summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-09-01 13:56:46 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-09-01 13:56:46 +0200
commit22f703cab05b7cd368f4de9e03991b7664dc5022 (patch)
tree6f4d50beaa42328e24b1c6b56b6ec059e4ef21a5
Initial import of argyll version 1.5.1-8debian/1.5.1-8
-rw-r--r--.pc/.quilt_patches1
-rw-r--r--.pc/.quilt_series1
-rw-r--r--.pc/.version1
-rw-r--r--.pc/01_autotools-support.diff/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/Makefile.shared0
-rw-r--r--.pc/01_autotools-support.diff/aclocal.m40
-rw-r--r--.pc/01_autotools-support.diff/cgats/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/config.guess0
-rw-r--r--.pc/01_autotools-support.diff/config.h.in0
-rw-r--r--.pc/01_autotools-support.diff/config.sub0
-rw-r--r--.pc/01_autotools-support.diff/configure0
-rw-r--r--.pc/01_autotools-support.diff/configure.ac0
-rw-r--r--.pc/01_autotools-support.diff/depcomp0
-rw-r--r--.pc/01_autotools-support.diff/doc/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/gamut/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/h/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/icc/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/imdi/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/imdi/imdi_k.h0
-rw-r--r--.pc/01_autotools-support.diff/install-sh0
-rw-r--r--.pc/01_autotools-support.diff/jcnf/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/jcnf/yajl/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/link/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/m4/libtool.m40
-rw-r--r--.pc/01_autotools-support.diff/m4/ltoptions.m40
-rw-r--r--.pc/01_autotools-support.diff/m4/ltsugar.m40
-rw-r--r--.pc/01_autotools-support.diff/m4/ltversion.m40
-rw-r--r--.pc/01_autotools-support.diff/m4/lt~obsolete.m40
-rw-r--r--.pc/01_autotools-support.diff/missing0
-rw-r--r--.pc/01_autotools-support.diff/numlib/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/plot/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/profile/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/ref/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/render/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/rspl/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/scanin/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/spectro/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/target/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/tweak/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/ucmm/Makefile.am0
-rw-r--r--.pc/01_autotools-support.diff/xicc/Makefile.am0
-rw-r--r--.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/changelog0
-rw-r--r--.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/compat0
-rw-r--r--.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/control0
-rw-r--r--.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/copyright0
-rw-r--r--.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/install0
-rw-r--r--.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/rules0
-rw-r--r--.pc/03_usb-db.diff/usb/55-Argyll.rules90
-rw-r--r--.pc/04_CVE-2012-4405.diff/icc/icc.c17833
-rw-r--r--.pc/06_fix_udev_rule.patch/usb/55-Argyll.rules90
-rw-r--r--.pc/applied-patches5
-rw-r--r--Jambase4541
-rw-r--r--Jamfile67
-rw-r--r--Jamtop160
-rw-r--r--License.txt662
-rw-r--r--License2.txt282
-rw-r--r--License3.txt674
-rw-r--r--Makefile10
-rw-r--r--Makefile.am23
-rw-r--r--Makefile.shared15
-rw-r--r--Readme.txt43
-rw-r--r--aclocal.m41073
-rw-r--r--adirs26
-rw-r--r--afiles22
-rw-r--r--binfiles3
-rw-r--r--blddirs1
-rw-r--r--cgats/Jamfile37
-rw-r--r--cgats/License.txt22
-rw-r--r--cgats/Makefile68
-rw-r--r--cgats/Makefile.IBMNT41
-rw-r--r--cgats/Makefile.OSX38
-rw-r--r--cgats/Makefile.UNIX38
-rw-r--r--cgats/Makefile.WNT38
-rw-r--r--cgats/Makefile.am9
-rw-r--r--cgats/Readme.txt286
-rw-r--r--cgats/afiles16
-rw-r--r--cgats/cgats.c2166
-rw-r--r--cgats/cgats.h180
-rw-r--r--cgats/cgatsstd.c111
-rw-r--r--cgats/makezip.ksh2
-rw-r--r--cgats/pars.c642
-rw-r--r--cgats/pars.h242
-rw-r--r--cgats/parsstd.c476
-rw-r--r--config.guess1558
-rw-r--r--config.h.in95
-rw-r--r--config.sub1791
-rw-r--r--configure15216
-rw-r--r--configure.ac133
-rw-r--r--debian/README.Debian8
-rw-r--r--debian/README.Spyder236
-rw-r--r--debian/applycal.159
-rw-r--r--debian/argyll.examples1
-rw-r--r--debian/argyll.install50
-rw-r--r--debian/argyll.manpages45
-rw-r--r--debian/argyll.postrm35
-rw-r--r--debian/argyll.preinst57
-rw-r--r--debian/average.152
-rw-r--r--debian/cb2ti3.135
-rw-r--r--debian/cctiff.1145
-rw-r--r--debian/ccttest.119
-rw-r--r--debian/ccxxmake.1171
-rw-r--r--debian/changelog506
-rw-r--r--debian/chartread.1185
-rw-r--r--debian/collink.1355
-rw-r--r--debian/colprof.1369
-rw-r--r--debian/compat1
-rw-r--r--debian/control114
-rw-r--r--debian/copyright823
-rw-r--r--debian/dispcal.1289
-rw-r--r--debian/dispread.1183
-rw-r--r--debian/dispwin.1151
-rw-r--r--debian/extracticc.119
-rw-r--r--debian/extractttag.131
-rw-r--r--debian/fakeCMY.137
-rw-r--r--debian/fakeread.1107
-rw-r--r--debian/greytiff.129
-rw-r--r--debian/icc-utils.install2
-rw-r--r--debian/icc-utils.manpages2
-rw-r--r--debian/iccdump.135
-rw-r--r--debian/iccgamut.1181
-rw-r--r--debian/icclu.161
-rw-r--r--debian/illumread.163
-rw-r--r--debian/invprofcheck.183
-rw-r--r--debian/kodak2ti3.141
-rw-r--r--debian/libicc-dev.install4
-rw-r--r--debian/libicc2.install1
-rw-r--r--debian/libicc2.symbols103
-rw-r--r--debian/libimdi-dev.install8
-rw-r--r--debian/libimdi0.install1
-rw-r--r--debian/libimdi0.symbols16
-rw-r--r--debian/mppcheck.151
-rw-r--r--debian/mpplu.1107
-rw-r--r--debian/mppprof.153
-rw-r--r--debian/oeminst.149
-rw-r--r--debian/patches/01_autotools-support.diff31463
-rw-r--r--debian/patches/02_firmware-package-builder.diff71
-rw-r--r--debian/patches/03_kfreebsd.diff22
-rw-r--r--debian/patches/03_usb-db.diff15
-rw-r--r--debian/patches/04_CVE-2012-4405.diff14
-rw-r--r--debian/patches/05_external-yajl.diff19
-rw-r--r--debian/patches/06_fix_udev_rule.patch23
-rw-r--r--debian/patches/series5
-rw-r--r--debian/pathplot.117
-rw-r--r--debian/printcal.1153
-rw-r--r--debian/printtarg.1243
-rw-r--r--debian/profcheck.1115
-rw-r--r--debian/refine.1109
-rw-r--r--debian/revfix.191
-rwxr-xr-xdebian/rules125
-rw-r--r--debian/scanin.1215
-rw-r--r--debian/simpprof.123
-rw-r--r--debian/source/format1
-rw-r--r--debian/spec2cie.184
-rw-r--r--debian/specplot.149
-rw-r--r--debian/splitti3.159
-rw-r--r--debian/spotread.1235
-rw-r--r--debian/synthcal.187
-rw-r--r--debian/synthread.185
-rw-r--r--debian/targen.1203
-rw-r--r--debian/tiffgamut.1165
-rw-r--r--debian/txt2ti3.161
-rw-r--r--debian/verify.1117
-rw-r--r--debian/viewgam.179
-rw-r--r--debian/watch3
-rw-r--r--debian/xicclu.1257
-rw-r--r--depcomp791
-rw-r--r--doc/ArgyllDoc.html5570
-rw-r--r--doc/ArgyllFlow.jpgbin0 -> 225826 bytes
-rw-r--r--doc/ArgyllFlowThumb.jpgbin0 -> 10629 bytes
-rw-r--r--doc/CMP_DT_003.jpgbin0 -> 23966 bytes
-rw-r--r--doc/CMP_Digital_Target-3.jpgbin0 -> 21111 bytes
-rw-r--r--doc/CRTspectrum.jpgbin0 -> 32231 bytes
-rw-r--r--doc/ChangesSummary.html790
-rw-r--r--doc/Chroma4.jpgbin0 -> 16118 bytes
-rw-r--r--doc/ColorManagement.html271
-rw-r--r--doc/ColorMunki.jpgbin0 -> 43097 bytes
-rw-r--r--doc/ColorMunkiCreate.jpgbin0 -> 29653 bytes
-rw-r--r--doc/Compiling.html170
-rw-r--r--doc/CrushedDisplyBlacks.html85
-rw-r--r--doc/DC.jpgbin0 -> 23570 bytes
-rw-r--r--doc/DTP20.jpgbin0 -> 83527 bytes
-rw-r--r--doc/DTP22.jpgbin0 -> 51054 bytes
-rw-r--r--doc/DTP41.jpgbin0 -> 78517 bytes
-rw-r--r--doc/DTP51.jpgbin0 -> 52356 bytes
-rw-r--r--doc/DTP92.jpgbin0 -> 41789 bytes
-rw-r--r--doc/DTP94.jpgbin0 -> 46245 bytes
-rw-r--r--doc/DocLicense.txt451
-rw-r--r--doc/Environment.html125
-rw-r--r--doc/FWA.html262
-rw-r--r--doc/FWA_measure.jpgbin0 -> 23717 bytes
-rw-r--r--doc/File_Formats.html186
-rw-r--r--doc/Fluorescent.jpgbin0 -> 35863 bytes
-rw-r--r--doc/HCFR.jpgbin0 -> 21765 bytes
-rw-r--r--doc/HCT.jpgbin0 -> 9601 bytes
-rw-r--r--doc/HiResLaser.jpgbin0 -> 28163 bytes
-rw-r--r--doc/Huey.jpgbin0 -> 30022 bytes
-rw-r--r--doc/Installing.html49
-rw-r--r--doc/Installing_Linux.html582
-rw-r--r--doc/Installing_MSWindows.html583
-rw-r--r--doc/Installing_OSX.html283
-rw-r--r--doc/Kgraph1.jpgbin0 -> 14691 bytes
-rw-r--r--doc/Kgraph2.jpgbin0 -> 13544 bytes
-rw-r--r--doc/Kgraph3.jpgbin0 -> 14548 bytes
-rw-r--r--doc/Kgraph4.jpgbin0 -> 14056 bytes
-rw-r--r--doc/Kgraph5.jpgbin0 -> 14084 bytes
-rw-r--r--doc/Kgraph6.jpgbin0 -> 14830 bytes
-rw-r--r--doc/Kgraph7.jpgbin0 -> 15134 bytes
-rw-r--r--doc/Kgraph8.jpgbin0 -> 14218 bytes
-rw-r--r--doc/Kparams.jpgbin0 -> 15850 bytes
-rw-r--r--doc/LSDC.jpgbin0 -> 12237 bytes
-rw-r--r--doc/LabSteps.jpgbin0 -> 13335 bytes
-rw-r--r--doc/License.txt662
-rw-r--r--doc/License2.txt282
-rw-r--r--doc/License3.txt674
-rw-r--r--doc/Limitations.html42
-rw-r--r--doc/Makefile.am6
-rw-r--r--doc/MinorTools.html64
-rw-r--r--doc/Organisation.html230
-rw-r--r--doc/Overview.html57
-rw-r--r--doc/Performance.html106
-rw-r--r--doc/Q60.jpgbin0 -> 14943 bytes
-rw-r--r--doc/QPcard201.jpgbin0 -> 4967 bytes
-rw-r--r--doc/QPcard202.jpgbin0 -> 9016 bytes
-rw-r--r--doc/SG.jpgbin0 -> 11348 bytes
-rw-r--r--doc/SG_footer.txt1
-rw-r--r--doc/SG_header.txt12
-rw-r--r--doc/Scenarios.html2177
-rw-r--r--doc/Smile.jpgbin0 -> 25761 bytes
-rw-r--r--doc/Source.html219
-rw-r--r--doc/Spyd2.jpgbin0 -> 64227 bytes
-rw-r--r--doc/Spyd3.jpgbin0 -> 13975 bytes
-rw-r--r--doc/Spyd3x.jpgbin0 -> 13519 bytes
-rw-r--r--doc/Spyd4.jpgbin0 -> 11284 bytes
-rw-r--r--doc/SpyderChecker.jpgbin0 -> 12497 bytes
-rw-r--r--doc/WideGamutColmters.html120
-rw-r--r--doc/YellowGreen.jpgbin0 -> 18404 bytes
-rw-r--r--doc/afiles179
-rw-r--r--doc/applycal.html135
-rw-r--r--doc/average.html43
-rw-r--r--doc/cal_format.html216
-rw-r--r--doc/calvschar.html62
-rw-r--r--doc/cb2ti3.html56
-rw-r--r--doc/ccmxs.html424
-rw-r--r--doc/ccmxs/DTP-94_1964_10_Dell_2408W.ccmx25
-rw-r--r--doc/ccmxs/DTP-94_1997_Shaw_Dell_2408W.ccmx25
-rw-r--r--doc/ccmxs/DTP-94_Dell_2408W.ccmx25
-rw-r--r--doc/ccmxs/DTP-94_Dell_U2410.ccmx25
-rw-r--r--doc/ccmxs/EyeOne_Display_1_NEC1990SXi.ccmx25
-rw-r--r--doc/ccmxs/EyeOne_Display_2_EIZO_S2233W.ccmx25
-rw-r--r--doc/ccmxs/EyeOne_Display_2_NEC1990SXi.ccmx25
-rw-r--r--doc/ccmxs/EyeOne_Display_LT_U2410_Standard_1931.ccmx25
-rw-r--r--doc/ccmxs/EyeOne_Display_LT_U2410_Standard_1964.ccmx25
-rw-r--r--doc/ccmxs/EyeOne_Display_LT_U2410_sRGB_1931.ccmx25
-rw-r--r--doc/ccmxs/EyeOne_Display_LT_U2410_sRGB_1964.ccmx25
-rw-r--r--doc/ccmxs/Huey_Acer_al2016w.ccmx25
-rw-r--r--doc/ccmxs/Huey_Eizo_CG243.ccmx25
-rw-r--r--doc/ccmxs/Huey_HP_compaq_6730s.ccmx25
-rw-r--r--doc/ccmxs/Huey_HP_lp2475w.ccmx25
-rw-r--r--doc/ccmxs/Huey_NEC1990SXi.ccmx25
-rw-r--r--doc/ccmxs/Huey_NEC_Spectraview_241.ccmx25
-rw-r--r--doc/ccmxs/NEC_EyeOne_Display_2_NEC2690WUXi2.ccmx25
-rw-r--r--doc/ccmxs/Spyder2_EIZO_S2433W_standard_1931.ccmx25
-rw-r--r--doc/ccmxs/Spyder2_EIZO_S2433W_standard_1964.ccmx25
-rw-r--r--doc/ccmxs/Spyder3_EIZO_S2233_standard_1964.ccmx25
-rw-r--r--doc/ccmxs/Spyder3_EIZO_S2243W_standard_1931.ccmx25
-rw-r--r--doc/ccmxs/Spyder3_HP_LP2475w.ccmx25
-rw-r--r--doc/ccmxs/Spyder3_NEC2690WUXi2.ccmx25
-rw-r--r--doc/ccmxs/Spyder3_NEC_PA301W.ccmx25
-rw-r--r--doc/cctiff.html351
-rw-r--r--doc/ccxxmake.html954
-rw-r--r--doc/chartread.html499
-rw-r--r--doc/cht_format.html576
-rw-r--r--doc/collink.html1059
-rw-r--r--doc/colorchecker.jpgbin0 -> 7522 bytes
-rw-r--r--doc/colprof.html1559
-rw-r--r--doc/cube.jpgbin0 -> 11036 bytes
-rw-r--r--doc/dispcal.html2256
-rw-r--r--doc/dispprofloc.html313
-rw-r--r--doc/dispread.html926
-rw-r--r--doc/dispwin.html593
-rw-r--r--doc/evalInputTargets.html61
-rw-r--r--doc/extracticc.html40
-rw-r--r--doc/extractttag.html43
-rw-r--r--doc/fakeCMY.html73
-rw-r--r--doc/fakeread.html248
-rw-r--r--doc/filmread.html55
-rw-r--r--doc/filmtarg.html78
-rw-r--r--doc/gamma.html64
-rw-r--r--doc/gamutmapping1.jpgbin0 -> 19794 bytes
-rw-r--r--doc/greytiff.html96
-rw-r--r--doc/i1d.jpgbin0 -> 36903 bytes
-rw-r--r--doc/i1d3_1.jpgbin0 -> 16744 bytes
-rw-r--r--doc/i1d3_2.jpgbin0 -> 16538 bytes
-rw-r--r--doc/i1m.jpgbin0 -> 29888 bytes
-rw-r--r--doc/i1p.jpgbin0 -> 62804 bytes
-rw-r--r--doc/i1pro2.jpgbin0 -> 73450 bytes
-rw-r--r--doc/i1proDriver.html157
-rw-r--r--doc/i1proDriver.xlsbin0 -> 187392 bytes
-rw-r--r--doc/i1scan14.jpgbin0 -> 15925 bytes
-rw-r--r--doc/iccdump.html52
-rw-r--r--doc/iccgamut.html334
-rw-r--r--doc/iccgamutmapping.html163
-rw-r--r--doc/icclu.html119
-rw-r--r--doc/illumread.html319
-rw-r--r--doc/illumread_1.jpgbin0 -> 14047 bytes
-rw-r--r--doc/illumread_2.jpgbin0 -> 13451 bytes
-rw-r--r--doc/illumread_3.jpgbin0 -> 17753 bytes
-rw-r--r--doc/illumread_4.jpgbin0 -> 21691 bytes
-rw-r--r--doc/illumread_5.jpgbin0 -> 15948 bytes
-rw-r--r--doc/illumread_6.jpgbin0 -> 8066 bytes
-rw-r--r--doc/instruments.html2214
-rw-r--r--doc/invprofcheck.html133
-rw-r--r--doc/kodak2ti3.html59
-rw-r--r--doc/monitorcontrols.html90
-rw-r--r--doc/mox.jpgbin0 -> 8355 bytes
-rw-r--r--doc/moxxr.jpgbin0 -> 6289 bytes
-rw-r--r--doc/mppcheck.html78
-rw-r--r--doc/mpplu.html182
-rw-r--r--doc/mppprof.html99
-rw-r--r--doc/oeminst.html323
-rw-r--r--doc/printcal.html399
-rw-r--r--doc/printtarg.html681
-rw-r--r--doc/profcheck.html251
-rw-r--r--doc/refine.html354
-rw-r--r--doc/revfix.html252
-rw-r--r--doc/scanin.html582
-rw-r--r--doc/sl.jpgbin0 -> 77102 bytes
-rw-r--r--doc/spec2cie.html207
-rw-r--r--doc/specplot.html46
-rw-r--r--doc/splitti3.html75
-rw-r--r--doc/spotread.html1011
-rw-r--r--doc/srgbplot.gifbin0 -> 3468 bytes
-rw-r--r--doc/ss.jpgbin0 -> 65180 bytes
-rw-r--r--doc/surface.jpgbin0 -> 11222 bytes
-rw-r--r--doc/synthcal.html108
-rw-r--r--doc/synthread.html166
-rw-r--r--doc/targen.html1024
-rw-r--r--doc/ti3_format.html311
-rw-r--r--doc/tiffgamut.html357
-rw-r--r--doc/timage.html100
-rw-r--r--doc/txt2ti3.html98
-rw-r--r--doc/ucmm.html122
-rw-r--r--doc/verify.html186
-rw-r--r--doc/viewgam.html125
-rw-r--r--doc/xicclu.html551
-rw-r--r--firmware-package-builder/argyll-firmware-spyder2/debian/changelog12
-rw-r--r--firmware-package-builder/argyll-firmware-spyder2/debian/compat1
-rw-r--r--firmware-package-builder/argyll-firmware-spyder2/debian/control17
-rw-r--r--firmware-package-builder/argyll-firmware-spyder2/debian/copyright8
-rw-r--r--firmware-package-builder/argyll-firmware-spyder2/debian/install1
-rw-r--r--firmware-package-builder/argyll-firmware-spyder2/debian/rules10
-rw-r--r--gamut/GenRMGam.c786
-rw-r--r--gamut/GenVisGam.c189
-rw-r--r--gamut/Jamfile93
-rw-r--r--gamut/License.txt662
-rw-r--r--gamut/Makefile.am27
-rw-r--r--gamut/Readme.txt25
-rw-r--r--gamut/afiles19
-rw-r--r--gamut/fakegam.c325
-rw-r--r--gamut/gammap.c2552
-rw-r--r--gamut/gammap.h68
-rw-r--r--gamut/gammap.txt259
-rw-r--r--gamut/gamut.c7136
-rw-r--r--gamut/gamut.h406
-rw-r--r--gamut/isecvol.c320
-rw-r--r--gamut/maptest.c240
-rw-r--r--gamut/nearsmth.c3570
-rw-r--r--gamut/nearsmth.h274
-rw-r--r--gamut/smthtest.c460
-rw-r--r--gamut/surftest.c255
-rw-r--r--gamut/viewgam.c700
-rw-r--r--h/License.txt662
-rw-r--r--h/Makefile.am3
-rw-r--r--h/Readme.txt1
-rw-r--r--h/aconfig.h29
-rw-r--r--h/afiles9
-rw-r--r--h/copyright.h5
-rw-r--r--h/counters.h246
-rw-r--r--h/llist.h92
-rw-r--r--h/sort.h62
-rw-r--r--h/xlist.h56
-rw-r--r--icc/ClayRGB1998.icmbin0 -> 580 bytes
-rw-r--r--icc/Jamfile58
-rw-r--r--icc/License.txt22
-rw-r--r--icc/Makefile82
-rw-r--r--icc/Makefile.IBMNT41
-rw-r--r--icc/Makefile.OSX38
-rw-r--r--icc/Makefile.UNIX38
-rw-r--r--icc/Makefile.WNT38
-rw-r--r--icc/Makefile.am22
-rw-r--r--icc/Readme.txt150
-rw-r--r--icc/afiles26
-rw-r--r--icc/icc.c17838
-rw-r--r--icc/icc.h1992
-rw-r--r--icc/iccV42.h555
-rw-r--r--icc/iccdump.c269
-rw-r--r--icc/icclu.c424
-rw-r--r--icc/iccrw.c311
-rw-r--r--icc/iccstd.c443
-rw-r--r--icc/icctest.c2393
-rw-r--r--icc/lab2lab.icmbin0 -> 500 bytes
-rw-r--r--icc/log.txt173
-rw-r--r--icc/lutest.c3506
-rw-r--r--icc/makezip.ksh6
-rw-r--r--icc/mcheck.c541
-rw-r--r--icc/sRGB.icmbin0 -> 3212 bytes
-rw-r--r--icc/testDE2K.c226
-rw-r--r--icc/todo.txt197
-rw-r--r--imdi/Jamfile90
-rw-r--r--imdi/License.txt662
-rw-r--r--imdi/Makefile66
-rw-r--r--imdi/Makefile.OSX42
-rw-r--r--imdi/Makefile.UNIX42
-rw-r--r--imdi/Makefile.WNT42
-rw-r--r--imdi/Makefile.am40
-rw-r--r--imdi/Readme.txt114
-rw-r--r--imdi/afiles26
-rw-r--r--imdi/cctiff.c2320
-rw-r--r--imdi/cctiffo.c1097
-rw-r--r--imdi/cgen.c2150
-rw-r--r--imdi/ctest.c156
-rw-r--r--imdi/greytiff.c575
-rw-r--r--imdi/imdi.c605
-rw-r--r--imdi/imdi.h93
-rw-r--r--imdi/imdi_arch.h71
-rw-r--r--imdi/imdi_gen.c319
-rw-r--r--imdi/imdi_gen.h271
-rw-r--r--imdi/imdi_k.h910
-rw-r--r--imdi/imdi_make.c514
-rw-r--r--imdi/imdi_tab.c803
-rw-r--r--imdi/imdi_tab.h170
-rw-r--r--imdi/imdi_utl.h262
-rw-r--r--imdi/itest.c652
-rw-r--r--imdi/refi.c212
-rw-r--r--imdi/refi.h53
-rw-r--r--imdi/ssort.c322
-rw-r--r--install-sh527
-rw-r--r--install.bat5
-rw-r--r--jam.patch74
-rw-r--r--jcnf/Jamfile32
-rw-r--r--jcnf/Makefile.am15
-rw-r--r--jcnf/Readme.txt22
-rw-r--r--jcnf/afiles7
-rw-r--r--jcnf/jcnf.c1248
-rw-r--r--jcnf/jcnf.h199
-rw-r--r--jcnf/test.c161
-rw-r--r--jcnf/test.jcnf33
-rw-r--r--jcnf/yajl/COPYING29
-rw-r--r--jcnf/yajl/ChangeLog88
-rw-r--r--jcnf/yajl/Jamfile30
-rw-r--r--jcnf/yajl/Makefile.am13
-rw-r--r--jcnf/yajl/README68
-rw-r--r--jcnf/yajl/TODO9
-rw-r--r--jcnf/yajl/YAJL.dxy1258
-rw-r--r--jcnf/yajl/YAJLDoc.cmake26
-rw-r--r--jcnf/yajl/afiles84
-rw-r--r--jcnf/yajl/cases/array.json6
-rw-r--r--jcnf/yajl/cases/array.json.gold22
-rw-r--r--jcnf/yajl/cases/bogus_char.json4
-rw-r--r--jcnf/yajl/cases/bogus_char.json.gold9
-rw-r--r--jcnf/yajl/cases/codepoints_from_unicode_org.json1
-rw-r--r--jcnf/yajl/cases/codepoints_from_unicode_org.json.gold1
-rw-r--r--jcnf/yajl/cases/dc_simple_with_comments.json11
-rw-r--r--jcnf/yajl/cases/dc_simple_with_comments.json.gold4
-rw-r--r--jcnf/yajl/cases/deep_arrays.json1
-rw-r--r--jcnf/yajl/cases/deep_arrays.json.gold2048
-rw-r--r--jcnf/yajl/cases/difficult_json_c_test_case.json1
-rw-r--r--jcnf/yajl/cases/difficult_json_c_test_case.json.gold35
-rw-r--r--jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json1
-rw-r--r--jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold35
-rw-r--r--jcnf/yajl/cases/doubles.json1
-rw-r--r--jcnf/yajl/cases/doubles.json.gold6
-rw-r--r--jcnf/yajl/cases/empty_array.json1
-rw-r--r--jcnf/yajl/cases/empty_array.json.gold2
-rw-r--r--jcnf/yajl/cases/escaped_bulgarian.json4
-rw-r--r--jcnf/yajl/cases/escaped_bulgarian.json.gold6
-rw-r--r--jcnf/yajl/cases/escaped_foobar.json1
-rw-r--r--jcnf/yajl/cases/escaped_foobar.json.gold1
-rw-r--r--jcnf/yajl/cases/integers.json3
-rw-r--r--jcnf/yajl/cases/integers.json.gold13
-rw-r--r--jcnf/yajl/cases/invalid_utf8.json1
-rw-r--r--jcnf/yajl/cases/invalid_utf8.json.gold2
-rw-r--r--jcnf/yajl/cases/isolated_surrogate_marker.json1
-rw-r--r--jcnf/yajl/cases/isolated_surrogate_marker.json.gold1
-rw-r--r--jcnf/yajl/cases/leading_zero_in_number.json1
-rw-r--r--jcnf/yajl/cases/leading_zero_in_number.json.gold4
-rw-r--r--jcnf/yajl/cases/lonely_minus_sign.json7
-rw-r--r--jcnf/yajl/cases/lonely_minus_sign.json.gold8
-rw-r--r--jcnf/yajl/cases/missing_integer_after_decimal_point.json1
-rw-r--r--jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold1
-rw-r--r--jcnf/yajl/cases/missing_integer_after_exponent.json1
-rw-r--r--jcnf/yajl/cases/missing_integer_after_exponent.json.gold1
-rw-r--r--jcnf/yajl/cases/non_utf8_char_in_string.json1
-rw-r--r--jcnf/yajl/cases/non_utf8_char_in_string.json.gold7
-rw-r--r--jcnf/yajl/cases/nulls_and_bools.json5
-rw-r--r--jcnf/yajl/cases/nulls_and_bools.json.gold8
-rw-r--r--jcnf/yajl/cases/simple.json5
-rw-r--r--jcnf/yajl/cases/simple.json.gold8
-rw-r--r--jcnf/yajl/cases/simple_with_comments.json11
-rw-r--r--jcnf/yajl/cases/simple_with_comments.json.gold8
-rw-r--r--jcnf/yajl/cases/string_invalid_escape.json1
-rw-r--r--jcnf/yajl/cases/string_invalid_escape.json.gold2
-rw-r--r--jcnf/yajl/cases/string_invalid_hex_char.json1
-rw-r--r--jcnf/yajl/cases/string_invalid_hex_char.json.gold1
-rw-r--r--jcnf/yajl/cases/string_with_escapes.json3
-rw-r--r--jcnf/yajl/cases/string_with_escapes.json.gold6
-rw-r--r--jcnf/yajl/cases/string_with_invalid_newline.json2
-rw-r--r--jcnf/yajl/cases/string_with_invalid_newline.json.gold1
-rw-r--r--jcnf/yajl/cases/unescaped_bulgarian.json1
-rw-r--r--jcnf/yajl/cases/unescaped_bulgarian.json.gold3
-rw-r--r--jcnf/yajl/configure94
-rw-r--r--jcnf/yajl/json_reformat.c204
-rw-r--r--jcnf/yajl/json_verify.c129
-rw-r--r--jcnf/yajl/rfc4627.txt3
-rw-r--r--jcnf/yajl/run_tests.sh61
-rw-r--r--jcnf/yajl/yajl.c152
-rw-r--r--jcnf/yajl/yajl_alloc.c65
-rw-r--r--jcnf/yajl/yajl_alloc.h50
-rw-r--r--jcnf/yajl/yajl_buf.c119
-rw-r--r--jcnf/yajl/yajl_buf.h73
-rw-r--r--jcnf/yajl/yajl_bytestack.h85
-rw-r--r--jcnf/yajl/yajl_common.h85
-rw-r--r--jcnf/yajl/yajl_encode.c179
-rw-r--r--jcnf/yajl/yajl_encode.h44
-rw-r--r--jcnf/yajl/yajl_gen.c381
-rw-r--r--jcnf/yajl/yajl_gen.h129
-rw-r--r--jcnf/yajl/yajl_lex.c753
-rw-r--r--jcnf/yajl/yajl_lex.h135
-rw-r--r--jcnf/yajl/yajl_parse.h184
-rw-r--r--jcnf/yajl/yajl_parser.c505
-rw-r--r--jcnf/yajl/yajl_parser.h79
-rw-r--r--jcnf/yajl/yajl_test.c293
-rw-r--r--jpg/Jamfile26
-rw-r--r--jpg/Makefile.am134
-rw-r--r--jpg/Makefile.in1094
-rw-r--r--jpg/README351
-rw-r--r--jpg/aclocal.m49652
-rw-r--r--jpg/afiles185
-rw-r--r--jpg/ansi2knr.136
-rw-r--r--jpg/ansi2knr.c739
-rw-r--r--jpg/cderror.h134
-rw-r--r--jpg/cdjpeg.c181
-rw-r--r--jpg/cdjpeg.h187
-rw-r--r--jpg/change.log346
-rw-r--r--jpg/cjpeg.1348
-rw-r--r--jpg/cjpeg.c643
-rw-r--r--jpg/ckconfig.c402
-rw-r--r--jpg/coderules.txt118
-rw-r--r--jpg/config.guess1522
-rw-r--r--jpg/config.sub1771
-rw-r--r--jpg/configure15928
-rw-r--r--jpg/configure.ac356
-rw-r--r--jpg/depcomp688
-rw-r--r--jpg/djpeg.1252
-rw-r--r--jpg/djpeg.c617
-rw-r--r--jpg/example.c433
-rw-r--r--jpg/filelist.txt215
-rw-r--r--jpg/install-sh527
-rw-r--r--jpg/install.txt1096
-rw-r--r--jpg/jaricom.c153
-rw-r--r--jpg/jcapimin.c288
-rw-r--r--jpg/jcapistd.c161
-rw-r--r--jpg/jcarith.c937
-rw-r--r--jpg/jccoefct.c454
-rw-r--r--jpg/jccolor.c490
-rw-r--r--jpg/jcdctmgr.c482
-rw-r--r--jpg/jchuff.c1576
-rw-r--r--jpg/jcinit.c65
-rw-r--r--jpg/jcmainct.c293
-rw-r--r--jpg/jcmarker.c682
-rw-r--r--jpg/jcmaster.c858
-rw-r--r--jpg/jcomapi.c106
-rw-r--r--jpg/jconfig.bcc48
-rw-r--r--jpg/jconfig.cfg53
-rw-r--r--jpg/jconfig.dj38
-rw-r--r--jpg/jconfig.mac43
-rw-r--r--jpg/jconfig.manx43
-rw-r--r--jpg/jconfig.mc652
-rw-r--r--jpg/jconfig.sas43
-rw-r--r--jpg/jconfig.st42
-rw-r--r--jpg/jconfig.txt164
-rw-r--r--jpg/jconfig.vc45
-rw-r--r--jpg/jconfig.vms37
-rw-r--r--jpg/jconfig.wat38
-rw-r--r--jpg/jcparam.c632
-rw-r--r--jpg/jcprepct.c358
-rw-r--r--jpg/jcsample.c545
-rw-r--r--jpg/jctrans.c382
-rw-r--r--jpg/jdapimin.c396
-rw-r--r--jpg/jdapistd.c275
-rw-r--r--jpg/jdarith.c776
-rw-r--r--jpg/jdatadst.c267
-rw-r--r--jpg/jdatasrc.c275
-rw-r--r--jpg/jdcoefct.c741
-rw-r--r--jpg/jdcolor.c512
-rw-r--r--jpg/jdct.h393
-rw-r--r--jpg/jddctmgr.c384
-rw-r--r--jpg/jdhuff.c1541
-rw-r--r--jpg/jdinput.c661
-rw-r--r--jpg/jdmainct.c512
-rw-r--r--jpg/jdmarker.c1406
-rw-r--r--jpg/jdmaster.c531
-rw-r--r--jpg/jdmerge.c400
-rw-r--r--jpg/jdosaobj.txt16
-rw-r--r--jpg/jdpostct.c290
-rw-r--r--jpg/jdsample.c361
-rw-r--r--jpg/jdtrans.c140
-rw-r--r--jpg/jerror.c252
-rw-r--r--jpg/jerror.h304
-rw-r--r--jpg/jfdctflt.c174
-rw-r--r--jpg/jfdctfst.c230
-rw-r--r--jpg/jfdctint.c4348
-rw-r--r--jpg/jidctflt.c235
-rw-r--r--jpg/jidctfst.c368
-rw-r--r--jpg/jidctint.c5137
-rw-r--r--jpg/jinclude.h91
-rw-r--r--jpg/jmemansi.c167
-rw-r--r--jpg/jmemdos.c638
-rw-r--r--jpg/jmemdosa.asm379
-rw-r--r--jpg/jmemmac.c289
-rw-r--r--jpg/jmemmgr.c1119
-rw-r--r--jpg/jmemname.c276
-rw-r--r--jpg/jmemnobs.c109
-rw-r--r--jpg/jmemsys.h198
-rw-r--r--jpg/jmorecfg.h369
-rw-r--r--jpg/jpegint.h426
-rw-r--r--jpg/jpeglib.h1160
-rw-r--r--jpg/jpegsr8d.zipbin0 -> 1060974 bytes
-rw-r--r--jpg/jpegtran.1285
-rw-r--r--jpg/jpegtran.c560
-rw-r--r--jpg/jquant1.c857
-rw-r--r--jpg/jquant2.c1311
-rw-r--r--jpg/jutils.c227
-rw-r--r--jpg/jversion.h14
-rw-r--r--jpg/libjpeg.map4
-rw-r--r--jpg/libjpeg.txt3085
-rw-r--r--jpg/ltmain.sh9655
-rw-r--r--jpg/makcjpeg.st36
-rw-r--r--jpg/makdjpeg.st36
-rw-r--r--jpg/makeadsw.vc677
-rw-r--r--jpg/makeasln.v1033
-rw-r--r--jpg/makecdep.vc682
-rw-r--r--jpg/makecdsp.vc6130
-rw-r--r--jpg/makecfil.v1069
-rw-r--r--jpg/makecmak.vc6159
-rw-r--r--jpg/makecvcx.v1076
-rw-r--r--jpg/makeddep.vc682
-rw-r--r--jpg/makeddsp.vc6130
-rw-r--r--jpg/makedfil.v1069
-rw-r--r--jpg/makedmak.vc6159
-rw-r--r--jpg/makedvcx.v1076
-rw-r--r--jpg/makefile.ansi221
-rw-r--r--jpg/makefile.bcc292
-rw-r--r--jpg/makefile.dj227
-rw-r--r--jpg/makefile.manx221
-rw-r--r--jpg/makefile.mc6256
-rw-r--r--jpg/makefile.mms225
-rw-r--r--jpg/makefile.sas259
-rw-r--r--jpg/makefile.unix235
-rw-r--r--jpg/makefile.vc273
-rw-r--r--jpg/makefile.vms142
-rw-r--r--jpg/makefile.wat240
-rw-r--r--jpg/makejdep.vc6423
-rw-r--r--jpg/makejdsp.vc6285
-rw-r--r--jpg/makejdsw.vc629
-rw-r--r--jpg/makejfil.v10186
-rw-r--r--jpg/makejmak.vc6425
-rw-r--r--jpg/makejsln.v1017
-rw-r--r--jpg/makejvcx.v10112
-rw-r--r--jpg/makeproj.mac213
-rw-r--r--jpg/makerdep.vc66
-rw-r--r--jpg/makerdsp.vc678
-rw-r--r--jpg/makerfil.v1030
-rw-r--r--jpg/makermak.vc6110
-rw-r--r--jpg/makervcx.v1062
-rw-r--r--jpg/maketdep.vc643
-rw-r--r--jpg/maketdsp.vc6122
-rw-r--r--jpg/maketfil.v1063
-rw-r--r--jpg/maketmak.vc6131
-rw-r--r--jpg/maketvcx.v1074
-rw-r--r--jpg/makewdep.vc66
-rw-r--r--jpg/makewdsp.vc678
-rw-r--r--jpg/makewfil.v1030
-rw-r--r--jpg/makewmak.vc6110
-rw-r--r--jpg/makewvcx.v1062
-rw-r--r--jpg/makljpeg.st68
-rw-r--r--jpg/maktjpeg.st30
-rw-r--r--jpg/makvms.opt4
-rw-r--r--jpg/missing376
-rw-r--r--jpg/rdbmp.c480
-rw-r--r--jpg/rdcolmap.c253
-rw-r--r--jpg/rdgif.c38
-rw-r--r--jpg/rdjpgcom.163
-rw-r--r--jpg/rdjpgcom.c515
-rw-r--r--jpg/rdppm.c459
-rw-r--r--jpg/rdrle.c387
-rw-r--r--jpg/rdswitch.c365
-rw-r--r--jpg/rdtarga.c500
-rw-r--r--jpg/readme.dos15
-rw-r--r--jpg/structure.txt941
-rw-r--r--jpg/testimg.bmpbin0 -> 35050 bytes
-rw-r--r--jpg/testimg.jpgbin0 -> 5764 bytes
-rw-r--r--jpg/testimg.ppm4
-rw-r--r--jpg/testimgp.jpgbin0 -> 5645 bytes
-rw-r--r--jpg/testorig.jpgbin0 -> 5770 bytes
-rw-r--r--jpg/testprog.jpgbin0 -> 5655 bytes
-rw-r--r--jpg/transupp.c1597
-rw-r--r--jpg/transupp.h213
-rw-r--r--jpg/usage.txt637
-rw-r--r--jpg/wizard.txt211
-rw-r--r--jpg/wrbmp.c442
-rw-r--r--jpg/wrgif.c399
-rw-r--r--jpg/wrjpgcom.1103
-rw-r--r--jpg/wrjpgcom.c583
-rw-r--r--jpg/wrppm.c269
-rw-r--r--jpg/wrrle.c305
-rw-r--r--jpg/wrtarga.c253
-rw-r--r--lib/Readme.txt1
-rw-r--r--lib/afiles2
-rw-r--r--link/Jamfile36
-rw-r--r--link/License.txt662
-rw-r--r--link/Makefile.am11
-rw-r--r--link/Readme.txt6
-rw-r--r--link/afiles7
-rw-r--r--link/collink.c3298
-rw-r--r--link/monoplot.c231
-rw-r--r--link/pathplot.c281
-rw-r--r--log.txt3581
-rw-r--r--m4/libtool.m47991
-rw-r--r--m4/ltoptions.m4384
-rw-r--r--m4/ltsugar.m4123
-rw-r--r--m4/ltversion.m423
-rw-r--r--m4/lt~obsolete.m498
-rw-r--r--makeall.bat5
-rw-r--r--makeall.sh12
-rw-r--r--makeinstall.sh9
-rw-r--r--makepackagebin.sh173
-rw-r--r--missing215
-rw-r--r--notes.txt118
-rw-r--r--numlib/Jamfile28
-rw-r--r--numlib/LUtest.c113
-rw-r--r--numlib/License.txt662
-rw-r--r--numlib/Makefile.am15
-rw-r--r--numlib/Readme.txt14
-rw-r--r--numlib/aatree.c432
-rw-r--r--numlib/aatree.h58
-rw-r--r--numlib/afiles32
-rw-r--r--numlib/dhsx.c302
-rw-r--r--numlib/dhsx.h42
-rw-r--r--numlib/dnsq.c1675
-rw-r--r--numlib/dnsq.h120
-rw-r--r--numlib/dnsqtest.c192
-rw-r--r--numlib/ludecomp.c500
-rw-r--r--numlib/ludecomp.h93
-rw-r--r--numlib/numlib.h18
-rw-r--r--numlib/numsup.c1539
-rw-r--r--numlib/numsup.h380
-rw-r--r--numlib/powell.c691
-rw-r--r--numlib/powell.h74
-rw-r--r--numlib/rand.c108
-rw-r--r--numlib/rand.h36
-rw-r--r--numlib/sobol.c211
-rw-r--r--numlib/sobol.h52
-rw-r--r--numlib/soboltest.c127
-rw-r--r--numlib/svd.c611
-rw-r--r--numlib/svd.h90
-rw-r--r--numlib/svdtest.c214
-rw-r--r--numlib/tdhsx.c117
-rw-r--r--numlib/tpowell.c123
-rw-r--r--numlib/zbrent.c182
-rw-r--r--numlib/zbrent.h44
-rw-r--r--numlib/zbrenttest.c56
-rw-r--r--plot/Imakefile6
-rw-r--r--plot/Jamfile27
-rw-r--r--plot/License.txt662
-rw-r--r--plot/Makefile.am12
-rw-r--r--plot/Readme.txt2
-rw-r--r--plot/afiles14
-rw-r--r--plot/osx/Jamfile21
-rw-r--r--plot/osx/Readme.txt1
-rw-r--r--plot/osx/acoccoa.h402
-rw-r--r--plot/osx/helloc.c313
-rw-r--r--plot/osx/hellom.m181
-rw-r--r--plot/plot.c2511
-rw-r--r--plot/plot.h94
-rw-r--r--plot/vrml.c928
-rw-r--r--plot/vrml.h113
-rw-r--r--profile/3dap5k.sp103
-rw-r--r--profile/CIE_C.sp118
-rw-r--r--profile/D50_0.0.sp132
-rw-r--r--profile/D50_0.1.sp132
-rw-r--r--profile/D50_0.3.sp132
-rw-r--r--profile/D50_0.5.sp132
-rw-r--r--profile/D50_0.7.sp132
-rw-r--r--profile/D50_1.0.sp132
-rw-r--r--profile/D50_1.2.sp132
-rw-r--r--profile/D50_1.5.sp132
-rw-r--r--profile/D50_1.7.sp132
-rw-r--r--profile/D50_2.0.sp132
-rw-r--r--profile/D50_2.5.sp132
-rw-r--r--profile/D50_3.0.sp132
-rw-r--r--profile/GTIPlus.sp64
-rw-r--r--profile/Jamfile104
-rw-r--r--profile/License.txt662
-rw-r--r--profile/Makefile.am27
-rw-r--r--profile/Office.sp103
-rw-r--r--profile/Readme.txt3
-rw-r--r--profile/Trulux.sp103
-rw-r--r--profile/TruluxPlus.sp103
-rw-r--r--profile/afiles40
-rw-r--r--profile/applycal.c693
-rw-r--r--profile/cb2ti3.c244
-rw-r--r--profile/colprof.c1116
-rw-r--r--profile/example.sp132
-rw-r--r--profile/example121.sp147
-rw-r--r--profile/invprofcheck.c733
-rw-r--r--profile/kodak2ti3.c1273
-rw-r--r--profile/mppcheck.c588
-rw-r--r--profile/mppprof.c961
-rw-r--r--profile/printcal.c2320
-rw-r--r--profile/prof.h109
-rw-r--r--profile/profcheck.c1349
-rw-r--r--profile/profin.c1310
-rw-r--r--profile/profout.c2963
-rw-r--r--profile/simpprof.c433
-rw-r--r--profile/splitti3.c400
-rw-r--r--profile/txt2ti3.c830
-rw-r--r--profile/verify.c783
-rw-r--r--ref/3dap5k.sp103
-rw-r--r--ref/CIE_C.sp118
-rw-r--r--ref/CMP_DT_003.cht336
-rw-r--r--ref/CMP_Digital_Target-3.cht1210
-rw-r--r--ref/CMP_Digital_Target-3.cie591
-rw-r--r--ref/CMP_Digital_Target-3.ti2601
-rw-r--r--ref/CRT.ccss42
-rw-r--r--ref/ClayRGB1998.icmbin0 -> 580 bytes
-rw-r--r--ref/ColorChecker.cht59
-rw-r--r--ref/ColorChecker.cie39
-rw-r--r--ref/ColorChecker.ti254
-rw-r--r--ref/ColorCheckerDC.cht318
-rw-r--r--ref/ColorCheckerPassport.cht122
-rw-r--r--ref/ColorCheckerPassport.cie64
-rw-r--r--ref/ColorCheckerSG.cht203
-rw-r--r--ref/D50_0.0.sp132
-rw-r--r--ref/D50_0.1.sp132
-rw-r--r--ref/D50_0.3.sp132
-rw-r--r--ref/D50_0.5.sp132
-rw-r--r--ref/D50_0.7.sp132
-rw-r--r--ref/D50_1.0.sp132
-rw-r--r--ref/D50_1.2.sp132
-rw-r--r--ref/D50_1.5.sp132
-rw-r--r--ref/D50_1.7.sp132
-rw-r--r--ref/D50_2.0.sp132
-rw-r--r--ref/D50_2.5.sp132
-rw-r--r--ref/D50_3.0.sp132
-rw-r--r--ref/ECI2002.ti21578
-rw-r--r--ref/ECI2002R.ti21517
-rw-r--r--ref/FograStrip2.ti1120
-rw-r--r--ref/FograStrip2_2.ti275
-rw-r--r--ref/FograStrip3.ti1146
-rw-r--r--ref/FograStrip3_3.ti2101
-rw-r--r--ref/GTIPlus.sp64
-rw-r--r--ref/Hutchcolor.cht597
-rw-r--r--ref/LaserSoftDCPro.cht202
-rw-r--r--ref/License.txt662
-rw-r--r--ref/Makefile.am7
-rw-r--r--ref/Office.sp103
-rw-r--r--ref/QPcard_201.cht76
-rw-r--r--ref/QPcard_201.cie42
-rw-r--r--ref/QPcard_202.cht80
-rw-r--r--ref/QPcard_202.cie48
-rw-r--r--ref/ReadMe.txt61
-rw-r--r--ref/SOtele.sp23
-rw-r--r--ref/SpyderChecker.cht115
-rw-r--r--ref/SpyderChecker.cie62
-rw-r--r--ref/Trulux.sp103
-rw-r--r--ref/TruluxPlus.sp103
-rw-r--r--ref/afiles59
-rw-r--r--ref/ccxx.ti122
-rw-r--r--ref/example.sp132
-rw-r--r--ref/example121.sp147
-rw-r--r--ref/i1_RGB_Scan_1.4.cht341
-rw-r--r--ref/i1_RGB_Scan_1.4.ti2319
-rw-r--r--ref/it8.cht338
-rw-r--r--ref/lab2lab.icmbin0 -> 500 bytes
-rw-r--r--ref/linear.cal275
-rw-r--r--ref/sRGB.icmbin0 -> 3212 bytes
-rw-r--r--ref/strange.cal275
-rw-r--r--render/Jamfile31
-rw-r--r--render/License.txt662
-rw-r--r--render/Makefile.am13
-rw-r--r--render/Readme.txt10
-rw-r--r--render/afiles11
-rw-r--r--render/makecharts.ksh12
-rw-r--r--render/render.c2425
-rw-r--r--render/render.h239
-rw-r--r--render/screens.h811
-rw-r--r--render/thscreen.c474
-rw-r--r--render/thscreen.h156
-rw-r--r--render/timage.c682
-rw-r--r--rspl/Jamfile83
-rw-r--r--rspl/License.txt662
-rw-r--r--rspl/Makefile.am15
-rw-r--r--rspl/Readme.txt39
-rw-r--r--rspl/afiles34
-rw-r--r--rspl/c1.c396
-rw-r--r--rspl/c1df.c313
-rw-r--r--rspl/gam.c1220
-rw-r--r--rspl/gam.h131
-rw-r--r--rspl/mlbs.c605
-rw-r--r--rspl/mlbs.h77
-rw-r--r--rspl/opt.c725
-rw-r--r--rspl/rev.c6608
-rw-r--r--rspl/rev.h457
-rw-r--r--rspl/revbench.c306
-rw-r--r--rspl/rspl.c1511
-rw-r--r--rspl/rspl.h645
-rw-r--r--rspl/rspl1.c391
-rw-r--r--rspl/rspl1.h115
-rw-r--r--rspl/rspl_imp.h27
-rw-r--r--rspl/scat.c2861
-rw-r--r--rspl/scat2.c233
-rw-r--r--rspl/sm1.c88
-rw-r--r--rspl/sm2.c110
-rw-r--r--rspl/sm3.c110
-rw-r--r--rspl/smtmpp.c1203
-rw-r--r--rspl/smtnd.c1171
-rw-r--r--rspl/spline.c352
-rw-r--r--rspl/stest.c654
-rw-r--r--rspl/t2d.c1016
-rw-r--r--rspl/t2ddf.c517
-rw-r--r--rspl/t3d.c905
-rw-r--r--rspl/t3ddf.c570
-rw-r--r--rspl/tnd.c489
-rw-r--r--rspl/trnd.c275
-rw-r--r--scanin/CMP_DT_003.cht336
-rw-r--r--scanin/CMP_Digital_Target-3.cht1210
-rw-r--r--scanin/CMP_Digital_Target-3.cie591
-rw-r--r--scanin/CMP_Digital_Target-3.ti2601
-rw-r--r--scanin/ColorChecker.cht59
-rw-r--r--scanin/ColorChecker.cie39
-rw-r--r--scanin/ColorCheckerDC.cht318
-rw-r--r--scanin/ColorCheckerPassport.cht122
-rw-r--r--scanin/ColorCheckerPassport.cie64
-rw-r--r--scanin/ColorCheckerSG.cht203
-rw-r--r--scanin/Hutchcolor.cht597
-rw-r--r--scanin/Jamfile33
-rw-r--r--scanin/LaserSoftDCPro.cht202
-rw-r--r--scanin/License.txt662
-rw-r--r--scanin/Makefile.am19
-rw-r--r--scanin/QPcard_201.cht76
-rw-r--r--scanin/QPcard_201.cie42
-rw-r--r--scanin/QPcard_202.cht80
-rw-r--r--scanin/QPcard_202.cie48
-rw-r--r--scanin/Readme.txt8
-rw-r--r--scanin/SpyderChecker.cht115
-rw-r--r--scanin/SpyderChecker.cie62
-rw-r--r--scanin/afiles28
-rw-r--r--scanin/i1_RGB_Scan_1.4.cht341
-rw-r--r--scanin/it8.cht338
-rw-r--r--scanin/scanin.c1436
-rw-r--r--scanin/scanrd.c4659
-rw-r--r--scanin/scanrd.h125
-rw-r--r--scanin/scanrd_.h321
-rw-r--r--spectro/IntsLib_Readme.txt21
-rw-r--r--spectro/Jamfile254
-rw-r--r--spectro/License.txt662
-rw-r--r--spectro/License2.txt282
-rw-r--r--spectro/License3.txt674
-rw-r--r--spectro/LzmaDec.c993
-rw-r--r--spectro/LzmaDec.h231
-rw-r--r--spectro/LzmaTypes.h254
-rw-r--r--spectro/Makefile.OSX44
-rw-r--r--spectro/Makefile.SA183
-rw-r--r--spectro/Makefile.UNIX44
-rw-r--r--spectro/Makefile.WNT47
-rw-r--r--spectro/Makefile.am53
-rw-r--r--spectro/Readme.txt37
-rw-r--r--spectro/SOtele.sp23
-rw-r--r--spectro/afiles110
-rw-r--r--spectro/aglob.c141
-rw-r--r--spectro/aglob.h63
-rw-r--r--spectro/average.c405
-rw-r--r--spectro/ccxx.ti122
-rw-r--r--spectro/ccxxmake.c1446
-rw-r--r--spectro/chartread.c2993
-rw-r--r--spectro/colorhug.c1093
-rw-r--r--spectro/colorhug.h90
-rw-r--r--spectro/conv.c1471
-rw-r--r--spectro/conv.h297
-rw-r--r--spectro/dispcal.c5356
-rw-r--r--spectro/dispread.c969
-rw-r--r--spectro/dispsup.c2343
-rw-r--r--spectro/dispsup.h247
-rw-r--r--spectro/dispwin.c6321
-rw-r--r--spectro/dispwin.h327
-rw-r--r--spectro/dtp20.c1695
-rw-r--r--spectro/dtp20.h139
-rw-r--r--spectro/dtp22.c1110
-rw-r--r--spectro/dtp22.h105
-rw-r--r--spectro/dtp41.c1292
-rw-r--r--spectro/dtp41.h110
-rw-r--r--spectro/dtp51.c898
-rw-r--r--spectro/dtp51.h102
-rw-r--r--spectro/dtp92.c1325
-rw-r--r--spectro/dtp92.h103
-rw-r--r--spectro/fakeread.c1025
-rw-r--r--spectro/hcfr.c878
-rw-r--r--spectro/hcfr.h102
-rw-r--r--spectro/hidio.c866
-rw-r--r--spectro/hidio.h87
-rw-r--r--spectro/huey.c1663
-rw-r--r--spectro/huey.h134
-rw-r--r--spectro/i1d3.c3637
-rw-r--r--spectro/i1d3.h161
-rw-r--r--spectro/i1disp.c2591
-rw-r--r--spectro/i1disp.h172
-rw-r--r--spectro/i1pro.c809
-rw-r--r--spectro/i1pro.h56
-rw-r--r--spectro/i1pro_imp.c12093
-rw-r--r--spectro/i1pro_imp.h1376
-rw-r--r--spectro/icoms.c484
-rw-r--r--spectro/icoms.h484
-rw-r--r--spectro/icoms_nt.c563
-rw-r--r--spectro/icoms_ux.c739
-rw-r--r--spectro/ifiles14
-rw-r--r--spectro/illumread.c1232
-rw-r--r--spectro/inflate.c922
-rw-r--r--spectro/inst.c1359
-rw-r--r--spectro/inst.h999
-rw-r--r--spectro/instappsup.c556
-rw-r--r--spectro/instappsup.h100
-rw-r--r--spectro/instlib.ksh191
-rw-r--r--spectro/instlib.txt11
-rw-r--r--spectro/insttypeinst.h25
-rw-r--r--spectro/insttypes.c384
-rw-r--r--spectro/insttypes.h100
-rw-r--r--spectro/iusb.h131
-rw-r--r--spectro/linear.cal275
-rw-r--r--spectro/linear.sp23
-rw-r--r--spectro/mongoose.c4819
-rw-r--r--spectro/mongoose.h308
-rw-r--r--spectro/munki.c940
-rw-r--r--spectro/munki.h72
-rw-r--r--spectro/munki_imp.c9103
-rw-r--r--spectro/munki_imp.h1029
-rw-r--r--spectro/oemarch.c2610
-rw-r--r--spectro/oemarch.h102
-rw-r--r--spectro/oeminst.c276
-rw-r--r--spectro/pollem.c111
-rw-r--r--spectro/pollem.h50
-rw-r--r--spectro/spec2cie.c831
-rw-r--r--spectro/spotread.c2271
-rw-r--r--spectro/spyd2.c3808
-rw-r--r--spectro/spyd2.h168
-rw-r--r--spectro/spyd2PLD.h10
-rw-r--r--spectro/spyd2setup.h119
-rw-r--r--spectro/ss.c2109
-rw-r--r--spectro/ss.h115
-rw-r--r--spectro/ss_imp.c1943
-rw-r--r--spectro/ss_imp.h1335
-rw-r--r--spectro/strange.cal275
-rw-r--r--spectro/synthcal.c350
-rw-r--r--spectro/synthread.c691
-rw-r--r--spectro/usbio.c585
-rw-r--r--spectro/usbio.h247
-rw-r--r--spectro/usbio_lusb.c897
-rw-r--r--spectro/usbio_lx.c1069
-rw-r--r--spectro/usbio_nt.c898
-rw-r--r--spectro/usbio_ox.c986
-rw-r--r--spectro/vinflate.c972
-rw-r--r--spectro/webwin.c455
-rw-r--r--spectro/webwin.h31
-rw-r--r--spectro/xdg_bds.c1088
-rw-r--r--spectro/xdg_bds.h115
-rw-r--r--target/ColorChecker.ti254
-rw-r--r--target/ECI2002.ti21578
-rw-r--r--target/ECI2002R.ti21517
-rw-r--r--target/FograStrip2.ti1120
-rw-r--r--target/FograStrip2_2.ti275
-rw-r--r--target/FograStrip3.ti1146
-rw-r--r--target/FograStrip3_3.ti2101
-rw-r--r--target/Jamfile74
-rw-r--r--target/License.txt662
-rw-r--r--target/Makefile.am28
-rw-r--r--target/Readme.txt13
-rw-r--r--target/afiles32
-rw-r--r--target/alphix.c468
-rw-r--r--target/alphix.h118
-rw-r--r--target/filmtarg.c458
-rw-r--r--target/i1_RGB_Scan_1.4.ti2319
-rw-r--r--target/ifarp.c946
-rw-r--r--target/ifarp.h67
-rw-r--r--target/ofps.c10222
-rw-r--r--target/ofps.h438
-rw-r--r--target/ppoint.c1056
-rw-r--r--target/ppoint.h134
-rw-r--r--target/prand.c604
-rw-r--r--target/prand.h68
-rw-r--r--target/printtarg.c4300
-rw-r--r--target/randix.c166
-rw-r--r--target/randix.h41
-rw-r--r--target/simdlat.c1063
-rw-r--r--target/simdlat.h94
-rw-r--r--target/simplat.c1095
-rw-r--r--target/simplat.h86
-rw-r--r--target/targen.c2224
-rw-r--r--target/targen.h30
-rw-r--r--tiff/COPYRIGHT21
-rw-r--r--tiff/ChangeLog4590
-rw-r--r--tiff/HOWTO-RELEASE105
-rw-r--r--tiff/Jamfile73
-rw-r--r--tiff/Makefile.am56
-rw-r--r--tiff/Makefile.in842
-rw-r--r--tiff/Makefile.vc65
-rw-r--r--tiff/README59
-rw-r--r--tiff/README.vms12
-rw-r--r--tiff/RELEASE-DATE1
-rw-r--r--tiff/SConstruct171
-rw-r--r--tiff/TODO12
-rw-r--r--tiff/VERSION1
-rw-r--r--tiff/aclocal.m41059
-rw-r--r--tiff/afiles448
-rw-r--r--tiff/autogen.sh8
-rw-r--r--tiff/build/Makefile.am31
-rw-r--r--tiff/build/Makefile.in625
-rw-r--r--tiff/build/README3
-rw-r--r--tiff/config/compile142
-rw-r--r--tiff/config/config.guess1516
-rw-r--r--tiff/config/config.sub1622
-rw-r--r--tiff/config/depcomp530
-rw-r--r--tiff/config/install-sh401
-rw-r--r--tiff/config/ltmain.sh8745
-rw-r--r--tiff/config/missing360
-rw-r--r--tiff/config/mkinstalldirs158
-rw-r--r--tiff/configure21416
-rw-r--r--tiff/configure.ac703
-rw-r--r--tiff/configure.com1345
-rw-r--r--tiff/contrib/Makefile.am29
-rw-r--r--tiff/contrib/Makefile.in623
-rw-r--r--tiff/contrib/README2
-rw-r--r--tiff/contrib/acorn/Makefile.acorn165
-rw-r--r--tiff/contrib/acorn/Makefile.am28
-rw-r--r--tiff/contrib/acorn/Makefile.in421
-rw-r--r--tiff/contrib/acorn/ReadMe79
-rw-r--r--tiff/contrib/acorn/SetVars3
-rw-r--r--tiff/contrib/acorn/cleanlib5
-rw-r--r--tiff/contrib/acorn/convert175
-rw-r--r--tiff/contrib/acorn/install128
-rw-r--r--tiff/contrib/addtiffo/Makefile.am36
-rw-r--r--tiff/contrib/addtiffo/Makefile.in556
-rw-r--r--tiff/contrib/addtiffo/Makefile.vc28
-rw-r--r--tiff/contrib/addtiffo/README142
-rw-r--r--tiff/contrib/addtiffo/addtiffo.c176
-rw-r--r--tiff/contrib/addtiffo/tif_overview.c896
-rw-r--r--tiff/contrib/addtiffo/tif_ovrcache.c341
-rw-r--r--tiff/contrib/addtiffo/tif_ovrcache.h108
-rw-r--r--tiff/contrib/dbs/Makefile.am43
-rw-r--r--tiff/contrib/dbs/Makefile.in737
-rw-r--r--tiff/contrib/dbs/README7
-rw-r--r--tiff/contrib/dbs/tiff-bi.c91
-rw-r--r--tiff/contrib/dbs/tiff-grayscale.c146
-rw-r--r--tiff/contrib/dbs/tiff-palette.c283
-rw-r--r--tiff/contrib/dbs/tiff-rgb.c201
-rw-r--r--tiff/contrib/dbs/xtiff/Makefile.am43
-rw-r--r--tiff/contrib/dbs/xtiff/Makefile.in436
-rw-r--r--tiff/contrib/dbs/xtiff/README6
-rw-r--r--tiff/contrib/dbs/xtiff/patchlevel.h8
-rw-r--r--tiff/contrib/dbs/xtiff/xtiff.c1290
-rw-r--r--tiff/contrib/dbs/xtiff/xtifficon.h21
-rw-r--r--tiff/contrib/iptcutil/Makefile.am36
-rw-r--r--tiff/contrib/iptcutil/Makefile.in553
-rw-r--r--tiff/contrib/iptcutil/README25
-rw-r--r--tiff/contrib/iptcutil/iptcutil.c941
-rw-r--r--tiff/contrib/iptcutil/test.iptcbin0 -> 1107 bytes
-rw-r--r--tiff/contrib/iptcutil/test.txt32
-rw-r--r--tiff/contrib/mac-cw/Makefile.am27
-rw-r--r--tiff/contrib/mac-cw/Makefile.in420
-rw-r--r--tiff/contrib/mac-cw/Makefile.script72
-rw-r--r--tiff/contrib/mac-cw/README18
-rw-r--r--tiff/contrib/mac-cw/mac_main.c27
-rw-r--r--tiff/contrib/mac-cw/mac_main.h19
-rw-r--r--tiff/contrib/mac-cw/metrowerks.note84
-rw-r--r--tiff/contrib/mac-cw/mkg3_main.c21
-rw-r--r--tiff/contrib/mac-cw/version.h11
-rw-r--r--tiff/contrib/mac-mpw/BUILD.mpw47
-rw-r--r--tiff/contrib/mac-mpw/Makefile.am27
-rw-r--r--tiff/contrib/mac-mpw/Makefile.in420
-rw-r--r--tiff/contrib/mac-mpw/README20
-rw-r--r--tiff/contrib/mac-mpw/libtiff.make202
-rw-r--r--tiff/contrib/mac-mpw/mactrans.c63
-rw-r--r--tiff/contrib/mac-mpw/port.make53
-rw-r--r--tiff/contrib/mac-mpw/tools.make138
-rw-r--r--tiff/contrib/mac-mpw/top.make133
-rw-r--r--tiff/contrib/mfs/Makefile.am28
-rw-r--r--tiff/contrib/mfs/Makefile.in421
-rw-r--r--tiff/contrib/mfs/README37
-rw-r--r--tiff/contrib/mfs/mfs_file.c586
-rw-r--r--tiff/contrib/pds/Makefile.am28
-rw-r--r--tiff/contrib/pds/Makefile.in421
-rw-r--r--tiff/contrib/pds/README90
-rw-r--r--tiff/contrib/pds/tif_imageiter.c525
-rw-r--r--tiff/contrib/pds/tif_imageiter.h64
-rw-r--r--tiff/contrib/pds/tif_pdsdirread.c1131
-rw-r--r--tiff/contrib/pds/tif_pdsdirwrite.c971
-rw-r--r--tiff/contrib/ras/Makefile.am28
-rw-r--r--tiff/contrib/ras/Makefile.in421
-rw-r--r--tiff/contrib/ras/README10
-rw-r--r--tiff/contrib/ras/ras2tif.c254
-rw-r--r--tiff/contrib/ras/tif2ras.c344
-rw-r--r--tiff/contrib/stream/Makefile.am28
-rw-r--r--tiff/contrib/stream/Makefile.in421
-rw-r--r--tiff/contrib/stream/README30
-rw-r--r--tiff/contrib/stream/tiffstream.cpp238
-rw-r--r--tiff/contrib/stream/tiffstream.h69
-rw-r--r--tiff/contrib/tags/Makefile.am28
-rw-r--r--tiff/contrib/tags/Makefile.in421
-rw-r--r--tiff/contrib/tags/README132
-rw-r--r--tiff/contrib/tags/listtif.c39
-rw-r--r--tiff/contrib/tags/maketif.c77
-rw-r--r--tiff/contrib/tags/xtif_dir.c350
-rw-r--r--tiff/contrib/tags/xtiffio.h59
-rw-r--r--tiff/contrib/tags/xtiffiop.h72
-rw-r--r--tiff/contrib/win_dib/Makefile.am28
-rw-r--r--tiff/contrib/win_dib/Makefile.in421
-rw-r--r--tiff/contrib/win_dib/Makefile.w95134
-rw-r--r--tiff/contrib/win_dib/README.Tiffile31
-rw-r--r--tiff/contrib/win_dib/README.tiff2dib51
-rw-r--r--tiff/contrib/win_dib/Tiffile.cpp449
-rw-r--r--tiff/contrib/win_dib/tiff2dib.c379
-rw-r--r--tiff/html/Makefile.am84
-rw-r--r--tiff/html/Makefile.in725
-rw-r--r--tiff/html/TIFFTechNote2.html707
-rw-r--r--tiff/html/addingtags.html292
-rw-r--r--tiff/html/bugs.html63
-rw-r--r--tiff/html/build.html880
-rw-r--r--tiff/html/contrib.html209
-rw-r--r--tiff/html/document.html48
-rw-r--r--tiff/html/images.html41
-rw-r--r--tiff/html/images/Makefile.am46
-rw-r--r--tiff/html/images/Makefile.in487
-rw-r--r--tiff/html/images/back.gifbin0 -> 1000 bytes
-rw-r--r--tiff/html/images/bali.jpgbin0 -> 26152 bytes
-rw-r--r--tiff/html/images/cat.gifbin0 -> 12477 bytes
-rw-r--r--tiff/html/images/cover.jpgbin0 -> 20189 bytes
-rw-r--r--tiff/html/images/cramps.gifbin0 -> 13137 bytes
-rw-r--r--tiff/html/images/dave.gifbin0 -> 8220 bytes
-rw-r--r--tiff/html/images/info.gifbin0 -> 131 bytes
-rw-r--r--tiff/html/images/jello.jpgbin0 -> 13744 bytes
-rw-r--r--tiff/html/images/jim.gifbin0 -> 14493 bytes
-rw-r--r--tiff/html/images/note.gifbin0 -> 264 bytes
-rw-r--r--tiff/html/images/oxford.gifbin0 -> 6069 bytes
-rw-r--r--tiff/html/images/quad.jpgbin0 -> 23904 bytes
-rw-r--r--tiff/html/images/ring.gifbin0 -> 4275 bytes
-rw-r--r--tiff/html/images/smallliz.jpgbin0 -> 16463 bytes
-rw-r--r--tiff/html/images/strike.gifbin0 -> 5610 bytes
-rw-r--r--tiff/html/images/warning.gifbin0 -> 287 bytes
-rw-r--r--tiff/html/index.html123
-rw-r--r--tiff/html/internals.html572
-rw-r--r--tiff/html/intro.html68
-rw-r--r--tiff/html/libtiff.html747
-rw-r--r--tiff/html/man/Makefile.am119
-rw-r--r--tiff/html/man/Makefile.in556
-rw-r--r--tiff/html/man/TIFFClose.3tiff.html87
-rw-r--r--tiff/html/man/TIFFDataWidth.3tiff.html98
-rw-r--r--tiff/html/man/TIFFError.3tiff.html106
-rw-r--r--tiff/html/man/TIFFFlush.3tiff.html113
-rw-r--r--tiff/html/man/TIFFGetField.3tiff.html1446
-rw-r--r--tiff/html/man/TIFFOpen.3tiff.html421
-rw-r--r--tiff/html/man/TIFFPrintDirectory.3tiff.html225
-rw-r--r--tiff/html/man/TIFFRGBAImage.3tiff.html319
-rw-r--r--tiff/html/man/TIFFReadDirectory.3tiff.html218
-rw-r--r--tiff/html/man/TIFFReadEncodedStrip.3tiff.html133
-rw-r--r--tiff/html/man/TIFFReadEncodedTile.3tiff.html130
-rw-r--r--tiff/html/man/TIFFReadRGBAImage.3tiff.html301
-rw-r--r--tiff/html/man/TIFFReadRGBAStrip.3tiff.html208
-rw-r--r--tiff/html/man/TIFFReadRGBATile.3tiff.html261
-rw-r--r--tiff/html/man/TIFFReadRawStrip.3tiff.html109
-rw-r--r--tiff/html/man/TIFFReadRawTile.3tiff.html111
-rw-r--r--tiff/html/man/TIFFReadScanline.3tiff.html157
-rw-r--r--tiff/html/man/TIFFReadTile.3tiff.html133
-rw-r--r--tiff/html/man/TIFFSetDirectory.3tiff.html122
-rw-r--r--tiff/html/man/TIFFSetField.3tiff.html1362
-rw-r--r--tiff/html/man/TIFFWarning.3tiff.html108
-rw-r--r--tiff/html/man/TIFFWriteDirectory.3tiff.html176
-rw-r--r--tiff/html/man/TIFFWriteEncodedStrip.3tiff.html153
-rw-r--r--tiff/html/man/TIFFWriteEncodedTile.3tiff.html147
-rw-r--r--tiff/html/man/TIFFWriteRawStrip.3tiff.html144
-rw-r--r--tiff/html/man/TIFFWriteRawTile.3tiff.html128
-rw-r--r--tiff/html/man/TIFFWriteScanline.3tiff.html206
-rw-r--r--tiff/html/man/TIFFWriteTile.3tiff.html115
-rw-r--r--tiff/html/man/TIFFbuffer.3tiff.html116
-rw-r--r--tiff/html/man/TIFFcodec.3tiff.html116
-rw-r--r--tiff/html/man/TIFFcolor.3tiff.html975
-rw-r--r--tiff/html/man/TIFFmemory.3tiff.html110
-rw-r--r--tiff/html/man/TIFFquery.3tiff.html148
-rw-r--r--tiff/html/man/TIFFsize.3tiff.html95
-rw-r--r--tiff/html/man/TIFFstrip.3tiff.html129
-rw-r--r--tiff/html/man/TIFFswab.3tiff.html110
-rw-r--r--tiff/html/man/TIFFtile.3tiff.html141
-rw-r--r--tiff/html/man/fax2ps.1.html252
-rw-r--r--tiff/html/man/fax2tiff.1.html607
-rw-r--r--tiff/html/man/gif2tiff.1.html141
-rw-r--r--tiff/html/man/index.html64
-rw-r--r--tiff/html/man/libtiff.3tiff.html3137
-rw-r--r--tiff/html/man/pal2rgb.1.html189
-rw-r--r--tiff/html/man/ppm2tiff.1.html141
-rw-r--r--tiff/html/man/ras2tiff.1.html139
-rw-r--r--tiff/html/man/raw2tiff.1.html510
-rw-r--r--tiff/html/man/rgb2ycbcr.1.html155
-rw-r--r--tiff/html/man/sgi2tiff.1.html147
-rw-r--r--tiff/html/man/thumbnail.1.html148
-rw-r--r--tiff/html/man/tiff2bw.1.html161
-rw-r--r--tiff/html/man/tiff2pdf.1.html609
-rw-r--r--tiff/html/man/tiff2ps.1.html532
-rw-r--r--tiff/html/man/tiff2rgba.1.html162
-rw-r--r--tiff/html/man/tiffcmp.1.html156
-rw-r--r--tiff/html/man/tiffcp.1.html536
-rw-r--r--tiff/html/man/tiffcrop.1.html851
-rw-r--r--tiff/html/man/tiffdither.1.html183
-rw-r--r--tiff/html/man/tiffdump.1.html145
-rw-r--r--tiff/html/man/tiffgt.1.html551
-rw-r--r--tiff/html/man/tiffinfo.1.html196
-rw-r--r--tiff/html/man/tiffmedian.1.html183
-rw-r--r--tiff/html/man/tiffset.1.html176
-rw-r--r--tiff/html/man/tiffsplit.1.html102
-rw-r--r--tiff/html/man/tiffsv.1.html207
-rw-r--r--tiff/html/misc.html116
-rw-r--r--tiff/html/support.html655
-rw-r--r--tiff/html/tools.html164
-rw-r--r--tiff/html/v3.4beta007.html112
-rw-r--r--tiff/html/v3.4beta016.html122
-rw-r--r--tiff/html/v3.4beta018.html84
-rw-r--r--tiff/html/v3.4beta024.html139
-rw-r--r--tiff/html/v3.4beta028.html146
-rw-r--r--tiff/html/v3.4beta029.html86
-rw-r--r--tiff/html/v3.4beta031.html94
-rw-r--r--tiff/html/v3.4beta032.html90
-rw-r--r--tiff/html/v3.4beta033.html82
-rw-r--r--tiff/html/v3.4beta034.html68
-rw-r--r--tiff/html/v3.4beta035.html63
-rw-r--r--tiff/html/v3.4beta036.html117
-rw-r--r--tiff/html/v3.5.1.html75
-rw-r--r--tiff/html/v3.5.2.html108
-rw-r--r--tiff/html/v3.5.3.html132
-rw-r--r--tiff/html/v3.5.4.html88
-rw-r--r--tiff/html/v3.5.5.html155
-rw-r--r--tiff/html/v3.5.6-beta.html185
-rw-r--r--tiff/html/v3.5.7.html259
-rw-r--r--tiff/html/v3.6.0.html434
-rw-r--r--tiff/html/v3.6.1.html199
-rw-r--r--tiff/html/v3.7.0.html144
-rw-r--r--tiff/html/v3.7.0alpha.html249
-rw-r--r--tiff/html/v3.7.0beta.html162
-rw-r--r--tiff/html/v3.7.0beta2.html131
-rw-r--r--tiff/html/v3.7.1.html233
-rw-r--r--tiff/html/v3.7.2.html222
-rw-r--r--tiff/html/v3.7.3.html230
-rw-r--r--tiff/html/v3.7.4.html133
-rw-r--r--tiff/html/v3.8.0.html199
-rw-r--r--tiff/html/v3.8.1.html217
-rw-r--r--tiff/html/v3.8.2.html137
-rw-r--r--tiff/html/v3.9.0beta.html304
-rw-r--r--tiff/html/v3.9.1.html115
-rw-r--r--tiff/html/v3.9.2.html122
-rw-r--r--tiff/libtiff/Makefile.am143
-rw-r--r--tiff/libtiff/Makefile.in887
-rw-r--r--tiff/libtiff/Makefile.vc102
-rw-r--r--tiff/libtiff/SConstruct73
-rw-r--r--tiff/libtiff/libtiff.def140
-rw-r--r--tiff/libtiff/mkg3states.c451
-rw-r--r--tiff/libtiff/t4.h292
-rw-r--r--tiff/libtiff/tif_acorn.c526
-rw-r--r--tiff/libtiff/tif_apple.c281
-rw-r--r--tiff/libtiff/tif_atari.c250
-rw-r--r--tiff/libtiff/tif_aux.c290
-rw-r--r--tiff/libtiff/tif_close.c126
-rw-r--r--tiff/libtiff/tif_codec.c160
-rw-r--r--tiff/libtiff/tif_color.c282
-rw-r--r--tiff/libtiff/tif_compress.c295
-rw-r--r--tiff/libtiff/tif_config.h-vms46
-rw-r--r--tiff/libtiff/tif_config.h.in309
-rw-r--r--tiff/libtiff/tif_config.vc.h63
-rw-r--r--tiff/libtiff/tif_config.wince.h74
-rw-r--r--tiff/libtiff/tif_dir.c1389
-rw-r--r--tiff/libtiff/tif_dir.h211
-rw-r--r--tiff/libtiff/tif_dirinfo.c888
-rw-r--r--tiff/libtiff/tif_dirread.c2081
-rw-r--r--tiff/libtiff/tif_dirwrite.c1414
-rw-r--r--tiff/libtiff/tif_dumpmode.c126
-rw-r--r--tiff/libtiff/tif_error.c80
-rw-r--r--tiff/libtiff/tif_extension.c118
-rw-r--r--tiff/libtiff/tif_fax3.c1626
-rw-r--r--tiff/libtiff/tif_fax3.h532
-rw-r--r--tiff/libtiff/tif_fax3sm.c1253
-rw-r--r--tiff/libtiff/tif_flush.c74
-rw-r--r--tiff/libtiff/tif_getimage.c2676
-rw-r--r--tiff/libtiff/tif_jbig.c385
-rw-r--r--tiff/libtiff/tif_jpeg.c2065
-rw-r--r--tiff/libtiff/tif_luv.c1629
-rw-r--r--tiff/libtiff/tif_lzw.c1129
-rw-r--r--tiff/libtiff/tif_msdos.c193
-rw-r--r--tiff/libtiff/tif_next.c154
-rw-r--r--tiff/libtiff/tif_ojpeg.c2438
-rw-r--r--tiff/libtiff/tif_open.c695
-rw-r--r--tiff/libtiff/tif_packbits.c300
-rw-r--r--tiff/libtiff/tif_pixarlog.c1371
-rw-r--r--tiff/libtiff/tif_predict.c736
-rw-r--r--tiff/libtiff/tif_predict.h77
-rw-r--r--tiff/libtiff/tif_print.c646
-rw-r--r--tiff/libtiff/tif_read.c750
-rw-r--r--tiff/libtiff/tif_stream.cxx295
-rw-r--r--tiff/libtiff/tif_strip.c370
-rw-r--r--tiff/libtiff/tif_swab.c242
-rw-r--r--tiff/libtiff/tif_thunder.c165
-rw-r--r--tiff/libtiff/tif_tile.c280
-rw-r--r--tiff/libtiff/tif_unix.c300
-rw-r--r--tiff/libtiff/tif_version.c40
-rw-r--r--tiff/libtiff/tif_warning.c81
-rw-r--r--tiff/libtiff/tif_win3.c232
-rw-r--r--tiff/libtiff/tif_win32.c408
-rw-r--r--tiff/libtiff/tif_write.c718
-rw-r--r--tiff/libtiff/tif_zip.c419
-rw-r--r--tiff/libtiff/tiff.h654
-rw-r--r--tiff/libtiff/tiffconf.h.in103
-rw-r--r--tiff/libtiff/tiffconf.vc.h116
-rw-r--r--tiff/libtiff/tiffconf.wince.h136
-rw-r--r--tiff/libtiff/tiffio.h526
-rw-r--r--tiff/libtiff/tiffio.hxx49
-rw-r--r--tiff/libtiff/tiffiop.h350
-rw-r--r--tiff/libtiff/tiffvers.h9
-rw-r--r--tiff/libtiff/uvcode.h180
-rw-r--r--tiff/m4/acinclude.m4669
-rw-r--r--tiff/m4/libtool.m47437
-rw-r--r--tiff/m4/ltoptions.m4369
-rw-r--r--tiff/m4/ltsugar.m4123
-rw-r--r--tiff/m4/ltversion.m423
-rw-r--r--tiff/m4/lt~obsolete.m498
-rw-r--r--tiff/man/Makefile.am92
-rw-r--r--tiff/man/Makefile.in602
-rw-r--r--tiff/man/TIFFClose.3tiff53
-rw-r--r--tiff/man/TIFFDataWidth.3tiff74
-rw-r--r--tiff/man/TIFFError.3tiff69
-rw-r--r--tiff/man/TIFFFlush.3tiff64
-rw-r--r--tiff/man/TIFFGetField.3tiff232
-rw-r--r--tiff/man/TIFFOpen.3tiff279
-rw-r--r--tiff/man/TIFFPrintDirectory.3tiff70
-rw-r--r--tiff/man/TIFFRGBAImage.3tiff286
-rw-r--r--tiff/man/TIFFReadDirectory.3tiff164
-rw-r--r--tiff/man/TIFFReadEncodedStrip.3tiff78
-rw-r--r--tiff/man/TIFFReadEncodedTile.3tiff76
-rw-r--r--tiff/man/TIFFReadRGBAImage.3tiff218
-rw-r--r--tiff/man/TIFFReadRGBAStrip.3tiff170
-rw-r--r--tiff/man/TIFFReadRGBATile.3tiff171
-rw-r--r--tiff/man/TIFFReadRawStrip.3tiff64
-rw-r--r--tiff/man/TIFFReadRawTile.3tiff65
-rw-r--r--tiff/man/TIFFReadScanline.3tiff94
-rw-r--r--tiff/man/TIFFReadTile.3tiff84
-rw-r--r--tiff/man/TIFFSetDirectory.3tiff79
-rw-r--r--tiff/man/TIFFSetField.3tiff217
-rw-r--r--tiff/man/TIFFWarning.3tiff70
-rw-r--r--tiff/man/TIFFWriteDirectory.3tiff138
-rw-r--r--tiff/man/TIFFWriteEncodedStrip.3tiff102
-rw-r--r--tiff/man/TIFFWriteEncodedTile.3tiff96
-rw-r--r--tiff/man/TIFFWriteRawStrip.3tiff96
-rw-r--r--tiff/man/TIFFWriteRawTile.3tiff84
-rw-r--r--tiff/man/TIFFWriteScanline.3tiff154
-rw-r--r--tiff/man/TIFFWriteTile.3tiff77
-rw-r--r--tiff/man/TIFFbuffer.3tiff77
-rw-r--r--tiff/man/TIFFcodec.3tiff82
-rw-r--r--tiff/man/TIFFcolor.3tiff268
-rw-r--r--tiff/man/TIFFmemory.3tiff90
-rw-r--r--tiff/man/TIFFquery.3tiff142
-rw-r--r--tiff/man/TIFFsize.3tiff59
-rw-r--r--tiff/man/TIFFstrip.3tiff99
-rw-r--r--tiff/man/TIFFswab.3tiff80
-rw-r--r--tiff/man/TIFFtile.3tiff131
-rw-r--r--tiff/man/bmp2tiff.185
-rw-r--r--tiff/man/fax2ps.1159
-rw-r--r--tiff/man/fax2tiff.1286
-rw-r--r--tiff/man/gif2tiff.181
-rw-r--r--tiff/man/libtiff.3tiff536
-rw-r--r--tiff/man/pal2rgb.1111
-rw-r--r--tiff/man/ppm2tiff.1105
-rw-r--r--tiff/man/ras2tiff.196
-rw-r--r--tiff/man/raw2tiff.1196
-rw-r--r--tiff/man/rgb2ycbcr.199
-rw-r--r--tiff/man/sgi2tiff.193
-rw-r--r--tiff/man/thumbnail.190
-rw-r--r--tiff/man/tiff2bw.194
-rw-r--r--tiff/man/tiff2pdf.1251
-rw-r--r--tiff/man/tiff2ps.1268
-rw-r--r--tiff/man/tiff2rgba.197
-rw-r--r--tiff/man/tiffcmp.187
-rw-r--r--tiff/man/tiffcp.1291
-rw-r--r--tiff/man/tiffcrop.1571
-rw-r--r--tiff/man/tiffdither.1132
-rw-r--r--tiff/man/tiffdump.181
-rw-r--r--tiff/man/tiffgt.1245
-rw-r--r--tiff/man/tiffinfo.188
-rw-r--r--tiff/man/tiffmedian.1112
-rw-r--r--tiff/man/tiffset.182
-rw-r--r--tiff/man/tiffsplit.169
-rw-r--r--tiff/man/tiffsv.1142
-rw-r--r--tiff/nmake.opt218
-rw-r--r--tiff/port/Makefile.am31
-rw-r--r--tiff/port/Makefile.in555
-rw-r--r--tiff/port/Makefile.vc43
-rw-r--r--tiff/port/dummy.c19
-rw-r--r--tiff/port/getopt.c131
-rw-r--r--tiff/port/lfind.c69
-rw-r--r--tiff/port/libport.h58
-rw-r--r--tiff/port/strcasecmp.c57
-rw-r--r--tiff/port/strtoul.c116
-rw-r--r--tiff/test/Makefile.am46
-rw-r--r--tiff/test/Makefile.in845
-rw-r--r--tiff/test/ascii_tag.c177
-rw-r--r--tiff/test/check_tag.c79
-rw-r--r--tiff/test/long_tag.c161
-rw-r--r--tiff/test/short_tag.c187
-rw-r--r--tiff/test/strip.c298
-rw-r--r--tiff/test/strip_rw.c162
-rw-r--r--tiff/test/test_arrays.c836
-rw-r--r--tiff/test/test_arrays.h70
-rw-r--r--tiff/tools/Jamfile20
-rw-r--r--tiff/tools/Makefile.am145
-rw-r--r--tiff/tools/Makefile.in876
-rw-r--r--tiff/tools/Makefile.vc51
-rw-r--r--tiff/tools/bmp2tiff.c850
-rw-r--r--tiff/tools/fax2ps.c446
-rw-r--r--tiff/tools/fax2tiff.c465
-rw-r--r--tiff/tools/gif2tiff.c522
-rw-r--r--tiff/tools/pal2rgb.c431
-rw-r--r--tiff/tools/ppm2tiff.c362
-rw-r--r--tiff/tools/ras2tiff.c306
-rw-r--r--tiff/tools/rasterfile.h49
-rw-r--r--tiff/tools/raw2tiff.c647
-rw-r--r--tiff/tools/rgb2ycbcr.c382
-rw-r--r--tiff/tools/sgi2tiff.c335
-rw-r--r--tiff/tools/sgisv.c316
-rw-r--r--tiff/tools/thumbnail.c639
-rw-r--r--tiff/tools/tiff2bw.c467
-rw-r--r--tiff/tools/tiff2pdf.c5405
-rw-r--r--tiff/tools/tiff2ps.c2370
-rw-r--r--tiff/tools/tiff2rgba.c548
-rw-r--r--tiff/tools/tiffcmp.c640
-rw-r--r--tiff/tools/tiffcp.c1770
-rw-r--r--tiff/tools/tiffcrop.c9012
-rw-r--r--tiff/tools/tiffdither.c332
-rw-r--r--tiff/tools/tiffdump.c785
-rw-r--r--tiff/tools/tiffgt.c462
-rw-r--r--tiff/tools/tiffinfo.c456
-rw-r--r--tiff/tools/tiffmedian.c902
-rw-r--r--tiff/tools/tiffset.c325
-rw-r--r--tiff/tools/tiffsplit.c297
-rw-r--r--tiff/tools/ycbcr.c168
-rw-r--r--ttbd.txt327
-rw-r--r--tweak/Jamfile26
-rw-r--r--tweak/License.txt662
-rw-r--r--tweak/Makefile.am11
-rw-r--r--tweak/Readme.txt5
-rw-r--r--tweak/afiles5
-rw-r--r--tweak/refine.c1269
-rw-r--r--ucmm/Jamfile26
-rw-r--r--ucmm/Makefile.am9
-rw-r--r--ucmm/afiles4
-rw-r--r--ucmm/ucmm.c1086
-rw-r--r--ucmm/ucmm.h98
-rw-r--r--usb/45-Argyll.rules62
-rw-r--r--usb/55-Argyll.rules90
-rw-r--r--usb/Argyll9
-rw-r--r--usb/Argyll.kext/Info.plist30
-rw-r--r--usb/Argyll.usermap53
-rw-r--r--usb/ArgyllCMS.cat3
-rw-r--r--usb/ArgyllCMS.inf213
-rw-r--r--usb/ArgyllCMS.inf.d34
-rw-r--r--usb/ArgyllCMS.inf.t111
-rw-r--r--usb/ArgyllCMS_x64.cat3
-rw-r--r--usb/Jamfile52
-rw-r--r--usb/Readme.txt8
-rw-r--r--usb/afiles60
-rw-r--r--usb/bin/amd64/libusb0.sysbin0 -> 52832 bytes
-rw-r--r--usb/bin/ia64/libusb0.sysbin0 -> 110176 bytes
-rw-r--r--usb/bin/libusb-win32-bin-README.txt27
-rw-r--r--usb/bin/x86/libusb0.sysbin0 -> 42592 bytes
-rw-r--r--usb/binfiles.lx4
-rw-r--r--usb/binfiles.msw6
-rw-r--r--usb/binfiles.osx2
-rw-r--r--usb/driver/AUTHORS.txt16
-rw-r--r--usb/driver/COPYING_GPL.txt674
-rw-r--r--usb/driver/LICENSE.txt9
-rw-r--r--usb/driver/Makefile261
-rw-r--r--usb/driver/README.txt12
-rw-r--r--usb/driver/abort_endpoint.c56
-rw-r--r--usb/driver/claim_interface.c89
-rw-r--r--usb/driver/clear_feature.c64
-rw-r--r--usb/driver/dispatch.c99
-rw-r--r--usb/driver/driver_api.h400
-rw-r--r--usb/driver/driver_debug.c75
-rw-r--r--usb/driver/driver_debug.h30
-rw-r--r--usb/driver/driver_registry.c376
-rw-r--r--usb/driver/get_configuration.c56
-rw-r--r--usb/driver/get_descriptor.c289
-rw-r--r--usb/driver/get_interface.c109
-rw-r--r--usb/driver/get_status.c74
-rw-r--r--usb/driver/ioctl.c795
-rw-r--r--usb/driver/libusb-win32-README-1.2.6.0.txt239
-rw-r--r--usb/driver/libusb_driver.c971
-rw-r--r--usb/driver/libusb_driver.h429
-rw-r--r--usb/driver/libusb_driver_rc.rc25
-rw-r--r--usb/driver/lusb_defdi_guids.h45
-rw-r--r--usb/driver/pnp.c302
-rw-r--r--usb/driver/power.c269
-rw-r--r--usb/driver/release_interface.c105
-rw-r--r--usb/driver/reset_device.c56
-rw-r--r--usb/driver/reset_endpoint.c56
-rw-r--r--usb/driver/set_configuration.c205
-rw-r--r--usb/driver/set_descriptor.c71
-rw-r--r--usb/driver/set_feature.c67
-rw-r--r--usb/driver/set_interface.c124
-rw-r--r--usb/driver/transfer.c1493
-rw-r--r--usb/driver/usbd.def35
-rw-r--r--usb/driver/usbdlib_gcc.h310
-rw-r--r--usb/driver/vendor_request.c143
-rw-r--r--usb/install_kext.sh6
-rw-r--r--xicc/Jamfile172
-rw-r--r--xicc/License.txt662
-rw-r--r--xicc/Makefile.am28
-rw-r--r--xicc/Readme.txt15
-rw-r--r--xicc/afiles68
-rw-r--r--xicc/cam02.c1279
-rw-r--r--xicc/cam02.h208
-rw-r--r--xicc/cam02plot.c845
-rw-r--r--xicc/cam02ref.h621
-rw-r--r--xicc/cam02test.c1325
-rw-r--r--xicc/cam97s3.c596
-rw-r--r--xicc/cam97s3.h169
-rw-r--r--xicc/cam97test.c456
-rw-r--r--xicc/ccmx.c766
-rw-r--r--xicc/ccmx.h120
-rw-r--r--xicc/ccss.c636
-rw-r--r--xicc/ccss.h112
-rw-r--r--xicc/ccttest.c306
-rw-r--r--xicc/cgatsplot.c248
-rw-r--r--xicc/cv.c136
-rw-r--r--xicc/cvtest.c411
-rw-r--r--xicc/example.sp130
-rw-r--r--xicc/extracticc.c219
-rw-r--r--xicc/extractttag.c203
-rw-r--r--xicc/fakeCMY.c493
-rw-r--r--xicc/fbview.c312
-rw-r--r--xicc/iccgamut.c811
-rw-r--r--xicc/iccjpeg.c271
-rw-r--r--xicc/iccjpeg.h73
-rw-r--r--xicc/icheck.c532
-rw-r--r--xicc/monctest.c278
-rw-r--r--xicc/moncurve.c668
-rw-r--r--xicc/moncurve.h121
-rw-r--r--xicc/mpp.c4446
-rw-r--r--xicc/mpp.h268
-rw-r--r--xicc/mpplu.c1355
-rw-r--r--xicc/revfix.c796
-rw-r--r--xicc/specplot.c370
-rw-r--r--xicc/specsubsamp.c232
-rw-r--r--xicc/spectest.c750
-rw-r--r--xicc/spectest2.c270
-rw-r--r--xicc/tiffgamut.c1300
-rw-r--r--xicc/tiffgmts.c1187
-rw-r--r--xicc/transplot.c279
-rw-r--r--xicc/xcal.c496
-rw-r--r--xicc/xcal.h78
-rw-r--r--xicc/xcam.c214
-rw-r--r--xicc/xcam.h82
-rw-r--r--xicc/xcolorants.c768
-rw-r--r--xicc/xcolorants.h326
-rw-r--r--xicc/xcolorantslu.c228
-rw-r--r--xicc/xdevlin.c299
-rw-r--r--xicc/xdevlin.h96
-rw-r--r--xicc/xdgb.c109
-rw-r--r--xicc/xdgb.h71
-rw-r--r--xicc/xfbview.c703
-rw-r--r--xicc/xfit.c2829
-rw-r--r--xicc/xfit.h239
-rw-r--r--xicc/xicc.c3607
-rw-r--r--xicc/xicc.h945
-rw-r--r--xicc/xicclu.c1149
-rw-r--r--xicc/xlut.c4271
-rw-r--r--xicc/xlutfix.c1306
-rw-r--r--xicc/xmatrix.c2022
-rw-r--r--xicc/xmono.c324
-rw-r--r--xicc/xspect.c4714
-rw-r--r--xicc/xspect.h430
-rw-r--r--xicc/xutils.c294
-rw-r--r--xicc/xutils.h69
-rw-r--r--ziparch.sh96
1695 files changed, 795790 insertions, 0 deletions
diff --git a/.pc/.quilt_patches b/.pc/.quilt_patches
new file mode 100644
index 0000000..6857a8d
--- /dev/null
+++ b/.pc/.quilt_patches
@@ -0,0 +1 @@
+debian/patches
diff --git a/.pc/.quilt_series b/.pc/.quilt_series
new file mode 100644
index 0000000..c206706
--- /dev/null
+++ b/.pc/.quilt_series
@@ -0,0 +1 @@
+series
diff --git a/.pc/.version b/.pc/.version
new file mode 100644
index 0000000..0cfbf08
--- /dev/null
+++ b/.pc/.version
@@ -0,0 +1 @@
+2
diff --git a/.pc/01_autotools-support.diff/Makefile.am b/.pc/01_autotools-support.diff/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/Makefile.am
diff --git a/.pc/01_autotools-support.diff/Makefile.shared b/.pc/01_autotools-support.diff/Makefile.shared
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/Makefile.shared
diff --git a/.pc/01_autotools-support.diff/aclocal.m4 b/.pc/01_autotools-support.diff/aclocal.m4
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/aclocal.m4
diff --git a/.pc/01_autotools-support.diff/cgats/Makefile.am b/.pc/01_autotools-support.diff/cgats/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/cgats/Makefile.am
diff --git a/.pc/01_autotools-support.diff/config.guess b/.pc/01_autotools-support.diff/config.guess
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/config.guess
diff --git a/.pc/01_autotools-support.diff/config.h.in b/.pc/01_autotools-support.diff/config.h.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/config.h.in
diff --git a/.pc/01_autotools-support.diff/config.sub b/.pc/01_autotools-support.diff/config.sub
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/config.sub
diff --git a/.pc/01_autotools-support.diff/configure b/.pc/01_autotools-support.diff/configure
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/configure
diff --git a/.pc/01_autotools-support.diff/configure.ac b/.pc/01_autotools-support.diff/configure.ac
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/configure.ac
diff --git a/.pc/01_autotools-support.diff/depcomp b/.pc/01_autotools-support.diff/depcomp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/depcomp
diff --git a/.pc/01_autotools-support.diff/doc/Makefile.am b/.pc/01_autotools-support.diff/doc/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/doc/Makefile.am
diff --git a/.pc/01_autotools-support.diff/gamut/Makefile.am b/.pc/01_autotools-support.diff/gamut/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/gamut/Makefile.am
diff --git a/.pc/01_autotools-support.diff/h/Makefile.am b/.pc/01_autotools-support.diff/h/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/h/Makefile.am
diff --git a/.pc/01_autotools-support.diff/icc/Makefile.am b/.pc/01_autotools-support.diff/icc/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/icc/Makefile.am
diff --git a/.pc/01_autotools-support.diff/imdi/Makefile.am b/.pc/01_autotools-support.diff/imdi/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/imdi/Makefile.am
diff --git a/.pc/01_autotools-support.diff/imdi/imdi_k.h b/.pc/01_autotools-support.diff/imdi/imdi_k.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/imdi/imdi_k.h
diff --git a/.pc/01_autotools-support.diff/install-sh b/.pc/01_autotools-support.diff/install-sh
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/install-sh
diff --git a/.pc/01_autotools-support.diff/jcnf/Makefile.am b/.pc/01_autotools-support.diff/jcnf/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/jcnf/Makefile.am
diff --git a/.pc/01_autotools-support.diff/jcnf/yajl/Makefile.am b/.pc/01_autotools-support.diff/jcnf/yajl/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/jcnf/yajl/Makefile.am
diff --git a/.pc/01_autotools-support.diff/link/Makefile.am b/.pc/01_autotools-support.diff/link/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/link/Makefile.am
diff --git a/.pc/01_autotools-support.diff/m4/libtool.m4 b/.pc/01_autotools-support.diff/m4/libtool.m4
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/m4/libtool.m4
diff --git a/.pc/01_autotools-support.diff/m4/ltoptions.m4 b/.pc/01_autotools-support.diff/m4/ltoptions.m4
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/m4/ltoptions.m4
diff --git a/.pc/01_autotools-support.diff/m4/ltsugar.m4 b/.pc/01_autotools-support.diff/m4/ltsugar.m4
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/m4/ltsugar.m4
diff --git a/.pc/01_autotools-support.diff/m4/ltversion.m4 b/.pc/01_autotools-support.diff/m4/ltversion.m4
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/m4/ltversion.m4
diff --git a/.pc/01_autotools-support.diff/m4/lt~obsolete.m4 b/.pc/01_autotools-support.diff/m4/lt~obsolete.m4
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/m4/lt~obsolete.m4
diff --git a/.pc/01_autotools-support.diff/missing b/.pc/01_autotools-support.diff/missing
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/missing
diff --git a/.pc/01_autotools-support.diff/numlib/Makefile.am b/.pc/01_autotools-support.diff/numlib/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/numlib/Makefile.am
diff --git a/.pc/01_autotools-support.diff/plot/Makefile.am b/.pc/01_autotools-support.diff/plot/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/plot/Makefile.am
diff --git a/.pc/01_autotools-support.diff/profile/Makefile.am b/.pc/01_autotools-support.diff/profile/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/profile/Makefile.am
diff --git a/.pc/01_autotools-support.diff/ref/Makefile.am b/.pc/01_autotools-support.diff/ref/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/ref/Makefile.am
diff --git a/.pc/01_autotools-support.diff/render/Makefile.am b/.pc/01_autotools-support.diff/render/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/render/Makefile.am
diff --git a/.pc/01_autotools-support.diff/rspl/Makefile.am b/.pc/01_autotools-support.diff/rspl/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/rspl/Makefile.am
diff --git a/.pc/01_autotools-support.diff/scanin/Makefile.am b/.pc/01_autotools-support.diff/scanin/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/scanin/Makefile.am
diff --git a/.pc/01_autotools-support.diff/spectro/Makefile.am b/.pc/01_autotools-support.diff/spectro/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/spectro/Makefile.am
diff --git a/.pc/01_autotools-support.diff/target/Makefile.am b/.pc/01_autotools-support.diff/target/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/target/Makefile.am
diff --git a/.pc/01_autotools-support.diff/tweak/Makefile.am b/.pc/01_autotools-support.diff/tweak/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/tweak/Makefile.am
diff --git a/.pc/01_autotools-support.diff/ucmm/Makefile.am b/.pc/01_autotools-support.diff/ucmm/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/ucmm/Makefile.am
diff --git a/.pc/01_autotools-support.diff/xicc/Makefile.am b/.pc/01_autotools-support.diff/xicc/Makefile.am
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/01_autotools-support.diff/xicc/Makefile.am
diff --git a/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/changelog b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/changelog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/changelog
diff --git a/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/compat b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/compat
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/compat
diff --git a/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/control b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/control
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/control
diff --git a/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/copyright b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/copyright
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/copyright
diff --git a/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/install b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/install
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/install
diff --git a/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/rules b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/rules
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.pc/02_firmware-package-builder.diff/firmware-package-builder/argyll-firmware-spyder2/debian/rules
diff --git a/.pc/03_usb-db.diff/usb/55-Argyll.rules b/.pc/03_usb-db.diff/usb/55-Argyll.rules
new file mode 100644
index 0000000..3da9c69
--- /dev/null
+++ b/.pc/03_usb-db.diff/usb/55-Argyll.rules
@@ -0,0 +1,90 @@
+# udev rule to recognize instruments and make them accessible to user applications.
+# Copy this to /etc/udev/rules.d/55-Argyll.rules
+
+# Skip all this to speed things up if it'a not a usb add.
+ACTION!="add", GOTO="argyll_rules_end"
+SUBSYSTEM!="usb", GOTO="argyll_rules_end"
+
+# Recognize the color measurement devices
+
+# Colorimtre HCFR
+ATTRS{idVendor}=="04db", ATTRS{idProduct}=="005b", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# MonacoOPTIX (Same as i1 Display 1)
+ATTRS{idVendor}=="0670", ATTRS{idProduct}=="0001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# HueyL (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# HueyL (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5010", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Display 3
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5020", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# ColorMunki Smile
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="6003", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP20
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d020", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP92Q (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d092", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP94
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d094", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# i1Pro
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2000", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Monitor
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Display
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2003", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1 io table (not tested)
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2004", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Huey
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2005", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1 iSis (not tested)
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2006", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# ColorMunki
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2007", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# Spyder 1
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0100", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 2
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0200", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 3
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0300", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 4
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0400", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# ColorHug, old and new
+ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="f8da", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# Let udev-acl manage these devices, if it's available
+TEST=="/var/run/ConsoleKit/database", ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}="1"
+
+# Otherwise, restrict access to members of the plugdev group,
+# which the user may have to add to the system.
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}!="*?", MODE="660", GROUP="plugdev"
+
+# Set ID_VENDOR and ID_MODEL acording to VID and PID
+IMPORT{program}="usb-db %p"
+
+LABEL="argyll_rules_end"
diff --git a/.pc/04_CVE-2012-4405.diff/icc/icc.c b/.pc/04_CVE-2012-4405.diff/icc/icc.c
new file mode 100644
index 0000000..68668d0
--- /dev/null
+++ b/.pc/04_CVE-2012-4405.diff/icc/icc.c
@@ -0,0 +1,17833 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * For ICC profile version 3.4
+ *
+ * Author: Graeme W. Gill
+ * Date: 2002/04/22
+ * Version: 2.15
+ *
+ * Copyright 1997 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/*
+ * TTBD:
+ *
+ * Add a "warning mode" to file reading, in which file format
+ * errors are ignored where possible, rather than generating
+ * a fatal error (see ICM_STRICT #define).
+ *
+ * NameColor Dump doesn't handle device space correctly -
+ * should use appropriate interpretation in case device is Lab etc.
+ *
+ * Should recognise & honour unicode 0xFFFE endian marker.
+ * Should generate it on writing too ?
+ *
+ * Add support for copying tags from one icc to another.
+ *
+ * Should fix all write_number failure errors to indicate failed value.
+ * (Partially implemented - need to check all write_number functions)
+ *
+ * Make write fail error messages be specific on which element failed.
+ *
+ * Should add named color space lookup function support.
+ *
+ * Would be nice to add generic ability to add new tag type handling,
+ * so that the base library doesn't need to be modified (ie. VideoCardGamma) ?
+ *
+ * Need to add DeviceSettings and OutputResponse tags to bring up to
+ * ICC.1:1998-09 [started but not complete]
+ *
+ */
+
+#undef ICM_STRICT /* Not fully implimented - switch off strict checking of file format */
+
+/* Make the default grid points of the Lab clut be symetrical about */
+/* a/b 0.0, and also make L = 100.0 fall on a grid point. */
+#define SYMETRICAL_DEFAULT_LAB_RANGE
+
+#define _ICC_C_ /* Turn on implimentation code */
+
+#undef DEBUG_SETLUT /* Show each value being set in setting lut contents */
+#undef DEBUG_SETLUT_CLIP /* Show clipped values when setting LUT */
+#undef DEBUG_LULUT /* Show each value being looked up from lut contents */
+#undef DEBUG_LLULUT /* Debug individual lookup steps (not fully implemented) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <time.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "icc.h"
+
+#ifdef _MSC_VER
+#define vsnprintf _vsnprintf
+#define snprintf _snprintf
+#endif
+
+/* ========================================================== */
+/* Default system interface object implementations */
+
+#ifndef SEPARATE_STD
+#define COMBINED_STD
+
+#include "iccstd.c"
+
+#undef COMBINED_STD
+#endif /* SEPARATE_STD */
+
+/* Forced byte alignment for tag table and tags */
+#define ALIGN_SIZE 4
+
+/* =========================================================== */
+
+#ifdef DEBUG_SETLUT
+#undef DBGSL
+#define DBGSL(xxx) printf xxx ;
+#else
+#undef DBGSL
+#define DBGSL(xxx)
+#endif
+
+#if defined(DEBUG_SETLUT) || defined(DEBUG_SETLUT_CLIP)
+#undef DBGSLC
+#define DBGSLC(xxx) printf xxx ;
+#else
+#undef DBGSLC
+#define DBGSLC(xxx)
+#endif
+
+#ifdef DEBUG_LULUT
+#undef DBGLL
+#define DBGLL(xxx) printf xxx ;
+#else
+#undef DBGLL
+#define DBGLL(xxx)
+#endif
+
+#ifdef DEBUG_LLULUT
+#undef DBLLL
+#define DBLLL(xxx) printf xxx ;
+#else
+#undef DBLLL
+#define DBLLL(xxx)
+#endif
+
+/* =========================================================== */
+/* Overflow protected unsigned int arithmatic functions. */
+/* These functions saturate rather than wrapping around. */
+/* (Divide doesn't need protection) */
+/* They return UINT_MAX if there was an overflow */
+
+/* a + b */
+static unsigned int sat_add(unsigned int a, unsigned int b) {
+ if (b > (UINT_MAX - a))
+ return UINT_MAX;
+ return a + b;
+}
+
+/* a - b */
+static unsigned int sat_sub(unsigned int a, unsigned int b) {
+ if (a < b)
+ return UINT_MAX;
+ return a - b;
+}
+
+/* a * b */
+static unsigned int sat_mul(unsigned int a, unsigned int b) {
+ unsigned int c;
+
+ if (a == 0 || b == 0)
+ return 0;
+
+ if (a > (UINT_MAX/b))
+ return UINT_MAX;
+ else
+ return a * b;
+}
+
+/* A + B + C */
+#define sat_addadd(A, B, C) sat_add(A, sat_add(B, C))
+
+/* A + B * C */
+#define sat_addmul(A, B, C) sat_add(A, sat_mul(B, C))
+
+/* A + B + C * D */
+#define sat_addaddmul(A, B, C, D) sat_add(A, sat_add(B, sat_mul(C, D)))
+
+/* A * B * C */
+#define sat_mul3(A, B, C) sat_mul(A, sat_mul(B, C))
+
+/* a ^ b */
+static unsigned int sat_pow(unsigned int a, unsigned int b) {
+ unsigned int c = 1;
+ for (; b > 0; b--) {
+ c = sat_mul(c, a);
+ if (c == UINT_MAX)
+ break;
+ }
+ return c;
+}
+
+/* Alignment */
+static unsigned int sat_align(unsigned int align_size, unsigned int a) {
+ align_size--;
+
+ if (align_size > (UINT_MAX - a))
+ return UINT_MAX;
+
+ return (a + align_size) & ~align_size;
+}
+
+/* These test functions detect whether an overflow would occur */
+
+/* Return nz if add would overflow */
+static int ovr_add(unsigned int a, unsigned int b) {
+
+ if (b > (UINT_MAX - a))
+ return 1;
+ return 0;
+}
+
+/* Return nz if sub would overflow */
+static int ovr_sub(unsigned int a, unsigned int b) {
+ if (a < b)
+ return 1;
+ return 0;
+}
+
+/* Return nz if mult would overflow */
+static int ovr_mul(unsigned int a, unsigned int b) {
+ if (a > (UINT_MAX/b))
+ return 1;
+ return 0;
+}
+
+
+/* size_t versions of saturating arithmatic */
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t)(-1))
+#endif
+
+/* a + b */
+static size_t ssat_add(size_t a, size_t b) {
+ if (b > (SIZE_MAX - a))
+ return SIZE_MAX;
+ return a + b;
+}
+
+/* a - b */
+static size_t ssat_sub(size_t a, size_t b) {
+ if (a < b)
+ return SIZE_MAX;
+ return a - b;
+}
+
+/* a * b */
+static size_t ssat_mul(size_t a, size_t b) {
+ size_t c;
+
+ if (a == 0 || b == 0)
+ return 0;
+
+ if (a > (SIZE_MAX/b))
+ return SIZE_MAX;
+ else
+ return a * b;
+}
+
+/* ------------------------------------------------- */
+/* Memory image icmFile compatible class */
+/* Buffer is assumed to have been allocated by the given allocator, */
+/* and will be expanded on write. */
+
+/* Get the size of the file */
+static size_t icmFileMem_get_size(icmFile *pp) {
+ icmFileMem *p = (icmFileMem *)pp;
+
+ return p->end - p->start;
+}
+
+/* Set current position to offset. Return 0 on success, nz on failure. */
+static int icmFileMem_seek(
+icmFile *pp,
+unsigned int offset
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ unsigned char *np;
+
+ np = p->start + offset;
+ if (np < p->start || np >= p->end)
+ return 1;
+ p->cur = np;
+ return 0;
+}
+
+/* Read count items of size length. Return number of items successfully read. */
+static size_t icmFileMem_read(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ size_t len;
+
+ len = ssat_mul(size, count);
+ if (len > (p->end - p->cur)) { /* Too much */
+ if (size > 0)
+ count = (p->end - p->cur)/size;
+ else
+ count = 0;
+ }
+ len = size * count;
+ if (len > 0)
+ memmove(buffer, p->cur, len);
+ p->cur += len;
+ return count;
+}
+
+/* Expand the memory buffer file to hold up to pointer ep */
+/* Don't expand if realloc fails */
+static void icmFileMem_filemem_resize(icmFileMem *p, unsigned char *ep) {
+ size_t na, co, ce;
+ unsigned char *nstart;
+
+ /* No need to realloc */
+ if (ep <= p->aend) {
+ return;
+ }
+
+ co = p->cur - p->start; /* Current offset */
+ ce = p->end - p->start; /* Current end */
+ na = ep - p->start; /* new allocated size */
+
+ /* Round new allocation up */
+ if (na <= 1024)
+ na += 1024;
+ else
+ na += 4096;
+
+ if ((nstart = p->al->realloc(p->al, p->start, na)) != NULL) {
+ p->start = nstart;
+ p->cur = nstart + co;
+ p->end = nstart + ce;
+ p->aend = nstart + na;
+ }
+}
+
+/* write count items of size length. Return number of items successfully written. */
+static size_t icmFileMem_write(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ size_t len;
+
+ len = ssat_mul(size, count);
+ if (len > (size_t)(p->aend - p->cur)) /* Try and expand buffer */
+ icmFileMem_filemem_resize(p, p->start + len);
+
+ if (len > (size_t)(p->aend - p->cur)) {
+ if (size > 0)
+ count = (p->aend - p->cur)/size;
+ else
+ count = 0;
+ }
+ len = size * count;
+ if (len > 0)
+ memmove(p->cur, buffer, len);
+ p->cur += len;
+ if (p->end < p->cur)
+ p->end = p->cur;
+ return count;
+}
+
+/* do a printf */
+static int icmFileMem_printf(
+icmFile *pp,
+const char *format,
+...
+) {
+ int rv;
+ va_list args;
+ icmFileMem *p = (icmFileMem *)pp;
+ int len;
+
+ va_start(args, format);
+
+ rv = 1;
+ len = 100; /* Initial allocation for printf */
+ icmFileMem_filemem_resize(p, p->cur + len);
+
+ /* We have to use the available printf functions to resize the buffer if needed. */
+ for (;rv != 0;) {
+ /* vsnprintf() either returns -1 if it doesn't fit, or */
+ /* returns the size-1 needed in order to fit. */
+ len = vsnprintf((char *)p->cur, (p->aend - p->cur), format, args);
+
+ if (len > -1 && ((p->cur + len +1) <= p->aend)) /* Fitted in current allocation */
+ break;
+
+ if (len > -1) /* vsnprintf returned needed size-1 */
+ len = len+2; /* (In case vsnprintf returned 1 less than it needs) */
+ else
+ len *= 2; /* We just have to guess */
+
+ /* Attempt to resize */
+ icmFileMem_filemem_resize(p, p->cur + len);
+
+ /* If resize failed */
+ if ((p->aend - p->cur) < len) {
+ rv = 0;
+ break;
+ }
+ }
+ if (rv != 0) {
+ /* Figure out where end of printf is */
+ len = strlen((char *)p->cur); /* Length excluding nul */
+ p->cur += len;
+ if (p->cur > p->end)
+ p->end = p->cur;
+ rv = len;
+ }
+ va_end(args);
+ return rv;
+}
+
+/* flush all write data out to secondary storage. Return nz on failure. */
+static int icmFileMem_flush(
+icmFile *pp
+) {
+ return 0;
+}
+
+/* Return the memory buffer. Error if not icmFileMem */
+static int icmFileMem_get_buf(
+icmFile *pp,
+unsigned char **buf,
+size_t *len
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ if (buf != NULL)
+ *buf = p->start;
+ if (len != NULL)
+ *len = p->end - p->start;
+ return 0;
+}
+
+/* we're done with the file object, return nz on failure */
+static int icmFileMem_delete(
+icmFile *pp
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ icmAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ if (p->del_buf) /* Free the memory buffer */
+ al->free(al, p->start);
+ al->free(al, p); /* Free object */
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+ return 0;
+}
+
+/* Create a memory image file access class with allocator */
+/* Buffer is used as is. */
+icmFile *new_icmFileMem_a(
+void *base, /* Pointer to base of memory buffer */
+size_t length, /* Number of bytes in buffer */
+icmAlloc *al /* heap allocator */
+) {
+ icmFileMem *p;
+
+ if ((p = (icmFileMem *) al->calloc(al, 1, sizeof(icmFileMem))) == NULL) {
+ return NULL;
+ }
+ p->al = al; /* Heap allocator */
+ p->get_size = icmFileMem_get_size;
+ p->seek = icmFileMem_seek;
+ p->read = icmFileMem_read;
+ p->write = icmFileMem_write;
+ p->gprintf = icmFileMem_printf;
+ p->flush = icmFileMem_flush;
+ p->get_buf = icmFileMem_get_buf;
+ p->del = icmFileMem_delete;
+
+ p->start = (unsigned char *)base;
+ p->cur = p->start;
+ p->aend = p->end = p->start + length;
+
+ return (icmFile *)p;
+}
+
+/* Create a memory image file access class with given allocator */
+/* and delete base when icmFile is deleted. */
+icmFile *new_icmFileMem_ad(void *base, size_t length, icmAlloc *al) {
+ icmFile *fp;
+
+ if ((fp = new_icmFileMem_a(base, length, al)) != NULL) {
+ ((icmFileMem *)fp)->del_buf = 1;
+ }
+
+ return fp;
+}
+
+/* ========================================================== */
+/* Conversion support functions */
+/* Convert between ICC storage types and native C types */
+/* Write routine return non-zero if numbers can't be represented */
+
+/* Unsigned */
+static unsigned int read_UInt8Number(char *p) {
+ unsigned int rv;
+ rv = (unsigned int)((ORD8 *)p)[0];
+ return rv;
+}
+
+static int write_UInt8Number(unsigned int d, char *p) {
+ if (d > 255)
+ return 1;
+ ((ORD8 *)p)[0] = (ORD8)d;
+ return 0;
+}
+
+static unsigned int read_UInt16Number(char *p) {
+ unsigned int rv;
+ rv = 256 * (unsigned int)((ORD8 *)p)[0]
+ + (unsigned int)((ORD8 *)p)[1];
+ return rv;
+}
+
+static int write_UInt16Number(unsigned int d, char *p) {
+ if (d > 65535)
+ return 1;
+ ((ORD8 *)p)[0] = (ORD8)(d >> 8);
+ ((ORD8 *)p)[1] = (ORD8)(d);
+ return 0;
+}
+
+static unsigned int read_UInt32Number(char *p) {
+ unsigned int rv;
+ rv = 16777216 * (unsigned int)((ORD8 *)p)[0]
+ + 65536 * (unsigned int)((ORD8 *)p)[1]
+ + 256 * (unsigned int)((ORD8 *)p)[2]
+ + (unsigned int)((ORD8 *)p)[3];
+ return rv;
+}
+
+static int write_UInt32Number(unsigned int d, char *p) {
+ ((ORD8 *)p)[0] = (ORD8)(d >> 24);
+ ((ORD8 *)p)[1] = (ORD8)(d >> 16);
+ ((ORD8 *)p)[2] = (ORD8)(d >> 8);
+ ((ORD8 *)p)[3] = (ORD8)(d);
+ return 0;
+}
+
+static void read_UInt64Number(icmUint64 *d, char *p) {
+ d->h = 16777216 * (unsigned int)((ORD8 *)p)[0]
+ + 65536 * (unsigned int)((ORD8 *)p)[1]
+ + 256 * (unsigned int)((ORD8 *)p)[2]
+ + (unsigned int)((ORD8 *)p)[3];
+ d->l = 16777216 * (unsigned int)((ORD8 *)p)[4]
+ + 65536 * (unsigned int)((ORD8 *)p)[5]
+ + 256 * (unsigned int)((ORD8 *)p)[6]
+ + (unsigned int)((ORD8 *)p)[7];
+}
+
+static int write_UInt64Number(icmUint64 *d, char *p) {
+ ((ORD8 *)p)[0] = (ORD8)(d->h >> 24);
+ ((ORD8 *)p)[1] = (ORD8)(d->h >> 16);
+ ((ORD8 *)p)[2] = (ORD8)(d->h >> 8);
+ ((ORD8 *)p)[3] = (ORD8)(d->h);
+ ((ORD8 *)p)[4] = (ORD8)(d->l >> 24);
+ ((ORD8 *)p)[5] = (ORD8)(d->l >> 16);
+ ((ORD8 *)p)[6] = (ORD8)(d->l >> 8);
+ ((ORD8 *)p)[7] = (ORD8)(d->l);
+ return 0;
+}
+
+static double read_U8Fixed8Number(char *p) {
+ ORD32 o32;
+ o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */
+ + (ORD32)((ORD8 *)p)[1];
+ return (double)o32/256.0;
+}
+
+static int write_U8Fixed8Number(double d, char *p) {
+ ORD32 o32;
+ d = d * 256.0 + 0.5;
+ if (d >= 65536.0)
+ return 1;
+ if (d < 0.0)
+ return 1;
+ o32 = (ORD32)d;
+ ((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
+ ((ORD8 *)p)[1] = (ORD8)((o32));
+ return 0;
+}
+
+static double read_U16Fixed16Number(char *p) {
+ ORD32 o32;
+ o32 = 16777216 * (ORD32)((ORD8 *)p)[0] /* Read big endian 32 bit unsigned */
+ + 65536 * (ORD32)((ORD8 *)p)[1]
+ + 256 * (ORD32)((ORD8 *)p)[2]
+ + (ORD32)((ORD8 *)p)[3];
+ return (double)o32/65536.0;
+}
+
+static int write_U16Fixed16Number(double d, char *p) {
+ ORD32 o32;
+ d = d * 65536.0 + 0.5;
+ if (d >= 4294967296.0)
+ return 1;
+ if (d < 0.0)
+ return 1;
+ o32 = (ORD32)d;
+ ((ORD8 *)p)[0] = (ORD8)((o32) >> 24);
+ ((ORD8 *)p)[1] = (ORD8)((o32) >> 16);
+ ((ORD8 *)p)[2] = (ORD8)((o32) >> 8);
+ ((ORD8 *)p)[3] = (ORD8)((o32));
+ return 0;
+}
+
+
+/* Signed numbers */
+static int read_SInt8Number(char *p) {
+ int rv;
+ rv = (int)((INR8 *)p)[0];
+ return rv;
+}
+
+static int write_SInt8Number(int d, char *p) {
+ if (d > 127)
+ return 1;
+ else if (d < -128)
+ return 1;
+ ((INR8 *)p)[0] = (INR8)d;
+ return 0;
+}
+
+static int read_SInt16Number(char *p) {
+ int rv;
+ rv = 256 * (int)((INR8 *)p)[0]
+ + (int)((ORD8 *)p)[1];
+ return rv;
+}
+
+static int write_SInt16Number(int d, char *p) {
+ if (d > 32767)
+ return 1;
+ else if (d < -32768)
+ return 1;
+ ((INR8 *)p)[0] = (INR8)(d >> 8);
+ ((ORD8 *)p)[1] = (ORD8)(d);
+ return 0;
+}
+
+static int read_SInt32Number(char *p) {
+ int rv;
+ rv = 16777216 * (int)((INR8 *)p)[0]
+ + 65536 * (int)((ORD8 *)p)[1]
+ + 256 * (int)((ORD8 *)p)[2]
+ + (int)((ORD8 *)p)[3];
+ return rv;
+}
+
+static int write_SInt32Number(int d, char *p) {
+ ((INR8 *)p)[0] = (INR8)(d >> 24);
+ ((ORD8 *)p)[1] = (ORD8)(d >> 16);
+ ((ORD8 *)p)[2] = (ORD8)(d >> 8);
+ ((ORD8 *)p)[3] = (ORD8)(d);
+ return 0;
+}
+
+static void read_SInt64Number(icmInt64 *d, char *p) {
+ d->h = 16777216 * (int)((INR8 *)p)[0]
+ + 65536 * (int)((ORD8 *)p)[1]
+ + 256 * (int)((ORD8 *)p)[2]
+ + (int)((ORD8 *)p)[3];
+ d->l = 16777216 * (unsigned int)((ORD8 *)p)[4]
+ + 65536 * (unsigned int)((ORD8 *)p)[5]
+ + 256 * (unsigned int)((ORD8 *)p)[6]
+ + (unsigned int)((ORD8 *)p)[7];
+}
+
+static int write_SInt64Number(icmInt64 *d, char *p) {
+ ((INR8 *)p)[0] = (INR8)(d->h >> 24);
+ ((ORD8 *)p)[1] = (ORD8)(d->h >> 16);
+ ((ORD8 *)p)[2] = (ORD8)(d->h >> 8);
+ ((ORD8 *)p)[3] = (ORD8)(d->h);
+ ((ORD8 *)p)[4] = (ORD8)(d->l >> 24);
+ ((ORD8 *)p)[5] = (ORD8)(d->l >> 16);
+ ((ORD8 *)p)[6] = (ORD8)(d->l >> 8);
+ ((ORD8 *)p)[7] = (ORD8)(d->l);
+ return 0;
+}
+
+static double read_S15Fixed16Number(char *p) {
+ INR32 i32;
+ i32 = 16777216 * (INR32)((INR8 *)p)[0] /* Read big endian 32 bit signed */
+ + 65536 * (INR32)((ORD8 *)p)[1]
+ + 256 * (INR32)((ORD8 *)p)[2]
+ + (INR32)((ORD8 *)p)[3];
+ return (double)i32/65536.0;
+}
+
+static int write_S15Fixed16Number(double d, char *p) {
+ INR32 i32;
+ d = floor(d * 65536.0 + 0.5); /* Beware! (int)(d + 0.5) doesn't work! */
+ if (d >= 2147483648.0)
+ return 1;
+ if (d < -2147483648.0)
+ return 1;
+ i32 = (INR32)d;
+ ((INR8 *)p)[0] = (INR8)((i32) >> 24); /* Write big endian 32 bit signed */
+ ((ORD8 *)p)[1] = (ORD8)((i32) >> 16);
+ ((ORD8 *)p)[2] = (ORD8)((i32) >> 8);
+ ((ORD8 *)p)[3] = (ORD8)((i32));
+ return 0;
+}
+
+/* Device coordinate as 8 bit value range 0.0 - 1.0 */
+static double read_DCS8Number(char *p) {
+ unsigned int rv;
+ rv = (unsigned int)((ORD8 *)p)[0];
+ return (double)rv/255.0;
+}
+
+static int write_DCS8Number(double d, char *p) {
+ ORD32 o32;
+ d = d * 255.0 + 0.5;
+ if (d >= 256.0)
+ return 1;
+ if (d < 0.0)
+ return 1;
+ o32 = (ORD32)d;
+ ((ORD8 *)p)[0] = (ORD8)(o32);
+ return 0;
+}
+
+/* Device coordinate as 16 bit value range 0.0 - 1.0 */
+static double read_DCS16Number(char *p) {
+ unsigned int rv;
+ rv = 256 * (unsigned int)((ORD8 *)p)[0]
+ + (unsigned int)((ORD8 *)p)[1];
+ return (double)rv/65535.0;
+}
+
+static int write_DCS16Number(double d, char *p) {
+ ORD32 o32;
+ d = d * 65535.0 + 0.5;
+ if (d >= 65536.0)
+ return 1;
+ if (d < 0.0)
+ return 1;
+ o32 = (ORD32)d;
+ ((ORD8 *)p)[0] = (ORD8)(o32 >> 8);
+ ((ORD8 *)p)[1] = (ORD8)(o32);
+ return 0;
+}
+
+static void Lut_Lut2XYZ(double *out, double *in);
+static void Lut_XYZ2Lut(double *out, double *in);
+static void Lut_Lut2Lab_8(double *out, double *in);
+static void Lut_Lab2Lut_8(double *out, double *in);
+static void Lut_Lut2LabV2_16(double *out, double *in);
+static void Lut_Lab2LutV2_16(double *out, double *in);
+static void Lut_Lut2LabV4_16(double *out, double *in);
+static void Lut_Lab2LutV4_16(double *out, double *in);
+
+static void Lut_Lut2Y(double *out, double *in);
+static void Lut_Y2Lut(double *out, double *in);
+static void Lut_Lut2L_8(double *out, double *in);
+static void Lut_L2Lut_8(double *out, double *in);
+static void Lut_Lut2LV2_16(double *out, double *in);
+static void Lut_L2LutV2_16(double *out, double *in);
+static void Lut_Lut2LV4_16(double *out, double *in);
+static void Lut_L2LutV4_16(double *out, double *in);
+
+//~~~~888888
+/* read a PCS number. PCS can be profile PCS, profile version Lab, */
+/* or a specific type of Lab, depending on the value of csig: */
+/* icmSigPCSData, icSigXYZData, icmSigLab8Data, icSigLabData, */
+/* icmSigLabV2Data or icmSigLabV4Data */
+/* Do nothing if not one of the above. */
+static void read_PCSNumber(icc *icp, icColorSpaceSignature csig, double pcs[3], char *p) {
+
+ if (csig == icmSigPCSData)
+ csig = icp->header->pcs;
+ if (csig == icSigLabData) {
+ if (icp->ver != 0)
+ csig = icmSigLabV4Data;
+ else
+ csig = icmSigLabV2Data;
+ }
+
+ if (csig == icmSigLab8Data) {
+ pcs[0] = read_DCS8Number(p);
+ pcs[1] = read_DCS8Number(p+1);
+ pcs[2] = read_DCS8Number(p+2);
+ } else {
+ pcs[0] = read_DCS16Number(p);
+ pcs[1] = read_DCS16Number(p+2);
+ pcs[2] = read_DCS16Number(p+4);
+ }
+ switch (csig) {
+ case icSigXYZData:
+ Lut_Lut2XYZ(pcs, pcs);
+ break;
+ case icmSigLab8Data:
+ Lut_Lut2Lab_8(pcs, pcs);
+ break;
+ case icmSigLabV2Data:
+ Lut_Lut2LabV2_16(pcs, pcs);
+ break;
+ case icmSigLabV4Data:
+ Lut_Lut2LabV4_16(pcs, pcs);
+ break;
+ default:
+ break;
+ }
+}
+
+/* write a PCS number. PCS can be profile PCS, profile version Lab, */
+/* or a specific type of Lab, depending on the value of csig: */
+/* icmSigPCSData, icSigXYZData, icmSigLab8Data, icSigLabData, */
+/* icmSigLabV2Data or icmSigLabV4Data */
+/* Return 1 if error */
+static int write_PCSNumber(icc *icp, icColorSpaceSignature csig, double pcs[3], char *p) {
+ double v[3];
+ int j;
+
+ if (csig == icmSigPCSData)
+ csig = icp->header->pcs;
+ if (csig == icSigLabData) {
+ if (icp->ver != 0)
+ csig = icmSigLabV4Data;
+ else
+ csig = icmSigLabV2Data;
+ }
+
+ switch (csig) {
+ case icSigXYZData:
+ Lut_XYZ2Lut(v, pcs);
+ break;
+ case icmSigLab8Data:
+ Lut_Lab2Lut_8(v, pcs);
+ break;
+ case icmSigLabV2Data:
+ Lut_Lab2LutV2_16(v, pcs);
+ break;
+ case icmSigLabV4Data:
+ Lut_Lab2LutV4_16(v, pcs);
+ break;
+ default:
+ return 1;
+ }
+ if (csig == icmSigLab8Data) {
+ for (j = 0; j < 3; j++) {
+ if (write_DCS8Number(v[j], p+j))
+ return 1;
+ }
+ } else {
+ for (j = 0; j < 3; j++) {
+ if (write_DCS16Number(v[j], p+(2 * j)))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Read a given primitive type. Return non-zero on error */
+/* (Not currently used internaly ?) */
+/* Public: */
+int read_Primitive(icc *icp, icmPrimType ptype, void *prim, char *p) {
+
+ switch(ptype) {
+ case icmUInt8Number:
+ *((unsigned int *)prim) = read_UInt8Number(p);
+ return 0;
+ case icmUInt16Number:
+ *((unsigned int *)prim) = read_UInt16Number(p);
+ return 0;
+ case icmUInt32Number:
+ *((unsigned int *)prim) = read_UInt32Number(p);
+ return 0;
+ case icmUInt64Number:
+ read_UInt64Number((icmUint64 *)prim, p);
+ return 0;
+ case icmU8Fixed8Number:
+ *((double *)prim) = read_U8Fixed8Number(p);
+ return 0;
+ case icmU16Fixed16Number:
+ *((double *)prim) = read_U16Fixed16Number(p);
+ return 0;
+ case icmSInt8Number:
+ *((int *)prim) = read_SInt8Number(p);
+ return 0;
+ case icmSInt16Number:
+ *((int *)prim) = read_SInt16Number(p);
+ return 0;
+ case icmSInt32Number:
+ *((int *)prim) = read_SInt32Number(p);
+ return 0;
+ case icmSInt64Number:
+ read_SInt64Number((icmInt64 *)prim, p);
+ return 0;
+ case icmS15Fixed16Number:
+ *((double *)prim) = read_S15Fixed16Number(p);
+ return 0;
+ case icmDCS8Number:
+ *((double *)prim) = read_DCS8Number(p);
+ return 0;
+ case icmDCS16Number:
+ *((double *)prim) = read_DCS16Number(p);
+ return 0;
+ case icmPCSNumber:
+ read_PCSNumber(icp, icmSigPCSData, ((double *)prim), p);
+ return 0;
+ case icmPCSXYZNumber:
+ read_PCSNumber(icp, icSigXYZData, ((double *)prim), p);
+ return 0;
+ case icmPCSLab8Number:
+ read_PCSNumber(icp, icmSigLab8Data, ((double *)prim), p);
+ return 0;
+ case icmPCSLabNumber:
+ read_PCSNumber(icp, icSigLabData, ((double *)prim), p);
+ return 0;
+ case icmPCSLabV2Number:
+ read_PCSNumber(icp, icmSigLabV2Data, ((double *)prim), p);
+ return 0;
+ case icmPCSLabV4Number:
+ read_PCSNumber(icp, icmSigLabV4Data, ((double *)prim), p);
+ return 0;
+ }
+
+ return 2;
+}
+
+/* Write a given primitive type. Return non-zero on error */
+/* (Not currently used internaly ?) */
+/* Public: */
+int write_Primitive(icc *icp, icmPrimType ptype, char *p, void *prim) {
+
+ switch(ptype) {
+ case icmUInt8Number:
+ return write_UInt8Number(*((unsigned int *)prim), p);
+ case icmUInt16Number:
+ return write_UInt16Number(*((unsigned int *)prim), p);
+ case icmUInt32Number:
+ return write_UInt32Number(*((unsigned int *)prim), p);
+ case icmUInt64Number:
+ return write_UInt64Number((icmUint64 *)prim, p);
+ case icmU8Fixed8Number:
+ return write_U8Fixed8Number(*((double *)prim), p);
+ case icmU16Fixed16Number:
+ return write_U16Fixed16Number(*((double *)prim), p);
+ case icmSInt8Number:
+ return write_SInt8Number(*((int *)prim), p);
+ case icmSInt16Number:
+ return write_SInt16Number(*((int *)prim), p);
+ case icmSInt32Number:
+ return write_SInt32Number(*((int *)prim), p);
+ case icmSInt64Number:
+ return write_SInt64Number((icmInt64 *)prim, p);
+ case icmS15Fixed16Number:
+ return write_S15Fixed16Number(*((double *)prim), p);
+ case icmDCS8Number:
+ return write_DCS8Number(*((double *)prim), p);
+ case icmDCS16Number:
+ return write_DCS16Number(*((double *)prim), p);
+ case icmPCSNumber:
+ return write_PCSNumber(icp, icmSigPCSData, ((double *)prim), p);
+ case icmPCSXYZNumber:
+ return write_PCSNumber(icp, icSigXYZData, ((double *)prim), p);
+ case icmPCSLab8Number:
+ return write_PCSNumber(icp, icmSigLab8Data, ((double *)prim), p);
+ case icmPCSLabNumber:
+ return write_PCSNumber(icp, icSigLabData, ((double *)prim), p);
+ case icmPCSLabV2Number:
+ return write_PCSNumber(icp, icmSigLabV2Data, ((double *)prim), p);
+ case icmPCSLabV4Number:
+ return write_PCSNumber(icp, icmSigLabV4Data, ((double *)prim), p);
+ }
+
+ return 2;
+}
+
+/* ---------------------------------------------------------- */
+/* Auiliary function - return a string that represents a tag */
+/* Note - returned buffers are static, can only be used 5 */
+/* times before buffers get reused. */
+char *tag2str(
+ int tag
+) {
+ int i;
+ static int si = 0; /* String buffer index */
+ static char buf[5][20]; /* String buffers */
+ char *bp;
+ unsigned char c[4];
+
+ bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ c[0] = 0xff & (tag >> 24);
+ c[1] = 0xff & (tag >> 16);
+ c[2] = 0xff & (tag >> 8);
+ c[3] = 0xff & (tag >> 0);
+ for (i = 0; i < 4; i++) { /* Can we represent it as a string ? */
+ if (!isprint(c[i]))
+ break;
+ }
+ if (i < 4) { /* Not printable - use hex */
+ sprintf(bp,"0x%x",tag);
+ } else { /* Printable */
+ sprintf(bp,"'%c%c%c%c'",c[0],c[1],c[2],c[3]);
+ }
+ return bp;
+}
+
+/* Auiliary function - return a tag created from a string */
+/* Note there is also the icmMakeTag() macro */
+unsigned int str2tag(
+ const char *str
+) {
+ unsigned int tag;
+ tag = (((unsigned int)str[0]) << 24)
+ + (((unsigned int)str[1]) << 16)
+ + (((unsigned int)str[2]) << 8)
+ + (((unsigned int)str[3]));
+ return tag;
+}
+
+/* helper - return 1 if the string doesn't have a */
+/* null terminator within len, return 0 has null at exactly len, */
+/* and 2 if it has null before len. */
+/* Note: will return 1 if len == 0 */
+static int check_null_string(char *cp, int len) {
+ for (; len > 0; len--) {
+ if (cp[0] == '\000')
+ break;
+ cp++;
+ }
+ if (len == 0)
+ return 1;
+ if (len > 1)
+ return 2;
+ return 0;
+}
+
+/* helper - return 1 if the string doesn't have a */
+/* null terminator within len, return 0 has null at exactly len, */
+/* and 2 if it has null before len. */
+/* Note: will return 1 if len == 0 */
+/* Unicode version */
+static int check_null_string16(char *cp, int len) {
+ for (; len > 0; len--) { /* Length is in characters */
+ if (cp[0] == 0 && cp[1] == 0)
+ break;
+ cp += 2;
+ }
+ if (len == 0)
+ return 1;
+ if (len > 1)
+ return 2;
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Color Space to number of component conversion */
+/* Return 0 on error */
+static unsigned int number_ColorSpaceSignature(icColorSpaceSignature sig) {
+ switch(sig) {
+ case icSigXYZData:
+ return 3;
+ case icSigLabData:
+ return 3;
+ case icSigLuvData:
+ return 3;
+ case icSigYCbCrData:
+ return 3;
+ case icSigYxyData:
+ return 3;
+ case icSigRgbData:
+ return 3;
+ case icSigGrayData:
+ return 1;
+ case icSigHsvData:
+ return 3;
+ case icSigHlsData:
+ return 3;
+ case icSigCmykData:
+ return 4;
+ case icSigCmyData:
+ return 3;
+ case icSig2colorData:
+ return 2;
+ case icSig3colorData:
+ return 3;
+ case icSig4colorData:
+ return 4;
+ case icSig5colorData:
+ case icSigMch5Data:
+ return 5;
+ case icSig6colorData:
+ case icSigMch6Data:
+ return 6;
+ case icSig7colorData:
+ case icSigMch7Data:
+ return 7;
+ case icSig8colorData:
+ case icSigMch8Data:
+ return 8;
+ case icSig9colorData:
+ return 9;
+ case icSig10colorData:
+ return 10;
+ case icSig11colorData:
+ return 11;
+ case icSig12colorData:
+ return 12;
+ case icSig13colorData:
+ return 13;
+ case icSig14colorData:
+ return 14;
+ case icSig15colorData:
+ return 15;
+
+ /* Non-standard and Pseudo spaces */
+ case icmSigYData:
+ return 1;
+ case icmSigLData:
+ return 1;
+ case icmSigL8Data:
+ return 1;
+ case icmSigLV2Data:
+ return 1;
+ case icmSigLV4Data:
+ return 1;
+ case icmSigPCSData:
+ return 3;
+ case icmSigLab8Data:
+ return 3;
+ case icmSigLabV2Data:
+ return 3;
+ case icmSigLabV4Data:
+ return 3;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* Public version of above */
+
+/* Return the number of channels for the given color space. Return 0 if unknown. */
+ICCLIB_API unsigned int icmCSSig2nchan(icColorSpaceSignature sig) {
+ return number_ColorSpaceSignature(sig);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return the individual channel names and number of channels give a colorspace signature. */
+/* Return 0 if it is not a colorspace that itself defines particular channels, */
+/* 1 if it is a colorant based colorspace, and 2 if it is not a colorant based space */
+static int chnames_ColorSpaceSignature(
+icColorSpaceSignature sig,
+char *cvals[] /* Pointers to return for each channel */
+) {
+ switch (sig) {
+ case icSigXYZData:
+ cvals[0] = "CIE X";
+ cvals[1] = "CIE Y";
+ cvals[2] = "CIE Z";
+ return 2;
+
+ case icSigLabData:
+ cvals[0] = "CIE L*";
+ cvals[1] = "CIE a*";
+ cvals[2] = "CIE b*";
+ return 2;
+
+ case icSigLuvData:
+ cvals[0] = "CIE L*";
+ cvals[1] = "CIE u*";
+ cvals[2] = "CIE v*";
+ return 2;
+
+ /* Usually ITU-R BT.601 (was CCIR 601) */
+ case icSigYCbCrData:
+ cvals[0] = "ITU Y";
+ cvals[1] = "ITU Cb";
+ cvals[2] = "ITU Cr";
+ return 2;
+
+ case icSigYxyData:
+ cvals[0] = "CIE Y";
+ cvals[1] = "CIE x";
+ cvals[2] = "CIE y";
+ return 2;
+
+ /* Alvy Ray Smith ? */
+ case icSigHsvData:
+ cvals[0] = "RGB Hue";
+ cvals[1] = "RGB Saturation";
+ cvals[2] = "RGB Value";
+ return 2;
+
+ /* GSPC ? */
+ case icSigHlsData:
+ cvals[0] = "RGB Hue";
+ cvals[1] = "RGB Lightness";
+ cvals[2] = "RGB Saturation";
+ return 2;
+
+ case icSigCmyData:
+ cvals[0] = "Cyan";
+ cvals[1] = "Magenta";
+ cvals[2] = "Yellow";
+ return 1;
+
+ case icSigRgbData:
+ cvals[0] = "Red";
+ cvals[1] = "Green";
+ cvals[2] = "Blue";
+ return 1;
+
+ case icSigCmykData:
+ cvals[0] = "Cyan";
+ cvals[1] = "Magenta";
+ cvals[2] = "Yellow";
+ cvals[3] = "Black";
+ return 1;
+
+
+ /* Non-standard and Pseudo spaces */
+ case icmSigYData:
+ cvals[0] = "CIE Y";
+ return 2;
+
+ case icmSigLData:
+ cvals[0] = "CIE L*";
+ return 2;
+
+ default:
+ break;
+
+ }
+ return 0;
+}
+
+/* Public version of above */
+
+/* Return the individual channel names and number of channels give a colorspace signature. */
+/* Return 0 if it is not a colorspace that itself defines particular channels, */
+/* 1 if it is a colorant based colorspace, and 2 if it is not a colorant based space */
+ICCLIB_API unsigned int icmCSSig2chanNames(icColorSpaceSignature sig, char *cvals[]) {
+
+ return chnames_ColorSpaceSignature(sig, cvals);
+}
+
+/* ------------------------------------------------------- */
+/* Flag dump functions */
+/* Note - returned buffers are static, can only be used 5 */
+/* times before buffers get reused. */
+
+/* Screening Encodings */
+static char *string_ScreenEncodings(unsigned int flags) {
+ static int si = 0; /* String buffer index */
+ static char buf[5][80]; /* String buffers */
+ char *bp, *cp;
+
+ cp = bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ if (flags & icPrtrDefaultScreensTrue) {
+ sprintf(cp,"Default Screen");
+ } else {
+ sprintf(cp,"No Default Screen");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icLinesPerInch) {
+ sprintf(cp,", Lines Per Inch");
+ } else {
+ sprintf(cp,", Lines Per cm");
+ }
+ cp = cp + strlen(cp);
+
+ return bp;
+}
+
+/* Device attributes */
+static char *string_DeviceAttributes(unsigned int flags) {
+ static int si = 0; /* String buffer index */
+ static char buf[5][80]; /* String buffers */
+ char *bp, *cp;
+
+ cp = bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ if (flags & icTransparency) {
+ sprintf(cp,"Transparency");
+ } else {
+ sprintf(cp,"Reflective");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icMatte) {
+ sprintf(cp,", Matte");
+ } else {
+ sprintf(cp,", Glossy");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icNegative) {
+ sprintf(cp,", Negative");
+ } else {
+ sprintf(cp,", Positive");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icBlackAndWhite) {
+ sprintf(cp,", BlackAndWhite");
+ } else {
+ sprintf(cp,", Color");
+ }
+ cp = cp + strlen(cp);
+
+ return bp;
+}
+
+/* Profile header flags */
+static char *string_ProfileHeaderFlags(unsigned int flags) {
+ static int si = 0; /* String buffer index */
+ static char buf[5][80]; /* String buffers */
+ char *bp, *cp;
+
+ cp = bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ if (flags & icEmbeddedProfileTrue) {
+ sprintf(cp,"Embedded Profile");
+ } else {
+ sprintf(cp,"Not Embedded Profile");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icUseWithEmbeddedDataOnly) {
+ sprintf(cp,", Use with embedded data only");
+ } else {
+ sprintf(cp,", Use anywhere");
+ }
+ cp = cp + strlen(cp);
+
+ return bp;
+}
+
+
+static char *string_AsciiOrBinaryData(unsigned int flags) {
+ static int si = 0; /* String buffer index */
+ static char buf[5][80]; /* String buffers */
+ char *bp, *cp;
+
+ cp = bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ if (flags & icBinaryData) {
+ sprintf(cp,"Binary");
+ } else {
+ sprintf(cp,"Ascii");
+ }
+ cp = cp + strlen(cp);
+
+ return bp;
+}
+
+/* ------------------------------------------------------------ */
+/* Enumeration dump functions */
+/* Note - returned buffers are static, can only be used once */
+/* before buffers get reused if type is unknown. */
+
+/* public tags and sizes */
+static const char *string_TagSignature(icTagSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigAToB0Tag:
+ return "AToB0 Multidimentional Transform";
+ case icSigAToB1Tag:
+ return "AToB1 Multidimentional Transform";
+ case icSigAToB2Tag:
+ return "AToB2 Multidimentional Transform";
+ case icSigBlueColorantTag:
+ return "Blue Colorant";
+ case icSigBlueTRCTag:
+ return "Blue Tone Reproduction Curve";
+ case icSigBToA0Tag:
+ return "BToA0 Multidimentional Transform";
+ case icSigBToA1Tag:
+ return "BToA1 Multidimentional Transform";
+ case icSigBToA2Tag:
+ return "BToA2 Multidimentional Transform";
+ case icSigCalibrationDateTimeTag:
+ return "Calibration Date & Time";
+ case icSigCharTargetTag:
+ return "Characterization Target";
+ case icSigCopyrightTag:
+ return "Copyright";
+ case icSigCrdInfoTag:
+ return "CRD Info";
+ case icSigDeviceMfgDescTag:
+ return "Device Manufacturer Description";
+ case icSigDeviceModelDescTag:
+ return "Device Model Description";
+ case icSigGamutTag:
+ return "Gamut";
+ case icSigGrayTRCTag:
+ return "Gray Tone Reproduction Curve";
+ case icSigGreenColorantTag:
+ return "Green Colorant";
+ case icSigGreenTRCTag:
+ return "Green Tone Reproduction Curve";
+ case icSigLuminanceTag:
+ return "Luminance";
+ case icSigMeasurementTag:
+ return "Measurement";
+ case icSigMediaBlackPointTag:
+ return "Media Black Point";
+ case icSigMediaWhitePointTag:
+ return "Media White Point";
+ case icSigNamedColorTag:
+ return "Named Color";
+ case icSigNamedColor2Tag:
+ return "Named Color 2";
+ case icSigPreview0Tag:
+ return "Preview0";
+ case icSigPreview1Tag:
+ return "Preview1";
+ case icSigPreview2Tag:
+ return "Preview2";
+ case icSigProfileDescriptionTag:
+ return "Profile Description";
+ case icSigProfileSequenceDescTag:
+ return "Profile Sequence";
+ case icSigPs2CRD0Tag:
+ return "PS Level 2 CRD perceptual";
+ case icSigPs2CRD1Tag:
+ return "PS Level 2 CRD colorimetric";
+ case icSigPs2CRD2Tag:
+ return "PS Level 2 CRD saturation";
+ case icSigPs2CRD3Tag:
+ return "PS Level 2 CRD absolute";
+ case icSigPs2CSATag:
+ return "PS Level 2 color space array";
+ case icSigPs2RenderingIntentTag:
+ return "PS Level 2 Rendering Intent";
+ case icSigRedColorantTag:
+ return "Red Colorant";
+ case icSigRedTRCTag:
+ return "Red Tone Reproduction Curve";
+ case icSigScreeningDescTag:
+ return "Screening Description";
+ case icSigScreeningTag:
+ return "Screening Attributes";
+ case icSigTechnologyTag:
+ return "Device Technology";
+ case icSigUcrBgTag:
+ return "Under Color Removal & Black Generation";
+ case icSigVideoCardGammaTag:
+ return "Video Card Gamma Curve";
+ case icSigViewingCondDescTag:
+ return "Viewing Condition Description";
+ case icSigViewingConditionsTag:
+ return "Viewing Condition Paramaters";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* technology signature descriptions */
+static const char *string_TechnologySignature(icTechnologySignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigDigitalCamera:
+ return "Digital Camera";
+ case icSigFilmScanner:
+ return "Film Scanner";
+ case icSigReflectiveScanner:
+ return "Reflective Scanner";
+ case icSigInkJetPrinter:
+ return "InkJet Printer";
+ case icSigThermalWaxPrinter:
+ return "Thermal WaxPrinter";
+ case icSigElectrophotographicPrinter:
+ return "Electrophotographic Printer";
+ case icSigElectrostaticPrinter:
+ return "Electrostatic Printer";
+ case icSigDyeSublimationPrinter:
+ return "DyeSublimation Printer";
+ case icSigPhotographicPaperPrinter:
+ return "Photographic Paper Printer";
+ case icSigFilmWriter:
+ return "Film Writer";
+ case icSigVideoMonitor:
+ return "Video Monitor";
+ case icSigVideoCamera:
+ return "Video Camera";
+ case icSigProjectionTelevision:
+ return "Projection Television";
+ case icSigCRTDisplay:
+ return "Cathode Ray Tube Display";
+ case icSigPMDisplay:
+ return "Passive Matrix Display";
+ case icSigAMDisplay:
+ return "Active Matrix Display";
+ case icSigPhotoCD:
+ return "Photo CD";
+ case icSigPhotoImageSetter:
+ return "Photo ImageSetter";
+ case icSigGravure:
+ return "Gravure";
+ case icSigOffsetLithography:
+ return "Offset Lithography";
+ case icSigSilkscreen:
+ return "Silkscreen";
+ case icSigFlexography:
+ return "Flexography";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* type signatures */
+static const char *string_TypeSignature(icTagTypeSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigCurveType:
+ return "Curve";
+ case icSigDataType:
+ return "Data";
+ case icSigDateTimeType:
+ return "DateTime";
+ case icSigLut16Type:
+ return "Lut16";
+ case icSigLut8Type:
+ return "Lut8";
+ case icSigMeasurementType:
+ return "Measurement";
+ case icSigNamedColorType:
+ return "Named Color";
+ case icSigProfileSequenceDescType:
+ return "Profile Sequence Desc";
+ case icSigS15Fixed16ArrayType:
+ return "S15Fixed16 Array";
+ case icSigScreeningType:
+ return "Screening";
+ case icSigSignatureType:
+ return "Signature";
+ case icSigTextType:
+ return "Text";
+ case icSigTextDescriptionType:
+ return "Text Description";
+ case icSigU16Fixed16ArrayType:
+ return "U16Fixed16 Array";
+ case icSigUcrBgType:
+ return "Under Color Removal & Black Generation";
+ case icSigUInt16ArrayType:
+ return "UInt16 Array";
+ case icSigUInt32ArrayType:
+ return "UInt32 Array";
+ case icSigUInt64ArrayType:
+ return "UInt64 Array";
+ case icSigUInt8ArrayType:
+ return "UInt8 Array";
+ case icSigVideoCardGammaType:
+ return "Video Card Gamma";
+ case icSigViewingConditionsType:
+ return "Viewing Conditions";
+ case icSigXYZType:
+ return "XYZ (Array?)";
+ case icSigNamedColor2Type:
+ return "Named Color 2";
+ case icSigCrdInfoType:
+ return "CRD Info";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* Color Space Signatures */
+static const char *string_ColorSpaceSignature(icColorSpaceSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigXYZData:
+ return "XYZ";
+ case icSigLabData:
+ return "Lab";
+ case icSigLuvData:
+ return "Luv";
+ case icSigYCbCrData:
+ return "YCbCr";
+ case icSigYxyData:
+ return "Yxy";
+ case icSigRgbData:
+ return "RGB";
+ case icSigGrayData:
+ return "Gray";
+ case icSigHsvData:
+ return "HSV";
+ case icSigHlsData:
+ return "HLS";
+ case icSigCmykData:
+ return "CMYK";
+ case icSigCmyData:
+ return "CMY";
+ case icSig2colorData:
+ return "2 Color";
+ case icSig3colorData:
+ return "3 Color";
+ case icSig4colorData:
+ return "4 Color";
+ case icSig5colorData:
+ case icSigMch5Data:
+ return "5 Color";
+ case icSig6colorData:
+ case icSigMch6Data:
+ return "6 Color";
+ case icSig7colorData:
+ case icSigMch7Data:
+ return "7 Color";
+ case icSig8colorData:
+ case icSigMch8Data:
+ return "8 Color";
+ case icSig9colorData:
+ return "9 Color";
+ case icSig10colorData:
+ return "10 Color";
+ case icSig11colorData:
+ return "11 Color";
+ case icSig12colorData:
+ return "12 Color";
+ case icSig13colorData:
+ return "13 Color";
+ case icSig14colorData:
+ return "14 Color";
+ case icSig15colorData:
+ return "15 Color";
+
+ /* Non-standard and Pseudo spaces */
+ case icmSigYData:
+ return "Y";
+ case icmSigLData:
+ return "L";
+ case icmSigL8Data:
+ return "L";
+ case icmSigLV2Data:
+ return "L";
+ case icmSigLV4Data:
+ return "L";
+ case icmSigPCSData:
+ return "PCS";
+ case icmSigLab8Data:
+ return "Lab";
+ case icmSigLabV2Data:
+ return "Lab";
+ case icmSigLabV4Data:
+ return "Lab";
+
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+#ifdef NEVER
+/* Public version of above */
+char *ColorSpaceSignature2str(icColorSpaceSignature sig) {
+ return string_ColorSpaceSignature(sig);
+}
+#endif
+
+
+/* profileClass enumerations */
+static const char *string_ProfileClassSignature(icProfileClassSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigInputClass:
+ return "Input";
+ case icSigDisplayClass:
+ return "Display";
+ case icSigOutputClass:
+ return "Output";
+ case icSigLinkClass:
+ return "Link";
+ case icSigAbstractClass:
+ return "Abstract";
+ case icSigColorSpaceClass:
+ return "Color Space";
+ case icSigNamedColorClass:
+ return "Named Color";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* Platform Signatures */
+static const char *string_PlatformSignature(icPlatformSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigMacintosh:
+ return "Macintosh";
+ case icSigMicrosoft:
+ return "Microsoft";
+ case icSigSolaris:
+ return "Solaris";
+ case icSigSGI:
+ return "SGI";
+ case icSigTaligent:
+ return "Taligent";
+ case icmSig_nix:
+ return "*nix";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* Measurement Geometry, used in the measurmentType tag */
+static const char *string_MeasurementGeometry(icMeasurementGeometry sig) {
+ static char buf[30];
+ switch(sig) {
+ case icGeometryUnknown:
+ return "Unknown";
+ case icGeometry045or450:
+ return "0/45 or 45/0";
+ case icGeometry0dord0:
+ return "0/d or d/0";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Rendering Intents, used in the profile header */
+static const char *string_RenderingIntent(icRenderingIntent sig) {
+ static char buf[30];
+ switch(sig) {
+ case icPerceptual:
+ return "Perceptual";
+ case icRelativeColorimetric:
+ return "Relative Colorimetric";
+ case icSaturation:
+ return "Saturation";
+ case icAbsoluteColorimetric:
+ return "Absolute Colorimetric";
+ case icmAbsolutePerceptual: /* icclib specials */
+ return "Absolute Perceptual";
+ case icmAbsoluteSaturation: /* icclib specials */
+ return "Absolute Saturation";
+ case icmDefaultIntent: /* icclib specials */
+ return "Default Intent";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Transform Lookup function */
+static const char *string_LookupFunc(icmLookupFunc sig) {
+ static char buf[30];
+ switch(sig) {
+ case icmFwd:
+ return "Forward";
+ case icmBwd:
+ return "Backward";
+ case icmGamut:
+ return "Gamut";
+ case icmPreview:
+ return "Preview";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+
+/* Different Spot Shapes currently defined, used for screeningType */
+static const char *string_SpotShape(icSpotShape sig) {
+ static char buf[30];
+ switch(sig) {
+ case icSpotShapeUnknown:
+ return "Unknown";
+ case icSpotShapePrinterDefault:
+ return "Printer Default";
+ case icSpotShapeRound:
+ return "Round";
+ case icSpotShapeDiamond:
+ return "Diamond";
+ case icSpotShapeEllipse:
+ return "Ellipse";
+ case icSpotShapeLine:
+ return "Line";
+ case icSpotShapeSquare:
+ return "Square";
+ case icSpotShapeCross:
+ return "Cross";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Standard Observer, used in the measurmentType tag */
+static const char *string_StandardObserver(icStandardObserver sig) {
+ static char buf[30];
+ switch(sig) {
+ case icStdObsUnknown:
+ return "Unknown";
+ case icStdObs1931TwoDegrees:
+ return "1931 Two Degrees";
+ case icStdObs1964TenDegrees:
+ return "1964 Ten Degrees";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Pre-defined illuminants, used in measurement and viewing conditions type */
+static const char *string_Illuminant(icIlluminant sig) {
+ static char buf[30];
+ switch(sig) {
+ case icIlluminantUnknown:
+ return "Unknown";
+ case icIlluminantD50:
+ return "D50";
+ case icIlluminantD65:
+ return "D65";
+ case icIlluminantD93:
+ return "D93";
+ case icIlluminantF2:
+ return "F2";
+ case icIlluminantD55:
+ return "D55";
+ case icIlluminantA:
+ return "A";
+ case icIlluminantEquiPowerE:
+ return "Equi-Power(E)";
+ case icIlluminantF8:
+ return "F8";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Return a text abreviation of a color lookup algorithm */
+static const char *string_LuAlg(icmLuAlgType alg) {
+ static char buf[80];
+
+ switch(alg) {
+ case icmMonoFwdType:
+ return "MonoFwd";
+ case icmMonoBwdType:
+ return "MonoBwd";
+ case icmMatrixFwdType:
+ return "MatrixFwd";
+ case icmMatrixBwdType:
+ return "MatrixBwd";
+ case icmLutType:
+ return "Lut";
+ default:
+ sprintf(buf,"Unrecognized - %d",alg);
+ return buf;
+ }
+}
+
+/* Return a string description of the given enumeration value */
+/* Public: */
+const char *icm2str(icmEnumType etype, int enumval) {
+
+ switch(etype) {
+ case icmScreenEncodings:
+ return string_ScreenEncodings((unsigned int) enumval);
+ case icmDeviceAttributes:
+ return string_DeviceAttributes((unsigned int) enumval);
+ case icmProfileHeaderFlags:
+ return string_ProfileHeaderFlags((unsigned int) enumval);
+ case icmAsciiOrBinaryData:
+ return string_AsciiOrBinaryData((unsigned int) enumval);
+ case icmTagSignature:
+ return string_TagSignature((icTagSignature) enumval);
+ case icmTechnologySignature:
+ return string_TechnologySignature((icTechnologySignature) enumval);
+ case icmTypeSignature:
+ return string_TypeSignature((icTagTypeSignature) enumval);
+ case icmColorSpaceSignature:
+ return string_ColorSpaceSignature((icColorSpaceSignature) enumval);
+ case icmProfileClassSignature:
+ return string_ProfileClassSignature((icProfileClassSignature) enumval);
+ case icmPlatformSignature:
+ return string_PlatformSignature((icPlatformSignature) enumval);
+ case icmMeasurementGeometry:
+ return string_MeasurementGeometry((icMeasurementGeometry) enumval);
+ case icmRenderingIntent:
+ return string_RenderingIntent((icRenderingIntent) enumval);
+ case icmTransformLookupFunc:
+ return string_LookupFunc((icmLookupFunc) enumval);
+ case icmSpotShape:
+ return string_SpotShape((icSpotShape) enumval);
+ case icmStandardObserver:
+ return string_StandardObserver((icStandardObserver) enumval);
+ case icmIlluminant:
+ return string_Illuminant((icIlluminant) enumval);
+ case icmLuAlg:
+ return string_LuAlg((icmLuAlgType) enumval);
+ default:
+ return "enum2str got unknown type";
+ }
+}
+
+/* ========================================================== */
+/* Object I/O routines */
+/* ========================================================== */
+/* icmUnknown object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUnknown_get_size(
+ icmBase *pp
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 1); /* 1 byte for each unknown data */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUnknown_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUnknown_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUnknown_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUnknown_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/1; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ p->uttype = (icTagTypeSignature)read_SInt32Number(bp);
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 1) {
+ p->data[i] = read_UInt8Number(bp);
+ }
+ icp->al->free(p->icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUnknown_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUnknown_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUnknown_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->uttype,bp)) != 0) {
+ sprintf(icp->err,"icmUnknown_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp += 8; /* Skip padding */
+
+ /* Write all the data to the buffer */
+ for (i = 0; i < p->size; i++, bp += 1) {
+ if ((rv = write_UInt8Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUnknown_write: write_UInt8umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUnknown_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUnknown_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ unsigned int i, ii, r, ph;
+
+ if (verb <= 1)
+ return;
+
+ op->gprintf(op,"Unknown:\n");
+ op->gprintf(op," Payload size in bytes = %u\n",p->size);
+
+ /* Print one row of binary and ASCII interpretation if verb == 2, All if == 3 */
+ /* else print all of it. */
+ ii = i = ph = 0;
+ for (r = 1;; r++) { /* count rows */
+ int c = 1; /* Character location */
+
+ c = 1;
+ if (ph != 0) { /* Print ASCII under binary */
+ op->gprintf(op," ");
+ i = ii; /* Swap */
+ c += 12;
+ } else {
+ op->gprintf(op," 0x%04lx: ",i);
+ ii = i; /* Swap */
+ c += 12;
+ }
+ while (i < p->size && c < 60) {
+ if (ph == 0)
+ op->gprintf(op,"%02x ",p->data[i]);
+ else {
+ if (isprint(p->data[i]))
+ op->gprintf(op,"%c ",p->data[i]);
+ else
+ op->gprintf(op," ",p->data[i]);
+ }
+ c += 3;
+ i++;
+ }
+ if (ph == 0 || i < p->size)
+ op->gprintf(op,"\n");
+
+ if (ph == 1 && i >= p->size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (ph == 1 && r > 1 && verb < 3) {
+ op->gprintf(op," ...\n");
+ break; /* Print 1 row if not verbose */
+ }
+
+ if (ph == 0)
+ ph = 1;
+ else
+ ph = 0;
+
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUnknown_allocate(
+ icmBase *pp
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned char))) {
+ sprintf(icp->err,"icmUnknown_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned char *) icp->al->calloc(icp->al, p->size, sizeof(unsigned char)))
+ == NULL) {
+ sprintf(icp->err,"icmUnknown_alloc: malloc() of icmUnknown data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUnknown_delete(
+ icmBase *pp
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUnknown(
+ icc *icp
+) {
+ icmUnknown *p;
+ if ((p = (icmUnknown *) icp->al->calloc(icp->al,1,sizeof(icmUnknown))) == NULL)
+ return NULL;
+ p->ttype = icmSigUnknownType;
+ p->uttype = icmSigUnknownType;
+ p->refcount = 1;
+ p->get_size = icmUnknown_get_size;
+ p->read = icmUnknown_read;
+ p->write = icmUnknown_write;
+ p->dump = icmUnknown_dump;
+ p->allocate = icmUnknown_allocate;
+ p->del = icmUnknown_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUInt8Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUInt8Array_get_size(
+ icmBase *pp
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 1); /* 1 byte for each UInt8 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUInt8Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUInt8Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt8Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUInt8Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/1; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ icp->al->free(icp->al, buf);
+ sprintf(icp->err,"icmUInt8Array_read: Wrong tag type for icmUInt8Array");
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 1) {
+ p->data[i] = read_UInt8Number(bp);
+ }
+ icp->al->free(p->icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUInt8Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUInt8Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt8Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUInt8Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp += 8; /* Skip padding */
+
+ /* Write all the data to the buffer */
+ for (i = 0; i < p->size; i++, bp += 1) {
+ if ((rv = write_UInt8Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUInt8Array_write: write_UInt8umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUInt8Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUInt8Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"UInt8Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %u\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUInt8Array_allocate(
+ icmBase *pp
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned int))) {
+ sprintf(icp->err,"icmUInt8Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned int *) icp->al->calloc(icp->al, p->size, sizeof(unsigned int)))
+ == NULL) {
+ sprintf(icp->err,"icmUInt8Array_alloc: malloc() of icmUInt8Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUInt8Array_delete(
+ icmBase *pp
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUInt8Array(
+ icc *icp
+) {
+ icmUInt8Array *p;
+ if ((p = (icmUInt8Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt8Array))) == NULL)
+ return NULL;
+ p->ttype = icSigUInt8ArrayType;
+ p->refcount = 1;
+ p->get_size = icmUInt8Array_get_size;
+ p->read = icmUInt8Array_read;
+ p->write = icmUInt8Array_write;
+ p->dump = icmUInt8Array_dump;
+ p->allocate = icmUInt8Array_allocate;
+ p->del = icmUInt8Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUInt16Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUInt16Array_get_size(
+ icmBase *pp
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 2); /* 2 bytes for each UInt16 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUInt16Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUInt16Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt16Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUInt16Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/2; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmUInt16Array_read: Wrong tag type for icmUInt16Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 2) {
+ p->data[i] = read_UInt16Number(bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUInt16Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUInt16Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt16Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUInt16Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 2) {
+ if ((rv = write_UInt16Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUInt16Array_write: write_UInt16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUInt16Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUInt16Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"UInt16Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %u\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUInt16Array_allocate(
+ icmBase *pp
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned int))) {
+ sprintf(icp->err,"icmUInt16Array_alloc:: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned int *) icp->al->calloc(icp->al, p->size, sizeof(unsigned int)))
+ == NULL) {
+ sprintf(icp->err,"icmUInt16Array_alloc: malloc() of icmUInt16Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUInt16Array_delete(
+ icmBase *pp
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUInt16Array(
+ icc *icp
+) {
+ icmUInt16Array *p;
+ if ((p = (icmUInt16Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt16Array))) == NULL)
+ return NULL;
+ p->ttype = icSigUInt16ArrayType;
+ p->refcount = 1;
+ p->get_size = icmUInt16Array_get_size;
+ p->read = icmUInt16Array_read;
+ p->write = icmUInt16Array_write;
+ p->dump = icmUInt16Array_dump;
+ p->allocate = icmUInt16Array_allocate;
+ p->del = icmUInt16Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUInt32Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUInt32Array_get_size(
+ icmBase *pp
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 4); /* 4 bytes for each UInt32 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUInt32Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUInt32Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt32Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUInt32Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/4; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmUInt32Array_read: Wrong tag type for icmUInt32Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 4) {
+ p->data[i] = read_UInt32Number(bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUInt32Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUInt32Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt32Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUInt32Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 4) {
+ if ((rv = write_UInt32Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUInt32Array_write: write_UInt32umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUInt32Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUInt32Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"UInt32Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %u\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUInt32Array_allocate(
+ icmBase *pp
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned int))) {
+ sprintf(icp->err,"icmUInt32Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned int *) icp->al->calloc(icp->al, p->size, sizeof(unsigned int)))
+ == NULL) {
+ sprintf(icp->err,"icmUInt32Array_alloc: malloc() of icmUInt32Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUInt32Array_delete(
+ icmBase *pp
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUInt32Array(
+ icc *icp
+) {
+ icmUInt32Array *p;
+ if ((p = (icmUInt32Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt32Array))) == NULL)
+ return NULL;
+ p->ttype = icSigUInt32ArrayType;
+ p->refcount = 1;
+ p->get_size = icmUInt32Array_get_size;
+ p->read = icmUInt32Array_read;
+ p->write = icmUInt32Array_write;
+ p->dump = icmUInt32Array_dump;
+ p->allocate = icmUInt32Array_allocate;
+ p->del = icmUInt32Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUInt64Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUInt64Array_get_size(
+ icmBase *pp
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 8); /* 8 bytes for each UInt64 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUInt64Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUInt64Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt64Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUInt64Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/8; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmUInt64Array_read: Wrong tag type for icmUInt64Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 8) {
+ read_UInt64Number(&p->data[i], bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUInt64Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUInt64Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt64Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUInt64Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 8) {
+ if ((rv = write_UInt64Number(&p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUInt64Array_write: write_UInt64umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUInt64Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUInt64Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"UInt64Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: h=%lu, l=%lu\n",i,p->data[i].h,p->data[i].l);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUInt64Array_allocate(
+ icmBase *pp
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(icmUint64))) {
+ sprintf(icp->err,"icmUInt64Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmUint64 *) icp->al->calloc(icp->al, p->size, sizeof(icmUint64)))
+ == NULL) {
+ sprintf(icp->err,"icmUInt64Array_alloc: malloc() of icmUInt64Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUInt64Array_delete(
+ icmBase *pp
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUInt64Array(
+ icc *icp
+) {
+ icmUInt64Array *p;
+ if ((p = (icmUInt64Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt64Array))) == NULL)
+ return NULL;
+ p->ttype = icSigUInt64ArrayType;
+ p->refcount = 1;
+ p->get_size = icmUInt64Array_get_size;
+ p->read = icmUInt64Array_read;
+ p->write = icmUInt64Array_write;
+ p->dump = icmUInt64Array_dump;
+ p->allocate = icmUInt64Array_allocate;
+ p->del = icmUInt64Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmU16Fixed16Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmU16Fixed16Array_get_size(
+ icmBase *pp
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 4); /* 4 byte for each U16Fixed16 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmU16Fixed16Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmU16Fixed16Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmU16Fixed16Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmU16Fixed16Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/4; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmU16Fixed16Array_read: Wrong tag type for icmU16Fixed16Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 4) {
+ p->data[i] = read_U16Fixed16Number(bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmU16Fixed16Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmU16Fixed16Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmU16Fixed16Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmU16Fixed16Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 4) {
+ if ((rv = write_U16Fixed16Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmU16Fixed16Array_write: write_U16Fixed16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmU16Fixed16Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmU16Fixed16Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"U16Fixed16Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %f\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmU16Fixed16Array_allocate(
+ icmBase *pp
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(double))) {
+ sprintf(icp->err,"icmU16Fixed16Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (double *) icp->al->calloc(icp->al, p->size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmU16Fixed16Array_alloc: malloc() of icmU16Fixed16Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmU16Fixed16Array_delete(
+ icmBase *pp
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmU16Fixed16Array(
+ icc *icp
+) {
+ icmU16Fixed16Array *p;
+ if ((p = (icmU16Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmU16Fixed16Array))) == NULL)
+ return NULL;
+ p->ttype = icSigU16Fixed16ArrayType;
+ p->refcount = 1;
+ p->get_size = icmU16Fixed16Array_get_size;
+ p->read = icmU16Fixed16Array_read;
+ p->write = icmU16Fixed16Array_write;
+ p->dump = icmU16Fixed16Array_dump;
+ p->allocate = icmU16Fixed16Array_allocate;
+ p->del = icmU16Fixed16Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmS15Fixed16Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmS15Fixed16Array_get_size(
+ icmBase *pp
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 4); /* 4 byte for each S15Fixed16 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmS15Fixed16Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmS15Fixed16Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmS15Fixed16Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmS15Fixed16Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/4; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmS15Fixed16Array_read: Wrong tag type for icmS15Fixed16Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 4) {
+ p->data[i] = read_S15Fixed16Number(bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmS15Fixed16Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmS15Fixed16Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmS15Fixed16Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmS15Fixed16Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 4) {
+ if ((rv = write_S15Fixed16Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmS15Fixed16Array_write: write_S15Fixed16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmS15Fixed16Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmS15Fixed16Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"S15Fixed16Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %f\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmS15Fixed16Array_allocate(
+ icmBase *pp
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(double))) {
+ sprintf(icp->err,"icmS15Fixed16Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (double *) icp->al->calloc(icp->al, p->size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmS15Fixed16Array_alloc: malloc() of icmS15Fixed16Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmS15Fixed16Array_delete(
+ icmBase *pp
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmS15Fixed16Array(
+ icc *icp
+) {
+ icmS15Fixed16Array *p;
+ if ((p = (icmS15Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmS15Fixed16Array))) == NULL)
+ return NULL;
+ p->ttype = icSigS15Fixed16ArrayType;
+ p->refcount = 1;
+ p->get_size = icmS15Fixed16Array_get_size;
+ p->read = icmS15Fixed16Array_read;
+ p->write = icmS15Fixed16Array_write;
+ p->dump = icmS15Fixed16Array_dump;
+ p->allocate = icmS15Fixed16Array_allocate;
+ p->del = icmS15Fixed16Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Data conversion support functions */
+static int write_XYZNumber(icmXYZNumber *p, char *d) {
+ int rv;
+ if ((rv = write_S15Fixed16Number(p->X, d + 0)) != 0)
+ return rv;
+ if ((rv = write_S15Fixed16Number(p->Y, d + 4)) != 0)
+ return rv;
+ if ((rv = write_S15Fixed16Number(p->Z, d + 8)) != 0)
+ return rv;
+ return 0;
+}
+
+static int read_XYZNumber(icmXYZNumber *p, char *d) {
+ p->X = read_S15Fixed16Number(d + 0);
+ p->Y = read_S15Fixed16Number(d + 4);
+ p->Z = read_S15Fixed16Number(d + 8);
+ return 0;
+}
+
+
+/* Helper: Return a string that shows the XYZ number value */
+static char *string_XYZNumber(icmXYZNumber *p) {
+ static char buf[40];
+
+ sprintf(buf,"%f, %f, %f", p->X, p->Y, p->Z);
+ return buf;
+}
+
+/* Helper: Return a string that shows the XYZ number value, */
+/* and the Lab D50 number in paren. Note the buffer will be re-used on every call. */
+static char *string_XYZNumber_and_Lab(icmXYZNumber *p) {
+ static char buf[100];
+ double lab[3];
+ lab[0] = p->X;
+ lab[1] = p->Y;
+ lab[2] = p->Z;
+ icmXYZ2Lab(&icmD50, lab, lab);
+ snprintf(buf,sizeof(buf),"%f, %f, %f [Lab %f, %f, %f]", p->X, p->Y, p->Z, lab[0], lab[1], lab[2]);
+ return buf;
+}
+
+/* icmXYZArray object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmXYZArray_get_size(
+ icmBase *pp
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 12); /* 12 bytes for each XYZ */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmXYZArray_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmXYZArray_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmXYZArray_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmXYZArray_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/12; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmXYZArray_read: Wrong tag type for icmXYZArray");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 12) {
+ read_XYZNumber(&p->data[i], bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmXYZArray_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmXYZArray_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmXYZArray_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmXYZArray_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 12) {
+ if ((rv = write_XYZNumber(&p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmXYZArray_write: write_XYZumber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmXYZArray_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmXYZArray_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"XYZArray:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++) {
+ op->gprintf(op," %lu: %s\n",i,string_XYZNumber_and_Lab(&p->data[i]));
+
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmXYZArray_allocate(
+ icmBase *pp
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(icmXYZNumber))) {
+ sprintf(icp->err,"icmXYZArray_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmXYZNumber *) icp->al->malloc(icp->al, sat_mul(p->size, sizeof(icmXYZNumber)))) == NULL) {
+ sprintf(icp->err,"icmXYZArray_alloc: malloc() of icmXYZArray data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmXYZArray_delete(
+ icmBase *pp
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmXYZArray(
+ icc *icp
+) {
+ icmXYZArray *p;
+ if ((p = (icmXYZArray *) icp->al->calloc(icp->al,1,sizeof(icmXYZArray))) == NULL)
+ return NULL;
+ p->ttype = icSigXYZArrayType;
+ p->refcount = 1;
+ p->get_size = icmXYZArray_get_size;
+ p->read = icmXYZArray_read;
+ p->write = icmXYZArray_write;
+ p->dump = icmXYZArray_dump;
+ p->allocate = icmXYZArray_allocate;
+ p->del = icmXYZArray_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmCurve object */
+
+/* Do a forward lookup through the curve */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmCurve_lookup_fwd(
+ icmCurve *p,
+ double *out,
+ double *in
+) {
+ int rv = 0;
+ if (p->flag == icmCurveLin) {
+ *out = *in;
+ } else if (p->flag == icmCurveGamma) {
+ double val = *in;
+ if (val <= 0.0)
+ *out = 0.0;
+ else
+ *out = pow(val, p->data[0]);
+ } else if (p->size == 0) { /* Table of 0 size */
+ *out = *in;
+ } else { /* Use linear interpolation */
+ unsigned int ix;
+ double val, w;
+ double inputEnt_1 = (double)(p->size-1);
+
+ val = *in * inputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > inputEnt_1) {
+ val = inputEnt_1;
+ rv |= 1;
+ }
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (p->size-2))
+ ix = (p->size-2);
+ w = val - (double)ix; /* weight */
+ val = p->data[ix];
+ *out = val + w * (p->data[ix+1] - val);
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - */
+/* Support for reverse interpolation of 1D lookup tables */
+
+/* Create a reverse curve lookup acceleration table */
+/* return non-zero on error, 2 = malloc error. */
+static int icmTable_setup_bwd(
+ icc *icp, /* Base icc object */
+ icmRevTable *rt, /* Reverse table data to setup */
+ unsigned int size, /* Size of fwd table */
+ double *data /* Table */
+) {
+ unsigned int i;
+
+ rt->size = size; /* Stash pointers to these away */
+ rt->data = data;
+
+ /* Find range of output values */
+ rt->rmin = 1e300;
+ rt->rmax = -1e300;
+ for (i = 0; i < rt->size; i++) {
+ if (rt->data[i] > rt->rmax)
+ rt->rmax = rt->data[i];
+ if (rt->data[i] < rt->rmin)
+ rt->rmin = rt->data[i];
+ }
+
+ /* Decide on reverse granularity */
+ rt->rsize = sat_add(rt->size,2)/2;
+ rt->qscale = (double)rt->rsize/(rt->rmax - rt->rmin); /* Scale factor to quantize to */
+
+ if (ovr_mul(rt->size, sizeof(unsigned int *))) {
+ return 2;
+ }
+ /* Initialize the reverse lookup structures, and get overall min/max */
+ if ((rt->rlists = (unsigned int **) icp->al->calloc(icp->al, rt->rsize, sizeof(unsigned int *))) == NULL) {
+ return 2;
+ }
+
+ /* Assign each output value range bucket lists it intersects */
+ for (i = 0; i < (rt->size-1); i++) {
+ unsigned int s, e, j; /* Start and end indexes (inclusive) */
+ s = (unsigned int)((rt->data[i] - rt->rmin) * rt->qscale);
+ e = (unsigned int)((rt->data[i+1] - rt->rmin) * rt->qscale);
+ if (s >= rt->rsize)
+ s = rt->rsize-1;
+ if (e >= rt->rsize)
+ e = rt->rsize-1;
+ if (s > e) { /* swap */
+ unsigned int t;
+ t = s; s = e; e = t;
+ }
+
+ /* For all buckets that may contain this output range, add index of this output */
+ for (j = s; j <= e; j++) {
+ unsigned int as; /* Allocation size */
+ unsigned int nf; /* Next free slot */
+ if (rt->rlists[j] == NULL) { /* No allocation */
+ as = 5; /* Start with space for 5 */
+ if ((rt->rlists[j] = (unsigned int *) icp->al->calloc(icp->al, as, sizeof(unsigned int))) == NULL) {
+ return 2;
+ }
+ rt->rlists[j][0] = as;
+ nf = rt->rlists[j][1] = 2;
+ } else {
+ as = rt->rlists[j][0]; /* Allocate space for this list */
+ nf = rt->rlists[j][1]; /* Next free location in list */
+ if (nf >= as) { /* need to expand space */
+ if ((as = sat_mul(as, 2)) == UINT_MAX
+ || ovr_mul(as, sizeof(unsigned int))) {
+ return 2;
+ }
+ rt->rlists[j] = (unsigned int *) icp->al->realloc(icp->al,rt->rlists[j], as * sizeof(unsigned int));
+ if (rt->rlists[j] == NULL) {
+ return 2;
+ }
+ rt->rlists[j][0] = as;
+ }
+ }
+ rt->rlists[j][nf++] = i;
+ rt->rlists[j][1] = nf;
+ }
+ }
+ rt->inited = 1;
+ return 0;
+}
+
+/* Free up any data */
+static void icmTable_delete_bwd(
+ icc *icp, /* Base icc */
+ icmRevTable *rt /* Reverse table data to setup */
+) {
+ if (rt->inited != 0) {
+ while (rt->rsize > 0)
+ icp->al->free(icp->al, rt->rlists[--rt->rsize]);
+ icp->al->free(icp->al, rt->rlists);
+ rt->size = 0; /* Don't keep these */
+ rt->data = NULL;
+ }
+}
+
+/* Do a reverse lookup through the curve */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmTable_lookup_bwd(
+ icmRevTable *rt,
+ double *out,
+ double *in
+) {
+ int rv = 0;
+ unsigned int ix, k, i;
+ double oval, ival = *in, val;
+ double rsize_1;
+
+ /* Find appropriate reverse list */
+ rsize_1 = (double)(rt->rsize-1);
+ val = ((ival - rt->rmin) * rt->qscale);
+ if (val < 0.0)
+ val = 0.0;
+ else if (val > rsize_1)
+ val = rsize_1;
+ ix = (unsigned int)floor(val); /* Coordinate */
+
+ if (ix > (rt->size-2))
+ ix = (rt->size-2);
+ if (rt->rlists[ix] != NULL) { /* There is a list of fwd candidates */
+ /* For each candidate forward range */
+ for (i = 2; i < rt->rlists[ix][1]; i++) { /* For all fwd indexes */
+ double lv,hv;
+ k = rt->rlists[ix][i]; /* Base index */
+ lv = rt->data[k];
+ hv = rt->data[k+1];
+ if ((ival >= lv && ival <= hv) /* If this slot contains output value */
+ || (ival >= hv && ival <= lv)) {
+ /* Reverse linear interpolation */
+ if (hv == lv) { /* Technically non-monotonic - due to quantization ? */
+ oval = (k + 0.5)/(rt->size-1.0);
+ } else
+ oval = (k + ((ival - lv)/(hv - lv)))/(rt->size-1.0);
+ /* If we kept looking, we would find multiple */
+ /* solution for non-monotonic curve */
+ *out = oval;
+ return rv;
+ }
+ }
+ }
+
+ /* We have failed to find an exact value, so return the nearest value */
+ /* (This is slow !) */
+ val = fabs(ival - rt->data[0]);
+ for (k = 0, i = 1; i < rt->size; i++) {
+ double er;
+ er = fabs(ival - rt->data[i]);
+ if (er < val) { /* new best */
+ val = er;
+ k = i;
+ }
+ }
+ *out = k/(rt->size-1.0);
+ rv |= 1;
+ return rv;
+}
+
+
+/* - - - - - - - - - - - - */
+
+/* Do a reverse lookup through the curve */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmCurve_lookup_bwd(
+ icmCurve *p,
+ double *out,
+ double *in
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+ if (p->flag == icmCurveLin) {
+ *out = *in;
+ } else if (p->flag == icmCurveGamma) {
+ double val = *in;
+ if (val <= 0.0)
+ *out = 0.0;
+ else
+ *out = pow(val, 1.0/p->data[0]);
+ } else if (p->size == 0) { /* Table of 0 size */
+ *out = *in;
+ } else { /* Use linear interpolation */
+ if (p->rt.inited == 0) {
+ rv = icmTable_setup_bwd(icp, &p->rt, p->size, p->data);
+ if (rv != 0) {
+ sprintf(icp->err,"icmCurve_lookup: Malloc failure in reverse lookup init.");
+ return icp->errc = rv;
+ }
+ }
+ rv = icmTable_lookup_bwd(&p->rt, out, in);
+ }
+ return rv;
+}
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmCurve_get_size(
+ icmBase *pp
+) {
+ icmCurve *p = (icmCurve *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 12); /* 12 bytes for tag, padding and count */
+ len = sat_addmul(len, p->size, 2); /* 2 bytes for each UInt16 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmCurve_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmCurve *p = (icmCurve *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i;
+ char *bp, *buf, *end;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmCurve_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmCurve_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmCurve_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmCurve_read: Wrong tag type for icmCurve");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ p->size = read_UInt32Number(bp+8);
+ bp = bp + 12;
+
+ /* Set flag up before allocating */
+ if (p->size == 0) { /* Linear curve */
+ p->flag = icmCurveLin;
+ } else if (p->size == 1) { /* Gamma curve */
+ p->flag = icmCurveGamma;
+ } else {
+ p->flag = icmCurveSpec;
+ if (p->size > (len - 12)/2) {
+ sprintf(icp->err,"icmCurve_read: size overflow");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ if (p->flag == icmCurveGamma) { /* Gamma curve */
+ if (bp > end || 1 > (end - bp)) {
+ sprintf(icp->err,"icmCurve_read: Data too short for curve gamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->data[0] = read_U8Fixed8Number(bp);
+ } else if (p->flag == icmCurveSpec) {
+ /* Read all the data from the buffer */
+ for (i = 0; i < p->size; i++, bp += 2) {
+ if (bp > end || 2 > (end - bp)) {
+ sprintf(icp->err,"icmCurve_read: Data too short for curve value");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->data[i] = read_DCS16Number(bp);
+ }
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmCurve_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmCurve *p = (icmCurve *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmCurve_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmCurve_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmCurve_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write count */
+ if ((rv = write_UInt32Number(p->size,bp+8)) != 0) {
+ sprintf(icp->err,"icmCurve_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write all the data to the buffer */
+ bp += 12; /* Skip padding */
+ if (p->flag == icmCurveLin) {
+ if (p->size != 0) {
+ sprintf(icp->err,"icmCurve_write: Must be exactly 0 entry for Linear");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ } else if (p->flag == icmCurveGamma) {
+ if (p->size != 1) {
+ sprintf(icp->err,"icmCurve_write: Must be exactly 1 entry for Gamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if ((rv = write_U8Fixed8Number(p->data[0],bp)) != 0) {
+ sprintf(icp->err,"icmCurve_write: write_U8Fixed8umber(%f) failed",p->data[0]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ } else if (p->flag == icmCurveSpec) {
+ if (p->size < 2) {
+ sprintf(icp->err,"icmCurve_write: Must be 2 or more entries for Specified curve");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ for (i = 0; i < p->size; i++, bp += 2) {
+ if ((rv = write_DCS16Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmCurve_write: write_UInt16umber(%f) failed",p->data[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmCurve_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmCurve_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmCurve *p = (icmCurve *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Curve:\n");
+
+ if (p->flag == icmCurveLin) {
+ op->gprintf(op," Curve is linear\n");
+ } else if (p->flag == icmCurveGamma) {
+ op->gprintf(op," Curve is gamma of %f\n",p->data[0]);
+ } else {
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %3lu: %f\n",i,p->data[i]);
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmCurve_allocate(
+ icmBase *pp
+) {
+ icmCurve *p = (icmCurve *)pp;
+ icc *icp = p->icp;
+
+ if (p->flag == icmCurveUndef) {
+ sprintf(icp->err,"icmCurve_alloc: flag not set");
+ return icp->errc = 1;
+ } else if (p->flag == icmCurveLin) {
+ p->size = 0;
+ } else if (p->flag == icmCurveGamma) {
+ p->size = 1;
+ }
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(double))) {
+ sprintf(icp->err,"icmCurve_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (double *) icp->al->calloc(icp->al, p->size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmCurve_alloc: malloc() of icmCurve data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmCurve_delete(
+ icmBase *pp
+) {
+ icmCurve *p = (icmCurve *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icmTable_delete_bwd(icp, &p->rt); /* Free reverse table info */
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmCurve(
+ icc *icp
+) {
+ icmCurve *p;
+ if ((p = (icmCurve *) icp->al->calloc(icp->al,1,sizeof(icmCurve))) == NULL)
+ return NULL;
+ p->ttype = icSigCurveType;
+ p->refcount = 1;
+ p->get_size = icmCurve_get_size;
+ p->read = icmCurve_read;
+ p->write = icmCurve_write;
+ p->dump = icmCurve_dump;
+ p->allocate = icmCurve_allocate;
+ p->del = icmCurve_delete;
+ p->icp = icp;
+
+ p->lookup_fwd = icmCurve_lookup_fwd;
+ p->lookup_bwd = icmCurve_lookup_bwd;
+
+ p->rt.inited = 0;
+
+ p->flag = icmCurveUndef;
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmData object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmData_get_size(
+ icmBase *pp
+) {
+ icmData *p = (icmData *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 12); /* 12 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 1); /* 1 byte for each data element */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmData_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmData *p = (icmData *)pp;
+ icc *icp = p->icp;
+ int rv;
+ unsigned size, f;
+ char *bp, *buf;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmData_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmData_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmData_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 12)/1; /* Number of elements in the array */
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmData_read: Wrong tag type for icmData");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Read the data type flag */
+ f = read_UInt32Number(bp+8);
+ if (f == 0) {
+ p->flag = icmDataASCII;
+ } else if (f == 1) {
+ p->flag = icmDataBin;
+#ifndef ICM_STRICT /* Profile maker sometimes has a problem */
+ } else if (f == 0x01000000) {
+ p->flag = icmDataBin;
+#endif
+ } else {
+ sprintf(icp->err,"icmData_read: Unknown flag value 0x%x",f);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 12; /* Skip padding and flag */
+
+ if (p->size > 0) {
+ if (p->flag == icmDataASCII) {
+ if ((rv = check_null_string(bp,p->size)) == 1) {
+ sprintf(icp->err,"icmData_read: ACSII is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ }
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ memmove((void *)p->data, (void *)bp, p->size);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmData_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmData *p = (icmData *)pp;
+ icc *icp = p->icp;
+ unsigned int len, f;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmData_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmData_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmData_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ switch(p->flag) {
+ case icmDataASCII:
+ f = 0;
+ break;
+ case icmDataBin:
+ f = 1;
+ break;
+ default:
+ sprintf(icp->err,"icmData_write: Unknown Data Flag value");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Write data flag descriptor to the buffer */
+ if ((rv = write_UInt32Number(f,bp+8)) != 0) {
+ sprintf(icp->err,"icmData_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 12; /* Skip padding */
+
+ if (p->data != NULL) {
+ if (p->flag == icmDataASCII) {
+ if ((rv = check_null_string((char *)p->data, p->size)) == 1) {
+ sprintf(icp->err,"icmData_write: ASCII is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ }
+ memmove((void *)bp, (void *)p->data, p->size);
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmData_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmData_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmData *p = (icmData *)pp;
+ unsigned int i, r, c, ii, size = 0;
+ int ph = 0; /* Phase */
+
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Data:\n");
+ switch(p->flag) {
+ case icmDataASCII:
+ op->gprintf(op," ASCII data\n");
+ size = p->size > 0 ? p->size-1 : 0;
+ break;
+ case icmDataBin:
+ op->gprintf(op," Binary data\n");
+ size = p->size;
+ break;
+ case icmDataUndef:
+ op->gprintf(op," Undefined data\n");
+ size = p->size;
+ break;
+ }
+ op->gprintf(op," No. elements = %lu\n",p->size);
+
+ ii = i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+
+ c = 1;
+ if (ph != 0) { /* Print ASCII under binary */
+ op->gprintf(op," ");
+ i = ii;
+ c += 11;
+ } else {
+ op->gprintf(op," 0x%04lx: ",i);
+ ii = i;
+ c += 10;
+ }
+ while (i < size && c < 75) {
+ if (p->flag == icmDataASCII) {
+ if (isprint(p->data[i])) {
+ op->gprintf(op,"%c",p->data[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->data[i]);
+ c += 4;
+ }
+ } else {
+ if (ph == 0)
+ op->gprintf(op,"%02x ",p->data[i]);
+ else {
+ if (isprint(p->data[i]))
+ op->gprintf(op," %c ",p->data[i]);
+ else
+ op->gprintf(op," ",p->data[i]);
+ }
+ c += 3;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ if (verb > 2 && p->flag != icmDataASCII && ph == 0)
+ ph = 1;
+ else
+ ph = 0;
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmData_allocate(
+ icmBase *pp
+) {
+ icmData *p = (icmData *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned char))) {
+ sprintf(icp->err,"icmData_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned char *) icp->al->calloc(icp->al, p->size, sizeof(unsigned char))) == NULL) {
+ sprintf(icp->err,"icmData_alloc: malloc() of icmData data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmData_delete(
+ icmBase *pp
+) {
+ icmData *p = (icmData *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmData(
+ icc *icp
+) {
+ icmData *p;
+ if ((p = (icmData *) icp->al->calloc(icp->al,1,sizeof(icmData))) == NULL)
+ return NULL;
+ p->ttype = icSigDataType;
+ p->refcount = 1;
+ p->get_size = icmData_get_size;
+ p->read = icmData_read;
+ p->write = icmData_write;
+ p->dump = icmData_dump;
+ p->allocate = icmData_allocate;
+ p->del = icmData_delete;
+ p->icp = icp;
+
+ p->flag = icmDataUndef;
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmText object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmText_get_size(
+ icmBase *pp
+) {
+ icmText *p = (icmText *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 1); /* 1 byte for each character element (inc. null) */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmText_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmText *p = (icmText *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmText_read: Tag too short to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmText_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmText_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = (len - 8)/1; /* Number of elements in the array */
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmText_read: Wrong tag type for icmText");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp = bp + 8;
+
+ if (p->size > 0) {
+ if ((rv = check_null_string(bp,p->size)) == 1) {
+ sprintf(icp->err,"icmText_read: text is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ memmove((void *)p->data, (void *)bp, p->size);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmText_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmText *p = (icmText *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmText_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmText_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmText_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp = bp + 8;
+
+ if (p->data != NULL) {
+ if ((rv = check_null_string(p->data, p->size)) == 1) {
+ sprintf(icp->err,"icmText_write: text is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ memmove((void *)bp, (void *)p->data, p->size);
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmText_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmText_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmText *p = (icmText *)pp;
+ unsigned int i, r, c, size;
+
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Text:\n");
+ op->gprintf(op," No. chars = %lu\n",p->size);
+
+ size = p->size > 0 ? p->size-1 : 0;
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 75) {
+ if (isprint(p->data[i])) {
+ op->gprintf(op,"%c",p->data[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->data[i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmText_allocate(
+ icmBase *pp
+) {
+ icmText *p = (icmText *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(char))) {
+ sprintf(icp->err,"icmText_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (char *) icp->al->calloc(icp->al, p->size, sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmText_alloc: malloc() of icmText data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmText_delete(
+ icmBase *pp
+) {
+ icmText *p = (icmText *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmText(
+ icc *icp
+) {
+ icmText *p;
+ if ((p = (icmText *) icp->al->calloc(icp->al,1,sizeof(icmText))) == NULL)
+ return NULL;
+ p->ttype = icSigTextType;
+ p->refcount = 1;
+ p->get_size = icmText_get_size;
+ p->read = icmText_read;
+ p->write = icmText_write;
+ p->dump = icmText_dump;
+ p->allocate = icmText_allocate;
+ p->del = icmText_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Data conversion support functions */
+static int write_DateTimeNumber(icmDateTimeNumber *p, char *d) {
+ int rv;
+ if (p->year < 1900 || p->year > 3000
+ || p->month == 0 || p->month > 12
+ || p->day == 0 || p->day > 31
+ || p->hours > 23
+ || p->minutes > 59
+ || p->seconds > 59)
+ return 1;
+
+ if ((rv = write_UInt16Number(p->year, d + 0)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->month, d + 2)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->day, d + 4)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->hours, d + 6)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->minutes, d + 8)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->seconds, d + 10)) != 0)
+ return rv;
+ return 0;
+}
+
+static int read_DateTimeNumber(icmDateTimeNumber *p, char *d) {
+
+ p->year = read_UInt16Number(d + 0);
+ p->month = read_UInt16Number(d + 2);
+ p->day = read_UInt16Number(d + 4);
+ p->hours = read_UInt16Number(d + 6);
+ p->minutes = read_UInt16Number(d + 8);
+ p->seconds = read_UInt16Number(d + 10);
+
+ /* Sanity check the date and time */
+ if (p->year >= 1900 && p->year <= 3000
+ && p->month != 0 && p->month <= 12
+ && p->day != 0 && p->day <= 31
+ && p->hours <= 23
+ && p->minutes <= 59
+ && p->seconds <= 59)
+ return 0;
+
+#ifdef NEVER
+ printf("Raw year = %d, month = %d, day = %d\n",p->year, p->month, p->day);
+ printf("Raw hour = %d, minutes = %d, seconds = %d\n", p->hours, p->minutes, p->seconds);
+#endif /* NEVER */
+
+#ifdef ICM_STRICT
+ return 1; /* Not legal */
+
+#else
+ /* Be more forgiving */
+
+ /* Check for Adobe problem */
+ if (p->month >= 1900 && p->month <= 3000
+ && p->year != 0 && p->year <= 12
+ && p->hours != 0 && p->hours <= 31
+ && p->day <= 23
+ && p->seconds <= 59
+ && p->minutes <= 59) {
+ unsigned int tt;
+
+ /* Correct Adobe's faulty profile */
+ tt = p->month; p->month = p->year; p->year = tt;
+ tt = p->hours; p->hours = p->day; p->day = tt;
+ tt = p->seconds; p->seconds = p->minutes; p->minutes = tt;
+
+ return 0;
+ }
+
+ /* Hmm. some other sort of corruption. Limit values to sane */
+ if (p->year < 1900) {
+ if (p->year < 100) /* Hmm. didn't use 4 digit year, guess it's 19xx ? */
+ p->year += 1900;
+ else
+ p->year = 1900;
+ } else if (p->year > 3000)
+ p->year = 3000;
+
+ if (p->month == 0)
+ p->month = 1;
+ else if (p->month > 12)
+ p->month = 12;
+
+ if (p->day == 0)
+ p->day = 1;
+ else if (p->day > 31)
+ p->day = 31;
+
+ if (p->hours > 23)
+ p->hours = 23;
+
+ if (p->minutes > 59)
+ p->minutes = 59;
+
+ if (p->seconds > 59)
+ p->seconds = 59;
+
+ return 0;
+#endif
+}
+
+/* Return a string that shows the given date and time */
+static char *string_DateTimeNumber(icmDateTimeNumber *p) {
+ static const char *mstring[13] = {"Bad", "Jan","Feb","Mar","Apr","May","Jun",
+ "Jul","Aug","Sep","Oct","Nov","Dec"};
+ static char buf[80];
+
+ sprintf(buf,"%d %s %4d, %d:%02d:%02d",
+ p->day, mstring[p->month > 12 ? 0 : p->month], p->year,
+ p->hours, p->minutes, p->seconds);
+ return buf;
+}
+
+/* Set the DateTime structure to the current date and time */
+static void setcur_DateTimeNumber(icmDateTimeNumber *p) {
+ time_t cclk;
+ struct tm *ctm;
+
+ cclk = time(NULL);
+ ctm = localtime(&cclk);
+
+ p->year = ctm->tm_year + 1900;
+ p->month = ctm->tm_mon + 1;
+ p->day = ctm->tm_mday;
+ p->hours = ctm->tm_hour;
+ p->minutes = ctm->tm_min;
+ p->seconds = ctm->tm_sec;
+}
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmDateTimeNumber_get_size(
+ icmBase *pp
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 12); /* 12 bytes for Date & Time */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmDateTimeNumber_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf;
+
+ if (len < 20) {
+ sprintf(icp->err,"icmDateTimeNumber_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmDateTimeNumber_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmDateTimeNumber_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmDateTimeNumber_read: Wrong tag type for icmDateTimeNumber");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read the time and date from buffer */
+ if((rv = read_DateTimeNumber(p, bp)) != 0) {
+ sprintf(icp->err,"icmDateTimeNumber_read: Corrupted DateTime");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmDateTimeNumber_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmDateTimeNumber_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmDateTimeNumber_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmDateTimeNumber_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ if ((rv = write_DateTimeNumber(p, bp)) != 0) {
+ sprintf(icp->err,"icmDateTimeNumber_write: write_DateTimeNumber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmDateTimeNumber_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmDateTimeNumber_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"DateTimeNumber:\n");
+ op->gprintf(op," Date = %s\n", string_DateTimeNumber(p));
+}
+
+/* Allocate variable sized data elements */
+static int icmDateTimeNumber_allocate(
+ icmBase *pp
+) {
+ /* Nothing to do */
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmDateTimeNumber_delete(
+ icmBase *pp
+) {
+ icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmDateTimeNumber(
+ icc *icp
+) {
+ icmDateTimeNumber *p;
+ if ((p = (icmDateTimeNumber *) icp->al->calloc(icp->al,1,sizeof(icmDateTimeNumber))) == NULL)
+ return NULL;
+ p->ttype = icSigDateTimeType;
+ p->refcount = 1;
+ p->get_size = icmDateTimeNumber_get_size;
+ p->read = icmDateTimeNumber_read;
+ p->write = icmDateTimeNumber_write;
+ p->dump = icmDateTimeNumber_dump;
+ p->allocate = icmDateTimeNumber_allocate;
+ p->del = icmDateTimeNumber_delete;
+ p->icp = icp;
+
+ setcur_DateTimeNumber(p); /* Default to current date and time */
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmLut object */
+
+/* Check if the matrix is non-zero */
+static int icmLut_nu_matrix(
+ icmLut *p /* Pointer to Lut object */
+) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) { /* Rows */
+ for (i = 0; i < 3; i++) { /* Columns */
+ if ( (i == j && p->e[j][i] != 1.0)
+ || (i != j && p->e[j][i] != 0.0))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* return the locations of the minimum and */
+/* maximum values of the given channel, in the clut */
+static void icmLut_min_max(
+ icmLut *p, /* Pointer to Lut object */
+ double *minp, /* Return position of min/max */
+ double *maxp,
+ int chan /* Channel, -1 for average of all */
+) {
+ double *tp;
+ double minv, maxv; /* Values */
+ unsigned int e, ee, f;
+ int gc[MAX_CHAN]; /* Grid coordinate */
+
+ minv = 1e6;
+ maxv = -1e6;
+
+ for (e = 0; e < p->inputChan; e++)
+ gc[e] = 0; /* init coords */
+
+ /* Search the whole table */
+ for (tp = p->clutTable, e = 0; e < p->inputChan; tp += p->outputChan) {
+ double v;
+ if (chan == -1) {
+ for (v = 0.0, f = 0; f < p->outputChan; f++)
+ v += tp[f];
+ } else {
+ v = tp[chan];
+ }
+ if (v < minv) {
+ minv = v;
+ for (ee = 0; ee < p->inputChan; ee++)
+ minp[ee] = gc[ee]/(p->clutPoints-1.0);
+ }
+ if (v > maxv) {
+ maxv = v;
+ for (ee = 0; ee < p->inputChan; ee++)
+ maxp[ee] = gc[ee]/(p->clutPoints-1.0);
+ }
+
+ /* Increment coord */
+ for (e = 0; e < p->inputChan; e++) {
+ if (++gc[e] < p->clutPoints)
+ break; /* No carry */
+ gc[e] = 0;
+ }
+ }
+}
+
+/* Convert XYZ throught Luts matrix */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmLut_lookup_matrix(
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[outputChan] in ICC order - see Table 39 in 6.5.5 */
+double *in /* Input array[inputChan] */
+) {
+ double t0,t1; /* Take care if out == in */
+ t0 = p->e[0][0] * in[0] + p->e[0][1] * in[1] + p->e[0][2] * in[2];
+ t1 = p->e[1][0] * in[0] + p->e[1][1] * in[1] + p->e[1][2] * in[2];
+ out[2] = p->e[2][0] * in[0] + p->e[2][1] * in[1] + p->e[2][2] * in[2];
+ out[0] = t0;
+ out[1] = t1;
+
+ return 0;
+}
+
+/* Convert normalized numbers though this Luts input tables. */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmLut_lookup_input(
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[inputChan] */
+double *in /* Input array[inputChan] */
+) {
+ int rv = 0;
+ unsigned int ix, n;
+ double inputEnt_1 = (double)(p->inputEnt-1);
+ double *table = p->inputTable;
+
+ if (p->inputEnt == 0) { /* Hmm. */
+ for (n = 0; n < p->inputChan; n++)
+ out[n] = in[n];
+ } else {
+ /* Use linear interpolation */
+ for (n = 0; n < p->inputChan; n++, table += p->inputEnt) {
+ double val, w;
+ val = in[n] * inputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > inputEnt_1) {
+ val = inputEnt_1;
+ rv |= 1;
+ }
+ ix = (unsigned int)floor(val); /* Grid coordinate */
+ if (ix > (p->inputEnt-2))
+ ix = (p->inputEnt-2);
+ w = val - (double)ix; /* weight */
+ val = table[ix];
+ out[n] = val + w * (table[ix+1] - val);
+ }
+ }
+ return rv;
+}
+
+/* Convert normalized numbers though this Luts multi-dimensional table. */
+/* using multi-linear interpolation. */
+static int icmLut_lookup_clut_nl(
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[inputChan] */
+double *in /* Input array[outputChan] */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+ double *gp; /* Pointer to grid cube base */
+ double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
+ double *gw, GW[1 << 8]; /* weight for each grid cube corner */
+
+ if (p->inputChan <= 8) {
+ gw = GW; /* Use stack allocation */
+ } else {
+ if ((gw = (double *) icp->al->malloc(icp->al, sat_mul((1 << p->inputChan), sizeof(double)))) == NULL) {
+ sprintf(icp->err,"icmLut_lookup_clut: malloc() failed");
+ return icp->errc = 2;
+ }
+ }
+
+ /* We are using an multi-linear (ie. Trilinear for 3D input) interpolation. */
+ /* The implementation here uses more multiplies that some other schemes, */
+ /* (for instance, see "Tri-Linear Interpolation" by Steve Hill, */
+ /* Graphics Gems IV, page 521), but has less involved bookeeping, */
+ /* needs less local storage for intermediate output values, does fewer */
+ /* output and intermediate value reads, and fp multiplies are fast on */
+ /* todays processors! */
+
+ /* Compute base index into grid and coordinate offsets */
+ {
+ unsigned int e;
+ double clutPoints_1 = (double)(p->clutPoints-1);
+ int clutPoints_2 = p->clutPoints-2;
+ gp = p->clutTable; /* Base of grid array */
+
+ for (e = 0; e < p->inputChan; e++) {
+ unsigned int x;
+ double val;
+ val = in[e] * clutPoints_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > clutPoints_1) {
+ val = clutPoints_1;
+ rv |= 1;
+ }
+ x = (unsigned int)floor(val); /* Grid coordinate */
+ if (x > clutPoints_2)
+ x = clutPoints_2;
+ co[e] = val - (double)x; /* 1.0 - weight */
+ gp += x * p->dinc[e]; /* Add index offset for base of cube */
+ }
+ }
+ /* Compute corner weights needed for interpolation */
+ {
+ unsigned int e;
+ int i, g = 1;
+ gw[0] = 1.0;
+ for (e = 0; e < p->inputChan; e++) {
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * co[e];
+ gw[i] *= (1.0 - co[e]);
+ }
+ g *= 2;
+ }
+ }
+ /* Now compute the output values */
+ {
+ int i;
+ unsigned int f;
+ double w = gw[0];
+ double *d = gp + p->dcube[0];
+ for (f = 0; f < p->outputChan; f++) /* Base of cube */
+ out[f] = w * d[f];
+ for (i = 1; i < (1 << p->inputChan); i++) { /* For all other corners of cube */
+ w = gw[i]; /* Strength reduce */
+ d = gp + p->dcube[i];
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * d[f];
+ }
+ }
+ if (gw != GW)
+ icp->al->free(icp->al, (void *)gw);
+ return rv;
+}
+
+/* Convert normalized numbers though this Luts multi-dimensional table */
+/* using simplex interpolation. */
+static int icmLut_lookup_clut_sx(
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[inputChan] */
+double *in /* Input array[outputChan] */
+) {
+ int rv = 0;
+ double *gp; /* Pointer to grid cube base */
+ double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
+ int si[MAX_CHAN]; /* co[] Sort index, [0] = smalest */
+
+ /* We are using a simplex (ie. tetrahedral for 3D input) interpolation. */
+ /* This method is more appropriate for XYZ/RGB/CMYK input spaces, */
+
+ /* Compute base index into grid and coordinate offsets */
+ {
+ unsigned int e;
+ double clutPoints_1 = (double)(p->clutPoints-1);
+ int clutPoints_2 = p->clutPoints-2;
+ gp = p->clutTable; /* Base of grid array */
+
+ for (e = 0; e < p->inputChan; e++) {
+ unsigned int x;
+ double val;
+ val = in[e] * clutPoints_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > clutPoints_1) {
+ val = clutPoints_1;
+ rv |= 1;
+ }
+ x = (unsigned int)floor(val); /* Grid coordinate */
+ if (x > clutPoints_2)
+ x = clutPoints_2;
+ co[e] = val - (double)x; /* 1.0 - weight */
+ gp += x * p->dinc[e]; /* Add index offset for base of cube */
+ }
+ }
+#ifdef NEVER
+ /* Do selection sort on coordinates, smallest to largest. */
+ {
+ int e, f;
+ for (e = 0; e < p->inputChan; e++)
+ si[e] = e; /* Initial unsorted indexes */
+ for (e = 0; e < (p->inputChan-1); e++) {
+ double cosn;
+ cosn = co[si[e]]; /* Current smallest value */
+ for (f = e+1; f < p->inputChan; f++) { /* Check against rest */
+ int tt;
+ tt = si[f];
+ if (cosn > co[tt]) {
+ si[f] = si[e]; /* Exchange */
+ si[e] = tt;
+ cosn = co[tt];
+ }
+ }
+ }
+ }
+#else
+ /* Do insertion sort on coordinates, smallest to largest. */
+ {
+ int f, vf;
+ unsigned int e;
+ double v;
+ for (e = 0; e < p->inputChan; e++)
+ si[e] = e; /* Initial unsorted indexes */
+
+ for (e = 1; e < p->inputChan; e++) {
+ f = e;
+ v = co[si[f]];
+ vf = f;
+ while (f > 0 && co[si[f-1]] > v) {
+ si[f] = si[f-1];
+ f--;
+ }
+ si[f] = vf;
+ }
+ }
+#endif
+ /* Now compute the weightings, simplex vertices and output values */
+ {
+ unsigned int e, f;
+ double w; /* Current vertex weight */
+
+ w = 1.0 - co[si[p->inputChan-1]]; /* Vertex at base of cell */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] = w * gp[f];
+
+ for (e = p->inputChan-1; e > 0; e--) { /* Middle verticies */
+ w = co[si[e]] - co[si[e-1]];
+ gp += p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * gp[f];
+ }
+
+ w = co[si[0]];
+ gp += p->dinc[si[0]]; /* Far corner from base of cell */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * gp[f];
+ }
+ return rv;
+}
+
+#ifdef NEVER // ~~~99 development code
+
+/* Convert normalized numbers though this Luts multi-dimensional table */
+/* using optimised simplex interpolation. */
+/* This version optimses the simplex split axis depending on the input */
+/* colorspace. */
+static int icmLut_lookup_clut_osx(
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[inputChan] */
+double *in /* Input array[outputChan] */
+) {
+ int rv = 0;
+ double *gp; /* Pointer to grid cube base */
+ double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
+ int si[MAX_CHAN]; /* co[] Sort index, [0] = smalest */
+ char xflip[MAX_CHAN]; /* Optimised simplex axis flip flags */
+
+ /* Compute base index into grid and coordinate offsets */
+ {
+ unsigned int e;
+ double clutPoints_1 = (double)(p->clutPoints-1);
+ int clutPoints_2 = p->clutPoints-2;
+ gp = p->clutTable; /* Base of grid array */
+
+ for (e = 0; e < p->inputChan; e++) {
+ unsigned int x;
+ double val;
+// ~~~999
+#ifdef NEVER
+ xflip[e] = p->finfo[e].bthff;
+ if (in[e] >= p->finfo[e].fth)
+ xflip[e] = p->finfo[e].athff;
+#else
+
+ xflip[e] = 0;
+ if (e == 0)
+ xflip[e] = 1;
+#endif
+ val = in[e] * clutPoints_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > clutPoints_1) {
+ val = clutPoints_1;
+ rv |= 1;
+ }
+ x = (unsigned int)floor(val); /* Grid coordinate */
+ if (x > clutPoints_2)
+ x = clutPoints_2;
+ co[e] = val - (double)x; /* 1.0 - weight */
+ gp += x * p->dinc[e]; /* Add index offset for base of cube */
+ if (xflip[e]) { /* Reverse sense of direction for this axis */
+ co[e] = 1.0 - co[e];
+ gp += p->dinc[e];
+ }
+ }
+ }
+//printf("*");fflush(stdout);
+#ifdef NEVER
+ /* Do selection sort on coordinates, smallest to largest. */
+ {
+ int e, f;
+ for (e = 0; e < p->inputChan; e++)
+ si[e] = e; /* Initial unsorted indexes */
+ for (e = 0; e < (p->inputChan-1); e++) {
+ double cosn;
+ cosn = co[si[e]]; /* Current smallest value */
+ for (f = e+1; f < p->inputChan; f++) { /* Check against rest */
+ int tt;
+ tt = si[f];
+ if (cosn > co[tt]) {
+ si[f] = si[e]; /* Exchange */
+ si[e] = tt;
+ cosn = co[tt];
+ }
+ }
+ }
+ }
+#else
+ /* Do insertion sort on coordinates, smallest to largest. */
+ {
+ int f, vf;
+ unsigned int e;
+ double v;
+ for (e = 0; e < p->inputChan; e++)
+ si[e] = e; /* Initial unsorted indexes */
+
+ for (e = 1; e < p->inputChan; e++) {
+ f = e;
+ v = co[si[f]];
+ vf = f;
+ while (f > 0 && co[si[f-1]] > v) {
+ si[f] = si[f-1];
+ f--;
+ }
+ si[f] = vf;
+ }
+ }
+#endif
+ /* Now compute the weightings, simplex vertices and output values */
+ {
+ unsigned int e, f;
+ double w; /* Current vertex weight */
+
+ w = 1.0 - co[si[p->inputChan-1]]; /* Vertex at base of cell */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] = w * gp[f];
+
+ for (e = p->inputChan-1; e > 0; e--) { /* Middle verticies */
+ w = co[si[e]] - co[si[e-1]];
+ if (xflip[e])
+ gp -= p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
+ else
+ gp += p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * gp[f];
+ }
+
+ w = co[si[0]];
+ if (xflip[0])
+ gp -= p->dinc[si[0]]; /* Far corner from base of cell */
+ else
+ gp += p->dinc[si[0]]; /* Far corner from base of cell */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * gp[f];
+ }
+ return rv;
+}
+
+#endif /* NEVER */ // ~~~99 development code
+
+
+/* Convert normalized numbers though this Luts output tables. */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmLut_lookup_output(
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[outputChan] */
+double *in /* Input array[outputChan] */
+) {
+ int rv = 0;
+ unsigned int ix, n;
+ double outputEnt_1 = (double)(p->outputEnt-1);
+ double *table = p->outputTable;
+
+ if (p->outputEnt == 0) { /* Hmm. */
+ for (n = 0; n < p->outputChan; n++)
+ out[n] = in[n];
+ } else {
+ /* Use linear interpolation */
+ for (n = 0; n < p->outputChan; n++, table += p->outputEnt) {
+ double val, w;
+ val = in[n] * outputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > outputEnt_1) {
+ val = outputEnt_1;
+ rv |= 1;
+ }
+ ix = (unsigned int)floor(val); /* Grid coordinate */
+ if (ix > (p->outputEnt-2))
+ ix = (p->outputEnt-2);
+ w = val - (double)ix; /* weight */
+ val = table[ix];
+ out[n] = val + w * (table[ix+1] - val);
+ }
+ }
+ return rv;
+}
+
+/* ----------------------------------------------- */
+/* Pseudo - Hilbert count sequencer */
+
+/* This multi-dimensional count sequence is a distributed */
+/* Gray code sequence, with direction reversal on every */
+/* alternate power of 2 scale. */
+/* It is intended to aid cache coherence in multi-dimensional */
+/* regular sampling. It approximates the Hilbert curve sequence. */
+
+/* Initialise, returns total usable count */
+unsigned
+psh_init(
+psh *p, /* Pointer to structure to initialise */
+int di, /* Dimensionality */
+unsigned int res, /* Size per coordinate */
+int co[] /* Coordinates to initialise (May be NULL) */
+) {
+ int e;
+
+ p->di = di;
+ p->res = res;
+
+ /* Compute bits */
+ for (p->bits = 0; (1u << p->bits) < res; p->bits++)
+ ;
+
+ /* Compute the total count mask */
+ p->tmask = ((((unsigned)1) << (p->bits * di))-1);
+
+ /* Compute usable count */
+ p->count = 1;
+ for (e = 0; e < di; e++)
+ p->count *= res;
+
+ p->ix = 0;
+
+ if (co != NULL) {
+ for (e = 0; e < di; e++)
+ co[e] = 0;
+ }
+
+ return p->count;
+}
+
+/* Reset the counter */
+void
+psh_reset(
+psh *p /* Pointer to structure */
+) {
+ p->ix = 0;
+}
+
+/* Increment pseudo-hilbert coordinates */
+/* Return non-zero if count rolls over to 0 */
+int
+psh_inc(
+psh *p, /* Pointer to structure */
+int co[] /* Coordinates to return */
+) {
+ int di = p->di;
+ unsigned int res = p->res;
+ unsigned int bits = p->bits;
+ int e;
+
+ do {
+ unsigned int b;
+ int gix; /* Gray code index */
+
+ p->ix = (p->ix + 1) & p->tmask;
+
+ gix = p->ix ^ (p->ix >> 1); /* Convert to gray code index */
+
+ for (e = 0; e < di; e++)
+ co[e] = 0;
+
+ for (b = 0; b < bits; b++) { /* Distribute bits */
+ if (b & 1) {
+ for (e = di-1; e >= 0; e--) { /* In reverse order */
+ co[e] |= (gix & 1) << b;
+ gix >>= 1;
+ }
+ } else {
+ for (e = 0; e < di; e++) { /* In normal order */
+ co[e] |= (gix & 1) << b;
+ gix >>= 1;
+ }
+ }
+ }
+
+ /* Convert from Gray to binary coordinates */
+ for (e = 0; e < di; e++) {
+ unsigned int sh, tv;
+
+ for(sh = 1, tv = co[e];; sh <<= 1) {
+ unsigned ptv = tv;
+ tv ^= (tv >> sh);
+ if (ptv <= 1 || sh == 16)
+ break;
+ }
+ if (tv >= res) /* Dumbo filter - increment again if outside cube range */
+ break;
+ co[e] = tv;
+ }
+
+ } while (e < di);
+
+ return (p->ix == 0);
+}
+
+/* ------------------------------------------------------- */
+
+#ifndef COUNTERS_H
+
+/* Macros for a multi-dimensional counter. */
+
+/* Declare the counter name nn, maximum di mxdi, dimensions di, & count */
+/* This counter can have each dimension range clipped */
+
+#define FCOUNT(nn, mxdi, di) \
+ int nn[mxdi]; /* counter value */ \
+ int nn##_di = (di); /* Number of dimensions */ \
+ int nn##_stt[mxdi]; /* start count value */ \
+ int nn##_res[mxdi]; /* last count +1 */ \
+ int nn##_e /* dimension index */
+
+#define FRECONF(nn, start, endp1) \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn##_stt[nn##_e] = (start); /* start count value */ \
+ nn##_res[nn##_e] = (endp1); /* last count +1 */ \
+ }
+
+/* Set the counter value to 0 */
+#define FC_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
+ nn[nn##_e] = nn##_stt[nn##_e]; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define FC_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < nn##_res[nn##_e]) \
+ break; /* No carry */ \
+ nn[nn##_e] = nn##_stt[nn##_e]; \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define FC_DONE(nn) \
+ (nn##_e >= nn##_di)
+
+#endif /* COUNTERS_H */
+
+/* Parameter to getNormFunc function */
+typedef enum {
+ icmFromLuti = 0, /* return "fromo Lut normalized index" conversion function */
+ icmToLuti = 1, /* return "to Lut normalized index" conversion function */
+ icmFromLutv = 2, /* return "from Lut normalized value" conversion function */
+ icmToLutv = 3 /* return "to Lut normalized value" conversion function */
+} icmNormFlag;
+
+/* Return an appropriate color space normalization function, */
+/* given the color space and Lut type */
+/* Return 0 on success, 1 on match failure */
+static int getNormFunc(
+ icc *icp,
+ icColorSpaceSignature csig,
+ icTagTypeSignature tagSig,
+ icmNormFlag flag,
+ void (**nfunc)(double *out, double *in)
+);
+
+#define CLIP_MARGIN 0.005 /* Margine to allow before reporting clipping = 0.5% */
+
+/* Helper function to set multiple Lut tables simultaneously. */
+/* Note that these tables all have to be compatible in */
+/* having the same configuration and resolution. */
+/* Set errc and return error number in underlying icc */
+/* Set warnc if there is clipping in the output values */
+/* 1 = input table, 2 = main clut, 3 = clut midpoin, 4 = midpoint interp, 5 = output table */
+int icmSetMultiLutTables(
+ int ntables, /* Number of tables to be set, 1..n */
+ icmLut **pp, /* Pointer to array of Lut objects */
+ int flags, /* Setting flags */
+ void *cbctx, /* Opaque callback context pointer value */
+ icColorSpaceSignature insig, /* Input color space */
+ icColorSpaceSignature outsig, /* Output color space */
+ void (*infunc)(void *cbctx, double *out, double *in),
+ /* Input transfer function, inspace->inspace' (NULL = default) */
+ /* Will be called ntables times for each input grid value */
+ double *inmin, double *inmax, /* Maximum range of inspace' values */
+ /* (NULL = default) */
+ void (*clutfunc)(void *cbntx, double *out, double *in),
+ /* inspace' -> outspace[ntables]' transfer function */
+ /* will be called once for each input' grid value, and */
+ /* ntables output values should be written consecutively */
+ /* to out[]. */
+ double *clutmin, double *clutmax, /* Maximum range of outspace' values */
+ /* (NULL = default) */
+ void (*outfunc)(void *cbntx, double *out, double *in))
+ /* Output transfer function, outspace'->outspace (NULL = deflt) */
+ /* Will be called ntables times on each output value */
+{
+ icmLut *p, *pn; /* Pointer to 0'th nd tn'th Lut object */
+ icc *icp; /* Pointer to common icc */
+ int tn;
+ unsigned int e, f, i, n;
+ double **clutTable2 = NULL; /* Cell center values for ICM_CLUT_SET_APXLS */
+ double *clutTable3 = NULL; /* Vertex smoothing radius values [ntables] per entry */
+ int dinc3[MAX_CHAN]; /* Dimensional increment through clut3 (in doubles) */
+ int dcube3[1 << MAX_CHAN]; /* Hyper cube offsets throught clut3 (in doubles) */
+ int ii[MAX_CHAN]; /* Index value */
+ psh counter; /* Pseudo-Hilbert counter */
+// double _iv[4 * MAX_CHAN], *iv = &_iv[MAX_CHAN], *ivn; /* Real index value/table value */
+ int maxchan; /* Actual max of input and output */
+ double *_iv, *iv, *ivn; /* Real index value/table value */
+ double imin[MAX_CHAN], imax[MAX_CHAN];
+ double omin[MAX_CHAN], omax[MAX_CHAN];
+ void (*ifromindex)(double *out, double *in); /* Index to input color space function */
+ void (*itoentry)(double *out, double *in); /* Input color space to entry function */
+ void (*ifromentry)(double *out, double *in); /* Entry to input color space function */
+ void (*otoentry)(double *out, double *in); /* Output colorspace to table value function */
+ void (*ofromentry)(double *out, double *in); /* Table value to output color space function */
+ int clip = 0;
+
+ /* Check that everything is OK to proceed */
+ if (ntables < 1 || ntables > MAX_CHAN) {
+ if (ntables >= 1) {
+ icp = pp[0]->icp;
+ sprintf(icp->err,"icmSetMultiLutTables has illegal number of tables %d",ntables);
+ return icp->errc = 1;
+ } else {
+ /* Can't write error message anywhere */
+ return 1;
+ }
+ }
+
+ p = pp[0];
+ icp = p->icp;
+
+ for (tn = 1; tn < ntables; tn++) {
+ if (pp[tn]->icp != icp) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables base icc is different");
+ return icp->errc = 1;
+ }
+ if (pp[tn]->ttype != p->ttype) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables have different Tage Type");
+ return icp->errc = 1;
+ }
+
+ if (pp[tn]->inputChan != p->inputChan) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables have different inputChan");
+ return icp->errc = 1;
+ }
+ if (pp[tn]->outputChan != p->outputChan) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables have different outputChan");
+ return icp->errc = 1;
+ }
+ if (pp[tn]->clutPoints != p->clutPoints) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables have different clutPoints");
+ return icp->errc = 1;
+ }
+ }
+
+ if (getNormFunc(icp, insig, p->ttype, icmFromLuti, &ifromindex) != 0) {
+ sprintf(icp->err,"icmLut_set_tables index to input colorspace function lookup failed");
+ return icp->errc = 1;
+ }
+ if (getNormFunc(icp, insig, p->ttype, icmToLutv, &itoentry) != 0) {
+ sprintf(icp->err,"icmLut_set_tables input colorspace to table entry function lookup failed");
+ return icp->errc = 1;
+ }
+ if (getNormFunc(icp, insig, p->ttype, icmFromLutv, &ifromentry) != 0) {
+ sprintf(icp->err,"icmLut_set_tables table entry to input colorspace function lookup failed");
+ return icp->errc = 1;
+ }
+
+ if (getNormFunc(icp, outsig, p->ttype, icmToLutv, &otoentry) != 0) {
+ sprintf(icp->err,"icmLut_set_tables output colorspace to table entry function lookup failed");
+ return icp->errc = 1;
+ }
+ if (getNormFunc(icp, outsig, p->ttype, icmFromLutv, &ofromentry) != 0) {
+ sprintf(icp->err,"icmLut_set_tables table entry to output colorspace function lookup failed");
+ return icp->errc = 1;
+ }
+
+ /* Allocate an array to hold the input and output values. */
+ /* It needs to be able to hold di "index under valus as in[], */
+ /* and ntables ICM_CLUT_SET_FILTER values as out[], so we assume maxchan >= di */
+ maxchan = p->inputChan > p->outputChan ? p->inputChan : p->outputChan;
+ if ((_iv = (double *) icp->al->malloc(icp->al, sizeof(double) * maxchan * (ntables+1)))
+ == NULL) {
+ sprintf(icp->err,"icmLut_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ iv = _iv + maxchan; /* Allow for "index under" and smoothing radius values */
+
+ /* Setup input table value min-max */
+ if (inmin == NULL || imax == NULL) {
+#ifdef SYMETRICAL_DEFAULT_LAB_RANGE /* Symetrical default range. */
+ /* We are assuming V2 Lab16 encoding, since this is a lut16type that always uses */
+ /* this encoding */
+ if (insig == icSigLabData) { /* Special case Lab */
+ double mn[3], mx[3];
+ /* This is to ensure that Lab 100,0,0 maps exactly to a clut grid point. */
+ /* This should work well if there is an odd grid resolution, */
+ /* and icclib is being used, as input lookup will */
+ /* be computed using floating point, so that the CLUT input value */
+ /* 0.5 can be represented exactly. */
+ /* Because the symetric range will cause slight clipping, */
+ /* only do it if the input table has sufficient resolution */
+ /* to represent the clipping faithfuly. */
+ if (p->inputEnt >= 64) {
+ if (p->ttype == icSigLut8Type) {
+ mn[0] = 0.0, mn[1] = mn[2] = -127.0;
+ mx[0] = 100.0, mx[1] = mx[2] = 127.0;
+ } else {
+ mn[0] = 0.0, mn[1] = mn[2] = -127.0 - 255.0/256.0;
+ mx[0] = 100.0, mx[1] = mx[2] = 127.0 + 255.0/256.0;
+ }
+ itoentry(imin, mn); /* Convert from input color space to table representation */
+ itoentry(imax, mx);
+ } else {
+ for (e = 0; e < p->inputChan; e++) {
+ imin[e] = 0.0;
+ imax[e] = 1.0;
+ }
+ }
+ } else
+#endif
+ {
+ for (e = 0; e < p->inputChan; e++) {
+ imin[e] = 0.0; /* We are assuming this is true for all other color spaces. */
+ imax[e] = 1.0;
+ }
+ }
+ } else {
+ itoentry(imin, inmin); /* Convert from input color space to table representation */
+ itoentry(imax, inmax);
+ }
+
+ /* Setup output table value min-max */
+ if (clutmin == NULL || clutmax == NULL) {
+#ifdef SYMETRICAL_DEFAULT_LAB_RANGE
+ /* This really isn't doing much, since the full range encoding doesn't need */
+ /* any adjustment to map a*b* 0 to an integer value. */
+ /* We are tweaking the 16 bit L* = 100 to the last index into */
+ /* the output table, which may help its accuracy slightly. */
+ /* We are assuming V2 Lab16 encoding, since this is a lut16type that always uses */
+ /* this encoding */
+ if (outsig == icSigLabData) { /* Special case Lab */
+ double mn[3], mx[3];
+ /* The output of the CLUT will be an 8 or 16 bit value, and we want to */
+ /* adjust the range so that the input grid point holding the white */
+ /* point can encode 0.0 exactly. */
+ /* Note that in the case of the a & b values, the range equates to */
+ /* normalised 0.0 .. 1.0, since 0 can be represented exactly in it. */
+ if (p->outputEnt >= 64) {
+ if (p->ttype == icSigLut8Type) {
+ mn[0] = 0.0, mn[1] = mn[2] = -128.0;
+ mx[0] = 100.0, mx[1] = mx[2] = 127.0;
+ } else {
+ mn[0] = 0.0, mn[1] = mn[2] = -128.0;
+ mx[0] = 100.0, mx[1] = mx[2] = (65535.0 * 255.0)/65280.0 - 128.0;
+ }
+ otoentry(omin, mn);/* Convert from output color space to table representation */
+ otoentry(omax, mx);
+ } else {
+ for (e = 0; e < p->inputChan; e++) {
+ omin[e] = 0.0;
+ omax[e] = 1.0;
+ }
+ }
+ } else
+#endif
+ {
+ for (f = 0; f < p->outputChan; f++) {
+ omin[f] = 0.0; /* We are assuming this is true for all other color spaces. */
+ omax[f] = 1.0;
+ }
+ }
+ } else {
+ otoentry(omin, clutmin);/* Convert from output color space to table representation */
+ otoentry(omax, clutmax);
+ }
+
+ /* Create the input table entry values */
+ for (tn = 0; tn < ntables; tn++) {
+ pn = pp[tn];
+ for (n = 0; n < pn->inputEnt; n++) {
+ double fv;
+ fv = n/(pn->inputEnt-1.0);
+ for (e = 0; e < pn->inputChan; e++)
+ iv[e] = fv;
+
+ ifromindex(iv,iv); /* Convert from index value to input color space value */
+
+ if (infunc != NULL)
+ infunc(cbctx, iv, iv); /* In colorspace -> input table -> In colorspace. */
+
+ itoentry(iv,iv); /* Convert from input color space value to table value */
+
+ /* Expand used range to 0.0 - 1.0, and clip to legal values */
+ /* Note that if the range is reduced, and clipping occurs, */
+ /* then there should be enough resolution within the input */
+ /* table, to represent the sharp edges of the clipping. */
+ for (e = 0; e < pn->inputChan; e++) {
+ double tt;
+ tt = (iv[e] - imin[e])/(imax[e] - imin[e]);
+ if (tt < 0.0) {
+ DBGSLC(("iclip: tt = %f, iv = %f, omin = %f, omax = %f\n",tt,iv[e],omin[e],omax[e]));
+ if (tt < -CLIP_MARGIN)
+ clip = 1;
+ tt = 0.0;
+ } else if (tt > 1.0) {
+ DBGSLC(("iclip: tt = %f, iv = %f, omin = %f, omax = %f\n",tt,iv[e],omin[e],omax[e]));
+ if (tt > (1.0 + CLIP_MARGIN))
+ clip = 1;
+ tt = 1.0;
+ }
+ iv[e] = tt;
+ }
+
+ for (e = 0; e < pn->inputChan; e++) /* Input tables */
+ pn->inputTable[e * pn->inputEnt + n] = iv[e];
+ }
+ }
+
+ /* Allocate space for cell center value lookup */
+ if (flags & ICM_CLUT_SET_APXLS) {
+ if ((clutTable2 = (double **) icp->al->calloc(icp->al,sizeof(double *), ntables)) == NULL) {
+ sprintf(icp->err,"icmLut_set_tables malloc of cube center array failed");
+ icp->al->free(icp->al, _iv);
+ return icp->errc = 1;
+ }
+ for (tn = 0; tn < ntables; tn++) {
+ if ((clutTable2[tn] = (double *) icp->al->calloc(icp->al,sizeof(double),
+ p->clutTable_size)) == NULL) {
+ for (--tn; tn >= 0; tn--)
+ icp->al->free(icp->al, clutTable2[tn]);
+ icp->al->free(icp->al, _iv);
+ icp->al->free(icp->al, clutTable2);
+ sprintf(icp->err,"icmLut_set_tables malloc of cube center array failed");
+ return icp->errc = 1;
+ }
+ }
+ }
+
+ /* Allocate space for smoothing radius values */
+ if (flags & ICM_CLUT_SET_FILTER) {
+ unsigned int j, g, size;
+
+ /* Private: compute dimensional increment though clut3 */
+ i = p->inputChan-1;
+ dinc3[i--] = ntables;
+ for (; i < p->inputChan; i--)
+ dinc3[i] = dinc3[i+1] * p->clutPoints;
+
+ /* Private: compute offsets from base of cube to other corners */
+ for (dcube3[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
+ for (i = 0; i < g; i++)
+ dcube3[g+i] = dcube3[i] + dinc3[j];
+ g *= 2;
+ }
+
+ if ((size = sat_mul(ntables, sat_pow(p->clutPoints,p->inputChan))) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_alloc size overflow");
+ if (flags & ICM_CLUT_SET_APXLS) {
+ for (tn = 0; tn < ntables; tn++)
+ icp->al->free(icp->al, clutTable2[tn]);
+ }
+ icp->al->free(icp->al, clutTable2);
+ icp->al->free(icp->al, _iv);
+ return icp->errc = 1;
+ }
+
+ if ((clutTable3 = (double *) icp->al->calloc(icp->al,sizeof(double),
+ size)) == NULL) {
+ if (flags & ICM_CLUT_SET_APXLS) {
+ for (tn = 0; tn < ntables; tn++)
+ icp->al->free(icp->al, clutTable2[tn]);
+ }
+ icp->al->free(icp->al, clutTable2);
+ icp->al->free(icp->al, _iv);
+ sprintf(icp->err,"icmLut_set_tables malloc of vertex smoothing value array failed");
+ return icp->errc = 1;
+ }
+ }
+
+ /* Create the multi-dimensional lookup table values */
+
+ /* To make this clut function cache friendly, we use the pseudo-hilbert */
+ /* count sequence. This keeps each point close to the last in the */
+ /* multi-dimensional space. This is the point of setting multiple Luts at */
+ /* once too - the assumption is that these tables are all related (different */
+ /* gamut compressions for instance), and hence calling the clutfunc() with */
+ /* close values will maximise reverse lookup cache hit rate. */
+
+ psh_init(&counter, p->inputChan, p->clutPoints, ii); /* Initialise counter */
+
+ /* Itterate through all verticies in the grid */
+ for (;;) {
+ int ti, ti3; /* Table indexes */
+
+ for (ti = e = 0; e < p->inputChan; e++) { /* Input tables */
+ ti += ii[e] * p->dinc[e]; /* Clut index */
+ iv[e] = ii[e]/(p->clutPoints-1.0); /* Vertex coordinates */
+ iv[e] = iv[e] * (imax[e] - imin[e]) + imin[e]; /* Undo expansion to 0.0 - 1.0 */
+ *((int *)&iv[-((int)e)-1]) = ii[e]; /* Trick to supply grid index in iv[] */
+ }
+
+ if (flags & ICM_CLUT_SET_FILTER) {
+ for (ti3 = e = 0; e < p->inputChan; e++) /* Input tables */
+ ti3 += ii[e] * dinc3[e]; /* Clut3 index */
+ }
+
+ DBGSL(("\nix %s\n",icmPiv(p->inputChan, ii)));
+ DBGSL(("raw itv %s to iv'",icmPdv(p->inputChan, iv)));
+ ifromentry(iv,iv); /* Convert from table value to input color space */
+ DBGSL((" %s\n",icmPdv(p->inputChan, iv)));
+
+ /* Apply incolor -> outcolor function we want to represent for all tables */
+ DBGSL(("iv: %s to ov'",icmPdv(p->inputChan, iv)));
+ clutfunc(cbctx, iv, iv);
+ DBGSL((" %s\n",icmPdv(p->outputChan, iv)));
+
+ /* Save the results to the output tables */
+ for (tn = 0, ivn = iv; tn < ntables; ivn += p->outputChan, tn++) {
+ pn = pp[tn];
+
+ DBGSL(("tn %d, ov' %s -> otv",tn,icmPdv(p->outputChan, ivn)));
+ otoentry(ivn,ivn); /* Convert from output color space value to table value */
+ DBGSL((" %s\n -> oval",icmPdv(p->outputChan, ivn)));
+
+ /* Expand used range to 0.0 - 1.0, and clip to legal values */
+ for (f = 0; f < pn->outputChan; f++) {
+ double tt;
+ tt = (ivn[f] - omin[f])/(omax[f] - omin[f]);
+ if (tt < 0.0) {
+ DBGSLC(("lclip: tt = %f, ivn= %f, omin = %f, omax = %f\n",tt,ivn[f],omin[f],omax[f]));
+ if (tt < -CLIP_MARGIN)
+ clip = 2;
+ tt = 0.0;
+ } else if (tt > 1.0) {
+ DBGSLC(("lclip: tt = %f, ivn= %f, omin = %f, omax = %f\n",tt,ivn[f],omin[f],omax[f]));
+ if (tt > (1.0 + CLIP_MARGIN))
+ clip = 2;
+ tt = 1.0;
+ }
+ ivn[f] = tt;
+ }
+
+ for (f = 0; f < pn->outputChan; f++) /* Output chans */
+ pn->clutTable[ti + f] = ivn[f];
+ DBGSL((" %s\n",icmPdv(pn->outputChan, ivn)));
+
+ if (flags & ICM_CLUT_SET_FILTER) {
+ clutTable3[ti3 + tn] = iv[-1 -tn]; /* Filter radiuses */
+ }
+ }
+
+ /* Lookup cell center value if ICM_CLUT_SET_APXLS */
+ if (clutTable2 != NULL) {
+
+ for (e = 0; e < p->inputChan; e++) {
+ if (ii[e] >= (p->clutPoints-1))
+ break; /* Don't lookup beyond last */
+ iv[e] = (ii[e] + 0.5)/(p->clutPoints-1.0); /* Vertex coordinates + 0.5 */
+ iv[e] = iv[e] * (imax[e] - imin[e]) + imin[e]; /* Undo expansion to 0.0 - 1.0 */
+ *((int *)&iv[-((int)e)-1]) = ii[e]; /* Trick to supply grid index in iv[] */
+ /* (Not this is only the base for +0.5) */
+ }
+
+ if (e >= p->inputChan) { /* We're not on the last row */
+
+ ifromentry(iv,iv); /* Convert from table value to input color space */
+
+ /* Apply incolor -> outcolor function we want to represent */
+ clutfunc(cbctx, iv, iv);
+
+ /* Save the results to the output tables */
+ for (tn = 0, ivn = iv; tn < ntables; ivn += p->outputChan, tn++) {
+ pn = pp[tn];
+
+ otoentry(ivn,ivn); /* Convert from output color space value to table value */
+
+ /* Expand used range to 0.0 - 1.0, and clip to legal values */
+ for (f = 0; f < pn->outputChan; f++) {
+ double tt;
+ tt = (ivn[f] - omin[f])/(omax[f] - omin[f]);
+ if (tt < 0.0) {
+ DBGSLC(("lclip: tt = %f, ivn= %f, omin = %f, omax = %f\n",tt,ivn[f],omin[f],omax[f]));
+ if (tt < -CLIP_MARGIN)
+ clip = 3;
+ tt = 0.0;
+ } else if (tt > 1.0) {
+ DBGSLC(("lclip: tt = %f, ivn= %f, omin = %f, omax = %f\n",tt,ivn[f],omin[f],omax[f]));
+ if (tt > (1.0 + CLIP_MARGIN))
+ clip = 3;
+ tt = 1.0;
+ }
+ ivn[f] = tt;
+ }
+
+ for (f = 0; f < pn->outputChan; f++) /* Output chans */
+ clutTable2[tn][ti + f] = ivn[f];
+ }
+ }
+ }
+
+ /* Increment index within block (Reverse index significancd) */
+ if (psh_inc(&counter, ii))
+ break;
+ }
+
+#define APXLS_WHT 0.5
+#define APXLS_DIFF_THRHESH 0.2
+ /* Deal with cell center value, aproximate least squares adjustment. */
+ /* Subtract some of the mean of the surrounding center values from each grid value. */
+ /* Skip the edges so that things like the white point are not changed. */
+ /* Avoid modifying the value if the difference between the */
+ /* interpolated value and the current value is too great, */
+ /* and there is the possibility of different color aliases. */
+ if (clutTable2 != NULL) {
+ int ti; /* cube vertex table index */
+ int ti2; /* cube center table2 index */
+ int ee;
+ double cw = 1.0/(double)(1 << p->inputChan); /* Weight for each cube corner */
+
+ /* For each cell center point except last row */
+ for (e = 0; e < p->inputChan; e++)
+ ii[e] = 0; /* init coords */
+
+ /* Compute linear interpolated value from center values */
+ for (ee = 0; ee < p->inputChan;) {
+
+ /* Compute base index for table2 */
+ for (ti2 = e = 0; e < p->inputChan; e++) /* Input tables */
+ ti2 += ii[e] * p->dinc[e]; /* Clut index */
+
+ ti = ti2 + p->dcube[(1 << p->inputChan)-1]; /* +1 to each coord for vertex index */
+
+ for (tn = 0; tn < ntables; tn++) {
+ double mval[MAX_CHAN], vv;
+ double maxd = 0.0;
+
+ pn = pp[tn];
+
+ /* Compute mean of center values */
+ for (f = 0; f < pn->outputChan; f++) { /* Output chans */
+
+ mval[f] = 0.0;
+ for (i = 0; i < (1 << p->inputChan); i++) { /* For surrounding center values */
+ mval[f] += clutTable2[tn][ti2 + p->dcube[i] + f];
+ }
+ mval[f] = pn->clutTable[ti + f] - mval[f] * cw; /* Diff to mean */
+ vv = fabs(mval[f]);
+ if (vv > maxd)
+ maxd = vv;
+ }
+
+ if (pn->outputChan <= 3 || maxd < APXLS_DIFF_THRHESH) {
+ for (f = 0; f < pn->outputChan; f++) { /* Output chans */
+
+ vv = pn->clutTable[ti + f] + APXLS_WHT * mval[f];
+
+ /* Hmm. This is a bit crude. How do we know valid range is 0-1 ? */
+ /* What about an ink limit ? */
+ if (vv < 0.0) {
+ vv = 0.0;
+ } else if (vv > 1.0) {
+ vv = 1.0;
+ }
+ pn->clutTable[ti + f] = vv;
+ }
+ }
+ }
+
+ /* Increment coord */
+ for (ee = 0; ee < p->inputChan; ee++) {
+ if (++ii[ee] < (p->clutPoints-2)) /* Don't go through upper edge */
+ break; /* No carry */
+ ii[ee] = 0;
+ }
+ }
+
+ /* Done with center values */
+ for (tn = 0; tn < ntables; tn++)
+ icp->al->free(icp->al, clutTable2[tn]);
+ icp->al->free(icp->al, clutTable2);
+ }
+
+ /* Apply any smoothing in the clipped region to the resulting clutTable */
+ if (clutTable3 != NULL) {
+ double *clutTable1; /* Copy of current unfilted values */
+ FCOUNT(cc, MAX_CHAN, p->inputChan); /* Surrounding counter */
+
+ if ((clutTable1 = (double *) icp->al->calloc(icp->al,sizeof(double),
+ p->clutTable_size)) == NULL) {
+ icp->al->free(icp->al, clutTable3);
+ icp->al->free(icp->al, _iv);
+ sprintf(icp->err,"icmLut_set_tables malloc of grid copy failed");
+ return icp->errc = 1;
+ }
+
+ for (tn = 0; tn < ntables; tn++) {
+ int aa;
+ int ee;
+ int ti, ti3; /* Table indexes */
+
+ pn = pp[tn];
+
+ /* For each pass */
+ for (aa = 0; aa < 2; aa++) {
+
+ /* Copy current values */
+ memcpy(clutTable1, pn->clutTable, sizeof(double) * pn->clutTable_size);
+
+ /* Filter each point */
+ for (e = 0; e < pn->inputChan; e++)
+ ii[e] = 0; /* init coords */
+
+ /* Compute linear interpolated error to actual cell center value */
+ for (ee = 0; ee < pn->inputChan;) {
+ double rr; /* Filter radius */
+ int ir; /* Integer radius */
+ double tw; /* Total weight */
+
+ /* Compute base index for this cell */
+ for (ti3 = ti = e = 0; e < pn->inputChan; e++) { /* Input tables */
+ ti += ii[e] * pn->dinc[e]; /* Clut index */
+ ti3 += ii[e] * dinc3[e]; /* Clut3 index */
+ }
+ rr = clutTable3[ti3 + tn] * (pn->clutPoints-1.0);
+ ir = (int)floor(rr + 0.5); /* Don't bother unless 1/2 over vertex */
+
+ if (ir < 1)
+ goto next_vert;
+
+ //FRECONF(cc, -ir, ir + 1); /* Set size of surroundign grid */
+
+ /* Clip scanning cube to be within grid */
+ for (e = 0; e < pn->inputChan; e++) {
+ int cr = ir;
+ if ((ii[e] - ir) < 0)
+ cr = ii[e];
+ if ((ii[e] + ir) >= pn->clutPoints)
+ cr = pn->clutPoints -1 -ii[e];
+
+ cc_stt[e] = -cr;
+ cc_res[e] = cr + 1;
+ }
+
+ for (f = 0; f < pn->outputChan; f++)
+ pn->clutTable[ti + f] = 0.0;
+ tw = 0.0;
+
+ FC_INIT(cc)
+ for (tw = 0.0; !FC_DONE(cc);) {
+ double r;
+ int tti;
+
+ /* Radius of this cell */
+ for (r = 0.0, tti = e = 0; e < pn->inputChan; e++) {
+ int ix;
+ r += cc[e] * cc[e];
+ tti += (ii[e] + cc[e]) * p->dinc[e];
+ }
+ r = sqrt(r);
+
+ if (r <= rr && e >= pn->inputChan) {
+ double w = (rr - r)/rr; /* Triangle weighting */
+ w = sqrt(w);
+ for (f = 0; f < pn->outputChan; f++)
+ pn->clutTable[ti+f] += w * clutTable1[tti + f];
+ tw += w;
+ }
+ FC_INC(cc);
+ }
+ for (f = 0; f < pn->outputChan; f++) {
+ double vv = pn->clutTable[ti+f] / tw;
+ if (vv < 0.0) {
+ vv = 0.0;
+ } else if (vv > 1.0) {
+ vv = 1.0;
+ }
+ pn->clutTable[ti+f] = vv;
+ }
+
+ /* Increment coord */
+ next_vert:;
+ for (ee = 0; ee < pn->inputChan; ee++) {
+ if (++ii[ee] < (pn->clutPoints-1)) /* Don't go through upper edge */
+ break; /* No carry */
+ ii[ee] = 0;
+ }
+ } /* Next grid point to filter */
+ } /* Next pass */
+ } /* Next table */
+
+ free(clutTable1);
+ free(clutTable3);
+ }
+
+ /* Create the output table entry values */
+ for (tn = 0; tn < ntables; tn++) {
+ pn = pp[tn];
+ for (n = 0; n < pn->outputEnt; n++) {
+ double fv;
+ fv = n/(pn->outputEnt-1.0);
+ for (f = 0; f < pn->outputChan; f++)
+ iv[f] = fv;
+
+ /* Undo expansion to 0.0 - 1.0 */
+ for (f = 0; f < pn->outputChan; f++) /* Output tables */
+ iv[f] = iv[f] * (omax[f] - omin[f]) + omin[f];
+
+ ofromentry(iv,iv); /* Convert from table value to output color space value */
+
+ if (outfunc != NULL)
+ outfunc(cbctx, iv, iv); /* Out colorspace -> output table -> out colorspace. */
+
+ otoentry(iv,iv); /* Convert from output color space value to table value */
+
+ /* Clip to legal values */
+ for (f = 0; f < pn->outputChan; f++) {
+ double tt;
+ tt = iv[f];
+ if (tt < 0.0) {
+ DBGSLC(("oclip: tt = %f\n",tt));
+ if (tt < -CLIP_MARGIN)
+ clip = 5;
+ tt = 0.0;
+ } else if (tt > 1.0) {
+ DBGSLC(("oclip: tt = %f\n",tt));
+ if (tt > (1.0 + CLIP_MARGIN))
+ clip = 5;
+ tt = 1.0;
+ }
+ iv[f] = tt;
+ }
+
+ for (f = 0; f < pn->outputChan; f++) /* Input tables */
+ pn->outputTable[f * pn->outputEnt + n] = iv[f];
+ }
+ }
+
+ icp->al->free(icp->al, _iv);
+
+ icp->warnc = 0;
+ if (clip) {
+ DBGSLC(("Returning clip status = %d\n",clip));
+ icp->warnc = clip;
+ }
+
+ return 0;
+}
+
+/* Helper function to initialize a Lut tables contents */
+/* from supplied transfer functions. */
+/* Set errc and return error number */
+/* Set warnc if there is clipping in the output values */
+static int icmLut_set_tables (
+icmLut *p, /* Pointer to Lut object */
+int flags, /* Setting flags */
+void *cbctx, /* Opaque callback context pointer value */
+icColorSpaceSignature insig, /* Input color space */
+icColorSpaceSignature outsig, /* Output color space */
+void (*infunc)(void *cbcntx, double *out, double *in),
+ /* Input transfer function, inspace->inspace' (NULL = default) */
+double *inmin, double *inmax, /* Maximum range of inspace' values (NULL = default) */
+void (*clutfunc)(void *cbctx, double *out, double *in),
+ /* inspace' -> outspace' transfer function */
+double *clutmin, double *clutmax, /* Maximum range of outspace' values (NULL = default) */
+void (*outfunc)(void *cbctx, double *out, double *in)
+ /* Output transfer function, outspace'->outspace (NULL = deflt) */
+) {
+ struct _icmLut *pp[3];
+
+ /* Simply call the multiple table function with one table */
+ pp[0] = p;
+ return icmSetMultiLutTables(1, pp, flags,
+ cbctx, insig, outsig,
+ infunc,
+ inmin, inmax,
+ clutfunc,
+ clutmin, clutmax,
+ outfunc);
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmLut_get_size(
+ icmBase *pp
+) {
+ icmLut *p = (icmLut *)pp;
+ unsigned int len = 0;
+
+ if (p->ttype == icSigLut8Type) {
+ len = sat_add(len, 48); /* tag and header */
+ len = sat_add(len, sat_mul3(1, p->inputChan, p->inputEnt));
+ len = sat_add(len, sat_mul3(1, p->outputChan, sat_pow(p->clutPoints,p->inputChan)));
+ len = sat_add(len, sat_mul3(1, p->outputChan, p->outputEnt));
+ } else {
+ len = sat_add(len, 52); /* tag and header */
+ len = sat_add(len, sat_mul3(2, p->inputChan, p->inputEnt));
+ len = sat_add(len, sat_mul3(2, p->outputChan, sat_pow(p->clutPoints,p->inputChan)));
+ len = sat_add(len, sat_mul3(2, p->outputChan, p->outputEnt));
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmLut_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmLut *p = (icmLut *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, j, g, size;
+ char *bp, *buf;
+
+ if (len < 4) {
+ sprintf(icp->err,"icmLut_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmLut_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmLut_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
+ if (p->ttype != icSigLut8Type && p->ttype != icSigLut16Type) {
+ sprintf(icp->err,"icmLut_read: Wrong tag type for icmLut");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ if (p->ttype == icSigLut8Type) {
+ if (len < 48) {
+ sprintf(icp->err,"icmLut_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ } else {
+ if (len < 52) {
+ sprintf(icp->err,"icmLut_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+
+ /* Read in the info common to 8 and 16 bit Lut */
+ p->inputChan = read_UInt8Number(bp+8);
+ p->outputChan = read_UInt8Number(bp+9);
+ p->clutPoints = read_UInt8Number(bp+10);
+
+ /* Sanity check */
+ if (p->inputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_read: Can't handle > %d input channels\n",MAX_CHAN);
+ return icp->errc = 1;
+ }
+
+ if (p->outputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_read: Can't handle > %d output channels\n",MAX_CHAN);
+ return icp->errc = 1;
+ }
+
+ /* Read 3x3 transform matrix */
+ for (j = 0; j < 3; j++) { /* Rows */
+ for (i = 0; i < 3; i++) { /* Columns */
+ p->e[j][i] = read_S15Fixed16Number(bp + 12 + ((j * 3 + i) * 4));
+ }
+ }
+ /* Read 16 bit specific stuff */
+ if (p->ttype == icSigLut8Type) {
+ p->inputEnt = 256; /* By definition */
+ p->outputEnt = 256; /* By definition */
+ bp = buf+48;
+ } else {
+ p->inputEnt = read_UInt16Number(bp+48);
+ p->outputEnt = read_UInt16Number(bp+50);
+ bp = buf+52;
+ }
+
+ /* Sanity check dimensions. This protects against */
+ /* subsequent integer overflows involving the dimensions. */
+ if ((size = icmLut_get_size((icmBase *)p)) == UINT_MAX
+ || size > len) {
+ sprintf(icp->err,"icmLut_read: Tag wrong size for contents");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read the input tables */
+ size = (p->inputChan * p->inputEnt);
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1)
+ p->inputTable[i] = read_DCS8Number(bp);
+ } else {
+ for (i = 0; i < size; i++, bp += 2)
+ p->inputTable[i] = read_DCS16Number(bp);
+ }
+
+ /* Read the clut table */
+ size = (p->outputChan * sat_pow(p->clutPoints,p->inputChan));
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1)
+ p->clutTable[i] = read_DCS8Number(bp);
+ } else {
+ for (i = 0; i < size; i++, bp += 2)
+ p->clutTable[i] = read_DCS16Number(bp);
+ }
+
+ /* Read the output tables */
+ size = (p->outputChan * p->outputEnt);
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1)
+ p->outputTable[i] = read_DCS8Number(bp);
+ } else {
+ for (i = 0; i < size; i++, bp += 2)
+ p->outputTable[i] = read_DCS16Number(bp);
+ }
+
+ /* Private: compute dimensional increment though clut */
+ /* Note that first channel varies least rapidly. */
+ i = p->inputChan-1;
+ p->dinc[i--] = p->outputChan;
+ for (; i < p->inputChan; i--)
+ p->dinc[i] = p->dinc[i+1] * p->clutPoints;
+
+ /* Private: compute offsets from base of cube to other corners */
+ for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
+ for (i = 0; i < g; i++)
+ p->dcube[g+i] = p->dcube[i] + p->dinc[j];
+ g *= 2;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmLut_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmLut *p = (icmLut *)pp;
+ icc *icp = p->icp;
+ unsigned int i,j;
+ unsigned int len, size;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmLut_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write the info common to 8 and 16 bit Lut */
+ if ((rv = write_UInt8Number(p->inputChan, bp+8)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt8Number(p->outputChan, bp+9)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt8Number(p->clutPoints, bp+10)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ write_UInt8Number(0, bp+11); /* Set padding to 0 */
+
+ /* Write 3x3 transform matrix */
+ for (j = 0; j < 3; j++) { /* Rows */
+ for (i = 0; i < 3; i++) { /* Columns */
+ if ((rv = write_S15Fixed16Number(p->e[j][i],bp + 12 + ((j * 3 + i) * 4))) != 0) {
+ sprintf(icp->err,"icmLut_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write 16 bit specific stuff */
+ if (p->ttype == icSigLut8Type) {
+ if (p->inputEnt != 256 || p->outputEnt != 256) {
+ sprintf(icp->err,"icmLut_write: 8 bit Input and Output tables must be 256 entries");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp = buf+48;
+ } else {
+ if (p->inputEnt > 4096 || p->outputEnt > 4096) {
+ sprintf(icp->err,"icmLut_write: 16 bit Input and Output tables must each be less than 4096 entries");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if ((rv = write_UInt16Number(p->inputEnt, bp+48)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt16Number(p->outputEnt, bp+50)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp = buf+52;
+ }
+
+ /* Write the input tables */
+ size = (p->inputChan * p->inputEnt);
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1) {
+ if ((rv = write_DCS8Number(p->inputTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: inputTable write_DCS8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ } else {
+ for (i = 0; i < size; i++, bp += 2) {
+ if ((rv = write_DCS16Number(p->inputTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: inputTable write_DCS16Number(%f) failed",p->inputTable[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write the clut table */
+ size = (p->outputChan * sat_pow(p->clutPoints,p->inputChan));
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1) {
+ if ((rv = write_DCS8Number(p->clutTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: clutTable write_DCS8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ } else {
+ for (i = 0; i < size; i++, bp += 2) {
+ if ((rv = write_DCS16Number(p->clutTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: clutTable write_DCS16Number(%f) failed",p->clutTable[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write the output tables */
+ size = (p->outputChan * p->outputEnt);
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1) {
+ if ((rv = write_DCS8Number(p->outputTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: outputTable write_DCS8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ } else {
+ for (i = 0; i < size; i++, bp += 2) {
+ if ((rv = write_DCS16Number(p->outputTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: outputTable write_DCS16Number(%f) failed",p->outputTable[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write buffer to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmLut_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmLut_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmLut *p = (icmLut *)pp;
+ if (verb <= 0)
+ return;
+
+ if (p->ttype == icSigLut8Type) {
+ op->gprintf(op,"Lut8:\n");
+ } else {
+ op->gprintf(op,"Lut16:\n");
+ }
+ op->gprintf(op," Input Channels = %u\n",p->inputChan);
+ op->gprintf(op," Output Channels = %u\n",p->outputChan);
+ op->gprintf(op," CLUT resolution = %u\n",p->clutPoints);
+ op->gprintf(op," Input Table entries = %u\n",p->inputEnt);
+ op->gprintf(op," Output Table entries = %u\n",p->outputEnt);
+ op->gprintf(op," XYZ matrix = %f, %f, %f\n",p->e[0][0],p->e[0][1],p->e[0][2]);
+ op->gprintf(op," %f, %f, %f\n",p->e[1][0],p->e[1][1],p->e[1][2]);
+ op->gprintf(op," %f, %f, %f\n",p->e[2][0],p->e[2][1],p->e[2][2]);
+
+ if (verb >= 2) {
+ unsigned int i, j, size;
+ unsigned int ii[MAX_CHAN]; /* maximum no of input channels */
+
+ op->gprintf(op," Input table:\n");
+ for (i = 0; i < p->inputEnt; i++) {
+ op->gprintf(op," %3u: ",i);
+ for (j = 0; j < p->inputChan; j++)
+ op->gprintf(op," %1.10f",p->inputTable[j * p->inputEnt + i]);
+ op->gprintf(op,"\n");
+ }
+
+ op->gprintf(op,"\n CLUT table:\n");
+ if (p->inputChan > MAX_CHAN) {
+ op->gprintf(op," !!Can't dump > %d input channel CLUT table!!\n",MAX_CHAN);
+ } else {
+ size = (p->outputChan * sat_pow(p->clutPoints,p->inputChan));
+ for (j = 0; j < p->inputChan; j++)
+ ii[j] = 0;
+ for (i = 0; i < size;) {
+ unsigned int k;
+ /* Print table entry index */
+ op->gprintf(op," ");
+ for (j = p->inputChan-1; j < p->inputChan; j--)
+ op->gprintf(op," %2u",ii[j]);
+ op->gprintf(op,":");
+ /* Print table entry contents */
+ for (k = 0; k < p->outputChan; k++, i++)
+ op->gprintf(op," %1.10f",p->clutTable[i]);
+ op->gprintf(op,"\n");
+
+ for (j = 0; j < p->inputChan; j++) { /* Increment index */
+ ii[j]++;
+ if (ii[j] < p->clutPoints)
+ break; /* No carry */
+ ii[j] = 0;
+ }
+ }
+ }
+
+ op->gprintf(op,"\n Output table:\n");
+ for (i = 0; i < p->outputEnt; i++) {
+ op->gprintf(op," %3u: ",i);
+ for (j = 0; j < p->outputChan; j++)
+ op->gprintf(op," %1.10f",p->outputTable[j * p->outputEnt + i]);
+ op->gprintf(op,"\n");
+ }
+
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmLut_allocate(
+ icmBase *pp
+) {
+ unsigned int i, j, g, size;
+ icmLut *p = (icmLut *)pp;
+ icc *icp = p->icp;
+
+ /* Sanity check */
+ if (p->inputChan < 1) {
+ sprintf(icp->err,"icmLut_alloc: Can't handle %d input channels\n",p->inputChan);
+ return icp->errc = 1;
+ }
+
+ if (p->inputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_alloc: Can't handle > %d input channels\n",MAX_CHAN);
+ return icp->errc = 1;
+ }
+
+ if (p->outputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_alloc: Can't handle > %d output channels\n",MAX_CHAN);
+ return icp->errc = 1;
+ }
+
+ if ((size = sat_mul(p->inputChan, p->inputEnt)) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_alloc size overflow");
+ return icp->errc = 1;
+ }
+ if (size != p->inputTable_size) {
+ if (ovr_mul(size, sizeof(double))) {
+ sprintf(icp->err,"icmLut_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->inputTable != NULL)
+ icp->al->free(icp->al, p->inputTable);
+ if ((p->inputTable = (double *) icp->al->calloc(icp->al,size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmLut_alloc: calloc() of Lut inputTable data failed");
+ return icp->errc = 2;
+ }
+ p->inputTable_size = size;
+ }
+ if ((size = sat_mul(p->outputChan, sat_pow(p->clutPoints,p->inputChan))) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_alloc size overflow");
+ return icp->errc = 1;
+ }
+ if (size != p->clutTable_size) {
+ if (ovr_mul(size, sizeof(double))) {
+ sprintf(icp->err,"icmLut_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->clutTable != NULL)
+ icp->al->free(icp->al, p->clutTable);
+ if ((p->clutTable = (double *) icp->al->calloc(icp->al,size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmLut_alloc: calloc() of Lut clutTable data failed");
+ return icp->errc = 2;
+ }
+ p->clutTable_size = size;
+ }
+ if ((size = sat_mul(p->outputChan, p->outputEnt)) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_alloc size overflow");
+ return icp->errc = 1;
+ }
+ if (size != p->outputTable_size) {
+ if (ovr_mul(size, sizeof(double))) {
+ sprintf(icp->err,"icmLut_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->outputTable != NULL)
+ icp->al->free(icp->al, p->outputTable);
+ if ((p->outputTable = (double *) icp->al->calloc(icp->al,size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmLut_alloc: calloc() of Lut outputTable data failed");
+ return icp->errc = 2;
+ }
+ p->outputTable_size = size;
+ }
+
+ /* Private: compute dimensional increment though clut */
+ /* Note that first channel varies least rapidly. */
+ i = p->inputChan-1;
+ p->dinc[i--] = p->outputChan;
+ for (; i < p->inputChan; i--)
+ p->dinc[i] = p->dinc[i+1] * p->clutPoints;
+
+ /* Private: compute offsets from base of cube to other corners */
+ for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
+ for (i = 0; i < g; i++)
+ p->dcube[g+i] = p->dcube[i] + p->dinc[j];
+ g *= 2;
+ }
+
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmLut_delete(
+ icmBase *pp
+) {
+ icmLut *p = (icmLut *)pp;
+ icc *icp = p->icp;
+ int i;
+
+ if (p->inputTable != NULL)
+ icp->al->free(icp->al, p->inputTable);
+ if (p->clutTable != NULL)
+ icp->al->free(icp->al, p->clutTable);
+ if (p->outputTable != NULL)
+ icp->al->free(icp->al, p->outputTable);
+ for (i = 0; i < p->inputChan; i++)
+ icmTable_delete_bwd(icp, &p->rit[i]);
+ for (i = 0; i < p->outputChan; i++)
+ icmTable_delete_bwd(icp, &p->rot[i]);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmLut(
+ icc *icp
+) {
+ int i,j;
+ icmLut *p;
+ if ((p = (icmLut *) icp->al->calloc(icp->al,1,sizeof(icmLut))) == NULL)
+ return NULL;
+ p->ttype = icSigLut16Type;
+ p->refcount = 1;
+ p->get_size = icmLut_get_size;
+ p->read = icmLut_read;
+ p->write = icmLut_write;
+ p->dump = icmLut_dump;
+ p->allocate = icmLut_allocate;
+ p->del = icmLut_delete;
+
+ /* Lookup methods */
+ p->nu_matrix = icmLut_nu_matrix;
+ p->min_max = icmLut_min_max;
+ p->lookup_matrix = icmLut_lookup_matrix;
+ p->lookup_input = icmLut_lookup_input;
+ p->lookup_clut_nl = icmLut_lookup_clut_nl;
+ p->lookup_clut_sx = icmLut_lookup_clut_sx;
+ p->lookup_output = icmLut_lookup_output;
+
+ /* Set method */
+ p->set_tables = icmLut_set_tables;
+
+ p->icp = icp;
+
+ /* Set matrix to reasonable default */
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++) {
+ if (i == j)
+ p->e[i][j] = 1.0;
+ else
+ p->e[i][j] = 0.0;
+ }
+
+ /* Init lookups to non-dangerous values */
+ for (i = 0; i < MAX_CHAN; i++)
+ p->dinc[i] = 0;
+
+ for (i = 0; i < (1 << MAX_CHAN); i++)
+ p->dcube[i] = 0;
+
+ for (i = 0; i < MAX_CHAN; i++) {
+ p->rit[i].inited = 0;
+ p->rot[i].inited = 0;
+ }
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* Measurement */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmMeasurement_get_size(
+ icmBase *pp
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for standard observer */
+ len = sat_add(len, 12); /* 12 for XYZ of measurement backing */
+ len = sat_add(len, 4); /* 4 for measurement geometry */
+ len = sat_add(len, 4); /* 4 for measurement flare */
+ len = sat_add(len, 4); /* 4 for standard illuminant */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmMeasurement_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmMeasurement *p = (icmMeasurement *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf;
+
+ if (len < 36) {
+ sprintf(icp->err,"icmMeasurement_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmMeasurement_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmMeasurement_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmMeasurement_read: Wrong tag type for icmMeasurement");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read the encoded standard observer */
+ p->observer = (icStandardObserver)read_SInt32Number(bp + 8);
+
+ /* Read the XYZ values for measurement backing */
+ if ((rv = read_XYZNumber(&p->backing, bp+12)) != 0) {
+ sprintf(icp->err,"icmMeasurement: read_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Read the encoded measurement geometry */
+ p->geometry = (icMeasurementGeometry)read_SInt32Number(bp + 24);
+
+ /* Read the proportion of flare */
+ p->flare = read_U16Fixed16Number(bp + 28);
+
+ /* Read the encoded standard illuminant */
+ p->illuminant = (icIlluminant)read_SInt32Number(bp + 32);
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmMeasurement_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmMeasurement *p = (icmMeasurement *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmMeasurement_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmMeasurement_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmMeasurement_write, type: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write the encoded standard observer */
+ if ((rv = write_SInt32Number((int)p->observer, bp + 8)) != 0) {
+ sprintf(icp->err,"icmMeasurementa_write, observer: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the XYZ values for measurement backing */
+ if ((rv = write_XYZNumber(&p->backing, bp+12)) != 0) {
+ sprintf(icp->err,"icmMeasurement, backing: write_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the encoded measurement geometry */
+ if ((rv = write_SInt32Number((int)p->geometry, bp + 24)) != 0) {
+ sprintf(icp->err,"icmMeasurementa_write, geometry: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the proportion of flare */
+ if ((rv = write_U16Fixed16Number(p->flare, bp + 28)) != 0) {
+ sprintf(icp->err,"icmMeasurementa_write, flare: write_U16Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the encoded standard illuminant */
+ if ((rv = write_SInt32Number((int)p->illuminant, bp + 32)) != 0) {
+ sprintf(icp->err,"icmMeasurementa_write, illuminant: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmMeasurement_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmMeasurement_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmMeasurement *p = (icmMeasurement *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Measurement:\n");
+ op->gprintf(op," Standard Observer = %s\n", string_StandardObserver(p->observer));
+ op->gprintf(op," XYZ for Measurement Backing = %s\n", string_XYZNumber_and_Lab(&p->backing));
+ op->gprintf(op," Measurement Geometry = %s\n", string_MeasurementGeometry(p->geometry));
+ op->gprintf(op," Measurement Flare = %5.1f%%\n", p->flare * 100.0);
+ op->gprintf(op," Standard Illuminant = %s\n", string_Illuminant(p->illuminant));
+}
+
+/* Allocate variable sized data elements */
+static int icmMeasurement_allocate(
+ icmBase *pp
+) {
+ /* Nothing to do */
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmMeasurement_delete(
+ icmBase *pp
+) {
+ icmMeasurement *p = (icmMeasurement *)pp;
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmMeasurement(
+ icc *icp
+) {
+ icmMeasurement *p;
+ if ((p = (icmMeasurement *) icp->al->calloc(icp->al,1,sizeof(icmMeasurement))) == NULL)
+ return NULL;
+ p->ttype = icSigMeasurementType;
+ p->refcount = 1;
+ p->get_size = icmMeasurement_get_size;
+ p->read = icmMeasurement_read;
+ p->write = icmMeasurement_write;
+ p->dump = icmMeasurement_dump;
+ p->allocate = icmMeasurement_allocate;
+ p->del = icmMeasurement_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Named color structure read/write support */
+static int read_NamedColorVal(
+ icmNamedColorVal *p,
+ char *bp,
+ char *end,
+ icColorSpaceSignature pcs, /* Header Profile Connection Space */
+ unsigned int ndc /* Number of device corrds */
+) {
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int mxl; /* Max possible string length */
+ int rv;
+
+ if (bp > end) {
+ sprintf(icp->err,"icmNamedColorVal_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ mxl = (end - bp) < 32 ? (end - bp) : 32;
+ if ((rv = check_null_string(bp,mxl)) == 1) {
+ sprintf(icp->err,"icmNamedColorVal_read: Root name string not terminated");
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ strcpy(p->root, bp);
+ bp += strlen(p->root) + 1;
+ if (bp > end || ndc > (end - bp)) {
+ sprintf(icp->err,"icmNamedColorVal_read: Data too short to read device coords");
+ return icp->errc = 1;
+ }
+ for (i = 0; i < ndc; i++) {
+ p->deviceCoords[i] = read_DCS8Number(bp);
+ bp += 1;
+ }
+ return 0;
+}
+
+static int read_NamedColorVal2(
+ icmNamedColorVal *p,
+ char *bp,
+ char *end,
+ icColorSpaceSignature pcs, /* Header Profile Connection Space */
+ unsigned int ndc /* Number of device coords */
+) {
+ int rv;
+ icc *icp = p->icp;
+ unsigned int i;
+
+ if (bp > end
+ || (32 + 6) > (end - bp)
+ || ndc > (end - bp - 32 - 6)/2) {
+ sprintf(icp->err,"icmNamedColorVal2_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,32)) == 1) {
+ sprintf(icp->err,"icmNamedColorVal2_read: Root name string not terminated");
+ return icp->errc = 1;
+ }
+ memmove((void *)p->root,(void *)(bp + 0),32);
+ switch(pcs) {
+ case icSigXYZData:
+ read_PCSNumber(icp, icSigXYZData, p->pcsCoords, bp+32);
+ break;
+ case icSigLabData:
+ /* namedColor2Type retains legacy Lab encoding */
+ read_PCSNumber(icp, icmSigLabV2Data, p->pcsCoords, bp+32);
+ break;
+ default:
+ return 1; /* Unknown PCS */
+ }
+ for (i = 0; i < ndc; i++)
+ p->deviceCoords[i] = read_DCS16Number(bp + 32 + 6 + 2 * i);
+ return 0;
+}
+
+static int write_NamedColorVal(
+ icmNamedColorVal *p,
+ char *d,
+ icColorSpaceSignature pcs, /* Header Profile Connection Space */
+ unsigned int ndc /* Number of device corrds */
+) {
+ icc *icp = p->icp;
+ unsigned int i;
+ int rv;
+
+ if ((rv = check_null_string(p->root,32)) == 1) {
+ sprintf(icp->err,"icmNamedColorVal_write: Root string names is unterminated");
+ return icp->errc = 1;
+ }
+ strcpy(d, p->root);
+ d += strlen(p->root) + 1;
+ for (i = 0; i < ndc; i++) {
+ if ((rv = write_DCS8Number(p->deviceCoords[i], d)) != 0) {
+ sprintf(icp->err,"icmNamedColorVal_write: write of device coord failed");
+ return icp->errc = 1;
+ }
+ d += 1;
+ }
+ return 0;
+}
+
+static int write_NamedColorVal2(
+ icmNamedColorVal *p,
+ char *bp,
+ icColorSpaceSignature pcs, /* Header Profile Connection Space */
+ unsigned int ndc /* Number of device coords */
+) {
+ icc *icp = p->icp;
+ unsigned int i;
+ int rv;
+
+ if ((rv = check_null_string(p->root,32)) == 1) {
+ sprintf(icp->err,"icmNamedColorVal2_write: Root string names is unterminated");
+ return icp->errc = 1;
+ }
+ rv = 0;
+ memmove((void *)(bp + 0),(void *)p->root,32);
+ switch(pcs) {
+ case icSigXYZData:
+ rv |= write_PCSNumber(icp, icSigXYZData, p->pcsCoords, bp+32);
+ break;
+ case icSigLabData:
+ /* namedColor2Type retains legacy Lab encoding */
+ rv |= write_PCSNumber(icp, icmSigLabV2Data, p->pcsCoords, bp+32);
+ break;
+ default:
+ sprintf(icp->err,"icmNamedColorVal2_write: Unknown PCS");
+ return icp->errc = 1;
+ }
+ if (rv) {
+ sprintf(icp->err,"icmNamedColorVal2_write: write of PCS coord failed");
+ return icp->errc = 1;
+ }
+ for (i = 0; i < ndc; i++) {
+ if ((rv = write_DCS16Number(p->deviceCoords[i], bp + 32 + 6 + 2 * i)) != 0) {
+ sprintf(icp->err,"icmNamedColorVal2_write: write of device coord failed");
+ return icp->errc = 1;
+ }
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - */
+/* icmNamedColor object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmNamedColor_get_size(
+ icmBase *pp
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ unsigned int len = 0;
+ if (p->ttype == icSigNamedColorType) {
+ unsigned int i;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for vendor specific flags */
+ len = sat_add(len, 4); /* 4 for count of named colors */
+ len = sat_add(len, strlen(p->prefix) + 1); /* prefix of color names */
+ len = sat_add(len, strlen(p->suffix) + 1); /* suffix of color names */
+ for (i = 0; i < p->count; i++) {
+ len = sat_add(len, strlen(p->data[i].root) + 1); /* color names */
+ len = sat_add(len, p->nDeviceCoords * 1); /* bytes for each named color */
+ }
+ } else { /* Named Color 2 */
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for vendor specific flags */
+ len = sat_add(len, 4); /* 4 for count of named colors */
+ len = sat_add(len, 4); /* 4 for number of device coords */
+ len = sat_add(len, 32); /* 32 for prefix of color names */
+ len = sat_add(len, 32); /* 32 for suffix of color names */
+ len = sat_add(len, sat_mul(p->count, (32 + 6 + p->nDeviceCoords * 2)));
+ /* bytes for each named color */
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmNamedColor_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ char *bp, *buf, *end;
+ int rv;
+
+ if (len < 4) {
+ sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmNamedColor_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmNamedColor_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
+ if (p->ttype != icSigNamedColorType && p->ttype != icSigNamedColor2Type) {
+ sprintf(icp->err,"icmNamedColor_read: Wrong tag type for icmNamedColor");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ if (p->ttype == icSigNamedColorType) {
+ if (len < 16) {
+ sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Make sure that the number of device coords in known */
+ p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace);
+ if (p->nDeviceCoords > MAX_CHAN) {
+ sprintf(icp->err,"icmNamedColor_read: Can't handle more than %d device channels",MAX_CHAN);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ } else { /* icmNC2 */
+ if (len < 84) {
+ sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+
+ /* Read vendor specific flag */
+ p->vendorFlag = read_UInt32Number(bp+8);
+
+ /* Read count of named colors */
+ p->count = read_UInt32Number(bp+12);
+
+ if (p->ttype == icSigNamedColorType) {
+ unsigned int mxl; /* Max possible string length */
+ bp = bp + 16;
+
+ /* Prefix for each color name */
+ if (bp > end) {
+ sprintf(icp->err,"icmNamedColor_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ mxl = (end - bp) < 32 ? (end - bp) : 32;
+ if ((rv = check_null_string(bp,mxl)) == 1) {
+ sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ strcpy(p->prefix, bp);
+ bp += strlen(p->prefix) + 1;
+
+ /* Suffix for each color name */
+ if (bp > end) {
+ sprintf(icp->err,"icmNamedColor_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ mxl = (end - bp) < 32 ? (end - bp) : 32;
+ if ((rv = check_null_string(bp,mxl)) == 1) {
+ sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ strcpy(p->suffix, bp);
+ bp += strlen(p->suffix) + 1;
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < p->count; i++) {
+ if ((rv = read_NamedColorVal(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ bp += strlen(p->data[i].root) + 1;
+ bp += p->nDeviceCoords * 1;
+ }
+ } else { /* icmNC2 */
+ /* Number of device coords per color */
+ p->nDeviceCoords = read_UInt32Number(bp+16);
+ if (p->nDeviceCoords > MAX_CHAN) {
+ sprintf(icp->err,"icmNamedColor_read: Can't handle more than %d device channels",MAX_CHAN);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Prefix for each color name */
+ memmove((void *)p->prefix, (void *)(bp + 20), 32);
+ if ((rv = check_null_string(p->prefix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Suffix for each color name */
+ memmove((void *)p->suffix, (void *)(bp + 52), 32);
+ if ((rv = check_null_string(p->suffix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read all the data from the buffer */
+ bp = bp + 84;
+ for (i = 0; i < p->count; i++) {
+ if ((rv = read_NamedColorVal2(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ bp += 32 + 6 + p->nDeviceCoords * 2;
+ }
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmNamedColor_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmNamedColor_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmNamedColor_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmNamedColor_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write vendor specific flag */
+ if ((rv = write_UInt32Number(p->vendorFlag, bp+8)) != 0) {
+ sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write count of named colors */
+ if ((rv = write_UInt32Number(p->count, bp+12)) != 0) {
+ sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ if (p->ttype == icSigNamedColorType) {
+ bp = bp + 16;
+
+ /* Prefix for each color name */
+ if ((rv = check_null_string(p->prefix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ strcpy(bp, p->prefix);
+ bp += strlen(p->prefix) + 1;
+
+ /* Suffix for each color name */
+ if ((rv = check_null_string(p->suffix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ strcpy(bp, p->suffix);
+ bp += strlen(p->suffix) + 1;
+
+ /* Write all the data to the buffer */
+
+ for (i = 0; i < p->count; i++) {
+ if ((rv = write_NamedColorVal(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ bp += strlen(p->data[i].root) + 1;
+ bp += p->nDeviceCoords * 1;
+ }
+ } else { /* icmNC2 */
+ /* Number of device coords per color */
+ if ((rv = write_UInt32Number(p->nDeviceCoords, bp+16)) != 0) {
+ sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Prefix for each color name */
+ if ((rv = check_null_string(p->prefix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ memmove((void *)(bp + 20), (void *)p->prefix, 32);
+
+ /* Suffix for each color name */
+ if ((rv = check_null_string(p->suffix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ memmove((void *)(bp + 52), (void *)p->suffix, 32);
+
+ /* Write all the data to the buffer */
+ bp = bp + 84;
+ for (i = 0; i < p->count; i++, bp += (32 + 6 + p->nDeviceCoords * 2)) {
+ if ((rv = write_NamedColorVal2(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmNamedColor_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmNamedColor_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+ if (verb <= 0)
+ return;
+
+ if (p->ttype == icSigNamedColorType)
+ op->gprintf(op,"NamedColor:\n");
+ else
+ op->gprintf(op,"NamedColor2:\n");
+ op->gprintf(op," Vendor Flag = 0x%x\n",p->vendorFlag);
+ op->gprintf(op," No. colors = %u\n",p->count);
+ op->gprintf(op," No. dev. coords = %u\n",p->nDeviceCoords);
+ op->gprintf(op," Name prefix = '%s'\n",p->prefix);
+ op->gprintf(op," Name suffix = '%s'\n",p->suffix);
+ if (verb >= 2) {
+ unsigned int i, n;
+ icmNamedColorVal *vp;
+ for (i = 0; i < p->count; i++) {
+ vp = p->data + i;
+ op->gprintf(op," Color %lu:\n",i);
+ op->gprintf(op," Name root = '%s'\n",vp->root);
+
+ if (p->ttype == icSigNamedColor2Type) {
+ switch(icp->header->pcs) {
+ case icSigXYZData:
+ op->gprintf(op," XYZ = %f, %f, %f\n",
+ vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
+ break;
+ case icSigLabData:
+ op->gprintf(op," Lab = %f, %f, %f\n",
+ vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
+ break;
+ default:
+ op->gprintf(op," Unexpected PCS\n");
+ break;
+ }
+ }
+ if (p->nDeviceCoords > 0) {
+ op->gprintf(op," Device Coords = ");
+ for (n = 0; n < p->nDeviceCoords; n++) {
+ if (n > 0)
+ op->gprintf(op,", ");
+ op->gprintf(op,"%f",vp->deviceCoords[n]);
+ }
+ op->gprintf(op,"\n");
+ }
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmNamedColor_allocate(
+ icmBase *pp
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+
+ if (p->count != p->_count) {
+ unsigned int i;
+ if (ovr_mul(p->count, sizeof(icmNamedColorVal))) {
+ sprintf(icp->err,"icmNamedColor_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmNamedColorVal *) icp->al->calloc(icp->al,p->count, sizeof(icmNamedColorVal))) == NULL) {
+ sprintf(icp->err,"icmNamedColor_alloc: malloc() of icmNamedColor data failed");
+ return icp->errc = 2;
+ }
+ for (i = 0; i < p->count; i++) {
+ p->data[i].icp = icp; /* Do init */
+ }
+ p->_count = p->count;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmNamedColor_delete(
+ icmBase *pp
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmNamedColor(
+ icc *icp
+) {
+ icmNamedColor *p;
+ if ((p = (icmNamedColor *) icp->al->calloc(icp->al,1,sizeof(icmNamedColor))) == NULL)
+ return NULL;
+ p->ttype = icSigNamedColor2Type;
+ p->refcount = 1;
+ p->get_size = icmNamedColor_get_size;
+ p->read = icmNamedColor_read;
+ p->write = icmNamedColor_write;
+ p->dump = icmNamedColor_dump;
+ p->allocate = icmNamedColor_allocate;
+ p->del = icmNamedColor_delete;
+ p->icp = icp;
+
+ /* Default the the number of device coords appropriately for NamedColorType */
+ p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace);
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* Colorant table structure read/write support */
+/* (Contribution from Piet Vandenborre) */
+
+static int read_ColorantTableVal(
+ icmColorantTableVal *p,
+ char *bp,
+ char *end,
+ icColorSpaceSignature pcs /* Header Profile Connection Space */
+) {
+ int rv;
+ icc *icp = p->icp;
+ if (bp > end || (32 + 6) > (end - bp)) {
+ sprintf(icp->err,"icmColorantTableVal_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,32)) == 1) {
+ sprintf(icp->err,"icmColorantTableVal_read: Name string not terminated");
+ return icp->errc = 1;
+ }
+ memmove((void *)p->name,(void *)(bp + 0),32);
+ switch(pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ read_PCSNumber(icp, pcs, p->pcsCoords, bp+32);
+ break;
+ default:
+ return 1; /* Unknown PCS */
+ }
+ return 0;
+}
+
+static int write_ColorantTableVal(
+ icmColorantTableVal *p,
+ char *bp,
+ icColorSpaceSignature pcs /* Header Profile Connection Space */
+) {
+ int rv;
+ icc *icp = p->icp;
+
+ if ((rv = check_null_string(p->name,32)) == 1) {
+ sprintf(icp->err,"icmColorantTableVal_write: Name string is unterminated");
+ return icp->errc = 1;
+ }
+ memmove((void *)(bp + 0),(void *)p->name,32);
+ rv = 0;
+ switch(pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ rv |= write_PCSNumber(icp, pcs, p->pcsCoords, bp+32);
+ break;
+ default:
+ sprintf(icp->err,"icmColorantTableVal_write: Unknown PCS");
+ return icp->errc = 1;
+ }
+ if (rv) {
+ sprintf(icp->err,"icmColorantTableVal_write: write of PCS coord failed");
+ return icp->errc = 1;
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - */
+/* icmColorantTable object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmColorantTable_get_size(
+ icmBase *pp
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ unsigned int len = 0;
+ if (p->ttype == icSigColorantTableType
+ || p->ttype == icmSigAltColorantTableType) {
+ unsigned int i;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for count of colorants */
+ for (i = 0; i < p->count; i++) {
+ len = sat_add(len, 32); /* colorant names - 32 bytes*/
+ len = sat_add(len, 6); /* colorant pcs value - 3 x 16bit number*/
+ }
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmColorantTable_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+ icColorSpaceSignature pcs;
+ unsigned int i;
+ char *bp, *buf, *end;
+ int rv = 0;
+
+ if (icp->header->deviceClass != icSigLinkClass)
+ pcs = icp->header->pcs;
+ else
+ pcs = icSigLabData;
+
+ if (len < 4) {
+ sprintf(icp->err,"icmColorantTable_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmColorantTable_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmColorantTable_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
+ if (p->ttype != icSigColorantTableType
+ && p->ttype != icmSigAltColorantTableType) {
+ sprintf(icp->err,"icmColorantTable_read: Wrong tag type for icmColorantTable");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ if (len < 12) {
+ sprintf(icp->err,"icmColorantTable_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read count of colorants */
+ if (p->ttype == icmSigAltColorantTableType)
+ p->count = read_UInt8Number(bp+8); /* Hmm. This is Little Endian */
+ else
+ p->count = read_UInt32Number(bp+8);
+
+ if (p->count > ((len - 12) / (32 + 6))) {
+ sprintf(icp->err,"icmColorantTable_read count overflow, count %x, len %d",p->count,len);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ bp = bp + 12;
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < p->count; i++, bp += (32 + 6)) {
+ if (p->ttype == icmSigAltColorantTableType /* Hack to reverse little endian */
+ && (end - bp) >= 38) {
+ int tt;
+ tt = *(bp + 32);
+ *(bp+32) = *(bp+33);
+ *(bp+33) = tt;
+ tt = *(bp + 34);
+ *(bp+34) = *(bp+35);
+ *(bp+35) = tt;
+ tt = *(bp + 36);
+ *(bp+36) = *(bp+37);
+ *(bp+37) = tt;
+ }
+ if ((rv = read_ColorantTableVal(p->data+i, bp, end, pcs)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+
+ icp->al->free(icp->al, buf);
+ return rv;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmColorantTable_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+ icColorSpaceSignature pcs;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ if (icp->header->deviceClass != icSigLinkClass)
+ pcs = icp->header->pcs;
+ else
+ pcs = icSigLabData;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmColorantTable_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmColorantTable_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmColorantTable_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write count of colorants */
+ if ((rv = write_UInt32Number(p->count, bp+8)) != 0) {
+ sprintf(icp->err,"icmColorantTable_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ bp = bp + 12;
+
+ /* Write all the data to the buffer */
+ for (i = 0; i < p->count; i++, bp += (32 + 6)) {
+ if ((rv = write_ColorantTableVal(p->data+i, bp, pcs)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmColorantTable_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmColorantTable_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+ icColorSpaceSignature pcs;
+
+ if (icp->header->deviceClass != icSigLinkClass)
+ pcs = icp->header->pcs;
+ else
+ pcs = icSigLabData;
+
+ if (verb <= 0)
+ return;
+
+ if (p->ttype == icSigColorantTableType
+ || p->ttype == icmSigAltColorantTableType)
+ op->gprintf(op,"ColorantTable:\n");
+ op->gprintf(op," No. colorants = %u\n",p->count);
+ if (verb >= 2) {
+ unsigned int i;
+ icmColorantTableVal *vp;
+ for (i = 0; i < p->count; i++) {
+ vp = p->data + i;
+ op->gprintf(op," Colorant %lu:\n",i);
+ op->gprintf(op," Name = '%s'\n",vp->name);
+
+ if (p->ttype == icSigColorantTableType
+ || p->ttype == icmSigAltColorantTableType) {
+
+ switch(pcs) {
+ case icSigXYZData:
+ op->gprintf(op," XYZ = %f, %f, %f\n",
+ vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
+ break;
+ case icSigLabData:
+ op->gprintf(op," Lab = %f, %f, %f\n",
+ vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
+ break;
+ default:
+ op->gprintf(op," Unexpected PCS\n");
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmColorantTable_allocate(
+ icmBase *pp
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+
+ if (p->count != p->_count) {
+ unsigned int i;
+ if (ovr_mul(p->count, sizeof(icmColorantTableVal))) {
+ sprintf(icp->err,"icmColorantTable_alloc: count overflow (%d of %ld bytes)",p->count,sizeof(icmColorantTableVal));
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmColorantTableVal *) icp->al->calloc(icp->al,p->count, sizeof(icmColorantTableVal))) == NULL) {
+ sprintf(icp->err,"icmColorantTable_alloc: malloc() of icmColorantTable data failed");
+ return icp->errc = 2;
+ }
+ for (i = 0; i < p->count; i++) {
+ p->data[i].icp = icp; /* Do init */
+ }
+ p->_count = p->count;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmColorantTable_delete(
+ icmBase *pp
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmColorantTable(
+ icc *icp
+) {
+ icmColorantTable *p;
+ if ((p = (icmColorantTable *) icp->al->calloc(icp->al,1,sizeof(icmColorantTable))) == NULL)
+ return NULL;
+ p->ttype = icSigColorantTableType;
+ p->refcount = 1;
+ p->get_size = icmColorantTable_get_size;
+ p->read = icmColorantTable_read;
+ p->write = icmColorantTable_write;
+ p->dump = icmColorantTable_dump;
+ p->allocate = icmColorantTable_allocate;
+ p->del = icmColorantTable_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* textDescription */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmTextDescription_get_size(
+ icmBase *pp
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addadd(len, 4, p->size); /* Ascii string length + ascii string */
+ len = sat_addaddmul(len, 8, 2, p->ucSize); /* Unicode language code + length + string */
+ len = sat_addadd(len, 3, 67); /* ScriptCode code, length string */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmTextDescription_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf, *end;
+
+#ifdef ICM_STRICT
+ if (len < (8 + 4 + 8 + 3 /* + 67 */)) {
+#else
+ if (len < (8 + 4 + 8 + 3)) {
+#endif
+ sprintf(icp->err,"icmTextDescription_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmTextDescription_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmTextDescription_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read from the buffer into the structure */
+ if ((rv = p->core_read(p, &bp, end)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* core read the object, return 0 on success, error code on fail */
+static int icmTextDescription_core_read(
+ icmTextDescription *p,
+ char **bpp, /* Pointer to buffer pointer, returns next after read */
+ char *end /* Pointer to past end of read buffer */
+) {
+ icc *icp = p->icp;
+ int rv;
+ char *bp = *bpp;
+
+ if (bp > end || 8 > (end - bp)) {
+ sprintf(icp->err,"icmTextDescription_read: Data too short to type descriptor");
+ *bpp = bp;
+ return icp->errc = 1;
+ }
+
+ p->size = read_UInt32Number(bp);
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Wrong tag type ('%s') for icmTextDescription",
+ tag2str((icTagTypeSignature)read_SInt32Number(bp)));
+ return icp->errc = 1;
+ }
+ bp = bp + 8;
+
+ /* Read the Ascii string */
+ if (bp > end || 4 > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read Ascii header");
+ return icp->errc = 1;
+ }
+ p->size = read_UInt32Number(bp);
+ bp += 4;
+ if (p->size > 0) {
+ if (bp > end || p->size > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read Ascii string");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,p->size)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: ascii string is not terminated");
+ return icp->errc = 1;
+ }
+#ifdef ICM_STRICT
+ if (rv == 2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: ascii string is shorter than count");
+ return icp->errc = 1;
+ }
+#endif
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ return rv;
+ }
+ strcpy(p->desc, bp);
+ bp += p->size;
+ }
+
+ /* Read the Unicode string */
+ if (bp > end || 8 > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
+ return icp->errc = 1;
+ }
+ p->ucLangCode = read_UInt32Number(bp);
+ bp += 4;
+ p->ucSize = read_UInt32Number(bp);
+ bp += 4;
+ if (p->ucSize > 0) {
+ ORD16 *up;
+ char *tbp;
+ if (bp > end || p->ucSize > (end - bp)/2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string16(bp,p->ucSize)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Unicode string is not terminated");
+ return icp->errc = 1;
+ }
+#ifdef ICM_STRICT
+ if (rv == 2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Unicode string is shorter than count");
+ return icp->errc = 1;
+ }
+#endif
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ return rv;
+ }
+ for (up = p->ucDesc, tbp = bp; tbp[0] != 0 || tbp[1] != 0; up++, tbp += 2)
+ *up = read_UInt16Number(tbp);
+ *up = 0; /* Unicode null */
+ bp += p->ucSize * 2;
+ }
+
+ /* Read the ScriptCode string */
+ if (bp > end || 3 > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode header");
+ return icp->errc = 1;
+ }
+ p->scCode = read_UInt16Number(bp);
+ bp += 2;
+ p->scSize = read_UInt8Number(bp);
+ bp += 1;
+ if (p->scSize > 0) {
+ if (p->scSize > 67) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: ScriptCode string too long");
+ return icp->errc = 1;
+ }
+ if (bp > end || p->scSize > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode string");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,p->scSize)) == 1) {
+#ifdef ICM_STRICT
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: ScriptCode string is not terminated");
+ return icp->errc = 1;
+#else
+ /* Patch it up */
+ bp[p->scSize-1] = '\000';
+#endif
+ }
+ memmove((void *)p->scDesc, (void *)bp, p->scSize);
+ } else {
+ memset((void *)p->scDesc, 0, 67);
+ }
+ bp += 67;
+
+ *bpp = bp;
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmTextDescription_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmTextDescription_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmTextDescription_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write to the buffer from the structure */
+ if ((rv = p->core_write(p, &bp)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmTextDescription_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Core write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmTextDescription_core_write(
+ icmTextDescription *p,
+ char **bpp /* Pointer to buffer pointer, returns next after read */
+) {
+ icc *icp = p->icp;
+ char *bp = *bpp;
+ int rv;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_SInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp = bp + 8;
+
+ /* Write the Ascii string */
+ if ((rv = write_UInt32Number(p->size,bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if (p->size > 0) {
+ if ((rv = check_null_string(p->desc,p->size)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: ascii string is not terminated");
+ return icp->errc = 1;
+ }
+ if (rv == 2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: ascii string is shorter than length");
+ return icp->errc = 1;
+ }
+ strcpy(bp, p->desc);
+ bp += strlen(p->desc) + 1;
+ }
+
+ /* Write the Unicode string */
+ if ((rv = write_UInt32Number(p->ucLangCode, bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if ((rv = write_UInt32Number(p->ucSize, bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if (p->ucSize > 0) {
+ ORD16 *up;
+ if ((rv = check_null_string16((char *)p->ucDesc,p->ucSize)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: Unicode string is not terminated");
+ return icp->errc = 1;
+ }
+ if (rv == 2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: Unicode string is shorter than length");
+ return icp->errc = 1;
+ }
+ for(up = p->ucDesc; *up != 0; up++, bp += 2) {
+ if ((rv = write_UInt16Number(((unsigned int)*up), bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ }
+ bp[0] = 0; /* null */
+ bp[1] = 0;
+ bp += 2;
+ }
+
+ /* Write the ScriptCode string */
+ if ((rv = write_UInt16Number(p->scCode, bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 2;
+ if ((rv = write_UInt8Number(p->scSize, bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt8Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 1;
+ if (p->scSize > 0) {
+ if (p->scSize > 67) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: ScriptCode string too long");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string((char *)p->scDesc,p->scSize)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: ScriptCode string is not terminated");
+ return icp->errc = 1;
+ }
+ memmove((void *)bp, (void *)p->scDesc, 67);
+ } else {
+ memset((void *)bp, 0, 67);
+ }
+ bp += 67;
+
+ *bpp = bp;
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmTextDescription_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ unsigned int i, r, c;
+
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"TextDescription:\n");
+
+ if (p->size > 0) {
+ unsigned int size = p->size > 0 ? p->size-1 : 0;
+ op->gprintf(op," ASCII data, length %lu chars:\n",p->size);
+
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 75) {
+ if (isprint(p->desc[i])) {
+ op->gprintf(op,"%c",p->desc[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->desc[i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ } else {
+ op->gprintf(op," No ASCII data\n");
+ }
+
+ /* Can't dump Unicode or ScriptCode as text with portable code */
+ if (p->ucSize > 0) {
+ unsigned int size = p->ucSize;
+ op->gprintf(op," Unicode Data, Language code 0x%x, length %lu chars\n",
+ p->ucLangCode, p->ucSize);
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 75) {
+ op->gprintf(op,"%04x ",p->ucDesc[i]);
+ c += 5;
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ } else {
+ op->gprintf(op," No Unicode data\n");
+ }
+ if (p->scSize > 0) {
+ unsigned int size = p->scSize;
+ op->gprintf(op," ScriptCode Data, Code 0x%x, length %lu chars\n",
+ p->scCode, p->scSize);
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 75) {
+ op->gprintf(op,"%02x ",p->scDesc[i]);
+ c += 3;
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ } else {
+ op->gprintf(op," No ScriptCode data\n");
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmTextDescription_allocate(
+ icmBase *pp
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(char))) {
+ sprintf(icp->err,"icmTextDescription_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->desc != NULL)
+ icp->al->free(icp->al, p->desc);
+ if ((p->desc = (char *) icp->al->calloc(icp->al, p->size, sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmTextDescription_alloc: malloc() of Ascii description failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ if (p->ucSize != p->uc_size) {
+ if (ovr_mul(p->ucSize, sizeof(ORD16))) {
+ sprintf(icp->err,"icmTextDescription_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->ucDesc != NULL)
+ icp->al->free(icp->al, p->ucDesc);
+ if ((p->ucDesc = (ORD16 *) icp->al->calloc(icp->al, p->ucSize, sizeof(ORD16))) == NULL) {
+ sprintf(icp->err,"icmTextDescription_alloc: malloc() of Unicode description failed");
+ return icp->errc = 2;
+ }
+ p->uc_size = p->ucSize;
+ }
+ return 0;
+}
+
+/* Free all variable sized elements */
+static void icmTextDescription_unallocate(
+ icmTextDescription *p
+) {
+ icc *icp = p->icp;
+
+ if (p->desc != NULL)
+ icp->al->free(icp->al, p->desc);
+ if (p->ucDesc != NULL)
+ icp->al->free(icp->al, p->ucDesc);
+}
+
+/* Free all storage in the object */
+static void icmTextDescription_delete(
+ icmBase *pp
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ icc *icp = p->icp;
+
+ icmTextDescription_unallocate(p);
+ icp->al->free(icp->al, p);
+}
+
+/* Initialze a named object */
+static void icmTextDescription_init(
+ icmTextDescription *p,
+ icc *icp
+) {
+ memset((void *)p, 0, sizeof(icmTextDescription)); /* Imitate calloc */
+
+ p->ttype = icSigTextDescriptionType;
+ p->refcount = 1;
+ p->get_size = icmTextDescription_get_size;
+ p->read = icmTextDescription_read;
+ p->write = icmTextDescription_write;
+ p->dump = icmTextDescription_dump;
+ p->allocate = icmTextDescription_allocate;
+ p->del = icmTextDescription_delete;
+ p->icp = icp;
+
+ p->core_read = icmTextDescription_core_read;
+ p->core_write = icmTextDescription_core_write;
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmTextDescription(
+ icc *icp
+) {
+ icmTextDescription *p;
+ if ((p = (icmTextDescription *) icp->al->calloc(icp->al,1,sizeof(icmTextDescription))) == NULL)
+ return NULL;
+
+ icmTextDescription_init(p,icp);
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Support for icmDescStruct */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmDescStruct_get_size(
+ icmDescStruct *p
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 20); /* 20 bytes for header info */
+ len = sat_add(len, p->device.get_size((icmBase *)&p->device));
+ if (p->device.size == 0)
+ len = sat_add(len, 1); /* Extra 1 because of zero length desciption */
+ len = sat_add(len, p->model.get_size((icmBase *)&p->model));
+ if (p->model.size == 0)
+ len = sat_add(len, 1); /* Extra 1 because of zero length desciption */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmDescStruct_read(
+ icmDescStruct *p,
+ char **bpp, /* Pointer to buffer pointer, returns next after read */
+ char *end /* Pointer to past end of read buffer */
+) {
+ icc *icp = p->icp;
+ char *bp = *bpp;
+ int rv = 0;
+
+ if (bp > end || 20 > (end - bp)) {
+ sprintf(icp->err,"icmDescStruct_read: Data too short read header");
+ *bpp = bp;
+ return icp->errc = 1;
+ }
+
+ p->deviceMfg = read_SInt32Number(bp + 0);
+ p->deviceModel = read_UInt32Number(bp + 4);
+ read_UInt64Number(&p->attributes, bp + 8);
+ p->technology = (icTechnologySignature) read_UInt32Number(bp + 16);
+ *bpp = bp += 20;
+
+ /* Read the device text description */
+ if ((rv = p->device.core_read(&p->device, bpp, end)) != 0) {
+ return rv;
+ }
+
+ /* Read the model text description */
+ if ((rv = p->model.core_read(&p->model, bpp, end)) != 0) {
+ return rv;
+ }
+
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmDescStruct_write(
+ icmDescStruct *p,
+ char **bpp /* Pointer to buffer pointer, returns next after read */
+) {
+ icc *icp = p->icp;
+ char *bp = *bpp;
+ int rv = 0;
+ char *ttd = NULL;
+ unsigned int tts = 0;
+
+ if ((rv = write_SInt32Number(p->deviceMfg, bp + 0)) != 0) {
+ sprintf(icp->err,"icmDescStruct_write: write_SInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->deviceModel, bp + 4)) != 0) {
+ sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt64Number(&p->attributes, bp + 8)) != 0) {
+ sprintf(icp->err,"icmDescStruct_write: write_UInt64Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->technology, bp + 16)) != 0) {
+ sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ *bpp = bp += 20;
+
+ /* Make sure the ASCII device text is a minimum size of 1, as per the spec. */
+ ttd = p->device.desc;
+ tts = p->device.size;
+
+ if (p->device.size == 0) {
+ p->device.desc = "";
+ p->device.size = 1;
+ }
+
+ /* Write the device text description */
+ if ((rv = p->device.core_write(&p->device, bpp)) != 0) {
+ return rv;
+ }
+
+ p->device.desc = ttd;
+ p->device.size = tts;
+
+ /* Make sure the ASCII model text is a minimum size of 1, as per the spec. */
+ ttd = p->model.desc;
+ tts = p->model.size;
+
+ if (p->model.size == 0) {
+ p->model.desc = "";
+ p->model.size = 1;
+ }
+
+ /* Write the model text description */
+ if ((rv = p->model.core_write(&p->model, bpp)) != 0) {
+ return rv;
+ }
+
+ p->model.desc = ttd;
+ p->model.size = tts;
+
+ /* Make sure the ASCII model text is a minimum size of 1, as per the spec. */
+ ttd = p->device.desc;
+ tts = p->device.size;
+
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmDescStruct_dump(
+ icmDescStruct *p,
+ icmFile *op, /* Output to dump to */
+ int verb, /* Verbosity level */
+ int index /* Description index */
+) {
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"DescStruct %u:\n",index);
+ if (verb >= 1) {
+ op->gprintf(op," Dev. Mnfctr. = %s\n",tag2str(p->deviceMfg)); /* ~~~ */
+ op->gprintf(op," Dev. Model = %s\n",tag2str(p->deviceModel)); /* ~~~ */
+ op->gprintf(op," Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l));
+ op->gprintf(op," Dev. Technology = %s\n", string_TechnologySignature(p->technology));
+ p->device.dump((icmBase *)&p->device, op,verb);
+ p->model.dump((icmBase *)&p->model, op,verb);
+ op->gprintf(op,"\n");
+ }
+}
+
+/* Allocate variable sized data elements (ie. descriptions) */
+static int icmDescStruct_allocate(
+ icmDescStruct *p
+) {
+ int rv;
+
+ if ((rv = p->device.allocate((icmBase *)&p->device)) != 0) {
+ return rv;
+ }
+ if ((rv = p->model.allocate((icmBase *)&p->model)) != 0) {
+ return rv;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmDescStruct_delete(
+ icmDescStruct *p
+) {
+ icmTextDescription_unallocate(&p->device);
+ icmTextDescription_unallocate(&p->model);
+}
+
+/* Init a DescStruct object */
+static void icmDescStruct_init(
+ icmDescStruct *p,
+ icc *icp
+) {
+
+ p->allocate = icmDescStruct_allocate;
+ p->icp = icp;
+
+ icmTextDescription_init(&p->device, icp);
+ icmTextDescription_init(&p->model, icp);
+}
+
+/* - - - - - - - - - - - - - - - */
+/* icmProfileSequenceDesc object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmProfileSequenceDesc_get_size(
+ icmBase *pp
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ unsigned int len = 0;
+ unsigned int i;
+ len = sat_add(len, 12); /* 12 bytes for tag, padding and count */
+ for (i = 0; i < p->count; i++) { /* All the description structures */
+ len = sat_add(len, icmDescStruct_get_size(&p->data[i]));
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmProfileSequenceDesc_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ char *bp, *buf, *end;
+ int rv = 0;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmProfileSequenceDesc_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmProfileSequenceDesc_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmProfileSequenceDesc_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmProfileSequenceDesc_read: Wrong tag type for icmProfileSequenceDesc");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ p->count = read_UInt32Number(bp); /* Number of sequence descriptions */
+ bp += 4;
+
+ /* Read all the sequence descriptions */
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ for (i = 0; i < p->count; i++) {
+ if ((rv = icmDescStruct_read(&p->data[i], &bp, end)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmProfileSequenceDesc_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ if ((rv = write_UInt32Number(p->count,bp+8)) != 0) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp = bp + 12;
+
+ /* Write all the description structures */
+ for (i = 0; i < p->count; i++) {
+ if ((rv = icmDescStruct_write(&p->data[i], &bp)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmProfileSequenceDesc_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"ProfileSequenceDesc:\n");
+ op->gprintf(op," No. elements = %u\n",p->count);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->count; i++)
+ icmDescStruct_dump(&p->data[i], op, verb-1, i);
+ }
+}
+
+/* Allocate variable sized data elements (ie. count of profile descriptions) */
+static int icmProfileSequenceDesc_allocate(
+ icmBase *pp
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+
+ if (p->count != p->_count) {
+ if (ovr_mul(p->count, sizeof(icmDescStruct))) {
+ sprintf(icp->err,"icmProfileSequenceDesc_allocate: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmDescStruct *) icp->al->calloc(icp->al, p->count, sizeof(icmDescStruct))) == NULL) {
+ sprintf(icp->err,"icmProfileSequenceDesc_allocate Allocation of DescStruct array failed");
+ return icp->errc = 2;
+ }
+ /* Now init the DescStructs */
+ for (i = 0; i < p->count; i++) {
+ icmDescStruct_init(&p->data[i], icp);
+ }
+ p->_count = p->count;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmProfileSequenceDesc_delete(
+ icmBase *pp
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++) {
+ icmDescStruct_delete(&p->data[i]); /* Free allocated contents */
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmProfileSequenceDesc(
+ icc *icp
+) {
+ icmProfileSequenceDesc *p;
+ if ((p = (icmProfileSequenceDesc *) icp->al->calloc(icp->al,1,sizeof(icmProfileSequenceDesc))) == NULL)
+ return NULL;
+ p->ttype = icSigProfileSequenceDescType;
+ p->refcount = 1;
+ p->get_size = icmProfileSequenceDesc_get_size;
+ p->read = icmProfileSequenceDesc_read;
+ p->write = icmProfileSequenceDesc_write;
+ p->dump = icmProfileSequenceDesc_dump;
+ p->allocate = icmProfileSequenceDesc_allocate;
+ p->del = icmProfileSequenceDesc_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* Signature */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmSignature_get_size(
+ icmBase *pp
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for signature */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmSignature_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmSignature *p = (icmSignature *)pp;
+ icc *icp = p->icp;
+ char *bp, *buf;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmSignature_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmSignature_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmSignature_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmSignaturSignatureng tag type for icmSignature");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read the encoded measurement geometry */
+ p->sig = (icTechnologySignature)read_SInt32Number(bp + 8);
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmSignature_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmSignature *p = (icmSignature *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmSignature_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmSignature_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmSignature_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write the signature */
+ if ((rv = write_SInt32Number((int)p->sig, bp + 8)) != 0) {
+ sprintf(icp->err,"icmSignaturea_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmSignature_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmSignature_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmSignature *p = (icmSignature *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Signature\n");
+ op->gprintf(op," Technology = %s\n", string_TechnologySignature(p->sig));
+}
+
+/* Allocate variable sized data elements */
+static int icmSignature_allocate(
+ icmBase *pp
+) {
+ /* Nothing to do */
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmSignature_delete(
+ icmBase *pp
+) {
+ icmSignature *p = (icmSignature *)pp;
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmSignature(
+ icc *icp
+) {
+ icmSignature *p;
+ if ((p = (icmSignature *) icp->al->calloc(icp->al,1,sizeof(icmSignature))) == NULL)
+ return NULL;
+ p->ttype = icSigSignatureType;
+ p->refcount = 1;
+ p->get_size = icmSignature_get_size;
+ p->read = icmSignature_read;
+ p->write = icmSignature_write;
+ p->dump = icmSignature_dump;
+ p->allocate = icmSignature_allocate;
+ p->del = icmSignature_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Data conversion support functions */
+static int read_ScreeningData(icmScreeningData *p, char *d) {
+ p->frequency = read_S15Fixed16Number(d + 0);
+ p->angle = read_S15Fixed16Number(d + 4);
+ p->spotShape = (icSpotShape)read_SInt32Number(d + 8);
+ return 0;
+}
+
+static int write_ScreeningData(icmScreeningData *p, char *d) {
+ int rv;
+ if ((rv = write_S15Fixed16Number(p->frequency, d + 0)) != 0)
+ return rv;
+ if ((rv = write_S15Fixed16Number(p->angle, d + 4)) != 0)
+ return rv;
+ if ((rv = write_SInt32Number((int)p->spotShape, d + 8)) != 0)
+ return rv;
+ return 0;
+}
+
+
+/* icmScreening object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmScreening_get_size(
+ icmBase *pp
+) {
+ icmScreening *p = (icmScreening *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 16); /* 16 bytes for tag, padding, flag & channeles */
+ len = sat_addmul(len, p->channels, 12); /* 12 bytes for each channel */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmScreening_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmScreening *p = (icmScreening *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i;
+ char *bp, *buf, *end;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmScreening_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmScreening_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmScreening_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmScreening_read: Wrong tag type for icmScreening");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->screeningFlag = read_UInt32Number(bp+8); /* Flags */
+ p->channels = read_UInt32Number(bp+12); /* Number of channels */
+ bp = bp + 16;
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < p->channels; i++, bp += 12) {
+ if (bp > end || 12 > (end - bp)) {
+ sprintf(icp->err,"icmScreening_read: Data too short to read Screening Data");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ read_ScreeningData(&p->data[i], bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmScreening_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmScreening *p = (icmScreening *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmScreening_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmScreening_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmScreening_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ if ((rv = write_UInt32Number(p->screeningFlag,bp+8)) != 0) {
+ sprintf(icp->err,"icmScreening_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->channels,bp+12)) != 0) {
+ sprintf(icp->err,"icmScreening_write: write_UInt32NumberXYZumber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp = bp + 16;
+
+ /* Write all the data to the buffer */
+ for (i = 0; i < p->channels; i++, bp += 12) {
+ if ((rv = write_ScreeningData(&p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmScreening_write: write_ScreeningData() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmScreening_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmScreening_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmScreening *p = (icmScreening *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Screening:\n");
+ op->gprintf(op," Flags = %s\n", string_ScreenEncodings(p->screeningFlag));
+ op->gprintf(op," No. channels = %u\n",p->channels);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->channels; i++) {
+ op->gprintf(op," %lu:\n",i);
+ op->gprintf(op," Frequency: %f\n",p->data[i].frequency);
+ op->gprintf(op," Angle: %f\n",p->data[i].angle);
+ op->gprintf(op," Spot shape: %s\n", string_SpotShape(p->data[i].spotShape));
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmScreening_allocate(
+ icmBase *pp
+) {
+ icmScreening *p = (icmScreening *)pp;
+ icc *icp = p->icp;
+
+ if (p->channels != p->_channels) {
+ if (ovr_mul(p->channels, sizeof(icmScreeningData))) {
+ sprintf(icp->err,"icmScreening_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmScreeningData *) icp->al->malloc(icp->al, p->channels * sizeof(icmScreeningData))) == NULL) {
+ sprintf(icp->err,"icmScreening_alloc: malloc() of icmScreening data failed");
+ return icp->errc = 2;
+ }
+ p->_channels = p->channels;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmScreening_delete(
+ icmBase *pp
+) {
+ icmScreening *p = (icmScreening *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmScreening(
+ icc *icp
+) {
+ icmScreening *p;
+ if ((p = (icmScreening *) icp->al->calloc(icp->al,1,sizeof(icmScreening))) == NULL)
+ return NULL;
+ p->ttype = icSigScreeningType;
+ p->refcount = 1;
+ p->get_size = icmScreening_get_size;
+ p->read = icmScreening_read;
+ p->write = icmScreening_write;
+ p->dump = icmScreening_dump;
+ p->allocate = icmScreening_allocate;
+ p->del = icmScreening_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUcrBg object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUcrBg_get_size(
+ icmBase *pp
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addaddmul(len, 4, p->UCRcount, 2); /* Undercolor Removal */
+ len = sat_addaddmul(len, 4, p->BGcount, 2); /* Black Generation */
+ len = sat_add(len, p->size); /* Description string */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUcrBg_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ int rv;
+ char *bp, *buf, *end;
+
+ if (len < 16) {
+ sprintf(icp->err,"icmUcrBg_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUcrBg_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUcrBg_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmUcrBg_read: Wrong tag type for icmUcrBg");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->UCRcount = read_UInt32Number(bp+8); /* First curve count */
+ bp = bp + 12;
+
+ if (p->UCRcount > 0) {
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ for (i = 0; i < p->UCRcount; i++, bp += 2) {
+ if (bp > end || 2 > (end - bp)) {
+ sprintf(icp->err,"icmUcrBg_read: Data too short to read UCR Data");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if (p->UCRcount == 1) /* % */
+ p->UCRcurve[i] = (double)read_UInt16Number(bp);
+ else /* 0.0 - 1.0 */
+ p->UCRcurve[i] = read_DCS16Number(bp);
+ }
+ } else {
+ p->UCRcurve = NULL;
+ }
+
+ if (bp > end || 4 > (end - bp)) {
+ sprintf(icp->err,"icmData_read: Data too short to read Black Gen count");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->BGcount = read_UInt32Number(bp); /* First curve count */
+ bp += 4;
+
+ if (p->BGcount > 0) {
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ for (i = 0; i < p->BGcount; i++, bp += 2) {
+ if (bp > end || 2 > (end - bp)) {
+ sprintf(icp->err,"icmUcrBg_read: Data too short to read BG Data");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if (p->BGcount == 1) /* % */
+ p->BGcurve[i] = (double)read_UInt16Number(bp);
+ else /* 0.0 - 1.0 */
+ p->BGcurve[i] = read_DCS16Number(bp);
+ }
+ } else {
+ p->BGcurve = NULL;
+ }
+
+ p->size = end - bp; /* Nominal string length */
+ if (p->size > 0) {
+ if ((rv = check_null_string(bp, p->size)) == 1) {
+ sprintf(icp->err,"icmUcrBg_read: string is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = strlen(bp) + 1;
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ memmove((void *)p->string, (void *)bp, p->size);
+ bp += p->size;
+ } else {
+ p->string = NULL;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUcrBg_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUcrBg_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUcrBg_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp = bp + 8;
+
+ /* Write UCR curve */
+ if ((rv = write_UInt32Number(p->UCRcount,bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 4;
+
+ for (i = 0; i < p->UCRcount; i++, bp += 2) {
+ if (p->UCRcount == 1) { /* % */
+ if ((rv = write_UInt16Number((unsigned int)(p->UCRcurve[i]+0.5),bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ } else {
+ if ((rv = write_DCS16Number(p->UCRcurve[i],bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->UCRcurve[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write BG curve */
+ if ((rv = write_UInt32Number(p->BGcount,bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 4;
+
+ for (i = 0; i < p->BGcount; i++, bp += 2) {
+ if (p->BGcount == 1) { /* % */
+ if ((rv = write_UInt16Number((unsigned int)(p->BGcurve[i]+0.5),bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ } else {
+ if ((rv = write_DCS16Number(p->BGcurve[i],bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->BGcurve[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ if (p->string != NULL) {
+ if ((rv = check_null_string(p->string,p->size)) == 1) {
+ sprintf(icp->err,"icmUcrBg_write: text is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if (rv == 2) {
+ sprintf(icp->err,"icmUcrBg_write: text is shorter than length");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ memmove((void *)bp, (void *)p->string, p->size);
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUcrBg_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUcrBg_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Undercolor Removal Curve & Black Generation:\n");
+
+ if (p->UCRcount == 0) {
+ op->gprintf(op," UCR: Not specified\n");
+ } else if (p->UCRcount == 1) {
+ op->gprintf(op," UCR: %f%%\n",p->UCRcurve[0]);
+ } else {
+ op->gprintf(op," UCR curve no. elements = %u\n",p->UCRcount);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->UCRcount; i++)
+ op->gprintf(op," %3lu: %f\n",i,p->UCRcurve[i]);
+ }
+ }
+ if (p->BGcount == 0) {
+ op->gprintf(op," BG: Not specified\n");
+ } else if (p->BGcount == 1) {
+ op->gprintf(op," BG: %f%%\n",p->BGcurve[0]);
+ } else {
+ op->gprintf(op," BG curve no. elements = %u\n",p->BGcount);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->BGcount; i++)
+ op->gprintf(op," %3lu: %f\n",i,p->BGcurve[i]);
+ }
+ }
+
+ {
+ unsigned int i, r, c, size;
+ op->gprintf(op," Description:\n");
+ op->gprintf(op," No. chars = %lu\n",p->size);
+
+ size = p->size > 0 ? p->size-1 : 0;
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 73) {
+ if (isprint(p->string[i])) {
+ op->gprintf(op,"%c",p->string[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->string[i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUcrBg_allocate(
+ icmBase *pp
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ icc *icp = p->icp;
+
+ if (p->UCRcount != p->UCR_count) {
+ if (ovr_mul(p->UCRcount, sizeof(double))) {
+ sprintf(icp->err,"icmUcrBg_allocate: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->UCRcurve != NULL)
+ icp->al->free(icp->al, p->UCRcurve);
+ if ((p->UCRcurve = (double *) icp->al->calloc(icp->al, p->UCRcount, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmUcrBg_allocate: malloc() of UCR curve data failed");
+ return icp->errc = 2;
+ }
+ p->UCR_count = p->UCRcount;
+ }
+ if (p->BGcount != p->BG_count) {
+ if (ovr_mul(p->BGcount, sizeof(double))) {
+ sprintf(icp->err,"icmUcrBg_allocate: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->BGcurve != NULL)
+ icp->al->free(icp->al, p->BGcurve);
+ if ((p->BGcurve = (double *) icp->al->calloc(icp->al, p->BGcount, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmUcrBg_allocate: malloc() of BG curve data failed");
+ return icp->errc = 2;
+ }
+ p->BG_count = p->BGcount;
+ }
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(char))) {
+ sprintf(icp->err,"icmUcrBg_allocate: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->string != NULL)
+ icp->al->free(icp->al, p->string);
+ if ((p->string = (char *) icp->al->calloc(icp->al, p->size, sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmUcrBg_allocate: malloc() of string data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUcrBg_delete(
+ icmBase *pp
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ icc *icp = p->icp;
+
+ if (p->UCRcurve != NULL)
+ icp->al->free(icp->al, p->UCRcurve);
+ if (p->BGcurve != NULL)
+ icp->al->free(icp->al, p->BGcurve);
+ if (p->string != NULL)
+ icp->al->free(icp->al, p->string);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUcrBg(
+ icc *icp
+) {
+ icmUcrBg *p;
+ if ((p = (icmUcrBg *) icp->al->calloc(icp->al,1,sizeof(icmUcrBg))) == NULL)
+ return NULL;
+ p->ttype = icSigUcrBgType;
+ p->refcount = 1;
+ p->get_size = icmUcrBg_get_size;
+ p->read = icmUcrBg_read;
+ p->write = icmUcrBg_write;
+ p->dump = icmUcrBg_dump;
+ p->allocate = icmUcrBg_allocate;
+ p->del = icmUcrBg_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* VideoCardGamma (ColorSync 2.5 specific - c/o Neil Okamoto) */
+/* 'vcgt' */
+
+static unsigned int icmVideoCardGamma_get_size(
+ icmBase *pp
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ unsigned int len = 0;
+
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for gamma type */
+
+ /* compute size of remainder */
+ if (p->tagType == icmVideoCardGammaTableType) {
+ len = sat_add(len, 2); /* 2 bytes for channels */
+ len = sat_add(len, 2); /* 2 for entry count */
+ len = sat_add(len, 2); /* 2 for entry size */
+ len = sat_add(len, sat_mul3(p->u.table.channels, /* compute table size */
+ p->u.table.entryCount, p->u.table.entrySize));
+ }
+ else if (p->tagType == icmVideoCardGammaFormulaType) {
+ len = sat_add(len, 12); /* 4 bytes each for red gamma, min, & max */
+ len = sat_add(len, 12); /* 4 bytes each for green gamma, min & max */
+ len = sat_add(len, 12); /* 4 bytes each for blue gamma, min & max */
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmVideoCardGamma_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ icc *icp = p->icp;
+ int rv, c;
+ char *bp, *buf;
+ ORD8 *pchar;
+ ORD16 *pshort;
+
+ if (len < 18) {
+ sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmVideoCardGamma_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmVideoCardGamma_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmVideoCardGamma_read: Wrong tag type for icmVideoCardGamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read gamma format (eg. table or formula) from the buffer */
+ p->tagType = (icmVideoCardGammaTagType)read_UInt32Number(bp+8);
+
+ /* Read remaining gamma data based on format */
+ if (p->tagType == icmVideoCardGammaTableType) {
+ p->u.table.channels = read_UInt16Number(bp+12);
+ p->u.table.entryCount = read_UInt16Number(bp+14);
+ p->u.table.entrySize = read_UInt16Number(bp+16);
+ if ((len-18) < sat_mul3(p->u.table.channels, p->u.table.entryCount,
+ p->u.table.entrySize)) {
+ sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+ if ((rv = pp->allocate(pp)) != 0) { /* make space for table */
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ /* ~~~~ This should be a table of doubles like the rest of icclib ! ~~~~ */
+ pchar = (ORD8 *)p->u.table.data;
+ pshort = (ORD16 *)p->u.table.data;
+ for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) {
+ switch (p->u.table.entrySize) {
+ case 1:
+ *pchar++ = read_UInt8Number(bp);
+ bp++;
+ break;
+ case 2:
+ *pshort++ = read_UInt16Number(bp);
+ bp+=2;
+ break;
+ default:
+ sprintf(icp->err,"icmVideoCardGamma_read: unsupported table entry size");
+ pp->del(pp);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+ } else if (p->tagType == icmVideoCardGammaFormulaType) {
+ if (len < 48) {
+ sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+ p->u.table.channels = 3; /* Always 3 for formula */
+ p->u.formula.redGamma = read_S15Fixed16Number(bp+12);
+ p->u.formula.redMin = read_S15Fixed16Number(bp+16);
+ p->u.formula.redMax = read_S15Fixed16Number(bp+20);
+ p->u.formula.greenGamma = read_S15Fixed16Number(bp+24);
+ p->u.formula.greenMin = read_S15Fixed16Number(bp+28);
+ p->u.formula.greenMax = read_S15Fixed16Number(bp+32);
+ p->u.formula.blueGamma = read_S15Fixed16Number(bp+36);
+ p->u.formula.blueMin = read_S15Fixed16Number(bp+40);
+ p->u.formula.blueMax = read_S15Fixed16Number(bp+44);
+ } else {
+ sprintf(icp->err,"icmVideoCardGammaTable_read: Unknown gamma format for icmVideoCardGamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmVideoCardGamma_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0, c;
+ ORD8 *pchar;
+ ORD16 *pshort;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmViewingConditions_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmViewingConditions_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write gamma format (eg. table of formula) */
+ if ((rv = write_UInt32Number(p->tagType,bp+8)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write remaining gamma data based on format */
+ if (p->tagType == icmVideoCardGammaTableType) {
+ if ((rv = write_UInt16Number(p->u.table.channels,bp+12)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt16Number(p->u.table.entryCount,bp+14)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt16Number(p->u.table.entrySize,bp+16)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ pchar = (ORD8 *)p->u.table.data;
+ pshort = (ORD16 *)p->u.table.data;
+ for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) {
+ switch (p->u.table.entrySize) {
+ case 1:
+ write_UInt8Number(*pchar++,bp);
+ bp++;
+ break;
+ case 2:
+ write_UInt16Number(*pshort++,bp);
+ bp+=2;
+ break;
+ default:
+ sprintf(icp->err,"icmVideoCardGamma_write: unsupported table entry size");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+ } else if (p->tagType == icmVideoCardGammaFormulaType) {
+ if ((rv = write_S15Fixed16Number(p->u.formula.redGamma,bp+12)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.redMin,bp+16)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.redMax,bp+20)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.greenGamma,bp+24)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.greenMin,bp+28)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.greenMax,bp+32)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.blueGamma,bp+36)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.blueMin,bp+40)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.blueMax,bp+44)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ } else {
+ sprintf(icp->err,"icmVideoCardGammaTable_write: Unknown gamma format for icmVideoCardGamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmVideoCardGamma_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ int c,i;
+
+ if (verb <= 0)
+ return;
+
+ if (p->tagType == icmVideoCardGammaTableType) {
+ op->gprintf(op,"VideoCardGammaTable:\n");
+ op->gprintf(op," channels = %d\n", p->u.table.channels);
+ op->gprintf(op," entries = %d\n", p->u.table.entryCount);
+ op->gprintf(op," entrysize = %d\n", p->u.table.entrySize);
+ if (verb >= 2) {
+ /* dump array contents also */
+ for (c=0; c<p->u.table.channels; c++) {
+ op->gprintf(op," channel #%d\n",c);
+ for (i=0; i<p->u.table.entryCount; i++) {
+ if (p->u.table.entrySize == 1) {
+ op->gprintf(op," %d: %d\n",i,((ORD8 *)p->u.table.data)[c*p->u.table.entryCount+i]);
+ }
+ else if (p->u.table.entrySize == 2) {
+ op->gprintf(op," %d: %d\n",i,((ORD16 *)p->u.table.data)[c*p->u.table.entryCount+i]);
+ }
+ }
+ }
+ }
+ } else if (p->tagType == icmVideoCardGammaFormulaType) {
+ op->gprintf(op,"VideoCardGammaFormula:\n");
+ op->gprintf(op," red gamma = %f\n", p->u.formula.redGamma);
+ op->gprintf(op," red min = %f\n", p->u.formula.redMin);
+ op->gprintf(op," red max = %f\n", p->u.formula.redMax);
+ op->gprintf(op," green gamma = %f\n", p->u.formula.greenGamma);
+ op->gprintf(op," green min = %f\n", p->u.formula.greenMin);
+ op->gprintf(op," green max = %f\n", p->u.formula.greenMax);
+ op->gprintf(op," blue gamma = %f\n", p->u.formula.blueGamma);
+ op->gprintf(op," blue min = %f\n", p->u.formula.blueMin);
+ op->gprintf(op," blue max = %f\n", p->u.formula.blueMax);
+ } else {
+ op->gprintf(op," Unknown tag format\n");
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmVideoCardGamma_allocate(
+ icmBase *pp
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ icc *icp = p->icp;
+ unsigned int size;
+
+ /* note: allocation is only relevant for table type
+ * and in that case the channels, entryCount, and entrySize
+ * fields must all be set prior to getting here
+ */
+
+ if (p->tagType == icmVideoCardGammaTableType) {
+ size = sat_mul(p->u.table.channels, p->u.table.entryCount);
+ switch (p->u.table.entrySize) {
+ case 1:
+ size = sat_mul(size, sizeof(ORD8));
+ break;
+ case 2:
+ size = sat_mul(size, sizeof(unsigned short));
+ break;
+ default:
+ sprintf(icp->err,"icmVideoCardGamma_alloc: unsupported table entry size");
+ return icp->errc = 1;
+ }
+ if (size == UINT_MAX) {
+ sprintf(icp->err,"icmVideoCardGamma_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->u.table.data != NULL)
+ icp->al->free(icp->al, p->u.table.data);
+ if ((p->u.table.data = (void*) icp->al->malloc(icp->al, size)) == NULL) {
+ sprintf(icp->err,"icmVideoCardGamma_alloc: malloc() of table data failed");
+ return icp->errc = 2;
+ }
+ }
+
+ return 0;
+}
+
+/* Read a value */
+static double icmVideoCardGamma_lookup(
+ icmVideoCardGamma *p,
+ int chan, /* Channel, 0, 1 or 2 */
+ double iv /* Input value 0.0 - 1.0 */
+) {
+ double ov = 0.0;
+
+ if (chan < 0 || chan > (p->u.table.channels-1)
+ || iv < 0.0 || iv > 1.0)
+ return iv;
+
+ if (p->tagType == icmVideoCardGammaTableType && p->u.table.entryCount == 0) {
+ /* Deal with siliness */
+ ov = iv;
+ } else if (p->tagType == icmVideoCardGammaTableType) {
+ /* Use linear interpolation */
+ unsigned int ix;
+ double val0, val1, w;
+ double inputEnt_1 = (double)(p->u.table.entryCount-1);
+
+ val0 = iv * inputEnt_1;
+ if (val0 < 0.0)
+ val0 = 0.0;
+ else if (val0 > inputEnt_1)
+ val0 = inputEnt_1;
+ ix = (unsigned int)floor(val0); /* Coordinate */
+ if (ix > (p->u.table.entryCount-2))
+ ix = (p->u.table.entryCount-2);
+ w = val0 - (double)ix; /* weight */
+ if (p->u.table.entrySize == 1) {
+ val0 = ((ORD8 *)p->u.table.data)[chan * p->u.table.entryCount + ix]/255.0;
+ val1 = ((ORD8 *)p->u.table.data)[chan * p->u.table.entryCount + ix + 1]/255.0;
+ } else if (p->u.table.entrySize == 2) {
+ val0 = ((ORD16 *)p->u.table.data)[chan * p->u.table.entryCount + ix]/65535.0;
+ val1 = ((ORD16 *)p->u.table.data)[chan * p->u.table.entryCount + ix + 1]/65535.0;
+ } else {
+ val0 = val1 = iv;
+ }
+ ov = val0 + w * (val1 - val0);
+
+ } else if (p->tagType == icmVideoCardGammaFormulaType) {
+ double min, max, gam;
+
+ if (iv == 0) {
+ min = p->u.formula.redMin;
+ max = p->u.formula.redMax;
+ gam = p->u.formula.redGamma;
+ } else if (iv == 1) {
+ min = p->u.formula.greenMin;
+ max = p->u.formula.greenMax;
+ gam = p->u.formula.greenGamma;
+ } else {
+ min = p->u.formula.blueMin;
+ max = p->u.formula.blueMax;
+ gam = p->u.formula.blueGamma;
+ }
+
+ /* The Apple OSX doco confirms this is the formula */
+ ov = min + (max - min) * pow(iv, gam);
+ }
+ return ov;
+}
+
+/* Free all storage in the object */
+static void icmVideoCardGamma_delete(
+ icmBase *pp
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ icc *icp = p->icp;
+
+ if (p->tagType == icmVideoCardGammaTableType && p->u.table.data != NULL)
+ icp->al->free(icp->al, p->u.table.data);
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmVideoCardGamma(
+ icc *icp
+) {
+ icmVideoCardGamma *p;
+ if ((p = (icmVideoCardGamma *) icp->al->calloc(icp->al,1,sizeof(icmVideoCardGamma))) == NULL)
+ return NULL;
+ p->ttype = icSigVideoCardGammaType;
+ p->refcount = 1;
+ p->get_size = icmVideoCardGamma_get_size;
+ p->read = icmVideoCardGamma_read;
+ p->write = icmVideoCardGamma_write;
+ p->lookup = icmVideoCardGamma_lookup;
+ p->dump = icmVideoCardGamma_dump;
+ p->allocate = icmVideoCardGamma_allocate;
+ p->del = icmVideoCardGamma_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* ViewingConditions */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmViewingConditions_get_size(
+ icmBase *pp
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 12); /* 12 for XYZ of illuminant */
+ len = sat_add(len, 12); /* 12 for XYZ of surround */
+ len = sat_add(len, 4); /* 4 for illuminant type */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmViewingConditions_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmViewingConditions *p = (icmViewingConditions *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf;
+
+ if (len < 36) {
+ sprintf(icp->err,"icmViewingConditions_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmViewingConditions_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmViewingConditions_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmViewingConditions_read: Wrong tag type for icmViewingConditions");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read the XYZ values for the illuminant */
+ if ((rv = read_XYZNumber(&p->illuminant, bp+8)) != 0) {
+ sprintf(icp->err,"icmViewingConditions: read_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Read the XYZ values for the surround */
+ if ((rv = read_XYZNumber(&p->surround, bp+20)) != 0) {
+ sprintf(icp->err,"icmViewingConditions: read_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Read the encoded standard illuminant */
+ p->stdIlluminant = (icIlluminant)read_SInt32Number(bp + 32);
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmViewingConditions_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmViewingConditions *p = (icmViewingConditions *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmViewingConditions_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmViewingConditions_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmViewingConditions_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write the XYZ values for the illuminant */
+ if ((rv = write_XYZNumber(&p->illuminant, bp+8)) != 0) {
+ sprintf(icp->err,"icmViewingConditions: write_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the XYZ values for the surround */
+ if ((rv = write_XYZNumber(&p->surround, bp+20)) != 0) {
+ sprintf(icp->err,"icmViewingConditions: write_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the encoded standard illuminant */
+ if ((rv = write_SInt32Number((int)p->stdIlluminant, bp + 32)) != 0) {
+ sprintf(icp->err,"icmViewingConditionsa_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmViewingConditions_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmViewingConditions *p = (icmViewingConditions *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Viewing Conditions:\n");
+ op->gprintf(op," XYZ value of illuminant in cd/m^2 = %s\n", string_XYZNumber(&p->illuminant));
+ op->gprintf(op," XYZ value of surround in cd/m^2 = %s\n", string_XYZNumber(&p->surround));
+ op->gprintf(op," Illuminant type = %s\n", string_Illuminant(p->stdIlluminant));
+}
+
+/* Allocate variable sized data elements */
+static int icmViewingConditions_allocate(
+ icmBase *pp
+) {
+ /* Nothing to do */
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmViewingConditions_delete(
+ icmBase *pp
+) {
+ icmViewingConditions *p = (icmViewingConditions *)pp;
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmViewingConditions(
+ icc *icp
+) {
+ icmViewingConditions *p;
+ if ((p = (icmViewingConditions *) icp->al->calloc(icp->al,1,sizeof(icmViewingConditions))) == NULL)
+ return NULL;
+ p->ttype = icSigViewingConditionsType;
+ p->refcount = 1;
+ p->get_size = icmViewingConditions_get_size;
+ p->read = icmViewingConditions_read;
+ p->write = icmViewingConditions_write;
+ p->dump = icmViewingConditions_dump;
+ p->allocate = icmViewingConditions_allocate;
+ p->del = icmViewingConditions_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmCrdInfo object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmCrdInfo_get_size(
+ icmBase *pp
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ unsigned int len = 0, t;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addadd(len, 4, p->ppsize); /* Postscript product name */
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ len = sat_addadd(len, 4, p->crdsize[t]); /* crd names */
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmCrdInfo_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ icc *icp = p->icp;
+ unsigned int t;
+ int rv;
+ char *bp, *buf, *end;
+
+ if (len < 28) {
+ sprintf(icp->err,"icmCrdInfo_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmCrdInfo_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmCrdInfo_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmCrdInfo_read: Wrong tag type for icmCrdInfo");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp = bp + 8;
+
+ /* Postscript product name */
+ if (bp > end || 4 > (end - bp)) {
+ sprintf(icp->err,"icmCrdInfo_read: Data too short to read Postscript product name");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->ppsize = read_UInt32Number(bp);
+ bp += 4;
+ if (p->ppsize > 0) {
+ if (p->ppsize > (end - bp)) {
+ sprintf(icp->err,"icmCrdInfo_read: Data to short to read Postscript product string");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,p->ppsize)) == 1) {
+ sprintf(icp->err,"icmCrdInfo_read: Postscript product name is not terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ memmove((void *)p->ppname, (void *)bp, p->ppsize);
+ bp += p->ppsize;
+ }
+
+ /* CRD names for the four rendering intents */
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ if (bp > end || 4 > (end - bp)) {
+ sprintf(icp->err,"icmCrdInfo_read: Data too short to read CRD%d name",t);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->crdsize[t] = read_UInt32Number(bp);
+ bp += 4;
+ if (p->crdsize[t] > 0) {
+ if (p->crdsize[t] > (end - bp)) {
+ sprintf(icp->err,"icmCrdInfo_read: Data to short to read CRD%d string",t);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,p->crdsize[t])) == 1) {
+ sprintf(icp->err,"icmCrdInfo_read: CRD%d name is not terminated",t);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ memmove((void *)p->crdname[t], (void *)bp, p->crdsize[t]);
+ bp += p->crdsize[t];
+ }
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmCrdInfo_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ icc *icp = p->icp;
+ unsigned int t;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmCrdInfo_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmCrdInfo_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmCrdInfo_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp = bp + 8;
+
+ /* Postscript product name */
+ if ((rv = write_UInt32Number(p->ppsize,bp)) != 0) {
+ sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if (p->ppsize > 0) {
+ if ((rv = check_null_string(p->ppname,p->ppsize)) == 1) {
+ sprintf(icp->err,"icmCrdInfo_write: Postscript product name is not terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ memmove((void *)bp, (void *)p->ppname, p->ppsize);
+ bp += p->ppsize;
+ }
+
+ /* CRD names for the four rendering intents */
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ if ((rv = write_UInt32Number(p->crdsize[t],bp)) != 0) {
+ sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if (p->ppsize > 0) {
+ if ((rv = check_null_string(p->crdname[t],p->crdsize[t])) == 1) {
+ sprintf(icp->err,"icmCrdInfo_write: CRD%d name is not terminated",t);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ memmove((void *)bp, (void *)p->crdname[t], p->crdsize[t]);
+ bp += p->crdsize[t];
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmCrdInfo_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmCrdInfo_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ unsigned int i, r, c, size, t;
+
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"PostScript Product name and CRD names:\n");
+
+ op->gprintf(op," Product name:\n");
+ op->gprintf(op," No. chars = %lu\n",p->ppsize);
+
+ size = p->ppsize > 0 ? p->ppsize-1 : 0;
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 73) {
+ if (isprint(p->ppname[i])) {
+ op->gprintf(op,"%c",p->ppname[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->ppname[i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ op->gprintf(op," CRD%ld name:\n",t);
+ op->gprintf(op," No. chars = %lu\n",p->crdsize[t]);
+
+ size = p->crdsize[t] > 0 ? p->crdsize[t]-1 : 0;
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 73) {
+ if (isprint(p->crdname[t][i])) {
+ op->gprintf(op,"%c",p->crdname[t][i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->crdname[t][i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmCrdInfo_allocate(
+ icmBase *pp
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ icc *icp = p->icp;
+ unsigned int t;
+
+ if (p->ppsize != p->_ppsize) {
+ if (ovr_mul(p->ppsize, sizeof(char))) {
+ sprintf(icp->err,"icmCrdInfo_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->ppname != NULL)
+ icp->al->free(icp->al, p->ppname);
+ if ((p->ppname = (char *) icp->al->calloc(icp->al, p->ppsize, sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmCrdInfo_alloc: malloc() of string data failed");
+ return icp->errc = 2;
+ }
+ p->_ppsize = p->ppsize;
+ }
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ if (p->crdsize[t] != p->_crdsize[t]) {
+ if (ovr_mul(p->crdsize[t], sizeof(char))) {
+ sprintf(icp->err,"icmCrdInfo_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->crdname[t] != NULL)
+ icp->al->free(icp->al, p->crdname[t]);
+ if ((p->crdname[t] = (char *) icp->al->calloc(icp->al, p->crdsize[t], sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmCrdInfo_alloc: malloc() of CRD%d name string failed",t);
+ return icp->errc = 2;
+ }
+ p->_crdsize[t] = p->crdsize[t];
+ }
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmCrdInfo_delete(
+ icmBase *pp
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ icc *icp = p->icp;
+ unsigned int t;
+
+ if (p->ppname != NULL)
+ icp->al->free(icp->al, p->ppname);
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ if (p->crdname[t] != NULL)
+ icp->al->free(icp->al, p->crdname[t]);
+ }
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmCrdInfo(
+ icc *icp
+) {
+ icmCrdInfo *p;
+ if ((p = (icmCrdInfo *) icp->al->calloc(icp->al,1,sizeof(icmCrdInfo))) == NULL)
+ return NULL;
+ p->ttype = icSigCrdInfoType;
+ p->refcount = 1;
+ p->get_size = icmCrdInfo_get_size;
+ p->read = icmCrdInfo_read;
+ p->write = icmCrdInfo_write;
+ p->dump = icmCrdInfo_dump;
+ p->allocate = icmCrdInfo_allocate;
+ p->del = icmCrdInfo_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ========================================================== */
+/* icmHeader object */
+/* ========================================================== */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmHeader_get_size(
+ icmHeader *p
+) {
+ return 128; /* By definition */
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmHeader_read(
+ icmHeader *p,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icc *icp = p->icp;
+ char *buf;
+ unsigned int tt;
+ int rv = 0;
+
+ if (len != 128) {
+ sprintf(icp->err,"icmHeader_read: Length expected to be 128");
+ return icp->errc = 1;
+ }
+
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmHeader_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmHeader_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Check that the magic number is right */
+ tt = read_SInt32Number(buf+36);
+ if (tt != icMagicNumber) { /* Check magic number */
+ sprintf(icp->err,"icmHeader_read: wrong magic number 0x%x",tt);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Fill in the in-memory structure */
+ p->size = read_UInt32Number(buf + 0); /* Profile size in bytes */
+ if (p->size < (128 + 4)) {
+ sprintf(icp->err,"icmHeader_read: file size %d too small to be legal",p->size);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->cmmId = read_SInt32Number(buf + 4); /* CMM for profile */
+ tt = read_UInt8Number(buf + 8); /* Raw major version number */
+ p->majv = (tt >> 4) * 10 + (tt & 0xf); /* Integer major version number */
+ icp->ver = p->majv > 3 ? 1 : 0; /* Set major version flag in icc */
+ tt = read_UInt8Number(buf + 9); /* Raw minor/bug fix version numbers */
+ p->minv = (tt >> 4); /* Integer minor version number */
+ p->bfv = (tt & 0xf); /* Integer bug fix version number */
+ p->deviceClass = (icProfileClassSignature)
+ read_SInt32Number(buf + 12); /* Type of profile */
+ p->colorSpace = (icColorSpaceSignature)
+ read_SInt32Number(buf + 16); /* Color space of data */
+ p->pcs = (icColorSpaceSignature)
+ read_SInt32Number(buf + 20); /* PCS: XYZ or Lab */
+ if ((rv = read_DateTimeNumber(&p->date, buf + 24)) != 0) { /* Creation Date */
+ sprintf(icp->err,"icmHeader_read: read_DateTimeNumber corrupted");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ p->platform = (icPlatformSignature)
+ read_SInt32Number(buf + 40); /* Primary platform */
+ p->flags = read_UInt32Number(buf + 44); /* Various bits */
+ p->manufacturer = read_SInt32Number(buf + 48); /* Dev manufacturer */
+ p->model = read_SInt32Number(buf + 52); /* Dev model */
+ read_UInt64Number(&p->attributes, buf + 56); /* Device attributes */
+ p->renderingIntent = (icRenderingIntent)
+ read_SInt32Number(buf + 64); /* Rendering intent */
+ if ((rv = read_XYZNumber(&p->illuminant, buf + 68)) != 0) { /* Profile illuminant */
+ sprintf(icp->err,"icmHeader_read: read_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ p->creator = read_SInt32Number(buf + 80); /* Profile creator */
+
+ for (tt = 0; tt < 16; tt++)
+ p->id[tt] = icp->ver ? read_UInt8Number(buf + 84 + tt) : 0; /* Profile ID */
+
+ icp->al->free(icp->al, buf);
+
+#ifndef ENABLE_V4
+ if (icp->ver) {
+ sprintf(icp->err,"icmHeader_read: ICC V4 not supported!");
+ return icp->errc = 1;
+ }
+#endif
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmHeader_write(
+ icmHeader *p,
+ unsigned int of, /* File offset to write from */
+ int doid /* Flag, nz = writing to compute ID */
+) {
+ icc *icp = p->icp;
+ char *buf; /* Buffer to write from */
+ unsigned int len;
+ unsigned int tt;
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size(p)) == UINT_MAX) {
+ sprintf(icp->err,"icmHeader_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->calloc(icp->al,1,len)) == NULL) { /* Zero it - some CMS are fussy */
+ sprintf(icp->err,"icmHeader_write calloc() failed");
+ return icp->errc = 2;
+ }
+
+ /* Fill in the write buffer */
+ if ((rv = write_UInt32Number(p->size, buf + 0)) != 0) { /* Profile size in bytes */
+ sprintf(icp->err,"icmHeader_write: profile size");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ if ((rv = write_SInt32Number(p->cmmId, buf + 4)) != 0) { /* CMM for profile */
+ sprintf(icp->err,"icmHeader_write: cmmId");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if (p->majv < 0 || p->majv > 99 /* Sanity check version numbers */
+ || p->minv < 0 || p->minv > 9
+ || p->bfv < 0 || p->bfv > 9) {
+ sprintf(icp->err,"icmHeader_write: version number");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ tt = ((p->majv/10) << 4) + (p->majv % 10);
+ if ((rv = write_UInt8Number(tt, buf + 8)) != 0) { /* Raw major version number */
+ sprintf(icp->err,"icmHeader_write: Uint8Number major version");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ tt = (p->minv << 4) + p->bfv;
+ if ((rv = write_UInt8Number(tt, buf + 9)) != 0) { /* Raw minor/bug fix version numbers */
+ sprintf(icp->err,"icmHeader_write: Uint8Number minor/bug fix");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number((int)p->deviceClass, buf + 12)) != 0) { /* Type of profile */
+ sprintf(icp->err,"icmHeader_write: SInt32Number deviceClass");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number((int)p->colorSpace, buf + 16)) != 0) { /* Color space of data */
+ sprintf(icp->err,"icmHeader_write: SInt32Number data color space");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number((int)p->pcs, buf + 20)) != 0) { /* PCS: XYZ or Lab */
+ sprintf(icp->err,"icmHeader_write: SInt32Number PCS");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_DateTimeNumber(&p->date, buf + 24)) != 0) { /* Creation Date */
+ sprintf(icp->err,"icmHeader_write: DateTimeNumber creation");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number(icMagicNumber, buf+36)) != 0) { /* Magic number */
+ sprintf(icp->err,"icmHeader_write: SInt32Number magic");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number((int)p->platform, buf + 40)) != 0) { /* Primary platform */
+ sprintf(icp->err,"icmHeader_write: SInt32Number platform");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt32Number(doid ? 0 : p->flags, buf + 44)) != 0) { /* Various flag bits */
+ sprintf(icp->err,"icmHeader_write: UInt32Number flags");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number(p->manufacturer, buf + 48)) != 0) { /* Dev manufacturer */
+ sprintf(icp->err,"icmHeader_write: SInt32Number manufaturer");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((write_SInt32Number(p->model, buf + 52)) != 0) { /* Dev model */
+ sprintf(icp->err,"icmHeader_write: SInt32Number model");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt64Number(&p->attributes, buf + 56)) != 0) { /* Device attributes */
+ sprintf(icp->err,"icmHeader_write: UInt64Number attributes");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number(doid ? 0 : (int)p->renderingIntent, buf + 64)) != 0) { /* Rendering intent */
+ sprintf(icp->err,"icmHeader_write: SInt32Number rendering intent");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_XYZNumber(&p->illuminant, buf + 68)) != 0) { /* Profile illuminant */
+ sprintf(icp->err,"icmHeader_write: XYZNumber illuminant");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number(p->creator, buf + 80)) != 0) { /* Profile creator */
+ sprintf(icp->err,"icmHeader_write: SInt32Number creator");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if (doid == 0 && icp->ver) { /* ID is V4.0+ feature */
+ for (tt = 0; tt < 16; tt++) {
+ if ((rv = write_UInt8Number(p->id[tt], buf + 84 + tt)) != 0) { /* Profile ID */
+ sprintf(icp->err,"icmHeader_write: UInt8Number creator");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmHeader_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+
+ icp->al->free(icp->al, buf);
+ return rv;
+}
+
+static void icmHeader_dump(
+ icmHeader *p,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ int i;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Header:\n");
+ op->gprintf(op," size = %d bytes\n",p->size);
+ op->gprintf(op," CMM = %s\n",tag2str(p->cmmId));
+ op->gprintf(op," Version = %d.%d.%d\n",p->majv, p->minv, p->bfv);
+ op->gprintf(op," Device Class = %s\n", string_ProfileClassSignature(p->deviceClass));
+ op->gprintf(op," Color Space = %s\n", string_ColorSpaceSignature(p->colorSpace));
+ op->gprintf(op," Conn. Space = %s\n", string_ColorSpaceSignature(p->pcs));
+ op->gprintf(op," Date, Time = %s\n", string_DateTimeNumber(&p->date));
+ op->gprintf(op," Platform = %s\n", string_PlatformSignature(p->platform));
+ op->gprintf(op," Flags = %s\n", string_ProfileHeaderFlags(p->flags));
+ op->gprintf(op," Dev. Mnfctr. = %s\n", tag2str(p->manufacturer)); /* ~~~ */
+ op->gprintf(op," Dev. Model = %s\n", tag2str(p->model)); /* ~~~ */
+ op->gprintf(op," Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l));
+ op->gprintf(op," Rndrng Intnt = %s\n", string_RenderingIntent(p->renderingIntent));
+ op->gprintf(op," Illuminant = %s\n", string_XYZNumber_and_Lab(&p->illuminant));
+ op->gprintf(op," Creator = %s\n", tag2str(p->creator)); /* ~~~ */
+ if (p->icp->ver) { /* V4.0+ feature */
+ for (i = 0; i < 16; i++) { /* Check if ID has been set */
+ if (p->id[i] != 0)
+ break;
+ }
+ if (i < 16)
+ op->gprintf(op," ID = %02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X%02X%02X%02X%02X\n",
+ p->id[0], p->id[1], p->id[2], p->id[3], p->id[4], p->id[5], p->id[6], p->id[7],
+ p->id[8], p->id[9], p->id[10], p->id[11], p->id[12], p->id[13], p->id[14], p->id[15]);
+ else
+ op->gprintf(op," ID = <Not set>\n");
+ }
+ op->gprintf(op,"\n");
+}
+
+static void icmHeader_delete(
+ icmHeader *p
+) {
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmHeader *new_icmHeader(
+ icc *icp
+) {
+ icmHeader *p;
+ if ((p = (icmHeader *) icp->al->calloc(icp->al,1,sizeof(icmHeader))) == NULL)
+ return NULL;
+ p->icp = icp;
+ p->get_size = icmHeader_get_size;
+ p->read = icmHeader_read;
+ p->write = icmHeader_write;
+ p->dump = icmHeader_dump;
+ p->del = icmHeader_delete;
+
+ return p;
+}
+
+/* ---------------------------------------------------------- */
+/* Type vector table. Match the Tag type against the object creator */
+static struct {
+ icTagTypeSignature ttype; /* The tag type signature */
+ icmBase * (*new_obj)(icc *icp);
+} typetable[] = {
+ {icSigColorantTableType, new_icmColorantTable},
+ {icmSigAltColorantTableType, new_icmColorantTable},
+ {icSigCrdInfoType, new_icmCrdInfo},
+ {icSigCurveType, new_icmCurve},
+ {icSigDataType, new_icmData},
+ {icSigDateTimeType, new_icmDateTimeNumber},
+ {icSigLut16Type, new_icmLut},
+ {icSigLut8Type, new_icmLut},
+ {icSigMeasurementType, new_icmMeasurement},
+ {icSigNamedColorType, new_icmNamedColor},
+ {icSigNamedColor2Type, new_icmNamedColor},
+ {icSigProfileSequenceDescType, new_icmProfileSequenceDesc},
+ {icSigS15Fixed16ArrayType, new_icmS15Fixed16Array},
+ {icSigScreeningType, new_icmScreening},
+ {icSigSignatureType, new_icmSignature},
+ {icSigTextDescriptionType, new_icmTextDescription},
+ {icSigTextType, new_icmText},
+ {icSigU16Fixed16ArrayType, new_icmU16Fixed16Array},
+ {icSigUcrBgType, new_icmUcrBg},
+ {icSigVideoCardGammaType, new_icmVideoCardGamma},
+ {icSigUInt16ArrayType, new_icmUInt16Array},
+ {icSigUInt32ArrayType, new_icmUInt32Array},
+ {icSigUInt64ArrayType, new_icmUInt64Array},
+ {icSigUInt8ArrayType, new_icmUInt8Array},
+ {icSigViewingConditionsType, new_icmViewingConditions},
+ {icSigXYZArrayType, new_icmXYZArray},
+ {icMaxEnumType, NULL}
+};
+
+/* Table that lists the legal Types for each Tag Signature */
+static struct {
+ icTagSignature sig;
+ icTagTypeSignature ttypes[4]; /* Arbitrary max of 4 */
+} sigtypetable[] = {
+ {icSigAToB0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigAToB1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigAToB2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigBlueColorantTag, {icSigXYZType,icMaxEnumType}},
+ {icSigBlueTRCTag, {icSigCurveType,icMaxEnumType}},
+ {icSigBToA0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigBToA1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigBToA2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigCalibrationDateTimeTag, {icSigDateTimeType,icMaxEnumType}},
+ {icSigCharTargetTag, {icSigTextType,icMaxEnumType}},
+ {icSigColorantTableTag, {icSigColorantTableType,icmSigAltColorantTableType,
+ icMaxEnumType}},
+ {icSigColorantTableOutTag, {icSigColorantTableType,icmSigAltColorantTableType,
+ icMaxEnumType}},
+ {icSigCopyrightTag, {icSigTextType,icMaxEnumType}},
+ {icSigCrdInfoTag, {icSigCrdInfoType,icMaxEnumType}},
+ {icSigDeviceMfgDescTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigDeviceModelDescTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigGamutTag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigGrayTRCTag, {icSigCurveType,icMaxEnumType}},
+ {icSigGreenColorantTag, {icSigXYZType,icMaxEnumType}},
+ {icSigGreenTRCTag, {icSigCurveType,icMaxEnumType}},
+ {icSigLuminanceTag, {icSigXYZType,icMaxEnumType}},
+ {icSigMeasurementTag, {icSigMeasurementType,icMaxEnumType}},
+ {icSigMediaBlackPointTag, {icSigXYZType,icMaxEnumType}},
+ {icSigMediaWhitePointTag, {icSigXYZType,icMaxEnumType}},
+ {icSigNamedColorTag, {icSigNamedColorType,icMaxEnumType}},
+ {icSigNamedColor2Tag, {icSigNamedColor2Type,icMaxEnumType}},
+ {icSigPreview0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigPreview1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigPreview2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigProfileDescriptionTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigProfileSequenceDescTag, {icSigProfileSequenceDescType,icMaxEnumType}},
+ {icSigPs2CRD0Tag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2CRD1Tag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2CRD2Tag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2CRD3Tag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2CSATag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2RenderingIntentTag, {icSigDataType,icMaxEnumType}},
+ {icSigRedColorantTag, {icSigXYZType,icMaxEnumType}},
+ {icSigRedTRCTag, {icSigCurveType,icMaxEnumType}},
+ {icSigScreeningDescTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigScreeningTag, {icSigScreeningType,icMaxEnumType}},
+ {icSigTechnologyTag, {icSigSignatureType,icMaxEnumType}},
+ {icSigUcrBgTag, {icSigUcrBgType,icMaxEnumType}},
+ {icSigVideoCardGammaTag, {icSigVideoCardGammaType,icMaxEnumType}},
+ {icSigViewingCondDescTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigViewingConditionsTag, {icSigViewingConditionsType,icMaxEnumType}},
+ {icMaxEnumTag, {icMaxEnumType}}
+};
+
+/* Fake color tag for specifying PCS */
+#define icSigPCSData ((icColorSpaceSignature) 0x50435320L)
+
+/* Table that lists the required tags for various profiles */
+static struct {
+ icProfileClassSignature sig; /* Profile signature */
+ int chans; /* Data Color channels, -ve for match but try next, */
+ /* -100 for ignore, -200 for ignore and try next */
+ icColorSpaceSignature colsig; /* Data Color space signature, icMaxEnumData for ignore, */
+ /* icSigPCSData for XYZ of Lab */
+ icColorSpaceSignature pcssig; /* PCS Color space signature, icMaxEnumData for ignore, */
+ /* icSigPCSData for XYZ or Lab */
+ icTagSignature tags[12]; /* Arbitrary max of 12 */
+} tagchecktable[] = {
+ {icSigInputClass, -1, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigGrayTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigInputClass, -3, icMaxEnumData, icSigXYZData,
+ {icSigProfileDescriptionTag,
+ icSigRedColorantTag,
+ icSigGreenColorantTag,
+ icSigBlueColorantTag,
+ icSigRedTRCTag,
+ icSigGreenTRCTag,
+ icSigBlueTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigInputClass, -100, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigDisplayClass, -1, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigGrayTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigDisplayClass, -3, icSigRgbData, icSigXYZData, /* Rgb or any 3 component space ?? */
+ {icSigProfileDescriptionTag,
+ icSigRedColorantTag,
+ icSigGreenColorantTag,
+ icSigBlueColorantTag,
+ icSigRedTRCTag,
+ icSigGreenTRCTag,
+ icSigBlueTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ /* Non-3 component Display device */
+ {icSigDisplayClass, -100, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag, /* BToA doesn't seem to be required, which is strange... */
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -1, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigGrayTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -1, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigBToA0Tag,
+ icSigGamutTag,
+ icSigAToB1Tag,
+ icSigBToA1Tag,
+ icSigAToB2Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -2, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigBToA0Tag,
+ icSigGamutTag,
+ icSigAToB1Tag,
+ icSigBToA1Tag,
+ icSigAToB2Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -3, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigBToA0Tag,
+ icSigGamutTag,
+ icSigAToB1Tag,
+ icSigBToA1Tag,
+ icSigAToB2Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -4, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigBToA0Tag,
+ icSigGamutTag,
+ icSigAToB1Tag,
+ icSigBToA1Tag,
+ icSigAToB2Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -100, icMaxEnumData, icSigPCSData, /* Assumed from Hexachrome examples */
+ {icSigProfileDescriptionTag,
+ icSigBToA0Tag,
+ icSigBToA1Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigLinkClass, -100, icMaxEnumData, icMaxEnumData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigProfileSequenceDescTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigColorSpaceClass, -100, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigBToA0Tag,
+ icSigAToB0Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigAbstractClass, -100, icSigPCSData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigNamedColorClass, -200, icMaxEnumData, icMaxEnumData,
+ {icSigProfileDescriptionTag,
+ icSigNamedColor2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigNamedColorClass, -100, icMaxEnumData, icMaxEnumData,
+ {icSigProfileDescriptionTag,
+ icSigNamedColorTag, /* Not strictly V3.4 */
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icMaxEnumClass,-1,icMaxEnumData, icMaxEnumData, {icMaxEnumTag}}
+};
+
+/* ------------------------------------------------------------- */
+
+/* Return the current read fp (if any) */
+static icmFile *icc_get_rfp(icc *p) {
+ return p->fp;
+}
+
+/* Change the version to be non-default (ie. not 2.2.0), */
+/* e.g. ICC V4 (used for creation) */
+/* Return 0 if OK */
+/* Return 1 on error */
+static int icc_set_version(icc *p, icmICCVersion ver) {
+
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_set_version: Header is missing");
+ return p->errc = 1;
+ }
+
+ switch (ver) {
+ case icmVersionDefault:
+ p->header->majv = 2;
+ p->header->minv = 2;
+ p->header->bfv = 0;
+ break;
+ case icmVersion2_3:
+ p->header->majv = 2;
+ p->header->minv = 3;
+ p->header->bfv = 0;
+ break;
+ case icmVersion2_4:
+ p->header->majv = 2;
+ p->header->minv = 4;
+ p->header->bfv = 0;
+ break;
+#ifdef ENABLE_V4
+ case icmVersion4_1:
+ p->header->majv = 4;
+ p->header->minv = 1;
+ p->header->bfv = 0;
+ break;
+#endif
+ default:
+ sprintf(p->err,"icc_set_version: Unsupported version 0x%x",ver);
+ return p->errc = 1;
+ }
+ return 0;
+}
+
+
+/* Check that the ICC profile looks like it will be legal. */
+/* Return non-zero and set error string if not */
+static int check_icc_legal(
+ icc *p
+) {
+ int i, j;
+ icProfileClassSignature sig;
+ icColorSpaceSignature colsig;
+ icColorSpaceSignature pcssig;
+ int dchans;
+
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_check_legal: Header is missing");
+ return p->errc = 1;
+ }
+
+ sig = p->header->deviceClass;
+ colsig = p->header->colorSpace;
+ dchans = number_ColorSpaceSignature(colsig);
+ pcssig = p->header->pcs;
+
+ /* Find a matching table entry */
+ for (i = 0; tagchecktable[i].sig != icMaxEnumType; i++) {
+ if ( tagchecktable[i].sig == sig
+ && ( tagchecktable[i].chans == dchans /* Exactly matches */
+ || tagchecktable[i].chans == -dchans /* Exactly matches, but can try next table */
+ || tagchecktable[i].chans < -99) /* Doesn't have to match or try next table */
+ && ( tagchecktable[i].colsig == colsig
+ || (tagchecktable[i].colsig == icSigPCSData
+ && (colsig == icSigXYZData || colsig == icSigLabData))
+ || tagchecktable[i].colsig == icMaxEnumData)
+ && ( tagchecktable[i].pcssig == pcssig
+ || (tagchecktable[i].pcssig == icSigPCSData
+ && (pcssig == icSigXYZData || pcssig == icSigLabData))
+ || tagchecktable[i].pcssig == icMaxEnumData)) {
+
+ /* Found entry, so now check that all the required tags are present. */
+ for (j = 0; tagchecktable[i].tags[j] != icMaxEnumType; j++) {
+ if (p->find_tag(p, tagchecktable[i].tags[j]) != 0) { /* Not present! */
+ if (tagchecktable[i].chans == -200
+ || tagchecktable[i].chans == -dchans) { /* But can try next table */
+ break;
+ }
+ sprintf(p->err,"icc_check_legal: deviceClass %s is missing required tag %s",
+ tag2str(sig), tag2str(tagchecktable[i].tags[j]));
+ return p->errc = 1;
+ }
+ }
+ if (tagchecktable[i].tags[j] == icMaxEnumType) {
+ break; /* Fount all required tags */
+ }
+ }
+ }
+
+ /* According to the spec. if the deviceClass is:
+ an Abstract Class: both in and out color spaces should be PCS
+ an Link Class: both in and out color spaces can be any, and should
+ be the input space of the first profile in the link, and the
+ input space of the last profile in the link respectively.
+ a Named Class: in and out color spaces are not defined in the spec.
+ Input, Display, Output and ColorSpace Classes, input color
+ space can be any, and the output space must be PCS.
+ ~~ should check this here ???
+ */
+
+ return 0; /* Assume anything is ok */
+}
+
+
+/* read the object, return 0 on success, error code on fail */
+/* NOTE: this doesn't read the tag types, they should be read on demand. */
+/* NOTE: fp ownership is taken even if the function fails. */
+static int icc_read_x(
+ icc *p,
+ icmFile *fp, /* File to read from */
+ unsigned int of, /* File offset to read from */
+ int take_fp /* NZ if icc is to take ownership of fp */
+) {
+ char tcbuf[4]; /* Tag count read buffer */
+ unsigned int i, len;
+ unsigned int minoff, maxoff; /* Minimum and maximum offsets of tag data */
+ int er = 0; /* Error code */
+
+ p->fp = fp;
+ if (take_fp)
+ p->del_fp = 1;
+ p->of = of;
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_read: No header defined");
+ return p->errc = 1;
+ }
+
+ /* Read the header */
+ if (p->header->read(p->header, 128, of)) {
+ return 1;
+ }
+
+ /* Read the tag count */
+ if ( p->fp->seek(p->fp, of + 128) != 0
+ || p->fp->read(p->fp, tcbuf, 1, 4) != 4) {
+ sprintf(p->err,"icc_read: fseek() or fread() failed on tag count");
+ return p->errc = 1;
+ }
+ p->count = read_UInt32Number(tcbuf);
+
+ /* Sanity check it */
+ if (p->count > 357913940 /* (2^32-5)/12 */
+ || (p->count > ((p->header->size - 128 - 4) / 12))) {
+ sprintf(p->err,"icc_read: tag count %d is too large to be legal",p->count);
+ return p->errc = 1;
+ }
+ minoff = 128 + 4 + p->count * 12;
+ maxoff = p->header->size;
+
+ if (p->count > 0) {
+ char *bp, *buf;
+
+ if (ovr_mul(p->count, sizeof(icmTag))) {
+ sprintf(p->err,"icc_read: size overflow");
+ return p->errc = 1;
+ }
+
+ /* Read the table into memory */
+ if ((p->data = (icmTag *) p->al->calloc(p->al, p->count, sizeof(icmTag))) == NULL) {
+ sprintf(p->err,"icc_read: Tag table malloc() failed");
+ return p->errc = 2;
+ }
+
+ len = sat_mul(p->count, 12);
+ if ((buf = (char *) p->al->malloc(p->al, len)) == NULL) {
+ sprintf(p->err,"icc_read: Tag table read buffer malloc() failed");
+ p->al->free(p->al, p->data);
+ p->data = NULL;
+ return p->errc = 2;
+ }
+ if ( p->fp->seek(p->fp, of + 128 + 4) != 0
+ || p->fp->read(p->fp, buf, 1, len) != len) {
+ sprintf(p->err,"icc_read: fseek() or fread() failed on tag table");
+ p->al->free(p->al, p->data);
+ p->data = NULL;
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+
+ /* Fill in the tag table structure for each tag */
+ for (bp = buf, i = 0; i < p->count; i++, bp += 12) {
+ p->data[i].sig = (icTagSignature)read_SInt32Number(bp + 0);
+ p->data[i].offset = read_UInt32Number(bp + 4);
+ p->data[i].size = read_UInt32Number(bp + 8);
+ }
+ p->al->free(p->al, buf);
+
+ /* Check that each tag lies within the nominated space available, */
+ /* and has a reasonable size. */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].offset < minoff
+ || p->data[i].offset > maxoff
+ || p->data[i].size < 4
+ || p->data[i].size > (maxoff - minoff)
+ || (p->data[i].offset + p->data[i].size) < p->data[i].offset /* Overflow */
+ || (p->data[i].offset + p->data[i].size) > p->header->size) {
+ sprintf(p->err,"icc_read: tag %d is out of range of the nominated file size",i);
+ p->al->free(p->al, p->data);
+ p->data = NULL;
+ return p->errc = 1;
+ }
+ }
+
+ /* Read each tag type */
+ for (i = 0; i < p->count; i++) {
+ if ( p->fp->seek(p->fp, of + p->data[i].offset) != 0
+ || p->fp->read(p->fp, tcbuf, 1, 4) != 4) {
+ sprintf(p->err,"icc_read: fseek() or fread() failed on tag headers");
+ p->al->free(p->al, p->data);
+ p->data = NULL;
+ return p->errc = 1;
+ }
+ p->data[i].ttype = (icTagTypeSignature) read_SInt32Number(tcbuf); /* Tag type */
+ p->data[i].objp = NULL; /* Read on demand */
+ }
+ } /* p->count > 0 */
+
+ return er;
+}
+
+/* read the object, return 0 on success, error code on fail */
+/* NOTE: this doesn't read the tag types, they should be read on demand. */
+/* (backward compatible version) */
+static int icc_read(
+ icc *p,
+ icmFile *fp, /* File to read from */
+ unsigned int of /* File offset to read from */
+) {
+ return icc_read_x(p, fp, of, 0);
+}
+
+/* Check the profiles ID. We assume the file has already been read. */
+/* Return 0 if OK, 1 if no ID to check, 2 if doesn't match, 3 if some other error. */
+/* NOTE: this reads the whole file again, to compute the checksum. */
+static int icc_check_id(
+ icc *p,
+ ORD8 *rid /* Optionaly return computed ID */
+) {
+ unsigned char buf[128];
+ ORD8 id[16];
+ icmMD5 *md5 = NULL;
+ unsigned int len;
+
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_check_id: No header defined");
+ return p->errc = 3;
+ }
+ len = p->header->size; /* Claimed size of profile */
+
+ /* See if there is an ID to compare against */
+ for (len = 0; len < 16; len++) {
+ if (p->header->id[len] != 0)
+ break;
+ }
+ if (len >= 16) {
+ return 1;
+ }
+
+ if ((md5 = new_icmMD5(p->al)) == NULL) {
+ sprintf(p->err,"icc_check_id: new_icmMD5 failed");
+ return p->errc = 3;
+ }
+
+ /* Check the header */
+ if ( p->fp->seek(p->fp, p->of) != 0
+ || p->fp->read(p->fp, buf, 1, 128) != 128) {
+ sprintf(p->err,"icc_check_id: fseek() or fread() failed");
+ return p->errc = 3;
+ }
+
+ /* Zero the appropriate bytes in the header */
+ buf[44] = buf[45] = buf[46] = buf[47] = 0;
+ buf[64] = buf[65] = buf[66] = buf[67] = 0;
+ buf[84] = buf[85] = buf[86] = buf[87] =
+ buf[88] = buf[89] = buf[90] = buf[91] =
+ buf[92] = buf[93] = buf[94] = buf[95] =
+ buf[96] = buf[97] = buf[98] = buf[99] = 0;
+
+ md5->add(md5, buf, 128);
+
+ /* Suck in the rest of the profile */
+ for (;len > 0;) {
+ unsigned int rsize = 128;
+ if (rsize > len)
+ rsize = len;
+ if (p->fp->read(p->fp, buf, 1, rsize) != rsize) {
+ sprintf(p->err,"icc_check_id: fread() failed");
+ return p->errc = 3;
+ }
+ md5->add(md5, buf, rsize);
+ len -= rsize;
+ }
+
+ md5->get(md5, id);
+ md5->del(md5);
+
+ if (rid != NULL) {
+ for (len = 0; len < 16; len++)
+ rid[len] = id[len];
+ }
+
+ /* Check the ID */
+ for (len = 0; len < 16; len++) {
+ if (p->header->id[len] != id[len])
+ break;
+ }
+ if (len >= 16) {
+ return 0; /* Matched */
+ }
+ return 2; /* Didn't match */
+}
+
+/* Return the total size needed for the profile */
+/* Return 0 on error. */
+static unsigned int icc_get_size(
+ icc *p
+) {
+ unsigned int i, size = 0;
+
+#ifdef ICM_STRICT
+ /* Check that the right tags etc. are present for a legal ICC profile */
+ if (check_icc_legal(p) != 0) {
+ return 0;
+ }
+#endif /* ICM_STRICT */
+
+ /* Compute the total size and tag element data offsets */
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_get_size: No header defined");
+ p->errc = 1;
+ return 0;
+ }
+
+ size = sat_add(size, p->header->get_size(p->header));
+ /* Assume header is aligned */
+ size = sat_addaddmul(size, 4, p->count, 12); /* Tag table length */
+ size = sat_align(ALIGN_SIZE, size);
+
+ if (size == UINT_MAX) {
+ sprintf(p->err,"icc_get_size: size overflow");
+ return p->errc = 1;
+ }
+
+ /* Reset touched flag for each tag type */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp == NULL) {
+ sprintf(p->err,"icc_get_size: Internal error - NULL tag element");
+ p->errc = 1;
+ return 0;
+ }
+ p->data[i].objp->touched = 0;
+ }
+ /* Get size for each tag type, skipping links */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp->touched == 0) { /* Not alllowed for previously */
+ size = sat_add(size, p->data[i].objp->get_size(p->data[i].objp));
+ size = sat_align(ALIGN_SIZE, size);
+ p->data[i].objp->touched = 1; /* Don't account for this again */
+ }
+ }
+
+ return size; /* Total size needed, or UINT_MAX if overflow */
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+/* NOTE: fp ownership is taken even if the function fails. */
+static int icc_write_x(
+ icc *p,
+ icmFile *fp, /* File to write to */
+ unsigned int of, /* File offset to write to */
+ int take_fp /* NZ if icc is to take ownership of fp */
+) {
+ char *bp, *buf; /* tag table buffer */
+ unsigned int len;
+ int rv = 0;
+ unsigned int i, size = 0;
+ unsigned char pbuf[ALIGN_SIZE];
+
+ p->fp = fp; /* Open file pointer */
+ if (take_fp)
+ p->del_fp = 1;
+ p->of = of; /* Offset of ICC profile */
+
+ for (i = 0; i < ALIGN_SIZE; i++)
+ pbuf[i] = 0;
+
+ /* Check that the right tags etc. are present for a legal ICC profile */
+ if ((rv = check_icc_legal(p)) != 0) {
+ return rv;
+ }
+
+ /* Compute the total size and tag element data offsets */
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_write: No header defined");
+ return p->errc = 1;
+ }
+
+ size = sat_add(size, p->header->get_size(p->header));
+ /* Assume header is aligned */
+ len = sat_addmul(4, p->count, 12); /* Tag table length */
+ len = sat_sub(sat_align(ALIGN_SIZE, sat_add(size, len)), size); /* Aligned size */
+ size = sat_align(ALIGN_SIZE, sat_add(size, len));
+
+ if (len == UINT_MAX) {
+ sprintf(p->err,"icc_write get_size overflow");
+ return p->errc = 1;
+ }
+
+ /* Allocate memory buffer for tag table */
+ if ((buf = (char *) p->al->calloc(p->al, 1, len)) == NULL) {
+ sprintf(p->err,"icc_write calloc() failed");
+ return p->errc = 2;
+ }
+ bp = buf;
+
+ if ((rv = write_UInt32Number(p->count, bp)) != 0) { /* Tag count */
+ sprintf(p->err,"icc_write: write_UInt32Number() failed on tag count");
+ p->al->free(p->al, buf);
+ return p->errc = rv;
+ }
+ bp += 4;
+ /* Reset touched flag for each tag type */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp == NULL) {
+ sprintf(p->err,"icc_write: Internal error - NULL tag element");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+ p->data[i].objp->touched = 0;
+ }
+ /* Set the offset and size for each tag type, create the tag table write data */
+ /* and compute the total profile size. */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp->touched == 0) { /* Allocate space for tag type */
+ p->data[i].offset = size; /* Profile relative target */
+ p->data[i].size = p->data[i].objp->get_size(p->data[i].objp);
+ size = sat_add(size, p->data[i].size);
+ p->data[i].pad = sat_sub(sat_align(ALIGN_SIZE, size), size);
+ size = sat_align(ALIGN_SIZE, size);
+ p->data[i].objp->touched = 1; /* Allocated space for it */
+ if (size == UINT_MAX) {
+ sprintf(p->err,"icc_write: size overflow");
+ return p->errc = 1;
+ }
+ } else { /* must be linked - copy allocation */
+ unsigned int k;
+ for (k = 0; k < p->count; k++) { /* Find linked tag */
+ if (p->data[k].objp == p->data[i].objp)
+ break;
+ }
+ if (k == p->count) {
+ sprintf(p->err,"icc_write: corrupted link");
+ return p->errc = 2;
+ }
+ p->data[i].offset = p->data[k].offset;
+ p->data[i].size = p->data[k].size;
+ p->data[i].pad = p->data[k].pad;
+ }
+ /* Write tag table entry for this tag */
+ if ((rv = write_SInt32Number((int)p->data[i].sig,bp + 0)) != 0) {
+ sprintf(p->err,"icc_write: write_SInt32Number() failed on tag signature");
+ p->al->free(p->al, buf);
+ return p->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->data[i].offset, bp + 4)) != 0) {
+ sprintf(p->err,"icc_write: write_UInt32Number() failed on tag offset");
+ p->al->free(p->al, buf);
+ return p->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->data[i].size, bp + 8)) != 0) {
+ sprintf(p->err,"icc_write: write_UInt32Number() failed on tag size");
+ p->al->free(p->al, buf);
+ return p->errc = rv;
+ }
+ bp += 12;
+ }
+ p->header->size = size; /* Record total icc padded size */
+
+
+ /* If V4.0+, Compute the MD5 id for the profile. */
+ /* We do this by writing to a fake icmFile */
+ if (p->ver) {
+ icmMD5 *md5 = NULL;
+ icmFile *ofp, *dfp = NULL;
+
+ if ((md5 = new_icmMD5(p->al)) == NULL) {
+ sprintf(p->err,"icc_write: new_icmMD5 failed");
+ p->al->free(p->al, buf);
+ return p->errc = 2;
+ }
+
+ if ((dfp = new_icmFileMD5_a(md5, p->al)) == NULL) {
+ sprintf(p->err,"icc_write: new_icmFileMD5 failed");
+ md5->del(md5);
+ p->al->free(p->al, buf);
+ return p->errc = 2;
+ }
+
+ ofp = p->fp;
+ p->fp = dfp;
+
+ /* Dumy write the header */
+ if ((rv = p->header->write(p->header, 0, 1)) != 0) {
+ p->al->free(p->al, buf);
+ return rv;
+ }
+
+ /* Dumy write the tag table */
+ if ( p->fp->seek(p->fp, 128) != 0
+ || p->fp->write(p->fp, buf, 1, len) != len) {
+ sprintf(p->err,"icc_write: seek() or write() failed");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+
+ /* Dumy write all the tag element data */
+ /* (We invert meaning of touched here) */
+ for (i = 0; i < p->count; i++) { /* For all the tag element data */
+ if (p->data[i].objp->touched == 0)
+ continue; /* Must be linked, and we've already written it */
+ if ((rv = p->data[i].objp->write(p->data[i].objp, p->data[i].offset)) != 0) {
+ p->al->free(p->al, buf);
+ return rv;
+ }
+ /* Pad with 0 to next boundary */
+ if (p->data[i].pad > 0) {
+ if (p->fp->write(p->fp, pbuf, 1, p->data[i].pad) != p->data[i].pad) {
+ sprintf(p->err,"icc_write: write() failed");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+ }
+ p->data[i].objp->touched = 0; /* Written it, so don't write it again. */
+ }
+
+ if (p->fp->flush(p->fp) != 0) {
+ sprintf(p->err,"icc_write flush() failed");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+
+ if ((p->errc = ((icmFileMD5 *)dfp)->get_errc(dfp)) != 0) {
+ sprintf(p->err,"icc_write compute ID failed with code %d", p->errc);
+ p->al->free(p->al, buf);
+ return p->errc;
+ }
+
+ /* Get the MD5 checksum ID */
+ md5->get(md5, p->header->id);
+
+ dfp->del(dfp);
+ md5->del(md5);
+ p->fp = ofp;
+
+ /* Reset the touched flags */
+ for (i = 0; i < p->count; i++)
+ p->data[i].objp->touched = 1;
+ }
+
+ /* Now write out the profile for real. */
+ /* Although it may appear like we're seeking for each element, */
+ /* in fact elements will be written in file order. */
+
+ /* Write the header */
+ if ((rv = p->header->write(p->header, of, 0)) != 0) {
+ p->al->free(p->al, buf);
+ return rv;
+ }
+
+ /* Write the tag table */
+ if ( p->fp->seek(p->fp, of + 128) != 0
+ || p->fp->write(p->fp, buf, 1, len) != len) {
+ sprintf(p->err,"icc_write: seek() or write() failed");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+ p->al->free(p->al, buf);
+
+ /* Write all the tag element data */
+ /* (We invert the meaning of touched here) */
+ for (i = 0; i < p->count; i++) { /* For all the tag element data */
+ if (p->data[i].objp->touched == 0)
+ continue; /* Must be linked, and we've already written it */
+ if ((rv = p->data[i].objp->write(p->data[i].objp, of + p->data[i].offset)) != 0) {
+ return rv;
+ }
+ /* Pad with 0 to next boundary */
+ if (p->data[i].pad > 0) {
+ if (p->fp->write(p->fp, pbuf, 1, p->data[i].pad) != p->data[i].pad) {
+ sprintf(p->err,"icc_write: write() failed");
+ return p->errc = 1;
+ }
+ }
+ p->data[i].objp->touched = 0; /* Written it, so don't write it again. */
+ }
+
+ if (p->fp->flush(p->fp) != 0) {
+ sprintf(p->err,"icc_write flush() failed");
+ return p->errc = 1;
+ }
+
+ return rv;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+/* (backwards compatible version) */
+static int icc_write(
+ icc *p,
+ icmFile *fp, /* File to write to */
+ unsigned int of /* File offset to write to */
+) {
+ return icc_write_x(p, fp, of, 0);
+}
+
+/* Create and add a tag with the given signature. */
+/* Returns a pointer to the element object */
+/* Returns NULL if error - icc->errc will contain */
+/* 2 on system error, */
+/* 3 if unknown tag */
+/* NOTE: that we prevent tag duplication */
+/* NOTE: to create a tag type icmSigUnknownType, set ttype to icmSigUnknownType, */
+/* and set the actual tag type in icmSigUnknownType->uttype */
+static icmBase *icc_add_tag(
+ icc *p,
+ icTagSignature sig, /* Tag signature - may be unknown */
+ icTagTypeSignature ttype /* Tag type */
+) {
+ icmBase *tp;
+ icmBase *nob;
+ int i = 0, ok = 1;
+ unsigned int j;
+
+ if (ttype != icmSigUnknownType) { /* Check only for possibly known types */
+
+ /* Check that a known signature has an acceptable type */
+ for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
+ if (sigtypetable[i].sig == sig) { /* recognized signature */
+ ok = 0;
+ for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
+ if (sigtypetable[i].ttypes[j] == ttype) /* recognized type */
+ ok = 1;
+ }
+ break;
+ }
+ }
+ if (!ok) {
+ sprintf(p->err,"icc_add_tag: wrong tag type for signature");
+ p->errc = 1;
+ return NULL;
+ }
+
+ /* Check that we know how to handle this type */
+ for (i = 0; typetable[i].ttype != icMaxEnumType; i++) {
+ if (typetable[i].ttype == ttype)
+ break;
+ }
+ if (typetable[i].ttype == icMaxEnumType) {
+ sprintf(p->err,"icc_add_tag: unsupported tag type");
+ p->errc = 1;
+ return NULL;
+ }
+ }
+
+ /* Check that this tag doesn't already exist */
+ /* (Perhaps we should simply replace it, rather than erroring ?) */
+ for (j = 0; j < p->count; j++) {
+ if (p->data[j].sig == sig) {
+ sprintf(p->err,"icc_add_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig));
+ p->errc = 1;
+ return NULL;
+ }
+ }
+
+ /* Make space in tag table for new tag item */
+ if (ovr_mul(sat_add(p->count,1), sizeof(icmTag))) {
+ sprintf(p->err,"icc_add_tag: size overflow");
+ p->errc = 1;
+ return NULL;
+ }
+ if (p->data == NULL)
+ tp = (icmBase *)p->al->malloc(p->al, (p->count+1) * sizeof(icmTag));
+ else
+ tp = (icmBase *)p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag));
+ if (tp == NULL) {
+ sprintf(p->err,"icc_add_tag: Tag table realloc() failed");
+ p->errc = 2;
+ return NULL;
+ }
+ p->data = (icmTag *)tp;
+
+ if (ttype == icmSigUnknownType) {
+ if ((nob = new_icmUnknown(p)) == NULL)
+ return NULL;
+ } else {
+ /* Allocate the empty object */
+ if ((nob = typetable[i].new_obj(p)) == NULL)
+ return NULL;
+ }
+
+ /* Fill out our tag table entry */
+ p->data[p->count].sig = sig; /* The tag signature */
+ p->data[p->count].ttype = nob->ttype = ttype; /* The tag type signature */
+ p->data[p->count].offset = 0; /* Unknown offset yet */
+ p->data[p->count].size = 0; /* Unknown size yet */
+ p->data[p->count].objp = nob; /* Empty object */
+ p->count++;
+
+ return nob;
+}
+
+/* Create and add a tag which is a link to an existing tag. */
+/* Returns a pointer to the element object */
+/* Returns NULL if error - icc->errc will contain */
+/* 3 if incompatible tag */
+/* NOTE: that we prevent tag duplication */
+static icmBase *icc_link_tag(
+ icc *p,
+ icTagSignature sig, /* Tag signature - may be unknown */
+ icTagSignature ex_sig /* Tag signature of tag to link to */
+) {
+ icmBase *tp;
+ unsigned int j, exi;
+ int i, ok = 1;
+
+ /* Search for existing signature */
+ for (exi = 0; exi < p->count; exi++) {
+ if (p->data[exi].sig == ex_sig) /* Found it */
+ break;
+ }
+ if (exi == p->count) {
+ sprintf(p->err,"icc_link_tag: Can't find existing tag '%s'",tag2str(ex_sig));
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (p->data[exi].objp == NULL) {
+ sprintf(p->err,"icc_link_tag: Existing tag '%s' isn't loaded",tag2str(ex_sig));
+ p->errc = 1;
+ return NULL;
+ }
+
+ /* Check that a known signature has an acceptable type */
+ for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
+ if (sigtypetable[i].sig == sig) { /* recognized signature */
+ ok = 0;
+ for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
+ if (sigtypetable[i].ttypes[j] == p->data[exi].ttype) /* recognized type */
+ ok = 1;
+ }
+ break;
+ }
+ }
+ if (!ok) {
+ sprintf(p->err,"icc_link_tag: wrong tag type for signature");
+ p->errc = 1;
+ return NULL;
+ }
+
+ /* Check that this tag doesn't already exits */
+ for (j = 0; j < p->count; j++) {
+ if (p->data[j].sig == sig) {
+ sprintf(p->err,"icc_link_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig));
+ p->errc = 1;
+ return NULL;
+ }
+ }
+
+ /* Make space in tag table for new tag item */
+ if (p->data == NULL)
+ tp = (icmBase *)p->al->malloc(p->al, (p->count+1) * sizeof(icmTag));
+ else
+ tp = (icmBase *)p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag));
+ if (tp == NULL) {
+ sprintf(p->err,"icc_link_tag: Tag table realloc() failed");
+ p->errc = 2;
+ return NULL;
+ }
+ p->data = (icmTag *)tp;
+
+ /* Fill out our tag table entry */
+ p->data[p->count].sig = sig; /* The tag signature */
+ p->data[p->count].ttype = p->data[exi].ttype; /* The tag type signature */
+ p->data[p->count].offset = p->data[exi].offset; /* Same offset (may not be allocated yet) */
+ p->data[p->count].size = p->data[exi].size; /* Same size (may not be allocated yet) */
+ p->data[p->count].objp = p->data[exi].objp; /* Shared object */
+ p->data[exi].objp->refcount++; /* Bump reference count on tag type */
+ p->count++;
+
+ return p->data[exi].objp;
+}
+
+/* Search for tag signature */
+/* return: */
+/* 0 if found */
+/* 1 if found but not handled type */
+/* 2 if not found */
+/* NOTE: doesn't set icc->errc or icc->err[] */
+/* NOTE: we don't handle tag duplication - you'll always get the first in the file. */
+static int icc_find_tag(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+ int j;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i == p->count)
+ return 2;
+
+ /* See if we can handle this type */
+ for (j = 0; typetable[j].ttype != icMaxEnumType; j++) {
+ if (typetable[j].ttype == p->data[i].ttype)
+ break;
+ }
+ if (typetable[j].ttype == icMaxEnumType)
+ return 1;
+
+ return 0;
+}
+
+/* Read the specific tag element data, and return a pointer to the object */
+/* (This is an internal function) */
+/* Returns NULL if error - icc->errc will contain: */
+/* 2 if not found */
+/* Returns an icmSigUnknownType object if the tag type isn't handled by a */
+/* specific object and alow_unk is NZ */
+/* NOTE: we don't handle tag duplication - you'll always get the first in the file */
+static icmBase *icc_read_tag_ix(
+ icc *p,
+ unsigned int i, /* Index from 0.. p->count-1 */
+ int alow_unk /* NZ to allow unknown tag to load */
+) {
+ icTagTypeSignature ttype; /* Tag type we will create */
+ icmBase *nob;
+ unsigned int k;
+ int j;
+
+ if (i >= p->count) {
+ sprintf(p->err,"icc_read_tag_ix: index %d is out of range",i);
+ p->errc = 2;
+ return NULL;
+ }
+
+ /* See if it's already been read */
+ if (p->data[i].objp != NULL) {
+ return p->data[i].objp; /* Just return it */
+ }
+
+ /* See if this should be a link */
+ for (k = 0; k < p->count; k++) {
+ if (i == k)
+ continue;
+ if (p->data[i].ttype == p->data[k].ttype /* Exact match and already read */
+ && p->data[i].offset == p->data[k].offset
+ && p->data[i].size == p->data[k].size
+ && p->data[k].objp != NULL)
+ break;
+ }
+ if (k < p->count) { /* Make this a link */
+ p->data[i].objp = p->data[k].objp;
+ p->data[k].objp->refcount++; /* Bump reference count */
+ return p->data[k].objp; /* Done */
+ }
+
+ /* See if we can handle this type */
+ for (j = 0; typetable[j].ttype != icMaxEnumType; j++) {
+ if (typetable[j].ttype == p->data[i].ttype)
+ break;
+ }
+
+ if (typetable[j].ttype == icMaxEnumType) {
+ if (!alow_unk) {
+ p->errc = 2;
+ return NULL;
+ }
+ ttype = icmSigUnknownType; /* Use the Unknown type to handle an unknown tag type */
+ } else {
+ ttype = p->data[i].ttype; /* We known this type */
+ }
+
+ /* Create and read in the object */
+ if (ttype == icmSigUnknownType)
+ nob = new_icmUnknown(p);
+ else
+ nob = typetable[j].new_obj(p);
+
+ if (nob == NULL)
+ return NULL;
+
+ if ((nob->read(nob, p->data[i].size, p->of + p->data[i].offset)) != 0) {
+ nob->del(nob); /* Failed, so destroy it */
+ return NULL;
+ }
+ p->data[i].objp = nob;
+ return nob;
+}
+
+/* Read the tag element data of the first matching, and return a pointer to the object */
+/* Returns NULL if error - icc->errc will contain: */
+/* 2 if not found */
+/* Doesn't read uknown type tags */
+static icmBase *icc_read_tag(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i >= p->count) {
+ sprintf(p->err,"icc_read_tag: Tag '%s' not found",string_TagSignature(sig));
+ p->errc = 2;
+ return NULL;
+ }
+
+ /* Let read_tag_ix do all the work */
+ return icc_read_tag_ix(p, i, 0);
+}
+
+/* Read the tag element data of the first matching, and return a pointer to the object */
+/* Returns NULL if error.
+/* Returns an icmSigUnknownType object if the tag type isn't handled by a specific object. */
+/* NOTE: we don't handle tag duplication - you'll always get the first in the file. */
+static icmBase *icc_read_tag_any(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i >= p->count) {
+ sprintf(p->err,"icc_read_tag: Tag '%s' not found",string_TagSignature(sig));
+ p->errc = 2;
+ return NULL;
+ }
+
+ /* Let read_tag_ix do all the work */
+ return icc_read_tag_ix(p, i, 1);
+}
+
+/* Rename a tag signature */
+static int icc_rename_tag(
+ icc *p,
+ icTagSignature sig, /* Existing Tag signature - may be unknown */
+ icTagSignature sigNew /* New Tag signature - may be unknown */
+) {
+ unsigned int k;
+ int i, j, ok = 1;
+
+ /* Search for signature */
+ for (k = 0; k < p->count; k++) {
+ if (p->data[k].sig == sig) /* Found it */
+ break;
+ }
+ if (k >= p->count) {
+ sprintf(p->err,"icc_rename_tag: Tag '%s' not found",string_TagSignature(sig));
+ return p->errc = 2;
+ }
+
+ /* Check that a known new signature has an acceptable type */
+ for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
+ if (sigtypetable[i].sig == sigNew) { /* recognized signature */
+ ok = 0;
+ for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
+ if (sigtypetable[i].ttypes[j] == p->data[k].ttype) /* recognized type */
+ ok = 1;
+ }
+ break;
+ }
+ }
+
+ if (!ok) {
+ sprintf(p->err,"icc_rename_tag: wrong signature for tag type");
+ p->errc = 1;
+ return p->errc;
+ }
+
+ /* change its signature */
+ p->data[k].sig = sigNew;
+
+ return 0;
+}
+
+/* Unread a specific tag, and free the underlying tag type data */
+/* if this was the last reference to it. */
+/* (This is an internal function) */
+/* Returns non-zero on error: */
+/* tag not found - icc->errc will contain 2 */
+/* tag not read - icc->errc will contain 2 */
+static int icc_unread_tag_ix(
+ icc *p,
+ unsigned int i /* Index from 0.. p->count-1 */
+) {
+ if (i >= p->count) {
+ sprintf(p->err,"icc_unread_tag_ix: index %d is out of range",i);
+ return p->errc = 2;
+ }
+
+ /* See if it's been read */
+ if (p->data[i].objp == NULL) {
+ sprintf(p->err,"icc_unread_tag: Tag '%s' not currently loaded",string_TagSignature(p->data[i].sig));
+ return p->errc = 2;
+ }
+
+ if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
+ (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
+ p->data[i].objp = NULL;
+
+ return 0;
+}
+
+/* Unread the tag, and free the underlying tag type */
+/* if this was the last reference to it. */
+/* Returns non-zero on error: */
+/* tag not found - icc->errc will contain 2 */
+/* tag not read - icc->errc will contain 2 */
+/* NOTE: we don't handle tag duplication - you'll always get the first in the file */
+static int icc_unread_tag(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i >= p->count) {
+ sprintf(p->err,"icc_unread_tag: Tag '%s' not found",string_TagSignature(sig));
+ return p->errc = 2;
+ }
+
+ return icc_unread_tag(p, i);
+}
+
+/* Delete the tag, and free the underlying tag type, */
+/* if this was the last reference to it. */
+/* Note this finds the first tag with a matching signature */
+/* Returns non-zero on error: */
+/* tag not found - icc->errc will contain 2 */
+static int icc_delete_tag_ix(
+ icc *p,
+ unsigned int i /* Index from 0.. p->count-1 */
+) {
+ if (i >= p->count) {
+ sprintf(p->err,"icc_delete_tag_ix: index %d of range",i);
+ return p->errc = 2;
+ }
+
+ /* If it's been read into memory, decrement the reference count */
+ if (p->data[i].objp != NULL) {
+ if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
+ (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
+ p->data[i].objp = NULL;
+ }
+
+ /* Now remove it from the tag list */
+ for (; i < (p->count-1); i++)
+ p->data[i] = p->data[i+1]; /* Copy the structure down */
+
+ p->count--; /* One less tag in list */
+
+ return 0;
+}
+
+/* Delete the tag, and free the underlying tag type, */
+/* if this was the last reference to it. */
+/* Note this finds the first tag with a matching signature. */
+/* Returns non-zero on error: */
+/* tag not found - icc->errc will contain 2 */
+static int icc_delete_tag(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i >= p->count) {
+ sprintf(p->err,"icc_delete_tag: Tag '%s' not found",string_TagSignature(sig));
+ return p->errc = 2;
+ }
+
+ return icc_delete_tag_ix(p, i);
+}
+
+/* Read all the tags into memory, including unknown types. */
+/* Returns non-zero on error. */
+static int icc_read_all_tags(
+ icc *p
+) {
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++) { /* For all the tag element data */
+ if (icc_read_tag_ix(p, i, 1) == NULL)
+ return p->errc;
+ }
+ return 0;
+}
+
+
+static void icc_dump(
+ icc *p,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ unsigned int i;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"icc:\n");
+
+ /* Dump the header */
+ if (p->header != NULL)
+ p->header->dump(p->header,op,verb);
+
+ /* Dump all the tag elements */
+ for (i = 0; i < p->count; i++) { /* For all the tag element data */
+ icmBase *ob;
+ int tr;
+ op->gprintf(op,"tag %d:\n",i);
+ op->gprintf(op," sig %s\n",tag2str(p->data[i].sig));
+ op->gprintf(op," type %s\n",tag2str(p->data[i].ttype));
+ op->gprintf(op," offset %d\n", p->data[i].offset);
+ op->gprintf(op," size %d\n", p->data[i].size);
+ tr = 0;
+ if (p->data[i].objp == NULL) {
+ /* The object is not loaded, so load it then free it */
+ if (icc_read_tag_ix(p, i, 1) == NULL)
+ op->gprintf(op,"Unable to read: %d, %s\n",p->errc,p->err);
+ tr = 1;
+ }
+ if ((ob = p->data[i].objp) != NULL) {
+ /* op->gprintf(op," refcount %d\n", ob->refcount); */
+ ob->dump(ob,op,verb-1);
+
+ if (tr != 0) { /* Cleanup if temporary */
+ icc_unread_tag_ix(p, i);
+ }
+ }
+ op->gprintf(op,"\n");
+ }
+}
+
+static void icc_delete(
+ icc *p
+) {
+ unsigned int i;
+ icmAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ /* Free up the header */
+ if (p->header != NULL)
+ (p->header->del)(p->header);
+
+ /* Free up the tag data objects */
+ if (p->data != NULL) {
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp != NULL) {
+ if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
+ (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
+ p->data[i].objp = NULL;
+ }
+ }
+ /* Free tag table */
+ al->free(al, p->data);
+ }
+
+ /* We are responsible for deleting the file object */
+ if (p->del_fp && p->fp != NULL)
+ p->fp->del(p->fp);
+
+ /* This object */
+ al->free(al, p);
+
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+}
+
+/* ================================================== */
+/* Lut Color normalizing and de-normalizing functions */
+
+/* As a rule, I am representing Lut in memory as values in machine form as real */
+/* numbers in the range 0.0 - 1.0. For many color spaces (ie. RGB, Gray, */
+/* hsv, hls, cmyk and other device coords), this is entirely appropriate. */
+/* For CIE based spaces though, this is not correct, since (I assume!) the binary */
+/* representation will be consistent with the encoding in Annex A, page 74 */
+/* of the standard. Note that the standard doesn't specify the encoding of */
+/* many color spaces (ie. Yuv, Yxy etc.), and is unclear about PCS. */
+
+/* The following functions convert to and from the CIE base spaces */
+/* and the real Lut input/output values. These are used to convert real color */
+/* space values into/out of the raw lut 0.0-1.0 representation (which subsequently */
+/* get converted to ICC integer values in the obvious way as a mapping to 0 .. 2^n-1). */
+
+/* This is used internally to support the Lut->lookup() function, */
+/* and can also be used by someone writing a Lut based profile to determine */
+/* the colorspace range that the input lut indexes cover, as well */
+/* as processing the output luts values into normalized form ready */
+/* for writing. */
+
+/* These functions should be accessed by calling icc.getNormFuncs() */
+
+/* - - - - - - - - - - - - - - - - */
+/* According to 6.5.5 and 6.5.6 of the spec., */
+/* XYZ index values are represented the same as their table */
+/* values, ie. as a u1.15 representation, with a value */
+/* range from 0.0 -> 1.999969482422 */
+
+/* Convert Lut index/value to XYZ coord. */
+static void Lut_Lut2XYZ(double *out, double *in) {
+ out[0] = in[0] * (1.0 + 32767.0/32768); /* X */
+ out[1] = in[1] * (1.0 + 32767.0/32768); /* Y */
+ out[2] = in[2] * (1.0 + 32767.0/32768); /* Z */
+}
+
+/* Convert XYZ coord to Lut index/value. */
+static void Lut_XYZ2Lut(double *out, double *in) {
+ out[0] = in[0] * (1.0/(1.0 + 32767.0/32768));
+ out[1] = in[1] * (1.0/(1.0 + 32767.0/32768));
+ out[2] = in[2] * (1.0/(1.0 + 32767.0/32768));
+}
+
+/* Convert Lut index/value to Y coord. */
+static void Lut_Lut2Y(double *out, double *in) {
+ out[0] = in[0] * (1.0 + 32767.0/32768); /* Y */
+}
+
+/* Convert Y coord to Lut index/value. */
+static void Lut_Y2Lut(double *out, double *in) {
+ out[0] = in[0] * (1.0/(1.0 + 32767.0/32768));
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Convert 8 bit Lab to Lut numbers */
+/* Annex A specifies 8 and 16 bit encoding, but is */
+/* silent on the Lut index normalization. */
+/* Following Michael Bourgoin's 1998 SIGGRAPH course comment on this, */
+/* we assume here that the index encoding is the same as the */
+/* value encoding. */
+
+/* Convert Lut8 table index/value to Lab */
+static void Lut_Lut2Lab_8(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+ out[1] = (in[1] * 255.0) - 128.0; /* a */
+ out[2] = (in[2] * 255.0) - 128.0; /* b */
+}
+
+/* Convert Lab to Lut8 table index/value */
+static void Lut_Lab2Lut_8(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+ out[1] = (in[1] + 128.0) * 1.0/255.0; /* a */
+ out[2] = (in[2] + 128.0) * 1.0/255.0; /* b */
+}
+
+/* Convert Lut8 table index/value to L */
+static void Lut_Lut2L_8(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+}
+
+/* Convert L to Lut8 table index/value */
+static void Lut_L2Lut_8(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Convert 16 bit Lab to Lut numbers, V2 */
+
+/* Convert Lut16 table index/value to Lab */
+static void Lut_Lut2LabV2_16(double *out, double *in) {
+ out[0] = in[0] * (100.0 * 65535.0)/65280.0; /* L */
+ out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0; /* a */
+ out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0; /* b */
+}
+
+/* Convert Lab to Lut16 table index/value */
+static void Lut_Lab2LutV2_16(double *out, double *in) {
+ out[0] = in[0] * 65280.0/(100.0 * 65535.0); /* L */
+ out[1] = (in[1] + 128.0) * 65280.0/(255.0 * 65535.0); /* a */
+ out[2] = (in[2] + 128.0) * 65280.0/(255.0 * 65535.0); /* b */
+}
+
+/* Convert Lut16 table index/value to L */
+static void Lut_Lut2LV2_16(double *out, double *in) {
+ out[0] = in[0] * (100.0 * 65535.0)/65280.0; /* L */
+}
+
+/* Convert Lab to Lut16 table index/value */
+static void Lut_L2LutV2_16(double *out, double *in) {
+ out[0] = in[0] * 65280.0/(100.0 * 65535.0); /* L */
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Convert 16 bit Lab to Lut numbers, V4 */
+
+/* Convert Lut16 table index/value to Lab */
+static void Lut_Lut2LabV4_16(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+ out[1] = (in[1] * 255.0) - 128.0; /* a */
+ out[2] = (in[2] * 255.0) - 128.0; /* b */
+}
+
+/* Convert Lab to Lut16 table index/value */
+static void Lut_Lab2LutV4_16(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+ out[1] = (in[1] + 128.0) * 1.0/255.0; /* a */
+ out[2] = (in[2] + 128.0) * 1.0/255.0; /* b */
+}
+
+/* Convert Lut16 table index/value to L */
+static void Lut_Lut2LV4_16(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+}
+
+/* Convert L to Lut16 table index/value */
+static void Lut_L2LutV4_16(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Convert Luv to Lut number */
+/* This data normalization is taken from Apples */
+/* Colorsync specification. */
+/* As per other color spaces, we assume that the index */
+/* normalization is the same as the data normalization. */
+
+/* Convert Lut table index/value to Luv */
+static void Lut_Lut2Luv(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+ out[1] = (in[1] * 65535.0/256.0) - 128.0; /* u */
+ out[2] = (in[2] * 65535.0/256.0) - 128.0; /* v */
+}
+
+/* Convert Luv to Lut table index/value */
+static void Lut_Luv2Lut(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+ out[1] = (in[1] + 128.0) * 256.0/65535.0; /* u */
+ out[2] = (in[2] + 128.0) * 256.0/65535.0; /* v */
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Default N component conversions */
+static void Lut_N(double *out, double *in, int nc) {
+ for (--nc; nc >= 0; nc--)
+ out[nc] = in[nc];
+}
+
+/* 1 */
+static void Lut_1(double *out, double *in) {
+ out[0] = in[0];
+}
+
+/* 2 */
+static void Lut_2(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+}
+
+/* 3 */
+static void Lut_3(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+}
+
+/* 4 */
+static void Lut_4(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* 5 */
+static void Lut_5(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[4] = in[4];
+}
+
+/* 6 */
+static void Lut_6(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[4] = in[4];
+ out[5] = in[5];
+}
+
+/* 7 */
+static void Lut_7(double *out, double *in) {
+ Lut_N(out, in, 7);
+}
+
+/* 8 */
+static void Lut_8(double *out, double *in) {
+ Lut_N(out, in, 8);
+}
+
+/* 9 */
+static void Lut_9(double *out, double *in) {
+ Lut_N(out, in, 9);
+}
+
+/* 10 */
+static void Lut_10(double *out, double *in) {
+ Lut_N(out, in, 10);
+}
+
+/* 11 */
+static void Lut_11(double *out, double *in) {
+ Lut_N(out, in, 11);
+}
+
+/* 12 */
+static void Lut_12(double *out, double *in) {
+ Lut_N(out, in, 12);
+}
+
+/* 13 */
+static void Lut_13(double *out, double *in) {
+ Lut_N(out, in, 13);
+}
+
+/* 14 */
+static void Lut_14(double *out, double *in) {
+ Lut_N(out, in, 14);
+}
+
+/* 15 */
+static void Lut_15(double *out, double *in) {
+ Lut_N(out, in, 15);
+}
+
+/* Function table - match conversions to color spaces. */
+/* Anything not here, we don't know how to convert. */
+/* (ie. YCbCr) */
+static struct {
+ icColorSpaceSignature csig;
+ void (*fromLut)(double *out, double *in); /* from Lut index/entry */
+ void (*toLut)(double *out, double *in); /* to Lut index/entry */
+} colnormtable[] = {
+ {icSigXYZData, Lut_Lut2XYZ, Lut_XYZ2Lut },
+ {icmSigYData, Lut_Lut2Y, Lut_Y2Lut },
+ {icmSigLab8Data, Lut_Lut2Lab_8, Lut_Lab2Lut_8 },
+ {icmSigLabV2Data, Lut_Lut2LabV2_16, Lut_Lab2LutV2_16 },
+ {icmSigLabV4Data, Lut_Lut2LabV4_16, Lut_Lab2LutV4_16 },
+ {icmSigL8Data, Lut_Lut2L_8, Lut_L2Lut_8 },
+ {icmSigLV2Data, Lut_Lut2LV2_16, Lut_L2LutV2_16 },
+ {icmSigLV4Data, Lut_Lut2LV4_16, Lut_L2LutV4_16 },
+ {icSigLuvData, Lut_Lut2Luv, Lut_Luv2Lut },
+ {icSigYxyData, Lut_3, Lut_3 },
+ {icSigRgbData, Lut_3, Lut_3 },
+ {icSigGrayData, Lut_1, Lut_1 },
+ {icSigHsvData, Lut_3, Lut_3 },
+ {icSigHlsData, Lut_3, Lut_3 },
+ {icSigCmykData, Lut_4, Lut_4 },
+ {icSigCmyData, Lut_3, Lut_3 },
+ {icSigMch6Data, Lut_6, Lut_6 },
+ {icSig2colorData, Lut_2, Lut_2 },
+ {icSig3colorData, Lut_3, Lut_3 },
+ {icSig4colorData, Lut_4, Lut_4 },
+ {icSig5colorData, Lut_5, Lut_5 },
+ {icSig6colorData, Lut_6, Lut_6 },
+ {icSig7colorData, Lut_7, Lut_7 },
+ {icSigMch5Data, Lut_5, Lut_5 },
+ {icSigMch6Data, Lut_6, Lut_6 },
+ {icSigMch7Data, Lut_7, Lut_7 },
+ {icSigMch8Data, Lut_8, Lut_8 },
+ {icSig8colorData, Lut_8, Lut_8 },
+ {icSig9colorData, Lut_9, Lut_9 },
+ {icSig10colorData, Lut_10, Lut_10 },
+ {icSig11colorData, Lut_11, Lut_11 },
+ {icSig12colorData, Lut_12, Lut_12 },
+ {icSig13colorData, Lut_13, Lut_13 },
+ {icSig14colorData, Lut_14, Lut_14 },
+ {icSig15colorData, Lut_15, Lut_15 },
+ {icMaxEnumData, NULL, NULL }
+};
+
+/*
+ Legacy Lab encoding:
+
+ The V4 specificatins are misleading on this, since they assume in this
+ instance that all devices spaces, however labeled, have no defined
+ ICC encoding. The end result is simple enough though:
+
+ ICC V2 Lab encoding should be used in all PCS encodings in
+ a icSigLut16Type or icSigNamedColor2Type tag, and can be used
+ for Lab encoding in device spaces for these tags.
+
+ ICC V4 Lab encoding should be used in all PCS encodings in
+ all other situations, and can be used for Lab encoding in
+ device spaces for all other situtaions.
+
+ [ Since the ICC spec. doesn't cover device spaces labeled as Lab,
+ these are ripe for mis-matches between different implementations.]
+
+ This logic has yet to be fully implemented here.
+*/
+
+/* Find appropriate conversion functions from the normalised */
+/* Lut data range 0.0 - 1.0 to/from a given colorspace value, */
+/* given the color space and Lut type. */
+/* Return 0 on success, 1 on match failure. */
+/* NOTE: doesn't set error value, message etc.! */
+static int getNormFunc(
+ icc *icp,
+// icProfileClassSignature psig, /* Profile signature to use */
+ icColorSpaceSignature csig, /* Colorspace to use. */
+// int lutin, /* 0 if this is for a icSigLut16Type input, nz for output */
+// icTagSignature tagSig, /* Tag signature involved (AtoB or B2A etc.) */
+ icTagTypeSignature tagType, /* icSigLut8Type or icSigLut16Type or V4 lut */
+ icmNormFlag flag, /* icmFromLuti, icmFromLutv or icmToLuti, icmToLutv */
+ void (**nfunc)(double *out, double *in)
+) {
+ int i;
+ if (tagType == icSigLut8Type && csig == icSigLabData) {
+ csig = icmSigLab8Data;
+ }
+ if (csig == icSigLabData) {
+ if (tagType == icSigLut16Type) /* Lut16 retains legacy encoding */
+ csig = icmSigLabV2Data;
+ else { /* Other tag types use version specific encoding */
+ if (icp->ver)
+ csig = icmSigLabV4Data;
+ else
+ csig = icmSigLabV2Data;
+ }
+ }
+
+ for (i = 0; colnormtable[i].csig != icMaxEnumData; i++) {
+ if (colnormtable[i].csig == csig)
+ break; /* Found it */
+ }
+ if (colnormtable[i].csig == icMaxEnumData) { /* Oops */
+ *nfunc = NULL;
+ return 1;
+ }
+
+ if (flag == icmFromLuti || flag == icmFromLutv) { /* Table index/value decoding functions */
+ *nfunc = colnormtable[i].fromLut;
+ return 0;
+ } else if (flag == icmToLuti || flag == icmToLutv) { /* Table index/value encoding functions */
+ *nfunc = colnormtable[i].toLut;
+ return 0;
+ }
+ *nfunc = NULL;
+ return 1;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Colorspace ranges - used instead of norm/denorm by Mono, Matrix and */
+/* override PCS */
+
+/* Function table - match ranges to color spaces. */
+/* Anything not here, we don't know how to convert. */
+/* (ie. YCbCr) */
+/* Hmm. we're not handling Lab8 properly ?? ~~~8888 */
+static struct {
+ icColorSpaceSignature csig;
+ int same; /* Non zero if first entry applies to all channels */
+ double min[3]; /* Minimum value for this colorspace */
+ double max[3]; /* Maximum value for this colorspace */
+} colorrangetable[] = {
+ {icSigXYZData, 1, { 0.0 } , { 1.0 + 32767.0/32768.0 } },
+ {icmSigLab8Data, 0, { 0.0, -128.0, -128.0 }, { 100.0, 127.0, 127.0 } },
+ {icmSigLabV2Data, 0, { 0.0, -128.0, -128.0 },
+ { 100.0 + 25500.0/65280.0, 127.0 + 255.0/256.0, 127.0 + 255.0/256.0 } },
+ {icmSigLabV4Data, 0, { 0.0, -128.0, -128.0 }, { 100.0, 127.0, 127.0 } },
+ {icmSigYData, 1, { 0.0 }, { 1.0 + 32767.0/32768.0 } },
+ {icmSigL8Data, 1, { 0.0 }, { 100.0 } },
+ {icmSigLV2Data, 1, { 0.0 }, { 100.0 + 25500.0/65280.0 } },
+ {icmSigLV4Data, 1, { 0.0 }, { 100.0 } },
+ {icSigLuvData, 0, { 0.0, -128.0, -128.0 },
+ { 100.0, 127.0 + 255.0/256.0, 127.0 + 255.0/256.0 } },
+ {icSigYCbCrData, 1, { 0.0 }, { 1.0 } }, /* ??? */
+ {icSigYxyData, 1, { 0.0 }, { 1.0 } }, /* ??? */
+ {icSigRgbData, 1, { 0.0 }, { 1.0 } },
+ {icSigGrayData, 1, { 0.0 }, { 1.0 } },
+ {icSigHsvData, 1, { 0.0 }, { 1.0 } },
+ {icSigHlsData, 1, { 0.0 }, { 1.0 } },
+ {icSigCmykData, 1, { 0.0 }, { 1.0 } },
+ {icSigCmyData, 1, { 0.0 }, { 1.0 } },
+ {icSigMch6Data, 1, { 0.0 }, { 1.0 } },
+ {icSig2colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig3colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig4colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig5colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig6colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig7colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig8colorData, 1, { 0.0 }, { 1.0 } },
+ {icSigMch5Data, 1, { 0.0 }, { 1.0 } },
+ {icSigMch6Data, 1, { 0.0 }, { 1.0 } },
+ {icSigMch7Data, 1, { 0.0 }, { 1.0 } },
+ {icSigMch8Data, 1, { 0.0 }, { 1.0 } },
+ {icSig9colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig10colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig11colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig12colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig13colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig14colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig15colorData, 1, { 0.0 }, { 1.0 } },
+ {icMaxEnumData, 1, { 0.0 }, { 1.0 } }
+};
+
+/* Find appropriate typical encoding ranges for a */
+/* colorspace given the color space. */
+/* Return 0 on success, 1 on match failure */
+static int getRange(
+ icc *icp,
+// icProfileClassSignature psig, /* Profile signature to use */
+ icColorSpaceSignature csig, /* Colorspace to use. */
+// int lutin, /* 0 if this is for a icSigLut16Type input, nz for output */
+// icTagSignature tagSig, /* Tag signature involved (AtoB or B2A etc.) */
+ icTagTypeSignature tagType, /* icSigLut8Type or icSigLut16Type or V4 lut */
+ double *min, double *max /* Return range values */
+) {
+ int i, e, ee;
+
+ if (tagType == icSigLut8Type && csig == icSigLabData) {
+ csig = icmSigLab8Data;
+ }
+ if (csig == icSigLabData) {
+ if (tagType == icSigLut16Type) /* Lut16 retains legacy encoding */
+ csig = icmSigLabV2Data;
+ else { /* Other tag types use version specific encoding */
+ if (icp->ver)
+ csig = icmSigLabV4Data;
+ else
+ csig = icmSigLabV2Data;
+ }
+ }
+
+ for (i = 0; colorrangetable[i].csig != icMaxEnumData; i++) {
+ if (colorrangetable[i].csig == csig)
+ break; /* Found it */
+ }
+ if (colorrangetable[i].csig == icMaxEnumData) { /* Oops */
+ return 1;
+ }
+ ee = number_ColorSpaceSignature(csig); /* Get number of components */
+
+ if (colorrangetable[i].same) { /* All channels are the same */
+ for (e = 0; e < ee; e++) {
+ if (min != NULL)
+ min[e] = colorrangetable[i].min[0];
+ if (max != NULL)
+ max[e] = colorrangetable[i].max[0];
+ }
+ } else {
+ for (e = 0; e < ee; e++) {
+ if (min != NULL)
+ min[e] = colorrangetable[i].min[e];
+ if (max != NULL)
+ max[e] = colorrangetable[i].max[e];
+ }
+ }
+ return 0;
+}
+
+/* ============================================= */
+/* Misc. support functions. */
+
+/* Clamp a 3 vector to be +ve */
+void icmClamp3(double out[3], double in[3]) {
+ int i;
+ for (i = 0; i < 3; i++)
+ out[i] = in[i] < 0.0 ? 0.0 : in[i];
+}
+
+/* Add two 3 vectors */
+void icmAdd3(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];
+}
+
+/* Subtract two 3 vectors, out = in1 - in2 */
+void icmSub3(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];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Set a 3x3 matrix to unity */
+void icmSetUnity3x3(double mat[3][3]) {
+ int i, j;
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ if (i == j)
+ mat[j][i] = 1.0;
+ else
+ mat[j][i] = 0.0;
+ }
+ }
+
+}
+
+/* Copy a 3x3 transform matrix */
+void icmCpy3x3(double dst[3][3], double src[3][3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src[j][i];
+ }
+}
+
+/* Scale each element of a 3x3 transform matrix */
+void icmScale3x3(double dst[3][3], double src[3][3], double scale) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src[j][i] * scale;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/*
+
+ mat in out
+
+[ ] [] []
+[ ] * [] => []
+[ ] [] []
+
+ */
+
+/* Multiply 3 array by 3x3 transform matrix */
+void icmMulBy3x3(double out[3], double mat[3][3], double in[3]) {
+ double tt[3];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
+ tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Add one 3x3 to another */
+/* dst = src1 + src2 */
+void icmAdd3x3(double dst[3][3], double src1[3][3], double src2[3][3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src1[j][i] + src2[j][i];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Tensor product. Multiply two 3 vectors to form a 3x3 matrix */
+/* src1[] forms the colums, and src2[] forms the rows in the result */
+void icmTensMul3(double dst[3][3], double src1[3], double src2[3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src1[j] * src2[i];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Multiply one 3x3 with another */
+/* dst = src * dst */
+void icmMul3x3(double dst[3][3], double src[3][3]) {
+ int i, j, k;
+ double td[3][3]; /* Temporary dest */
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ double tt = 0.0;
+ for (k = 0; k < 3; k++)
+ tt += src[j][k] * dst[k][i];
+ td[j][i] = tt;
+ }
+ }
+
+ /* Copy result out */
+ for (j = 0; j < 3; j++)
+ for (i = 0; i < 3; i++)
+ dst[j][i] = td[j][i];
+}
+
+/* Multiply one 3x3 with another #2 */
+/* dst = src1 * src2 */
+void icmMul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]) {
+ int i, j, k;
+ double td[3][3]; /* Temporary dest */
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ double tt = 0.0;
+ for (k = 0; k < 3; k++)
+ tt += src1[j][k] * src2[k][i];
+ td[j][i] = tt;
+ }
+ }
+
+ /* Copy result out */
+ for (j = 0; j < 3; j++)
+ for (i = 0; i < 3; i++)
+ dst[j][i] = td[j][i];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ Matrix Inversion
+ by Richard Carling
+ from "Graphics Gems", Academic Press, 1990
+*/
+
+/*
+ * adjoint( original_matrix, inverse_matrix )
+ *
+ * calculate the adjoint of a 3x3 matrix
+ *
+ * Let a denote the minor determinant of matrix A obtained by
+ * ij
+ *
+ * deleting the ith row and jth column from A.
+ *
+ * i+j
+ * Let b = (-1) a
+ * ij ji
+ *
+ * The matrix B = (b ) is the adjoint of A
+ * ij
+ */
+
+#define det2x2(a, b, c, d) (a * d - b * c)
+
+static void adjoint(
+double out[3][3],
+double in[3][3]
+) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+
+ /* assign to individual variable names to aid */
+ /* selecting correct values */
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ /* row column labeling reversed since we transpose rows & columns */
+
+ out[0][0] = det2x2(b2, b3, c2, c3);
+ out[1][0] = - det2x2(a2, a3, c2, c3);
+ out[2][0] = det2x2(a2, a3, b2, b3);
+
+ out[0][1] = - det2x2(b1, b3, c1, c3);
+ out[1][1] = det2x2(a1, a3, c1, c3);
+ out[2][1] = - det2x2(a1, a3, b1, b3);
+
+ out[0][2] = det2x2(b1, b2, c1, c2);
+ out[1][2] = - det2x2(a1, a2, c1, c2);
+ out[2][2] = det2x2(a1, a2, b1, b2);
+}
+
+/*
+ * double = icmDet3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3 )
+ *
+ * calculate the determinant of a 3x3 matrix
+ * in the form
+ *
+ * | a1, b1, c1 |
+ * | a2, b2, c2 |
+ * | a3, b3, c3 |
+ */
+
+double icmDet3x3(double in[3][3]) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+ double ans;
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ ans = a1 * det2x2(b2, b3, c2, c3)
+ - b1 * det2x2(a2, a3, c2, c3)
+ + c1 * det2x2(a2, a3, b2, b3);
+ return ans;
+}
+
+#define ICM_SMALL_NUMBER 1.e-8
+/*
+ * inverse( original_matrix, inverse_matrix )
+ *
+ * calculate the inverse of a 4x4 matrix
+ *
+ * -1
+ * A = ___1__ adjoint A
+ * det A
+ */
+
+/* Return non-zero if not invertable */
+int icmInverse3x3(
+double out[3][3],
+double in[3][3]
+) {
+ int i, j;
+ double det;
+
+ /* calculate the 3x3 determinant
+ * if the determinant is zero,
+ * then the inverse matrix is not unique.
+ */
+ det = icmDet3x3(in);
+
+ if ( fabs(det) < ICM_SMALL_NUMBER)
+ return 1;
+
+ /* calculate the adjoint matrix */
+ adjoint(out, in);
+
+ /* scale the adjoint matrix to get the inverse */
+ for (i = 0; i < 3; i++)
+ for(j = 0; j < 3; j++)
+ out[i][j] /= det;
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Transpose a 3x3 matrix */
+void icmTranspose3x3(double out[3][3], double in[3][3]) {
+ int i, j;
+ if (out != in) {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = in[j][i];
+ } else {
+ double tt[3][3];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ tt[i][j] = in[j][i];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = tt[i][j];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the dot product of two 3 vectors */
+double icmDot3(double in1[3], double in2[3]) {
+ return in1[0] * in2[0] + in1[1] * in2[1] + in1[2] * in2[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the cross product of two 3D vectors, out = in1 x in2 */
+void icmCross3(double out[3], double in1[3], double in2[3]) {
+ double tt[3];
+ tt[0] = (in1[1] * in2[2]) - (in1[2] * in2[1]);
+ tt[1] = (in1[2] * in2[0]) - (in1[0] * in2[2]);
+ tt[2] = (in1[0] * in2[1]) - (in1[1] * in2[0]);
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the norm (length) squared of a 3 vector */
+double icmNorm3sq(double in[3]) {
+ return in[0] * in[0] + in[1] * in[1] + in[2] * in[2];
+}
+
+/* Compute the norm (length) of a 3 vector */
+double icmNorm3(double in[3]) {
+ return sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]);
+}
+
+/* Scale a 3 vector by the given ratio */
+void icmScale3(double out[3], double in[3], double rat) {
+ out[0] = in[0] * rat;
+ out[1] = in[1] * rat;
+ out[2] = in[2] * rat;
+}
+
+/* Compute a blend between in0 and in1 */
+void icmBlend3(double out[3], double in0[3], double in1[3], double bf) {
+ out[0] = (1.0 - bf) * in0[0] + bf * in1[0];
+ out[1] = (1.0 - bf) * in0[1] + bf * in1[1];
+ out[2] = (1.0 - bf) * in0[2] + bf * in1[2];
+}
+
+/* Normalise a 3 vector to the given length. Return nz if not normalisable */
+int icmNormalize3(double out[3], double in[3], double len) {
+ double tt = sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]);
+
+ if (tt < ICM_SMALL_NUMBER)
+ return 1;
+ tt = len/tt;
+ out[0] = in[0] * tt;
+ out[1] = in[1] * tt;
+ out[2] = in[2] * tt;
+ return 0;
+}
+
+/* Compute the norm (length) squared of a vector define by two points */
+double icmNorm33sq(double in1[3], double in0[3]) {
+ int j;
+ double rv;
+ for (rv = 0.0, j = 0; j < 3; j++) {
+ double tt = in1[j] - in0[j];
+ rv += tt * tt;
+ }
+ return rv;
+}
+
+/* Compute the norm (length) of a vector define by two points */
+double icmNorm33(double in1[3], double in0[3]) {
+ int j;
+ double rv;
+ for (rv = 0.0, j = 0; j < 3; j++) {
+ double tt = in1[j] - in0[j];
+ rv += tt * tt;
+ }
+ return sqrt(rv);
+}
+
+/* Scale a two point vector by the given ratio. in0[] is the origin */
+void icmScale33(double out[3], double in1[3], double in0[3], double rat) {
+ out[0] = in0[0] + (in1[0] - in0[0]) * rat;
+ out[1] = in0[1] + (in1[1] - in0[1]) * rat;
+ out[2] = in0[2] + (in1[2] - in0[2]) * rat;
+}
+
+/* Normalise a two point vector to the given length. */
+/* The new location of in1[] is returned in out[]. */
+/* Return nz if not normalisable */
+int icmNormalize33(double out[3], double in1[3], double in0[3], double len) {
+ int j;
+ double vl;
+
+ for (vl = 0.0, j = 0; j < 3; j++) {
+ double tt = in1[j] - in0[j];
+ vl += tt * tt;
+ }
+ vl = sqrt(vl);
+ if (vl < ICM_SMALL_NUMBER)
+ return 1;
+
+ vl = len/vl;
+ for (j = 0; j < 3; j++) {
+ out[j] = in0[j] + (in1[j] - in0[j]) * vl;
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given two 3D points, create a matrix that rotates */
+/* and scales one onto the other about the origin 0,0,0. */
+/* The maths is from page 52 of Tomas Moller and Eric Haines "Real-Time Rendering". */
+/* s is source vector, t is target vector. */
+/* Usage of icmRotMat: */
+/* t[0] == mat[0][0] * s[0] + mat[0][1] * s[1] + mat[0][2] * s[2]; */
+/* t[1] == mat[1][0] * s[0] + mat[1][1] * s[1] + mat[1][2] * s[2]; */
+/* t[2] == mat[2][0] * s[0] + mat[2][1] * s[1] + mat[2][2] * s[2]; */
+/* i.e. use icmMulBy3x3 */
+void icmRotMat(double m[3][3], double s[3], double t[3]) {
+ double sl, tl, sn[3], tn[3];
+ double v[3]; /* Cross product */
+ double e; /* Dot product */
+ double h; /* 1-e/Cross product dot squared */
+
+ /* Normalise input vectors */
+ /* The rotation will be about 0,0,0 */
+ sl = sqrt(s[0] * s[0] + s[1] * s[1] + s[2] * s[2]);
+ tl = sqrt(t[0] * t[0] + t[1] * t[1] + t[2] * t[2]);
+
+ if (sl < 1e-12 || tl < 1e-12) { /* Hmm. Do nothing */
+ m[0][0] = 1.0;
+ m[0][1] = 0.0;
+ m[0][2] = 0.0;
+ m[1][0] = 0.0;
+ m[1][1] = 1.0;
+ m[1][2] = 0.0;
+ m[2][0] = 0.0;
+ m[2][1] = 0.0;
+ m[2][2] = 1.0;
+ return;
+ }
+
+ sn[0] = s[0]/sl; sn[1] = s[1]/sl; sn[2] = s[2]/sl;
+ tn[0] = t[0]/tl; tn[1] = t[1]/tl; tn[2] = t[2]/tl;
+
+ /* Compute the cross product */
+ v[0] = (sn[1] * tn[2]) - (sn[2] * tn[1]);
+ v[1] = (sn[2] * tn[0]) - (sn[0] * tn[2]);
+ v[2] = (sn[0] * tn[1]) - (sn[1] * tn[0]);
+
+ /* Compute the dot product */
+ e = sn[0] * tn[0] + sn[1] * tn[1] + sn[2] * tn[2];
+
+ /* Cross product dot squared */
+ h = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
+
+ /* If the two input vectors are close to being parallel, */
+ /* then h will be close to zero. */
+ if (fabs(h) < 1e-12) {
+ m[0][0] = tl/sl;
+ m[0][1] = 0.0;
+ m[0][2] = 0.0;
+ m[1][0] = 0.0;
+ m[1][1] = tl/sl;
+ m[1][2] = 0.0;
+ m[2][0] = 0.0;
+ m[2][1] = 0.0;
+ m[2][2] = tl/sl;
+ } else {
+ /* 1-e/Cross product dot squared */
+ h = (1.0 - e) / h;
+
+ m[0][0] = tl/sl * (e + h * v[0] * v[0]);
+ m[0][1] = tl/sl * (h * v[0] * v[1] - v[2]);
+ m[0][2] = tl/sl * (h * v[0] * v[2] + v[1]);
+ m[1][0] = tl/sl * (h * v[0] * v[1] + v[2]);
+ m[1][1] = tl/sl * (e + h * v[1] * v[1]);
+ m[1][2] = tl/sl * (h * v[1] * v[2] - v[0]);
+ m[2][0] = tl/sl * (h * v[0] * v[2] - v[1]);
+ m[2][1] = tl/sl * (h * v[1] * v[2] + v[0]);
+ m[2][2] = tl/sl * (e + h * v[2] * v[2]);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Multiply 2 array by 2x2 transform matrix */
+void icmMulBy2x2(double out[2], double mat[2][2], double in[2]) {
+ double tt[2];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Copy a 3x4 transform matrix */
+void icmCpy3x4(double dst[3][4], double src[3][4]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 4; i++)
+ dst[j][i] = src[j][i];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Multiply 3 array by 3x4 transform matrix */
+void icmMul3By3x4(double out[3], double mat[3][4], double in[3]) {
+ double tt[3];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2] + mat[0][3];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2] + mat[1][3];
+ tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2] + mat[2][3];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given two 3D vectors, create a matrix that translates, */
+/* rotates and scales one onto the other. */
+/* The maths is from page 52 of Tomas Moller and Eric Haines */
+/* "Real-Time Rendering". */
+/* s0 -> s1 is source vector, t0 -> t1 is target vector. */
+/* Usage of icmRotMat: */
+/* t[0] == mat[0][0] * s[0] + mat[0][1] * s[1] + mat[0][2] * s[2] + mat[0][3]; */
+/* t[1] == mat[1][0] * s[0] + mat[1][1] * s[1] + mat[1][2] * s[2] + mat[1][3]; */
+/* t[2] == mat[2][0] * s[0] + mat[2][1] * s[1] + mat[2][2] * s[2] + mat[2][3]; */
+/* i.e. use icmMul3By3x4 */
+void icmVecRotMat(double m[3][4], double s1[3], double s0[3], double t1[3], double t0[3]) {
+ int i, j;
+ double ss[3], tt[3], rr[3][3];
+
+ /* Create the rotation matrix: */
+ for (i = 0; i < 3; i++) {
+ ss[i] = s1[i] - s0[i];
+ tt[i] = t1[i] - t0[i];
+ }
+ icmRotMat(rr, ss, tt);
+
+ /* Create rotated version of s0: */
+ icmMulBy3x3(ss, rr, s0);
+
+ /* Create 4x4 matrix */
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 4; i++) {
+ if (i < 3 && j < 3)
+ m[j][i] = rr[j][i];
+ else if (i == 3 && j < 3)
+ m[j][i] = t0[j] - ss[j];
+ else if (i == j)
+ m[j][i] = 1.0;
+ else
+ m[j][i] = 0.0;
+ }
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the 3D intersection of a vector and a plane */
+/* return nz if there is no intersection */
+int icmVecPlaneIsect(
+double isect[3], /* return intersection point */
+double pl_const, /* Plane equation constant */
+double pl_norm[3], /* Plane normal vector */
+double ve_1[3], /* Point on line */
+double ve_0[3] /* Second point on line */
+) {
+ double den; /* denominator */
+ double rv; /* Vector parameter value */
+ double vvec[3]; /* Vector vector */
+ double ival[3]; /* Intersection value */
+
+ /* Compute vector between the two points */
+ vvec[0] = ve_1[0] - ve_0[0];
+ vvec[1] = ve_1[1] - ve_0[1];
+ vvec[2] = ve_1[2] - ve_0[2];
+
+ /* Compute the denominator */
+ den = pl_norm[0] * vvec[0] + pl_norm[1] * vvec[1] + pl_norm[2] * vvec[2];
+
+ /* Too small to intersect ? */
+ if (fabs(den) < 1e-12) {
+ return 1;
+ }
+
+ /* Compute the parameterized intersction point */
+ rv = -(pl_norm[0] * ve_0[0] + pl_norm[1] * ve_0[1] + pl_norm[2] * ve_0[2] + pl_const)/den;
+
+ /* Compute the actual intersection point */
+ isect[0] = ve_0[0] + rv * vvec[0];
+ isect[1] = ve_0[1] + rv * vvec[1];
+ isect[2] = ve_0[2] + rv * vvec[2];
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the closest points between two lines a and b. */
+/* Return closest points and parameter values if not NULL. */
+/* Return nz if they are paralel. */
+/* The maths is from page 338 of Tomas Moller and Eric Haines "Real-Time Rendering". */
+int icmLineLineClosest(double ca[3], double cb[3], double *pa, double * pb,
+ double la0[3], double la1[3], double lb0[3], double lb1[3]) {
+ double va[3], vb[3];
+ double vvab[3], vvabns; /* Cross product of va and vb and its norm squared */
+ double vba0[3]; /* lb0 - la0 */
+ double tt[3];
+ double a, b; /* Parameter values */
+
+ icmSub3(va, la1, la0);
+ icmSub3(vb, lb1, lb0);
+ icmCross3(vvab, va, vb);
+ vvabns = icmNorm3sq(vvab);
+
+ if (vvabns < 1e-12)
+ return 1;
+
+ icmSub3(vba0, lb0, la0);
+ icmCross3(tt, vba0, vb);
+ a = icmDot3(tt, vvab) / vvabns;
+
+ icmCross3(tt, vba0, va);
+ b = icmDot3(tt, vvab) / vvabns;
+
+ if (pa != NULL)
+ *pa = a;
+
+ if (pb != NULL)
+ *pb = b;
+
+ if (ca != NULL) {
+ ca[0] = la0[0] + a * va[0];
+ ca[1] = la0[1] + a * va[1];
+ ca[2] = la0[2] + a * va[2];
+ }
+
+ if (cb != NULL) {
+ cb[0] = lb0[0] + b * vb[0];
+ cb[1] = lb0[1] + b * vb[1];
+ cb[2] = lb0[2] + b * vb[2];
+ }
+
+#ifdef NEVER /* Verify */
+ {
+ double vab[3]; /* Vector from ca to cb */
+
+ vab[0] = lb0[0] + b * vb[0] - la0[0] - a * va[0];
+ vab[1] = lb0[1] + b * vb[1] - la0[1] - a * va[1];
+ vab[2] = lb0[2] + b * vb[2] - la0[2] - a * va[2];
+
+ if (icmDot3(va, vab) > 1e-6
+ || icmDot3(vb, vab) > 1e-6)
+ warning("icmLineLineClosest verify failed\n");
+ }
+#endif
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given 3 3D points, compute a plane equation. */
+/* The normal will be right handed given the order of the points */
+/* The plane equation will be the 3 normal components and the constant. */
+/* Return nz if any points are cooincident or co-linear */
+int icmPlaneEqn3(double eq[4], double p0[3], double p1[3], double p2[3]) {
+ double ll, v1[3], v2[3];
+
+ /* Compute vectors along edges */
+ v2[0] = p1[0] - p0[0];
+ v2[1] = p1[1] - p0[1];
+ v2[2] = p1[2] - p0[2];
+
+ v1[0] = p2[0] - p0[0];
+ v1[1] = p2[1] - p0[1];
+ v1[2] = p2[2] - p0[2];
+
+ /* Compute cross products v1 x v2, which will be the normal */
+ eq[0] = v1[1] * v2[2] - v1[2] * v2[1];
+ eq[1] = v1[2] * v2[0] - v1[0] * v2[2];
+ eq[2] = v1[0] * v2[1] - v1[1] * v2[0];
+
+ /* Normalise the equation */
+ ll = sqrt(eq[0] * eq[0] + eq[1] * eq[1] + eq[2] * eq[2]);
+ if (ll < 1e-10) {
+ return 1;
+ }
+ eq[0] /= ll;
+ eq[1] /= ll;
+ eq[2] /= ll;
+
+ /* Compute the plane equation constant */
+ eq[3] = - (eq[0] * p0[0])
+ - (eq[1] * p0[1])
+ - (eq[2] * p0[2]);
+
+ return 0;
+}
+
+/* Given a 3D point and a plane equation, return the signed */
+/* distance from the plane */
+double icmPlaneDist3(double eq[4], double p[3]) {
+ double rv;
+
+ rv = eq[0] * p[0]
+ + eq[1] * p[1]
+ + eq[2] * p[2]
+ + eq[3];
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* CIE Y (range 0 .. 1) to perceptual CIE 1976 L* (range 0 .. 100) */
+double
+icmY2L(double val) {
+ if (val > 0.008856451586)
+ val = pow(val,1.0/3.0);
+ else
+ val = 7.787036979 * val + 16.0/116.0;
+
+ val = (116.0 * val - 16.0);
+ return val;
+}
+
+/* Perceptual CIE 1976 L* (range 0 .. 100) to CIE Y (range 0 .. 1) */
+double
+icmL2Y(double val) {
+ val = (val + 16.0)/116.0;
+
+ if (val > 24.0/116.0)
+ val = pow(val,3.0);
+ else
+ val = (val - 16.0/116.0)/7.787036979;
+ return val;
+}
+
+/* CIE XYZ to perceptual CIE 1976 L*a*b* */
+void
+icmXYZ2Lab(icmXYZNumber *w, double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/w->X;
+ y = Y/w->Y;
+ z = Z/w->Z;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+/* Perceptual CIE 1976 L*a*b* to CIE XYZ */
+void
+icmLab2XYZ(icmXYZNumber *w, double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+
+ fy = (L + 16.0)/116.0;
+ fx = a/500.0 + fy;
+ fz = fy - b/200.0;
+
+ if (fy > 24.0/116.0)
+ y = pow(fy,3.0);
+ else
+ y = (fy - 16.0/116.0)/7.787036979;
+
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ out[0] = x * w->X;
+ out[1] = y * w->Y;
+ out[2] = z * w->Z;
+}
+
+
+/* LCh to Lab */
+void icmLCh2Lab(double *out, double *in) {
+ double C, h;
+
+ C = in[1];
+ h = 3.14159265359/180.0 * in[2];
+
+ out[0] = in[0];
+ out[1] = C * cos(h);
+ out[2] = C * sin(h);
+}
+
+/* Lab to LCh */
+void icmLab2LCh(double *out, double *in) {
+ double C, h;
+
+ C = sqrt(in[1] * in[1] + in[2] * in[2]);
+
+ h = (180.0/3.14159265359) * atan2(in[2], in[1]);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ out[0] = in[0];
+ out[1] = C;
+ out[2] = h;
+}
+
+/* XYZ to Yxy */
+extern ICCLIB_API void icmXYZ2Yxy(double *out, double *in) {
+ double sum = in[0] + in[1] + in[2];
+ double Y, x, y;
+
+ if (sum < 1e-9) {
+ Y = 0.0;
+ y = 0.333333333;
+ x = 0.333333333;
+ } else {
+ Y = in[1];
+ x = in[0]/sum;
+ y = in[1]/sum;
+ }
+ out[0] = Y;
+ out[1] = x;
+ out[2] = y;
+}
+
+/* Yxy to XYZ */
+extern ICCLIB_API void icmYxy2XYZ(double *out, double *in) {
+ double Y = in[0];
+ double x = in[1];
+ double y = in[2];
+ double z = 1.0 - x - y;
+ double sum;
+ if (y < 1e-9) {
+ out[0] = out[1] = out[2] = 0.0;
+ } else {
+ sum = Y/y;
+ out[0] = x * sum;
+ out[1] = Y;
+ out[2] = z * sum;
+ }
+}
+
+
+/* CIE XYZ to perceptual CIE 1976 L*u*v* */
+extern ICCLIB_API void icmXYZ2Luv(icmXYZNumber *w, double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double un, vn, u, v, fl, fu, fv;
+
+ un = (4.0 * w->X) / (w->X + 15.0 * w->Y + 3.0 * w->Z);
+ vn = (9.0 * w->Y) / (w->X + 15.0 * w->Y + 3.0 * w->Z);
+ u = (4.0 * X) / (X + 15.0 * Y + 3.0 * Z);
+ v = (9.0 * Y) / (X + 15.0 * Y + 3.0 * Z);
+
+ Y /= w->Y;
+
+ if (Y > 0.008856451586)
+ fl = pow(Y,1.0/3.0);
+ else
+ fl = 7.787036979 * Y + 16.0/116.0;
+
+ fu = u - un;
+ fv = v - vn;
+
+ out[0] = 116.0 * fl - 16.0;
+ out[1] = 13.0 * out[0] * fu;
+ out[2] = 13.0 * out[0] * fv;
+}
+
+/* Perceptual CIE 1976 L*u*v* to CIE XYZ */
+extern ICCLIB_API void icmLuv2XYZ(icmXYZNumber *w, double *out, double *in) {
+ double un, vn, u, v, fl, fu, fv, sum, X, Y, Z;
+
+ fl = (in[0] + 16.0)/116.0;
+ fu = in[1] / (13.0 * in[0]);
+ fv = in[2] / (13.0 * in[0]);
+
+ un = (4.0 * w->X) / (w->X + 15.0 * w->Y + 3.0 * w->Z);
+ vn = (9.0 * w->Y) / (w->X + 15.0 * w->Y + 3.0 * w->Z);
+
+ u = fu + un;
+ v = fv + vn;
+
+ if (fl > 24.0/116.0)
+ Y = pow(fl,3.0);
+ else
+ Y = (fl - 16.0/116.0)/7.787036979;
+ Y *= w->Y;
+
+ sum = (9.0 * Y)/v;
+ X = (u * sum)/4.0;
+ Z = (sum - X - 15.0 * Y)/3.0;
+
+ out[0] = X;
+ out[1] = Y;
+ out[2] = Z;
+}
+
+/* NOTE :- none of the following seven have been protected */
+/* against arithmmetic issues (ie. for black) */
+
+/* CIE XYZ to perceptual CIE 1976 UCS diagram Yu'v'*/
+/* (Yu'v' is a better chromaticity space than Yxy) */
+extern ICCLIB_API void icmXYZ21976UCS(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double den, u, v;
+
+ den = (X + 15.0 * Y + 3.0 * Z);
+ u = (4.0 * X) / den;
+ v = (9.0 * Y) / den;
+
+ out[0] = Y;
+ out[1] = u;
+ out[2] = v;
+}
+
+/* Perceptual CIE 1976 UCS diagram Yu'v' to CIE XYZ */
+extern ICCLIB_API void icm1976UCS2XYZ(double *out, double *in) {
+ double u, v, fl, fu, fv, sum, X, Y, Z;
+
+ Y = in[0];
+ u = in[1];
+ v = in[2];
+
+ X = ((9.0 * u * Y)/(4.0 * v));
+ Z = -(((20.0 * v + 3.0 * u - 12.0) * Y)/(4.0 * v));
+
+ out[0] = X;
+ out[1] = Y;
+ out[2] = Z;
+}
+
+/* CIE XYZ to perceptual CIE 1960 UCS */
+/* (This was obsoleted by the 1976UCS, but is still used */
+/* in computing color temperatures.) */
+extern ICCLIB_API void icmXYZ21960UCS(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double u, v;
+
+ u = (4.0 * X) / (X + 15.0 * Y + 3.0 * Z);
+ v = (6.0 * Y) / (X + 15.0 * Y + 3.0 * Z);
+
+ out[0] = Y;
+ out[1] = u;
+ out[2] = v;
+}
+
+/* Perceptual CIE 1960 UCS to CIE XYZ */
+extern ICCLIB_API void icm1960UCS2XYZ(double *out, double *in) {
+ double u, v, fl, fu, fv, sum, X, Y, Z;
+
+ Y = in[0];
+ u = in[1];
+ v = in[2];
+
+ X = ((3.0 * u * Y)/(2.0 * v));
+ Z = -(((10.0 * v + u - 4.0) * Y)/(2.0 * v));
+
+ out[0] = X;
+ out[1] = Y;
+ out[2] = Z;
+}
+
+/* CIE XYZ to perceptual CIE 1964 WUV (U*V*W*) */
+/* (This is obsolete but still used in computing CRI) */
+extern ICCLIB_API void icmXYZ21964WUV(icmXYZNumber *w, double *out, double *in) {
+ double W, U, V;
+ double wucs[3];
+ double iucs[3];
+
+ icmXYZ2Ary(wucs, *w);
+ icmXYZ21960UCS(wucs, wucs);
+ icmXYZ21960UCS(iucs, in);
+
+ W = 25.0 * pow(iucs[0] * 100.0/wucs[0], 1.0/3.0) - 17.0;
+ U = 13.0 * W * (iucs[1] - wucs[1]);
+ V = 13.0 * W * (iucs[2] - wucs[2]);
+
+ out[0] = W;
+ out[1] = U;
+ out[2] = V;
+}
+
+/* Perceptual CIE 1964 WUV (U*V*W*) to CIE XYZ */
+extern ICCLIB_API void icm1964WUV2XYZ(icmXYZNumber *w, double *out, double *in) {
+ double W, U, V;
+ double wucs[3];
+ double iucs[3];
+
+ icmXYZ2Ary(wucs, *w);
+ icmXYZ21960UCS(wucs, wucs);
+
+ W = in[0];
+ U = in[1];
+ V = in[2];
+
+ iucs[0] = pow((W + 17.0)/25.0, 3.0) * wucs[0]/100.0;
+ iucs[1] = U / (13.0 * W) + wucs[1];
+ iucs[2] = V / (13.0 * W) + wucs[2];
+
+ icm1960UCS2XYZ(out, iucs);
+}
+
+/* CIE CIE1960 UCS to perceptual CIE 1964 WUV (U*V*W*) */
+extern ICCLIB_API void icm1960UCS21964WUV(icmXYZNumber *w, double *out, double *in) {
+ double W, U, V;
+ double wucs[3];
+
+ icmXYZ2Ary(wucs, *w);
+ icmXYZ21960UCS(wucs, wucs);
+
+ W = 25.0 * pow(in[0] * 100.0/wucs[0], 1.0/3.0) - 17.0;
+ U = 13.0 * W * (in[1] - wucs[1]);
+ V = 13.0 * W * (in[2] - wucs[2]);
+
+ out[0] = W;
+ out[1] = U;
+ out[2] = V;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* available D50 Illuminant */
+icmXYZNumber icmD50 = { /* Profile illuminant - D50 */
+ 0.9642, 1.0000, 0.8249
+};
+
+icmXYZNumber icmD50_100 = { /* Profile illuminant - D50, scaled to 100 */
+ 96.42, 100.00, 82.49
+};
+
+double icmD50_ary3[3] = { /* Profile illuminant - D50 */
+ 0.9642, 1.0000, 0.8249
+};
+
+double icmD50_100_ary3[3] = { /* Profile illuminant - D50, scaled to 100 */
+ 96.42, 100.00, 82.49
+};
+
+/* available D65 Illuminant */
+icmXYZNumber icmD65 = { /* Profile illuminant - D65 */
+ 0.9505, 1.0000, 1.0890
+};
+
+icmXYZNumber icmD65_100 = { /* Profile illuminant - D65, scaled to 100 */
+ 95.05, 100.00, 108.90
+};
+
+double icmD65_ary3[3] = { /* Profile illuminant - D65 */
+ 0.9505, 1.0000, 1.0890
+};
+
+double icmD65_100_ary3[3] = { /* Profile illuminant - D65, scaled to 100 */
+ 95.05, 100.00, 108.90
+};
+
+/* Default black point */
+icmXYZNumber icmBlack = {
+ 0.0000, 0.0000, 0.0000
+};
+
+/* Return the normal Delta E given two Lab values */
+double icmLabDE(double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ rv += tt * tt;
+
+ return sqrt(rv);
+}
+
+/* Return the normal Delta E squared, given two Lab values */
+double icmLabDEsq(double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ rv += tt * tt;
+
+ return rv;
+}
+
+/* Return the normal Delta E given two XYZ values */
+extern ICCLIB_API double icmXYZLabDE(icmXYZNumber *w, double *in0, double *in1) {
+ double lab0[3], lab1[3], rv;
+
+ icmXYZ2Lab(w, lab0, in0);
+ icmXYZ2Lab(w, lab1, in1);
+ rv = icmLabDE(lab0, lab1);
+ return rv;
+}
+
+/* (Note that CIE94 can give odd results for very large delta E's, */
+/* when one of the two points is near the neutral axis: */
+/* ie DE(A,B + del) != DE(A,B) + DE(del) */
+#ifdef NEVER
+{
+ double w1[3] = { 99.996101, -0.058417, -0.010557 };
+ double c1[3] = { 60.267956, 98.845863, -61.163277 };
+ double w2[3] = { 100.014977, -0.138339, 0.089744 };
+ double c2[3] = { 60.294464, 98.117104, -60.843159 };
+
+ printf("DE 1 = %f, 2 = %f\n", icmLabDE(c1, w1), icmLabDE(c2, w2));
+ printf("DE94 1 = %f, 2 = %f\n", icmCIE94(c1, w1), icmCIE94(c2, w2));
+}
+#endif
+
+
+/* Return the CIE94 Delta E color difference measure, squared */
+double icmCIE94sq(double Lab0[3], double Lab1[3]) {
+ double desq, dhsq;
+ double dlsq, dcsq;
+ double c12;
+
+ {
+ double dl, da, db;
+ dl = Lab0[0] - Lab1[0];
+ dlsq = dl * dl; /* dl squared */
+ da = Lab0[1] - Lab1[1];
+ db = Lab0[2] - Lab1[2];
+
+ /* Compute normal Lab delta E squared */
+ desq = dlsq + da * da + db * db;
+ }
+
+ {
+ double c1, c2, dc;
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ c2 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ c12 = sqrt(c1 * c2); /* Symetric chromanance */
+
+ /* delta chromanance squared */
+ dc = c2 - c1;
+ dcsq = dc * dc;
+ }
+
+ /* Compute delta hue squared */
+ if ((dhsq = desq - dlsq - dcsq) < 0.0)
+ dhsq = 0.0;
+ {
+ double sc, sh;
+
+ /* Weighting factors for delta chromanance & delta hue */
+ sc = 1.0 + 0.048 * c12;
+ sh = 1.0 + 0.014 * c12;
+ return dlsq + dcsq/(sc * sc) + dhsq/(sh * sh);
+ }
+}
+
+/* Return the CIE94 Delta E color difference measure */
+double icmCIE94(double Lab0[3], double Lab1[3]) {
+ return sqrt(icmCIE94sq(Lab0, Lab1));
+}
+
+/* Return the CIE94 Delta E color difference measure for two XYZ values */
+extern ICCLIB_API double icmXYZCIE94(icmXYZNumber *w, double *in0, double *in1) {
+ double lab0[3], lab1[3];
+
+ icmXYZ2Lab(w, lab0, in0);
+ icmXYZ2Lab(w, lab1, in1);
+ return sqrt(icmCIE94sq(lab0, lab1));
+}
+
+
+/* From the paper "The CIEDE2000 Color-Difference Formula: Implementation Notes, */
+/* Supplementary Test Data, and Mathematical Observations", by */
+/* Gaurav Sharma, Wencheng Wu and Edul N. Dalal, */
+/* Color Res. Appl., vol. 30, no. 1, pp. 21-30, Feb. 2005. */
+
+/* Return the CIEDE2000 Delta E color difference measure squared, for two Lab values */
+double icmCIE2Ksq(double *Lab0, double *Lab1) {
+ double C1, C2;
+ double h1, h2;
+ double dL, dC, dH;
+ double dsq;
+
+ /* The trucated value of PI is needed to ensure that the */
+ /* test cases pass, as one of them lies on the edge of */
+ /* a mathematical discontinuity. The precision is still */
+ /* enough for any practical use. */
+#define RAD2DEG(xx) (180.0/3.14159265358979 * (xx))
+#define DEG2RAD(xx) (3.14159265358979/180.0 * (xx))
+
+ /* Compute Cromanance and Hue angles */
+ {
+ double C1ab, C2ab;
+ double Cab, Cab7, G;
+ double a1, a2;
+
+ C1ab = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ C2ab = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ Cab = 0.5 * (C1ab + C2ab);
+ Cab7 = pow(Cab,7.0);
+ G = 0.5 * (1.0 - sqrt(Cab7/(Cab7 + 6103515625.0)));
+ a1 = (1.0 + G) * Lab0[1];
+ a2 = (1.0 + G) * Lab1[1];
+ C1 = sqrt(a1 * a1 + Lab0[2] * Lab0[2]);
+ C2 = sqrt(a2 * a2 + Lab1[2] * Lab1[2]);
+
+ if (C1 < 1e-9)
+ h1 = 0.0;
+ else {
+ h1 = RAD2DEG(atan2(Lab0[2], a1));
+ if (h1 < 0.0)
+ h1 += 360.0;
+ }
+
+ if (C2 < 1e-9)
+ h2 = 0.0;
+ else {
+ h2 = RAD2DEG(atan2(Lab1[2], a2));
+ if (h2 < 0.0)
+ h2 += 360.0;
+ }
+ }
+
+ /* Compute delta L, C and H */
+ {
+ double dh;
+
+ dL = Lab1[0] - Lab0[0];
+ dC = C2 - C1;
+ if (C1 < 1e-9 || C2 < 1e-9) {
+ dh = 0.0;
+ } else {
+ dh = h2 - h1;
+ if (dh > 180.0)
+ dh -= 360.0;
+ else if (dh < -180.0)
+ dh += 360.0;
+ }
+
+ dH = 2.0 * sqrt(C1 * C2) * sin(DEG2RAD(0.5 * dh));
+ }
+
+ {
+ double L, C, h, T;
+ double hh, ddeg;
+ double C7, RC, L50sq, SL, SC, SH, RT;
+ double dLsq, dCsq, dHsq, RCH;
+
+ L = 0.5 * (Lab0[0] + Lab1[0]);
+ C = 0.5 * (C1 + C2);
+ if (C1 < 1e-9 || C2 < 1e-9) {
+ h = h1 + h2;
+ } else {
+ h = h1 + h2;
+ if (fabs(h1 - h2) > 180.0) {
+ if (h < 360.0)
+ h += 360.0;
+ else if (h >= 360.0)
+ h -= 360.0;
+ }
+ h *= 0.5;
+ }
+ T = 1.0 - 0.17 * cos(DEG2RAD(h-30.0)) + 0.24 * cos(DEG2RAD(2.0 * h))
+ + 0.32 * cos(DEG2RAD(3.0 * h + 6.0)) - 0.2 * cos(DEG2RAD(4.0 * h - 63.0));
+ hh = (h - 275.0)/25.0;
+ ddeg = 30.0 * exp(-hh * hh);
+ C7 = pow(C,7.0);
+ RC = 2.0 * sqrt(C7/(C7 + 6103515625.0));
+ L50sq = (L - 50.0) * (L - 50.0);
+ SL = 1.0 + (0.015 * L50sq)/sqrt(20.0 + L50sq);
+ SC = 1.0 + 0.045 * C;
+ SH = 1.0 + 0.015 * C * T;
+ RT = -sin(DEG2RAD(2 * ddeg)) * RC;
+
+ dLsq = dL/SL;
+ dCsq = dC/SC;
+ dHsq = dH/SH;
+
+ RCH = RT * dCsq * dHsq;
+
+ dLsq *= dLsq;
+ dCsq *= dCsq;
+ dHsq *= dHsq;
+
+ dsq = dLsq + dCsq + dHsq + RCH;
+ }
+
+ return dsq;
+
+#undef RAD2DEG
+#undef DEG2RAD
+}
+
+/* Return the CIE2DE000 Delta E color difference measure for two Lab values */
+double icmCIE2K(double *Lab0, double *Lab1) {
+ return sqrt(icmCIE2Ksq(Lab0, Lab1));
+}
+
+/* Return the CIEDE2000 Delta E color difference measure for two XYZ values */
+extern ICCLIB_API double icmXYZCIE2K(icmXYZNumber *w, double *in0, double *in1) {
+ double lab0[3], lab1[3];
+
+ icmXYZ2Lab(w, lab0, in0);
+ icmXYZ2Lab(w, lab1, in1);
+ return sqrt(icmCIE2Ksq(lab0, lab1));
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Chromatic adaptation transform utility */
+/* Return a 3x3 chromatic adaptation matrix */
+/* Use icmMulBy3x3(dst, mat, src) */
+void icmChromAdaptMatrix(
+ int flags, /* Use bradford, Transform given matrix flags */
+ icmXYZNumber d_wp, /* Destination white point */
+ icmXYZNumber s_wp, /* Source white point */
+ double mat[3][3] /* Destination matrix */
+) {
+ double dst[3], src[3]; /* Source & destination white points */
+ double vkmat[3][3]; /* Von Kries matrix */
+#ifdef NEVER
+ static double bradford[3][3] = { /* Linear cone space matrix */
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+#endif /* NEVER */
+ static double bradford[3][3] = { /* Bradford cone space matrix */
+ { 0.8951, 0.2664, -0.1614 },
+ { -0.7502, 1.7135, 0.0367 },
+ { 0.0389, -0.0685, 1.0296 }
+ };
+ static int inited = 0; /* Compute inverse bradford once */
+ static double ibradford[3][3]; /* Inverse Bradford */
+
+ /* Set initial matrix to unity */
+ if (!(flags & ICM_CAM_MULMATRIX)) {
+ icmSetUnity3x3(mat);
+ }
+
+ icmXYZ2Ary(src, s_wp);
+ icmXYZ2Ary(dst, d_wp);
+
+ if (flags & ICM_CAM_BRADFORD) {
+ icmMulBy3x3(src, bradford, src);
+ icmMulBy3x3(dst, bradford, dst);
+ }
+
+ /* Setup the Von Kries white point adaptation matrix */
+ vkmat[0][0] = dst[0]/src[0];
+ vkmat[1][1] = dst[1]/src[1];
+ vkmat[2][2] = dst[2]/src[2];
+ vkmat[0][1] = vkmat[0][2] = 0.0;
+ vkmat[1][0] = vkmat[1][2] = 0.0;
+ vkmat[2][0] = vkmat[2][1] = 0.0;
+
+ /* Transform to Bradford space if requested */
+ if (flags & ICM_CAM_BRADFORD) {
+ icmMul3x3(mat, bradford);
+ }
+
+ /* Apply chromatic adaptation */
+ icmMul3x3(mat, vkmat);
+
+ /* Transform from Bradford space */
+ if (flags & ICM_CAM_BRADFORD) {
+ if (inited == 0) {
+ icmInverse3x3(ibradford, bradford);
+ inited = 1;
+ }
+ icmMul3x3(mat, ibradford);
+ }
+
+ /* We're done */
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* RGB primaries device to RGB->XYZ transform matrix. */
+/* We assume that the device is perfectly additive, but that */
+/* there may be a scale factor applied to the channels to */
+/* match the white point at RGB = 1. */
+
+/* Return non-zero if matrix would be singular */
+int icmRGBprim2matrix(
+ icmXYZNumber white, /* White point */
+ icmXYZNumber red, /* Red colorant */
+ icmXYZNumber green, /* Green colorant */
+ icmXYZNumber blue, /* Blue colorant */
+ double mat[3][3] /* Destination matrix */
+) {
+ double tmat[3][3];
+ double t[3];
+
+ /* Assemble the colorants into a matrix */
+ tmat[0][0] = red.X;
+ tmat[0][1] = green.X;
+ tmat[0][2] = blue.X;
+ tmat[1][0] = red.Y;
+ tmat[1][1] = green.Y;
+ tmat[1][2] = blue.Y;
+ tmat[2][0] = red.Z;
+ tmat[2][1] = green.Z;
+ tmat[2][2] = blue.Z;
+
+ /* Compute the inverse */
+ if (icmInverse3x3(mat, tmat))
+ return 1;
+
+ /* Compute scale vector that maps colorants to white point */
+ t[0] = mat[0][0] * white.X
+ + mat[0][1] * white.Y
+ + mat[0][2] * white.Z;
+ t[1] = mat[1][0] * white.X
+ + mat[1][1] * white.Y
+ + mat[1][2] * white.Z;
+ t[2] = mat[2][0] * white.X
+ + mat[2][1] * white.Y
+ + mat[2][2] * white.Z;
+
+ /* Now formulate the transform matrix */
+ mat[0][0] = red.X * t[0];
+ mat[0][1] = green.X * t[1];
+ mat[0][2] = blue.X * t[2];
+ mat[1][0] = red.Y * t[0];
+ mat[1][1] = green.Y * t[1];
+ mat[1][2] = blue.Y * t[2];
+ mat[2][0] = red.Z * t[0];
+ mat[2][1] = green.Z * t[1];
+ mat[2][2] = blue.Z * t[2];
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Some PCS utility functions */
+
+/* Clip Lab, while maintaining hue angle. */
+/* Return nz if clipping occured */
+int icmClipLab(double out[3], double in[3]) {
+ double C;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+
+ if (out[0] >= 0.0 && out[0] <= 100.0
+ && out[1] >= -128.0 && out[1] <= 127.0
+ && out[2] >= -128.0 && out[2] <= 127.0)
+ return 0;
+
+ /* Clip L */
+ if (out[0] < 0.0)
+ out[0] = 0.0;
+ else if (out[0] > 100.0)
+ out[0] = 100.0;
+
+ C = out[1];
+ if (fabs(out[2]) > fabs(C))
+ C = out[2];
+ if (C < -128.0 || C > 127.0) {
+ if (C < 0.0)
+ C = -128.0/C;
+ else
+ C = 127.0/C;
+ out[1] *= C;
+ out[2] *= C;
+ }
+
+ return 1;
+}
+
+/* Clip XYZ, while maintaining hue angle */
+/* Return nz if clipping occured */
+int icmClipXYZ(double out[3], double in[3]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+
+ if (out[0] >= 0.0 && out[0] <= 1.9999
+ && out[1] >= 0.0 && out[1] <= 1.9999
+ && out[2] >= 0.0 && out[2] <= 1.9999)
+ return 0;
+
+ /* Clip Y and scale X and Z similarly */
+
+ if (out[1] > 1.9999) {
+ out[0] *= 1.9999/out[1];
+ out[2] *= 1.9999/out[1];
+ out[1] = 1.9999;
+ } else if (out[1] < 0.0) {
+ out[0] = 0.0;
+ out[1] = 0.0;
+ out[2] = 0.0;
+ }
+
+ if (out[0] < 0.0 || out[0] > 1.9999
+ || out[2] < 0.0 || out[2] > 1.9999) {
+ double D50[3] = { 0.9642, 1.0000, 0.8249 };
+ double bb = 0.0;
+
+ /* Scale the D50 so that it has the same Y value as our color */
+ D50[0] *= out[1];
+ D50[1] *= out[1];
+ D50[2] *= out[1];
+
+ /* Figure out what blend factor with Y scaled D50, brings our */
+ /* color X and Z values into range */
+
+ if (out[0] < 0.0) {
+ double b;
+ b = (0.0 - out[0])/(D50[0] - out[0]);
+ if (b > bb)
+ bb = b;
+ } else if (out[0] > 1.9999) {
+ double b;
+ b = (1.9999 - out[0])/(D50[0] - out[0]);
+ if (b > bb)
+ bb = b;
+ }
+ if (out[2] < 0.0) {
+ double b;
+ b = (0.0 - out[2])/(D50[2] - out[2]);
+ if (b > bb)
+ bb = b;
+ } else if (out[2] > 1.9999) {
+ double b;
+ b = (1.9999 - out[2])/(D50[2] - out[2]);
+ if (b > bb)
+ bb = b;
+ }
+ /* Do the desaturation */
+ out[0] = D50[0] * bb + (1.0 - bb) * out[0];
+ out[2] = D50[2] * bb + (1.0 - bb) * out[2];
+ }
+ return 1;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Object for computing RFC 1321 MD5 checksums. */
+/* Derived from Colin Plumb's 1993 public domain code. */
+
+/* Reset the checksum */
+static void icmMD5_reset(icmMD5 *p) {
+ p->tlen = 0;
+
+ p->sum[0] = 0x67452301;
+ p->sum[1] = 0xefcdab89;
+ p->sum[2] = 0x98badcfe;
+ p->sum[3] = 0x10325476;
+
+ p->fin = 0;
+}
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, pp, xtra, s) \
+ data = (pp)[0] + ((pp)[3] << 24) + ((pp)[2] << 16) + ((pp)[1] << 8); \
+ w += f(x, y, z) + data + xtra; \
+ w = (w << s) | (w >> (32-s)); \
+ w += x;
+
+/* Add another 64 bytes to the checksum */
+static void icmMD5_accume(icmMD5 *p, ORD8 *in) {
+ ORD32 data, a, b, c, d;
+
+ a = p->sum[0];
+ b = p->sum[1];
+ c = p->sum[2];
+ d = p->sum[3];
+
+ MD5STEP(F1, a, b, c, d, in + (4 * 0), 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 1), 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 2), 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 3), 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 4), 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 5), 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 6), 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 7), 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 8), 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 9), 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 10), 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 11), 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 12), 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 13), 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 14), 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 15), 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in + (4 * 1), 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 6), 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 11), 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 0), 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 5), 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 10), 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 15), 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 4), 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 9), 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 14), 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 3), 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 8), 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 13), 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 2), 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 7), 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 12), 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in + (4 * 5), 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 8), 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 11), 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 14), 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 1), 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 4), 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 7), 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 10), 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 13), 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 0), 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 3), 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 6), 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 9), 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 12), 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 15), 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 2), 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in + (4 * 0), 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 7), 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 14), 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 5), 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 12), 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 3), 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 10), 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 1), 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 8), 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 15), 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 6), 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 13), 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 4), 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 11), 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 2), 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 9), 0xeb86d391, 21);
+
+ p->sum[0] += a;
+ p->sum[1] += b;
+ p->sum[2] += c;
+ p->sum[3] += d;
+}
+
+#undef F1
+#undef F2
+#undef F3
+#undef F4
+#undef MD5STEP
+
+/* Add some bytes */
+static void icmMD5_add(icmMD5 *p, ORD8 *ibuf, unsigned int len) {
+ unsigned int bs;
+
+ if (p->fin)
+ return; /* This is actually an error */
+
+ bs = p->tlen; /* Current bytes added */
+ p->tlen = bs + len; /* Update length after adding this buffer */
+ bs &= 0x3f; /* Bytes already in buffer */
+
+ /* Deal with any existing partial bytes in p->buf */
+ if (bs) {
+ ORD8 *np = (ORD8 *)p->buf + bs; /* Next free location in partial buffer */
+
+ bs = 64 - bs; /* Free space in partial buffer */
+
+ if (len < bs) { /* Not enought new to make a full buffer */
+ memmove(np, ibuf, len);
+ return;
+ }
+
+ memmove(np, ibuf, bs); /* Now got one full buffer */
+ icmMD5_accume(p, np);
+ ibuf += bs;
+ len -= bs;
+ }
+
+ /* Deal with input data 64 bytes at a time */
+ while (len >= 64) {
+ icmMD5_accume(p, ibuf);
+ ibuf += 64;
+ len -= 64;
+ }
+
+ /* Deal with any remaining bytes */
+ memmove(p->buf, ibuf, len);
+}
+
+/* Finalise the checksum and return the result. */
+static void icmMD5_get(icmMD5 *p, ORD8 chsum[16]) {
+ int i;
+ unsigned count;
+ ORD32 bits1, bits0;
+ ORD8 *pp;
+
+ if (p->fin == 0) {
+
+ /* Compute number of bytes processed mod 64 */
+ count = p->tlen & 0x3f;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ pp = p->buf + count;
+ *pp++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64, allowing 8 bytes for length in bits. */
+ if (count < 8) { /* Not enough space for padding and length */
+
+ memset(pp, 0, count);
+ icmMD5_accume(p, p->buf);
+
+ /* Now fill the next block with 56 bytes */
+ memset(p->buf, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(pp, 0, count - 8);
+ }
+
+ /* Compute number of bits */
+ bits1 = 0x7 & (p->tlen >> (32 - 3));
+ bits0 = p->tlen << 3;
+
+ /* Append number of bits */
+ p->buf[64 - 8] = bits0 & 0xff;
+ p->buf[64 - 7] = (bits0 >> 8) & 0xff;
+ p->buf[64 - 6] = (bits0 >> 16) & 0xff;
+ p->buf[64 - 5] = (bits0 >> 24) & 0xff;
+ p->buf[64 - 4] = bits1 & 0xff;
+ p->buf[64 - 3] = (bits1 >> 8) & 0xff;
+ p->buf[64 - 2] = (bits1 >> 16) & 0xff;
+ p->buf[64 - 1] = (bits1 >> 24) & 0xff;
+
+ icmMD5_accume(p, p->buf);
+
+ p->fin = 1;
+ }
+
+ /* Return the result, lsb to msb */
+ pp = chsum;
+ for (i = 0; i < 4; i++) {
+ *pp++ = p->sum[i] & 0xff;
+ *pp++ = (p->sum[i] >> 8) & 0xff;
+ *pp++ = (p->sum[i] >> 16) & 0xff;
+ *pp++ = (p->sum[i] >> 24) & 0xff;
+ }
+}
+
+
+/* Delete the instance */
+static void icmMD5_del(icmMD5 *p) {
+ p->al->free(p->al, p);
+}
+
+/* Create a new MD5 checksumming object, with a reset checksum value */
+/* Return it or NULL if there is an error */
+icmMD5 *new_icmMD5(icmAlloc *al) {
+ icmMD5 *p;
+
+ if ((p = (icmMD5 *)al->calloc(al,1,sizeof(icmMD5))) == NULL)
+ return NULL;
+
+ p->al = al;
+ p->reset = icmMD5_reset;
+ p->add = icmMD5_add;
+ p->get = icmMD5_get;
+ p->del = icmMD5_del;
+
+ p->reset(p);
+
+ return p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Dumy icmFile used to compute MD5 checksum on write */
+
+/* Get the size of the file (Only valid for reading file. */
+static size_t icmFileMD5_get_size(icmFile *pp) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+
+ return p->size;
+}
+
+/* Set current position to offset. Return 0 on success, nz on failure. */
+/* Seek can't be supported for MD5, so and seek must be to current location. */
+static int icmFileMD5_seek(
+icmFile *pp,
+unsigned int offset
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+
+ if (p->of != offset) {
+ p->errc = 1;
+ }
+ if (p->of > p->size)
+ p->size = p->of;
+ return 0;
+}
+
+/* Read count items of size length. Return number of items successfully read. */
+/* Read is not implemented */
+static size_t icmFileMD5_read(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ return 0;
+}
+
+/* write count items of size length. Return number of items successfully written. */
+/* Simply pass to MD5 to compute checksum */
+static size_t icmFileMD5_write(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+ size_t len = size * count;
+
+ p->md5->add(p->md5, (ORD8 *)buffer, len);
+ p->of += len;
+ if (p->of > p->size)
+ p->size = p->of;
+ return count;
+}
+
+/* do a printf */
+/* Not implemented */
+static int icmFileMD5_printf(
+icmFile *pp,
+const char *format,
+...
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+ p->errc = 2;
+ return 0;
+}
+
+/* flush all write data out to secondary storage. Return nz on failure. */
+static int icmFileMD5_flush(
+icmFile *pp
+) {
+ return 0;
+}
+
+/* we're done with the file object, return nz on failure */
+static int icmFileMD5_delete(
+icmFile *pp
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+
+ p->al->free(p->al, p); /* Free object */
+ return 0;
+}
+
+/* Return the error code. Error code will usually be set */
+/* if we did a seek to other than the current location, */
+/* or did a printf. */
+static int icmFileMD5_geterrc(
+icmFile *pp
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+
+ return p->errc;
+}
+
+/* Create a checksum dump file access class with allocator */
+icmFile *new_icmFileMD5_a(
+icmMD5 *md5, /* MD5 object to use */
+icmAlloc *al /* heap allocator */
+) {
+ icmFileMD5 *p;
+
+ if ((p = (icmFileMD5 *) al->calloc(al, 1, sizeof(icmFileMD5))) == NULL) {
+ return NULL;
+ }
+ p->md5 = md5; /* MD5 compute object */
+ p->al = al; /* Heap allocator */
+ p->get_size = icmFileMD5_get_size;
+ p->seek = icmFileMD5_seek;
+ p->read = icmFileMD5_read;
+ p->write = icmFileMD5_write;
+ p->gprintf = icmFileMD5_printf;
+ p->flush = icmFileMD5_flush;
+ p->del = icmFileMD5_delete;
+ p->get_errc = icmFileMD5_geterrc;
+
+ p->of = 0;
+ p->errc = 0;
+
+ return (icmFile *)p;
+}
+
+
+/* ============================================= */
+/* Implementation of color transform lookups. */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Methods common to all transforms (icmLuBase) : */
+
+/* Return information about the native lut in/out/pcs colorspaces. */
+/* Any pointer may be NULL if value is not to be returned */
+static void
+icmLutSpaces(
+ struct _icmLuBase *p, /* This */
+ icColorSpaceSignature *ins, /* Return Native input color space */
+ int *inn, /* Return number of input components */
+ icColorSpaceSignature *outs, /* Return Native output color space */
+ int *outn, /* Return number of output components */
+ icColorSpaceSignature *pcs /* Return Native PCS color space */
+ /* (this will be the same as ins or outs */
+ /* depending on the lookup direction) */
+) {
+ if (ins != NULL)
+ *ins = p->inSpace;
+ if (inn != NULL)
+ *inn = (int)number_ColorSpaceSignature(p->inSpace);
+
+ if (outs != NULL)
+ *outs = p->outSpace;
+ if (outn != NULL)
+ *outn = (int)number_ColorSpaceSignature(p->outSpace);
+ if (pcs != NULL)
+ *pcs = p->pcs;
+}
+
+/* Return information about the effective lookup in/out colorspaces, */
+/* including allowance for PCS override. */
+/* Any pointer may be NULL if value is not to be returned */
+static void
+icmLuSpaces(
+ struct _icmLuBase *p, /* This */
+ icColorSpaceSignature *ins, /* Return effective input color space */
+ int *inn, /* Return number of input components */
+ icColorSpaceSignature *outs, /* Return effective output color space */
+ int *outn, /* Return number of output components */
+ icmLuAlgType *alg, /* Return type of lookup algorithm used */
+ icRenderingIntent *intt, /* Return the intent being implented */
+ icmLookupFunc *fnc, /* Return the profile function being implemented */
+ icColorSpaceSignature *pcs, /* Return the profile effective PCS */
+ icmLookupOrder *ord /* return the search Order */
+) {
+ if (ins != NULL)
+ *ins = p->e_inSpace;
+ if (inn != NULL)
+ *inn = (int)number_ColorSpaceSignature(p->e_inSpace);
+
+ if (outs != NULL)
+ *outs = p->e_outSpace;
+ if (outn != NULL)
+ *outn = (int)number_ColorSpaceSignature(p->e_outSpace);
+
+ if (alg != NULL)
+ *alg = p->ttype;
+
+ if (intt != NULL)
+ *intt = p->intent;
+
+ if (fnc != NULL)
+ *fnc = p->function;
+
+ if (pcs != NULL)
+ *pcs = p->e_pcs;
+
+ if (ord != NULL)
+ *ord = p->order;
+}
+
+/* Relative to Absolute for this WP in XYZ */
+static void icmLuXYZ_Rel2Abs(icmLuBase *p, double *out, double *in) {
+ icmMulBy3x3(out, p->toAbs, in);
+}
+
+/* Absolute to Relative for this WP in XYZ */
+static void icmLuXYZ_Abs2Rel(icmLuBase *p, double *out, double *in) {
+ icmMulBy3x3(out, p->fromAbs, in);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Methods common to all non-named transforms (icmLuBase) : */
+
+/* Initialise the LU white and black points from the ICC tags, */
+/* and the corresponding absolute<->relative conversion matrices */
+/* return nz on error */
+static int icmLuInit_Wh_bk(
+struct _icmLuBase *lup
+) {
+ icmXYZArray *whitePointTag, *blackPointTag;
+ icc *p = lup->icp;
+
+ if ((whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) == NULL
+ || whitePointTag->ttype != icSigXYZType || whitePointTag->size < 1) {
+ if (p->header->deviceClass != icSigLinkClass
+ && (lup->intent == icAbsoluteColorimetric
+ || lup->intent == icmAbsolutePerceptual
+ || lup->intent == icmAbsoluteSaturation)) {
+ sprintf(p->err,"icc_lookup: Profile is missing Media White Point Tag");
+ p->errc = 1;
+ return 1;
+ }
+ p->err[0] = '\000';
+ p->errc = 0;
+ lup->whitePoint = icmD50; /* safe value */
+ } else
+ lup->whitePoint = whitePointTag->data[0]; /* Copy structure */
+
+ if ((blackPointTag = (icmXYZArray *)p->read_tag(p, icSigMediaBlackPointTag)) == NULL
+ || blackPointTag->ttype != icSigXYZType || blackPointTag->size < 1) {
+ p->err[0] = '\000';
+ p->errc = 0;
+ lup->blackPoint = icmBlack; /* default */
+ lup->blackisassumed = 1; /* We assumed the default */
+ } else {
+ lup->blackPoint = blackPointTag->data[0]; /* Copy structure */
+ lup->blackisassumed = 0; /* The black is from the tag */
+ }
+
+ /* Create absolute <-> relative conversion matricies */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, lup->whitePoint, icmD50, lup->toAbs);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, lup->whitePoint, lup->fromAbs);
+ DBLLL(("toAbs and fromAbs created from wp %f %f %f and D50 %f %f %f\n", lup->whitePoint.X, lup->whitePoint.Y, lup->whitePoint.Z, icmD50.X, icmD50.Y, icmD50.Z));
+ DBLLL(("toAbs = %f %f %f\n %f %f %f\n %f %f %f\n", lup->toAbs[0][0], lup->toAbs[0][1], lup->toAbs[0][2], lup->toAbs[1][0], lup->toAbs[1][1], lup->toAbs[1][2], lup->toAbs[2][0], lup->toAbs[2][1], lup->toAbs[2][2]));
+ DBLLL(("fromAbs = %f %f %f\n %f %f %f\n %f %f %f\n", lup->fromAbs[0][0], lup->fromAbs[0][1], lup->fromAbs[0][2], lup->fromAbs[1][0], lup->fromAbs[1][1], lup->fromAbs[1][2], lup->fromAbs[2][0], lup->fromAbs[2][1], lup->fromAbs[2][2]));
+
+ return 0;
+}
+
+/* Return the media white and black points in absolute XYZ space. */
+/* Note that if not in the icc, the black point will be returned as 0, 0, 0, */
+/* and the function will return nz. */
+/* Any pointer may be NULL if value is not to be returned */
+static int icmLuWh_bk_points(
+struct _icmLuBase *p,
+double *wht,
+double *blk
+) {
+ if (wht != NULL) {
+ icmXYZ2Ary(wht,p->whitePoint);
+ }
+
+ if (blk != NULL) {
+ icmXYZ2Ary(blk,p->blackPoint);
+ }
+ if (p->blackisassumed)
+ return 1;
+ return 0;
+}
+
+/* Get the LU white and black points in LU PCS space, converted to XYZ. */
+/* (ie. white and black will be relative if LU is relative intent etc.) */
+/* Return nz if the black point is being assumed to be 0,0,0 rather */
+/* than being from the tag. */ \
+static int icmLuLu_wh_bk_points(
+struct _icmLuBase *p,
+double *wht,
+double *blk
+) {
+ if (wht != NULL) {
+ icmXYZ2Ary(wht,p->whitePoint);
+ }
+
+ if (blk != NULL) {
+ icmXYZ2Ary(blk,p->blackPoint);
+ }
+ if (p->intent != icAbsoluteColorimetric
+ && p->intent != icmAbsolutePerceptual
+ && p->intent != icmAbsoluteSaturation) {
+ if (wht != NULL)
+ icmMulBy3x3(wht, p->fromAbs, wht);
+ if (blk != NULL)
+ icmMulBy3x3(blk, p->fromAbs, blk);
+ }
+ if (p->blackisassumed)
+ return 1;
+ return 0;
+}
+
+/* Get the native (internal) ranges for the Monochrome or Matrix profile */
+/* Arguments may be NULL */
+static void
+icmLu_get_lutranges (
+ struct _icmLuBase *p,
+ double *inmin, double *inmax, /* Return maximum range of inspace values */
+ double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ icTagTypeSignature tagType;
+
+ if (p->ttype == icmLutType) {
+ icmLuLut *pp = (icmLuLut *)p;
+ tagType = pp->lut->ttype;
+ } else {
+ tagType = icMaxEnumType;
+ }
+
+ /* Hmm. we have no way of handling an error from getRange. */
+ /* It shouldn't ever return one unless there is a mismatch between */
+ /* getRange and Lu creation... */
+ getRange(p->icp, p->inSpace, tagType, inmin, inmax);
+ getRange(p->icp, p->outSpace, tagType, outmin, outmax);
+}
+
+/* Get the effective (externally visible) ranges for the all profile types */
+/* Arguments may be NULL */
+static void
+icmLu_get_ranges (
+ struct _icmLuBase *p,
+ double *inmin, double *inmax, /* Return maximum range of inspace values */
+ double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ icTagTypeSignature tagType;
+
+ if (p->ttype == icmLutType) {
+ icmLuLut *pp = (icmLuLut *)p;
+ tagType = pp->lut->ttype;
+ } else {
+ tagType = icMaxEnumType;
+ }
+ /* Hmm. we have no way of handling an error from getRange. */
+ /* It shouldn't ever return one unless there is a mismatch between */
+ /* getRange and Lu creation... */
+ getRange(p->icp, p->e_inSpace, tagType, inmin, inmax);
+ getRange(p->icp, p->e_outSpace, tagType, outmin, outmax);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Forward and Backward Monochrome type methods: */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* Individual components of Fwd conversion: */
+
+/* Actual device to linearised device */
+static int
+icmLuMonoFwd_curve (
+icmLuMono *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+
+ /* Translate from device to PCS scale */
+ if ((rv |= p->grayCurve->lookup_fwd(p->grayCurve,&out[0],&in[0])) > 1) {
+ sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed");
+ icp->errc = rv;
+ return 2;
+ }
+
+ return rv;
+}
+
+/* Linearised device to relative PCS */
+static int
+icmLuMonoFwd_map (
+icmLuMono *p, /* This */
+double *out, /* Vector of output values (native space) */
+double *in /* Vector of input values (native space) */
+) {
+ int rv = 0;
+ double Y = in[0]; /* In case out == in */
+
+ out[0] = p->pcswht.X;
+ out[1] = p->pcswht.Y;
+ out[2] = p->pcswht.Z;
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out); /* in Lab */
+
+ /* Scale linearized device level to PCS white */
+ out[0] *= Y;
+ out[1] *= Y;
+ out[2] *= Y;
+
+ return rv;
+}
+
+/* relative PCS to absolute PCS (if required) */
+static int
+icmLuMonoFwd_abs ( /* Abs comes last in Fwd conversion */
+icmLuMono *p, /* This */
+double *out, /* Vector of output values in Effective PCS */
+double *in /* Vector of input values in Native PCS */
+) {
+ int rv = 0;
+
+ if (out != in) { /* Don't alter input values */
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+
+ /* Do absolute conversion */
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+
+ if (p->pcs == icSigLabData) /* Convert L to Y */
+ icmLab2XYZ(&p->pcswht, out, out);
+
+ /* Convert from Relative to Absolute colorimetric */
+ icmMulBy3x3(out, p->toAbs, out);
+
+ if (p->e_pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+
+ } else {
+
+ /* Convert from Native to Effective output space */
+ if (p->pcs == icSigLabData && p->e_pcs == icSigXYZData)
+ icmLab2XYZ(&p->pcswht, out, out);
+ else if (p->pcs == icSigXYZData && p->e_pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+ }
+
+ return rv;
+}
+
+
+/* Overall Fwd conversion routine (Dev->PCS) */
+static int
+icmLuMonoFwd_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Input value */
+) {
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoFwd_curve(p, out, in);
+ rv |= icmLuMonoFwd_map(p, out, out);
+ rv |= icmLuMonoFwd_abs(p, out, out);
+ return rv;
+}
+
+/* Three stage conversion routines */
+static int
+icmLuMonoFwd_lookup_in(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoFwd_curve(p, out, in);
+ return rv;
+}
+
+static int
+icmLuMonoFwd_lookup_core(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoFwd_map(p, out, in);
+ rv |= icmLuMonoFwd_abs(p, out, out);
+ return rv;
+}
+
+static int
+icmLuMonoFwd_lookup_out(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ return rv;
+}
+
+
+/* - - - - - - - - - - - - - - */
+/* Individual components of Bwd conversion: */
+
+/* Convert from relative PCS to absolute PCS (if required) */
+static int
+icmLuMonoBwd_abs ( /* Abs comes first in Bwd conversion */
+icmLuMono *p, /* This */
+double *out, /* Vector of output values in Native PCS */
+double *in /* Vector of input values in Effective PCS */
+) {
+ int rv = 0;
+
+ if (out != in) { /* Don't alter input values */
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+
+ /* Force to monochrome locus in correct space */
+ if (p->e_pcs == icSigLabData) {
+ double wp[3];
+
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+ wp[0] = p->whitePoint.X;
+ wp[1] = p->whitePoint.Y;
+ wp[2] = p->whitePoint.Z;
+ } else {
+ wp[0] = p->pcswht.X;
+ wp[1] = p->pcswht.Y;
+ wp[2] = p->pcswht.Z;
+ }
+ icmXYZ2Lab(&p->pcswht, wp, wp); /* Convert to Lab white point */
+ out[1] = out[0]/wp[0] * wp[1];
+ out[2] = out[0]/wp[0] * wp[2];
+
+ } else {
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+ out[0] = out[1]/p->whitePoint.Y * p->whitePoint.X;
+ out[2] = out[1]/p->whitePoint.Y * p->whitePoint.Z;
+ } else {
+ out[0] = out[1]/p->pcswht.Y * p->pcswht.X;
+ out[2] = out[1]/p->pcswht.Y * p->pcswht.Z;
+ }
+ }
+
+ /* Do absolute conversion, and conversion to effective PCS */
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+
+ if (p->e_pcs == icSigLabData)
+ icmLab2XYZ(&p->pcswht, out, out);
+
+ icmMulBy3x3(out, p->fromAbs, out);
+
+ /* Convert from Effective to Native input space */
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+
+ } else {
+
+ /* Convert from Effective to Native input space */
+ if (p->e_pcs == icSigLabData && p->pcs == icSigXYZData)
+ icmLab2XYZ(&p->pcswht, out, out);
+ else if (p->e_pcs == icSigXYZData && p->pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+ }
+
+ return rv;
+}
+
+/* Map from relative PCS to linearised device */
+static int
+icmLuMonoBwd_map (
+icmLuMono *p, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values (native space) */
+) {
+ int rv = 0;
+ double pcsw[3];
+
+ pcsw[0] = p->pcswht.X;
+ pcsw[1] = p->pcswht.Y;
+ pcsw[2] = p->pcswht.Z;
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, pcsw, pcsw); /* in Lab (should be 100.0!) */
+
+ /* Divide linearized device level into PCS white luminence */
+ if (p->pcs == icSigLabData)
+ out[0] = in[0]/pcsw[0];
+ else
+ out[0] = in[1]/pcsw[1];
+
+ return rv;
+}
+
+/* Map from linearised device to actual device */
+static int
+icmLuMonoBwd_curve (
+icmLuMono *p, /* This */
+double *out, /* Output value */
+double *in /* Input value */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+
+ /* Convert to device value through curve */
+ if ((rv = p->grayCurve->lookup_bwd(p->grayCurve,&out[0],&in[0])) > 1) {
+ sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed");
+ icp->errc = rv;
+ return 2;
+ }
+
+ return rv;
+}
+
+/* Overall Bwd conversion routine (PCS->Dev) */
+static int
+icmLuMonoBwd_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ double temp[3];
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoBwd_abs(p, temp, in);
+ rv |= icmLuMonoBwd_map(p, out, temp);
+ rv |= icmLuMonoBwd_curve(p, out, out);
+ return rv;
+}
+
+/* Three stage conversion routines */
+static int
+icmLuMonoBwd_lookup_in(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ return rv;
+}
+
+static int
+icmLuMonoBwd_lookup_core(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ double temp[3];
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoBwd_abs(p, temp, in);
+ rv |= icmLuMonoBwd_map(p, out, temp);
+ return rv;
+}
+
+static int
+icmLuMonoBwd_lookup_out(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoBwd_curve(p, out, in);
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - */
+
+static void
+icmLuMono_delete(
+icmLuBase *p
+) {
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+static icmLuBase *
+new_icmLuMono(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func, /* Functionality requested */
+ int dir /* 0 = fwd, 1 = bwd */
+) {
+ icmLuMono *p;
+
+ if ((p = (icmLuMono *) icp->al->calloc(icp->al,1,sizeof(icmLuMono))) == NULL)
+ return NULL;
+ p->icp = icp;
+ p->del = icmLuMono_delete;
+ p->lutspaces= icmLutSpaces;
+ p->spaces = icmLuSpaces;
+ p->XYZ_Rel2Abs = icmLuXYZ_Rel2Abs;
+ p->XYZ_Abs2Rel = icmLuXYZ_Abs2Rel;
+ p->get_lutranges = icmLu_get_lutranges;
+ p->get_ranges = icmLu_get_ranges;
+ p->init_wh_bk = icmLuInit_Wh_bk;
+ p->wh_bk_points = icmLuWh_bk_points;
+ p->lu_wh_bk_points = icmLuLu_wh_bk_points;
+ p->fwd_lookup = icmLuMonoFwd_lookup;
+ p->fwd_curve = icmLuMonoFwd_curve;
+ p->fwd_map = icmLuMonoFwd_map;
+ p->fwd_abs = icmLuMonoFwd_abs;
+ p->bwd_lookup = icmLuMonoBwd_lookup;
+ p->bwd_abs = icmLuMonoFwd_abs;
+ p->bwd_map = icmLuMonoFwd_map;
+ p->bwd_curve = icmLuMonoFwd_curve;
+ if (dir) {
+ p->ttype = icmMonoBwdType;
+ p->lookup = icmLuMonoBwd_lookup;
+ p->lookup_in = icmLuMonoBwd_lookup_in;
+ p->lookup_core = icmLuMonoBwd_lookup_core;
+ p->lookup_out = icmLuMonoBwd_lookup_out;
+ p->lookup_inv_in = icmLuMonoFwd_lookup_out; /* Opposite of Bwd_lookup_in */
+ } else {
+ p->ttype = icmMonoFwdType;
+ p->lookup = icmLuMonoFwd_lookup;
+ p->lookup_in = icmLuMonoFwd_lookup_in;
+ p->lookup_core = icmLuMonoFwd_lookup_core;
+ p->lookup_out = icmLuMonoFwd_lookup_out;
+ p->lookup_inv_in = icmLuMonoBwd_lookup_out; /* Opposite of Fwd_lookup_in */
+ }
+
+ /* Lookup the white and black points */
+ if (p->init_wh_bk((icmLuBase *)p)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* See if the color spaces are appropriate for the mono type */
+ if (number_ColorSpaceSignature(icp->header->colorSpace) != 1
+ || ( icp->header->pcs != icSigXYZData && icp->header->pcs != icSigLabData)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Find the appropriate tags */
+ if ((p->grayCurve = (icmCurve *)icp->read_tag(icp, icSigGrayTRCTag)) == NULL
+ || p->grayCurve->ttype != icSigCurveType) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ p->pcswht = icp->header->illuminant;
+ p->intent = intent;
+ p->function = func;
+ p->inSpace = inSpace;
+ p->outSpace = outSpace;
+ p->pcs = pcs;
+ p->e_inSpace = e_inSpace;
+ p->e_outSpace = e_outSpace;
+ p->e_pcs = e_pcs;
+
+ return (icmLuBase *)p;
+}
+
+static icmLuBase *
+new_icmLuMonoFwd(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func /* Functionality requested */
+) {
+ return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
+ intent, func, 0);
+}
+
+
+static icmLuBase *
+new_icmLuMonoBwd(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func /* Functionality requested */
+) {
+ return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
+ intent, func, 1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Forward and Backward Matrix type conversion */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* Individual components of Fwd conversion: */
+static int
+icmLuMatrixFwd_curve (
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+
+ /* Curve lookups */
+ if ((rv |= p->redCurve->lookup_fwd( p->redCurve, &out[0],&in[0])) > 1
+ || (rv |= p->greenCurve->lookup_fwd(p->greenCurve,&out[1],&in[1])) > 1
+ || (rv |= p->blueCurve->lookup_fwd( p->blueCurve, &out[2],&in[2])) > 1) {
+ sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed");
+ icp->errc = rv;
+ return 2;
+ }
+
+ return rv;
+}
+
+static int
+icmLuMatrixFwd_matrix (
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ double tt[3];
+
+ /* Matrix */
+ tt[0] = p->mx[0][0] * in[0] + p->mx[0][1] * in[1] + p->mx[0][2] * in[2];
+ tt[1] = p->mx[1][0] * in[0] + p->mx[1][1] * in[1] + p->mx[1][2] * in[2];
+ tt[2] = p->mx[2][0] * in[0] + p->mx[2][1] * in[1] + p->mx[2][2] * in[2];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+
+ return rv;
+}
+
+static int
+icmLuMatrixFwd_abs (/* Abs comes last in Fwd conversion */
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+
+ if (out != in) { /* Don't alter input values */
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+
+ /* If required, convert from Relative to Absolute colorimetric */
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+ icmMulBy3x3(out, p->toAbs, out);
+ }
+
+ /* If e_pcs is Lab, then convert XYZ to Lab */
+ if (p->e_pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+
+ return rv;
+}
+
+
+/* Overall Fwd conversion (Dev->PCS)*/
+static int
+icmLuMatrixFwd_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixFwd_curve(p, out, in);
+ rv |= icmLuMatrixFwd_matrix(p, out, out);
+ rv |= icmLuMatrixFwd_abs(p, out, out);
+ return rv;
+}
+
+/* Three stage conversion routines */
+static int
+icmLuMatrixFwd_lookup_in (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixFwd_curve(p, out, in);
+ return rv;
+}
+
+static int
+icmLuMatrixFwd_lookup_core (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixFwd_matrix(p, out, in);
+ rv |= icmLuMatrixFwd_abs(p, out, out);
+ return rv;
+}
+
+static int
+icmLuMatrixFwd_lookup_out (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - */
+/* Individual components of Bwd conversion: */
+
+static int
+icmLuMatrixBwd_abs (/* Abs comes first in Bwd conversion */
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+
+ if (out != in) { /* Don't alter input values */
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+
+ /* If e_pcs is Lab, then convert Lab to XYZ */
+ if (p->e_pcs == icSigLabData)
+ icmLab2XYZ(&p->pcswht, out, out);
+
+ /* If required, convert from Absolute to Relative colorimetric */
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+ icmMulBy3x3(out, p->fromAbs, out);
+ }
+
+ return rv;
+}
+
+static int
+icmLuMatrixBwd_matrix (
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ double tt[3];
+
+ tt[0] = in[0];
+ tt[1] = in[1];
+ tt[2] = in[2];
+
+ /* Matrix */
+ out[0] = p->bmx[0][0] * tt[0] + p->bmx[0][1] * tt[1] + p->bmx[0][2] * tt[2];
+ out[1] = p->bmx[1][0] * tt[0] + p->bmx[1][1] * tt[1] + p->bmx[1][2] * tt[2];
+ out[2] = p->bmx[2][0] * tt[0] + p->bmx[2][1] * tt[1] + p->bmx[2][2] * tt[2];
+
+ return rv;
+}
+
+static int
+icmLuMatrixBwd_curve (
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+
+ /* Curves */
+ if ((rv |= p->redCurve->lookup_bwd(p->redCurve,&out[0],&in[0])) > 1
+ || (rv |= p->greenCurve->lookup_bwd(p->greenCurve,&out[1],&in[1])) > 1
+ || (rv |= p->blueCurve->lookup_bwd(p->blueCurve,&out[2],&in[2])) > 1) {
+ sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed");
+ icp->errc = rv;
+ return 2;
+ }
+ return rv;
+}
+
+/* Overall Bwd conversion (PCS->Dev) */
+static int
+icmLuMatrixBwd_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixBwd_abs(p, out, in);
+ rv |= icmLuMatrixBwd_matrix(p, out, out);
+ rv |= icmLuMatrixBwd_curve(p, out, out);
+ return rv;
+}
+
+/* Three stage conversion routines */
+static int
+icmLuMatrixBwd_lookup_in (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ return rv;
+}
+
+static int
+icmLuMatrixBwd_lookup_core (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixBwd_abs(p, out, in);
+ rv |= icmLuMatrixBwd_matrix(p, out, out);
+ return rv;
+}
+
+static int
+icmLuMatrixBwd_lookup_out (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixBwd_curve(p, out, in);
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - */
+
+static void
+icmLuMatrix_delete(
+icmLuBase *p
+) {
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* We setup valid fwd and bwd component conversions, */
+/* but setup only the asked for overal conversion. */
+static icmLuBase *
+new_icmLuMatrix(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func, /* Functionality requested */
+ int dir /* 0 = fwd, 1 = bwd */
+) {
+ icmLuMatrix *p;
+
+ if ((p = (icmLuMatrix *) icp->al->calloc(icp->al,1,sizeof(icmLuMatrix))) == NULL)
+ return NULL;
+ p->icp = icp;
+ p->del = icmLuMatrix_delete;
+ p->lutspaces= icmLutSpaces;
+ p->spaces = icmLuSpaces;
+ p->XYZ_Rel2Abs = icmLuXYZ_Rel2Abs;
+ p->XYZ_Abs2Rel = icmLuXYZ_Abs2Rel;
+ p->get_lutranges = icmLu_get_lutranges;
+ p->get_ranges = icmLu_get_ranges;
+ p->init_wh_bk = icmLuInit_Wh_bk;
+ p->wh_bk_points = icmLuWh_bk_points;
+ p->lu_wh_bk_points = icmLuLu_wh_bk_points;
+ p->fwd_lookup = icmLuMatrixFwd_lookup;
+ p->fwd_curve = icmLuMatrixFwd_curve;
+ p->fwd_matrix = icmLuMatrixFwd_matrix;
+ p->fwd_abs = icmLuMatrixFwd_abs;
+ p->bwd_lookup = icmLuMatrixBwd_lookup;
+ p->bwd_abs = icmLuMatrixBwd_abs;
+ p->bwd_matrix = icmLuMatrixBwd_matrix;
+ p->bwd_curve = icmLuMatrixBwd_curve;
+ if (dir) {
+ p->ttype = icmMatrixBwdType;
+ p->lookup = icmLuMatrixBwd_lookup;
+ p->lookup_in = icmLuMatrixBwd_lookup_in;
+ p->lookup_core = icmLuMatrixBwd_lookup_core;
+ p->lookup_out = icmLuMatrixBwd_lookup_out;
+ p->lookup_inv_in = icmLuMatrixFwd_lookup_out; /* Opposite of Bwd_lookup_in */
+ } else {
+ p->ttype = icmMatrixFwdType;
+ p->lookup = icmLuMatrixFwd_lookup;
+ p->lookup_in = icmLuMatrixFwd_lookup_in;
+ p->lookup_core = icmLuMatrixFwd_lookup_core;
+ p->lookup_out = icmLuMatrixFwd_lookup_out;
+ p->lookup_inv_in = icmLuMatrixBwd_lookup_out; /* Opposite of Fwd_lookup_in */
+ }
+
+ /* Lookup the white and black points */
+ if (p->init_wh_bk((icmLuBase *)p)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Note that we can use matrix type even if PCS is Lab, */
+ /* by simply converting it. */
+
+ /* Find the appropriate tags */
+ if ((p->redCurve = (icmCurve *)icp->read_tag(icp, icSigRedTRCTag)) == NULL
+ || p->redCurve->ttype != icSigCurveType
+ || (p->greenCurve = (icmCurve *)icp->read_tag(icp, icSigGreenTRCTag)) == NULL
+ || p->greenCurve->ttype != icSigCurveType
+ || (p->blueCurve = (icmCurve *)icp->read_tag(icp, icSigBlueTRCTag)) == NULL
+ || p->blueCurve->ttype != icSigCurveType
+ || (p->redColrnt = (icmXYZArray *)icp->read_tag(icp, icSigRedColorantTag)) == NULL
+ || p->redColrnt->ttype != icSigXYZType || p->redColrnt->size < 1
+ || (p->greenColrnt = (icmXYZArray *)icp->read_tag(icp, icSigGreenColorantTag)) == NULL
+ || p->greenColrnt->ttype != icSigXYZType || p->greenColrnt->size < 1
+ || (p->blueColrnt = (icmXYZArray *)icp->read_tag(icp, icSigBlueColorantTag)) == NULL
+ || p->blueColrnt->ttype != icSigXYZType || p->blueColrnt->size < 1) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Setup the matrix */
+ p->mx[0][0] = p->redColrnt->data[0].X;
+ p->mx[0][1] = p->greenColrnt->data[0].X;
+ p->mx[0][2] = p->blueColrnt->data[0].X;
+ p->mx[1][1] = p->greenColrnt->data[0].Y;
+ p->mx[1][0] = p->redColrnt->data[0].Y;
+ p->mx[1][2] = p->blueColrnt->data[0].Y;
+ p->mx[2][1] = p->greenColrnt->data[0].Z;
+ p->mx[2][0] = p->redColrnt->data[0].Z;
+ p->mx[2][2] = p->blueColrnt->data[0].Z;
+
+#ifndef ICM_STRICT
+ /* Workaround for buggy Kodak RGB profiles. Their matrix values */
+ /* may be scaled to 100 rather than 1.0, and the colorant curves */
+ /* may be scaled by 0.5 */
+ if (icp->header->cmmId == str2tag("KCMS")) {
+ int i, j, oc = 0;
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ if (p->mx[i][j] > 5.0)
+ oc++;
+ if (oc > 4) { /* Looks like it */
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ p->mx[i][j] /= 100.0;
+ }
+ }
+#endif /* ICM_STRICT */
+
+ if (icmInverse3x3(p->bmx, p->mx) != 0) { /* Compute inverse */
+ sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable");
+ icp->errc = 2;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ p->pcswht = icp->header->illuminant;
+ p->intent = intent;
+ p->function = func;
+ p->inSpace = inSpace;
+ p->outSpace = outSpace;
+ p->pcs = pcs;
+ p->e_inSpace = e_inSpace;
+ p->e_outSpace = e_outSpace;
+ p->e_pcs = e_pcs;
+
+ /* Lookup the white and black points */
+ if (p->init_wh_bk((icmLuBase *)p)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ return (icmLuBase *)p;
+}
+
+static icmLuBase *
+new_icmLuMatrixFwd(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func /* Functionality requested */
+) {
+ return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
+ intent, func, 0);
+}
+
+
+static icmLuBase *
+new_icmLuMatrixBwd(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func /* Functionality requested */
+) {
+ return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
+ intent, func, 1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Forward and Backward Multi-Dimensional Interpolation type conversion */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* Components of overall lookup, in order */
+static int icmLuLut_in_abs(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ DBLLL(("icm in_abs: input %s\n",icmPdv(lut->inputChan, in)));
+ if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */
+ out[i] = in[i];
+ }
+
+ /* If Bwd Lut, take care of Absolute color space and effective input space */
+ if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation)) {
+
+ if (p->e_inSpace == icSigLabData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm in_abs: after Lab2XYZ %s\n",icmPdv(lut->inputChan, out)));
+ }
+
+ /* Convert from Absolute to Relative colorimetric */
+ icmMulBy3x3(out, p->fromAbs, out);
+ DBLLL(("icm in_abs: after fromAbs %s\n",icmPdv(lut->inputChan, out)));
+
+ if (p->inSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm in_abs: after XYZ2Lab %s\n",icmPdv(lut->inputChan, out)));
+ }
+
+ } else {
+
+ /* Convert from Effective to Native input space */
+ if (p->e_inSpace == icSigLabData && p->inSpace == icSigXYZData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm in_abs: after Lab2XYZ %s\n",icmPdv(lut->inputChan, out)));
+ } else if (p->e_inSpace == icSigXYZData && p->inSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm in_abs: after XYZ2Lab %s\n",icmPdv(lut->inputChan, out)));
+ }
+ }
+ DBLLL(("icm in_abs: returning %s\n",icmPdv(lut->inputChan, out)));
+
+ return rv;
+}
+
+/* Possible matrix lookup */
+static int icmLuLut_matrix(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ if (p->usematrix)
+ rv |= lut->lookup_matrix(lut,out,in);
+ else if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++)
+ out[i] = in[i];
+ }
+ return rv;
+}
+
+/* Do input -> input' lookup */
+static int icmLuLut_input(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ p->in_normf(out, in); /* Normalize from input color space */
+ rv |= lut->lookup_input(lut,out,out); /* Lookup though input tables */
+ p->in_denormf(out,out); /* De-normalize to input color space */
+ return rv;
+}
+
+/* Do input'->output' lookup */
+static int icmLuLut_clut(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ double temp[MAX_CHAN];
+ int rv = 0;
+
+ p->in_normf(temp, in); /* Normalize from input color space */
+ rv |= p->lookup_clut(lut,out,temp); /* Lookup though clut tables */
+ p->out_denormf(out,out); /* De-normalize to output color space */
+ return rv;
+}
+
+/* Do output'->output lookup */
+static int icmLuLut_output(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ p->out_normf(out,in); /* Normalize from output color space */
+ rv |= lut->lookup_output(lut,out,out); /* Lookup though output tables */
+ p->out_denormf(out, out); /* De-normalize to output color space */
+ return rv;
+}
+
+static int icmLuLut_out_abs(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ DBLLL(("icm out_abs: input %s\n",icmPdv(lut->outputChan, in)));
+ if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->outputChan; i++) /* Don't alter input values */
+ out[i] = in[i];
+ }
+
+ /* If Fwd Lut, take care of Absolute color space */
+ /* and convert from native to effective out PCS */
+ if ((p->function == icmFwd || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation)) {
+
+ if (p->outSpace == icSigLabData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm out_abs: after Lab2XYZ %s\n",icmPdv(lut->outputChan, out)));
+ }
+
+ /* Convert from Relative to Absolute colorimetric XYZ */
+ icmMulBy3x3(out, p->toAbs, out);
+ DBLLL(("icm out_abs: after toAbs %s\n",icmPdv(lut->outputChan, out)));
+
+ if (p->e_outSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm out_abs: after XYZ2Lab %s\n",icmPdv(lut->outputChan, out)));
+ }
+ } else {
+
+ /* Convert from Native to Effective output space */
+ if (p->outSpace == icSigLabData && p->e_outSpace == icSigXYZData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm out_abs: after Lab2 %s\n",icmPdv(lut->outputChan, out)));
+ } else if (p->outSpace == icSigXYZData && p->e_outSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm out_abs: after XYZ2Lab %s\n",icmPdv(lut->outputChan, out)));
+ }
+ }
+ DBLLL(("icm out_abs: returning %s\n",icmPdv(lut->outputChan, out)));
+ return rv;
+}
+
+
+/* Overall lookup */
+static int
+icmLuLut_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+ double temp[MAX_CHAN];
+
+ DBGLL(("icmLuLut_lookup: in = %s\n", icmPdv(p->inputChan, in)));
+ rv |= p->in_abs(p,temp,in); /* Possible absolute conversion */
+ DBGLL(("icmLuLut_lookup: in_abs = %s\n", icmPdv(p->inputChan, temp)));
+ if (p->usematrix) {
+ rv |= lut->lookup_matrix(lut,temp,temp);/* If XYZ, multiply by non-unity matrix */
+ DBGLL(("icmLuLut_lookup: matrix = %s\n", icmPdv(p->inputChan, temp)));
+ }
+ p->in_normf(temp, temp); /* Normalize for input color space */
+ DBGLL(("icmLuLut_lookup: norm = %s\n", icmPdv(p->inputChan, temp)));
+ rv |= lut->lookup_input(lut,temp,temp); /* Lookup though input tables */
+ DBGLL(("icmLuLut_lookup: input = %s\n", icmPdv(p->inputChan, temp)));
+ rv |= p->lookup_clut(lut,out,temp); /* Lookup though clut tables */
+ DBGLL(("icmLuLut_lookup: clut = %s\n", icmPdv(p->outputChan, out)));
+ rv |= lut->lookup_output(lut,out,out); /* Lookup though output tables */
+ DBGLL(("icmLuLut_lookup: output = %s\n", icmPdv(p->outputChan, out)));
+ p->out_denormf(out,out); /* Normalize for output color space */
+ DBGLL(("icmLuLut_lookup: denorm = %s\n", icmPdv(p->outputChan, out)));
+ rv |= p->out_abs(p,out,out); /* Possible absolute conversion */
+ DBGLL(("icmLuLut_lookup: out_abse = %s\n", icmPdv(p->outputChan, out)));
+
+ return rv;
+}
+
+#ifdef NEVER /* The following should be identical in effect to the above. */
+
+/* Overall lookup */
+static int
+icmLuLut_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int i, rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+ double temp[MAX_CHAN];
+
+ rv |= p->in_abs(p,temp,in);
+ rv |= p->matrix(p,temp,temp);
+ rv |= p->input(p,temp,temp);
+ rv |= p->clut(p,out,temp);
+ rv |= p->output(p,out,out);
+ rv |= p->out_abs(p,out,out);
+
+ return rv;
+}
+
+#endif /* NEVER */
+
+/* Three stage conversion */
+static int
+icmLuLut_lookup_in (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+
+ /* If in_abs() or matrix() are active, then we can't have a per component input curve */
+ if (((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->e_inSpace != p->inSpace)
+ || (p->usematrix)) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++)
+ out[i] = in[i];
+ } else {
+ rv |= p->input(p,out,in);
+ }
+ return rv;
+}
+
+static int
+icmLuLut_lookup_core (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+
+ /* If in_abs() or matrix() are active, then we have to do the per component input curve here */
+ if (((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->e_inSpace != p->inSpace)
+ || (p->usematrix)) {
+ double temp[MAX_CHAN];
+ rv |= p->in_abs(p,temp,in);
+ rv |= p->matrix(p,temp,temp);
+ rv |= p->input(p,temp,temp);
+ rv |= p->clut(p,out,temp);
+ } else {
+ rv |= p->clut(p,out,in);
+ }
+
+ /* If out_abs() is active, then we can't have do per component out curve here */
+ if (((p->function == icmFwd || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->outSpace != p->e_outSpace)) {
+ rv |= p->output(p,out,out);
+ rv |= p->out_abs(p,out,out);
+ }
+
+ return rv;
+}
+
+static int
+icmLuLut_lookup_out (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+
+ /* If out_abs() is active, then we can't have a per component out curve */
+ if (((p->function == icmFwd || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->outSpace != p->e_outSpace)) {
+ unsigned int i;
+ for (i = 0; i < lut->outputChan; i++)
+ out[i] = in[i];
+ } else {
+ rv |= p->output(p,out,in);
+ }
+
+ return rv;
+}
+
+/* Inverse three stage conversion (partly implemented) */
+static int
+icmLuLut_lookup_inv_in (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+
+ /* If in_abs() or matrix() are active, then we can't have a per component input curve */
+ if (((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->e_inSpace != p->inSpace)
+ || (p->usematrix)) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++)
+ out[i] = in[i];
+ } else {
+ rv |= p->inv_input(p,out,in);
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Some components of inverse lookup, in order */
+/* ~~ should these be in icmLut (like all the fwd transforms)? */
+
+static int icmLuLut_inv_out_abs(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ DBLLL(("icm inv_out_abs: input %s\n",icmPdv(lut->outputChan, in)));
+ if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->outputChan; i++) /* Don't alter input values */
+ out[i] = in[i];
+ }
+
+ /* If Fwd Lut, take care of Absolute color space */
+ /* and convert from effective to native inverse output PCS */
+ /* OutSpace must be PCS: XYZ or Lab */
+ if ((p->function == icmFwd || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation)) {
+
+ if (p->e_outSpace == icSigLabData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm inv_out_abs: after Lab2XYZ %s\n",icmPdv(lut->outputChan, out)));
+ }
+
+ /* Convert from Absolute to Relative colorimetric */
+ icmMulBy3x3(out, p->fromAbs, out);
+ DBLLL(("icm inv_out_abs: after fromAbs %s\n",icmPdv(lut->outputChan, out)));
+
+ if (p->outSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm inv_out_abs: after XYZ2Lab %s\n",icmPdv(lut->outputChan, out)));
+ }
+
+ } else {
+
+ /* Convert from Effective to Native output space */
+ if (p->e_outSpace == icSigLabData && p->outSpace == icSigXYZData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm inv_out_abs: after Lab2XYZ %s\n",icmPdv(lut->outputChan, out)));
+ } else if (p->e_outSpace == icSigXYZData && p->outSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm inv_out_abs: after XYZ2Lab %s\n",icmPdv(lut->outputChan, out)));
+ }
+ }
+ return rv;
+}
+
+/* Do output->output' inverse lookup */
+static int icmLuLut_inv_output(icmLuLut *p, double *out, double *in) {
+ icc *icp = p->icp;
+ icmLut *lut = p->lut;
+ int i;
+ int rv = 0;
+
+ if (lut->rot[0].inited == 0) {
+ for (i = 0; i < lut->outputChan; i++) {
+ rv = icmTable_setup_bwd(icp, &lut->rot[i], lut->outputEnt,
+ lut->outputTable + i * lut->outputEnt);
+ if (rv != 0) {
+ sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init.");
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ p->out_normf(out,in); /* Normalize from output color space */
+ for (i = 0; i < lut->outputChan; i++) {
+ /* Reverse lookup though output tables */
+ rv |= icmTable_lookup_bwd(&lut->rot[i], &out[i], &out[i]);
+ }
+ p->out_denormf(out, out); /* De-normalize to output color space */
+ return rv;
+}
+
+/* No output' -> input inverse lookup. */
+/* This is non-trivial ! */
+
+/* Do input' -> input inverse lookup */
+static int icmLuLut_inv_input(icmLuLut *p, double *out, double *in) {
+ icc *icp = p->icp;
+ icmLut *lut = p->lut;
+ int i;
+ int rv = 0;
+
+ if (lut->rit[0].inited == 0) {
+ for (i = 0; i < lut->inputChan; i++) {
+ rv = icmTable_setup_bwd(icp, &lut->rit[i], lut->inputEnt,
+ lut->inputTable + i * lut->inputEnt);
+ if (rv != 0) {
+ sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init.");
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ p->in_normf(out, in); /* Normalize from input color space */
+ for (i = 0; i < lut->inputChan; i++) {
+ /* Reverse lookup though input tables */
+ rv |= icmTable_lookup_bwd(&lut->rit[i], &out[i], &out[i]);
+ }
+ p->in_denormf(out,out); /* De-normalize to input color space */
+ return rv;
+}
+
+/* Possible inverse matrix lookup */
+static int icmLuLut_inv_matrix(icmLuLut *p, double *out, double *in) {
+ icc *icp = p->icp;
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ if (p->usematrix) {
+ double tt[3];
+ if (p->imx_valid == 0) {
+ if (icmInverse3x3(p->imx, lut->e) != 0) { /* Compute inverse */
+ sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable");
+ icp->errc = 2;
+ return 2;
+ }
+ p->imx_valid = 1;
+ }
+ /* Matrix multiply */
+ tt[0] = p->imx[0][0] * in[0] + p->imx[0][1] * in[1] + p->imx[0][2] * in[2];
+ tt[1] = p->imx[1][0] * in[0] + p->imx[1][1] * in[1] + p->imx[1][2] * in[2];
+ tt[2] = p->imx[2][0] * in[0] + p->imx[2][1] * in[1] + p->imx[2][2] * in[2];
+ out[0] = tt[0], out[1] = tt[1], out[2] = tt[2];
+ } else if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++)
+ out[i] = in[i];
+ }
+ return rv;
+}
+
+static int icmLuLut_inv_in_abs(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ DBLLL(("icm inv_in_abs: input %s\n",icmPdv(lut->inputChan, in)));
+ if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */
+ out[i] = in[i];
+ }
+
+ /* If Bwd Lut, take care of Absolute color space, and */
+ /* convert from native to effective input space */
+ if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation)) {
+
+ if (p->inSpace == icSigLabData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm inv_in_abs: after Lab2XYZ %s\n",icmPdv(lut->inputChan, out)));
+ }
+
+ /* Convert from Relative to Absolute colorimetric XYZ */
+ icmMulBy3x3(out, p->toAbs, out);
+ DBLLL(("icm inv_in_abs: after toAbs %s\n",icmPdv(lut->inputChan, out)));
+
+ if (p->e_inSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm inv_in_abs: after XYZ2Lab %s\n",icmPdv(lut->inputChan, out)));
+ }
+ } else {
+
+ /* Convert from Native to Effective input space */
+ if (p->inSpace == icSigLabData && p->e_inSpace == icSigXYZData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm inv_in_abs: after Lab2XYZ %s\n",icmPdv(lut->inputChan, out)));
+ } else if (p->inSpace == icSigXYZData && p->e_inSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm inv_in_abs: after XYZ2Lab %s\n",icmPdv(lut->inputChan, out)));
+ }
+ }
+ DBLLL(("icm inv_in_abs: returning %s\n",icmPdv(lut->inputChan, out)));
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return LuLut information */
+static void icmLuLut_get_info(
+ icmLuLut *p, /* this */
+ icmLut **lutp, /* Pointer to icc lut type */
+ icmXYZNumber *pcswhtp, /* Pointer to profile PCS white point */
+ icmXYZNumber *whitep, /* Pointer to profile absolute white point */
+ icmXYZNumber *blackp /* Pointer to profile absolute black point */
+) {
+ if (lutp != NULL)
+ *lutp = p->lut;
+ if (pcswhtp != NULL)
+ *pcswhtp = p->pcswht;
+ if (whitep != NULL)
+ *whitep = p->whitePoint;
+ if (blackp != NULL)
+ *blackp = p->blackPoint;
+}
+
+/* Get the native ranges for the LuLut */
+/* This is computed differently to the mono & matrix types, to */
+/* accurately take into account the different range for 8 bit Lab */
+/* lut type. The range returned for the effective PCS is not so accurate. */
+static void
+icmLuLut_get_lutranges (
+ struct _icmLuBase *pp,
+ double *inmin, double *inmax, /* Return maximum range of inspace values */
+ double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ icmLuLut *p = (icmLuLut *)pp;
+ unsigned int i;
+
+ for (i = 0; i < p->lut->inputChan; i++) {
+ inmin[i] = 0.0; /* Normalized range of input space values */
+ inmax[i] = 1.0;
+ }
+ p->in_denormf(inmin,inmin); /* Convert to real colorspace range */
+ p->in_denormf(inmax,inmax);
+
+ /* Make sure min and max are so. */
+ for (i = 0; i < p->lut->inputChan; i++) {
+ if (inmin[i] > inmax[i]) {
+ double tt;
+ tt = inmin[i];
+ inmin[i] = inmax[i];
+ inmax[i] = tt;
+ }
+ }
+
+ for (i = 0; i < p->lut->outputChan; i++) {
+ outmin[i] = 0.0; /* Normalized range of output space values */
+ outmax[i] = 1.0;
+ }
+ p->out_denormf(outmin,outmin); /* Convert to real colorspace range */
+ p->out_denormf(outmax,outmax);
+
+ /* Make sure min and max are so. */
+ for (i = 0; i < p->lut->outputChan; i++) {
+ if (outmin[i] > outmax[i]) {
+ double tt;
+ tt = outmin[i];
+ outmin[i] = outmax[i];
+ outmax[i] = tt;
+ }
+ }
+}
+
+/* Get the effective (externaly visible) ranges for the LuLut */
+/* This will be accurate if there is no override, but only */
+/* aproximate if a PCS override is in place. */
+static void
+icmLuLut_get_ranges (
+ struct _icmLuBase *pp,
+ double *inmin, double *inmax, /* Return maximum range of inspace values */
+ double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ icmLuLut *p = (icmLuLut *)pp;
+
+ /* Get the native ranges first */
+ icmLuLut_get_lutranges(pp, inmin, inmax, outmin, outmax);
+
+ /* And replace them if the effective space is different */
+ if (p->e_inSpace != p->inSpace)
+ getRange(p->icp, p->e_inSpace, p->lut->ttype, inmin, inmax);
+
+ if (p->e_outSpace != p->outSpace)
+ getRange(p->icp, p->e_outSpace, p->lut->ttype, outmin, outmax);
+}
+
+/* Return the underlying Lut matrix */
+static void
+icmLuLut_get_matrix (
+ struct _icmLuLut *p,
+ double m[3][3]
+) {
+ int i, j;
+ icmLut *lut = p->lut;
+
+ if (p->usematrix) {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ m[i][j] = lut->e[i][j]; /* Copy from Lut */
+
+ } else { /* return unity matrix */
+ icmSetUnity3x3(m);
+ }
+}
+
+
+static void
+icmLuLut_delete(
+icmLuBase *p
+) {
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+icmLuBase *
+icc_new_icmLuLut(
+ icc *icp,
+ icTagSignature ttag, /* Target Lut tag */
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS (from header) */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent (For absolute) */
+ icmLookupFunc func /* Functionality requested (for icmLuSpaces()) */
+) {
+ icmLuLut *p;
+
+ if ((p = (icmLuLut *) icp->al->calloc(icp->al,1,sizeof(icmLuLut))) == NULL)
+ return NULL;
+ p->ttype = icmLutType;
+ p->icp = icp;
+ p->del = icmLuLut_delete;
+ p->lutspaces= icmLutSpaces;
+ p->spaces = icmLuSpaces;
+ p->XYZ_Rel2Abs = icmLuXYZ_Rel2Abs;
+ p->XYZ_Abs2Rel = icmLuXYZ_Abs2Rel;
+ p->init_wh_bk = icmLuInit_Wh_bk;
+ p->wh_bk_points = icmLuWh_bk_points;
+ p->lu_wh_bk_points = icmLuLu_wh_bk_points;
+
+ p->lookup = icmLuLut_lookup;
+ p->lookup_in = icmLuLut_lookup_in;
+ p->lookup_core = icmLuLut_lookup_core;
+ p->lookup_out = icmLuLut_lookup_out;
+ p->lookup_inv_in = icmLuLut_lookup_inv_in;
+
+ p->in_abs = icmLuLut_in_abs;
+ p->matrix = icmLuLut_matrix;
+ p->input = icmLuLut_input;
+ p->clut = icmLuLut_clut;
+ p->output = icmLuLut_output;
+ p->out_abs = icmLuLut_out_abs;
+
+ p->inv_in_abs = icmLuLut_inv_in_abs;
+ p->inv_matrix = icmLuLut_inv_matrix;
+ p->inv_input = icmLuLut_inv_input;
+ p->inv_output = icmLuLut_inv_output;
+ p->inv_out_abs = icmLuLut_inv_out_abs;
+
+ p->pcswht = icp->header->illuminant;
+ p->intent = intent; /* used to trigger absolute processing */
+ p->function = func;
+ p->inSpace = inSpace;
+ p->outSpace = outSpace;
+ p->pcs = pcs;
+ p->e_inSpace = e_inSpace;
+ p->e_outSpace = e_outSpace;
+ p->e_pcs = e_pcs;
+ p->get_info = icmLuLut_get_info;
+ p->get_lutranges = icmLuLut_get_lutranges;
+ p->get_ranges = icmLuLut_get_ranges;
+ p->get_matrix = icmLuLut_get_matrix;
+
+ /* Lookup the white and black points */
+ if (p->init_wh_bk((icmLuBase *)p)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Get the Lut tag, & check that it is expected type */
+ if ((p->lut = (icmLut *)icp->read_tag(icp, ttag)) == NULL
+ || (p->lut->ttype != icSigLut8Type && p->lut->ttype != icSigLut16Type)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Check if matrix should be used */
+ if (inSpace == icSigXYZData && p->lut->nu_matrix(p->lut))
+ p->usematrix = 1;
+ else
+ p->usematrix = 0;
+
+ /* Lookup input color space to normalized index function */
+ if (getNormFunc(icp, inSpace, p->lut->ttype, icmToLuti, &p->in_normf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Lookup normalized index to input color space function */
+ if (getNormFunc(icp, inSpace, p->lut->ttype, icmFromLuti, &p->in_denormf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Lookup output color space to normalized Lut entry value function */
+ if (getNormFunc(icp, outSpace, p->lut->ttype, icmToLutv, &p->out_normf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Lookup normalized Lut entry value to output color space function */
+ if (getNormFunc(icp, outSpace, p->lut->ttype, icmFromLutv, &p->out_denormf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Note that the following two are only used in computing the expected */
+ /* value ranges of the effective PCS. This might not be the best way of */
+ /* doing this. */
+ /* Lookup normalized index to effective input color space function */
+ if (getNormFunc(icp, e_inSpace, p->lut->ttype, icmFromLuti, &p->e_in_denormf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Lookup normalized Lut entry value to effective output color space function */
+ if (getNormFunc(icp, e_outSpace, p->lut->ttype, icmFromLutv, &p->e_out_denormf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+// ~~~999
+#ifndef NEVER
+ /* Standard code */
+ /* Determine appropriate clut lookup algorithm */
+ {
+ int use_sx; /* -1 = undecided, 0 = N-linear, 1 = Simplex lookup */
+ icColorSpaceSignature ins, outs; /* In and out Lut color spaces */
+ int inn, outn; /* in and out number of Lut components */
+
+ p->lutspaces((icmLuBase *)p, &ins, &inn, &outs, &outn, NULL);
+
+ /* Determine if the input space is "Device" like, */
+ /* ie. luminance will be expected to vary most strongly */
+ /* with the diagonal change in input coordinates. */
+ switch(ins) {
+
+ /* Luminence is carried by the sum of all the output channels, */
+ /* so output luminence will dominantly be in diagonal direction. */
+ case icSigXYZData: /* This seems to be appropriate ? */
+ case icSigRgbData:
+ case icSigGrayData:
+ case icSigCmykData:
+ case icSigCmyData:
+ case icSigMch6Data:
+ use_sx = 1; /* Simplex interpolation is appropriate */
+ break;
+
+ /* A single channel carries the luminence information */
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigHlsData:
+ case icSigHsvData:
+ use_sx = 0; /* N-linear interpolation is appropriate */
+ break;
+ default:
+ use_sx = -1; /* undecided */
+ break;
+ }
+
+ /* If we couldn't figure it out from the input space, */
+ /* check output luminance variation with a diagonal input */
+ /* change. */
+ if (use_sx == -1) {
+ int lc; /* Luminance channel */
+
+ /* Determine where the luminence is carried in the output */
+ switch(outs) {
+
+ /* Luminence is carried by the sum of all the output channels */
+ case icSigRgbData:
+ case icSigGrayData:
+ case icSigCmykData:
+ case icSigCmyData:
+ case icSigMch6Data:
+ lc = -1; /* Average all channels */
+ break;
+
+ /* A single channel carries the luminence information */
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ lc = 0;
+ break;
+
+ case icSigXYZData:
+ case icSigHlsData:
+ lc = 1;
+ break;
+
+ case icSigHsvData:
+ lc = 2;
+ break;
+
+ /* default means give up and use N-linear type lookup */
+ default:
+ lc = -2;
+ break;
+ }
+
+ /* If we know how luminance is represented in output space */
+ if (lc != -2) {
+ double tout1[MAX_CHAN]; /* Test output values */
+ double tout2[MAX_CHAN];
+ double tt, diag;
+ int n;
+
+ /* Determine input space location of min and max of */
+ /* given output channel (chan = -1 means average of all) */
+ p->lut->min_max(p->lut, tout1, tout2, lc);
+
+ /* Convert to vector and then calculate normalized */
+ /* dot product with diagonal vector (1,1,1...) */
+ for (tt = 0.0, n = 0; n < inn; n++) {
+ tout1[n] = tout2[n] - tout1[n];
+ tt += tout1[n] * tout1[n];
+ }
+ if (tt > 0.0)
+ tt = sqrt(tt); /* normalizing factor for maximum delta */
+ else
+ tt = 1.0; /* Hmm. */
+ tt *= sqrt((double)inn); /* Normalizing factor for diagonal vector */
+ for (diag = 0.0, n = 0; n < outn; n++)
+ diag += tout1[n] / tt;
+ diag = fabs(diag);
+
+ /* I'm not really convinced that this is a reliable */
+ /* indicator of whether simplex interpolation should be used ... */
+ /* It does seem to do the right thing with YCC space though. */
+ if (diag > 0.8) /* Diagonal is dominant ? */
+ use_sx = 1;
+
+ /* If we couldn't figure it out, use N-linear interpolation */
+ if (use_sx == -1)
+ use_sx = 0;
+ }
+ }
+
+ if (use_sx) {
+ p->lookup_clut = p->lut->lookup_clut_sx;
+ } else {
+ p->lookup_clut = p->lut->lookup_clut_nl;
+ }
+ }
+#else /* Development code */
+ /* Determine appropriate clut lookup algorithm, */
+ /* and set optimised simplex tables */
+ {
+ int lualg = 0; /* 0 = simplex, 1 = multi-linear, 2 = optimised simlpex */
+ icColorSpaceSignature ins, outs; /* In and out Lut color spaces */
+ int inn, outn; /* in and out number of Lut components */
+
+ p->lutspaces((icmLuBase *)p, &ins, &inn, &outs, &outn, NULL);
+
+ /* Determine which type of Lut lookup algorithm is likely to give */
+ /* minimal interpolation errors. */
+ /* To use the optimised simplex, we should ideally determine */
+ /* the simplex cell orientation that makes the simplex split diagonal */
+ /* always point towards the white or black points. */
+ switch(ins) {
+
+ case icSigXYZData: /* This seems to be appropriate ? */
+ case icSigRgbData:
+ case icSigGrayData:
+ case icSigCmykData:
+ case icSigCmyData:
+ case icSigMch6Data:
+ lualg = 0; /* Simplex interpolation is appropriate */
+ break;
+
+ case icSigLabData:
+// ~~~~9999 this isn't right! need to lookup Lab 50,0,0 through input curves then */
+/* quantize to clut nodes to figure threshold for axis flips */
+ p->lut->finfo[0].fth = 0.5; p->lut->finfo[0].bthff = 0; p->lut->finfo[0].athff = 1;
+ p->lut->finfo[1].fth = 0.5; p->lut->finfo[1].bthff = 1; p->lut->finfo[1].athff = 0;
+ p->lut->finfo[2].fth = 0.5; p->lut->finfo[2].bthff = 1; p->lut->finfo[2].athff = 0;
+ lualg = 2;
+ break;
+
+ /* !!! Should switch to optimised simplex for these too !!! */
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigHlsData:
+ case icSigHsvData:
+ lualg = 1; /* Multi-linear is best as a default for these ? */
+ break;
+
+ default:
+ lualg = 0; /* Simplex is best if we known nothing. */
+ break;
+ }
+
+ if (lualg == 2) {
+ p->lookup_clut = icmLut_lookup_clut_osx;
+ } else if (lualg == 1) {
+ p->lookup_clut = p->lut->lookup_clut_nl;
+ } else {
+ p->lookup_clut = p->lut->lookup_clut_sx;
+ }
+ }
+#endif
+ return (icmLuBase *)p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return an appropriate lookup object */
+/* Return NULL on error, and detailed error in icc */
+static icmLuBase* icc_get_luobj (
+ icc *p, /* ICC */
+ icmLookupFunc func, /* Conversion functionality */
+ icRenderingIntent intent, /* Rendering intent, including icmAbsoluteColorimetricXYZ */
+ icColorSpaceSignature pcsor,/* PCS override (0 = def) */
+ icmLookupOrder order /* Conversion representation search Order */
+) {
+ icmLuBase *luobj = NULL; /* Lookup object to return */
+ icColorSpaceSignature pcs, e_pcs; /* PCS and effective PCS */
+
+#ifdef ICM_STRICT
+ int rv;
+ /* Check that the profile is legal, since we depend on it ? */
+ if ((rv = check_icc_legal(p)) != 0)
+ return NULL;
+#endif /* ICM_STRICT */
+
+ /* Figure out the native and effective PCS */
+ e_pcs = pcs = p->header->pcs;
+ if (pcsor != icmSigDefaultData)
+ e_pcs = pcsor; /* Override */
+
+ /* How we expect to execute the request depends firstly on the type of profile */
+ switch (p->header->deviceClass) {
+ case icSigInputClass:
+ case icSigDisplayClass:
+ case icSigColorSpaceClass:
+
+ /* Look for Intent based AToBX profile + optional BToAX reverse */
+ /* or for AToB0 based profile + optional BToA0 reverse */
+ /* or three component matrix profile (reversable) */
+ /* or momochrome table profile (reversable) */
+ /* No Lut intent for ICC < V2.4, but possible for >= V2.4, */
+ /* so fall back if we can't find the chosen Lut intent.. */
+ /* Device <-> PCS */
+ /* Determine the algorithm and set its parameters */
+
+ switch (func) {
+ icRenderingIntent fbintent; /* Fallback intent */
+ icTagSignature ttag, fbtag;
+
+ case icmFwd: /* Device to PCS */
+ if (intent == icmDefaultIntent)
+ intent = icPerceptual; /* Make this the default */
+
+ switch (intent) {
+ case icAbsoluteColorimetric:
+ ttag = icSigAToB1Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = intent;
+ break;
+ case icRelativeColorimetric:
+ ttag = icSigAToB1Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icPerceptual:
+ ttag = icSigAToB0Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icSaturation:
+ ttag = icSigAToB2Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ ttag = icSigAToB0Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = intent;
+ break;
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ ttag = icSigAToB2Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = intent;
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (order != icmLuOrdRev) {
+ /* Try Lut type lookup with the chosen intent first */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try the fallback tag */
+ if ((luobj = icc_new_icmLuLut(p, fbtag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ fbintent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ } else {
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try Lut type lookup last */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try the fallback tag */
+ if ((luobj = icc_new_icmLuLut(p, fbtag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ fbintent, func)) != NULL)
+ break;
+ }
+ break;
+
+ case icmBwd: /* PCS to Device */
+ if (intent == icmDefaultIntent)
+ intent = icPerceptual; /* Make this the default */
+
+ switch (intent) {
+ case icAbsoluteColorimetric:
+ ttag = icSigBToA1Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = intent;
+ break;
+ case icRelativeColorimetric:
+ ttag = icSigBToA1Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icPerceptual:
+ ttag = icSigBToA0Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icSaturation:
+ ttag = icSigBToA2Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ ttag = icSigBToA0Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = intent;
+ break;
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ ttag = icSigBToA2Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = intent;
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+
+ if (order != icmLuOrdRev) {
+ /* Try Lut type lookup first */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try the fallback Lut */
+ if ((luobj = icc_new_icmLuLut(p, fbtag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ fbintent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+ } else {
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try Lut type lookup last */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try the fallback Lut */
+ if ((luobj = icc_new_icmLuLut(p, fbtag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ fbintent, func)) != NULL)
+ break;
+ }
+ break;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
+ p->errc = 1;
+ return NULL;
+ }
+ break;
+
+ case icSigOutputClass:
+ /* Expect BToA Lut and optional AToB Lut, All intents, expect gamut */
+ /* or momochrome table profile (reversable) */
+ /* Device <-> PCS */
+ /* Gamut Lut - no intent */
+ /* Optional preview links PCS <-> PCS */
+
+ /* Determine the algorithm and set its parameters */
+ switch (func) {
+ icTagSignature ttag;
+
+ case icmFwd: /* Device to PCS */
+
+ if (intent == icmDefaultIntent)
+ intent = icPerceptual; /* Make this the default */
+
+ switch (intent) {
+ case icRelativeColorimetric:
+ case icAbsoluteColorimetric:
+ ttag = icSigAToB1Tag;
+ break;
+ case icPerceptual:
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ ttag = icSigAToB0Tag;
+ break;
+ case icSaturation:
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ ttag = icSigAToB2Tag;
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (order != icmLuOrdRev) {
+ /* Try Lut type lookup first */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL) {
+ break;
+ }
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+ } else {
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try Lut type lookup last */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+ }
+ break;
+
+ case icmBwd: /* PCS to Device */
+
+ if (intent == icmDefaultIntent)
+ intent = icPerceptual; /* Make this the default */
+
+ switch (intent) {
+ case icRelativeColorimetric:
+ case icAbsoluteColorimetric:
+ ttag = icSigBToA1Tag;
+ break;
+ case icPerceptual:
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ ttag = icSigBToA0Tag;
+ break;
+ case icSaturation:
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ ttag = icSigBToA2Tag;
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (order != icmLuOrdRev) {
+ /* Try Lut type lookup first */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+ } else {
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try Lut type lookup last */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+ }
+ break;
+
+ case icmGamut: /* PCS to 1D */
+
+#ifdef ICM_STRICT /* Allow only default and absolute */
+ if (intent != icmDefaultIntent
+ && intent != icAbsoluteColorimetric) {
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Gamut table");
+ p->errc = 1;
+ return NULL;
+ }
+#else /* Be more forgiving */
+ switch (intent) {
+ case icAbsoluteColorimetric:
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ break;
+ case icmDefaultIntent:
+ case icRelativeColorimetric:
+ case icPerceptual:
+ case icSaturation:
+ intent = icmDefaultIntent; /* Make all other look like default */
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent (0x%x)",intent);
+ p->errc = 1;
+ return NULL;
+ }
+
+#endif
+ /* If the target tag exists, and it is a Lut */
+ luobj = icc_new_icmLuLut(p, icSigGamutTag,
+ pcs, icSigGrayData, pcs,
+ e_pcs, icSigGrayData, e_pcs,
+ intent, func);
+ break;
+
+ case icmPreview: /* PCS to PCS */
+
+ switch (intent) {
+ case icRelativeColorimetric:
+ ttag = icSigPreview1Tag;
+ break;
+ case icPerceptual:
+ ttag = icSigPreview0Tag;
+ break;
+ case icSaturation:
+ ttag = icSigPreview2Tag;
+ break;
+ case icAbsoluteColorimetric:
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for preview table");
+ p->errc = 1;
+ return NULL;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+ /* If the target tag exists, and it is a Lut */
+ luobj = icc_new_icmLuLut(p, ttag,
+ pcs, pcs, pcs,
+ e_pcs, e_pcs, e_pcs,
+ intent, func);
+ break;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
+ p->errc = 1;
+ return NULL;
+ }
+ break;
+
+ case icSigLinkClass:
+ /* Expect AToB0 Lut and optional BToA0 Lut, One intent in header */
+ /* Device <-> Device */
+
+ if (intent != p->header->renderingIntent
+ && intent != icmDefaultIntent) {
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Link profile");
+ p->errc = 1;
+ return NULL;
+ }
+ intent = p->header->renderingIntent;
+
+ /* Determine the algorithm and set its parameters */
+ switch (func) {
+ case icmFwd: /* Device to PCS (== Device) */
+
+ luobj = icc_new_icmLuLut(p, icSigAToB0Tag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, pcs, pcs,
+ intent, func);
+ break;
+
+ case icmBwd: /* PCS (== Device) to Device */
+
+ luobj = icc_new_icmLuLut(p, icSigBToA0Tag,
+ pcs, p->header->colorSpace, pcs,
+ pcs, p->header->colorSpace, pcs,
+ intent, func);
+ break;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
+ p->errc = 1;
+ return NULL;
+ }
+ break;
+
+ case icSigAbstractClass:
+ /* Expect AToB0 Lut and option BToA0 Lut, with either relative or absolute intent. */
+ /* PCS <-> PCS */
+ /* Determine the algorithm and set its parameters */
+
+ if (intent != icmDefaultIntent
+ && intent != icRelativeColorimetric
+ && intent != icAbsoluteColorimetric) {
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Abstract profile");
+ p->errc = 1;
+ return NULL;
+ }
+
+ switch (func) {
+ case icmFwd: /* PCS (== Device) to PCS */
+
+ luobj = icc_new_icmLuLut(p, icSigAToB0Tag,
+ p->header->colorSpace, pcs, pcs,
+ e_pcs, e_pcs, e_pcs,
+ intent, func);
+ break;
+
+ case icmBwd: /* PCS to PCS (== Device) */
+
+ luobj = icc_new_icmLuLut(p, icSigBToA0Tag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, e_pcs, e_pcs,
+ intent, func);
+ break;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
+ p->errc = 1;
+ return NULL;
+ }
+ break;
+
+ case icSigNamedColorClass:
+ /* Expect Name -> Device, Optional PCS */
+ /* and a reverse lookup would be useful */
+ /* (ie. PCS or Device coords to closest named color) */
+ /* ~~ to be implemented ~~ */
+
+ /* ~~ Absolute intent is valid for processing of */
+ /* PCS from named Colors. Also allow for e_pcs */
+ if (intent != icmDefaultIntent
+ && intent != icRelativeColorimetric
+ && intent != icAbsoluteColorimetric) {
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Named Color profile");
+ p->errc = 1;
+ return NULL;
+ }
+
+ sprintf(p->err,"icc_get_luobj: Named Colors not handled yet");
+ p->errc = 1;
+ return NULL;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown profile class");
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (luobj == NULL) {
+ sprintf(p->err,"icc_get_luobj: Unable to locate usable conversion");
+ p->errc = 1;
+ } else {
+ luobj->order = order;
+ }
+
+ return luobj;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Returns total ink limit and channel maximums. */
+/* Returns -1.0 if not applicable for this type of profile. */
+/* Returns -1.0 for grey, additive, or any profiles < 4 channels. */
+/* This is a place holder that uses a heuristic, */
+/* until there is a private or standard tag for this information */
+static double icm_get_tac( /* return TAC */
+icc *p,
+double *chmax, /* device return channel sums. May be NULL */
+void (*calfunc)(void *cntx, double *out, double *in), /* Optional calibration func. */
+void *cntx
+) {
+ icmHeader *rh = p->header;
+ icmLuBase *luo;
+ icmLuLut *ll;
+ icmLut *lut;
+ icColorSpaceSignature outs; /* Type of output space */
+ int inn, outn; /* Number of components */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ double tac = 0.0;
+ double max[MAX_CHAN]; /* Channel maximums */
+ int i, f;
+ unsigned int uf;
+ int size; /* Lut table size */
+ double *gp; /* Pointer to grid cube base */
+
+ /* If not something that can really have a TAC */
+ if (rh->deviceClass != icSigDisplayClass
+ && rh->deviceClass != icSigOutputClass
+ && rh->deviceClass != icSigLinkClass) {
+ return -1.0;
+ }
+
+ /* If not a suitable color space */
+ switch (rh->colorSpace) {
+ /* Not applicable */
+ case icSigXYZData:
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ return -1.0;
+
+ /* Assume no limit */
+ case icSigGrayData:
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSigRgbData:
+ return -1.0;
+
+ default:
+ break;
+ }
+
+ /* Get a PCS->device colorimetric lookup */
+ if ((luo = p->get_luobj(p, icmBwd, icRelativeColorimetric, icmSigDefaultData, icmLuOrdNorm)) == NULL) {
+ if ((luo = p->get_luobj(p, icmBwd, icmDefaultIntent, icmSigDefaultData, icmLuOrdNorm)) == NULL) {
+ return -1.0;
+ }
+ }
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ luo->spaces(luo, NULL, &inn, &outs, &outn, &alg, NULL, NULL, NULL, NULL);
+
+ /* Assume any non-Lut type doesn't have a TAC */
+ if (alg != icmLutType) {
+ return -1.0;
+ }
+
+ ll = (icmLuLut *)luo;
+
+ /* We have a Lut type. Search the lut for the largest values */
+ for (f = 0; f < outn; f++)
+ max[f] = 0.0;
+
+ lut = ll->lut;
+ gp = lut->clutTable; /* Base of grid array */
+ size = sat_pow(lut->clutPoints,lut->inputChan);
+ for (i = 0; i < size; i++) {
+ double tot, vv[MAX_CHAN];
+
+ lut->lookup_output(lut,vv,gp); /* Lookup though output tables */
+ ll->out_denormf(vv,vv); /* Normalize for output color space */
+
+ if (calfunc != NULL)
+ calfunc(cntx, vv, vv); /* Apply device calibration */
+
+ for (tot = 0.0, uf = 0; uf < lut->outputChan; uf++) {
+ tot += vv[uf];
+ if (vv[uf] > max[uf])
+ max[uf] = vv[uf];
+ }
+ if (tot > tac)
+ tac = tot;
+ gp += lut->outputChan;
+ }
+
+ if (chmax != NULL) {
+ for (f = 0; f < outn; f++)
+ chmax[f] = max[f];
+ }
+
+ luo->del(luo);
+
+ return tac;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Create an empty object. Return NULL on error */
+icc *new_icc_a(
+icmAlloc *al /* Memory allocator */
+) {
+ unsigned int i;
+ icc *p;
+
+ if ((p = (icc *) al->calloc(al, 1,sizeof(icc))) == NULL) {
+ return NULL;
+ }
+ p->ver = 0; /* default is V2 profile */
+
+ p->al = al; /* Heap allocator */
+
+ p->get_rfp = icc_get_rfp;
+ p->set_version = icc_set_version;
+ p->get_size = icc_get_size;
+ p->read = icc_read;
+ p->read_x = icc_read_x;
+ p->write = icc_write;
+ p->write_x = icc_write_x;
+ p->dump = icc_dump;
+ p->del = icc_delete;
+ p->add_tag = icc_add_tag;
+ p->link_tag = icc_link_tag;
+ p->find_tag = icc_find_tag;
+ p->read_tag = icc_read_tag;
+ p->read_tag_any = icc_read_tag_any;
+ p->rename_tag = icc_rename_tag;
+ p->unread_tag = icc_unread_tag;
+ p->read_all_tags = icc_read_all_tags;
+ p->delete_tag = icc_delete_tag;
+ p->check_id = icc_check_id;
+ p->get_tac = icm_get_tac;
+ p->get_luobj = icc_get_luobj;
+ p->new_clutluobj = icc_new_icmLuLut;
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+#endif
+
+ /* Allocate a header object */
+ if ((p->header = new_icmHeader(p)) == NULL) {
+ al->free(al, p);
+ return NULL;
+ }
+
+ /* Values that must be set before writing */
+ p->header->deviceClass = icMaxEnumClass;/* Type of profile - must be set! */
+ p->header->colorSpace = icMaxEnumData; /* Clr space of data - must be set! */
+ p->header->pcs = icMaxEnumData; /* PCS: XYZ or Lab - must be set! */
+ p->header->renderingIntent = icMaxEnumIntent; /* Rendering intent - must be set ! */
+
+ /* Values that should be set before writing */
+ p->header->manufacturer = -1; /* Dev manufacturer - should be set ! */
+ p->header->model = -1; /* Dev model number - should be set ! */
+ p->header->attributes.l = 0; /* ICC Device attributes - should set ! */
+ p->header->flags = 0; /* Embedding flags - should be set ! */
+
+ /* Values that may be set before writing */
+ p->header->attributes.h = 0; /* Dev Device attributes - may be set ! */
+ p->header->creator = str2tag("argl"); /* Profile creator - Argyll - may be set ! */
+
+ /* Init default values in header */
+ p->header->cmmId = str2tag("argl"); /* CMM for profile - Argyll CMM */
+ p->header->majv = 2; /* Current version 2.2.0 */
+ p->header->minv = 2;
+ p->header->bfv = 0;
+ setcur_DateTimeNumber(&p->header->date);/* Creation Date */
+ p->header->platform = icSigMicrosoft; /* Primary Platform */
+ p->header->illuminant = icmD50; /* Profile illuminant - D50 */
+
+ /* Values that will be created automatically */
+ for (i = 0; i < 16; i++)
+ p->header->id[i] = 0;
+
+ return p;
+}
+
+
+/* ---------------------------------------------------------- */
+/* Print an int vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPiv(int di, int *p) {
+ static char buf[5][MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > MAX_CHAN)
+ di = MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%d", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print a double color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPdv(int di, double *p) {
+ static char buf[5][MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > MAX_CHAN)
+ di = MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%f", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print a float color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPfv(int di, float *p) {
+ static char buf[5][MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > MAX_CHAN)
+ di = MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%f", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print an 0..1 range XYZ as a D50 Lab string */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPLab(double *p) {
+ static char buf[5][MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+ double lab[3];
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ icmXYZ2Lab(&icmD50, lab, p);
+
+ for (e = 0; e < 3; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%f", lab[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+
+/* ---------------------------------------------------------- */
+
diff --git a/.pc/06_fix_udev_rule.patch/usb/55-Argyll.rules b/.pc/06_fix_udev_rule.patch/usb/55-Argyll.rules
new file mode 100644
index 0000000..87fc720
--- /dev/null
+++ b/.pc/06_fix_udev_rule.patch/usb/55-Argyll.rules
@@ -0,0 +1,90 @@
+# udev rule to recognize instruments and make them accessible to user applications.
+# Copy this to /etc/udev/rules.d/55-Argyll.rules
+
+# Skip all this to speed things up if it'a not a usb add.
+ACTION!="add", GOTO="argyll_rules_end"
+SUBSYSTEM!="usb", GOTO="argyll_rules_end"
+
+# Recognize the color measurement devices
+
+# Colorimtre HCFR
+ATTRS{idVendor}=="04db", ATTRS{idProduct}=="005b", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# MonacoOPTIX (Same as i1 Display 1)
+ATTRS{idVendor}=="0670", ATTRS{idProduct}=="0001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# HueyL (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# HueyL (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5010", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Display 3
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5020", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# ColorMunki Smile
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="6003", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP20
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d020", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP92Q (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d092", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP94
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d094", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# i1Pro
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2000", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Monitor
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Display
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2003", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1 io table (not tested)
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2004", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Huey
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2005", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1 iSis (not tested)
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2006", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# ColorMunki
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2007", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# Spyder 1
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0100", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 2
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0200", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 3
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0300", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 4
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0400", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# ColorHug, old and new
+ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="f8da", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# Let udev-acl manage these devices, if it's available
+TEST=="/var/run/ConsoleKit/database", ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}="1"
+
+# Otherwise, restrict access to members of the plugdev group,
+# which the user may have to add to the system.
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}!="*?", MODE="660", GROUP="plugdev"
+
+# Set ID_VENDOR and ID_MODEL acording to VID and PID
+IMPORT{builtin}="hwdb --subsystem=usb"
+
+LABEL="argyll_rules_end"
diff --git a/.pc/applied-patches b/.pc/applied-patches
new file mode 100644
index 0000000..ea92233
--- /dev/null
+++ b/.pc/applied-patches
@@ -0,0 +1,5 @@
+01_autotools-support.diff
+02_firmware-package-builder.diff
+03_usb-db.diff
+04_CVE-2012-4405.diff
+06_fix_udev_rule.patch
diff --git a/Jambase b/Jambase
new file mode 100644
index 0000000..6ee19eb
--- /dev/null
+++ b/Jambase
@@ -0,0 +1,4541 @@
+#
+# /+\
+# +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
+# \+/
+#
+# This file is part of Jam - see jam.c for Copyright information.
+#
+
+# The Copyright information in jam.c reads:
+#
+#/*
+# * /+\
+# * +\ Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
+# * \+/
+# *
+# * This file is part of jam.
+# *
+# * License is hereby granted to use this software and distribute it
+# * freely, as long as this copyright notice is retained and modifications
+# * are clearly marked.
+# *
+# * ALL WARRANTIES ARE HEREBY DISCLAIMED.
+# */
+
+# MODIFIDED version of jam 2.5 Jambase, for the ArgyllCMS project by Graeme W. Gill.
+# These modifications are herebye licensed under the same conditions
+# as as the rest of Jam, as detailed above.
+# Moved to a "Normalized" scheme, where Jamfile UNIX style target paths
+# are converted to platform specific, Jamfile relative, Gristed/SEARCH/LOCATE
+# form internally. Creating the tree is simplified by eliminating the SubDir
+# rule. Better support for MingW, OS X. More comprehensive ruleset.
+# Renamed Jamrules to Jamtop.
+#
+# JAMBASE - jam 2.5 ruleset providing make(1)-like functionality
+#
+# Supports UNIX, NT, and VMS.
+#
+# Special targets defined in this file:
+#
+# all - parent of first, shell, files, lib, exe
+# first - first dependent of 'all', for potential initialization
+# shell - parent of all Shell targets
+# files - parent of all File targets
+# lib - parent of all Library targets
+# exe - parent of all Main targets
+# dirs - parent of all MkDir targets
+# install - parent of all Install targets
+# clean - removes all Shell, File, Library, and Main targets
+# uninstall - removes all Install targets
+#
+
+# Rules defined by this file:
+#
+# As obj : source.s ; .s -> .o
+# Bulk dir : files ; populate directory with many files
+# Cc obj : src.c : flags : defines : hdrpaths
+# .c -> .o
+# C++ obj : src.cc : flags : defines : hdrpaths
+# .cc -> .o
+# Clean clean : sources ; remove sources with 'jam clean'
+# File dest : source ; copy file
+# FileNoClean dest : source ; copy file, but don't delete dest during clean
+# FakeFile dest : source ; Fudge to say dest is created with source
+# Fortran obj.o : source.f ; .f -> .o
+# GenFile target : program args ; make custom file
+# GenFileND target : program args : extra_dependecies ;
+# make custom file, program dependent & args not
+# GenFileNND target : program args : extra_dependecies ;
+# make custom file, program & args not dependent
+# CatToFile dest : strings ; save the arguments to the file
+# GuiBin image ; Mark executable as GUI applications
+# (Needs to go before other declarations of image)
+# HardLink target : source ; make link from source to target
+# HdrRule source : headers ; handle #includes
+# InstallInto dir : sources ; install any files
+# InstallBin dir : sources ; install binaries
+# InstallLib dir : sources ; install files
+# InstallShLib dir : sources ; install files
+# InstallFile dir : sources ; install files
+# InstallMan dir : sources ; install man pages
+# InstallShell dir : sources ; install shell scripts
+# Lex source.c : source.l ; .l -> .c
+# Library library : sources : flags : defines : hdrpaths : objects
+# static library from compiled sources
+# LibraryFromLibraries lib : libs ; static library from static libraries
+# LibraryFromObjects lib : objects ; static library from objects
+# LinkLibraries images : libraries ; add static libraries onto Mains
+# LinkObjects images : objects ; add objects onto Mains
+# LinkShLibraries images : shlibraries ; add shared libraries onto Mains
+# Main image : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
+# create exe from compiled sources
+# MainsFromSources sources ; create exes each from their source
+# MainFromObjects image : objects : libs : shlibs ;
+# create executable from objects
+# MainVariant image : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
+# create exe from compiled sources with separate named objs
+# MainLinkFlags mains : flags ; add linker flags for object
+# MkDir dir ; make a directory, if not there
+# Mod target : mode ; sets mode of file
+# NDepends dest : source ; make Normalized dependency
+# NNoUpdate targ ; create Normalized target if needed but never update it
+# NIncludes dest : source ; make Normalized co-dependency
+# Object object : sources : flags : defines : hdrpaths ; compile object from source
+# ObjectCcFlags objects : flags ; add compiler flags for object
+# ObjectPrefCcFlags objects : flags ; add preference compiler flags for object (overridable)
+# ObjectC++Flags objects : flags ; add compiler flags for object
+# ObjectPrefC++Flags objects : flags ; add preference compiler flags for object (overridable)
+# ObjectDefines objects : defines ; add defines for object
+# ObjectHdrs objects : dirs ; add include directories for object
+# ObjectKeep objects ; mark objects to be kept after library build
+# Objects sources : flags : defines : hdrpaths compile sources
+# PeerInclude dir ; include peer Jamfile
+# FindTop ; Set TOP by locating JAMTOP file above SUBDIR
+# ProjTop d1 d2 .. ; Set project TOP
+# RmTemps target : sources ; remove temp sources after target made
+# Setuid images ; mark executables Setuid
+# set SHLINKDEFFILE on for Windows to define exports using .def file.
+# set SHLINKSEARCHEXEPATH true on UNIX to have applications search exeutable location for it
+# ShLibrary shlib : source ; link shared library from compiled sources
+# ShLibraryFromObjects shlib : objects ; link shared library from objects
+# ShLibraryLibraries shlib : libraries ; add static libraries onto shared libraries link
+# ShLibraryObjects shlib : objects ; add objects onto shared libraries link
+# ShLibraryShLibraries shlib : shlibraries ; add shared libraries onto shared libraries link
+# SoftLink target : source ; make symlink from source to target
+# SubInclude dir ; include sub Jamfile
+# Shell exe : source ; make a shell executable
+# Undefines images : symbols ; save undef's for linking
+# UserObject object : source ; handle unknown suffixes for Object
+# Yacc source.c : source.y ; .y -> .c
+# Aswig : source.i ; .i -> .h _i.c .hpp
+#
+# Utility rules
+#
+# val = geton var : varname ; return the value of varname on var
+# paths = NormPaths paths [ : dir ] ; normalize a set of paths relative to SUBDIR or dir
+# paths = NormSrcPaths paths [ : dir ] ; NormPaths with SRCDIR
+# paths = NormDstPaths paths [ : dir ] ; NormPaths with DSTDIR
+# paths = NormSrcTargets paths [ : dir ] ; normalize source targets, set Grist NOMLOC SEARCH
+# paths = NormDstTargets paths [ : dir ] ; normalize destination targets, set Grist NOMLOC LOCATE
+# paths = NormISrcTargets paths [ : dir ] ; Same as NormSrcTargets but ignore SRCDIR
+# paths = NormIDstTargets paths [ : dir ] ; Same as NormDstTargets but ignore DSTDIR
+#
+# More utility rules that have no side effects :
+#
+# FAppendSuffix f1 f2 ... : $(SUF) ; return $(<) with suffixes if no current suffixes
+# FStripCommon v1 : v2 ; strip common initial parts of v1 v2
+# FReverse a1 a2 ... ; return ... a2 a1
+# FDelEmpty a1 a2 ... ; return a1 a2 ... with any empty elements deleted
+#
+# Variables:
+#
+# Sub-Jamfile build variables, optionaly set in each Sub-Jamfile. They will
+# be picked up by subsequent rules that set target relationships and
+# creation rules. They are added to any Parent-Jamfile variables,
+# and become the Parent-Jamfile variables of any SubIncludes.
+# Relative file/path variables are anchored by the Jamfile location.
+#
+# ASFLAGS - Flags for the assembler.
+# CCFLAGS - Flags for the C compiler.
+# C++FLAGS - Flags for the C++ compiler.
+# LINKFLAGS - Flags for the executable linker.
+# SHLINKFLAGS - Flags for the shared library linker.
+# HDRS - Complile header search directories
+# DEFINES - Compile defines
+# LINKOBJS - Link extra objects
+# LINKLIBS - Link extra libraries
+# LINKSHLIBS - Link extra shared libraries
+# SHLINKOBJS - ShLibrary Linker extra objects
+# SHLINKLIBS - ShLibrary Linker extra libraries
+# SHLINKSHLIBS - ShLibrary Linker extra shared libraries
+#
+# Sub-directory preferred build flags, e.g. optimizations etc. These will only
+# have effect if not set by a parent Jamfile (ie. involked from a leaf Jamfile).
+#
+# PREF_ASFLAGS
+# PREF_CCFLAGS
+# PREF_C++FLAGS
+# PREF_LINKFLAGS
+# PREF_SHLINKFLAGS
+#
+# Parent-Jamfile build variables. These are the accumulated
+# values from any Parent Jamfiles, and will be added to any
+# Sub-Jamfile variables when a rule picks them up.
+# File/path variables will have been normalized.
+#
+# P_ASFLAGS - Flags for the assembler.
+# P_CCFLAGS - Flags for the C compiler.
+# P_C++FLAGS - Flags for the C++ compiler.
+# P_LINKFLAGS - Flags for the executable linker.
+# P_SHLINKFLAGS - Flags for the shared library linker.
+# P_HDRS - Complile header search directories
+# P_DEFINES - Compile defines
+# P_LINKOBJS - Link extra objects
+# P_LINKLIBS - Link extra libraries
+# P_LINKSHLIBS - Link extra shared libraries
+# P_SHLINKOBJS - ShLibrary Linker extra objects
+# P_SHLINKLIBS - ShLibrary Linker extra libraries
+# P_SHLINKSHLIBS - ShLibrary Linker extra shared libraries
+#
+# Pre-defined values
+#
+# Pre-packaged flags that conceal platform dependence,
+# and are used to set CCFLAGS/C++FLAGS/LINKFLAGS/SHLINLFLAGS etc.
+#
+# CCOPTFLAG - CC/C++ flag for optimization
+# CCDEBUGFLAG - CC/C++ flag for debug
+# CCPROFFLAG - CC/C++ flag for performance profiling
+# CCSHOBJFLAG - CC/C++ flag for compiling for a shared library (UNIX)
+#
+# LINKOPTFLAG - LINK flag for optimization of the binary/shared library
+# LINKDEBUGFLAG - LINK flag to support debugging
+# LINKPROFFLAG - LINK flag to support performance profiling
+# LINKSTRIPFLAG - LINK flag to strip binary of any symbols
+#
+# Location variables:
+#
+# DSTDIR - puts all products in a subdirectory of their nominated location.
+# Useful for storing variants in their own areas.
+#
+# SRCDIR - Looks for all sources and Jamfiles in an alternate top level source
+# location. Useful for accessing a read only source repository, or
+# building a variant without copying all the sources.
+# Note that at least the project Jamtop must be in the location
+# that is the target for the build, and will most likely be where
+# SRCDIR is set. SRCDIR is the location of the sources relative
+# to where it is declared.
+# (Not currently useful for a shadow build repository where the source
+# is spread between the SRCDIR and the build dir, because Jam 2.5 fails
+# to look at SEARCH if LOCATE is set).
+#
+# =========================================================================
+# ArgyllCMS Normalize mods:
+#
+# The main change is to locate and identify targets using their nominated location in the
+# filesystem. This eliminates the need to create Grist, or manipulate SEARCH, LOCATE etc.
+# when setting up a herachy of Jamfiles.
+#
+# Whenever a path is provided as an argument to one of the public rules, its path is assumed
+# to be relative to the Jamfile that it is declared in. [ The NormPaths/NormTargets rules do this. ]
+# Naturally absolute paths are not affected by this.
+# During execution this means that all files are translated to paths that are
+# in a normalized form, with either an absolute path or one that is relative to
+# the directory that Jam was involked in. For simplicity it is assumed that
+# the Jamfile contains UNIX style paths, and these are converted to the
+# platform specific form on normalization.
+#
+# For a target, the normalized directory is then stripped from the name and
+# set as the Grist (path elements separated by !), and also set in the NOMLOC,
+# LOCATE and SEARCH variables "on" the target. This gives a target a unique
+# identity for the whole of the build, determined by its nominated file system location.
+# The NOMLOC variable is a way of recovering it's location without having the reverse
+# the Grist strings. The actual location of the target can then be varied by
+# augmenting it's LOCATE and/or SEARCH variables.
+#
+# Any include file discovered by header scanning is searched for using the
+# search path that is expected to be used during compilation, and
+# its nominated location resolved this way. Any headers that are not
+# located this way or who's location isn't declared by another rule (the
+# latter being typical when headers are being generated) will be marked as
+# being in an __unknown__ directory and will not be scaned. Normally any
+# header files located in the STDHDRS directories will not be scanned either.
+#
+# [ Typically headers will be __unknown__ if the STDHDRS directories do
+# not reflect the default paths actually searched by the compiler, or if a
+# header is not actually going to be #included because it is protected
+# by an #ifdef. ]
+
+# Argyll Jambase internal implementation rules:
+
+# IDs = _TargetIDs targpaths ; return target ID's (gristed) from normalized paths
+# path = DeNormTargs target ; return the original path
+# CopyTarget dest : source ; duplicate a targets on NOMLOC LOCATE SEARCH variables.
+# NotTargets vars ; ensure variables aren't treated as LOCATE etc targets
+
+# d1 d2 ... file = _SepPath path ; separate a path into its components
+# path = _DirName d1 d2 ... ; combine components into a path
+# d1 d2 .. = _RatPath d1 d2 .. rationalize a path
+# d1 d2 .. = _RootPath d1 d2 .. : p1 p2 ... re-root a path
+# paths = RatPaths paths ; rationalize a set of paths
+# paths = RootPaths dir : paths ; re-root a set of paths
+# targs = CreateIDstTargets targs : dir ; create dest targets by locating targets in dir
+# paths1/paths = CatPaths path1 : paths ; concatenate paths separated by a /
+# found = FindToRoot starting_dir : file ; Try and locate file from directory up to root.
+
+# FindTop ; # Look for a default project file
+
+# DoInit ; Do subdir initialization (done by JAMBASE)
+
+# public write/read Variables:
+#
+# TRACESTDHDRS # Normally false, set to true to trace system path #include file dependenicies
+
+# public read only Variables:
+#
+# SUBDIR d1/d2/d3 # Current path from PWD to Jamfile
+# TOP d1/d2/d3 # Current path from PWD to the project Jamtop
+
+# internal variables
+#
+# _SUBDIR d1 d2 d3 ... # Current path from PWD to Jamfile
+# _TOP d1 d2 d3 # Current path from PWD to the project Jamtop
+
+# - - - - - - - - - - - - - - -
+
+# NOTE: Cross compiling support :-
+# To fix this to support cross compilation, the setup needs to be
+# modularised into 3 parts, making them all rules that can be re-involked:
+# 1) OS/Platform setup. System tools like copy, delete etc.
+# 2) Compiler setup. Basic compiler syntax etc.
+# 3) Target setup. Make this a rule, and allow switching
+# target by involking the rule. This will be simpler to
+# get working that per target 'on' variable (some
+# things are currently broken for 'on' variables, such
+# as library members, and it will be easier to do
+# things such as switch compilers.
+
+# - - - - - - - - - - - - - - -
+
+
+# Brief review of the jam language:
+#
+# Statements:
+# rule RULE - statements to process a rule
+# actions RULE - system commands to carry out target update
+#
+# Modifiers on actions:
+# together - multiple instances of same rule on target get executed
+# once with their sources ($(>)) concatenated
+# updated - refers to updated sources ($(>)) only
+# ignore - ignore return status of command
+# quietly - don't trace its execution unless verbose
+# piecemeal - iterate command each time with a small subset of $(>)
+# existing - refers to currently existing sources ($(>)) only
+# bind vars - subject to binding before expanding in actions
+#
+# Special rules:
+# Always - always build a target
+# Depends - builds the dependency graph
+# NOTE: can have only one $(<), or parallel builds stuff up!!
+# Use FakeFile to work around the problem.
+# Echo - blurt out targets on stdout
+# Exit - blurt out targets and exit
+# Includes - marks sources as headers for target (a codependency)
+# NoCare - don't panic if the target can't be built
+# NoUpdate - create the target if needed but never update it
+# NotFile - ignore the timestamp of the target (it's not a file)
+# Temporary - target need not be present if sources haven't changed
+#
+# Special variables set by jam:
+# $(<) - targets of a rule (to the left of the :)
+# $(>) - sources of a rule (to the right of the :)
+# $(xxx) - true on xxx (UNIX, VMS, NT, OS2, MAC)
+# $(OS) - name of OS - varies wildly
+# $(JAMVERSION) - version number (2.5)
+#
+# Special variables used by jam:
+# SEARCH - where to find something (used during binding and actions)
+# LOCATE - where to plop something not found with SEARCH
+# HDRRULE - rule to call to handle include files
+# HDRSCAN - egrep regex to extract include files
+#
+# Special targets:
+# all - default if none given on command line
+#
+
+# for perforce use -- jambase version
+
+JAMBASEDATE = 2008.03.26 ;
+
+# Initialize variables
+#
+
+# ===========================================================
+#
+# OS specific variable settings
+#
+
+if $(NT)
+{
+ MV ?= move /y ;
+ CP ?= copy ;
+ RM ?= del /f/q ;
+ RMDIR ?= rmdir /s/q ;
+ SLASH ?= \\ ;
+ SUFLIB ?= .lib ;
+ SUFSHLIB ?= .dll ;
+ SUFIMPLIB ?= .lib ;
+ SUFOBJ ?= .obj ;
+ SUFEXE ?= .exe ;
+ SUFSH ?= .bat ;
+ CCSHOBJFLAG ?= ;
+
+ if $(BCCROOT)
+ {
+ AR ?= tlib /C /P64 ;
+ CC ?= bcc32 ;
+ CCFLAGS ?= -v -w- -q -DWIN -tWR -tWM -tWC ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) -P ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= ;
+ STDLIBPATH ?= $(BCCROOT)\\lib ;
+ STDHDRS ?= $(BCCROOT)\\include ;
+ NOARSCAN ?= true ;
+ }
+ else if $(MingW) || $(MINGW)
+ {
+ # We need to do something about adding -Wl,-subsystem,windows
+ # if WinMain is being used ? (it defaults to console)
+
+ MINGW ?= $(MingW) ;
+ TPFX = "" ;
+
+ if [ GLOB $(MINGW)/bin : x86_64-w64-mingw32-gcc.exe ] {
+ MINGW64 = $(MINGW) ;
+ }
+
+ # This doesn't work on a 32 bit system because we're cross
+ # compiling and need to create build system exe's
+ # (tiff/mkversion.exe, imdi/imdi_make.exe
+ # Will using -m32 for local exe's fix this ?
+ # What is multi-lib option ???
+ if $(MINGW64) {
+ ECHO "Compiler is MingW for 64 bit target" ;
+ TARGET64 = true ;
+ TPFX = x86_64-w64-mingw32- ;
+ MINGW64_LIB32 = $(MINGW)/mingw/lib32 ;
+ } else {
+ ECHO "Compiler is MingW for 32 bit target" ;
+ }
+
+
+ # Basic C/C++ tools
+ AR ?= $(TPFX)ar rusc ;
+ AS ?= $(TPFX)as ;
+ CC ?= $(TPFX)gcc ;
+ CCFLAGS ?= -DNT -mwin32 -pipe ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+
+ OLELIBS ?= -loleaut32 -luuid ;
+ BASELIBS ?= -lstdc++ -lgcc -lodbc32 -lwsock32 ;
+# WINLIBS ?= -lwinspool -lwinmm -lshell32 -lcomctl32 -lctl3d32
+# -lodbc32 -ladvapi32 -lodbc32 -lwsock32 -lopengl32
+# -lglu32 -lshlwapi -lsetupapi ;
+ WINLIBS ?= -lshlwapi -lsetupapi -lole32 -lws2_32 -lpsapi ;
+ GUILIBS ?= -lgdi32 -lmscms ;
+
+ LINK ?= $(TPFX)g++ ; # In case we link to C++ files
+ LINKFLAGS ?= -static ;
+ SHLINKFLAGS ?= ;
+ STDLIBS ?= -lm $(OLELIBS) $(WINLIBS) $(GUILIBS) ;
+ SHSTDLIBS ?= $(STDLIBS) ;
+
+ STDHDRS ?= $(MINGW)\\include ;
+
+ # Not sure whether linker -mconsole or -mwindow are needed ??
+
+ # Allow setting of flags, independent of compiler
+ DEFFLAG ?= -D ;
+ UNDEFFLAG ?= -U ;
+ CCOPTFLAG ?= -O3 ;
+ if $(PROCESSOR_LEVEL) = 15
+ { # -mtune seems faster than -march !!!
+# CCOPTFLAG += -mtune=pentium4 ;
+# CCOPTFLAG += -mtune=prescott ;
+ CCOPTFLAG += -mtune=nocona ; # portable code for Pentium4 640
+# CCOPTFLAG += -march=nocona -mfpmath=sse -msse3 ; # non-portable
+
+ }
+
+ CCDEBUGFLAG ?= -g ; # default (TABS? DWARF2 ?) format
+ CCPROFFLAG ?= -pg ;
+ LINKDEBUGFLAG ?= -g ;
+ LINKPROFFLAG ?= -pg ;
+ LINKOPTFLAG ?= -s -O ; # Affects creating .so's ??
+ LINKSTRIPFLAG ?= -s ;
+
+ # Other tools
+ AWK ?= awk ;
+ SED ?= sed ;
+
+# YACC ?= yacc ;
+# YACCFLAGS ?= -d ;
+# YACCFILES ?= y.tab ;
+
+ YACC ?= bison -y ;
+ YACCGEN ?= .c ;
+ YACCFILES ?= y.tab ;
+ YACCFLAGS ?= -d ;
+ }
+ else if $(MSVC) #
+ {
+ ECHO "Compiler is VC++ 16 bit" ;
+ AR ?= lib /nologo ;
+ CC ?= cl /nologo ;
+ CCFLAGS ?= /D \"WIN\" ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= ;
+ STDLIBS ?=
+ $(MSVC)\\lib\\mlibce.lib
+ $(MSVC)\\lib\\oldnames.lib
+ ;
+ NOARSCAN ?= true ;
+ STDHDRS ?= $(MSVC)\\include ;
+ DEFFLAG ?= /D ;
+ UNDEFFLAG ?= "/u _" ;
+ }
+ else if $(MSVCNT) || $(MSVCDIR) || $(MSVCDir) || $(VCINSTALLDIR)
+ {
+ # Visual C++ 8.0/9.0 uses VCINSTALLDIR
+ # We assume VC++ Express + XP32 SDK has been setup
+
+ # Visual C++ 6.0 uses MSVCDIR
+
+ if $(VCINSTALLDIR) {
+ MSVCNT ?= $(VCINSTALLDIR) ;
+ } else if $(MSVCDir) {
+ MSVCNT ?= $(MSVCDir) ;
+ } else {
+ MSVCNT ?= $(MSVCDIR) ;
+ }
+
+ if $(COMPILER) = MSVCPP10 {
+ ECHO "Compiler is VC++10 32 bit" ;
+ MSVCVER = 10 ;
+ } else if $(COMPILER) = MSVCPP9 {
+ ECHO "Compiler is VC++9 32 bit" ;
+ MSVCVER = 9 ;
+ } else if $(COMPILER) = MSVCPP8 {
+ ECHO "Compiler is VC++8 32 bit" ;
+ MSVCVER = 8 ;
+ } else {
+ ECHO "Compiler is VC++ 32 bit" ;
+ MSVCVER = 6 ;
+ }
+
+ # Add the SDK include and lib if it is present
+ if $(MSSdk) {
+ MSNTSDK ?= $(MSSdk) ;
+ } else if $(MSSDK) {
+ MSNTSDK ?= $(MSSDK) ;
+ } else if $(MSVCNT) {
+ MSNTSDK ?= $(MSVCNT) ;
+ }
+
+ # bury IA64 in the path for the SDK ???
+ # (but MSSDK already has this ?
+# local I ; if $(CPU) = "IA64" { I = ia64\\ ; } else { I = "" ; }
+ local I ; I = "" ;
+
+ AR ?= lib /NOLOGO ;
+ AS ?= masm386 ;
+ CC ?= cl /nologo ;
+ CCFLAGS ?= /DNT /MD ; # DLL compatible build by default
+ if $(MSVCVER) >= 8 {
+ CCFLAGS += /D_CRT_SECURE_NO_DEPRECATE=1
+ /D_CRT_NONSTDC_NO_DEPRECATE=1 ;
+ }
+ C++ ?= $(CC) ;
+ C++FLAGS ?= $(CCFLAGS) /GX ; # GX enables syncronous exception handling
+ LINK ?= link /nologo ;
+ LINKOUTFLAG ?= /out: ;
+ LINKFLAGS ?= /INCREMENTAL:NO /LIBPATH:$(MSNTSDK)\\lib\\$(I) ;
+ SHLINKFLAGS ?= ;
+
+ STDLIBS ?=
+ oldnames.lib
+ kernel32.lib
+ advapi32.lib
+ user32.lib
+ mscms.lib
+ gdi32.lib
+ shlwapi.lib
+ shell32.lib
+ setupapi.lib
+ ole32.lib
+ oleaut32.lib
+ ws2_32.lib
+ Wbemuuid.lib
+ ;
+ SHSTDLIBS ?= $(STDLIBS) ;
+ LINKFLAG ?= ;
+ STDHDRS ?= $(MSNTSDK)\\Include ;
+ DEFFLAG ?= /D ;
+ UNDEFFLAG ?= /U ;
+ CCOPTFLAG ?= /Ox ; # MSVC9 doesn't understamd GB, G6 ?
+ if $(MSVCVER) = 6 {
+ CCDEBUGFLAG ?= /Od /Z7 ; # Include debugging into in each object
+ CCPROFFLAG ?= /Od /Z7 ;
+ LINKDEBUGFLAG ?= /DEBUGTYPE:BOTH /DEBUG /PDB:NONE ;
+ } else {
+ CCDEBUGFLAG ?= /Od /Zi ; # /Zi creates debugging database
+ CCPROFFLAG ?= /Od /Zi ;
+ LINKDEBUGFLAG ?= /DEBUG ;
+ }
+ LINKPROFFLAG ?= /PROFILE $(LINKDEBUGFLAG) ;
+ LINKOPTFLAG ?= /OPT:REF ;
+ LINKSTRIPFLAG ?= ;
+ YACC ?= bison -y ;
+ YACCGEN ?= .c ;
+ YACCFILES ?= y.tab ;
+ YACCFLAGS ?= -d ;
+ }
+ else
+ {
+ EXIT On NT, set BCCROOT, MINGW, MSVCDIR, MSVCNT, MSVC or VCINSTALLDIR to the root
+ of the Borland, GCC or Microsoft directories. ;
+ }
+}
+else if $(OS2)
+{
+ WATCOM ?= $(watcom) ;
+
+ if ! $(WATCOM)
+ {
+ Exit On OS2, set WATCOM to the root of the Watcom directory. ;
+ }
+
+ AR ?= wlib ;
+ BINDIR ?= \\os2\\apps ;
+ CC ?= wcc386 ;
+ CCFLAGS ?= /zq /DOS2 /I$(WATCOM)\\h ; # zq=quiet
+ C++ ?= wpp386 ;
+ C++FLAGS ?= $(CCFLAGS) ;
+ CP ?= copy ;
+ DOT ?= . ;
+ DOTDOT ?= .. ;
+ LINK ?= wcl386 ;
+ LINKFLAGS ?= /zq ; # zq=quiet
+ STDLIBS ?= ;
+ MV ?= move ;
+ NOARSCAN ?= true ;
+ RM ?= del /f ;
+ SLASH ?= \\ ;
+ STDHDRS ?= $(WATCOM)\\h ;
+ SUFEXE ?= .exe ;
+ SUFSH ?= .bat ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .obj ;
+ DEFFLAG ?= /D ;
+ UNDEFFLAG ?= "/u _" ;
+
+}
+else if $(VMS)
+{
+ C++ ?= cxx ;
+ C++FLAGS ?= ;
+ CC ?= cc ;
+ CCFLAGS ?= ;
+ CHMOD ?= set file/prot= ;
+ CP ?= copy/replace ;
+ CRELIB ?= true ;
+ DOT ?= [] ;
+ DOTDOT ?= [-] ;
+ EXEMODE ?= (w:e) ;
+ FILEMODE ?= (w:r) ;
+ HDRS ?= ;
+ LINK ?= link ;
+ LINKFLAGS ?= "" ;
+ STDLIBS ?= ;
+ MKDIR ?= create/dir ;
+ MV ?= rename ;
+ RM ?= delete ;
+ RUNVMS ?= mcr ;
+ SHELLMODE ?= (w:er) ;
+ SLASH ?= . ;
+ STDHDRS ?= decc$library_include ;
+ SUFEXE ?= .exe ;
+ SUFSH ?= .bat ;
+ SUFLIB ?= .olb ;
+ SUFOBJ ?= .obj ;
+
+ switch $(OS)
+ {
+ case OPENVMS : CCFLAGS ?= /stand=vaxc ;
+ case VMS : STDLIBS ?= sys$library:vaxcrtl.olb/lib ;
+ }
+}
+else if $(MAC)
+{
+ local OPT ;
+
+ CW ?= "{CW}" ;
+
+ MACHDRS ?=
+ "$(UMACHDRS):Universal:Interfaces:CIncludes"
+ "$(CW):MSL:MSL_C:MSL_Common:Include"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Include" ;
+
+ MACLIBS ?=
+ "$(CW):MacOS Support:Universal:Libraries:StubLibraries:Interfacelib"
+ "$(CW):MacOS Support:Universal:Libraries:StubLibraries:Mathlib" ;
+
+ MPWLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_MPWCRuntime_PPC.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC_MPW.Lib" ;
+
+ MPWNLLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_MPWCRuntime_PPC.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC_MPW(NL).Lib" ;
+
+ SIOUXHDRS ?= ;
+
+ SIOUXLIBS ?=
+ "$(CW):MacOS Support:Libraries:Runtime:Libs:MSL_Runtime_PPC.lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_SIOUX_PPC.Lib"
+ "$(CW):MSL:MSL_C:MSL_MacOS:Lib:PPC:MSL_C_PPC.Lib" ;
+
+ C++ ?= mwcppc ;
+ C++FLAGS ?= -w off ;
+ CC ?= mwcppc ;
+ CCFLAGS ?= -w off ;
+ CP ?= duplicate -y ;
+ DOT ?= ":" ;
+ DOTDOT ?= "::" ;
+ HDRS ?= $(MACHDRS) $(MPWHDRS) ;
+ LINK ?= mwlinkppc ;
+ LINKFLAGS ?= -mpwtool -warn ;
+ STDLIBS ?= $(MACLIBS) $(MPWLIBS) ;
+ SHSTDLIBS ?= $(STDLIBS) ;
+ MKDIR ?= newfolder ;
+ MV ?= rename -y ;
+ NOARSCAN ?= true ;
+ RM ?= delete -y ;
+ SLASH ?= ":" ;
+ STDHDRS ?= ;
+ SUFLIB ?= .lib ;
+ SUFOBJ ?= .o ;
+}
+else if $(OS) = BEOS && $(OSPLAT) = PPC
+{
+ AR ?= mwld -xml -o ;
+ BINDIR ?= /boot/home/config/bin ;
+ CC ?= mwcc ;
+ CCFLAGS ?= -nosyspath ;
+ C++ ?= $(CC) ;
+ C++FLAGS ?= -nosyspath ;
+ CHMOD ?= chmod ;
+ CHGRP ?= chgrp ;
+ CHOWN ?= chown ;
+ FORTRAN ?= "" ;
+ LEX ?= flex ;
+ LIBDIR ?= /boot/home/config/lib ;
+ LINK ?= mwld ;
+ LINKFLAGS ?= "" ;
+ MANDIR ?= /boot/home/config/man ;
+ NOARSCAN ?= true ;
+ RANLIB ?= ranlib ;
+ STDHDRS ?= /boot/develop/headers/posix ;
+ YACC ?= bison -y ;
+ YACCGEN ?= .c ;
+ YACCFILES ?= y.tab ;
+ YACCFLAGS ?= -d ;
+}
+else if $(OS) = BEOS
+{
+ BINDIR ?= /boot/home/config/bin ;
+ CC ?= gcc ;
+ C++ ?= $(CC) ;
+ CHMOD ?= chmod ;
+ CHGRP ?= chgrp ;
+ CHOWN ?= chown ;
+ FORTRAN ?= "" ;
+ LEX ?= flex ;
+ LIBDIR ?= /boot/home/config/lib ;
+ LINK ?= gcc ;
+ MANDIR ?= /boot/home/config/man ;
+ NOARSCAN ?= true ;
+ RANLIB ?= ranlib ;
+ STDHDRS ?= /boot/develop/headers/posix ;
+ YACC ?= bison -y ;
+ YACCGEN ?= .c ;
+ YACCFILES ?= y.tab ;
+ YACCFLAGS ?= -d ;
+}
+else if $(UNIX)
+{
+ switch $(OS)
+ {
+ case AIX :
+ STDLIBS ?= -lbsd ;
+
+ case AMIGA :
+ CC ?= gcc ;
+ YACC ?= bison -y ;
+
+ case CYGWIN :
+ CC ?= gcc ;
+ CCFLAGS += -D__cygwin__ ;
+ LEX ?= flex ;
+ JAMSHELL ?= sh -c ;
+ RANLIB ?= "" ;
+ SUFEXE ?= .exe ;
+ YACC ?= bison -y ;
+
+ case DGUX :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+
+ case HPUX :
+ RANLIB ?= "" ;
+
+ case INTERIX :
+ CC ?= gcc ;
+ JAMSHELL ?= sh -c ;
+ RANLIB ?= "" ;
+
+ case IRIX :
+ RANLIB ?= "" ;
+
+ case MPEIX :
+ CC ?= gcc ;
+ C++ ?= gcc ;
+ CCFLAGS += -D_POSIX_SOURCE ;
+ HDRS += /usr/include ;
+ RANLIB ?= "" ;
+ NOARSCAN ?= true ;
+ NOARUPDATE ?= true ;
+
+ case MVS :
+ RANLIB ?= "" ;
+
+ case NEXT :
+ AR ?= libtool -o ;
+ RANLIB ?= "" ;
+
+ case MACOSX :
+# AR ?= libtool -o ;
+ AR ?= ar rusc ;
+ C++ ?= c++ ;
+ MANDIR ?= /usr/local/share/man ;
+ RANLIB ?= "" ;
+ SUFSHLIB ?= .dylib ;
+ SUFIMPLIB ?= .dylib ;
+
+ case NCR :
+ RANLIB ?= "" ;
+
+ case PTX :
+ RANLIB ?= "" ;
+
+ case QNX :
+ AR ?= wlib ;
+ CC ?= cc ;
+ CCFLAGS ?= -Q ; # quiet
+ C++ ?= $(CC) ;
+ C++FLAGS ?= -Q ; # quiet
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= -Q ; # quiet
+ NOARSCAN ?= true ;
+ RANLIB ?= "" ;
+
+ case SCO :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+
+ case SINIX :
+ RANLIB ?= "" ;
+
+ case SOLARIS :
+ RANLIB ?= "" ;
+ AR ?= "/usr/ccs/bin/ar ru" ;
+
+ case UNICOS :
+ NOARSCAN ?= true ;
+ CCOPTFLAG ?= -O0 ;
+
+ case UNIXWARE :
+ RANLIB ?= "" ;
+ RELOCATE ?= true ;
+ }
+
+ # UNIX defaults
+
+ CCFLAGS ?= -DUNIX -D_THREAD_SAFE -pipe ;
+ CCOPTFLAG ?= -O2 ;
+ CCDEBUGFLAG ?= -g ;
+ CCPROFFLAG ?= ;
+ CCSHOBJFLAG ?= -fPIC ; # Position independent is better for ShLibrary
+ C++FLAGS ?= $(CCFLAGS) ;
+ CHMOD ?= chmod ;
+ CHGRP ?= chgrp ;
+ CHOWN ?= chown ;
+ LEX ?= lex ;
+ LINKFLAGS ?= ;
+ LINKOPTFLAG ?= -O ; # Affects creating .so's
+ LINKSTRIPFLAG ?= -s ;
+ LINKDEBUGFLAG ?= ;
+ LINKPROFFLAG ?= ;
+ SHLINKFLAGS ?= ; # Flags for creation of shared library
+ STDLIBS ?= -lm -lpthread ;
+ SHSTDLIBS ?= $(STDLIBS) ;
+ LINKFLAG ?= -l ;
+ RANLIB ?= "" ;
+ YACC ?= yacc ;
+ YACCGEN ?= .c ;
+ YACCFILES ?= y.tab ;
+ YACCFLAGS ?= -d ;
+
+ HDRS ?= /usr/local/include ;
+
+ # Add some good defaults for OS X
+ if $(OS) = MACOSX {
+ CCFLAGS += -Wno-sign-compare ; # supress new gcc4 warnings ?
+ CCFLAGS += -fpascal-strings ; # for compatibility with the OSX API
+ LINKFLAGS += -framework Carbon ; # default for .c
+ LINKFLAGS += -framework Cocoa ; # default for .m
+ }
+
+ # Make things work on 64 bit Linux
+ # Note that HOSTTYPE needs to be exported by the shell!
+ if $(HOSTTYPE) = x86_64
+ || $(HOSTTYPE) = x86_64-linux {
+ ECHO "We're on a 64 bit host" ;
+ HOST64 = true ;
+ CCFLAGS += -m64 ;
+ C++FLAGS += -m64 ;
+ }
+
+ # Adding --hash-style=sysv to the compiler options
+ # might improve Linux compatibility with FC5 ?
+}
+
+#
+# General defaults; a lot like UNIX
+#
+
+ AR ?= ar rusc ;
+ AS ?= as ;
+ ASFLAGS ?= ;
+ AWK ?= awk ;
+ BINDIR ?= /usr/local/bin ;
+ C++ ?= cc ;
+ C++FLAGS ?= ;
+ CC ?= cc ;
+ CCFLAGS ?= ;
+ CP ?= cp -f ;
+ CRELIB ?= ;
+ DOT ?= . ;
+ DOTDOT ?= .. ;
+ EXEMODE ?= 711 ;
+ FILEMODE ?= 644 ;
+ FORTRAN ?= f77 ;
+ FORTRANFLAGS ?= ;
+ HDRS ?= ;
+ INSTALLGRIST ?= installed ;
+ JAMFILE ?= Jamfile ;
+ JAMTOP ?= Jamtop ;
+ LEX ?= ;
+ LIBDIR ?= /usr/local/lib ;
+ LINK ?= $(CC) ;
+ LINKFLAGS ?= ;
+ SHLINKFLAGS ?= ;
+ STDLIBS ?= ;
+ SHSTDLIBS ?= $(STDLIBS) ;
+ LINKOUTFLAG ?= "-o " ;
+ LN ?= ln ;
+ MANDIR ?= /usr/local/man ;
+ MKDIR ?= mkdir ;
+ MV ?= mv -f ;
+ RCP ?= rcp ;
+ RM ?= rm -f ;
+ RMDIR ?= $(RM) ;
+ RSH ?= rsh ;
+ SED ?= sed ;
+ SHELLHEADER ?= "#!/bin/sh" ;
+ SHELLMODE ?= 755 ;
+ SLASH ?= / ;
+ STDHDRS ?= /usr/include ;
+ SUFEXE ?= "" ;
+ SUFSH ?= .sh ;
+ SUFLIB ?= .a ;
+ SUFSHLIB ?= .so ;
+ SUFIMPLIB ?= .so ;
+ SUFOBJ ?= .o ;
+
+ DEFFLAG ?= -D ;
+ UNDEFFLAG ?= -U ;
+ YACC ?= ;
+ YACCGEN ?= ;
+ YACCFILES ?= ;
+ YACCFLAGS ?= ;
+
+ HDRPATTERN =
+ "^[ ]*#[ ]*include[ ]*[<\"]([^\">]*)[\">].*$" ;
+
+ OSFULL = $(OS)$(OSVER)$(OSPLAT) $(OS)$(OSPLAT) $(OS)$(OSVER) $(OS) ;
+
+
+# ===========================================================
+
+#
+# Base dependencies - first for "bootstrap" kinds of rules
+#
+
+Depends all : shell files lib exe obj ;
+Depends all shell files lib exe obj install : first ;
+NotFile all first shell files lib exe obj dirs clean install uninstall ;
+Always clean uninstall ;
+
+# ===========================================================
+# ArgyllCMS Jambase building blocks:
+
+# Allow returning of a targets "on" variable
+# Only the first variable in the list "on" variable is retrieved
+# ret = geton target : variable ;
+rule noop { return $(<) ; }
+rule geton {
+ local _rv ;
+ _rv = [ on $(<[1]) noop $($(>)) ] ;
+ return $(_rv) ;
+}
+
+# Separate a single path into it's components, irrespective of
+# whether a MSWindows or UNIX path separator is used.
+# d1 d2 ... file = _SepPath path ;
+rule _SepPath
+{
+#Echo "_SepPath called with = '" $(<[1]) "'" ;
+
+ local _in = /$(<[1]) ; # leading / is to detect absolute path
+ local split = true ;
+ local _out = ;
+
+ if ! $(<) {
+#Echo "_SepPath returning '" "" "'" ;
+ return $(<) ;
+ }
+
+ split = [ MATCH (.*)[/\\](.*) : $(_in) ] ;
+ while $(split) {
+#Echo "Split = '" $(split[1]) "' and '" $(split[2]) "'" ;
+ _out = $(split[2]) $(_out) ;
+ _in = $(split[1]) ;
+ split = [ MATCH (.*)[/\\](.*) : $(_in) ] ;
+ }
+#Echo "After slplitting got '" $(_in) "' out '" $(_out) "'" ;
+
+ if $(_in) != "" { # No leading /
+#Echo "Setting _out to '" $(_in) "' plus '" $(_out) "'" ;
+ _out = $(_in) $(_out) ;
+ }
+
+#Echo "_SepPath initial sep =" $(_out) ;
+
+ # Deal with DOS drive letters
+ if $(NT) {
+ switch $(_out[1]) {
+ case *:* : {
+ split = [ MATCH (.*)[:](.*) : $(_out[1]) ] ;
+ if $(split[2]) != "" {
+ _out = $(split[1]): $(split[2]) $(_out[2-]) ;
+ } else {
+ _out = $(split[1]): $(SLASH) $(_out[2-]) ;
+ }
+ }
+ }
+#Echo "_SepPath after DOS letters _out =" $(_out) ;
+ }
+
+ # Make sure leading / is in the correct form
+ if $(_out[1]) = "/" || $(_out[1]) = "\\" {
+ _out = $(SLASH) $(_out[2-]) ;
+ }
+
+#Echo "_SepPath returning _out =" $(_out) ;
+
+ return $(_out) ;
+}
+
+# Turn a sequence of directories into a directory path.
+# Opposite of _SepPath
+# path = _DirName d1 d2 ... ;
+rule _DirName
+{
+ local _in = $(<) ;
+ local _out = "" ;
+
+#Echo "_DirName got '" $(_in) "'" ;
+
+ # Deal with DOS drive letters
+ if $(NT) {
+ switch $(_in[1]) {
+ case *:* : {
+#Echo "_DirName match x:" ;
+ _out = $(_in[1]) ;
+ _in = $(_in[2-]) ;
+ }
+ }
+#Echo "_DirName _in = '" $(_in) "' out = '" $(_out) "'" ;
+ }
+
+ # Deal with absolute path
+ if $(_in[1]) = "/" || $(_in[1]) = "\\" {
+ _out = $(_out)$(SLASH) ;
+ _in = $(_in[2-]) ;
+#Echo "_DirName abs in = '" $(_in) "' out = '" $(_out) "'" ;
+ }
+
+ while $(_in) {
+ _out = $(_out)$(_in[1]) ;
+ _in = $(_in[2-]) ;
+#Echo "_DirName in = '" $(_in) "' out = '" $(_out) "'" ;
+ if $(_in) {
+ _out = $(_out)$(SLASH) ;
+ }
+#Echo "_DirName sep in = '" $(_in) "' out = '" $(_out) "'" ;
+ }
+
+#Echo "_DirName returning '" $(_out) "'" ;
+ return $(_out) ;
+}
+
+# Rationalize a path (ie. cancell dirs & .. )
+# Currently paths that cancel out return " ".
+# d1 d2 .. file = _RatPath d1 d2 .. file ;
+rule _RatPath
+{
+ local _in = $(<) ;
+ local _rio = ; # reversed intermediate output
+ local _out = ;
+ local _gotdot = ; # There was at a dot in the input path
+ local _first = ; # Fixed first elements
+
+#Echo "_RatPath called with '" $(_in) "'" ;
+
+ # Deal with DOS drive letters
+ if $(NT) {
+ switch $(_in[1]) {
+ case *:* : {
+ _first = $(_first) $(_in[1]) ;
+ _in = $(_in[2-]) ;
+ }
+ }
+#Echo "_RatPath got first '" $(_first) "' in = '" $(_in) "'" ;
+ }
+
+ # Deal with absolute path or single dot
+ if $(_in[1]) = / || $(_in[1]) = \\ {
+ _first = $(_first) $(SLASH) ;
+ _in = $(_in[2-]) ;
+#Echo "_RatPath got first '" $(_first) "' in = '" $(_in) "'" ;
+ } else {
+ if $(_in[1]) = $(DOT) && ! $(_in[2-]) {
+ _first = $(_first) $(DOT) ;
+ _in = $(_in[2-]) ;
+#Echo "_RatPath got first '" $(_first) "' in = '" $(_in) "'" ;
+ }
+ }
+ while $(_in) {
+#Echo "Next = " $(_in[1]) " and last = " $(_rio[1]) ;
+ if $(_in[1]) = $(DOT) {
+ _gotdot = true ;
+ }
+ # if the .. will cancel out the previous directory
+ if $(_in[1]) = $(DOTDOT) && $(_rio[1]) && $(_rio[1] != $(DOTDOT) {
+ _rio = $(_rio[2-]) ; # Remove previous
+#Echo "Found .. so removed previous and got _rio = " $(_rio) ;
+ } else { # Add next
+ # If we're decending with a directory
+ if $(_in[1]) != $(DOT) {
+ _rio = $(_in[1]) $(_rio) ;
+#Echo "Adding so _rio = " $(_rio) ;
+ } else {
+#Echo "Found . so ignoring got _rio = " $(_rio) ;
+ }
+ }
+ _in = $(_in[2-]) ;
+ }
+ # Make sure that a single dot is preserved
+ if $(_gotdot) && ! $(_rio) {
+ _rio = $(DOT) ;
+ }
+#Echo "Final _rio = " $(_rio) ;
+ # Reverse it
+ for _i in $(_rio) {
+ _out = $(_i) $(_out) ;
+ }
+
+ # Preprent with first */
+ _out = $(_first) $(_out) ;
+
+#Echo "_RatPath rationalized to '" $(_out) "'" ;
+#Echo ;
+
+ return $(_out) ;
+}
+
+# Re-root a directory path by pre-pending the given path.
+# Don't do this if the path is absolute
+# Don't return anything if the path is empty.
+# p1 p2 .. file = _RootPath d1 d2 .. : p1 p2 ... file ;
+rule _RootPath
+{
+ local _i _out = ;
+
+#Echo "_RootPath called with '" $(<) "' and '" $(>) "'" ;
+
+ if ! $(>[1]) {
+#Echo "_RootPath no RHS returning '" $(<) "'" ;
+ return $(<) ;
+ }
+
+ if $(>[1]) = "/" || $(>[1]) = "\\" {
+#Echo "_RootPath RHS = / returning '" $(<) "'" ;
+ return $(>) ;
+ }
+ if $(NT) {
+ switch $(>[1]) {
+ case *:* : {
+#Echo "_RootPath RHS = drive: returning '" $(<) "'" ;
+ return $(>) ;
+ }
+ }
+ }
+
+#Echo "_RootPath returning '" $(<) $(>) "'" ;
+ return $(<) $(>) ;
+
+}
+
+# Re-root a set of directory paths by pre-pending the given path.
+# Don't do this if the path is absolute
+# Don't return anything if the path is empty.
+# paths = RootPaths dir : paths ;
+rule RootPaths
+{
+ local _d = [ _SepPath $(<[1]) ] ;
+ local _i _t ;
+ local _out = ;
+
+#Echo "RootPaths got dir '" $(<[1]) "' and paths '" $(>) "'" ;
+ for _i in $(>)
+ {
+ _t = [ _SepPath $(_i) ] ;
+ _t = [ _RootPath $(_d) : $(_t) ] ;
+ _t = [ _RatPath $(_t) ] ;
+ _out += [ _DirName $(_t) ] ;
+ }
+
+#Echo "RootPaths returns to '" $(_out) "'" ;
+
+ return $(_out) ;
+}
+
+# - - - - - - - - - - - - - -
+
+# Rationalize a set of paths (ie. cancell dirs & .. )
+# paths = RatPaths paths ;
+rule RatPaths
+{
+ local _i _t ;
+ local _out = ;
+
+#Echo "RatPaths got '" $(<) "'" ;
+ for _i in $(<)
+ {
+ _t = [ _SepPath $(_i) ] ;
+ _t = [ _RatPath $(_t) ] ;
+ _out += [ _DirName $(_t) ] ;
+ }
+
+#Echo "RatPaths returns to '" $(_out) "'" ;
+
+ return $(_out) ;
+}
+
+# Normalize a set of paths. This resolves the
+# paths location with respect to SUBDIR, and so
+# accounting for the location of the Jamfile
+# the path is declared, and rationalizes the result.
+# If the optional dir is present, use it to
+# locate their targets rather than SUBDIR.
+# If paths is empty, nothing is returned.
+# SRCDIR and DSTDIR are ignored.
+# paths = NormPaths paths : [ dir ] ;
+rule NormPaths
+{
+ return [ _NormPaths $(<) : $(>) : "none" ] ;
+}
+
+# Normalize a set of Source paths. This resolves the
+# paths location with respect to SUBDIR, and so
+# accounting for the location of the Jamfile
+# the path is declared, and rationalizes the result.
+# If the optional dir is present, use it to
+# locate thie targets rather than SUBDIR.
+# If paths is empty, nothing is returned.
+# paths = NormPaths paths : [ dir ] ;
+rule NormSrcPaths
+{
+ return [ _NormPaths $(<) : $(>) : "src" ] ;
+}
+
+# Normalize a set of destination paths. This resolves the
+# paths location with respect to SUBDIR, and so
+# accounting for the location of the Jamfile
+# the path is declared, and rationalizes the result.
+# If the optional dir is present, use it to
+# locate thie targets rather than SUBDIR.
+# If paths is empty, nothing is returned.
+# paths = NormPaths paths : [ dir ] ;
+rule NormDstPaths
+{
+ return [ _NormPaths $(<) : $(>) : "dst" ] ;
+}
+
+# Normalize a set of paths. This resolves the
+# paths location with respect to SUBDIR, and so
+# accounting for the location of the Jamfile
+# the path is declared, and rationalizes the result.
+# If the optional dir is present, use it to
+# locate thie targets rather than SUBDIR.
+# If paths is empty, nothing is returned.
+# paths = NormPaths paths : dir : type ;
+# (This and the other rules it calls, is probably a good candidate for speed optimization!)
+rule _NormPaths
+{
+ local _p _i _t ;
+ local _out = ;
+ local _src _dst ;
+
+ if $(>) {
+ _p = [ _SepPath $(>[1]) ] ;
+ _p = [ _RatPath $(_p) ] ;
+ } else {
+ _p = $(_SUBDIR) ;
+ }
+
+ _src = [ _SepPath $(SRCDIR) ] ;
+ _dst = [ _SepPath $(DSTDIR) ] ;
+
+#Echo "_NormPaths got '" $(<) "' dir '" $(_p) "' type '" $(3) "'srcdir "' $(_src) "' dstdir '" $(_dst) "'" ;
+ for _i in $(<)
+ {
+#Echo "_i = '" $(_i) "'" ;
+ _t = [ _SepPath $(_i) ] ;
+#Echo "_SepPath _i = '" $(_i) "'" ;
+ _t = [ _RootPath $(_p) : $(_t) ] ;
+#Echo "_RootPath _t = '" $(_t) "'" ;
+
+ if $(_src) && $(3) = "src" {
+ _t = [ _RootPath $(_src) : $(_t) ] ;
+#Echo "_src += _t = '" $(_i) "'" ;
+
+ } else if $(_dst) && $(3) = "dst" {
+ local _f ;
+ _t = [ _DirName $(_t) ] ;
+ _f = [ _SepPath $(_t:BS) ] ;
+ _t = $(_t:D) ;
+ if ! $(_t) {
+ _t = $(DOT) ;
+ }
+ _t = [ _RootPath [ _SepPath $(_t) ] : $(_dst) ] $(_f) ;
+#Echo " _t += _dst = '" $(_t) "'" ;
+ }
+ _t = [ _RatPath $(_t) ] ;
+#Echo "_RatPath _t = '" $(_t) "'" ;
+ # Special case of complete cancelation that can occure for a pure
+ # directory path (?)
+ if $(_t) = "" {
+ _t = "." ;
+ }
+ _t = [ _DirName $(_t) ] ;
+ _out += $(_t) ;
+#Echo "_out += '" $(_t) "'" ;
+ }
+
+#Echo "_NormPaths returns '" $(_out) "'" ;
+ return $(_out) ;
+}
+
+# Normalize a set of targets.
+# This is the same as NormPaths except it
+# then strips the path out and uses it to set the
+# Grist, NOMLOC, LOCATE and SEARCH on the target.
+# If the optional dir is present, use it to
+# locate the targets rather than SUBDIR.
+# Ignore SRCDIR if present.
+# paths = NormTargets paths [ : dir ] ;
+rule NormISrcTargets
+{
+ return [ _NormTargets $(<) : $(>) : "isrc" ] ;
+}
+
+# Normalize a set of targets.
+# This is the same as NormPaths except it
+# then strips the path out and uses it to set the
+# Grist, NOMLOC, LOCATE and SEARCH on the target.
+# If the optional dir is present, use it to
+# locate the targets rather than SUBDIR.
+# se DSTDIR if present.
+# paths = NormTargets paths [ : dir ] ;
+rule NormIDstTargets
+{
+ return [ _NormTargets $(<) : $(>) : "idst" ] ;
+}
+
+# Normalize a set of targets.
+# This is the same as NormPaths except it
+# then strips the path out and uses it to set the
+# Grist, NOMLOC, LOCATE and SEARCH on the target.
+# If the optional dir is present, use it to
+# locate the targets rather than SUBDIR.
+# Use SRCDIR if present.
+# paths = NormTargets paths [ : dir ] ;
+rule NormSrcTargets
+{
+ return [ _NormTargets $(<) : $(>) : "src" ] ;
+}
+
+# Normalize a set of targets.
+# This is the same as NormPaths except it
+# then strips the path out and uses it to set the
+# Grist, NOMLOC, LOCATE and SEARCH on the target.
+# If the optional dir is present, use it to
+# locate the targets rather than SUBDIR.
+# Use DSTDIR if present.
+# paths = NormTargets paths [ : dir ] ;
+rule NormDstTargets
+{
+ return [ _NormTargets $(<) : $(>) : "dst" ] ;
+}
+
+# Normalize a set of targets.
+# This is the same as NormPaths except it
+# then strips the path out and uses it to set the
+# Grist, NOMLOC, LOCATE and SEARCH on the target.
+# If the optional dir is present, use it to
+# locate the targets rather than SUBDIR.
+# paths = NormTargets paths : dir : type ;
+rule _NormTargets
+{
+ local _p _i _t _d _ds ;
+ local _out = ;
+ local _src _dst ;
+
+ if $(>) {
+ _p = [ _SepPath $(>[1]) ] ;
+ } else {
+ _p = $(_SUBDIR) ;
+ }
+
+ if $(3) = "src" || $(3) = "dst" {
+ _src = [ _SepPath $(SRCDIR) ] ;
+ _dst = [ _SepPath $(DSTDIR) ] ;
+ }
+
+#Echo ;
+#Echo "_NormTargets got '" $(<) "' base = '" $(_p) "' type '" $(3) "' srcdir = '" $(_src) "' dstdirr = '" $(_dst) "'" ;
+ for _i in $(<)
+ {
+ _t = [ _SepPath $(_i) ] ;
+#Echo " _t = '" $(_t) "'" ;
+ _t = [ _RootPath $(_p) : $(_t) ] ;
+#Echo " _t = '" $(_t) "'" ;
+ _t = [ _RatPath $(_t) ] ;
+#Echo " _t = '" $(_t) "'" ;
+ _t = [ _DirName $(_t) ] ;
+#Echo " _t = '" $(_t) "'" ;
+ _d = $(_t:D) ;
+#Echo " _d = '" $(_d) "'" ;
+ _ds = [ _SepPath $(_d) ] ;
+#Echo " _ds = '" $(_ds) "'" ;
+ _t = $(_t:D=) ;
+#Echo " _t = '" $(_t) "'" ;
+ _t = $(_t:G=$(_ds:J=!)) ;
+#Echo " _t = '" $(_t) "'" ;
+
+ # dst trumps all the others
+ if $(3) = "dst" {
+ if $($(_t)-target) != "dst" {
+ NOMLOC on $(_t) = $(_d) ;
+ if $(_dst) {
+ if ! $(_ds) {
+ _ds = $(DOT) ;
+ }
+ _d = [ _DirName [ _RootPath $(_ds) : $(_dst) ] ] ;
+ }
+ if $(_d) = "/" || $(_d) = "\\" { # Jam has a bug when locating in root
+ _d = $(_d). ;
+ }
+ LOCATE on $(_t) = $(_d) ;
+ $(_t)-target = "dst" ;
+ }
+
+ # idst trumps src and isrc
+ } else if $(3) = "idst" {
+ if $($(_t)-target) != "dst" && $($(_t)-target) != "idst" {
+ NOMLOC on $(_t) = $(_d) ;
+ if $(_d) = "/" || $(_d) = "\\" { # Jam has a bug when locating in root
+ _d = $(_d). ;
+ }
+ LOCATE on $(_t) = $(_d) ;
+ $(_t)-target = "idst" ;
+ }
+
+ # src trumps isrc
+ } else if $(3) = "src" {
+ if $($(_t)-target) != "dst" && $($(_t)-target) != "idst"
+ && $($(_t)-target) != "src" {
+ local _d1 _d2 ;
+ NOMLOC on $(_t) = $(_d) ;
+ if $(_src) {
+ _d1 = [ _DirName [ _RootPath $(_src) : $(_ds) ] ] ;
+ } else {
+ _d1 = $(_d) ;
+ }
+ if $(_dst) {
+ if ! $(_ds) {
+ _ds = $(DOT) ;
+ }
+ _d2 = [ _DirName [ _RootPath $(_ds) : $(_dst) ] ] ;
+ }
+ if $(_d1) = "/" || $(_d1) = "\\" { # Jam has a bug when locating in root
+ _d1 = $(_d1). ;
+ }
+ if $(_d2) = "/" || $(_d2) = "\\" { # Jam has a bug when locating in root
+ _d2 = $(_d2). ;
+ }
+ # We assume that if we've got a DSTDIR here, then
+ # it may apply to this source, even if it is never
+ # gets labelled this way. - ie. it may be a dst of a
+ # Jamfile with the same DSTDIR that's not in scope.
+ SEARCH on $(_t) = $(_d2) $(_d1) ;
+ $(_t)-target = "src" ;
+ }
+
+ # isrc is lowest priority
+ } else if $(3) = "isrc" && ! $($(_t)-target) {
+ if $(_d) = "/" || $(_d) = "\\" { # Jam has a bug when locating in root
+ _d = $(_d). ;
+ }
+ NOMLOC on $(_t) = $(_d) ;
+ SEARCH on $(_t) = $(_d) ;
+ $(_t)-target = "isrc" ;
+ }
+
+#Echo "On '" $(_t) "' set LOCATE = '" [ geton $(_t) : LOCATE ] "' SEARCH = '" [ geton $(_t) : SEARCH ] "' NOMLOC = '" [ geton $(_t) : NOMLOC ] "'" ;
+ _out += $(_t) ;
+ }
+
+#Echo "_NormTargets returns to '" $(_out) "'" ;
+ return $(_out) ;
+}
+
+# Given a set of normalized paths, return the Target ID's for
+# them (ie. Gristed version of path)
+# IDs = _TargetIDs targpaths ;
+rule _TargetIDs
+{
+ local _i _t _d _ds ;
+ local _out = ;
+
+#Echo "_TargetIDs got '" $(<) "'" ;
+ for _i in $(<)
+ {
+ _d = $(_i:D) ;
+ _ds = [ _SepPath $(_d) ] ;
+ _t = $(_i:D=) ;
+ _t = $(_t:G=$(_ds:J=!)) ;
+ _out += $(_t) ;
+ }
+
+#Echo "_TargetIDs returning '" $(_out) "'" ;
+ return $(_out) ;
+}
+
+
+# Copy the target related "on" variables from one
+# target to another.
+#rule CopyTarget dest : source ;
+rule CopyTarget
+{
+ NOMLOC on $(<) = [ geton $(>) : NOMLOC ] ;
+ LOCATE on $(<) = [ geton $(>) : LOCATE ] ;
+ SEARCH on $(<) = [ geton $(>) : SEARCH ] ;
+}
+
+# Make sure a non-target isn't LOCATED or SEARCH'd by
+# setting LOCATE, SEARCH and NOMLOC to ""
+#rule NotTargets vars ;
+rule NotTargets
+{
+ NOMLOC on $(<) = "" ;
+ LOCATE on $(<) = "" ;
+ SEARCH on $(<) = "" ;
+}
+
+# Create a destination target by locating
+# the given files in the given directory.
+# The dir is assumed to be normalized.
+# SRCDIR and DSTDIR are ignored.
+# targs = SetTargetsLoc targs : dir ;
+rule CreateIDstTargets
+{
+ local _o ;
+#Echo "CreateIDstTargets got '" $(<) "' and '" $(>) "'" ;
+ _o = [ NormIDstTargets $(<:BS) : $(>[1]) ] ;
+#Echo "CreateIDstTargets returning '" $(_o) "'" ;
+ return $(_o) ;
+}
+
+# Given a normalized target, return the
+# orgiginal path to it.
+# (We use NOMLOC to do this.)
+# path = DeNormTargs target ;
+rule DeNormTargs
+{
+ local _i _t _p _out = ;
+
+ for _i in $(<) {
+ _p = [ geton $(_i) : NOMLOC ] ;
+ _t = $(_i:G=) ;
+ _out += $(_t:D=$(_p)) ;
+ }
+
+ return $(_out) ;
+}
+
+# Given a list of directories and a list of files,
+# simply concatenate them in combination separated by a /
+# paths1/paths = CatPaths path1 : paths ;
+rule CatPaths
+{
+ return $(<)$(SLASH)$(>) ;
+}
+
+# Try and locate a given file pattern starting from the current
+# directory and working towards the root.
+# We use a heuristic to figure out when to stop, since
+# Jam doesn't have pwd :-(
+# found = FindRoot starting_dir : file ;
+rule FindToRoot
+{
+ local dir = $(<[1]) ;
+ local dir_list, prev_list = ;
+ local dir_list;
+ local found = ;
+
+#Echo "FindToRoot got starting_dir '" $(<) "' file '" $(>) "'" ;
+ found = [ GLOB $(dir) : $(>[1]) ] ;
+
+ if $(found) {
+ return $(found) ;
+ }
+
+#Echo "dir_list = " $(dir_list) ;
+
+ dir_list = [ GLOB $(dir) : * ] ;
+ while $(dir_list:D="") != $(prev_list:D="") {
+ dir = $(dir)$(SLASH)$(DOTDOT) ;
+#Echo "dir = " $(dir) ;
+ found = [ GLOB $(dir) : $(>[1]) ] ;
+
+ if $(found) {
+ return $(found) ;
+ }
+
+ prev_list = $(dir_list) ;
+ dir_list = [ GLOB $(dir) : * ] ;
+#Echo "dir_list = " $(dir_list) ;
+ }
+#Echo "returning " $(found) ;
+ return $(found) ;
+}
+
+# -----------------------------------------
+
+rule DoInit
+{
+ if ! $(DONEANCHORINIT) {
+
+ SUBDIR ?= $(DOT) ;
+ _SUBDIR ?= $(DOT) ;
+
+ # initial "parent" settings
+ P_ASFLAGS = ;
+ P_CCFLAGS = ;
+ P_C++FLAGS = ;
+ P_LINKFLAGS = ;
+ P_SHLINKFLAGS = ;
+ P_HDRS = ;
+ P_DEFINES = ;
+
+ P_PREF_ASFLAGS = ;
+ P_PREF_CCFLAGS = ;
+ P_PREF_C++FLAGS = ;
+ P_PREF_LINKFLAGS = ;
+ P_PREF_SHLINKFLAGS = ;
+
+ FindTop ; # Look for a default project file
+
+ TRACESTDHDRS = false ; # don't trace system path #include file dependenicies
+ DONEANCHORINIT = true ;
+ }
+}
+
+# Set the project top for this Jamfile and all sub Jamfiles
+# until another top is set or we return.
+# ProjTop d1 d2 .. ;
+rule ProjTop
+{
+#Echo "ProjTop got '" $(<) "'" ;
+
+ _TOP = [ _RatPath $(<) ] ;
+ TOP = [ _DirName $(_TOP) ] ;
+
+#Echo "ProjTop set TOP to '" $(TOP) "'" ;
+
+ if ! $($(TOP)-SET) { # Not tried to read the project file
+
+ local found = [ GLOB $(_top) : $(JAMFILE) ] ;
+
+ if $(found) {
+ local save__SUBDIR = $(_SUBDIR) ;
+ local save__INVSUBDIR = $(_INVSUBDIR) ;
+ local save_SUBDIR = $(SUBDIR) ;
+
+ _SUBDIR = $(_TOP) ;
+ _INVSUBDIR = [ _InvertPath $(_SUBDIR) ] ;
+ SUBDIR = [ _DirName $(_SUBDIR) ] ;
+#Echo "_SUBDIR = '" $(_SUBDIR) "'" ;
+#Echo "_INVSUBDIR = '" $(_INVSUBDIR) "'" ;
+
+ # Translate SRCDIR for new SUBDIR
+ if $(SRCDIR) {
+#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
+ SRCDIR = [ _SepPath $(SRCDIR) ] ;
+ SRCDIR = [ _RootPath $(_INVSUBDIR) : [ _RootPath $(SRCDIR) : $(_SUBDIR) ] ] ;
+ SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
+#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
+ }
+
+#Echo "About to include Jamtop '" $(found) "'" ;
+ include $(found) ;
+
+ # Un Translate SRCDIR, in case it was set in the rules directory
+ if $(SRCDIR) {
+#Echo "_SUBDIR = '" $(_SUBDIR) "'" ;
+#Echo "_INVSUBDIR = '" $(_INVSUBDIR) "'" ;
+#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
+ SRCDIR = [ _SepPath $(SRCDIR) ] ;
+ SRCDIR = [ _RootPath $(_SUBDIR) : [ _RootPath $(SRCDIR) : $(_INVSUBDIR) ] ] ;
+ SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
+#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
+ }
+
+ # Restore things
+ _SUBDIR = $(save__SUBDIR) ;
+ _INVSUBDIR = $(save__INVSUBDIR) ;
+ SUBDIR = $(save_SUBDIR) ;
+ } else {
+ Echo "WARNING :- no project " $(TOP) "Jamtop found" ;
+ }
+
+ $(TOP)-SET = true ;
+ }
+}
+
+# Search for the project top by looking for the Jamtop
+# starting at $(SUBDIR) and lookup upwards.
+# FindTop ;
+rule FindTop
+{
+#Echo ;
+#Echo "FindTop called SUBDIR = '" $(SUBDIR) "'" ;
+
+ local _JRF = [ FindToRoot $(SUBDIR) : $(JAMTOP) ] ;
+
+#Echo "FindTop found '" $(_JRF) "'" ;
+ if $(_JRF) {
+
+ _TOP = [ _RatPath [ _SepPath $(_JRF:D) ] ] ;
+ TOP = [ _DirName $(_TOP) ] ;
+#Echo "ProjTop set TOP to '" $(TOP) "'" ;
+
+ if ! $($(TOP)-SET) { # Not tried to read the project file
+ local save__SUBDIR = $(_SUBDIR) ;
+ local save__INVSUBDIR = $(_INVSUBDIR) ;
+ local save_SUBDIR = $(SUBDIR) ;
+
+ _SUBDIR = $(_TOP) ;
+ _INVSUBDIR = [ _InvertPath $(_SUBDIR) ] ;
+ SUBDIR = [ _DirName $(_SUBDIR) ] ;
+#Echo "_SUBDIR = '" $(_SUBDIR) "'" ;
+#Echo "_INVSUBDIR = '" $(_INVSUBDIR) "'" ;
+
+ # Translate SRCDIR for new SUBDIR
+ if $(SRCDIR) {
+#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
+ SRCDIR = [ _SepPath $(SRCDIR) ] ;
+ SRCDIR = [ _RootPath $(_INVSUBDIR) : [ _RootPath $(SRCDIR) : $(_SUBDIR) ] ] ;
+ SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
+#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
+ }
+
+#Echo "About to include Jamtop '" $(_JRF) "'" ;
+ include $(_JRF) ;
+ $(TOP)-SET = true ;
+
+ # Un Translate SRCDIR, in case it was set in the ruls directory
+ if $(SRCDIR) {
+#Echo "_SUBDIR = '" $(_SUBDIR) "'" ;
+#Echo "_INVSUBDIR = '" $(_INVSUBDIR) "'" ;
+#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
+ SRCDIR = [ _SepPath $(SRCDIR) ] ;
+ SRCDIR = [ _RootPath $(_SUBDIR) : [ _RootPath $(SRCDIR) : $(_INVSUBDIR) ] ] ;
+ SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
+#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
+ }
+
+ # Restore things
+ _SUBDIR = $(save__SUBDIR) ;
+ _INVSUBDIR = $(save__INVSUBDIR) ;
+ SUBDIR = $(save_SUBDIR) ;
+ }
+ } else {
+ Echo "WARNING :- no project Jamtop found, no TOP set !" ;
+
+ if ! $(TOP) {
+ TOP = $(DOT) ; # set a default TOP
+ _TOP = $(DOT) ;
+ }
+ }
+}
+
+# Given a path relative to CWD, return the inverse direction
+# path. Return nothing if the path is absolute.
+# [ we're using a hack here, since Jam 2.5 doesn't have
+# any functions that will simply resolve a path relative
+# to CWD into an absolute path. ]
+# d1 d2 .. = _InvertPath d1 d2 ..
+rule _InvertPath
+{
+ local _i _o _d ;
+#Echo "_InvertPath got '" $(<) "'" ;
+ if $(<[1]) = "/" || $(<[1]) = "\\" {
+#Echo "_InvertPath returning nothing" ;
+ return "" ;
+ }
+ if $(NT) {
+ switch $(<[1]) {
+ case *:* : {
+#Echo "_InvertPath returning nothing" ;
+ return "" ;
+ }
+ }
+ }
+
+ for _i in $(<) {
+#Echo "_InvertPath _i = '" $(_i) "' _o = '" $(_o) "'" ;
+ # Ignore .
+ if $(_i) = $(DOT) {
+ continue ;
+ }
+ # The hard one. Look amongst all the
+ # sub directories for one that has the same
+ # contents as the directory we came from.
+ # Too bad if two directories have the same contents...
+ if $(_i) = $(DOTDOT) {
+ local _j;
+ local _d1 _d2 _l1, _l2 _l3 ;
+
+#Echo "_InvertPath inverting '" $(_i) "'" ;
+
+ _d1 = [ _DirName $(_d) ] ;
+ _l1 = [ GLOB $(_d1) : * ] ;
+#Echo "_d1 = '" $(_d1) "'" ;
+ _d += $(_i) ;
+ _d2 = [ _DirName $(_d) ] ;
+#Echo "_d2 = '" $(_d2) "'" ;
+ _l2 = [ GLOB $(_d2) : * ] ;
+
+ for _j in $(_l2) {
+ if $(_j) = $(DOT) || $(_j) = $(DOTDOT) {
+ continue ;
+ }
+#Echo "Checking _j = '" $(_j) "'" ;
+ _l3 = [ GLOB $(_j) : * ] ;
+#Echo "_l1 = '" $(_l1) "'" ;
+#Echo "_l3 = '" $(_l3:BS) "'" ;
+ if $(_l3:BS) = $(_l1) {
+#Echo "Found reverse = '" $(_j) "'" ;
+ _o = $(_j:BS) $(_o) ;
+ break ;
+ }
+ }
+
+ # The easy one. the opposite of a directory
+ # is ..
+ } else {
+ _o = $(DOTDOT) $(_o) ;
+ _d += $(_i) ;
+ }
+ }
+ if ! $(_o) {
+ _o = $(DOT) ;
+ }
+
+#Echo "_InvertPath returning '" $(_o) "'" ;
+ return $(_o) ;
+}
+
+# Variables containing (possible) relative paths that are to remain
+# anchored to where they were declared. This is to prevent
+# NormPath in a sub-Jamfile assuming they are relative to that Jamfile.
+# (This is a bit messy. How could it be avoided ? If there were
+# a simple way of making paths absolute, rather than computing eveything
+# relative to the invokation directory, it could help.)
+ANCHORED_PATH_VARS = ;
+
+# Variables to save before starting a new Jamfile, then
+# restore once it's finished.
+
+SUBDIR_VARS = SUBDIR _SUBDIR TOP _TOP SRCDIR DSTDIR
+ P_ASFLAGS P_CCFLAGS P_C++FLAGS P_LINKFLAGS P_SHLINKFLAGS
+ ASFLAGS CCFLAGS C++FLAGS LINKFLAGS SHLINKFLAGS
+ P_PREF_ASFLAGS P_PREF_CCFLAGS P_PREF_C++FLAGS P_PREF_LINKFLAGS
+ PREF_ASFLAGS PREF_CCFLAGS PREF_C++FLAGS PREF_LINKFLAGS PREF_SHLINKFLAGS
+ P_HDRS HDRS
+ P_DEFINES DEFINES
+ P_LINKOBJS LINKOBJS
+ P_LINKLIBS LINKLIBS
+ P_LINKSHLIBS LINKSHLIBS
+ P_SHLINKOBJS SHLINKOBJS
+ P_SHLINKLIBS SHLINKLIBS
+ P_SHLINKSHLIBS SHLINKSHLIBS
+ ;
+
+# Implement including a Jamfile from a sub or peer directory,
+# Sub includes cause flags/headers/options to be inhereted
+# from the calling Jamfile, while Peer includes do not.
+# The global _JAMINCLUDE_PEER variable controls whether
+# this is a sub or peer include.
+# _JamInclude dir ;
+rule _JamInclude
+{
+#Echo "_JamInclude called with '" $(<) "' SUBDIR '" $(SUBDIR) "' and _JAMINCLUDE_PEER '" $(_JAMINCLUDE_PEER) "'" ;
+
+ # Save certain variables so that sub-Jamfiles don't affect them
+ local _jamfile ;
+ local _SUBDIR_VARS = $(SUBDIR_VARS) $(ANCHORED_PATH_VARS) ;
+ local _i parent_$(_SUBDIR_VARS) ;
+
+ for _i in $(_SUBDIR_VARS) {
+ parent_$(_i) = $($(_i)) ;
+ }
+
+ 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) ;
+
+ # Set parent flags no existing parent flags
+ if ! $(P_PREF_ASFLAGS) {
+ P_PREF_ASFLAGS = $(PREF_ASFLAGS) ; }
+ if ! $(P_PREF_CCFLAGS) {
+ P_PREF_CCFLAGS = $(PREF_CCFLAGS) ; }
+ if ! $(P_PREF_C++FLAGS) {
+ P_PREF_C++FLAGS = $(PREF_C++FLAGS) ; }
+ if ! $(P_PREF_LINKFLAGS) {
+ P_PREF_LINKFLAGS = $(PREF_LINKFLAGS) ; }
+ if ! $(P_PREF_SHLINKFLAGS) {
+ P_PREF_SHLINKFLAGS = $(PREF_SHLINKFLAGS) ; }
+ }
+
+ # Set default for new Jamfile extra and preferred flags
+ ASFLAGS = ;
+ CCFLAGS = ;
+ C++FLAGS = ;
+ LINKFLAGS = ;
+ SHLINKFLAGS = ;
+ HDRS = ;
+ DEFINES = ;
+ LINKOBJS = ;
+ LINKLIBS = ;
+ LINKSHLIBS = ;
+ SHLINKOBJS = ;
+ SHLINKLIBS = ;
+ SHLINKSHLIBS = ;
+
+ PREF_ASFLAGS = ;
+ PREF_CCFLAGS = ;
+ PREF_C++FLAGS = ;
+ PREF_LINKFLAGS = ;
+ PREF_SHLINKFLAGS = ;
+
+ _SUBDIR = [ _RatPath [ _RootPath $(_SUBDIR) : [ _SepPath $(<) ] ] ] ;
+ _INVSUBDIR = [ _InvertPath $(_SUBDIR) ] ;
+ SUBDIR = [ _DirName $(_SUBDIR) ] ;
+
+#Echo "new _SUBDIR =" $(_SUBDIR) ;
+#Echo "new _INVSUBDIR =" $(_INVSUBDIR) ;
+
+ if $(_INVSUBDIR) != "." {
+ # Keep paths relative to where they were defined, so that
+ # NormPaths doesn't think they are relative to the sub-Jamfile.
+#Echo "Before ANCHORED_PATH_VARS = $(ANCHORED_PATH_VARS) vals $($(ANCHORED_PATH_VARS))" ;
+ for _i in $(ANCHORED_PATH_VARS) {
+ $(_i) = [ RootPaths $(_INVSUBDIR) : $($(_i)) ] ;
+ }
+#Echo "After ANCHORED_PATH_VARS = $(ANCHORED_PATH_VARS) vals $($(ANCHORED_PATH_VARS))" ;
+ }
+
+ # Translate SRCDIR for new SUBDIR
+#Echo "SRCDIR olddir '" $(SRCDIR) "'" ;
+ if $(SRCDIR) {
+ local subdir = $(_SUBDIR[2-]) ;
+ local invsubdir = [ FReverse $(_INVSUBDIR) ] ;
+ invsubdir = [ FReverse $(invsubdir[2-]) ] ;
+#Echo "subdir-1 =" $(subdir) ;
+#Echo "invsubdir-1 =" $(invsubdir) ;
+ SRCDIR = [ _SepPath $(SRCDIR) ] ;
+ SRCDIR = [ _RootPath $(invsubdir) : [ _RootPath $(SRCDIR) : $(subdir) ] ] ;
+ SRCDIR = [ _DirName [ _RatPath $(SRCDIR) ] ] ;
+#Echo "SRCDIR newdir '" $(SRCDIR) "'" ;
+ }
+
+ _jamfile = [ NormSrcPaths $(JAMFILE) ] ;
+
+#Echo "About to include " $(_jamfile) ;
+ include $(_jamfile) ;
+
+ # Restore variable before returning
+ for _i in $(_SUBDIR_VARS) {
+ $(_i) = $(parent_$(_i)) ;
+ }
+
+#Echo "Done include " $(JAMFILE:D=$(_subdir)) ;
+#Echo "restored SUBDIR =" $(SUBDIR) ;
+#Echo "_JamInclude done" ;
+}
+
+# Invoke a Jamfile as a sub Jamfile
+# SubInclude dir ;
+rule SubInclude
+{
+#Echo "### SubInclude called with '" $(<[1]) "' and SUBDIR = '" $(SUBDIR) "'" ;
+ _JAMINCLUDE_PEER = "false" ; # This is a sub include
+ return [ _JamInclude $(<) ] ;
+}
+
+# Invoke a Jamfile in as a peer Jamfile
+# PeerInclude dir ;
+rule PeerInclude
+{
+#Echo "### PeerInclude called with '" $(<[1]) "' and SUBDIR = '" $(SUBDIR) "'" ;
+ _JAMINCLUDE_PEER = "true" ; # This is a peer include
+ return [ _JamInclude $(<) ] ;
+}
+
+# ===========================================================
+#
+# Rules
+#
+
+# Public As
+# As obj : source.s ; .s -> .o
+rule As
+{
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
+ local _s = [ NormSrcTargets $(>) ] ;
+
+ Depends $(_t) : $(_s) ;
+ Depends obj : $(_t) ;
+ MakeLocate $(_t) ;
+
+ HDRS on $(_t) = [ geton $(_t) : SEARCH ] [ NormPaths $(HDRS) ] $(P_HDRS) ;
+}
+
+# Internal As
+rule As_
+{
+ local pref_asflags = $(P_PREF_ASFLAGS) ;
+ pref_asflags ?= $(PREF_ASFLAGS) ;
+ ASFLAGS1 on $(<) = $(P_ASFLAGS) $(ASFLAGS) ;
+ ASFLAGS2 on $(<) = $(pref_asflags) ;
+ ASFLAGS on $(<) = [ geton $(<) : ASFLAGS1 ] [ geton $(<) : ASFLAGS2 ] ;
+ ASHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
+}
+
+# copies sources into directory.
+# SRCDIR and DSTDIR will be ignored.
+# Bulk directory : sources ;
+rule Bulk
+{
+#Echo "Bulk got '" $(<) "' and '" $(>) "'" ;
+ local _d = [ NormPaths $(<) ] ; # Directory
+ local _s = [ NormSrcTargets $(>) ] ; # Sources
+ local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
+ local _is _it ; # individual source and target
+
+ for _is in $(_s)
+ {
+ _it = $(_t[1]) ;
+ _t = $(_t[2-]) ; # Track _is
+
+ Depends files : $(_it) ;
+ Depends $(_it) : $(_is) ;
+ MakeLocate $(_it) ;
+ File_ $(_it) : $(_is) ;
+ MODE on $(_it) = $(FILEMODE) ;
+ Chmod_ $(_it) ;
+ }
+}
+
+# Cc object : source : flags : defines : hdrpaths ;
+rule Cc
+{
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ Depends $(_t) : $(_s) ;
+ Depends obj : $(_t) ;
+ Clean clean : $(_t) ;
+ MakeLocate $(_t) ;
+
+ HDRS on $(_t) = [ geton $(_t) : SEARCH ] [ NormPaths $(HDRS) ] $(P_HDRS) ;
+ SOURCE on $(_t) = $(_s) ;
+
+ HDRRULE on $(_s) = HdrRule ;
+ HDRSCAN on $(_s) = $(HDRPATTERN) ;
+ # Construct HDRSEARCH so that we can know where to look for headers
+ local _dot = [ geton $(_>) : NOMLOC ] ;
+ if ! $(_dot) { _dot = $(DOT) ; }
+ HDRSEARCH1 on $(_s) = $(_dot) ;
+ HDRSEARCH2 on $(_s) = [ NormPaths $(HDRS) ] $(P_HDRS) ;
+ HDRSEARCH3 on $(_s) = [ NormPaths $(STDHDRS) ] ;
+ HDRSEARCH on $(_s) = [ geton $(_s) : HDRSEARCH1 ] [ geton $(_s) : HDRSEARCH2 ]
+ [ geton $(_s) : HDRSEARCH3 ] ;
+#Echo "Cc set HDRSEARCH on '" $(_s) "' to '" [ geton $(_s) : HDRSEARCH ] "'" ;
+
+ # propagate target specific-defines
+
+ DEFINES on $(_t) = $(P_DEFINES) $(DEFINES) ;
+
+ Cc_ $(_t) : $(_s) : $(3) ;
+
+ if $(3) {
+ ObjectCcFlags $(<) : $(3) ;
+ }
+ if $(4) {
+ ObjectDefines $(<) : $(4) ;
+ }
+ if $(5) {
+ ObjectHdrs $(<) : $(5) ;
+ }
+}
+
+# Internal Cc
+# Cc_ object : sources ;
+rule Cc_
+{
+ # If the compiler's -o flag doesn't work, relocate the .o
+ if $(RELOCATE)
+ {
+ CcMv $(<) : $(>) ;
+ }
+
+ local pref_ccflags = $(P_PREF_CCFLAGS) ;
+ pref_ccflags ?= $(PREF_CCFLAGS) ;
+ # Make sure we incorporate any CCFLAGS[12] on object into total
+ CCFLAGS1 on $(<) += $(P_CCFLAGS) $(CCFLAGS) ;
+ CCFLAGS2 on $(<) += $(pref_ccflags) ;
+ CCFLAGS on $(<) = [ geton $(<) : CCFLAGS1 ] [ geton $(<) : CCFLAGS2 ] ;
+
+#Echo "Cc object '" $(<) "' got CCFLAGS1 '" [ geton $(<) : CCFLAGS1 ] "' and CCFLAGS2 '" [ geton $(<) : CCFLAGS2 ] "' for total CCFLAGS '" [ geton $(<) : CCFLAGS ] "'" ;
+
+ # Make sure the CCHDRS and CCDEFS are formatter correctly
+ CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
+ CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
+}
+
+# C++ object : source : flags : defines : hdrpaths ;
+rule C++
+{
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ Depends $(_t) : $(_s) ;
+ Depends obj : $(_t) ;
+ Clean clean : $(_t) ;
+ MakeLocate $(_t) ;
+
+ HDRS on $(_t) = [ geton $(_t) : SEARCH ] [ NormPaths $(HDRS) ] $(P_HDRS) ;
+ SOURCE on $(_t) = $(_s) ;
+
+ HDRRULE on $(_s) = HdrRule ;
+ HDRSCAN on $(_s) = $(HDRPATTERN) ;
+ # Construct HDRSEARCH so that we can know where to look for headers
+ local _dot = [ geton $(_>) : NOMLOC ] ;
+ if ! $(_dot) { _dot = $(DOT) ; }
+ HDRSEARCH1 on $(_s) = $(_dot) ;
+ HDRSEARCH2 on $(_s) = [ NormPaths $(HDRS) ] $(P_HDRS) ;
+ HDRSEARCH3 on $(_s) = [ NormPaths $(STDHDRS) ] ;
+ HDRSEARCH on $(_s) = [ geton $(_s) : HDRSEARCH1 ] [ geton $(_s) : HDRSEARCH2 ]
+ [ geton $(_s) : HDRSEARCH3 ] ;
+
+ # propagate target specific-defines
+
+ DEFINES on $(_t) = $(P_DEFINES) $(DEFINES) ;
+
+ C++_ $(_t) : $(_s) ;
+
+ if $(3) {
+ ObjectC++Flags $(<) : $(3) ;
+ }
+ if $(4) {
+ ObjectDefines $(<) : $(4) ;
+ }
+ if $(5) {
+ ObjectHdrs $(<) : $(5) ;
+ }
+}
+
+# Internal C++
+# C++_ object : sources ;
+rule C++_
+{
+ # If the compiler's -o flag doesn't work, relocate the .o
+ if $(RELOCATE)
+ {
+ CcMv $(<) : $(>) ;
+ }
+
+ local pref_c++flags = $(P_PREF_C++FLAGS) ;
+ pref_c++flags ?= $(PREF_C++FLAGS) ;
+ # Make sure we incorporate any C++FLAGS[12] on object into total
+ C++FLAGS1 on $(<) += $(P_C++FLAGS) $(C++FLAGS) ;
+ C++FLAGS2 on $(<) += $(pref_c++flags) ;
+ C++FLAGS on $(<) = [ geton $(<) : C++FLAGS1 ] [ geton $(<) : C++FLAGS2 ] ;
+
+ # Make sure the CCHDRS and CCDEFS are formatter correctly
+ CCHDRS on $(<) = [ on $(<) FIncludes $(HDRS) ] ;
+ CCDEFS on $(<) = [ on $(<) FDefines $(DEFINES) ] ;
+}
+
+rule Chmod_
+{
+#Echo "Chmod_ on '" $(<) "' with MODE = '" [ geton $(<) : MODE ] "'" ;
+ if $(CHMOD) { Chmod1 $(<) ; }
+}
+
+# Public use Depends that does normalisation of its targets
+# (non-normalizing Depends is a built in)
+# NDepends dest : source ; make dependency
+rule NDepends {
+ local _t _s ;
+ local _p = ;
+
+#Echo "NDepends got '" $(<) "' and '" $(>) "'" ;
+
+ # Don't anchor psuedo targets
+ switch $(<)
+ {
+ case all : _p = true ;
+ case first : _p = true ;
+ case shell : _p = true ;
+ case files : _p = true ;
+ case lib : _p = true ;
+ case exe : _p = true ;
+ case obj : _p = true ;
+ case dirs : _p = true ;
+ case clean : _p = true ;
+ case install : _p = true ;
+ case uninstall : _p = true ;
+ }
+
+ # Normalize target names and set Grist LOCATE and SOURCE
+ if ! $(_p) {
+ _t = [ NormDstTargets $(<) ] ;
+ } else {
+ _t = $(<) ;
+ }
+ _s = [ NormSrcTargets $(>) ] ;
+
+#Echo "Passing Depends '" $(_t) "' and '" $(_s) "'" ;
+
+ Depends $(_t) : $(_s) ;
+}
+
+# Public use NoUpdate that does normalisation of its targets
+# (non-normalizing NoUpdate is a built in)
+# NNoUpdate dest ; Make sure created, but don't update
+rule NNoUpdate {
+ local _t ;
+ local _p = ;
+
+#Echo "NNoUpdate got '" $(<) "'" ;
+
+ # Don't anchor psuedo targets
+ switch $(<)
+ {
+ case all : _p = true ;
+ case first : _p = true ;
+ case shell : _p = true ;
+ case files : _p = true ;
+ case lib : _p = true ;
+ case exe : _p = true ;
+ case obj : _p = true ;
+ case dirs : _p = true ;
+ case clean : _p = true ;
+ case install : _p = true ;
+ case uninstall : _p = true ;
+ }
+
+ # Normalize target names and set Grist LOCATE and SOURCE
+ if ! $(_p) {
+ _t = [ NormDstTargets $(<) ] ;
+ } else {
+ _t = $(<) ;
+ }
+ _s = [ NormSrcTargets $(>) ] ;
+
+#Echo "Passing NoUpdate '" $(_t) "'" ;
+
+ NoUpdate $(_t) ;
+}
+
+# Public use Includes that does normalisation of its targets
+# (non-normalizing Includes is a built in)
+# NDepends dest : source ; make dependency
+rule NIncludes {
+ local _t _s ;
+ local _p = ;
+
+#Echo "NIncludes got '" $(<) "' and '" $(>) "'" ;
+
+ # Normalize target names and set Grist LOCATE and SOURCE
+ _t = [ NormDstTargets $(<) ] ;
+ _s = [ NormSrcTargets $(>) ] ;
+
+#Echo "Passing Includes '" $(_t) "' and '" $(_s) "'" ;
+
+ Includes $(_t) : $(_s) ;
+}
+
+# sets mode of file
+# Mod target : mode ;
+rule Mod
+{
+ local _t = [ NormIDstTargets $(<[1]) ] ;
+ MODE on $(_t) = $(>) ;
+ Chmod_ $(_t) ;
+}
+
+# copies source onto target.
+# SRCDIR and DSTDIR will be ignored.
+# File target : source ;
+rule File
+{
+ local _t = [ NormIDstTargets $(<[1]) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ Depends files : $(_t) ;
+ Depends $(_t) : $(_s) ;
+ Clean clean : $(_t) ;
+ MakeLocate $(_t) ;
+ File_ $(_t) : $(_s) ;
+ MODE on $(_t) = $(FILEMODE) ;
+ Chmod_ $(_t) ;
+}
+
+# copies source onto target, but doesn't clean source.
+# SRCDIR and DSTDIR will be ignored.
+# File target : source ;
+rule FileNoClean
+{
+ local _t = [ NormIDstTargets $(<[1]) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ Depends files : $(_t) ;
+ Depends $(_t) : $(_s) ;
+ MakeLocate $(_t) ;
+ File_ $(_t) : $(_s) ;
+ MODE on $(_t) = $(FILEMODE) ;
+ Chmod_ $(_t) ;
+}
+
+# Fake file copy. Creates a dependence to work around
+# problem that Jam doesn't understand two products from one action.
+# FakeFile target : source ;
+rule FakeFile
+{
+ local _t = [ NormIDstTargets $(<[1]) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ FakeFile_ $(_t) : $(_s) ;
+}
+
+rule FakeFile_
+{
+ local _t = $(<) ;
+ local _s = $(>) ;
+
+ Depends files : $(_t) ;
+ Depends $(_t) : $(_s) ;
+ Clean clean : $(_t) ;
+ MakeLocate $(_t) ;
+}
+
+
+# Compile Fortran source file into object
+# Fortran object : source ;
+rule Fortran
+{
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ Depends $(_t) : $(_s) ;
+ Depends obj : $(_t) ;
+ Clean clean : $(_t) ;
+ MakeLocate $(_t) ;
+
+ Fortran_ $(_t) : $(_s) ;
+}
+
+# Internal Fortran
+rule Fortran_
+{
+}
+
+
+# NOTE! Perhaps GenFileND and GenFileNND could be replaced by a GenFile
+# with a $(3) for the dependecies ?
+
+# All > are assumed to be files that < is dependent on
+# with >[1] being an executable
+# SRCDIR and DSTDIR are ignored.
+rule GenFile
+{
+#Echo "GenFile got '" $(<) "' and '" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormIDstTargets $(<) ] ;
+ local _s = [ NormISrcTargets $(>[1]:S=$(SUFEXE)) ] ;
+ local _a = [ NormISrcTargets $(>[2-]) ] ;
+
+#Echo "GenFile normed '" $(_t) "' and '" $(_s) "' plus '" $(_a) "'" ;
+
+ Depends $(_t) : $(_s) $(_a) ;
+ if ! $(_s[1]:G) { # In case PATH doesn't have . in it.
+ _s = $(DOT)$(SLASH)$(_s[1]:G=) $(_s[2-]) ;
+ NotTargets $(_s) ;
+ NoCare $(_s) ;
+ NotFile $(_s) ;
+ }
+ GenFile1 $(_t) : $(_s) $(_a) ;
+ Clean clean : $(_t) ;
+}
+
+rule GenFile1
+{
+ MakeLocate $(<) ;
+}
+
+# Only >[1] is assumed to be an executable that < is dependent on.
+# $(3) are optional extra dependecies
+# SRCDIR and DSTDIR are ignored.
+rule GenFileND
+{
+#Echo "GenFileND got '$(<)' and '$(>)' and src targets '$(_d)'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormIDstTargets $(<[1]) ] ;
+ local _s = [ NormISrcTargets $(>[1]:S=$(SUFEXE)) ] ;
+ local _a = $(>[2-]) ;
+ _a = $(_a:J=" ") ;
+ local _d = [ NormSrcTargets $(3) ] ;
+
+#Echo "GenFileND normed '$(_t)' and '$(_s)' plus '$(_a)' and src targets '$(_d)'" ;
+
+ NotTargets $(_a) ;
+ NoCare $(_a) ;
+ NotFile $(_a) ; # Supresses "independent target", but may mark a directory wrongly
+ Depends $(_t) : $(_s) $(_d) ;
+#Echo "GenFileND set Depends '$(_t)' and '$(_s)' and '$(_d)'" ;
+
+ if ! $(_s[1]:G) { # In case PATH doesn't have . in it.
+ _s = $(DOT)$(SLASH)$(_s[1]) $(_s[2-]) ;
+ NotTargets $(_s) ;
+ NoCare $(_s) ;
+ NotFile $(_s) ;
+ }
+ GenFileND1 $(_t) : $(_s) $(_a) ;
+
+ Clean clean : $(_t) ;
+}
+
+rule GenFileND1
+{
+ MakeLocate $(<) ;
+}
+
+# GenFileNND target : program args : extra_dependecies ;
+# None of > is assumed to be a file.
+# $(3) are optional extra dependecies
+# SRCDIR and DSTDIR are ignored.
+rule GenFileNND
+{
+#Echo "GenFileNND got '$(<)' and '$(>)' and src targets '$(3)' " ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormIDstTargets $(<) ] ;
+ local _a = $(>) ;
+ _a = $(_a:J=" ") ; # Split up by space delimeter ?
+ local _d = [ NormSrcTargets $(3) ] ;
+
+#Echo "GenFileNND normed '$(_t)' plus '$(_a)' and src targets '$(_d)'" ;
+
+ Depends files : $(_t) ;
+ Depends $(_t) : $(_d) ;
+
+ NotTargets $(_a) ;
+ NoCare $(_a) ;
+ NotFile $(_a) ; # Supresses "independent target", but may mark a directory wrongly
+
+ GenFileNND1 $(_t) : $(_a) ;
+ Clean clean : $(_t) ;
+}
+
+rule GenFileNND1
+{
+#Echo "GenFileNND1 got "' $(<) "' and "' $(>) "'" ;
+ MakeLocate $(<) ;
+}
+
+# Concatenate all the argument to the file
+# Each argument to a separate line
+# If no arguments, create empty file
+# SRCDIR and DSTDIR are ignored.
+rule CatToFile
+{
+#Echo "CatToFile got '" $(<) "' and '" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormIDstTargets $(<) ] ;
+
+ MakeLocate $(_t) ;
+ Depends files : $(_t) ;
+ NotFile $(2) $(3) $(4) $(5) $(6) $(7) $(8) $(9) ;
+
+ Clean clean : $(_t) ;
+
+ if ! $(>) {
+ CreateCatFile_ $(_t) ;
+
+ } else {
+ if $(2) {
+ CatToFile_ $(_t) : $(2) ;
+ }
+ if $(3) {
+ CatToFile_ $(_t) : $(3) ;
+ }
+ if $(4) {
+ CatToFile_ $(_t) : $(4) ;
+ }
+ if $(5) {
+ CatToFile_ $(_t) : $(5) ;
+ }
+ if $(6) {
+ CatToFile_ $(_t) : $(6) ;
+ }
+ if $(7) {
+ CatToFile_ $(_t) : $(7) ;
+ }
+ if $(8) {
+ CatToFile_ $(_t) : $(8) ;
+ }
+ if $(9) {
+ CatToFile_ $(_t) : $(9) ;
+ }
+ }
+}
+
+rule HardLink
+{
+ local _t = [ NormDstTargets $(<) ] ;
+ local _s = [ NormSrcTargets $(>) ] ;
+
+ Depends files : $(_t) ;
+ Depends $(_t) : $(_s) ;
+
+ HardLink_ $(_t) : $(_s) ;
+}
+
+# Mark executable as GUI applications (ie. OS X Bundle)
+# GuiImages images ;
+rule GuiBin
+{
+ local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
+ GUIAPP on $(_t) = "true" ;
+}
+
+rule GUIAPP
+{
+}
+
+# /HdrMacroFile
+#
+# this rule is specific to FT-Jam. It is used to indicate that a given file
+# contains definitions for filename macros (e.g. "#define MYFILE_H <myfile>.h")
+# that can later be used in #include statements in the rest of the source
+#
+# these files must be parsed before any make is tried.
+#
+rule HdrMacroFile
+{
+ HDRMACRO $(<) ;
+}
+
+# Handle #includes that are found.
+# Try and locate them to asociate them with declared targets, as
+# well as tracing any further #includes they may have.
+# HdrRule NormedSource : headers ;
+rule HdrRule
+{
+ # N.B. This rule is called during binding, potentially after
+ # the fate of many targets has been determined, and must be
+ # used with caution: don't add dependencies to unrelated
+ # targets, and don't set variables on $(<).
+
+#Echo "HdrRule got '" $(<) "' and '" $(>) "'" ;
+
+ local _d = [ geton $(<) : NOMLOC ] ; # Directory location of source file
+ local _schpath = [ geton $(<) : HDRSEARCH ] ; # Search path used to find these
+ local _s _ts ; # include source targets, sources to trace
+
+#Echo "HDRSEARCH on '" $(<) "' is = '" $(_schpath) "'" ;
+
+ # See if we can locate the header amongst the generated files.
+#Echo "Checking for matches of known targets" ;
+ local _i _j _k _ss _sp _n ;
+ local _stdhdrs = [ NormPaths $(STDHDRS) ] ;
+ _st = ;
+ for _j in $(>) {
+ _sp = ; # Search path
+ _ss = ; # Resolved source target
+#Echo "Checking include '" $(_j) "'" ;
+ for _k in $(_schpath) "__unknown__" { # search path and plain
+ _n = [ NormPaths $(_j) : $(_k) ] ; # Normalized path for that search path
+ _i = [ _TargetIDs $(_n) ] ; # Target ID/name if it exitsts
+#Echo "Checking target ID '" $(_i)-target "' value '" $($(_i)-target) "'" ;
+ if $($(_i)-target) { # Target exists
+ _ss = $(_i) ;
+ _s += $(_ss) ;
+#Echo "Found existing target '" $(_ss) "'" ;
+ break ;
+ } else if ! $($(_i)-target) { # unknown state
+#Echo "Unknown statis target '" $(_i) "'" ;
+ _sp += [ NormPaths $(_j:D) : $(_k) ] ; # paths to search
+ }
+ }
+ if ! $(_ss) && $(_sp) { # We've not seen that target
+ local _found = ;
+#Echo "Searching for '" $(_j) "' in paths '" $(_sp) "'" ;
+ # See if we can find the header
+ _found = [ GLOB $(_sp) : $(_j:BS) ] ;
+
+ # Hmm. This sort of works around Windows problem of std include files being upper case.
+ # It won't solve the problem of tracing them if TRACESTDHDRS is true though.
+ if $(NT) && ! $(_found) {
+ _found = [ GLOB $(_sp) : $(_j:UBS) ] ;
+ _found = $(_found:D)\\$(_found:LBS) ;
+ }
+ if $(_found) {
+ _ss = [ NormSrcTargets $(_found[1]) ] ; # Add it to our list
+#Echo "Using new found target '" $(_ss) "'" ;
+ _s += $(_ss) ;
+ }
+ # Mark off not found targets
+ for _k in $(_schpath) {
+ _n = [ NormPaths $(_j) : $(_k) ] ; # Normalized path for that search path
+ _i = [ _TargetIDs $(_n) ] ; # Target ID/name if it exitsts
+ if $(_i) = $(_ss) {
+ break ; # The one we found
+ }
+#Echo "marking off '" $(_i) "' as non-existant" ;
+ $(_i)-target = "false" ; # That combination doesn't exist
+ }
+ if ! $(_found) {
+ _k = "__unknown__" ;
+ _ss = [ NormSrcTargets $(_j) : $(_k) ] ;
+ # ~~99 This would make good warning information ?
+#Echo "Include unresolved: '" $(_ss) "'" ;
+ _s += $(_ss) ; # Use plain header name as target ID
+ }
+ }
+ # We're left with $(_ss_) being the target and $(_k) being the search path
+
+ # Add this to our list that will also be scanned for #includes
+#Echo "Dealt with'" $(_j) "', _ss = '" $(_ss) "' and _k = '" $(_k) "'" ;
+ if ( ! $(_k) in "__unknown__" )
+ && ( $(TRACESTDHDRS) = true || ! $(_k) in $(_stdhdrs) ) {
+ _st += $(_ss) ;
+ }
+ }
+
+#Echo "Normalized includes = '" $(_s) "'" ;
+#Echo "Includes to be traced = '" $(_st) "'" ;
+
+ # Propagate on $(<) to $(>)
+ # Compute header search path for any #includes in these #includes
+
+ if $(_st) {
+ HDRSEARCH2 on $(_st) = [ geton $(<) : HDRSEARCH2 ] ;
+ HDRSEARCH3 on $(_st) = [ geton $(<) : HDRSEARCH3 ] ;
+ for _i in $(_st) {
+ # Replace file dot/HDRSEARCH1 with one for this file
+ local _dot = [ geton $(_i) : NOMLOC ] ;
+ if ! $(_dot) { _dot = $(DOT) ; }
+ HDRSEARCH1 on $(_i) = $(_dot) ;
+ HDRSEARCH on $(_i) = [ geton $(_i) : HDRSEARCH1 ] [ geton $(_i) : HDRSEARCH2 ]
+ [ geton $(_i) : HDRSEARCH3 ] ;
+ }
+ HDRSCAN on $(_st) = [ geton $(<) : HDRSCAN ] ;
+ HDRRULE on $(_st) = [ geton $(<) : HDRRULE ] ;
+ HDRGRIST on $(_st) = [ geton $(<) : HDRGRIST ] ;
+#Echo "HdrRule SEARCH on '" $(_st) "' set to '" [ geton $(_st) : SEARCH ] "'" ;
+#Echo "HdrRule HDRSEARCH on '" $(_st) "' set to '" [ geton $(_st) : HDRSEARCH ] "'" ;
+#Echo "HdrRule HDRSCAN on '" $(_st) "' set to '" [ geton $(_st) : HDRSCAN ] "'" ;
+#Echo "HdrRule HDRRULE on '" $(_st) "' set to '" [ geton $(_st) : HDRRULE ] "'" ;
+ }
+
+ # Tell Jam that anything depending on $(<) also depends on $(>),
+ # set SEARCH so Jam can find the headers, but then say we don't
+ # care if we can't actually find the headers (they may have been
+ # within ifdefs),
+
+ NoCare $(_s) ;
+ SEARCH on $(_s) = $(_schpath) ; # Use search path used to find these #includes as Jam SEARCH path.
+ Includes $(<) : $(_s) ;
+}
+
+# Public InstallInto
+# InstallInto dir : sources ; install any files
+rule InstallInto
+{
+#Echo "InstallInto got '" $(<) "' and '" $(>) "'" ;
+ local _d = [ NormPaths $(<) ] ; # Directory
+ local _s = [ NormSrcTargets $(>) ] ; # Sources
+ local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
+ _InstallInto $(_t) : $(_s) ;
+}
+
+# Private InstallInto
+# Note that the install rules ignore SRDDIR and DSTDIR.
+# InstallInto destinations : sources ; install any files
+rule _InstallInto
+{
+#Echo "_InstallInto got '" $(<) "' and '" $(>) "'" ;
+
+ local _t = $(<) ; # targets
+ local _s = $(>) ; # sources
+ local _is _it ; # individual source and target
+
+ # Arrange for jam install
+ # Arrange for jam uninstall
+ # targets are in dir
+
+ Depends install : $(_t) ;
+ Clean uninstall : $(_t) ;
+ MakeLocate $(_t) ; # create directories
+
+ # For each source, Install, Chmod, Chown, and Chgrp
+
+ for _is in $(_s)
+ {
+ _it = $(_t[1]) ;
+ _t = $(_t[2-]) ; # Track _is
+
+#Echo "_InstallInto installing target '" $(_it) "' from src '" $(_is) "'" ;
+ Depends $(_it) : $(_is) ;
+ Install $(_it) : $(_is) ;
+ Chmod_ $(_it) ;
+
+ if $(OWNER) && $(CHOWN)
+ {
+ Chown_ $(_it) ;
+ OWNER on $(_it) = $(OWNER) ;
+ }
+
+ if $(GROUP) && $(CHGRP)
+ {
+ Chgrp_ $(_it) ;
+ GROUP on $(_it) = $(GROUP) ;
+ }
+ }
+}
+
+# InstallBin dir : sources ; install binaries
+rule InstallBin
+{
+#Echo "InstallBin got '" $(<) "' and '" $(>) "'" ;
+ local _d = [ NormPaths $(<) ] ; # Directory
+ local _s = [ NormSrcTargets $(>:S=$(SUFEXE)) ] ; # Sources
+ local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
+#Echo "InstallBin norm '" $(_d) "' and '" $(_s) "' and '" $(_t) "'" ;
+ MODE on $(_t) = $(EXEMODE) ;
+ _InstallInto $(_t) : $(_s) ;
+#Echo "InstallBin done " ;
+}
+
+# InstallFile dir : sources ; install files
+rule InstallFile
+{
+#Echo "InstallFile got '" $(<) "' and '" $(>) "'" ;
+ local _d = [ NormPaths $(<) ] ; # Directory
+ local _s = [ NormSrcTargets $(>) ] ; # Sources
+ local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
+#Echo "InstallFile normed targ '" $(_t) "' src '" $(_s) "' and dir '" $(_d) "'" ;
+ MODE on $(_t) = $(FILEMODE) ;
+ _InstallInto $(_t) : $(_s) ;
+}
+
+# InstallLib dir : sources ; install static library files
+rule InstallLib
+{
+#Echo "InstallLib got '" $(<) "' and '" $(>) "'" ;
+ local _d = [ NormPaths $(<) ] ; # Directory
+ local _s = [ NormSrcTargets $(>:S=$(SUFLIB)) ] ; # Sources
+ local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
+ MODE on $(_t) = $(FILEMODE) ;
+ _InstallInto $(_t) : $(_s) ;
+}
+
+# InstallShLib dir : sources ; install shared library files
+rule InstallShLib
+{
+#Echo "InstallShLib got '" $(<) "' and '" $(>) "'" ;
+ local _d = [ NormPaths $(<) ] ; # Directory
+ local _s = [ NormSrcTargets $(>:S=$(SUFSHLIB)) ] ; # Sources
+ local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
+ MODE on $(_t) = $(FILEMODE) ;
+ _InstallInto $(_t) : $(_s) ;
+}
+
+# InstallShell dir : sources ; install files
+rule InstallShell
+{
+#Echo "InstallShell got '" $(<) "' and '" $(>) "'" ;
+ local _d = [ NormPaths $(<) ] ; # Directory
+ local _s = [ NormSrcTargets $(>) ] ; # Sources
+ local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
+ MODE on $(_t) = $(SHELLMODE) ;
+ _InstallInto $(_t) : $(_s) ;
+}
+
+# InstallMan dir : sources ; install files
+rule InstallMan
+{
+#Echo "InstallMan got '" $(<) "' and '" $(>) "'" ;
+ local _d = [ NormPaths $(<) ] ; # Directory
+ local _s = [ NormSrcTargets $(>) ] ; # Sources
+ local _t = [ CreateIDstTargets $(_s) : $(_d) ] ; # Relocate targs to dir
+
+ # Really this just strips the . from the suffix
+
+ local _is _it _tt _s _id ;
+
+ _tt = $(_t) ;
+ for _is in $(_s)
+ {
+ _it = $(_tt[1]) ;
+ _tt = $(_tt[2-]) ;
+
+ switch $(_is:S)
+ {
+ case .1 : s = 1 ; case .2 : s = 2 ; case .3 : s = 3 ;
+ case .4 : s = 4 ; case .5 : s = 5 ; case .6 : s = 6 ;
+ case .7 : s = 7 ; case .8 : s = 8 ; case .l : s = l ;
+ case .n : s = n ; case .man : s = 1 ;
+ }
+
+ _id = [ RootPaths $(_d) : man$(_s) ] ;
+ CreateIDstTargets $(_it) : $(_id) ;
+ MODE on $(_it) = $(FILEMODE) ;
+ _InstallInto $(_it) : $(_is) ;
+ }
+}
+
+# Lex
+# Lex source.c : source.l ;
+rule Lex
+{
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<[1]) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ Depends $(_t) : $(_s) ;
+ Clean clean : $(_t) ;
+ MakeLocate $(_t) ;
+
+ Lex_ $(_t) : $(_s) ;
+}
+
+# Internal Lex
+rule Lex_
+{
+ LexMv_ $(<) : $(>) ;
+}
+
+# Library - create a static library from sources.
+# Library library : sources : flags : defines : hdrpaths : objects ;
+rule Library
+{
+ LibraryFromObjects $(<) : $(>) $(6) ;
+ Objects $(>) : $(3) : $(4) : $(5) ;
+}
+
+# LibraryFromObjects - create a static library from object files.
+# LibraryFromObjects library : objects ;
+rule LibraryFromObjects
+{
+ local _i ;
+
+#Echo "LibraryFromObjects got " $(<) "and" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _l = [ NormDstTargets $(<[1]:S=$(SUFLIB)) ] ;
+ local _s = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
+#Echo "LibraryFromObjects nomed = " $(_l) "and" $(_s) ;
+
+ Depends lib : $(_l) ;
+
+ MakeLocate $(_l) ;
+
+ if $(NOARSCAN)
+ {
+ # If we can't scan the library to timestamp its contents,
+ # we have to just make the library depend directly on the
+ # on-disk object files.
+
+ Depends $(_l) : $(_s) ;
+ }
+ else
+ {
+ # If we can scan the library, we make the library depend
+ # on its members and each member depend on the on-disk
+ # object file.
+
+ for _i in $(_s)
+ {
+ local _m ;
+ _m = $(_l:M=$(_i:BS)) ;
+ CopyTarget $(_m) : $(_l) ; # Transfer LOCATE, SEARCH, NOMLOC
+ Depends $(_l) : $(_m) ;
+ Depends $(_m) : $(_i) ;
+ }
+ }
+
+ Clean clean : $(_l) ;
+
+ if $(CRELIB) {
+ CreLib $(_l) : $(_s[1]) ;
+ }
+
+ Archive $(_l) : $(_s) ;
+
+ if $(RANLIB) {
+ Ranlib $(_l) ;
+ }
+
+ # If we can't scan the library, we have to leave the .o's around.
+ if ! ( $(NOARSCAN) || $(NOARUPDATE) ) {
+ local _ds ;
+ for _i in $(_s) {
+ # Don't delete any objects that we've marked with KEEPOBJS
+ if ! [ geton $(_i) : KEEPOBJS ] {
+ _ds += $(_i) ;
+ }
+ }
+ if $(_ds) {
+ RmTemps_ $(_l) : $(_ds) ;
+ }
+ }
+}
+
+# LibraryFromLibraries - create a static library from object files and static libraries.
+# LibraryFromLibraries library : libraries ;
+rule LibraryFromLibraries
+{
+ local _i ;
+
+#Echo "LibraryFromLibraries got " $(<) "and" $(>) ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _l = [ NormDstTargets $(<[1]:S=$(SUFLIB)) ] ;
+ local _s = [ NormSrcTargets $(>:S=$(SUFLIB)) ] ;
+#Echo "LibraryFromObjects nomed = " $(_l) "and" $(_s) ;
+
+ Depends lib : $(_l) ;
+ Depends $(_l) : $(_s) ;
+
+ MakeLocate $(_l) ;
+
+ Clean clean : $(_l) ;
+
+ if $(CRELIB) {
+ CreLib $(_l) : $(_s[1]) ;
+ }
+
+ ArchiveArchive $(_l) : $(_s) ;
+}
+
+# ShLibrary - create a shared library from sources.
+# ShLibrary library : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
+rule ShLibrary
+{
+ ShLibraryFromObjects $(<) : $(>) $(6) : $(7) : $(8) ;
+ Objects $(>) : $(CCSHOBJFLAG) $(3) : $(4) : $(5) ;
+}
+
+# ShLibraryFromObjects - create a shared library from object files.
+# Both the import (if used on the system) and shared library will be created.
+# ShLibraryFromObjects shlib : objects : libs : shlibs ;
+rule ShLibraryFromObjects
+{
+ local _i _l ;
+
+#Echo "ShLibraryFromObjects got " $(<) "and" $(>) ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _sl = [ NormDstTargets $(<[1]:S=$(SUFSHLIB)) ] ;
+ if $(NT) {
+ _l = [ NormDstTargets $(<[1]:S=$(SUFIMPLIB)) ] ;
+ }
+ local _s = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
+#Echo "ShLibraryFromObjects nomed =" $(_sl) "and" $(_l) "and" $(_s) ;
+
+ Depends lib : $(_sl) ;
+# Depends lib : $(_l) ;
+ MakeLocate $(_sl) ;
+
+ Depends $(_sl) : $(_s) ;
+ Clean clean : $(_sl) $(_l) ;
+
+ if $(_l) {
+ Depends $(_l) : $(_s) ;
+ Clean clean : $(_l:S=.exp) ;
+ }
+
+#Echo "ShLibraryFromObjects SHLINKFLAGS = '" $(SHLINKFLAGS) "' and P_SHLINKFLAGS ='" $(P_LSHINKFLAGS) "'" ;
+
+ if $(SHLINKFLAGS) || $(P_SHLINKFLAGS)
+ || $(PREF_SHLINKFLAGS) || $(P_PREF_SHLINKFLAGS) {
+ local pref_shlinkflags = $(P_PREF_SHLINKFLAGS) ;
+ pref_shlinkflags ?= $(PREF_SHLINKFLAGS) ;
+ SHLINKFLAGS on $(_sl) += $(P_SHLINKFLAGS) $(SHLINKFLAGS) $(pref_shlinkflags) ;
+ }
+
+#Echo "ShLibraryFromObjects SHLINKOBJS = '" $(SHLINKOBJS) "' and P_SHLINKOBJS ='" $(P_SHLINKOBJS) "'" ;
+ if $(SHLINKOBJS) || $(P_SHLINKOBJS) {
+ local _o = [ NormSrcTargets $(SHLINKOBJS:S=$(SUFOBJ)) ] $(P_SHLINKOBJS:S=$(SUFOBJ)) ;
+ Depends $(_t) : $(_o) ;
+ SHLINKOBJS on $(_t) += $(_o) ;
+ }
+
+#Echo "ShLibraryFromObjects SHLINKLIBS = '" $(SHLINKLIBS) "' and P_SHLINKLIBS ='" $(P_SHLINKLIBS) "'" ;
+ if $(SHLINKLIBS) || $(P_SHLINKLIBS) {
+ local _l = [ NormSrcTargets $(SHLINKLIBS:S=$(SUFLIB)) ] $(P_SHLINKLIBS:S=$(SUFLIB)) ;
+ Depends $(_t) : $(_l) ;
+ SHLINKLIBS on $(_t) += $(_l) ;
+ }
+
+#Echo "ShLibraryFromObjects SHLINKSHLIBS = '" $(SHLINKSHLIBS) "' and P_SHLINKSHLIBS ='" $(P_SHLINKSHLIBS) "'" ;
+ if $(SHLINKSHLIBS) || $(P_SHLINKSHLIBS) {
+ local _l = [ NormSrcTargets $(SHLINKSHLIBS:S=$(SUFSHLIB)) ] $(P_SHLINKSHLIBS:S=$(SUFSHLIB)) ;
+ Depends $(_t) : $(_l) ;
+ SHLINKSHLIBS on $(_t) += $(_l) ;
+ }
+
+ if $(SHLINKDEFFILE) { # Windows special option
+ SHLINKDEFFILE on $(_sl) $(_l) = [ NormSrcTargets $(SHLINKDEFFILE) ] ;
+ Depends $(_sl) : [ geton $(_sl) : SHLINKDEFFILE ] ;
+ FakeFile_ $(_l) : $(_sl) ; # .lib is created with .dll
+ ShLinkDef_ $(_sl) $(_l) : $(_s) ;
+ } else {
+ if (SHLINKSEARCHEXEPATH) { # UNIX special option
+
+ if $(OS) = MACOSX { # OS X version of ld
+ SHLINKSEARCHEXEPATH = @executable_path/ ;
+ } else {
+# SHLINKSEARCHEXEPATH = \\$PATH/ ;
+ SHLINKSEARCHEXEPATH = \\$ORIGIN/ ;
+ }
+ }
+ ShLink_ $(_sl) $(_l) : $(_s) ;
+ }
+
+ # Try and make sure the objects are build with the correct flag
+ ObjectCcFlags $(>) : $(CCSHOBJFLAG) ;
+ ObjectC++Flags $(>) : $(CCSHOBJFLAG) ;
+
+ if $(3) {
+ ShLibraryLibraries $(<) : $(3) ;
+ }
+ if $(4) {
+ ShLibraryShLibraries $(<) : $(4) ;
+ }
+}
+
+# Internal link
+rule Link_
+{
+ MODE on $(<) = $(EXEMODE) ;
+ Chmod_ $(<) ;
+}
+
+# Make the shared library link with the given objects.
+# This is just a way of adding common object files to many shlibs.
+# ShLibraryObjects shlib : objects ;
+rule ShLibraryObjects
+{
+#Echo "ShLibraryObjects got '" $(<) "' and '" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<:S=$(SUFSHLIB)) ] ;
+ local _o = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
+
+ Depends $(_t) : $(_o) ;
+
+ SHLINKOBJS on $(_t) += $(_o) ;
+}
+
+# Make the executables link with the given static libraries.
+# ShLibraryLibraries shlib : libraries ;
+rule ShLibraryLibraries
+{
+#Echo "ShLibraryLibraries got '" $(<) "' and '" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<:S=$(SUFSHLIB)) ] ;
+ local _l = [ NormSrcTargets $(>:S=$(SUFLIB)) ] ;
+
+ Depends $(_t) : $(_l) ;
+
+ SHLINKLIBS on $(_t) += $(_l) ;
+}
+
+# Make the executables link with the given shared libraries.
+# ShLibraryShLibraries shlib : shlibraries ;
+rule ShLibraryShLibraries
+{
+#Echo "ShLibraryShLibraries got '" $(<) "' and '" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<:S=$(SUFSHLIB)) ] ;
+ local _l = [ NormSrcTargets $(>:S=$(SUFSHIMPLIB)) ] ;
+
+ Depends $(_t) : $(_l) ;
+
+ SHLINKSHLIBS on $(_t) += $(_l) ;
+}
+
+# Add extra LINKFLAGS to mains
+# MainLinkFlags mains : flags ;
+rule MainLinkFlags
+{
+#Echo "MainLinkFlags got '" $(<) "' and '" $(>) "'" ;
+ local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
+ local _i ;
+
+ for _i in $(_t) {
+ LINKFLAGS on $(_i) += $(>) ;
+#Echo "exes '" $(_i) "' got LINKFLAGS '" [ geton $(_i) : LINKFLAGS ] "'" ;
+ }
+}
+
+# Make an executable from sources
+# Main image : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
+rule Main
+{
+ MainFromObjects $(<) : $(>) $(6) : $(7) : $(8) ;
+ Objects $(>) : $(3) : $(4) : $(5) ;
+}
+
+# Make a variant executable from sources
+# Objects are distiguished by appending "_image"
+# MainVariant image : sources : flags : defines : hdrpaths : objects : libs : shlibs ;
+rule MainVariant
+{
+ local _i _t _o ;
+
+#Echo "MainVariant got '" $(<) "' and '" $(>) "'" ;
+ for _i in $(>) {
+ _t = $(_i:DB)_$(<[1]) ;
+ Object $(_t) : $(_i) : $(3) : $(4) : $(5) ;
+#Echo "MainVariant object '" $(_t) "' and src '" $(_i) "'" ;
+ _o += $(_t) ;
+ }
+#Echo "MainVariant image '" $(<) "' and objs '" $(_o) "'" ;
+ MainFromObjects $(<) : $(_o) $(6) : $(7) : $(8) ;
+}
+
+# Make an executable from objects
+# MainFromObjects image : objects : libs : shlibs ;
+rule MainFromObjects
+{
+#Echo "MainFromObjects got" $(<) "and" $(>) ;
+
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<[1]:S=$(SUFEXE)) ] ;
+ local _s = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
+
+#Echo "MainFromObjects _t" $(_t) "and _s" $(_s) ;
+
+ # so 'jam foo' works when it's really foo.exe
+ if $(_t:S=) != $(_t)
+ {
+ Depends $(_t:S=) : $(_t) ;
+ NotFile $(_t:S=) ;
+ }
+
+ # make compiled sources a dependency of target
+
+ Depends exe : $(_t) ;
+ Depends $(_t) : $(_s) ;
+ Clean clean : $(_t) ;
+ MakeLocate $(_t) ;
+
+ if $(3) {
+ LinkLibraries $(<) : $(3) ;
+ }
+ if $(4) {
+ LinkShLibraries $(<) : $(4) ;
+ }
+
+#Echo "MainFromObjects LINKFLAGS = '" $(LINKFLAGS) "' and P_LINKFLAGS ='" $(P_LINKFLAGS) "'" ;
+#Echo " PREF_LINKFLAGS = '" $(PREF_LINKFLAGS) "' and P_PREF_LINKFLAGS ='" $(P_PREF_LINKFLAGS) "'" ;
+ if $(LINKFLAGS) || $(P_LINKFLAGS)
+ || $(PREF_LINKFLAGS) || $(P_PREF_LINKFLAGS) {
+ local pref_linkflags = $(P_PREF_LINKFLAGS) ;
+ pref_linkflags ?= $(PREF_LINKFLAGS) ;
+ LINKFLAGS on $(_t) += $(P_LINKFLAGS) $(LINKFLAGS) $(pref_linkflags) ;
+#Echo "LINKFLAGS on $(_t) = '" [ geton $(_t) : LINKFLAGS ] "'" ;
+ }
+
+#Echo "MainFromObjects LINKOBJS = '" $(LINKOBJS) "' and P_LINKOBJS ='" $(P_LINKOBJS) "'" ;
+ if $(LINKOBJS) || $(P_LINKOBJS) {
+ local _o = [ NormSrcTargets $(LINKOBJS:S=$(SUFOBJ)) ] $(P_LINKOBJS:S=$(SUFOBJ)) ;
+ Depends $(_t) : $(_o) ;
+ LINKOBJS on $(_t) += $(_o) ;
+ }
+
+#Echo "MainFromObjects LINKLIBS = '" $(LINKLIBS) "' and P_LINKLIBS ='" $(P_LINKLIBS) "'" ;
+ if $(LINKLIBS) || $(P_LINKLIBS) {
+ local _l = [ NormSrcTargets $(LINKLIBS:S=$(SUFLIB)) ] $(P_LINKLIBS:S=$(SUFLIB)) ;
+ Depends $(_t) : $(_l) ;
+ LINKLIBS on $(_t) += $(_l) ;
+ }
+
+#Echo "MainFromObjects LINKSHLIBS = '" $(LINKSHLIBS) "' and P_LINKSHLIBS ='" $(P_LINKSHLIBS) "'" ;
+ if $(LINKSHLIBS) || $(P_LINKSHLIBS) {
+ local _l = [ NormSrcTargets $(LINKSHLIBS:S=$(SUFIMPLIB)) ] $(P_LINKSHLIBS:S=$(SUFIMPLIB)) ;
+ Depends $(_t) : $(_l) ;
+ LINKSHLIBS on $(_t) += $(_l) ;
+ }
+
+ Link_ $(_t) : $(_s) ;
+
+ # Some OS's need to post process GUI apps to work (ie. OS X bundle)
+ if [ geton $(_t) : GUIAPP ] = "true" {
+ GUIAPP $(_t) ;
+ }
+#Echo "MainFromObjects done" ;
+}
+
+# A rule to make several mains from each of their single source files.
+# MainsFromSources executables ;
+rule MainsFromSources
+{
+ local _i ;
+ for _i in $(<) {
+ Main $(_i) : $(_i) ;
+ }
+}
+
+# Make the executables link with the given objects.
+# This is just a way of adding common object files to many mains.
+# LinkObjects image : objects ;
+rule LinkObjects
+{
+#Echo "LinkObjects got '" $(<) "' and '" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
+ local _o = [ NormSrcTargets $(>:S=$(SUFOBJ)) ] ;
+
+ Depends $(_t) : $(_o) ;
+
+ LINKOBJS on $(_t) += $(_o) ;
+}
+
+# Make the executables link with the given static libraries.
+# LinkLibraries image : libraries ;
+rule LinkLibraries
+{
+#Echo "LinkLibraries got '" $(<) "' and '" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
+ local _l = [ NormSrcTargets $(>:S=$(SUFLIB)) ] ;
+
+ Depends $(_t) : $(_l) ;
+
+ LINKLIBS on $(_t) += $(_l) ;
+}
+
+# Make the executables link with the given shared libraries.
+# LinkShLibraries image : shlibraries ;
+rule LinkShLibraries
+{
+#Echo "LinkShLibraries got '" $(<) "' and '" $(>) "'" ;
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<:S=$(SUFEXE)) ] ;
+ local _l = [ NormSrcTargets $(>:S=$(SUFSHIMPLIB)) ] ;
+
+ Depends $(_t) : $(_l) ;
+
+ LINKSHLIBS on $(_t) += $(_l) ;
+}
+
+# Ensure that each targets directories are created
+# Makelocate targets ;
+rule MakeLocate
+{
+#Echo "MakeLocate got '" $(<) "'" ;
+ local _i ;
+ # Uses special variable LOCATE of targets, and arranges
+ # with MkDir to create target directory.
+ # The directory itself becomes a target
+
+ for _i in $(<) {
+ local _t = [ geton $(_i) : LOCATE ] ;
+ if $(_t) {
+ MkDir_ $(_t) : $(_i) ;
+ }
+ }
+}
+
+# Make the directories and all their parent directories.
+# MkDir directories ;
+rule MkDir
+{
+#Echo "MkDir got '" $(<) "'" ;
+ # Ignore timestamps on directories: we only care if they exist.
+ local _t= [ NormPaths $(<) ] ;
+ local _i ;
+
+ for _i in $(_t) {
+ MkDir_ $(_i) ;
+ }
+}
+
+# Internal MkDir
+# MkDir dir [ : dependency ]
+rule MkDir_
+{
+#Echo "MkDir_ got '" $(<) "' : '" $(>) "'" ;
+
+ if ! $(<:BS) {
+ return ;
+ }
+
+ local _t ;
+ local _d = $(<:D) ; # Form target id from path + last directory
+ if ! $(_d) {
+ _d = $(DOT) ;
+ }
+ local _t = [ NormIDstTargets $(<:BS) : $(_d) ] ;
+
+#Echo "MkDir_ target = '" $(_t) "' dependant = '" $(>) "'" ;
+
+ if $(>) { # Thing that depends on this directory
+ Depends $(>) : $(_t) ;
+ }
+ NoUpdate $(_t) ;
+
+ # Don't create . or any directory already created.
+
+ if $(_t) != $(DOT) && ! $($(_t)-mkdir)
+ {
+ # Cheesy gate to prevent multiple invocations on same dir
+ # Arrange for jam dirs
+ # MkDir1 has the actions
+
+#Echo "Making '" $(_t) "'" ;
+ $(_t)-mkdir = true ;
+ Depends dirs : $(_t) ;
+ MkDir1 $(_t) ;
+
+ # Recursively make parent directories.
+ # $(_t:P) = $(_t)'s parent, & we recurse until root
+
+ local _s = $(<:P) ;
+#Echo "parent = '" $(_s) "'" ;
+
+ # Don't try to create A: or A:\ on windows
+
+ if $(NT)
+ {
+ switch $(_s)
+ {
+ case *: : _s = ;
+ case *:\\ : _s = ;
+ case *:/ : _s = ;
+ }
+ }
+
+#Echo "parent now = '" $(_s) "'" ;
+ if $(_s) = $(SLASH) # Hmm. Was $(_s) = $(<). How could that work ?
+ {
+#Echo "At root, ignore '" $(_s) "' = '" $(<) "'" ;
+ # The parent is the same as the dir.
+ # We're at the root, which some OS's can't stat, so we mark
+ # it as NotFile.
+
+ NotFile $(_s) ;
+ }
+ else if $(_s)
+ {
+ # There's a parent; recurse.
+
+#Echo "Doing Depends '" $(_t) "' with '" [ _TargetIDs $(_s) ] "'" ;
+ Depends $(_t) : [ _TargetIDs $(_s) ] ;
+#Echo "Recursing with parent '" $(_s) "'" ;
+ MkDir_ $(_s) ;
+ }
+ } else {
+#Echo "Not making '" $(_t) "' because it's dot, or it's been made before" ;
+ }
+}
+
+# Deal with a single source to object.
+# Object object : sources : flags : defines : hdrpaths
+rule Object
+{
+#Echo "Object got " $(<) "and" $(>) "' flags '" $(3) "' defs '" $(4) "' hds '" $(5) "'" ;
+
+ # Normalize target names and set Grist LOCATE and SOURCE
+ local _t = [ NormDstTargets $(<[1]:S=$(SUFOBJ)) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+ local _dot ;
+
+#Echo "Object norms " $(_t) "and" $(_s) ;
+
+ Depends $(_t) : $(_s) ;
+ Depends obj : $(_t) ;
+ Clean clean : $(_t) ;
+ MakeLocate $(_t) ;
+
+ # HDRS is used to provide the -I$(HDRS) options on compile.
+
+#Echo "Object sets HDRS on '" $(_t) "' to HDRS '" $(HDRS) "' and P_HDRS '" $(P_HDRS) "'" ;
+ HDRS on $(_t) = [ geton $(_t) : SEARCH ] [ NormPaths $(HDRS) ] $(P_HDRS) ;
+#Echo "HDRS on '" $(_t) "' is now '" [ geton $(_t) : HDRS ] "'" ;
+
+ # we need to mark what the associated source is so
+ # that if we want to change HDRS we can propogate
+ # it to the #include files.
+
+ SOURCE on $(_t) = $(_s) ; # ~~99 should check source is the same as any previous ?
+
+ # handle #includes for source: Jam scans for headers with
+ # the regexp pattern $(HDRSCAN) and then invokes $(HDRRULE)
+ # with the scanned file as the target and the found headers
+ # as the sources. HDRSEARCH is the value of SEARCH used for
+ # the found header files.
+
+ HDRRULE on $(_s) = HdrRule ;
+ HDRSCAN on $(_s) = $(HDRPATTERN) ;
+
+ # Construct HDRSEARCH so that we can latter add to HDRS
+ local _dot = [ geton $(_s) : NOMLOC ] ;
+ if ! $(_dot) { _dot = $(DOT) ; }
+ HDRSEARCH1 on $(_s) = $(_dot) ;
+ HDRSEARCH2 on $(_s) = [ NormPaths $(HDRS) ] $(P_HDRS) ;
+ HDRSEARCH3 on $(_s) = [ NormPaths $(STDHDRS) ] ;
+ HDRSEARCH on $(_s) = [ geton $(_s) : HDRSEARCH1 ] [ geton $(_s) : HDRSEARCH2 ]
+ [ geton $(_s) : HDRSEARCH3 ] ;
+#Echo "Object: HDRSEARCH on '" $(_s) "' set to '" [ geton $(_s) : HDRSEARCH ] "'" ;
+
+ # propagate target specific-defines
+
+ DEFINES on $(_t) = $(P_DEFINES) $(DEFINES) ;
+
+ # if source is not .c, generate .c with specific rule
+
+ switch $(_s:S)
+ {
+ case .asm : As_ $(_t) : $(_s) ;
+
+ case .c : Cc_ $(_t) : $(_s) ;
+
+ case .C : C++_ $(_t) : $(_s) ;
+ case .cc : C++_ $(_t) : $(_s) ;
+ case .cpp : C++_ $(_t) : $(_s) ;
+ case .cxx : C++_ $(_t) : $(_s) ;
+
+ case .m : Cc_ $(_t) : $(_s) ;
+
+ case .f : Fortran_ $(_t) : $(_s) ;
+
+ case .l : {
+ local _c = $(_t:S=.c) ;
+ CopyTarget $(_c) : $(_t) ; # Transfer LOCATE, SEARCH, NOMLOC
+ Lex_ $(_c) : $(_s) ;
+ Cc_ $(_t) : $(_c) ;
+ }
+
+ case .s : As_ $(_t) : $(_s) ;
+
+ case .y : {
+ local _c = $(_t:S=$(YACCGEN)) ;
+ CopyTarget $(_c) : $(_t) ; # Transfer LOCATE, SEARCH, NOMLOC
+ Yacc_ $(_c) : $(_s) ;
+ Cc_ $(_t) : $(_c) ;
+ }
+ # Note user object gets normalized target and source
+ case * : UserObject $(_t) : $(_s) : $(3) : $(4) : $(5) ;
+ }
+#Echo ;
+
+ if $(3) {
+ ObjectCcFlags $(<) : $(3) ;
+ switch $(_s:S)
+ {
+ case .c : ObjectCcFlags $(_t) : $(3) ;
+
+ case .C : ObjectC++Flags $(_t) : $(3) ;
+ case .cc : ObjectC++Flags $(_t) : $(3) ;
+ case .cpp : ObjectC++Flags $(_t) : $(3) ;
+ case .cxx : ObjectC++Flags $(_t) : $(3) ;
+
+ case .l : ObjectCcFlags $(_t) : $(3) ;
+ case .y : ObjectCcFlags $(_t) : $(3) ;
+ }
+ }
+ if $(4) {
+ ObjectDefines $(<) : $(4) ;
+ }
+ if $(5) {
+ ObjectHdrs $(<) : $(5) ;
+ }
+}
+
+# Add extra CCFLAGS to objects
+# ObjectCcFlags objects : flags ;
+rule ObjectCcFlags
+{
+#Echo "ObjectCcFLags got '" $(<) "' and '" $(>) "'" ;
+ local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
+ local _i ;
+
+ for _i in $(_t) {
+ CCFLAGS1 on $(_i) += $(>) ;
+ CCFLAGS on $(_i) = [ geton $(_i) : CCFLAGS1 ] [ geton $(_i) : CCFLAGS2 ] ;
+#Echo "object '" $(_i) "' got CCFLAGS1 '" [ geton $(_i) : CCFLAGS1 ] "' and CCFLAGS2 '" [ geton $(_i) : CCFLAGS2 ] "' for total CCFLAGS '" [ geton $(_i) : CCFLAGS ] "'" ;
+ }
+}
+
+# Add extra PREF_CCFLAGS to objects
+# ObjectPrefCcFlags objects : flags ;
+rule ObjectPrefCcFlags
+{
+#Echo "ObjectPrefCcFLags got '" $(<) "' and '" $(>) "'" ;
+ if ! $(P_PREF_CCFLAGS) {
+ local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
+ local _i ;
+
+ for _i in $(_t) {
+ CCFLAGS2 on $(_i) += $(>) ;
+ CCFLAGS on $(_i) = [ geton $(_i) : CCFLAGS1 ] [ geton $(_i) : CCFLAGS2 ] ;
+#Echo "object '" $(_i) "' got CCFLAGS1 '" [ geton $(_i) : CCFLAGS1 ] "' and CCFLAGS2 '" [ geton $(_i) : CCFLAGS2 ] "' for total CCFLAGS '" [ geton $(_i) : CCFLAGS ] "'" ;
+ }
+ }
+}
+
+# Add extra C++FLAGS to objects
+# ObjectC++Flags objects : flags ;
+rule ObjectC++Flags
+{
+#Echo "ObjectC++FLags got '" $(<) "' and '" $(>) "'" ;
+ local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
+ local _i ;
+
+ for _i in $(_t) {
+ C++FLAGS1 on $(_i) += $(>) ;
+ C++FLAGS on $(_i) = [ geton $(_i) : C++FLAGS1 ] [ geton $(_i) : C++FLAGS2 ] ;
+ }
+}
+
+# Add extra PREF_C++FLAGS to objects
+# ObjectPrefC++Flags objects : flags ;
+rule ObjectPrefC++Flags
+{
+#Echo "ObjectPrefC++FLags got '" $(<) "' and '" $(>) "'" ;
+ if ! $(P_PREF_C++FLAGS) {
+ local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
+ local _i ;
+
+ for _i in $(_t) {
+ C++FLAGS2 on $(_i) += $(>) ;
+ C++FLAGS on $(_i) = [ geton $(_i) : C++FLAGS1 ] [ geton $(_i) : C++FLAGS2 ] ;
+ }
+ }
+}
+
+# Add extra DEFINES to objects
+# ObjectDefines objects : defines ;
+rule ObjectDefines
+{
+ # must reformat CCDEFS according to current defines
+
+ local s = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
+
+ DEFINES on $(s) += $(>) ;
+ CCDEFS on $(s) = [ on $(s) FDefines $(DEFINES) ] ;
+}
+
+# Add extra header search paths to objects.
+# ObjectHdrs objects : dirs ;
+rule ObjectHdrs
+{
+#Echo "ObjectHdrs HDRS got '" $(<) "' and '" $(>) "'" ;
+ # Add to HDRS for CCHDRS benefit.
+ local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
+ local _h = [ NormSrcPaths $(>) ] ;
+ local _i _s ;
+
+#Echo "ObjectHdrs changed HDRS on '" $(_t) "' from '" [ geton $(_t) : HDRS ] "'" ;
+ HDRS on $(_t) += $(_h) ;
+#Echo " to '" [ geton $(_t) : HDRS ] "'" ;
+ for _i in $(_t) {
+ _s = [ geton $(_i) : SOURCE ] ;
+#Echo " obj '" $(_i) "' has source '" $(_s) "'" ;
+#Echo " ObjectHdrs changed HDRSEARCH on '" $(_s) "' from '" [ geton $(_s) : HDRSEARCH ] "'" ;
+ HDRSEARCH2 on $(_s) += $(_h) ;
+ HDRSEARCH on $(_s) = [ geton $(_s) : HDRSEARCH1 ] [ geton $(_s) : HDRSEARCH2 ]
+ [ geton $(_s) : HDRSEARCH3 ] ;
+#Echo " to '" [ geton $(_s) : HDRSEARCH ] "'" ;
+ CCHDRS on $(_i) = [ on $(_i) FIncludes $(HDRS) ] ;
+ }
+}
+
+# Set KEEPOBJS on the given headers
+# ObjectKeep objects ;
+rule ObjectKeep
+{
+#Echo "ObjectKeep got '" $(<) "" ;
+ local _t = [ NormDstTargets $(<:S=$(SUFOBJ)) ] ;
+
+ KEEPOBJS on $(_t) = "true" ;
+#Echo "ObjectHdrs changed KEEPOBJS on '" $(_t) "' to '" [ geton $(_t[1]) : KEEPOBJS ] "'" ;
+}
+
+# Create object files from sources.
+# Objects sources : flags : defines : hdrpaths ;
+rule Objects
+{
+#Echo "Objects got src '" $(<) "' flags '" $(2) "' def '" $(3) "' hdrs '" $(4) "'" ;
+ local _i ;
+
+ for _i in $(<) {
+ Object $(_i) : $(_i) : $(2) : $(3) : $(4) ;
+ }
+}
+
+# Marks sources as temporary with the TEMPORARY rule, and deletes sources once targets are built.
+# Must be the last rule invoked on targets.
+# RmTemps targets : sources ;
+rule RmTemps
+{
+ local _s = [ NormPaths $(>) ] ;
+ if $(_s) {
+ RmTemps_ $(<) : $(_s) ;
+ }
+}
+
+# internal RmTemps
+rule RmTemps_
+{
+ Temporary $(>) ;
+}
+
+# Setuid
+rule Setuid
+{
+ local _t = [ NormPaths $(>:S=$(SUFEXE)) ] ;
+ MODE on $(_t) = 4711 ;
+}
+
+# Shell
+rule Shell
+{
+ local _t = [ NormTargs $(>:S=$(SUFSH)) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+ Shell_ $(_t) : $(_s) ;
+}
+
+# internal Shell
+rule Shell_
+{
+ Depends shell : $(<) ;
+ Depends $(<) : $(>) ;
+ MODE on $(<) = $(SHELLMODE) ;
+ Clean clean : $(<) ;
+ Chmod_ $(<) ;
+}
+
+# SoftLink
+rule SoftLink
+{
+ local _t = [ NormDstTargets $(<) ] ;
+ local _s = [ NormSrcTargets $(>) ] ;
+
+ SoftLink_ $(_t) : $(_s) ;
+}
+
+# internal SoftLink
+rule SoftLink_
+{
+ Depends files : $(<) ;
+ Depends $(<) : $(>) ;
+ Clean clean : $(<) ;
+}
+
+#Adds flags to mark symbols as undefined on link command for images
+rule Undefines
+{
+ local _t = [ NormDstTargets $(<) ] ;
+ UNDEFS on [ $(_t:S=$(SUFEXE)) ] += $(UNDEFFLAG)$(>) ;
+}
+
+# User routine to handle objects. Note that
+# targets and sources are in normalized form.
+rule UserObject
+{
+ Exit "Unknown suffix on" $(>) "- see UserObject rule in Jamfile(5)." ;
+}
+
+# Yacc source.c : source.y ;
+rule Yacc
+{
+ local _t = [ NormDstTargets $(<[1]) ] ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ Yacc_ $(_t) : $(_s) ;
+}
+
+# internal Yacc
+rule Yacc_
+{
+ local _h ;
+
+ _h = $(<:S=.h) ;
+ CopyTarget $(_h) : $(<) ; # Transfer LOCATE, SEARCH, NOMLOC
+
+ # Some places don't have a yacc.
+
+ MakeLocate $(<) $(_h) ;
+
+ if $(YACC)
+ {
+ Depends $(<) : $(>) ;
+ FakeFile_ $(_h) : $(<) ; # .h is created with .c
+ Yacc1_ $(<) $(_h) : $(>) ;
+ YaccMv_ $(<) $(_h) ;
+ Clean clean : $(<) $(_h) ;
+ }
+
+ # make sure someone includes $(_h) else it will be
+ # a deadly independent target
+
+ Includes $(<) : $(_h) ;
+}
+
+# Aswig : source.i ;
+# Argyll C class generator. Creates C class declaration source.h,
+# C class partial implementation source_i.c, C++ class wrapper
+# declaration & implementation source.hpp.
+rule Aswig
+{
+#Echo "Aswig called with $(>) " ;
+ local _s = [ NormSrcTargets $(>[1]) ] ;
+
+ Aswig_ : $(_s) ;
+}
+
+# internal Aswig
+rule Aswig_
+{
+#Echo "Aswig_ called with $(>)" ;
+ local _i = $(>[1]) ;
+ local _h = $(_i:S=.h) ;
+ CopyTarget $(_h) : $(_i) ; # Transfer LOCATE, SEARCH, NOMLOC
+ local _c = $(_i:B=$(_i:B)_i:S=.c) ;
+ CopyTarget $(_c) : $(_i) ; # Transfer LOCATE, SEARCH, NOMLOC
+ local _hpp = $(_i:S=.hpp) ;
+ CopyTarget $(_hpp) : $(_i) ; # Transfer LOCATE, SEARCH, NOMLOC
+
+#Echo "Aswig_ creates $(_h) $(_c) $(_hpp) from $(_i) " ;
+
+ MakeLocate $(_h) $(_c) $(_hpp) ;
+
+ Depends $(_h) : $(_i) ;
+ FakeFile_ $(_c) : $(_h) ; # _i.c is created with .h
+ FakeFile_ $(_hpp) : $(_h) ; # _.hpp is created with .h
+ Aswig1_ $(_h) : $(_i) ;
+ Clean clean : $(_h) $(_c) $(_hpp) ;
+}
+
+#
+# Utility rules; no side effects on these
+#
+
+# FReverse a1 a2 a3 ... ;
+# return ... a3 a2 a1 ;
+rule FReverse
+{
+
+ local _i _o = ;
+ for _i in $(1)
+ {
+ _o = $(_i) $(_o) ;
+ }
+ return $(_o) ;
+}
+
+# Strip common initial elements of variables v1 and v2.
+# Modifies the variable values themselves.
+# FStripCommon v1 : v2 ;
+rule FStripCommon
+{
+
+ if $($(<)[1]) && $($(<)[1]) = $($(>)[1])
+ {
+ $(<) = $($(<)[2-]) ;
+ $(>) = $($(>)[2-]) ;
+ FStripCommon $(<) : $(>) ;
+ }
+}
+
+# Append suffix if there is not already one
+# E.g., "FAppendSuffix yacc lex foo.bat : $(SUFEXE) ;"
+# returns (yacc,lex,foo.bat) on Unix and
+# (yacc.exe,lex.exe,foo.bat) on NT.
+# FAppendSuffix files : suffix ;
+rule FAppendSuffix
+{
+
+ if $(>)
+ {
+ local _i _o ;
+
+ for _i in $(<)
+ {
+ if $(_i:S)
+ {
+ _o += $(_i) ;
+ }
+ else
+ {
+ _o += $(_i:S=$(>)) ;
+ }
+ }
+ return $(_o) ;
+ }
+ else
+ {
+ return $(<) ;
+ }
+}
+
+# return a1 a2 ... with any empty elements deleted
+# FDelEmpty a1 a2 ... ;
+rule FDelEmpty
+{
+
+ local _i _o = ;
+ for _i in $(<)
+ {
+ if $(_i) {
+ _o += $(_i) ;
+ }
+ }
+ return $(_o) ;
+}
+
+#
+# Operating system specific utility rules
+# First, the (generic) UNIX versions
+#
+
+rule FQuote { return \\\"$(<)\\\" ; }
+rule FDefines { local _t = [ FDelEmpty $(<) ] ; return -D$(_t) ; }
+rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return -I$(_t) ; }
+
+if $(OS2)
+{
+ rule FQuote { return \"$(<)\" ; }
+ rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return /I$(_t) ; }
+}
+
+else if $(NT)
+{
+ if ! $(MINGW) {
+ rule FDefines { local _t = [ FDelEmpty $(<) ] ; return /D$(_t) ; }
+ rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return /I$(_t) ; }
+ }
+}
+
+else if $(MAC)
+{
+ rule FQuote { return \"$(<)\" ; }
+ rule FDefines { local _t = [ FDelEmpty $(<) ] ; return "-define '$(_t)'" ; }
+ rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return \"$(_t:J=,)\" ; }
+}
+
+else if $(VMS)
+{
+ rule FQuote { return \"\"\"$(<)\"\"\" ; }
+ rule FDefines { local _t = [ FDelEmpty $(<) ] ; return "/define=( $(_t:J=,) )" ; }
+ rule FIncludes { local _t = [ FDelEmpty $(<) ] ; return "/inc=( $(_t:J=,) )" ; }
+
+ rule FDirName
+ {
+ local _s _i ;
+
+ # Turn individual elements in $(<) into a usable path.
+
+ if ! $(<)
+ {
+ _s = $(DOT) ;
+ }
+ else
+ {
+ # This handles the following cases:
+ # a -> [.a]
+ # a b c -> [.a.b.c]
+ # x: -> x:
+ # x: a -> x:[a]
+ # x:[a] b -> x:[a.b]
+
+ switch $(<[1])
+ {
+ case *:* : _s = $(<[1]) ;
+ case \\[*\\] : _s = $(<[1]) ;
+ case * : _s = [.$(<[1])] ;
+ }
+
+ for _i in [.$(<[2-])]
+ {
+ _s = $(_i:R=$(_s)) ;
+ }
+ }
+
+ return $(_s) ;
+ }
+}
+
+#
+# Actions
+#
+
+#
+# First the defaults
+#
+
+actions updated together piecemeal Archive
+{
+ $(AR) $(<) $(>)
+}
+
+actions together ArchiveArchive
+{
+ mkdir .jamArchiveArchive$PPID
+ cp $(>) .jamArchiveArchive$PPID
+ cd .jamArchiveArchive$PPID
+ for i in $(>:BS)
+ do
+ ar -xo $i
+ done
+ cd ..
+ ar -r $(<) .jamArchiveArchive$PPID/*.o
+ rm -rf .jamArchiveArchive$PPID
+}
+
+actions As
+{
+ $(AS) $(ASFLAGS) $(ASHDRS) -o $(<) $(>)
+}
+
+actions C++_
+{
+ $(C++) -c -o $(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
+}
+
+actions Cc_
+{
+ $(CC) -c -o $(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
+}
+
+actions Chgrp_
+{
+ $(CHGRP) $(GROUP) $(<)
+}
+
+actions Chmod1
+{
+ $(CHMOD) $(MODE) $(<)
+}
+
+actions Chown_
+{
+ $(CHOWN) $(OWNER) $(<)
+}
+
+actions piecemeal together existing Clean
+{
+ $(RM) $(>)
+}
+
+actions File_
+{
+ $(CP) $(>) $(<)
+}
+
+#actions FakeFile_ { }
+
+actions GenFile1
+{
+ $(>[1]) $(<) $(>[2-])
+}
+
+actions GenFileND1
+{
+ $(>)
+}
+
+actions GenFileNND1
+{
+ $(>)
+}
+
+actions CreateCatFile_
+{
+ $(CP) /Y nul $(<) > nul
+}
+
+actions CatToFile_
+{
+ echo $(>) >> $(<)
+}
+
+actions Fortran_
+{
+ $(FORTRAN) $(FORTRANFLAGS) -o $(<) $(>)
+}
+
+actions HardLink_
+{
+ $(RM) $(<) && $(LN) $(>) $(<)
+}
+
+actions Install
+{
+ $(CP) $(>) $(<)
+}
+
+actions Lex_
+{
+ $(LEX) $(>)
+}
+
+actions LexMv_
+{
+ $(MV) lex.yy.c $(<)
+}
+
+# Old: $(LINK) $(LINKFLAGS) $(LINKOUTFLAG)$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
+# $(LINK) $(LINKOUTFLAG)$(<) $(UNDEFS) $(>) $(LINKFLAGS) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
+actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
+{
+ $(LINK) $(LINKOUTFLAG)$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(LINKFLAGS) $(STDLIBS)
+}
+
+if $(OS) = MACOSX { # OS X version of ld
+
+ # Link .o and .a into a .dylib
+ # gcc -dynamiclib -Wl,-headerpad_max_install_names,-undefined,dynamic_lookup,-compatibility_version,1.0,-current_version,1.0,-install_name,/usr/local/lib/libfoo.1.dylib -o libfoo.1.dylib $(OBJ)
+ # -Wl,-install_name,@executable_path ???
+ actions ShLink_
+ {
+ $(LINK) -dynamiclib -Wl,-undefined,dynamic_lookup,-install_name,$(SHLINKSEARCHEXEPATH)$(<[1]:BS) $(LINKOUTFLAG)$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHLINKFLAGS) $(SHSTDLIBS)
+ }
+
+} else { # General gcc
+
+ # Link .o and .a into a .so
+ # To set .so search path: -Wl,-rpath,$(LINKSHLIBS:D)
+ # or set LD_LIBRARY_PATH
+ # or set /etc/ld.so.conf.d/*.conf
+ # To set .so search path (after flag): -Wl,-soname=$(<[1]:BS)
+# Old: $(LINK) -shared -Wl,-soname=$(SHLINKSEARCHEXEPATH)$(<[1]:BS) $(SHLINKFLAGS) $(LINKOUTFLAG)$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS)
+ actions ShLink_
+ {
+ $(LINK) -shared -Wl,-soname=$(SHLINKSEARCHEXEPATH)$(<[1]:BS) $(LINKOUTFLAG)$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHLINKFLAGS) $(SHSTDLIBS)
+ }
+}
+
+actions MkDir1
+{
+ $(MKDIR) $(<)
+}
+
+actions together Ranlib
+{
+ $(RANLIB) $(<)
+}
+
+actions quietly updated piecemeal together RmTemps_
+{
+ $(RM) $(>)
+}
+
+actions Shell_
+{
+ $(AWK) '
+ NR == 1 { print "$(SHELLHEADER)" }
+ NR == 1 && /^[#:]/ { next }
+ /^##/ { next }
+ { print }
+ ' < $(>) > $(<)
+}
+
+actions SoftLink_
+{
+ $(RM) $(<) && $(LN) -s $(>) $(<)
+}
+
+actions Yacc1_
+{
+ $(YACC) $(YACCFLAGS) $(>)
+}
+
+actions YaccMv_
+{
+ $(MV) $(YACCFILES).c $(<[1])
+ $(MV) $(YACCFILES).h $(<[2])
+}
+
+actions Aswig1_
+{
+ aswig $(ASWIGFLAGS) -c++ -a2c $(>)
+}
+
+#
+# RELOCATE - for compilers with broken -o flags
+#
+
+if $(RELOCATE)
+{
+ actions C++_
+ {
+ $(C++) -c $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+
+ actions Cc_
+ {
+ $(CC) -c $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+
+ actions ignore CcMv
+ {
+ [ $(<) != $(>:BS=$(SUFOBJ)) ] && $(MV) $(>:BS=$(SUFOBJ)) $(<)
+ }
+}
+
+#
+# NOARUPDATE - can't update an archive
+#
+
+if $(NOARUPDATE)
+{
+ actions Archive
+ {
+ $(AR) $(<) $(>)
+ }
+}
+
+#
+# UNIX specific actions
+#
+
+if $(UNIX)
+{
+ actions GenFile1
+ {
+ PATH="$PATH:."
+ $(>[1]) $(<) $(>[2-])
+ }
+
+ actions CreateCatFile_
+ {
+ $(CP) /dev/null $(<)
+ }
+
+ actions CatToFile_
+ {
+ echo "$(>)" >> $(<)
+ }
+
+ # Make OS X GUI apps work
+ if $(OS) = MACOSX
+ {
+
+ # Used to use /Developer/Tools/Rez -t APPL Carbon.r -o $(<)
+ # but this no longer works in OS X 10.5, and we don't need this
+ # stuff with TransformProcessType()
+ # Another alternative is to use link option "-sectcreate __TEXT __info_plist Info.plist" ???
+ # to embed the plist in the executable, but not sure what should be in plist.
+ # Pure GUI app
+ actions GUIAPP
+ {
+ rm -rf $(<).app
+ mkdir -p $(<).app
+ mkdir $(<).app/Contents
+ mkdir $(<).app/Contents/Resources
+ mkdir $(<).app/Contents/MacOS
+ echo APPLnone > $(<).app/Contents/PkgInfo
+ mv $(<) $(<).app/Contents/MacOS
+ chmod 755 $(<).app/Contents/MacOS/$(<:BS)
+ cat << EOF > $(<).app/Contents/info.plist
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
+<plist version="0.9">
+<dict>
+ <key>CFBundleName</key>
+ <string>$(<:BS)</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleVersion</key>
+ <string>59</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.1</string>
+ <key>CFBundleSignature</key>
+ <string>none</string>
+</dict>
+</plist>
+EOF
+ cat << EOF > $(<)
+#!/bin/sh
+\$0.app/Contents/MacOS/$(<:BS)
+EOF
+ chmod 755 $(<)
+ }
+ }
+}
+
+#
+# NT specific actions
+#
+
+if $(NT)
+{
+ # Ensure timestamp is updated
+
+ actions File_
+ {
+ $(CP) /b $(>) + nul $(<) > nul
+ }
+
+ actions Install
+ {
+ $(CP) /b $(>) + nul $(<) > nul
+ }
+}
+
+if $(NT) && $(MSVCNT)
+{
+# actions updated together piecemeal Archive
+# {
+# if exist $(<) set _$(<:B)_=$(<)
+# $(AR) /out:$(<) %_$(<:B)_% $(>)
+# }
+
+ # This is slightly dodgy if you've got multiple
+ # libraries with the same name in different directories with
+ # jam -j n, or you have .obj's distinguished only by their directory
+ # being combined into the same library, but it overcomes
+ # the problem of lib not updating a library properly if
+ # jam is involked from different directories.
+ actions updated together piecemeal Archive
+ {
+ if exist $(<:BS)_ RMDIR /S/Q $(<:BS)_
+ MKDIR $(<:BS)_
+ for %%i in ( $(>) ) do COPY %%i $(<:BS)_ 1>nul
+ if exist $(<) set _$(<:B)_=$(<)
+ $(AR) /out:$(<) %_$(<:B)_% $(<:BS)_\*
+ DEL /F/S/Q $(<:BS)_\* 1>nul
+ RMDIR /Q $(<:BS)_
+ }
+
+ actions together ArchiveArchive
+ {
+ $(AR) /out:$(<) $(>)
+ }
+
+ actions As
+ {
+ $(AS) /Ml /p /v /w2 $(>) $(<) ,nul,nul;
+ }
+
+ actions Cc_
+ {
+ $(CC) /c /Fo$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) /I$(STDHDRS) $(>)
+ }
+
+ actions C++_
+ {
+ $(C++) /c /Fo$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) /I$(STDHDRS) /Tp $(>)
+ }
+
+ actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
+ {
+ $(LINK) $(LINKFLAGS) $(P_LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
+ }
+
+ # Create DLL using export attribute
+ actions ShLink_ bind SHLINKOBJS SHLINKLIBS SHLINKSHLIBS
+ {
+ $(LINK) /DLL $(SHLINKFLAGS) /out:$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS)
+ }
+
+ # Create DLL using .def file
+ actions ShLinkDef_ bind SHLINKDEFFILE SHLINKOBJS SHLINKLIBS SHLINKSHLIBS
+ {
+ $(LINK) /DLL /DEF:$(SHLINKDEFFILE) $(SHLINKFLAGS) /out:$(<[1]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS)
+ }
+}
+else if $(NT) && $(MSVC)
+{
+ actions updated together piecemeal Archive
+ {
+ $(AR) $(<) -+$(>)
+ }
+
+ actions Cc_
+ {
+ $(CC) /c /Fo$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+
+ actions C++_
+ {
+ $(C++) /c /Fo$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) /Tp $(>)
+ }
+
+ actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
+ {
+ $(LINK) $(LINKFLAGS) $(P_LINKFLAGS) /out:$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
+ }
+}
+else if $(NT) && $(BCCROOT)
+{
+ actions updated together piecemeal Archive
+ {
+ $(AR) $(<) -+$(>)
+ }
+
+ actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
+ {
+ $(LINK) -e$(<) $(LINKFLAGS) $(P_LINKFLAGS) $(UNDEFS) -L$(STDLIBS) $(LINKLIBS) $(LINKSHLIBS) $(>) $(LINKOBJS)
+ }
+
+ actions C++_
+ {
+ $(C++) -c -o$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+
+ actions Cc_
+ {
+ $(CC) -c -o$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+}
+
+else if $(NT) && $(MINGW) {
+
+ # Create DLL using export attribute
+ actions ShLink_ bind SHLINKOBJS SHLINKLIBS SHLINKSHLIBS
+ {
+ $(LINK) -shared $(SHLINKFLAGS) $(LINKOUTFLAG)$(<[1]) -Wl,--out-implib,$(<[2]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS)
+ }
+ # Create DLL using .def file
+ actions ShLinkDef_ bind SHLINKOBJS SHLINKLIBS SHLINKSHLIBS SHLINKDEFFILE
+ {
+ $(LINK) -shared $(SHLINKFLAGS) $(LINKOUTFLAG)$(<[1]) -Wl,--out-implib,$(<[2]) $(>) $(SHLINKOBJS) $(SHLINKLIBS) $(SHLINKSHLIBS) $(SHSTDLIBS) $(SHLINKDEFFILE)
+ }
+}
+
+#
+# OS2 specific actions
+#
+
+else if $(OS2) && $(WATCOM)
+{
+ actions together piecemeal Archive
+ {
+ $(AR) $(<) +-$(>)
+ }
+
+ actions Cc_
+ {
+ $(CC) /Fo=$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+
+ actions C++_
+ {
+ $(C++) /Fo=$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+
+ actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
+ {
+ $(LINK) $(LINKFLAGS) $(P_LINKFLAGS) /Fe=$(<) $(UNDEFS) $(>) $(LINKOBJS) $(LINKLIBS) $(LINKSHLIBS) $(STDLIBS)
+ }
+
+ actions Shell_
+ {
+ $(CP) $(>) $(<)
+ }
+}
+
+#
+# VMS specific actions
+#
+
+else if $(VMS)
+{
+ actions updated together piecemeal Archive
+ {
+ lib/replace $(<) $(>[1]) ,$(>[2-])
+ }
+
+ actions Cc_
+ {
+ $(CC)/obj=$(<) $(CCFLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+
+ actions C++_
+ {
+ $(C++)/obj=$(<) $(C++FLAGS) $(CCDEFS) $(CCHDRS) $(>)
+ }
+
+ actions piecemeal together existing Clean
+ {
+ $(RM) $(>[1]);* ,$(>[2-]);*
+ }
+
+ actions together quietly CreLib
+ {
+ if f$search("$(<)") .eqs. "" then lib/create $(<)
+ }
+
+ actions GenFile1
+ {
+ mcr $(>[1]) $(<) $(>[2-])
+ }
+
+ actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
+ {
+ $(LINK)/exe=$(<) $(LINKFLAGS) $(P_LINKFLAGS) $(>:J=,) ,$(LINKOBJS:J=,) ,$(LINKLIBS)/lib ,$(LINKSHLIBS)/lib ,$(STDLIBS)
+ }
+
+ actions quietly updated piecemeal together RmTemps_
+ {
+ $(RM) $(>[1]);* ,$(>[2-]);*
+ }
+
+ actions Shell_
+ {
+ $(CP) $(>) $(<)
+ }
+}
+
+#
+# Mac specifc actions
+#
+
+else if $(MAC)
+{
+ actions together Archive
+ {
+ $(LINK) -library -o $(<) $(>)
+ }
+
+ actions Cc_
+ {
+ set -e MWCincludes $(CCHDRS)
+ $(CC) -o $(<) $(CCFLAGS) $(CCDEFS) $(>)
+ }
+
+ actions C++_
+ {
+ set -e MWCincludes $(CCHDRS)
+ $(CC) -o $(<) $(C++FLAGS) $(CCDEFS) $(>)
+ }
+
+ actions Link_ bind LINKOBJS LINKLIBS LINKSHLIBS
+ {
+ $(LINK) -o $(<) $(LINKOBJS) $(LINKFLAGS) $(P_LINKFLAGS) $(>) $(LINKLIBS) $(LINKSHLIBS) "$(STDLIBS)"
+ }
+}
+
+if $(WIN98)
+{
+ actions existing Clean
+ {
+ del $(>)
+ }
+}
+
+# =========================================
+
+# Now do Argyll init and read default Jamtop
+DoInit ;
+
+#
+# Now include the user's Jamfile.
+#
+
+#PeerInclude $(DOT) ;
+SubInclude $(DOT) ;
+
diff --git a/Jamfile b/Jamfile
new file mode 100644
index 0000000..1e38a48
--- /dev/null
+++ b/Jamfile
@@ -0,0 +1,67 @@
+
+# Top level Argyll Jamfile.
+
+# Overall optization state and configuration. Overrides sub-Jamfiles
+# See Jamtop and Jambase for other details.
+
+PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+#PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags
+#PREF_LINKFLAGS = $(LINKOPTFLAG) ; # Link optimization flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags
+#PREF_CCFLAGS = $(CCPROFFLAG) ; # Profile flags
+#PREF_LINKFLAGS = $(LINKPROFFLAG) ; # Profile flags
+
+# Include all the sub-directory Jamfiles
+
+SubInclude numlib ;
+SubInclude plot ;
+SubInclude icc ;
+#SubInclude icc4 ;
+SubInclude cgats ;
+SubInclude rspl ;
+SubInclude gamut ;
+SubInclude xicc ;
+SubInclude imdi ;
+SubInclude spectro ;
+SubInclude target ;
+SubInclude scanin ;
+SubInclude profile ;
+SubInclude link ;
+SubInclude tweak ;
+SubInclude render ;
+
+if ! $(HAVE_TIFF) {
+ SubInclude tiff ;
+}
+
+if ! $(HAVE_JPEG) {
+ SubInclude jpg ;
+}
+
+if ! $(USE_NATIVE_USB) {
+
+ if $(USE_LIBUSB1) = true {
+ SubInclude libusb1 ;
+ } else {
+ if $(NT) {
+ SubInclude libusbw ;
+ }
+ if $(UNIX) {
+ SubInclude libusb ;
+ }
+ }
+} else {
+ if $(NT) {
+ SubInclude usb ;
+ }
+}
+
+if $(UNIX) && $(OS) != MACOSX {
+ SubInclude jcnf ;
+ SubInclude ucmm ;
+}
+
+if $(OS) = FREEBSD || $(OS) = OPENBSD {
+ SubInclude libusb ;
+}
diff --git a/Jamtop b/Jamtop
new file mode 100644
index 0000000..1809c9d
--- /dev/null
+++ b/Jamtop
@@ -0,0 +1,160 @@
+
+# This holds the common definitions for Argyll that all the
+# subdirectory jam's will include (even if run in the sub directory)
+
+Echo "Argyll Jamrules has been read" ;
+
+
+# Default install base directory is same directory as Jamtop,
+# but can be overriden in the command line.
+DESTDIR ?= [ NormPaths . ] ;
+
+# Default prefix is empty, but can be overriden in the command line.
+PREFIX ?= "" ;
+
+# Default ref file sub-directory is "ref", but can be overriden in the command line.
+REFSUBDIR ?= "ref" ;
+
+Echo "DESTDIR = '$(DESTDIR)', PREFIX = '$(PREFIX)', REFSUBDIR = '$(REFSUBDIR)'" ;
+
+# Keep this DESTDIR anchored to Jamtop. PREFIX is used literally
+ANCHORED_PATH_VARS = DESTDIR ;
+
+
+# Tell standalone libraries that they are part of Argyll:
+DEFINES += ARGYLLCMS ;
+
+# enable serial instruments & support
+USE_SERIAL = true ;
+
+# enable USB instruments & support
+USE_USB = true ;
+
+# Use native USB drivers, else use libusb
+USE_NATIVE_USB = true ;
+
+# Use libusb1 rather than libusb0 & libusb0-win32
+USE_LIBUSB1 = true ;
+
+# Except that FreeBSD doesn't have a spectro/usbio_bsd.c yet
+if $(OS) = FREEBSD || $(OS) = OPENBSD {
+ USE_NATIVE_USB = false ; # Use libusb
+ USE_LIBUSB1 = false ; # Use libusb 0.1
+}
+
+# Make the USB V1 library static
+LIBUSB_IS_DLL = false ;
+
+# Always use DLL for MSWin, because driver install expects it (.inf)
+if $(NT) {
+ LIBUSB_IS_DLL = true ;
+}
+
+# Set the libubs1 library name.
+LIBUSB1NAME = libusb-1.0A ;
+
+# Information for compiling and linking GUI programs
+
+if $(UNIX) {
+ if $(OS) = MACOSX {
+ LINKFLAGS += -framework IOKit ;
+ LINKFLAGS += -framework CoreFoundation ;
+ LINKFLAGS += -framework AudioToolbox ;
+ LINKFLAGS += -framework AppKit ;
+
+ } else {
+ if [ GLOB /usr/X11R6/include/X11 : X.h ] {
+ LibWinH = /usr/X11R6/include ;
+ } else if [ GLOB /usr/include/X11 : X.h ] {
+ LibWinH = /usr/include ;
+ } else if [ GLOB /usr/local/include/X11 : X.h ] {
+ LibWinH = /usr/local/include ;
+ } else {
+ EXIT Unable to locate the X11 include files ;
+ }
+
+ if $(HOST64) {
+ if [ GLOB /usr/X11R6/lib : libX11.so ] {
+ LibWinD = /usr/X11R6/lib ;
+ } else if [ GLOB /usr/lib/x86_64-linux-gnu : libX11.so ] {
+ LibWinD = /usr/lib/x86_64-linux-gnu ;
+ } else if [ GLOB /usr/lib64 : libX11.so ] {
+ LibWinD = /usr/lib64 ;
+ } else if [ GLOB /usr/lib : libX11.so ] {
+ LibWinD = /usr/lib ;
+ } else if [ GLOB /usr/local/lib : libX11.so ] {
+ LibWinD = /usr/local/lib ;
+ } else {
+ ECHO Unable to locate the 64 bit X11 library files ;
+ }
+ } else {
+ if [ GLOB /usr/X11R6/lib : libX11.so ] {
+ LibWinD = /usr/X11R6/lib ;
+ } else if [ GLOB /usr/lib : libX11.so ] {
+ LibWinD = /usr/lib ;
+ } else if [ GLOB /usr/local/lib : libX11.so ] {
+ LibWinD = /usr/local/lib ;
+ } else {
+ ECHO Unable to locate the 32 bit X11 library files ;
+ }
+ }
+ if $(OS) = FREEBSD {
+ LINKFLAGS += -L$(LibWinD) -g -lrt -lX11 -lXext -lXxf86vm -lXinerama -lXrandr -lXau -lXdmcp -lXss -lusb ;
+ } else {
+ LINKFLAGS += -L$(LibWinD) -ldl -lrt -lX11 -lXext -lXxf86vm -lXinerama -lXrandr -lXau -lXdmcp -lXss ;
+ }
+ # HDRS += $(LibWinH) ;
+ }
+}
+
+# See if we have a system TIFF library.
+if ! $(BUILTIN_TIFF) && $(UNIX) {
+ if [ GLOB /usr/include : tiffio.h ] || [ GLOB /usr/local/include : tiffio.h ] {
+ if [ GLOB /usr/lib : libtiff.so ] || [ GLOB /usr/lib : libtiff.a ]
+ || [ GLOB /usr/lib64 : libtiff.so ] || [ GLOB /usr/lib64 : libtiff.a ]
+ || [ GLOB /usr/lib/x86_64-linux-gnu : libtiff.so ]
+ || [ GLOB /usr/lib/x86_64-linux-gnu : libtiff.a ]
+ || [ GLOB /usr/local/lib : libtiff.so ] || [ GLOB /usr/local/lib : libtiff.a ] {
+ echo "Using system TIFF library" ;
+ TIFFLIB = ;
+ TIFFINC = ;
+ LINKFLAGS += $(LINKFLAG)tiff ;
+ HAVE_TIFF = true ;
+ }
+ }
+}
+
+# If nothing else, use Argyll supplied TIFF library
+if ! $(HAVE_TIFF) || $(BUILTIN_TIFF) {
+ echo "Using Argyll TIFF library" ;
+ TIFFLIB = ../tiff/libtiff.lib ;
+ TIFFINC = ../tiff ;
+}
+
+# See if we have a system JPEG library.
+if ! $(BUILTIN_JPEG) && $(UNIX) {
+ if [ GLOB /usr/include : jpeglib.h ] || [ GLOB /usr/local/include : jpeglib.h ] {
+ if [ GLOB /usr/lib : libjpeg.so ] || [ GLOB /usr/lib : libjpeg.a ]
+ || [ GLOB /usr/lib64 : libjpeg.so ] || [ GLOB /usr/lib64 : libjpeg.a ]
+ || [ GLOB /usr/lib/x86_64-linux-gnu : libjpeg.so ]
+ || [ GLOB /usr/lib/x86_64-linux-gnu : libjpeg.a ]
+ || [ GLOB /usr/local/lib : libjpeg.so ] || [ GLOB /usr/local/lib : libjpeg.a ] {
+ echo "Using system JPEG library" ;
+ JPEGLIB = ;
+ JPEGINC = ;
+ LINKFLAGS += $(LINKFLAG)jpeg ;
+ HAVE_JPEG = true ;
+ }
+ }
+}
+
+# If nothing else, use Argyll supplied JPEG library
+if ! $(HAVE_JPEG) || $(BUILTIN_JPEG) {
+ echo "Using Argyll JPEG library" ;
+ JPEGLIB = ../jpg/libjpeg.lib ;
+ JPEGINC = ../jpg ;
+}
+
+# testing
+#DSTDIR = var ;
+#SRCDIR = .. ;
diff --git a/License.txt b/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/License2.txt b/License2.txt
new file mode 100644
index 0000000..05ca889
--- /dev/null
+++ b/License2.txt
@@ -0,0 +1,282 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
diff --git a/License3.txt b/License3.txt
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/License3.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..44fb7f1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,10 @@
+# default Makefile to invoke Jam
+
+all::
+ jam -q -fJambase -j 3
+
+clean::
+ jam -fJambase clean
+
+install::
+ jam -q -fJambase -j 3 install
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..6bddae8
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,23 @@
+include $(top_srcdir)/Makefile.shared
+
+ACLOCAL_AMFLAGS = -I m4
+
+privatelib_LTLIBRARIES = libargyll.la
+privatelibdir = $(pkglibdir)
+
+libargyll_la_SOURCES = xicc/xicc.c xicc/xicc.h xicc/xcam.c xicc/xcam.h \
+ gamut/gamut.c gamut/gamut.h xicc/xfit.c xicc/xfit.h \
+ xicc/cam97s3.c xicc/cam97s3.h xicc/cam02.c xicc/cam02.h \
+ xicc/moncurve.c xicc/moncurve.h xicc/xspect.c xicc/xspect.h \
+ xicc/xcal.c xicc/xcal.h xicc/xcolorants.h xicc/xcolorants.c xicc/ccmx.c
+libargyll_la_LIBADD = ./rspl/librspl.la $(ICC_LIBS) \
+ ./numlib/libargyllnum.la ./cgats/libcgats.la
+
+SUBDIRS = h doc ref numlib cgats $(ICC_SUBDIRS) plot rspl jcnf ucmm render . gamut \
+ spectro xicc target link tweak profile scanin imdi
+
+#SUBDIRS = h doc ref numlib cgats $(ICC_SUBDIRS) plot rspl jcnf ucmm render . gamut \
+# spectro xicc target link tweak profile scanin imdi
+
+
+EXTRA_DIST = Readme.txt ttbd.txt log.txt
diff --git a/Makefile.shared b/Makefile.shared
new file mode 100644
index 0000000..1f1e105
--- /dev/null
+++ b/Makefile.shared
@@ -0,0 +1,15 @@
+# Common CFLAGS for Argyll components
+
+AM_CFLAGS = -D_GNU_SOURCE -DUNIX -DENABLE_USB -DENABLE_SERIAL -I$(top_srcdir)/cgats \
+ -I$(top_srcdir)/gamut -I$(top_srcdir)/h -I$(top_srcdir)/jcnf \
+ -I$(top_srcdir)/libusb1/libusb -I$(top_srcdir)/numlib \
+ -I$(top_srcdir)/plot -I$(top_srcdir)/profile -I$(top_srcdir)/render \
+ -I$(top_srcdir)/rspl -I$(top_srcdir)/spectro -I$(top_srcdir)/target \
+ -I$(top_srcdir)/ucmm -I$(top_srcdir)/xicc $(TIFF_CFLAGS) $(ICC_CFLAGS) \
+ $(YAJL_CFLAGS) -L$(top_srcdir)/spectro
+
+# Build libs in other dirs when required
+../%.la:
+ $(MAKE) -C $(@D) $(@F)
+./%.la:
+ $(MAKE) -C $(@D) $(@F)
diff --git a/Readme.txt b/Readme.txt
new file mode 100644
index 0000000..f1b9cb5
--- /dev/null
+++ b/Readme.txt
@@ -0,0 +1,43 @@
+
+Argyll CMS README file - Version 1.5.0
+--------------------------------------
+
+Date: 8th March 2013
+Author: Graeme Gill
+
+Introduction
+
+ArgyllCMS is an ICC compatible color management system, available as Open Source.
+It supports accurate ICC profile creation for scanners, cameras and film
+recorders, and calibration and profiling of displays and RGB & CMYK printers.
+Spectral sample data is supported, allowing a selection of illuminants observer
+types, and paper fluorescent whitener additive compensation. Profiles can also
+incorporate source specific gamut mappings for perceptual and saturation intents.
+Gamut mapping and profile linking uses the CIECAM02 appearance model, a unique
+gamut mapping algorithm, and a wide selection of rendering intents. Device Link
+can be created with a wide variety of advanced options. It also includes code for
+the fastest portable 8 bit raster color conversion engine available anywhere, as
+well as support for fast, fully accurate 16 bit conversion. Device color gamuts
+can also be viewed and compared using a VRML viewer. Comprehensive documentation
+is provided for each major tool, and a general guide to using the tools for typical
+color management tasks is also available. A mailing list provides support for
+more advanced usage.
+
+This is Version 1.5.1, a bug fix update to V1.5.0 released on 1st March 2013.
+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
+between revisions is detailed in the log.txt file that accompanies the source code.
+
+It is licensed under the Affero GNU Version 3 license.
+
+For more detailed information, please consult the HTML documentation in
+<doc/ArgyllDoc.html>, or <http://www.argyllcms.com/doc/ArgyllDoc.html>.
+
+For the most recent source code start at <http://www.argyllcms.com/index.html>.
+
+Contact me in regards to Argyll, icclib or cgatslib at:
+
+ Graeme at argyllcms dot com
+
+Enjoy!
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..9740558
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,1073 @@
+# generated automatically by aclocal 1.13.3 -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.13'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.13.3], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.13.3])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
+ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
+ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
+ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+ [--enable-dependency-tracking],
+ [do not reject slow dependency extractors])
+AS_HELP_STRING(
+ [--disable-dependency-tracking],
+ [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+ [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ [ok:ok],,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES([CC])],
+ [m4_define([AC_PROG_CC],
+ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES([CXX])],
+ [m4_define([AC_PROG_CXX],
+ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES([OBJC])],
+ [m4_define([AC_PROG_OBJC],
+ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+ [_AM_DEPENDENCIES([OBJCXX])],
+ [m4_define([AC_PROG_OBJCXX],
+ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# -*- Autoconf -*-
+# Obsolete and "removed" macros, that must however still report explicit
+# error messages when used, to smooth transition.
+#
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([AM_CONFIG_HEADER],
+[AC_DIAGNOSE([obsolete],
+['$0': this macro is obsolete.
+You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl
+AC_CONFIG_HEADERS($@)])
+
+AC_DEFUN([AM_PROG_CC_STDC],
+[AC_PROG_CC
+am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
+AC_DIAGNOSE([obsolete],
+['$0': this macro is obsolete.
+You should simply use the 'AC][_PROG_CC' macro instead.
+Also, your code should no longer depend upon 'am_cv_prog_cc_stdc',
+but upon 'ac_cv_prog_cc_stdc'.])])
+
+AC_DEFUN([AM_C_PROTOTYPES],
+ [AC_FATAL([automatic de-ANSI-fication support has been removed])])
+AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+ alias in your environment])
+ fi
+ if test "$[2]" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+ [AC_MSG_CHECKING([that generated files are newer than configure])
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+ [am_cv_make_support_nested_variables],
+ [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+ dnl Using '$V' instead of '$(V)' breaks IRIX make.
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+ [m4_case([$1],
+ [ustar],
+ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+ if test $am_uid -le $am_max_uid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi
+ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+ if test $am_gid -le $am_max_gid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi],
+
+ [pax],
+ [],
+
+ [m4_fatal([Unknown tar format])])
+
+ AC_MSG_CHECKING([how to create a $1 tar archive])
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ AM_RUN_LOG([cat conftest.dir/file])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
diff --git a/adirs b/adirs
new file mode 100644
index 0000000..6816f91
--- /dev/null
+++ b/adirs
@@ -0,0 +1,26 @@
+.
+numlib
+usb
+plot
+icc
+cgats
+rspl
+gamut
+xicc
+spectro
+imdi
+target
+scanin
+profile
+link
+tweak
+render
+ucmm
+jcnf
+jcnf/yajl
+lib
+h
+ref
+doc
+tiff
+jpg
diff --git a/afiles b/afiles
new file mode 100644
index 0000000..7bf76cf
--- /dev/null
+++ b/afiles
@@ -0,0 +1,22 @@
+Readme.txt
+afiles
+adirs
+blddirs
+binfiles
+jam.patch
+Jambase
+Jamfile
+Jamtop
+Makefile
+License.txt
+License2.txt
+License3.txt
+ttbd.txt
+log.txt
+notes.txt
+makeall.bat
+install.bat
+makeall.sh
+ziparch.sh
+makeinstall.sh
+makepackagebin.sh
diff --git a/binfiles b/binfiles
new file mode 100644
index 0000000..93615a4
--- /dev/null
+++ b/binfiles
@@ -0,0 +1,3 @@
+Readme.txt
+License.txt
+log.txt
diff --git a/blddirs b/blddirs
new file mode 100644
index 0000000..73d667b
--- /dev/null
+++ b/blddirs
@@ -0,0 +1 @@
+numlib tiff libusb libusbw plot icc cgats rspl gamut xicc spectro xicc imdi target scanin profile link tweak render spectro
diff --git a/cgats/Jamfile b/cgats/Jamfile
new file mode 100644
index 0000000..813269a
--- /dev/null
+++ b/cgats/Jamfile
@@ -0,0 +1,37 @@
+
+# Jamfile for cgats library
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ;
+
+#if stdio is not wanted in icclib:
+#DEFINES = SEPARATE_STD ;
+
+#Products
+Libraries = libcgats ;
+Headers = cgats.h ;
+
+#Install
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+
+# Stop objects that are in more than one library from being
+# prematurely deleted:
+ObjectKeep cgats pars ;
+
+# CGATS library
+Library libcgats : pars.c cgats.c ;
+
+# Executable support if SEPARATED_STD
+if SEPARATE_STD in $(DEFINES) {
+ Objects parsstd.c cgatsstd.c ;
+ LINKOBJS = cgatsstd parsstd ; # Link all tests here with these
+}
+
+# Individual stand alone test of parser
+MainVariant pars : pars.c : : STANDALONE_TEST ;
+
+# Individual stand alone test of cgats i/o
+MainVariant cgats : cgats.c : : STANDALONE_TEST : : pars ;
+
diff --git a/cgats/License.txt b/cgats/License.txt
new file mode 100644
index 0000000..7655233
--- /dev/null
+++ b/cgats/License.txt
@@ -0,0 +1,22 @@
+*************************************************************************
+Copyright (c) 1995-2002 Graeme W. Gill
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*************************************************************************
diff --git a/cgats/Makefile b/cgats/Makefile
new file mode 100644
index 0000000..5312104
--- /dev/null
+++ b/cgats/Makefile
@@ -0,0 +1,68 @@
+# UNIX style makefile, for icclib and friends.
+# "include" the right environment for your system,
+# by uncommenting the appropriate line:
+
+# Microsoft C++, WinNT setup
+#include Makefile.WNT
+
+# IBM C++, WinNT setup
+include Makefile.IBMNT
+
+# Generic UNIX setup
+#include Makefile.UNIX
+
+# Apple OSX
+#include Makefile.OSX
+
+###############################
+
+#Compile with separate stndard malloc & file io
+#CCDEFINES = $(DEFFLAG)SEPARATE_STD
+
+#Set optimisation on
+CCFLAGS = $(CCFLAGSDEF) $(CCOPTFLAG) $(CCDEFINES)
+
+#Set debugging on
+#CCFLAGS = $(CCFLAGSDEF) $(CCDEBUGFLAG) $(CCDEFINES)
+
+STDHDRS = $(STDHDRSDEF)
+LINKFLAGS = $(LINKFLAGSDEF) $(LINKDEBUGFLAG)
+
+all:: libcgats$(SUFLIB) pars$(SUFEXE) cgats$(SUFEXE)
+
+
+# Separate for executables
+parsstd$(SUFOBJ): parsstd.c pars.h
+ $(CC) $(CCOF)parsstd$(SUFOBJ) parsstd.c
+
+cgatsstd$(SUFOBJ): cgatsstd.c cgats.h pars.h
+ $(CC) $(CCOF)cgatsstd$(SUFOBJ) cgatsstd.c
+
+
+pars$(SUFOBJ): pars.c pars.h
+ $(CC) $(CCOF)pars$(SUFOBJ) pars.c
+
+cgats$(SUFOBJ): cgats.c cgats.h pars.h
+ $(CC) $(CCOF)cgats$(SUFOBJ) cgats.c
+
+
+libcgats$(SUFLIB): pars$(SUFOBJ) cgats$(SUFOBJ)
+ $(LIBU) $(LIBOF)libcgats$(SUFLIB) cgats$(SUFOBJ) pars$(SUFOBJ)
+ $(RANLIB) libcgats$(SUFLIB)
+
+
+sa_pars$(SUFOBJ): pars.c pars.h
+ $(CC) $(CCOF)sa_pars$(SUFOBJ) $(DEFFLAG)STANDALONE_TEST pars.c
+
+pars$(SUFEXE): sa_pars$(SUFOBJ) parsstd$(SUFOBJ)
+ $(LINK) $(LINKOF)pars$(SUFEXE) sa_pars$(SUFOBJ) parsstd$(SUFOBJ) $(LINKLIBS)
+
+
+sa_cgats$(SUFOBJ): cgats.c cgats.h pars.h
+ $(CC) $(CCOF)sa_cgats$(SUFOBJ) $(DEFFLAG)STANDALONE_TEST cgats.c
+
+cgats$(SUFEXE): sa_cgats$(SUFOBJ) pars$(SUFOBJ) parsstd$(SUFOBJ) cgatsstd$(SUFOBJ)
+ $(LINK) $(LINKOF)cgats$(SUFEXE) sa_cgats$(SUFOBJ) pars$(SUFOBJ) parsstd$(SUFOBJ) \
+ cgatsstd$(SUFOBJ) $(LINKLIBS)
+
+
diff --git a/cgats/Makefile.IBMNT b/cgats/Makefile.IBMNT
new file mode 100644
index 0000000..26a2bd2
--- /dev/null
+++ b/cgats/Makefile.IBMNT
@@ -0,0 +1,41 @@
+# IBM C++, WinNT setup
+
+SLASH = \
+SUFLIB = .lib
+SUFOBJ = .obj
+SUFEXE = .exe
+CMDSEP = &
+
+INCFLAG = /I
+DEFFLAG = /D
+UNDEFFLAG = "/U _"
+CCOPTFLAG = /O+ /qtune=pentiumpro
+CCDEBUGFLAG = /Ti+ /O- /Oi- /DEbug
+CCPROFFLAG = /Ti+ /Gh+
+LINKDEBUGFLAG = /DEbug
+LINKPROFFLAG = /DE /NOE cppwpa3.obj
+
+STDHDRSDEF = $(IPF_PATH32)\\include $(IPF_PATH32)\\sdk\\winh
+
+MAKEU = nmake
+LIBU = ilib /Q
+LIBOF = /OUT:
+RANLIB = rem
+AS = masm386
+CCFLAGSDEF = /DNT /c
+CC = icc /Q $(CCFLAGS) $(INCFLAG)$(STDHDRS)
+CCOF = /Fo
+LINKLIBS = $(IPF_PATH32)\\sdk\\lib\\*.lib
+LINKFLAGSDEF =
+LINK = ilink /NOLogo $(LINKFLAGS)
+LINKOF = /OUT:
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
+
+
+
diff --git a/cgats/Makefile.OSX b/cgats/Makefile.OSX
new file mode 100644
index 0000000..fb1c88f
--- /dev/null
+++ b/cgats/Makefile.OSX
@@ -0,0 +1,38 @@
+# MAC OSX, derived from UNIX setup
+
+SLASH = /
+SUFLIB = .a
+SUFOBJ = .o
+SUFEXE =
+CMDSEP = ;
+
+INCFLAG = -I
+DEFFLAG = -D
+UNDEFFLAG = "-u _"
+CCOPTFLAG = -O
+CCDEBUGFLAG = -g
+CCPROFFLAG =
+LINKDEBUGFLAG =
+LINKPROFFLAG =
+
+STDHDRSDEF = /usr/include
+
+MAKEU = make
+LIBU = ar -r
+LIBOF =
+RANLIB = ranlib
+AS = as
+CCFLAGSDEF = -DUNIX -c
+CC = cc $(CCFLAGS) $(INCFLAG)$(STDHDRS)
+CCOF = -o
+LINKFLAGSDEF = -lm
+LINKLIBS =
+LINK = cc $(LINKFLAGS) $(LINKLIBS)
+LINKOF = -o
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/cgats/Makefile.UNIX b/cgats/Makefile.UNIX
new file mode 100644
index 0000000..91d6005
--- /dev/null
+++ b/cgats/Makefile.UNIX
@@ -0,0 +1,38 @@
+# Generic UNIX setup
+
+SLASH = /
+SUFLIB = .a
+SUFOBJ = .o
+SUFEXE =
+CMDSEP = ;
+
+INCFLAG = -I
+DEFFLAG = -D
+UNDEFFLAG = "-u _"
+CCOPTFLAG = -O
+CCDEBUGFLAG = -g
+CCPROFFLAG =
+LINKDEBUGFLAG =
+LINKPROFFLAG =
+
+STDHDRSDEF = /usr/include
+
+MAKEU = make
+LIBU = ar -r
+LIBOF = -o
+RANLIB = echo
+AS = as
+CCFLAGSDEF = -DUNIX -c
+CC = cc $(CCFLAGS) $(INCFLAG)$(STDHDRS)
+CCOF = -o
+LINKFLAGSDEF = -lm
+LINKLIBS =
+LINK = cc $(LINKFLAGS) $(LINKLIBS)
+LINKOF = -o
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/cgats/Makefile.WNT b/cgats/Makefile.WNT
new file mode 100644
index 0000000..4ca291d
--- /dev/null
+++ b/cgats/Makefile.WNT
@@ -0,0 +1,38 @@
+# Microsoft C++, WinNT setup
+
+SLASH = \
+SUFLIB = .lib
+SUFOBJ = .obj
+SUFEXE = .exe
+CMDSEP = &
+
+INCFLAG = /I
+DEFFLAG = /D
+UNDEFFLAG = "/u _"
+CCOPTFLAG = /Ox /GB
+CCDEBUGFLAG = /Z7 /Od
+CCPROFFLAG = /Z7
+LINKDEBUGFLAG = /DEBUG
+LINKPROFFLAG = /PROFILE
+
+STDHDRSDEF = $(MSVCNT)\include
+
+MAKEU = nmake
+LIBU = lib
+LIBOF = /OUT:
+RANLIB = rem
+AS = masm386
+CCFLAGSDEF = /DNT /c
+CC = cl /nologo $(CCFLAGS) $(INCFLAG)$(STDHDRS)
+CCOF = /Fo
+LINKLIBS = $(MSVCNT)/lib/user32.lib $(MSVCNT)/lib/gdi32.lib
+LINKFLAGSDEF = /link /INCREMENTAL:NO
+LINK = link $(LINKFLAGS)
+LINKOF = /OUT:
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/cgats/Makefile.am b/cgats/Makefile.am
new file mode 100644
index 0000000..23db698
--- /dev/null
+++ b/cgats/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libcgats.la
+privatelibdir = $(pkglibdir)
+
+libcgats_la_SOURCES = pars.c pars.h cgats.c cgats.h parsstd.c \
+ cgatsstd.c
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/cgats/Readme.txt b/cgats/Readme.txt
new file mode 100644
index 0000000..94f3e3d
--- /dev/null
+++ b/cgats/Readme.txt
@@ -0,0 +1,286 @@
+
+CGATS file I/O library, V2.01 README file
+-----------------------------------------
+
+Package contents:
+-----------------
+cgatslib.zip ZIP archive of the following files
+Readme.txt This file.
+License.txt Important! - Permissions for use of this package.
+cgats.c CGATS Library source code.
+cgatsstd.c I/O and malloc source code.
+cgats.h CGATS Library include file. Note machine dependent defines.
+pars.c Parser source code.
+parsstd.c I/O and malloc source code.
+pars.h Parser include file. Note machine dependent defines.
+Jampfile JAM style "makefile" see <http://www.perforce.com/jam/jam.html>
+Makefile Makefile. Modify this to include one of the following rule sets.
+Makefile.WNT Makefile defines for Microsoft C++ on Windows NT
+Makefile.IBMNT Makefile defines for IBM C++ on Windows NT
+Makefile.UNIX Makefile defines for generic UNIX system
+Makefile.OSX Makefile defines for Apple MAC OSX
+
+Changes:
+--------
+
+Changes since V2.00
+
+ Removed all exit()s from code - now return error values
+ from all functions.
+
+ Added abstract objects for File I/O and memory allocation
+ to improve system compatibility.
+
+ Separated the implimentations of the abstract I/O and
+ memory objects that ise stdio and malloc into separate
+ files so that a library can be compiled without reference
+ to these system calls.
+
+
+---------------------------------------------------------------
+ DOCUMENTATION
+
+ This library has been implemented from the CGATS.5 Data Exchange Format
+ specification, in Annex J, of the ANSI CGATS.5-1993 standard.
+ See <http://www.npes.org/standards/description.htm>
+
+ This module attempts to make reading CGATS.5 and IT8.7 files
+ easy and convenient. Since the standard is a less than clear
+ on some points it is hard to know how much compatibility is
+ to be expected.
+
+ The module supports non-standard keywords and fields automatically.
+ It does not support reading of comments.
+ It supports reading and writing multiple tables within one file.
+ Abreviated tables may be written.
+ Non-standard fields written by this module will be recognized
+ correcty when read by this module (data types are written
+ unambiguously - reals all have a decimal point, no non-quoted strings
+ are written that could be interpreted as a real or integer), but
+ there is no certainty that non-standard fields written by other
+ software will be recognized corectly (e.g. - how to you tell
+ whether 1234 is an integer, real, or non-quoted string ?)
+
+ To creat a file each element needs to be built up in turn:
+
+ Create an empty cgats structure:
+ new_cgats().
+
+ A non-standard memory allocator can be specified for use
+ by the cgats object by passing an object that inherits
+ from the cgatsAlloc class defined in parse.h, to the
+ new_cgats_al(cgatsAlloc *al) constructor.
+
+
+ Use the module methods to:
+
+
+ Add a user defined file identifier to augment the standard identifiers:
+ add_other(cgats *p, char *osym)
+ This can be used to read or write table that are compatible with CGATS.5
+ syntax but have different file identifiers.
+ Use a zero length string (ie. just "") for wildcard.
+ Normaly returns 0, returns -ve if there was a system error,
+ & sets p->errc & p->err appropriately.
+
+
+ create an empty table entry:
+ add_table(cgats *p, table_type tt, int oi)
+ tt is the table type: it8_7_1, it8_7_2, it8_7_3, it8_7_4, cgats_5, cgats_X,
+ tt_other or tt_none.
+ cgat_X represents any "CGATS.XXX" table type.
+ If tt_other is used for creating a file, then oi must be set to the index of the
+ user defined table identifiers set by calls to p->add_other();
+ The table type read can be identified by looking at the index
+ p->t[table_number].tt, which will be set to the table type.
+ If the type is cgats_X type, the type actually found will be in p->cgats_type.
+ If tt == tt_other, then the "other index" value is p->t[table_numberx].oi.
+ For a wildcard tt_other, the actual type found will be at p->others[oi].
+
+ Tables are added in turn, and are indexed from 0 in other functions.
+ Returns 0 normally.
+ It returns -2 if there was a system error, & sets p->errc & p->err appropriately.
+
+
+ Suppress the writing of the file identifier string, standard keyword definitions
+ and/or field definitions for a second or subsequent table:
+ set_table_flags(cgats *p, int table, int sup_id, int sup_kwords, int sup_fields);
+ This only makes sense if the subsequent table has the same identifier type, keywords
+ and field definitions as the preceding table. Returns 0 normally.
+ It returns -1 if there was an error, & sets p->errc & p->err appropriately.
+
+
+ Add keywords and their values:
+ int add_kword(cgats *p, int table, char *ksym, char *kdata, char *kcom);
+ The return value is the index of the new keyword, or -1, errc & err on error.
+ Any non-standard keywords will automatically be declared in the file.
+ The comment is optional and NULL should be passed if no comment is to be used
+ after the keyword/value pair.
+
+ Standard keywords are:
+ ORIGINATOR System, organization or individual that created data
+ DESCRIPTOR Purpose or contents of the data file
+ CREATED Date of creation of the file
+ MANUFACTURER Manufacturer of physical target
+ PROD_DATE Year and month of physical target production yyyy:mm
+ SERIAL Unique physical target serial number
+ MATERIAL Material physical target was produced on
+ INSTRUMENTATION Manufacturer and model number of measuring instrument
+ MEASUREMENT_SOURCE Illumination used for spectral measurements
+ PRINT_CONDITIONS Characteristics of printed sheet being reported
+
+ Standard keywords will be created automatically if necessary for a legal file format.
+
+ The following kewords are supplied automatically by the module,
+ and cannot be used for other things:
+ NUMBER_OF_FIELDS
+ BEGIN_DATA_FORMAT
+ END_DATA_FORMAT
+ NUMBER_OF_SETS
+ BEGIN_DATA
+ END_DATA
+ KEYWORD
+
+
+ Add fields:
+ int add_field(cgats *p, int table, char *fsym, data_type ftype);
+
+ The return value is the index of the new field, or return
+ -1, errc & err on error, -2, errc & err on system error.
+
+ ftype defines the data type from: r_t, i_t, cs_t, nqcs_t.
+ r_t is the real (double) type,
+ i_t is the integer (int) type,
+ cs_t is the character string (char*) type,
+ nqcs_t is the same as cs_t except that it will be non-quoted if possible.
+ Note that the type must agree with the standard type if the field is
+ from the set default data format identifiers:
+
+ SAMPLE_ID nqcs_t Identifies sample which data represents
+ STRING cs_t Identifies label, or other non-machine readable value.
+ CMYK_C r_t Cyan percentage of CMYK
+ CMYK_M r_t Magenta percentage of CMYK
+ CMYK_Y r_t Yellow percentage of CMYK
+ CMYK_K r_t Black percentage of CMYK
+ D_RED r_t Red filter reflection density
+ D_GREEN r_t Green filter reflection density
+ D_BLUE r_t Blue filter reflection density
+ D_VIS r_t Visual filter reflection density
+ RGB_R r_t Red component of RGB data
+ RGB_G r_t Green component of RGB data
+ RGB_B r_t Blue component of RGB data
+ SPECTRAL_NM r_t Wavelength of measurement in nanometers
+ SPECTRAL_PCT r_t Precentage reflectance/transmittance
+ XYZ_X r_t X component of tristimulus data
+ XYZ_Y r_t Y component of tristimulus data
+ XYZ_Z r_t Z component of tristimulus data
+ XYY_X r_t x component of chromaticity data
+ XYY_Y r_t y component of chromaticity data
+ XYY_CAPY r_t Y component of chromaticity data
+ LAB_L r_t L* component of Lab data
+ LAB_A r_t a* component of Lab data
+ LAB_B r_t b* component of Lab data
+ LAB_C r_t C*ab component of Lab data
+ LAB_H r_t hab component of Lab data
+ LAB_DE r_t CIA delta E
+ STDEV_X r_t Standard deviation of X (tristimulous data)
+ STDEV_Y r_t Standard deviation of Y (tristimulous data)
+ STDEV_Z r_t Standard deviation of Z (tristimulous data)
+ STDEV_L r_t Standard deviation of L*
+ STDEV_A r_t Standard deviation of a*
+ STDEV_B r_t Standard deviation of b*
+ STDEV_DE r_t Standard deviation of CIE delta E
+
+ Add a set of data:
+ add_set(cgats *p, int table, ...)
+ The data should be supplied as a varargs list in the appropropriate
+ data format [char*, double or int].
+ Returns 0 normally, -1 errc & err if parameter error,
+ -2 errc & err if system error.
+
+ Add a set of data from union array:
+ add_setarr(cgats *p, int table, cgats_set_elem *args);
+ The data should be supplied as an array of cgats_set_elem unions.
+ Returns 0 normally, -1 errc & err if parameter error,
+ -2 errc & err if system error.
+
+ Write the data out to a file.
+ write_name(cgats *p, char *fname);
+ The method will return non-zero on an error, with an error
+ description in the err location of the structure.
+
+
+ A non-standard destination of data can be read by passing an
+ object that inherits from the cgatsFile class defined in
+ parse.h to the write(cgats *p, cgatsFile *fp) method.
+
+ To read in a data file, the cgats structure should be created
+ as usual. The read method can then be called to read in the file:
+ read_name(cgats *p, char *fname)
+ Returns 0 normally, and -ve on an error, with an error
+ description in the err location of the structure,
+ and errc set with the return code.
+
+ A non-standard source of data can be read by passing an
+ object that inherits from the cgatsFile class defined in
+ parse.h to the read(cgats *p, cgatsFile *fp) method.
+
+ The reader will deal automaticaly with carry over of keywords
+ and/or field definitions from one table to another, making each
+ table appear independent once read.
+
+ The data is accessed by refering to the following read-only
+ structure entries:
+
+ The number of tables will be in p->ntables
+
+ The number of keywords will be in p->t[table_number].nkwords
+ The number of fields will be in p->t[table_number].nfields
+ The number of sets will be in p->t[table_number].nsets
+
+ Tables, keywords, fields and sets index from 0.
+
+ The keywords will be in
+ p->t[table_number].ksym[keyword_index]
+
+ The keywords character string value be in
+ p->t[table_number].kdata[keyword_index]
+
+ The field format identifiers of each field will be in
+ p->t[table_number].fsym[field_index]
+
+ The data type of each field will be in
+ p->t[table_number].ftype[field_index]
+
+ A void pointer to the data of each field of each set will be in
+ p->t[table_number].fdata[set_index][field_index]
+ Cast the void pointet according to its type to retrieve the data.
+ Alternatively the
+ p->get_setarr(struct _cgats *p, int table, int set_index, cgats_set_elem *ary)
+ method can be used to fill in a suitable sized cgats_set_elem array with
+ the value of all the fields at a particular index. Any character string
+ type will be a pointer to the data in p->t[table_number].fdata[set_index][field_index].
+
+ To find the index to a particular keyword, use:
+ find_kword(cgats *p, int table, char *ksym)
+ -1 will be returned if no match is found.
+ -2 will be returned, p->errc & p->err will be set if table is out of range.
+
+ To find the index to a particular field, use:
+ find_field(cgats *p, int table, char *fsym);
+ -1 will be returned if no match is found.
+ -2 will be returned, p->errc & p->err will be set if table is out of range.
+
+ Rather than checking the error return codes from every method,
+ the first error is "sticky", and recorded in the object.
+ This can be checked after a series of operations by calling
+ the error(cgats *p, char **mes) method, which will return the
+ error code, and (optionaly) the error message.
+
+ Once operations are finished, the object can be deleted by calling
+ the delete method:
+ del(cgats *p)
+
+Graeme Gill.
+
+---------------------------------------------------------------
diff --git a/cgats/afiles b/cgats/afiles
new file mode 100644
index 0000000..dc20cb4
--- /dev/null
+++ b/cgats/afiles
@@ -0,0 +1,16 @@
+Readme.txt
+License.txt
+afiles
+cgats.c
+cgats.h
+pars.c
+pars.h
+parsstd.c
+cgatsstd.c
+Jamfile
+Makefile
+Makefile.WNT
+Makefile.IBMNT
+Makefile.UNIX
+Makefile.OSX
+makezip.ksh
diff --git a/cgats/cgats.c b/cgats/cgats.c
new file mode 100644
index 0000000..baf9992
--- /dev/null
+++ b/cgats/cgats.c
@@ -0,0 +1,2166 @@
+
+/*
+ * Committee for Graphics Arts Technologies Standards
+ * CGATS.5 and IT8.7 family file I/O class
+ * Version 2.05
+ *
+ * Author: Graeme W. Gill
+ * Date: 20/12/95
+ *
+ * Copyright 1995, 1996, 2002, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+#define _CGATS_C_ /* Turn on implimentation code */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#undef DEBUG /* Debug only in slected places */
+
+#ifdef DEBUG
+# define DBGA g_log, 0 /* First argument to DBGF() */
+# define DBGF(xx) a1logd xx
+#else
+# define DBGF(xx)
+#endif
+
+#ifdef STANDALONE_TEST
+extern void error(const char *fmt, ...), warning(const char *fmt, ...);
+#endif
+
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include <math.h>
+#include "pars.h"
+#include "cgats.h"
+
+#define REAL_SIGDIG 5 /* Number of significant digits in real representation */
+
+static int cgats_read(cgats *p, cgatsFile *fp);
+static int find_kword(cgats *p, int table, const char *ksym);
+static int find_field(cgats *p, int table, const char *fsym);
+static int add_table(cgats *p, table_type tt, int oi);
+static int set_table_flags(cgats *p, int table, int sup_id, int sup_kwords, int sup_fields);
+static int set_cgats_type(cgats *p, const char *osym);
+static int add_other(cgats *p, const char *osym);
+static int get_oi(cgats *p, const char *osym);
+static int add_kword(cgats *p, int table, const char *ksym, const char *kdata, const char *kcom);
+static int add_field(cgats *p, int table, const char *fsym, data_type ftype);
+static int add_set(cgats *p, int table, ...);
+static int add_setarr(cgats *p, int table, cgats_set_elem *args);
+static int get_setarr(cgats *p, int table, int set_index, cgats_set_elem *args);
+static int cgats_write(cgats *p, cgatsFile *fp);
+static int cgats_error(cgats *p, char **mes);
+static void cgats_del(cgats *p);
+
+static void cgats_table_free(cgats_table *t);
+static void *alloc_copy_data_type(cgatsAlloc *al, data_type ktype, void *dpoint);
+static int reserved_kword(const char *ksym);
+static int standard_kword(const char *ksym);
+static data_type standard_field(const char *fsym);
+static int cs_has_ws(const char *cs);
+static char *quote_cs(cgatsAlloc *al, const char *cs);
+static int clear_fields(cgats *p, int table);
+static int add_kword_at(cgats *p, int table, int pos, const char *ksym, const char *kdatak, const char *kcom);
+static int add_data_item(cgats *p, int table, void *data);
+static void unquote_cs(char *cs);
+static data_type guess_type(const char *cs);
+static void real_format(double value, int nsd, char *fmt);
+
+#ifdef COMBINED_STD
+static int cgats_read_name(cgats *p, const char *filename);
+static int cgats_write_name(cgats *p, const char *filename);
+#endif
+
+static const char *data_type_desc[] =
+ { "real", "integer", "char string", "non-quoted char string", "no type" };
+
+/* Create an empty cgats object */
+/* Return NULL on error */
+cgats *new_cgats_al(
+cgatsAlloc *al /* memory allocator */
+) {
+ cgats *p;
+
+ if ((p = (cgats *) al->calloc(al, sizeof(cgats), 1)) == NULL) {
+ return NULL;
+ }
+ p->al = al; /* Heap allocator */
+
+ /* Initialize the methods */
+ p->find_kword = find_kword;
+ p->find_field = find_field;
+ p->read = cgats_read;
+ p->add_table = add_table;
+ p->set_table_flags = set_table_flags;
+ p->set_cgats_type = set_cgats_type;
+ p->add_other = add_other;
+ p->get_oi = get_oi;
+ p->add_kword = add_kword;
+ p->add_field = add_field;
+ p->add_set = add_set;
+ p->add_setarr = add_setarr;
+ p->get_setarr = get_setarr;
+ p->write = cgats_write;
+ p->error = cgats_error;
+ p->del = cgats_del;
+
+#ifndef SEPARATE_STD
+ p->read_name = cgats_read_name;
+ p->write_name = cgats_write_name;
+#else
+ p->read_name = NULL;
+ p->write_name = NULL;
+#endif
+
+ return p;
+}
+
+static int err(cgats *p, int errc, const char *fmt, ...);
+
+/* new_cgats() with default malloc allocator */
+
+#ifndef SEPARATE_STD
+#define COMBINED_STD
+
+#include "cgatsstd.c"
+
+#undef COMBINED_STD
+#endif /* SEPARATE_STD */
+
+/* ------------------------------------------- */
+
+/* Implimentation function - register an error */
+/* Return the error number */
+static int
+err(cgats *p, int errc, const char *fmt, ...) {
+ va_list args;
+
+ p->errc = errc;
+ va_start(args, fmt);
+ vsprintf(p->err, fmt, args);
+ va_end(args);
+
+ /* If this is the first registered error */
+ if (p->ferrc != 0) {
+ p->ferrc = p->errc;
+ strcpy(p->ferr, p->err);
+ }
+
+ return errc;
+}
+
+/* Define methods */
+
+/* Return error code and message */
+/* for the first error, if any error */
+/* has occured since object creation. */
+static int cgats_error(
+cgats *p,
+char **mes
+) {
+ if (p->ferrc != 0) {
+ if (mes != NULL)
+ *mes = p->ferr;
+ return p->ferrc;
+ }
+ return 0;
+}
+
+/* ------------------------------------------- */
+
+/* Free the cgats object */
+static void
+cgats_del(cgats *p) {
+ int i;
+ cgatsAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ /* Free all the user defined file identifiers */
+ if (p->cgats_type != NULL) {
+ al->free(al, p->cgats_type);
+ }
+
+ if (p->others != NULL) {
+ for (i = 0; i < p->nothers; i++)
+ if(p->others[i] != NULL)
+ al->free(al, p->others[i]);
+ al->free(al, p->others);
+ }
+
+ /* Free contents of all the tables */
+ for (i = 0; i < p->ntables; i++)
+ cgats_table_free(&p->t[i]);
+
+ /* Free the table structures */
+ if (p->t != NULL)
+ al->free(al, p->t);
+
+ al->free(al, p);
+
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+}
+
+/* Free up the contents of a cgats_table struct */
+static void
+cgats_table_free(cgats_table *t) {
+ cgatsAlloc *al = t->al;
+ int i,j;
+
+ /* Free all the keyword symbols */
+ if (t->ksym != NULL) {
+ for (i = 0; i < t->nkwords; i++)
+ if(t->ksym[i] != NULL)
+ al->free(al, t->ksym[i]);
+ al->free(al, t->ksym);
+ }
+ /* Free all the keyword values */
+ if (t->kdata != NULL) {
+ for (i = 0; i < t->nkwords; i++)
+ if(t->kdata[i] != NULL)
+ al->free(al, t->kdata[i]);
+ al->free(al, t->kdata);
+ }
+ /* Free all the keyword comments */
+ if (t->kcom != NULL) {
+ for (i = 0; i < t->nkwords; i++)
+ if(t->kcom[i] != NULL)
+ al->free(al, t->kcom[i]);
+ al->free(al, t->kcom);
+ }
+
+ /* Free all the field symbols */
+ if (t->fsym != NULL) {
+ for (i = 0; i < t->nfields; i++)
+ if(t->fsym[i] != NULL)
+ al->free(al, t->fsym[i]);
+ al->free(al, t->fsym);
+ }
+ /* Free array of field types */
+ if (t->ftype != NULL)
+ al->free(al, t->ftype);
+ /* Free all the original fields text values */
+ if (t->rfdata != NULL) {
+ for (j = 0; j < t->nsets; j++)
+ if (t->rfdata[j] != NULL) {
+ for (i = 0; i < t->nfields; i++)
+ if(t->rfdata[j][i] != NULL)
+ al->free(al, t->rfdata[j][i]);
+ al->free(al, t->rfdata[j]);
+ }
+ al->free(al, t->rfdata);
+ }
+ /* Free all the fields values */
+ if (t->fdata != NULL) {
+ for (j = 0; j < t->nsets; j++)
+ if (t->fdata[j] != NULL) {
+ for (i = 0; i < t->nfields; i++)
+ if(t->fdata[j][i] != NULL)
+ al->free(al, t->fdata[j][i]);
+ al->free(al, t->fdata[j]);
+ }
+ al->free(al, t->fdata);
+ }
+}
+
+/* Return index of the keyword, -1 on fail */
+/* -2 on illegal table index, message in err & errc */
+static int
+find_kword(cgats *p, int table, const char *ksym) {
+ int i;
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+
+ if (table < 0 || table >= p->ntables)
+ return err(p, -2, "cgats.find_kword(), table number '%d' is out of range",table);
+ t = &p->t[table];
+
+ if (ksym == NULL || ksym[0] == '\000')
+ return -1;
+
+ for (i = 0; i < t->nkwords; i ++) {
+ if (t->ksym[i] != NULL && t->kdata[i] != NULL
+ && strcmp(t->ksym[i],ksym) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+/* Return index of the field, -1 on fail */
+/* -2 on illegal table index, message in err & errc */
+static int
+find_field(cgats *p, int table, const char *fsym) {
+ int i;
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+
+ if (table < 0 || table >= p->ntables)
+ return err(p, -2, "cgats.find_field(), table number '%d' is out of range",table);
+ t = &p->t[table];
+
+ if (fsym == NULL || fsym[0] == '\000')
+ return -1;
+
+ for (i = 0; i < t->nfields; i ++)
+ if (strcmp(t->fsym[i],fsym) == 0)
+ return i;
+
+ return -1;
+}
+
+/* Read a cgats file into structure */
+/* returns 0 normally, -ve if there was an error, */
+/* and p->errc and p->err will be valid */
+static int
+cgats_read(cgats *p, cgatsFile *fp) {
+ parse *pp;
+/* Read states */
+#define R_IDENT 0 /* Reading file identifier */
+#define R_KWORDS 1 /* Reading keywords */
+#define R_KWORD_VALUE 2 /* Reading keywords values */
+#define R_FIELDS 3 /* Reading field declarations */
+#define R_DATA 4 /* Reading data in set */
+ int rstate = R_IDENT;
+ int tablef = 0; /* Current table we should be filling */
+ int expsets = 0; /* Expected number of sets */
+ char *kw = NULL; /* keyword symbol */
+
+ p->errc = 0;
+ p->err[0] = '\000';
+
+ if ((pp = new_parse_al(p->al, fp)) == NULL) {
+ DBGF((DBGA,"Failed to open parser for file\n"));
+ return err(p, -1, "Unable to create file parser for file '%s'",fp->fname(fp));
+ }
+
+ /* Setup our token parsing charaters */
+ /* Terminators, Not Read, Comment start, Quote characters */
+ pp->add_del(pp, " \t"," \t", "#", "\"");
+
+ /* Read in the file */
+ for (;;) {
+ char *tp; /* Token string */
+
+ /* Fetch the next token */
+ while ((tp = pp->get_token(pp)) == NULL) {
+ int rc;
+ if (pp->errc != 0) { /* get_token got an error */
+ err(p, -1, "%s", pp->err);
+ pp->del(pp);
+ DBGF((DBGA,"Get token got error '%s'\n",pp->err));
+ return p->errc;
+ }
+ if ((rc = pp->read_line(pp)) == 0)
+ break; /* End of file */
+ else if (rc == -1) { /* read_line got an error */
+ err(p, -1, "%s", pp->err);
+ pp->del(pp);
+ DBGF((DBGA,"Read line got error '%s'\n",pp->err));
+ return p->errc;
+ }
+ }
+ if (tp == NULL)
+ break; /* EOF */
+
+ switch(rstate) {
+ case R_IDENT: /* Expecting file identifier */
+ case R_KWORDS: { /* Expecting keyword, field def or data */
+ table_type tt = tt_none;
+ int oi = 0; /* Index if tt_other */
+
+ DBGF((DBGA,"Got kword '%s'\n",tp));
+ if (rstate == R_IDENT) {
+ DBGF((DBGA,"Expecting file identifier\n"));
+ }
+
+ /* The standard says that keywords have to be at the start of a line */
+ if (pp->token != 1) /* Be robust and ignore any problems */
+ break;
+
+ /* See if we have a file identifier */
+ if(strcmp(tp,"IT8.7/1") == 0)
+ tt = it8_7_1;
+ else if(strcmp(tp,"IT8.7/2") == 0)
+ tt = it8_7_2;
+ else if(strcmp(tp,"IT8.7/3") == 0)
+ tt = it8_7_3;
+ else if(strcmp(tp,"IT8.7/4") == 0)
+ tt = it8_7_4;
+ else if(strcmp(tp,"CGATS.5") == 0)
+ tt = cgats_5;
+ else if(strncmp(tp,"CGATS.",6) == 0) { /* Variable CGATS type */
+ tt = cgats_X;
+ if (p->cgats_type != NULL)
+ p->al->free(p->al, p->cgats_type);
+ if ((p->cgats_type = (char *)p->al->malloc(p->al,
+ (strlen(tp)+1) * sizeof(char))) == NULL) {
+ err(p,-1,"Failed to malloc space for CGATS.X keyword");
+ pp->del(pp);
+ return p->errc;
+ }
+ strcpy(p->cgats_type,tp);
+ DBGF((DBGA,"Found CGATS file identifier\n"));
+ rstate = R_KWORDS;
+ } else { /* See if it is an 'other' file identifier */
+ int iswild = 0;
+ DBGF((DBGA,"Checking for 'other' identifier\n"));
+
+ /* Check for non-wildcard "other" */
+ for (oi = 0; oi < p->nothers; oi++) {
+
+ if (p->others[oi][0] == '\000') { /* Wild card */
+ iswild = 1;
+ continue;
+ }
+ /* If "other" is a specific string */
+ if(strcmp(tp,p->others[oi]) == 0) {
+ DBGF((DBGA,"Matches 'other' %s\n",p->others[oi]));
+ tt = tt_other;
+ rstate = R_KWORDS;
+ break;
+ }
+ }
+
+ if (tt == tt_none
+ && iswild
+ && rstate == R_IDENT /* First token after a table */
+ && standard_kword(tp) == 0 /* And not an obvious kword */
+ && reserved_kword(tp) == 0) {
+ DBGF((DBGA,"Matches 'other' wildcard\n"));
+ if ((oi = add_other(p, tp)) == -2) {
+ pp->del(pp);
+ DBGF((DBGA,"add_other for wilidcard failed\n"));
+ return p->errc;
+ }
+ tt = tt_other;
+ rstate = R_KWORDS;
+ }
+ }
+
+ /* First ever token must be file identifier */
+ if (tt == tt_none && p->ntables == 0) {
+ err(p,-1,"Error at line %d of file '%s': No CGATS file identifier found",pp->line,fp->fname(fp));
+ pp->del(pp);
+ DBGF((DBGA,"Failed to match file identifier\n"));
+ return p->errc;
+ }
+
+ /* Any token after previous table has data finished */
+ /* causes a new table to be created. */
+ if (p->ntables == tablef) {
+
+ if (tt != tt_none) { /* Current token is a file identifier */
+ DBGF((DBGA,"Got file identifier, adding plain table\n"));
+ if (add_table(p, tt, oi) < 0) {
+ pp->del(pp);
+ DBGF((DBGA,"Add table failed\n"));
+ return p->errc;
+ }
+ } else { /* Carry everything over from previous table the table type */
+ int i;
+ cgats_table *pt;
+ int ct;
+
+ DBGF((DBGA,"No file identifier, adding table copy of previous\n"));
+
+ if (add_table(p, p->t[p->ntables-1].tt, p->t[p->ntables-1].oi) < 0) {
+ pp->del(pp);
+ DBGF((DBGA,"Add table failed\n"));
+ return p->errc;
+ }
+
+ pt = &p->t[p->ntables-2];
+ ct = p->ntables-1;
+
+ for (i = 0; i < pt->nkwords; i++) {
+ if (p->add_kword(p, ct, pt->ksym[i], pt->kdata[i], pt->kcom[i]) < 0) {
+ pp->del(pp);
+ DBGF((DBGA,"Add keyword failed\n"));
+ return p->errc;
+ }
+ }
+ for (i = 0; i < pt->nfields; i++)
+ if (p->add_field(p, ct, pt->fsym[i], none_t) < 0) {
+ pp->del(pp);
+ DBGF((DBGA,"Add field failed\n"));
+ return p->errc;
+ }
+ }
+ }
+
+ /* If not a file identifier */
+ if (tt == tt_none) {
+ /* See if we're starting the field declarations */
+ if(strcmp(tp,"BEGIN_DATA_FORMAT") == 0) {
+ rstate = R_FIELDS;
+ if (clear_fields(p, p->ntables-1) < 0) {
+ pp->del(pp);
+ DBGF((DBGA,"Clear field failed\n"));
+ return p->errc;
+ }
+ break;
+ }
+ if(strcmp(tp,"SAMPLE_ID") == 0) { /* Faulty table - cope gracefully */
+ rstate = R_FIELDS;
+ if (clear_fields(p, p->ntables-1) < 0) {
+ pp->del(pp);
+ DBGF((DBGA,"Clear field failed\n"));
+ return p->errc;
+ }
+ goto first_field;
+ }
+
+ if(strcmp(tp,"BEGIN_DATA") == 0) {
+ rstate = R_DATA;
+ break;
+ }
+ /* Else must be a keyword */
+ if ((kw = (char *)alloc_copy_data_type(p->al, cs_t, (void *)tp)) == NULL) {
+ err(p, -2, "cgats.alloc_copy_data_type() malloc fail");
+ pp->del(pp);
+ DBGF((DBGA,"Alloc data type failed\n"));
+ return p->errc;
+ }
+ rstate = R_KWORD_VALUE;
+ }
+ break;
+ }
+ case R_KWORD_VALUE: {
+ /* Add a keyword and its value */
+
+ DBGF((DBGA,"Got keyword value '%s'\n",kw));
+
+ /* Special case for read() use */
+ if(strcmp(kw,"NUMBER_OF_SETS") == 0)
+ expsets = atoi(tp);
+
+ if (!reserved_kword(kw)) { /* Don't add reserved keywords */
+ int ix;
+
+ /* Replace keyword if it already exists */
+ unquote_cs(tp);
+ if ((ix = find_kword(p, p->ntables-1, kw)) < -1) {
+ pp->del(pp);
+ DBGF((DBGA,"Failed to find keyword\n"));
+ return p->errc;
+ }
+ if (add_kword_at(p, p->ntables-1, ix, kw, tp, NULL) < 0) {
+ pp->del(pp);
+ DBGF((DBGA,"Failed to add keyword '%s'\n",kw));
+ return p->errc;
+ }
+ }
+ p->al->free(p->al, kw);
+ rstate = R_KWORDS;
+ break;
+ }
+ case R_FIELDS: {
+ DBGF((DBGA,"Got fields value '%s'\n",tp));
+
+ /* Add a list of field name declarations */
+ if(strcmp(tp,"END_DATA_FORMAT") == 0) {
+ rstate = R_KWORDS;
+ break;
+ }
+ if(strcmp(tp,"BEGIN_DATA") == 0) { /* Faulty table - cope gracefully */
+ rstate = R_DATA;
+ break;
+ }
+ if(strcmp(tp,"DEVICE_NAME") == 0) { /* Faulty CB table - cope gracefully */
+ /* It's unlikely anyone will use DEVICE_NAME as a field name */
+ /* Assume this is a keyword */
+ if ((kw = (char *)alloc_copy_data_type(p->al, cs_t, (void *)tp)) == NULL) {
+ err(p, -2, "cgats.alloc_copy_data_type() malloc fail");
+ pp->del(pp);
+ DBGF((DBGA,"Alloc data type failed\n"));
+ return p->errc;
+ }
+ rstate = R_KWORD_VALUE;
+ break;
+ }
+ first_field:; /* Direct leap - cope with faulty table */
+ if (p->add_field(p, p->ntables-1, tp, none_t) < 0) /* none == cs untill figure type */ {
+ pp->del(pp);
+ DBGF((DBGA,"Add field failed\n"));
+ return p->errc;
+ }
+ break;
+ }
+ case R_DATA: {
+ cgats_table *ct = &p->t[p->ntables-1];
+
+ DBGF((DBGA,"Got data value '%s'\n",tp));
+ if(strcmp(tp,"END_DATA") == 0) {
+ int i,j;
+#ifdef NEVER
+ if (ct->nsets == 0) {
+ err(p,-1,"Error at line %d of file '%s': End of data without any data being read",pp->line,fp->fname(fp));
+ pp->del(pp);
+ DBGF((DBGA,"End of data without any data being read\n"));
+ return p->errc;
+ }
+#endif // NEVER
+ if (expsets != 0 && ct->nsets != expsets) {
+ err(p,-1,"Error at line %d of file '%s': Read %d sets, expected %d sets",pp->line,fp->fname(fp),ct->nsets,expsets);
+ pp->del(pp);
+ DBGF((DBGA,"End of mimatch in number of sets\n"));
+ return p->errc;
+ }
+ if (ct->ndf != 0) {
+ err(p,-1,"Error at line %d of file '%s': Data was not an integer multiple of fields (remainder %d out of %d)",pp->line,fp->fname(fp),ct->ndf,ct->nfields);
+ pp->del(pp);
+ DBGF((DBGA,"Not an interger multiple of fields\n"));
+ return p->errc;
+ }
+
+ /* We now need to determine the data types */
+ /* and convert them appropriately */
+ for (i = 0; i < ct->nfields; i++) {
+ data_type bt = i_t, st;
+ for (j = 0; j < ct->nsets; j++) {
+ data_type ty;
+ ty = guess_type(((char *)ct->rfdata[j][i]));
+ if (ty == cs_t) {
+ bt = cs_t;
+ break; /* Early out */
+ } else if (ty == nqcs_t) {
+ if (bt == i_t || bt == r_t)
+ bt = ty;
+ } else if (ty == r_t) {
+ if (bt == i_t)
+ bt = ty;
+ } else { /* ty == i_t */
+ bt = ty;
+ }
+ }
+ /* Got guessed type bt. Sanity check against known field types */
+ /* and promote if that seems reasonable */
+ st = standard_field(ct->fsym[i]);
+ if ((st == r_t && bt == i_t) /* If ambiguous, use standard field */
+ || ((st == cs_t || st == nqcs_t) && bt == i_t) /* Promote any to string */
+ || ((st == cs_t || st == nqcs_t) && bt == r_t) /* Promote any to string */
+ || (st == nqcs_t && bt == cs_t)
+ || (st == cs_t && bt == nqcs_t))
+ bt = st;
+
+ /* If standard type doesn't match what it should, throw an error */
+ if (st != none_t && st != bt) {
+ err(p, -1,"Error in file '%s': Field '%s' has unexpected type, should be '%s', is '%s'",fp->fname(fp),ct->fsym[i],data_type_desc[st],data_type_desc[bt]);
+ pp->del(pp);
+ DBGF((DBGA,"Standard field has unexpected data type\n"));
+ return p->errc;
+ }
+
+ /* Set field type, and then convert the fields to correct type. */
+ ct->ftype[i] = bt;
+ for (j = 0; j < ct->nsets; j++) {
+ switch(bt) {
+ case r_t: {
+ double dv;
+ dv = atof((char *)ct->rfdata[j][i]);
+ if ((ct->fdata[j][i] = alloc_copy_data_type(p->al, bt, (void *)&dv)) == NULL) {
+ err(p, -2, "cgats.alloc_copy_data_type() malloc fail");
+ pp->del(pp);
+ DBGF((DBGA,"Alloc copy data type failed\n"));
+ return p->errc;
+ }
+ break;
+ }
+ case i_t: {
+ int iv;
+ iv = atoi((char *)ct->rfdata[j][i]);
+ if ((ct->fdata[j][i] = alloc_copy_data_type(p->al, bt, (void *)&iv)) == NULL) {
+ err(p, -2, "cgats.alloc_copy_data_type() malloc fail");
+ pp->del(pp);
+ DBGF((DBGA,"Alloc copy data type failed\n"));
+ return p->errc = -2;
+ }
+ break;
+ }
+ case cs_t:
+ case nqcs_t: {
+ char *cv;
+ cv = ct->rfdata[j][i];
+ if ((ct->fdata[j][i]
+= alloc_copy_data_type(p->al, bt, (void *)cv)) == NULL) {
+ err(p, -2, "cgats.alloc_copy_data_type() malloc fail");
+ pp->del(pp);
+ DBGF((DBGA,"Alloc copy data type failed\n"));
+ return p->errc = -2;
+ }
+ unquote_cs((char *)ct->fdata[j][i]);
+ break;
+ }
+ case none_t:
+ break;
+ }
+ }
+ }
+
+ tablef = p->ntables; /* Finished data for current table */
+ rstate = R_IDENT;
+ break;
+ }
+
+ /* Make sure fields have been decalared */
+ if (ct->nfields == 0) {
+ err(p, -1,"Error at line %d of file '%s': Found data without field definitions",pp->line,fp->fname(fp));
+ pp->del(pp);
+ DBGF((DBGA,"Found data without field definition\n"));
+ return p->errc;
+ }
+ /* Add the data item */
+ if (add_data_item(p, p->ntables-1, tp) < 0) {
+ pp->del(pp);
+ DBGF((DBGA,"Adding data item failed\n"));
+ return p->errc;
+ }
+ break;
+ }
+ }
+ }
+
+ pp->del(pp); /* Clean up the parse file */
+ return 0;
+}
+
+/* Define the (one) variable CGATS type */
+/* Return -2 & set errc and err on system error */
+static int
+set_cgats_type(cgats *p, const char *osym) {
+ cgatsAlloc *al = p->al;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (p->cgats_type != NULL)
+ al->free(al, p->cgats_type);
+ if ((p->cgats_type = (char *)al->malloc(al, (strlen(osym)+1) * sizeof(char))) == NULL)
+ return err(p,-2,"cgats.add_cgats_type(), malloc failed!");
+ strcpy(p->cgats_type,osym);
+ return 0;
+}
+
+/* Add an 'other' file identifier string, and return the oi. */
+/* Use a zero length string to indicate a wildcard. */
+/* Return -2 & set errc and err on system error */
+static int
+add_other(cgats *p, const char *osym) {
+ cgatsAlloc *al = p->al;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ p->nothers++;
+ if ((p->others = (char **)al->realloc(al, p->others, p->nothers * sizeof(char *))) == NULL)
+ return err(p,-2, "cgats.add_other(), realloc failed!");
+ if ((p->others[p->nothers-1] =
+ (char *)al->malloc(al, (strlen(osym)+1) * sizeof(char))) == NULL)
+ return err(p,-2,"cgats.add_other(), malloc failed!");
+ strcpy(p->others[p->nothers-1],osym);
+ return p->nothers-1;
+}
+
+/* Return the oi of the given other type */
+/* return -ve and errc and err set on error */
+static int get_oi(cgats *p, const char *osym) {
+ int oi;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+
+ for (oi = 0; oi < p->nothers; oi++) {
+ if (strcmp(p->others[oi], osym) == 0)
+ return oi;
+ }
+ return err(p,-1,"cgats.get_oi(), failed to find '%s'!",osym);
+}
+
+/* Add a new (empty) table to the structure */
+/* Return the index of the table. */
+/* tt defines the table type, and oi is used if tt = tt_other */
+/* Return -2 & set errc and err on system error */
+static int
+add_table(cgats *p, table_type tt, int oi) {
+ cgatsAlloc *al = p->al;
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ p->ntables++;
+ if ((p->t = (cgats_table *) al->realloc(al, p->t, p->ntables * sizeof(cgats_table))) == NULL)
+ return err(p,-2, "cgats.add_table(), realloc failed!");
+ memset(&p->t[p->ntables-1],0,sizeof(cgats_table));
+ t = &p->t[p->ntables-1];
+
+ t->al = al; /* Pointer to allocator */
+ t->tt = tt;
+ t->oi = oi;
+
+ return p->ntables-1;
+}
+
+/* set or reset table flags */
+/* The sup_id flag suppreses the writing of the file identifier string for the table */
+/* The sup_kwords flag suppreses the writing of the standard keyword definitions for the table */
+/* The sup_fields flag suppreses the writing of the field definitions for the table */
+/* The assumption is that the previous tables id and/or fields will be correct for */
+/* the table that have these flags set. */
+/* Return -1 & set errc and err on error */
+static int set_table_flags(cgats *p, int table, int sup_id, int sup_kwords, int sup_fields) {
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables)
+ return err(p,-1, "cgats.set_table_flags(), table number '%d' is out of range",table);
+ t = &p->t[table];
+
+ if (sup_id == 0 && (sup_kwords != 0 || sup_fields != 0))
+ return err(p,-1, "cgats.set_table_flags(), Can't suppress kwords or fields if ID is not suppressed");
+ t->sup_id = sup_id;
+ t->sup_kwords = sup_kwords;
+ t->sup_fields = sup_fields;
+
+ return 0;
+}
+
+
+/* Append a new keyword/value + optional comment pair to the table */
+/* If no comment is provided, kcom should be set to NULL */
+/* A comment only line can be inserted amongst the keywords by providing */
+/* NULL values for ksym and kdata, and the comment in kcom */
+/* Return the index of the new keyword, or -1, err & errc on error */
+static int
+add_kword(cgats *p, int table, const char *ksym, const char *kdata, const char *kcom) {
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables)
+ return err(p,-1, "cgats.add_kword(), table number '%d' is out of range",table);
+ t = &p->t[table];
+
+ return add_kword_at(p, table, t->nkwords, ksym, kdata, kcom);
+}
+
+/* Replace or append a new keyword/value pair + optional comment */
+/* to the table in the given position. The keyword will be appended */
+/* if it is < 0. */
+/* If no comment is provided, kcom should be set to NULL */
+/* A comment only line can be inserted amongst the keywords by providing */
+/* NULL values for ksym and kdata, and the comment in kcom */
+/* Return the index of the keyword, or -1, err & errc on error */
+static int
+add_kword_at(cgats *p, int table, int pos, const char *ksym, const char *kdata, const char *kcom) {
+ cgatsAlloc *al = p->al;
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables) {
+ DBGF((DBGA,"add_kword_at: table is invalid\n"));
+ return err(p,-1, "cgats.add_kword(), table number '%d' is out of range",table);
+ }
+ t = &p->t[table];
+
+ if (ksym != NULL && cs_has_ws(ksym)) { /* oops */
+ DBGF((DBGA,"add_kword_at: keyword '%s' is illegal (embedded white space, quote or comment character)\n",ksym));
+ return err(p,-1, "cgats.add_kword(), keyword '%s'is illegal",ksym);
+ }
+
+ if (ksym != NULL && reserved_kword(ksym)) { /* oops */
+ DBGF((DBGA,"add_kword_at: keyword '%s' is illegal (reserved)\n",ksym));
+ return err(p,-1, "cgats.add_kword(), keyword '%s'is generated automatically",ksym);
+ }
+
+ if (pos < 0 || pos >= t->nkwords) { /* This is an append */
+ t->nkwords++;
+ if (t->nkwords > t->nkwordsa) { /* Allocate keyword pointers in groups of 8 */
+ t->nkwordsa += 8;
+ if ((t->ksym = (char **)al->realloc(al, t->ksym, t->nkwordsa * sizeof(char *))) == NULL)
+ return err(p,-2, "cgats.add_kword(), realloc failed!");
+ if ((t->kdata = (char **)al->realloc(al, t->kdata, t->nkwordsa * sizeof(char *)))
+ == NULL)
+ return err(p,-2, "cgats.add_kword(), realloc failed!");
+ if ((t->kcom = (char **)al->realloc(al, t->kcom, t->nkwordsa * sizeof(char *)))
+ == NULL)
+ return err(p,-2, "cgats.add_kword(), realloc failed!");
+ }
+ pos = t->nkwords-1;
+ } else { /* This is a replacement */
+ if (t->ksym[pos] != NULL)
+ al->free(al, t->ksym[pos]);
+ if (t->kdata[pos] != NULL)
+ al->free(al, t->kdata[pos]);
+ if (t->kcom[pos] != NULL)
+ al->free(al, t->kcom[pos]);
+ }
+
+ if (ksym != NULL) {
+ if ((t->ksym[pos] = (char *)alloc_copy_data_type(al, cs_t, (void *)ksym)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ } else
+ t->ksym[pos] = NULL;
+
+ if (kdata != NULL) {
+ if ((t->kdata[pos] = (char *)alloc_copy_data_type(al, cs_t, (void *)kdata)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ } else
+ t->kdata[pos] = NULL;
+
+ if (kcom != NULL) {
+ if ((t->kcom[pos] = (char *)alloc_copy_data_type(al, cs_t, (void *)kcom)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ } else
+ t->kcom[pos] = NULL;
+ return pos;
+}
+
+/* Add a new field to the table */
+/* Return the index of the field */
+/* return -1 or -2, errc & err on error */
+static int
+add_field(cgats *p, int table, const char *fsym, data_type ftype) {
+ cgatsAlloc *al = p->al;
+ cgats_table *t;
+ data_type st;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables)
+ return err(p,-1,"cgats.add_field(), table parameter out of range");
+ t = &p->t[table];
+
+ if (t->nsets != 0)
+ return err(p,-1,"cgats.add_field(), attempt to add field to non-empty table");
+
+ /* Check the field name is reasonable */
+ if (cs_has_ws(fsym))
+ return err(p,-1,"cgats.add_kword(), field name '%s'is illegal",fsym);
+
+ if (ftype == none_t)
+ ftype = cs_t; /* Fudge - unknown type yet, used for reads */
+ else {
+ /* Check that the data type is reasonable */
+ st = standard_field(fsym);
+ if (st == nqcs_t && ftype == cs_t) /* Fudge - standard type to non-quoted if normal */
+ ftype = nqcs_t;
+ if (st != none_t && st != ftype)
+ return err(p,-1,"cgats.add_field(): unexpected data type for standard field name");
+ }
+
+ t->nfields++;
+ if (t->nfields > t->nfieldsa) {
+ /* Allocate fields in groups of 4 */
+ t->nfieldsa += 4;
+ if ((t->fsym = (char **)al->realloc(al, t->fsym, t->nfieldsa * sizeof(char *))) == NULL)
+ return err(p,-2,"cgats.add_field(), realloc failed!");
+ if ((t->ftype = (data_type *)al->realloc(al, t->ftype, t->nfieldsa * sizeof(data_type)))
+ == NULL)
+ return err(p,-2,"cgats.add_field(), realloc failed!");
+ }
+ if ((t->fsym[t->nfields-1] = (char *)alloc_copy_data_type(al, cs_t, (void *)fsym)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ t->ftype[t->nfields-1] = ftype;
+
+ return t->nfields-1;
+}
+
+/* Clear all fields in the table */
+/* return 0 if OK */
+/* return -1 or -2, errc & err on error */
+static int
+clear_fields(cgats *p, int table) {
+ cgatsAlloc *al = p->al;
+ int i;
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables)
+ return err(p,-1,"cgats.clear_field(), table parameter out of range");
+ t = &p->t[table];
+
+ if (t->nsets != 0)
+ return err(p,-1,"cgats.clear_field(), attempt to clear fields in a non-empty table");
+
+ /* Free all the field symbols */
+ if (t->fsym != NULL) {
+ for (i = 0; i < t->nfields; i++)
+ if(t->fsym[i] != NULL)
+ al->free(al, t->fsym[i]);
+ al->free(al, t->fsym);
+ t->fsym = NULL;
+ }
+
+ /* Free array of field types */
+ if (t->ftype != NULL)
+ al->free(al, t->ftype);
+ t->ftype = NULL;
+
+ /* Zero all the field counters */
+ t->nfields = 0;
+ t->nfieldsa = 0;
+
+ return 0;
+}
+
+/* Add a set of data */
+/* return 0 normally. */
+/* return -2, -1, errc & err on error */
+static int
+add_set(cgats *p, int table, ...) {
+ cgatsAlloc *al = p->al;
+ va_list args;
+ int i;
+ cgats_table *t;
+
+ va_start(args, table);
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables)
+ return err(p,-1,"cgats.add_kword(), table parameter out of range");
+ t = &p->t[table];
+
+ if (t->nfields == 0)
+ return err(p,-1,"cgats.add_set(), attempt to add set when no fields are defined");
+
+ t->nsets++;
+
+ if (t->nsets > t->nsetsa) /* Allocate space for more sets */ {
+ /* Allocate set pointers in groups of 100 */
+ t->nsetsa += 100;
+ if ((t->fdata = (void ***)al->realloc(al, t->fdata, t->nsetsa * sizeof(void **))) == NULL)
+ return err(p,-2,"cgats.add_set(), realloc failed!");
+ }
+ /* Allocate set pointer to data element values */
+ if ((t->fdata[t->nsets-1] = (void **)al->malloc(al, t->nfields * sizeof(void *))) == NULL)
+ return err(p,-2,"cgats.add_set(), malloc failed!");
+
+ /* Allocate and copy data to new set */
+ for (i = 0; i < t->nfields; i++) {
+ switch(t->ftype[i]) {
+ case r_t: {
+ double dv;
+ dv = va_arg(args, double);
+ if ((t->fdata[t->nsets-1][i] = alloc_copy_data_type(al, t->ftype[i], (void *)&dv)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ break;
+ }
+ case i_t: {
+ int iv;
+ iv = va_arg(args, int);
+ if ((t->fdata[t->nsets-1][i] = alloc_copy_data_type(al, t->ftype[i], (void *)&iv)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ break;
+ }
+ case cs_t:
+ case nqcs_t: {
+ char *sv;
+ sv = va_arg(args, char *);
+ if ((t->fdata[t->nsets-1][i] = alloc_copy_data_type(al, t->ftype[i], (void *)sv)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ break;
+ }
+ default:
+ return err(p,-1,"cgats.add_set(), field has unknown data type");
+ }
+ }
+ va_end(args);
+
+ return 0;
+}
+
+/* Add a set of data from void array */
+/* (Courtesy of Neil Okamoto) */
+/* return 0 normally. */
+/* return -2, -1, errc & err on error */
+static int
+add_setarr(cgats *p, int table, cgats_set_elem *args) {
+ cgatsAlloc *al = p->al;
+ int i;
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables)
+ return err(p,-1,"cgats.add_setarr(), table parameter out of range");
+ t = &p->t[table];
+
+ if (t->nfields == 0)
+ return err(p,-1,"cgats.add_setarr(), attempt to add set when no fields are defined");
+
+ t->nsets++;
+
+ if (t->nsets > t->nsetsa) /* Allocate space for more sets */ {
+ /* Allocate set pointers in groups of 100 */
+ t->nsetsa += 100;
+ if ((t->fdata = (void ***)al->realloc(al,t->fdata, t->nsetsa * sizeof(void **))) == NULL)
+ return err(p,-2,"cgats.add_set(), realloc failed!");
+ }
+ /* Allocate set pointer to data element values */
+ if ((t->fdata[t->nsets-1] = (void **)al->malloc(al,t->nfields * sizeof(void *))) == NULL)
+ return err(p,-2,"cgats.add_set(), malloc failed!");
+
+ /* Allocate and copy data to new set */
+ for (i = 0; i < t->nfields; i++) {
+ switch(t->ftype[i]) {
+ case r_t: {
+ double dv;
+ dv = args[i].d;
+ if ((t->fdata[t->nsets-1][i] = alloc_copy_data_type(al, t->ftype[i], (void *)&dv)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ break;
+ }
+ case i_t: {
+ int iv;
+ iv = args[i].i;
+ if ((t->fdata[t->nsets-1][i] = alloc_copy_data_type(al, t->ftype[i], (void *)&iv)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ break;
+ }
+ case cs_t:
+ case nqcs_t: {
+ char *sv;
+ sv = args[i].c;
+ if ((t->fdata[t->nsets-1][i] = alloc_copy_data_type(al, t->ftype[i], (void *)sv)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+ break;
+ }
+ default:
+ return err(p,-1,"cgats.add_set(), field has unknown data type");
+ }
+ }
+ return 0;
+}
+
+/* Fill a suitable set_element with a set of data. */
+/* Note a returned char pointer is to a string in *p */
+/* return 0 normally. */
+/* return -2, -1, errc & err on error */
+static int
+get_setarr(cgats *p, int table, int set_index, cgats_set_elem *args) {
+ int i;
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables)
+ return err(p,-1,"cgats.get_setarr(), table parameter out of range");
+ t = &p->t[table];
+ if (set_index < 0 || set_index >= t->nsets)
+ return err(p,-1,"cgats.get_setarr(), set parameter out of range");
+
+ for (i = 0; i < t->nfields; i++) {
+ switch(t->ftype[i]) {
+ case r_t:
+ args[i].d = *((double *)t->fdata[set_index][i]);
+ break;
+ case i_t:
+ args[i].i = *((int *)t->fdata[set_index][i]);
+ break;
+ case cs_t:
+ case nqcs_t:
+ args[i].c = ((char *)t->fdata[set_index][i]);
+ break;
+ default:
+ return err(p,-1,"cgats.get_setarr(), field has unknown data type");
+ }
+ }
+ return 0;
+}
+
+/* Add an item of data to rgdata[][] from the read file. */
+/* return 0 normally. */
+/* return -2, -1, errc & err on error */
+static int
+add_data_item(cgats *p, int table, void *data) {
+ cgatsAlloc *al = p->al;
+ cgats_table *t;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+ if (table < 0 || table >= p->ntables)
+ return err(p,-1,"cgats.add_kword(), table parameter out of range");
+ t = &p->t[table];
+
+ if (t->nfields == 0)
+ return err(p,-1,"cgats.add_item(), attempt to add data when no fields are defined");
+
+ if (t->ndf == 0) { /* We're about to do the first element of a new set */
+ t->nsets++;
+
+ if (t->nsets > t->nsetsa) { /* Allocate space for more sets */
+ /* Allocate set pointers in groups of 100 */
+ t->nsetsa += 100;
+ if ((t->rfdata = (char ***)al->realloc(al, t->rfdata, t->nsetsa * sizeof(void **)))
+ == NULL)
+ return err(p,-2,"cgats.add_item(), realloc failed!");
+ if ((t->fdata = (void ***)al->realloc(al, t->fdata, t->nsetsa * sizeof(void **)))
+ == NULL)
+ return err(p,-2,"cgats.add_item(), realloc failed!");
+ }
+ /* Allocate set pointer to data element values */
+ if ((t->rfdata[t->nsets-1] = (char **)al->malloc(al, t->nfields * sizeof(void *))) == NULL)
+ return err(p,-2,"cgats.add_item(), malloc failed!");
+ if ((t->fdata[t->nsets-1] = (void **)al->malloc(al, t->nfields * sizeof(void *))) == NULL)
+ return err(p,-2,"cgats.add_item(), malloc failed!");
+ }
+
+ /* Data type is always cs_t at this point, because we haven't decided the type */
+ if ((t->rfdata[t->nsets-1][t->ndf] = alloc_copy_data_type(al, cs_t, data)) == NULL)
+ return err(p,-2,"cgats.alloc_copy_data_type() malloc fail");
+
+ if (++t->ndf >= t->nfields)
+ t->ndf = 0;
+
+ return 0;
+}
+
+/* Write structure into cgats file */
+/* Return -ve, errc & err if there was an error */
+static int
+cgats_write(cgats *p, cgatsFile *fp) {
+ cgatsAlloc *al = p->al;
+ int i;
+ int table,set,field;
+ int *sfield = NULL; /* Standard field flag */
+ p->errc = 0;
+ p->err[0] = '\000';
+
+ DBGF((DBGA,"CGATS write called, ntables = %d\n",p->ntables));
+ for (table = 0; table < p->ntables; table++) {
+ cgats_table *t = &p->t[table];
+
+ DBGF((DBGA,"CGATS writing table %d\n",table));
+
+ /* Figure out the standard and non-standard fields */
+ if (t->nfields > 0)
+ if ((sfield = (int *)al->malloc(al, t->nfields * sizeof(int))) == NULL)
+ return err(p,-2,"cgats.write(), malloc failed!");
+ for (field = 0; field < t->nfields; field++) {
+ if (standard_field(t->fsym[field]) != none_t)
+ sfield[field] = 1; /* Is standard */
+ else
+ sfield[field] = 0;
+ }
+
+ if (!t->sup_kwords) /* If not suppressed */ {
+ /* Make sure table has basic keywords */
+ if ((i = p->find_kword(p,table,"ORIGINATOR")) < 0) /* Create it */
+ if (p->add_kword(p,table,"ORIGINATOR","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ if ((i = p->find_kword(p,table,"DESCRIPTOR")) < 0) /* Create it */
+ if (p->add_kword(p,table,"DESCRIPTOR","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ if ((i = p->find_kword(p,table,"CREATED")) < 0) { /* Create it */
+ static char *amonths[] = {"January","February","March","April",
+ "May","June","July","August","September",
+ "October","November","December"};
+ time_t ctime;
+ struct tm *ptm;
+ char tcs[100];
+ ctime = time(NULL);
+ ptm = localtime(&ctime);
+ sprintf(tcs,"%s %d, %d",amonths[ptm->tm_mon],ptm->tm_mday,1900+ptm->tm_year);
+ if (p->add_kword(p,table,"CREATED",tcs, NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ }
+
+ /* And table type specific keywords */
+ /* (Not sure this is correct - CGATS.5 appendix J is not specific enough) */
+ switch(t->tt) {
+ case it8_7_1:
+ case it8_7_2: /* Physical target reference files */
+ if ((i = p->find_kword(p,table,"MANUFACTURER")) < 0) /* Create it */
+ if (p->add_kword(p,table,"MANUFACTURER","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ if ((i = p->find_kword(p,table,"PROD_DATE")) < 0) /* Create it */
+ if (p->add_kword(p,table,"PROD_DATE","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ if ((i = p->find_kword(p,table,"SERIAL")) < 0) /* Create it */
+ if (p->add_kword(p,table,"SERIAL","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ if ((i = p->find_kword(p,table,"MATERIAL")) < 0) /* Create it */
+ if (p->add_kword(p,table,"MATERIAL","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ break;
+ case it8_7_3: /* Target measurement files */
+ case it8_7_4:
+ case cgats_5:
+ case cgats_X:
+ if ((i = p->find_kword(p,table,"INSTRUMENTATION")) < 0) /* Create it */
+ if (p->add_kword(p,table,"INSTRUMENTATION","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ if ((i = p->find_kword(p,table,"MEASUREMENT_SOURCE")) < 0) /* Create it */
+ if (p->add_kword(p,table,"MEASUREMENT_SOURCE","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ if ((i = p->find_kword(p,table,"PRINT_CONDITIONS")) < 0) /* Create it */
+ if (p->add_kword(p,table,"PRINT_CONDITIONS","Not specified", NULL) < 0) {
+ al->free(al, sfield);
+ return p->errc;
+ }
+ break;
+ case tt_other:
+ /* We enforce no pre-defined keywords for user defined file types */
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Output the table */
+
+ /* First the table identifier */
+ if (!t->sup_id) /* If not suppressed */ {
+ switch(t->tt) {
+ case it8_7_1:
+ if (fp->gprintf(fp,"IT8.7/1\n\n") < 0)
+ goto write_error;
+ break;
+ case it8_7_2:
+ if (fp->gprintf(fp,"IT8.7/2\n\n") < 0)
+ goto write_error;
+ break;
+ case it8_7_3:
+ if (fp->gprintf(fp,"IT8.7/3\n\n") < 0)
+ goto write_error;
+ break;
+ case it8_7_4:
+ if (fp->gprintf(fp,"IT8.7/4\n\n") < 0)
+ goto write_error;
+ break;
+ case cgats_5:
+ if (fp->gprintf(fp,"CGATS.5\n\n") < 0)
+ goto write_error;
+ break;
+ case cgats_X: /* variable CGATS type */
+ if (p->cgats_type == NULL)
+ goto write_error;
+ if (fp->gprintf(fp,"%-7s\n\n", p->cgats_type) < 0)
+ goto write_error;
+ break;
+ case tt_other: /* User defined file identifier */
+ if (fp->gprintf(fp,"%-7s\n\n",p->others[t->oi]) < 0)
+ goto write_error;
+ break;
+ case tt_none:
+ break;
+ }
+ } else { /* At least space the next table out a bit */
+ if (table == 0) {
+ al->free(al, sfield);
+ return err(p,-1,"cgats_write(), ID should not be suppressed on first table");
+ }
+ if (t->tt != p->t[table-1].tt || (t->tt == tt_other && t->oi != p->t[table-1].oi)) {
+ al->free(al, sfield);
+ return err(p,-1,"cgats_write(), ID should not be suppressed when table %d type is not the same as previous table",table);
+ }
+ if (fp->gprintf(fp,"\n\n") < 0)
+ goto write_error;
+ }
+
+ /* Then all the keywords */
+ for (i = 0; i < t->nkwords; i++) {
+ char *qs = NULL;
+
+ DBGF((DBGA,"CGATS writing keyword %d\n",i));
+
+ /* Keyword and data if it is present */
+ if (t->ksym[i] != NULL && t->kdata[i] != NULL) {
+ if (!standard_kword(t->ksym[i])) { /* Do the right thing */
+ if ((qs = quote_cs(al, t->ksym[i])) == NULL) {
+ al->free(al, sfield);
+ return err(p,-2,"quote_cs() malloc failed!");
+ }
+ if (fp->gprintf(fp,"KEYWORD %s\n",qs) < 0) {
+ al->free(al, qs);
+ goto write_error;
+ }
+ al->free(al, qs);
+ }
+
+ if ((qs = quote_cs(al, t->kdata[i])) == NULL) {
+ al->free(al, sfield);
+ return err(p,-2,"quote_cs() malloc failed!");
+ }
+ if (fp->gprintf(fp,"%s %s%s",t->ksym[i],qs,
+ t->kcom[i] == NULL ? "\n":"\t") < 0) {
+ al->free(al, qs);
+ goto write_error;
+ }
+ al->free(al, qs);
+ }
+ /* Comment if its present */
+ if (t->kcom[i] != NULL) {
+ if (fp->gprintf(fp,"# %s\n",t->kcom[i]) < 0) {
+ al->free(al, qs);
+ goto write_error;
+ }
+ }
+ }
+
+ /* Then the field specification */
+ if (!t->sup_fields) { /* If not suppressed */
+ if (fp->gprintf(fp,"\n") < 0)
+ goto write_error;
+
+ /* Declare any non-standard fields */
+ for (field = 0; field < t->nfields; field++) {
+ if (!sfield[field]) /* Non-standard */ {
+ char *qs;
+ if ((qs = quote_cs(al, t->fsym[field])) == NULL) {
+ al->free(al, sfield);
+ return err(p,-2,"quote_cs() malloc failed!");
+ }
+ if (fp->gprintf(fp,"KEYWORD %s\n",qs) < 0) {
+ al->free(al, qs);
+ goto write_error;
+ }
+ al->free(al, qs);
+ }
+ }
+
+ if (fp->gprintf(fp,"NUMBER_OF_FIELDS %d\n",t->nfields) < 0)
+ goto write_error;
+ if (fp->gprintf(fp,"BEGIN_DATA_FORMAT\n") < 0)
+ goto write_error;
+ for (field = 0; field < t->nfields; field ++) {
+ DBGF((DBGA,"CGATS writing field %d\n",field));
+ if (fp->gprintf(fp,"%s ",t->fsym[field]) < 0)
+ goto write_error;
+ }
+ if (fp->gprintf(fp,"\nEND_DATA_FORMAT\n") < 0)
+ goto write_error;
+ } else { /* Check that it is safe to suppress fields */
+ cgats_table *pt = &p->t[table-1];
+ if (table == 0) {
+ al->free(al, sfield);
+ return err(p,-1,"cgats_write(), Fields should not be suppressed on first table");
+ }
+ if (t->nfields != pt->nfields) {
+ al->free(al, sfield);
+ return err(p,-1,"cgats_write(), Fields should not be suppressed when table %d different number than previous table",table);
+ }
+ for (field = 0; field < t->nfields; field ++)
+ if (strcmp(t->fsym[field],pt->fsym[field]) != 0
+ || t->ftype[field] != pt->ftype[field]) {
+ al->free(al, sfield);
+ return err(p,-1,"cgats_write(), Fields should not be suppressed when table %d types is not the same as previous table",table);
+ }
+ }
+
+ /* Then the actual data */
+ if (fp->gprintf(fp,"\nNUMBER_OF_SETS %d\n",t->nsets) < 0)
+ goto write_error;
+ if (fp->gprintf(fp,"BEGIN_DATA\n") < 0)
+ goto write_error;
+ for (set = 0; set < t->nsets; set++) {
+ DBGF((DBGA,"CGATS writing set %d\n",set));
+ for (field = 0; field < t->nfields; field++) {
+ data_type tt;
+ if (t->ftype[field] == r_t) {
+ char fmt[30];
+ double val = *((double *)t->fdata[set][field]);
+ real_format(val, REAL_SIGDIG, fmt);
+ strcat(fmt," ");
+ if (fp->gprintf(fp,fmt,val) < 0)
+ goto write_error;
+ } else if (t->ftype[field] == i_t) {
+ if (fp->gprintf(fp,"%d ",*((int *)t->fdata[set][field])) < 0)
+ goto write_error;
+ } else if (t->ftype[field] == nqcs_t
+ && !cs_has_ws((char *)t->fdata[set][field])
+ && (sfield[field] || (tt = guess_type((char *)t->fdata[set][field]),
+ tt != i_t && tt != r_t))) {
+ /* We can only print a non-quote string if it doesn't contain white space, */
+ /* quote or comment characters, and if it is a standard field or */
+ /* can't be mistaken for a number. */
+ if (fp->gprintf(fp,"%s ",(char *)t->fdata[set][field]) < 0)
+ goto write_error;
+ } else if (t->ftype[field] == nqcs_t
+ || t->ftype[field] == cs_t) {
+ char *qs;
+ if ((qs = quote_cs(al, (char *)t->fdata[set][field])) == NULL) {
+ al->free(al, sfield);
+ return err(p,-2,"quote_cs() malloc failed!");
+ }
+ if (fp->gprintf(fp,"%s ",qs) < 0) {
+ al->free(al, qs);
+ goto write_error;
+ }
+ al->free(al, qs);
+ } else {
+ al->free(al, sfield);
+ return err(p,-1,"cgats_write(), illegal data type found");
+ }
+ }
+ if (fp->gprintf(fp,"\n") < 0)
+ goto write_error;
+ }
+ if (fp->gprintf(fp,"END_DATA\n") < 0)
+ goto write_error;
+
+ if (sfield != NULL)
+ al->free(al, sfield);
+ sfield = NULL;
+ }
+ return 0;
+
+write_error:
+ err(p,-1,"Write error to file '%s'",fp->fname(fp));
+ if (sfield != NULL)
+ al->free(al, sfield);
+ return p->errc;
+}
+
+/* Allocate space for data with given type, and copy it from source */
+/* Return NULL if alloc failed, or unknown data type */
+static void *
+alloc_copy_data_type(cgatsAlloc *al, data_type dtype, void *dpoint) {
+ switch(dtype) {
+ case r_t: { /* Real value */
+ double *p;
+ if ((p = (double *)al->malloc(al, sizeof(double))) == NULL)
+ return NULL;
+ *p = *((double *)dpoint);
+ return (void *)p;
+ }
+ case i_t: { /* Integer value */
+ int *p;
+ if ((p = (int *)al->malloc(al, sizeof(int))) == NULL)
+ return NULL;
+ *p = *((int *)dpoint);
+ return (void *)p;
+ }
+ case cs_t: /* Character string */
+ case nqcs_t: { /* Character string */
+ char *p;
+ if ((p = (char *)al->malloc(al, (strlen(((char *)dpoint))+1) * sizeof(char))) == NULL)
+ return NULL;
+ strcpy(p, (char *)dpoint);
+ return (void *)p;
+ }
+ case none_t:
+ default:
+ return NULL;
+ }
+ return NULL; /* Shut the compiler up */
+}
+
+/* See if the keyword name is a standard one */
+/* Return non-zero if it is standard */
+static int
+standard_kword(const char *ksym) {
+ if (ksym == NULL)
+ return 0;
+ if (strcmp(ksym,"ORIGINATOR") == 0)
+ return 1;
+ if (strcmp(ksym,"DESCRIPTOR") == 0)
+ return 1;
+ if (strcmp(ksym,"CREATED") == 0)
+ return 1;
+ if (strcmp(ksym,"MANUFACTURER") == 0)
+ return 1;
+ if (strcmp(ksym,"PROD_DATE") == 0)
+ return 1;
+ if (strcmp(ksym,"SERIAL") == 0)
+ return 1;
+ if (strcmp(ksym,"MATERIAL") == 0)
+ return 1;
+ if (strcmp(ksym,"INSTRUMENTATION") == 0)
+ return 1;
+ if (strcmp(ksym,"MEASUREMENT_SOURCE") == 0)
+ return 1;
+ if (strcmp(ksym,"PRINT_CONDITIONS") == 0)
+ return 1;
+ return 0;
+}
+
+/* See if the keyword name is reserved. */
+/* (code generates it automatically) */
+/* Return non-zero if it is reserved */
+static int
+reserved_kword(const char *ksym) {
+ if (ksym == NULL)
+ return 0;
+ if (strcmp(ksym,"NUMBER_OF_FIELDS") == 0)
+ return 1;
+ if (strcmp(ksym,"BEGIN_DATA_FORMAT") == 0)
+ return 1;
+ if (strcmp(ksym,"END_DATA_FORMAT") == 0)
+ return 1;
+ if (strcmp(ksym,"NUMBER_OF_SETS") == 0)
+ return 1;
+ if (strcmp(ksym,"BEGIN_DATA") == 0)
+ return 1;
+ if (strcmp(ksym,"END_DATA") == 0)
+ return 1;
+ if (strcmp(ksym,"KEYWORD") == 0)
+ return 1;
+ return 0;
+}
+
+/* See if the field name is a standard one */
+/* with an expected data type */
+static data_type
+standard_field(const char *fsym) {
+ if (strcmp(fsym,"SAMPLE_ID") == 0)
+ return nqcs_t;
+ if (strcmp(fsym,"STRING") == 0)
+ return cs_t;
+ if (strncmp(fsym,"CMYK_",5) == 0) {
+ if (fsym[5] == 'C')
+ return r_t;
+ if (fsym[5] == 'M')
+ return r_t;
+ if (fsym[5] == 'Y')
+ return r_t;
+ if (fsym[5] == 'K')
+ return r_t;
+ return none_t;
+ }
+ /* Non standard, but logical */
+ if (strncmp(fsym,"CMY_",4) == 0) {
+ if (fsym[4] == 'C')
+ return r_t;
+ if (fsym[4] == 'M')
+ return r_t;
+ if (fsym[4] == 'Y')
+ return r_t;
+ return none_t;
+ }
+ if (strncmp(fsym,"D_",2) == 0) {
+ if (strcmp(fsym + 2, "RED") == 0)
+ return r_t;
+ if (strcmp(fsym + 2, "GREEN") == 0)
+ return r_t;
+ if (strcmp(fsym + 2, "BLUE") == 0)
+ return r_t;
+ if (strcmp(fsym + 2, "VIS") == 0)
+ return r_t;
+ return none_t;
+ }
+ if (strncmp(fsym,"RGB_",4) == 0) {
+ if (fsym[4] == 'R')
+ return r_t;
+ if (fsym[4] == 'G')
+ return r_t;
+ if (fsym[4] == 'B')
+ return r_t;
+ return none_t;
+ }
+ if (strncmp(fsym,"SPECTRAL_",9) == 0) {
+ if (strcmp(fsym + 9, "NM") == 0)
+ return r_t;
+ if (strcmp(fsym + 9, "PCT") == 0)
+ return r_t;
+ return none_t;
+ }
+ if (strncmp(fsym,"XYZ_",4) == 0) {
+ if (fsym[4] == 'X')
+ return r_t;
+ if (fsym[4] == 'Y')
+ return r_t;
+ if (fsym[4] == 'Z')
+ return r_t;
+ return none_t;
+ }
+ if (strncmp(fsym,"XYY_",4) == 0) {
+ if (fsym[4] == 'X')
+ return r_t;
+ if (fsym[4] == 'Y')
+ return r_t;
+ if (strcmp(fsym + 4, "CAPY") == 0)
+ return r_t;
+ return none_t;
+ }
+ if (strncmp(fsym,"LAB_",4) == 0) {
+ if (fsym[4] == 'L')
+ return r_t;
+ if (fsym[4] == 'A')
+ return r_t;
+ if (fsym[4] == 'B')
+ return r_t;
+ if (fsym[4] == 'C')
+ return r_t;
+ if (fsym[4] == 'H')
+ return r_t;
+ if (strcmp(fsym + 4, "DE") == 0)
+ return r_t;
+ return none_t;
+ }
+ if (strncmp(fsym,"STDEV_",6) == 0) {
+ if (fsym[6] == 'X')
+ return r_t;
+ if (fsym[6] == 'Y')
+ return r_t;
+ if (fsym[6] == 'Z')
+ return r_t;
+ if (fsym[6] == 'L')
+ return r_t;
+ if (fsym[6] == 'A')
+ return r_t;
+ if (fsym[6] == 'B')
+ return r_t;
+ if (strcmp(fsym + 6, "DE") == 0)
+ return r_t;
+ return none_t;
+ }
+ return none_t;
+}
+
+/* Return non-zero if char string has an embedded */
+/* white space, quote or comment character. */
+static int
+cs_has_ws(const char *cs)
+ {
+ int i;
+ for (i = 0; cs[i] != '\000'; i++)
+ {
+ switch (cs[i])
+ {
+ case ' ':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '"':
+ case '#':
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+/* Return a string with quotes added */
+/* Return NULL if malloc failed */
+/* (Returned string should be free()'d after use) */
+static char *
+quote_cs(cgatsAlloc *al, const char *cs) {
+ int i,j;
+ char *rs;
+ /* see how much space we need for returned string */
+ for (i = 0, j = 3; cs[i] != '\000'; i++, j++)
+ if (cs[i] == '"')
+ j++;
+ if ((rs = (char *)al->malloc(al, j * sizeof(char))) == NULL) {
+ return NULL;
+ }
+
+ j = 0;
+ rs[j++] = '"';
+ for (i = 0; cs[i] != '\000'; i++, j++) {
+ if (cs[i] == '"')
+ rs[j++] = '"';
+ rs[j] = cs[i];
+ }
+ rs[j++] = '"';
+ rs[j] = '\000';
+ return rs;
+}
+
+/* Remove quotes from the string */
+static void
+unquote_cs(char *cs) {
+ int sl,i,j;
+ int s; /* flag - set if skipped last character */
+
+ sl = strlen(cs);
+
+ if (sl < 2 || cs[0] != '"' || cs[sl-1] != '"')
+ return;
+
+ for (i = 1, j = 0, s = 1; i < (sl-1); i++) {
+ if (s == 1 || cs[i-1] != '"' || cs[i] != '"') {
+ cs[j++] = cs[i]; /* skip second " in a row */
+ s = 0;
+ } else
+ s = 1;
+ }
+ cs[j] = '\000';
+
+ return;
+}
+
+/* Guess the data type from the string */
+static data_type
+guess_type(const char *cs)
+ {
+ int i;
+ int rf = 0;
+
+ /* See if its a quoted string */
+ if (cs[0] == '"')
+ {
+ for (i = 1;cs[i] != '\000';i++);
+ if (i >= 2 && cs[i-1] == '"')
+ return cs_t;
+ return nqcs_t;
+ }
+ /* See if its an integer or real */
+ for (i = 0;;i++)
+ {
+ char c = cs[i];
+ if (c == '\000')
+ break;
+ if (c >= '0' && c <= '9') /* Strictly numeric */
+ continue;
+ if (c == '-' && /* Allow appropriate '-' */
+ ( i == 0 ||
+ ( i > 0 && (cs[i-1] == 'e' || cs[i-1] == 'E'))))
+ continue;
+ if (c == '+' && /* Allow appropriate '+' */
+ ( i == 0 ||
+ ( i > 0 && (cs[i-1] == 'e' || cs[i-1] == 'E'))))
+ continue;
+ if (!(rf & 3) && c == '.') /* Allow one '.' before 'e' in real */
+ {
+ rf |= 1;
+ continue;
+ }
+ if (!(rf & 2) && (c == 'e' || c == 'E')) /* Allow one 'e' in real */
+ {
+ rf |= 2;
+ continue;
+ }
+ /* Not numeric or incorrect 'e' or '.' or '-' or '+' */
+ return nqcs_t;
+ }
+ if (rf)
+ return r_t;
+ return i_t;
+ }
+
+/* Set the character format to the appropriate printf() */
+/* format given the real value and the desired number of significant digits. */
+/* We try to do this while not using the %e format for normal values. */
+/* The fmt string space is assumed to be big enough to contain the format */
+static void
+real_format(double value, int nsd, char *fmt) {
+ int ndigs;
+ int tot = nsd + 1;
+ int xtot = tot;
+ if (value == 0.0) {
+ sprintf(fmt,"%%%d.%df",tot,tot-2);
+ return;
+ }
+ if (value != value) { /* Hmm. A nan */
+ sprintf(fmt,"%%f");
+ return;
+ }
+ if (value < 0.0) {
+ value = -value;
+ xtot++;
+ }
+ if (value < 1.0) {
+ ndigs = (int)(log10(value));
+ if (ndigs <= -2) {
+ sprintf(fmt,"%%%d.%de",xtot,tot-2);
+ return;
+ }
+ sprintf(fmt,"%%%d.%df",xtot-ndigs,nsd-ndigs);
+ return;
+ } else {
+ ndigs = (int)(log10(value));
+ if (ndigs >= (nsd -1))
+ {
+ sprintf(fmt,"%%%d.%de",xtot,tot-2);
+ return;
+ }
+ sprintf(fmt,"%%%d.%df",xtot,(nsd-1)-ndigs);
+ return;
+ }
+}
+
+/* ---------------------------------------------------------- */
+/* Debug and test code */
+/* ---------------------------------------------------------- */
+
+#ifdef STANDALONE_TEST
+
+/* Dump the contents of a cgats structure to the given output */
+static void
+cgats_dump(cgats *p, cgatsFile *fp) {
+ int tn;
+
+ fp->gprintf(fp,"Number of tables = %d\n",p->ntables);
+ for (tn = 0; tn < p->ntables; tn++) {
+ cgats_table *t;
+ int i,j;
+ t = &p->t[tn];
+
+
+ fp->gprintf(fp,"\nTable %d:\n",tn);
+
+ switch(t->tt) /* Table identifier */
+ {
+ case it8_7_1:
+ fp->gprintf(fp,"Identifier = 'IT8.7/1'\n");
+ break;
+ case it8_7_2:
+ fp->gprintf(fp,"Identifier = 'IT8.7/2'\n");
+ break;
+ case it8_7_3:
+ fp->gprintf(fp,"Identifier = 'IT8.7/3'\n");
+ break;
+ case it8_7_4:
+ fp->gprintf(fp,"Identifier = 'IT8.7/4'\n");
+ break;
+ case cgats_5:
+ fp->gprintf(fp,"Identifier = 'CGATS.5'\n");
+ break;
+ case cgats_X:
+ fp->gprintf(fp,"Identifier = '%s'\n",p->cgats_type);
+ break;
+ case tt_other: /* User defined file identifier */
+ fp->gprintf(fp,"Identifier = '%s'\n",p->others[t->oi]);
+ break;
+ default:
+ fp->gprintf(fp,"**ILLEGAL**\n");
+ break;
+ }
+
+ fp->gprintf(fp,"\nNumber of keywords = %d\n",t->nkwords);
+
+ /* Dump all the keyword symbols and values */
+ for (i = 0; i < t->nkwords; i++) {
+ if (t->ksym[i] != NULL && t->kdata[i] != NULL)
+ {
+ if (t->kcom[i] != NULL)
+ fp->gprintf(fp,"Keyword '%s' has value '%s' and comment '%s'\n",
+ t->ksym[i],t->kdata[i],t->kcom[i]);
+ else
+ fp->gprintf(fp,"Keyword '%s' has value '%s'\n",t->ksym[i],t->kdata[i]);
+ }
+ if (t->kcom[i] != NULL)
+ fp->gprintf(fp,"Comment '%s'\n",t->kcom[i]);
+ }
+
+ fp->gprintf(fp,"\nNumber of field defs = %d\n",t->nfields);
+
+ /* Dump all the field symbols */
+ for (i = 0; i < t->nfields; i++) {
+ char *fname;
+ switch(t->ftype[i]) {
+ case r_t:
+ fname = "real";
+ break;
+ case i_t:
+ fname = "integer";
+ break;
+ case cs_t:
+ fname = "character string";
+ break;
+ case nqcs_t:
+ fname = "non-quoted char string";
+ break;
+ default:
+ fname = "illegal";
+ break;
+ }
+ fp->gprintf(fp,"Field '%s' has type '%s'\n",t->fsym[i],fname);
+ }
+
+ fp->gprintf(fp,"\nNumber of sets = %d\n",t->nsets);
+
+ /* Dump all the set values */
+ for (j = 0; j < t->nsets; j++) {
+ for (i = 0; i < t->nfields; i++) {
+ switch(t->ftype[i]) {
+ case r_t: {
+ char fmt[30];
+ double val = *((double *)t->fdata[j][i]);
+ fmt[0] = ' ';
+ real_format(val, REAL_SIGDIG, fmt+1);
+ fp->gprintf(fp,fmt,*((double *)t->fdata[j][i]));
+ break;
+ }
+ case i_t:
+ fp->gprintf(fp," %d",*((int *)t->fdata[j][i]));
+ break;
+ case cs_t:
+ case nqcs_t:
+ fp->gprintf(fp," %s",((char *)t->fdata[j][i]));
+ break;
+ default:
+ fp->gprintf(fp," illegal");
+ break;
+ }
+ }
+ fp->gprintf(fp,"\n");
+ }
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ char *fn;
+ cgatsFile *fp;
+ cgats *pp;
+
+ if (argc == 1) {
+ /* Write test */
+ pp = new_cgats(); /* Create a CGATS structure */
+
+ if (pp->add_table(pp, cgats_5, 0) < 0 /* Start the first table */
+ || pp->add_kword(pp, 0, NULL, NULL, "Comment only test comment") < 0
+ || pp->add_kword(pp, 0, "TEST_KEY_WORD", "try this out", "Keyword comment") < 0
+ || pp->add_kword(pp, 0, "TEST_KEY_WORD2", "try this\" out \"\" huh !", NULL) < 0
+
+ || pp->add_field(pp, 0, "SAMPLE_ID", cs_t) < 0
+ || pp->add_field(pp, 0, "SAMPLE_LOC", nqcs_t) < 0
+ || pp->add_field(pp, 0, "XYZ_X", r_t) < 0)
+ error("Initial error: '%s'",pp->err);
+
+ if (pp->add_set(pp, 0, "1", "A1", 0.000012345678) < 0
+ || pp->add_set(pp, 0, "2", "A2", 0.00012345678) < 0
+ || pp->add_set(pp, 0, "3 ", "A#5",0.0012345678) < 0
+ || pp->add_set(pp, 0, "4", "A5", 0.012345678) < 0
+ || pp->add_set(pp, 0, "5", "A5", 0.12345678) < 0
+ || pp->add_set(pp, 0, "5", "A5", 0.00000000) < 0
+ || pp->add_set(pp, 0, "6", "A5", 1.2345678) < 0
+ || pp->add_set(pp, 0, "7", "A5", 12.345678) < 0
+ || pp->add_set(pp, 0, "8", "A5", 123.45678) < 0
+ || pp->add_set(pp, 0, "9", "A5", 1234.5678) < 0
+ || pp->add_set(pp, 0, "10", "A5", 12345.678) < 0
+ || pp->add_set(pp, 0, "12", "A5", 123456.78) < 0
+ || pp->add_set(pp, 0, "13", "A5", 1234567.8) < 0
+ || pp->add_set(pp, 0, "14", "A5", 12345678.0) < 0
+ || pp->add_set(pp, 0, "15", "A5", 123456780.0) < 0
+ || pp->add_set(pp, 0, "16", "A5", 1234567800.0) < 0
+ || pp->add_set(pp, 0, "17", "A5", 12345678000.0) < 0
+ || pp->add_set(pp, 0, "18", "A5", 123456780000.0) < 0)
+ error("Adding set error '%s'",pp->err);
+
+ if (pp->add_table(pp, cgats_5, 0) < 0 /* Start the second table */
+ || pp->set_table_flags(pp, 1, 1, 1, 1) < 0 /* Suppress id, kwords and fields */
+ || pp->add_kword(pp, 1, NULL, NULL, "Second Comment only test comment") < 0)
+ error("Adding table error '%s'",pp->err);
+
+ if (pp->add_field(pp, 1, "SAMPLE_ID", cs_t) < 0 /* Need to define fields same as table 0 */
+ || pp->add_field(pp, 1, "SAMPLE_LOC", nqcs_t) < 0
+ || pp->add_field(pp, 1, "XYZ_X", r_t) < 0)
+ error("Adding field error '%s'",pp->err);
+
+ if (pp->add_set(pp, 1, "4", "A4", -0.000012345678) < 0
+ || pp->add_set(pp, 1, "5", "A5", -0.00012345678) < 0
+ || pp->add_set(pp, 1, "6", "A5", -0.0012345678) < 0
+ || pp->add_set(pp, 1, "7", "A5", -0.012345678) < 0
+ || pp->add_set(pp, 1, "8", "A5", -0.12345678) < 0
+ || pp->add_set(pp, 1, "9", "A5", -1.2345678) < 0
+ || pp->add_set(pp, 1, "10", "A5", -12.345678) < 0
+ || pp->add_set(pp, 1, "11", "A5", -123.45678) < 0
+ || pp->add_set(pp, 1, "12", "A5", -1234.5678) < 0
+ || pp->add_set(pp, 1, "13", "A5", -12345.678) < 0
+ || pp->add_set(pp, 1, "14", "A5", -123456.78) < 0
+ || pp->add_set(pp, 1, "15", "A5", -1234567.8) < 0
+ || pp->add_set(pp, 1, "16", "A5", -12345678.0) < 0
+ || pp->add_set(pp, 1, "17", "A5", -123456780.0) < 0
+ || pp->add_set(pp, 1, "18", "A5", -1234567800.0) < 0
+ || pp->add_set(pp, 1, "19", "A5", -12345678000.0) < 0
+ || pp->add_set(pp, 1, "20", "A5", -123456780000.0) < 0)
+ error("Adding set 2 error '%s'",pp->err);
+
+ if ((fp = new_cgatsFileStd_name("fred.it8", "w")) == NULL)
+ error("Error opening '%s' for writing","fred.it8");
+
+ if (pp->write(pp, fp))
+ error("Write error : %s",pp->err);
+
+ fp->del(fp); /* Close file */
+ pp->del(pp); /* Clean up */
+ }
+
+ /* Read test */
+ pp = new_cgats(); /* Create a CGATS structure */
+
+ /* Setup to cope with Argyll files */
+ if (pp->add_other(pp, "CTI1") == -2
+ || pp->add_other(pp, "CTI2") == -2
+ || pp->add_other(pp, "CTI3") == -2)
+ error("Adding other error '%s'",pp->err);
+
+ /* Setup to cope with colorblind files */
+ if (pp->add_other(pp, "CBSC") == -2
+ || pp->add_other(pp, "CBTA") == -2
+ || pp->add_other(pp, "CBPR") == -2)
+ error("Adding other 2 error '%s'",pp->err);
+
+ if (argc == 2)
+ fn = argv[1];
+ else
+ fn = "fred.it8";
+
+ if ((fp = new_cgatsFileStd_name(fn, "r")) == NULL)
+ error("Error opening '%s' for reading",fn);
+ if (pp->read(pp, fp))
+ error("Read error : %s",pp->err);
+ fp->del(fp); /* Close file */
+
+ if ((fp = new_cgatsFileStd_fp(stdout)) == NULL)
+ error("Error opening stdout");
+ cgats_dump(pp, fp);
+ fp->del(fp); /* delete file object */
+
+ pp->del(pp); /* Clean up */
+ return 0;
+}
+
+
+/* Basic printf type error() and warning() routines */
+
+void
+error(const char *fmt, ...) {
+ va_list args;
+
+ fprintf(stderr,"cgats: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(const char *fmt, ...) {
+ va_list args;
+
+ fprintf(stderr,"cgats: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#endif /* STANDALONE_TEST */
+/* ---------------------------------------------------------- */
diff --git a/cgats/cgats.h b/cgats/cgats.h
new file mode 100644
index 0000000..2a6b1fd
--- /dev/null
+++ b/cgats/cgats.h
@@ -0,0 +1,180 @@
+#ifndef CGATS_H
+
+/*
+ * Committee for Graphics Arts Technologies Standards
+ * CGATS.5 and IT8.7 family file I/O class
+ * Version 2.05
+ *
+ * Author: Graeme W. Gill
+ * Date: 20/12/95
+ *
+ * Copyright 1995, 1996, 2002, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/* Version of cgatslib release */
+
+#define CGATSLIB_VERSION 0x020005
+#define CGATSLIB_VERSION_STR "2.05"
+
+#define CGATS_ERRM_LENGTH 200
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "pars.h" /* We use the ASCII parsing class */
+
+/* Possible table types */
+typedef enum { it8_7_1, it8_7_2, it8_7_3, it8_7_4, cgats_5, cgats_X, tt_other, tt_none } table_type;
+
+/* Possible data types - real, integer, char string, non-quoted char string, no value */
+typedef enum { r_t, i_t, cs_t, nqcs_t, none_t } data_type;
+
+union _cgats_set_elem {
+ int i;
+ double d;
+ char *c;
+}; typedef union _cgats_set_elem cgats_set_elem;
+
+struct _cgats_table {
+ cgatsAlloc *al; /* Copy of parent memory allocator */
+ table_type tt; /* Table type */
+ int oi; /* other type index */
+
+ /* Read only */
+ int nkwords; /* Number of keywords */
+ int nfields; /* Number of fields of data */
+ int nsets; /* Number of data sets */
+
+ char **ksym; /* Pointer to [nkwords] array of pointers to keyword symbols */
+ char **kdata; /* Pointer to [nkwords] array of pointers to keyword values */
+
+ char **fsym; /* Pointer to [nfields] array of pointers to field symbols */
+ data_type *ftype; /* Pointer to [nfields] array of field types */
+ char ***rfdata; /* Pointer to [nsets] array of pointers */
+ /* to [nfields] array of pointers to read file field text values */
+ void ***fdata; /* Pointer to [nsets] array of pointers */
+ /* to [nfields] array of pointers to field set values of ftype */
+ /* Private */
+ int nkwordsa; /* Number of keywords allocated */
+ int nfieldsa; /* Number of fields allocated */
+ int nsetsa; /* Number of sets allocated */
+ char **kcom; /* Pointer to [nkwords] array of pointers to keyword comments */
+ int ndf; /* Next data field - used by add_data_item() */
+ int sup_id; /* Set to non-zero if table ID output is to be suppressed */
+ int sup_kwords; /* Set to non-zero if table default keyword output is to be suppressed */
+ int sup_fields; /* Set to non-zero if table field output is to be suppressed */
+}; typedef struct _cgats_table cgats_table;
+
+struct _cgats {
+ /* Private */
+ cgatsAlloc *al; /* Memory allocator */
+ int del_al; /* Flag to indicate we al->del() */
+
+ /* Read only Variables */
+ int ntables; /* Number of tables */
+
+ cgats_table *t; /* Pointer to an array of ntable table structures */
+
+ /* Undefined CGATS table type */
+ char *cgats_type;
+
+ /* User defined table types */
+ int nothers; /* Number of other identifiers */
+ char **others; /* Other file type identifiers */
+
+ /* Public Methods */
+ int (*set_cgats_type)(struct _cgats *p, const char *osym);
+ /* Define the (one) variable CGATS type */
+ /* Return -2, set errc & err on system error */
+
+ int (*add_other)(struct _cgats *p, const char *osym);
+ /* Add a user defined file identifier string. */
+ /* Use a zero length string for wildcard. */
+ /* Return the oi */
+ /* Return -2, set errc & err on system error */
+
+ int (*get_oi)(struct _cgats *p, const char *osym);
+ /* Return the oi of the given other type */
+ /* return -ve and errc and err set on error */
+
+ int (*read)(struct _cgats *p, cgatsFile *fp); /* Read a cgats file into structure */
+ /* return -ve and errc and err set on error */
+
+ /* NULL if SEPARATE_STD is defined: */
+ int (*read_name)(struct _cgats *p, const char *filename); /* Standard file I/O */
+ /* return -ve and errc and err set on error */
+
+ int (*find_kword)(struct _cgats *p, int table, const char *ksym);
+ /* Return index of the keyword, -1 on fail */
+ /* -2 on illegal table index, errc & err */
+ int (*find_field)(struct _cgats *p, int table, const char *fsym);
+ /* Return index of the field, -1 on fail */
+ /* -2 on illegal table index, errc & err */
+
+ int (*add_table)(struct _cgats *p, table_type tt, int oi);
+ /* Add a new (empty) table to the structure */
+ /* Return the index of the table */
+ /* Return -2, set errc & err on system error */
+ /* if tt is tt_other, io sets the other index */
+ int (*set_table_flags)(struct _cgats *p, int table, int sup_id,int sup_kwords,int sup_fields);
+ /* Set or reset table output suppresion flags */
+ /* Return -ve, set errc & err on error */
+ int (*add_kword)(struct _cgats *p, int table, const char *ksym, const char *kdata, const char *kcom);
+ /* Add a new keyword/value pair + optional comment to the table */
+ /* Return index of new keyword, or -1, errc & err on error */
+ int (*add_field)(struct _cgats *p, int table, const char *fsym, data_type ftype);
+ /* Add a new field to the table */
+ /* Return index of new field, or -1, -2, errc and err on error */
+ int (*add_set)(struct _cgats *p, int table, ...); /* Add a set of data */
+ /* Return 0 normally, -1, -2, errc & err if error */
+ int (*add_setarr)(struct _cgats *p, int table, cgats_set_elem *ary); /* Add data from array */
+ /* Return 0 normally, -1, -2, errc & err if error */
+ int (*write)(struct _cgats *p, cgatsFile *fp); /* Write structure into cgats file */
+ /* return -ve and errc and err set on error */
+
+ int (*get_setarr)(struct _cgats *p, int table, int set_index, cgats_set_elem *ary);
+ /* Fill a suitable set_element with a line of data */
+ /* Return 0 normally, -1, -2, errc & err if error */
+ /* NULL if SEPARATE_STD is defined: */
+ int (*write_name)(struct _cgats *p, const char *filename); /* Standard file I/O */
+ /* return -ve and errc and err set on error */
+
+
+ int (*error)(struct _cgats *p, char **mes); /* Return error code and message */
+ /* for the first error, if any error */
+ /* has occured since object creation. */
+ void (*del)(struct _cgats *p); /* Delete the object */
+
+ char err[CGATS_ERRM_LENGTH]; /* Error message */
+ int errc; /* Error code */
+ char ferr[CGATS_ERRM_LENGTH]; /* First error message */
+ int ferrc; /* First error code */
+}; typedef struct _cgats cgats;
+
+/* Creator */
+extern cgats *new_cgats_al(cgatsAlloc *al); /* with allocator object */
+
+#ifdef COMBINED_STD
+#define CGATS_STATIC static
+#else
+#define CGATS_STATIC
+#endif
+
+/* Available if SEPARATE_STD is not defined */
+extern cgats *new_cgats(void); /* Standard allocator */
+
+/* Available from cgatsstd.obj SEPARATE_STD is defined: */
+CGATS_STATIC int cgats_read_name(cgats *p, const char *filename);
+CGATS_STATIC int cgats_write_name(cgats *p, const char *filename);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define CGATS_H
+#endif /* CGATS_H */
diff --git a/cgats/cgatsstd.c b/cgats/cgatsstd.c
new file mode 100644
index 0000000..d8fbb34
--- /dev/null
+++ b/cgats/cgatsstd.c
@@ -0,0 +1,111 @@
+
+/*
+ * cgats library stdio and malloc utility classes.
+ * Version 2.05
+ *
+ * Author: Graeme W. Gill
+ * Date: 2002/10/24
+ *
+ * Copyright 2002, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ *
+ * These are kept in a separate file to allow them to be
+ * selectively ommitted from the cgats library.
+ *
+ */
+
+#ifndef COMBINED_STD
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "cgats.h"
+
+#ifdef NEVER /* Not sure if this is needed with some combinations */
+
+/* Implimentation function - register an error */
+/* Return the error number */
+/* [Note that this is a duplicate of the one in cgats.c] */
+static int
+err(cgats *p, int errc, const char *fmt, ...) {
+ va_list args;
+
+ p->errc = errc;
+ va_start(args, fmt);
+ vsprintf(p->err, fmt, args);
+ va_end(args);
+
+ /* If this is the first registered error */
+ if (p->ferrc != 0) {
+ p->ferrc = p->errc;
+ strcpy(p->ferr, p->err);
+ }
+
+ return errc;
+}
+
+#endif /* NEVER */
+
+#endif /* !COMBINED_STD */
+
+#if defined(SEPARATE_STD) || defined(COMBINED_STD)
+
+/* Create an empty cgats object, default standard allocator */
+cgats *new_cgats(void) {
+ cgats *p;
+ cgatsAlloc *al; /* memory allocator */
+
+ if ((al = new_cgatsAllocStd()) == NULL)
+ return NULL;
+
+ if ((p = new_cgats_al(al)) == NULL) {
+ al->del(al);
+ return NULL;
+ }
+
+ p->del_al = 1; /* Get cgets->del to cleanup allocator */
+ return p;
+}
+
+/* Read a cgats file into structure */
+/* Return non-zero if there was an error */
+/* and set p->errc * p->err */
+CGATS_STATIC
+int
+cgats_read_name(cgats *p, const char *filename) {
+ int rv;
+ cgatsFile *fp;
+
+ p->errc = 0;
+ p->err[0] = '\000';
+
+ if ((fp = new_cgatsFileStd_name(filename, "r")) == NULL)
+ return err(p,-1,"Unable to open file '%s' for reading",filename);
+ rv = p->read(p, fp);
+ fp->del(fp);
+
+ return rv;
+}
+
+/* Write a cgats file into structure */
+/* Return -ve, errc & err if there was an error */
+CGATS_STATIC
+int
+cgats_write_name(cgats *p, const char *filename) {
+ int rv;
+ cgatsFile *fp;
+
+ if ((fp = new_cgatsFileStd_name(filename, "w")) == NULL)
+ return err(p,-1,"Unable to open file '%s' for writing",filename);
+ rv = p->write(p, fp);
+ fp->del(fp);
+
+ return rv;
+}
+
+#endif /* defined(SEPARATE_STD) || defined(COMBINED_STD) */
diff --git a/cgats/makezip.ksh b/cgats/makezip.ksh
new file mode 100644
index 0000000..8cc5f6c
--- /dev/null
+++ b/cgats/makezip.ksh
@@ -0,0 +1,2 @@
+rm cgatslib.zip
+zip -9 -ll cgatslib.zip Readme.txt Licence.txt afiles cgats.c cgats.h pars.c pars.h parsstd.c cgatsstd.c Jamfile Makefile Makefile.WNT Makefile.IBMNT Makefile.UNIX Makefile.OSX
diff --git a/cgats/pars.c b/cgats/pars.c
new file mode 100644
index 0000000..606957c
--- /dev/null
+++ b/cgats/pars.c
@@ -0,0 +1,642 @@
+
+/*
+ * Simple ASCII file parsing object.
+ * Used as a base for the CGATS.5 and IT8.7 family file I/O class
+ * Version 2.05
+ *
+ * Author: Graeme W. Gill
+ * Date: 20/12/95
+ *
+ * Copyright 1996, 2002 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+#define _PARS_C_ /* Turn on implimentation code */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <time.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+
+#ifdef _MSC_VER
+#define vsnprintf _vsnprintf
+#define snprintf _snprintf
+#endif
+
+#ifdef STANDALONE_TEST
+extern void error(const char *fmt, ...), warning(const char *fmt, ...);
+#endif
+
+#include "pars.h"
+
+static void del_parse(parse *p);
+static int read_line(parse *p);
+static void reset_del(parse *p);
+static void add_del(struct _parse *p, char *t,
+ char *nr, char *c, char *q);
+static char *get_token(parse *p);
+
+/* Open the file, allocate and initialize the parse structure */
+/* Return pointer to parse structure. Return NULL on error */
+parse *
+new_parse_al(
+cgatsAlloc *al, /* Allocator object */
+cgatsFile *fp /* File to read from */
+) {
+ parse *p;
+
+ if ((p = (parse *) al->calloc(al, sizeof(parse), 1)) == NULL) {
+ return NULL;
+ }
+ p->al = al; /* Heap allocator */
+
+ p->fp = fp;
+ p->b = NULL; /* Init line buffer */
+ p->bs = 0;
+ p->bo = 0;
+ p->tb = NULL; /* Init token buffer */
+ p->tbs = 0;
+ p->to = 0;
+ p->line = 0;
+ p->token = 0;
+ p->ltflag = 0;
+ p->q = 0;
+ p->errc = 0;
+ p->err[0] = '\000';
+
+ /* Reset the parsing delimiters */
+ reset_del(p);
+
+ /* Set default pointers to methods */
+ p->del = del_parse;
+ p->read_line = read_line;
+ p->reset_del = reset_del;
+ p->add_del = add_del;
+ p->get_token = get_token;
+
+ return p;
+}
+
+/* new_parse() with default malloc allocator is in parsstd.c */
+
+#ifndef SEPARATE_STD
+#define COMBINED_STD
+
+#include "parsstd.c"
+
+#undef COMBINED_STD
+#endif /* SEPARATE_STD */
+
+/* --------------------------------------------- */
+
+/* size_t versions of saturating arithmatic */
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t)(-1))
+#endif
+
+/* a * b */
+static size_t ssat_mul(size_t a, size_t b) {
+
+ if (a == 0 || b == 0)
+ return 0;
+
+ if (a > (SIZE_MAX/b))
+ return SIZE_MAX;
+ else
+ return a * b;
+}
+
+/* --------------------------------------------- */
+/* Memory image cgatsFile compatible class */
+/* Buffer is assumed to have been allocated by the given allocator, */
+/* and will be expanded on write. */
+
+/* Get the size of the file (Only valid for memory file). */
+static size_t cgatsFileMem_get_size(cgatsFile *pp) {
+ cgatsFileMem *p = (cgatsFileMem *)pp;
+
+ return p->end - p->start;
+}
+
+/* Set current position to offset. Return 0 on success, nz on failure. */
+static int cgatsFileMem_seek(
+cgatsFile *pp,
+unsigned int offset
+) {
+ cgatsFileMem *p = (cgatsFileMem *)pp;
+ unsigned char *np;
+
+ np = p->start + offset;
+ if (np < p->start || np >= p->end)
+ return 1;
+ p->cur = np;
+ return 0;
+}
+
+/* Read count items of size length. Return number of items successfully read. */
+static size_t cgatsFileMem_read(
+cgatsFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ cgatsFileMem *p = (cgatsFileMem *)pp;
+ size_t len;
+
+ len = ssat_mul(size, count);
+ if (len > (size_t)(p->end - p->cur)) { /* Too much */
+ if (size > 0)
+ count = (p->end - p->cur)/size;
+ else
+ count = 0;
+ }
+ len = size * count;
+ if (len > 0)
+ memmove(buffer, p->cur, len);
+ p->cur += len;
+ return count;
+}
+
+/* Read a character */
+static int cgatsFileMem_getch(
+cgatsFile *pp
+) {
+ cgatsFileMem *p = (cgatsFileMem *)pp;
+ int c;
+
+ if (p->cur < p->start || p->cur >= p->end)
+ return EOF;
+
+ c = (int)*p->cur;
+ p->cur++;
+
+ return c;
+}
+
+/* Expand the memory buffer file to hold up to pointer ep */
+/* Don't expand if realloc fails */
+static void cgatsFileMem_filemem_resize(cgatsFileMem *p, unsigned char *ep) {
+ size_t na, co, ce;
+ unsigned char *nstart;
+
+ /* No need to realloc */
+ if (ep <= p->aend) {
+ return;
+ }
+
+ co = p->cur - p->start; /* Current offset */
+ ce = p->end - p->start; /* Current end */
+ na = ep - p->start; /* new allocatd size */
+
+ /* Round new allocation up */
+ if (na <= 1024)
+ na += 1024;
+ else
+ na += 4096;
+
+ if ((nstart = p->al->realloc(p->al, p->start, na)) != NULL) {
+ p->start = nstart;
+ p->cur = nstart + co;
+ p->end = nstart + ce;
+ p->aend = nstart + na;
+ }
+}
+
+/* write count items of size length. Return number of items successfully written. */
+static size_t cgatsFileMem_write(
+cgatsFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ cgatsFileMem *p = (cgatsFileMem *)pp;
+ size_t len;
+
+ len = ssat_mul(size, count);
+ if (len > (size_t)(p->end - p->cur)) /* Try and expand buffer */
+ cgatsFileMem_filemem_resize(p, p->start + len);
+
+ if (len > (size_t)(p->end - p->cur)) {
+ if (size > 0)
+ count = (p->end - p->cur)/size;
+ else
+ count = 0;
+ }
+ len = size * count;
+ if (len > 0)
+ memmove(p->cur, buffer, len);
+ p->cur += len;
+ if (p->end < p->cur)
+ p->end = p->cur;
+ return count;
+}
+
+/* do a printf */
+static int cgatsFileMem_printf(
+cgatsFile *pp,
+const char *format,
+...
+) {
+ int rv;
+ va_list args;
+ cgatsFileMem *p = (cgatsFileMem *)pp;
+ int len;
+
+ va_start(args, format);
+
+ rv = 1;
+ len = 100; /* Initial allocation for printf */
+ cgatsFileMem_filemem_resize(p, p->cur + len);
+
+ /* We have to use the available printf functions to resize the buffer if needed. */
+ for (;rv != 0;) {
+ /* vsnprintf() either returns -1 if it doesn't fit, or */
+ /* returns the size-1 needed in order to fit. */
+ len = vsnprintf((char *)p->cur, (p->aend - p->cur), format, args);
+
+ if (len > -1 && ((p->cur + len +1) <= p->aend)) /* Fitted in current allocation */
+ break;
+
+ if (len > -1) /* vsnprintf returned needed size-1 */
+ len = len+2; /* (In case vsnprintf returned 1 less than it needs) */
+ else
+ len *= 2; /* We just have to guess */
+
+ /* Attempt to resize */
+ cgatsFileMem_filemem_resize(p, p->cur + len);
+
+ /* If resize failed */
+ if ((p->aend - p->cur) < len) {
+ rv = 0;
+ break;
+ }
+ }
+ if (rv != 0) {
+ /* Figure out where end of printf is */
+ len = strlen((char *)p->cur); /* Length excluding nul */
+ p->cur += len;
+ if (p->cur > p->end)
+ p->end = p->cur;
+ rv = len;
+ }
+ va_end(args);
+ return rv;
+}
+
+/* flush all write data out to secondary storage. Return nz on failure. */
+static int cgatsFileMem_flush(
+cgatsFile *pp
+) {
+ return 0;
+}
+
+/* Return the memory buffer. Error if not cgatsFileMem */
+static int cgatsFileMem_get_buf(
+cgatsFile *pp,
+unsigned char **buf,
+size_t *len
+) {
+ cgatsFileMem *p = (cgatsFileMem *)pp;
+ if (buf != NULL)
+ *buf = p->start;
+ if (len != NULL)
+ *len = p->end - p->start;
+ return 0;
+}
+
+/* return the filename */
+static char *cgatsFileMem_fname(
+cgatsFile *pp
+) {
+// cgatsFileMem *p = (cgatsFileMem *)pp;
+
+ /* Memory doesn't have a name */
+ return "**Mem**";
+}
+
+/* we're done with the file object, return nz on failure */
+static int cgatsFileMem_delete(
+cgatsFile *pp
+) {
+ cgatsFileMem *p = (cgatsFileMem *)pp;
+ cgatsAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ if (p->del_buf) /* Free the memory buffer */
+ al->free(al, p->start);
+ al->free(al, p); /* Free object */
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+ return 0;
+}
+
+/* Create a memory image file access class with allocator */
+/* Buffer is used as is. */
+cgatsFile *new_cgatsFileMem_a(
+void *base, /* Pointer to base of memory buffer */
+size_t length, /* Number of bytes in buffer */
+cgatsAlloc *al /* heap allocator */
+) {
+ cgatsFileMem *p;
+
+ if ((p = (cgatsFileMem *) al->calloc(al, 1, sizeof(cgatsFileMem))) == NULL) {
+ return NULL;
+ }
+ p->al = al; /* Heap allocator */
+ p->get_size = cgatsFileMem_get_size;
+ p->seek = cgatsFileMem_seek;
+ p->read = cgatsFileMem_read;
+ p->getch = cgatsFileMem_getch;
+ p->write = cgatsFileMem_write;
+ p->gprintf = cgatsFileMem_printf;
+ p->flush = cgatsFileMem_flush;
+ p->get_buf = cgatsFileMem_get_buf;
+ p->fname = cgatsFileMem_fname;
+ p->del = cgatsFileMem_delete;
+
+ p->start = (unsigned char *)base;
+ p->cur = p->start;
+ p->aend = p->end = p->start + length;
+
+ return (cgatsFile *)p;
+}
+
+/* Create a memory image file access class with given allocator */
+/* and delete base when cgatsFile is deleted. */
+cgatsFile *new_cgatsFileMem_ad(void *base, size_t length, cgatsAlloc *al) {
+ cgatsFile *fp;
+
+ if ((fp = new_cgatsFileMem_a(base, length, al)) != NULL) {
+ ((cgatsFileMem *)fp)->del_buf = 1;
+ }
+
+ return fp;
+}
+
+/* --------------------------------------------- */
+/* Free up the structure (doesn't close the file) */
+static void
+del_parse(parse *p) {
+ cgatsAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ if (p->b != NULL)
+ al->free(al, p->b);
+ if (p->tb != NULL)
+ al->free(al, p->tb);
+ al->free(al, p);
+
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+}
+
+
+/* Read the next line from the file into the line buffer. */
+/* Return 0 if the read fails due to reaching EOF before */
+/* putting anything in the buffer. */
+/* Return -1 if there was some other sort of failure, */
+/* and the error message in parse will be valid. */
+static int
+read_line(parse *p) {
+ int c;
+ p->bo = 0; /* Reset pointer to the start of the line buffer */
+ p->q = 0; /* Reset quoted flag */
+ p->errc = 0; /* Reset error status */
+ p->err[0] = '\000';
+ do {
+ if ((c = p->fp->getch(p->fp)) == EOF) {
+ if (p->bo == 0) { /* If there is nothing in the buffer */
+ p->line = 0;
+ return 0;
+ }
+ c = 0; /* Finish the line */
+ }
+ if (p->ltflag == 1) { /* Finished last line on '\r' */
+ p->ltflag = 0;
+ if (c == '\n') {
+ if (p->q == 0)
+ continue; /* Ignore the following '\n' */
+ else
+ p->line--; /* Undo double increment due to \n after \r */
+ }
+ /* else fall through and use character */
+ } else if (p->ltflag == 2) { /* Finished last line on comment character */
+ /* Suck up chars till the start of the next line */
+ if (c == '\r')
+ p->ltflag = 1;
+ else if (c == '\n')
+ p->ltflag = 0;
+ continue; /* Ignore characters untill we get to the end of the line */
+ }
+
+ if (c == '\r') {
+ p->line++; /* Increment line number */
+ p->ltflag = 1; /* Remember to allow 1 of '\n' before next line */
+ if (p->q == 0)
+ c = 0; /* Finish the line */
+ } else if (p->q == 0 && (p->delf[c] & PARS_COMM) != 0) { /* Hit a comment */
+ p->line++; /* Increment line number */
+ p->ltflag = 2; /* Remember to flush all chars up to end of line */
+ c = 0; /* Finish the line */
+ } else if (c == '\n') {
+ p->line++; /* Increment line number */
+ if (p->q == 0)
+ c = 0; /* Finish the the line */
+ }
+
+ /* Deal with starting/stopping a quoted section */
+ if ((p->delf[c] & PARS_QUOTE) != 0) {
+ if (p->q == 0) /* We weren't in a quoted section */
+ p->q = c; /* Start of quoted section */
+ else if (c == p->q) /* If matching quote */
+ p->q = 0; /* End quoted section */
+ }
+
+ /* Can put the character in the buffer now */
+ if (p->bo == p->bs) { /* Run out of buffer space */
+ p->bs = (p->bs + 100) * 2; /* Expand line buffer size */
+ if ((p->b = (char *) p->al->realloc(p->al, p->b, p->bs)) == NULL) {
+ sprintf(p->err,"parse.read_line(), realloc failed!");
+ return (p->errc = -1);
+ }
+ }
+ p->b[p->bo++] = c; /* Stash character away */
+ } while (c != 0); /* Null means we've done the end of the line */
+ p->to = 0; /* Reset token pointer to the start of the line buffer */
+ p->q = 0; /* Reset quoted flag */
+ return 1;
+}
+
+/* Reset the delimiter character set */
+static void
+reset_del(parse *p) {
+ int i;
+ for (i = 0; i < 256; i++)
+ p->delf[i] = 0;
+ p->delf[0] = PARS_TERM;
+}
+
+/* Add to the parsing characters */
+static void
+add_del(
+ parse *p, /* Parse structure */
+ char *t, /* Terminators */
+ char *nr, /* Not Read */
+ char *c, /* Comment start */
+ char *q) /* Quote characters */
+ {
+ int i;
+ if (t != NULL)
+ for (i = 0; t[i] != '\000'; i++)
+ p->delf[(int)t[i]] |= PARS_TERM;
+ if (nr != NULL)
+ for (i = 0; nr[i] != '\000'; i++)
+ p->delf[(int)nr[i]] |= PARS_SKIP;
+ if (c != NULL)
+ for (i = 0; c[i] != '\000'; i++)
+ p->delf[(int)c[i]] |= PARS_COMM;
+ if (q != NULL)
+ for (i = 0; q[i] != '\000'; i++)
+ p->delf[(int)q[i]] |= PARS_QUOTE;
+ }
+
+/* Using the current token delimiter table and the current line, */
+/* parse it from the current location and return a pointer to the */
+/* null terminated token. Return NULL if there is no token found */
+/* set the parse err and errc to non-zero if there was some other error */
+static char *
+get_token(parse *p) {
+ int tbo = 0; /* Token buffer offset */
+ int term = 0; /* flag to trigger token termination */
+ char c;
+
+ p->errc = 0; /* Reset error status */
+ p->err[0] = '\000';
+ if (p->b == NULL)
+ return NULL;
+ p->token++; /* Increment token number */
+ p->q = 0;
+ do {
+ if (term)
+ c = '\000'; /* end token */
+ else if ((c = p->b[p->to++]) == '\000') /* Fetch next token */
+ p->to--; /* Safety - don't pass end */
+
+ /* Deal with starting/stopping a quoted section */
+ if ((p->delf[c] & PARS_QUOTE) != 0) {
+ if (p->q == 0) /* We weren't in a quoted section */
+ p->q = c; /* Start of quoted section */
+ else if (c == p->q) /* If matching quote */
+ p->q = 0; /* End quoted section */
+ }
+
+ if (tbo == p->tbs) { /* Run out of buffer space */
+ p->tbs = (p->tbs + 100) * 2; /* Expand token buffer size */
+ if ((p->tb = (char *) p->al->realloc(p->al, p->tb, p->tbs)) == NULL) {
+ sprintf(p->err,"parse.get_token(), realloc failed!");
+ p->errc = -1;
+ return NULL;
+ }
+ }
+
+ if ((p->q != 0 && (p->q != c || (p->delf[c] & PARS_SKIP) == 0))
+ /* If quoted, store if trigger quite is not being skipped */
+ || (!(tbo == 0 && (p->delf[c] & PARS_TERM) != 0 && (p->delf[c] & PARS_SKIP) != 0)
+ /* Skip initial non-reader terminators */
+ && (p->delf[c] & PARS_SKIP) == 0)) /* Skip non-readers */
+ p->tb[tbo++] = c; /* Stash character away in token */
+
+ if (p->q == 0 /* If not quoted and if token is non-empty and we have a terminator */
+ && tbo != 0 && (p->delf[c] & PARS_TERM) != 0)
+ term = 1; /* Finish token off next time around */
+ } while (c != '\000'); /* Null means we've done the end of the token */
+ p->q = 0;
+ if (tbo <= 1) {
+ p->token = 0;
+ return NULL; /* Haven't read anything useful */
+ }
+ return p->tb;
+}
+
+/* ========================================================== */
+/* Test code */
+
+#ifdef STANDALONE_TEST
+int
+main() {
+ int rc;
+ parse *pp;
+ cgatsFile *fp;
+
+ if ((fp = new_cgatsFileStd_name("test.txt", "r")) == NULL)
+ error("Failed to open file 'test.txt'");
+
+ if ((pp = new_parse(fp)) == NULL)
+ error("Failed to create parse object with file 'test.txt'");
+
+ /* Setup our token parsing charaters */
+ pp->add_del(pp, " ,\to"," ,\t", "#", "\"");
+
+ for (;;) {
+ char *tp;
+ if ((rc = pp->read_line(pp)) == -1)
+ error("%s",pp->err);
+ if (rc == 0)
+ break;
+ printf("Line %d = '%s'\n",pp->line,pp->b);
+ do {
+ tp = pp->get_token(pp);
+ if (pp->errc != 0)
+ error("%s",pp->err);
+ if (tp != NULL)
+ printf("Token %d = '%s'\n",pp->token,tp);
+ } while (tp != NULL);
+ }
+ printf("End of File\n");
+
+ pp->del(pp); /* Clean up */
+ fp->del(fp); /* Close the file */
+
+ return 0;
+}
+
+
+/* Basic printf type error() and warning() routines for standalone test */
+void
+error(const char *fmt, ...) {
+ va_list args;
+
+ fprintf(stderr,"chart: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(const char *fmt, ...) {
+ va_list args;
+
+ fprintf(stderr,"chart: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#endif /* STANDALONE_TEST */
+/* ---------------------------------------------------------- */
diff --git a/cgats/pars.h b/cgats/pars.h
new file mode 100644
index 0000000..83bbdad
--- /dev/null
+++ b/cgats/pars.h
@@ -0,0 +1,242 @@
+#ifndef PARS_H
+/*
+ * Simple ASCII file parsing object.
+ * Used as a base for the CGATS.5 and IT8.7 family file I/O class
+ * Version 2.01
+ *
+ * Author: Graeme W. Gill
+ * Date: 20/12/95
+ *
+ * Copyright 1995, 1996, 2002 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+#undef CGATS_DEBUG_MALLOC /* Turns on partial support for filename and linenumber capture */
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+/* System interface objects. The defaults can be replaced */
+/* for adaption to different system environments */
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef CGATS_DEBUG_MALLOC
+
+/* Heap allocator class interface definition */
+#define CGATS_ALLOC_BASE \
+ /* Public: */ \
+ \
+ void *(*dmalloc) (struct _cgatsAlloc *p, size_t size, char *file, int line); \
+ void *(*dcalloc) (struct _cgatsAlloc *p, size_t num, size_t size, char *file, int line);\
+ void *(*drealloc)(struct _cgatsAlloc *p, void *ptr, size_t size, char *file, int line); \
+ void (*dfree) (struct _cgatsAlloc *p, void *ptr, char *file, int line); \
+ \
+ /* we're done with the allocator object */ \
+ void (*del)(struct _cgatsAlloc *p); \
+
+#if defined(_PARS_C_) || defined(_CGATS_C_) || defined(_PARSSTD_C_) /* only inside implimentation */
+#define malloc( p, size ) dmalloc( p, size, __FILE__, __LINE__ )
+#define calloc( p, num, size ) dcalloc( p, num, size, __FILE__, __LINE__ )
+#define realloc( p, ptr, size ) drealloc( p, ptr, size, __FILE__, __LINE__ )
+#define free( p, ptr ) dfree( p, ptr , __FILE__, __LINE__ )
+#endif
+
+#else /* !CGATS_DEBUG_MALLOC */
+
+/* Heap allocator class interface definition */
+#define CGATS_ALLOC_BASE \
+ /* Public: */ \
+ \
+ void *(*malloc) (struct _cgatsAlloc *p, size_t size); \
+ void *(*calloc) (struct _cgatsAlloc *p, size_t num, size_t size); \
+ void *(*realloc)(struct _cgatsAlloc *p, void *ptr, size_t size); \
+ void (*free) (struct _cgatsAlloc *p, void *ptr); \
+ \
+ /* we're done with the allocator object */ \
+ void (*del)(struct _cgatsAlloc *p); \
+
+#endif /* !CGATS_DEBUG_MALLOC */
+
+/* Common heap allocator interface class */
+struct _cgatsAlloc {
+ CGATS_ALLOC_BASE
+}; typedef struct _cgatsAlloc cgatsAlloc;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+/* Available when SEPARATE_STD is not defined: */
+/* Implementation of heap class based on standard system malloc */
+struct _cgatsAllocStd {
+ CGATS_ALLOC_BASE
+}; typedef struct _cgatsAllocStd cgatsAllocStd;
+
+/* Create a standard alloc object */
+cgatsAlloc *new_cgatsAllocStd(void);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+/* File access class interface definition */
+#define CGATS_FILE_BASE \
+ /* Public: */ \
+ \
+ /* Get the size of the file (Only valid for reading file). */ \
+ size_t (*get_size) (struct _cgatsFile *p); \
+ \
+ /* Set current position to offset. Return 0 on success, nz on failure. */ \
+ int (*seek) (struct _cgatsFile *p, unsigned int offset); \
+ \
+ /* Read count items of size length. Return number of items successfully read. */ \
+ size_t (*read) (struct _cgatsFile *p, void *buffer, size_t size, size_t count); \
+ \
+ /* Read a single character */ \
+ int (*getch) (struct _cgatsFile *p); \
+ \
+ /* write count items of size length. Return number of items successfully written. */ \
+ size_t (*write)(struct _cgatsFile *p, void *buffer, size_t size, size_t count); \
+ \
+ /* printf to the file */ \
+ int (*gprintf)(struct _cgatsFile *p, const char *format, ...); \
+ \
+ /* flush all write data out to secondary storage. Return nz on failure. */ \
+ int (*flush)(struct _cgatsFile *p); \
+ \
+ /* return the filename if known, NULL if not */ \
+ char *(*fname)(struct _cgatsFile *p); \
+ \
+ /* Return the memory buffer. Error if not cgatsFileMem */ \
+ int (*get_buf)(struct _cgatsFile *p, unsigned char **buf, size_t *len); \
+ \
+ /* we're done with the file object, close & free it */ \
+ /* return nz on failure */ \
+ int (*del)(struct _cgatsFile *p); \
+
+/* Common file interface class */
+struct _cgatsFile {
+ CGATS_FILE_BASE
+}; typedef struct _cgatsFile cgatsFile;
+
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+/* Available when SEPARATE_STD is not defined: */
+
+/* Implementation of file access class based on standard file I/O */
+struct _cgatsFileStd {
+ CGATS_FILE_BASE
+
+ /* Private: */
+ cgatsAlloc *al; /* Heap allocator */
+ int del_al; /* NZ if heap allocator should be deleted */
+ FILE *fp;
+ int doclose; /* nz if free should close */
+ char *filename; /* NULL if not known */
+
+ /* Private: */
+ size_t size; /* Size of the file (For read) */
+
+}; typedef struct _cgatsFileStd cgatsFileStd;
+
+/* Create given a file name */
+cgatsFile *new_cgatsFileStd_name(const char *name, const char *mode);
+
+/* Create given a (binary) FILE* */
+cgatsFile *new_cgatsFileStd_fp(FILE *fp);
+
+/* Create given a file name and allocator */
+cgatsFile *new_cgatsFileStd_name_a(const char *name, const char *mode, cgatsAlloc *al);
+
+/* Create given a (binary) FILE* and allocator */
+cgatsFile *new_cgatsFileStd_fp_a(FILE *fp, cgatsAlloc *al);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Implementation of file access class based on a memory image */
+/* The buffer is assumed to be allocated with the given heap allocator */
+/* Pass base = NULL, length = 0 for no initial buffer */
+
+/* ~~ should ad method that returns buffer and length */
+
+struct _cgatsFileMem {
+ CGATS_FILE_BASE
+
+ /* Private: */
+ cgatsAlloc *al; /* Heap allocator */
+ int del_al; /* NZ if heap allocator should be deleted */
+ int del_buf; /* NZ if memory file buffer should be deleted */
+ unsigned char *start, *cur, *end, *aend;
+
+}; typedef struct _cgatsFileMem cgatsFileMem;
+
+/* Create a memory image file access class with given allocator */
+/* The buffer is not delete with the object. */
+cgatsFile *new_cgatsFileMem_a(void *base, size_t length, cgatsAlloc *al);
+
+/* Create a memory image file access class with given allocator */
+/* and delete buffer when cgatsFile is deleted. */
+cgatsFile *new_cgatsFileMem_ad(void *base, size_t length, cgatsAlloc *al);
+
+/* This is avalailable if SEPARATE_STD is not defined: */
+
+/* Create a memory image file access class with the std allocator */
+/* The buffer is not delete with the object. */
+cgatsFile *new_cgatsFileMem(void *base, size_t length);
+
+/* Create a memory image file access class with the std allocator */
+/* and delete buffer when cgatsFile is deleted. */
+cgatsFile *new_cgatsFileMem_d(void *base, size_t length);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+struct _parse {
+ /* Public Variables */
+ int line; /* Current line number */
+ int token; /* Current token number */
+
+ /* Public Methods */
+ void (*del)(struct _parse *p); /* Delete the object */
+ void (*reset_del)(struct _parse *p); /* Reset the parsing delimiters */
+ void (*add_del)(struct _parse *p, /* Add to the parsing delimiters */
+ char *t, char *nr,
+ char *c, char *q);
+ int (*read_line)(struct _parse *p); /* Read in a line. Return 0 if read failed, */
+ /* -1 on other error */
+ char *(*get_token)(struct _parse *p); /* Return a pointer to the next token, */
+ /* NULL if no tokens. set errc NZ on other error */
+
+ /* Private */
+ cgatsAlloc *al; /* Memory allocator */
+ int del_al; /* Flag to indicate we al->del() */
+ cgatsFile *fp; /* File we're dealing with */
+ int ltflag; /* Last terminator flag */
+ int q; /* Quote */
+ char *b; /* Line buffer */
+ int bs; /* Buffer size */
+ int bo; /* Next buffer offset */
+ int to; /* Token parsing offset into b */
+ char *tb; /* Token buffer */
+ int tbs; /* Token buffer size */
+ char delf[256]; /* Parsing delimiter flags */
+ /* Parsing flags */
+#define PARS_TERM 0x01 /* Terminates a token */
+#define PARS_SKIP 0x02 /* Character is not read */
+#define PARS_COMM 0x04 /* Character starts a comment */
+#define PARS_QUOTE 0x08 /* Character starts/ends a quoted string */
+
+ char err[200]; /* Error message */
+ int errc; /* Error code */
+}; typedef struct _parse parse;
+
+/* Creator */
+extern parse *new_parse_al(cgatsAlloc *al, cgatsFile *fp); /* With allocator class */
+
+/* Available when SEPARATE_STD is not defined: */
+extern parse *new_parse(cgatsFile *fp); /* Default allocator */
+
+#define PARS_H
+#endif /* PARS_H */
+
diff --git a/cgats/parsstd.c b/cgats/parsstd.c
new file mode 100644
index 0000000..4443e0a
--- /dev/null
+++ b/cgats/parsstd.c
@@ -0,0 +1,476 @@
+
+/*
+ * parse library stdio and malloc utility classes.
+ * Version 2.05
+ *
+ * Author: Graeme W. Gill
+ * Date: 2002/10/24
+ *
+ * Copyright 2002, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ *
+ * These are kept in a separate file to allow them to be
+ * selectively ommitted from the cgats library.
+ *
+ */
+
+#define _PARSSTD_C_
+
+#ifndef COMBINED_STD
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <time.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+
+#include "pars.h"
+
+#endif /* !COMBINED_STD */
+
+#if defined(SEPARATE_STD) || defined(COMBINED_STD)
+
+/* ----------------------------------------------- */
+/* Standard Heap allocator cgatsAlloc compatible class */
+/* Just call the standard system function */
+
+#ifdef CGATS_DEBUG_MALLOC
+
+/* Make sure that inline malloc #defines are turned off for this file */
+#undef was_debug_malloc
+#ifdef malloc
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+#define was_debug_malloc
+#endif /* dmalloc */
+
+static void *cgatsAllocStd_dmalloc(
+struct _cgatsAlloc *pp,
+size_t size,
+char *file,
+int line
+) {
+ void *rv = malloc(size);
+ return rv;
+}
+
+static void *cgatsAllocStd_dcalloc(
+struct _cgatsAlloc *pp,
+size_t num,
+size_t size,
+char *file,
+int line
+) {
+ void *rv = calloc(num, size);
+ return rv;
+}
+
+static void *cgatsAllocStd_drealloc(
+struct _cgatsAlloc *pp,
+void *ptr,
+size_t size,
+char *file,
+int line
+) {
+ void *rv = realloc(ptr, size);
+ return rv;
+}
+
+
+static void cgatsAllocStd_dfree(
+struct _cgatsAlloc *pp,
+void *ptr,
+char *file,
+int line
+) {
+ free(ptr);
+}
+
+/* we're done with the AllocStd object */
+static void cgatsAllocStd_delete(
+cgatsAlloc *pp
+) {
+ cgatsAllocStd *p = (cgatsAllocStd *)pp;
+
+ free(p);
+}
+
+/* Create cgatsAllocStd */
+cgatsAlloc *new_cgatsAllocStd() {
+ cgatsAllocStd *p;
+ if ((p = (cgatsAllocStd *) calloc(1,sizeof(cgatsAllocStd))) == NULL)
+ return NULL;
+ p->dmalloc = cgatsAllocStd_dmalloc;
+ p->dcalloc = cgatsAllocStd_dcalloc;
+ p->drealloc = cgatsAllocStd_drealloc;
+ p->dfree = cgatsAllocStd_dfree;
+ p->del = cgatsAllocStd_delete;
+
+ return (cgatsAlloc *)p;
+}
+
+#ifdef was_debug_malloc
+#undef was_debug_malloc
+#define malloc( p, size ) dmalloc( p, size, __FILE__, __LINE__ )
+#define calloc( p, num, size ) dcalloc( p, num, size, __FILE__, __LINE__ )
+#define realloc( p, ptr, size ) drealloc( p, ptr, size, __FILE__, __LINE__ )
+#define free( p, ptr ) dfree( p, ptr , __FILE__, __LINE__ )
+#endif /* was_debug_malloc */
+
+#else /* !CGATS_DEBUG_MALLOC */
+
+static void *cgatsAllocStd_malloc(
+struct _cgatsAlloc *pp,
+size_t size
+) {
+ void *rv = malloc(size);
+ return rv;
+}
+
+static void *cgatsAllocStd_calloc(
+struct _cgatsAlloc *pp,
+size_t num,
+size_t size
+) {
+ void *rv = calloc(num, size);
+ return rv;
+}
+
+static void *cgatsAllocStd_realloc(
+struct _cgatsAlloc *pp,
+void *ptr,
+size_t size
+) {
+ void *rv = realloc(ptr, size);
+ return rv;
+}
+
+
+static void cgatsAllocStd_free(
+struct _cgatsAlloc *pp,
+void *ptr
+) {
+ free(ptr);
+}
+
+/* we're done with the AllocStd object */
+static void cgatsAllocStd_delete(
+cgatsAlloc *pp
+) {
+ cgatsAllocStd *p = (cgatsAllocStd *)pp;
+
+ free(p);
+}
+
+/* Create cgatsAllocStd */
+cgatsAlloc *new_cgatsAllocStd() {
+ cgatsAllocStd *p;
+ if ((p = (cgatsAllocStd *) calloc(1,sizeof(cgatsAllocStd))) == NULL)
+ return NULL;
+ p->malloc = cgatsAllocStd_malloc;
+ p->calloc = cgatsAllocStd_calloc;
+ p->realloc = cgatsAllocStd_realloc;
+ p->free = cgatsAllocStd_free;
+ p->del = cgatsAllocStd_delete;
+
+ return (cgatsAlloc *)p;
+}
+
+#endif /* !CGATS_DEBUG_MALLOC */
+
+/* ------------------------------------------------- */
+/* Standard Stream file I/O cgatsFile compatible class */
+
+/* Get the size of the file (Only valid for reading file. */
+static size_t cgatsFileStd_get_size(cgatsFile *pp) {
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+
+ return p->size;
+}
+
+/* Set current position to offset. Return 0 on success, nz on failure. */
+static int cgatsFileStd_seek(
+cgatsFile *pp,
+unsigned int offset
+) {
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+
+ return fseek(p->fp, offset, SEEK_SET);
+}
+
+/* Read count items of size length. Return number of items successfully read. */
+static size_t cgatsFileStd_read(
+cgatsFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+
+ return fread(buffer, size, count, p->fp);
+}
+
+/* Read a character */
+static int cgatsFileStd_getch(
+cgatsFile *pp
+) {
+
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+
+ return fgetc(p->fp);
+}
+
+/* write count items of size length. Return number of items successfully written. */
+static size_t cgatsFileStd_write(
+cgatsFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+
+ return fwrite(buffer, size, count, p->fp);
+}
+
+/* do a printf */
+static int cgatsFileStd_printf(
+cgatsFile *pp,
+const char *format,
+...
+) {
+ int rv;
+ va_list args;
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+
+ va_start(args, format);
+ rv = vfprintf(p->fp, format, args);
+ va_end(args);
+ return rv;
+}
+
+/* flush all write data out to secondary storage. Return nz on failure. */
+static int cgatsFileStd_flush(
+cgatsFile *pp
+) {
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+
+ return fflush(p->fp);
+}
+
+/* Return the memory buffer. Error if not cgatsFileMem */
+static int cgatsFileStd_get_buf(
+cgatsFile *pp,
+unsigned char **buf,
+size_t *len
+) {
+ return 1;
+}
+
+/* return the filename */
+static char *cgatsFileStd_fname(
+cgatsFile *pp
+) {
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+
+ if (p->filename != NULL)
+ return p->filename;
+ else
+ return "**Unknown**";
+}
+
+
+/* we're done with the file object, return nz on failure */
+static int cgatsFileStd_delete(
+cgatsFile *pp
+) {
+ int rv = 0;
+ cgatsFileStd *p = (cgatsFileStd *)pp;
+ cgatsAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ if (p->doclose != 0) {
+ if (fclose(p->fp) != 0)
+ rv = 2;
+ }
+
+ if (p->filename != NULL)
+ al->free(al, p->filename);
+
+ al->free(al, p); /* Free object */
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+
+ return rv;
+}
+
+/* Create cgatsFile given a (binary) FILE* */
+cgatsFile *new_cgatsFileStd_fp(
+FILE *fp
+) {
+ return new_cgatsFileStd_fp_a(fp, NULL);
+}
+
+/* Create cgatsFile given a (binary) FILE* and allocator */
+cgatsFile *new_cgatsFileStd_fp_a(
+FILE *fp,
+cgatsAlloc *al /* heap allocator, NULL for default */
+) {
+ cgatsFileStd *p;
+ int del_al = 0;
+ struct stat sbuf;
+
+ if (al == NULL) { /* None provided, create default */
+ if ((al = new_cgatsAllocStd()) == NULL)
+ return NULL;
+ del_al = 1; /* We need to delete it */
+ }
+
+ if ((p = (cgatsFileStd *) al->calloc(al, 1, sizeof(cgatsFileStd))) == NULL) {
+ if (del_al)
+ al->del(al);
+ return NULL;
+ }
+ p->al = al; /* Heap allocator */
+ p->del_al = del_al; /* Flag noting whether we delete it */
+ p->get_size = cgatsFileStd_get_size;
+ p->seek = cgatsFileStd_seek;
+ p->read = cgatsFileStd_read;
+ p->getch = cgatsFileStd_getch;
+ p->write = cgatsFileStd_write;
+ p->gprintf = cgatsFileStd_printf;
+ p->flush = cgatsFileStd_flush;
+ p->get_buf = cgatsFileStd_get_buf;
+ p->fname = cgatsFileStd_fname;
+ p->del = cgatsFileStd_delete;
+
+ if (fstat(fileno(fp), &sbuf) == 0) {
+ p->size = sbuf.st_size;
+ } else {
+ p->size = 0;
+ }
+
+ p->fp = fp;
+ p->doclose = 0;
+
+ return (cgatsFile *)p;
+}
+
+/* Create cgatsFile given a file name */
+cgatsFile *new_cgatsFileStd_name(
+const char *name,
+const char *mode
+) {
+ return new_cgatsFileStd_name_a(name, mode, NULL);
+}
+
+/* Create given a file name and allocator */
+cgatsFile *new_cgatsFileStd_name_a(
+const char *name,
+const char *mode,
+cgatsAlloc *al /* heap allocator, NULL for default */
+) {
+ FILE *fp;
+ cgatsFile *p;
+ char nmode[50];
+
+ strcpy(nmode, mode);
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ strcat(nmode, "b");
+#endif
+
+ if ((fp = fopen(name, nmode)) == NULL)
+ return NULL;
+
+ p = new_cgatsFileStd_fp_a(fp, al);
+
+ if (p != NULL) {
+ cgatsFileStd *pp = (cgatsFileStd *)p;
+ pp->doclose = 1;
+
+ pp->filename = pp->al->malloc(pp->al, strlen(name) + 1);
+ strcpy(pp->filename, name);
+ }
+ return p;
+}
+
+/* Create a memory image file access class with the std allocator */
+/* Don't free the buffer on delete */
+cgatsFile *new_cgatsFileMem(
+void *base, /* Pointer to base of memory buffer */
+size_t length /* Number of bytes in buffer */
+) {
+ cgatsFile *p;
+ cgatsAlloc *al; /* memory allocator */
+
+ if ((al = new_cgatsAllocStd()) == NULL)
+ return NULL;
+
+ if ((p = new_cgatsFileMem_a(base, length, al)) == NULL) {
+ al->del(al);
+ return NULL;
+ }
+
+ ((cgatsFileMem *)p)->del_al = 1; /* Get cgatsFileMem->del to cleanup al */
+ return p;
+}
+
+/* Create a memory image file access class with the std allocator */
+/* Free buffer on delete */
+cgatsFile *new_cgatsFileMem_d(
+void *base, /* Pointer to base of memory buffer */
+size_t length /* Number of bytes in buffer */
+) {
+ cgatsFile *p;
+ cgatsAlloc *al; /* memory allocator */
+
+ if ((al = new_cgatsAllocStd()) == NULL)
+ return NULL;
+
+ if ((p = new_cgatsFileMem_a(base, length, al)) == NULL) {
+ al->del(al);
+ return NULL;
+ }
+
+ ((cgatsFileMem *)p)->del_al = 1; /* Get cgatsFileMem->del to cleanup al */
+ ((cgatsFileMem *)p)->del_buf = 1; /* Get cgatsFileMem->del to cleanup buffer */
+ return p;
+}
+
+/* ------------------------------------------------- */
+
+/* Create an empty parse object, default standard allocator */
+parse *
+new_parse(cgatsFile *fp) {
+ parse *p;
+ cgatsAlloc *al; /* memory allocator */
+
+ if ((al = new_cgatsAllocStd()) == NULL)
+ return NULL;
+
+ if ((p = new_parse_al(al, fp)) == NULL) {
+ al->del(al);
+ return NULL;
+ }
+
+ p->del_al = 1; /* Get parse->del to cleanup allocator */
+ return p;
+}
+
+
+#endif /* defined(SEPARATE_STD) || defined(COMBINED_STD) */
diff --git a/config.guess b/config.guess
new file mode 100644
index 0000000..b79252d
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1558 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2013 Free Software Foundation, Inc.
+
+timestamp='2013-06-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2013 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval $set_cc_for_build
+ cat <<-EOF > $dummy.c
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo ${UNAME_MACHINE}-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ cris:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ crisv32:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ frv:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:Linux:*:*)
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ ;;
+ or1k:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ or32:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-${LIBC}
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+ *) echo hppa-unknown-linux-${LIBC} ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-${LIBC}
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-${LIBC}
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-${LIBC}
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-${LIBC}
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ exit ;;
+ x86_64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval $set_cc_for_build
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ fi
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
+esac
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..3f66386
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,95 @@
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Default visibility */
+#undef API_EXPORTED
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#undef HAVE_LIBRT
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Linux kernel */
+#undef OS_LINUX
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
diff --git a/config.sub b/config.sub
new file mode 100644
index 0000000..9633db7
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1791 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2013 Free Software Foundation, Inc.
+
+timestamp='2013-08-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2013 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arceb \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | be32 | be64 \
+ | bfin \
+ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | epiphany \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+ | open8 \
+ | or1k | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pyramid \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | we32k \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pyramid-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ c8051-*)
+ os=-elf
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or1k-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100644
index 0000000..9ca113f
--- /dev/null
+++ b/configure
@@ -0,0 +1,15216 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for argyll 1.3.7.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+
+ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='argyll'
+PACKAGE_TARNAME='argyll'
+PACKAGE_VERSION='1.3.7'
+PACKAGE_STRING='argyll 1.3.7'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+BIGENDIAN
+OS_LINUX_FALSE
+OS_LINUX_TRUE
+OS_BSD
+OS_LINUX
+YAJL_SUBDIRS
+YAJL_CFLAGS
+YAJL_LIBS
+ICC_SUBDIRS
+ICC_CFLAGS
+ICC_LIBS
+TIFF_LIBS
+X_EXTRA_LIBS
+X_LIBS
+X_PRE_LIBS
+X_CFLAGS
+XMKMF
+CPP
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+ac_ct_AR
+AR
+DLLTOOL
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+EGREP
+GREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+with_x
+with_system_libicc
+with_system_libyajl
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+XMKMF'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures argyll 1.3.7 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/argyll]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+X features:
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of argyll 1.3.7:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-silent-rules less verbose build output (undo: "make V=1")
+ --disable-silent-rules verbose build output (undo: "make V=0")
+ --enable-dependency-tracking
+ do not reject slow dependency extractors
+ --disable-dependency-tracking
+ speeds up one-time build
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-static[=PKGS] build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-sysroot=DIR Search for dependent libraries within DIR
+ (or the compiler's sysroot if not specified).
+ --with-x use the X Window System
+ --with-system-libicc use system libicc instead of argyllcms copy
+ --with-system-libyajl use system libyajl instead of argyllcms copy
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ XMKMF Path to xmkmf, Makefile generator for X Window System
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+argyll configure 1.3.7
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by argyll $as_me 1.3.7, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+am__api_version='1.13'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+ alias in your environment" "$LINENO" 5
+ fi
+ if test "$2" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if ${ac_cv_path_mkdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='argyll'
+ VERSION='1.3.7'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case "$ECHO" in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in dumpbin "link -dump"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in dumpbin "link -dump"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,b/c, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test "$GCC" != yes; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DLLTOOL"; then
+ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+ ac_ct_DLLTOOL=$DLLTOOL
+ # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DLLTOOL"; then
+ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DLLTOOL" = x; then
+ DLLTOOL="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DLLTOOL=$ac_ct_DLLTOOL
+ fi
+else
+ DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh
+ # decide which to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in ar
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AR" && break
+ done
+fi
+if test -z "$AR"; then
+ ac_ct_AR=$AR
+ for ac_prog in ar
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_AR" && break
+done
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ar_at_file=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -ne 0; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test "x$lt_cv_ar_at_file" = xno; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+ (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+ withval=$with_sysroot;
+else
+ with_sysroot=no
+fi
+
+
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+ if test "$GCC" = yes; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
+$as_echo "${with_sysroot}" >&6; }
+ as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+ ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD="${LD-ld}_sol2"
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$MANIFEST_TOOL"; then
+ ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+ ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+ # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_MANIFEST_TOOL"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_MANIFEST_TOOL" = x; then
+ MANIFEST_TOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+ fi
+else
+ MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&5
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+ MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&5
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+ echo "$AR cru libconftest.a conftest.o" >&5
+ $AR cru libconftest.a conftest.o 2>&5
+ echo "$RANLIB libconftest.a" >&5
+ $RANLIB libconftest.a 2>&5
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&5
+ elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[012]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+
+
+
+ enable_dlopen=no
+
+
+ enable_win32_dll=no
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+ # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for lt_pkg in $withval; do
+ IFS="$lt_save_ifs"
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl='-Xlinker '
+ if test -n "$lt_prog_compiler_pic"; then
+ lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ lt_prog_compiler_wl='-Wl,-Wl,,'
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ *Intel*\ [CF]*Compiler*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ *Portland\ Group*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ link_all_deplibs=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ export_dynamic_flag_spec='${wl}--export-all-symbols'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+ exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ link_all_deplibs=no
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_="/usr/lib:/lib"
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_="/usr/lib:/lib"
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ fi
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ file_list_spec='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+ enable_shared_with_static_runtimes=yes
+ exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ old_postinstall_cmds='chmod 644 $oldlib'
+ postlink_cmds='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ enable_shared_with_static_runtimes=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+ else
+ whole_archive_flag_spec=''
+ fi
+ link_all_deplibs=yes
+ allow_undefined_flag="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler__b=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -b"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler__b=yes
+ fi
+ else
+ lt_cv_prog_compiler__b=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_irix_exported_symbol=yes
+else
+ lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+ if test "$lt_cv_irix_exported_symbol" = yes; then
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ fi
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc=no
+ else
+ lt_cv_archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='${libname}.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec="$LIB"
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[23].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+ test "$inherit_rpath" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+ lt_cv_dlopen="shl_load"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report which library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5
+$as_echo_n "checking for X... " >&6; }
+
+
+# Check whether --with-x was given.
+if test "${with_x+set}" = set; then :
+ withval=$with_x;
+fi
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+ # The user explicitly disabled X.
+ have_x=disabled
+else
+ case $x_includes,$x_libraries in #(
+ *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #(
+ *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # One or both of the vars are not set, and there is no cached value.
+ac_x_includes=no ac_x_libraries=no
+rm -f -r conftest.dir
+if mkdir conftest.dir; then
+ cd conftest.dir
+ cat >Imakefile <<'_ACEOF'
+incroot:
+ @echo incroot='${INCROOT}'
+usrlibdir:
+ @echo usrlibdir='${USRLIBDIR}'
+libdir:
+ @echo libdir='${LIBDIR}'
+_ACEOF
+ if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then
+ # GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+ for ac_var in incroot usrlibdir libdir; do
+ eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`"
+ done
+ # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+ for ac_extension in a so sl dylib la dll; do
+ if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" &&
+ test -f "$ac_im_libdir/libX11.$ac_extension"; then
+ ac_im_usrlibdir=$ac_im_libdir; break
+ fi
+ done
+ # Screen out bogus values from the imake configuration. They are
+ # bogus both because they are the default anyway, and because
+ # using them would break gcc on systems where it needs fixed includes.
+ case $ac_im_incroot in
+ /usr/include) ac_x_includes= ;;
+ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;;
+ esac
+ case $ac_im_usrlibdir in
+ /usr/lib | /usr/lib64 | /lib | /lib64) ;;
+ *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;;
+ esac
+ fi
+ cd ..
+ rm -f -r conftest.dir
+fi
+
+# Standard set of common directories for X headers.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ac_x_header_dirs='
+/usr/X11/include
+/usr/X11R7/include
+/usr/X11R6/include
+/usr/X11R5/include
+/usr/X11R4/include
+
+/usr/include/X11
+/usr/include/X11R7
+/usr/include/X11R6
+/usr/include/X11R5
+/usr/include/X11R4
+
+/usr/local/X11/include
+/usr/local/X11R7/include
+/usr/local/X11R6/include
+/usr/local/X11R5/include
+/usr/local/X11R4/include
+
+/usr/local/include/X11
+/usr/local/include/X11R7
+/usr/local/include/X11R6
+/usr/local/include/X11R5
+/usr/local/include/X11R4
+
+/usr/X386/include
+/usr/x386/include
+/usr/XFree86/include/X11
+
+/usr/include
+/usr/local/include
+/usr/unsupported/include
+/usr/athena/include
+/usr/local/x11r5/include
+/usr/lpp/Xamples/include
+
+/usr/openwin/include
+/usr/openwin/share/include'
+
+if test "$ac_x_includes" = no; then
+ # Guess where to find include files, by looking for Xlib.h.
+ # First, try using that file with no special directory specified.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+ for ac_dir in $ac_x_header_dirs; do
+ if test -r "$ac_dir/X11/Xlib.h"; then
+ ac_x_includes=$ac_dir
+ break
+ fi
+done
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+fi # $ac_x_includes = no
+
+if test "$ac_x_libraries" = no; then
+ # Check for the libraries.
+ # See if we find them without any special options.
+ # Don't add to $LIBS permanently.
+ ac_save_LIBS=$LIBS
+ LIBS="-lX11 $LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+int
+main ()
+{
+XrmInitialize ()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ LIBS=$ac_save_LIBS
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+ LIBS=$ac_save_LIBS
+for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g`
+do
+ # Don't even attempt the hair of trying to link an X program!
+ for ac_extension in a so sl dylib la dll; do
+ if test -r "$ac_dir/libX11.$ac_extension"; then
+ ac_x_libraries=$ac_dir
+ break 2
+ fi
+ done
+done
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi # $ac_x_libraries = no
+
+case $ac_x_includes,$ac_x_libraries in #(
+ no,* | *,no | *\'*)
+ # Didn't find X, or a directory has "'" in its name.
+ ac_cv_have_x="have_x=no";; #(
+ *)
+ # Record where we found X for the cache.
+ ac_cv_have_x="have_x=yes\
+ ac_x_includes='$ac_x_includes'\
+ ac_x_libraries='$ac_x_libraries'"
+esac
+fi
+;; #(
+ *) have_x=yes;;
+ esac
+ eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5
+$as_echo "$have_x" >&6; }
+ no_x=yes
+else
+ # If each of the values was on the command line, it overrides each guess.
+ test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+ test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+ # Update the cache value to reflect the command line values.
+ ac_cv_have_x="have_x=yes\
+ ac_x_includes='$x_includes'\
+ ac_x_libraries='$x_libraries'"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5
+$as_echo "libraries $x_libraries, headers $x_includes" >&6; }
+fi
+
+if test "$no_x" = yes; then
+ # Not all programs may use this symbol, but it does not hurt to define it.
+
+$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h
+
+ X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+else
+ if test -n "$x_includes"; then
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+
+ # It would also be nice to do this for all -L options, not just this one.
+ if test -n "$x_libraries"; then
+ X_LIBS="$X_LIBS -L$x_libraries"
+ # For Solaris; some versions of Sun CC require a space after -R and
+ # others require no space. Words are not sufficient . . . .
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5
+$as_echo_n "checking whether -R must be followed by a space... " >&6; }
+ ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
+ ac_xsave_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ X_LIBS="$X_LIBS -R$x_libraries"
+else
+ LIBS="$ac_xsave_LIBS -R $x_libraries"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ X_LIBS="$X_LIBS -R $x_libraries"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5
+$as_echo "neither works" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_c_werror_flag=$ac_xsave_c_werror_flag
+ LIBS=$ac_xsave_LIBS
+ fi
+
+ # Check for system-dependent libraries X programs must link with.
+ # Do this before checking for the system-independent R6 libraries
+ # (-lICE), since we may need -lsocket or whatever for X linking.
+
+ if test "$ISC" = yes; then
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
+ else
+ # Martyn Johnson says this is needed for Ultrix, if the X
+ # libraries were built with DECnet support. And Karl Berry says
+ # the Alpha needs dnet_stub (dnet does not exist).
+ ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XOpenDisplay ();
+int
+main ()
+{
+return XOpenDisplay ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; }
+if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dnet_dnet_ntoa=yes
+else
+ ac_cv_lib_dnet_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+fi
+
+ if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; }
+if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet_stub $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dnet_stub_dnet_ntoa=yes
+else
+ ac_cv_lib_dnet_stub_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+fi
+
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_xsave_LIBS"
+
+ # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
+ # to get the SysV transport functions.
+ # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4)
+ # needs -lnsl.
+ # The nsl library prevents programs from opening the X display
+ # on Irix 5.2, according to T.E. Dickey.
+ # The functions gethostbyname, getservbyname, and inet_addr are
+ # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking.
+ ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
+if test "x$ac_cv_func_gethostbyname" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_gethostbyname = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+fi
+
+ if test $ac_cv_lib_nsl_gethostbyname = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5
+$as_echo_n "checking for gethostbyname in -lbsd... " >&6; }
+if ${ac_cv_lib_bsd_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_bsd_gethostbyname=yes
+else
+ ac_cv_lib_bsd_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5
+$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; }
+if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd"
+fi
+
+ fi
+ fi
+
+ # lieder@skyler.mavd.honeywell.com says without -lsocket,
+ # socket/setsockopt and other routines are undefined under SCO ODT
+ # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary
+ # on later versions), says Simon Leinen: it contains gethostby*
+ # variants that don't use the name server (or something). -lsocket
+ # must be given before -lnsl if both are needed. We assume that
+ # if connect needs -lnsl, so does gethostbyname.
+ ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
+if test "x$ac_cv_func_connect" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_connect = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if ${ac_cv_lib_socket_connect+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_connect=yes
+else
+ ac_cv_lib_socket_connect=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = xyes; then :
+ X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+fi
+
+ fi
+
+ # Guillermo Gomez says -lposix is necessary on A/UX.
+ ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove"
+if test "x$ac_cv_func_remove" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_remove = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5
+$as_echo_n "checking for remove in -lposix... " >&6; }
+if ${ac_cv_lib_posix_remove+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char remove ();
+int
+main ()
+{
+return remove ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_posix_remove=yes
+else
+ ac_cv_lib_posix_remove=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5
+$as_echo "$ac_cv_lib_posix_remove" >&6; }
+if test "x$ac_cv_lib_posix_remove" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+fi
+
+ fi
+
+ # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+ ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat"
+if test "x$ac_cv_func_shmat" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_shmat = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5
+$as_echo_n "checking for shmat in -lipc... " >&6; }
+if ${ac_cv_lib_ipc_shmat+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lipc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shmat ();
+int
+main ()
+{
+return shmat ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ipc_shmat=yes
+else
+ ac_cv_lib_ipc_shmat=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5
+$as_echo "$ac_cv_lib_ipc_shmat" >&6; }
+if test "x$ac_cv_lib_ipc_shmat" = xyes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
+fi
+
+ fi
+ fi
+
+ # Check for libraries that X11R6 Xt/Xaw programs need.
+ ac_save_LDFLAGS=$LDFLAGS
+ test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
+ # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
+ # check for ICE first), but we must link in the order -lSM -lICE or
+ # we get undefined symbols. So assume we have SM if we have ICE.
+ # These have to be linked with before -lX11, unlike the other
+ # libraries we check for below, so use a different variable.
+ # John Interrante, Karl Berry
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5
+$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; }
+if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char IceConnectionNumber ();
+int
+main ()
+{
+return IceConnectionNumber ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ICE_IceConnectionNumber=yes
+else
+ ac_cv_lib_ICE_IceConnectionNumber=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5
+$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; }
+if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then :
+ X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
+fi
+
+ LDFLAGS=$ac_save_LDFLAGS
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5
+$as_echo_n "checking for sqrt in -lm... " >&6; }
+if ${ac_cv_lib_m_sqrt+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sqrt ();
+int
+main ()
+{
+return sqrt ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_sqrt=yes
+else
+ ac_cv_lib_m_sqrt=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5
+$as_echo "$ac_cv_lib_m_sqrt" >&6; }
+if test "x$ac_cv_lib_m_sqrt" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_pthread_create+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+ LIBS="-lpthread $LIBS"
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TIFFOpen in -ltiff" >&5
+$as_echo_n "checking for TIFFOpen in -ltiff... " >&6; }
+if ${ac_cv_lib_tiff_TIFFOpen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ltiff -lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char TIFFOpen ();
+int
+main ()
+{
+return TIFFOpen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_tiff_TIFFOpen=yes
+else
+ ac_cv_lib_tiff_TIFFOpen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tiff_TIFFOpen" >&5
+$as_echo "$ac_cv_lib_tiff_TIFFOpen" >&6; }
+if test "x$ac_cv_lib_tiff_TIFFOpen" = xyes; then :
+ TIFF_LIBS="-ltiff"
+fi
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if ${ac_cv_lib_rt_clock_gettime+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_rt_clock_gettime=yes
+else
+ ac_cv_lib_rt_clock_gettime=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBRT 1
+_ACEOF
+
+ LIBS="-lrt $LIBS"
+
+fi
+
+
+
+# Check whether --with-system-libicc was given.
+if test "${with_system_libicc+set}" = set; then :
+ withval=$with_system_libicc; system_libicc=$withval
+else
+ system_libicc=no
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use system libicc or not" >&5
+$as_echo_n "checking whether to use system libicc or not... " >&6; }
+if test x$system_libicc = xno ; then
+ HAVE_ICC=false
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for new_icmFileStd_name in -licc" >&5
+$as_echo_n "checking for new_icmFileStd_name in -licc... " >&6; }
+if ${ac_cv_lib_icc_new_icmFileStd_name+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-licc -lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char new_icmFileStd_name ();
+int
+main ()
+{
+return new_icmFileStd_name ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_icc_new_icmFileStd_name=yes
+else
+ ac_cv_lib_icc_new_icmFileStd_name=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_icc_new_icmFileStd_name" >&5
+$as_echo "$ac_cv_lib_icc_new_icmFileStd_name" >&6; }
+if test "x$ac_cv_lib_icc_new_icmFileStd_name" = xyes; then :
+ HAVE_ICC="true"
+fi
+
+ if test "$HAVE_ICC" != "true" ; then
+ as_fn_error $? "system libicc missing or not compatible with argyllcms" "$LINENO" 5
+ fi
+fi
+if test "$HAVE_ICC" = "true" ; then
+ ICC_LIBS="-licc"
+else
+ ICC_LIBS='$(top_srcdir)/icc/libicc.la'
+ ICC_CFLAGS='-I$(top_srcdir)/icc'
+ ICC_SUBDIRS='icc'
+fi
+
+
+
+
+
+# Check whether --with-system-libyajl was given.
+if test "${with_system_libyajl+set}" = set; then :
+ withval=$with_system_libyajl; system_libyajl=$withval
+else
+ system_libyajl=no
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use system libyajl or not" >&5
+$as_echo_n "checking whether to use system libyajl or not... " >&6; }
+if test x$system_libyajl = xno ; then
+ HAVE_YAJL=false
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for yajl_gen_c_comment in -lyajl" >&5
+$as_echo_n "checking for yajl_gen_c_comment in -lyajl... " >&6; }
+if ${ac_cv_lib_yajl_yajl_gen_c_comment+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lyajl -lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char yajl_gen_c_comment ();
+int
+main ()
+{
+return yajl_gen_c_comment ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_yajl_yajl_gen_c_comment=yes
+else
+ ac_cv_lib_yajl_yajl_gen_c_comment=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_yajl_yajl_gen_c_comment" >&5
+$as_echo "$ac_cv_lib_yajl_yajl_gen_c_comment" >&6; }
+if test "x$ac_cv_lib_yajl_yajl_gen_c_comment" = xyes; then :
+ HAVE_YAJL="true"
+fi
+
+ if test "$HAVE_YAJL" != "true" ; then
+ as_fn_error $? "system libyajl missing or not compatible with argyllcms" "$LINENO" 5
+ fi
+fi
+if test "$HAVE_YAJL" = "true" ; then
+ YAJL_LIBS="-lyajl"
+else
+ YAJL_LIBS='$(top_srcdir)/jcnf/yajl/libyajl.la'
+ YAJL_CFLAGS='-I$(top_srcdir)/jcnf/yajl'
+ YAJL_SUBDIRS='yajl'
+fi
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XOpenDisplay in -lX11" >&5
+$as_echo_n "checking for XOpenDisplay in -lX11... " >&6; }
+if ${ac_cv_lib_X11_XOpenDisplay+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lX11 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XOpenDisplay ();
+int
+main ()
+{
+return XOpenDisplay ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_X11_XOpenDisplay=yes
+else
+ ac_cv_lib_X11_XOpenDisplay=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_X11_XOpenDisplay" >&5
+$as_echo "$ac_cv_lib_X11_XOpenDisplay" >&6; }
+if test "x$ac_cv_lib_X11_XOpenDisplay" = xyes; then :
+ X_LIBS="$X_LIBS -lX11"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XextFindDisplay in -lXext" >&5
+$as_echo_n "checking for XextFindDisplay in -lXext... " >&6; }
+if ${ac_cv_lib_Xext_XextFindDisplay+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXext -lX11 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XextFindDisplay ();
+int
+main ()
+{
+return XextFindDisplay ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xext_XextFindDisplay=yes
+else
+ ac_cv_lib_Xext_XextFindDisplay=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XextFindDisplay" >&5
+$as_echo "$ac_cv_lib_Xext_XextFindDisplay" >&6; }
+if test "x$ac_cv_lib_Xext_XextFindDisplay" = xyes; then :
+ X_LIBS="$X_LIBS -lXext"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XScreenSaverSuspend in -lXss" >&5
+$as_echo_n "checking for XScreenSaverSuspend in -lXss... " >&6; }
+if ${ac_cv_lib_Xss_XScreenSaverSuspend+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXss -lXext -lX11 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XScreenSaverSuspend ();
+int
+main ()
+{
+return XScreenSaverSuspend ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xss_XScreenSaverSuspend=yes
+else
+ ac_cv_lib_Xss_XScreenSaverSuspend=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xss_XScreenSaverSuspend" >&5
+$as_echo "$ac_cv_lib_Xss_XScreenSaverSuspend" >&6; }
+if test "x$ac_cv_lib_Xss_XScreenSaverSuspend" = xyes; then :
+ X_LIBS="$X_LIBS -lXss"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XRRRootToScreen in -lXrandr" >&5
+$as_echo_n "checking for XRRRootToScreen in -lXrandr... " >&6; }
+if ${ac_cv_lib_Xrandr_XRRRootToScreen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXrandr -LXext -lX11 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XRRRootToScreen ();
+int
+main ()
+{
+return XRRRootToScreen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xrandr_XRRRootToScreen=yes
+else
+ ac_cv_lib_Xrandr_XRRRootToScreen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xrandr_XRRRootToScreen" >&5
+$as_echo "$ac_cv_lib_Xrandr_XRRRootToScreen" >&6; }
+if test "x$ac_cv_lib_Xrandr_XRRRootToScreen" = xyes; then :
+ X_LIBS="$X_LIBS -lXrandr"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XineramaQueryScreens in -lXinerama" >&5
+$as_echo_n "checking for XineramaQueryScreens in -lXinerama... " >&6; }
+if ${ac_cv_lib_Xinerama_XineramaQueryScreens+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXinerama -LXext -lX11 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XineramaQueryScreens ();
+int
+main ()
+{
+return XineramaQueryScreens ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xinerama_XineramaQueryScreens=yes
+else
+ ac_cv_lib_Xinerama_XineramaQueryScreens=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xinerama_XineramaQueryScreens" >&5
+$as_echo "$ac_cv_lib_Xinerama_XineramaQueryScreens" >&6; }
+if test "x$ac_cv_lib_Xinerama_XineramaQueryScreens" = xyes; then :
+ X_LIBS="$X_LIBS -lXinerama"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XF86VidModeGetGamma in -lXxf86vm" >&5
+$as_echo_n "checking for XF86VidModeGetGamma in -lXxf86vm... " >&6; }
+if ${ac_cv_lib_Xxf86vm_XF86VidModeGetGamma+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lXxf86vm -lXext -lX11 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XF86VidModeGetGamma ();
+int
+main ()
+{
+return XF86VidModeGetGamma ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_Xxf86vm_XF86VidModeGetGamma=yes
+else
+ ac_cv_lib_Xxf86vm_XF86VidModeGetGamma=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xxf86vm_XF86VidModeGetGamma" >&5
+$as_echo "$ac_cv_lib_Xxf86vm_XF86VidModeGetGamma" >&6; }
+if test "x$ac_cv_lib_Xxf86vm_XF86VidModeGetGamma" = xyes; then :
+ X_LIBS="$X_LIBS -lXxf86vm"
+fi
+
+
+
+
+
+case $host in
+ *-linux*)
+ OS_LINUX=1
+ OS_BSD=0
+
+$as_echo "#define OS_LINUX 1" >>confdefs.h
+
+ if true; then
+ OS_LINUX_TRUE=
+ OS_LINUX_FALSE='#'
+else
+ OS_LINUX_TRUE='#'
+ OS_LINUX_FALSE=
+fi
+
+ ;;
+ *-freebsd*|*-kfreebsd*-gnu|*-openbsd*|*-netbsd*)
+ OS_LINUX=0
+ OS_BSD=1
+
+$as_echo "#define OS_LINUX 0" >>confdefs.h
+
+ if false; then
+ OS_LINUX_TRUE=
+ OS_LINUX_FALSE='#'
+else
+ OS_LINUX_TRUE='#'
+ OS_LINUX_FALSE=
+fi
+
+ ;;
+ *)
+ OS_LINUX=0
+ OS_BSD=0
+
+$as_echo "#define OS_LINUX 0" >>confdefs.h
+
+ if false; then
+ OS_LINUX_TRUE=
+ OS_LINUX_FALSE='#'
+else
+ OS_LINUX_TRUE='#'
+ OS_LINUX_FALSE=
+fi
+
+ ;;
+esac
+
+$as_echo "#define API_EXPORTED /**/" >>confdefs.h
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_bigendian=unknown
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # Compile a test program.
+ if test "$cross_compiling" = yes; then :
+ # Try to guess by grepping values from an object file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+short int ascii_mm[] =
+ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+ short int ascii_ii[] =
+ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+ int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+ }
+ short int ebcdic_ii[] =
+ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+ short int ebcdic_mm[] =
+ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+ int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+ }
+ extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+ ac_cv_c_bigendian=yes
+ fi
+ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+ u.l = 1;
+ return u.c[sizeof (long int) - 1] == 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_c_bigendian=no
+else
+ ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+ yes)
+ $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+ no)
+ ;; #(
+ universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+ ;; #(
+ *)
+ as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+if test "$ac_cv_c_bigendian" = "yes"; then
+ BIGENDIAN="1"
+else
+ BIGENDIAN="0"
+fi
+
+
+ac_config_files="$ac_config_files Makefile h/Makefile doc/Makefile ref/Makefile numlib/Makefile cgats/Makefile plot/Makefile rspl/Makefile icc/Makefile gamut/Makefile xicc/Makefile link/Makefile spectro/Makefile profile/Makefile tweak/Makefile scanin/Makefile render/Makefile target/Makefile imdi/Makefile jcnf/Makefile jcnf/yajl/Makefile ucmm/Makefile"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then
+ as_fn_error $? "conditional \"OS_LINUX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then
+ as_fn_error $? "conditional \"OS_LINUX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then
+ as_fn_error $? "conditional \"OS_LINUX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by argyll $as_me 1.3.7, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+argyll config.status 1.3.7
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+nm_file_list_spec \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "h/Makefile") CONFIG_FILES="$CONFIG_FILES h/Makefile" ;;
+ "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+ "ref/Makefile") CONFIG_FILES="$CONFIG_FILES ref/Makefile" ;;
+ "numlib/Makefile") CONFIG_FILES="$CONFIG_FILES numlib/Makefile" ;;
+ "cgats/Makefile") CONFIG_FILES="$CONFIG_FILES cgats/Makefile" ;;
+ "plot/Makefile") CONFIG_FILES="$CONFIG_FILES plot/Makefile" ;;
+ "rspl/Makefile") CONFIG_FILES="$CONFIG_FILES rspl/Makefile" ;;
+ "icc/Makefile") CONFIG_FILES="$CONFIG_FILES icc/Makefile" ;;
+ "gamut/Makefile") CONFIG_FILES="$CONFIG_FILES gamut/Makefile" ;;
+ "xicc/Makefile") CONFIG_FILES="$CONFIG_FILES xicc/Makefile" ;;
+ "link/Makefile") CONFIG_FILES="$CONFIG_FILES link/Makefile" ;;
+ "spectro/Makefile") CONFIG_FILES="$CONFIG_FILES spectro/Makefile" ;;
+ "profile/Makefile") CONFIG_FILES="$CONFIG_FILES profile/Makefile" ;;
+ "tweak/Makefile") CONFIG_FILES="$CONFIG_FILES tweak/Makefile" ;;
+ "scanin/Makefile") CONFIG_FILES="$CONFIG_FILES scanin/Makefile" ;;
+ "render/Makefile") CONFIG_FILES="$CONFIG_FILES render/Makefile" ;;
+ "target/Makefile") CONFIG_FILES="$CONFIG_FILES target/Makefile" ;;
+ "imdi/Makefile") CONFIG_FILES="$CONFIG_FILES imdi/Makefile" ;;
+ "jcnf/Makefile") CONFIG_FILES="$CONFIG_FILES jcnf/Makefile" ;;
+ "jcnf/yajl/Makefile") CONFIG_FILES="$CONFIG_FILES jcnf/yajl/Makefile" ;;
+ "ucmm/Makefile") CONFIG_FILES="$CONFIG_FILES ucmm/Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=""
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ if test x"$xsi_shell" = xyes; then
+ sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\ case ${1} in\
+\ */*) func_dirname_result="${1%/*}${2}" ;;\
+\ * ) func_dirname_result="${3}" ;;\
+\ esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\ func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\ case ${1} in\
+\ */*) func_dirname_result="${1%/*}${2}" ;;\
+\ * ) func_dirname_result="${3}" ;;\
+\ esac\
+\ func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\ # positional parameters, so assign one to ordinary parameter first.\
+\ func_stripname_result=${3}\
+\ func_stripname_result=${func_stripname_result#"${1}"}\
+\ func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\ func_split_long_opt_name=${1%%=*}\
+\ func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\ func_split_short_opt_arg=${1#??}\
+\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\ case ${1} in\
+\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\ *) func_lo2o_result=${1} ;;\
+\ esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+ func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+ func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+ func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+ sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+ eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\ func_quote_for_eval "${2}"\
+\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ # Save a `func_append' function call where possible by direct use of '+='
+ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+else
+ # Save a `func_append' function call even when '+=' is not available
+ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..3c93dc0
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,133 @@
+AC_INIT([argyll], [1.3.7])
+AM_INIT_AUTOMAKE([1.9 foreign])
+
+AC_PROG_CC
+LT_INIT
+AC_PROG_INSTALL
+
+AM_PROG_LIBTOOL
+AC_PROG_LIBTOOL
+
+AC_CONFIG_MACRO_DIR([m4])
+AM_CONFIG_HEADER([config.h])
+
+AC_PATH_XTRA
+
+AC_CHECK_LIB(m, sqrt)
+AC_CHECK_LIB(pthread, pthread_create)
+
+AC_CHECK_LIB(tiff, TIFFOpen, TIFF_LIBS="-ltiff", , -lm)
+AC_SUBST([TIFF_LIBS])
+
+AC_CHECK_LIB(rt, clock_gettime)
+
+AC_ARG_WITH(system-libicc, [ --with-system-libicc use system libicc instead of argyllcms copy],system_libicc=$withval,system_libicc=no)
+AC_MSG_CHECKING([whether to use system libicc or not])
+if test x$system_libicc = xno ; then
+ HAVE_ICC=false
+ AC_MSG_RESULT(no)
+else
+ AC_MSG_RESULT(yes)
+ AC_CHECK_LIB(icc, new_icmFileStd_name, HAVE_ICC="true", , -lm)
+ if test "$HAVE_ICC" != "true" ; then
+ AC_MSG_ERROR([system libicc missing or not compatible with argyllcms])
+ fi
+fi
+if test "$HAVE_ICC" = "true" ; then
+ ICC_LIBS="-licc"
+else
+ ICC_LIBS='$(top_srcdir)/icc/libicc.la'
+ ICC_CFLAGS='-I$(top_srcdir)/icc'
+ ICC_SUBDIRS='icc'
+fi
+AC_SUBST([ICC_LIBS])
+AC_SUBST([ICC_CFLAGS])
+AC_SUBST([ICC_SUBDIRS])
+
+AC_ARG_WITH(system-libyajl, [ --with-system-libyajl use system libyajl instead of argyllcms copy],system_libyajl=$withval,system_libyajl=no)
+AC_MSG_CHECKING([whether to use system libyajl or not])
+if test x$system_libyajl = xno ; then
+ HAVE_YAJL=false
+ AC_MSG_RESULT(no)
+else
+ AC_MSG_RESULT(yes)
+ AC_CHECK_LIB(yajl, yajl_gen_c_comment, HAVE_YAJL="true", , -lm)
+ if test "$HAVE_YAJL" != "true" ; then
+ AC_MSG_ERROR([system libyajl missing or not compatible with argyllcms])
+ fi
+fi
+if test "$HAVE_YAJL" = "true" ; then
+ YAJL_LIBS="-lyajl"
+else
+ YAJL_LIBS='$(top_srcdir)/jcnf/yajl/libyajl.la'
+ YAJL_CFLAGS='-I$(top_srcdir)/jcnf/yajl'
+ YAJL_SUBDIRS='yajl'
+fi
+AC_SUBST([YAJL_LIBS])
+AC_SUBST([YAJL_CFLAGS])
+AC_SUBST([YAJL_SUBDIRS])
+
+AC_CHECK_LIB(X11, XOpenDisplay, X_LIBS="$X_LIBS -lX11")
+AC_CHECK_LIB(Xext, XextFindDisplay, X_LIBS="$X_LIBS -lXext",,-lX11)
+AC_CHECK_LIB(Xss, XScreenSaverSuspend, X_LIBS="$X_LIBS -lXss",,-lXext -lX11)
+AC_CHECK_LIB(Xrandr, XRRRootToScreen, X_LIBS="$X_LIBS -lXrandr",,-LXext -lX11)
+AC_CHECK_LIB(Xinerama, XineramaQueryScreens, X_LIBS="$X_LIBS -lXinerama",,-LXext -lX11)
+AC_CHECK_LIB(Xxf86vm, XF86VidModeGetGamma, X_LIBS="$X_LIBS -lXxf86vm",,-lXext -lX11)
+AC_SUBST([X_LIBS])
+
+AC_SUBST(OS_LINUX)
+AC_SUBST(OS_BSD)
+case $host in
+ *-linux*)
+ OS_LINUX=1
+ OS_BSD=0
+ AC_DEFINE([OS_LINUX],[1],[Linux kernel])
+ AM_CONDITIONAL([OS_LINUX],[true])
+ ;;
+ *-freebsd*|*-kfreebsd*-gnu|*-openbsd*|*-netbsd*)
+ OS_LINUX=0
+ OS_BSD=1
+ AC_DEFINE([OS_LINUX],[0],[Linux kernel])
+ AM_CONDITIONAL([OS_LINUX],[false])
+ ;;
+ *)
+ OS_LINUX=0
+ OS_BSD=0
+ AC_DEFINE([OS_LINUX],[0],[Linux kernel])
+ AM_CONDITIONAL([OS_LINUX],[false])
+ ;;
+esac
+AC_DEFINE([API_EXPORTED],[],[Default visibility])
+
+AC_C_BIGENDIAN
+if test "$ac_cv_c_bigendian" = "yes"; then
+ BIGENDIAN="1"
+else
+ BIGENDIAN="0"
+fi
+AC_SUBST(BIGENDIAN)
+
+AC_CONFIG_FILES([Makefile
+ h/Makefile
+ doc/Makefile
+ ref/Makefile
+ numlib/Makefile
+ cgats/Makefile
+ plot/Makefile
+ rspl/Makefile
+ icc/Makefile
+ gamut/Makefile
+ xicc/Makefile
+ link/Makefile
+ spectro/Makefile
+ profile/Makefile
+ tweak/Makefile
+ scanin/Makefile
+ render/Makefile
+ target/Makefile
+ imdi/Makefile
+ jcnf/Makefile
+ jcnf/yajl/Makefile
+ ucmm/Makefile])
+
+AC_OUTPUT
diff --git a/debian/README.Debian b/debian/README.Debian
new file mode 100644
index 0000000..4b5f35b
--- /dev/null
+++ b/debian/README.Debian
@@ -0,0 +1,8 @@
+Notes for argyll as packaged in Debian:
+---------------------------------------
+
+* Four binaries with a very generic name (average, refine, targen and
+ verify) have been renamed to argyll-* in order to prevent naming
+ collisions.
+
+ -- Roland Mas <lolando@debian.org>, Thu, 19 Feb 2009 20:34:17 +0100
diff --git a/debian/README.Spyder2 b/debian/README.Spyder2
new file mode 100644
index 0000000..1922b5e
--- /dev/null
+++ b/debian/README.Spyder2
@@ -0,0 +1,36 @@
+Note for users of the ColorVision Spyder2:
+------------------------------------------
+
+The Spyder2 device doesn't work "out of the box" because it needs
+firmware to be loaded into it. That firmware is proprietary and
+cannot be distributed within Debian, but Argyll provides a tool to
+extract that firmware from the driver CD provided with the device.
+
+If you're only using your Spyder2 on one computer, then all you need
+to do is run the "spyd2en -S l" utility (as root) while the driver CD
+is mounted. spyd2en looks for the CD in a few typical mount points
+(/media/ColorVision, /mnt/cdrom, /media/cdrom, /cdrom). If your CD is
+mounted somewhere else, just add the location of the "setup.exe" file,
+for instance "spyd2en -S l /mnt/tmp/setup/setup.exe". In both cases,
+the firmware will be extracted and stored into
+/usr/share/color/spyd2PLD.bin, where the other utilities will be able
+to look for it when needed. You're done!
+
+If you use the Spyder2 on several computers, and don't want to carry
+the CD and perform the same operation on all, you might like to
+generate a Debian package containing the firmware on one computer, and
+install that package on the others. A source package is provided in
+/usr/share/doc/argyll/examples/spyder2.tar.gz. Here's the procedure
+for the first computer:
+
+- first, extract the firmware with spyd2en (as above);
+- then, apt-get install debhelper fakeroot build-essential;
+- uncompress the spyder2.tar.gz archive somewhere;
+ you'll get a argyll-firmware-spyder2 directory;
+- in that directory, run "fakeroot debian/rules binary clean";
+- you should get a .deb in the parent directory.
+
+You can then copy that .deb file to other computers and install it
+with "dpkg -i argyll-firmware-spyder2_1.1_all.deb". You're done!
+
+ -- Roland Mas <lolando@debian.org>, Thu, 05 Aug 2010 15:44:23 +0200
diff --git a/debian/applycal.1 b/debian/applycal.1
new file mode 100644
index 0000000..12aef3f
--- /dev/null
+++ b/debian/applycal.1
@@ -0,0 +1,59 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH APPLY "1" "August 2013" "Apply device calibration to an ICC profile, Version 1.5.1" "User Commands"
+.SH NAME
+Apply \- Apply device calibration to an ICC profile.
+.SH DESCRIPTION
+Apply device calibration to an ICC profile, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Too few arguments
+.PP
+usage: applycal [\-options] [calfile.cal] inprof.icc [outprof.icc]
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-a\fR
+Apply or re\-apply calibration (default)
+.TP
+\fB\-u\fR
+Remove calibration
+.TP
+\fB\-c\fR
+Check calibration
+.TP
+calfile.cal
+Calibration file to apply
+.TP
+inprof.icc
+ICC profile to read
+.TP
+outprof.icc
+modified ICC profile to write
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Too few arguments
+.PP
+usage: applycal [\-options] [calfile.cal] inprof.icc [outprof.icc]
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-a\fR
+Apply or re\-apply calibration (default)
+.TP
+\fB\-u\fR
+Remove calibration
+.TP
+\fB\-c\fR
+Check calibration
+.TP
+calfile.cal
+Calibration file to apply
+.TP
+inprof.icc
+ICC profile to read
+.TP
+outprof.icc
+modified ICC profile to write
diff --git a/debian/argyll.examples b/debian/argyll.examples
new file mode 100644
index 0000000..7f1dbaa
--- /dev/null
+++ b/debian/argyll.examples
@@ -0,0 +1 @@
+firmware-package-builder/spyder2.tar.gz
diff --git a/debian/argyll.install b/debian/argyll.install
new file mode 100644
index 0000000..4bb69a1
--- /dev/null
+++ b/debian/argyll.install
@@ -0,0 +1,50 @@
+usb/55-Argyll.rules lib/udev/rules.d/
+usb/Argyll.usermap etc/hotplug/usb
+usr/bin/applycal
+usr/bin/average
+usr/bin/cb2ti3
+usr/bin/cctiff
+usr/bin/ccttest
+usr/bin/ccxxmake
+usr/bin/chartread
+usr/bin/collink
+usr/bin/colprof
+usr/bin/dispcal
+usr/bin/dispread
+usr/bin/dispwin
+usr/bin/extracticc
+usr/bin/extractttag
+usr/bin/fakeCMY
+usr/bin/fakeread
+usr/bin/greytiff
+usr/bin/iccgamut
+usr/bin/illumread
+usr/bin/invprofcheck
+usr/bin/kodak2ti3
+usr/bin/mppcheck
+usr/bin/mpplu
+usr/bin/mppprof
+usr/bin/pathplot
+usr/bin/printcal
+usr/bin/printtarg
+usr/bin/profcheck
+usr/bin/refine
+usr/bin/revfix
+usr/bin/scanin
+usr/bin/simpprof
+usr/bin/spec2cie
+usr/bin/specplot
+usr/bin/splitti3
+usr/bin/spotread
+usr/bin/synthcal
+usr/bin/synthread
+usr/bin/targen
+usr/bin/tiffgamut
+usr/bin/txt2ti3
+usr/bin/verify
+usr/bin/viewgam
+usr/bin/xicclu
+usr/lib/*/argyll/*
+usr/share/color/argyll/ref/*
+usr/share/doc/argyll/*
+usr/bin/oeminst
diff --git a/debian/argyll.manpages b/debian/argyll.manpages
new file mode 100644
index 0000000..59f586e
--- /dev/null
+++ b/debian/argyll.manpages
@@ -0,0 +1,45 @@
+debian/applycal.1
+debian/average.1
+debian/cb2ti3.1
+debian/cctiff.1
+debian/ccttest.1
+debian/ccxxmake.1
+debian/chartread.1
+debian/collink.1
+debian/colprof.1
+debian/dispcal.1
+debian/dispread.1
+debian/dispwin.1
+debian/extracticc.1
+debian/extractttag.1
+debian/fakeCMY.1
+debian/fakeread.1
+debian/greytiff.1
+debian/iccgamut.1
+debian/illumread.1
+debian/invprofcheck.1
+debian/kodak2ti3.1
+debian/mppcheck.1
+debian/mpplu.1
+debian/mppprof.1
+debian/oeminst.1
+debian/pathplot.1
+debian/printcal.1
+debian/printtarg.1
+debian/profcheck.1
+debian/refine.1
+debian/revfix.1
+debian/scanin.1
+debian/simpprof.1
+debian/spec2cie.1
+debian/specplot.1
+debian/splitti3.1
+debian/spotread.1
+debian/synthcal.1
+debian/synthread.1
+debian/targen.1
+debian/tiffgamut.1
+debian/txt2ti3.1
+debian/verify.1
+debian/viewgam.1
+debian/xicclu.1
diff --git a/debian/argyll.postrm b/debian/argyll.postrm
new file mode 100644
index 0000000..4a165ab
--- /dev/null
+++ b/debian/argyll.postrm
@@ -0,0 +1,35 @@
+#! /bin/sh
+# postrm script for argyll
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <r>overwrit>r> <new-version>
+# for details, see /usr/share/doc/packaging-manual/
+
+case "$1" in
+ purge)
+ rm -rf /var/lib/argyll
+ ;;
+ remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+ ;;
+
+ *)
+ echo "postrm called with unknown argument \`$1'" >&2
+ exit 0
+
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
diff --git a/debian/argyll.preinst b/debian/argyll.preinst
new file mode 100644
index 0000000..200ce8a
--- /dev/null
+++ b/debian/argyll.preinst
@@ -0,0 +1,57 @@
+#!/bin/sh
+# preinst script for #PACKAGE#
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <new-preinst> `install'
+# * <new-preinst> `install' <old-version>
+# * <new-preinst> `upgrade' <old-version>
+# * <old-preinst> `abort-upgrade' <new-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+# Remove a no-longer used conffile
+rm_conffile() {
+ local PKGNAME="$1"
+ local CONFFILE="$2"
+
+ [ -e "$CONFFILE" ] || return 0
+
+ local md5sum="$(md5sum $CONFFILE | sed -e 's/ .*//')"
+ local old_md5sum="$(dpkg-query -W -f='${Conffiles}' $PKGNAME | \
+ sed -n -e "\' $CONFFILE ' { s/ obsolete$//; s/.* //; p }")"
+ if [ "$md5sum" != "$old_md5sum" ]; then
+ echo "Obsolete conffile $CONFFILE has been modified by you."
+ echo "Saving as $CONFFILE.dpkg-bak ..."
+ mv -f "$CONFFILE" "$CONFFILE".dpkg-bak
+ else
+ echo "Removing obsolete conffile $CONFFILE ..."
+ rm -f "$CONFFILE"
+ fi
+}
+
+case "$1" in
+ install|upgrade)
+ if dpkg --compare-versions "$2" le "1.1.0-3"; then
+ rm_conffile argyll "/etc/udev/permissions.d/10-Argyll.permissions"
+ rm_conffile argyll "/etc/udev/rules.d/45-Argyll.rules"
+ rm_conffile argyll "/etc/udev/rules.d/55-Argyll.rules"
+ fi
+ ;;
+ abort-upgrade)
+ ;;
+ *)
+ echo "preinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+esac
+
+# dh_installdeb will replace this with shell code automatically
+# generated by other debhelper scripts.
+
+#DEBHELPER#
+
+exit 0
diff --git a/debian/average.1 b/debian/average.1
new file mode 100644
index 0000000..38b43c3
--- /dev/null
+++ b/debian/average.1
@@ -0,0 +1,52 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH AVERAGE "1" "August 2013" "Average or merge values in .ti3 like files, Version 1.5.1" "User Commands"
+.SH NAME
+Average \- Average or merge values in .ti3 like files.
+.SH DESCRIPTION
+Average or merge values in .ti3 like files, Version 1.5.1
+.IP
+Diagnostic: Too few arguments (1, minimum is 2)
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: average [\-options] input1.ti3 input2.ti3 ... output.ti3
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-m\fR
+Merge rather than average
+.TP
+input1.ti3
+First input file
+.TP
+input2.ti3
+Second input file
+.TP
+\&...
+etc.
+.TP
+output.ti3
+Resulting averaged or merged output file
+.IP
+Diagnostic: Too few arguments (1, minimum is 2)
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: average [\-options] input1.ti3 input2.ti3 ... output.ti3
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-m\fR
+Merge rather than average
+.TP
+input1.ti3
+First input file
+.TP
+input2.ti3
+Second input file
+.TP
+\&...
+etc.
+.TP
+output.ti3
+Resulting averaged or merged output file
diff --git a/debian/cb2ti3.1 b/debian/cb2ti3.1
new file mode 100644
index 0000000..93b39d4
--- /dev/null
+++ b/debian/cb2ti3.1
@@ -0,0 +1,35 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CONVERT "1" "August 2013" "Convert Colorblind raw device profile data to Argyll data, Version 1.5.1" "User Commands"
+.SH NAME
+Convert \- Convert Colorblind raw device profile data to Argyll data.
+.SH DESCRIPTION
+Convert Colorblind raw device profile data to Argyll data, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: cb2ti3 [\-v] [\-l limit] infile outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-l\fR limit
+Set inklimit in .ti3 file
+.TP
+infile
+Base name for input.CMY and input.nCIE file
+.TP
+outfile
+Base name for output.ti3 file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: cb2ti3 [\-v] [\-l limit] infile outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-l\fR limit
+Set inklimit in .ti3 file
+.TP
+infile
+Base name for input.CMY and input.nCIE file
+.TP
+outfile
+Base name for output.ti3 file
diff --git a/debian/cctiff.1 b/debian/cctiff.1
new file mode 100644
index 0000000..7198186
--- /dev/null
+++ b/debian/cctiff.1
@@ -0,0 +1,145 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH COLOR "1" "August 2013" "Color Correct a TIFF or JPEG file using any sequence of ICC profiles or Calibrations, V1.5.1" "User Commands"
+.SH NAME
+Color \- Color Correct a TIFF file using any sequence of ICC profiles or Calibrations.
+.SH DESCRIPTION
+Color Correct a TIFF or JPEG file using any sequence of ICC profiles or Calibrations, V1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Unknown flag '\-'
+.PP
+usage: cctiff [\-options] { [\-i intent] profile.icc | calbrtn.cal ...} infile.tif/jpg outfile.tif/jpg
+.TP
+\fB\-v\fR
+Verbose.
+.TP
+\fB\-c\fR
+Combine linearisation curves into one transform.
+.TP
+\fB\-p\fR
+Use slow precise correction.
+.TP
+\fB\-k\fR
+Check fast result against precise, and report.
+.TP
+\fB\-r\fR n
+Override the default CLUT resolution
+.TP
+\fB\-t\fR n
+Choose output encoding from 1..n
+.TP
+\fB\-f\fR [T|J]
+Set output format to Tiff or Jpeg (Default is same as input)
+.TP
+\fB\-q\fR quality
+Set JPEG quality 1..100 (Default 80)
+.TP
+\fB\-a\fR
+Read and Write planes > 4 as alpha planes
+.TP
+\fB\-I\fR
+Ignore any file or profile colorspace mismatches
+.TP
+\fB\-D\fR
+Don't append or set the output TIFF or JPEG description
+.TP
+\fB\-e\fR profile.[icc | tiff | jpg]
+Optionally embed a profile in the destination TIFF or JPEG file.
+.IP
+Then for each profile in sequence:
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute colorimetric
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+profile.[icc | tiff]
+Device, Link or Abstract profile
+.IP
+( May be embedded profile in TIFF/JPEG file)
+.IP
+or each calibration file in sequence:
+.TP
+\fB\-d\fR dir
+f = forward cal. (default), b = backwards cal.
+.TP
+calbrtn.cal
+Device calibration file.
+.TP
+infile.tif/jpg
+Input TIFF/JPEG file in appropriate color space
+.IP
+outfile.tif/jpg Output TIFF/JPEG file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Unknown flag '\-'
+.PP
+usage: cctiff [\-options] { [\-i intent] profile.icc | calbrtn.cal ...} infile.tif/jpg outfile.tif/jpg
+.TP
+\fB\-v\fR
+Verbose.
+.TP
+\fB\-c\fR
+Combine linearisation curves into one transform.
+.TP
+\fB\-p\fR
+Use slow precise correction.
+.TP
+\fB\-k\fR
+Check fast result against precise, and report.
+.TP
+\fB\-r\fR n
+Override the default CLUT resolution
+.TP
+\fB\-t\fR n
+Choose output encoding from 1..n
+.TP
+\fB\-f\fR [T|J]
+Set output format to Tiff or Jpeg (Default is same as input)
+.TP
+\fB\-q\fR quality
+Set JPEG quality 1..100 (Default 80)
+.TP
+\fB\-a\fR
+Read and Write planes > 4 as alpha planes
+.TP
+\fB\-I\fR
+Ignore any file or profile colorspace mismatches
+.TP
+\fB\-D\fR
+Don't append or set the output TIFF or JPEG description
+.TP
+\fB\-e\fR profile.[icc | tiff | jpg]
+Optionally embed a profile in the destination TIFF or JPEG file.
+.IP
+Then for each profile in sequence:
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute colorimetric
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+profile.[icc | tiff]
+Device, Link or Abstract profile
+.IP
+( May be embedded profile in TIFF/JPEG file)
+.IP
+or each calibration file in sequence:
+.TP
+\fB\-d\fR dir
+f = forward cal. (default), b = backwards cal.
+.TP
+calbrtn.cal
+Device calibration file.
+.TP
+infile.tif/jpg
+Input TIFF/JPEG file in appropriate color space
+.IP
+outfile.tif/jpg Output TIFF/JPEG file
diff --git a/debian/ccttest.1 b/debian/ccttest.1
new file mode 100644
index 0000000..749f61c
--- /dev/null
+++ b/debian/ccttest.1
@@ -0,0 +1,19 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH PLOT "1" "August 2013" "Plot spectrum and calculate CCT and VCT" "User Commands"
+.SH NAME
+Plot \- Plot spectrum and calculate CCT and VCT.
+.SH DESCRIPTION
+Plot spectrum and calculate CCT and VCT
+Author: Graeme W. Gill
+usage: ccttest [infile.sp]
+.TP
+[infile.sp]
+spectrum to plot
+default is all built in illuminants
+.PP
+Author: Graeme W. Gill
+usage: ccttest [infile.sp]
+.TP
+[infile.sp]
+spectrum to plot
+default is all built in illuminants
diff --git a/debian/ccxxmake.1 b/debian/ccxxmake.1
new file mode 100644
index 0000000..afae2c7
--- /dev/null
+++ b/debian/ccxxmake.1
@@ -0,0 +1,171 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create CCMX or CCSS, Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create CCMX or CCSS.
+.SH DESCRIPTION
+Create CCMX or CCSS, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Flag '\-\-' not recognised
+usage: ccmxmake [\-options] output.ccmx
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-S\fR
+Create CCSS rather than CCMX
+.HP
+\fB\-f\fR file1.ti3[,file2.ti3] Create from one or two .ti3 files rather than measure.
+.TP
+\fB\-display\fR displayname
+Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 name = ':0.0'
+1 = 'Screen 1, Output VBOX0 at 0, 0, width 1605, height 1079'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for CCMX spectrometer data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-s\fR steps
+Override default patch sequence combination steps (default 1)
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+\fB\-E\fR desciption
+Override the default overall description
+.TP
+\fB\-I\fR displayname
+Set display make and model description
+.TP
+\fB\-T\fR displaytech
+Set display technology description (ie. CRT, LCD etc.)
+.TP
+\fB\-U\fR c
+Set UI selection character(s)
+.TP
+\fB\-Y\fR r|n
+Set or override refresh/non\-refresh display type
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.IP
+correction.ccmx | calibration.ccss
+.IP
+File to save result to
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Flag '\-\-' not recognised
+usage: ccmxmake [\-options] output.ccmx
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-S\fR
+Create CCSS rather than CCMX
+.HP
+\fB\-f\fR file1.ti3[,file2.ti3] Create from one or two .ti3 files rather than measure.
+.TP
+\fB\-display\fR displayname
+Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 name = ':0.0'
+1 = 'Screen 1, Output VBOX0 at 0, 0, width 1605, height 1079'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for CCMX spectrometer data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-s\fR steps
+Override default patch sequence combination steps (default 1)
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+\fB\-E\fR desciption
+Override the default overall description
+.TP
+\fB\-I\fR displayname
+Set display make and model description
+.TP
+\fB\-T\fR displaytech
+Set display technology description (ie. CRT, LCD etc.)
+.TP
+\fB\-U\fR c
+Set UI selection character(s)
+.TP
+\fB\-Y\fR r|n
+Set or override refresh/non\-refresh display type
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.IP
+correction.ccmx | calibration.ccss
+.IP
+File to save result to
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..80983b1
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,506 @@
+argyll (1.5.1-8) unstable; urgency=medium
+
+ * QA upload.
+ * Add a symbols file for libicc2 and libimdi0.
+
+ -- Iain Lane <laney@debian.org> Mon, 09 Jun 2014 12:52:11 +0100
+
+argyll (1.5.1-7) unstable; urgency=medium
+
+ * QA upload.
+ * debian/control: Bump udev recommended version to >= 196
+
+ -- Laurent Bigonville <bigon@debian.org> Sun, 04 May 2014 22:30:57 +0200
+
+argyll (1.5.1-6) unstable; urgency=medium
+
+ * QA upload.
+ * debian/patches/03_usb-db.diff: Use hwdb builtin, instead of the obsolete
+ usb-db in the udev rules.
+ * debian/patches/06_fix_udev_rule.patch: Fix udev rules to actually work;
+ ENV{ACL_MANAGE} has stopped working ages ago, and with logind it's now the
+ "uaccess" tag. Dropping also consolekit from Recommends. (Closes: #746974)
+ * debian/rules: Add libpam-systemd as a recommends to be sure we have a
+ session registered, this is needed for the permissions on the devices.
+ * debian/control: Build-depend on libtiff-dev rather than libtiff4-dev.
+ (Closes: #733126)
+ * debian/control: Drop Uploaders as the package has been orphaned
+ * debian/control: Bump Standards-Version to 3.9.5 (no further changes)
+
+ -- Laurent Bigonville <bigon@debian.org> Sun, 04 May 2014 21:36:24 +0200
+
+argyll (1.5.1-5) unstable; urgency=low
+
+ * Package orphaned. I don't intent to support the work of an agressive
+ upstream author more longer and realy good luck for the next maintainer.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 19 Aug 2013 14:18:29 +0200
+
+argyll (1.5.1-4) unstable; urgency=low
+
+ * Revert previous yajl patch this break argyll.
+ * Regenerate all manpages.
+ * Add colord and gir1.2-colordgtk-1.0 in Suggests.
+ * Don't package .a and .la files.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 12 Aug 2013 15:51:54 +0200
+
+argyll (1.5.1-3) unstable; urgency=low
+
+ * Uptade patch 01_autotools-support with patch from bug report to link
+ argyll against external yajl also add an one line patch called
+ 05_external-yajl (Closes: #544223)
+
+ -- Christian Marillat <marillat@debian.org> Fri, 02 Aug 2013 08:10:38 +0200
+
+argyll (1.5.1-2) unstable; urgency=low
+
+ * Package iccdump.1 and icclu.1 only in icc-utils package
+ (Closes: #717990, # 717993).
+
+ -- Christian Marillat <marillat@debian.org> Sat, 27 Jul 2013 21:43:59 +0200
+
+argyll (1.5.1-1) unstable; urgency=low
+
+ * New upstream release.
+ * Removed 03_kfreebsd patch.
+ * Refresh 01_autotools-support patch (CLoses: 713545)
+ * New patch 03_usb-db to add support for newer udev (Closes: 717504)
+
+ -- Christian Marillat <marillat@debian.org> Fri, 26 Jul 2013 16:25:19 +0200
+
+argyll (1.4.0-8) unstable; urgency=low
+
+ * Add a Breaks field and update the version in the Replaces field for the
+ icc-utils package (Closes: #694287)
+
+ -- Christian Marillat <marillat@debian.org> Sun, 25 Nov 2012 09:59:35 +0100
+
+argyll (1.4.0-7) unstable; urgency=high
+
+ * New patch 04_CVE-2012-4405.diff to fix CVE-2012-4405 issue
+ (Closes: #687275)
+
+ -- Christian Marillat <marillat@debian.org> Tue, 11 Sep 2012 13:45:12 +0200
+
+argyll (1.4.0-6) unstable; urgency=low
+
+ * Use dh_autoreconf (Closes: #678909)
+
+ -- Christian Marillat <marillat@debian.org> Mon, 25 Jun 2012 07:52:56 +0200
+
+argyll (1.4.0-5) unstable; urgency=low
+
+ * Refresh 01_autotools-support patch (Closes: #678750).
+
+ -- Christian Marillat <marillat@debian.org> Mon, 25 Jun 2012 00:01:31 +0200
+
+argyll (1.4.0-4) unstable; urgency=low
+
+ * Should Build-Depends on libusb-dev (Closes: #670329).
+
+ -- Christian Marillat <marillat@debian.org> Wed, 25 Apr 2012 07:46:07 +0200
+
+argyll (1.4.0-3) unstable; urgency=low
+
+ * Fix kfreebsd build. Thanks to Robert Millan for the patch.
+ (Closes: #595951 #630208).
+
+ -- Christian Marillat <marillat@debian.org> Tue, 24 Apr 2012 07:49:03 +0200
+
+argyll (1.4.0-2) unstable; urgency=low
+
+ * Move binaries from libicc2 package to a new icc-utils package (Closes:
+ #670003).
+
+ -- Christian Marillat <marillat@debian.org> Sun, 22 Apr 2012 16:07:43 +0200
+
+argyll (1.4.0-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Christian Marillat <marillat@debian.org> Sat, 21 Apr 2012 15:53:50 +0200
+
+argyll (1.3.7-1.1) unstable; urgency=low
+
+ * Use DEB_LDFLAGS_MAINT_APPEND to add more LDFLAGS (Closes: #667924)
+
+ -- Christian Marillat <marillat@debian.org> Mon, 09 Apr 2012 10:45:56 +0200
+
+argyll (1.3.7-1) unstable; urgency=low
+
+ * New upstream release.
+ * Try to fix the build (Thanks to Dmitry Nezhevenko) (Closes: #665055).
+ * Move to debhelper 9 for multi-arch and hardened flags.
+
+ -- Christian Marillat <marillat@debian.org> Tue, 03 Apr 2012 08:46:37 +0200
+
+argyll (1.3.6-3) unstable; urgency=low
+
+ * Call dh_quilt_unpatch after MAKE distclean.
+ * Rework Makefile test to be sure we don't call upstream Makefile with
+ missing distclean target.
+
+ -- Christian Marillat <marillat@debian.org> Tue, 20 Mar 2012 14:44:40 +0100
+
+argyll (1.3.6-2) unstable; urgency=low
+
+ * debian/rules Fix clean target.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 19 Mar 2012 16:50:40 +0100
+
+argyll (1.3.6-1) unstable; urgency=low
+
+ * New upstream release.
+ * Removed 03_add-ColorHug_sensor_driver patch, but beware the support for
+ ColorHug is experimental.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 19 Mar 2012 10:55:20 +0100
+
+argyll (1.3.5-7) unstable; urgency=low
+
+ * Really fix previous bug.
+ * Use debhelper 9.
+
+ -- Christian Marillat <marillat@debian.org> Tue, 13 Mar 2012 08:41:01 +0100
+
+argyll (1.3.5-6) unstable; urgency=low
+
+ * Fix another bug in ColorHugColorHug (Closes: #661643)
+
+ -- Christian Marillat <marillat@debian.org> Sun, 11 Mar 2012 16:59:06 +0100
+
+argyll (1.3.5-5) unstable; urgency=low
+
+ * Fix two bugs in ColorHugColorHug patch (Closes: #657582).
+
+ -- Christian Marillat <marillat@debian.org> Sat, 28 Jan 2012 01:42:30 +0100
+
+argyll (1.3.5-4) unstable; urgency=low
+
+ * New patch 03_add-ColorHug_sensor_driver to add support for the ColorHug
+ sensor (Closes: #655888)
+
+ -- Christian Marillat <marillat@debian.org> Tue, 17 Jan 2012 18:22:51 +0100
+
+argyll (1.3.5-3) unstable; urgency=low
+
+ * debian/rules Enable make distclean (Closes: #649728).
+
+ -- Christian Marillat <marillat@debian.org> Wed, 23 Nov 2011 15:17:42 +0100
+
+argyll (1.3.5-2) unstable; urgency=low
+
+ * Don't package icclu and iccdump binaries in argyll, files already in
+ libicc2 package.
+
+ -- Christian Marillat <marillat@debian.org> Mon, 21 Nov 2011 08:25:40 +0100
+
+argyll (1.3.5-1) unstable; urgency=low
+
+ [ Christian Marillat ]
+ * New maintainer (Closes: #622620) Thanks, Roland!
+ * Use dh-autoreconf.
+
+ [ Dmitry Nezhevenko ]
+ * New upstream release (Closes: #647093).
+ * Switch to dpkg-source 3.0 (quilt) format.
+ * Merge debian changes from 1.3.0 (experimental) and 1.1.1 (unstable).
+ * Unsplit libicc2, built from the same source package again (since
+ upstream only ships it as part of Argyll anyway). Actually was already
+ done in experimental (Closes: #636801).
+ * Use kfreebsd-any instead of kfreebsd-(i386|amd64) to match kFreeBSD
+ (Closes: #634688).
+ * Provide dedicated libimdi0/libimdi-dev libraries (Closes: #611139).
+ * Add argyll-dbg package with debug symbols.
+
+ -- Christian Marillat <marillat@debian.org> Sun, 13 Nov 2011 15:30:42 +0100
+
+argyll (1.3.0-3) experimental; urgency=low
+
+ * Minor future-proofing in debian/rules.
+ * Also removed redundant shipping of the firmware-package-builder
+ tarball, thanks to Pascal de Bruijn for noticing.
+
+ -- Roland Mas <lolando@debian.org> Fri, 17 Sep 2010 11:05:22 +0200
+
+argyll (1.3.0-2) experimental; urgency=low
+
+ * Fixed packaging bugs introduced when un-splitting the source package.
+
+ -- Roland Mas <lolando@debian.org> Tue, 14 Sep 2010 11:29:27 +0200
+
+argyll (1.3.0-1) experimental; urgency=low
+
+ * New upstream release.
+
+ -- Roland Mas <lolando@debian.org> Wed, 08 Sep 2010 15:16:29 +0200
+
+argyll (1.2.1-1) experimental; urgency=low
+
+ * New upstream bugfix release.
+ * Please welcome Xavier Oswald as uploader.
+
+ -- Roland Mas <lolando@debian.org> Sun, 05 Sep 2010 15:50:41 +0200
+
+argyll (1.2.0-0) UNRELEASED; urgency=low
+
+ * New upstream release.
+ * Unsplit libicc2, built from the same source package again (since
+ upstream only ships it as part of Argyll anyway).
+ * Bumped Standards-Version to 3.9.1 (no changes).
+ * argyll-firmware-spyder2: Moved firmware to /usr/share/color, which is
+ freedesktop.org-compliant and (more to the point) where Argyll 1.2.0
+ looks for it.
+
+ -- Roland Mas <lolando@debian.org> Thu, 05 Aug 2010 15:33:20 +0200
+
+argyll (1.1.1-2) unstable; urgency=medium
+
+ * QA upload.
+ * Add ../libargyll.la to LDADD (Closes: #615692).
+ * Don't ship .la files (Closes: #621142).
+
+ -- Luk Claes <luk@debian.org> Sat, 11 Jun 2011 11:18:43 +0200
+
+argyll (1.1.1-1) unstable; urgency=low
+
+ * New upstream release.
+ * Switched dependency on policykit-1 to a more correct recommendation on
+ consolekit + recent udev.
+ * Updated copyright file (doc is now GFDL-1.3).
+ * Bumped Standards-Version to 3.8.4 (no changes required).
+
+ -- Roland Mas <lolando@debian.org> Wed, 24 Feb 2010 21:26:55 +0100
+
+argyll (1.1.0-5) unstable; urgency=low
+
+ * Bumped version build-dependency on libicc-dev to prevent segmentation
+ fault.
+
+ -- Roland Mas <lolando@debian.org> Mon, 25 Jan 2010 19:06:07 +0100
+
+argyll (1.1.0-4) unstable; urgency=low
+
+ * Adapted packaging to new udev rules, now compatible with PolicyKit-1
+ (closes: #529411). This should fix device file permissions problems,
+ too (closes: #549406). And also the "deprecated udev function"
+ warning (closes: #564269).
+ * Removed conffiles no longer shipped by the package.
+
+ -- Roland Mas <lolando@debian.org> Mon, 25 Jan 2010 13:47:59 +0100
+
+argyll (1.1.0-3) unstable; urgency=low
+
+ * Only depend on udev for Linux systems.
+
+ -- Roland Mas <lolando@debian.org> Mon, 25 Jan 2010 11:42:54 +0100
+
+argyll (1.1.0-2) unstable; urgency=low
+
+ * Fix build on FreeBSD, patch from Petr Salinger
+ <Petr.Salinger@seznam.cz> (closes: #566768).
+
+ -- Roland Mas <lolando@debian.org> Mon, 25 Jan 2010 10:29:33 +0100
+
+argyll (1.1.0-1) unstable; urgency=low
+
+ * New upstream release, including a patch obtained from upstream just
+ after the actual release.
+ * Also, stop using the system's libusb, which causes known problems with
+ Argyll. Now using Argyll's patched copy (privately, since the patches
+ cause problems with other software).
+
+ -- Roland Mas <lolando@debian.org> Sun, 24 Jan 2010 23:34:18 +0100
+
+argyll (1.1.0~rc4-1) unstable; urgency=low
+
+ * New upstream pre-release.
+ * Ship all doc files with a wildcard rule, rather than a fixed (and
+ outdated) set.
+
+ -- Roland Mas <lolando@debian.org> Wed, 06 Jan 2010 10:33:54 +0100
+
+argyll (1.1.0~rc3-1) unstable; urgency=low
+
+ * New upstream pre-release.
+ * Moved udev rules file to /lib/udev/rules.d.
+
+ -- Roland Mas <lolando@debian.org> Tue, 05 Jan 2010 14:49:38 +0100
+
+argyll (1.1.0~rc2-1) unstable; urgency=low
+
+ * New upstream pre-release.
+ * Updated location of Bazaar branches in control file.
+ * The Debian-specific branch now feeds from the "midstream" branch
+ rather than the "upstream-releases" branch, to ease collaboration with
+ other distributions. This shouldn't make any difference on the
+ package contents.
+
+ -- Roland Mas <lolando@debian.org> Thu, 10 Dec 2009 17:26:04 +0100
+
+argyll (1.1.0~rc1+dfsg-1) unstable; urgency=low
+
+ * Removed non-free IETF RFC/I-D from source package, thanks to Simon
+ Josefsson (closes: #555377).
+
+ -- Roland Mas <lolando@debian.org> Sat, 14 Nov 2009 20:23:53 +0100
+
+argyll (1.1.0~rc1-3) unstable; urgency=low
+
+ * Added Build-Depends: libusbhid-dev for kFreeBSD architectures.
+
+ -- Roland Mas <lolando@debian.org> Mon, 09 Nov 2009 13:34:54 +0100
+
+argyll (1.1.0~rc1-2) unstable; urgency=low
+
+ * Fixed build on GNU/kFreeBSD ports.
+ * Applied patch from upstream that fixes an infinite loop if Xrandr is
+ enabled.
+
+ -- Roland Mas <lolando@debian.org> Mon, 09 Nov 2009 11:46:57 +0100
+
+argyll (1.1.0~rc1-1) unstable; urgency=low
+
+ * New upstream pre-release.
+ * Updated debian/copyright (upstream switched to Affero GPLv3).
+ * Bumped versioned build-dependency on debhelper.
+ * Bumped standards version to 3.8.3 (no changes needed).
+
+ -- Roland Mas <lolando@debian.org> Sun, 08 Nov 2009 22:19:45 +0100
+
+argyll (1.0.4-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Roland Mas <lolando@debian.org> Fri, 03 Jul 2009 14:14:11 +0200
+
+argyll (1.0.3+dfsg1-3) unstable; urgency=low
+
+ * libicc is now a separate source+binary package, so argyll now links
+ against it.
+ * Since that new libicc is a proper new upstream snapshot, the problems
+ introduced with the local patches should be fixed (closes: #524478).
+
+ -- Roland Mas <lolando@debian.org> Tue, 02 Jun 2009 11:26:01 +0200
+
+argyll (1.0.3+dfsg1-2) unstable; urgency=low
+
+ * Adapted debian/watch file to match version mangling.
+ * Updated autotools build system to dynamically link against the
+ internal libraries and provide a libicc.so for dynamic linking.
+ * Also ship the corresponding header files.
+ * Not splitting libicc into its own binary package just yet though, I
+ want to get more testing of the dynamic linking first.
+
+ -- Roland Mas <lolando@debian.org> Thu, 14 May 2009 16:49:44 +0200
+
+argyll (1.0.3+dfsg1-1) unstable; urgency=low
+
+ * argyll-firmware-spyder2 is now generated as section non-free/graphics
+ rather than just graphics.
+ * Removed non-free RFC from source package (closes: #524972).
+
+ -- Roland Mas <lolando@debian.org> Tue, 28 Apr 2009 11:47:38 +0200
+
+argyll (1.0.3-5) unstable; urgency=low
+
+ * Documented web interface for the Bazaar repository.
+ * Added source package for the Spyder2 firmware.
+
+ -- Roland Mas <lolando@debian.org> Fri, 17 Apr 2009 23:34:40 +0200
+
+argyll (1.0.3-4) unstable; urgency=low
+
+ * Actually create /var/lib/argyll so spyd2en can store its firmware in
+ it... also remove it on purge.
+ * Also look for the Spyder2 firmware in /lib/firmware.
+ * Shortened debian/rules quite a bit thanks to Debhelper 7.
+ * Fixed build rules so testsuite passes.
+ * Bumped standards-version to 3.8.1 (no changes).
+
+ -- Roland Mas <lolando@debian.org> Thu, 16 Apr 2009 11:25:26 +0200
+
+argyll (1.0.3-3) unstable; urgency=low
+
+ * Another patch for icclib, this time from Jan Lieskovsky, fixing some
+ more vulnerabilities described in CVE-2009-0792 (closes: #523472).
+
+ -- Roland Mas <lolando@debian.org> Fri, 10 Apr 2009 17:53:55 +0200
+
+argyll (1.0.3-2) unstable; urgency=low
+
+ * Patched embedded copy of icclib to fix integer overflow and denial of
+ service vulnerabilities as described in CVE-2009-0583 and
+ CVE-2009-0584. Patch provided by Moritz Muehlenhoff and the Debian
+ security team (closes: #522448).
+
+ -- Roland Mas <lolando@debian.org> Fri, 03 Apr 2009 22:43:14 +0200
+
+argyll (1.0.3-1) unstable; urgency=low
+
+ * New upstream release.
+ * Adopted package from Christian Marillat's Debian-Multimedia
+ repository (closes: #498396). Thanks, Christian!
+ * Stopped removing some files in clean target.
+ * Switched build-system to autotools.
+ * Link to system libusb rather than locally-shipped one.
+ * Fixed watch file.
+ * Moved Spyder2 firmware to /var/lib/argyll.
+ * Added detailed debian/copyright file.
+ * Use dh_prep instead of dh_clean -k.
+ * Rename /usr/bin/foo to /usr/bin/argyll-foo, for foo in
+ {average,refine,targen,verify}, to avoid having binaries with too
+ generic names. Documented in README.Debian.
+
+ -- Roland Mas <lolando@debian.org> Thu, 19 Feb 2009 20:34:48 +0100
+
+argyll (1.0.0-0.0) unstable; urgency=low
+
+ * New upstream release.
+ * Added configuration files for udev, hal and policykit.
+
+ -- Christian Marillat <marillat@debian.org> Fri, 18 Jul 2008 08:51:45 +0200
+
+argyll (0.60-0.1) unstable; urgency=low
+
+ * Need to Build-depends on libxinerama-dev instead of x11proto-xinerama-dev.
+
+ -- Christian Marillat <marillat@debian.org> Fri, 21 Jul 2006 06:25:46 +0200
+
+argyll (0.60-0.0) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Christian Marillat <marillat@debian.org> Thu, 20 Jul 2006 10:56:43 +0200
+
+argyll (0.53.1-0.2) unstable; urgency=low
+
+ * Apply a patch from Guido to fix build under ppc.
+
+ -- Christian Marillat <marillat@debian.org> Tue, 23 May 2006 14:40:45 +0200
+
+argyll (0.53.1-0.1) unstable; urgency=low
+
+ * Add libxxf86vm-dev and x11proto-xf86vidmode-dev in build-Depends.
+
+ -- Christian Marillat <marillat@debian.org> Fri, 12 May 2006 16:27:46 +0200
+
+argyll (0.53.1-0.0) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Christian Marillat <marillat@debian.org> Thu, 9 Feb 2006 13:56:03 +0100
+
+argyll (0.53-0.1) unstable; urgency=low
+
+ * Rename icclink in icclink-argyll.
+ * Rename sprof in sprof-argyll.
+
+ -- Christian Marillat <marillat@debian.org> Wed, 8 Feb 2006 11:42:15 +0100
+
+argyll (0.53-0.0) unstable; urgency=low
+
+ * Initial release.
+
+ -- Christian Marillat <marillat@debian.org> Sun, 5 Feb 2006 22:08:11 +0100
diff --git a/debian/chartread.1 b/debian/chartread.1
new file mode 100644
index 0000000..d4d0bbf
--- /dev/null
+++ b/debian/chartread.1
@@ -0,0 +1,185 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH READ "1" "August 2013" "Read Target Test Chart, Version 1.5.1" "User Commands"
+.SH NAME
+Read \- Read Target Test Chart.
+.SH DESCRIPTION
+Read Target Test Chart, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: chartread [\-options] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-t\fR
+Use transmission measurement mode
+.TP
+\fB\-d\fR
+Use display measurement mode (white Y relative results)
+.TP
+\fB\-e\fR
+Emissive for transparency on a light box
+.TP
+\fB\-p\fR
+Measure patch by patch rather than strip
+.TP
+\fB\-x\fR [lx]
+Take external values, either L*a*b* (\fB\-xl\fR) or XYZ (\fB\-xx\fR).
+.TP
+\fB\-n\fR
+Don't save spectral information (default saves spectral)
+.TP
+\fB\-l\fR
+Save CIE as D50 L*a*b* rather than XYZ
+.TP
+\fB\-L\fR
+Save CIE as D50 L*a*b* as well as XYZ
+.TP
+\fB\-r\fR
+Resume reading partly read chart
+.TP
+\fB\-I\fR file.cal
+Override calibration info from .ti2 in resulting .ti3
+.TP
+\fB\-F\fR filter
+Set filter configuration (if aplicable):
+.TP
+n
+None
+.TP
+p
+Polarising filter
+.TP
+6
+D65
+.TP
+u
+U.V. Cut
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-B\fR
+Disable auto bi\-directional strip recognition
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for CCSS instrument:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-T\fR ratio
+Modify strip patch consistency tolerance by ratio
+.TP
+\fB\-S\fR
+Suppress wrong strip & unexpected value warnings
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+outfile
+Base name for input[ti2]/output[ti3] file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: chartread [\-options] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-t\fR
+Use transmission measurement mode
+.TP
+\fB\-d\fR
+Use display measurement mode (white Y relative results)
+.TP
+\fB\-e\fR
+Emissive for transparency on a light box
+.TP
+\fB\-p\fR
+Measure patch by patch rather than strip
+.TP
+\fB\-x\fR [lx]
+Take external values, either L*a*b* (\fB\-xl\fR) or XYZ (\fB\-xx\fR).
+.TP
+\fB\-n\fR
+Don't save spectral information (default saves spectral)
+.TP
+\fB\-l\fR
+Save CIE as D50 L*a*b* rather than XYZ
+.TP
+\fB\-L\fR
+Save CIE as D50 L*a*b* as well as XYZ
+.TP
+\fB\-r\fR
+Resume reading partly read chart
+.TP
+\fB\-I\fR file.cal
+Override calibration info from .ti2 in resulting .ti3
+.TP
+\fB\-F\fR filter
+Set filter configuration (if aplicable):
+.TP
+n
+None
+.TP
+p
+Polarising filter
+.TP
+6
+D65
+.TP
+u
+U.V. Cut
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-B\fR
+Disable auto bi\-directional strip recognition
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for CCSS instrument:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-T\fR ratio
+Modify strip patch consistency tolerance by ratio
+.TP
+\fB\-S\fR
+Suppress wrong strip & unexpected value warnings
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+outfile
+Base name for input[ti2]/output[ti3] file
diff --git a/debian/collink.1 b/debian/collink.1
new file mode 100644
index 0000000..2ee3c2f
--- /dev/null
+++ b/debian/collink.1
@@ -0,0 +1,355 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH LINK "1" "August 2013" "Link ICC profiles, Version 1.5.1" "User Commands"
+.SH NAME
+Link \- Link ICC profiles.
+.SH DESCRIPTION
+Link ICC profiles, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Too few arguments, got 1 expect at least 3
+.PP
+usage: collink [options] srcprofile dstprofile linkedprofile
+.TP
+\fB\-v\fR
+Verbose
+.HP
+\fB\-A\fR manufacturer Manufacturer description string
+.TP
+\fB\-M\fR model
+Model description string
+.TP
+\fB\-D\fR description
+Profile Description string (Default "inoutfile")
+.TP
+\fB\-C\fR copyright
+Copyright string
+.TP
+\fB\-V\fR
+Verify existing profile, rather than link
+.TP
+\fB\-q\fR lmhu
+Quality \- Low, Medium (def), High, Ultra
+.TP
+\fB\-r\fR res
+Override clut res. set by \fB\-q\fR
+.TP
+\fB\-n\fR
+Don't preserve device linearization curves in result
+.TP
+\fB\-f\fR
+Special :\- Force neutral colors to be K only output
+.TP
+\fB\-fk\fR
+Special :\- Force K only neutral colors to be K only output
+.TP
+\fB\-F\fR
+Special :\- Force all colors to be K only output
+.TP
+\fB\-fcmy\fR
+Special :\- Force 100% C,M or Y only to stay pure
+.TP
+\fB\-p\fR absprof
+Include abstract profile in link
+.TP
+\fB\-s\fR
+Simple Mode (default)
+.TP
+\fB\-g\fR [src.gam]
+Gamut Mapping Mode [optional source image gamut]
+.TP
+\fB\-G\fR [src.gam]
+Gamut Mapping Mode using inverse outprofile A2B
+.IP
+Simple Mode Options:
+\fB\-i\fR in_intent p = perceptual, r = relative colorimetric,
+.IP
+s = saturation, a = absolute colorimetric
+.TP
+\fB\-o\fR out_intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute colorimetric
+.TP
+Gamut Mapping
+Mode Options:
+.TP
+\fB\-i\fR intent
+set linking intent from the following choice:
+.IP
+a \- Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]
+.IP
+aw \- Absolute Colorimetric (in Jab) with scaling to fit white point
+aa \- Absolute Appearance
+.IP
+r \- White Point Matched Appearance [ICC Relative Colorimetric]
+.IP
+la \- Luminance axis matched Appearance
+.IP
+p \- Perceptual (Preferred) (Default) [ICC Perceptual]
+.IP
+pa \- Perceptual Apperance
+ms \- Saturation
+.IP
+s \- Enhanced Saturation [ICC Saturation]
+.IP
+al \- Absolute Colorimetric (Lab)
+rl \- White Point Matched Appearance (Lab)
+.TP
+\fB\-w\fR [J,a,b]
+Use forced whitepoint hack [optional target point]
+.TP
+\fB\-c\fR viewcond
+set source viewing conditions for CIECAM02,
+either an enumerated choice, or a parameter
+.TP
+\fB\-d\fR viewcond
+set destination viewing conditions for CIECAM02,
+either an enumerated choice, or parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:scenewhite
+Scene white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 1)
+.TP
+f:X:Y:Z
+Flare color as XYZ (default media white)
+.TP
+f:x:y
+Flare color as x, y
+.TP
+\fB\-t\fR tlimit
+set source total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-T\fR klimit
+set source black ink limit, 0 \- 100% (estimate by default)
+.IP
+Inverse outprofile A2B Options:
+\fB\-k\fR tezhxr CMYK Black generation
+.IP
+t = transfer K from source to destination, e = retain K of destination B2A table
+z = zero K, h = 0.5 K, x = maximum K, r = ramp K (default)
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+p = black target generation curve parameters
+.HP
+\fB\-k\fR q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2
+.IP
+q = transfer source K to dual curve limits
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set destination total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set destination black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-P\fR
+Create gamut gammap.wrl diagostic
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Too few arguments, got 1 expect at least 3
+.PP
+usage: collink [options] srcprofile dstprofile linkedprofile
+.TP
+\fB\-v\fR
+Verbose
+.HP
+\fB\-A\fR manufacturer Manufacturer description string
+.TP
+\fB\-M\fR model
+Model description string
+.TP
+\fB\-D\fR description
+Profile Description string (Default "inoutfile")
+.TP
+\fB\-C\fR copyright
+Copyright string
+.TP
+\fB\-V\fR
+Verify existing profile, rather than link
+.TP
+\fB\-q\fR lmhu
+Quality \- Low, Medium (def), High, Ultra
+.TP
+\fB\-r\fR res
+Override clut res. set by \fB\-q\fR
+.TP
+\fB\-n\fR
+Don't preserve device linearization curves in result
+.TP
+\fB\-f\fR
+Special :\- Force neutral colors to be K only output
+.TP
+\fB\-fk\fR
+Special :\- Force K only neutral colors to be K only output
+.TP
+\fB\-F\fR
+Special :\- Force all colors to be K only output
+.TP
+\fB\-fcmy\fR
+Special :\- Force 100% C,M or Y only to stay pure
+.TP
+\fB\-p\fR absprof
+Include abstract profile in link
+.TP
+\fB\-s\fR
+Simple Mode (default)
+.TP
+\fB\-g\fR [src.gam]
+Gamut Mapping Mode [optional source image gamut]
+.TP
+\fB\-G\fR [src.gam]
+Gamut Mapping Mode using inverse outprofile A2B
+.IP
+Simple Mode Options:
+\fB\-i\fR in_intent p = perceptual, r = relative colorimetric,
+.IP
+s = saturation, a = absolute colorimetric
+.TP
+\fB\-o\fR out_intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute colorimetric
+.TP
+Gamut Mapping
+Mode Options:
+.TP
+\fB\-i\fR intent
+set linking intent from the following choice:
+.IP
+a \- Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]
+.IP
+aw \- Absolute Colorimetric (in Jab) with scaling to fit white point
+aa \- Absolute Appearance
+.IP
+r \- White Point Matched Appearance [ICC Relative Colorimetric]
+.IP
+la \- Luminance axis matched Appearance
+.IP
+p \- Perceptual (Preferred) (Default) [ICC Perceptual]
+.IP
+pa \- Perceptual Apperance
+ms \- Saturation
+.IP
+s \- Enhanced Saturation [ICC Saturation]
+.IP
+al \- Absolute Colorimetric (Lab)
+rl \- White Point Matched Appearance (Lab)
+.TP
+\fB\-w\fR [J,a,b]
+Use forced whitepoint hack [optional target point]
+.TP
+\fB\-c\fR viewcond
+set source viewing conditions for CIECAM02,
+either an enumerated choice, or a parameter
+.TP
+\fB\-d\fR viewcond
+set destination viewing conditions for CIECAM02,
+either an enumerated choice, or parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:scenewhite
+Scene white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 1)
+.TP
+f:X:Y:Z
+Flare color as XYZ (default media white)
+.TP
+f:x:y
+Flare color as x, y
+.TP
+\fB\-t\fR tlimit
+set source total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-T\fR klimit
+set source black ink limit, 0 \- 100% (estimate by default)
+.IP
+Inverse outprofile A2B Options:
+\fB\-k\fR tezhxr CMYK Black generation
+.IP
+t = transfer K from source to destination, e = retain K of destination B2A table
+z = zero K, h = 0.5 K, x = maximum K, r = ramp K (default)
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+p = black target generation curve parameters
+.HP
+\fB\-k\fR q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2
+.IP
+q = transfer source K to dual curve limits
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set destination total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set destination black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-P\fR
+Create gamut gammap.wrl diagostic
diff --git a/debian/colprof.1 b/debian/colprof.1
new file mode 100644
index 0000000..75e8564
--- /dev/null
+++ b/debian/colprof.1
@@ -0,0 +1,369 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create ICC profile, Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create ICC profile.
+.SH DESCRIPTION
+Create ICC profile, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Unknown flag '\-'
+.PP
+usage: debian/tmp/usr/bin/colprof [\-options] inoutfile
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-A\fR manufacturer Manufacturer description string
+.TP
+\fB\-M\fR model
+Model description string
+.TP
+\fB\-D\fR description
+Profile Description string (Default "inoutfile")
+.TP
+\fB\-C\fR copyright
+Copyright string
+.TP
+\fB\-Z\fR tmnb
+Attributes: Transparency, Matte, Negative, BlackAndWhite
+.TP
+\fB\-Z\fR prsa
+Default intent: Perceptual, Rel. Colorimetric, Saturation, Abs. Colorimetric
+.TP
+\fB\-q\fR lmhu
+Quality \- Low, Medium (def), High, Ultra
+.TP
+\fB\-b\fR [lmhun]
+Low quality B2A table \- or specific B2A quality or none for input device
+.TP
+\fB\-y\fR
+Verify A2B profile
+.TP
+\fB\-ni\fR
+Don't create input (Device) shaper curves
+.TP
+\fB\-np\fR
+Don't create input (Device) grid position curves
+.TP
+\fB\-no\fR
+Don't create output (PCS) shaper curves
+.TP
+\fB\-nc\fR
+Don't put the input .ti3 data in the profile
+.TP
+\fB\-k\fR zhxr
+Black value target: z = zero K,
+h = 0.5 K, x = max K, r = ramp K (def.)
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+override total ink limit, 0 \- 400% (default from .ti3)
+.TP
+\fB\-L\fR klimit
+override black ink limit, 0 \- 100% (default from .ti3)
+.TP
+\fB\-a\fR lxXgsmGS
+Algorithm type override
+l = Lab cLUT (def.), x = XYZ cLUT, X = display XYZ cLUT + matrix
+g = gamma+matrix, s = shaper+matrix, m = matrix only,
+G = single gamma+matrix, S = single shaper+matrix
+.TP
+\fB\-u\fR
+If input profile, auto scale WP to allow extrapolation
+.TP
+\fB\-uc\fR
+If input profile, clip cLUT values above WP
+.TP
+\fB\-U\fR scale
+If input profile, scale media white point by scale
+.TP
+\fB\-R\fR
+Restrict white <= 1.0, black and primaries to be +ve
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-r\fR avgdev
+Average deviation of device+instrument readings as a percentage (default 0.50%)
+.TP
+\fB\-s\fR src.icc
+Apply gamut mapping to output profile perceptual B2A table for given source space
+.TP
+\fB\-S\fR src.icc
+Apply gamut mapping to output profile perceptual and saturation B2A table
+.TP
+\fB\-nP\fR
+Use colormetric source gamut to make output profile perceptual table
+.TP
+\fB\-nS\fR
+Use colormetric source gamut to make output profile saturation table
+.TP
+\fB\-g\fR src.gam
+Use source image gamut as well for output profile gamut mapping
+.TP
+\fB\-p\fR absprof,...
+Incorporate abstract profile(s) into output tables
+.TP
+\fB\-t\fR intent
+Override gamut mapping intent for output profile perceptual table:
+.TP
+\fB\-T\fR intent
+Override gamut mapping intent for output profile saturation table:
+.IP
+a \- Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]
+.IP
+aw \- Absolute Colorimetric (in Jab) with scaling to fit white point
+aa \- Absolute Appearance
+.IP
+r \- White Point Matched Appearance [ICC Relative Colorimetric]
+.IP
+la \- Luminance axis matched Appearance
+.IP
+p \- Perceptual (Preferred) (Default) [ICC Perceptual]
+.IP
+pa \- Perceptual Apperance
+ms \- Saturation
+.IP
+s \- Enhanced Saturation [ICC Saturation]
+.IP
+al \- Absolute Colorimetric (Lab)
+rl \- White Point Matched Appearance (Lab)
+.TP
+\fB\-c\fR viewcond
+set input viewing conditions for output profile CIECAM02 gamut mapping,
+.IP
+either an enumerated choice, or a parameter
+.TP
+\fB\-d\fR viewcond
+set output viewing conditions for output profile CIECAM02 gamut mapping
+.IP
+either an enumerated choice, or a parameter
+Also sets out of gamut clipping CAM space.
+either an enumerated choice, or a series of parameters:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+\fB\-P\fR
+Create gamut gammap_p.wrl and gammap_s.wrl diagostics
+.TP
+\fB\-O\fR outputfile
+Override the default output filename.
+.TP
+inoutfile
+Base name for input.ti3/output.icc file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Unknown flag '\-'
+.PP
+usage: debian/tmp/usr/bin/colprof [\-options] inoutfile
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-A\fR manufacturer Manufacturer description string
+.TP
+\fB\-M\fR model
+Model description string
+.TP
+\fB\-D\fR description
+Profile Description string (Default "inoutfile")
+.TP
+\fB\-C\fR copyright
+Copyright string
+.TP
+\fB\-Z\fR tmnb
+Attributes: Transparency, Matte, Negative, BlackAndWhite
+.TP
+\fB\-Z\fR prsa
+Default intent: Perceptual, Rel. Colorimetric, Saturation, Abs. Colorimetric
+.TP
+\fB\-q\fR lmhu
+Quality \- Low, Medium (def), High, Ultra
+.TP
+\fB\-b\fR [lmhun]
+Low quality B2A table \- or specific B2A quality or none for input device
+.TP
+\fB\-y\fR
+Verify A2B profile
+.TP
+\fB\-ni\fR
+Don't create input (Device) shaper curves
+.TP
+\fB\-np\fR
+Don't create input (Device) grid position curves
+.TP
+\fB\-no\fR
+Don't create output (PCS) shaper curves
+.TP
+\fB\-nc\fR
+Don't put the input .ti3 data in the profile
+.TP
+\fB\-k\fR zhxr
+Black value target: z = zero K,
+h = 0.5 K, x = max K, r = ramp K (def.)
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+override total ink limit, 0 \- 400% (default from .ti3)
+.TP
+\fB\-L\fR klimit
+override black ink limit, 0 \- 100% (default from .ti3)
+.TP
+\fB\-a\fR lxXgsmGS
+Algorithm type override
+l = Lab cLUT (def.), x = XYZ cLUT, X = display XYZ cLUT + matrix
+g = gamma+matrix, s = shaper+matrix, m = matrix only,
+G = single gamma+matrix, S = single shaper+matrix
+.TP
+\fB\-u\fR
+If input profile, auto scale WP to allow extrapolation
+.TP
+\fB\-uc\fR
+If input profile, clip cLUT values above WP
+.TP
+\fB\-U\fR scale
+If input profile, scale media white point by scale
+.TP
+\fB\-R\fR
+Restrict white <= 1.0, black and primaries to be +ve
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-r\fR avgdev
+Average deviation of device+instrument readings as a percentage (default 0.50%)
+.TP
+\fB\-s\fR src.icc
+Apply gamut mapping to output profile perceptual B2A table for given source space
+.TP
+\fB\-S\fR src.icc
+Apply gamut mapping to output profile perceptual and saturation B2A table
+.TP
+\fB\-nP\fR
+Use colormetric source gamut to make output profile perceptual table
+.TP
+\fB\-nS\fR
+Use colormetric source gamut to make output profile saturation table
+.TP
+\fB\-g\fR src.gam
+Use source image gamut as well for output profile gamut mapping
+.TP
+\fB\-p\fR absprof,...
+Incorporate abstract profile(s) into output tables
+.TP
+\fB\-t\fR intent
+Override gamut mapping intent for output profile perceptual table:
+.TP
+\fB\-T\fR intent
+Override gamut mapping intent for output profile saturation table:
+.IP
+a \- Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]
+.IP
+aw \- Absolute Colorimetric (in Jab) with scaling to fit white point
+aa \- Absolute Appearance
+.IP
+r \- White Point Matched Appearance [ICC Relative Colorimetric]
+.IP
+la \- Luminance axis matched Appearance
+.IP
+p \- Perceptual (Preferred) (Default) [ICC Perceptual]
+.IP
+pa \- Perceptual Apperance
+ms \- Saturation
+.IP
+s \- Enhanced Saturation [ICC Saturation]
+.IP
+al \- Absolute Colorimetric (Lab)
+rl \- White Point Matched Appearance (Lab)
+.TP
+\fB\-c\fR viewcond
+set input viewing conditions for output profile CIECAM02 gamut mapping,
+.IP
+either an enumerated choice, or a parameter
+.TP
+\fB\-d\fR viewcond
+set output viewing conditions for output profile CIECAM02 gamut mapping
+.IP
+either an enumerated choice, or a parameter
+Also sets out of gamut clipping CAM space.
+either an enumerated choice, or a series of parameters:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+\fB\-P\fR
+Create gamut gammap_p.wrl and gammap_s.wrl diagostics
+.TP
+\fB\-O\fR outputfile
+Override the default output filename.
+.TP
+inoutfile
+Base name for input.ti3/output.icc file
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..4821b4c
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,114 @@
+Source: argyll
+Section: graphics
+Priority: optional
+Maintainer: Debian QA Group <packages@qa.debian.org>
+Homepage: http://www.argyllcms.com/
+Standards-Version: 3.9.5
+Build-Depends: debhelper (>= 9), libtiff-dev, libx11-dev, libxxf86vm-dev,
+ x11proto-xf86vidmode-dev, libxinerama-dev, libxrandr-dev, x11proto-scrnsaver-dev,
+ libxss-dev, libusbhid-dev [kfreebsd-any], autoconf, automake | automaken, libtool,
+ quilt, libjpeg-dev, libusb-dev, dh-autoreconf
+
+Package: argyll
+Architecture: any
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Replaces: argyll-bin
+Recommends: libpam-systemd [linux-any], udev (>= 196) [linux-any]
+Suggests: colord, gir1.2-colordgtk-1.0
+Conflicts: argyll-bin
+Description: Color Management System, calibrator and profiler
+ Argyll is an experimental, open source, ICC compatible color management
+ system. It supports accurate ICC profile creation for scanners, CMYK
+ printers, film recorders and calibration and profiling of displays.
+ Spectral sample data is supported, allowing a selection of illuminants
+ observer types, and paper fluorescent whitener additive compensation.
+ Profiles can also incorporate source specific gamut mappings for perceptual
+ and saturation intents. Gamut mapping and profile linking uses the CIECAM02
+ appearance model, a unique gamut mapping algorithm, and a wide selection of
+ rendering intents. It also includes code for the fastest portable 8 bit
+ raster color conversion engine available anywhere, as well as support for
+ fast, fully accurate 16 bit conversion. Device color gamuts can also be
+ viewed and compared using a VRML viewer.
+
+Package: argyll-dbg
+Section: debug
+Architecture: any
+Priority: extra
+Depends: argyll (= ${binary:Version}), ${misc:Depends}
+Description: debugging symbols for argyll
+ Argyll is an experimental, open source, ICC compatible color management
+ system. It supports accurate ICC profile creation for scanners, CMYK
+ printers, film recorders and calibration and profiling of displays.
+ .
+ This package contains the debugging symbols for argyll, libicc and libimdi
+ libraries
+
+Package: icc-utils
+Section: graphics
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Breaks: libicc2 (<< 2.12+argyll1.4.0-2)
+Replaces: libicc2 (<< 2.12+argyll1.4.0-2)
+Description: ICC profile I/O library
+ The icclib is a set of routines which implement the reading and
+ writing of color profile files that conform to the International
+ Color Consortium (ICC) Profile Format Specification, Version 3.4.
+ .
+ This package contains two utilities :
+ .
+ * iccdump : dump an ICC file in human readable form.
+ * icclu : translate colors through an ICC profile.
+
+Package: libicc-dev
+Section: libdevel
+Architecture: any
+Multi-Arch: same
+Depends: libicc2 (= ${binary:Version}), ${misc:Depends}
+Conflicts: argyll (<< 1.0.3+dfsg1-3)
+Description: Development files for the ICC profile I/O library
+ The icclib is a set of routines which implement the reading and
+ writing of color profile files that conform to the International
+ Color Consortium (ICC) Profile Format Specification, Version 3.4.
+ .
+ This package is needed to compile programs against libicc2, as
+ it only includes the header files and static libraries (optionally)
+ needed for compiling.
+
+Package: libicc2
+Section: libs
+Architecture: any
+Multi-Arch: same
+Pre-Depends: ${misc:Pre-Depends}
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Replaces: argyll
+Description: ICC profile I/O library
+ The icclib is a set of routines which implement the reading and
+ writing of color profile files that conform to the International
+ Color Consortium (ICC) Profile Format Specification, Version 3.4.
+
+Package: libimdi-dev
+Section: libdevel
+Architecture: any
+Multi-Arch: same
+Depends: libimdi0 (= ${binary:Version}), ${misc:Depends}
+Conflicts: argyll (<< 1.3.0-3)
+Description: Development files for the IMDI library
+ The Interger Multi-Dimensional Interpolation routines provides a flexible
+ and high performance system for applying color transforms to typical raster
+ pixel data.
+ .
+ This package is needed to compile programs against libimdi0, as
+ it only includes the header files and static libraries (optionally)
+ needed for compiling.
+
+Package: libimdi0
+Section: libs
+Architecture: any
+Multi-Arch: same
+Pre-Depends: ${misc:Pre-Depends}
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Conflicts: argyll (<< 1.3.0-3)
+Description: Integer Multi-Dimensional Interpolation routines (IMDI) library
+ The Interger Multi-Dimensional Interpolation routines provides a flexible
+ and high performance system for applying color transforms to typical raster
+ pixel data.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..24f646f
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,823 @@
+Format-Specification: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?op=file&rev=59
+Name: ArgyllCMS
+Maintainer: Graeme W. Gill <Graeme@argyllcms.com>
+Source: http://www.argyllcms.com/
+
+Files: *
+Copyright: Copyright 1995-2010, Graeme W. Gill <Graeme@argyllcms.com>
+License: AGPL-3
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+ software and other kinds of works, specifically designed to ensure
+ cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+ to take away your freedom to share and change the works. By contrast,
+ our General Public Licenses are intended to guarantee your freedom to
+ share and change all versions of a program--to make sure it remains free
+ software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+ price. Our General Public Licenses are designed to make sure that you
+ have the freedom to distribute copies of free software (and charge for
+ them if you wish), that you receive source code or can get it if you
+ want it, that you can change the software or use pieces of it in new
+ free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+ with two steps: (1) assert copyright on the software, and (2) offer
+ you this License which gives you legal permission to copy, distribute
+ and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+ improvements made in alternate versions of the program, if they
+ receive widespread use, become available for other developers to
+ incorporate. Many developers of free software are heartened and
+ encouraged by the resulting cooperation. However, in the case of
+ software used on network servers, this result may fail to come about.
+ The GNU General Public License permits making a modified version and
+ letting the public access it on a server without ever releasing its
+ source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ ensure that, in such cases, the modified source code becomes available
+ to the community. It requires the operator of a network server to
+ provide the source code of the modified version running there to the
+ users of that server. Therefore, public use of a modified version, on
+ a publicly accessible server, gives the public access to the source
+ code of the modified version.
+
+ An older license, called the Affero General Public License and
+ published by Affero, was designed to accomplish similar goals. This is
+ a different license, not a version of the Affero GPL, but Affero has
+ released a new version of the Affero GPL which permits relicensing under
+ this license.
+
+ The precise terms and conditions for copying, distribution and
+ modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+ works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+ License. Each licensee is addressed as "you". "Licensees" and
+ "recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+ in a fashion requiring copyright permission, other than the making of an
+ exact copy. The resulting work is called a "modified version" of the
+ earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+ on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+ permission, would make you directly or secondarily liable for
+ infringement under applicable copyright law, except executing it on a
+ computer or modifying a private copy. Propagation includes copying,
+ distribution (with or without modification), making available to the
+ public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+ parties to make or receive copies. Mere interaction with a user through
+ a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+ to the extent that it includes a convenient and prominently visible
+ feature that (1) displays an appropriate copyright notice, and (2)
+ tells the user that there is no warranty for the work (except to the
+ extent that warranties are provided), that licensees may convey the
+ work under this License, and how to view a copy of this License. If
+ the interface presents a list of user commands or options, such as a
+ menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+ for making modifications to it. "Object code" means any non-source
+ form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+ standard defined by a recognized standards body, or, in the case of
+ interfaces specified for a particular programming language, one that
+ is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+ than the work as a whole, that (a) is included in the normal form of
+ packaging a Major Component, but which is not part of that Major
+ Component, and (b) serves only to enable use of the work with that
+ Major Component, or to implement a Standard Interface for which an
+ implementation is available to the public in source code form. A
+ "Major Component", in this context, means a major essential component
+ (kernel, window system, and so on) of the specific operating system
+ (if any) on which the executable work runs, or a compiler used to
+ produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+ the source code needed to generate, install, and (for an executable
+ work) run the object code and to modify the work, including scripts to
+ control those activities. However, it does not include the work's
+ System Libraries, or general-purpose tools or generally available free
+ programs which are used unmodified in performing those activities but
+ which are not part of the work. For example, Corresponding Source
+ includes interface definition files associated with source files for
+ the work, and the source code for shared libraries and dynamically
+ linked subprograms that the work is specifically designed to require,
+ such as by intimate data communication or control flow between those
+ subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+ can regenerate automatically from other parts of the Corresponding
+ Source.
+
+ The Corresponding Source for a work in source code form is that
+ same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+ copyright on the Program, and are irrevocable provided the stated
+ conditions are met. This License explicitly affirms your unlimited
+ permission to run the unmodified Program. The output from running a
+ covered work is covered by this License only if the output, given its
+ content, constitutes a covered work. This License acknowledges your
+ rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+ convey, without conditions so long as your license otherwise remains
+ in force. You may convey covered works to others for the sole purpose
+ of having them make modifications exclusively for you, or provide you
+ with facilities for running those works, provided that you comply with
+ the terms of this License in conveying all material for which you do
+ not control copyright. Those thus making or running the covered works
+ for you must do so exclusively on your behalf, under your direction
+ and control, on terms that prohibit them from making any copies of
+ your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+ the conditions stated below. Sublicensing is not allowed; section 10
+ makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+ measure under any applicable law fulfilling obligations under article
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
+ similar laws prohibiting or restricting circumvention of such
+ measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+ circumvention of technological measures to the extent such circumvention
+ is effected by exercising rights under this License with respect to
+ the covered work, and you disclaim any intention to limit operation or
+ modification of the work as a means of enforcing, against the work's
+ users, your or third parties' legal rights to forbid circumvention of
+ technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+ receive it, in any medium, provided that you conspicuously and
+ appropriately publish on each copy an appropriate copyright notice;
+ keep intact all notices stating that this License and any
+ non-permissive terms added in accord with section 7 apply to the code;
+ keep intact all notices of the absence of any warranty; and give all
+ recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+ and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+ produce it from the Program, in the form of source code under the
+ terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+ works, which are not by their nature extensions of the covered work,
+ and which are not combined with it such as to form a larger program,
+ in or on a volume of a storage or distribution medium, is called an
+ "aggregate" if the compilation and its resulting copyright are not
+ used to limit the access or legal rights of the compilation's users
+ beyond what the individual works permit. Inclusion of a covered work
+ in an aggregate does not cause this License to apply to the other
+ parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+ of sections 4 and 5, provided that you also convey the
+ machine-readable Corresponding Source under the terms of this License,
+ in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+ from the Corresponding Source as a System Library, need not be
+ included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+ tangible personal property which is normally used for personal, family,
+ or household purposes, or (2) anything designed or sold for incorporation
+ into a dwelling. In determining whether a product is a consumer product,
+ doubtful cases shall be resolved in favor of coverage. For a particular
+ product received by a particular user, "normally used" refers to a
+ typical or common use of that class of product, regardless of the status
+ of the particular user or of the way in which the particular user
+ actually uses, or expects or is expected to use, the product. A product
+ is a consumer product regardless of whether the product has substantial
+ commercial, industrial or non-consumer uses, unless such uses represent
+ the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+ procedures, authorization keys, or other information required to install
+ and execute modified versions of a covered work in that User Product from
+ a modified version of its Corresponding Source. The information must
+ suffice to ensure that the continued functioning of the modified object
+ code is in no case prevented or interfered with solely because
+ modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+ specifically for use in, a User Product, and the conveying occurs as
+ part of a transaction in which the right of possession and use of the
+ User Product is transferred to the recipient in perpetuity or for a
+ fixed term (regardless of how the transaction is characterized), the
+ Corresponding Source conveyed under this section must be accompanied
+ by the Installation Information. But this requirement does not apply
+ if neither you nor any third party retains the ability to install
+ modified object code on the User Product (for example, the work has
+ been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+ requirement to continue to provide support service, warranty, or updates
+ for a work that has been modified or installed by the recipient, or for
+ the User Product in which it has been modified or installed. Access to a
+ network may be denied when the modification itself materially and
+ adversely affects the operation of the network or violates the rules and
+ protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+ in accord with this section must be in a format that is publicly
+ documented (and with an implementation available to the public in
+ source code form), and must require no special password or key for
+ unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+ License by making exceptions from one or more of its conditions.
+ Additional permissions that are applicable to the entire Program shall
+ be treated as though they were included in this License, to the extent
+ that they are valid under applicable law. If additional permissions
+ apply only to part of the Program, that part may be used separately
+ under those permissions, but the entire Program remains governed by
+ this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+ remove any additional permissions from that copy, or from any part of
+ it. (Additional permissions may be written to require their own
+ removal in certain cases when you modify the work.) You may place
+ additional permissions on material, added by you to a covered work,
+ for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+ add to a covered work, you may (if authorized by the copyright holders of
+ that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+ restrictions" within the meaning of section 10. If the Program as you
+ received it, or any part of it, contains a notice stating that it is
+ governed by this License along with a term that is a further
+ restriction, you may remove that term. If a license document contains
+ a further restriction but permits relicensing or conveying under this
+ License, you may add to a covered work material governed by the terms
+ of that license document, provided that the further restriction does
+ not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+ must place, in the relevant source files, a statement of the
+ additional terms that apply to those files, or a notice indicating
+ where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+ form of a separately written license, or stated as exceptions;
+ the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+ provided under this License. Any attempt otherwise to propagate or
+ modify it is void, and will automatically terminate your rights under
+ this License (including any patent licenses granted under the third
+ paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+ license from a particular copyright holder is reinstated (a)
+ provisionally, unless and until the copyright holder explicitly and
+ finally terminates your license, and (b) permanently, if the copyright
+ holder fails to notify you of the violation by some reasonable means
+ prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+ reinstated permanently if the copyright holder notifies you of the
+ violation by some reasonable means, this is the first time you have
+ received notice of violation of this License (for any work) from that
+ copyright holder, and you cure the violation prior to 30 days after
+ your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+ licenses of parties who have received copies or rights from you under
+ this License. If your rights have been terminated and not permanently
+ reinstated, you do not qualify to receive new licenses for the same
+ material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+ run a copy of the Program. Ancillary propagation of a covered work
+ occurring solely as a consequence of using peer-to-peer transmission
+ to receive a copy likewise does not require acceptance. However,
+ nothing other than this License grants you permission to propagate or
+ modify any covered work. These actions infringe copyright if you do
+ not accept this License. Therefore, by modifying or propagating a
+ covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+ receives a license from the original licensors, to run, modify and
+ propagate that work, subject to this License. You are not responsible
+ for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+ organization, or substantially all assets of one, or subdividing an
+ organization, or merging organizations. If propagation of a covered
+ work results from an entity transaction, each party to that
+ transaction who receives a copy of the work also receives whatever
+ licenses to the work the party's predecessor in interest had or could
+ give under the previous paragraph, plus a right to possession of the
+ Corresponding Source of the work from the predecessor in interest, if
+ the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+ rights granted or affirmed under this License. For example, you may
+ not impose a license fee, royalty, or other charge for exercise of
+ rights granted under this License, and you may not initiate litigation
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
+ any patent claim is infringed by making, using, selling, offering for
+ sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+ License of the Program or a work on which the Program is based. The
+ work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+ owned or controlled by the contributor, whether already acquired or
+ hereafter acquired, that would be infringed by some manner, permitted
+ by this License, of making, using, or selling its contributor version,
+ but do not include claims that would be infringed only as a
+ consequence of further modification of the contributor version. For
+ purposes of this definition, "control" includes the right to grant
+ patent sublicenses in a manner consistent with the requirements of
+ this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+ patent license under the contributor's essential patent claims, to
+ make, use, sell, offer for sale, import and otherwise run, modify and
+ propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+ agreement or commitment, however denominated, not to enforce a patent
+ (such as an express permission to practice a patent or covenant not to
+ sue for patent infringement). To "grant" such a patent license to a
+ party means to make such an agreement or commitment not to enforce a
+ patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+ and the Corresponding Source of the work is not available for anyone
+ to copy, free of charge and under the terms of this License, through a
+ publicly available network server or other readily accessible means,
+ then you must either (1) cause the Corresponding Source to be so
+ available, or (2) arrange to deprive yourself of the benefit of the
+ patent license for this particular work, or (3) arrange, in a manner
+ consistent with the requirements of this License, to extend the patent
+ license to downstream recipients. "Knowingly relying" means you have
+ actual knowledge that, but for the patent license, your conveying the
+ covered work in a country, or your recipient's use of the covered work
+ in a country, would infringe one or more identifiable patents in that
+ country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+ arrangement, you convey, or propagate by procuring conveyance of, a
+ covered work, and grant a patent license to some of the parties
+ receiving the covered work authorizing them to use, propagate, modify
+ or convey a specific copy of the covered work, then the patent license
+ you grant is automatically extended to all recipients of the covered
+ work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+ the scope of its coverage, prohibits the exercise of, or is
+ conditioned on the non-exercise of one or more of the rights that are
+ specifically granted under this License. You may not convey a covered
+ work if you are a party to an arrangement with a third party that is
+ in the business of distributing software, under which you make payment
+ to the third party based on the extent of your activity of conveying
+ the work, and under which the third party grants, to any of the
+ parties who would receive the covered work from you, a discriminatory
+ patent license (a) in connection with copies of the covered work
+ conveyed by you (or copies made from those copies), or (b) primarily
+ for and in connection with specific products or compilations that
+ contain the covered work, unless you entered into that arrangement,
+ or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+ any implied license or other defenses to infringement that may
+ otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+ otherwise) that contradict the conditions of this License, they do not
+ excuse you from the conditions of this License. If you cannot convey a
+ covered work so as to satisfy simultaneously your obligations under this
+ License and any other pertinent obligations, then as a consequence you may
+ not convey it at all. For example, if you agree to terms that obligate you
+ to collect a royalty for further conveying from those to whom you convey
+ the Program, the only way you could satisfy both those terms and this
+ License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+ Program, your modified version must prominently offer all users
+ interacting with it remotely through a computer network (if your version
+ supports such interaction) an opportunity to receive the Corresponding
+ Source of your version by providing access to the Corresponding Source
+ from a network server at no charge, through some standard or customary
+ means of facilitating copying of software. This Corresponding Source
+ shall include the Corresponding Source for any work covered by version 3
+ of the GNU General Public License that is incorporated pursuant to the
+ following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+ permission to link or combine any covered work with a work licensed
+ under version 3 of the GNU General Public License into a single
+ combined work, and to convey the resulting work. The terms of this
+ License will continue to apply to the part which is the covered work,
+ but the work with which it is combined will remain governed by version
+ 3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+ the GNU Affero General Public License from time to time. Such new versions
+ will be similar in spirit to the present version, but may differ in detail to
+ address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+ Program specifies that a certain numbered version of the GNU Affero General
+ Public License "or any later version" applies to it, you have the
+ option of following the terms and conditions either of that numbered
+ version or of any later version published by the Free Software
+ Foundation. If the Program does not specify a version number of the
+ GNU Affero General Public License, you may choose any version ever published
+ by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+ versions of the GNU Affero General Public License can be used, that proxy's
+ public statement of acceptance of a version permanently authorizes you
+ to choose that version for the Program.
+
+ Later license versions may give you additional or different
+ permissions. However, no additional obligations are imposed on any
+ author or copyright holder as a result of your choosing to follow a
+ later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+ above cannot be given local legal effect according to their terms,
+ reviewing courts shall apply local law that most closely approximates
+ an absolute waiver of all civil liability in connection with the
+ Program, unless a warranty or assumption of liability accompanies a
+ copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+ possible use to the public, the best way to achieve this is to make it
+ free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+ to attach them to the start of each source file to most effectively
+ state the exclusion of warranty; and each file should have at least
+ the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+ network, you should also make sure that it provides a way for users to
+ get its source. For example, if your program is a web application, its
+ interface could display a "Source" link that leads users to an archive
+ of the code. There are many ways you could offer source, and different
+ solutions will be better for different programs; see section 13 for the
+ specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
+ For more information on this, and how to apply and follow the GNU AGPL, see
+ <http://www.gnu.org/licenses/>.
+
+
+Files: icc/*, cgats/*, jcnf/*, ucmm/*
+Copyright: Copyright 1995-2011, Graeme W. Gill
+License: MIT/X11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+Files: jcnf/yajl/*
+Copyright: Copyright 2007, Lloyd Hilaiel
+License: BSD-3
+
+Files: libusb/*
+Copyright: Copyright 2000-2003, Johannes Erdfelt <johannes@erdfelt.com>
+Copyright: Copyright 2003, Brad Hards <bradh@frogmouth.net>
+Copyright: Copyright Thomas Sailer <sailer@ife.ee.ethz.ch>
+License: GPL-2+
+
+Files: libusb/usb.h.in
+Copyright: Copyright 2000-2003, Johannes Erdfelt <johannes@erdfelt.com>
+License: GPL-2+ | BSD-3
+
+Files: libusbw/*
+Copyright: Copyright 2000-2004, Johannes Erdfelt <johannes@erdfelt.com>
+Copyright: Copyright 2002-2005, Stephan Meyer <ste_meyer@web.de>
+Copyright: Copyright Thomas Sailer <sailer@ife.ee.ethz.ch>
+License: GPL-2 and LGPL-2
+ The library (DLL) is distributed under the terms of the GNU Lesser
+ General Public License (LGPL).
+
+ All other components (drivers, services, installer) are distributed
+ under the terms of the GNU General Public License (GPL).
+
+Files: libusb1/msvc/*
+Copyright: Copyright 2006, Alexander Chemeris
+License: BSD-2
+
+Files: libusb1/*
+Copyright: Copyright 2001, Johannes Erdfelt <johannes@erdfelt.com>
+Copyright: Copyright 2007-2009, Daniel Drake <dsd@gentoo.org>
+Copyright: Copyright 2008-2009, Nathan Hjelm <hjelmn@users.sourceforge.net>
+Copyright: Copyright 2009-2010, Pete Batard <pbatard@gmail.com>
+Copyright: Copyright 2010, Michael Plante <michael.plante@gmail.com>
+License: LGPL-2+
+
+Files: libusb1/os/driver/*
+Copyright: Copyright 2002-2005, Stephan Meyer <ste_meyer@web.de>
+License: GPL-2+
+
+Files: spectro/*
+Copyright: Copyright 1996-2011, Graeme W. Gill
+License: GPL-2+
+
+Files:
+ spectro/dispcal.c
+ spectro/dispsup.c
+ spectro/dispsup.h
+ spectro/dispwin.c
+ spectro/dispwin.h
+ spectro/average.c
+ spectro/synthcal.c
+ spectro/synthread.c
+ spectro/ccxxmake.c
+ spectro/fakeread.c
+ spectro/License.txt
+ spectro/chartread.c
+ spectro/dispread.c
+ spectro/illumread.c
+Copyright: Copyright 1996-2007, Graeme W. Gill
+License: AGPL-3
+
+Files: h/sort.h
+Copyright: Copyright 1996-2010, Graeme W. Gill
+License: GPL-2+
+
+Files: tiff/*
+Copyright: Copyright 1988-1997, Sam Leffler
+Copyright: Copyright 1991-1997, Silicon Graphics, Inc.
+License: MIT/X11
+ Permission to use, copy, modify, distribute, and sell this software and
+ its documentation for any purpose is hereby granted without fee, provided
+ that (i) the above copyright notices and this permission notice appear in
+ all copies of the software and related documentation, and (ii) the names of
+ Sam Leffler and Silicon Graphics may not be used in any advertising or
+ publicity relating to the software without the specific, prior written
+ permission of Sam Leffler and Silicon Graphics.
+
+ THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+ IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ OF THIS SOFTWARE.
+
+Files: tiff/contrib/addtiffo/*
+Copyright: Copyright 1999, Frank Warmerdam
+License: MIT/X11
+ Same as above.
+
+Files: tiff/contrib/dbs/*
+Copyright: Copyright 1990, Digital Equipment Corporation
+License: MIT/X11
+ Same as above.
+
+Files: tiff/contrib/mfs/*
+Copyright: Copyright 1996 BancTec AB
+Copyright: Copyright 1996 Mike Johnson
+License: MIT/X11
+ Same as above.
+
+Files: tiff/contrib/ras/*
+Copyright: Copyright 1990, Sun Microsystems, Inc.
+License: MIT/X11
+ Same as above.
+
+Files: xicc/xspect.c
+Copyright: Copyright 2000-2006, Graeme W. Gill
+License: GPL-2+
+
+Files: doc/*
+Copyright: Copyright 1995-2010, Graeme W. Gill <Graeme@argyllcms.com>
+License: GFDL-1.3
+
+Files: numlib/numsup.*
+Copyright: Copyright 1997-2010, Graeme W. Gill
+License: GPL-2+
+
+Files: rspl/rspl1.*
+Copyright: 1996-2010, Graeme W. Gill
+License: GPL-2+
+
+Files: debian/*
+Copyright: Copyright 2006-2008, Christian Marillat <marillat@debian.org>
+Copyright: Copyright 2008-2010, Roland Mas <lolando@debian.org>
+License: GPL-3+
diff --git a/debian/dispcal.1 b/debian/dispcal.1
new file mode 100644
index 0000000..ce04a1f
--- /dev/null
+++ b/debian/dispcal.1
@@ -0,0 +1,289 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CALIBRATE "1" "August 2013" "Calibrate a Display, Version 1.5.1" "User Commands"
+.SH NAME
+Calibrate \- Calibrate a Display.
+.SH DESCRIPTION
+Calibrate a Display, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Usage requested
+usage: dispcal [options] outfile
+.TP
+\fB\-v\fR [n]
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 = 'Screen 1, Output VBOX0 at 0, 0, width 1605, height 1079'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-r\fR
+Report on the calibrated display then exit
+.TP
+\fB\-R\fR
+Report on the uncalibrated display then exit
+.TP
+\fB\-m\fR
+Skip adjustment of the monitor controls
+.TP
+\fB\-o\fR [profile.icc]
+Create fast matrix/shaper profile [different filename to outfile.icc]
+.TP
+\fB\-O\fR "description"
+Fast ICC Profile Description string (Default "outfile")
+.TP
+\fB\-u\fR
+Update previous calibration and (if \fB\-o\fR used) ICC profile VideoLUTs
+.TP
+\fB\-q\fR [vlmh]
+Quality \- Very Low, Low, Medium (def), High
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-t\fR [temp]
+White Daylight locus target, optional target temperaturee in deg. K (deflt.)
+.TP
+\fB\-T\fR [temp]
+White Black Body locus target, optional target temperaturee in deg. K
+.TP
+\fB\-w\fR x,y
+Set the target white point as chromaticity coordinates
+.TP
+\fB\-b\fR bright
+Set the target white brightness in cd/m^2
+.TP
+\fB\-g\fR gamma
+Set the target response curve advertised gamma (Def. 2.4)
+Use "\-gl" for L*a*b* curve
+Use "\-gs" for sRGB curve
+Use "\-g709" for REC 709 curve (should use \fB\-a\fR as well!)
+Use "\-g240" for SMPTE 240M curve (should use \fB\-a\fR as well!)
+Use "\-G2.4 \fB\-f0\fR" for BT.1886
+.TP
+\fB\-G\fR gamma
+Set the target response curve actual technical gamma
+.TP
+\fB\-f\fR [degree]
+Amount of black level accounted for with output offset (default all output offset)
+.TP
+\fB\-a\fR ambient
+Use viewing condition adjustment for ambient in Lux
+.TP
+\fB\-k\fR factor
+Amount to correct black hue, 0 = none, 1 = full, Default = Automatic
+.TP
+\fB\-A\fR rate
+Rate of blending from neutral to black point. Default 4.0
+.TP
+\fB\-B\fR blkbright
+Set the target black brightness in cd/m^2
+.TP
+\fB\-e\fR [n]
+Run n verify passes on final curves
+.TP
+\fB\-E\fR
+Run only verify pass on installed calibration curves
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-J\fR
+Run instrument calibration first (used rarely)
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectrometer or CCSS colorimeter data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2, 1964_10c
+.TP
+\fB\-I\fR b|w
+Drift compensation, Black: \fB\-Ib\fR, White: \fB\-Iw\fR, Both: \fB\-Ibw\fR
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-M\fR "command"
+Invoke shell "command" each time a color is measured
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+inoutfile
+Base name for created or updated .cal and .icc output files
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Usage requested
+usage: dispcal [options] outfile
+.TP
+\fB\-v\fR [n]
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 = 'Screen 1, Output VBOX0 at 0, 0, width 1605, height 1079'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-r\fR
+Report on the calibrated display then exit
+.TP
+\fB\-R\fR
+Report on the uncalibrated display then exit
+.TP
+\fB\-m\fR
+Skip adjustment of the monitor controls
+.TP
+\fB\-o\fR [profile.icc]
+Create fast matrix/shaper profile [different filename to outfile.icc]
+.TP
+\fB\-O\fR "description"
+Fast ICC Profile Description string (Default "outfile")
+.TP
+\fB\-u\fR
+Update previous calibration and (if \fB\-o\fR used) ICC profile VideoLUTs
+.TP
+\fB\-q\fR [vlmh]
+Quality \- Very Low, Low, Medium (def), High
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-t\fR [temp]
+White Daylight locus target, optional target temperaturee in deg. K (deflt.)
+.TP
+\fB\-T\fR [temp]
+White Black Body locus target, optional target temperaturee in deg. K
+.TP
+\fB\-w\fR x,y
+Set the target white point as chromaticity coordinates
+.TP
+\fB\-b\fR bright
+Set the target white brightness in cd/m^2
+.TP
+\fB\-g\fR gamma
+Set the target response curve advertised gamma (Def. 2.4)
+Use "\-gl" for L*a*b* curve
+Use "\-gs" for sRGB curve
+Use "\-g709" for REC 709 curve (should use \fB\-a\fR as well!)
+Use "\-g240" for SMPTE 240M curve (should use \fB\-a\fR as well!)
+Use "\-G2.4 \fB\-f0\fR" for BT.1886
+.TP
+\fB\-G\fR gamma
+Set the target response curve actual technical gamma
+.TP
+\fB\-f\fR [degree]
+Amount of black level accounted for with output offset (default all output offset)
+.TP
+\fB\-a\fR ambient
+Use viewing condition adjustment for ambient in Lux
+.TP
+\fB\-k\fR factor
+Amount to correct black hue, 0 = none, 1 = full, Default = Automatic
+.TP
+\fB\-A\fR rate
+Rate of blending from neutral to black point. Default 4.0
+.TP
+\fB\-B\fR blkbright
+Set the target black brightness in cd/m^2
+.TP
+\fB\-e\fR [n]
+Run n verify passes on final curves
+.TP
+\fB\-E\fR
+Run only verify pass on installed calibration curves
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-J\fR
+Run instrument calibration first (used rarely)
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectrometer or CCSS colorimeter data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2, 1964_10c
+.TP
+\fB\-I\fR b|w
+Drift compensation, Black: \fB\-Ib\fR, White: \fB\-Iw\fR, Both: \fB\-Ibw\fR
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-M\fR "command"
+Invoke shell "command" each time a color is measured
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+inoutfile
+Base name for created or updated .cal and .icc output files
diff --git a/debian/dispread.1 b/debian/dispread.1
new file mode 100644
index 0000000..44b042f
--- /dev/null
+++ b/debian/dispread.1
@@ -0,0 +1,183 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH READ "1" "August 2013" "Read a Display, Version 1.5.1" "User Commands"
+.SH NAME
+Read \- Read a Display.
+.SH DESCRIPTION
+Read a Display, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Usage requested
+usage: dispread [options] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 = 'Screen 1, Output VBOX0 at 0, 0, width 1605, height 1079'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-k\fR file.cal
+Load calibration file into display while reading
+.TP
+\fB\-K\fR file.cal
+Apply calibration file to test values while reading
+.TP
+\fB\-s\fR
+Save spectral information (default don't save)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-J\fR
+Run instrument calibration first (used rarely)
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-w\fR
+Disable normalisation of white to Y = 100
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectrometer or CCSS colorimeter data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2, 1964_10c
+.TP
+\fB\-I\fR b|w
+Drift compensation, Black: \fB\-Ib\fR, White: \fB\-Iw\fR, Both: \fB\-Ibw\fR
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-M\fR "command"
+Invoke shell "command" each time a color is measured
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+outfile
+Base name for input[ti1]/output[ti3] file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Usage requested
+usage: dispread [options] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for VideoLUT access
+.IP
+1 = 'Screen 1, Output VBOX0 at 0, 0, width 1605, height 1079'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-p\fR
+Use telephoto mode (ie. for a projector) (if available)
+.TP
+\fB\-k\fR file.cal
+Load calibration file into display while reading
+.TP
+\fB\-K\fR file.cal
+Apply calibration file to test values while reading
+.TP
+\fB\-s\fR
+Save spectral information (default don't save)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+ho,vi: 0.0 = left/top, 0.5 = center, 1.0 = right/bottom etc.
+ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-n\fR
+Don't set override redirect on test window
+.TP
+\fB\-J\fR
+Run instrument calibration first (used rarely)
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-w\fR
+Disable normalisation of white to Y = 100
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectrometer or CCSS colorimeter data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2, 1964_10c
+.TP
+\fB\-I\fR b|w
+Drift compensation, Black: \fB\-Ib\fR, White: \fB\-Iw\fR, Both: \fB\-Ibw\fR
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-C\fR "command"
+Invoke shell "command" each time a color is set
+.TP
+\fB\-M\fR "command"
+Invoke shell "command" each time a color is measured
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+outfile
+Base name for input[ti1]/output[ti3] file
diff --git a/debian/dispwin.1 b/debian/dispwin.1
new file mode 100644
index 0000000..6e1d5a1
--- /dev/null
+++ b/debian/dispwin.1
@@ -0,0 +1,151 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH TEST "1" "August 2013" "Test display patch window, Set Video LUTs, Install profiles, Version 1.5.1" "User Commands"
+.SH NAME
+Test \- Test display patch window, Set Video LUTs, Install profiles.
+.SH DESCRIPTION
+Test display patch window, Set Video LUTs, Install profiles, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Unknown flag '\-\-help'
+usage: dispwin [options] [calfile]
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for Video LUT access
+.IP
+1 = 'Screen 1, Output VBOX0 at 0, 0, width 1605, height 1079'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-i\fR
+Run forever with random values
+.TP
+\fB\-G\fR filename
+Display RGB colors from CGATS file
+.TP
+\fB\-m\fR
+Manually cycle through values
+.TP
+\fB\-f\fR
+Test grey ramp fade
+.TP
+\fB\-r\fR
+Test just Video LUT loading & Beeps
+.TP
+\fB\-n\fR
+Test native output (rather than through Video LUT)
+.TP
+\fB\-s\fR filename
+Save the currently loaded Video LUT to 'filename'
+.TP
+\fB\-c\fR
+Load a linear display calibration
+.TP
+\fB\-V\fR
+Verify that calfile/profile cal. is currently loaded in LUT
+.TP
+\fB\-I\fR
+Install profile for display and use it's calibration
+.TP
+\fB\-U\fR
+Un\-install profile for display
+.TP
+\fB\-S\fR d
+Specify the install/uninstall scope for OS X [nlu] or X11/Vista [lu]
+d is one of: n = network, l = local system, u = user (default)
+.TP
+\fB\-L\fR
+Load installed profiles cal. into Video LUT
+.TP
+\fB\-E\fR
+Run in daemon loader mode for given X11 server
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+calfile
+Load calibration (.cal or .icc) into Video LUT
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Unknown flag '\-\-version'
+usage: dispwin [options] [calfile]
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-display\fR displayname Choose X11 display name
+.TP
+\fB\-d\fR n[,m]
+Choose the display n from the following list (default 1)
+Optionally choose different display m for Video LUT access
+.IP
+1 = 'Screen 1, Output VBOX0 at 0, 0, width 1605, height 1079'
+.TP
+\fB\-dweb[\fR:port]
+Display via a web server at port (default 8080)
+.TP
+\fB\-P\fR ho,vo,ss[,vs]
+Position test window and scale it
+.TP
+\fB\-F\fR
+Fill whole screen with black background
+.TP
+\fB\-i\fR
+Run forever with random values
+.TP
+\fB\-G\fR filename
+Display RGB colors from CGATS file
+.TP
+\fB\-m\fR
+Manually cycle through values
+.TP
+\fB\-f\fR
+Test grey ramp fade
+.TP
+\fB\-r\fR
+Test just Video LUT loading & Beeps
+.TP
+\fB\-n\fR
+Test native output (rather than through Video LUT)
+.TP
+\fB\-s\fR filename
+Save the currently loaded Video LUT to 'filename'
+.TP
+\fB\-c\fR
+Load a linear display calibration
+.TP
+\fB\-V\fR
+Verify that calfile/profile cal. is currently loaded in LUT
+.TP
+\fB\-I\fR
+Install profile for display and use it's calibration
+.TP
+\fB\-U\fR
+Un\-install profile for display
+.TP
+\fB\-S\fR d
+Specify the install/uninstall scope for OS X [nlu] or X11/Vista [lu]
+d is one of: n = network, l = local system, u = user (default)
+.TP
+\fB\-L\fR
+Load installed profiles cal. into Video LUT
+.TP
+\fB\-E\fR
+Run in daemon loader mode for given X11 server
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+calfile
+Load calibration (.cal or .icc) into Video LUT
diff --git a/debian/extracticc.1 b/debian/extracticc.1
new file mode 100644
index 0000000..941e610
--- /dev/null
+++ b/debian/extracticc.1
@@ -0,0 +1,19 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH EXTRACT "1" "August 2013" "Extract an ICC profile from a TIFF or JPEG file, Version 1.5.1" "User Commands"
+.SH NAME
+Extract \- Extract an ICC profile from a TIFF file.
+.SH DESCRIPTION
+Extract an ICC profile from a TIFF or JPEG file, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Too few parameters
+usage: extracticc [\-v] infile.tif/jpg outfile.icc
+.TP
+\fB\-v\fR
+Verbose
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Too few parameters
+usage: extracticc [\-v] infile.tif/jpg outfile.icc
+.TP
+\fB\-v\fR
+Verbose
diff --git a/debian/extractttag.1 b/debian/extractttag.1
new file mode 100644
index 0000000..ee10a25
--- /dev/null
+++ b/debian/extractttag.1
@@ -0,0 +1,31 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH EXTRACT "1" "August 2013" "Extract a text tag from an ICC profile, Version 1.5.1" "User Commands"
+.SH NAME
+Extract \- Extract a text tag from an ICC profile.
+.SH DESCRIPTION
+Extract a text tag from an ICC profile, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Too few parameters
+usage: extractttag [\-v] infile.icc outfile
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-t\fR tag
+Extract this tag rather than default 'targ'
+.TP
+\fB\-c\fR
+Extract calibration file from 'targ' tag
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Too few parameters
+usage: extractttag [\-v] infile.icc outfile
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-t\fR tag
+Extract this tag rather than default 'targ'
+.TP
+\fB\-c\fR
+Extract calibration file from 'targ' tag
diff --git a/debian/fakeCMY.1 b/debian/fakeCMY.1
new file mode 100644
index 0000000..7cde10e
--- /dev/null
+++ b/debian/fakeCMY.1
@@ -0,0 +1,37 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create a fake CMY data file from a CMYK profile, Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create a fake CMY data file from a CMYK profile.
+.SH DESCRIPTION
+Create a fake CMY data file from a CMYK profile, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: fakeCMY [option] profile.icm fake.ti3
+Diagnostic: Unknown flag
+.TP
+\fB\-v\fR
+verbose
+.TP
+\fB\-r\fR res
+set surface point resolution (default 3)
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: fakeCMY [option] profile.icm fake.ti3
+Diagnostic: Unknown flag
+.TP
+\fB\-v\fR
+verbose
+.TP
+\fB\-r\fR res
+set surface point resolution (default 3)
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
diff --git a/debian/fakeread.1 b/debian/fakeread.1
new file mode 100644
index 0000000..68d4211
--- /dev/null
+++ b/debian/fakeread.1
@@ -0,0 +1,107 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH FAKE "1" "August 2013" "Fake test chart reader - lookup values in ICC/MPP profile, Version 1.5.1" "User Commands"
+.SH NAME
+Fake \- Fake test chart reader - lookup values in ICC/MPP profile.
+.SH DESCRIPTION
+Fake test chart reader \- lookup values in ICC/MPP profile, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Too few arguments
+.PP
+usage: fakeread [\-v] [\-s] [separation.icm] profile.[icc|mpp|ti3] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-s\fR
+Lookup MPP spectral values
+.TP
+\fB\-p\fR
+Use separation profile
+.TP
+\fB\-l\fR
+Output Lab rather than XYZ
+.TP
+\fB\-k\fR file.cal
+Apply calibration (after sep.) and include in .ti3
+.TP
+\fB\-i\fR file.cal
+Include calibration in .ti3 (but don't apply it)
+.TP
+\fB\-r\fR level
+Add average random deviation of <level>% to input device values (after sep. & cal.)
+.TP
+\fB\-0\fR pow
+Apply power to input device chanel 0\-9 (after sep. cal. & rand)
+.TP
+\fB\-R\fR level
+Add average random deviation of <level>% to output PCS values
+.TP
+\fB\-u\fR
+Make random deviations have uniform distributions rather than normal
+.TP
+\fB\-S\fR seed
+Set random seed
+.TP
+\fB\-b\fR L,a,b
+Scale black point to target Lab value
+.TP
+\fB\-I\fR intent
+r = relative colorimetric, a = absolute (default)
+.TP
+[separation.icc]
+Device link separation profile
+.IP
+profile.[icc|mpp|ti3] ICC, MPP profile or TI3 to use
+outfile Base name for input[ti1]/output[ti3] file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Too few arguments
+.PP
+usage: fakeread [\-v] [\-s] [separation.icm] profile.[icc|mpp|ti3] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-s\fR
+Lookup MPP spectral values
+.TP
+\fB\-p\fR
+Use separation profile
+.TP
+\fB\-l\fR
+Output Lab rather than XYZ
+.TP
+\fB\-k\fR file.cal
+Apply calibration (after sep.) and include in .ti3
+.TP
+\fB\-i\fR file.cal
+Include calibration in .ti3 (but don't apply it)
+.TP
+\fB\-r\fR level
+Add average random deviation of <level>% to input device values (after sep. & cal.)
+.TP
+\fB\-0\fR pow
+Apply power to input device chanel 0\-9 (after sep. cal. & rand)
+.TP
+\fB\-R\fR level
+Add average random deviation of <level>% to output PCS values
+.TP
+\fB\-u\fR
+Make random deviations have uniform distributions rather than normal
+.TP
+\fB\-S\fR seed
+Set random seed
+.TP
+\fB\-b\fR L,a,b
+Scale black point to target Lab value
+.TP
+\fB\-I\fR intent
+r = relative colorimetric, a = absolute (default)
+.TP
+[separation.icc]
+Device link separation profile
+.IP
+profile.[icc|mpp|ti3] ICC, MPP profile or TI3 to use
+outfile Base name for input[ti1]/output[ti3] file
diff --git a/debian/greytiff.1 b/debian/greytiff.1
new file mode 100644
index 0000000..93a7e31
--- /dev/null
+++ b/debian/greytiff.1
@@ -0,0 +1,29 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CONVERT "1" "August 2013" "Convert a TIFF file to monochrome using an ICC device profile, V1.5.1" "User Commands"
+.SH NAME
+Convert \- Convert a TIFF file to monochrome using an ICC device profile.
+.SH DESCRIPTION
+Convert a TIFF file to monochrome using an ICC device profile, V1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: greytiff [\-v level] profile.icm infile.tif outfile.tif
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-p\fR
+Use slow precise correction
+.TP
+\fB\-j\fR
+Use CIECAM02
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: greytiff [\-v level] profile.icm infile.tif outfile.tif
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-p\fR
+Use slow precise correction
+.TP
+\fB\-j\fR
+Use CIECAM02
diff --git a/debian/icc-utils.install b/debian/icc-utils.install
new file mode 100644
index 0000000..fc29bc0
--- /dev/null
+++ b/debian/icc-utils.install
@@ -0,0 +1,2 @@
+usr/bin/icclu
+usr/bin/iccdump
diff --git a/debian/icc-utils.manpages b/debian/icc-utils.manpages
new file mode 100644
index 0000000..edf8334
--- /dev/null
+++ b/debian/icc-utils.manpages
@@ -0,0 +1,2 @@
+debian/iccdump.1
+debian/icclu.1
diff --git a/debian/iccdump.1 b/debian/iccdump.1
new file mode 100644
index 0000000..3d1b8ef
--- /dev/null
+++ b/debian/iccdump.1
@@ -0,0 +1,35 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH DUMP "1" "August 2013" "Dump an ICC file in human readable form, V2.16" "User Commands"
+.SH NAME
+Dump \- Dump an ICC file in human readable form.
+.SH DESCRIPTION
+Dump an ICC file in human readable form, V2.16
+Author: Graeme W. Gill
+usage: iccdump [\-v level] [\-t tagname] [\-s] infile
+.TP
+\fB\-v\fR level
+Verbose level 1\-3 (default 2)
+.TP
+\fB\-t\fR tag
+Dump this tag only (can be used multiple times)
+.TP
+\fB\-s\fR
+Search for embedded profile
+.TP
+\fB\-i\fR
+Check V4 ID value
+.PP
+Author: Graeme W. Gill
+usage: iccdump [\-v level] [\-t tagname] [\-s] infile
+.TP
+\fB\-v\fR level
+Verbose level 1\-3 (default 2)
+.TP
+\fB\-t\fR tag
+Dump this tag only (can be used multiple times)
+.TP
+\fB\-s\fR
+Search for embedded profile
+.TP
+\fB\-i\fR
+Check V4 ID value
diff --git a/debian/iccgamut.1 b/debian/iccgamut.1
new file mode 100644
index 0000000..28abb13
--- /dev/null
+++ b/debian/iccgamut.1
@@ -0,0 +1,181 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create Lab/Jab gamut plot Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create Lab/Jab gamut plot.
+.SH DESCRIPTION
+Create Lab/Jab gamut plot Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: iccgamut [options] profile
+Diagnostic: Unknown flag
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-d\fR sres
+Surface resolution details 1.0 \- 50.0
+.TP
+\fB\-w\fR
+emit VRML .wrl file as well as CGATS .gam file
+.TP
+\fB\-n\fR
+Don't add VRML axes or white/black point
+.TP
+\fB\-k\fR
+Add VRML markers for prim. & sec. "cusp" points
+.TP
+\fB\-f\fR function
+f = forward*, b = backwards
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute (default), d = profile default
+.TP
+\fB\-p\fR oride
+l = Lab_PCS (default), j = CIECAM02 Appearance Jab
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-c\fR viewcond
+set viewing conditions for CIECAM02,
+either an enumerated choice, or a series of parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:scenewhite
+Scene white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 1)
+.TP
+f:X:Y:Z
+Flare color as XYZ (default media white)
+.TP
+f:x:y
+Flare color as x, y
+.TP
+\fB\-s\fR
+Create special cube surface topology plot
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: iccgamut [options] profile
+Diagnostic: Unknown flag
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-d\fR sres
+Surface resolution details 1.0 \- 50.0
+.TP
+\fB\-w\fR
+emit VRML .wrl file as well as CGATS .gam file
+.TP
+\fB\-n\fR
+Don't add VRML axes or white/black point
+.TP
+\fB\-k\fR
+Add VRML markers for prim. & sec. "cusp" points
+.TP
+\fB\-f\fR function
+f = forward*, b = backwards
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute (default), d = profile default
+.TP
+\fB\-p\fR oride
+l = Lab_PCS (default), j = CIECAM02 Appearance Jab
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-c\fR viewcond
+set viewing conditions for CIECAM02,
+either an enumerated choice, or a series of parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:scenewhite
+Scene white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 1)
+.TP
+f:X:Y:Z
+Flare color as XYZ (default media white)
+.TP
+f:x:y
+Flare color as x, y
+.TP
+\fB\-s\fR
+Create special cube surface topology plot
diff --git a/debian/icclu.1 b/debian/icclu.1
new file mode 100644
index 0000000..f0239a6
--- /dev/null
+++ b/debian/icclu.1
@@ -0,0 +1,61 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH TRANSLATE "1" "August 2013" "Translate colors through an ICC profile, V2.16" "User Commands"
+.SH NAME
+Translate \- Translate colors through an ICC profile.
+.SH DESCRIPTION
+Translate colors through an ICC profile, V2.16
+Author: Graeme W. Gill
+usage: icclu [\-v level] [\-f func] [\-i intent] [\-o order] profile
+.TP
+\fB\-v\fR level
+Verbosity level 0 \- 2 (default = 1)
+.TP
+\fB\-f\fR function
+f = forward, b = backwards, g = gamut, p = preview
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, l = Lab_PCS, y = Yxy,
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-s\fR scale
+Scale device range 0.0 \- scale rather than 0.0 \- 1.0
+.IP
+The colors to be translated should be fed into standard input,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
+.PP
+Author: Graeme W. Gill
+usage: icclu [\-v level] [\-f func] [\-i intent] [\-o order] profile
+.TP
+\fB\-v\fR level
+Verbosity level 0 \- 2 (default = 1)
+.TP
+\fB\-f\fR function
+f = forward, b = backwards, g = gamut, p = preview
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, l = Lab_PCS, y = Yxy,
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-s\fR scale
+Scale device range 0.0 \- scale rather than 0.0 \- 1.0
+.IP
+The colors to be translated should be fed into standard input,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
diff --git a/debian/illumread.1 b/debian/illumread.1
new file mode 100644
index 0000000..07f7ba0
--- /dev/null
+++ b/debian/illumread.1
@@ -0,0 +1,63 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH MEASURE "1" "August 2013" "Measure an illuminant, Version 1.5.1" "User Commands"
+.SH NAME
+Measure \- Measure an illuminant.
+.SH DESCRIPTION
+Measure an illuminant, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: illumread [\-options] output.sp
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-S\fR
+Plot spectrum for each reading
+.TP
+\fB\-c\fR listno
+Choose instrument from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+illuminant.sp
+File to save measurement to
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: illumread [\-options] output.sp
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-S\fR
+Plot spectrum for each reading
+.TP
+\fB\-c\fR listno
+Choose instrument from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-N\fR
+Disable initial calibration of instrument if possible
+.TP
+\fB\-H\fR
+Use high resolution spectrum mode (if available)
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+illuminant.sp
+File to save measurement to
diff --git a/debian/invprofcheck.1 b/debian/invprofcheck.1
new file mode 100644
index 0000000..d3781b3
--- /dev/null
+++ b/debian/invprofcheck.1
@@ -0,0 +1,83 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CHECK "1" "August 2013" "Check fwd to bwd relative transfer of an ICC file, Version 1.5.1" "User Commands"
+.SH NAME
+Check \- Check fwd to bwd relative transfer of an ICC file.
+.SH DESCRIPTION
+Check fwd to bwd relative transfer of an ICC file, Version 1.5.1
+Author: Graeme W. Gill
+usage: invprofcheck [\-] profile.icm
+.TP
+\fB\-v\fR [level]
+verbosity level (default 1), 2 to print each DE
+.TP
+\fB\-l\fR limit
+set total ink limit (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black channel ink limit (estimate by default)
+.TP
+\fB\-h\fR
+high res test (27)
+.TP
+\fB\-u\fR
+Ultra high res test (61)
+.TP
+\fB\-R\fR res
+Specific grid resolution
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-w\fR
+create VRML visualisation (profile.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-e\fR
+Color vectors acording to delta E
+.TP
+profile.icm
+Profile to check
+.PP
+Author: Graeme W. Gill
+usage: invprofcheck [\-] profile.icm
+.TP
+\fB\-v\fR [level]
+verbosity level (default 1), 2 to print each DE
+.TP
+\fB\-l\fR limit
+set total ink limit (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black channel ink limit (estimate by default)
+.TP
+\fB\-h\fR
+high res test (27)
+.TP
+\fB\-u\fR
+Ultra high res test (61)
+.TP
+\fB\-R\fR res
+Specific grid resolution
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-w\fR
+create VRML visualisation (profile.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-e\fR
+Color vectors acording to delta E
+.TP
+profile.icm
+Profile to check
diff --git a/debian/kodak2ti3.1 b/debian/kodak2ti3.1
new file mode 100644
index 0000000..325b564
--- /dev/null
+++ b/debian/kodak2ti3.1
@@ -0,0 +1,41 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CONVERT "1" "August 2013" "Convert Kodak raw printer profile data to Argyll print data, Version 1.5.1" "User Commands"
+.SH NAME
+Convert \- Convert Kodak raw printer profile data to Argyll print data.
+.SH DESCRIPTION
+Convert Kodak raw printer profile data to Argyll print data, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: kodak2ti3 [\-v] [\-l limit] infile outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-l\fR limit
+set ink limit, 0 \- 400%
+.TP
+\fB\-r\fR filename
+Use an alternate 928 patch reference file
+.TP
+infile
+Base name for input.pat file
+.TP
+outfile
+Base name for output.ti3 file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: kodak2ti3 [\-v] [\-l limit] infile outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-l\fR limit
+set ink limit, 0 \- 400%
+.TP
+\fB\-r\fR filename
+Use an alternate 928 patch reference file
+.TP
+infile
+Base name for input.pat file
+.TP
+outfile
+Base name for output.ti3 file
diff --git a/debian/libicc-dev.install b/debian/libicc-dev.install
new file mode 100644
index 0000000..bd6bae2
--- /dev/null
+++ b/debian/libicc-dev.install
@@ -0,0 +1,4 @@
+usr/include/icc.h
+usr/include/iccV42.h
+usr/lib/*/libicc.a
+usr/lib/*/libicc.so
diff --git a/debian/libicc2.install b/debian/libicc2.install
new file mode 100644
index 0000000..453ba88
--- /dev/null
+++ b/debian/libicc2.install
@@ -0,0 +1 @@
+usr/lib/*/libicc*.so.*
diff --git a/debian/libicc2.symbols b/debian/libicc2.symbols
new file mode 100644
index 0000000..fa91e97
--- /dev/null
+++ b/debian/libicc2.symbols
@@ -0,0 +1,103 @@
+libicc.so.2 libicc2 #MINVER#
+ icc_new_icmLuLut@Base 1.5.1
+ icm1960UCS21964WUV@Base 1.5.1
+ icm1960UCS2XYZ@Base 1.5.1
+ icm1964WUV2XYZ@Base 1.5.1
+ icm1976UCS2XYZ@Base 1.5.1
+ icm2str@Base 1.5.1
+ icmAdd3@Base 1.5.1
+ icmAdd3x3@Base 1.5.1
+ icmBlack@Base 1.5.1
+ icmBlend3@Base 1.5.1
+ icmCIE2K@Base 1.5.1
+ icmCIE2Ksq@Base 1.5.1
+ icmCIE94@Base 1.5.1
+ icmCIE94sq@Base 1.5.1
+ icmCSSig2chanNames@Base 1.5.1
+ icmCSSig2nchan@Base 1.5.1
+ icmChromAdaptMatrix@Base 1.5.1
+ icmClamp3@Base 1.5.1
+ icmClipLab@Base 1.5.1
+ icmClipXYZ@Base 1.5.1
+ icmCpy3x3@Base 1.5.1
+ icmCpy3x4@Base 1.5.1
+ icmCross3@Base 1.5.1
+ icmD50@Base 1.5.1
+ icmD50_100@Base 1.5.1
+ icmD50_100_ary3@Base 1.5.1
+ icmD50_ary3@Base 1.5.1
+ icmD65@Base 1.5.1
+ icmD65_100@Base 1.5.1
+ icmD65_100_ary3@Base 1.5.1
+ icmD65_ary3@Base 1.5.1
+ icmDet3x3@Base 1.5.1
+ icmDot3@Base 1.5.1
+ icmInverse3x3@Base 1.5.1
+ icmL2Y@Base 1.5.1
+ icmLCh2Lab@Base 1.5.1
+ icmLab2LCh@Base 1.5.1
+ icmLab2XYZ@Base 1.5.1
+ icmLabDE@Base 1.5.1
+ icmLabDEsq@Base 1.5.1
+ icmLineLineClosest@Base 1.5.1
+ icmLuv2XYZ@Base 1.5.1
+ icmMul3By3x4@Base 1.5.1
+ icmMul3x3@Base 1.5.1
+ icmMul3x3_2@Base 1.5.1
+ icmMulBy2x2@Base 1.5.1
+ icmMulBy3x3@Base 1.5.1
+ icmNorm33@Base 1.5.1
+ icmNorm33sq@Base 1.5.1
+ icmNorm3@Base 1.5.1
+ icmNorm3sq@Base 1.5.1
+ icmNormalize33@Base 1.5.1
+ icmNormalize3@Base 1.5.1
+ icmPLab@Base 1.5.1
+ icmPdv@Base 1.5.1
+ icmPfv@Base 1.5.1
+ icmPiv@Base 1.5.1
+ icmPlaneDist3@Base 1.5.1
+ icmPlaneEqn3@Base 1.5.1
+ icmRGBprim2matrix@Base 1.5.1
+ icmRotMat@Base 1.5.1
+ icmScale33@Base 1.5.1
+ icmScale3@Base 1.5.1
+ icmScale3x3@Base 1.5.1
+ icmSetMultiLutTables@Base 1.5.1
+ icmSetUnity3x3@Base 1.5.1
+ icmSub3@Base 1.5.1
+ icmTensMul3@Base 1.5.1
+ icmTranspose3x3@Base 1.5.1
+ icmVecPlaneIsect@Base 1.5.1
+ icmVecRotMat@Base 1.5.1
+ icmXYZ21960UCS@Base 1.5.1
+ icmXYZ21964WUV@Base 1.5.1
+ icmXYZ21976UCS@Base 1.5.1
+ icmXYZ2Lab@Base 1.5.1
+ icmXYZ2Luv@Base 1.5.1
+ icmXYZ2Yxy@Base 1.5.1
+ icmXYZCIE2K@Base 1.5.1
+ icmXYZCIE94@Base 1.5.1
+ icmXYZLabDE@Base 1.5.1
+ icmY2L@Base 1.5.1
+ icmYxy2XYZ@Base 1.5.1
+ new_icc@Base 1.5.1
+ new_icc_a@Base 1.5.1
+ new_icmAllocStd@Base 1.5.1
+ new_icmFileMD5_a@Base 1.5.1
+ new_icmFileMem@Base 1.5.1
+ new_icmFileMem_a@Base 1.5.1
+ new_icmFileMem_ad@Base 1.5.1
+ new_icmFileMem_d@Base 1.5.1
+ new_icmFileStd_fp@Base 1.5.1
+ new_icmFileStd_fp_a@Base 1.5.1
+ new_icmFileStd_name@Base 1.5.1
+ new_icmFileStd_name_a@Base 1.5.1
+ new_icmMD5@Base 1.5.1
+ psh_inc@Base 1.5.1
+ psh_init@Base 1.5.1
+ psh_reset@Base 1.5.1
+ read_Primitive@Base 1.5.1
+ str2tag@Base 1.5.1
+ tag2str@Base 1.5.1
+ write_Primitive@Base 1.5.1
diff --git a/debian/libimdi-dev.install b/debian/libimdi-dev.install
new file mode 100644
index 0000000..88d4ce7
--- /dev/null
+++ b/debian/libimdi-dev.install
@@ -0,0 +1,8 @@
+usr/include/imdi_arch.h
+usr/include/imdi_gen.h
+usr/include/imdi.h
+usr/include/imdi_tab.h
+usr/include/imdi_utl.h
+usr/include/refi.h
+usr/lib/*/libimdi.a
+usr/lib/*/libimdi.so
diff --git a/debian/libimdi0.install b/debian/libimdi0.install
new file mode 100644
index 0000000..58a0992
--- /dev/null
+++ b/debian/libimdi0.install
@@ -0,0 +1 @@
+usr/lib/*/libimdi*.so.*
diff --git a/debian/libimdi0.symbols b/debian/libimdi0.symbols
new file mode 100644
index 0000000..1f00372
--- /dev/null
+++ b/debian/libimdi0.symbols
@@ -0,0 +1,16 @@
+libimdi.so.0 libimdi0 #MINVER#
+ (regex)"^imdi_k\d+@Base$" 1.5.1
+ (regex)"^imdi_k\d+_gentab@Base$" 1.5.1
+ imdi_tab@Base 1.5.1
+ imdi_tab_free@Base 1.5.1
+ in_adj@Base 1.5.1
+ ktable@Base 1.5.1
+ new_imdi@Base 1.5.1
+ no_kfuncs@Base 1.5.1
+ write_default@Base 1.5.1
+ write_entry@Base 1.5.1
+ write_uchar@Base 1.5.1
+ write_uint@Base 1.5.1
+ write_ulong@Base 1.5.1
+ write_ulonglong@Base 1.5.1
+ write_ushort@Base 1.5.1
diff --git a/debian/mppcheck.1 b/debian/mppcheck.1
new file mode 100644
index 0000000..9aad8d6
--- /dev/null
+++ b/debian/mppcheck.1
@@ -0,0 +1,51 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CHECK "1" "August 2013" "Check Model Printer Profile, Version 1.5.1" "User Commands"
+.SH NAME
+Check \- Check Model Printer Profile.
+.SH DESCRIPTION
+Check Model Printer Profile, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: debian/tmp/usr/bin/mppcheck [\-v] [\-c] [\-s] [\-y] values.ti3 profile.mpp
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-s\fR
+Check spectral model too
+.TP
+\fB\-y\fR
+Detail each value
+.TP
+values.ti3
+Test values to check against
+.IP
+profile.mpp Profile to check
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: debian/tmp/usr/bin/mppcheck [\-v] [\-c] [\-s] [\-y] values.ti3 profile.mpp
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-s\fR
+Check spectral model too
+.TP
+\fB\-y\fR
+Detail each value
+.TP
+values.ti3
+Test values to check against
+.IP
+profile.mpp Profile to check
diff --git a/debian/mpplu.1 b/debian/mpplu.1
new file mode 100644
index 0000000..ad19c94
--- /dev/null
+++ b/debian/mpplu.1
@@ -0,0 +1,107 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH TRANSLATE "1" "August 2013" "Translate colors through an MPP profile, V1.00" "User Commands"
+.SH NAME
+Translate \- Translate colors through an MPP profile.
+.SH DESCRIPTION
+Translate colors through an MPP profile, V1.00
+Author: Graeme W. Gill
+usage: mpplu [\-v] [\-f func] [\-i intent] [\-o order] profile
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-f\fR function
+f = forward, b = backwards
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, l = Lab_PCS, y = Yxy, s = spectral,
+.TP
+\fB\-l\fR limit
+override default ink limit, 1 \- N00%
+.TP
+\fB\-i\fR illum
+Choose illuminant for print/transparency spectral data:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-u\fR
+Use Fluorescent Whitening Agent compensation
+.TP
+\fB\-g\fR
+Create gamut output
+.TP
+\fB\-w\fR
+Create gamut VRML as well
+.TP
+\fB\-n\fR
+Don't add VRML axes
+.TP
+\fB\-a\fR n
+Gamut transparency level
+.TP
+\fB\-d\fR n
+Gamut surface detail level
+.TP
+\fB\-t\fR num
+Invoke debugging test code "num" 1..n
+1 \- check partial derivative for device input
+2 \- create overlap diagnostic VRML gamut surface
+.IP
+The colors to be translated should be fed into stdin,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
+.PP
+Author: Graeme W. Gill
+usage: mpplu [\-v] [\-f func] [\-i intent] [\-o order] profile
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-f\fR function
+f = forward, b = backwards
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, l = Lab_PCS, y = Yxy, s = spectral,
+.TP
+\fB\-l\fR limit
+override default ink limit, 1 \- N00%
+.TP
+\fB\-i\fR illum
+Choose illuminant for print/transparency spectral data:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-u\fR
+Use Fluorescent Whitening Agent compensation
+.TP
+\fB\-g\fR
+Create gamut output
+.TP
+\fB\-w\fR
+Create gamut VRML as well
+.TP
+\fB\-n\fR
+Don't add VRML axes
+.TP
+\fB\-a\fR n
+Gamut transparency level
+.TP
+\fB\-d\fR n
+Gamut surface detail level
+.TP
+\fB\-t\fR num
+Invoke debugging test code "num" 1..n
+1 \- check partial derivative for device input
+2 \- create overlap diagnostic VRML gamut surface
+.IP
+The colors to be translated should be fed into stdin,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
diff --git a/debian/mppprof.1 b/debian/mppprof.1
new file mode 100644
index 0000000..007453f
--- /dev/null
+++ b/debian/mppprof.1
@@ -0,0 +1,53 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create Model Printer Profile, Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create Model Printer Profile.
+.SH DESCRIPTION
+Create Model Printer Profile, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: debian/tmp/usr/bin/mppprof [options] outfile
+.HP
+\fB\-v\fR [level] Verbose mode
+.HP
+\fB\-q\fR [lmhus] Quality \- Low, Medium (def), High, Ultra, Simple
+.TP
+\fB\-l\fR limit
+override default ink limit, 1 \- n00%
+.TP
+\fB\-s\fR
+Generate spectral model too
+.TP
+\fB\-m\fR
+Generate ink mixing model
+.HP
+\fB\-y\fR [level] Verify profile, 2 = read/write verify
+.TP
+\fB\-L\fR
+Output Lab values
+.TP
+outfile
+Base name for input.ti3/output.mpp file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: debian/tmp/usr/bin/mppprof [options] outfile
+.HP
+\fB\-v\fR [level] Verbose mode
+.HP
+\fB\-q\fR [lmhus] Quality \- Low, Medium (def), High, Ultra, Simple
+.TP
+\fB\-l\fR limit
+override default ink limit, 1 \- n00%
+.TP
+\fB\-s\fR
+Generate spectral model too
+.TP
+\fB\-m\fR
+Generate ink mixing model
+.HP
+\fB\-y\fR [level] Verify profile, 2 = read/write verify
+.TP
+\fB\-L\fR
+Output Lab values
+.TP
+outfile
+Base name for input.ti3/output.mpp file
diff --git a/debian/oeminst.1 b/debian/oeminst.1
new file mode 100644
index 0000000..8db1f8a
--- /dev/null
+++ b/debian/oeminst.1
@@ -0,0 +1,49 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH INSTALL "1" "August 2013" "Install OEM data files, Version 1.5.1" "User Commands"
+.SH NAME
+Install \- List information about the FILEs.
+.SH DESCRIPTION
+Install OEM data files, Version 1.5.1
+Author: Graeme W. Gill, licensed under the GPL Version 2 or later
+usage: oeminst [\-options] [infile(s)]
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-n\fR
+Don't install, show where files would be installed
+.TP
+\fB\-c\fR
+Don't install, save files to current directory
+.TP
+\fB\-S\fR d
+Specify the install scope u = user (def.), l = local system]
+.TP
+infile
+setup.exe CD install file(s) or .dll(s) containing install files
+.TP
+infile.[edr|ccss|ccmx]
+EDR file(s) to translate and install or CCSS or CCMX files to install
+If no file is provided, oeminst will look for the install CD.
+.PP
+Author: Graeme W. Gill, licensed under the GPL Version 2 or later
+usage: oeminst [\-options] [infile(s)]
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-n\fR
+Don't install, show where files would be installed
+.TP
+\fB\-c\fR
+Don't install, save files to current directory
+.TP
+\fB\-S\fR d
+Specify the install scope u = user (def.), l = local system]
+.TP
+infile
+setup.exe CD install file(s) or .dll(s) containing install files
+.TP
+infile.[edr|ccss|ccmx]
+EDR file(s) to translate and install or CCSS or CCMX files to install
+If no file is provided, oeminst will look for the install CD.
diff --git a/debian/patches/01_autotools-support.diff b/debian/patches/01_autotools-support.diff
new file mode 100644
index 0000000..8e0a6fe
--- /dev/null
+++ b/debian/patches/01_autotools-support.diff
@@ -0,0 +1,31463 @@
+--- /dev/null
++++ b/Makefile.shared
+@@ -0,0 +1,15 @@
++# Common CFLAGS for Argyll components
++
++AM_CFLAGS = -D_GNU_SOURCE -DUNIX -DENABLE_USB -DENABLE_SERIAL -I$(top_srcdir)/cgats \
++ -I$(top_srcdir)/gamut -I$(top_srcdir)/h -I$(top_srcdir)/jcnf \
++ -I$(top_srcdir)/libusb1/libusb -I$(top_srcdir)/numlib \
++ -I$(top_srcdir)/plot -I$(top_srcdir)/profile -I$(top_srcdir)/render \
++ -I$(top_srcdir)/rspl -I$(top_srcdir)/spectro -I$(top_srcdir)/target \
++ -I$(top_srcdir)/ucmm -I$(top_srcdir)/xicc $(TIFF_CFLAGS) $(ICC_CFLAGS) \
++ $(YAJL_CFLAGS) -L$(top_srcdir)/spectro
++
++# Build libs in other dirs when required
++../%.la:
++ $(MAKE) -C $(@D) $(@F)
++./%.la:
++ $(MAKE) -C $(@D) $(@F)
+--- /dev/null
++++ b/config.h.in
+@@ -0,0 +1,95 @@
++/* config.h.in. Generated from configure.ac by autoheader. */
++
++/* Define if building universal (internal helper macro) */
++#undef AC_APPLE_UNIVERSAL_BUILD
++
++/* Default visibility */
++#undef API_EXPORTED
++
++/* Define to 1 if you have the <dlfcn.h> header file. */
++#undef HAVE_DLFCN_H
++
++/* Define to 1 if you have the <inttypes.h> header file. */
++#undef HAVE_INTTYPES_H
++
++/* Define to 1 if you have the `m' library (-lm). */
++#undef HAVE_LIBM
++
++/* Define to 1 if you have the `pthread' library (-lpthread). */
++#undef HAVE_LIBPTHREAD
++
++/* Define to 1 if you have the `rt' library (-lrt). */
++#undef HAVE_LIBRT
++
++/* Define to 1 if you have the <memory.h> header file. */
++#undef HAVE_MEMORY_H
++
++/* Define to 1 if you have the <stdint.h> header file. */
++#undef HAVE_STDINT_H
++
++/* Define to 1 if you have the <stdlib.h> header file. */
++#undef HAVE_STDLIB_H
++
++/* Define to 1 if you have the <strings.h> header file. */
++#undef HAVE_STRINGS_H
++
++/* Define to 1 if you have the <string.h> header file. */
++#undef HAVE_STRING_H
++
++/* Define to 1 if you have the <sys/stat.h> header file. */
++#undef HAVE_SYS_STAT_H
++
++/* Define to 1 if you have the <sys/types.h> header file. */
++#undef HAVE_SYS_TYPES_H
++
++/* Define to 1 if you have the <unistd.h> header file. */
++#undef HAVE_UNISTD_H
++
++/* Define to the sub-directory in which libtool stores uninstalled libraries.
++ */
++#undef LT_OBJDIR
++
++/* Linux kernel */
++#undef OS_LINUX
++
++/* Name of package */
++#undef PACKAGE
++
++/* Define to the address where bug reports for this package should be sent. */
++#undef PACKAGE_BUGREPORT
++
++/* Define to the full name of this package. */
++#undef PACKAGE_NAME
++
++/* Define to the full name and version of this package. */
++#undef PACKAGE_STRING
++
++/* Define to the one symbol short name of this package. */
++#undef PACKAGE_TARNAME
++
++/* Define to the home page for this package. */
++#undef PACKAGE_URL
++
++/* Define to the version of this package. */
++#undef PACKAGE_VERSION
++
++/* Define to 1 if you have the ANSI C header files. */
++#undef STDC_HEADERS
++
++/* Version number of package */
++#undef VERSION
++
++/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
++ significant byte first (like Motorola and SPARC, unlike Intel). */
++#if defined AC_APPLE_UNIVERSAL_BUILD
++# if defined __BIG_ENDIAN__
++# define WORDS_BIGENDIAN 1
++# endif
++#else
++# ifndef WORDS_BIGENDIAN
++# undef WORDS_BIGENDIAN
++# endif
++#endif
++
++/* Define to 1 if the X Window System is missing or not being used. */
++#undef X_DISPLAY_MISSING
+--- /dev/null
++++ b/Makefile.am
+@@ -0,0 +1,23 @@
++include $(top_srcdir)/Makefile.shared
++
++ACLOCAL_AMFLAGS = -I m4
++
++privatelib_LTLIBRARIES = libargyll.la
++privatelibdir = $(pkglibdir)
++
++libargyll_la_SOURCES = xicc/xicc.c xicc/xicc.h xicc/xcam.c xicc/xcam.h \
++ gamut/gamut.c gamut/gamut.h xicc/xfit.c xicc/xfit.h \
++ xicc/cam97s3.c xicc/cam97s3.h xicc/cam02.c xicc/cam02.h \
++ xicc/moncurve.c xicc/moncurve.h xicc/xspect.c xicc/xspect.h \
++ xicc/xcal.c xicc/xcal.h xicc/xcolorants.h xicc/xcolorants.c xicc/ccmx.c
++libargyll_la_LIBADD = ./rspl/librspl.la $(ICC_LIBS) \
++ ./numlib/libargyllnum.la ./cgats/libcgats.la
++
++SUBDIRS = h doc ref numlib cgats $(ICC_SUBDIRS) plot rspl jcnf ucmm render . gamut \
++ spectro xicc target link tweak profile scanin imdi
++
++#SUBDIRS = h doc ref numlib cgats $(ICC_SUBDIRS) plot rspl jcnf ucmm render . gamut \
++# spectro xicc target link tweak profile scanin imdi
++
++
++EXTRA_DIST = Readme.txt ttbd.txt log.txt
+--- /dev/null
++++ b/configure.ac
+@@ -0,0 +1,133 @@
++AC_INIT([argyll], [1.3.7])
++AM_INIT_AUTOMAKE([1.9 foreign])
++
++AC_PROG_CC
++LT_INIT
++AC_PROG_INSTALL
++
++AM_PROG_LIBTOOL
++AC_PROG_LIBTOOL
++
++AC_CONFIG_MACRO_DIR([m4])
++AM_CONFIG_HEADER([config.h])
++
++AC_PATH_XTRA
++
++AC_CHECK_LIB(m, sqrt)
++AC_CHECK_LIB(pthread, pthread_create)
++
++AC_CHECK_LIB(tiff, TIFFOpen, TIFF_LIBS="-ltiff", , -lm)
++AC_SUBST([TIFF_LIBS])
++
++AC_CHECK_LIB(rt, clock_gettime)
++
++AC_ARG_WITH(system-libicc, [ --with-system-libicc use system libicc instead of argyllcms copy],system_libicc=$withval,system_libicc=no)
++AC_MSG_CHECKING([whether to use system libicc or not])
++if test x$system_libicc = xno ; then
++ HAVE_ICC=false
++ AC_MSG_RESULT(no)
++else
++ AC_MSG_RESULT(yes)
++ AC_CHECK_LIB(icc, new_icmFileStd_name, HAVE_ICC="true", , -lm)
++ if test "$HAVE_ICC" != "true" ; then
++ AC_MSG_ERROR([system libicc missing or not compatible with argyllcms])
++ fi
++fi
++if test "$HAVE_ICC" = "true" ; then
++ ICC_LIBS="-licc"
++else
++ ICC_LIBS='$(top_srcdir)/icc/libicc.la'
++ ICC_CFLAGS='-I$(top_srcdir)/icc'
++ ICC_SUBDIRS='icc'
++fi
++AC_SUBST([ICC_LIBS])
++AC_SUBST([ICC_CFLAGS])
++AC_SUBST([ICC_SUBDIRS])
++
++AC_ARG_WITH(system-libyajl, [ --with-system-libyajl use system libyajl instead of argyllcms copy],system_libyajl=$withval,system_libyajl=no)
++AC_MSG_CHECKING([whether to use system libyajl or not])
++if test x$system_libyajl = xno ; then
++ HAVE_YAJL=false
++ AC_MSG_RESULT(no)
++else
++ AC_MSG_RESULT(yes)
++ AC_CHECK_LIB(yajl, yajl_gen_c_comment, HAVE_YAJL="true", , -lm)
++ if test "$HAVE_YAJL" != "true" ; then
++ AC_MSG_ERROR([system libyajl missing or not compatible with argyllcms])
++ fi
++fi
++if test "$HAVE_YAJL" = "true" ; then
++ YAJL_LIBS="-lyajl"
++else
++ YAJL_LIBS='$(top_srcdir)/jcnf/yajl/libyajl.la'
++ YAJL_CFLAGS='-I$(top_srcdir)/jcnf/yajl'
++ YAJL_SUBDIRS='yajl'
++fi
++AC_SUBST([YAJL_LIBS])
++AC_SUBST([YAJL_CFLAGS])
++AC_SUBST([YAJL_SUBDIRS])
++
++AC_CHECK_LIB(X11, XOpenDisplay, X_LIBS="$X_LIBS -lX11")
++AC_CHECK_LIB(Xext, XextFindDisplay, X_LIBS="$X_LIBS -lXext",,-lX11)
++AC_CHECK_LIB(Xss, XScreenSaverSuspend, X_LIBS="$X_LIBS -lXss",,-lXext -lX11)
++AC_CHECK_LIB(Xrandr, XRRRootToScreen, X_LIBS="$X_LIBS -lXrandr",,-LXext -lX11)
++AC_CHECK_LIB(Xinerama, XineramaQueryScreens, X_LIBS="$X_LIBS -lXinerama",,-LXext -lX11)
++AC_CHECK_LIB(Xxf86vm, XF86VidModeGetGamma, X_LIBS="$X_LIBS -lXxf86vm",,-lXext -lX11)
++AC_SUBST([X_LIBS])
++
++AC_SUBST(OS_LINUX)
++AC_SUBST(OS_BSD)
++case $host in
++ *-linux*)
++ OS_LINUX=1
++ OS_BSD=0
++ AC_DEFINE([OS_LINUX],[1],[Linux kernel])
++ AM_CONDITIONAL([OS_LINUX],[true])
++ ;;
++ *-freebsd*|*-kfreebsd*-gnu|*-openbsd*|*-netbsd*)
++ OS_LINUX=0
++ OS_BSD=1
++ AC_DEFINE([OS_LINUX],[0],[Linux kernel])
++ AM_CONDITIONAL([OS_LINUX],[false])
++ ;;
++ *)
++ OS_LINUX=0
++ OS_BSD=0
++ AC_DEFINE([OS_LINUX],[0],[Linux kernel])
++ AM_CONDITIONAL([OS_LINUX],[false])
++ ;;
++esac
++AC_DEFINE([API_EXPORTED],[],[Default visibility])
++
++AC_C_BIGENDIAN
++if test "$ac_cv_c_bigendian" = "yes"; then
++ BIGENDIAN="1"
++else
++ BIGENDIAN="0"
++fi
++AC_SUBST(BIGENDIAN)
++
++AC_CONFIG_FILES([Makefile
++ h/Makefile
++ doc/Makefile
++ ref/Makefile
++ numlib/Makefile
++ cgats/Makefile
++ plot/Makefile
++ rspl/Makefile
++ icc/Makefile
++ gamut/Makefile
++ xicc/Makefile
++ link/Makefile
++ spectro/Makefile
++ profile/Makefile
++ tweak/Makefile
++ scanin/Makefile
++ render/Makefile
++ target/Makefile
++ imdi/Makefile
++ jcnf/Makefile
++ jcnf/yajl/Makefile
++ ucmm/Makefile])
++
++AC_OUTPUT
+--- /dev/null
++++ b/tweak/Makefile.am
+@@ -0,0 +1,11 @@
++include $(top_srcdir)/Makefile.shared
++
++LDADD = ../spectro/libinsttypes.la ../gamut/libgamut.la \
++ ../gamut/libgammap.la ../plot/libvrml.la ../xicc/libxutils.la \
++ ../xicc/libxicc.la ../rspl/librspl.la ../gamut/libgamut.la \
++ ../gamut/libgammap.la $(ICC_LIBS) ../cgats/libcgats.la \
++ ../numlib/libargyllnum.la $(TIFF_LIBS)
++
++bin_PROGRAMS = refine
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/rspl/Makefile.am
+@@ -0,0 +1,15 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = librspl.la
++privatelibdir = $(pkglibdir)
++
++librspl_la_SOURCES = rspl.h rspl_imp.h mlbs.h rspl.c scat.c rev.c \
++ rev.h gam.c spline.c opt.c
++librspl_la_LIBADD = ../numlib/libargyllnum.la ../plot/libvrml.la
++
++LDADD = ./librspl.la ../numlib/libargyllnum.la ../plot/libplot.la \
++ ../plot/libvrml.la $(X_LIBS) $(TIFF_LIBS) $(ICC_LIBS)
++
++check_PROGRAMS = revbench c1 c1df t2d t2ddf t3d t3ddf tnd trnd
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/plot/Makefile.am
+@@ -0,0 +1,12 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libplot.la libvrml.la
++privatelibdir = $(pkglibdir)
++
++libplot_la_SOURCES = plot.h plot.c
++libplot_la_LIBADD = $(X_LIBS)
++
++libvrml_la_SOURCES = vrml.h vrml.c
++libvrml_la_LIBADD = $(ICC_LIBS) ../numlib/libargyllnum.la
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/doc/Makefile.am
+@@ -0,0 +1,6 @@
++docdir = $(datadir)/doc/argyll
++
++doc_DATA = $(wildcard *.txt) $(wildcard *.html) $(wildcard *.jpg) \
++ $(wildcard *.gif)
++
++EXTRA_DIST = $(doc_DATA)
+--- /dev/null
++++ b/numlib/Makefile.am
+@@ -0,0 +1,15 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libargyllnum.la
++privatelibdir = $(pkglibdir)
++
++libargyllnum_la_SOURCES = numlib.h numsup.c numsup.h dnsq.c dnsq.h \
++ powell.c powell.h dhsx.c dhsx.h ludecomp.c ludecomp.h svd.c \
++ svd.h zbrent.c zbrent.h rand.c rand.h sobol.c sobol.h aatree.c
++
++LDADD = ./libargyllnum.la
++
++check_PROGRAMS = dnsqtest tpowell tdhsx LUtest svdtest zbrenttest \
++ soboltest
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/spectro/Makefile.am
+@@ -0,0 +1,53 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libinsttypes.la libconv.la libinst.la libinstapp.la libdisp.la
++privatelibdir = $(pkglibdir)
++
++libinsttypes_la_SOURCES = insttypes.h insttypes.c insttypeinst.h
++libinsttypes_la_LIBADD = ../libargyll.la
++
++libinst_la_SOURCES = inst.h inst.c insttypes.c dtp20.c dtp20.h dtp22.c \
++ dtp22.h dtp41.c dtp41.h dtp51.c dtp51.h dtp92.c dtp92.h \
++ i1disp.c i1disp.h i1pro.c i1pro.h i1pro_imp.c i1pro_imp.h \
++ munki.c munki_imp.c ss.c ss.h ss_imp.c ss_imp.h hcfr.c hcfr.h \
++ spyd2.c spyd2.h spyd2setup.h spyd2PLD.h huey.c huey.h \
++ usbio.c hidio.c pollem.c pollem.h icoms.h conv.h usbio.h \
++ hidio.h i1d3.h i1d3.c colorhug.c colorhug.h icoms.c \
++ oemarch.h oemarch.c iusb.h vinflate.c inflate.c
++libinst_la_LIBADD = $(ICC_LIBS) ../numlib/libargyllnum.la \
++ ../libargyll.la ../rspl/librspl.la libconv.la
++
++libinst_la_LDFLAGS = $(shell libusb-config --libs)
++
++libdisp_la_SOURCES = dispsup.c dispwin.c dispwin.h dispsup.h webwin.c webwin.h mongoose.c mongoose.h
++libdisp_la_LIBADD = $(X_LIBS) ../ucmm/libucmm.la $(ICC_LIBS) -ldl \
++ ../numlib/libargyllnum.la libconv.la libinst.la libinstapp.la \
++ ../libargyll.la
++
++libconv_la_SOURCES = conv.c pollem.c xdg_bds.h xdg_bds.c aglob.c ../xicc/ccss.c
++libconv_la_LIBADD = ../libargyll.la ../numlib/libargyllnum.la \
++ ../cgats/libcgats.la
++
++libinstapp_la_SOURCES = instappsup.c instappsup.h
++libinstapp_la_LIBADD = libinst.la ../libargyll.la ../numlib/libargyllnum.la \
++ libconv.la
++
++LDADD = ./libinsttypes.la ./libinstapp.la ./libdisp.la ./libinst.la \
++ ./libconv.la ../ucmm/libucmm.la ../jcnf/libjcnf.la $(YAJL_LIBS) \
++ ../xicc/libxicc.la $(ICC_LIBS) ../cgats/libcgats.la \
++ ../rspl/librspl.la ../gamut/libgamut.la ../target/libtarget.la \
++ ../plot/libplot.la ../numlib/libargyllnum.la $(X_LIBS) \
++ ../libargyll.la
++
++bin_PROGRAMS = dispwin synthcal dispread dispcal fakeread synthread \
++ chartread spotread illumread ccxxmake spec2cie average oeminst
++
++dispwin_CFLAGS = $(AM_CFLAGS) -DSTANDALONE_TEST
++
++synthcal_DEPENDENCIES = ../gamut/libgammap.la ../target/libtarget.la
++
++refdir = $(datadir)/color/argyll/ref
++
++ref_DATA = ccxx.ti1 SOtele.sp $(wildcard *.cal)
++
++EXTRA_DIST = Readme.txt
+--- /dev/null
++++ b/ref/Makefile.am
+@@ -0,0 +1,7 @@
++refdir = $(datadir)/color/argyll/ref
++
++ref_DATA = $(wildcard *.cal) $(wildcard *.cht) $(wildcard *.cie) \
++ $(wildcard *.icm) $(wildcard *.sp) $(wildcard *.ti1) \
++ $(wildcard *.ti2)
++
++EXTRA_DIST = $(ref_DATA)
+--- /dev/null
++++ b/link/Makefile.am
+@@ -0,0 +1,11 @@
++include $(top_srcdir)/Makefile.shared
++
++LDADD = ../spectro/libinsttypes.la ../xicc/libxicc.la \
++ ../xicc/libxutils.la ../gamut/libgamut.la \
++ ../gamut/libgammap.la ../plot/libplot.la ../plot/libvrml.la \
++ ../rspl/librspl.la $(ICC_LIBS) ../cgats/libcgats.la \
++ ../numlib/libargyllnum.la ../libargyll.la $(X_LIBS) $(TIFF_LIBS)
++
++bin_PROGRAMS = collink pathplot
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/imdi/Makefile.am
+@@ -0,0 +1,40 @@
++include $(top_srcdir)/Makefile.shared
++
++lib_LTLIBRARIES = libimdi.la
++
++LIBIMDI_VERSION=0.0
++
++libimdi_la_SOURCES = imdi.c imdi_tab.c imdi_arch.h imdi_gen.h imdi.h \
++ imdi_tab.h imdi_utl.h refi.h imdi_k.h
++libimdi_la_LDFLAGS = -version $(shell echo $(LIBIMDI_VERSION) | tr . :):0
++
++include_HEADERS = imdi_arch.h imdi_gen.h imdi.h imdi_tab.h \
++ imdi_utl.h refi.h
++
++bin_PROGRAMS = cctiff greytiff
++
++BINLDADD = ./libimdi.la ../spectro/libinsttypes.la ../plot/libvrml.la \
++ ../xicc/libxicc.la ../xicc/libxutils.la ../gamut/libgamut.la \
++ ../gamut/libgammap.la ../rspl/librspl.la $(ICC_LIBS) \
++ ../cgats/libcgats.la ../numlib/libargyllnum.la ../libargyll.la \
++ $(TIFF_LIBS) -ljpeg
++
++cctiff_LDADD = $(BINLDADD)
++greytiff_LDADD = $(BINLDADD)
++
++check_PROGRAMS = ctest
++
++ctest_SOURCES = ctest.c cgen.c
++
++noinst_PROGRAMS = imdi_make
++
++imdi_make_SOURCES = imdi_make.c imdi_gen.c cgen.c
++##imdi_make_CFLAGS = $(CFLAGS) -O
++
++BUILT_SOURCES = imdi_k.h
++
++imdi.c: imdi_k.h
++imdi_k.h: imdi_make
++ ./imdi_make
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/scanin/Makefile.am
+@@ -0,0 +1,19 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libscanrd.la
++privatelibdir = $(pkglibdir)
++
++libscanrd_la_SOURCES = scanrd.h scanrd_.h scanrd.c
++libscanrd_la_LIBADD = ../rspl/librspl.la ../numlib/libargyllnum.la
++
++LDADD = ./libscanrd.la ../numlib/libargyllnum.la $(ICC_LIBS) \
++ ../cgats/libcgats.la ../xicc/libxicc.la $(TIFF_LIBS) \
++ ../libargyll.la
++
++bin_PROGRAMS = scanin
++
++refdir = $(datadir)/color/argyll/ref
++
++ref_DATA = $(wildcard *.cht) $(wildcard *.cie) $(wildcard *.ti2)
++
++EXTRA_DIST = $(ref_DATA) License.txt Readme.txt
+--- /dev/null
++++ b/cgats/Makefile.am
+@@ -0,0 +1,9 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libcgats.la
++privatelibdir = $(pkglibdir)
++
++libcgats_la_SOURCES = pars.c pars.h cgats.c cgats.h parsstd.c \
++ cgatsstd.c
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/render/Makefile.am
+@@ -0,0 +1,13 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = librender.la
++privatelibdir = $(pkglibdir)
++
++librender_la_SOURCES = render.h render.c thscreen.h thscreen.c
++librender_la_LIBADD = $(TIFF_LIBS) ../numlib/libargyllnum.la
++
++LDADD = ./librender.la ../numlib/libargyllnum.la $(TIFF_LIBS)
++
++check_PROGRAMS = timage
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/jcnf/Makefile.am
+@@ -0,0 +1,15 @@
++include $(top_srcdir)/Makefile.shared
++
++SUBDIRS = $(YAJL_SUBDIRS)
++
++privatelib_LTLIBRARIES = libjcnf.la
++privatelibdir = $(pkglibdir)
++
++libjcnf_la_SOURCES = jcnf.h jcnf.c
++libjcnf_la_LIBADD = $(YAJL_LIBS)
++
++LDADD = ./libjcnf.la $(YAJL_LIBS)
++
++check_PROGRAMS = test
++
++EXTRA_DIST = Readme.txt
+--- /dev/null
++++ b/jcnf/yajl/Makefile.am
+@@ -0,0 +1,13 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libyajl.la
++privatelibdir = $(pkglibdir)
++
++libyajl_la_SOURCES = yajl_common.h yajl_gen.h yajl_parse.h yajl.c \
++ yajl_alloc.c yajl_alloc.h yajl_buf.c yajl_buf.h yajl_encode.c \
++ yajl_encode.h yajl_gen.c yajl_lex.c yajl_lex.h yajl_parser.c \
++ yajl_parser.h
++
++LDADD = ./libyajl.la
++
++check_PROGRAMS = yajl_test json_verify
+--- /dev/null
++++ b/h/Makefile.am
+@@ -0,0 +1,3 @@
++EXTRA_DIST = Readme.txt copyright.h config.h sort.h llist.h xlist.h \
++ counters.h
++
+--- /dev/null
++++ b/icc/Makefile.am
+@@ -0,0 +1,22 @@
++include $(top_srcdir)/Makefile.shared
++
++LIBICC_VERSION=2.12
++
++lib_LTLIBRARIES = libicc.la
++
++libicc_la_SOURCES = icc.h iccV42.h icc.c iccstd.c
++libicc_la_LDFLAGS = -version-number $(shell echo $(LIBICC_VERSION) | tr . :):0
++
++include_HEADERS = icc.h iccV42.h
++
++LDADD = libicc.la
++
++bin_PROGRAMS = iccdump icclu
++
++check_PROGRAMS = icctest iccrw lutest
++
++refdir = $(datadir)/color/argyll/ref
++
++ref_DATA = $(wildcard *.icm)
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/ucmm/Makefile.am
+@@ -0,0 +1,9 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libucmm.la
++privatelibdir = $(pkglibdir)
++
++libucmm_la_SOURCES = ucmm.h ucmm.c
++libucmm_la_LIBADD = $(ICC_LIBS) ../jcnf/libjcnf.la ../spectro/libconv.la
++
++LDADD = libucmm.la
+--- /dev/null
++++ b/xicc/Makefile.am
+@@ -0,0 +1,28 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libxicc.la libxutils.la
++privatelibdir = $(pkglibdir)
++
++libxicc_la_SOURCES = xicc.c xlutfix.c xspect.c xcolorants.c \
++ xutils.c iccjpeg.c xdevlin.c xcam.c cam97s3.c cam02.c mpp.c \
++ ccmx.c ccss.c xfit.c xdgb.c moncurve.c xcal.c
++libxicc_la_LIBADD = $(ICC_LIBS) ../gamut/libgamut.la \
++ ../numlib/libargyllnum.la ../spectro/libinsttypes.la \
++ ../cgats/libcgats.la ../rspl/librspl.la ../libargyll.la -ljpeg $(TIFF_LIBS)
++
++libxutils_la_SOURCES = xutils.h xutils.c iccjpeg.c iccjpeg.h
++libxutils_la_LIBADD = $(TIFF_LIBS) $(ICC_LIBS) -ljpeg
++
++LDADD = ./libxicc.la ./libxutils.la ../rspl/librspl.la \
++ ../numlib/libargyllnum.la ../gamut/libgamut.la \
++ ../gamut/libgammap.la ../spectro/libinsttypes.la $(ICC_LIBS) \
++ ../cgats/libcgats.la ../plot/libvrml.la ../plot/libplot.la \
++ $(TIFF_LIBS) $(X_LIBS) ../libargyll.la -ljpeg
++
++bin_PROGRAMS = fakeCMY iccgamut mpplu revfix tiffgamut xicclu \
++ extracticc extractttag specplot ccttest
++
++fakeCMY_DEPENDENCIES = ../spectro/libinsttypes.la \
++ ../gamut/libgammap.la ../target/libtarget.la
++
++EXTRA_DIST = xmono.c xmatrix.c xlut.c
+--- /dev/null
++++ b/target/Makefile.am
+@@ -0,0 +1,28 @@
++include $(top_srcdir)/Makefile.shared
++
++CPPFLAGS+=-D_FORTIFY_SOURCE=2
++
++privatelib_LTLIBRARIES = libtarget.la
++privatelibdir = $(pkglibdir)
++
++libtarget_la_SOURCES = alphix.c alphix.h randix.c randix.h
++
++LDADD = ./libtarget.la ../rspl/librspl.la ../plot/libvrml.la \
++ $(ICC_LIBS) ../render/librender.la ../cgats/libcgats.la \
++ ../xicc/libxicc.la ../gamut/libgamut.la \
++ ../spectro/libinsttypes.la ../spectro/libconv.la \
++ ../numlib/libargyllnum.la ../libargyll.la $(TIFF_LIBS)
++
++bin_PROGRAMS = targen printtarg
++
++targen_DEPENDENCIES = ../spectro/libinsttypes.la
++targen_SOURCES = targen.c targen.h ofps.c ofps.h ifarp.c ifarp.h \
++ simplat.c simplat.h simdlat.c simdlat.h prand.c prand.h
++
++printtarg_SOURCES = printtarg.c
++
++refdir = $(datadir)/color/argyll/ref
++
++ref_DATA = $(wildcard *.ti2)
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/profile/Makefile.am
+@@ -0,0 +1,27 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libprof.la
++privatelibdir = $(pkglibdir)
++
++libprof_la_SOURCES = prof.h profin.c profout.c
++libprof_la_LIBADD = ../gamut/libgammap.la $(ICC_LIBS) \
++ ../gamut/libgamut.la ../xicc/libxicc.la \
++ ../numlib/libargyllnum.la ../spectro/libinsttypes.la \
++ ../xicc/libxutils.la ../libargyll.la
++
++LDADD = ./libprof.la ../xicc/libxutils.la ../spectro/libinst.la \
++ ../xicc/libxicc.la ../spectro/libinsttypes.la \
++ ../gamut/libgamut.la ../gamut/libgammap.la ../plot/libvrml.la \
++ ../plot/libplot.la ../rspl/librspl.la \
++ ../numlib/libargyllnum.la $(ICC_LIBS) ../cgats/libcgats.la \
++ ../libargyll.la $(TIFF_LIBS) ../spectro/libconv.la
++
++bin_PROGRAMS = simpprof kodak2ti3 cb2ti3 txt2ti3 splitti3 \
++ profcheck invprofcheck mppprof mppcheck verify colprof printcal \
++ applycal
++
++refdir = $(datadir)/color/argyll/ref
++
++ref_DATA = $(wildcard *.sp)
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/gamut/Makefile.am
+@@ -0,0 +1,27 @@
++include $(top_srcdir)/Makefile.shared
++
++privatelib_LTLIBRARIES = libgamut.la libgammap.la
++privatelibdir = $(pkglibdir)
++
++libgamut_la_SOURCES = gamut.h gamut.c
++libgamut_la_LIBADD = ../cgats/libcgats.la $(ICC_LIBS) \
++ ../numlib/libargyllnum.la
++
++libgammap_la_SOURCES = gammap.h gammap.c nearsmth.c nearsmth.h
++libgammap_la_LIBADD = ./libgamut.la $(ICC_LIBS) \
++ ../numlib/libargyllnum.la ../plot/libvrml.la \
++ ../rspl/librspl.la ../libargyll.la ../cgats/libcgats.la
++
++LDADD = ./libgamut.la ./libgammap.la $(ICC_LIBS) ../cgats/libcgats.la \
++ ../rspl/librspl.la ../plot/libvrml.la ../xicc/libxicc.la \
++ ../spectro/libinsttypes.la ../numlib/libargyllnum.la
++
++bin_PROGRAMS = viewgam
++
++check_PROGRAMS = smthtest GenRMGam GenVisGam maptest surftest fakegam
++
++refdir = $(datadir)/color/argyll/ref
++
++##ref_DATA = RefMediumGamut.gam
++
++EXTRA_DIST = License.txt Readme.txt
+--- /dev/null
++++ b/imdi/imdi_k.h
+@@ -0,0 +1,910 @@
++/* Integer Multi-Dimensional Interpolation */
++/* Declarations for all the generated kernel functions */
++/* This file is generated by imdi_make */
++
++/* Copyright 2000 - 2007 Graeme W. Gill */
++/* All rights reserved. */
++/* This material is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- */
++/* see the License.txt file for licensing details.*/
++
++#include "imdi_k.c" /* All the kernel code */
++
++struct {
++ void (*interp)(imdi *s, void **outp, int ostride, void **inp, int istride, unsigned int npix);
++ void (*gentab)(genspec *g, tabspec *t);
++} ktable[891] = {
++ { imdi_k1, imdi_k1_gentab },
++ { imdi_k2, imdi_k2_gentab },
++ { imdi_k3, imdi_k3_gentab },
++ { imdi_k4, imdi_k4_gentab },
++ { imdi_k5, imdi_k5_gentab },
++ { imdi_k6, imdi_k6_gentab },
++ { imdi_k7, imdi_k7_gentab },
++ { imdi_k8, imdi_k8_gentab },
++ { imdi_k9, imdi_k9_gentab },
++ { imdi_k10, imdi_k10_gentab },
++ { imdi_k11, imdi_k11_gentab },
++ { imdi_k12, imdi_k12_gentab },
++ { imdi_k13, imdi_k13_gentab },
++ { imdi_k14, imdi_k14_gentab },
++ { imdi_k15, imdi_k15_gentab },
++ { imdi_k16, imdi_k16_gentab },
++ { imdi_k17, imdi_k17_gentab },
++ { imdi_k18, imdi_k18_gentab },
++ { imdi_k19, imdi_k19_gentab },
++ { imdi_k20, imdi_k20_gentab },
++ { imdi_k21, imdi_k21_gentab },
++ { imdi_k22, imdi_k22_gentab },
++ { imdi_k23, imdi_k23_gentab },
++ { imdi_k24, imdi_k24_gentab },
++ { imdi_k25, imdi_k25_gentab },
++ { imdi_k26, imdi_k26_gentab },
++ { imdi_k27, imdi_k27_gentab },
++ { imdi_k28, imdi_k28_gentab },
++ { imdi_k29, imdi_k29_gentab },
++ { imdi_k30, imdi_k30_gentab },
++ { imdi_k31, imdi_k31_gentab },
++ { imdi_k32, imdi_k32_gentab },
++ { imdi_k33, imdi_k33_gentab },
++ { imdi_k34, imdi_k34_gentab },
++ { imdi_k35, imdi_k35_gentab },
++ { imdi_k36, imdi_k36_gentab },
++ { imdi_k37, imdi_k37_gentab },
++ { imdi_k38, imdi_k38_gentab },
++ { imdi_k39, imdi_k39_gentab },
++ { imdi_k40, imdi_k40_gentab },
++ { imdi_k41, imdi_k41_gentab },
++ { imdi_k42, imdi_k42_gentab },
++ { imdi_k43, imdi_k43_gentab },
++ { imdi_k44, imdi_k44_gentab },
++ { imdi_k45, imdi_k45_gentab },
++ { imdi_k46, imdi_k46_gentab },
++ { imdi_k47, imdi_k47_gentab },
++ { imdi_k48, imdi_k48_gentab },
++ { imdi_k49, imdi_k49_gentab },
++ { imdi_k50, imdi_k50_gentab },
++ { imdi_k51, imdi_k51_gentab },
++ { imdi_k52, imdi_k52_gentab },
++ { imdi_k53, imdi_k53_gentab },
++ { imdi_k54, imdi_k54_gentab },
++ { imdi_k55, imdi_k55_gentab },
++ { imdi_k56, imdi_k56_gentab },
++ { imdi_k57, imdi_k57_gentab },
++ { imdi_k58, imdi_k58_gentab },
++ { imdi_k59, imdi_k59_gentab },
++ { imdi_k60, imdi_k60_gentab },
++ { imdi_k61, imdi_k61_gentab },
++ { imdi_k62, imdi_k62_gentab },
++ { imdi_k63, imdi_k63_gentab },
++ { imdi_k64, imdi_k64_gentab },
++ { imdi_k65, imdi_k65_gentab },
++ { imdi_k66, imdi_k66_gentab },
++ { imdi_k67, imdi_k67_gentab },
++ { imdi_k68, imdi_k68_gentab },
++ { imdi_k69, imdi_k69_gentab },
++ { imdi_k70, imdi_k70_gentab },
++ { imdi_k71, imdi_k71_gentab },
++ { imdi_k72, imdi_k72_gentab },
++ { imdi_k73, imdi_k73_gentab },
++ { imdi_k74, imdi_k74_gentab },
++ { imdi_k75, imdi_k75_gentab },
++ { imdi_k76, imdi_k76_gentab },
++ { imdi_k77, imdi_k77_gentab },
++ { imdi_k78, imdi_k78_gentab },
++ { imdi_k79, imdi_k79_gentab },
++ { imdi_k80, imdi_k80_gentab },
++ { imdi_k81, imdi_k81_gentab },
++ { imdi_k82, imdi_k82_gentab },
++ { imdi_k83, imdi_k83_gentab },
++ { imdi_k84, imdi_k84_gentab },
++ { imdi_k85, imdi_k85_gentab },
++ { imdi_k86, imdi_k86_gentab },
++ { imdi_k87, imdi_k87_gentab },
++ { imdi_k88, imdi_k88_gentab },
++ { imdi_k89, imdi_k89_gentab },
++ { imdi_k90, imdi_k90_gentab },
++ { imdi_k91, imdi_k91_gentab },
++ { imdi_k92, imdi_k92_gentab },
++ { imdi_k93, imdi_k93_gentab },
++ { imdi_k94, imdi_k94_gentab },
++ { imdi_k95, imdi_k95_gentab },
++ { imdi_k96, imdi_k96_gentab },
++ { imdi_k97, imdi_k97_gentab },
++ { imdi_k98, imdi_k98_gentab },
++ { imdi_k99, imdi_k99_gentab },
++ { imdi_k100, imdi_k100_gentab },
++ { imdi_k101, imdi_k101_gentab },
++ { imdi_k102, imdi_k102_gentab },
++ { imdi_k103, imdi_k103_gentab },
++ { imdi_k104, imdi_k104_gentab },
++ { imdi_k105, imdi_k105_gentab },
++ { imdi_k106, imdi_k106_gentab },
++ { imdi_k107, imdi_k107_gentab },
++ { imdi_k108, imdi_k108_gentab },
++ { imdi_k109, imdi_k109_gentab },
++ { imdi_k110, imdi_k110_gentab },
++ { imdi_k111, imdi_k111_gentab },
++ { imdi_k112, imdi_k112_gentab },
++ { imdi_k113, imdi_k113_gentab },
++ { imdi_k114, imdi_k114_gentab },
++ { imdi_k115, imdi_k115_gentab },
++ { imdi_k116, imdi_k116_gentab },
++ { imdi_k117, imdi_k117_gentab },
++ { imdi_k118, imdi_k118_gentab },
++ { imdi_k119, imdi_k119_gentab },
++ { imdi_k120, imdi_k120_gentab },
++ { imdi_k121, imdi_k121_gentab },
++ { imdi_k122, imdi_k122_gentab },
++ { imdi_k123, imdi_k123_gentab },
++ { imdi_k124, imdi_k124_gentab },
++ { imdi_k125, imdi_k125_gentab },
++ { imdi_k126, imdi_k126_gentab },
++ { imdi_k127, imdi_k127_gentab },
++ { imdi_k128, imdi_k128_gentab },
++ { imdi_k129, imdi_k129_gentab },
++ { imdi_k130, imdi_k130_gentab },
++ { imdi_k131, imdi_k131_gentab },
++ { imdi_k132, imdi_k132_gentab },
++ { imdi_k133, imdi_k133_gentab },
++ { imdi_k134, imdi_k134_gentab },
++ { imdi_k135, imdi_k135_gentab },
++ { imdi_k136, imdi_k136_gentab },
++ { imdi_k137, imdi_k137_gentab },
++ { imdi_k138, imdi_k138_gentab },
++ { imdi_k139, imdi_k139_gentab },
++ { imdi_k140, imdi_k140_gentab },
++ { imdi_k141, imdi_k141_gentab },
++ { imdi_k142, imdi_k142_gentab },
++ { imdi_k143, imdi_k143_gentab },
++ { imdi_k144, imdi_k144_gentab },
++ { imdi_k145, imdi_k145_gentab },
++ { imdi_k146, imdi_k146_gentab },
++ { imdi_k147, imdi_k147_gentab },
++ { imdi_k148, imdi_k148_gentab },
++ { imdi_k149, imdi_k149_gentab },
++ { imdi_k150, imdi_k150_gentab },
++ { imdi_k151, imdi_k151_gentab },
++ { imdi_k152, imdi_k152_gentab },
++ { imdi_k153, imdi_k153_gentab },
++ { imdi_k154, imdi_k154_gentab },
++ { imdi_k155, imdi_k155_gentab },
++ { imdi_k156, imdi_k156_gentab },
++ { imdi_k157, imdi_k157_gentab },
++ { imdi_k158, imdi_k158_gentab },
++ { imdi_k159, imdi_k159_gentab },
++ { imdi_k160, imdi_k160_gentab },
++ { imdi_k161, imdi_k161_gentab },
++ { imdi_k162, imdi_k162_gentab },
++ { imdi_k163, imdi_k163_gentab },
++ { imdi_k164, imdi_k164_gentab },
++ { imdi_k165, imdi_k165_gentab },
++ { imdi_k166, imdi_k166_gentab },
++ { imdi_k167, imdi_k167_gentab },
++ { imdi_k168, imdi_k168_gentab },
++ { imdi_k169, imdi_k169_gentab },
++ { imdi_k170, imdi_k170_gentab },
++ { imdi_k171, imdi_k171_gentab },
++ { imdi_k172, imdi_k172_gentab },
++ { imdi_k173, imdi_k173_gentab },
++ { imdi_k174, imdi_k174_gentab },
++ { imdi_k175, imdi_k175_gentab },
++ { imdi_k176, imdi_k176_gentab },
++ { imdi_k177, imdi_k177_gentab },
++ { imdi_k178, imdi_k178_gentab },
++ { imdi_k179, imdi_k179_gentab },
++ { imdi_k180, imdi_k180_gentab },
++ { imdi_k181, imdi_k181_gentab },
++ { imdi_k182, imdi_k182_gentab },
++ { imdi_k183, imdi_k183_gentab },
++ { imdi_k184, imdi_k184_gentab },
++ { imdi_k185, imdi_k185_gentab },
++ { imdi_k186, imdi_k186_gentab },
++ { imdi_k187, imdi_k187_gentab },
++ { imdi_k188, imdi_k188_gentab },
++ { imdi_k189, imdi_k189_gentab },
++ { imdi_k190, imdi_k190_gentab },
++ { imdi_k191, imdi_k191_gentab },
++ { imdi_k192, imdi_k192_gentab },
++ { imdi_k193, imdi_k193_gentab },
++ { imdi_k194, imdi_k194_gentab },
++ { imdi_k195, imdi_k195_gentab },
++ { imdi_k196, imdi_k196_gentab },
++ { imdi_k197, imdi_k197_gentab },
++ { imdi_k198, imdi_k198_gentab },
++ { imdi_k199, imdi_k199_gentab },
++ { imdi_k200, imdi_k200_gentab },
++ { imdi_k201, imdi_k201_gentab },
++ { imdi_k202, imdi_k202_gentab },
++ { imdi_k203, imdi_k203_gentab },
++ { imdi_k204, imdi_k204_gentab },
++ { imdi_k205, imdi_k205_gentab },
++ { imdi_k206, imdi_k206_gentab },
++ { imdi_k207, imdi_k207_gentab },
++ { imdi_k208, imdi_k208_gentab },
++ { imdi_k209, imdi_k209_gentab },
++ { imdi_k210, imdi_k210_gentab },
++ { imdi_k211, imdi_k211_gentab },
++ { imdi_k212, imdi_k212_gentab },
++ { imdi_k213, imdi_k213_gentab },
++ { imdi_k214, imdi_k214_gentab },
++ { imdi_k215, imdi_k215_gentab },
++ { imdi_k216, imdi_k216_gentab },
++ { imdi_k217, imdi_k217_gentab },
++ { imdi_k218, imdi_k218_gentab },
++ { imdi_k219, imdi_k219_gentab },
++ { imdi_k220, imdi_k220_gentab },
++ { imdi_k221, imdi_k221_gentab },
++ { imdi_k222, imdi_k222_gentab },
++ { imdi_k223, imdi_k223_gentab },
++ { imdi_k224, imdi_k224_gentab },
++ { imdi_k225, imdi_k225_gentab },
++ { imdi_k226, imdi_k226_gentab },
++ { imdi_k227, imdi_k227_gentab },
++ { imdi_k228, imdi_k228_gentab },
++ { imdi_k229, imdi_k229_gentab },
++ { imdi_k230, imdi_k230_gentab },
++ { imdi_k231, imdi_k231_gentab },
++ { imdi_k232, imdi_k232_gentab },
++ { imdi_k233, imdi_k233_gentab },
++ { imdi_k234, imdi_k234_gentab },
++ { imdi_k235, imdi_k235_gentab },
++ { imdi_k236, imdi_k236_gentab },
++ { imdi_k237, imdi_k237_gentab },
++ { imdi_k238, imdi_k238_gentab },
++ { imdi_k239, imdi_k239_gentab },
++ { imdi_k240, imdi_k240_gentab },
++ { imdi_k241, imdi_k241_gentab },
++ { imdi_k242, imdi_k242_gentab },
++ { imdi_k243, imdi_k243_gentab },
++ { imdi_k244, imdi_k244_gentab },
++ { imdi_k245, imdi_k245_gentab },
++ { imdi_k246, imdi_k246_gentab },
++ { imdi_k247, imdi_k247_gentab },
++ { imdi_k248, imdi_k248_gentab },
++ { imdi_k249, imdi_k249_gentab },
++ { imdi_k250, imdi_k250_gentab },
++ { imdi_k251, imdi_k251_gentab },
++ { imdi_k252, imdi_k252_gentab },
++ { imdi_k253, imdi_k253_gentab },
++ { imdi_k254, imdi_k254_gentab },
++ { imdi_k255, imdi_k255_gentab },
++ { imdi_k256, imdi_k256_gentab },
++ { imdi_k257, imdi_k257_gentab },
++ { imdi_k258, imdi_k258_gentab },
++ { imdi_k259, imdi_k259_gentab },
++ { imdi_k260, imdi_k260_gentab },
++ { imdi_k261, imdi_k261_gentab },
++ { imdi_k262, imdi_k262_gentab },
++ { imdi_k263, imdi_k263_gentab },
++ { imdi_k264, imdi_k264_gentab },
++ { imdi_k265, imdi_k265_gentab },
++ { imdi_k266, imdi_k266_gentab },
++ { imdi_k267, imdi_k267_gentab },
++ { imdi_k268, imdi_k268_gentab },
++ { imdi_k269, imdi_k269_gentab },
++ { imdi_k270, imdi_k270_gentab },
++ { imdi_k271, imdi_k271_gentab },
++ { imdi_k272, imdi_k272_gentab },
++ { imdi_k273, imdi_k273_gentab },
++ { imdi_k274, imdi_k274_gentab },
++ { imdi_k275, imdi_k275_gentab },
++ { imdi_k276, imdi_k276_gentab },
++ { imdi_k277, imdi_k277_gentab },
++ { imdi_k278, imdi_k278_gentab },
++ { imdi_k279, imdi_k279_gentab },
++ { imdi_k280, imdi_k280_gentab },
++ { imdi_k281, imdi_k281_gentab },
++ { imdi_k282, imdi_k282_gentab },
++ { imdi_k283, imdi_k283_gentab },
++ { imdi_k284, imdi_k284_gentab },
++ { imdi_k285, imdi_k285_gentab },
++ { imdi_k286, imdi_k286_gentab },
++ { imdi_k287, imdi_k287_gentab },
++ { imdi_k288, imdi_k288_gentab },
++ { imdi_k289, imdi_k289_gentab },
++ { imdi_k290, imdi_k290_gentab },
++ { imdi_k291, imdi_k291_gentab },
++ { imdi_k292, imdi_k292_gentab },
++ { imdi_k293, imdi_k293_gentab },
++ { imdi_k294, imdi_k294_gentab },
++ { imdi_k295, imdi_k295_gentab },
++ { imdi_k296, imdi_k296_gentab },
++ { imdi_k297, imdi_k297_gentab },
++ { imdi_k298, imdi_k298_gentab },
++ { imdi_k299, imdi_k299_gentab },
++ { imdi_k300, imdi_k300_gentab },
++ { imdi_k301, imdi_k301_gentab },
++ { imdi_k302, imdi_k302_gentab },
++ { imdi_k303, imdi_k303_gentab },
++ { imdi_k304, imdi_k304_gentab },
++ { imdi_k305, imdi_k305_gentab },
++ { imdi_k306, imdi_k306_gentab },
++ { imdi_k307, imdi_k307_gentab },
++ { imdi_k308, imdi_k308_gentab },
++ { imdi_k309, imdi_k309_gentab },
++ { imdi_k310, imdi_k310_gentab },
++ { imdi_k311, imdi_k311_gentab },
++ { imdi_k312, imdi_k312_gentab },
++ { imdi_k313, imdi_k313_gentab },
++ { imdi_k314, imdi_k314_gentab },
++ { imdi_k315, imdi_k315_gentab },
++ { imdi_k316, imdi_k316_gentab },
++ { imdi_k317, imdi_k317_gentab },
++ { imdi_k318, imdi_k318_gentab },
++ { imdi_k319, imdi_k319_gentab },
++ { imdi_k320, imdi_k320_gentab },
++ { imdi_k321, imdi_k321_gentab },
++ { imdi_k322, imdi_k322_gentab },
++ { imdi_k323, imdi_k323_gentab },
++ { imdi_k324, imdi_k324_gentab },
++ { imdi_k325, imdi_k325_gentab },
++ { imdi_k326, imdi_k326_gentab },
++ { imdi_k327, imdi_k327_gentab },
++ { imdi_k328, imdi_k328_gentab },
++ { imdi_k329, imdi_k329_gentab },
++ { imdi_k330, imdi_k330_gentab },
++ { imdi_k331, imdi_k331_gentab },
++ { imdi_k332, imdi_k332_gentab },
++ { imdi_k333, imdi_k333_gentab },
++ { imdi_k334, imdi_k334_gentab },
++ { imdi_k335, imdi_k335_gentab },
++ { imdi_k336, imdi_k336_gentab },
++ { imdi_k337, imdi_k337_gentab },
++ { imdi_k338, imdi_k338_gentab },
++ { imdi_k339, imdi_k339_gentab },
++ { imdi_k340, imdi_k340_gentab },
++ { imdi_k341, imdi_k341_gentab },
++ { imdi_k342, imdi_k342_gentab },
++ { imdi_k343, imdi_k343_gentab },
++ { imdi_k344, imdi_k344_gentab },
++ { imdi_k345, imdi_k345_gentab },
++ { imdi_k346, imdi_k346_gentab },
++ { imdi_k347, imdi_k347_gentab },
++ { imdi_k348, imdi_k348_gentab },
++ { imdi_k349, imdi_k349_gentab },
++ { imdi_k350, imdi_k350_gentab },
++ { imdi_k351, imdi_k351_gentab },
++ { imdi_k352, imdi_k352_gentab },
++ { imdi_k353, imdi_k353_gentab },
++ { imdi_k354, imdi_k354_gentab },
++ { imdi_k355, imdi_k355_gentab },
++ { imdi_k356, imdi_k356_gentab },
++ { imdi_k357, imdi_k357_gentab },
++ { imdi_k358, imdi_k358_gentab },
++ { imdi_k359, imdi_k359_gentab },
++ { imdi_k360, imdi_k360_gentab },
++ { imdi_k361, imdi_k361_gentab },
++ { imdi_k362, imdi_k362_gentab },
++ { imdi_k363, imdi_k363_gentab },
++ { imdi_k364, imdi_k364_gentab },
++ { imdi_k365, imdi_k365_gentab },
++ { imdi_k366, imdi_k366_gentab },
++ { imdi_k367, imdi_k367_gentab },
++ { imdi_k368, imdi_k368_gentab },
++ { imdi_k369, imdi_k369_gentab },
++ { imdi_k370, imdi_k370_gentab },
++ { imdi_k371, imdi_k371_gentab },
++ { imdi_k372, imdi_k372_gentab },
++ { imdi_k373, imdi_k373_gentab },
++ { imdi_k374, imdi_k374_gentab },
++ { imdi_k375, imdi_k375_gentab },
++ { imdi_k376, imdi_k376_gentab },
++ { imdi_k377, imdi_k377_gentab },
++ { imdi_k378, imdi_k378_gentab },
++ { imdi_k379, imdi_k379_gentab },
++ { imdi_k380, imdi_k380_gentab },
++ { imdi_k381, imdi_k381_gentab },
++ { imdi_k382, imdi_k382_gentab },
++ { imdi_k383, imdi_k383_gentab },
++ { imdi_k384, imdi_k384_gentab },
++ { imdi_k385, imdi_k385_gentab },
++ { imdi_k386, imdi_k386_gentab },
++ { imdi_k387, imdi_k387_gentab },
++ { imdi_k388, imdi_k388_gentab },
++ { imdi_k389, imdi_k389_gentab },
++ { imdi_k390, imdi_k390_gentab },
++ { imdi_k391, imdi_k391_gentab },
++ { imdi_k392, imdi_k392_gentab },
++ { imdi_k393, imdi_k393_gentab },
++ { imdi_k394, imdi_k394_gentab },
++ { imdi_k395, imdi_k395_gentab },
++ { imdi_k396, imdi_k396_gentab },
++ { imdi_k397, imdi_k397_gentab },
++ { imdi_k398, imdi_k398_gentab },
++ { imdi_k399, imdi_k399_gentab },
++ { imdi_k400, imdi_k400_gentab },
++ { imdi_k401, imdi_k401_gentab },
++ { imdi_k402, imdi_k402_gentab },
++ { imdi_k403, imdi_k403_gentab },
++ { imdi_k404, imdi_k404_gentab },
++ { imdi_k405, imdi_k405_gentab },
++ { imdi_k406, imdi_k406_gentab },
++ { imdi_k407, imdi_k407_gentab },
++ { imdi_k408, imdi_k408_gentab },
++ { imdi_k409, imdi_k409_gentab },
++ { imdi_k410, imdi_k410_gentab },
++ { imdi_k411, imdi_k411_gentab },
++ { imdi_k412, imdi_k412_gentab },
++ { imdi_k413, imdi_k413_gentab },
++ { imdi_k414, imdi_k414_gentab },
++ { imdi_k415, imdi_k415_gentab },
++ { imdi_k416, imdi_k416_gentab },
++ { imdi_k417, imdi_k417_gentab },
++ { imdi_k418, imdi_k418_gentab },
++ { imdi_k419, imdi_k419_gentab },
++ { imdi_k420, imdi_k420_gentab },
++ { imdi_k421, imdi_k421_gentab },
++ { imdi_k422, imdi_k422_gentab },
++ { imdi_k423, imdi_k423_gentab },
++ { imdi_k424, imdi_k424_gentab },
++ { imdi_k425, imdi_k425_gentab },
++ { imdi_k426, imdi_k426_gentab },
++ { imdi_k427, imdi_k427_gentab },
++ { imdi_k428, imdi_k428_gentab },
++ { imdi_k429, imdi_k429_gentab },
++ { imdi_k430, imdi_k430_gentab },
++ { imdi_k431, imdi_k431_gentab },
++ { imdi_k432, imdi_k432_gentab },
++ { imdi_k433, imdi_k433_gentab },
++ { imdi_k434, imdi_k434_gentab },
++ { imdi_k435, imdi_k435_gentab },
++ { imdi_k436, imdi_k436_gentab },
++ { imdi_k437, imdi_k437_gentab },
++ { imdi_k438, imdi_k438_gentab },
++ { imdi_k439, imdi_k439_gentab },
++ { imdi_k440, imdi_k440_gentab },
++ { imdi_k441, imdi_k441_gentab },
++ { imdi_k442, imdi_k442_gentab },
++ { imdi_k443, imdi_k443_gentab },
++ { imdi_k444, imdi_k444_gentab },
++ { imdi_k445, imdi_k445_gentab },
++ { imdi_k446, imdi_k446_gentab },
++ { imdi_k447, imdi_k447_gentab },
++ { imdi_k448, imdi_k448_gentab },
++ { imdi_k449, imdi_k449_gentab },
++ { imdi_k450, imdi_k450_gentab },
++ { imdi_k451, imdi_k451_gentab },
++ { imdi_k452, imdi_k452_gentab },
++ { imdi_k453, imdi_k453_gentab },
++ { imdi_k454, imdi_k454_gentab },
++ { imdi_k455, imdi_k455_gentab },
++ { imdi_k456, imdi_k456_gentab },
++ { imdi_k457, imdi_k457_gentab },
++ { imdi_k458, imdi_k458_gentab },
++ { imdi_k459, imdi_k459_gentab },
++ { imdi_k460, imdi_k460_gentab },
++ { imdi_k461, imdi_k461_gentab },
++ { imdi_k462, imdi_k462_gentab },
++ { imdi_k463, imdi_k463_gentab },
++ { imdi_k464, imdi_k464_gentab },
++ { imdi_k465, imdi_k465_gentab },
++ { imdi_k466, imdi_k466_gentab },
++ { imdi_k467, imdi_k467_gentab },
++ { imdi_k468, imdi_k468_gentab },
++ { imdi_k469, imdi_k469_gentab },
++ { imdi_k470, imdi_k470_gentab },
++ { imdi_k471, imdi_k471_gentab },
++ { imdi_k472, imdi_k472_gentab },
++ { imdi_k473, imdi_k473_gentab },
++ { imdi_k474, imdi_k474_gentab },
++ { imdi_k475, imdi_k475_gentab },
++ { imdi_k476, imdi_k476_gentab },
++ { imdi_k477, imdi_k477_gentab },
++ { imdi_k478, imdi_k478_gentab },
++ { imdi_k479, imdi_k479_gentab },
++ { imdi_k480, imdi_k480_gentab },
++ { imdi_k481, imdi_k481_gentab },
++ { imdi_k482, imdi_k482_gentab },
++ { imdi_k483, imdi_k483_gentab },
++ { imdi_k484, imdi_k484_gentab },
++ { imdi_k485, imdi_k485_gentab },
++ { imdi_k486, imdi_k486_gentab },
++ { imdi_k487, imdi_k487_gentab },
++ { imdi_k488, imdi_k488_gentab },
++ { imdi_k489, imdi_k489_gentab },
++ { imdi_k490, imdi_k490_gentab },
++ { imdi_k491, imdi_k491_gentab },
++ { imdi_k492, imdi_k492_gentab },
++ { imdi_k493, imdi_k493_gentab },
++ { imdi_k494, imdi_k494_gentab },
++ { imdi_k495, imdi_k495_gentab },
++ { imdi_k496, imdi_k496_gentab },
++ { imdi_k497, imdi_k497_gentab },
++ { imdi_k498, imdi_k498_gentab },
++ { imdi_k499, imdi_k499_gentab },
++ { imdi_k500, imdi_k500_gentab },
++ { imdi_k501, imdi_k501_gentab },
++ { imdi_k502, imdi_k502_gentab },
++ { imdi_k503, imdi_k503_gentab },
++ { imdi_k504, imdi_k504_gentab },
++ { imdi_k505, imdi_k505_gentab },
++ { imdi_k506, imdi_k506_gentab },
++ { imdi_k507, imdi_k507_gentab },
++ { imdi_k508, imdi_k508_gentab },
++ { imdi_k509, imdi_k509_gentab },
++ { imdi_k510, imdi_k510_gentab },
++ { imdi_k511, imdi_k511_gentab },
++ { imdi_k512, imdi_k512_gentab },
++ { imdi_k513, imdi_k513_gentab },
++ { imdi_k514, imdi_k514_gentab },
++ { imdi_k515, imdi_k515_gentab },
++ { imdi_k516, imdi_k516_gentab },
++ { imdi_k517, imdi_k517_gentab },
++ { imdi_k518, imdi_k518_gentab },
++ { imdi_k519, imdi_k519_gentab },
++ { imdi_k520, imdi_k520_gentab },
++ { imdi_k521, imdi_k521_gentab },
++ { imdi_k522, imdi_k522_gentab },
++ { imdi_k523, imdi_k523_gentab },
++ { imdi_k524, imdi_k524_gentab },
++ { imdi_k525, imdi_k525_gentab },
++ { imdi_k526, imdi_k526_gentab },
++ { imdi_k527, imdi_k527_gentab },
++ { imdi_k528, imdi_k528_gentab },
++ { imdi_k529, imdi_k529_gentab },
++ { imdi_k530, imdi_k530_gentab },
++ { imdi_k531, imdi_k531_gentab },
++ { imdi_k532, imdi_k532_gentab },
++ { imdi_k533, imdi_k533_gentab },
++ { imdi_k534, imdi_k534_gentab },
++ { imdi_k535, imdi_k535_gentab },
++ { imdi_k536, imdi_k536_gentab },
++ { imdi_k537, imdi_k537_gentab },
++ { imdi_k538, imdi_k538_gentab },
++ { imdi_k539, imdi_k539_gentab },
++ { imdi_k540, imdi_k540_gentab },
++ { imdi_k541, imdi_k541_gentab },
++ { imdi_k542, imdi_k542_gentab },
++ { imdi_k543, imdi_k543_gentab },
++ { imdi_k544, imdi_k544_gentab },
++ { imdi_k545, imdi_k545_gentab },
++ { imdi_k546, imdi_k546_gentab },
++ { imdi_k547, imdi_k547_gentab },
++ { imdi_k548, imdi_k548_gentab },
++ { imdi_k549, imdi_k549_gentab },
++ { imdi_k550, imdi_k550_gentab },
++ { imdi_k551, imdi_k551_gentab },
++ { imdi_k552, imdi_k552_gentab },
++ { imdi_k553, imdi_k553_gentab },
++ { imdi_k554, imdi_k554_gentab },
++ { imdi_k555, imdi_k555_gentab },
++ { imdi_k556, imdi_k556_gentab },
++ { imdi_k557, imdi_k557_gentab },
++ { imdi_k558, imdi_k558_gentab },
++ { imdi_k559, imdi_k559_gentab },
++ { imdi_k560, imdi_k560_gentab },
++ { imdi_k561, imdi_k561_gentab },
++ { imdi_k562, imdi_k562_gentab },
++ { imdi_k563, imdi_k563_gentab },
++ { imdi_k564, imdi_k564_gentab },
++ { imdi_k565, imdi_k565_gentab },
++ { imdi_k566, imdi_k566_gentab },
++ { imdi_k567, imdi_k567_gentab },
++ { imdi_k568, imdi_k568_gentab },
++ { imdi_k569, imdi_k569_gentab },
++ { imdi_k570, imdi_k570_gentab },
++ { imdi_k571, imdi_k571_gentab },
++ { imdi_k572, imdi_k572_gentab },
++ { imdi_k573, imdi_k573_gentab },
++ { imdi_k574, imdi_k574_gentab },
++ { imdi_k575, imdi_k575_gentab },
++ { imdi_k576, imdi_k576_gentab },
++ { imdi_k577, imdi_k577_gentab },
++ { imdi_k578, imdi_k578_gentab },
++ { imdi_k579, imdi_k579_gentab },
++ { imdi_k580, imdi_k580_gentab },
++ { imdi_k581, imdi_k581_gentab },
++ { imdi_k582, imdi_k582_gentab },
++ { imdi_k583, imdi_k583_gentab },
++ { imdi_k584, imdi_k584_gentab },
++ { imdi_k585, imdi_k585_gentab },
++ { imdi_k586, imdi_k586_gentab },
++ { imdi_k587, imdi_k587_gentab },
++ { imdi_k588, imdi_k588_gentab },
++ { imdi_k589, imdi_k589_gentab },
++ { imdi_k590, imdi_k590_gentab },
++ { imdi_k591, imdi_k591_gentab },
++ { imdi_k592, imdi_k592_gentab },
++ { imdi_k593, imdi_k593_gentab },
++ { imdi_k594, imdi_k594_gentab },
++ { imdi_k595, imdi_k595_gentab },
++ { imdi_k596, imdi_k596_gentab },
++ { imdi_k597, imdi_k597_gentab },
++ { imdi_k598, imdi_k598_gentab },
++ { imdi_k599, imdi_k599_gentab },
++ { imdi_k600, imdi_k600_gentab },
++ { imdi_k601, imdi_k601_gentab },
++ { imdi_k602, imdi_k602_gentab },
++ { imdi_k603, imdi_k603_gentab },
++ { imdi_k604, imdi_k604_gentab },
++ { imdi_k605, imdi_k605_gentab },
++ { imdi_k606, imdi_k606_gentab },
++ { imdi_k607, imdi_k607_gentab },
++ { imdi_k608, imdi_k608_gentab },
++ { imdi_k609, imdi_k609_gentab },
++ { imdi_k610, imdi_k610_gentab },
++ { imdi_k611, imdi_k611_gentab },
++ { imdi_k612, imdi_k612_gentab },
++ { imdi_k613, imdi_k613_gentab },
++ { imdi_k614, imdi_k614_gentab },
++ { imdi_k615, imdi_k615_gentab },
++ { imdi_k616, imdi_k616_gentab },
++ { imdi_k617, imdi_k617_gentab },
++ { imdi_k618, imdi_k618_gentab },
++ { imdi_k619, imdi_k619_gentab },
++ { imdi_k620, imdi_k620_gentab },
++ { imdi_k621, imdi_k621_gentab },
++ { imdi_k622, imdi_k622_gentab },
++ { imdi_k623, imdi_k623_gentab },
++ { imdi_k624, imdi_k624_gentab },
++ { imdi_k625, imdi_k625_gentab },
++ { imdi_k626, imdi_k626_gentab },
++ { imdi_k627, imdi_k627_gentab },
++ { imdi_k628, imdi_k628_gentab },
++ { imdi_k629, imdi_k629_gentab },
++ { imdi_k630, imdi_k630_gentab },
++ { imdi_k631, imdi_k631_gentab },
++ { imdi_k632, imdi_k632_gentab },
++ { imdi_k633, imdi_k633_gentab },
++ { imdi_k634, imdi_k634_gentab },
++ { imdi_k635, imdi_k635_gentab },
++ { imdi_k636, imdi_k636_gentab },
++ { imdi_k637, imdi_k637_gentab },
++ { imdi_k638, imdi_k638_gentab },
++ { imdi_k639, imdi_k639_gentab },
++ { imdi_k640, imdi_k640_gentab },
++ { imdi_k641, imdi_k641_gentab },
++ { imdi_k642, imdi_k642_gentab },
++ { imdi_k643, imdi_k643_gentab },
++ { imdi_k644, imdi_k644_gentab },
++ { imdi_k645, imdi_k645_gentab },
++ { imdi_k646, imdi_k646_gentab },
++ { imdi_k647, imdi_k647_gentab },
++ { imdi_k648, imdi_k648_gentab },
++ { imdi_k649, imdi_k649_gentab },
++ { imdi_k650, imdi_k650_gentab },
++ { imdi_k651, imdi_k651_gentab },
++ { imdi_k652, imdi_k652_gentab },
++ { imdi_k653, imdi_k653_gentab },
++ { imdi_k654, imdi_k654_gentab },
++ { imdi_k655, imdi_k655_gentab },
++ { imdi_k656, imdi_k656_gentab },
++ { imdi_k657, imdi_k657_gentab },
++ { imdi_k658, imdi_k658_gentab },
++ { imdi_k659, imdi_k659_gentab },
++ { imdi_k660, imdi_k660_gentab },
++ { imdi_k661, imdi_k661_gentab },
++ { imdi_k662, imdi_k662_gentab },
++ { imdi_k663, imdi_k663_gentab },
++ { imdi_k664, imdi_k664_gentab },
++ { imdi_k665, imdi_k665_gentab },
++ { imdi_k666, imdi_k666_gentab },
++ { imdi_k667, imdi_k667_gentab },
++ { imdi_k668, imdi_k668_gentab },
++ { imdi_k669, imdi_k669_gentab },
++ { imdi_k670, imdi_k670_gentab },
++ { imdi_k671, imdi_k671_gentab },
++ { imdi_k672, imdi_k672_gentab },
++ { imdi_k673, imdi_k673_gentab },
++ { imdi_k674, imdi_k674_gentab },
++ { imdi_k675, imdi_k675_gentab },
++ { imdi_k676, imdi_k676_gentab },
++ { imdi_k677, imdi_k677_gentab },
++ { imdi_k678, imdi_k678_gentab },
++ { imdi_k679, imdi_k679_gentab },
++ { imdi_k680, imdi_k680_gentab },
++ { imdi_k681, imdi_k681_gentab },
++ { imdi_k682, imdi_k682_gentab },
++ { imdi_k683, imdi_k683_gentab },
++ { imdi_k684, imdi_k684_gentab },
++ { imdi_k685, imdi_k685_gentab },
++ { imdi_k686, imdi_k686_gentab },
++ { imdi_k687, imdi_k687_gentab },
++ { imdi_k688, imdi_k688_gentab },
++ { imdi_k689, imdi_k689_gentab },
++ { imdi_k690, imdi_k690_gentab },
++ { imdi_k691, imdi_k691_gentab },
++ { imdi_k692, imdi_k692_gentab },
++ { imdi_k693, imdi_k693_gentab },
++ { imdi_k694, imdi_k694_gentab },
++ { imdi_k695, imdi_k695_gentab },
++ { imdi_k696, imdi_k696_gentab },
++ { imdi_k697, imdi_k697_gentab },
++ { imdi_k698, imdi_k698_gentab },
++ { imdi_k699, imdi_k699_gentab },
++ { imdi_k700, imdi_k700_gentab },
++ { imdi_k701, imdi_k701_gentab },
++ { imdi_k702, imdi_k702_gentab },
++ { imdi_k703, imdi_k703_gentab },
++ { imdi_k704, imdi_k704_gentab },
++ { imdi_k705, imdi_k705_gentab },
++ { imdi_k706, imdi_k706_gentab },
++ { imdi_k707, imdi_k707_gentab },
++ { imdi_k708, imdi_k708_gentab },
++ { imdi_k709, imdi_k709_gentab },
++ { imdi_k710, imdi_k710_gentab },
++ { imdi_k711, imdi_k711_gentab },
++ { imdi_k712, imdi_k712_gentab },
++ { imdi_k713, imdi_k713_gentab },
++ { imdi_k714, imdi_k714_gentab },
++ { imdi_k715, imdi_k715_gentab },
++ { imdi_k716, imdi_k716_gentab },
++ { imdi_k717, imdi_k717_gentab },
++ { imdi_k718, imdi_k718_gentab },
++ { imdi_k719, imdi_k719_gentab },
++ { imdi_k720, imdi_k720_gentab },
++ { imdi_k721, imdi_k721_gentab },
++ { imdi_k722, imdi_k722_gentab },
++ { imdi_k723, imdi_k723_gentab },
++ { imdi_k724, imdi_k724_gentab },
++ { imdi_k725, imdi_k725_gentab },
++ { imdi_k726, imdi_k726_gentab },
++ { imdi_k727, imdi_k727_gentab },
++ { imdi_k728, imdi_k728_gentab },
++ { imdi_k729, imdi_k729_gentab },
++ { imdi_k730, imdi_k730_gentab },
++ { imdi_k731, imdi_k731_gentab },
++ { imdi_k732, imdi_k732_gentab },
++ { imdi_k733, imdi_k733_gentab },
++ { imdi_k734, imdi_k734_gentab },
++ { imdi_k735, imdi_k735_gentab },
++ { imdi_k736, imdi_k736_gentab },
++ { imdi_k737, imdi_k737_gentab },
++ { imdi_k738, imdi_k738_gentab },
++ { imdi_k739, imdi_k739_gentab },
++ { imdi_k740, imdi_k740_gentab },
++ { imdi_k741, imdi_k741_gentab },
++ { imdi_k742, imdi_k742_gentab },
++ { imdi_k743, imdi_k743_gentab },
++ { imdi_k744, imdi_k744_gentab },
++ { imdi_k745, imdi_k745_gentab },
++ { imdi_k746, imdi_k746_gentab },
++ { imdi_k747, imdi_k747_gentab },
++ { imdi_k748, imdi_k748_gentab },
++ { imdi_k749, imdi_k749_gentab },
++ { imdi_k750, imdi_k750_gentab },
++ { imdi_k751, imdi_k751_gentab },
++ { imdi_k752, imdi_k752_gentab },
++ { imdi_k753, imdi_k753_gentab },
++ { imdi_k754, imdi_k754_gentab },
++ { imdi_k755, imdi_k755_gentab },
++ { imdi_k756, imdi_k756_gentab },
++ { imdi_k757, imdi_k757_gentab },
++ { imdi_k758, imdi_k758_gentab },
++ { imdi_k759, imdi_k759_gentab },
++ { imdi_k760, imdi_k760_gentab },
++ { imdi_k761, imdi_k761_gentab },
++ { imdi_k762, imdi_k762_gentab },
++ { imdi_k763, imdi_k763_gentab },
++ { imdi_k764, imdi_k764_gentab },
++ { imdi_k765, imdi_k765_gentab },
++ { imdi_k766, imdi_k766_gentab },
++ { imdi_k767, imdi_k767_gentab },
++ { imdi_k768, imdi_k768_gentab },
++ { imdi_k769, imdi_k769_gentab },
++ { imdi_k770, imdi_k770_gentab },
++ { imdi_k771, imdi_k771_gentab },
++ { imdi_k772, imdi_k772_gentab },
++ { imdi_k773, imdi_k773_gentab },
++ { imdi_k774, imdi_k774_gentab },
++ { imdi_k775, imdi_k775_gentab },
++ { imdi_k776, imdi_k776_gentab },
++ { imdi_k777, imdi_k777_gentab },
++ { imdi_k778, imdi_k778_gentab },
++ { imdi_k779, imdi_k779_gentab },
++ { imdi_k780, imdi_k780_gentab },
++ { imdi_k781, imdi_k781_gentab },
++ { imdi_k782, imdi_k782_gentab },
++ { imdi_k783, imdi_k783_gentab },
++ { imdi_k784, imdi_k784_gentab },
++ { imdi_k785, imdi_k785_gentab },
++ { imdi_k786, imdi_k786_gentab },
++ { imdi_k787, imdi_k787_gentab },
++ { imdi_k788, imdi_k788_gentab },
++ { imdi_k789, imdi_k789_gentab },
++ { imdi_k790, imdi_k790_gentab },
++ { imdi_k791, imdi_k791_gentab },
++ { imdi_k792, imdi_k792_gentab },
++ { imdi_k793, imdi_k793_gentab },
++ { imdi_k794, imdi_k794_gentab },
++ { imdi_k795, imdi_k795_gentab },
++ { imdi_k796, imdi_k796_gentab },
++ { imdi_k797, imdi_k797_gentab },
++ { imdi_k798, imdi_k798_gentab },
++ { imdi_k799, imdi_k799_gentab },
++ { imdi_k800, imdi_k800_gentab },
++ { imdi_k801, imdi_k801_gentab },
++ { imdi_k802, imdi_k802_gentab },
++ { imdi_k803, imdi_k803_gentab },
++ { imdi_k804, imdi_k804_gentab },
++ { imdi_k805, imdi_k805_gentab },
++ { imdi_k806, imdi_k806_gentab },
++ { imdi_k807, imdi_k807_gentab },
++ { imdi_k808, imdi_k808_gentab },
++ { imdi_k809, imdi_k809_gentab },
++ { imdi_k810, imdi_k810_gentab },
++ { imdi_k811, imdi_k811_gentab },
++ { imdi_k812, imdi_k812_gentab },
++ { imdi_k813, imdi_k813_gentab },
++ { imdi_k814, imdi_k814_gentab },
++ { imdi_k815, imdi_k815_gentab },
++ { imdi_k816, imdi_k816_gentab },
++ { imdi_k817, imdi_k817_gentab },
++ { imdi_k818, imdi_k818_gentab },
++ { imdi_k819, imdi_k819_gentab },
++ { imdi_k820, imdi_k820_gentab },
++ { imdi_k821, imdi_k821_gentab },
++ { imdi_k822, imdi_k822_gentab },
++ { imdi_k823, imdi_k823_gentab },
++ { imdi_k824, imdi_k824_gentab },
++ { imdi_k825, imdi_k825_gentab },
++ { imdi_k826, imdi_k826_gentab },
++ { imdi_k827, imdi_k827_gentab },
++ { imdi_k828, imdi_k828_gentab },
++ { imdi_k829, imdi_k829_gentab },
++ { imdi_k830, imdi_k830_gentab },
++ { imdi_k831, imdi_k831_gentab },
++ { imdi_k832, imdi_k832_gentab },
++ { imdi_k833, imdi_k833_gentab },
++ { imdi_k834, imdi_k834_gentab },
++ { imdi_k835, imdi_k835_gentab },
++ { imdi_k836, imdi_k836_gentab },
++ { imdi_k837, imdi_k837_gentab },
++ { imdi_k838, imdi_k838_gentab },
++ { imdi_k839, imdi_k839_gentab },
++ { imdi_k840, imdi_k840_gentab },
++ { imdi_k841, imdi_k841_gentab },
++ { imdi_k842, imdi_k842_gentab },
++ { imdi_k843, imdi_k843_gentab },
++ { imdi_k844, imdi_k844_gentab },
++ { imdi_k845, imdi_k845_gentab },
++ { imdi_k846, imdi_k846_gentab },
++ { imdi_k847, imdi_k847_gentab },
++ { imdi_k848, imdi_k848_gentab },
++ { imdi_k849, imdi_k849_gentab },
++ { imdi_k850, imdi_k850_gentab },
++ { imdi_k851, imdi_k851_gentab },
++ { imdi_k852, imdi_k852_gentab },
++ { imdi_k853, imdi_k853_gentab },
++ { imdi_k854, imdi_k854_gentab },
++ { imdi_k855, imdi_k855_gentab },
++ { imdi_k856, imdi_k856_gentab },
++ { imdi_k857, imdi_k857_gentab },
++ { imdi_k858, imdi_k858_gentab },
++ { imdi_k859, imdi_k859_gentab },
++ { imdi_k860, imdi_k860_gentab },
++ { imdi_k861, imdi_k861_gentab },
++ { imdi_k862, imdi_k862_gentab },
++ { imdi_k863, imdi_k863_gentab },
++ { imdi_k864, imdi_k864_gentab },
++ { imdi_k865, imdi_k865_gentab },
++ { imdi_k866, imdi_k866_gentab },
++ { imdi_k867, imdi_k867_gentab },
++ { imdi_k868, imdi_k868_gentab },
++ { imdi_k869, imdi_k869_gentab },
++ { imdi_k870, imdi_k870_gentab },
++ { imdi_k871, imdi_k871_gentab },
++ { imdi_k872, imdi_k872_gentab },
++ { imdi_k873, imdi_k873_gentab },
++ { imdi_k874, imdi_k874_gentab },
++ { imdi_k875, imdi_k875_gentab },
++ { imdi_k876, imdi_k876_gentab },
++ { imdi_k877, imdi_k877_gentab },
++ { imdi_k878, imdi_k878_gentab },
++ { imdi_k879, imdi_k879_gentab },
++ { imdi_k880, imdi_k880_gentab },
++ { imdi_k881, imdi_k881_gentab },
++ { imdi_k882, imdi_k882_gentab },
++ { imdi_k883, imdi_k883_gentab },
++ { imdi_k884, imdi_k884_gentab },
++ { imdi_k885, imdi_k885_gentab },
++ { imdi_k886, imdi_k886_gentab },
++ { imdi_k887, imdi_k887_gentab },
++ { imdi_k888, imdi_k888_gentab },
++ { imdi_k889, imdi_k889_gentab },
++ { imdi_k890, imdi_k890_gentab },
++ { imdi_k891, imdi_k891_gentab }
++};
++
++int no_kfuncs = 891;
++
+--- /dev/null
++++ b/configure
+@@ -0,0 +1,15216 @@
++#! /bin/sh
++# Guess values for system-dependent variables and create Makefiles.
++# Generated by GNU Autoconf 2.69 for argyll 1.3.7.
++#
++#
++# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
++#
++#
++# This configure script is free software; the Free Software Foundation
++# gives unlimited permission to copy, distribute and modify it.
++## -------------------- ##
++## M4sh Initialization. ##
++## -------------------- ##
++
++# Be more Bourne compatible
++DUALCASE=1; export DUALCASE # for MKS sh
++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
++ emulate sh
++ NULLCMD=:
++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
++ # is contrary to our usage. Disable this feature.
++ alias -g '${1+"$@"}'='"$@"'
++ setopt NO_GLOB_SUBST
++else
++ case `(set -o) 2>/dev/null` in #(
++ *posix*) :
++ set -o posix ;; #(
++ *) :
++ ;;
++esac
++fi
++
++
++as_nl='
++'
++export as_nl
++# Printing a long string crashes Solaris 7 /usr/bin/printf.
++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
++# Prefer a ksh shell builtin over an external printf program on Solaris,
++# but without wasting forks for bash or zsh.
++if test -z "$BASH_VERSION$ZSH_VERSION" \
++ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='print -r --'
++ as_echo_n='print -rn --'
++elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='printf %s\n'
++ as_echo_n='printf %s'
++else
++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
++ as_echo_n='/usr/ucb/echo -n'
++ else
++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
++ as_echo_n_body='eval
++ arg=$1;
++ case $arg in #(
++ *"$as_nl"*)
++ expr "X$arg" : "X\\(.*\\)$as_nl";
++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
++ esac;
++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
++ '
++ export as_echo_n_body
++ as_echo_n='sh -c $as_echo_n_body as_echo'
++ fi
++ export as_echo_body
++ as_echo='sh -c $as_echo_body as_echo'
++fi
++
++# The user is always right.
++if test "${PATH_SEPARATOR+set}" != set; then
++ PATH_SEPARATOR=:
++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
++ PATH_SEPARATOR=';'
++ }
++fi
++
++
++# IFS
++# We need space, tab and new line, in precisely that order. Quoting is
++# there to prevent editors from complaining about space-tab.
++# (If _AS_PATH_WALK were called with IFS unset, it would disable word
++# splitting by setting IFS to empty value.)
++IFS=" "" $as_nl"
++
++# Find who we are. Look in the path if we contain no directory separator.
++as_myself=
++case $0 in #((
++ *[\\/]* ) as_myself=$0 ;;
++ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
++ done
++IFS=$as_save_IFS
++
++ ;;
++esac
++# We did not find ourselves, most probably we were run as `sh COMMAND'
++# in which case we are not to be found in the path.
++if test "x$as_myself" = x; then
++ as_myself=$0
++fi
++if test ! -f "$as_myself"; then
++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
++ exit 1
++fi
++
++# Unset variables that we do not need and which cause bugs (e.g. in
++# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
++# suppresses any "Segmentation fault" message there. '((' could
++# trigger a bug in pdksh 5.2.14.
++for as_var in BASH_ENV ENV MAIL MAILPATH
++do eval test x\${$as_var+set} = xset \
++ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
++done
++PS1='$ '
++PS2='> '
++PS4='+ '
++
++# NLS nuisances.
++LC_ALL=C
++export LC_ALL
++LANGUAGE=C
++export LANGUAGE
++
++# CDPATH.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
++
++# Use a proper internal environment variable to ensure we don't fall
++ # into an infinite loop, continuously re-executing ourselves.
++ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
++ _as_can_reexec=no; export _as_can_reexec;
++ # We cannot yet assume a decent shell, so we have to provide a
++# neutralization value for shells without unset; and this also
++# works around shells that cannot unset nonexistent variables.
++# Preserve -v and -x to the replacement shell.
++BASH_ENV=/dev/null
++ENV=/dev/null
++(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
++case $- in # ((((
++ *v*x* | *x*v* ) as_opts=-vx ;;
++ *v* ) as_opts=-v ;;
++ *x* ) as_opts=-x ;;
++ * ) as_opts= ;;
++esac
++exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
++# Admittedly, this is quite paranoid, since all the known shells bail
++# out after a failed `exec'.
++$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
++as_fn_exit 255
++ fi
++ # We don't want this to propagate to other subprocesses.
++ { _as_can_reexec=; unset _as_can_reexec;}
++if test "x$CONFIG_SHELL" = x; then
++ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
++ emulate sh
++ NULLCMD=:
++ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
++ # is contrary to our usage. Disable this feature.
++ alias -g '\${1+\"\$@\"}'='\"\$@\"'
++ setopt NO_GLOB_SUBST
++else
++ case \`(set -o) 2>/dev/null\` in #(
++ *posix*) :
++ set -o posix ;; #(
++ *) :
++ ;;
++esac
++fi
++"
++ as_required="as_fn_return () { (exit \$1); }
++as_fn_success () { as_fn_return 0; }
++as_fn_failure () { as_fn_return 1; }
++as_fn_ret_success () { return 0; }
++as_fn_ret_failure () { return 1; }
++
++exitcode=0
++as_fn_success || { exitcode=1; echo as_fn_success failed.; }
++as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
++as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
++as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
++if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
++
++else
++ exitcode=1; echo positional parameters were not saved.
++fi
++test x\$exitcode = x0 || exit 1
++test -x / || exit 1"
++ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
++ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
++ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
++ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
++
++ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
++ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
++ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
++ PATH=/empty FPATH=/empty; export PATH FPATH
++ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
++ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
++test \$(( 1 + 1 )) = 2 || exit 1"
++ if (eval "$as_required") 2>/dev/null; then :
++ as_have_required=yes
++else
++ as_have_required=no
++fi
++ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
++
++else
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++as_found=false
++for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ as_found=:
++ case $as_dir in #(
++ /*)
++ for as_base in sh bash ksh sh5; do
++ # Try only shells that exist, to save several forks.
++ as_shell=$as_dir/$as_base
++ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
++ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
++ CONFIG_SHELL=$as_shell as_have_required=yes
++ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
++ break 2
++fi
++fi
++ done;;
++ esac
++ as_found=false
++done
++$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
++ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
++ CONFIG_SHELL=$SHELL as_have_required=yes
++fi; }
++IFS=$as_save_IFS
++
++
++ if test "x$CONFIG_SHELL" != x; then :
++ export CONFIG_SHELL
++ # We cannot yet assume a decent shell, so we have to provide a
++# neutralization value for shells without unset; and this also
++# works around shells that cannot unset nonexistent variables.
++# Preserve -v and -x to the replacement shell.
++BASH_ENV=/dev/null
++ENV=/dev/null
++(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
++case $- in # ((((
++ *v*x* | *x*v* ) as_opts=-vx ;;
++ *v* ) as_opts=-v ;;
++ *x* ) as_opts=-x ;;
++ * ) as_opts= ;;
++esac
++exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
++# Admittedly, this is quite paranoid, since all the known shells bail
++# out after a failed `exec'.
++$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
++exit 255
++fi
++
++ if test x$as_have_required = xno; then :
++ $as_echo "$0: This script requires a shell more modern than all"
++ $as_echo "$0: the shells that I found on your system."
++ if test x${ZSH_VERSION+set} = xset ; then
++ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
++ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
++ else
++ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
++$0: including any error possibly output before this
++$0: message. Then install a modern shell, or manually run
++$0: the script under such a shell if you do have one."
++ fi
++ exit 1
++fi
++fi
++fi
++SHELL=${CONFIG_SHELL-/bin/sh}
++export SHELL
++# Unset more variables known to interfere with behavior of common tools.
++CLICOLOR_FORCE= GREP_OPTIONS=
++unset CLICOLOR_FORCE GREP_OPTIONS
++
++## --------------------- ##
++## M4sh Shell Functions. ##
++## --------------------- ##
++# as_fn_unset VAR
++# ---------------
++# Portably unset VAR.
++as_fn_unset ()
++{
++ { eval $1=; unset $1;}
++}
++as_unset=as_fn_unset
++
++# as_fn_set_status STATUS
++# -----------------------
++# Set $? to STATUS, without forking.
++as_fn_set_status ()
++{
++ return $1
++} # as_fn_set_status
++
++# as_fn_exit STATUS
++# -----------------
++# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
++as_fn_exit ()
++{
++ set +e
++ as_fn_set_status $1
++ exit $1
++} # as_fn_exit
++
++# as_fn_mkdir_p
++# -------------
++# Create "$as_dir" as a directory, including parents if necessary.
++as_fn_mkdir_p ()
++{
++
++ case $as_dir in #(
++ -*) as_dir=./$as_dir;;
++ esac
++ test -d "$as_dir" || eval $as_mkdir_p || {
++ as_dirs=
++ while :; do
++ case $as_dir in #(
++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
++ *) as_qdir=$as_dir;;
++ esac
++ as_dirs="'$as_qdir' $as_dirs"
++ as_dir=`$as_dirname -- "$as_dir" ||
++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$as_dir" : 'X\(//\)[^/]' \| \
++ X"$as_dir" : 'X\(//\)$' \| \
++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$as_dir" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ test -d "$as_dir" && break
++ done
++ test -z "$as_dirs" || eval "mkdir $as_dirs"
++ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
++
++
++} # as_fn_mkdir_p
++
++# as_fn_executable_p FILE
++# -----------------------
++# Test if FILE is an executable regular file.
++as_fn_executable_p ()
++{
++ test -f "$1" && test -x "$1"
++} # as_fn_executable_p
++# as_fn_append VAR VALUE
++# ----------------------
++# Append the text in VALUE to the end of the definition contained in VAR. Take
++# advantage of any shell optimizations that allow amortized linear growth over
++# repeated appends, instead of the typical quadratic growth present in naive
++# implementations.
++if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
++ eval 'as_fn_append ()
++ {
++ eval $1+=\$2
++ }'
++else
++ as_fn_append ()
++ {
++ eval $1=\$$1\$2
++ }
++fi # as_fn_append
++
++# as_fn_arith ARG...
++# ------------------
++# Perform arithmetic evaluation on the ARGs, and store the result in the
++# global $as_val. Take advantage of shells that can avoid forks. The arguments
++# must be portable across $(()) and expr.
++if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
++ eval 'as_fn_arith ()
++ {
++ as_val=$(( $* ))
++ }'
++else
++ as_fn_arith ()
++ {
++ as_val=`expr "$@" || test $? -eq 1`
++ }
++fi # as_fn_arith
++
++
++# as_fn_error STATUS ERROR [LINENO LOG_FD]
++# ----------------------------------------
++# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
++# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
++# script with STATUS, using 1 if that was 0.
++as_fn_error ()
++{
++ as_status=$1; test $as_status -eq 0 && as_status=1
++ if test "$4"; then
++ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
++ fi
++ $as_echo "$as_me: error: $2" >&2
++ as_fn_exit $as_status
++} # as_fn_error
++
++if expr a : '\(a\)' >/dev/null 2>&1 &&
++ test "X`expr 00001 : '.*\(...\)'`" = X001; then
++ as_expr=expr
++else
++ as_expr=false
++fi
++
++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
++ as_basename=basename
++else
++ as_basename=false
++fi
++
++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
++ as_dirname=dirname
++else
++ as_dirname=false
++fi
++
++as_me=`$as_basename -- "$0" ||
++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
++ X"$0" : 'X\(//\)$' \| \
++ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X/"$0" |
++ sed '/^.*\/\([^/][^/]*\)\/*$/{
++ s//\1/
++ q
++ }
++ /^X\/\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\/\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++
++# Avoid depending upon Character Ranges.
++as_cr_letters='abcdefghijklmnopqrstuvwxyz'
++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
++as_cr_Letters=$as_cr_letters$as_cr_LETTERS
++as_cr_digits='0123456789'
++as_cr_alnum=$as_cr_Letters$as_cr_digits
++
++
++ as_lineno_1=$LINENO as_lineno_1a=$LINENO
++ as_lineno_2=$LINENO as_lineno_2a=$LINENO
++ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
++ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
++ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
++ sed -n '
++ p
++ /[$]LINENO/=
++ ' <$as_myself |
++ sed '
++ s/[$]LINENO.*/&-/
++ t lineno
++ b
++ :lineno
++ N
++ :loop
++ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
++ t loop
++ s/-\n.*//
++ ' >$as_me.lineno &&
++ chmod +x "$as_me.lineno" ||
++ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
++
++ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
++ # already done that, so ensure we don't try to do so again and fall
++ # in an infinite loop. This has already happened in practice.
++ _as_can_reexec=no; export _as_can_reexec
++ # Don't try to exec as it changes $[0], causing all sort of problems
++ # (the dirname of $[0] is not the place where we might find the
++ # original and so on. Autoconf is especially sensitive to this).
++ . "./$as_me.lineno"
++ # Exit status is that of the last command.
++ exit
++}
++
++ECHO_C= ECHO_N= ECHO_T=
++case `echo -n x` in #(((((
++-n*)
++ case `echo 'xy\c'` in
++ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
++ xy) ECHO_C='\c';;
++ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
++ ECHO_T=' ';;
++ esac;;
++*)
++ ECHO_N='-n';;
++esac
++
++rm -f conf$$ conf$$.exe conf$$.file
++if test -d conf$$.dir; then
++ rm -f conf$$.dir/conf$$.file
++else
++ rm -f conf$$.dir
++ mkdir conf$$.dir 2>/dev/null
++fi
++if (echo >conf$$.file) 2>/dev/null; then
++ if ln -s conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s='ln -s'
++ # ... but there are two gotchas:
++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
++ # In both cases, we have to default to `cp -pR'.
++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
++ as_ln_s='cp -pR'
++ elif ln conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s=ln
++ else
++ as_ln_s='cp -pR'
++ fi
++else
++ as_ln_s='cp -pR'
++fi
++rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
++rmdir conf$$.dir 2>/dev/null
++
++if mkdir -p . 2>/dev/null; then
++ as_mkdir_p='mkdir -p "$as_dir"'
++else
++ test -d ./-p && rmdir ./-p
++ as_mkdir_p=false
++fi
++
++as_test_x='test -x'
++as_executable_p=as_fn_executable_p
++
++# Sed expression to map a string onto a valid CPP name.
++as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
++
++# Sed expression to map a string onto a valid variable name.
++as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
++
++SHELL=${CONFIG_SHELL-/bin/sh}
++
++
++test -n "$DJDIR" || exec 7<&0 </dev/null
++exec 6>&1
++
++# Name of the host.
++# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
++# so uname gets run too.
++ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
++
++#
++# Initializations.
++#
++ac_default_prefix=/usr/local
++ac_clean_files=
++ac_config_libobj_dir=.
++LIBOBJS=
++cross_compiling=no
++subdirs=
++MFLAGS=
++MAKEFLAGS=
++
++# Identity of this package.
++PACKAGE_NAME='argyll'
++PACKAGE_TARNAME='argyll'
++PACKAGE_VERSION='1.3.7'
++PACKAGE_STRING='argyll 1.3.7'
++PACKAGE_BUGREPORT=''
++PACKAGE_URL=''
++
++# Factoring default headers for most tests.
++ac_includes_default="\
++#include <stdio.h>
++#ifdef HAVE_SYS_TYPES_H
++# include <sys/types.h>
++#endif
++#ifdef HAVE_SYS_STAT_H
++# include <sys/stat.h>
++#endif
++#ifdef STDC_HEADERS
++# include <stdlib.h>
++# include <stddef.h>
++#else
++# ifdef HAVE_STDLIB_H
++# include <stdlib.h>
++# endif
++#endif
++#ifdef HAVE_STRING_H
++# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
++# include <memory.h>
++# endif
++# include <string.h>
++#endif
++#ifdef HAVE_STRINGS_H
++# include <strings.h>
++#endif
++#ifdef HAVE_INTTYPES_H
++# include <inttypes.h>
++#endif
++#ifdef HAVE_STDINT_H
++# include <stdint.h>
++#endif
++#ifdef HAVE_UNISTD_H
++# include <unistd.h>
++#endif"
++
++ac_subst_vars='am__EXEEXT_FALSE
++am__EXEEXT_TRUE
++LTLIBOBJS
++LIBOBJS
++BIGENDIAN
++OS_LINUX_FALSE
++OS_LINUX_TRUE
++OS_BSD
++OS_LINUX
++YAJL_SUBDIRS
++YAJL_CFLAGS
++YAJL_LIBS
++ICC_SUBDIRS
++ICC_CFLAGS
++ICC_LIBS
++TIFF_LIBS
++X_EXTRA_LIBS
++X_LIBS
++X_PRE_LIBS
++X_CFLAGS
++XMKMF
++CPP
++OTOOL64
++OTOOL
++LIPO
++NMEDIT
++DSYMUTIL
++MANIFEST_TOOL
++RANLIB
++ac_ct_AR
++AR
++DLLTOOL
++OBJDUMP
++LN_S
++NM
++ac_ct_DUMPBIN
++DUMPBIN
++LD
++FGREP
++EGREP
++GREP
++SED
++host_os
++host_vendor
++host_cpu
++host
++build_os
++build_vendor
++build_cpu
++build
++LIBTOOL
++am__fastdepCC_FALSE
++am__fastdepCC_TRUE
++CCDEPMODE
++am__nodep
++AMDEPBACKSLASH
++AMDEP_FALSE
++AMDEP_TRUE
++am__quote
++am__include
++DEPDIR
++OBJEXT
++EXEEXT
++ac_ct_CC
++CPPFLAGS
++LDFLAGS
++CFLAGS
++CC
++AM_BACKSLASH
++AM_DEFAULT_VERBOSITY
++AM_DEFAULT_V
++AM_V
++am__untar
++am__tar
++AMTAR
++am__leading_dot
++SET_MAKE
++AWK
++mkdir_p
++MKDIR_P
++INSTALL_STRIP_PROGRAM
++STRIP
++install_sh
++MAKEINFO
++AUTOHEADER
++AUTOMAKE
++AUTOCONF
++ACLOCAL
++VERSION
++PACKAGE
++CYGPATH_W
++am__isrc
++INSTALL_DATA
++INSTALL_SCRIPT
++INSTALL_PROGRAM
++target_alias
++host_alias
++build_alias
++LIBS
++ECHO_T
++ECHO_N
++ECHO_C
++DEFS
++mandir
++localedir
++libdir
++psdir
++pdfdir
++dvidir
++htmldir
++infodir
++docdir
++oldincludedir
++includedir
++localstatedir
++sharedstatedir
++sysconfdir
++datadir
++datarootdir
++libexecdir
++sbindir
++bindir
++program_transform_name
++prefix
++exec_prefix
++PACKAGE_URL
++PACKAGE_BUGREPORT
++PACKAGE_STRING
++PACKAGE_VERSION
++PACKAGE_TARNAME
++PACKAGE_NAME
++PATH_SEPARATOR
++SHELL'
++ac_subst_files=''
++ac_user_opts='
++enable_option_checking
++enable_silent_rules
++enable_dependency_tracking
++enable_shared
++enable_static
++with_pic
++enable_fast_install
++with_gnu_ld
++with_sysroot
++enable_libtool_lock
++with_x
++with_system_libicc
++with_system_libyajl
++'
++ ac_precious_vars='build_alias
++host_alias
++target_alias
++CC
++CFLAGS
++LDFLAGS
++LIBS
++CPPFLAGS
++CPP
++XMKMF'
++
++
++# Initialize some variables set by options.
++ac_init_help=
++ac_init_version=false
++ac_unrecognized_opts=
++ac_unrecognized_sep=
++# The variables have the same names as the options, with
++# dashes changed to underlines.
++cache_file=/dev/null
++exec_prefix=NONE
++no_create=
++no_recursion=
++prefix=NONE
++program_prefix=NONE
++program_suffix=NONE
++program_transform_name=s,x,x,
++silent=
++site=
++srcdir=
++verbose=
++x_includes=NONE
++x_libraries=NONE
++
++# Installation directory options.
++# These are left unexpanded so users can "make install exec_prefix=/foo"
++# and all the variables that are supposed to be based on exec_prefix
++# by default will actually change.
++# Use braces instead of parens because sh, perl, etc. also accept them.
++# (The list follows the same order as the GNU Coding Standards.)
++bindir='${exec_prefix}/bin'
++sbindir='${exec_prefix}/sbin'
++libexecdir='${exec_prefix}/libexec'
++datarootdir='${prefix}/share'
++datadir='${datarootdir}'
++sysconfdir='${prefix}/etc'
++sharedstatedir='${prefix}/com'
++localstatedir='${prefix}/var'
++includedir='${prefix}/include'
++oldincludedir='/usr/include'
++docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
++infodir='${datarootdir}/info'
++htmldir='${docdir}'
++dvidir='${docdir}'
++pdfdir='${docdir}'
++psdir='${docdir}'
++libdir='${exec_prefix}/lib'
++localedir='${datarootdir}/locale'
++mandir='${datarootdir}/man'
++
++ac_prev=
++ac_dashdash=
++for ac_option
++do
++ # If the previous option needs an argument, assign it.
++ if test -n "$ac_prev"; then
++ eval $ac_prev=\$ac_option
++ ac_prev=
++ continue
++ fi
++
++ case $ac_option in
++ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
++ *=) ac_optarg= ;;
++ *) ac_optarg=yes ;;
++ esac
++
++ # Accept the important Cygnus configure options, so we can diagnose typos.
++
++ case $ac_dashdash$ac_option in
++ --)
++ ac_dashdash=yes ;;
++
++ -bindir | --bindir | --bindi | --bind | --bin | --bi)
++ ac_prev=bindir ;;
++ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
++ bindir=$ac_optarg ;;
++
++ -build | --build | --buil | --bui | --bu)
++ ac_prev=build_alias ;;
++ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
++ build_alias=$ac_optarg ;;
++
++ -cache-file | --cache-file | --cache-fil | --cache-fi \
++ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
++ ac_prev=cache_file ;;
++ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
++ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
++ cache_file=$ac_optarg ;;
++
++ --config-cache | -C)
++ cache_file=config.cache ;;
++
++ -datadir | --datadir | --datadi | --datad)
++ ac_prev=datadir ;;
++ -datadir=* | --datadir=* | --datadi=* | --datad=*)
++ datadir=$ac_optarg ;;
++
++ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
++ | --dataroo | --dataro | --datar)
++ ac_prev=datarootdir ;;
++ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
++ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
++ datarootdir=$ac_optarg ;;
++
++ -disable-* | --disable-*)
++ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
++ # Reject names that are not valid shell variable names.
++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
++ as_fn_error $? "invalid feature name: $ac_useropt"
++ ac_useropt_orig=$ac_useropt
++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
++ case $ac_user_opts in
++ *"
++"enable_$ac_useropt"
++"*) ;;
++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
++ ac_unrecognized_sep=', ';;
++ esac
++ eval enable_$ac_useropt=no ;;
++
++ -docdir | --docdir | --docdi | --doc | --do)
++ ac_prev=docdir ;;
++ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
++ docdir=$ac_optarg ;;
++
++ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
++ ac_prev=dvidir ;;
++ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
++ dvidir=$ac_optarg ;;
++
++ -enable-* | --enable-*)
++ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
++ # Reject names that are not valid shell variable names.
++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
++ as_fn_error $? "invalid feature name: $ac_useropt"
++ ac_useropt_orig=$ac_useropt
++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
++ case $ac_user_opts in
++ *"
++"enable_$ac_useropt"
++"*) ;;
++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
++ ac_unrecognized_sep=', ';;
++ esac
++ eval enable_$ac_useropt=\$ac_optarg ;;
++
++ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
++ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
++ | --exec | --exe | --ex)
++ ac_prev=exec_prefix ;;
++ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
++ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
++ | --exec=* | --exe=* | --ex=*)
++ exec_prefix=$ac_optarg ;;
++
++ -gas | --gas | --ga | --g)
++ # Obsolete; use --with-gas.
++ with_gas=yes ;;
++
++ -help | --help | --hel | --he | -h)
++ ac_init_help=long ;;
++ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
++ ac_init_help=recursive ;;
++ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
++ ac_init_help=short ;;
++
++ -host | --host | --hos | --ho)
++ ac_prev=host_alias ;;
++ -host=* | --host=* | --hos=* | --ho=*)
++ host_alias=$ac_optarg ;;
++
++ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
++ ac_prev=htmldir ;;
++ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
++ | --ht=*)
++ htmldir=$ac_optarg ;;
++
++ -includedir | --includedir | --includedi | --included | --include \
++ | --includ | --inclu | --incl | --inc)
++ ac_prev=includedir ;;
++ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
++ | --includ=* | --inclu=* | --incl=* | --inc=*)
++ includedir=$ac_optarg ;;
++
++ -infodir | --infodir | --infodi | --infod | --info | --inf)
++ ac_prev=infodir ;;
++ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
++ infodir=$ac_optarg ;;
++
++ -libdir | --libdir | --libdi | --libd)
++ ac_prev=libdir ;;
++ -libdir=* | --libdir=* | --libdi=* | --libd=*)
++ libdir=$ac_optarg ;;
++
++ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
++ | --libexe | --libex | --libe)
++ ac_prev=libexecdir ;;
++ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
++ | --libexe=* | --libex=* | --libe=*)
++ libexecdir=$ac_optarg ;;
++
++ -localedir | --localedir | --localedi | --localed | --locale)
++ ac_prev=localedir ;;
++ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
++ localedir=$ac_optarg ;;
++
++ -localstatedir | --localstatedir | --localstatedi | --localstated \
++ | --localstate | --localstat | --localsta | --localst | --locals)
++ ac_prev=localstatedir ;;
++ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
++ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
++ localstatedir=$ac_optarg ;;
++
++ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
++ ac_prev=mandir ;;
++ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
++ mandir=$ac_optarg ;;
++
++ -nfp | --nfp | --nf)
++ # Obsolete; use --without-fp.
++ with_fp=no ;;
++
++ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
++ | --no-cr | --no-c | -n)
++ no_create=yes ;;
++
++ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
++ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
++ no_recursion=yes ;;
++
++ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
++ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
++ | --oldin | --oldi | --old | --ol | --o)
++ ac_prev=oldincludedir ;;
++ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
++ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
++ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
++ oldincludedir=$ac_optarg ;;
++
++ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
++ ac_prev=prefix ;;
++ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
++ prefix=$ac_optarg ;;
++
++ -program-prefix | --program-prefix | --program-prefi | --program-pref \
++ | --program-pre | --program-pr | --program-p)
++ ac_prev=program_prefix ;;
++ -program-prefix=* | --program-prefix=* | --program-prefi=* \
++ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
++ program_prefix=$ac_optarg ;;
++
++ -program-suffix | --program-suffix | --program-suffi | --program-suff \
++ | --program-suf | --program-su | --program-s)
++ ac_prev=program_suffix ;;
++ -program-suffix=* | --program-suffix=* | --program-suffi=* \
++ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
++ program_suffix=$ac_optarg ;;
++
++ -program-transform-name | --program-transform-name \
++ | --program-transform-nam | --program-transform-na \
++ | --program-transform-n | --program-transform- \
++ | --program-transform | --program-transfor \
++ | --program-transfo | --program-transf \
++ | --program-trans | --program-tran \
++ | --progr-tra | --program-tr | --program-t)
++ ac_prev=program_transform_name ;;
++ -program-transform-name=* | --program-transform-name=* \
++ | --program-transform-nam=* | --program-transform-na=* \
++ | --program-transform-n=* | --program-transform-=* \
++ | --program-transform=* | --program-transfor=* \
++ | --program-transfo=* | --program-transf=* \
++ | --program-trans=* | --program-tran=* \
++ | --progr-tra=* | --program-tr=* | --program-t=*)
++ program_transform_name=$ac_optarg ;;
++
++ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
++ ac_prev=pdfdir ;;
++ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
++ pdfdir=$ac_optarg ;;
++
++ -psdir | --psdir | --psdi | --psd | --ps)
++ ac_prev=psdir ;;
++ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
++ psdir=$ac_optarg ;;
++
++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
++ | -silent | --silent | --silen | --sile | --sil)
++ silent=yes ;;
++
++ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
++ ac_prev=sbindir ;;
++ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
++ | --sbi=* | --sb=*)
++ sbindir=$ac_optarg ;;
++
++ -sharedstatedir | --sharedstatedir | --sharedstatedi \
++ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
++ | --sharedst | --shareds | --shared | --share | --shar \
++ | --sha | --sh)
++ ac_prev=sharedstatedir ;;
++ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
++ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
++ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
++ | --sha=* | --sh=*)
++ sharedstatedir=$ac_optarg ;;
++
++ -site | --site | --sit)
++ ac_prev=site ;;
++ -site=* | --site=* | --sit=*)
++ site=$ac_optarg ;;
++
++ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
++ ac_prev=srcdir ;;
++ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
++ srcdir=$ac_optarg ;;
++
++ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
++ | --syscon | --sysco | --sysc | --sys | --sy)
++ ac_prev=sysconfdir ;;
++ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
++ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
++ sysconfdir=$ac_optarg ;;
++
++ -target | --target | --targe | --targ | --tar | --ta | --t)
++ ac_prev=target_alias ;;
++ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
++ target_alias=$ac_optarg ;;
++
++ -v | -verbose | --verbose | --verbos | --verbo | --verb)
++ verbose=yes ;;
++
++ -version | --version | --versio | --versi | --vers | -V)
++ ac_init_version=: ;;
++
++ -with-* | --with-*)
++ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
++ # Reject names that are not valid shell variable names.
++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
++ as_fn_error $? "invalid package name: $ac_useropt"
++ ac_useropt_orig=$ac_useropt
++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
++ case $ac_user_opts in
++ *"
++"with_$ac_useropt"
++"*) ;;
++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
++ ac_unrecognized_sep=', ';;
++ esac
++ eval with_$ac_useropt=\$ac_optarg ;;
++
++ -without-* | --without-*)
++ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
++ # Reject names that are not valid shell variable names.
++ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
++ as_fn_error $? "invalid package name: $ac_useropt"
++ ac_useropt_orig=$ac_useropt
++ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
++ case $ac_user_opts in
++ *"
++"with_$ac_useropt"
++"*) ;;
++ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
++ ac_unrecognized_sep=', ';;
++ esac
++ eval with_$ac_useropt=no ;;
++
++ --x)
++ # Obsolete; use --with-x.
++ with_x=yes ;;
++
++ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
++ | --x-incl | --x-inc | --x-in | --x-i)
++ ac_prev=x_includes ;;
++ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
++ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
++ x_includes=$ac_optarg ;;
++
++ -x-libraries | --x-libraries | --x-librarie | --x-librari \
++ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
++ ac_prev=x_libraries ;;
++ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
++ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
++ x_libraries=$ac_optarg ;;
++
++ -*) as_fn_error $? "unrecognized option: \`$ac_option'
++Try \`$0 --help' for more information"
++ ;;
++
++ *=*)
++ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
++ # Reject names that are not valid shell variable names.
++ case $ac_envvar in #(
++ '' | [0-9]* | *[!_$as_cr_alnum]* )
++ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
++ esac
++ eval $ac_envvar=\$ac_optarg
++ export $ac_envvar ;;
++
++ *)
++ # FIXME: should be removed in autoconf 3.0.
++ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
++ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
++ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
++ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
++ ;;
++
++ esac
++done
++
++if test -n "$ac_prev"; then
++ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
++ as_fn_error $? "missing argument to $ac_option"
++fi
++
++if test -n "$ac_unrecognized_opts"; then
++ case $enable_option_checking in
++ no) ;;
++ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
++ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
++ esac
++fi
++
++# Check all directory arguments for consistency.
++for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
++ datadir sysconfdir sharedstatedir localstatedir includedir \
++ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
++ libdir localedir mandir
++do
++ eval ac_val=\$$ac_var
++ # Remove trailing slashes.
++ case $ac_val in
++ */ )
++ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
++ eval $ac_var=\$ac_val;;
++ esac
++ # Be sure to have absolute directory names.
++ case $ac_val in
++ [\\/$]* | ?:[\\/]* ) continue;;
++ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
++ esac
++ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
++done
++
++# There might be people who depend on the old broken behavior: `$host'
++# used to hold the argument of --host etc.
++# FIXME: To remove some day.
++build=$build_alias
++host=$host_alias
++target=$target_alias
++
++# FIXME: To remove some day.
++if test "x$host_alias" != x; then
++ if test "x$build_alias" = x; then
++ cross_compiling=maybe
++ elif test "x$build_alias" != "x$host_alias"; then
++ cross_compiling=yes
++ fi
++fi
++
++ac_tool_prefix=
++test -n "$host_alias" && ac_tool_prefix=$host_alias-
++
++test "$silent" = yes && exec 6>/dev/null
++
++
++ac_pwd=`pwd` && test -n "$ac_pwd" &&
++ac_ls_di=`ls -di .` &&
++ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
++ as_fn_error $? "working directory cannot be determined"
++test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
++ as_fn_error $? "pwd does not report name of working directory"
++
++
++# Find the source files, if location was not specified.
++if test -z "$srcdir"; then
++ ac_srcdir_defaulted=yes
++ # Try the directory containing this script, then the parent directory.
++ ac_confdir=`$as_dirname -- "$as_myself" ||
++$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$as_myself" : 'X\(//\)[^/]' \| \
++ X"$as_myself" : 'X\(//\)$' \| \
++ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$as_myself" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ srcdir=$ac_confdir
++ if test ! -r "$srcdir/$ac_unique_file"; then
++ srcdir=..
++ fi
++else
++ ac_srcdir_defaulted=no
++fi
++if test ! -r "$srcdir/$ac_unique_file"; then
++ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
++ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
++fi
++ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
++ac_abs_confdir=`(
++ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
++ pwd)`
++# When building in place, set srcdir=.
++if test "$ac_abs_confdir" = "$ac_pwd"; then
++ srcdir=.
++fi
++# Remove unnecessary trailing slashes from srcdir.
++# Double slashes in file names in object file debugging info
++# mess up M-x gdb in Emacs.
++case $srcdir in
++*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
++esac
++for ac_var in $ac_precious_vars; do
++ eval ac_env_${ac_var}_set=\${${ac_var}+set}
++ eval ac_env_${ac_var}_value=\$${ac_var}
++ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
++ eval ac_cv_env_${ac_var}_value=\$${ac_var}
++done
++
++#
++# Report the --help message.
++#
++if test "$ac_init_help" = "long"; then
++ # Omit some internal or obsolete options to make the list less imposing.
++ # This message is too long to be a string in the A/UX 3.1 sh.
++ cat <<_ACEOF
++\`configure' configures argyll 1.3.7 to adapt to many kinds of systems.
++
++Usage: $0 [OPTION]... [VAR=VALUE]...
++
++To assign environment variables (e.g., CC, CFLAGS...), specify them as
++VAR=VALUE. See below for descriptions of some of the useful variables.
++
++Defaults for the options are specified in brackets.
++
++Configuration:
++ -h, --help display this help and exit
++ --help=short display options specific to this package
++ --help=recursive display the short help of all the included packages
++ -V, --version display version information and exit
++ -q, --quiet, --silent do not print \`checking ...' messages
++ --cache-file=FILE cache test results in FILE [disabled]
++ -C, --config-cache alias for \`--cache-file=config.cache'
++ -n, --no-create do not create output files
++ --srcdir=DIR find the sources in DIR [configure dir or \`..']
++
++Installation directories:
++ --prefix=PREFIX install architecture-independent files in PREFIX
++ [$ac_default_prefix]
++ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
++ [PREFIX]
++
++By default, \`make install' will install all the files in
++\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
++an installation prefix other than \`$ac_default_prefix' using \`--prefix',
++for instance \`--prefix=\$HOME'.
++
++For better control, use the options below.
++
++Fine tuning of the installation directories:
++ --bindir=DIR user executables [EPREFIX/bin]
++ --sbindir=DIR system admin executables [EPREFIX/sbin]
++ --libexecdir=DIR program executables [EPREFIX/libexec]
++ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
++ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
++ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
++ --libdir=DIR object code libraries [EPREFIX/lib]
++ --includedir=DIR C header files [PREFIX/include]
++ --oldincludedir=DIR C header files for non-gcc [/usr/include]
++ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
++ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
++ --infodir=DIR info documentation [DATAROOTDIR/info]
++ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
++ --mandir=DIR man documentation [DATAROOTDIR/man]
++ --docdir=DIR documentation root [DATAROOTDIR/doc/argyll]
++ --htmldir=DIR html documentation [DOCDIR]
++ --dvidir=DIR dvi documentation [DOCDIR]
++ --pdfdir=DIR pdf documentation [DOCDIR]
++ --psdir=DIR ps documentation [DOCDIR]
++_ACEOF
++
++ cat <<\_ACEOF
++
++Program names:
++ --program-prefix=PREFIX prepend PREFIX to installed program names
++ --program-suffix=SUFFIX append SUFFIX to installed program names
++ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
++
++X features:
++ --x-includes=DIR X include files are in DIR
++ --x-libraries=DIR X library files are in DIR
++
++System types:
++ --build=BUILD configure for building on BUILD [guessed]
++ --host=HOST cross-compile to build programs to run on HOST [BUILD]
++_ACEOF
++fi
++
++if test -n "$ac_init_help"; then
++ case $ac_init_help in
++ short | recursive ) echo "Configuration of argyll 1.3.7:";;
++ esac
++ cat <<\_ACEOF
++
++Optional Features:
++ --disable-option-checking ignore unrecognized --enable/--with options
++ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
++ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
++ --enable-silent-rules less verbose build output (undo: "make V=1")
++ --disable-silent-rules verbose build output (undo: "make V=0")
++ --enable-dependency-tracking
++ do not reject slow dependency extractors
++ --disable-dependency-tracking
++ speeds up one-time build
++ --enable-shared[=PKGS] build shared libraries [default=yes]
++ --enable-static[=PKGS] build static libraries [default=yes]
++ --enable-fast-install[=PKGS]
++ optimize for fast installation [default=yes]
++ --disable-libtool-lock avoid locking (might break parallel builds)
++
++Optional Packages:
++ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
++ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
++ --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
++ both]
++ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
++ --with-sysroot=DIR Search for dependent libraries within DIR
++ (or the compiler's sysroot if not specified).
++ --with-x use the X Window System
++ --with-system-libicc use system libicc instead of argyllcms copy
++ --with-system-libyajl use system libyajl instead of argyllcms copy
++
++Some influential environment variables:
++ CC C compiler command
++ CFLAGS C compiler flags
++ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
++ nonstandard directory <lib dir>
++ LIBS libraries to pass to the linker, e.g. -l<library>
++ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
++ you have headers in a nonstandard directory <include dir>
++ CPP C preprocessor
++ XMKMF Path to xmkmf, Makefile generator for X Window System
++
++Use these variables to override the choices made by `configure' or to help
++it to find libraries and programs with nonstandard names/locations.
++
++Report bugs to the package provider.
++_ACEOF
++ac_status=$?
++fi
++
++if test "$ac_init_help" = "recursive"; then
++ # If there are subdirs, report their specific --help.
++ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
++ test -d "$ac_dir" ||
++ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
++ continue
++ ac_builddir=.
++
++case "$ac_dir" in
++.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
++*)
++ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
++ # A ".." for each directory in $ac_dir_suffix.
++ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
++ case $ac_top_builddir_sub in
++ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
++ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
++ esac ;;
++esac
++ac_abs_top_builddir=$ac_pwd
++ac_abs_builddir=$ac_pwd$ac_dir_suffix
++# for backward compatibility:
++ac_top_builddir=$ac_top_build_prefix
++
++case $srcdir in
++ .) # We are building in place.
++ ac_srcdir=.
++ ac_top_srcdir=$ac_top_builddir_sub
++ ac_abs_top_srcdir=$ac_pwd ;;
++ [\\/]* | ?:[\\/]* ) # Absolute name.
++ ac_srcdir=$srcdir$ac_dir_suffix;
++ ac_top_srcdir=$srcdir
++ ac_abs_top_srcdir=$srcdir ;;
++ *) # Relative name.
++ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
++ ac_top_srcdir=$ac_top_build_prefix$srcdir
++ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
++esac
++ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
++
++ cd "$ac_dir" || { ac_status=$?; continue; }
++ # Check for guested configure.
++ if test -f "$ac_srcdir/configure.gnu"; then
++ echo &&
++ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
++ elif test -f "$ac_srcdir/configure"; then
++ echo &&
++ $SHELL "$ac_srcdir/configure" --help=recursive
++ else
++ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
++ fi || ac_status=$?
++ cd "$ac_pwd" || { ac_status=$?; break; }
++ done
++fi
++
++test -n "$ac_init_help" && exit $ac_status
++if $ac_init_version; then
++ cat <<\_ACEOF
++argyll configure 1.3.7
++generated by GNU Autoconf 2.69
++
++Copyright (C) 2012 Free Software Foundation, Inc.
++This configure script is free software; the Free Software Foundation
++gives unlimited permission to copy, distribute and modify it.
++_ACEOF
++ exit
++fi
++
++## ------------------------ ##
++## Autoconf initialization. ##
++## ------------------------ ##
++
++# ac_fn_c_try_compile LINENO
++# --------------------------
++# Try to compile conftest.$ac_ext, and return whether this succeeded.
++ac_fn_c_try_compile ()
++{
++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ rm -f conftest.$ac_objext
++ if { { ac_try="$ac_compile"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_compile") 2>conftest.err
++ ac_status=$?
++ if test -s conftest.err; then
++ grep -v '^ *+' conftest.err >conftest.er1
++ cat conftest.er1 >&5
++ mv -f conftest.er1 conftest.err
++ fi
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && {
++ test -z "$ac_c_werror_flag" ||
++ test ! -s conftest.err
++ } && test -s conftest.$ac_objext; then :
++ ac_retval=0
++else
++ $as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ ac_retval=1
++fi
++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
++ as_fn_set_status $ac_retval
++
++} # ac_fn_c_try_compile
++
++# ac_fn_c_try_link LINENO
++# -----------------------
++# Try to link conftest.$ac_ext, and return whether this succeeded.
++ac_fn_c_try_link ()
++{
++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ rm -f conftest.$ac_objext conftest$ac_exeext
++ if { { ac_try="$ac_link"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_link") 2>conftest.err
++ ac_status=$?
++ if test -s conftest.err; then
++ grep -v '^ *+' conftest.err >conftest.er1
++ cat conftest.er1 >&5
++ mv -f conftest.er1 conftest.err
++ fi
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && {
++ test -z "$ac_c_werror_flag" ||
++ test ! -s conftest.err
++ } && test -s conftest$ac_exeext && {
++ test "$cross_compiling" = yes ||
++ test -x conftest$ac_exeext
++ }; then :
++ ac_retval=0
++else
++ $as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ ac_retval=1
++fi
++ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
++ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
++ # interfere with the next link command; also delete a directory that is
++ # left behind by Apple's compiler. We do this before executing the actions.
++ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
++ as_fn_set_status $ac_retval
++
++} # ac_fn_c_try_link
++
++# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
++# -------------------------------------------------------
++# Tests whether HEADER exists and can be compiled using the include files in
++# INCLUDES, setting the cache variable VAR accordingly.
++ac_fn_c_check_header_compile ()
++{
++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
++$as_echo_n "checking for $2... " >&6; }
++if eval \${$3+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++$4
++#include <$2>
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ eval "$3=yes"
++else
++ eval "$3=no"
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++fi
++eval ac_res=\$$3
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
++$as_echo "$ac_res" >&6; }
++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
++
++} # ac_fn_c_check_header_compile
++
++# ac_fn_c_try_cpp LINENO
++# ----------------------
++# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
++ac_fn_c_try_cpp ()
++{
++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ if { { ac_try="$ac_cpp conftest.$ac_ext"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
++ ac_status=$?
++ if test -s conftest.err; then
++ grep -v '^ *+' conftest.err >conftest.er1
++ cat conftest.er1 >&5
++ mv -f conftest.er1 conftest.err
++ fi
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } > conftest.i && {
++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
++ test ! -s conftest.err
++ }; then :
++ ac_retval=0
++else
++ $as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ ac_retval=1
++fi
++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
++ as_fn_set_status $ac_retval
++
++} # ac_fn_c_try_cpp
++
++# ac_fn_c_try_run LINENO
++# ----------------------
++# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
++# that executables *can* be run.
++ac_fn_c_try_run ()
++{
++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ if { { ac_try="$ac_link"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_link") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
++ { { case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_try") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; }; then :
++ ac_retval=0
++else
++ $as_echo "$as_me: program exited with status $ac_status" >&5
++ $as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++ ac_retval=$ac_status
++fi
++ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
++ as_fn_set_status $ac_retval
++
++} # ac_fn_c_try_run
++
++# ac_fn_c_check_func LINENO FUNC VAR
++# ----------------------------------
++# Tests whether FUNC exists, setting the cache variable VAR accordingly
++ac_fn_c_check_func ()
++{
++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
++$as_echo_n "checking for $2... " >&6; }
++if eval \${$3+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
++ For example, HP-UX 11i <limits.h> declares gettimeofday. */
++#define $2 innocuous_$2
++
++/* System header to define __stub macros and hopefully few prototypes,
++ which can conflict with char $2 (); below.
++ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
++ <limits.h> exists even on freestanding compilers. */
++
++#ifdef __STDC__
++# include <limits.h>
++#else
++# include <assert.h>
++#endif
++
++#undef $2
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char $2 ();
++/* The GNU C library defines this for functions which it implements
++ to always fail with ENOSYS. Some functions are actually named
++ something starting with __ and the normal name is an alias. */
++#if defined __stub_$2 || defined __stub___$2
++choke me
++#endif
++
++int
++main ()
++{
++return $2 ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ eval "$3=yes"
++else
++ eval "$3=no"
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++fi
++eval ac_res=\$$3
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
++$as_echo "$ac_res" >&6; }
++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
++
++} # ac_fn_c_check_func
++cat >config.log <<_ACEOF
++This file contains any messages produced by compilers while
++running configure, to aid debugging if configure makes a mistake.
++
++It was created by argyll $as_me 1.3.7, which was
++generated by GNU Autoconf 2.69. Invocation command line was
++
++ $ $0 $@
++
++_ACEOF
++exec 5>>config.log
++{
++cat <<_ASUNAME
++## --------- ##
++## Platform. ##
++## --------- ##
++
++hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
++uname -m = `(uname -m) 2>/dev/null || echo unknown`
++uname -r = `(uname -r) 2>/dev/null || echo unknown`
++uname -s = `(uname -s) 2>/dev/null || echo unknown`
++uname -v = `(uname -v) 2>/dev/null || echo unknown`
++
++/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
++/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
++
++/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
++/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
++/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
++/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
++/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
++/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
++/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
++
++_ASUNAME
++
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ $as_echo "PATH: $as_dir"
++ done
++IFS=$as_save_IFS
++
++} >&5
++
++cat >&5 <<_ACEOF
++
++
++## ----------- ##
++## Core tests. ##
++## ----------- ##
++
++_ACEOF
++
++
++# Keep a trace of the command line.
++# Strip out --no-create and --no-recursion so they do not pile up.
++# Strip out --silent because we don't want to record it for future runs.
++# Also quote any args containing shell meta-characters.
++# Make two passes to allow for proper duplicate-argument suppression.
++ac_configure_args=
++ac_configure_args0=
++ac_configure_args1=
++ac_must_keep_next=false
++for ac_pass in 1 2
++do
++ for ac_arg
++ do
++ case $ac_arg in
++ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
++ | -silent | --silent | --silen | --sile | --sil)
++ continue ;;
++ *\'*)
++ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
++ esac
++ case $ac_pass in
++ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
++ 2)
++ as_fn_append ac_configure_args1 " '$ac_arg'"
++ if test $ac_must_keep_next = true; then
++ ac_must_keep_next=false # Got value, back to normal.
++ else
++ case $ac_arg in
++ *=* | --config-cache | -C | -disable-* | --disable-* \
++ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
++ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
++ | -with-* | --with-* | -without-* | --without-* | --x)
++ case "$ac_configure_args0 " in
++ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
++ esac
++ ;;
++ -* ) ac_must_keep_next=true ;;
++ esac
++ fi
++ as_fn_append ac_configure_args " '$ac_arg'"
++ ;;
++ esac
++ done
++done
++{ ac_configure_args0=; unset ac_configure_args0;}
++{ ac_configure_args1=; unset ac_configure_args1;}
++
++# When interrupted or exit'd, cleanup temporary files, and complete
++# config.log. We remove comments because anyway the quotes in there
++# would cause problems or look ugly.
++# WARNING: Use '\'' to represent an apostrophe within the trap.
++# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
++trap 'exit_status=$?
++ # Save into config.log some information that might help in debugging.
++ {
++ echo
++
++ $as_echo "## ---------------- ##
++## Cache variables. ##
++## ---------------- ##"
++ echo
++ # The following way of writing the cache mishandles newlines in values,
++(
++ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
++ eval ac_val=\$$ac_var
++ case $ac_val in #(
++ *${as_nl}*)
++ case $ac_var in #(
++ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
++$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
++ esac
++ case $ac_var in #(
++ _ | IFS | as_nl) ;; #(
++ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
++ *) { eval $ac_var=; unset $ac_var;} ;;
++ esac ;;
++ esac
++ done
++ (set) 2>&1 |
++ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
++ *${as_nl}ac_space=\ *)
++ sed -n \
++ "s/'\''/'\''\\\\'\'''\''/g;
++ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
++ ;; #(
++ *)
++ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
++ ;;
++ esac |
++ sort
++)
++ echo
++
++ $as_echo "## ----------------- ##
++## Output variables. ##
++## ----------------- ##"
++ echo
++ for ac_var in $ac_subst_vars
++ do
++ eval ac_val=\$$ac_var
++ case $ac_val in
++ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
++ esac
++ $as_echo "$ac_var='\''$ac_val'\''"
++ done | sort
++ echo
++
++ if test -n "$ac_subst_files"; then
++ $as_echo "## ------------------- ##
++## File substitutions. ##
++## ------------------- ##"
++ echo
++ for ac_var in $ac_subst_files
++ do
++ eval ac_val=\$$ac_var
++ case $ac_val in
++ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
++ esac
++ $as_echo "$ac_var='\''$ac_val'\''"
++ done | sort
++ echo
++ fi
++
++ if test -s confdefs.h; then
++ $as_echo "## ----------- ##
++## confdefs.h. ##
++## ----------- ##"
++ echo
++ cat confdefs.h
++ echo
++ fi
++ test "$ac_signal" != 0 &&
++ $as_echo "$as_me: caught signal $ac_signal"
++ $as_echo "$as_me: exit $exit_status"
++ } >&5
++ rm -f core *.core core.conftest.* &&
++ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
++ exit $exit_status
++' 0
++for ac_signal in 1 2 13 15; do
++ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
++done
++ac_signal=0
++
++# confdefs.h avoids OS command line length limits that DEFS can exceed.
++rm -f -r conftest* confdefs.h
++
++$as_echo "/* confdefs.h */" > confdefs.h
++
++# Predefined preprocessor variables.
++
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE_NAME "$PACKAGE_NAME"
++_ACEOF
++
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
++_ACEOF
++
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE_VERSION "$PACKAGE_VERSION"
++_ACEOF
++
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE_STRING "$PACKAGE_STRING"
++_ACEOF
++
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
++_ACEOF
++
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE_URL "$PACKAGE_URL"
++_ACEOF
++
++
++# Let the site file select an alternate cache file if it wants to.
++# Prefer an explicitly selected file to automatically selected ones.
++ac_site_file1=NONE
++ac_site_file2=NONE
++if test -n "$CONFIG_SITE"; then
++ # We do not want a PATH search for config.site.
++ case $CONFIG_SITE in #((
++ -*) ac_site_file1=./$CONFIG_SITE;;
++ */*) ac_site_file1=$CONFIG_SITE;;
++ *) ac_site_file1=./$CONFIG_SITE;;
++ esac
++elif test "x$prefix" != xNONE; then
++ ac_site_file1=$prefix/share/config.site
++ ac_site_file2=$prefix/etc/config.site
++else
++ ac_site_file1=$ac_default_prefix/share/config.site
++ ac_site_file2=$ac_default_prefix/etc/config.site
++fi
++for ac_site_file in "$ac_site_file1" "$ac_site_file2"
++do
++ test "x$ac_site_file" = xNONE && continue
++ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
++$as_echo "$as_me: loading site script $ac_site_file" >&6;}
++ sed 's/^/| /' "$ac_site_file" >&5
++ . "$ac_site_file" \
++ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "failed to load site script $ac_site_file
++See \`config.log' for more details" "$LINENO" 5; }
++ fi
++done
++
++if test -r "$cache_file"; then
++ # Some versions of bash will fail to source /dev/null (special files
++ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
++ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
++$as_echo "$as_me: loading cache $cache_file" >&6;}
++ case $cache_file in
++ [\\/]* | ?:[\\/]* ) . "$cache_file";;
++ *) . "./$cache_file";;
++ esac
++ fi
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
++$as_echo "$as_me: creating cache $cache_file" >&6;}
++ >$cache_file
++fi
++
++# Check that the precious variables saved in the cache have kept the same
++# value.
++ac_cache_corrupted=false
++for ac_var in $ac_precious_vars; do
++ eval ac_old_set=\$ac_cv_env_${ac_var}_set
++ eval ac_new_set=\$ac_env_${ac_var}_set
++ eval ac_old_val=\$ac_cv_env_${ac_var}_value
++ eval ac_new_val=\$ac_env_${ac_var}_value
++ case $ac_old_set,$ac_new_set in
++ set,)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
++$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
++ ac_cache_corrupted=: ;;
++ ,set)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
++$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
++ ac_cache_corrupted=: ;;
++ ,);;
++ *)
++ if test "x$ac_old_val" != "x$ac_new_val"; then
++ # differences in whitespace do not lead to failure.
++ ac_old_val_w=`echo x $ac_old_val`
++ ac_new_val_w=`echo x $ac_new_val`
++ if test "$ac_old_val_w" != "$ac_new_val_w"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
++$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
++ ac_cache_corrupted=:
++ else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
++$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
++ eval $ac_var=\$ac_old_val
++ fi
++ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
++$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
++$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
++ fi;;
++ esac
++ # Pass precious variables to config.status.
++ if test "$ac_new_set" = set; then
++ case $ac_new_val in
++ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
++ *) ac_arg=$ac_var=$ac_new_val ;;
++ esac
++ case " $ac_configure_args " in
++ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
++ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
++ esac
++ fi
++done
++if $ac_cache_corrupted; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
++$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
++ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
++fi
++## -------------------- ##
++## Main body of script. ##
++## -------------------- ##
++
++ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++
++
++am__api_version='1.13'
++
++ac_aux_dir=
++for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
++ if test -f "$ac_dir/install-sh"; then
++ ac_aux_dir=$ac_dir
++ ac_install_sh="$ac_aux_dir/install-sh -c"
++ break
++ elif test -f "$ac_dir/install.sh"; then
++ ac_aux_dir=$ac_dir
++ ac_install_sh="$ac_aux_dir/install.sh -c"
++ break
++ elif test -f "$ac_dir/shtool"; then
++ ac_aux_dir=$ac_dir
++ ac_install_sh="$ac_aux_dir/shtool install -c"
++ break
++ fi
++done
++if test -z "$ac_aux_dir"; then
++ as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5
++fi
++
++# These three variables are undocumented and unsupported,
++# and are intended to be withdrawn in a future Autoconf release.
++# They can cause serious problems if a builder's source tree is in a directory
++# whose full name contains unusual characters.
++ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
++ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
++ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
++
++
++# Find a good install program. We prefer a C program (faster),
++# so one script is as good as another. But avoid the broken or
++# incompatible versions:
++# SysV /etc/install, /usr/sbin/install
++# SunOS /usr/etc/install
++# IRIX /sbin/install
++# AIX /bin/install
++# AmigaOS /C/install, which installs bootblocks on floppy discs
++# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
++# AFS /usr/afsws/bin/install, which mishandles nonexistent args
++# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
++# OS/2's system install, which has a completely different semantic
++# ./install, which can be erroneously created by make from ./install.sh.
++# Reject install programs that cannot install multiple files.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
++$as_echo_n "checking for a BSD-compatible install... " >&6; }
++if test -z "$INSTALL"; then
++if ${ac_cv_path_install+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ # Account for people who put trailing slashes in PATH elements.
++case $as_dir/ in #((
++ ./ | .// | /[cC]/* | \
++ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
++ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
++ /usr/ucb/* ) ;;
++ *)
++ # OSF1 and SCO ODT 3.0 have their own names for install.
++ # Don't use installbsd from OSF since it installs stuff as root
++ # by default.
++ for ac_prog in ginstall scoinst install; do
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
++ if test $ac_prog = install &&
++ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
++ # AIX install. It has an incompatible calling convention.
++ :
++ elif test $ac_prog = install &&
++ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
++ # program-specific install script used by HP pwplus--don't use.
++ :
++ else
++ rm -rf conftest.one conftest.two conftest.dir
++ echo one > conftest.one
++ echo two > conftest.two
++ mkdir conftest.dir
++ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
++ test -s conftest.one && test -s conftest.two &&
++ test -s conftest.dir/conftest.one &&
++ test -s conftest.dir/conftest.two
++ then
++ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
++ break 3
++ fi
++ fi
++ fi
++ done
++ done
++ ;;
++esac
++
++ done
++IFS=$as_save_IFS
++
++rm -rf conftest.one conftest.two conftest.dir
++
++fi
++ if test "${ac_cv_path_install+set}" = set; then
++ INSTALL=$ac_cv_path_install
++ else
++ # As a last resort, use the slow shell script. Don't cache a
++ # value for INSTALL within a source directory, because that will
++ # break other packages using the cache if that directory is
++ # removed, or if the value is a relative name.
++ INSTALL=$ac_install_sh
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
++$as_echo "$INSTALL" >&6; }
++
++# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
++# It thinks the first close brace ends the variable substitution.
++test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
++
++test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
++
++test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
++$as_echo_n "checking whether build environment is sane... " >&6; }
++# Reject unsafe characters in $srcdir or the absolute working directory
++# name. Accept space and tab only in the latter.
++am_lf='
++'
++case `pwd` in
++ *[\\\"\#\$\&\'\`$am_lf]*)
++ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
++esac
++case $srcdir in
++ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
++ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
++esac
++
++# Do 'set' in a subshell so we don't clobber the current shell's
++# arguments. Must try -L first in case configure is actually a
++# symlink; some systems play weird games with the mod time of symlinks
++# (eg FreeBSD returns the mod time of the symlink's containing
++# directory).
++if (
++ am_has_slept=no
++ for am_try in 1 2; do
++ echo "timestamp, slept: $am_has_slept" > conftest.file
++ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
++ if test "$*" = "X"; then
++ # -L didn't work.
++ set X `ls -t "$srcdir/configure" conftest.file`
++ fi
++ if test "$*" != "X $srcdir/configure conftest.file" \
++ && test "$*" != "X conftest.file $srcdir/configure"; then
++
++ # If neither matched, then we have a broken ls. This can happen
++ # if, for instance, CONFIG_SHELL is bash and it inherits a
++ # broken ls alias from the environment. This has actually
++ # happened. Such a system could not be considered "sane".
++ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
++ alias in your environment" "$LINENO" 5
++ fi
++ if test "$2" = conftest.file || test $am_try -eq 2; then
++ break
++ fi
++ # Just in case.
++ sleep 1
++ am_has_slept=yes
++ done
++ test "$2" = conftest.file
++ )
++then
++ # Ok.
++ :
++else
++ as_fn_error $? "newly created file is older than distributed files!
++Check your system clock" "$LINENO" 5
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++# If we didn't sleep, we still need to ensure time stamps of config.status and
++# generated files are strictly newer.
++am_sleep_pid=
++if grep 'slept: no' conftest.file >/dev/null 2>&1; then
++ ( sleep 1 ) &
++ am_sleep_pid=$!
++fi
++
++rm -f conftest.file
++
++test "$program_prefix" != NONE &&
++ program_transform_name="s&^&$program_prefix&;$program_transform_name"
++# Use a double $ so make ignores it.
++test "$program_suffix" != NONE &&
++ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
++# Double any \ or $.
++# By default was `s,x,x', remove it if useless.
++ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
++program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
++
++# expand $ac_aux_dir to an absolute path
++am_aux_dir=`cd $ac_aux_dir && pwd`
++
++if test x"${MISSING+set}" != xset; then
++ case $am_aux_dir in
++ *\ * | *\ *)
++ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
++ *)
++ MISSING="\${SHELL} $am_aux_dir/missing" ;;
++ esac
++fi
++# Use eval to expand $SHELL
++if eval "$MISSING --is-lightweight"; then
++ am_missing_run="$MISSING "
++else
++ am_missing_run=
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
++$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
++fi
++
++if test x"${install_sh}" != xset; then
++ case $am_aux_dir in
++ *\ * | *\ *)
++ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
++ *)
++ install_sh="\${SHELL} $am_aux_dir/install-sh"
++ esac
++fi
++
++# Installed binaries are usually stripped using 'strip' when the user
++# run "make install-strip". However 'strip' might not be the right
++# tool to use in cross-compilation environments, therefore Automake
++# will honor the 'STRIP' environment variable to overrule this program.
++if test "$cross_compiling" != no; then
++ if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
++set dummy ${ac_tool_prefix}strip; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_STRIP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$STRIP"; then
++ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++STRIP=$ac_cv_prog_STRIP
++if test -n "$STRIP"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
++$as_echo "$STRIP" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_STRIP"; then
++ ac_ct_STRIP=$STRIP
++ # Extract the first word of "strip", so it can be a program name with args.
++set dummy strip; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_STRIP"; then
++ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_STRIP="strip"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
++if test -n "$ac_ct_STRIP"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
++$as_echo "$ac_ct_STRIP" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_STRIP" = x; then
++ STRIP=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ STRIP=$ac_ct_STRIP
++ fi
++else
++ STRIP="$ac_cv_prog_STRIP"
++fi
++
++fi
++INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
++$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
++if test -z "$MKDIR_P"; then
++ if ${ac_cv_path_mkdir+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_prog in mkdir gmkdir; do
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
++ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
++ 'mkdir (GNU coreutils) '* | \
++ 'mkdir (coreutils) '* | \
++ 'mkdir (fileutils) '4.1*)
++ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
++ break 3;;
++ esac
++ done
++ done
++ done
++IFS=$as_save_IFS
++
++fi
++
++ test -d ./--version && rmdir ./--version
++ if test "${ac_cv_path_mkdir+set}" = set; then
++ MKDIR_P="$ac_cv_path_mkdir -p"
++ else
++ # As a last resort, use the slow shell script. Don't cache a
++ # value for MKDIR_P within a source directory, because that will
++ # break other packages using the cache if that directory is
++ # removed, or if the value is a relative name.
++ MKDIR_P="$ac_install_sh -d"
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
++$as_echo "$MKDIR_P" >&6; }
++
++for ac_prog in gawk mawk nawk awk
++do
++ # Extract the first word of "$ac_prog", so it can be a program name with args.
++set dummy $ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_AWK+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$AWK"; then
++ ac_cv_prog_AWK="$AWK" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_AWK="$ac_prog"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++AWK=$ac_cv_prog_AWK
++if test -n "$AWK"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
++$as_echo "$AWK" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ test -n "$AWK" && break
++done
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
++$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
++set x ${MAKE-make}
++ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
++if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat >conftest.make <<\_ACEOF
++SHELL = /bin/sh
++all:
++ @echo '@@@%%%=$(MAKE)=@@@%%%'
++_ACEOF
++# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
++case `${MAKE-make} -f conftest.make 2>/dev/null` in
++ *@@@%%%=?*=@@@%%%*)
++ eval ac_cv_prog_make_${ac_make}_set=yes;;
++ *)
++ eval ac_cv_prog_make_${ac_make}_set=no;;
++esac
++rm -f conftest.make
++fi
++if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++ SET_MAKE=
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++ SET_MAKE="MAKE=${MAKE-make}"
++fi
++
++rm -rf .tst 2>/dev/null
++mkdir .tst 2>/dev/null
++if test -d .tst; then
++ am__leading_dot=.
++else
++ am__leading_dot=_
++fi
++rmdir .tst 2>/dev/null
++
++# Check whether --enable-silent-rules was given.
++if test "${enable_silent_rules+set}" = set; then :
++ enableval=$enable_silent_rules;
++fi
++
++case $enable_silent_rules in # (((
++ yes) AM_DEFAULT_VERBOSITY=0;;
++ no) AM_DEFAULT_VERBOSITY=1;;
++ *) AM_DEFAULT_VERBOSITY=1;;
++esac
++am_make=${MAKE-make}
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
++$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
++if ${am_cv_make_support_nested_variables+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if $as_echo 'TRUE=$(BAR$(V))
++BAR0=false
++BAR1=true
++V=1
++am__doit:
++ @$(TRUE)
++.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
++ am_cv_make_support_nested_variables=yes
++else
++ am_cv_make_support_nested_variables=no
++fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
++$as_echo "$am_cv_make_support_nested_variables" >&6; }
++if test $am_cv_make_support_nested_variables = yes; then
++ AM_V='$(V)'
++ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
++else
++ AM_V=$AM_DEFAULT_VERBOSITY
++ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
++fi
++AM_BACKSLASH='\'
++
++if test "`cd $srcdir && pwd`" != "`pwd`"; then
++ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
++ # is not polluted with repeated "-I."
++ am__isrc=' -I$(srcdir)'
++ # test to see if srcdir already configured
++ if test -f $srcdir/config.status; then
++ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
++ fi
++fi
++
++# test whether we have cygpath
++if test -z "$CYGPATH_W"; then
++ if (cygpath --version) >/dev/null 2>/dev/null; then
++ CYGPATH_W='cygpath -w'
++ else
++ CYGPATH_W=echo
++ fi
++fi
++
++
++# Define the identity of the package.
++ PACKAGE='argyll'
++ VERSION='1.3.7'
++
++
++cat >>confdefs.h <<_ACEOF
++#define PACKAGE "$PACKAGE"
++_ACEOF
++
++
++cat >>confdefs.h <<_ACEOF
++#define VERSION "$VERSION"
++_ACEOF
++
++# Some tools Automake needs.
++
++ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
++
++
++AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
++
++
++AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
++
++
++AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
++
++
++MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
++
++# For better backward compatibility. To be removed once Automake 1.9.x
++# dies out for good. For more background, see:
++# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
++# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
++mkdir_p='$(MKDIR_P)'
++
++# We need awk for the "check" target. The system "awk" is bad on
++# some platforms.
++# Always define AMTAR for backward compatibility. Yes, it's still used
++# in the wild :-( We should find a proper way to deprecate it ...
++AMTAR='$${TAR-tar}'
++
++
++# We'll loop over all known methods to create a tar archive until one works.
++_am_tools='gnutar pax cpio none'
++
++am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
++
++
++
++
++
++
++
++ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
++set dummy ${ac_tool_prefix}gcc; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$CC"; then
++ ac_cv_prog_CC="$CC" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_CC="${ac_tool_prefix}gcc"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++CC=$ac_cv_prog_CC
++if test -n "$CC"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_CC"; then
++ ac_ct_CC=$CC
++ # Extract the first word of "gcc", so it can be a program name with args.
++set dummy gcc; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_CC"; then
++ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_CC="gcc"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_CC=$ac_cv_prog_ac_ct_CC
++if test -n "$ac_ct_CC"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
++$as_echo "$ac_ct_CC" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_CC" = x; then
++ CC=""
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ CC=$ac_ct_CC
++ fi
++else
++ CC="$ac_cv_prog_CC"
++fi
++
++if test -z "$CC"; then
++ if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
++set dummy ${ac_tool_prefix}cc; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$CC"; then
++ ac_cv_prog_CC="$CC" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_CC="${ac_tool_prefix}cc"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++CC=$ac_cv_prog_CC
++if test -n "$CC"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ fi
++fi
++if test -z "$CC"; then
++ # Extract the first word of "cc", so it can be a program name with args.
++set dummy cc; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$CC"; then
++ ac_cv_prog_CC="$CC" # Let the user override the test.
++else
++ ac_prog_rejected=no
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
++ ac_prog_rejected=yes
++ continue
++ fi
++ ac_cv_prog_CC="cc"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++if test $ac_prog_rejected = yes; then
++ # We found a bogon in the path, so make sure we never use it.
++ set dummy $ac_cv_prog_CC
++ shift
++ if test $# != 0; then
++ # We chose a different compiler from the bogus one.
++ # However, it has the same basename, so the bogon will be chosen
++ # first if we set CC to just the basename; use the full file name.
++ shift
++ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
++ fi
++fi
++fi
++fi
++CC=$ac_cv_prog_CC
++if test -n "$CC"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$CC"; then
++ if test -n "$ac_tool_prefix"; then
++ for ac_prog in cl.exe
++ do
++ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
++set dummy $ac_tool_prefix$ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$CC"; then
++ ac_cv_prog_CC="$CC" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++CC=$ac_cv_prog_CC
++if test -n "$CC"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
++$as_echo "$CC" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ test -n "$CC" && break
++ done
++fi
++if test -z "$CC"; then
++ ac_ct_CC=$CC
++ for ac_prog in cl.exe
++do
++ # Extract the first word of "$ac_prog", so it can be a program name with args.
++set dummy $ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_CC+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_CC"; then
++ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_CC="$ac_prog"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_CC=$ac_cv_prog_ac_ct_CC
++if test -n "$ac_ct_CC"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
++$as_echo "$ac_ct_CC" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ test -n "$ac_ct_CC" && break
++done
++
++ if test "x$ac_ct_CC" = x; then
++ CC=""
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ CC=$ac_ct_CC
++ fi
++fi
++
++fi
++
++
++test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "no acceptable C compiler found in \$PATH
++See \`config.log' for more details" "$LINENO" 5; }
++
++# Provide some information about the compiler.
++$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
++set X $ac_compile
++ac_compiler=$2
++for ac_option in --version -v -V -qversion; do
++ { { ac_try="$ac_compiler $ac_option >&5"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
++ ac_status=$?
++ if test -s conftest.err; then
++ sed '10a\
++... rest of stderr output deleted ...
++ 10q' conftest.err >conftest.er1
++ cat conftest.er1 >&5
++ fi
++ rm -f conftest.er1 conftest.err
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }
++done
++
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++ac_clean_files_save=$ac_clean_files
++ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
++# Try to create an executable without -o first, disregard a.out.
++# It will help us diagnose broken compilers, and finding out an intuition
++# of exeext.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
++$as_echo_n "checking whether the C compiler works... " >&6; }
++ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
++
++# The possible output files:
++ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
++
++ac_rmfiles=
++for ac_file in $ac_files
++do
++ case $ac_file in
++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
++ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
++ esac
++done
++rm -f $ac_rmfiles
++
++if { { ac_try="$ac_link_default"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_link_default") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then :
++ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
++# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
++# in a Makefile. We should not override ac_cv_exeext if it was cached,
++# so that the user can short-circuit this test for compilers unknown to
++# Autoconf.
++for ac_file in $ac_files ''
++do
++ test -f "$ac_file" || continue
++ case $ac_file in
++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
++ ;;
++ [ab].out )
++ # We found the default executable, but exeext='' is most
++ # certainly right.
++ break;;
++ *.* )
++ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
++ then :; else
++ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
++ fi
++ # We set ac_cv_exeext here because the later test for it is not
++ # safe: cross compilers may not add the suffix if given an `-o'
++ # argument, so we may need to know it at that point already.
++ # Even if this section looks crufty: it has the advantage of
++ # actually working.
++ break;;
++ * )
++ break;;
++ esac
++done
++test "$ac_cv_exeext" = no && ac_cv_exeext=
++
++else
++ ac_file=''
++fi
++if test -z "$ac_file"; then :
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++$as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error 77 "C compiler cannot create executables
++See \`config.log' for more details" "$LINENO" 5; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
++$as_echo_n "checking for C compiler default output file name... " >&6; }
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
++$as_echo "$ac_file" >&6; }
++ac_exeext=$ac_cv_exeext
++
++rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
++ac_clean_files=$ac_clean_files_save
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
++$as_echo_n "checking for suffix of executables... " >&6; }
++if { { ac_try="$ac_link"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_link") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then :
++ # If both `conftest.exe' and `conftest' are `present' (well, observable)
++# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
++# work properly (i.e., refer to `conftest.exe'), while it won't with
++# `rm'.
++for ac_file in conftest.exe conftest conftest.*; do
++ test -f "$ac_file" || continue
++ case $ac_file in
++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
++ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
++ break;;
++ * ) break;;
++ esac
++done
++else
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "cannot compute suffix of executables: cannot compile and link
++See \`config.log' for more details" "$LINENO" 5; }
++fi
++rm -f conftest conftest$ac_cv_exeext
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
++$as_echo "$ac_cv_exeext" >&6; }
++
++rm -f conftest.$ac_ext
++EXEEXT=$ac_cv_exeext
++ac_exeext=$EXEEXT
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <stdio.h>
++int
++main ()
++{
++FILE *f = fopen ("conftest.out", "w");
++ return ferror (f) || fclose (f) != 0;
++
++ ;
++ return 0;
++}
++_ACEOF
++ac_clean_files="$ac_clean_files conftest.out"
++# Check that the compiler produces executables we can run. If not, either
++# the compiler is broken, or we cross compile.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
++$as_echo_n "checking whether we are cross compiling... " >&6; }
++if test "$cross_compiling" != yes; then
++ { { ac_try="$ac_link"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_link") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }
++ if { ac_try='./conftest$ac_cv_exeext'
++ { { case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_try") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; }; then
++ cross_compiling=no
++ else
++ if test "$cross_compiling" = maybe; then
++ cross_compiling=yes
++ else
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "cannot run C compiled programs.
++If you meant to cross compile, use \`--host'.
++See \`config.log' for more details" "$LINENO" 5; }
++ fi
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
++$as_echo "$cross_compiling" >&6; }
++
++rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
++ac_clean_files=$ac_clean_files_save
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
++$as_echo_n "checking for suffix of object files... " >&6; }
++if ${ac_cv_objext+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++rm -f conftest.o conftest.obj
++if { { ac_try="$ac_compile"
++case "(($ac_try" in
++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
++ *) ac_try_echo=$ac_try;;
++esac
++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
++$as_echo "$ac_try_echo"; } >&5
++ (eval "$ac_compile") 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then :
++ for ac_file in conftest.o conftest.obj conftest.*; do
++ test -f "$ac_file" || continue;
++ case $ac_file in
++ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
++ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
++ break;;
++ esac
++done
++else
++ $as_echo "$as_me: failed program was:" >&5
++sed 's/^/| /' conftest.$ac_ext >&5
++
++{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "cannot compute suffix of object files: cannot compile
++See \`config.log' for more details" "$LINENO" 5; }
++fi
++rm -f conftest.$ac_cv_objext conftest.$ac_ext
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
++$as_echo "$ac_cv_objext" >&6; }
++OBJEXT=$ac_cv_objext
++ac_objext=$OBJEXT
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
++$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
++if ${ac_cv_c_compiler_gnu+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++#ifndef __GNUC__
++ choke me
++#endif
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ ac_compiler_gnu=yes
++else
++ ac_compiler_gnu=no
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++ac_cv_c_compiler_gnu=$ac_compiler_gnu
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
++$as_echo "$ac_cv_c_compiler_gnu" >&6; }
++if test $ac_compiler_gnu = yes; then
++ GCC=yes
++else
++ GCC=
++fi
++ac_test_CFLAGS=${CFLAGS+set}
++ac_save_CFLAGS=$CFLAGS
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
++$as_echo_n "checking whether $CC accepts -g... " >&6; }
++if ${ac_cv_prog_cc_g+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_save_c_werror_flag=$ac_c_werror_flag
++ ac_c_werror_flag=yes
++ ac_cv_prog_cc_g=no
++ CFLAGS="-g"
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ ac_cv_prog_cc_g=yes
++else
++ CFLAGS=""
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++
++else
++ ac_c_werror_flag=$ac_save_c_werror_flag
++ CFLAGS="-g"
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ ac_cv_prog_cc_g=yes
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++ ac_c_werror_flag=$ac_save_c_werror_flag
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
++$as_echo "$ac_cv_prog_cc_g" >&6; }
++if test "$ac_test_CFLAGS" = set; then
++ CFLAGS=$ac_save_CFLAGS
++elif test $ac_cv_prog_cc_g = yes; then
++ if test "$GCC" = yes; then
++ CFLAGS="-g -O2"
++ else
++ CFLAGS="-g"
++ fi
++else
++ if test "$GCC" = yes; then
++ CFLAGS="-O2"
++ else
++ CFLAGS=
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
++$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
++if ${ac_cv_prog_cc_c89+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_cv_prog_cc_c89=no
++ac_save_CC=$CC
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <stdarg.h>
++#include <stdio.h>
++struct stat;
++/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
++struct buf { int x; };
++FILE * (*rcsopen) (struct buf *, struct stat *, int);
++static char *e (p, i)
++ char **p;
++ int i;
++{
++ return p[i];
++}
++static char *f (char * (*g) (char **, int), char **p, ...)
++{
++ char *s;
++ va_list v;
++ va_start (v,p);
++ s = g (p, va_arg (v,int));
++ va_end (v);
++ return s;
++}
++
++/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
++ function prototypes and stuff, but not '\xHH' hex character constants.
++ These don't provoke an error unfortunately, instead are silently treated
++ as 'x'. The following induces an error, until -std is added to get
++ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
++ array size at least. It's necessary to write '\x00'==0 to get something
++ that's true only with -std. */
++int osf4_cc_array ['\x00' == 0 ? 1 : -1];
++
++/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
++ inside strings and character constants. */
++#define FOO(x) 'x'
++int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
++
++int test (int i, double x);
++struct s1 {int (*f) (int a);};
++struct s2 {int (*f) (double a);};
++int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
++int argc;
++char **argv;
++int
++main ()
++{
++return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
++ ;
++ return 0;
++}
++_ACEOF
++for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
++ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
++do
++ CC="$ac_save_CC $ac_arg"
++ if ac_fn_c_try_compile "$LINENO"; then :
++ ac_cv_prog_cc_c89=$ac_arg
++fi
++rm -f core conftest.err conftest.$ac_objext
++ test "x$ac_cv_prog_cc_c89" != "xno" && break
++done
++rm -f conftest.$ac_ext
++CC=$ac_save_CC
++
++fi
++# AC_CACHE_VAL
++case "x$ac_cv_prog_cc_c89" in
++ x)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
++$as_echo "none needed" >&6; } ;;
++ xno)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
++$as_echo "unsupported" >&6; } ;;
++ *)
++ CC="$CC $ac_cv_prog_cc_c89"
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
++$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
++esac
++if test "x$ac_cv_prog_cc_c89" != xno; then :
++
++fi
++
++ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++DEPDIR="${am__leading_dot}deps"
++
++ac_config_commands="$ac_config_commands depfiles"
++
++
++am_make=${MAKE-make}
++cat > confinc << 'END'
++am__doit:
++ @echo this is the am__doit target
++.PHONY: am__doit
++END
++# If we don't find an include directive, just comment out the code.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
++$as_echo_n "checking for style of include used by $am_make... " >&6; }
++am__include="#"
++am__quote=
++_am_result=none
++# First try GNU make style include.
++echo "include confinc" > confmf
++# Ignore all kinds of additional output from 'make'.
++case `$am_make -s -f confmf 2> /dev/null` in #(
++*the\ am__doit\ target*)
++ am__include=include
++ am__quote=
++ _am_result=GNU
++ ;;
++esac
++# Now try BSD make style include.
++if test "$am__include" = "#"; then
++ echo '.include "confinc"' > confmf
++ case `$am_make -s -f confmf 2> /dev/null` in #(
++ *the\ am__doit\ target*)
++ am__include=.include
++ am__quote="\""
++ _am_result=BSD
++ ;;
++ esac
++fi
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
++$as_echo "$_am_result" >&6; }
++rm -f confinc confmf
++
++# Check whether --enable-dependency-tracking was given.
++if test "${enable_dependency_tracking+set}" = set; then :
++ enableval=$enable_dependency_tracking;
++fi
++
++if test "x$enable_dependency_tracking" != xno; then
++ am_depcomp="$ac_aux_dir/depcomp"
++ AMDEPBACKSLASH='\'
++ am__nodep='_no'
++fi
++ if test "x$enable_dependency_tracking" != xno; then
++ AMDEP_TRUE=
++ AMDEP_FALSE='#'
++else
++ AMDEP_TRUE='#'
++ AMDEP_FALSE=
++fi
++
++
++
++depcc="$CC" am_compiler_list=
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
++$as_echo_n "checking dependency style of $depcc... " >&6; }
++if ${am_cv_CC_dependencies_compiler_type+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
++ # We make a subdir and do the tests there. Otherwise we can end up
++ # making bogus files that we don't know about and never remove. For
++ # instance it was reported that on HP-UX the gcc test will end up
++ # making a dummy file named 'D' -- because '-MD' means "put the output
++ # in D".
++ rm -rf conftest.dir
++ mkdir conftest.dir
++ # Copy depcomp to subdir because otherwise we won't find it if we're
++ # using a relative directory.
++ cp "$am_depcomp" conftest.dir
++ cd conftest.dir
++ # We will build objects and dependencies in a subdirectory because
++ # it helps to detect inapplicable dependency modes. For instance
++ # both Tru64's cc and ICC support -MD to output dependencies as a
++ # side effect of compilation, but ICC will put the dependencies in
++ # the current directory while Tru64 will put them in the object
++ # directory.
++ mkdir sub
++
++ am_cv_CC_dependencies_compiler_type=none
++ if test "$am_compiler_list" = ""; then
++ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
++ fi
++ am__universal=false
++ case " $depcc " in #(
++ *\ -arch\ *\ -arch\ *) am__universal=true ;;
++ esac
++
++ for depmode in $am_compiler_list; do
++ # Setup a source with many dependencies, because some compilers
++ # like to wrap large dependency lists on column 80 (with \), and
++ # we should not choose a depcomp mode which is confused by this.
++ #
++ # We need to recreate these files for each test, as the compiler may
++ # overwrite some of them when testing with obscure command lines.
++ # This happens at least with the AIX C compiler.
++ : > sub/conftest.c
++ for i in 1 2 3 4 5 6; do
++ echo '#include "conftst'$i'.h"' >> sub/conftest.c
++ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
++ # Solaris 10 /bin/sh.
++ echo '/* dummy */' > sub/conftst$i.h
++ done
++ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
++
++ # We check with '-c' and '-o' for the sake of the "dashmstdout"
++ # mode. It turns out that the SunPro C++ compiler does not properly
++ # handle '-M -o', and we need to detect this. Also, some Intel
++ # versions had trouble with output in subdirs.
++ am__obj=sub/conftest.${OBJEXT-o}
++ am__minus_obj="-o $am__obj"
++ case $depmode in
++ gcc)
++ # This depmode causes a compiler race in universal mode.
++ test "$am__universal" = false || continue
++ ;;
++ nosideeffect)
++ # After this tag, mechanisms are not by side-effect, so they'll
++ # only be used when explicitly requested.
++ if test "x$enable_dependency_tracking" = xyes; then
++ continue
++ else
++ break
++ fi
++ ;;
++ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
++ # This compiler won't grok '-c -o', but also, the minuso test has
++ # not run yet. These depmodes are late enough in the game, and
++ # so weak that their functioning should not be impacted.
++ am__obj=conftest.${OBJEXT-o}
++ am__minus_obj=
++ ;;
++ none) break ;;
++ esac
++ if depmode=$depmode \
++ source=sub/conftest.c object=$am__obj \
++ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
++ >/dev/null 2>conftest.err &&
++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
++ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
++ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
++ # icc doesn't choke on unknown options, it will just issue warnings
++ # or remarks (even with -Werror). So we grep stderr for any message
++ # that says an option was ignored or not supported.
++ # When given -MP, icc 7.0 and 7.1 complain thusly:
++ # icc: Command line warning: ignoring option '-M'; no argument required
++ # The diagnosis changed in icc 8.0:
++ # icc: Command line remark: option '-MP' not supported
++ if (grep 'ignoring option' conftest.err ||
++ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
++ am_cv_CC_dependencies_compiler_type=$depmode
++ break
++ fi
++ fi
++ done
++
++ cd ..
++ rm -rf conftest.dir
++else
++ am_cv_CC_dependencies_compiler_type=none
++fi
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
++$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
++CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
++
++ if
++ test "x$enable_dependency_tracking" != xno \
++ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
++ am__fastdepCC_TRUE=
++ am__fastdepCC_FALSE='#'
++else
++ am__fastdepCC_TRUE='#'
++ am__fastdepCC_FALSE=
++fi
++
++
++case `pwd` in
++ *\ * | *\ *)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
++$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
++esac
++
++
++
++macro_version='2.4.2'
++macro_revision='1.3337'
++
++
++
++
++
++
++
++
++
++
++
++
++
++ltmain="$ac_aux_dir/ltmain.sh"
++
++# Make sure we can run config.sub.
++$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
++ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
++$as_echo_n "checking build system type... " >&6; }
++if ${ac_cv_build+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_build_alias=$build_alias
++test "x$ac_build_alias" = x &&
++ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
++test "x$ac_build_alias" = x &&
++ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
++ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
++ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
++$as_echo "$ac_cv_build" >&6; }
++case $ac_cv_build in
++*-*-*) ;;
++*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
++esac
++build=$ac_cv_build
++ac_save_IFS=$IFS; IFS='-'
++set x $ac_cv_build
++shift
++build_cpu=$1
++build_vendor=$2
++shift; shift
++# Remember, the first character of IFS is used to create $*,
++# except with old shells:
++build_os=$*
++IFS=$ac_save_IFS
++case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
++$as_echo_n "checking host system type... " >&6; }
++if ${ac_cv_host+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test "x$host_alias" = x; then
++ ac_cv_host=$ac_cv_build
++else
++ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
++ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
++fi
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
++$as_echo "$ac_cv_host" >&6; }
++case $ac_cv_host in
++*-*-*) ;;
++*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
++esac
++host=$ac_cv_host
++ac_save_IFS=$IFS; IFS='-'
++set x $ac_cv_host
++shift
++host_cpu=$1
++host_vendor=$2
++shift; shift
++# Remember, the first character of IFS is used to create $*,
++# except with old shells:
++host_os=$*
++IFS=$ac_save_IFS
++case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
++
++
++# Backslashify metacharacters that are still active within
++# double-quoted strings.
++sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
++
++# Same as above, but do not quote variable references.
++double_quote_subst='s/\(["`\\]\)/\\\1/g'
++
++# Sed substitution to delay expansion of an escaped shell variable in a
++# double_quote_subst'ed string.
++delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
++
++# Sed substitution to delay expansion of an escaped single quote.
++delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
++
++# Sed substitution to avoid accidental globbing in evaled expressions
++no_glob_subst='s/\*/\\\*/g'
++
++ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
++ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
++$as_echo_n "checking how to print strings... " >&6; }
++# Test print first, because it will be a builtin if present.
++if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
++ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
++ ECHO='print -r --'
++elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
++ ECHO='printf %s\n'
++else
++ # Use this function as a fallback that always works.
++ func_fallback_echo ()
++ {
++ eval 'cat <<_LTECHO_EOF
++$1
++_LTECHO_EOF'
++ }
++ ECHO='func_fallback_echo'
++fi
++
++# func_echo_all arg...
++# Invoke $ECHO with all args, space-separated.
++func_echo_all ()
++{
++ $ECHO ""
++}
++
++case "$ECHO" in
++ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
++$as_echo "printf" >&6; } ;;
++ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
++$as_echo "print -r" >&6; } ;;
++ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
++$as_echo "cat" >&6; } ;;
++esac
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
++$as_echo_n "checking for a sed that does not truncate output... " >&6; }
++if ${ac_cv_path_SED+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
++ for ac_i in 1 2 3 4 5 6 7; do
++ ac_script="$ac_script$as_nl$ac_script"
++ done
++ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
++ { ac_script=; unset ac_script;}
++ if test -z "$SED"; then
++ ac_path_SED_found=false
++ # Loop through the user's path and test for each of PROGNAME-LIST
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_prog in sed gsed; do
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
++ as_fn_executable_p "$ac_path_SED" || continue
++# Check for GNU ac_path_SED and select it if it is found.
++ # Check for GNU $ac_path_SED
++case `"$ac_path_SED" --version 2>&1` in
++*GNU*)
++ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
++*)
++ ac_count=0
++ $as_echo_n 0123456789 >"conftest.in"
++ while :
++ do
++ cat "conftest.in" "conftest.in" >"conftest.tmp"
++ mv "conftest.tmp" "conftest.in"
++ cp "conftest.in" "conftest.nl"
++ $as_echo '' >> "conftest.nl"
++ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
++ as_fn_arith $ac_count + 1 && ac_count=$as_val
++ if test $ac_count -gt ${ac_path_SED_max-0}; then
++ # Best one so far, save it but keep looking for a better one
++ ac_cv_path_SED="$ac_path_SED"
++ ac_path_SED_max=$ac_count
++ fi
++ # 10*(2^10) chars as input seems more than enough
++ test $ac_count -gt 10 && break
++ done
++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
++esac
++
++ $ac_path_SED_found && break 3
++ done
++ done
++ done
++IFS=$as_save_IFS
++ if test -z "$ac_cv_path_SED"; then
++ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
++ fi
++else
++ ac_cv_path_SED=$SED
++fi
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
++$as_echo "$ac_cv_path_SED" >&6; }
++ SED="$ac_cv_path_SED"
++ rm -f conftest.sed
++
++test -z "$SED" && SED=sed
++Xsed="$SED -e 1s/^X//"
++
++
++
++
++
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
++$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
++if ${ac_cv_path_GREP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -z "$GREP"; then
++ ac_path_GREP_found=false
++ # Loop through the user's path and test for each of PROGNAME-LIST
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_prog in grep ggrep; do
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
++ as_fn_executable_p "$ac_path_GREP" || continue
++# Check for GNU ac_path_GREP and select it if it is found.
++ # Check for GNU $ac_path_GREP
++case `"$ac_path_GREP" --version 2>&1` in
++*GNU*)
++ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
++*)
++ ac_count=0
++ $as_echo_n 0123456789 >"conftest.in"
++ while :
++ do
++ cat "conftest.in" "conftest.in" >"conftest.tmp"
++ mv "conftest.tmp" "conftest.in"
++ cp "conftest.in" "conftest.nl"
++ $as_echo 'GREP' >> "conftest.nl"
++ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
++ as_fn_arith $ac_count + 1 && ac_count=$as_val
++ if test $ac_count -gt ${ac_path_GREP_max-0}; then
++ # Best one so far, save it but keep looking for a better one
++ ac_cv_path_GREP="$ac_path_GREP"
++ ac_path_GREP_max=$ac_count
++ fi
++ # 10*(2^10) chars as input seems more than enough
++ test $ac_count -gt 10 && break
++ done
++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
++esac
++
++ $ac_path_GREP_found && break 3
++ done
++ done
++ done
++IFS=$as_save_IFS
++ if test -z "$ac_cv_path_GREP"; then
++ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
++ fi
++else
++ ac_cv_path_GREP=$GREP
++fi
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
++$as_echo "$ac_cv_path_GREP" >&6; }
++ GREP="$ac_cv_path_GREP"
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
++$as_echo_n "checking for egrep... " >&6; }
++if ${ac_cv_path_EGREP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
++ then ac_cv_path_EGREP="$GREP -E"
++ else
++ if test -z "$EGREP"; then
++ ac_path_EGREP_found=false
++ # Loop through the user's path and test for each of PROGNAME-LIST
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_prog in egrep; do
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
++ as_fn_executable_p "$ac_path_EGREP" || continue
++# Check for GNU ac_path_EGREP and select it if it is found.
++ # Check for GNU $ac_path_EGREP
++case `"$ac_path_EGREP" --version 2>&1` in
++*GNU*)
++ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
++*)
++ ac_count=0
++ $as_echo_n 0123456789 >"conftest.in"
++ while :
++ do
++ cat "conftest.in" "conftest.in" >"conftest.tmp"
++ mv "conftest.tmp" "conftest.in"
++ cp "conftest.in" "conftest.nl"
++ $as_echo 'EGREP' >> "conftest.nl"
++ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
++ as_fn_arith $ac_count + 1 && ac_count=$as_val
++ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
++ # Best one so far, save it but keep looking for a better one
++ ac_cv_path_EGREP="$ac_path_EGREP"
++ ac_path_EGREP_max=$ac_count
++ fi
++ # 10*(2^10) chars as input seems more than enough
++ test $ac_count -gt 10 && break
++ done
++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
++esac
++
++ $ac_path_EGREP_found && break 3
++ done
++ done
++ done
++IFS=$as_save_IFS
++ if test -z "$ac_cv_path_EGREP"; then
++ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
++ fi
++else
++ ac_cv_path_EGREP=$EGREP
++fi
++
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
++$as_echo "$ac_cv_path_EGREP" >&6; }
++ EGREP="$ac_cv_path_EGREP"
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
++$as_echo_n "checking for fgrep... " >&6; }
++if ${ac_cv_path_FGREP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
++ then ac_cv_path_FGREP="$GREP -F"
++ else
++ if test -z "$FGREP"; then
++ ac_path_FGREP_found=false
++ # Loop through the user's path and test for each of PROGNAME-LIST
++ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_prog in fgrep; do
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
++ as_fn_executable_p "$ac_path_FGREP" || continue
++# Check for GNU ac_path_FGREP and select it if it is found.
++ # Check for GNU $ac_path_FGREP
++case `"$ac_path_FGREP" --version 2>&1` in
++*GNU*)
++ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
++*)
++ ac_count=0
++ $as_echo_n 0123456789 >"conftest.in"
++ while :
++ do
++ cat "conftest.in" "conftest.in" >"conftest.tmp"
++ mv "conftest.tmp" "conftest.in"
++ cp "conftest.in" "conftest.nl"
++ $as_echo 'FGREP' >> "conftest.nl"
++ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
++ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
++ as_fn_arith $ac_count + 1 && ac_count=$as_val
++ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
++ # Best one so far, save it but keep looking for a better one
++ ac_cv_path_FGREP="$ac_path_FGREP"
++ ac_path_FGREP_max=$ac_count
++ fi
++ # 10*(2^10) chars as input seems more than enough
++ test $ac_count -gt 10 && break
++ done
++ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
++esac
++
++ $ac_path_FGREP_found && break 3
++ done
++ done
++ done
++IFS=$as_save_IFS
++ if test -z "$ac_cv_path_FGREP"; then
++ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
++ fi
++else
++ ac_cv_path_FGREP=$FGREP
++fi
++
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
++$as_echo "$ac_cv_path_FGREP" >&6; }
++ FGREP="$ac_cv_path_FGREP"
++
++
++test -z "$GREP" && GREP=grep
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++# Check whether --with-gnu-ld was given.
++if test "${with_gnu_ld+set}" = set; then :
++ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
++else
++ with_gnu_ld=no
++fi
++
++ac_prog=ld
++if test "$GCC" = yes; then
++ # Check if gcc -print-prog-name=ld gives a path.
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
++$as_echo_n "checking for ld used by $CC... " >&6; }
++ case $host in
++ *-*-mingw*)
++ # gcc leaves a trailing carriage return which upsets mingw
++ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
++ *)
++ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
++ esac
++ case $ac_prog in
++ # Accept absolute paths.
++ [\\/]* | ?:[\\/]*)
++ re_direlt='/[^/][^/]*/\.\./'
++ # Canonicalize the pathname of ld
++ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
++ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
++ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
++ done
++ test -z "$LD" && LD="$ac_prog"
++ ;;
++ "")
++ # If it fails, then pretend we aren't using GCC.
++ ac_prog=ld
++ ;;
++ *)
++ # If it is relative, then search for the first ld in PATH.
++ with_gnu_ld=unknown
++ ;;
++ esac
++elif test "$with_gnu_ld" = yes; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
++$as_echo_n "checking for GNU ld... " >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
++$as_echo_n "checking for non-GNU ld... " >&6; }
++fi
++if ${lt_cv_path_LD+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -z "$LD"; then
++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++ for ac_dir in $PATH; do
++ IFS="$lt_save_ifs"
++ test -z "$ac_dir" && ac_dir=.
++ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
++ lt_cv_path_LD="$ac_dir/$ac_prog"
++ # Check to see if the program is GNU ld. I'd rather use --version,
++ # but apparently some variants of GNU ld only accept -v.
++ # Break only if it was the GNU/non-GNU ld that we prefer.
++ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
++ *GNU* | *'with BFD'*)
++ test "$with_gnu_ld" != no && break
++ ;;
++ *)
++ test "$with_gnu_ld" != yes && break
++ ;;
++ esac
++ fi
++ done
++ IFS="$lt_save_ifs"
++else
++ lt_cv_path_LD="$LD" # Let the user override the test with a path.
++fi
++fi
++
++LD="$lt_cv_path_LD"
++if test -n "$LD"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
++$as_echo "$LD" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
++$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
++if ${lt_cv_prog_gnu_ld+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ # I'd rather use --version here, but apparently some GNU lds only accept -v.
++case `$LD -v 2>&1 </dev/null` in
++*GNU* | *'with BFD'*)
++ lt_cv_prog_gnu_ld=yes
++ ;;
++*)
++ lt_cv_prog_gnu_ld=no
++ ;;
++esac
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
++$as_echo "$lt_cv_prog_gnu_ld" >&6; }
++with_gnu_ld=$lt_cv_prog_gnu_ld
++
++
++
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
++$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
++if ${lt_cv_path_NM+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$NM"; then
++ # Let the user override the test.
++ lt_cv_path_NM="$NM"
++else
++ lt_nm_to_check="${ac_tool_prefix}nm"
++ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
++ lt_nm_to_check="$lt_nm_to_check nm"
++ fi
++ for lt_tmp_nm in $lt_nm_to_check; do
++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
++ IFS="$lt_save_ifs"
++ test -z "$ac_dir" && ac_dir=.
++ tmp_nm="$ac_dir/$lt_tmp_nm"
++ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
++ # Check to see if the nm accepts a BSD-compat flag.
++ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
++ # nm: unknown option "B" ignored
++ # Tru64's nm complains that /dev/null is an invalid object file
++ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
++ */dev/null* | *'Invalid file or object type'*)
++ lt_cv_path_NM="$tmp_nm -B"
++ break
++ ;;
++ *)
++ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
++ */dev/null*)
++ lt_cv_path_NM="$tmp_nm -p"
++ break
++ ;;
++ *)
++ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
++ continue # so that we can try to find one that supports BSD flags
++ ;;
++ esac
++ ;;
++ esac
++ fi
++ done
++ IFS="$lt_save_ifs"
++ done
++ : ${lt_cv_path_NM=no}
++fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
++$as_echo "$lt_cv_path_NM" >&6; }
++if test "$lt_cv_path_NM" != "no"; then
++ NM="$lt_cv_path_NM"
++else
++ # Didn't find any BSD compatible name lister, look for dumpbin.
++ if test -n "$DUMPBIN"; then :
++ # Let the user override the test.
++ else
++ if test -n "$ac_tool_prefix"; then
++ for ac_prog in dumpbin "link -dump"
++ do
++ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
++set dummy $ac_tool_prefix$ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_DUMPBIN+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$DUMPBIN"; then
++ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++DUMPBIN=$ac_cv_prog_DUMPBIN
++if test -n "$DUMPBIN"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
++$as_echo "$DUMPBIN" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ test -n "$DUMPBIN" && break
++ done
++fi
++if test -z "$DUMPBIN"; then
++ ac_ct_DUMPBIN=$DUMPBIN
++ for ac_prog in dumpbin "link -dump"
++do
++ # Extract the first word of "$ac_prog", so it can be a program name with args.
++set dummy $ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_DUMPBIN"; then
++ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
++if test -n "$ac_ct_DUMPBIN"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
++$as_echo "$ac_ct_DUMPBIN" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ test -n "$ac_ct_DUMPBIN" && break
++done
++
++ if test "x$ac_ct_DUMPBIN" = x; then
++ DUMPBIN=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ DUMPBIN=$ac_ct_DUMPBIN
++ fi
++fi
++
++ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
++ *COFF*)
++ DUMPBIN="$DUMPBIN -symbols"
++ ;;
++ *)
++ DUMPBIN=:
++ ;;
++ esac
++ fi
++
++ if test "$DUMPBIN" != ":"; then
++ NM="$DUMPBIN"
++ fi
++fi
++test -z "$NM" && NM=nm
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
++$as_echo_n "checking the name lister ($NM) interface... " >&6; }
++if ${lt_cv_nm_interface+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_nm_interface="BSD nm"
++ echo "int some_variable = 0;" > conftest.$ac_ext
++ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
++ (eval "$ac_compile" 2>conftest.err)
++ cat conftest.err >&5
++ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
++ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
++ cat conftest.err >&5
++ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
++ cat conftest.out >&5
++ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
++ lt_cv_nm_interface="MS dumpbin"
++ fi
++ rm -f conftest*
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
++$as_echo "$lt_cv_nm_interface" >&6; }
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
++$as_echo_n "checking whether ln -s works... " >&6; }
++LN_S=$as_ln_s
++if test "$LN_S" = "ln -s"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
++$as_echo "no, using $LN_S" >&6; }
++fi
++
++# find the maximum length of command line arguments
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
++$as_echo_n "checking the maximum length of command line arguments... " >&6; }
++if ${lt_cv_sys_max_cmd_len+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ i=0
++ teststring="ABCD"
++
++ case $build_os in
++ msdosdjgpp*)
++ # On DJGPP, this test can blow up pretty badly due to problems in libc
++ # (any single argument exceeding 2000 bytes causes a buffer overrun
++ # during glob expansion). Even if it were fixed, the result of this
++ # check would be larger than it should be.
++ lt_cv_sys_max_cmd_len=12288; # 12K is about right
++ ;;
++
++ gnu*)
++ # Under GNU Hurd, this test is not required because there is
++ # no limit to the length of command line arguments.
++ # Libtool will interpret -1 as no limit whatsoever
++ lt_cv_sys_max_cmd_len=-1;
++ ;;
++
++ cygwin* | mingw* | cegcc*)
++ # On Win9x/ME, this test blows up -- it succeeds, but takes
++ # about 5 minutes as the teststring grows exponentially.
++ # Worse, since 9x/ME are not pre-emptively multitasking,
++ # you end up with a "frozen" computer, even though with patience
++ # the test eventually succeeds (with a max line length of 256k).
++ # Instead, let's just punt: use the minimum linelength reported by
++ # all of the supported platforms: 8192 (on NT/2K/XP).
++ lt_cv_sys_max_cmd_len=8192;
++ ;;
++
++ mint*)
++ # On MiNT this can take a long time and run out of memory.
++ lt_cv_sys_max_cmd_len=8192;
++ ;;
++
++ amigaos*)
++ # On AmigaOS with pdksh, this test takes hours, literally.
++ # So we just punt and use a minimum line length of 8192.
++ lt_cv_sys_max_cmd_len=8192;
++ ;;
++
++ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
++ # This has been around since 386BSD, at least. Likely further.
++ if test -x /sbin/sysctl; then
++ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
++ elif test -x /usr/sbin/sysctl; then
++ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
++ else
++ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
++ fi
++ # And add a safety zone
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
++ ;;
++
++ interix*)
++ # We know the value 262144 and hardcode it with a safety zone (like BSD)
++ lt_cv_sys_max_cmd_len=196608
++ ;;
++
++ os2*)
++ # The test takes a long time on OS/2.
++ lt_cv_sys_max_cmd_len=8192
++ ;;
++
++ osf*)
++ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
++ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
++ # nice to cause kernel panics so lets avoid the loop below.
++ # First set a reasonable default.
++ lt_cv_sys_max_cmd_len=16384
++ #
++ if test -x /sbin/sysconfig; then
++ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
++ *1*) lt_cv_sys_max_cmd_len=-1 ;;
++ esac
++ fi
++ ;;
++ sco3.2v5*)
++ lt_cv_sys_max_cmd_len=102400
++ ;;
++ sysv5* | sco5v6* | sysv4.2uw2*)
++ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
++ if test -n "$kargmax"; then
++ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
++ else
++ lt_cv_sys_max_cmd_len=32768
++ fi
++ ;;
++ *)
++ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
++ if test -n "$lt_cv_sys_max_cmd_len" && \
++ test undefined != "$lt_cv_sys_max_cmd_len"; then
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
++ else
++ # Make teststring a little bigger before we do anything with it.
++ # a 1K string should be a reasonable start.
++ for i in 1 2 3 4 5 6 7 8 ; do
++ teststring=$teststring$teststring
++ done
++ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
++ # If test is not a shell built-in, we'll probably end up computing a
++ # maximum length that is only half of the actual maximum length, but
++ # we can't tell.
++ while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
++ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
++ test $i != 17 # 1/2 MB should be enough
++ do
++ i=`expr $i + 1`
++ teststring=$teststring$teststring
++ done
++ # Only check the string length outside the loop.
++ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
++ teststring=
++ # Add a significant safety factor because C++ compilers can tack on
++ # massive amounts of additional arguments before passing them to the
++ # linker. It appears as though 1/2 is a usable value.
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
++ fi
++ ;;
++ esac
++
++fi
++
++if test -n $lt_cv_sys_max_cmd_len ; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
++$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
++$as_echo "none" >&6; }
++fi
++max_cmd_len=$lt_cv_sys_max_cmd_len
++
++
++
++
++
++
++: ${CP="cp -f"}
++: ${MV="mv -f"}
++: ${RM="rm -f"}
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
++$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
++# Try some XSI features
++xsi_shell=no
++( _lt_dummy="a/b/c"
++ test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
++ = c,a/b,b/c, \
++ && eval 'test $(( 1 + 1 )) -eq 2 \
++ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
++ && xsi_shell=yes
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
++$as_echo "$xsi_shell" >&6; }
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
++$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
++lt_shell_append=no
++( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
++ >/dev/null 2>&1 \
++ && lt_shell_append=yes
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
++$as_echo "$lt_shell_append" >&6; }
++
++
++if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
++ lt_unset=unset
++else
++ lt_unset=false
++fi
++
++
++
++
++
++# test EBCDIC or ASCII
++case `echo X|tr X '\101'` in
++ A) # ASCII based system
++ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
++ lt_SP2NL='tr \040 \012'
++ lt_NL2SP='tr \015\012 \040\040'
++ ;;
++ *) # EBCDIC based system
++ lt_SP2NL='tr \100 \n'
++ lt_NL2SP='tr \r\n \100\100'
++ ;;
++esac
++
++
++
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
++$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
++if ${lt_cv_to_host_file_cmd+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ case $host in
++ *-*-mingw* )
++ case $build in
++ *-*-mingw* ) # actually msys
++ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
++ ;;
++ *-*-cygwin* )
++ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
++ ;;
++ * ) # otherwise, assume *nix
++ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
++ ;;
++ esac
++ ;;
++ *-*-cygwin* )
++ case $build in
++ *-*-mingw* ) # actually msys
++ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
++ ;;
++ *-*-cygwin* )
++ lt_cv_to_host_file_cmd=func_convert_file_noop
++ ;;
++ * ) # otherwise, assume *nix
++ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
++ ;;
++ esac
++ ;;
++ * ) # unhandled hosts (and "normal" native builds)
++ lt_cv_to_host_file_cmd=func_convert_file_noop
++ ;;
++esac
++
++fi
++
++to_host_file_cmd=$lt_cv_to_host_file_cmd
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
++$as_echo "$lt_cv_to_host_file_cmd" >&6; }
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
++$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
++if ${lt_cv_to_tool_file_cmd+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ #assume ordinary cross tools, or native build.
++lt_cv_to_tool_file_cmd=func_convert_file_noop
++case $host in
++ *-*-mingw* )
++ case $build in
++ *-*-mingw* ) # actually msys
++ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
++ ;;
++ esac
++ ;;
++esac
++
++fi
++
++to_tool_file_cmd=$lt_cv_to_tool_file_cmd
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
++$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
++$as_echo_n "checking for $LD option to reload object files... " >&6; }
++if ${lt_cv_ld_reload_flag+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_ld_reload_flag='-r'
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
++$as_echo "$lt_cv_ld_reload_flag" >&6; }
++reload_flag=$lt_cv_ld_reload_flag
++case $reload_flag in
++"" | " "*) ;;
++*) reload_flag=" $reload_flag" ;;
++esac
++reload_cmds='$LD$reload_flag -o $output$reload_objs'
++case $host_os in
++ cygwin* | mingw* | pw32* | cegcc*)
++ if test "$GCC" != yes; then
++ reload_cmds=false
++ fi
++ ;;
++ darwin*)
++ if test "$GCC" = yes; then
++ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
++ else
++ reload_cmds='$LD$reload_flag -o $output$reload_objs'
++ fi
++ ;;
++esac
++
++
++
++
++
++
++
++
++
++if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
++set dummy ${ac_tool_prefix}objdump; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_OBJDUMP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$OBJDUMP"; then
++ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++OBJDUMP=$ac_cv_prog_OBJDUMP
++if test -n "$OBJDUMP"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
++$as_echo "$OBJDUMP" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_OBJDUMP"; then
++ ac_ct_OBJDUMP=$OBJDUMP
++ # Extract the first word of "objdump", so it can be a program name with args.
++set dummy objdump; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_OBJDUMP"; then
++ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_OBJDUMP="objdump"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
++if test -n "$ac_ct_OBJDUMP"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
++$as_echo "$ac_ct_OBJDUMP" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_OBJDUMP" = x; then
++ OBJDUMP="false"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ OBJDUMP=$ac_ct_OBJDUMP
++ fi
++else
++ OBJDUMP="$ac_cv_prog_OBJDUMP"
++fi
++
++test -z "$OBJDUMP" && OBJDUMP=objdump
++
++
++
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
++$as_echo_n "checking how to recognize dependent libraries... " >&6; }
++if ${lt_cv_deplibs_check_method+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_file_magic_cmd='$MAGIC_CMD'
++lt_cv_file_magic_test_file=
++lt_cv_deplibs_check_method='unknown'
++# Need to set the preceding variable on all platforms that support
++# interlibrary dependencies.
++# 'none' -- dependencies not supported.
++# `unknown' -- same as none, but documents that we really don't know.
++# 'pass_all' -- all dependencies passed with no checks.
++# 'test_compile' -- check by making test program.
++# 'file_magic [[regex]]' -- check by looking for files in library path
++# which responds to the $file_magic_cmd with a given extended regex.
++# If you have `file' or equivalent on your system and you're not sure
++# whether `pass_all' will *always* work, you probably want this one.
++
++case $host_os in
++aix[4-9]*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++beos*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++bsdi[45]*)
++ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
++ lt_cv_file_magic_cmd='/usr/bin/file -L'
++ lt_cv_file_magic_test_file=/shlib/libc.so
++ ;;
++
++cygwin*)
++ # func_win32_libid is a shell function defined in ltmain.sh
++ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
++ lt_cv_file_magic_cmd='func_win32_libid'
++ ;;
++
++mingw* | pw32*)
++ # Base MSYS/MinGW do not provide the 'file' command needed by
++ # func_win32_libid shell function, so use a weaker test based on 'objdump',
++ # unless we find 'file', for example because we are cross-compiling.
++ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
++ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
++ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
++ lt_cv_file_magic_cmd='func_win32_libid'
++ else
++ # Keep this pattern in sync with the one in func_win32_libid.
++ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
++ lt_cv_file_magic_cmd='$OBJDUMP -f'
++ fi
++ ;;
++
++cegcc*)
++ # use the weaker test based on 'objdump'. See mingw*.
++ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
++ lt_cv_file_magic_cmd='$OBJDUMP -f'
++ ;;
++
++darwin* | rhapsody*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++freebsd* | dragonfly*)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
++ case $host_cpu in
++ i*86 )
++ # Not sure whether the presence of OpenBSD here was a mistake.
++ # Let's accept both of them until this is cleared up.
++ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
++ lt_cv_file_magic_cmd=/usr/bin/file
++ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
++ ;;
++ esac
++ else
++ lt_cv_deplibs_check_method=pass_all
++ fi
++ ;;
++
++haiku*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++hpux10.20* | hpux11*)
++ lt_cv_file_magic_cmd=/usr/bin/file
++ case $host_cpu in
++ ia64*)
++ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
++ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
++ ;;
++ hppa*64*)
++ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
++ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
++ ;;
++ *)
++ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
++ lt_cv_file_magic_test_file=/usr/lib/libc.sl
++ ;;
++ esac
++ ;;
++
++interix[3-9]*)
++ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
++ ;;
++
++irix5* | irix6* | nonstopux*)
++ case $LD in
++ *-32|*"-32 ") libmagic=32-bit;;
++ *-n32|*"-n32 ") libmagic=N32;;
++ *-64|*"-64 ") libmagic=64-bit;;
++ *) libmagic=never-match;;
++ esac
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++# This must be glibc/ELF.
++linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++netbsd* | netbsdelf*-gnu)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
++ else
++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
++ fi
++ ;;
++
++newos6*)
++ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
++ lt_cv_file_magic_cmd=/usr/bin/file
++ lt_cv_file_magic_test_file=/usr/lib/libnls.so
++ ;;
++
++*nto* | *qnx*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++openbsd*)
++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
++ else
++ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
++ fi
++ ;;
++
++osf3* | osf4* | osf5*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++rdos*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++solaris*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++sysv4 | sysv4.3*)
++ case $host_vendor in
++ motorola)
++ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
++ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
++ ;;
++ ncr)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++ sequent)
++ lt_cv_file_magic_cmd='/bin/file'
++ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
++ ;;
++ sni)
++ lt_cv_file_magic_cmd='/bin/file'
++ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
++ lt_cv_file_magic_test_file=/lib/libc.so
++ ;;
++ siemens)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++ pc)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++ esac
++ ;;
++
++tpf*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++esac
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
++$as_echo "$lt_cv_deplibs_check_method" >&6; }
++
++file_magic_glob=
++want_nocaseglob=no
++if test "$build" = "$host"; then
++ case $host_os in
++ mingw* | pw32*)
++ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
++ want_nocaseglob=yes
++ else
++ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
++ fi
++ ;;
++ esac
++fi
++
++file_magic_cmd=$lt_cv_file_magic_cmd
++deplibs_check_method=$lt_cv_deplibs_check_method
++test -z "$deplibs_check_method" && deplibs_check_method=unknown
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
++set dummy ${ac_tool_prefix}dlltool; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_DLLTOOL+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$DLLTOOL"; then
++ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++DLLTOOL=$ac_cv_prog_DLLTOOL
++if test -n "$DLLTOOL"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
++$as_echo "$DLLTOOL" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_DLLTOOL"; then
++ ac_ct_DLLTOOL=$DLLTOOL
++ # Extract the first word of "dlltool", so it can be a program name with args.
++set dummy dlltool; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_DLLTOOL"; then
++ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
++if test -n "$ac_ct_DLLTOOL"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
++$as_echo "$ac_ct_DLLTOOL" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_DLLTOOL" = x; then
++ DLLTOOL="false"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ DLLTOOL=$ac_ct_DLLTOOL
++ fi
++else
++ DLLTOOL="$ac_cv_prog_DLLTOOL"
++fi
++
++test -z "$DLLTOOL" && DLLTOOL=dlltool
++
++
++
++
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
++$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
++if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_sharedlib_from_linklib_cmd='unknown'
++
++case $host_os in
++cygwin* | mingw* | pw32* | cegcc*)
++ # two different shell functions defined in ltmain.sh
++ # decide which to use based on capabilities of $DLLTOOL
++ case `$DLLTOOL --help 2>&1` in
++ *--identify-strict*)
++ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
++ ;;
++ *)
++ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
++ ;;
++ esac
++ ;;
++*)
++ # fallback: assume linklib IS sharedlib
++ lt_cv_sharedlib_from_linklib_cmd="$ECHO"
++ ;;
++esac
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
++$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
++sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
++test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
++
++
++
++
++
++
++
++
++if test -n "$ac_tool_prefix"; then
++ for ac_prog in ar
++ do
++ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
++set dummy $ac_tool_prefix$ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_AR+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$AR"; then
++ ac_cv_prog_AR="$AR" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++AR=$ac_cv_prog_AR
++if test -n "$AR"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
++$as_echo "$AR" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ test -n "$AR" && break
++ done
++fi
++if test -z "$AR"; then
++ ac_ct_AR=$AR
++ for ac_prog in ar
++do
++ # Extract the first word of "$ac_prog", so it can be a program name with args.
++set dummy $ac_prog; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_AR+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_AR"; then
++ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_AR="$ac_prog"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_AR=$ac_cv_prog_ac_ct_AR
++if test -n "$ac_ct_AR"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
++$as_echo "$ac_ct_AR" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ test -n "$ac_ct_AR" && break
++done
++
++ if test "x$ac_ct_AR" = x; then
++ AR="false"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ AR=$ac_ct_AR
++ fi
++fi
++
++: ${AR=ar}
++: ${AR_FLAGS=cru}
++
++
++
++
++
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
++$as_echo_n "checking for archiver @FILE support... " >&6; }
++if ${lt_cv_ar_at_file+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_ar_at_file=no
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ echo conftest.$ac_objext > conftest.lst
++ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
++ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
++ (eval $lt_ar_try) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }
++ if test "$ac_status" -eq 0; then
++ # Ensure the archiver fails upon bogus file names.
++ rm -f conftest.$ac_objext libconftest.a
++ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
++ (eval $lt_ar_try) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }
++ if test "$ac_status" -ne 0; then
++ lt_cv_ar_at_file=@
++ fi
++ fi
++ rm -f conftest.* libconftest.a
++
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
++$as_echo "$lt_cv_ar_at_file" >&6; }
++
++if test "x$lt_cv_ar_at_file" = xno; then
++ archiver_list_spec=
++else
++ archiver_list_spec=$lt_cv_ar_at_file
++fi
++
++
++
++
++
++
++
++if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
++set dummy ${ac_tool_prefix}strip; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_STRIP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$STRIP"; then
++ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++STRIP=$ac_cv_prog_STRIP
++if test -n "$STRIP"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
++$as_echo "$STRIP" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_STRIP"; then
++ ac_ct_STRIP=$STRIP
++ # Extract the first word of "strip", so it can be a program name with args.
++set dummy strip; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_STRIP"; then
++ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_STRIP="strip"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
++if test -n "$ac_ct_STRIP"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
++$as_echo "$ac_ct_STRIP" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_STRIP" = x; then
++ STRIP=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ STRIP=$ac_ct_STRIP
++ fi
++else
++ STRIP="$ac_cv_prog_STRIP"
++fi
++
++test -z "$STRIP" && STRIP=:
++
++
++
++
++
++
++if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
++set dummy ${ac_tool_prefix}ranlib; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_RANLIB+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$RANLIB"; then
++ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++RANLIB=$ac_cv_prog_RANLIB
++if test -n "$RANLIB"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
++$as_echo "$RANLIB" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_RANLIB"; then
++ ac_ct_RANLIB=$RANLIB
++ # Extract the first word of "ranlib", so it can be a program name with args.
++set dummy ranlib; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_RANLIB"; then
++ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_RANLIB="ranlib"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
++if test -n "$ac_ct_RANLIB"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
++$as_echo "$ac_ct_RANLIB" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_RANLIB" = x; then
++ RANLIB=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ RANLIB=$ac_ct_RANLIB
++ fi
++else
++ RANLIB="$ac_cv_prog_RANLIB"
++fi
++
++test -z "$RANLIB" && RANLIB=:
++
++
++
++
++
++
++# Determine commands to create old-style static archives.
++old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
++old_postinstall_cmds='chmod 644 $oldlib'
++old_postuninstall_cmds=
++
++if test -n "$RANLIB"; then
++ case $host_os in
++ openbsd*)
++ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
++ ;;
++ *)
++ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
++ ;;
++ esac
++ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
++fi
++
++case $host_os in
++ darwin*)
++ lock_old_archive_extraction=yes ;;
++ *)
++ lock_old_archive_extraction=no ;;
++esac
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++# If no C compiler was specified, use CC.
++LTCC=${LTCC-"$CC"}
++
++# If no C compiler flags were specified, use CFLAGS.
++LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
++
++# Allow CC to be a program name with arguments.
++compiler=$CC
++
++
++# Check for command to grab the raw symbol name followed by C symbol from nm.
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
++$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
++if ${lt_cv_sys_global_symbol_pipe+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++
++# These are sane defaults that work on at least a few old systems.
++# [They come from Ultrix. What could be older than Ultrix?!! ;)]
++
++# Character class describing NM global symbol codes.
++symcode='[BCDEGRST]'
++
++# Regexp to match symbols that can be accessed directly from C.
++sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
++
++# Define system-specific variables.
++case $host_os in
++aix*)
++ symcode='[BCDT]'
++ ;;
++cygwin* | mingw* | pw32* | cegcc*)
++ symcode='[ABCDGISTW]'
++ ;;
++hpux*)
++ if test "$host_cpu" = ia64; then
++ symcode='[ABCDEGRST]'
++ fi
++ ;;
++irix* | nonstopux*)
++ symcode='[BCDEGRST]'
++ ;;
++osf*)
++ symcode='[BCDEGQRST]'
++ ;;
++solaris*)
++ symcode='[BDRT]'
++ ;;
++sco3.2v5*)
++ symcode='[DT]'
++ ;;
++sysv4.2uw2*)
++ symcode='[DT]'
++ ;;
++sysv5* | sco5v6* | unixware* | OpenUNIX*)
++ symcode='[ABDT]'
++ ;;
++sysv4)
++ symcode='[DFNSTU]'
++ ;;
++esac
++
++# If we're using GNU nm, then use its standard symbol codes.
++case `$NM -V 2>&1` in
++*GNU* | *'with BFD'*)
++ symcode='[ABCDGIRSTW]' ;;
++esac
++
++# Transform an extracted symbol line into a proper C declaration.
++# Some systems (esp. on ia64) link data and code symbols differently,
++# so use this general approach.
++lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
++
++# Transform an extracted symbol line into symbol name and symbol address
++lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
++
++# Handle CRLF in mingw tool chain
++opt_cr=
++case $build_os in
++mingw*)
++ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
++ ;;
++esac
++
++# Try without a prefix underscore, then with it.
++for ac_symprfx in "" "_"; do
++
++ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
++ symxfrm="\\1 $ac_symprfx\\2 \\2"
++
++ # Write the raw and C identifiers.
++ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
++ # Fake it for dumpbin and say T for any non-static function
++ # and D for any global variable.
++ # Also find C++ and __fastcall symbols from MSVC++,
++ # which start with @ or ?.
++ lt_cv_sys_global_symbol_pipe="$AWK '"\
++" {last_section=section; section=\$ 3};"\
++" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
++" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
++" \$ 0!~/External *\|/{next};"\
++" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
++" {if(hide[section]) next};"\
++" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
++" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
++" s[1]~/^[@?]/{print s[1], s[1]; next};"\
++" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
++" ' prfx=^$ac_symprfx"
++ else
++ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
++ fi
++ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
++
++ # Check to see that the pipe works correctly.
++ pipe_works=no
++
++ rm -f conftest*
++ cat > conftest.$ac_ext <<_LT_EOF
++#ifdef __cplusplus
++extern "C" {
++#endif
++char nm_test_var;
++void nm_test_func(void);
++void nm_test_func(void){}
++#ifdef __cplusplus
++}
++#endif
++int main(){nm_test_var='a';nm_test_func();return(0);}
++_LT_EOF
++
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
++ (eval $ac_compile) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then
++ # Now try to grab the symbols.
++ nlist=conftest.nm
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
++ (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && test -s "$nlist"; then
++ # Try sorting and uniquifying the output.
++ if sort "$nlist" | uniq > "$nlist"T; then
++ mv -f "$nlist"T "$nlist"
++ else
++ rm -f "$nlist"T
++ fi
++
++ # Make sure that we snagged all the symbols we need.
++ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
++ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
++ cat <<_LT_EOF > conftest.$ac_ext
++/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
++#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
++/* DATA imports from DLLs on WIN32 con't be const, because runtime
++ relocations are performed -- see ld's documentation on pseudo-relocs. */
++# define LT_DLSYM_CONST
++#elif defined(__osf__)
++/* This system does not cope well with relocations in const data. */
++# define LT_DLSYM_CONST
++#else
++# define LT_DLSYM_CONST const
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++_LT_EOF
++ # Now generate the symbol file.
++ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
++
++ cat <<_LT_EOF >> conftest.$ac_ext
++
++/* The mapping between symbol names and symbols. */
++LT_DLSYM_CONST struct {
++ const char *name;
++ void *address;
++}
++lt__PROGRAM__LTX_preloaded_symbols[] =
++{
++ { "@PROGRAM@", (void *) 0 },
++_LT_EOF
++ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
++ cat <<\_LT_EOF >> conftest.$ac_ext
++ {0, (void *) 0}
++};
++
++/* This works around a problem in FreeBSD linker */
++#ifdef FREEBSD_WORKAROUND
++static const void *lt_preloaded_setup() {
++ return lt__PROGRAM__LTX_preloaded_symbols;
++}
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++_LT_EOF
++ # Now try linking the two files.
++ mv conftest.$ac_objext conftstm.$ac_objext
++ lt_globsym_save_LIBS=$LIBS
++ lt_globsym_save_CFLAGS=$CFLAGS
++ LIBS="conftstm.$ac_objext"
++ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
++ (eval $ac_link) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && test -s conftest${ac_exeext}; then
++ pipe_works=yes
++ fi
++ LIBS=$lt_globsym_save_LIBS
++ CFLAGS=$lt_globsym_save_CFLAGS
++ else
++ echo "cannot find nm_test_func in $nlist" >&5
++ fi
++ else
++ echo "cannot find nm_test_var in $nlist" >&5
++ fi
++ else
++ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
++ fi
++ else
++ echo "$progname: failed program was:" >&5
++ cat conftest.$ac_ext >&5
++ fi
++ rm -rf conftest* conftst*
++
++ # Do not use the global_symbol_pipe unless it works.
++ if test "$pipe_works" = yes; then
++ break
++ else
++ lt_cv_sys_global_symbol_pipe=
++ fi
++done
++
++fi
++
++if test -z "$lt_cv_sys_global_symbol_pipe"; then
++ lt_cv_sys_global_symbol_to_cdecl=
++fi
++if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
++$as_echo "failed" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
++$as_echo "ok" >&6; }
++fi
++
++# Response file support.
++if test "$lt_cv_nm_interface" = "MS dumpbin"; then
++ nm_file_list_spec='@'
++elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
++ nm_file_list_spec='@'
++fi
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
++$as_echo_n "checking for sysroot... " >&6; }
++
++# Check whether --with-sysroot was given.
++if test "${with_sysroot+set}" = set; then :
++ withval=$with_sysroot;
++else
++ with_sysroot=no
++fi
++
++
++lt_sysroot=
++case ${with_sysroot} in #(
++ yes)
++ if test "$GCC" = yes; then
++ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
++ fi
++ ;; #(
++ /*)
++ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
++ ;; #(
++ no|'')
++ ;; #(
++ *)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
++$as_echo "${with_sysroot}" >&6; }
++ as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
++ ;;
++esac
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
++$as_echo "${lt_sysroot:-no}" >&6; }
++
++
++
++
++
++# Check whether --enable-libtool-lock was given.
++if test "${enable_libtool_lock+set}" = set; then :
++ enableval=$enable_libtool_lock;
++fi
++
++test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
++
++# Some flags need to be propagated to the compiler or linker for good
++# libtool support.
++case $host in
++ia64-*-hpux*)
++ # Find out which ABI we are using.
++ echo 'int i;' > conftest.$ac_ext
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
++ (eval $ac_compile) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then
++ case `/usr/bin/file conftest.$ac_objext` in
++ *ELF-32*)
++ HPUX_IA64_MODE="32"
++ ;;
++ *ELF-64*)
++ HPUX_IA64_MODE="64"
++ ;;
++ esac
++ fi
++ rm -rf conftest*
++ ;;
++*-*-irix6*)
++ # Find out which ABI we are using.
++ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
++ (eval $ac_compile) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then
++ if test "$lt_cv_prog_gnu_ld" = yes; then
++ case `/usr/bin/file conftest.$ac_objext` in
++ *32-bit*)
++ LD="${LD-ld} -melf32bsmip"
++ ;;
++ *N32*)
++ LD="${LD-ld} -melf32bmipn32"
++ ;;
++ *64-bit*)
++ LD="${LD-ld} -melf64bmip"
++ ;;
++ esac
++ else
++ case `/usr/bin/file conftest.$ac_objext` in
++ *32-bit*)
++ LD="${LD-ld} -32"
++ ;;
++ *N32*)
++ LD="${LD-ld} -n32"
++ ;;
++ *64-bit*)
++ LD="${LD-ld} -64"
++ ;;
++ esac
++ fi
++ fi
++ rm -rf conftest*
++ ;;
++
++x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
++s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
++ # Find out which ABI we are using.
++ echo 'int i;' > conftest.$ac_ext
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
++ (eval $ac_compile) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then
++ case `/usr/bin/file conftest.o` in
++ *32-bit*)
++ case $host in
++ x86_64-*kfreebsd*-gnu)
++ LD="${LD-ld} -m elf_i386_fbsd"
++ ;;
++ x86_64-*linux*)
++ case `/usr/bin/file conftest.o` in
++ *x86-64*)
++ LD="${LD-ld} -m elf32_x86_64"
++ ;;
++ *)
++ LD="${LD-ld} -m elf_i386"
++ ;;
++ esac
++ ;;
++ ppc64-*linux*|powerpc64-*linux*)
++ LD="${LD-ld} -m elf32ppclinux"
++ ;;
++ s390x-*linux*)
++ LD="${LD-ld} -m elf_s390"
++ ;;
++ sparc64-*linux*)
++ LD="${LD-ld} -m elf32_sparc"
++ ;;
++ esac
++ ;;
++ *64-bit*)
++ case $host in
++ x86_64-*kfreebsd*-gnu)
++ LD="${LD-ld} -m elf_x86_64_fbsd"
++ ;;
++ x86_64-*linux*)
++ LD="${LD-ld} -m elf_x86_64"
++ ;;
++ ppc*-*linux*|powerpc*-*linux*)
++ LD="${LD-ld} -m elf64ppc"
++ ;;
++ s390*-*linux*|s390*-*tpf*)
++ LD="${LD-ld} -m elf64_s390"
++ ;;
++ sparc*-*linux*)
++ LD="${LD-ld} -m elf64_sparc"
++ ;;
++ esac
++ ;;
++ esac
++ fi
++ rm -rf conftest*
++ ;;
++
++*-*-sco3.2v5*)
++ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
++ SAVE_CFLAGS="$CFLAGS"
++ CFLAGS="$CFLAGS -belf"
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
++$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
++if ${lt_cv_cc_needs_belf+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ lt_cv_cc_needs_belf=yes
++else
++ lt_cv_cc_needs_belf=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
++$as_echo "$lt_cv_cc_needs_belf" >&6; }
++ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
++ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
++ CFLAGS="$SAVE_CFLAGS"
++ fi
++ ;;
++*-*solaris*)
++ # Find out which ABI we are using.
++ echo 'int i;' > conftest.$ac_ext
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
++ (eval $ac_compile) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }; then
++ case `/usr/bin/file conftest.o` in
++ *64-bit*)
++ case $lt_cv_prog_gnu_ld in
++ yes*)
++ case $host in
++ i?86-*-solaris*)
++ LD="${LD-ld} -m elf_x86_64"
++ ;;
++ sparc*-*-solaris*)
++ LD="${LD-ld} -m elf64_sparc"
++ ;;
++ esac
++ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
++ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
++ LD="${LD-ld}_sol2"
++ fi
++ ;;
++ *)
++ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
++ LD="${LD-ld} -64"
++ fi
++ ;;
++ esac
++ ;;
++ esac
++ fi
++ rm -rf conftest*
++ ;;
++esac
++
++need_locks="$enable_libtool_lock"
++
++if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
++set dummy ${ac_tool_prefix}mt; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$MANIFEST_TOOL"; then
++ ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
++if test -n "$MANIFEST_TOOL"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
++$as_echo "$MANIFEST_TOOL" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
++ ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
++ # Extract the first word of "mt", so it can be a program name with args.
++set dummy mt; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_MANIFEST_TOOL"; then
++ ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
++if test -n "$ac_ct_MANIFEST_TOOL"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
++$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_MANIFEST_TOOL" = x; then
++ MANIFEST_TOOL=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
++ fi
++else
++ MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
++fi
++
++test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
++$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
++if ${lt_cv_path_mainfest_tool+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_path_mainfest_tool=no
++ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
++ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
++ cat conftest.err >&5
++ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
++ lt_cv_path_mainfest_tool=yes
++ fi
++ rm -f conftest*
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
++$as_echo "$lt_cv_path_mainfest_tool" >&6; }
++if test "x$lt_cv_path_mainfest_tool" != xyes; then
++ MANIFEST_TOOL=:
++fi
++
++
++
++
++
++
++ case $host_os in
++ rhapsody* | darwin*)
++ if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
++set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_DSYMUTIL+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$DSYMUTIL"; then
++ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++DSYMUTIL=$ac_cv_prog_DSYMUTIL
++if test -n "$DSYMUTIL"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
++$as_echo "$DSYMUTIL" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_DSYMUTIL"; then
++ ac_ct_DSYMUTIL=$DSYMUTIL
++ # Extract the first word of "dsymutil", so it can be a program name with args.
++set dummy dsymutil; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_DSYMUTIL"; then
++ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
++if test -n "$ac_ct_DSYMUTIL"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
++$as_echo "$ac_ct_DSYMUTIL" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_DSYMUTIL" = x; then
++ DSYMUTIL=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ DSYMUTIL=$ac_ct_DSYMUTIL
++ fi
++else
++ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
++fi
++
++ if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
++set dummy ${ac_tool_prefix}nmedit; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_NMEDIT+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$NMEDIT"; then
++ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++NMEDIT=$ac_cv_prog_NMEDIT
++if test -n "$NMEDIT"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
++$as_echo "$NMEDIT" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_NMEDIT"; then
++ ac_ct_NMEDIT=$NMEDIT
++ # Extract the first word of "nmedit", so it can be a program name with args.
++set dummy nmedit; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_NMEDIT"; then
++ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_NMEDIT="nmedit"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
++if test -n "$ac_ct_NMEDIT"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
++$as_echo "$ac_ct_NMEDIT" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_NMEDIT" = x; then
++ NMEDIT=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ NMEDIT=$ac_ct_NMEDIT
++ fi
++else
++ NMEDIT="$ac_cv_prog_NMEDIT"
++fi
++
++ if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
++set dummy ${ac_tool_prefix}lipo; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_LIPO+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$LIPO"; then
++ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++LIPO=$ac_cv_prog_LIPO
++if test -n "$LIPO"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
++$as_echo "$LIPO" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_LIPO"; then
++ ac_ct_LIPO=$LIPO
++ # Extract the first word of "lipo", so it can be a program name with args.
++set dummy lipo; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_LIPO"; then
++ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_LIPO="lipo"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
++if test -n "$ac_ct_LIPO"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
++$as_echo "$ac_ct_LIPO" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_LIPO" = x; then
++ LIPO=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ LIPO=$ac_ct_LIPO
++ fi
++else
++ LIPO="$ac_cv_prog_LIPO"
++fi
++
++ if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
++set dummy ${ac_tool_prefix}otool; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_OTOOL+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$OTOOL"; then
++ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++OTOOL=$ac_cv_prog_OTOOL
++if test -n "$OTOOL"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
++$as_echo "$OTOOL" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_OTOOL"; then
++ ac_ct_OTOOL=$OTOOL
++ # Extract the first word of "otool", so it can be a program name with args.
++set dummy otool; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_OTOOL"; then
++ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_OTOOL="otool"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
++if test -n "$ac_ct_OTOOL"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
++$as_echo "$ac_ct_OTOOL" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_OTOOL" = x; then
++ OTOOL=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ OTOOL=$ac_ct_OTOOL
++ fi
++else
++ OTOOL="$ac_cv_prog_OTOOL"
++fi
++
++ if test -n "$ac_tool_prefix"; then
++ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
++set dummy ${ac_tool_prefix}otool64; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_OTOOL64+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$OTOOL64"; then
++ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++OTOOL64=$ac_cv_prog_OTOOL64
++if test -n "$OTOOL64"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
++$as_echo "$OTOOL64" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++fi
++if test -z "$ac_cv_prog_OTOOL64"; then
++ ac_ct_OTOOL64=$OTOOL64
++ # Extract the first word of "otool64", so it can be a program name with args.
++set dummy otool64; ac_word=$2
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
++$as_echo_n "checking for $ac_word... " >&6; }
++if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test -n "$ac_ct_OTOOL64"; then
++ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
++else
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
++ ac_cv_prog_ac_ct_OTOOL64="otool64"
++ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
++ break 2
++ fi
++done
++ done
++IFS=$as_save_IFS
++
++fi
++fi
++ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
++if test -n "$ac_ct_OTOOL64"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
++$as_echo "$ac_ct_OTOOL64" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++ if test "x$ac_ct_OTOOL64" = x; then
++ OTOOL64=":"
++ else
++ case $cross_compiling:$ac_tool_warned in
++yes:)
++{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
++$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
++ac_tool_warned=yes ;;
++esac
++ OTOOL64=$ac_ct_OTOOL64
++ fi
++else
++ OTOOL64="$ac_cv_prog_OTOOL64"
++fi
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
++$as_echo_n "checking for -single_module linker flag... " >&6; }
++if ${lt_cv_apple_cc_single_mod+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_apple_cc_single_mod=no
++ if test -z "${LT_MULTI_MODULE}"; then
++ # By default we will add the -single_module flag. You can override
++ # by either setting the environment variable LT_MULTI_MODULE
++ # non-empty at configure time, or by adding -multi_module to the
++ # link flags.
++ rm -rf libconftest.dylib*
++ echo "int foo(void){return 1;}" > conftest.c
++ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
++-dynamiclib -Wl,-single_module conftest.c" >&5
++ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
++ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
++ _lt_result=$?
++ # If there is a non-empty error log, and "single_module"
++ # appears in it, assume the flag caused a linker warning
++ if test -s conftest.err && $GREP single_module conftest.err; then
++ cat conftest.err >&5
++ # Otherwise, if the output was created with a 0 exit code from
++ # the compiler, it worked.
++ elif test -f libconftest.dylib && test $_lt_result -eq 0; then
++ lt_cv_apple_cc_single_mod=yes
++ else
++ cat conftest.err >&5
++ fi
++ rm -rf libconftest.dylib*
++ rm -f conftest.*
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
++$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
++$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
++if ${lt_cv_ld_exported_symbols_list+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_ld_exported_symbols_list=no
++ save_LDFLAGS=$LDFLAGS
++ echo "_main" > conftest.sym
++ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ lt_cv_ld_exported_symbols_list=yes
++else
++ lt_cv_ld_exported_symbols_list=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ LDFLAGS="$save_LDFLAGS"
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
++$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
++$as_echo_n "checking for -force_load linker flag... " >&6; }
++if ${lt_cv_ld_force_load+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_ld_force_load=no
++ cat > conftest.c << _LT_EOF
++int forced_loaded() { return 2;}
++_LT_EOF
++ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
++ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
++ echo "$AR cru libconftest.a conftest.o" >&5
++ $AR cru libconftest.a conftest.o 2>&5
++ echo "$RANLIB libconftest.a" >&5
++ $RANLIB libconftest.a 2>&5
++ cat > conftest.c << _LT_EOF
++int main() { return 0;}
++_LT_EOF
++ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
++ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
++ _lt_result=$?
++ if test -s conftest.err && $GREP force_load conftest.err; then
++ cat conftest.err >&5
++ elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
++ lt_cv_ld_force_load=yes
++ else
++ cat conftest.err >&5
++ fi
++ rm -f conftest.err libconftest.a conftest conftest.c
++ rm -rf conftest.dSYM
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
++$as_echo "$lt_cv_ld_force_load" >&6; }
++ case $host_os in
++ rhapsody* | darwin1.[012])
++ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
++ darwin1.*)
++ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
++ darwin*) # darwin 5.x on
++ # if running on 10.5 or later, the deployment target defaults
++ # to the OS version, if on x86, and 10.4, the deployment
++ # target defaults to 10.4. Don't you love it?
++ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
++ 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
++ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
++ 10.[012]*)
++ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
++ 10.*)
++ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
++ esac
++ ;;
++ esac
++ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
++ _lt_dar_single_mod='$single_module'
++ fi
++ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
++ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
++ else
++ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
++ fi
++ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
++ _lt_dsymutil='~$DSYMUTIL $lib || :'
++ else
++ _lt_dsymutil=
++ fi
++ ;;
++ esac
++
++ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
++$as_echo_n "checking how to run the C preprocessor... " >&6; }
++# On Suns, sometimes $CPP names a directory.
++if test -n "$CPP" && test -d "$CPP"; then
++ CPP=
++fi
++if test -z "$CPP"; then
++ if ${ac_cv_prog_CPP+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ # Double quotes because CPP needs to be expanded
++ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
++ do
++ ac_preproc_ok=false
++for ac_c_preproc_warn_flag in '' yes
++do
++ # Use a header file that comes with gcc, so configuring glibc
++ # with a fresh cross-compiler works.
++ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
++ # <limits.h> exists even on freestanding compilers.
++ # On the NeXT, cc -E runs the code through the compiler's parser,
++ # not just through cpp. "Syntax error" is here to catch this case.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#ifdef __STDC__
++# include <limits.h>
++#else
++# include <assert.h>
++#endif
++ Syntax error
++_ACEOF
++if ac_fn_c_try_cpp "$LINENO"; then :
++
++else
++ # Broken: fails on valid input.
++continue
++fi
++rm -f conftest.err conftest.i conftest.$ac_ext
++
++ # OK, works on sane cases. Now check whether nonexistent headers
++ # can be detected and how.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <ac_nonexistent.h>
++_ACEOF
++if ac_fn_c_try_cpp "$LINENO"; then :
++ # Broken: success on invalid input.
++continue
++else
++ # Passes both tests.
++ac_preproc_ok=:
++break
++fi
++rm -f conftest.err conftest.i conftest.$ac_ext
++
++done
++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
++rm -f conftest.i conftest.err conftest.$ac_ext
++if $ac_preproc_ok; then :
++ break
++fi
++
++ done
++ ac_cv_prog_CPP=$CPP
++
++fi
++ CPP=$ac_cv_prog_CPP
++else
++ ac_cv_prog_CPP=$CPP
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
++$as_echo "$CPP" >&6; }
++ac_preproc_ok=false
++for ac_c_preproc_warn_flag in '' yes
++do
++ # Use a header file that comes with gcc, so configuring glibc
++ # with a fresh cross-compiler works.
++ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
++ # <limits.h> exists even on freestanding compilers.
++ # On the NeXT, cc -E runs the code through the compiler's parser,
++ # not just through cpp. "Syntax error" is here to catch this case.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#ifdef __STDC__
++# include <limits.h>
++#else
++# include <assert.h>
++#endif
++ Syntax error
++_ACEOF
++if ac_fn_c_try_cpp "$LINENO"; then :
++
++else
++ # Broken: fails on valid input.
++continue
++fi
++rm -f conftest.err conftest.i conftest.$ac_ext
++
++ # OK, works on sane cases. Now check whether nonexistent headers
++ # can be detected and how.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <ac_nonexistent.h>
++_ACEOF
++if ac_fn_c_try_cpp "$LINENO"; then :
++ # Broken: success on invalid input.
++continue
++else
++ # Passes both tests.
++ac_preproc_ok=:
++break
++fi
++rm -f conftest.err conftest.i conftest.$ac_ext
++
++done
++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
++rm -f conftest.i conftest.err conftest.$ac_ext
++if $ac_preproc_ok; then :
++
++else
++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
++as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
++See \`config.log' for more details" "$LINENO" 5; }
++fi
++
++ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
++$as_echo_n "checking for ANSI C header files... " >&6; }
++if ${ac_cv_header_stdc+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <stdlib.h>
++#include <stdarg.h>
++#include <string.h>
++#include <float.h>
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ ac_cv_header_stdc=yes
++else
++ ac_cv_header_stdc=no
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++
++if test $ac_cv_header_stdc = yes; then
++ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <string.h>
++
++_ACEOF
++if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
++ $EGREP "memchr" >/dev/null 2>&1; then :
++
++else
++ ac_cv_header_stdc=no
++fi
++rm -f conftest*
++
++fi
++
++if test $ac_cv_header_stdc = yes; then
++ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <stdlib.h>
++
++_ACEOF
++if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
++ $EGREP "free" >/dev/null 2>&1; then :
++
++else
++ ac_cv_header_stdc=no
++fi
++rm -f conftest*
++
++fi
++
++if test $ac_cv_header_stdc = yes; then
++ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
++ if test "$cross_compiling" = yes; then :
++ :
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <ctype.h>
++#include <stdlib.h>
++#if ((' ' & 0x0FF) == 0x020)
++# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
++# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
++#else
++# define ISLOWER(c) \
++ (('a' <= (c) && (c) <= 'i') \
++ || ('j' <= (c) && (c) <= 'r') \
++ || ('s' <= (c) && (c) <= 'z'))
++# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
++#endif
++
++#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
++int
++main ()
++{
++ int i;
++ for (i = 0; i < 256; i++)
++ if (XOR (islower (i), ISLOWER (i))
++ || toupper (i) != TOUPPER (i))
++ return 2;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_run "$LINENO"; then :
++
++else
++ ac_cv_header_stdc=no
++fi
++rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
++ conftest.$ac_objext conftest.beam conftest.$ac_ext
++fi
++
++fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
++$as_echo "$ac_cv_header_stdc" >&6; }
++if test $ac_cv_header_stdc = yes; then
++
++$as_echo "#define STDC_HEADERS 1" >>confdefs.h
++
++fi
++
++# On IRIX 5.3, sys/types and inttypes.h are conflicting.
++for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
++ inttypes.h stdint.h unistd.h
++do :
++ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
++ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
++"
++if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
++ cat >>confdefs.h <<_ACEOF
++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
++_ACEOF
++
++fi
++
++done
++
++
++for ac_header in dlfcn.h
++do :
++ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
++"
++if test "x$ac_cv_header_dlfcn_h" = xyes; then :
++ cat >>confdefs.h <<_ACEOF
++#define HAVE_DLFCN_H 1
++_ACEOF
++
++fi
++
++done
++
++
++
++
++
++# Set options
++
++
++
++ enable_dlopen=no
++
++
++ enable_win32_dll=no
++
++
++ # Check whether --enable-shared was given.
++if test "${enable_shared+set}" = set; then :
++ enableval=$enable_shared; p=${PACKAGE-default}
++ case $enableval in
++ yes) enable_shared=yes ;;
++ no) enable_shared=no ;;
++ *)
++ enable_shared=no
++ # Look at the argument we got. We use all the common list separators.
++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
++ for pkg in $enableval; do
++ IFS="$lt_save_ifs"
++ if test "X$pkg" = "X$p"; then
++ enable_shared=yes
++ fi
++ done
++ IFS="$lt_save_ifs"
++ ;;
++ esac
++else
++ enable_shared=yes
++fi
++
++
++
++
++
++
++
++
++
++ # Check whether --enable-static was given.
++if test "${enable_static+set}" = set; then :
++ enableval=$enable_static; p=${PACKAGE-default}
++ case $enableval in
++ yes) enable_static=yes ;;
++ no) enable_static=no ;;
++ *)
++ enable_static=no
++ # Look at the argument we got. We use all the common list separators.
++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
++ for pkg in $enableval; do
++ IFS="$lt_save_ifs"
++ if test "X$pkg" = "X$p"; then
++ enable_static=yes
++ fi
++ done
++ IFS="$lt_save_ifs"
++ ;;
++ esac
++else
++ enable_static=yes
++fi
++
++
++
++
++
++
++
++
++
++
++# Check whether --with-pic was given.
++if test "${with_pic+set}" = set; then :
++ withval=$with_pic; lt_p=${PACKAGE-default}
++ case $withval in
++ yes|no) pic_mode=$withval ;;
++ *)
++ pic_mode=default
++ # Look at the argument we got. We use all the common list separators.
++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
++ for lt_pkg in $withval; do
++ IFS="$lt_save_ifs"
++ if test "X$lt_pkg" = "X$lt_p"; then
++ pic_mode=yes
++ fi
++ done
++ IFS="$lt_save_ifs"
++ ;;
++ esac
++else
++ pic_mode=default
++fi
++
++
++test -z "$pic_mode" && pic_mode=default
++
++
++
++
++
++
++
++ # Check whether --enable-fast-install was given.
++if test "${enable_fast_install+set}" = set; then :
++ enableval=$enable_fast_install; p=${PACKAGE-default}
++ case $enableval in
++ yes) enable_fast_install=yes ;;
++ no) enable_fast_install=no ;;
++ *)
++ enable_fast_install=no
++ # Look at the argument we got. We use all the common list separators.
++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
++ for pkg in $enableval; do
++ IFS="$lt_save_ifs"
++ if test "X$pkg" = "X$p"; then
++ enable_fast_install=yes
++ fi
++ done
++ IFS="$lt_save_ifs"
++ ;;
++ esac
++else
++ enable_fast_install=yes
++fi
++
++
++
++
++
++
++
++
++
++
++
++# This can be used to rebuild libtool when needed
++LIBTOOL_DEPS="$ltmain"
++
++# Always use our own libtool.
++LIBTOOL='$(SHELL) $(top_builddir)/libtool'
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++test -z "$LN_S" && LN_S="ln -s"
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++if test -n "${ZSH_VERSION+set}" ; then
++ setopt NO_GLOB_SUBST
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
++$as_echo_n "checking for objdir... " >&6; }
++if ${lt_cv_objdir+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ rm -f .libs 2>/dev/null
++mkdir .libs 2>/dev/null
++if test -d .libs; then
++ lt_cv_objdir=.libs
++else
++ # MS-DOS does not allow filenames that begin with a dot.
++ lt_cv_objdir=_libs
++fi
++rmdir .libs 2>/dev/null
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
++$as_echo "$lt_cv_objdir" >&6; }
++objdir=$lt_cv_objdir
++
++
++
++
++
++cat >>confdefs.h <<_ACEOF
++#define LT_OBJDIR "$lt_cv_objdir/"
++_ACEOF
++
++
++
++
++case $host_os in
++aix3*)
++ # AIX sometimes has problems with the GCC collect2 program. For some
++ # reason, if we set the COLLECT_NAMES environment variable, the problems
++ # vanish in a puff of smoke.
++ if test "X${COLLECT_NAMES+set}" != Xset; then
++ COLLECT_NAMES=
++ export COLLECT_NAMES
++ fi
++ ;;
++esac
++
++# Global variables:
++ofile=libtool
++can_build_shared=yes
++
++# All known linkers require a `.a' archive for static linking (except MSVC,
++# which needs '.lib').
++libext=a
++
++with_gnu_ld="$lt_cv_prog_gnu_ld"
++
++old_CC="$CC"
++old_CFLAGS="$CFLAGS"
++
++# Set sane defaults for various variables
++test -z "$CC" && CC=cc
++test -z "$LTCC" && LTCC=$CC
++test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
++test -z "$LD" && LD=ld
++test -z "$ac_objext" && ac_objext=o
++
++for cc_temp in $compiler""; do
++ case $cc_temp in
++ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
++ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
++ \-*) ;;
++ *) break;;
++ esac
++done
++cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
++
++
++# Only perform the check for file, if the check method requires it
++test -z "$MAGIC_CMD" && MAGIC_CMD=file
++case $deplibs_check_method in
++file_magic*)
++ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
++$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
++if ${lt_cv_path_MAGIC_CMD+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ case $MAGIC_CMD in
++[\\/*] | ?:[\\/]*)
++ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
++ ;;
++*)
++ lt_save_MAGIC_CMD="$MAGIC_CMD"
++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
++ for ac_dir in $ac_dummy; do
++ IFS="$lt_save_ifs"
++ test -z "$ac_dir" && ac_dir=.
++ if test -f $ac_dir/${ac_tool_prefix}file; then
++ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
++ if test -n "$file_magic_test_file"; then
++ case $deplibs_check_method in
++ "file_magic "*)
++ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
++ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
++ $EGREP "$file_magic_regex" > /dev/null; then
++ :
++ else
++ cat <<_LT_EOF 1>&2
++
++*** Warning: the command libtool uses to detect shared libraries,
++*** $file_magic_cmd, produces output that libtool cannot recognize.
++*** The result is that libtool may fail to recognize shared libraries
++*** as such. This will affect the creation of libtool libraries that
++*** depend on shared libraries, but programs linked with such libtool
++*** libraries will work regardless of this problem. Nevertheless, you
++*** may want to report the problem to your system manager and/or to
++*** bug-libtool@gnu.org
++
++_LT_EOF
++ fi ;;
++ esac
++ fi
++ break
++ fi
++ done
++ IFS="$lt_save_ifs"
++ MAGIC_CMD="$lt_save_MAGIC_CMD"
++ ;;
++esac
++fi
++
++MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++if test -n "$MAGIC_CMD"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
++$as_echo "$MAGIC_CMD" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++
++
++
++if test -z "$lt_cv_path_MAGIC_CMD"; then
++ if test -n "$ac_tool_prefix"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
++$as_echo_n "checking for file... " >&6; }
++if ${lt_cv_path_MAGIC_CMD+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ case $MAGIC_CMD in
++[\\/*] | ?:[\\/]*)
++ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
++ ;;
++*)
++ lt_save_MAGIC_CMD="$MAGIC_CMD"
++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
++ for ac_dir in $ac_dummy; do
++ IFS="$lt_save_ifs"
++ test -z "$ac_dir" && ac_dir=.
++ if test -f $ac_dir/file; then
++ lt_cv_path_MAGIC_CMD="$ac_dir/file"
++ if test -n "$file_magic_test_file"; then
++ case $deplibs_check_method in
++ "file_magic "*)
++ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
++ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
++ $EGREP "$file_magic_regex" > /dev/null; then
++ :
++ else
++ cat <<_LT_EOF 1>&2
++
++*** Warning: the command libtool uses to detect shared libraries,
++*** $file_magic_cmd, produces output that libtool cannot recognize.
++*** The result is that libtool may fail to recognize shared libraries
++*** as such. This will affect the creation of libtool libraries that
++*** depend on shared libraries, but programs linked with such libtool
++*** libraries will work regardless of this problem. Nevertheless, you
++*** may want to report the problem to your system manager and/or to
++*** bug-libtool@gnu.org
++
++_LT_EOF
++ fi ;;
++ esac
++ fi
++ break
++ fi
++ done
++ IFS="$lt_save_ifs"
++ MAGIC_CMD="$lt_save_MAGIC_CMD"
++ ;;
++esac
++fi
++
++MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++if test -n "$MAGIC_CMD"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
++$as_echo "$MAGIC_CMD" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
++ else
++ MAGIC_CMD=:
++ fi
++fi
++
++ fi
++ ;;
++esac
++
++# Use C for the default configuration in the libtool script
++
++lt_save_CC="$CC"
++ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++
++
++# Source file extension for C test sources.
++ac_ext=c
++
++# Object file extension for compiled C test sources.
++objext=o
++objext=$objext
++
++# Code to be used in simple compile tests
++lt_simple_compile_test_code="int some_variable = 0;"
++
++# Code to be used in simple link tests
++lt_simple_link_test_code='int main(){return(0);}'
++
++
++
++
++
++
++
++# If no C compiler was specified, use CC.
++LTCC=${LTCC-"$CC"}
++
++# If no C compiler flags were specified, use CFLAGS.
++LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
++
++# Allow CC to be a program name with arguments.
++compiler=$CC
++
++# Save the default compiler, since it gets overwritten when the other
++# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
++compiler_DEFAULT=$CC
++
++# save warnings/boilerplate of simple test code
++ac_outfile=conftest.$ac_objext
++echo "$lt_simple_compile_test_code" >conftest.$ac_ext
++eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
++_lt_compiler_boilerplate=`cat conftest.err`
++$RM conftest*
++
++ac_outfile=conftest.$ac_objext
++echo "$lt_simple_link_test_code" >conftest.$ac_ext
++eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
++_lt_linker_boilerplate=`cat conftest.err`
++$RM -r conftest*
++
++
++## CAVEAT EMPTOR:
++## There is no encapsulation within the following macros, do not change
++## the running order or otherwise move them around unless you know exactly
++## what you are doing...
++if test -n "$compiler"; then
++
++lt_prog_compiler_no_builtin_flag=
++
++if test "$GCC" = yes; then
++ case $cc_basename in
++ nvcc*)
++ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
++ *)
++ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
++ esac
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
++$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
++if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_prog_compiler_rtti_exceptions=no
++ ac_outfile=conftest.$ac_objext
++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++ lt_compiler_flag="-fno-rtti -fno-exceptions"
++ # Insert the option either (1) after the last *FLAGS variable, or
++ # (2) before a word containing "conftest.", or (3) at the end.
++ # Note that $ac_compile itself does not contain backslashes and begins
++ # with a dollar sign (not a hyphen), so the echo should work correctly.
++ # The option is referenced via a variable to avoid confusing sed.
++ lt_compile=`echo "$ac_compile" | $SED \
++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
++ -e 's:$: $lt_compiler_flag:'`
++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
++ (eval "$lt_compile" 2>conftest.err)
++ ac_status=$?
++ cat conftest.err >&5
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ if (exit $ac_status) && test -s "$ac_outfile"; then
++ # The compiler can only warn and ignore the option if not recognized
++ # So say no if there are warnings other than the usual output.
++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
++ lt_cv_prog_compiler_rtti_exceptions=yes
++ fi
++ fi
++ $RM conftest*
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
++$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
++
++if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
++ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
++else
++ :
++fi
++
++fi
++
++
++
++
++
++
++ lt_prog_compiler_wl=
++lt_prog_compiler_pic=
++lt_prog_compiler_static=
++
++
++ if test "$GCC" = yes; then
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_static='-static'
++
++ case $host_os in
++ aix*)
++ # All AIX code is PIC.
++ if test "$host_cpu" = ia64; then
++ # AIX 5 now supports IA64 processor
++ lt_prog_compiler_static='-Bstatic'
++ fi
++ ;;
++
++ amigaos*)
++ case $host_cpu in
++ powerpc)
++ # see comment about AmigaOS4 .so support
++ lt_prog_compiler_pic='-fPIC'
++ ;;
++ m68k)
++ # FIXME: we need at least 68020 code to build shared libraries, but
++ # adding the `-m68020' flag to GCC prevents building anything better,
++ # like `-m68040'.
++ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
++ ;;
++ esac
++ ;;
++
++ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
++ # PIC is the default for these OSes.
++ ;;
++
++ mingw* | cygwin* | pw32* | os2* | cegcc*)
++ # This hack is so that the source file can tell whether it is being
++ # built for inclusion in a dll (and should export symbols for example).
++ # Although the cygwin gcc ignores -fPIC, still need this for old-style
++ # (--disable-auto-import) libraries
++ lt_prog_compiler_pic='-DDLL_EXPORT'
++ ;;
++
++ darwin* | rhapsody*)
++ # PIC is the default on this platform
++ # Common symbols not allowed in MH_DYLIB files
++ lt_prog_compiler_pic='-fno-common'
++ ;;
++
++ haiku*)
++ # PIC is the default for Haiku.
++ # The "-static" flag exists, but is broken.
++ lt_prog_compiler_static=
++ ;;
++
++ hpux*)
++ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
++ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
++ # sets the default TLS model and affects inlining.
++ case $host_cpu in
++ hppa*64*)
++ # +Z the default
++ ;;
++ *)
++ lt_prog_compiler_pic='-fPIC'
++ ;;
++ esac
++ ;;
++
++ interix[3-9]*)
++ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++ # Instead, we relocate shared libraries at runtime.
++ ;;
++
++ msdosdjgpp*)
++ # Just because we use GCC doesn't mean we suddenly get shared libraries
++ # on systems that don't support them.
++ lt_prog_compiler_can_build_shared=no
++ enable_shared=no
++ ;;
++
++ *nto* | *qnx*)
++ # QNX uses GNU C++, but need to define -shared option too, otherwise
++ # it will coredump.
++ lt_prog_compiler_pic='-fPIC -shared'
++ ;;
++
++ sysv4*MP*)
++ if test -d /usr/nec; then
++ lt_prog_compiler_pic=-Kconform_pic
++ fi
++ ;;
++
++ *)
++ lt_prog_compiler_pic='-fPIC'
++ ;;
++ esac
++
++ case $cc_basename in
++ nvcc*) # Cuda Compiler Driver 2.2
++ lt_prog_compiler_wl='-Xlinker '
++ if test -n "$lt_prog_compiler_pic"; then
++ lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
++ fi
++ ;;
++ esac
++ else
++ # PORTME Check for flag to pass linker flags through the system compiler.
++ case $host_os in
++ aix*)
++ lt_prog_compiler_wl='-Wl,'
++ if test "$host_cpu" = ia64; then
++ # AIX 5 now supports IA64 processor
++ lt_prog_compiler_static='-Bstatic'
++ else
++ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
++ fi
++ ;;
++
++ mingw* | cygwin* | pw32* | os2* | cegcc*)
++ # This hack is so that the source file can tell whether it is being
++ # built for inclusion in a dll (and should export symbols for example).
++ lt_prog_compiler_pic='-DDLL_EXPORT'
++ ;;
++
++ hpux9* | hpux10* | hpux11*)
++ lt_prog_compiler_wl='-Wl,'
++ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
++ # not for PA HP-UX.
++ case $host_cpu in
++ hppa*64*|ia64*)
++ # +Z the default
++ ;;
++ *)
++ lt_prog_compiler_pic='+Z'
++ ;;
++ esac
++ # Is there a better lt_prog_compiler_static that works with the bundled CC?
++ lt_prog_compiler_static='${wl}-a ${wl}archive'
++ ;;
++
++ irix5* | irix6* | nonstopux*)
++ lt_prog_compiler_wl='-Wl,'
++ # PIC (with -KPIC) is the default.
++ lt_prog_compiler_static='-non_shared'
++ ;;
++
++ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
++ case $cc_basename in
++ # old Intel for x86_64 which still supported -KPIC.
++ ecc*)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='-KPIC'
++ lt_prog_compiler_static='-static'
++ ;;
++ # icc used to be incompatible with GCC.
++ # ICC 10 doesn't accept -KPIC any more.
++ icc* | ifort*)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='-fPIC'
++ lt_prog_compiler_static='-static'
++ ;;
++ # Lahey Fortran 8.1.
++ lf95*)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='--shared'
++ lt_prog_compiler_static='--static'
++ ;;
++ nagfor*)
++ # NAG Fortran compiler
++ lt_prog_compiler_wl='-Wl,-Wl,,'
++ lt_prog_compiler_pic='-PIC'
++ lt_prog_compiler_static='-Bstatic'
++ ;;
++ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
++ # Portland Group compilers (*not* the Pentium gcc compiler,
++ # which looks to be a dead project)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='-fpic'
++ lt_prog_compiler_static='-Bstatic'
++ ;;
++ ccc*)
++ lt_prog_compiler_wl='-Wl,'
++ # All Alpha code is PIC.
++ lt_prog_compiler_static='-non_shared'
++ ;;
++ xl* | bgxl* | bgf* | mpixl*)
++ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='-qpic'
++ lt_prog_compiler_static='-qstaticlink'
++ ;;
++ *)
++ case `$CC -V 2>&1 | sed 5q` in
++ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
++ # Sun Fortran 8.3 passes all unrecognized flags to the linker
++ lt_prog_compiler_pic='-KPIC'
++ lt_prog_compiler_static='-Bstatic'
++ lt_prog_compiler_wl=''
++ ;;
++ *Sun\ F* | *Sun*Fortran*)
++ lt_prog_compiler_pic='-KPIC'
++ lt_prog_compiler_static='-Bstatic'
++ lt_prog_compiler_wl='-Qoption ld '
++ ;;
++ *Sun\ C*)
++ # Sun C 5.9
++ lt_prog_compiler_pic='-KPIC'
++ lt_prog_compiler_static='-Bstatic'
++ lt_prog_compiler_wl='-Wl,'
++ ;;
++ *Intel*\ [CF]*Compiler*)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='-fPIC'
++ lt_prog_compiler_static='-static'
++ ;;
++ *Portland\ Group*)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='-fpic'
++ lt_prog_compiler_static='-Bstatic'
++ ;;
++ esac
++ ;;
++ esac
++ ;;
++
++ newsos6)
++ lt_prog_compiler_pic='-KPIC'
++ lt_prog_compiler_static='-Bstatic'
++ ;;
++
++ *nto* | *qnx*)
++ # QNX uses GNU C++, but need to define -shared option too, otherwise
++ # it will coredump.
++ lt_prog_compiler_pic='-fPIC -shared'
++ ;;
++
++ osf3* | osf4* | osf5*)
++ lt_prog_compiler_wl='-Wl,'
++ # All OSF/1 code is PIC.
++ lt_prog_compiler_static='-non_shared'
++ ;;
++
++ rdos*)
++ lt_prog_compiler_static='-non_shared'
++ ;;
++
++ solaris*)
++ lt_prog_compiler_pic='-KPIC'
++ lt_prog_compiler_static='-Bstatic'
++ case $cc_basename in
++ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
++ lt_prog_compiler_wl='-Qoption ld ';;
++ *)
++ lt_prog_compiler_wl='-Wl,';;
++ esac
++ ;;
++
++ sunos4*)
++ lt_prog_compiler_wl='-Qoption ld '
++ lt_prog_compiler_pic='-PIC'
++ lt_prog_compiler_static='-Bstatic'
++ ;;
++
++ sysv4 | sysv4.2uw2* | sysv4.3*)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='-KPIC'
++ lt_prog_compiler_static='-Bstatic'
++ ;;
++
++ sysv4*MP*)
++ if test -d /usr/nec ;then
++ lt_prog_compiler_pic='-Kconform_pic'
++ lt_prog_compiler_static='-Bstatic'
++ fi
++ ;;
++
++ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_pic='-KPIC'
++ lt_prog_compiler_static='-Bstatic'
++ ;;
++
++ unicos*)
++ lt_prog_compiler_wl='-Wl,'
++ lt_prog_compiler_can_build_shared=no
++ ;;
++
++ uts4*)
++ lt_prog_compiler_pic='-pic'
++ lt_prog_compiler_static='-Bstatic'
++ ;;
++
++ *)
++ lt_prog_compiler_can_build_shared=no
++ ;;
++ esac
++ fi
++
++case $host_os in
++ # For platforms which do not support PIC, -DPIC is meaningless:
++ *djgpp*)
++ lt_prog_compiler_pic=
++ ;;
++ *)
++ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
++ ;;
++esac
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
++$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
++if ${lt_cv_prog_compiler_pic+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
++$as_echo "$lt_cv_prog_compiler_pic" >&6; }
++lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
++
++#
++# Check to make sure the PIC flag actually works.
++#
++if test -n "$lt_prog_compiler_pic"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
++$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
++if ${lt_cv_prog_compiler_pic_works+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_prog_compiler_pic_works=no
++ ac_outfile=conftest.$ac_objext
++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
++ # Insert the option either (1) after the last *FLAGS variable, or
++ # (2) before a word containing "conftest.", or (3) at the end.
++ # Note that $ac_compile itself does not contain backslashes and begins
++ # with a dollar sign (not a hyphen), so the echo should work correctly.
++ # The option is referenced via a variable to avoid confusing sed.
++ lt_compile=`echo "$ac_compile" | $SED \
++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
++ -e 's:$: $lt_compiler_flag:'`
++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
++ (eval "$lt_compile" 2>conftest.err)
++ ac_status=$?
++ cat conftest.err >&5
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ if (exit $ac_status) && test -s "$ac_outfile"; then
++ # The compiler can only warn and ignore the option if not recognized
++ # So say no if there are warnings other than the usual output.
++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
++ lt_cv_prog_compiler_pic_works=yes
++ fi
++ fi
++ $RM conftest*
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
++$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
++
++if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
++ case $lt_prog_compiler_pic in
++ "" | " "*) ;;
++ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
++ esac
++else
++ lt_prog_compiler_pic=
++ lt_prog_compiler_can_build_shared=no
++fi
++
++fi
++
++
++
++
++
++
++
++
++
++
++
++#
++# Check to make sure the static flag actually works.
++#
++wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
++$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
++if ${lt_cv_prog_compiler_static_works+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_prog_compiler_static_works=no
++ save_LDFLAGS="$LDFLAGS"
++ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
++ echo "$lt_simple_link_test_code" > conftest.$ac_ext
++ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
++ # The linker can only warn and ignore the option if not recognized
++ # So say no if there are warnings
++ if test -s conftest.err; then
++ # Append any errors to the config.log.
++ cat conftest.err 1>&5
++ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++ if diff conftest.exp conftest.er2 >/dev/null; then
++ lt_cv_prog_compiler_static_works=yes
++ fi
++ else
++ lt_cv_prog_compiler_static_works=yes
++ fi
++ fi
++ $RM -r conftest*
++ LDFLAGS="$save_LDFLAGS"
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
++$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
++
++if test x"$lt_cv_prog_compiler_static_works" = xyes; then
++ :
++else
++ lt_prog_compiler_static=
++fi
++
++
++
++
++
++
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
++$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
++if ${lt_cv_prog_compiler_c_o+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_prog_compiler_c_o=no
++ $RM -r conftest 2>/dev/null
++ mkdir conftest
++ cd conftest
++ mkdir out
++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++
++ lt_compiler_flag="-o out/conftest2.$ac_objext"
++ # Insert the option either (1) after the last *FLAGS variable, or
++ # (2) before a word containing "conftest.", or (3) at the end.
++ # Note that $ac_compile itself does not contain backslashes and begins
++ # with a dollar sign (not a hyphen), so the echo should work correctly.
++ lt_compile=`echo "$ac_compile" | $SED \
++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
++ -e 's:$: $lt_compiler_flag:'`
++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
++ (eval "$lt_compile" 2>out/conftest.err)
++ ac_status=$?
++ cat out/conftest.err >&5
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ if (exit $ac_status) && test -s out/conftest2.$ac_objext
++ then
++ # The compiler can only warn and ignore the option if not recognized
++ # So say no if there are warnings
++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
++ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
++ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
++ lt_cv_prog_compiler_c_o=yes
++ fi
++ fi
++ chmod u+w . 2>&5
++ $RM conftest*
++ # SGI C++ compiler will create directory out/ii_files/ for
++ # template instantiation
++ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
++ $RM out/* && rmdir out
++ cd ..
++ $RM -r conftest
++ $RM conftest*
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
++$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
++
++
++
++
++
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
++$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
++if ${lt_cv_prog_compiler_c_o+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_prog_compiler_c_o=no
++ $RM -r conftest 2>/dev/null
++ mkdir conftest
++ cd conftest
++ mkdir out
++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++
++ lt_compiler_flag="-o out/conftest2.$ac_objext"
++ # Insert the option either (1) after the last *FLAGS variable, or
++ # (2) before a word containing "conftest.", or (3) at the end.
++ # Note that $ac_compile itself does not contain backslashes and begins
++ # with a dollar sign (not a hyphen), so the echo should work correctly.
++ lt_compile=`echo "$ac_compile" | $SED \
++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
++ -e 's:$: $lt_compiler_flag:'`
++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
++ (eval "$lt_compile" 2>out/conftest.err)
++ ac_status=$?
++ cat out/conftest.err >&5
++ echo "$as_me:$LINENO: \$? = $ac_status" >&5
++ if (exit $ac_status) && test -s out/conftest2.$ac_objext
++ then
++ # The compiler can only warn and ignore the option if not recognized
++ # So say no if there are warnings
++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
++ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
++ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
++ lt_cv_prog_compiler_c_o=yes
++ fi
++ fi
++ chmod u+w . 2>&5
++ $RM conftest*
++ # SGI C++ compiler will create directory out/ii_files/ for
++ # template instantiation
++ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
++ $RM out/* && rmdir out
++ cd ..
++ $RM -r conftest
++ $RM conftest*
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
++$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
++
++
++
++
++hard_links="nottested"
++if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
++ # do not overwrite the value of need_locks provided by the user
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
++$as_echo_n "checking if we can lock with hard links... " >&6; }
++ hard_links=yes
++ $RM conftest*
++ ln conftest.a conftest.b 2>/dev/null && hard_links=no
++ touch conftest.a
++ ln conftest.a conftest.b 2>&5 || hard_links=no
++ ln conftest.a conftest.b 2>/dev/null && hard_links=no
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
++$as_echo "$hard_links" >&6; }
++ if test "$hard_links" = no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
++$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
++ need_locks=warn
++ fi
++else
++ need_locks=no
++fi
++
++
++
++
++
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
++$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
++
++ runpath_var=
++ allow_undefined_flag=
++ always_export_symbols=no
++ archive_cmds=
++ archive_expsym_cmds=
++ compiler_needs_object=no
++ enable_shared_with_static_runtimes=no
++ export_dynamic_flag_spec=
++ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++ hardcode_automatic=no
++ hardcode_direct=no
++ hardcode_direct_absolute=no
++ hardcode_libdir_flag_spec=
++ hardcode_libdir_separator=
++ hardcode_minus_L=no
++ hardcode_shlibpath_var=unsupported
++ inherit_rpath=no
++ link_all_deplibs=unknown
++ module_cmds=
++ module_expsym_cmds=
++ old_archive_from_new_cmds=
++ old_archive_from_expsyms_cmds=
++ thread_safe_flag_spec=
++ whole_archive_flag_spec=
++ # include_expsyms should be a list of space-separated symbols to be *always*
++ # included in the symbol list
++ include_expsyms=
++ # exclude_expsyms can be an extended regexp of symbols to exclude
++ # it will be wrapped by ` (' and `)$', so one must not match beginning or
++ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
++ # as well as any symbol that contains `d'.
++ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
++ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
++ # platforms (ab)use it in PIC code, but their linkers get confused if
++ # the symbol is explicitly referenced. Since portable code cannot
++ # rely on this symbol name, it's probably fine to never include it in
++ # preloaded symbol tables.
++ # Exclude shared library initialization/finalization symbols.
++ extract_expsyms_cmds=
++
++ case $host_os in
++ cygwin* | mingw* | pw32* | cegcc*)
++ # FIXME: the MSVC++ port hasn't been tested in a loooong time
++ # When not using gcc, we currently assume that we are using
++ # Microsoft Visual C++.
++ if test "$GCC" != yes; then
++ with_gnu_ld=no
++ fi
++ ;;
++ interix*)
++ # we just hope/assume this is gcc and not c89 (= MSVC++)
++ with_gnu_ld=yes
++ ;;
++ openbsd*)
++ with_gnu_ld=no
++ ;;
++ linux* | k*bsd*-gnu | gnu*)
++ link_all_deplibs=no
++ ;;
++ esac
++
++ ld_shlibs=yes
++
++ # On some targets, GNU ld is compatible enough with the native linker
++ # that we're better off using the native interface for both.
++ lt_use_gnu_ld_interface=no
++ if test "$with_gnu_ld" = yes; then
++ case $host_os in
++ aix*)
++ # The AIX port of GNU ld has always aspired to compatibility
++ # with the native linker. However, as the warning in the GNU ld
++ # block says, versions before 2.19.5* couldn't really create working
++ # shared libraries, regardless of the interface used.
++ case `$LD -v 2>&1` in
++ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
++ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
++ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
++ *)
++ lt_use_gnu_ld_interface=yes
++ ;;
++ esac
++ ;;
++ *)
++ lt_use_gnu_ld_interface=yes
++ ;;
++ esac
++ fi
++
++ if test "$lt_use_gnu_ld_interface" = yes; then
++ # If archive_cmds runs LD, not CC, wlarc should be empty
++ wlarc='${wl}'
++
++ # Set some defaults for GNU ld with shared library support. These
++ # are reset later if shared libraries are not supported. Putting them
++ # here allows them to be overridden if necessary.
++ runpath_var=LD_RUN_PATH
++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
++ export_dynamic_flag_spec='${wl}--export-dynamic'
++ # ancient GNU ld didn't support --whole-archive et. al.
++ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
++ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++ else
++ whole_archive_flag_spec=
++ fi
++ supports_anon_versioning=no
++ case `$LD -v 2>&1` in
++ *GNU\ gold*) supports_anon_versioning=yes ;;
++ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
++ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
++ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
++ *\ 2.11.*) ;; # other 2.11 versions
++ *) supports_anon_versioning=yes ;;
++ esac
++
++ # See if GNU ld supports shared libraries.
++ case $host_os in
++ aix[3-9]*)
++ # On AIX/PPC, the GNU linker is very broken
++ if test "$host_cpu" != ia64; then
++ ld_shlibs=no
++ cat <<_LT_EOF 1>&2
++
++*** Warning: the GNU linker, at least up to release 2.19, is reported
++*** to be unable to reliably create shared libraries on AIX.
++*** Therefore, libtool is disabling shared libraries support. If you
++*** really care for shared libraries, you may want to install binutils
++*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
++*** You will then need to restart the configuration process.
++
++_LT_EOF
++ fi
++ ;;
++
++ amigaos*)
++ case $host_cpu in
++ powerpc)
++ # see comment about AmigaOS4 .so support
++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ archive_expsym_cmds=''
++ ;;
++ m68k)
++ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
++ hardcode_libdir_flag_spec='-L$libdir'
++ hardcode_minus_L=yes
++ ;;
++ esac
++ ;;
++
++ beos*)
++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ allow_undefined_flag=unsupported
++ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
++ # support --undefined. This deserves some investigation. FIXME
++ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ else
++ ld_shlibs=no
++ fi
++ ;;
++
++ cygwin* | mingw* | pw32* | cegcc*)
++ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
++ # as there is no search path for DLLs.
++ hardcode_libdir_flag_spec='-L$libdir'
++ export_dynamic_flag_spec='${wl}--export-all-symbols'
++ allow_undefined_flag=unsupported
++ always_export_symbols=no
++ enable_shared_with_static_runtimes=yes
++ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
++ exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
++
++ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++ # If the export-symbols file already is a .def file (1st line
++ # is EXPORTS), use it as is; otherwise, prepend...
++ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++ cp $export_symbols $output_objdir/$soname.def;
++ else
++ echo EXPORTS > $output_objdir/$soname.def;
++ cat $export_symbols >> $output_objdir/$soname.def;
++ fi~
++ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++ else
++ ld_shlibs=no
++ fi
++ ;;
++
++ haiku*)
++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ link_all_deplibs=yes
++ ;;
++
++ interix[3-9]*)
++ hardcode_direct=no
++ hardcode_shlibpath_var=no
++ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
++ export_dynamic_flag_spec='${wl}-E'
++ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++ # Instead, shared libraries are loaded at an image base (0x10000000 by
++ # default) and relocated if they conflict, which is a slow very memory
++ # consuming and fragmenting process. To avoid this, we pick a random,
++ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
++ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++ ;;
++
++ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
++ tmp_diet=no
++ if test "$host_os" = linux-dietlibc; then
++ case $cc_basename in
++ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
++ esac
++ fi
++ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
++ && test "$tmp_diet" = no
++ then
++ tmp_addflag=' $pic_flag'
++ tmp_sharedflag='-shared'
++ case $cc_basename,$host_cpu in
++ pgcc*) # Portland Group C compiler
++ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ tmp_addflag=' $pic_flag'
++ ;;
++ pgf77* | pgf90* | pgf95* | pgfortran*)
++ # Portland Group f77 and f90 compilers
++ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ tmp_addflag=' $pic_flag -Mnomain' ;;
++ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
++ tmp_addflag=' -i_dynamic' ;;
++ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
++ tmp_addflag=' -i_dynamic -nofor_main' ;;
++ ifc* | ifort*) # Intel Fortran compiler
++ tmp_addflag=' -nofor_main' ;;
++ lf95*) # Lahey Fortran 8.1
++ whole_archive_flag_spec=
++ tmp_sharedflag='--shared' ;;
++ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
++ tmp_sharedflag='-qmkshrobj'
++ tmp_addflag= ;;
++ nvcc*) # Cuda Compiler Driver 2.2
++ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ compiler_needs_object=yes
++ ;;
++ esac
++ case `$CC -V 2>&1 | sed 5q` in
++ *Sun\ C*) # Sun C 5.9
++ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ compiler_needs_object=yes
++ tmp_sharedflag='-G' ;;
++ *Sun\ F*) # Sun Fortran 8.3
++ tmp_sharedflag='-G' ;;
++ esac
++ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++
++ if test "x$supports_anon_versioning" = xyes; then
++ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
++ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++ echo "local: *; };" >> $output_objdir/$libname.ver~
++ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
++ fi
++
++ case $cc_basename in
++ xlf* | bgf* | bgxlf* | mpixlf*)
++ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
++ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
++ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
++ if test "x$supports_anon_versioning" = xyes; then
++ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
++ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++ echo "local: *; };" >> $output_objdir/$libname.ver~
++ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
++ fi
++ ;;
++ esac
++ else
++ ld_shlibs=no
++ fi
++ ;;
++
++ netbsd* | netbsdelf*-gnu)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
++ wlarc=
++ else
++ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ fi
++ ;;
++
++ solaris*)
++ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
++ ld_shlibs=no
++ cat <<_LT_EOF 1>&2
++
++*** Warning: The releases 2.8.* of the GNU linker cannot reliably
++*** create shared libraries on Solaris systems. Therefore, libtool
++*** is disabling shared libraries support. We urge you to upgrade GNU
++*** binutils to release 2.9.1 or newer. Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
++
++_LT_EOF
++ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ else
++ ld_shlibs=no
++ fi
++ ;;
++
++ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
++ case `$LD -v 2>&1` in
++ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
++ ld_shlibs=no
++ cat <<_LT_EOF 1>&2
++
++*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
++*** reliably create shared libraries on SCO systems. Therefore, libtool
++*** is disabling shared libraries support. We urge you to upgrade GNU
++*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
++
++_LT_EOF
++ ;;
++ *)
++ # For security reasons, it is highly recommended that you always
++ # use absolute paths for naming shared libraries, and exclude the
++ # DT_RUNPATH tag from executables and libraries. But doing so
++ # requires that you compile everything twice, which is a pain.
++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ else
++ ld_shlibs=no
++ fi
++ ;;
++ esac
++ ;;
++
++ sunos4*)
++ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++ wlarc=
++ hardcode_direct=yes
++ hardcode_shlibpath_var=no
++ ;;
++
++ *)
++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ else
++ ld_shlibs=no
++ fi
++ ;;
++ esac
++
++ if test "$ld_shlibs" = no; then
++ runpath_var=
++ hardcode_libdir_flag_spec=
++ export_dynamic_flag_spec=
++ whole_archive_flag_spec=
++ fi
++ else
++ # PORTME fill in a description of your system's linker (not GNU ld)
++ case $host_os in
++ aix3*)
++ allow_undefined_flag=unsupported
++ always_export_symbols=yes
++ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
++ # Note: this linker hardcodes the directories in LIBPATH if there
++ # are no directories specified by -L.
++ hardcode_minus_L=yes
++ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
++ # Neither direct hardcoding nor static linking is supported with a
++ # broken collect2.
++ hardcode_direct=unsupported
++ fi
++ ;;
++
++ aix[4-9]*)
++ if test "$host_cpu" = ia64; then
++ # On IA64, the linker does run time linking by default, so we don't
++ # have to do anything special.
++ aix_use_runtimelinking=no
++ exp_sym_flag='-Bexport'
++ no_entry_flag=""
++ else
++ # If we're using GNU nm, then we don't want the "-C" option.
++ # -C means demangle to AIX nm, but means don't demangle with GNU nm
++ # Also, AIX nm treats weak defined symbols like other global
++ # defined symbols, whereas GNU nm marks them as "W".
++ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
++ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++ else
++ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++ fi
++ aix_use_runtimelinking=no
++
++ # Test if we are trying to use run time linking or normal
++ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
++ # need to do runtime linking.
++ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
++ for ld_flag in $LDFLAGS; do
++ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
++ aix_use_runtimelinking=yes
++ break
++ fi
++ done
++ ;;
++ esac
++
++ exp_sym_flag='-bexport'
++ no_entry_flag='-bnoentry'
++ fi
++
++ # When large executables or shared objects are built, AIX ld can
++ # have problems creating the table of contents. If linking a library
++ # or program results in "error TOC overflow" add -mminimal-toc to
++ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
++ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
++
++ archive_cmds=''
++ hardcode_direct=yes
++ hardcode_direct_absolute=yes
++ hardcode_libdir_separator=':'
++ link_all_deplibs=yes
++ file_list_spec='${wl}-f,'
++
++ if test "$GCC" = yes; then
++ case $host_os in aix4.[012]|aix4.[012].*)
++ # We only want to do this on AIX 4.2 and lower, the check
++ # below for broken collect2 doesn't work under 4.3+
++ collect2name=`${CC} -print-prog-name=collect2`
++ if test -f "$collect2name" &&
++ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
++ then
++ # We have reworked collect2
++ :
++ else
++ # We have old collect2
++ hardcode_direct=unsupported
++ # It fails to find uninstalled libraries when the uninstalled
++ # path is not listed in the libpath. Setting hardcode_minus_L
++ # to unsupported forces relinking
++ hardcode_minus_L=yes
++ hardcode_libdir_flag_spec='-L$libdir'
++ hardcode_libdir_separator=
++ fi
++ ;;
++ esac
++ shared_flag='-shared'
++ if test "$aix_use_runtimelinking" = yes; then
++ shared_flag="$shared_flag "'${wl}-G'
++ fi
++ link_all_deplibs=no
++ else
++ # not using gcc
++ if test "$host_cpu" = ia64; then
++ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
++ # chokes on -Wl,-G. The following line is correct:
++ shared_flag='-G'
++ else
++ if test "$aix_use_runtimelinking" = yes; then
++ shared_flag='${wl}-G'
++ else
++ shared_flag='${wl}-bM:SRE'
++ fi
++ fi
++ fi
++
++ export_dynamic_flag_spec='${wl}-bexpall'
++ # It seems that -bexpall does not export symbols beginning with
++ # underscore (_), so it is better to generate a list of symbols to export.
++ always_export_symbols=yes
++ if test "$aix_use_runtimelinking" = yes; then
++ # Warning - without using the other runtime loading flags (-brtl),
++ # -berok will link without error, but may produce a broken library.
++ allow_undefined_flag='-berok'
++ # Determine the default libpath from the value encoded in an
++ # empty executable.
++ if test "${lt_cv_aix_libpath+set}" = set; then
++ aix_libpath=$lt_cv_aix_libpath
++else
++ if ${lt_cv_aix_libpath_+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++
++ lt_aix_libpath_sed='
++ /Import File Strings/,/^$/ {
++ /^0/ {
++ s/^0 *\([^ ]*\) *$/\1/
++ p
++ }
++ }'
++ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++ # Check for a 64-bit object if we didn't find anything.
++ if test -z "$lt_cv_aix_libpath_"; then
++ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++ fi
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ if test -z "$lt_cv_aix_libpath_"; then
++ lt_cv_aix_libpath_="/usr/lib:/lib"
++ fi
++
++fi
++
++ aix_libpath=$lt_cv_aix_libpath_
++fi
++
++ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
++ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++ else
++ if test "$host_cpu" = ia64; then
++ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
++ allow_undefined_flag="-z nodefs"
++ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
++ else
++ # Determine the default libpath from the value encoded in an
++ # empty executable.
++ if test "${lt_cv_aix_libpath+set}" = set; then
++ aix_libpath=$lt_cv_aix_libpath
++else
++ if ${lt_cv_aix_libpath_+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++
++ lt_aix_libpath_sed='
++ /Import File Strings/,/^$/ {
++ /^0/ {
++ s/^0 *\([^ ]*\) *$/\1/
++ p
++ }
++ }'
++ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++ # Check for a 64-bit object if we didn't find anything.
++ if test -z "$lt_cv_aix_libpath_"; then
++ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++ fi
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ if test -z "$lt_cv_aix_libpath_"; then
++ lt_cv_aix_libpath_="/usr/lib:/lib"
++ fi
++
++fi
++
++ aix_libpath=$lt_cv_aix_libpath_
++fi
++
++ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
++ # Warning - without using the other run time loading flags,
++ # -berok will link without error, but may produce a broken library.
++ no_undefined_flag=' ${wl}-bernotok'
++ allow_undefined_flag=' ${wl}-berok'
++ if test "$with_gnu_ld" = yes; then
++ # We only use this code for GNU lds that support --whole-archive.
++ whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
++ else
++ # Exported symbols can be pulled into shared objects from archives
++ whole_archive_flag_spec='$convenience'
++ fi
++ archive_cmds_need_lc=yes
++ # This is similar to how AIX traditionally builds its shared libraries.
++ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++ fi
++ fi
++ ;;
++
++ amigaos*)
++ case $host_cpu in
++ powerpc)
++ # see comment about AmigaOS4 .so support
++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ archive_expsym_cmds=''
++ ;;
++ m68k)
++ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
++ hardcode_libdir_flag_spec='-L$libdir'
++ hardcode_minus_L=yes
++ ;;
++ esac
++ ;;
++
++ bsdi[45]*)
++ export_dynamic_flag_spec=-rdynamic
++ ;;
++
++ cygwin* | mingw* | pw32* | cegcc*)
++ # When not using gcc, we currently assume that we are using
++ # Microsoft Visual C++.
++ # hardcode_libdir_flag_spec is actually meaningless, as there is
++ # no search path for DLLs.
++ case $cc_basename in
++ cl*)
++ # Native MSVC
++ hardcode_libdir_flag_spec=' '
++ allow_undefined_flag=unsupported
++ always_export_symbols=yes
++ file_list_spec='@'
++ # Tell ltmain to make .lib files, not .a files.
++ libext=lib
++ # Tell ltmain to make .dll files, not .so files.
++ shrext_cmds=".dll"
++ # FIXME: Setting linknames here is a bad hack.
++ archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
++ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++ sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
++ else
++ sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
++ fi~
++ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
++ linknames='
++ # The linker will not automatically build a static lib if we build a DLL.
++ # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
++ enable_shared_with_static_runtimes=yes
++ exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
++ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
++ # Don't use ranlib
++ old_postinstall_cmds='chmod 644 $oldlib'
++ postlink_cmds='lt_outputfile="@OUTPUT@"~
++ lt_tool_outputfile="@TOOL_OUTPUT@"~
++ case $lt_outputfile in
++ *.exe|*.EXE) ;;
++ *)
++ lt_outputfile="$lt_outputfile.exe"
++ lt_tool_outputfile="$lt_tool_outputfile.exe"
++ ;;
++ esac~
++ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
++ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
++ $RM "$lt_outputfile.manifest";
++ fi'
++ ;;
++ *)
++ # Assume MSVC wrapper
++ hardcode_libdir_flag_spec=' '
++ allow_undefined_flag=unsupported
++ # Tell ltmain to make .lib files, not .a files.
++ libext=lib
++ # Tell ltmain to make .dll files, not .so files.
++ shrext_cmds=".dll"
++ # FIXME: Setting linknames here is a bad hack.
++ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
++ # The linker will automatically build a .lib file if we build a DLL.
++ old_archive_from_new_cmds='true'
++ # FIXME: Should let the user specify the lib program.
++ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
++ enable_shared_with_static_runtimes=yes
++ ;;
++ esac
++ ;;
++
++ darwin* | rhapsody*)
++
++
++ archive_cmds_need_lc=no
++ hardcode_direct=no
++ hardcode_automatic=yes
++ hardcode_shlibpath_var=unsupported
++ if test "$lt_cv_ld_force_load" = "yes"; then
++ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
++
++ else
++ whole_archive_flag_spec=''
++ fi
++ link_all_deplibs=yes
++ allow_undefined_flag="$_lt_dar_allow_undefined"
++ case $cc_basename in
++ ifort*) _lt_dar_can_shared=yes ;;
++ *) _lt_dar_can_shared=$GCC ;;
++ esac
++ if test "$_lt_dar_can_shared" = "yes"; then
++ output_verbose_link_cmd=func_echo_all
++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
++
++ else
++ ld_shlibs=no
++ fi
++
++ ;;
++
++ dgux*)
++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_libdir_flag_spec='-L$libdir'
++ hardcode_shlibpath_var=no
++ ;;
++
++ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
++ # support. Future versions do this automatically, but an explicit c++rt0.o
++ # does not break anything, and helps significantly (at the cost of a little
++ # extra space).
++ freebsd2.2*)
++ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
++ hardcode_libdir_flag_spec='-R$libdir'
++ hardcode_direct=yes
++ hardcode_shlibpath_var=no
++ ;;
++
++ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
++ freebsd2.*)
++ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_direct=yes
++ hardcode_minus_L=yes
++ hardcode_shlibpath_var=no
++ ;;
++
++ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
++ freebsd* | dragonfly*)
++ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++ hardcode_libdir_flag_spec='-R$libdir'
++ hardcode_direct=yes
++ hardcode_shlibpath_var=no
++ ;;
++
++ hpux9*)
++ if test "$GCC" = yes; then
++ archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++ else
++ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++ fi
++ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
++ hardcode_libdir_separator=:
++ hardcode_direct=yes
++
++ # hardcode_minus_L: Not really in the search PATH,
++ # but as the default location of the library.
++ hardcode_minus_L=yes
++ export_dynamic_flag_spec='${wl}-E'
++ ;;
++
++ hpux10*)
++ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
++ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++ else
++ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
++ fi
++ if test "$with_gnu_ld" = no; then
++ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
++ hardcode_libdir_separator=:
++ hardcode_direct=yes
++ hardcode_direct_absolute=yes
++ export_dynamic_flag_spec='${wl}-E'
++ # hardcode_minus_L: Not really in the search PATH,
++ # but as the default location of the library.
++ hardcode_minus_L=yes
++ fi
++ ;;
++
++ hpux11*)
++ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
++ case $host_cpu in
++ hppa*64*)
++ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ ia64*)
++ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ *)
++ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ esac
++ else
++ case $host_cpu in
++ hppa*64*)
++ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ ia64*)
++ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ *)
++
++ # Older versions of the 11.00 compiler do not understand -b yet
++ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
++$as_echo_n "checking if $CC understands -b... " >&6; }
++if ${lt_cv_prog_compiler__b+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_prog_compiler__b=no
++ save_LDFLAGS="$LDFLAGS"
++ LDFLAGS="$LDFLAGS -b"
++ echo "$lt_simple_link_test_code" > conftest.$ac_ext
++ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
++ # The linker can only warn and ignore the option if not recognized
++ # So say no if there are warnings
++ if test -s conftest.err; then
++ # Append any errors to the config.log.
++ cat conftest.err 1>&5
++ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++ if diff conftest.exp conftest.er2 >/dev/null; then
++ lt_cv_prog_compiler__b=yes
++ fi
++ else
++ lt_cv_prog_compiler__b=yes
++ fi
++ fi
++ $RM -r conftest*
++ LDFLAGS="$save_LDFLAGS"
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
++$as_echo "$lt_cv_prog_compiler__b" >&6; }
++
++if test x"$lt_cv_prog_compiler__b" = xyes; then
++ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++else
++ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
++fi
++
++ ;;
++ esac
++ fi
++ if test "$with_gnu_ld" = no; then
++ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
++ hardcode_libdir_separator=:
++
++ case $host_cpu in
++ hppa*64*|ia64*)
++ hardcode_direct=no
++ hardcode_shlibpath_var=no
++ ;;
++ *)
++ hardcode_direct=yes
++ hardcode_direct_absolute=yes
++ export_dynamic_flag_spec='${wl}-E'
++
++ # hardcode_minus_L: Not really in the search PATH,
++ # but as the default location of the library.
++ hardcode_minus_L=yes
++ ;;
++ esac
++ fi
++ ;;
++
++ irix5* | irix6* | nonstopux*)
++ if test "$GCC" = yes; then
++ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ # Try to use the -exported_symbol ld option, if it does not
++ # work, assume that -exports_file does not work either and
++ # implicitly export all symbols.
++ # This should be the same for all languages, so no per-tag cache variable.
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
++$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
++if ${lt_cv_irix_exported_symbol+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ save_LDFLAGS="$LDFLAGS"
++ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++int foo (void) { return 0; }
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ lt_cv_irix_exported_symbol=yes
++else
++ lt_cv_irix_exported_symbol=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ LDFLAGS="$save_LDFLAGS"
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
++$as_echo "$lt_cv_irix_exported_symbol" >&6; }
++ if test "$lt_cv_irix_exported_symbol" = yes; then
++ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
++ fi
++ else
++ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
++ fi
++ archive_cmds_need_lc='no'
++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
++ hardcode_libdir_separator=:
++ inherit_rpath=yes
++ link_all_deplibs=yes
++ ;;
++
++ netbsd* | netbsdelf*-gnu)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
++ else
++ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
++ fi
++ hardcode_libdir_flag_spec='-R$libdir'
++ hardcode_direct=yes
++ hardcode_shlibpath_var=no
++ ;;
++
++ newsos6)
++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_direct=yes
++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
++ hardcode_libdir_separator=:
++ hardcode_shlibpath_var=no
++ ;;
++
++ *nto* | *qnx*)
++ ;;
++
++ openbsd*)
++ if test -f /usr/libexec/ld.so; then
++ hardcode_direct=yes
++ hardcode_shlibpath_var=no
++ hardcode_direct_absolute=yes
++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
++ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
++ export_dynamic_flag_spec='${wl}-E'
++ else
++ case $host_os in
++ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
++ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_libdir_flag_spec='-R$libdir'
++ ;;
++ *)
++ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
++ ;;
++ esac
++ fi
++ else
++ ld_shlibs=no
++ fi
++ ;;
++
++ os2*)
++ hardcode_libdir_flag_spec='-L$libdir'
++ hardcode_minus_L=yes
++ allow_undefined_flag=unsupported
++ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
++ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
++ ;;
++
++ osf3*)
++ if test "$GCC" = yes; then
++ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
++ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ else
++ allow_undefined_flag=' -expect_unresolved \*'
++ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++ fi
++ archive_cmds_need_lc='no'
++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
++ hardcode_libdir_separator=:
++ ;;
++
++ osf4* | osf5*) # as osf3* with the addition of -msym flag
++ if test "$GCC" = yes; then
++ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
++ archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
++ else
++ allow_undefined_flag=' -expect_unresolved \*'
++ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
++ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
++
++ # Both c and cxx compiler support -rpath directly
++ hardcode_libdir_flag_spec='-rpath $libdir'
++ fi
++ archive_cmds_need_lc='no'
++ hardcode_libdir_separator=:
++ ;;
++
++ solaris*)
++ no_undefined_flag=' -z defs'
++ if test "$GCC" = yes; then
++ wlarc='${wl}'
++ archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
++ else
++ case `$CC -V 2>&1` in
++ *"Compilers 5.0"*)
++ wlarc=''
++ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
++ ;;
++ *)
++ wlarc='${wl}'
++ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
++ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
++ ;;
++ esac
++ fi
++ hardcode_libdir_flag_spec='-R$libdir'
++ hardcode_shlibpath_var=no
++ case $host_os in
++ solaris2.[0-5] | solaris2.[0-5].*) ;;
++ *)
++ # The compiler driver will combine and reorder linker options,
++ # but understands `-z linker_flag'. GCC discards it without `$wl',
++ # but is careful enough not to reorder.
++ # Supported since Solaris 2.6 (maybe 2.5.1?)
++ if test "$GCC" = yes; then
++ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
++ else
++ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
++ fi
++ ;;
++ esac
++ link_all_deplibs=yes
++ ;;
++
++ sunos4*)
++ if test "x$host_vendor" = xsequent; then
++ # Use $CC to link under sequent, because it throws in some extra .o
++ # files that make .init and .fini sections work.
++ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
++ else
++ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
++ fi
++ hardcode_libdir_flag_spec='-L$libdir'
++ hardcode_direct=yes
++ hardcode_minus_L=yes
++ hardcode_shlibpath_var=no
++ ;;
++
++ sysv4)
++ case $host_vendor in
++ sni)
++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_direct=yes # is this really true???
++ ;;
++ siemens)
++ ## LD is ld it makes a PLAMLIB
++ ## CC just makes a GrossModule.
++ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
++ reload_cmds='$CC -r -o $output$reload_objs'
++ hardcode_direct=no
++ ;;
++ motorola)
++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
++ ;;
++ esac
++ runpath_var='LD_RUN_PATH'
++ hardcode_shlibpath_var=no
++ ;;
++
++ sysv4.3*)
++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_shlibpath_var=no
++ export_dynamic_flag_spec='-Bexport'
++ ;;
++
++ sysv4*MP*)
++ if test -d /usr/nec; then
++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_shlibpath_var=no
++ runpath_var=LD_RUN_PATH
++ hardcode_runpath_var=yes
++ ld_shlibs=yes
++ fi
++ ;;
++
++ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
++ no_undefined_flag='${wl}-z,text'
++ archive_cmds_need_lc=no
++ hardcode_shlibpath_var=no
++ runpath_var='LD_RUN_PATH'
++
++ if test "$GCC" = yes; then
++ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ else
++ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ fi
++ ;;
++
++ sysv5* | sco3.2v5* | sco5v6*)
++ # Note: We can NOT use -z defs as we might desire, because we do not
++ # link with -lc, and that would cause any symbols used from libc to
++ # always be unresolved, which means just about no library would
++ # ever link correctly. If we're not using GNU ld we use -z text
++ # though, which does catch some bad symbols but isn't as heavy-handed
++ # as -z defs.
++ no_undefined_flag='${wl}-z,text'
++ allow_undefined_flag='${wl}-z,nodefs'
++ archive_cmds_need_lc=no
++ hardcode_shlibpath_var=no
++ hardcode_libdir_flag_spec='${wl}-R,$libdir'
++ hardcode_libdir_separator=':'
++ link_all_deplibs=yes
++ export_dynamic_flag_spec='${wl}-Bexport'
++ runpath_var='LD_RUN_PATH'
++
++ if test "$GCC" = yes; then
++ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ else
++ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ fi
++ ;;
++
++ uts4*)
++ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ hardcode_libdir_flag_spec='-L$libdir'
++ hardcode_shlibpath_var=no
++ ;;
++
++ *)
++ ld_shlibs=no
++ ;;
++ esac
++
++ if test x$host_vendor = xsni; then
++ case $host in
++ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
++ export_dynamic_flag_spec='${wl}-Blargedynsym'
++ ;;
++ esac
++ fi
++ fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
++$as_echo "$ld_shlibs" >&6; }
++test "$ld_shlibs" = no && can_build_shared=no
++
++with_gnu_ld=$with_gnu_ld
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++#
++# Do we need to explicitly link libc?
++#
++case "x$archive_cmds_need_lc" in
++x|xyes)
++ # Assume -lc should be added
++ archive_cmds_need_lc=yes
++
++ if test "$enable_shared" = yes && test "$GCC" = yes; then
++ case $archive_cmds in
++ *'~'*)
++ # FIXME: we may have to deal with multi-command sequences.
++ ;;
++ '$CC '*)
++ # Test whether the compiler implicitly links with -lc since on some
++ # systems, -lgcc has to come before -lc. If gcc already passes -lc
++ # to ld, don't add -lc before -lgcc.
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
++$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
++if ${lt_cv_archive_cmds_need_lc+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ $RM conftest*
++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
++ (eval $ac_compile) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } 2>conftest.err; then
++ soname=conftest
++ lib=conftest
++ libobjs=conftest.$ac_objext
++ deplibs=
++ wl=$lt_prog_compiler_wl
++ pic_flag=$lt_prog_compiler_pic
++ compiler_flags=-v
++ linker_flags=-v
++ verstring=
++ output_objdir=.
++ libname=conftest
++ lt_save_allow_undefined_flag=$allow_undefined_flag
++ allow_undefined_flag=
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
++ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; }
++ then
++ lt_cv_archive_cmds_need_lc=no
++ else
++ lt_cv_archive_cmds_need_lc=yes
++ fi
++ allow_undefined_flag=$lt_save_allow_undefined_flag
++ else
++ cat conftest.err 1>&5
++ fi
++ $RM conftest*
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
++$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
++ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
++ ;;
++ esac
++ fi
++ ;;
++esac
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
++$as_echo_n "checking dynamic linker characteristics... " >&6; }
++
++if test "$GCC" = yes; then
++ case $host_os in
++ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
++ *) lt_awk_arg="/^libraries:/" ;;
++ esac
++ case $host_os in
++ mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
++ *) lt_sed_strip_eq="s,=/,/,g" ;;
++ esac
++ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
++ case $lt_search_path_spec in
++ *\;*)
++ # if the path contains ";" then we assume it to be the separator
++ # otherwise default to the standard path separator (i.e. ":") - it is
++ # assumed that no part of a normal pathname contains ";" but that should
++ # okay in the real world where ";" in dirpaths is itself problematic.
++ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
++ ;;
++ *)
++ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
++ ;;
++ esac
++ # Ok, now we have the path, separated by spaces, we can step through it
++ # and add multilib dir if necessary.
++ lt_tmp_lt_search_path_spec=
++ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
++ for lt_sys_path in $lt_search_path_spec; do
++ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
++ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
++ else
++ test -d "$lt_sys_path" && \
++ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
++ fi
++ done
++ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
++BEGIN {RS=" "; FS="/|\n";} {
++ lt_foo="";
++ lt_count=0;
++ for (lt_i = NF; lt_i > 0; lt_i--) {
++ if ($lt_i != "" && $lt_i != ".") {
++ if ($lt_i == "..") {
++ lt_count++;
++ } else {
++ if (lt_count == 0) {
++ lt_foo="/" $lt_i lt_foo;
++ } else {
++ lt_count--;
++ }
++ }
++ }
++ }
++ if (lt_foo != "") { lt_freq[lt_foo]++; }
++ if (lt_freq[lt_foo] == 1) { print lt_foo; }
++}'`
++ # AWK program above erroneously prepends '/' to C:/dos/paths
++ # for these hosts.
++ case $host_os in
++ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
++ $SED 's,/\([A-Za-z]:\),\1,g'` ;;
++ esac
++ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
++else
++ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
++fi
++library_names_spec=
++libname_spec='lib$name'
++soname_spec=
++shrext_cmds=".so"
++postinstall_cmds=
++postuninstall_cmds=
++finish_cmds=
++finish_eval=
++shlibpath_var=
++shlibpath_overrides_runpath=unknown
++version_type=none
++dynamic_linker="$host_os ld.so"
++sys_lib_dlsearch_path_spec="/lib /usr/lib"
++need_lib_prefix=unknown
++hardcode_into_libs=no
++
++# when you set need_version to no, make sure it does not cause -set_version
++# flags to be left without arguments
++need_version=unknown
++
++case $host_os in
++aix3*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
++ shlibpath_var=LIBPATH
++
++ # AIX 3 has no versioning support, so we append a major version to the name.
++ soname_spec='${libname}${release}${shared_ext}$major'
++ ;;
++
++aix[4-9]*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ hardcode_into_libs=yes
++ if test "$host_cpu" = ia64; then
++ # AIX 5 supports IA64
++ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
++ shlibpath_var=LD_LIBRARY_PATH
++ else
++ # With GCC up to 2.95.x, collect2 would create an import file
++ # for dependence libraries. The import file would start with
++ # the line `#! .'. This would cause the generated library to
++ # depend on `.', always an invalid library. This was fixed in
++ # development snapshots of GCC prior to 3.0.
++ case $host_os in
++ aix4 | aix4.[01] | aix4.[01].*)
++ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
++ echo ' yes '
++ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
++ :
++ else
++ can_build_shared=no
++ fi
++ ;;
++ esac
++ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
++ # soname into executable. Probably we can add versioning support to
++ # collect2, so additional links can be useful in future.
++ if test "$aix_use_runtimelinking" = yes; then
++ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
++ # instead of lib<name>.a to let people know that these are not
++ # typical AIX shared libraries.
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ else
++ # We preserve .a as extension for shared libraries through AIX4.2
++ # and later when we are not doing run time linking.
++ library_names_spec='${libname}${release}.a $libname.a'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ fi
++ shlibpath_var=LIBPATH
++ fi
++ ;;
++
++amigaos*)
++ case $host_cpu in
++ powerpc)
++ # Since July 2007 AmigaOS4 officially supports .so libraries.
++ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ ;;
++ m68k)
++ library_names_spec='$libname.ixlibrary $libname.a'
++ # Create ${libname}_ixlibrary.a entries in /sys/libs.
++ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
++ ;;
++ esac
++ ;;
++
++beos*)
++ library_names_spec='${libname}${shared_ext}'
++ dynamic_linker="$host_os ld.so"
++ shlibpath_var=LIBRARY_PATH
++ ;;
++
++bsdi[45]*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
++ shlibpath_var=LD_LIBRARY_PATH
++ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
++ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
++ # the default ld.so.conf also contains /usr/contrib/lib and
++ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
++ # libtool to hard-code these into programs
++ ;;
++
++cygwin* | mingw* | pw32* | cegcc*)
++ version_type=windows
++ shrext_cmds=".dll"
++ need_version=no
++ need_lib_prefix=no
++
++ case $GCC,$cc_basename in
++ yes,*)
++ # gcc
++ library_names_spec='$libname.dll.a'
++ # DLL is installed to $(libdir)/../bin by postinstall_cmds
++ postinstall_cmds='base_file=`basename \${file}`~
++ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
++ dldir=$destdir/`dirname \$dlpath`~
++ test -d \$dldir || mkdir -p \$dldir~
++ $install_prog $dir/$dlname \$dldir/$dlname~
++ chmod a+x \$dldir/$dlname~
++ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
++ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
++ fi'
++ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
++ dlpath=$dir/\$dldll~
++ $RM \$dlpath'
++ shlibpath_overrides_runpath=yes
++
++ case $host_os in
++ cygwin*)
++ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
++ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
++
++ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
++ ;;
++ mingw* | cegcc*)
++ # MinGW DLLs use traditional 'lib' prefix
++ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
++ ;;
++ pw32*)
++ # pw32 DLLs use 'pw' prefix rather than 'lib'
++ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
++ ;;
++ esac
++ dynamic_linker='Win32 ld.exe'
++ ;;
++
++ *,cl*)
++ # Native MSVC
++ libname_spec='$name'
++ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
++ library_names_spec='${libname}.dll.lib'
++
++ case $build_os in
++ mingw*)
++ sys_lib_search_path_spec=
++ lt_save_ifs=$IFS
++ IFS=';'
++ for lt_path in $LIB
++ do
++ IFS=$lt_save_ifs
++ # Let DOS variable expansion print the short 8.3 style file name.
++ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
++ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
++ done
++ IFS=$lt_save_ifs
++ # Convert to MSYS style.
++ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
++ ;;
++ cygwin*)
++ # Convert to unix form, then to dos form, then back to unix form
++ # but this time dos style (no spaces!) so that the unix form looks
++ # like /cygdrive/c/PROGRA~1:/cygdr...
++ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
++ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
++ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
++ ;;
++ *)
++ sys_lib_search_path_spec="$LIB"
++ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
++ # It is most probably a Windows format PATH.
++ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
++ else
++ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
++ fi
++ # FIXME: find the short name or the path components, as spaces are
++ # common. (e.g. "Program Files" -> "PROGRA~1")
++ ;;
++ esac
++
++ # DLL is installed to $(libdir)/../bin by postinstall_cmds
++ postinstall_cmds='base_file=`basename \${file}`~
++ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
++ dldir=$destdir/`dirname \$dlpath`~
++ test -d \$dldir || mkdir -p \$dldir~
++ $install_prog $dir/$dlname \$dldir/$dlname'
++ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
++ dlpath=$dir/\$dldll~
++ $RM \$dlpath'
++ shlibpath_overrides_runpath=yes
++ dynamic_linker='Win32 link.exe'
++ ;;
++
++ *)
++ # Assume MSVC wrapper
++ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
++ dynamic_linker='Win32 ld.exe'
++ ;;
++ esac
++ # FIXME: first we should search . and the directory the executable is in
++ shlibpath_var=PATH
++ ;;
++
++darwin* | rhapsody*)
++ dynamic_linker="$host_os dyld"
++ version_type=darwin
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
++ soname_spec='${libname}${release}${major}$shared_ext'
++ shlibpath_overrides_runpath=yes
++ shlibpath_var=DYLD_LIBRARY_PATH
++ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
++
++ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
++ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
++ ;;
++
++dgux*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ ;;
++
++freebsd* | dragonfly*)
++ # DragonFly does not have aout. When/if they implement a new
++ # versioning mechanism, adjust this.
++ if test -x /usr/bin/objformat; then
++ objformat=`/usr/bin/objformat`
++ else
++ case $host_os in
++ freebsd[23].*) objformat=aout ;;
++ *) objformat=elf ;;
++ esac
++ fi
++ version_type=freebsd-$objformat
++ case $version_type in
++ freebsd-elf*)
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++ need_version=no
++ need_lib_prefix=no
++ ;;
++ freebsd-*)
++ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
++ need_version=yes
++ ;;
++ esac
++ shlibpath_var=LD_LIBRARY_PATH
++ case $host_os in
++ freebsd2.*)
++ shlibpath_overrides_runpath=yes
++ ;;
++ freebsd3.[01]* | freebsdelf3.[01]*)
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ ;;
++ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
++ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ ;;
++ *) # from 4.6 on, and DragonFly
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ ;;
++ esac
++ ;;
++
++haiku*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ dynamic_linker="$host_os runtime_loader"
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
++ hardcode_into_libs=yes
++ ;;
++
++hpux9* | hpux10* | hpux11*)
++ # Give a soname corresponding to the major version so that dld.sl refuses to
++ # link against other versions.
++ version_type=sunos
++ need_lib_prefix=no
++ need_version=no
++ case $host_cpu in
++ ia64*)
++ shrext_cmds='.so'
++ hardcode_into_libs=yes
++ dynamic_linker="$host_os dld.so"
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ if test "X$HPUX_IA64_MODE" = X32; then
++ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
++ else
++ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
++ fi
++ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
++ ;;
++ hppa*64*)
++ shrext_cmds='.sl'
++ hardcode_into_libs=yes
++ dynamic_linker="$host_os dld.sl"
++ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
++ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
++ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
++ ;;
++ *)
++ shrext_cmds='.sl'
++ dynamic_linker="$host_os dld.sl"
++ shlibpath_var=SHLIB_PATH
++ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ ;;
++ esac
++ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
++ postinstall_cmds='chmod 555 $lib'
++ # or fails outright, so override atomically:
++ install_override_mode=555
++ ;;
++
++interix[3-9]*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ ;;
++
++irix5* | irix6* | nonstopux*)
++ case $host_os in
++ nonstopux*) version_type=nonstopux ;;
++ *)
++ if test "$lt_cv_prog_gnu_ld" = yes; then
++ version_type=linux # correct to gnu/linux during the next big refactor
++ else
++ version_type=irix
++ fi ;;
++ esac
++ need_lib_prefix=no
++ need_version=no
++ soname_spec='${libname}${release}${shared_ext}$major'
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
++ case $host_os in
++ irix5* | nonstopux*)
++ libsuff= shlibsuff=
++ ;;
++ *)
++ case $LD in # libtool.m4 will add one of these switches to LD
++ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
++ libsuff= shlibsuff= libmagic=32-bit;;
++ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
++ libsuff=32 shlibsuff=N32 libmagic=N32;;
++ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
++ libsuff=64 shlibsuff=64 libmagic=64-bit;;
++ *) libsuff= shlibsuff= libmagic=never-match;;
++ esac
++ ;;
++ esac
++ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
++ shlibpath_overrides_runpath=no
++ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
++ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
++ hardcode_into_libs=yes
++ ;;
++
++# No shared lib support for Linux oldld, aout, or coff.
++linux*oldld* | linux*aout* | linux*coff*)
++ dynamic_linker=no
++ ;;
++
++# This must be glibc/ELF.
++linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++
++ # Some binutils ld are patched to set DT_RUNPATH
++ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ lt_cv_shlibpath_overrides_runpath=no
++ save_LDFLAGS=$LDFLAGS
++ save_libdir=$libdir
++ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
++ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
++ lt_cv_shlibpath_overrides_runpath=yes
++fi
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ LDFLAGS=$save_LDFLAGS
++ libdir=$save_libdir
++
++fi
++
++ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
++
++ # This implies no fast_install, which is unacceptable.
++ # Some rework will be needed to allow for fast_install
++ # before this can be enabled.
++ hardcode_into_libs=yes
++
++ # Append ld.so.conf contents to the search path
++ if test -f /etc/ld.so.conf; then
++ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
++ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
++ fi
++
++ # We used to test for /lib/ld.so.1 and disable shared libraries on
++ # powerpc, because MkLinux only supported shared libraries with the
++ # GNU dynamic linker. Since this was broken with cross compilers,
++ # most powerpc-linux boxes support dynamic linking these days and
++ # people can always --disable-shared, the test was removed, and we
++ # assume the GNU/Linux dynamic linker is in use.
++ dynamic_linker='GNU/Linux ld.so'
++ ;;
++
++netbsdelf*-gnu)
++ version_type=linux
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ dynamic_linker='NetBSD ld.elf_so'
++ ;;
++
++netbsd*)
++ version_type=sunos
++ need_lib_prefix=no
++ need_version=no
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
++ dynamic_linker='NetBSD (a.out) ld.so'
++ else
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ dynamic_linker='NetBSD ld.elf_so'
++ fi
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ ;;
++
++newsos6)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ ;;
++
++*nto* | *qnx*)
++ version_type=qnx
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ dynamic_linker='ldqnx.so'
++ ;;
++
++openbsd*)
++ version_type=sunos
++ sys_lib_dlsearch_path_spec="/usr/lib"
++ need_lib_prefix=no
++ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
++ case $host_os in
++ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
++ *) need_version=no ;;
++ esac
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
++ shlibpath_var=LD_LIBRARY_PATH
++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++ case $host_os in
++ openbsd2.[89] | openbsd2.[89].*)
++ shlibpath_overrides_runpath=no
++ ;;
++ *)
++ shlibpath_overrides_runpath=yes
++ ;;
++ esac
++ else
++ shlibpath_overrides_runpath=yes
++ fi
++ ;;
++
++os2*)
++ libname_spec='$name'
++ shrext_cmds=".dll"
++ need_lib_prefix=no
++ library_names_spec='$libname${shared_ext} $libname.a'
++ dynamic_linker='OS/2 ld.exe'
++ shlibpath_var=LIBPATH
++ ;;
++
++osf3* | osf4* | osf5*)
++ version_type=osf
++ need_lib_prefix=no
++ need_version=no
++ soname_spec='${libname}${release}${shared_ext}$major'
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ shlibpath_var=LD_LIBRARY_PATH
++ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
++ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
++ ;;
++
++rdos*)
++ dynamic_linker=no
++ ;;
++
++solaris*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ # ldd complains unless libraries are executable
++ postinstall_cmds='chmod +x $lib'
++ ;;
++
++sunos4*)
++ version_type=sunos
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ if test "$with_gnu_ld" = yes; then
++ need_lib_prefix=no
++ fi
++ need_version=yes
++ ;;
++
++sysv4 | sysv4.3*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ case $host_vendor in
++ sni)
++ shlibpath_overrides_runpath=no
++ need_lib_prefix=no
++ runpath_var=LD_RUN_PATH
++ ;;
++ siemens)
++ need_lib_prefix=no
++ ;;
++ motorola)
++ need_lib_prefix=no
++ need_version=no
++ shlibpath_overrides_runpath=no
++ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
++ ;;
++ esac
++ ;;
++
++sysv4*MP*)
++ if test -d /usr/nec ;then
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
++ soname_spec='$libname${shared_ext}.$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ fi
++ ;;
++
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++ version_type=freebsd-elf
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ if test "$with_gnu_ld" = yes; then
++ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
++ else
++ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
++ case $host_os in
++ sco3.2v5*)
++ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
++ ;;
++ esac
++ fi
++ sys_lib_dlsearch_path_spec='/usr/lib'
++ ;;
++
++tpf*)
++ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ ;;
++
++uts4*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ ;;
++
++*)
++ dynamic_linker=no
++ ;;
++esac
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
++$as_echo "$dynamic_linker" >&6; }
++test "$dynamic_linker" = no && can_build_shared=no
++
++variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
++if test "$GCC" = yes; then
++ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
++fi
++
++if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
++ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
++fi
++if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
++ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
++fi
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
++$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
++hardcode_action=
++if test -n "$hardcode_libdir_flag_spec" ||
++ test -n "$runpath_var" ||
++ test "X$hardcode_automatic" = "Xyes" ; then
++
++ # We can hardcode non-existent directories.
++ if test "$hardcode_direct" != no &&
++ # If the only mechanism to avoid hardcoding is shlibpath_var, we
++ # have to relink, otherwise we might link with an installed library
++ # when we should be linking with a yet-to-be-installed one
++ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
++ test "$hardcode_minus_L" != no; then
++ # Linking always hardcodes the temporary library directory.
++ hardcode_action=relink
++ else
++ # We can link without hardcoding, and we can hardcode nonexisting dirs.
++ hardcode_action=immediate
++ fi
++else
++ # We cannot hardcode anything, or else we can only hardcode existing
++ # directories.
++ hardcode_action=unsupported
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
++$as_echo "$hardcode_action" >&6; }
++
++if test "$hardcode_action" = relink ||
++ test "$inherit_rpath" = yes; then
++ # Fast installation is not supported
++ enable_fast_install=no
++elif test "$shlibpath_overrides_runpath" = yes ||
++ test "$enable_shared" = no; then
++ # Fast installation is not necessary
++ enable_fast_install=needless
++fi
++
++
++
++
++
++
++ if test "x$enable_dlopen" != xyes; then
++ enable_dlopen=unknown
++ enable_dlopen_self=unknown
++ enable_dlopen_self_static=unknown
++else
++ lt_cv_dlopen=no
++ lt_cv_dlopen_libs=
++
++ case $host_os in
++ beos*)
++ lt_cv_dlopen="load_add_on"
++ lt_cv_dlopen_libs=
++ lt_cv_dlopen_self=yes
++ ;;
++
++ mingw* | pw32* | cegcc*)
++ lt_cv_dlopen="LoadLibrary"
++ lt_cv_dlopen_libs=
++ ;;
++
++ cygwin*)
++ lt_cv_dlopen="dlopen"
++ lt_cv_dlopen_libs=
++ ;;
++
++ darwin*)
++ # if libdl is installed we need to link against it
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
++$as_echo_n "checking for dlopen in -ldl... " >&6; }
++if ${ac_cv_lib_dl_dlopen+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-ldl $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char dlopen ();
++int
++main ()
++{
++return dlopen ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_dl_dlopen=yes
++else
++ ac_cv_lib_dl_dlopen=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
++$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
++if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
++ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
++else
++
++ lt_cv_dlopen="dyld"
++ lt_cv_dlopen_libs=
++ lt_cv_dlopen_self=yes
++
++fi
++
++ ;;
++
++ *)
++ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
++if test "x$ac_cv_func_shl_load" = xyes; then :
++ lt_cv_dlopen="shl_load"
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
++$as_echo_n "checking for shl_load in -ldld... " >&6; }
++if ${ac_cv_lib_dld_shl_load+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-ldld $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char shl_load ();
++int
++main ()
++{
++return shl_load ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_dld_shl_load=yes
++else
++ ac_cv_lib_dld_shl_load=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
++$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
++if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
++ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
++else
++ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
++if test "x$ac_cv_func_dlopen" = xyes; then :
++ lt_cv_dlopen="dlopen"
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
++$as_echo_n "checking for dlopen in -ldl... " >&6; }
++if ${ac_cv_lib_dl_dlopen+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-ldl $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char dlopen ();
++int
++main ()
++{
++return dlopen ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_dl_dlopen=yes
++else
++ ac_cv_lib_dl_dlopen=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
++$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
++if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
++ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
++$as_echo_n "checking for dlopen in -lsvld... " >&6; }
++if ${ac_cv_lib_svld_dlopen+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lsvld $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char dlopen ();
++int
++main ()
++{
++return dlopen ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_svld_dlopen=yes
++else
++ ac_cv_lib_svld_dlopen=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
++$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
++if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
++ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
++$as_echo_n "checking for dld_link in -ldld... " >&6; }
++if ${ac_cv_lib_dld_dld_link+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-ldld $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char dld_link ();
++int
++main ()
++{
++return dld_link ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_dld_dld_link=yes
++else
++ ac_cv_lib_dld_dld_link=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
++$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
++if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
++ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
++fi
++
++
++fi
++
++
++fi
++
++
++fi
++
++
++fi
++
++
++fi
++
++ ;;
++ esac
++
++ if test "x$lt_cv_dlopen" != xno; then
++ enable_dlopen=yes
++ else
++ enable_dlopen=no
++ fi
++
++ case $lt_cv_dlopen in
++ dlopen)
++ save_CPPFLAGS="$CPPFLAGS"
++ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
++
++ save_LDFLAGS="$LDFLAGS"
++ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
++
++ save_LIBS="$LIBS"
++ LIBS="$lt_cv_dlopen_libs $LIBS"
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
++$as_echo_n "checking whether a program can dlopen itself... " >&6; }
++if ${lt_cv_dlopen_self+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test "$cross_compiling" = yes; then :
++ lt_cv_dlopen_self=cross
++else
++ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
++ lt_status=$lt_dlunknown
++ cat > conftest.$ac_ext <<_LT_EOF
++#line $LINENO "configure"
++#include "confdefs.h"
++
++#if HAVE_DLFCN_H
++#include <dlfcn.h>
++#endif
++
++#include <stdio.h>
++
++#ifdef RTLD_GLOBAL
++# define LT_DLGLOBAL RTLD_GLOBAL
++#else
++# ifdef DL_GLOBAL
++# define LT_DLGLOBAL DL_GLOBAL
++# else
++# define LT_DLGLOBAL 0
++# endif
++#endif
++
++/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
++ find out it does not work in some platform. */
++#ifndef LT_DLLAZY_OR_NOW
++# ifdef RTLD_LAZY
++# define LT_DLLAZY_OR_NOW RTLD_LAZY
++# else
++# ifdef DL_LAZY
++# define LT_DLLAZY_OR_NOW DL_LAZY
++# else
++# ifdef RTLD_NOW
++# define LT_DLLAZY_OR_NOW RTLD_NOW
++# else
++# ifdef DL_NOW
++# define LT_DLLAZY_OR_NOW DL_NOW
++# else
++# define LT_DLLAZY_OR_NOW 0
++# endif
++# endif
++# endif
++# endif
++#endif
++
++/* When -fvisbility=hidden is used, assume the code has been annotated
++ correspondingly for the symbols needed. */
++#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
++int fnord () __attribute__((visibility("default")));
++#endif
++
++int fnord () { return 42; }
++int main ()
++{
++ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
++ int status = $lt_dlunknown;
++
++ if (self)
++ {
++ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
++ else
++ {
++ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
++ else puts (dlerror ());
++ }
++ /* dlclose (self); */
++ }
++ else
++ puts (dlerror ());
++
++ return status;
++}
++_LT_EOF
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
++ (eval $ac_link) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
++ (./conftest; exit; ) >&5 2>/dev/null
++ lt_status=$?
++ case x$lt_status in
++ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
++ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
++ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
++ esac
++ else :
++ # compilation failed
++ lt_cv_dlopen_self=no
++ fi
++fi
++rm -fr conftest*
++
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
++$as_echo "$lt_cv_dlopen_self" >&6; }
++
++ if test "x$lt_cv_dlopen_self" = xyes; then
++ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
++$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
++if ${lt_cv_dlopen_self_static+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ if test "$cross_compiling" = yes; then :
++ lt_cv_dlopen_self_static=cross
++else
++ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
++ lt_status=$lt_dlunknown
++ cat > conftest.$ac_ext <<_LT_EOF
++#line $LINENO "configure"
++#include "confdefs.h"
++
++#if HAVE_DLFCN_H
++#include <dlfcn.h>
++#endif
++
++#include <stdio.h>
++
++#ifdef RTLD_GLOBAL
++# define LT_DLGLOBAL RTLD_GLOBAL
++#else
++# ifdef DL_GLOBAL
++# define LT_DLGLOBAL DL_GLOBAL
++# else
++# define LT_DLGLOBAL 0
++# endif
++#endif
++
++/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
++ find out it does not work in some platform. */
++#ifndef LT_DLLAZY_OR_NOW
++# ifdef RTLD_LAZY
++# define LT_DLLAZY_OR_NOW RTLD_LAZY
++# else
++# ifdef DL_LAZY
++# define LT_DLLAZY_OR_NOW DL_LAZY
++# else
++# ifdef RTLD_NOW
++# define LT_DLLAZY_OR_NOW RTLD_NOW
++# else
++# ifdef DL_NOW
++# define LT_DLLAZY_OR_NOW DL_NOW
++# else
++# define LT_DLLAZY_OR_NOW 0
++# endif
++# endif
++# endif
++# endif
++#endif
++
++/* When -fvisbility=hidden is used, assume the code has been annotated
++ correspondingly for the symbols needed. */
++#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
++int fnord () __attribute__((visibility("default")));
++#endif
++
++int fnord () { return 42; }
++int main ()
++{
++ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
++ int status = $lt_dlunknown;
++
++ if (self)
++ {
++ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
++ else
++ {
++ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
++ else puts (dlerror ());
++ }
++ /* dlclose (self); */
++ }
++ else
++ puts (dlerror ());
++
++ return status;
++}
++_LT_EOF
++ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
++ (eval $ac_link) 2>&5
++ ac_status=$?
++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
++ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
++ (./conftest; exit; ) >&5 2>/dev/null
++ lt_status=$?
++ case x$lt_status in
++ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
++ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
++ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
++ esac
++ else :
++ # compilation failed
++ lt_cv_dlopen_self_static=no
++ fi
++fi
++rm -fr conftest*
++
++
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
++$as_echo "$lt_cv_dlopen_self_static" >&6; }
++ fi
++
++ CPPFLAGS="$save_CPPFLAGS"
++ LDFLAGS="$save_LDFLAGS"
++ LIBS="$save_LIBS"
++ ;;
++ esac
++
++ case $lt_cv_dlopen_self in
++ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
++ *) enable_dlopen_self=unknown ;;
++ esac
++
++ case $lt_cv_dlopen_self_static in
++ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
++ *) enable_dlopen_self_static=unknown ;;
++ esac
++fi
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++striplib=
++old_striplib=
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
++$as_echo_n "checking whether stripping libraries is possible... " >&6; }
++if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
++ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
++ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++else
++# FIXME - insert some real tests, host_os isn't really good enough
++ case $host_os in
++ darwin*)
++ if test -n "$STRIP" ; then
++ striplib="$STRIP -x"
++ old_striplib="$STRIP -S"
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++ else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++ fi
++ ;;
++ *)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++ ;;
++ esac
++fi
++
++
++
++
++
++
++
++
++
++
++
++
++ # Report which library types will actually be built
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
++$as_echo_n "checking if libtool supports shared libraries... " >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
++$as_echo "$can_build_shared" >&6; }
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
++$as_echo_n "checking whether to build shared libraries... " >&6; }
++ test "$can_build_shared" = "no" && enable_shared=no
++
++ # On AIX, shared libraries and static libraries use the same namespace, and
++ # are all built from PIC.
++ case $host_os in
++ aix3*)
++ test "$enable_shared" = yes && enable_static=no
++ if test -n "$RANLIB"; then
++ archive_cmds="$archive_cmds~\$RANLIB \$lib"
++ postinstall_cmds='$RANLIB $lib'
++ fi
++ ;;
++
++ aix[4-9]*)
++ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++ test "$enable_shared" = yes && enable_static=no
++ fi
++ ;;
++ esac
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
++$as_echo "$enable_shared" >&6; }
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
++$as_echo_n "checking whether to build static libraries... " >&6; }
++ # Make sure either enable_shared or enable_static is yes.
++ test "$enable_shared" = yes || enable_static=yes
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
++$as_echo "$enable_static" >&6; }
++
++
++
++
++fi
++ac_ext=c
++ac_cpp='$CPP $CPPFLAGS'
++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
++ac_compiler_gnu=$ac_cv_c_compiler_gnu
++
++CC="$lt_save_CC"
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++ ac_config_commands="$ac_config_commands libtool"
++
++
++
++
++# Only expand once:
++
++
++
++
++
++
++
++
++ac_config_headers="$ac_config_headers config.h"
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5
++$as_echo_n "checking for X... " >&6; }
++
++
++# Check whether --with-x was given.
++if test "${with_x+set}" = set; then :
++ withval=$with_x;
++fi
++
++# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
++if test "x$with_x" = xno; then
++ # The user explicitly disabled X.
++ have_x=disabled
++else
++ case $x_includes,$x_libraries in #(
++ *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #(
++ *,NONE | NONE,*) if ${ac_cv_have_x+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ # One or both of the vars are not set, and there is no cached value.
++ac_x_includes=no ac_x_libraries=no
++rm -f -r conftest.dir
++if mkdir conftest.dir; then
++ cd conftest.dir
++ cat >Imakefile <<'_ACEOF'
++incroot:
++ @echo incroot='${INCROOT}'
++usrlibdir:
++ @echo usrlibdir='${USRLIBDIR}'
++libdir:
++ @echo libdir='${LIBDIR}'
++_ACEOF
++ if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then
++ # GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
++ for ac_var in incroot usrlibdir libdir; do
++ eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`"
++ done
++ # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
++ for ac_extension in a so sl dylib la dll; do
++ if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" &&
++ test -f "$ac_im_libdir/libX11.$ac_extension"; then
++ ac_im_usrlibdir=$ac_im_libdir; break
++ fi
++ done
++ # Screen out bogus values from the imake configuration. They are
++ # bogus both because they are the default anyway, and because
++ # using them would break gcc on systems where it needs fixed includes.
++ case $ac_im_incroot in
++ /usr/include) ac_x_includes= ;;
++ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;;
++ esac
++ case $ac_im_usrlibdir in
++ /usr/lib | /usr/lib64 | /lib | /lib64) ;;
++ *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;;
++ esac
++ fi
++ cd ..
++ rm -f -r conftest.dir
++fi
++
++# Standard set of common directories for X headers.
++# Check X11 before X11Rn because it is often a symlink to the current release.
++ac_x_header_dirs='
++/usr/X11/include
++/usr/X11R7/include
++/usr/X11R6/include
++/usr/X11R5/include
++/usr/X11R4/include
++
++/usr/include/X11
++/usr/include/X11R7
++/usr/include/X11R6
++/usr/include/X11R5
++/usr/include/X11R4
++
++/usr/local/X11/include
++/usr/local/X11R7/include
++/usr/local/X11R6/include
++/usr/local/X11R5/include
++/usr/local/X11R4/include
++
++/usr/local/include/X11
++/usr/local/include/X11R7
++/usr/local/include/X11R6
++/usr/local/include/X11R5
++/usr/local/include/X11R4
++
++/usr/X386/include
++/usr/x386/include
++/usr/XFree86/include/X11
++
++/usr/include
++/usr/local/include
++/usr/unsupported/include
++/usr/athena/include
++/usr/local/x11r5/include
++/usr/lpp/Xamples/include
++
++/usr/openwin/include
++/usr/openwin/share/include'
++
++if test "$ac_x_includes" = no; then
++ # Guess where to find include files, by looking for Xlib.h.
++ # First, try using that file with no special directory specified.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <X11/Xlib.h>
++_ACEOF
++if ac_fn_c_try_cpp "$LINENO"; then :
++ # We can compile using X headers with no special include directory.
++ac_x_includes=
++else
++ for ac_dir in $ac_x_header_dirs; do
++ if test -r "$ac_dir/X11/Xlib.h"; then
++ ac_x_includes=$ac_dir
++ break
++ fi
++done
++fi
++rm -f conftest.err conftest.i conftest.$ac_ext
++fi # $ac_x_includes = no
++
++if test "$ac_x_libraries" = no; then
++ # Check for the libraries.
++ # See if we find them without any special options.
++ # Don't add to $LIBS permanently.
++ ac_save_LIBS=$LIBS
++ LIBS="-lX11 $LIBS"
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <X11/Xlib.h>
++int
++main ()
++{
++XrmInitialize ()
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ LIBS=$ac_save_LIBS
++# We can link X programs with no special library path.
++ac_x_libraries=
++else
++ LIBS=$ac_save_LIBS
++for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g`
++do
++ # Don't even attempt the hair of trying to link an X program!
++ for ac_extension in a so sl dylib la dll; do
++ if test -r "$ac_dir/libX11.$ac_extension"; then
++ ac_x_libraries=$ac_dir
++ break 2
++ fi
++ done
++done
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++fi # $ac_x_libraries = no
++
++case $ac_x_includes,$ac_x_libraries in #(
++ no,* | *,no | *\'*)
++ # Didn't find X, or a directory has "'" in its name.
++ ac_cv_have_x="have_x=no";; #(
++ *)
++ # Record where we found X for the cache.
++ ac_cv_have_x="have_x=yes\
++ ac_x_includes='$ac_x_includes'\
++ ac_x_libraries='$ac_x_libraries'"
++esac
++fi
++;; #(
++ *) have_x=yes;;
++ esac
++ eval "$ac_cv_have_x"
++fi # $with_x != no
++
++if test "$have_x" != yes; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5
++$as_echo "$have_x" >&6; }
++ no_x=yes
++else
++ # If each of the values was on the command line, it overrides each guess.
++ test "x$x_includes" = xNONE && x_includes=$ac_x_includes
++ test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
++ # Update the cache value to reflect the command line values.
++ ac_cv_have_x="have_x=yes\
++ ac_x_includes='$x_includes'\
++ ac_x_libraries='$x_libraries'"
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5
++$as_echo "libraries $x_libraries, headers $x_includes" >&6; }
++fi
++
++if test "$no_x" = yes; then
++ # Not all programs may use this symbol, but it does not hurt to define it.
++
++$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h
++
++ X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
++else
++ if test -n "$x_includes"; then
++ X_CFLAGS="$X_CFLAGS -I$x_includes"
++ fi
++
++ # It would also be nice to do this for all -L options, not just this one.
++ if test -n "$x_libraries"; then
++ X_LIBS="$X_LIBS -L$x_libraries"
++ # For Solaris; some versions of Sun CC require a space after -R and
++ # others require no space. Words are not sufficient . . . .
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5
++$as_echo_n "checking whether -R must be followed by a space... " >&6; }
++ ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
++ ac_xsave_c_werror_flag=$ac_c_werror_flag
++ ac_c_werror_flag=yes
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++ X_LIBS="$X_LIBS -R$x_libraries"
++else
++ LIBS="$ac_xsave_LIBS -R $x_libraries"
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++int
++main ()
++{
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++ X_LIBS="$X_LIBS -R $x_libraries"
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5
++$as_echo "neither works" >&6; }
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ ac_c_werror_flag=$ac_xsave_c_werror_flag
++ LIBS=$ac_xsave_LIBS
++ fi
++
++ # Check for system-dependent libraries X programs must link with.
++ # Do this before checking for the system-independent R6 libraries
++ # (-lICE), since we may need -lsocket or whatever for X linking.
++
++ if test "$ISC" = yes; then
++ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
++ else
++ # Martyn Johnson says this is needed for Ultrix, if the X
++ # libraries were built with DECnet support. And Karl Berry says
++ # the Alpha needs dnet_stub (dnet does not exist).
++ ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11"
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char XOpenDisplay ();
++int
++main ()
++{
++return XOpenDisplay ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5
++$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; }
++if ${ac_cv_lib_dnet_dnet_ntoa+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-ldnet $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char dnet_ntoa ();
++int
++main ()
++{
++return dnet_ntoa ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_dnet_dnet_ntoa=yes
++else
++ ac_cv_lib_dnet_dnet_ntoa=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5
++$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; }
++if test "x$ac_cv_lib_dnet_dnet_ntoa" = xyes; then :
++ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
++fi
++
++ if test $ac_cv_lib_dnet_dnet_ntoa = no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5
++$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; }
++if ${ac_cv_lib_dnet_stub_dnet_ntoa+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-ldnet_stub $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char dnet_ntoa ();
++int
++main ()
++{
++return dnet_ntoa ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_dnet_stub_dnet_ntoa=yes
++else
++ ac_cv_lib_dnet_stub_dnet_ntoa=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5
++$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; }
++if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = xyes; then :
++ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
++fi
++
++ fi
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++ LIBS="$ac_xsave_LIBS"
++
++ # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
++ # to get the SysV transport functions.
++ # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4)
++ # needs -lnsl.
++ # The nsl library prevents programs from opening the X display
++ # on Irix 5.2, according to T.E. Dickey.
++ # The functions gethostbyname, getservbyname, and inet_addr are
++ # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking.
++ ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
++if test "x$ac_cv_func_gethostbyname" = xyes; then :
++
++fi
++
++ if test $ac_cv_func_gethostbyname = no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
++$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
++if ${ac_cv_lib_nsl_gethostbyname+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lnsl $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char gethostbyname ();
++int
++main ()
++{
++return gethostbyname ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_nsl_gethostbyname=yes
++else
++ ac_cv_lib_nsl_gethostbyname=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
++$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
++if test "x$ac_cv_lib_nsl_gethostbyname" = xyes; then :
++ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
++fi
++
++ if test $ac_cv_lib_nsl_gethostbyname = no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5
++$as_echo_n "checking for gethostbyname in -lbsd... " >&6; }
++if ${ac_cv_lib_bsd_gethostbyname+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lbsd $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char gethostbyname ();
++int
++main ()
++{
++return gethostbyname ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_bsd_gethostbyname=yes
++else
++ ac_cv_lib_bsd_gethostbyname=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5
++$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; }
++if test "x$ac_cv_lib_bsd_gethostbyname" = xyes; then :
++ X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd"
++fi
++
++ fi
++ fi
++
++ # lieder@skyler.mavd.honeywell.com says without -lsocket,
++ # socket/setsockopt and other routines are undefined under SCO ODT
++ # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary
++ # on later versions), says Simon Leinen: it contains gethostby*
++ # variants that don't use the name server (or something). -lsocket
++ # must be given before -lnsl if both are needed. We assume that
++ # if connect needs -lnsl, so does gethostbyname.
++ ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
++if test "x$ac_cv_func_connect" = xyes; then :
++
++fi
++
++ if test $ac_cv_func_connect = no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5
++$as_echo_n "checking for connect in -lsocket... " >&6; }
++if ${ac_cv_lib_socket_connect+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char connect ();
++int
++main ()
++{
++return connect ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_socket_connect=yes
++else
++ ac_cv_lib_socket_connect=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5
++$as_echo "$ac_cv_lib_socket_connect" >&6; }
++if test "x$ac_cv_lib_socket_connect" = xyes; then :
++ X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
++fi
++
++ fi
++
++ # Guillermo Gomez says -lposix is necessary on A/UX.
++ ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove"
++if test "x$ac_cv_func_remove" = xyes; then :
++
++fi
++
++ if test $ac_cv_func_remove = no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5
++$as_echo_n "checking for remove in -lposix... " >&6; }
++if ${ac_cv_lib_posix_remove+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lposix $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char remove ();
++int
++main ()
++{
++return remove ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_posix_remove=yes
++else
++ ac_cv_lib_posix_remove=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5
++$as_echo "$ac_cv_lib_posix_remove" >&6; }
++if test "x$ac_cv_lib_posix_remove" = xyes; then :
++ X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
++fi
++
++ fi
++
++ # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
++ ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat"
++if test "x$ac_cv_func_shmat" = xyes; then :
++
++fi
++
++ if test $ac_cv_func_shmat = no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5
++$as_echo_n "checking for shmat in -lipc... " >&6; }
++if ${ac_cv_lib_ipc_shmat+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lipc $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char shmat ();
++int
++main ()
++{
++return shmat ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_ipc_shmat=yes
++else
++ ac_cv_lib_ipc_shmat=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5
++$as_echo "$ac_cv_lib_ipc_shmat" >&6; }
++if test "x$ac_cv_lib_ipc_shmat" = xyes; then :
++ X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
++fi
++
++ fi
++ fi
++
++ # Check for libraries that X11R6 Xt/Xaw programs need.
++ ac_save_LDFLAGS=$LDFLAGS
++ test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
++ # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
++ # check for ICE first), but we must link in the order -lSM -lICE or
++ # we get undefined symbols. So assume we have SM if we have ICE.
++ # These have to be linked with before -lX11, unlike the other
++ # libraries we check for below, so use a different variable.
++ # John Interrante, Karl Berry
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5
++$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; }
++if ${ac_cv_lib_ICE_IceConnectionNumber+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lICE $X_EXTRA_LIBS $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char IceConnectionNumber ();
++int
++main ()
++{
++return IceConnectionNumber ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_ICE_IceConnectionNumber=yes
++else
++ ac_cv_lib_ICE_IceConnectionNumber=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5
++$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; }
++if test "x$ac_cv_lib_ICE_IceConnectionNumber" = xyes; then :
++ X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
++fi
++
++ LDFLAGS=$ac_save_LDFLAGS
++
++fi
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrt in -lm" >&5
++$as_echo_n "checking for sqrt in -lm... " >&6; }
++if ${ac_cv_lib_m_sqrt+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lm $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char sqrt ();
++int
++main ()
++{
++return sqrt ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_m_sqrt=yes
++else
++ ac_cv_lib_m_sqrt=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrt" >&5
++$as_echo "$ac_cv_lib_m_sqrt" >&6; }
++if test "x$ac_cv_lib_m_sqrt" = xyes; then :
++ cat >>confdefs.h <<_ACEOF
++#define HAVE_LIBM 1
++_ACEOF
++
++ LIBS="-lm $LIBS"
++
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
++$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
++if ${ac_cv_lib_pthread_pthread_create+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lpthread $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char pthread_create ();
++int
++main ()
++{
++return pthread_create ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_pthread_pthread_create=yes
++else
++ ac_cv_lib_pthread_pthread_create=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
++$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
++if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
++ cat >>confdefs.h <<_ACEOF
++#define HAVE_LIBPTHREAD 1
++_ACEOF
++
++ LIBS="-lpthread $LIBS"
++
++fi
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TIFFOpen in -ltiff" >&5
++$as_echo_n "checking for TIFFOpen in -ltiff... " >&6; }
++if ${ac_cv_lib_tiff_TIFFOpen+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-ltiff -lm $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char TIFFOpen ();
++int
++main ()
++{
++return TIFFOpen ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_tiff_TIFFOpen=yes
++else
++ ac_cv_lib_tiff_TIFFOpen=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_tiff_TIFFOpen" >&5
++$as_echo "$ac_cv_lib_tiff_TIFFOpen" >&6; }
++if test "x$ac_cv_lib_tiff_TIFFOpen" = xyes; then :
++ TIFF_LIBS="-ltiff"
++fi
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
++$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
++if ${ac_cv_lib_rt_clock_gettime+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lrt $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char clock_gettime ();
++int
++main ()
++{
++return clock_gettime ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_rt_clock_gettime=yes
++else
++ ac_cv_lib_rt_clock_gettime=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
++$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
++if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
++ cat >>confdefs.h <<_ACEOF
++#define HAVE_LIBRT 1
++_ACEOF
++
++ LIBS="-lrt $LIBS"
++
++fi
++
++
++
++# Check whether --with-system-libicc was given.
++if test "${with_system_libicc+set}" = set; then :
++ withval=$with_system_libicc; system_libicc=$withval
++else
++ system_libicc=no
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use system libicc or not" >&5
++$as_echo_n "checking whether to use system libicc or not... " >&6; }
++if test x$system_libicc = xno ; then
++ HAVE_ICC=false
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for new_icmFileStd_name in -licc" >&5
++$as_echo_n "checking for new_icmFileStd_name in -licc... " >&6; }
++if ${ac_cv_lib_icc_new_icmFileStd_name+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-licc -lm $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char new_icmFileStd_name ();
++int
++main ()
++{
++return new_icmFileStd_name ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_icc_new_icmFileStd_name=yes
++else
++ ac_cv_lib_icc_new_icmFileStd_name=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_icc_new_icmFileStd_name" >&5
++$as_echo "$ac_cv_lib_icc_new_icmFileStd_name" >&6; }
++if test "x$ac_cv_lib_icc_new_icmFileStd_name" = xyes; then :
++ HAVE_ICC="true"
++fi
++
++ if test "$HAVE_ICC" != "true" ; then
++ as_fn_error $? "system libicc missing or not compatible with argyllcms" "$LINENO" 5
++ fi
++fi
++if test "$HAVE_ICC" = "true" ; then
++ ICC_LIBS="-licc"
++else
++ ICC_LIBS='$(top_srcdir)/icc/libicc.la'
++ ICC_CFLAGS='-I$(top_srcdir)/icc'
++ ICC_SUBDIRS='icc'
++fi
++
++
++
++
++
++# Check whether --with-system-libyajl was given.
++if test "${with_system_libyajl+set}" = set; then :
++ withval=$with_system_libyajl; system_libyajl=$withval
++else
++ system_libyajl=no
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use system libyajl or not" >&5
++$as_echo_n "checking whether to use system libyajl or not... " >&6; }
++if test x$system_libyajl = xno ; then
++ HAVE_YAJL=false
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for yajl_gen_c_comment in -lyajl" >&5
++$as_echo_n "checking for yajl_gen_c_comment in -lyajl... " >&6; }
++if ${ac_cv_lib_yajl_yajl_gen_c_comment+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lyajl -lm $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char yajl_gen_c_comment ();
++int
++main ()
++{
++return yajl_gen_c_comment ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_yajl_yajl_gen_c_comment=yes
++else
++ ac_cv_lib_yajl_yajl_gen_c_comment=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_yajl_yajl_gen_c_comment" >&5
++$as_echo "$ac_cv_lib_yajl_yajl_gen_c_comment" >&6; }
++if test "x$ac_cv_lib_yajl_yajl_gen_c_comment" = xyes; then :
++ HAVE_YAJL="true"
++fi
++
++ if test "$HAVE_YAJL" != "true" ; then
++ as_fn_error $? "system libyajl missing or not compatible with argyllcms" "$LINENO" 5
++ fi
++fi
++if test "$HAVE_YAJL" = "true" ; then
++ YAJL_LIBS="-lyajl"
++else
++ YAJL_LIBS='$(top_srcdir)/jcnf/yajl/libyajl.la'
++ YAJL_CFLAGS='-I$(top_srcdir)/jcnf/yajl'
++ YAJL_SUBDIRS='yajl'
++fi
++
++
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XOpenDisplay in -lX11" >&5
++$as_echo_n "checking for XOpenDisplay in -lX11... " >&6; }
++if ${ac_cv_lib_X11_XOpenDisplay+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lX11 $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char XOpenDisplay ();
++int
++main ()
++{
++return XOpenDisplay ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_X11_XOpenDisplay=yes
++else
++ ac_cv_lib_X11_XOpenDisplay=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_X11_XOpenDisplay" >&5
++$as_echo "$ac_cv_lib_X11_XOpenDisplay" >&6; }
++if test "x$ac_cv_lib_X11_XOpenDisplay" = xyes; then :
++ X_LIBS="$X_LIBS -lX11"
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XextFindDisplay in -lXext" >&5
++$as_echo_n "checking for XextFindDisplay in -lXext... " >&6; }
++if ${ac_cv_lib_Xext_XextFindDisplay+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lXext -lX11 $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char XextFindDisplay ();
++int
++main ()
++{
++return XextFindDisplay ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_Xext_XextFindDisplay=yes
++else
++ ac_cv_lib_Xext_XextFindDisplay=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XextFindDisplay" >&5
++$as_echo "$ac_cv_lib_Xext_XextFindDisplay" >&6; }
++if test "x$ac_cv_lib_Xext_XextFindDisplay" = xyes; then :
++ X_LIBS="$X_LIBS -lXext"
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XScreenSaverSuspend in -lXss" >&5
++$as_echo_n "checking for XScreenSaverSuspend in -lXss... " >&6; }
++if ${ac_cv_lib_Xss_XScreenSaverSuspend+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lXss -lXext -lX11 $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char XScreenSaverSuspend ();
++int
++main ()
++{
++return XScreenSaverSuspend ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_Xss_XScreenSaverSuspend=yes
++else
++ ac_cv_lib_Xss_XScreenSaverSuspend=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xss_XScreenSaverSuspend" >&5
++$as_echo "$ac_cv_lib_Xss_XScreenSaverSuspend" >&6; }
++if test "x$ac_cv_lib_Xss_XScreenSaverSuspend" = xyes; then :
++ X_LIBS="$X_LIBS -lXss"
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XRRRootToScreen in -lXrandr" >&5
++$as_echo_n "checking for XRRRootToScreen in -lXrandr... " >&6; }
++if ${ac_cv_lib_Xrandr_XRRRootToScreen+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lXrandr -LXext -lX11 $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char XRRRootToScreen ();
++int
++main ()
++{
++return XRRRootToScreen ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_Xrandr_XRRRootToScreen=yes
++else
++ ac_cv_lib_Xrandr_XRRRootToScreen=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xrandr_XRRRootToScreen" >&5
++$as_echo "$ac_cv_lib_Xrandr_XRRRootToScreen" >&6; }
++if test "x$ac_cv_lib_Xrandr_XRRRootToScreen" = xyes; then :
++ X_LIBS="$X_LIBS -lXrandr"
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XineramaQueryScreens in -lXinerama" >&5
++$as_echo_n "checking for XineramaQueryScreens in -lXinerama... " >&6; }
++if ${ac_cv_lib_Xinerama_XineramaQueryScreens+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lXinerama -LXext -lX11 $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char XineramaQueryScreens ();
++int
++main ()
++{
++return XineramaQueryScreens ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_Xinerama_XineramaQueryScreens=yes
++else
++ ac_cv_lib_Xinerama_XineramaQueryScreens=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xinerama_XineramaQueryScreens" >&5
++$as_echo "$ac_cv_lib_Xinerama_XineramaQueryScreens" >&6; }
++if test "x$ac_cv_lib_Xinerama_XineramaQueryScreens" = xyes; then :
++ X_LIBS="$X_LIBS -lXinerama"
++fi
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for XF86VidModeGetGamma in -lXxf86vm" >&5
++$as_echo_n "checking for XF86VidModeGetGamma in -lXxf86vm... " >&6; }
++if ${ac_cv_lib_Xxf86vm_XF86VidModeGetGamma+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_check_lib_save_LIBS=$LIBS
++LIBS="-lXxf86vm -lXext -lX11 $LIBS"
++cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++
++/* Override any GCC internal prototype to avoid an error.
++ Use char because int might match the return type of a GCC
++ builtin and then its argument prototype would still apply. */
++#ifdef __cplusplus
++extern "C"
++#endif
++char XF86VidModeGetGamma ();
++int
++main ()
++{
++return XF86VidModeGetGamma ();
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_link "$LINENO"; then :
++ ac_cv_lib_Xxf86vm_XF86VidModeGetGamma=yes
++else
++ ac_cv_lib_Xxf86vm_XF86VidModeGetGamma=no
++fi
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
++LIBS=$ac_check_lib_save_LIBS
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xxf86vm_XF86VidModeGetGamma" >&5
++$as_echo "$ac_cv_lib_Xxf86vm_XF86VidModeGetGamma" >&6; }
++if test "x$ac_cv_lib_Xxf86vm_XF86VidModeGetGamma" = xyes; then :
++ X_LIBS="$X_LIBS -lXxf86vm"
++fi
++
++
++
++
++
++case $host in
++ *-linux*)
++ OS_LINUX=1
++ OS_BSD=0
++
++$as_echo "#define OS_LINUX 1" >>confdefs.h
++
++ if true; then
++ OS_LINUX_TRUE=
++ OS_LINUX_FALSE='#'
++else
++ OS_LINUX_TRUE='#'
++ OS_LINUX_FALSE=
++fi
++
++ ;;
++ *-freebsd*|*-kfreebsd*-gnu|*-openbsd*|*-netbsd*)
++ OS_LINUX=0
++ OS_BSD=1
++
++$as_echo "#define OS_LINUX 0" >>confdefs.h
++
++ if false; then
++ OS_LINUX_TRUE=
++ OS_LINUX_FALSE='#'
++else
++ OS_LINUX_TRUE='#'
++ OS_LINUX_FALSE=
++fi
++
++ ;;
++ *)
++ OS_LINUX=0
++ OS_BSD=0
++
++$as_echo "#define OS_LINUX 0" >>confdefs.h
++
++ if false; then
++ OS_LINUX_TRUE=
++ OS_LINUX_FALSE='#'
++else
++ OS_LINUX_TRUE='#'
++ OS_LINUX_FALSE=
++fi
++
++ ;;
++esac
++
++$as_echo "#define API_EXPORTED /**/" >>confdefs.h
++
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
++$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
++if ${ac_cv_c_bigendian+:} false; then :
++ $as_echo_n "(cached) " >&6
++else
++ ac_cv_c_bigendian=unknown
++ # See if we're dealing with a universal compiler.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#ifndef __APPLE_CC__
++ not a universal capable compiler
++ #endif
++ typedef int dummy;
++
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++
++ # Check for potential -arch flags. It is not universal unless
++ # there are at least two -arch flags with different values.
++ ac_arch=
++ ac_prev=
++ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
++ if test -n "$ac_prev"; then
++ case $ac_word in
++ i?86 | x86_64 | ppc | ppc64)
++ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
++ ac_arch=$ac_word
++ else
++ ac_cv_c_bigendian=universal
++ break
++ fi
++ ;;
++ esac
++ ac_prev=
++ elif test "x$ac_word" = "x-arch"; then
++ ac_prev=arch
++ fi
++ done
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++ if test $ac_cv_c_bigendian = unknown; then
++ # See if sys/param.h defines the BYTE_ORDER macro.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <sys/types.h>
++ #include <sys/param.h>
++
++int
++main ()
++{
++#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
++ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
++ && LITTLE_ENDIAN)
++ bogus endian macros
++ #endif
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ # It does; now see whether it defined to BIG_ENDIAN or not.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <sys/types.h>
++ #include <sys/param.h>
++
++int
++main ()
++{
++#if BYTE_ORDER != BIG_ENDIAN
++ not big endian
++ #endif
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ ac_cv_c_bigendian=yes
++else
++ ac_cv_c_bigendian=no
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++ fi
++ if test $ac_cv_c_bigendian = unknown; then
++ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <limits.h>
++
++int
++main ()
++{
++#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
++ bogus endian macros
++ #endif
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ # It does; now see whether it defined to _BIG_ENDIAN or not.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++#include <limits.h>
++
++int
++main ()
++{
++#ifndef _BIG_ENDIAN
++ not big endian
++ #endif
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ ac_cv_c_bigendian=yes
++else
++ ac_cv_c_bigendian=no
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++ fi
++ if test $ac_cv_c_bigendian = unknown; then
++ # Compile a test program.
++ if test "$cross_compiling" = yes; then :
++ # Try to guess by grepping values from an object file.
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++short int ascii_mm[] =
++ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
++ short int ascii_ii[] =
++ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
++ int use_ascii (int i) {
++ return ascii_mm[i] + ascii_ii[i];
++ }
++ short int ebcdic_ii[] =
++ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
++ short int ebcdic_mm[] =
++ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
++ int use_ebcdic (int i) {
++ return ebcdic_mm[i] + ebcdic_ii[i];
++ }
++ extern int foo;
++
++int
++main ()
++{
++return use_ascii (foo) == use_ebcdic (foo);
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_compile "$LINENO"; then :
++ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
++ ac_cv_c_bigendian=yes
++ fi
++ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
++ if test "$ac_cv_c_bigendian" = unknown; then
++ ac_cv_c_bigendian=no
++ else
++ # finding both strings is unlikely to happen, but who knows?
++ ac_cv_c_bigendian=unknown
++ fi
++ fi
++fi
++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++else
++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
++/* end confdefs.h. */
++$ac_includes_default
++int
++main ()
++{
++
++ /* Are we little or big endian? From Harbison&Steele. */
++ union
++ {
++ long int l;
++ char c[sizeof (long int)];
++ } u;
++ u.l = 1;
++ return u.c[sizeof (long int) - 1] == 1;
++
++ ;
++ return 0;
++}
++_ACEOF
++if ac_fn_c_try_run "$LINENO"; then :
++ ac_cv_c_bigendian=no
++else
++ ac_cv_c_bigendian=yes
++fi
++rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
++ conftest.$ac_objext conftest.beam conftest.$ac_ext
++fi
++
++ fi
++fi
++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
++$as_echo "$ac_cv_c_bigendian" >&6; }
++ case $ac_cv_c_bigendian in #(
++ yes)
++ $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
++;; #(
++ no)
++ ;; #(
++ universal)
++
++$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
++
++ ;; #(
++ *)
++ as_fn_error $? "unknown endianness
++ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
++ esac
++
++if test "$ac_cv_c_bigendian" = "yes"; then
++ BIGENDIAN="1"
++else
++ BIGENDIAN="0"
++fi
++
++
++ac_config_files="$ac_config_files Makefile h/Makefile doc/Makefile ref/Makefile numlib/Makefile cgats/Makefile plot/Makefile rspl/Makefile icc/Makefile gamut/Makefile xicc/Makefile link/Makefile spectro/Makefile profile/Makefile tweak/Makefile scanin/Makefile render/Makefile target/Makefile imdi/Makefile jcnf/Makefile jcnf/yajl/Makefile ucmm/Makefile"
++
++
++cat >confcache <<\_ACEOF
++# This file is a shell script that caches the results of configure
++# tests run on this system so they can be shared between configure
++# scripts and configure runs, see configure's option --config-cache.
++# It is not useful on other systems. If it contains results you don't
++# want to keep, you may remove or edit it.
++#
++# config.status only pays attention to the cache file if you give it
++# the --recheck option to rerun configure.
++#
++# `ac_cv_env_foo' variables (set or unset) will be overridden when
++# loading this file, other *unset* `ac_cv_foo' will be assigned the
++# following values.
++
++_ACEOF
++
++# The following way of writing the cache mishandles newlines in values,
++# but we know of no workaround that is simple, portable, and efficient.
++# So, we kill variables containing newlines.
++# Ultrix sh set writes to stderr and can't be redirected directly,
++# and sets the high bit in the cache file unless we assign to the vars.
++(
++ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
++ eval ac_val=\$$ac_var
++ case $ac_val in #(
++ *${as_nl}*)
++ case $ac_var in #(
++ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
++$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
++ esac
++ case $ac_var in #(
++ _ | IFS | as_nl) ;; #(
++ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
++ *) { eval $ac_var=; unset $ac_var;} ;;
++ esac ;;
++ esac
++ done
++
++ (set) 2>&1 |
++ case $as_nl`(ac_space=' '; set) 2>&1` in #(
++ *${as_nl}ac_space=\ *)
++ # `set' does not quote correctly, so add quotes: double-quote
++ # substitution turns \\\\ into \\, and sed turns \\ into \.
++ sed -n \
++ "s/'/'\\\\''/g;
++ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
++ ;; #(
++ *)
++ # `set' quotes correctly as required by POSIX, so do not add quotes.
++ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
++ ;;
++ esac |
++ sort
++) |
++ sed '
++ /^ac_cv_env_/b end
++ t clear
++ :clear
++ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
++ t end
++ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
++ :end' >>confcache
++if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
++ if test -w "$cache_file"; then
++ if test "x$cache_file" != "x/dev/null"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
++$as_echo "$as_me: updating cache $cache_file" >&6;}
++ if test ! -f "$cache_file" || test -h "$cache_file"; then
++ cat confcache >"$cache_file"
++ else
++ case $cache_file in #(
++ */* | ?:*)
++ mv -f confcache "$cache_file"$$ &&
++ mv -f "$cache_file"$$ "$cache_file" ;; #(
++ *)
++ mv -f confcache "$cache_file" ;;
++ esac
++ fi
++ fi
++ else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
++$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
++ fi
++fi
++rm -f confcache
++
++test "x$prefix" = xNONE && prefix=$ac_default_prefix
++# Let make expand exec_prefix.
++test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
++
++DEFS=-DHAVE_CONFIG_H
++
++ac_libobjs=
++ac_ltlibobjs=
++for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
++ # 1. Remove the extension, and $U if already installed.
++ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
++ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
++ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
++ # will be set to the directory where LIBOBJS objects are built.
++ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
++ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
++done
++LIBOBJS=$ac_libobjs
++
++LTLIBOBJS=$ac_ltlibobjs
++
++
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
++$as_echo_n "checking that generated files are newer than configure... " >&6; }
++ if test -n "$am_sleep_pid"; then
++ # Hide warnings about reused PIDs.
++ wait $am_sleep_pid 2>/dev/null
++ fi
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
++$as_echo "done" >&6; }
++ if test -n "$EXEEXT"; then
++ am__EXEEXT_TRUE=
++ am__EXEEXT_FALSE='#'
++else
++ am__EXEEXT_TRUE='#'
++ am__EXEEXT_FALSE=
++fi
++
++if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
++ as_fn_error $? "conditional \"AMDEP\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
++fi
++if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
++ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
++fi
++if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then
++ as_fn_error $? "conditional \"OS_LINUX\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
++fi
++if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then
++ as_fn_error $? "conditional \"OS_LINUX\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
++fi
++if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then
++ as_fn_error $? "conditional \"OS_LINUX\" was never defined.
++Usually this means the macro was only invoked conditionally." "$LINENO" 5
++fi
++
++
++: "${CONFIG_STATUS=./config.status}"
++ac_write_fail=0
++ac_clean_files_save=$ac_clean_files
++ac_clean_files="$ac_clean_files $CONFIG_STATUS"
++{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
++$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
++as_write_fail=0
++cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
++#! $SHELL
++# Generated by $as_me.
++# Run this file to recreate the current configuration.
++# Compiler output produced by configure, useful for debugging
++# configure, is in config.log if it exists.
++
++debug=false
++ac_cs_recheck=false
++ac_cs_silent=false
++
++SHELL=\${CONFIG_SHELL-$SHELL}
++export SHELL
++_ASEOF
++cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
++## -------------------- ##
++## M4sh Initialization. ##
++## -------------------- ##
++
++# Be more Bourne compatible
++DUALCASE=1; export DUALCASE # for MKS sh
++if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
++ emulate sh
++ NULLCMD=:
++ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
++ # is contrary to our usage. Disable this feature.
++ alias -g '${1+"$@"}'='"$@"'
++ setopt NO_GLOB_SUBST
++else
++ case `(set -o) 2>/dev/null` in #(
++ *posix*) :
++ set -o posix ;; #(
++ *) :
++ ;;
++esac
++fi
++
++
++as_nl='
++'
++export as_nl
++# Printing a long string crashes Solaris 7 /usr/bin/printf.
++as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
++as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
++# Prefer a ksh shell builtin over an external printf program on Solaris,
++# but without wasting forks for bash or zsh.
++if test -z "$BASH_VERSION$ZSH_VERSION" \
++ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='print -r --'
++ as_echo_n='print -rn --'
++elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
++ as_echo='printf %s\n'
++ as_echo_n='printf %s'
++else
++ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
++ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
++ as_echo_n='/usr/ucb/echo -n'
++ else
++ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
++ as_echo_n_body='eval
++ arg=$1;
++ case $arg in #(
++ *"$as_nl"*)
++ expr "X$arg" : "X\\(.*\\)$as_nl";
++ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
++ esac;
++ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
++ '
++ export as_echo_n_body
++ as_echo_n='sh -c $as_echo_n_body as_echo'
++ fi
++ export as_echo_body
++ as_echo='sh -c $as_echo_body as_echo'
++fi
++
++# The user is always right.
++if test "${PATH_SEPARATOR+set}" != set; then
++ PATH_SEPARATOR=:
++ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
++ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
++ PATH_SEPARATOR=';'
++ }
++fi
++
++
++# IFS
++# We need space, tab and new line, in precisely that order. Quoting is
++# there to prevent editors from complaining about space-tab.
++# (If _AS_PATH_WALK were called with IFS unset, it would disable word
++# splitting by setting IFS to empty value.)
++IFS=" "" $as_nl"
++
++# Find who we are. Look in the path if we contain no directory separator.
++as_myself=
++case $0 in #((
++ *[\\/]* ) as_myself=$0 ;;
++ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
++ done
++IFS=$as_save_IFS
++
++ ;;
++esac
++# We did not find ourselves, most probably we were run as `sh COMMAND'
++# in which case we are not to be found in the path.
++if test "x$as_myself" = x; then
++ as_myself=$0
++fi
++if test ! -f "$as_myself"; then
++ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
++ exit 1
++fi
++
++# Unset variables that we do not need and which cause bugs (e.g. in
++# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
++# suppresses any "Segmentation fault" message there. '((' could
++# trigger a bug in pdksh 5.2.14.
++for as_var in BASH_ENV ENV MAIL MAILPATH
++do eval test x\${$as_var+set} = xset \
++ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
++done
++PS1='$ '
++PS2='> '
++PS4='+ '
++
++# NLS nuisances.
++LC_ALL=C
++export LC_ALL
++LANGUAGE=C
++export LANGUAGE
++
++# CDPATH.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
++
++
++# as_fn_error STATUS ERROR [LINENO LOG_FD]
++# ----------------------------------------
++# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
++# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
++# script with STATUS, using 1 if that was 0.
++as_fn_error ()
++{
++ as_status=$1; test $as_status -eq 0 && as_status=1
++ if test "$4"; then
++ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
++ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
++ fi
++ $as_echo "$as_me: error: $2" >&2
++ as_fn_exit $as_status
++} # as_fn_error
++
++
++# as_fn_set_status STATUS
++# -----------------------
++# Set $? to STATUS, without forking.
++as_fn_set_status ()
++{
++ return $1
++} # as_fn_set_status
++
++# as_fn_exit STATUS
++# -----------------
++# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
++as_fn_exit ()
++{
++ set +e
++ as_fn_set_status $1
++ exit $1
++} # as_fn_exit
++
++# as_fn_unset VAR
++# ---------------
++# Portably unset VAR.
++as_fn_unset ()
++{
++ { eval $1=; unset $1;}
++}
++as_unset=as_fn_unset
++# as_fn_append VAR VALUE
++# ----------------------
++# Append the text in VALUE to the end of the definition contained in VAR. Take
++# advantage of any shell optimizations that allow amortized linear growth over
++# repeated appends, instead of the typical quadratic growth present in naive
++# implementations.
++if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
++ eval 'as_fn_append ()
++ {
++ eval $1+=\$2
++ }'
++else
++ as_fn_append ()
++ {
++ eval $1=\$$1\$2
++ }
++fi # as_fn_append
++
++# as_fn_arith ARG...
++# ------------------
++# Perform arithmetic evaluation on the ARGs, and store the result in the
++# global $as_val. Take advantage of shells that can avoid forks. The arguments
++# must be portable across $(()) and expr.
++if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
++ eval 'as_fn_arith ()
++ {
++ as_val=$(( $* ))
++ }'
++else
++ as_fn_arith ()
++ {
++ as_val=`expr "$@" || test $? -eq 1`
++ }
++fi # as_fn_arith
++
++
++if expr a : '\(a\)' >/dev/null 2>&1 &&
++ test "X`expr 00001 : '.*\(...\)'`" = X001; then
++ as_expr=expr
++else
++ as_expr=false
++fi
++
++if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
++ as_basename=basename
++else
++ as_basename=false
++fi
++
++if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
++ as_dirname=dirname
++else
++ as_dirname=false
++fi
++
++as_me=`$as_basename -- "$0" ||
++$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
++ X"$0" : 'X\(//\)$' \| \
++ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X/"$0" |
++ sed '/^.*\/\([^/][^/]*\)\/*$/{
++ s//\1/
++ q
++ }
++ /^X\/\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\/\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++
++# Avoid depending upon Character Ranges.
++as_cr_letters='abcdefghijklmnopqrstuvwxyz'
++as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
++as_cr_Letters=$as_cr_letters$as_cr_LETTERS
++as_cr_digits='0123456789'
++as_cr_alnum=$as_cr_Letters$as_cr_digits
++
++ECHO_C= ECHO_N= ECHO_T=
++case `echo -n x` in #(((((
++-n*)
++ case `echo 'xy\c'` in
++ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
++ xy) ECHO_C='\c';;
++ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
++ ECHO_T=' ';;
++ esac;;
++*)
++ ECHO_N='-n';;
++esac
++
++rm -f conf$$ conf$$.exe conf$$.file
++if test -d conf$$.dir; then
++ rm -f conf$$.dir/conf$$.file
++else
++ rm -f conf$$.dir
++ mkdir conf$$.dir 2>/dev/null
++fi
++if (echo >conf$$.file) 2>/dev/null; then
++ if ln -s conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s='ln -s'
++ # ... but there are two gotchas:
++ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
++ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
++ # In both cases, we have to default to `cp -pR'.
++ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
++ as_ln_s='cp -pR'
++ elif ln conf$$.file conf$$ 2>/dev/null; then
++ as_ln_s=ln
++ else
++ as_ln_s='cp -pR'
++ fi
++else
++ as_ln_s='cp -pR'
++fi
++rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
++rmdir conf$$.dir 2>/dev/null
++
++
++# as_fn_mkdir_p
++# -------------
++# Create "$as_dir" as a directory, including parents if necessary.
++as_fn_mkdir_p ()
++{
++
++ case $as_dir in #(
++ -*) as_dir=./$as_dir;;
++ esac
++ test -d "$as_dir" || eval $as_mkdir_p || {
++ as_dirs=
++ while :; do
++ case $as_dir in #(
++ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
++ *) as_qdir=$as_dir;;
++ esac
++ as_dirs="'$as_qdir' $as_dirs"
++ as_dir=`$as_dirname -- "$as_dir" ||
++$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$as_dir" : 'X\(//\)[^/]' \| \
++ X"$as_dir" : 'X\(//\)$' \| \
++ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$as_dir" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ test -d "$as_dir" && break
++ done
++ test -z "$as_dirs" || eval "mkdir $as_dirs"
++ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
++
++
++} # as_fn_mkdir_p
++if mkdir -p . 2>/dev/null; then
++ as_mkdir_p='mkdir -p "$as_dir"'
++else
++ test -d ./-p && rmdir ./-p
++ as_mkdir_p=false
++fi
++
++
++# as_fn_executable_p FILE
++# -----------------------
++# Test if FILE is an executable regular file.
++as_fn_executable_p ()
++{
++ test -f "$1" && test -x "$1"
++} # as_fn_executable_p
++as_test_x='test -x'
++as_executable_p=as_fn_executable_p
++
++# Sed expression to map a string onto a valid CPP name.
++as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
++
++# Sed expression to map a string onto a valid variable name.
++as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
++
++
++exec 6>&1
++## ----------------------------------- ##
++## Main body of $CONFIG_STATUS script. ##
++## ----------------------------------- ##
++_ASEOF
++test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
++
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++# Save the log message, to keep $0 and so on meaningful, and to
++# report actual input values of CONFIG_FILES etc. instead of their
++# values after options handling.
++ac_log="
++This file was extended by argyll $as_me 1.3.7, which was
++generated by GNU Autoconf 2.69. Invocation command line was
++
++ CONFIG_FILES = $CONFIG_FILES
++ CONFIG_HEADERS = $CONFIG_HEADERS
++ CONFIG_LINKS = $CONFIG_LINKS
++ CONFIG_COMMANDS = $CONFIG_COMMANDS
++ $ $0 $@
++
++on `(hostname || uname -n) 2>/dev/null | sed 1q`
++"
++
++_ACEOF
++
++case $ac_config_files in *"
++"*) set x $ac_config_files; shift; ac_config_files=$*;;
++esac
++
++case $ac_config_headers in *"
++"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
++esac
++
++
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++# Files that config.status was made for.
++config_files="$ac_config_files"
++config_headers="$ac_config_headers"
++config_commands="$ac_config_commands"
++
++_ACEOF
++
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++ac_cs_usage="\
++\`$as_me' instantiates files and other configuration actions
++from templates according to the current configuration. Unless the files
++and actions are specified as TAGs, all are instantiated by default.
++
++Usage: $0 [OPTION]... [TAG]...
++
++ -h, --help print this help, then exit
++ -V, --version print version number and configuration settings, then exit
++ --config print configuration, then exit
++ -q, --quiet, --silent
++ do not print progress messages
++ -d, --debug don't remove temporary files
++ --recheck update $as_me by reconfiguring in the same conditions
++ --file=FILE[:TEMPLATE]
++ instantiate the configuration file FILE
++ --header=FILE[:TEMPLATE]
++ instantiate the configuration header FILE
++
++Configuration files:
++$config_files
++
++Configuration headers:
++$config_headers
++
++Configuration commands:
++$config_commands
++
++Report bugs to the package provider."
++
++_ACEOF
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
++ac_cs_version="\\
++argyll config.status 1.3.7
++configured by $0, generated by GNU Autoconf 2.69,
++ with options \\"\$ac_cs_config\\"
++
++Copyright (C) 2012 Free Software Foundation, Inc.
++This config.status script is free software; the Free Software Foundation
++gives unlimited permission to copy, distribute and modify it."
++
++ac_pwd='$ac_pwd'
++srcdir='$srcdir'
++INSTALL='$INSTALL'
++MKDIR_P='$MKDIR_P'
++AWK='$AWK'
++test -n "\$AWK" || AWK=awk
++_ACEOF
++
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++# The default lists apply if the user does not specify any file.
++ac_need_defaults=:
++while test $# != 0
++do
++ case $1 in
++ --*=?*)
++ ac_option=`expr "X$1" : 'X\([^=]*\)='`
++ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
++ ac_shift=:
++ ;;
++ --*=)
++ ac_option=`expr "X$1" : 'X\([^=]*\)='`
++ ac_optarg=
++ ac_shift=:
++ ;;
++ *)
++ ac_option=$1
++ ac_optarg=$2
++ ac_shift=shift
++ ;;
++ esac
++
++ case $ac_option in
++ # Handling of the options.
++ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
++ ac_cs_recheck=: ;;
++ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
++ $as_echo "$ac_cs_version"; exit ;;
++ --config | --confi | --conf | --con | --co | --c )
++ $as_echo "$ac_cs_config"; exit ;;
++ --debug | --debu | --deb | --de | --d | -d )
++ debug=: ;;
++ --file | --fil | --fi | --f )
++ $ac_shift
++ case $ac_optarg in
++ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
++ '') as_fn_error $? "missing file argument" ;;
++ esac
++ as_fn_append CONFIG_FILES " '$ac_optarg'"
++ ac_need_defaults=false;;
++ --header | --heade | --head | --hea )
++ $ac_shift
++ case $ac_optarg in
++ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
++ esac
++ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
++ ac_need_defaults=false;;
++ --he | --h)
++ # Conflict between --help and --header
++ as_fn_error $? "ambiguous option: \`$1'
++Try \`$0 --help' for more information.";;
++ --help | --hel | -h )
++ $as_echo "$ac_cs_usage"; exit ;;
++ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
++ | -silent | --silent | --silen | --sile | --sil | --si | --s)
++ ac_cs_silent=: ;;
++
++ # This is an error.
++ -*) as_fn_error $? "unrecognized option: \`$1'
++Try \`$0 --help' for more information." ;;
++
++ *) as_fn_append ac_config_targets " $1"
++ ac_need_defaults=false ;;
++
++ esac
++ shift
++done
++
++ac_configure_extra_args=
++
++if $ac_cs_silent; then
++ exec 6>/dev/null
++ ac_configure_extra_args="$ac_configure_extra_args --silent"
++fi
++
++_ACEOF
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++if \$ac_cs_recheck; then
++ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
++ shift
++ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
++ CONFIG_SHELL='$SHELL'
++ export CONFIG_SHELL
++ exec "\$@"
++fi
++
++_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++exec 5>>config.log
++{
++ echo
++ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
++## Running $as_me. ##
++_ASBOX
++ $as_echo "$ac_log"
++} >&5
++
++_ACEOF
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++#
++# INIT-COMMANDS
++#
++AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
++
++
++# The HP-UX ksh and POSIX shell print the target directory to stdout
++# if CDPATH is set.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
++
++sed_quote_subst='$sed_quote_subst'
++double_quote_subst='$double_quote_subst'
++delay_variable_subst='$delay_variable_subst'
++macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
++macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
++enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
++enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
++pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
++enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
++SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
++ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
++PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
++host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
++host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
++host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
++build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
++build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
++build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
++SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
++Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
++GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
++EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
++FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
++LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
++NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
++LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
++max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
++ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
++exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
++lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
++lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
++lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
++lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
++lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
++reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
++reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
++OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
++deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
++file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
++file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
++want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
++DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
++sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
++AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
++AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
++archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
++STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
++RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
++old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
++old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
++old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
++lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
++CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
++CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
++compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
++GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
++lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
++lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
++lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
++nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
++lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
++objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
++MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
++lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
++lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
++need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
++MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
++DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
++NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
++LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
++OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
++OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
++libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
++shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
++extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
++archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
++enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
++export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
++whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
++compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
++old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
++old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
++archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
++archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
++module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
++module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
++with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
++allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
++no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
++hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
++hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
++hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
++hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
++hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
++hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
++hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
++inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
++link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
++always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
++export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
++exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
++include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
++prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
++postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
++file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
++variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
++need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
++need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
++version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
++runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
++shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
++shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
++libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
++library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
++soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
++install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
++postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
++postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
++finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
++finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
++hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
++sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
++sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
++hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
++enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
++enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
++enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
++old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
++striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
++
++LTCC='$LTCC'
++LTCFLAGS='$LTCFLAGS'
++compiler='$compiler_DEFAULT'
++
++# A function that is used when there is no print builtin or printf.
++func_fallback_echo ()
++{
++ eval 'cat <<_LTECHO_EOF
++\$1
++_LTECHO_EOF'
++}
++
++# Quote evaled strings.
++for var in SHELL \
++ECHO \
++PATH_SEPARATOR \
++SED \
++GREP \
++EGREP \
++FGREP \
++LD \
++NM \
++LN_S \
++lt_SP2NL \
++lt_NL2SP \
++reload_flag \
++OBJDUMP \
++deplibs_check_method \
++file_magic_cmd \
++file_magic_glob \
++want_nocaseglob \
++DLLTOOL \
++sharedlib_from_linklib_cmd \
++AR \
++AR_FLAGS \
++archiver_list_spec \
++STRIP \
++RANLIB \
++CC \
++CFLAGS \
++compiler \
++lt_cv_sys_global_symbol_pipe \
++lt_cv_sys_global_symbol_to_cdecl \
++lt_cv_sys_global_symbol_to_c_name_address \
++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
++nm_file_list_spec \
++lt_prog_compiler_no_builtin_flag \
++lt_prog_compiler_pic \
++lt_prog_compiler_wl \
++lt_prog_compiler_static \
++lt_cv_prog_compiler_c_o \
++need_locks \
++MANIFEST_TOOL \
++DSYMUTIL \
++NMEDIT \
++LIPO \
++OTOOL \
++OTOOL64 \
++shrext_cmds \
++export_dynamic_flag_spec \
++whole_archive_flag_spec \
++compiler_needs_object \
++with_gnu_ld \
++allow_undefined_flag \
++no_undefined_flag \
++hardcode_libdir_flag_spec \
++hardcode_libdir_separator \
++exclude_expsyms \
++include_expsyms \
++file_list_spec \
++variables_saved_for_relink \
++libname_spec \
++library_names_spec \
++soname_spec \
++install_override_mode \
++finish_eval \
++old_striplib \
++striplib; do
++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
++ *[\\\\\\\`\\"\\\$]*)
++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
++ ;;
++ *)
++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
++ ;;
++ esac
++done
++
++# Double-quote double-evaled strings.
++for var in reload_cmds \
++old_postinstall_cmds \
++old_postuninstall_cmds \
++old_archive_cmds \
++extract_expsyms_cmds \
++old_archive_from_new_cmds \
++old_archive_from_expsyms_cmds \
++archive_cmds \
++archive_expsym_cmds \
++module_cmds \
++module_expsym_cmds \
++export_symbols_cmds \
++prelink_cmds \
++postlink_cmds \
++postinstall_cmds \
++postuninstall_cmds \
++finish_cmds \
++sys_lib_search_path_spec \
++sys_lib_dlsearch_path_spec; do
++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
++ *[\\\\\\\`\\"\\\$]*)
++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
++ ;;
++ *)
++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
++ ;;
++ esac
++done
++
++ac_aux_dir='$ac_aux_dir'
++xsi_shell='$xsi_shell'
++lt_shell_append='$lt_shell_append'
++
++# See if we are running on zsh, and set the options which allow our
++# commands through without removal of \ escapes INIT.
++if test -n "\${ZSH_VERSION+set}" ; then
++ setopt NO_GLOB_SUBST
++fi
++
++
++ PACKAGE='$PACKAGE'
++ VERSION='$VERSION'
++ TIMESTAMP='$TIMESTAMP'
++ RM='$RM'
++ ofile='$ofile'
++
++
++
++
++_ACEOF
++
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++
++# Handling of arguments.
++for ac_config_target in $ac_config_targets
++do
++ case $ac_config_target in
++ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
++ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
++ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
++ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
++ "h/Makefile") CONFIG_FILES="$CONFIG_FILES h/Makefile" ;;
++ "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
++ "ref/Makefile") CONFIG_FILES="$CONFIG_FILES ref/Makefile" ;;
++ "numlib/Makefile") CONFIG_FILES="$CONFIG_FILES numlib/Makefile" ;;
++ "cgats/Makefile") CONFIG_FILES="$CONFIG_FILES cgats/Makefile" ;;
++ "plot/Makefile") CONFIG_FILES="$CONFIG_FILES plot/Makefile" ;;
++ "rspl/Makefile") CONFIG_FILES="$CONFIG_FILES rspl/Makefile" ;;
++ "icc/Makefile") CONFIG_FILES="$CONFIG_FILES icc/Makefile" ;;
++ "gamut/Makefile") CONFIG_FILES="$CONFIG_FILES gamut/Makefile" ;;
++ "xicc/Makefile") CONFIG_FILES="$CONFIG_FILES xicc/Makefile" ;;
++ "link/Makefile") CONFIG_FILES="$CONFIG_FILES link/Makefile" ;;
++ "spectro/Makefile") CONFIG_FILES="$CONFIG_FILES spectro/Makefile" ;;
++ "profile/Makefile") CONFIG_FILES="$CONFIG_FILES profile/Makefile" ;;
++ "tweak/Makefile") CONFIG_FILES="$CONFIG_FILES tweak/Makefile" ;;
++ "scanin/Makefile") CONFIG_FILES="$CONFIG_FILES scanin/Makefile" ;;
++ "render/Makefile") CONFIG_FILES="$CONFIG_FILES render/Makefile" ;;
++ "target/Makefile") CONFIG_FILES="$CONFIG_FILES target/Makefile" ;;
++ "imdi/Makefile") CONFIG_FILES="$CONFIG_FILES imdi/Makefile" ;;
++ "jcnf/Makefile") CONFIG_FILES="$CONFIG_FILES jcnf/Makefile" ;;
++ "jcnf/yajl/Makefile") CONFIG_FILES="$CONFIG_FILES jcnf/yajl/Makefile" ;;
++ "ucmm/Makefile") CONFIG_FILES="$CONFIG_FILES ucmm/Makefile" ;;
++
++ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
++ esac
++done
++
++
++# If the user did not use the arguments to specify the items to instantiate,
++# then the envvar interface is used. Set only those that are not.
++# We use the long form for the default assignment because of an extremely
++# bizarre bug on SunOS 4.1.3.
++if $ac_need_defaults; then
++ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
++ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
++ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
++fi
++
++# Have a temporary directory for convenience. Make it in the build tree
++# simply because there is no reason against having it here, and in addition,
++# creating and moving files from /tmp can sometimes cause problems.
++# Hook for its removal unless debugging.
++# Note that there is a small window in which the directory will not be cleaned:
++# after its creation but before its name has been assigned to `$tmp'.
++$debug ||
++{
++ tmp= ac_tmp=
++ trap 'exit_status=$?
++ : "${ac_tmp:=$tmp}"
++ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
++' 0
++ trap 'as_fn_exit 1' 1 2 13 15
++}
++# Create a (secure) tmp directory for tmp files.
++
++{
++ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
++ test -d "$tmp"
++} ||
++{
++ tmp=./conf$$-$RANDOM
++ (umask 077 && mkdir "$tmp")
++} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
++ac_tmp=$tmp
++
++# Set up the scripts for CONFIG_FILES section.
++# No need to generate them if there are no CONFIG_FILES.
++# This happens for instance with `./config.status config.h'.
++if test -n "$CONFIG_FILES"; then
++
++
++ac_cr=`echo X | tr X '\015'`
++# On cygwin, bash can eat \r inside `` if the user requested igncr.
++# But we know of no other shell where ac_cr would be empty at this
++# point, so we can use a bashism as a fallback.
++if test "x$ac_cr" = x; then
++ eval ac_cr=\$\'\\r\'
++fi
++ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
++if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
++ ac_cs_awk_cr='\\r'
++else
++ ac_cs_awk_cr=$ac_cr
++fi
++
++echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
++_ACEOF
++
++
++{
++ echo "cat >conf$$subs.awk <<_ACEOF" &&
++ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
++ echo "_ACEOF"
++} >conf$$subs.sh ||
++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
++ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
++ac_delim='%!_!# '
++for ac_last_try in false false false false false :; do
++ . ./conf$$subs.sh ||
++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
++
++ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
++ if test $ac_delim_n = $ac_delim_num; then
++ break
++ elif $ac_last_try; then
++ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
++ else
++ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
++ fi
++done
++rm -f conf$$subs.sh
++
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
++_ACEOF
++sed -n '
++h
++s/^/S["/; s/!.*/"]=/
++p
++g
++s/^[^!]*!//
++:repl
++t repl
++s/'"$ac_delim"'$//
++t delim
++:nl
++h
++s/\(.\{148\}\)..*/\1/
++t more1
++s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
++p
++n
++b repl
++:more1
++s/["\\]/\\&/g; s/^/"/; s/$/"\\/
++p
++g
++s/.\{148\}//
++t nl
++:delim
++h
++s/\(.\{148\}\)..*/\1/
++t more2
++s/["\\]/\\&/g; s/^/"/; s/$/"/
++p
++b
++:more2
++s/["\\]/\\&/g; s/^/"/; s/$/"\\/
++p
++g
++s/.\{148\}//
++t delim
++' <conf$$subs.awk | sed '
++/^[^""]/{
++ N
++ s/\n//
++}
++' >>$CONFIG_STATUS || ac_write_fail=1
++rm -f conf$$subs.awk
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++_ACAWK
++cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
++ for (key in S) S_is_set[key] = 1
++ FS = ""
++
++}
++{
++ line = $ 0
++ nfields = split(line, field, "@")
++ substed = 0
++ len = length(field[1])
++ for (i = 2; i < nfields; i++) {
++ key = field[i]
++ keylen = length(key)
++ if (S_is_set[key]) {
++ value = S[key]
++ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
++ len += length(value) + length(field[++i])
++ substed = 1
++ } else
++ len += 1 + keylen
++ }
++
++ print line
++}
++
++_ACAWK
++_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
++ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
++else
++ cat
++fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
++ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
++_ACEOF
++
++# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
++# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
++# trailing colons and then remove the whole line if VPATH becomes empty
++# (actually we leave an empty line to preserve line numbers).
++if test "x$srcdir" = x.; then
++ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
++h
++s///
++s/^/:/
++s/[ ]*$/:/
++s/:\$(srcdir):/:/g
++s/:\${srcdir}:/:/g
++s/:@srcdir@:/:/g
++s/^:*//
++s/:*$//
++x
++s/\(=[ ]*\).*/\1/
++G
++s/\n//
++s/^[^=]*=[ ]*$//
++}'
++fi
++
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++fi # test -n "$CONFIG_FILES"
++
++# Set up the scripts for CONFIG_HEADERS section.
++# No need to generate them if there are no CONFIG_HEADERS.
++# This happens for instance with `./config.status Makefile'.
++if test -n "$CONFIG_HEADERS"; then
++cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
++BEGIN {
++_ACEOF
++
++# Transform confdefs.h into an awk script `defines.awk', embedded as
++# here-document in config.status, that substitutes the proper values into
++# config.h.in to produce config.h.
++
++# Create a delimiter string that does not exist in confdefs.h, to ease
++# handling of long lines.
++ac_delim='%!_!# '
++for ac_last_try in false false :; do
++ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
++ if test -z "$ac_tt"; then
++ break
++ elif $ac_last_try; then
++ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
++ else
++ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
++ fi
++done
++
++# For the awk script, D is an array of macro values keyed by name,
++# likewise P contains macro parameters if any. Preserve backslash
++# newline sequences.
++
++ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
++sed -n '
++s/.\{148\}/&'"$ac_delim"'/g
++t rset
++:rset
++s/^[ ]*#[ ]*define[ ][ ]*/ /
++t def
++d
++:def
++s/\\$//
++t bsnl
++s/["\\]/\\&/g
++s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
++D["\1"]=" \3"/p
++s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
++d
++:bsnl
++s/["\\]/\\&/g
++s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
++D["\1"]=" \3\\\\\\n"\\/p
++t cont
++s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
++t cont
++d
++:cont
++n
++s/.\{148\}/&'"$ac_delim"'/g
++t clear
++:clear
++s/\\$//
++t bsnlc
++s/["\\]/\\&/g; s/^/"/; s/$/"/p
++d
++:bsnlc
++s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
++b cont
++' <confdefs.h | sed '
++s/'"$ac_delim"'/"\\\
++"/g' >>$CONFIG_STATUS || ac_write_fail=1
++
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++ for (key in D) D_is_set[key] = 1
++ FS = ""
++}
++/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
++ line = \$ 0
++ split(line, arg, " ")
++ if (arg[1] == "#") {
++ defundef = arg[2]
++ mac1 = arg[3]
++ } else {
++ defundef = substr(arg[1], 2)
++ mac1 = arg[2]
++ }
++ split(mac1, mac2, "(") #)
++ macro = mac2[1]
++ prefix = substr(line, 1, index(line, defundef) - 1)
++ if (D_is_set[macro]) {
++ # Preserve the white space surrounding the "#".
++ print prefix "define", macro P[macro] D[macro]
++ next
++ } else {
++ # Replace #undef with comments. This is necessary, for example,
++ # in the case of _POSIX_SOURCE, which is predefined and required
++ # on some systems where configure will not decide to define it.
++ if (defundef == "undef") {
++ print "/*", prefix defundef, macro, "*/"
++ next
++ }
++ }
++}
++{ print }
++_ACAWK
++_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
++fi # test -n "$CONFIG_HEADERS"
++
++
++eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
++shift
++for ac_tag
++do
++ case $ac_tag in
++ :[FHLC]) ac_mode=$ac_tag; continue;;
++ esac
++ case $ac_mode$ac_tag in
++ :[FHL]*:*);;
++ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
++ :[FH]-) ac_tag=-:-;;
++ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
++ esac
++ ac_save_IFS=$IFS
++ IFS=:
++ set x $ac_tag
++ IFS=$ac_save_IFS
++ shift
++ ac_file=$1
++ shift
++
++ case $ac_mode in
++ :L) ac_source=$1;;
++ :[FH])
++ ac_file_inputs=
++ for ac_f
++ do
++ case $ac_f in
++ -) ac_f="$ac_tmp/stdin";;
++ *) # Look for the file first in the build tree, then in the source tree
++ # (if the path is not absolute). The absolute path cannot be DOS-style,
++ # because $ac_f cannot contain `:'.
++ test -f "$ac_f" ||
++ case $ac_f in
++ [\\/$]*) false;;
++ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
++ esac ||
++ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
++ esac
++ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
++ as_fn_append ac_file_inputs " '$ac_f'"
++ done
++
++ # Let's still pretend it is `configure' which instantiates (i.e., don't
++ # use $as_me), people would be surprised to read:
++ # /* config.h. Generated by config.status. */
++ configure_input='Generated from '`
++ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
++ `' by configure.'
++ if test x"$ac_file" != x-; then
++ configure_input="$ac_file. $configure_input"
++ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
++$as_echo "$as_me: creating $ac_file" >&6;}
++ fi
++ # Neutralize special characters interpreted by sed in replacement strings.
++ case $configure_input in #(
++ *\&* | *\|* | *\\* )
++ ac_sed_conf_input=`$as_echo "$configure_input" |
++ sed 's/[\\\\&|]/\\\\&/g'`;; #(
++ *) ac_sed_conf_input=$configure_input;;
++ esac
++
++ case $ac_tag in
++ *:-:* | *:-) cat >"$ac_tmp/stdin" \
++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
++ esac
++ ;;
++ esac
++
++ ac_dir=`$as_dirname -- "$ac_file" ||
++$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$ac_file" : 'X\(//\)[^/]' \| \
++ X"$ac_file" : 'X\(//\)$' \| \
++ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$ac_file" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ as_dir="$ac_dir"; as_fn_mkdir_p
++ ac_builddir=.
++
++case "$ac_dir" in
++.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
++*)
++ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
++ # A ".." for each directory in $ac_dir_suffix.
++ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
++ case $ac_top_builddir_sub in
++ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
++ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
++ esac ;;
++esac
++ac_abs_top_builddir=$ac_pwd
++ac_abs_builddir=$ac_pwd$ac_dir_suffix
++# for backward compatibility:
++ac_top_builddir=$ac_top_build_prefix
++
++case $srcdir in
++ .) # We are building in place.
++ ac_srcdir=.
++ ac_top_srcdir=$ac_top_builddir_sub
++ ac_abs_top_srcdir=$ac_pwd ;;
++ [\\/]* | ?:[\\/]* ) # Absolute name.
++ ac_srcdir=$srcdir$ac_dir_suffix;
++ ac_top_srcdir=$srcdir
++ ac_abs_top_srcdir=$srcdir ;;
++ *) # Relative name.
++ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
++ ac_top_srcdir=$ac_top_build_prefix$srcdir
++ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
++esac
++ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
++
++
++ case $ac_mode in
++ :F)
++ #
++ # CONFIG_FILE
++ #
++
++ case $INSTALL in
++ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
++ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
++ esac
++ ac_MKDIR_P=$MKDIR_P
++ case $MKDIR_P in
++ [\\/$]* | ?:[\\/]* ) ;;
++ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
++ esac
++_ACEOF
++
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++# If the template does not know about datarootdir, expand it.
++# FIXME: This hack should be removed a few years after 2.60.
++ac_datarootdir_hack=; ac_datarootdir_seen=
++ac_sed_dataroot='
++/datarootdir/ {
++ p
++ q
++}
++/@datadir@/p
++/@docdir@/p
++/@infodir@/p
++/@localedir@/p
++/@mandir@/p'
++case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
++*datarootdir*) ac_datarootdir_seen=yes;;
++*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
++$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
++_ACEOF
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++ ac_datarootdir_hack='
++ s&@datadir@&$datadir&g
++ s&@docdir@&$docdir&g
++ s&@infodir@&$infodir&g
++ s&@localedir@&$localedir&g
++ s&@mandir@&$mandir&g
++ s&\\\${datarootdir}&$datarootdir&g' ;;
++esac
++_ACEOF
++
++# Neutralize VPATH when `$srcdir' = `.'.
++# Shell code in configure.ac might set extrasub.
++# FIXME: do we really want to maintain this feature?
++cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
++ac_sed_extra="$ac_vpsub
++$extrasub
++_ACEOF
++cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
++:t
++/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
++s|@configure_input@|$ac_sed_conf_input|;t t
++s&@top_builddir@&$ac_top_builddir_sub&;t t
++s&@top_build_prefix@&$ac_top_build_prefix&;t t
++s&@srcdir@&$ac_srcdir&;t t
++s&@abs_srcdir@&$ac_abs_srcdir&;t t
++s&@top_srcdir@&$ac_top_srcdir&;t t
++s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
++s&@builddir@&$ac_builddir&;t t
++s&@abs_builddir@&$ac_abs_builddir&;t t
++s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
++s&@INSTALL@&$ac_INSTALL&;t t
++s&@MKDIR_P@&$ac_MKDIR_P&;t t
++$ac_datarootdir_hack
++"
++eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
++ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
++
++test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
++ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
++ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
++ "$ac_tmp/out"`; test -z "$ac_out"; } &&
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
++which seems to be undefined. Please make sure it is defined" >&5
++$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
++which seems to be undefined. Please make sure it is defined" >&2;}
++
++ rm -f "$ac_tmp/stdin"
++ case $ac_file in
++ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
++ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
++ esac \
++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
++ ;;
++ :H)
++ #
++ # CONFIG_HEADER
++ #
++ if test x"$ac_file" != x-; then
++ {
++ $as_echo "/* $configure_input */" \
++ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
++ } >"$ac_tmp/config.h" \
++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
++ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
++$as_echo "$as_me: $ac_file is unchanged" >&6;}
++ else
++ rm -f "$ac_file"
++ mv "$ac_tmp/config.h" "$ac_file" \
++ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
++ fi
++ else
++ $as_echo "/* $configure_input */" \
++ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
++ || as_fn_error $? "could not create -" "$LINENO" 5
++ fi
++# Compute "$ac_file"'s index in $config_headers.
++_am_arg="$ac_file"
++_am_stamp_count=1
++for _am_header in $config_headers :; do
++ case $_am_header in
++ $_am_arg | $_am_arg:* )
++ break ;;
++ * )
++ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
++ esac
++done
++echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
++$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$_am_arg" : 'X\(//\)[^/]' \| \
++ X"$_am_arg" : 'X\(//\)$' \| \
++ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$_am_arg" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`/stamp-h$_am_stamp_count
++ ;;
++
++ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
++$as_echo "$as_me: executing $ac_file commands" >&6;}
++ ;;
++ esac
++
++
++ case $ac_file$ac_mode in
++ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
++ # Older Autoconf quotes --file arguments for eval, but not when files
++ # are listed without --file. Let's play safe and only enable the eval
++ # if we detect the quoting.
++ case $CONFIG_FILES in
++ *\'*) eval set x "$CONFIG_FILES" ;;
++ *) set x $CONFIG_FILES ;;
++ esac
++ shift
++ for mf
++ do
++ # Strip MF so we end up with the name of the file.
++ mf=`echo "$mf" | sed -e 's/:.*$//'`
++ # Check whether this is an Automake generated Makefile or not.
++ # We used to match only the files named 'Makefile.in', but
++ # some people rename them; so instead we look at the file content.
++ # Grep'ing the first line is not enough: some people post-process
++ # each Makefile.in and add a new line on top of each file to say so.
++ # Grep'ing the whole file is not good either: AIX grep has a line
++ # limit of 2048, but all sed's we know have understand at least 4000.
++ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
++ dirpart=`$as_dirname -- "$mf" ||
++$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$mf" : 'X\(//\)[^/]' \| \
++ X"$mf" : 'X\(//\)$' \| \
++ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$mf" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ else
++ continue
++ fi
++ # Extract the definition of DEPDIR, am__include, and am__quote
++ # from the Makefile without running 'make'.
++ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
++ test -z "$DEPDIR" && continue
++ am__include=`sed -n 's/^am__include = //p' < "$mf"`
++ test -z "$am__include" && continue
++ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
++ # Find all dependency output files, they are included files with
++ # $(DEPDIR) in their names. We invoke sed twice because it is the
++ # simplest approach to changing $(DEPDIR) to its actual value in the
++ # expansion.
++ for file in `sed -n "
++ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
++ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
++ # Make sure the directory exists.
++ test -f "$dirpart/$file" && continue
++ fdir=`$as_dirname -- "$file" ||
++$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$file" : 'X\(//\)[^/]' \| \
++ X"$file" : 'X\(//\)$' \| \
++ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
++$as_echo X"$file" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'`
++ as_dir=$dirpart/$fdir; as_fn_mkdir_p
++ # echo "creating $dirpart/$file"
++ echo '# dummy' > "$dirpart/$file"
++ done
++ done
++}
++ ;;
++ "libtool":C)
++
++ # See if we are running on zsh, and set the options which allow our
++ # commands through without removal of \ escapes.
++ if test -n "${ZSH_VERSION+set}" ; then
++ setopt NO_GLOB_SUBST
++ fi
++
++ cfgfile="${ofile}T"
++ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
++ $RM "$cfgfile"
++
++ cat <<_LT_EOF >> "$cfgfile"
++#! $SHELL
++
++# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
++# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
++# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
++# NOTE: Changes made to this file will be lost: look at ltmain.sh.
++#
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
++# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
++# Foundation, Inc.
++# Written by Gordon Matzigkeit, 1996
++#
++# This file is part of GNU Libtool.
++#
++# GNU Libtool is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# As a special exception to the GNU General Public License,
++# if you distribute this file as part of a program or library that
++# is built using GNU Libtool, you may include this file under the
++# same distribution terms that you use for the rest of that program.
++#
++# GNU Libtool is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GNU Libtool; see the file COPYING. If not, a copy
++# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
++# obtained by writing to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++
++
++# The names of the tagged configurations supported by this script.
++available_tags=""
++
++# ### BEGIN LIBTOOL CONFIG
++
++# Which release of libtool.m4 was used?
++macro_version=$macro_version
++macro_revision=$macro_revision
++
++# Whether or not to build shared libraries.
++build_libtool_libs=$enable_shared
++
++# Whether or not to build static libraries.
++build_old_libs=$enable_static
++
++# What type of objects to build.
++pic_mode=$pic_mode
++
++# Whether or not to optimize for fast installation.
++fast_install=$enable_fast_install
++
++# Shell to use when invoking shell scripts.
++SHELL=$lt_SHELL
++
++# An echo program that protects backslashes.
++ECHO=$lt_ECHO
++
++# The PATH separator for the build system.
++PATH_SEPARATOR=$lt_PATH_SEPARATOR
++
++# The host system.
++host_alias=$host_alias
++host=$host
++host_os=$host_os
++
++# The build system.
++build_alias=$build_alias
++build=$build
++build_os=$build_os
++
++# A sed program that does not truncate output.
++SED=$lt_SED
++
++# Sed that helps us avoid accidentally triggering echo(1) options like -n.
++Xsed="\$SED -e 1s/^X//"
++
++# A grep program that handles long lines.
++GREP=$lt_GREP
++
++# An ERE matcher.
++EGREP=$lt_EGREP
++
++# A literal string matcher.
++FGREP=$lt_FGREP
++
++# A BSD- or MS-compatible name lister.
++NM=$lt_NM
++
++# Whether we need soft or hard links.
++LN_S=$lt_LN_S
++
++# What is the maximum length of a command?
++max_cmd_len=$max_cmd_len
++
++# Object file suffix (normally "o").
++objext=$ac_objext
++
++# Executable file suffix (normally "").
++exeext=$exeext
++
++# whether the shell understands "unset".
++lt_unset=$lt_unset
++
++# turn spaces into newlines.
++SP2NL=$lt_lt_SP2NL
++
++# turn newlines into spaces.
++NL2SP=$lt_lt_NL2SP
++
++# convert \$build file names to \$host format.
++to_host_file_cmd=$lt_cv_to_host_file_cmd
++
++# convert \$build files to toolchain format.
++to_tool_file_cmd=$lt_cv_to_tool_file_cmd
++
++# An object symbol dumper.
++OBJDUMP=$lt_OBJDUMP
++
++# Method to check whether dependent libraries are shared objects.
++deplibs_check_method=$lt_deplibs_check_method
++
++# Command to use when deplibs_check_method = "file_magic".
++file_magic_cmd=$lt_file_magic_cmd
++
++# How to find potential files when deplibs_check_method = "file_magic".
++file_magic_glob=$lt_file_magic_glob
++
++# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
++want_nocaseglob=$lt_want_nocaseglob
++
++# DLL creation program.
++DLLTOOL=$lt_DLLTOOL
++
++# Command to associate shared and link libraries.
++sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
++
++# The archiver.
++AR=$lt_AR
++
++# Flags to create an archive.
++AR_FLAGS=$lt_AR_FLAGS
++
++# How to feed a file listing to the archiver.
++archiver_list_spec=$lt_archiver_list_spec
++
++# A symbol stripping program.
++STRIP=$lt_STRIP
++
++# Commands used to install an old-style archive.
++RANLIB=$lt_RANLIB
++old_postinstall_cmds=$lt_old_postinstall_cmds
++old_postuninstall_cmds=$lt_old_postuninstall_cmds
++
++# Whether to use a lock for old archive extraction.
++lock_old_archive_extraction=$lock_old_archive_extraction
++
++# A C compiler.
++LTCC=$lt_CC
++
++# LTCC compiler flags.
++LTCFLAGS=$lt_CFLAGS
++
++# Take the output of nm and produce a listing of raw symbols and C names.
++global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
++
++# Transform the output of nm in a proper C declaration.
++global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
++
++# Transform the output of nm in a C name address pair.
++global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
++
++# Transform the output of nm in a C name address pair when lib prefix is needed.
++global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
++
++# Specify filename containing input files for \$NM.
++nm_file_list_spec=$lt_nm_file_list_spec
++
++# The root where to search for dependent libraries,and in which our libraries should be installed.
++lt_sysroot=$lt_sysroot
++
++# The name of the directory that contains temporary libtool files.
++objdir=$objdir
++
++# Used to examine libraries when file_magic_cmd begins with "file".
++MAGIC_CMD=$MAGIC_CMD
++
++# Must we lock files when doing compilation?
++need_locks=$lt_need_locks
++
++# Manifest tool.
++MANIFEST_TOOL=$lt_MANIFEST_TOOL
++
++# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
++DSYMUTIL=$lt_DSYMUTIL
++
++# Tool to change global to local symbols on Mac OS X.
++NMEDIT=$lt_NMEDIT
++
++# Tool to manipulate fat objects and archives on Mac OS X.
++LIPO=$lt_LIPO
++
++# ldd/readelf like tool for Mach-O binaries on Mac OS X.
++OTOOL=$lt_OTOOL
++
++# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
++OTOOL64=$lt_OTOOL64
++
++# Old archive suffix (normally "a").
++libext=$libext
++
++# Shared library suffix (normally ".so").
++shrext_cmds=$lt_shrext_cmds
++
++# The commands to extract the exported symbol list from a shared archive.
++extract_expsyms_cmds=$lt_extract_expsyms_cmds
++
++# Variables whose values should be saved in libtool wrapper scripts and
++# restored at link time.
++variables_saved_for_relink=$lt_variables_saved_for_relink
++
++# Do we need the "lib" prefix for modules?
++need_lib_prefix=$need_lib_prefix
++
++# Do we need a version for libraries?
++need_version=$need_version
++
++# Library versioning type.
++version_type=$version_type
++
++# Shared library runtime path variable.
++runpath_var=$runpath_var
++
++# Shared library path variable.
++shlibpath_var=$shlibpath_var
++
++# Is shlibpath searched before the hard-coded library search path?
++shlibpath_overrides_runpath=$shlibpath_overrides_runpath
++
++# Format of library name prefix.
++libname_spec=$lt_libname_spec
++
++# List of archive names. First name is the real one, the rest are links.
++# The last name is the one that the linker finds with -lNAME
++library_names_spec=$lt_library_names_spec
++
++# The coded name of the library, if different from the real name.
++soname_spec=$lt_soname_spec
++
++# Permission mode override for installation of shared libraries.
++install_override_mode=$lt_install_override_mode
++
++# Command to use after installation of a shared archive.
++postinstall_cmds=$lt_postinstall_cmds
++
++# Command to use after uninstallation of a shared archive.
++postuninstall_cmds=$lt_postuninstall_cmds
++
++# Commands used to finish a libtool library installation in a directory.
++finish_cmds=$lt_finish_cmds
++
++# As "finish_cmds", except a single script fragment to be evaled but
++# not shown.
++finish_eval=$lt_finish_eval
++
++# Whether we should hardcode library paths into libraries.
++hardcode_into_libs=$hardcode_into_libs
++
++# Compile-time system search path for libraries.
++sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
++
++# Run-time system search path for libraries.
++sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
++
++# Whether dlopen is supported.
++dlopen_support=$enable_dlopen
++
++# Whether dlopen of programs is supported.
++dlopen_self=$enable_dlopen_self
++
++# Whether dlopen of statically linked programs is supported.
++dlopen_self_static=$enable_dlopen_self_static
++
++# Commands to strip libraries.
++old_striplib=$lt_old_striplib
++striplib=$lt_striplib
++
++
++# The linker used to build libraries.
++LD=$lt_LD
++
++# How to create reloadable object files.
++reload_flag=$lt_reload_flag
++reload_cmds=$lt_reload_cmds
++
++# Commands used to build an old-style archive.
++old_archive_cmds=$lt_old_archive_cmds
++
++# A language specific compiler.
++CC=$lt_compiler
++
++# Is the compiler the GNU compiler?
++with_gcc=$GCC
++
++# Compiler flag to turn off builtin functions.
++no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
++
++# Additional compiler flags for building library objects.
++pic_flag=$lt_lt_prog_compiler_pic
++
++# How to pass a linker flag through the compiler.
++wl=$lt_lt_prog_compiler_wl
++
++# Compiler flag to prevent dynamic linking.
++link_static_flag=$lt_lt_prog_compiler_static
++
++# Does compiler simultaneously support -c and -o options?
++compiler_c_o=$lt_lt_cv_prog_compiler_c_o
++
++# Whether or not to add -lc for building shared libraries.
++build_libtool_need_lc=$archive_cmds_need_lc
++
++# Whether or not to disallow shared libs when runtime libs are static.
++allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
++
++# Compiler flag to allow reflexive dlopens.
++export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
++
++# Compiler flag to generate shared objects directly from archives.
++whole_archive_flag_spec=$lt_whole_archive_flag_spec
++
++# Whether the compiler copes with passing no objects directly.
++compiler_needs_object=$lt_compiler_needs_object
++
++# Create an old-style archive from a shared archive.
++old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
++
++# Create a temporary old-style archive to link instead of a shared archive.
++old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
++
++# Commands used to build a shared archive.
++archive_cmds=$lt_archive_cmds
++archive_expsym_cmds=$lt_archive_expsym_cmds
++
++# Commands used to build a loadable module if different from building
++# a shared archive.
++module_cmds=$lt_module_cmds
++module_expsym_cmds=$lt_module_expsym_cmds
++
++# Whether we are building with GNU ld or not.
++with_gnu_ld=$lt_with_gnu_ld
++
++# Flag that allows shared libraries with undefined symbols to be built.
++allow_undefined_flag=$lt_allow_undefined_flag
++
++# Flag that enforces no undefined symbols.
++no_undefined_flag=$lt_no_undefined_flag
++
++# Flag to hardcode \$libdir into a binary during linking.
++# This must work even if \$libdir does not exist
++hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
++
++# Whether we need a single "-rpath" flag with a separated argument.
++hardcode_libdir_separator=$lt_hardcode_libdir_separator
++
++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
++# DIR into the resulting binary.
++hardcode_direct=$hardcode_direct
++
++# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
++# DIR into the resulting binary and the resulting library dependency is
++# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
++# library is relocated.
++hardcode_direct_absolute=$hardcode_direct_absolute
++
++# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
++# into the resulting binary.
++hardcode_minus_L=$hardcode_minus_L
++
++# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
++# into the resulting binary.
++hardcode_shlibpath_var=$hardcode_shlibpath_var
++
++# Set to "yes" if building a shared library automatically hardcodes DIR
++# into the library and all subsequent libraries and executables linked
++# against it.
++hardcode_automatic=$hardcode_automatic
++
++# Set to yes if linker adds runtime paths of dependent libraries
++# to runtime path list.
++inherit_rpath=$inherit_rpath
++
++# Whether libtool must link a program against all its dependency libraries.
++link_all_deplibs=$link_all_deplibs
++
++# Set to "yes" if exported symbols are required.
++always_export_symbols=$always_export_symbols
++
++# The commands to list exported symbols.
++export_symbols_cmds=$lt_export_symbols_cmds
++
++# Symbols that should not be listed in the preloaded symbols.
++exclude_expsyms=$lt_exclude_expsyms
++
++# Symbols that must always be exported.
++include_expsyms=$lt_include_expsyms
++
++# Commands necessary for linking programs (against libraries) with templates.
++prelink_cmds=$lt_prelink_cmds
++
++# Commands necessary for finishing linking programs.
++postlink_cmds=$lt_postlink_cmds
++
++# Specify filename containing input files.
++file_list_spec=$lt_file_list_spec
++
++# How to hardcode a shared library path into an executable.
++hardcode_action=$hardcode_action
++
++# ### END LIBTOOL CONFIG
++
++_LT_EOF
++
++ case $host_os in
++ aix3*)
++ cat <<\_LT_EOF >> "$cfgfile"
++# AIX sometimes has problems with the GCC collect2 program. For some
++# reason, if we set the COLLECT_NAMES environment variable, the problems
++# vanish in a puff of smoke.
++if test "X${COLLECT_NAMES+set}" != Xset; then
++ COLLECT_NAMES=
++ export COLLECT_NAMES
++fi
++_LT_EOF
++ ;;
++ esac
++
++
++ltmain="$ac_aux_dir/ltmain.sh"
++
++
++ # We use sed instead of cat because bash on DJGPP gets confused if
++ # if finds mixed CR/LF and LF-only lines. Since sed operates in
++ # text mode, it properly converts lines to CR/LF. This bash problem
++ # is reportedly fixed, but why not run on old versions too?
++ sed '$q' "$ltmain" >> "$cfgfile" \
++ || (rm -f "$cfgfile"; exit 1)
++
++ if test x"$xsi_shell" = xyes; then
++ sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
++func_dirname ()\
++{\
++\ case ${1} in\
++\ */*) func_dirname_result="${1%/*}${2}" ;;\
++\ * ) func_dirname_result="${3}" ;;\
++\ esac\
++} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_basename ()$/,/^} # func_basename /c\
++func_basename ()\
++{\
++\ func_basename_result="${1##*/}"\
++} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
++func_dirname_and_basename ()\
++{\
++\ case ${1} in\
++\ */*) func_dirname_result="${1%/*}${2}" ;;\
++\ * ) func_dirname_result="${3}" ;;\
++\ esac\
++\ func_basename_result="${1##*/}"\
++} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
++func_stripname ()\
++{\
++\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
++\ # positional parameters, so assign one to ordinary parameter first.\
++\ func_stripname_result=${3}\
++\ func_stripname_result=${func_stripname_result#"${1}"}\
++\ func_stripname_result=${func_stripname_result%"${2}"}\
++} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
++func_split_long_opt ()\
++{\
++\ func_split_long_opt_name=${1%%=*}\
++\ func_split_long_opt_arg=${1#*=}\
++} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
++func_split_short_opt ()\
++{\
++\ func_split_short_opt_arg=${1#??}\
++\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
++} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
++func_lo2o ()\
++{\
++\ case ${1} in\
++\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
++\ *) func_lo2o_result=${1} ;;\
++\ esac\
++} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_xform ()$/,/^} # func_xform /c\
++func_xform ()\
++{\
++ func_xform_result=${1%.*}.lo\
++} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_arith ()$/,/^} # func_arith /c\
++func_arith ()\
++{\
++ func_arith_result=$(( $* ))\
++} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_len ()$/,/^} # func_len /c\
++func_len ()\
++{\
++ func_len_result=${#1}\
++} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++fi
++
++if test x"$lt_shell_append" = xyes; then
++ sed -e '/^func_append ()$/,/^} # func_append /c\
++func_append ()\
++{\
++ eval "${1}+=\\${2}"\
++} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
++func_append_quoted ()\
++{\
++\ func_quote_for_eval "${2}"\
++\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
++} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++
++
++ # Save a `func_append' function call where possible by direct use of '+='
++ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++ test 0 -eq $? || _lt_function_replace_fail=:
++else
++ # Save a `func_append' function call even when '+=' is not available
++ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++ test 0 -eq $? || _lt_function_replace_fail=:
++fi
++
++if test x"$_lt_function_replace_fail" = x":"; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
++$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
++fi
++
++
++ mv -f "$cfgfile" "$ofile" ||
++ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
++ chmod +x "$ofile"
++
++ ;;
++
++ esac
++done # for ac_tag
++
++
++as_fn_exit 0
++_ACEOF
++ac_clean_files=$ac_clean_files_save
++
++test $ac_write_fail = 0 ||
++ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
++
++
++# configure is writing to config.log, and then calls config.status.
++# config.status does its own redirection, appending to config.log.
++# Unfortunately, on DOS this fails, as config.log is still kept open
++# by configure, so config.status won't be able to write to it; its
++# output is simply discarded. So we exec the FD to /dev/null,
++# effectively closing config.log, so it can be properly (re)opened and
++# appended to by config.status. When coming back to configure, we
++# need to make the FD available again.
++if test "$no_create" != yes; then
++ ac_cs_success=:
++ ac_config_status_args=
++ test "$silent" = yes &&
++ ac_config_status_args="$ac_config_status_args --quiet"
++ exec 5>/dev/null
++ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
++ exec 5>>config.log
++ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
++ # would make configure fail if this is the last instruction.
++ $ac_cs_success || as_fn_exit 1
++fi
++if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
++$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
++fi
++
+--- /dev/null
++++ b/config.sub
+@@ -0,0 +1,1791 @@
++#! /bin/sh
++# Configuration validation subroutine script.
++# Copyright 1992-2013 Free Software Foundation, Inc.
++
++timestamp='2013-08-10'
++
++# This file is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, see <http://www.gnu.org/licenses/>.
++#
++# As a special exception to the GNU General Public License, if you
++# distribute this file as part of a program that contains a
++# configuration script generated by Autoconf, you may include it under
++# the same distribution terms that you use for the rest of that
++# program. This Exception is an additional permission under section 7
++# of the GNU General Public License, version 3 ("GPLv3").
++
++
++# Please send patches with a ChangeLog entry to config-patches@gnu.org.
++#
++# Configuration subroutine to validate and canonicalize a configuration type.
++# Supply the specified configuration type as an argument.
++# If it is invalid, we print an error message on stderr and exit with code 1.
++# Otherwise, we print the canonical config type on stdout and succeed.
++
++# You can get the latest version of this script from:
++# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
++
++# This file is supposed to be the same for all GNU packages
++# and recognize all the CPU types, system types and aliases
++# that are meaningful with *any* GNU software.
++# Each package is responsible for reporting which valid configurations
++# it does not support. The user should be able to distinguish
++# a failure to support a valid configuration from a meaningless
++# configuration.
++
++# The goal of this file is to map all the various variations of a given
++# machine specification into a single specification in the form:
++# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
++# or in some cases, the newer four-part form:
++# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
++# It is wrong to echo any other type of specification.
++
++me=`echo "$0" | sed -e 's,.*/,,'`
++
++usage="\
++Usage: $0 [OPTION] CPU-MFR-OPSYS
++ $0 [OPTION] ALIAS
++
++Canonicalize a configuration name.
++
++Operation modes:
++ -h, --help print this help, then exit
++ -t, --time-stamp print date of last modification, then exit
++ -v, --version print version number, then exit
++
++Report bugs and patches to <config-patches@gnu.org>."
++
++version="\
++GNU config.sub ($timestamp)
++
++Copyright 1992-2013 Free Software Foundation, Inc.
++
++This is free software; see the source for copying conditions. There is NO
++warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
++
++help="
++Try \`$me --help' for more information."
++
++# Parse command line
++while test $# -gt 0 ; do
++ case $1 in
++ --time-stamp | --time* | -t )
++ echo "$timestamp" ; exit ;;
++ --version | -v )
++ echo "$version" ; exit ;;
++ --help | --h* | -h )
++ echo "$usage"; exit ;;
++ -- ) # Stop option processing
++ shift; break ;;
++ - ) # Use stdin as input.
++ break ;;
++ -* )
++ echo "$me: invalid option $1$help"
++ exit 1 ;;
++
++ *local*)
++ # First pass through any local machine types.
++ echo $1
++ exit ;;
++
++ * )
++ break ;;
++ esac
++done
++
++case $# in
++ 0) echo "$me: missing argument$help" >&2
++ exit 1;;
++ 1) ;;
++ *) echo "$me: too many arguments$help" >&2
++ exit 1;;
++esac
++
++# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
++# Here we must recognize all the valid KERNEL-OS combinations.
++maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
++case $maybe_os in
++ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
++ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
++ knetbsd*-gnu* | netbsd*-gnu* | \
++ kopensolaris*-gnu* | \
++ storm-chaos* | os2-emx* | rtmk-nova*)
++ os=-$maybe_os
++ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
++ ;;
++ android-linux)
++ os=-linux-android
++ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
++ ;;
++ *)
++ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
++ if [ $basic_machine != $1 ]
++ then os=`echo $1 | sed 's/.*-/-/'`
++ else os=; fi
++ ;;
++esac
++
++### Let's recognize common machines as not being operating systems so
++### that things like config.sub decstation-3100 work. We also
++### recognize some manufacturers as not being operating systems, so we
++### can provide default operating systems below.
++case $os in
++ -sun*os*)
++ # Prevent following clause from handling this invalid input.
++ ;;
++ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
++ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
++ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
++ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
++ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
++ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
++ -apple | -axis | -knuth | -cray | -microblaze*)
++ os=
++ basic_machine=$1
++ ;;
++ -bluegene*)
++ os=-cnk
++ ;;
++ -sim | -cisco | -oki | -wec | -winbond)
++ os=
++ basic_machine=$1
++ ;;
++ -scout)
++ ;;
++ -wrs)
++ os=-vxworks
++ basic_machine=$1
++ ;;
++ -chorusos*)
++ os=-chorusos
++ basic_machine=$1
++ ;;
++ -chorusrdb)
++ os=-chorusrdb
++ basic_machine=$1
++ ;;
++ -hiux*)
++ os=-hiuxwe2
++ ;;
++ -sco6)
++ os=-sco5v6
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -sco5)
++ os=-sco3.2v5
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -sco4)
++ os=-sco3.2v4
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -sco3.2.[4-9]*)
++ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -sco3.2v[4-9]*)
++ # Don't forget version if it is 3.2v4 or newer.
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -sco5v6*)
++ # Don't forget version if it is 3.2v4 or newer.
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -sco*)
++ os=-sco3.2v2
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -udk*)
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -isc)
++ os=-isc2.2
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -clix*)
++ basic_machine=clipper-intergraph
++ ;;
++ -isc*)
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
++ ;;
++ -lynx*178)
++ os=-lynxos178
++ ;;
++ -lynx*5)
++ os=-lynxos5
++ ;;
++ -lynx*)
++ os=-lynxos
++ ;;
++ -ptx*)
++ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
++ ;;
++ -windowsnt*)
++ os=`echo $os | sed -e 's/windowsnt/winnt/'`
++ ;;
++ -psos*)
++ os=-psos
++ ;;
++ -mint | -mint[0-9]*)
++ basic_machine=m68k-atari
++ os=-mint
++ ;;
++esac
++
++# Decode aliases for certain CPU-COMPANY combinations.
++case $basic_machine in
++ # Recognize the basic CPU types without company name.
++ # Some are omitted here because they have special meanings below.
++ 1750a | 580 \
++ | a29k \
++ | aarch64 | aarch64_be \
++ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
++ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
++ | am33_2.0 \
++ | arc | arceb \
++ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
++ | avr | avr32 \
++ | be32 | be64 \
++ | bfin \
++ | c4x | c8051 | clipper \
++ | d10v | d30v | dlx | dsp16xx \
++ | epiphany \
++ | fido | fr30 | frv \
++ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
++ | hexagon \
++ | i370 | i860 | i960 | ia64 \
++ | ip2k | iq2000 \
++ | le32 | le64 \
++ | lm32 \
++ | m32c | m32r | m32rle | m68000 | m68k | m88k \
++ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
++ | mips | mipsbe | mipseb | mipsel | mipsle \
++ | mips16 \
++ | mips64 | mips64el \
++ | mips64octeon | mips64octeonel \
++ | mips64orion | mips64orionel \
++ | mips64r5900 | mips64r5900el \
++ | mips64vr | mips64vrel \
++ | mips64vr4100 | mips64vr4100el \
++ | mips64vr4300 | mips64vr4300el \
++ | mips64vr5000 | mips64vr5000el \
++ | mips64vr5900 | mips64vr5900el \
++ | mipsisa32 | mipsisa32el \
++ | mipsisa32r2 | mipsisa32r2el \
++ | mipsisa64 | mipsisa64el \
++ | mipsisa64r2 | mipsisa64r2el \
++ | mipsisa64sb1 | mipsisa64sb1el \
++ | mipsisa64sr71k | mipsisa64sr71kel \
++ | mipsr5900 | mipsr5900el \
++ | mipstx39 | mipstx39el \
++ | mn10200 | mn10300 \
++ | moxie \
++ | mt \
++ | msp430 \
++ | nds32 | nds32le | nds32be \
++ | nios | nios2 | nios2eb | nios2el \
++ | ns16k | ns32k \
++ | open8 \
++ | or1k | or32 \
++ | pdp10 | pdp11 | pj | pjl \
++ | powerpc | powerpc64 | powerpc64le | powerpcle \
++ | pyramid \
++ | rl78 | rx \
++ | score \
++ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
++ | sh64 | sh64le \
++ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
++ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
++ | spu \
++ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
++ | ubicom32 \
++ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
++ | we32k \
++ | x86 | xc16x | xstormy16 | xtensa \
++ | z8k | z80)
++ basic_machine=$basic_machine-unknown
++ ;;
++ c54x)
++ basic_machine=tic54x-unknown
++ ;;
++ c55x)
++ basic_machine=tic55x-unknown
++ ;;
++ c6x)
++ basic_machine=tic6x-unknown
++ ;;
++ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
++ basic_machine=$basic_machine-unknown
++ os=-none
++ ;;
++ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
++ ;;
++ ms1)
++ basic_machine=mt-unknown
++ ;;
++
++ strongarm | thumb | xscale)
++ basic_machine=arm-unknown
++ ;;
++ xgate)
++ basic_machine=$basic_machine-unknown
++ os=-none
++ ;;
++ xscaleeb)
++ basic_machine=armeb-unknown
++ ;;
++
++ xscaleel)
++ basic_machine=armel-unknown
++ ;;
++
++ # We use `pc' rather than `unknown'
++ # because (1) that's what they normally are, and
++ # (2) the word "unknown" tends to confuse beginning users.
++ i*86 | x86_64)
++ basic_machine=$basic_machine-pc
++ ;;
++ # Object if more than one company name word.
++ *-*-*)
++ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
++ exit 1
++ ;;
++ # Recognize the basic CPU types with company name.
++ 580-* \
++ | a29k-* \
++ | aarch64-* | aarch64_be-* \
++ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
++ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
++ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
++ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
++ | avr-* | avr32-* \
++ | be32-* | be64-* \
++ | bfin-* | bs2000-* \
++ | c[123]* | c30-* | [cjt]90-* | c4x-* \
++ | c8051-* | clipper-* | craynv-* | cydra-* \
++ | d10v-* | d30v-* | dlx-* \
++ | elxsi-* \
++ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
++ | h8300-* | h8500-* \
++ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
++ | hexagon-* \
++ | i*86-* | i860-* | i960-* | ia64-* \
++ | ip2k-* | iq2000-* \
++ | le32-* | le64-* \
++ | lm32-* \
++ | m32c-* | m32r-* | m32rle-* \
++ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
++ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
++ | microblaze-* | microblazeel-* \
++ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
++ | mips16-* \
++ | mips64-* | mips64el-* \
++ | mips64octeon-* | mips64octeonel-* \
++ | mips64orion-* | mips64orionel-* \
++ | mips64r5900-* | mips64r5900el-* \
++ | mips64vr-* | mips64vrel-* \
++ | mips64vr4100-* | mips64vr4100el-* \
++ | mips64vr4300-* | mips64vr4300el-* \
++ | mips64vr5000-* | mips64vr5000el-* \
++ | mips64vr5900-* | mips64vr5900el-* \
++ | mipsisa32-* | mipsisa32el-* \
++ | mipsisa32r2-* | mipsisa32r2el-* \
++ | mipsisa64-* | mipsisa64el-* \
++ | mipsisa64r2-* | mipsisa64r2el-* \
++ | mipsisa64sb1-* | mipsisa64sb1el-* \
++ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
++ | mipsr5900-* | mipsr5900el-* \
++ | mipstx39-* | mipstx39el-* \
++ | mmix-* \
++ | mt-* \
++ | msp430-* \
++ | nds32-* | nds32le-* | nds32be-* \
++ | nios-* | nios2-* | nios2eb-* | nios2el-* \
++ | none-* | np1-* | ns16k-* | ns32k-* \
++ | open8-* \
++ | orion-* \
++ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
++ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
++ | pyramid-* \
++ | rl78-* | romp-* | rs6000-* | rx-* \
++ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
++ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
++ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
++ | sparclite-* \
++ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
++ | tahoe-* \
++ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
++ | tile*-* \
++ | tron-* \
++ | ubicom32-* \
++ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
++ | vax-* \
++ | we32k-* \
++ | x86-* | x86_64-* | xc16x-* | xps100-* \
++ | xstormy16-* | xtensa*-* \
++ | ymp-* \
++ | z8k-* | z80-*)
++ ;;
++ # Recognize the basic CPU types without company name, with glob match.
++ xtensa*)
++ basic_machine=$basic_machine-unknown
++ ;;
++ # Recognize the various machine names and aliases which stand
++ # for a CPU type and a company and sometimes even an OS.
++ 386bsd)
++ basic_machine=i386-unknown
++ os=-bsd
++ ;;
++ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
++ basic_machine=m68000-att
++ ;;
++ 3b*)
++ basic_machine=we32k-att
++ ;;
++ a29khif)
++ basic_machine=a29k-amd
++ os=-udi
++ ;;
++ abacus)
++ basic_machine=abacus-unknown
++ ;;
++ adobe68k)
++ basic_machine=m68010-adobe
++ os=-scout
++ ;;
++ alliant | fx80)
++ basic_machine=fx80-alliant
++ ;;
++ altos | altos3068)
++ basic_machine=m68k-altos
++ ;;
++ am29k)
++ basic_machine=a29k-none
++ os=-bsd
++ ;;
++ amd64)
++ basic_machine=x86_64-pc
++ ;;
++ amd64-*)
++ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ amdahl)
++ basic_machine=580-amdahl
++ os=-sysv
++ ;;
++ amiga | amiga-*)
++ basic_machine=m68k-unknown
++ ;;
++ amigaos | amigados)
++ basic_machine=m68k-unknown
++ os=-amigaos
++ ;;
++ amigaunix | amix)
++ basic_machine=m68k-unknown
++ os=-sysv4
++ ;;
++ apollo68)
++ basic_machine=m68k-apollo
++ os=-sysv
++ ;;
++ apollo68bsd)
++ basic_machine=m68k-apollo
++ os=-bsd
++ ;;
++ aros)
++ basic_machine=i386-pc
++ os=-aros
++ ;;
++ aux)
++ basic_machine=m68k-apple
++ os=-aux
++ ;;
++ balance)
++ basic_machine=ns32k-sequent
++ os=-dynix
++ ;;
++ blackfin)
++ basic_machine=bfin-unknown
++ os=-linux
++ ;;
++ blackfin-*)
++ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
++ os=-linux
++ ;;
++ bluegene*)
++ basic_machine=powerpc-ibm
++ os=-cnk
++ ;;
++ c54x-*)
++ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ c55x-*)
++ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ c6x-*)
++ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ c90)
++ basic_machine=c90-cray
++ os=-unicos
++ ;;
++ cegcc)
++ basic_machine=arm-unknown
++ os=-cegcc
++ ;;
++ convex-c1)
++ basic_machine=c1-convex
++ os=-bsd
++ ;;
++ convex-c2)
++ basic_machine=c2-convex
++ os=-bsd
++ ;;
++ convex-c32)
++ basic_machine=c32-convex
++ os=-bsd
++ ;;
++ convex-c34)
++ basic_machine=c34-convex
++ os=-bsd
++ ;;
++ convex-c38)
++ basic_machine=c38-convex
++ os=-bsd
++ ;;
++ cray | j90)
++ basic_machine=j90-cray
++ os=-unicos
++ ;;
++ craynv)
++ basic_machine=craynv-cray
++ os=-unicosmp
++ ;;
++ cr16 | cr16-*)
++ basic_machine=cr16-unknown
++ os=-elf
++ ;;
++ crds | unos)
++ basic_machine=m68k-crds
++ ;;
++ crisv32 | crisv32-* | etraxfs*)
++ basic_machine=crisv32-axis
++ ;;
++ cris | cris-* | etrax*)
++ basic_machine=cris-axis
++ ;;
++ crx)
++ basic_machine=crx-unknown
++ os=-elf
++ ;;
++ da30 | da30-*)
++ basic_machine=m68k-da30
++ ;;
++ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
++ basic_machine=mips-dec
++ ;;
++ decsystem10* | dec10*)
++ basic_machine=pdp10-dec
++ os=-tops10
++ ;;
++ decsystem20* | dec20*)
++ basic_machine=pdp10-dec
++ os=-tops20
++ ;;
++ delta | 3300 | motorola-3300 | motorola-delta \
++ | 3300-motorola | delta-motorola)
++ basic_machine=m68k-motorola
++ ;;
++ delta88)
++ basic_machine=m88k-motorola
++ os=-sysv3
++ ;;
++ dicos)
++ basic_machine=i686-pc
++ os=-dicos
++ ;;
++ djgpp)
++ basic_machine=i586-pc
++ os=-msdosdjgpp
++ ;;
++ dpx20 | dpx20-*)
++ basic_machine=rs6000-bull
++ os=-bosx
++ ;;
++ dpx2* | dpx2*-bull)
++ basic_machine=m68k-bull
++ os=-sysv3
++ ;;
++ ebmon29k)
++ basic_machine=a29k-amd
++ os=-ebmon
++ ;;
++ elxsi)
++ basic_machine=elxsi-elxsi
++ os=-bsd
++ ;;
++ encore | umax | mmax)
++ basic_machine=ns32k-encore
++ ;;
++ es1800 | OSE68k | ose68k | ose | OSE)
++ basic_machine=m68k-ericsson
++ os=-ose
++ ;;
++ fx2800)
++ basic_machine=i860-alliant
++ ;;
++ genix)
++ basic_machine=ns32k-ns
++ ;;
++ gmicro)
++ basic_machine=tron-gmicro
++ os=-sysv
++ ;;
++ go32)
++ basic_machine=i386-pc
++ os=-go32
++ ;;
++ h3050r* | hiux*)
++ basic_machine=hppa1.1-hitachi
++ os=-hiuxwe2
++ ;;
++ h8300hms)
++ basic_machine=h8300-hitachi
++ os=-hms
++ ;;
++ h8300xray)
++ basic_machine=h8300-hitachi
++ os=-xray
++ ;;
++ h8500hms)
++ basic_machine=h8500-hitachi
++ os=-hms
++ ;;
++ harris)
++ basic_machine=m88k-harris
++ os=-sysv3
++ ;;
++ hp300-*)
++ basic_machine=m68k-hp
++ ;;
++ hp300bsd)
++ basic_machine=m68k-hp
++ os=-bsd
++ ;;
++ hp300hpux)
++ basic_machine=m68k-hp
++ os=-hpux
++ ;;
++ hp3k9[0-9][0-9] | hp9[0-9][0-9])
++ basic_machine=hppa1.0-hp
++ ;;
++ hp9k2[0-9][0-9] | hp9k31[0-9])
++ basic_machine=m68000-hp
++ ;;
++ hp9k3[2-9][0-9])
++ basic_machine=m68k-hp
++ ;;
++ hp9k6[0-9][0-9] | hp6[0-9][0-9])
++ basic_machine=hppa1.0-hp
++ ;;
++ hp9k7[0-79][0-9] | hp7[0-79][0-9])
++ basic_machine=hppa1.1-hp
++ ;;
++ hp9k78[0-9] | hp78[0-9])
++ # FIXME: really hppa2.0-hp
++ basic_machine=hppa1.1-hp
++ ;;
++ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
++ # FIXME: really hppa2.0-hp
++ basic_machine=hppa1.1-hp
++ ;;
++ hp9k8[0-9][13679] | hp8[0-9][13679])
++ basic_machine=hppa1.1-hp
++ ;;
++ hp9k8[0-9][0-9] | hp8[0-9][0-9])
++ basic_machine=hppa1.0-hp
++ ;;
++ hppa-next)
++ os=-nextstep3
++ ;;
++ hppaosf)
++ basic_machine=hppa1.1-hp
++ os=-osf
++ ;;
++ hppro)
++ basic_machine=hppa1.1-hp
++ os=-proelf
++ ;;
++ i370-ibm* | ibm*)
++ basic_machine=i370-ibm
++ ;;
++ i*86v32)
++ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
++ os=-sysv32
++ ;;
++ i*86v4*)
++ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
++ os=-sysv4
++ ;;
++ i*86v)
++ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
++ os=-sysv
++ ;;
++ i*86sol2)
++ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
++ os=-solaris2
++ ;;
++ i386mach)
++ basic_machine=i386-mach
++ os=-mach
++ ;;
++ i386-vsta | vsta)
++ basic_machine=i386-unknown
++ os=-vsta
++ ;;
++ iris | iris4d)
++ basic_machine=mips-sgi
++ case $os in
++ -irix*)
++ ;;
++ *)
++ os=-irix4
++ ;;
++ esac
++ ;;
++ isi68 | isi)
++ basic_machine=m68k-isi
++ os=-sysv
++ ;;
++ m68knommu)
++ basic_machine=m68k-unknown
++ os=-linux
++ ;;
++ m68knommu-*)
++ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
++ os=-linux
++ ;;
++ m88k-omron*)
++ basic_machine=m88k-omron
++ ;;
++ magnum | m3230)
++ basic_machine=mips-mips
++ os=-sysv
++ ;;
++ merlin)
++ basic_machine=ns32k-utek
++ os=-sysv
++ ;;
++ microblaze*)
++ basic_machine=microblaze-xilinx
++ ;;
++ mingw64)
++ basic_machine=x86_64-pc
++ os=-mingw64
++ ;;
++ mingw32)
++ basic_machine=i686-pc
++ os=-mingw32
++ ;;
++ mingw32ce)
++ basic_machine=arm-unknown
++ os=-mingw32ce
++ ;;
++ miniframe)
++ basic_machine=m68000-convergent
++ ;;
++ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
++ basic_machine=m68k-atari
++ os=-mint
++ ;;
++ mips3*-*)
++ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
++ ;;
++ mips3*)
++ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
++ ;;
++ monitor)
++ basic_machine=m68k-rom68k
++ os=-coff
++ ;;
++ morphos)
++ basic_machine=powerpc-unknown
++ os=-morphos
++ ;;
++ msdos)
++ basic_machine=i386-pc
++ os=-msdos
++ ;;
++ ms1-*)
++ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
++ ;;
++ msys)
++ basic_machine=i686-pc
++ os=-msys
++ ;;
++ mvs)
++ basic_machine=i370-ibm
++ os=-mvs
++ ;;
++ nacl)
++ basic_machine=le32-unknown
++ os=-nacl
++ ;;
++ ncr3000)
++ basic_machine=i486-ncr
++ os=-sysv4
++ ;;
++ netbsd386)
++ basic_machine=i386-unknown
++ os=-netbsd
++ ;;
++ netwinder)
++ basic_machine=armv4l-rebel
++ os=-linux
++ ;;
++ news | news700 | news800 | news900)
++ basic_machine=m68k-sony
++ os=-newsos
++ ;;
++ news1000)
++ basic_machine=m68030-sony
++ os=-newsos
++ ;;
++ news-3600 | risc-news)
++ basic_machine=mips-sony
++ os=-newsos
++ ;;
++ necv70)
++ basic_machine=v70-nec
++ os=-sysv
++ ;;
++ next | m*-next )
++ basic_machine=m68k-next
++ case $os in
++ -nextstep* )
++ ;;
++ -ns2*)
++ os=-nextstep2
++ ;;
++ *)
++ os=-nextstep3
++ ;;
++ esac
++ ;;
++ nh3000)
++ basic_machine=m68k-harris
++ os=-cxux
++ ;;
++ nh[45]000)
++ basic_machine=m88k-harris
++ os=-cxux
++ ;;
++ nindy960)
++ basic_machine=i960-intel
++ os=-nindy
++ ;;
++ mon960)
++ basic_machine=i960-intel
++ os=-mon960
++ ;;
++ nonstopux)
++ basic_machine=mips-compaq
++ os=-nonstopux
++ ;;
++ np1)
++ basic_machine=np1-gould
++ ;;
++ neo-tandem)
++ basic_machine=neo-tandem
++ ;;
++ nse-tandem)
++ basic_machine=nse-tandem
++ ;;
++ nsr-tandem)
++ basic_machine=nsr-tandem
++ ;;
++ op50n-* | op60c-*)
++ basic_machine=hppa1.1-oki
++ os=-proelf
++ ;;
++ openrisc | openrisc-*)
++ basic_machine=or32-unknown
++ ;;
++ os400)
++ basic_machine=powerpc-ibm
++ os=-os400
++ ;;
++ OSE68000 | ose68000)
++ basic_machine=m68000-ericsson
++ os=-ose
++ ;;
++ os68k)
++ basic_machine=m68k-none
++ os=-os68k
++ ;;
++ pa-hitachi)
++ basic_machine=hppa1.1-hitachi
++ os=-hiuxwe2
++ ;;
++ paragon)
++ basic_machine=i860-intel
++ os=-osf
++ ;;
++ parisc)
++ basic_machine=hppa-unknown
++ os=-linux
++ ;;
++ parisc-*)
++ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
++ os=-linux
++ ;;
++ pbd)
++ basic_machine=sparc-tti
++ ;;
++ pbb)
++ basic_machine=m68k-tti
++ ;;
++ pc532 | pc532-*)
++ basic_machine=ns32k-pc532
++ ;;
++ pc98)
++ basic_machine=i386-pc
++ ;;
++ pc98-*)
++ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ pentium | p5 | k5 | k6 | nexgen | viac3)
++ basic_machine=i586-pc
++ ;;
++ pentiumpro | p6 | 6x86 | athlon | athlon_*)
++ basic_machine=i686-pc
++ ;;
++ pentiumii | pentium2 | pentiumiii | pentium3)
++ basic_machine=i686-pc
++ ;;
++ pentium4)
++ basic_machine=i786-pc
++ ;;
++ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
++ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ pentiumpro-* | p6-* | 6x86-* | athlon-*)
++ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
++ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ pentium4-*)
++ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ pn)
++ basic_machine=pn-gould
++ ;;
++ power) basic_machine=power-ibm
++ ;;
++ ppc | ppcbe) basic_machine=powerpc-unknown
++ ;;
++ ppc-* | ppcbe-*)
++ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ ppcle | powerpclittle | ppc-le | powerpc-little)
++ basic_machine=powerpcle-unknown
++ ;;
++ ppcle-* | powerpclittle-*)
++ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ ppc64) basic_machine=powerpc64-unknown
++ ;;
++ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
++ basic_machine=powerpc64le-unknown
++ ;;
++ ppc64le-* | powerpc64little-*)
++ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ ps2)
++ basic_machine=i386-ibm
++ ;;
++ pw32)
++ basic_machine=i586-unknown
++ os=-pw32
++ ;;
++ rdos | rdos64)
++ basic_machine=x86_64-pc
++ os=-rdos
++ ;;
++ rdos32)
++ basic_machine=i386-pc
++ os=-rdos
++ ;;
++ rom68k)
++ basic_machine=m68k-rom68k
++ os=-coff
++ ;;
++ rm[46]00)
++ basic_machine=mips-siemens
++ ;;
++ rtpc | rtpc-*)
++ basic_machine=romp-ibm
++ ;;
++ s390 | s390-*)
++ basic_machine=s390-ibm
++ ;;
++ s390x | s390x-*)
++ basic_machine=s390x-ibm
++ ;;
++ sa29200)
++ basic_machine=a29k-amd
++ os=-udi
++ ;;
++ sb1)
++ basic_machine=mipsisa64sb1-unknown
++ ;;
++ sb1el)
++ basic_machine=mipsisa64sb1el-unknown
++ ;;
++ sde)
++ basic_machine=mipsisa32-sde
++ os=-elf
++ ;;
++ sei)
++ basic_machine=mips-sei
++ os=-seiux
++ ;;
++ sequent)
++ basic_machine=i386-sequent
++ ;;
++ sh)
++ basic_machine=sh-hitachi
++ os=-hms
++ ;;
++ sh5el)
++ basic_machine=sh5le-unknown
++ ;;
++ sh64)
++ basic_machine=sh64-unknown
++ ;;
++ sparclite-wrs | simso-wrs)
++ basic_machine=sparclite-wrs
++ os=-vxworks
++ ;;
++ sps7)
++ basic_machine=m68k-bull
++ os=-sysv2
++ ;;
++ spur)
++ basic_machine=spur-unknown
++ ;;
++ st2000)
++ basic_machine=m68k-tandem
++ ;;
++ stratus)
++ basic_machine=i860-stratus
++ os=-sysv4
++ ;;
++ strongarm-* | thumb-*)
++ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
++ ;;
++ sun2)
++ basic_machine=m68000-sun
++ ;;
++ sun2os3)
++ basic_machine=m68000-sun
++ os=-sunos3
++ ;;
++ sun2os4)
++ basic_machine=m68000-sun
++ os=-sunos4
++ ;;
++ sun3os3)
++ basic_machine=m68k-sun
++ os=-sunos3
++ ;;
++ sun3os4)
++ basic_machine=m68k-sun
++ os=-sunos4
++ ;;
++ sun4os3)
++ basic_machine=sparc-sun
++ os=-sunos3
++ ;;
++ sun4os4)
++ basic_machine=sparc-sun
++ os=-sunos4
++ ;;
++ sun4sol2)
++ basic_machine=sparc-sun
++ os=-solaris2
++ ;;
++ sun3 | sun3-*)
++ basic_machine=m68k-sun
++ ;;
++ sun4)
++ basic_machine=sparc-sun
++ ;;
++ sun386 | sun386i | roadrunner)
++ basic_machine=i386-sun
++ ;;
++ sv1)
++ basic_machine=sv1-cray
++ os=-unicos
++ ;;
++ symmetry)
++ basic_machine=i386-sequent
++ os=-dynix
++ ;;
++ t3e)
++ basic_machine=alphaev5-cray
++ os=-unicos
++ ;;
++ t90)
++ basic_machine=t90-cray
++ os=-unicos
++ ;;
++ tile*)
++ basic_machine=$basic_machine-unknown
++ os=-linux-gnu
++ ;;
++ tx39)
++ basic_machine=mipstx39-unknown
++ ;;
++ tx39el)
++ basic_machine=mipstx39el-unknown
++ ;;
++ toad1)
++ basic_machine=pdp10-xkl
++ os=-tops20
++ ;;
++ tower | tower-32)
++ basic_machine=m68k-ncr
++ ;;
++ tpf)
++ basic_machine=s390x-ibm
++ os=-tpf
++ ;;
++ udi29k)
++ basic_machine=a29k-amd
++ os=-udi
++ ;;
++ ultra3)
++ basic_machine=a29k-nyu
++ os=-sym1
++ ;;
++ v810 | necv810)
++ basic_machine=v810-nec
++ os=-none
++ ;;
++ vaxv)
++ basic_machine=vax-dec
++ os=-sysv
++ ;;
++ vms)
++ basic_machine=vax-dec
++ os=-vms
++ ;;
++ vpp*|vx|vx-*)
++ basic_machine=f301-fujitsu
++ ;;
++ vxworks960)
++ basic_machine=i960-wrs
++ os=-vxworks
++ ;;
++ vxworks68)
++ basic_machine=m68k-wrs
++ os=-vxworks
++ ;;
++ vxworks29k)
++ basic_machine=a29k-wrs
++ os=-vxworks
++ ;;
++ w65*)
++ basic_machine=w65-wdc
++ os=-none
++ ;;
++ w89k-*)
++ basic_machine=hppa1.1-winbond
++ os=-proelf
++ ;;
++ xbox)
++ basic_machine=i686-pc
++ os=-mingw32
++ ;;
++ xps | xps100)
++ basic_machine=xps100-honeywell
++ ;;
++ xscale-* | xscalee[bl]-*)
++ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
++ ;;
++ ymp)
++ basic_machine=ymp-cray
++ os=-unicos
++ ;;
++ z8k-*-coff)
++ basic_machine=z8k-unknown
++ os=-sim
++ ;;
++ z80-*-coff)
++ basic_machine=z80-unknown
++ os=-sim
++ ;;
++ none)
++ basic_machine=none-none
++ os=-none
++ ;;
++
++# Here we handle the default manufacturer of certain CPU types. It is in
++# some cases the only manufacturer, in others, it is the most popular.
++ w89k)
++ basic_machine=hppa1.1-winbond
++ ;;
++ op50n)
++ basic_machine=hppa1.1-oki
++ ;;
++ op60c)
++ basic_machine=hppa1.1-oki
++ ;;
++ romp)
++ basic_machine=romp-ibm
++ ;;
++ mmix)
++ basic_machine=mmix-knuth
++ ;;
++ rs6000)
++ basic_machine=rs6000-ibm
++ ;;
++ vax)
++ basic_machine=vax-dec
++ ;;
++ pdp10)
++ # there are many clones, so DEC is not a safe bet
++ basic_machine=pdp10-unknown
++ ;;
++ pdp11)
++ basic_machine=pdp11-dec
++ ;;
++ we32k)
++ basic_machine=we32k-att
++ ;;
++ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
++ basic_machine=sh-unknown
++ ;;
++ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
++ basic_machine=sparc-sun
++ ;;
++ cydra)
++ basic_machine=cydra-cydrome
++ ;;
++ orion)
++ basic_machine=orion-highlevel
++ ;;
++ orion105)
++ basic_machine=clipper-highlevel
++ ;;
++ mac | mpw | mac-mpw)
++ basic_machine=m68k-apple
++ ;;
++ pmac | pmac-mpw)
++ basic_machine=powerpc-apple
++ ;;
++ *-unknown)
++ # Make sure to match an already-canonicalized machine name.
++ ;;
++ *)
++ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
++ exit 1
++ ;;
++esac
++
++# Here we canonicalize certain aliases for manufacturers.
++case $basic_machine in
++ *-digital*)
++ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
++ ;;
++ *-commodore*)
++ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
++ ;;
++ *)
++ ;;
++esac
++
++# Decode manufacturer-specific aliases for certain operating systems.
++
++if [ x"$os" != x"" ]
++then
++case $os in
++ # First match some system type aliases
++ # that might get confused with valid system types.
++ # -solaris* is a basic system type, with this one exception.
++ -auroraux)
++ os=-auroraux
++ ;;
++ -solaris1 | -solaris1.*)
++ os=`echo $os | sed -e 's|solaris1|sunos4|'`
++ ;;
++ -solaris)
++ os=-solaris2
++ ;;
++ -svr4*)
++ os=-sysv4
++ ;;
++ -unixware*)
++ os=-sysv4.2uw
++ ;;
++ -gnu/linux*)
++ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
++ ;;
++ # First accept the basic system types.
++ # The portable systems comes first.
++ # Each alternative MUST END IN A *, to match a version number.
++ # -sysv* is not here because it comes later, after sysvr4.
++ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
++ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
++ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
++ | -sym* | -kopensolaris* | -plan9* \
++ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
++ | -aos* | -aros* \
++ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
++ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
++ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
++ | -bitrig* | -openbsd* | -solidbsd* \
++ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
++ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
++ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
++ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
++ | -chorusos* | -chorusrdb* | -cegcc* \
++ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
++ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
++ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
++ | -uxpv* | -beos* | -mpeix* | -udk* \
++ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
++ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
++ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
++ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
++ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
++ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
++ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
++ # Remember, each alternative MUST END IN *, to match a version number.
++ ;;
++ -qnx*)
++ case $basic_machine in
++ x86-* | i*86-*)
++ ;;
++ *)
++ os=-nto$os
++ ;;
++ esac
++ ;;
++ -nto-qnx*)
++ ;;
++ -nto*)
++ os=`echo $os | sed -e 's|nto|nto-qnx|'`
++ ;;
++ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
++ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
++ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
++ ;;
++ -mac*)
++ os=`echo $os | sed -e 's|mac|macos|'`
++ ;;
++ -linux-dietlibc)
++ os=-linux-dietlibc
++ ;;
++ -linux*)
++ os=`echo $os | sed -e 's|linux|linux-gnu|'`
++ ;;
++ -sunos5*)
++ os=`echo $os | sed -e 's|sunos5|solaris2|'`
++ ;;
++ -sunos6*)
++ os=`echo $os | sed -e 's|sunos6|solaris3|'`
++ ;;
++ -opened*)
++ os=-openedition
++ ;;
++ -os400*)
++ os=-os400
++ ;;
++ -wince*)
++ os=-wince
++ ;;
++ -osfrose*)
++ os=-osfrose
++ ;;
++ -osf*)
++ os=-osf
++ ;;
++ -utek*)
++ os=-bsd
++ ;;
++ -dynix*)
++ os=-bsd
++ ;;
++ -acis*)
++ os=-aos
++ ;;
++ -atheos*)
++ os=-atheos
++ ;;
++ -syllable*)
++ os=-syllable
++ ;;
++ -386bsd)
++ os=-bsd
++ ;;
++ -ctix* | -uts*)
++ os=-sysv
++ ;;
++ -nova*)
++ os=-rtmk-nova
++ ;;
++ -ns2 )
++ os=-nextstep2
++ ;;
++ -nsk*)
++ os=-nsk
++ ;;
++ # Preserve the version number of sinix5.
++ -sinix5.*)
++ os=`echo $os | sed -e 's|sinix|sysv|'`
++ ;;
++ -sinix*)
++ os=-sysv4
++ ;;
++ -tpf*)
++ os=-tpf
++ ;;
++ -triton*)
++ os=-sysv3
++ ;;
++ -oss*)
++ os=-sysv3
++ ;;
++ -svr4)
++ os=-sysv4
++ ;;
++ -svr3)
++ os=-sysv3
++ ;;
++ -sysvr4)
++ os=-sysv4
++ ;;
++ # This must come after -sysvr4.
++ -sysv*)
++ ;;
++ -ose*)
++ os=-ose
++ ;;
++ -es1800*)
++ os=-ose
++ ;;
++ -xenix)
++ os=-xenix
++ ;;
++ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
++ os=-mint
++ ;;
++ -aros*)
++ os=-aros
++ ;;
++ -zvmoe)
++ os=-zvmoe
++ ;;
++ -dicos*)
++ os=-dicos
++ ;;
++ -nacl*)
++ ;;
++ -none)
++ ;;
++ *)
++ # Get rid of the `-' at the beginning of $os.
++ os=`echo $os | sed 's/[^-]*-//'`
++ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
++ exit 1
++ ;;
++esac
++else
++
++# Here we handle the default operating systems that come with various machines.
++# The value should be what the vendor currently ships out the door with their
++# machine or put another way, the most popular os provided with the machine.
++
++# Note that if you're going to try to match "-MANUFACTURER" here (say,
++# "-sun"), then you have to tell the case statement up towards the top
++# that MANUFACTURER isn't an operating system. Otherwise, code above
++# will signal an error saying that MANUFACTURER isn't an operating
++# system, and we'll never get to this point.
++
++case $basic_machine in
++ score-*)
++ os=-elf
++ ;;
++ spu-*)
++ os=-elf
++ ;;
++ *-acorn)
++ os=-riscix1.2
++ ;;
++ arm*-rebel)
++ os=-linux
++ ;;
++ arm*-semi)
++ os=-aout
++ ;;
++ c4x-* | tic4x-*)
++ os=-coff
++ ;;
++ c8051-*)
++ os=-elf
++ ;;
++ hexagon-*)
++ os=-elf
++ ;;
++ tic54x-*)
++ os=-coff
++ ;;
++ tic55x-*)
++ os=-coff
++ ;;
++ tic6x-*)
++ os=-coff
++ ;;
++ # This must come before the *-dec entry.
++ pdp10-*)
++ os=-tops20
++ ;;
++ pdp11-*)
++ os=-none
++ ;;
++ *-dec | vax-*)
++ os=-ultrix4.2
++ ;;
++ m68*-apollo)
++ os=-domain
++ ;;
++ i386-sun)
++ os=-sunos4.0.2
++ ;;
++ m68000-sun)
++ os=-sunos3
++ ;;
++ m68*-cisco)
++ os=-aout
++ ;;
++ mep-*)
++ os=-elf
++ ;;
++ mips*-cisco)
++ os=-elf
++ ;;
++ mips*-*)
++ os=-elf
++ ;;
++ or1k-*)
++ os=-elf
++ ;;
++ or32-*)
++ os=-coff
++ ;;
++ *-tti) # must be before sparc entry or we get the wrong os.
++ os=-sysv3
++ ;;
++ sparc-* | *-sun)
++ os=-sunos4.1.1
++ ;;
++ *-be)
++ os=-beos
++ ;;
++ *-haiku)
++ os=-haiku
++ ;;
++ *-ibm)
++ os=-aix
++ ;;
++ *-knuth)
++ os=-mmixware
++ ;;
++ *-wec)
++ os=-proelf
++ ;;
++ *-winbond)
++ os=-proelf
++ ;;
++ *-oki)
++ os=-proelf
++ ;;
++ *-hp)
++ os=-hpux
++ ;;
++ *-hitachi)
++ os=-hiux
++ ;;
++ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
++ os=-sysv
++ ;;
++ *-cbm)
++ os=-amigaos
++ ;;
++ *-dg)
++ os=-dgux
++ ;;
++ *-dolphin)
++ os=-sysv3
++ ;;
++ m68k-ccur)
++ os=-rtu
++ ;;
++ m88k-omron*)
++ os=-luna
++ ;;
++ *-next )
++ os=-nextstep
++ ;;
++ *-sequent)
++ os=-ptx
++ ;;
++ *-crds)
++ os=-unos
++ ;;
++ *-ns)
++ os=-genix
++ ;;
++ i370-*)
++ os=-mvs
++ ;;
++ *-next)
++ os=-nextstep3
++ ;;
++ *-gould)
++ os=-sysv
++ ;;
++ *-highlevel)
++ os=-bsd
++ ;;
++ *-encore)
++ os=-bsd
++ ;;
++ *-sgi)
++ os=-irix
++ ;;
++ *-siemens)
++ os=-sysv4
++ ;;
++ *-masscomp)
++ os=-rtu
++ ;;
++ f30[01]-fujitsu | f700-fujitsu)
++ os=-uxpv
++ ;;
++ *-rom68k)
++ os=-coff
++ ;;
++ *-*bug)
++ os=-coff
++ ;;
++ *-apple)
++ os=-macos
++ ;;
++ *-atari*)
++ os=-mint
++ ;;
++ *)
++ os=-none
++ ;;
++esac
++fi
++
++# Here we handle the case where we know the os, and the CPU type, but not the
++# manufacturer. We pick the logical manufacturer.
++vendor=unknown
++case $basic_machine in
++ *-unknown)
++ case $os in
++ -riscix*)
++ vendor=acorn
++ ;;
++ -sunos*)
++ vendor=sun
++ ;;
++ -cnk*|-aix*)
++ vendor=ibm
++ ;;
++ -beos*)
++ vendor=be
++ ;;
++ -hpux*)
++ vendor=hp
++ ;;
++ -mpeix*)
++ vendor=hp
++ ;;
++ -hiux*)
++ vendor=hitachi
++ ;;
++ -unos*)
++ vendor=crds
++ ;;
++ -dgux*)
++ vendor=dg
++ ;;
++ -luna*)
++ vendor=omron
++ ;;
++ -genix*)
++ vendor=ns
++ ;;
++ -mvs* | -opened*)
++ vendor=ibm
++ ;;
++ -os400*)
++ vendor=ibm
++ ;;
++ -ptx*)
++ vendor=sequent
++ ;;
++ -tpf*)
++ vendor=ibm
++ ;;
++ -vxsim* | -vxworks* | -windiss*)
++ vendor=wrs
++ ;;
++ -aux*)
++ vendor=apple
++ ;;
++ -hms*)
++ vendor=hitachi
++ ;;
++ -mpw* | -macos*)
++ vendor=apple
++ ;;
++ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
++ vendor=atari
++ ;;
++ -vos*)
++ vendor=stratus
++ ;;
++ esac
++ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
++ ;;
++esac
++
++echo $basic_machine$os
++exit
++
++# Local variables:
++# eval: (add-hook 'write-file-hooks 'time-stamp)
++# time-stamp-start: "timestamp='"
++# time-stamp-format: "%:y-%02m-%02d"
++# time-stamp-end: "'"
++# End:
+--- /dev/null
++++ b/aclocal.m4
+@@ -0,0 +1,1073 @@
++# generated automatically by aclocal 1.13.3 -*- Autoconf -*-
++
++# Copyright (C) 1996-2013 Free Software Foundation, Inc.
++
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
++# PARTICULAR PURPOSE.
++
++m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
++m4_ifndef([AC_AUTOCONF_VERSION],
++ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
++m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
++[m4_warning([this file was generated for autoconf 2.69.
++You have another version of autoconf. It may work, but is not guaranteed to.
++If you have problems, you may need to regenerate the build system entirely.
++To do so, use the procedure documented by the package, typically 'autoreconf'.])])
++
++# Copyright (C) 2002-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# AM_AUTOMAKE_VERSION(VERSION)
++# ----------------------------
++# Automake X.Y traces this macro to ensure aclocal.m4 has been
++# generated from the m4 files accompanying Automake X.Y.
++# (This private macro should not be called outside this file.)
++AC_DEFUN([AM_AUTOMAKE_VERSION],
++[am__api_version='1.13'
++dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
++dnl require some minimum version. Point them to the right macro.
++m4_if([$1], [1.13.3], [],
++ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
++])
++
++# _AM_AUTOCONF_VERSION(VERSION)
++# -----------------------------
++# aclocal traces this macro to find the Autoconf version.
++# This is a private macro too. Using m4_define simplifies
++# the logic in aclocal, which can simply ignore this definition.
++m4_define([_AM_AUTOCONF_VERSION], [])
++
++# AM_SET_CURRENT_AUTOMAKE_VERSION
++# -------------------------------
++# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
++# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
++AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
++[AM_AUTOMAKE_VERSION([1.13.3])dnl
++m4_ifndef([AC_AUTOCONF_VERSION],
++ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
++_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
++
++# AM_AUX_DIR_EXPAND -*- Autoconf -*-
++
++# Copyright (C) 2001-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
++# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
++# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
++#
++# Of course, Automake must honor this variable whenever it calls a
++# tool from the auxiliary directory. The problem is that $srcdir (and
++# therefore $ac_aux_dir as well) can be either absolute or relative,
++# depending on how configure is run. This is pretty annoying, since
++# it makes $ac_aux_dir quite unusable in subdirectories: in the top
++# source directory, any form will work fine, but in subdirectories a
++# relative path needs to be adjusted first.
++#
++# $ac_aux_dir/missing
++# fails when called from a subdirectory if $ac_aux_dir is relative
++# $top_srcdir/$ac_aux_dir/missing
++# fails if $ac_aux_dir is absolute,
++# fails when called from a subdirectory in a VPATH build with
++# a relative $ac_aux_dir
++#
++# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
++# are both prefixed by $srcdir. In an in-source build this is usually
++# harmless because $srcdir is '.', but things will broke when you
++# start a VPATH build or use an absolute $srcdir.
++#
++# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
++# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
++# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
++# and then we would define $MISSING as
++# MISSING="\${SHELL} $am_aux_dir/missing"
++# This will work as long as MISSING is not called from configure, because
++# unfortunately $(top_srcdir) has no meaning in configure.
++# However there are other variables, like CC, which are often used in
++# configure, and could therefore not use this "fixed" $ac_aux_dir.
++#
++# Another solution, used here, is to always expand $ac_aux_dir to an
++# absolute PATH. The drawback is that using absolute paths prevent a
++# configured tree to be moved without reconfiguration.
++
++AC_DEFUN([AM_AUX_DIR_EXPAND],
++[dnl Rely on autoconf to set up CDPATH properly.
++AC_PREREQ([2.50])dnl
++# expand $ac_aux_dir to an absolute path
++am_aux_dir=`cd $ac_aux_dir && pwd`
++])
++
++# AM_CONDITIONAL -*- Autoconf -*-
++
++# Copyright (C) 1997-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# AM_CONDITIONAL(NAME, SHELL-CONDITION)
++# -------------------------------------
++# Define a conditional.
++AC_DEFUN([AM_CONDITIONAL],
++[AC_PREREQ([2.52])dnl
++ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
++ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
++AC_SUBST([$1_TRUE])dnl
++AC_SUBST([$1_FALSE])dnl
++_AM_SUBST_NOTMAKE([$1_TRUE])dnl
++_AM_SUBST_NOTMAKE([$1_FALSE])dnl
++m4_define([_AM_COND_VALUE_$1], [$2])dnl
++if $2; then
++ $1_TRUE=
++ $1_FALSE='#'
++else
++ $1_TRUE='#'
++ $1_FALSE=
++fi
++AC_CONFIG_COMMANDS_PRE(
++[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
++ AC_MSG_ERROR([[conditional "$1" was never defined.
++Usually this means the macro was only invoked conditionally.]])
++fi])])
++
++# Copyright (C) 1999-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++
++# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
++# written in clear, in which case automake, when reading aclocal.m4,
++# will think it sees a *use*, and therefore will trigger all it's
++# C support machinery. Also note that it means that autoscan, seeing
++# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
++
++
++# _AM_DEPENDENCIES(NAME)
++# ----------------------
++# See how the compiler implements dependency checking.
++# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
++# We try a few techniques and use that to set a single cache variable.
++#
++# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
++# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
++# dependency, and given that the user is not expected to run this macro,
++# just rely on AC_PROG_CC.
++AC_DEFUN([_AM_DEPENDENCIES],
++[AC_REQUIRE([AM_SET_DEPDIR])dnl
++AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
++AC_REQUIRE([AM_MAKE_INCLUDE])dnl
++AC_REQUIRE([AM_DEP_TRACK])dnl
++
++m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
++ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
++ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
++ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
++ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
++ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
++ [depcc="$$1" am_compiler_list=])
++
++AC_CACHE_CHECK([dependency style of $depcc],
++ [am_cv_$1_dependencies_compiler_type],
++[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
++ # We make a subdir and do the tests there. Otherwise we can end up
++ # making bogus files that we don't know about and never remove. For
++ # instance it was reported that on HP-UX the gcc test will end up
++ # making a dummy file named 'D' -- because '-MD' means "put the output
++ # in D".
++ rm -rf conftest.dir
++ mkdir conftest.dir
++ # Copy depcomp to subdir because otherwise we won't find it if we're
++ # using a relative directory.
++ cp "$am_depcomp" conftest.dir
++ cd conftest.dir
++ # We will build objects and dependencies in a subdirectory because
++ # it helps to detect inapplicable dependency modes. For instance
++ # both Tru64's cc and ICC support -MD to output dependencies as a
++ # side effect of compilation, but ICC will put the dependencies in
++ # the current directory while Tru64 will put them in the object
++ # directory.
++ mkdir sub
++
++ am_cv_$1_dependencies_compiler_type=none
++ if test "$am_compiler_list" = ""; then
++ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
++ fi
++ am__universal=false
++ m4_case([$1], [CC],
++ [case " $depcc " in #(
++ *\ -arch\ *\ -arch\ *) am__universal=true ;;
++ esac],
++ [CXX],
++ [case " $depcc " in #(
++ *\ -arch\ *\ -arch\ *) am__universal=true ;;
++ esac])
++
++ for depmode in $am_compiler_list; do
++ # Setup a source with many dependencies, because some compilers
++ # like to wrap large dependency lists on column 80 (with \), and
++ # we should not choose a depcomp mode which is confused by this.
++ #
++ # We need to recreate these files for each test, as the compiler may
++ # overwrite some of them when testing with obscure command lines.
++ # This happens at least with the AIX C compiler.
++ : > sub/conftest.c
++ for i in 1 2 3 4 5 6; do
++ echo '#include "conftst'$i'.h"' >> sub/conftest.c
++ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
++ # Solaris 10 /bin/sh.
++ echo '/* dummy */' > sub/conftst$i.h
++ done
++ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
++
++ # We check with '-c' and '-o' for the sake of the "dashmstdout"
++ # mode. It turns out that the SunPro C++ compiler does not properly
++ # handle '-M -o', and we need to detect this. Also, some Intel
++ # versions had trouble with output in subdirs.
++ am__obj=sub/conftest.${OBJEXT-o}
++ am__minus_obj="-o $am__obj"
++ case $depmode in
++ gcc)
++ # This depmode causes a compiler race in universal mode.
++ test "$am__universal" = false || continue
++ ;;
++ nosideeffect)
++ # After this tag, mechanisms are not by side-effect, so they'll
++ # only be used when explicitly requested.
++ if test "x$enable_dependency_tracking" = xyes; then
++ continue
++ else
++ break
++ fi
++ ;;
++ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
++ # This compiler won't grok '-c -o', but also, the minuso test has
++ # not run yet. These depmodes are late enough in the game, and
++ # so weak that their functioning should not be impacted.
++ am__obj=conftest.${OBJEXT-o}
++ am__minus_obj=
++ ;;
++ none) break ;;
++ esac
++ if depmode=$depmode \
++ source=sub/conftest.c object=$am__obj \
++ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
++ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
++ >/dev/null 2>conftest.err &&
++ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
++ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
++ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
++ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
++ # icc doesn't choke on unknown options, it will just issue warnings
++ # or remarks (even with -Werror). So we grep stderr for any message
++ # that says an option was ignored or not supported.
++ # When given -MP, icc 7.0 and 7.1 complain thusly:
++ # icc: Command line warning: ignoring option '-M'; no argument required
++ # The diagnosis changed in icc 8.0:
++ # icc: Command line remark: option '-MP' not supported
++ if (grep 'ignoring option' conftest.err ||
++ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
++ am_cv_$1_dependencies_compiler_type=$depmode
++ break
++ fi
++ fi
++ done
++
++ cd ..
++ rm -rf conftest.dir
++else
++ am_cv_$1_dependencies_compiler_type=none
++fi
++])
++AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
++AM_CONDITIONAL([am__fastdep$1], [
++ test "x$enable_dependency_tracking" != xno \
++ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
++])
++
++
++# AM_SET_DEPDIR
++# -------------
++# Choose a directory name for dependency files.
++# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
++AC_DEFUN([AM_SET_DEPDIR],
++[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
++AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
++])
++
++
++# AM_DEP_TRACK
++# ------------
++AC_DEFUN([AM_DEP_TRACK],
++[AC_ARG_ENABLE([dependency-tracking], [dnl
++AS_HELP_STRING(
++ [--enable-dependency-tracking],
++ [do not reject slow dependency extractors])
++AS_HELP_STRING(
++ [--disable-dependency-tracking],
++ [speeds up one-time build])])
++if test "x$enable_dependency_tracking" != xno; then
++ am_depcomp="$ac_aux_dir/depcomp"
++ AMDEPBACKSLASH='\'
++ am__nodep='_no'
++fi
++AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
++AC_SUBST([AMDEPBACKSLASH])dnl
++_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
++AC_SUBST([am__nodep])dnl
++_AM_SUBST_NOTMAKE([am__nodep])dnl
++])
++
++# Generate code to set up dependency tracking. -*- Autoconf -*-
++
++# Copyright (C) 1999-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++
++# _AM_OUTPUT_DEPENDENCY_COMMANDS
++# ------------------------------
++AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
++[{
++ # Older Autoconf quotes --file arguments for eval, but not when files
++ # are listed without --file. Let's play safe and only enable the eval
++ # if we detect the quoting.
++ case $CONFIG_FILES in
++ *\'*) eval set x "$CONFIG_FILES" ;;
++ *) set x $CONFIG_FILES ;;
++ esac
++ shift
++ for mf
++ do
++ # Strip MF so we end up with the name of the file.
++ mf=`echo "$mf" | sed -e 's/:.*$//'`
++ # Check whether this is an Automake generated Makefile or not.
++ # We used to match only the files named 'Makefile.in', but
++ # some people rename them; so instead we look at the file content.
++ # Grep'ing the first line is not enough: some people post-process
++ # each Makefile.in and add a new line on top of each file to say so.
++ # Grep'ing the whole file is not good either: AIX grep has a line
++ # limit of 2048, but all sed's we know have understand at least 4000.
++ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
++ dirpart=`AS_DIRNAME("$mf")`
++ else
++ continue
++ fi
++ # Extract the definition of DEPDIR, am__include, and am__quote
++ # from the Makefile without running 'make'.
++ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
++ test -z "$DEPDIR" && continue
++ am__include=`sed -n 's/^am__include = //p' < "$mf"`
++ test -z "$am__include" && continue
++ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
++ # Find all dependency output files, they are included files with
++ # $(DEPDIR) in their names. We invoke sed twice because it is the
++ # simplest approach to changing $(DEPDIR) to its actual value in the
++ # expansion.
++ for file in `sed -n "
++ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
++ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
++ # Make sure the directory exists.
++ test -f "$dirpart/$file" && continue
++ fdir=`AS_DIRNAME(["$file"])`
++ AS_MKDIR_P([$dirpart/$fdir])
++ # echo "creating $dirpart/$file"
++ echo '# dummy' > "$dirpart/$file"
++ done
++ done
++}
++])# _AM_OUTPUT_DEPENDENCY_COMMANDS
++
++
++# AM_OUTPUT_DEPENDENCY_COMMANDS
++# -----------------------------
++# This macro should only be invoked once -- use via AC_REQUIRE.
++#
++# This code is only required when automatic dependency tracking
++# is enabled. FIXME. This creates each '.P' file that we will
++# need in order to bootstrap the dependency handling code.
++AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
++[AC_CONFIG_COMMANDS([depfiles],
++ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
++ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
++])
++
++# Do all the work for Automake. -*- Autoconf -*-
++
++# Copyright (C) 1996-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# This macro actually does too much. Some checks are only needed if
++# your package does certain things. But this isn't really a big deal.
++
++# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
++# AM_INIT_AUTOMAKE([OPTIONS])
++# -----------------------------------------------
++# The call with PACKAGE and VERSION arguments is the old style
++# call (pre autoconf-2.50), which is being phased out. PACKAGE
++# and VERSION should now be passed to AC_INIT and removed from
++# the call to AM_INIT_AUTOMAKE.
++# We support both call styles for the transition. After
++# the next Automake release, Autoconf can make the AC_INIT
++# arguments mandatory, and then we can depend on a new Autoconf
++# release and drop the old call support.
++AC_DEFUN([AM_INIT_AUTOMAKE],
++[AC_PREREQ([2.65])dnl
++dnl Autoconf wants to disallow AM_ names. We explicitly allow
++dnl the ones we care about.
++m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
++AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
++AC_REQUIRE([AC_PROG_INSTALL])dnl
++if test "`cd $srcdir && pwd`" != "`pwd`"; then
++ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
++ # is not polluted with repeated "-I."
++ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
++ # test to see if srcdir already configured
++ if test -f $srcdir/config.status; then
++ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
++ fi
++fi
++
++# test whether we have cygpath
++if test -z "$CYGPATH_W"; then
++ if (cygpath --version) >/dev/null 2>/dev/null; then
++ CYGPATH_W='cygpath -w'
++ else
++ CYGPATH_W=echo
++ fi
++fi
++AC_SUBST([CYGPATH_W])
++
++# Define the identity of the package.
++dnl Distinguish between old-style and new-style calls.
++m4_ifval([$2],
++[AC_DIAGNOSE([obsolete],
++ [$0: two- and three-arguments forms are deprecated.])
++m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
++ AC_SUBST([PACKAGE], [$1])dnl
++ AC_SUBST([VERSION], [$2])],
++[_AM_SET_OPTIONS([$1])dnl
++dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
++m4_if(
++ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
++ [ok:ok],,
++ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
++ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
++ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
++
++_AM_IF_OPTION([no-define],,
++[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
++ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
++
++# Some tools Automake needs.
++AC_REQUIRE([AM_SANITY_CHECK])dnl
++AC_REQUIRE([AC_ARG_PROGRAM])dnl
++AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
++AM_MISSING_PROG([AUTOCONF], [autoconf])
++AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
++AM_MISSING_PROG([AUTOHEADER], [autoheader])
++AM_MISSING_PROG([MAKEINFO], [makeinfo])
++AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
++AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
++AC_REQUIRE([AC_PROG_MKDIR_P])dnl
++# For better backward compatibility. To be removed once Automake 1.9.x
++# dies out for good. For more background, see:
++# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
++# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
++AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
++# We need awk for the "check" target. The system "awk" is bad on
++# some platforms.
++AC_REQUIRE([AC_PROG_AWK])dnl
++AC_REQUIRE([AC_PROG_MAKE_SET])dnl
++AC_REQUIRE([AM_SET_LEADING_DOT])dnl
++_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
++ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
++ [_AM_PROG_TAR([v7])])])
++_AM_IF_OPTION([no-dependencies],,
++[AC_PROVIDE_IFELSE([AC_PROG_CC],
++ [_AM_DEPENDENCIES([CC])],
++ [m4_define([AC_PROG_CC],
++ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
++AC_PROVIDE_IFELSE([AC_PROG_CXX],
++ [_AM_DEPENDENCIES([CXX])],
++ [m4_define([AC_PROG_CXX],
++ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
++AC_PROVIDE_IFELSE([AC_PROG_OBJC],
++ [_AM_DEPENDENCIES([OBJC])],
++ [m4_define([AC_PROG_OBJC],
++ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
++AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
++ [_AM_DEPENDENCIES([OBJCXX])],
++ [m4_define([AC_PROG_OBJCXX],
++ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
++])
++AC_REQUIRE([AM_SILENT_RULES])dnl
++dnl The testsuite driver may need to know about EXEEXT, so add the
++dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
++dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
++AC_CONFIG_COMMANDS_PRE(dnl
++[m4_provide_if([_AM_COMPILER_EXEEXT],
++ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
++])
++
++dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
++dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
++dnl mangled by Autoconf and run in a shell conditional statement.
++m4_define([_AC_COMPILER_EXEEXT],
++m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
++
++
++# When config.status generates a header, we must update the stamp-h file.
++# This file resides in the same directory as the config header
++# that is generated. The stamp files are numbered to have different names.
++
++# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
++# loop where config.status creates the headers, so we can generate
++# our stamp files there.
++AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
++[# Compute $1's index in $config_headers.
++_am_arg=$1
++_am_stamp_count=1
++for _am_header in $config_headers :; do
++ case $_am_header in
++ $_am_arg | $_am_arg:* )
++ break ;;
++ * )
++ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
++ esac
++done
++echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
++
++# Copyright (C) 2001-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# AM_PROG_INSTALL_SH
++# ------------------
++# Define $install_sh.
++AC_DEFUN([AM_PROG_INSTALL_SH],
++[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
++if test x"${install_sh}" != xset; then
++ case $am_aux_dir in
++ *\ * | *\ *)
++ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
++ *)
++ install_sh="\${SHELL} $am_aux_dir/install-sh"
++ esac
++fi
++AC_SUBST([install_sh])])
++
++# Copyright (C) 2003-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# Check whether the underlying file-system supports filenames
++# with a leading dot. For instance MS-DOS doesn't.
++AC_DEFUN([AM_SET_LEADING_DOT],
++[rm -rf .tst 2>/dev/null
++mkdir .tst 2>/dev/null
++if test -d .tst; then
++ am__leading_dot=.
++else
++ am__leading_dot=_
++fi
++rmdir .tst 2>/dev/null
++AC_SUBST([am__leading_dot])])
++
++# Check to see how 'make' treats includes. -*- Autoconf -*-
++
++# Copyright (C) 2001-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# AM_MAKE_INCLUDE()
++# -----------------
++# Check to see how make treats includes.
++AC_DEFUN([AM_MAKE_INCLUDE],
++[am_make=${MAKE-make}
++cat > confinc << 'END'
++am__doit:
++ @echo this is the am__doit target
++.PHONY: am__doit
++END
++# If we don't find an include directive, just comment out the code.
++AC_MSG_CHECKING([for style of include used by $am_make])
++am__include="#"
++am__quote=
++_am_result=none
++# First try GNU make style include.
++echo "include confinc" > confmf
++# Ignore all kinds of additional output from 'make'.
++case `$am_make -s -f confmf 2> /dev/null` in #(
++*the\ am__doit\ target*)
++ am__include=include
++ am__quote=
++ _am_result=GNU
++ ;;
++esac
++# Now try BSD make style include.
++if test "$am__include" = "#"; then
++ echo '.include "confinc"' > confmf
++ case `$am_make -s -f confmf 2> /dev/null` in #(
++ *the\ am__doit\ target*)
++ am__include=.include
++ am__quote="\""
++ _am_result=BSD
++ ;;
++ esac
++fi
++AC_SUBST([am__include])
++AC_SUBST([am__quote])
++AC_MSG_RESULT([$_am_result])
++rm -f confinc confmf
++])
++
++# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
++
++# Copyright (C) 1997-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# AM_MISSING_PROG(NAME, PROGRAM)
++# ------------------------------
++AC_DEFUN([AM_MISSING_PROG],
++[AC_REQUIRE([AM_MISSING_HAS_RUN])
++$1=${$1-"${am_missing_run}$2"}
++AC_SUBST($1)])
++
++# AM_MISSING_HAS_RUN
++# ------------------
++# Define MISSING if not defined so far and test if it is modern enough.
++# If it is, set am_missing_run to use it, otherwise, to nothing.
++AC_DEFUN([AM_MISSING_HAS_RUN],
++[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
++AC_REQUIRE_AUX_FILE([missing])dnl
++if test x"${MISSING+set}" != xset; then
++ case $am_aux_dir in
++ *\ * | *\ *)
++ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
++ *)
++ MISSING="\${SHELL} $am_aux_dir/missing" ;;
++ esac
++fi
++# Use eval to expand $SHELL
++if eval "$MISSING --is-lightweight"; then
++ am_missing_run="$MISSING "
++else
++ am_missing_run=
++ AC_MSG_WARN(['missing' script is too old or missing])
++fi
++])
++
++# -*- Autoconf -*-
++# Obsolete and "removed" macros, that must however still report explicit
++# error messages when used, to smooth transition.
++#
++# Copyright (C) 1996-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++AC_DEFUN([AM_CONFIG_HEADER],
++[AC_DIAGNOSE([obsolete],
++['$0': this macro is obsolete.
++You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl
++AC_CONFIG_HEADERS($@)])
++
++AC_DEFUN([AM_PROG_CC_STDC],
++[AC_PROG_CC
++am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc
++AC_DIAGNOSE([obsolete],
++['$0': this macro is obsolete.
++You should simply use the 'AC][_PROG_CC' macro instead.
++Also, your code should no longer depend upon 'am_cv_prog_cc_stdc',
++but upon 'ac_cv_prog_cc_stdc'.])])
++
++AC_DEFUN([AM_C_PROTOTYPES],
++ [AC_FATAL([automatic de-ANSI-fication support has been removed])])
++AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES])
++
++# Helper functions for option handling. -*- Autoconf -*-
++
++# Copyright (C) 2001-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# _AM_MANGLE_OPTION(NAME)
++# -----------------------
++AC_DEFUN([_AM_MANGLE_OPTION],
++[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
++
++# _AM_SET_OPTION(NAME)
++# --------------------
++# Set option NAME. Presently that only means defining a flag for this option.
++AC_DEFUN([_AM_SET_OPTION],
++[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
++
++# _AM_SET_OPTIONS(OPTIONS)
++# ------------------------
++# OPTIONS is a space-separated list of Automake options.
++AC_DEFUN([_AM_SET_OPTIONS],
++[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
++
++# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
++# -------------------------------------------
++# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
++AC_DEFUN([_AM_IF_OPTION],
++[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
++
++# Check to make sure that the build environment is sane. -*- Autoconf -*-
++
++# Copyright (C) 1996-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# AM_SANITY_CHECK
++# ---------------
++AC_DEFUN([AM_SANITY_CHECK],
++[AC_MSG_CHECKING([whether build environment is sane])
++# Reject unsafe characters in $srcdir or the absolute working directory
++# name. Accept space and tab only in the latter.
++am_lf='
++'
++case `pwd` in
++ *[[\\\"\#\$\&\'\`$am_lf]]*)
++ AC_MSG_ERROR([unsafe absolute working directory name]);;
++esac
++case $srcdir in
++ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
++ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
++esac
++
++# Do 'set' in a subshell so we don't clobber the current shell's
++# arguments. Must try -L first in case configure is actually a
++# symlink; some systems play weird games with the mod time of symlinks
++# (eg FreeBSD returns the mod time of the symlink's containing
++# directory).
++if (
++ am_has_slept=no
++ for am_try in 1 2; do
++ echo "timestamp, slept: $am_has_slept" > conftest.file
++ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
++ if test "$[*]" = "X"; then
++ # -L didn't work.
++ set X `ls -t "$srcdir/configure" conftest.file`
++ fi
++ if test "$[*]" != "X $srcdir/configure conftest.file" \
++ && test "$[*]" != "X conftest.file $srcdir/configure"; then
++
++ # If neither matched, then we have a broken ls. This can happen
++ # if, for instance, CONFIG_SHELL is bash and it inherits a
++ # broken ls alias from the environment. This has actually
++ # happened. Such a system could not be considered "sane".
++ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
++ alias in your environment])
++ fi
++ if test "$[2]" = conftest.file || test $am_try -eq 2; then
++ break
++ fi
++ # Just in case.
++ sleep 1
++ am_has_slept=yes
++ done
++ test "$[2]" = conftest.file
++ )
++then
++ # Ok.
++ :
++else
++ AC_MSG_ERROR([newly created file is older than distributed files!
++Check your system clock])
++fi
++AC_MSG_RESULT([yes])
++# If we didn't sleep, we still need to ensure time stamps of config.status and
++# generated files are strictly newer.
++am_sleep_pid=
++if grep 'slept: no' conftest.file >/dev/null 2>&1; then
++ ( sleep 1 ) &
++ am_sleep_pid=$!
++fi
++AC_CONFIG_COMMANDS_PRE(
++ [AC_MSG_CHECKING([that generated files are newer than configure])
++ if test -n "$am_sleep_pid"; then
++ # Hide warnings about reused PIDs.
++ wait $am_sleep_pid 2>/dev/null
++ fi
++ AC_MSG_RESULT([done])])
++rm -f conftest.file
++])
++
++# Copyright (C) 2009-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# AM_SILENT_RULES([DEFAULT])
++# --------------------------
++# Enable less verbose build rules; with the default set to DEFAULT
++# ("yes" being less verbose, "no" or empty being verbose).
++AC_DEFUN([AM_SILENT_RULES],
++[AC_ARG_ENABLE([silent-rules], [dnl
++AS_HELP_STRING(
++ [--enable-silent-rules],
++ [less verbose build output (undo: "make V=1")])
++AS_HELP_STRING(
++ [--disable-silent-rules],
++ [verbose build output (undo: "make V=0")])dnl
++])
++case $enable_silent_rules in @%:@ (((
++ yes) AM_DEFAULT_VERBOSITY=0;;
++ no) AM_DEFAULT_VERBOSITY=1;;
++ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
++esac
++dnl
++dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
++dnl do not support nested variable expansions.
++dnl See automake bug#9928 and bug#10237.
++am_make=${MAKE-make}
++AC_CACHE_CHECK([whether $am_make supports nested variables],
++ [am_cv_make_support_nested_variables],
++ [if AS_ECHO([['TRUE=$(BAR$(V))
++BAR0=false
++BAR1=true
++V=1
++am__doit:
++ @$(TRUE)
++.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
++ am_cv_make_support_nested_variables=yes
++else
++ am_cv_make_support_nested_variables=no
++fi])
++if test $am_cv_make_support_nested_variables = yes; then
++ dnl Using '$V' instead of '$(V)' breaks IRIX make.
++ AM_V='$(V)'
++ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
++else
++ AM_V=$AM_DEFAULT_VERBOSITY
++ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
++fi
++AC_SUBST([AM_V])dnl
++AM_SUBST_NOTMAKE([AM_V])dnl
++AC_SUBST([AM_DEFAULT_V])dnl
++AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
++AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
++AM_BACKSLASH='\'
++AC_SUBST([AM_BACKSLASH])dnl
++_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
++])
++
++# Copyright (C) 2001-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# AM_PROG_INSTALL_STRIP
++# ---------------------
++# One issue with vendor 'install' (even GNU) is that you can't
++# specify the program used to strip binaries. This is especially
++# annoying in cross-compiling environments, where the build's strip
++# is unlikely to handle the host's binaries.
++# Fortunately install-sh will honor a STRIPPROG variable, so we
++# always use install-sh in "make install-strip", and initialize
++# STRIPPROG with the value of the STRIP variable (set by the user).
++AC_DEFUN([AM_PROG_INSTALL_STRIP],
++[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
++# Installed binaries are usually stripped using 'strip' when the user
++# run "make install-strip". However 'strip' might not be the right
++# tool to use in cross-compilation environments, therefore Automake
++# will honor the 'STRIP' environment variable to overrule this program.
++dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
++if test "$cross_compiling" != no; then
++ AC_CHECK_TOOL([STRIP], [strip], :)
++fi
++INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
++AC_SUBST([INSTALL_STRIP_PROGRAM])])
++
++# Copyright (C) 2006-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# _AM_SUBST_NOTMAKE(VARIABLE)
++# ---------------------------
++# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
++# This macro is traced by Automake.
++AC_DEFUN([_AM_SUBST_NOTMAKE])
++
++# AM_SUBST_NOTMAKE(VARIABLE)
++# --------------------------
++# Public sister of _AM_SUBST_NOTMAKE.
++AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
++
++# Check how to create a tarball. -*- Autoconf -*-
++
++# Copyright (C) 2004-2013 Free Software Foundation, Inc.
++#
++# This file is free software; the Free Software Foundation
++# gives unlimited permission to copy and/or distribute it,
++# with or without modifications, as long as this notice is preserved.
++
++# _AM_PROG_TAR(FORMAT)
++# --------------------
++# Check how to create a tarball in format FORMAT.
++# FORMAT should be one of 'v7', 'ustar', or 'pax'.
++#
++# Substitute a variable $(am__tar) that is a command
++# writing to stdout a FORMAT-tarball containing the directory
++# $tardir.
++# tardir=directory && $(am__tar) > result.tar
++#
++# Substitute a variable $(am__untar) that extract such
++# a tarball read from stdin.
++# $(am__untar) < result.tar
++#
++AC_DEFUN([_AM_PROG_TAR],
++[# Always define AMTAR for backward compatibility. Yes, it's still used
++# in the wild :-( We should find a proper way to deprecate it ...
++AC_SUBST([AMTAR], ['$${TAR-tar}'])
++
++# We'll loop over all known methods to create a tar archive until one works.
++_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
++
++m4_if([$1], [v7],
++ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
++
++ [m4_case([$1],
++ [ustar],
++ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
++ # There is notably a 21 bits limit for the UID and the GID. In fact,
++ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
++ # and bug#13588).
++ am_max_uid=2097151 # 2^21 - 1
++ am_max_gid=$am_max_uid
++ # The $UID and $GID variables are not portable, so we need to resort
++ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
++ # below are definitely unexpected, so allow the users to see them
++ # (that is, avoid stderr redirection).
++ am_uid=`id -u || echo unknown`
++ am_gid=`id -g || echo unknown`
++ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
++ if test $am_uid -le $am_max_uid; then
++ AC_MSG_RESULT([yes])
++ else
++ AC_MSG_RESULT([no])
++ _am_tools=none
++ fi
++ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
++ if test $am_gid -le $am_max_gid; then
++ AC_MSG_RESULT([yes])
++ else
++ AC_MSG_RESULT([no])
++ _am_tools=none
++ fi],
++
++ [pax],
++ [],
++
++ [m4_fatal([Unknown tar format])])
++
++ AC_MSG_CHECKING([how to create a $1 tar archive])
++
++ # Go ahead even if we have the value already cached. We do so because we
++ # need to set the values for the 'am__tar' and 'am__untar' variables.
++ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
++
++ for _am_tool in $_am_tools; do
++ case $_am_tool in
++ gnutar)
++ for _am_tar in tar gnutar gtar; do
++ AM_RUN_LOG([$_am_tar --version]) && break
++ done
++ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
++ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
++ am__untar="$_am_tar -xf -"
++ ;;
++ plaintar)
++ # Must skip GNU tar: if it does not support --format= it doesn't create
++ # ustar tarball either.
++ (tar --version) >/dev/null 2>&1 && continue
++ am__tar='tar chf - "$$tardir"'
++ am__tar_='tar chf - "$tardir"'
++ am__untar='tar xf -'
++ ;;
++ pax)
++ am__tar='pax -L -x $1 -w "$$tardir"'
++ am__tar_='pax -L -x $1 -w "$tardir"'
++ am__untar='pax -r'
++ ;;
++ cpio)
++ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
++ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
++ am__untar='cpio -i -H $1 -d'
++ ;;
++ none)
++ am__tar=false
++ am__tar_=false
++ am__untar=false
++ ;;
++ esac
++
++ # If the value was cached, stop now. We just wanted to have am__tar
++ # and am__untar set.
++ test -n "${am_cv_prog_tar_$1}" && break
++
++ # tar/untar a dummy directory, and stop if the command works.
++ rm -rf conftest.dir
++ mkdir conftest.dir
++ echo GrepMe > conftest.dir/file
++ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
++ rm -rf conftest.dir
++ if test -s conftest.tar; then
++ AM_RUN_LOG([$am__untar <conftest.tar])
++ AM_RUN_LOG([cat conftest.dir/file])
++ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
++ fi
++ done
++ rm -rf conftest.dir
++
++ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
++ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
++
++AC_SUBST([am__tar])
++AC_SUBST([am__untar])
++]) # _AM_PROG_TAR
++
++m4_include([m4/libtool.m4])
++m4_include([m4/ltoptions.m4])
++m4_include([m4/ltsugar.m4])
++m4_include([m4/ltversion.m4])
++m4_include([m4/lt~obsolete.m4])
+--- /dev/null
++++ b/missing
+@@ -0,0 +1,215 @@
++#! /bin/sh
++# Common wrapper for a few potentially missing GNU programs.
++
++scriptversion=2012-06-26.16; # UTC
++
++# Copyright (C) 1996-2013 Free Software Foundation, Inc.
++# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2, or (at your option)
++# any later version.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++# As a special exception to the GNU General Public License, if you
++# distribute this file as part of a program that contains a
++# configuration script generated by Autoconf, you may include it under
++# the same distribution terms that you use for the rest of that program.
++
++if test $# -eq 0; then
++ echo 1>&2 "Try '$0 --help' for more information"
++ exit 1
++fi
++
++case $1 in
++
++ --is-lightweight)
++ # Used by our autoconf macros to check whether the available missing
++ # script is modern enough.
++ exit 0
++ ;;
++
++ --run)
++ # Back-compat with the calling convention used by older automake.
++ shift
++ ;;
++
++ -h|--h|--he|--hel|--help)
++ echo "\
++$0 [OPTION]... PROGRAM [ARGUMENT]...
++
++Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
++to PROGRAM being missing or too old.
++
++Options:
++ -h, --help display this help and exit
++ -v, --version output version information and exit
++
++Supported PROGRAM values:
++ aclocal autoconf autoheader autom4te automake makeinfo
++ bison yacc flex lex help2man
++
++Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
++'g' are ignored when checking the name.
++
++Send bug reports to <bug-automake@gnu.org>."
++ exit $?
++ ;;
++
++ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
++ echo "missing $scriptversion (GNU Automake)"
++ exit $?
++ ;;
++
++ -*)
++ echo 1>&2 "$0: unknown '$1' option"
++ echo 1>&2 "Try '$0 --help' for more information"
++ exit 1
++ ;;
++
++esac
++
++# Run the given program, remember its exit status.
++"$@"; st=$?
++
++# If it succeeded, we are done.
++test $st -eq 0 && exit 0
++
++# Also exit now if we it failed (or wasn't found), and '--version' was
++# passed; such an option is passed most likely to detect whether the
++# program is present and works.
++case $2 in --version|--help) exit $st;; esac
++
++# Exit code 63 means version mismatch. This often happens when the user
++# tries to use an ancient version of a tool on a file that requires a
++# minimum version.
++if test $st -eq 63; then
++ msg="probably too old"
++elif test $st -eq 127; then
++ # Program was missing.
++ msg="missing on your system"
++else
++ # Program was found and executed, but failed. Give up.
++ exit $st
++fi
++
++perl_URL=http://www.perl.org/
++flex_URL=http://flex.sourceforge.net/
++gnu_software_URL=http://www.gnu.org/software
++
++program_details ()
++{
++ case $1 in
++ aclocal|automake)
++ echo "The '$1' program is part of the GNU Automake package:"
++ echo "<$gnu_software_URL/automake>"
++ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
++ echo "<$gnu_software_URL/autoconf>"
++ echo "<$gnu_software_URL/m4/>"
++ echo "<$perl_URL>"
++ ;;
++ autoconf|autom4te|autoheader)
++ echo "The '$1' program is part of the GNU Autoconf package:"
++ echo "<$gnu_software_URL/autoconf/>"
++ echo "It also requires GNU m4 and Perl in order to run:"
++ echo "<$gnu_software_URL/m4/>"
++ echo "<$perl_URL>"
++ ;;
++ esac
++}
++
++give_advice ()
++{
++ # Normalize program name to check for.
++ normalized_program=`echo "$1" | sed '
++ s/^gnu-//; t
++ s/^gnu//; t
++ s/^g//; t'`
++
++ printf '%s\n' "'$1' is $msg."
++
++ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
++ case $normalized_program in
++ autoconf*)
++ echo "You should only need it if you modified 'configure.ac',"
++ echo "or m4 files included by it."
++ program_details 'autoconf'
++ ;;
++ autoheader*)
++ echo "You should only need it if you modified 'acconfig.h' or"
++ echo "$configure_deps."
++ program_details 'autoheader'
++ ;;
++ automake*)
++ echo "You should only need it if you modified 'Makefile.am' or"
++ echo "$configure_deps."
++ program_details 'automake'
++ ;;
++ aclocal*)
++ echo "You should only need it if you modified 'acinclude.m4' or"
++ echo "$configure_deps."
++ program_details 'aclocal'
++ ;;
++ autom4te*)
++ echo "You might have modified some maintainer files that require"
++ echo "the 'automa4te' program to be rebuilt."
++ program_details 'autom4te'
++ ;;
++ bison*|yacc*)
++ echo "You should only need it if you modified a '.y' file."
++ echo "You may want to install the GNU Bison package:"
++ echo "<$gnu_software_URL/bison/>"
++ ;;
++ lex*|flex*)
++ echo "You should only need it if you modified a '.l' file."
++ echo "You may want to install the Fast Lexical Analyzer package:"
++ echo "<$flex_URL>"
++ ;;
++ help2man*)
++ echo "You should only need it if you modified a dependency" \
++ "of a man page."
++ echo "You may want to install the GNU Help2man package:"
++ echo "<$gnu_software_URL/help2man/>"
++ ;;
++ makeinfo*)
++ echo "You should only need it if you modified a '.texi' file, or"
++ echo "any other file indirectly affecting the aspect of the manual."
++ echo "You might want to install the Texinfo package:"
++ echo "<$gnu_software_URL/texinfo/>"
++ echo "The spurious makeinfo call might also be the consequence of"
++ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
++ echo "want to install GNU make:"
++ echo "<$gnu_software_URL/make/>"
++ ;;
++ *)
++ echo "You might have modified some files without having the proper"
++ echo "tools for further handling them. Check the 'README' file, it"
++ echo "often tells you about the needed prerequisites for installing"
++ echo "this package. You may also peek at any GNU archive site, in"
++ echo "case some other package contains this missing '$1' program."
++ ;;
++ esac
++}
++
++give_advice "$1" | sed -e '1s/^/WARNING: /' \
++ -e '2,$s/^/ /' >&2
++
++# Propagate the correct exit status (expected to be 127 for a program
++# not found, 63 for a program that failed due to version mismatch).
++exit $st
++
++# Local variables:
++# eval: (add-hook 'write-file-hooks 'time-stamp)
++# time-stamp-start: "scriptversion="
++# time-stamp-format: "%:y-%02m-%02d.%02H"
++# time-stamp-time-zone: "UTC"
++# time-stamp-end: "; # UTC"
++# End:
+--- /dev/null
++++ b/depcomp
+@@ -0,0 +1,791 @@
++#! /bin/sh
++# depcomp - compile a program generating dependencies as side-effects
++
++scriptversion=2013-05-30.07; # UTC
++
++# Copyright (C) 1999-2013 Free Software Foundation, Inc.
++
++# This program is free software; you can redistribute it and/or modify
++# it under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 2, or (at your option)
++# any later version.
++
++# This program is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++
++# You should have received a copy of the GNU General Public License
++# along with this program. If not, see <http://www.gnu.org/licenses/>.
++
++# As a special exception to the GNU General Public License, if you
++# distribute this file as part of a program that contains a
++# configuration script generated by Autoconf, you may include it under
++# the same distribution terms that you use for the rest of that program.
++
++# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
++
++case $1 in
++ '')
++ echo "$0: No command. Try '$0 --help' for more information." 1>&2
++ exit 1;
++ ;;
++ -h | --h*)
++ cat <<\EOF
++Usage: depcomp [--help] [--version] PROGRAM [ARGS]
++
++Run PROGRAMS ARGS to compile a file, generating dependencies
++as side-effects.
++
++Environment variables:
++ depmode Dependency tracking mode.
++ source Source file read by 'PROGRAMS ARGS'.
++ object Object file output by 'PROGRAMS ARGS'.
++ DEPDIR directory where to store dependencies.
++ depfile Dependency file to output.
++ tmpdepfile Temporary file to use when outputting dependencies.
++ libtool Whether libtool is used (yes/no).
++
++Report bugs to <bug-automake@gnu.org>.
++EOF
++ exit $?
++ ;;
++ -v | --v*)
++ echo "depcomp $scriptversion"
++ exit $?
++ ;;
++esac
++
++# Get the directory component of the given path, and save it in the
++# global variables '$dir'. Note that this directory component will
++# be either empty or ending with a '/' character. This is deliberate.
++set_dir_from ()
++{
++ case $1 in
++ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
++ *) dir=;;
++ esac
++}
++
++# Get the suffix-stripped basename of the given path, and save it the
++# global variable '$base'.
++set_base_from ()
++{
++ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
++}
++
++# If no dependency file was actually created by the compiler invocation,
++# we still have to create a dummy depfile, to avoid errors with the
++# Makefile "include basename.Plo" scheme.
++make_dummy_depfile ()
++{
++ echo "#dummy" > "$depfile"
++}
++
++# Factor out some common post-processing of the generated depfile.
++# Requires the auxiliary global variable '$tmpdepfile' to be set.
++aix_post_process_depfile ()
++{
++ # If the compiler actually managed to produce a dependency file,
++ # post-process it.
++ if test -f "$tmpdepfile"; then
++ # Each line is of the form 'foo.o: dependency.h'.
++ # Do two passes, one to just change these to
++ # $object: dependency.h
++ # and one to simply output
++ # dependency.h:
++ # which is needed to avoid the deleted-header problem.
++ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
++ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
++ } > "$depfile"
++ rm -f "$tmpdepfile"
++ else
++ make_dummy_depfile
++ fi
++}
++
++# A tabulation character.
++tab=' '
++# A newline character.
++nl='
++'
++# Character ranges might be problematic outside the C locale.
++# These definitions help.
++upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
++lower=abcdefghijklmnopqrstuvwxyz
++digits=0123456789
++alpha=${upper}${lower}
++
++if test -z "$depmode" || test -z "$source" || test -z "$object"; then
++ echo "depcomp: Variables source, object and depmode must be set" 1>&2
++ exit 1
++fi
++
++# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
++depfile=${depfile-`echo "$object" |
++ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
++tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
++
++rm -f "$tmpdepfile"
++
++# Avoid interferences from the environment.
++gccflag= dashmflag=
++
++# Some modes work just like other modes, but use different flags. We
++# parameterize here, but still list the modes in the big case below,
++# to make depend.m4 easier to write. Note that we *cannot* use a case
++# here, because this file can only contain one case statement.
++if test "$depmode" = hp; then
++ # HP compiler uses -M and no extra arg.
++ gccflag=-M
++ depmode=gcc
++fi
++
++if test "$depmode" = dashXmstdout; then
++ # This is just like dashmstdout with a different argument.
++ dashmflag=-xM
++ depmode=dashmstdout
++fi
++
++cygpath_u="cygpath -u -f -"
++if test "$depmode" = msvcmsys; then
++ # This is just like msvisualcpp but w/o cygpath translation.
++ # Just convert the backslash-escaped backslashes to single forward
++ # slashes to satisfy depend.m4
++ cygpath_u='sed s,\\\\,/,g'
++ depmode=msvisualcpp
++fi
++
++if test "$depmode" = msvc7msys; then
++ # This is just like msvc7 but w/o cygpath translation.
++ # Just convert the backslash-escaped backslashes to single forward
++ # slashes to satisfy depend.m4
++ cygpath_u='sed s,\\\\,/,g'
++ depmode=msvc7
++fi
++
++if test "$depmode" = xlc; then
++ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
++ gccflag=-qmakedep=gcc,-MF
++ depmode=gcc
++fi
++
++case "$depmode" in
++gcc3)
++## gcc 3 implements dependency tracking that does exactly what
++## we want. Yay! Note: for some reason libtool 1.4 doesn't like
++## it if -MD -MP comes after the -MF stuff. Hmm.
++## Unfortunately, FreeBSD c89 acceptance of flags depends upon
++## the command line argument order; so add the flags where they
++## appear in depend2.am. Note that the slowdown incurred here
++## affects only configure: in makefiles, %FASTDEP% shortcuts this.
++ for arg
++ do
++ case $arg in
++ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
++ *) set fnord "$@" "$arg" ;;
++ esac
++ shift # fnord
++ shift # $arg
++ done
++ "$@"
++ stat=$?
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile"
++ exit $stat
++ fi
++ mv "$tmpdepfile" "$depfile"
++ ;;
++
++gcc)
++## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
++## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
++## (see the conditional assignment to $gccflag above).
++## There are various ways to get dependency output from gcc. Here's
++## why we pick this rather obscure method:
++## - Don't want to use -MD because we'd like the dependencies to end
++## up in a subdir. Having to rename by hand is ugly.
++## (We might end up doing this anyway to support other compilers.)
++## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
++## -MM, not -M (despite what the docs say). Also, it might not be
++## supported by the other compilers which use the 'gcc' depmode.
++## - Using -M directly means running the compiler twice (even worse
++## than renaming).
++ if test -z "$gccflag"; then
++ gccflag=-MD,
++ fi
++ "$@" -Wp,"$gccflag$tmpdepfile"
++ stat=$?
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile"
++ exit $stat
++ fi
++ rm -f "$depfile"
++ echo "$object : \\" > "$depfile"
++ # The second -e expression handles DOS-style file names with drive
++ # letters.
++ sed -e 's/^[^:]*: / /' \
++ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
++## This next piece of magic avoids the "deleted header file" problem.
++## The problem is that when a header file which appears in a .P file
++## is deleted, the dependency causes make to die (because there is
++## typically no way to rebuild the header). We avoid this by adding
++## dummy dependencies for each header file. Too bad gcc doesn't do
++## this for us directly.
++## Some versions of gcc put a space before the ':'. On the theory
++## that the space means something, we add a space to the output as
++## well. hp depmode also adds that space, but also prefixes the VPATH
++## to the object. Take care to not repeat it in the output.
++## Some versions of the HPUX 10.20 sed can't process this invocation
++## correctly. Breaking it into two sed invocations is a workaround.
++ tr ' ' "$nl" < "$tmpdepfile" \
++ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
++ | sed -e 's/$/ :/' >> "$depfile"
++ rm -f "$tmpdepfile"
++ ;;
++
++hp)
++ # This case exists only to let depend.m4 do its work. It works by
++ # looking at the text of this script. This case will never be run,
++ # since it is checked for above.
++ exit 1
++ ;;
++
++sgi)
++ if test "$libtool" = yes; then
++ "$@" "-Wp,-MDupdate,$tmpdepfile"
++ else
++ "$@" -MDupdate "$tmpdepfile"
++ fi
++ stat=$?
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile"
++ exit $stat
++ fi
++ rm -f "$depfile"
++
++ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
++ echo "$object : \\" > "$depfile"
++ # Clip off the initial element (the dependent). Don't try to be
++ # clever and replace this with sed code, as IRIX sed won't handle
++ # lines with more than a fixed number of characters (4096 in
++ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
++ # the IRIX cc adds comments like '#:fec' to the end of the
++ # dependency line.
++ tr ' ' "$nl" < "$tmpdepfile" \
++ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
++ | tr "$nl" ' ' >> "$depfile"
++ echo >> "$depfile"
++ # The second pass generates a dummy entry for each header file.
++ tr ' ' "$nl" < "$tmpdepfile" \
++ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
++ >> "$depfile"
++ else
++ make_dummy_depfile
++ fi
++ rm -f "$tmpdepfile"
++ ;;
++
++xlc)
++ # This case exists only to let depend.m4 do its work. It works by
++ # looking at the text of this script. This case will never be run,
++ # since it is checked for above.
++ exit 1
++ ;;
++
++aix)
++ # The C for AIX Compiler uses -M and outputs the dependencies
++ # in a .u file. In older versions, this file always lives in the
++ # current directory. Also, the AIX compiler puts '$object:' at the
++ # start of each line; $object doesn't have directory information.
++ # Version 6 uses the directory in both cases.
++ set_dir_from "$object"
++ set_base_from "$object"
++ if test "$libtool" = yes; then
++ tmpdepfile1=$dir$base.u
++ tmpdepfile2=$base.u
++ tmpdepfile3=$dir.libs/$base.u
++ "$@" -Wc,-M
++ else
++ tmpdepfile1=$dir$base.u
++ tmpdepfile2=$dir$base.u
++ tmpdepfile3=$dir$base.u
++ "$@" -M
++ fi
++ stat=$?
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
++ exit $stat
++ fi
++
++ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
++ do
++ test -f "$tmpdepfile" && break
++ done
++ aix_post_process_depfile
++ ;;
++
++tcc)
++ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
++ # FIXME: That version still under development at the moment of writing.
++ # Make that this statement remains true also for stable, released
++ # versions.
++ # It will wrap lines (doesn't matter whether long or short) with a
++ # trailing '\', as in:
++ #
++ # foo.o : \
++ # foo.c \
++ # foo.h \
++ #
++ # It will put a trailing '\' even on the last line, and will use leading
++ # spaces rather than leading tabs (at least since its commit 0394caf7
++ # "Emit spaces for -MD").
++ "$@" -MD -MF "$tmpdepfile"
++ stat=$?
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile"
++ exit $stat
++ fi
++ rm -f "$depfile"
++ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
++ # We have to change lines of the first kind to '$object: \'.
++ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
++ # And for each line of the second kind, we have to emit a 'dep.h:'
++ # dummy dependency, to avoid the deleted-header problem.
++ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
++ rm -f "$tmpdepfile"
++ ;;
++
++## The order of this option in the case statement is important, since the
++## shell code in configure will try each of these formats in the order
++## listed in this file. A plain '-MD' option would be understood by many
++## compilers, so we must ensure this comes after the gcc and icc options.
++pgcc)
++ # Portland's C compiler understands '-MD'.
++ # Will always output deps to 'file.d' where file is the root name of the
++ # source file under compilation, even if file resides in a subdirectory.
++ # The object file name does not affect the name of the '.d' file.
++ # pgcc 10.2 will output
++ # foo.o: sub/foo.c sub/foo.h
++ # and will wrap long lines using '\' :
++ # foo.o: sub/foo.c ... \
++ # sub/foo.h ... \
++ # ...
++ set_dir_from "$object"
++ # Use the source, not the object, to determine the base name, since
++ # that's sadly what pgcc will do too.
++ set_base_from "$source"
++ tmpdepfile=$base.d
++
++ # For projects that build the same source file twice into different object
++ # files, the pgcc approach of using the *source* file root name can cause
++ # problems in parallel builds. Use a locking strategy to avoid stomping on
++ # the same $tmpdepfile.
++ lockdir=$base.d-lock
++ trap "
++ echo '$0: caught signal, cleaning up...' >&2
++ rmdir '$lockdir'
++ exit 1
++ " 1 2 13 15
++ numtries=100
++ i=$numtries
++ while test $i -gt 0; do
++ # mkdir is a portable test-and-set.
++ if mkdir "$lockdir" 2>/dev/null; then
++ # This process acquired the lock.
++ "$@" -MD
++ stat=$?
++ # Release the lock.
++ rmdir "$lockdir"
++ break
++ else
++ # If the lock is being held by a different process, wait
++ # until the winning process is done or we timeout.
++ while test -d "$lockdir" && test $i -gt 0; do
++ sleep 1
++ i=`expr $i - 1`
++ done
++ fi
++ i=`expr $i - 1`
++ done
++ trap - 1 2 13 15
++ if test $i -le 0; then
++ echo "$0: failed to acquire lock after $numtries attempts" >&2
++ echo "$0: check lockdir '$lockdir'" >&2
++ exit 1
++ fi
++
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile"
++ exit $stat
++ fi
++ rm -f "$depfile"
++ # Each line is of the form `foo.o: dependent.h',
++ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
++ # Do two passes, one to just change these to
++ # `$object: dependent.h' and one to simply `dependent.h:'.
++ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
++ # Some versions of the HPUX 10.20 sed can't process this invocation
++ # correctly. Breaking it into two sed invocations is a workaround.
++ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
++ | sed -e 's/$/ :/' >> "$depfile"
++ rm -f "$tmpdepfile"
++ ;;
++
++hp2)
++ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
++ # compilers, which have integrated preprocessors. The correct option
++ # to use with these is +Maked; it writes dependencies to a file named
++ # 'foo.d', which lands next to the object file, wherever that
++ # happens to be.
++ # Much of this is similar to the tru64 case; see comments there.
++ set_dir_from "$object"
++ set_base_from "$object"
++ if test "$libtool" = yes; then
++ tmpdepfile1=$dir$base.d
++ tmpdepfile2=$dir.libs/$base.d
++ "$@" -Wc,+Maked
++ else
++ tmpdepfile1=$dir$base.d
++ tmpdepfile2=$dir$base.d
++ "$@" +Maked
++ fi
++ stat=$?
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile1" "$tmpdepfile2"
++ exit $stat
++ fi
++
++ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
++ do
++ test -f "$tmpdepfile" && break
++ done
++ if test -f "$tmpdepfile"; then
++ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
++ # Add 'dependent.h:' lines.
++ sed -ne '2,${
++ s/^ *//
++ s/ \\*$//
++ s/$/:/
++ p
++ }' "$tmpdepfile" >> "$depfile"
++ else
++ make_dummy_depfile
++ fi
++ rm -f "$tmpdepfile" "$tmpdepfile2"
++ ;;
++
++tru64)
++ # The Tru64 compiler uses -MD to generate dependencies as a side
++ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
++ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
++ # dependencies in 'foo.d' instead, so we check for that too.
++ # Subdirectories are respected.
++ set_dir_from "$object"
++ set_base_from "$object"
++
++ if test "$libtool" = yes; then
++ # Libtool generates 2 separate objects for the 2 libraries. These
++ # two compilations output dependencies in $dir.libs/$base.o.d and
++ # in $dir$base.o.d. We have to check for both files, because
++ # one of the two compilations can be disabled. We should prefer
++ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
++ # automatically cleaned when .libs/ is deleted, while ignoring
++ # the former would cause a distcleancheck panic.
++ tmpdepfile1=$dir$base.o.d # libtool 1.5
++ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
++ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
++ "$@" -Wc,-MD
++ else
++ tmpdepfile1=$dir$base.d
++ tmpdepfile2=$dir$base.d
++ tmpdepfile3=$dir$base.d
++ "$@" -MD
++ fi
++
++ stat=$?
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
++ exit $stat
++ fi
++
++ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
++ do
++ test -f "$tmpdepfile" && break
++ done
++ # Same post-processing that is required for AIX mode.
++ aix_post_process_depfile
++ ;;
++
++msvc7)
++ if test "$libtool" = yes; then
++ showIncludes=-Wc,-showIncludes
++ else
++ showIncludes=-showIncludes
++ fi
++ "$@" $showIncludes > "$tmpdepfile"
++ stat=$?
++ grep -v '^Note: including file: ' "$tmpdepfile"
++ if test $stat -ne 0; then
++ rm -f "$tmpdepfile"
++ exit $stat
++ fi
++ rm -f "$depfile"
++ echo "$object : \\" > "$depfile"
++ # The first sed program below extracts the file names and escapes
++ # backslashes for cygpath. The second sed program outputs the file
++ # name when reading, but also accumulates all include files in the
++ # hold buffer in order to output them again at the end. This only
++ # works with sed implementations that can handle large buffers.
++ sed < "$tmpdepfile" -n '
++/^Note: including file: *\(.*\)/ {
++ s//\1/
++ s/\\/\\\\/g
++ p
++}' | $cygpath_u | sort -u | sed -n '
++s/ /\\ /g
++s/\(.*\)/'"$tab"'\1 \\/p
++s/.\(.*\) \\/\1:/
++H
++$ {
++ s/.*/'"$tab"'/
++ G
++ p
++}' >> "$depfile"
++ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
++ rm -f "$tmpdepfile"
++ ;;
++
++msvc7msys)
++ # This case exists only to let depend.m4 do its work. It works by
++ # looking at the text of this script. This case will never be run,
++ # since it is checked for above.
++ exit 1
++ ;;
++
++#nosideeffect)
++ # This comment above is used by automake to tell side-effect
++ # dependency tracking mechanisms from slower ones.
++
++dashmstdout)
++ # Important note: in order to support this mode, a compiler *must*
++ # always write the preprocessed file to stdout, regardless of -o.
++ "$@" || exit $?
++
++ # Remove the call to Libtool.
++ if test "$libtool" = yes; then
++ while test "X$1" != 'X--mode=compile'; do
++ shift
++ done
++ shift
++ fi
++
++ # Remove '-o $object'.
++ IFS=" "
++ for arg
++ do
++ case $arg in
++ -o)
++ shift
++ ;;
++ $object)
++ shift
++ ;;
++ *)
++ set fnord "$@" "$arg"
++ shift # fnord
++ shift # $arg
++ ;;
++ esac
++ done
++
++ test -z "$dashmflag" && dashmflag=-M
++ # Require at least two characters before searching for ':'
++ # in the target name. This is to cope with DOS-style filenames:
++ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
++ "$@" $dashmflag |
++ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
++ rm -f "$depfile"
++ cat < "$tmpdepfile" > "$depfile"
++ # Some versions of the HPUX 10.20 sed can't process this sed invocation
++ # correctly. Breaking it into two sed invocations is a workaround.
++ tr ' ' "$nl" < "$tmpdepfile" \
++ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
++ | sed -e 's/$/ :/' >> "$depfile"
++ rm -f "$tmpdepfile"
++ ;;
++
++dashXmstdout)
++ # This case only exists to satisfy depend.m4. It is never actually
++ # run, as this mode is specially recognized in the preamble.
++ exit 1
++ ;;
++
++makedepend)
++ "$@" || exit $?
++ # Remove any Libtool call
++ if test "$libtool" = yes; then
++ while test "X$1" != 'X--mode=compile'; do
++ shift
++ done
++ shift
++ fi
++ # X makedepend
++ shift
++ cleared=no eat=no
++ for arg
++ do
++ case $cleared in
++ no)
++ set ""; shift
++ cleared=yes ;;
++ esac
++ if test $eat = yes; then
++ eat=no
++ continue
++ fi
++ case "$arg" in
++ -D*|-I*)
++ set fnord "$@" "$arg"; shift ;;
++ # Strip any option that makedepend may not understand. Remove
++ # the object too, otherwise makedepend will parse it as a source file.
++ -arch)
++ eat=yes ;;
++ -*|$object)
++ ;;
++ *)
++ set fnord "$@" "$arg"; shift ;;
++ esac
++ done
++ obj_suffix=`echo "$object" | sed 's/^.*\././'`
++ touch "$tmpdepfile"
++ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
++ rm -f "$depfile"
++ # makedepend may prepend the VPATH from the source file name to the object.
++ # No need to regex-escape $object, excess matching of '.' is harmless.
++ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
++ # Some versions of the HPUX 10.20 sed can't process the last invocation
++ # correctly. Breaking it into two sed invocations is a workaround.
++ sed '1,2d' "$tmpdepfile" \
++ | tr ' ' "$nl" \
++ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
++ | sed -e 's/$/ :/' >> "$depfile"
++ rm -f "$tmpdepfile" "$tmpdepfile".bak
++ ;;
++
++cpp)
++ # Important note: in order to support this mode, a compiler *must*
++ # always write the preprocessed file to stdout.
++ "$@" || exit $?
++
++ # Remove the call to Libtool.
++ if test "$libtool" = yes; then
++ while test "X$1" != 'X--mode=compile'; do
++ shift
++ done
++ shift
++ fi
++
++ # Remove '-o $object'.
++ IFS=" "
++ for arg
++ do
++ case $arg in
++ -o)
++ shift
++ ;;
++ $object)
++ shift
++ ;;
++ *)
++ set fnord "$@" "$arg"
++ shift # fnord
++ shift # $arg
++ ;;
++ esac
++ done
++
++ "$@" -E \
++ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
++ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
++ | sed '$ s: \\$::' > "$tmpdepfile"
++ rm -f "$depfile"
++ echo "$object : \\" > "$depfile"
++ cat < "$tmpdepfile" >> "$depfile"
++ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
++ rm -f "$tmpdepfile"
++ ;;
++
++msvisualcpp)
++ # Important note: in order to support this mode, a compiler *must*
++ # always write the preprocessed file to stdout.
++ "$@" || exit $?
++
++ # Remove the call to Libtool.
++ if test "$libtool" = yes; then
++ while test "X$1" != 'X--mode=compile'; do
++ shift
++ done
++ shift
++ fi
++
++ IFS=" "
++ for arg
++ do
++ case "$arg" in
++ -o)
++ shift
++ ;;
++ $object)
++ shift
++ ;;
++ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
++ set fnord "$@"
++ shift
++ shift
++ ;;
++ *)
++ set fnord "$@" "$arg"
++ shift
++ shift
++ ;;
++ esac
++ done
++ "$@" -E 2>/dev/null |
++ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
++ rm -f "$depfile"
++ echo "$object : \\" > "$depfile"
++ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
++ echo "$tab" >> "$depfile"
++ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
++ rm -f "$tmpdepfile"
++ ;;
++
++msvcmsys)
++ # This case exists only to let depend.m4 do its work. It works by
++ # looking at the text of this script. This case will never be run,
++ # since it is checked for above.
++ exit 1
++ ;;
++
++none)
++ exec "$@"
++ ;;
++
++*)
++ echo "Unknown depmode $depmode" 1>&2
++ exit 1
++ ;;
++esac
++
++exit 0
++
++# Local Variables:
++# mode: shell-script
++# sh-indentation: 2
++# eval: (add-hook 'write-file-hooks 'time-stamp)
++# time-stamp-start: "scriptversion="
++# time-stamp-format: "%:y-%02m-%02d.%02H"
++# time-stamp-time-zone: "UTC"
++# time-stamp-end: "; # UTC"
++# End:
+--- /dev/null
++++ b/install-sh
+@@ -0,0 +1,527 @@
++#!/bin/sh
++# install - install a program, script, or datafile
++
++scriptversion=2011-11-20.07; # UTC
++
++# This originates from X11R5 (mit/util/scripts/install.sh), which was
++# later released in X11R6 (xc/config/util/install.sh) with the
++# following copyright and license.
++#
++# Copyright (C) 1994 X Consortium
++#
++# Permission is hereby granted, free of charge, to any person obtaining a copy
++# of this software and associated documentation files (the "Software"), to
++# deal in the Software without restriction, including without limitation the
++# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++# sell copies of the Software, and to permit persons to whom the Software is
++# furnished to do so, subject to the following conditions:
++#
++# The above copyright notice and this permission notice shall be included in
++# all copies or substantial portions of the Software.
++#
++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
++# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
++# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++#
++# Except as contained in this notice, the name of the X Consortium shall not
++# be used in advertising or otherwise to promote the sale, use or other deal-
++# ings in this Software without prior written authorization from the X Consor-
++# tium.
++#
++#
++# FSF changes to this file are in the public domain.
++#
++# Calling this script install-sh is preferred over install.sh, to prevent
++# 'make' implicit rules from creating a file called install from it
++# when there is no Makefile.
++#
++# This script is compatible with the BSD install script, but was written
++# from scratch.
++
++nl='
++'
++IFS=" "" $nl"
++
++# set DOITPROG to echo to test this script
++
++# Don't use :- since 4.3BSD and earlier shells don't like it.
++doit=${DOITPROG-}
++if test -z "$doit"; then
++ doit_exec=exec
++else
++ doit_exec=$doit
++fi
++
++# Put in absolute file names if you don't have them in your path;
++# or use environment vars.
++
++chgrpprog=${CHGRPPROG-chgrp}
++chmodprog=${CHMODPROG-chmod}
++chownprog=${CHOWNPROG-chown}
++cmpprog=${CMPPROG-cmp}
++cpprog=${CPPROG-cp}
++mkdirprog=${MKDIRPROG-mkdir}
++mvprog=${MVPROG-mv}
++rmprog=${RMPROG-rm}
++stripprog=${STRIPPROG-strip}
++
++posix_glob='?'
++initialize_posix_glob='
++ test "$posix_glob" != "?" || {
++ if (set -f) 2>/dev/null; then
++ posix_glob=
++ else
++ posix_glob=:
++ fi
++ }
++'
++
++posix_mkdir=
++
++# Desired mode of installed file.
++mode=0755
++
++chgrpcmd=
++chmodcmd=$chmodprog
++chowncmd=
++mvcmd=$mvprog
++rmcmd="$rmprog -f"
++stripcmd=
++
++src=
++dst=
++dir_arg=
++dst_arg=
++
++copy_on_change=false
++no_target_directory=
++
++usage="\
++Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
++ or: $0 [OPTION]... SRCFILES... DIRECTORY
++ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
++ or: $0 [OPTION]... -d DIRECTORIES...
++
++In the 1st form, copy SRCFILE to DSTFILE.
++In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
++In the 4th, create DIRECTORIES.
++
++Options:
++ --help display this help and exit.
++ --version display version info and exit.
++
++ -c (ignored)
++ -C install only if different (preserve the last data modification time)
++ -d create directories instead of installing files.
++ -g GROUP $chgrpprog installed files to GROUP.
++ -m MODE $chmodprog installed files to MODE.
++ -o USER $chownprog installed files to USER.
++ -s $stripprog installed files.
++ -t DIRECTORY install into DIRECTORY.
++ -T report an error if DSTFILE is a directory.
++
++Environment variables override the default commands:
++ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
++ RMPROG STRIPPROG
++"
++
++while test $# -ne 0; do
++ case $1 in
++ -c) ;;
++
++ -C) copy_on_change=true;;
++
++ -d) dir_arg=true;;
++
++ -g) chgrpcmd="$chgrpprog $2"
++ shift;;
++
++ --help) echo "$usage"; exit $?;;
++
++ -m) mode=$2
++ case $mode in
++ *' '* | *' '* | *'
++'* | *'*'* | *'?'* | *'['*)
++ echo "$0: invalid mode: $mode" >&2
++ exit 1;;
++ esac
++ shift;;
++
++ -o) chowncmd="$chownprog $2"
++ shift;;
++
++ -s) stripcmd=$stripprog;;
++
++ -t) dst_arg=$2
++ # Protect names problematic for 'test' and other utilities.
++ case $dst_arg in
++ -* | [=\(\)!]) dst_arg=./$dst_arg;;
++ esac
++ shift;;
++
++ -T) no_target_directory=true;;
++
++ --version) echo "$0 $scriptversion"; exit $?;;
++
++ --) shift
++ break;;
++
++ -*) echo "$0: invalid option: $1" >&2
++ exit 1;;
++
++ *) break;;
++ esac
++ shift
++done
++
++if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
++ # When -d is used, all remaining arguments are directories to create.
++ # When -t is used, the destination is already specified.
++ # Otherwise, the last argument is the destination. Remove it from $@.
++ for arg
++ do
++ if test -n "$dst_arg"; then
++ # $@ is not empty: it contains at least $arg.
++ set fnord "$@" "$dst_arg"
++ shift # fnord
++ fi
++ shift # arg
++ dst_arg=$arg
++ # Protect names problematic for 'test' and other utilities.
++ case $dst_arg in
++ -* | [=\(\)!]) dst_arg=./$dst_arg;;
++ esac
++ done
++fi
++
++if test $# -eq 0; then
++ if test -z "$dir_arg"; then
++ echo "$0: no input file specified." >&2
++ exit 1
++ fi
++ # It's OK to call 'install-sh -d' without argument.
++ # This can happen when creating conditional directories.
++ exit 0
++fi
++
++if test -z "$dir_arg"; then
++ do_exit='(exit $ret); exit $ret'
++ trap "ret=129; $do_exit" 1
++ trap "ret=130; $do_exit" 2
++ trap "ret=141; $do_exit" 13
++ trap "ret=143; $do_exit" 15
++
++ # Set umask so as not to create temps with too-generous modes.
++ # However, 'strip' requires both read and write access to temps.
++ case $mode in
++ # Optimize common cases.
++ *644) cp_umask=133;;
++ *755) cp_umask=22;;
++
++ *[0-7])
++ if test -z "$stripcmd"; then
++ u_plus_rw=
++ else
++ u_plus_rw='% 200'
++ fi
++ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
++ *)
++ if test -z "$stripcmd"; then
++ u_plus_rw=
++ else
++ u_plus_rw=,u+rw
++ fi
++ cp_umask=$mode$u_plus_rw;;
++ esac
++fi
++
++for src
++do
++ # Protect names problematic for 'test' and other utilities.
++ case $src in
++ -* | [=\(\)!]) src=./$src;;
++ esac
++
++ if test -n "$dir_arg"; then
++ dst=$src
++ dstdir=$dst
++ test -d "$dstdir"
++ dstdir_status=$?
++ else
++
++ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
++ # might cause directories to be created, which would be especially bad
++ # if $src (and thus $dsttmp) contains '*'.
++ if test ! -f "$src" && test ! -d "$src"; then
++ echo "$0: $src does not exist." >&2
++ exit 1
++ fi
++
++ if test -z "$dst_arg"; then
++ echo "$0: no destination specified." >&2
++ exit 1
++ fi
++ dst=$dst_arg
++
++ # If destination is a directory, append the input filename; won't work
++ # if double slashes aren't ignored.
++ if test -d "$dst"; then
++ if test -n "$no_target_directory"; then
++ echo "$0: $dst_arg: Is a directory" >&2
++ exit 1
++ fi
++ dstdir=$dst
++ dst=$dstdir/`basename "$src"`
++ dstdir_status=0
++ else
++ # Prefer dirname, but fall back on a substitute if dirname fails.
++ dstdir=`
++ (dirname "$dst") 2>/dev/null ||
++ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
++ X"$dst" : 'X\(//\)[^/]' \| \
++ X"$dst" : 'X\(//\)$' \| \
++ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
++ echo X"$dst" |
++ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)[^/].*/{
++ s//\1/
++ q
++ }
++ /^X\(\/\/\)$/{
++ s//\1/
++ q
++ }
++ /^X\(\/\).*/{
++ s//\1/
++ q
++ }
++ s/.*/./; q'
++ `
++
++ test -d "$dstdir"
++ dstdir_status=$?
++ fi
++ fi
++
++ obsolete_mkdir_used=false
++
++ if test $dstdir_status != 0; then
++ case $posix_mkdir in
++ '')
++ # Create intermediate dirs using mode 755 as modified by the umask.
++ # This is like FreeBSD 'install' as of 1997-10-28.
++ umask=`umask`
++ case $stripcmd.$umask in
++ # Optimize common cases.
++ *[2367][2367]) mkdir_umask=$umask;;
++ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
++
++ *[0-7])
++ mkdir_umask=`expr $umask + 22 \
++ - $umask % 100 % 40 + $umask % 20 \
++ - $umask % 10 % 4 + $umask % 2
++ `;;
++ *) mkdir_umask=$umask,go-w;;
++ esac
++
++ # With -d, create the new directory with the user-specified mode.
++ # Otherwise, rely on $mkdir_umask.
++ if test -n "$dir_arg"; then
++ mkdir_mode=-m$mode
++ else
++ mkdir_mode=
++ fi
++
++ posix_mkdir=false
++ case $umask in
++ *[123567][0-7][0-7])
++ # POSIX mkdir -p sets u+wx bits regardless of umask, which
++ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
++ ;;
++ *)
++ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
++ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
++
++ if (umask $mkdir_umask &&
++ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
++ then
++ if test -z "$dir_arg" || {
++ # Check for POSIX incompatibilities with -m.
++ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
++ # other-writable bit of parent directory when it shouldn't.
++ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
++ ls_ld_tmpdir=`ls -ld "$tmpdir"`
++ case $ls_ld_tmpdir in
++ d????-?r-*) different_mode=700;;
++ d????-?--*) different_mode=755;;
++ *) false;;
++ esac &&
++ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
++ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
++ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
++ }
++ }
++ then posix_mkdir=:
++ fi
++ rmdir "$tmpdir/d" "$tmpdir"
++ else
++ # Remove any dirs left behind by ancient mkdir implementations.
++ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
++ fi
++ trap '' 0;;
++ esac;;
++ esac
++
++ if
++ $posix_mkdir && (
++ umask $mkdir_umask &&
++ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
++ )
++ then :
++ else
++
++ # The umask is ridiculous, or mkdir does not conform to POSIX,
++ # or it failed possibly due to a race condition. Create the
++ # directory the slow way, step by step, checking for races as we go.
++
++ case $dstdir in
++ /*) prefix='/';;
++ [-=\(\)!]*) prefix='./';;
++ *) prefix='';;
++ esac
++
++ eval "$initialize_posix_glob"
++
++ oIFS=$IFS
++ IFS=/
++ $posix_glob set -f
++ set fnord $dstdir
++ shift
++ $posix_glob set +f
++ IFS=$oIFS
++
++ prefixes=
++
++ for d
++ do
++ test X"$d" = X && continue
++
++ prefix=$prefix$d
++ if test -d "$prefix"; then
++ prefixes=
++ else
++ if $posix_mkdir; then
++ (umask=$mkdir_umask &&
++ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
++ # Don't fail if two instances are running concurrently.
++ test -d "$prefix" || exit 1
++ else
++ case $prefix in
++ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
++ *) qprefix=$prefix;;
++ esac
++ prefixes="$prefixes '$qprefix'"
++ fi
++ fi
++ prefix=$prefix/
++ done
++
++ if test -n "$prefixes"; then
++ # Don't fail if two instances are running concurrently.
++ (umask $mkdir_umask &&
++ eval "\$doit_exec \$mkdirprog $prefixes") ||
++ test -d "$dstdir" || exit 1
++ obsolete_mkdir_used=true
++ fi
++ fi
++ fi
++
++ if test -n "$dir_arg"; then
++ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
++ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
++ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
++ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
++ else
++
++ # Make a couple of temp file names in the proper directory.
++ dsttmp=$dstdir/_inst.$$_
++ rmtmp=$dstdir/_rm.$$_
++
++ # Trap to clean up those temp files at exit.
++ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
++
++ # Copy the file name to the temp name.
++ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
++
++ # and set any options; do chmod last to preserve setuid bits.
++ #
++ # If any of these fail, we abort the whole thing. If we want to
++ # ignore errors from any of these, just make sure not to ignore
++ # errors from the above "$doit $cpprog $src $dsttmp" command.
++ #
++ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
++ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
++ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
++ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
++
++ # If -C, don't bother to copy if it wouldn't change the file.
++ if $copy_on_change &&
++ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
++ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
++
++ eval "$initialize_posix_glob" &&
++ $posix_glob set -f &&
++ set X $old && old=:$2:$4:$5:$6 &&
++ set X $new && new=:$2:$4:$5:$6 &&
++ $posix_glob set +f &&
++
++ test "$old" = "$new" &&
++ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
++ then
++ rm -f "$dsttmp"
++ else
++ # Rename the file to the real destination.
++ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
++
++ # The rename failed, perhaps because mv can't rename something else
++ # to itself, or perhaps because mv is so ancient that it does not
++ # support -f.
++ {
++ # Now remove or move aside any old file at destination location.
++ # We try this two ways since rm can't unlink itself on some
++ # systems and the destination file might be busy for other
++ # reasons. In this case, the final cleanup might fail but the new
++ # file should still install successfully.
++ {
++ test ! -f "$dst" ||
++ $doit $rmcmd -f "$dst" 2>/dev/null ||
++ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
++ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
++ } ||
++ { echo "$0: cannot unlink or rename $dst" >&2
++ (exit 1); exit 1
++ }
++ } &&
++
++ # Now rename the file to the real destination.
++ $doit $mvcmd "$dsttmp" "$dst"
++ }
++ fi || exit 1
++
++ trap '' 0
++ fi
++done
++
++# Local variables:
++# eval: (add-hook 'write-file-hooks 'time-stamp)
++# time-stamp-start: "scriptversion="
++# time-stamp-format: "%:y-%02m-%02d.%02H"
++# time-stamp-time-zone: "UTC"
++# time-stamp-end: "; # UTC"
++# End:
+--- /dev/null
++++ b/config.guess
+@@ -0,0 +1,1558 @@
++#! /bin/sh
++# Attempt to guess a canonical system name.
++# Copyright 1992-2013 Free Software Foundation, Inc.
++
++timestamp='2013-06-10'
++
++# This file is free software; you can redistribute it and/or modify it
++# under the terms of the GNU General Public License as published by
++# the Free Software Foundation; either version 3 of the License, or
++# (at your option) any later version.
++#
++# This program is distributed in the hope that it will be useful, but
++# WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++# General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, see <http://www.gnu.org/licenses/>.
++#
++# As a special exception to the GNU General Public License, if you
++# distribute this file as part of a program that contains a
++# configuration script generated by Autoconf, you may include it under
++# the same distribution terms that you use for the rest of that
++# program. This Exception is an additional permission under section 7
++# of the GNU General Public License, version 3 ("GPLv3").
++#
++# Originally written by Per Bothner.
++#
++# You can get the latest version of this script from:
++# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
++#
++# Please send patches with a ChangeLog entry to config-patches@gnu.org.
++
++
++me=`echo "$0" | sed -e 's,.*/,,'`
++
++usage="\
++Usage: $0 [OPTION]
++
++Output the configuration name of the system \`$me' is run on.
++
++Operation modes:
++ -h, --help print this help, then exit
++ -t, --time-stamp print date of last modification, then exit
++ -v, --version print version number, then exit
++
++Report bugs and patches to <config-patches@gnu.org>."
++
++version="\
++GNU config.guess ($timestamp)
++
++Originally written by Per Bothner.
++Copyright 1992-2013 Free Software Foundation, Inc.
++
++This is free software; see the source for copying conditions. There is NO
++warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
++
++help="
++Try \`$me --help' for more information."
++
++# Parse command line
++while test $# -gt 0 ; do
++ case $1 in
++ --time-stamp | --time* | -t )
++ echo "$timestamp" ; exit ;;
++ --version | -v )
++ echo "$version" ; exit ;;
++ --help | --h* | -h )
++ echo "$usage"; exit ;;
++ -- ) # Stop option processing
++ shift; break ;;
++ - ) # Use stdin as input.
++ break ;;
++ -* )
++ echo "$me: invalid option $1$help" >&2
++ exit 1 ;;
++ * )
++ break ;;
++ esac
++done
++
++if test $# != 0; then
++ echo "$me: too many arguments$help" >&2
++ exit 1
++fi
++
++trap 'exit 1' 1 2 15
++
++# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
++# compiler to aid in system detection is discouraged as it requires
++# temporary files to be created and, as you can see below, it is a
++# headache to deal with in a portable fashion.
++
++# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
++# use `HOST_CC' if defined, but it is deprecated.
++
++# Portable tmp directory creation inspired by the Autoconf team.
++
++set_cc_for_build='
++trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
++trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
++: ${TMPDIR=/tmp} ;
++ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
++ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
++ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
++ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
++dummy=$tmp/dummy ;
++tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
++case $CC_FOR_BUILD,$HOST_CC,$CC in
++ ,,) echo "int x;" > $dummy.c ;
++ for c in cc gcc c89 c99 ; do
++ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
++ CC_FOR_BUILD="$c"; break ;
++ fi ;
++ done ;
++ if test x"$CC_FOR_BUILD" = x ; then
++ CC_FOR_BUILD=no_compiler_found ;
++ fi
++ ;;
++ ,,*) CC_FOR_BUILD=$CC ;;
++ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
++esac ; set_cc_for_build= ;'
++
++# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
++# (ghazi@noc.rutgers.edu 1994-08-24)
++if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
++ PATH=$PATH:/.attbin ; export PATH
++fi
++
++UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
++UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
++UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
++UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
++
++case "${UNAME_SYSTEM}" in
++Linux|GNU|GNU/*)
++ # If the system lacks a compiler, then just pick glibc.
++ # We could probably try harder.
++ LIBC=gnu
++
++ eval $set_cc_for_build
++ cat <<-EOF > $dummy.c
++ #include <features.h>
++ #if defined(__UCLIBC__)
++ LIBC=uclibc
++ #elif defined(__dietlibc__)
++ LIBC=dietlibc
++ #else
++ LIBC=gnu
++ #endif
++ EOF
++ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
++ ;;
++esac
++
++# Note: order is significant - the case branches are not exclusive.
++
++case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
++ *:NetBSD:*:*)
++ # NetBSD (nbsd) targets should (where applicable) match one or
++ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
++ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
++ # switched to ELF, *-*-netbsd* would select the old
++ # object file format. This provides both forward
++ # compatibility and a consistent mechanism for selecting the
++ # object file format.
++ #
++ # Note: NetBSD doesn't particularly care about the vendor
++ # portion of the name. We always set it to "unknown".
++ sysctl="sysctl -n hw.machine_arch"
++ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
++ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
++ case "${UNAME_MACHINE_ARCH}" in
++ armeb) machine=armeb-unknown ;;
++ arm*) machine=arm-unknown ;;
++ sh3el) machine=shl-unknown ;;
++ sh3eb) machine=sh-unknown ;;
++ sh5el) machine=sh5le-unknown ;;
++ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
++ esac
++ # The Operating System including object format, if it has switched
++ # to ELF recently, or will in the future.
++ case "${UNAME_MACHINE_ARCH}" in
++ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
++ eval $set_cc_for_build
++ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
++ | grep -q __ELF__
++ then
++ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
++ # Return netbsd for either. FIX?
++ os=netbsd
++ else
++ os=netbsdelf
++ fi
++ ;;
++ *)
++ os=netbsd
++ ;;
++ esac
++ # The OS release
++ # Debian GNU/NetBSD machines have a different userland, and
++ # thus, need a distinct triplet. However, they do not need
++ # kernel version information, so it can be replaced with a
++ # suitable tag, in the style of linux-gnu.
++ case "${UNAME_VERSION}" in
++ Debian*)
++ release='-gnu'
++ ;;
++ *)
++ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
++ ;;
++ esac
++ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
++ # contains redundant information, the shorter form:
++ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
++ echo "${machine}-${os}${release}"
++ exit ;;
++ *:Bitrig:*:*)
++ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
++ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
++ exit ;;
++ *:OpenBSD:*:*)
++ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
++ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
++ exit ;;
++ *:ekkoBSD:*:*)
++ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
++ exit ;;
++ *:SolidBSD:*:*)
++ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
++ exit ;;
++ macppc:MirBSD:*:*)
++ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
++ exit ;;
++ *:MirBSD:*:*)
++ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
++ exit ;;
++ alpha:OSF1:*:*)
++ case $UNAME_RELEASE in
++ *4.0)
++ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
++ ;;
++ *5.*)
++ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
++ ;;
++ esac
++ # According to Compaq, /usr/sbin/psrinfo has been available on
++ # OSF/1 and Tru64 systems produced since 1995. I hope that
++ # covers most systems running today. This code pipes the CPU
++ # types through head -n 1, so we only detect the type of CPU 0.
++ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
++ case "$ALPHA_CPU_TYPE" in
++ "EV4 (21064)")
++ UNAME_MACHINE="alpha" ;;
++ "EV4.5 (21064)")
++ UNAME_MACHINE="alpha" ;;
++ "LCA4 (21066/21068)")
++ UNAME_MACHINE="alpha" ;;
++ "EV5 (21164)")
++ UNAME_MACHINE="alphaev5" ;;
++ "EV5.6 (21164A)")
++ UNAME_MACHINE="alphaev56" ;;
++ "EV5.6 (21164PC)")
++ UNAME_MACHINE="alphapca56" ;;
++ "EV5.7 (21164PC)")
++ UNAME_MACHINE="alphapca57" ;;
++ "EV6 (21264)")
++ UNAME_MACHINE="alphaev6" ;;
++ "EV6.7 (21264A)")
++ UNAME_MACHINE="alphaev67" ;;
++ "EV6.8CB (21264C)")
++ UNAME_MACHINE="alphaev68" ;;
++ "EV6.8AL (21264B)")
++ UNAME_MACHINE="alphaev68" ;;
++ "EV6.8CX (21264D)")
++ UNAME_MACHINE="alphaev68" ;;
++ "EV6.9A (21264/EV69A)")
++ UNAME_MACHINE="alphaev69" ;;
++ "EV7 (21364)")
++ UNAME_MACHINE="alphaev7" ;;
++ "EV7.9 (21364A)")
++ UNAME_MACHINE="alphaev79" ;;
++ esac
++ # A Pn.n version is a patched version.
++ # A Vn.n version is a released version.
++ # A Tn.n version is a released field test version.
++ # A Xn.n version is an unreleased experimental baselevel.
++ # 1.2 uses "1.2" for uname -r.
++ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
++ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
++ exitcode=$?
++ trap '' 0
++ exit $exitcode ;;
++ Alpha\ *:Windows_NT*:*)
++ # How do we know it's Interix rather than the generic POSIX subsystem?
++ # Should we change UNAME_MACHINE based on the output of uname instead
++ # of the specific Alpha model?
++ echo alpha-pc-interix
++ exit ;;
++ 21064:Windows_NT:50:3)
++ echo alpha-dec-winnt3.5
++ exit ;;
++ Amiga*:UNIX_System_V:4.0:*)
++ echo m68k-unknown-sysv4
++ exit ;;
++ *:[Aa]miga[Oo][Ss]:*:*)
++ echo ${UNAME_MACHINE}-unknown-amigaos
++ exit ;;
++ *:[Mm]orph[Oo][Ss]:*:*)
++ echo ${UNAME_MACHINE}-unknown-morphos
++ exit ;;
++ *:OS/390:*:*)
++ echo i370-ibm-openedition
++ exit ;;
++ *:z/VM:*:*)
++ echo s390-ibm-zvmoe
++ exit ;;
++ *:OS400:*:*)
++ echo powerpc-ibm-os400
++ exit ;;
++ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
++ echo arm-acorn-riscix${UNAME_RELEASE}
++ exit ;;
++ arm*:riscos:*:*|arm*:RISCOS:*:*)
++ echo arm-unknown-riscos
++ exit ;;
++ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
++ echo hppa1.1-hitachi-hiuxmpp
++ exit ;;
++ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
++ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
++ if test "`(/bin/universe) 2>/dev/null`" = att ; then
++ echo pyramid-pyramid-sysv3
++ else
++ echo pyramid-pyramid-bsd
++ fi
++ exit ;;
++ NILE*:*:*:dcosx)
++ echo pyramid-pyramid-svr4
++ exit ;;
++ DRS?6000:unix:4.0:6*)
++ echo sparc-icl-nx6
++ exit ;;
++ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
++ case `/usr/bin/uname -p` in
++ sparc) echo sparc-icl-nx7; exit ;;
++ esac ;;
++ s390x:SunOS:*:*)
++ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
++ exit ;;
++ sun4H:SunOS:5.*:*)
++ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
++ exit ;;
++ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
++ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
++ exit ;;
++ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
++ echo i386-pc-auroraux${UNAME_RELEASE}
++ exit ;;
++ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
++ eval $set_cc_for_build
++ SUN_ARCH="i386"
++ # If there is a compiler, see if it is configured for 64-bit objects.
++ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
++ # This test works for both compilers.
++ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
++ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
++ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
++ grep IS_64BIT_ARCH >/dev/null
++ then
++ SUN_ARCH="x86_64"
++ fi
++ fi
++ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
++ exit ;;
++ sun4*:SunOS:6*:*)
++ # According to config.sub, this is the proper way to canonicalize
++ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
++ # it's likely to be more like Solaris than SunOS4.
++ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
++ exit ;;
++ sun4*:SunOS:*:*)
++ case "`/usr/bin/arch -k`" in
++ Series*|S4*)
++ UNAME_RELEASE=`uname -v`
++ ;;
++ esac
++ # Japanese Language versions have a version number like `4.1.3-JL'.
++ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
++ exit ;;
++ sun3*:SunOS:*:*)
++ echo m68k-sun-sunos${UNAME_RELEASE}
++ exit ;;
++ sun*:*:4.2BSD:*)
++ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
++ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
++ case "`/bin/arch`" in
++ sun3)
++ echo m68k-sun-sunos${UNAME_RELEASE}
++ ;;
++ sun4)
++ echo sparc-sun-sunos${UNAME_RELEASE}
++ ;;
++ esac
++ exit ;;
++ aushp:SunOS:*:*)
++ echo sparc-auspex-sunos${UNAME_RELEASE}
++ exit ;;
++ # The situation for MiNT is a little confusing. The machine name
++ # can be virtually everything (everything which is not
++ # "atarist" or "atariste" at least should have a processor
++ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
++ # to the lowercase version "mint" (or "freemint"). Finally
++ # the system name "TOS" denotes a system which is actually not
++ # MiNT. But MiNT is downward compatible to TOS, so this should
++ # be no problem.
++ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
++ echo m68k-atari-mint${UNAME_RELEASE}
++ exit ;;
++ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
++ echo m68k-atari-mint${UNAME_RELEASE}
++ exit ;;
++ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
++ echo m68k-atari-mint${UNAME_RELEASE}
++ exit ;;
++ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
++ echo m68k-milan-mint${UNAME_RELEASE}
++ exit ;;
++ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
++ echo m68k-hades-mint${UNAME_RELEASE}
++ exit ;;
++ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
++ echo m68k-unknown-mint${UNAME_RELEASE}
++ exit ;;
++ m68k:machten:*:*)
++ echo m68k-apple-machten${UNAME_RELEASE}
++ exit ;;
++ powerpc:machten:*:*)
++ echo powerpc-apple-machten${UNAME_RELEASE}
++ exit ;;
++ RISC*:Mach:*:*)
++ echo mips-dec-mach_bsd4.3
++ exit ;;
++ RISC*:ULTRIX:*:*)
++ echo mips-dec-ultrix${UNAME_RELEASE}
++ exit ;;
++ VAX*:ULTRIX*:*:*)
++ echo vax-dec-ultrix${UNAME_RELEASE}
++ exit ;;
++ 2020:CLIX:*:* | 2430:CLIX:*:*)
++ echo clipper-intergraph-clix${UNAME_RELEASE}
++ exit ;;
++ mips:*:*:UMIPS | mips:*:*:RISCos)
++ eval $set_cc_for_build
++ sed 's/^ //' << EOF >$dummy.c
++#ifdef __cplusplus
++#include <stdio.h> /* for printf() prototype */
++ int main (int argc, char *argv[]) {
++#else
++ int main (argc, argv) int argc; char *argv[]; {
++#endif
++ #if defined (host_mips) && defined (MIPSEB)
++ #if defined (SYSTYPE_SYSV)
++ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
++ #endif
++ #if defined (SYSTYPE_SVR4)
++ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
++ #endif
++ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
++ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
++ #endif
++ #endif
++ exit (-1);
++ }
++EOF
++ $CC_FOR_BUILD -o $dummy $dummy.c &&
++ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
++ SYSTEM_NAME=`$dummy $dummyarg` &&
++ { echo "$SYSTEM_NAME"; exit; }
++ echo mips-mips-riscos${UNAME_RELEASE}
++ exit ;;
++ Motorola:PowerMAX_OS:*:*)
++ echo powerpc-motorola-powermax
++ exit ;;
++ Motorola:*:4.3:PL8-*)
++ echo powerpc-harris-powermax
++ exit ;;
++ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
++ echo powerpc-harris-powermax
++ exit ;;
++ Night_Hawk:Power_UNIX:*:*)
++ echo powerpc-harris-powerunix
++ exit ;;
++ m88k:CX/UX:7*:*)
++ echo m88k-harris-cxux7
++ exit ;;
++ m88k:*:4*:R4*)
++ echo m88k-motorola-sysv4
++ exit ;;
++ m88k:*:3*:R3*)
++ echo m88k-motorola-sysv3
++ exit ;;
++ AViiON:dgux:*:*)
++ # DG/UX returns AViiON for all architectures
++ UNAME_PROCESSOR=`/usr/bin/uname -p`
++ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
++ then
++ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
++ [ ${TARGET_BINARY_INTERFACE}x = x ]
++ then
++ echo m88k-dg-dgux${UNAME_RELEASE}
++ else
++ echo m88k-dg-dguxbcs${UNAME_RELEASE}
++ fi
++ else
++ echo i586-dg-dgux${UNAME_RELEASE}
++ fi
++ exit ;;
++ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
++ echo m88k-dolphin-sysv3
++ exit ;;
++ M88*:*:R3*:*)
++ # Delta 88k system running SVR3
++ echo m88k-motorola-sysv3
++ exit ;;
++ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
++ echo m88k-tektronix-sysv3
++ exit ;;
++ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
++ echo m68k-tektronix-bsd
++ exit ;;
++ *:IRIX*:*:*)
++ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
++ exit ;;
++ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
++ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
++ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
++ i*86:AIX:*:*)
++ echo i386-ibm-aix
++ exit ;;
++ ia64:AIX:*:*)
++ if [ -x /usr/bin/oslevel ] ; then
++ IBM_REV=`/usr/bin/oslevel`
++ else
++ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
++ fi
++ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
++ exit ;;
++ *:AIX:2:3)
++ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
++ eval $set_cc_for_build
++ sed 's/^ //' << EOF >$dummy.c
++ #include <sys/systemcfg.h>
++
++ main()
++ {
++ if (!__power_pc())
++ exit(1);
++ puts("powerpc-ibm-aix3.2.5");
++ exit(0);
++ }
++EOF
++ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
++ then
++ echo "$SYSTEM_NAME"
++ else
++ echo rs6000-ibm-aix3.2.5
++ fi
++ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
++ echo rs6000-ibm-aix3.2.4
++ else
++ echo rs6000-ibm-aix3.2
++ fi
++ exit ;;
++ *:AIX:*:[4567])
++ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
++ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
++ IBM_ARCH=rs6000
++ else
++ IBM_ARCH=powerpc
++ fi
++ if [ -x /usr/bin/oslevel ] ; then
++ IBM_REV=`/usr/bin/oslevel`
++ else
++ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
++ fi
++ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
++ exit ;;
++ *:AIX:*:*)
++ echo rs6000-ibm-aix
++ exit ;;
++ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
++ echo romp-ibm-bsd4.4
++ exit ;;
++ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
++ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
++ exit ;; # report: romp-ibm BSD 4.3
++ *:BOSX:*:*)
++ echo rs6000-bull-bosx
++ exit ;;
++ DPX/2?00:B.O.S.:*:*)
++ echo m68k-bull-sysv3
++ exit ;;
++ 9000/[34]??:4.3bsd:1.*:*)
++ echo m68k-hp-bsd
++ exit ;;
++ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
++ echo m68k-hp-bsd4.4
++ exit ;;
++ 9000/[34678]??:HP-UX:*:*)
++ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
++ case "${UNAME_MACHINE}" in
++ 9000/31? ) HP_ARCH=m68000 ;;
++ 9000/[34]?? ) HP_ARCH=m68k ;;
++ 9000/[678][0-9][0-9])
++ if [ -x /usr/bin/getconf ]; then
++ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
++ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
++ case "${sc_cpu_version}" in
++ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
++ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
++ 532) # CPU_PA_RISC2_0
++ case "${sc_kernel_bits}" in
++ 32) HP_ARCH="hppa2.0n" ;;
++ 64) HP_ARCH="hppa2.0w" ;;
++ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
++ esac ;;
++ esac
++ fi
++ if [ "${HP_ARCH}" = "" ]; then
++ eval $set_cc_for_build
++ sed 's/^ //' << EOF >$dummy.c
++
++ #define _HPUX_SOURCE
++ #include <stdlib.h>
++ #include <unistd.h>
++
++ int main ()
++ {
++ #if defined(_SC_KERNEL_BITS)
++ long bits = sysconf(_SC_KERNEL_BITS);
++ #endif
++ long cpu = sysconf (_SC_CPU_VERSION);
++
++ switch (cpu)
++ {
++ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
++ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
++ case CPU_PA_RISC2_0:
++ #if defined(_SC_KERNEL_BITS)
++ switch (bits)
++ {
++ case 64: puts ("hppa2.0w"); break;
++ case 32: puts ("hppa2.0n"); break;
++ default: puts ("hppa2.0"); break;
++ } break;
++ #else /* !defined(_SC_KERNEL_BITS) */
++ puts ("hppa2.0"); break;
++ #endif
++ default: puts ("hppa1.0"); break;
++ }
++ exit (0);
++ }
++EOF
++ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
++ test -z "$HP_ARCH" && HP_ARCH=hppa
++ fi ;;
++ esac
++ if [ ${HP_ARCH} = "hppa2.0w" ]
++ then
++ eval $set_cc_for_build
++
++ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
++ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
++ # generating 64-bit code. GNU and HP use different nomenclature:
++ #
++ # $ CC_FOR_BUILD=cc ./config.guess
++ # => hppa2.0w-hp-hpux11.23
++ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
++ # => hppa64-hp-hpux11.23
++
++ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
++ grep -q __LP64__
++ then
++ HP_ARCH="hppa2.0w"
++ else
++ HP_ARCH="hppa64"
++ fi
++ fi
++ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
++ exit ;;
++ ia64:HP-UX:*:*)
++ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
++ echo ia64-hp-hpux${HPUX_REV}
++ exit ;;
++ 3050*:HI-UX:*:*)
++ eval $set_cc_for_build
++ sed 's/^ //' << EOF >$dummy.c
++ #include <unistd.h>
++ int
++ main ()
++ {
++ long cpu = sysconf (_SC_CPU_VERSION);
++ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
++ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
++ results, however. */
++ if (CPU_IS_PA_RISC (cpu))
++ {
++ switch (cpu)
++ {
++ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
++ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
++ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
++ default: puts ("hppa-hitachi-hiuxwe2"); break;
++ }
++ }
++ else if (CPU_IS_HP_MC68K (cpu))
++ puts ("m68k-hitachi-hiuxwe2");
++ else puts ("unknown-hitachi-hiuxwe2");
++ exit (0);
++ }
++EOF
++ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
++ { echo "$SYSTEM_NAME"; exit; }
++ echo unknown-hitachi-hiuxwe2
++ exit ;;
++ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
++ echo hppa1.1-hp-bsd
++ exit ;;
++ 9000/8??:4.3bsd:*:*)
++ echo hppa1.0-hp-bsd
++ exit ;;
++ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
++ echo hppa1.0-hp-mpeix
++ exit ;;
++ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
++ echo hppa1.1-hp-osf
++ exit ;;
++ hp8??:OSF1:*:*)
++ echo hppa1.0-hp-osf
++ exit ;;
++ i*86:OSF1:*:*)
++ if [ -x /usr/sbin/sysversion ] ; then
++ echo ${UNAME_MACHINE}-unknown-osf1mk
++ else
++ echo ${UNAME_MACHINE}-unknown-osf1
++ fi
++ exit ;;
++ parisc*:Lites*:*:*)
++ echo hppa1.1-hp-lites
++ exit ;;
++ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
++ echo c1-convex-bsd
++ exit ;;
++ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
++ if getsysinfo -f scalar_acc
++ then echo c32-convex-bsd
++ else echo c2-convex-bsd
++ fi
++ exit ;;
++ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
++ echo c34-convex-bsd
++ exit ;;
++ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
++ echo c38-convex-bsd
++ exit ;;
++ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
++ echo c4-convex-bsd
++ exit ;;
++ CRAY*Y-MP:*:*:*)
++ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
++ exit ;;
++ CRAY*[A-Z]90:*:*:*)
++ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
++ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
++ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
++ -e 's/\.[^.]*$/.X/'
++ exit ;;
++ CRAY*TS:*:*:*)
++ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
++ exit ;;
++ CRAY*T3E:*:*:*)
++ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
++ exit ;;
++ CRAY*SV1:*:*:*)
++ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
++ exit ;;
++ *:UNICOS/mp:*:*)
++ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
++ exit ;;
++ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
++ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
++ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
++ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
++ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
++ exit ;;
++ 5000:UNIX_System_V:4.*:*)
++ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
++ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
++ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
++ exit ;;
++ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
++ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
++ exit ;;
++ sparc*:BSD/OS:*:*)
++ echo sparc-unknown-bsdi${UNAME_RELEASE}
++ exit ;;
++ *:BSD/OS:*:*)
++ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
++ exit ;;
++ *:FreeBSD:*:*)
++ UNAME_PROCESSOR=`/usr/bin/uname -p`
++ case ${UNAME_PROCESSOR} in
++ amd64)
++ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
++ *)
++ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
++ esac
++ exit ;;
++ i*:CYGWIN*:*)
++ echo ${UNAME_MACHINE}-pc-cygwin
++ exit ;;
++ *:MINGW64*:*)
++ echo ${UNAME_MACHINE}-pc-mingw64
++ exit ;;
++ *:MINGW*:*)
++ echo ${UNAME_MACHINE}-pc-mingw32
++ exit ;;
++ i*:MSYS*:*)
++ echo ${UNAME_MACHINE}-pc-msys
++ exit ;;
++ i*:windows32*:*)
++ # uname -m includes "-pc" on this system.
++ echo ${UNAME_MACHINE}-mingw32
++ exit ;;
++ i*:PW*:*)
++ echo ${UNAME_MACHINE}-pc-pw32
++ exit ;;
++ *:Interix*:*)
++ case ${UNAME_MACHINE} in
++ x86)
++ echo i586-pc-interix${UNAME_RELEASE}
++ exit ;;
++ authenticamd | genuineintel | EM64T)
++ echo x86_64-unknown-interix${UNAME_RELEASE}
++ exit ;;
++ IA64)
++ echo ia64-unknown-interix${UNAME_RELEASE}
++ exit ;;
++ esac ;;
++ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
++ echo i${UNAME_MACHINE}-pc-mks
++ exit ;;
++ 8664:Windows_NT:*)
++ echo x86_64-pc-mks
++ exit ;;
++ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
++ # How do we know it's Interix rather than the generic POSIX subsystem?
++ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
++ # UNAME_MACHINE based on the output of uname instead of i386?
++ echo i586-pc-interix
++ exit ;;
++ i*:UWIN*:*)
++ echo ${UNAME_MACHINE}-pc-uwin
++ exit ;;
++ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
++ echo x86_64-unknown-cygwin
++ exit ;;
++ p*:CYGWIN*:*)
++ echo powerpcle-unknown-cygwin
++ exit ;;
++ prep*:SunOS:5.*:*)
++ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
++ exit ;;
++ *:GNU:*:*)
++ # the GNU system
++ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
++ exit ;;
++ *:GNU/*:*:*)
++ # other systems with GNU libc and userland
++ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
++ exit ;;
++ i*86:Minix:*:*)
++ echo ${UNAME_MACHINE}-pc-minix
++ exit ;;
++ aarch64:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ aarch64_be:Linux:*:*)
++ UNAME_MACHINE=aarch64_be
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ alpha:Linux:*:*)
++ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
++ EV5) UNAME_MACHINE=alphaev5 ;;
++ EV56) UNAME_MACHINE=alphaev56 ;;
++ PCA56) UNAME_MACHINE=alphapca56 ;;
++ PCA57) UNAME_MACHINE=alphapca56 ;;
++ EV6) UNAME_MACHINE=alphaev6 ;;
++ EV67) UNAME_MACHINE=alphaev67 ;;
++ EV68*) UNAME_MACHINE=alphaev68 ;;
++ esac
++ objdump --private-headers /bin/sh | grep -q ld.so.1
++ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ arc:Linux:*:* | arceb:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ arm*:Linux:*:*)
++ eval $set_cc_for_build
++ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
++ | grep -q __ARM_EABI__
++ then
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ else
++ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
++ | grep -q __ARM_PCS_VFP
++ then
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
++ else
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
++ fi
++ fi
++ exit ;;
++ avr32*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ cris:Linux:*:*)
++ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
++ exit ;;
++ crisv32:Linux:*:*)
++ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
++ exit ;;
++ frv:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ hexagon:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ i*86:Linux:*:*)
++ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
++ exit ;;
++ ia64:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ m32r*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ m68*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ mips:Linux:*:* | mips64:Linux:*:*)
++ eval $set_cc_for_build
++ sed 's/^ //' << EOF >$dummy.c
++ #undef CPU
++ #undef ${UNAME_MACHINE}
++ #undef ${UNAME_MACHINE}el
++ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
++ CPU=${UNAME_MACHINE}el
++ #else
++ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
++ CPU=${UNAME_MACHINE}
++ #else
++ CPU=
++ #endif
++ #endif
++EOF
++ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
++ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
++ ;;
++ or1k:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ or32:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ padre:Linux:*:*)
++ echo sparc-unknown-linux-${LIBC}
++ exit ;;
++ parisc64:Linux:*:* | hppa64:Linux:*:*)
++ echo hppa64-unknown-linux-${LIBC}
++ exit ;;
++ parisc:Linux:*:* | hppa:Linux:*:*)
++ # Look for CPU level
++ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
++ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
++ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
++ *) echo hppa-unknown-linux-${LIBC} ;;
++ esac
++ exit ;;
++ ppc64:Linux:*:*)
++ echo powerpc64-unknown-linux-${LIBC}
++ exit ;;
++ ppc:Linux:*:*)
++ echo powerpc-unknown-linux-${LIBC}
++ exit ;;
++ ppc64le:Linux:*:*)
++ echo powerpc64le-unknown-linux-${LIBC}
++ exit ;;
++ ppcle:Linux:*:*)
++ echo powerpcle-unknown-linux-${LIBC}
++ exit ;;
++ s390:Linux:*:* | s390x:Linux:*:*)
++ echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
++ exit ;;
++ sh64*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ sh*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ sparc:Linux:*:* | sparc64:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ tile*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ vax:Linux:*:*)
++ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
++ exit ;;
++ x86_64:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ xtensa*:Linux:*:*)
++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
++ exit ;;
++ i*86:DYNIX/ptx:4*:*)
++ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
++ # earlier versions are messed up and put the nodename in both
++ # sysname and nodename.
++ echo i386-sequent-sysv4
++ exit ;;
++ i*86:UNIX_SV:4.2MP:2.*)
++ # Unixware is an offshoot of SVR4, but it has its own version
++ # number series starting with 2...
++ # I am not positive that other SVR4 systems won't match this,
++ # I just have to hope. -- rms.
++ # Use sysv4.2uw... so that sysv4* matches it.
++ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
++ exit ;;
++ i*86:OS/2:*:*)
++ # If we were able to find `uname', then EMX Unix compatibility
++ # is probably installed.
++ echo ${UNAME_MACHINE}-pc-os2-emx
++ exit ;;
++ i*86:XTS-300:*:STOP)
++ echo ${UNAME_MACHINE}-unknown-stop
++ exit ;;
++ i*86:atheos:*:*)
++ echo ${UNAME_MACHINE}-unknown-atheos
++ exit ;;
++ i*86:syllable:*:*)
++ echo ${UNAME_MACHINE}-pc-syllable
++ exit ;;
++ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
++ echo i386-unknown-lynxos${UNAME_RELEASE}
++ exit ;;
++ i*86:*DOS:*:*)
++ echo ${UNAME_MACHINE}-pc-msdosdjgpp
++ exit ;;
++ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
++ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
++ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
++ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
++ else
++ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
++ fi
++ exit ;;
++ i*86:*:5:[678]*)
++ # UnixWare 7.x, OpenUNIX and OpenServer 6.
++ case `/bin/uname -X | grep "^Machine"` in
++ *486*) UNAME_MACHINE=i486 ;;
++ *Pentium) UNAME_MACHINE=i586 ;;
++ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
++ esac
++ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
++ exit ;;
++ i*86:*:3.2:*)
++ if test -f /usr/options/cb.name; then
++ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
++ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
++ elif /bin/uname -X 2>/dev/null >/dev/null ; then
++ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
++ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
++ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
++ && UNAME_MACHINE=i586
++ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
++ && UNAME_MACHINE=i686
++ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
++ && UNAME_MACHINE=i686
++ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
++ else
++ echo ${UNAME_MACHINE}-pc-sysv32
++ fi
++ exit ;;
++ pc:*:*:*)
++ # Left here for compatibility:
++ # uname -m prints for DJGPP always 'pc', but it prints nothing about
++ # the processor, so we play safe by assuming i586.
++ # Note: whatever this is, it MUST be the same as what config.sub
++ # prints for the "djgpp" host, or else GDB configury will decide that
++ # this is a cross-build.
++ echo i586-pc-msdosdjgpp
++ exit ;;
++ Intel:Mach:3*:*)
++ echo i386-pc-mach3
++ exit ;;
++ paragon:*:*:*)
++ echo i860-intel-osf1
++ exit ;;
++ i860:*:4.*:*) # i860-SVR4
++ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
++ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
++ else # Add other i860-SVR4 vendors below as they are discovered.
++ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
++ fi
++ exit ;;
++ mini*:CTIX:SYS*5:*)
++ # "miniframe"
++ echo m68010-convergent-sysv
++ exit ;;
++ mc68k:UNIX:SYSTEM5:3.51m)
++ echo m68k-convergent-sysv
++ exit ;;
++ M680?0:D-NIX:5.3:*)
++ echo m68k-diab-dnix
++ exit ;;
++ M68*:*:R3V[5678]*:*)
++ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
++ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
++ OS_REL=''
++ test -r /etc/.relid \
++ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
++ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
++ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
++ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
++ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
++ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
++ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
++ && { echo i486-ncr-sysv4; exit; } ;;
++ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
++ OS_REL='.3'
++ test -r /etc/.relid \
++ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
++ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
++ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
++ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
++ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
++ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
++ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
++ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
++ echo m68k-unknown-lynxos${UNAME_RELEASE}
++ exit ;;
++ mc68030:UNIX_System_V:4.*:*)
++ echo m68k-atari-sysv4
++ exit ;;
++ TSUNAMI:LynxOS:2.*:*)
++ echo sparc-unknown-lynxos${UNAME_RELEASE}
++ exit ;;
++ rs6000:LynxOS:2.*:*)
++ echo rs6000-unknown-lynxos${UNAME_RELEASE}
++ exit ;;
++ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
++ echo powerpc-unknown-lynxos${UNAME_RELEASE}
++ exit ;;
++ SM[BE]S:UNIX_SV:*:*)
++ echo mips-dde-sysv${UNAME_RELEASE}
++ exit ;;
++ RM*:ReliantUNIX-*:*:*)
++ echo mips-sni-sysv4
++ exit ;;
++ RM*:SINIX-*:*:*)
++ echo mips-sni-sysv4
++ exit ;;
++ *:SINIX-*:*:*)
++ if uname -p 2>/dev/null >/dev/null ; then
++ UNAME_MACHINE=`(uname -p) 2>/dev/null`
++ echo ${UNAME_MACHINE}-sni-sysv4
++ else
++ echo ns32k-sni-sysv
++ fi
++ exit ;;
++ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
++ # says <Richard.M.Bartel@ccMail.Census.GOV>
++ echo i586-unisys-sysv4
++ exit ;;
++ *:UNIX_System_V:4*:FTX*)
++ # From Gerald Hewes <hewes@openmarket.com>.
++ # How about differentiating between stratus architectures? -djm
++ echo hppa1.1-stratus-sysv4
++ exit ;;
++ *:*:*:FTX*)
++ # From seanf@swdc.stratus.com.
++ echo i860-stratus-sysv4
++ exit ;;
++ i*86:VOS:*:*)
++ # From Paul.Green@stratus.com.
++ echo ${UNAME_MACHINE}-stratus-vos
++ exit ;;
++ *:VOS:*:*)
++ # From Paul.Green@stratus.com.
++ echo hppa1.1-stratus-vos
++ exit ;;
++ mc68*:A/UX:*:*)
++ echo m68k-apple-aux${UNAME_RELEASE}
++ exit ;;
++ news*:NEWS-OS:6*:*)
++ echo mips-sony-newsos6
++ exit ;;
++ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
++ if [ -d /usr/nec ]; then
++ echo mips-nec-sysv${UNAME_RELEASE}
++ else
++ echo mips-unknown-sysv${UNAME_RELEASE}
++ fi
++ exit ;;
++ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
++ echo powerpc-be-beos
++ exit ;;
++ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
++ echo powerpc-apple-beos
++ exit ;;
++ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
++ echo i586-pc-beos
++ exit ;;
++ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
++ echo i586-pc-haiku
++ exit ;;
++ x86_64:Haiku:*:*)
++ echo x86_64-unknown-haiku
++ exit ;;
++ SX-4:SUPER-UX:*:*)
++ echo sx4-nec-superux${UNAME_RELEASE}
++ exit ;;
++ SX-5:SUPER-UX:*:*)
++ echo sx5-nec-superux${UNAME_RELEASE}
++ exit ;;
++ SX-6:SUPER-UX:*:*)
++ echo sx6-nec-superux${UNAME_RELEASE}
++ exit ;;
++ SX-7:SUPER-UX:*:*)
++ echo sx7-nec-superux${UNAME_RELEASE}
++ exit ;;
++ SX-8:SUPER-UX:*:*)
++ echo sx8-nec-superux${UNAME_RELEASE}
++ exit ;;
++ SX-8R:SUPER-UX:*:*)
++ echo sx8r-nec-superux${UNAME_RELEASE}
++ exit ;;
++ Power*:Rhapsody:*:*)
++ echo powerpc-apple-rhapsody${UNAME_RELEASE}
++ exit ;;
++ *:Rhapsody:*:*)
++ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
++ exit ;;
++ *:Darwin:*:*)
++ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
++ eval $set_cc_for_build
++ if test "$UNAME_PROCESSOR" = unknown ; then
++ UNAME_PROCESSOR=powerpc
++ fi
++ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
++ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
++ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
++ grep IS_64BIT_ARCH >/dev/null
++ then
++ case $UNAME_PROCESSOR in
++ i386) UNAME_PROCESSOR=x86_64 ;;
++ powerpc) UNAME_PROCESSOR=powerpc64 ;;
++ esac
++ fi
++ fi
++ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
++ exit ;;
++ *:procnto*:*:* | *:QNX:[0123456789]*:*)
++ UNAME_PROCESSOR=`uname -p`
++ if test "$UNAME_PROCESSOR" = "x86"; then
++ UNAME_PROCESSOR=i386
++ UNAME_MACHINE=pc
++ fi
++ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
++ exit ;;
++ *:QNX:*:4*)
++ echo i386-pc-qnx
++ exit ;;
++ NEO-?:NONSTOP_KERNEL:*:*)
++ echo neo-tandem-nsk${UNAME_RELEASE}
++ exit ;;
++ NSE-*:NONSTOP_KERNEL:*:*)
++ echo nse-tandem-nsk${UNAME_RELEASE}
++ exit ;;
++ NSR-?:NONSTOP_KERNEL:*:*)
++ echo nsr-tandem-nsk${UNAME_RELEASE}
++ exit ;;
++ *:NonStop-UX:*:*)
++ echo mips-compaq-nonstopux
++ exit ;;
++ BS2000:POSIX*:*:*)
++ echo bs2000-siemens-sysv
++ exit ;;
++ DS/*:UNIX_System_V:*:*)
++ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
++ exit ;;
++ *:Plan9:*:*)
++ # "uname -m" is not consistent, so use $cputype instead. 386
++ # is converted to i386 for consistency with other x86
++ # operating systems.
++ if test "$cputype" = "386"; then
++ UNAME_MACHINE=i386
++ else
++ UNAME_MACHINE="$cputype"
++ fi
++ echo ${UNAME_MACHINE}-unknown-plan9
++ exit ;;
++ *:TOPS-10:*:*)
++ echo pdp10-unknown-tops10
++ exit ;;
++ *:TENEX:*:*)
++ echo pdp10-unknown-tenex
++ exit ;;
++ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
++ echo pdp10-dec-tops20
++ exit ;;
++ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
++ echo pdp10-xkl-tops20
++ exit ;;
++ *:TOPS-20:*:*)
++ echo pdp10-unknown-tops20
++ exit ;;
++ *:ITS:*:*)
++ echo pdp10-unknown-its
++ exit ;;
++ SEI:*:*:SEIUX)
++ echo mips-sei-seiux${UNAME_RELEASE}
++ exit ;;
++ *:DragonFly:*:*)
++ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
++ exit ;;
++ *:*VMS:*:*)
++ UNAME_MACHINE=`(uname -p) 2>/dev/null`
++ case "${UNAME_MACHINE}" in
++ A*) echo alpha-dec-vms ; exit ;;
++ I*) echo ia64-dec-vms ; exit ;;
++ V*) echo vax-dec-vms ; exit ;;
++ esac ;;
++ *:XENIX:*:SysV)
++ echo i386-pc-xenix
++ exit ;;
++ i*86:skyos:*:*)
++ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
++ exit ;;
++ i*86:rdos:*:*)
++ echo ${UNAME_MACHINE}-pc-rdos
++ exit ;;
++ i*86:AROS:*:*)
++ echo ${UNAME_MACHINE}-pc-aros
++ exit ;;
++ x86_64:VMkernel:*:*)
++ echo ${UNAME_MACHINE}-unknown-esx
++ exit ;;
++esac
++
++eval $set_cc_for_build
++cat >$dummy.c <<EOF
++#ifdef _SEQUENT_
++# include <sys/types.h>
++# include <sys/utsname.h>
++#endif
++main ()
++{
++#if defined (sony)
++#if defined (MIPSEB)
++ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
++ I don't know.... */
++ printf ("mips-sony-bsd\n"); exit (0);
++#else
++#include <sys/param.h>
++ printf ("m68k-sony-newsos%s\n",
++#ifdef NEWSOS4
++ "4"
++#else
++ ""
++#endif
++ ); exit (0);
++#endif
++#endif
++
++#if defined (__arm) && defined (__acorn) && defined (__unix)
++ printf ("arm-acorn-riscix\n"); exit (0);
++#endif
++
++#if defined (hp300) && !defined (hpux)
++ printf ("m68k-hp-bsd\n"); exit (0);
++#endif
++
++#if defined (NeXT)
++#if !defined (__ARCHITECTURE__)
++#define __ARCHITECTURE__ "m68k"
++#endif
++ int version;
++ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
++ if (version < 4)
++ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
++ else
++ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
++ exit (0);
++#endif
++
++#if defined (MULTIMAX) || defined (n16)
++#if defined (UMAXV)
++ printf ("ns32k-encore-sysv\n"); exit (0);
++#else
++#if defined (CMU)
++ printf ("ns32k-encore-mach\n"); exit (0);
++#else
++ printf ("ns32k-encore-bsd\n"); exit (0);
++#endif
++#endif
++#endif
++
++#if defined (__386BSD__)
++ printf ("i386-pc-bsd\n"); exit (0);
++#endif
++
++#if defined (sequent)
++#if defined (i386)
++ printf ("i386-sequent-dynix\n"); exit (0);
++#endif
++#if defined (ns32000)
++ printf ("ns32k-sequent-dynix\n"); exit (0);
++#endif
++#endif
++
++#if defined (_SEQUENT_)
++ struct utsname un;
++
++ uname(&un);
++
++ if (strncmp(un.version, "V2", 2) == 0) {
++ printf ("i386-sequent-ptx2\n"); exit (0);
++ }
++ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
++ printf ("i386-sequent-ptx1\n"); exit (0);
++ }
++ printf ("i386-sequent-ptx\n"); exit (0);
++
++#endif
++
++#if defined (vax)
++# if !defined (ultrix)
++# include <sys/param.h>
++# if defined (BSD)
++# if BSD == 43
++ printf ("vax-dec-bsd4.3\n"); exit (0);
++# else
++# if BSD == 199006
++ printf ("vax-dec-bsd4.3reno\n"); exit (0);
++# else
++ printf ("vax-dec-bsd\n"); exit (0);
++# endif
++# endif
++# else
++ printf ("vax-dec-bsd\n"); exit (0);
++# endif
++# else
++ printf ("vax-dec-ultrix\n"); exit (0);
++# endif
++#endif
++
++#if defined (alliant) && defined (i860)
++ printf ("i860-alliant-bsd\n"); exit (0);
++#endif
++
++ exit (1);
++}
++EOF
++
++$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
++ { echo "$SYSTEM_NAME"; exit; }
++
++# Apollos put the system type in the environment.
++
++test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
++
++# Convex versions that predate uname can use getsysinfo(1)
++
++if [ -x /usr/convex/getsysinfo ]
++then
++ case `getsysinfo -f cpu_type` in
++ c1*)
++ echo c1-convex-bsd
++ exit ;;
++ c2*)
++ if getsysinfo -f scalar_acc
++ then echo c32-convex-bsd
++ else echo c2-convex-bsd
++ fi
++ exit ;;
++ c34*)
++ echo c34-convex-bsd
++ exit ;;
++ c38*)
++ echo c38-convex-bsd
++ exit ;;
++ c4*)
++ echo c4-convex-bsd
++ exit ;;
++ esac
++fi
++
++cat >&2 <<EOF
++$0: unable to guess system type
++
++This script, last modified $timestamp, has failed to recognize
++the operating system you are using. It is advised that you
++download the most up to date version of the config scripts from
++
++ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
++and
++ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
++
++If the version you run ($0) is already up to date, please
++send the following data and any information you think might be
++pertinent to <config-patches@gnu.org> in order to provide the needed
++information to handle your system.
++
++config.guess timestamp = $timestamp
++
++uname -m = `(uname -m) 2>/dev/null || echo unknown`
++uname -r = `(uname -r) 2>/dev/null || echo unknown`
++uname -s = `(uname -s) 2>/dev/null || echo unknown`
++uname -v = `(uname -v) 2>/dev/null || echo unknown`
++
++/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
++/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
++
++hostinfo = `(hostinfo) 2>/dev/null`
++/bin/universe = `(/bin/universe) 2>/dev/null`
++/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
++/bin/arch = `(/bin/arch) 2>/dev/null`
++/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
++/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
++
++UNAME_MACHINE = ${UNAME_MACHINE}
++UNAME_RELEASE = ${UNAME_RELEASE}
++UNAME_SYSTEM = ${UNAME_SYSTEM}
++UNAME_VERSION = ${UNAME_VERSION}
++EOF
++
++exit 1
++
++# Local variables:
++# eval: (add-hook 'write-file-hooks 'time-stamp)
++# time-stamp-start: "timestamp='"
++# time-stamp-format: "%:y-%02m-%02d"
++# time-stamp-end: "'"
++# End:
+--- /dev/null
++++ b/m4/ltoptions.m4
+@@ -0,0 +1,384 @@
++# Helper functions for option handling. -*- Autoconf -*-
++#
++# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
++# Inc.
++# Written by Gary V. Vaughan, 2004
++#
++# This file is free software; the Free Software Foundation gives
++# unlimited permission to copy and/or distribute it, with or without
++# modifications, as long as this notice is preserved.
++
++# serial 7 ltoptions.m4
++
++# This is to help aclocal find these macros, as it can't see m4_define.
++AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
++
++
++# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
++# ------------------------------------------
++m4_define([_LT_MANGLE_OPTION],
++[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
++
++
++# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
++# ---------------------------------------
++# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
++# matching handler defined, dispatch to it. Other OPTION-NAMEs are
++# saved as a flag.
++m4_define([_LT_SET_OPTION],
++[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
++m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
++ _LT_MANGLE_DEFUN([$1], [$2]),
++ [m4_warning([Unknown $1 option `$2'])])[]dnl
++])
++
++
++# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
++# ------------------------------------------------------------
++# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
++m4_define([_LT_IF_OPTION],
++[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
++
++
++# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
++# -------------------------------------------------------
++# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
++# are set.
++m4_define([_LT_UNLESS_OPTIONS],
++[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
++ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
++ [m4_define([$0_found])])])[]dnl
++m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
++])[]dnl
++])
++
++
++# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
++# ----------------------------------------
++# OPTION-LIST is a space-separated list of Libtool options associated
++# with MACRO-NAME. If any OPTION has a matching handler declared with
++# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
++# the unknown option and exit.
++m4_defun([_LT_SET_OPTIONS],
++[# Set options
++m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
++ [_LT_SET_OPTION([$1], _LT_Option)])
++
++m4_if([$1],[LT_INIT],[
++ dnl
++ dnl Simply set some default values (i.e off) if boolean options were not
++ dnl specified:
++ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
++ ])
++ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
++ ])
++ dnl
++ dnl If no reference was made to various pairs of opposing options, then
++ dnl we run the default mode handler for the pair. For example, if neither
++ dnl `shared' nor `disable-shared' was passed, we enable building of shared
++ dnl archives by default:
++ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
++ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
++ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
++ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
++ [_LT_ENABLE_FAST_INSTALL])
++ ])
++])# _LT_SET_OPTIONS
++
++
++## --------------------------------- ##
++## Macros to handle LT_INIT options. ##
++## --------------------------------- ##
++
++# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
++# -----------------------------------------
++m4_define([_LT_MANGLE_DEFUN],
++[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
++
++
++# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
++# -----------------------------------------------
++m4_define([LT_OPTION_DEFINE],
++[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
++])# LT_OPTION_DEFINE
++
++
++# dlopen
++# ------
++LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
++])
++
++AU_DEFUN([AC_LIBTOOL_DLOPEN],
++[_LT_SET_OPTION([LT_INIT], [dlopen])
++AC_DIAGNOSE([obsolete],
++[$0: Remove this warning and the call to _LT_SET_OPTION when you
++put the `dlopen' option into LT_INIT's first parameter.])
++])
++
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
++
++
++# win32-dll
++# ---------
++# Declare package support for building win32 dll's.
++LT_OPTION_DEFINE([LT_INIT], [win32-dll],
++[enable_win32_dll=yes
++
++case $host in
++*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
++ AC_CHECK_TOOL(AS, as, false)
++ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
++ AC_CHECK_TOOL(OBJDUMP, objdump, false)
++ ;;
++esac
++
++test -z "$AS" && AS=as
++_LT_DECL([], [AS], [1], [Assembler program])dnl
++
++test -z "$DLLTOOL" && DLLTOOL=dlltool
++_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
++
++test -z "$OBJDUMP" && OBJDUMP=objdump
++_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
++])# win32-dll
++
++AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++_LT_SET_OPTION([LT_INIT], [win32-dll])
++AC_DIAGNOSE([obsolete],
++[$0: Remove this warning and the call to _LT_SET_OPTION when you
++put the `win32-dll' option into LT_INIT's first parameter.])
++])
++
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
++
++
++# _LT_ENABLE_SHARED([DEFAULT])
++# ----------------------------
++# implement the --enable-shared flag, and supports the `shared' and
++# `disable-shared' LT_INIT options.
++# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
++m4_define([_LT_ENABLE_SHARED],
++[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
++AC_ARG_ENABLE([shared],
++ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
++ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
++ [p=${PACKAGE-default}
++ case $enableval in
++ yes) enable_shared=yes ;;
++ no) enable_shared=no ;;
++ *)
++ enable_shared=no
++ # Look at the argument we got. We use all the common list separators.
++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
++ for pkg in $enableval; do
++ IFS="$lt_save_ifs"
++ if test "X$pkg" = "X$p"; then
++ enable_shared=yes
++ fi
++ done
++ IFS="$lt_save_ifs"
++ ;;
++ esac],
++ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
++
++ _LT_DECL([build_libtool_libs], [enable_shared], [0],
++ [Whether or not to build shared libraries])
++])# _LT_ENABLE_SHARED
++
++LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
++LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
++
++# Old names:
++AC_DEFUN([AC_ENABLE_SHARED],
++[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
++])
++
++AC_DEFUN([AC_DISABLE_SHARED],
++[_LT_SET_OPTION([LT_INIT], [disable-shared])
++])
++
++AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
++AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
++
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AM_ENABLE_SHARED], [])
++dnl AC_DEFUN([AM_DISABLE_SHARED], [])
++
++
++
++# _LT_ENABLE_STATIC([DEFAULT])
++# ----------------------------
++# implement the --enable-static flag, and support the `static' and
++# `disable-static' LT_INIT options.
++# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
++m4_define([_LT_ENABLE_STATIC],
++[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
++AC_ARG_ENABLE([static],
++ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
++ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
++ [p=${PACKAGE-default}
++ case $enableval in
++ yes) enable_static=yes ;;
++ no) enable_static=no ;;
++ *)
++ enable_static=no
++ # Look at the argument we got. We use all the common list separators.
++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
++ for pkg in $enableval; do
++ IFS="$lt_save_ifs"
++ if test "X$pkg" = "X$p"; then
++ enable_static=yes
++ fi
++ done
++ IFS="$lt_save_ifs"
++ ;;
++ esac],
++ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
++
++ _LT_DECL([build_old_libs], [enable_static], [0],
++ [Whether or not to build static libraries])
++])# _LT_ENABLE_STATIC
++
++LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
++LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
++
++# Old names:
++AC_DEFUN([AC_ENABLE_STATIC],
++[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
++])
++
++AC_DEFUN([AC_DISABLE_STATIC],
++[_LT_SET_OPTION([LT_INIT], [disable-static])
++])
++
++AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
++AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
++
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AM_ENABLE_STATIC], [])
++dnl AC_DEFUN([AM_DISABLE_STATIC], [])
++
++
++
++# _LT_ENABLE_FAST_INSTALL([DEFAULT])
++# ----------------------------------
++# implement the --enable-fast-install flag, and support the `fast-install'
++# and `disable-fast-install' LT_INIT options.
++# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
++m4_define([_LT_ENABLE_FAST_INSTALL],
++[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
++AC_ARG_ENABLE([fast-install],
++ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
++ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
++ [p=${PACKAGE-default}
++ case $enableval in
++ yes) enable_fast_install=yes ;;
++ no) enable_fast_install=no ;;
++ *)
++ enable_fast_install=no
++ # Look at the argument we got. We use all the common list separators.
++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
++ for pkg in $enableval; do
++ IFS="$lt_save_ifs"
++ if test "X$pkg" = "X$p"; then
++ enable_fast_install=yes
++ fi
++ done
++ IFS="$lt_save_ifs"
++ ;;
++ esac],
++ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
++
++_LT_DECL([fast_install], [enable_fast_install], [0],
++ [Whether or not to optimize for fast installation])dnl
++])# _LT_ENABLE_FAST_INSTALL
++
++LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
++LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
++
++# Old names:
++AU_DEFUN([AC_ENABLE_FAST_INSTALL],
++[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
++AC_DIAGNOSE([obsolete],
++[$0: Remove this warning and the call to _LT_SET_OPTION when you put
++the `fast-install' option into LT_INIT's first parameter.])
++])
++
++AU_DEFUN([AC_DISABLE_FAST_INSTALL],
++[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
++AC_DIAGNOSE([obsolete],
++[$0: Remove this warning and the call to _LT_SET_OPTION when you put
++the `disable-fast-install' option into LT_INIT's first parameter.])
++])
++
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
++dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
++
++
++# _LT_WITH_PIC([MODE])
++# --------------------
++# implement the --with-pic flag, and support the `pic-only' and `no-pic'
++# LT_INIT options.
++# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
++m4_define([_LT_WITH_PIC],
++[AC_ARG_WITH([pic],
++ [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
++ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
++ [lt_p=${PACKAGE-default}
++ case $withval in
++ yes|no) pic_mode=$withval ;;
++ *)
++ pic_mode=default
++ # Look at the argument we got. We use all the common list separators.
++ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
++ for lt_pkg in $withval; do
++ IFS="$lt_save_ifs"
++ if test "X$lt_pkg" = "X$lt_p"; then
++ pic_mode=yes
++ fi
++ done
++ IFS="$lt_save_ifs"
++ ;;
++ esac],
++ [pic_mode=default])
++
++test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
++
++_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
++])# _LT_WITH_PIC
++
++LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
++LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
++
++# Old name:
++AU_DEFUN([AC_LIBTOOL_PICMODE],
++[_LT_SET_OPTION([LT_INIT], [pic-only])
++AC_DIAGNOSE([obsolete],
++[$0: Remove this warning and the call to _LT_SET_OPTION when you
++put the `pic-only' option into LT_INIT's first parameter.])
++])
++
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
++
++## ----------------- ##
++## LTDL_INIT Options ##
++## ----------------- ##
++
++m4_define([_LTDL_MODE], [])
++LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
++ [m4_define([_LTDL_MODE], [nonrecursive])])
++LT_OPTION_DEFINE([LTDL_INIT], [recursive],
++ [m4_define([_LTDL_MODE], [recursive])])
++LT_OPTION_DEFINE([LTDL_INIT], [subproject],
++ [m4_define([_LTDL_MODE], [subproject])])
++
++m4_define([_LTDL_TYPE], [])
++LT_OPTION_DEFINE([LTDL_INIT], [installable],
++ [m4_define([_LTDL_TYPE], [installable])])
++LT_OPTION_DEFINE([LTDL_INIT], [convenience],
++ [m4_define([_LTDL_TYPE], [convenience])])
+--- /dev/null
++++ b/m4/libtool.m4
+@@ -0,0 +1,7991 @@
++# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
++#
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
++# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
++# Foundation, Inc.
++# Written by Gordon Matzigkeit, 1996
++#
++# This file is free software; the Free Software Foundation gives
++# unlimited permission to copy and/or distribute it, with or without
++# modifications, as long as this notice is preserved.
++
++m4_define([_LT_COPYING], [dnl
++# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
++# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
++# Foundation, Inc.
++# Written by Gordon Matzigkeit, 1996
++#
++# This file is part of GNU Libtool.
++#
++# GNU Libtool is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# As a special exception to the GNU General Public License,
++# if you distribute this file as part of a program or library that
++# is built using GNU Libtool, you may include this file under the
++# same distribution terms that you use for the rest of that program.
++#
++# GNU Libtool is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU General Public License for more details.
++#
++# You should have received a copy of the GNU General Public License
++# along with GNU Libtool; see the file COPYING. If not, a copy
++# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
++# obtained by writing to the Free Software Foundation, Inc.,
++# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++])
++
++# serial 57 LT_INIT
++
++
++# LT_PREREQ(VERSION)
++# ------------------
++# Complain and exit if this libtool version is less that VERSION.
++m4_defun([LT_PREREQ],
++[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
++ [m4_default([$3],
++ [m4_fatal([Libtool version $1 or higher is required],
++ 63)])],
++ [$2])])
++
++
++# _LT_CHECK_BUILDDIR
++# ------------------
++# Complain if the absolute build directory name contains unusual characters
++m4_defun([_LT_CHECK_BUILDDIR],
++[case `pwd` in
++ *\ * | *\ *)
++ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
++esac
++])
++
++
++# LT_INIT([OPTIONS])
++# ------------------
++AC_DEFUN([LT_INIT],
++[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
++AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
++AC_BEFORE([$0], [LT_LANG])dnl
++AC_BEFORE([$0], [LT_OUTPUT])dnl
++AC_BEFORE([$0], [LTDL_INIT])dnl
++m4_require([_LT_CHECK_BUILDDIR])dnl
++
++dnl Autoconf doesn't catch unexpanded LT_ macros by default:
++m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
++m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
++dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
++dnl unless we require an AC_DEFUNed macro:
++AC_REQUIRE([LTOPTIONS_VERSION])dnl
++AC_REQUIRE([LTSUGAR_VERSION])dnl
++AC_REQUIRE([LTVERSION_VERSION])dnl
++AC_REQUIRE([LTOBSOLETE_VERSION])dnl
++m4_require([_LT_PROG_LTMAIN])dnl
++
++_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
++
++dnl Parse OPTIONS
++_LT_SET_OPTIONS([$0], [$1])
++
++# This can be used to rebuild libtool when needed
++LIBTOOL_DEPS="$ltmain"
++
++# Always use our own libtool.
++LIBTOOL='$(SHELL) $(top_builddir)/libtool'
++AC_SUBST(LIBTOOL)dnl
++
++_LT_SETUP
++
++# Only expand once:
++m4_define([LT_INIT])
++])# LT_INIT
++
++# Old names:
++AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
++AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
++dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
++
++
++# _LT_CC_BASENAME(CC)
++# -------------------
++# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
++m4_defun([_LT_CC_BASENAME],
++[for cc_temp in $1""; do
++ case $cc_temp in
++ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
++ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
++ \-*) ;;
++ *) break;;
++ esac
++done
++cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
++])
++
++
++# _LT_FILEUTILS_DEFAULTS
++# ----------------------
++# It is okay to use these file commands and assume they have been set
++# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
++m4_defun([_LT_FILEUTILS_DEFAULTS],
++[: ${CP="cp -f"}
++: ${MV="mv -f"}
++: ${RM="rm -f"}
++])# _LT_FILEUTILS_DEFAULTS
++
++
++# _LT_SETUP
++# ---------
++m4_defun([_LT_SETUP],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++AC_REQUIRE([AC_CANONICAL_BUILD])dnl
++AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
++AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
++
++_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
++dnl
++_LT_DECL([], [host_alias], [0], [The host system])dnl
++_LT_DECL([], [host], [0])dnl
++_LT_DECL([], [host_os], [0])dnl
++dnl
++_LT_DECL([], [build_alias], [0], [The build system])dnl
++_LT_DECL([], [build], [0])dnl
++_LT_DECL([], [build_os], [0])dnl
++dnl
++AC_REQUIRE([AC_PROG_CC])dnl
++AC_REQUIRE([LT_PATH_LD])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++dnl
++AC_REQUIRE([AC_PROG_LN_S])dnl
++test -z "$LN_S" && LN_S="ln -s"
++_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
++dnl
++AC_REQUIRE([LT_CMD_MAX_LEN])dnl
++_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
++_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
++dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_CHECK_SHELL_FEATURES])dnl
++m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
++m4_require([_LT_CMD_RELOAD])dnl
++m4_require([_LT_CHECK_MAGIC_METHOD])dnl
++m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
++m4_require([_LT_CMD_OLD_ARCHIVE])dnl
++m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
++m4_require([_LT_WITH_SYSROOT])dnl
++
++_LT_CONFIG_LIBTOOL_INIT([
++# See if we are running on zsh, and set the options which allow our
++# commands through without removal of \ escapes INIT.
++if test -n "\${ZSH_VERSION+set}" ; then
++ setopt NO_GLOB_SUBST
++fi
++])
++if test -n "${ZSH_VERSION+set}" ; then
++ setopt NO_GLOB_SUBST
++fi
++
++_LT_CHECK_OBJDIR
++
++m4_require([_LT_TAG_COMPILER])dnl
++
++case $host_os in
++aix3*)
++ # AIX sometimes has problems with the GCC collect2 program. For some
++ # reason, if we set the COLLECT_NAMES environment variable, the problems
++ # vanish in a puff of smoke.
++ if test "X${COLLECT_NAMES+set}" != Xset; then
++ COLLECT_NAMES=
++ export COLLECT_NAMES
++ fi
++ ;;
++esac
++
++# Global variables:
++ofile=libtool
++can_build_shared=yes
++
++# All known linkers require a `.a' archive for static linking (except MSVC,
++# which needs '.lib').
++libext=a
++
++with_gnu_ld="$lt_cv_prog_gnu_ld"
++
++old_CC="$CC"
++old_CFLAGS="$CFLAGS"
++
++# Set sane defaults for various variables
++test -z "$CC" && CC=cc
++test -z "$LTCC" && LTCC=$CC
++test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
++test -z "$LD" && LD=ld
++test -z "$ac_objext" && ac_objext=o
++
++_LT_CC_BASENAME([$compiler])
++
++# Only perform the check for file, if the check method requires it
++test -z "$MAGIC_CMD" && MAGIC_CMD=file
++case $deplibs_check_method in
++file_magic*)
++ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
++ _LT_PATH_MAGIC
++ fi
++ ;;
++esac
++
++# Use C for the default configuration in the libtool script
++LT_SUPPORTED_TAG([CC])
++_LT_LANG_C_CONFIG
++_LT_LANG_DEFAULT_CONFIG
++_LT_CONFIG_COMMANDS
++])# _LT_SETUP
++
++
++# _LT_PREPARE_SED_QUOTE_VARS
++# --------------------------
++# Define a few sed substitution that help us do robust quoting.
++m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
++[# Backslashify metacharacters that are still active within
++# double-quoted strings.
++sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
++
++# Same as above, but do not quote variable references.
++double_quote_subst='s/\([["`\\]]\)/\\\1/g'
++
++# Sed substitution to delay expansion of an escaped shell variable in a
++# double_quote_subst'ed string.
++delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
++
++# Sed substitution to delay expansion of an escaped single quote.
++delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
++
++# Sed substitution to avoid accidental globbing in evaled expressions
++no_glob_subst='s/\*/\\\*/g'
++])
++
++# _LT_PROG_LTMAIN
++# ---------------
++# Note that this code is called both from `configure', and `config.status'
++# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
++# `config.status' has no value for ac_aux_dir unless we are using Automake,
++# so we pass a copy along to make sure it has a sensible value anyway.
++m4_defun([_LT_PROG_LTMAIN],
++[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
++_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
++ltmain="$ac_aux_dir/ltmain.sh"
++])# _LT_PROG_LTMAIN
++
++
++## ------------------------------------- ##
++## Accumulate code for creating libtool. ##
++## ------------------------------------- ##
++
++# So that we can recreate a full libtool script including additional
++# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
++# in macros and then make a single call at the end using the `libtool'
++# label.
++
++
++# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
++# ----------------------------------------
++# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
++m4_define([_LT_CONFIG_LIBTOOL_INIT],
++[m4_ifval([$1],
++ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
++ [$1
++])])])
++
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_INIT])
++
++
++# _LT_CONFIG_LIBTOOL([COMMANDS])
++# ------------------------------
++# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
++m4_define([_LT_CONFIG_LIBTOOL],
++[m4_ifval([$1],
++ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
++ [$1
++])])])
++
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
++
++
++# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
++# -----------------------------------------------------
++m4_defun([_LT_CONFIG_SAVE_COMMANDS],
++[_LT_CONFIG_LIBTOOL([$1])
++_LT_CONFIG_LIBTOOL_INIT([$2])
++])
++
++
++# _LT_FORMAT_COMMENT([COMMENT])
++# -----------------------------
++# Add leading comment marks to the start of each line, and a trailing
++# full-stop to the whole comment if one is not present already.
++m4_define([_LT_FORMAT_COMMENT],
++[m4_ifval([$1], [
++m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
++ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
++)])
++
++
++
++## ------------------------ ##
++## FIXME: Eliminate VARNAME ##
++## ------------------------ ##
++
++
++# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
++# -------------------------------------------------------------------
++# CONFIGNAME is the name given to the value in the libtool script.
++# VARNAME is the (base) name used in the configure script.
++# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
++# VARNAME. Any other value will be used directly.
++m4_define([_LT_DECL],
++[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
++ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
++ [m4_ifval([$1], [$1], [$2])])
++ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
++ m4_ifval([$4],
++ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
++ lt_dict_add_subkey([lt_decl_dict], [$2],
++ [tagged?], [m4_ifval([$5], [yes], [no])])])
++])
++
++
++# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
++# --------------------------------------------------------
++m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
++
++
++# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
++# ------------------------------------------------
++m4_define([lt_decl_tag_varnames],
++[_lt_decl_filter([tagged?], [yes], $@)])
++
++
++# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
++# ---------------------------------------------------------
++m4_define([_lt_decl_filter],
++[m4_case([$#],
++ [0], [m4_fatal([$0: too few arguments: $#])],
++ [1], [m4_fatal([$0: too few arguments: $#: $1])],
++ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
++ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
++ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
++])
++
++
++# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
++# --------------------------------------------------
++m4_define([lt_decl_quote_varnames],
++[_lt_decl_filter([value], [1], $@)])
++
++
++# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
++# ---------------------------------------------------
++m4_define([lt_decl_dquote_varnames],
++[_lt_decl_filter([value], [2], $@)])
++
++
++# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
++# ---------------------------------------------------
++m4_define([lt_decl_varnames_tagged],
++[m4_assert([$# <= 2])dnl
++_$0(m4_quote(m4_default([$1], [[, ]])),
++ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
++ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
++m4_define([_lt_decl_varnames_tagged],
++[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
++
++
++# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
++# ------------------------------------------------
++m4_define([lt_decl_all_varnames],
++[_$0(m4_quote(m4_default([$1], [[, ]])),
++ m4_if([$2], [],
++ m4_quote(lt_decl_varnames),
++ m4_quote(m4_shift($@))))[]dnl
++])
++m4_define([_lt_decl_all_varnames],
++[lt_join($@, lt_decl_varnames_tagged([$1],
++ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
++])
++
++
++# _LT_CONFIG_STATUS_DECLARE([VARNAME])
++# ------------------------------------
++# Quote a variable value, and forward it to `config.status' so that its
++# declaration there will have the same value as in `configure'. VARNAME
++# must have a single quote delimited value for this to work.
++m4_define([_LT_CONFIG_STATUS_DECLARE],
++[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
++
++
++# _LT_CONFIG_STATUS_DECLARATIONS
++# ------------------------------
++# We delimit libtool config variables with single quotes, so when
++# we write them to config.status, we have to be sure to quote all
++# embedded single quotes properly. In configure, this macro expands
++# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
++#
++# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
++m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
++[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
++ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
++
++
++# _LT_LIBTOOL_TAGS
++# ----------------
++# Output comment and list of tags supported by the script
++m4_defun([_LT_LIBTOOL_TAGS],
++[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
++available_tags="_LT_TAGS"dnl
++])
++
++
++# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
++# -----------------------------------
++# Extract the dictionary values for VARNAME (optionally with TAG) and
++# expand to a commented shell variable setting:
++#
++# # Some comment about what VAR is for.
++# visible_name=$lt_internal_name
++m4_define([_LT_LIBTOOL_DECLARE],
++[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
++ [description])))[]dnl
++m4_pushdef([_libtool_name],
++ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
++m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
++ [0], [_libtool_name=[$]$1],
++ [1], [_libtool_name=$lt_[]$1],
++ [2], [_libtool_name=$lt_[]$1],
++ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
++m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
++])
++
++
++# _LT_LIBTOOL_CONFIG_VARS
++# -----------------------
++# Produce commented declarations of non-tagged libtool config variables
++# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
++# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
++# section) are produced by _LT_LIBTOOL_TAG_VARS.
++m4_defun([_LT_LIBTOOL_CONFIG_VARS],
++[m4_foreach([_lt_var],
++ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
++ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
++
++
++# _LT_LIBTOOL_TAG_VARS(TAG)
++# -------------------------
++m4_define([_LT_LIBTOOL_TAG_VARS],
++[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
++ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
++
++
++# _LT_TAGVAR(VARNAME, [TAGNAME])
++# ------------------------------
++m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
++
++
++# _LT_CONFIG_COMMANDS
++# -------------------
++# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
++# variables for single and double quote escaping we saved from calls
++# to _LT_DECL, we can put quote escaped variables declarations
++# into `config.status', and then the shell code to quote escape them in
++# for loops in `config.status'. Finally, any additional code accumulated
++# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
++m4_defun([_LT_CONFIG_COMMANDS],
++[AC_PROVIDE_IFELSE([LT_OUTPUT],
++ dnl If the libtool generation code has been placed in $CONFIG_LT,
++ dnl instead of duplicating it all over again into config.status,
++ dnl then we will have config.status run $CONFIG_LT later, so it
++ dnl needs to know what name is stored there:
++ [AC_CONFIG_COMMANDS([libtool],
++ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
++ dnl If the libtool generation code is destined for config.status,
++ dnl expand the accumulated commands and init code now:
++ [AC_CONFIG_COMMANDS([libtool],
++ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
++])#_LT_CONFIG_COMMANDS
++
++
++# Initialize.
++m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
++[
++
++# The HP-UX ksh and POSIX shell print the target directory to stdout
++# if CDPATH is set.
++(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
++
++sed_quote_subst='$sed_quote_subst'
++double_quote_subst='$double_quote_subst'
++delay_variable_subst='$delay_variable_subst'
++_LT_CONFIG_STATUS_DECLARATIONS
++LTCC='$LTCC'
++LTCFLAGS='$LTCFLAGS'
++compiler='$compiler_DEFAULT'
++
++# A function that is used when there is no print builtin or printf.
++func_fallback_echo ()
++{
++ eval 'cat <<_LTECHO_EOF
++\$[]1
++_LTECHO_EOF'
++}
++
++# Quote evaled strings.
++for var in lt_decl_all_varnames([[ \
++]], lt_decl_quote_varnames); do
++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
++ *[[\\\\\\\`\\"\\\$]]*)
++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
++ ;;
++ *)
++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
++ ;;
++ esac
++done
++
++# Double-quote double-evaled strings.
++for var in lt_decl_all_varnames([[ \
++]], lt_decl_dquote_varnames); do
++ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
++ *[[\\\\\\\`\\"\\\$]]*)
++ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
++ ;;
++ *)
++ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
++ ;;
++ esac
++done
++
++_LT_OUTPUT_LIBTOOL_INIT
++])
++
++# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
++# ------------------------------------
++# Generate a child script FILE with all initialization necessary to
++# reuse the environment learned by the parent script, and make the
++# file executable. If COMMENT is supplied, it is inserted after the
++# `#!' sequence but before initialization text begins. After this
++# macro, additional text can be appended to FILE to form the body of
++# the child script. The macro ends with non-zero status if the
++# file could not be fully written (such as if the disk is full).
++m4_ifdef([AS_INIT_GENERATED],
++[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
++[m4_defun([_LT_GENERATED_FILE_INIT],
++[m4_require([AS_PREPARE])]dnl
++[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
++[lt_write_fail=0
++cat >$1 <<_ASEOF || lt_write_fail=1
++#! $SHELL
++# Generated by $as_me.
++$2
++SHELL=\${CONFIG_SHELL-$SHELL}
++export SHELL
++_ASEOF
++cat >>$1 <<\_ASEOF || lt_write_fail=1
++AS_SHELL_SANITIZE
++_AS_PREPARE
++exec AS_MESSAGE_FD>&1
++_ASEOF
++test $lt_write_fail = 0 && chmod +x $1[]dnl
++m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
++
++# LT_OUTPUT
++# ---------
++# This macro allows early generation of the libtool script (before
++# AC_OUTPUT is called), incase it is used in configure for compilation
++# tests.
++AC_DEFUN([LT_OUTPUT],
++[: ${CONFIG_LT=./config.lt}
++AC_MSG_NOTICE([creating $CONFIG_LT])
++_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
++[# Run this file to recreate a libtool stub with the current configuration.])
++
++cat >>"$CONFIG_LT" <<\_LTEOF
++lt_cl_silent=false
++exec AS_MESSAGE_LOG_FD>>config.log
++{
++ echo
++ AS_BOX([Running $as_me.])
++} >&AS_MESSAGE_LOG_FD
++
++lt_cl_help="\
++\`$as_me' creates a local libtool stub from the current configuration,
++for use in further configure time tests before the real libtool is
++generated.
++
++Usage: $[0] [[OPTIONS]]
++
++ -h, --help print this help, then exit
++ -V, --version print version number, then exit
++ -q, --quiet do not print progress messages
++ -d, --debug don't remove temporary files
++
++Report bugs to <bug-libtool@gnu.org>."
++
++lt_cl_version="\
++m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
++m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
++configured by $[0], generated by m4_PACKAGE_STRING.
++
++Copyright (C) 2011 Free Software Foundation, Inc.
++This config.lt script is free software; the Free Software Foundation
++gives unlimited permision to copy, distribute and modify it."
++
++while test $[#] != 0
++do
++ case $[1] in
++ --version | --v* | -V )
++ echo "$lt_cl_version"; exit 0 ;;
++ --help | --h* | -h )
++ echo "$lt_cl_help"; exit 0 ;;
++ --debug | --d* | -d )
++ debug=: ;;
++ --quiet | --q* | --silent | --s* | -q )
++ lt_cl_silent=: ;;
++
++ -*) AC_MSG_ERROR([unrecognized option: $[1]
++Try \`$[0] --help' for more information.]) ;;
++
++ *) AC_MSG_ERROR([unrecognized argument: $[1]
++Try \`$[0] --help' for more information.]) ;;
++ esac
++ shift
++done
++
++if $lt_cl_silent; then
++ exec AS_MESSAGE_FD>/dev/null
++fi
++_LTEOF
++
++cat >>"$CONFIG_LT" <<_LTEOF
++_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
++_LTEOF
++
++cat >>"$CONFIG_LT" <<\_LTEOF
++AC_MSG_NOTICE([creating $ofile])
++_LT_OUTPUT_LIBTOOL_COMMANDS
++AS_EXIT(0)
++_LTEOF
++chmod +x "$CONFIG_LT"
++
++# configure is writing to config.log, but config.lt does its own redirection,
++# appending to config.log, which fails on DOS, as config.log is still kept
++# open by configure. Here we exec the FD to /dev/null, effectively closing
++# config.log, so it can be properly (re)opened and appended to by config.lt.
++lt_cl_success=:
++test "$silent" = yes &&
++ lt_config_lt_args="$lt_config_lt_args --quiet"
++exec AS_MESSAGE_LOG_FD>/dev/null
++$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
++exec AS_MESSAGE_LOG_FD>>config.log
++$lt_cl_success || AS_EXIT(1)
++])# LT_OUTPUT
++
++
++# _LT_CONFIG(TAG)
++# ---------------
++# If TAG is the built-in tag, create an initial libtool script with a
++# default configuration from the untagged config vars. Otherwise add code
++# to config.status for appending the configuration named by TAG from the
++# matching tagged config vars.
++m4_defun([_LT_CONFIG],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++_LT_CONFIG_SAVE_COMMANDS([
++ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
++ m4_if(_LT_TAG, [C], [
++ # See if we are running on zsh, and set the options which allow our
++ # commands through without removal of \ escapes.
++ if test -n "${ZSH_VERSION+set}" ; then
++ setopt NO_GLOB_SUBST
++ fi
++
++ cfgfile="${ofile}T"
++ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
++ $RM "$cfgfile"
++
++ cat <<_LT_EOF >> "$cfgfile"
++#! $SHELL
++
++# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
++# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
++# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
++# NOTE: Changes made to this file will be lost: look at ltmain.sh.
++#
++_LT_COPYING
++_LT_LIBTOOL_TAGS
++
++# ### BEGIN LIBTOOL CONFIG
++_LT_LIBTOOL_CONFIG_VARS
++_LT_LIBTOOL_TAG_VARS
++# ### END LIBTOOL CONFIG
++
++_LT_EOF
++
++ case $host_os in
++ aix3*)
++ cat <<\_LT_EOF >> "$cfgfile"
++# AIX sometimes has problems with the GCC collect2 program. For some
++# reason, if we set the COLLECT_NAMES environment variable, the problems
++# vanish in a puff of smoke.
++if test "X${COLLECT_NAMES+set}" != Xset; then
++ COLLECT_NAMES=
++ export COLLECT_NAMES
++fi
++_LT_EOF
++ ;;
++ esac
++
++ _LT_PROG_LTMAIN
++
++ # We use sed instead of cat because bash on DJGPP gets confused if
++ # if finds mixed CR/LF and LF-only lines. Since sed operates in
++ # text mode, it properly converts lines to CR/LF. This bash problem
++ # is reportedly fixed, but why not run on old versions too?
++ sed '$q' "$ltmain" >> "$cfgfile" \
++ || (rm -f "$cfgfile"; exit 1)
++
++ _LT_PROG_REPLACE_SHELLFNS
++
++ mv -f "$cfgfile" "$ofile" ||
++ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
++ chmod +x "$ofile"
++],
++[cat <<_LT_EOF >> "$ofile"
++
++dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
++dnl in a comment (ie after a #).
++# ### BEGIN LIBTOOL TAG CONFIG: $1
++_LT_LIBTOOL_TAG_VARS(_LT_TAG)
++# ### END LIBTOOL TAG CONFIG: $1
++_LT_EOF
++])dnl /m4_if
++],
++[m4_if([$1], [], [
++ PACKAGE='$PACKAGE'
++ VERSION='$VERSION'
++ TIMESTAMP='$TIMESTAMP'
++ RM='$RM'
++ ofile='$ofile'], [])
++])dnl /_LT_CONFIG_SAVE_COMMANDS
++])# _LT_CONFIG
++
++
++# LT_SUPPORTED_TAG(TAG)
++# ---------------------
++# Trace this macro to discover what tags are supported by the libtool
++# --tag option, using:
++# autoconf --trace 'LT_SUPPORTED_TAG:$1'
++AC_DEFUN([LT_SUPPORTED_TAG], [])
++
++
++# C support is built-in for now
++m4_define([_LT_LANG_C_enabled], [])
++m4_define([_LT_TAGS], [])
++
++
++# LT_LANG(LANG)
++# -------------
++# Enable libtool support for the given language if not already enabled.
++AC_DEFUN([LT_LANG],
++[AC_BEFORE([$0], [LT_OUTPUT])dnl
++m4_case([$1],
++ [C], [_LT_LANG(C)],
++ [C++], [_LT_LANG(CXX)],
++ [Go], [_LT_LANG(GO)],
++ [Java], [_LT_LANG(GCJ)],
++ [Fortran 77], [_LT_LANG(F77)],
++ [Fortran], [_LT_LANG(FC)],
++ [Windows Resource], [_LT_LANG(RC)],
++ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
++ [_LT_LANG($1)],
++ [m4_fatal([$0: unsupported language: "$1"])])])dnl
++])# LT_LANG
++
++
++# _LT_LANG(LANGNAME)
++# ------------------
++m4_defun([_LT_LANG],
++[m4_ifdef([_LT_LANG_]$1[_enabled], [],
++ [LT_SUPPORTED_TAG([$1])dnl
++ m4_append([_LT_TAGS], [$1 ])dnl
++ m4_define([_LT_LANG_]$1[_enabled], [])dnl
++ _LT_LANG_$1_CONFIG($1)])dnl
++])# _LT_LANG
++
++
++m4_ifndef([AC_PROG_GO], [
++############################################################
++# NOTE: This macro has been submitted for inclusion into #
++# GNU Autoconf as AC_PROG_GO. When it is available in #
++# a released version of Autoconf we should remove this #
++# macro and use it instead. #
++############################################################
++m4_defun([AC_PROG_GO],
++[AC_LANG_PUSH(Go)dnl
++AC_ARG_VAR([GOC], [Go compiler command])dnl
++AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
++_AC_ARG_VAR_LDFLAGS()dnl
++AC_CHECK_TOOL(GOC, gccgo)
++if test -z "$GOC"; then
++ if test -n "$ac_tool_prefix"; then
++ AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
++ fi
++fi
++if test -z "$GOC"; then
++ AC_CHECK_PROG(GOC, gccgo, gccgo, false)
++fi
++])#m4_defun
++])#m4_ifndef
++
++
++# _LT_LANG_DEFAULT_CONFIG
++# -----------------------
++m4_defun([_LT_LANG_DEFAULT_CONFIG],
++[AC_PROVIDE_IFELSE([AC_PROG_CXX],
++ [LT_LANG(CXX)],
++ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
++
++AC_PROVIDE_IFELSE([AC_PROG_F77],
++ [LT_LANG(F77)],
++ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
++
++AC_PROVIDE_IFELSE([AC_PROG_FC],
++ [LT_LANG(FC)],
++ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
++
++dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
++dnl pulling things in needlessly.
++AC_PROVIDE_IFELSE([AC_PROG_GCJ],
++ [LT_LANG(GCJ)],
++ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
++ [LT_LANG(GCJ)],
++ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
++ [LT_LANG(GCJ)],
++ [m4_ifdef([AC_PROG_GCJ],
++ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
++ m4_ifdef([A][M_PROG_GCJ],
++ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
++ m4_ifdef([LT_PROG_GCJ],
++ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
++
++AC_PROVIDE_IFELSE([AC_PROG_GO],
++ [LT_LANG(GO)],
++ [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
++
++AC_PROVIDE_IFELSE([LT_PROG_RC],
++ [LT_LANG(RC)],
++ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
++])# _LT_LANG_DEFAULT_CONFIG
++
++# Obsolete macros:
++AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
++AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
++AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
++AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
++AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
++dnl AC_DEFUN([AC_LIBTOOL_F77], [])
++dnl AC_DEFUN([AC_LIBTOOL_FC], [])
++dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
++dnl AC_DEFUN([AC_LIBTOOL_RC], [])
++
++
++# _LT_TAG_COMPILER
++# ----------------
++m4_defun([_LT_TAG_COMPILER],
++[AC_REQUIRE([AC_PROG_CC])dnl
++
++_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
++_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
++_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
++_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
++
++# If no C compiler was specified, use CC.
++LTCC=${LTCC-"$CC"}
++
++# If no C compiler flags were specified, use CFLAGS.
++LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
++
++# Allow CC to be a program name with arguments.
++compiler=$CC
++])# _LT_TAG_COMPILER
++
++
++# _LT_COMPILER_BOILERPLATE
++# ------------------------
++# Check for compiler boilerplate output or warnings with
++# the simple compiler test code.
++m4_defun([_LT_COMPILER_BOILERPLATE],
++[m4_require([_LT_DECL_SED])dnl
++ac_outfile=conftest.$ac_objext
++echo "$lt_simple_compile_test_code" >conftest.$ac_ext
++eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
++_lt_compiler_boilerplate=`cat conftest.err`
++$RM conftest*
++])# _LT_COMPILER_BOILERPLATE
++
++
++# _LT_LINKER_BOILERPLATE
++# ----------------------
++# Check for linker boilerplate output or warnings with
++# the simple link test code.
++m4_defun([_LT_LINKER_BOILERPLATE],
++[m4_require([_LT_DECL_SED])dnl
++ac_outfile=conftest.$ac_objext
++echo "$lt_simple_link_test_code" >conftest.$ac_ext
++eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
++_lt_linker_boilerplate=`cat conftest.err`
++$RM -r conftest*
++])# _LT_LINKER_BOILERPLATE
++
++# _LT_REQUIRED_DARWIN_CHECKS
++# -------------------------
++m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
++ case $host_os in
++ rhapsody* | darwin*)
++ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
++ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
++ AC_CHECK_TOOL([LIPO], [lipo], [:])
++ AC_CHECK_TOOL([OTOOL], [otool], [:])
++ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
++ _LT_DECL([], [DSYMUTIL], [1],
++ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
++ _LT_DECL([], [NMEDIT], [1],
++ [Tool to change global to local symbols on Mac OS X])
++ _LT_DECL([], [LIPO], [1],
++ [Tool to manipulate fat objects and archives on Mac OS X])
++ _LT_DECL([], [OTOOL], [1],
++ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
++ _LT_DECL([], [OTOOL64], [1],
++ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
++
++ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
++ [lt_cv_apple_cc_single_mod=no
++ if test -z "${LT_MULTI_MODULE}"; then
++ # By default we will add the -single_module flag. You can override
++ # by either setting the environment variable LT_MULTI_MODULE
++ # non-empty at configure time, or by adding -multi_module to the
++ # link flags.
++ rm -rf libconftest.dylib*
++ echo "int foo(void){return 1;}" > conftest.c
++ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
++-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
++ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
++ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
++ _lt_result=$?
++ # If there is a non-empty error log, and "single_module"
++ # appears in it, assume the flag caused a linker warning
++ if test -s conftest.err && $GREP single_module conftest.err; then
++ cat conftest.err >&AS_MESSAGE_LOG_FD
++ # Otherwise, if the output was created with a 0 exit code from
++ # the compiler, it worked.
++ elif test -f libconftest.dylib && test $_lt_result -eq 0; then
++ lt_cv_apple_cc_single_mod=yes
++ else
++ cat conftest.err >&AS_MESSAGE_LOG_FD
++ fi
++ rm -rf libconftest.dylib*
++ rm -f conftest.*
++ fi])
++
++ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
++ [lt_cv_ld_exported_symbols_list],
++ [lt_cv_ld_exported_symbols_list=no
++ save_LDFLAGS=$LDFLAGS
++ echo "_main" > conftest.sym
++ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
++ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
++ [lt_cv_ld_exported_symbols_list=yes],
++ [lt_cv_ld_exported_symbols_list=no])
++ LDFLAGS="$save_LDFLAGS"
++ ])
++
++ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
++ [lt_cv_ld_force_load=no
++ cat > conftest.c << _LT_EOF
++int forced_loaded() { return 2;}
++_LT_EOF
++ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
++ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
++ echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
++ $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
++ echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
++ $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
++ cat > conftest.c << _LT_EOF
++int main() { return 0;}
++_LT_EOF
++ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
++ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
++ _lt_result=$?
++ if test -s conftest.err && $GREP force_load conftest.err; then
++ cat conftest.err >&AS_MESSAGE_LOG_FD
++ elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
++ lt_cv_ld_force_load=yes
++ else
++ cat conftest.err >&AS_MESSAGE_LOG_FD
++ fi
++ rm -f conftest.err libconftest.a conftest conftest.c
++ rm -rf conftest.dSYM
++ ])
++ case $host_os in
++ rhapsody* | darwin1.[[012]])
++ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
++ darwin1.*)
++ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
++ darwin*) # darwin 5.x on
++ # if running on 10.5 or later, the deployment target defaults
++ # to the OS version, if on x86, and 10.4, the deployment
++ # target defaults to 10.4. Don't you love it?
++ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
++ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
++ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
++ 10.[[012]]*)
++ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
++ 10.*)
++ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
++ esac
++ ;;
++ esac
++ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
++ _lt_dar_single_mod='$single_module'
++ fi
++ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
++ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
++ else
++ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
++ fi
++ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
++ _lt_dsymutil='~$DSYMUTIL $lib || :'
++ else
++ _lt_dsymutil=
++ fi
++ ;;
++ esac
++])
++
++
++# _LT_DARWIN_LINKER_FEATURES([TAG])
++# ---------------------------------
++# Checks for linker and compiler features on darwin
++m4_defun([_LT_DARWIN_LINKER_FEATURES],
++[
++ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++ _LT_TAGVAR(hardcode_direct, $1)=no
++ _LT_TAGVAR(hardcode_automatic, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++ if test "$lt_cv_ld_force_load" = "yes"; then
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
++ m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
++ [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
++ else
++ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
++ fi
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
++ case $cc_basename in
++ ifort*) _lt_dar_can_shared=yes ;;
++ *) _lt_dar_can_shared=$GCC ;;
++ esac
++ if test "$_lt_dar_can_shared" = "yes"; then
++ output_verbose_link_cmd=func_echo_all
++ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
++ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
++ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
++ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
++ m4_if([$1], [CXX],
++[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
++ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
++ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
++ fi
++],[])
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++])
++
++# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
++# ----------------------------------
++# Links a minimal program and checks the executable
++# for the system default hardcoded library path. In most cases,
++# this is /usr/lib:/lib, but when the MPI compilers are used
++# the location of the communication and MPI libs are included too.
++# If we don't find anything, use the default library path according
++# to the aix ld manual.
++# Store the results from the different compilers for each TAGNAME.
++# Allow to override them for all tags through lt_cv_aix_libpath.
++m4_defun([_LT_SYS_MODULE_PATH_AIX],
++[m4_require([_LT_DECL_SED])dnl
++if test "${lt_cv_aix_libpath+set}" = set; then
++ aix_libpath=$lt_cv_aix_libpath
++else
++ AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
++ [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
++ lt_aix_libpath_sed='[
++ /Import File Strings/,/^$/ {
++ /^0/ {
++ s/^0 *\([^ ]*\) *$/\1/
++ p
++ }
++ }]'
++ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++ # Check for a 64-bit object if we didn't find anything.
++ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
++ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
++ fi],[])
++ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
++ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
++ fi
++ ])
++ aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
++fi
++])# _LT_SYS_MODULE_PATH_AIX
++
++
++# _LT_SHELL_INIT(ARG)
++# -------------------
++m4_define([_LT_SHELL_INIT],
++[m4_divert_text([M4SH-INIT], [$1
++])])# _LT_SHELL_INIT
++
++
++
++# _LT_PROG_ECHO_BACKSLASH
++# -----------------------
++# Find how we can fake an echo command that does not interpret backslash.
++# In particular, with Autoconf 2.60 or later we add some code to the start
++# of the generated configure script which will find a shell with a builtin
++# printf (which we can use as an echo command).
++m4_defun([_LT_PROG_ECHO_BACKSLASH],
++[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
++ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
++
++AC_MSG_CHECKING([how to print strings])
++# Test print first, because it will be a builtin if present.
++if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
++ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
++ ECHO='print -r --'
++elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
++ ECHO='printf %s\n'
++else
++ # Use this function as a fallback that always works.
++ func_fallback_echo ()
++ {
++ eval 'cat <<_LTECHO_EOF
++$[]1
++_LTECHO_EOF'
++ }
++ ECHO='func_fallback_echo'
++fi
++
++# func_echo_all arg...
++# Invoke $ECHO with all args, space-separated.
++func_echo_all ()
++{
++ $ECHO "$*"
++}
++
++case "$ECHO" in
++ printf*) AC_MSG_RESULT([printf]) ;;
++ print*) AC_MSG_RESULT([print -r]) ;;
++ *) AC_MSG_RESULT([cat]) ;;
++esac
++
++m4_ifdef([_AS_DETECT_SUGGESTED],
++[_AS_DETECT_SUGGESTED([
++ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
++ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
++ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
++ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
++ PATH=/empty FPATH=/empty; export PATH FPATH
++ test "X`printf %s $ECHO`" = "X$ECHO" \
++ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
++
++_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
++_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
++])# _LT_PROG_ECHO_BACKSLASH
++
++
++# _LT_WITH_SYSROOT
++# ----------------
++AC_DEFUN([_LT_WITH_SYSROOT],
++[AC_MSG_CHECKING([for sysroot])
++AC_ARG_WITH([sysroot],
++[ --with-sysroot[=DIR] Search for dependent libraries within DIR
++ (or the compiler's sysroot if not specified).],
++[], [with_sysroot=no])
++
++dnl lt_sysroot will always be passed unquoted. We quote it here
++dnl in case the user passed a directory name.
++lt_sysroot=
++case ${with_sysroot} in #(
++ yes)
++ if test "$GCC" = yes; then
++ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
++ fi
++ ;; #(
++ /*)
++ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
++ ;; #(
++ no|'')
++ ;; #(
++ *)
++ AC_MSG_RESULT([${with_sysroot}])
++ AC_MSG_ERROR([The sysroot must be an absolute path.])
++ ;;
++esac
++
++ AC_MSG_RESULT([${lt_sysroot:-no}])
++_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
++[dependent libraries, and in which our libraries should be installed.])])
++
++# _LT_ENABLE_LOCK
++# ---------------
++m4_defun([_LT_ENABLE_LOCK],
++[AC_ARG_ENABLE([libtool-lock],
++ [AS_HELP_STRING([--disable-libtool-lock],
++ [avoid locking (might break parallel builds)])])
++test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
++
++# Some flags need to be propagated to the compiler or linker for good
++# libtool support.
++case $host in
++ia64-*-hpux*)
++ # Find out which ABI we are using.
++ echo 'int i;' > conftest.$ac_ext
++ if AC_TRY_EVAL(ac_compile); then
++ case `/usr/bin/file conftest.$ac_objext` in
++ *ELF-32*)
++ HPUX_IA64_MODE="32"
++ ;;
++ *ELF-64*)
++ HPUX_IA64_MODE="64"
++ ;;
++ esac
++ fi
++ rm -rf conftest*
++ ;;
++*-*-irix6*)
++ # Find out which ABI we are using.
++ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
++ if AC_TRY_EVAL(ac_compile); then
++ if test "$lt_cv_prog_gnu_ld" = yes; then
++ case `/usr/bin/file conftest.$ac_objext` in
++ *32-bit*)
++ LD="${LD-ld} -melf32bsmip"
++ ;;
++ *N32*)
++ LD="${LD-ld} -melf32bmipn32"
++ ;;
++ *64-bit*)
++ LD="${LD-ld} -melf64bmip"
++ ;;
++ esac
++ else
++ case `/usr/bin/file conftest.$ac_objext` in
++ *32-bit*)
++ LD="${LD-ld} -32"
++ ;;
++ *N32*)
++ LD="${LD-ld} -n32"
++ ;;
++ *64-bit*)
++ LD="${LD-ld} -64"
++ ;;
++ esac
++ fi
++ fi
++ rm -rf conftest*
++ ;;
++
++x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
++s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
++ # Find out which ABI we are using.
++ echo 'int i;' > conftest.$ac_ext
++ if AC_TRY_EVAL(ac_compile); then
++ case `/usr/bin/file conftest.o` in
++ *32-bit*)
++ case $host in
++ x86_64-*kfreebsd*-gnu)
++ LD="${LD-ld} -m elf_i386_fbsd"
++ ;;
++ x86_64-*linux*)
++ case `/usr/bin/file conftest.o` in
++ *x86-64*)
++ LD="${LD-ld} -m elf32_x86_64"
++ ;;
++ *)
++ LD="${LD-ld} -m elf_i386"
++ ;;
++ esac
++ ;;
++ ppc64-*linux*|powerpc64-*linux*)
++ LD="${LD-ld} -m elf32ppclinux"
++ ;;
++ s390x-*linux*)
++ LD="${LD-ld} -m elf_s390"
++ ;;
++ sparc64-*linux*)
++ LD="${LD-ld} -m elf32_sparc"
++ ;;
++ esac
++ ;;
++ *64-bit*)
++ case $host in
++ x86_64-*kfreebsd*-gnu)
++ LD="${LD-ld} -m elf_x86_64_fbsd"
++ ;;
++ x86_64-*linux*)
++ LD="${LD-ld} -m elf_x86_64"
++ ;;
++ ppc*-*linux*|powerpc*-*linux*)
++ LD="${LD-ld} -m elf64ppc"
++ ;;
++ s390*-*linux*|s390*-*tpf*)
++ LD="${LD-ld} -m elf64_s390"
++ ;;
++ sparc*-*linux*)
++ LD="${LD-ld} -m elf64_sparc"
++ ;;
++ esac
++ ;;
++ esac
++ fi
++ rm -rf conftest*
++ ;;
++
++*-*-sco3.2v5*)
++ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
++ SAVE_CFLAGS="$CFLAGS"
++ CFLAGS="$CFLAGS -belf"
++ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
++ [AC_LANG_PUSH(C)
++ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
++ AC_LANG_POP])
++ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
++ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
++ CFLAGS="$SAVE_CFLAGS"
++ fi
++ ;;
++*-*solaris*)
++ # Find out which ABI we are using.
++ echo 'int i;' > conftest.$ac_ext
++ if AC_TRY_EVAL(ac_compile); then
++ case `/usr/bin/file conftest.o` in
++ *64-bit*)
++ case $lt_cv_prog_gnu_ld in
++ yes*)
++ case $host in
++ i?86-*-solaris*)
++ LD="${LD-ld} -m elf_x86_64"
++ ;;
++ sparc*-*-solaris*)
++ LD="${LD-ld} -m elf64_sparc"
++ ;;
++ esac
++ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
++ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
++ LD="${LD-ld}_sol2"
++ fi
++ ;;
++ *)
++ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
++ LD="${LD-ld} -64"
++ fi
++ ;;
++ esac
++ ;;
++ esac
++ fi
++ rm -rf conftest*
++ ;;
++esac
++
++need_locks="$enable_libtool_lock"
++])# _LT_ENABLE_LOCK
++
++
++# _LT_PROG_AR
++# -----------
++m4_defun([_LT_PROG_AR],
++[AC_CHECK_TOOLS(AR, [ar], false)
++: ${AR=ar}
++: ${AR_FLAGS=cru}
++_LT_DECL([], [AR], [1], [The archiver])
++_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
++
++AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
++ [lt_cv_ar_at_file=no
++ AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
++ [echo conftest.$ac_objext > conftest.lst
++ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
++ AC_TRY_EVAL([lt_ar_try])
++ if test "$ac_status" -eq 0; then
++ # Ensure the archiver fails upon bogus file names.
++ rm -f conftest.$ac_objext libconftest.a
++ AC_TRY_EVAL([lt_ar_try])
++ if test "$ac_status" -ne 0; then
++ lt_cv_ar_at_file=@
++ fi
++ fi
++ rm -f conftest.* libconftest.a
++ ])
++ ])
++
++if test "x$lt_cv_ar_at_file" = xno; then
++ archiver_list_spec=
++else
++ archiver_list_spec=$lt_cv_ar_at_file
++fi
++_LT_DECL([], [archiver_list_spec], [1],
++ [How to feed a file listing to the archiver])
++])# _LT_PROG_AR
++
++
++# _LT_CMD_OLD_ARCHIVE
++# -------------------
++m4_defun([_LT_CMD_OLD_ARCHIVE],
++[_LT_PROG_AR
++
++AC_CHECK_TOOL(STRIP, strip, :)
++test -z "$STRIP" && STRIP=:
++_LT_DECL([], [STRIP], [1], [A symbol stripping program])
++
++AC_CHECK_TOOL(RANLIB, ranlib, :)
++test -z "$RANLIB" && RANLIB=:
++_LT_DECL([], [RANLIB], [1],
++ [Commands used to install an old-style archive])
++
++# Determine commands to create old-style static archives.
++old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
++old_postinstall_cmds='chmod 644 $oldlib'
++old_postuninstall_cmds=
++
++if test -n "$RANLIB"; then
++ case $host_os in
++ openbsd*)
++ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
++ ;;
++ *)
++ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
++ ;;
++ esac
++ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
++fi
++
++case $host_os in
++ darwin*)
++ lock_old_archive_extraction=yes ;;
++ *)
++ lock_old_archive_extraction=no ;;
++esac
++_LT_DECL([], [old_postinstall_cmds], [2])
++_LT_DECL([], [old_postuninstall_cmds], [2])
++_LT_TAGDECL([], [old_archive_cmds], [2],
++ [Commands used to build an old-style archive])
++_LT_DECL([], [lock_old_archive_extraction], [0],
++ [Whether to use a lock for old archive extraction])
++])# _LT_CMD_OLD_ARCHIVE
++
++
++# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
++# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
++# ----------------------------------------------------------------
++# Check whether the given compiler option works
++AC_DEFUN([_LT_COMPILER_OPTION],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_SED])dnl
++AC_CACHE_CHECK([$1], [$2],
++ [$2=no
++ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++ lt_compiler_flag="$3"
++ # Insert the option either (1) after the last *FLAGS variable, or
++ # (2) before a word containing "conftest.", or (3) at the end.
++ # Note that $ac_compile itself does not contain backslashes and begins
++ # with a dollar sign (not a hyphen), so the echo should work correctly.
++ # The option is referenced via a variable to avoid confusing sed.
++ lt_compile=`echo "$ac_compile" | $SED \
++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
++ -e 's:$: $lt_compiler_flag:'`
++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
++ (eval "$lt_compile" 2>conftest.err)
++ ac_status=$?
++ cat conftest.err >&AS_MESSAGE_LOG_FD
++ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
++ if (exit $ac_status) && test -s "$ac_outfile"; then
++ # The compiler can only warn and ignore the option if not recognized
++ # So say no if there are warnings other than the usual output.
++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
++ $2=yes
++ fi
++ fi
++ $RM conftest*
++])
++
++if test x"[$]$2" = xyes; then
++ m4_if([$5], , :, [$5])
++else
++ m4_if([$6], , :, [$6])
++fi
++])# _LT_COMPILER_OPTION
++
++# Old name:
++AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
++
++
++# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
++# [ACTION-SUCCESS], [ACTION-FAILURE])
++# ----------------------------------------------------
++# Check whether the given linker option works
++AC_DEFUN([_LT_LINKER_OPTION],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_SED])dnl
++AC_CACHE_CHECK([$1], [$2],
++ [$2=no
++ save_LDFLAGS="$LDFLAGS"
++ LDFLAGS="$LDFLAGS $3"
++ echo "$lt_simple_link_test_code" > conftest.$ac_ext
++ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
++ # The linker can only warn and ignore the option if not recognized
++ # So say no if there are warnings
++ if test -s conftest.err; then
++ # Append any errors to the config.log.
++ cat conftest.err 1>&AS_MESSAGE_LOG_FD
++ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
++ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
++ if diff conftest.exp conftest.er2 >/dev/null; then
++ $2=yes
++ fi
++ else
++ $2=yes
++ fi
++ fi
++ $RM -r conftest*
++ LDFLAGS="$save_LDFLAGS"
++])
++
++if test x"[$]$2" = xyes; then
++ m4_if([$4], , :, [$4])
++else
++ m4_if([$5], , :, [$5])
++fi
++])# _LT_LINKER_OPTION
++
++# Old name:
++AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
++
++
++# LT_CMD_MAX_LEN
++#---------------
++AC_DEFUN([LT_CMD_MAX_LEN],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++# find the maximum length of command line arguments
++AC_MSG_CHECKING([the maximum length of command line arguments])
++AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
++ i=0
++ teststring="ABCD"
++
++ case $build_os in
++ msdosdjgpp*)
++ # On DJGPP, this test can blow up pretty badly due to problems in libc
++ # (any single argument exceeding 2000 bytes causes a buffer overrun
++ # during glob expansion). Even if it were fixed, the result of this
++ # check would be larger than it should be.
++ lt_cv_sys_max_cmd_len=12288; # 12K is about right
++ ;;
++
++ gnu*)
++ # Under GNU Hurd, this test is not required because there is
++ # no limit to the length of command line arguments.
++ # Libtool will interpret -1 as no limit whatsoever
++ lt_cv_sys_max_cmd_len=-1;
++ ;;
++
++ cygwin* | mingw* | cegcc*)
++ # On Win9x/ME, this test blows up -- it succeeds, but takes
++ # about 5 minutes as the teststring grows exponentially.
++ # Worse, since 9x/ME are not pre-emptively multitasking,
++ # you end up with a "frozen" computer, even though with patience
++ # the test eventually succeeds (with a max line length of 256k).
++ # Instead, let's just punt: use the minimum linelength reported by
++ # all of the supported platforms: 8192 (on NT/2K/XP).
++ lt_cv_sys_max_cmd_len=8192;
++ ;;
++
++ mint*)
++ # On MiNT this can take a long time and run out of memory.
++ lt_cv_sys_max_cmd_len=8192;
++ ;;
++
++ amigaos*)
++ # On AmigaOS with pdksh, this test takes hours, literally.
++ # So we just punt and use a minimum line length of 8192.
++ lt_cv_sys_max_cmd_len=8192;
++ ;;
++
++ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
++ # This has been around since 386BSD, at least. Likely further.
++ if test -x /sbin/sysctl; then
++ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
++ elif test -x /usr/sbin/sysctl; then
++ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
++ else
++ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
++ fi
++ # And add a safety zone
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
++ ;;
++
++ interix*)
++ # We know the value 262144 and hardcode it with a safety zone (like BSD)
++ lt_cv_sys_max_cmd_len=196608
++ ;;
++
++ os2*)
++ # The test takes a long time on OS/2.
++ lt_cv_sys_max_cmd_len=8192
++ ;;
++
++ osf*)
++ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
++ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
++ # nice to cause kernel panics so lets avoid the loop below.
++ # First set a reasonable default.
++ lt_cv_sys_max_cmd_len=16384
++ #
++ if test -x /sbin/sysconfig; then
++ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
++ *1*) lt_cv_sys_max_cmd_len=-1 ;;
++ esac
++ fi
++ ;;
++ sco3.2v5*)
++ lt_cv_sys_max_cmd_len=102400
++ ;;
++ sysv5* | sco5v6* | sysv4.2uw2*)
++ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
++ if test -n "$kargmax"; then
++ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
++ else
++ lt_cv_sys_max_cmd_len=32768
++ fi
++ ;;
++ *)
++ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
++ if test -n "$lt_cv_sys_max_cmd_len" && \
++ test undefined != "$lt_cv_sys_max_cmd_len"; then
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
++ else
++ # Make teststring a little bigger before we do anything with it.
++ # a 1K string should be a reasonable start.
++ for i in 1 2 3 4 5 6 7 8 ; do
++ teststring=$teststring$teststring
++ done
++ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
++ # If test is not a shell built-in, we'll probably end up computing a
++ # maximum length that is only half of the actual maximum length, but
++ # we can't tell.
++ while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
++ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
++ test $i != 17 # 1/2 MB should be enough
++ do
++ i=`expr $i + 1`
++ teststring=$teststring$teststring
++ done
++ # Only check the string length outside the loop.
++ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
++ teststring=
++ # Add a significant safety factor because C++ compilers can tack on
++ # massive amounts of additional arguments before passing them to the
++ # linker. It appears as though 1/2 is a usable value.
++ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
++ fi
++ ;;
++ esac
++])
++if test -n $lt_cv_sys_max_cmd_len ; then
++ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
++else
++ AC_MSG_RESULT(none)
++fi
++max_cmd_len=$lt_cv_sys_max_cmd_len
++_LT_DECL([], [max_cmd_len], [0],
++ [What is the maximum length of a command?])
++])# LT_CMD_MAX_LEN
++
++# Old name:
++AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
++
++
++# _LT_HEADER_DLFCN
++# ----------------
++m4_defun([_LT_HEADER_DLFCN],
++[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
++])# _LT_HEADER_DLFCN
++
++
++# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
++# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
++# ----------------------------------------------------------------
++m4_defun([_LT_TRY_DLOPEN_SELF],
++[m4_require([_LT_HEADER_DLFCN])dnl
++if test "$cross_compiling" = yes; then :
++ [$4]
++else
++ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
++ lt_status=$lt_dlunknown
++ cat > conftest.$ac_ext <<_LT_EOF
++[#line $LINENO "configure"
++#include "confdefs.h"
++
++#if HAVE_DLFCN_H
++#include <dlfcn.h>
++#endif
++
++#include <stdio.h>
++
++#ifdef RTLD_GLOBAL
++# define LT_DLGLOBAL RTLD_GLOBAL
++#else
++# ifdef DL_GLOBAL
++# define LT_DLGLOBAL DL_GLOBAL
++# else
++# define LT_DLGLOBAL 0
++# endif
++#endif
++
++/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
++ find out it does not work in some platform. */
++#ifndef LT_DLLAZY_OR_NOW
++# ifdef RTLD_LAZY
++# define LT_DLLAZY_OR_NOW RTLD_LAZY
++# else
++# ifdef DL_LAZY
++# define LT_DLLAZY_OR_NOW DL_LAZY
++# else
++# ifdef RTLD_NOW
++# define LT_DLLAZY_OR_NOW RTLD_NOW
++# else
++# ifdef DL_NOW
++# define LT_DLLAZY_OR_NOW DL_NOW
++# else
++# define LT_DLLAZY_OR_NOW 0
++# endif
++# endif
++# endif
++# endif
++#endif
++
++/* When -fvisbility=hidden is used, assume the code has been annotated
++ correspondingly for the symbols needed. */
++#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
++int fnord () __attribute__((visibility("default")));
++#endif
++
++int fnord () { return 42; }
++int main ()
++{
++ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
++ int status = $lt_dlunknown;
++
++ if (self)
++ {
++ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
++ else
++ {
++ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
++ else puts (dlerror ());
++ }
++ /* dlclose (self); */
++ }
++ else
++ puts (dlerror ());
++
++ return status;
++}]
++_LT_EOF
++ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
++ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
++ lt_status=$?
++ case x$lt_status in
++ x$lt_dlno_uscore) $1 ;;
++ x$lt_dlneed_uscore) $2 ;;
++ x$lt_dlunknown|x*) $3 ;;
++ esac
++ else :
++ # compilation failed
++ $3
++ fi
++fi
++rm -fr conftest*
++])# _LT_TRY_DLOPEN_SELF
++
++
++# LT_SYS_DLOPEN_SELF
++# ------------------
++AC_DEFUN([LT_SYS_DLOPEN_SELF],
++[m4_require([_LT_HEADER_DLFCN])dnl
++if test "x$enable_dlopen" != xyes; then
++ enable_dlopen=unknown
++ enable_dlopen_self=unknown
++ enable_dlopen_self_static=unknown
++else
++ lt_cv_dlopen=no
++ lt_cv_dlopen_libs=
++
++ case $host_os in
++ beos*)
++ lt_cv_dlopen="load_add_on"
++ lt_cv_dlopen_libs=
++ lt_cv_dlopen_self=yes
++ ;;
++
++ mingw* | pw32* | cegcc*)
++ lt_cv_dlopen="LoadLibrary"
++ lt_cv_dlopen_libs=
++ ;;
++
++ cygwin*)
++ lt_cv_dlopen="dlopen"
++ lt_cv_dlopen_libs=
++ ;;
++
++ darwin*)
++ # if libdl is installed we need to link against it
++ AC_CHECK_LIB([dl], [dlopen],
++ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
++ lt_cv_dlopen="dyld"
++ lt_cv_dlopen_libs=
++ lt_cv_dlopen_self=yes
++ ])
++ ;;
++
++ *)
++ AC_CHECK_FUNC([shl_load],
++ [lt_cv_dlopen="shl_load"],
++ [AC_CHECK_LIB([dld], [shl_load],
++ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
++ [AC_CHECK_FUNC([dlopen],
++ [lt_cv_dlopen="dlopen"],
++ [AC_CHECK_LIB([dl], [dlopen],
++ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
++ [AC_CHECK_LIB([svld], [dlopen],
++ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
++ [AC_CHECK_LIB([dld], [dld_link],
++ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
++ ])
++ ])
++ ])
++ ])
++ ])
++ ;;
++ esac
++
++ if test "x$lt_cv_dlopen" != xno; then
++ enable_dlopen=yes
++ else
++ enable_dlopen=no
++ fi
++
++ case $lt_cv_dlopen in
++ dlopen)
++ save_CPPFLAGS="$CPPFLAGS"
++ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
++
++ save_LDFLAGS="$LDFLAGS"
++ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
++
++ save_LIBS="$LIBS"
++ LIBS="$lt_cv_dlopen_libs $LIBS"
++
++ AC_CACHE_CHECK([whether a program can dlopen itself],
++ lt_cv_dlopen_self, [dnl
++ _LT_TRY_DLOPEN_SELF(
++ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
++ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
++ ])
++
++ if test "x$lt_cv_dlopen_self" = xyes; then
++ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
++ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
++ lt_cv_dlopen_self_static, [dnl
++ _LT_TRY_DLOPEN_SELF(
++ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
++ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
++ ])
++ fi
++
++ CPPFLAGS="$save_CPPFLAGS"
++ LDFLAGS="$save_LDFLAGS"
++ LIBS="$save_LIBS"
++ ;;
++ esac
++
++ case $lt_cv_dlopen_self in
++ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
++ *) enable_dlopen_self=unknown ;;
++ esac
++
++ case $lt_cv_dlopen_self_static in
++ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
++ *) enable_dlopen_self_static=unknown ;;
++ esac
++fi
++_LT_DECL([dlopen_support], [enable_dlopen], [0],
++ [Whether dlopen is supported])
++_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
++ [Whether dlopen of programs is supported])
++_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
++ [Whether dlopen of statically linked programs is supported])
++])# LT_SYS_DLOPEN_SELF
++
++# Old name:
++AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
++
++
++# _LT_COMPILER_C_O([TAGNAME])
++# ---------------------------
++# Check to see if options -c and -o are simultaneously supported by compiler.
++# This macro does not hard code the compiler like AC_PROG_CC_C_O.
++m4_defun([_LT_COMPILER_C_O],
++[m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
++ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
++ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
++ $RM -r conftest 2>/dev/null
++ mkdir conftest
++ cd conftest
++ mkdir out
++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++
++ lt_compiler_flag="-o out/conftest2.$ac_objext"
++ # Insert the option either (1) after the last *FLAGS variable, or
++ # (2) before a word containing "conftest.", or (3) at the end.
++ # Note that $ac_compile itself does not contain backslashes and begins
++ # with a dollar sign (not a hyphen), so the echo should work correctly.
++ lt_compile=`echo "$ac_compile" | $SED \
++ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
++ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
++ -e 's:$: $lt_compiler_flag:'`
++ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
++ (eval "$lt_compile" 2>out/conftest.err)
++ ac_status=$?
++ cat out/conftest.err >&AS_MESSAGE_LOG_FD
++ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
++ if (exit $ac_status) && test -s out/conftest2.$ac_objext
++ then
++ # The compiler can only warn and ignore the option if not recognized
++ # So say no if there are warnings
++ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
++ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
++ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
++ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
++ fi
++ fi
++ chmod u+w . 2>&AS_MESSAGE_LOG_FD
++ $RM conftest*
++ # SGI C++ compiler will create directory out/ii_files/ for
++ # template instantiation
++ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
++ $RM out/* && rmdir out
++ cd ..
++ $RM -r conftest
++ $RM conftest*
++])
++_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
++ [Does compiler simultaneously support -c and -o options?])
++])# _LT_COMPILER_C_O
++
++
++# _LT_COMPILER_FILE_LOCKS([TAGNAME])
++# ----------------------------------
++# Check to see if we can do hard links to lock some files if needed
++m4_defun([_LT_COMPILER_FILE_LOCKS],
++[m4_require([_LT_ENABLE_LOCK])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++_LT_COMPILER_C_O([$1])
++
++hard_links="nottested"
++if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
++ # do not overwrite the value of need_locks provided by the user
++ AC_MSG_CHECKING([if we can lock with hard links])
++ hard_links=yes
++ $RM conftest*
++ ln conftest.a conftest.b 2>/dev/null && hard_links=no
++ touch conftest.a
++ ln conftest.a conftest.b 2>&5 || hard_links=no
++ ln conftest.a conftest.b 2>/dev/null && hard_links=no
++ AC_MSG_RESULT([$hard_links])
++ if test "$hard_links" = no; then
++ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
++ need_locks=warn
++ fi
++else
++ need_locks=no
++fi
++_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
++])# _LT_COMPILER_FILE_LOCKS
++
++
++# _LT_CHECK_OBJDIR
++# ----------------
++m4_defun([_LT_CHECK_OBJDIR],
++[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
++[rm -f .libs 2>/dev/null
++mkdir .libs 2>/dev/null
++if test -d .libs; then
++ lt_cv_objdir=.libs
++else
++ # MS-DOS does not allow filenames that begin with a dot.
++ lt_cv_objdir=_libs
++fi
++rmdir .libs 2>/dev/null])
++objdir=$lt_cv_objdir
++_LT_DECL([], [objdir], [0],
++ [The name of the directory that contains temporary libtool files])dnl
++m4_pattern_allow([LT_OBJDIR])dnl
++AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
++ [Define to the sub-directory in which libtool stores uninstalled libraries.])
++])# _LT_CHECK_OBJDIR
++
++
++# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
++# --------------------------------------
++# Check hardcoding attributes.
++m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
++[AC_MSG_CHECKING([how to hardcode library paths into programs])
++_LT_TAGVAR(hardcode_action, $1)=
++if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
++ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
++ test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
++
++ # We can hardcode non-existent directories.
++ if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
++ # If the only mechanism to avoid hardcoding is shlibpath_var, we
++ # have to relink, otherwise we might link with an installed library
++ # when we should be linking with a yet-to-be-installed one
++ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
++ test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
++ # Linking always hardcodes the temporary library directory.
++ _LT_TAGVAR(hardcode_action, $1)=relink
++ else
++ # We can link without hardcoding, and we can hardcode nonexisting dirs.
++ _LT_TAGVAR(hardcode_action, $1)=immediate
++ fi
++else
++ # We cannot hardcode anything, or else we can only hardcode existing
++ # directories.
++ _LT_TAGVAR(hardcode_action, $1)=unsupported
++fi
++AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
++
++if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
++ test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
++ # Fast installation is not supported
++ enable_fast_install=no
++elif test "$shlibpath_overrides_runpath" = yes ||
++ test "$enable_shared" = no; then
++ # Fast installation is not necessary
++ enable_fast_install=needless
++fi
++_LT_TAGDECL([], [hardcode_action], [0],
++ [How to hardcode a shared library path into an executable])
++])# _LT_LINKER_HARDCODE_LIBPATH
++
++
++# _LT_CMD_STRIPLIB
++# ----------------
++m4_defun([_LT_CMD_STRIPLIB],
++[m4_require([_LT_DECL_EGREP])
++striplib=
++old_striplib=
++AC_MSG_CHECKING([whether stripping libraries is possible])
++if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
++ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
++ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
++ AC_MSG_RESULT([yes])
++else
++# FIXME - insert some real tests, host_os isn't really good enough
++ case $host_os in
++ darwin*)
++ if test -n "$STRIP" ; then
++ striplib="$STRIP -x"
++ old_striplib="$STRIP -S"
++ AC_MSG_RESULT([yes])
++ else
++ AC_MSG_RESULT([no])
++ fi
++ ;;
++ *)
++ AC_MSG_RESULT([no])
++ ;;
++ esac
++fi
++_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
++_LT_DECL([], [striplib], [1])
++])# _LT_CMD_STRIPLIB
++
++
++# _LT_SYS_DYNAMIC_LINKER([TAG])
++# -----------------------------
++# PORTME Fill in your ld.so characteristics
++m4_defun([_LT_SYS_DYNAMIC_LINKER],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_OBJDUMP])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_CHECK_SHELL_FEATURES])dnl
++AC_MSG_CHECKING([dynamic linker characteristics])
++m4_if([$1],
++ [], [
++if test "$GCC" = yes; then
++ case $host_os in
++ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
++ *) lt_awk_arg="/^libraries:/" ;;
++ esac
++ case $host_os in
++ mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
++ *) lt_sed_strip_eq="s,=/,/,g" ;;
++ esac
++ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
++ case $lt_search_path_spec in
++ *\;*)
++ # if the path contains ";" then we assume it to be the separator
++ # otherwise default to the standard path separator (i.e. ":") - it is
++ # assumed that no part of a normal pathname contains ";" but that should
++ # okay in the real world where ";" in dirpaths is itself problematic.
++ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
++ ;;
++ *)
++ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
++ ;;
++ esac
++ # Ok, now we have the path, separated by spaces, we can step through it
++ # and add multilib dir if necessary.
++ lt_tmp_lt_search_path_spec=
++ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
++ for lt_sys_path in $lt_search_path_spec; do
++ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
++ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
++ else
++ test -d "$lt_sys_path" && \
++ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
++ fi
++ done
++ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
++BEGIN {RS=" "; FS="/|\n";} {
++ lt_foo="";
++ lt_count=0;
++ for (lt_i = NF; lt_i > 0; lt_i--) {
++ if ($lt_i != "" && $lt_i != ".") {
++ if ($lt_i == "..") {
++ lt_count++;
++ } else {
++ if (lt_count == 0) {
++ lt_foo="/" $lt_i lt_foo;
++ } else {
++ lt_count--;
++ }
++ }
++ }
++ }
++ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
++ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
++}'`
++ # AWK program above erroneously prepends '/' to C:/dos/paths
++ # for these hosts.
++ case $host_os in
++ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
++ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
++ esac
++ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
++else
++ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
++fi])
++library_names_spec=
++libname_spec='lib$name'
++soname_spec=
++shrext_cmds=".so"
++postinstall_cmds=
++postuninstall_cmds=
++finish_cmds=
++finish_eval=
++shlibpath_var=
++shlibpath_overrides_runpath=unknown
++version_type=none
++dynamic_linker="$host_os ld.so"
++sys_lib_dlsearch_path_spec="/lib /usr/lib"
++need_lib_prefix=unknown
++hardcode_into_libs=no
++
++# when you set need_version to no, make sure it does not cause -set_version
++# flags to be left without arguments
++need_version=unknown
++
++case $host_os in
++aix3*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
++ shlibpath_var=LIBPATH
++
++ # AIX 3 has no versioning support, so we append a major version to the name.
++ soname_spec='${libname}${release}${shared_ext}$major'
++ ;;
++
++aix[[4-9]]*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ hardcode_into_libs=yes
++ if test "$host_cpu" = ia64; then
++ # AIX 5 supports IA64
++ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
++ shlibpath_var=LD_LIBRARY_PATH
++ else
++ # With GCC up to 2.95.x, collect2 would create an import file
++ # for dependence libraries. The import file would start with
++ # the line `#! .'. This would cause the generated library to
++ # depend on `.', always an invalid library. This was fixed in
++ # development snapshots of GCC prior to 3.0.
++ case $host_os in
++ aix4 | aix4.[[01]] | aix4.[[01]].*)
++ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
++ echo ' yes '
++ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
++ :
++ else
++ can_build_shared=no
++ fi
++ ;;
++ esac
++ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
++ # soname into executable. Probably we can add versioning support to
++ # collect2, so additional links can be useful in future.
++ if test "$aix_use_runtimelinking" = yes; then
++ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
++ # instead of lib<name>.a to let people know that these are not
++ # typical AIX shared libraries.
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ else
++ # We preserve .a as extension for shared libraries through AIX4.2
++ # and later when we are not doing run time linking.
++ library_names_spec='${libname}${release}.a $libname.a'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ fi
++ shlibpath_var=LIBPATH
++ fi
++ ;;
++
++amigaos*)
++ case $host_cpu in
++ powerpc)
++ # Since July 2007 AmigaOS4 officially supports .so libraries.
++ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ ;;
++ m68k)
++ library_names_spec='$libname.ixlibrary $libname.a'
++ # Create ${libname}_ixlibrary.a entries in /sys/libs.
++ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
++ ;;
++ esac
++ ;;
++
++beos*)
++ library_names_spec='${libname}${shared_ext}'
++ dynamic_linker="$host_os ld.so"
++ shlibpath_var=LIBRARY_PATH
++ ;;
++
++bsdi[[45]]*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
++ shlibpath_var=LD_LIBRARY_PATH
++ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
++ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
++ # the default ld.so.conf also contains /usr/contrib/lib and
++ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
++ # libtool to hard-code these into programs
++ ;;
++
++cygwin* | mingw* | pw32* | cegcc*)
++ version_type=windows
++ shrext_cmds=".dll"
++ need_version=no
++ need_lib_prefix=no
++
++ case $GCC,$cc_basename in
++ yes,*)
++ # gcc
++ library_names_spec='$libname.dll.a'
++ # DLL is installed to $(libdir)/../bin by postinstall_cmds
++ postinstall_cmds='base_file=`basename \${file}`~
++ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
++ dldir=$destdir/`dirname \$dlpath`~
++ test -d \$dldir || mkdir -p \$dldir~
++ $install_prog $dir/$dlname \$dldir/$dlname~
++ chmod a+x \$dldir/$dlname~
++ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
++ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
++ fi'
++ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
++ dlpath=$dir/\$dldll~
++ $RM \$dlpath'
++ shlibpath_overrides_runpath=yes
++
++ case $host_os in
++ cygwin*)
++ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
++ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
++m4_if([$1], [],[
++ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
++ ;;
++ mingw* | cegcc*)
++ # MinGW DLLs use traditional 'lib' prefix
++ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
++ ;;
++ pw32*)
++ # pw32 DLLs use 'pw' prefix rather than 'lib'
++ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
++ ;;
++ esac
++ dynamic_linker='Win32 ld.exe'
++ ;;
++
++ *,cl*)
++ # Native MSVC
++ libname_spec='$name'
++ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
++ library_names_spec='${libname}.dll.lib'
++
++ case $build_os in
++ mingw*)
++ sys_lib_search_path_spec=
++ lt_save_ifs=$IFS
++ IFS=';'
++ for lt_path in $LIB
++ do
++ IFS=$lt_save_ifs
++ # Let DOS variable expansion print the short 8.3 style file name.
++ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
++ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
++ done
++ IFS=$lt_save_ifs
++ # Convert to MSYS style.
++ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
++ ;;
++ cygwin*)
++ # Convert to unix form, then to dos form, then back to unix form
++ # but this time dos style (no spaces!) so that the unix form looks
++ # like /cygdrive/c/PROGRA~1:/cygdr...
++ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
++ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
++ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
++ ;;
++ *)
++ sys_lib_search_path_spec="$LIB"
++ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
++ # It is most probably a Windows format PATH.
++ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
++ else
++ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
++ fi
++ # FIXME: find the short name or the path components, as spaces are
++ # common. (e.g. "Program Files" -> "PROGRA~1")
++ ;;
++ esac
++
++ # DLL is installed to $(libdir)/../bin by postinstall_cmds
++ postinstall_cmds='base_file=`basename \${file}`~
++ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
++ dldir=$destdir/`dirname \$dlpath`~
++ test -d \$dldir || mkdir -p \$dldir~
++ $install_prog $dir/$dlname \$dldir/$dlname'
++ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
++ dlpath=$dir/\$dldll~
++ $RM \$dlpath'
++ shlibpath_overrides_runpath=yes
++ dynamic_linker='Win32 link.exe'
++ ;;
++
++ *)
++ # Assume MSVC wrapper
++ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
++ dynamic_linker='Win32 ld.exe'
++ ;;
++ esac
++ # FIXME: first we should search . and the directory the executable is in
++ shlibpath_var=PATH
++ ;;
++
++darwin* | rhapsody*)
++ dynamic_linker="$host_os dyld"
++ version_type=darwin
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
++ soname_spec='${libname}${release}${major}$shared_ext'
++ shlibpath_overrides_runpath=yes
++ shlibpath_var=DYLD_LIBRARY_PATH
++ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
++m4_if([$1], [],[
++ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
++ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
++ ;;
++
++dgux*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ ;;
++
++freebsd* | dragonfly*)
++ # DragonFly does not have aout. When/if they implement a new
++ # versioning mechanism, adjust this.
++ if test -x /usr/bin/objformat; then
++ objformat=`/usr/bin/objformat`
++ else
++ case $host_os in
++ freebsd[[23]].*) objformat=aout ;;
++ *) objformat=elf ;;
++ esac
++ fi
++ version_type=freebsd-$objformat
++ case $version_type in
++ freebsd-elf*)
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++ need_version=no
++ need_lib_prefix=no
++ ;;
++ freebsd-*)
++ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
++ need_version=yes
++ ;;
++ esac
++ shlibpath_var=LD_LIBRARY_PATH
++ case $host_os in
++ freebsd2.*)
++ shlibpath_overrides_runpath=yes
++ ;;
++ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ ;;
++ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
++ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ ;;
++ *) # from 4.6 on, and DragonFly
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ ;;
++ esac
++ ;;
++
++haiku*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ dynamic_linker="$host_os runtime_loader"
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
++ hardcode_into_libs=yes
++ ;;
++
++hpux9* | hpux10* | hpux11*)
++ # Give a soname corresponding to the major version so that dld.sl refuses to
++ # link against other versions.
++ version_type=sunos
++ need_lib_prefix=no
++ need_version=no
++ case $host_cpu in
++ ia64*)
++ shrext_cmds='.so'
++ hardcode_into_libs=yes
++ dynamic_linker="$host_os dld.so"
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ if test "X$HPUX_IA64_MODE" = X32; then
++ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
++ else
++ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
++ fi
++ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
++ ;;
++ hppa*64*)
++ shrext_cmds='.sl'
++ hardcode_into_libs=yes
++ dynamic_linker="$host_os dld.sl"
++ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
++ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
++ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
++ ;;
++ *)
++ shrext_cmds='.sl'
++ dynamic_linker="$host_os dld.sl"
++ shlibpath_var=SHLIB_PATH
++ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ ;;
++ esac
++ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
++ postinstall_cmds='chmod 555 $lib'
++ # or fails outright, so override atomically:
++ install_override_mode=555
++ ;;
++
++interix[[3-9]]*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ ;;
++
++irix5* | irix6* | nonstopux*)
++ case $host_os in
++ nonstopux*) version_type=nonstopux ;;
++ *)
++ if test "$lt_cv_prog_gnu_ld" = yes; then
++ version_type=linux # correct to gnu/linux during the next big refactor
++ else
++ version_type=irix
++ fi ;;
++ esac
++ need_lib_prefix=no
++ need_version=no
++ soname_spec='${libname}${release}${shared_ext}$major'
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
++ case $host_os in
++ irix5* | nonstopux*)
++ libsuff= shlibsuff=
++ ;;
++ *)
++ case $LD in # libtool.m4 will add one of these switches to LD
++ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
++ libsuff= shlibsuff= libmagic=32-bit;;
++ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
++ libsuff=32 shlibsuff=N32 libmagic=N32;;
++ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
++ libsuff=64 shlibsuff=64 libmagic=64-bit;;
++ *) libsuff= shlibsuff= libmagic=never-match;;
++ esac
++ ;;
++ esac
++ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
++ shlibpath_overrides_runpath=no
++ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
++ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
++ hardcode_into_libs=yes
++ ;;
++
++# No shared lib support for Linux oldld, aout, or coff.
++linux*oldld* | linux*aout* | linux*coff*)
++ dynamic_linker=no
++ ;;
++
++# This must be glibc/ELF.
++linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++
++ # Some binutils ld are patched to set DT_RUNPATH
++ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
++ [lt_cv_shlibpath_overrides_runpath=no
++ save_LDFLAGS=$LDFLAGS
++ save_libdir=$libdir
++ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
++ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
++ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
++ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
++ [lt_cv_shlibpath_overrides_runpath=yes])])
++ LDFLAGS=$save_LDFLAGS
++ libdir=$save_libdir
++ ])
++ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
++
++ # This implies no fast_install, which is unacceptable.
++ # Some rework will be needed to allow for fast_install
++ # before this can be enabled.
++ hardcode_into_libs=yes
++
++ # Append ld.so.conf contents to the search path
++ if test -f /etc/ld.so.conf; then
++ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
++ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
++ fi
++
++ # We used to test for /lib/ld.so.1 and disable shared libraries on
++ # powerpc, because MkLinux only supported shared libraries with the
++ # GNU dynamic linker. Since this was broken with cross compilers,
++ # most powerpc-linux boxes support dynamic linking these days and
++ # people can always --disable-shared, the test was removed, and we
++ # assume the GNU/Linux dynamic linker is in use.
++ dynamic_linker='GNU/Linux ld.so'
++ ;;
++
++netbsdelf*-gnu)
++ version_type=linux
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ dynamic_linker='NetBSD ld.elf_so'
++ ;;
++
++netbsd*)
++ version_type=sunos
++ need_lib_prefix=no
++ need_version=no
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
++ dynamic_linker='NetBSD (a.out) ld.so'
++ else
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ dynamic_linker='NetBSD ld.elf_so'
++ fi
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ ;;
++
++newsos6)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ ;;
++
++*nto* | *qnx*)
++ version_type=qnx
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ dynamic_linker='ldqnx.so'
++ ;;
++
++openbsd*)
++ version_type=sunos
++ sys_lib_dlsearch_path_spec="/usr/lib"
++ need_lib_prefix=no
++ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
++ case $host_os in
++ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
++ *) need_version=no ;;
++ esac
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
++ shlibpath_var=LD_LIBRARY_PATH
++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++ case $host_os in
++ openbsd2.[[89]] | openbsd2.[[89]].*)
++ shlibpath_overrides_runpath=no
++ ;;
++ *)
++ shlibpath_overrides_runpath=yes
++ ;;
++ esac
++ else
++ shlibpath_overrides_runpath=yes
++ fi
++ ;;
++
++os2*)
++ libname_spec='$name'
++ shrext_cmds=".dll"
++ need_lib_prefix=no
++ library_names_spec='$libname${shared_ext} $libname.a'
++ dynamic_linker='OS/2 ld.exe'
++ shlibpath_var=LIBPATH
++ ;;
++
++osf3* | osf4* | osf5*)
++ version_type=osf
++ need_lib_prefix=no
++ need_version=no
++ soname_spec='${libname}${release}${shared_ext}$major'
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ shlibpath_var=LD_LIBRARY_PATH
++ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
++ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
++ ;;
++
++rdos*)
++ dynamic_linker=no
++ ;;
++
++solaris*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ # ldd complains unless libraries are executable
++ postinstall_cmds='chmod +x $lib'
++ ;;
++
++sunos4*)
++ version_type=sunos
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
++ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ if test "$with_gnu_ld" = yes; then
++ need_lib_prefix=no
++ fi
++ need_version=yes
++ ;;
++
++sysv4 | sysv4.3*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ case $host_vendor in
++ sni)
++ shlibpath_overrides_runpath=no
++ need_lib_prefix=no
++ runpath_var=LD_RUN_PATH
++ ;;
++ siemens)
++ need_lib_prefix=no
++ ;;
++ motorola)
++ need_lib_prefix=no
++ need_version=no
++ shlibpath_overrides_runpath=no
++ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
++ ;;
++ esac
++ ;;
++
++sysv4*MP*)
++ if test -d /usr/nec ;then
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
++ soname_spec='$libname${shared_ext}.$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ fi
++ ;;
++
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++ version_type=freebsd-elf
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=yes
++ hardcode_into_libs=yes
++ if test "$with_gnu_ld" = yes; then
++ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
++ else
++ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
++ case $host_os in
++ sco3.2v5*)
++ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
++ ;;
++ esac
++ fi
++ sys_lib_dlsearch_path_spec='/usr/lib'
++ ;;
++
++tpf*)
++ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
++ version_type=linux # correct to gnu/linux during the next big refactor
++ need_lib_prefix=no
++ need_version=no
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ shlibpath_var=LD_LIBRARY_PATH
++ shlibpath_overrides_runpath=no
++ hardcode_into_libs=yes
++ ;;
++
++uts4*)
++ version_type=linux # correct to gnu/linux during the next big refactor
++ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
++ soname_spec='${libname}${release}${shared_ext}$major'
++ shlibpath_var=LD_LIBRARY_PATH
++ ;;
++
++*)
++ dynamic_linker=no
++ ;;
++esac
++AC_MSG_RESULT([$dynamic_linker])
++test "$dynamic_linker" = no && can_build_shared=no
++
++variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
++if test "$GCC" = yes; then
++ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
++fi
++
++if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
++ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
++fi
++if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
++ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
++fi
++
++_LT_DECL([], [variables_saved_for_relink], [1],
++ [Variables whose values should be saved in libtool wrapper scripts and
++ restored at link time])
++_LT_DECL([], [need_lib_prefix], [0],
++ [Do we need the "lib" prefix for modules?])
++_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
++_LT_DECL([], [version_type], [0], [Library versioning type])
++_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
++_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
++_LT_DECL([], [shlibpath_overrides_runpath], [0],
++ [Is shlibpath searched before the hard-coded library search path?])
++_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
++_LT_DECL([], [library_names_spec], [1],
++ [[List of archive names. First name is the real one, the rest are links.
++ The last name is the one that the linker finds with -lNAME]])
++_LT_DECL([], [soname_spec], [1],
++ [[The coded name of the library, if different from the real name]])
++_LT_DECL([], [install_override_mode], [1],
++ [Permission mode override for installation of shared libraries])
++_LT_DECL([], [postinstall_cmds], [2],
++ [Command to use after installation of a shared archive])
++_LT_DECL([], [postuninstall_cmds], [2],
++ [Command to use after uninstallation of a shared archive])
++_LT_DECL([], [finish_cmds], [2],
++ [Commands used to finish a libtool library installation in a directory])
++_LT_DECL([], [finish_eval], [1],
++ [[As "finish_cmds", except a single script fragment to be evaled but
++ not shown]])
++_LT_DECL([], [hardcode_into_libs], [0],
++ [Whether we should hardcode library paths into libraries])
++_LT_DECL([], [sys_lib_search_path_spec], [2],
++ [Compile-time system search path for libraries])
++_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
++ [Run-time system search path for libraries])
++])# _LT_SYS_DYNAMIC_LINKER
++
++
++# _LT_PATH_TOOL_PREFIX(TOOL)
++# --------------------------
++# find a file program which can recognize shared library
++AC_DEFUN([_LT_PATH_TOOL_PREFIX],
++[m4_require([_LT_DECL_EGREP])dnl
++AC_MSG_CHECKING([for $1])
++AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
++[case $MAGIC_CMD in
++[[\\/*] | ?:[\\/]*])
++ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
++ ;;
++*)
++ lt_save_MAGIC_CMD="$MAGIC_CMD"
++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++dnl $ac_dummy forces splitting on constant user-supplied paths.
++dnl POSIX.2 word splitting is done only on the output of word expansions,
++dnl not every word. This closes a longstanding sh security hole.
++ ac_dummy="m4_if([$2], , $PATH, [$2])"
++ for ac_dir in $ac_dummy; do
++ IFS="$lt_save_ifs"
++ test -z "$ac_dir" && ac_dir=.
++ if test -f $ac_dir/$1; then
++ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
++ if test -n "$file_magic_test_file"; then
++ case $deplibs_check_method in
++ "file_magic "*)
++ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
++ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
++ $EGREP "$file_magic_regex" > /dev/null; then
++ :
++ else
++ cat <<_LT_EOF 1>&2
++
++*** Warning: the command libtool uses to detect shared libraries,
++*** $file_magic_cmd, produces output that libtool cannot recognize.
++*** The result is that libtool may fail to recognize shared libraries
++*** as such. This will affect the creation of libtool libraries that
++*** depend on shared libraries, but programs linked with such libtool
++*** libraries will work regardless of this problem. Nevertheless, you
++*** may want to report the problem to your system manager and/or to
++*** bug-libtool@gnu.org
++
++_LT_EOF
++ fi ;;
++ esac
++ fi
++ break
++ fi
++ done
++ IFS="$lt_save_ifs"
++ MAGIC_CMD="$lt_save_MAGIC_CMD"
++ ;;
++esac])
++MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
++if test -n "$MAGIC_CMD"; then
++ AC_MSG_RESULT($MAGIC_CMD)
++else
++ AC_MSG_RESULT(no)
++fi
++_LT_DECL([], [MAGIC_CMD], [0],
++ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
++])# _LT_PATH_TOOL_PREFIX
++
++# Old name:
++AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
++
++
++# _LT_PATH_MAGIC
++# --------------
++# find a file program which can recognize a shared library
++m4_defun([_LT_PATH_MAGIC],
++[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
++if test -z "$lt_cv_path_MAGIC_CMD"; then
++ if test -n "$ac_tool_prefix"; then
++ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
++ else
++ MAGIC_CMD=:
++ fi
++fi
++])# _LT_PATH_MAGIC
++
++
++# LT_PATH_LD
++# ----------
++# find the pathname to the GNU or non-GNU linker
++AC_DEFUN([LT_PATH_LD],
++[AC_REQUIRE([AC_PROG_CC])dnl
++AC_REQUIRE([AC_CANONICAL_HOST])dnl
++AC_REQUIRE([AC_CANONICAL_BUILD])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
++
++AC_ARG_WITH([gnu-ld],
++ [AS_HELP_STRING([--with-gnu-ld],
++ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
++ [test "$withval" = no || with_gnu_ld=yes],
++ [with_gnu_ld=no])dnl
++
++ac_prog=ld
++if test "$GCC" = yes; then
++ # Check if gcc -print-prog-name=ld gives a path.
++ AC_MSG_CHECKING([for ld used by $CC])
++ case $host in
++ *-*-mingw*)
++ # gcc leaves a trailing carriage return which upsets mingw
++ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
++ *)
++ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
++ esac
++ case $ac_prog in
++ # Accept absolute paths.
++ [[\\/]]* | ?:[[\\/]]*)
++ re_direlt='/[[^/]][[^/]]*/\.\./'
++ # Canonicalize the pathname of ld
++ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
++ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
++ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
++ done
++ test -z "$LD" && LD="$ac_prog"
++ ;;
++ "")
++ # If it fails, then pretend we aren't using GCC.
++ ac_prog=ld
++ ;;
++ *)
++ # If it is relative, then search for the first ld in PATH.
++ with_gnu_ld=unknown
++ ;;
++ esac
++elif test "$with_gnu_ld" = yes; then
++ AC_MSG_CHECKING([for GNU ld])
++else
++ AC_MSG_CHECKING([for non-GNU ld])
++fi
++AC_CACHE_VAL(lt_cv_path_LD,
++[if test -z "$LD"; then
++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++ for ac_dir in $PATH; do
++ IFS="$lt_save_ifs"
++ test -z "$ac_dir" && ac_dir=.
++ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
++ lt_cv_path_LD="$ac_dir/$ac_prog"
++ # Check to see if the program is GNU ld. I'd rather use --version,
++ # but apparently some variants of GNU ld only accept -v.
++ # Break only if it was the GNU/non-GNU ld that we prefer.
++ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
++ *GNU* | *'with BFD'*)
++ test "$with_gnu_ld" != no && break
++ ;;
++ *)
++ test "$with_gnu_ld" != yes && break
++ ;;
++ esac
++ fi
++ done
++ IFS="$lt_save_ifs"
++else
++ lt_cv_path_LD="$LD" # Let the user override the test with a path.
++fi])
++LD="$lt_cv_path_LD"
++if test -n "$LD"; then
++ AC_MSG_RESULT($LD)
++else
++ AC_MSG_RESULT(no)
++fi
++test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
++_LT_PATH_LD_GNU
++AC_SUBST([LD])
++
++_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
++])# LT_PATH_LD
++
++# Old names:
++AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
++AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AM_PROG_LD], [])
++dnl AC_DEFUN([AC_PROG_LD], [])
++
++
++# _LT_PATH_LD_GNU
++#- --------------
++m4_defun([_LT_PATH_LD_GNU],
++[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
++[# I'd rather use --version here, but apparently some GNU lds only accept -v.
++case `$LD -v 2>&1 </dev/null` in
++*GNU* | *'with BFD'*)
++ lt_cv_prog_gnu_ld=yes
++ ;;
++*)
++ lt_cv_prog_gnu_ld=no
++ ;;
++esac])
++with_gnu_ld=$lt_cv_prog_gnu_ld
++])# _LT_PATH_LD_GNU
++
++
++# _LT_CMD_RELOAD
++# --------------
++# find reload flag for linker
++# -- PORTME Some linkers may need a different reload flag.
++m4_defun([_LT_CMD_RELOAD],
++[AC_CACHE_CHECK([for $LD option to reload object files],
++ lt_cv_ld_reload_flag,
++ [lt_cv_ld_reload_flag='-r'])
++reload_flag=$lt_cv_ld_reload_flag
++case $reload_flag in
++"" | " "*) ;;
++*) reload_flag=" $reload_flag" ;;
++esac
++reload_cmds='$LD$reload_flag -o $output$reload_objs'
++case $host_os in
++ cygwin* | mingw* | pw32* | cegcc*)
++ if test "$GCC" != yes; then
++ reload_cmds=false
++ fi
++ ;;
++ darwin*)
++ if test "$GCC" = yes; then
++ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
++ else
++ reload_cmds='$LD$reload_flag -o $output$reload_objs'
++ fi
++ ;;
++esac
++_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
++_LT_TAGDECL([], [reload_cmds], [2])dnl
++])# _LT_CMD_RELOAD
++
++
++# _LT_CHECK_MAGIC_METHOD
++# ----------------------
++# how to check for library dependencies
++# -- PORTME fill in with the dynamic library characteristics
++m4_defun([_LT_CHECK_MAGIC_METHOD],
++[m4_require([_LT_DECL_EGREP])
++m4_require([_LT_DECL_OBJDUMP])
++AC_CACHE_CHECK([how to recognize dependent libraries],
++lt_cv_deplibs_check_method,
++[lt_cv_file_magic_cmd='$MAGIC_CMD'
++lt_cv_file_magic_test_file=
++lt_cv_deplibs_check_method='unknown'
++# Need to set the preceding variable on all platforms that support
++# interlibrary dependencies.
++# 'none' -- dependencies not supported.
++# `unknown' -- same as none, but documents that we really don't know.
++# 'pass_all' -- all dependencies passed with no checks.
++# 'test_compile' -- check by making test program.
++# 'file_magic [[regex]]' -- check by looking for files in library path
++# which responds to the $file_magic_cmd with a given extended regex.
++# If you have `file' or equivalent on your system and you're not sure
++# whether `pass_all' will *always* work, you probably want this one.
++
++case $host_os in
++aix[[4-9]]*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++beos*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++bsdi[[45]]*)
++ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
++ lt_cv_file_magic_cmd='/usr/bin/file -L'
++ lt_cv_file_magic_test_file=/shlib/libc.so
++ ;;
++
++cygwin*)
++ # func_win32_libid is a shell function defined in ltmain.sh
++ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
++ lt_cv_file_magic_cmd='func_win32_libid'
++ ;;
++
++mingw* | pw32*)
++ # Base MSYS/MinGW do not provide the 'file' command needed by
++ # func_win32_libid shell function, so use a weaker test based on 'objdump',
++ # unless we find 'file', for example because we are cross-compiling.
++ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
++ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
++ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
++ lt_cv_file_magic_cmd='func_win32_libid'
++ else
++ # Keep this pattern in sync with the one in func_win32_libid.
++ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
++ lt_cv_file_magic_cmd='$OBJDUMP -f'
++ fi
++ ;;
++
++cegcc*)
++ # use the weaker test based on 'objdump'. See mingw*.
++ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
++ lt_cv_file_magic_cmd='$OBJDUMP -f'
++ ;;
++
++darwin* | rhapsody*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++freebsd* | dragonfly*)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
++ case $host_cpu in
++ i*86 )
++ # Not sure whether the presence of OpenBSD here was a mistake.
++ # Let's accept both of them until this is cleared up.
++ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
++ lt_cv_file_magic_cmd=/usr/bin/file
++ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
++ ;;
++ esac
++ else
++ lt_cv_deplibs_check_method=pass_all
++ fi
++ ;;
++
++haiku*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++hpux10.20* | hpux11*)
++ lt_cv_file_magic_cmd=/usr/bin/file
++ case $host_cpu in
++ ia64*)
++ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
++ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
++ ;;
++ hppa*64*)
++ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
++ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
++ ;;
++ *)
++ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
++ lt_cv_file_magic_test_file=/usr/lib/libc.sl
++ ;;
++ esac
++ ;;
++
++interix[[3-9]]*)
++ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
++ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
++ ;;
++
++irix5* | irix6* | nonstopux*)
++ case $LD in
++ *-32|*"-32 ") libmagic=32-bit;;
++ *-n32|*"-n32 ") libmagic=N32;;
++ *-64|*"-64 ") libmagic=64-bit;;
++ *) libmagic=never-match;;
++ esac
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++# This must be glibc/ELF.
++linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++netbsd* | netbsdelf*-gnu)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
++ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
++ else
++ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
++ fi
++ ;;
++
++newos6*)
++ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
++ lt_cv_file_magic_cmd=/usr/bin/file
++ lt_cv_file_magic_test_file=/usr/lib/libnls.so
++ ;;
++
++*nto* | *qnx*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++openbsd*)
++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
++ else
++ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
++ fi
++ ;;
++
++osf3* | osf4* | osf5*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++rdos*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++solaris*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++
++sysv4 | sysv4.3*)
++ case $host_vendor in
++ motorola)
++ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
++ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
++ ;;
++ ncr)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++ sequent)
++ lt_cv_file_magic_cmd='/bin/file'
++ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
++ ;;
++ sni)
++ lt_cv_file_magic_cmd='/bin/file'
++ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
++ lt_cv_file_magic_test_file=/lib/libc.so
++ ;;
++ siemens)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++ pc)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++ esac
++ ;;
++
++tpf*)
++ lt_cv_deplibs_check_method=pass_all
++ ;;
++esac
++])
++
++file_magic_glob=
++want_nocaseglob=no
++if test "$build" = "$host"; then
++ case $host_os in
++ mingw* | pw32*)
++ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
++ want_nocaseglob=yes
++ else
++ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
++ fi
++ ;;
++ esac
++fi
++
++file_magic_cmd=$lt_cv_file_magic_cmd
++deplibs_check_method=$lt_cv_deplibs_check_method
++test -z "$deplibs_check_method" && deplibs_check_method=unknown
++
++_LT_DECL([], [deplibs_check_method], [1],
++ [Method to check whether dependent libraries are shared objects])
++_LT_DECL([], [file_magic_cmd], [1],
++ [Command to use when deplibs_check_method = "file_magic"])
++_LT_DECL([], [file_magic_glob], [1],
++ [How to find potential files when deplibs_check_method = "file_magic"])
++_LT_DECL([], [want_nocaseglob], [1],
++ [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
++])# _LT_CHECK_MAGIC_METHOD
++
++
++# LT_PATH_NM
++# ----------
++# find the pathname to a BSD- or MS-compatible name lister
++AC_DEFUN([LT_PATH_NM],
++[AC_REQUIRE([AC_PROG_CC])dnl
++AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
++[if test -n "$NM"; then
++ # Let the user override the test.
++ lt_cv_path_NM="$NM"
++else
++ lt_nm_to_check="${ac_tool_prefix}nm"
++ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
++ lt_nm_to_check="$lt_nm_to_check nm"
++ fi
++ for lt_tmp_nm in $lt_nm_to_check; do
++ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
++ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
++ IFS="$lt_save_ifs"
++ test -z "$ac_dir" && ac_dir=.
++ tmp_nm="$ac_dir/$lt_tmp_nm"
++ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
++ # Check to see if the nm accepts a BSD-compat flag.
++ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
++ # nm: unknown option "B" ignored
++ # Tru64's nm complains that /dev/null is an invalid object file
++ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
++ */dev/null* | *'Invalid file or object type'*)
++ lt_cv_path_NM="$tmp_nm -B"
++ break
++ ;;
++ *)
++ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
++ */dev/null*)
++ lt_cv_path_NM="$tmp_nm -p"
++ break
++ ;;
++ *)
++ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
++ continue # so that we can try to find one that supports BSD flags
++ ;;
++ esac
++ ;;
++ esac
++ fi
++ done
++ IFS="$lt_save_ifs"
++ done
++ : ${lt_cv_path_NM=no}
++fi])
++if test "$lt_cv_path_NM" != "no"; then
++ NM="$lt_cv_path_NM"
++else
++ # Didn't find any BSD compatible name lister, look for dumpbin.
++ if test -n "$DUMPBIN"; then :
++ # Let the user override the test.
++ else
++ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
++ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
++ *COFF*)
++ DUMPBIN="$DUMPBIN -symbols"
++ ;;
++ *)
++ DUMPBIN=:
++ ;;
++ esac
++ fi
++ AC_SUBST([DUMPBIN])
++ if test "$DUMPBIN" != ":"; then
++ NM="$DUMPBIN"
++ fi
++fi
++test -z "$NM" && NM=nm
++AC_SUBST([NM])
++_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
++
++AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
++ [lt_cv_nm_interface="BSD nm"
++ echo "int some_variable = 0;" > conftest.$ac_ext
++ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
++ (eval "$ac_compile" 2>conftest.err)
++ cat conftest.err >&AS_MESSAGE_LOG_FD
++ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
++ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
++ cat conftest.err >&AS_MESSAGE_LOG_FD
++ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
++ cat conftest.out >&AS_MESSAGE_LOG_FD
++ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
++ lt_cv_nm_interface="MS dumpbin"
++ fi
++ rm -f conftest*])
++])# LT_PATH_NM
++
++# Old names:
++AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
++AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AM_PROG_NM], [])
++dnl AC_DEFUN([AC_PROG_NM], [])
++
++# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
++# --------------------------------
++# how to determine the name of the shared library
++# associated with a specific link library.
++# -- PORTME fill in with the dynamic library characteristics
++m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
++[m4_require([_LT_DECL_EGREP])
++m4_require([_LT_DECL_OBJDUMP])
++m4_require([_LT_DECL_DLLTOOL])
++AC_CACHE_CHECK([how to associate runtime and link libraries],
++lt_cv_sharedlib_from_linklib_cmd,
++[lt_cv_sharedlib_from_linklib_cmd='unknown'
++
++case $host_os in
++cygwin* | mingw* | pw32* | cegcc*)
++ # two different shell functions defined in ltmain.sh
++ # decide which to use based on capabilities of $DLLTOOL
++ case `$DLLTOOL --help 2>&1` in
++ *--identify-strict*)
++ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
++ ;;
++ *)
++ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
++ ;;
++ esac
++ ;;
++*)
++ # fallback: assume linklib IS sharedlib
++ lt_cv_sharedlib_from_linklib_cmd="$ECHO"
++ ;;
++esac
++])
++sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
++test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
++
++_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
++ [Command to associate shared and link libraries])
++])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
++
++
++# _LT_PATH_MANIFEST_TOOL
++# ----------------------
++# locate the manifest tool
++m4_defun([_LT_PATH_MANIFEST_TOOL],
++[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
++test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
++AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
++ [lt_cv_path_mainfest_tool=no
++ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
++ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
++ cat conftest.err >&AS_MESSAGE_LOG_FD
++ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
++ lt_cv_path_mainfest_tool=yes
++ fi
++ rm -f conftest*])
++if test "x$lt_cv_path_mainfest_tool" != xyes; then
++ MANIFEST_TOOL=:
++fi
++_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
++])# _LT_PATH_MANIFEST_TOOL
++
++
++# LT_LIB_M
++# --------
++# check for math library
++AC_DEFUN([LT_LIB_M],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++LIBM=
++case $host in
++*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
++ # These system don't have libm, or don't need it
++ ;;
++*-ncr-sysv4.3*)
++ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
++ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
++ ;;
++*)
++ AC_CHECK_LIB(m, cos, LIBM="-lm")
++ ;;
++esac
++AC_SUBST([LIBM])
++])# LT_LIB_M
++
++# Old name:
++AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([AC_CHECK_LIBM], [])
++
++
++# _LT_COMPILER_NO_RTTI([TAGNAME])
++# -------------------------------
++m4_defun([_LT_COMPILER_NO_RTTI],
++[m4_require([_LT_TAG_COMPILER])dnl
++
++_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
++
++if test "$GCC" = yes; then
++ case $cc_basename in
++ nvcc*)
++ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
++ esac
++
++ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
++ lt_cv_prog_compiler_rtti_exceptions,
++ [-fno-rtti -fno-exceptions], [],
++ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
++fi
++_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
++ [Compiler flag to turn off builtin functions])
++])# _LT_COMPILER_NO_RTTI
++
++
++# _LT_CMD_GLOBAL_SYMBOLS
++# ----------------------
++m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++AC_REQUIRE([AC_PROG_CC])dnl
++AC_REQUIRE([AC_PROG_AWK])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++AC_REQUIRE([LT_PATH_LD])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++
++# Check for command to grab the raw symbol name followed by C symbol from nm.
++AC_MSG_CHECKING([command to parse $NM output from $compiler object])
++AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
++[
++# These are sane defaults that work on at least a few old systems.
++# [They come from Ultrix. What could be older than Ultrix?!! ;)]
++
++# Character class describing NM global symbol codes.
++symcode='[[BCDEGRST]]'
++
++# Regexp to match symbols that can be accessed directly from C.
++sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
++
++# Define system-specific variables.
++case $host_os in
++aix*)
++ symcode='[[BCDT]]'
++ ;;
++cygwin* | mingw* | pw32* | cegcc*)
++ symcode='[[ABCDGISTW]]'
++ ;;
++hpux*)
++ if test "$host_cpu" = ia64; then
++ symcode='[[ABCDEGRST]]'
++ fi
++ ;;
++irix* | nonstopux*)
++ symcode='[[BCDEGRST]]'
++ ;;
++osf*)
++ symcode='[[BCDEGQRST]]'
++ ;;
++solaris*)
++ symcode='[[BDRT]]'
++ ;;
++sco3.2v5*)
++ symcode='[[DT]]'
++ ;;
++sysv4.2uw2*)
++ symcode='[[DT]]'
++ ;;
++sysv5* | sco5v6* | unixware* | OpenUNIX*)
++ symcode='[[ABDT]]'
++ ;;
++sysv4)
++ symcode='[[DFNSTU]]'
++ ;;
++esac
++
++# If we're using GNU nm, then use its standard symbol codes.
++case `$NM -V 2>&1` in
++*GNU* | *'with BFD'*)
++ symcode='[[ABCDGIRSTW]]' ;;
++esac
++
++# Transform an extracted symbol line into a proper C declaration.
++# Some systems (esp. on ia64) link data and code symbols differently,
++# so use this general approach.
++lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
++
++# Transform an extracted symbol line into symbol name and symbol address
++lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
++lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
++
++# Handle CRLF in mingw tool chain
++opt_cr=
++case $build_os in
++mingw*)
++ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
++ ;;
++esac
++
++# Try without a prefix underscore, then with it.
++for ac_symprfx in "" "_"; do
++
++ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
++ symxfrm="\\1 $ac_symprfx\\2 \\2"
++
++ # Write the raw and C identifiers.
++ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
++ # Fake it for dumpbin and say T for any non-static function
++ # and D for any global variable.
++ # Also find C++ and __fastcall symbols from MSVC++,
++ # which start with @ or ?.
++ lt_cv_sys_global_symbol_pipe="$AWK ['"\
++" {last_section=section; section=\$ 3};"\
++" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
++" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
++" \$ 0!~/External *\|/{next};"\
++" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
++" {if(hide[section]) next};"\
++" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
++" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
++" s[1]~/^[@?]/{print s[1], s[1]; next};"\
++" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
++" ' prfx=^$ac_symprfx]"
++ else
++ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
++ fi
++ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
++
++ # Check to see that the pipe works correctly.
++ pipe_works=no
++
++ rm -f conftest*
++ cat > conftest.$ac_ext <<_LT_EOF
++#ifdef __cplusplus
++extern "C" {
++#endif
++char nm_test_var;
++void nm_test_func(void);
++void nm_test_func(void){}
++#ifdef __cplusplus
++}
++#endif
++int main(){nm_test_var='a';nm_test_func();return(0);}
++_LT_EOF
++
++ if AC_TRY_EVAL(ac_compile); then
++ # Now try to grab the symbols.
++ nlist=conftest.nm
++ if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
++ # Try sorting and uniquifying the output.
++ if sort "$nlist" | uniq > "$nlist"T; then
++ mv -f "$nlist"T "$nlist"
++ else
++ rm -f "$nlist"T
++ fi
++
++ # Make sure that we snagged all the symbols we need.
++ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
++ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
++ cat <<_LT_EOF > conftest.$ac_ext
++/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
++#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
++/* DATA imports from DLLs on WIN32 con't be const, because runtime
++ relocations are performed -- see ld's documentation on pseudo-relocs. */
++# define LT@&t@_DLSYM_CONST
++#elif defined(__osf__)
++/* This system does not cope well with relocations in const data. */
++# define LT@&t@_DLSYM_CONST
++#else
++# define LT@&t@_DLSYM_CONST const
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++_LT_EOF
++ # Now generate the symbol file.
++ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
++
++ cat <<_LT_EOF >> conftest.$ac_ext
++
++/* The mapping between symbol names and symbols. */
++LT@&t@_DLSYM_CONST struct {
++ const char *name;
++ void *address;
++}
++lt__PROGRAM__LTX_preloaded_symbols[[]] =
++{
++ { "@PROGRAM@", (void *) 0 },
++_LT_EOF
++ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
++ cat <<\_LT_EOF >> conftest.$ac_ext
++ {0, (void *) 0}
++};
++
++/* This works around a problem in FreeBSD linker */
++#ifdef FREEBSD_WORKAROUND
++static const void *lt_preloaded_setup() {
++ return lt__PROGRAM__LTX_preloaded_symbols;
++}
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++_LT_EOF
++ # Now try linking the two files.
++ mv conftest.$ac_objext conftstm.$ac_objext
++ lt_globsym_save_LIBS=$LIBS
++ lt_globsym_save_CFLAGS=$CFLAGS
++ LIBS="conftstm.$ac_objext"
++ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
++ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
++ pipe_works=yes
++ fi
++ LIBS=$lt_globsym_save_LIBS
++ CFLAGS=$lt_globsym_save_CFLAGS
++ else
++ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
++ fi
++ else
++ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
++ fi
++ else
++ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
++ fi
++ else
++ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
++ cat conftest.$ac_ext >&5
++ fi
++ rm -rf conftest* conftst*
++
++ # Do not use the global_symbol_pipe unless it works.
++ if test "$pipe_works" = yes; then
++ break
++ else
++ lt_cv_sys_global_symbol_pipe=
++ fi
++done
++])
++if test -z "$lt_cv_sys_global_symbol_pipe"; then
++ lt_cv_sys_global_symbol_to_cdecl=
++fi
++if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
++ AC_MSG_RESULT(failed)
++else
++ AC_MSG_RESULT(ok)
++fi
++
++# Response file support.
++if test "$lt_cv_nm_interface" = "MS dumpbin"; then
++ nm_file_list_spec='@'
++elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
++ nm_file_list_spec='@'
++fi
++
++_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
++ [Take the output of nm and produce a listing of raw symbols and C names])
++_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
++ [Transform the output of nm in a proper C declaration])
++_LT_DECL([global_symbol_to_c_name_address],
++ [lt_cv_sys_global_symbol_to_c_name_address], [1],
++ [Transform the output of nm in a C name address pair])
++_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
++ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
++ [Transform the output of nm in a C name address pair when lib prefix is needed])
++_LT_DECL([], [nm_file_list_spec], [1],
++ [Specify filename containing input files for $NM])
++]) # _LT_CMD_GLOBAL_SYMBOLS
++
++
++# _LT_COMPILER_PIC([TAGNAME])
++# ---------------------------
++m4_defun([_LT_COMPILER_PIC],
++[m4_require([_LT_TAG_COMPILER])dnl
++_LT_TAGVAR(lt_prog_compiler_wl, $1)=
++_LT_TAGVAR(lt_prog_compiler_pic, $1)=
++_LT_TAGVAR(lt_prog_compiler_static, $1)=
++
++m4_if([$1], [CXX], [
++ # C++ specific cases for pic, static, wl, etc.
++ if test "$GXX" = yes; then
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++
++ case $host_os in
++ aix*)
++ # All AIX code is PIC.
++ if test "$host_cpu" = ia64; then
++ # AIX 5 now supports IA64 processor
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ fi
++ ;;
++
++ amigaos*)
++ case $host_cpu in
++ powerpc)
++ # see comment about AmigaOS4 .so support
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ ;;
++ m68k)
++ # FIXME: we need at least 68020 code to build shared libraries, but
++ # adding the `-m68020' flag to GCC prevents building anything better,
++ # like `-m68040'.
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
++ ;;
++ esac
++ ;;
++
++ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
++ # PIC is the default for these OSes.
++ ;;
++ mingw* | cygwin* | os2* | pw32* | cegcc*)
++ # This hack is so that the source file can tell whether it is being
++ # built for inclusion in a dll (and should export symbols for example).
++ # Although the cygwin gcc ignores -fPIC, still need this for old-style
++ # (--disable-auto-import) libraries
++ m4_if([$1], [GCJ], [],
++ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++ ;;
++ darwin* | rhapsody*)
++ # PIC is the default on this platform
++ # Common symbols not allowed in MH_DYLIB files
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
++ ;;
++ *djgpp*)
++ # DJGPP does not support shared libraries at all
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++ ;;
++ haiku*)
++ # PIC is the default for Haiku.
++ # The "-static" flag exists, but is broken.
++ _LT_TAGVAR(lt_prog_compiler_static, $1)=
++ ;;
++ interix[[3-9]]*)
++ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++ # Instead, we relocate shared libraries at runtime.
++ ;;
++ sysv4*MP*)
++ if test -d /usr/nec; then
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
++ fi
++ ;;
++ hpux*)
++ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
++ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
++ # sets the default TLS model and affects inlining.
++ case $host_cpu in
++ hppa*64*)
++ ;;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ ;;
++ esac
++ ;;
++ *qnx* | *nto*)
++ # QNX uses GNU C++, but need to define -shared option too, otherwise
++ # it will coredump.
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++ ;;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ ;;
++ esac
++ else
++ case $host_os in
++ aix[[4-9]]*)
++ # All AIX code is PIC.
++ if test "$host_cpu" = ia64; then
++ # AIX 5 now supports IA64 processor
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ else
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
++ fi
++ ;;
++ chorus*)
++ case $cc_basename in
++ cxch68*)
++ # Green Hills C++ Compiler
++ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
++ ;;
++ esac
++ ;;
++ mingw* | cygwin* | os2* | pw32* | cegcc*)
++ # This hack is so that the source file can tell whether it is being
++ # built for inclusion in a dll (and should export symbols for example).
++ m4_if([$1], [GCJ], [],
++ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++ ;;
++ dgux*)
++ case $cc_basename in
++ ec++*)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ ;;
++ ghcx*)
++ # Green Hills C++ Compiler
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++ ;;
++ *)
++ ;;
++ esac
++ ;;
++ freebsd* | dragonfly*)
++ # FreeBSD uses GNU C++
++ ;;
++ hpux9* | hpux10* | hpux11*)
++ case $cc_basename in
++ CC*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++ if test "$host_cpu" != ia64; then
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++ fi
++ ;;
++ aCC*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++ case $host_cpu in
++ hppa*64*|ia64*)
++ # +Z the default
++ ;;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++ ;;
++ esac
++ ;;
++ *)
++ ;;
++ esac
++ ;;
++ interix*)
++ # This is c89, which is MS Visual C++ (no shared libs)
++ # Anyone wants to do a port?
++ ;;
++ irix5* | irix6* | nonstopux*)
++ case $cc_basename in
++ CC*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++ # CC pic flag -KPIC is the default.
++ ;;
++ *)
++ ;;
++ esac
++ ;;
++ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
++ case $cc_basename in
++ KCC*)
++ # KAI C++ Compiler
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ ;;
++ ecpc* )
++ # old Intel C++ for x86_64 which still supported -KPIC.
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++ ;;
++ icpc* )
++ # Intel C++, used to be incompatible with GCC.
++ # ICC 10 doesn't accept -KPIC any more.
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++ ;;
++ pgCC* | pgcpp*)
++ # Portland Group C++ compiler
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++ cxx*)
++ # Compaq C++
++ # Make sure the PIC flag is empty. It appears that all Alpha
++ # Linux and Compaq Tru64 Unix objects are PIC.
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++ ;;
++ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
++ # IBM XL 8.0, 9.0 on PPC and BlueGene
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
++ ;;
++ *)
++ case `$CC -V 2>&1 | sed 5q` in
++ *Sun\ C*)
++ # Sun C++ 5.9
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++ ;;
++ esac
++ ;;
++ esac
++ ;;
++ lynxos*)
++ ;;
++ m88k*)
++ ;;
++ mvs*)
++ case $cc_basename in
++ cxx*)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
++ ;;
++ *)
++ ;;
++ esac
++ ;;
++ netbsd* | netbsdelf*-gnu)
++ ;;
++ *qnx* | *nto*)
++ # QNX uses GNU C++, but need to define -shared option too, otherwise
++ # it will coredump.
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++ ;;
++ osf3* | osf4* | osf5*)
++ case $cc_basename in
++ KCC*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
++ ;;
++ RCC*)
++ # Rational C++ 2.4.1
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++ ;;
++ cxx*)
++ # Digital/Compaq C++
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ # Make sure the PIC flag is empty. It appears that all Alpha
++ # Linux and Compaq Tru64 Unix objects are PIC.
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++ ;;
++ *)
++ ;;
++ esac
++ ;;
++ psos*)
++ ;;
++ solaris*)
++ case $cc_basename in
++ CC* | sunCC*)
++ # Sun C++ 4.2, 5.x and Centerline C++
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++ ;;
++ gcx*)
++ # Green Hills C++ Compiler
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
++ ;;
++ *)
++ ;;
++ esac
++ ;;
++ sunos4*)
++ case $cc_basename in
++ CC*)
++ # Sun C++ 4.x
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++ lcc*)
++ # Lucid
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++ ;;
++ *)
++ ;;
++ esac
++ ;;
++ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++ case $cc_basename in
++ CC*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++ esac
++ ;;
++ tandem*)
++ case $cc_basename in
++ NCC*)
++ # NonStop-UX NCC 3.20
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ ;;
++ *)
++ ;;
++ esac
++ ;;
++ vxworks*)
++ ;;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++ ;;
++ esac
++ fi
++],
++[
++ if test "$GCC" = yes; then
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++
++ case $host_os in
++ aix*)
++ # All AIX code is PIC.
++ if test "$host_cpu" = ia64; then
++ # AIX 5 now supports IA64 processor
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ fi
++ ;;
++
++ amigaos*)
++ case $host_cpu in
++ powerpc)
++ # see comment about AmigaOS4 .so support
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ ;;
++ m68k)
++ # FIXME: we need at least 68020 code to build shared libraries, but
++ # adding the `-m68020' flag to GCC prevents building anything better,
++ # like `-m68040'.
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
++ ;;
++ esac
++ ;;
++
++ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
++ # PIC is the default for these OSes.
++ ;;
++
++ mingw* | cygwin* | pw32* | os2* | cegcc*)
++ # This hack is so that the source file can tell whether it is being
++ # built for inclusion in a dll (and should export symbols for example).
++ # Although the cygwin gcc ignores -fPIC, still need this for old-style
++ # (--disable-auto-import) libraries
++ m4_if([$1], [GCJ], [],
++ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++ ;;
++
++ darwin* | rhapsody*)
++ # PIC is the default on this platform
++ # Common symbols not allowed in MH_DYLIB files
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
++ ;;
++
++ haiku*)
++ # PIC is the default for Haiku.
++ # The "-static" flag exists, but is broken.
++ _LT_TAGVAR(lt_prog_compiler_static, $1)=
++ ;;
++
++ hpux*)
++ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
++ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
++ # sets the default TLS model and affects inlining.
++ case $host_cpu in
++ hppa*64*)
++ # +Z the default
++ ;;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ ;;
++ esac
++ ;;
++
++ interix[[3-9]]*)
++ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
++ # Instead, we relocate shared libraries at runtime.
++ ;;
++
++ msdosdjgpp*)
++ # Just because we use GCC doesn't mean we suddenly get shared libraries
++ # on systems that don't support them.
++ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++ enable_shared=no
++ ;;
++
++ *nto* | *qnx*)
++ # QNX uses GNU C++, but need to define -shared option too, otherwise
++ # it will coredump.
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++ ;;
++
++ sysv4*MP*)
++ if test -d /usr/nec; then
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
++ fi
++ ;;
++
++ *)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ ;;
++ esac
++
++ case $cc_basename in
++ nvcc*) # Cuda Compiler Driver 2.2
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
++ if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
++ fi
++ ;;
++ esac
++ else
++ # PORTME Check for flag to pass linker flags through the system compiler.
++ case $host_os in
++ aix*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ if test "$host_cpu" = ia64; then
++ # AIX 5 now supports IA64 processor
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ else
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
++ fi
++ ;;
++
++ mingw* | cygwin* | pw32* | os2* | cegcc*)
++ # This hack is so that the source file can tell whether it is being
++ # built for inclusion in a dll (and should export symbols for example).
++ m4_if([$1], [GCJ], [],
++ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
++ ;;
++
++ hpux9* | hpux10* | hpux11*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
++ # not for PA HP-UX.
++ case $host_cpu in
++ hppa*64*|ia64*)
++ # +Z the default
++ ;;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
++ ;;
++ esac
++ # Is there a better lt_prog_compiler_static that works with the bundled CC?
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
++ ;;
++
++ irix5* | irix6* | nonstopux*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ # PIC (with -KPIC) is the default.
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++ ;;
++
++ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
++ case $cc_basename in
++ # old Intel for x86_64 which still supported -KPIC.
++ ecc*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++ ;;
++ # icc used to be incompatible with GCC.
++ # ICC 10 doesn't accept -KPIC any more.
++ icc* | ifort*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++ ;;
++ # Lahey Fortran 8.1.
++ lf95*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
++ ;;
++ nagfor*)
++ # NAG Fortran compiler
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
++ # Portland Group compilers (*not* the Pentium gcc compiler,
++ # which looks to be a dead project)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++ ccc*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ # All Alpha code is PIC.
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++ ;;
++ xl* | bgxl* | bgf* | mpixl*)
++ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
++ ;;
++ *)
++ case `$CC -V 2>&1 | sed 5q` in
++ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
++ # Sun Fortran 8.3 passes all unrecognized flags to the linker
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
++ ;;
++ *Sun\ F* | *Sun*Fortran*)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++ ;;
++ *Sun\ C*)
++ # Sun C 5.9
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ ;;
++ *Intel*\ [[CF]]*Compiler*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
++ ;;
++ *Portland\ Group*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++ esac
++ ;;
++ esac
++ ;;
++
++ newsos6)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++
++ *nto* | *qnx*)
++ # QNX uses GNU C++, but need to define -shared option too, otherwise
++ # it will coredump.
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
++ ;;
++
++ osf3* | osf4* | osf5*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ # All OSF/1 code is PIC.
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++ ;;
++
++ rdos*)
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
++ ;;
++
++ solaris*)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ case $cc_basename in
++ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
++ esac
++ ;;
++
++ sunos4*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++
++ sysv4 | sysv4.2uw2* | sysv4.3*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++
++ sysv4*MP*)
++ if test -d /usr/nec ;then
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ fi
++ ;;
++
++ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++
++ unicos*)
++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
++ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++ ;;
++
++ uts4*)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
++ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
++ ;;
++
++ *)
++ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
++ ;;
++ esac
++ fi
++])
++case $host_os in
++ # For platforms which do not support PIC, -DPIC is meaningless:
++ *djgpp*)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
++ ;;
++ *)
++ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
++ ;;
++esac
++
++AC_CACHE_CHECK([for $compiler option to produce PIC],
++ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
++ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
++_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
++
++#
++# Check to make sure the PIC flag actually works.
++#
++if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
++ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
++ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
++ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
++ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
++ "" | " "*) ;;
++ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
++ esac],
++ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
++ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
++fi
++_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
++ [Additional compiler flags for building library objects])
++
++_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
++ [How to pass a linker flag through the compiler])
++#
++# Check to make sure the static flag actually works.
++#
++wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
++_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
++ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
++ $lt_tmp_static_flag,
++ [],
++ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
++_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
++ [Compiler flag to prevent dynamic linking])
++])# _LT_COMPILER_PIC
++
++
++# _LT_LINKER_SHLIBS([TAGNAME])
++# ----------------------------
++# See if the linker supports building shared libraries.
++m4_defun([_LT_LINKER_SHLIBS],
++[AC_REQUIRE([LT_PATH_LD])dnl
++AC_REQUIRE([LT_PATH_NM])dnl
++m4_require([_LT_PATH_MANIFEST_TOOL])dnl
++m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_DECL_SED])dnl
++m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
++m4_require([_LT_TAG_COMPILER])dnl
++AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
++m4_if([$1], [CXX], [
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
++ case $host_os in
++ aix[[4-9]]*)
++ # If we're using GNU nm, then we don't want the "-C" option.
++ # -C means demangle to AIX nm, but means don't demangle with GNU nm
++ # Also, AIX nm treats weak defined symbols like other global defined
++ # symbols, whereas GNU nm marks them as "W".
++ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++ else
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++ fi
++ ;;
++ pw32*)
++ _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
++ ;;
++ cygwin* | mingw* | cegcc*)
++ case $cc_basename in
++ cl*)
++ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
++ ;;
++ *)
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
++ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
++ ;;
++ esac
++ ;;
++ linux* | k*bsd*-gnu | gnu*)
++ _LT_TAGVAR(link_all_deplibs, $1)=no
++ ;;
++ *)
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++ ;;
++ esac
++], [
++ runpath_var=
++ _LT_TAGVAR(allow_undefined_flag, $1)=
++ _LT_TAGVAR(always_export_symbols, $1)=no
++ _LT_TAGVAR(archive_cmds, $1)=
++ _LT_TAGVAR(archive_expsym_cmds, $1)=
++ _LT_TAGVAR(compiler_needs_object, $1)=no
++ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
++ _LT_TAGVAR(hardcode_automatic, $1)=no
++ _LT_TAGVAR(hardcode_direct, $1)=no
++ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=
++ _LT_TAGVAR(hardcode_minus_L, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++ _LT_TAGVAR(inherit_rpath, $1)=no
++ _LT_TAGVAR(link_all_deplibs, $1)=unknown
++ _LT_TAGVAR(module_cmds, $1)=
++ _LT_TAGVAR(module_expsym_cmds, $1)=
++ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
++ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
++ _LT_TAGVAR(thread_safe_flag_spec, $1)=
++ _LT_TAGVAR(whole_archive_flag_spec, $1)=
++ # include_expsyms should be a list of space-separated symbols to be *always*
++ # included in the symbol list
++ _LT_TAGVAR(include_expsyms, $1)=
++ # exclude_expsyms can be an extended regexp of symbols to exclude
++ # it will be wrapped by ` (' and `)$', so one must not match beginning or
++ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
++ # as well as any symbol that contains `d'.
++ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
++ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
++ # platforms (ab)use it in PIC code, but their linkers get confused if
++ # the symbol is explicitly referenced. Since portable code cannot
++ # rely on this symbol name, it's probably fine to never include it in
++ # preloaded symbol tables.
++ # Exclude shared library initialization/finalization symbols.
++dnl Note also adjust exclude_expsyms for C++ above.
++ extract_expsyms_cmds=
++
++ case $host_os in
++ cygwin* | mingw* | pw32* | cegcc*)
++ # FIXME: the MSVC++ port hasn't been tested in a loooong time
++ # When not using gcc, we currently assume that we are using
++ # Microsoft Visual C++.
++ if test "$GCC" != yes; then
++ with_gnu_ld=no
++ fi
++ ;;
++ interix*)
++ # we just hope/assume this is gcc and not c89 (= MSVC++)
++ with_gnu_ld=yes
++ ;;
++ openbsd*)
++ with_gnu_ld=no
++ ;;
++ linux* | k*bsd*-gnu | gnu*)
++ _LT_TAGVAR(link_all_deplibs, $1)=no
++ ;;
++ esac
++
++ _LT_TAGVAR(ld_shlibs, $1)=yes
++
++ # On some targets, GNU ld is compatible enough with the native linker
++ # that we're better off using the native interface for both.
++ lt_use_gnu_ld_interface=no
++ if test "$with_gnu_ld" = yes; then
++ case $host_os in
++ aix*)
++ # The AIX port of GNU ld has always aspired to compatibility
++ # with the native linker. However, as the warning in the GNU ld
++ # block says, versions before 2.19.5* couldn't really create working
++ # shared libraries, regardless of the interface used.
++ case `$LD -v 2>&1` in
++ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
++ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
++ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
++ *)
++ lt_use_gnu_ld_interface=yes
++ ;;
++ esac
++ ;;
++ *)
++ lt_use_gnu_ld_interface=yes
++ ;;
++ esac
++ fi
++
++ if test "$lt_use_gnu_ld_interface" = yes; then
++ # If archive_cmds runs LD, not CC, wlarc should be empty
++ wlarc='${wl}'
++
++ # Set some defaults for GNU ld with shared library support. These
++ # are reset later if shared libraries are not supported. Putting them
++ # here allows them to be overridden if necessary.
++ runpath_var=LD_RUN_PATH
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++ # ancient GNU ld didn't support --whole-archive et. al.
++ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
++ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++ else
++ _LT_TAGVAR(whole_archive_flag_spec, $1)=
++ fi
++ supports_anon_versioning=no
++ case `$LD -v 2>&1` in
++ *GNU\ gold*) supports_anon_versioning=yes ;;
++ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
++ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
++ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
++ *\ 2.11.*) ;; # other 2.11 versions
++ *) supports_anon_versioning=yes ;;
++ esac
++
++ # See if GNU ld supports shared libraries.
++ case $host_os in
++ aix[[3-9]]*)
++ # On AIX/PPC, the GNU linker is very broken
++ if test "$host_cpu" != ia64; then
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ cat <<_LT_EOF 1>&2
++
++*** Warning: the GNU linker, at least up to release 2.19, is reported
++*** to be unable to reliably create shared libraries on AIX.
++*** Therefore, libtool is disabling shared libraries support. If you
++*** really care for shared libraries, you may want to install binutils
++*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
++*** You will then need to restart the configuration process.
++
++_LT_EOF
++ fi
++ ;;
++
++ amigaos*)
++ case $host_cpu in
++ powerpc)
++ # see comment about AmigaOS4 .so support
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)=''
++ ;;
++ m68k)
++ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ ;;
++ esac
++ ;;
++
++ beos*)
++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
++ # support --undefined. This deserves some investigation. FIXME
++ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++
++ cygwin* | mingw* | pw32* | cegcc*)
++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
++ # as there is no search path for DLLs.
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ _LT_TAGVAR(always_export_symbols, $1)=no
++ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
++ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
++
++ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++ # If the export-symbols file already is a .def file (1st line
++ # is EXPORTS), use it as is; otherwise, prepend...
++ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++ cp $export_symbols $output_objdir/$soname.def;
++ else
++ echo EXPORTS > $output_objdir/$soname.def;
++ cat $export_symbols >> $output_objdir/$soname.def;
++ fi~
++ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++
++ haiku*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ ;;
++
++ interix[[3-9]]*)
++ _LT_TAGVAR(hardcode_direct, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++ # Instead, shared libraries are loaded at an image base (0x10000000 by
++ # default) and relocated if they conflict, which is a slow very memory
++ # consuming and fragmenting process. To avoid this, we pick a random,
++ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++ ;;
++
++ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
++ tmp_diet=no
++ if test "$host_os" = linux-dietlibc; then
++ case $cc_basename in
++ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
++ esac
++ fi
++ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
++ && test "$tmp_diet" = no
++ then
++ tmp_addflag=' $pic_flag'
++ tmp_sharedflag='-shared'
++ case $cc_basename,$host_cpu in
++ pgcc*) # Portland Group C compiler
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ tmp_addflag=' $pic_flag'
++ ;;
++ pgf77* | pgf90* | pgf95* | pgfortran*)
++ # Portland Group f77 and f90 compilers
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ tmp_addflag=' $pic_flag -Mnomain' ;;
++ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
++ tmp_addflag=' -i_dynamic' ;;
++ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
++ tmp_addflag=' -i_dynamic -nofor_main' ;;
++ ifc* | ifort*) # Intel Fortran compiler
++ tmp_addflag=' -nofor_main' ;;
++ lf95*) # Lahey Fortran 8.1
++ _LT_TAGVAR(whole_archive_flag_spec, $1)=
++ tmp_sharedflag='--shared' ;;
++ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
++ tmp_sharedflag='-qmkshrobj'
++ tmp_addflag= ;;
++ nvcc*) # Cuda Compiler Driver 2.2
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ _LT_TAGVAR(compiler_needs_object, $1)=yes
++ ;;
++ esac
++ case `$CC -V 2>&1 | sed 5q` in
++ *Sun\ C*) # Sun C 5.9
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ _LT_TAGVAR(compiler_needs_object, $1)=yes
++ tmp_sharedflag='-G' ;;
++ *Sun\ F*) # Sun Fortran 8.3
++ tmp_sharedflag='-G' ;;
++ esac
++ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++
++ if test "x$supports_anon_versioning" = xyes; then
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++ echo "local: *; };" >> $output_objdir/$libname.ver~
++ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
++ fi
++
++ case $cc_basename in
++ xlf* | bgf* | bgxlf* | mpixlf*)
++ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
++ if test "x$supports_anon_versioning" = xyes; then
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++ echo "local: *; };" >> $output_objdir/$libname.ver~
++ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
++ fi
++ ;;
++ esac
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++
++ netbsd* | netbsdelf*-gnu)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
++ wlarc=
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ fi
++ ;;
++
++ solaris*)
++ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ cat <<_LT_EOF 1>&2
++
++*** Warning: The releases 2.8.* of the GNU linker cannot reliably
++*** create shared libraries on Solaris systems. Therefore, libtool
++*** is disabling shared libraries support. We urge you to upgrade GNU
++*** binutils to release 2.9.1 or newer. Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
++
++_LT_EOF
++ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++
++ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
++ case `$LD -v 2>&1` in
++ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ cat <<_LT_EOF 1>&2
++
++*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
++*** reliably create shared libraries on SCO systems. Therefore, libtool
++*** is disabling shared libraries support. We urge you to upgrade GNU
++*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
++*** your PATH or compiler configuration so that the native linker is
++*** used, and then restart.
++
++_LT_EOF
++ ;;
++ *)
++ # For security reasons, it is highly recommended that you always
++ # use absolute paths for naming shared libraries, and exclude the
++ # DT_RUNPATH tag from executables and libraries. But doing so
++ # requires that you compile everything twice, which is a pain.
++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++ esac
++ ;;
++
++ sunos4*)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++ wlarc=
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ *)
++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++ esac
++
++ if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
++ runpath_var=
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
++ _LT_TAGVAR(whole_archive_flag_spec, $1)=
++ fi
++ else
++ # PORTME fill in a description of your system's linker (not GNU ld)
++ case $host_os in
++ aix3*)
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ _LT_TAGVAR(always_export_symbols, $1)=yes
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
++ # Note: this linker hardcodes the directories in LIBPATH if there
++ # are no directories specified by -L.
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
++ # Neither direct hardcoding nor static linking is supported with a
++ # broken collect2.
++ _LT_TAGVAR(hardcode_direct, $1)=unsupported
++ fi
++ ;;
++
++ aix[[4-9]]*)
++ if test "$host_cpu" = ia64; then
++ # On IA64, the linker does run time linking by default, so we don't
++ # have to do anything special.
++ aix_use_runtimelinking=no
++ exp_sym_flag='-Bexport'
++ no_entry_flag=""
++ else
++ # If we're using GNU nm, then we don't want the "-C" option.
++ # -C means demangle to AIX nm, but means don't demangle with GNU nm
++ # Also, AIX nm treats weak defined symbols like other global
++ # defined symbols, whereas GNU nm marks them as "W".
++ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++ else
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
++ fi
++ aix_use_runtimelinking=no
++
++ # Test if we are trying to use run time linking or normal
++ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
++ # need to do runtime linking.
++ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
++ for ld_flag in $LDFLAGS; do
++ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
++ aix_use_runtimelinking=yes
++ break
++ fi
++ done
++ ;;
++ esac
++
++ exp_sym_flag='-bexport'
++ no_entry_flag='-bnoentry'
++ fi
++
++ # When large executables or shared objects are built, AIX ld can
++ # have problems creating the table of contents. If linking a library
++ # or program results in "error TOC overflow" add -mminimal-toc to
++ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
++ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
++
++ _LT_TAGVAR(archive_cmds, $1)=''
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
++
++ if test "$GCC" = yes; then
++ case $host_os in aix4.[[012]]|aix4.[[012]].*)
++ # We only want to do this on AIX 4.2 and lower, the check
++ # below for broken collect2 doesn't work under 4.3+
++ collect2name=`${CC} -print-prog-name=collect2`
++ if test -f "$collect2name" &&
++ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
++ then
++ # We have reworked collect2
++ :
++ else
++ # We have old collect2
++ _LT_TAGVAR(hardcode_direct, $1)=unsupported
++ # It fails to find uninstalled libraries when the uninstalled
++ # path is not listed in the libpath. Setting hardcode_minus_L
++ # to unsupported forces relinking
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=
++ fi
++ ;;
++ esac
++ shared_flag='-shared'
++ if test "$aix_use_runtimelinking" = yes; then
++ shared_flag="$shared_flag "'${wl}-G'
++ fi
++ _LT_TAGVAR(link_all_deplibs, $1)=no
++ else
++ # not using gcc
++ if test "$host_cpu" = ia64; then
++ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
++ # chokes on -Wl,-G. The following line is correct:
++ shared_flag='-G'
++ else
++ if test "$aix_use_runtimelinking" = yes; then
++ shared_flag='${wl}-G'
++ else
++ shared_flag='${wl}-bM:SRE'
++ fi
++ fi
++ fi
++
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
++ # It seems that -bexpall does not export symbols beginning with
++ # underscore (_), so it is better to generate a list of symbols to export.
++ _LT_TAGVAR(always_export_symbols, $1)=yes
++ if test "$aix_use_runtimelinking" = yes; then
++ # Warning - without using the other runtime loading flags (-brtl),
++ # -berok will link without error, but may produce a broken library.
++ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
++ # Determine the default libpath from the value encoded in an
++ # empty executable.
++ _LT_SYS_MODULE_PATH_AIX([$1])
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++ else
++ if test "$host_cpu" = ia64; then
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
++ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
++ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
++ else
++ # Determine the default libpath from the value encoded in an
++ # empty executable.
++ _LT_SYS_MODULE_PATH_AIX([$1])
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++ # Warning - without using the other run time loading flags,
++ # -berok will link without error, but may produce a broken library.
++ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
++ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
++ if test "$with_gnu_ld" = yes; then
++ # We only use this code for GNU lds that support --whole-archive.
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
++ else
++ # Exported symbols can be pulled into shared objects from archives
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
++ fi
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++ # This is similar to how AIX traditionally builds its shared libraries.
++ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++ fi
++ fi
++ ;;
++
++ amigaos*)
++ case $host_cpu in
++ powerpc)
++ # see comment about AmigaOS4 .so support
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)=''
++ ;;
++ m68k)
++ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ ;;
++ esac
++ ;;
++
++ bsdi[[45]]*)
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
++ ;;
++
++ cygwin* | mingw* | pw32* | cegcc*)
++ # When not using gcc, we currently assume that we are using
++ # Microsoft Visual C++.
++ # hardcode_libdir_flag_spec is actually meaningless, as there is
++ # no search path for DLLs.
++ case $cc_basename in
++ cl*)
++ # Native MSVC
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ _LT_TAGVAR(always_export_symbols, $1)=yes
++ _LT_TAGVAR(file_list_spec, $1)='@'
++ # Tell ltmain to make .lib files, not .a files.
++ libext=lib
++ # Tell ltmain to make .dll files, not .so files.
++ shrext_cmds=".dll"
++ # FIXME: Setting linknames here is a bad hack.
++ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
++ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++ sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
++ else
++ sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
++ fi~
++ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
++ linknames='
++ # The linker will not automatically build a static lib if we build a DLL.
++ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
++ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
++ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
++ # Don't use ranlib
++ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
++ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
++ lt_tool_outputfile="@TOOL_OUTPUT@"~
++ case $lt_outputfile in
++ *.exe|*.EXE) ;;
++ *)
++ lt_outputfile="$lt_outputfile.exe"
++ lt_tool_outputfile="$lt_tool_outputfile.exe"
++ ;;
++ esac~
++ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
++ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
++ $RM "$lt_outputfile.manifest";
++ fi'
++ ;;
++ *)
++ # Assume MSVC wrapper
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ # Tell ltmain to make .lib files, not .a files.
++ libext=lib
++ # Tell ltmain to make .dll files, not .so files.
++ shrext_cmds=".dll"
++ # FIXME: Setting linknames here is a bad hack.
++ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
++ # The linker will automatically build a .lib file if we build a DLL.
++ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
++ # FIXME: Should let the user specify the lib program.
++ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
++ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++ ;;
++ esac
++ ;;
++
++ darwin* | rhapsody*)
++ _LT_DARWIN_LINKER_FEATURES($1)
++ ;;
++
++ dgux*)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
++ # support. Future versions do this automatically, but an explicit c++rt0.o
++ # does not break anything, and helps significantly (at the cost of a little
++ # extra space).
++ freebsd2.2*)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
++ freebsd2.*)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
++ freebsd* | dragonfly*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ hpux9*)
++ if test "$GCC" = yes; then
++ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++ fi
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++
++ # hardcode_minus_L: Not really in the search PATH,
++ # but as the default location of the library.
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++ ;;
++
++ hpux10*)
++ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
++ fi
++ if test "$with_gnu_ld" = no; then
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++ # hardcode_minus_L: Not really in the search PATH,
++ # but as the default location of the library.
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ fi
++ ;;
++
++ hpux11*)
++ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
++ case $host_cpu in
++ hppa*64*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ ia64*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ *)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ esac
++ else
++ case $host_cpu in
++ hppa*64*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ ia64*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ *)
++ m4_if($1, [], [
++ # Older versions of the 11.00 compiler do not understand -b yet
++ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
++ _LT_LINKER_OPTION([if $CC understands -b],
++ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
++ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
++ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
++ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
++ ;;
++ esac
++ fi
++ if test "$with_gnu_ld" = no; then
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++ case $host_cpu in
++ hppa*64*|ia64*)
++ _LT_TAGVAR(hardcode_direct, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++ *)
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++
++ # hardcode_minus_L: Not really in the search PATH,
++ # but as the default location of the library.
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ ;;
++ esac
++ fi
++ ;;
++
++ irix5* | irix6* | nonstopux*)
++ if test "$GCC" = yes; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ # Try to use the -exported_symbol ld option, if it does not
++ # work, assume that -exports_file does not work either and
++ # implicitly export all symbols.
++ # This should be the same for all languages, so no per-tag cache variable.
++ AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
++ [lt_cv_irix_exported_symbol],
++ [save_LDFLAGS="$LDFLAGS"
++ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
++ AC_LINK_IFELSE(
++ [AC_LANG_SOURCE(
++ [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
++ [C++], [[int foo (void) { return 0; }]],
++ [Fortran 77], [[
++ subroutine foo
++ end]],
++ [Fortran], [[
++ subroutine foo
++ end]])])],
++ [lt_cv_irix_exported_symbol=yes],
++ [lt_cv_irix_exported_symbol=no])
++ LDFLAGS="$save_LDFLAGS"])
++ if test "$lt_cv_irix_exported_symbol" = yes; then
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
++ fi
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
++ fi
++ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++ _LT_TAGVAR(inherit_rpath, $1)=yes
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ ;;
++
++ netbsd* | netbsdelf*-gnu)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
++ fi
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ newsos6)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ *nto* | *qnx*)
++ ;;
++
++ openbsd*)
++ if test -f /usr/libexec/ld.so; then
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++ else
++ case $host_os in
++ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++ ;;
++ *)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++ ;;
++ esac
++ fi
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++
++ os2*)
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
++ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
++ ;;
++
++ osf3*)
++ if test "$GCC" = yes; then
++ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ else
++ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++ fi
++ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++ ;;
++
++ osf4* | osf5*) # as osf3* with the addition of -msym flag
++ if test "$GCC" = yes; then
++ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ else
++ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
++ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
++
++ # Both c and cxx compiler support -rpath directly
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++ fi
++ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++ ;;
++
++ solaris*)
++ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
++ if test "$GCC" = yes; then
++ wlarc='${wl}'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
++ else
++ case `$CC -V 2>&1` in
++ *"Compilers 5.0"*)
++ wlarc=''
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
++ ;;
++ *)
++ wlarc='${wl}'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
++ ;;
++ esac
++ fi
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ case $host_os in
++ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++ *)
++ # The compiler driver will combine and reorder linker options,
++ # but understands `-z linker_flag'. GCC discards it without `$wl',
++ # but is careful enough not to reorder.
++ # Supported since Solaris 2.6 (maybe 2.5.1?)
++ if test "$GCC" = yes; then
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
++ else
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
++ fi
++ ;;
++ esac
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ ;;
++
++ sunos4*)
++ if test "x$host_vendor" = xsequent; then
++ # Use $CC to link under sequent, because it throws in some extra .o
++ # files that make .init and .fini sections work.
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
++ fi
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ sysv4)
++ case $host_vendor in
++ sni)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
++ ;;
++ siemens)
++ ## LD is ld it makes a PLAMLIB
++ ## CC just makes a GrossModule.
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
++ _LT_TAGVAR(hardcode_direct, $1)=no
++ ;;
++ motorola)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
++ ;;
++ esac
++ runpath_var='LD_RUN_PATH'
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ sysv4.3*)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
++ ;;
++
++ sysv4*MP*)
++ if test -d /usr/nec; then
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ runpath_var=LD_RUN_PATH
++ hardcode_runpath_var=yes
++ _LT_TAGVAR(ld_shlibs, $1)=yes
++ fi
++ ;;
++
++ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
++ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ runpath_var='LD_RUN_PATH'
++
++ if test "$GCC" = yes; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ fi
++ ;;
++
++ sysv5* | sco3.2v5* | sco5v6*)
++ # Note: We can NOT use -z defs as we might desire, because we do not
++ # link with -lc, and that would cause any symbols used from libc to
++ # always be unresolved, which means just about no library would
++ # ever link correctly. If we're not using GNU ld we use -z text
++ # though, which does catch some bad symbols but isn't as heavy-handed
++ # as -z defs.
++ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
++ runpath_var='LD_RUN_PATH'
++
++ if test "$GCC" = yes; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ fi
++ ;;
++
++ uts4*)
++ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++
++ *)
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ esac
++
++ if test x$host_vendor = xsni; then
++ case $host in
++ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
++ ;;
++ esac
++ fi
++ fi
++])
++AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
++test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
++
++_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
++
++_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
++_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
++_LT_DECL([], [extract_expsyms_cmds], [2],
++ [The commands to extract the exported symbol list from a shared archive])
++
++#
++# Do we need to explicitly link libc?
++#
++case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
++x|xyes)
++ # Assume -lc should be added
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++
++ if test "$enable_shared" = yes && test "$GCC" = yes; then
++ case $_LT_TAGVAR(archive_cmds, $1) in
++ *'~'*)
++ # FIXME: we may have to deal with multi-command sequences.
++ ;;
++ '$CC '*)
++ # Test whether the compiler implicitly links with -lc since on some
++ # systems, -lgcc has to come before -lc. If gcc already passes -lc
++ # to ld, don't add -lc before -lgcc.
++ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
++ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
++ [$RM conftest*
++ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
++
++ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
++ soname=conftest
++ lib=conftest
++ libobjs=conftest.$ac_objext
++ deplibs=
++ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
++ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
++ compiler_flags=-v
++ linker_flags=-v
++ verstring=
++ output_objdir=.
++ libname=conftest
++ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
++ _LT_TAGVAR(allow_undefined_flag, $1)=
++ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
++ then
++ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++ else
++ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++ fi
++ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
++ else
++ cat conftest.err 1>&5
++ fi
++ $RM conftest*
++ ])
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
++ ;;
++ esac
++ fi
++ ;;
++esac
++
++_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
++ [Whether or not to add -lc for building shared libraries])
++_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
++ [enable_shared_with_static_runtimes], [0],
++ [Whether or not to disallow shared libs when runtime libs are static])
++_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
++ [Compiler flag to allow reflexive dlopens])
++_LT_TAGDECL([], [whole_archive_flag_spec], [1],
++ [Compiler flag to generate shared objects directly from archives])
++_LT_TAGDECL([], [compiler_needs_object], [1],
++ [Whether the compiler copes with passing no objects directly])
++_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
++ [Create an old-style archive from a shared archive])
++_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
++ [Create a temporary old-style archive to link instead of a shared archive])
++_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
++_LT_TAGDECL([], [archive_expsym_cmds], [2])
++_LT_TAGDECL([], [module_cmds], [2],
++ [Commands used to build a loadable module if different from building
++ a shared archive.])
++_LT_TAGDECL([], [module_expsym_cmds], [2])
++_LT_TAGDECL([], [with_gnu_ld], [1],
++ [Whether we are building with GNU ld or not])
++_LT_TAGDECL([], [allow_undefined_flag], [1],
++ [Flag that allows shared libraries with undefined symbols to be built])
++_LT_TAGDECL([], [no_undefined_flag], [1],
++ [Flag that enforces no undefined symbols])
++_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
++ [Flag to hardcode $libdir into a binary during linking.
++ This must work even if $libdir does not exist])
++_LT_TAGDECL([], [hardcode_libdir_separator], [1],
++ [Whether we need a single "-rpath" flag with a separated argument])
++_LT_TAGDECL([], [hardcode_direct], [0],
++ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
++ DIR into the resulting binary])
++_LT_TAGDECL([], [hardcode_direct_absolute], [0],
++ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
++ DIR into the resulting binary and the resulting library dependency is
++ "absolute", i.e impossible to change by setting ${shlibpath_var} if the
++ library is relocated])
++_LT_TAGDECL([], [hardcode_minus_L], [0],
++ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
++ into the resulting binary])
++_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
++ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
++ into the resulting binary])
++_LT_TAGDECL([], [hardcode_automatic], [0],
++ [Set to "yes" if building a shared library automatically hardcodes DIR
++ into the library and all subsequent libraries and executables linked
++ against it])
++_LT_TAGDECL([], [inherit_rpath], [0],
++ [Set to yes if linker adds runtime paths of dependent libraries
++ to runtime path list])
++_LT_TAGDECL([], [link_all_deplibs], [0],
++ [Whether libtool must link a program against all its dependency libraries])
++_LT_TAGDECL([], [always_export_symbols], [0],
++ [Set to "yes" if exported symbols are required])
++_LT_TAGDECL([], [export_symbols_cmds], [2],
++ [The commands to list exported symbols])
++_LT_TAGDECL([], [exclude_expsyms], [1],
++ [Symbols that should not be listed in the preloaded symbols])
++_LT_TAGDECL([], [include_expsyms], [1],
++ [Symbols that must always be exported])
++_LT_TAGDECL([], [prelink_cmds], [2],
++ [Commands necessary for linking programs (against libraries) with templates])
++_LT_TAGDECL([], [postlink_cmds], [2],
++ [Commands necessary for finishing linking programs])
++_LT_TAGDECL([], [file_list_spec], [1],
++ [Specify filename containing input files])
++dnl FIXME: Not yet implemented
++dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
++dnl [Compiler flag to generate thread safe objects])
++])# _LT_LINKER_SHLIBS
++
++
++# _LT_LANG_C_CONFIG([TAG])
++# ------------------------
++# Ensure that the configuration variables for a C compiler are suitably
++# defined. These variables are subsequently used by _LT_CONFIG to write
++# the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_C_CONFIG],
++[m4_require([_LT_DECL_EGREP])dnl
++lt_save_CC="$CC"
++AC_LANG_PUSH(C)
++
++# Source file extension for C test sources.
++ac_ext=c
++
++# Object file extension for compiled C test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
++
++# Code to be used in simple compile tests
++lt_simple_compile_test_code="int some_variable = 0;"
++
++# Code to be used in simple link tests
++lt_simple_link_test_code='int main(){return(0);}'
++
++_LT_TAG_COMPILER
++# Save the default compiler, since it gets overwritten when the other
++# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
++compiler_DEFAULT=$CC
++
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
++
++## CAVEAT EMPTOR:
++## There is no encapsulation within the following macros, do not change
++## the running order or otherwise move them around unless you know exactly
++## what you are doing...
++if test -n "$compiler"; then
++ _LT_COMPILER_NO_RTTI($1)
++ _LT_COMPILER_PIC($1)
++ _LT_COMPILER_C_O($1)
++ _LT_COMPILER_FILE_LOCKS($1)
++ _LT_LINKER_SHLIBS($1)
++ _LT_SYS_DYNAMIC_LINKER($1)
++ _LT_LINKER_HARDCODE_LIBPATH($1)
++ LT_SYS_DLOPEN_SELF
++ _LT_CMD_STRIPLIB
++
++ # Report which library types will actually be built
++ AC_MSG_CHECKING([if libtool supports shared libraries])
++ AC_MSG_RESULT([$can_build_shared])
++
++ AC_MSG_CHECKING([whether to build shared libraries])
++ test "$can_build_shared" = "no" && enable_shared=no
++
++ # On AIX, shared libraries and static libraries use the same namespace, and
++ # are all built from PIC.
++ case $host_os in
++ aix3*)
++ test "$enable_shared" = yes && enable_static=no
++ if test -n "$RANLIB"; then
++ archive_cmds="$archive_cmds~\$RANLIB \$lib"
++ postinstall_cmds='$RANLIB $lib'
++ fi
++ ;;
++
++ aix[[4-9]]*)
++ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++ test "$enable_shared" = yes && enable_static=no
++ fi
++ ;;
++ esac
++ AC_MSG_RESULT([$enable_shared])
++
++ AC_MSG_CHECKING([whether to build static libraries])
++ # Make sure either enable_shared or enable_static is yes.
++ test "$enable_shared" = yes || enable_static=yes
++ AC_MSG_RESULT([$enable_static])
++
++ _LT_CONFIG($1)
++fi
++AC_LANG_POP
++CC="$lt_save_CC"
++])# _LT_LANG_C_CONFIG
++
++
++# _LT_LANG_CXX_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for a C++ compiler are suitably
++# defined. These variables are subsequently used by _LT_CONFIG to write
++# the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_CXX_CONFIG],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++m4_require([_LT_DECL_EGREP])dnl
++m4_require([_LT_PATH_MANIFEST_TOOL])dnl
++if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
++ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
++ (test "X$CXX" != "Xg++"))) ; then
++ AC_PROG_CXXCPP
++else
++ _lt_caught_CXX_error=yes
++fi
++
++AC_LANG_PUSH(C++)
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(compiler_needs_object, $1)=no
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(reload_flag, $1)=$reload_flag
++_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
++
++# Source file extension for C++ test sources.
++ac_ext=cpp
++
++# Object file extension for compiled C++ test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
++
++# No sense in running all these tests if we already determined that
++# the CXX compiler isn't working. Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_caught_CXX_error" != yes; then
++ # Code to be used in simple compile tests
++ lt_simple_compile_test_code="int some_variable = 0;"
++
++ # Code to be used in simple link tests
++ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
++
++ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++ _LT_TAG_COMPILER
++
++ # save warnings/boilerplate of simple test code
++ _LT_COMPILER_BOILERPLATE
++ _LT_LINKER_BOILERPLATE
++
++ # Allow CC to be a program name with arguments.
++ lt_save_CC=$CC
++ lt_save_CFLAGS=$CFLAGS
++ lt_save_LD=$LD
++ lt_save_GCC=$GCC
++ GCC=$GXX
++ lt_save_with_gnu_ld=$with_gnu_ld
++ lt_save_path_LD=$lt_cv_path_LD
++ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
++ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
++ else
++ $as_unset lt_cv_prog_gnu_ld
++ fi
++ if test -n "${lt_cv_path_LDCXX+set}"; then
++ lt_cv_path_LD=$lt_cv_path_LDCXX
++ else
++ $as_unset lt_cv_path_LD
++ fi
++ test -z "${LDCXX+set}" || LD=$LDCXX
++ CC=${CXX-"c++"}
++ CFLAGS=$CXXFLAGS
++ compiler=$CC
++ _LT_TAGVAR(compiler, $1)=$CC
++ _LT_CC_BASENAME([$compiler])
++
++ if test -n "$compiler"; then
++ # We don't want -fno-exception when compiling C++ code, so set the
++ # no_builtin_flag separately
++ if test "$GXX" = yes; then
++ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
++ else
++ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
++ fi
++
++ if test "$GXX" = yes; then
++ # Set up default GNU C++ configuration
++
++ LT_PATH_LD
++
++ # Check if GNU C++ uses GNU ld as the underlying linker, since the
++ # archiving commands below assume that GNU ld is being used.
++ if test "$with_gnu_ld" = yes; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++
++ # If archive_cmds runs LD, not CC, wlarc should be empty
++ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
++ # investigate it a little bit more. (MM)
++ wlarc='${wl}'
++
++ # ancient GNU ld didn't support --whole-archive et. al.
++ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
++ $GREP 'no-whole-archive' > /dev/null; then
++ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++ else
++ _LT_TAGVAR(whole_archive_flag_spec, $1)=
++ fi
++ else
++ with_gnu_ld=no
++ wlarc=
++
++ # A generic and very simple default shared library creation
++ # command for GNU C++ for the case where it uses the native
++ # linker, instead of GNU ld. If possible, this setting should
++ # overridden to take advantage of the native linker features on
++ # the platform it is being used on.
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
++ fi
++
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
++
++ else
++ GXX=no
++ with_gnu_ld=no
++ wlarc=
++ fi
++
++ # PORTME: fill in a description of your system's C++ link characteristics
++ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
++ _LT_TAGVAR(ld_shlibs, $1)=yes
++ case $host_os in
++ aix3*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ aix[[4-9]]*)
++ if test "$host_cpu" = ia64; then
++ # On IA64, the linker does run time linking by default, so we don't
++ # have to do anything special.
++ aix_use_runtimelinking=no
++ exp_sym_flag='-Bexport'
++ no_entry_flag=""
++ else
++ aix_use_runtimelinking=no
++
++ # Test if we are trying to use run time linking or normal
++ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
++ # need to do runtime linking.
++ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
++ for ld_flag in $LDFLAGS; do
++ case $ld_flag in
++ *-brtl*)
++ aix_use_runtimelinking=yes
++ break
++ ;;
++ esac
++ done
++ ;;
++ esac
++
++ exp_sym_flag='-bexport'
++ no_entry_flag='-bnoentry'
++ fi
++
++ # When large executables or shared objects are built, AIX ld can
++ # have problems creating the table of contents. If linking a library
++ # or program results in "error TOC overflow" add -mminimal-toc to
++ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
++ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
++
++ _LT_TAGVAR(archive_cmds, $1)=''
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
++
++ if test "$GXX" = yes; then
++ case $host_os in aix4.[[012]]|aix4.[[012]].*)
++ # We only want to do this on AIX 4.2 and lower, the check
++ # below for broken collect2 doesn't work under 4.3+
++ collect2name=`${CC} -print-prog-name=collect2`
++ if test -f "$collect2name" &&
++ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
++ then
++ # We have reworked collect2
++ :
++ else
++ # We have old collect2
++ _LT_TAGVAR(hardcode_direct, $1)=unsupported
++ # It fails to find uninstalled libraries when the uninstalled
++ # path is not listed in the libpath. Setting hardcode_minus_L
++ # to unsupported forces relinking
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=
++ fi
++ esac
++ shared_flag='-shared'
++ if test "$aix_use_runtimelinking" = yes; then
++ shared_flag="$shared_flag "'${wl}-G'
++ fi
++ else
++ # not using gcc
++ if test "$host_cpu" = ia64; then
++ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
++ # chokes on -Wl,-G. The following line is correct:
++ shared_flag='-G'
++ else
++ if test "$aix_use_runtimelinking" = yes; then
++ shared_flag='${wl}-G'
++ else
++ shared_flag='${wl}-bM:SRE'
++ fi
++ fi
++ fi
++
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
++ # It seems that -bexpall does not export symbols beginning with
++ # underscore (_), so it is better to generate a list of symbols to
++ # export.
++ _LT_TAGVAR(always_export_symbols, $1)=yes
++ if test "$aix_use_runtimelinking" = yes; then
++ # Warning - without using the other runtime loading flags (-brtl),
++ # -berok will link without error, but may produce a broken library.
++ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
++ # Determine the default libpath from the value encoded in an empty
++ # executable.
++ _LT_SYS_MODULE_PATH_AIX([$1])
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
++ else
++ if test "$host_cpu" = ia64; then
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
++ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
++ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
++ else
++ # Determine the default libpath from the value encoded in an
++ # empty executable.
++ _LT_SYS_MODULE_PATH_AIX([$1])
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
++ # Warning - without using the other run time loading flags,
++ # -berok will link without error, but may produce a broken library.
++ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
++ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
++ if test "$with_gnu_ld" = yes; then
++ # We only use this code for GNU lds that support --whole-archive.
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
++ else
++ # Exported symbols can be pulled into shared objects from archives
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
++ fi
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
++ # This is similar to how AIX traditionally builds its shared
++ # libraries.
++ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
++ fi
++ fi
++ ;;
++
++ beos*)
++ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
++ # support --undefined. This deserves some investigation. FIXME
++ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++
++ chorus*)
++ case $cc_basename in
++ *)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ esac
++ ;;
++
++ cygwin* | mingw* | pw32* | cegcc*)
++ case $GXX,$cc_basename in
++ ,cl* | no,cl*)
++ # Native MSVC
++ # hardcode_libdir_flag_spec is actually meaningless, as there is
++ # no search path for DLLs.
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ _LT_TAGVAR(always_export_symbols, $1)=yes
++ _LT_TAGVAR(file_list_spec, $1)='@'
++ # Tell ltmain to make .lib files, not .a files.
++ libext=lib
++ # Tell ltmain to make .dll files, not .so files.
++ shrext_cmds=".dll"
++ # FIXME: Setting linknames here is a bad hack.
++ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
++ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++ $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
++ else
++ $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
++ fi~
++ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
++ linknames='
++ # The linker will not automatically build a static lib if we build a DLL.
++ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
++ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++ # Don't use ranlib
++ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
++ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
++ lt_tool_outputfile="@TOOL_OUTPUT@"~
++ case $lt_outputfile in
++ *.exe|*.EXE) ;;
++ *)
++ lt_outputfile="$lt_outputfile.exe"
++ lt_tool_outputfile="$lt_tool_outputfile.exe"
++ ;;
++ esac~
++ func_to_tool_file "$lt_outputfile"~
++ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
++ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
++ $RM "$lt_outputfile.manifest";
++ fi'
++ ;;
++ *)
++ # g++
++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
++ # as there is no search path for DLLs.
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
++ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
++ _LT_TAGVAR(always_export_symbols, $1)=no
++ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
++
++ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++ # If the export-symbols file already is a .def file (1st line
++ # is EXPORTS), use it as is; otherwise, prepend...
++ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
++ cp $export_symbols $output_objdir/$soname.def;
++ else
++ echo EXPORTS > $output_objdir/$soname.def;
++ cat $export_symbols >> $output_objdir/$soname.def;
++ fi~
++ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++ esac
++ ;;
++ darwin* | rhapsody*)
++ _LT_DARWIN_LINKER_FEATURES($1)
++ ;;
++
++ dgux*)
++ case $cc_basename in
++ ec++*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ ghcx*)
++ # Green Hills C++ Compiler
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ *)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ esac
++ ;;
++
++ freebsd2.*)
++ # C++ shared libraries reported to be fairly broken before
++ # switch to ELF
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++
++ freebsd-elf*)
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++ ;;
++
++ freebsd* | dragonfly*)
++ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
++ # conventions
++ _LT_TAGVAR(ld_shlibs, $1)=yes
++ ;;
++
++ haiku*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ ;;
++
++ hpux9*)
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
++ # but as the default
++ # location of the library.
++
++ case $cc_basename in
++ CC*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ aCC*)
++ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ #
++ # There doesn't appear to be a way to prevent this compiler from
++ # explicitly linking system object files so we need to strip them
++ # from the output so that they don't get included in the library
++ # dependencies.
++ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
++ ;;
++ *)
++ if test "$GXX" = yes; then
++ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
++ else
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++ esac
++ ;;
++
++ hpux10*|hpux11*)
++ if test $with_gnu_ld = no; then
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++ case $host_cpu in
++ hppa*64*|ia64*)
++ ;;
++ *)
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++ ;;
++ esac
++ fi
++ case $host_cpu in
++ hppa*64*|ia64*)
++ _LT_TAGVAR(hardcode_direct, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ ;;
++ *)
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
++ # but as the default
++ # location of the library.
++ ;;
++ esac
++
++ case $cc_basename in
++ CC*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ aCC*)
++ case $host_cpu in
++ hppa*64*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++ ;;
++ ia64*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++ ;;
++ *)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++ ;;
++ esac
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ #
++ # There doesn't appear to be a way to prevent this compiler from
++ # explicitly linking system object files so we need to strip them
++ # from the output so that they don't get included in the library
++ # dependencies.
++ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
++ ;;
++ *)
++ if test "$GXX" = yes; then
++ if test $with_gnu_ld = no; then
++ case $host_cpu in
++ hppa*64*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++ ;;
++ ia64*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++ ;;
++ *)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++ ;;
++ esac
++ fi
++ else
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++ esac
++ ;;
++
++ interix[[3-9]]*)
++ _LT_TAGVAR(hardcode_direct, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
++ # Instead, shared libraries are loaded at an image base (0x10000000 by
++ # default) and relocated if they conflict, which is a slow very memory
++ # consuming and fragmenting process. To avoid this, we pick a random,
++ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
++ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
++ ;;
++ irix5* | irix6*)
++ case $cc_basename in
++ CC*)
++ # SGI C++
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++
++ # Archives containing C++ object files must be created using
++ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
++ # necessary to make sure instantiated templates are included
++ # in the archive.
++ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
++ ;;
++ *)
++ if test "$GXX" = yes; then
++ if test "$with_gnu_ld" = no; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ else
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
++ fi
++ fi
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ ;;
++ esac
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++ _LT_TAGVAR(inherit_rpath, $1)=yes
++ ;;
++
++ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
++ case $cc_basename in
++ KCC*)
++ # Kuck and Associates, Inc. (KAI) C++ Compiler
++
++ # KCC will only create a shared library if the output file
++ # ends with ".so" (or ".sl" for HP-UX), so rename the library
++ # to its proper name (with version) after linking.
++ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ #
++ # There doesn't appear to be a way to prevent this compiler from
++ # explicitly linking system object files so we need to strip them
++ # from the output so that they don't get included in the library
++ # dependencies.
++ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
++
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++
++ # Archives containing C++ object files must be created using
++ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
++ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
++ ;;
++ icpc* | ecpc* )
++ # Intel C++
++ with_gnu_ld=yes
++ # version 8.0 and above of icpc choke on multiply defined symbols
++ # if we add $predep_objects and $postdep_objects, however 7.1 and
++ # earlier do not add the objects themselves.
++ case `$CC -V 2>&1` in
++ *"Version 7."*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ ;;
++ *) # Version 8.0 or newer
++ tmp_idyn=
++ case $host_cpu in
++ ia64*) tmp_idyn=' -i_dynamic';;
++ esac
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
++ ;;
++ esac
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
++ ;;
++ pgCC* | pgcpp*)
++ # Portland Group C++ compiler
++ case `$CC -V` in
++ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
++ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
++ rm -rf $tpldir~
++ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
++ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
++ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
++ rm -rf $tpldir~
++ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
++ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
++ $RANLIB $oldlib'
++ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
++ rm -rf $tpldir~
++ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
++ rm -rf $tpldir~
++ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
++ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ ;;
++ *) # Version 6 and above use weak symbols
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
++ ;;
++ esac
++
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ ;;
++ cxx*)
++ # Compaq C++
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
++
++ runpath_var=LD_RUN_PATH
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ #
++ # There doesn't appear to be a way to prevent this compiler from
++ # explicitly linking system object files so we need to strip them
++ # from the output so that they don't get included in the library
++ # dependencies.
++ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
++ ;;
++ xl* | mpixl* | bgxl*)
++ # IBM XL 8.0 on PPC, with GNU ld
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
++ if test "x$supports_anon_versioning" = xyes; then
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
++ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
++ echo "local: *; };" >> $output_objdir/$libname.ver~
++ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
++ fi
++ ;;
++ *)
++ case `$CC -V 2>&1 | sed 5q` in
++ *Sun\ C*)
++ # Sun C++ 5.9
++ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
++ _LT_TAGVAR(compiler_needs_object, $1)=yes
++
++ # Not sure whether something based on
++ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
++ # would be better.
++ output_verbose_link_cmd='func_echo_all'
++
++ # Archives containing C++ object files must be created using
++ # "CC -xar", where "CC" is the Sun C++ compiler. This is
++ # necessary to make sure instantiated templates are included
++ # in the archive.
++ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
++ ;;
++ esac
++ ;;
++ esac
++ ;;
++
++ lynxos*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++
++ m88k*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++
++ mvs*)
++ case $cc_basename in
++ cxx*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ *)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ esac
++ ;;
++
++ netbsd*)
++ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
++ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
++ wlarc=
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ fi
++ # Workaround some broken pre-1.5 toolchains
++ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
++ ;;
++
++ *nto* | *qnx*)
++ _LT_TAGVAR(ld_shlibs, $1)=yes
++ ;;
++
++ openbsd2*)
++ # C++ shared libraries are fairly broken
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++
++ openbsd*)
++ if test -f /usr/libexec/ld.so; then
++ _LT_TAGVAR(hardcode_direct, $1)=yes
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
++ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
++ fi
++ output_verbose_link_cmd=func_echo_all
++ else
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++
++ osf3* | osf4* | osf5*)
++ case $cc_basename in
++ KCC*)
++ # Kuck and Associates, Inc. (KAI) C++ Compiler
++
++ # KCC will only create a shared library if the output file
++ # ends with ".so" (or ".sl" for HP-UX), so rename the library
++ # to its proper name (with version) after linking.
++ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
++
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++ # Archives containing C++ object files must be created using
++ # the KAI C++ compiler.
++ case $host in
++ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
++ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
++ esac
++ ;;
++ RCC*)
++ # Rational C++ 2.4.1
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ cxx*)
++ case $host in
++ osf3*)
++ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ ;;
++ *)
++ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
++ echo "-hidden">> $lib.exp~
++ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
++ $RM $lib.exp'
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
++ ;;
++ esac
++
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ #
++ # There doesn't appear to be a way to prevent this compiler from
++ # explicitly linking system object files so we need to strip them
++ # from the output so that they don't get included in the library
++ # dependencies.
++ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
++ ;;
++ *)
++ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
++ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
++ case $host in
++ osf3*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ ;;
++ *)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
++ ;;
++ esac
++
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
++
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
++
++ else
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ fi
++ ;;
++ esac
++ ;;
++
++ psos*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++
++ sunos4*)
++ case $cc_basename in
++ CC*)
++ # Sun C++ 4.x
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ lcc*)
++ # Lucid
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ *)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ esac
++ ;;
++
++ solaris*)
++ case $cc_basename in
++ CC* | sunCC*)
++ # Sun C++ 4.2, 5.x and Centerline C++
++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
++ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ case $host_os in
++ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++ *)
++ # The compiler driver will combine and reorder linker options,
++ # but understands `-z linker_flag'.
++ # Supported since Solaris 2.6 (maybe 2.5.1?)
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
++ ;;
++ esac
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++
++ output_verbose_link_cmd='func_echo_all'
++
++ # Archives containing C++ object files must be created using
++ # "CC -xar", where "CC" is the Sun C++ compiler. This is
++ # necessary to make sure instantiated templates are included
++ # in the archive.
++ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
++ ;;
++ gcx*)
++ # Green Hills C++ Compiler
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++
++ # The C++ compiler must be used to create the archive.
++ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
++ ;;
++ *)
++ # GNU C++ compiler with Solaris linker
++ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
++ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
++ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
++ else
++ # g++ 2.7 appears to require `-G' NOT `-shared' on this
++ # platform.
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
++ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
++
++ # Commands to make compiler produce verbose output that lists
++ # what "hidden" libraries, object files and flags are used when
++ # linking a shared library.
++ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
++ fi
++
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
++ case $host_os in
++ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
++ *)
++ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
++ ;;
++ esac
++ fi
++ ;;
++ esac
++ ;;
++
++ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
++ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ runpath_var='LD_RUN_PATH'
++
++ case $cc_basename in
++ CC*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ *)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ esac
++ ;;
++
++ sysv5* | sco3.2v5* | sco5v6*)
++ # Note: We can NOT use -z defs as we might desire, because we do not
++ # link with -lc, and that would cause any symbols used from libc to
++ # always be unresolved, which means just about no library would
++ # ever link correctly. If we're not using GNU ld we use -z text
++ # though, which does catch some bad symbols but isn't as heavy-handed
++ # as -z defs.
++ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
++ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
++ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
++ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
++ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
++ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
++ _LT_TAGVAR(link_all_deplibs, $1)=yes
++ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
++ runpath_var='LD_RUN_PATH'
++
++ case $cc_basename in
++ CC*)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
++ '"$_LT_TAGVAR(old_archive_cmds, $1)"
++ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
++ '"$_LT_TAGVAR(reload_cmds, $1)"
++ ;;
++ *)
++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
++ ;;
++ esac
++ ;;
++
++ tandem*)
++ case $cc_basename in
++ NCC*)
++ # NonStop-UX NCC 3.20
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ *)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ esac
++ ;;
++
++ vxworks*)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++
++ *)
++ # FIXME: insert proper C++ library support
++ _LT_TAGVAR(ld_shlibs, $1)=no
++ ;;
++ esac
++
++ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
++ test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
++
++ _LT_TAGVAR(GCC, $1)="$GXX"
++ _LT_TAGVAR(LD, $1)="$LD"
++
++ ## CAVEAT EMPTOR:
++ ## There is no encapsulation within the following macros, do not change
++ ## the running order or otherwise move them around unless you know exactly
++ ## what you are doing...
++ _LT_SYS_HIDDEN_LIBDEPS($1)
++ _LT_COMPILER_PIC($1)
++ _LT_COMPILER_C_O($1)
++ _LT_COMPILER_FILE_LOCKS($1)
++ _LT_LINKER_SHLIBS($1)
++ _LT_SYS_DYNAMIC_LINKER($1)
++ _LT_LINKER_HARDCODE_LIBPATH($1)
++
++ _LT_CONFIG($1)
++ fi # test -n "$compiler"
++
++ CC=$lt_save_CC
++ CFLAGS=$lt_save_CFLAGS
++ LDCXX=$LD
++ LD=$lt_save_LD
++ GCC=$lt_save_GCC
++ with_gnu_ld=$lt_save_with_gnu_ld
++ lt_cv_path_LDCXX=$lt_cv_path_LD
++ lt_cv_path_LD=$lt_save_path_LD
++ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
++ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
++fi # test "$_lt_caught_CXX_error" != yes
++
++AC_LANG_POP
++])# _LT_LANG_CXX_CONFIG
++
++
++# _LT_FUNC_STRIPNAME_CNF
++# ----------------------
++# func_stripname_cnf prefix suffix name
++# strip PREFIX and SUFFIX off of NAME.
++# PREFIX and SUFFIX must not contain globbing or regex special
++# characters, hashes, percent signs, but SUFFIX may contain a leading
++# dot (in which case that matches only a dot).
++#
++# This function is identical to the (non-XSI) version of func_stripname,
++# except this one can be used by m4 code that may be executed by configure,
++# rather than the libtool script.
++m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
++AC_REQUIRE([_LT_DECL_SED])
++AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
++func_stripname_cnf ()
++{
++ case ${2} in
++ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
++ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
++ esac
++} # func_stripname_cnf
++])# _LT_FUNC_STRIPNAME_CNF
++
++# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
++# ---------------------------------
++# Figure out "hidden" library dependencies from verbose
++# compiler output when linking a shared library.
++# Parse the compiler output and extract the necessary
++# objects, libraries and library flags.
++m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
++[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
++AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
++# Dependencies to place before and after the object being linked:
++_LT_TAGVAR(predep_objects, $1)=
++_LT_TAGVAR(postdep_objects, $1)=
++_LT_TAGVAR(predeps, $1)=
++_LT_TAGVAR(postdeps, $1)=
++_LT_TAGVAR(compiler_lib_search_path, $1)=
++
++dnl we can't use the lt_simple_compile_test_code here,
++dnl because it contains code intended for an executable,
++dnl not a library. It's possible we should let each
++dnl tag define a new lt_????_link_test_code variable,
++dnl but it's only used here...
++m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
++int a;
++void foo (void) { a = 0; }
++_LT_EOF
++], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
++class Foo
++{
++public:
++ Foo (void) { a = 0; }
++private:
++ int a;
++};
++_LT_EOF
++], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
++ subroutine foo
++ implicit none
++ integer*4 a
++ a=0
++ return
++ end
++_LT_EOF
++], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
++ subroutine foo
++ implicit none
++ integer a
++ a=0
++ return
++ end
++_LT_EOF
++], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
++public class foo {
++ private int a;
++ public void bar (void) {
++ a = 0;
++ }
++};
++_LT_EOF
++], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
++package foo
++func foo() {
++}
++_LT_EOF
++])
++
++_lt_libdeps_save_CFLAGS=$CFLAGS
++case "$CC $CFLAGS " in #(
++*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
++*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
++*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
++esac
++
++dnl Parse the compiler output and extract the necessary
++dnl objects, libraries and library flags.
++if AC_TRY_EVAL(ac_compile); then
++ # Parse the compiler output and extract the necessary
++ # objects, libraries and library flags.
++
++ # Sentinel used to keep track of whether or not we are before
++ # the conftest object file.
++ pre_test_object_deps_done=no
++
++ for p in `eval "$output_verbose_link_cmd"`; do
++ case ${prev}${p} in
++
++ -L* | -R* | -l*)
++ # Some compilers place space between "-{L,R}" and the path.
++ # Remove the space.
++ if test $p = "-L" ||
++ test $p = "-R"; then
++ prev=$p
++ continue
++ fi
++
++ # Expand the sysroot to ease extracting the directories later.
++ if test -z "$prev"; then
++ case $p in
++ -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
++ -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
++ -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
++ esac
++ fi
++ case $p in
++ =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
++ esac
++ if test "$pre_test_object_deps_done" = no; then
++ case ${prev} in
++ -L | -R)
++ # Internal compiler library paths should come after those
++ # provided the user. The postdeps already come after the
++ # user supplied libs so there is no need to process them.
++ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
++ _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
++ else
++ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
++ fi
++ ;;
++ # The "-l" case would never come before the object being
++ # linked, so don't bother handling this case.
++ esac
++ else
++ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
++ _LT_TAGVAR(postdeps, $1)="${prev}${p}"
++ else
++ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
++ fi
++ fi
++ prev=
++ ;;
++
++ *.lto.$objext) ;; # Ignore GCC LTO objects
++ *.$objext)
++ # This assumes that the test object file only shows up
++ # once in the compiler output.
++ if test "$p" = "conftest.$objext"; then
++ pre_test_object_deps_done=yes
++ continue
++ fi
++
++ if test "$pre_test_object_deps_done" = no; then
++ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
++ _LT_TAGVAR(predep_objects, $1)="$p"
++ else
++ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
++ fi
++ else
++ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
++ _LT_TAGVAR(postdep_objects, $1)="$p"
++ else
++ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
++ fi
++ fi
++ ;;
++
++ *) ;; # Ignore the rest.
++
++ esac
++ done
++
++ # Clean up.
++ rm -f a.out a.exe
++else
++ echo "libtool.m4: error: problem compiling $1 test program"
++fi
++
++$RM -f confest.$objext
++CFLAGS=$_lt_libdeps_save_CFLAGS
++
++# PORTME: override above test on systems where it is broken
++m4_if([$1], [CXX],
++[case $host_os in
++interix[[3-9]]*)
++ # Interix 3.5 installs completely hosed .la files for C++, so rather than
++ # hack all around it, let's just trust "g++" to DTRT.
++ _LT_TAGVAR(predep_objects,$1)=
++ _LT_TAGVAR(postdep_objects,$1)=
++ _LT_TAGVAR(postdeps,$1)=
++ ;;
++
++linux*)
++ case `$CC -V 2>&1 | sed 5q` in
++ *Sun\ C*)
++ # Sun C++ 5.9
++
++ # The more standards-conforming stlport4 library is
++ # incompatible with the Cstd library. Avoid specifying
++ # it if it's in CXXFLAGS. Ignore libCrun as
++ # -library=stlport4 depends on it.
++ case " $CXX $CXXFLAGS " in
++ *" -library=stlport4 "*)
++ solaris_use_stlport4=yes
++ ;;
++ esac
++
++ if test "$solaris_use_stlport4" != yes; then
++ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
++ fi
++ ;;
++ esac
++ ;;
++
++solaris*)
++ case $cc_basename in
++ CC* | sunCC*)
++ # The more standards-conforming stlport4 library is
++ # incompatible with the Cstd library. Avoid specifying
++ # it if it's in CXXFLAGS. Ignore libCrun as
++ # -library=stlport4 depends on it.
++ case " $CXX $CXXFLAGS " in
++ *" -library=stlport4 "*)
++ solaris_use_stlport4=yes
++ ;;
++ esac
++
++ # Adding this requires a known-good setup of shared libraries for
++ # Sun compiler versions before 5.6, else PIC objects from an old
++ # archive will be linked into the output, leading to subtle bugs.
++ if test "$solaris_use_stlport4" != yes; then
++ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
++ fi
++ ;;
++ esac
++ ;;
++esac
++])
++
++case " $_LT_TAGVAR(postdeps, $1) " in
++*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
++esac
++ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
++if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
++ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
++fi
++_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
++ [The directories searched by this compiler when creating a shared library])
++_LT_TAGDECL([], [predep_objects], [1],
++ [Dependencies to place before and after the objects being linked to
++ create a shared library])
++_LT_TAGDECL([], [postdep_objects], [1])
++_LT_TAGDECL([], [predeps], [1])
++_LT_TAGDECL([], [postdeps], [1])
++_LT_TAGDECL([], [compiler_lib_search_path], [1],
++ [The library search path used internally by the compiler when linking
++ a shared library])
++])# _LT_SYS_HIDDEN_LIBDEPS
++
++
++# _LT_LANG_F77_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for a Fortran 77 compiler are
++# suitably defined. These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_F77_CONFIG],
++[AC_LANG_PUSH(Fortran 77)
++if test -z "$F77" || test "X$F77" = "Xno"; then
++ _lt_disable_F77=yes
++fi
++
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(reload_flag, $1)=$reload_flag
++_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
++
++# Source file extension for f77 test sources.
++ac_ext=f
++
++# Object file extension for compiled f77 test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
++
++# No sense in running all these tests if we already determined that
++# the F77 compiler isn't working. Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_disable_F77" != yes; then
++ # Code to be used in simple compile tests
++ lt_simple_compile_test_code="\
++ subroutine t
++ return
++ end
++"
++
++ # Code to be used in simple link tests
++ lt_simple_link_test_code="\
++ program t
++ end
++"
++
++ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++ _LT_TAG_COMPILER
++
++ # save warnings/boilerplate of simple test code
++ _LT_COMPILER_BOILERPLATE
++ _LT_LINKER_BOILERPLATE
++
++ # Allow CC to be a program name with arguments.
++ lt_save_CC="$CC"
++ lt_save_GCC=$GCC
++ lt_save_CFLAGS=$CFLAGS
++ CC=${F77-"f77"}
++ CFLAGS=$FFLAGS
++ compiler=$CC
++ _LT_TAGVAR(compiler, $1)=$CC
++ _LT_CC_BASENAME([$compiler])
++ GCC=$G77
++ if test -n "$compiler"; then
++ AC_MSG_CHECKING([if libtool supports shared libraries])
++ AC_MSG_RESULT([$can_build_shared])
++
++ AC_MSG_CHECKING([whether to build shared libraries])
++ test "$can_build_shared" = "no" && enable_shared=no
++
++ # On AIX, shared libraries and static libraries use the same namespace, and
++ # are all built from PIC.
++ case $host_os in
++ aix3*)
++ test "$enable_shared" = yes && enable_static=no
++ if test -n "$RANLIB"; then
++ archive_cmds="$archive_cmds~\$RANLIB \$lib"
++ postinstall_cmds='$RANLIB $lib'
++ fi
++ ;;
++ aix[[4-9]]*)
++ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++ test "$enable_shared" = yes && enable_static=no
++ fi
++ ;;
++ esac
++ AC_MSG_RESULT([$enable_shared])
++
++ AC_MSG_CHECKING([whether to build static libraries])
++ # Make sure either enable_shared or enable_static is yes.
++ test "$enable_shared" = yes || enable_static=yes
++ AC_MSG_RESULT([$enable_static])
++
++ _LT_TAGVAR(GCC, $1)="$G77"
++ _LT_TAGVAR(LD, $1)="$LD"
++
++ ## CAVEAT EMPTOR:
++ ## There is no encapsulation within the following macros, do not change
++ ## the running order or otherwise move them around unless you know exactly
++ ## what you are doing...
++ _LT_COMPILER_PIC($1)
++ _LT_COMPILER_C_O($1)
++ _LT_COMPILER_FILE_LOCKS($1)
++ _LT_LINKER_SHLIBS($1)
++ _LT_SYS_DYNAMIC_LINKER($1)
++ _LT_LINKER_HARDCODE_LIBPATH($1)
++
++ _LT_CONFIG($1)
++ fi # test -n "$compiler"
++
++ GCC=$lt_save_GCC
++ CC="$lt_save_CC"
++ CFLAGS="$lt_save_CFLAGS"
++fi # test "$_lt_disable_F77" != yes
++
++AC_LANG_POP
++])# _LT_LANG_F77_CONFIG
++
++
++# _LT_LANG_FC_CONFIG([TAG])
++# -------------------------
++# Ensure that the configuration variables for a Fortran compiler are
++# suitably defined. These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_FC_CONFIG],
++[AC_LANG_PUSH(Fortran)
++
++if test -z "$FC" || test "X$FC" = "Xno"; then
++ _lt_disable_FC=yes
++fi
++
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++_LT_TAGVAR(allow_undefined_flag, $1)=
++_LT_TAGVAR(always_export_symbols, $1)=no
++_LT_TAGVAR(archive_expsym_cmds, $1)=
++_LT_TAGVAR(export_dynamic_flag_spec, $1)=
++_LT_TAGVAR(hardcode_direct, $1)=no
++_LT_TAGVAR(hardcode_direct_absolute, $1)=no
++_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
++_LT_TAGVAR(hardcode_libdir_separator, $1)=
++_LT_TAGVAR(hardcode_minus_L, $1)=no
++_LT_TAGVAR(hardcode_automatic, $1)=no
++_LT_TAGVAR(inherit_rpath, $1)=no
++_LT_TAGVAR(module_cmds, $1)=
++_LT_TAGVAR(module_expsym_cmds, $1)=
++_LT_TAGVAR(link_all_deplibs, $1)=unknown
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(reload_flag, $1)=$reload_flag
++_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
++_LT_TAGVAR(no_undefined_flag, $1)=
++_LT_TAGVAR(whole_archive_flag_spec, $1)=
++_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
++
++# Source file extension for fc test sources.
++ac_ext=${ac_fc_srcext-f}
++
++# Object file extension for compiled fc test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
++
++# No sense in running all these tests if we already determined that
++# the FC compiler isn't working. Some variables (like enable_shared)
++# are currently assumed to apply to all compilers on this platform,
++# and will be corrupted by setting them based on a non-working compiler.
++if test "$_lt_disable_FC" != yes; then
++ # Code to be used in simple compile tests
++ lt_simple_compile_test_code="\
++ subroutine t
++ return
++ end
++"
++
++ # Code to be used in simple link tests
++ lt_simple_link_test_code="\
++ program t
++ end
++"
++
++ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
++ _LT_TAG_COMPILER
++
++ # save warnings/boilerplate of simple test code
++ _LT_COMPILER_BOILERPLATE
++ _LT_LINKER_BOILERPLATE
++
++ # Allow CC to be a program name with arguments.
++ lt_save_CC="$CC"
++ lt_save_GCC=$GCC
++ lt_save_CFLAGS=$CFLAGS
++ CC=${FC-"f95"}
++ CFLAGS=$FCFLAGS
++ compiler=$CC
++ GCC=$ac_cv_fc_compiler_gnu
++
++ _LT_TAGVAR(compiler, $1)=$CC
++ _LT_CC_BASENAME([$compiler])
++
++ if test -n "$compiler"; then
++ AC_MSG_CHECKING([if libtool supports shared libraries])
++ AC_MSG_RESULT([$can_build_shared])
++
++ AC_MSG_CHECKING([whether to build shared libraries])
++ test "$can_build_shared" = "no" && enable_shared=no
++
++ # On AIX, shared libraries and static libraries use the same namespace, and
++ # are all built from PIC.
++ case $host_os in
++ aix3*)
++ test "$enable_shared" = yes && enable_static=no
++ if test -n "$RANLIB"; then
++ archive_cmds="$archive_cmds~\$RANLIB \$lib"
++ postinstall_cmds='$RANLIB $lib'
++ fi
++ ;;
++ aix[[4-9]]*)
++ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
++ test "$enable_shared" = yes && enable_static=no
++ fi
++ ;;
++ esac
++ AC_MSG_RESULT([$enable_shared])
++
++ AC_MSG_CHECKING([whether to build static libraries])
++ # Make sure either enable_shared or enable_static is yes.
++ test "$enable_shared" = yes || enable_static=yes
++ AC_MSG_RESULT([$enable_static])
++
++ _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
++ _LT_TAGVAR(LD, $1)="$LD"
++
++ ## CAVEAT EMPTOR:
++ ## There is no encapsulation within the following macros, do not change
++ ## the running order or otherwise move them around unless you know exactly
++ ## what you are doing...
++ _LT_SYS_HIDDEN_LIBDEPS($1)
++ _LT_COMPILER_PIC($1)
++ _LT_COMPILER_C_O($1)
++ _LT_COMPILER_FILE_LOCKS($1)
++ _LT_LINKER_SHLIBS($1)
++ _LT_SYS_DYNAMIC_LINKER($1)
++ _LT_LINKER_HARDCODE_LIBPATH($1)
++
++ _LT_CONFIG($1)
++ fi # test -n "$compiler"
++
++ GCC=$lt_save_GCC
++ CC=$lt_save_CC
++ CFLAGS=$lt_save_CFLAGS
++fi # test "$_lt_disable_FC" != yes
++
++AC_LANG_POP
++])# _LT_LANG_FC_CONFIG
++
++
++# _LT_LANG_GCJ_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for the GNU Java Compiler compiler
++# are suitably defined. These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_GCJ_CONFIG],
++[AC_REQUIRE([LT_PROG_GCJ])dnl
++AC_LANG_SAVE
++
++# Source file extension for Java test sources.
++ac_ext=java
++
++# Object file extension for compiled Java test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
++
++# Code to be used in simple compile tests
++lt_simple_compile_test_code="class foo {}"
++
++# Code to be used in simple link tests
++lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
++
++# ltmain only uses $CC for tagged configurations so make sure $CC is set.
++_LT_TAG_COMPILER
++
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
++
++# Allow CC to be a program name with arguments.
++lt_save_CC=$CC
++lt_save_CFLAGS=$CFLAGS
++lt_save_GCC=$GCC
++GCC=yes
++CC=${GCJ-"gcj"}
++CFLAGS=$GCJFLAGS
++compiler=$CC
++_LT_TAGVAR(compiler, $1)=$CC
++_LT_TAGVAR(LD, $1)="$LD"
++_LT_CC_BASENAME([$compiler])
++
++# GCJ did not exist at the time GCC didn't implicitly link libc in.
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(reload_flag, $1)=$reload_flag
++_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
++
++## CAVEAT EMPTOR:
++## There is no encapsulation within the following macros, do not change
++## the running order or otherwise move them around unless you know exactly
++## what you are doing...
++if test -n "$compiler"; then
++ _LT_COMPILER_NO_RTTI($1)
++ _LT_COMPILER_PIC($1)
++ _LT_COMPILER_C_O($1)
++ _LT_COMPILER_FILE_LOCKS($1)
++ _LT_LINKER_SHLIBS($1)
++ _LT_LINKER_HARDCODE_LIBPATH($1)
++
++ _LT_CONFIG($1)
++fi
++
++AC_LANG_RESTORE
++
++GCC=$lt_save_GCC
++CC=$lt_save_CC
++CFLAGS=$lt_save_CFLAGS
++])# _LT_LANG_GCJ_CONFIG
++
++
++# _LT_LANG_GO_CONFIG([TAG])
++# --------------------------
++# Ensure that the configuration variables for the GNU Go compiler
++# are suitably defined. These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_GO_CONFIG],
++[AC_REQUIRE([LT_PROG_GO])dnl
++AC_LANG_SAVE
++
++# Source file extension for Go test sources.
++ac_ext=go
++
++# Object file extension for compiled Go test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
++
++# Code to be used in simple compile tests
++lt_simple_compile_test_code="package main; func main() { }"
++
++# Code to be used in simple link tests
++lt_simple_link_test_code='package main; func main() { }'
++
++# ltmain only uses $CC for tagged configurations so make sure $CC is set.
++_LT_TAG_COMPILER
++
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
++
++# Allow CC to be a program name with arguments.
++lt_save_CC=$CC
++lt_save_CFLAGS=$CFLAGS
++lt_save_GCC=$GCC
++GCC=yes
++CC=${GOC-"gccgo"}
++CFLAGS=$GOFLAGS
++compiler=$CC
++_LT_TAGVAR(compiler, $1)=$CC
++_LT_TAGVAR(LD, $1)="$LD"
++_LT_CC_BASENAME([$compiler])
++
++# Go did not exist at the time GCC didn't implicitly link libc in.
++_LT_TAGVAR(archive_cmds_need_lc, $1)=no
++
++_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
++_LT_TAGVAR(reload_flag, $1)=$reload_flag
++_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
++
++## CAVEAT EMPTOR:
++## There is no encapsulation within the following macros, do not change
++## the running order or otherwise move them around unless you know exactly
++## what you are doing...
++if test -n "$compiler"; then
++ _LT_COMPILER_NO_RTTI($1)
++ _LT_COMPILER_PIC($1)
++ _LT_COMPILER_C_O($1)
++ _LT_COMPILER_FILE_LOCKS($1)
++ _LT_LINKER_SHLIBS($1)
++ _LT_LINKER_HARDCODE_LIBPATH($1)
++
++ _LT_CONFIG($1)
++fi
++
++AC_LANG_RESTORE
++
++GCC=$lt_save_GCC
++CC=$lt_save_CC
++CFLAGS=$lt_save_CFLAGS
++])# _LT_LANG_GO_CONFIG
++
++
++# _LT_LANG_RC_CONFIG([TAG])
++# -------------------------
++# Ensure that the configuration variables for the Windows resource compiler
++# are suitably defined. These variables are subsequently used by _LT_CONFIG
++# to write the compiler configuration to `libtool'.
++m4_defun([_LT_LANG_RC_CONFIG],
++[AC_REQUIRE([LT_PROG_RC])dnl
++AC_LANG_SAVE
++
++# Source file extension for RC test sources.
++ac_ext=rc
++
++# Object file extension for compiled RC test sources.
++objext=o
++_LT_TAGVAR(objext, $1)=$objext
++
++# Code to be used in simple compile tests
++lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
++
++# Code to be used in simple link tests
++lt_simple_link_test_code="$lt_simple_compile_test_code"
++
++# ltmain only uses $CC for tagged configurations so make sure $CC is set.
++_LT_TAG_COMPILER
++
++# save warnings/boilerplate of simple test code
++_LT_COMPILER_BOILERPLATE
++_LT_LINKER_BOILERPLATE
++
++# Allow CC to be a program name with arguments.
++lt_save_CC="$CC"
++lt_save_CFLAGS=$CFLAGS
++lt_save_GCC=$GCC
++GCC=
++CC=${RC-"windres"}
++CFLAGS=
++compiler=$CC
++_LT_TAGVAR(compiler, $1)=$CC
++_LT_CC_BASENAME([$compiler])
++_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
++
++if test -n "$compiler"; then
++ :
++ _LT_CONFIG($1)
++fi
++
++GCC=$lt_save_GCC
++AC_LANG_RESTORE
++CC=$lt_save_CC
++CFLAGS=$lt_save_CFLAGS
++])# _LT_LANG_RC_CONFIG
++
++
++# LT_PROG_GCJ
++# -----------
++AC_DEFUN([LT_PROG_GCJ],
++[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
++ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
++ [AC_CHECK_TOOL(GCJ, gcj,)
++ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
++ AC_SUBST(GCJFLAGS)])])[]dnl
++])
++
++# Old name:
++AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
++
++
++# LT_PROG_GO
++# ----------
++AC_DEFUN([LT_PROG_GO],
++[AC_CHECK_TOOL(GOC, gccgo,)
++])
++
++
++# LT_PROG_RC
++# ----------
++AC_DEFUN([LT_PROG_RC],
++[AC_CHECK_TOOL(RC, windres,)
++])
++
++# Old name:
++AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_RC], [])
++
++
++# _LT_DECL_EGREP
++# --------------
++# If we don't have a new enough Autoconf to choose the best grep
++# available, choose the one first in the user's PATH.
++m4_defun([_LT_DECL_EGREP],
++[AC_REQUIRE([AC_PROG_EGREP])dnl
++AC_REQUIRE([AC_PROG_FGREP])dnl
++test -z "$GREP" && GREP=grep
++_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
++_LT_DECL([], [EGREP], [1], [An ERE matcher])
++_LT_DECL([], [FGREP], [1], [A literal string matcher])
++dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
++AC_SUBST([GREP])
++])
++
++
++# _LT_DECL_OBJDUMP
++# --------------
++# If we don't have a new enough Autoconf to choose the best objdump
++# available, choose the one first in the user's PATH.
++m4_defun([_LT_DECL_OBJDUMP],
++[AC_CHECK_TOOL(OBJDUMP, objdump, false)
++test -z "$OBJDUMP" && OBJDUMP=objdump
++_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
++AC_SUBST([OBJDUMP])
++])
++
++# _LT_DECL_DLLTOOL
++# ----------------
++# Ensure DLLTOOL variable is set.
++m4_defun([_LT_DECL_DLLTOOL],
++[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
++test -z "$DLLTOOL" && DLLTOOL=dlltool
++_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
++AC_SUBST([DLLTOOL])
++])
++
++# _LT_DECL_SED
++# ------------
++# Check for a fully-functional sed program, that truncates
++# as few characters as possible. Prefer GNU sed if found.
++m4_defun([_LT_DECL_SED],
++[AC_PROG_SED
++test -z "$SED" && SED=sed
++Xsed="$SED -e 1s/^X//"
++_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
++_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
++ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
++])# _LT_DECL_SED
++
++m4_ifndef([AC_PROG_SED], [
++############################################################
++# NOTE: This macro has been submitted for inclusion into #
++# GNU Autoconf as AC_PROG_SED. When it is available in #
++# a released version of Autoconf we should remove this #
++# macro and use it instead. #
++############################################################
++
++m4_defun([AC_PROG_SED],
++[AC_MSG_CHECKING([for a sed that does not truncate output])
++AC_CACHE_VAL(lt_cv_path_SED,
++[# Loop through the user's path and test for sed and gsed.
++# Then use that list of sed's as ones to test for truncation.
++as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
++for as_dir in $PATH
++do
++ IFS=$as_save_IFS
++ test -z "$as_dir" && as_dir=.
++ for lt_ac_prog in sed gsed; do
++ for ac_exec_ext in '' $ac_executable_extensions; do
++ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
++ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
++ fi
++ done
++ done
++done
++IFS=$as_save_IFS
++lt_ac_max=0
++lt_ac_count=0
++# Add /usr/xpg4/bin/sed as it is typically found on Solaris
++# along with /bin/sed that truncates output.
++for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
++ test ! -f $lt_ac_sed && continue
++ cat /dev/null > conftest.in
++ lt_ac_count=0
++ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
++ # Check for GNU sed and select it if it is found.
++ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
++ lt_cv_path_SED=$lt_ac_sed
++ break
++ fi
++ while true; do
++ cat conftest.in conftest.in >conftest.tmp
++ mv conftest.tmp conftest.in
++ cp conftest.in conftest.nl
++ echo >>conftest.nl
++ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
++ cmp -s conftest.out conftest.nl || break
++ # 10000 chars as input seems more than enough
++ test $lt_ac_count -gt 10 && break
++ lt_ac_count=`expr $lt_ac_count + 1`
++ if test $lt_ac_count -gt $lt_ac_max; then
++ lt_ac_max=$lt_ac_count
++ lt_cv_path_SED=$lt_ac_sed
++ fi
++ done
++done
++])
++SED=$lt_cv_path_SED
++AC_SUBST([SED])
++AC_MSG_RESULT([$SED])
++])#AC_PROG_SED
++])#m4_ifndef
++
++# Old name:
++AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
++dnl aclocal-1.4 backwards compatibility:
++dnl AC_DEFUN([LT_AC_PROG_SED], [])
++
++
++# _LT_CHECK_SHELL_FEATURES
++# ------------------------
++# Find out whether the shell is Bourne or XSI compatible,
++# or has some other useful features.
++m4_defun([_LT_CHECK_SHELL_FEATURES],
++[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
++# Try some XSI features
++xsi_shell=no
++( _lt_dummy="a/b/c"
++ test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
++ = c,a/b,b/c, \
++ && eval 'test $(( 1 + 1 )) -eq 2 \
++ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
++ && xsi_shell=yes
++AC_MSG_RESULT([$xsi_shell])
++_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
++
++AC_MSG_CHECKING([whether the shell understands "+="])
++lt_shell_append=no
++( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
++ >/dev/null 2>&1 \
++ && lt_shell_append=yes
++AC_MSG_RESULT([$lt_shell_append])
++_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
++
++if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
++ lt_unset=unset
++else
++ lt_unset=false
++fi
++_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
++
++# test EBCDIC or ASCII
++case `echo X|tr X '\101'` in
++ A) # ASCII based system
++ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
++ lt_SP2NL='tr \040 \012'
++ lt_NL2SP='tr \015\012 \040\040'
++ ;;
++ *) # EBCDIC based system
++ lt_SP2NL='tr \100 \n'
++ lt_NL2SP='tr \r\n \100\100'
++ ;;
++esac
++_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
++_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
++])# _LT_CHECK_SHELL_FEATURES
++
++
++# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
++# ------------------------------------------------------
++# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
++# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
++m4_defun([_LT_PROG_FUNCTION_REPLACE],
++[dnl {
++sed -e '/^$1 ()$/,/^} # $1 /c\
++$1 ()\
++{\
++m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1])
++} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++test 0 -eq $? || _lt_function_replace_fail=:
++])
++
++
++# _LT_PROG_REPLACE_SHELLFNS
++# -------------------------
++# Replace existing portable implementations of several shell functions with
++# equivalent extended shell implementations where those features are available..
++m4_defun([_LT_PROG_REPLACE_SHELLFNS],
++[if test x"$xsi_shell" = xyes; then
++ _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
++ case ${1} in
++ */*) func_dirname_result="${1%/*}${2}" ;;
++ * ) func_dirname_result="${3}" ;;
++ esac])
++
++ _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
++ func_basename_result="${1##*/}"])
++
++ _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
++ case ${1} in
++ */*) func_dirname_result="${1%/*}${2}" ;;
++ * ) func_dirname_result="${3}" ;;
++ esac
++ func_basename_result="${1##*/}"])
++
++ _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
++ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
++ # positional parameters, so assign one to ordinary parameter first.
++ func_stripname_result=${3}
++ func_stripname_result=${func_stripname_result#"${1}"}
++ func_stripname_result=${func_stripname_result%"${2}"}])
++
++ _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
++ func_split_long_opt_name=${1%%=*}
++ func_split_long_opt_arg=${1#*=}])
++
++ _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
++ func_split_short_opt_arg=${1#??}
++ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
++
++ _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
++ case ${1} in
++ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
++ *) func_lo2o_result=${1} ;;
++ esac])
++
++ _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo])
++
++ _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))])
++
++ _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}])
++fi
++
++if test x"$lt_shell_append" = xyes; then
++ _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"])
++
++ _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
++ func_quote_for_eval "${2}"
++dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
++ eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
++
++ # Save a `func_append' function call where possible by direct use of '+='
++ sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++ test 0 -eq $? || _lt_function_replace_fail=:
++else
++ # Save a `func_append' function call even when '+=' is not available
++ sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
++ && mv -f "$cfgfile.tmp" "$cfgfile" \
++ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
++ test 0 -eq $? || _lt_function_replace_fail=:
++fi
++
++if test x"$_lt_function_replace_fail" = x":"; then
++ AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
++fi
++])
++
++# _LT_PATH_CONVERSION_FUNCTIONS
++# -----------------------------
++# Determine which file name conversion functions should be used by
++# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
++# for certain cross-compile configurations and native mingw.
++m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
++[AC_REQUIRE([AC_CANONICAL_HOST])dnl
++AC_REQUIRE([AC_CANONICAL_BUILD])dnl
++AC_MSG_CHECKING([how to convert $build file names to $host format])
++AC_CACHE_VAL(lt_cv_to_host_file_cmd,
++[case $host in
++ *-*-mingw* )
++ case $build in
++ *-*-mingw* ) # actually msys
++ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
++ ;;
++ *-*-cygwin* )
++ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
++ ;;
++ * ) # otherwise, assume *nix
++ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
++ ;;
++ esac
++ ;;
++ *-*-cygwin* )
++ case $build in
++ *-*-mingw* ) # actually msys
++ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
++ ;;
++ *-*-cygwin* )
++ lt_cv_to_host_file_cmd=func_convert_file_noop
++ ;;
++ * ) # otherwise, assume *nix
++ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
++ ;;
++ esac
++ ;;
++ * ) # unhandled hosts (and "normal" native builds)
++ lt_cv_to_host_file_cmd=func_convert_file_noop
++ ;;
++esac
++])
++to_host_file_cmd=$lt_cv_to_host_file_cmd
++AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
++_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
++ [0], [convert $build file names to $host format])dnl
++
++AC_MSG_CHECKING([how to convert $build file names to toolchain format])
++AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
++[#assume ordinary cross tools, or native build.
++lt_cv_to_tool_file_cmd=func_convert_file_noop
++case $host in
++ *-*-mingw* )
++ case $build in
++ *-*-mingw* ) # actually msys
++ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
++ ;;
++ esac
++ ;;
++esac
++])
++to_tool_file_cmd=$lt_cv_to_tool_file_cmd
++AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
++_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
++ [0], [convert $build files to toolchain format])dnl
++])# _LT_PATH_CONVERSION_FUNCTIONS
+--- /dev/null
++++ b/m4/ltversion.m4
+@@ -0,0 +1,23 @@
++# ltversion.m4 -- version numbers -*- Autoconf -*-
++#
++# Copyright (C) 2004 Free Software Foundation, Inc.
++# Written by Scott James Remnant, 2004
++#
++# This file is free software; the Free Software Foundation gives
++# unlimited permission to copy and/or distribute it, with or without
++# modifications, as long as this notice is preserved.
++
++# @configure_input@
++
++# serial 3337 ltversion.m4
++# This file is part of GNU Libtool
++
++m4_define([LT_PACKAGE_VERSION], [2.4.2])
++m4_define([LT_PACKAGE_REVISION], [1.3337])
++
++AC_DEFUN([LTVERSION_VERSION],
++[macro_version='2.4.2'
++macro_revision='1.3337'
++_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
++_LT_DECL(, macro_revision, 0)
++])
+--- /dev/null
++++ b/m4/ltsugar.m4
+@@ -0,0 +1,123 @@
++# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
++#
++# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
++# Written by Gary V. Vaughan, 2004
++#
++# This file is free software; the Free Software Foundation gives
++# unlimited permission to copy and/or distribute it, with or without
++# modifications, as long as this notice is preserved.
++
++# serial 6 ltsugar.m4
++
++# This is to help aclocal find these macros, as it can't see m4_define.
++AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
++
++
++# lt_join(SEP, ARG1, [ARG2...])
++# -----------------------------
++# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
++# associated separator.
++# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
++# versions in m4sugar had bugs.
++m4_define([lt_join],
++[m4_if([$#], [1], [],
++ [$#], [2], [[$2]],
++ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
++m4_define([_lt_join],
++[m4_if([$#$2], [2], [],
++ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
++
++
++# lt_car(LIST)
++# lt_cdr(LIST)
++# ------------
++# Manipulate m4 lists.
++# These macros are necessary as long as will still need to support
++# Autoconf-2.59 which quotes differently.
++m4_define([lt_car], [[$1]])
++m4_define([lt_cdr],
++[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
++ [$#], 1, [],
++ [m4_dquote(m4_shift($@))])])
++m4_define([lt_unquote], $1)
++
++
++# lt_append(MACRO-NAME, STRING, [SEPARATOR])
++# ------------------------------------------
++# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
++# Note that neither SEPARATOR nor STRING are expanded; they are appended
++# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
++# No SEPARATOR is output if MACRO-NAME was previously undefined (different
++# than defined and empty).
++#
++# This macro is needed until we can rely on Autoconf 2.62, since earlier
++# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
++m4_define([lt_append],
++[m4_define([$1],
++ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
++
++
++
++# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
++# ----------------------------------------------------------
++# Produce a SEP delimited list of all paired combinations of elements of
++# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
++# has the form PREFIXmINFIXSUFFIXn.
++# Needed until we can rely on m4_combine added in Autoconf 2.62.
++m4_define([lt_combine],
++[m4_if(m4_eval([$# > 3]), [1],
++ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
++[[m4_foreach([_Lt_prefix], [$2],
++ [m4_foreach([_Lt_suffix],
++ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
++ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
++
++
++# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
++# -----------------------------------------------------------------------
++# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
++# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
++m4_define([lt_if_append_uniq],
++[m4_ifdef([$1],
++ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
++ [lt_append([$1], [$2], [$3])$4],
++ [$5])],
++ [lt_append([$1], [$2], [$3])$4])])
++
++
++# lt_dict_add(DICT, KEY, VALUE)
++# -----------------------------
++m4_define([lt_dict_add],
++[m4_define([$1($2)], [$3])])
++
++
++# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
++# --------------------------------------------
++m4_define([lt_dict_add_subkey],
++[m4_define([$1($2:$3)], [$4])])
++
++
++# lt_dict_fetch(DICT, KEY, [SUBKEY])
++# ----------------------------------
++m4_define([lt_dict_fetch],
++[m4_ifval([$3],
++ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
++ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
++
++
++# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
++# -----------------------------------------------------------------
++m4_define([lt_if_dict_fetch],
++[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
++ [$5],
++ [$6])])
++
++
++# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
++# --------------------------------------------------------------
++m4_define([lt_dict_filter],
++[m4_if([$5], [], [],
++ [lt_join(m4_quote(m4_default([$4], [[, ]])),
++ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
++ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
++])
+--- /dev/null
++++ b/m4/lt~obsolete.m4
+@@ -0,0 +1,98 @@
++# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
++#
++# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
++# Written by Scott James Remnant, 2004.
++#
++# This file is free software; the Free Software Foundation gives
++# unlimited permission to copy and/or distribute it, with or without
++# modifications, as long as this notice is preserved.
++
++# serial 5 lt~obsolete.m4
++
++# These exist entirely to fool aclocal when bootstrapping libtool.
++#
++# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
++# which have later been changed to m4_define as they aren't part of the
++# exported API, or moved to Autoconf or Automake where they belong.
++#
++# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
++# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
++# using a macro with the same name in our local m4/libtool.m4 it'll
++# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
++# and doesn't know about Autoconf macros at all.)
++#
++# So we provide this file, which has a silly filename so it's always
++# included after everything else. This provides aclocal with the
++# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
++# because those macros already exist, or will be overwritten later.
++# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
++#
++# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
++# Yes, that means every name once taken will need to remain here until
++# we give up compatibility with versions before 1.7, at which point
++# we need to keep only those names which we still refer to.
++
++# This is to help aclocal find these macros, as it can't see m4_define.
++AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
++
++m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
++m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
++m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
++m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
++m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
++m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
++m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
++m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
++m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
++m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
++m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
++m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
++m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
++m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
++m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
++m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
++m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
++m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
++m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
++m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
++m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
++m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
++m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
++m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
++m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
++m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
++m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
++m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
++m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
++m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
++m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
++m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
++m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
++m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
++m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
++m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
++m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
++m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
++m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
++m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
++m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
++m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
++m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
++m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
++m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
++m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
++m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
++m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
++m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
++m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
++m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
++m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
++m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
++m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
++m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
++m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
++m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
++m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
++m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
++m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
++m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/debian/patches/02_firmware-package-builder.diff b/debian/patches/02_firmware-package-builder.diff
new file mode 100644
index 0000000..a398123
--- /dev/null
+++ b/debian/patches/02_firmware-package-builder.diff
@@ -0,0 +1,71 @@
+Description: template for firmware for Spyder2 device
+ Contains template for argyll-firmware-spyder2 package that may be created
+ by end user to distribute firmware for Spyder2 to multiple Debian systems
+Author: Roland Mas <lolando@debian.org>
+--- /dev/null
++++ b/firmware-package-builder/argyll-firmware-spyder2/debian/control
+@@ -0,0 +1,17 @@
++Source: argyll-firmware-spyder2
++Section: non-free/graphics
++Priority: optional
++Maintainer: Roland Mas <lolando@debian.org>
++Build-Depends: debhelper (>= 7)
++Standards-Version: 3.9.1
++
++Package: argyll-firmware-spyder2
++Architecture: all
++Recommends: argyll
++Depends: ${misc:Depends}
++Description: ColorVision Spyder2 firmware for Argyll
++ Argyll is an open source, ICC compatible color management system. It
++ can drive display calibrators such as the ColorVision Spyder2, which
++ requires a firmware to be uploaded to the device. This package is
++ generated from the drivers CD provided with the Spyder2, and contains
++ the firmware ready to be used by Argyll.
+--- /dev/null
++++ b/firmware-package-builder/argyll-firmware-spyder2/debian/rules
+@@ -0,0 +1,10 @@
++#! /usr/bin/make -f
++
++%:
++ dh $@
++
++override_dh_auto_build:
++ cp /usr/local/share/color/spyd2PLD.bin .
++
++override_dh_auto_clean:
++ rm -f spyd2PLD.bin
+--- /dev/null
++++ b/firmware-package-builder/argyll-firmware-spyder2/debian/changelog
+@@ -0,0 +1,12 @@
++argyll-firmware-spyder2 (1.1) unstable; urgency=low
++
++ * Moved firmware to /usr/share/color, which is freedesktop.org-compliant
++ and (more to the point) where Argyll 1.2.0 looks for it.
++
++ -- Roland Mas <lolando@debian.org> Thu, 05 Aug 2010 15:32:53 +0200
++
++argyll-firmware-spyder2 (1.0) unstable; urgency=low
++
++ * Package automatically generated from the Spyder2 driver CD.
++
++ -- Roland Mas <lolando@debian.org> Fri, 17 Apr 2009 22:28:37 +0200
+--- /dev/null
++++ b/firmware-package-builder/argyll-firmware-spyder2/debian/compat
+@@ -0,0 +1 @@
++7
+--- /dev/null
++++ b/firmware-package-builder/argyll-firmware-spyder2/debian/copyright
+@@ -0,0 +1,8 @@
++The binary package contains the proprietary firmware for the
++ColorVision Spyder2 device. As such, it is not meant to be
++distributed.
++
++The source package itself (which builds the binary package) is
++Copyright 2009, Roland Mas, and can be distributed under the terms of
++the GNU General Public License, version 2 or (at your option) any
++later version published by the Free Software Foundation.
+--- /dev/null
++++ b/firmware-package-builder/argyll-firmware-spyder2/debian/install
+@@ -0,0 +1 @@
++spyd2PLD.bin usr/share/color
diff --git a/debian/patches/03_kfreebsd.diff b/debian/patches/03_kfreebsd.diff
new file mode 100644
index 0000000..bbe7e5d
--- /dev/null
+++ b/debian/patches/03_kfreebsd.diff
@@ -0,0 +1,22 @@
+--- a/spectro/usbio.c
++++ b/spectro/usbio.c
+@@ -203,10 +203,6 @@ struct _icoms *p
+ #ifdef ENABLE_USB
+ struct usb_bus *bus;
+
+- /* Check that we've got an up to date version of libusb */
+- if (usb_argyll_patched() < 2)
+- error("usblib isn't up to date to work with this version of Argyll");
+-
+ if (p->debug > 8)
+ usb_set_debug(p->debug);
+
+@@ -738,7 +734,7 @@ char **pnames /* List of process names
+ if (libusb_get_device_descriptor(p->ppath->dev, &descriptor) != LIBUSB_SUCCESS)
+ error("Get device descriptor on USB port '%s' failed with %d (%s)",p->ppath->path,rv,libusb_strerror(rv));
+ #else
+- descriptor = dev->descriptor; /* Copy */
++ descriptor = p->ppath->dev->descriptor; /* Copy */
+ #endif
+
+ p->vid = p->ppath->vid;
diff --git a/debian/patches/03_usb-db.diff b/debian/patches/03_usb-db.diff
new file mode 100644
index 0000000..ebbc47b
--- /dev/null
+++ b/debian/patches/03_usb-db.diff
@@ -0,0 +1,15 @@
+Description: Use hwdb builtin, instead of the obsolete usb-db in the udev rules.
+Author: Dmitrijs Ledkovs <dmitrij.ledkov@ubuntu.com>
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/1200185
+Last-Update: 2014-02-03
+
+--- a/usb/55-Argyll.rules
++++ b/usb/55-Argyll.rules
+@@ -85,6 +85,6 @@ TEST=="/var/run/ConsoleKit/database", EN
+ ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}!="*?", MODE="660", GROUP="plugdev"
+
+ # Set ID_VENDOR and ID_MODEL acording to VID and PID
+-IMPORT{program}="usb-db %p"
++IMPORT{builtin}="hwdb --subsystem=usb"
+
+ LABEL="argyll_rules_end"
diff --git a/debian/patches/04_CVE-2012-4405.diff b/debian/patches/04_CVE-2012-4405.diff
new file mode 100644
index 0000000..60f7e48
--- /dev/null
+++ b/debian/patches/04_CVE-2012-4405.diff
@@ -0,0 +1,14 @@
+--- a/icc/icc.c
++++ b/icc/icc.c
+@@ -6348,6 +6348,11 @@ static int icmLut_read(
+ p->clutPoints = read_UInt8Number(bp+10);
+
+ /* Sanity check */
++ if (p->inputChan < 1) {
++ sprintf(icp->err,"icmLut_read: No input channels!");
++ return icp->errc = 1;
++ }
++
+ if (p->inputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_read: Can't handle > %d input channels\n",MAX_CHAN);
+ return icp->errc = 1;
diff --git a/debian/patches/05_external-yajl.diff b/debian/patches/05_external-yajl.diff
new file mode 100644
index 0000000..b77135a
--- /dev/null
+++ b/debian/patches/05_external-yajl.diff
@@ -0,0 +1,19 @@
+--- a/jcnf/jcnf.c
++++ b/jcnf/jcnf.c
+@@ -989,14 +989,15 @@ static jc_error jcnf_write(
+ }
+ }
+
++#ifdef NEVER
+ if (p->keys[i]->cpp_comment != NULL) {
+ yajl_gen_cpp_comment(g, p->keys[i]->cpp_comment, strlen(p->keys[i]->cpp_comment));
+ }
++
+ if (p->keys[i]->c_comment != NULL) {
+ yajl_gen_c_comment(g, p->keys[i]->c_comment, strlen(p->keys[i]->c_comment), 1);
+ }
+
+-#ifdef NEVER
+ yajl_gen_map_open(g);
+ yajl_gen_string(g, "test", strlen("test"));
+ yajl_gen_string(g, "test value", strlen("test value"));
diff --git a/debian/patches/06_fix_udev_rule.patch b/debian/patches/06_fix_udev_rule.patch
new file mode 100644
index 0000000..fb5c283
--- /dev/null
+++ b/debian/patches/06_fix_udev_rule.patch
@@ -0,0 +1,23 @@
+Description: Fix udev rules to actually work; ENV{ACL_MANAGE} has stopped working ages ago, and with logind it's now the "uaccess" tag.
+Author: Martin Pitt <martin.pitt@ubuntu.com>
+Bug-Ubuntu: https://launchpad.net/bugs/468345
+Last-Update: 2014-02-03
+
+--- a/usb/55-Argyll.rules
++++ b/usb/55-Argyll.rules
+@@ -77,12 +77,12 @@ ATTRS{idVendor}=="04d8", ATTRS{idProduct
+ ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+-# Let udev-acl manage these devices, if it's available
+-TEST=="/var/run/ConsoleKit/database", ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}="1"
++# Let users access these devices
++ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess"
+
+ # Otherwise, restrict access to members of the plugdev group,
+ # which the user may have to add to the system.
+-ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}!="*?", MODE="660", GROUP="plugdev"
++ENV{COLOR_MEASUREMENT_DEVICE}=="*?", MODE="660", GROUP="plugdev"
+
+ # Set ID_VENDOR and ID_MODEL acording to VID and PID
+ IMPORT{builtin}="hwdb --subsystem=usb"
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..ea92233
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,5 @@
+01_autotools-support.diff
+02_firmware-package-builder.diff
+03_usb-db.diff
+04_CVE-2012-4405.diff
+06_fix_udev_rule.patch
diff --git a/debian/pathplot.1 b/debian/pathplot.1
new file mode 100644
index 0000000..4abbda7
--- /dev/null
+++ b/debian/pathplot.1
@@ -0,0 +1,17 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH PLOT "1" "August 2013" "Plot device space path L in/out curve from an ICC link file, Version 1.5.1" "User Commands"
+.SH NAME
+Plot \- Plot device space path L in/out curve from an ICC link file.
+.SH DESCRIPTION
+Plot device space path L in/out curve from an ICC link file, Version 1.5.1
+Author: Graeme W. Gill
+usage: pathplot inprof linkprof outprof
+.TP
+\fB\-v\fR
+verbose
+.PP
+Author: Graeme W. Gill
+usage: pathplot inprof linkprof outprof
+.TP
+\fB\-v\fR
+verbose
diff --git a/debian/printcal.1 b/debian/printcal.1
new file mode 100644
index 0000000..93e0c5c
--- /dev/null
+++ b/debian/printcal.1
@@ -0,0 +1,153 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create printer calibration, Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create printer calibration.
+.SH DESCRIPTION
+Create printer calibration, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Too few arguments, got 1 expect at least 2
+.PP
+usage: debian/tmp/usr/bin/printcal [\-options] [prevcal] inoutfile
+.TP
+\fB\-v\fR verbosity
+Verbose mode
+.TP
+\fB\-p\fR
+Plot graphs.
+.TP
+\fB\-i\fR
+Initial calibration, set targets, create .cal
+.TP
+\fB\-r\fR
+Re\-calibrate against previous .cal and create new .cal
+.TP
+\fB\-e\fR
+Verify against previous .cal
+.TP
+\fB\-I\fR
+Create imitation target from .ti3 and null calibration
+.TP
+\fB\-d\fR
+Go through the motions but don't write any files
+.TP
+\fB\-s\fR smoothing
+Extra curve smoothing (default 1.0)
+.HP
+\fB\-A\fR manufacturer Set the manufacturer description string
+.TP
+\fB\-M\fR model
+Set the model description string
+.TP
+\fB\-D\fR description
+Set the profile Description string
+.TP
+\fB\-C\fR copyright
+Set the copyright string
+.TP
+\fB\-x\fR# percent
+Set initial maximum device % target (override auto)
+.TP
+\fB\-m\fR# percent
+Set initial dev target to % of auto maximum
+.TP
+\fB\-n\fR# deltaE
+Set initial white minimum deltaE target
+.TP
+\fB\-t\fR# percent
+Set initial 50% transfer curve percentage target
+.TP
+# = c, r, 0
+First channel
+.TP
+m, g, 1
+Second channel
+.TP
+y, b, 2
+Third channel
+.TP
+k,
+3 Fourth channel, etc.
+.TP
+\fB\-a\fR
+Create an Adobe Photoshop .AMP file as well as a .cal
+.TP
+prevcal
+Base name of previous .cal file for recal or verify.
+.TP
+inoutname
+Base name of input .ti3 file, output .cal file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Too few arguments, got 1 expect at least 2
+.PP
+usage: debian/tmp/usr/bin/printcal [\-options] [prevcal] inoutfile
+.TP
+\fB\-v\fR verbosity
+Verbose mode
+.TP
+\fB\-p\fR
+Plot graphs.
+.TP
+\fB\-i\fR
+Initial calibration, set targets, create .cal
+.TP
+\fB\-r\fR
+Re\-calibrate against previous .cal and create new .cal
+.TP
+\fB\-e\fR
+Verify against previous .cal
+.TP
+\fB\-I\fR
+Create imitation target from .ti3 and null calibration
+.TP
+\fB\-d\fR
+Go through the motions but don't write any files
+.TP
+\fB\-s\fR smoothing
+Extra curve smoothing (default 1.0)
+.HP
+\fB\-A\fR manufacturer Set the manufacturer description string
+.TP
+\fB\-M\fR model
+Set the model description string
+.TP
+\fB\-D\fR description
+Set the profile Description string
+.TP
+\fB\-C\fR copyright
+Set the copyright string
+.TP
+\fB\-x\fR# percent
+Set initial maximum device % target (override auto)
+.TP
+\fB\-m\fR# percent
+Set initial dev target to % of auto maximum
+.TP
+\fB\-n\fR# deltaE
+Set initial white minimum deltaE target
+.TP
+\fB\-t\fR# percent
+Set initial 50% transfer curve percentage target
+.TP
+# = c, r, 0
+First channel
+.TP
+m, g, 1
+Second channel
+.TP
+y, b, 2
+Third channel
+.TP
+k,
+3 Fourth channel, etc.
+.TP
+\fB\-a\fR
+Create an Adobe Photoshop .AMP file as well as a .cal
+.TP
+prevcal
+Base name of previous .cal file for recal or verify.
+.TP
+inoutname
+Base name of input .ti3 file, output .cal file
diff --git a/debian/printtarg.1 b/debian/printtarg.1
new file mode 100644
index 0000000..bad9f5a
--- /dev/null
+++ b/debian/printtarg.1
@@ -0,0 +1,243 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH GENERATE "1" "August 2013" "Generate Target PostScrip file, Version 1.5.1" "User Commands"
+.SH NAME
+Generate \- Generate Target PostScrip file.
+.SH DESCRIPTION
+Generate Target PostScrip file, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Unknown flag
+.PP
+usage: printtarg [\-v] [\-i instr] [\-r] [\-s] [\-p size] basename
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-i\fR 20 | 22 | 41 | 51 | SS | i1 | CM Select target instrument (default DTP41)
+.IP
+20 = DTP20, 22 = DTP22, 41 = DTP41, 51 = DTP51,
+SS = SpectroScan, i1 = i1Pro, CM = ColorMunki
+.TP
+\fB\-h\fR
+Use hexagon patches for SS, double density for CM
+.TP
+\fB\-a\fR scale
+Scale patch size and spacers by factor (e.g. 0.857 or 1.5 etc.)
+.TP
+\fB\-A\fR scale
+Scale spacers by additional factor (e.g. 0.857 or 1.5 etc.)
+.TP
+\fB\-r\fR
+Don't randomize patch location
+.TP
+\fB\-s\fR
+Create a scan image recognition (.cht) file
+.TP
+\fB\-S\fR
+Same as \fB\-s\fR, but don't generate wide orientation strip.
+.TP
+\fB\-c\fR
+Force colored spacers
+.TP
+\fB\-b\fR
+Force B&W spacers
+.TP
+\fB\-n\fR
+Force no spacers
+.TP
+\fB\-f\fR
+Create PostScript DeviceN Color fallback
+.TP
+\fB\-w\fR g|r|s|n
+White colorspace encoding DeviceGray (def), DeviceRGB, Separation or DeviceN
+.TP
+\fB\-k\fR g|c|s|n
+Black colorspace encoding DeviceGray (def), DeviceCMYK, Separation or DeviceN
+.TP
+\fB\-o\fR k|r|n
+CMY colorspace encoding DefiveCMYK (def), inverted DeviceRGB or DeviceN
+.TP
+\fB\-e\fR
+Output EPS compatible file
+.TP
+\fB\-t\fR [res]
+Output 8 bit TIFF raster file, optional res DPI (default 100)
+.TP
+\fB\-T\fR [res]
+Output 16 bit TIFF raster file, optional res DPI (default 100)
+.TP
+\fB\-C\fR
+Don't use TIFF compression
+.TP
+\fB\-N\fR
+Use TIFF alpha N channels more than 4
+.TP
+\fB\-D\fR
+Dither 8 bit TIFF values down from 16 bit
+.TP
+\fB\-Q\fR nbits
+Quantize test values to fit in nbits
+.TP
+\fB\-R\fR rsnum
+Use given random start number
+.TP
+\fB\-K\fR file.cal
+Apply printer calibration to patch values and include in .ti2
+.TP
+\fB\-I\fR file.cal
+Include calibration in .ti2 (but don't apply it)
+.TP
+\fB\-x\fR pattern
+Use given strip indexing pattern (Default = "A\-Z, A\-Z")
+.TP
+\fB\-y\fR pattern
+Use given patch indexing pattern (Default = "0\-9,@\-9,@\-9;1\-999")
+.TP
+\fB\-m\fR margin
+Set a page margin in mm (default 6.0 mm)
+.TP
+\fB\-M\fR margin
+Set a page margin in mm and include it in TIFF
+.TP
+\fB\-P\fR
+Don't limit strip length
+.TP
+\fB\-L\fR
+Suppress any left paper clip border
+.TP
+\fB\-p\fR size
+Select page size from:
+A4 [210.0 x 297.0 mm]
+A4R [297.0 x 210.0 mm]
+A3 [297.0 x 420.0 mm] (default)
+A2 [420.0 x 594.0 mm]
+Letter [215.9 x 279.4 mm]
+LetterR [279.4 x 215.9 mm]
+Legal [215.9 x 355.6 mm]
+4x6 [101.6 x 152.4 mm]
+11x17 [279.4 x 431.8 mm]
+.TP
+\fB\-p\fR WWWxHHH
+Custom size, WWW mm wide by HHH mm high
+.TP
+basname
+Base name for input(.ti1), output(.ti2) and output(.ps/.eps/.tif)
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.IP
+Diagnostic: Unknown flag
+.PP
+usage: printtarg [\-v] [\-i instr] [\-r] [\-s] [\-p size] basename
+.TP
+\fB\-v\fR
+Verbose mode
+.HP
+\fB\-i\fR 20 | 22 | 41 | 51 | SS | i1 | CM Select target instrument (default DTP41)
+.IP
+20 = DTP20, 22 = DTP22, 41 = DTP41, 51 = DTP51,
+SS = SpectroScan, i1 = i1Pro, CM = ColorMunki
+.TP
+\fB\-h\fR
+Use hexagon patches for SS, double density for CM
+.TP
+\fB\-a\fR scale
+Scale patch size and spacers by factor (e.g. 0.857 or 1.5 etc.)
+.TP
+\fB\-A\fR scale
+Scale spacers by additional factor (e.g. 0.857 or 1.5 etc.)
+.TP
+\fB\-r\fR
+Don't randomize patch location
+.TP
+\fB\-s\fR
+Create a scan image recognition (.cht) file
+.TP
+\fB\-S\fR
+Same as \fB\-s\fR, but don't generate wide orientation strip.
+.TP
+\fB\-c\fR
+Force colored spacers
+.TP
+\fB\-b\fR
+Force B&W spacers
+.TP
+\fB\-n\fR
+Force no spacers
+.TP
+\fB\-f\fR
+Create PostScript DeviceN Color fallback
+.TP
+\fB\-w\fR g|r|s|n
+White colorspace encoding DeviceGray (def), DeviceRGB, Separation or DeviceN
+.TP
+\fB\-k\fR g|c|s|n
+Black colorspace encoding DeviceGray (def), DeviceCMYK, Separation or DeviceN
+.TP
+\fB\-o\fR k|r|n
+CMY colorspace encoding DefiveCMYK (def), inverted DeviceRGB or DeviceN
+.TP
+\fB\-e\fR
+Output EPS compatible file
+.TP
+\fB\-t\fR [res]
+Output 8 bit TIFF raster file, optional res DPI (default 100)
+.TP
+\fB\-T\fR [res]
+Output 16 bit TIFF raster file, optional res DPI (default 100)
+.TP
+\fB\-C\fR
+Don't use TIFF compression
+.TP
+\fB\-N\fR
+Use TIFF alpha N channels more than 4
+.TP
+\fB\-D\fR
+Dither 8 bit TIFF values down from 16 bit
+.TP
+\fB\-Q\fR nbits
+Quantize test values to fit in nbits
+.TP
+\fB\-R\fR rsnum
+Use given random start number
+.TP
+\fB\-K\fR file.cal
+Apply printer calibration to patch values and include in .ti2
+.TP
+\fB\-I\fR file.cal
+Include calibration in .ti2 (but don't apply it)
+.TP
+\fB\-x\fR pattern
+Use given strip indexing pattern (Default = "A\-Z, A\-Z")
+.TP
+\fB\-y\fR pattern
+Use given patch indexing pattern (Default = "0\-9,@\-9,@\-9;1\-999")
+.TP
+\fB\-m\fR margin
+Set a page margin in mm (default 6.0 mm)
+.TP
+\fB\-M\fR margin
+Set a page margin in mm and include it in TIFF
+.TP
+\fB\-P\fR
+Don't limit strip length
+.TP
+\fB\-L\fR
+Suppress any left paper clip border
+.TP
+\fB\-p\fR size
+Select page size from:
+A4 [210.0 x 297.0 mm]
+A4R [297.0 x 210.0 mm]
+A3 [297.0 x 420.0 mm] (default)
+A2 [420.0 x 594.0 mm]
+Letter [215.9 x 279.4 mm]
+LetterR [279.4 x 215.9 mm]
+Legal [215.9 x 355.6 mm]
+4x6 [101.6 x 152.4 mm]
+11x17 [279.4 x 431.8 mm]
+.TP
+\fB\-p\fR WWWxHHH
+Custom size, WWW mm wide by HHH mm high
+.TP
+basname
+Base name for input(.ti1), output(.ti2) and output(.ps/.eps/.tif)
diff --git a/debian/profcheck.1 b/debian/profcheck.1
new file mode 100644
index 0000000..d6d974d
--- /dev/null
+++ b/debian/profcheck.1
@@ -0,0 +1,115 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CHECK "1" "August 2013" "Check accuracy of ICC profile, Version 1.5.1" "User Commands"
+.SH NAME
+Check \- Check accuracy of ICC profile.
+.SH DESCRIPTION
+Check accuracy of ICC profile, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: profcheck [\-options] data.ti3 iccprofile.icm
+.TP
+\fB\-v\fR [level]
+Verbosity level (default 1), 2 to print each DE
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-w\fR
+create VRML visualisation (iccprofile.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-m\fR
+Make VRML lines a minimum of 0.5
+.TP
+\fB\-e\fR
+Color vectors acording to delta E
+.HP
+\fB\-d\fR devval1,deval2,devvalN
+.IP
+Specify a device value to sort against
+.TP
+\fB\-p\fR
+Sort device value by PCS (Lab) target
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-I\fR intent
+r = relative colorimetric, a = absolute (default)
+.TP
+data.ti3
+Test data file
+.TP
+iccprofile.icm
+Profile to check against
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: profcheck [\-options] data.ti3 iccprofile.icm
+.TP
+\fB\-v\fR [level]
+Verbosity level (default 1), 2 to print each DE
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-w\fR
+create VRML visualisation (iccprofile.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-m\fR
+Make VRML lines a minimum of 0.5
+.TP
+\fB\-e\fR
+Color vectors acording to delta E
+.HP
+\fB\-d\fR devval1,deval2,devvalN
+.IP
+Specify a device value to sort against
+.TP
+\fB\-p\fR
+Sort device value by PCS (Lab) target
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-I\fR intent
+r = relative colorimetric, a = absolute (default)
+.TP
+data.ti3
+Test data file
+.TP
+iccprofile.icm
+Profile to check against
diff --git a/debian/refine.1 b/debian/refine.1
new file mode 100644
index 0000000..ad63ddf
--- /dev/null
+++ b/debian/refine.1
@@ -0,0 +1,109 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create abstract correction profile given table of absolute CIE correction values, Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create abstract correction profile given table of absolute CIE correction values.
+.SH DESCRIPTION
+Create abstract correction profile given table of absolute CIE correction values, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Too few arguments
+usage: refine [\-options] cietarget ciecurrent [outdevicc] [inabs] outabs
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-c\fR
+Create initial abstract correction profile
+.TP
+\fB\-g\fR
+Don't impose output device gamut limit
+.TP
+\fB\-r\fR res
+Set abstract profile clut resolution (default 33)
+.TP
+\fB\-d\fR factor
+Override default damping factor (default 0.950000, then 0.700000)
+.TP
+\fB\-R\fR
+Aim for white point relative match rather than absolute
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+cietarget
+Target CIE or spectral values, CGATS file (e.g. .ti3)
+.TP
+ciecurrent
+Actual CIE or spectral values, CGATS file (e.g. .ti3)
+.TP
+[outdevicc]
+Output device ICC profile to set gamut limit (not used if \fB\-g\fR)
+.TP
+[inabs]
+Previous abstract correction ICC profile (not used if \fB\-c\fR)
+.TP
+outabs
+Created/refined abstract correction ICC profile
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Too few arguments
+usage: refine [\-options] cietarget ciecurrent [outdevicc] [inabs] outabs
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-c\fR
+Create initial abstract correction profile
+.TP
+\fB\-g\fR
+Don't impose output device gamut limit
+.TP
+\fB\-r\fR res
+Set abstract profile clut resolution (default 33)
+.TP
+\fB\-d\fR factor
+Override default damping factor (default 0.950000, then 0.700000)
+.TP
+\fB\-R\fR
+Aim for white point relative match rather than absolute
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+cietarget
+Target CIE or spectral values, CGATS file (e.g. .ti3)
+.TP
+ciecurrent
+Actual CIE or spectral values, CGATS file (e.g. .ti3)
+.TP
+[outdevicc]
+Output device ICC profile to set gamut limit (not used if \fB\-g\fR)
+.TP
+[inabs]
+Previous abstract correction ICC profile (not used if \fB\-c\fR)
+.TP
+outabs
+Created/refined abstract correction ICC profile
diff --git a/debian/revfix.1 b/debian/revfix.1
new file mode 100644
index 0000000..334215b
--- /dev/null
+++ b/debian/revfix.1
@@ -0,0 +1,91 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH INVERT "1" "August 2013" "Invert AtoB1 to make BtoA1 for CMYK profiles, Version 1.5.1" "User Commands"
+.SH NAME
+Invert \- Invert AtoB1 to make BtoA1 for CMYK profiles.
+.SH DESCRIPTION
+Invert AtoB1 to make BtoA1 for CMYK profiles, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: revfix [\-options] iccin iccout
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-0\fR
+Process perceptual
+.TP
+\fB\-1\fR
+Process absolute/relative colorimetric
+.TP
+\fB\-2\fR
+Process saturation
+.TP
+\fB\-r\fR res
+Override BtoA1 Clut res
+.TP
+\fB\-k\fR [ezhxr]
+e = same K as existing BtoA table (def)
+z = zero, h = 0.5 K, x = max K, r = ramp K
+.HP
+\fB\-k\fR p stle stpo enle enpo shape
+.IP
+p = curve parameters
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-p\fR absprof
+Include abstract profile in output tables
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: revfix [\-options] iccin iccout
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-0\fR
+Process perceptual
+.TP
+\fB\-1\fR
+Process absolute/relative colorimetric
+.TP
+\fB\-2\fR
+Process saturation
+.TP
+\fB\-r\fR res
+Override BtoA1 Clut res
+.TP
+\fB\-k\fR [ezhxr]
+e = same K as existing BtoA table (def)
+z = zero, h = 0.5 K, x = max K, r = ramp K
+.HP
+\fB\-k\fR p stle stpo enle enpo shape
+.IP
+p = curve parameters
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-p\fR absprof
+Include abstract profile in output tables
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..54eca76
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,125 @@
+#!/usr/bin/make -f
+
+export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed -Wl,--no-undefined
+
+####CC:=ccache $(CC)
+
+%:
+ dh $@ --with quilt,autoreconf
+
+# Doesn't work for now.
+#--parallel
+
+override_dh_auto_configure:
+ chmod +x ./configure
+
+ dh_auto_configure -- \
+ CC="$(CC)"
+
+override_dh_autoreconf:
+ dh_autoreconf --as-needed
+
+override_dh_auto_clean:
+ dh_clean imdi/imdi_k.c ref/RefMediumGamut.gam \
+ libusb/Makefile libusb/config.h libusb/config.log libusb/usb.h \
+ libusb/config.status libusb/doc/Makefile libusb/libtool \
+ libusb/libusb-config libusb/libusb.pc libusb/stamp-h1 \
+ libusb/tests/Makefile firmware-package-builder/*.tar.gz
+
+ [ ! $(shell grep jam Makefile) ] || rm Makefile
+
+ [ ! -f Makefile ] || $(MAKE) distclean
+
+ find -name Makefile.in | xargs -r rm
+
+override_dh_auto_install: firmware-package-builder/spyder2.tar.gz
+ $(MAKE) install -i DESTDIR=$(CURDIR)/debian/tmp
+ $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
+
+ rm debian/tmp/usr/share/doc/argyll/DocLicense.txt
+ rm debian/tmp/usr/share/doc/argyll/License.txt
+
+ -rm `find $(CURDIR)/debian/tmp -name '*.la'`
+
+override_dh_install:
+ dh_install -X.a -X.la --fail-missing
+
+# for i in $$(cat debian/libicc2.install debian/libicc-dev.install) ; do rm -f $(CURDIR)/debian/argyll/$$i ; done
+# rm $(CURDIR)/debian/argyll/usr/share/doc/argyll/License.txt $(CURDIR)/debian/argyll/usr/share/doc/argyll/DocLicense.txt
+# for i in average refine targen verify ; do mv $(CURDIR)/debian/argyll/usr/bin/$$i $(CURDIR)/debian/argyll/usr/bin/argyll-$$i ; done
+
+override_dh_installchangelogs:
+ dh_installchangelogs log.txt
+
+LIBICC_VERSION=$(shell awk -F= '/^LIBICC_VERSION=/ { print $$2 }' icc/Makefile.am)
+ARGYLL_VERSION=$(shell dpkg-parsechangelog | awk '/^Version:/ { print $$2 }')
+
+override_dh_gencontrol:
+ dh_gencontrol -plibicc2 -- -v$(LIBICC_VERSION)+argyll$(ARGYLL_VERSION)
+ dh_gencontrol -plibicc-dev -- -v$(LIBICC_VERSION)+argyll$(ARGYLL_VERSION)
+ dh_gencontrol --remaining-packages
+
+#build: firmware-package-builder/spyder2.tar.gz
+
+firmware-package-builder/%.tar.gz: firmware-package-builder/argyll-firmware-%
+ chmod +x $</debian/rules
+ tar cfCz $@ firmware-package-builder $(notdir $<)
+
+override_dh_strip:
+ dh_strip --dbg-package=argyll-dbg
+
+override_dh_makeshlibs:
+ dh_makeshlibs -- -c4
+
+override_dh_builddeb:
+ dh_builddeb -- -Zbzip2
+
+build-manpages:
+ help2man -N --no-discard-stderr --name="Dump an ICC file in human readable form." debian/tmp/usr/bin/iccdump > debian/iccdump.1
+ help2man -N --no-discard-stderr --name="Translate colors through an ICC profile." debian/tmp/usr/bin/icclu > debian/icclu.1
+ help2man -N --no-discard-stderr --name="Apply device calibration to an ICC profile." debian/tmp/usr/bin/applycal > debian/applycal.1
+ help2man -N --no-discard-stderr --name="Average or merge values in .ti3 like files." debian/tmp/usr/bin/average > debian/average.1
+ help2man -N --no-discard-stderr --name="Convert Colorblind raw device profile data to Argyll data." debian/tmp/usr/bin/cb2ti3 > debian/cb2ti3.1
+ help2man -N --no-discard-stderr --name="Color Correct a TIFF file using any sequence of ICC profiles or Calibrations." debian/tmp/usr/bin/cctiff > debian/cctiff.1
+ help2man -N --no-discard-stderr --name="Plot spectrum and calculate CCT and VCT." debian/tmp/usr/bin/ccttest > debian/ccttest.1
+ help2man -N --no-discard-stderr --name="Create CCMX or CCSS." debian/tmp/usr/bin/ccxxmake > debian/ccxxmake.1
+ help2man -N --no-discard-stderr --name="Read Target Test Chart." debian/tmp/usr/bin/chartread > debian/chartread.1
+ help2man -N --no-discard-stderr --name="Link ICC profiles." debian/tmp/usr/bin/collink > debian/collink.1
+ help2man -N --no-discard-stderr --name="Create ICC profile." debian/tmp/usr/bin/colprof > debian/colprof.1
+ help2man -N --no-discard-stderr --name="Calibrate a Display." debian/tmp/usr/bin/dispcal > debian/dispcal.1
+ help2man -N --no-discard-stderr --name="Read a Display." debian/tmp/usr/bin/dispread > debian/dispread.1
+ help2man -N --no-discard-stderr --name="Test display patch window, Set Video LUTs, Install profiles." debian/tmp/usr/bin/dispwin > debian/dispwin.1
+ help2man -N --no-discard-stderr --name="Extract an ICC profile from a TIFF file." debian/tmp/usr/bin/extracticc > debian/extracticc.1
+ help2man -N --no-discard-stderr --name="Extract a text tag from an ICC profile." debian/tmp/usr/bin/extractttag > debian/extractttag.1
+ help2man -N --no-discard-stderr --name="Create a fake CMY data file from a CMYK profile." debian/tmp/usr/bin/fakeCMY > debian/fakeCMY.1
+ help2man -N --no-discard-stderr --name="Fake test chart reader - lookup values in ICC/MPP profile." debian/tmp/usr/bin/fakeread > debian/fakeread.1
+ help2man -N --no-discard-stderr --name="Convert a TIFF file to monochrome using an ICC device profile." debian/tmp/usr/bin/greytiff > debian/greytiff.1
+ help2man -N --no-discard-stderr --name="Dump an ICC file in human readable form." debian/tmp/usr/bin/iccdump > debian/iccdump.1
+ help2man -N --no-discard-stderr --name="Create Lab/Jab gamut plot." debian/tmp/usr/bin/iccgamut > debian/iccgamut.1
+ help2man -N --no-discard-stderr --name="Measure an illuminant." debian/tmp/usr/bin/illumread > debian/illumread.1
+ help2man -N --no-discard-stderr --name="Check fwd to bwd relative transfer of an ICC file." debian/tmp/usr/bin/invprofcheck > debian/invprofcheck.1
+ help2man -N --no-discard-stderr --name="Convert Kodak raw printer profile data to Argyll print data." debian/tmp/usr/bin/kodak2ti3 > debian/kodak2ti3.1
+ help2man -N --no-discard-stderr --name="Check Model Printer Profile." debian/tmp/usr/bin/mppcheck > debian/mppcheck.1
+ help2man -N --no-discard-stderr --name="Translate colors through an MPP profile." debian/tmp/usr/bin/mpplu > debian/mpplu.1
+ help2man -N --no-discard-stderr --name="Create Model Printer Profile." debian/tmp/usr/bin/mppprof > debian/mppprof.1
+ help2man -N --no-discard-stderr --name="Plot device space path L in/out curve from an ICC link file." debian/tmp/usr/bin/pathplot > debian/pathplot.1
+ help2man -N --no-discard-stderr --name="Create printer calibration." debian/tmp/usr/bin/printcal > debian/printcal.1
+ help2man -N --no-discard-stderr --name="Generate Target PostScrip file." debian/tmp/usr/bin/printtarg > debian/printtarg.1
+ help2man -N --no-discard-stderr --name="Check accuracy of ICC profile." debian/tmp/usr/bin/profcheck > debian/profcheck.1
+ help2man -N --no-discard-stderr --name="Create abstract correction profile given table of absolute CIE correction values." debian/tmp/usr/bin/refine > debian/refine.1
+ help2man -N --no-discard-stderr --name="Invert AtoB1 to make BtoA1 for CMYK profiles." debian/tmp/usr/bin/revfix > debian/revfix.1
+ help2man -N --no-discard-stderr --name="Scanin." debian/tmp/usr/bin/scanin > debian/scanin.1
+ help2man -N --no-discard-stderr --name="Create Simple CMYK Device Profile." debian/tmp/usr/bin/simpprof > debian/simpprof.1
+ help2man -N --no-discard-stderr --name="Convert spectral .ti3 file." debian/tmp/usr/bin/spec2cie > debian/spec2cie.1
+ help2man -N --no-discard-stderr --name="Plot spectrum and calculate CCT and VCT." debian/tmp/usr/bin/specplot > debian/specplot.1
+ help2man -N --no-discard-stderr --name="Split a .ti3 into two." debian/tmp/usr/bin/splitti3 > debian/splitti3.1
+ help2man -N --no-discard-stderr --name="Read Print Spot values." debian/tmp/usr/bin/spotread > debian/spotread.1
+ help2man -N --no-discard-stderr --name="Create a synthetic calibration file." debian/tmp/usr/bin/synthcal > debian/synthcal.1
+ help2man -N --no-discard-stderr --name="Synthetic device model test chart reader." debian/tmp/usr/bin/synthread > debian/synthread.1
+ help2man -N --no-discard-stderr --name="Generate Target deviceb test chart color values." debian/tmp/usr/bin/targen > debian/targen.1
+ help2man -N --no-discard-stderr --name="Create VRML image of the gamut surface of a TIFF." debian/tmp/usr/bin/tiffgamut > debian/tiffgamut.1
+ help2man -N --no-discard-stderr --name="Convert Gretag/Logo or X-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data." debian/tmp/usr/bin/txt2ti3 > debian/txt2ti3.1
+ help2man -N --no-discard-stderr --name="Verify CIE values." debian/tmp/usr/bin/verify > debian/verify.1
+ help2man -N --no-discard-stderr --name="View gamuts." debian/tmp/usr/bin/viewgam > debian/viewgam.1
+ help2man -N --no-discard-stderr --name="Translate colors through an xicc." debian/tmp/usr/bin/xicclu > debian/xicclu.1
+ help2man -N --no-discard-stderr --name="List information about the FILEs." debian/tmp/usr/bin/oeminst > debian/oeminst.1
diff --git a/debian/scanin.1 b/debian/scanin.1
new file mode 100644
index 0000000..e107ae8
--- /dev/null
+++ b/debian/scanin.1
@@ -0,0 +1,215 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH SCANIN, "1" "August 2013" "Scanin, Version 1.5.1" "User Commands"
+.SH NAME
+Scanin, \- Scanin.
+.SH DESCRIPTION
+Scanin, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.PP
+usage: scanin [options] input.tif recogin.cht valin.cie [diag.tif]
+.IP
+:\- inputs 'input.tif' and outputs scanner 'input.ti3', or
+.PP
+usage: scanin \fB\-g\fR [options] input.tif recogout.cht [diag.tif]
+.IP
+:\- outputs file 'recogout.cht', or
+.PP
+usage: scanin \fB\-o\fR [options] input.tif recogin.cht [diag.tif]
+.IP
+:\- outputs file 'input.val', or
+.PP
+usage: scanin \fB\-c\fR [options] input.tif recogin.cht scanprofile.[icc|mpp] pbase [diag.tif]
+.IP
+:\- inputs pbase.ti2 and outputs printer pbase.ti3, or
+.PP
+usage: scanin \fB\-r\fR [options] input.tif recogin.cht pbase [diag.tif]
+.IP
+:\- inputs pbase.ti2+.ti3 and outputs pbase.ti3
+.TP
+\fB\-g\fR
+Generate a chart reference (.cht) file
+.TP
+\fB\-o\fR
+Output patch values in .val file
+.TP
+\fB\-c\fR
+Use image to measure color to convert printer pbase .ti2 to .ti3
+.TP
+\fB\-ca\fR
+Same as \fB\-c\fR, but accumulates more values to pbase .ti3
+from subsequent pages
+.TP
+\fB\-r\fR
+Replace device values in pbase .ti2/.ti3
+Default is to create a scanner .ti3 file
+.TP
+\fB\-F\fR x1,y1,x2,y2,x3,y3,x4,y4
+Don't auto recognize, locate using four fiducual marks
+.TP
+\fB\-p\fR
+Compensate for perspective distortion
+.TP
+\fB\-a\fR
+Recognise chart in normal orientation only (\fB\-A\fR fallback as is)
+Default is to recognise all possible chart angles
+.TP
+\fB\-m\fR
+Return true mean (default is robust mean)
+.TP
+\fB\-G\fR gamma
+Approximate gamma encoding of image
+.TP
+\fB\-v\fR [n]
+Verbosity level 0\-9
+.TP
+\fB\-d\fR [ihvglLIcrsonap]
+Generate diagnostic output (try \fB\-dipn\fR)
+.TP
+i
+diag \- B&W of input image
+.TP
+h
+diag \- Horizontal edge/tick detection
+.TP
+v
+diag \- Vertical edge/tick detection
+.TP
+g
+diag \- Groups detected
+.TP
+l
+diag \- Lines detected
+.TP
+L
+diag \- All lines detected
+.TP
+I
+diag \- lines used to improve fit
+.TP
+c
+diag \- lines perspective corrected
+.TP
+r
+diag \- lines rotated
+.TP
+s
+diag \- diagnostic sample boxes rotated
+.TP
+o
+diag \- sample box outlines
+.TP
+n
+diag \- sample box names
+.TP
+a
+diag \- sample box areas
+.TP
+p
+diag \- pixel areas sampled
+.HP
+\fB\-O\fR outputfile Override the default output filename & extension.
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+.PP
+usage: scanin [options] input.tif recogin.cht valin.cie [diag.tif]
+.IP
+:\- inputs 'input.tif' and outputs scanner 'input.ti3', or
+.PP
+usage: scanin \fB\-g\fR [options] input.tif recogout.cht [diag.tif]
+.IP
+:\- outputs file 'recogout.cht', or
+.PP
+usage: scanin \fB\-o\fR [options] input.tif recogin.cht [diag.tif]
+.IP
+:\- outputs file 'input.val', or
+.PP
+usage: scanin \fB\-c\fR [options] input.tif recogin.cht scanprofile.[icc|mpp] pbase [diag.tif]
+.IP
+:\- inputs pbase.ti2 and outputs printer pbase.ti3, or
+.PP
+usage: scanin \fB\-r\fR [options] input.tif recogin.cht pbase [diag.tif]
+.IP
+:\- inputs pbase.ti2+.ti3 and outputs pbase.ti3
+.TP
+\fB\-g\fR
+Generate a chart reference (.cht) file
+.TP
+\fB\-o\fR
+Output patch values in .val file
+.TP
+\fB\-c\fR
+Use image to measure color to convert printer pbase .ti2 to .ti3
+.TP
+\fB\-ca\fR
+Same as \fB\-c\fR, but accumulates more values to pbase .ti3
+from subsequent pages
+.TP
+\fB\-r\fR
+Replace device values in pbase .ti2/.ti3
+Default is to create a scanner .ti3 file
+.TP
+\fB\-F\fR x1,y1,x2,y2,x3,y3,x4,y4
+Don't auto recognize, locate using four fiducual marks
+.TP
+\fB\-p\fR
+Compensate for perspective distortion
+.TP
+\fB\-a\fR
+Recognise chart in normal orientation only (\fB\-A\fR fallback as is)
+Default is to recognise all possible chart angles
+.TP
+\fB\-m\fR
+Return true mean (default is robust mean)
+.TP
+\fB\-G\fR gamma
+Approximate gamma encoding of image
+.TP
+\fB\-v\fR [n]
+Verbosity level 0\-9
+.TP
+\fB\-d\fR [ihvglLIcrsonap]
+Generate diagnostic output (try \fB\-dipn\fR)
+.TP
+i
+diag \- B&W of input image
+.TP
+h
+diag \- Horizontal edge/tick detection
+.TP
+v
+diag \- Vertical edge/tick detection
+.TP
+g
+diag \- Groups detected
+.TP
+l
+diag \- Lines detected
+.TP
+L
+diag \- All lines detected
+.TP
+I
+diag \- lines used to improve fit
+.TP
+c
+diag \- lines perspective corrected
+.TP
+r
+diag \- lines rotated
+.TP
+s
+diag \- diagnostic sample boxes rotated
+.TP
+o
+diag \- sample box outlines
+.TP
+n
+diag \- sample box names
+.TP
+a
+diag \- sample box areas
+.TP
+p
+diag \- pixel areas sampled
+.HP
+\fB\-O\fR outputfile Override the default output filename & extension.
diff --git a/debian/simpprof.1 b/debian/simpprof.1
new file mode 100644
index 0000000..243a085
--- /dev/null
+++ b/debian/simpprof.1
@@ -0,0 +1,23 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create Simple CMYK Device Profile, Version 1.1" "User Commands"
+.SH NAME
+Create \- Create Simple CMYK Device Profile.
+.SH DESCRIPTION
+Create Simple CMYK Device Profile, Version 1.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: debian/tmp/usr/bin/simpprof [\-v] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+outfile
+Base name for input.tr3/output.pr1 file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: debian/tmp/usr/bin/simpprof [\-v] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+outfile
+Base name for input.tr3/output.pr1 file
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/spec2cie.1 b/debian/spec2cie.1
new file mode 100644
index 0000000..1ec3695
--- /dev/null
+++ b/debian/spec2cie.1
@@ -0,0 +1,84 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CONVERT "1" "August 2013" "Convert spectral .ti3 file, Version 1.5.1" "User Commands"
+.SH NAME
+Convert \- Convert spectral .ti3 file.
+.SH SYNOPSIS
+.B spec2cie
+[\fIoptions\fR] \fIinput.ti3 output.ti3\fR
+.SH DESCRIPTION
+Convert spectral .ti3 file, Version 1.5.1
+Author: Gerhard Fuernkranz, licensed under the AGPL Version 3
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-I\fR illum
+Override actual instrument illuminant in .ti3 file:
+.IP
+A, C, D50, D50M2, D65, F5, F8, F10 or file.sp
+(only used in conjunction with \fB\-f\fR)
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-n\fR
+Don't output spectral values
+.TP
+\fB\-p\fR
+Plot each values spectrum
+.TP
+input.ti3
+Measurement file
+.TP
+output.ti3
+Converted measurement file
+.PP
+Author: Gerhard Fuernkranz, licensed under the AGPL Version 3
+.PP
+Usage: spec2cie [options] input.ti3 output.ti3
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-I\fR illum
+Override actual instrument illuminant in .ti3 file:
+.IP
+A, C, D50, D50M2, D65, F5, F8, F10 or file.sp
+(only used in conjunction with \fB\-f\fR)
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+.IP
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-n\fR
+Don't output spectral values
+.TP
+\fB\-p\fR
+Plot each values spectrum
+.TP
+input.ti3
+Measurement file
+.TP
+output.ti3
+Converted measurement file
diff --git a/debian/specplot.1 b/debian/specplot.1
new file mode 100644
index 0000000..969e717
--- /dev/null
+++ b/debian/specplot.1
@@ -0,0 +1,49 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH PLOT "1" "August 2013" "Plot spectrum and calculate CCT and VCT" "User Commands"
+.SH NAME
+Plot \- Plot spectrum and calculate CCT and VCT.
+.SH DESCRIPTION
+Plot spectrum and calculate CCT and VCT
+Author: Graeme W. Gill
+usage: specplot [infile.sp]
+.TP
+\fB\-v\fR
+verbose
+.TP
+\fB\-c\fR
+combine multiple files into one plot
+.TP
+\fB\-z\fR
+don't make range cover zero
+.TP
+\fB\-u\fR level
+plot effect of adding estimated UV level
+.TP
+\fB\-U\fR
+plot effect of adding range of estimated UV level
+.TP
+[infile.sp ...]
+spectrum files to plot
+default is all built in illuminants
+.PP
+Author: Graeme W. Gill
+usage: specplot [infile.sp]
+.TP
+\fB\-v\fR
+verbose
+.TP
+\fB\-c\fR
+combine multiple files into one plot
+.TP
+\fB\-z\fR
+don't make range cover zero
+.TP
+\fB\-u\fR level
+plot effect of adding estimated UV level
+.TP
+\fB\-U\fR
+plot effect of adding range of estimated UV level
+.TP
+[infile.sp ...]
+spectrum files to plot
+default is all built in illuminants
diff --git a/debian/splitti3.1 b/debian/splitti3.1
new file mode 100644
index 0000000..e1a3dd1
--- /dev/null
+++ b/debian/splitti3.1
@@ -0,0 +1,59 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH SPLIT "1" "August 2013" "Split a .ti3 into two, Version 1.5.1" "User Commands"
+.SH NAME
+Split \- Split a .ti3 into two.
+.SH DESCRIPTION
+Split a .ti3 into two, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: splitcgats [\-options] input.ti3 output1.ti3 output2.ti3
+.TP
+\fB\-v\fR
+Verbose \- print each patch value
+.TP
+\fB\-n\fR no
+Put no sets in first file, and balance in second file.
+.TP
+\fB\-p\fR percent
+Put percent% sets in first file, and balance in second file. (def. 50%)
+.TP
+\fB\-w\fR
+Put white patches in both files.
+.TP
+\fB\-r\fR seed
+Use given random seed.
+.TP
+input.ti3
+File to be split up.
+.TP
+output1.ti3
+First output file
+.TP
+output2.ti3
+Second output file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: splitcgats [\-options] input.ti3 output1.ti3 output2.ti3
+.TP
+\fB\-v\fR
+Verbose \- print each patch value
+.TP
+\fB\-n\fR no
+Put no sets in first file, and balance in second file.
+.TP
+\fB\-p\fR percent
+Put percent% sets in first file, and balance in second file. (def. 50%)
+.TP
+\fB\-w\fR
+Put white patches in both files.
+.TP
+\fB\-r\fR seed
+Use given random seed.
+.TP
+input.ti3
+File to be split up.
+.TP
+output1.ti3
+First output file
+.TP
+output2.ti3
+Second output file
diff --git a/debian/spotread.1 b/debian/spotread.1
new file mode 100644
index 0000000..0432ef7
--- /dev/null
+++ b/debian/spotread.1
@@ -0,0 +1,235 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH MEASURE "1" "August 2013" "Measure spot values, Version 1.5.1" "User Commands"
+.SH NAME
+Measure \- Read Print Spot values.
+.SH DESCRIPTION
+Measure spot values, Version 1.5.1
+Author: Graeme W. Gill, licensed under the GPL Version 2 or later
+Diagnostic: Flag \fB\-\-\fR not recognised
+usage: spotread [\-options] [logfile]
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-s\fR
+Print spectrum for each reading
+.TP
+\fB\-S\fR
+Plot spectrum for each reading
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-t\fR
+Use transmission measurement mode
+.TP
+\fB\-e\fR
+Use emissive measurement mode (absolute results)
+.TP
+\fB\-eb\fR
+Use display white brightness relative measurement mode
+.TP
+\fB\-ew\fR
+Use display white relative measurement mode
+.TP
+\fB\-p\fR
+Use telephoto measurement mode (absolute results)
+.TP
+\fB\-pb\fR
+Use projector white brightness relative measurement mode
+.TP
+\fB\-pw\fR
+Use projector white relative measurement mode
+.TP
+\fB\-a\fR
+Use ambient measurement mode (absolute results)
+.TP
+\fB\-f\fR
+Use ambient flash measurement mode (absolute results)
+.TP
+\fB\-I\fR illum
+Set simulated instrument illumination using FWA (def \fB\-i\fR illum):
+M0, M1, M2, A, C, D50, D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectral data or CCSS instrument:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+(Choose FWA during operation)
+.TP
+\fB\-F\fR filter
+Set filter configuration (if aplicable):
+.TP
+n
+None
+.TP
+p
+Polarising filter
+.TP
+6
+D65
+.TP
+u
+U.V. Cut
+.TP
+\fB\-E\fR extrafilterfile
+Apply extra filter compensation file
+.TP
+\fB\-x\fR
+Display Yxy instead of Lab
+.TP
+\fB\-h\fR
+Display LCh instead of Lab
+.TP
+\fB\-V\fR
+Show running average and std. devation from ref.
+.TP
+\fB\-T\fR
+Display correlated color temperatures and CRI
+.TP
+\fB\-N\fR
+Disable auto calibration of instrument
+.TP
+\fB\-H\fR
+Start in high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Y\fR r|n
+Override refresh, non\-refresh display mode
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+logfile
+Optional file to save reading results as text
+.PP
+Author: Graeme W. Gill, licensed under the GPL Version 2 or later
+Diagnostic: Flag \fB\-\-\fR not recognised
+usage: spotread [\-options] [logfile]
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-s\fR
+Print spectrum for each reading
+.TP
+\fB\-S\fR
+Plot spectrum for each reading
+.TP
+\fB\-c\fR listno
+Set communication port from the following list (default 1)
+.IP
+** No ports found **
+.TP
+\fB\-t\fR
+Use transmission measurement mode
+.TP
+\fB\-e\fR
+Use emissive measurement mode (absolute results)
+.TP
+\fB\-eb\fR
+Use display white brightness relative measurement mode
+.TP
+\fB\-ew\fR
+Use display white relative measurement mode
+.TP
+\fB\-p\fR
+Use telephoto measurement mode (absolute results)
+.TP
+\fB\-pb\fR
+Use projector white brightness relative measurement mode
+.TP
+\fB\-pw\fR
+Use projector white relative measurement mode
+.TP
+\fB\-a\fR
+Use ambient measurement mode (absolute results)
+.TP
+\fB\-f\fR
+Use ambient flash measurement mode (absolute results)
+.TP
+\fB\-I\fR illum
+Set simulated instrument illumination using FWA (def \fB\-i\fR illum):
+M0, M1, M2, A, C, D50, D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-Q\fR observ
+Choose CIE Observer for spectral data or CCSS instrument:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+(Choose FWA during operation)
+.TP
+\fB\-F\fR filter
+Set filter configuration (if aplicable):
+.TP
+n
+None
+.TP
+p
+Polarising filter
+.TP
+6
+D65
+.TP
+u
+U.V. Cut
+.TP
+\fB\-E\fR extrafilterfile
+Apply extra filter compensation file
+.TP
+\fB\-x\fR
+Display Yxy instead of Lab
+.TP
+\fB\-h\fR
+Display LCh instead of Lab
+.TP
+\fB\-V\fR
+Show running average and std. devation from ref.
+.TP
+\fB\-T\fR
+Display correlated color temperatures and CRI
+.TP
+\fB\-N\fR
+Disable auto calibration of instrument
+.TP
+\fB\-H\fR
+Start in high resolution spectrum mode (if available)
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix
+.TP
+\fB\-X\fR file.ccss
+Use Colorimeter Calibration Spectral Samples for calibration
+.TP
+\fB\-Y\fR r|n
+Override refresh, non\-refresh display mode
+.TP
+\fB\-Y\fR A
+Use non\-adaptive integration time mode (if available).
+.TP
+\fB\-W\fR n|h|x
+Override serial port flow control: n = none, h = HW, x = Xon/Xoff
+.TP
+\fB\-D\fR [level]
+Print debug diagnostics to stderr
+.TP
+logfile
+Optional file to save reading results as text
diff --git a/debian/synthcal.1 b/debian/synthcal.1
new file mode 100644
index 0000000..9a6d828
--- /dev/null
+++ b/debian/synthcal.1
@@ -0,0 +1,87 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create a synthetic calibration file, Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create a synthetic calibration file.
+.SH DESCRIPTION
+Create a synthetic calibration file, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: synthcal [\-options] outfile
+.TP
+\fB\-t\fR N
+i = input, o = output, d = display (default)
+.TP
+\fB\-d\fR col_comb
+choose colorant combination from the following (default 3):
+0: Print grey
+1: Video grey
+2: Print RGB
+3: Video RGB
+4: CMYK
+5: CMY
+6: CMYK + Light CM
+7: CMYK + Light CMK
+8: CMYK + Red + Blue
+9: CMYK + Orange + Green
+10: CMYK + Light CMK + Light Light K
+11: CMYK + Orange + Green + Light CM
+12: CMYK + Light CM + Medium CM
+.TP
+\fB\-D\fR colorant
+Add or delete colorant from combination:
+(Use \-?? to list known colorants)
+.TP
+\fB\-o\fR o1,o2,o3,
+Set non\-linear curve offset (default 0.0)
+.TP
+\fB\-s\fR s1,s2,s3,
+Set non\-linear curve scale (default 1.0)
+.TP
+\fB\-p\fR p1,p2,p3,
+Set non\-linear curve powers (default 1.0)
+.TP
+\fB\-E\fR description
+Set the profile dEscription string
+.TP
+outfile
+Base name for output .cal file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: synthcal [\-options] outfile
+.TP
+\fB\-t\fR N
+i = input, o = output, d = display (default)
+.TP
+\fB\-d\fR col_comb
+choose colorant combination from the following (default 3):
+0: Print grey
+1: Video grey
+2: Print RGB
+3: Video RGB
+4: CMYK
+5: CMY
+6: CMYK + Light CM
+7: CMYK + Light CMK
+8: CMYK + Red + Blue
+9: CMYK + Orange + Green
+10: CMYK + Light CMK + Light Light K
+11: CMYK + Orange + Green + Light CM
+12: CMYK + Light CM + Medium CM
+.TP
+\fB\-D\fR colorant
+Add or delete colorant from combination:
+(Use \-?? to list known colorants)
+.TP
+\fB\-o\fR o1,o2,o3,
+Set non\-linear curve offset (default 0.0)
+.TP
+\fB\-s\fR s1,s2,s3,
+Set non\-linear curve scale (default 1.0)
+.TP
+\fB\-p\fR p1,p2,p3,
+Set non\-linear curve powers (default 1.0)
+.TP
+\fB\-E\fR description
+Set the profile dEscription string
+.TP
+outfile
+Base name for output .cal file
diff --git a/debian/synthread.1 b/debian/synthread.1
new file mode 100644
index 0000000..02345c1
--- /dev/null
+++ b/debian/synthread.1
@@ -0,0 +1,85 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH SYNTHETIC "1" "August 2013" "Synthetic device model test chart reader - Version 1.5.1" "User Commands"
+.SH NAME
+Synthetic \- Synthetic device model test chart reader.
+.SH DESCRIPTION
+Synthetic device model test chart reader \- Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Error 'Unrecognised flag'
+usage: synthread [\-v] [\-s] [separation.icm] profile.[icc|mpp|ti3] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-p\fR
+Use separation profile
+.TP
+\fB\-l\fR
+Construct and output in Lab rather than XYZ
+.TP
+\fB\-i\fR p1,p2,p3,
+Set input channel curve powers (default 1.0)
+.TP
+\fB\-k\fR x1:y1,x2:y2,x3:y2
+Set input channel inflection points (default 0.5,0.5)
+.TP
+\fB\-o\fR p1,p2,p3,
+Set output channel curve powers (default 1.0)
+.TP
+\fB\-r\fR level
+Add average random deviation of <level>% to input device values (after sep.)
+.TP
+\fB\-R\fR level
+Add average random deviation of <level>% to output PCS values
+.TP
+\fB\-u\fR
+Make random deviations have uniform distributions rather than normal
+.TP
+\fB\-b\fR L,a,b
+Scale black point to target Lab value
+.TP
+[separation.icm]
+Device link separation profile
+.IP
+profile.[icc|mpp|ti3] ICC, MPP profile or TI3 to use
+outfile Base name for input[ti1]/output[ti3] file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Error 'Unrecognised flag'
+usage: synthread [\-v] [\-s] [separation.icm] profile.[icc|mpp|ti3] outfile
+.TP
+\fB\-v\fR
+Verbose mode
+.TP
+\fB\-p\fR
+Use separation profile
+.TP
+\fB\-l\fR
+Construct and output in Lab rather than XYZ
+.TP
+\fB\-i\fR p1,p2,p3,
+Set input channel curve powers (default 1.0)
+.TP
+\fB\-k\fR x1:y1,x2:y2,x3:y2
+Set input channel inflection points (default 0.5,0.5)
+.TP
+\fB\-o\fR p1,p2,p3,
+Set output channel curve powers (default 1.0)
+.TP
+\fB\-r\fR level
+Add average random deviation of <level>% to input device values (after sep.)
+.TP
+\fB\-R\fR level
+Add average random deviation of <level>% to output PCS values
+.TP
+\fB\-u\fR
+Make random deviations have uniform distributions rather than normal
+.TP
+\fB\-b\fR L,a,b
+Scale black point to target Lab value
+.TP
+[separation.icm]
+Device link separation profile
+.IP
+profile.[icc|mpp|ti3] ICC, MPP profile or TI3 to use
+outfile Base name for input[ti1]/output[ti3] file
diff --git a/debian/targen.1 b/debian/targen.1
new file mode 100644
index 0000000..1150f14
--- /dev/null
+++ b/debian/targen.1
@@ -0,0 +1,203 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH GENERATE "1" "August 2013" "Generate Target deviceb test chart color values, Version 1.5.1" "User Commands"
+.SH NAME
+Generate \- Generate Target deviceb test chart color values.
+.SH DESCRIPTION
+Generate Target deviceb test chart color values, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: targen [options] outfile
+.IP
+Diagnostic: Usage requested
+.TP
+\fB\-v\fR [level]
+Verbose mode [optional level 1..N]
+.TP
+\fB\-d\fR col_comb
+choose colorant combination from the following:
+0: Print grey
+1: Video grey
+2: Print RGB
+3: Video RGB
+4: CMYK
+5: CMY
+6: CMYK + Light CM
+7: CMYK + Light CMK
+8: CMYK + Red + Blue
+9: CMYK + Orange + Green
+10: CMYK + Light CMK + Light Light K
+11: CMYK + Orange + Green + Light CM
+12: CMYK + Light CM + Medium CM
+.TP
+\fB\-D\fR colorant
+Add or delete colorant from combination:
+(Use \-?? to list known colorants)
+.TP
+\fB\-G\fR
+Generate good optimized points rather than Fast
+.TP
+\fB\-e\fR patches
+White test patches (default 4)
+.TP
+\fB\-s\fR steps
+Single channel steps (default grey 50, color 0)
+.TP
+\fB\-g\fR steps
+Grey axis RGB or CMY steps (default 0)
+.TP
+\fB\-m\fR steps
+Multidimensional device space cube steps (default 0)
+.TP
+\fB\-f\fR patches
+Add iterative & adaptive full spread patches to total (default grey 0, color 836)
+Default is Optimised Farthest Point Sampling (OFPS)
+.TP
+\fB\-t\fR
+Use incremental far point for full spread
+.TP
+\fB\-r\fR
+Use device space random for full spread
+.TP
+\fB\-R\fR
+Use perceptual space random for full spread
+.TP
+\fB\-q\fR
+Use device space\-filling quasi\-random for full spread
+.TP
+\fB\-Q\fR
+Use perceptual space\-filling quasi\-random for full spread
+.TP
+\fB\-i\fR
+Use device space body centered cubic grid for full spread
+.TP
+\fB\-I\fR
+Use perceptual space body centered cubic grid for full spread
+.TP
+\fB\-a\fR angle
+Simplex grid angle 0.0 \- 0.5 for B.C.C. grid, default 0.333300
+.TP
+\fB\-A\fR adaptation
+Degree of adaptation of OFPS 0.0 \- 1.0 (default 0.1, \fB\-c\fR profile used 1.0)
+.TP
+\fB\-l\fR ilimit
+Total ink limit in % (default = none)
+.TP
+\fB\-p\fR power
+Optional power\-like value applied to all device values.
+.TP
+\fB\-c\fR profile
+Optional device ICC or MPP pre\-conditioning profile filename
+(Use "none" to turn off any conditioning)
+.TP
+\fB\-N\fR emphasis
+Degree of neutral axis patch concentration 0.0\-1.0 (default 0.50)
+.TP
+\fB\-F\fR L,a,b,rad
+Filter out samples outside Lab sphere.
+.TP
+\fB\-w\fR
+Dump diagnostic outfilel.wrl file (Lab locations)
+.TP
+\fB\-W\fR
+Dump diagnostic outfiled.wrl file (Device locations)
+.TP
+outfile
+Base name for output(.ti1)
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: targen [options] outfile
+.IP
+Diagnostic: Usage requested
+.TP
+\fB\-v\fR [level]
+Verbose mode [optional level 1..N]
+.TP
+\fB\-d\fR col_comb
+choose colorant combination from the following:
+0: Print grey
+1: Video grey
+2: Print RGB
+3: Video RGB
+4: CMYK
+5: CMY
+6: CMYK + Light CM
+7: CMYK + Light CMK
+8: CMYK + Red + Blue
+9: CMYK + Orange + Green
+10: CMYK + Light CMK + Light Light K
+11: CMYK + Orange + Green + Light CM
+12: CMYK + Light CM + Medium CM
+.TP
+\fB\-D\fR colorant
+Add or delete colorant from combination:
+(Use \-?? to list known colorants)
+.TP
+\fB\-G\fR
+Generate good optimized points rather than Fast
+.TP
+\fB\-e\fR patches
+White test patches (default 4)
+.TP
+\fB\-s\fR steps
+Single channel steps (default grey 50, color 0)
+.TP
+\fB\-g\fR steps
+Grey axis RGB or CMY steps (default 0)
+.TP
+\fB\-m\fR steps
+Multidimensional device space cube steps (default 0)
+.TP
+\fB\-f\fR patches
+Add iterative & adaptive full spread patches to total (default grey 0, color 836)
+Default is Optimised Farthest Point Sampling (OFPS)
+.TP
+\fB\-t\fR
+Use incremental far point for full spread
+.TP
+\fB\-r\fR
+Use device space random for full spread
+.TP
+\fB\-R\fR
+Use perceptual space random for full spread
+.TP
+\fB\-q\fR
+Use device space\-filling quasi\-random for full spread
+.TP
+\fB\-Q\fR
+Use perceptual space\-filling quasi\-random for full spread
+.TP
+\fB\-i\fR
+Use device space body centered cubic grid for full spread
+.TP
+\fB\-I\fR
+Use perceptual space body centered cubic grid for full spread
+.TP
+\fB\-a\fR angle
+Simplex grid angle 0.0 \- 0.5 for B.C.C. grid, default 0.333300
+.TP
+\fB\-A\fR adaptation
+Degree of adaptation of OFPS 0.0 \- 1.0 (default 0.1, \fB\-c\fR profile used 1.0)
+.TP
+\fB\-l\fR ilimit
+Total ink limit in % (default = none)
+.TP
+\fB\-p\fR power
+Optional power\-like value applied to all device values.
+.TP
+\fB\-c\fR profile
+Optional device ICC or MPP pre\-conditioning profile filename
+(Use "none" to turn off any conditioning)
+.TP
+\fB\-N\fR emphasis
+Degree of neutral axis patch concentration 0.0\-1.0 (default 0.50)
+.TP
+\fB\-F\fR L,a,b,rad
+Filter out samples outside Lab sphere.
+.TP
+\fB\-w\fR
+Dump diagnostic outfilel.wrl file (Lab locations)
+.TP
+\fB\-W\fR
+Dump diagnostic outfiled.wrl file (Device locations)
+.TP
+outfile
+Base name for output(.ti1)
diff --git a/debian/tiffgamut.1 b/debian/tiffgamut.1
new file mode 100644
index 0000000..5b3114d
--- /dev/null
+++ b/debian/tiffgamut.1
@@ -0,0 +1,165 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CREATE "1" "August 2013" "Create VRML image of the gamut surface of a TIFF or JPEG, Version 1.5.1" "User Commands"
+.SH NAME
+Create \- Create VRML image of the gamut surface of a TIFF.
+.SH DESCRIPTION
+Create VRML image of the gamut surface of a TIFF or JPEG, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: tiffgamut [\-v level] [profile.icm | embedded.tif/jpg] infile1.tif/jpg [infile2.tif/jpg ...]
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-d\fR sres
+Surface resolution details 1.0 \- 50.0
+.TP
+\fB\-w\fR
+emit VRML .wrl file as well as CGATS .gam file
+.TP
+\fB\-n\fR
+Don't add VRML axes or white/black point
+.TP
+\fB\-k\fR
+Add markers for prim. & sec. "cusp" points
+.TP
+\fB\-f\fR perc
+Filter by popularity, perc = percent to use
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute (default), d = profile default
+.TP
+\fB\-p\fR oride
+l = Lab_PCS (default), j = CIECAM02 Appearance Jab
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-c\fR viewcond
+set appearance mode and viewing conditions for CIECAM02,
+either an enumerated choice, or a parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:scenewhite
+Scene white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 1)
+.TP
+f:X:Y:Z
+Flare color as XYZ (default media white)
+.TP
+f:x:y
+Flare color as x, y
+.HP
+\fB\-O\fR outputfile Override the default output filename.
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: tiffgamut [\-v level] [profile.icm | embedded.tif/jpg] infile1.tif/jpg [infile2.tif/jpg ...]
+.TP
+\fB\-v\fR
+Verbose
+.TP
+\fB\-d\fR sres
+Surface resolution details 1.0 \- 50.0
+.TP
+\fB\-w\fR
+emit VRML .wrl file as well as CGATS .gam file
+.TP
+\fB\-n\fR
+Don't add VRML axes or white/black point
+.TP
+\fB\-k\fR
+Add markers for prim. & sec. "cusp" points
+.TP
+\fB\-f\fR perc
+Filter by popularity, perc = percent to use
+.TP
+\fB\-i\fR intent
+p = perceptual, r = relative colorimetric,
+s = saturation, a = absolute (default), d = profile default
+.TP
+\fB\-p\fR oride
+l = Lab_PCS (default), j = CIECAM02 Appearance Jab
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-c\fR viewcond
+set appearance mode and viewing conditions for CIECAM02,
+either an enumerated choice, or a parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:scenewhite
+Scene white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 1)
+.TP
+f:X:Y:Z
+Flare color as XYZ (default media white)
+.TP
+f:x:y
+Flare color as x, y
+.HP
+\fB\-O\fR outputfile Override the default output filename.
diff --git a/debian/txt2ti3.1 b/debian/txt2ti3.1
new file mode 100644
index 0000000..789d352
--- /dev/null
+++ b/debian/txt2ti3.1
@@ -0,0 +1,61 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH CONVERT "1" "August 2013" "Convert Gretag/Logo or X-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data, Version 1.5.1" "User Commands"
+.SH NAME
+Convert \- Convert Gretag/Logo or X-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data.
+.SH DESCRIPTION
+Convert Gretag/Logo or X\-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+error: Unknown flag
+usage: txt2ti3 [\-v] [\-l limit] [devfile] infile [specfile] outfile
+.TP
+\fB\-2\fR
+Create dummy .ti2 file as well
+.TP
+\fB\-l\fR limit
+set ink limit, 0 \- 400% (default max in file)
+.TP
+\fB\-d\fR
+Set type of device as Display, not Output
+.TP
+\fB\-i\fR
+Set type of device as Input, not Output
+.TP
+[devfile]
+Input Device CMYK target file (typically file.txt)
+.TP
+infile
+Input CIE, Spectral or Device & Spectral file (typically file.txt)
+.TP
+[specfile]
+Input Spectral file (typically file.txt)
+.TP
+outbasename
+Output file basename for .ti3 and .ti2
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+error: Unknown flag
+usage: txt2ti3 [\-v] [\-l limit] [devfile] infile [specfile] outfile
+.TP
+\fB\-2\fR
+Create dummy .ti2 file as well
+.TP
+\fB\-l\fR limit
+set ink limit, 0 \- 400% (default max in file)
+.TP
+\fB\-d\fR
+Set type of device as Display, not Output
+.TP
+\fB\-i\fR
+Set type of device as Input, not Output
+.TP
+[devfile]
+Input Device CMYK target file (typically file.txt)
+.TP
+infile
+Input CIE, Spectral or Device & Spectral file (typically file.txt)
+.TP
+[specfile]
+Input Spectral file (typically file.txt)
+.TP
+outbasename
+Output file basename for .ti3 and .ti2
diff --git a/debian/verify.1 b/debian/verify.1
new file mode 100644
index 0000000..09f742f
--- /dev/null
+++ b/debian/verify.1
@@ -0,0 +1,117 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH VERIFY "1" "August 2013" "Verify CIE values, Version 1.5.1" "User Commands"
+.SH NAME
+Verify \- Verify CIE values.
+.SH DESCRIPTION
+Verify CIE values, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: verify [\-options] target.ti3 measured.ti3
+.TP
+\fB\-v\fR
+Verbose \- print each patch value
+.TP
+\fB\-n\fR
+Normalise each files reading to white Y
+.TP
+\fB\-N\fR
+Normalise each files reading to white XYZ
+.TP
+\fB\-D\fR
+Use D50 100.0 as L*a*b* white reference
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-s\fR
+Sort patch values by error
+.TP
+\fB\-w\fR
+create VRML vector visualisation (measured.wrl)
+.TP
+\fB\-W\fR
+create VRML marker visualisation (measured.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix to second file
+.TP
+target.ti3
+Target (reference) PCS or spectral values.
+.TP
+measured.ti3
+Measured (actual) PCS or spectral values
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: verify [\-options] target.ti3 measured.ti3
+.TP
+\fB\-v\fR
+Verbose \- print each patch value
+.TP
+\fB\-n\fR
+Normalise each files reading to white Y
+.TP
+\fB\-N\fR
+Normalise each files reading to white XYZ
+.TP
+\fB\-D\fR
+Use D50 100.0 as L*a*b* white reference
+.TP
+\fB\-c\fR
+Show CIE94 delta E values
+.TP
+\fB\-k\fR
+Show CIEDE2000 delta E values
+.TP
+\fB\-s\fR
+Sort patch values by error
+.TP
+\fB\-w\fR
+create VRML vector visualisation (measured.wrl)
+.TP
+\fB\-W\fR
+create VRML marker visualisation (measured.wrl)
+.TP
+\fB\-x\fR
+Use VRML axes
+.TP
+\fB\-f\fR [illum]
+Use Fluorescent Whitening Agent compensation [opt. simulated inst. illum.:
+.IP
+M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]
+.TP
+\fB\-i\fR illum
+Choose illuminant for computation of CIE XYZ from spectral data & FWA:
+.IP
+A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp
+.TP
+\fB\-o\fR observ
+Choose CIE Observer for spectral data:
+1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2
+.TP
+\fB\-X\fR file.ccmx
+Apply Colorimeter Correction Matrix to second file
+.TP
+target.ti3
+Target (reference) PCS or spectral values.
+.TP
+measured.ti3
+Measured (actual) PCS or spectral values
diff --git a/debian/viewgam.1 b/debian/viewgam.1
new file mode 100644
index 0000000..79cf7ad
--- /dev/null
+++ b/debian/viewgam.1
@@ -0,0 +1,79 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH VIEW "1" "August 2013" "View gamuts Version 1.5.1" "User Commands"
+.SH NAME
+View \- View gamuts.
+.SH DESCRIPTION
+View gamuts Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Too few arguments, got 1 expect at least 2
+usage: viewgam { [\-c color] [\-t trans] [\-w|s] infile.gam } ... outfile.wrl
+.TP
+\fB\-c\fR color
+Color to make gamut, r = red, g = green, b = blue
+c = cyan, m = magenta, y = yellow, e = grey, w = white
+n = natural color
+.TP
+\fB\-t\fR trans
+Set transparency from 0.0 (opaque) to 1.0 (invisible)
+.TP
+\fB\-w\fR
+Show as a wireframe
+.TP
+\fB\-s\fR
+Show as a solid surace
+.TP
+infile.gam
+Name of .gam file
+Repeat above for each input file
+.TP
+\fB\-n\fR
+Don't add Lab axes
+.TP
+\fB\-k\fR
+Add markers for prim. & sec. "cusp" points
+.TP
+\fB\-i\fR
+Compute and print intersecting volume of first 2 gamuts
+.TP
+\fB\-I\fR isect.gam
+Same as \fB\-i\fR, but save intersection gamut to isect.gam
+.TP
+outfile.wrl
+Name of output .wrl file
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+Diagnostic: Too few arguments, got 1 expect at least 2
+usage: viewgam { [\-c color] [\-t trans] [\-w|s] infile.gam } ... outfile.wrl
+.TP
+\fB\-c\fR color
+Color to make gamut, r = red, g = green, b = blue
+c = cyan, m = magenta, y = yellow, e = grey, w = white
+n = natural color
+.TP
+\fB\-t\fR trans
+Set transparency from 0.0 (opaque) to 1.0 (invisible)
+.TP
+\fB\-w\fR
+Show as a wireframe
+.TP
+\fB\-s\fR
+Show as a solid surace
+.TP
+infile.gam
+Name of .gam file
+Repeat above for each input file
+.TP
+\fB\-n\fR
+Don't add Lab axes
+.TP
+\fB\-k\fR
+Add markers for prim. & sec. "cusp" points
+.TP
+\fB\-i\fR
+Compute and print intersecting volume of first 2 gamuts
+.TP
+\fB\-I\fR isect.gam
+Same as \fB\-i\fR, but save intersection gamut to isect.gam
+.TP
+outfile.wrl
+Name of output .wrl file
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..52b696a
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,3 @@
+version=3
+
+opts="dversionmangle=s/\+dfsg\d+$//" http://www.argyllcms.com/downloadsrc.html Argyll_V(.*)_src\.zip
diff --git a/debian/xicclu.1 b/debian/xicclu.1
new file mode 100644
index 0000000..9806d66
--- /dev/null
+++ b/debian/xicclu.1
@@ -0,0 +1,257 @@
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.43.3.
+.TH TRANSLATE "1" "August 2013" "Translate colors through an xicc, Version 1.5.1" "User Commands"
+.SH NAME
+Translate \- Translate colors through an xicc.
+.SH DESCRIPTION
+Translate colors through an xicc, Version 1.5.1
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: xicclu [\-options] profile
+Diagnostic: Unknown flag
+.TP
+\fB\-v\fR level
+Verbosity level 0 \- 2 (default = 1)
+.TP
+\fB\-g\fR
+Plot slice instead of looking colors up. (Default white to black)
+.TP
+\fB\-G\fR s:L:a:b
+Override plot slice start with Lab or Jab co\-ordinate
+.TP
+\fB\-G\fR e:L:a:b
+Override plot slice end with Lab or Jab co\-ordinate
+.TP
+\fB\-f\fR function
+f = forward, b = backwards, g = gamut, p = preview
+if = inverted forward, ib = inverted backwards
+.TP
+\fB\-i\fR intent
+a = absolute, r = relative colorimetric
+p = perceptual, s = saturation
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, X = XYZ * 100, l = Lab_PCS, L = LCh, y = Yxy
+j = CIECAM02 Appearance Jab, J = CIECAM02 Appearance JCh
+.TP
+\fB\-s\fR scale
+Scale device range 0.0 \- scale rather than 0.0 \- 1.0
+.TP
+\fB\-k\fR [zhxrlv]
+Black value target: z = zero K,
+h = 0.5 K, x = max K, r = ramp K (def.)
+l = extra PCS input is portion of K locus
+v = extra PCS input is K target value
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.HP
+\fB\-k\fR q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2
+.IP
+Transfer extra PCS input to dual curve limits
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-a\fR
+show actual target values if clipped
+.TP
+\fB\-u\fR
+warn if output PCS is outside the spectrum locus
+.TP
+\fB\-m\fR
+merge output processing into clut
+.TP
+\fB\-b\fR
+use CAM Jab for clipping
+.TP
+\fB\-c\fR viewcond
+set viewing conditions for CIECAM97s,
+either an enumerated choice, or a parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white, Abs: D50)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:scenewhite
+Scene white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 1)
+.TP
+f:X:Y:Z
+Flare color as XYZ (default media white, Abs: D50)
+.TP
+f:x:y
+Flare color as x, y
+.IP
+The colors to be translated should be fed into standard in,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
+Use \fB\-v0\fR for just output colors.
+.PP
+Author: Graeme W. Gill, licensed under the AGPL Version 3
+usage: xicclu [\-options] profile
+Diagnostic: Unknown flag
+.TP
+\fB\-v\fR level
+Verbosity level 0 \- 2 (default = 1)
+.TP
+\fB\-g\fR
+Plot slice instead of looking colors up. (Default white to black)
+.TP
+\fB\-G\fR s:L:a:b
+Override plot slice start with Lab or Jab co\-ordinate
+.TP
+\fB\-G\fR e:L:a:b
+Override plot slice end with Lab or Jab co\-ordinate
+.TP
+\fB\-f\fR function
+f = forward, b = backwards, g = gamut, p = preview
+if = inverted forward, ib = inverted backwards
+.TP
+\fB\-i\fR intent
+a = absolute, r = relative colorimetric
+p = perceptual, s = saturation
+.TP
+\fB\-o\fR order
+n = normal (priority: lut > matrix > monochrome)
+r = reverse (priority: monochrome > matrix > lut)
+.TP
+\fB\-p\fR oride
+x = XYZ_PCS, X = XYZ * 100, l = Lab_PCS, L = LCh, y = Yxy
+j = CIECAM02 Appearance Jab, J = CIECAM02 Appearance JCh
+.TP
+\fB\-s\fR scale
+Scale device range 0.0 \- scale rather than 0.0 \- 1.0
+.TP
+\fB\-k\fR [zhxrlv]
+Black value target: z = zero K,
+h = 0.5 K, x = max K, r = ramp K (def.)
+l = extra PCS input is portion of K locus
+v = extra PCS input is K target value
+.HP
+\fB\-k\fR p stle stpo enpo enle shape
+.IP
+stle: K level at White 0.0 \- 1.0
+stpo: start point of transition Wh 0.0 \- Bk 1.0
+enpo: End point of transition Wh 0.0 \- Bk 1.0
+enle: K level at Black 0.0 \- 1.0
+shape: 1.0 = straight, 0.0\-1.0 concave, 1.0\-2.0 convex
+.HP
+\fB\-k\fR q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2
+.IP
+Transfer extra PCS input to dual curve limits
+.TP
+\fB\-K\fR parameters
+Same as \fB\-k\fR, but target is K locus rather than K value itself
+.TP
+\fB\-l\fR tlimit
+set total ink limit, 0 \- 400% (estimate by default)
+.TP
+\fB\-L\fR klimit
+set black ink limit, 0 \- 100% (estimate by default)
+.TP
+\fB\-a\fR
+show actual target values if clipped
+.TP
+\fB\-u\fR
+warn if output PCS is outside the spectrum locus
+.TP
+\fB\-m\fR
+merge output processing into clut
+.TP
+\fB\-b\fR
+use CAM Jab for clipping
+.TP
+\fB\-c\fR viewcond
+set viewing conditions for CIECAM97s,
+either an enumerated choice, or a parameter:value changes
+.IP
+pp \- Practical Reflection Print (ISO\-3664 P2)
+pe \- Print evaluation environment (CIE 116\-1995)
+pc \- Critical print evaluation environment (ISO\-3664 P1)
+mt \- Monitor in typical work environment
+mb \- Bright monitor in bright work environment
+md \- Monitor in darkened work environment
+jm \- Projector in dim environment
+jd \- Projector in dark environment
+.IP
+pcd \- Photo CD \- original scene outdoors
+.IP
+ob \- Original scene \- Bright Outdoors
+cx \- Cut Sheet Transparencies on a viewing box
+.TP
+s:surround
+n = auto, a = average, m = dim, d = dark,
+c = transparency (default average)
+.TP
+w:X:Y:Z
+Adapted white point as XYZ (default media white, Abs: D50)
+.TP
+w:x:y
+Adapted white point as x, y
+.TP
+a:adaptation
+Adaptation luminance in cd.m^2 (default 50.0)
+.TP
+b:background
+Background % of image luminance (default 20)
+.TP
+l:scenewhite
+Scene white in cd.m^2 if surround = auto (default 250)
+.TP
+f:flare
+Flare light % of image luminance (default 1)
+.TP
+f:X:Y:Z
+Flare color as XYZ (default media white, Abs: D50)
+.TP
+f:x:y
+Flare color as x, y
+.IP
+The colors to be translated should be fed into standard in,
+one input color per line, white space separated.
+A line starting with a # will be ignored.
+A line not starting with a number will terminate the program.
+Use \fB\-v0\fR for just output colors.
diff --git a/depcomp b/depcomp
new file mode 100644
index 0000000..4ebd5b3
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2013-05-30.07; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'. Note that this directory component will
+# be either empty or ending with a '/' character. This is deliberate.
+set_dir_from ()
+{
+ case $1 in
+ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+ *) dir=;;
+ esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+ echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+ # If the compiler actually managed to produce a dependency file,
+ # post-process it.
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form 'foo.o: dependency.h'.
+ # Do two passes, one to just change these to
+ # $object: dependency.h
+ # and one to simply output
+ # dependency.h:
+ # which is needed to avoid the deleted-header problem.
+ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+ } > "$depfile"
+ rm -f "$tmpdepfile"
+ else
+ make_dummy_depfile
+ fi
+}
+
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say). Also, it might not be
+## supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The second -e expression handles DOS-style file names with drive
+ # letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like '#:fec' to the end of the
+ # dependency line.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+ | tr "$nl" ' ' >> "$depfile"
+ echo >> "$depfile"
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts '$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ aix_post_process_depfile
+ ;;
+
+tcc)
+ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+ # FIXME: That version still under development at the moment of writing.
+ # Make that this statement remains true also for stable, released
+ # versions.
+ # It will wrap lines (doesn't matter whether long or short) with a
+ # trailing '\', as in:
+ #
+ # foo.o : \
+ # foo.c \
+ # foo.h \
+ #
+ # It will put a trailing '\' even on the last line, and will use leading
+ # spaces rather than leading tabs (at least since its commit 0394caf7
+ # "Emit spaces for -MD").
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+ # We have to change lines of the first kind to '$object: \'.
+ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+ # And for each line of the second kind, we have to emit a 'dep.h:'
+ # dummy dependency, to avoid the deleted-header problem.
+ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file. A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+ # Portland's C compiler understands '-MD'.
+ # Will always output deps to 'file.d' where file is the root name of the
+ # source file under compilation, even if file resides in a subdirectory.
+ # The object file name does not affect the name of the '.d' file.
+ # pgcc 10.2 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using '\' :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+ set_dir_from "$object"
+ # Use the source, not the object, to determine the base name, since
+ # that's sadly what pgcc will do too.
+ set_base_from "$source"
+ tmpdepfile=$base.d
+
+ # For projects that build the same source file twice into different object
+ # files, the pgcc approach of using the *source* file root name can cause
+ # problems in parallel builds. Use a locking strategy to avoid stomping on
+ # the same $tmpdepfile.
+ lockdir=$base.d-lock
+ trap "
+ echo '$0: caught signal, cleaning up...' >&2
+ rmdir '$lockdir'
+ exit 1
+ " 1 2 13 15
+ numtries=100
+ i=$numtries
+ while test $i -gt 0; do
+ # mkdir is a portable test-and-set.
+ if mkdir "$lockdir" 2>/dev/null; then
+ # This process acquired the lock.
+ "$@" -MD
+ stat=$?
+ # Release the lock.
+ rmdir "$lockdir"
+ break
+ else
+ # If the lock is being held by a different process, wait
+ # until the winning process is done or we timeout.
+ while test -d "$lockdir" && test $i -gt 0; do
+ sleep 1
+ i=`expr $i - 1`
+ done
+ fi
+ i=`expr $i - 1`
+ done
+ trap - 1 2 13 15
+ if test $i -le 0; then
+ echo "$0: failed to acquire lock after $numtries attempts" >&2
+ echo "$0: check lockdir '$lockdir'" >&2
+ exit 1
+ fi
+
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add 'dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in 'foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ set_dir_from "$object"
+ set_base_from "$object"
+
+ if test "$libtool" = yes; then
+ # Libtool generates 2 separate objects for the 2 libraries. These
+ # two compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir$base.o.d # libtool 1.5
+ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
+ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ # Same post-processing that is required for AIX mode.
+ aix_post_process_depfile
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/'"$tab"'/
+ G
+ p
+}' >> "$depfile"
+ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for ':'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ "$@" $dashmflag |
+ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this sed invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process the last invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed '1,2d' "$tmpdepfile" \
+ | tr ' ' "$nl" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E \
+ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ | sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/doc/ArgyllDoc.html b/doc/ArgyllDoc.html
new file mode 100644
index 0000000..498e974
--- /dev/null
+++ b/doc/ArgyllDoc.html
@@ -0,0 +1,5570 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ <meta name="description" content="Root of Argyll CMS documentation">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Documentation Top</title>
+ </head>
+ <body>
+ <h1> Argyll CMS documentation index (V1.5.1)<br>
+ </h1>
+ Date:&nbsp;&nbsp; 8th March 2013<br>
+ Author: Graeme Gill
+ <h2><u><a name="Intro"></a>Introduction</u></h2>
+ ArgyllCMS is an ICC compatible color management system, available as
+ Open Source. It supports accurate ICC profile creation for scanners,
+ cameras and film recorders, and calibration and profiling of
+ displays and RGB &amp; CMYK printers. Spectral sample data is
+ supported, allowing a selection of illuminants observer types, and
+ paper fluorescent whitener additive compensation. Profiles can also
+ incorporate source specific gamut mappings for perceptual and
+ saturation intents. Gamut mapping and profile linking uses the
+ CIECAM02 appearance model, a unique gamut mapping algorithm, and a
+ wide selection of rendering intents. Device Link can be created with
+ a wide variety of advanced options. It also includes code for the
+ fastest portable 8 bit raster color conversion engine available
+ anywhere, as well as support for fast, fully accurate 16 bit
+ conversion. Device color gamuts can also be viewed and compared
+ using a VRML viewer. Comprehensive documentation is provided for
+ each major tool, and a general guide to using the tools for typical
+ color management tasks is also available. A mailing list provides
+ support for more advanced usage.<br>
+ <p>This is Version 1.5.1, a bug fix and feature update to V1.5.0
+ released on 1st March 2013. The first public release of icclib was
+ in November 1998, and of Argyll was in October 2000. Code
+ development commenced in 1995. See <a href="ChangesSummary.html">Changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Summary</a> for an overview of changes since the last release.
+ Changes between revisions is detailed in the <b>log.txt</b> file
+ that accompanies the source code. </p>
+ <p>The latest source code is available from <a
+ href="http://www.argyllcms.com/">here</a>.<br>
+ </p>
+ <h2><a href="ColorManagement.html">An Introduction to Color
+ Management</a></h2>
+ A <a href="ColorManagement.html">concise discussion</a> of what
+ color management is, and why we need it, together with a brief
+ overview of the ICC profile format.<br>
+ <h2 style="text-decoration: underline;">Operating Environments</h2>
+ <h2> </h2>
+ <p>Argyll is known to compile and run in at least the following
+ environments: </p>
+ 1) MSWindows XP system using Microsoft VC++ 6.0 compiler<br>
+ 2) MSWindows XP system using Microsoft VC++ 8.0 Express compiler +
+ Platform SDK Feb. 2003<br>
+ 3) MSWindows XP system using Microsoft VC++ 9.0 Express compiler +
+ Platform SDK Feb. 2003<br>
+ 4) MSWindows XP system using the MingW port of the GCC compiler<br>
+ 5) Linux on Fedora Core 8, 32 bit using gcc <br>
+ 6) Linux on Fedora Core 8, 64 bit using gcc<br>
+ 7) Apple OS X 10.3 PPC using GCC<br>
+ 8) Apple OS X 10.4, 10.5, 10.6 Intel using GCC<br>
+ 9) Apple OS X10.7 Intel using&nbsp; Clang<br>
+ 10) PCBSD 9.1 (FreeBSD) [You need to copy the libusb sub directory
+ from ArgyllCMS V1.4.0]<br>
+ <br>
+ Additionally it is also known to run on:<br>
+ <br>
+ &nbsp;MSWindows 2000, Vista &amp; Windows 7 32 bit.<br>
+ &nbsp;MSWindows Vista 64bit, Windows 7 64bit &amp; Windows 8 64 bit.<br>
+ &nbsp;Linux Ubuntu 7.10<br>
+ &nbsp;Linux Kubuntu 7.10<br>
+ &nbsp;Linux Mandriva 2008.0<br>
+ &nbsp;Linux OpenSuSE 10.3<br>
+ &nbsp;Linux Whitebox 4.2/2<br>
+ <p>but may well compile and run correctly in many more than this,
+ including OS X 10.8. </p>
+ This is a <span style="font-weight: bold;">command line terminal</span>
+ only environment. Those unfamiliar with command line environments
+ should consult an appropriate tutorial for their environment if they
+ are interested in using this software. See the listing of <a
+ href="#cltutes">tutorials</a> below.<span style="font-weight:
+ bold;"></span><br>
+ <br>
+ The following color measuring instruments are directly supported:<br>
+ <br>
+ X-Rite:<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP20">DTP20 "Pulse"</a>&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - "swipe" type reflective spectrometer, that can be used untethered.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP22">DTP22 Digital
+ Swatchbook</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot type reflective spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP41">DTP41</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot and strip reading reflective spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP41">DTP41T</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot and strip reading reflective/transmissive spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#dtp51">DTP51</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - strip reading reflective colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP92">DTP92</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - CRT display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#DTP94">DTP94</a> <font
+ size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro"- display
+ colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#ColorMunki"><span
+ style="text-decoration: underline;">ColorMunki</span></a> Design
+ or Photo&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
+ spot and "swipe" reflective/emissive spectrometer (UV cut only).<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d"><span
+ style="text-decoration: underline;">ColorMunki</span></a> Create
+ or Smile&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter. (Similar to an Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Lenovo W</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; -
+ built in laptop Huey display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d3">Eye-One Display
+ 3</a> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - Xrite i1 DisplayPro and ColorMunki
+ Display <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
+ i1Display Pro, NEC SpectraSensor Pro and<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; Quato Silver Haze 3 OEM i1d3 are also
+ reported to work.]<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
+ "swipe" reflective/emissive spectrometer.<br>
+ <br>
+ Gretag-Macbeth (now X-Rite):<br>
+ &nbsp; &nbsp; <a href="instruments.html#sl">Spectrolino</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScan</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive, XY table reflective spectrometer&nbsp; .<br>
+ &nbsp; &nbsp; <a href="instruments.html#ss">SpectroScanT</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot
+ reflective/emissive/transmissive, XY table reflective spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p">Eye-One Pro</a> "EFI
+ ES-1000" &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe"
+ reflective/emissive spectrometer.<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive
+ spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">Eye-One Display 1
+ or 2&nbsp; or LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -
+ display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
+ APS</a>&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">CalMAN X2</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#Huey">Huey</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ <br>
+ Sequel imaging (Now X-Rite):<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#mox">MonacoOPTIX</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter (Treated as an Eye-One Display 1)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [The Sequel Chroma 4 may also work.]<br>
+ <br>
+ Lacie Blue
+ Eye:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - see <a href="instruments.html#i1d">Eye-One Display</a><br>
+ <br>
+ DataColor ColorVision:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd2">Spyder 2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> firmware)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [The Spyder 1 has also been reported as working, but this has not
+ been confirmed.]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd3">Spyder 3</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="instruments.html#spyd4">Spyder 4</a>
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ <br>
+ Other:<br>
+ &nbsp;&nbsp;&nbsp; <span class="titre"><a
+ href="instruments.html#HCFR">Colorim&egrave;tre HCFR</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter</span><br>
+ &nbsp;&nbsp;&nbsp; <a href="http://www.hughski.com/">ColorHug</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. Experimental only, does not work on all
+ platforms.<br>
+ <span style="font-weight: bold;"></span><span class="titre"><br>
+ See </span><a href="instruments.html">Operation of particular
+ instruments</a> for more instrument specific detail.<br>
+ <br>
+ Other instruments can be supported indirectly, since patch result
+ files created by other packages can be imported into Argyll.<br>
+ <br>
+ Please <span style="font-weight: bold;">note</span> the <a
+ href="Installing.html">installation instructions</a> for each
+ platform - they contain important information for getting your
+ instruments working.<br>
+ <p>If you've decided to buy a color instrument because Argyll
+ supports it, please let the dealer and manufacturer know that "<span
+ style="font-weight: bold;">You bought it because Argyll CMS
+ supports it</span>" - thanks.<br>
+ </p>
+ <p><span style="font-weight: bold;">Please note that instruments are
+ being driven by ArgyllCMS drivers, and that any problems or
+ queries regarding instrument<br>
+ operation </span><span style="font-weight: bold;">should be
+ directed to the Argyll's author(s) or the Argyll mailing list,
+ and not to any</span> <span style="font-weight: bold;">other
+ party.</span> </p>
+ <p>There is a <a href="file:///D:/src/argyll/doc/ccmxs.html">list
+ of contributed</a> <span style="font-weight: bold;">ccmx</span>
+ (Colorimeter Correction Matrix) files for some display/colorimeter
+ combinations.</p>
+ <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
+ name="Copyright"></a>Copyright and Licensing:</span><br>
+ </h2>
+ <p>Most of the source code and provided executable files are
+ copyrighted works, licensed under the <span style="font-weight:
+ bold;">Affero GNU Version 3 license</span>, and therefore they
+ (or works derived from them) can't be copied, sold or made
+ available to users interacting with them remotely through a
+ computer network, without providing the source code. Nothing other
+ than your agreement and compliance with the Affero GNU License
+ grants you permission to use, modify or distribute Argyll source
+ code, executables or its derivative works. You could be sued for
+ copyright infringement if you use or distribute Argyll without a
+ valid license. The <span style="font-weight: bold;">Affero GNU</span>
+ license <span style="font-weight: bold;">prohibits</span>
+ extending these tools<span style="font-weight: bold;"></span>
+ (i.e. by combining them with other programs or scripts that make
+ use of, depend on, or work with the Argyll code) and distributing
+ them, unless the all the elements of the extensions are also made
+ available under a GPL compatible license. It is permissible to
+ provide Argyll tools with other non GPL components if the elements
+ of the package are not related, such that the packaging is mere
+ aggregation. For all the gory details, please read the
+ accompanying <a href="License.txt">license</a>. </p>
+ Note that unlike many commercial ICC profiling tools, the profiles
+ created using Argyll, are not subject to any claims or restrictions
+ of Argyll's author(s), but are assumed to be the copyright property
+ of the person who gathers the characterization data, and causes the
+ profiles to be created.
+ <p>The Argyll CMS is Copyright 1995 - 2013 Graeme W. Gill, and is
+ made available under the terms of the Affero GNU General Public
+ License Version 3, as detailed in the <a href="License.txt">License.txt</a>
+ file. Documentation is licensed under the terms of the GNU Free
+ Documentation License, Version 1.3. The author asserts his moral
+ rights over this material in relationship to the attribution and
+ integrity of these works. In particular, if these works are
+ modified in a way that materially changes their functionality,
+ then the modified works should be renamed in a way that clearly
+ distinguishes them from "Argyll" or "ArgyllCMS" so that the
+ effects of such changes do not reflect on the original works
+ integrity or the original authors reputation. A subset of files
+ (those that are related to the color instrument drivers, and are
+ collected together into the instlib.zip archive by the
+ spectro/instlib.ksh script + xicc/ccmx.h and xicc/ccmx.c) are
+ licensed under the General Public License Version 2 or later, as
+ detailed in the <a href="License2.txt">License2.txt</a> file.<br>
+ </p>
+ <p>Portions of the ColorHug instrument library
+ (spectro/colorhug.[ch]) are Copyright 2011, Richard Hughes, and is
+ licensed under the General Public License Version 2 or later, as
+ detailed in the <a href="License2.txt">License2.txt</a> file.</p>
+ <p>The tool spectro/spec2cie.c is Copyright 2005 Gerhard Fuernkranz,
+ and is made available under the terms of the GNU General Public
+ License Version 2 or later, and is licensed here under the Version
+ 3 license, as detailed in the <a href="License3.txt">License3.txt</a>
+ file.<br>
+ </p>
+ <p>The Win32 USB library libusb-win32 kernel drivers are included in
+ this distribution in the usb/driver and usb/bin directories, and
+ are copyright Stephan Meyer and Travis Robinson, and are licensed
+ under the GNU Version 2 or later (the drivers, services,
+ installer). See&nbsp; usb/driver/License.txt,
+ libusbw/COPYING_LGPL.txt and libusbw/COPYING_GPL.txt for details.
+ Additional terms noted on the <a
+ href="http://sourceforge.net/apps/trac/libusb-win32/wiki">website</a>
+ are "This license combination explicitly allows the use of this
+ library in commercial, non-Open-Source applications."<br>
+ </p>
+ <p>The icc library in<span style="font-weight: bold;"> icc</span>/,
+ the CGATS library in <span style="font-weight: bold;">cgats</span>/,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the jcnf library in <span style="font-weight: bold;">jcnf</span>/,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the files <span style="font-weight: bold;">spectro/xdg_bds.*</span>,
+ <span style="font-weight: bold;">spectro/aglob.*</span> and the
+ ucmm library in <span style="font-weight: bold;">ucmm</span>/ are
+ Copyright 1995 - 2011 Graeme W. Gill, and available according to
+ the "MIT" license granted in the icc/License.txt and
+ cgats/License.txt files, and the licenses at the top of
+ ucmm/ucmm.c and jcnf/jcnf.c.<br>
+ </p>
+ <p>The yajl library in <span style="font-weight: bold;">jcnf/yajl</span>
+ is Copyright 2007-2009, Lloyd Hilaiel and is licensed according to
+ the Berkeley-style License granted in the jcnf/yajl/COPYING files.
+ The yajl library has been repackaged and modified slightly for
+ convenience.<br>
+ </p>
+ <p> The TIFF library included in this distribution for convenience,
+ has its own copyright and license detailed in tiff/COPYRIGHT (an
+ "MIT"/"BSD" like license).<br>
+ </p>
+ <p>The Independent JPEG Group's JPEG library included in this
+ distribution for convenience, has its own copyright and license
+ detailed in jpg/README (an "MIT"/"BSD" like license). Executables
+ that include JPEG format support are based in part on the work of
+ the Independent JPEG Group. </p>
+ <p>xicc/iccjpeg.h and xicc/iccjpeg.c are from <a
+ href="http://www.littlecms.com/">lcms</a> and they are Copyright
+ (c) 1998-2010 Marti Maria Saguer and is licensed under an
+ "MIT"/"BSD" like license. See the top of the iccjpeg.c file for
+ the detailed copyright and licensing conditions.<br>
+ </p>
+ <p>The mongoose web server software is Copyright (c) 2004-2011
+ Sergey Lyubka, and is licensed under an "MIT" license. </p>
+ <h2><span style="text-decoration: underline; color: rgb(51, 0, 51);"><a
+ name="ProjType"></a>What sort of project is this ? (re:
+ contributions)<br>
+ </span></h2>
+ This is essentially my private project, that I've made available
+ under GNU licensing conditions. Because I license my code under
+ other licenses as well, there is a limit to what I will accept in
+ the way of code contributions back into this project. For me to
+ accept contributions into the distribution, it either has to a
+ non-core (side) project, or has to be offered to me with copyright
+ conditions that are compatible with my other uses (i.e.. a "BSD"
+ like license, or assigning or licensing the copyright to me), or has
+ to be so trivial (say a one line bug fix), that it can't be the
+ subject of copyright. <br>
+ <br>
+ Of course there is nothing to stop someone setting up a real free
+ software, community project based on the GNU licensed code made
+ available here, that would be able to take GNU licensed
+ contributions from everyone and would essentially be a "fork" of
+ this code base.<br>
+ <br>
+ <h1><u><a href="Compiling.html">Compiling</a></u></h1>
+ How to <a href="Compiling.html">build the software</a> from the
+ source if you want to.<br>
+ <span style="font-weight: bold;">Note</span> that you don't need to
+ do this if you are using one of the binary installations.<br>
+ <h1 style="color: rgb(51, 204, 0);"><u><a href="Installing.html">Installing</a></u></h1>
+ Important notes on <a href="Installing.html">installing the binary
+ software</a> on various platforms.<br>
+ <br>
+ <h2 style="color: rgb(51, 0, 51);"><u><u><a name="GUIs"></a>Graphic
+ User Interfaces<br>
+ </u></u></h2>
+ ArgyllCMS does not directly support a graphic user interface, but
+ several people have written <span style="font-weight: bold;">GUI</span>
+ based front ends for it. A popular <span style="font-weight: bold;"></span>front
+end
+that
+supports
+display
+calibration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and profiling is <a href="http://hoech.net/dispcalGUI/">dispcalGUI</a>
+ by Florian H&ouml;ch. Others can be found with a suitable <a
+href="http://www.google.com/search?hl=en&amp;source=hp&amp;q=argyllcms+GUI&amp;aq=f&amp;aqi=g1&amp;aql=&amp;oq=">search</a>.<br>
+ <h2 style="color: rgb(51, 0, 51);"><u><a name="CmdLine"></a>Main
+ Tools and the command line<br>
+ </u></h2>
+ These are all command line ("DOS" shell) tools, and each tool
+ require appropriate options to be set, followed by filename
+ arguments. Sometimes the filenames will have to include the usual
+ extensions, sometimes they are implicit. To get a brief listing of
+ the possible arguments and <span style="font-weight: bold;">usage</span>
+ of any of the tools, run it with just an "-?" argument, i.e. <b>targen
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -? </b>(or some other unrecognized flag, if the "?" character is
+ treated specially in your shell, i.e. try "--" on OS X zsh).<br>
+ <br>
+ Note that in general the arguments consist of possible flags or
+ options followed by file name arguments. All arguments need to be
+ separated by whitespace.&nbsp; (If you need to specify a string with
+ embedded white space, double quote the string). A flag consists of a
+ dash attached to a single letter, the letter identifying the flag,
+ and is usually case sensitive. An option is a flag that has an
+ associated parameter or parameters. The parameter can be separated
+ from the flag by white space, or may come directly after the flag.
+ So if a tool has a usage that looks like this:<br>
+ <br>
+ &nbsp; tool -?<br>
+ &nbsp; usage: tool [options] infile outfile<br>
+ &nbsp;&nbsp;
+ -v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Verbose mode<br>
+ &nbsp;&nbsp; -d
+ n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Choose a depth 0-4<br>
+ &nbsp;&nbsp; -r
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use a random depth<br>
+ &nbsp;&nbsp; -f
+ [nn]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Use full range. nn optional range 0 - 100.<br>
+ &nbsp;&nbsp; -M
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Manual<br>
+ &nbsp;&nbsp; infile
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Input file<br>
+ &nbsp;&nbsp; outfile
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Output file<br>
+ <br>
+ then there are&nbsp; 5 flags/options, and two filename arguments.
+ Notice that square braces [] denote optional items. The first
+ flag/option is a flag. The second is an option that has a numerical
+ argument in the range 0 to 4. The third is a flag. the fourth is an
+ option with an optional argument. The fourth is a flag.&nbsp; The
+ flags and options can generally be in any order, but must be before
+ the file name arguments. (For a few special tools you actually
+ specify a sequence of flags and files where the flags apply just to
+ the following file.) So example invocations may look like:<br>
+ <br>
+ &nbsp; tool -v testin testout<br>
+ &nbsp; tool -d3 -M testin1 testout2<br>
+ &nbsp; tool -f infile outfile<br>
+ &nbsp; tool -f 45 infile outfile<br>
+ &nbsp; tool -d 3 -f67 infile outfile<br>
+ <p>In order to make use of the tools, it is necessary to keep track
+ of where various files are, and what they are called. There are
+ many possible ways of doing this. One way is to put each source
+ profile and all its associated files (test charts, spectrometer
+ values etc.) in one set of directories for each source profile
+ type. Similarly the device profiles could be stored in a hierarchy
+ of directories ordered by device type, media, resolution, device
+ mode etc. Naturally you will want to set your $PATH so that you
+ can run the tools from whichever directory you are in, as well as
+ specify any necessary directory paths for file arguments so that
+ the tools are able to open them.<br>
+ </p>
+ <p>Note that there are two ways the Argyll tools deal with filename
+ extensions. In one you supply the extension (ie. you supply the
+ whole file name), so the extension is up to you. In the other
+ (used where one name is used for input and output files, or where
+ there are multiple output files), the program adds the extension.
+ In the documentation this should be indicated by calling it a
+ "base name".<br>
+ </p>
+ <p><a name="cltutes"></a>For more information on using a command
+ line environments, consult an appropriate tutorial:</p>
+ <p>MS Windows :<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.bleepingcomputer.com/tutorials/tutorial76.html">http://www.bleepingcomputer.com/tutorials/tutorial76.html</a>&gt;<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1">http://www.pcstats.com/articleview.cfm?articleid=1723&amp;page=1</a>&gt;<br>
+ &nbsp;&nbsp; &lt;<a
+ href="http://www.voidspace.org.uk/python/articles/command_line.shtml">http://www.voidspace.org.uk/python/articles/command_line.shtml</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+href="http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial">http://www.google.com/search?hl=en&amp;q=windows+command+prompt+tutorial&gt;</a><br>
+ <br>
+ OS X:<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.osxfaq.com/Tutorials/LearningCenter/">http://www.osxfaq.com/Tutorials/LearningCenter/</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.atomiclearning.com/macosxterminalx.shtml">http://www.atomiclearning.com/macosxterminalx.shtml</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html">http://www.oreillynet.com/pub/a/mac/2001/12/14/terminal_one.html</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+ href="http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial">http://www.google.com/search?hl=en&amp;q=OS+X+shell+tutorial</a>&gt;<br>
+ <br>
+ Linux:<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.linuxcommand.org/index.php">http://www.linuxcommand.org/index.php</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.tuxfiles.org/linuxhelp/shell.html">http://www.tuxfiles.org/linuxhelp/shell.html</a>&gt;<br>
+ &nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.ee.surrey.ac.uk/Teaching/Unix/">http://www.ee.surrey.ac.uk/Teaching/Unix/</a>&gt;<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; To find more: &lt;<a
+ href="http://www.google.com/search?q=linux+command+line+shell+tutorial">http://www.google.com/search?q=linux+command+line+shell+tutorial</a>&gt;</p>
+ <p><br>
+ <span style="font-weight: bold;">Note</span> that since OS X is
+ based on UNIX, there is much in common between the OS X and Linux
+ command line environments, and many of the UNIX tutorials may be
+ useful:<br>
+ </p>
+ <p>&nbsp;&nbsp;&nbsp; &lt;<a
+ href="http://www.rain.org/%7Emkummel/unix.html">http://www.rain.org/~mkummel/unix.html</a>&gt;<br>
+ <br>
+ </p>
+ <h2><u><a href="Scenarios.html">Tutorial: Typical usage scenarios
+ and examples</a></u></h2>
+ A <a href="Scenarios.html">guided tour</a> of the major tools,
+ applied to typical CMS jobs, such as calibrating displays, creating
+ device profiles, calibrating printers, linking profiles, and
+ converting color spaces of raster files. <br>
+ <br>
+ Although it is is a couple of years old now, this <a
+ href="http://www.argyllcms.com/doc/FCMS2010_ArgyllTute.pdf">tutorial</a>
+ may also be of interest.<br>
+ &nbsp; <br>
+ <h3 style="color: rgb(0, 0, 0);"><u><a name="Topics"></a>Topical
+ Discussions</u></h3>
+ Discussions about particular topics:<br>
+ <br>
+ <a href="FWA.html">About Fluorescent Whitening Agent compensation</a><br>
+ <br>
+ <a href="instruments.html">Operation of particular instruments</a><br>
+ <br>
+ <a href="iccgamutmapping.html">About ICC profiles and Gamut Mapping</a><br>
+ <br>
+ <a href="monitorcontrols.html">About display monitor settings and
+ targets</a><br>
+ <br>
+ <a href="gamma.html">About display "Gamma"</a><br>
+ <br>
+ <a href="calvschar.html">What's the difference between Calibration
+ and Characterization ?</a><br>
+ <br>
+ <a href="WideGamutColmters.html">Why doesn't my Colorimeter work
+ well on my Wide Gamut display ?</a><br>
+ <span style="font-family: monospace;"></span><br>
+ <a href="CrushedDisplyBlacks.html">My blacks get crushed on my
+ display - why ? How do I fix it ?</a><br>
+ <br>
+ <a href="i1proDriver.html">How can I have confidence in the i1pro
+ Driver ?</a><br>
+ <br>
+ <a href="evalInputTargets.html">Evaluating input targets</a><br>
+ <br>
+ <h2><b><u><font><b><u><font size="+2"><a name="Flow"></a>Flow
+ diagram of Major Tools:</font></u></b></font></u></b></h2>
+ <br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a
+ href="ArgyllFlow.jpg"><img alt="Thumbnail of Flow Diagram"
+ src="ArgyllFlowThumb.jpg" style="border: 2px solid ; width:
+ 150px; height: 202px;"></a><br>
+ <br>
+ <h2><b><u><font size="+2"><a name="CatList"></a>Main Tools by
+ category:</font></u></b></h2>
+ <h3>Calibrating devices<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="dispcal.html">dispcal</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></small>Adjust,
+ calibrate and profile a display<small><big>.<br>
+ </big></small><small><a style="font-family: monospace;"
+ href="printcal.html">printcal</a><span style="font-family:
+ monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create a
+ printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
+ <h3>Creating test targets for profiling or print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="targen.html">targen</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Generate a profiling test target values .ti1 file. </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ film recorder TIFF files from Argyll .ti1 file. </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a PS, EPS or TIFF file containing test patch values, ready for
+ printing.</big></small>
+ <h3>Obtaining test results for profiling or print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Read
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a test chart using an instrument to create a .ti3 data file.</big><span
+ style="font-family: monospace;"> </span><br style="font-family:
+ monospace;">
+ <a style="font-family: monospace;" href="dispread.html">dispread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and read colorimetric values from a display </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="filmread.html">filmread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Read
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ film colorimetric values using a SpectroScanT (Deprecated ?)</big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="scanin.html">scanin</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Convert a TIFF&nbsp; image of a test chart into .ti3
+ device values. <br>
+ </big></small><small><a style="font-family: monospace;"
+ href="illumread.html">illumread</a><span style="font-family:
+ monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use an
+ instrument to measure an illuminant spectrum, and estimate its UV
+ content.<br style="font-family: monospace;">
+ <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the reading of a device using an ICC or MPP profile. <br>
+ </big></small><small><a style="font-family: monospace;"
+ href="synthread.html">synthread</a><span style="font-family:
+ monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake the
+ reading of a device using a synthetic device model. </big></small><br
+ style="font-family: monospace;">
+ <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Convert Colorblind format CMY/RGB test chart into
+ Argyll .ti3 CGATS format. </big><br style="font-family:
+ monospace;">
+ <a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
+ format. </big><br style="font-family: monospace;">
+ <a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Convert Gretag/Logo/X-Rite or other format RGB or CMYK
+ test chart results into Argyll .ti3 CGATS format. </big><br
+ style="font-family: monospace;">
+ <a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Create a fake Argyll .ti3 CMY data file from a CMYK
+ profile, as a basis of creating a CMY to CMYK separation<br>
+ </big></small><small><a style="font-family: monospace;"
+ href="average.html">average</a><span style="font-family:
+ monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Average
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ / Merge two measurement data files</big></small><br>
+ <h3>Creating Device Profiles</h3>
+ <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create an ICC profile from the .ti3 test data. <br>
+ <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create a Model Printer Profile (MPP) from the .ti3
+ test data. <br>
+ <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Regenerate a device profiles B2A table data by
+ inverting the A2B table.
+ <h3>Creating Device Link Profiles</h3>
+ <small><a style="font-family: monospace;" href="collink.html">collink</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Link two device ICC profiles to create a device
+ link profile.
+ <h3>Converting colors or applying print calibration<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Color convert a TIFF or JPEG file using a sequence
+ of ICC device, device link, abstract profiles and calibration files.
+ <br>
+ <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Apply
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ calibration curves to an ICC profile.<br>
+ <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values through any ICC
+ profile table. <br>
+ <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values forward or inverted
+ though an ICC profile table. <br>
+ <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values though an MPP
+ profile. Also create MPP gamut files/views.<br>
+ <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a TIFF file to monochrome using an ICC device profile <br>
+ <h3>Color Tweaking tools<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="refine.html">refine</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
+ abstract profile from two chart readings, useful for refining
+ proofing profiles. <a href="mppprof.html"><br>
+ </a>
+ <h3>Creating gamut views</h3>
+ <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a gamut file or VRML file of the color gamut of an ICC profile. <br>
+ <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a gamut file or VRML file of the color gamut of a TIFF or JPEG
+ image. <br>
+ <small><a style="font-family: monospace;" href="viewgam.html">viewgam</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Convert one or more gamuts into a VRML 3D
+ visualization file. Compute an intersection.<br>
+ <h3>Diagnostic and test tools<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Dump the contents of an ICC profile as text. <br>
+ <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an ICC profile against .ti3 test chart data. <br>
+ <small style="font-family: monospace;"><a href="invprofcheck.html">invprofcheck</a>&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </small>Check ICC forward against inverse lookup. <br>
+ <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Split
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a CGATS file (ie. a .ti3) into two parts randomly to verify
+ profiling. <br>
+ <small style="font-family: monospace;"><a href="timage.html">timage</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Create TIFF test
+ images. <br>
+ <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an MPP profile against .ti3 test chart data. <br>
+ <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an instrument to read a single spot color value. <br>
+ <small><a style="font-family: monospace;" href="verify.html">verify</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Verify
+ matching of CIE in two CGATS/.ti3 files (also view differences as
+ VRML)<br>
+ <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a synthetic input, display or output calibration (<a
+ href="File_Formats.html#.cal">.cal</a>)file.
+ <h3>Other Tools</h3>
+ <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a Spectrometer to create a Colorimeter Correction Matrix
+ (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
+ for a particular display.<br>
+ <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; </span>Extract
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an embedded ICC profile from a TIFF or JPEG file.<br>
+ </small><small><a style="font-family: monospace;"
+ href="extractttag.html">extractttag</a><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
+ .ti3 data or CAL) from an ICC profile.</small><br>
+ <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; </span></small>Install
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ or uninstall display profile, set display calibration from profile
+ or .cal file, test displace and dispwin access to a display.<br>
+ <small><a style=" font-family: monospace;" href="oeminst.html">oeminst</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span></small>Install Instrument manufacturers files for the
+ Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4,&nbsp;
+ CCMX files for colorimeters.<br>
+ <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
+ style="text-decoration: underline; font-family: monospace;"></span></small>&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
+ <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
+ style="text-decoration: underline; font-family: monospace;"></span></small>Convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ spectral .ti3 readings into CIE XYZ or L*a*b* readings. Apply FWA,
+ plot spectrums.<small><a style="font-family: monospace;"
+ href="oeminst.html"></a></small><br>
+ &nbsp;
+ <h2><b><u><font size="+2"><a name="AlphList"></a>Main Tools
+ Alphabetic Listing:</font></u></b></h2>
+ <small><a style="font-family: monospace;" href="applycal.html">applycal</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Apply
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ calibration curves to an ICC profile.<br>
+ <small><a style="font-family: monospace;" href="average.html">average</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><big>Average / Merge two measurement data files</big></small><br>
+ <small><a style="font-family: monospace;" href="cb2ti3.html">cb2ti3</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Convert Colorblind format CMY/RGB test chart into
+ Argyll .ti3 CGATS format. <br>
+ <small><a style="font-family: monospace;" href="cctiff.html">cctiff</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Color convert a TIFF or JPEG file using a sequence
+ of ICC device, device link, abstract profiles and calibration files.<br>
+ <small><a style="font-family: monospace;" href="ccxxmake.html">ccxxmake</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a Spectrometer to create a Colorimeter Correction Matrix
+ (CCMX)&nbsp; or a Colorimeter Calibration Spectral Set (CCSS)&nbsp;
+ for a particular display.<br>
+ <small><a style="font-family: monospace;" href="chartread.html">chartread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Read
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a test chart using an instrument to create a .ti3 data file. <br>
+ <small><a style="font-family: monospace;" href="collink.html">collink</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Link two device ICC profiles to create a device
+ link profile. <br>
+ <small><a style="font-family: monospace;" href="colprof.html">colprof</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create an ICC profile from the .ti3 test data. <br>
+ <small style="font-family: monospace;"><a href="dispcal.html">dispcal</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </small>Adjust, calibrate and
+ profile a display<small><big>.</big></small><br>
+ <small><a style="font-family: monospace;" href="dispread.html">dispread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Test
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and read colorimetric values from a display <br>
+ <small><a style="font-family: monospace;" href="dispwin.html">dispwin</a><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; </span></small>Install
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ or uninstall display profile, set display calibration from profile
+ or .cal file, test displace and dispwin access to a display.<br>
+ <small><a style="font-family: monospace;" href="extracticc.html">extracticc</a><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; </span>Extract
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an embedded ICC profile from a TIFF or JPEG file.<br>
+ </small><small><a style="font-family: monospace;"
+ href="extractttag.html">extractttag</a><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;">&nbsp;&nbsp; </span>Extract a text tag (ie. CGATS
+ .ti3 data or CAL) from an ICC profile.</small><br>
+ <small><a style="font-family: monospace;" href="fakeCMY.html">fakeCMY</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create a fake Argyll .ti3 CMY data file from a CMYK
+ profile, as a basis of creating a CMY to CMYK separation <br>
+ <small><a style="font-family: monospace;" href="fakeread.html">fakeread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Fake
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the reading of a device using an ICC or MPP profile. <br>
+ <small><a style="font-family: monospace;" href="filmread.html">filmread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Read
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ film colorimetric values using a SpectroScanT (Deprecated ?)<br>
+ <small><a style="font-family: monospace;" href="filmtarg.html">filmtarg</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ film recorder TIFF files from Argyll .ti1 file. <br>
+ <small><a style="font-family: monospace;" href="greytiff.html">greytiff</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a TIFF file to monochrome using an ICC device profile <small><a
+ style="font-family: monospace;" href="oeminst.html"></a></small><br>
+ <small><a style="font-family: monospace;" href="iccdump.html">iccdump</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Dump the contents of an ICC profile as text. <br>
+ <small><a style="font-family: monospace;" href="iccgamut.html">iccgamut</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a gamut file or VRML file of the color gamut of an ICC profile. <br>
+ <small><a style="font-family: monospace;" href="icclu.html">icclu&nbsp;</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values through any ICC
+ profile table. <br>
+ <small><a style="font-family: monospace;" href="illumread.html">illumread</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Use
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an instrument to measure an illuminant spectrum, and estimate its UV
+ content.<br>
+ <small><a style="font-family: monospace;" href="invprofcheck.html">invprofcheck</a><span
+ style="font-family: monospace;">&nbsp; </span></small>Check ICC
+ forward against inverse lookup. <br>
+ <small><a style="font-family: monospace;" href="kodak2ti3.html">kodak2ti3</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Kodak Colorflow format CMYK test chart into Argyll .ti3 CGATS
+ format. <br>
+ <small><a style="font-family: monospace;" href="mppcheck.html">mppcheck</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an MPP profile against .ti3 test chart data. <br>
+ <small><a style="font-family: monospace;" href="mpplu.html">mpplu</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values though an MPP
+ profile. Also create MPP gamut files/views. <br>
+ <small><a style="font-family: monospace;" href="mppprof.html">mppprof</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Create a Model Printer Profile (MPP) from the .ti3
+ test data. <br>
+ <small><a style=" font-family: monospace;"
+ href="file:///D:/src/argyll/doc/oeminst.html">oeminst</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ </span></small>Install Instrument manufacturers files for the
+ Spyder 2, EDR or CCSS calibration files for i1d3 or Spyder 4,&nbsp;
+ CCMX files for colorimeters.<br>
+ <small><a style="font-family: monospace;" href="printcal.html">printcal</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a printer calibration .cal file from a .ti3 data file<small><big>.</big></small><br>
+ <small><a style="font-family: monospace;" href="printtarg.html">printtarg</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small><small><big>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a PS, EPS or TIFF file containing test patch values, ready for
+ printing.</big></small><br>
+ <small><a style="font-family: monospace;" href="profcheck.html">profcheck</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Check
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an ICC profile against .ti3 test chart data. <br>
+ <small><a style="font-family: monospace;" href="refine.html">refine</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Creates an
+ abstract profile from two chart readings, useful for refining
+ proofing profiles. <br>
+ <small><a style="font-family: monospace;" href="revfix.html">revfix</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Regenerate a device profiles B2A table data by
+ inverting the A2B table. <br>
+ <small><a style="font-family: monospace;" href="scanin.html">scanin</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Convert a TIFF&nbsp; image of a test chart into
+ .ti3 device values. <br>
+ <small><a style="font-family: monospace;" href="spec2cie.html">spec2cie</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span
+ style="text-decoration: underline; font-family: monospace;"></span></small>Convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ spectral .ti3 readings into CIE XYZ or L*a*b* readings. Apply FWA,
+ plot spectrums.<br>
+ <small><a style="font-family: monospace;" href="specplot.html">specplot</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><span
+ style="text-decoration: underline; font-family: monospace;"></span></small>&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Plot a spectrum (.sp, .cmf, .ccss) and calculate CCT and VCT.<br>
+ <small><a style="font-family: monospace;" href="splitti3.html">splitsti3</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span></small>Split
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a CGATS file (ie. a .ti3) into two parts randomly to verify
+ profiling. <br>
+ <small><a style="font-family: monospace;" href="spotread.html">spotread</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Use
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ an instrument to read a single spot color value. <small><a
+ style="font-family: monospace;" href="oeminst.html"></a></small><br>
+ <small><a style="font-family: monospace;" href="synthcal.html">synthcal</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a synthetic input, display or output calibration (<a
+ href="File_Formats.html#.cal">.cal</a>)file.<br>
+ <small><a style="font-family: monospace;" href="synthread.html">synthread</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><big>Fake
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the reading of a device using a synthetic device model. </big></small><br>
+ <small><a style="font-family: monospace;" href="targen.html">targen</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Generate a profiling test target values .ti1 file.
+ <br>
+ <small><a style="font-family: monospace;" href="tiffgamut.html">tiffgamut</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ a gamut file or VRML file of the color gamut of a TIFF or JPEG
+ image. <br>
+ <small><a style="font-family: monospace;" href="timage.html">timage</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></small>Create TIFF
+ test images. <br>
+ <small><a style="font-family: monospace;" href="txt2ti3.html">txt2ti3</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small><small><big>Convert Gretag/Logo/X-Rite or other
+ format RGB or CMYK test chart results into Argyll .ti3 CGATS
+ format.</big></small> <br>
+ <font size="-1"><a style="font-family: monospace;"
+ href="verify.html">verify</a><span style="font-family:
+ monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font>Verify
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ matching of CIE in two CGATS/.ti3 files (also view differences as
+ VRML)<br>
+ <font size="-1"><a style="font-family: monospace;"
+ href="viewgam.html">viewgam</a><span style="font-family:
+ monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></font>Convert
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ one or more gamuts into a VRML 3D visualization file. Compute an
+ intersection.<br>
+ <small><a style="font-family: monospace;" href="xicclu.html">xicclu</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span></small>Lookup individual color values forward or inverted
+ though an ICC profile table. <br>
+ <br>
+ <h2><u><a href="Environment.html">Environment Variables<br>
+ </a></u></h2>
+ <span style="text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span> Performance/memory tuning hints, plus
+ tweaks for scipting.<br>
+ <h2><u><a href="Performance.html">Performance Tuning<br>
+ </a></u></h2>
+ <span style="text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span> Performance hints. <br>
+ <h2><u><a href="Overview.html">Overview</a></u></h2>
+ Overview of the software and its aims and functionality.<br>
+ <h2><u><a href="Limitations.html">Limitations</a></u></h2>
+ Limitations of the current functionality.<br>
+ <h2><u><a href="Organisation.html">Organization</a></u></h2>
+ How directories are organized, what they contain.
+ <h2><u><a href="Source.html">Source</a></u></h2>
+ Any detailed documentation on how the software works, or what
+ algorithms it is based on. (Very incomplete.)
+ <h2><u><a href="MinorTools.html">Minor Tools</a></u></h2>
+ A very brief description of minor tools and test harnesses. <br>
+ <br>
+ <br>
+ <h2><u><a name="FFormats"></a><a href="File_Formats.html">File
+ formats that Argyll uses</a></u></h2>
+ Argyll uses a number of file formats for its operation, some that
+ are external standards, and some that are unique to Argyll. <br>
+ <br>
+ <a href="File_Formats.html#.ti1">.ti1</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Device test values <br>
+ <a href="File_Formats.html#.ti2">.ti2</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Device test values &amp; chart layout <br>
+ <a href="File_Formats.html#.ti3">.ti3</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Device test values &amp; CIE tristimulus/spectral results&nbsp; <a
+ href="ti3_format.html">Format details.</a><br>
+ <a href="File_Formats.html#.cal">.cal</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Device
+ calibration information. <a href="cal_format.html">Format details.</a><br>
+ <a href="File_Formats.html#.cht">.cht</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Test chart recognition template. <a href="cht_format.html">Format
+ details.</a> <br>
+ <a href="File_Formats.html#.gam">.gam</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3D gamut surface description <br>
+ <a href="File_Formats.html#.sp">.sp</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Illuminant spectral description <br>
+ <a href="File_Formats.html#.ccmx">.ccmx</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Colorimeter Correction Matrix <br>
+ <a href="File_Formats.html#.ccmx">.ccss</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Colorimeter Calibration
+ Spectral Set <br>
+ <a href="File_Formats.html#CGATS">CGATS</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Standard text based data exchange format <br>
+ <a href="File_Formats.html#ICC">ICC</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ International Color Consortium profile format <br>
+ <a href="File_Formats.html#MPP">MPP</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Model device profile format <br>
+ <a href="File_Formats.html#TIFF">TIFF</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tag Image File Format raster files. <br>
+ <a href="File_Formats.html#JPEG">JPEG</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Joint Photographic Experts Group, JPEG File Interchange Format
+ raster files. <br>
+ <a href="File_Formats.html#VRML">VRML</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Virtual Reality Modelling Language 3D file format. <br>
+ <br>
+ <a href="ucmm.html">ucmm</a> &nbsp; &nbsp;&nbsp;&nbsp; Unix micro
+ Color Management Module convention and configuration file format and
+ <span style="color: rgb(204, 0, 0); font-weight: bold;">Profile
+ Locations</span>.<br>
+ &nbsp;
+ <h2><u>Errors, Corrections and Omissions:</u></h2>
+ <script language="JavaScript">
+
+<!--
+
+// Comment
+
+var v1 = ".com"
+
+var v2 = "argyllcms"
+
+var v3 = "Graeme"
+
+var v4 = "@"
+
+var v5 = "mailto:"
+
+var v6 = v5 + v3 + v4 + v2 + v1
+
+document.write("<a href=" + v6 + ">" + "Let me know" + "</a>")
+
+//-->
+
+
+
+</script> If you notice any errors, corrections needed or omissions in
+ the current documentation, please contact the author.<br>
+ &nbsp; <br>
+ &nbsp;
+ </body>
+</html>
diff --git a/doc/ArgyllFlow.jpg b/doc/ArgyllFlow.jpg
new file mode 100644
index 0000000..962e42a
--- /dev/null
+++ b/doc/ArgyllFlow.jpg
Binary files differ
diff --git a/doc/ArgyllFlowThumb.jpg b/doc/ArgyllFlowThumb.jpg
new file mode 100644
index 0000000..a98b4ff
--- /dev/null
+++ b/doc/ArgyllFlowThumb.jpg
Binary files differ
diff --git a/doc/CMP_DT_003.jpg b/doc/CMP_DT_003.jpg
new file mode 100644
index 0000000..1975eeb
--- /dev/null
+++ b/doc/CMP_DT_003.jpg
Binary files differ
diff --git a/doc/CMP_Digital_Target-3.jpg b/doc/CMP_Digital_Target-3.jpg
new file mode 100644
index 0000000..b6502d5
--- /dev/null
+++ b/doc/CMP_Digital_Target-3.jpg
Binary files differ
diff --git a/doc/CRTspectrum.jpg b/doc/CRTspectrum.jpg
new file mode 100644
index 0000000..82ddd17
--- /dev/null
+++ b/doc/CRTspectrum.jpg
Binary files differ
diff --git a/doc/ChangesSummary.html b/doc/ChangesSummary.html
new file mode 100644
index 0000000..94e3aa3
--- /dev/null
+++ b/doc/ChangesSummary.html
@@ -0,0 +1,790 @@
+<!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ <meta name="description" content="Root of Argyll CMS documentation">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <meta name="Author" content="Graeme Gill">
+ <meta name="Description" content="Summary of changes for the most
+ recent release.">
+ <title>Argyll CMS changes since last release</title>
+ </head>
+ <body>
+ <h1> Summary of Argyll CMS Changes since last release</h1>
+ <h3>For a <span style="text-decoration: underline;">complete</span>
+ and more detailed list of changes, please see the log.txt file.</h3>
+ <h1>[V1.5.0 -&gt; V1.5.1] 8th March 2013</h1>
+ <ul>
+ <li>Fix spectro/instlib.ksh and standalone instlib build.</li>
+ <li>Turned off debug plot on using FWA.</li>
+ <li>Changed link $(LINKFLAGS) location in link command line
+ Jambase to get latest gcc working.</li>
+ <li>Fixed new bug in matrix display profile creation that causes
+ an inaccurate relative white point. This causes Photoshop to
+ barf on the profiles.</li>
+ <li>Added -m option to printcal.</li>
+ <li>Fix bug in webwin that causes crash.<br>
+ </li>
+ </ul>
+ <h1>[V1.4.0 -&gt; V1.5.0] 1st March 2013</h1>
+ <ul>
+ <li>Increased ease of selecting ISO 13655:2009 M0, M1 and M2
+ measurements using FWA comensation using any spectrometer that
+ can take non-UV filtered measurements. M0, M1 or M2 can now be
+ selected directly using the -f flag. [ArgyllCMS has been
+ supporting ISO 13655 M0, M1 &amp; M2 well before the standard
+ was created, thanks to its FWA compensation feature.]<br>
+ </li>
+ <li>Increased stability of i1d3 refresh display measurements by
+ increasing integration time, and tweaking crossover from
+ frequency to period measurement.</li>
+ <li>Added i1pro Rev E (i1pro2) feature support. Uses RevE
+ measurement mode, and does wavelength calibration. Uses RevE
+ (internal) stray light reduction, and black level temperature
+ compensation. The only Rev E feature not currently supported is
+ U.V. measurement, which would improve the accuracy of FWA
+ compensation. Rev E driver can be disabled and the legacy driver
+ mode used by setting the ARGYLL_DISABLE_I1PRO2_DRIVER
+ environment variable.</li>
+ <li>Changed i1pro adaptive mode to avoid high gain mode, so as to
+ give more consistent and longer integration times for low light
+ levels.</li>
+ <li>Changed ColorMunki adaptive mode to avoid high gain mode, so
+ as to give more consistent and longer integration times for low
+ levels. Added black level temperature compensation.</li>
+ <li>Added spotread interactive function 'f' to read out the
+ calibrate display refresh rate for instruments that have a
+ refresh display mode, as well as an 'F' function that measures
+ the refresh rate for instruments that support a refresh rate
+ measurement function (colorimeters &amp; spectrometers).</li>
+ <li>The Display Type selection option -y in dispcal, dispread,
+ chartread, spotread &amp; ccxxmake now lists installed CCSS and
+ CCMX files as a selection, rather than using the -X parameter.
+ CCMX and CCSS files now have extra fields to indicate the
+ refresh mode, an optional list of default UI selection
+ characters, and (for CCMX files) the base display type they
+ apply over (CB-n).<br>
+ </li>
+ <li>Tweaked CIECAM02 to improve behavior for extreme blue colors,
+ so that the hue doesn't swing too far towards the cyan. This
+ helps in the clipping behavior from colorspaces such as
+ ProPhotoRGB.</li>
+ <li>Made the input profile cLUT extra neutral axis extrapolation
+ points the default for colprof -u and non -u profiles. Changed
+ -u algorithm to work similarly to -U scale :- it sets the scale
+ automatically. Relative colorimetric is therefore hue matched to
+ the white reference patch, Removed colprof -un, as it seems
+ unnecessary. Added colprof -uc, which clips cLUT colors over Y =
+ 1 to white.</li>
+ <li>The spyd2en, spyd4en and i1d3ccss tools have been combined
+ into, and replaced by a single oeminst tool.</li>
+ <li>Fix problem with dispwin/dispcal/dispread -dweb and the latest
+ Safari browser.</li>
+ <li>Changed to a single ArgyllCMS.inf file for MSWin USB driver
+ installation. This eases installation of more than a single type
+ of instrument. Tested on MS Windows 8 and updated installation
+ instructions.</li>
+ <li>Dropped libusb for USB access, using native USB access
+ instead. MSWin uses the libusb-win32 kernel driver. Moved the
+ usb setup files from libusb1 to a new directory, usb.</li>
+ <li>Added scanin support for ColorCheckerPassort.</li>
+ <li>Updated OS X code to compile on 10.6 and 10.7 and (presumably)
+ 10.8 (64 bit compatible API used when compiling on those
+ platforms, including Cocoa for the test patch window).<br>
+ </li>
+ <li>Changed udev file usb/55-Argyll.rules to eliminate the test
+ for /lib/udev/udev-acl as a condition of using ACL_MANAGE, since
+ I'm informed that it is deprecated in recent distribution
+ releases (but who can tell, given the churn in the udev API).</li>
+ <li>Deprecated -V flag (adaptive mode) in dispcal, dispread and
+ ccxxmake, since this is now the default. Flag will be ignored
+ with a warning. Added -ZA flag instead, to select non-adaptive
+ integration time mode.</li>
+ <li>spotread -d flag is deprecated, and is now a synonym for the
+ -e flag, since it defaults to adaptive mode. Added -ZA flag
+ instead, to select non-adaptive integration time mode. Also
+ added -Zr and -ZR flags to allow testing of the refresh mode
+ overrides.</li>
+ <li>Migrated ArgyllCMS specific application runtime files (such as
+ instrument blobs, calibration state &amp; calibration files) to
+ an "ArgyllCMS" sub-directory rather than the generic "color"
+ directory. On OS X also moved data files to below the
+ "Application Support" sub directory. The old locations will be
+ used as a fallback.<br>
+ </li>
+ <li>Added support for Quato Silver Haze 3 OEM i1d3<br>
+ </li>
+ <li>Added support for X-Rite ColorMunki Smile colorimeter.</li>
+ <li>Enable the ColorHug by default, although it isn't advertised
+ as supported, since it doesn't yet work reliably on OS X.
+ Updated ColorHug PCI VID &amp; PID</li>
+ <li>For Spyder, emit a warning rather than error if the feature
+ bits are missing for calibration tables.</li>
+ <li>Added automatic adjustment of patch reading delay for i1d3, so
+ that a more conservative (longer) default value (200 msec) can
+ be used without impacting i1d3 speed. Also added environment
+ variable ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS that can set a
+ different minimum update delay.</li>
+ <li>Fixed a bug introduced in V1.3.6 that stops the dtp41 from
+ being initialized properly.</li>
+ <li>Improved black level readings derived from spectral values by
+ allowing them to be -ve. <br>
+ </li>
+ <li>The instlib API has been modified quite extensively to make it
+ more self contained and flexible, although the basic
+ architecture remains the same.<br>
+ </li>
+ </ul>
+ <h1>[V1.3.7 -&gt; V1.4.0] 20th April 2012</h1>
+ <ul>
+ <li>Modified spectro/ccxxmake so that a colorimeter can be used as
+ a reference to make ccmx files if two .ti3 files are used. Added
+ ref/ccxx.ti1 as convenient way of creating ccmx .ti3 files.<br>
+ </li>
+ <li>Added dither/screening support for 8 bit output of render, and
+ then made it available in target/printtarg.<br>
+ </li>
+ <li>Added JPEG file support to imdi/cctiff, xicc/tiffgamut and
+ xicc/extracticc. ICC profiles embedded in JPEG files can now be
+ used anywhere a TIFF file with embedded ICC profile can be used
+ as a source of an ICC profile.<br>
+ </li>
+ <li>Fixed memory leaks in usbio.c, xdg_bds.c &amp; conv.c</li>
+ <li>Fixed double memory free bug in icc/icc.c when iccdump'ing a
+ profile that has a duplicate tag.</li>
+ <li>Changed license of xicc/ccmx.[ch] to GPL2+.<br>
+ </li>
+ <li>Made display calibration and profile making deal with displays
+ without hardware calibration support (VideoLUT support) more
+ graceful. Added tutorial section covering this.<br>
+ </li>
+ <li>Added option to dispwin/dispcal/dispread/ccxxmake to redirect
+ the test patches to a web browser via a local web server. This
+ augments Argyll's existing local and remote display capability.<br>
+ </li>
+ <li>Fixed bug in spectro/i1d3.c which results in NAN if a low
+ level readings drops to zero at a particular time. Improved
+ refresh rate calibration accuracy. Fixed bugs in adaptive
+ measurement logic that caused a channel to be pre-measured when
+ it shouldn't. This seems to noticeably improve repeatability on
+ refresh displays.<br>
+ </li>
+ <li>Fixed bug in ucmm/jcnf where it was failing to locate the
+ correct profile for a display.<br>
+ </li>
+ <li>Fix bugs in ColorMunki Transmissive measurement mode
+ calibration.<br>
+ </li>
+ </ul>
+ <h1>[V1.3.6 -&gt; V1.3.7] 26th March 2012</h1>
+ <ul>
+ <li>Fix regression in Spyder support - ccmx files were not being
+ handled (bug introduced in 1.3.6).</li>
+ <li>Fix packaging problem - Spyder4 MSWin .inf file was missing.</li>
+ <li>Change dispwin so that it will install a profile when there is
+ no access to the display VideoLUT if the profile has no vcgt.<br>
+ </li>
+ </ul>
+ <h1>[V1.3.5 -&gt; V1.3.6] 19th March 2012<br>
+ </h1>
+ <ul>
+ <li>Added Spyder4 support. Note the need for spyd4en for access to
+ a full range of Manufacturers calibrations. The Spyder4 can use
+ .ccss calibration files too. Speeded up all Spyder instrument
+ readings on brighter colors.</li>
+ <li>Experimental ColorHug support is compiled in, but is disabled
+ unless the environment variable "ENABLE_COLORHUG" is set. The
+ ColorHug currently doesn't seem to work reliably across all
+ platforms ArgyllCMS supports.<br>
+ </li>
+ <li>Changed and expanded display selection (-y flag) to be
+ instrument specific. This is to support the Spyder4 and
+ ColorHug, and adds a refresh display selection to the i1d3.</li>
+ <li>Tweaked i1d3 integration times and added accurate refresh
+ period calibration to the refresh display mode. Refresh display
+ measurement times are double non-refresh displays. Improved i1d3
+ period measurement logic to improve measurement speed and
+ accuracy for dark colors.</li>
+ <li>Changed i1disp measurement logic to try and make it more
+ robust against light to dark changes during a reading. This may
+ make it slightly less precise for LCD displays on bright colors
+ (equivalent now to Refresh display precision).<br>
+ </li>
+ <li>Added a -V option to spotread to allow tracking reading
+ consistency.</li>
+ <li>Changed ccxxmake to create default .ccss with just&nbsp; RGBW,
+ and not to weight W. This may give better matching. Made
+ corresponding change to CCMX, giving the white patch 1/4
+ weighting of sum of all other patches.</li>
+ <li>Fixed applycal so that it applies calibration to both A2B and
+ B2A tables, to preserve softproofing.</li>
+ <li>Fixed timeout in SpectroScanT reference transmission
+ measurement. (Someone kindly donated me a SpectroScanT to test
+ with!)</li>
+ <li>Made DTP94 driver ignore with a warning any
+ NEEDS_OFFSET_DRIFT_CAL_ERR after a full reset. It seems that
+ occasionally a few instruments do this, and X-Rite don't appear
+ to be prepared to treat this as an instrument fault.</li>
+ <li>Added support for Datacolor SpyderCheckr (Thanks to Jos
+ Pereira).</li>
+ <li>Improved the ability of spyd2en to cope with slightly
+ different setup.exe formats.</li>
+ <li>Add support for NEC SpectraSensor Pro version of the i1d3.<br>
+ </li>
+ </ul>
+ <h1>[V1.3.4 -&gt; V1.3.5] 24th October 2011</h1>
+ <ul>
+ <li>Fix bug (crash) that affects ColorMunki design/photo display
+ measurement. This also stops it restoring a calibration (-N
+ flag).</li>
+ <li>Add support for the OEM version of the i1d3.</li>
+ <li>Fix bug that stopped ccxxmake being able to make ccmx's.</li>
+ <li>Tweak gamut mapping to improve dark area mapping,
+ non-monotonic profile inversion, and contrast preservation to
+ small gamut.</li>
+ <li>Kill i1ProfileTray.exe process if unable to open i1d3 on
+ MSWin.</li>
+ <li>Fix DTP20 chart printing - TID was sometimes incomplete. This
+ shows up on a 4x6 chart.<br>
+ </li>
+ </ul>
+ <h1>[V1.3.3 -&gt; V1.3.4] 31st August 2011</h1>
+ <ul>
+ <li>Added support for the X-Rite i1 Display Pro and ColorMunki
+ Display colorimeters. As part of this, added support for CCSS
+ calibration files for the instruments and added CCSS support to
+ ccxxmake (renamed from ccmxmake). Provide new tool i1d3ccss to
+ translating and installing CCSS files as well as the
+ manufacturers calibration files for these instruments. Added
+ non-default observer support for these instruments too.</li>
+ <li>Fix gamut code to ignore setting primary/secondary cusps that
+ are unlikely to be true. This avoids buggy gamut mapping
+ behavior for gamuts that are very small and odd shaped.</li>
+ <li>Changed Linux USB code to avoid doing a
+ set_configuration&nbsp; if possible, since the USB driver does
+ this by default. This then avoids triggering a bug in the
+ Spyder2, which allows it to work on Linux version without the
+ reset_ep fix, and may also allow the Spyder to work better with
+ USB hubs.</li>
+ <li>Change printtarg for DTP20 to allow for variable patch size.</li>
+ <li>Changed dummy display matrix table to have channels rotated
+ rather than R &amp; G swapped, to make it more obvious.</li>
+ <li>Added option to colprof to allow setting the default profile
+ rendering intent.</li>
+ <li>Enhanced spectro/fakeread so that it will process a .ti3 file
+ that has been renamed to .ti1.</li>
+ <li>Fix bug in matrix input profile white point selection, + add
+ in slight neutral bias code used in clut profiles.</li>
+ <li>New profcheck -I wasn't working - fix option parsing.</li>
+ </ul>
+ <h1>[V1.3.2 -&gt; V1.3.3] 13th May 2011</h1>
+ <ul>
+ </ul>
+ <ul>
+ <li>Fixed compiler dependant bug in Eye-One pro and (possibly)
+ Munki high res. spectral wavelength calculation.</li>
+ <li>Add support for install variables DESTDIR and PREFIX in
+ Jamtop. These can be set on the command line using "jam -s"</li>
+ <li>Added targen -N parameter to allow adjustment of neutral axis
+ patch density emphasis, as well as increasing the default. This
+ should improve the result without needing to add explicit grey
+ test patches.</li>
+ <li>Added spectro/instlib.ksh script to assemble all the files
+ needed for a standalone instrument library. Changed licence to
+ GPLv2 for the files included in the instlib.zip file that is
+ thus created. See spectro/instlib.txt for more details.</li>
+ <li>Fix Jambase so that recent MingW compilers don't need extra
+ .dll's</li>
+ <li>Change Linux serial code to test ports using O_NONBLOCK</li>
+ <li>Modify xspect &amp; illumread to improve realism of UV
+ spectrum estimation.</li>
+ <li>Fixed profile/txt2ti3 so that a sample name that looks like an
+ integer is treated as text. (Fixes problem with latest
+ ProfileMaker file).</li>
+ <li>Added LCh option to spotread.</li>
+ <li>Fixed numerical issue in scanin/scanrd.c, where large input
+ rasters would cause fitting to fail.</li>
+ <li>Modified colprof input chart white patch detection to slightly
+ favour patches that are close to D50 neutral.</li>
+ <li>Increase the default XYZ PCS A2B profile default smoothness.</li>
+ <li>Improved cLUT input -u black &amp; white&nbsp; point
+ extrapolation.</li>
+ <li>Improved black point determination for devices that have
+ extremely narrow gamuts doe to the use of custom inks.</li>
+ <li>Added -Z option to colprof, to allow setting ICC attribute
+ flags.</li>
+ <li>Fix CIECAM02 to better match forward and backwards, to fix
+ perceptual table white point.</li>
+ <li>Add code to override X-Rite's new OS X drivers for ColorMunki
+ and EyeOne. Note new installation instructions
+ &lt;http://www.argyllcms.com/doc/Installing_OSX.html&gt;.</li>
+ <li>Added -R flag to colprof, which restricts the range of the
+ white, black for better compatibility with other programs.</li>
+ <li>Fixed typo bug that prevented flash measurement mode from
+ working.</li>
+ <li>Replaced spectro/average with a new version that is more
+ general.</li>
+ <li>Fixed bug in printcal not working with spectral only files.</li>
+ <li>Added extra verbose output to printcal in which it computes an
+ ideal power-like value to apply to the test chart values in
+ targen.</li>
+ <li>Modify the way that XYZ cLUT B2A tables are indexed, so that
+ the white point is at the top corner of the grid.This should
+ solve Photoshop CS4/CS5 complaining that XYZ LUT profiles are
+ 'defective'.</li>
+ <li>Added option in xicc/xicclu to plot an arbitrary slice.</li>
+ <li>Expand the number of i1 Display OEM devices that can be used.</li>
+ <li>Made some changes to help compile on FreeBSD.</li>
+ <li>Added another intent, "pa", Perceptual Appearance, which is
+ the same as perceptual except that the grey axes are not forced
+ into alignment, allowing the appearance parameters to have full
+ affect, including altering the chromatic mapping.</li>
+ <li>Fixed bug in txt2ti3 - it wasn't creating an iRGB colorspace
+ file for output device RGB files, causing warnings warnings and
+ failures when mixed with other iRGB tool sequences. </li>
+ <li>Added pathological case fix for target/ofps where the ink
+ limit == di-2. </li>
+ <li>targen was failing to proceed when fixed points happened to be
+ numerically just over the total ink limit.</li>
+ <li>Added more navigation options for chartread patch by patch
+ mode.</li>
+ <li>&nbsp;Fixed bug in "chartread -r -H" that caused resume of
+ i1Pro high res to fail with "The resumed spectral type seems to
+ have changed".</li>
+ <li>Modified profcheck so that it prints patch location if it is
+ present in the .ti3 file.</li>
+ <li>Changed dispcal and dispread -K option to -J. Added -K option
+ to dispcal as an alternate way of profiling a calibrated
+ display, and also added a -K option to dispcal. </li>
+ <li>Increased ColorMunki emissive auto scaling target "over"
+ margin from 5% to 10% to allow more room for instrument drift
+ during measurement.</li>
+ <li>&nbsp;Fix bug in winusb + i1Display, where dark CRT
+ measurements timeout.</li>
+ </ul>
+ <h1>[V1.3.1 -&gt; V1.3.2] 4th November 2010<br>
+ </h1>
+ <ul>
+ <li>Turn off debugging that was accidentally left on in FWA code.
+ Add gcc 3.3 PPC optimizer bug workaround to FWA code in
+ xicc/xspect.c</li>
+ <li>Change shaper/matrix profile back to using power curve as 0th
+ order shape. Improve it with input &amp; output offsets and
+ straight segment at zero. Make cLUT input -u black &amp; white
+ point extrapolation use pure shaper curves with special tweaks.</li>
+ <li>Increase dispcal native white target weighting from 10 to 50
+ to encourage white to be device 1.0,1.0,1.0 more strongly.</li>
+ </ul>
+ <h1>[V1.3.0 -&gt; V1.3.1] 26th October 2010<br>
+ </h1>
+ <ul>
+ <li>Fixed MSWIN Vista/Win7 problem where having Task Manager
+ running would stop display test window updating. Also fixed plot
+ library to avoid the same problem.</li>
+ <li>Swapped dispwin -E and -D flags, to make -D debug consistent
+ throughout tools.</li>
+ <li>Changed the ARGYLL_NOT_INTERACTIVE mode so that all return and
+ line feed characters are ignored, so that they can be used
+ freely to flush stdin without triggering anything.</li>
+ <li>Fixed endless loop problem with chartread -r -p on fully read
+ chart.</li>
+ <li>Added -S option to chartread, that suppresses wrong strip and
+ unexpected value warnings.</li>
+ <li>Fix dispcal and spotread so that color temperature takes into
+ account any non-standard observer (ie. the color temperature is
+ the closest point on the spectrum locus as determined by the
+ chosen observers interpretation of the Plancian or daylight
+ spectrum.)</li>
+ <li>Fix bug in libusb1 triggered on systems that support bulk
+ continuation (Linux)</li>
+ <li>Added 1964_10c observer to spectro/dispcal, to better allow
+ comparison to the default numbers.</li>
+ <li>Added recognition for Huey built into Lenovo W series Laptops.</li>
+ <li>Fixed chartread/dispsup/spotread etc. so that -N isn't fatal
+ if the instrument doesn't support it.</li>
+ <li>Fixed dispcal to disable black &amp; white drift tracking
+ during interactive adjustment.</li>
+ <li>Added -s option to ccmxmake to allow the number of test
+ patches to be set.</li>
+ </ul>
+ <h1>[V1.2.0 -&gt; V1.3.0] 8th September 2010<br>
+ </h1>
+ <ul>
+ <li>Added option to <span style="font-weight: bold;">dispcal</span>
+ and dispread that attempts to counteract instrument black drift
+ and display white drift (-I option). This may help with
+ instruments that haven't properly acclimatised to the
+ measurement location, and LCD displays that also take some time
+ to stabilise. The is a short discussion <a
+ href="Scenarios.html#PM6">here</a>.<br>
+ </li>
+ <li>Added option to <span style="font-weight: bold;">dispcal</span>
+ to allow specifying a non 1931 2 degree observer if a
+ spectrometer is being used.<br>
+ </li>
+ <li>Added new utility spectro/<span style="font-weight: bold;">ccmxmake</span>,
+ which makes Colorimeter Correction Matrices for a particular
+ Colorimeter + Display combination, using a Spectrometer as a
+ reference. The resulting <span style="font-weight: bold;">.ccmx</span>
+ file can then be used with <span style="font-weight: bold;">spotread/dispcal/dispread</span>
+ (-X option) to improve the&nbsp; accuracy of the colorimeter on
+ that particular display. See a discussion <a
+ href="WideGamutColmters.html">here</a> and <a
+ href="Scenarios.html#PM6">here</a>.<br>
+ </li>
+ <li>Fixed bug in spotread's handling of emissive measurements. If
+ the XYZ was computed from spectral, it was using a D50 white
+ instead of no white reference.</li>
+ <li>Fixed bug in i1pro normal resolution wavelength calibration,
+ introduced in V1.2.0.<br>
+ </li>
+ <li>Changed libusb V1.0 name to libusb-1.0A, so as not to clash
+ with any official but different libusb V1.0 installation. [This
+ may necessitate re-installing device drivers on MSWin.]</li>
+ <li>Added support for HP DreamColor version of the i1 display.<br>
+ </li>
+ <li>Fix problem with ARGYLL_NOT_INTERACTIVE - reading from
+ instruments was not actually possible, because polling for input
+ was disabled.</li>
+ <li>Adjust ColorMunki dark threshold to reduce misread reports.
+ Add inconsistent data to debug output. Fix bug in adaptive mode
+ - the integration time was sometimes&nbsp; too short. Set
+ adaptive emissive target at 95% to allow a little more margin to
+ saturation.<br>
+ </li>
+ <li>Fix problem with ColorMunki reporting erroneous inconsistent
+ measurement errors. This shows up on display calibration.</li>
+ <li>Fix some minor compiler warnings.</li>
+ <li>Added direction indicators to xy values in dispcal
+ interactive&nbsp; monitor adjustments. </li>
+ <li>Fix bug in CIECAM02 viewing condition settings :- the
+ enumerated conditions after "mt" are displaced by 1. (ie. "mt"
+ is really "pc", "mb" is "mt", "md" is "mb" etc.) Added option
+ -c:sn for auto surround from the Lv parameter (-c:l).</li>
+ <li>Add option to illumread to average several readings. Fixed bug
+ in the way illumread displays available instruments.<br>
+ </li>
+ </ul>
+ <h1>[V1.1.1 -&gt; V1.2.0] 30 July 2010<br>
+ </h1>
+ <ul>
+ <li>Re-worked gamut mapping to improve perceptual intent
+ saturation levels, as well as improve highlight and shadow
+ contrast. Added fine tuning to improve both smoothness and the
+ precision with which the source is mapped to the destination.</li>
+ <li>Added illumread, which allows measuring an illuminant and
+ estimating its UV content, for better accuracy with FWA
+ compensation.</li>
+ <li>Use a modified/forked version of libusb V1.0, that supports
+ Win2K (libusb0.sys) back end by default. Supports 64 but MSWin
+ using a combination of WinUSB.sys and ptlibusb0.sys. [ The HCFR
+ does not work on Win 64 bit though, due to its buggy USB
+ implementation. ] NOTE that the included version of Libusb V1
+ has been carefully tested with all supported instruments on all
+ supported platforms,&nbsp; and includes many bug fixes needed
+ for correct functioning. While bug fixes have been fed upstream,
+ not all have been adopted. In particular there is a nasty race
+ condition that has not, and may never be fixed upstream, as well
+ as missing critical functionality (clearep()).<br>
+ </li>
+ <li>Modified colprof -p to allow different abstract profiles to be
+ applied for each intent.</li>
+ <li>Added -I option (imitation) to printcal, so that an existing
+ devices response can be set as a target.</li>
+ <li>Increase target/ofps.c vertex intersection retries from 10 to
+ 40 to give it a better chance of working with difficult
+ profiles.</li>
+ <li>Fixed bug in plot that shows up on XP+, where the window isn't
+ dismissed by the first keystroke, but only after it has been
+ moved or resized.</li>
+ <li>Changed CMYK black point to be natural, rather than the
+ darkest point in the same direction and K only. This may wreck K
+ only to black point matching, but it will stop printers with
+ funny colored K ink from messing up the black point.</li>
+ <li>Make Lacie Blue Eye colorimeter appear as an i1display.</li>
+ <li>Improved i1pro matching to Original Manufacturers Driver (see
+ doc/i1proDriver.html).</li>
+ <li>Improved i1pro/ColorMunki patch recognition for better
+ uniformity.</li>
+ <li>Fixed bug in ColorMunki driver scan mode calibration when
+ instrument is more sensitive than usual.</li>
+ <li>Added EV calculation to spotread -a<br>
+ </li>
+ </ul>
+ <h1>[V1.1.0 -&gt; V1.1.1] 21 February 2010<br>
+ </h1>
+ <ul>
+ <li>Renamed the following tools:<br>
+ &nbsp;&nbsp;&nbsp; cb2cgats&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;
+ cb2ti3<br>
+ &nbsp;&nbsp;&nbsp; kodak2cgats -&gt; kodak2ti3<br>
+ &nbsp;&nbsp;&nbsp; logo2cgats&nbsp;&nbsp;&nbsp; -&gt; txt2ti3<br>
+ &nbsp;&nbsp;&nbsp; splitcgats&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ -&gt; splitti3<br>
+ &nbsp;&nbsp;&nbsp;
+ mpprof&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -&gt;
+ mppprof<br>
+ </li>
+ <li>Modified black curve to make sure that smoothed curve meets
+ target level at boundaries.</li>
+ <li>Added -M option to printtarg, for the case where the TIFF file
+ is to include the margin.</li>
+ <li>Fixed several build bugs in imdi code related to 64 bits.</li>
+ <li>Fixed profile/colprof -u so that it is applied to matrix
+ profiles too</li>
+ <li>Changed tiffgamut to use one pass gamut hull finding and
+ modified the smoothing so as to end up with a more closely
+ wrapped volume.</li>
+ <li>Fixed bug in input matrix profiles introduced by the XYZ cLUT
+ display matrix profile change, where the correct white and black
+ point weren't being written.</li>
+ <li>Added matrix only/linear algorithm option to profile/colprof,
+ for raw camera profiling.</li>
+ <li>Modified libusb/55-Argyll.rules for better compatibility with
+ systems that have ACL installed but no ConsoleKit. Also set
+ ID_VENDOR and ID_MODEL using. usb-db.</li>
+ <li>Modified target/targen to cope better with case where adding
+ nodes fails to determine vertex positions a lot of the time,
+ causing extreme slowdown.</li>
+ <li>Fixed colprof so that the per channel input curves for XYZ PCS
+ B2A tables are actually scaled correctly.</li>
+ <li>Changed link/collink to apply Y to L* curve if the input or
+ output space is XYZ. Fixed the Y to L* scaling to make sure it
+ only apples to XYZ space, and that the L* non-linearisation
+ still applies to Y like device spaces.</li>
+ <li>Modified scanin so that it ignores any alpha channels in the
+ input .tiff file.</li>
+ <li>Changed printcal so that it will create .AMP file with more
+ than 4 channels. Also fixed up plotting to plot up to 10
+ channels.</li>
+ <li>Changed dispcal and dispread so that a request for projector
+ mode falls back to display mode if the instrument doesn't
+ support a projector mode.</li>
+ <li>Updated ref/CMP_Digital_Target-3.cht as it seems that the
+ reference chart has columns labelled "2A - 2D" rather than the
+ "AA - AD" that is actually printed on the chart...</li>
+ <li>Altered xpsect FWA code to reduce overshoot artefacts due to
+ filtering.<br>
+ </li>
+ </ul>
+ <h1>[V1.0.4 -&gt; V1.1.0] 17th January 2010<br>
+ </h1>
+ <ul>
+ <li>Spyder3 and ColorMunki Design, Photo and Create instrument
+ support.</li>
+ <li>Added a complete printer calibration system. This can work
+ either with a print system that supports per channel print
+ calibration curves, or purely using ICC profiling mechanisms.</li>
+ <li>Default targen (OFPS) test point distribution has been
+ re-written to generate test points on the gamut surface, refine
+ the point locations when using a guide profile, and use a better
+ error estimate model to determine the test point locations. <br>
+ </li>
+ <li>Changed chartread strip reading mode to allow navigating about
+ the strips, saving a partially read chart, and resuming a
+ partially read chart.<br>
+ </li>
+ <li>Improved and re-tuned gamut mapping. This is noticeably
+ smoother and better retains source image detail.</li>
+ <li>Re-tuned the cLUT profile creation smoothness vs. accuracy.</li>
+ <li>Fixed viewgam so that the number of gamuts that can be viewed
+ is unlimited. Also added error when computing intersecting
+ volume if the two gamuts are incompatible.</li>
+ <li>Improved CMYK black generation control and smoothness near the
+ black point.</li>
+ <li>Improved collink special black and colorant handling so that
+ the gamut mapping is consistent&nbsp; with the special black and
+ colorant mapping</li>
+ <li>Changed profile/colprof to generate matrix tags for Display
+ XYZ PCS cLUT profiles, to improve compatibility with other CMMs.<br>
+ By default (-ax) the matrix tags will be a dummy transform that
+ swaps red and green, while using -aX will create real matrix
+ tags.</li>
+ <li>Added -V option to dispcal and dispread to allow use of i1pro
+ adaptive mode to give better low level consistency.</li>
+ <li>Changed dispcal to default to -f 1.0 (assume black is all
+ output offset) to make it work in more sympathy to a typical
+ display response. Also changed default gamma to 2.4 for OS X
+ 10.6 systems.<br>
+ </li>
+ <li>Improved X11 XRandR CRTC detection.</li>
+ <li>Added spotread option to save spectral reading of an
+ illuminant to a .sp file.</li>
+ <li>Added Color Rendering Index (Ra) to spotread measurement
+ results.</li>
+ <li>Added i1pro &amp; ColorMunki flash measurement
+ support.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>
+ </li>
+ <li>Improve reliability of detecting backwards read i1pro/Munki
+ strips.</li>
+ <li>Fixed bug in i1pro driver that subtly affected accuracy.</li>
+ <li>Modified xicc/cam02 to clip the blue to avoid crazy behavior
+ outside the spectrum locus.</li>
+ <li>Simplified the Linux installation instructions, particularly
+ with regard to USB and serial permissions.</li>
+ <li>Added working MSWindows 64 bit libusb drivers, which will work
+ on Vista 64 and MSWindows 7 64 bit. Because of Microsoft's
+ driver signing requirements though, they won't be usable unless
+ a driver code signing workaround is used.</li>
+ <li>Changed printtarg so that the TIFF output has the paper margin
+ subtracted from it. This is so that the resulting TIFF can be
+ placed on that sized paper without clipping or scaling. Set the
+ margin to zero to get a TIFF that exactly fits into the
+ specified paper size</li>
+ </ul>
+ <h1>[V1.0.3 -&gt; V1.0.4] 30th June 2009<br>
+ </h1>
+ <ul>
+ <li>Modify icc/icclib to protect against integer overflow
+ exploits, and fixes to minor bugs. Bump icclib version to 2.11
+ to reflect this.<br>
+ </li>
+ <li>Fix bug in spectro/hidio.c that can cause a crash (bus error)
+ on OS X for any program that accesses the instruments.</li>
+ <li>Fix bug in xicc/xfit.c where too little memory was being
+ allocated.<br>
+ </li>
+ </ul>
+ <h1>[V1.0.2 -&gt; V1.0.3] 3rd September 2008<br>
+ </h1>
+ <ul>
+ <li>Added multi-TIFF and popularity filtering to <span
+ style="font-weight: bold;">tiffgamut</span>.<br>
+ </li>
+ <li>Modified gamut mapping in <span style="font-weight: bold;">colprof</span>
+ and <span style="font-weight: bold;">collink</span> to be
+ consistent, and have higher perceptual intent saturation.<br>
+ </li>
+ <li>Fixed timeout problem with the Eye-One Display colorimeter.<br>
+ </li>
+ <li>Fix segmentation fault in <span style="font-weight: bold;">dispread</span>.</li>
+ <li>Fix out of memory error in <span style="font-weight: bold;">colprof
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span>for systems with &gt; 3Gig Ram.</li>
+ <li>Add support for the Eye-One Monitor spectrometer.</li>
+ <li>Added -L option to <span style="font-weight: bold;">printtarg</span>
+ to suppress the i1pro target holder clip margin.<br>
+ </li>
+ <li>Fixed bug in <span style="font-weight: bold;">dispcal</span>
+ when using -a with -t<br>
+ </li>
+ </ul>
+ <h1>[V1.0.1 -&gt; V1.0.2] 19th August 2008<br>
+ </h1>
+ Various bug fixes, the main ones being:<br>
+ <ul>
+ <li>Fixed some <span style="font-weight: bold;">colprof </span>performance
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ and memory usage issues.</li>
+ <li>Fixed issues with Eye-One Pro Rev B timeouts.</li>
+ <li>Added new option to collink -fk, that forces 000K input to K
+ only output.</li>
+ <li>Added device target value quantization option to <span
+ style="font-weight: bold;">printtarg</span>, as well as making
+ it default for TIFF output files.put files.</li>
+ <li>Fixed leak that was affecting <span style="font-weight:
+ bold;">printtarg</span>.<br>
+ </li>
+ </ul>
+ <h1>[V0.70 Beta 8 -&gt; V1.0.0] 1st July 2008<br>
+ </h1>
+ <br>
+ Apart from numerous bug fixes and many minor feature additions and
+ improvements, the main changes to this version compared to the
+ previous one are:<br>
+ <ul>
+ <li>Speedup in profile and device link generation (inversion
+ code), and better memory usage.<br>
+ </li>
+ <li>Support for embedded profiles in TIFF files.</li>
+ <li>Support for installing and uninstalling and loading of display
+ profiles for all operating systems, and a micro CMM system for
+ X11/Linux<br>
+ </li>
+ <li>Improved display calibration and profiling, including ambient
+ light adjustment.</li>
+ <li>X11 XRandR 1.2 support added.</li>
+ <li>Raster test charts now supported, as well as PS and EPS.<br>
+ </li>
+ <li>Guidance for installing on a wider range of systems.</li>
+ <li>Fixed luminance and ambient calibration issues with various
+ instruments.</li>
+ <li>Renamed "profile" to "colprof", and "icclink" to "collink" to
+ avoid clashes that have arisen with other executable names.</li>
+ <li>Streamlined source code build system, for much easier
+ building.<br>
+ </li>
+ <li>Installation archives now include a top directory, and
+ gzip/tar format for OS X and Linux.</li>
+ <li>Added B2A table to input device LUT profiles by default.<br>
+ </li>
+ </ul>
+ As usual, a more detailed description of all changes is in the <b>log.txt</b>
+ file that accompanies the source code.
+ <h1>[V0.60 -&gt; V0.70 Beta 8]15th January 2008<br>
+ </h1>
+ <ul>
+ <li>Added quick display ICC profile creation as part of
+ calibration.</li>
+ <li>Added support for the Huey, Spyder 2, DTP20, Eye-One Pro,
+ DTP22/Digital Swatchbook, Eye-One Display 1 and 2 instruments.</li>
+ <li>Changed to GPL Version 3 license.</li>
+ <li>Countless other bug fixes and feature enhancements.<br>
+ </li>
+ </ul>
+ <br>
+ <br>
+ <br>
+ <p><br>
+ &nbsp; <br>
+ &nbsp; <br>
+ &nbsp; <br>
+ &nbsp; <br>
+ &nbsp; <br>
+ &nbsp; </p>
+ <br>
+ </body>
+</html>
diff --git a/doc/Chroma4.jpg b/doc/Chroma4.jpg
new file mode 100644
index 0000000..917a9e5
--- /dev/null
+++ b/doc/Chroma4.jpg
Binary files differ
diff --git a/doc/ColorManagement.html b/doc/ColorManagement.html
new file mode 100644
index 0000000..fa7b656
--- /dev/null
+++ b/doc/ColorManagement.html
@@ -0,0 +1,271 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="Content-Type">
+ <title>Color Management</title>
+ <meta content="Graeme W. Gill" name="author">
+ </head>
+ <body>
+ <h2 style="text-decoration: underline;">A Concise Introduction to
+ Color Management and ICC profiles<br>
+ </h2>
+ [Note that there are many other, perhaps more comprehensive and
+ expansive "introduction to Color Management" resources on the web.
+ Google is your friend...]<br>
+ <br>
+ Color management is a means of dealing with the fact that color
+ capture and output devices such as Cameras, Scanners, Displays and
+ Printers etc., all have different color capabilities and different
+ native ways of communicating color. In the modern world each device
+ is typically just part of a chain of devices and applications that
+ deal with color, so it is essential that there be some means for
+ each of these devices to communicate with each other about what they
+ mean by color.<br>
+ <br>
+ Successful color management allows colors to be captured,
+ interchanged and reproduced by different devices in a consistent
+ manner, and in such a way as to minimize the impact of any technical
+ limitation each device has in relation to color. It must also deal
+ with the interaction of human vision and devices, allowing for such
+ fundamental vision characteristics as white point adaptation and
+ other phenomena. It should also allow the human end purposes to
+ influence the choice between&nbsp; tradeoffs in dealing with
+ practical device limitations.<br>
+ <br>
+ The key means of implementing color management is to have a way of
+ relating what we see, to the numbers that each device uses to
+ represent color.<br>
+ <br>
+ The human eye is known to have 3 type of receptors responsible for
+ color vision, the long, medium and short wavelength receptors.
+ Because there are 3 receptors, human color perception is a 3
+ dimensional phenomena, and therefore at least 3 channels are
+ necessary when communicating color information. Any device capable
+ of sensing or reproducing color must therefore have at least 3
+ channels, and any numerical representation of a full range of colors
+ must have at least 3 components and hence may be interpreted as a
+ point in a 3 dimensional space. Such a representation is referred to
+ as a <span style="font-weight: bold;">Color Space</span>. <br>
+ <br>
+ Typically color capture and output devices expose their native color
+ spaces in their hardware interfaces. The native color space is
+ usually related to the particular technology they employ to capture
+ or reproduce color. Devices that emit light often choose <span
+ style="font-weight: bold;">Red Green</span> and <span
+ style="font-weight: bold;">Blue</span> (<span style="font-weight:
+ bold;">RGB</span>) wavelengths, as these are particularly
+ efficient at independently stimulating the human eye's receptors,
+ and for capture devices R,G &amp; B are roughly similar to the type
+ of spectral sensitivity of our eyes receptors. Devices that work by
+ taking a white background or illumination and filtering out (or <span
+ style="font-weight: bold;">subtracting</span>) colors tend to use
+ <span style="font-weight: bold;">Cyan</span>, <span
+ style="font-weight: bold;">Magenta</span>, and <span
+ style="font-weight: bold;">Yellow</span> (<span
+ style="font-weight: bold;">CMY</span>) filters or colorants to
+ manipulate the color, often augmented by a <span
+ style="font-weight: bold;">Black</span> channel (<span
+ style="font-weight: bold;">CMYK</span>). This is because a Cyan
+ filters out Red wavelengths, Magenta filters out Green wavelengths,
+ and Yellow filters out Blue wavelengths, allowing these colorants to
+ independently control how much RGB is emitted. Because it's
+ impossible to make filters that perfectly block C, M or Y
+ wavelengths without overlapping each other, C+M+Y filters together
+ tend to let some light through, making for an imperfect black.
+ Augmenting with an additional Black filter allows improving Black,
+ but the extra channel greatly complicates the choice of values to
+ create any particular color. <br>
+ <br>
+ Many color devices have mechanisms for changing the way they respond
+ to or reproduce color, and such features are called <span
+ style="font-weight: bold;">Adjustments</span>, or <span
+ style="font-weight: bold;">Calibration</span>. Such features can
+ be very useful in adapting the device for use in a particular
+ situation, or for matching different instances of the device, or for
+ keeping its behavior constant in the face of component or
+ environmental changes. Sometimes there may be internal
+ transformations going on in the device so that it presents a more or
+ less expected type of color space in its hardware interface. [ Some
+ sophisticated devices have built in means of emulating the behavior
+ of other devices, but we won't go into such details here, as this is
+ really just a specialized implementation of color management. ]<br>
+ <br>
+ To be able to communicate the way we see color, a common "language"
+ is needed, and the scientific basis for such a language was laid
+ down by the International Commission on Illumination (CIE) in 1931
+ with the establishment of the CIE 1931 <span style="font-weight:
+ bold;">XYZ</span> color space. This provides a means of predicting
+ what light spectra will match in color for a Standard Observer, who
+ represents the typical response of the Human eye under given viewing
+ conditions. Such a color space is said to be <span
+ style="font-weight: bold;">Device Independent</span> since it is
+ not related to a particular technological capture or reproduction
+ device. There are also closely related color-spaces which are direct
+ transformations of the XYZ space, such as the <span
+ style="font-weight: bold;">L* a* b*</span> space which is a more
+ perceptually uniform device independent colorspace.<br>
+ <br>
+ As mentioned above, the key to managing color is to be able to
+ relate different color spaces so that they can be compares and
+ transformed between. The most practical approach to doing this is to
+ relate all color spaces back to one common colorspace, and the CIE
+ XYZ colorspace is the logical choice for this. A description of the
+ relationship between a devices native color space and an XYZ based
+ colorspace is commonly referred to as a <span style="font-weight:
+ bold;">Color Profile</span>. As a practical issue when dealing
+ with computers, it's important to have a common and widely
+ understood means to communicate such profiles, and the <span
+ style="font-weight: bold;">ICC</span> profile format standardized
+ by the <b>International Color Consortium</b> is today's most widely
+ supported color profile format.<br>
+ <br>
+ The ICC profile format refers to it's common color space as the <span
+ style="font-weight: bold;">Profile Connection Space</span> (<span
+ style="font-weight: bold;">PCS</span>), which is closely based on
+ the CIE XYZ space. ICC profile are based on a Tagged format, so they
+ are very flexible, and may contain a variety of ways to represent
+ profile information, and may also contain a lot of other optional
+ information.<br>
+ <br>
+ There are several fundamental types of ICC profiles. <span
+ style="font-weight: bold;">Device</span> and <span
+ style="font-weight: bold;">Named</span> profiles represent color <span
+ style="text-decoration: underline;">anchor points</span>. <span
+ style="font-weight: bold;">Device Link</span> and <span
+ style="font-weight: bold;">Abstract</span> profiles represent <span
+ style="text-decoration: underline;">journeys</span> between anchor
+ points.<br>
+ <br>
+ <span style="font-weight: bold;">Device</span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; These primarily provide a translation between
+ device space and PCS. They also typically provide a translation in
+ the reverse direction, from PCS to device space. They provide an
+ "color anchor" with which we are able to navigate our way around
+ device color. The mechanisms they use to do this are discussed in
+ more detail below.<br>
+ <br>
+ <span style="font-weight: bold;">Device Link</span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; A Device Link profile provides a transformation
+ from one Device space to another. It is typically the result of
+ linking two device profiles, ie. Device A -&gt; PCS -&gt; Device B,
+ resulting in a direct Device A -&gt; Device B transformation.<br>
+ <br>
+ <span style="font-weight: bold;">Abstract</span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; An abstract profile contains a transformation
+ define in PCS space, and typically represents some sort of color
+ adjustment in a device independent manner.<br>
+ <br>
+ <span style="font-weight: bold;">Named</span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; A Named profile is analogous to a device Profile,
+ but contains a list of named colors, and the equivalent PCS and
+ possibly Device values.<br>
+ <br>
+ Most of the time when people talk about "ICC profiles" they mean <span
+ style="font-weight: bold;">Device Profiles</span>. Profiles rely
+ on a set of mathematical models to define the translation from one
+ colorspace to another. The models represent a general framework,
+ while a specific profile will define the scope of the model as well
+ as it's specific parameters, resulting an a concrete translation.
+ Profiles are typically used by <span style="font-weight: bold;">CMM</span>s
+ (Color Management Modules), which are a piece of software (and
+ possibly hardware) that knows how to read and interpret an ICC
+ profile, and perform the translation it contains.<br>
+ <br>
+ Often the function of a CMM will be to take two device profiles, one
+ representing the starting point and the other representing the
+ destination, and create a transformation between the two and
+ applying it to image pixel values.<br>
+ <br>
+ Two basic models can be used in ICC profiles, a <span
+ style="font-weight: bold;">Matrix/shaper</span> model and a <span
+ style="font-weight: bold;">cLUT</span> (Color Lookup Table) model.
+ Models often contain several optional processing elements that are
+ applied one after the other in order to provide an overall
+ transformation. <br>
+ <br>
+ The Matrix/Shaper model consists of a set of per channel lookup
+ curves followed by a 3x3 matrix. The curves may be defined as a
+ single power value, or as a one dimensional lookup table which
+ encodes a discretely represented curve (Lut). The matrix step can
+ only transform between 3 dimensional to 3 dimensional color spaces.<br>
+ <br>
+ The cLUT model consists of an optional 3x3 matrix, a set of per
+ channel one dimensional LUTs, an N dimensional lookup table (cLUT)
+ and a set of per channel one dimensional LUTs. It can transform from
+ any dimension input to any dimension output.<br>
+ <br>
+ All Lookup Tables are interpolated, so while they are defined by a
+ specific set of point values, in-between values are filled in using
+ (typically linear) interpolation.<br>
+ <br>
+ For a one dimensional Lookup table, the number of points needed to
+ define it is equal to its resolution.<br>
+ <br>
+ For an n-dimensional cLUT, the number of points needed to define it
+ is equal to it's resolution taken to the power of the number of
+ input channels. Because of this, the number of entries <span
+ class="st"><em></em></span>climbs rapidly with resolution, and
+ typical limited resolution tables are used to constrain profile file
+ size and processing time. cLUT's permit detailed, independent
+ control over the the transformation throughout the colorspace.<br>
+ <br>
+ <span style="font-weight: bold;">Limitations of CIE XYZ</span><br>
+ <br>
+ Although CIE XYZ colorspace forms an excellent basis for connecting
+ what we can measure with what we see in regard to color, it has its
+ limitations. The primary limitation is that the visual match between
+ two colors with the same XYZ values assumes identical viewing
+ conditions. Our eyes are marvelously adaptable, automatically
+ adjusting to different viewing conditions so that we are able to
+ extract the maximum amount of useful visual information. There are
+ many practical situations in which the viewing conditions are not
+ identical - e.g. when evaluating an image against our memory of an
+ image seen in a different location, or in viewing images side by
+ side under mixed viewing conditions. One of the primary things that
+ can change is our adaptation to the white point of what we are
+ looking at. This can be accounted for in XYZ space by applying a
+ chromatic adaptation, which mimics the adaptation of the eye. The
+ ICC profile format PCS space by default adapts the XYZ values to a
+ common white point (D50), to facilitate ease of matching colors
+ amongst devices with different white points. Other viewing condition
+ effects (ie. image luminance level, viewing surround luminance and
+ flare) can be modeled using (for example) using CIECAM02 to modify
+ XYZ values.<br>
+ <br>
+ Another limitation relates to spectral assumptions. CIE XYZ uses a
+ standard observer to convert spectral light values into XYZ values,
+ but in practice every observer may have slightly different spectral
+ sensitivities due to biological differences, including aging.
+ (People with color deficient vision may have radically different
+ spectral sensitivities.) Our eyes also have a fourth receptor
+ responsible for low light level vision, and in the eye's periphery
+ or at very low light levels it too comes to play a role in the color
+ we perceive, and is the source of a difference in the eye's spectral
+ sensitivity under these conditions. <br>
+ <br>
+ Another spectral effect is in the practice of separating the color
+ of reflective prints from the light source used to view them, by
+ characterizing a prints color by it's reflectance. This is very
+ convenient, since a print will probably be taken into many different
+ lighting situations, but if the color is reduced to XYZ reflectance
+ the effect of the detailed interaction between the spectra of the
+ light source and print will lead to inaccuracies.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/ColorMunki.jpg b/doc/ColorMunki.jpg
new file mode 100644
index 0000000..513d770
--- /dev/null
+++ b/doc/ColorMunki.jpg
Binary files differ
diff --git a/doc/ColorMunkiCreate.jpg b/doc/ColorMunkiCreate.jpg
new file mode 100644
index 0000000..64b3dbd
--- /dev/null
+++ b/doc/ColorMunkiCreate.jpg
Binary files differ
diff --git a/doc/Compiling.html b/doc/Compiling.html
new file mode 100644
index 0000000..b4fcd7c
--- /dev/null
+++ b/doc/Compiling.html
@@ -0,0 +1,170 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=ISO-8859-1">
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Compiling</title>
+ </head>
+ <body>
+ <h2> <u>Compiling the Source Code</u></h2>
+ If you have downloaded the source code package, then you will need
+ to read the following instructions in order to compile and then run
+ any of the tools. If you have downloaded one of the platform
+ specific executable package, then the executables don't need to be
+ compiled, and the following instructions are not relevant.<br>
+ <h5 style="text-decoration: underline;">Check your development
+ environment:</h5>
+ Check you have one of the supported development environments <a
+ href="ArgyllDoc.html">listed</a>, and that your shell is
+ configured to have access to the development tools.<br>
+ <br>
+ On Linux, check that the appropriate development packages are
+ installed:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; jam: Program construction tool, similar to make
+ [If available]<br>
+ &nbsp;&nbsp;&nbsp; gcc C compiler<br>
+ &nbsp;&nbsp;&nbsp; Development files for libX11<br>
+ &nbsp;&nbsp;&nbsp; Development files for libXdmcp<br>
+ &nbsp;&nbsp;&nbsp; X.Org X11 libXext development package<br>
+ &nbsp;&nbsp;&nbsp; X.Org X11 libXxf86vm development package<br>
+ &nbsp;&nbsp;&nbsp; X.Org X11 libXinerama development package<br>
+ &nbsp;&nbsp;&nbsp; X.Org X11 libXrandr development package<br>
+ &nbsp;&nbsp;&nbsp; X.Org X11 libXScrnSaver A.K.A. libxss-dev
+ development package
+ <h5><span style="text-decoration: underline;">Setup JAM:</span><br>
+ </h5>
+ Argyll makes use of a build system called <a
+ href="http://www.perforce.com/jam/jam.html">Jam/MR</a>. Jam is
+ cross platform, highly customizable and flexible. It uses a concise,
+ scalable and platform neutral configuration files, and is fast.<br>
+ <p>If you do not already have Jam 2.5 on your system or if it is not
+ available as an installable package, you will need to install it.
+ [It may be available as an RPM for Linux systems.] Jam/MR is
+ available from <a href="ftp://ftp.perforce.com/jam/">&lt;ftp://ftp.perforce.com/jam&gt;</a>
+ You'll want to bootstrap it up using its Makefile - see the <span
+ style="font-weight: bold;">README</span> file that comes with
+ Jam for more information. You may want to apply the patch <span
+ style="font-weight: bold;">jam.patch</span> included in Argyll
+ to <span style="font-weight: bold;">jam.c</span> so that it uses
+ the environment variable <span style="font-weight: bold;">JAMBASE</span>,
+ and then setting this environment variable to point to the Argyll
+ Jambase. The patch also fixes a non-critical bug that affects
+ building using MingW. Note that building jam results in an
+ executable <span style="font-weight: bold;">jam0</span> that you
+ will want to rename and install in an appropriate place on your
+ system. A <span style="font-weight: bold;">pre-patched</span>
+ source archive of Jam is available as a&nbsp; <a
+ href="http://www.argyllcms.com/ajam-2.5.2-1.3.3.zip">.zip here
+ for MSWin</a>, or as a <a
+ href="http://www.argyllcms.com/ajam-2.5.2-1.3.3.tgz">.tgz for OS
+ X and Linux</a>.<br>
+ </p>
+ <p>An alternative to the original Jam may be <a
+ href="http://freetype.sourceforge.net/jam/index.html">ftjam</a>,
+ which is appears to be backwards compatible with the original
+ Jam/MR.</p>
+ <p>The <span style="font-weight: bold;">Jambase</span> I am using
+ for Argyll is different to the default Jambase provided with Jam
+ and compiled into it,&nbsp; and you need to arrange to use this
+ when you compile Argyll. You can tell Jam to use an alternate
+ Jambase using the <span style="font-weight: bold;">-f</span>
+ option, or by setting the environment variable <span
+ style="font-weight: bold;">JAMBASE</span> to point to the Argyll
+ Jambase if you applied the Argyll patch to jam. Another method
+ would be to create a shell alias of jam that invokes jam using the
+ -f flag, or to create a script that provides the -f option to
+ point to the Argyll Jambase. Argyll will not build properly if you
+ use the wrong Jambase. </p>
+ If you are running on Mac OSX, then even though OSX comes with a
+ version of Jam/MR in the development system, you will need to
+ download, build and install a normal version of Jam/MR Version 2.5
+ or later from perforce, to be able to build Argyll. This is due to
+ Apple changing their version of Jam sufficiently to make it
+ incompatible with normal Jamfiles :-(.<br>
+ <p>On OSX what I did was to name the "normal" Jam ajam, and then
+ setup a jam shell script to invoke it something like this: "ajam
+ -f~/src/argyll/Jambase $*", and to make sure that my script is
+ ahead of Apples jam in my $PATH.&nbsp; The makeall.ksh script or
+ Makefile will run Jam with the -f flag.</p>
+ <p>You may also have to set the appropriate environment variable to
+ tell the Jambase which compiler you are using.<br>
+ </p>
+ <h5><span style="text-decoration: underline;">Then compile Argyll:</span><br>
+ </h5>
+ <p>Once you've got a working Jam, you simply have to unzip the
+ argyll.zip file, and it will create a top level directory <span
+ style="font-weight: bold;">Argyll_VX.X.X</span>, where X.X.X is
+ the version number, and you can then cd into this directory and
+ run <span style="font-weight: bold;">jam</span>. <span
+ style="color: rgb(102, 0, 204);"></span><span style="color:
+ rgb(102, 0, 204);"></span>For a faster build on a multiprocessor
+ system you may like to use the -j option&nbsp; to do a parallel
+ build, e.g. <span style="font-weight: bold;">jam -j3</span>. To
+ install the executables in the bin directory and the sample files
+ into the <span style="font-weight: bold;">ref</span> directory,
+ run <span style="font-weight: bold;">jam install</span>. To
+ remove everything that has been built, run <span
+ style="font-weight: bold;">jam clean</span>. On Linux/OS X you
+ could also just try running make, and the makefile will invoke
+ jam.<br>
+ </p>
+ <p>Something to watch on the Intel versions of OS X 10.4, is that
+ your shell environment variable $MACHTYPE may be incorrect. On
+ Intel 10.4 it should be i386-apple-darwin8.0, but there are bugs
+ in Apples distribution.<br>
+ </p>
+ <p>You may have to check that your shell environment variable $<span
+ style="font-weight: bold;">HOSTTYPE</span> has been exported, so
+ that Jam can know if it's 64 bit or not,<br>
+ and look for libraries in the right place. You can fix this
+ permanently in your shell .initialization file (ie. ~/.profile,
+ ~/.bashrc etc.).<br>
+ </p>
+ <p>To build a particular sub directory only, cd to the directory and
+ simply run <span style="font-weight: bold;">jam</span>, although
+ be aware that the local Jamfile compile time options may be
+ different to those in the top level Jamfile used when compiling
+ from the top.<br>
+ </p>
+ <p><span style="font-weight: bold;">NOTE</span> that "jam install"
+ doesn't install the resulting binaries in the "usual places", it
+ installs them in the <span style="font-weight: bold;">Argyll_VX.X.X/</span><span
+ style="font-weight: bold;">bin</span> directory, and it's then
+ up to you whether you want copy them to somewhere like C:\Program
+ Files\argyll, /usr/bin, /usr/local/bin etc., or simply leave them
+ there. </p>
+ <h5><span style="text-decoration: underline;">Compile environment on
+ MSWindows:</span></h5>
+ <p>Setting up a compile environment on MSWindows can be challenging.
+ The simplest approach is probably to install MingW, since it
+ provides both the compiler and the SDK in one package.<br>
+ <br>
+ I've successfully compiled using Microsoft VC++ 6.0, but I think I
+ remember tweaking some of the header files by borrowing from a
+ latter SDK to be able to incorporate the&nbsp; necessary function
+ calls to access display and color profiles on Win2K and latter, so
+ this may not work "out of the box".</p>
+ <p>I've also successfully compiled using Microsoft VC++ 8.0 and VC++
+ 9.0 Express (the free Microsoft compiler) plus the Microsoft
+ Platform SDK February 2008. To get this to work though, I had to
+ create my own batch file to setup the SDK environment variables <span
+ style="font-weight: bold;">MSSdk</span> etc., because the batch
+ files provided with the SDK got confused by the presence of VC++6,
+ and didn't notice that VC++8 or 9 was configured.</p>
+ <p>Note that for some hard to fathom reason VC++ 9.0 refused to
+ install on my Win2K development machine, so I had to install it on
+ a WinXP machine and then copy the installation back to Win2K, and
+ manually complete the installation. There seems to be no reason
+ for this limitation, since the VC++9&nbsp; compiler/linker etc.
+ seems quite happy to run on Win2K.</p>
+ <p>I haven't attempted to compile for Win64, and currently the
+ Jambase isn't setup for cross compilation, nor have I tried to
+ setup a native build environment yet on Vista64.<br>
+ &nbsp; </p>
+ </body>
+</html>
diff --git a/doc/CrushedDisplyBlacks.html b/doc/CrushedDisplyBlacks.html
new file mode 100644
index 0000000..3038384
--- /dev/null
+++ b/doc/CrushedDisplyBlacks.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Crushed Display Blacks</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta content="Graeme Gill" name="author">
+</head>
+<body>
+<h2 style="text-decoration: underline; font-weight: bold;">Crushed
+Display Blacks<br>
+</h2>
+Often people create a display profile, and then notice that when they
+try and display some images using the profile, that the darkest blacks
+in the image all get crushed into the black of the display. Why does
+this happen ?<br>
+<br>
+There are many reasons this may happen, but here is a common one:<br>
+<br>
+The image has blacks that are darker than the black of the display, and
+the color management intent being used clips out of gamut colors. So
+all the blacks that are darker than the display black get mapped to the
+display black. To avoid this, some sort of <span
+ style="font-weight: bold;">Gamut Mapping</span> that maps that black
+of the source image to the black of the display, while preserving the
+distinction between all the rest of the colors needs to be used.<br>
+<br>
+Some popular synthetic colorspaces have a perfect (and unrealistic)
+zero black, for instance <span style="font-weight: bold;">sRGB</span>
+and <span style="font-weight: bold;">AdobeRGB</span>. Real world
+display profiles have non-zero blacks, so transforming between these
+two using a colorimetric intent will clip the blacks, and loose the
+shadow details.<br>
+<br>
+<h4 style="text-decoration: underline;">What performs gamut mapping ?</h4>
+Typically there are only two mechanisms available to perform gamut
+mapping. The main one is a pre-cooked (static) gamut mapping built into
+cLUT type ICC profiles. The second is an on-the-fly (dynamic) gamut
+mapping performed by the CMM (Color Management Module). A limited form
+of the latter is Adobe BPC (Black point compensation), which is also
+available sometimes with applications or systems that use lcms. (Little
+cms).<br>
+<br>
+<h4 style="text-decoration: underline;">How do I fix it ?</h4>
+There are two ways of avoiding the black crush. One is to turn on BPC
+if it is available in the system you are using. Sometimes it may only
+be available for certain intents.<br>
+<br>
+The second way of fixing it is to create your display profile with
+appropriate gamut mapping, and make sure that it gets used.<br>
+<br>
+Shaper/Matrix type ICC profiles do not support gamut mapping, since
+there is only one transformation in them and it does not have the
+necessary flexibility to incorporate gamut mapping. Shaper/Matrix
+profiles are always colorimetric intent. So it is necessary to create a
+cLUT based Display profile if gamut mapping is to be incorporated into
+the profile. (Note that not all systems accept cLUT based Display
+profiles). Creating cLUT profiles that incorporate appropriate gamut
+mapping depends on the profile creation tools, and not all tools give
+adequate control over gamut mapping to reliably fix this problem.<br>
+<br>
+<h4 style="text-decoration: underline;">OK, so how do I fix it using
+Argyll ?</h4>
+You can usually fix this problem using Argyll by simply creating a cLUT
+based profile (the default), and telling colprof what the source
+colorspace is going to be.<br>
+<br>
+i.e. say your source images are in sRGB space, then:<br>
+<br>
+&nbsp;&nbsp;&nbsp; colprof&nbsp;-v -S&nbsp;sRGB.icm&nbsp;-D "My
+Display" MyDisplayProfile
+<br>
+<br>
+[It's usually safer to use the sRGB profile provided by Argyll than use
+an sRGB profile of unknown origin. Find it in the ref directory.]<br>
+<br>
+This will create 3 separate B2A cLUT tables, one for colorimetric
+intent, one for Perceptual intent, and one for Saturation intent. Both
+Perceptual and Saturation tables will have appropriate gamut mapping
+for a source colorspace of sRGB. So it is just a matter of making sure
+that either Perceptual or Saturation intent is used when making use of
+the display profile.<br>
+<br>
+</body>
+</html>
diff --git a/doc/DC.jpg b/doc/DC.jpg
new file mode 100644
index 0000000..4b3508e
--- /dev/null
+++ b/doc/DC.jpg
Binary files differ
diff --git a/doc/DTP20.jpg b/doc/DTP20.jpg
new file mode 100644
index 0000000..f5ec164
--- /dev/null
+++ b/doc/DTP20.jpg
Binary files differ
diff --git a/doc/DTP22.jpg b/doc/DTP22.jpg
new file mode 100644
index 0000000..93d7400
--- /dev/null
+++ b/doc/DTP22.jpg
Binary files differ
diff --git a/doc/DTP41.jpg b/doc/DTP41.jpg
new file mode 100644
index 0000000..1a946e9
--- /dev/null
+++ b/doc/DTP41.jpg
Binary files differ
diff --git a/doc/DTP51.jpg b/doc/DTP51.jpg
new file mode 100644
index 0000000..946810c
--- /dev/null
+++ b/doc/DTP51.jpg
Binary files differ
diff --git a/doc/DTP92.jpg b/doc/DTP92.jpg
new file mode 100644
index 0000000..2570daa
--- /dev/null
+++ b/doc/DTP92.jpg
Binary files differ
diff --git a/doc/DTP94.jpg b/doc/DTP94.jpg
new file mode 100644
index 0000000..d99feaf
--- /dev/null
+++ b/doc/DTP94.jpg
Binary files differ
diff --git a/doc/DocLicense.txt b/doc/DocLicense.txt
new file mode 100644
index 0000000..cd2b3b1
--- /dev/null
+++ b/doc/DocLicense.txt
@@ -0,0 +1,451 @@
+ GNU Free Documentation License
+ Version 1.3, 3 November 2008
+
+
+ Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+ <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The "Document", below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as "you". You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject. (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The "publisher" means any person or entity that distributes copies of
+the Document to the public.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".) To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no
+other conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to
+give them a chance to provide you with an updated version of the
+Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other
+documents released under this License, and replace the individual
+copies of this License in the various documents with a single copy
+that is included in the collection, provided that you follow the rules
+of this License for verbatim copying of each of the documents in all
+other respects.
+
+You may extract a single document from such a collection, and
+distribute it individually under this License, provided you insert a
+copy of this License into the extracted document, and follow this
+License in all other respects regarding verbatim copying of that
+document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the
+GNU Free Documentation License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in
+detail to address new problems or concerns. See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation. If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+11. RELICENSING
+
+"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works. A
+public wiki that anybody can edit is an example of such a server. A
+"Massive Multiauthor Collaboration" (or "MMC") contained in the site
+means any set of copyrightable works thus published on the MMC site.
+
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+"Incorporate" means to publish or republish a Document, in whole or in
+part, as part of another Document.
+
+An MMC is "eligible for relicensing" if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole or
+in part into the MMC, (1) had no cover texts or invariant sections, and
+(2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.3
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
diff --git a/doc/Environment.html b/doc/Environment.html
new file mode 100644
index 0000000..a319513
--- /dev/null
+++ b/doc/Environment.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=ISO-8859-1">
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Environment Variables</title>
+ </head>
+ <body>
+ <br>
+ <h2> <u>Environment variables<br>
+ </u></h2>
+ The following environment variables affect behaviour:<br>
+ <br>
+ <span style="font-weight: bold;">ARGYLL_NOT_INTERACTIVE</span><br>
+ <br>
+ <div style="margin-left: 40px;">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.<br>
+ <br>
+ If the <span style="font-weight: bold;">ARGYLL_NOT_INTERACTIVE</span>
+ environment variable is set, then:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; A Line Feed will be added to the end of each
+ progress line.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Any time it would wait for a single keystroke
+ input, it will instead wait for and read the next character from
+ stdin.<br>
+ &nbsp;&nbsp;&nbsp; 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.<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Note that while a reading is being made, a
+ character input can abort the reading, just as with normal
+ interactive mode.<br>
+ </div>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;">ARGYLL_COLMTER_CAL_SPEC_SET</span><br>
+ <span style="font-weight: bold;">ARGYLL_COLMTER_COR_MATRIX</span><br>
+ <br>
+ <div style="margin-left: 40px;">Both of these can be used to set a
+ default <span style="font-weight: bold;">CCMX</span> or <span
+ style="font-weight: bold;">CCSS</span> colorimeter calibration
+ file, equivalent to supplying a <span style="font-weight: bold;">-X</span>
+ argument to spotread, dispcal, dispread and any other utility that
+ allows using a colorimteter. The ARGYLL_COLMTER_CAL_SPEC_SET will
+ take priority if both are set.<br>
+ <br>
+ </div>
+ <br>
+ <span style="font-weight: bold;">ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS<br>
+ <br>
+ </span>
+ <div style="margin-left: 40px;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"></span></span></span>Normally
+
+ a delay of 200 msec is allowed between changing a patch color on a
+ display, and reading the color with an instrument, although some
+ instruments (ie. i1d3) will automatically measure and set an
+ appropriate delay during instrument calibration. In rare
+ situations this delay may not be sufficient (ie. some TV's with
+ extensive image processing features turned on), and a larger delay
+ can be set using the <span style="font-weight: bold;"><span
+ style="font-weight: bold;"><span style="font-weight: bold;"></span></span></span>ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS
+
+ environment variable, ie. ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS=400
+ would set a 400 msec minimum delay.<br>
+ </div>
+ <span style="font-weight: bold;"><br>
+ ARGYLL_IGNORE_XRANDR1_2<br>
+ <br>
+ </span>
+ <div style="margin-left: 40px;">On an X11 system, if this is <span
+ style="font-weight: bold;"></span>set (ie. set it to "yes"),
+ then the presence of the XRandR 1.2 extension will be ignored, and
+ other extensions such as Xinerama and XF86VidMode extension will
+ be used. This may be a way to work around buggy XRandR 1.2
+ implementations.<br>
+ <br>
+ </div>
+ <span style="font-weight: bold;">ARGYLL_DISABLE_I1PRO2_DRIVER<br>
+ <br>
+ </span>
+ <div style="margin-left: 40px;">There is now partial support for the
+ Eye-One Pro Rev E (aka Eye-One Pro 2) instrument, but a Rev E can
+ be operated in legacy mode if the environment variable
+ ARGYLL_DISABLE_I1PRO2_DRIVER is set (ie. set it to "yes").<br>
+ </div>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;">XDG_CACHE_HOME<br>
+ <span style="font-weight: bold;"><br>
+ </span></span>
+ <div style="margin-left: 40px;">Argyll tries to follow the <a
+href="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG
+
+ Base Directory Specification</a>, and uses the <span
+ style="font-weight: bold;">XDG_CACHE_HOME</span> environment
+ variable to place per instrument calibration information (Eye-One
+ Pro and ColorMunki instruments).<br>
+ </div>
+ <br>
+ <span style="font-weight: bold;">XDG_CONFIG_DIRS<br>
+ XDG_DATA_DIRS<span style="font-weight: bold;"><br>
+ <span style="font-weight: bold;"></span></span></span><br>
+ <div style="margin-left: 40px;">On Unix type operating systems,
+ configuration and profiles for displays are placed relative to
+ these environment variables.<br>
+ </div>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; <br>
+ <br>
+ See <a href="Performance.html">Performance Tuning</a> for other
+ variables.<br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/FWA.html b/doc/FWA.html
new file mode 100644
index 0000000..c1d4c6d
--- /dev/null
+++ b/doc/FWA.html
@@ -0,0 +1,262 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Fluorescent Whitener Additive Compensation</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ </head>
+ <body>
+ <h2><u>Fluorescent Whitener Additive Compensation (FWA Compensation)</u></h2>
+ <br>
+ <h3>Introduction</h3>
+ To make paper look "whiter" without increasing the cost of
+ production, paper manufactures often employ a couple of different
+ techniques. One technique is to add "shading agents" to the paper,
+ that absorb a little of the middle wavelengths, thereby changing the
+ color of the paper to be a little less green. By far the most
+ powerful way of making the paper appear more white is to add
+ Fluorescent Whitener Additive (FWA, or Optical Brightening Agents -
+ OBA) to the paper. This is basically a fluorescent material that
+ absorbs light at Ultra Violet (U.V.) wavelengths, and re-emits it at
+ a slightly longer blue wavelengths. Subjectively something that
+ appears more blue, is regarded as being "whiter".<br>
+ <br>
+ For more technical treatment of this topic, please refer to this
+ excellent paper: &lt;<a
+ href="http://www.axiphos.com/BrightnessReview.pdf">http://www.axiphos.com/BrightnessReview.pdf</a>&gt;<br>
+ <br>
+ <h3>Fluorescence</h3>
+ Fluorescent materials absorb light radiation at one wavelength, and
+ then almost instantaneously re-emit some of that energy at a longer
+ wavelength. Typical FWA absorbs wavelengths in the U.V. between
+ about 300 and 400 nm, and re-emit it between 400 and 460nm. The
+ visual effect of FWA depends on the amount of it present in the
+ paper, and the amount of U.V. in the illumination compared to the
+ level of normal, visible light. Generally better quality papers have
+ lower levels of whitening agents, and cheaper papers more. <br>
+ <br>
+ <h3>Reflection Models and Spectro-colorimetry</h3>
+ The way a spectrometer measures the effect of ink on paper, depends
+ on a model of how an illuminant is reflected by the ink and the
+ paper. Typically a spectrometer instrument illuminates the sample
+ with a known illumination, often a incandescent tungsten lamp having
+ a color temperature of&nbsp; 2800 degrees Kelvin. It measures the
+ amount of light reflected by the sample at each wavelength, and then
+ converts that to spectral reflectance value between 0 and 100% by
+ dividing by it's measurement illuminant's intensity at each
+ wavelength. When it comes time to use that measurement to create an
+ ICC profile, the intensity of the assumed viewing illumination at
+ each wavelength (typically D50 for standard ICC profiles) is then
+ multiplied by the reflectance at each wavelength, and the overall
+ spectral reflectance is in this way converted into CIE tri-stimulus
+ values using an observer model.<br>
+ <br>
+ So while the instrument measures with one type of light (type A, or
+ a white LED), it returns a measurement as if it had been measured
+ under a different kind of light (D50) by making use of a simple
+ model of light reflection off the media.<br>
+ <br>
+ Notice that a key assumption of this simple model is that the light
+ that impinges on the sample at a given wavelength is reflected back
+ at exactly the same wavelength at a diminished intensity. Notice
+ also that any sort of fluorescent material (such as FWA) breaks this
+ model, since fluorescent materials emit light a different
+ wavelengths to which they absorb it. So the color measurements do
+ not accurately portray the appearance of the media when FWA is
+ present. A more complicated bi-spectral measurement (2 dimensional
+ spectral reflectance) is actually needed to fully characterize
+ fluorescent materials.<br>
+ <br>
+ <h3>What Argyll's FWA compensation does</h3>
+ The FWA compensation function in Argyll improve on this simple model
+ of spectral reflection by taking into account the action of FWA. To
+ do this, it needs to measure the amount and nature of the FWA in the
+ media, and then have enough information about the viewing
+ environment to model how that FWA will behave.<br>
+ <br>
+ To be able to measure the level of FWA in the media, the instrument
+ needs to be able to "see" the FWA in action, so the instrument needs
+ to be illuminating the samples with some level of U.V. Typically all
+ instruments do this, unless they have been fitted with a filter that
+ filters out any U.V. illumination (so called "UV cut" instruments),
+ or use an illumination source such as a "white" LED that doesn't
+ emit any U.V.<br>
+ Such UV excluded instruments are not suitable for use with FWA
+ compensation.<br>
+ The effects of FWA are modeled spectrally, so a spectral reading
+ instrument is also required.<br>
+ <br>
+ Argyll can compute a model for the effects of FWA given the media's
+ spectral characteristics, and the illuminations spectral
+ characteristic, which must include the levels of U.V. in the
+ illuminant. Given these two things, Argyll can calculate how much
+ effect the FWA will have on the light being reflected and emitted by
+ the media under the intended illumination.<br>
+ <br>
+ Ideally the level of FWA would be measured by comparing the paper
+ spectrum with and without U.V. present in the instruments
+ illumination. Because not all instruments allow these two
+ measurements to be done without some sort of manual intervention,
+ Argyll avoids the need for an FWA inactive (UV cut) or extra UV (UV
+ LED) measurement by employing a heuristic to estimate the FWA
+ inactive spectrum from the spectrum of the paper with FWA active.
+ Being a heuristic, it can sometimes be fooled by certain paper
+ colors into estimating more or less FWA content than is actual
+ present. The heuristic works best with high quality papers with an
+ essentially flat non-FWA enhanced spectrum. Papers with colored
+ tints or particularly off white appearance may not work well with
+ FWA compensation, unless the instrument has the capability of
+ measuring with two different levels of UV.<br>
+ <br>
+ <img alt="Graph showing FWA effect on UV vs. UV cut measurement."
+ src="FWA_measure.jpg" style="width: 387px; height: 284px;"><br>
+ <br>
+ Note that typically in Argyll, if a viewing illuminant is specified,
+ then it is used for computing the appearance under that illumination
+ (CIE XYZ values), and if FWA compensation is used, then that same
+ illuminant will be assumed for the simulated measurement illuminant.
+ This results in measurements that better reflects the appearance as
+ the media as if it was being viewed under that illuminant, FWA
+ effects and all.<br>
+ <br>
+ &nbsp;It is possible to also simulate the measurement of a media
+ under one illuminant, while then computing the tristimulus values as
+ if being viewed under a different illuminant, but this scenario is
+ only really useful for reproducing standardized measurement
+ conditions such as ISO 13655:2009 M0, M1 and M2, and is less useful
+ than the normal FWA compensation scenario in modelling real world
+ situations.<br>
+ <br>
+ [The Argyll FWA compensation algorithm is described in the paper: <font
+ color="#000000"><font face="Times, serif"><font style="font-size:
+ 8pt;" size="1"><a
+ href="http://www.imaging.org/IST/store/epub.cfm?abstrid=22190">A
+ Practical Approach to Measuring and Modelling Paper
+ Fluorescense for Improved Colorimetric Characterisation of
+ Printing Processes", <i>Graeme W. Gill, Proc. IS&amp;T/SID
+ 11th Color Imaging Conference</i></a><span
+ style="font-style: normal;"><a
+ href="http://www.imaging.org/IST/store/epub.cfm?abstrid=22190">,
+ Scottsdale, Arizona; November 2003; p. 248-254</a><font
+ size="1">, and <font size="1">w<font size="1">as f<font
+ size="1">irst publi<font size="1">shed <font
+ size="1">on December 2, 2002</font></font></font></font></font></font></span></font></font></font>
+ in the argyllu_2002_12_02 source code. ]<br>
+ <br>
+ <h3>Using FWA Compensation with proofing</h3>
+ The most common situation for employing FWA compensation, is in
+ proofing. This is when you have one printing device, the target (say
+ a printing press), and wish to emulate the behaviour of it with a
+ different device, the proofer (say an inkjet printer). The aim is to
+ be able to put both prints next to each other in a viewing booth,
+ and have them look identical. Typically the printing process, the
+ inks, and the media will be different between the target device and
+ the proofer. The aim of applying color profiling is to compensate
+ for these differences. Since the printing process can only darken a
+ white media, the selection of the proofing stock is critical.
+ Ideally it should be exactly the same color as the target, or if not
+ possible, lighter, so that the proofer can tint the proofing media
+ to match the target. If the two media had identical levels and types
+ of FWA in them, then there would be no need to use FWA compensation,
+ since the appearance of the media would match under any viewing
+ condition. Typically though, the levels and types of FWA are
+ different between the target paper and the proofing paper. A
+ limitation imposed by tri-stimulus colorimetry is that the
+ differences between the two media, inks and FWA can only be
+ compensated for perfectly, under a fixed and known illuminant.<br>
+ <br>
+ By allowing Argyll to model the effects of FWA for both the source
+ profile (the target device), and the destination profile (the
+ proofing device), the effects can be accounted for, modeled
+ accurately, and incorporated in the profiles, so that a subsequent
+ transformation from source to destination device spaces using
+ absolute colorimetric intent, achieves a (hopefully) perfect
+ colorimetric reproduction. Since this is a closed system, where both
+ the source and destination profiles are made for each other,
+ non-standard parameters such as illuminant and observer models can
+ be used, as long as they are the same for both profiles. For
+ proofing, FWA should be applied identically to both profiles, by
+ specifying the same illuminant, and (optionally) the same observer
+ model.<br>
+ <br>
+ In practice it is possible to compensate for the color shift that
+ results in viewing the media under non-D50 illumination or using a
+ non 1931_2 observer, or allowing for FWA effects without severe
+ incompatibility because all rendering intents except absolute
+ rendering normalize to the media color, rendering the media white as
+ white, even though the absolute values are not measured using a D50
+ illuminant.<br>
+ <h3>Using FWA compensation for single, general use profiles</h3>
+ For creating ICC profiles that will be interchanged with other
+ unknown ICC profiles, or used with non-print source or destination
+ profiles, there is less flexibility, since ICC profiles by
+ convention assume that all media is being viewed under D50
+ illumination. The implication of this is that to be fully
+ interchangeable, it's not really possible to make the profile for
+ your actual viewing environment. Note that the D50 values that are
+ calculated without FWA compensation do not actually reflect the
+ appearance of a media under real D50, because they fail to take into
+ account the different levels of FWA activity between the
+ illumination using by the instrument to measure the media, and real
+ D50. To allow for this and actually meet the letter of the ICC
+ 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 <b><span
+ style="text-decoration: underline;">less</span></b>
+ 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&nbsp; ISO 13655:2009 M0 measurements).<br>
+ <br>
+ Similarly, the effects of viewing the media in an environment with a
+ UV filter fitted over the D50 illuminant can be simulated by using
+ FWA compensation with the D50M2 illuminant, and the 1931_2 observer,
+ thereby simulating the results one would get if the media had been
+ measured with a "UV cut" type instrument, although such profiles are
+ not technically ICC compatible.<br>
+ <br>
+ <h3>Measuring the illuminant</h3>
+ For FWA compensation to work well, it is necessary to know what the
+ spectral shape of the illuminant used for viewing is. While many
+ instruments provide an illuminant measurement capability over the
+ visible spectrum, for FWA compensation it is desirable to know the
+ Ultra Violet (UV) component of the illuminant. Few color instruments
+ are capable of reading to such short wavelengths though. Argyll
+ provides an indirect way of estimating the UV component of an
+ illuminant using its <a href="illumread.html">illumread</a>
+ utility. Using illumread in combination with FWA compensation is the
+ recommended approach to modelling real world appearance of paper
+ containing FWA.<br>
+ <br>
+ <h3>FWA myths</h3>
+ Amongst the user (and to some degree) vendor community, there is 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&nbsp; ANSI
+ CGATS.5-1993 Annex B recommendations for measuring the impact of
+ fluorescent effects, a translation of some of paper whiteness
+ measurement standards into the color profiling world, or possibly in
+ some common situations, if the viewing environment is very poor in
+ UV, then adding a UV filter to the tungsten instrument illuminant
+ makes for a better instrument/viewing illuminant match. There seems
+ to be no scientific or practical basis for believing that a UV
+ filter fitted instrument magically makes all FWA induced problems go
+ away.<br>
+ <br>
+ <h3>Instrument UV filters</h3>
+ 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.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/FWA_measure.jpg b/doc/FWA_measure.jpg
new file mode 100644
index 0000000..7d97fff
--- /dev/null
+++ b/doc/FWA_measure.jpg
Binary files differ
diff --git a/doc/File_Formats.html b/doc/File_Formats.html
new file mode 100644
index 0000000..d6e38c5
--- /dev/null
+++ b/doc/File_Formats.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Argyll File Formats</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h1>File formats that Argyll uses</h1>
+ <br>
+ Argyll uses a number of file formats for its operation, some that
+ are external standards, and some that are unique to Argyll.<br>
+ <br>
+ <a href="#.ti1">.ti1</a><br>
+ <a href="#.ti2">.ti2</a><br>
+ <a href="#.ti3">.ti3</a><br>
+ <a href="#.cal">.cal</a><br>
+ <a href="#.cht">.cht</a> <br>
+ <a href="#.gam">.gam</a> <br>
+ <a href="#.sp">.sp</a><br>
+ <a href="#CGATS">CGATS</a><br>
+ <a href="#ICC">ICC</a><br>
+ <a href="#MPP">MPP</a><br>
+ <a href="#TIFF">TIFF</a><br>
+ <a href="#VRML">VRML</a><br>
+ <br>
+ <h2><a name=".ti1"></a>.ti1</h2>
+ Target Information 1 data. This is an ASCII text, <a href="#CGATS">CGATS</a>,
+ Argyll specific format, used to hold device value ready for creating
+ a profiling test chart, as well as the estimated CIE color values
+ for each value, used in laying out the test chart and reading
+ validation purposes. Additional information on possible spacer and
+ marking values that may be needed in creating a rendered test chart
+ is also included. This file is typically created using the <a
+ href="targen.html"> targen</a> tool.<br>
+ <br>
+ <h2><a name=".ti2"></a>.ti2</h2>
+ Target Information 2 data. This is an ASCII text, <a href="#CGATS">CGATS</a>,
+ Argyll specific format, used to hold device value that have been
+ laid out in a test chart, together with each test patches location,
+ and estimated CIE color values for each value used for reading
+ validation purposes. This file is typically created using the <a
+ href="printtarg.html">printtarg</a> or <a href="filmtarg.html">
+ filmtarg</a> tools.<br>
+ <br>
+ <h2><a name=".ti3"></a>.ti3</h2>
+ Target Information 3 data. This is an ASCII text, <a href="#CGATS">CGATS</a>,
+ Argyll specific format, used to hold device value and CIE/Spectral
+ value pairs, the raw information needed to create device profiles.
+ This file is typically created using the <a href="chartread.html">chartread</a>,&nbsp;<a
+ href="dispread.html"> dispread</a>, <a href="filmread.html">filmread</a>,
+ <a href="scanin.html"> scanin</a>, <a href="fakeread.html">
+ fakeread</a> or one of the conversion tools such as <a
+ href="cb2ti3.html">cb2ti3</a>, <a href="kodak2ti3.html">kodak2ti3</a>,
+ <a href="txt2ti3.html">txt2ti3</a>. See&nbsp; <a
+ href="ti3_format.html">TI3 file format</a> for more detail.
+ <h2><a name=".cal"></a>.cal</h2>
+ Device calibration information. This is ASCII text, <a
+ href="File_Formats.html#CGATS">CGATS</a>, Argyll specific format,
+ used to hold a description of device setup information that brings
+ it to a desired calibration state. Created by <a
+ href="dispcal.html">dispcal</a>, <a href="printcal.html">printcal</a>,
+ <a href="synthcal.html">synthcal</a>. See&nbsp; <a
+ href="cal_format.html">CAL file format</a> for more detail.
+ <h2><a name=".cht"></a>.cht</h2>
+ Test chart recognition file. This is ASCII text Argyll specific
+ format, used to hold a description of a test chart, so that a raster
+ image of the chart can be turned into device test values by the <a
+ href="scanin.html"> scanin</a> tool. <span style="font-weight:
+ bold;">.cht</span> files are created manually (usually in
+ combination with <a href="scanin.html"> scanin</a> creating a
+ boilerplate file containing the recognition parameters, but not the
+ patch location information), or by the <a href="printtarg.html">
+ printtarg</a> tool, when creating a test print chart that will be
+ scanned in, rather than read by an instrument. See &nbsp;<a
+ href="cht_format.html">CHT file format</a> for more detail.<br>
+ <h2><a name=".gam"></a>.gam</h2>
+ Gamut surface description. This is an ASCII text, <a
+ href="File_Formats.html#CGATS">CGATS</a>, Argyll specific format,
+ used to hold a 3 Dimensional surface description of a color gamut.
+ Typical this is created using the <a href="iccgamut.html">iccgamut</a>,
+ <a href="tiffgamut.html">tiffgamut</a>, or <a href="mpplu.html">mpplu</a>
+ tools. The resulting file is typically viewed using the <a
+ href="viewgam.html">viewgam</a> tool to convert one or more gamuts
+ into a <a href="#VRML">VRML</a> file, or as input to <a
+ href="collink.html">collink</a>, to describe a source colorspace
+ gamut.<br>
+ <h2><a name=".sp"></a>.sp</h2>
+ Spectral illuminant description. This is an ASCII text, <a
+ href="File_Formats.html#CGATS">CGATS</a>, Argyll specific format,
+ used to hold a spectral description of an illuminant. Typically it
+ is used to record a custom illuminant, for use in
+ computing&nbsp;Fluorescent Whitening Agent compensation for
+ reflective samples, as well as computing CIE tristimulus values from
+ spectral samples.<br>
+ <h2><a name=".ccmx"></a>.ccmx</h2>
+ Colorimeter Correction Matrix. This is an ASCII text, <a
+ href="File_Formats.html#CGATS">CGATS</a>, Argyll specific format,
+ used to hold a 3x3 correction matrix. The matrix is for a specific
+ display and Colorimeter, and is used to transform the instruments
+ XYZ values to make them better match a reference spectrometers
+ measurements for that display. The file contains a description of
+ the display, Colorimeter and reference Spectrometer. See <a
+ href="ccxxmake.html">ccxxmake</a> for more information.<br>
+ <h2><a name=".ccss"></a>.ccss</h2>
+ Colorimeter Calibration Spectral Set. This is an ASCII text, <a
+ href="File_Formats.html#CGATS">CGATS</a>, Argyll specific format,
+ used to hold a set of display spectral samples. For Colorimeters
+ that have known sensor spectral sensitivity information (such as the
+ i1d3 and Spyder4), this allows a calibration to be created that is
+ tuned for a particular display. The file contains a description of
+ the display, the display technology type, the type of spectrometer
+ used for taking the readings. See <a href="oeminst.html">oeminst</a>
+ and <a href="ccxxmake.html">ccxxmake</a> for more information.<br>
+ <h3><a name="CGATS"></a>CGATS</h3>
+ CGATS.5 Data Exchange Format, from the Annex J, of the ANSI
+ CGATS.5-1993 standard.<br>
+ This is a general purpose ASCII file format suitable for
+ representing color data, and widely used to store color test values.
+ Argyll uses this as a base, human readable format, for a variety of
+ purposes.<br>
+ <h3><a name="ICC"></a>ICC</h3>
+ ICC files are files that conform to the International Color
+ Consortium, File Format for Color profiles. The ICC Profile Format
+ attempts to provide a cross platform device profile format, that can
+ be used to translate color data created on one device into another
+ device's native color space. For a fuller explanation of what the
+ ICC Profile Format is all about, please refer to <a
+ href="http://www.color.org">http://www.color.org</a>, and the
+ profile specification. Argyll currently supports profiles that meet
+ the V3.4 specification. These files are commonly named with a <b>.icm</b>
+ extension on the Windows platform, <b>.pr</b> or <b>.icc</b> on
+ the Macintosh and other platforms. As well as device profiles, the
+ ICC format can also store device link profiles, abstract profiles
+ and named color profiles. This file is typically created using the <a
+ href="colprof.html">colprof</a> or <a href="collink.html">
+ collink</a> tools. A device link profile is also a way of
+ specifying a custom ink separation from (say) CMYK to the 6 or more
+ colorants used by inkjet printers.<br>
+ <h3><a name="MPP"></a>MPP</h3>
+ Model based device profile format. This is an ASCII text, <a
+ href="File_Formats.html#CGATS">CGATS</a>, Argyll specific format,
+ used to hold the parameters to a general model based device profile.
+ This is a less precise and general format than and ICC profile, but
+ is a compact way of representing a devices response when it has a
+ large number of color channels, or when very few measured data
+ points are available for its construction. This file is typically
+ created using the <a href="mppprof.html">mppprof</a> tool.<br>
+ <h3><a name="TIFF"></a>TIFF</h3>
+ Tag Image File Format (TIFF), a widely used format within the
+ graphic arts industries for storing image data. It handles various
+ forms of compression, and various colorspaces, including RGB, CMYK
+ and multi-channel files. See <a
+ href="http://en.wikipedia.org/wiki/TIFF">http://en.wikipedia.org/wiki/TIFF/</a>.
+ Argyll makes use of this as a default raster format.<br>
+ <h3><a name="JPEG"></a>JPEG</h3>
+ Joint Photographic Experts Group, (JPEG), a widely used format
+ within the graphic arts and photographic industries for storing
+ image data. It handles various forms of compression, and various
+ colorspaces, including RGB and CMYK. See <a
+ href="http://en.wikipedia.org/wiki/JPEG/">http://en.wikipedia.org/wiki/JPEG/</a>.
+ Argyll makes use of this as an alternate raster format for some
+ tools.<br>
+ <h3><a name="VRML"></a>VRML</h3>
+ Virtual Reality Modeling Language file. This is a portable way of
+ encoding 3 Dimensional objects (such as gamut surfaces). Typically
+ these can be viewed with a suitable standalone VRML viewer, or a
+ plug in for a web browser. VRML97 is International Standard ISO/IEC
+ 14772-1:1997. See <a href="http://www.vrml.org/">http://www.vrml.org/</a>
+ for more information.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/Fluorescent.jpg b/doc/Fluorescent.jpg
new file mode 100644
index 0000000..acabf74
--- /dev/null
+++ b/doc/Fluorescent.jpg
Binary files differ
diff --git a/doc/HCFR.jpg b/doc/HCFR.jpg
new file mode 100644
index 0000000..9454842
--- /dev/null
+++ b/doc/HCFR.jpg
Binary files differ
diff --git a/doc/HCT.jpg b/doc/HCT.jpg
new file mode 100644
index 0000000..a1f1f23
--- /dev/null
+++ b/doc/HCT.jpg
Binary files differ
diff --git a/doc/HiResLaser.jpg b/doc/HiResLaser.jpg
new file mode 100644
index 0000000..66da2eb
--- /dev/null
+++ b/doc/HiResLaser.jpg
Binary files differ
diff --git a/doc/Huey.jpg b/doc/Huey.jpg
new file mode 100644
index 0000000..5f25980
--- /dev/null
+++ b/doc/Huey.jpg
Binary files differ
diff --git a/doc/Installing.html b/doc/Installing.html
new file mode 100644
index 0000000..a759044
--- /dev/null
+++ b/doc/Installing.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=ISO-8859-1">
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Installation</title>
+ </head>
+ <body>
+ <h1>
+ <u>Installing the software</u></h1>
+ <br>
+ Argyll doesn't come with any installation programs or scripts, so
+ installation is a manual process. Because things are mostly
+ self-contained, this isn't particularly onerous. In general the
+ steps
+ are:<br>
+ <br>
+ 1) Provide somewhere for the executables to reside<br>
+ 2) Provide a means of the shell finding the executables<br>
+ 3) Setup the system to be able to use instruments (USB in
+ particular)<br>
+ <br>
+ Please choose from the detailed instructions below that suite your
+ system:<br>
+ <br>
+ <span style="font-weight: bold;"><a href="Installing_MSWindows.html">Microsoft
+ Windows</a><br>
+ <a href="Installing_OSX.html">Apple OS X</a><br>
+ <a href="Installing_Linux.html">Linux/UNIX X11</a><br>
+ <br>
+ </span>If you have a Spyder 2, Spyder 4, Xrite i1 DisplayPro or
+ ColorMunki Display colorimeter, please also see <a
+ href="oeminst.html">oeminst</a>.<br>
+ <br>
+ <p><br>
+ &nbsp;
+ <br>
+ &nbsp;
+ <br>
+ &nbsp;
+ <br>
+ &nbsp;
+ </p>
+ </body>
+</html>
diff --git a/doc/Installing_Linux.html b/doc/Installing_Linux.html
new file mode 100644
index 0000000..ad2cacc
--- /dev/null
+++ b/doc/Installing_Linux.html
@@ -0,0 +1,582 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=ISO-8859-1">
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Installation on Linux</title>
+ </head>
+ <body>
+ <h1> <u>Installing the software on Linux with X11<br>
+ </u></h1>
+ <br>
+ You will need to unpack the downloaded file in the location you have
+ chosen to hold the executable files. Typically this might be in <span
+ style="font-style: italic;">/usr/local/</span>, or perhaps <span
+ style="font-style: italic;">$HOME/bin/</span>. You would then
+ unpack the files using <span style="font-weight: bold;">tar -zxf</span>
+ <span style="font-weight: bold;">archivename.tgz</span>, which will
+ create a directory <span style="font-weight: bold;">Argyll_VX.X.X</span>,
+ where X.X.X is the version number, and the executables will be in <span
+ style="font-weight: bold;">Argyll_VX.X.X/bin</span> You will also
+ have to configure your $PATH environment variable to give access to
+ the executables from your command line environment. The .tgz file
+ also contains several useful reference files (such as scanner chart
+ recognition templates, sample illumination spectrum etc.) in the ref
+ sub-directory, as well as all the current HTML documentation in a
+ doc sub-directory. You may want to copy things to more standard
+ locations such as /usr/local/bin, /usr/local/argyll/bin etc.,
+ depending on the conventions used on your system.<br>
+ <br>
+ <big style="color: rgb(51, 102, 255);"><span style="font-weight:
+ bold;"><a name="bell"></a>Note on the system bell:</span></big><br>
+ <br>
+ When reading strips using the Eye-One Pro or ColorMunki instrument,
+ the system bell is used to indicate when the instrument the ready to
+ be used, and to provide feedback on any problems. On some Linux
+ installations the system bell may be disabled. As well as checking
+ the terminal and GUI sound preferences, you may have to enable the
+ used of the PC speaker driver, which can be done by adding the
+ command <span style="font-weight: bold;">/sbin/modprobe pcspkr </span>to
+
+
+
+ the <span style="font-weight: bold;">/etc/rc.local</span> startup
+ script. You may also have to run <span style="font-weight: bold;">xset
+
+
+
+ b 100 1000 100</span> in your local setup, if you are running in
+ an X11 environment. You can check that the system bell is operating
+ by doing an "echo ^G", where ^G is ctrl-G.<br>
+ <br>
+ <big style="color: rgb(51, 102, 255);"><span style="font-weight:
+ bold;"><a name="multimonitor"></a>Note on X11 multi-monitor
+ setups:</span></big><br>
+ <br>
+ When working with a multi-monitor X11 configuration, note that you
+ will only be able to individually calibrate monitors if the
+ multi-window extension you are using (if any), supports access to
+ the individual screen Video LUT tables that are used for
+ calibration. The native X11 multi-screen addressing supports this,
+ as does the Xinerama extension, and XRandR V1.2.<br>
+ <br>
+ The proprietary NVidia TwinView and ATI MergeFB extensions do not
+ currently support access to the individual screen Video LUTs, so
+ calibration of each screen independently is impossible if either of
+ these extensions are running. You can switch to using Xinerama to
+ solve this problem, or you can try doing a calibration for the
+ screens that do have accessible Video LUTs with these proprietary
+ extensions, or ignore calibration and rely purely on display
+ profiling. Use the dispwin tool to figure out what works on your
+ system. The NVidia ATI binary drivers do not seem to properly
+ support XRandR V1.2 either, even though they claim to do so. You may
+ have to set the <span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ environment variable if the XRandR V1.2 extension is faulty.<br>
+ <br>
+ If these limitations trouble you, then as a valuable customer of
+ NVidia or AMD/ATI, perhaps you should contact them and urge them to
+ fix the problems with Video LUT access in their proprietary
+ multi-monitor extensions and XRandR implementation, bringing their
+ support for multi-monitors on X11 up to the same standards as other
+ operating systems. Ask them to add full and correct support for the
+ XRandR V1.2 extension.<br>
+ <br>
+ <big style="color: rgb(51, 102, 255);"><span style="font-weight:
+ bold;"><a name="VideoLUTs"></a>Fixing access to Video LUTs:</span></big><br>
+ <br>
+ Some users have noted that their default X11 installation doesn't
+ properly enable access to the video card Video Lookup Tables
+ (RAMDAC). The Video LUTs are used for display calibration purposes,
+ and a warning will be issues by the <span style="font-weight:
+ bold;">dispcal</span> and <span style="font-weight: bold;">dispread</span>
+ tools if there is a problem with this. Without access to the
+ VideoLUTs, you won't be able to use display calibration.<br>
+ <br>
+ The problem may be because certain X11 extensions aren't being
+ loaded by default. You may want to check that you have<br>
+ <br>
+ <big style="color: rgb(51, 102, 255);"><span style="font-weight:
+ bold;"></span></big>&nbsp; Load&nbsp; "extmod" <br>
+ <br>
+ in&nbsp;the&nbsp;appropriate&nbsp;(or&nbsp;any)&nbsp;section&nbsp;of
+ your Xorg.conf file, to allow the XF86Video&nbsp;LUT
+ extensions&nbsp;to function correctly.<br>
+ <br>
+ Another source of problems is if the display isn't configured with a
+ suitable visual. Typically for high quality color you need to be
+ using at least <span style="font-weight: bold;">24 bits</span> per
+ pixel (8 Bits for each of Red, Green and Blue channels), but more
+ importantly the number of entries in the the VideoLUTs needs to
+ match the depth of the screen. So if the VideoLUTs have 256 entries
+ per channel, then the screen must be using 8 bits per channel to
+ match. Or 64 entries and 6 bits. Or 4096 entries and 12 bits, etc.
+ Running "dispwin -D" may give some clues as to what the nature of
+ the problem is. You might have to look into your xorg.conf or XRANDR
+ setup, or on some distributions there will be some configuration
+ program that will let you choose the display configuration (ie. YaST
+ or SaX2 on openSUSE, etc.).<br>
+ <br>
+ <big style="color: rgb(51, 102, 255);"><span style="font-weight:
+ bold;"><a name="InstAccess"></a>Setting up instrument access:<br>
+ <br>
+ </span></big>By default most Linux based systems make devices
+ inaccessible to user mode programs, so it is necessary to make some
+ modification to your permissions so that Argyll tools are able to
+ access the Color Measurement Instruments. In order from newest to
+ oldest, the following sub-systems may need to be configured to
+ permit this:<br>
+ <br>
+ &nbsp; <a style="font-weight: bold;" href="#None">No device
+ configuration needed when running from the console:</a><span
+ style="font-weight: bold; text-decoration: underline;"><br>
+ <br>
+ </span>&nbsp;&nbsp;&nbsp; <a href="#None">Mandriva 2008.0 default
+ installation</a><br>
+ <br>
+ <h5>&nbsp; <a href="Installing_Linux.html#udev1">USB instruments
+ access using udev:</a></h5>
+ <a href="#udev1"></a>&nbsp;&nbsp;&nbsp; <a
+ href="Installing_Linux.html#udev1">Ubuntu 10.04</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="Installing_Linux.html#udev1">Fedora
+ Core 8</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="#udev1">Mandriva 2008.1</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="#udev1">OpenSuSE 10.3</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="#udev1">Ubuntu 7.1</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="#udev1">Kubuntu 7.1</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="#udev1">Debian 4.0</a><br>
+ <h5>&nbsp; <a href="#hotplug">USB instruments access using hotplug:</a></h5>
+ &nbsp;&nbsp; <a href="#hotplug">Red Hat 4.0</a><br>
+ &nbsp;&nbsp; <a href="Installing_Linux.html#hotplug">Fedora Core 4</a><br>
+ &nbsp;&nbsp; <a href="Installing_Linux.html#hotplug">Fedora Core 3</a><br>
+ &nbsp;&nbsp; <a href="Installing_Linux.html#hotplug">Fedora Core 2</a><br>
+ <br>
+ <h5>&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#serial">Serial instrument access:</a></h5>
+ &nbsp;&nbsp; <a href="#serial">All</a><br>
+ <br>
+ <span style="font-weight: bold;">NOTE:</span> That <span
+ style="font-weight: bold;">libmtp</span> has been known to
+ interfere with device access, particularly the Spyder 3. You
+ probably want to disable this library (look in udev).<br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <hr style="width: 100%; height: 2px;">
+ <h5><span style="color: rgb(204, 51, 204);"><a name="None"></a>No
+ device configuration needed:</span></h5>
+ Some systems have in place&nbsp; a security configuration such that
+ anyone logging in at the console of a machine has access to all the
+ local devices.<span style="color: rgb(204, 51, 204);"><span
+ style="font-weight: bold;"><br>
+ </span></span>
+ <h5><span style="color: rgb(204, 51, 204);"><a name="udev1"></a>USB
+ instruments access using udev:<br>
+ </span></h5>
+ <span style="color: rgb(204, 51, 204);"> </span>Most recent systems
+ use udev to manage device names and permissions, but by default
+ color instruments may not be accessible to normal system users.<br>
+ To solve this a udev rule file needs to be added that modifies the
+ group and permission of any Color Measurement Instruments, and you
+ may then need to add yourself to that group.<br>
+ <br>
+ <span style="font-weight: bold;"></span>Copy the file <span
+ style="font-weight: bold;">usb/</span><span style="font-weight:
+ bold;">55-Argyll.rules</span> from the binary or source
+ distribution into <span style="font-weight: bold;">/etc/udev/rules.d/55-Argyll.rules</span>
+ with&nbsp;owner root, group root, permissions 644.<br>
+ (There may already be a file that handles some of the color
+ instruments as part of your installation. You need to check though
+ that it is up to date.)<br>
+ <br>
+ If you are on an <span style="font-weight: bold;">older system</span>
+ that uses a udev that doesn't recognize the syntax used in
+ 55-Argyll.rules, or that doesn't have rules to create the libusb
+ /dev/bus/usb/00X/00Y device entries, you should install the <span
+ style="font-weight: bold;">usb/45-Argyll.rules</span> file
+ instead.<br>
+ <br>
+ On recent systems the new rules file will be notices as soon as you
+ plug the instrument in again.<br>
+ On older systems you may need to run <b>/sbin/udevtrigger</b>,&nbsp;
+
+
+
+
+ <b>/sbin/udevcontrol reload_rules</b> or&nbsp; <span
+ style="font-weight: bold;">/sbin/udevstart</span> or reboot to get
+ the new file noticed.<br>
+ <br>
+ ----------------- cut here ---------------------<br>
+ # udev rule to recognize instruments and make them accessible to
+ user applications.<br>
+ # Copy this to /etc/udev/rules.d/55-Argyll.rules<br>
+ <br>
+ # Skip all this to speed things up if it'a not a usb add.<br>
+ ACTION!="add", GOTO="argyll_rules_end"<br>
+ SUBSYSTEM!="usb", GOTO="argyll_rules_end"<br>
+ <br>
+ # Recognize the color measurement devices<br>
+ <br>
+ # Colorimtre HCFR<br>
+ ATTRS{idVendor}=="04db", ATTRS{idProduct}=="005b",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ <br>
+ # MonacoOPTIX (Same as i1 Display 1)<br>
+ ATTRS{idVendor}=="0670", ATTRS{idProduct}=="0001",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ <br>
+ # HueyL (not tested)<br>
+ ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5001",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # HueyL (not tested)<br>
+ ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5010",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # i1Display 3<br>
+ ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5020",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # ColorMunki Smile<br>
+ ATTRS{idVendor}=="0765", ATTRS{idProduct}=="6003",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # DTP20<br>
+ ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d020",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # DTP92Q (not tested)<br>
+ ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d092",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # DTP94<br>
+ ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d094",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ <br>
+ # i1Pro<br>
+ ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2000",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # i1Monitor<br>
+ ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2001",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # i1Display<br>
+ ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2003",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # i1 io table (not tested)<br>
+ ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2004",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # Huey<br>
+ ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2005",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # i1 iSis (not tested)<br>
+ ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2006",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # ColorMunki<br>
+ ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2007",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ <br>
+ # Spyder 1<br>
+ ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0100",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # Spyder 2<br>
+ ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0200",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # Spyder 3<br>
+ ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0300",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ # Spyder 4<br>
+ ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0400",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ <br>
+ # ColorHug, old and new<br>
+ ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="f8da",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1001",
+ ENV{COLOR_MEASUREMENT_DEVICE}="1"<br>
+ <br>
+ <br>
+ # Let udev-acl manage these devices, if it's available<br>
+ TEST=="/var/run/ConsoleKit/database",
+ ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}="1"<br>
+ <br>
+ # Otherwise, restrict access to members of the plugdev group,<br>
+ # which the user may have to add to the system.<br>
+ ENV{COLOR_MEASUREMENT_DEVICE}=="*?", ENV{ACL_MANAGE}!="*?",
+ MODE="660", GROUP="plugdev"<br>
+ <br>
+ # Set ID_VENDOR and ID_MODEL acording to VID and PID<br>
+ IMPORT{program}="usb-db %p"<br>
+ <br>
+ LABEL="argyll_rules_end"<br>
+ ----------------- cut here ---------------------<br>
+ <br>
+ (You may want to refer to <a
+ href="http://reactivated.net/writing_udev_rules.html">this
+ document</a> for more guidance on modifying udev rules, as well as
+ <a
+href="http://www.google.com/search?hl=en&amp;q=man+udev&amp;btnG=Search&amp;meta=&amp;aq=f&amp;oq=">this</a>.)<br>
+ <br style="font-weight: bold;">
+ <span style="font-weight: bold;">YOU THEN MAY NEED TO:</span><br>
+ <br>
+ If your system is <span style="font-weight: bold;">not</span> using
+ the new ACL to manage device access for console users (the file <span
+ style="font-weight: bold;">/lib/udev/udev-acl</span> doesn't exist
+ on your system), then you will <span style="text-decoration:
+ underline;">need to add</span> yourself to the <span
+ style="font-weight: bold;">plugdev</span> group, if you are not
+ already a member of it. You can do this either by using a "Users and
+ Groups" system administration tool, or on the command line running
+ as root:<br>
+ <br>
+ &nbsp;&nbsp; sudo usermod -a -G plugdev yourusernamehere<br>
+ <br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; su root<br>
+ &nbsp;&nbsp;&nbsp; usermod -a -G plugdev yourusernamehere<br>
+ <br>
+ (If the usermod program isn't found as root, it might be in
+ /usr/sbin, ie. use /usr/sbin/usermod .... etc.<br>
+ &nbsp;If usermod doesn't recognize the -a flag try "usermod -A
+ plugdev yourusernamehere".<br>
+ &nbsp;If this doesn't work you will have to run "id yourusername" to
+ list the current supplemental<br>
+ &nbsp;groups, and add them plus plugdev using just "usermod -G
+ group1,group2,... yourusername")<br>
+ <br>
+ You may find that the <span style="font-weight: bold;">plugdev</span>
+ group doesn't exist on your system, and if so you will need to
+ create it:<br>
+ <br>
+ &nbsp; sudo groupadd -r plugdev<br>
+ <br>
+ and then add yourself to the plugdev group.<br>
+ <br>
+ You may have to log out and then in again for the groups to become
+ effective.<br>
+ <br>
+ You can check whether the instrument is being recognized and set to
+ the plugdev group by comparing the output of <span
+ style="font-weight: bold;">ls -l -R /dev/bus/usb</span> without
+ and then with the instrument plugged in.<br>
+ <br>
+ You can test whether your instrument is accessible by plugging it in
+ and then running "spotread -?" and looking for it listed after the <span
+ style="font-weight: bold;">-c</span> option.<br>
+ <span style="font-weight: bold;"></span> &nbsp;
+ <h5><span style="color: rgb(204, 51, 204);"><a name="hotplug"></a>USB
+instruments
+
+
+
+
+ access using hotplug:<br>
+ </span></h5>
+ Under <span style="font-weight: bold;">much older versions of Linux</span>,
+ you should look into the hotplug system configuration for USB
+ devices. You know you are running this because the <span
+ style="font-weight: bold;">/etc/hotplug</span> directory exists on
+ your system.<br>
+ <br>
+ Assuming we want to configure for all Argyll supported USB
+ instruments, copy the file <span style="font-weight: bold;">usb/</span><span
+ style="font-weight: bold;">Argyll.usermap</span> from the binary
+ or source distribution into&nbsp; <span style="font-weight: bold;">/etc/hotplug/usb/Argyll.usermap</span>
+ with owner root, group root, permissions 644.<span
+ style="font-weight: bold;"></span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
+ # hotplug device mapping to handling script.<br>
+ # Copy this to /etc/hotplug/usb/Argyll.usermap<br>
+ #<br>
+ # Detect instruments by their USB VID and PID<br>
+ #<br>
+ # DTP20<br>
+ Argyll 0x0003 0x0765 0xd020 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # DTP92Q - not tested<br>
+ Argyll 0x0003 0x0765 0xd092 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # DTP94<br>
+ Argyll 0x0003 0x0765 0xd094 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # MonacoOPTIX (Same as i1 Display 1)<br>
+ Argyll 0x0003 0x0670 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # i1 Display<br>
+ Argyll 0x0003 0x0971 0x2003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # i1 Display 3<br>
+ Argyll 0x0003 0x0765 0x5020 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # i1 Monitor<br>
+ Argyll 0x0003 0x0971 0x2001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # i1 Pro<br>
+ Argyll 0x0003 0x0971 0x2000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # ColorMunki<br>
+ Argyll 0x0003 0x0971 0x2007 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # ColorMunki Smile<br>
+ Argyll 0x0003 0x0765 0x6003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # Colorimtre HCFR<br>
+ Argyll 0x0003 0x04DB 0x005B 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # Spyder 2<br>
+ Argyll 0x0003 0x085C 0x0200 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # Spyder 3<br>
+ Argyll 0x0003 0x085C 0x0300 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # Spyder 4<br>
+ Argyll 0x0003 0x085C 0x0400 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # Huey<br>
+ Argyll 0x0003 0x0971 0x2005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ #<br>
+ # ColorHug<br>
+ Argyll 0x0003 0x04D8 0xF8DA 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ Argyll 0x0003 0x273F 0x1001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00
+ 0x00 0x00000000<br>
+ &nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
+ <br>
+ &nbsp;(For even older versions, append the lines above to <span
+ style="font-weight: bold;">/etc/hotplug/usb.usermap</span>, and
+ you may have to run <span style="font-weight: bold;">update-usb.usermap</span>)<br>
+ <br>
+ Then copy the file <span style="font-weight: bold;">usb/</span><span
+ style="font-weight: bold;">Argyll</span> from the binary or source
+ distribution into <span style="font-weight: bold;">/etc/hotplug/usb/Argyll</span>
+ with owner root, group root, permissions 744.<span
+ style="font-weight: bold;"></span><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
+ #!/bin/sh<br>
+ # Copy to /etc/hotplug/usb/Argyll<br>
+ #<br>
+ # Argyll hotplug script. Adds the USB devices to the plugdev group.<br>
+ if [ "${ACTION}" = "add" ] &amp;&amp; [ -f "${DEVICE}" ]<br>
+ then<br>
+ &nbsp;&nbsp;&nbsp; chgrp plugdev "${DEVICE}"<br>
+ &nbsp;&nbsp;&nbsp; chmod 660 "${DEVICE}"<br>
+ fi<br>
+ &nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
+ <br>
+ <span style="font-weight: bold;">YOU THEN NEED TO:</span><br>
+ <br>
+ You will then <span style="text-decoration: underline;">need to add</span>
+ yourself to the <span style="font-weight: bold;">plugdev</span>
+ group, if you are not already a member of it. You can do this either
+ by using a "Users and Groups" system administration tool, or on the
+ command line running as root:<br>
+ <br>
+ &nbsp;&nbsp; sudo usermod -a -G plugdev yourusernamehere<br>
+ <br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; su root<br>
+ &nbsp;&nbsp;&nbsp; usermod -a -G plugdev yourusernamehere<br>
+ <br>
+ <br>
+ (If the usermod program isn't found as root, it might be in
+ /usr/sbin, ie. use /usr/sbin/usermod .... etc.<br>
+ &nbsp;If usermod doesn't recognize the -a flag try "usermod -A
+ plugdev yourusernamehere".<br>
+ &nbsp;If this doesn't work you will have to run "id yourusername" to
+ list the current suplemental<br>
+ &nbsp;groups, and add plugdev using just "usermod -G
+ group1,group2,... yourusername")<br>
+ <br>
+ You may find that the <span style="font-weight: bold;">plugdev</span>
+ group doesn't exist on your system, and if so you will need to
+ create it:<br>
+ <br>
+ &nbsp; sudo groupadd -r plugdev<br>
+ <br>
+ and then add youself to the plugdev group.<br>
+ <br>
+ You may have to log out and then in again for the groups to become
+ effecive.<br>
+ <br>
+ You can test whether your instrument is accessible by plugging it in
+ and then running "spotread -?" and looking for it listed after the <span
+ style="font-weight: bold;">-c</span> option.<br>
+ <span style="font-weight: bold;"></span>&nbsp; <br>
+ <h5><span style="color: rgb(204, 51, 204);"><a name="serial"></a>Serial
+instruments
+
+
+
+
+ access:</span><br>
+ </h5>
+ If you have a serial instrument then you may find that by default
+ you don't have permission to access the serial ports or a Serial to
+ USB adapter. Most systems make the serial ports available to any
+ user in the <span style="font-weight: bold;">tty</span> and <span
+ style="font-weight: bold;">uucp </span>group, so the best way of
+ getting access to the serial ports is to add yourself to those
+ groups. You can do this either by using a "Users and Groups" system
+ administration tool, or on the command line using "usermod":<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; su root<br>
+ &nbsp;&nbsp;&nbsp; usermod -a -G tty,uucp yourusernamehere<br>
+ <br>
+ or<br>
+ <br>
+ &nbsp;&nbsp; sudo usermod -a -G tty,uucp yourusernamehere<br>
+ <br>
+ (If the usermod program isn't found as root, it might be in
+ /usr/sbin, ie. use /usr/sbin/usermod .... etc.<br>
+ &nbsp;If usermod doesn't recognize the -a flag try "usermod -A
+ plugdev yourusernamehere".<br>
+ &nbsp;If this doesn't work you will have to run "id yourusername" to
+ list the current suplemental<br>
+ &nbsp;groups, and add a tty or uucp group using just "usermod -G
+ group1,group2,... yourusername")<br>
+ <br>
+ You may have to log out and then in again for the group to become
+ effecive.<span style="font-weight: bold;"><br>
+ </span>
+ <p>&nbsp; <br>
+ &nbsp; <br>
+ &nbsp; <br>
+ &nbsp; <br>
+ &nbsp; <br>
+ &nbsp; </p>
+ </body>
+</html>
diff --git a/doc/Installing_MSWindows.html b/doc/Installing_MSWindows.html
new file mode 100644
index 0000000..9079db0
--- /dev/null
+++ b/doc/Installing_MSWindows.html
@@ -0,0 +1,583 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html;
+ charset=ISO-8859-1">
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I)
+ [Netscape]">
+ <title>Argyll Installation on Microsoft Windows</title>
+ </head>
+ <body style="color: rgb(0, 0, 0);" alink="#ee0000" link="#0000ee"
+ vlink="#551a8b">
+ <h1> <u>Installing the software on Microsoft Windows<br>
+ </u></h1>
+ <h3 style="background-color: rgb(255, 255, 255);"><span
+ style="color: rgb(51, 153, 153);">Unpacking the .zip archive:</span></h3>
+ You will need to unzip the downloaded file in the location you have
+ chosen to hold the executable files (perhaps somewhere like <span
+ style="font-weight: bold;">\bin</span>). I would <span
+ style="font-weight: bold;">NOT</span> put them in <span
+ style="font-style: italic;">\Program Files</span>, since spaces in
+ directory or file names and command line environments are a very bad
+ mix, and will cause you endless problems. The archive will create a
+ <span style="font-weight: bold;"></span> top level directory <span
+ style="font-weight: bold;">Argyll_VX.X.X</span>, where X.X.X is
+ the version number, and the executables will be in <span
+ style="font-weight: bold;">Argyll_VX.X.X\bin</span>.
+ <h3><span style="color: rgb(51, 153, 153);">Making the tools
+ accessible:</span></h3>
+ You should also configure your %PATH% environment variable to give
+ access to the executables from your command line environment.<br>
+ <br>
+ For <span style="font-weight: bold;">Windows 8</span>, look in<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;"></span>Desktop
+ -&gt; Settings -&gt; Control Panel -&gt; System And Security -&gt;
+ System -&gt; Advanced System Settings -&gt; Environment Variables<br>
+ <br>
+ For <span style="font-weight: bold;">Windows 7</span>, look in<br>
+ &nbsp;&nbsp;&nbsp; Start Menu -&gt; Control Panel -&gt; System And
+ Security -&gt; System -&gt; Change Settings -&gt; Advanced -&gt;
+ Environment Variables<br>
+ <br>
+ For <span style="font-weight: bold;">Vista</span>, look in<br>
+ &nbsp;&nbsp;&nbsp; Start Menu -&gt; Control Panel -&gt; System And
+ Maintenance -&gt; System -&gt; Change Settings -&gt; Advanced -&gt;
+ Environment Variables<br>
+ <br>
+ For <span style="font-weight: bold;">XP and 2000 </span>look in<br>
+ &nbsp;&nbsp;&nbsp; Start-&gt;Settings-&gt;Control
+ Panel-&gt;System-&gt;Advanced-&gt;Environment Variables<br>
+ <br>
+ For <span style="font-weight: bold;">NT 4</span> look in<br>
+ &nbsp;&nbsp;&nbsp; Start-&gt;Settings-&gt;Control
+ Panel-&gt;System-&gt;Environment<br>
+ <br>
+ You want to add the directory you've chosen to your %PATH%, which is
+ a System Variable. Normally you would add this to the end of the
+ current setting, separated by a ';'.&nbsp; <br>
+ <br>
+ &nbsp;So if the current value of PATH is
+ "%SystemRoot%\system32;%SystemRoot%" and you unpacked Argyll version
+ 1.5.1 in <span style="font-weight: bold;">d:\bin\</span>, then you
+ would modify PATH to be
+ "%SystemRoot%\system32;%SystemRoot%;d:\bin\Argyll_V1.5.1\bin", -
+ i.e. you append the path to the Argyll binaries to your PATH,
+ separated by the ';' character. The change will take effect when you
+ start a new command shell, which you start from Start
+ Menu-&gt;Accessories-&gt;Command Prompt, or Start
+ Menu-&gt;Programs-&gt;Accessories-&gt;Command Prompt. You can check
+ that the environment variable has been set by running the command
+ "echo %PATH%" in the command shell.<br>
+ <br>
+ The .zip file also contains several useful reference files (such as
+ scanner chart recognition templates, sample illumination spectrum
+ etc.) in the ref sub-directory, all the current documentation in a
+ doc sub-directory, and instrument USB drivers in the usb directory.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE: </span><span
+ style="font-weight: bold;">Vista 64/Windows 7 &amp; 8&nbsp; 64 bit</span>
+ and <span style="font-weight: bold;">Beep</span> prompt<span
+ style="font-weight: bold;">: </span>Microsoft (in its infinite
+ wisdom) has removed the built in speaker driver, and now relies on
+ systems having a sound card and speakers's installed and turned on
+ to hear system beeps. So if you're wondering where the beeps have
+ gone when using <a href="chartread.html">chartread</a>, now you
+ know.<span style="font-weight: bold;"></span><br>
+ <br>
+ <span style="font-weight: bold;">NOTE: Microsofts generic VGA Driver</span>
+ does not appear to support setting the display VideoLUTs. You will
+ need to install a display driver for your specific display hardware
+ to enable this. Note that it is possible in many cases to use
+ Windows 7 video drivers on Windows 8 systems.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;">NOTE</span> that if you wish to use
+ Argyll tools (<a href="dispwin.html">dispwin</a>) to control display
+ calibration, that you will have to disable any other calibration
+ loader programs.<br>
+ <br>
+ There are other programs that will interfere with calibration
+ loading, such as igfxpers.exe that gets installed with nVidia
+ "Optimus" technology.<br>
+ You may have to disable both the igfx tray module
+ (c:\windows\system32\igfxtray.exe) and the igfxpph Module
+ (c:\windows\system32\igfxpph.dll) in addition to the persistence
+ Module (c:\windows\system32\igfxpers.exe).<br>
+ <br>
+ A good tool for this is <a
+ href="http://technet.microsoft.com/en-us/sysinternals/bb963902">AutoRuns</a>.
+ Note that the igfxpph module may exist in several locations and you
+ have to disable all of them. Reboot after changing settings.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><span style="color: rgb(51, 153, 153);">Serial Instruments:</span><br>
+ </h3>
+ If you are using a serial connected instrument, then there is
+ nothing special to do to enable this.<br>
+ <h3><span style="color: rgb(51, 153, 153);">USB Instruments:</span></h3>
+ If you are using a USB connected instrument, then suitable <span
+ style="font-weight: bold;">USB drivers</span> may need to be
+ installed.<br>
+ <span style="font-weight: bold;"><br>
+ </span>Note that the <span style="font-weight: bold;">Huey</span>
+ and <span style="font-weight: bold;">i1 Display Pro</span> and <span
+ style="font-weight: bold;">ColorMunki Display</span> colorimeter
+ appears as an HID (USB Human Interface Device Class) device, and
+ hence will be assigned to the default MSWindows HID driver. You
+ therefore <span style="font-weight: bold; text-decoration:
+ underline;">don't need</span> to install an Argyll <span
+ style="font-weight: bold;">usb</span> driver for these
+ instruments, although it is possible to select the libusb0.sys
+ driver as an alternative to the default HID driver.<br>
+ <br>
+ Jump to your operating system version:<br>
+ <br>
+ <a href="#WIN8">Windows 8</a><br>
+ <a href="#WINV7">Windows 7</a><br>
+ <a href="#WINV7">Windows Vista</a><br>
+ <a href="#WINXP">Windows XP</a><br>
+ <a href="#WIN2K">Windows 2000</a><br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><a name="WIN8"></a><font
+ size="+1"><span style="font-weight: bold;">Windows 8</span></font><br>
+ <br>
+ <span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
+ 0, 0); text-decoration: underline;"><span style="font-weight:
+ bold;">Fresh Install of Instrument USB driver:</span></span><br>
+ <br>
+ </span>If you currently don't have any applications that talk to
+ your instrument using USB, then it is relatively simple to use the
+ drivers provided with Argyll, since you don't have to deal with the
+ instrument already having an assigned driver.<br>
+ <br>
+ Windows 8 does not automatically pop up a "New Hardware" dialog, so
+ you will have to open the Device Manager manually, and you will also
+ have to temporarily disable UBS driver .inf signature enforcement.<br>
+ <br>
+ <span style="text-decoration: underline;">To install the Argyll
+ driver for the first instrument:</span><br>
+ &nbsp;&nbsp;&nbsp; Settings -&gt; Power -&gt; <span
+ style="font-weight: bold;">Hold Shift Key down and click</span>
+ "Restart" -&gt; Troubleshoot -&gt; Advanced Options -&gt; Startup
+ Settings -&gt; Restart -&gt;<br>
+ &nbsp;&nbsp;&nbsp; (After Reboot) -&gt; "Disable Driver Signature
+ Enforcement" (number 7 on the list)<br>
+ &nbsp;&nbsp;&nbsp; (After system starts, Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp; Desktop -&gt; Settings -&gt; Control Panel -&gt;
+ Hardware and Sound -&gt; Device Manager -&gt;<br>
+ &nbsp;&nbsp;&nbsp; Other Devices -&gt; &lt;instrument being
+ installed&gt; -&gt; right click -&gt; Update Driver Software...
+ -&gt; Browse my computer for driver software -&gt; Browse...<br>
+ &nbsp;&nbsp;&nbsp; -&gt; <span style="font-weight: bold;">argyll\usb</span>
+ folder -&gt; Next -&gt; Install this driver software anyway -&gt;
+ Close<br>
+ <br style="text-decoration: underline;">
+ <span style="text-decoration: underline;">On subsequent installation
+ of other instrument types:</span><br>
+ &nbsp;&nbsp;&nbsp; Simply plug the instrument in. The Argyll driver
+ will be automatically selected.<br>
+ <br>
+ <br>
+ <span style="color: rgb(51, 153, 153); font-weight: bold;"><span
+ style="color: rgb(0, 0, 0); text-decoration: underline;">Adding
+ Argyll drivers to existing drivers:</span></span><br>
+ <br>
+ If you currently have applications other than Argyll accessing your
+ USB connected instrument, then you will have to manually install the
+ Argyll driver, and then switch back and forth between the Argyll and
+ other drivers if you want to switch between applications. <br>
+ <br>
+ <span style="text-decoration: underline;">To install the Argyll
+ Driver:</span><br>
+ Settings -&gt; Power -&gt; <span style="font-weight: bold;">Hold
+ Shift Key down and click</span> "Restart" -&gt; Troubleshoot -&gt;
+ Advanced Options -&gt; Startup Settings -&gt; Restart -&gt;<br>
+ &nbsp;&nbsp;&nbsp; (After Reboot) -&gt; Disable Driver Signature
+ Enforcement" (number 7 on the list)<br>
+ &nbsp;&nbsp;&nbsp; (After system starts, Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp; Desktop -&gt; Settings -&gt; Control Panel -&gt;
+ Hardware and Sound -&gt; Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Update Driver
+ Software... -&gt; let me pick from a list of device drivers on my
+ computer -&gt; Have disk... -&gt; Browse...<br>
+ &nbsp;&nbsp;&nbsp; -&gt; <span style="font-weight: bold;">argyll\usb</span>
+ folder -&gt; select ArgyllCMS.inf -&gt; Open -&gt; OK -&gt; Install
+ this driver software anyway -&gt; Close<br>
+ <br>
+ <span style="text-decoration: underline;">To switch between drivers:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in the instrument)<br>
+ &nbsp;&nbsp;&nbsp; Desktop -&gt; Settings -&gt; Control Panel -&gt;
+ Hardware and Sound -&gt; Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Update Driver
+ Software... -&gt; let me pick from a list of device drivers on my
+ computer<br>
+ &nbsp;&nbsp;&nbsp; (Choose either the Argyll driver or another
+ driver from the list)<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Next -&gt; Close<br>
+ <br>
+ <span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
+ 0, 0); text-decoration: underline;"><span style="font-weight:
+ bold;">Un-installing Argyll driver:</span></span></span><br>
+ <br>
+ If you are updating to a new version of Argyll, that it may be
+ necessary to uninstall all the existing Argyll USB driver, and do a
+ fresh re-install to update the relevant libusb system driver and
+ .inf file. (This is true for updating to Argyll Version 1.5.0). <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; (Plug in the instrument)<br>
+ &nbsp;&nbsp;&nbsp; Desktop -&gt; Settings -&gt; Control Panel -&gt;
+ Hardware and Sound -&gt; Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It
+ will be underneath the Argyll LibUSB-win32 devices top level item.)<br>
+ &nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Uninstall -&gt;
+ click "Delete the driver software for this device" -&gt; OK <br>
+ <br>
+ Proceed then with either <span style="color: rgb(51, 153, 153);"><span
+ style="color: rgb(0, 0, 0); text-decoration: underline;">Fresh
+ Install of Argyll USB driver</span></span> or <span
+ style="color: rgb(51, 153, 153);"><span style="color: rgb(0, 0,
+ 0); text-decoration: underline;">Adding Argyll drivers to
+ existing drivers</span></span> above.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><a name="WINV7"></a><font
+ size="+1"><span style="font-weight: bold;">Windows Vista &amp;
+ Windows 7</span></font><br>
+ <br>
+ <span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
+ 0, 0); text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span></span><span style="color: rgb(51, 153,
+ 153);"><span style="color: rgb(0, 0, 0); text-decoration:
+ underline;"><span style="font-weight: bold;">Fresh Install of
+ Instrument USB driver:</span></span><br>
+ <br>
+ </span>If you currently don't have any applications that talk to
+ your instrument using USB, then it is relatively simple to use the
+ drivers provided with Argyll since you don't have to deal with the
+ instrument already having an assigned driver.<br>
+ <br>
+ <span style="text-decoration: underline;">To install the Argyll
+ driver for the first instrument:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp; (Wait for the "Found New Hardware" or "Installing
+ new device driver software - Device driver software was not
+ successfully installed" popup and dismiss it)<br>
+ &nbsp;&nbsp;&nbsp; Start -&gt; Control Panel -&gt; Hardware and
+ Sound -&gt; Device Manager -&gt;<br>
+ &nbsp;&nbsp;&nbsp; Other Devices -&gt; &lt;instrument being
+ installed&gt; -&gt; right click -&gt; Update Driver Software...
+ -&gt; Browse my computer for driver software -&gt; Browse...<br>
+ &nbsp;&nbsp;&nbsp; -&gt; <span style="font-weight: bold;">argyll\usb</span>
+ folder -&gt; Next -&gt; Install this driver software anyway -&gt;
+ Close<br>
+ <br style="text-decoration: underline;">
+ <span style="text-decoration: underline;">On subsequent installation
+ of other instrument types:</span><br>
+ &nbsp;&nbsp;&nbsp; Simply plug the instrument in. The Argyll driver
+ will be automatically installed.<br>
+ <br>
+ <br>
+ <span style="color: rgb(51, 153, 153); font-weight: bold;"><span
+ style="color: rgb(0, 0, 0); text-decoration: underline;">Adding
+ Argyll drivers to existing drivers:</span></span><br>
+ <br>
+ If you currently have applications other than Argyll accessing your
+ USB connected instrument, then you will have to manually install the
+ Argyll driver, and then switch back and forth between the Argyll and
+ other drivers if you want to switch between applications. <br>
+ <br>
+ <span style="text-decoration: underline;">To install the Argyll
+ Driver:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp; Start -&gt; Control Panel -&gt; Hardware and
+ Sound -&gt; Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Update Driver
+ Software... -&gt; let me pick from a list of device drivers on my
+ computer -&gt; Have disk... -&gt; Browse...<br>
+ &nbsp;&nbsp;&nbsp; -&gt; <span style="font-weight: bold;">argyll\usb</span>
+ folder -&gt; select ArgyllCMS.inf -&gt; Open -&gt; OK -&gt; Install
+ this driver software anyway -&gt; Close<br>
+ <br>
+ <span style="text-decoration: underline;">To switch between drivers:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in the instrument)<br>
+ &nbsp;&nbsp;&nbsp; Start -&gt; Control Panel -&gt; Hardware and
+ Sound -&gt; Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Update Driver
+ Software... -&gt; let me pick from a list of device drivers on my
+ computer<br>
+ &nbsp;&nbsp;&nbsp; (Choose either the Argyll driver or another
+ driver from the list)<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Next -&gt; Close<br>
+ <br>
+ <span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
+ 0, 0); text-decoration: underline;"><span style="font-weight:
+ bold;">Un-installing Argyll driver:</span></span></span><br>
+ <br>
+ If you are updating to a new version of Argyll, that it may be
+ necessary to uninstall all the existing Argyll USB driver, and do a
+ fresh re-install, to update the relevant libusb system driver and
+ .inf file. (This is true for updating to Argyll Version 1.5.0). <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; (Plug in the instrument)<br>
+ &nbsp;&nbsp;&nbsp; Start -&gt; Control Panel -&gt; Hardware and
+ Sound -&gt; Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It
+ will be underneath the Argyll LibUSB-win32 devices top level item.)<br>
+ &nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Uninstall -&gt;
+ click "Delete the driver software for this device" -&gt; OK <br>
+ <br>
+ Proceed then with either <span style="color: rgb(51, 153, 153);"><span
+ style="color: rgb(0, 0, 0); text-decoration: underline;">Fresh
+ Install of Argyll USB driver</span></span> or <span
+ style="color: rgb(51, 153, 153);"><span style="color: rgb(0, 0,
+ 0); text-decoration: underline;">Adding Argyll drivers to
+ existing drivers</span></span> above.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><a name="WINXP"></a><font
+ size="+1"><span style="font-weight: bold;">Windows XP</span></font><br>
+ <br>
+ <span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
+ 0, 0); text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span></span><span style="color: rgb(51, 153,
+ 153);"><span style="color: rgb(0, 0, 0); text-decoration:
+ underline;"><span style="font-weight: bold;">Fresh Install of
+ Instrument USB driver:</span></span><br>
+ <br>
+ </span>If you currently don't have any applications that talk to
+ your instrument using USB, then it is relatively simple to use the
+ drivers provided with Argyll since you don't have to deal with the
+ instrument already having an assigned driver.<br>
+ <br>
+ <span style="text-decoration: underline;">To install the Argyll
+ driver for the first instrument:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp; (Wait for the "Welcome to the Found New Hardware
+ Wizard" popups and dismiss it)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; My Computer, Right Click -&gt; Manage -&gt;
+ Device Manager<br>
+ &nbsp;&nbsp;&nbsp; Other Devices -&gt; &lt;instrument being
+ installed&gt; -&gt; right click -&gt; Update Driver... -&gt; No, not
+ this time -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt;Install from a list or specific location
+ (Advanced) -&gt; Next -&gt; Don't search. I will choose the driver
+ to install -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Have Disk... -&gt; Browse -&gt; <span
+ style="font-weight: bold;">argyll\usb</span> folder -&gt;
+ ArgyllCMS.inf -&gt; Open -&gt; OK -&gt; Next -&gt; Finish<br>
+ <br style="text-decoration: underline;">
+ <span style="text-decoration: underline;">On subsequent installation
+ of other instrument types:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug the instrument in, and wait for the
+ "Welcome to the Found New Hardware Wizard"&nbsp; to pop up.)<br>
+ &nbsp;&nbsp;&nbsp; No, not this time -&gt; Install the software
+ automatically (Recommended) -&gt; Next -&gt; Finish<br>
+ <br>
+ <br>
+ <span style="color: rgb(51, 153, 153); font-weight: bold;"><span
+ style="color: rgb(0, 0, 0); text-decoration: underline;">Adding
+ Argyll drivers to existing drivers:</span></span><br>
+ <br>
+ If you currently have applications other than Argyll accessing your
+ USB connected instrument, then you will have to manually install the
+ Argyll driver, and then switch back and forth between the Argyll and
+ other drivers if you want to switch between applications. <br>
+ <br>
+ <span style="text-decoration: underline;">To install the Argyll
+ Driver:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; My Computer, Right Click -&gt; Manage -&gt;
+ Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; Right click on instrument -&gt; right click
+ -&gt; Update Driver... -&gt; No, not this time -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt;Install from a list or specific location
+ (Advanced) -&gt; Next -&gt; Don't search. I will choose the driver
+ to install -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Have Disk... -&gt; Browse -&gt; <span
+ style="font-weight: bold;">argyll\usb</span> folder -&gt;
+ ArgyllCMS.inf -&gt; Open -&gt; OK -&gt; Next -&gt; Finish<br>
+ <br>
+ <span style="text-decoration: underline;">To switch between drivers:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in the instrument)<br>
+ &nbsp;&nbsp;&nbsp; My Computer,&nbsp; Right Click -&gt; Manage -&gt;
+ Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Update Driver...
+ -&gt; No, not this time -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt;Install from a list or specific location
+ (Advanced) -&gt; Next -&gt; Don't search. I will choose the driver
+ to install -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt;let me pick from a list of device drivers on
+ my computer<br>
+ &nbsp;&nbsp;&nbsp; (Choose either the Argyll driver or another
+ driver from the list)<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Next -&gt; Finish<br>
+ <br>
+ <span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
+ 0, 0); text-decoration: underline;"><span style="font-weight:
+ bold;">Un-installing Argyll driver:</span></span></span><br>
+ <br>
+ If you are updating to a new version of Argyll, that it may be
+ necessary to uninstall all the existing Argyll USB driver, and do a
+ fresh re-install, to update the relevant libusb system driver and
+ .inf file. (This is true for updating to Argyll Version 1.5.0). <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; (Plug in the instrument)<br>
+ &nbsp;&nbsp; My Computer, Right Click -&gt; Manage -&gt; Device
+ Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It
+ will be underneath the Argyll LibUSB-win32 devices top level item.)<br>
+ &nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Uninstall -&gt;
+ click "Delete the driver software for this device" -&gt; OK <br>
+ <br>
+ &nbsp; Then you will have to delete the cached copy of the old
+ Argyll driver .inf files, that MSWindows keeps.<br>
+ <br>
+ &nbsp; cd to where Windows keeps it's cached driver information
+ files, ie:<br>
+ &nbsp;&nbsp;&nbsp; c:<br>
+ &nbsp;&nbsp;&nbsp; cd \windows\inf<br>
+ <br>
+ &nbsp; identify all the system copies of the Argyll .inf files:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; find /I "ArgyllCMS" oem*.inf<br>
+ <br>
+ &nbsp; then delete just the files that contain "ArgyllCMS":<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; del /F oemXXX.inf<br>
+ &nbsp;&nbsp;&nbsp; del /F oemXXY.inf<br>
+ &nbsp;&nbsp;&nbsp; etc.<br>
+ <br>
+ Proceed then with either <span style="color: rgb(51, 153, 153);"><span
+ style="color: rgb(0, 0, 0); text-decoration: underline;">Fresh
+ Install of Argyll USB driver</span></span> or <span
+ style="color: rgb(51, 153, 153);"><span style="color: rgb(0, 0,
+ 0); text-decoration: underline;">Adding Argyll drivers to
+ existing drivers</span></span> above.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><a name="WIN2K"></a><font
+ size="+1"><span style="font-weight: bold;">Windows 2000</span></font><br>
+ <br>
+ <span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
+ 0, 0); text-decoration: underline;"><span style="font-weight:
+ bold;"></span></span></span><span style="color: rgb(51, 153,
+ 153);"><span style="color: rgb(0, 0, 0); text-decoration:
+ underline;"><span style="font-weight: bold;">Fresh Install of
+ Instrument USB driver:</span></span><br>
+ <br>
+ </span>If you currently don't have any applications that talk to
+ your instrument using USB, then it is relatively simple to use the
+ drivers provided with Argyll since you don't have to deal with the
+ instrument already having an assigned driver.<br>
+ <br>
+ <span style="text-decoration: underline;">To install the Argyll
+ driver for the first instrument:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp; (Wait for the "Welcome to the Found New Hardware
+ Wizard" pops up) -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Search for a suitable driver for my device
+ (recommended) -&gt; Next -&gt; Specify a location -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Browse -&gt;&nbsp; <span
+ style="font-weight: bold;">argyll\usb</span> folder -&gt;
+ ArgyllCMS.inf -&gt; Open -&gt; OK -&gt; Next -&gt; Finish<br>
+ <br style="text-decoration: underline;">
+ <span style="text-decoration: underline;">On subsequent installation
+ of other instrument types:</span><br>
+ &nbsp;&nbsp;&nbsp; Simply plug the instrument in. The Argyll driver
+ will be automatically installed.<br>
+ <br>
+ <span style="color: rgb(51, 153, 153); font-weight: bold;"><span
+ style="color: rgb(0, 0, 0); text-decoration: underline;">Adding
+ Argyll drivers to existing drivers:</span></span><br>
+ <br>
+ If you currently have applications other than Argyll accessing your
+ USB connected instrument, then you will have to manually install the
+ Argyll driver, and then switch back and forth between the Argyll and
+ other drivers if you want to switch between applications. <br>
+ <br>
+ <span style="text-decoration: underline;">To install the Argyll
+ Driver:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; My Computer, Right Click -&gt; Manage -&gt;
+ Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Properties
+ -&gt; Driver -&gt; Update Driver&nbsp; this time<br>
+ &nbsp;&nbsp;&nbsp; -&gt; "Welcome to the Found New Hardware Wizard"
+ -&gt; Next -&gt; Display a list of known drivers for this device so
+ that I can choose a specific driver -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Have Disk -&gt; Browse -&gt; <span
+ style="font-weight: bold;">argyll\usb</span> folder -&gt;
+ ArgyllCMS.inf -&gt; Open -&gt; OK -&gt; Next -&gt; Next -&gt; Finish<br>
+ <br>
+ <span style="text-decoration: underline;">To switch between drivers:</span><br>
+ &nbsp;&nbsp;&nbsp; (Plug in instrument)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; My Computer, Right Click -&gt; Manage -&gt;
+ Device Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Properties
+ -&gt; Driver -&gt; Update Driver... -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Display a list of known drivers for this
+ device so that I can choose a specific driver -&gt; Next<br>
+ &nbsp;&nbsp;&nbsp; (Choose either the Argyll driver or another
+ driver from the list)<br>
+ &nbsp;&nbsp;&nbsp; -&gt; Next -&gt; Next -&gt; Finish<br>
+ <br>
+ <span style="color: rgb(51, 153, 153);"><span style="color: rgb(0,
+ 0, 0); text-decoration: underline;"><span style="font-weight:
+ bold;">Un-installing Argyll driver:</span></span></span><br>
+ <br>
+ If you are updating to a new version of Argyll, that it may be
+ necessary to uninstall all the existing Argyll USB driver, and do a
+ fresh re-install, to update the relevant libusb system driver and
+ .inf file. (This is true for updating to Argyll Version 1.5.0). <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; (Plug in the instrument)<br>
+ &nbsp;&nbsp; My Computer, Right Click -&gt; Manage -&gt; Device
+ Manager<br>
+ &nbsp;&nbsp;&nbsp; (Locate the instrument in the device list. It may
+ be underneath one of the top level items.)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; Right click on instrument -&gt; Uninstall
+ -&gt; OK<br>
+ <br>
+ &nbsp; Then you will have to delete the cached copy of the old
+ Argyll driver .inf files, that MSWindows keeps.<br>
+ <br>
+ &nbsp; cd to where Windows keeps it's cached driver information
+ files, ie:<br>
+ &nbsp;&nbsp;&nbsp; c:<br>
+ &nbsp;&nbsp;&nbsp; cd \winnt\inf<br>
+ <br>
+ &nbsp; identify all the system copies of the Argyll .inf files:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; find /I "ArgyllCMS" oem*.inf<br>
+ <br>
+ &nbsp; &nbsp; then delete just the files that contain "ArgyllCMS":<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; del /F oemXXX.inf<br>
+ &nbsp;&nbsp;&nbsp; del /F oemXXY.inf<br>
+ &nbsp;&nbsp;&nbsp; etc.<br>
+ <br>
+ Proceed then with either <span style="color: rgb(51, 153, 153);"><span
+ style="color: rgb(0, 0, 0); text-decoration: underline;">Fresh
+ Install of Argyll USB driver</span></span> or <span
+ style="color: rgb(51, 153, 153);"><span style="color: rgb(0, 0,
+ 0); text-decoration: underline;">Adding Argyll drivers to
+ existing drivers</span></span> above.<br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/Installing_OSX.html b/doc/Installing_OSX.html
new file mode 100644
index 0000000..d3f9057
--- /dev/null
+++ b/doc/Installing_OSX.html
@@ -0,0 +1,283 @@
+<!DOCTYPE HTML PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=ISO-8859-1">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="GENERATOR"
+ content="Mozilla/4.73 [en] (WinNT; I) [Netscape]">
+ <title>Argyll Installation on Apple OS X</title>
+</head>
+<body>
+<h1>
+<u>Installing the software on Apple OS X<br>
+</u></h1>
+<br>
+You
+will need to unpack the downloaded file in the location you have chosen
+to hold the executable files. Typically this might be in <span
+ style="font-style: italic;">/usr/bin</span>, or perhaps <span
+ style="font-style: italic;">$HOME/bin/</span>.<br>
+<br>
+You can unpack it by control-click on the downloaded file
+and &#8220;Open With&#8221; BOMArchiveHelper or Archive Utility. Drag the resulting
+folder to where you want it, e.g. into your home folder (/Users/usrnam
+where usrnam is your username).<br>
+<br>
+Alternatively you can unpack it on the command line using&nbsp; the
+command <span style="font-weight: bold;">tar -zxf</span> <span
+ style="font-weight: bold;">archivename.tgz</span>, which will create a
+directory <span style="font-weight: bold;">Argyll_VX.X.X</span>, where
+X.X.X is the version number, and the executables will be in <span
+ style="font-weight: bold;">Argyll_VX.X.X/bin</span>. <br>
+<br>
+Open a Terminal shell. This will be in
+Applications-&gt;Utilities-&gt;Terminal (Dragging it to the dock is a
+good idea to make it more accessible).<br>
+<br>
+You will have to
+configure your $PATH environment variable to give access to the
+executables from your command line environment, by editing your <span
+ style="font-weight: bold;">.profile</span> file.<br>
+You can do this using a graphical editor, by using the open command:<br>
+<br>
+&nbsp; ~$open .profile<br>
+<br>
+or by using some other editor, such as <span style="font-weight: bold;">vi</span>.<br>
+<br>
+And add the following line to your .path file<br>
+<br>
+&nbsp; PATH=$PATH:$HOME/Argyll_V1.1.1/bin<br>
+<br>
+If you are unfamiliar
+with how to do this, consult an appropriate tutorial, e.g. &lt;<a
+ href="http://heather.cs.ucdavis.edu/matloff/public_html/UnixAndC/Unix/ShellIntro.pdf">ShellIntro</a>&gt;.
+The
+.tgz
+file
+also
+contains
+several
+useful
+reference files (such as
+scanner chart recognition templates, sample illumination spectrum
+etc.) in the ref sub-directory, as well as
+all the current documentation in a doc sub-directory.<br>
+<br>
+For most devices there is nothing special to do. Plug in and go. Some
+devices may not work without some extra help though:<br>
+<h3><a name="ColorMunki"></a><span style="text-decoration: underline;">X-Rite
+ColorMunki</span></h3>
+Some version of X-Rite's ColorMunki drivers released between 2009 and
+2011 install an X-Rite
+daemon that runs as root and grabs the device, preventing any other
+programs (such as Argyll) from opening them. Latter versions seem to be
+more cooperative, and don't suffer from this problem. There are three
+ways of
+working around this problem:<br>
+<br>
+1) Turn off the X-Rite service for the ColorMunki. See &lt;<a
+ class="moz-txt-link-freetext"
+ href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
+<br>
+2) Run all Argyll programs that need to access the instrument as root.
+For instance:<br>
+<br>
+&nbsp;&nbsp;&nbsp; sudo spotread<br>
+<br>
+and then you will be asked for the root password.<br>
+While these methods will work, they are incovenient. <br>
+<br>
+3) Alter the X-Rite drivers Daeomon so that it runs under your user
+account.<br>
+<br>
+To do this you need to edit the script that controls the X-Rite Daemon.<br>
+<br>
+&nbsp;&nbsp;&nbsp; cd ~<br>
+&nbsp;&nbsp;&nbsp; whoami<br>
+&nbsp;&nbsp;&nbsp; cp
+/Library/LaunchDaemons/com.xrite.device.colormunki.plist temp.plist<br>
+&nbsp;&nbsp;&nbsp; open temp.plist<br>
+<br>
+and add one child below the root:<br>
+<br>
+&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;">Item&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+</span><br>
+&nbsp;&nbsp;&nbsp; UserName &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+myusername<br>
+<br>
+where "myusername" is your username shown by whoami, and save the file.
+You then need
+to copy the modified file back: <br>
+<br>
+&nbsp;&nbsp;&nbsp; sudo cp temp.plist
+/Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+<br>
+You will then need to restart the machine for this change to take
+effect, or invoke the following commands:<br>
+<br>
+&nbsp;&nbsp; sudo launchctl unload
+/Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+&nbsp;&nbsp; sudo launchctl load
+/Library/LaunchDaemons/com.xrite.device.colormunki.plist<br>
+<br>
+<span style="font-weight: bold;">NOTE</span> that after running Argyll
+tools, you may have to turn the X-Rite service off then on again, or
+disconnect and reconnect the instrument.<br>
+<br>
+<h3><a name="ColorMunki"></a><span style="text-decoration: underline;">X-Rite
+EyeOne
+Pro</span><br>
+</h3>
+Some version of X-Rite's EyeOne Pro drivers drivers released between
+2009 and
+2011 install an X-Rite
+daemon that runs as root and grabs the device, preventing any other
+programs (such as Argyll) from opening them. Latter versions seem to be
+more cooperative, and don't suffer from this problem. There are three
+ways of
+working around this problem:<br>
+<br>
+1) Turn off the X-Rite service for the EyeOne Pro. See &lt;<a
+ class="moz-txt-link-freetext"
+ href="http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980">http://www.xrite.com/product_overview.aspx?ID=1161&amp;Action=support&amp;SupportID=4980</a>&gt;.<br>
+<br>
+2) Run all Argyll programs that need to access the instrument as root.
+For instance:<br>
+<br>
+&nbsp;&nbsp;&nbsp; sudo spotread<br>
+<br>
+and then you will be asked for the root password.<br>
+While these methods will work, they are incovenient. <br>
+<br>
+3) Alter the X-Rite drivers Daeomon so that it runs under your user
+account.<br>
+<br>
+To do this you need to edit the script that controls the X-Rite Daemon.<br>
+<br>
+&nbsp;&nbsp;&nbsp; cd ~<br>
+&nbsp;&nbsp;&nbsp; whoami<br>
+&nbsp;&nbsp;&nbsp; cp
+/Library/LaunchDaemons/com.xrite.device.i1.plist temp.plist<br>
+&nbsp;&nbsp;&nbsp; open temp.plist<br>
+<br>
+and add one child below the root:<br>
+<br>
+&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;">Item&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Value&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+</span><br>
+&nbsp;&nbsp;&nbsp; UserName &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+myusername<br>
+<br>
+where "myusername" is your username shown by whoami, and save the file.
+You then need
+to copy the modified file back: <br>
+<br>
+&nbsp;&nbsp;&nbsp; sudo cp temp.plist
+/Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+<br>
+You will then need to restart the machine for this change to take
+effect, or invoke the following commands:<br>
+<br>
+&nbsp;&nbsp; sudo launchctl unload
+/Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+&nbsp;&nbsp; sudo launchctl load
+/Library/LaunchDaemons/com.xrite.device.i1.plist<br>
+<br>
+<span style="font-weight: bold;">NOTE</span> that after running Argyll
+tools, you may have to turn the X-Rite service off then on again, or
+disconnect and reconnect the instrument.<br>
+<br>
+<h3><a name="HCFR"></a>HCFR Colorimeter</h3>
+The default OS X class
+drivers will grab this device, preventing Argyll from accessing it. To
+overcome this, you need to install a codeless kernel extension if you
+wish to use the HCFR colorimeter, that
+prevents this from happening. From the command line you need to create
+a directory called Argyll.kext somewhere convenient, and then place in
+it one file called Info.plist, containing the following:<br>
+<br>
+&nbsp;&nbsp;&nbsp; ----------------- cut here ---------------------<br>
+&nbsp;&nbsp; &lt;?xml version="1.0" encoding="UTF-8"?&gt;<br>
+&nbsp;&nbsp; &lt;!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST
+1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;<br>
+&nbsp;&nbsp; &lt;plist version="1.0"&gt;<br>
+&nbsp;&nbsp; &lt;dict&gt;<br>
+&nbsp; &nbsp;&nbsp; &nbsp;
+&lt;key&gt;CFBundleDevelopmentRegion&lt;/key&gt;
+&lt;string&gt;English&lt;/string&gt;<br>
+&nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;CFBundleGetInfoString&lt;/key&gt;
+&lt;string&gt;Libusb USB device Shield&lt;/string&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&lt;key&gt;CFBundleIdentifier&lt;/key&gt;
+&lt;string&gt;com.libusb.USB_Shield&lt;/string&gt;<br>
+&nbsp;&nbsp; &nbsp; &nbsp;
+&lt;key&gt;CFBundleInfoDictionaryVersion&lt;/key&gt;
+&lt;string&gt;6.0&lt;/string&gt;<br>
+&nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleName&lt;/key&gt;
+&lt;string&gt;Libusb USB device Shield&lt;/string&gt;<br>
+&nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundlePackageType&lt;/key&gt;
+&lt;string&gt;KEXT&lt;/string&gt;<br>
+&nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;CFBundleSignature&lt;/key&gt;
+&lt;string&gt;????&lt;/string&gt;<br>
+&nbsp; &nbsp; &nbsp;&nbsp; &lt;key&gt;CFBundleVersion&lt;/key&gt;
+&lt;string&gt;6.0&lt;/string&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&lt;key&gt;IOKitPersonalities&lt;/key&gt;<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;dict&gt;<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
+&lt;key&gt;HCFR&lt;/key&gt;<br>
+&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;
+&lt;key&gt;CFBundleIdentifier&lt;/key&gt;
+&lt;string&gt;com.apple.driver.AppleUSBComposite&lt;/string&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+&lt;key&gt;IOClass&lt;/key&gt;
+&lt;string&gt;AppleUSBComposite&lt;/string&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp;
+&lt;key&gt;IOProviderClass&lt;/key&gt;
+&lt;string&gt;IOUSBDevice&lt;/string&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp; &lt;key&gt;idVendor&lt;/key&gt;
+&lt;integer&gt;1243&lt;/integer&gt;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&lt;key&gt;idProduct&lt;/key&gt;
+&lt;integer&gt;91&lt;/integer&gt;<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/dict&gt;<br>
+&nbsp;&nbsp; &nbsp; &nbsp; &lt;/dict&gt;<br>
+&nbsp; &nbsp; &nbsp;&nbsp;
+&lt;key&gt;OSBundleCompatibleVersion&lt;/key&gt;
+&lt;string&gt;1.8&lt;/string&gt;<br>
+&nbsp;&nbsp; &nbsp; &nbsp; &lt;key&gt;OSBundleLibraries&lt;/key&gt;<br>
+&nbsp; &nbsp; &nbsp;&nbsp; &lt;dict&gt;<br>
+&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+&lt;key&gt;com.apple.kernel.iokit&lt;/key&gt;
+&lt;string&gt;6.0&lt;/string&gt;<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &lt;/dict&gt;<br>
+&nbsp;&nbsp; &lt;/dict&gt;<br>
+&nbsp;&nbsp; &lt;/plist&gt;<br>
+&nbsp; &nbsp; ----------------- cut here ---------------------<br>
+<br>
+(You can also copy this from the source installation in
+usb/Argyll.kext)<br>
+<br>
+You then need to install it by using:<br>
+<br>
+&nbsp; sudo cp -R Argyll.kext /System/Library/Extensions<br>
+<br>
+supplying the appropriate root password when prompted.<br>
+Reboot the system to activate the extension.<br>
+<br>
+<p><br>
+</p>
+</body>
+</html>
diff --git a/doc/Kgraph1.jpg b/doc/Kgraph1.jpg
new file mode 100644
index 0000000..9f6edf9
--- /dev/null
+++ b/doc/Kgraph1.jpg
Binary files differ
diff --git a/doc/Kgraph2.jpg b/doc/Kgraph2.jpg
new file mode 100644
index 0000000..a7d532d
--- /dev/null
+++ b/doc/Kgraph2.jpg
Binary files differ
diff --git a/doc/Kgraph3.jpg b/doc/Kgraph3.jpg
new file mode 100644
index 0000000..f916558
--- /dev/null
+++ b/doc/Kgraph3.jpg
Binary files differ
diff --git a/doc/Kgraph4.jpg b/doc/Kgraph4.jpg
new file mode 100644
index 0000000..603c9bd
--- /dev/null
+++ b/doc/Kgraph4.jpg
Binary files differ
diff --git a/doc/Kgraph5.jpg b/doc/Kgraph5.jpg
new file mode 100644
index 0000000..1de1b88
--- /dev/null
+++ b/doc/Kgraph5.jpg
Binary files differ
diff --git a/doc/Kgraph6.jpg b/doc/Kgraph6.jpg
new file mode 100644
index 0000000..f3981d2
--- /dev/null
+++ b/doc/Kgraph6.jpg
Binary files differ
diff --git a/doc/Kgraph7.jpg b/doc/Kgraph7.jpg
new file mode 100644
index 0000000..c2d0686
--- /dev/null
+++ b/doc/Kgraph7.jpg
Binary files differ
diff --git a/doc/Kgraph8.jpg b/doc/Kgraph8.jpg
new file mode 100644
index 0000000..1bb9569
--- /dev/null
+++ b/doc/Kgraph8.jpg
Binary files differ
diff --git a/doc/Kparams.jpg b/doc/Kparams.jpg
new file mode 100644
index 0000000..04e344b
--- /dev/null
+++ b/doc/Kparams.jpg
Binary files differ
diff --git a/doc/LSDC.jpg b/doc/LSDC.jpg
new file mode 100644
index 0000000..2ad2a67
--- /dev/null
+++ b/doc/LSDC.jpg
Binary files differ
diff --git a/doc/LabSteps.jpg b/doc/LabSteps.jpg
new file mode 100644
index 0000000..d25590f
--- /dev/null
+++ b/doc/LabSteps.jpg
Binary files differ
diff --git a/doc/License.txt b/doc/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/doc/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/doc/License2.txt b/doc/License2.txt
new file mode 100644
index 0000000..05ca889
--- /dev/null
+++ b/doc/License2.txt
@@ -0,0 +1,282 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
diff --git a/doc/License3.txt b/doc/License3.txt
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/doc/License3.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/doc/Limitations.html b/doc/Limitations.html
new file mode 100644
index 0000000..f3fb811
--- /dev/null
+++ b/doc/Limitations.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="GENERATOR"
+ content="Mozilla/4.73 [en] (WinNT; I) [Netscape]">
+ <title>Argyll Overview</title>
+</head>
+<body>
+<h2>
+<u>Limitations</u></h2>
+Some features that have been often asked for, but aren't currently
+implemented are:<br>
+<ul>
+ <li>ICC Version 4 profile support</li>
+ <li>Monochrome profiling support</li>
+ <li>More than 4 colorant printer support</li>
+ <li>GUI interface</li>
+ <li>Support for all available instruments</li>
+</ul>
+Some of these features are being worked upon, and some are beyond the
+scope of a non-commercial project. The range of instruments supported
+is mainly limited by the availability of information on their
+interfaces, as well as the instruments themselves.<br>
+<br>
+The file ttbd.txt in the source distribution has a longer and more
+detailed list of feature ideas.<br>
+<blockquote>
+ <p><br>
+&nbsp;</p>
+</blockquote>
+<br>
+&nbsp;
+<br>
+&nbsp;
+<br>
+&nbsp;
+</body>
+</html>
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..ea48cb5
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,6 @@
+docdir = $(datadir)/doc/argyll
+
+doc_DATA = $(wildcard *.txt) $(wildcard *.html) $(wildcard *.jpg) \
+ $(wildcard *.gif)
+
+EXTRA_DIST = $(doc_DATA)
diff --git a/doc/MinorTools.html b/doc/MinorTools.html
new file mode 100644
index 0000000..5e9a5c4
--- /dev/null
+++ b/doc/MinorTools.html
@@ -0,0 +1,64 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en] (WinNT; I) [Netscape]">
+ <title>Argyll Minor Tools</title>
+</head>
+<body>
+
+<h3>
+Minor tools, test frameworks</h3>
+numlib/LUtest.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test LU matrix decomposition.
+<br>numlib/dnsqtest.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test nonlinear square system solution.
+<br>numlib/soboltest.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test sobol sequence generator
+<br>numlib/svdtest.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test Singular Value Decomposition code
+<br>numlib/tpowell.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test Powell non linear minimiser code
+<br>numlib/zbrenttest.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test 1D Brent solver
+<br>plot/plot.exe
+<br>icc/fbtest.exe
+<br>icc/icclu.exe
+<br>icc/iccrw.exe
+<br>icc/icctest.exe
+<br>icc/lutest.exe
+<br>rspl/c1.exe
+<br>rspl/revbench.exe
+<br>rspl/t2d.exe
+<br>rspl/tnd.exe
+<br>rspl/trnd.exe
+<br>imdi/ctest.exe
+<br>imdi/greytiff.exe
+<br>imdi/imdi_gen.exe
+<br>imdi/itest.exe
+<br>imdi/sort.exe
+<br>imdi/tsort.exe
+<br>cgats/cgats.exe
+<br>cgats/pars.exe
+<br>gamut/maptest.exe
+<br>gamut/smthtest.exe
+<br>xicc/camtest.exe
+<br>xicc/fbview.exe
+<br>xicc/icheck.exe
+<br>xicc/spectest.exe
+<br>xicc/tcheck.exe
+<br>xicc/xcolorantslu.exe
+<br>xicc/xfbview.exe
+<br>spectro/dispwin.exe
+<br>target/ifarp.exe
+<br>target/ppoint.exe
+<br>target/qrand.exe
+<br>target/simplat.exe
+<br>profile/sprof.exe
+<br>link/monoplot.exe
+<br>link/pathplot.exe
+<br>&nbsp;
+</body>
+</html>
diff --git a/doc/Organisation.html b/doc/Organisation.html
new file mode 100644
index 0000000..738b4ba
--- /dev/null
+++ b/doc/Organisation.html
@@ -0,0 +1,230 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Argyll Organization</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+</head>
+<body>
+A brief tour of all the directories in the Argyll source code archive:<br>
+<br>
+<b>TARGET</b><br>
+<br>
+This directory contains routines that generate calibration test charts,
+based
+on various distribution algorithms suitable for
+reading using an Xrite DTP51 or DTP41 colorimeter, or scanner for print
+charts,
+the Gretag Spectrolino for film charts, or the Xrite DTP92 pr DTP94 for
+monitor
+calibration.
+The generated file is a PostScript file for the print chart, and a
+series
+of TIFF files for the film chart.<br>
+<br>
+<b>SPECTRO</b><br>
+<br>
+This directory contains the implementation of all the instrument
+drivers, as well as the tools to calibrate a display, take readings
+from a display, or read a test chart. It also contains the tool that
+supports installing and uninstalling display profiles.<br>
+<br>
+<b> PROFILE</b><br>
+<br>
+This directory has code for taking raw device information (created
+from,
+xxxread.exe or scanin.exe), and creating an ICC device profile from it.
+It
+takes care of the top level details of creating profiles, and relies on
+the
+XICC and RSPL libraries to do the underlying hard work, <br>
+<br>
+<b> LINK</b><br>
+<br>
+This directory holds the ICC profile linking code. Linking two device
+profiles
+creates a device link profile, that embodies a direct device to device
+colorspace
+conversion.<br>
+<br>
+<b> IMDI</b><br>
+<br>
+This is the development area for IMDI, the Integer Multi-Dimensional
+Interpolation
+routines. They provide a flexible and high performance system for
+applying
+color transforms to typical raster pixel data. The system has two
+parts,
+one that generates tailored, optimized source code for the
+transformation
+kernels, and the run time code that matches a transform request&nbsp;
+to
+a compiled kernel, and initializes the appropriate run time lookup
+tables.<br>
+<br>
+The kernel source generator is intended to accommodate various
+optimizations,
+such as assembly code, vector instruction set (ie. MMX, AltiVec etc.)
+version, but
+at present only generates the more portable 'C' code kernels.<br>
+<br>
+<b> ICC</b><br>
+<br>
+ICC profile I/O library (icclib). This distribution contains
+source code which implements the reading and writing of color profile
+files
+that conform to the International Color Consortium (ICC) Profile Format
+Specification,
+Version 3.4.<br>
+<br>
+<b> XICC</b><br>
+<br>
+This directory holds the "extension" icc libraries. These supplement
+the base icc library with enhanced profile functionality, such as
+smoothed
+interpolation, reverse interpolation, table creation from scattered
+data
+etc.<br>
+<br>
+Most of this functionality is based on the rspl and icc libraries. This
+is
+where ink limiting and black generation policies for CMYK devices is
+implemented. The CIECAM97s and CIECAM02 Color Appearance
+Model libraries live here. Support for spectral to CIE conversions
+(including
+FWA compensation) lives here. A simple model, notation and
+classification
+system for n-color printing devices (MPP) lives here too.<br>
+<br>
+<b>RSPL</b><br>
+<br>
+This is the second generation Regular Spline library. It
+contains
+scattered data point to regular grid interpolation, as well as spline
+smoothing,
+and the reverse interpolation code. This version is more modular, and
+uses
+better solution algorithms than the earlier REGSPL, and generally
+replaces
+it. As well as creation from scattered data, there is support for
+lookup,
+re-processing and reverse interpolation (inversion). The reverse
+interpolation
+algorithms support features needed for devices like CMYK printers, such
+as
+total ink limiting, black locus selection, gamut boundary detection,
+vector&nbsp;
+and nearest gamut clipping.<br>
+<br>
+<b>NUMLIB</b><br>
+<br>
+Collection of numerical routines used by various other (mainly color)
+code.<br>
+<br>
+&nbsp; Included are:<br>
+<br>
+&nbsp; numsup&nbsp;&nbsp; &nbsp;Support routines, array and vector
+malloc/free,
+macros<br>
+&nbsp; dnsq&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; Non-linear equation
+solver<br>
+&nbsp; powell&nbsp;&nbsp; &nbsp; &nbsp;Powell multi dimensional
+minimizer<br>
+&nbsp; ludecomp &nbsp;LU decomposition matrix solver<br>
+&nbsp; svd&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Singular
+Value decomposition matrix solver<br>
+&nbsp; zbrent&nbsp;&nbsp; &nbsp; &nbsp; 1 dimensional brent root search<br>
+&nbsp; rand&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Random number
+generators<br>
+&nbsp; sobol&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;Sobol pseudo-random
+sequence generator.<br>
+<br>
+<b>SCANIN</b><br>
+<br>
+This directory contains the code to extract charts from TIFF scan
+files,
+and output the patch values using the CGATS file format. Typically this
+is
+used to get the patch information from a scan of an IT8 calibration
+chart.
+It also has a mode to use a scanned image to measure color, and
+convert a print test chart into approximate CIE values.<br>
+<br>
+<b>GAMUT</b><br>
+<br>
+This directory contains the gamut boundary creation, and usage code. It
+also
+contains the gamut mapping code. <br>
+<br>
+<b>CGATS</b><br>
+<br>
+This directory contains a library for reading and writing CGATS format
+color data files. These files are used extensively for holding color
+related
+information in a human readable form.<br>
+<br>
+<b>TIFF</b><br>
+<br>
+Sam Lefflers standard TIFF library.<br>
+<br>
+<b>PLOT</b><br>
+<br>
+A simple 2D graph plot library,&nbsp; to quickly display 2D graphs for
+debug
+purposes.<br>
+<br>
+<span style="font-weight: bold;">H</span><br>
+<br>
+Where project common #include files live.<br>
+<br>
+<span style="font-weight: bold;">BIN</span><br>
+<br>
+Where the main executables are copied to, when install.ksh or
+install.bat is run. Other useful files get copied here too.<br>
+<br style="font-weight: bold;">
+<span style="font-weight: bold;">LIBUSB, LIBUSBW<br>
+<br>
+</span>The necessary libraries to access USB devices live here<br>
+<br>
+<span style="font-weight: bold;">TWEAK<br>
+<br>
+</span>Tools that allow adjustment and improvement of profiles or links
+live here. Currently the tool <span style="font-weight: bold;">refine</span>
+is the only member.<br>
+<br>
+<span style="font-weight: bold;">RENDER</span><br>
+<span style="font-weight: bold;"></span><br>
+This is a library and set of tools for rendering to raster images. It
+supports creating a test images, and the raster output of <span
+ style="font-weight: bold;">printtarg</span>. <br>
+<br>
+<span style="font-weight: bold;">JCNF</span><br>
+<br>
+Implementation of color configuration file format using JSON, used by <span
+ style="font-weight: bold;">ucmm</span>.<br>
+<br>
+<span style="font-weight: bold;">UCMM</span><br>
+<br>
+Unix micro Color Management Module implementation, for supporting the
+installation and access to display profiles.<br>
+<br>
+<span style="font-weight: bold;">REF</span><br>
+<br>
+Miscellaneous useful reference files, such as scanin recognition
+templates for standard charts, live here.<br>
+<br>
+<span style="font-weight: bold;">DOC</span><br>
+<br>
+All the Argyll HTML documentation lives here.<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/Overview.html b/doc/Overview.html
new file mode 100644
index 0000000..373d195
--- /dev/null
+++ b/doc/Overview.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="GENERATOR"
+ content="Mozilla/4.73 [en] (WinNT; I) [Netscape]">
+ <title>Argyll Overview</title>
+</head>
+<body>
+<h2>
+<u>Overview</u></h2>
+Many commercial and research electronic color correction systems have
+been
+developed over the years, but all state-of-the-art systems are
+proprietary,
+and their technology is jealously guarded. This makes this interesting
+subject area a difficult one to both explore, and to bridge the gap
+between
+theory and practice.
+<p>Argyll was written to allow me to improve my understanding and
+expertise
+in the color area, and as a platform to try out ideas for alternate
+approaches
+to electronic color correction, as well as developing new advanced
+features.
+</p>
+<p>I hope that by making the source code available under "Free" and
+"Open
+Source" licenses, that other researchers and experimenters will also
+find
+it of interest and value. I also hope that it may be attractive as a
+software platform on which future research and advances in electronic
+color correction
+systems can be based.
+</p>
+<p>To complement this aim, I hope at some stage to turn my notes made
+in
+the creation of this software into a more readable
+explanation of how Argyll works, and the principles on which it is
+based.
+</p>
+<br>
+<blockquote>
+ <p><br>
+&nbsp;</p>
+</blockquote>
+<br>
+&nbsp;
+<br>
+&nbsp;
+<br>
+&nbsp;
+</body>
+</html>
diff --git a/doc/Performance.html b/doc/Performance.html
new file mode 100644
index 0000000..b69f5ae
--- /dev/null
+++ b/doc/Performance.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="GENERATOR"
+ content="Mozilla/4.73 [en] (WinNT; I) [Netscape]">
+ <title>Argyll Performance Tuning</title>
+</head>
+<body>
+<h2>
+<u>Performance Tuning</u></h2>
+<br>
+Some operations in Argyll can be particularly slow, so it is worth
+examining ways of improving performance, or trading memory consumption
+for performance.<br>
+<h3>Creating Device Links and Profiles<br>
+</h3>
+In creating device links or the B2A tables of profiles, the execution
+time is often dominated by the inversion of forward
+color lookup values. An in-memory cache is employed to speed up this
+operation, by keeping computed values in case they can be used more
+than once. The amount of memory used for caching these values is
+pre-set within the inversion code, and by default is set to use half of
+the available RAM on the system, with a minimum of 50 Mbytes.<br>
+<br>
+The reverse cache size can be changed by setting an environment
+variable
+<span style="font-weight: bold;">ARGYLL_REV_CACHE_MULT</span> to a
+number greater or less than than 1.0 This will multiply the size of the
+cache by that number (i.e. 1.5 would increase the cache size by 50%,
+0.5 would halve it).<br>
+<br>
+If you find that <span style="font-weight: bold;">colprof</span>
+or&nbsp; <span style="font-weight: bold;">collink</span>
+are working very slowly, but that your CPU's are nearly idle, then this
+is a sign of disk swapping, and that too much memory is being
+requested.&nbsp; This can be because other applications are also using
+memory, or Argyll's default setting tries to use more memory than is
+actually available. You can try shutting down other applications when
+this happens, or you can <span style="font-weight: bold;">lower</span>
+the amount of memory Argyll uses by setting <span
+ style="font-weight: bold;">ARGYLL_REV_CACHE_MULT</span> to a value
+less than 1.0 (ie. try 0.5). <br>
+<br>
+If you have a lot of memory available, you can try increasing the
+cache size to use more of the available RAM (particularly if you get a
+"Warning - Reverse Cell Cache exhausted,
+processing in chunks" message during processing), but if you set it to
+a value too near 2.0 you risk disk swapping, which can slow progress to
+a crawl.<br>
+<br>
+If you have a lot of memory available, then a second adjustment that
+can make a great difference to the time taken
+in creating B2A tables is the resolution of the inverse lookup
+acceleration grid. The finer the grid, the less searching is needed to
+locate the input colorspace values that
+correspond to a target output color value, but the greater the memory
+used in this
+structure, and the greater the setup time needed to initialize the
+acceleration grid. The <span style="font-weight: bold;">ARGYLL_REV_ACC_GRID_RES_MULT</span>
+environment variable can alter the default resolution by a scale
+factor. A value of 0.5 for instance, would halve the resolution
+(typically meaning 1/8 th. the total number of grid entries and
+memory), while a value of 2.0 would double it, typically resulting in 8
+times the memory usage. Increasing the resolution too much will reduce
+the available memory for the reverse cache, and greatly increase setup
+time.<br>
+<br>
+<h3>Setting an environment variable:</h3>
+<br>
+To set an environment variable an MSWindows DOS shell, either use set,
+e.g.;<br>
+<br>
+&nbsp;&nbsp;&nbsp; set ARGYLL_REV_CACHE_MULT=1.5<br>
+<br>
+which will set the value for that session, or set it in<br>
+<br>
+Control Panel-&gt;System-&gt;Advanced-&gt;Environment Variables..<br>
+<br>
+in either user or system variables.<br>
+<br>
+For OS X or Linux, the exact procedure will depend on the shell you are
+running, but<br>
+is usually something like:<br>
+<br>
+&nbsp;&nbsp;&nbsp; export ARGYLL_REV_CACHE_MULT=1.5<br>
+or<br>
+&nbsp;&nbsp;&nbsp; set ARGYLL_REV_CACHE_MULT=1.5<br>
+or<br>
+&nbsp;&nbsp;&nbsp; ARGYLL_REV_CACHE_MULT=1.5<br>
+<br>
+and may need separately exporting, something like:<br>
+<br>
+&nbsp;&nbsp;&nbsp; export ARGYLL_REV_CACHE_MULT<br>
+<br>
+Generally it should be configured in the shell start-up script,&nbsp;
+if you
+want the setting to be used<br>
+for every session.<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/Q60.jpg b/doc/Q60.jpg
new file mode 100644
index 0000000..1521e04
--- /dev/null
+++ b/doc/Q60.jpg
Binary files differ
diff --git a/doc/QPcard201.jpg b/doc/QPcard201.jpg
new file mode 100644
index 0000000..dbe1448
--- /dev/null
+++ b/doc/QPcard201.jpg
Binary files differ
diff --git a/doc/QPcard202.jpg b/doc/QPcard202.jpg
new file mode 100644
index 0000000..3332bdd
--- /dev/null
+++ b/doc/QPcard202.jpg
Binary files differ
diff --git a/doc/SG.jpg b/doc/SG.jpg
new file mode 100644
index 0000000..7dc20e1
--- /dev/null
+++ b/doc/SG.jpg
Binary files differ
diff --git a/doc/SG_footer.txt b/doc/SG_footer.txt
new file mode 100644
index 0000000..e82fbc2
--- /dev/null
+++ b/doc/SG_footer.txt
@@ -0,0 +1 @@
+END_DATA
diff --git a/doc/SG_header.txt b/doc/SG_header.txt
new file mode 100644
index 0000000..83af2cd
--- /dev/null
+++ b/doc/SG_header.txt
@@ -0,0 +1,12 @@
+IT8.7/2
+ORIGINATOR "Graeme Gill"
+DESCRIPTOR "Header to prepend to X-Rite digital_colorchecker_sg_l_a_b.txt file"
+CREATED "June 26, 2012"
+
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+SAMPLE_ID LAB_L LAB_A LAB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 140
+BEGIN_DATA
diff --git a/doc/Scenarios.html b/doc/Scenarios.html
new file mode 100644
index 0000000..3995d21
--- /dev/null
+++ b/doc/Scenarios.html
@@ -0,0 +1,2177 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Argyll Usage Scenarios</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ </head>
+ <body>
+ <h2><u>Typical usage Scenarios and Examples</u></h2>
+ Choose a task from the list below. For more details on alternative
+ options, follow the links to the individual tools being used.<br>
+ <br>
+ Note that by default it is assumed that ICC profile have the file
+ extension <span style="font-weight: bold;">.icm</span>, but that on
+ Apple OS X and Unix/Linux platforms, the <span style="font-weight:
+ bold;">.icc</span> extension is expected and should be used.<br>
+ <h4><a href="#PM1">Profiling Displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1a">Checking you can access your
+ display<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1b">Adjusting and Calibrating a
+ displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM1c">Adjusting, calibrating and
+ profiling in one step<br>
+ </a><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span><span style="text-decoration:
+ underline;"></span></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PM2">Creating display test values</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PM3">Taking readings from a
+ display</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PM4">Creating a display profile</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM5">Installing a display profile</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM6">Expert tips when measuring displays</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <span style="text-decoration: underline;"></span><a
+ href="#PM7">Calibrating and profiling a display that doesn't
+ have VideoLUT access.</a></h4>
+ <h4><br>
+ <a href="#PS1">Profiling Scanners and other input devices such as
+ cameras<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS2">Types of test charts</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS3">Taking readings from a
+ scanner</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PS4">Creating a scanner profile</a></h4>
+ <h4><br>
+ <a href="#PP1">Profiling Printers</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP2">Creating a print profile
+ test chart</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PP2b">Printing a
+ print profile test chart</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP3">Reading a print test chart
+ using an instrument</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="#PP4">Reading a print test chart
+ using a scanner</a></h4>
+ <h4> </h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PP5">Creating a printer profile<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PP6">Choosing a black generation
+ curve</a></h4>
+ <br>
+ <h4><a href="Scenarios.html#PC1">Calibrating Printers</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC2">Calibrated
+ print workflows</a></h4>
+ <h4> &nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC3">Creating a
+ print calibration test chart</a></h4>
+ <h4> </h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC4">Creating a
+ printer calibration<br>
+ </a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="Scenarios.html#PC5">Using a printer
+ calibration</a></h4>
+ <h4>&nbsp;&nbsp;&nbsp; <a href="#PC6">How profile ink limits are
+ handled when calibration is being used<br>
+ </a></h4>
+ <h4><br>
+ <a href="#LP1">Linking Profiles</a></h4>
+ <h4><br>
+ <a href="#TR1">Transforming colorspaces of raster files</a></h4>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <h3><a name="PM1"></a>Profiling Displays</h3>
+ Argyll supports adjusting, calibrating and profiling of displays
+ using one of a number of instruments - see <a
+ href="instruments.html">instruments</a> for a current list.&nbsp;
+ Adjustment and calibration are prior steps to profiling, in which
+ the display is adjusted using it's screen controls,&nbsp; and then
+ per channel lookup tables are created to make it meet a well behaved
+ response of the desired type. The&nbsp; process following that of
+ creating a display profile is then similar to that of all other
+ output devices :- first a set of device colorspace test values needs
+ to be created to exercise the display, then these values need to be
+ displayed, while taking measurements of the resulting colors using
+ the instrument. Finally, the device value/measured color values need
+ to be converted into an ICC profile.<br>
+ <br>
+ <h3><a name="PM1a"></a>Checking you can access your display<br>
+ </h3>
+ You might first want to check that you are accessing and can
+ calibrate your display. You can do this using the <a
+ href="dispwin.html">dispwin</a><span style="font-weight: bold;"></span>
+ tool<span style="font-weight: bold;">.</span> If you just run <span
+ style="font-weight: bold;">dispwin</span> it will create a test
+ window and run through a series of test colors before checking that
+ the VideoLUT can be accessed by the display. If you invoke the usage
+ for <span style="font-weight: bold;">dispwin</span> (by giving it
+ an unrecognized option, e.g. <span style="font-weight: bold;">-?</span>)
+ then it will show a list of available displays next to the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">-d</span></span>
+ flag. Make sure that you are accessing the display you intend to
+ calibrate and profile, and that the VideoLUT is effective (the <span
+ style="font-weight: bold;">-r</span> flag can be used to just run
+ the VideoLUT test). You can also try clearing the VideoLUTs using
+ the <span style="font-weight: bold;">-c</span> flag, and loading a
+ deliberately strange looking calibration <span style="font-weight:
+ bold;">strange.cal</span> that is provided in the Argyll <span
+ style="font-weight: bold;">ref</span> directory.<br>
+ <br>
+ Note that calibrating and/or profiling <span style="font-weight:
+ bold;">remote</span> displays is possible using X11 or a web
+ browser (see <span style="font-weight: bold;">-d</span> option of
+ dispcal and dispread), or by using some external program to send
+ test colors to a display (see <span style="font-weight: bold;">-C</span>
+ and <span style="font-weight: bold;">-M</span> options of dispcal
+ and dispread), but you may want to refer to <a href="#PM7">Calibrating
+
+
+
+ and profiling a display that doesn't have VideoLUT access</a>.<br>
+ <br>
+ <h3><a name="PM1b"></a>Adjusting and Calibrating Displays</h3>
+ Please read <a href="calvschar.html">What's the difference between
+ Calibration and Characterization ?</a> if you are unclear as to
+ the difference .<br>
+ <br>
+ The first step is to decide what the target should be for adjustment
+ and calibration. This boils down to three things: The desired
+ brightness, the desired white point, and the desired response curve.
+ The native brightness and white points of a display may be different
+ to the desired characteristics for some purposes. For instance, for
+ graphic arts use, it might be desirable to run with a warmer white
+ point of about 5000 degrees Kelvin, rather than the default display
+ white point of 6500 to 9000 Kelvin. Some LCD displays are too bright
+ to compare to printed material under available lighting, so it might
+ be desirable to reduce the maximum brightness.<br>
+ <br>
+ You can run <a href="dispcal.html#r">dispcal -r</a> to check on how
+ your display is currently set up. (you may have to run this as <span
+ style="text-decoration: underline; color: rgb(204, 51, 204);">dispcal
+-yl
+
+
+
+
+
+
+
+
+ -r</span> for an LCD display, or <span style="text-decoration:
+ underline; color: rgb(204, 51, 204);">dispcal -yc -r</span> for a
+ CRT display with most of the colorimeter instruments. If so, this
+ will apply to all of the following examples.)<br>
+ <br>
+ Once this is done, <a href="dispcal.html">dispcal</a> can be run to
+ guide you through the display adjustments, and then calibrate it. By
+ default, the brightness and white point will be kept the same as the
+ devices natural brightness and white point. The default response
+ curve is a gamma of 2.4, except for Apple OS X systems prior to 10.6
+ where a gamma of 1.8 is the default. 2.4 is close to that of&nbsp;
+ many monitors, and close to that of the sRGB colorspace. <br>
+ <br>
+ A typical calibration that leaves the brightness and white point
+ alone, might be:<br>
+ <br>
+ <a href="dispcal.html">dispcal</a> -v TargetA<br>
+ <br>
+ which will result in a "TargetA.cal" calibration file, that can then
+ be used during the profiling stage.<br>
+ <br>
+ If the absolutely native response of the display is desired during
+ profiling, then calibration should be skipped, and the linear.cal
+ file from the "ref" directory used instead as the argument to the -k
+ flag of <span style="font-weight: bold;">dispread</span>.<br>
+ <br>
+ <b>Dispcal</b> will display a test window in the middle of the
+ screen, and issue a series of instructions about placing the
+ instrument on the display. You may need to make sure that the
+ display cursor is not in the test window, and it may also be
+ necessary to disable any screensaver and powersavers before starting
+ the process, although both <span style="font-weight: bold;">dispcal</span>
+ and <span style="font-weight: bold;">dispread</span> will attempt
+ to do this for you. It's also highly desirable on CRT's, to clear
+ your screen of any white or bright background images or windows
+ (running your shell window with white text on a black background
+ helps a lot here.), or at least keep any bright areas away from the
+ test window, and be careful not to change anything on the display
+ while the readings are taken. Lots of bright images or windows can
+ affect the ability to measure the black point accurately, and
+ changing images on the display can cause inconsistency in the
+ readings,&nbsp; and leading to poor results.<span
+ style="font-weight: bold;"></span> LCD displays seem to be less
+ influenced by what else is on the screen.<br>
+ <br>
+ If <span style="font-weight: bold;">dispcal</span> is run without
+ arguments, it will provide a usage screen. The <span
+ style="font-weight: bold;">-c</span> parameter allows selecting a
+ communication port for an instrument, or selecting the instrument
+ you want to use,&nbsp; and the <a href="dispcal.html#d"><span
+ style="font-weight: bold;">-d</span></a> option allows selecting
+ a target display on a multi-display system. On some multi-monitor
+ systems, it may not be possible to independently calibrate and
+ profile each display if they appear as one single screen to the
+ operating system, or if it is not possible to set separate video
+ lookup tables for each display. You can change the position and size
+ of the test window using the <a href="dispcal.html#P"><span
+ style="font-weight: bold;">-P</span></a> parameter. You can
+ determine how best to arrange the test window, as well as whether
+ each display has separate video lookup capability, by experimenting
+ with the <a href="dispwin.html">dispwin</a> tool. <br>
+ <br>
+ For a more detailed discussion on interactively adjusting the
+ display controls using <span style="font-weight: bold;">dispcal</span>,
+ see <a href="dispcal.html#Adjustment">dispcal-adjustment</a>. Once
+ you have adjusted and calibrated your display, you can move on to
+ the next step.<br>
+ <br>
+ When you have calibrated and profiled your display, you can keep it
+ calibrated using the <a href="dispcal.html#u">dispcal -u</a>
+ option.<br>
+ <br>
+ <h4><a name="PM1c"></a>Adjusting, calibrating and profiling in one
+ step.</h4>
+ If a simple matrix/shaper display profile is all that is desired, <span
+ style="font-weight: bold;">dispcal</span> can be used to do this,
+ permitting display adjustment, calibration and profiling all in one
+ operation. This is done by using the <span style="font-weight:
+ bold;"><span style="font-weight: bold;">dispcal </span>-o</span>
+ flag:<br>
+ <br>
+ <a href="dispcal.html">dispcal</a> <a href="dispcal.html#v">-v</a>
+ <a href="dispcal.html#o">-o</a> <a href="dispcal.html#p1">TargetA</a><br>
+ <br>
+ This will create both a TargetA.cal file, but also a TargetA.icm
+ file. See <a href="dispcal.html#o">-o</a> and <a
+ href="dispcal.html#O">-O</a> for other variations.<br>
+ <br>
+ For more flexibility in creating a display profile, the separate
+ steps of creating characterization test values using <span
+ style="font-weight: bold;">targen</span>, reading them from the
+ display using <span style="font-weight: bold;">dispread</span>, and
+ then creating a profile using <span style="font-weight: bold;">colprof</span>
+ are used. The following steps illustrate this:<br>
+ <h4><a name="PM2"></a>Profiling in several steps: Creating display
+ test values</h4>
+ If the <span style="font-weight: bold;">dispcal</span> has not been
+ used to create a display profile at the same time as adjustment and
+ calibration, then it can be used to create a suitable set of
+ calibration curves as the first step, or the calibration step can be
+ omitted, and the display cansimply be profiled.<br>
+ <br>
+ The first step in profiling any output device, is to create a set of
+ device colorspace test values. The important parameters needed are:
+ <br>
+ <ul>
+ <li>What colorspace does the device use ?</li>
+ <li>How many test patches do I want to use ?</li>
+ <li>What information do I already have about how the device
+ behaves ?</li>
+ </ul>
+ For a display device, &nbsp;the colorspace will be RGB. The number
+ of test patches will depend somewhat on what quality profile you
+ want to make, what type of profile you want to make, and how long
+ you are prepared to wait when testing the display.<br>
+ At a minimum, a few hundred values are needed. A matrix/shaper type
+ of profile can get by with fewer test values, while a LUT based
+ profile will give better results if more test values are used. A
+ typical number might be 200-600 or so values, while 1000-2000 is not
+ an unreasonable number for a high quality characterization of a
+ display.<br>
+ <br>
+ To assist the choice of test patch values, it can help to have a
+ rough idea of how the device behaves. This could be in the form of
+ an ICC profile of a similar device, or a lower quality, or previous
+ profile for that particular device. If one were going to make a very
+ high quality LUT based profile, then it might be worthwhile to make
+ up a smaller, preliminary shaper/matrix profile using a few hundred
+ test points, before embarking on testing the device with several
+ thousand.<br>
+ <br>
+ Lets say that we ultimately want to make a profile for the device
+ "DisplayA", the simplest approach is to make a set of test values
+ that is independent of the characteristics of the particular device:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
+ <a href="targen.html#p1">DisplayA</a><br>
+ <br>
+ If there is a preliminary or previous profile called "OldDisplay"
+ available, and we want to try creating a "pre-conditioned" set of
+ test values that will more efficiently sample the device response,
+ then the following would achieve this:<br>
+ <u><br>
+ </u><a href="targen.html"> targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d3</a> <a href="targen.html#f">-f500</a>
+ <a href="targen.html#c">-cOldDisplay.icm</a> <a
+ href="targen.html#p1">DisplayA</a><br>
+ <br>
+ The output of <b>targen</b> will be the file DisplayA.ti1,
+ containing the device space test values, as well as expected CIE
+ values used for chart recognition purposes.<br>
+ <br>
+ <h4><a name="PM3"></a>Profiling in several steps: Taking readings
+ from a display</h4>
+ First it is necessary to connect your measurement instrument to your
+ computer, and check which communication port it is connected to. In
+ the following example, it is assumed that the instrument is
+ connected to the default port 1, which is either the first USB
+ instrument found, or serial port found. Invoking dispread so as to
+ display the usage information (by using a flag -? or --) will list
+ the identified serial and USB ports, and their labels.<br>
+ <br>
+ <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#p1">DisplayA</a><br>
+ <br>
+ If we created a calibration for the display using <a
+ href="dispcal.html">dispcal</a>, then we will want to use this
+ when we take the display readings (e.g. TargetA.cal from the
+ calibration example)..<br>
+ <br>
+ <a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#k">-k TargetA.cal</a> <a
+ href="dispread.html#p1">DisplayA</a><br>
+ <br>
+ <b>dispread</b> will display a test window in the middle of the
+ screen, and issue a series of instructions about placing the
+ instrument on the display. You may need to make sure that the
+ display cursor is not in the test window, and it may also be
+ necessary to disable any screensaver before starting the process.
+ Exactly the same facilities are provided to select alternate
+ displays using the <span style="font-weight: bold;">-d</span>
+ parameter, and an alternate location and size for the test window
+ using the <span style="font-weight: bold;">-P</span> parameter as
+ with <span style="font-weight: bold;">dispcal</span>.<br>
+ <h4><a name="PM4"></a>Profiling in several steps: Creating a display
+ profile</h4>
+ There are two basic choices of profile type for a display, a
+ shaper/matrix profile, or a LUT based profile. They have different
+ tradeoffs. A shaper/matrix profile will work well on a well behaved
+ display, that is one that behaves in an additive color manner, will
+ give very smooth looking results, and needs fewer test points to
+ create. A LUT based profile on the other hand, will model any
+ display behaviour more accurately, and can accommodate gamut mapping
+ and different intent tables. Often it can show some unevenness and
+ contouring in the results though.<br>
+ <br>
+ To create a matrix/shaper profile, the following suffices:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-as</a> <a href="colprof.html#p1">DisplayA</a><br>
+ <br>
+ For a LUT based profile, where gamut mapping is desired, then a
+ source profile will need to be provided to define the source gamut.
+ For instance, if the display profile was likely to be linked to a
+ CMYK printing source profile, say "swop.icm" or "fogra39l.icm", then
+ the following would suffice:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Display A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S">
+ fogra39l.icm</a> <a href="colprof.html#c">-cpp</a> <a
+ href="colprof.html#d">-dmt</a> <a href="colprof.html#p1">DisplayA</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the profile is behaving reasonably.<br>
+ If a calibration file was used with <a href="dispread.html">dispread</a>,
+ then it will be converted to a vcgt tag in the profile, so that the
+ operating system or other system color tools load the lookup curves
+ into the display hardware, when the profile is used.<br>
+ <h4><a name="PM5"></a>Installing a display profile</h4>
+ <a href="dispwin.html">dispwin</a> provides a convenient way of
+ installing a profile as the default system profile for the chosen
+ display:<br>
+ <br>
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#I">-I</a>
+ <a href="dispwin.html#p1">DisplayA.icm</a><br>
+ <br>
+ This also sets the display to the calibration contained in the
+ profile. If you want to try out a calibration before installing the
+ profile, using dispwin without the <span style="font-weight: bold;">-I</span>
+ option will load a calibration (ICC profile or .cal file) into the
+ current display.<br>
+ <br>
+ Some systems will automatically set the display to the calibration
+ contained in the installed profile (ie. OS X), while on other
+ systems (ie. MSWindows and Linux/X11) it is necessary to use some
+ tool to do this. On MSWindows XP you could install the
+ optional&nbsp; <span style="font-weight: bold;">Microsoft&nbsp;Color&nbsp;Control&nbsp;Panel&nbsp;Applet&nbsp;for&nbsp;Windows&nbsp;XP</span>
+ available for download from Microsoft to do this, but&nbsp;<span
+ style="font-weight: bold;">NOTE</span> however that it seems to
+ have a <span style="font-weight: bold;">bug</span>, in that it
+ sometimes associates the profiles with the <span
+ style="font-weight: bold;">wrong monitor</span> entry. Other
+ display calibration tools will often install a similar tool, so
+ beware of there being multiple, competing programs. [ Commonly these
+ will be in your Start-&gt;Programs-&gt;Startup folder. ]<br>
+ On Microsoft Vista, you need to use dispwin -L or some other tool to
+ load the installed profiles calibration at startup.<br>
+ <br>
+ To use dispwin to load the installed profiles calibration to the
+ display, use<br>
+ <br>
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a><br>
+ <br>
+ As per usual, you can select the appropriate display using the <a
+ href="dispwin.html#d">-d</a> flag.<br>
+ <br>
+ This can be automated on MSWindows and X11/Linux by adding this
+ command to an appropriate startup script.<br>
+ More system specific details, including how to create such startup
+ scripts are <a href="dispprofloc.html">here</a>. <br>
+ <br>
+ If you are using Microsoft <span style="font-weight: bold;">Vista</span>,
+ there is a known <span style="font-weight: bold;">bug</span> in
+ Vista that resets the calibration every time a fade-in effect is
+ executed, which happens if you lock and unlock the computer, resume
+ from sleep or hibernate, or User Access Control is activated. Using
+ <a href="dispwin.html">dispwin</a> <a href="dispwin.html#L">-L</a>
+ may not restore the calibration, because Vista filters out setting
+ (what it thinks) is a calibration that is already loaded. Use <a
+ href="dispwin.html">dispwin</a> <a href="dispwin.html#c">-c</a> <a
+ href="dispwin.html#L">-L</a><span style="font-family: monospace;"></span>
+ as a workaround, as this will first clear the calibration, then
+ re-load the current calibration.<br>
+ <br>
+ On X11/Linux systems, you could try adding <a href="dispwin.html">dispwin</a>
+ <a href="dispwin.html#L">-L</a> to your <span style="font-weight:
+ bold;">~/.config/autostart</span> file, so that your window
+ manager automatically sets calibration when it starts. If you are
+ running XRandR 1.2, you might consider running the experimental <a
+ href="dispwin.html#D">dispwin -E</a> in the background, as in its
+ "daemon" mode it will update the profile and calibration in response
+ to any changes in the the connected display.<br>
+ <br>
+ <h4><a name="PM6"></a>Expert tips when measuring displays:<br>
+ </h4>
+ Sometimes it can be difficult to get good quality, consistent and
+ visually relevant readings from displays, due to various practical
+ considerations with regard to instruments and the displays
+ themselves. Argyll's tools have some extra options that may assist
+ in overcoming these problems.<br>
+ <br>
+ If you are using an Eye-One Pro or ColorMunki spectrometer, then you
+ may wish to use the <a href="dispcal.html#H">high resolution
+ spectral mode</a> (<span style="font-weight: bold;">-H</span>).
+ This may be better at capturing the often narrow wavelength peaks
+ that are typical of display primary colors.<br>
+ <br>
+ All instruments depend on silicon sensors, and such sensors generate
+ a temperature dependant level of noise ("dark noise") that is
+ factored out of the measurements by a dark or black instrument
+ calibration. The spectrometers in particular need this calibration
+ before commencing each set of measurements. Often an instrument will
+ warm up as it sits on a display, and this warming up can cause the
+ dark noise to increase, leading to inaccuracies in dark patch
+ measurements. The longer the measurement takes, the worse this
+ problem is likely to be. One way of addressing this is to
+ "acclimatise" the instrument before commencing measurements by
+ placing it on the screen in a powered up state, and leaving it for
+ some time. (Some people leave it for up to an hour to acclimatise.).
+ Another approach is to try and <a href="dispcal.html#I">compensate
+ for dark calibration changes</a> (<span style="font-weight: bold;">-Ib</span>)
+ by doing on the fly calibrations during the measurements, based on
+ the assumption that the black level of the display itself won't
+ change significantly. <br>
+ <br>
+ Some displays take a long time to settle down and stabilise. The is
+ often the case with LCD (Liquid Crystal) displays that use
+ fluorescent back lights, and these sorts of displays can change in
+ brightness significantly with changes in temperature. One way of
+ addressing this is to make sure that the display is given adequate
+ time to warm up before measurements. Another approach is to try and
+ <a href="dispcal.html#I">compensate for display white level</a>&nbsp;
+
+
+
+
+
+
+
+
+ (<span style="font-weight: bold;">-Iw</span>) changes by doing on
+ the fly calibrations during the measurements. Instrument black level
+ drift and display white level drift can be combined (<span
+ style="font-weight: bold;">-Ibw</span>).<br>
+ <br>
+ Colorimeter instruments make use of physical color filters that
+ approximate the standard observer spectral sensitivity curves.
+ Because these filters are not perfectly accurate, the manufacturer
+ calibrates the instrument for typical displays, which is why you
+ have to make a selection between CRT (Cathode Ray Tube) and LCD
+ (Liquid Crystal Display) modes. If you are measuring a display that
+ has primary colorants that differ significantly from those typical
+ displays,&nbsp; (ie. you have a Wide Gamut Display), then you may
+ get disappointing results with a Colorimeter. One way of addressing
+ this problem is to use a <a href="File_Formats.html#.ccmx">Colorimeter
+
+
+
+
+
+
+
+ Correction Matrix</a>. These are specific to a particular
+ Colorimeter and Display make and model combination, although a
+ matrix for a different but similar type of display may give better
+ results than none at all. A list of contributed <span
+ style="font-weight: bold;">ccmx</span> files is <a
+ href="ccmxs.html">here</a>.<br>
+ <br>
+ <h4><a name="PM7"></a>Calibrating and profiling a display that
+ doesn't have VideoLUT access.</h4>
+ <p>In some situation there is no access to a displays VideoLUT
+ hardware, and this hardware is what is usually used to implement
+ display calibration. This could be because the display is being
+ accessed via a web server, or because the driver or windowing
+ system doesn't support VideoLUT access.<br>
+ </p>
+ <p>There are two basic options in this situation:<br>
+ </p>
+ <p>&nbsp; 1) Don't attempt to calibrate, just profile the display.<br>
+ &nbsp; 2) Calibrate, but incorporate the calibration in some other
+ way in the workflow.<br>
+ </p>
+ <p>The first case requires nothing special - just skip calibration
+ (see the previous section <a href="#PM7">Profiling in several
+ steps: Creating display test values</a>).</p>
+ <p> In the second case, there are three choices:<br>
+ </p>
+ <p>&nbsp;2a) Use dispcal to create a calibration and a quick profile
+ that incorporates the calibration into the profile.<br>
+ &nbsp;2b) Use dispcal to create the calibration, then dispread and
+ colprof to create a profile, and then incorporate the calibration
+ into the profile using applycal.<br>
+ &nbsp;2c) Use dispcal to create the calibration, then dispread and
+ colprof to create a profile, and then apply the calibration after
+ the profile in a cctiff workflow.<br>
+ </p>
+ <p>The first case requires nothing special, use dispcal in a normal
+ fashioned with the <span style="font-weight: bold;">-o</span>
+ option to generate a quick profile.The profile created will <span
+ style="text-decoration: underline;">not</span> contain a 'vcgt'
+ tag, but instead will have the calibration curves incorporated
+ into the profile itself. If calibration parameters are chosen that
+ change the displays white point or brightness, then this will
+ result in a slightly unusual profile that has a white point that
+ does not correspond with device R=G=B=1.0. Some systems may not
+ cope properly with this type of profile, and a general shift in
+ white point through such a profile can create an odd looking
+ display if it is applied to images but not to other elements on
+ the display say as GUI decoration elements or other application
+ windows.<br>
+ </p>
+ <p>In the second case, the calibration file created using dispcal
+ should be provided to dispread using the <span
+ style="font-weight: bold;">-K</span> flag:<br>
+ </p>
+ <p><a href="dispread.html">dispread</a> <a href="dispread.html#v">-v</a>
+ <a href="dispread.html#K">-K TargetA.cal</a> <a
+ href="dispread.html#p1">DisplayA</a></p>
+ <p><span style="font-weight: bold;"></span>Create the profile as
+ usual using colprof. but note that colprof will ignore the
+ calibration, and that no 'vcgt' tag will be added to the profile.<br>
+ You can then use <a href="applycal.html">applycal </a>to combine
+ the calibration into the profile. Note that the resulting profile
+ will be slightly unusual, since the profile is not made completely
+ consistent with the effects of the calibration, and the device
+ R=G=B=1.0 probably not longer corresponds with the PCS white or
+ the white point.<br>
+ </p>
+ In the third case, the same procedure as above is used to create a
+ profile, but the calibration is applied in a raster transformation
+ workflow explicitly, e.g.:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">SourceProfile.icm</a> <a
+ href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">SourceProfile.icm</a> <a
+ href="cctiff.html#p1">DisplayA.icm</a> <a href="cctiff.html#p2">DisplayA.cal</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <span style="font-weight: bold;"></span><br>
+ <hr size="2" width="100%">
+ <h3><a name="PS1"></a>Profiling Scanners and other input devices
+ such as cameras<br>
+ </h3>
+ Because a scanner or camera is an input device, it is necessary to
+ go about profiling it in quite a different way to an output device.
+ To profile it, a test chart is needed to exercise the input device
+ response, to which the CIE values for each test patch is known.
+ Generally standard reflection or transparency test charts are used
+ for this purpose.<br>
+ <h4><a name="PS2"></a>Types of test charts</h4>
+ The most common and popular test chart for scanner profiling is the
+ IT8.7/2 chart. This is a standard format chart generally reproduced
+ on photographic film, containing about 264 test patches.<br>
+ An accessible and affordable source of such targets is Wolf Faust a
+ <a href="http://www.targets.coloraid.de/">www.coloraid.de</a>.<br>
+ Another source is LaserSoft <a
+ href="http://www.silverfast.com/show/it8/en.html">www.silverfast.com.</a><br>
+ The Kodak Q-60 Color Input Target is also a typical example:<br>
+ <br>
+ <img src="Q60.jpg" alt="Kodak Q60 chart image" height="141"
+ width="200"> <br>
+ <br>
+ A very simple chart that is widely available is the Macbeth
+ ColorChecker chart, although it contains only 24 patches and
+ therefore is probably not ideal for creating profiles:<br>
+ <img alt="ColorChecker 24 patch" src="colorchecker.jpg"
+ style="width: 112px; height: 78px;"><br>
+ <br>
+ Other popular charts are the X-Rite/GretagMacbeth ColorChecker DC
+ and <a href="http://www.xrite.com/product_overview.aspx?ID=938">ColorChecker
+
+
+
+
+
+
+
+
+ SG</a> charts:<br>
+ <br>
+ <img src="DC.jpg" alt="GretagMacbeth ColorChecker DC chart"
+ height="122" width="200"> <img alt="ColorChecker SG" src="SG.jpg"
+ style="width: 174px; height: 122px;"><br>
+ <br>
+ The GretagMacbeth Eye-One Pro Scan Target 1.4 can also be used:<br>
+ <br>
+ <img alt="Eye-One Scan Target 1.4" src="i1scan14.jpg" style="border:
+ 2px solid ; width: 200px; height: 140px;"><br>
+ <br>
+ Also supported is the <a href="http://www.hutchcolor.com/hct.htm">HutchColor
+
+
+
+
+
+
+
+
+ HCT</a> :<br>
+ <br>
+ <img alt="HutchColor HCT" src="HCT.jpg" style="width: 182px; height:
+ 140px;"><br>
+ <br>
+ <br>
+ and <a
+href="http://www.christophe-metairie-photographie.com/eng%20digital%20target.html">Christophe
+
+
+
+
+
+
+
+
+ M&eacute;tairie's Digital TargeT 003</a> and <a
+href="http://www.christophe-metairie-photographie.com/eng%20digital%20target.html">Christophe
+
+
+
+
+
+
+
+
+ M&eacute;tairie's Digital Target - 3</a> :<br>
+ <br>
+ <img alt="CMP_DT_003" src="CMP_DT_003.jpg" style="width: 186px;
+ height: 141px;">&nbsp; <img style="width: 203px; height: 140px;"
+ alt="CMP_Digital_Target-3" src="CMP_Digital_Target-3.jpg"><br>
+ <br>
+ and the <a href="http://www.silverfast.com/show/dc-targets/en.html">LaserSoft
+
+
+
+
+
+
+
+
+ Imaging DCPro Target</a>:<br>
+ <br>
+ <img style="width: 153px; height: 122px;" alt="LaserSoft DCPro
+ Target" src="LSDC.jpg"><br>
+ <br>
+ The Datacolor <a
+ href="http://spyder.datacolor.com/product-cb-spydercheckr.php">SpyderCheckr</a>:<br>
+ <br>
+ <img style=" width: 146px; height: 109px;" alt="Datacolor
+ SpyderCheckr" src="SpyderChecker.jpg"><br>
+ <br>
+ One of the QPcard's:<br>
+ <a
+ href="http://www.qpcard.com/en_b2c/color-reference-cards/qpcard201.html">QPcard
+
+
+ 201</a>:&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <a
+href="http://www.qpcard.com/en_b2c/color-reference-cards/instant-camera-raw-profiling-with-qpcard-202.html">QPcard
+
+
+ 202</a>:<br>
+ <br>
+ <img style=" width: 41px; height: 141px;" alt="QPCard201"
+ src="QPcard201.jpg">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <img
+ style=" width: 97px; height: 141px;" alt="QPcard202"
+ src="QPcard202.jpg"><br>
+ <br>
+ <h4><a name="PS3"></a>Taking readings from a scanner or camera<br>
+ </h4>
+ The test chart you are using needs to be placed on the scanner, and
+ the scanner needs to be configured to a suitable state, and restored
+ to that same state when used subsequently with the resulting
+ profile. For a camera, the chart needs to be lit in a controlled and
+ even manner using the light source that will be used for subsequent
+ photographs, and should be shot so as to minimise any geometric
+ distortion, although the <a href="scanin.html#p">scanin -p</a> flag
+ may be used to compensate for some degree of distortion. As with any
+ color profiling task, it is important to setup a known and
+ repeatable image processing flow, to ensure that the resulting
+ profile will be usable.<br>
+ <br>
+ The chart should be captured and saved to a TIFF format file. I will
+ assume the resulting file is called scanner.tif. The raster file
+ need only be roughly cropped so as to contain the test chart
+ (including the charts edges).<br>
+ <br>
+ The second step is to extract the RGB values from the scanner.tif
+ file, and match then to the reference CIE values. To locate the
+ patch values in the scan, the <b>scanin</b> tool needs to be given
+ a template <a href="File_Formats.html#.cht">.cht</a> file that
+ describes the features of the chart, and how the test patches are
+ labeled. Also needed is a file containing the CIE values for each of
+ the patches in the chart, which is typically supplied with the
+ chart, available from the manufacturers web site, or has been
+ measured using a spectrometer.<br>
+ <br>
+ <div style="margin-left: 40px;">For an IT8.7/2 chart, this is the <span
+ style="font-weight: bold;">ref/</span><b>it8.cht</b> file
+ supplied with Argyll, and&nbsp; the manufacturer will will supply
+ an individual or batch average file along with the chart
+ containing this information, or downloadable from their web site.
+ For instance, Kodak Q60 target reference files are <a
+ href="ftp://ftp.kodak.com/gastds/Q60DATA/">here</a>.<br>
+ NOTE that the reference file for the IT8.7/2 chart supplied with <span
+ style="font-weight: bold;">Monaco&nbsp;EZcolor</span> can be
+ obtained by unzipping the .mrf file. (You may have to make a copy
+ of the file with a .zip extension to do this.)<br>
+ <br>
+ For the ColorChecker 24 patch chart, the <span
+ style="font-weight: bold;">ref/ColorChecker.cht</span> file
+ should be used, and there is also a <span style="font-weight:
+ bold;">ref/ColorChecker.cie</span> file provided that is based
+ on the manufacturers reference values for the chart. You can also
+ create your own reference file using an instrument and chartread,
+ making use of the chart reference file <span style="font-weight:
+ bold;">ref/ColorChecker.ti2</span>:<br>
+ &nbsp;&nbsp; <a href="chartread.html">chartread</a> -n -a
+ ColorChecker.ti2<br>
+ Note that due to the small number of patches, a profile created
+ from such a chart is not likely to be very detailed.<br>
+ <br>
+ For the ColorChecker DC chart, the <span style="font-weight:
+ bold;">ref/ColorCheckerDC.cht</span> file should be used, and
+ there will be a ColorCheckerDC reference file supplied by
+ X-Rite/GretagMacbeth with the chart.<br>
+ <br>
+ The ColorChecker SG is relatively expensive, but is preferred by
+ many people because (like the ColorChecker and ColorCheckerDC) its
+ colors are composed of multiple different pigments, giving it
+ reflective spectra that are more representative of the real world,
+ unlike many other charts that are created out of combination of 3
+ or 4 colorants.<br>
+ A limited CIE reference file is available from X-Rite <a
+href="http://www.xrite.com/documents/apps/public/digital_colorchecker_sg_l_a_b.txt">here</a>,
+ but it is not in the usual CGATS format. To convert it to a CIE
+ reference file useful for <span style="font-weight: bold;">scanin</span>,
+ you will need to edit the X-Rite file using a <span
+ style="text-decoration: underline;">plain text</span> editor,
+ first deleting everything before the line starting with "A1" and
+ everything after "N10", then prepending <a href="SG_header.txt">this
+
+
+
+
+
+
+
+ header</a>, and appending <a href="SG_footer.txt">this footer</a>,
+ making sure there are no blank lines inserted in the process.<br>
+ If you do happen to have access to a more comprehensive instrument
+ measurement of the ColorChecker SG, or you have measured it
+ yourself using a color instrument,<br>
+ then you <span style="text-decoration: underline;">may</span>
+ need to convert the reference information from spectral <span
+ style="font-weight: bold;">ColorCheckerSG.txt</span> file to CIE
+ value <span style="font-weight: bold;">ColorCheckerSG.cie</span>
+ reference file, follow the following steps:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="txt2ti3.html">txt2ti3</a>
+ ColorCheckerSG.txt ColorCheckerSG<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="spec2cie.html">spec2cie</a>
+ ColorCheckerSG.ti3 ColorCheckerSG.cie<br>
+ <br>
+ For the Eye-One Pro Scan Target 1.4 chart, the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">ref/</span>i1_RGB_Scan_1.4.cht</span>
+ file should be used, and as there is no reference file
+ accompanying this chart, the chart needs to be read with an
+ instrument (usually the Eye-One Pro). This can be done using
+ chartread,&nbsp; making use of the chart reference file <span
+ style="font-weight: bold;">ref/i1_RGB_Scan_1.4.ti2</span>:<br>
+ &nbsp;&nbsp;&nbsp; <a href="chartread.html">chartread</a> -n -a
+ i1_RGB_Scan_1.4<br>
+ and then rename the resulting <span style="font-weight: bold;">i1_RGB_Scan_1.4.ti3</span>
+ file to <span style="font-weight: bold;">i1_RGB_Scan_1.4.cie</span><br>
+ <span style="font-weight: bold;"></span><br>
+ For the HutchColor HCT chart, the <span style="font-weight:
+ bold;"><span style="font-weight: bold;">ref/</span>Hutchcolor.cht</span>
+ file should be used, and the reference <span style="font-weight:
+ bold;">.txt</span> file downloaded from the HutchColor website.<br>
+ <br>
+ For the Christophe M&eacute;tairie's Digital TargeT 003 chart with
+ 285 patches, the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">ref/</span>CMP_DT_003.cht</span>
+ file should be used, and the cie reference <span
+ style="font-weight: bold;"></span>files come with the chart.<br>
+ <br>
+ For the Christophe M&eacute;tairie's Digital Target-3 chart with
+ 570 patches, the <span style="font-weight: bold;">ref/CMP_Digital_Target-3.cht</span>
+ file should be used, and the cie reference <span
+ style="font-weight: bold;"></span>files come with the chart.<br>
+ <br>
+ For the LaserSoft DCPro chart, the <span style="font-weight:
+ bold;">ref/LaserSoftDCPro.cht</span> file should be used, and
+ reference <span style="font-weight: bold;">.txt</span> file
+ downloaded from the <a
+ href="http://www.silverfast.com/it8calibration/">Silverfast
+ website</a>.<br>
+ <br>
+ For the Datacolor SpyderCheckr, the <span style="font-weight:
+ bold;">ref/SpyderChecker.cht</span> file should be used, and a
+ reference <span style="font-weight: bold;">ref/SpyderChecker.cie
+ </span>file made from measuring a sample chart is also available.
+ Alternately you could create your own reference file by
+ transcribing the <a
+ href="http://spyder.datacolor.com/images/photo_checkr_colordatainfo.jpg">values</a>
+ on the Datacolor website. <br>
+ <br>
+ For the QPCard 201, the <span style="font-weight: bold;">ref/QPcard_201.cht</span>
+ file should be used, and a reference <span style="font-weight:
+ bold;">ref/QPcard_201.cie</span> file made from measuring a
+ sample chart is also available. <br>
+ <br>
+ For the QPCard 202, the <span style="font-weight: bold;">ref/QPcard_202.cht</span>
+ file should be used, and a reference <span style="font-weight:
+ bold;">ref/QPcard_202.cie</span> file made from measuring a
+ sample chart is also available. <br>
+ </div>
+ <br>
+ For any other type of chart, a chart recognition template file will
+ need to be created (this is beyond the scope of the current
+ documentation, although see&nbsp; the <a href="cht_format.html">.cht_format
+
+
+
+
+
+
+
+ documentation</a>).<br>
+ <br>
+ To create the scanner .ti3 file, run the <b>scanin</b> tool as
+ follows (assuming an IT8 chart is being used):<br>
+ <br>
+ <a href="scanin.html"> scanin</a> -v scanner.tif It8.cht It8ref.txt<br>
+ <br>
+ "It8ref.txt" or "It8ref.cie" is assumed to be the name of the CIE
+ reference file supplied by the chart manufacturer. The resulting
+ file will be named "<b>scanner.ti3</b>".<br>
+ <br>
+ <span style="font-weight: bold;">scanin</span> will process 16 bit
+ per component .tiff files, which (if the scanner is capable of
+ creating such files),&nbsp; may improve the quality of the profile.
+ <br>
+ <br>
+ If you have any doubts about the correctness of the chart
+ recognition, or the subsequent profile's delta E report is unusual,
+ then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
+ and examine the <span style="font-weight: bold;">diag.tif</span>
+ diagnostic file, to make sure that the patches are identified and
+ aligned correctly. If you have problems getting good automatic
+ alignment, then consider doing a manual alignment by locating the
+ fiducial marks on your scan, and feeding them into scanin <a
+ href="scanin.html#F">-F</a> parameters. The fiducial marks should
+ be listed in a clockwise direction starting at the top left.<br>
+ <h4><a name="PS4"></a>Creating a scanner or camera input profile</h4>
+ Similar to a display profile, an input profile can be either a
+ shaper/matrix or LUT based profile. Well behaved input devices will
+ probably give the best results with a shaper/matrix profile, and
+ this may also be the best choice if your test chart has a small or
+ unevenly distributed set of test patchs (ie. the IT8.7.2). If a
+ shaper/matrix profile is a poor fit, consider using a LUT type
+ profile.<br>
+ <br>
+ When creating a LUT type profile, there is the choice of XYZ or
+ L*a*b* PCS (Device independent, Profile Connection Space). Often for
+ input devices, it is better to choose the XYZ PCS, as this may be a
+ better fit given that input devices are usually close to being
+ linearly additive in behaviour.<br>
+ <br>
+ If the purpose of the input profile is to use it as a substitute for
+ a colorimeter, then the <b>-u</b> flag should be used to avoid
+ clipping values above the white point. Unless the shaper/matrix type
+ profile is a very good fit, it is probably advisable to use a LUT
+ type profile in this situation.<br>
+ <br>
+ To create a matrix/shaper profile, the following suffices:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner</a> <a href="colprof.html#E">A"</a>
+ <a href="colprof.html#q">-qm</a> <a href="colprof.html#a">-as</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ For an XYZ PCS LUT based profile then the following would be used:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-ax</a> <a href="colprof.html#p1">scanner</a><br>
+ <br>
+ For the purposes of a poor mans colorimeter, the following would
+ generally be used:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Scanner A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-ax</a> <a href="colprof.html#u">-u</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the profile is behaving reasonably.<br>
+ <br>
+ <br>
+ If profiling a <span style="font-weight: bold;">camera</span> in <span
+ style="font-weight: bold;">RAW</span> mode, then there may be some
+ advantage in creating a pure matrix only profile, in which it is
+ assumed that the camera response is completely linear. This may
+ reduce extrapolation artefacts. If setting the white point will be
+ done in some application, then it may also be an advantage to use
+ the <span style="font-weight: bold;">-u</span> flag and avoid
+ setting the white point to that of the profile chart:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Camera"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#a">-am</a> <a href="colprof.html#u">-u</a> <a
+ href="colprof.html#p1">scanner</a><br>
+ <br>
+ <br>
+ <hr size="2" width="100%">
+ <h3><a name="PP1"></a>Profiling Printers<br>
+ </h3>
+ The overall process is to create a set of device measurement target
+ values, print them out, measure them, and then create an ICC profile
+ from the measurements. If the printer is an RGB based printer, then
+ the process is only slightly more complicated than profiling a
+ display. If the printer is CMYK based, then some additional
+ parameters are required to set the total ink limit (TAC) and
+ &nbsp;black generation curve.<br>
+ <h4><a name="PP2"></a>Creating a print profile test chart</h4>
+ The first step in profiling any output device, is to create a set of
+ device colorspace test values. The important parameters needed are:<br>
+ <ul>
+ <li>What colorspace does the device use ?</li>
+ <li>How many test patches do I want to use/what paper size do I
+ want to use ?</li>
+ <li>What instrument am I going to use to read the patches ?<br>
+ </li>
+ <li>If it is a CMYK device, what is the total ink limit ?<br>
+ </li>
+ <li>What information do I already have about how the device
+ behaves ?</li>
+ </ul>
+ Most printers running through simple drivers will appear as if they
+ are RGB devices. In fact there is no such thing as a real RGB
+ printer, since printers use white media and the colorant must
+ subtract from the light reflected on it to create color, but the
+ printer itself turns the incoming RGB into the native print
+ colorspace, so for this reason we will tell targen to use the "Print
+ RGB" colorspace, so that it knows that it's really a subtractive
+ media. Other drivers will drive a printer more directly, and will
+ expect a CMYK profile. [Currently Argyll is not capable of creating
+ an ICC profile for devices with more colorants than CMYK. When this
+ capability is introduced, it will by creating an additional
+ separation profile which then allows the printer to be treated as a
+ CMY or CMYK printer.] One way of telling what sort of profile is
+ expected for your device is to examine an existing profile for that
+ device using <a href="http://www.argyllcms.com/doc/iccdump.html">iccdump</a>.<br>
+ <br>
+ The number of test patches will depend somewhat on what quality
+ profile you want to make, how well behaved the printer is, as well
+ as the effort needed to read the number of test values. Generally it
+ is convenient to fill a certain paper size with the maximum number
+ of test values that will fit.<br>
+ <br>
+ At a minimum, for an "RGB" device, a few hundred values are needed
+ (400-1000). For high quality CMYK profiles, 1000-3000 is not an
+ unreasonable number of patches.<br>
+ <br>
+ To assist the determination of test patch values, it can help to
+ have a rough idea of how the device behaves, so that the device test
+ point locations can be pre-conditioned. This could be in the form of
+ an ICC profile of a similar device, or a lower quality, or previous
+ profile for that particular device. If one were going to make a very
+ high quality Lut based profile, then it might be worthwhile to make
+ up a smaller, preliminary shaper/matrix profile using a few hundred
+ test points, before embarking on testing the device with several
+ thousand.<br>
+ <br>
+ The documentation for the <a
+ href="http://www.argyllcms.com/doc/targen.html">targen</a> tool
+ lists a <a href="http://www.argyllcms.com/doc/targen.html#Table">table</a>
+ of paper sizes and number of &nbsp;patches for typical situations.<br>
+ <br>
+ For a CMYK device, a total ink limit usually needs to be specified.
+ Sometimes a device will have a maximum total ink limit set by its
+ manufacturer or operator, and some CMYK systems (such as chemical
+ proofing systems) don't have any limit. Typical printing devices
+ such as Xerographic printers, inkjet printers and printing presses
+ will have a limit. The exact procedure for determining an ink limit
+ is outside the scope of this document, but one way of going about
+ this might be to generate some small (say a few hundred patches)
+ with targen &amp; pritntarg with different total ink limits, and
+ printing them out, making the ink limit as large as possible without
+ striking problems that are caused by too much ink.<br>
+ <br>
+ Generally one wants to use the maximum possible amount of ink to
+ maximize the gamut available on the device. For most CMYK devices,
+ an ink limit between 200 and 400 is usual, but and ink limit of 250%
+ or over is generally desirable for reasonably dense blacks and dark
+ saturated colors. And ink limit of less than 200% will begin to
+ compromise the fully saturated gamut, as secondary colors (ie
+ combinations of any two primary colorants) will not be able to reach
+ full strength.<br>
+ <br>
+ Once an ink limit is used in printing the characterization test
+ chart for a device, it becomes a critical parameter in knowing what
+ the characterized gamut of the device is. If after printing the test
+ chart, a greater ink limit were to be used, the the software would
+ effectively be extrapolating the device behaviour at total ink
+ levels beyond that used in the test chart, leading to inaccuracies.<br>
+ <br>
+ Generally in Argyll, the ink limit is established when creating the
+ test chart values, and then carried through the profile making
+ process automatically. Once the profile has been made however, the
+ ink limit is no longer recorded, and you, the user, will have to
+ keep track of it if the ICC profile is used in any program than
+ needs to know the usable gamut of the device.<br>
+ <br>
+ <br>
+ Lets consider two devices in our examples, "PrinterA" which is an
+ "RGB" device, and "PrinterB" which is CMYK, and has a target ink
+ limit of 250%. <br>
+ <br>
+ The simplest approach is to make a set of test values that is
+ independent of the characteristics of the particular device:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
+ <a href="targen.html#p1">PrinterA</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
+ <a href="targen.html#f">-f1053</a> <a href="targen.html#p1">PrinterB</a><br>
+ <br>
+ The number of patches chosen here happens to be right for an A4
+ paper size being read using a Spectroscan instrument. See the <a
+ href="targen.html#Table">table</a> in&nbsp; the <a
+ href="targen.html">targen</a> documentation for some other
+ suggested numbers.<br>
+ <br>
+ If there is a preliminary or previous profile called "OldPrinterA"
+ available, and we want to try creating a "pre-conditioned" set of
+ test values that will more efficiently sample the device response,
+ then the following would achieve this:<u><br>
+ </u><br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#f">-f1053</a>
+ <a href="targen.html#c">-c OldPrinterA</a>&nbsp;<a
+ href="targen.html#p1">PrinterA</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#l">-l260</a>
+ <a href="targen.html#f">-f1053</a> <a href="targen.html#c">-c
+ OldPrinterB</a> <a href="targen.html#p1">PrinterB</a><br>
+ <a href="targen.html#p1"></a><br>
+ <br>
+ The output of <b>targen</b> will be the file PrinterA.ti1 and
+ PrinterB.ti1 respectively, containing the device space test values,
+ as well as expected CIE values used for chart recognition purposes.<br>
+ <br>
+ <h4><a name="PP2b"></a>Printing a print profile test chart<br>
+ <br>
+ </h4>
+ The next step is turn the test values in to a PostScript or TIFF
+ raster test file that can printed on the device. The basic
+ information that needs to be supplied is the type of instrument that
+ will be used to read the patches, as well as the paper size it is to
+ be formatted for.<br>
+ <br>
+ For an X-Rite DTP41, the following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#i">-i41</a> <a href="printtarg.html#p">-pA4</a>
+ <a href="printtarg.html#p1">PrinterA</a><br>
+ &nbsp;<br>
+ For a Gretag Eye-One Pro, the following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#i">-ii1</a> <a href="printtarg.html#p">-pA4</a>
+ <a href="printtarg.html#p1">PrinterA</a><br>
+ <br>
+ For using with a scanner as a colorimeter, the Gretag Spectroscan
+ layout is suitable, but the <a href="printtarg.html#s">-s</a> flag
+ should be used so as to generate a layout suitable for scan
+ recognition, as well as generating the scan recognition template
+ files. (You probably want to use less patches with <span
+ style="font-weight: bold;">targen</span>, when using the <span
+ style="font-weight: bold;">printtarg -s</span> flag, e.g. 1026
+ patches for an A4R page, etc.) The following would be typical:<br>
+ <br>
+ <a href="printtarg.html">printtarg</a> <a href="printtarg.html#v">-v</a>
+ <a href="printtarg.html#s">-s</a> <a href="printtarg.html#i">-iSS</a>
+ <a href="printtarg.html#p">-pA4R</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <span style="font-weight: bold;"><br>
+ printtarg</span> reads the PrinterA.ti1 file, creates a
+ PrinterA.ti2 file containing the layout information as well as the
+ device values and expected CIE values, as well as a PrinterA.ps file
+ containing the test chart. If the <span style="font-weight: bold;">-s</span>
+ flag is used, one or more PrinterA.cht files is created to allow the
+ <a href="scanin.html">scanin</a> program to recognize the chart.<br>
+ <br>
+ To create TIFF raster files rather than PostScript, use the <a
+ href="printtarg.html#t"><span style="font-weight: bold;">-t</span></a>
+ flag.<br>
+ <br>
+ <span style="font-weight: bold;">GSview</span> is a good program to
+ use to check what the PostScript file will look like, without
+ actually printing it out. You could also use <span
+ style="font-weight: bold;">Photoshop</span> or <span
+ style="font-weight: bold;">ImageMagick</span> for this purpose.<br>
+ <br>
+ The last step is to print the chart out.<br>
+ <br>
+ Using a suitable PostScript or raster file printing program,
+ downloader, print the chart. If you are not using a TIFF test chart,
+ and you do not have a PostScript capable printer, then an
+ interpreter like GhostScript or even Photoshop could be used to
+ rasterize the file into something that can be printed. Note that it
+ is important that the PostScript interpreter or TIFF printing
+ application and printer configuration is setup for a device
+ profiling run, and that any sort of color conversion of color
+ correction be turned off so that the device values in the PostScript
+ or TIFF file are sent directly to the device. If the device has a
+ calibration system, then it would be usual to have setup and
+ calibrated the device before starting the profiling run, and to
+ apply calibration to the chart values. If Photoshop was to be used,
+ then either the chart needs to be a single page, or separate .eps or
+ .tiff files for each page should be used, so that they can be
+ converted and printed one at a time (see the <a
+ href="printtarg.html#e">-e</a> and <a href="printtarg.html#t">-t</a>
+ flags).<br>
+ <br>
+ <h4><a name="PP3"></a>Reading a print test chart using an instrument</h4>
+ Once the test chart has been printed, the color of the patches needs
+ to be read using a suitable instrument.<br>
+ <br>
+ Several different instruments are currently supported, some that
+ need to be used patch by patch, some read a strip at a time, and
+ some read a sheet at a time. See <a href="instruments.html">instruments</a>
+ for a current list.<br>
+ <br>
+ The instrument needs to be connected to your computer before running
+ the <a href="chartread.html">chartread</a> command. Both serial
+ port and USB connected Instruments are supported. A serial port to
+ USB adapter might have to be used if your computer doesn't have any
+ serial ports, and you have a serial interface connected instrument.<br>
+ <br>
+ If you run <a href="chartread.html">chartread</a> so as to print
+ out its usage message (ie. by using a <span style="font-weight:
+ bold;">-?</span> or <span style="font-weight: bold;">--</span>
+ flags), then it will list any identified serial ports or USB
+ connected instruments, and their corresponding number for the <a
+ href="chartread.html#c">-c</a> option. By default, <a
+ href="chartread.html">chartread</a> will try to connect to the
+ first available USB instrument, or an instrument on the first serial
+ port.<br>
+ <br>
+ The only arguments required is to specify the basename of the .ti2
+ file. If a non-default serial port is to be used, then the <span
+ style="font-weight: bold;">-c</span> option would also be
+ specified.<br>
+ <br>
+ &nbsp;e.g. for a Spectroscan on the second port:<br>
+ <br>
+ <a href="chartread.html">chartread</a> <a href="chartread.html#c">-c2</a>
+ <a href="chartread.html#p1">PrinterA</a><br>
+ <br>
+ For a DTP41 to the default serial port:<br>
+ <br>
+ <a href="chartread.html">chartread</a><a href="chartread.html#i"></a>
+ <a href="chartread.html#p1">PrinterA</a><br>
+ <br>
+ <span style="font-weight: bold;">chartread</span> will interactively
+ prompt you through the process of reading each sheet or strip. See <a
+ href="chartread.html">chartread</a> for more details on the
+ responses for each type of instrument. Continue with <a
+ href="Scenarios.html#PP5">Creating a printer profile</a>.<br>
+ <br>
+ <h4><a name="PP4"></a>Reading a print test chart using a scanner or
+ camera<br>
+ </h4>
+ <br>
+ Argyll supports using a scanner or even a camera as a substitute for
+ a colorimeter. While a scanner or camera is no replacement for a
+ color measurement instrument, it may give acceptable results in some
+ situations, and may give better results than a generic profile for a
+ printing device.<br>
+ <br>
+ The main limitation of the scanner-as-colorimeter approach are:<br>
+ <br>
+ * The scanner dynamic range and/or precision may not match the
+ printers or what is required for a good profile.<br>
+ * The spectral interaction of the scanner test chart and printer
+ test chart with the scanner spectral response can cause color
+ errors.<br>
+ * Spectral differences caused by different black amounts in the
+ print test chart can cause color errors. <br>
+ * The scanner reference chart gamut may be much smaller than the
+ printers gamut, making the scanner profile too inaccurate to be
+ useful. <br>
+ <br>
+ As well as some of the above, a camera may not be suitable if it
+ automatically adjusts exposure or white point when taking a picture,
+ and this behavior cannot be disabled.<br>
+ <br>
+ The end result is often a profile that has a noticeable color cast,
+ compared to a profile created using a colorimeter or spectrometer.<br>
+ <br>
+ <br>
+ It is assumed that you have created a scanner or camera profile
+ following the <a
+ href="http://www.argyllcms.com/doc/Scenarios.html#PS1">procedure</a>
+ outline above. For best possible results it is advisable to both
+ profile the scanner or camera, and use it in scanning the printed
+ test chart, in as "raw" mode as possible (i.e. using 16 bits per
+ component images, if the scanner or camera is capable of doing so;
+ not setting white or black points, using a fixed exposure etc.). It
+ is generally advisable to create a LUT type input profile, and use
+ the <a href="http://www.argyllcms.com/doc/colprof.html#u">-u</a>
+ flag to avoid clipping scanned value whiter than the input
+ calibration chart.<br>
+ <br>
+ Scan or photograph your printer chart (or charts) on the scanner or
+ camera previously profiled. <big><span style="font-weight: bold;">The
+
+
+
+
+
+
+
+
+ scanner or camera must be configured and used exactly the same
+ as it was when it was profiled.</span></big><br>
+ <br>
+ I will assume the resulting scan/photo input file is called <span
+ style="font-weight: bold;">PrinterB.tif</span> (or <span
+ style="font-weight: bold;">PrinterB1.tif</span>, <span
+ style="font-weight: bold;">PrinterB2.tif</span> etc. in the case
+ of multiple charts). As with profiling the scanner or camera, the
+ raster file need only be roughly cropped so as to contain the test
+ chart.<br>
+ <br>
+ The scanner recognition files created when <span
+ style="font-weight: bold;">printtarg</span> was run is assumed to
+ be called <span style="font-weight: bold;">PrinterB.cht</span>.
+ Using the scanner profile created previously (assumed to be called <span
+ style="font-weight: bold;">scanner.icm</span>), the printer test
+ chart scan patches are converted to CIE values using the <span
+ style="font-weight: bold;">scanin</span> tool:<br>
+ <br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB.tif</a>
+ <a href="scanin.html#cp2">PrinterB.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <br>
+ If there were multiple test chart pages, the results would be
+ accumulated page by page using the <a href="scanin.html#ca">-ca</a>
+ option, ie., if there were 3 pages:<br>
+ <br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#c">-c</a> <a href="scanin.html#cp1">PrinterB1.tif</a>
+ <a href="scanin.html#cp2">PrinterB1.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB2.tif</a>
+ <a href="scanin.html#cp2">PrinterB2.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <a href="scanin.html">scanin</a> <a href="scanin.html#v">-v</a> <a
+ href="scanin.html#ca">-ca</a> <a href="scanin.html#cp1">PrinterB3.tif</a>
+ <a href="scanin.html#cp2">PrinterB3.cht</a> <a
+ href="scanin.html#cp3">scanner.icm</a> <a href="scanin.html#cp4">PrinterB</a><br>
+ <br>
+ Now that the <span style="font-weight: bold;">PrinterB.ti3</span>
+ data has been obtained, the profile continue in the next section
+ with <span style="font-weight: bold;">Creating a printer profile</span>.<br>
+ <br>
+ If you have any doubts about the correctness of the chart
+ recognition, or the subsequent profile's delta E report is unusual,
+ then use the scanin diagnostic flags <a href="scanin.html#d">-dipn</a>
+ and examine the <span style="font-weight: bold;">diag.tif</span>
+ diagnostic file.<br>
+ <h4><a name="PP5"></a>Creating a printer profile<br>
+ </h4>
+ Creating an RGB based printing profile is very similar to creating a
+ display device profile. For a CMYK printer, some additional
+ information is needed to set the black generation.<br>
+ <br>
+ Where the resulting profile will be used conventionally (ie. using <a
+ href="collink.html">collink</a> <a href="collink.html#s">-s</a>,
+ or <a href="cctiff.html">cctiff</a> or most other "dumb" CMMs) it
+ is important to specify that gamut mapping should be computed for
+ the output (B2A) perceptual and saturation tables. This is done by
+ specifying a device profile as the parameter to the <a
+ href="colprof.html">colprof</a> <a href="colprof.html#S">-S</a>
+ flag. When you intend to create a "general use" profile, it can be a
+ good technique to specify the source gamut as the opposite type of
+ profile to that being created, i.e. if a printer profile is being
+ created, specify a display profile (e.g. sRGB) as the source gamut.
+ If a display profile is being created, then specify a printer
+ profile as the source (e.g. Figra, SWOP etc.).&nbsp; When linking to
+ the profile you have created this way as the output profile, then
+ use perceptual intent if the source is the opposite type, and
+ relative colorimetric if it is the same type.<br>
+ <br>
+ "Opposite type of profile" refers to the native gamut of the device,
+ and what its fundamental nature is, additive or subtractive. An
+ emissive display will have additive primaries (R, G &amp; B), while
+ a reflective print, will have subtractive primaries (C, M, Y &amp;
+ possibly others), irrespective of what colorspace the printer is
+ driven in (a printer might present an RGB interface, but internally
+ this will be converted to CMY, and it will have a CMY type of
+ gamut).&nbsp; Because of the complimentary nature of additive and
+ subtractive device primary colorants, these types of devices have
+ the most different gamuts, and hence need the most gamut mapping to
+ convert from one colorspace to the other.<br>
+ <br>
+ If you are creating a profile for a specific purpose, intending to
+ link it to a specific input profile, then you will get the best
+ results by specifying that source profile as the source gamut.<br>
+ <br>
+ If a profile is only going to be used as an input profile, or is
+ going to be used with a "smart" CMM (e.g. <a href="collink.html">collink</a>
+ <a href="collink.html#g">-g</a> or <a href="collink.html#G">-G</a>),
+then
+
+
+
+
+
+
+
+
+ it can save considerable processing time and space if the -b flag is
+ used, and the -S flag not used.<br>
+ <br>
+ For an RGB printer intended to print RGB originals, the following
+ might be a typical profile usage:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
+ <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#p1">PrinterA</a><br>
+ <br>
+ or if you intent to print from Fogra, SWOP or other standard CMYK
+ style originals:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer A"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S">
+ fogra39l.icm</a> <a href="colprof.html#c">-cmt</a> <a
+ href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterA</a><br>
+ <br>
+ If you know what colorspace your originals are in, use that as the
+ argument to <span style="font-weight: bold;">-S</span>.<br>
+ <br>
+ <h4><a name="PP6"></a>Choosing a black generation curve (and other
+ CMYK printer options)<br>
+ </h4>
+ For a CMYK printer, it would be normal to specify the type of black
+ generation, either as something simple, or as a specific curve. The
+ documentation&nbsp; in <a href="colprof.html#k">colprof</a> for the
+ details of the options.<span style="font-weight: bold;"><br>
+ <br>
+ Note</span> that making a good choice of black generation curve
+ can affect things such as: how robust neutrals are given printer
+ drift or changes in viewing lighting, how visible screening is, and
+ how smooth looking the B2A conversion is.<br>
+ <br>
+ For instance, maximizing the level of K will mean that the neutral
+ colors are composed of greater amounts of Black ink, and black ink
+ retains its neutral appearance irrespective of printer behavior or
+ the spectrum of the illuminant used to view the print. On the other
+ hand, output which is dominantly from one of the color channels will
+ tend to emphasize the screening pattern and any unevenness (banding
+ etc.) of that channel, and the black channel in particular has the
+ highest visibility. So in practice, some balance between the levels
+ of the four channels is probably best, with more K if the screening
+ is fine and a robust neutral balance is important, or less K if the
+ screening is more visible and neutral balance is less critical. The
+ levels of K at the edges of the gamut of the device will be fixed by
+ the nature of the ink combinations that maximize the gamut (ie.
+ typically zero ink for light chromatic colors, some combination for
+ dark colors, and a high level of black for very dark near neutrals),
+ and it is also usually important to set a curve that smoothly
+ transitions to the K values at the gamut edges. Dramatic changes in
+ K imply equally dramatic changes in CMY, and these abrupt
+ transitions will reveal the limited precision and detail that can be
+ captured in a lookup table based profile, often resulting in a
+ "bumpy" looking output.<br>
+ <br>
+ If you want to experiment with the various black generation
+ parameters, then it might be a good idea to create a preliminary
+ profile (using <a href="colprof.html#q">-ql</a> <a
+ href="colprof.html#b">-b</a> <a href="colprof.html#ni">-no</a>, <a
+ href="colprof.html#no">-ni</a> and no <a href="colprof.html#S">-S</a>),
+
+
+
+
+
+
+
+ and then used <a href="xicclu.html#g">xicclu</a> to explore the
+ effect of the parameters.<br>
+ <br>
+ For instance, say we have our CMYK .ti3 file <span
+ style="font-weight: bold;">PrinterB.ti3</span>. First we make a
+ preliminary profile called <span style="font-weight: bold;">PrinterBt</span>:<br>
+ <br>
+ copy PrinterB.ti3 PrinterBt.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (Use
+ "cp" on Linux or OSX of course.)<br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#q">-qm</a> <a href="colprof.html#b">-b</a> <a
+ href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#p1">PrinterBt</a><br>
+ <br>
+ Then see what the minimum black level down the neutral axis can be.
+ Note that we need to also set any ink limits we've decided on as
+ well (coloprof defaulting to 10% less than the value recorded in the
+ .ti3 file). In this example the test chart has a 300% total ink
+ limit, and we've decided to use 290%:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kz</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ Which might be a graph something like this:<br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with minimum K"
+ src="Kgraph1.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ Note&nbsp; how the minimum black is zero up to 93% of the
+ white-&gt;black L* curve, and then jumps up to 87%. This is because
+ we've reached the total ink limit, and K then has to be substituted
+ for CMY, to keep the total under the total ink limit.<br>
+ <br>
+ Then let's see what the maximum black level down the neutral axis
+ can be:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kx</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ Which might be a graph something like this:<br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with maximum K"
+ src="Kgraph2.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ Note how the CMY values are fairly low up to 93% of the
+ white-&gt;black L* curve (the low levels of CMY are helping set the
+ neutral color), and then they jump up. This is because we've reach
+ the point where black on it's own, isn't as dark as the color that
+ can be achieved using CMY and K. Because the K has a dominant effect
+ on the hue of the black, the levels of CMY are often fairly volatile
+ in this region.<br>
+ <br>
+ Any K curve we specify must lie between the black curves of the
+ above two graphs.<br>
+ <br>
+ Let's say we'd like to chose a moderate black curve, one that aims
+ for about equal levels of CMY and K. We should also aim for it to be
+ fairly smooth, since this will minimize visual artefacts caused by
+ the limited fidelity that profile LUT tables are able to represent
+ inside the profile.<br>
+ <br>
+ <img style="width: 340px; height: 258px;" alt="-k parameters"
+ src="Kparams.jpg"><br>
+ <br>
+ <br>
+ For minimum discontinuities we should aim for the curve to finish at
+ the point it has to reach to satisfy the total ink limit at 87%
+ curve and 93% black. For a first try we can simply set a straight
+ line to that point: <br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp 0 0 .93 .87 1.0</a> <a
+ href="xicclu.html#l">-l290</a> <a href="xicclu.html#f">-fif</a> <a
+ href="xicclu.html#i">-ir</a> <a href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with kp 0 0 1.0 1.0 1.0 -l290"
+ src="Kgraph3.jpg" style="width: 250px; height: 250px;"><br>
+ <br>
+ The black "curve" hits the 93%/87% mark well, but is a bit too far
+ above CMY, so we'll try making the black curve concave:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 0.65</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img alt="Graph of CMYK neutral axis with -kp 0 .05 1 .9 1 -l290"
+ src="Kgraph4.jpg" style="width: 250px; height: 249px;"><br>
+ <br>
+ This looks just about perfect, so the the curve parameters can now
+ be used to generate our real profile:<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#k">-kp </a><a href="xicclu.html#k">0 0 .93
+ .87 0.65</a> <a href="colprof.html#S">-S</a><a
+ href="colprof.html#S"> sRGB.icm</a> <a href="colprof.html#c">-cmt</a>
+ <a href="colprof.html#d">-dpp</a> <a href="colprof.html#p1">PrinterB</a><br>
+ <br>
+ and the resulting B2A table black curve can be checked using xicclu:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#f">-fb</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterB.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph5.jpg"><br>
+ <br>
+ <br>
+ <hr style="margin-left: 0px; margin-right: auto; width: 20%; height:
+ 2px;"><br>
+ <span style="font-weight: bold;">Examples of other inkings:<br>
+ <br>
+ </span>A smoothed zero black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 .7 .93 .87
+ 1.0</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph6.jpg"><br>
+ <br>
+ A low black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 0.15</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph7.jpg"><br>
+ <br>
+ <br>
+ A high black inking:<br>
+ <br>
+ <a href="xicclu.html">xicclu</a> <a href="xicclu.html#g">-g</a> <a
+ href="xicclu.html#k">-kp </a><a href="xicclu.html#k">0 0 .93 .87
+ 1.2</a> <a href="xicclu.html#l">-l290</a> <a
+ href="xicclu.html#f">-fif</a> <a href="xicclu.html#i">-ir</a> <a
+ href="xicclu.html#p1">PrinterBt.icm</a><br>
+ <br>
+ <img style="width: 250px; height: 250px;" alt="sadsadas"
+ src="Kgraph8.jpg"><br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <h4>Overriding the ink limit<br>
+ </h4>
+ Normally the total ink limit will be read from the <span
+ style="font-weight: bold;">PrinterB.ti3</span> file, and will be
+ set at a level 10% lower than the number used in creating the test
+ chart values using <a href="targen.html#l">targen -l</a>. If you
+ want to override this with a lower limit, then use the <a
+ href="colprof.html#l">-l flag</a>.<br>
+ <br>
+ <a href="colprof.html">colprof</a> <a href="colprof.html#v">-v</a>
+ <a href="colprof.html#E">-D"Printer B"</a> <a href="colprof.html#q">-qm</a>
+ <a href="colprof.html#S">-S</a><a href="colprof.html#S"> sRGB.icm</a>
+ <a href="colprof.html#c">-cmt</a> <a href="colprof.html#d">-dpp</a>
+ <a href="colprof.html#k">-kr</a> <a href="xicclu.html#l">-l290</a>
+ <a href="colprof.html#p1">PrinterB</a><br>
+ <br>
+ Make sure you check the delta E report at the end of the profile
+ creation, to see if the profile is behaving reasonably.<br>
+ <br>
+ One way of checking that your ink limit is not too high, is to use "<span
+ style="font-weight: bold;">xicc -fif -ia</span>" to check, by
+ setting different ink limits using the <span style="font-weight:
+ bold;">-l</span> option, feeding Lab = 0 0 0 into it, and checking
+ the resulting&nbsp; black point. Starting with the ink limit used
+ with <span style="font-weight: bold;">targen</span> for the test
+ chart, reduce it until the black point starts to be affected. If it
+ is immediately affected by any reduction in the ink limit, then the
+ black point may be improved by increasing the ink limit used to
+ generate the test chart and then re-print and re-measuring it,
+ assuming other aspects such as wetness, smudging, spreading or
+ drying time are not an issue.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <h3><a name="PC1"></a>Calibrating Printers<br>
+ </h3>
+ <span style="font-weight: bold;">Profiling</span> creates a
+ description of how a device behaves, while <span
+ style="font-weight: bold;">calibration</span> on the other hand is
+ intended to <span style="text-decoration: underline;">change</span>
+ how a device behaves. Argyll has the ability to create per-channel
+ device space calibration curves for print devices, that can then be
+ used to improve the behavior of of the device, making a subsequent
+ profile fit the device more easily and also allow day to day
+ correction of device drift without resorting to a full re-profile.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE:</span> Because calibration
+ adds yet another layer to the way color is processed, it is
+ recommended that it not be attempted until the normal profiling
+ workflow is established, understood and verified.<br>
+ <h4><a name="PC2"></a>Calibrated print workflows</h4>
+ There are two main workflows that printer calibration curves can be
+ applied to:<br>
+ <br>
+ <span style="text-decoration: underline;">Workflow <span
+ style="font-weight: bold;">with</span> native calibration
+ capability</span>:<br>
+ <br>
+ Firstly the printer itself may have the capability of using per
+ channel calibration curves. In this situation, the calibration
+ process will be largely independent of profiling. Firstly the
+ printer is configured to have both its color management and
+ calibration disabled (the latter perhaps achieved by loading linear
+ calibration curves), and a print calibration test chart that
+ consists of per channel color wedges is printed. The calibration
+ chart is read and the resulting .ti3 file converted into calibration
+ curves by processing it using <span style="font-weight: bold;">printcal</span>.
+ The calibration is then installed into the printer. Subsequent
+ profiling will be performed on the <span style="text-decoration:
+ underline;">calibrated</span> printer (ie. the profile test chart
+ will have the calibration curves applied to it by the printer, and
+ the resulting ICC profile will represent the behavior of the
+ calibrated printer.)<br>
+ <br>
+ <span style="text-decoration: underline;">Workflow <span
+ style="font-weight: bold;">without</span> native calibration
+ capability</span>:<br>
+ <br>
+ The second workflow is one in which the printer has no calibration
+ capability itself. In this situation, the calibration process will
+ have to be applied using the ICC color management tools, so careful
+ coordination with profiling is needed. Firstly the printer is
+ configured to have its color management disabled, and a print
+ calibration test chart that consists of per channel color wedges is
+ printed. The calibration chart is converted into calibration curves
+ by reading it and then processing the resultant .ti3 using <span
+ style="font-weight: bold;">printcal</span>,. During the subsequent
+ <span style="text-decoration: underline;">profiling</span>, the
+ calibration curves will need to be applied to the profile test chart
+ in the process of using <span style="font-weight: bold;">printtarg</span>.
+ Once the the profile has been created, then in subsequent printing
+ the calibration curves will need to be applied to an image being
+ printed either explicitly when using <span style="font-weight:
+ bold;">cctiff</span> to apply color profiles <span
+ style="text-decoration: underline;">and</span> calibration, <span
+ style="font-weight: bold;">OR</span> by creating a version of the
+ profile that has had the calibration curves incorporated into it
+ using the <span style="font-weight: bold;">applycal</span> tool.
+ The latter is useful when some CMM (color management module) other
+ than <span style="font-weight: bold;">cctiff </span>is being used.<br>
+ <br>
+ Once calibration aim targets for a particular device and mode
+ (screening, paper etc.) have been established, then the printer can
+ be re-calibrated at any time to bring its per channel behavior back
+ into line if it drifts, and the new calibration curves can be
+ installed into the printer, or re-incorporated into the profile.
+ &nbsp;
+ <h4><a name="PC3"></a>Creating a print calibration test chart</h4>
+ The first step is to create a print calibration test chart. Since
+ calibration only creates per-channel curves, only single channel
+ step wedges are required for the chart. The main choice is the
+ number of steps in each wedge. For simple fast calibrations perhaps
+ as few as 20 steps per channel may be enough, but for a better
+ quality of calibration something like 50 or more steps would be a
+ better choice.<br>
+ <br>
+ Let's consider two devices in our examples, "PrinterA" which is an
+ "RGB" printer device, and "PrinterB" which is CMYK. In fact there is
+ no such thing as a real RGB printer, since printers use white media
+ and the colorant must subtract from the light reflected on it to
+ create color, but the printer itself turns the incoming RGB into the
+ native print colorspace, so for this reason we are careful to tell
+ targen to use the "Print RGB" colorspace, so that it knows to create
+ step wedges from media white to full colorant values.<br>
+ <br>
+ For instance, to create a 50 steps per channel calibration test
+ chart for our RGB and CMYK devices, the following would be
+ sufficient:<br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d2</a> <a href="targen.html#s">-s50</a>
+ <a href="targen.html#e">-e3</a> <a href="targen.html#f">-f0</a> <a
+ href="targen.html#p1">PrinterA_c</a><br>
+ <br>
+ <a href="targen.html">targen</a> <a href="targen.html#v">-v</a>
+ &nbsp;<a href="targen.html#d">-d4</a> <a href="targen.html#s">-s50</a>
+ <a href="targen.html#e">-e4</a> <a href="targen.html#f">-f0</a> <a
+ href="targen.html#p1">PrinterB_c</a><br>
+ <a href="targen.html#p1"></a><br>
+ For an outline of how to then print and read the resulting test
+ chart, see&nbsp; <a href="Scenarios.html#PP2b">Printing a print
+ profile test chart</a>, and <a href="Scenarios.html#PP3">Reading
+ a print test chart using an instrument</a>. Note that the printer
+ must be in an un-profiled and un-calibrated mode when doing this
+ print. Having done this, there will be a PrinterA.ti3 or
+ PrinterB.ti3 file containing the step wedge calibration chart
+ readings.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you are
+ calibrating a raw printer driver, and there is considerable dot
+ gain, then you may want to use the <a href="targen.html#p">-p</a>
+ parameter to adjust the test chart point distribution to spread them
+ more evenly in perceptual space, giving more accurate control over
+ the calibration. Typically this will be a value greater than one for
+ a device that has dot gain, e.g. values of 1.5, 2.0 or 2.5 might be
+ good places to start. You can do a preliminary calibration and use
+ the verbose output of printcal to recommend a suitable value for <span
+ style="font-weight: bold;">-p</span>.<br>
+ <h4><a name="PC4"></a>Creating a printer calibration<br>
+ </h4>
+ The <a href="printcal.html">printcal</a> tool turns a calibration
+ chart <a href="File_Formats.html#.ti3">.ti3</a> file into a <a
+ href="File_Formats.html#.cal">.cal</a> file. It has three main
+ operating modes:- Initial calibration, Re-Calibration, and
+ Verification. (A fourth mode, "Imitation" is very like Initial
+ Calibration, but is used for establishing a calibration target that
+ a similar printer can attempt to imitate.)<br>
+ <br>
+ The distinction between Initial Calibration and Re-Calibration is
+ that in the initial calibration we establish the "aim points" or
+ response we want out of the printer after calibration. There are
+ three basic parameters to set this for each channel: Maximum level,
+ minimum level, and curve shape.<br>
+ <br>
+ By default the maximum level will be set using a heuristic which
+ attempts to pick the point when there is diminishing returns for
+ applying more colorant. This can be overridden using the <span
+ style="font-weight: bold;">-x# percent</span> option, where <span
+ style="font-weight: bold;">#</span> represents the choice of
+ channel this will be applied to. The parameter is the percentage of
+ device maximum. <br>
+ <br>
+ The minimum level defaults to 0, but can be overridden using the <span
+ style="font-weight: bold;">-n# deltaE</span> option. A minimum of
+ 0 means that zero colorant will correspond to the natural media
+ color, but it may be desirable to set a non-pure media color using
+ calibration for the purposes of emulating some other media. The
+ parameter is in Delta E units.<br>
+ <br>
+ The curve shape defaults to being perceptually uniform, which means
+ that even steps of calibrated device value result in perceptually
+ even color steps. In some situations it may be desirable to alter
+ this curve (for instance when non color managed output needs to be
+ sent to the calibrated printer), and a simple curve shape target can
+ be set using the <span style="font-weight: bold;">-t# percent</span>
+ parameter. This affects the output value at 50% input value, and
+ represents the percentage of perceptual output. By default it is 50%
+ perceptual output for 50% device input.<br>
+ <br>
+ Once a device has been calibrated, it can be re-calibrated to the
+ same aim target.<br>
+ <br>
+ Verification uses a calibration test chart printed through the
+ calibration, and compares the achieved response to the aim target.<br>
+ <br>
+ The simplest possible way of creating the <span style="font-weight:
+ bold;">PrinterA.cal</span> file is:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterA_c</a><br>
+ <br>
+ For more detailed information, you can add the <span
+ style="font-weight: bold;">-v</span> and <span
+ style="font-weight: bold;">-p</span> flags:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#p2">PrinterB_c</a><br>
+ <br>
+ (You will need to select the plot window and hit a key to advance
+ past each plot).<br>
+ <br>
+ For re-calibration, the name of the previous calibration file will
+ need to be supplied, and a new calibration<br>
+ file will be created:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#r">-r</a> <a href="colprof.html#p1">PrinterB_c_old</a>
+ <a href="colprof.html#p2">PrinterB_c_new</a><br>
+ <br>
+ Various aim points are normally set automatically by <span
+ style="font-weight: bold;">printcal</span>, but these can be
+ overridden using the <a href="colprof.html#x">-x</a>, <a
+ href="colprof.html#n">-n</a> and <a href="colprof.html#t">-t</a>
+ options. e.g. say we wanted to set the maximum ink for Cyan to 80%
+ and Black to 95%, we might use:<br>
+ <br>
+ &nbsp; <a href="printcal.html">printcal</a> <a
+ href="printcal.html#v">-v</a> <a href="printcal.html#p">-p</a> <a
+ href="printcal.html#i">-i</a> <a href="colprof.html#x">-xc 80</a>
+ <a href="colprof.html#x">-xk 95</a> <a href="colprof.html#p2">PrinterB_c</a><br>
+ <br>
+ <a href="colprof.html#p2"></a>
+ <h4><a name="PC5"></a>Using a printer calibration</h4>
+ The resulting calibration curves can be used with the following
+ other Argyll tools:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="printtarg.html#K">printtarg</a>&nbsp;&nbsp;&nbsp;&nbsp;
+To
+apply
+calibration
+to
+a
+profile
+test
+chart,
+
+
+
+
+
+
+
+
+ and/or to have it included in .ti3 file.<br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html#p2">cctiff</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+To
+apply
+color
+management
+and
+calibration
+to
+an
+
+
+
+
+
+
+
+
+ image file.<br>
+ &nbsp;&nbsp;&nbsp; <a href="applycal.html#p1">applycal</a>&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+ To incorporate calibration into an ICC profile.<br>
+ &nbsp;&nbsp;&nbsp; <a href="chartread.html#I">chartread</a>&nbsp;&nbsp;
+To
+override
+the
+calibration
+assumed
+when
+reading
+a
+
+
+
+
+
+
+
+
+ profile chart.<br>
+ <br>
+ <br>
+ In a workflow <span style="font-weight: bold;">with</span> native
+ calibration capability, the calibration curves would be used with
+ printarg during subsequent <span style="font-weight: bold;">profiling</span>
+ so that any ink limit calculations will reflect final device values,
+ while not otherwise using the calibration within the ICC workflow:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
+ href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
+ <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#I">-I
+ PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <br>
+ This will cause the .ti2 and resulting .ti3 and ICC profiles to
+ contain the calibration curves, allowing all the tools to be able to
+ compute final device value ink limits. The calibration curves must
+ also of course be installed into the printer. The means to do this
+ is currently outside the scope of Argyll (ie. either the print
+ system needs to be able to understand Argyll CAL format files, or
+ some tool will be needed to convert Argyll CAL files into the
+ printer calibration format).<br>
+ <br>
+ <br>
+ In a workflow <span style="font-weight: bold;">without</span>
+ native calibration capability, the calibration curves would be used
+ with printarg to <span style="text-decoration: underline;">apply</span>
+ the calibration to the test patch samples during subsequent <span
+ style="font-weight: bold;">profiling</span>, as well as embedding
+ it in the resulting .ti3 to allow all the tools to be able to
+ compute final device value ink limits:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="printtarg.html">printtarg</a> <a
+ href="printtarg.html#v">-v</a> <a href="printtarg.html#i">-ii1</a>
+ <a href="printtarg.html#p">-pA4</a> <a href="printtarg.html#K">-K
+ PrinterA_c.cal</a> <a href="printtarg.html#p1">PrinterA</a><br>
+ <a href="cctiff.html#p4"></a><br>
+ To apply calibration to an ICC profile, so that a calibration
+ unaware CMM can be used:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="applycal.html">applycal</a> <a
+ href="applycal.html#p1">PrinterA.cal</a> <a
+ href="applycal.html#p2">PrinterA.icm</a> <a
+ href="applycal.html#p3">PrinterA_cal.icm</a><br>
+ <br>
+ To apply color management and calibration to a raster image:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">Source2Destination.icm</a> <a
+ href="cctiff.html#p2">PrinterA_c.cal</a> <a href="cctiff.html#p3">infile.tif</a>
+ <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; <a href="cctiff.html">cctiff</a> <a
+ href="cctiff.html#p1">Source2Destination.icm</a> <a
+ href="cctiff.html#p2">PrinterA_c.cal</a> <a href="cctiff.html#p3">infile.jpg</a>
+ <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <br>
+ <br>
+ Another useful tool is <a href="synthcal.html">synthcal</a>, that
+ allows creating linear or synthetic calibration files for disabling
+ calibration or testing.<br>
+ Similarly, <a href="fakeread.html">fakeread</a> also supports
+ applying calibration curves and embedding them in the resulting .ti3
+ file<br>
+ <h4><a name="PC6"></a>How profile ink limits are handled when
+ calibration is being used.</h4>
+ Even though the profiling process is carried out on top of the
+ linearized device, and the profiling is generally unaware of the
+ underlying non-linearized device values, an exception is made in the
+ calculation of ink limits during profiling. This is made possible by
+ including the calibration curves in the profile charts .ti2 and
+ subsequent .ti3 file and resulting ICC profile <span
+ style="font-weight: bold;">'targ'</span> text tag, by way of the <span
+ style="font-weight: bold;">printtarg</span> <span
+ style="font-weight: bold;">-I</span> or <span style="font-weight:
+ bold;">-K</span> options. This is done on the assumption that the
+ physical quantity of ink is what's important in setting the ink
+ limit, and that the underlying non-linearized device values
+ represent such a physical quantity.<br>
+ <br>
+ <br>
+ <hr size="2" width="100%">
+ <h3><a name="LP1"></a>Linking Profiles</h3>
+ Two device profiles can be linked together to create a device link
+ profile, than encapsulates a particular device to device transform.
+ Often this step is not necessary, as many systems and tools will
+ link two device profiles "on the fly", but creating a device link
+ profile gives you the option of using "smart CMM" techniques, such
+ as true gamut mapping, improved inverse transform accuracy, tailored
+ black generation and ink limiting.<br>
+ <br>
+ The overall process is to link the input space and output space
+ profiles using <a href="collink.html">collink</a>, creating a
+ device to device link profile. The device to device link profile can
+ then be used by cctiff (or other ICC device profile capable tools),
+ to color correct a raster files.<br>
+ <br>
+ Three examples will be given here, showing the three different modes
+ than <span style="font-weight: bold;">collink</span> supports.<br>
+ <br>
+ In <a href="collink.html#s">simple mode</a>, the two profiles are
+ linked together in a similar fashion to other <span
+ style="font-weight: bold;">CMMs</span> simply using the forward
+ and backwards color transforms defined by the profiles. Any gamut
+ mapping is determined by the content of the tables within the two
+ profiles, together with the particular intent chosen. Typically the
+ same intent will be used for both the source and destination
+ profile:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#s">-s</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#so">-op</a>
+ <a href="collink.html#p1">SouceProfile.icm</a> <a
+ href="collink.html#p2">DestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ <br>
+ In <a href="collink.html#g">gamut mapping mode</a>, the
+ pre-computed intent mappings inside the profiles are not used, but
+ instead the gamut mapping between source and destination is tailored
+ to the specific gamuts of the two profiles, and the intent parameter
+ supplied to <span style="font-weight: bold;">collink</span>.
+ Additionally, source and destination viewing conditions should be
+ provided, to allow the color appearance space conversion to work as
+ intended. The colorimetric B2A table in the destination profile is
+ used, and this will determine any black generation and ink limiting:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#g">-g</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">DestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ <br>
+ In <a href="collink.html#G">inverse output table gamut mapping mode</a>,
+ the pre-computed intent mappings inside the profiles are not used,
+ but instead the gamut mapping between source and destination is
+ tailored to the specific gamuts of the two profiles, and the intent
+ parameter supplied to <span style="font-weight: bold;">collink</span>.
+ In addition, the B2A table is <span style="font-weight: bold;">not</span>
+ used in the destination profile, but the A2B table is instead
+ inverted, leading to improved transform accuracy, and in CMYK
+ devices, allowing the ink limiting and black generation parameters
+ to be set:<br>
+ <br>
+ For a CLUT table based RGB printer destination profile, the
+ following would be appropriate:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">RGBDestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ For a CMYK profile, the total ink limit needs to be specified (a
+ typical value being 10% less than the value used in creating the
+ device test chart), and the type of black generation also needs to
+ be specified:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ip</a> <a href="collink.html#c">-cmt</a>
+ <a href="collink.html#d">-dpp</a> <a href="collink.html#l">-l250</a>
+ <a href="collink.html#k">-kr</a> <a href="collink.html#p1">MonitorSouceProfile.icm</a>
+ <a href="collink.html#p2">CMYKDestinationProfile.icm</a> <a
+ href="collink.html#p3">Source2Destination.icm</a><br>
+ <br>
+ Note that you should set the source (<a href="collink.html#c">-c</a>)
+ and destination (<a href="collink.html#d">-d</a>) viewing conditions
+ for the type of device the profile represents, and the conditions
+ under which it will be viewed.<br>
+ <br>
+ <h3><a name="LP2"></a>Soft Proofing Link</h3>
+ Often it is desirable to get an idea what a particular devices
+ output will look like using a different device. Typically this might
+ be trying to evaluate print output using a display. Often it is
+ sufficient to use an absolute or relative colorimetric transform
+ from the print device space to the display space, but while these
+ provide a colorimetric preview of the result, they do not take into
+ account the subjective appearance differences due to the different
+ device conditions. It can therefore be useful to create a soft proof
+ appearance transform using collink:<br>
+ <br>
+ <a href="collink.html">collink</a> <a href="collink.html#v">-v</a>
+ <a href="collink.html#q">-qm</a> <a href="collink.html#G">-G</a> <a
+ href="collink.html#si">-ila</a> <a href="collink.html#c">-cpp</a>
+ <a href="collink.html#d">-dmt</a> <a href="collink.html#l">-t250</a>&nbsp;<a
+ href="collink.html#k"></a><a href="collink.html#p1">CMYKDestinationProfile.icm</a>
+ <a href="collink.html#p2">MonitorProfile.icm</a> <a
+ href="collink.html#p3">SoftProof.icm</a><br>
+ <br>
+ We use the Luminance matched appearance intent, to preserve the
+ subjective apperance of the target device, which takes into account
+ the viewing conditions and assumes adaptation to the differences in
+ the luminence range, but otherwise not attempting to compress or
+ change the gamut.<br>
+ &nbsp;
+ <hr size="2" width="100%"><br>
+ <h3><a name="TR1"></a>Transforming colorspaces of raster files</h3>
+ Although a device profile or device link profile may be useful with
+ other programs and systems, Argyll provides the tool <a
+ href="cctiff.html">cctiff</a> for directly applying a device to
+ device transform to a <a href="File_Formats.html#TIFF">TIFF</a> or
+ <a href="File_Formats.html#JPEG">JPEG</a> raster file. The cctiff
+ tool is capable of linking an arbitrary sequence of device profiles,
+ device links, abstract profiles and calibration curves. Each device
+ profile can be preceded by the <span style="font-weight: bold;">-i</span>
+ option to indicate the intent that should be used. Both 8 and 16 bit
+ per component files can be handled, and up to 8 color channels. The
+ color transform is optimized to perform the overall transformation
+ rapidly.<br>
+ <br>
+ If a device link is to be used, the following is a typical example:<br>
+ <br>
+ <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ <a href="cctiff.html">cctiff</a> <a href="cctiff.html#p1">Source2Destination.icm</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <br>
+ <i><br>
+ </i>If a source and destination profile are to be used, the
+ following would be a typical example:<br>
+ <br>
+ <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
+ <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
+ href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
+ <a href="cctiff.html#p3">infile.tif</a> <a href="cctiff.html#p4">outfile.tif</a><br>
+ or<br>
+ <a href="cctiff.html"> cctiff</a>&nbsp; <a href="cctiff.html#i">-ip</a>
+ <a href="cctiff.html#p1i">SourceProfile.icm</a> <a
+ href="cctiff.html#i">-ip</a> <a href="cctiff.html#p1o">DestinationProfile.icm</a>
+ <a href="cctiff.html#p3">infile.jpg</a> <a href="cctiff.html#p4">outfile.jpg</a><br>
+ <br>
+ <br>
+ <hr size="2" width="100%"><br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/Smile.jpg b/doc/Smile.jpg
new file mode 100644
index 0000000..66a6b00
--- /dev/null
+++ b/doc/Smile.jpg
Binary files differ
diff --git a/doc/Source.html b/doc/Source.html
new file mode 100644
index 0000000..5ea423e
--- /dev/null
+++ b/doc/Source.html
@@ -0,0 +1,219 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Argyll Overview</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+</head>
+<body>
+<h2><u>Source Code Documentation</u></h2>
+Some general comments about how different software works.<br>
+<br>
+<b>TARGET</b><br>
+<br>
+&nbsp;Nearly all current Color correction systems generate test charts
+(or device characterization target charts) by laying out a regular
+rectangular grid of test points in device space (Targen will do this if
+you feed it a non-zero <span style="font-weight: bold;">-m</span>
+option). On some consideration, this approach is far from optimal. Not
+only is a regular grid inefficient in packing the multidimensional
+device space but if the points are spaced evenly in device space, they
+will probably not be optimal in determining the underlying device
+characteristic, sampling too finely where the device behavior is
+smooth, and too coarsely where the device behavior changes rapidly.
+Some commercial color systems tackle
+the latter problem by "pre-linearizing" the device, which amounts to
+distorting
+the regular device space grid points with a perceptual inverse per
+device
+channel lookup curve.<br>
+<br>
+The approach I have taken with Argyll, is a little different. Both a
+device independent and device dependent approach are available. In the
+device independent mode, test points are distributed so as to minimize
+the distance from any point in the device space to the nearest test
+chart value. When the device dependent approach is used, test points
+are chosen so as to minimize the expected error between the resulting
+profile and the underlying device response.<br>
+<br>
+For higher dimensional spaces, where the aim is to create a more
+approximate device profile, I've used an "incremental far point" point
+generator, that starting with a previous test point as a seed, use a
+minimization algorithm to locate another point that is as far as
+possible from the nearest existing test point in perceptual space,
+while remaining in gamut at all tines. This means that ideally each
+point "fills in" the gaps in the existing distribution.<br>
+<br>
+Another issue with laying test points out in regular grids, is that
+this means that the device response is poorly sampled (since the grids
+are usually coarse), and this can make it impossible to create detailed
+device linearisation "shaper" curves from the resulting data ! Ideally,
+in any colorspace (input or output), when viewed from any possible
+angle, none of the test data points should appear&nbsp; to line up. The
+Argyll target generator seems to achieve this goal.<br>
+<br>
+<br>
+target/printtarg.c:<br>
+<br>
+printtarg simply generates a PostScript file containing the patches
+laid out for an Xrite DTP51/DTP41/SpectroScan. It allows them to be
+laid out on
+a choice of paper sizes, with the appropriate contrasting color spacers
+between
+each patch for the strip reading instruments. Unlike other charts,
+Argyll
+charts are generated as required, rather that being fixed. Also unlike
+most
+other strip reading charts, the spacers may colored, so that the
+density contrast
+ratio is guaranteed, even when two patches are about 50% density.<br>
+<br>
+Another feature is the pseudo random patch layout. This has three
+purposes. One is to try and average out any variation in the device
+response in relationship to the location of the patch on the paper.
+Color copiers and printing presses (for instance), are notorious in
+having side to side density variations.<br>
+<br>
+Another purpose of the random patch layout, is that it gives the
+reading program a good mechanism for detecting user error. It can guess
+the expected values, compare them to the readings, and complain if it
+seems that the strip is probably the wrong one.<br>
+<br>
+The final purpose of the random patch layout is to optimize the
+contrast
+between patches in a strip, to improve the robustness of the strip
+reading.
+Using this, small charts may be even be generated without any gaps
+between
+the test patches.<br>
+<b><br>
+RSPL</b><br>
+<br>
+A lot of core Argyll algorithms are bound up in the RSPL (Regular
+Spline) class. The RSPL class is closely related to the CLUT table
+structure used in the ICC profile format, and is a general purpose way
+of mapping one multi-dimensional value to another, using interpolation
+to reduce the mapping function to a manageable size.<br>
+Regular splines are not directly related to other types of splines, and
+do not generally suffer from the sort of "wiggles" and "overshoot"
+characteristic of other spline systems.<br>
+<br>
+The RSPL class adds three basic methods to the underlying data
+structure:<br>
+<br>
+1) Interpolation<br>
+<br>
+2) Creation from scattered data<br>
+<br>
+The regular spline implementation was inspired by the following
+technical reports:<br>
+<br>
+D.J. Bone, "Adaptive Multi-Dimensional Interpolation Using Regularized
+Linear Splines," Proc. SPIE Vol. 1902, p.243-253, Nonlinear Image
+Processing IV, Edward R. Dougherty; Jaakko T. Astola; Harold G.
+Longbotham;(Eds)(1993).<br>
+<br>
+D.J. Bone, "Adaptive Colour Printer Modeling using regularized linear
+splines," Proc. SPIE Vol. 1909, p. 104-115, Device-Independent Color
+Imaging and Imaging Systems Integration, Ricardo J. Motta; Hapet A.
+Berberian; Eds.(1993)<br>
+<br>
+Don Bone and Duncan Stevenson, "Modelling of Colour Hard Copy Devices
+Using Regularised Linear Splines," Proceedings of the APRS workshop on
+Colour Imaging and Applications, Canberra (1994)<br>
+<br>
+see &lt;http://www.cmis.csiro.au/Don.Bone/&gt;<br>
+<br>
+Also of interest was:<br>
+<br>
+"Discrete Smooth Interpolation", Jean-Laurent Mallet, ACM Transactions
+on Graphics, Volume 8, Number 2, April 1989, Pages 121-144.<br>
+<br>
+3) Inversion<br>
+<br>
+Simplex interpolation is normally done in Baricentric space, where
+there
+is one more baricentric coordinate than dimensions, and the sum of all
+the
+baricentric coordinates must be 1.<br>
+To simplify things, we work in a "Simplex parameter" space, in which
+there are only &lt;dimension&gt; parameters, and each directly
+corresponds with a cartesian coordinate, but the parameter order
+corresponds with the baricentric order.<br>
+For example, given cartesian coordinates D0, D1, D2 these should be
+sorted from smallest to largest, thereby choosing a particular simplex
+within a cube,
+and allowing a correspondence to the parameter coordinates, ie:<br>
+<br>
+D1 D0 D2&nbsp;&nbsp;&nbsp;&nbsp; Smallest -&gt; Largest cartesian sort<br>
+P2 P1 P0&nbsp;&nbsp;&nbsp;&nbsp; Corresponding Parameter coordinates
+(note reverse order!)<br>
+<br>
+B0 = P0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Conversion to Baricentric
+coordinates<br>
+B1 = P1 - P0<br>
+B2 = P2 - P1<br>
+B3 = 1&nbsp; - P2<br>
+<br>
+The vertex values directly correspond to Baricentric coordinates,<br>
+giving the usual interpolation equation of:<br>
+<br>
+&nbsp; VV0 * B0<br>
++ VV1 * B1<br>
++ VV2 * B2<br>
++ VV3 * B3<br>
+<br>
+where VVn is the vertex value for each of the 4 vertices of the simplex.<br>
+<br>
+Reversing the Parameter -&gt; Baricentric equations gives the<br>
+following interpolation equation using Parameter coordinates:<br>
+<br>
+&nbsp; VV0 - VV1 * P0<br>
++ VV1 - VV2 * P1<br>
++ VV2 - VV3 * P2<br>
++ VV3<br>
+<br>
+It is this which is used in rev.c for solving the reverse interpolation
+problem. Within a simplex, only linear algebra is needed to compute
+inverses. To deal with the 4D-&gt;3D nature of a CMYK profile, the SVD
+(Singular Value Decomposition) approach is used to solving a CMYK for a
+given CIE value, the result being the equation of the line of
+solutions. The lines from adjacent simplexes form a solution locus,
+that can be resolved into a single point solution once a black
+generation rule is applied.<br>
+<br>
+Outline of inversion processing:<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp; Basic function requirements:&nbsp; exact,
+auxil, locus, clip inversion.<br>
+&nbsp;&nbsp;&nbsp;&nbsp; Fwd cell - reverse cell list lookup<br>
+&nbsp;&nbsp;&nbsp;&nbsp; Basic layout di -&gt; fdi + auxils + ink limit<br>
+&nbsp;&nbsp;&nbsp;&nbsp; Basic search strategy<br>
+&nbsp;&nbsp;&nbsp;&nbsp; Sub Simplex decomposition &amp; properties<br>
+&nbsp;&nbsp;&nbsp;&nbsp; How each type of function finds solutions<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Sub-simplex dimensionality &amp;
+dof + target dim &amp; dof<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Linear algebra choices.<br>
+&nbsp;&nbsp;&nbsp;&nbsp; How final solutions are chosen<br>
+<b><br>
+XICC</b><br>
+<br>
+&nbsp;&nbsp;&nbsp; Profiling using concatenated shapers to augment thin
+plate splines for per channel curves.<br>
+<br>
+<b>IMDI</b><br>
+<br>
+This module generates C code routines which implement an integer
+multi-channel transform. The input values are read, passed through per
+channel lookup tables, a multi-dimensional interpolation table, and
+then a per channel output lookup table, before being written.<br>
+<br>
+<b> MPP<br>
+</b> <br>
+Outline model parameter optimization using slope accelerated error
+metric, and initial parameter speedup for adjacent spectral bands etc.<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/Spyd2.jpg b/doc/Spyd2.jpg
new file mode 100644
index 0000000..8f8eff5
--- /dev/null
+++ b/doc/Spyd2.jpg
Binary files differ
diff --git a/doc/Spyd3.jpg b/doc/Spyd3.jpg
new file mode 100644
index 0000000..e1ab16f
--- /dev/null
+++ b/doc/Spyd3.jpg
Binary files differ
diff --git a/doc/Spyd3x.jpg b/doc/Spyd3x.jpg
new file mode 100644
index 0000000..8916915
--- /dev/null
+++ b/doc/Spyd3x.jpg
Binary files differ
diff --git a/doc/Spyd4.jpg b/doc/Spyd4.jpg
new file mode 100644
index 0000000..0d1b1b6
--- /dev/null
+++ b/doc/Spyd4.jpg
Binary files differ
diff --git a/doc/SpyderChecker.jpg b/doc/SpyderChecker.jpg
new file mode 100644
index 0000000..e50a205
--- /dev/null
+++ b/doc/SpyderChecker.jpg
Binary files differ
diff --git a/doc/WideGamutColmters.html b/doc/WideGamutColmters.html
new file mode 100644
index 0000000..67a5817
--- /dev/null
+++ b/doc/WideGamutColmters.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Wide Gamut Displays &amp; Colorimeters</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ </head>
+ <body>
+ <h2 style="text-decoration: underline; font-weight: bold;">Wide
+ Gamut Displays and Colorimeters<br>
+ </h2>
+ With the introduction of more wide color gamut displays, many people
+ are finding that their Colorimeter instruments don't work so well on
+ them. Why is this, and what can be done about it ?<br>
+ <h3>What's the difference between a Colorimeter and a Spectrometer ?</h3>
+ Colorimeters and Spectrometers both have the same aim: to measure
+ tri-stimulus color values, but they go about this in two quite
+ different ways.<br>
+ <br>
+ A spectrometer breaks the captured light up into a narrow series of
+ wavelengths, measures the response at each of the wavelengths, and
+ then weights and sums each wavelength response by the Standard
+ Observer weighting curves, to arrive at the CIE XYZ tri-stimulus
+ values. Because a Spectrometer computes the Standard Observer
+ weightings in software, the accuracy of the curves is nearly
+ perfect, the primary errors being due to wavelength calibration
+ errors, spectrum calibration errors, and the quantised nature of the
+ discrete wavelength bands.<br>
+ <br>
+ A Colorimeter uses physical filters that approximate the Standard
+ Observer weighting curves to filter the captured light onto three
+ sensors, the sensor values then<br>
+ being measured, and then multiplied by a 3x3 calibration matrix to
+ arrive at the CIE XYZ tri-stimulus values. The main advantage of a
+ Colorimeter is its simplicity, which results in a lower cost
+ instrument. In theory it is also possible to make a Colorimeter that
+ cheaply captures more light by using larger sensors, but this
+ possibility is rarely exploited by low cost instruments. Also due to
+ cost constraints, the physical filters used in these instruments may
+ not be a very good match to the CIE Standard Observer weightings,
+ and if nothing were done about it, this would result&nbsp; in large
+ measurement errors. Because such Display Colorimeters are typically
+ used with additive, 3 colorant displays, it is possible to calibrate
+ these errors out for any particular display, and this is the purpose
+ of the 3x3 calibration matrix that is used by the instrument and/or
+ instrument drivers. Since the calibration depends on the spectral
+ characteristics of the display primaries, no single calibration
+ matrix will be perfect for all display technologies, and typically
+ the instruments will come with two matrices, one for "typical" CRT
+ (Cathode Ray Tube) type displays, and one for "typical" LCD (Liquid
+ Crystal) type displays. Each individual Colorimeter may have
+ slightly different filters to others of the same model, due to batch
+ variations in the filter material. If each Colorimeter is calibrated
+ against a reference instrument, then this source of error can also
+ be minimised.<br>
+ <h3>Why don't Colorimeters work so well on Wide Gamut displays ?</h3>
+ As explained above, due to the imperfect match between the
+ Colorimeter filters and CIE Standard Observer weighting curves,
+ Colorimeters have calibration matrices that are created for
+ "typical" CRT or LCD displays. A Wide Gamut display by its very
+ nature has primaries that have narrower spectral characteristics
+ than typical displays, and this spectral difference exacerbates the
+ approximations and errors in the Colorimeter filters.<br>
+ <br>
+ Since Spectrometers have mathematically computed weighting curves,
+ they are less sensitive to the spectral characteristics of the
+ display primary colors, and generally work better on Wide Gamut
+ displays.<br>
+ <h3>What can be done about this ?</h3>
+ There are three approaches to addressing this problem:<br>
+ <br>
+ One is to use a Spectrometer to measure Wide Gamut displays. Since
+ lower cost Spectrometers are now available (e.g. Color Munki
+ Design/Photo), this may be the best general solution, since a
+ Spectrometer offers a good deal more flexibility and display
+ technology independence than a Colorimeter. Spectrometers are more
+ expensive than colorimeters though, and typical low cost instruments
+ are not well compensated for temperature changes (making reliable
+ black measurement somewhat tricky), and may take longer, or be less
+ accurate at measuring low light levels than the best colorimeters.<br>
+ <br>
+ The second approach is to correct the Colorimeter for the specific
+ type of Wide Gamut Display. Often this is what has been done when a
+ Colorimeter ("Puck") is supplied with a Wide Gamut display :- the
+ 3x3 calibration matrix inside the Colorimeter will have been "tuned"
+ to match the display, or the Colorimeter driver or color management
+ software will include an additional 3x3 correction matrix for that
+ Colorimeter/Display combination.<br>
+ <br>
+ The third approach is to make a colorimeter that has filters that
+ are closer to the standard observer curves, reducing the calibration
+ needed for the instrument, and making it less dependent on the exact
+ type of display technology. The X-Rite i1 DisplayPro, Pantone
+ ColorMunki Display and possibly the Spyder 4 may have such an
+ improvement. <br>
+ <br>
+ Argyll V1.3.0 has a facility to create and apply a <a
+ href="File_Formats.html#.ccmx">correct matrix</a> to Colorimeter
+ measurements. To create the correction matrix, the display, the
+ Colorimeter and a reference Spectrometer are needed. (see <a
+ href="ccxxmake.html">ccxxmake</a>). The correction matrix can then
+ be used with the usual display measurement utilities (see <a
+ href="dispcal.html#X">dispcal</a>, <a href="dispread.html#X">dispread</a>
+ and <a href="spotread.html#X">spotread</a> -X option).<br>
+ <br>
+ Some recent colorimeters take a slightly different approach to
+ calibration, and rather than using pre-defined 3x3 calibration
+ matricies, they instead contain the spectral sensitivity curves for
+ each particular colorimeter (e.g. i1 DisplayPro and ColorMunki
+ Display, Spyder 4). It's then possible to create 3x3 calibration
+ matricies automatically for any display for which the spectral
+ characteristics are known. This makes it easy to tailor the
+ colorimeters measurements to a particular type of display without
+ having to cater for each colorimeter &amp; display combination. <a
+ href="ccxxmake.html">ccxxmake</a> also allows creation of these <a
+ href="File_Formats.html#.ccss">Colorimeter Calibration Spectral
+ Sample</a> files.<br>
+ <br>
+ </body>
+</html>
diff --git a/doc/YellowGreen.jpg b/doc/YellowGreen.jpg
new file mode 100644
index 0000000..16f637f
--- /dev/null
+++ b/doc/YellowGreen.jpg
Binary files differ
diff --git a/doc/afiles b/doc/afiles
new file mode 100644
index 0000000..b01b147
--- /dev/null
+++ b/doc/afiles
@@ -0,0 +1,179 @@
+afiles
+DocLicense.txt
+License.txt
+License2.txt
+License3.txt
+ArgyllDoc.html
+ChangesSummary.html
+ColorManagement.html
+cal_format.html
+Compiling.html
+Installing.html
+Installing_MSWindows.html
+Installing_OSX.html
+Installing_Linux.html
+File_Formats.html
+MinorTools.html
+Organisation.html
+Overview.html
+Limitations.html
+Performance.html
+Environment.html
+Scenarios.html
+FWA.html
+FWA_measure.jpg
+instruments.html
+ArgyllFlow.jpg
+ArgyllFlowThumb.jpg
+DTP20.jpg
+DTP22.jpg
+DTP41.jpg
+DTP51.jpg
+DTP92.jpg
+DTP94.jpg
+HCFR.jpg
+Huey.jpg
+Smile.jpg
+Spyd2.jpg
+Spyd3.jpg
+Spyd3x.jpg
+Spyd4.jpg
+i1d.jpg
+i1d3_1.jpg
+i1d3_2.jpg
+i1m.jpg
+i1p.jpg
+sl.jpg
+ss.jpg
+mox.jpg
+moxxr.jpg
+Chroma4.jpg
+ColorMunki.jpg
+ColorMunkiCreate.jpg
+i1pro2.jpg
+iccgamutmapping.html
+gamutmapping1.jpg
+monitorcontrols.html
+gamma.html
+calvschar.html
+WideGamutColmters.html
+CrushedDisplyBlacks.html
+i1proDriver.html
+i1proDriver.xls
+evalInputTargets.html
+YellowGreen.jpg
+srgbplot.gif
+Source.html
+average.html
+applycal.html
+cb2ti3.html
+cctiff.html
+cht_format.html
+dispwin.html
+dispcal.html
+dispread.html
+dispprofloc.html
+extracticc.html
+extractttag.html
+synthcal.html
+fakeCMY.html
+fakeread.html
+filmread.html
+filmtarg.html
+greytiff.html
+iccdump.html
+iccgamut.html
+illumread.html
+illumread_1.jpg
+illumread_2.jpg
+illumread_3.jpg
+illumread_4.jpg
+illumread_5.jpg
+illumread_6.jpg
+collink.html
+icclu.html
+kodak2ti3.html
+txt2ti3.html
+mppcheck.html
+mpplu.html
+mppprof.html
+chartread.html
+printtarg.html
+profcheck.html
+invprofcheck.html
+colprof.html
+printcal.html
+refine.html
+revfix.html
+scanin.html
+splitti3.html
+spec2cie.html
+specplot.html
+spotread.html
+synthread.html
+targen.html
+ti3_format.html
+tiffgamut.html
+timage.html
+cube.jpg
+surface.jpg
+LabSteps.jpg
+verify.html
+viewgam.html
+xicclu.html
+oeminst.html
+ucmm.html
+Q60.jpg
+DC.jpg
+SG.jpg
+SG_header.txt
+SG_footer.txt
+i1scan14.jpg
+HCT.jpg
+CMP_DT_003.jpg
+CMP_Digital_Target-3.jpg
+colorchecker.jpg
+SpyderChecker.jpg
+LSDC.jpg
+QPcard201.jpg
+QPcard202.jpg
+Kgraph1.jpg
+Kgraph2.jpg
+Kgraph3.jpg
+Kgraph4.jpg
+Kgraph5.jpg
+Kgraph6.jpg
+Kgraph7.jpg
+Kgraph8.jpg
+Kparams.jpg
+CRTspectrum.jpg
+Fluorescent.jpg
+HiResLaser.jpg
+ccxxmake.html
+ccmxs.html
+ccmxs/DTP-94_1964_10_Dell_2408W.ccmx
+ccmxs/DTP-94_1997_Shaw_Dell_2408W.ccmx
+ccmxs/DTP-94_Dell_2408W.ccmx
+ccmxs/DTP-94_Dell_U2410.ccmx
+ccmxs/EyeOne_Display_1_NEC1990SXi.ccmx
+ccmxs/EyeOne_Display_2_EIZO_S2233W.ccmx
+ccmxs/EyeOne_Display_2_NEC1990SXi.ccmx
+ccmxs/EyeOne_Display_LT_U2410_Standard_1931.ccmx
+ccmxs/EyeOne_Display_LT_U2410_Standard_1964.ccmx
+ccmxs/EyeOne_Display_LT_U2410_sRGB_1931.ccmx
+ccmxs/EyeOne_Display_LT_U2410_sRGB_1964.ccmx
+ccmxs/Huey_Acer_al2016w.ccmx
+ccmxs/Huey_Eizo_CG243.ccmx
+ccmxs/Huey_HP_compaq_6730s.ccmx
+ccmxs/Huey_HP_lp2475w.ccmx
+ccmxs/Huey_NEC1990SXi.ccmx
+ccmxs/Huey_NEC_Spectraview_241.ccmx
+ccmxs/NEC_EyeOne_Display_2_NEC2690WUXi2.ccmx
+ccmxs/Spyder2_EIZO_S2433W_standard_1931.ccmx
+ccmxs/Spyder2_EIZO_S2433W_standard_1964.ccmx
+ccmxs/Spyder3_EIZO_S2233_standard_1964.ccmx
+ccmxs/Spyder3_EIZO_S2243W_standard_1931.ccmx
+ccmxs/Spyder3_HP_LP2475w.ccmx
+ccmxs/Spyder3_NEC2690WUXi2.ccmx
+ccmxs/Spyder3_NEC_PA301W.ccmx
+
diff --git a/doc/applycal.html b/doc/applycal.html
new file mode 100644
index 0000000..5c5e661
--- /dev/null
+++ b/doc/applycal.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>applycal</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme W. Gill">
+ </head>
+ <body>
+ <h2><b>profile/applycal</b></h2>
+ <h3>Summary</h3>
+ Apply, re-apply or remove calibration curves to an ICC profile.<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">usage: applycal
+ [-options]
+ [calfile.cal] inprof.icm [outprof.icm]<br>
+ &nbsp;<a href="#v">-v</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose
+ mode<br>
+ &nbsp;<a href="#a">-a</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Apply
+ or re-apply calibration (default)<br>
+ &nbsp;<a href="#u">-u</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Remove
+ calibration<br>
+ &nbsp;<a href="#c">-c</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Check
+ calibration<br>
+ &nbsp;<a href="#p1">calfile.cal</a>&nbsp;&nbsp;&nbsp;&nbsp;
+ Calibration
+ file to apply<br>
+ &nbsp;<a href="#p2">inprof.icm</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ ICC
+ profile to read<br>
+ &nbsp;<a href="#p3">outprof.icm</a>&nbsp;&nbsp;&nbsp;&nbsp;
+ modified
+ ICC
+ profile to write</span></small><br>
+ <br>
+ <h3>Usage Details <br>
+ </h3>
+ <a name="v"></a> The <b>-v</b> flag makes applycal more verbose.<br>
+ <br>
+ <span style="font-weight: bold;"><a name="a"></a>-a</span> By
+ default
+ the <span style="font-weight: bold;">calfile.cal </span>is applied
+ or
+ re-applied to the <span style="font-weight: bold;">inprof.icm</span>,
+ and then written to <span style="font-weight: bold;">outprof.icm</span>.<br>
+ <br>
+ <span style="font-weight: bold;"><a name="u"></a>-u</span> This flag
+ causes any calibration applied to the <span style="font-weight:
+ bold;">inprof.icm</span>
+ to be remove, the profile being restored to its pre-calibrated
+ state,
+ and then written to <span style="font-weight: bold;">outprof.icm</span>.<br>
+ <br>
+ <span style="font-weight: bold;"><a name="c"></a>-c</span> This flag
+ checks the <span style="font-weight: bold;">inprof.icm</span> and
+ if
+ verbose is on, reports whether it has had calibration applied. It
+ will
+ return status 0 if it has not been applied, 1 if it has, and 2 on
+ error.<br>
+ <br>
+ <span style="font-weight: bold;"><a name="p1"></a>calfile.cal</span>&nbsp;
+must
+ be supplied if the calibration is being applied or re-applied.<br>
+ <br>
+ <span style="font-weight: bold;"><a name="p2"></a>inprof.icm</span>&nbsp;
+should
+ be the
+ path to the ICC profile that will have calibration applied,
+ re-applied
+ or removed. The appropriate extension should be used for the
+ platform, i.e. <span style="font-weight: bold;">icm</span> for
+ MSWindows, and <span style="font-weight: bold;">icc</span> for OS X
+ or
+ Unix/Linux.<br>
+ <br>
+ <span style="font-weight: bold;"><a name="p3"></a>outprof.icm</span>&nbsp;
+should
+ be the
+ path to the file that will be created to hold the modified ICC
+ profile.
+ The appropriate extension should be used for the
+ platform, i.e. <span style="font-weight: bold;">icm</span> for
+ MSWindows, and <span style="font-weight: bold;">icc</span> for OS X
+ or
+ Unix/Linux.<br>
+ <br>
+ <h3>Discussion</h3>
+ <span style="font-weight: bold;">Applycal</span> provides a means of
+ using per channel calibration on devices and systems that don't
+ explicitly support such calibration. Once a calibration has been
+ created for a device (see <a href="printcal.html">printcal</a>), it
+ needs to be then used for all subsequent profiling and printing. If
+ the
+ printing device, display or system doesn't explicitly support the
+ use of
+ calibration, then the calibration can be applied during the printing
+ of
+ profile test charts using <a href="printtarg.html#K">printtarg -K</a>,
+ or the reading of a display target using dispread -K, and then for
+ processing imagery using <a href="cctiff.html">cctiff</a>
+ or by modifying the device ICC profiles using <span
+ style="font-weight: bold;">applycal</span>.<br>
+ <br>
+ <span style="font-weight: bold;">Applycal</span> modifies the
+ appropriate input or output per-channel curves of the profile to
+ incorporate the per-channel calibration. To allow the calibration to
+ be
+ re-applied or removed, it first makes a copy of the uncalibrated
+ curves
+ and stores them in private tags in the profile.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that things like the
+ white point, black point tag, gamut tag etc. are <span
+ style="text-decoration: underline;">not</span> adjusted to account
+ for the calibration, nor does applycal read, add or change any
+ 'vcgt' tag (If a 'vcgt' tag is present and a calibration applied as
+ well, then both will be in effect when such a profile is installed
+ using typical display installation tools.)<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that any calibration
+ embedded in the ICC profile <span style="font-weight: bold;">'targ</span>'
+ tag is ignored, since it is intended for computation of final
+ calibrated device value ink limits, and may not represent the exact
+ current calibration curves.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/average.html b/doc/average.html
new file mode 100644
index 0000000..31adf9b
--- /dev/null
+++ b/doc/average.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>average</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>spectro/average</b></h2>
+<h3>Summary</h3>
+Average or merge two or more <a href="File_Formats.html#.ti3">.ti3</a>
+measurement
+files.<br>
+<h3>Usage</h3>
+<small><span style="font-family: monospace;"></span></small><small>
+<span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;"></span></small><span
+ style="font-family: monospace;">usage: average [-options] input1.ti3
+input2.ti3 ... output.ti3</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-m&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Merge rather than average</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;input1.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+First input file</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;input2.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Second input file</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;...&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+etc.</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;output.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Resulting averaged or merged output file</span><br>
+<br>
+<br>
+All keywords and other table data will be taken from the first input
+file. By default the input files are averaged, but they can be merged
+by using the <span style="font-weight: bold;">-m</span> flag.<br>
+<br>
+The fields must be the same and in the same order. For averaging, the
+device values must be the same and in the same order.<br>
+<br>
+</body>
+</html>
diff --git a/doc/cal_format.html b/doc/cal_format.html
new file mode 100644
index 0000000..3e40205
--- /dev/null
+++ b/doc/cal_format.html
@@ -0,0 +1,216 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Calibration Format File (.cal)</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2>Description of the .cal format</h2>
+ Device calibration information. This is ASCII text, <a
+ href="File_Formats.html#CGATS">CGATS</a>, Argyll specific format,
+ used
+ to hold a description of device setup information that brings it to
+ a
+ desired calibration state. Calibration files are created by <a
+ href="synthcal.html">synthcal</a>, <a href="dispcal.html">dispcal</a>
+ and <a href="printcal.html">printcal</a>.<br>
+ <br>
+ While fully compatible with the CGATS.5 Data Exchange Format, the
+ particular required keywords and fields are unique to Argyll, hence
+ an
+ Argyll specific file identifier <span style="font-weight: bold;">CAL</span>
+ is used to avoid confusion with standard ANSI or CGATS files.<br>
+ <br>
+ The <span style="font-weight: bold;">.cal</span> format changes
+ from
+ time to time with new releases, to add new functionality, but
+ generally
+ retains backwards compatibility. Note that in the description below,
+ the word "may" indicates an optional component, while the word
+ "shall"
+ indicates a necessary component.<br>
+ <br>
+ Generally a .cal file contains only one table, the table containing
+ the
+ setup information. <br>
+ <br>
+ <br>
+ The table contains the following:<br>
+ <br>
+ The file identifier (First 7 characters) shall be <span
+ style="font-weight: bold;">CAL</span>.<br>
+ <br>
+ A <span style="font-weight: bold;">#</span> character introduces a
+ comment.<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"></span></span></span>There may be <span
+ style="font-weight: bold;">DESCRIPTOR</span>, <span
+ style="font-weight: bold;">ORIGINATOR</span>, or <span
+ style="font-weight: bold;">CREATED</span> keywords and values (as
+ per
+ CGATS).<br>
+ <br>
+ There shall be a <span style="font-weight: bold;">DEVICE_CLASS</span>
+ keyword that has a value of <span style="font-weight: bold;">"OUTPUT</span>",
+ "<span style="font-weight: bold;">DISPLAY</span>" or <span
+ style="font-weight: bold;">"INPUT"</span>.<br>
+ This indicates what type of device the calibration information is
+ suitable for.<br>
+ <br>
+ A <span style="font-weight: bold;">"DISPLAY"</span> type device may
+ have a <span style="font-weight: bold;">VIDEO_LUT_CALIBRATION_POSSIBLE
+ </span>keyword that
+ must have a value of "<span style="font-weight: bold;">NO</span>" or
+ "<span style="font-weight: bold;">YES</span>", to indicate whether
+ the display has the ability to be calibrated by loading VideoLUT
+ values.<br>
+ <br>
+ There shall be a keyword <span style="font-weight: bold;">COLOR_REP</span>
+ that has a value that indicates what colorspaces of the device
+ values.
+ The colorspaces shall be encoded with one&nbsp; or two letters
+ per
+ component. The device spaces shall use the
+ following letter encoding:<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>&nbsp;&nbsp;&nbsp;
+Cyan
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ C<br>
+ &nbsp;&nbsp;&nbsp; Magenta &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; M<br>
+ &nbsp;&nbsp;&nbsp; Yellow &nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Y<br>
+ &nbsp;&nbsp;&nbsp; Black &nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ K<br>
+ &nbsp;&nbsp;&nbsp; Orange &nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ O<br>
+ &nbsp;&nbsp;&nbsp; Red
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ R<br>
+ &nbsp;&nbsp;&nbsp; Green &nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ G<br>
+ &nbsp;&nbsp;&nbsp; Blue &nbsp;&nbsp; &nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ B<br>
+ &nbsp;&nbsp;&nbsp; White &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; W<br>
+ &nbsp;&nbsp;&nbsp; Light Cyan
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ c<br>
+ &nbsp;&nbsp;&nbsp; Light
+Magenta&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ m<br>
+ &nbsp;&nbsp;&nbsp; Light
+Yellow&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ y<br>
+ &nbsp;&nbsp;&nbsp; Light
+Black&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ k<br>
+ &nbsp;&nbsp;&nbsp; Medium Cyan&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2c<br>
+ &nbsp;&nbsp;&nbsp; Medium Magenta
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 2m<br>
+ &nbsp;&nbsp;&nbsp; Medium Yellow
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2y<br>
+ &nbsp;&nbsp;&nbsp; Medium Black
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2k<br>
+ &nbsp;&nbsp;&nbsp; Light Light Black &nbsp; &nbsp; &nbsp;&nbsp; 1k<br>
+ <br>
+ There may be an a prefix <span style="font-weight: bold;">i</span>
+ preceding the device space letter encoding, indicating that although
+ the space appears to be an additive space, it is in fact a
+ subtractive
+ device.<br>
+ <br>
+ Typical values might be: "<span style="font-weight: bold;">RGB</span><span
+ style="font-weight: bold;"></span>" for an RGB display, "<span
+ style="font-weight: bold;">iRGB</span><span style="font-weight:
+ bold;"></span>"
+ for an RGB printer, "<span style="font-weight: bold;">CMYK</span>"
+ for
+ a
+ printer, "<span style="font-weight: bold;">RGB"</span> for an RGB
+ scanner.<br>
+ <br>
+ The <span style="font-weight: bold;">NUMBER_OF_FIELDS</span>
+ keyword
+ shall have a value that indicates the number of fields in each data
+ set, e.g. <span style="font-weight: bold;">4</span> (as per CGATS).<br>
+ <br>
+ The start of the declaration of the fields shall be marked by the <span
+ style="font-weight: bold;">BEGIN_DATA_FORMAT</span> keyword (as
+ per
+ CGATS).<br>
+ <br>
+ The fields shall use the standard CGATS pattern of the full
+ colorspace
+ identified followed by the individual colorant identifier. There
+ shall
+ be an initial input index value identified by the letter <span
+ style="font-weight: bold;">I</span>.<br>
+ <br>
+ For an RGB device, the
+ following fields would be used:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">RGB_I</span>&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+ The device value input value between 0.0 and 1.0.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">RGB_R</span>&nbsp;&nbsp;&nbsp;
+&nbsp;
+ The Red device value input value between 0.0 and 1.0.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">RGB_G</span>
+ &nbsp;&nbsp; &nbsp; The Green device value input value between 0.0
+ and
+ 1.0.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">RGB_B</span>
+ &nbsp;&nbsp; &nbsp; The Blue device value input value between 0.0
+ and
+ 1.0.<br>
+ <br>
+ The corresponding field names for a CMYK device would be <span
+ style="font-weight: bold;">CMYK_I</span>, <span
+ style="font-weight: bold;">CMYK_C</span>, <span
+ style="font-weight: bold;">CMYK_M</span>, <span
+ style="font-weight: bold;">CMYK_Y</span> and <span
+ style="font-weight: bold;">CMYK_K</span>, etc.<br>
+ <br>
+ The definition of the fields shall be terminated by the <span
+ style="font-weight: bold;">END_DATA_FORMAT</span> keyword (as per
+ CGATS).<br>
+ <br>
+ The <span style="font-weight: bold;">NUMBER_OF_SETS</span> keyword
+ shall have a value that indicates the number of sets of data, e.g. <span
+ style="font-weight: bold;">256</span> (as per CGATS).<br>
+ <br>
+ The start of the values of the data sets shall be marked by the <span
+ style="font-weight: bold;">BEGIN_DATA</span> keyword (as per
+ CGATS).<br>
+ <br>
+ Each set of data shall be on one line, and shall be separated by
+ white
+ space. All values shall be normalized to lie between 0.0 and 1.0.<br>
+ <br>
+ The end of the values of the data sets shall be marked by the <span
+ style="font-weight: bold;">END_DATA</span> keyword (as per CGATS).<br>
+ <br>
+ There may then be device type specific extra tables that hold target
+ or
+ device behavior information. These will be specific to the tool that
+ creates that particular type of calibration.<br>
+ <br>
+ Generally any other keywords and values will be ignored.<br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/calvschar.html b/doc/calvschar.html
new file mode 100644
index 0000000..f194d79
--- /dev/null
+++ b/doc/calvschar.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Calibration vs. Characterization</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ </head>
+ <body>
+ <h2 style="text-decoration: underline; font-weight: bold;">Calibration
+vs.
+
+ Characterization<br>
+ </h2>
+ Some of the terminology can be confusing. Many people are initially
+ confused about the difference between <span style="font-weight:
+ bold;">Calibration</span> and <span style="font-weight: bold;">Characterization</span>.<br>
+ <h3>What is Calibration ?</h3>
+ "Calibration" is a short hand Graphic Arts term for adjusting a
+ devices behavior to meet calibration targets.<br>
+ Calibration is the process of modifying the color behavior of a
+ device. This is typically done using two mechanisms:<br>
+ &nbsp;&nbsp;&nbsp; 1) Changing controls or internal settings that it
+ has.<br>
+ &nbsp;&nbsp;&nbsp; 2) Applying curves to its color channels.<br>
+ <br>
+ The idea of calibration is to put a device is a defined state with
+ regard to its color response. Often this is used as a day to day
+ means of maintaining reproducible behavior. Calibration is often the
+ most practical way of setting parameters such as white point and
+ brightness of displays. Typically calibration will be stored in
+ device or systems specific file formats that record the device
+ settings and/or per channel calibration curves.<br>
+ <h3>What is Characterization ?</h3>
+ Characterization (or <span style="font-weight: bold;">profiling</span>)
+ is <span style="text-decoration: underline;">recording</span> the
+ way a device reproduces or responds to color. Typically the result
+ is stored in a device <span style="font-weight: bold;">ICC</span>
+ profile. Such a profile does not in itself modify color in any way.
+ What it does is allow a system such as a CMM (Color Management
+ Module) or color aware application to modify color when combined
+ with another device profile. Only by knowing the characteristics of
+ two devices or colorspaces, can a way of transferring color from one
+ device representation to another be achieved.<br>
+ <br>
+ Note that a characterization (profile) will only be valid for a
+ device if it is in the same state of calibration as it was when it
+ was characterized.<br>
+ <h3>What about display calibration and profiles ?</h3>
+ In the case of display profiles there is some additional confusion
+ because often the <span style="font-weight: bold;">calibration</span>
+ information is stored in the <span style="font-weight: bold;">profile</span>
+ for convenience. By convention it is stored in a tag called the
+ 'vcgt' tag. Although it is stored in the profile, none of the normal
+ <span style="font-weight: bold;">ICC</span> based tools or
+ applications are aware of it, or do anything with it, it is just
+ "along for the ride". Similarly, typical display calibration tools
+ and applications will not be aware of, or do anything with the ICC
+ characterization (profile) information.<br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/cb2ti3.html b/doc/cb2ti3.html
new file mode 100644
index 0000000..d999075
--- /dev/null
+++ b/doc/cb2ti3.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>cb2ti3</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>profile/cb2ti3</b></h2>
+<h3>Summary</h3>
+Convert Colorblind format CMY/RGB test chart information into <a
+ href="File_Formats.html#.ti3">Argyll .ti3</a> CGATS profile forma
+files.
+This allows the use of raw Colorblind profiling data, to be used for
+Argyll
+profile creation or validation..<br>
+<h3>Usage</h3>
+<small><span style="font-family: monospace;"> cb2gcats [-v] [-l limit] </span><i
+ style="font-family: monospace;">inbasename outbasename</i><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;
+-v&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp; Verbose flag</span><br style="font-family: monospace;">
+<span style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; -l
+limit&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Set and ink limit
+(TAC) in the resulting .ti3 file</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><i
+ style="font-family: monospace;">inbasename</i><span
+ style="font-family: monospace;"> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Base
+name for input Colorblind .CMY and input. nCIE file</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; </span><i
+ style="font-family: monospace;">outbasename</i><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Base
+name for output.ti3 file.</span></small><br>
+<h3>Examples</h3>
+Given the Colorblind files <i>fred.CMY</i> and <i>fred.nCIE</i>, and
+an
+ink limit of 280%, one would create the Argyll CGATs file <i>device.ti3</i>
+file thus:<br>
+<br>
+cb2ti3 -l 280 fred device<br>
+<h3>Comments</h3>
+This tool only handles RGB or CMY files, and nothing else.<br>
+There is no extra output when the verbose flag is used.<br>
+Because the two Colorblind files are specified by a basename., they
+must reside in the same directory.<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/ccmxs.html b/doc/ccmxs.html
new file mode 100644
index 0000000..1ceaeac
--- /dev/null
+++ b/doc/ccmxs.html
@@ -0,0 +1,424 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Contributed CCMX files</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>Contributed ccmx files.<br>
+ </b></h2>
+ <span style="font-weight: bold;">ccmx</span> files are specific to a
+ particular Colorimeter and Display make and model combination. You
+ may find though that you get some benefit from using a file for your
+ instrument and a similar type of display to yours.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE<span style="font-weight:
+ bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"> </span></span></span></span>that
+these
+files
+have
+been
+contributed
+by
+
+ various Argyll users, and their usefulness to your particular
+ situation is <span style="text-decoration: underline;">up to you to
+ evaluate</span>. They may or may not improve the absolute accuracy
+ of your colorimeter with your display.<br>
+ <span style="font-weight: bold;"></span><br>
+ <table style="text-align: left; width: 1225px; height: 205px;"
+ border="1" cellpadding="2" cellspacing="2">
+ <tbody>
+ <tr>
+ <td style="text-align: center; vertical-align: top;">Display/Colorimeter<br>
+ </td>
+ <td style="vertical-align: top;">Rebadged &amp; came with the
+ display<br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="instruments.html#DTP92">DTP92</a> </td>
+ <td style="vertical-align: top;"> <a
+ href="instruments.html#DTP94">DTP94</a> </td>
+ <td style="vertical-align: top;"> <a
+ href="instruments.html#i1d">Eye-One Display 1</a> </td>
+ <td style="vertical-align: top;"> <a
+ href="instruments.html#i1d">Eye-One Display 2/LT</a><br>
+ <a href="instruments.html#i1d"><span style="text-decoration:
+ underline;">ColorMunki Create</span></a><br>
+ </td>
+ <td style="vertical-align: top;"> <a
+ href="instruments.html#Huey">Huey</a> </td>
+ <td style="vertical-align: top;"><a
+ href="instruments.html#spyd2">Spyder 2</a> </td>
+ <td style="vertical-align: top;"> <a
+ href="instruments.html#spyd3">Spyder 3</a> </td>
+ <td style="vertical-align: top;"><span class="titre"><a
+ href="instruments.html#HCFR">Colorim&egrave;tre HCFR</a></span></td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;"> Acer AL2016w </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Huey_Acer_al2016w.ccmx">Huey_Acer_al2016w</a></td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">Dell 2408W<br>
+ Dell 2709W<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/DTP-94_Dell_2408W.ccmx">DTP-94_Dell_2408W</a><br>
+ <a href="ccmxs/DTP-94_1964_10_Dell_2408W.ccmx">DTP-94_1964_10_Dell_2408W</a><br>
+ <a href="ccmxs/DTP-94_1997_Shaw_Dell_2408W.ccmx">DTP-94_1997_Shaw_Dell_2408W</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">
+ <pre>Dell Ultrasharp U2410</pre>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/DTP-94_Dell_U2410.ccmx">DTP-94_Dell_U2410</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/EyeOne_Display_LT_U2410_sRGB_1931.ccmx">EyeOne_Display_LT_U2410_sRGB_2deg</a><br>
+ <a href="ccmxs/EyeOne_Display_LT_U2410_sRGB_1964.ccmx">EyeOne_Display_LT_U2410_sRGB_10deg</a><br>
+ <a href="ccmxs/EyeOne_Display_LT_U2410_Standard_1931.ccmx">EyeOne_Display_LT_U2410_Standard_2deg</a><br>
+ <a href="ccmxs/EyeOne_Display_LT_U2410_Standard_1964.ccmx">EyeOne_Display_LT_U2410_Standard_10deg</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">EIZO CG243<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Huey_Eizo_CG243.ccmx">Huey_Eizo_CG243</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">EIZO S2233<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Spyder3_Eizo_S2233_standard_1964.ccmx">Spyder3_EIZO_S2233_standard_10deg</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">EIZO S2233W<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/EyeOne_Display_2_EIZO_S2233W.ccmx">EyeOne_Display_2_EIZO_S2233W</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">EIZO S2243W</td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;">
+ <table border="1" cellpadding="2" cellspacing="2">
+ <tbody>
+ <tr>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Spyder3_EIZO_S2243W_standard_1931.ccmx">Spyder3_EIZO_S2243W</a><a
+ href="ccmxs/Spyder2_EIZO_S2433W_1964_10.ccmx">_2deg</a>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">EIZO S2433W<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Spyder2_EIZO_S2433W_standard_1931.ccmx">Spyder3_EIZO_S2433W_2deg</a><br>
+ <a href="ccmxs/Spyder2_EIZO_S2433W_standard_1964.ccmx">Spyder2_EIZO_S2433W</a><a
+ href="ccmxs/Spyder2_EIZO_S2433W_1964_10.ccmx">_10deg</a> </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Spyder3_EIZO_S2233_standard_1931.ccmx"><br>
+ </a> </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;"> HP Compaq 6730s laptop </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><span style="text-decoration:
+ underline;"></span><a
+ href="ccmxs/Huey_HP_compaq_6730s.ccmx">Huey_HP_compaq_6730s</a></td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;"> HP LP2475w Wide Gamut </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Huey_HP_lp2475w.ccmx">Huey_HP_lp2475w</a></td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Spyder3_HP_LP2475w.ccmx">Spyder3_HP_LP2475w</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">NEC MultiSync LCD 1990SXi </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/EyeOne_Display_1_NEC1990SXi.ccmx">EyeOne_Display_1_NEC1990SXi</a><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/EyeOne_Display_2_NEC1990SXi.ccmx">EyeOne_Display_2_NEC1990SXi</a><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Huey_NEC1990SXi.ccmx">Huey_NEC1990SXi</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">NEC MultySync LCD 2690WUXi2</td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/NEC_EyeOne_Display_2_NEC2690WUXi2.ccmx">NEC_EyeOne_Display_2_NEC2690WUXi2</a></td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Spyder3_NEC2690WUXi2.ccmx">Spyder3
+ _NEC2690WUXi2</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">NEC PA301W<br>
+ </td>
+ <td valign="top"><br>
+ </td>
+ <td valign="top"><br>
+ </td>
+ <td valign="top"><br>
+ </td>
+ <td valign="top"><br>
+ </td>
+ <td valign="top"><br>
+ </td>
+ <td valign="top"><br>
+ </td>
+ <td valign="top"><br>
+ </td>
+ <td valign="top"><a href="ccmxs/Spyder3_NEC_PA301W.ccmx">Spyder3_NEC_PA301W</a><br>
+ </td>
+ <td valign="top"><br>
+ </td>
+ </tr>
+ <tr>
+ <td style="vertical-align: top;">NEC Spectraview 241<br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><a
+ href="ccmxs/Huey_NEC_Spectraview_241.ccmx">Huey_NEC_Spectraview_241</a><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ <td style="vertical-align: top;"><br>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"></span> If anyone wants to
+ contribute correction matrices that they've made for particular
+ colorimeter + display combinations, I'm happy to put them on the
+ website so that others can make use of them. Any <span
+ style="font-weight: bold;">ccmx</span> files contributed for this
+ purpose will be assumed to have been placed in the <span
+ style="font-weight: bold;">public domain</span>.<br>
+ <br>
+ <script language="JavaScript">
+<!--
+// Comment
+var v1 = ".com"
+var v2 = "argyllcms"
+var v3 = "graeme"
+var v4 = "@"
+var v5 = "mailto:"
+var v6 = v5 + v3 + v4 + v2 + v1
+document.write("<a href=" + v6 + ">" + "Contact Me" + "</a>")
+//-->
+</script><br>
+ &nbsp;
+ </body>
+</html>
diff --git a/doc/ccmxs/DTP-94_1964_10_Dell_2408W.ccmx b/doc/ccmxs/DTP-94_1964_10_Dell_2408W.ccmx
new file mode 100644
index 0000000..c1d0e8c
--- /dev/null
+++ b/doc/ccmxs/DTP-94_1964_10_Dell_2408W.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Xrite DTP94 & Dell 2408WFP"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "1964_10 Xrite DTP94"
+KEYWORD "DISPLAY"
+DISPLAY "Dell 2408WFP"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Mon Sep 20 10:38:25 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.83589 0.11701 0.028937
+-0.080058 1.0887 0.058441
+0.011479 -0.035708 1.0529
+END_DATA
diff --git a/doc/ccmxs/DTP-94_1997_Shaw_Dell_2408W.ccmx b/doc/ccmxs/DTP-94_1997_Shaw_Dell_2408W.ccmx
new file mode 100644
index 0000000..168fc51
--- /dev/null
+++ b/doc/ccmxs/DTP-94_1997_Shaw_Dell_2408W.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Xrite DTP94 & Dell 2408WFP"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "1997 Shaw Xrite DTP94"
+KEYWORD "DISPLAY"
+DISPLAY "Dell 2408WFP"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Mon Sep 20 10:41:08 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.84519 0.048811 0.010471
+-0.057861 1.0433 0.013805
+-0.017341 0.027907 0.94117
+END_DATA
diff --git a/doc/ccmxs/DTP-94_Dell_2408W.ccmx b/doc/ccmxs/DTP-94_Dell_2408W.ccmx
new file mode 100644
index 0000000..bf58d48
--- /dev/null
+++ b/doc/ccmxs/DTP-94_Dell_2408W.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Xrite DTP94 & Dell 2408WFP"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "Xrite DTP94"
+KEYWORD "DISPLAY"
+DISPLAY "Dell 2408WFP"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Mon Sep 20 10:37:13 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.86461 0.030195 0.012871
+-0.069159 1.0244 0.017185
+-0.010324 0.011396 0.96486
+END_DATA
diff --git a/doc/ccmxs/DTP-94_Dell_U2410.ccmx b/doc/ccmxs/DTP-94_Dell_U2410.ccmx
new file mode 100644
index 0000000..0d7c610
--- /dev/null
+++ b/doc/ccmxs/DTP-94_Dell_U2410.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Xrite DTP94 & Dell U2410"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "Xrite DTP94"
+KEYWORD "DISPLAY"
+DISPLAY "Dell U2410"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro prd.de ccmx"
+ORIGINATOR "Argyll ccmx"
+CREATED "Tue May 17 19:18:08 2011"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.936109 0.022419 0.014533
+-0.038308 1.014059 0.010001
+-0.012576 0.010240 1.005667
+END_DATA
diff --git a/doc/ccmxs/EyeOne_Display_1_NEC1990SXi.ccmx b/doc/ccmxs/EyeOne_Display_1_NEC1990SXi.ccmx
new file mode 100644
index 0000000..b8d3072
--- /dev/null
+++ b/doc/ccmxs/EyeOne_Display_1_NEC1990SXi.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "GretagMacbeth i1 Display & NEC MultiSync LCD 1990SXi"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth i1 Display"
+KEYWORD "DISPLAY"
+DISPLAY "NEC MultiSync LCD 1990SXi"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Thu Sep 09 17:46:39 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+1.0193 -0.022377 0.014860
+0.017260 0.95636 2.3599e-003
+8.5413e-003 -9.3046e-003 1.0208
+END_DATA
diff --git a/doc/ccmxs/EyeOne_Display_2_EIZO_S2233W.ccmx b/doc/ccmxs/EyeOne_Display_2_EIZO_S2233W.ccmx
new file mode 100644
index 0000000..c3f9d80
--- /dev/null
+++ b/doc/ccmxs/EyeOne_Display_2_EIZO_S2233W.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "GretagMacbeth i1 Display & Eizo FlexScan S2233W 1680x1050"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth i1 Display"
+KEYWORD "DISPLAY"
+DISPLAY "Eizo FlexScan S2233W 1680x1050"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Mon Oct 11 16:13:03 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+1.0610 -0.045412 0.010132
+0.010992 0.96393 -5.6546e-03
+-0.015770 0.034683 1.0333
+END_DATA
diff --git a/doc/ccmxs/EyeOne_Display_2_NEC1990SXi.ccmx b/doc/ccmxs/EyeOne_Display_2_NEC1990SXi.ccmx
new file mode 100644
index 0000000..c70758e
--- /dev/null
+++ b/doc/ccmxs/EyeOne_Display_2_NEC1990SXi.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "GretagMacbeth i1 Display & NEC MultiSync LCD 1990SXi"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth i1 Display"
+KEYWORD "DISPLAY"
+DISPLAY "NEC MultiSync LCD 1990SXi"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Thu Sep 09 17:56:02 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.95118 -5.5218e-003 0.013440
+-0.010828 0.94247 3.0624e-003
+9.7395e-003 -0.013508 0.98334
+END_DATA
diff --git a/doc/ccmxs/EyeOne_Display_LT_U2410_Standard_1931.ccmx b/doc/ccmxs/EyeOne_Display_LT_U2410_Standard_1931.ccmx
new file mode 100644
index 0000000..4500b0e
--- /dev/null
+++ b/doc/ccmxs/EyeOne_Display_LT_U2410_Standard_1931.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Native gamut, CIE 1931 observer, Reference spectro: ColorMunki"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth i1 Display"
+KEYWORD "DISPLAY"
+DISPLAY "Dell U2410"
+KEYWORD "REFERENCE"
+REFERENCE "X-Rite ColorMunki"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sun Oct 03 00:38:56 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.88951 -0.036475 0.032403
+0.013090 0.88419 0.010053
+-9.3198e-003 0.026884 0.95894
+END_DATA
diff --git a/doc/ccmxs/EyeOne_Display_LT_U2410_Standard_1964.ccmx b/doc/ccmxs/EyeOne_Display_LT_U2410_Standard_1964.ccmx
new file mode 100644
index 0000000..1d8e082
--- /dev/null
+++ b/doc/ccmxs/EyeOne_Display_LT_U2410_Standard_1964.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Native gamut, CIE 1964 observer, Reference spectro: ColorMunki"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth i1 Display (CIE 1964 10 degree observer)"
+KEYWORD "DISPLAY"
+DISPLAY "Dell U2410"
+KEYWORD "REFERENCE"
+REFERENCE "X-Rite ColorMunki"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sun Oct 03 00:42:36 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.86409 0.046894 0.035027
+8.6952e-003 0.95117 0.036360
+5.7496e-003 -8.8727e-003 1.0383
+END_DATA
diff --git a/doc/ccmxs/EyeOne_Display_LT_U2410_sRGB_1931.ccmx b/doc/ccmxs/EyeOne_Display_LT_U2410_sRGB_1931.ccmx
new file mode 100644
index 0000000..e6be5d5
--- /dev/null
+++ b/doc/ccmxs/EyeOne_Display_LT_U2410_sRGB_1931.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Emulated sRGB gamut, CIE 1964 observer, Reference spectro: ColorMunki"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth i1 Display"
+KEYWORD "DISPLAY"
+DISPLAY "Dell U2410"
+KEYWORD "REFERENCE"
+REFERENCE "X-Rite ColorMunki"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sun Oct 03 00:46:11 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.89191 -0.027759 0.025810
+0.010695 0.90054 9.3429e-005
+-0.016307 0.034060 0.96249
+END_DATA
diff --git a/doc/ccmxs/EyeOne_Display_LT_U2410_sRGB_1964.ccmx b/doc/ccmxs/EyeOne_Display_LT_U2410_sRGB_1964.ccmx
new file mode 100644
index 0000000..1de91c9
--- /dev/null
+++ b/doc/ccmxs/EyeOne_Display_LT_U2410_sRGB_1964.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Emulated sRGB gamut, CIE 1964 observer, Reference spectro: ColorMunki"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth i1 Display (CIE 1964 10 degree observer)"
+KEYWORD "DISPLAY"
+DISPLAY "Dell U2410"
+KEYWORD "REFERENCE"
+REFERENCE "X-Rite ColorMunki"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sun Oct 03 00:49:29 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.86736 0.046873 0.035348
+0.013981 0.95224 0.034689
+2.8361e-003 -4.8598e-003 1.0424
+END_DATA
diff --git a/doc/ccmxs/Huey_Acer_al2016w.ccmx b/doc/ccmxs/Huey_Acer_al2016w.ccmx
new file mode 100644
index 0000000..288a230
--- /dev/null
+++ b/doc/ccmxs/Huey_Acer_al2016w.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "GretagMacbeth Huey & Screen 1, Output DVI-0 at 0, 0, width 1680, height 1050"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth Huey"
+KEYWORD "DISPLAY"
+DISPLAY "Screen 1, Output DVI-0 at 0, 0, width 1680, height 1050"
+KEYWORD "REFERENCE"
+REFERENCE "X-Rite ColorMunki"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sun Sep 12 17:27:22 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.93560 -0.019669 -7.1772e-04
+0.019205 0.88201 -1.7456e-03
+1.4914e-03 -1.1984e-03 0.89885
+END_DATA
diff --git a/doc/ccmxs/Huey_Eizo_CG243.ccmx b/doc/ccmxs/Huey_Eizo_CG243.ccmx
new file mode 100644
index 0000000..29e21bd
--- /dev/null
+++ b/doc/ccmxs/Huey_Eizo_CG243.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Eizo CG243"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth Huey"
+KEYWORD "DISPLAY"
+DISPLAY "Eizo CG243"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Mon Mar 07 10:40:28 2011"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.84312 -0.016137 0.028123
+0.033176 0.82353 -4.9480e-003
+-0.011411 0.024250 0.94937
+END_DATA
diff --git a/doc/ccmxs/Huey_HP_compaq_6730s.ccmx b/doc/ccmxs/Huey_HP_compaq_6730s.ccmx
new file mode 100644
index 0000000..26f11ae
--- /dev/null
+++ b/doc/ccmxs/Huey_HP_compaq_6730s.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "GretagMacbeth Huey & Screen 1, Output LVDS1 at 0, 0, width 1280, height 800"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth Huey"
+KEYWORD "DISPLAY"
+DISPLAY "Screen 1, Output LVDS1 at 0, 0, width 1280, height 800"
+KEYWORD "REFERENCE"
+REFERENCE "X-Rite ColorMunki"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sun Sep 12 16:15:40 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.90072 4.7979e-05 0.018055
+-0.020339 0.93625 3.1028e-03
+-6.8272e-04 -1.7912e-03 0.99187
+END_DATA
diff --git a/doc/ccmxs/Huey_HP_lp2475w.ccmx b/doc/ccmxs/Huey_HP_lp2475w.ccmx
new file mode 100644
index 0000000..c33ee75
--- /dev/null
+++ b/doc/ccmxs/Huey_HP_lp2475w.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "GretagMacbeth Huey & Screen 1, Output HDMI2 at 0, 0, width 1920, height 1200"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth Huey"
+KEYWORD "DISPLAY"
+DISPLAY "Screen 1, Output HDMI2 at 0, 0, width 1920, height 1200"
+KEYWORD "REFERENCE"
+REFERENCE "X-Rite ColorMunki"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sun Sep 12 16:41:53 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.92211 -0.025380 0.014354
+0.040892 0.86304 -4.6763e-03
+-0.018470 0.041757 0.93443
+END_DATA
diff --git a/doc/ccmxs/Huey_NEC1990SXi.ccmx b/doc/ccmxs/Huey_NEC1990SXi.ccmx
new file mode 100644
index 0000000..97f8d8a
--- /dev/null
+++ b/doc/ccmxs/Huey_NEC1990SXi.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "GretagMacbeth Huey & NEC MultiSync LCD 1990SXi"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth Huey"
+KEYWORD "DISPLAY"
+DISPLAY "NEC MultiSync LCD 1990SXi"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Thu Sep 09 18:03:01 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+1.0456 -0.050500 4.6236e-003
+-3.3083e-003 0.98878 -0.012307
+0.014538 -0.023853 1.0341
+END_DATA
diff --git a/doc/ccmxs/Huey_NEC_Spectraview_241.ccmx b/doc/ccmxs/Huey_NEC_Spectraview_241.ccmx
new file mode 100644
index 0000000..f7341da
--- /dev/null
+++ b/doc/ccmxs/Huey_NEC_Spectraview_241.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Spectraview241"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth Huey"
+KEYWORD "DISPLAY"
+DISPLAY "NEC Spectraview 241"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Thu Mar 03 11:12:44 2011"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.84308 -0.012484 0.028477
+0.023148 0.83371 -3.9284e-003
+-0.013409 0.025818 0.94938
+END_DATA
diff --git a/doc/ccmxs/NEC_EyeOne_Display_2_NEC2690WUXi2.ccmx b/doc/ccmxs/NEC_EyeOne_Display_2_NEC2690WUXi2.ccmx
new file mode 100644
index 0000000..a6c29fc
--- /dev/null
+++ b/doc/ccmxs/NEC_EyeOne_Display_2_NEC2690WUXi2.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "GretagMacbeth i1 Display & NEC MultiSync LCD2690WUXi2"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "GretagMacbeth i1 Display"
+KEYWORD "DISPLAY"
+DISPLAY "NEC MultiSync LCD2690WUXi2"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sat Sep 11 19:53:24 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.91203 -0.015033 0.014040
+2.3004e-004 0.89781 5.1274e-004
+-0.014259 0.026863 0.93352
+END_DATA
diff --git a/doc/ccmxs/Spyder2_EIZO_S2433W_standard_1931.ccmx b/doc/ccmxs/Spyder2_EIZO_S2433W_standard_1931.ccmx
new file mode 100644
index 0000000..0cbe855
--- /dev/null
+++ b/doc/ccmxs/Spyder2_EIZO_S2433W_standard_1931.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "ColorVision Spyder2 & EIZO_S2433W"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "ColorVision Spyder2"
+KEYWORD "DISPLAY"
+DISPLAY "EIZO_S2433W"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Fri Nov 19 15:57:46 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+1.1862 0.027113 0.025124
+-8.2603e-003 1.2120 0.015153
+0.10617 -0.23223 1.3005
+END_DATA
diff --git a/doc/ccmxs/Spyder2_EIZO_S2433W_standard_1964.ccmx b/doc/ccmxs/Spyder2_EIZO_S2433W_standard_1964.ccmx
new file mode 100644
index 0000000..d1960b3
--- /dev/null
+++ b/doc/ccmxs/Spyder2_EIZO_S2433W_standard_1964.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "ColorVision Spyder2 (CIE 1964 10 degree observer) & EIZO_S2433W"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "ColorVision Spyder2 (CIE 1964 10 degree observer)"
+KEYWORD "DISPLAY"
+DISPLAY "EIZO_S2433W"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sun Oct 31 22:09:52 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+1.1215 0.13625 0.039510
+-0.026007 1.2650 0.068299
+0.14057 -0.29555 1.3623
+END_DATA
diff --git a/doc/ccmxs/Spyder3_EIZO_S2233_standard_1964.ccmx b/doc/ccmxs/Spyder3_EIZO_S2233_standard_1964.ccmx
new file mode 100644
index 0000000..214a680
--- /dev/null
+++ b/doc/ccmxs/Spyder3_EIZO_S2233_standard_1964.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Datacolor Spyder3 (CIE 1964 10 degree observer) & EIZO S2233"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "Datacolor Spyder3 (CIE 1964 10 degree observer)"
+KEYWORD "DISPLAY"
+DISPLAY "EIZO S2233"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Mon Nov 15 23:15:33 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.81240 0.11317 0.056264
+-0.058301 1.0547 0.059013
+0.068682 -0.28738 1.1497
+END_DATA
diff --git a/doc/ccmxs/Spyder3_EIZO_S2243W_standard_1931.ccmx b/doc/ccmxs/Spyder3_EIZO_S2243W_standard_1931.ccmx
new file mode 100644
index 0000000..7fbf60b
--- /dev/null
+++ b/doc/ccmxs/Spyder3_EIZO_S2243W_standard_1931.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Datacolor Spyder3 & EIZO S2243W"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "Datacolor Spyder3"
+KEYWORD "DISPLAY"
+DISPLAY "EIZO S2243W"
+KEYWORD "REFERENCE"
+REFERENCE "X-Rite ColorMunki"
+ORIGINATOR "Argyll ccmx"
+CREATED "Thu Nov 25 19:28:17 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.95589 0.019068 0.017652
+-2.3435e-003 0.97122 -4.2447e-003
+2.9065e-003 -4.1199e-004 1.0474
+END_DATA
diff --git a/doc/ccmxs/Spyder3_HP_LP2475w.ccmx b/doc/ccmxs/Spyder3_HP_LP2475w.ccmx
new file mode 100644
index 0000000..40e990c
--- /dev/null
+++ b/doc/ccmxs/Spyder3_HP_LP2475w.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Datacolor Spyder3 & HP LP2475w"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "Datacolor Spyder3"
+KEYWORD "DISPLAY"
+DISPLAY "HP LP2475w"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Mon Sep 13 23:44:09 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+0.92077 0.050783 -0.010618
+6.1547e-003 0.89775 5.5560e-003
+0.028303 -0.16027 0.87261
+END_DATA
diff --git a/doc/ccmxs/Spyder3_NEC2690WUXi2.ccmx b/doc/ccmxs/Spyder3_NEC2690WUXi2.ccmx
new file mode 100644
index 0000000..2a663bc
--- /dev/null
+++ b/doc/ccmxs/Spyder3_NEC2690WUXi2.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Datacolor Spyder3 & NEC MultiSync LCD2690WUXi2"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "Datacolor Spyder3"
+KEYWORD "DISPLAY"
+DISPLAY "NEC MultiSync LCD2690WUXi2"
+KEYWORD "REFERENCE"
+REFERENCE "GretagMacbeth i1 Pro"
+ORIGINATOR "Argyll ccmx"
+CREATED "Sat Sep 11 17:42:33 2010"
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+1.0956 0.012843 2.0372e-004
+0.013872 1.0803 7.7446e-003
+0.032831 -0.15950 1.0888
+END_DATA
diff --git a/doc/ccmxs/Spyder3_NEC_PA301W.ccmx b/doc/ccmxs/Spyder3_NEC_PA301W.ccmx
new file mode 100644
index 0000000..b0dd777
--- /dev/null
+++ b/doc/ccmxs/Spyder3_NEC_PA301W.ccmx
@@ -0,0 +1,25 @@
+CCMX
+
+DESCRIPTOR "Spyder3 & NEC PA301W"
+KEYWORD "INSTRUMENT"
+INSTRUMENT "Spyder3"
+KEYWORD "DISPLAY"
+DISPLAY "NEC WA301P"
+KEYWORD "REFERENCE"
+REFERENCE "NEC factory read of primaries; monitor is new"
+ORIGINATOR "DC"
+CREATED "Sun 06 Jan 2013 19:50 "
+KEYWORD "COLOR_REP"
+COLOR_REP "XYZ"
+
+NUMBER_OF_FIELDS 3
+BEGIN_DATA_FORMAT
+XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 3
+BEGIN_DATA
+1.03390 -0.00402 0.00022
+0.01819 0.98822 0.00145
+-0.00899 0.04468 1.02205
+END_DATA
diff --git a/doc/cctiff.html b/doc/cctiff.html
new file mode 100644
index 0000000..c19d5c5
--- /dev/null
+++ b/doc/cctiff.html
@@ -0,0 +1,351 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>cctiff</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>imdi/cctiff</b></h2>
+ <h3>Summary</h3>
+ Color convert a TIFF or JPEG file using a sequence of compatible ICC
+ device profiles, abstract profiles, device link profiles and
+ calibration files. The sequence may be zero length, facilitating
+ format conversion and ICC profile embedding without otherwise
+ altering the pixel values.<br>
+ <h3>Usage<br>
+ </h3>
+ <small><span style="font-family: monospace;"></span> <span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;">cctiff [-options] { [-i intent] <span
+ style="font-style: italic;">profile.icm</span> | [-d dir]
+ calibration.cal ...} <span style="font-style: italic;">infile.tif
+
+ outfile.tif</span></span></small><small><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+
+ &nbsp;&nbsp; Verbose</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+
+ &nbsp;&nbsp; Combine linearisation curves into one transform</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p">-p</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+
+ &nbsp;&nbsp; Use slow precise floating point conversion, rather
+ than fast integer routines.</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#k">-k</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+
+ &nbsp;&nbsp; Check fast result against precise, and report
+ differences.<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#r">-r n<span
+ style="font-style: italic;"></span></a><span
+ style="font-family: monospace;">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Override
+ the default CLUT resolution</span></small><small><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#t">-t n<span
+ style="font-style: italic;"></span></a><span
+ style="font-family: monospace;">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Choose
+ output encoding from 1..n<br>
+ &nbsp;<a href="#f">-f [T|J]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Set output format to Tiff or Jpeg (Default is same as input)<br>
+ &nbsp;<a href="#q">-q quality</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Set JPEG quality 1..100 (Default 80)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#a">-a</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Read and Write planes &gt; 4 as
+ alpha planes<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;<a
+ href="#I">-I</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Ignore
+
+ any file or profile colorspace mismatches<br>
+ &nbsp;<a href="#D">-D</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't
+
+ append or set the output TIFF description<br>
+ <br>
+ </span></small><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"><br>
+ &nbsp;</span></small><small><a style="font-family: monospace;"
+ href="#e"><i>-e profile.[ic<span style="font-family: monospace;">m
+ | tiff | jpg]</span></i></a><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;">&nbsp; Optionally embed a profile in the destination
+ TIFF or JPEG file.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ </span></small><small><span style="font-family: monospace;">This
+ may be an ICC file or TIFF or JPEG file with embedded profile.</span></small><br>
+ <small><span style="font-family: monospace;"><br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Then
+
+ for each profile in the linked sequence:<br style="font-family:
+ monospace;">
+ </span></small><small><span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;">&nbsp; </span><a style="font-family: monospace;"
+ href="#i">-i <span style="font-style: italic;">intent</span></a><span
+ style="font-family: monospace;">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Profile intent</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p =
+ perceptual, r = relative colorimetric,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+
+ &nbsp;&nbsp;&nbsp; s = saturation, a = absolute colorimetric<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;
+ </span><a style="font-family: monospace;" href="#o">-o order<span
+ style="font-style: italic;"></span></a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; n = normal (priority: lut
+ &gt; matrix &gt; monochrome)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+r
+
+ = reverse (priority: monochrome &gt; matrix &gt; lut)</span></small><small><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#p1"><i>profile.[ic<span
+ style="font-family: monospace;">m | tiff | jpg]</span></i></a><span
+ style="font-family: monospace;">&nbsp; A Device, Link or
+ Abstract profile. This may be an ICC file<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+(May
+
+ be embedded profile in TIFF or JPEG file)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+or
+
+ each calibration file in sequence:<br style="font-family:
+ monospace;">
+ </span></small><small><span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;">&nbsp; </span><a style="font-family: monospace;"
+ href="#d">-d <span style="font-style: italic;"><span
+ style="font-family: monospace;">dir</span></span></a><span
+ style="font-family: monospace;">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Calibration direction</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; f =
+ forward cal. (default), b = backwards cal.</span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;"></span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#p2"><i>calibration.cal<span
+ style="font-family: monospace;"></span></i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ A calibration file.</span></small><br>
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span><br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Then finally:<br style="font-family:
+ monospace;">
+ &nbsp;<span style="font-family: monospace;"></span><a
+ style="font-family: monospace;" href="#p3"><i>infile.tif</i></a><span
+ style="font-family: monospace;"> &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; A </span><a style="font-family: monospace;"
+ href="File_Formats.html#TIFF">TIFF</a><span style="font-family:
+ monospace;">
+ or <a href="File_Formats.html#JPEG">JPEG</a> Raster file that
+ will be the input raster to be transformed.</span><br
+ style="font-family: monospace;">
+ &nbsp;<span style="font-family: monospace;"></span><a
+ style="font-family: monospace;" href="#p4"><i>outfile.tif</i></a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; A </span><a style="font-family: monospace;"
+ href="File_Formats.html#TIFF">TIFF</a><span style="font-family:
+ monospace;"> or <a href="File_Formats.html#JPEG">JPEG</a>
+ Raster file created from the input raster, using the given color
+ transform.</span></small><b><br>
+ </b><b><br>
+ Examples</b><br>
+ <br>
+ Convert an RGB file to a CMYK file using perceptual intent:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cctiff -ip sRGB.icm -i cmyk.icm rgbinfile.tif
+ cmykoutfile.tif<br>
+ <br>
+ Same as above, but use the source file embedded profile, and embed
+ the resulting colorspace profile in the output:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cctiff -e cmyk.icm -ip rgbfile.tif -ip
+ cmyk.icm&nbsp; rgbinfile.tif cmyout.tif<br>
+ <br>
+ Convert a raster file using a device link:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cctiff devicelink.icm infile.tif outfile.tif<br>
+ <br>
+ Convert an RGB source to CMYK via an abstract adjustment, and then
+ convert the CMYK to CMYK using a device link, also apply CMYK
+ calibration:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cctiff -ir sRGB.icm abstract.icm -ir CMYK.icm
+ devlink.icm CMYKcal.cal infile.tif outfile.tif<br>
+ <br>
+ Convert an RGB source file into a CIELab raster file:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; cctiff -t1 -ir sRGB.icm rgbfile.tif labfile.tif<br>
+ <h3>Comments<br>
+ </h3>
+ <a name="v"></a> The <span style="font-weight: bold;">-v</span>
+ flag reports extra information about the ICC profile.<br>
+ <br>
+ <a name="c"></a><a name="p"></a><a name="k"></a><a name="r"></a> The
+ <span style="font-weight: bold;">-c</span>, <span
+ style="font-weight: bold;">-p</span>, <span style="font-weight:
+ bold;">-k</span> and <span style="font-weight: bold;">-r</span>
+ options are intended to aid debugging.<br>
+ <br>
+ <a name="t"></a><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">-t </span>Some colorspaces can be
+ encoded in more than one way. If there is a choice, the choice
+ should be specified the <span style="font-weight: bold;">-t</span>
+ parameter. If this parameter is not given, then cctiff will print
+ the possible choices and choose the default. For TIFF LAB output
+ there are two choices <span style="font-weight: bold;">1</span> for
+ CIELab encoding (Default), and <span style="font-weight: bold;">2</span>
+ for ICCLab encoding. For JPEG RGB output there are two choices: <span
+ style="font-weight: bold;">1</span> for YCbCr encoding with
+ sub-sampled Cb and Cr (Default)\n", and <span style="font-weight:
+ bold;">2</span> RGB encoding which does not use sub sampling. For
+ JPEG CMYK output there are two choices: <span style="font-weight:
+ bold;">1</span> for YCCK encoding with sub-sampled C and C
+ (Default)\n", and <span style="font-weight: bold;">2</span> CMYK
+ encoding which does not use sub sampling<br>
+ <br>
+ <a name="f"></a><span style="font-weight: bold;"></span> <span
+ style="font-weight: bold;">-f</span> By default the output raster
+ file format will be the same as the input, and the <span
+ style="font-weight: bold;">-f</span> parameter will override this.
+ <span style="font-weight: bold;">-f T</span> will select <span
+ style="font-weight: bold;">TIFF</span> format output, and <span
+ style="font-weight: bold;">-f J</span> will select <span
+ style="font-weight: bold;">JPEG</span> format output.<span
+ style="font-weight: bold;"> </span><br>
+ <br>
+ <a name="q"></a><span style="font-weight: bold;"></span> <span
+ style="font-weight: bold;">-q</span> JPEG raster files use lossy
+ compression, and the <span style="font-weight: bold;">-q</span>
+ parameter controls how much compression is used in creating a JPEG
+ output file. The value can be between 1 and 100, with 1 being the
+ lowest quality and highest compression, and 100 being the highest
+ quality and lowest compression. The default value is 80.<br>
+ <br>
+ <a name="a"></a><span style="font-weight: bold;"></span> Normally
+ colorspaces that have more than 4 channels will be read and written
+ as multichannel TIFF files. These are not handled well by all
+ applications, so the <span style="font-weight: bold;">-a</span>
+ option causes extra channels above 4 to be stored as alpha planes,
+ providing more flexibility in using such files.<br>
+ <br>
+ <a name="I"></a>The <span style="font-weight: bold;">-I</span> flag
+ causes any mismatch between the color spaces of the image files and
+ each profile in the sequence to be ignored. The results might be
+ unpredictable unless you know exactly what you are doing.<br>
+ <br>
+ <a name="D"></a>The <span style="font-weight: bold;">-D</span> flag
+ stops the description tag being set or appended to by cctiff.<br>
+ <br>
+ <small><a name="e"></a></small><small>The <span style="font-weight:
+ bold;">-e profile.[icm | tiff | jpg]</span> option allows an ICC
+ profile to be embedded in the </small>destination TIFF or JPEG
+ file. The profile may either be an <small>ICC file or a TIFF or
+ JPEG file with embedded profile.</small><br>
+ <br>
+ Following these global options, you should specify the chain of
+ profiles and calibrations you want to apply. Each link of the chain
+ consists of the (optional) intent to be used for device profiles and
+ the filename of the profile, or the optional direction to be used
+ for the calibration and the filename of the calibration. The first
+ profile or calibrations input colorspace must be compatible with the
+ input TIFF file, and each profile or calibration output space must
+ be compatible with the next profile or calibrations input space. An
+ error will result if this is not the case.<br>
+ <br>
+ <div style="margin-left: 40px;"><a name="i"></a>The <span
+ style="font-weight: bold;">-i</span> parameters selects the
+ intent for the following device profile. Normally the same intent
+ should be used for all device profiles, but other combinations
+ allow special uses such as mixed proofing workflows.<br>
+ <br>
+ <a name="o"></a>The <span style="font-weight: bold;">-o</span>
+ parameter changes the order the profiles tags are searched in. A
+ profile is allowed to contain more than the minimum number of
+ elements or table needed to describe a certain transform, and may
+ contain redundant descriptions. &nbsp;By default, lut based table
+ information will be used first if present, followed by
+ matrix/shaper information, and only using monochrome information
+ if it is all that is present. <b>-o r</b> reverses this order. <br>
+ <br>
+ <a name="p1"></a>The file that will be the source of the ICC
+ profile. This can be either an ICC profile or a TIFF or JPEG file
+ that contains an embedded profile. Typically the first profile in
+ the chain might be taken from an embedded profile from the source
+ TIFF or JPEG file.<br>
+ <br>
+ <a name="d"></a>The <span style="font-weight: bold;">-d</span>
+ parameters selects the direction for the following calibration.
+ The default direction is the normal forward calibration, but if
+ -db is used, then a backwards (inverse) calibration will be
+ applied.<br>
+ <br>
+ <a name="p2"></a>The file that will be the source calibration.
+ This will be an Argyll <a href="File_Formats.html#.cal">.cal</a>
+ format file.<span style="font-weight: bold;"></span><br>
+ </div>
+ <br>
+ <a name="p3"></a>The second last argument should be the name of the
+ source TIFF or JPEG file that is to be processed.<br>
+ <br>
+ <a name="p4"></a>The last argument should be the name of the
+ destination TIFF or JPEG file to hold the results.<br>
+ <br>
+ <span style="font-weight: bold;">cctiff</span> uses very fast
+ integer conversion routines to process the raster. Both 8 and 16 bit
+ per component files can be handled, and up to 8 color channels (The
+ limit can be lifted to 15 re-compiling). JPEG files with no more
+ than 8 bit per component can be handled.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/ccxxmake.html b/doc/ccxxmake.html
new file mode 100644
index 0000000..c4d8059
--- /dev/null
+++ b/doc/ccxxmake.html
@@ -0,0 +1,954 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>ccxxmake</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/ccxxmake</b></h2>
+ <h3>Summary</h3>
+ For Colorimeters that rely on a calibration matrix, <span
+ style="font-weight: bold;">ccxxmake</span> allows creation of a
+ correction matrix file (<a href="File_Formats.html#.ccmx">ccmx</a>)
+ for a particular <span style="font-weight: bold;">Colorimeter &amp;
+ Display</span> combination, by making use a reference <span
+ style="font-weight: bold;">Spectrometer</span> or Colorimeter
+ instrument. This can then be used to improve the accuracy of
+ subsequent measurements with that Colorimeter on that Display by
+ using it with the <a href="dispcal.html#X">dispcal</a>, <a
+ href="dispread.html#X">dispread</a> and <a href="spotread.html#X">spotread</a>
+ -X option. A ccmx file can also be <a href="oeminst.html">installed</a>,
+ and will then appear in the available display type selection (<b>-y</b>
+ option). See <a href="WideGamutColmters.html">Wide Gamut Displays
+ and Colorimeters</a> for more information on why this may be
+ useful. [ <span style="font-weight: bold;">Note</span> that to make
+ use of a <u>colorimeter</u> as a CCMX reference, you will have to
+ provide two .ti3 files rather than using interactive measurement-
+ see <a href="#f"><span style="font-weight: bold;">-f</span></a>. ]<br>
+ <br>
+ For Colorimeters that have sensor spectral sensitivity calibration
+ information built into them&nbsp; (ie. the X-Rite <span
+ style="font-weight: bold;">i1d3</span>, and<span
+ style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ DataColor <span style="font-weight: bold;">Spyder4</span>), <span
+ style="font-weight: bold;">ccxxmake</span> allows a creation of a
+ calibration spectral sample (<a href="File_Formats.html#.ccss">ccss</a>)
+ for a particular <span style="font-weight: bold;">Display</span>,
+ by making use a reference <span style="font-weight: bold;">Spectrometer</span>
+ instrument. This can then be used to improve the accuracy of
+ subsequent measurements on that Display using such Colorimeters, by
+ using it with the <a href="dispcal.html#X">dispcal</a>, <a
+ href="dispread.html#X">dispread</a> and <a href="spotread.html#X">spotread</a>
+ -X option, or it can be <a
+ href="file:///D:/src/argyll/doc/oeminst.html">installed</a>, and
+ will then appear in the available display type selection (<b>-y</b>
+ option).<br>
+ <br>
+ The instrument manufacturer may supply spectral sample files (see <a
+ href="oeminst.html">oeminst</a>).<br>
+ <br>
+ There is a <a href="ccmxs.html">list of contributed</a> <span
+ style="font-weight: bold;">ccmx</span> (Colorimeter Correction
+ Matrix) files.<br>
+ <h3>Usage Summary</h3>
+ <small style="font-family: monospace;">ccxxmake [-options]
+ correction.ccmx<br>
+ </small><small style="font-family: monospace;">&nbsp;<a href="#v">-v</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; Verbose mode</small><br>
+ &nbsp; <a href="#S">-S</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Create
+CCSS
+rather
+
+
+
+
+
+
+
+
+
+
+
+
+
+ than CCMX<br>
+ &nbsp; <a href="#f">-f file1.ti3[,file2.ti3]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Create
+from
+one
+or
+two
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .ti3 files rather than measure.<br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><font
+ style="font-family: monospace;" size="-1"><a href="#display">-display
+
+
+
+
+
+
+
+
+
+
+
+
+
+ displayname</a>&nbsp; [X11 only] Choose X11 display name</font><br
+ style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1"></font><font
+ style="font-family: monospace;" size="-1">&nbsp;<a href="#dnm">-d
+ n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [X11 only] Choose the display from the following list (default 1),</font><br
+ style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+and
+optionally
+choose
+a
+different
+display
+m
+
+
+
+
+
+
+
+
+
+
+
+
+
+ for VideoLUT access.</font><br style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;<a href="#d">-d
+
+
+
+
+
+
+
+
+
+
+
+
+
+ n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Choose
+the
+display
+from
+the
+following
+list
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (default 1)</font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display via a web server at port (default 8080)</span><br
+ style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;</font><font
+ style="font-family: monospace;" size="-1"><a href="#p">-p</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use telephoto mode (ie. for a projector) (if available)</font><br
+ style="font-family: monospace;">
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#y">-y X</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display type - instrument specific list to choose from.</span></font><font
+ style="font-family: monospace;" size="-1"> (CCMX)</font><br
+ style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;<a href="#P">-P
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Position test
+ window and scale it</font><br style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ho,vi:
+0.0
+=
+left/top,
+0.5
+=
+center,
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.0 = right/bottom etc.</font><br style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ss:
+0.5
+=
+half,
+1.0
+=
+normal,
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0 = double etc.</font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+ ss,vs: = optional horizontal, vertical scale.</span></font><br
+ style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;</font><font
+ style="font-family: monospace;" size="-1"><a href="#F">-F</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fill whole screen with black background</font><br
+ style="font-family: monospace;">
+ <small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;"></span><a href="#n">-n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+[X11
+only]
+Don't
+set
+override
+redirect
+on
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test window<br>
+ </small><font style="font-family: monospace;" size="-1">&nbsp;<a
+ href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Disable initial calibration of instrument</font><small
+ style="font-family: monospace;"> if possible<br>
+ </small><span style="font-family: monospace;">&nbsp;</span><font
+ style="font-family: monospace;" size="-1"><a href="#H">-H</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use high resolution spectrum mode (if available)</font><font
+ style="font-family: monospace;" size="-1"></font><br
+ style="font-family: monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;<a href="#C">-C
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "command"</a> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Invoke shell "command" each time a color is set<br>
+ </font><small style="font-family: monospace;">&nbsp;<a href="#o">-o
+ <i>observ</i></a>&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Choose CIE Observer for CCMX spectral
+ data:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; 1931_2 </small><small
+ style="font-family: monospace;"> (def.)</small><small
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2<br>
+ </small><font style="font-family: monospace;" size="-1">&nbsp;<a
+ href="#s">-s steps</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+default
+patch
+sequence
+
+
+
+
+
+
+
+
+
+
+
+
+
+ combination steps (default 3)</font><br style="font-family:
+ monospace;">
+ <font style="font-family: monospace;" size="-1">&nbsp;<a href="#W">-W
+
+
+
+
+
+
+
+
+
+
+
+
+
+ n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+serial
+port
+flow
+control:
+n
+=
+
+
+
+
+
+
+
+
+
+
+
+
+
+ none, h = HW, x = Xon/Xoff</font><br style="font-family:
+ monospace;">
+ <small style="font-family: monospace;">&nbsp;<a href="#D">-D [level]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Print
+ debug diagnostics to stderr<br>
+ </small><small style="font-family: monospace;">&nbsp;<a
+ href="ccxxmake.html#E">-E "description"</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+the
+default
+overall
+
+
+
+
+
+
+
+
+
+
+
+
+
+ escription</small><br>
+ <small style="font-family: monospace;">&nbsp;<a href="#I">-I
+ "displayname"</a> &nbsp;&nbsp;&nbsp;&nbsp; </small><span
+ style="font-family: monospace;">Set display make and model
+ description</span><small style="font-family: monospace;"><br>
+ &nbsp;</small><small style="font-family: monospace;"><a href="#T">-T
+
+
+
+
+
+
+
+
+
+
+
+
+
+ "displaytech"</a> &nbsp;&nbsp;&nbsp;&nbsp; </small><span
+ style="font-family: monospace;">Set display technology description</span>
+ (ie. CRT, LCD etc.)<small style="font-family: monospace;"></small><br>
+ <tt>&nbsp;<a href="#U">-U c</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Set UI selection character(s)</tt><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#Yrn">-<font size="-1">Y</font>
+ r|n</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Override refresh, non-refresh display
+ mode</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#YA">-<font size="-1">Y</font>A</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Use non-adaptive integration time mode
+ (if available).</span></font><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><font
+ style="font-family: monospace;" size="-1"><a href="#file1"><span
+ style="font-style: italic;">correction.ccmx</span></a> |&nbsp;<a
+ href="#file2"></a></font><font style="font-family: monospace;"
+ size="-1"><a href="ccxxmake.html#file2">calibration.ccss</a></font><font
+ style="font-family: monospace;" size="-1"><br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File to save result to.</font><br>
+ <h3>Usage Details and Discussion</h3>
+ <a name="v"></a>The <b>-v</b> flag causes extra information to be
+ printed out during chartread operation.<br>
+ <br>
+ <a name="S"></a><span style="font-weight: bold;">-S</span> By
+ default a Colorimeter Correction Matrix (<span style="font-weight:
+ bold;">CCMX</span>) will be created from both <span
+ style="font-weight: bold;">Colorimeter</span> and <span
+ style="font-weight: bold;">Spectrometer</span> readings, which
+ allows correction for errors with a particular Colorimeter and
+ Display combination. If the <span style="font-weight: bold;">-S</span>
+ flag is used, then instead a Colorimeter Calibration Spectral Set (<span
+ style="font-weight: bold;">CCSS</span>) file is created from just
+ the <span style="font-weight: bold;">Spectrometer</span> readings,
+ that allows calibrating any suitable Colorimeter to the Display.<br>
+ <br>
+ <a name="f"></a><span style="font-weight: bold;">-f <span
+ style="font-style: italic;">file1.ti3[,file2.ti3]</span></span>
+ By <span style="text-decoration: underline;">default</span> <span
+ style="font-weight: bold;">ccxxmake</span> creates a <span
+ style="font-weight: bold;">CCMX</span> file by displaying test
+ patches on the screen, and then prompting you to measure them
+ interactively with the two instruments. An alternative is to create
+ a small number of test values using <span style="font-weight:
+ bold;">targen</span> suitable for display profiling (or use the <span
+ style="font-weight: bold;">ref/ccxx.ti1</span> file provided with
+ ArgyllCMS), and then measure them with the two instruments using <span
+ style="font-weight: bold;">dispread</span> to create a reference
+ and target .ti3 files, and then provide the two files as arguments
+ to <span style="font-weight: bold;">ccxxmake -f</span>. Normally
+ the reference file will be created using a spectral instrument and
+ you will want to use the <span style="font-weight: bold;">-s</span>
+ flag with dispread for this. If you want to use a colorimeter as a
+ reference instrument, then make sure that it is the first file
+ provided to the ccxxmake <span style="font-weight: bold;">-f</span>
+ option. The filenames should be concatenated with a <span
+ style="font-weight: bold;">","</span> separator without spaces.
+ You will also have to supply a display name using the <span
+ style="font-weight: bold;">-I</span> option and/or technology
+ description using <span style="font-weight: bold;">-T</span>.<br>
+ When creating a <span style="font-weight: bold;">CCSS</span> file,
+ only spectral readings from the display measured with the reference
+ instrument are needed, and a single <span style="font-weight:
+ bold;">.ti3</span> file should be provided.<br>
+ <br>
+ <a name="display"></a>When running on a UNIX based system that used
+ the X11 Windowing System, <b>ccxxmake</b> will by default use the
+ $DISPLAY environment variable to determine which display and screen
+ to read from. This can be overridden by supplying an X11 display
+ name to the <span style="font-weight: bold;">-display</span>
+ option. Note that if Xinerama is active, you can't select the screen
+ using $DISPLAY or -display, you have to select it using the <span
+ style="font-weight: bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a> By default the main display will be the location of
+ the test window. If the system has more than one display or screen,
+ an alternate display/screen can be selected with the <span
+ style="font-weight: bold;">-d</span> parameter. If you invoke <b>ccxxmake</b>
+ so as to display the usage information (i.e. "dispcal -?" or
+ "dispcal --"), then the discovered displays/screens will be listed.
+ Multiple displays may not be listed, if they appear as a single
+ display to the operating system (ie. the multi-display support is
+ hidden in the video card driver). On UNIX based system that used the
+ X11 Windowing System, the <span style="font-weight: bold;">-d</span>
+ parameter will override the screen specified by the $DISPLAY or
+ parameter.<br>
+ <br>
+ <a name="dnm"></a>Because of the difficulty cause by TwinView and
+ MergedFB in X11 based systems, you can optionally specify a separate
+ display number after the display that is going to be used to present
+ test patches, for accessing the VideoLUT hardware. This must be
+ specified as a single string, e.g. <span style="font-weight: bold;">-d
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1,2</span> . Some experimentation may be needed using <a
+ href="dispwin.html">dispwin</a> on such systems, to discover what
+ screen has access to the VideoLUT hardware, and which screens the
+ test patches appear on.<br>
+ <br>
+ <span style="font-weight: bold;"><a name="dweb"></a>-dweb</span> or
+ <span style="font-weight: bold;">-dweb:port</span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way.<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ allows measuring in telephoto mode, using instruments that support
+ this mode, e.g. the ColorMunki. Telephoto mode is one for taking
+ emissive measurements from a distance (ie. telespectometer,
+ tele-colorimeter) mode, and typically would be used for measuring
+ projector type displays. If a device does not support a specific
+ telephoto mode, then the normal emissive mode may be suitable for
+ measuring projectors.<br>
+ <br>
+ <a name="y"></a> The <span style="font-weight: bold;">-y</span>
+ flag allows setting the Display Type used as a base for color
+ correction matrix CCMX creation. Only base calibration display types
+ will be listed. The selection typically determines two aspects of of
+ the instrument operation: <span style="font-weight: bold;">1)</span>
+ It may set the measuring mode to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument internal calibration matrix suitable for a particular
+ display type. The selections available depends on the type and model
+ of instrument, and a list of the options for the discovered
+ instruments will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. Any CCMX created will work on top of
+ the selected Display Type, so to be valid, the same Display Type
+ must be selected whenever the CCMX is used with this instrument.
+ Installed CCMX files will automatically select the appropriate base
+ type.<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="n"></a><span style="font-weight: bold;">-n</span> When
+ running on a UNIX based system that used the X11 Windowing System, <b>dispcal</b>
+ normally selects the override redirect so that the test window will
+ appear above any other windows on the display. On some systems this
+ can interfere with window manager operation, and the <b>-n</b>
+ option turns this behaviour off.<br>
+ <br>
+ <a name="N"></a><span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="L"></a> The -<span style="font-weight: bold;">H</span>
+ option on high resolution spectral mode, if the instrument supports
+ it, such as the Eye-One Pro. See <a href="instruments.html">Operation
+
+
+
+
+
+
+
+
+
+
+
+
+ of particular instruments</a> for more details. This may give
+ better accuracy for display measurements.<br>
+ <br>
+ <a name="C"></a> The -<span style="font-weight: bold;">C</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of relaying each test value to some other display than that
+ on the system running dispcal (for instance, a photo frame, PDA
+ screen etc.), by causing the given command to be invoked to the
+ shell, with six arguments. The first three arguments are the RGB
+ test color as integers in the range 0 to 255, the second three
+ parameters are the RGB test color as floating point numbers in the
+ range 0.0 to 1.0. The script or tool should relay the given color to
+ the screen in some manner (e.g. by generating a raster file of the
+ given color and sending it to the display being profiled), before
+ returning. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="o"></a> (CCMX creation) The <b>-o</b> flag allows
+ specifying a tristimulus observer, and is used to compute
+ tristimulus values from spectral readings.&nbsp; The following
+ choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ <br>
+ <a name="s"></a>The <b>-s steps</b><span style="font-weight: bold;"></span>
+ parameter overrides the default number of test patch combination
+ steps used in measuring a colorimeter &amp; display combination.<span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span>&nbsp; The steps are those out
+ of every combination of R,G &amp; B values of the given number of
+ steps that have at least one colorant at 100%. So 2 steps gives 7
+ test patches, 3 gives 19, 4 gives 37, 5 gives 61, 6 gives 91 etc.
+ Note that typically this won't make much difference to the resulting
+ calibration, since it depends primarily on the underlying spectral
+ characteristics of the display.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="E"></a>The <b>-E</b> parameter allows overriding the <span
+ style="font-weight: bold;">ccmx/ccss</span> files overall
+ description tag. Normally this is not necessary. With most command
+ line shells, it will be necessary to enclose the parameter with
+ double quotes, so that spaces and other special characters are
+ included in the parameter, and not mistaken for the start of another
+ flag, or as a final command line parameter. <br>
+ <br>
+ <a name="I"></a>The <b>-I</b> parameter allows setting of the
+ display description string in the resulting <span
+ style="font-weight: bold;">ccmx/ccss</span> file. Since the
+ default display description is probably very generic, it is <span
+ style="font-weight: bold;">highly recommended</span> that a
+ description of the make and model of the display be provided here,
+ or set a display technology description using <span
+ style="font-weight: bold;">-T</span> (see below). The default or
+ given display description will be printed before the menu. With most
+ command line shells, it will be necessary to enclose the parameter
+ with double quotes, so that spaces and other special characters are
+ included in the parameter, and not mistaken for the start of another
+ flag, or as a final command line parameters.<br>
+ <br>
+ <a name="T"></a>The <b>-T</b> parameter allows setting of the
+ display technology description string in the resulting <span
+ style="font-weight: bold;">ccmx/ccss</span> file. The
+ applicability of the calibration mainly depends on the technology
+ type of the display, so a description of the technology (ie. "CRT",
+ "LCD", "LCD + backlight type + LCD type",&nbsp; etc.) is <span
+ style="font-weight: bold;">highly recommended</span>, because it
+ can make the calibration more widely usable. With most command line
+ shells, it will be necessary to enclose the parameter with double
+ quotes, so that spaces and other special characters are included in
+ the parameter, and not mistaken for the start of another flag, or as
+ a final command line parameters.<br>
+ <br>
+ <a name="U"></a>The <b>-U</b> parameter allows setting of the user
+ interface selection character this display type can be selected by,
+ if installed. This character will only be used if there is no clash
+ with any preceding selections. Characters in the range 0-9, A-Z a-z
+ can be used.<br>
+ <br>
+ <a name="Yrn"></a>The -<span style="font-weight: bold;">Y r </span>and
+
+
+
+
+
+
+
+
+ <b>-Y n</b> options overrides the refresh display mode set by the <a
+ href="file:///D:/src/argyll/doc/spotread.html#y">-y display type
+ selection</a>, with <b>-Y</b><span style="font-weight: bold;"> r</span>
+ forcing refresh display mode, and <b>-Y n</b> forcing a non-refresh
+ display mode. Not all instruments support a display measurement
+ refresh mode, or the ability to override the mode set by the display
+ type selection.<br>
+ <br>
+ <a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
+ option uses a non-adaptive integration time emission measurement
+ mode, if the instrument supports it, such as the Eye-One Pro or
+ ColorMunki. By default an adaptive integration time measurement mode
+ will be used for emission measurements, but some instruments support
+ a fixed integration time mode that can be used with display devices.
+ This may give increased consistency and faster measurement times,
+ but may also give less accurate low level readings.<br>
+ <br>
+ <a name="file1"></a>The <span style="font-weight: bold; font-style:
+ italic;">correction.ccmx</span> is the name of the file to save
+ the resulting <a href="File_Formats.html#.ccmx">Colorimeter
+ Correction Matrix</a> to. It is best to give it a short but
+ informative name that includes the Colorimeter model and the display
+ make and model. By convention it should have a <span
+ style="font-weight: bold;">.ccmx</span> file extension.<br>
+ <br>
+ <a name="file2"></a>The <span style="font-weight: bold; font-style:
+ italic;">correction.ccss</span> is the name of the file to save
+ the resulting <a href="File_Formats.html#.ccss">Colorimeter
+ Calibration Spectral Samples</a> to. It is best to give it a short
+ but informative name that includes the display technology or model.
+ By convention it should have a <span style="font-weight: bold;">.ccss</span>
+ file extension.<br>
+ <br>
+ If you are going to use the same CCMX or CCSS file all the time,
+ then you may want to set the <a href="Environment.html">ARGYLL_COLMTER_CAL_SPEC_SET</a>
+ environment variable.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3>Instrument Communications:</h3>
+ Unlike the other measurement utilities,<span style="font-weight:
+ bold;"> ccxxmake</span> doesn't connect to the instrument until it
+ is about to make a measurement. This allows for the possibility of
+ using a different instrument for each measurement.<br>
+ <br>
+ It will display a menu:<span style="font-style: italic;"></span><br>
+ <br>
+ Press 1 .. 4:<br>
+ 1) Select an instrument, Currently 1 'usb:/bus4/dev2/ (GretagMacbeth
+ i1 Pro)'<br>
+ 2) Measure test patches with current instrument<br>
+ 3) [ Compute Colorimeter Correction Matrix &amp; save it ]<br>
+ 4) Exit<br>
+ <br>
+ For creating a CCMX there are two measurements to be made, after
+ which the correction matrix can be computed and saved. Before each
+ measurement, the instrument may need calibrating. For creating a
+ CCSS a single measurement is needed.<br>
+ <br>
+ &nbsp;A spectral measurement using a spectral instrument is always
+ needed.<br>
+ <br>
+ &nbsp;A measurement using the Colorimeter that the correction matrix
+ is being created for is needed in the case of creating a CCMX, but <span
+ style="font-weight: bold;">not</span> needed when creating a CCSS.<br>
+ <br>
+ There will be a message before the menu indicating which of the
+ measurements has been completed.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h4>Display Setup:</h4>
+ Because ccmx/ccss is measuring spectral matching, the exact levels
+ of each channel is not important, so the display settings or
+ calibration state shouldn't make any difference to the result, as
+ long as it is the same for the readings of both instruments.
+ Similarly, the number and variety of test patches shouldn't make a
+ huge difference, as long as there is at least Red, Green, Blue and
+ White test patches.<br>
+ &nbsp;<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/chartread.html b/doc/chartread.html
new file mode 100644
index 0000000..18d0144
--- /dev/null
+++ b/doc/chartread.html
@@ -0,0 +1,499 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>chartread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/chartread</b></h2>
+ <h3>Summary</h3>
+ Read a printer test chart using an instrument, to create a&nbsp;<a
+ href="File_Formats.html#.ti3">.ti3</a> data file. The type of
+ instrument is determined by the communication port selected.<br>
+ <br>
+ <span style="font-weight: bold;">chartread</span> can also be used
+ to read transmission values, and to read display values manually.<br>
+ <h3>Usage</h3>
+ <small><span style="font-family: monospace;">chartread [-options]
+ outfile</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+Verbose
+
+
+ mode</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c listno</a><span
+ style="font-family: monospace;"> &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Set communication port from the following
+ list (default 1)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#t">-t</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+Use
+transmission
+
+
+ measurement mode<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#d">-d</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+display
+measurement
+
+
+ mode (white Y relative results)</span></small><small><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;"><br>
+ &nbsp;</span></small><font size="-1"><span style="font-family:
+ monospace;"><a href="#y">-y X</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Display type - instrument specific list to choose from.</span></font><br>
+ <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#e">-e</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+emissive&nbsp;
+measurement
+
+
+ mode (absolute results)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p">-p</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Measure
+patch
+by
+
+
+ patch rather than strip</span></small><br>
+ <small><span style="font-family: monospace;"></span>&nbsp; <a
+ style="font-family: monospace;" href="#x">-x [lx]</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Take
+external
+values,
+
+
+ either L*a*b* (-xl) or XYZ (-xx).</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#n">-n</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+Don't
+
+
+ save spectral information (default saves spectral)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#l">-l</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; Save CIE as D50 L*a*b* rather than XYZ<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#L">-L</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; Save CIE as D50 L*a*b* as well as XYZ</span></small><br>
+ <small><span style="font-family: monospace;">&nbsp;<a href="#r">-r</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Resume
+reading
+partly
+
+
+ read chart<br>
+ &nbsp;<a href="#I">-I</a>
+ file.cal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Override
+ calibration info from .ti2 in resulting .ti3<br>
+ &nbsp;</span></small><font size="-1"><span style="font-family:
+ monospace;"><a href="#F">-F filter</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Set filter configuration:<br>
+ &nbsp;
+ n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ None<br>
+ &nbsp;
+ p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Polarising filter<br>
+ &nbsp;
+ 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ D65<br>
+ &nbsp;
+ u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ U.V. Cut</span></font><small><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span></small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#N">-N</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; Disable initial calibration of instrument unless
+ essential<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#B">-B</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; Disable auto bi-directional strip recognition</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#H">-H</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; Use high resolution spectrum mode (if available)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span></font><font size="-1"><span
+ style="font-family: monospace;"><a href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+ Apply Colorimeter Correction Matrix</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
+ file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+Colorimeter
+Calibration
+Spectral
+Samples
+
+
+
+ for calibration</span><br>
+ <small><span style="font-family: monospace;">&nbsp;</span><a style="
+ font-family: monospace;" href="#Q">-Q observ</a><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Choose CIE Observer for
+ spectral data or CCSS instrument:</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span></small><small><span
+ style="font-family: monospace;">1931_2 </span></small><small><span
+ style="font-family: monospace;"> (def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2</span></small><small><span style="font-family:
+ monospace;"></span></small><font size="-1"><span
+ style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;"> &nbsp;<a
+ href="#T">-T ratio</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Modify
+strip
+patch
+
+
+ consistency tolerance by ratio (if available)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#S">-S</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Suppress
+wrong
+strip
+
+
+ &amp; unexpected value warnings</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+
+
+ serial port flow control: n = none, h = HW, x = Xon/Xoff</span></font><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><small
+ style="font-family: monospace;">&nbsp;<a href="#D">-D [level]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Print debug
+ diagnostics to stderr</small><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p1"><i>inoutfile</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ &nbsp;Base name for input[</span><a style="font-family:
+ monospace;" href="File_Formats.html#.ti2">.ti2</a><span
+ style="font-family: monospace;">]/output[</span><a
+ style="font-family: monospace;" href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">] file</span></small> <br>
+ <h3>Usage Details</h3>
+ <a name="v"></a>The <b>-v</b> flag causes extra information to be
+ printed out during chartread operation.<br>
+ <br>
+ <a name="c"></a>Normally instruments are connected via a serial
+ communication port, and the port used should be selected by
+ supplying the correct parameter to the <b>-c</b> flag. If you
+ invoke <span style="font-weight: bold;">chartread</span> so as to
+ display the usage information (i.e. "chartread -?" or "chartread
+ --"), then the discovered serial ports will be listed on Windows and
+ Mac OSX systems.<br>
+ <br>
+ <a name="t"></a>If using an Xrite DTP41T, and printing onto
+ transparent or back lit media, use the <b>-t</b> flag to operate
+ the instrument in transparency mode. If using a Spectrolino or
+ Eye-One Pro (handheld), this triggers a fake transparency mode, that
+ uses a separate backlight (such as a light box). The&nbsp;
+ instrument will be used to calibrate the level of backlight, and use
+ this to compute the transparency of the test chart samples. Note
+ that for good transparency values, the backlight level needs to be
+ neither too bright not too dark, should ideally be incandescent
+ rather than fluorescent (since fluorescent lights often have big
+ dips in their spectrum), and ideally should be of uniform brightness
+ over the measurement area. If using the SpectroScanT, the <span
+ style="font-weight: bold;">-t</span> flag operates the instrument
+ in transparency mode, each reading being manually triggered.<br>
+ <br>
+ <a name="d"></a>The <span style="font-weight: bold;">-d</span> flag
+ allows measuring in display mode using instruments that support this
+ mode, with the brightness normalized to the white patch value in the
+ test chart. While the brightness values are then relative to the
+ white, the readings are otherwise absolute. This corresponds to the
+ raw ICC absolute readings created by <a href="dispread.html">dispread</a>,
+ and is the mode that should be used for creating a normal display
+ ICC profile using manual, spot by spot readings. This can be useful
+ if the display cannot be driven directly by the computer, but can be
+ made manually to display the test charts.<br>
+ <br>
+ <a name="y"></a>&nbsp; The <span style="font-weight: bold;">-y</span>
+ flag allows setting the Display Type. The selection typically
+ determines two aspects of of the instrument operation: <span
+ style="font-weight: bold;">1)</span> It may set the measuring mode
+ to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument calibration matrix suitable for a particular display
+ type. The selections available depends on the type and model of
+ instrument, and a list of the options for the discovered instruments
+ will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. <b>3)</b> Any installed CCSS files
+ (if applicable), or CCMX files. These files are typically created
+ using <a href="ccxxmake.html">ccxxmake</a>, and installed using <a
+ href="oeminst.html">oeminst</a>. The default and Base Calibration
+ types will be indicated in the usage.<br>
+ <br>
+ <a name="e"></a> If using an instrument that supports an emissive
+ measurement mode (such as the Spectrolino), then the <span
+ style="font-weight: bold;">-e</span> flag enables this measurement
+ mode, and the values recorded will be absolute XYZ values. This can
+ be used for media such as backlit film, measuring it on a lightbox,
+ so as to capture the actual illumination characteristics of that
+ particular media. An adaptive integration time will be used in
+ devices that support it. <br>
+ <br>
+ <a name="p"></a> The <span style="font-weight: bold;">-p</span>
+ flag causes chartread to use a spot read mode for an instrument,
+ even if it is capable of faster chart reading modes such as strip
+ reading. This can be useful if strip measurement patch recognition
+ is not reliable for certain media.<br>
+ <br>
+ <a name="x"></a> The <span style="font-weight: bold;">-x</span>
+ flag causes chartread to expect values to be entered for each
+ reading, rather than using an instrument to do the
+ measurements.&nbsp; This mode is ideal if your instrument is not
+ supported by Argyll. Either XYZ or L*a*b* values can be entered,
+ depending on what option follows <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-l</span></span>, <span
+ style="font-weight: bold;">-lx</span> to specify XYZ values, or <span
+ style="font-weight: bold;">-ll</span> to specify L*a*b* values.
+ XYZ values are expected to be scaled to a maximum of 100. It is
+ possible to navigate about the test values being measured, so as to
+ do them in any order, as well as re-do values, in case of any
+ mistakes.<br>
+ <br>
+ <a name="n"></a> <span style="font-weight: bold;">-n</span> By
+ default spectral information as well as D50 standard observer XYZ
+ values will be recorded for each test patch, when such readings are
+ available from a device. The spectral readings allow for choosing a
+ non-standard viewing illuminant, a non-standard observer model, or
+ the use of the Fluorescent Paper Whitener Additive compensation when
+ creating the profile. If the spectral readings are not needed, then
+ prinread operation can be speeded up by specifying the <b>-n</b>
+ flag.<br>
+ <br>
+ <a name="l"></a> <span style="font-weight: bold;">-l</span> By
+ default D50 standard observer XYZ values will be recorded for each
+ test patch, but if the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-l</span></span> flag is used, D50
+ L*a*b* values will be recorded instead.<br>
+ <br>
+ <a name="L"></a> <span style="font-weight: bold;">-L</span> By
+ default D50 standard observer XYZ values will be recorded for each
+ test patch, but if the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-L</span></span> flag is used, XYZ <span
+ style="font-weight: bold;">and&nbsp;</span>D50 L*a*b* values will
+ be recorded.<br>
+ <br>
+ <a name="r"></a> <span style="font-weight: bold;">-r</span> By
+ default chartread reads the chart from scratch each time. When
+ reading a chart using a strip instrument or patch by patch you can
+ choose to finish chartread without reading all the patches, and
+ whatever patches have been read will be saved to the output .ti3
+ file. You can then <span style="text-decoration: underline;">resume</span>
+ reading the patches by using the <span style="font-weight: bold;">-r</span>
+ flag, in which case chartread will read the .ti3 file and set the
+ patches to those previously read values, allowing any unread patches
+ to then be read, or to re-read previously read patches.<br>
+ <br>
+ <a name="I"></a> <span style="font-weight: bold;">-I</span> <span
+ style="font-style: italic;">file.cal</span>&nbsp; Normally per
+ channel calibration curves are added to the .ti2 file using the <span
+ style="font-weight: bold;">printtarg -K</span> or <span
+ style="font-weight: bold;">-I</span> options, so that they will be
+ passed on to the .ti3 file by&nbsp; <span style="font-weight:
+ bold;">chartread</span>, so that <span style="font-weight: bold;">colprof</span>
+ is able to correctly compute total ink limits. Where the calibration
+ is being applied in a workflow with native calibration capability<small><span
+ style="font-family: monospace;"></span></small> though, it is
+ sometimes convenient to re-use a profile chart with different
+ calibration curves without going through the process of using <span
+ style="font-weight: bold;">printtarg</span> to re-create it. This
+ would mean though, that the calibration information and subsequent
+ ink limit calculations wouldn't be accurate. To overcome this and
+ allow such a scenario, the <span style="font-weight: bold;">chartread
+
+ -I</span> parameter allows overriding the .ti2 calibration curves
+ placed in the resulting .ti3 file with the actual calibration that
+ was used for that particular print.<br>
+ <br>
+ <a name="F"></a>The <b>-F</b> options allows configuring the
+ instrument to have a particular filter fitted to it. Some
+ instruments (i.e. the Gretag Spectrolino) allow the fitting of
+ various filters, such as a polarizing filter, D65 illuminant
+ simulation, or Ultra Violet Cut filter, and this option allows the
+ instrument to be configured appropriately.<br>
+ <br>
+ <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="B"></a> <span style="font-weight: bold;">-B</span> Some
+ strip instruments (i.e.. Eye-One Pro, Color Munki) when used with
+ Argyll will automatically recognize a strip when read in the reverse
+ direction by matching the patch readings against their expected
+ values. If the randomized patch layout has not been used, or the
+ expected values are not known accurately enough, this may cause
+ erroneous reverse recognition, so the <span style="font-weight:
+ bold;">-<span style="font-weight: bold;">B</span></span> flag
+ allows this to be turned off, forcing strips to only be read in the
+ forward direction.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it. See <a href="instruments.html">Operation of particular
+ instruments</a> for more details.<br>
+ <br>
+ <a name="X1"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccmx</span></span> option reads
+ a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
+ from the given file, and applies it to the colorimeter instruments
+ readings. This can improve a colorimeters accuracy for a particular
+ type of display. A list of contributed <span style="font-weight:
+ bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
+ <br>
+ <a name="X2"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccss</span></span> option reads
+ a <a href="File_Formats.html#.ccss">Colorimeter Calibration
+ Spectral Sample</a> from the given file, and uses it to set the
+ colorimeter instruments calibration. This will only work with
+ colorimeters that rely on sensor spectral sensitivity calibration
+ information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
+ or the DataColor <span style="font-weight: bold;">Spyder4</span>).This
+can
+improve
+a
+
+
+ colorimeters accuracy for a particular type of display.<br>
+ <br>
+ <a name="T"></a> The -<span style="font-weight: bold;">T ratio</span>
+ argument modifies the patch consistency tolerance threshold for some
+ strip reading instruments (ie. the Eye-One Pro). In recognizing
+ patches in a strip, an instrument may take multiple readings as the
+ strip is read, and then divide the readings up into each patch. It
+ may then check the consistency of the multiple readings
+ corresponding to each patch, and reject the measurement if they are
+ too inconsistent. For some media (ie. a coarser screens, fabric
+ etc.) the default tolerance may be unreasonably tight, so the <span
+ style="font-weight: bold;">-T ratio</span> argument can be used to
+ modify this criteria. To loosen the tolerance, use a number greater
+ than 1.0 (ie. 1.5, 2.0).<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
+ observer for a colorimeter when using CCSS instrument calibration
+ capability. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ <br>
+ <a name="S"></a>The <b>-S</b> flag causes the normal "wrong strip"
+ and "unexpected value" warnings to be suppressed. There may be a lot
+ of these warnings if the expected patch value in the .ti2 file is in
+ fact far from the values actually being measured. It is probably
+ advisable to also use the <span style="font-weight: bold;">-B</span>
+ flag if warnings are turned off, since many warnings indicate that
+ the expected values are not to be relied on. With warnings
+ suppressed, greater care must be taken to read the correct strip.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="p1"></a> The <i>inoutfile</i> parameters should be the
+ base name of the .ti2 file, and chartread will output an .ti3 that
+ has the same basename and the .ti3 extension. If the incoming .ti2
+ file contains per-channel calibration curves, these will be passed
+ through to the .ti3 so that accurate ink limits can be computed
+ during profiling.<br>
+ <br>
+ <hr style="width: 50%; height: 2px;">
+ <h3>Discussion</h3>
+ For information about the operation of different instruments, see <a
+ href="instruments.html">Operation of particular instruments</a>.<br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/cht_format.html b/doc/cht_format.html
new file mode 100644
index 0000000..1e02db1
--- /dev/null
+++ b/doc/cht_format.html
@@ -0,0 +1,576 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Scan Recognition Format File (.cht)</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2>Description of the .cht format</h2>
+[This is a rather inflexible format, that should really be replaced
+with a CGATS style file.]<br>
+<br>
+The <span style="font-weight: bold;">.cht</span> format file is used
+to hold the image recognition information that allows the <a
+ href="scanin.html">scanin</a> program to align the input image with
+the specified sample boxes.<br>
+<br>
+A raw <span style="font-weight: bold;">.cht</span> file can be
+produced by running <a href="scanin.html">scanin</a>
+with the <a href="scanin.html#g">-g</a> option, although this will
+then need
+cleaning up manually, using a text editor. The cleanup consists of
+deleting
+any unwanted reference lines from the XLIST and YLISTs, adding the the
+sample
+box references, and possibly adding the expected sample values.<br>
+<br>
+The <span style="font-weight: bold;">.cht</span> image recognition
+file is usually set up to recognized a scanned test chart that includes
+the edges of the chart itself, <span style="font-weight: bold;">not</span>
+a cropped version of the chart that excludes the edges of the chart
+itself. This is to allow <span style="font-weight: bold;">scanin</span>
+to be used with scans that have just be roughly cropped, without
+requiring that a scan be treated in detail with an application such as
+Adobe Photoshop.<br>
+<br>
+The keywords and associated data must be used in the following order: <b>BOXES</b>,
+<b>BOX_SHRINK</b>, <b>REF_ROTATION</b>, <b>XLIST</b>, <b>YLIST</b>
+and <b>EXPECTED</b>.<br>
+<br>
+The physical units used for boxes and edge lists are arbitrary units
+(i.e.
+pixels as generated by scanin -g, but could be mm, inches etc. if
+created
+&nbsp;some other way), the only requirement is that the sample box
+definitions need to agree with the X/YLIST definitions. Typically if a
+scanned chart is used to build the reference, the units will be pixels
+of the scanned chart.<br>
+<br>
+The <b>BOXES</b> keyword introduces the list of diagnostic and sample
+boxes.
+The integer following this keyword must be the total number of
+diagnostic
+and sample boxes, but <span style="font-weight: bold;">not</span>
+including any fiducual marks. The lines following the BOXES keyword must
+then
+contain
+the fiducial mark, diagnostic or sample box definitions. Each box
+definition line
+consists
+of 11 space separated parameters, and can generate a grid of sample or
+diagnostic
+boxes:<br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>kl lxs lxe lys lye w h xo yo xi yi</b><br>
+<br>
+with the following usage:<br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>kl</b> is a key letter.<br>
+<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">F</span>
+is used to define four fiducial mZarks that may be used for manual
+alignment of an image to the target. The four marks are nominally a
+top left mark, a top right mark, bottom right mark and a bottom left
+mark. The parameters are labeled as follows:<br>
+&nbsp;<b><br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; </b><b>F _ _ x0 y0 x1 y1 x2 y2
+x3 y3<br>
+<br>
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; </b>Where the first two
+parameters are not used, and a '_' character should be used as
+a place holder, and the follows the X and Y coordinates for the four
+fiducial marks.<span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span> Typically fiducial marks are chosen
+to be at the corners of the overall bounding box, or at corner cross
+marks on the chart etc. Fiducial marks may be omitted, but in this case
+manual alignment cannot be used.<br>
+<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<b>D</b> is used for a diagnostic
+box which will show up in the diagnostic raster output, but is not used
+as
+a sample box.&nbsp; The label information can be arbitrary.<br>
+&nbsp;&nbsp; &nbsp;<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<b>X</b> is used for a sequence
+of boxes in which the X label comes first in the concatenated sample
+box label.<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<b>Y</b> is used for a sequence
+of boxes in which the Y label comes first in the concatenated sample
+box label.<br>
+<br>
+&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Boxes are created incrementing in
+the X direction fastest, and the Y direction slowest.<br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>lxs</b> is the X axis starting label. This is
+generally a letter or number, and it will be incremented appropriately
+to reach <b>lxe</b><br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>lxe</b> is the X axis ending label. When the X
+label reaches this this value (inclusively), the iteration in the X
+direction will reset.<br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>lys</b> is the Y axis starting label. This is
+generally a letter or number, and it will be incremented appropriately
+to reach <b>lye</b><br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>lye</b> is the Y axis ending label. When the Y
+label reaches this this value (inclusively), the iteration through the
+boxes will end.<br>
+<br>
+&nbsp;&nbsp; &nbsp;The X &amp; Y labels will be concatenated to form
+the sample box label.<br>
+<br>
+&nbsp;&nbsp; &nbsp;A sample label that consists of the character '_' is
+treated as a null label (useful for an array that only iterates in one
+direction).<br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>w</b>,<b> h</b> are the width and height of each
+box in the array.<br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>xo</b>, <b>yo</b> are the origin of the top
+left
+of the array.<br>
+<br>
+&nbsp;&nbsp; &nbsp;<b>xi</b>, <b>yi</b> are the increments between
+each
+box in the array.<br>
+<br>
+A blank line should follow the last box definition line.<br>
+<br>
+The keyword <b>BOX_SHRINK</b> marks the definition of how much each
+sample
+box should be shrunk on each edge before sampling the pixel values.
+This
+allows the sample boxes to be defined at their edges, while allowing a
+safety
+margin for the pixels actually sampled. The units are the same
+arbitrary units
+used for the sample box definitions.<br>
+<br>
+A blank line should follow this keyword.<br>
+<br>
+The optional <b>REF_ROTATION</b> keyword indicates the rotation in
+radians
+clockwise of the reference image when the edge lists were generated.
+This
+amount of rotation is undone to the image before applying the sample
+box
+location information. The rotation is about the origin
+(the
+origin is assumed to be upper left corner). If omitted, the reference
+rotation
+is assumed to be 0.0<br>
+<br>
+A blank line should follow this keyword.<br>
+<br>
+The <b>XLIST</b> is a list of vertical edge reference "ticks", along
+the
+X axis. Ticks are just edge transitions, typically being each edge of
+the sample boxes, but should include edges of any features that have
+significant width and a length that is at least 50% of the available
+space. It is these edge ticks that are used to locate the reference
+cells position within the input raster. The integer after the keyword
+"XLIST" is the number of entries
+in
+the list. The first number in the column is the offset of the tick from
+the
+origin, the second number is used to improve the correlation by
+representing
+the strength of that "tick" relative to the strongest tick which will
+have
+a value 1.0. Strength is measured by the relative length of the edge.<br>
+<br>
+The third number represents the relative number of times this "tick" is
+crossed by lines in the other direction. A line is regarded as crossing
+if part of it is closer to the "tick" line that half the distance to
+the next tick line. The number is normalized so that the largest
+crossing count has a weight of
+1.0. This may be set to 1.0 if it is not known or easily computed.<br>
+<br>
+A blank line should follow the last <b>XLIST</b> edge definition.<br>
+<br>
+The <b>YLIST</b> is same format and details as the <b>XLIST</b>, used
+for
+horizontal edges.<br>
+<br>
+The <b>EXPECTED</b> keyword introduces an optional list of <span
+ style="text-decoration: underline;">approximate</span>
+expected
+sample
+box color values, allowing better identification of the possible
+rotation
+of a chart, particularly if it has no asymmetric patch shapes or
+locations
+in the chart. Following the keyword should either be <b>XYZ</b> or <b>LAB</b>,
+depending on the color space used to describe the reference values,
+then
+an integer indicating the number of entries in the list.<br>
+<br>
+Each following expected color entry consists of four values. The first
+is
+the sample box label, which should correspond to one of those defined
+by
+the <b>BOXES</b> entry above. It is an error if no corresponding box
+has
+been defined. The remaining three values are the <span
+ style="text-decoration: underline;">approximate</span> XYZ or
+L*a*b*
+color value expected for that sample box. The XYZ values are assumed to
+be
+scaled to a maximum Y value of 100. An expected color value doesn't
+have
+to be provided for every defined sample box, nor is it expected to be
+accurate - it just has to represent the approximate expected color.
+(Actual chart reference values are provided as a separate CGATS file to
+<a href="scanin.html"><span style="font-weight: bold;">scanin</span></a>).<br>
+<br>
+A blank line should follow the last <b>EXPECTED</b> box value.<br>
+<br>
+<br>
+<hr size="2" width="100%"><br>
+The following is an example .cht file, suitable for a typical Q60 IT8
+scan target.<br>
+<tt><br>
+<font size="-1"> BOXES 290<br>
+&nbsp; F _ _ _ _ 1 1&nbsp; 615.5 1.5&nbsp; 615 409<br>
+&nbsp; D ALL ALL _ _ 615 409 1 1 0 0<br>
+&nbsp; D MARK MARK _ _ 14 14 1 1 0 0<br>
+&nbsp; Y 01 22 A L 25.625 25.625 26.625 26.625 25.625 25.625<br>
+&nbsp; X GS00 GS23 _ _ 25.625 51.25 0.0 358.75 25.625 0.0<br>
+<br>
+BOX_SHRINK 3.0<br>
+<br>
+REF_ROTATION -0.002006<br>
+<br>
+XLIST 32<br>
+&nbsp; 1.799625 1.000000 0.312500<br>
+&nbsp; 27.064987 0.874039 0.750000<br>
+&nbsp; 52.592403 0.133439 0.687500<br>
+&nbsp; 78.196610 0.264191 0.687500<br>
+&nbsp; 104.117756 0.165427 0.937500<br>
+&nbsp; 129.377994 0.844432 0.937500<br>
+&nbsp; 155.144274 0.501218 0.875000<br>
+&nbsp; 180.839181 0.491428 0.937500<br>
+&nbsp; 206.359758 0.212384 0.937500<br>
+&nbsp; 232.038808 0.851851 0.937500<br>
+&nbsp; 257.854725 0.162956 0.625000<br>
+&nbsp; 283.552463 0.101243 0.812500<br>
+&nbsp; 300.534000 0.024750 0.812500<br>
+&nbsp; 309.507688 0.093829 1.000000<br>
+&nbsp; 334.711314 0.856821 1.000000<br>
+&nbsp; 360.428194 0.787677 1.000000<br>
+&nbsp; 385.849730 0.748130 0.937500<br>
+&nbsp; 386.650071 0.039487 0.687500<br>
+&nbsp; 394.630372 0.024725 0.687500<br>
+&nbsp; 411.835654 0.802501 0.750000<br>
+&nbsp; 414.017731 0.041974 0.937500<br>
+&nbsp; 437.133504 0.674062 0.937500<br>
+&nbsp; 437.975355 0.103714 1.000000<br>
+&nbsp; 462.938460 0.671643 1.000000<br>
+&nbsp; 463.880560 0.093836 0.937500<br>
+&nbsp; 488.517995 0.679022 1.000000<br>
+&nbsp; 514.338544 0.760511 1.000000<br>
+&nbsp; 540.037492 0.111108 0.625000<br>
+&nbsp; 565.856396 0.133330 0.562500<br>
+&nbsp; 591.114717 0.565475 0.562500<br>
+&nbsp; 603.447516 0.032097 0.312500<br>
+&nbsp; 615.984915 0.829608 0.250000<br>
+<br>
+YLIST 22<br>
+&nbsp; 2.477956 0.993407 0.142857<br>
+&nbsp; 12.988903 0.016393 0.190476<br>
+&nbsp; 14.739109 0.036082 0.190476<br>
+&nbsp; 26.746171 0.911487 0.428571<br>
+&nbsp; 52.537114 0.303282 0.904762<br>
+&nbsp; 78.060317 0.585303 0.857143<br>
+&nbsp; 103.498271 0.606862 0.761905<br>
+&nbsp; 128.994535 0.567266 0.761905<br>
+&nbsp; 154.483041 0.550814 0.714286<br>
+&nbsp; 179.935985 0.623055 0.666667<br>
+&nbsp; 205.552940 0.350826 0.714286<br>
+&nbsp; 212.051372 0.016393 0.714286<br>
+&nbsp; 231.153547 0.824618 0.857143<br>
+&nbsp; 256.697418 0.744268 0.952381<br>
+&nbsp; 282.145841 0.736126 0.904762<br>
+&nbsp; 307.899015 0.536075 0.952381<br>
+&nbsp; 333.262903 0.903282 0.809524<br>
+&nbsp; 340.217754 0.019722 0.190476<br>
+&nbsp; 344.988867 0.019671 0.095238<br>
+&nbsp; 346.988885 0.018032 0.095238<br>
+&nbsp; 358.840278 0.999967 1.000000<br>
+&nbsp; 409.201393 1.000000 0.000000<br>
+<br>
+EXPECTED XYZ 264<br>
+&nbsp; A1&nbsp;&nbsp;&nbsp; 3.85 3.22 1.9<br>
+&nbsp; A2&nbsp;&nbsp;&nbsp; 4.89 3.27 1.6<br>
+&nbsp; A3&nbsp;&nbsp;&nbsp; 5.87 3.31 1.33<br>
+&nbsp; A4&nbsp;&nbsp;&nbsp; 6.3 3.38 1.19<br>
+&nbsp; A5&nbsp;&nbsp;&nbsp; 13.01 11.44 7.64<br>
+&nbsp; A6&nbsp;&nbsp;&nbsp; 16.14 11.99 6.81<br>
+&nbsp; A7&nbsp;&nbsp;&nbsp; 19.35 12.41 6.06<br>
+&nbsp; A8&nbsp;&nbsp;&nbsp; 20.41 11.97 5.3<br>
+&nbsp; A9&nbsp;&nbsp;&nbsp; 43.5 42.81 32.65<br>
+&nbsp; A10&nbsp;&nbsp; 45.58 42.37 30.95<br>
+&nbsp; A11&nbsp;&nbsp; 48.99 43.2 29.9<br>
+&nbsp; A12&nbsp;&nbsp; 50.73 44.02 29.96<br>
+&nbsp; A13&nbsp;&nbsp; 74.46 78.76 66.06<br>
+&nbsp; A14&nbsp;&nbsp; 75.66 76.42 64.08<br>
+&nbsp; A15&nbsp;&nbsp; 78.36 81.34 65.41<br>
+&nbsp; A16&nbsp;&nbsp; 70.52 73.3 59.16<br>
+&nbsp; A17&nbsp;&nbsp; 74.98 75.98 60.69<br>
+&nbsp; A18&nbsp;&nbsp; 72.85 77.3 60.25<br>
+&nbsp; A19&nbsp;&nbsp; 73.09 75.52 64.54<br>
+&nbsp; B1&nbsp;&nbsp;&nbsp; 3.47 3.08 1.41<br>
+&nbsp; B2&nbsp;&nbsp;&nbsp; 4.41 3.25 0.9<br>
+&nbsp; B3&nbsp;&nbsp;&nbsp; 5.04 3.23 0.58<br>
+&nbsp; B4&nbsp;&nbsp;&nbsp; 5.19 3.11 0.47<br>
+&nbsp; B5&nbsp;&nbsp;&nbsp; 13.36 11.59 5.56<br>
+&nbsp; B6&nbsp;&nbsp;&nbsp; 15.97 12.03 3.69<br>
+&nbsp; B7&nbsp;&nbsp;&nbsp; 19.2 12.49 2.2<br>
+&nbsp; B8&nbsp;&nbsp;&nbsp; 19.73 11.52 1.17<br>
+&nbsp; B9&nbsp;&nbsp;&nbsp; 42.19 41.84 29.34<br>
+&nbsp; B10&nbsp;&nbsp; 44.83 42.17 25.93<br>
+&nbsp; B11&nbsp;&nbsp; 48.06 42.9 23.01<br>
+&nbsp; B12&nbsp;&nbsp; 49.63 43.08 21.34<br>
+&nbsp; B13&nbsp;&nbsp; 66.21 72.54 64.61<br>
+&nbsp; B14&nbsp;&nbsp; 70.16 67.1 60.33<br>
+&nbsp; B15&nbsp;&nbsp; 75.46 78.69 51.58<br>
+&nbsp; B16&nbsp;&nbsp; 57.47 59.58 47.66<br>
+&nbsp; B17&nbsp;&nbsp; 68.33 66.45 49.05<br>
+&nbsp; B18&nbsp;&nbsp; 63.89 70.29 51.3<br>
+&nbsp; B19&nbsp;&nbsp; 61.12 62.16 59.79<br>
+&nbsp; C1&nbsp;&nbsp;&nbsp; 4.97 4.75 1.98<br>
+&nbsp; C2&nbsp;&nbsp;&nbsp; 5.18 4.65 1.23<br>
+&nbsp; C3&nbsp;&nbsp;&nbsp; 5.51 4.58 0.71<br>
+&nbsp; C4&nbsp;&nbsp;&nbsp; 5.77 4.61 0.67<br>
+&nbsp; C5&nbsp;&nbsp;&nbsp; 24.57 23.44 10.14<br>
+&nbsp; C6&nbsp;&nbsp;&nbsp; 28.1 24.64 5.22<br>
+&nbsp; C7&nbsp;&nbsp;&nbsp; 31.15 25.28 2.2<br>
+&nbsp; C8&nbsp;&nbsp;&nbsp; 30.85 23.68 1.35<br>
+&nbsp; C9&nbsp;&nbsp;&nbsp; 49.16 49.36 32.37<br>
+&nbsp; C10&nbsp;&nbsp; 51.72 50.72 26.53<br>
+&nbsp; C11&nbsp;&nbsp; 55.24 53.14 21.93<br>
+&nbsp; C12&nbsp;&nbsp; 56.87 53.62 18.46<br>
+&nbsp; C13&nbsp;&nbsp; 57.68 65.65 62.7<br>
+&nbsp; C14&nbsp;&nbsp; 63.46 56.66 55.49<br>
+&nbsp; C15&nbsp;&nbsp; 73 76.11 40.78<br>
+&nbsp; C16&nbsp;&nbsp; 44.73 46.38 36.8<br>
+&nbsp; C17&nbsp;&nbsp; 60.64 55.73 38.1<br>
+&nbsp; C18&nbsp;&nbsp; 52.15 60.27 41.5<br>
+&nbsp; C19&nbsp;&nbsp; 48.13 49.18 54.38<br>
+&nbsp; D1&nbsp;&nbsp;&nbsp; 4.19 4.41 1.93<br>
+&nbsp; D2&nbsp;&nbsp;&nbsp; 4.48 4.72 1.24<br>
+&nbsp; D3&nbsp;&nbsp;&nbsp; 4.55 4.78 0.8<br>
+&nbsp; D4&nbsp;&nbsp;&nbsp; 4.32 4.53 0.78<br>
+&nbsp; D5&nbsp;&nbsp;&nbsp; 27.33 28.55 12.95<br>
+&nbsp; D6&nbsp;&nbsp;&nbsp; 28.68 30.04 7.25<br>
+&nbsp; D7&nbsp;&nbsp;&nbsp; 29.51 31.01 3.41<br>
+&nbsp; D8&nbsp;&nbsp;&nbsp; 27.55 28.44 1.83<br>
+&nbsp; D9&nbsp;&nbsp;&nbsp; 56.06 58.19 38.21<br>
+&nbsp; D10&nbsp;&nbsp; 56.03 58.46 30.02<br>
+&nbsp; D11&nbsp;&nbsp; 56.2 59.33 24.44<br>
+&nbsp; D12&nbsp;&nbsp; 56.19 59.41 19.14<br>
+&nbsp; D13&nbsp;&nbsp; 48.21 57.42 59.53<br>
+&nbsp; D14&nbsp;&nbsp; 58.18 49.14 51.36<br>
+&nbsp; D15&nbsp;&nbsp; 70.98 73.73 33.63<br>
+&nbsp; D16&nbsp;&nbsp; 34.31 35.73 28.22<br>
+&nbsp; D17&nbsp;&nbsp; 54.27 47.53 29.58<br>
+&nbsp; D18&nbsp;&nbsp; 41.67 50.64 32.28<br>
+&nbsp; D19&nbsp;&nbsp; 36.95 37.82 48.09<br>
+&nbsp; E1&nbsp;&nbsp;&nbsp; 4.15 4.75 2.03<br>
+&nbsp; E2&nbsp;&nbsp;&nbsp; 4 4.98 1.37<br>
+&nbsp; E3&nbsp;&nbsp;&nbsp; 3.3 4.49 0.86<br>
+&nbsp; E4&nbsp;&nbsp;&nbsp; 3.11 4.3 0.86<br>
+&nbsp; E5&nbsp;&nbsp;&nbsp; 13.11 14.9 7.06<br>
+&nbsp; E6&nbsp;&nbsp;&nbsp; 12.26 15.23 4.18<br>
+&nbsp; E7&nbsp;&nbsp;&nbsp; 11.53 15.57 2.27<br>
+&nbsp; E8&nbsp;&nbsp;&nbsp; 9.69 13.74 1.51<br>
+&nbsp; E9&nbsp;&nbsp;&nbsp; 39.15 42.08 27.33<br>
+&nbsp; E10&nbsp;&nbsp; 37.43 41.51 22.23<br>
+&nbsp; E11&nbsp;&nbsp; 36.99 42.5 18.85<br>
+&nbsp; E12&nbsp;&nbsp; 36.4 42.58 16.27<br>
+&nbsp; E13&nbsp;&nbsp; 39.97 49.81 56.15<br>
+&nbsp; E14&nbsp;&nbsp; 52.08 41.07 46.36<br>
+&nbsp; E15&nbsp;&nbsp; 68.71 70.76 26.45<br>
+&nbsp; E16&nbsp;&nbsp; 25.7 26.97 21.28<br>
+&nbsp; E17&nbsp;&nbsp; 48.53 40.6 22<br>
+&nbsp; E18&nbsp;&nbsp; 31.62 40.82 23.35<br>
+&nbsp; E19&nbsp;&nbsp; 31.19 31.19 43.4<br>
+&nbsp; F1&nbsp;&nbsp;&nbsp; 1.51 1.91 1.06<br>
+&nbsp; F2&nbsp;&nbsp;&nbsp; 1.29 2.04 0.98<br>
+&nbsp; F3&nbsp;&nbsp;&nbsp; 1.16 2.09 0.82<br>
+&nbsp; F4&nbsp;&nbsp;&nbsp; 1.14 2.04 0.8<br>
+&nbsp; F5&nbsp;&nbsp;&nbsp; 6.53 8.25 5.13<br>
+&nbsp; F6&nbsp;&nbsp;&nbsp; 5.61 8.66 4.38<br>
+&nbsp; F7&nbsp;&nbsp;&nbsp; 4.6 8.77 3.7<br>
+&nbsp; F8&nbsp;&nbsp;&nbsp; 3.45 7.63 2.78<br>
+&nbsp; F9&nbsp;&nbsp;&nbsp; 37.8 41.07 30.91<br>
+&nbsp; F10&nbsp;&nbsp; 35.92 40.76 29.03<br>
+&nbsp; F11&nbsp;&nbsp; 35.42 41.99 29.07<br>
+&nbsp; F12&nbsp;&nbsp; 34 41.8 28<br>
+&nbsp; F13&nbsp;&nbsp; 32.13 42.12 51.99<br>
+&nbsp; F14&nbsp;&nbsp; 45.72 33.34 40.77<br>
+&nbsp; F15&nbsp;&nbsp; 66.26 67.29 19.65<br>
+&nbsp; F16&nbsp;&nbsp; 17.02 18.07 14.4<br>
+&nbsp; F17&nbsp;&nbsp; 41.59 32.53 15.16<br>
+&nbsp; F18&nbsp;&nbsp; 26.26 35.26 18.81<br>
+&nbsp; F19&nbsp;&nbsp; 24.3 23.6 37.48<br>
+&nbsp; G1&nbsp;&nbsp;&nbsp; 2.31 3 2.27<br>
+&nbsp; G2&nbsp;&nbsp;&nbsp; 2 3.21 2.58<br>
+&nbsp; G3&nbsp;&nbsp;&nbsp; 1.66 3.21 2.75<br>
+&nbsp; G4&nbsp;&nbsp;&nbsp; 1.58 3.03 2.6<br>
+&nbsp; G5&nbsp;&nbsp;&nbsp; 8.99 11.08 8.79<br>
+&nbsp; G6&nbsp;&nbsp;&nbsp; 7.68 11.3 9.56<br>
+&nbsp; G7&nbsp;&nbsp;&nbsp; 6.52 11.5 10.2<br>
+&nbsp; G8&nbsp;&nbsp;&nbsp; 5.5 10.85 10.55<br>
+&nbsp; G9&nbsp;&nbsp;&nbsp; 38.29 41.75 33.45<br>
+&nbsp; G10&nbsp;&nbsp; 35.83 41.16 34.11<br>
+&nbsp; G11&nbsp;&nbsp; 34.56 41.83 35.63<br>
+&nbsp; G12&nbsp;&nbsp; 33.69 42.14 36.7<br>
+&nbsp; G13&nbsp;&nbsp; 25.95 35.68 48<br>
+&nbsp; G14&nbsp;&nbsp; 40.6 27.62 36.14<br>
+&nbsp; G15&nbsp;&nbsp; 63.72 63.63 14.35<br>
+&nbsp; G16&nbsp;&nbsp; 10.85 11.82 9.58<br>
+&nbsp; G17&nbsp;&nbsp; 37.23 27.64 11.62<br>
+&nbsp; G18&nbsp;&nbsp; 20.28 28.97 14.15<br>
+&nbsp; G19&nbsp;&nbsp; 17.7 16.74 31.7<br>
+&nbsp; H1&nbsp;&nbsp;&nbsp; 2.56 3.04 2.92<br>
+&nbsp; H2&nbsp;&nbsp;&nbsp; 2.34 3.2 4.12<br>
+&nbsp; H3&nbsp;&nbsp;&nbsp; 2.12 3.28 5.43<br>
+&nbsp; H4&nbsp;&nbsp;&nbsp; 2.06 3.18 5.29<br>
+&nbsp; H5&nbsp;&nbsp;&nbsp; 10.07 11.6 11.24<br>
+&nbsp; H6&nbsp;&nbsp;&nbsp; 9.01 11.68 14.81<br>
+&nbsp; H7&nbsp;&nbsp;&nbsp; 8.22 12 19.42<br>
+&nbsp; H8&nbsp;&nbsp;&nbsp; 7.25 11.55 21.45<br>
+&nbsp; H9&nbsp;&nbsp;&nbsp; 39.25 42.31 36.81<br>
+&nbsp; H10&nbsp;&nbsp; 37.58 41.85 40.37<br>
+&nbsp; H11&nbsp;&nbsp; 37.16 43.07 45.79<br>
+&nbsp; H12&nbsp;&nbsp; 36.27 43.78 49.47<br>
+&nbsp; H13&nbsp;&nbsp; 21.47 30.78 44.22<br>
+&nbsp; H14&nbsp;&nbsp; 36.49 23.35 32.38<br>
+&nbsp; H15&nbsp;&nbsp; 61.58 60.55 10.95<br>
+&nbsp; H16&nbsp;&nbsp; 8.21 8.71 6.91<br>
+&nbsp; H17&nbsp;&nbsp; 33.04 23.26 8.38<br>
+&nbsp; H18&nbsp;&nbsp; 16.22 24.35 10.41<br>
+&nbsp; H19&nbsp;&nbsp; 12.86 11.84 26.82<br>
+&nbsp; I1&nbsp;&nbsp;&nbsp; 4.22 4.44 5.28<br>
+&nbsp; I2&nbsp;&nbsp;&nbsp; 4.35 4.48 8.36<br>
+&nbsp; I3&nbsp;&nbsp;&nbsp; 4.4 4.44 11.94<br>
+&nbsp; I4&nbsp;&nbsp;&nbsp; 4.48 4.58 12.17<br>
+&nbsp; I5&nbsp;&nbsp;&nbsp; 15.15 15.78 15.23<br>
+&nbsp; I6&nbsp;&nbsp;&nbsp; 14.56 15.12 19.52<br>
+&nbsp; I7&nbsp;&nbsp;&nbsp; 14.37 14.81 24.48<br>
+&nbsp; I8&nbsp;&nbsp;&nbsp; 14.11 14.76 30.03<br>
+&nbsp; I9&nbsp;&nbsp;&nbsp; 41.03 42.58 36.94<br>
+&nbsp; I10&nbsp;&nbsp; 40.85 42.23 40.73<br>
+&nbsp; I11&nbsp;&nbsp; 40.86 42.33 45.05<br>
+&nbsp; I12&nbsp;&nbsp; 41.31 42.73 47.77<br>
+&nbsp; I13&nbsp;&nbsp; 17.26 25.93 40.23<br>
+&nbsp; I14&nbsp;&nbsp; 32.66 19.63 28.81<br>
+&nbsp; I15&nbsp;&nbsp; 59.37 57.18 7.79<br>
+&nbsp; I16&nbsp;&nbsp; 4.97 5.32 4.32<br>
+&nbsp; I17&nbsp;&nbsp; 28.62 18.88 5.48<br>
+&nbsp; I18&nbsp;&nbsp; 11.58 18.98 7.25<br>
+&nbsp; I19&nbsp;&nbsp; 9.58 8.34 22.87<br>
+&nbsp; I20&nbsp;&nbsp; 0.45 0.4 0.33<br>
+&nbsp; I21&nbsp;&nbsp; 2.28 1.78 0.98<br>
+&nbsp; I22&nbsp;&nbsp; 2.37 1.95 0.85<br>
+&nbsp; J1&nbsp;&nbsp;&nbsp; 2.15 1.9 2.6<br>
+&nbsp; J2&nbsp;&nbsp;&nbsp; 2.57 2 4.72<br>
+&nbsp; J3&nbsp;&nbsp;&nbsp; 2.93 1.95 8.1<br>
+&nbsp; J4&nbsp;&nbsp;&nbsp; 3.15 1.92 10.76<br>
+&nbsp; J5&nbsp;&nbsp;&nbsp; 11.73 11.6 11.81<br>
+&nbsp; J6&nbsp;&nbsp;&nbsp; 12.98 11.93 16.19<br>
+&nbsp; J7&nbsp;&nbsp;&nbsp; 13.91 12.07 20.95<br>
+&nbsp; J8&nbsp;&nbsp;&nbsp; 14.01 11.59 24.35<br>
+&nbsp; J9&nbsp;&nbsp;&nbsp; 40.75 41.22 36.34<br>
+&nbsp; J10&nbsp;&nbsp; 41.26 41.07 39.74<br>
+&nbsp; J11&nbsp;&nbsp; 42.63 41.68 44.51<br>
+&nbsp; J12&nbsp;&nbsp; 44.02 41.78 49.25<br>
+&nbsp; J13&nbsp;&nbsp; 13.82 21.69 35.98<br>
+&nbsp; J14&nbsp;&nbsp; 28.87 16.33 25.08<br>
+&nbsp; J15&nbsp;&nbsp; 56.04 52.29 4.97<br>
+&nbsp; J16&nbsp;&nbsp; 2.46 2.63 2.29<br>
+&nbsp; J17&nbsp;&nbsp; 24.04 14.75 3.15<br>
+&nbsp; J18&nbsp;&nbsp; 8.12 14.49 4.55<br>
+&nbsp; J19&nbsp;&nbsp; 5.98 4.79 17.76<br>
+&nbsp; J20&nbsp;&nbsp; 8.26 5.37 1.04<br>
+&nbsp; J21&nbsp;&nbsp; 11.52 7.81 1.62<br>
+&nbsp; J22&nbsp;&nbsp; 14.67 10.72 2.6<br>
+&nbsp; K1&nbsp;&nbsp;&nbsp; 5.63 4.7 4.86<br>
+&nbsp; K2&nbsp;&nbsp;&nbsp; 6.74 4.58 7.23<br>
+&nbsp; K3&nbsp;&nbsp;&nbsp; 8.04 4.48 9.73<br>
+&nbsp; K4&nbsp;&nbsp;&nbsp; 9.39 4.76 11.79<br>
+&nbsp; K5&nbsp;&nbsp;&nbsp; 16.66 15.39 14.44<br>
+&nbsp; K6&nbsp;&nbsp;&nbsp; 18.72 15.18 18.23<br>
+&nbsp; K7&nbsp;&nbsp;&nbsp; 21.56 15.5 22.97<br>
+&nbsp; K8&nbsp;&nbsp;&nbsp; 23 15.02 25.37<br>
+&nbsp; K9&nbsp;&nbsp;&nbsp; 42.5 42.02 36.05<br>
+&nbsp; K10&nbsp;&nbsp; 44.55 41.63 39.71<br>
+&nbsp; K11&nbsp;&nbsp; 47.19 41.96 44.03<br>
+&nbsp; K12&nbsp;&nbsp; 49.9 43.14 47.21<br>
+&nbsp; K13&nbsp;&nbsp; 10.61 17.44 31.24<br>
+&nbsp; K14&nbsp;&nbsp; 24.84 13.19 21<br>
+&nbsp; K15&nbsp;&nbsp; 53.12 48.05 3.19<br>
+&nbsp; K16&nbsp;&nbsp; 1.05 1.14 1.13<br>
+&nbsp; K17&nbsp;&nbsp; 19.93 11.34 1.67<br>
+&nbsp; K18&nbsp;&nbsp; 5.3 10.47 2.73<br>
+&nbsp; K19&nbsp;&nbsp; 3.95 2.76 13.94<br>
+&nbsp; K20&nbsp;&nbsp; 30.61 26.43 11.04<br>
+&nbsp; K21&nbsp;&nbsp; 34.91 29.6 11.78<br>
+&nbsp; K22&nbsp;&nbsp; 38.95 34.57 18.4<br>
+&nbsp; L1&nbsp;&nbsp;&nbsp; 3.88 3.12 2.32<br>
+&nbsp; L2&nbsp;&nbsp;&nbsp; 4.93 3.2 2.69<br>
+&nbsp; L3&nbsp;&nbsp;&nbsp; 5.75 3.14 3.02<br>
+&nbsp; L4&nbsp;&nbsp;&nbsp; 7.31 3.79 3.4<br>
+&nbsp; L5&nbsp;&nbsp;&nbsp; 13.29 11.54 9.39<br>
+&nbsp; L6&nbsp;&nbsp;&nbsp; 16.22 11.73 10.32<br>
+&nbsp; L7&nbsp;&nbsp;&nbsp; 19.95 12.08 12.06<br>
+&nbsp; L8&nbsp;&nbsp;&nbsp; 20.79 11.31 12.01<br>
+&nbsp; L9&nbsp;&nbsp;&nbsp; 43.22 42.09 33.78<br>
+&nbsp; L10&nbsp;&nbsp; 45.52 41.88 34.65<br>
+&nbsp; L11&nbsp;&nbsp; 49.04 42.87 35.98<br>
+&nbsp; L12&nbsp;&nbsp; 51.03 43.83 37.78<br>
+&nbsp; L13&nbsp;&nbsp; 7.45 12.77 25.59<br>
+&nbsp; L14&nbsp;&nbsp; 21.26 10.76 17.73<br>
+&nbsp; L15&nbsp;&nbsp; 49.45 43.12 2.14<br>
+&nbsp; L16&nbsp;&nbsp; 0.47 0.49 0.5<br>
+&nbsp; L17&nbsp;&nbsp; 16.04 8.49 0.78<br>
+&nbsp; L18&nbsp;&nbsp; 2.91 6.5 1.39<br>
+&nbsp; L19&nbsp;&nbsp; 2.5 1.45 10.28<br>
+&nbsp; L20&nbsp;&nbsp; 38.7 33.98 20.86<br>
+&nbsp; L21&nbsp;&nbsp; 39.36 35.23 21.23<br>
+&nbsp; L22&nbsp;&nbsp; 41.36 38.77 23.51<br>
+&nbsp; GS0&nbsp;&nbsp;&nbsp; 79.47 82.51 69.04<br>
+&nbsp; GS1&nbsp;&nbsp;&nbsp; 72.62 74.94 59.17<br>
+&nbsp; GS2&nbsp;&nbsp;&nbsp; 63.15 65.11 51.57<br>
+&nbsp; GS3&nbsp;&nbsp;&nbsp; 54.72 56.51 45.03<br>
+&nbsp; GS4&nbsp;&nbsp;&nbsp; 48.1 49.81 39.24<br>
+&nbsp; GS5&nbsp;&nbsp;&nbsp; 42.22 43.64 34.45<br>
+&nbsp; GS6&nbsp;&nbsp;&nbsp; 37.33 38.7 30.5<br>
+&nbsp; GS7&nbsp;&nbsp;&nbsp; 32.38 33.61 26.11<br>
+&nbsp; GS8&nbsp;&nbsp;&nbsp; 27.56 28.7 22.11<br>
+&nbsp; GS9&nbsp;&nbsp;&nbsp; 22.5 23.4 17.99<br>
+&nbsp; GS10&nbsp;&nbsp; 18.77 19.55 14.83<br>
+&nbsp; GS11&nbsp;&nbsp; 15.48 16.08 12.04<br>
+&nbsp; GS12&nbsp;&nbsp; 12.69 13.29 9.98<br>
+&nbsp; GS13&nbsp;&nbsp; 10.35 10.81 7.97<br>
+&nbsp; GS14&nbsp;&nbsp; 8.39 8.77 6.37<br>
+&nbsp; GS15&nbsp;&nbsp; 6.45 6.79 4.97<br>
+&nbsp; GS16&nbsp;&nbsp; 4.95 5.18 3.7<br>
+&nbsp; GS17&nbsp;&nbsp; 3.58 3.82 2.76<br>
+&nbsp; GS18&nbsp;&nbsp; 2.76 2.89 2.06<br>
+&nbsp; GS19&nbsp;&nbsp; 1.97 2.08 1.45<br>
+&nbsp; GS20&nbsp;&nbsp; 1.22 1.31 0.98<br>
+&nbsp; GS21&nbsp;&nbsp; 1 1.05 0.74<br>
+&nbsp; GS22&nbsp;&nbsp; 0.87 0.89 0.65<br>
+&nbsp; GS23&nbsp;&nbsp; 0.34 0.32 0.32<br>
+<br>
+</font> </tt><br>
+<tt> <br>
+</tt><br>
+<br>
+</body>
+</html>
diff --git a/doc/collink.html b/doc/collink.html
new file mode 100644
index 0000000..0b94bc7
--- /dev/null
+++ b/doc/collink.html
@@ -0,0 +1,1059 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>collink</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>link/collink</b></h2>
+ <h3>Summary</h3>
+ Link two ICC device profiles to create an ICC device link profile.<br>
+ <br>
+ <b> collink</b> takes two device ICC profiles, and links them
+ together, either in a simple fashion using the standard ICC forward
+ and reverse tables of the specified intent, or using color
+ appearance space and true gamut mapping, together with possibly
+ inverting the forward profile,&nbsp; to allow black ink regeneration
+ or to retain the source black characteristic from the source
+ profile.<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">collink [-options] <span
+ style="font-style: italic;">srcprofile dstprofile
+ linkedprofile</span></span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Verbose<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#A">-A "manufacturer"</a><span
+ style="font-family: monospace;">&nbsp; Set the manufacturer
+ description string</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#M">-M "model"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set the model
+ description string</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D "description"</a><span
+ style="font-family: monospace;">&nbsp;&nbsp; Set the profile
+ Description string&nbsp; (Default "</span><span
+ style="font-style: italic; font-family: monospace;">inoutfile</span><span
+ style="font-family: monospace;">")</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#C">-C "copyright"</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; Set the
+ copyright string</span></small><br style="font-family:
+ monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#V">-V</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verify
+existing
+
+
+ profile, rather than link (Debug option)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#q">-q lmhu</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quality - Low, Medium (def),
+ High, Ultra</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#r">-r <i>res</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+clut
+
+
+ res. set by -q</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#n">-n</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't
+preserve
+
+
+ device curves in result</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#f">-f</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Special :- Force neutral colors
+ to be K only output.<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#fk">-fk</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Special :- Force K only neutral colors
+ to be K only output<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#fcmy">-fcmy</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; Special :- Force 100% C,M or Y only to stay pure</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#F">-F</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Special :- Force all colors to be
+ K only output.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p">-p aprof.icm</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Include
+
+
+ abstract profile in link</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#s">-s</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Simple
+Mode
+
+
+ (default)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#g">-g [src.gam]</a><span
+ style="font-family: monospace;">&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
+ Gamut Mapping Mode [optional source image gamut]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#G">-G [src.gam]</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Gamut
+
+
+ Mapping Mode using inverse outprofile A2B [optional source
+ gamut]</span><br style="font-family: monospace;">
+ <br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; &nbsp;&nbsp; </span><u
+ style="font-family: monospace;">Simple Mode Options:</u><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#si">-i <i>in_intent</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp;&nbsp;&nbsp; p =
+ perceptual, r = relative colorimetric,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+s
+
+
+ = saturation, a = absolute colorimetric</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#so">-o </a><i
+ style="font-family: monospace;"><a href="#so">out_intent</a> </i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; p =
+ perceptual, r = relative colorimetric,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+s
+
+
+ = saturation, a = absolute colorimetric</span><br
+ style="font-family: monospace;">
+ <br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; &nbsp;&nbsp; </span><u
+ style="font-family: monospace;">Mapping Mode Options:</u><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#i">-i <i>intent</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ set linking intent from the following choice:</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+a
+-
+
+
+ Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+aw
+-
+
+
+ Absolute Colorimetric (in Jab) with scaling to fit white point<br
+ style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+aa
+-
+
+
+ Absolute Appearance</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+r
+-
+
+
+ White Point Matched Appearance [ICC Relative Colorimetric]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+la
+-
+
+
+ Luminance matched Appearance</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+p
+-
+
+
+ Perceptual (Preferred) [ICC Perceptual]<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+pa
+
+
+ - Perceptual Appearance</span></small><br style="font-family:
+ monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ms
+-
+
+
+ Saturation</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+s
+-
+
+
+ Enhanced Saturation [ICC Saturation]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+al
+-
+
+
+ Absolute Colorimetric (Lab)</span><span style="font-family:
+ monospace;"></span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#w">-w [J,a,b]</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; Use forced
+ whitepoint hack [optional color to map the white to]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c <i>viewcond</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp; set source viewing
+ conditions for CIECAM02,</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+either
+
+
+ an enumerated choice, or a parameter</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#d">-d <i>viewcond</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp; set destination
+ viewing conditions for CIECAM02,</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+either
+
+
+ an enumerated choice, or a parameter:value change<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pp - Practical
+ Reflection Print (ISO-3664 P2)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+
+
+ &nbsp; pe - Print evaluation environment (CIE 116-1995)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+
+
+ &nbsp; pc - Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; mt - Monitor in
+ typical work environment</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+
+
+ mb - Monitor in bright work environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; md - Monitor in darkened work
+ environment</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; jm - Projector in dim
+ environment</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; jd - Projector in dark
+ environment</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp;&nbsp;&nbsp; pcd - Photo CD - original scene
+ outdoors</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; ob - Original scene - Bright
+ Outdoors</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; cx - Cut Sheet Transparencies
+ on a viewing box</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+s:surround
+n
+
+
+ = auto, a = average, m = dim, d = dark,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp;
+
+
+ c = transparency (default average)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+w:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Adapted
+
+
+ white point as XYZ (default media white)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+w:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Adapted
+
+
+ white point as x, y</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+a:adaptation&nbsp;
+Adaptatation
+
+
+ luminance in cd.m^2 (default 50.0)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+b:background&nbsp;
+Background
+%
+
+
+ of image luminance (default 20)<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; l:scenewhite&nbsp;
+ Scene white in cd.m^2 if surround = auto (default 250)<br
+ style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Flare
+light
+
+
+ % of image luminance (default 1)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Flare
+
+
+ color as XYZ (default media white)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Flare
+
+
+ color as x, y</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#t">-t <i>tlimit</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+set
+source
+
+
+ total ink limit, 0 - 400% (estimate by default)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#T">-T <i>klimit</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+set
+source
+
+
+ total ink limit, 0 - 100% (estimate by default)</span><br
+ style="font-family: monospace;">
+ <br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; &nbsp; &nbsp;&nbsp; </span><u
+ style="font-family: monospace;">Inverse outprofile A2B Options:</u><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#k">-k tezhxr</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; CMYK Black generation</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+t
+
+
+ = transfer K from source to destination, e = retain K of
+ destination B2A table</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+z
+
+
+ = zero K, h = 0.5 K, x = maximum K, r = ramp K (default)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#kp">-k p stle stpo enpo
+ enle shape</a><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+p
+
+
+ = black level generation curve parameters</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#kq">-k q stle0 stpo0
+ enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2</a><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+q
+
+
+ = transfer source K to dual curve limits</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#K">-K parameters</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Same as -k, but target is K locus rather than K value itself</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#l">-l <i>tlimit</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+set
+destination
+
+
+ total ink limit, 0 - 400% (estimate by default)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#L">-L <i>klimit</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+set
+destination
+
+
+ total ink limit, 0 - 100% (estimate by default)<br>
+ </span></small>&nbsp;&nbsp;<small><span style="font-family:
+ monospace;"><a href="#P">-P</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Create
+gamut
+
+
+ gammap_p.wrl and gammap_s.wrl diagostics</span></small><small><br>
+ <br>
+ <span style="font-family: monospace;"></span></small><span
+ style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;"><span style="font-style:
+ italic;"></span></span></span><a href="#p1"><i
+ style="font-family: monospace;">srcprofile</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+source
+ICC
+
+
+ profile. A </span><small><span style="font-family: monospace;">TIFF
+
+
+ or JPEG file with embedded profile may be used here.</span></small><br
+ style="font-family: monospace;">
+ &nbsp; <span style="font-family: monospace;"><span
+ style="text-decoration: underline;"><span style="font-style:
+ italic;"></span></span></span><a href="#p2"><i
+ style="font-family: monospace;">dstprofile</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+destination
+ICC
+
+
+ profile. </span><span style="font-family: monospace;">A </span><small><span
+ style="font-family: monospace;">TIFF or JPEG file with embedded
+ profile may be used here.</span></small><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a href="#p3"><i
+ style="font-family: monospace;">linkedprofile</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ resulting device link profile</span><br>
+ <h3>Usage Details and Discussion</h3>
+ <b><a name="v"></a> -v</b> Turns on verbose mode. Gives progress
+ information as the profile is created. Since gamut map mode inverse
+ profile linking can take a long time to perform, this is often
+ useful. <br>
+ <br>
+ <a name="A"></a>The <b>-A</b> parameter allows setting of the
+ device manufacturer description tag. This parameter may not be
+ relevant for a link profile, but if used should be a string that
+ identifies the manufacturer of the primary device used in the link.
+ With most command line shells, it will be necessary to enclose the
+ parameter with double quotes, so that spaces and other special
+ characters are included in the parameter, and not mistaken for the
+ start of another flag, or as a final command line parameters. By
+ default no manufacturer description string tag will be generated for
+ the profile.<br>
+ <br>
+ <a name="M"></a>The <b>-M</b> parameter allows setting of the
+ device mode description tag. This parameter may not be relevant for
+ a link profile, but if used should be a string that identifies the
+ particular model of primary device used in the link. With most
+ command line shells, it will be necessary to enclose the parameter
+ with double quotes, so that spaces and other special characters are
+ included in the parameter, and not mistaken for the start of another
+ flag, or as a final command line parameters. By default no model
+ description string tag will be generated for the profile.<br>
+ <br>
+ <a name="D"></a>The <b>-D</b> parameter allows setting of the
+ profile description tag. The parameter should be a string that
+ describes the profile. On many systems, it will be this string that
+ will be used to identify the profile from a list of possible
+ profiles. With most command line shells, it will be necessary to
+ enclose the parameter with double quotes, so that spaces and other
+ special characters are included in the parameter, and not mistaken
+ for the start of another flag, or as a final command line parameter.
+ Many programs that deal with ICC profiles use the description tag to
+ identify a profile, rather than the profile filename, so using a
+ descriptive string is important in being able to find a profile. By
+ default, the base name of the resulting profile will be used as the
+ description.<br>
+ <br>
+ <a name="C"></a>The <b>-C</b> parameter allows setting of the
+ profile copyright tag. The parameter should be a string that
+ describes the copyright (if any) claimed on the profile being
+ generated.. With most command line shells, it will be necessary to
+ enclose the parameter with double quotes, so that spaces and other
+ special characters are included in the parameter, and not mistaken
+ for the start of another flag, or as a final command line
+ parameters. By default a generic copyright string will be generated
+ for the profile.<br>
+ <br>
+ <br>
+ <b><a name="V"></a> -V</b> Verifies an existing profile. This is
+ really a debugging option. It is only useful if all the linking
+ parameters are identical to those used during the creation of the
+ profile being verified.<br>
+ <br>
+ <b><a name="q"></a> -q [lmhu]</b>&nbsp; &nbsp; &nbsp; &nbsp;Quality
+ - Low, Medium (def), High, Ultra<br>
+ <b><a name="r"></a> -r res&nbsp;</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+
+
+ &nbsp;Override clut res. set by <b>-q</b><br>
+ <br>
+ This sets the basic quality of the resulting link, by choosing the
+ resolution of various tables in the resulting profile, as well as
+ the resolution of other temporary tables used in creating the link.
+ The <b>-r</b> flag allows overriding the resolution set by the <b>-q</b>
+ option, for the ICC profile CLUT multi-dimensional interpolation
+ table. It is highly recommended that <span style="font-weight:
+ bold;">-qm</span> be used as a starting point, and other settings
+ only tried after this has been evaluated. <span style="font-weight:
+ bold;">-qu</span> should almost never be used, except to prove
+ that it should almost never be used.<br>
+ <br>
+ <a name="n"></a>Normally the per channel device curves in the source
+ and destination profiles are preserved in the resulting device link
+ profile, but the <b>-n</b> option disables this. This can be useful
+ if the device linearisation curves are inappropriate in nature.<br>
+ <br>
+ <a name="f"></a> The <b>-f</b> option is a special purpose flag
+ useful only for 3 or 4 component (RGB, CMY or CMYK) source to CMYK
+ destination linking, that causes the destination to be <span
+ style="font-weight: bold;">K only</span> for neutral axis input.
+ Neutral axis input is assumed for R=G=B or C=M=Y input values. So as
+ to get a smooth mapping from the source to the K only destination,
+ by default the gamut mapping will be adjusted to target the
+ destination K only black, and Perceptual gamut mapping will be
+ selected along with maximum K inking. If other options are selected
+ that conflict with achieving a smooth mapping, warnings messages
+ will be emitted.<br>
+ <br>
+ <a name="F"></a> The <b>-F</b> option is a special purpose flag
+ useful only mapping to a CMYK destination, that causes the
+ destination to be converted to K only monochrome. So as to get a
+ smooth mapping from the source to the K only destination, by default
+ the gamut mapping will be adjusted to target the destination K only
+ black, and Perceptual gamut mapping will be selected along with
+ maximum K inking. If other options are selected that conflict with
+ achieving a smooth mapping, warnings messages will be emitted.<br>
+ <br>
+ <a name="fk"></a>&nbsp;The <b>-fk</b> option is a special purpose
+ flag useful only for CMYK source to CMYK destination linking, that
+ causes K only source values to map to K only destination values.
+ This is often useful in re-targeting CMYK material while preserving
+ K only text and graphics. So as to get a smooth mapping from the
+ source to the K only destination, by default the gamut mapping will
+ be adjusted to assume K only black source to destination K only
+ black for K only values, and Perceptual gamut mapping will be
+ selected along with a black generation rule (<span
+ style="font-weight: bold;">-kt</span>) that preserves the black
+ level from source to destination. If other options are selected that
+ conflict with achieving a smooth mapping, warnings messages will be
+ emitted.<br>
+ <br>
+ <a name="fcmy"></a>&nbsp;The <b>-fcmy</b> options are special
+ purpose flags useful only for CMY or CMYK source to CMY or CMYK
+ destination linking. The <span style="font-weight: bold;">cmy</span>
+ flags may be used independently or in combination (ie. <span
+ style="font-weight: bold;">-fc, -fm, -fy, -fcm, -fcy, -fmy, -fcmy</span>)
+ or combined with the <span style="font-weight: bold;">-fk</span>
+ option.&nbsp; These flags ensure that the pure 100% primary colorant
+ source values map to 100% pure colorant destination values, and may
+ be useful in some situations where CMYK material is being
+ re-targeted. <span style="font-weight: bold;">Note</span> that
+ forcing the 100% colorant values to map this way largely works
+ against the aims of color management in preserving colors
+ appearance.&nbsp; So as to get a smooth mapping from the source
+ to&nbsp; destination, by default the gamut mapping will a Saturation
+ intent with 100 percept alignment of the selected C, M and/or Y cusp
+ values. A Saturation intent is often what is desired in such CMYK to
+ CMYK re-renderings, as it makes best use of the (usually quite
+ similar sized) destination gamut. If other options are selected that
+ conflict with achieving a smooth mapping, warnings messages will be
+ emitted.<br>
+ <br>
+ <a name="p"></a> The <b>-p</b> option alows specifying an abstract
+ profile be applied between the source and destination profiles. An
+ abstract profile is a way of specifying a color adjustment in a
+ device independent way. The abstract profile might have been created
+ using one of the <span style="font-weight: bold;">tweak</span>
+ tools, such as <a href="refine.html">refine</a>.<br>
+ <br>
+ The basic linking style is chosen by using the <b>-s</b> (default),
+ <b>-g</b> or <b>-G</b> flags. The three behaviors are:<br>
+ <br>
+ <a name="s"></a>&nbsp;<b>-s</b>&nbsp;&nbsp; Simple mode. No gamut
+ mapping is performed, the selected intent AtoB and BtoA tables are
+ simply concatenated to create the output link, with the gamut
+ mapping behavior being determined solely by the BtoA table. The -i
+ and -o options allow selection of the source and destination ICC
+ intents. This is typically how other CMS do ICC linking. <a
+ href="#ss">Details</a>.<br>
+ <br>
+ <a name="g"></a> &nbsp;<b>-g</b>&nbsp;&nbsp; Gamut mapping mode. In
+ this mode, the absolute colorimetric AtoB and BtoA tables are used
+ to perform the link, and the intermediate linking color space is
+ (generally) the CIECAM02 Jab appearance space. The source and
+ destination viewing conditions can be selected using the <b>-c</b>
+ and <b>-d</b> options. A gamut mapping is performed between the two
+ spaces, using&nbsp; the intent selected by the <b>-i</b> option.
+ There is an optional argument, which is a source gamut to use
+ instead of that of the source profile. This is to allow optimizing
+ the gamut mapping to a source gamut of &nbsp;a particular image,
+ which can give slightly better results that gamut mapping from the
+ gamut of the source colorspace. Such a source image gamut can be
+ created using the <a href="tiffgamut.html"> tiffgamut</a> tool.
+ More&nbsp; <a href="#gg">details</a> about gamut mapping mode.<br>
+ <br>
+ <a name="G"></a>&nbsp;<b>-G</b>&nbsp; Use the gamut mapped, inverse
+ AtoB table linking method. This is generally the most accurate,
+ smooth and flexible linking method, but takes the longest to
+ perform. The gamut mapping mode&nbsp; (<span style="font-weight:
+ bold;">-g</span>) options <b>-i</b>, <b>-c</b>, <b>-d</b>, <b>-k</b>
+ and <b>-l</b> are effective when this method is selected. There is
+ an optional argument, which is a source gamut to use instead of that
+ of the source profile. This is to allow optimizing the gamut mapping
+ to a source gamut of &nbsp;a particular image, which can give
+ slightly better results that gamut mapping from the gamut of the
+ source colorspace. Such a source image gamut can be created using
+ the <a href="tiffgamut.html"> tiffgamut</a> tool. More <a
+ href="#GG">details</a> about the gamut mapping, inverse AtoB mode.<br>
+ <br>
+ The gamut provided to the <span style="font-weight: bold;">-g</span>
+ or <span style="font-weight: bold;">-G</span> flag should be in the
+ same colorspace that <span style="font-weight: bold;">collink</span>
+ is using internally to connect the two profiles. For all intents
+ except the last one (no. <span style="font-weight: bold;">7</span>),
+
+
+ the space should be Jab appearance space, with the viewing
+ conditions generally being those of the source profile viewing
+ conditions. The source profile will normally be the one used to
+ create a source image gamut using <span style="font-weight: bold;">tiffgamut</span>.<br>
+ &nbsp;<br>
+ <u><a name="ss"></a> Simple mode gamut mapping options:</u><br>
+ <br>
+ <a name="si"></a> &nbsp;&nbsp; &nbsp;&nbsp; <b>-i</b> <i>in_intent</i>&nbsp;
+&nbsp;
+&nbsp;
+
+
+ &nbsp;<b>p</b> = perceptual, <b>r</b> = relative colorimetric,<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>s</b>
+ = saturation, <b>a</b> = absolute colorimetric<br>
+ <a name="so"></a> &nbsp;&nbsp; &nbsp;&nbsp; <b>-o</b> <i>out_intent</i>
+ &nbsp; &nbsp;<b>p</b> = perceptual, <b>r</b> = relative
+ colorimetric,<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <b>s</b>
+ = saturation, <b>a</b> = absolute colorimetric<br>
+ <br>
+ These two options simply select the appropriate ICC table, according
+ to desired intent. Generally, it is a good idea to use the same
+ intent for both source and destination. Not all ICC profiles support
+ all four intents.<br>
+ <br>
+ <u><a name="gg"></a> Gamut mapping mode options:</u><br>
+ <br>
+ <a name="i"></a> &nbsp;<b>-i</b> <i>intent</i><br>
+ <br>
+ Select the gamut mapping intent. In gamut mapping mode there is only
+ a single overall intent. The intent is selected using the 1 two
+ letter option parameter, the standard ICC profile being a subset of
+ the available selections.<br>
+ <br>
+ <div style="margin-left: 40px;"><a name="ia"></a>The <span
+ style="font-weight: bold;">a</span> intent, Absolute
+ Colorimetric, is intended to reproduce colors exactly,
+ irrespective of the white point of the each medium. This is done
+ using CIECAM02 Jab appearance colorspace by forcing the source and
+ destination to have a common white point (but other aspects of the
+ individual viewing conditions are active), and colors are mapped
+ directly from source to destination, clipping any out of gamut
+ colors to the closest match. This is equivalent to the ICC <span
+ style="font-weight: bold;">Absolute Colorimetric</span> intent,
+ and is often used for proofing purposes. <br>
+ <br>
+ <a name="iaw"></a>The <span style="font-weight: bold;">aw</span>
+ intent, Absolute Colorimetric with scaling to fit white point, is
+ very similar to the <span style="font-weight: bold;">a</span>
+ intent, except that it will scale the source colorspace down in
+ order to make sure that the source white point isn't clipped by
+ the gamut of the destination. This might be used in some print
+ proofing situations where the source white is lightly lighter than
+ the destination white (as an alternative to using the <a
+ href="#w">-w</a> flag), or it may be useful in some soft
+ proofing situations where the differences in white point of the
+ display destination would cause clipping of the source white
+ point.&nbsp; When the <a href="#v">-v</a> flag is on, the scaling
+ factor used will be displayed during execution.<br>
+ <br>
+ <a name="iaa"></a>The <span style="font-weight: bold;">aa</span>
+ intent, Absolute Appearance, simply maps the Jab colors directly
+ from source to destination, clipping any out of gamut colors to
+ the closest match. This attempts to match the exact appearance of
+ colors as closely as possible, but may not exactly map the white
+ point of the source to the destination, depending on how different
+ the viewing conditions are.<br>
+ <br>
+ <a name="ir"></a>The&nbsp;<span style="font-weight: bold;">r</span>
+ intent is like Absolute Appearance mode, but maps the white point
+ from source to destination precisely, and otherwise maps the Jab
+ colors directly from source to destination, clipping any out of
+ gamut colors to the closest match. This is equivalent to the ICC <span
+ style="font-weight: bold;">Relative Colorimetric</span> intent.<br>
+ <br>
+ <a name="ila"></a>The <span style="font-weight: bold;">la</span>
+ intent, Luminance matched appearance, linearly compresses or
+ expands the the luminance axis to match the source to the
+ destination space, while not otherwise altering the gamut,
+ clipping any out of gamut colors to the closest match. This is
+ often useful for appearance based soft proofing.<br>
+ <br>
+ <a name="ip"></a>The&nbsp; <span style="font-weight: bold;">p</span>
+ intent, Perceptual, uses "knee" type 3 Dimensional compression to
+ make the source gamut fit within the destination gamut. As much as
+ possible, clipping is avoided, hues and the overall appearance is
+ maintained. The white point is mapped precisely from source to
+ destination.This is equivalent to the ICC <span
+ style="font-weight: bold;">Perceptual</span> intent.<br>
+ <br>
+ <a name="ipa"></a>The&nbsp; <span style="font-weight: bold;">pa</span>
+ intent, Perceptual Appearance uses "knee" type 3 Dimensional
+ compression to make the source gamut fit within the destination
+ gamut. As much as possible, clipping is avoided, hues and the
+ overall appearance is maintained. The white point is<span
+ style="font-weight: bold;"> not</span> mapped from source to
+ destination, allowing the apperance parameters to alter the
+ chromatic mapping.<br>
+ <br>
+ <a name="ims"></a>The <span style="font-weight: bold;">ms</span>
+ intent, Saturation, uses 3 Dimensional compression and <span
+ style="text-decoration: underline;">expansion</span> to try and
+ make the source gamut exactly match the destination gamut, and
+ also favours higher saturation over hue or lightness preservation.
+ The white point is mapped precisely from source to destination.<br>
+ <br>
+ <a name="is"></a>The <span style="font-weight: bold;"></span><span
+ style="font-weight: bold;">s</span> intent, Enhanced Saturation,
+ uses the same basic gamut mapping as <span style="font-weight:
+ bold;">ms</span>, Saturation, but increases saturation slightly
+ in highly saturated areas of the gamut. This is equivalent to the
+ ICC <span style="font-weight: bold;">Saturation</span> intent.
+ The white point is mapped precisely from source to destination.<br>
+ <br>
+ <a name="ial"></a>The <span style="font-weight: bold;">al</span>
+ intent, Absolute Appearance (Lab), is similar to intent <span
+ style="font-weight: bold;">a</span>, but L*a*b* colorspace is
+ used rather than CIECAM02 Jab appearance space. This often leads
+ to poor reproduction of blue and red hues, but can be useful as a
+ reference mapping.<br>
+ </div>
+ <br>
+ <a name="w"></a> The <b>-w</b> flag forces the white points to be
+ mapped from source to destination, irrespective of the intent
+ chosen. This is useful if absolute intent is being used, and the two
+ media white points should match, but don't quite due to measurement
+ error.<br>
+ The <b>-w</b> flag can optionally be followed by three numbers,
+ that specify a color that white should be mapped to. This will be in
+ the colorspace used during linking (typically Jab space, which has
+ similar characteristics to L*a*b* space). This options can be useful
+ in fine tuning paper emulation in absolute colorimetric mapping
+ mode.<br>
+ <br>
+ <a name="c"></a><a name="d"></a> The <b>-c</b> and <b>-d</b>
+ options allow specification of the viewing conditions for the source
+ and destination colorspaces respectively. The viewing condition
+ information is used to map the profile PCS (Profile Connection
+ Space, which us either XYZ or L*a*b*) color into appearance space
+ (CIECAM02), which is a better colorspace to do gamut mapping in. The
+ viewing conditions allow the conversion into appearance space to
+ take account of how color will be seen under particular viewing
+ conditions.<br>
+ Viewing conditions can be specified in two basic ways. One is to
+ select from the list of "pre canned", enumerated viewing conditions,
+ choosing one that is closest to the conditions that are appropriate
+ for the media type and situation. Alternatively, the viewing
+ conditions parameters can be specified in detail individually. If
+ both methods are used, them the chosen enumerated condition will be
+ used as a base, and its parameters will then be individually
+ overridden.<br>
+ <br>
+ <a name="t"></a> The <b>-t</b> <i>tlimit</i> parameter sets the
+ total ink limit (TAC, Total Area Coverage) for a CMYK source
+ profile, as a total percentage from 0% to 400%. This affects the
+ gamut assumed for the source profile. By default, a total ink limit
+ will be estimated from the source profile B2A table.<br>
+ <br>
+ <a name="T"></a> The <b>-T</b> <i>klimit</i> parameter sets the
+ black channel ink limit for a CMYK source profile, as a total
+ percentage from 0% to 100%. This affects the gamut assumed for the
+ source profile. By default, a black ink limit will be estimated from
+ the source profile B2A table.<br>
+ <br>
+ <br>
+ <u> <a name="GG"></a>Inverse outprofile A2B Options:</u><br>
+ <br>
+ When the <b>-G</b> flag is used, the A2B table is inverted "on the
+ fly", allowing various additional choices as to what device values
+ are used to reproduce a particular color. (If the <b>-G</b> flag is
+ not used, then such decisions are encoded in the B2A table in the
+ profile, and cannot be altered during linking).<br>
+ <br>
+ <a name="k"></a> -<b>k</b> parameter sets the target level of black
+ (K) when creating a B2A CMYK output tables. This is often called a
+ black level, a black inking rule, black generation, or under color
+ removal.&nbsp; These set the target black level:<br>
+ <br>
+ <b> -kz</b> selects minimum black (0.0)<br>
+ <b> -kh</b> selects a black level value of 0.5<br>
+ <b> -kx</b> selects the maximum possible black (1.0)<br>
+ <b> -kr</b> selects a linear level ramp, starting at minimum black
+ for highlight, and maximum black for shadow (equivalent to -kp 0 0 1
+ 1 1). This is the default.<br>
+ <b>-kt</b>, will preserve the black amount from the source (CMYK)
+ profile to the destination&nbsp; (CMYK) profile as much as possible.
+ This may be most useful in creating a CMYK to CMYK conversion
+ between two different press conditions, while preserving as much as
+ possible the &nbsp;black only use for text etc. in anything
+ converted. Note that if the source black point is darker than the
+ destination, composite black will still be generated for K only
+ input. The <span style="font-weight: bold;">-fk</span> option can
+ be used to avoid this behavior.<br>
+ <b>-ke</b>, will preserve the black amount from the destination
+ profile B2A table (CMYK).<br>
+ <br>
+ <b><a name="kp"></a>-k p stle stpo enpo enle shape</b>&nbsp; allows
+ an arbitrary black locus ramp to be defined, consisting of a
+ starting value (stle) for highlights, a breakpoint L value (stpo)
+ where it starts to transition to the shadow level, an end breakpoint
+ L (enpo) where it flattens out again, and the finishing black level
+ (enle) for the shadows. There is also a curve parameter, that
+ modifies the transition from stle to enle to either be concave
+ (ie.&nbsp; the transition starts gradually and and finished more
+ abruptly) using values 0.0-1.0, with 0.0 being most concave, or
+ convex (the transition starts more abruptly but finishes gradually),
+ using values 1.0-2.0, with 2.0 being the most convex.<br>
+ <br>
+ Typical black value generation curve with parameters something like:
+ -kp 0 .1 .9 1 .5<br>
+ <br>
+ <tt> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0 K &nbsp; |
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;enpo<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+
+
+ &nbsp; &nbsp;_______&nbsp; enle<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+
+ &nbsp; &nbsp;/<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+
+
+ &nbsp; /<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+
+ &nbsp;/<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+
+ /<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ stle&nbsp; | ------/<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; +-------------------<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0 K&nbsp;
+ 0.0&nbsp;&nbsp;&nbsp;
+ stpo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Black<br>
+ <br>
+ </tt>For minimum sensitivity of printed output to the lighting
+ spectrum, it currently seems best to use the maximum possible black,
+ but other black generation levels (ie. 0.3 to 0.5) may well be
+ preferred if one wants to minimize the noisy appearance of black on
+ an inkjet device, or if the banding behaviour or other rendering
+ flaws of the printer is to be minimized. <br>
+ <br>
+ Note that the black level curve is applied throughout the gamut,
+ resulting in GCR (Grey Component Replacement). There is no facility
+ to restrict black to just neutral colors, hence UCR is not currently
+ supported.<br>
+ <br>
+ <b><a name="kq"></a>-k q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2
+ enpo2 enle2 shape2</b> is a combination of the <b>-kt</b> and <b>-kp</b>
+ functionality, with the black being preserved in CMYK to CMYK
+ linking, with the output black constrained to be between the first
+ and second set of curve parameters.<br>
+ <br>
+ The <a href="xicclu.html">xicclu</a> tool can be used to plot out
+ the resulting black level for a given set of parameters, by using
+ the <a href="xicclu.html#g">-g</a> flag of a profile already
+ created from the same .ti3 file.<br>
+ <br>
+ <a name="K"></a> <span style="font-weight: bold;">-K parameters.</span>
+ Any of the <span style="font-weight: bold;">-k</span> options above
+ can use the <span style="font-weight: bold;">-K</span> version, in
+ which rather than a black value target being defined by the inking
+ rule, a black <span style="text-decoration: underline;">locus</span>
+ target is defined. For each lookup, the minimum possible black level
+ and the maximum possible black level is determined, the former
+ corresponding to a locus target value of 0, and the latter
+ corresponding to a locus target value of 1. For instance, at the
+ white point, no black will be used in the output, even if the black
+ locus specifies a maximum (since the maximum amount of black that
+ can be used to print white is actually zero). Similarly, at the
+ black point, black may well be used, even if the black locus
+ specifies zero black (since a certain amount of black is needed to
+ achieve the desired density of color). <br>
+ <tt> </tt><br>
+ <a name="l"></a> The <b>-l</b> <i>tlimit</i> parameter sets the
+ total ink limit (TAC, Total Area Coverage) for the CMYK separation,
+ as a total percentage from 0% to 400%. This affects the gamut
+ assumed for the destination profile, as well as the ink limit in the
+ generated device link. The limit value should generally be set a
+ little below the value used in the test chart generation, to avoid
+ the very edges of the gamut. If the test chart ink limit has been
+ chosen to be a little beyond an acceptable level, then this number
+ should be the acceptable level. Although limits can be set below
+ 200%, this will generally restrict the color gamut noticeably, as
+ fully saturated secondary colors will not be reproduced. Values are
+ between 220% and 300% for typical printing devices. By default, a
+ total ink limit will be estimated from the destination profile B2A
+ table. The ink limit will be in final calibrated device values if
+ the profile includes calibration information.<br>
+ <br>
+ <a name="L"></a> The <b>-L</b> <i>klimit</i> parameter sets the
+ black channel ink limit for the CMYK separation, as a total
+ percentage from 0% to 100%. This affects the gamut assumed for the
+ source profile, as well as the ink limit in the generated device
+ link. For printing press like devices, this can be used to prevent
+ the black channel screening pattern "filling in". Typical values
+ might be from 95% to 99%. By default, a black ink limit will be
+ estimated from the source profile B2A table. The ink limit will be
+ in final calibrated device values if the profile includes
+ calibration information.<br>
+ <br>
+ <b><a name="P"></a></b>The <b>-P</b> option causes a diagnostic 3D
+ <a href="File_Formats.html#VRML">VRML</a> plots to be created that
+ illustrate the gamut mapping generated.<br>
+ <br>
+ <a name="p1"></a>The <i><b>inprofile</b></i> argument specifies the
+ source profile. This is the color space/device we are attempting to
+ emulate in the overall conversion. A <small>TIFF or JPEG file with
+ embedded profile may be used here.</small><br>
+ <br>
+ <a name="p2"></a>The<i><b> outprofile</b></i> argument specifies the
+ destination profile. This is the device we are actually displaying
+ on or printing to. A <small>TIFF or JPEG file with embedded profile
+ may be used here.</small><br>
+ <br>
+ <a name="p3"></a>The <i><b>linkedprofile</b></i> argument specifies
+ the resulting device link profile. This profile will contain the
+ color transform from the source space to destination space.<br>
+ <br>
+ For information on typical usage, see the <a href="Scenarios.html">Typical
+
+
+ Usage Scenarios</a> page.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/colorchecker.jpg b/doc/colorchecker.jpg
new file mode 100644
index 0000000..464dd11
--- /dev/null
+++ b/doc/colorchecker.jpg
Binary files differ
diff --git a/doc/colprof.html b/doc/colprof.html
new file mode 100644
index 0000000..de9d5c2
--- /dev/null
+++ b/doc/colprof.html
@@ -0,0 +1,1559 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>colprof</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2> profile/colprof</h2>
+ <h3>Summary</h3>
+ Create an&nbsp;<a href="File_Formats.html#ICC">ICC</a> profile from
+ the&nbsp;<a href="File_Formats.html#.ti3">.ti3</a> test chart patch
+ values.<br>
+ <h3>Usage Summary</h3>
+ &nbsp;<tt><small>colprof [-<i>options</i>] inoutfile<br>
+ &nbsp;<a href="#v">-v</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; Verbose mode<br>
+ &nbsp;<a href="#A">-A "manufacturer"</a>&nbsp; Set the
+ manufacturer description string<br>
+ &nbsp;<a href="#M">-M "model"</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set the model
+ description string<br>
+ &nbsp;<a href="#D">-D "description"</a>&nbsp;&nbsp; Set the
+ profile Description string&nbsp; (Default "<span
+ style="font-style: italic;">inoutfile</span>")<br>
+ &nbsp;<a href="#C">-C "copyright"</a> &nbsp;&nbsp;&nbsp; Set the
+ copyright string<br>
+ &nbsp;<a href="#Za">-Z tmnb &nbsp;</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Attributes:
+ Transparency, Matte, Negative, BlackAndWhite<br>
+ </small></tt><tt><small>&nbsp;<a href="colprof.html#Zi">-Z prsa</a>&nbsp;
+
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Default
+ intent: Perceptual, Rel. Colorimetric, Saturation, Abs.
+ Colorimetric</small></tt><tt><br>
+ </tt><tt> </tt><tt><small>&nbsp;<a href="#q">-q lmhu</a>
+ &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; Quality - Low,
+ Medium (def), High, Ultra<br>
+ &nbsp;<a href="#b">-b [lmhun]</a>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp; Low quality B2A table - or specific B2A quality or none
+ for input device<br>
+ &nbsp;<a href="#y">-y</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; Verify A2B profile<br>
+ &nbsp;<a href="#ni">-ni</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; Don't create input (Device) shaper
+ curves<br>
+ </small></tt><tt><small>&nbsp;<a href="#np">-np</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ Don't create input (Device) grid position curves</small></tt><tt><br>
+ </tt><tt> </tt><tt><small>&nbsp;<a href="#no">-no</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; Don't create output (PCS) shaper
+ curves<br>
+ </small></tt><tt><small>&nbsp;<a href="#nc">-nc</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ Don't put the input .ti3 data in the profile</small></tt><tt><br>
+ </tt><tt> </tt><tt><small>&nbsp;<a href="#k">-k zhxr</a>&nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Black generation: z = zero K,<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp;
+h
+=
+0.5
+K
+(def),
+x
+=
+
+
+
+
+
+
+
+
+
+
+
+ max K, r = ramp K<br>
+ &nbsp;<a href="#kp">-k p stle stpo enpo enle shape</a><br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp;
+stle:
+K
+level
+at
+White
+0.0
+
+
+
+
+
+
+
+
+
+
+
+ - 1.0<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+stpo:
+start
+point
+of
+transition
+Wh
+
+
+
+
+
+
+
+
+
+
+
+ 0.0 - Bk 1.0<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+enpo:
+End
+point
+of
+transition
+Wh
+
+
+
+
+
+
+
+
+
+
+
+ 0.0 - Bk 1.0<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+enle:
+K
+level
+at
+Black
+
+
+
+
+
+
+
+
+
+
+
+ 0.0 - 1.0<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+shape:
+1.0
+=
+straight,
+0.0-1.0
+concave,
+
+
+
+
+
+
+
+
+
+
+
+ 1.0-2.0 convex<br>
+ &nbsp;<a href="#K">-K parameters</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Same as -k, but target is K locus rather than K value itself<br>
+ &nbsp;<a href="#l">-l <i>tlimit</i></a>&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp;&nbsp; override CMYK total ink limit, 0 - 400%
+ (default from .ti3)<br>
+ &nbsp;<a href="#L">-L <i>klimit</i></a>&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp;&nbsp; override black ink limit, 0 - 100% (default
+ from .ti3)<br>
+ &nbsp;<a href="#a">-a lxXgsmGS</a> &nbsp;&nbsp; &nbsp; &nbsp;
+ Algorithm type override<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+l
+=
+Lab
+cLUT
+(def.),
+
+
+
+
+
+
+
+
+
+
+
+ x = XYZ cLUT, X = display XYZ cLUT + matrix<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+g
+=
+gamma+matrix,
+s
+=
+
+
+
+
+
+
+
+
+
+
+
+ shaper+matrix, m = matrix only,<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+G
+=
+single
+gamma+matrix,
+S
+=
+
+
+
+
+
+
+
+
+
+
+
+ single shaper+matrix<br>
+ &nbsp;<a href="#u">-u</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+
+
+
+ If input profile, auto scale WP to allow extrapolation</small></tt><tt><br>
+ </tt><tt> </tt><tt><small><small>&nbsp;<a href="#uc">-uc</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; If input profile, clip cLUT values above WP<br>
+ </small>&nbsp;</small></tt><tt><small><a href="#U">-U <span
+ style="font-style: italic;">scale</span></a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; If input
+ profile, scale media white point by scale</small></tt><tt><br>
+ </tt><tt> </tt><tt>&nbsp;</tt><tt><a href="#R">-R</a></tt><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Restrict
+white
+&lt;=
+1.0,
+black
+and
+
+
+
+
+
+
+
+
+
+
+
+ primaries to be +ve</tt><tt><br>
+ </tt><tt>&nbsp;</tt><tt><small><small><a
+ href="file:///D:/src/argyll/doc/colprof.html#f">-f [<i>illum</i>]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use Fluorescent
+ Whitening Agent compensation [opt. simulated inst. illum.:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ M0, M1, M2, </small></small></tt><tt><small><small><small>A,
+ C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp ]</small></small></small></tt><tt><br>
+ </tt><tt><small><small><small><small>&nbsp;<a
+ href="file:///D:/src/argyll/doc/colprof.html#i">-i <i>illum</i></a>&nbsp;&nbsp;
+
+ &nbsp; &nbsp; &nbsp; &nbsp; Choose illuminant for
+ computation of CIE XYZ from spectral data &amp; FWA:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+A,
+C,
+D50
+(def.),
+D50M2,
+
+ D65, F5, F8, F10 or file.sp</small></small></small><br>
+ &nbsp;<a href="#o">-o <i>observ</i></a>&nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; Choose CIE Observer for spectral data:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </small></tt><tt><small>(def.)</small></tt><tt><small>,
+ 1964_10, S&amp;B 1955_2, shaw, J&amp;V 1978_2<br>
+ &nbsp;<a href="#r">-r avgdev</a> &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; Average deviation of device+instrument readings as
+ a percentage (default 0.5%)<br>
+ &nbsp;<a href="#s">-s src.icc</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Apply
+gamut
+mapping
+to
+output
+profile
+perceptual
+B2A
+table
+for
+
+
+
+
+
+
+
+
+
+
+
+ given source<br>
+ &nbsp;<a href="#S">-S src.icc</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ Apply gamut mapping to output profile perceptual and saturation
+ B2A table<br>
+ &nbsp;<a href="#nP">-nP</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ Use colormetric source gamut to make output profile perceptual
+ table<br>
+ &nbsp;<a href="#nS">-nS</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ Use colormetric source gamut to make output profile saturation
+ table<br>
+ &nbsp;<a href="#g">-g src.gam</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use source image
+ gamut as well for output profile gamut mapping<br>
+ &nbsp;<a href="#p">-p aprof.icm,...</a> &nbsp; Incorporate
+ abstract profile(s) into output tables<br>
+ &nbsp;<a href="#t">-t intent</a>&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Override gamut
+ mapping intent for output profile perceptual table:<br>
+ &nbsp;<a href="#T">-T intent</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ Override gamut mapping intent for output profile saturation
+ table:<br>
+ </small></tt><tt><small> &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ a - Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aw - Absolute Colorimetric
+ (in Jab) with scaling to fit white point<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; &nbsp;&nbsp; aa - Absolute Appearance<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r - White Point Matched
+ Appearance [ICC Relative Colorimetric]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; &nbsp; la - Luminance matched Appearance<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; p - Perceptual (Preferred) [ICC
+ Perceptual]<br>
+ </small></tt><tt><small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ pa - Perceptual Appearance</small></tt><tt><br>
+ </tt><tt> </tt><tt><small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ms - Saturation<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; s - Enhanced Saturation [ICC
+ Saturation]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; &nbsp; al - Absolute Colorimetric (Lab)</small></tt><tt><small><br>
+ &nbsp;<a href="#c">-c viewcond</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ set input viewing conditions for output profile CIECAM02 gamut
+ mapping,<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ either an enumerated choice, or a parameter<br>
+ &nbsp;<a href="#d">-d viewcond</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ set output viewing conditions for output profile CIECAM02, gamut
+ mapping<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ either an enumerated choice, or a parameter:value change<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ Also sets out of gamut clipping CAM space.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ Enumerated Viewing Conditions:<br>
+ </small></tt><tt><small>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; &nbsp; pp - Practical Reflection Print (ISO-3664
+ P2)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; &nbsp; pe - Print evaluation environment (CIE
+ 116-1995)<br>
+ </small></tt><tt><small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; pc - Critical print evaluation
+ environment (ISO-3664 P1)</small></tt><tt><br>
+ </tt><tt> </tt><tt><small>&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; mt - Monitor in typical work
+ environment<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; mb - Monitor in bright work environment<br>
+ &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; md - Monitor in darkened work environment<br>
+ &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;
+ &nbsp; jm - Projector in dim environment<br>
+ &nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp; jd - Projector in dark environment<br>
+ &nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp; pcd - Photo CD - original scene outdoors<br>
+ &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; ob - Original scene - Bright Outdoors<br>
+ &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; cx - Cut Sheet Transparencies on a viewing box</small></tt><tt><small><br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp;&nbsp;&nbsp; s:surround n = auto, a = average, m =
+ dim, d = dark,<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; c = transparency (default average)<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ w:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Adapted white point
+ as XYZ (default media white)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ w:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Adapted
+ white point as x, y<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a:adaptation&nbsp; Adaptatation
+ luminance in cd.m^2 (default 50.0)<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b:background&nbsp; Background %
+ of image luminance (default 20)<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; l:scenewhite&nbsp;
+ Scene white in cd.m^2 if surround = auto (default 250)<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Flare light % of
+ image luminance (default 1)<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ f:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Flare color as XYZ
+ (default media white)<br>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ f:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Flare
+ color as x, y<br>
+ &nbsp;<a href="#P">-P</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ Create gamut gammap_p.wrl and gammap_s.wrl diagostics<br>
+ </small></tt><tt><small>&nbsp;<a href="#O">-O outputfile</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+
+
+
+
+
+
+
+
+
+
+
+ the default output filename &amp; extension.</small></tt><tt><br>
+ </tt><tt> </tt><tt><small>&nbsp;<a href="#p1"><i>inoutfile</i></a>
+ &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Base name for
+ input.ti3/output.icc file</small></tt><br>
+ <h3>Options<br>
+ </h3>
+ <b><a name="v"></a>-v</b>&nbsp; Turn on verbose mode. Gives progress
+ information as the profile is created. Since colprof can take a long
+ time to generate, this is often useful to monitor progress. If used
+ in combination with the <b>-y</b> flag, the error of each test
+ point to the resulting profile will be printed out.<br>
+ <br>
+ <a name="A"></a>The <b>-A</b> parameter allows setting of the
+ device manufacturer description tag. The parameter should be a
+ string that identifies the manufacturer of the device being
+ profiled. With most command line shells, it will be necessary to
+ enclose the parameter with double quotes, so that spaces and other
+ special characters are included in the parameter, and not mistaken
+ for the start of another flag, or as a final command line
+ parameters. By default no manufacturer description string tag will
+ be generated for the profile.<br>
+ <br>
+ <a name="M"></a>The <b>-M</b> parameter allows setting of the
+ device mode description tag. The parameter should be a string that
+ identifies the particular model of device being profiled. With most
+ command line shells, it will be necessary to enclose the parameter
+ with double quotes, so that spaces and other special characters are
+ included in the parameter, and not mistaken for the start of another
+ flag, or as a final command line parameters. By default no model
+ description string tag will be generated for the profile.<br>
+ <br>
+ <a name="D"></a>The <b>-D</b> parameter allows setting of the
+ profile description tag. The parameter should be a string that
+ describes the device and profile. On many systems, it will be this
+ string that will be used to identify the profile from a list of
+ possible profiles. With most command line shells, it will be
+ necessary to enclose the parameter with double quotes, so that
+ spaces and other special characters are included in the parameter,
+ and not mistaken for the start of another flag, or as a final
+ command line parameter. Many programs that deal with ICC profiles
+ use the description tag to identify a profile, rather than the
+ profile filename, so using a descriptive string is important in
+ being able to find a profile. By default, the base name of the
+ resulting profile will be used as the description.<br>
+ <br>
+ <a name="C"></a>The <b>-C</b> parameter allows setting of the
+ profile copyright tag. The parameter should be a string that
+ describes the copyright (if any) claimed on the profile being
+ generated.. With most command line shells, it will be necessary to
+ enclose the parameter with double quotes, so that spaces and other
+ special characters are included in the parameter, and not mistaken
+ for the start of another flag, or as a final command line
+ parameters. By default a generic copyright string will be generated
+ for the profile.<br>
+ <br>
+ <a name="Za"></a>The <b>-Z</b> parameter allows setting of the
+ profile attribute flags. There are four flags: <span
+ style="font-weight: bold;">t</span> to set Transparency, the
+ default being Reflective; <span style="font-weight: bold;">m</span>
+ to set Matte, the default is Glossy; <span style="font-weight:
+ bold;">n</span> to set Negative, the default is Positive; <span
+ style="font-weight: bold;">b</span> to set BlackAndWhite, the
+ default is Color.<br>
+ <br>
+ <a name="Zi"></a>The <b>-Z</b> parameter allows setting of the
+ profile default intent. The default intent can be one of the four
+ standard intents: <span style="font-weight: bold;">p</span> to set
+ Perceptual, <span style="font-weight: bold;">r</span> to set
+ Relative Colorimetric, <span style="font-weight: bold;">s</span> to
+ set Saturation, and <span style="font-weight: bold;">a</span> to
+ set Absolute colorimetric.<br>
+ <br>
+ <a name="q"></a> The <b>-q</b> parameter sets the level of effort
+ and/or detail in the resulting profile. For table based profiles
+ ("cLUT" profiles), it sets the main lookup table size, and hence
+ detail in the resulting profile. For matrix profiles it sets the per
+ channel curve detail level and fitting "effort". It is <span
+ style="text-decoration: underline;">highly recommended</span> that
+ <span style="font-weight: bold;">-qm</span> be used as a starting
+ point, and other settings only tried after this has been evaluated.
+ <span style="font-weight: bold;">NOTE</span> that <span
+ style="font-weight: bold;">-qu</span> is a <span
+ style="text-decoration: underline;">test mode</span>, and
+ shouldn't be used, except to prove that it is not worth using.<br>
+ <br>
+ <a name="b"></a> The <b>-b</b> flag overrides the <b>-q</b>
+ parameter, and sets the lut resolution for the BtoA (inverse) to a
+ low value. The creation of the B2A table is fairly time consuming,
+ and if the profile is only going to be used by <a
+ href="targen.html">targen</a>, or if it will only be used as an
+ input space profile, or if it will only be linked as an output
+ profile using Argyll's <a href="collink.html">collink</a> tool
+ using the <b>-G</b> option (inverse AtoB option), then a high
+ detail BtoA table is not required, and some time and profile space
+ can be saved. If the profile is to be used as an output space
+ profile with another CMS, or is going to be linked using the simple
+ (-s) or mapping mode (-g) options, then a good quality B2A table is
+ needed, and the -b flag should <span style="font-weight: bold;">NOT</span>
+ be set. Optionally, a specific B2A table quality can be set.<br>
+ <br>
+ For input devices,&nbsp; the presence of a B2A table is not
+ mandatory, and it can be omitted entirely from the profile by using
+ <span style="font-weight: bold;">-bn</span>. Note that input
+ profiles and matrix profiles will only contain a colorimetric intent
+ table or matrix.<br>
+ <br>
+ <a name="y"></a> The <b>-y</b> flag does a verification check on
+ the AtoB profile. This is done by comparing what CIE colors the
+ profile predicts for the test chart test patches, and comparing them
+ to the actual values. A summary of the average and maximum Lab delta
+ E's will be printed out if this flag is set. If the <b>-v</b> flag
+ is also set, then information for each patch will also be printed.<br>
+ <br>
+ <a name="ni"></a><a name="np"></a><a name="no"></a>Normally cLUT
+ base profiles are generated with three major elements:- per device
+ channel (shaper) input curves, the multi-dimensional lut table, and
+ per PCS channel (shaper) output curves. The&nbsp; Using the <b>-ni</b>
+ flag disables the creation of the per device channel curves, while
+ using the <b>-no</b> flag disables the creation of the per PCS
+ channel curves.<br>
+ For cLUT based profiles, the input curves that are written to the
+ profile are composed of two components, a shape to best match the
+ detailed shape of the device behavior, and a shape to distribute the
+ input values evenly across the LUT input indexes. The <span
+ style="font-weight: bold;">-no</span> flag disables the former,
+ while the <span style="font-weight: bold;">-np</span> flag disables
+ the latter. <br>
+ <br>
+ <a name="nc"></a><span style="font-weight: bold;">-nc </span>Normally
+the
+
+
+
+
+
+
+
+
+
+
+
+ device and CIE/spectral sample data and calibration curves used to
+ create a profile is stored in the <span style="font-weight: bold;">'targ'</span>
+ text tag in the resulting ICC profile. To suppress this and make the
+ resulting profile smaller, use the <span style="font-weight: bold;">-nc
+
+
+
+
+
+
+
+
+
+
+ </span>flag. <span style="font-weight: bold;">Note</span> that this
+ will then preclude final calibrated device value ink limits from
+ being computed for the resulting profile in subsequent use (ie. <a
+ href="collink.html">collink</a>, <a href="xicclu.html">xicclu</a>
+ etc.).<br>
+ <br>
+ <a name="k"></a> -<b>k</b> parameter sets the target level of black
+ (K) when creating a B2A CMYK output tables. This is often called a
+ black level, a black inking rule, black generation, or under color
+ removal.&nbsp; These set the target black level.<br>
+ <br>
+ &nbsp;Possible arguments to the <b>-k</b> flag are:<br>
+ <br>
+ <b> -kz</b> selects minimum black (0.0)<br>
+ <b> -kh</b> selects a black value of 0.5<br>
+ <b> -kx</b> selects the maximum possible black (1.0)<br>
+ <b> -kr</b> selects a linear black ramp, starting at minimum black
+ for highlight, and maximum black for shadow (equivalent to -kp 0 0 1
+ 1 1). This is the default.<br>
+ <br>
+ <b><a name="kp"></a>-k p stle stpo enpo enle shape</b>&nbsp; allows
+ an arbitrary black value ramp to be defined, consisting of a
+ starting value (stle) for highlights, a breakpoint L value (stpo)
+ where it starts to transition to the shadow level, an end breakpoint
+ L (enpo) where it flattens out again, and the finishing black level
+ (enle) for the shadows. There is also a curve parameter, that
+ modifies the transition from stle to enle to either be concave
+ (ie.&nbsp; the transition starts gradually and and finished more
+ abruptly) using values 0.0-1.0, with 0.0 being most concave, or
+ convex (the transition starts more abruptly but finishes gradually),
+ using values 1.0-2.0, with 2.0 being the most convex.<br>
+ <br>
+ Typical black value generation curve with parameters something like:
+ -kp 0 .1 .9 1 .5<br>
+ <br>
+ <tt> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0 K &nbsp; |
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;enpo<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
+ &nbsp;_______&nbsp; enle<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;/<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ |&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;/<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; /<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ stle&nbsp; | ------/<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; +-------------------<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0 K&nbsp;
+ 0.0&nbsp;&nbsp;&nbsp;
+ stpo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+ Black<br>
+ </tt> <br>
+ For minimum sensitivity of printed output to the lighting spectrum,
+ it currently seems best to use the maximum possible black, but other
+ black generation levels (ie. 0.3 to 0.5) may well be preferred if
+ one wants to minimize the noisy appearance of black on an inkjet
+ device, or if the banding behaviour or other rendering flaws of the
+ printer is to be minimized. <br>
+ <br>
+ Note that the black level curve is applied throughout the gamut,
+ resulting in GCR (Grey Component Replacement). There is no facility
+ to restrict black to just neutral colors, hence UCR is not currently
+ supported.<br>
+ &nbsp; <br>
+ The <a href="xicclu.html">xicclu</a> tool can be used to plot out
+ the resulting black level for a given set of parameters, by using
+ the <a href="xicclu.html#g">-g</a> flag of a profile already
+ created from the same .ti3 file.<br>
+ <br>
+ <a name="K"></a> <span style="font-weight: bold;">-K parameters.</span>
+ Any of the <span style="font-weight: bold;">-k</span> options above
+ can use the <span style="font-weight: bold;">-K</span> version, in
+ which rather than a black value target being defined by the inking
+ rule, a black <span style="text-decoration: underline;">locus</span>
+ target is defined. For each lookup, the minimum possible black level
+ and the maximum possible black level is determined, the former
+ corresponding to a locus target of 0, and the latter corresponding
+ to a locus target of 1. For instance, at the white point, no black
+ will be used in the output, even if the black locus specifies a
+ maximum (since the maximum amount of black that can be used to print
+ white is actually zero). Similarly, at the black point, black may
+ well be used, even if the black locus specifies zero black (since a
+ certain amount of black is needed to achieve the desired density of
+ color). <br>
+ <tt> </tt><br>
+ <a name="l"></a> The <b>-l</b> <i>tlimit</i> parameter sets the
+ total ink limit (TAC, Total Area Coverage) for the CMYK separation,
+ as a total percentage from 0% to 400%, and overrides any ink limit
+ specified in the .ti3 file. The limit value should generally be set
+ a little below the value used in the test chart generation, to avoid
+ the very edges of the gamut. If the test chart ink limit has been
+ chosen to be a little beyond an acceptable level, then this number
+ should be the acceptable level. Although limits can be set below
+ 200%, this will generally restrict the color gamut noticeably, as
+ fully saturated secondary colors will not be reproduced. Values are
+ between 220% and 300% for typical printing devices. Ink limits will
+ be in the final calibrated device values if the <span
+ style="font-weight: bold;">.ti3</span> includes the calibration
+ table.<br>
+ <br>
+ <a name="L"></a> The <b>-L</b> <i>klimit</i> parameter sets the
+ black channel ink limit for the CMYK separation, as a total
+ percentage from 0% to 100%. For printing press like devices, this
+ can be used to prevent the black channel screening pattern "filling
+ in". Typical values might be from 95% to 99%. Note that with the
+ current implementation this can slow down the creation of the
+ profile quite noticeably, so do not use <span style="font-weight:
+ bold;">-L</span> unless you really need to. Ink limits will be in
+ the final calibrated device values if the <span style="font-weight:
+ bold;">.ti3</span> includes the calibration table.<br>
+ <br>
+ <a name="a"></a> The <b>-a</b> parameter allows choosing an
+ alternate profile type. <br>
+ <br>
+ By default (equivalent to <b>-al</b>) profile creates a <span
+ style="font-weight: bold;">cLUT</span> based table profile with a
+ PCS (Profile Connection Space) of L*a*b*, which generally gives the
+ most accurate results, and allows for the four different rendering
+ intents that ICC profiles can support.<br>
+ <br>
+ A cLUT base table profile using a PCS of XYZ can be created if <b>-ax</b>
+ is used, and this may have the advantage of better accuracy for
+ additive type devices (displays, scanners, cameras etc.), may avoid
+ clipping for displays with a colorant chromaticity that can't be
+ encoded in L*a*b* PCS space, and may give a more accurate white
+ point for input devices by avoiding clipping of values above the
+ white point that can occur in L*a*b* based cLUT input profiles. By
+ default cLUT XYZ PCS Display profiles will also have a set of dummy
+ matrix tags included in them, for better compatibility with other
+ systems. The dummy matrix deliberately interchanges Red, Green and
+ Blue channels, so that it is obvious if the cLUT tables are not
+ being used. If it is important for both the cLUT and matrix be
+ accurate, use <span style="font-weight: bold;">-aX</span>, which
+ will create shaper/matrix tags.<br>
+ <br>
+ For RGB input or display profiles, a simpler type of profile using
+ either a gamma curves or a general shaper curves, combined with a
+ matrix can be created, although such a profile cannot support
+ perceptual or saturation intents. Gamma curve and matrix profiles
+ can be created by specifying <b>-ag</b> or <b>-aG</b>, the former
+ creating three independent gamma curves, one for each device
+ channel, and the latter creating one common curve for all the device
+ channels. The latter may be needed with certain applications that
+ will not accept different gamma curves for each channel. General
+ shaper curve and matrix profiles (which are superior to gamma curve
+ profiles) can be created by specifying <b>-as</b> or <b>-aS</b>,
+ the former creating three independent shaper curves, one for each
+ device channel, and the latter creating one common curve for all the
+ device channels. The latter may be needed with certain applications
+ that will not accept different shaper curves for each channel.<br>
+ <br>
+ The <span style="font-weight: bold;">-am</span> option will create
+ a matrix profile with linear (i.e. gamma = 1.0) curves. This may be
+ useful in creating a profile for a device that is known to have a
+ perfectly linear response, such as a camera in RAW mode.<br>
+ <br>
+ <a name="u"></a> <span style="font-weight: bold;">-u:</span> Input
+ profiles will normally be created such that the white patch of the
+ test chart will be mapped to perfect white when used with any of the
+ non-absolute colorimetric intents. This is the expected behavior for
+ input profiles. If such a profile is then used with a sample that
+ has a lighter color than the original test chart, then a cLUT
+ profile will clip the value, since it cannot be represented in the
+ lut table. Using the <b>-u</b> flag causes the media white point to
+ be automatically scaled (using the same type of scaling as the <span
+ style="font-weight: bold;">-U scale</span> option) to avoid
+ clipping values up to full device white. This flag can be useful
+ when an input profile is needed for using a scanner as a "poor mans"
+ colorimeter, or if the white point of the test chart doesn't
+ represent the white points of media that will be used in practice,
+ and that white point adjustment will be done individually in some
+ downstream application.<br>
+ <br>
+ <a name="uc"></a> <span style="font-weight: bold;">-uc:</span> For
+ input profiles it is sometimes desirable that any highlights
+ brighter than the white point, map exactly to white, and this option
+ post processes the cLUT entries to ensure this is the case. Note
+ that due to the finite nature of the cLUT grid, this may affect the
+ accuracy of colors near the light surface of the device gamut.<br>
+ <br>
+ <a name="U"></a><span style="font-weight: bold;"> -U <span
+ style="font-style: italic;">scale</span>:</span> Input profiles
+ will normally be created such that the white patch of the test chart
+ will be mapped to perfect white when used with any of the
+ non-absolute colorimetric intents. This is the expected behavior for
+ input profiles. Sometimes the test chart white is not quite the same
+ as the media being converted through the input profile, and it may
+ be desirable in these cases to adjust the input profile white point
+ to compensate for this. This can happen in the case of a camera
+ profile, where the test chart is not perfectly exposed. The <span
+ style="font-weight: bold;">-U</span> parameter allows this. If the
+ media converted is a little darker than the test chart white, then
+ use a scale factor slightly less than 1.0 to make sure that the
+ media white comes out as white on conversion (ie. try 0.9 for
+ instance). If the media is a little lighter than the test chart
+ white and is "blowing out" the highlights, try a value slightly
+ greater than 1.0 (ie. try 1.1 for instance). The <span
+ style="font-weight: bold;">-u</span> option sets the scale
+ automatically to accomodate a perfect white, but <span
+ style="font-weight: bold;">-U scale</span> can be used on top of
+ this automatic scaling.<br>
+ <br>
+ <a name="R"></a><span style="font-weight: bold;"> -</span><span
+ style="font-weight: bold;">R</span><span style="font-weight:
+ bold;">:</span> Normally the white point, black point and primary
+ locations (for matrix profiles) are computed so as to create
+ profiles that best match the sample data provided. Some programs are
+ not happy with the resulting locations if they have negative XYZ
+ values, or if the white point has a Y value &gt; 1. The <span
+ style="font-weight: bold;">-R</span> option restricts the white,
+ black and primary values, so as to work with these programs, but
+ this will reduce the accuracy of the profile.<br>
+ <br>
+ <a name="f"></a> The <b>-f</b> flag enables Fluorescent Whitening
+ Agent (FWA) compensation. This only works if spectral data is
+ available and, the instrument is not UV filtered.&nbsp; FWA
+ compensation adjusts the spectral samples so that they appear to
+ have been measured using an illuminant that has a different level of
+ Ultra Violet to the one the instrument actually used in the
+ measurement. There are two ways this can be used:<br>
+ <br>
+ The first and most common is to use the <b>-f</b> flag with the <b>-i</b>
+ illuminant parameter, to make the color values more accurately
+ reflect their appearance under the viewing illuminant. This will
+ work accurately if you specify the <span style="text-decoration:
+ underline;">actual illuminant spectrum you are using to view the
+ print</span>, using the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-i</span></span> flag. If you are
+ doing proofing, you need to apply this to <span
+ style="text-decoration: underline;">both your source profile, and
+ your destination profile</span>. Note that it is not sufficient to
+ specify an illuminant with the same white point as the one you are
+ using, you should specify the spectrum of the illuminant you are <span
+ style="text-decoration: underline;">actually using</span> for the
+ proofing, including its <span style="text-decoration: underline;">Ultra
+
+
+
+
+
+
+
+
+
+
+
+ Violet</span> spectral content, otherwise FWA compensation won't
+ work properly. This means you ideally need to measure your
+ illuminant spectrum using an instrument that can measure down to
+ 300nm. Such instruments are not easy to come by. The best
+ alternative is to use the <a href="illumread.html">illumread</a>
+ utility, which uses an indirect means of measuring an illuminant and
+ estimating its UV content. Another alternative is to simply try
+ different illuminant spectra in the <span style="font-weight:
+ bold;">ref </span>directory, and see if one gives you the result
+ you are after, although this will be fairly a tedious approach. The
+ ref/D50_X.X.sp set of illuminant spectra are the D50 spectrum with
+ different levels of U.V. added or subtracted, ref/D50_1.0.sp being
+ the standard D50 illuminant, and may be somewhere to start.<br>
+ &nbsp;[Note: Generally using <span style="font-weight: bold;">-f</span>
+ with the standard (<b>-i) </b>D50 illuminant spectrum will predict
+ that the device will produce bluer output than the default of not
+ FWA compensation. This is because most instruments use an
+ incandescent illuminant (A type illuminant), which has lower
+ relative levels of UV than D50, so the FWA compensation simulates
+ the effect of the greater UV in the D50. Also note that in an
+ absolute colorimetric color transformation, the more a profile
+ predicts the output device will have blue output, the yellower the
+ result will be, as the overall color correction compensates for the
+ blueness. The opposite will happen for an input profile.]<br>
+ <br>
+ The second way of using the <b>-f</b> flag is to provide it with a
+ instrument simulation illuminant spectrum parameter, in addition to
+ the default D50 or <b>-i</b> parameter&nbsp; CIE XYZ&nbsp;
+ calculation illuminant<b></b>. This more complicated scenario
+ simulates the measurement of the spectral reflectance of the samples
+ under a particular instrument illuminant, then computes the CIE XYZ
+ values of that reflectance spectrum under the default D50 or <b>-i</b>
+ parameter illuminant. This is <u>not</u> used to give a more
+ accurate real world result, but to provide simulations of various
+ standardized measurement conditions. For instance, to reproduce ISO
+ 13655:2009 M2 measurement conditions, the <b>-f D50M2</b> could be
+ used (together with the default <b>-i D50</b> setting). There are
+ shortcuts provided for ISO 13655:2009 conditions:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <b>-f M0</b>&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; equivalent to<b>&nbsp;&nbsp;&nbsp; -f A</b><br>
+ &nbsp;&nbsp;&nbsp; <b>-f M1</b> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ equivalent to<b>&nbsp;&nbsp;&nbsp; -f D50</b><br>
+ &nbsp;&nbsp;&nbsp; <b>-f M2</b> &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ equivalent to<b>&nbsp;&nbsp;&nbsp; -f D50M2</b><b><br>
+ </b><br>
+ &nbsp;Note that using <span style="font-weight: bold;">-f</span> <b>M2</b>
+ gives a result that is comparable to that of a U.V. cut filter
+ instrument. See also the discussion <a href="FWA.html">About
+ Fluorescent Whitening Agent compensation</a>.<br>
+ <br>
+ <a name="i"></a> The <b>-i</b> parameter allows specifying a
+ standard or custom illumination spectrum, applied to spectral .ti3
+ data to compute PCS (Profile Connection Space) tristimulus values. <b>A</b>,
+ <b>D50</b>, <b>D65</b>, <b>F5</b>, <b>F8</b>, <b>F10</b> are a
+ selection of standard illuminant spectrums, with <b>D50</b> being
+ the default. If a filename is specified instead, it will be assumed
+ to be an Argyll specific <a href="File_Formats.html#.sp">.sp</a>
+ custom spectrum file. This only works if spectral data is available.
+ Illuminant details are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A&nbsp;&nbsp; CIE
+ tungsten filament lamp 2848K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D50 CIE daylight 5000K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D65 CIE daylight 6500K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F5&nbsp; CIE Fluorescent
+ 6350K, CRI 72<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F8&nbsp; CIE Fluorescent
+ 5000K, CRI 95<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F10 CIE Fluorescent
+ 5000K, CRI 81<br>
+ <br>
+ Custom illuminants are most often used when a&nbsp; viewing booth or
+ other known viewing conditions is going to be used to view results.
+ Other illuminant reference files could be created using a suitable
+ measuring instrument such as a spectrolino, or an eyeone using <a
+ href="spotread.html">spotread</a>, although such instruments do
+ not themselves provide the necessary response down to Ultra Violet
+ that is needed for accurate operation of Fluorescent Whitening Agent
+ compensation. The best way of measuring a custom illuminant is to
+ use <a href="illumread.html">illumread</a>, since it uses a special
+ method to estimate the illuminant UV in a way that complements FWA
+ compensation. (See the discussion above for the <b>-f</b> flag).<br>
+ <br>
+ Note that if an illuminant other than D50 is chosen, the resulting
+ ICC profile will not be standard, and may not work perfectly with
+ other profiles that that use&nbsp; the standard ICC D50 illuminant,
+ particularly if the absolute rendering intent is used. Profiles
+ should generally be linked with other profiles that have the same
+ illuminant and observer.<br>
+ <br>
+ <a name="o"></a> The <b>-o</b> flag allows specifying a tristimulus
+ observer, and is used to compute tristimulus values. The following
+ choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ <br>
+ Note that if an observer other than 1931 2 degree is chosen, the
+ resulting ICC profile will not be standard, and cannot be freely
+ interchanged with other profiles that that use the standard 1931 2
+ degree observer. Profiles should only be linked with other profiles
+ that have the same illuminant and observer. The <b>1978_2</b>
+ observer or <span style="font-weight: bold;">shaw</span> observer
+ may give slightly better results than the <b>1931_2</b> observer.<br>
+ <br>
+ <br>
+ <a name="r"></a> The <b>-r</b> parameter specifies the average
+ deviation of device+instrument readings from the perfect, noiseless
+ values as a percentage. Knowing the uncertainty in the reproduction
+ and test patch reading can allow the profiling process to be
+ optimized in determining the behaviour of the underlying system. The
+ lower the uncertainty, the more each individual test reading can be
+ relied on to infer the underlying systems color behaviour at that
+ point in the device space. Conversely, the higher the uncertainty,
+ the less the individual readings can be relied upon, and the more
+ the collective response will have to be used. In effect, the higher
+ the uncertainty, the more the input test patch values will be
+ smoothed in determining the devices response. If the perfect,
+ noiseless test patch values had a uniformly distributed error of +/-
+ 1.0% added to them, then this would be an average deviation of 0.5%.
+ If the perfect, noiseless test patch values had a normally
+ distributed&nbsp; error with a standard deviation of 1% added to
+ them, then this would correspond to an average deviation of 0.564%.
+ For a lower quality instrument (less than say a Gretag Spectrolino
+ or Xrite DTP41), or a more variable device (such as a xerographic
+ print engine, rather than a good quality inkjet), then you might be
+ advised to increase the <span style="font-weight: bold;">-r</span>
+ parameter above its default value (double or perhaps 4x would be
+ good starting values.) <br>
+ <br>
+ <a name="S"></a><a name="s"></a><span style="font-weight: bold;">-s
+ -S&nbsp; </span>In order to generate perceptual and saturation
+ intent B2A tables for output profiles, it is necessary to specify at
+ least one profile to define what source gamut should be used in the
+ source to destination gamut mapping. [For more information on <span
+ style="text-decoration: underline;">why</span> a source gamut is
+ needed, see <a href="iccgamutmapping.html">About ICC profiles and
+ Gamut Mapping</a>] The <b>-S</b> parameter is used to do this,
+ and doing so causes perceptual and saturation tables to be
+ generated. If only a perceptual intent is needed, then the <b>-s</b>
+ flag can be used, and the saturation intent will use the same table
+ as the perceptual intent. Note that a input, output, display or
+ device colororspace profile should be specified, not a non-device
+ colorspace, device link, abstract or named color profile.<br>
+ If no source gamut is specified for a cLUT Display profile, then an
+ ICC Version 2.2.0 profile will be created with only an A2B0 and B2A0
+ tag. If a source gamut is specified, then an ICC Version 2.4.0
+ profile will be created with a full complement of B2A tags to
+ support all intents. The source gamut is created from the
+ corresponding intent table of the provided profile to the output
+ table being created. A TIFF or JPEG file containing an embedded ICC
+ profile may be supplied as the argument.<br>
+ <span style="font-weight: bold;">Note</span> that input profiles and
+ matrix profiles will only contain a colorimetric intent table or
+ matrix, and hence the <span style="font-weight: bold;">-s</span>
+ and <span style="font-weight: bold;">-S</span> option is not
+ relevant.<br>
+ <br>
+ <a name="nP"></a><span style="font-weight: bold;">-nP</span>:
+ Normally when a source profile is provided to define the source
+ gamut for the output profile perceptual table gamut mapping, the
+ perceptual source table is used to determine this gamut. This is
+ because some profile have gamut transformations in their perceptual
+ A2B tables that is not in the colorimetric A2B table, and this needs
+ to be taken into account in creating the perceptual B2A table, so
+ that when the two profiles are linked together with the perceptual
+ intent, the gamut mapping works as intended. The <span
+ style="font-weight: bold;">-nP</span> option causes the source
+ gamut to be taken from the source profile colorimetric table
+ instead, causing the perceptual gamut mapping created for the
+ perceptual table to be from the natural source colorspace gamut to
+ the output space gamut.<br>
+ <br>
+ <a name="nS"></a><span style="font-weight: bold;">-nS</span>:
+ Normally when a source profile is provided to define the source
+ gamut for the output profile saturation table gamut mapping, the
+ saturation source table is used to determine this gamut. This is
+ because some profile have gamut transformations in their saturation
+ A2B tables that is not in the colorimetric A2B table, and this needs
+ to be taken into account in creating the saturation B2A table, so
+ that when the two profiles are linked together with the saturation
+ intent, the gamut mapping works as intended. The <span
+ style="font-weight: bold;">-nS</span> option causes the source
+ gamut to be taken from the source profile colorimetric table
+ instead, causing the saturation gamut mapping created for the
+ saturation table to be from the natural source colorspace gamut to
+ the output space gamut.<small><span style="font-family: monospace;"></span></small><br>
+ <br>
+ <a name="g"></a>The <span style="font-weight: bold;">-g</span> flag
+ and its argument allow the use of a specific source gamut instead of
+ that of the source profile. This is to allow optimizing the gamut
+ mapping to a source gamut of &nbsp;a particular image, which can
+ give slightly better results that gamut mapping from the gamut of
+ the source colorspace. Such a source image gamut can be created
+ using the <a href="tiffgamut.html"> tiffgamut</a> tool. The gamut
+ provided to the <span style="font-weight: bold;">-g</span> <span
+ style="font-weight: bold;"></span> flag should be in the same
+ colorspace that <span style="font-weight: bold;">colprof</span> is
+ using internally to connect the two profiles. For all intents except
+ the last one (no. <span style="font-weight: bold;">7</span>), the
+ space should be Jab appearance space, with the viewing conditions
+ generally being those of the input profile viewing conditions. The
+ input profile will normally be the one used to create a source image
+ gamut using <span style="font-weight: bold;">tiffgamut</span>.<br>
+ <br>
+ <b><a name="p"></a></b>The <b>-p</b> option allows specifying one
+ or more abstract profiles that will be applied to the output tables,
+ after any gamut mapping. An abstract profile is a way of specifying
+ a color adjustment in a device independent way. The abstract profile
+ might have been created using one of the <span style="font-weight:
+ bold;">tweak</span> tools, such as <a href="refine.html">refine</a>.<br>
+ If a single abstract profile is specified, then it will be applied
+ to all the output tables (colorimetric, perceptual and saturation).
+ To specify different abstract profiles for each output table, use a
+ contiguous comma separated list of filenames. Omit a filename
+ between the commas if no abstract profile is to be applied to a
+ table. For instance: -<span style="font-weight: bold;">p
+ colabst.icm,percabst.icm,satabst.icm</span> for three different
+ abstract transforms, or: <span style="font-weight: bold;">-p
+ ,percabst.icm,</span> for just a perceptual table abstract
+ transform.<br>
+ <br>
+ One strategy for getting the best perceptual results with output
+ profile when using ICC profiles with systems that don't accept
+ device link profiles, is as follows: Specify a gamut mapping profile
+ of opposite type to the type of device being profiled, and when
+ linking, use the relative colorimetric intent if the two profiles
+ are of the same type, and perceptual intent if the two profiles are
+ of the opposite type. For instance, if you are creating a CMYK
+ output profile, specify an RGB profile for the <b>-s</b> or <b>-S</b>
+ parameter. If linking that profile with a CMYK source profile, use
+ relative colorimetric intent, or if linking with an RGB profile, use
+ the perceptual intent. Conversely, if creating an RGB output
+ profile, specify a CMYK profile for the <b>-s</b> or <b>-S</b>
+ parameter, and if linking that profile with an RGB source profile,
+ use relative colorimetric intent, or if linking with a CMYK profile,
+ use the perceptual intent.<br>
+ <br>
+ (Note that the perceptual and saturation table gamut mapping doesn't
+ make any allowance for the application of the abstract profile. This
+ is a bug.)<br>
+ <br>
+ <a name="t"></a><a name="T"></a><span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span>Normally, the gamut mapping used
+ in creating the perceptual and saturation intent tables for output
+ profiles is set to perceptual and saturation gamut mapping (as would
+ be expected), but it is possible to override this default selection
+ for each intent using the <b>-t</b> and <b>-T</b> flags. The <b>-t</b>
+ flag can be used to set the gamut mapping for the perceptual table,
+ and the <b>-T</b> flag can be used to set the gamut mapping for the
+ saturation table. A more detailed description of the different
+ intents is given in <a href="collink.html#i">collink</a>. Note that
+ selecting any of the absolute intents will probably not function as
+ expected, since the perceptual and saturation tables are inherently
+ relative colorimetric in nature.<br>
+ <br>
+ <a name="c"></a><b><a name="d"></a></b>Since appearance space is
+ used in the gamut mapping (just as it is in <a href="collink.html">
+ collink</a>), the viewing conditions for the source and
+ destination colorspaces should really be specified. The source
+ colorspace is the profile specified with the <b>-s</b> or <b>-S</b>
+ flag, and the destination is the profile being created. The <b>-c</b>
+ and <b>-d</b> options allow specification of their respective,
+ associated viewing conditions. The viewing condition information is
+ used to map the profile PCS (Profile Connection Space, which us
+ either XYZ or L*a*b*) color into appearance space (CIECAM02), which
+ is a better colorspace to do gamut mapping in. The viewing
+ conditions allow the conversion into appearance space to take
+ account of how color will be seen under particular viewing
+ conditions.<br>
+ <br>
+ Viewing conditions can be specified in two basic ways. One is to
+ select from the list of "pre canned", enumerated viewing conditions,
+ choosing one that is closest to the conditions that are appropriate
+ for the media type and situation. Alternatively, the viewing
+ conditions parameters can be specified individually. If both methods
+ are used, them the chosen enumerated condition will be used as a
+ base, and its parameters will then be individually overridden.<br>
+ <br>
+ Appearance space is also used to provide a space to map any
+ remaining out of gamut colors (after a possible gamut mapping has
+ been applied) into the device gamut. <br>
+ <br>
+ <b><a name="P"></a></b>The <b>-P</b> option causes diagnostic 3D <a
+ href="File_Formats.html#VRML">VRML</a> plots to be created that
+ illustrate the gamut mappings generated for the perceptual and
+ saturation intent tables.<br>
+ <br>
+ <a name="O"></a>The <span style="font-weight: bold;">-O</span>
+ parameter allows the output file name &amp; extension to be
+ specified independently of the final parameter basename. Note that
+ the full filename must be specified, including the extension.<span
+ style="font-weight: bold;"></span><br>
+ <br>
+ <a name="p1"></a> The final parameter is the file base name for the
+ <a href="File_Formats.html#.ti3">.ti3</a> input test point data, and
+ the resulting <a href="File_Formats.html#ICC">ICC</a> output
+ profile (.icm extension on the MSWindows platform, .icc on Apple or
+ Unix platforms). The <span style="font-weight: bold;">-O</span>
+ parameter will override this default.
+ <h3>Discussion</h3>
+ Note that monochrome profiling isn't currently supported. It may be
+ supported sometime in the future.<br>
+ <br>
+ If the <b>-v</b> flag is used (verbose), then at the end of
+ creating a profile, the maximum and average fit error of the input
+ points to the resulting profile will be reported. This is a good
+ guide as to whether things have gone smoothly in creating a profile.
+ Depending on the type of device, and the consistency of the
+ readings, average errors of 5 or less, and maximum errors of 15 or
+ less would normally be expected. If errors are grossly higher than
+ this, then this is an indication that something is seriously wrong
+ with the device testing, or profile creation.<br>
+ <br>
+ Given a .ti3 file from a display device that contains calibration
+ curves (generated by <a href="dispcal.html">dispcal</a>, passed
+ through <a href="dispread.html">dispread</a>) and the calibration
+ indicates that the VideoLUTs are accessible for the device, then <span
+ style="font-weight: bold;">colprof</span> will convert the
+ calibration into a <span style="font-weight: bold;">vcgt</span> tag
+ in the resulting profile so that the operating system tools can
+ configure the display hardware appropriately, whenever the profile
+ is used. If the VideoLUTs are not marked as being accessible, <span
+ style="font-weight: bold;">colprof</span> will do nothing with the
+ calibration curves. In this case, to apply calibration, the curves
+ have to be incorporated in the subsequent workflow, either by
+ incorporating them into the profile using <a
+ href="applycal.html#p1">applycal</a>, or including them after the
+ profile in a <a href="cctiff.html#p2">cctiff</a> profile chain.<br>
+ <br>
+ Given a .ti3 file from a print device that contains the per-channel
+ calibration information (generated by <a href="printcal.html">printcal</a>,
+ passed through <a href="printtarg.html">printtarg</a> and <a
+ href="chartread.html">chartread</a>), <span style="font-weight:
+ bold;">colprof</span> will save this along with the .ti3 file in
+ the <span style="font-weight: bold;">'targ'</span> text tag in the
+ profile, <span style="font-weight: bold;"></span> so that
+ subsequent evaluation of ink limits can compute the final calibrated
+ device values.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/cube.jpg b/doc/cube.jpg
new file mode 100644
index 0000000..929273c
--- /dev/null
+++ b/doc/cube.jpg
Binary files differ
diff --git a/doc/dispcal.html b/doc/dispcal.html
new file mode 100644
index 0000000..7327c8f
--- /dev/null
+++ b/doc/dispcal.html
@@ -0,0 +1,2256 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispcal</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispcal</b></h2>
+ <h3>Summary</h3>
+ Given calibration target information [white point, maximum
+ brightness, and response curve ("gamma")], display a series of test
+ patches on the display, and using the colorimetric values read,
+ create a calibration lookup tables that make the display meet the
+ desired target. The type of instrument is determined by the
+ communication port selected. Emission and display measurement
+ instruments are supported.<br>
+ <h3>Usage</h3>
+ <font size="-1"><span style="font-family: monospace;">dispcal
+ [-options]</span><i style="font-family: monospace;"> inoutfile</i><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v [n]</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Verbose mode<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [X11 only] Choose X11 display
+ name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [X11 only]Choose the display from the following list (default
+ 1),<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+and
+optionally
+choose
+a
+different
+display
+m
+for
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ VideoLUT access.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Choose
+the
+display
+from
+the
+following
+list
+(default
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1)</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display via a web server at port (default 8080)</span><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span>&nbsp; <span style="font-family: monospace;"></span></font><small
+ style="font-family: monospace;"><span style="font-family:
+ monospace;"></span><a style="font-family: monospace;" href="#c">-c
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ listno</a><span style="font-family: monospace;"> &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set communication port from
+ the following list (default 1)<br>
+ </span></small><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#r">-r</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Report on the calibrated display then
+ exit</span></font><font size="-1"><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#R">-R</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Report on the uncalibrated display then
+ exit</span></font><font size="-1"><span style="font-family:
+ monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#m">-m</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; </span></font><font size="-1"><span
+ style="font-family: monospace;">Skip</span><span
+ style="font-family: monospace;"> adjustment of the monitor
+ controls</span></font><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#o">-o [profile.icm]</a>&nbsp;&nbsp;&nbsp;&nbsp; Create
+ fast matrix/shaper profile [different filename to outfile.icm]<br>
+ &nbsp;<a href="#O">-O description</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fast ICC Profile Description string (Default "outfile")<br>
+ &nbsp;<a href="#u">-u</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Update
+previous
+calibration
+and
+(if
+-o
+used)
+ICC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ profile VideoLUTs</span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#q">-q [lmh]</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Quality - Low, Medium (def), High<br>
+ &nbsp;<a href="#p">-p</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+ Use telephoto mode (ie. for a projector) (if available)<br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><a href="#y">-y X</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display type - instrument specific list to choose from.</span></font><font
+ size="-1"><span style="font-family: monospace;"><br
+ style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#t">-t [temp]</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+White
+Daylight
+locus
+target,
+optional
+target
+temperaturee
+in
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ deg. K (deflt.)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#T">-T [temp]</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+White
+Black
+Body
+locus
+target,
+optional
+target
+temperaturee
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ in deg. K</span></font><br style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#w">-w x,y</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set the target white point as chromaticity coordinates</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#b">-b bright</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set the target white brightness in cd/m^2</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#g">-g gamma</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set the target response curve gamma (Def. 2.4)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use "-gl" for L*a*b* curve</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Use "-gs" for sRGB curve<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+"-g709"
+for
+REC
+709
+curve
+(should
+use
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -a as well!)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use "-g240" for SMPTE 240M curve </span></font><font size="-1"><span
+ style="font-family: monospace;">(should use -a as well!)</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use "-G2.4 -f0" for BT.1886</span></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+ <br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#G">-G gamma</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Set the target response curve actual technical gamma<br>
+ &nbsp;<a href="#f">-f [degree]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Amount
+of
+black
+level
+accounted
+for
+with
+output
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ offset (default all output offset)<br>
+ &nbsp;<a href="#a">-a ambient</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use viewing condition adjustment for ambient in Lux<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#k">-k factor</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Amount to try and correct black point hue. Default 1.0, LCD
+ default 0.0<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#A">-A rate</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Rate of blending from neutral to black point. Default 4.0</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#B">-B bkbright</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set the target black brightness in cd/m^2</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#e">-e [n]</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Run n verify passes on final curves<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#E">-E</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Run only verify pass on installed calibration curves</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;<a href="#P">-P
+ ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
+ and scale it</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ho,vi:
+0.0
+=
+left/top,
+0.5
+=
+center,
+1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ = right/bottom etc.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ss:
+0.5
+=
+half,
+1.0
+=
+normal,
+2.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ = double etc.<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+ ss,vs: = optional horizontal, vertical scale.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;"> &nbsp;<a
+ href="#F">-F</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fill whole screen with black background</span></font><font
+ size="-1"><span style="font-family: monospace;"></span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#n">-n</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;
+[X11
+only]
+Don't
+set
+override
+redirect
+on
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ test window<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#J">-J</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Run instrument calibration first<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Disable initial calibration of instrument if possible</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#H">-H</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
+ available)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"><br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><span style="text-decoration: underline;"></span><a
+ href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Apply Colorimeter Correction Matrix</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
+ file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+Colorimeter
+Calibration
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Spectral Samples for calibration</span><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
+ colorimeter data:</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
+ style="font-family: monospace;">(def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2, 1964_10c<br>
+ &nbsp;<a href="#I">-I b|w</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Drift compensation, Black: -Ib, White: -Iw, Both: -Ibw<br>
+ </span></small><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style=" font-family: monospace;"
+ href="#YA">-<font size="-1">Y</font> A</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; Use non-adaptive integration time mode (if
+ available).</span></font><br>
+ <small><span style="font-family: monospace;"> </span></small><font
+ size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#C">-C "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is set</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#M">-M "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is measured</span></font><font
+ size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+serial
+port
+flow
+control:
+n
+=
+none,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ h = HW, x = Xon/Xoff</span></font><font size="-1"><span
+ style="font-family: monospace;"></span></font><br>
+ <font size="-1"><span style="font-family: monospace;"> </span></font><font
+ size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D [level]</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Print debug diagnostics to stderr</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p1"><i>inoutfile</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ </span><span style="font-family: monospace;">Base name for created
+ or updated </span></font><font size="-1"><a style="font-family:
+ monospace;" href="cal_format.html">.cal</a><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;">&nbsp; and <a
+ href="File_Formats.html#ICC">.icm</a> output files</span></font><br>
+ <br>
+ <h3>Comments<br>
+ </h3>
+ This is the tool is used for adjusting and calibrating a display to
+ reach specified target behaviour, and optionally profiling it.&nbsp;
+ For best results on a CRT, you should run this against a neutral
+ grey desktop background, and avoid having any bright images or
+ windows on the screen at the time you run dispcal. You could also
+ use the <span style="font-weight: bold;">-B</span> option to black
+ the whole screen out, although this will make it impossible to
+ control dispcal unless you have more than one display.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag reports progress information,
+ as well as other statistics about the progress of calibration. A
+ numerical argument greater than 1 gives greater verbosity.<br>
+ <br>
+ <a name="display"></a>When running on a UNIX based system that used
+ the X11 Windowing System, <b>dispcal</b> will by default use the
+ $DISPLAY environment variable to determine which local or remote
+ display and screen to read from. This can be overridden by supplying
+ an X11 display name to the <span style="font-weight: bold;">-display</span>
+ option. Note that if Xinerama is active, you can't select the screen
+ using $DISPLAY or -display, you have to select it using the <span
+ style="font-weight: bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a> By default the main display will be the location of
+ the test window. If the system has more than one display or screen,
+ an alternate display/screen can be selected with the <span
+ style="font-weight: bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispcal</span> so as to display the
+ usage information (i.e. "dispcal -?" or "dispcal --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed, if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or parameter.<br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
+ display are not accessible (i.e. no hardware calibration
+ capability), <span style="font-weight: bold;">dispcal</span> will
+ will issue a warning, but continue creating a calibration based on
+ the display "as-is" rather than its native response. See the <a
+ href="dispcal.html#o">-o</a> flag for an explanation of the
+ implications of having no access to the VideoLUTs.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
+ <a name="dnm"></a>Because of the difficulty cause by TwinView and
+ MergedFB in X11 based systems, you can optionally specify a separate
+ display number after the display that is going to be used to present
+ test patches, for accessing the VideoLUT hardware. This must be
+ specified as a single string, e.g. <span style="font-weight: bold;">-d
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1,2</span> . Some experimentation may be needed using <a
+ href="dispwin.html">dispwin</a> on such systems, to discover what
+ screen has access to the VideoLUT hardware, and which screens the
+ test patches appear on. You may be able to calibrate one screen, and
+ then share the calibration with another screen. Profiling can be
+ done independently to calibration on each screen.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:port</span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way. <b>JavaScript</b>
+ needs to be enabled in your web browser for this to work.<br>
+ <br>
+ Note that if you use this method of displaying test patches, that
+ there is no access to the display VideoLUTs and that the colors will
+ be displayed with 8 bit per component precision, and any
+ screen-saver or power-saver will not be disabled. You will also be
+ at the mercy of any color management applied by the web browser, and
+ may have to carefully review and configure such color management.
+ See the <a href="#o">-o</a> flag for an explanation of the
+ implications of having no access to the VideoLUTs.<br>
+ <br>
+ <a name="c"></a> <span style="font-weight: bold;">-c</span> The
+ instrument is assumed to communicate through a USB or serial
+ communication port, and the port can be selected with the <b>-c</b>
+ option, if the instrument is not connected to the first port. If you
+ invoke <span style="font-weight: bold;">dispcal</span> so as to
+ display the usage information (i.e. "dispcal -?" or "dispcal --"),
+ then the discovered USB and serial ports will be listed. On
+ UNIX/Linux, a list of all possible serial ports are shown, but not
+ all of them may actually be present on your system.<br>
+ <br>
+ <a name="r"></a> The -<span style="font-weight: bold;">r</span> and
+ <span style="font-weight: bold;"><a name="R"></a>-R </span>flags
+ perform a quick measurement of current display behaviour, reports
+ and then exits. If the <span style="font-weight: bold;">-r</span>
+ flag is used the measurement are taken using the currently loaded
+ calibration (Video LUT) curves. If <span style="font-weight: bold;">-R</span>
+ is use, then the uncalibrated ("raw" or "native") behaviour is
+ measured. Reported are: <br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Black Brightness in cd/m^2<br>
+ &nbsp;&nbsp;&nbsp; White Brightness in cd/m^2<br>
+ &nbsp;&nbsp;&nbsp; The approximate Gamma<br>
+ &nbsp;&nbsp;&nbsp; The white point x,y chromaticity co-ordinates<br>
+ &nbsp;&nbsp;&nbsp; The correlated color temperature in Kelvin, and
+ the CIEDE200 to the Black Body locus.<br>
+ &nbsp;&nbsp;&nbsp; The correlated Daylight temperature in Kelvin,
+ and the CIEDE200 to the Daylight locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin, and the
+ CIEDE200 to the Black Body locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual Daylight temperature in Kelvin, and
+ the CIEDE200 to the Daylight locus.<br>
+ &nbsp;&nbsp;&nbsp; The visual color temperature in Kelvin<br>
+ (for <span style="font-weight: bold;">-R </span>"raw":)<br>
+ &nbsp;&nbsp;&nbsp; The apparent VideoLUT entry number of significant
+ bits.<br>
+ <br>
+ Note that the correlated color temperature is the temperature of a
+ black body radiator that has the closest color to the white point
+ measured using the traditional CIE 1960 UCS space color difference
+ formula. The correlated daylight temperature is a similar thing,
+ except the CIE daylight locus is used. The visual color temperature
+ values are calculated similarly to the correlated color
+ temperatures, but using the modern CIEDE2000 color difference
+ formula to calculate a better visual approximation to the closest
+ temperature to the displays white point. There will be no difference
+ between the UCS and CIEDE2000 temperatures if the display white
+ point actually lies on the particular locus.<br>
+ <br>
+ <a name="m"></a> The -<span style="font-weight: bold;">m</span>
+ option skips the usual process of adjusting the display monitor
+ contrast, brightness and white point controls, and skips straight to
+ calibration.<br>
+ <br>
+ <a name="o"></a><span style="font-weight: bold;">-o [</span><span
+ style="font-style: italic;">profile.icm</span><span
+ style="font-weight: bold;">]</span> Normally <span
+ style="font-weight: bold;">dispcal</span> creates just a
+ calibration file, which can then be used for subsequent
+ characterization using <a href="dispread.html">dispread</a> and
+ profiling using <a href="colprof.html">colprof</a>. If the <span
+ style="font-weight: bold;">-o</span> flag is used, <span
+ style="font-weight: bold;">dispcal</span> will also create a
+ shaper/matrix profile. By default it will create a profile named <span
+ style="font-weight: bold;">inoutfile.icm</span>, but a differently
+ named file can be created or updated by specifying the name after
+ the <span style="font-weight: bold;">-o</span> flag. If the <span
+ style="font-weight: bold;">-u</span> flag is used with <span
+ style="font-weight: bold;">-o</span>, then the ICC profile <span
+ style="font-weight: bold;">vcgt</span> calibration curves will be
+ updated.<br>
+ <br>
+ Note that if VideoLUT access is not possible for the display, that
+ hardware calibration is not possible. dispcal will create
+ calibration curves anyway with a warning, and if a profile is
+ created, it will not contain a 'vcgt' tag, but instead will have the
+ calibration curves incorporated into the profile itself. If
+ calibration parameters are chosen that change the displays white
+ point or brightness, then this will result in a slightly unusual
+ profile that has a white point that does not correspond with
+ R=G=B=1.0. Some systems may not cope properly with this type of
+ profile. See the <a href="Scenarios.html#PM7">tutorial</a> for a
+ further explanation.<br>
+ <br>
+ <a name="O"></a>The <b>-O</b> parameter allows setting of the
+ shaper/matrix profile description tag. The parameter should be a
+ string that describes the device and profile. With most command line
+ shells, it will be necessary to enclose the parameter with double
+ quotes, so that spaces and other special characters are included in
+ the parameter, and not mistaken for the start of another flag, or as
+ a final command line parameter. Many programs that deal with ICC
+ profiles use the description tag to identify a profile, rather than
+ the profile filename, so using a descriptive string is important in
+ being able to find a profile. By default, the profile file name will
+ be used as the description.<br>
+ <br>
+ <a name="u"></a><span style="font-weight: bold;">-u</span> Normally
+ <span style="font-weight: bold;">dispcal</span> creates a new
+ calibration file and optional profile, based on the requested
+ targets and the response of the display. This can take a fair amount
+ of time, particularly if a high quality level has been selected, so
+ to speed up the process of keeping a display in calibration the <span
+ style="font-weight: bold;">-u</span> flag can be used. This uses
+ the same calibration targets as the previous calibration but does a
+ smaller number of refinement passes, enough to improve the accuracy
+ of the calibration to account for drift in the device. If the <span
+ style="font-weight: bold;">-o</span> flag is used as well, then
+ the ICC profile <span style="font-weight: bold;"></span>will have
+ its vcgt tag updated with the new calibration. This keeps the
+ profile up to date with the display. Normally <span
+ style="font-weight: bold;">dispcal -u</span> will use the same
+ quality level that was specified in the previous calibration, but
+ this can be overridden using the <span style="font-weight: bold;">-q</span>
+ flag. Any options that attempt to change the calibration target (ie.
+ white point, brightness, gamma etc.) will be ignored. Adjustment of
+ the display monitor controls is skipped. A profile cannot be updated
+ if the display does not support hardware calibration (no VideoLUT
+ access).<br>
+ <br>
+ <a name="q"></a>&nbsp; Quality - Low, Medium (def), High. The <span
+ style="font-weight: bold;">-q</span> flag determines how much time
+ and effort to go to in calibrating the display. The higher the
+ quality, the more test readings will be done, the more refinement
+ passes will be done, the tighter will be the accuracy tolerance, and
+ the more detailed will be the calibration of the display. The result
+ will ultimately be limited by the accuracy of the instrument, the
+ repeatability of the display and instrument, and the resolution of
+ the Video Lookup table entries and Digital or Analogue output
+ (RAMDAC).<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ allows measuring in telephoto mode, using instruments that support
+ this mode, e.g. the ColorMunki. Telephoto mode is one for taking
+ emissive measurements from a distance (ie. telespectometer,
+ tele-colorimeter) mode, and typically would be used for measuring
+ projector type displays. If a device does not support a specific
+ telephoto mode, then the normal emissive mode may be suitable for
+ measuring projectors.<br>
+ <br>
+ <a name="y"></a>&nbsp; The <span style="font-weight: bold;">-y</span>
+ flag allows setting the Display Type. The selection typically
+ determines two aspects of of the instrument operation: <span
+ style="font-weight: bold;">1)</span> It may set the measuring mode
+ to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument calibration matrix suitable for a particular display
+ type. The selections available depends on the type and model of
+ instrument, and a list of the options for the discovered instruments
+ will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. <b>3)</b> Any installed CCSS files
+ (if applicable), or CCMX files. These files are typically created
+ using <a href="file:///D:/src/argyll/doc/ccxxmake.html">ccxxmake</a>,
+ and installed using <a
+ href="file:///D:/src/argyll/doc/oeminst.html">oeminst</a>. The
+ default and Base Calibration types will be indicated in the usage.<br>
+ <br>
+ <a name="t"></a><span style="text-decoration: underline;"></span> <span
+ style="font-weight: bold;">-t</span> Set the target white point
+ locus to the equivalent of a Daylight spectrum of the given
+ temperature in degrees Kelvin. By default the white point target
+ will be the native white of the display, and it's color temperature
+ and delta E to the daylight spectrum locus will be shown during
+ monitor adjustment, and adjustments will be recommended to put the
+ display white point directly on the Daylight locus. If a Daylight
+ color temperature is given as an argument to <span
+ style="font-weight: bold;">-t</span>, then this will become the
+ target of the adjustment, and the recommended adjustments will be
+ those needed to make the monitor white point meet the target.
+ Typical&nbsp; values might be 5000 for matching printed output, or
+ 6500, which gives a brighter, bluer look. A white point temperature
+ different to that native to the display may limit the maximum
+ brightness possible.<br>
+ <br>
+ <a name="T"></a><span style="text-decoration: underline;"></span> <span
+ style="font-weight: bold;">-T</span>&nbsp; Same functionality as
+ the <span style="font-weight: bold;">-t</span> option, except the
+ white point locus will be the Black Body, or Planckian locus, rather
+ than the Daylight locus. While these two white point loci are quite
+ close, they are subtly different. If a temperature is given as an
+ argument, this will become the Black Body target temperature during
+ adjustment.<br>
+ <br>
+ <a name="w"></a><span style="font-weight: bold;">-w</span>&nbsp; An
+ alternative to specifying a&nbsp; white point target in Daylight or
+ Black Body degrees Kevin, is to specify it in chromaticity
+ co-ordinates. This allows the white point to be a color other than
+ one on the Daylight or Black Body. Note that the x,y numbers must be
+ specified as a single string (no space between the numbers and the
+ comma).<br>
+ <br>
+ <a name="b"></a><span style="font-weight: bold;">-b</span>&nbsp; Set
+ the target brightness of white in cd/m^2. If this number cannot be
+ reached, the brightest output possible is chosen, consistent with
+ matching the white point target. Note that many of the instruments
+ are not particularly accurate when assessing the absolute display
+ brightness in cd/m^2. <span style="font-weight: bold;">NOTE</span>
+ that some LCD screens behave a little strangely near their absolute
+ white point, and may therefore exhibit odd behavior at values just
+ below white. It may be advisable in such cases to set a brightness
+ slightly less than the maximum such a display is capable of.<br>
+ <br>
+ <a name="g"></a><span style="font-weight: bold;">-g gamma</span>&nbsp;
+Set
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the target response curve gamma. This is normally an exponential
+ curve (output = input ^gamma), and defaults to 2.4 on MSWindows and
+ Macintosh OS X 10.6 or latter and Linux/Unix (which is typical of a
+ CRT type displays real response), and 1.8 on a Macintosh (prior to
+ OS X 10.6). Four pre-defined curves can be used as well: the sRGB
+ colorspace response curve, which is an exponent curve with a
+ straight segment at the dark end and an overall response of
+ approximately gamma 2.2 (<span style="font-weight: bold;">-gs</span>),
+the
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ L* curve, which is the response of the CIE L*a*b* perceptual
+ colorspace (<span style="font-weight: bold;">-gl</span>). the REC
+ 709 video standard response curve (<span style="font-weight: bold;">-g709</span>)
+ and the SMPTE 240M video standard response curve (<span
+ style="font-weight: bold;">-g240</span>) <br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that a real display
+ can't reproduce any of these ideal curves, since it will have a
+ non-zero black point, whereas all the ideal curves assume zero light
+ at zero input. In the case of a gamma curve target, dispcal uses an
+ actual technical power curve shape that aims for the same relative
+ output at 50% input as the ideal gamma power curve. To allow for the
+ non-zero black level of a real display, by default <span
+ style="font-weight: bold;">dispcal</span> will offset the target
+ curve values so that zero input gives the actual black level of the
+ display (output offset). This ensures that the target curve better
+ corresponds to the typical natural behavior of displays, but it may
+ not be the most visually even progression from display minimum, but
+ this behavior can be changed using the <span style="font-weight:
+ bold;">-f</span> option (see below).<br>
+ <br>
+ <span style="font-weight: bold;">Also note</span> that many color
+ spaces are encoded with, and labelled as having a gamma of
+ approximately<span style="font-weight: bold;"> 2.2</span> (ie. sRGB,
+ REC 709, SMPTE 240M, Macintosh OS X 10.6), but are actually intended
+ to be displayed on a display with a typical CRT gamma of <span
+ style="font-weight: bold;">2.4</span> viewed in a darkened
+ environment. This is because this <span style="font-weight: bold;">2.2</span>
+ gamma is a source gamma encoding in bright viewing conditions such
+ as a television studio, while typical display viewing conditions are
+ quite dark by comparison, and a contrast expansion of (approx.)
+ gamma 1.1 is desirable to make the images look as intended. So if
+ you are displaying images encoded to the sRGB standard, or
+ displaying video through the calibration, just setting the gamma
+ curve to sRGB or REC 709 (respectively) is probably <span
+ style="font-weight: bold;">not what you want!</span> What you
+ probably want to do, is to set the gamma curve to about gamma 2.4,
+ so that the contrast range is expanded appropriately, or <span
+ style="text-decoration: underline; font-weight: bold;">alternatively</span>
+ use sRGB or REC 709 or a gamm of 2.2 but <span style="font-weight:
+ bold;">also</span> use the <span style="font-weight: bold;">-a</span>
+ parameter to specify the actual ambient viewing conditions, so that
+ <span style="font-weight: bold;">dispcal</span> can make an
+ appropriate contrast enhancement. If your instrument is capable of
+ measuring ambient light levels, then you can do so during the
+ interactive display control adjustment. See
+ &lt;http://www.color.org/sRGB.xalter&gt; for details of how sRGB is
+ intended to be used.<br>
+ <br>
+ It is hard to know whether Apple Macintosh computers prior to OS X
+ 10.6 should also have such an adjustment, since it is not really
+ possible to know whether colors labelled as being in such a
+ colorspace are actually encoded in that gamma with the expectation
+ that they will be displayed on a display with that actual response,
+ or whether they are intended to be displayed on a display that
+ contrast expands by a power 1.1.&nbsp; Both situations might be the
+ case, depending on how source material is created!<br>
+ <br>
+ <a name="G"></a><span style="font-weight: bold;">-G gamma</span>&nbsp;
+As
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ explained above, the gamma value provided to the <span
+ style="font-weight: bold;">-g</span> option is used to set and
+ actual response curve that makes an allowance for the non-zero black
+ of the actual display, and will have the same relative output at 50%
+ input as the ideal gamma power curve, and so best matches typical
+ expectations. The <span style="font-weight: bold;">-G</span> option
+ is an alternative that allows the <span style="font-weight: bold;">actual</span>
+ power to be specified instead, meaning that when combined with the
+ displays non-zero black value, the response at 50% input will
+ probably not match that of the ideal power curve with that gamma
+ value.<br>
+ <br>
+ <a name="f"></a><span style="font-weight: bold;">-f [degree]</span>:
+ As explained in for the <span style="font-weight: bold;">-g</span>
+ and <span style="font-weight: bold;">-G</span> options, real
+ displays do not have a zero black response, while all the target
+ response curves do, so this has to be allowed for in some way. The
+ default way of handling this (equivalent to -f 1.0)&nbsp; is to
+ allow for this at the output of the ideal response curve, by
+ offsetting and scaling the output values.<span style="font-weight:
+ bold;"></span> This defined a curve that will match the responses
+ that many other systems provide and may be a better match to the
+ natural response of the display, but will give a less visually even
+ response from black<span style="font-weight: bold;"></span>. The
+ other alternative is to offset and scale the input values into the
+ ideal response curve so that zero input gives the actual non-zero
+ display response. This ensures the most visually even progression
+ from display minimum, but might be hard to achieve since it is
+ different to the naturally response of a display. A subtlety is to
+ provide a split between how much of the offset is accounted for as
+ input to the ideal response curve, and how much is accounted for at
+ the output, and this can be done by providing a parameter <span
+ style="font-weight: bold;">-f degree</span>, where the degree is
+ 0.0 accounts for it all as input offset, and 1.0 accounts for all of
+ it as output offset. If <span style="font-weight: bold;">-f</span>
+ is used without a specified degree, a degree of 0.0 is assumed, the
+ opposite of the default. <span style="font-weight: bold;">Note</span>
+ that using all input offset (degree == 0.0) is equivalent to the use
+ of the <span style="font-weight: bold;">BT.1886</span> transfer
+ function.<br>
+ <br>
+ <a name="a"></a><span style="font-weight: bold;">-a ambient</span>:
+ As explained for the <span style="font-weight: bold;">-g</span>
+ parameter, often colors are encoded in a situation with viewing
+ conditions that are quite different to the viewing conditions of a
+ typical display, with the expectation that this difference in
+ viewing conditions will be allowed for in the way the display is
+ calibrated. The <span style="font-weight: bold;">-a</span> option
+ is a way of doing this. By default <span style="font-weight: bold;">dispcal</span>
+ will not make any allowances for viewing conditions, but will
+ calibrate to the specified response curve, but if the <span
+ style="font-weight: bold;">-a</span> option is used, or the
+ ambient level is measured during the interactive display controls
+ portion of the calibration, an appropriate viewing conditions
+ adjustment will be performed. For a gamma value or sRGB, the
+ original viewing conditions will be assumed to be that of the sRGB
+ standard viewing conditions, while for REC 709 and SMPTE 240M they
+ will be assumed to be television studio viewing conditions. By
+ specifying or measuring the ambient lighting for your display, a
+ viewing conditions adjustment based on the CIECAM02 color appearance
+ model will be made for the brightness of&nbsp; your display and the
+ contrast it makes with your ambient light levels. <br>
+ <br>
+ <a name="k"></a><span style="font-weight: bold;">-k factor</span>:
+ Normally this will be set automatically, based on the measured black
+ level of the display. A <span style="font-weight: bold;">-k</span>
+ factor of 1.0 will make all colors down the neutral axis (R=G=B)
+ have the same hue as the chosen white point. Near the black point,
+ red, green or blue can only be added, not subtracted from zero, so
+ the process of making the near black colors have the desired hue,
+ will <span style="font-weight: bold;">lighten</span> them to some
+ extent. For a device with a good contrast ratio or a black point
+ that has nearly the same hue as the white, this should not affect
+ the contrast ration too severely. If the device contrast ratio is
+ not so good, and the native black hue is noticeably different to
+ that of the chosen white point (which is often the case for <span
+ style="font-weight: bold;">LCD</span> type displays, or <span
+ style="font-weight: bold;">CRT</span> type displays with one
+ channel which has a poor level of black), this could have a
+ noticeably detrimental effect on an already limited contrast ratio,
+ and result in a black that is not as good as it can be, and a lower
+ <span style="font-weight: bold;">-k</span> factor should be used. <span
+ style="font-weight: bold;">-k</span> values can range between 0.0
+ (no correction of black) to 1.0 (full correction of black). If less
+ than full correction is chosen, then the resulting calibration
+ curves will have the target white point down most of the curve, but
+ will then blend over to the native or compromise black point that is
+ blacker, but not of the right hue. The rate of this blend can be
+ controlled with the <span style="font-weight: bold;">-A</span>
+ parameter (see below).<br>
+ <br>
+ <a name="A"></a><span style="font-weight: bold;">-A rate</span>:&nbsp;
+If
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ the black point is not being set completely to the same hue as the
+ white point (ie. because the <span style="font-weight: bold;">-k</span>
+ factor is less than 1.0), then the resulting calibration curves will
+ have the target white point down most of the curve, but will then
+ blend over to the native or compromise black point that is blacker,
+ but not of the right hue. The rate of this blend can be controlled
+ with the <span style="font-weight: bold;">-A</span> parameter. The
+ default value 4.0, which results in a target that switches from the
+ white point target to the black, moderately close to the black
+ point. While this typically gives a good visual result with the
+ target neutral hue being maintained to the point where the crossover
+ to the black hue is not visible, it may be asking too much of some
+ displays (typically LCD type displays), and there may be some visual
+ effects due to inconsistent color with viewing angle. For this
+ situation a smaller value may give a better visual result (e.g. try
+ values of 3.0 or 2.0. A value of 1.0 will set a pure linear blend
+ from white point to black point). If there is too much coloration
+ near black, try a larger value, e.g. 6.0 or 8.0.<br>
+ <br>
+ <a name="B"></a><span style="font-weight: bold;">-B</span>&nbsp; Set
+ the target brightness of black in cd/m^2. Setting too high a value
+ may give strange results as it interacts with trying to achieve the
+ target "advertised" gamma curve shape. You could try using -f 1 if
+ this causes a problem.<br>
+ <br>
+ <a name="e"></a><span style="font-weight: bold;">-e [n]</span> Run <span
+ style="font-weight: bold;">n</span> verify passes on the final
+ curves. This is an extra set of instrument readings, that can be
+ used to estimate how well the device will match the targets with the
+ computed calibration curves. Note that the usefulness of the
+ verification is sometimes limited by the repeatability of the device
+ &amp; instrument readings. This is often evident for CRT displays,
+ which (due to their refresh rate) flicker. More than one
+ verification pass can be done by providing the parameter <span
+ style="font-weight: bold;">n</span>, and by then comparing the
+ successive verifications, some idea of the repeatability can be
+ ascertained. The verification uses a fixed number of semi-random
+ test values to test the calibration.<br>
+ <br>
+ <a name="E"></a><span style="font-weight: bold;">-E</span> Run
+ verify pass on the display as it is currently setup (currently
+ installed LUT curves). This will use the usual input parameters to
+ establish the expected (target) characteristic. <span
+ style="font-weight: bold;">Note</span> that if the initial
+ calibration was modified due to it being out of gamut of the
+ display, verify will show the resulting discrepancy. You can use <a
+ href="dispwin.html">dispwin</a> to load a <span
+ style="font-weight: bold;">.cal</span> file into the display
+ before running dispcal <span style="font-weight: bold;">-E</span>.
+ Note that if you set an Ambient light level interactively during the
+ calibration, you need to enter the same number that was measured and
+ set using the <span style="font-weight: bold;">-a</span> parameter
+ for verify.<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="n"></a><span style="font-weight: bold;">-n</span> When
+ running on a UNIX based system that used the X11 Windowing System, <b>dispcal</b>
+ normally selects the override redirect so that the test window will
+ appear above any other windows on the display. On some systems this
+ can interfere with window manager operation, and the <b>-n</b>
+ option turns this behaviour off.<br>
+ <br>
+ <a name="J"></a> The -<span style="font-weight: bold;">J</span>
+ option runs through the black and sensor relative calibration
+ routines for the Xrite DTP92 and DTP94 instruments, the black level
+ calibration for the Eye-One Display 1, and a CRT frequency
+ calibration for the Eye-One Display 2. For the black calibration the
+ instrument should be placed on an opaque, black surface, and any
+ stray light should be avoided by placing something opaque over the
+ instrument. If a Spectrolino is being used, then a white and black
+ calibration will always be performed before the instrument can be
+ placed on the display, unless the <a href="dispcal.html#N">-N</a>
+ flag is used. Generally it is not necessary to do a calibration
+ every time an instrument is used, just now and again. There is also
+ no point in doing&nbsp; a CRT frequency calibration, as this will be
+ done automatically at the commencement of patch reading, and will be
+ lost between runs.<br>
+ <br>
+ <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it, such as the Eye-One Pro. See <a
+ href="instruments.html">Operation of particular instruments</a>
+ for more details. This may give better accuracy for display
+ measurements.<br>
+ <br>
+ <a name="X1"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccmx</span></span> option reads
+ a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
+ from the given file, and applies it to the colorimeter instruments
+ readings. This can improve a colorimeters accuracy for a particular
+ type of display. A list of contributed <span style="font-weight:
+ bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
+ <br>
+ <a name="X2"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccss</span></span> option reads
+ a <a href="File_Formats.html#.ccss">Colorimeter Calibration
+ Spectral Sample</a> from the given file, and uses it to set the
+ colorimeter instruments calibration. This will only work with
+ colorimeters that rely on sensor spectral sensitivity calibration
+ information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
+ or the DataColor <span style="font-weight: bold;">Spyder4</span>).This
+can
+improve
+a
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ colorimeters accuracy for a particular type of display.<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values from spectral readings or using a colorimeter
+ that has CCSS capability. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
+ observer that has been adjusted using a 3x3 matrix to better agree
+ with the 1931 2 degree observer.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you select
+ anything other than the default 1931 2 degree observer, that the Y
+ values will not be cd/m^2, due to the Y curve not being the CIE 1924
+ photopic V(&#955;) luminosity function.<br>
+ <br>
+ <a name="I"></a> The -<span style="font-weight: bold;">I <span
+ style="font-style: italic;">b|w</span></span> options invoke
+ instrument black level, and display white level compensation
+ (respectively). Instrument black level drift compensation attempts
+ to combat instrument black calibration drift by using a display
+ black test patch as a reference. If an instrument is not
+ acclimatised sufficiently to the measurement conditions, changes in
+ temperature can affect the black readings. Display white level drift
+ compensation attempts to combat changes in display brightness as it
+ warms up by measuring a white patch every so often, and using it to
+ normalise all the other readings. If just instrument black drift
+ compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
+ If just display white level compensation is needed, use <span
+ style="font-weight: bold;">-Iw</span>. If both are needed, use <span
+ style="font-weight: bold;">-Ibw</span> or <span
+ style="font-weight: bold;">-Iwb</span>.<span style="font-weight:
+ bold;"> </span><br>
+ <br>
+ <a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
+ option uses a non-adaptive integration time emission measurement
+ mode, if the instrument supports it, such as the Eye-One Pro or
+ ColorMunki. By default an adaptive integration time measurement mode
+ will be used for emission measurements, but some instruments support
+ a fixed integration time mode that can be used with display devices.
+ This may give increased consistency and faster measurement times,
+ but may also give less accurate low level readings.<br>
+ <br>
+ <a name="C"></a> The -<span style="font-weight: bold;">C</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of relaying each test value to some other display than that
+ on the system running dispcal (for instance, a photo frame, PDA
+ screen etc.), by causing the given command to be invoked to the
+ shell, with six arguments. The first three arguments are the RGB
+ test color as integers in the range 0 to 255, the second three
+ parameters are the RGB test color as floating point numbers in the
+ range 0.0 to 1.0. The script or tool should relay the given color to
+ the screen in some manner (e.g. by generating a raster file of the
+ given color and sending it to the display being profiled), before
+ returning. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of gathering each test value from some external source, such
+ as an instrument that is not directly supported by Argyll. The given
+ command is involked to the shell, with six arguments. The first
+ three arguments are the RGB test color as integers in the range 0 to
+ 255, the second three parameters are the RGB test color as floating
+ point numbers in the range 0.0 to 1.0. The script or tool should
+ create a file called <span style="font-weight: bold;">"command.meas</span>"
+ that contains the XYZ values for the given RGB (or measured from the
+ test window) in cd/m^2 as three numbers separated by spaces, before
+ returning. If the command returns a non-zero return value, dispcal
+ will abort. Note that a test window will also be created on the
+ system running dispcal.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="p1"></a><span style="font-weight: bold;">inoutfile</span>
+ The final parameter on the command line is the base filename for the
+ <a href="cal_format.html">.cal</a> file and the optional ICC
+ profile. Normally this will be created (or an existing file will be
+ overwritten). If the <span style="font-weight: bold;">-u</span>
+ flag is used, then these files will be updated. If a different ICC
+ profile name needs to be specified, do so as an argument to the <span
+ style="font-weight: bold;">-o</span> flag.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h2><a name="Adjustment"></a>Discussion and guide to display control
+ adjustment:</h2>
+ <br>
+ The adjustment of the display controls (brightness, contrast, R, G
+ &amp; B channel controls etc.) is very dependent on the particular
+ monitor. Different types and brands of monitors will have different
+ controls, or controls that operate in different ways. Some displays
+ have almost no user controls, and so you may well be best skipping
+ display adjustment, and going straight to calibration.<br>
+ <br>
+ Almost all LCD displays lack a real <span style="font-weight:
+ bold;">contrast</span> control. Those that do present such a
+ control generally fake it by adjusting the video signal. For this
+ reason it is usually best to set an LCD's <span style="font-weight:
+ bold;">contrast</span> control at its neutral setting (ie. the
+ setting at which it doesn't change the video signal). Unfortunately,
+ it can be hard to know what this neutral setting is. On some
+ displays it is 50%, others 75%. If the LCD display has a "reset to
+ factory defaults" mode, then try using this first, as a way of
+ setting the <span style="font-weight: bold;">contrast</span>
+ control to neutral. The LCD <span style="font-weight: bold;">brightness</span>
+ control generally adjusts the level of backlighting the display
+ gets, which affects the maximum brightness, and also tends to raise
+ or lower the black level in proportion, without changing the
+ displays response curve shape or overall contrast ratio. If your LCD
+ display has a <span style="font-weight: bold;">backlight</span>
+ control as well as a <span style="font-weight: bold;">brightness</span>
+ control, then the brightness control is also probably being faked,
+ and you are probably better off setting it to it's neutral setting,
+ and using the <span style="font-weight: bold;">backlight</span>
+ control in place of <span style="font-weight: bold;">brightness</span>
+ in the following adjustments.<br>
+ <br>
+ Some high end displays have the ability to mimic various standard
+ colorspaces such as sRGB or AdobeRGB. You could choose to calibrate
+ and profile the display in such an emulation mode, although you
+ probably don't want to fight the emulations white point and gamma.
+ To get the best out of such a display you really want to choose it's
+ "Native Gamut" setting, whatever that is called. Note that some
+ people have reported bad experiences in trying to use "6-axis custom
+ controls" on displays such as the Dell U2410, so attempting to use
+ such a mode should be approached with caution. Ideally such a mode
+ should be used to give just the underlying native display response,
+ but the settings to achieve this may be very difficult to determine,
+ and/or it may not be possible, depending on how such a mode distorts
+ the RGB signals.<br>
+ <br>
+ On CRT based displays, the <span style="font-weight: bold;">brightness</span>
+ control generally adjusts the black level of the display (sometimes
+ called the <span style="font-weight: bold;">offset</span>), and as
+ a side effect, tends to change the maximum brightness too. A CRT <span
+ style="font-weight: bold;">contrast</span> control generally
+ adjusts the maximum brightness (sometimes called <span
+ style="font-weight: bold;">gain</span>) without affecting the
+ black level a great deal. On a CRT both the <span
+ style="font-weight: bold;">brightness</span> and <span
+ style="font-weight: bold;">contrast</span> controls will tend to
+ affect the shape or gamma of the display response curve.<br>
+ <br>
+ Many displays have some sort of color temperature adjustment. This
+ may be in the form of some pre-set color temperatures, or in the
+ form of individual Red, Green and Blue channel gain adjustments.
+ Some CRT displays also have R, G &amp; B channel offset adjustments
+ that will affect the color temperatures near black, as well as
+ affect the individual channels curve shape. The color temperature
+ adjustment will generally affect the maximum brightness, and may
+ also affect the black level and the shape of the display response
+ curves.<br>
+ <br>
+ Some special (expensive) LCD displays may have a white point
+ adjustment that changes the color of the backlight. If you do not
+ have one of these types of LCD displays, then attempting to change
+ the white point of the display (even if it appears to have a "<span
+ style="font-weight: bold;">white point selection</span>" or <span
+ style="font-weight: bold;">R/G/B</span> "<span style="font-weight:
+ bold;">gain</span>" controls") may not be a good idea, as once
+ again these controls are probably being faked by manipulating the
+ signal levels. Even if you do manage to change the white point
+ significantly, it may do things like change the mid tone color too
+ dramatically, or create a display response that is hard to correct
+ with calibration, or results in side effects such as quantization
+ (banding) or other undesirable effects. You may have to try out
+ various controls (and your aim points for the display calibration),
+ to decide what is reasonable to attempt on an LCD display.<br>
+ <br>
+ Due to the variety of controls as well as the interaction between
+ them, it can be an iterative process to arrive at a good monitor
+ set-up, before proceeding on to calibrating and profiling a display.
+ For this reason, <span style="font-weight: bold;">dispcal</span>
+ offers a menu of adjustment modes, so that the user can
+ interactively and iteratively adjust the display controls to meet
+ the desired targets.<br>
+ <br>
+ &nbsp; 1) Black level (CRT: Brightness)<br>
+ &nbsp; 2) White point (Color temperature, R,G,B, Gain/Contrast)<br>
+ &nbsp; 3) White level (CRT: Gain/Contrast, LCD:
+ Brightness/Backlight)<br>
+ &nbsp; 4) Black point (R,G,B, Offset/Brightness)<br>
+ &nbsp; 5) Check all<br>
+ &nbsp; 6) Measure and set ambient for viewing condition adjustment<br>
+ &nbsp; 7) Continue on to calibration<br>
+ &nbsp; 8) Exit<br>
+ <br>
+ There are four basic adjustment modes. Normally one would proceed
+ through them in the order above, then perhaps repeat the first
+ adjustment, before checking the overall settings. The White point
+ and White level modes operate slightly differently, depending on
+ whether a white target point has been set using the <span
+ style="font-weight: bold;">-t -T</span> or <span
+ style="font-weight: bold;">-w</span> options, and on whether a
+ brightness target has been set using the <span style="font-weight:
+ bold;">-b</span> option.<br>
+ <br>
+ <br>
+ The first mode lets you adjust the black level of a CRT display.
+ Given the current white level, it calculates a value that should
+ produce a 1% display brightness if the black level is set correctly.
+ After doing some initial measurements, it will show the target
+ brightness value (in cd/m^2) on one line, and then underneath it
+ will show continuously updated readings from the display. The left
+ most character will switch from '\' to '/' or back again each time a
+ reading is updated. Some instruments can be quite slow in measuring
+ dark colors, and it's best to wait for a reading update before
+ changing the controls more than once. Underneath the target value is
+ displayed the current reading, and to the right of this is a '+',
+ '-' or '=' symbol, which gives a hint as to which way to adjust the
+ brightness control to improve the match to the target.<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Adjust CRT brightness to get target level.
+ Press space when done.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp; Target
+ 0.60</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; / Current 0.68&nbsp;
+ -</span></small><br>
+ <br>
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The second mode lets you adjust the color of the white point of the
+ display. If a target white point has been set, it will show the
+ target brightness value (in cd/m^2) on one line, together with the
+ target chromaticity co-ordinates for the white point, and then
+ underneath it will show continuously updated readings from the
+ display. The left most character will switch from '\' to '/' or back
+ again each time a reading is updated. Underneath the target
+ brightness value is displayed the current reading, and then the
+ current chromaticity co-ordinate values. To the right of this is the
+ current delta E of the white point from the target, and further to
+ the right are hints '+', '-' or '='&nbsp; as to which direction to
+ adjust the individual Red, Green and Blue gain settings to move the
+ white point in the direction of the target, and reduce the delta E.
+ If the symbol is doubled, then this channel will have the greatest
+ effect. If you do not have individual channel gain controls, then
+ try choosing amongst color temperature pre-sets, to find one with
+ the lowest delta E. Depending on the stability of the display, the
+ coarseness of the controls, and the repeatability of the instrument,
+ you may not be able to get a perfectly zero delta E.<br>
+ <br>
+ &nbsp;&nbsp; <small style="font-weight: bold;"><span
+ style="font-family: monospace;">Adjust R,G &amp; B gain to get
+ target x,y. Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target B 60.00, x 0.3451, y 0.3516<br>
+ &nbsp; / Current B 60.05, x 0.3426, y 0.3506&nbsp; DE&nbsp;
+ 1.4&nbsp; R+&nbsp; G+&nbsp; B--</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ If you did not set a white point target, then the information shown
+ is a little different - it will show the initial white point value,
+ as well as the color temperature, and the CIEDE2000 of the white
+ point to either the Daylight or Black Body locus (depending on
+ whether the <span style="font-weight: bold;">-T</span> flag was
+ set). The constantly updated values show the same thing, and the
+ Red, Green and Blue control hints show the direction to adjust the
+ controls to place the white point on the locus. The control that
+ will have the most direct effect on the color temperature will be
+ the Blue, while the Green will most directly move the white point
+ towards or away from the locus, thereby reducing the delta E of the
+ white point to the locus (but there is interaction).<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">Adjust R,G &amp; B gain to desired white point.
+ Press space when done.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Initial B 47.25, x
+ 0.3417, y 0.3456, CDT 5113 DE&nbsp; 6.9</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">\ Current B 47.38, x 0.3420,
+ y 0.3460&nbsp; CDT 5104 DE&nbsp; 6.7&nbsp; R-- G+&nbsp; B-</span></small><br>
+ <br>
+ &nbsp;The brightness value is just there as a guide to what effect
+ the adjustment is having on the overall brightness. Usually the
+ white level brightness is adjusted using the next adjustment mode.
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The third mode lets you adjust the brightness of white on the
+ display. If you set a target brightness using the <span
+ style="font-weight: bold;"><span style="font-weight: bold;">-b</span></span>
+ parameter, it will show the target brightness value (in cd/m^2) on
+ one line, and then underneath it will show continuously updated
+ readings from the display. The left most character will switch from
+ '\' to '/' or back again each time a reading is updated. Underneath
+ the target value is displayed the current reading, and to the right
+ of this is a '+', '-' or '=' symbol, which gives a hint as to which
+ way to adjust the CRT contrast or LCD brightness control to improve
+ the match to the target.<br>
+ <br>
+ &nbsp;&nbsp; <small style="font-weight: bold;"><span
+ style="font-family: monospace;">Adjust CRT Contrast or LCD
+ Brightness to get target level. Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target 60.00<br>
+ &nbsp; / Current 59.96&nbsp; +</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ If you did not set a brightness target, it will show the initial
+ brightness as the target, and the current brightness, which you can
+ then set any way you want:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">Adjust CRT Contrast or LCD Brightness to desired
+ level. Press space when done.</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp; Initial 47.32</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">/ Current 47.54</span></small><br>
+ <br>
+ Once happy with the adjustment, press space to go back to the menu.<br>
+ <br>
+ <br>
+ The fourth mode lets you adjust the color of the black point of the
+ display, if the display has Red, Green and Blue channel offset
+ controls. It will show the target 1% brightness value (in cd/m^2) on
+ one line, together with the target chromaticity co-ordinates for the
+ black point, and then underneath it will show continuously updated
+ readings from the display. The left most character will switch from
+ '\' to '/' or back again each time a reading is updated. Underneath
+ the target brightness value is displayed the current reading, and
+ then the current chromaticity co-ordinate values. To the right of
+ this is the current delta E of the black point from the target, and
+ further to the right are hints '+', '-' or '='&nbsp; as to which
+ direction to adjust the individual Red, Green and Blue offset
+ settings to move the black point in the right direction. If the
+ symbol is doubled, then this channel will have the greatest effect.
+ <br>
+ <br>
+ <span style="font-family: monospace;"><span style="font-weight:
+ bold;">&nbsp; Adjust R,G &amp; B offsets to get target x,y.
+ Press space when done.<br>
+ &nbsp;&nbsp; &nbsp; Target B 0.60, x 0.3451, y 0.3516<br>
+ &nbsp; \ Current B 0.62, x 0.2782, y 0.2331&nbsp; DE&nbsp;
+ 10.3&nbsp; R+&nbsp; G++ B-</span></span><small
+ style="font-weight: bold;"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><br>
+ <br>
+ The 1%&nbsp; brightness value is just there as a guide to what
+ effect the adjustment is having on the 1% brightness level. The
+ combined channel offsets may have an effect on this in combination
+ with the CRT brightness control. Press space to go back to the menu.<br>
+ <br>
+ <br>
+ The fifth selection checks on the overall settings.&nbsp; If targets
+ have been set, it will be like:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Target Brightness = 50.00, Current = 47.44,
+ error = -5.1%<br>
+ &nbsp; Target 50% Level&nbsp; = 10.32, Current =&nbsp; 8.10,
+ error = -4.4%<br>
+ &nbsp; Target Near Black =&nbsp; 0.47, Current =&nbsp; 0.68,
+ error =&nbsp; 0.4%<br>
+ &nbsp; Target white = x 0.3458, y 0.3586, Current = x 0.3420, y
+ 0.3454, error =&nbsp; 7.55 DE<br>
+ &nbsp; Target black = x 0.3458, y 0.3586, Current = x 0.2908, y
+ 0.2270, error = 29.69 DE</span><span style="font-family:
+ monospace;"></span></small><br>
+ <br>
+ or if no targets are set:<br>
+ <br>
+ <small style="font-weight: bold;"><span style="font-family:
+ monospace;">&nbsp; Current Brightness = 46.28</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target 50%
+ Level&nbsp; = 10.07, Current =&nbsp; 7.52, error = -5.5%</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target Near Black
+ =&nbsp; 0.46, Current =&nbsp; 0.46, error = -0.0%</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Current white = x
+ 0.3439, y 0.3466, VCT 5098K DE&nbsp; 3.0</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; Target black = x
+ 0.3439, y 0.3466, Current = x 0.3093, y 0.2165, error = 30.30 DE</span></small><br>
+ <br>
+ and will then go back to the menu.<br>
+ <br>
+ The sixth selection <span style="font-weight: bold;">6)</span>
+ allows the reading of you ambient lighting conditions if your
+ instrument supports such a mode. Doing so will enable the <span
+ style="font-weight: bold;">-a</span> option to compensate for your
+ viewing conditions in the subsequent calibration. See <a
+ href="dispcal.html#a">-a</a>.<br>
+ <br>
+ Once&nbsp; you're happy with the display set-up, you can either
+ proceed on to the rest of the calibration by selecting <span
+ style="font-weight: bold;">7)</span>, or exit and re-start by
+ selecting <span style="font-weight: bold;">8)</span>. You might
+ want to re-start if you want to change the calibration targets.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h2>Other caveats:</h2>
+ NOTE that some <span style="font-weight: bold;">LCD</span> screens
+ behave a little strangely near their absolute white point, and may
+ therefore exhibit odd behavior at values just below white. It may be
+ advisable in such cases to set a brightness slightly less than the
+ maximum such a display is capable of.<br>
+ <br>
+ The program attempts to stop any screensaver or powersaver from
+ interfering with the measurements, but this may not be effective on
+ some systems, so it may be necessary to manually disable the
+ screensaver and/or powersaver before commencing the calibration with
+ a large number of patches.<br>
+ <br>
+ The calibration tables produced maintain the maximum level of
+ precision available on a system. If the display has VideoLUTs
+ available (Video Lookup Tables that the frame buffer values pass
+ through on their way to the display) and thier outputs are better
+ than 8 bits per component, then the resulting curves can reflect
+ this, although few current operating systems and/or display cards
+ actually support better than 8 bit per component output.<br>
+ <br>
+ If calibration curves are created for a display in which VideoLUTs
+ are not available, then the resulting calibration file will be
+ marked to indicate this, and a subsequent profile created with the
+ calibration will not have the calibration converted to the 'vcgt'
+ tag, since such a tag can't be loaded into the displays VideoLUTs.<br>
+ <br>
+ If communications break down with a USB connected instrument, you
+ may have to unplug it, and plug it in again to recover operation.<br>
+ <br>
+ Some systems (Apple OSX in particular) have a special set of user
+ interface controls ("Universal Access") that allows altering the
+ display in ways designed to assist visually impaired users, by
+ increasing contrast etc. This will interfere badly with any attempts
+ to calibrate or profile such a system, and must be turned off in
+ order to do so. Note that certain magic keyboard sequences can turn
+ this on by accident.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/dispprofloc.html b/doc/dispprofloc.html
new file mode 100644
index 0000000..b583914
--- /dev/null
+++ b/doc/dispprofloc.html
@@ -0,0 +1,313 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Display profile locations</title>
+ </head>
+ <body>
+ <h2>Where display profiles are stored, and how to load them
+ automatically.<br>
+ </h2>
+ <br>
+ Installing a display profile for your monitor is very operating
+ system
+ dependent, which is why <a href="dispwin.html#I">dispin -I</a> is a
+ good way of taking care of all these details. On some systems it is
+ not
+ the operating system itself that
+ supports display profiles, but individual applications, or helper
+ programs.<br>
+ <br>
+ Please choose from the detailed instructions below that suite your
+ system:<br>
+ <br>
+ <span style="font-weight: bold;"><a href="#MSW">Microsoft
+ Windows</a><br>
+ <a href="#OSX">Apple OS X</a><br>
+ <a href="#Linux">Linux/UNIX X11</a></span><br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><a name="MSW"></a>On <span
+ style="font-weight: bold;">Microsoft Windows</span>, display
+ profiles are typically in one of the
+ following directories:<br>
+ <p>&nbsp;&nbsp;&nbsp; MS Windows Me and 98: C:\Windows\System\Color<br>
+ </p>
+ <p>&nbsp;&nbsp;&nbsp; MS Windows NT:
+ C:\Winnt\system32\spool\drivers\color
+ </p>
+ <p>&nbsp;&nbsp;&nbsp; MS Window 2000, XP, Vista and 7:
+ C:\Windows\system32\spool\drivers\color</p>
+ <p>An alternative to using <span style="font-weight: bold;">dispwin
+ -I</span>
+ to install your display profiles,
+ is to use the Display
+ Property dialog, advanced settings, Color management tab, and
+ locate
+ the profile and install it there. This in
+ itself does not cause the profile to be made use of anywhere in
+ your
+ system.<br>
+ </p>
+ <p>If you are using Adobe Photoshop on your system, then you can
+ tell
+ it to use your monitor profile by editing the appropriate registry
+ key,
+ typically "My
+ Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Adobe\Color\Monitor\Monitor0",
+ to
+ contain the name of the display profile, and then restart
+ Photoshop
+ This is the simplest way of ensuring that the Adobe calibration
+ loader
+ tool Adobe Gamma loads the video hardware lookup tables from the
+ vcgt tag, and
+ uses the profile as its display profile.<br>
+ </p>
+ <p>The adobe gamma tool can be told to use your profile, but the
+ procedure is slightly tricky: Open adobe gamma from photoshop (in
+ the
+ Help-&gt;Color Management... menu item), select "Open Adobe
+ Gamma", and
+ select the "Load.." button. Select your profile and "Open". Select
+ "OK"
+ in the Adobe Gamma, it will then ask you to save it's modified
+ version
+ of your profile under a different name. Chose a name for the
+ modified
+ profile, and save it. Exit from Photoshop. Copy the profile you
+ want to
+ use, over the modified profile that you saved in Adobe Gamma. (If
+ you
+ don't do the last step, the profile Photoshop will be using will
+ have
+ been modified in strange ways from what you intended.)<br>
+ </p>
+ <p>Installing a profile on Microsoft Windows generally doesn't mean
+ that the profiles calibration will be automatically loaded into a
+ display on startup. A separated tool is usually needed to achiev
+ this.<br>
+ </p>
+ <p>Some Microsoft Windows applications may come with
+ "Gamma/VCGT/RAMDAC/Video LUT"
+ loader tools, consult their documentation and check your Start
+ Menu
+ Startup folders. If you don't want to use any of these 3rd party
+ tools, you can also use the <a
+ href="file:///D:/src/argyll/doc/dispwin.html">dispwin</a>
+ tool to do this for you, as it takes either a <a
+ href="file:///D:/src/argyll/doc/cal_format.html">.cal</a> or ICC
+ file
+ as an argument. The <a
+ href="http://freshmeat.net/projects/xcalib/">xcalib</a>
+ tool could also be used.<br>
+ </p>
+ <p>To add a startup item that will load a profiles calibration into
+ the
+ display using <span style="font-weight: bold;">dispwin</span>,
+ use the
+ following
+ instructions:<br>
+ </p>
+ <p style="margin-left: 40px;">On the task bar, right click and
+ select
+ "Properties", then select the "Advanced" tab, then click "Add..".
+ then
+ browse till you locate dispwin.exe. In the box containing the path
+ to
+ <span style="font-weight: bold;">dispwin.exe</span>, add a space
+ then
+ the option <span style="font-weight: bold;">-L</span>, eg:<br>
+ </p>
+ <p style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; <span
+ style="font-weight: bold;">c:\bin\argyll\dispwin -L</span></p>
+ <p style="margin-left: 40px;">If you don't want to use the default
+ installed profile, you could explicitly set the calibration file
+ to use
+ as an argument:</p>
+ <p style="margin-left: 40px;">&nbsp;&nbsp;&nbsp; <span
+ style="font-weight: bold;">c:\bin\argyll\dispwin
+ c:\myprofiles\mydisplay.icm<br>
+ </span></p>
+ <p style="margin-left: 40px;">Click "Next &gt;", select the
+ "Startup"
+ folder, then name the item (ie.
+ "Argyll Calibration Loader"), then press "Finish".<br>
+ <br>
+ You can test it out by simply navigating the "Start" menu to the
+ "Startup" folder and selecting the item you've just created. If
+ you
+ want to alter any of the details, navigate to the item again and
+ right
+ click it, and select "Properties". More than one startup item can
+ be
+ created to set the calibration for more than one display. You may
+ want
+ to cut and paste the "Target" line to a normal Command Prompt
+ shell to
+ check that it works as expected, as it is impossible to catch
+ error
+ messages in the startup.<br>
+ </p>
+ Microsoft Windows <span style="font-weight: bold;">XP</span> has an
+ optional <span style="font-weight: bold;">Microsoft&nbsp;Color&nbsp;Control&nbsp;Panel&nbsp;Applet&nbsp;for&nbsp;Windows&nbsp;XP</span>
+ available for
+ download from
+ Microsoft, which handles installation and registering of the a
+ display
+ profile, and will also automatically set the display calibration on
+ system startup. The applet is started from the control panel, and
+ first
+ you have to "Install..." the profile in the <span
+ style="font-weight: bold;">Profiles</span> tab, then associate it
+ with
+ the display in the <span style="font-weight: bold;">Devices</span>
+ tab, but <span style="font-weight: bold;">NOTE</span> that it seems
+ to
+ have a <span style="font-weight: bold;">bug</span>, in that it
+ sometimes associates the profiles with the <span
+ style="font-weight: bold;">wrong monitor</span> entry!<br>
+ <br>
+ On
+ Microsoft <span style="font-weight: bold;">Vista</span> you can set
+ the display profile in
+ Control&nbsp;Panel&nbsp;-&gt;&nbsp;Hardware&nbsp;and&nbsp;Sound
+ -&gt;&nbsp;Color&nbsp;Management, as an alternative to <span
+ style="font-weight: bold;">dispwin -I</span>.&nbsp;In&nbsp;Devices&nbsp;
+you&nbsp;select&nbsp;"Use&nbsp;my&nbsp;settings&nbsp;for&nbsp;this
+device",&nbsp;and&nbsp;then&nbsp;add&nbsp;the&nbsp;profile&nbsp;you've&nbsp;created.
+Unfortunately
+ though, it doesn't use the 'vcgt'
+ calibration curves on system startup, so a tool such as <span
+ style="font-weight: bold;">dispwin</span> will still have to be
+ used
+ to do this. Note that currently Vista also has a <span
+ style="font-weight: bold;">bug</span> that causes the calibration
+ curves to be reset whenever the User Account Dialog (and similar) is
+ displayed. This problem can only be worked around manually, by
+ re-running the startup item whenever this happens. Note that due to
+ the
+ details of this bug it is necessary to actually reset the
+ calibration
+ to something else before re-setting it. This can be done quite
+ conveniently in dispwin by adding the <span style="font-weight:
+ bold;">-c</span>
+ flag: e.g.: <span style="font-weight: bold;">c:\bin\argyll\dispwin
+ -c
+ -L</span><br>
+ <br>
+ On
+ Microsoft <span style="font-weight: bold;">Windows 7</span> you can
+ set
+ the display profile by opening the <span class="phrase">Color
+ Management control by clicking the <span class="ui">Start</span>
+ button and then clicking <span class="ui">Control Panel</span>.
+ In the search box, type <span class="userInput">color management</span>,
+ and then click <span class="ui">Color Management</span>.</span>
+ Make sure the correct display device is selected in "Device:", and
+ then tick the "Use my settings for this device" box. Select "Add..."
+ and then "Browse..." to locate and load the profile. (Alternately
+ you can use the normal file browser to locate the profile, and then
+ right click on it and select "Install Profile". In the Color Manager
+ "Add..." dialog you can then select it.). Make sure that the new
+ profile has been marked "(default)" if you want it to be
+ automatically used for your display.<br>
+ <br>
+ By default Windows 7 seems to automatically load the default display
+ profiles calibration on startup, but needs to be told to do this at
+ all other times by changing the system defaults, or if some 3rd
+ party tool to load display calibration has been installed. This can
+ be done by logging on with a user account that has administrative
+ privileges, then opening the <span class="phrase">Color Management
+ (see above), and then select the "</span><span class="ui">Advanced</span>"
+ tab, and then "<span class="ui">Change system defaults...", then
+ select the </span><span class="phrase">"</span><span class="ui">Advanced</span>"
+ tab, and select/un-select the "<span class="ui">Use <span
+ class="notLocalizable">Windows</span> display calibration</span>"
+ check box. (You could use <span style="font-weight: bold;">dispwin
+ -I</span> as an alternative to this if you really wanted.)<br>
+ <br>
+ &nbsp;<br>
+ <hr style="width: 100%; height: 2px;"><a name="OSX"></a>On <span
+ style="font-weight: bold;">Apple OSX</span>, the display
+ profile are in one of the following
+ locations:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; /Network/Library/ColorSync/Profiles<br>
+ &nbsp;&nbsp;&nbsp; /System/Library/Colorsync/Profiles<br>
+ &nbsp;&nbsp;&nbsp; /Library/ColorSync/Profiles<br>
+ &nbsp;&nbsp;&nbsp; ~/Library/ColorSync/Profiles<br>
+ <br>
+ Note though that&nbsp; /System/Library/Colorsync/Profiles is only
+ for
+ profiles supplied by Apple. You can use <a href="dispwin.html#S">dispwin
+ -S</a>&nbsp; to select the appropriate scope when installing a
+ profile
+ using <a href="dispwin.html#I">dispwin -I</a>. You can use the
+ "System
+ Preferences-&gt;Displays-&gt;Color" tool to check that the profile
+ has been installed correctly. Note that the contents of
+ the description tag (the argument to the <span style="font-weight:
+ bold;"><span style="font-weight: bold;">-D</span></span>
+ flag used with the <span style="font-weight: bold;">colprof</span>
+ tool) will be used to identify the profile.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><a name="Linux"></a>On <span
+ style="font-weight: bold;">Linux</span> and other <span
+ style="font-weight: bold;">Unix</span> style systems, there is no
+ universally agreed location for ICC profiles yet,
+ although the following locations have been suggested at various
+ times:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; /usr/share/color/icc<br>
+ &nbsp;&nbsp;&nbsp; /usr/local/share/color/icc<br>
+ &nbsp;&nbsp;&nbsp; ~/.color/icc<br>
+ <br>
+ although particular applications may use their own locations, such
+ as:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; /usr/local/share/Scribus/profiles<br>
+ <br>
+ Argyll <a href="dispwin.html">dispwin</a> follows uses the <a
+ href="ucmm.html">ucmm</a> scheme for storing user and system
+ display
+ profiles, and when a display is set to use a profile correctly, it
+ will
+ follow <a
+ href="http://www.burtonini.com/computing/x-icc-profiles-spec-0.2.html">this
+ convention</a> to make it available to applications.<br>
+ &nbsp;&nbsp; <br>
+ If you want the display calibration to be loaded, you should
+ consider
+ installing a tool to do so at startup, such as <a
+ href="file:///D:/src/argyll/doc/dispwin.html">dispwin</a>
+ or <a href="http://freshmeat.net/projects/xcalib/">xcalib</a>.<br>
+ <br>
+ Using <a href="dispwin.html">dispwin</a> the currently installed
+ profile for a particular display can be loaded using the <a
+ href="dispwin.html#L">-L</a> option of <a href="dispwin.html">dispwin:</a><br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">dispwin -L</span><span
+ style="font-style: italic;"><span style="font-weight: bold;"></span><br>
+ <br>
+ </span>which will both upload the installed profile <span
+ style="font-style: italic;"></span>into the <span
+ style="font-weight: bold;"></span>root
+ window _ICC_PROFILE property, and also load it into the display
+ VideoLUTs. <br>
+ <br>
+ You can use the <span style="font-weight: bold;">dispwin</span> <a
+ href="file:///D:/src/argyll/doc/dispwin.html#d">-d</a> parameter
+ in
+ the usual way to select other
+ displays to store or load the calibration using the _ICC_PROFILE
+ property.<br>
+ <br>
+ To do this when you start your X11 server, you could put the above
+ command in your <span style="font-weight: bold;">.xinitrc</span>
+ file
+ in your home directory for each screen.<br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/dispread.html b/doc/dispread.html
new file mode 100644
index 0000000..e1ce861
--- /dev/null
+++ b/doc/dispread.html
@@ -0,0 +1,926 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispread</b>&nbsp;</h2>
+ <h3>Summary</h3>
+ Display test patches on a monitor, read the colorimetric value
+ result with the colorimeter, and create the chart readings file. The
+ type of instrument is determined by the communication port selected.
+ Emission and display measurement instruments are supported.<br>
+ <br>
+ If you want to read a display manually rather than automatically,
+ see <a href="chartread.html">chartread</a> and the <a
+ href="chartread.html#d">-d</a> option.<br>
+ <h3>Usage</h3>
+ <small style="font-family: monospace;">dispread [-options]<i>
+ inoutfile</i><br>
+ &nbsp;<a href="#v">-v</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Verbose mode<br>
+ &nbsp;</small><font size="-1"><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [X11 only] Choose X11 display
+ name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [X11 only]Choose the display from the following list (default
+ 1),<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+and
+optionally
+choose
+a
+different
+display
+m
+
+
+
+
+
+
+
+
+
+
+
+
+
+ for VideoLUT access.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Choose
+the
+display
+from
+the
+following
+list
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (default 1)</span></font><small style="font-family: monospace;"><br>
+ </small><span style="font-family: monospace;">&nbsp;<a href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display via a web server at port (default 8080)</span><br>
+ <small style="font-family: monospace;"> <span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#c">-c listno</a><span style="font-family: monospace;">
+ &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set
+ communication port from the following list (default 1)<br>
+ </span></small><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#p">-p</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use telephoto mode (ie. for a projector) (if available)</span></font><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#y">-y X</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Display
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ type - instrument specific list to choose from.</span></font><br>
+ <small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;">-</span><a href="#k">k
+ file.cal</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Load calibration file into display while reading<br>
+ </small><small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;">-</span><a href="#K">K
+ file.cal</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Apply
+
+
+
+
+
+
+
+
+
+
+
+
+
+ calibration file to test values while reading</small><br>
+ <small style="font-family: monospace;">&nbsp;<a href="#s">-s</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Save spectral information (default don't
+ save)<br>
+ </small><font style="font-family: monospace;" size="-1">&nbsp;<a
+ href="#P">-P ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position
+ test window and scale it<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ho,vi:
+0.0
+=
+left/top,
+0.5
+=
+center,
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.0 = right/bottom etc.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ss:
+0.5
+=
+half,
+1.0
+=
+normal,
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0 = double etc.<br>
+ </font><font size="-1"><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+ ss,vs: = optional horizontal, vertical scale.</span></font><br>
+ <font style="font-family: monospace;" size="-1"> &nbsp;</font><font
+ size="-1"><span style="font-family: monospace;"><a href="#F">-F</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Fill whole screen with black background</span></font><br
+ style="font-family: monospace;">
+ <small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;"></span><a href="#n">-n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;
+[X11
+only]
+Don't
+set
+override
+redirect
+
+
+
+
+
+
+
+
+
+
+
+
+
+ on test window<br>
+ </small><small style="font-family: monospace;">&nbsp;<a href="#J">-J</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Run calibration first</small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Disable initial calibration of instrument if possible<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#H">-H</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode (if
+ available)</span></font><font size="-1"><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ &nbsp;<a href="#w">-w</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Disable
+normalisation
+of
+white
+to
+Y
+=
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 100</span></font><small><span style="font-family: monospace;"></span></small><br>
+ &nbsp; <font size="-1"><span style="font-family: monospace;"><a
+ href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Apply Colorimeter Correction Matrix</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
+ file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+Colorimeter
+Calibration
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Spectral Samples for calibration</span><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#Q">-Q <i>observ</i></a><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp; Choose CIE Observer for spectrometer or CCSS
+ colorimeter data:</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1931_2 </span></small><small><span
+ style="font-family: monospace;">(def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2, 1964_10c</span></small><br>
+ <small><span style="font-family: monospace;">&nbsp;<a
+ href="dispread.html#I">-I b|w</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Drift
+compensation,
+Black:
+-Ib,
+White:
+-Iw,
+Both:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -Ibw<br>
+ </span></small><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style=" font-family: monospace;"
+ href="#YA">-<font size="-1">Y</font> A</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+ Use non-adaptive integration time mode (if available).</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#C">-C "command"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is set<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#M">-M "command"</a><span style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Invoke shell
+ "command" each time a color is measured</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+serial
+port
+flow
+control:
+n
+=
+
+
+
+
+
+
+
+
+
+
+
+
+
+ none, h = HW, x = Xon/Xoff</span></font><br>
+ <small style="font-family: monospace;">&nbsp;<a href="#D">-D [level]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Print debug
+ diagnostics to stderr</small><br>
+ <small style="font-family: monospace;">&nbsp;<a href="#p1"><i>inoutfile</i></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Base name for input[<a href="File_Formats.html#.ti1">.ti1</a>]/output[<a
+ href="File_Formats.html#.ti3">.ti3</a>] file.<br>
+ </small> <br>
+ <b>Examples</b><br>
+ <br>
+ dispread -c1 -i92 mycrt<br>
+ <h3>Comments<br>
+ </h3>
+ This is the tool for exercising a display, in order to measure its
+ color characteristics. The device test colors are defined by the
+ outfile.ti1 file, while the resulting device+colorimetric and
+ optional spectral readings are stored in the outfile.ti3 file.
+ Display calibration curves can be applied during the measurements,
+ and the curves included in the resulting .ti3 data file using the <span
+ style="font-weight: bold;">-k</span>flag. See <a
+ href="dispcal.html">dispcal</a> for information on how&nbsp; to
+ calibrate the display before profiling it. For best results, you
+ should run this against a neutral grey desktop background, and avoid
+ having any bright images or windows on the screen at the time you
+ run it.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag reports progress information.<br>
+ <br>
+ <a name="display"></a><span style="font-weight: bold;">-display</span>:
+ When running on a UNIX based system that used the X11 Windowing
+ System, <b>dispread</b> will by default use the $DISPLAY
+ environment variable to determine which display and screen to read
+ from. This can be overridden by supplying an X11 display name to the
+ <span style="font-weight: bold;">-display</span> option. Note that
+ if Xinerama is active, you can't select the screen using $DISPLAY or
+ -display, you have to select it using the <span style="font-weight:
+ bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a> <span style="font-weight: bold;">-d</span>: By
+ default the main display will be the location of the test window. If
+ the system has more than one display or screen, an alternate
+ display/screen can be selected with the <span style="font-weight:
+ bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispread</span> so as to display the
+ usage information (i.e. "dispread -?" or "dispread --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed, if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or <span
+ style="font-weight: bold;">-display</span> parameter.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
+ <a name="dnm"></a>Because of the difficulty cause by TwinView and
+ MergedFB in X11 based systems, you can optionally specify a separate
+ display number after the display that is going to be used to present
+ test patches, for accessing the VideoLUT hardware. This must be
+ specified as a single string, e.g. <span style="font-weight: bold;">-d
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1,2</span> . Some experimentation may be needed using <a
+ href="dispwin.html">dispwin</a> on such systems, to discover what
+ screen has access to the VideoLUT hardware, and which screens the
+ test patches appear on. You may be able to calibrate one screen, and
+ then share the calibration with another screen. Profiling can be
+ done independently to calibration.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:port</span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way.
+ <b> JavaScript</b> needs to be enabled in your web browser for this
+ to work.<br>
+ <br>
+ Note that if you use this method of displaying test patches, that
+ there is no access to the display VideoLUTs and that the colors will
+ be displayed with 8 bit per component precision, and any
+ screen-saver or power-saver will not be disabled. You will also be
+ at the mercy of any color management applied by the web browser, and
+ may have to carefully review and configure such color management.
+ See the <a href="dispcal.html#o">-o</a> flag for an explanation of
+ the implications of having no access to the VideoLUTs.<br>
+ <br>
+ <a name="c"></a> <span style="font-weight: bold;">-c</span>: The
+ instrument is assumed to communicate through a USB or serial
+ communication port, and the port can be selected with the <b>-c</b>
+ option, if the instrument is not connected to the first port. If you
+ invoke <span style="font-weight: bold;">dispread</span> so as to
+ display the usage information (i.e. "dispread -?" or "dispread --"),
+ then the discovered USB and serial ports will be listed. On
+ UNIX/Linux, a list of all possible serial ports are shown, but not
+ all of them may actually be present on your system.<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ allows measuring in telephoto mode, using instruments that support
+ this mode, e.g. the ColorMunki. Telephoto mode is one for taking
+ emissive measurements from a distance (ie. telespectometer,
+ tele-colorimeter) mode, and typically would be used for measuring
+ projector type displays. If a device does not support a specific
+ telephoto mode, then the normal emissive mode may be suitable for
+ measuring projectors.<br>
+ <br>
+ <a name="y"></a>The <span style="font-weight: bold;">-y</span> flag
+ allows setting the Display Type. The selection typically determines
+ two aspects of of the instrument operation: <span
+ style="font-weight: bold;">1)</span> It may set the measuring mode
+ to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument calibration matrix suitable for a particular display
+ type. The selections available depends on the type and model of
+ instrument, and a list of the options for the discovered instruments
+ will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. <b>3)</b> Any installed CCSS files
+ (if applicable), or CCMX files. These files are typically created
+ using <a href="file:///D:/src/argyll/doc/ccxxmake.html">ccxxmake</a>,
+ and installed using <a
+ href="file:///D:/src/argyll/doc/oeminst.html">oeminst</a>. The
+ default and Base Calibration types will be indicated in the usage.<br>
+ <br>
+ <a name="s"></a><span style="font-weight: bold;">-s</span>: By
+ default only the colorimetric information (XYZ value) will be saved,
+ but for instruments that support spectral readings (such as the
+ Gretag Spectrolino), the <b>-s</b> option will save the spectral
+ readings to the .ti3 file as well.<br>
+ <br>
+ <a name="k"></a> <span style="font-weight: bold;">-k: </span>If a
+ display video lookup table calibration <a
+ href="File_Formats.html#.cal">.cal</a> file is provided, it will
+ be loaded into the display <span style="font-weight: bold;">ViedoLUTs</span>
+ while the measurements are being taken, thereby being applied to the
+ measurement values, and the calibration will also included in the
+ resulting .ti3 data file, so that <a href="colprof.html">colprof</a>
+ can include it as a <span style="font-weight: bold;">vcgt</span>
+ tag in the resulting profile. This is the <span style="font-weight:
+ bold;">normal</span> way to profile a calibrated display. The
+ calibration file has usually been created using <a
+ href="dispcal.html">dispcal</a>. If a calibration file is not
+ created, then the display will be read in whatever calibration state
+ it is in. If the calibration file indicates that the displays
+ VideoLUTs are not accessible, or if they prove not to be accessible,
+ then dispread will switch to <span style="font-weight: bold;">-K</span>
+ mode (see below). <span style="font-weight: bold;">NOTE</span> that
+ the calibration is loaded into the display hardware just before the
+ instrument starts measurement, after the test window first appears.<br>
+ <br>
+ <a name="K"></a> <span style="font-weight: bold;">-K: </span>If a
+ display video lookup table calibration <a
+ href="File_Formats.html#.cal">.cal</a> file is provided, it will
+ be applied to the test values for each measurement, and also
+ included in the resulting .ti3 data file, so that <a
+ href="colprof.html">colprof</a> can include it as a <span
+ style="font-weight: bold;">vcgt</span> tag in the resulting
+ profile. This is <span style="font-weight: bold;">NOT</span>
+ normally the best way to profile a calibrated display, since the
+ frame buffer may have lower precision than the VideoLUTs output
+ values.<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ <a name="n"></a><span style="font-weight: bold;">-n</span>: When
+ running on a UNIX based system that used the X11 Windowing System, <b>dispread</b>
+ normally selects the override redirect so that the test window will
+ appear above any other windows on the display. On some systems this
+ can interfere with window manager operation, and the <b>-n</b>
+ option turns this behaviour off.<br>
+ <br>
+ <a name="J"></a> The -<span style="font-weight: bold;">J</span>
+ option runs through the black and sensor relative calibration
+ routines for the Xrite DTP92 and DTP94 instrument, the black level
+ calibration for the Eye-One Display 1, and a CRT frequency
+ calibration for the Eye-One Display 2. For the black calibration the
+ instrument should be placed on an opaque, black surface, and any
+ stray light should be avoided by placing something opaque over the
+ instrument. If a Spectrolino is being used, then a white and black
+ calibration will always be performed before the instrument can be
+ placed on the display, unless the <a href="#N">-N</a> flag is used.
+ Generally it is not necessary to do a calibration every time an
+ instrument is used, just now and again. There is no point in
+ doing&nbsp; a CRT frequency calibration, as this will be done
+ automatically at the commencement of patch reading.<br>
+ <br>
+ <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it. See <a href="instruments.html">Operation of particular
+ instruments</a> for more details. This may give better accuracy
+ for display measurements.<br>
+ <br>
+ <a name="w"></a>The <b>-w</b> flag disables the normalisation of
+ the white patch value to 100.0, resulting in values that are in
+ cd/m^2. This is mainly for diagnostic purposes.<br>
+ <br>
+ <a name="X1"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccmx</span></span> option reads
+ a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
+ from the given file, and applies it to the colorimeter instruments
+ readings. This can improve a colorimeters accuracy for a particular
+ type of display. A list of contributed <span style="font-weight:
+ bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
+ <br>
+ <a name="X2"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccss</span></span> option reads
+ a <a href="File_Formats.html#.ccss">Colorimeter Calibration
+ Spectral Sample</a> from the given file, and uses it to set the
+ colorimeter instruments calibration. This will only work with
+ colorimeters that rely on sensor spectral sensitivity calibration
+ information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
+ or the DataColor <span style="font-weight: bold;">Spyder4</span>).This
+can
+improve
+a
+
+
+
+
+
+
+
+
+
+
+
+
+
+ colorimeters accuracy for a particular type of display.<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values from spectral readings or using a colorimeter
+ that has CCSS capability. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ &nbsp; <b>1964_10c</b> selects a version of the CIE 1964 10 degree
+ observer that has been adjusted using a 3x3 matrix to better agree
+ with the 1931 2 degree observer.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you select
+ anything other than the default 1931 2 degree observer, that the Y
+ values will not be cd/m^2, due to the Y curve not being the CIE 1924
+ photopic V(&#955;) luminosity function.<br>
+ <br>
+ <a name="I"></a> The -<span style="font-weight: bold;">I <span
+ style="font-style: italic;">b|w</span></span> options invoke
+ instrument black level, and display white level compensation
+ (respectively). Instrument black level drift compensation attempts
+ to combat instrument black calibration drift by using a display
+ black test patch as a reference. If an instrument is not
+ acclimatised sufficiently to the measurement conditions, changes in
+ temperature can affect the black readings. Display white level drift
+ compensation attempts to combat changes in display brightness as it
+ warms up by measuring a white patch every so often, and using it to
+ normalise all the other readings. If just instrument black drift
+ compensation is needed, use <span style="font-weight: bold;">-Ib</span>.
+ If just display white level compensation is needed, use <span
+ style="font-weight: bold;">-Iw</span>. If both are needed, use <span
+ style="font-weight: bold;">-Ibw</span> or <span
+ style="font-weight: bold;">-Iwb</span>.<span style="font-weight:
+ bold;"> <br>
+ <br>
+ </span><a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
+ option uses a non-adaptive integration time emission measurement
+ mode, if the instrument supports it, such as the Eye-One Pro or
+ ColorMunki. By default an adaptive integration time measurement mode
+ will be used for emission measurements, but some instruments support
+ a fixed integration time mode that can be used with display devices.
+ This may give increased consistency and faster measurement times,
+ but may also give less accurate low level readings.<br>
+ <span style="font-weight: bold;"> <br>
+ </span><a name="C"></a> The -<span style="font-weight: bold;">C</span>
+ <span style="font-weight: bold;">"command" </span>option allows a
+ method of relaying each test value to some other display than that
+ on the system running dispread (for instance, a photo frame, PDA
+ screen etc.), by causing the given command to be invoked to the
+ shell, with six arguments. The first three arguments are the RGB
+ test color as integers in the range 0 to 255, the second three
+ parameters are the RGB test color as floating point numbers in the
+ range 0.0 to 1.0. The script or tool should relay the given color to
+ the screen in some manner (e.g. by generating a raster file of the
+ given color and sending it to the display being profiled), before
+ returning. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="M"></a> The -<span style="font-weight: bold;">M</span> <span
+ style="font-weight: bold;">"command" </span>option allows a
+ method of gathering each test value from some external source, such
+ as an instrument that is not directly supported by Argyll. The given
+ command is involked to the shell, with six arguments. The first
+ three arguments are the RGB test color as integers in the range 0 to
+ 255, the second three parameters are the RGB test color as floating
+ point numbers in the range 0.0 to 1.0. The script or tool should
+ create a file called <span style="font-weight: bold;">"command.meas</span>"
+ that contains the XYZ values for the given RGB (or measured from the
+ test window) in cd/m^2 as three numbers separated by spaces, before
+ returning. If the command returns a non-zero return value, dispread
+ will abort. Note that a test window will also be created on the
+ system running dispread.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="p1"></a> The final parameter on the command line is the
+ base filename for the <a href="File_Formats.html#.ti1">.ti1</a>
+ input file, and the <a href="File_Formats.html#.ti3">.ti3</a>
+ output file. <b>dispread</b> will add the .ti1 and .ti3 extensions
+ automatically.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ If a large number of patches is being read, the screensaver on many
+ systems can interfere with the operation of dispread. It is
+ therefore advisable in these cases to manually turn off the
+ screensaver before commencing the measurements.<br>
+ <br>
+ If communications break down with a USB connected instrument, you
+ may have to unplug it, and plug it in again to recover.<br>
+ <br>
+ Some systems (Apple OSX in particular) have a special set of user
+ interface controls ("Universal Access") that allows altering the
+ display in ways designed to assist visually impaired users, by
+ increasing contrast etc. This will interfere badly with any attempts
+ to calibrate or profile such a system, and must be turned off in
+ order to do so. Note that certain magic keyboard sequences can turn
+ this on by accident.<br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/dispwin.html b/doc/dispwin.html
new file mode 100644
index 0000000..a07d50f
--- /dev/null
+++ b/doc/dispwin.html
@@ -0,0 +1,593 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>dispwin</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/dispwin</b></h2>
+ <h3>Summary</h3>
+ This tool has several different but related functions. When given as
+ a file argument an ICC profile containing vcgt "gamma" curves, or an
+ Argyll video calibration .cal file, it will load that calibration
+ into the chosen display. It can also install or uninstall a profile
+ in the system for the chosen display, or set the display calibration
+ to that in the currently installed system profile. By default it
+ displays a test window the same as that used by dispcal and
+ dispread, to test this functionality. It can also be used to test
+ the ability to load video card LUT curves to each display, and to
+ test how the console Bell will sound when used with some instruments
+ (ie. Eye-One Pro).<br>
+ <br>
+ [Note that in OS X 10.7 Lion, changes to the default system profile
+ permissions mean that you can't set a calibration persistently when
+ the default system profile is being used, unless you run as root
+ (ie. use sudo). Note that you do <span style="font-weight: bold;">not</span>
+ need to run as root to install a user profile (-Su, the default
+ install type.)]<br>
+ <h3>Usage</h3>
+ <font size="-1"><span style="font-family: monospace;">dispwin
+ [options] [<span style="font-style: italic;">calfile</span>]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose
+
+
+
+
+
+
+
+ mode<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#display">-display displayname</a><span
+ style="font-family: monospace;"> [<span style="font-weight:
+ bold;">X11 only</span>] Choose X11 display name<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#dnm">-d n[,m]</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ [<span style="font-weight: bold;">X11 only</span>] Choose the
+ display from the following list (default 1),<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+and
+optionally
+
+
+
+
+
+
+
+ choose a different display m for Video LUT access.<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#d">-d n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+[Not
+X11]
+
+
+
+
+
+
+
+ Choose the display from the following list (default 1)<br>
+ </span></font><span style="font-family: monospace;">&nbsp;<a
+ href="#dweb">-dweb[:port]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+ Display via a web server at port (default 8080)</span><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;<a href="#P">-P
+ ho,vo,ss[,vs]</a>&nbsp;&nbsp;&nbsp;&nbsp; Position test window
+ and scale it</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ho,vi:
+0.0
+
+
+
+
+
+
+
+ = left/top, 0.5 = center, 1.0 = right/bottom etc.</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ss:
+0.5
+
+
+
+
+
+
+
+ = half, 1.0 = normal, 2.0 = double etc.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+ ss,vs: = optional horizontal, vertical scale.<br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><a href="#F">-F</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Fill
+whole
+
+
+
+
+
+
+
+ screen with black background</span></font><br
+ style="font-family: monospace;">
+ <font size="-1"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#i">-i</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Run forever with random values<br>
+ &nbsp;<a href="#G">-G <span style="font-style: italic;">filename</span></a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Display RGB
+ colors from CGATS file<br>
+ &nbsp;</span></font><font size="-1"><a style="font-family:
+ monospace;" href="#m">-m</a><span style="font-family:
+ monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Manually step through colors</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#r">-r</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test
+just
+
+
+
+
+
+
+
+ video LUT loading &amp; Beeps<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#n">-n</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Test
+native
+
+
+
+
+
+
+
+ display values (rather than through Video LUT)<br>
+ &nbsp;<a href="#s">-s <span style="font-style: italic;">filename.cal</span></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Save
+the
+
+
+
+
+
+
+
+ currently loaded Video LUT to 'filename'<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#c">-c</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Load
+a
+
+
+
+
+
+
+
+ linear display calibration (clear calibration)</span></font><font
+ size="-1"><span style="font-family: monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#V">-V</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verify
+that
+
+
+
+
+
+
+
+ calfile/profile cal. is currently loaded in LUT<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#I">-I</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Install profile for display and use it's calibration<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#U">-U</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Un-install profile for display<br>
+ &nbsp;<a href="#S">-S d</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Specify
+the
+
+
+
+
+
+
+
+ install/uninstall scope for OS X [nlu] or Vista [lu]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+d
+is
+
+
+
+
+
+
+
+ one of: n = network, l = local system, u = user (default)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;">&nbsp;<a href="#L">-L</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">Load installed profiles cal. into Video LUT<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#E">-E</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+ [<span style="font-weight: bold;">X11 only</span>] Run in daemon
+ loader mode for given X11 server <br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;</span><a style="font-family: monospace;"
+ href="#D">-D [level]</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Print
+debug
+
+
+
+
+
+
+
+ diagnostics to stderr</span></font><font size="-1"><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"><br>
+ &nbsp;</span></font><a style="font-family: monospace;"
+ href="#p1"><font size="-1"><span style="font-family: monospace;"></span></font></a><font
+ size="-1"><a style="font-family: monospace;" href="#p1"><i>calfile</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Load
+display
+
+
+
+
+
+
+
+ calibration (<a href="cal_format.html">.cal</a> or .icm) into
+ LUT, and exit.</span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></font><br>
+ <br>
+ <h3>Comments<br>
+ </h3>
+ <a name="v"></a> The <b>-v</b> flag makes the program more
+ verbose..<br>
+ <br>
+ <a name="display"></a><span style="font-weight: bold;">display</span>:
+ When running on a UNIX based system that used the X11 Windowing
+ System, <b>dispwin</b> will by default use the $DISPLAY environment
+ variable to determine which display and screen to read from. This
+ can be overridden by supplying an X11 display name to the <span
+ style="font-weight: bold;">-display</span> option. Note that if
+ Xinerama is active, you can't select the screen using $DISPLAY or
+ -display, you have to select it using the <span style="font-weight:
+ bold;">-d</span> parameter.<br>
+ <br>
+ <a name="d"></a><span style="font-weight: bold;">-d</span>: By
+ default the location of the test window will be the main display. If
+ the system has more than one display or screen, an alternate
+ display/screen can be selected with the <span style="font-weight:
+ bold;">-d</span> parameter. If you invoke <span
+ style="font-weight: bold;">dispwin</span> so as to display the
+ usage information (i.e. "dispcal -?" or "dispcal --"), then the
+ discovered displays/screens will be listed. Multiple displays may
+ not be listed if they appear as a single display to the operating
+ system (ie. the multi-display support is hidden in the video card
+ driver). On UNIX based system that used the X11 Windowing System,
+ the <span style="font-weight: bold;">-d</span> parameter will
+ override the screen specified by the $DISPLAY or <span
+ style="font-weight: bold;">-display</span> parameter.<br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;">Note</span> that if VideoLUTs for a
+ display are not accessible (i.e. no hardware calibration
+ capability), <span style="font-weight: bold;">dispwin</span> will
+ will issue a warning or fail when it attempts to access them.<br>
+ <br>
+ On X11 the inability to access VideoLUTs could be because you are
+ trying to access a remote display, and the remote display doesn't
+ support the XF86VidMode extension, or perhaps you are running
+ multiple monitors using NVidia TwinView, or MergedFB, and trying to
+ access anything other than the primary monitor. TwinView and
+ MergedFB don't properly support the XF86VidMode extension for
+ multiple displays. You can use <a href="dispwin.html#r">dispwin -r</a>
+ to test whether the VideoLUTs are accessible for a particular
+ display. See also below, on how to select a different display for
+ VideoLUT access. Also note that dispcal will fail if the Visual
+ depth doesn't match the VideoLUT depth. Typically the VideoLUTs have
+ 256 entries per color component, so the Visual generally needs to be
+ 24 bits, 8 bits per color component.<br>
+ <br>
+ <a name="dnm"></a><span style="font-weight: bold;">-d n[,m]</span>Because
+of
+the
+
+
+
+
+
+
+
+ difficulty cause by TwinView and MergedFB in X11 based systems, you
+ can optionally specify a separate display number after the display
+ that is going to be used to present test patches, for accessing the
+ VideoLUT hardware. This must be specified as a single string, e.g. <span
+ style="font-weight: bold;">-d 1,2</span> . Some experimentation
+ may be needed on such systems, to discover what screen has access to
+ the VideoLUT hardware, and which screens the test patches appear on.
+ You may be able to calibrate one screen, and then share the
+ calibration with another screen. Profiling can be done independently
+ to calibration.<br>
+ <br>
+ <a name="dweb"></a><span style="font-weight: bold;">-dweb</span> or
+ <span style="font-weight: bold;">-dweb:port</span> starts a
+ standalone web server on your machine, which then allows a local or
+ remote web browser to display the the color test patches. By default
+ port <span style="font-weight: bold;">8080</span> is used, but this
+ can be overridden by appending a <span style="font-weight: bold;">:</span>
+ and the port number i.e. <span style="font-weight: bold;">-dweb:8001</span>.
+ The URL will be <span style="font-weight: bold;">http://</span>
+ then name of the machine or its I.P. address followed by a colon and
+ the port number - e.g something like <span style="font-weight:
+ bold;">http://192.168.0.1:8080</span>. If you use the verbose
+ option (<span style="font-weight: bold;">-v</span>) then a likely
+ URL will be printed once the server is started, or you could run <span
+ style="font-weight: bold;">ipconfig</span> (MSWin) or <span
+ style="font-weight: bold;">/sbin/ifconfig</span> (Linux or OS X)
+ and identify an internet address for your machine that way. <b>JavaScript</b>
+ needs to be enabled in your web browser for this to work.<br>
+ <br>
+ Note that if you use this method of accessing a display, that there
+ is no access to the display Video Lookup tables, and that any
+ operation that depends on accessing the VideoLUTs will either
+ generate a warning or fail.<br>
+ <br>
+ <a name="P"></a> The <span style="font-weight: bold;">-P</span>
+ parameter allows you to position and size the test patch window. By
+ default it is places in the center of the screen, and sized
+ appropriately for the type of instrument. The <span
+ style="font-weight: bold;">ho</span> and <span
+ style="font-weight: bold;">vo</span> values govern the horizontal
+ and vertical offset respectively. A value of 0.0 positions the
+ window to the far left or top of the screen, a value of 0.5
+ positions it in the center of the screen (the default), and 1.0
+ positions it to the far right or bottom of the screen. If three
+ parameters are provided, then the <span style="font-weight: bold;">ss</span>
+ parameter is a scale factor for the test window size. A value of 0.5
+ for instance, would produce a half sized window. A value of 2.0 will
+ produce a double size window. If four parameters are provided, then
+ the last two set independent horizontal and vertical scaling
+ factors. Note that the ho,vo,ss or ho,vo,hs,vs numbers must be
+ specified as a single string (no space between the numbers and the
+ comma). For example, to create a double sized test window at the top
+ right of the screen, use <span style="font-weight: bold;">-P 1,0,2</span>
+ . To create a window twice as wide as high: <span
+ style="font-weight: bold;">-P 1,0,2,1</span>.<br>
+ <br>
+ <a name="F"></a> The <span style="font-weight: bold;">-F</span>
+ flag causes the while screen behind the test window to be masked
+ with black. This can aid black accuracy when measuring CRT displays
+ or projectors.<br>
+ <br>
+ By default <span style="font-weight: bold;">dispwin</span> will put
+ a test window on the selected display, and display some test colors,
+ before darkening&nbsp; then brightening the screen by loading video
+ LUT values, test the bell sounds, then restore the original values
+ and exit.<br>
+ <br>
+ If the&nbsp;<a name="i"></a><span style="font-weight: bold;">-i</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the preset sequence, then random test colors forever.<br>
+ <br>
+ If the&nbsp;<a name="G"></a><span style="font-weight: bold;">-G</span>
+ parameter is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the sequence of RGB color in the supplied CGATS file,
+ e.g. a .ti1 file. Typically this might the used with the <span
+ style="font-weight: bold;">-m</span> option to manually measure a
+ set of test patches.<br>
+ <br>
+ If the&nbsp;<a name="m"></a><span style="font-weight: bold;">-m</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the preset sequence then exits, but advances manually
+ after each return key.<br>
+ <br>
+ If the&nbsp;<a name="r"></a><span style="font-weight: bold;">-r</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will test just the loading of video LUT values by first darkening,
+ then lightening the screen, before exiting.<br>
+ <br>
+ If the&nbsp;<a name="n"></a><span style="font-weight: bold;">-n</span>
+ flag is set, then <span style="font-weight: bold;">dispwin</span>
+ will display the colors directly on the display, rather than having
+ the color values translated through the currently loaded Video LUTs.<br>
+ <br>
+ <a name="s"></a> If a <span style="font-weight: bold;">-s <span
+ style="font-style: italic;">filename.cal</span></span> option is
+ used, then rather than displaying a test window, <span
+ style="font-weight: bold;">dispwin</span> will save the currently
+ loaded calibration curves to the given calibration file. Note that
+ other functions such as clearing or loading a calibration can be
+ performed after this action.<br>
+ <br>
+ <a name="c"></a> If a <span style="font-weight: bold;">-c</span>
+ flag is used, then rather than displaying a test window, <span
+ style="font-weight: bold;">dispwin</span> will load the selected
+ display with a linear set of Video LUT curves, effectively clearing
+ the calibration, and will then exit. Note that other functions such
+ as loading a calibration can be performed after this action.<span
+ style="font-style: italic;"></span><br>
+ <br>
+ <a name="V"></a> If a <span style="font-weight: bold;">-V</span>
+ flag is used, then rather than loading the calibration specified as
+ the final argument, the currently loaded calibration will be
+ verified as being the same as the given calibration file. If this is
+ combined with the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-L</span></span> flag, the currently
+ loaded calibration will be verified as being the same as the
+ installed system profile for the display.<br>
+ <br>
+ <a name="I"></a><span style="font-weight: bold;">-I</span>: The ICC
+ profile specified as the final argument will be installed as the
+ default operating system profile for the chosen display, and the
+ display calibration will be set to the calibration tag ('vcgt' tag,
+ if any) in that profile.. On MSWindows and OS X this means that the
+ profile will be copied to the appropriate color profile directory
+ and registered with the operating system. For Linux X11 systems, the
+ profile will be installed using the <a href="ucmm.html">ucmm</a>
+ convention, and the X11 _ICC_PROFILE property in the root window,
+ and also the the XrandR 1.2 X11 _ICC_PROFILE output property on
+ systems that are running XrandR 1.2 or later. The latter is
+ following this <a
+ href="http://www.burtonini.com/computing/x-icc-profiles-spec-0.2.html">convention</a>
+ for allowing applications to locate the display profile for a
+ particular X11 display, and expands it to accomodate XrandR 1.2.
+ Note that for X11 systems, the properties are not persistent, and
+ will need to be loaded each time the X11 server is started (see the
+ <a href="#L">-L</a> flag).<br>
+ <br>
+ <a name="U"></a><span style="font-weight: bold;">-U</span>: The ICC
+ profile specified as the final argument will be un-installed as the
+ default operating system profile for the chosen display. The display
+ calibration will remain unchanged.<br>
+ <br>
+ <a name="S"></a><span style="font-weight: bold;">-S</span> d: Some
+ systems have more than one profile scope that an installed profile
+ will apply to, and this parameter allows overriding the default user
+ scope. On OS X, there is a choice of three scopes: <span
+ style="font-weight: bold;">n</span>: for network scope, if people
+ are sharing profiles over a network, <span style="font-weight:
+ bold;">l</span>: local system scope, which installs the profile
+ for all users of a system, and the default <span
+ style="font-weight: bold;">u</span>, which covers just the user
+ installing the profile. On Linux or Microsoft Vista, just the local
+ system <span style="font-weight: bold;">l</span> and user <span
+ style="font-weight: bold;">u</span> scope are available. Note that
+ you may need to run dispwin with elevated privileges(sudo) to be
+ able to successfully use network or local system scope. This option
+ also applies to uninstalling a profile. Note that to install a user
+ profile for the root account, you will have to login as root (sudo
+ will not achieve this).<br>
+ <br>
+ <a name="L"></a> <span style="font-weight: bold;">-L</span>: This
+ option fetches the current installed system profile for the chosen
+ display, and sets the display to the calibration tag ('vcgt' tag, if
+ any) in the profile. This is a convenient way of initializing the
+ display on system startup from the installed display profile, if the
+ system doesn't not do this automatically .<br>
+ <br>
+ <a name="E"></a> <span style="font-weight: bold;">-E</span>: Daemon
+ mode (experimental). When running on a UNIX based system that used
+ the X11 Windowing System, this option runs dispwin in a "daemon"
+ mode where it monitors the given X11 server, waiting for any changes
+ in monitors that may require loading a matching ICC profile (ie.
+ such as re-configuring, plugging in a different monitor etc.)&nbsp;
+ This only works if XRandR 1.2 is available on the server. By default
+ dispwin runs silently, and will not terminate. If the <span
+ style="font-weight: bold;">-v</span> option is given, it will emit
+ messages to stdout to show what it is doing. When it is first
+ invoked, it will load the installed profiles of all the screens of
+ the given X11 server.<br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes diagnostics to be printed
+ to stdout. A level can be set between 1 .. 9, that may give
+ progressively more verbose information. This can be useful in
+ tracking down why an operation fails.<br>
+ <br>
+ <a name="p1"></a> The final optional parameter on the command line
+ is the name of an ICC profile that contains a Video LUT <span
+ style="font-weight: bold;">vcgt</span> tag, or an Argyll <a
+ href="cal_format.html">.cal</a> format display calibration. If
+ this parameter is provided, then the selected display will be loaded
+ with the given calibration. If the <span style="font-weight: bold;">-V</span>
+ flag was given, then it is verified that this calibration is the
+ currently loaded one.&nbsp; This may be useful in initializing a
+ system to the current calibration on system startup, although a
+ better way may be to install the profile (<span style="font-weight:
+ bold;">-I</span> option), and then just use <span
+ style="font-weight: bold;">-L</span>. Note that the vcgt tag
+ interpretation within Argyll is consistent with that of the
+ originators of the tag. Other ICC profile vcgt implementations may
+ not be so consistent.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that on an X11 system,
+ if the environment variable <span style="font-weight: bold;">ARGYLL_IGNORE_XRANDR1_2</span>
+ is set (ie. set it to "yes"), then the presence of the XRandR 1.2
+ extension will be ignored, and other extensions such as Xinerama and
+ XF86VidMode extension will be used. This may be a way to work around
+ buggy XRandR 1.2 implementations.<br>
+ <span style="font-weight: bold;"><br>
+ NOTE</span> on MSWin systems that you will have to disable any
+ other calibration installer program if you want to be able to
+ control calibration using dispwin. Note also that there are other
+ programs that will interfere with calibration loading, such as
+ igfxpers.exe that gets installed with nVidia "Optimus" technology.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/evalInputTargets.html b/doc/evalInputTargets.html
new file mode 100644
index 0000000..91a38f1
--- /dev/null
+++ b/doc/evalInputTargets.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>Evauating Input Targets</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta content="Graeme Gill" name="author">
+</head>
+<body>
+<h2 style="text-decoration: underline; font-weight: bold;">Evaluating
+input targets<br>
+</h2>
+There are a variety of color profiling targets available for
+characterizing input targets, and it is sometimes hard to decide which
+one will be best for your particular purpose. Listed here are some
+criteria to evaluate:<br>
+<h4>Color gamut</h4>
+The resulting profile will only be accurate between or near the color
+values contained on the chart. This means that if the colors you are
+actually processing with your device go outside the gamut of your test
+chart, the color values will have been extrapolated by the profile, and
+are therefore likely to be not very accurate. <br>
+<h4>Color Resolution</h4>
+The profile will be most accurate for colors that are near those
+contained on the chart. This means that the more closely and evenly
+spaced within the color gamut the value of<br>
+the test chart are, the more accurate overall the chart will be. So
+typically the greater the number of test values, the better.<br>
+<h4>Dynamic range and White point</h4>
+Similar to color gamut, the profile will only be accurate over the
+range of lightness levels exercised by the chart. At the dark end the
+ideal black test value will be a light trap. At the white end the ideal
+white test value would be the perfect 100% reflective diffuser. In
+practice there is another consideration, which is that by default the
+white point of the profile is set by the white value of the test chart,
+and any values over this may be clipped by the profile. So ideally the
+white patches should represent the white value of the work you will be
+using the input device for.<br>
+<h4>Spectral similarity</h4>
+One of the fundamental problems with colorimetrically characterizing
+input devices, is that typically input devices don't have the same
+spectral sensitivity as a human observer. This means that it "sees"
+color differently, and that there is no way to perfectly compensate for
+this in a device profile. [There will be some spectral values that look
+the same to the device but appear different to us, and visa-versa.] A
+colorimetric profile will best compensate for such differences when the
+target test colors have the same spectral reflectance characteristics
+as the the intended work. What this translates to is that you will get
+best results when the test chart uses a similar printing process to
+whatever work you will be using the input device for. So if you are
+intending to scan photographic prints, you should use a photographic
+based test chart. If you were scanning artworks, then you should use a
+test chart that has pigments that are similar to paint used on such
+artworks, etc. When characterizing camera's, an additional source of
+spectral differences is the illuminating light source used. Once again,
+it will be best to choose a light source to characterize the camera
+that is going to be most similar to the light source you will typically
+shoot photographs under. <br>
+<br>
+</body>
+</html>
diff --git a/doc/extracticc.html b/doc/extracticc.html
new file mode 100644
index 0000000..73e572b
--- /dev/null
+++ b/doc/extracticc.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>extracticc</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>xicc/extracticc</b></h2>
+ <h3>Summary</h3>
+ Extract an embedded ICC profile from a TIFF or JPEG raster file.<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">usage: extracticc&nbsp;
+ [-v] infile.tif/jpg outfile.icm<br>
+&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Verbose</span></small><small><span style="font-family:
+ monospace;"></span><br style="font-family: monospace;">
+ </small><br>
+ <h3>Usage Details and Discussion<br>
+ </h3>
+ The<b> -v</b> flag may give extra information.<br>
+ <br>
+ <span style="font-weight: bold;">infile.tif/jpg</span> &nbsp;&nbsp;
+ should be the path to the TIFF or JPEG image file that contains the
+ embedded
+ ICC profile<br>
+ <br>
+ <span style="font-weight: bold;">outfile.icm</span>&nbsp; should be
+ the
+ path to the file that will be created to hold the ICC profile
+ extract
+ from the TIFF or JPEG file. The appropriate extension should be used
+ for the
+ platform, i.e. <span style="font-weight: bold;">icm</span> for
+ MSWindows, and <span style="font-weight: bold;">icc</span> for OS X
+ or
+ Unix/Linux.<br>
+ </body>
+</html>
diff --git a/doc/extractttag.html b/doc/extractttag.html
new file mode 100644
index 0000000..90174b4
--- /dev/null
+++ b/doc/extractttag.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>extractttag</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>xicc/extractttag</b></h2>
+<h3>Summary</h3>
+<small><span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;"></span>Extract a text tag (ie. CGATS
+.ti3 data or CAL) from an ICC profile.</small>
+<h3>Usage Summary</h3>
+<small><span style="font-family: monospace;">usage: extractttag&nbsp;
+[-v] infile.icm outfile<br>
+&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose<br>
+&nbsp;-t tag&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Extract this tag
+rather than default 'targ'<br>
+&nbsp;-c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Extract calibration file from 'targ' tag</span></small><small><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+</small><br>
+<h3>Usage Details and Discussion<br>
+</h3>
+The<b> -v</b> flag may give extra information.<br>
+<br>
+<span style="font-weight: bold;">infile.icm</span> &nbsp;&nbsp;
+should be the path to the ICC profile<br>
+<br>
+<span style="font-weight: bold;">outfile</span>&nbsp; should be the
+path to the file that will be created to hold the contents of the text
+tag. The appropriate extension should be used for the contents of the
+tag (ie. <span style="font-weight: bold;">.ti3</span> for the&nbsp;
+for the
+'targ' tag, <span style="font-weight: bold;">.cal</span> for a
+calibration, etc.)<span style="font-weight: bold;"></span><span
+ style="font-weight: bold;"></span>.<br>
+</body>
+</html>
diff --git a/doc/fakeCMY.html b/doc/fakeCMY.html
new file mode 100644
index 0000000..3122073
--- /dev/null
+++ b/doc/fakeCMY.html
@@ -0,0 +1,73 @@
+<!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type"
+ content="text/html; charset=iso-8859-1">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ <meta name="GENERATOR"
+ content="Mozilla/4.73 [en] (WinNT; I) [Netscape]">
+ <title>fakeread</title>
+</head>
+<body>
+<h2> <b>xicc/fakeCMY</b></h2>
+<h3> Summary</h3>
+Using a CMYK <a href="File_Formats.html#ICC">ICC</a> profile, create a
+<a href="File_Formats.html#.ti3">.ti3</a> file containing device CMY to
+colorimetric
+values. This can then be used to create a CMY profile, that can be
+linked
+with the original CMYK profile to form a CMY to CMYK separation
+transform.
+<h3> Usage</h3>
+<small><span style="font-family: monospace;">fakeCMY [</span><i
+ style="font-family: monospace;">options</i><span
+ style="font-family: monospace;">]&nbsp; </span><i
+ style="font-family: monospace;">cmykprofile.</i><span
+ style="font-family: monospace;">icm </span><i
+ style="font-family: monospace;">fakecmy</i><span
+ style="font-family: monospace;">.ti3
+</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose mode </span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-r </span><i
+ style="font-family: monospace;">res</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set the resolution of the resulting </span><a
+ style="font-family: monospace;" href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">
+file (default 3). </span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-l </span><i
+ style="font-family: monospace;">tlimit</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set a total ink limit, 0 .. 400%&nbsp; (estimate by default)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-l </span><i
+ style="font-family: monospace;">klimit</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set a black ink limit, 0 .. 100%&nbsp; (estimate by default) </span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><i
+ style="font-family: monospace;">profile.</i><span
+ style="font-family: monospace;">icm&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+CMYK&nbsp; </span><a style="font-family: monospace;"
+ href="File_Formats.html#ICC">ICC</a><span
+ style="font-family: monospace;"> input profile to
+use </span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><i
+ style="font-family: monospace;">outfile</i><span
+ style="font-family: monospace;">.ti3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Name for output </span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;"> file </span></small><br>
+&nbsp;
+<h3> Comments</h3>
+This tool is a means of producing a CMY to CMYK separation. A fake
+CMY profile is created from the output of fakeCMY, and this is then
+linked to
+the original CMYK profile using <a href="collink.html">collink</a>, to
+create
+a separation containing the desired black generation. <br>
+</body>
+</html>
diff --git a/doc/fakeread.html b/doc/fakeread.html
new file mode 100644
index 0000000..aa2847c
--- /dev/null
+++ b/doc/fakeread.html
@@ -0,0 +1,248 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>fakeread</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>spectro/fakeread</b></h2>
+<h3>Summary</h3>
+Simulate the measurement of a devices response, using an existing
+device profile, or measured test point data set. The device profile can
+be either
+an <a href="File_Formats.html#ICC">ICC</a> or <a
+ href="File_Formats.html#MPP">MPP</a> profile, or the data set can be a
+<a href="File_Formats.html#.ti3">.ti3</a> file. A device link
+separation or color space conversion can be applied before the
+print/measure simulation.<br>
+<h3>Usage</h3>
+<small><span style="font-family: monospace;">fakeread [-v] [-s] </span></small><small><span
+ style="font-family: monospace;">[<span style="font-style: italic;">separation.ic<span
+ style="font-family: monospace;">m</span></span>] </span></small><small><span
+ style="font-family: monospace;"></span><i
+ style="font-family: monospace;">profile.</i><span
+ style="font-family: monospace;">[icm|mpp|ti3] </span><i
+ style="font-family: monospace;">inoutfile</i><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp; &nbsp; &nbsp; Verbose mode</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp; &nbsp; &nbsp; Lookup </span><a style="font-family: monospace;"
+ href="File_Formats.html#MPP">MPP</a><span
+ style="font-family: monospace;"> spectral values</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+separation profile</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Output
+Lab rather than XYZ<br>
+&nbsp;-k
+file.cal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Apply
+calibration (after sep.) and include in .ti3<br>
+&nbsp;-i
+file.cal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Include
+calibration in .ti3 (but don't apply it)<br>
+</span></small><small><span style="font-family: monospace;">&nbsp;-r
+level&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Add
+average random deviation of &lt;level&gt;% to input device values
+(after sep. &amp; cal.)</span></small><br
+ style="font-family: monospace;">
+<small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;-0
+pow&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Apply
+power to input device chanel 0-9 (after sep. cal. &amp; rand.)</span><br
+ style="font-family: monospace;">
+&nbsp;
+<span style="font-family: monospace;">-R
+level&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Add
+average random deviation of &lt;level&gt;% to output PCS values<br>
+</span></small><small><span style="font-family: monospace;">&nbsp;-u
+&nbsp; &nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Make
+random deviations have uniform distributions rather than normal<br>
+&nbsp;-S
+seed&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set
+random seed<br style="font-family: monospace;">
+</span></small><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;-b
+L,a,b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Scale
+black point to target Lab value<br>
+&nbsp;-I
+intent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+r = relative colorimetric, a = absolute (default)<br
+ style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;[<span
+ style="font-style: italic;">separation.ic<span
+ style="font-family: monospace;">m</span></span>]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Device
+link separation profile</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><i
+ style="font-family: monospace;">profile.</i><span
+ style="font-family: monospace;">[icm|mpp|ti3] &nbsp; &nbsp; </span><a
+ style="font-family: monospace;" href="File_Formats.html#ICC">ICC</a><span
+ style="font-family: monospace;">, </span><a
+ style="font-family: monospace;" href="File_Formats.html#MPP">MPP</a><span
+ style="font-family: monospace;">
+or&nbsp;</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">
+profile/file to use</span><br style="font-family: monospace;">
+&nbsp;
+<span style="font-family: monospace;"></span><i
+ style="font-family: monospace;">inoutfile</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp; &nbsp; Base name for
+input[</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti1">.ti1</a><span
+ style="font-family: monospace;">]/output[</span><a
+ style="font-family: monospace;" href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">] file</span></small><br>
+<b><br>
+Examples</b><br>
+<br>
+fakeread profile.icm testvalues<br>
+fakeread -p separation.icm profile.icm testvalues<br>
+<h3>Comments<br>
+</h3>
+The <span style="font-weight: bold;">-v</span> flag does nothing at
+the moment.<br>
+The <span style="font-weight: bold;">-s</span> flag works only with
+MPP profiles that contain spectral model
+information.<br>
+The <span style="font-weight: bold;">-p</span> flag enables a device
+to device value conversion before
+converting to expected PCS values.<br>
+The <span style="font-weight: bold;">-l</span> flag causes the CIE
+output values to be L*a*b* rather than the
+default XYZ values.<br>
+<br>
+The <b>-k file.cal</b> parameter specifies a printer
+calibration file created by <a href="printcal.html">printcal</a>, and
+the supplied calibration curves will be applied to the chart device
+values after any separation. This allows emulating a system that uses
+per device channel calibration. The calibration curves will also be
+included in
+the resulting .ti3 file, so that they can be passed through to the ICC
+profile allowing accurate computation of ink
+limits.<br>
+<br>
+<a name="i"></a> The <b>-i file.cal</b> parameter specifies a printer
+calibration file created by <a href="printcal.html">printcal</a>,
+and the calibration curves will be
+included in the included in
+the resulting .ti3 file, so that they can be passed through to the ICC
+profile, to allow accurate computation of ink limits.
+The calibration <span style="font-weight: bold;">is not applied</span>
+to tchart values. <span style="font-weight: bold;">Note</span> that if
+the supplied ICC profile contains calibration curves, that these will
+be included in the resulting .ti3 by default.<br>
+<span style="font-weight: bold;"></span><br>
+The <span style="font-weight: bold;">-r</span> parameter is a way of
+simulating instability in the behaviour of
+the simulated
+printing system. The parameter supplied to the flag will be used to
+scale a random offset added to the device values (after any separation
+and calibration is applied). The offset will be a normally distributed
+error with an
+average deviation of level%. A typically value supplied
+might be 1.0 to simulate 1% randomness.<br>
+<br>
+The <span style="font-weight: bold;">-0, -1, -2 .. -9</span>
+parameters are a way of simulating changes in the
+behaviour of the simulated printing system. The parameter supplied to
+the flag will be used to modify the device values (after any
+separation, calibration and device randomness
+is applied) by raising them to the power of the parameter. This applies
+a transfer curve to the simulated device response.<br>
+<br>
+The <span style="font-weight: bold;">-R</span> parameter is a way of
+simulating instability in the behaviour of
+the simulated
+measuring system. The parameter supplied to the flag will be used to
+scale a random offset added to the PCS values. The offset will be a
+normally distributed error with an average deviation of level%. A
+typically value supplied
+might be 1.0 to simulate 1% randomness. <br>
+<br>
+The <span style="font-weight: bold;">-u</span> flag changes the
+distribution of the random offsets applied using the <span
+ style="font-weight: bold;">-r</span> or <span
+ style="font-weight: bold;">-R</span> flags, from the default standard
+deviation, to a uniform deviation distribution. The level is still
+specified as an average deviation.<br>
+<br>
+The <span style="font-weight: bold;">-S</span> parameter lets a
+particular random seed be used when generating random offsets, so that
+the randomness can be made repeatable. Normally a different seed will
+be used for each run. <br>
+<br>
+The <span style="font-weight: bold;">-b</span> parameter is a way of
+simulating devices that have a different black point to the profile
+used. This only works if an ICC profile is used, and scales the black
+point to the parameter value. This will be done in XYZ space by
+default, and in L*a*b* space if the <span style="font-weight: bold;">-l</span>
+flag is used.<br>
+<br>
+The <span style="font-weight: bold;">-I</span> parameter allows
+changing the intent used in looking up the ICC profile colors to
+relative colorimetric. This would <span
+ style="text-decoration: underline;">not</span> be used if you intend
+to make a profile from the resulting .ti3 file, since profiles are
+always made from absolute colorimetric measurement values. Note that
+this flag does nothing if the profile is an MPP or .ti3 file.<br>
+<br>
+Fakeread is useful in creating artificial test value for testing <a
+ href="colprof.html">colprof</a>, as well as providing one path for
+turning an MPP profile into an ICC profile. If a <a
+ href="File_Formats.html#.ti3">.ti3</a> file is
+specified instead of an <a href="File_Formats.html#ICC">ICC</a> or <a
+ href="File_Formats.html#MPP">MPP</a> profile,
+then the closest matching measured points in the .<a
+ href="File_Formats.html#.ti3">.ti3</a> are substituted
+for the test values in the <a href="File_Formats.html#.ti1">.ti1</a>
+file on
+output. If the <a href="File_Formats.html#.ti1">.ti1</a>
+file is a monochrome test file with a White device value, then an RGB <a
+ href="File_Formats.html#ICC">ICC</a> profile, <a
+ href="File_Formats.html#MPP">MPP</a> or <a
+ href="File_Formats.html#.ti3">.ti3</a> may be used, and the White
+values will be translated to equal RGB values. If the <a
+ href="File_Formats.html#.ti1">.ti1</a>
+file is a monochrome test file with a Black device value, then a CMYK <a
+ href="File_Formats.html#ICC">ICC</a> profile, <a
+ href="File_Formats.html#MPP">MPP</a> or <a
+ href="File_Formats.html#.ti3">.ti3</a> may be used, and the Black
+values will be translated to equal CMY = 0, K = grey values. <span
+ style="font-weight: bold;">Note</span> that
+any calibration within a supplied ICC profile is <span
+ style="text-decoration: underline;">not</span> applied during the
+conversion, although it will be included in the .ti3 output (see <span
+ style="font-weight: bold;">-k</span> and <span
+ style="font-weight: bold;">-i</span> flags for how apply calibration
+curves during the conversion and/or include
+a specific calibration curves in the output).<br>
+<br>
+If a separation device profile is provided (e.g. from CMY -&gt; CMYK,
+or perhaps CMYK-&gt;CMYK, to simulate a color correction step before
+"printing"), then this will be applied to the .ti1 device values,
+before converting the the device values into .ti3 PCS values.<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/filmread.html b/doc/filmread.html
new file mode 100644
index 0000000..2109b99
--- /dev/null
+++ b/doc/filmread.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>filmread</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>spectro/filmread</b></h2>
+<h3>Summary</h3>
+Read film colorimetric values using a Gretag SpectroScanT spectrometer.<br>
+<h3>Usage</h3>
+<small><span style="font-family: monospace;">filmread [-v] [-s] [-c
+comport] outfile</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose mode</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Gather spectral data also</span><br style="font-family: monospace;">
+&nbsp;
+<span style="font-family: monospace;"></span></small><small
+ style="font-family: monospace;"><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">-c listno</span><span
+ style="font-family: monospace;"> &nbsp; &nbsp;&nbsp; Set communication
+port from the following list (default 1)</span></small><small><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;outfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Base
+name for input[</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti2">.ti2</a><span
+ style="font-family: monospace;">]/output[</span><a
+ style="font-family: monospace;" href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">] file</span></small><br>
+<h3>Comments</h3>
+This tool allows reading of film test patches, one at a time using
+the
+transparent mode of the Gretag SpectroscanT. <br>
+<br>
+The instrument is assumed to communicate through a
+serial
+communication port, and the port can be selected with the <b>-c</b>
+option,
+if the instrument is not connected to the first port. If you invoke <span
+ style="font-weight: bold;">filmread</span> so as to display the usage
+information (i.e. "filmread -?" or "filmread --"), then the discovered
+serial ports will be listed on Windows and Mac OSX systems.<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/filmtarg.html b/doc/filmtarg.html
new file mode 100644
index 0000000..ba1c060
--- /dev/null
+++ b/doc/filmtarg.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>filmtarg</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>target/filmtarg</b></h2>
+<h3>Summary</h3>
+Create film recorder TIFF files from an Argyll&nbsp;<a
+ href="File_Formats.html#.ti1">.ti1</a> device
+test values.<br>
+<h3>Usage</h3>
+f<small><span style="font-family: monospace;">ilmtarg [-v] [-r] [-g
+gamma] [-f format] </span><i style="font-family: monospace;">basename<br>
+</i><span style="font-family: monospace;">
+&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose mode</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;-r&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't randomise patch location</span><br style="font-family: monospace;">
+<span style="font-family: monospace;"> &nbsp;-g
+gamma&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Gamma correction / linearization</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;"> &nbsp;-f
+format&nbsp;&nbsp;&nbsp;&nbsp; Select format from:</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Acad_Full&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [3656 x 2664]</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Acad_Half&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [1828 x 1332]</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Cscope_Full&nbsp;&nbsp;&nbsp; [3656 x 3112]</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Cscope_Half&nbsp;&nbsp;&nbsp; [1828 x 1556]</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+FullAp_Full&nbsp;&nbsp;&nbsp;&nbsp; [4096 x 3112]</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+FullAp_Half&nbsp;&nbsp;&nbsp; [2048 x 1556]</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Vista_Full&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [4096 x 6144]</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Vista_Half&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [2048 x 3072]</span><br
+ style="font-family: monospace;">
+<i style="font-family: monospace;"> &nbsp;basename</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Base
+name for input[</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti1">.ti1</a><span
+ style="font-family: monospace;">]/output[</span><a
+ style="font-family: monospace;" href="File_Formats.html#.ti2">.ti2</a><span
+ style="font-family: monospace;">] and output </span><a
+ style="font-family: monospace;" href="File_Formats.html#TIFF">TIFF</a><span
+ style="font-family: monospace;"> files.</span></small>
+<h3>Comments</h3>
+The TIFF files will have a name "basename.XXXX.tiff", where XXXX is the
+patch number.<br>
+The TIFF files generate are 16 bit, RGB files.<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/gamma.html b/doc/gamma.html
new file mode 100644
index 0000000..2a9cec3
--- /dev/null
+++ b/doc/gamma.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>About Gamma</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+</head>
+<body>
+<h2 style="text-decoration: underline; font-weight: bold;">About Gamma</h2>
+When calibrating display devices, the notion of "gamma value" quickly
+becomes a topic for discussion. Various numbers are often bandied about
+as if they have a well known and accepted meaning, but it turns out
+that gamma values are not a very precise way of specifying real world
+device behavior at all.<br>
+<br>
+A "gamma" curve is typically thought of as an ideal power curve, but no
+real world device has the necessary zero output at zero input to be
+able to match such a curve, and in general a display may not exactly
+reproduce an idealized power curve shape at all. The consequence of
+this is that there are countless ways of matching a real world curve
+with the ideal gamma power one, and each different method of matching
+will result in a different notional gamma value.<br>
+<br>
+Argyll's approximate specification and reading is simply the gamma of
+the ideal curve that matches the real 50% stimulus relative-to-white
+output level. I think this is a reasonable (robust and simple)
+approximation,
+because it matches the overall impression of brightness for an image. A
+more sophisticated approximation that could be adopted would be to
+locate the idea power curve that minimizes the total delta E of some
+collection of test values, but there are still many details that the
+final result will depend on, such as what distribution of test values
+should be used, what delta E measure should be used, and how can a
+delta E be computed if the colorimetric behavior of the device is not
+known ? Some approaches do things such as minimize the sum of the
+squares of the output value discrepancy for linearly sampled input
+values, and while this is mathematically elegant, it is hard to justify
+the choice of device space as the metric.<br>
+<br>
+There are many other ways in which it could be done, and any such
+approximation may have a quite different numerical value, even though
+the visual result is very similar. This is because the numerical power
+value is very sensitive to what's happening near zero, the very point
+that is non-ideal. Consider the sRGB curve for instance. It's
+technically composed of a power curve segment with a power of 2.4, but
+when combined with its linear segment near zero, has an overall curve
+best approximated by a power curve of gamma 2.2. Matching the 50%
+stimulus would result in yet another slightly different approximation
+value of about 2.224. All these different gamma values represent curves
+that are very visually similar.<br>
+<br>
+<img style="width: 400px; height: 400px;"
+ alt="Plot of sRGB curve vs. power of 2.224" src="srgbplot.gif"
+ align="left"><br>
+<br>
+The result of this ambiguity about what gamma values mean when applied
+to real world curves, is that it shouldn't be expected that there are
+going to be good matches between various gamma numbers, even for curves
+that are very visually similar, unless the precise method of matching
+the ideal gamma curve to the real world curve is known.<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/gamutmapping1.jpg b/doc/gamutmapping1.jpg
new file mode 100644
index 0000000..e962666
--- /dev/null
+++ b/doc/gamutmapping1.jpg
Binary files differ
diff --git a/doc/greytiff.html b/doc/greytiff.html
new file mode 100644
index 0000000..caccece
--- /dev/null
+++ b/doc/greytiff.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>greytiff</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>imdi/greytiff</b></h2>
+<h3>Summary</h3>
+Convert a TIFF file to monochrome colorimetrically, using an ICC device
+profile.<br>
+<h3>Usage<br>
+</h3>
+<small><span style="font-family: monospace;">greytiff [-options] </span><i
+ style="font-family: monospace;">profile.icm infile.tif
+outfile.tif</i><span style="font-family: monospace;"></span><i
+ style="font-family: monospace;"></i><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Verbose</span><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p">-p</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Use slow
+precise floating point conversion, rather than fast integer routines.<br>
+</span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="greytiff.html#c">-j</a><span
+ style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; Use CIECAM02 space for removing color,
+rather than default L*a*b* space.</span></small><small><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#p1"><i>profile.icm</i></a><span
+ style="font-family: monospace;"> &nbsp; &nbsp; &nbsp; &nbsp; Profile
+to define the colorspace of the </span></small><small><a
+ style="font-family: monospace;" href="File_Formats.html#TIFF">TIFF</a><span
+ style="font-family: monospace;">
+Raster file</span></small><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">.</span><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#p2"><i>infile.tif</i></a><span
+ style="font-family: monospace;"> &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+A </span><a style="font-family: monospace;"
+ href="File_Formats.html#TIFF">TIFF</a><span
+ style="font-family: monospace;">
+Raster file that will be the input raster to be transformed.</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#p3"><i>outfile.tif</i></a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; A </span><a style="font-family: monospace;"
+ href="File_Formats.html#TIFF">TIFF</a><span
+ style="font-family: monospace;">
+Raster file created from the input raster, that will have had the color
+removed.</span></small><b><br>
+<br>
+Examples</b><br>
+<br>
+greytiff sRGB.icm infile.tif outfile.tif<br>
+<h3>Comments<br>
+</h3>
+<a name="v"></a> The -v flag reports extra information about the ICC
+profile.<br>
+<a name="p"></a> The -p
+option is intended to aid debugging.<br>
+<a name="j"></a> The -j
+option uses CIECAM02 colorspace to remove the color in. This may
+produce better subjective results for images with highly chromatic
+colors.<br>
+<a name="p2"></a>The second last argument should be the name of the
+TIFF file that is to be processed.<br>
+<a name="p3"></a>The last argument should be the name of the TIFF file
+to hold the results.<br>
+<span style="font-weight: bold;"></span><br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/i1d.jpg b/doc/i1d.jpg
new file mode 100644
index 0000000..e7cc159
--- /dev/null
+++ b/doc/i1d.jpg
Binary files differ
diff --git a/doc/i1d3_1.jpg b/doc/i1d3_1.jpg
new file mode 100644
index 0000000..afb77a3
--- /dev/null
+++ b/doc/i1d3_1.jpg
Binary files differ
diff --git a/doc/i1d3_2.jpg b/doc/i1d3_2.jpg
new file mode 100644
index 0000000..306f830
--- /dev/null
+++ b/doc/i1d3_2.jpg
Binary files differ
diff --git a/doc/i1m.jpg b/doc/i1m.jpg
new file mode 100644
index 0000000..efbf55f
--- /dev/null
+++ b/doc/i1m.jpg
Binary files differ
diff --git a/doc/i1p.jpg b/doc/i1p.jpg
new file mode 100644
index 0000000..7e59c06
--- /dev/null
+++ b/doc/i1p.jpg
Binary files differ
diff --git a/doc/i1pro2.jpg b/doc/i1pro2.jpg
new file mode 100644
index 0000000..8b3cbec
--- /dev/null
+++ b/doc/i1pro2.jpg
Binary files differ
diff --git a/doc/i1proDriver.html b/doc/i1proDriver.html
new file mode 100644
index 0000000..0894f59
--- /dev/null
+++ b/doc/i1proDriver.html
@@ -0,0 +1,157 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>The i1pro Driver</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta content="Graeme Gill" name="author">
+</head>
+<body>
+<h2 style="text-decoration: underline; font-weight: bold;">How can I
+have confidence in the i1pro Driver ?<br>
+</h2>
+A question that has been asked is : "<span style="font-weight: bold;">You've
+written your own driver for the Eye-One Pro. How can I have confidence
+that the measurements are accurate, and will match those made with the
+original manufacturers driver </span>?"<br>
+<br>
+This is a quite reasonable question. The following attempts to answer
+it.<br>
+<h4 style="text-decoration: underline;">Why does Argyll use it's own
+i1pro driver ?</h4>
+Primarily because the Original Manufacturers Driver (OMD) isn't
+available for all the platforms that ArgyllCMS supports (Linux in
+particular). A side benefit is that it's possible to tweak many of the
+driver parameters for slightly better results and more flexibility. It
+has also helped in understanding the characteristics and limitations of
+such instruments.<br>
+<h4 style="text-decoration: underline;">Does it match the OMD ?</h4>
+In principle the behaviour should be very similar. While the Argyll
+driver has been written from scratch, it does use exactly the same
+calibration values from<br>
+inside the instrument, and attempts to use the calibration values and
+process the raw instrument readings in an equivalent manner to that of
+the OMD.<br>
+<br>
+But the proof of the pudding is in the measuring, so to actually verify
+this, the following experiment was conducted:<br>
+<br>
+The Argyll version used was V1.2.0<br>
+<br>
+The Macbeth 24 patch ColorChecker was used as a sample target. For each
+patch (and the calibration tile), the following steps were performed:<br>
+<br>
+1) Place the instrument on the calibration tile.<br>
+<br>
+2) Use Argyll spotread to calibrate the Argyll driver.<br>
+<br>
+3) Change drivers to the OMD.<br>
+<br>
+4) Use the OMD to calibrate the instrument.<br>
+<br>
+5) Move the instrument to the patch on the ColorChecker.<br>
+<br>
+6) Read the color using the OMD.<br>
+<br>
+7) Change the back to the Argyll driver.<br>
+<br>
+8) Using the calibration made in step 2), read the color using Argyll.<br>
+<br>
+Each calibration or reading was performed 15 seconds from the previous
+one, to put the instrument lamp in a repeatable state.<br>
+The instrument was kept in exactly the same position for calibration
+and patch measurement with the two drivers.<br>
+(The whole idea is to reduce all other sources of error, other than the
+driver itself.)<br>
+<br>
+This measurement was repeated just once for each patch + the
+calibration tile. This was done in one run, and the readings were not
+specially selected.<br>
+<h4 style="text-decoration: underline;">Results:</h4>
+The following D50 L*a*b* values were recorded for each measurement:<br>
+<br>
+A) &nbsp;&nbsp; The OMD internally calculated L*a*b* value<br>
+B) &nbsp;&nbsp; The L*a*b* value calculated by Argyll from the OMD
+spectral values.<br>
+C) &nbsp;&nbsp; The L*a*b* value calculated from the Argyll measured
+spectral values.<br>
+D) &nbsp;&nbsp; The L*a*b* value calculated from the Argyll
+Hi-Resolution mode measured spectral values.<br>
+<br>
+<span style="text-decoration: underline;">A is compare to B, to check
+that the spectral to standard observer calculations are equivalent.</span><br>
+<br>
+&nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of 0.006,
+with a maximum of 0.012.<br>
+<br>
+&nbsp;&nbsp;&nbsp; This shows that there is very close agreement in the
+way spectral values are converted to XYZ and L*a*b*.<br>
+<br>
+<span style="text-decoration: underline;">B is compared to C to check
+that the Argyll driver behaves the same as the OMD.</span><br>
+<br>
+&nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of 0.028,
+with a maximum of 0.051.<br>
+<br>
+&nbsp;&nbsp;&nbsp; This shows that the OMD and Argyll driver are in
+close agreement in spectral measurement.<br>
+&nbsp;&nbsp;&nbsp; This error is an order of magnitude smaller than
+uniformity induced errors typical in the media being measured.<br>
+<br>
+<span style="text-decoration: underline;">A is compared to C to check
+that the Argyll driver and spectral to XYZ differences don't compound.</span><br>
+<br>
+&nbsp;&nbsp;&nbsp; The result was an <span style="font-weight: bold;">average</span>
+Delta E (CIE76) of <span style="font-weight: bold;">0.026</span>, with
+a <span style="font-weight: bold;">maximum</span> of <span
+ style="font-weight: bold;">0.048</span>.<br>
+<br>
+&nbsp;&nbsp;&nbsp; Rather than compounding, any spectral to XYZ
+differences tend to cancel
+out slightly. This is the <span style="font-weight: bold;">bottom line</span>
+experimental difference between
+the two drivers. The actual underlying difference may in fact be less
+than this, but it would be necessary to do multiple test runs to
+filter out experimental error.<br>
+<br>
+<span style="text-decoration: underline;">C is compare to D to check
+that the Argyll Hi-Resolution mode is behaving reasonably.</span><br>
+<br>
+&nbsp;&nbsp;&nbsp; The result was an average Delta E (CIE76) of 0.158,
+with a maximum of 0.353.<br>
+<br>
+&nbsp;&nbsp;&nbsp; Because the ColorChecker samples have relatively
+smooth reflectance spectra, it can be expected that<br>
+&nbsp;&nbsp;&nbsp; the normal and Hi-Res mode results should be fairly
+similar. And indeed, this is the case. The biggest<br>
+&nbsp;&nbsp;&nbsp; differences are for patches
+with the largest spectral transitions in them, which is to be expected
+as the<br>
+&nbsp;&nbsp;&nbsp; Hi-Res measurement more
+closely follows the spectral shape, while the differences for
+spectrally flat<br>
+&nbsp;&nbsp;&nbsp; patches is neglegable, since both can follow the
+spectral shape well.<br>
+<br>
+Example Yellow-Green Patch, Hi-Res &amp; Normal spectrum:<br>
+<img style="width: 709px; height: 259px;"
+ alt="Yellow-Green patch, Hi-Res vs. Normal" src="YellowGreen.jpg"><br>
+<br>
+<h4 style="text-decoration: underline;">Conclusions:</h4>
+The experimental average difference of <span style="font-weight: bold;">0.026</span>
+Delta E76 shown above provides evidence that despite using a completely
+different instrument driver to that supplied with the instrument, the
+ArgyllCMS Eye-One pro measurement values have comparable accuracy, and
+can be relied upon to match measurements made using the original
+manufactures driver.<br>
+<h4 style="text-decoration: underline;">Raw Data:</h4>
+The raw data is available in this <a href="i1proDriver.xls">spread
+sheet</a>.<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/i1proDriver.xls b/doc/i1proDriver.xls
new file mode 100644
index 0000000..ca1cdf5
--- /dev/null
+++ b/doc/i1proDriver.xls
Binary files differ
diff --git a/doc/i1scan14.jpg b/doc/i1scan14.jpg
new file mode 100644
index 0000000..94b68fb
--- /dev/null
+++ b/doc/i1scan14.jpg
Binary files differ
diff --git a/doc/iccdump.html b/doc/iccdump.html
new file mode 100644
index 0000000..8be51f3
--- /dev/null
+++ b/doc/iccdump.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>iccdump</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>icclib/iccdump</b></h2>
+<br>
+Dump the contents of an ICC profile as human readable text.<br>
+<h3>Usage</h3>
+<small><span style="font-family: monospace;">&nbsp;iccdump [-v level]
+[-t tagname] [-s] </span><i style="font-family: monospace;">infile</i><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v
+level&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Verbose level 1-3 (default 2)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-t
+tag&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dump this tag only (can
+be used multiple times)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Search for embedded profile</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp; </span><i
+ style="font-family: monospace;">infile</i><span
+ style="font-family: monospace;"> &nbsp; &nbsp; &nbsp; </span><a
+ style="font-family: monospace;" href="File_Formats.html#ICC">ICC</a><span
+ style="font-family: monospace;"> profile</span></small><br>
+<h3><b> Examples</b></h3>
+iccdump sRGB.icm<br>
+<br>
+iccdump -v3 -t rTRC sRGB.icm<br>
+<h3>Comments</h3>
+This tool will dump the contents of the header, and each known type
+of tag within the ICC profile. For more detail on each tag, the -v flag
+should be used, typically with verbose level 3.<br>
+<br>
+The <span style="font-weight: bold;">-s</span> flag causes iccdump to
+do a brute force search for any embedded
+profiles within the file, and dumps them all. This won't work if the
+profile data is
+segmented or compressed.<br>
+<br>
+The <span style="font-weight: bold;">-t</span> parameter may be used
+multiple times, to dump just specific tags, e.g. <span
+ style="font-weight: bold;">iccdump -v3 -t clrt -t clot devicelink.icm</span><br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/iccgamut.html b/doc/iccgamut.html
new file mode 100644
index 0000000..6d2f5ba
--- /dev/null
+++ b/doc/iccgamut.html
@@ -0,0 +1,334 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>iccgamut</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>xicc/iccgamut</b></h2>
+ <br>
+ Create a gamut file or VRML file &nbsp;of the color gamut of an ICC
+ profile.<br>
+ <span style="font-weight: bold;"> iccgamut</span> allows creation of
+ gamut files from the forward or backwards
+ table of an ICC profile, in Lab or CIECAM02 Jab colorspace, and can
+ also
+ representing the gamut as a VRML file.<br>
+ <h3>Usage<br>
+ </h3>
+ <small><span style="font-family: monospace;">iccgamut [-options] </span><i
+ style="font-family: monospace;">profile</i><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Verbose</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-d
+ sres&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Surface
+ resolution details 1.0 - 50.0</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;-w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+emit
+ VRML .wrl file as well as CGATS .gam file</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't
+ add VRML axes or white/black point</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;-k&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Add
+ VRML markers for prim. &amp; sec. "cusp" points</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-f
+ function&nbsp;&nbsp; f =
+ forward*, b = backwards</span><br style="font-family:
+ monospace;">
+ &nbsp;
+ <span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">-i
+ intent&nbsp;&nbsp;&nbsp;&nbsp; p =
+ perceptual, r = relative colorimetric,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+s
+ = saturation, a = absolute (default), d = profile default</span></small><small><span
+ style="font-family: monospace;"></span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;-o
+ order&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = normal
+ (priority: lut &gt; matrix &gt; monochrome)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+r
+ = reverse (priority: monochrome &gt;
+ matrix &gt; lut)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><span
+ style="font-family: monospace;">-p oride</span><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l
+ =
+ Lab_PCS (default), j = CIECAM02 Appearance Jab</span></small><small><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-l
+ tlimit&nbsp;&nbsp;&nbsp;&nbsp; set total
+ ink limit, 0 - 400% (estimate by default)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-L
+ klimit&nbsp;&nbsp;&nbsp;&nbsp; set black ink
+ limit, 0 - 100% (estimate by default)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-c
+ viewcond&nbsp;&nbsp; set
+ viewing conditions for CIECAM02,</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+either
+ an enumerated choice, or a series of
+ parameters:value changes</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pp - Practical Reflection
+ Print
+ (ISO-3664 P2)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; pe - Print evaluation environment (CIE 116-1995)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; pc - Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; &nbsp; mt - Monitor in typical work environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; mb - Monitor in bright work environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; md - Monitor in darkened work
+ environment</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; jm - Projector in dim environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; jd - Projector in dark environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; pcd - Photo CD - original scene
+ outdoors</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; ob - Original scene - Bright Outdoors</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; cx - Cut Sheet Transparencies on a viewing
+ box</span></small><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+s:surround&nbsp;&nbsp;
+ n = auto, a = average, m = dim, d = dark,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; &nbsp;&nbsp; c = transparency (default average)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+w:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Adapted white point
+ as XYZ (default media white)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+w:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Adapted white point as
+ x, y</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+a:adaptation
+ Adaptation luminance in cd.m^2 (default 50.0)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+b:background
+Background
+ % of image luminance (default 20)<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; l:scenewhite Scene
+ white in
+ cd.m^2 if surround = auto (default 250)<br style="font-family:
+ monospace;">
+ </span><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Flare
+ light % of image luminance (default 1)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Flare color as
+ XYZ (default media white)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Flare color as x, y<br>
+ &nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Create
+ special cube surface topology plot<br style="font-family:
+ monospace;">
+ </span><i style="font-family: monospace;">profile</i><span
+ style="font-family: monospace;"> &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; The
+ name of the </span><a style="font-family: monospace;"
+ href="File_Formats.html#ICC">ICC</a><span style="font-family:
+ monospace;">
+ profile, as well as the basename of the </span><a
+ style="font-family: monospace;" href="File_Formats.html#.gam">gamut</a><span
+ style="font-family: monospace;"> [.gam] and/or </span><a
+ style="font-family: monospace;" href="File_Formats.html#.wrl">VRML</a><span
+ style="font-family: monospace;"> [.wrl] file.</span></small>
+ <br>
+ <h3>Comments</h3>
+ The parameters are all those that control which table in the ICC
+ profile to use, as well as what color space to convert it to. <br>
+ <br>
+ The<b> -v</b> flag dumps out the ICC profile header information.
+ Using <b>-v</b> <b>-w</b> will also print the gamut volume in
+ cubic L*a*b* units.<br>
+ <br>
+ The <b>-d</b> parameter controls the level of detail displayed in
+ the
+ surface. The parameter roughly corresponds to a deltaE value, so
+ smaller
+ values give greater detail. The default value is around 10, and is a
+ good
+ place to start. Small values may take a lot of time to generate, and
+ will
+ produce big files.<br>
+ <br>
+ The <b>-w</b> flag causes a VRML file to be produced, as well as a
+ gamut file.<br>
+ <br>
+ The <b>-n</b> flag suppresses the L*a*b* axes being created in
+ the VRML.<br>
+ <br>
+ The <span style="font-weight: bold;">-k</span> flag adds markers
+ for
+ each of the primary and secondary "cusp" points (Red, Yellow, Green,
+ Cyan, Blue &amp; Magenta). No markers will be displayed if the cusps
+ cannot be determined.<br>
+ <br>
+ The <b>-f </b>parameter allows choosing the ICC table to be used
+ in
+ plotting the gamut. The backwards tables generally incorporate gamut
+ compression, and therefore don't reflect the native capabilities of
+ the
+ device.<br>
+ <br>
+ The <b>-i</b> flag selects the intent transform used for a lut
+ based
+ profile. It also selects between relative and absolute colorimetric
+ for
+ non-lut base profiles. Note that anything other than colorimetric
+ may
+ not represent the
+ native capabilities of the device. The default intent will be
+ absolute
+ colorimetic for L*a*b* output, and CIECAM02 appearance for Jab
+ output.<br>
+ <br>
+ An ICC profile is allowed to contain more than the minimum number of
+ elements or table needed to describe a certain transform, and may
+ contain redundant descriptions. &nbsp;By default, lut based table
+ information will be used first if present, followed by matrix/shaper
+ information, and only using
+ monochrome information if it is all that is present. The <b>-o</b>
+ flag,
+ reverses this order.&nbsp;&nbsp;&nbsp; <br>
+ <br>
+ <span style="font-weight: bold;">-p</span>: By default the gamut
+ will
+ be created in L*a*b* colorspace. If&nbsp; <span style="font-weight:
+ bold;">-pj</span> is selected, then CIECAM02
+ appearance space Jab will be used for the output, and the viewing
+ conditions will be taken into account. Jab space is what is normally
+ needed to be compatible with the default intents used in <a
+ href="colprof.html">colprof</a>. <span style="font-weight: bold;"><br>
+ </span>Note that the CIECAM02 output space selection by default uses
+ the colorimetric transform of the profile resulting in the
+ appearance
+ of the native device, but that the perceptual or
+ saturation transforms may be used by selecting them using the <span
+ style="font-weight: bold;">-i</span> parameter, which may give a
+ different result with some profiles. This may be desirable if an
+ image
+ is to be transformed through the perceptual or saturation tables of
+ a
+ profile as part of a link with an Argyll generated output profile,
+ since it will then represent the apparent gamut of the image when
+ subject to these tables. If the absolute colorimetric intent is
+ chosen
+ using <span style="font-weight: bold;">-ia</span> in combinations
+ with
+ <span style="font-weight: bold;">-pj</span>, then&nbsp; Jab with
+ a fixed white reference is used, which emulates an absolute CIECAM02
+ Jab
+ appearance space. <br>
+ <br>
+ The <b>-l</b> parameter allows setting a total ink limit (TAC) for
+ printing
+ devices. If a device has a total ink limit, and hasn't been
+ characterised with device values above this limit, then plotting the
+ gamut in these areas will almost certainly be misleading. tables. By
+ default, a total ink limit will
+ be estimated from the profile tables. The ink limit
+ will be in final calibrated device values if the profile includes
+ calibration information.<br>
+ <br>
+ The <b>-L</b> parameter allows setting a black ink limit for
+ printing
+ devices. If a device is to be used with a black ink limit, then it
+ is
+ useful to evaluate
+ the gamut with the limit in place. By default, a black ink limit
+ will
+ be estimated from the profile tables. The ink limit
+ will be in final calibrated device values if the profile includes
+ calibration information.<br>
+ <br>
+ The <b>-c</b> parameter allows setting the CIECAM02 viewing
+ conditions,
+ either by choosing a typical viewing environment, or controlling
+ particular viewing condition parameters.<br>
+ <br>
+ The <span style="font-weight: bold;">-s</span> flag creates a
+ special
+ hyper-cube surface plot that is artificially colored. This can be
+ useful for identifying the topology of the black ink color response.<br>
+ <h3>Example<br>
+ </h3>
+ To create a view in L*a*b* of the absolute gamut of a CMYK file with
+ an
+ ink limit of 260%, one might use:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-style: italic;">iccgamut -w
+ -ff
+ -ia -l260 profile.icm</span><br>
+ <br>
+ and the resulting files will be <span style="text-decoration:
+ underline;">profile.gam</span> and <span style="text-decoration:
+ underline;">profile.wrl</span>.<br>
+ <br style="font-weight: bold;">
+ <span style="font-weight: bold;"></span><br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/iccgamutmapping.html b/doc/iccgamutmapping.html
new file mode 100644
index 0000000..d180372
--- /dev/null
+++ b/doc/iccgamutmapping.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>About ICC profiles and Gamut Mapping</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+</head>
+<body>
+<h2><u>About ICC profiles and Gamut Mapping</u></h2>
+<h3>How ICC profiles support different intents</h3>
+cLUT (Color Lookup Table) based ICC profiles support multiple <span
+ style="font-weight: bold;">intents</span> by having a table for each
+intent. In a typical device cLUT profile, there are up to 6 cLUT's,
+three for input (AtoB tables, that convert from device space to PCS
+(Profile connection space)), and three for output (BtoA tables, that
+convert from PCS to device space). The tables allow the use of
+different color transforms, each transform being tailored for a
+different effect:<br>
+<br>
+AtoB0, BtoA0:&nbsp;&nbsp; Perceptual<br>
+AtoB1, BtoA1:&nbsp;&nbsp; Colorimetric<br>
+AtoB2, BtoA2:&nbsp;&nbsp; Saturation<br>
+<br>
+The colorimetric intent is meant to convey the exact device color
+behaviour, without any gamut mapping. Typically it is used to store the
+devices behaviour (characterization), and is also used where exact
+color reproduction is required, such as for proofing. The Colorimetric
+tables double up for both relative colorimetric and
+absolute colorimetric with the application of a white point restoration.<br>
+<br>
+The Perceptual and Saturation tables are meant to contain gamut mapping
+combined with the device characterization. The allowance for this in
+both the AtoB direction, as well as the BtoA direction permits a
+profile to gamut map from the device gamut to some intermediate gamut,
+and then from the intermediate gamut to the device gamut.<br>
+<br>
+[Note that Shaper/Matrix profiles are always Colorimetric intent, since
+there is only a single transformation, and it does not have the
+necessary flexibility to accommodate gamut mapping.]<br>
+<h3>ICC Version 2 behaviour<br>
+</h3>
+Apart from defining the general purpose of the different tables, the
+ICC Version 2 specification doesn't specify exactly how they are to
+achieve this, so it is up to the profile maker to make a choice in this
+regard. There is no common gamut boundary specified for the PCS, and
+such an approach limits the achievable intents in any case (see ICC
+Version 4 behaviour for an explanation why).<br>
+<br>
+What I've chosen to do with Argyll profiles, is to make all the AtoB
+tables the same as colorimetric. This means that the conversion used
+for the source profile is always colorimetric, and also means that the
+source gamut seen by the destination profile is the source colorspace
+gamut. This means that the gamut mapping is done solely in the BtoA
+tables,
+and that their task is to map the source colorspace gamut to the
+destination colorspace gamut. So to construct the perceptual and
+saturation intent mapping tables, a source profile or source gamut
+needs to be specified, so that a gamut mapping can be constructed.<br>
+<br>
+The advantages of this approach is that the behaviour is precisely
+defined, a full range of gamut mapping options is available, and
+compatibility with matrix profiles (which do not have gamut mapping
+transforms) and other foreign profiles can be assured, by simply using
+such profiles as colorimetric sources. The main disadvantage is that
+the gamut mapping will only operate exactly as intended when the
+profile is linked with the source profile it was setup for. This is
+really a fundamental limitation of the idea of having pre-computed
+gamut mapping color transforms, that the ICC profile format was
+intended to support.<br>
+<br>
+Some non-Argyll profile have gamut mapping transforms in their
+Perceptual and Saturation A2B tables, and this means that the apparent
+gamut of a source through these tables may be different to the actual
+device gamut. To accommodate using these profiles with CMM's (Color
+Management Modules) that do not permit the separate choice of intent
+tables for the source and destination profiles, Argyll will by default
+use the gamut defined by the source profile perceptual table to
+create the gamut mapping of the destination perceptual table, and the
+source saturation table to make the destination saturation table. Note
+that this can affect the exact nature of the gamut mapping, the
+distortion of the source gamut changing the apparent relationship
+between it and the destination gamut - see "ICC Version 4 behavior" for
+an illustration of the kind of changes this causes. [This default can
+be overridden though using the colprof -nP and -nS flags.]<br>
+<h3>ICC Version 4 behaviour</h3>
+(Note that Argyll does not currently support ICC V4)<br>
+<br>
+By default, ICC Version 4 profile operate exactly the same as the ICC
+V2 profile in regard to gamut mapping. A slight adjustment was made to
+the permitted tag contents, to allow things like Display profiles to
+contain the full range of AtoB and BtoA tables, so that they could also
+be gamut mapped. But an optional part of ICCV4, is to use the <span
+ style="font-weight: bold;">Profile Reference Medium Gamut</span>
+(PRMG) as an
+intermediate gamut boundary between the source colorspace, and the
+destination colorspace. If this option is used, then an additional tag
+in the ICCV4 profile indicates that this is the case. This then solves
+the problem of the gamut mapping having to know the source and
+destination gamuts to operate. Instead, the gamut mapping is split into
+two parts, the first where the source gamut to RMG is done by the AtoB
+tables, and then the RMG to destination gamut is done by the BtoA
+tables. Profiles can therefore be mix and matches, while retaining true
+gamut mapping.<br>
+<br>
+This approach has a number of drawbacks though. One is that the colors
+get gamut mapped twice. Gamut mapping is sometimes not very precise,
+and the geometry of the transforms may not cancel out, especially since
+different profile vendors may choose different algorithms in their
+gamut mapping. By "cancel out", I mean that even if you were linking
+the same source colorspace to the same destination colorspace, the
+gamut may be expanded (say) in the process of mapping to the PRMG, and
+then compressed again in mapping from the RMG to the device space, and
+these expansions and compressions may not quite match. Given that the
+PRMG is a relatively large gamut, larger than many real devices actual
+behavior, this sort of expansion and re-compression will be the normal
+thing.<br>
+<br>
+The chief drawback, is that only one (non colorimetric) intent can
+really be supported, that of saturation. <br>
+<br>
+The typically expected behaviour of perceptual intent gamut mapping, is
+to
+compress any areas of the source gamut that lie outside the destination
+gamut, but for areas that fall within the destination gamut, change
+them as little as possible, consistent with keeping smooth and
+proportional with respect to the compressed colors. This preserves the
+source "look" as much as
+possible, while ensuring that out of gamut colors are smoothly brought
+within the destination gamut.<br>
+<br>
+Typical behavior of a saturation intent, is (at least), to not only
+compress out of gamut source colors to fit within the destination, but
+to expand any source boundary that falls within the destination gamut
+outwards match the destination gamut. Some practical saturation gamut
+mappings may go further than this, and expand a little beyond the
+destination gamut to ensure fully saturated boundary colors, and also
+enhance the saturation of all colors mapped through it.<br>
+<br>
+&nbsp;By mapping the source gamut to
+the RMG in the A2B, all information about what areas of the source
+gamut are
+inside or outside of the destination gamut are lost, so the destination
+gamut mapping can not known which colors may be left unchanged, and
+which really need compressing. All it can do is map the RMG to match
+the destination gamut,
+thereby effecting a saturation style intent. <br>
+<br>
+Once again, this is a fundamental limitation of using pre-computed
+gamut mappings. The only effective way of overcoming such limitations
+is to move to a more active color management architecture, in which
+gamut mappings are computed at link time, to accommodate the actual
+source and destination gamuts.<br>
+<br>
+<br>
+<img alt="Illustration of perceptual and saturation gamut mapping."
+ src="gamutmapping1.jpg" style="width: 665px; height: 215px;"><br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/icclu.html b/doc/icclu.html
new file mode 100644
index 0000000..9a95fbf
--- /dev/null
+++ b/doc/icclu.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>icclu</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>icclib/icclu</b></h2>
+<h3>Summary</h3>
+Lookup individual color values through any ICC profile table, either
+interactively, or as a batch.<br>
+<h3>Usage summary<br>
+</h3>
+<small><span style="font-family: monospace;">icclu [-v level] [-f func]
+[-i intent] [-o order] profile</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v level
+&nbsp;&nbsp;&nbsp;&nbsp; Verbosity level 0 -
+2 (default = 1)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-f </span><i
+ style="font-family: monospace;">function</i><span
+ style="font-family: monospace;">&nbsp;&nbsp; f = forward, b =
+backwards, g =
+gamut, p = preview</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-i </span><i
+ style="font-family: monospace;">intent</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; p =
+perceptual, r = relative colorimetric,</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+s = saturation, a = absolute</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-p </span><i
+ style="font-family: monospace;">oride</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x =
+XYZ_PCS, l = Lab_PCS, y = Yxy,</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-o </span><i
+ style="font-family: monospace;">order</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n =
+normal
+(priority: lut &gt; matrix &gt; monochrome)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+r = reverse (priority: monochrome &gt; matrix &gt;
+lut)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-s</span><span
+ style="font-style: italic; font-family: monospace;"> scale</span><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Scale
+device range 0.0 - scale rather than 0.0 - 1.0</span></small><br>
+<br>
+The colors to be translated should be fed into standard input,<br>
+one input color per line, white space separated.<br>
+A line starting with a # will be ignored.<br>
+A line not starting with a number will terminate the program.<br>
+<h3></h3>
+<h3>Flags and Parameters</h3>
+The <b>-v</b> parameter sets the level of verbosity.
+Default is level 1, which repeats each input value, the colorspaces of
+input and output, the type of conversion algorithm used, and if the
+result was clipped. Level 2 adds prints extra information about the
+profile before doing the conversions. Level 0 turns off all verbosity,
+just outputting the results of each conversion. Use the latter to
+capture batch output ready for further processing.<br>
+<br>
+The <b>-f</b> flag selects which type of table or conversion is to be
+used.<br>
+<br>
+The <b>-i</b> flag selects the intent for a lut based profile.<br>
+<br>
+Normally the native PCS (Profile Connection Space) of a device or
+abstract profile is used, but the <b>-p</b> flag<br>
+allows this to be overridden, and XYZ, L*a*b* or Yxy space to be used.<br>
+<br>
+A profile is allowed to contain more than the minimum number of
+elements or table needed to<br>
+describe a certain transform, and may contain redundant descriptions.
+&nbsp;By default, lut based<br>
+table information will be used first if present, followed by
+matrix/shaper information, and<br>
+only using monochrome information if it is all that is present. <b>-o
+r</b> reverses this order. <br>
+<br>
+Usually device values are processed and displayed using a normalized
+value range between 0.0 and 1.0<br>
+Sometimes other systems scale them to some other range (such as 100 or
+255) due to an underlying<br>
+binary representation. The <span style="font-weight: bold;">-s</span>
+flag lets you input and display such data in its normal range. For
+instance,<br>
+if your device values have a range between 0 and 255, use <span
+ style="font-weight: bold;">-s 255.</span><br>
+<h3>Usage Details and Discussion</h3>
+Typical usage for an output profile might be:<br>
+<br>
+&nbsp;&nbsp;&nbsp; icclu -ff -ip profile.icm<br>
+<br>
+Normally the program is interactive, allowing the user to type in input
+color values, each number separated by a space, and the resulting
+output
+color being looked up and displayed after pressing return. To batch
+process
+a group of color values, prepare a text file containing each input
+value on
+a separate line, and use the input indirection facilities of your
+command
+line shell to redirect this input file into the standard input of
+icclu.
+The output can be captured to a file by redirecting standard output to
+a file. In most shells this would be done something like this:<br>
+<br>
+&nbsp;&nbsp;&nbsp; icclu -ff -ip profile.icm &lt; inputvalues.txt &gt;
+outputvalues.txt<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/illumread.html b/doc/illumread.html
new file mode 100644
index 0000000..03b5648
--- /dev/null
+++ b/doc/illumread.html
@@ -0,0 +1,319 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>illumread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/illumread</b></h2>
+ <h3>Summary</h3>
+ Use an instrument or instruments to measure an illuminant spectrum,
+ including estimate
+ its Ultra Violet content. A combination of direct illumination
+ readings
+ and readings from a piece of paper having some FWA content are used
+ for
+ this. (If the UV content is not needed, or a suitable instrument is
+ not
+ available, then <a href="spotread.html">spotread</a> should be used
+ instead.)<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">illumread [-options]
+ illuminant.sp</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; &nbsp; Verbose mode</span><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;"></span></small><br style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#S">-S</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; &nbsp; Plot
+ the readings in a graph window.</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c comport</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set
+ COM port, 1..4
+ (default 1)</span><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span></small><small><span style="font-family:
+ monospace;"></span></small><font size="-1"><span
+ style="font-family: monospace;"></span></font><font size="-1"><span
+ style="font-family: monospace;"><br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Disable
+ initial calibration of instrument</span></font> if possible<br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#H">-H</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Use high resolution spectrum mode (if
+ available)<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+ serial port flow control: n = none, h = HW, x = Xon/Xoff</span></font><br>
+ <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D [level]</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Print
+ debug diagnostics to stderr</span></small><br>
+ &nbsp;
+ <font size="-1"><span style="font-family: monospace;"><a
+ href="#file"><span style="font-style: italic;">illuminant.sp</span></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+File
+ to save measurement to<br style="font-family: monospace;">
+ </span></font><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><br>
+ <h3>Usage Details and Discussion</h3>
+ <b>illumread</b> uses a suitable instrument to read an illuminant
+ spectrum, and uses an indirect method to estimate the Ultra Violet
+ content of the illuminant, so as to provide better accuracy with <a
+ href="FWA.html">FWA
+ compensation</a>. An instrument or combination of instruments
+ capable
+ of spectral measurement of both
+ emissive measurement and reflective measurement without a U.V.
+ filter
+ is required for this.<br>
+ <br>
+ <a name="v"></a>The <b>-v</b> flag causes extra information to be
+ printed out during
+ chartread operation.<br>
+ <br>
+ <a name="S"></a>The <b>-S</b> flag enables the plotting of the
+ spectral
+ reflectance/transmittance values. You must select the plot window
+ and
+ strike a key
+ in it to continue with another measurement.<br>
+ <br>
+ <a name="c"></a> The instrument is assumed to communicate through a
+ USB or serial communication port, and the initial port can be
+ selected
+ with the
+ <b>-c</b>
+ option,
+ if the instrument is not connected to the first port. If you invoke
+ <span style="font-weight: bold;">illumread</span>
+ so as to display the usage
+ information (i.e. "illumread -?" or "illumread --"), then the
+ discovered
+ USB and serial ports will be listed. On
+ UNIX/Linux, a list of all possible serial ports are shown, but not
+ all
+ of them may
+ actually be present on your system.<br>
+ <br>
+ <a name="N"></a><span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option
+ turns on high resolution spectral mode, if the instrument supports
+ it.
+ See <a href="instruments.html">Operation of particular instruments</a>
+ for more details.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications
+ flow control setting. The value <span style="font-weight: bold;">n</span>
+ turns all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications
+ and other instrument diagnostics to be printed to stdout. A level
+ can
+ be set between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking
+ down why an instrument can't connect.<br>
+ <br>
+ <a name="file"></a>The <span style="font-weight: bold; font-style:
+ italic;">illuminant.sp</span> is
+ the name of the file to save the resulting illuminant spectrum to.
+ The
+ format used is <a href="File_Formats.html#.sp">.sp</a>.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ Unlike the other measurement utilities, <span style="font-weight:
+ bold;">illumread</span> doesn't connect to the
+ instrument until it is about to make a measurement. This allows for
+ the
+ possibility of using a different instrument for each measurement.<br>
+ <br>
+ It will display a menu:<br>
+ <br>
+ Press 1 .. 6<br>
+ 1) Measure direct illuminant<br>
+ 2) Measure illuminant reflected from paper<br>
+ 3) Measure paper<br>
+ 4) Select another instrument, Currently 1 'usb:/bus4/dev2/
+ (GretagMacbeth i1 Pro)'<br>
+ 5) Compute illuminant spectrum, average result with 0 previous
+ readings
+ &amp; save it<br>
+ 6) Compute illuminant spectrum from this reading &amp; save result<br>
+ 7) Exit<br>
+ <br>
+ There are three measurements to be made, after which the illuminant
+ can
+ be computed and saved. Before each measurement, the instrument may
+ need
+ calibrating.<br>
+ <br>
+ The first measurement needs a spectral instrument capable of reading
+ in
+ an ambient or emissive mode. For instance, a Spectrolino, Eye-One
+ Pro
+ or ColorMunki would be suitable instruments.<br>
+ <br>
+ The second measurement needs a spectral instrument capable of
+ reading
+ in an projector or emissive mode. For instance, a Spectrolino,
+ Eye-One
+ Pro or ColorMunki would be suitable instruments.<br>
+ <br>
+ The third measurement needs a spectral instrument capable of reading
+ in
+ reflective mode with UV included. For instance, a Spectrolino,
+ Eye-One
+ Pro, DTP20, DTP22 or&nbsp; DTP41 would be suitable instruments, as
+ long
+ as they are not fitted with UV filters.<br>
+ <br>
+ To be able to estimate the level of Ultra Violet (UV) light in the
+ illuminant, a reasonable sized piece of white paper needs to be
+ used.
+ The paper should have some noticeable level of FWA (Fluorescent
+ Whitener Additive, or Optical Brightening Agents) in it, so that it
+ responds to UV light. A piece of cheap copier paper is ideal, since
+ cheap paper is typically whitened with large amounts of FWA. If the
+ paper is thin (less than 160 gsm) then two or three sheets should be
+ used to prevent any background showing through. [If the intention is
+ to
+ use the illuminant spectrum for proofing to a particular paper, then
+ an
+ alternative might be to use a piece of the intended paper for this
+ purpose. It's unclear which may give a better result.]<br>
+ <br>
+ The first measurement <span style="font-weight: bold;">1)</span>,
+ is
+ to use either the ambient or emissive measurement mode to measure
+ the
+ illumination directly.<br>
+ <br>
+ <div style="margin-left: 40px;">If the instrument supports an
+ ambient
+ measurement capability, then it will be used. If the insrument
+ does not
+ have an ambient mode, then an emissive measurement mode can be
+ used,
+ although typically many illuminants are too bright to directly
+ point
+ the instrument at. A work-around is to reflect the illuminant from
+ a
+ spectrally flat white surface. A good candidate for this is a
+ piece of
+ white, fine textured polystyrene foam. [The suitability of a
+ reflector
+ can be checked using <span style="font-weight: bold;">spotread -S</span>
+ to check that the reflection characteristic is close to flat.]<br>
+ <br>
+ <img style="width: 228px; height: 300px;" alt="Measuring Ambient"
+ src="illumread_1.jpg"><img style="width: 141px; height: 282px;"
+ alt="Measuring Ambient" src="illumread_2.jpg">&nbsp; <img
+ style="width: 226px; height: 282px;" alt="Measuring Ambient"
+ src="illumread_3.jpg"><br>
+ </div>
+ <br>
+ The second measurement <span style="font-weight: bold;">2)</span>,
+ is
+ to measure the illuminant after it has reflected from the paper.<br>
+ <br>
+ <div style="margin-left: 40px;">This is done by placing the paper
+ such
+ that it is uniformly illuminated with reasonable brightness, and
+ then
+ placing the instrument so that it receives the reflected light
+ from the
+ paper. This is typically achieved by placing the instrument close
+ to
+ the paper at about 45&ordm;, so that it's aperture has a clear
+ view of
+ the illuminated paper, but avoiding shadowing the region that is
+ in
+ view. <br>
+ <br>
+ <img style="width: 219px; height: 261px;" alt="Measuring via
+ Paper" src="illumread_5.jpg"><img style="width: 252px; height:
+ 259px;" alt="Measuring via Paper" src="illumread_4.jpg"><br>
+ </div>
+ <br>
+ The third measurement <span style="font-weight: bold;">3)</span>,
+ is
+ to measure the paper directly using the instrument reflective mode
+ measurement.<br>
+ <div style="margin-left: 40px;"><img style="width: 186px; height:
+ 162px;" alt="Measuring Paper" src="illumread_6.jpg"><br>
+ </div>
+ If a different instrument is needed, use <span style="font-weight:
+ bold;">4)</span> to select from the available
+ instruments attached to your computer.<br>
+ <br>
+ Once these three measurements have been made, then the illuminant
+ readings spectrum
+ can be computed and save using <span style="font-weight: bold;">6)</span>,
+ or a series of readings can be made with each reading being averages
+ with the previous readings before saving it by using <span
+ style="font-weight: bold;">5)</span>. Note that the averaged
+ readings
+ will be weighted by their absolute intensities, and that while the
+ direct and indirect illumination needs measuring for each reading,
+ the
+ same paper measurement can be used each time.<br>
+ <br>
+ If plotting is enabled, a plot of the
+ measured (black) and with estimated UV (red) is plotted. This is
+ followed by a plot showing measured paper reflectance (black) and
+ the
+ FWA calculated paper reflectance (red).<br>
+ <br>
+ <br>
+ Illumread can then be terminated using <span style="font-weight:
+ bold;">7)</span>.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/illumread_1.jpg b/doc/illumread_1.jpg
new file mode 100644
index 0000000..97b5382
--- /dev/null
+++ b/doc/illumread_1.jpg
Binary files differ
diff --git a/doc/illumread_2.jpg b/doc/illumread_2.jpg
new file mode 100644
index 0000000..6fef757
--- /dev/null
+++ b/doc/illumread_2.jpg
Binary files differ
diff --git a/doc/illumread_3.jpg b/doc/illumread_3.jpg
new file mode 100644
index 0000000..fcab321
--- /dev/null
+++ b/doc/illumread_3.jpg
Binary files differ
diff --git a/doc/illumread_4.jpg b/doc/illumread_4.jpg
new file mode 100644
index 0000000..6c955c0
--- /dev/null
+++ b/doc/illumread_4.jpg
Binary files differ
diff --git a/doc/illumread_5.jpg b/doc/illumread_5.jpg
new file mode 100644
index 0000000..5462e8f
--- /dev/null
+++ b/doc/illumread_5.jpg
Binary files differ
diff --git a/doc/illumread_6.jpg b/doc/illumread_6.jpg
new file mode 100644
index 0000000..a91a63e
--- /dev/null
+++ b/doc/illumread_6.jpg
Binary files differ
diff --git a/doc/instruments.html b/doc/instruments.html
new file mode 100644
index 0000000..896c0e5
--- /dev/null
+++ b/doc/instruments.html
@@ -0,0 +1,2214 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Operation of particular instruments</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ </head>
+ <body>
+ <h2><u>Operation of particular instruments</u></h2>
+ <span style="font-weight: bold;">Please note that instruments are
+ being driven by ArgyllCMS drivers, and that any problems or
+ queries regarding instrument<br>
+ operation </span><span style="font-weight: bold;">should be
+ directed to the Argyll's author(s) or the Argyll mailing list, and
+ not to any</span> <span style="font-weight: bold;">other party.</span><span
+ style="font-weight: bold;"></span><br>
+ <br>
+ The following instruments are directly supported:<br>
+ (Please <span style="font-weight: bold;">note</span> the <a
+ href="Installing.html">installation instructions</a> for each
+ platform - they contain important information for getting your
+ instruments working.)<br>
+ <br>
+ X-Rite:<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP20">DTP20 "Pulse"</a>&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - "swipe" type reflective spectrometer, that can be used untethered.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP22">DTP22 Digital Swatchbook</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot type reflective spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP41">DTP41</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot and strip reading reflective spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP41">DTP41T</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - spot and strip reading reflective/transmissive spectrometer.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#dtp51">DTP51</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - strip reading reflective colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP92">DTP92</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - CRT display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#DTP94">DTP94</a> <font size="-1">"Optix
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ XR"</font> or "Optix XR2" or "Optix Pro"- display colorimeter.<br>
+ <a href="#ColorMunki"><span style="text-decoration: underline;"></span></a>&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <a href="#ColorMunki"><span style="text-decoration: underline;">ColorMunki</span></a>
+ Design or Photo&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - spot and "swipe"
+ reflective/emissive spectrometer (UV cut only).<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d"><span style="text-decoration:
+ underline;">ColorMunki</span></a> Create or Smile&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter. (Similar to an Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#Huey">Lenovo W</a> &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - built in laptop
+ Huey display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d3">Eye-One Display 3</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; - i1 DisplayPro and ColorMunki Display<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ The OEM
+ i1Display Pro and<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ NEC SpectraSensor Pro are also reported to work.]<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1p2">Eye-One Pro2</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp; - spot and
+ "swipe" reflective/emissive spectrometer.<br>
+ <br>
+ Gretag-Macbeth (now X-Rite):<br>
+ &nbsp; &nbsp; <a href="#sl">Spectrolino</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive
+ spectrometer<br>
+ &nbsp; &nbsp; <a href="#ss">SpectroScan</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot reflective/emissive, XY table
+ reflective spectrometer&nbsp; <br>
+ &nbsp; &nbsp; <a href="#ss">SpectroScanT</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; - spot reflective/emissive/transmissive, XY
+ table reflective spectrometer<br>
+ &nbsp; &nbsp; <a href="#i1p">Eye-One Pro</a> "EFI ES-1000" &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" reflective/emissive
+ spectrometer<br>
+ &nbsp; &nbsp; <a href="instruments.html#i1m">Eye-One Monitor</a>
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; - spot and "swipe" emissive spectrometer<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d">Eye-One Display 1 or 2&nbsp; or
+ LT</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display
+ colorimeter<br>
+ &nbsp;&nbsp;&nbsp; <a href="instruments.html#i1d">HP DreamColor or
+ APS</a>&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#i1d">CalMAN X2</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. (Treated as a Eye-One Display 2)<br>
+ &nbsp;&nbsp;&nbsp; <a href="#Huey">Huey</a> &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter<br>
+ <br>
+ Sequel imaging (Now X-Rite):<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#mox">MonacoOPTIX</a> &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Treated
+ as an Eye-One Display 1)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [The Sequel Chroma 4 may also work.]<br>
+ <br>
+ Lacie Blue
+ Eye:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - see <a href="#i1d">Eye-One Display</a><br>
+ <br>
+ DataColor ColorVision:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd2">Spyder 2</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> firmware)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [The Spyder 1 also seems to work.]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd3">Spyder 3</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp; <a href="#spyd4">Spyder 4</a> &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - display colorimeter (Note
+ that the user must <a href="oeminst.html">supply</a> calibration
+ data)<br>
+ <br>
+ Other:<br>
+ &nbsp;&nbsp;&nbsp; <span class="titre"><a href="#HCFR">Colorim&egrave;tre
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HCFR</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter<br>
+ </span>&nbsp;&nbsp;&nbsp;
+ ColorHug&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+ - display colorimeter. Experimental only, does not work on all
+ platforms.<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+ Set environmental variable ENABLE_COLORHUG=true to test it.<span
+ class="titre"><br>
+ </span><br>
+ Other instruments can be supported indirectly, since patch result
+ files created by other packages can be imported into Argyll.<br>
+ <span class="titre"><br>
+ General information about:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <a href="#strip">Strip reading instruments</a><br>
+ </span>&nbsp;&nbsp;&nbsp; <a href="#xy">X-Y Table instruments</a><br>
+ &nbsp;&nbsp;&nbsp; <a href="#spot">Spot reading instruments</a><br>
+ <span style="font-weight: bold;"></span><br>
+ <br>
+ There is a <a href="ccmxs.html">list of contributed</a> <span
+ style="font-weight: bold;">ccmx</span> (Colorimeter Correction
+ Matrix) files.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="strip"></a>Strip reading instruments</h3>
+ When used with a <span style="font-weight: bold;">DT20</span>, <span
+ style="font-weight: bold;">DTP41</span>, <span
+ style="font-weight: bold;">DTP51</span>, <span
+ style="font-weight: bold;">Eye-One Pro<span style="font-weight:
+ bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
+ strip reading instrument, chartread will first establish
+ communications with the instrument, and then set it up ready to read
+ the strips. The strips are labeled A to ZZ, and for each strip it
+ will prompt:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; About to read strip XX&nbsp; :<br>
+ <br>
+ where XX is the strip label, and this is followed by the available
+ options to navigate, read the strip, or finish. Note that the normal
+ (forward) direction of strip reading is one that starts at the strip
+ label.<br>
+ <br>
+ For the <span style="font-weight: bold;">DTP51</span> you should
+ feed the strip into the instrument, and the microswitch will trigger
+ the read.<br>
+ <br>
+ For the <span style="font-weight: bold;">DTP41</span> you should
+ line the appropriate strip up in the machine, and press its button.<br>
+ <br>
+ For the <span style="font-weight: bold;">Eye-One Pro</span> you
+ should set the guide to the appropriate strip, place the instrument
+ <span style="text-decoration: underline;">ahead</span> of the first
+ patch on blank paper, and then press and hold the instruments
+ button. When you hear a beep from the computer, you can then move
+ the instrument steadily over the patches, releasing the button after
+ the instrument is past the last patch. Moving the instrument too
+ fast or changing speeds may cause a mis-read, or a scan with few
+ samples read per patch.<br>
+ <br>
+ For the <span style="font-weight: bold;">ColorMunki</span> with the
+ default chart, the patches are the same width as the silver portion
+ of body (white version), or the textured portion of the body (black
+ version). Place aperture of the the instrument (located at its
+ center) in the white space ahead of the first patch, and then press
+ and hold the instruments button. When you hear a beep from the
+ computer, you can then move the instrument steadily over the
+ patches, releasing the button after the instrument is past the last
+ patch. Moving the instrument too fast or changing speeds may cause a
+ mis-read, or a scan with few samples read per patch. For the <span
+ style="font-weight: bold;">high density</span> ColorMunki chart (<a
+ href="printtarg.html#h">printtarg -h</a>), the patches are
+ arranged so that three rows are exactly the width of the&nbsp; body
+ of the instrument. If you are careful you can use this to guide the
+ center of the instrument over each row, or you may prefer to use
+ something like a plastic ruler to help guide the instrument.<br>
+ <br>
+ Using the <span style="font-weight: bold;">DTP20</span> or the <span
+ style="font-weight: bold;">Eye-One Pro</span> or <span
+ style="font-weight: bold;">ColorMunki</span> with a randomized
+ chart layout, the strip may be scanned from either direction. If a
+ randomized chart layout has not been used for the <span
+ style="font-weight: bold;">Eye-One Pro</span> or <span
+ style="font-weight: bold;">ColorMunki</span>, then the chart
+ should only be read in the one direction (use <a
+ href="chartread.html#B">chartread -B</a>).<br>
+ <br>
+ Note that you may have to check that system alert sounds are enabled
+ and at a suitable volume to in order to hear the beep prompt. For
+ the Eye-One Pro and ColorMunki, a second beep will sound after a
+ successfully read strip, or a double beep will sound,&nbsp;
+ indicating a failure or warning that needs attention. See also the
+ note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
+ <br>
+ If the strip is read successfully there will be a single "success"
+ beep, and the line will be followed with:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; : <br>
+ &nbsp;&nbsp;&nbsp; Strip read OK<br>
+ <br>
+ If there is an error of some sort there will be a double "fail"
+ beep, and a message will be issued, and you will be asked whether to
+ abort the chart reading, or retry the<br>
+ failed strip:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip XX&nbsp; : <br>
+ &nbsp;&nbsp;&nbsp; Strip read failed due to misread (Not enough
+ patches)<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
+ <br>
+ If you are unable to successfully read a strip after several
+ retries, you can skip that strip using the <span
+ style="font-weight: bold;">'n'</span> key, and save<br>
+ the chart readings without that strip.<br>
+ <br>
+ If the strip is read successfully, but the patches values don't seem
+ to be what is expected, you will get a double "fail" beep&nbsp; and
+ the following type of warning:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; (Warning) Seem to have read strip&nbsp; YY&nbsp;
+ rather than&nbsp; XX !<br>
+ &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
+ retry, Esc, ^C or Q to give up:<br>
+ <br>
+ This could be because you have accidentally read the wrong strip (a
+ common mistake), or it could be that the device response is so
+ different from what is expected that warning is erroneous, or you
+ may get a lot of these sorts of warnings if you are accidentally
+ reading the wrong chart. You may also get this sort of warning if
+ you are not using bi-direction reading (chartread -B), and read the
+ strip from the wrong end.<br>
+ If you are absolutely sure you lined up the correct strip, then hit
+ return, otherwise line the appropriate strip up again, and hit some
+ other key (ie. space).<br>
+ Erroneous warnings are less likely if a previous profile for a
+ device was given to <span style="font-weight: bold;">targen</span>
+ to set more accurate expectations.<br>
+ <br>
+ You may also see the following type of warning:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read strip&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; (Warning) Patch error YY.YYY (&gt;35 not good,
+ &gt;95 bad)<br>
+ &nbsp;&nbsp; There is at least one patch with an very unexpected
+ response!<br>
+ &nbsp;&nbsp;&nbsp; Hit Return to use it anyway, any other key to
+ retry, Esc, ^C or Q to give up:<br>
+ <br>
+ Similar to the previous warning, this indicates that while the right
+ strip appears to have been read, one of the patch readings is quite
+ different to what is expected. This may indicate an error of some
+ sort (ie. damaged test chart, or bad instrument positioning), or may
+ be erroneous if the actual device response is quite different to the
+ expectation. Erroneous warnings are less likely if a previous
+ profile for a device was given to <span style="font-weight: bold;">targen</span>
+ to set more accurate expectations.<br>
+ <br>
+ You can also navigate the next strip to be read using the <span
+ style="font-weight: bold;">'f'</span> key to move forward and the
+ <span style="font-weight: bold;">'b'</span> keys<span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
+ to move backwards. The prompt will indicate whether this strip has
+ already been read or not, or whether all strips have been read. You
+ can also use <span style="font-weight: bold;">'n'</span> to move
+ forward to the next unread strip. After each successful reading it
+ will move forward to the next unread strip. When you are finished,
+ use the <span style="font-weight: bold;">'d'</span> to indicate
+ that you are done. You can choose to finish before all the strips
+ are read, and the patches that have been read will be saved to the
+ .ti3 file. This is useful if you are unable to read a particular
+ strip successfully, or if you are unable to finish the chart in one
+ session, and you can later <span style="text-decoration:
+ underline;">resume</span> reading the chart by using the <span
+ style="font-weight: bold;">chartread -r</span> flag. [You could
+ resume reading the chart patch by patch using the <span
+ style="font-weight: bold;">chartread -r -p</span> if you are
+ unable to read a strip successfully.]<br>
+ <br>
+ When reading in patch by patch mode, there are a few additional
+ navigation options, such as <span style="font-weight: bold;"><span
+ style="font-weight: bold;">F</span></span> to move forward 10
+ patches, <span style="font-weight: bold;">B</span> to move
+ backwards 10 patches, and <span style="font-weight: bold;">g</span>
+ to go to a specific patch.<br>
+ <br>
+ You can abort the whole process at any time by hitting Escape, and
+ the readings will not be saved.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="xy"></a>X-Y Table instruments</h3>
+ When you are using an XY table type instrument, such as a Gretag <span
+ style="font-weight: bold;">SpectroScan</span>, &nbsp;chartread
+ will first establish communications with the instrument, and then
+ set it up ready to read the chart. You will be prompted for each
+ sheet with a message such as:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Please make sure that the white reference is in
+ slot 1, then<br>
+ &nbsp;&nbsp;&nbsp; place sheet 1 of 4 on table, then<br>
+ &nbsp;&nbsp;&nbsp; hit return to continue, Esc to give up<br>
+ <br>
+ After hitting return you will be prompted to line up three squares
+ on the sheet, one at a time:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Using the XY table controls, locate patch A1 with
+ the sight,<br>
+ &nbsp;&nbsp;&nbsp; then hit return to continue, Esc to give up<br>
+ <br>
+ On completing this, the instrument will commence reading each sheet.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="spot"></a>Spot reading instruments</h3>
+ When used with a <span style="font-weight: bold;">DT22</span> or <span
+ style="font-weight: bold;">SpectroLino</span> or use the patch by
+ patch reading mode (<span style="font-weight: bold;">chartread -p</span>)
+ with the <span style="font-weight: bold;"></span> <span
+ style="font-weight: bold;">Eye-One Pro<span style="font-weight:
+ bold;"> </span></span>or <span style="font-weight: bold;">ColorMunki</span>
+ instrument, or use the external values mode (<span
+ style="font-weight: bold;">chartread -x</span>), chartread will
+ first establish communications with the instrument, and then set it
+ up ready to read the patches. The patches are typically labeled by
+ column A to ZZ, and row 1-999. Each patch will prompt:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch 'XX'&nbsp; :<br>
+ <br>
+ where XX is the patch label, and this is followed by the available
+ options to navigate, read the strip, or finish.<br>
+ <br>
+ Place the instrument on the indicated patch, and trigger a reading
+ using one of the available methods (typically using the instrument
+ switch of pressing a key).<br>
+ <br>
+ There should be an audible prompt on a successful or failed reading.
+ <br>
+ <br>
+ Note that you may have to check that system alert sounds are enabled
+ and at a suitable volume to in order to hear the beep prompt. For
+ the Eye-One Pro and ColorMunki, a second beep will sound after a
+ successfully read strip, or a double beep will sound,&nbsp;
+ indicating a failure or warning that needs attention. See also the
+ note on Linux in <a href="Installing_Linux.html">installation</a>.<br>
+ <br>
+ If the patch is read successfully, the line will be completed with:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch&nbsp; XX&nbsp; :<br>
+ &nbsp;&nbsp;&nbsp; Patch read OK<br>
+ <br>
+ If there is an error of some sort, a message will be issued, and you
+ will be asked whether to abort the chart reading, or retry the<br>
+ failed patch:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Ready to read patch XX&nbsp; : read_strip
+ returned 'Strip misread' (Bad reading)<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; Strip read failed due to misread<br>
+ &nbsp;&nbsp;&nbsp; Hit Esc to give up, any other key to retry:<br>
+ <br>
+ You can navigate the next patch to be read using the <span
+ style="font-weight: bold;">'f'</span> key to move forward and the
+ <span style="font-weight: bold;">'b'</span> keys<span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span>
+ to move backwards, while <span style="font-weight: bold;">'F'</span>
+ and <span style="font-weight: bold;">'B'</span> will move forward
+ and backwards by 10 patches. The prompt will indicate whether this
+ patch has already been read or not, or whether all patches have been
+ read. You can also use <span style="font-weight: bold;">'n'</span>
+ to move forward to the next unread patch. When you are finished, use
+ the <span style="font-weight: bold;">'d'</span> to indicate that
+ you are done. You can choose to finish before all the patches are
+ read, and they will be saved to the .ti3 file. This is useful if you
+ are unable to finish the chart in one session, and you can later <span
+ style="text-decoration: underline;">resume</span> reading the
+ chart by using the <span style="font-weight: bold;">chartread -r</span>
+ flag.<br>
+ <br>
+ You can abort the whole process at any time by hitting Escape, and
+ the readings will not be saved.<br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <hr style="width: 100%; height: 2px;">
+ <h3><a name="displaytype"></a>Display Type<br>
+ </h3>
+ Many of the colorimeters have a <span style="font-weight: bold;">display
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ type</span> selection parameter. Depending on the instrument, this
+ may combine two related functions: 1) Changing the measurement mode
+ to suite either refresh-type, or non-refresh displays, and 2)
+ Changing the calibration to suite a particular displays spectral
+ characteristics.<br>
+ <br>
+ A refresh type display uses a technology that presents different
+ portions of the image at different times, doing so at a high enough
+ rate that this is normally imperceptible. This time varying
+ characteristic can interfere with measuring a display color unless
+ the instrument makes allowances for it, typically by making its
+ measurement period a multiple of the display refresh period. Display
+ types that <span style="font-weight: bold;">refresh</span> are CRT
+ (Cathode Ray Tube), Single chip DLP (Digital Light Processing) and
+ Plasma displays. An example of a <span style="font-weight: bold;">non-refresh</span>
+ display technology is LCD (Liquid Crystal Display), although is a
+ few cases the back-light illumination may have a low enough
+ frequency flicker to benefit from the refresh mode.<br>
+ <br>
+ Instruments in which the display type selection only changes the
+ measurement mode (i.e. i1d3), will typically have some other
+ independent option to set the calibration type. Simpler instruments
+ combine the measurement mode with a calibration selections,
+ typically refresh+CRT and non-refresh+LCD. Some instruments are a
+ hybrid of both (Spyder4), where the display type can select between
+ generic refresh/non-refresh that can then use a .CCSS to set the
+ calibration type, or a combined selection of non-refresh and a
+ particular display type.<br>
+ <br>
+ See <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology">Comparison_of_display_technology</a>
+ for some background on different display technologies.<br>
+ <br>
+ <hr size="2" width="100%"><br>
+ <h3><a name="refreshmeasurement"></a>Refresh Rate Measurement</h3>
+ <p>Most of the colorimeters that have a refresh display type
+ selection, also have an ability to measure the refresh rate of a
+ display. Some of the spectrometers also have a display refresh
+ rate measurement capability when in an emissive measurement mode,
+ even though they don't use this to support a refresh display mode.
+ You can do a display refresh rate measurement in <a
+ href="spotread.html">spotread</a> using the <b>'F' </b>key.
+ The particular instruments have a range of accuracy when making
+ this measurement. A rough guide is as follows:<br>
+ <br>
+ </p>
+ <table border="1" cellpadding="2" cellspacing="2" height="230"
+ width="372">
+ <tbody>
+ <tr>
+ <td valign="top"><b>Instrument</b></td>
+ <td valign="top"><b>Typical error in Hz.</b></td>
+ </tr>
+ <tr>
+ <td valign="top">DTP92<br>
+ </td>
+ <td valign="top">0.1<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Display 2<br>
+ </td>
+ <td valign="top">0.5<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 2<br>
+ </td>
+ <td valign="top">0.7<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 3<br>
+ </td>
+ <td valign="top">3<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">Spyder 4<br>
+ </td>
+ <td valign="top">3<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Display Pro<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">i1 Pro Spectro.<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">ColorMunki Spectro.<br>
+ </td>
+ <td valign="top">0.05<br>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <p><br>
+ </p>
+ <hr style="width: 100%; height: 8px;"><br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><a name="ColorMunki"></a><span
+ style="font-weight: bold;">ColorMunki </span>Design or Photo <span
+ style="font-weight: bold;">reflective/emissive spectrometer</span><br>
+ <br>
+ <img style="width: 272px; height: 243px;" alt="" title="ColorMunki
+ (White)" src="ColorMunki.jpg">&nbsp;&nbsp; <br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">ColorMunki</span> <span
+ style="font-weight: bold;">Design or Photo </span>from <a
+ href="http://www.xrite.com/">X-Rite</a>&nbsp; is currently
+ available in two different packages from the manufacturer. These
+ packages differ in what features the manufacturers software
+ provides, as well as cosmetic differences between the instrument
+ (white and black). This comparison <a
+ href="http://www.colormunki.com/product/show?page=2">chart</a>
+ illustrates the differences. Used with Argyll, there are no
+ differences in operation of a ColorMunki instrument, irrespective of
+ which package it came with. The ColorMunki Design has the lowest
+ RRP, but the Photo package may be cheaper with discounting .<br>
+ <br>
+ <span style="font-weight: bold;">Limitations &amp; Features:</span><br>
+ <br>
+ Unlike the Eye-One Pro, the ColorMunki is only available in a U.V.
+ Cut (ie. "Ultra Violet filtered") model. This means that it is not
+ suitable for use with the&nbsp; Fluorescent Whitener Additive
+ Compensation option in Argyll (see <a href="FWA.html">here</a> for
+ a discussion about what FWA compensation is).<br>
+ <br>
+ Like the Eye-One Pro, this instrument does support the <a
+ href="spotread.html#H">high resolution</a> spectral mode.<br>
+ <br>
+ <span style="font-weight: bold;">OS X and X-Rite drivers</span><br>
+ <br>
+ Please note the installation <a
+ href="Installing_OSX.html#ColorMunki">instructions</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Tips &amp; Tricks:<br>
+ <br>
+ </span>In handling the instrument when about to make a reading, be
+ very careful not to accidentally press the switch - it is large and
+ easily pressed by accident. A guide of some sort (ie. a plastic
+ ruler) can help a lot in&nbsp; keeping the instrument over a line
+ of&nbsp; patches. <br>
+ <br>
+ <span style="font-weight: bold;">Patch recognition:</span><br>
+ <br>
+ For the best chances of good patch recognition, the instrument
+ should be drawn smoothly and not too rapidly over the strip. (This
+ can be a little tricky due to the two small rubber feet on the
+ bottom of the device that aid its spot reading guide.) If there is a
+ misread, try slowing down slightly. Generally a higher quality set
+ of readings will result if slower scans are used, since there will
+ then be more samples averaged for each patch. <br>
+ <br>
+ In <a href="chartread.html">chartread</a>, the -<span
+ style="font-weight: bold;">T ratio</span> argument modifies the
+ patch consistency tolerance threshold for the ColorMunki. In
+ recognizing patches in a strip, the instrument takes multiple
+ readings as the strip is read, and then divide the readings up into
+ each patch. It then check the consistency of the multiple readings
+ corresponding to each patch, and reject the measurement if they are
+ too inconsistent. For some media (ie. a coarser screens, fabric
+ etc.) the default tolerance may be unreasonably tight, so the <span
+ style="font-weight: bold;">-T ratio</span> argument can be used to
+ modify this criteria. To loosen the tolerance, use a number greater
+ than 1.0 (ie. 1.5, 2.0). <br>
+ <br>
+ Note that <a href="printtarg.html">printtarg</a> provides the <a
+ href="printtarg.html#h">-h</a> option that allows the choice of
+ two different patch row widths with ColorMunki test charts. [Some
+ people have successfully used the i1Pro patch layout with the
+ ColorMunki, by making a guide to keep it over the much narrower
+ patchs.]<br>
+ <br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP20"></a></span><span style="font-weight: bold;">DTP20
+ "Pulse" reflective spectrometer<br>
+ <br>
+ </span><span style="font-weight: bold;"><img title="DTP20" alt=""
+ src="DTP20.jpg" style="width: 304px; height: 210px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP20</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> was discontinued during
+ 2007, but may still be available from old stock or second hand. <br>
+ <br>
+ <span style="font-weight: bold;">Special features:</span><br>
+ <br>
+ The <span style="font-weight: bold;">DTP20</span> has a couple of
+ unique features that Argyll can take advantage of. One is that it
+ can operate un-tethered (off line). A whole chart can be read
+ un-tethered by first clearing any previous readings in the
+ instrument, then reading the chart TID strip, before reading all the
+ other strips. The instrument can then be connected up to <span
+ style="font-weight: bold;">chartread</span>, which will recognize
+ the chart, and download all the measurements.<br>
+ If there is no chart in the instrument when chartread connects to
+ it, then it will use the strip by strip tethered mode, just like the
+ other strip instruments. If the right number of spot readings are
+ present in the instrument, these will be used by <span
+ style="font-weight: bold;">chartread</span> too.<br>
+ <br>
+ Un-tethered spot measurements can also be read in using&nbsp; <span
+ style="font-weight: bold;">spotread</span>, which will notice the
+ stored readings, and offer to print them out, or they can be
+ ignored, and tethered readings taken. This will clear any saved spot
+ readings.<br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that tethered (on-line)
+ strip reading will only work if the firmware in the device is
+ version 1.03 or greater. You can check the firmware version by
+ running with the verbose option: <span style="font-weight: bold;">-v<br>
+ <br>
+ Chart printing:<br>
+ <span style="font-weight: bold;"><br>
+ </span></span>Because the DTP20 measures exact distances using the
+ markings on its ruler, it's critical that the chart be printed out
+ exactly the right size. If the chart gets re-sized at all in the
+ process of printing it, the DTP20 is likely to fail in reading it.
+ If you have a problem with this, you might want to increase the page
+ margins using the <span style="font-weight: bold;">printtarg -m</span>
+ parameter, or find a printing path that preserves the test chart
+ size correctly.<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;">Operation:<br>
+ <br>
+ </span>When reading in tethered (on-line) mode, that the instrument
+ takes <span style="font-weight: bold;">several seconds</span> to
+ download the measurements after each strip, and that the indicator
+ will be in "rainbow" mode while this occurs. <span
+ style="text-decoration: underline;">Wait</span> until the
+ indicator turns solid green again before starting to measure the
+ next strip.<br>
+ <br>
+ To <span style="font-weight: bold;">reset</span> the instrument and
+ clear any stored readings: press the button three times in quick
+ succession. The indicator will turn solid blue. Then hold the button
+ down until the instrument beeps and the indicator goes out. Release
+ the button and the indicator should flash then return to solid green
+ (ready).<br>
+ <br>
+ To <span style="font-weight: bold;">calibrate</span> the
+ instrument, place it on its calibration tile, then press the button
+ three times in quick succession.The indicator will turn solid blue.
+ Click the button another three times in quick succession, and the
+ indicator should turn yellow. Then hold the button down until the
+ instrument beeps and the indicator goes out. Release the button and
+ the instrument should flash and then turn solid green.<br>
+ <br>
+ If the chart is particularly <span style="font-weight: bold;">small</span>,
+ the patches may end up printed very close to the edge of the chart,
+ and therefore it may be difficult to confine your scan to the chart,
+ and passing<br>
+ the instrument over the edge of the chart may prevent it reading
+ successfully. One way of working around this is to place the chart
+ on a larger piece of paper of the same type.<br>
+ <br>
+ The <span style="font-weight: bold;">speed</span> of scan can be
+ quite critical with this instrument. In particular, it doesn't work
+ very well if the scan is too <span style="font-weight: bold;">slow</span>.
+ You don't want to go too fast either, as this reduces the number of
+ samples per patch.<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><span
+ style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP22"></a></span><span style="font-weight: bold;">DTP22
+ Digital Swatchbook reflective spectrometer</span><br>
+ <span style="font-weight: bold;"><br>
+ <img alt="" src="DTP22.jpg" style="width: 222px; height: 193px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP22</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. It is
+ capable of reading colored patches one at a time.<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP41"></a>DTP41 reflective, DTP41T
+ reflective/transmissive spectrometers<br>
+ <br>
+ <img alt="" src="DTP41.jpg" style="width: 263px; height: 298px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP41</span> and <span
+ style="font-weight: bold;">DTP41T</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. <br>
+ <br>
+ The series II instruments (<span style="font-weight: bold;">DTP41B</span>
+ and <span style="font-weight: bold;">DTP41TB</span>) offer both
+ serial and USB connection. Note that currently only serial operation
+ using Argyll is possible with these instruments.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <a name="dtp51"></a><span style="font-weight: bold;">DTP51
+ reflective colorimeter<br>
+ <br>
+ <img alt="" src="DTP51.jpg" style="width: 263px; height: 223px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP51</span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. <br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"><br>
+ </span></span>The DTP51's switch is triggered by inserting a strip
+ into the slot.<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="DTP92"></a>DTP92 CRT display colorimeter<br>
+ <br>
+ <img alt="" src="DTP92.jpg" style="width: 223px; height: 180px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP92</span><span
+ style="font-weight: bold;"></span> from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument.&nbsp; It may still be available second hand. It will
+ only read CRT technology displays.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type [Default, CB2].<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="DTP94"></a>DTP94, </span><font
+ size="-1">"Optix XR"</font> or "Optix XR2" or "Optix Pro" <span
+ style="font-weight: bold;">display colorimetrers</span><br>
+ <span style="font-weight: bold;"><br>
+ <img title="DTP94" alt="" src="DTP94.jpg" style="width: 138px;
+ height: 171px;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; <img alt="" title="Optix XR/Pro" src="moxxr.jpg"
+ style="width: 155px; height: 190px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">DTP94 </span>from <a
+ href="http://www.xrite.com/">X-Rite</a> is a discontinued
+ instrument, although it is still being supplied to OEMs.&nbsp; It
+ may still be available as old stock, or second hand. It was sold as
+ an instrument without software as the DTP94, and packaged with
+ software from the manufacturer as the "Optix XR" range.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type [default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type [CB2].<br>
+ &nbsp;&nbsp;&nbsp; <b>g</b>&nbsp;&nbsp;&nbsp;
+ Generic&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Generic
+ display [CB3]<br>
+ &nbsp;&nbsp; <br>
+ <br>
+ <span style="font-weight: bold;"></span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="sl"></a>Spectrolino reflective/emissive spectrometer<br>
+ <br>
+ <img alt="" src="sl.jpg" style="width: 239px; height: 200px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spectrolino </span>from
+Gretag
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacBeth (Now X-Rite) is a discontinued instrument. It is often
+ available second hand. If buying it second hand, make sure it comes
+ with all it's accessories, including white reference, spot reading
+ adapter, display reading adapters, filters (UV, polarizing, D65),
+ serial cable adapter and power supply.<br>
+ <span style="font-weight: bold;"><br>
+ </span>
+ <hr style="width: 100%; height: 2px;"><span style="font-weight:
+ bold;"><br>
+ <a name="ss"></a>SpectroScan reflective/emissive and SpectroScanT
+ reflective/emissive/transmissive spectrometers<br>
+ <br>
+ <img style="width: 336px; height: 294px;" alt="" src="ss.jpg"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">SpectroScan</span> and
+ <span style="font-weight: bold;">SpectroScanT</span> from Gretag
+ MacBeth (Now X-Rite) is a discontinued instrument. It is the
+ combination of an X-Y table and the <span style="font-weight:
+ bold;">Spectrolino</span> instrument. The <span
+ style="font-weight: bold;">SpectroScanT</span> is capable of
+ measuring transparency. It is often available second hand. If buying
+ it second hand, make sure it comes with all it's accessories,
+ including white reference, spot reading adapter, display reading
+ adapters, filters (UV, polarizing, D65) and power supply.<br>
+ <br>
+ If measuring transparencies using a SpectroScanT, the <b>Enter</b>
+ key on the instrument may be used to trigger each reading. It will
+ be recognized after each previous reading has been completed.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <br>
+ <span style="font-weight: bold;"><a name="i1p2"></a>Eye-One Pro2:</span><br>
+ <img style=" width: 357px; height: 234px;" alt="Eye-One Pro 2"
+ src="i1pro2.jpg"><br>
+ <br>
+ There is support for some of the new features of the Eye-One Pro2
+ (also known as the Eye-One Pro Rev E), in particular the&nbsp; Rev E
+ measurement mode, spectrometer stray light reduction, wavelength
+ calibration, and improved black level tracking. This new support can
+ be disabled and an Eye-One Pro2 operated in legacy mode by setting
+ the environment variable ARGYLL_DISABLE_I1PRO2_DRIVER. See <a
+ href="file:///D:/src/argyll/doc/instruments.html#i1p">Eye-One Pro
+ reflective/emissive spectrometer</a><span style="font-weight:
+ bold;"> </span>below for details on the operation of this type of
+ instrument.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1p"></a>Eye-One Pro and
+ Eye-One Pro2 reflective/emissive spectrometer<br>
+ <br>
+ <img alt="" src="i1p.jpg" style="width: 347px; height: 234px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Eye-One Pro</span> from
+ <a href="http://www.xrite.com/">X-Rite</a> (was Gretag MacBeth) is
+ available in two packages from the manufacturer. These packages
+ differ partly in what accessories come with the instrument, but
+ primarily in what features the manufacturers software provides. This
+ comparison <a
+ href="http://www.xrite.com/product_overview.aspx?ID=812">chart</a>
+ illustrates the differences. Used with Argyll, there are no
+ differences in operation of an Eye-One Pro instrument, irrespective
+ of which package it came with. The lowest cost package is the <a
+ href="http://www.xrite.com/product_overview.aspx?ID=1461">i1 Basic
+ Pro</a>.<br>
+ <br>
+ The EFI ES-1000 (which is a re-badged Eye-One Pro) is also reported
+ to work with Argyll.<br>
+ <br>
+ Unless you know what you're doing, and have a very specific reason
+ to buy an instrument fitted with a UV (Ultra Violet) filter, make
+ sure that you buy an instrument without the filter. A UV filtered
+ instrument can't deal intelligently with FWA (Fluorescent Whitener
+ Additive) effects in paper. (Look <a href="FWA.html">here</a> for
+ more information about FWA compensation.) Using FWA compensation you
+ can make measurements using ISO 13655:2009 M0, M1 and M2 conditions.
+ The M2 condition emulates a UV cut instrument.<br>
+ <br>
+ There have been four revisions of the Eye-One Pro, Rev. A, B, D and
+ E (AKA Eye-One Pro2). The rev B, D and E are capable of sampling
+ twice as fast as the Rev. A version of the instrument, and are also
+ available with an ambient light reading capability.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> for those running on
+ older versions of Linux with a Rev. D, there was a problem with the
+ Linux USB stack that causes the instrument to stop working once it
+ has been used. The only workaround is to unplug and replug the
+ instrument in again, whereupon it can be used one time again. A fix
+ for this problem was in the&nbsp; Linux 2.6.26 kernel release.<br>
+ <br>
+ See also <a href="i1proDriver.html">How can I have confidence in
+ the i1pro Driver ?</a><br>
+ <br>
+ <span style="font-weight: bold;">Patch recognition:</span><br>
+ <br>
+ For the best chances of good patch recognition, the instrument
+ should be drawn smoothly and not too rapidly over the strip. If
+ there is a misread, try slowing down slightly. The Rev A and B.
+ instruments have a slower sampling rate than the latter revision
+ instruments, and hence must be used a bit more slowly. Generally a
+ higher quality set of readings will result if slower scans are used,
+ since there will then be more samples averaged for each patch.<br>
+ <br>
+ In <a href="chartread.html">chartread</a>, the -<span
+ style="font-weight: bold;">T ratio</span> argument modifies the
+ patch consistency tolerance threshold for the Eye-One Pro. In
+ recognizing patches in a strip, the instrument takes multiple
+ readings as the strip is read, and then divide the readings up into
+ each patch. It then check the consistency of the multiple readings
+ corresponding to each patch, and reject the measurement if they are
+ too inconsistent. For some media (ie. a coarser screens, fabric
+ etc.) the default tolerance may be unreasonably tight, so the <span
+ style="font-weight: bold;">-T ratio</span> argument can be used to
+ modify this criteria. To loosen the tolerance, use a number greater
+ than 1.0 (ie. 1.5, 2.0). <span style="font-weight: bold;"></span><br>
+ <br>
+ <span style="font-weight: bold;">Special features:</span><br>
+ <br>
+ A feature unique to Argyll when used with the Eye-One Pro, is the
+ high resolution spectral mode. This returns spectral measurements at
+ 3.333 nm spacing, rather than the default 10nm spacing, and also
+ extends the range of wavelengths very slightly. This high resolution
+ may assist in giving better accuracy for "peaky" emissive sources
+ such as illuminants and displays. The high resolution mode is
+ selected by using the <span style="font-weight: bold;">-H</span>
+ flag on the command line to <span style="font-weight: bold;">dispcal</span>,
+ <span style="font-weight: bold;">dispread</span>, <span
+ style="font-weight: bold;">chartread</span>, and <span
+ style="font-weight: bold;">spotread</span>. It can also be toggled
+ on and off within <span style="font-weight: bold;">spotread</span>
+ using the <span style="font-weight: bold;">h</span> key. The
+ extended range down to 350nm may give some information about an
+ illuminants ultra violet content, although the accuracy of the
+ readings between 350-380, and 730-740nm should not be relied upon.<br>
+ <br>
+ <img alt="High res. and standard res. spectrum."
+ src="Fluorescent.jpg" style="width: 750px; height: 375px;"><br>
+ <br>
+ <img alt="C.R.T high res. and standard res. spectrum."
+ src="CRTspectrum.jpg" style="width: 750px; height: 375px;"><br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1m"></a>Eye-One Monitor
+ emissive spectrometer<br>
+ <br>
+ <img alt="" src="i1m.jpg" style="width: 347px; height: 234px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Eye-One Monitor</span>
+ from <a href="http://www.xrite.com/">X-Rite</a> (was Gretag
+ MacBeth) is a discontinued instrument. It was a lower cost version
+ of the <span style="font-weight: bold;">Eye-One Pro</span> without
+ reflective measurement capability. See <a href="#i1p">Eye-One Pro
+ reflective/emissive spectrometer</a><span style="font-weight:
+ bold;"> </span>for details on the operation of this instrument.<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1d"></a>Eye-One Display
+ 1, Eye-One Display 2, Eye-One Display LT, ColorMunki Create,
+ ColorMunki Smile colorimeters,<br>
+ <br>
+ <img style=" width: 124px; height: 168px;" alt="ColorMunki Smile"
+ src="Smile.jpg"><img alt="Eye-One Display 2" src="i1d.jpg"
+ style="width: 145px; height: 168px;"> <img style="width: 133px;
+ height: 168px;" alt="ColorMunki Create"
+ src="ColorMunkiCreate.jpg"><br>
+ <br>
+ Instrument Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">ColorMunki Smile</span>
+ colorimeter is a currently available instrument.<br>
+ The <span style="font-weight: bold;">Eye-One Display LT</span> and
+ <span style="font-weight: bold;">Eye-One Display 2</span> are
+ discontinued products, although they may still be available from
+ some retailers, second hand, and may still be shipped with some
+ displays as part of their calibration capability.<br>
+ The <span style="font-weight: bold;">ColorMunki Create</span>
+ colorimeter is a discontinued product, although they may still be
+ available from some retailers or second hand,can also be used. They
+ will appear as an i1Display2 colorimeter.<br>
+ The <span style="font-weight: bold;">HP DreamColor</span>
+ colorimeter can also be used, and will appear as an i1Display2
+ colorimeter [note that it is calibrated for the DreamColor display].<br>
+ The <span style="font-weight: bold;">HP APS</span> (Advanced
+ Profiling Solution) colorimeter is also reported to work, and will
+ appear as an i1Display2.<br>
+ The <span style="font-weight: bold;">CalMAN X2</span> colorimeter
+ is also reported to work, and will appear as an i1Display2
+ colorimeter.<br>
+ The&nbsp; <span style="font-weight: bold;">Lacie Blue Eye</span> <span
+ style="font-weight: bold;"></span> colorimeter is also reported to
+ work, and will appear as an i1Display2 colorimeter.<br>
+ <br>
+ <span style="font-weight: bold;"></span>The <span
+ style="font-weight: bold;">Eye-One Display 1</span> is a
+ discontinued instrument. <br>
+ <br>
+ The Eye-One Display LT came with a less expensive<span
+ style="text-decoration: underline;"></span> package with more
+ limited software from the manufacture.<br>
+ The Eye-One Display 2 package came with more software
+ features,&nbsp; but the instruments are virtually identical, and
+ will operate identically using Argyll.<br>
+ The ColorMunki Create<span style="text-decoration: underline;"></span>
+ package is another alternative, and will operate identically using
+ Argyll.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for the <span style="font-weight: bold;">ColorMunki
+
+
+
+
+
+
+ Smile</span> are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f</span>
+ &nbsp;&nbsp; LCD with CCFL back-light&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses a Cold
+ Cathode Fluorescent back lighting. [Default, CB1]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>&nbsp;&nbsp;&nbsp;
+
+
+
+
+ LCD with LED back-light&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A Liquid Crystal display that uses
+ Light Emitting Diode back lighting.<br>
+ <br>
+ other instruments will offer:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
+ Cathode Ray Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="i1d3"></a></span>&nbsp; <span
+ style="font-weight: bold;">i1 DisplayPro and ColorMunki Display<span
+ style="font-weight: bold;"> colorimeters (i1 Display 3)</span><br>
+ <br>
+ <img alt="i1 Display Pro" src="i1d3_1.jpg" style="width: 194px;
+ height: 223px;"> <img style="width: 176px; height: 222px;"
+ alt="ColorMunki Display" src="i1d3_2.jpg"><br>
+ <br>
+ Instrument Availability:<br>
+ <br>
+ </span>Both instruments are currently available..<br>
+ <br>
+ The ColorMunki Display is a less expensive <a
+href="http://xritephoto.com/ph_product_overview.aspx?id=1513&amp;catid=149">package</a>
+ with more limited software from the manufacture, and takes a
+ noticeably longer time to make most measurements (a minimum of 1
+ second), but both instruments will take longer for very dark
+ samples, and under these conditions the speed difference is less
+ significant.<br>
+ <br>
+ The i1Display Pro <a
+href="http://xritephoto.com/ph_product_overview.aspx?id=1454&amp;catid=109">package</a>
+ comes with i1Profiler, and the instrument is generally faster than
+ the ColorMunki Display, but other than this and the software
+ package, the instruments appear to be virtually identical. (Note
+ though that the ColorMunki Display is <u>unable</u> to measure the
+ refresh period, so is less repeatable in this mode than the
+ i1Display Pro).<br>
+ <br>
+ Both instruments are capable of using CCSS (<a
+ href="File_Formats.html#ccss">Colorimeter Calibration Spectral
+ Sample</a>) files, and this also gives the instrument the
+ capability of using a non-default standard observer. CCSS files can
+ be created using the <a href="ccxxmake.html">ccxxmake</a> tool, and
+ installed or translated from the .EDR files that are provided with
+ the instrument CD using the <a href="oeminst.html">oeminst</a>
+ utility using a spectrometer as a reference.<br>
+ <br>
+ There are some OEM versions of this instrument around too, and the <a
+ href="http://www.spectracal.com/">SpectraCal OEM i1Display</a>, <a
+ href="http://www.chromapure.com/">ChromaPure</a> and <a
+ href="http://www.necdisplay.com/p/sensors/mdsvsensor3">NEC
+ SpectraSensor Pro</a> instruments are also reported to work. They
+ will appear as a be a the same as the i1Display Pro.<br>
+ <span style="font-weight: bold;">[Note</span> that if you have an
+ OEM version of this instrument, it's worth checking if they come
+ with any extra .edr files, that can then be translated for use with
+ ArgyllCMS using <a href="oeminst.html">oeminst</a>.]<br>
+ <br>
+ On MSWindows, if you have installed the Manufacturers applications,
+ you may have to shut the i1Profiler tray application down before
+ Argyll can open the instrument.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
+ &nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh period
+ is measured, and the integration time adjusted appropriately. [CB2]<br>
+ <br>
+ With the manufacturers .edr files &amp; reference Argyll .ccss files
+ installed, the following selections are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span>
+ &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display&nbsp; - The refresh
+ period is measured, and the integration time adjusted appropriately.
+ [CB2]<br>
+ &nbsp;&nbsp;&nbsp; <b>c</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRT
+ (Hitachi CM2112MET, Diamond View 1772ie)<br>
+ &nbsp;&nbsp;&nbsp; <b>l</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
+ IPS (CCFL AC EIZO HP with CORRECTION)<br>
+ &nbsp;&nbsp;&nbsp; <b>L</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD CCFL
+ Wide Gamut IPS (WG CCFL NEC241 271)<br>
+ &nbsp;&nbsp;&nbsp; <b>b&nbsp;</b>&nbsp;&nbsp;&nbsp;&nbsp; LCD RGB
+ LED IPS (RGBLED HP SOYO)<br>
+ &nbsp;&nbsp;&nbsp; <b>e</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LCD White
+ LED IPS (WLED AC LG Samsung)<br>
+ &nbsp;&nbsp;&nbsp; <b>p</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Projector
+ (Marantz HP Panasonic Projectors Hybrid EDR)<br>
+ <br>
+ <b>Note when measuring CRT displays:<br>
+ </b><br>
+ The small magnet in the ambient light cover used to signal what
+ position it is in, can interfere in the operation of the CRT
+ display, particularly if the ambient cover is in it's natural
+ position at 180 degrees away from the measuring lens. One way of
+ minimizing this is to swing the cover down so that it touches the
+ display adjacent to the lens, thereby moving the magnet away from
+ the display surface. A more thorough but inconvenient way of
+ avoiding this problem is to unclip the ambient light cover and slide
+ it down the cable.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="Huey"></a>Huey colorimeter<br>
+ <br>
+ <img alt="" src="Huey.jpg" style="width: 128px; height: 202px;"><br>
+ <br>
+ Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Huey </span>is widely
+ available under the <a href="http://www.pantone.com/">Pantone</a>
+ name as well as the manufacturer, <a href="http://www.xrite.com/">X-Rite</a>.
+ There lower cost Huey is now discontinued, while the <a
+href="http://www.pantone.com/pages/products/product.aspx?pid=562&amp;ca=2">Huey
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pro</a> is still available.<br>
+ <span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type. [Default, CB1]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="mox"></a>MonacoOPTIX
+ colorimeters<br>
+ <br>
+ <img alt="" src="mox.jpg" style="width: 115px; height: 147px;">
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <img alt="" src="Chroma4.jpg"
+ style="width: 135px; height: 146px;"><br>
+ <br>
+ Instrument Availability:<br>
+ </span><br>
+ <span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">MonacoOPTIX</span> from
+ Monaco Soft is a discontinued instrument.&nbsp; It may still be
+ available as old stock, or second hand. It was sold packaged with
+ software from the manufacturer. The Sequel Chroma 4 appears to be a
+ similar instrument, and both seem to operate as if they were an
+ Eye-One Display 1 using Argyll.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display, that is of the Non-Refresh type.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd2"></a>Spyder 2
+ colorimeter<br>
+ <br>
+ <img alt="" src="Spyd2.jpg" style="width: 218px; height: 232px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder 2 </span><span
+ style="font-weight: bold;"></span>has been superseded by the
+ Spyder 3 &amp; 4, but may be available second hand.<br>
+ [The Spyder 1 has also been reported as working, but this has not
+ been confirmed.]<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ <span style="font-weight: bold;">Important Note </span>about the
+ ColorVision Spyder 2 instrument support:<br>
+ <br>
+ This instrument cannot function without the driver software having
+ access to the vendor supplied PLD firmware pattern for it.<br>
+ This firmware is not provided with Argyll, since it is not available
+ under a compatible license.<br>
+ <br>
+ The purchaser of a Spyder 2 instrument should have received a copy
+ of this firmware along with their instrument, and should therefore
+ be able to enable the Argyll driver for this instrument by using the
+ <a href="oeminst.html">oeminst</a> tool.<span style="font-weight:
+ bold;"></span><br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; A Liquid Crystal
+ Display, that is of the Non-Refresh type. [Default, CB1]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display, that is of the Refresh type. [CB2]<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;">Linux USB hub problems:<br>
+ <br>
+ </span>Note that the Spyder doesn't appear to operate at all well on
+ Linux if attached to a secondary USB hub. You may have such a
+ secondary hub built into your motherboard. If Argyll has difficulty
+ in reliably talking to the Spyder, try connecting it directly to the
+ computer rather than via a usb hub, or try using a USB port on your
+ computer that connects directly to a root hub. This is probably due
+ to a bug in the Linux EHCI driver, and a fix is due to appear in the
+ Linux kernel sometime after July 2011. The name of the fix is "EHCI:
+ fix direction handling for interrupt data toggles".<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd3"></a>Spyder 3
+ colorimeter<br>
+ <br>
+ <img style="width: 262px; height: 220px;" alt="Spyder3"
+ src="Spyd3.jpg"> <img style="width: 193px; height: 220px;"
+ alt="Spyder3Express" src="Spyd3x.jpg"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder3Elite</span>, <span
+ style="font-weight: bold;">Spyder3Pro</span> and <span
+ style="font-weight: bold;">Spyder3Express</span> are being
+ superseded by the Spyder4, but may still stocked by some dealers,
+ and may be available second hand. The <span style="font-weight:
+ bold;">Spyder3Elite</span> and <span style="font-weight: bold;">Spyder3Pro</span>
+ appear to be identical hardware with different software from the
+ manufacturer. The <span style="font-weight: bold;">Spyder3Express</span>
+ lacks the ambient sensor.<br>
+ <br>
+ [Note that this instrument doesn't seem particularly suited to
+ measuring CRT displays, since it no longer seems to synchronise its
+ readings to a CRT refresh, and you can no longer remove the LCD
+ filter, reducing its sensitivity compared to the Spyder 2 in CRT
+ mode. The Spyder 2 or one of the other instruments may be a better
+ choice if you particularly need to measure CRTs or Refresh
+ displays.]<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ The ambient light sensor can be used with the <span
+ style="font-weight: bold;">Spyder3Elite</span> and <span
+ style="font-weight: bold;">Spyder3Pro</span> instruments, but is
+ only capable of monochrome readings.<span style="font-weight: bold;"><br>
+ </span><br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
+ style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp; A
+ non-refresh type display [Default, CB1]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span>
+ &nbsp;&nbsp;&nbsp; A refresh type display. [CB2]<br>
+ <br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ <span style="font-weight: bold;"><a name="spyd4"></a>Spyder 4
+ colorimeter<br>
+ <br>
+ <img style=" width: 262px; height: 220px;" alt="Spyder4"
+ src="Spyd4.jpg"> <br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;">Spyder4Elite</span>, <span
+ style="font-weight: bold;">Spyder4Pro</span> and <span
+ style="font-weight: bold;">Spyder4Express</span> are a currently
+ available instruments. The <span style="font-weight: bold;">Spyder4Elite</span>
+ and <span style="font-weight: bold;">Spyder4Pro</span> appear to be
+ identical hardware with different software from the manufacturer.
+ The <span style="font-weight: bold;">Spyder4Express</span> lacks
+ the ambient sensor.<br>
+ <span style="font-weight: bold;"><br>
+ </span><span style="font-weight: bold;">Operation:<br>
+ </span><br>
+ These instruments are capable of using using CCSS (<a
+ href="File_Formats.html#ccss">Colorimeter Calibration Spectral
+ Sample</a>) files, and this also gives the instrument the
+ capability of using a non-default standard observer. CCSS files can
+ be created using the <a href="ccxxmake.html">ccxxmake</a> tool
+ using a spectrometer as a reference.<br>
+ <br>
+ <span style="font-weight: bold;">Important Note </span>about the
+ DataColor Spyder 4 vendor display type/calibration support:<br>
+ <br>
+ This instrument does not have a full range of display type
+ calibration selections available without the vendor supplied
+ calibration data for it.<br>
+ This calibration data is not provided with Argyll, since it is not
+ available under a compatible license.<br>
+ You can use CCSS files as an alternative (see above), or as the
+ purchaser of a Spyder 4 instrument you should have received a copy
+ of the calibration data along with their instrument, and should
+ therefore be able to enable the full range of display type
+ selections in Argyll by using the <a href="oeminst.html">oeminst</a>
+ tool.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n</span> | <span
+ style="font-weight: bold;">l</span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp; A non-refresh type display with a generic calibration
+ [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r | c</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp; A
+ refresh type display with a generic calibration.[CB2]<br>
+ <br>
+ The Display Selections for this instrument when the manufacturers
+ calibration information has been installed is:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">n&nbsp;&nbsp; </span><span
+ style="font-weight: bold;"></span>&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A non-refresh type display with a generic
+ calibration [Default, CB1].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">r</span> <span
+ style="font-weight: bold;"></span> &nbsp; &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; A refresh type display with a generic
+ calibration.[CB2]<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">f &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; </span>&nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+ Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - normal gamut Liquid Crystal Display with standard Cold Cathode
+ Fluorescent Lamp backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">L</span>&nbsp;
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; Wide Gamut LCD, CCFL
+ Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - wide gamut Liquid Crystal
+ Display with Cold Cathode Fluorescent Lamps backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">e</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, White
+ LED Backlight&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; - normal
+ gamut Liquid Crystal Display with a White LED backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">B</span>&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; Wide Gamut LCD, RGB LED
+ Backlight - wide gamut Liquid Crystal Display with RGB LED
+ backlight.<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">x</span>
+ &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; LCD, CCFL
+ Type 2
+ Backlight&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - normal gamut Liquid Crystal Display with alternative Cold Cathode
+ Fluorescent Lamp backlight (Laptop ?)<br>
+ <br>
+ The ambient light sensor can be used with the <span
+ style="font-weight: bold;">Spyder4Elite</span> and <span
+ style="font-weight: bold;">Spyder4Pro</span> instruments, but is
+ only capable of monochrome readings.<span style="font-weight: bold;"></span><br>
+ <span style="font-weight: bold;"></span><br>
+ <hr style="width: 100%; height: 2px;"><a name="HCFR"></a><span
+ style="font-weight: bold;" class="titre">Colorim&egrave;tre HCFR
+ colorimeter<br>
+ <br>
+ <img alt="" src="HCFR.jpg" style="width: 203px; height: 194px;"><br>
+ <br>
+ </span><span style="font-weight: bold;">Availability:<br>
+ <br>
+ </span>The <span style="font-weight: bold;" class="titre">Colorim&egrave;tre
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HCFR Probe</span> is a kit instrument from <span
+ style="font-weight: bold;"></span> <a
+ href="http://www.homecinema-fr.com/colorimetre/index_en.php">HCFR</a>.
+ <br>
+ <br>
+ <span style="font-weight: bold;">OS X</span><br>
+ <br>
+ Please note the installation <a href="Installing_OSX.html#HCFR">instructions</a>.<br>
+ <br>
+ <span style="font-weight: bold;">Operation:</span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
+ The accuracy of this instrument does not seem to be comparable to
+ the commercial instruments when used for measuring displays,
+ particularly in the area of measuring dark colors, and I've seen the
+ best results when used with a CRT display. It may well give good
+ results in calibrating projectors, since this was what it was
+ designed to do.<br>
+ <br>
+ The Display Selections for this instrument are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">l</span>&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LCD display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Liquid
+ Crystal Display [Default].<br>
+ &nbsp;&nbsp;&nbsp; <span style="font-weight: bold;">c</span>&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CRT display&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; A Cathode Ray
+ Tube display.<br>
+ &nbsp;&nbsp;&nbsp; <b>R</b> &nbsp; Raw&nbsp;
+ Reading&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Raw sensor readings,
+ used for calibration [CB1]<br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/invprofcheck.html b/doc/invprofcheck.html
new file mode 100644
index 0000000..9851774
--- /dev/null
+++ b/doc/invprofcheck.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>invprofcheck</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>profile/invprofcheck</b></h2>
+<h3>Summary</h3>
+Check <a href="File_Formats.html#ICC">ICC</a> forward against reverse
+lookup.
+<br>
+<h3>Usage Summary</h3>
+<small><span style="font-family: monospace;">usage: invprofcheck
+[-options] </span><span
+ style="font-style: italic; font-family: monospace;">profile.icm</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v [level]&nbsp;&nbsp;
+verbosity level (default 1), 2 to print each DE</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-l
+limit&nbsp;&nbsp;&nbsp;&nbsp; set total ink
+limit (estimate by default)<br>
+</span></small><small><span style="font-family: monospace;">&nbsp;-L
+klimit &nbsp;&nbsp; set black channel ink
+limit (estimate by default)</span></small><br
+ style="font-family: monospace;">
+<small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;-h&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+high res test (27)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Ultra high res test (61)<br>
+&nbsp;-R res&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Specific grid
+resolution<br style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;-c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Show CIE94 delta E values</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-k&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Show CIEDE2000 delta E values</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+create VRML visualisation (profile.wrl)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use VRML axes</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Color vectors acording to delta E</span><br
+ style="font-family: monospace;">
+<span style="font-style: italic; font-family: monospace;">&nbsp;profile.icm</span><span
+ style="font-family: monospace;">&nbsp;
+Profile to check</span></small>
+<br>
+<h3>Usage Details and Discussion</h3>
+<b>invprofcheck</b> provides a way of checking how well an&nbsp;<a
+ href="File_Formats.html#ICC">ICC</a> profile inverse transform inverts
+the forward transform. For devices with more than 4 channels, a total
+ink limit is assumed, and (if no <span style="font-weight: bold;">-l</span>
+parameter is given) a reasonable number is deduced from the reverse
+table. A grid of device values is created, and the transform from
+PCS-&gt;device, and then device-&gt;PCS is computed in L*a*b* space.
+The average, maximum and RMS error delta E values are computed and
+displayed in the chosen delta E metric. A <a
+ href="File_Formats.html#VRML">VRML</a> plot of the error vectors can
+be created. <span style="font-weight: bold;">invprofcheck</span> tries
+to only test in-gamut color values. Note that because it scans a device
+grid, for a CMYK device, the density of test points will be
+progressively higher in the dark regions, and the average and RMS
+values will be distorted by the denser sampling.<br>
+<br>
+The <b>-v</b> flag prints out extra information during the checking. A
+value greater than 1 will print the color values of each test point.<br>
+<br>
+The <b>-l</b> flag allows setting a total ink limit (TAC) for printing
+devices. If a device has a total ink limit, and hasn't been
+characterised with device values above this limit, then plotting the
+gamut in these areas will almost certainly be misleading. The ink limit
+will be in final calibrated device values if the profile includes
+calibration information.<br>
+<br>
+The <b>-L</b> flag allows setting a black channel ink limit for
+printing
+devices. If a device has a black ink limit, and hasn't been
+characterised with device values above this limit, then plotting the
+gamut in these areas will almost certainly be misleading. The black ink
+limit
+will be final calibrated device values if the profile
+includes calibration information.<br>
+<br>
+The default device grid is relativy low, and 11 (ie. 11 x 11 x 11 for
+an RGB device, 11 x 11 x 11 x 11 for a CMYK device etc.).<br>
+<br>
+The <span style="font-weight: bold;">-h</span> flag selects a higher
+device grid resolution of 27.<br>
+<br>
+The <span style="font-weight: bold;">-u</span> flag selects an
+extremely high device grid resolution of 61. This will probably take a
+long time to run.<br>
+<br>
+The <span style="font-weight: bold;">-G res</span> option allows a
+specific grid resolution to be used.<br>
+<br>
+The <b>-c</b> option causes the error differences to be
+displayed
+in CIE94 delta E, rather than plain L*a*b* delta E. CIE94 delta E has a
+closer
+correspondence with perceived color differences than the default CIE76
+delta E values.<br>
+<br>
+The <b>-k</b> option causes the error differences to be
+displayed
+in CIEDE2000 delta E, rather than plain L*a*b* delta E. CIEDE2000 delta
+E has a
+closer
+correspondence with perceived color differences than either CIE76 or
+CIE94 delta E values.<br>
+<br>
+The <b>-w</b> creates a <a href="File_Formats.html#VRML">VRML</a> 3D
+visualization
+of the differences between the test points and the profiles prediction
+of
+the resulting colors.<br>
+<br>
+The <b>-x</b> flag adds Lab axes to the VRML output.<br>
+<br>
+The <span style="font-weight: bold;">-e</span> flag causes the error
+vectors in the VRML output to be color coded according to their
+lengths, from longest to shortest: yellow, red, magenta, blue, cyan and
+green.<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/kodak2ti3.html b/doc/kodak2ti3.html
new file mode 100644
index 0000000..5485506
--- /dev/null
+++ b/doc/kodak2ti3.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>kodak2ti3</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>profile/kodak2ti3</b></h2>
+<h3>Summary</h3>
+Convert Kodak Colorflow format CMYK test chart into Argyll&nbsp;<a
+ href="File_Formats.html#.ti3">.ti3</a> CGATS format.<br>
+<h3>Usage Summary</h3>
+<small><span style="font-family: monospace;">kodak2gcats [-v] [-l
+limit] infile outfile<br>
+</span></small><small><b style="font-family: monospace;"> -v</b><span
+ style="font-family: monospace;"> <span style="font-style: italic;">&nbsp;
+&nbsp; &nbsp;</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+verbose mode<br>
+</span></small><small><b style="font-family: monospace;"> -l</b><span
+ style="font-family: monospace;"> </span><i
+ style="font-family: monospace;">limit</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+set
+ink
+limit, 0 - 400%</span></small><br style="font-family: monospace;">
+<small><span style="font-family: monospace;"></span><b
+ style="font-family: monospace;"> -r</b><span
+ style="font-family: monospace;"> <span style="font-style: italic;">filename</span>
+&nbsp;&nbsp;&nbsp; Use an alternate 928 patch reference file</span><br
+ style="font-family: monospace;">
+<i style="font-family: monospace;"> infile</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Base name for input.pat file</span><br style="font-family: monospace;">
+<i style="font-family: monospace;"> outfile</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Base
+name for output</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">
+file</span></small>
+<br>
+<h3>Usage Details and Discussion</h3>
+kodak2ti3 takes the Kodak Colorflow CMYK printer spectrometer data
+file, and turns them into Argyll .ti3 CGATS files.<br>
+By default kodak2ti3 expects a standard 928 patch test chart has been
+used. If an alternate 928 test chart has been used, an alternate device
+reference file can be supplied using the -r parameter.<br>
+The Argyll <a href="File_Formats.html#.ti3">.ti3</a>
+format usually contains an ink limit or TAC (Total Area Coverage) limit
+value,
+used to specify the gamut limits during profile creation. the <b>-l</b>
+flag allows this to be specified, and included in the created <a
+ href="File_Formats.html#.ti3">.ti3</a> file.<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/monitorcontrols.html b/doc/monitorcontrols.html
new file mode 100644
index 0000000..83ab695
--- /dev/null
+++ b/doc/monitorcontrols.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>About display monitor settings and targets</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+</head>
+<body>
+<h2 style="text-decoration: underline; font-weight: bold;">About
+display monitor settings and
+targets</h2>
+Setting monitor controls and target behaviour for monitor calibration
+boils down to two things:<br>
+<br>
+&nbsp;&nbsp; What is the equipment capable of without introducing side
+effects ?<br>
+<br>
+&nbsp;&nbsp; What are you trying to do ?<br>
+<br>
+There are three reasons you may want to adjust display settings and set
+calibration targets:<br>
+<br>
+1) You want to change how non-color managed applications appear.<br>
+2) You want to change basic behaviour of the display that the profile
+based<br>
+&nbsp;&nbsp; color management doesn't usually change, such as white
+point and brightness.<br>
+3) You want to improve the behaviour of the device so that the normal
+profile based<br>
+&nbsp;&nbsp; color management does a better job of controlling the
+display.<br>
+<br>
+<br>
+You can make adjustments to a display using it's controls and/or the
+video
+card LUTs. Generally the former are more powerful and have less side
+effects. There can be exceptions though, for instance LCD's have no
+native contrast control capability, only brightness, so contrast is
+usually faked by manipulating the lookup curves, which can introduce
+side effects. The same applies to white point control on an LCD (unless
+it has
+R/G/B LED back lighting). So generally LCD displays are much less
+flexible than CRT displays in targeting some non-native colorspace
+without introducing side effects, so it is generally best to set all
+the LCD controls except back lighting brightness to their default
+settings.<br>
+<br>
+Brightness depends on what you are trying to do. If you are trying to
+do soft proofing for instance, you will have some brightness level in
+mind dictated by the hard proofing booth you are comparing to, or the
+ambient brightens level. For good color judgement and low fatigue it's
+desirable that the display brightness roughly match that of the ambient
+lighting.<br>
+<br>
+In terms of what you are trying to do, it comes down to what colorspace
+you want the display to be, and how far from native for that display it
+is. A CRT can be reasonably flexible in the behaviour it can be given
+without side effects, an LCD less so. If you want to minimize artefacts
+on an LCD you want to set the contrast and white points to their native
+values (ie. where the monitor is not manipulating the digital signal
+levels). It may not be easy to figure out what this is. In this
+scenario you would probably only want calibration to set the transfer
+characteristic and neutral axis, and leave the white point native.<br>
+<br>
+For typical MSWindows/Linux this would probably be the typical CRT
+transfer
+("gamma") curve, or a gamma of about 2.4. For OS X it would probably <br>
+be a gamma of 1.8 for versions 10.5 or earlier, or 2.4 for 10.6 or
+latter ("Snow Leopard").<br>
+<br>
+The nominal white point of a display is D65 (set by Television
+standards), and an LCD's native white point is somewhere near there,
+but this is dictated by their backlight color. The CRT's will give
+maximum brightness with a much higher white point (9000K or so), but
+this can be reduced with fewer side effects (just reduced brightness)
+using typical CRT controls. <br>
+<br>
+If you have specific requirements (trying to do soft proofing) then you
+may want to target a specific white point and brightness, and be
+prepared to compromise other aspects of the display to achieve this. By
+all means use the controls to move the display in the direction you
+want to go, and then use the calibration curves to get there. If you
+are moving far from native (especially on an LCD) you may find the side
+effects unacceptable though.<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/mox.jpg b/doc/mox.jpg
new file mode 100644
index 0000000..f3c7166
--- /dev/null
+++ b/doc/mox.jpg
Binary files differ
diff --git a/doc/moxxr.jpg b/doc/moxxr.jpg
new file mode 100644
index 0000000..579d7fc
--- /dev/null
+++ b/doc/moxxr.jpg
Binary files differ
diff --git a/doc/mppcheck.html b/doc/mppcheck.html
new file mode 100644
index 0000000..cd44989
--- /dev/null
+++ b/doc/mppcheck.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>mppcheck</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>profile/mppcheck</b>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;<br>
+</h2>
+<h3>Summary</h3>
+Check an&nbsp;<a href="File_Formats.html#MPP">MPP</a> profile
+against&nbsp;<a href="File_Formats.html#.ti3">.ti3</a>
+test chart data.<br>
+<h3>Usage Summary</h3>
+<small><span style="font-family: monospace;">mppcheck [-v] [-s] -[y]
+values.ti3 profile.mpp</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; Verbose mode</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">-c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp; Show CIE94 delta E values</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">-k
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Show CIEDE2000 delta E values</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; Check spectral model too</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">-y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; Detail each value</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">values.ti3&nbsp; &nbsp; Test
+values to check against</span><br style="font-family: monospace;">
+<i style="font-family: monospace;"> profile.mpp</i><span
+ style="font-family: monospace;"> &nbsp; Profile to check</span></small>
+<br>
+<h3>Usage Details and Discussion</h3>
+mppcheck provides a way of checking how well an&nbsp;<a
+ href="File_Formats.html#MPP">MPP</a> profile conforms to the test
+sample data that was used to create it. This is the same sort of check
+done within the profile making tool (<a href="mppprof.html">mppprof</a>),
+but having a separate tool provides some flexibility. <br>
+<br>
+The <b>-v</b> flag prints out extra information during the checking.<br>
+<br>
+The <b>-c</b> option causes the differences between the test values
+and
+the profile prediction of the color for each device value to be
+displayed
+in CIE94 delta E, rather than plain L*a*b* delta E. CIE94 delta E has a
+closer
+correspondence with perceived color differences than the default CIE76
+delta E values.<br>
+<br>
+The <b>-k</b> option causes the differences between the test values
+and
+the profile prediction of the color for each device value to be
+displayed
+in CIEDE2000 delta E, rather than plain L*a*b* delta E. CIEDE2000 delta
+E has a
+closer
+correspondence with perceived color differences than either CIE76 or
+CIE94 delta E values.<br>
+<br>
+The <b>-s</b> flag causes the spectral model (if present) to be
+checked against the test data spectral values (if present). Errors are
+given as a percentage error for each reflectance band, as well as a
+delta E of the resulting CIE color computed from the spectral values.<br>
+<br>
+The <b>-y</b> flag when used in combination with the <b>-v</b> flag,
+causes each test value and its error to be printed. <br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/mpplu.html b/doc/mpplu.html
new file mode 100644
index 0000000..2f0b955
--- /dev/null
+++ b/doc/mpplu.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>mpplu</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>xicc/mpplu</b></h2>
+<h3>Summary</h3>
+Lookup individual color values though an&nbsp;<a
+ href="File_Formats.html#MPP">MPP</a> profile. Also
+create MPP gamut files or&nbsp;<a href="File_Formats.html#VRML">VRML</a>
+views.<br>
+<h3>Usage</h3>
+<small><span style="font-family: monospace;">mpplu [-v level] [-f func]
+[-i intent] [-o order] profile.mpp</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">-f </span><i
+ style="font-family: monospace;">function</i><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp;f = forward, b =
+backwards</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">-p </span><i
+ style="font-family: monospace;">oride</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x
+= XYZ_PCS, l =
+Lab_PCS, y = Yxy, s = spectral,</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">-l </span><i
+ style="font-family: monospace;">limit</i><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; override
+default
+ink limit, 1 - N00%</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">-i </span><i
+ style="font-family: monospace;">illum</i><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp; Choose
+illuminant for
+print/transparency spectral data:</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp; A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">-o </span><i
+ style="font-family: monospace;">observ</i><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp; Choose CIE
+Observer for spectral
+data:</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp; </span></small><small><span
+ style="font-family: monospace;">1931_2 </span></small><small><span
+ style="font-family: monospace;"> (def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B
+1955_2, shaw, J&amp;V 1978_2</span></small><small><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">-u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; Use Fluorescent Whitening Agent compensation</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">-g&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; Create gamut output</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">-w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; Create gamut VRML as well<br>
+-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't add VRML axes<br>
+-a n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Gamut
+transparency level<br style="font-family: monospace;">
+</span><span style="font-family: monospace;">-d
+n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; Gamut
+surface detail level</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">-t num&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; Invoke debugging test code
+"num" 1..n</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp; 1 - check partial derivative for device
+input</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp; 2 - create overlap diagnostic VRML gamut
+surface</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">profile.mpp &nbsp; Profile to be
+used</span><br style="font-family: monospace;">
+<br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; The colors to
+be translated should be fed into
+standard input,</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; one input
+color per line, white space separated.</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; A line
+starting with a # will be ignored.</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; A line not
+starting with a number will terminate the
+program.</span></small>
+<br>
+<h3>Usage Details and Discussion</h3>
+This is an analogous tool to <a href="icclu.html"> icclu </a>, but
+applying
+to <a href="File_Formats.html#MPP">MPP</a> profile, rather than <a
+ href="File_Formats.html#ICC">ICC</a> profiles. Because MPP profiles
+can also contain a spectral description of device behavior, there are
+extra options in mpplu to describe how to convert spectral values into
+CIE tristimulus values.<br>
+Some additional functionality is included in mpplu, analogous to <a
+ href="iccgamut.html"> iccgamut</a>, allowing gamut files and images to
+be generated from MPP profiles.<br>
+<br>
+The <b>-v</b> flag causes extra information about the profile to be
+printed.<br>
+<br>
+The <b>-f</b> flag is experimental, and should be ignored.<br>
+<br>
+Normally L*a*b* is displayed, but this can be changed using the the <b>-p</b>
+flag and XYZ, Yxy, or spectral values to be be displayed.<br>
+<br>
+If an illuminant, observer or Fluorescent Whitening Agent compensation
+is selected, then the CIE tristimulus values will be computed from the
+spectral information in the MPP profile (if present).<br>
+<br>
+The <b>-l</b> flag overrides any default ink limit (Total Area
+Coverage) recorded in the profile. The ink limit has an effect on the
+results of a gamut
+generated from the profile.<br>
+<br>
+The <b>-i</b> flag allows specifying a standard or custom illumination
+spectrum, applied to reflective spectral profile data to compute CIE
+tristimulus
+values. <b>A</b>, <b>D50</b>, <b>D65</b>, <b>F5</b>, <b>F8</b>, <b>F10</b>
+are a selection of standard illuminant spectrums, with <b>D50</b>
+being the
+default. If a filename is specified instead, it will be assumed to be
+an
+Argyll specific <a href="File_Formats.html#.sp">.sp</a> spectrum file.<br>
+<br>
+<a name="o"></a> The <b>-o</b> flag allows specifying a tristimulus
+observer, and is used to compute PCS (Profile Connection Space)
+tristimulus values. The following choices are available:<br>
+<b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree observer.
+The default.<br>
+&nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree observer.<br>
+&nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+observer<br>
+&nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree observer<br>
+&nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+observer<br>
+<br>
+The <b>-u</b> flag enables Fluorescent Whitening Agent compensation,
+which compensates for the effect a different illuminant will have, on
+any Fluorescent Whitening Agent present in the reflective media.<br>
+<br>
+The <b>-g</b> flag causes mpplu to simply generate a gamut surface
+description from the profile, creating a <a
+ href="File_Formats.html#.gam">.gam</a> file with the same base name as
+the given profile.<br>
+<br>
+The <b>-w</b> flag causes the gamut surface to be generated in <a
+ href="File_Formats.html#VRML">VRML</a> format
+as well as <a href="File_Formats.html#.gam">.gam</a> format.<br>
+<br>
+<small><span style="font-family: monospace;">The <span
+ style="font-weight: bold;">-n</span> flag suppresses the VRML axes.<br>
+<br>
+The <span style="font-weight: bold;">-a</span> <span
+ style="font-weight: bold;">n</span> parameter sets a transparency
+level in the VRML surface.</span></small><br>
+<br>
+The <b>-d</b> parameter controls the level of detail displayed in the
+gamut surface. The parameter roughly corresponds to a deltaE value, so
+smaller values give greater detail. The default value is around 10, and
+is a good place to start. Small values may take a lot of time to
+generate, and will produce big files.<br>
+<br>
+The <b>-t</b> parameter invokes special MPP test and diagnostic output.<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/mppprof.html b/doc/mppprof.html
new file mode 100644
index 0000000..5446451
--- /dev/null
+++ b/doc/mppprof.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>mppprof</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>profile/mppprof</b></h2>
+<h3>Summary</h3>
+Create a Model Printer Profile (<a href="File_Formats.html#MPP">MPP</a>)
+from the&nbsp;<a href="File_Formats.html#.ti3">.ti3</a> test data.<br>
+<h3>Usage summary</h3>
+<small><span style="font-family: monospace;">mppprof [options] outfile</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose mode</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-q [lmhs]&nbsp;&nbsp;
+Quality - Low, Medium (def), High, Simple</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-l limit&nbsp;&nbsp;&nbsp;
+override default ink limit, 1 -
+n00%</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Generate spectral model too</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-m&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Generate ink mixing model</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verify profile<br>
+&nbsp;-L&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Output
+Lab values<br style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;</span><i
+ style="font-family: monospace;">inoutfile</i><span
+ style="font-family: monospace;">&nbsp;&nbsp; Base name for input</span><a
+ style="font-family: monospace;" href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">/output.</span><a
+ style="font-family: monospace;" href="File_Formats.html#MPP">MPP</a><span
+ style="font-family: monospace;"> file</span></small><br>
+<h3>Usage Details and Discussion</h3>
+This is an analogous tool to&nbsp;<a href="colprof.html">colprof</a>,
+but applying to
+<a href="File_Formats.html#MPP">MPP</a> profiles, rather than <a
+ href="File_Formats.html#ICC">ICC</a> profiles. This tool creates an
+MPP profile given the <a href="File_Formats.html#.ti3">.ti3</a> test
+chart information. The model based device profile is an Argyll specific
+format, used to hold the parameters to a general model based device
+characterization.
+This is a less precise and general format than and ICC profile, but is
+a compact way of representing a devices response when it has a large
+number
+of color channels, or when very few measured data points are available
+for its construction.<br>
+<br>
+The <b>-v</b> flag causes extra information to be printed as the
+profile is being created, including the delta E statistics for the test
+data fit against the profile.<br>
+<br>
+The <b>-q</b> parameter sets the level of effort and hence quality in
+the resulting profile. Different quality profile use different numbers
+of
+model parameters.<br>
+&nbsp;&nbsp;&nbsp; <b>s &nbsp; &nbsp; &nbsp;</b>simple - use a close
+variation
+of the Neugenbauer model, with a single parameter, per device
+linearisation curve.<br>
+&nbsp;&nbsp;&nbsp; <b>l</b> &nbsp;&nbsp; &nbsp; &nbsp;low quality
+profiles
+have more detail terms to account for device linearisation.<br>
+&nbsp;&nbsp;&nbsp; <b>m</b> &nbsp; &nbsp; medium quality profiles, add
+color channel cross mixing terms, as well as using more detail
+parameters.<br>
+&nbsp;&nbsp;&nbsp; <b>h</b> &nbsp;&nbsp; &nbsp; high quality profiles,
+use more detail terms and more profile refinement iterations.<br>
+<br>
+The <b>-l</b> flag overrides any default ink limit (Total Area
+Coverage) recorded in the .ti3 file.<br>
+<br>
+The <b>-s</b> flag enables the creation of spectral model values, as
+well as the tri-stimulus model.<br>
+<br>
+The <b>-m</b> flag is currently not implemented.<br>
+<br>
+The <b>-y</b> flag causes each test value and its error to be printed.<br>
+<br>
+The <b>-L</b> flag causes the CGATS output file to contain D50 L*a*b*
+parameters rather than XYZ.<br>
+<br>
+The <i>inoutfile</i> parameters should be the base name of the .ti3
+file, and mppprof will output an mpp that has the same basename and the
+.mpp extension.<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/oeminst.html b/doc/oeminst.html
new file mode 100644
index 0000000..7334d8d
--- /dev/null
+++ b/doc/oeminst.html
@@ -0,0 +1,323 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>oeminst</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/oeminst</b></h2>
+ <h3>Summary</h3>
+ A special purpose tool that installs various Instruments
+ Manufacturers support files to enable various instrument operations
+ when used with Argyll, as well as install colorimeter calibration
+ and spectral sample files so that they appear in the display type
+ list (<b>-y</b> option).<br>
+ For the Spyder 2, it can install the instrument manufacturers PLD
+ firmware pattern, which is necessary for it to operate.<br>
+ For the Spyder 4, it can enable the full range of manufacturers
+ colorimeter calibration selections, as well as install CCSS files.<br>
+ For the eye-one display 3 it can&nbsp; locate and translate X-Rite
+ .EDR files to CCSS files and install them to enable a full range of
+ colorimeter calibration selections, as well as install CCSS files.<br>
+ For all colorimeters it can install CCMX files make for that model
+ of colorimeter.<br>
+ <h3>Usage summary<br>
+ </h3>
+ <small><span style="font-family: monospace;">oeminst [-options] [<span
+ style="font-style: italic;">inputfile</span></span>s]<span
+ style="font-family: monospace;"></span></small><br>
+ <span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+ Verbose</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+ Don't install, show where files would be installed</span><br>
+ <span style="font-family: monospace;">&nbsp;-c
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+ Don't install, save files to current directory</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-S
+ d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+ Specify the install scope u = user (def.), l = local system]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;infile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+ setup.exe CD install file(s) or .dll(s) containing install files</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;infile.[edr|ccss|ccmx]&nbsp;
+
+
+
+
+
+
+
+
+ EDR file(s) to translate and install or CCSS or CCMX files to
+ install</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+ </span><small><span style="font-family: monospace;">If no file is
+ provided, oeminst will look for the install CD.</span></small>
+ <h3></h3>
+ <h3>Flags and Parameters</h3>
+ The <span style="font-style: italic;">inputfiles</span> arguments
+ are optional, and and can be used to specify the MSWindows setup.exe
+ file from the installation CD or other files to install. If files
+ are specified, then they can be any combination of the setup.exe
+ file, .dll libraries that contain the files to be installed, or
+ X-Rite .edr files to convert or the equivalent to an Argyll .ccss
+ files, or<br>
+ .ccss or .ccmx files created using <a href="ccxxmake.html">ccxxmake</a>.<br>
+ <br>
+ The <b>-v</b> flag enables verbosity. This may be of use in
+ figuring out what went wrong if it doesn't work, and where files
+ have been installed.<br>
+ <br>
+ The <span style="font-weight: bold;">-n</span> flag causes oeminst
+ to show where the files would be installed or saved to, rather than
+ actually doing it.<br>
+ <br>
+ The <span style="font-weight: bold;">-c</span> flag causes oeminst
+ to save the files to the current directory, rather than the install
+ location.<br>
+ <br>
+ The <span style="font-weight: bold;">-S</span> option allows
+ installing the file(s) in a local system location, rather than the
+ default user accessible location. With this option you may need to
+ run this as superuser using the "sudo" command on OS X and Linux
+ systems.<span style="font-weight: bold;"><span style="font-weight:
+ bold;"><span style="font-weight: bold;"></span></span></span><br>
+ <h3>Usage Details and Discussion</h3>
+ <p>The <span style="font-weight: bold; text-decoration: underline;">Spyder
+
+
+
+
+
+
+
+
+
+ 2</span> instrument cannot function without the presence of the
+ instrument vendors PLD firmware pattern for the device. This
+ firmware is not provided with Argyll, since it has not been made
+ available under a compatible license.<br>
+ <br>
+ The purchaser of a Spyder 2 instrument should have received a copy
+ of this firmware along with their instrument from the original
+ vendor, and <span style="font-weight: bold;">oeminst</span>
+ enables their instrument, by locating the firmware in the users
+ copy of the instrument install files.<br>
+ <br>
+ On Microsoft Windows or Apple OS X platforms, <span
+ style="font-weight: bold;">oeminst</span> will look to see if
+ the vendors drivers have been installed on the users machine, and
+ locate the firmware pattern from there. If the vendors drivers
+ have not been installed, or the user does not wish to install
+ them, or no vendors drivers are available for the users platform
+ (i.e. Linux), then <span style="font-weight: bold;">oeminst</span>
+ will also attempt to locate the Spyder 2 installation CDROM, and
+ make use of the firmware pattern from there.<br>
+ <br>
+ If the instrument firmware pattern is successfully located, then
+ oeminst will create a <span style="font-weight: bold;">spyd2PLD.bin</span>
+ file in a subdirectory of the users home directory, or if the <span
+ style="font-weight: bold;">-S l</span> option is used, will
+ store it in a system wide location. (the <a
+href="http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html">XDG
+
+
+
+
+
+
+
+
+
+ Base Directory specifications</a> are used as a basis for
+ storing the file). Programs that access instruments such as&nbsp;
+ <span style="font-weight: bold;">spotread</span>, <span
+ style="font-weight: bold;">dispcal</span> and <span
+ style="font-weight: bold;">dispread</span>, can then locate and
+ load the firmware into the instrument.<br>
+ <br>
+ <span style="font-weight: bold;">Note</span> that the <span
+ style="font-weight: bold;">spyd2PLD.bin</span> file created by
+ oeminst contains the proprietary and copyrighted firmware provided
+ by the instrument vendor, and while the vendor has provided the
+ firmware to the end user to facilitate the use of their purchased
+ instrument, the instrument vendor (typically) does not permit the
+ user to distribute such a file or make copies for purposes other
+ than making use of their own instrument.<br>
+ </p>
+ <p><br>
+ The <span style="font-weight: bold; text-decoration: underline;">Spyder
+
+
+
+
+
+
+
+
+
+ 4</span> instrument does not have the full range of vendor
+ instrument calibration options without the presence of the
+ instrument vendors calibration information for the device. This
+ calibration information is not provided with Argyll, since it has
+ not been made available under a compatible license.<br>
+ <br>
+ The purchaser of a Spyder 4 instrument should have received a copy
+ of this calibration information along with their instrument from
+ the original vendor, and <span style="font-weight: bold;">oeminst</span>
+ enables the full range of calibration choice for their instrument,
+ by locating the necessary information in the users copy of the
+ instrument install files.</p>
+ <p>On Microsoft Windows or Apple OS X platforms, <span
+ style="font-weight: bold;">oeminst</span> will look to see if
+ the vendors drivers have been installed on the users machine, and
+ locate the calibration information from there. If the vendors
+ drivers have not been installed, or the user does not wish to
+ install them, or no vendors drivers are available for the users
+ platform (i.e. Linux), then <span style="font-weight: bold;">oeminst</span>
+ will also attempt to locate the Spyder 4 installation CDROM, and
+ make use of the calibration information from there.</p>
+ <br>
+ <span style="font-weight: bold;"></span>The <span
+ style="font-weight: bold; text-decoration: underline;">i1d3</span>
+ family of instruments can make use of display specific spectral
+ calibration information, which improves their accuracy when used on
+ displays of a similar type. The manufacturer provides 5 of these <b>.edr</b>
+ calibration files that cover various projectors and LCD displays
+ with the instrument on the install CD. The <span
+ style="font-weight: bold;">oeminst</span> utility allows you to
+ translate these files into Argyll <span style="font-weight: bold;">CCSS</span>
+ format, and install them where the measurement tools can
+ automatically find them, so that they can be selected using the <span
+ style="font-weight: bold;">-y</span> option.<br>
+ Also provided with Argyll in the ref directory is <span
+ style="font-weight: bold;">CRT.ccss</span> to cover CRT type
+ displays. <span style="font-weight: bold;">oeminst</span> allows
+ this file to be installed too.<br>
+ <br>
+ On Microsoft Windows or Apple OS X platforms, <span
+ style="font-weight: bold;">oeminst</span> will look to see if the
+ manufacturers files have been installed on the users machine, and
+ locate them from there. If the manufacturers files have not been
+ installed, or the user does not wish to install them, or no
+ manufacturers installation is available for the users platform (i.e.
+ Linux), then <span style="font-weight: bold;">oeminst</span> will
+ also attempt to locate the i1d3 installation CDROM, and make use of
+ the .edr files from there.<br>
+ <br>
+ If the .edr files are successfully located, then oeminst will
+ translate them to .ccss files and copy them into a <span
+ style="font-weight: bold;"></span> subdirectory of the users home
+ directory, or if the <span style="font-weight: bold;">-S l</span>
+ option is used, will store it in a system wide location. (the <a
+href="http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html">XDG
+
+
+
+
+
+
+
+
+
+
+ Base Directory specifications</a> are used as a basis for storing
+ the file). Programs that access instruments such as&nbsp; <span
+ style="font-weight: bold;">spotread</span>, <span
+ style="font-weight: bold;">dispcal</span> and <span
+ style="font-weight: bold;">dispread</span>, can then locate and
+ list the installed .ccss as possible choices for the <span
+ style="font-weight: bold;">-y</span> option.<br>
+ <br>
+ You can also install <b>CCSS</b> and <b>CCMX</b> files that you
+ have created using <a href="ccxxmake.html">ccxxmake</a>, and these
+ will then be listed and selected as a display type selection using
+ the <b>-y</b> option of the utilities that access colorimeter
+ devices. Note that <b>CCMX</b> selections will only show up for the
+ colorimeter model that they were created for.<br>
+ <br>
+ If you are going to use the same CCSS or CCMX file all the time,
+ then you may want to set the <a
+ href="file:///D:/src/argyll/doc/Environment.html">ARGYLL_COLMTER_CAL_SPEC_SET</a>
+ environment variable.<br>
+ <br>
+ <br>
+ To allow <span style="font-weight: bold;">oeminst</span> to install
+ files from the CDROM, it should be in a CD drive prior to running
+ oeminst. If your Linux system is not running automount, or your
+ automount is setup to mount CDROM's somewhere other than <span
+ style="font-style: italic;">/media</span>,<span style="font-style:
+ italic;"> /mnt/cdrom</span>, <span style="font-style: italic;">/media/cdrom</span>
+ or <span style="font-style: italic;">/cdrom</span>, then you will
+ have to mount the CDROM manually, and give oeminst the path to the
+ CDROM setup/setup.exe file as the argument <span style="font-style:
+ italic;">inputfile</span>.<span style="font-weight: bold;"><br>
+ <br>
+ NOTE </span>that under <span style="font-weight: bold;">OS X
+ 10.6</span> (Snow Leopard) and latter, you may need to run oeminst
+ as root to be able to mount the CDROM's ISO partition. The simplest
+ way of doing this is to use the "sudo" commands. e.g. "sudo
+ oeminst", which will then ask you to enter the root password.<br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/printcal.html b/doc/printcal.html
new file mode 100644
index 0000000..89264c5
--- /dev/null
+++ b/doc/printcal.html
@@ -0,0 +1,399 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>printcal</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme W. Gill">
+ </head>
+ <body>
+ <h2> profile/printcal</h2>
+ <h3>Summary</h3>
+ Create a printer linearization calibration file from <a
+ href="File_Formats.html#.ti3">.ti3</a> test chart patch values.<br>
+ <h3>Usage Summary</h3>
+ &nbsp;<span style="font-family: monospace;">printcal</span><small
+ style="font-family: monospace;"> [-<i>options</i>] [prevcal]
+ inoutfile<br>
+ &nbsp;<a href="#v">-v verbosity</a> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Set verbosity level<br>
+ </small><small style="font-family: monospace;">&nbsp;<a href="#p">-p</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; Plot graphs.<br>
+ &nbsp;<a href="#i">-i</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+ &nbsp; &nbsp; &nbsp;&nbsp; Initial calibration, set targets,
+ create .cal<br>
+ </small><small style="font-family: monospace;">&nbsp;<a href="#r">-r</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; Re-calibrate against previous .cal and create new
+ .cal</small><br style="font-family: monospace;">
+ <span style="font-family: monospace;"></span><small
+ style="font-family: monospace;">&nbsp;<a href="#e">-e</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+
+ &nbsp; &nbsp;&nbsp; Verify against previous .cal<br>
+ </small><small style="font-family: monospace;">&nbsp;<a href="#I">-I</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; Create imitation target from .ti3 and null
+ calibration</small><br>
+ <small style="font-family: monospace;">&nbsp;<a href="#d">-d</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; Go through the motions but don't write any files</small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#A">-A "manufacturer"</a><span
+ style="font-family: monospace;">&nbsp; Set the manufacturer
+ description string</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#M">-M "model"</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set the model
+ description string</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D "description"</a><span
+ style="font-family: monospace;">&nbsp;&nbsp; Set the profile
+ Description string </span><br style="font-family: monospace;">
+ <tt>&nbsp;</tt><tt><a href="#C">-C "copyright"</a></tt><tt>
+ &nbsp;&nbsp;&nbsp; Set the copyright string</tt><tt><br>
+ </tt><tt> </tt><tt>&nbsp;</tt><tt><a href="#x">-x# percent</a></tt><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set
+initial
+
+ maximum device % target (override auto)</tt><tt><br>
+ </tt></small><small><span style="font-family: monospace;"><small>&nbsp;<a
+ href="#m">-m# percent</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Set initial dev target to % of auto maximum<br>
+ </small>&nbsp;<a href="#n">-n# deltaE</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set initial white
+ minimum deltaE target<br>
+ &nbsp;<a href="#t">-t# percent</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set
+initial
+
+ 50% transfer curve percentage target<br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; # = c, r,
+ 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; First channel</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+m,
+g,
+1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Second channel</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+y,
+b,
+2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Third channel</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+k,&nbsp;&nbsp;&nbsp;
+3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Fourth
+
+ channel, etc.<br>
+ &nbsp;<a href="#a">-a</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Create
+an
+
+ Adobe Photoshop .AMP file as well as a .cal<br
+ style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p1">prevcal</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Base
+name
+
+ of previous .cal file for recal or verify.</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p2">inoutname</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Base
+name
+
+ of input .ti3 file, output .cal file</span><br>
+ </span><span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"></span></small><br>
+ <h3>Options<br>
+ </h3>
+ <b><a name="v"></a>-v</b>&nbsp; Turn on verbose mode. Gives progress
+ information as the calibration is created. An argument greater than
+ 1 increases the verbosity. Will also report the ideal power value to
+ apply to the test chart in targen.<br>
+ <br>
+ <a name="p"></a><span style="font-weight: bold;">-p</span> Turns on
+ plot mode. This causes various graphs to be plotted as the
+ calibration is created. The channels will be plotted in the graph
+ colors: Blue, Red, Yellow, Black, Green, Purple, Brown, Orange,
+ Grey, White.<br>
+ <br>
+ <a name="i"></a><span style="font-weight: bold;">-i</span> Select
+ initial calibration mode. Initial calibration mode allows setting
+ the targets for the calibration, such as maximum device percentage,
+ minimum white level, and the transfer curve shape. The second last
+ parameter <span style="font-weight: bold;"><span
+ style="font-weight: bold;"></span>prevcal</span> is not used in
+ this mode.<br>
+ <br>
+ <a name="r"></a><span style="font-weight: bold;">-r</span> Turns on
+ re-calibration mode. This is used for calibrations after the initial
+ one, where the aim is to return the devices response to the same
+ state as it was after the initial caibration. Parameters that affect
+ the calibration targets are ignored. The second last parameter <span
+ style="font-weight: bold;"><span style="font-weight: bold;"></span>prevcal</span>
+ is used to establish what the targets for the calibration are.<br>
+ <br>
+ <a name="e"></a><span style="font-weight: bold;">-e</span> Turns on
+ verify mode. In this mode the test chart input is verified agains
+ the expected response in the <span style="font-weight: bold;"><span
+ style="font-weight: bold;"></span>prevcal</span> file.<br>
+ <br>
+ <a name="I"></a><span style="font-weight: bold;">-I</span> Similar
+ to <span style="font-weight: bold;">-i</span>, except that rather
+ than creating a linear target curve and corresponding calibration,
+ it takes the given behaviour as an absolute target and create a
+ corresponding null set of calibration curves. This .cal can then be
+ used to recalibrate a similar device (or the same device at some
+ other time) to imitate the behaviour of the initial device. The
+ second last parameter <span style="font-weight: bold;"><span
+ style="font-weight: bold;"></span>prevcal</span> is not used in
+ this mode. Parameters that affect the calibration targets are
+ ignored.<br>
+ <br>
+ <a name="d"></a><span style="font-weight: bold;">-d</span> Disables
+ the writing of any files, causing printcal to go through the motions
+ without changing anything.<br>
+ <br>
+ <a name="A"></a>The <b>-A</b> parameter allows setting of the
+ device manufacturer description string in the calibration file. The
+ parameter should be a string that identifies the manufacturer of the
+ device being profiled. With most command line shells, it will be
+ necessary to enclose the parameter with double quotes, so that
+ spaces and other special characters are included in the parameter,
+ and not mistaken for the start of another flag or as a final command
+ line parameters. By default no device manufacturer description
+ string will be put in the calibration file.<br>
+ <br>
+ <a name="M"></a>The <b>-M</b> parameter allows setting of the
+ device mode description string in the calibration file. The
+ parameter should be a string that identifies the particular model of
+ device being profiled. With most command line shells, it will be
+ necessary to enclose the parameter with double quotes, so that
+ spaces and other special characters are included in the parameter,
+ and not mistaken for the start of another flag or as a final command
+ line parameters. By default no model description string will be put
+ in the calibration file.<br>
+ <br>
+ <a name="D"></a>The <b>-D</b> parameter allows setting of the
+ profile description string in the calibration file. The parameter
+ should be a string that describes the device and profile. On many
+ systems, it will be this string that will be used to identify the
+ profile from a list of possible profiles. With most command line
+ shells, it will be necessary to enclose the parameter with double
+ quotes, so that spaces and other special characters are included in
+ the parameter, and not mistaken for the start of another flag or as
+ a final command line parameter. By default no profile description
+ string will be put in the calibration file.<br>
+ <br>
+ <a name="C"></a>The <b>-C</b> parameter allows setting of the
+ profile copyright string in the calibration file. The parameter
+ should be a string that describes the copyright (if any) claimed on
+ the profile being generated. With most command line shells, it will
+ be necessary to enclose the parameter with double quotes, so that
+ spaces and other special characters are included in the parameter,
+ and not mistaken for the start of another flag or as a final command
+ line parameters. By default no copyright string will be put in the
+ calibration file.<br>
+ <br>
+ <a name="x"></a> The <b>-x</b> parameter allows overriding the
+ default auto maximum device target value computed from the raw
+ device response for the initial calibration. The default uses a
+ heuristic to decide when the response of the device to each channels
+ colorant value reaches the point of diminishing returns, while the <span
+ style="font-weight: bold;">-x</span> parameter allows this default
+ to be overridden. The <span style="font-weight: bold;">-x</span>
+ paramater can be used multiple times, once for each channel that is
+ being set. The <span style="font-weight: bold;">-x</span> should be
+ followed by the channel number between 0 and 15, or the aliases <span
+ style="font-weight: bold;">r</span>, <span style="font-weight:
+ bold;">g</span> or <span style="font-weight: bold;">g</span>, or
+ <span style="font-weight: bold;">c</span>, <span
+ style="font-weight: bold;">m</span>, <span style="font-weight:
+ bold;">y</span> or <span style="font-weight: bold;">k,</span> and
+ the channel number should then be followed by the device value as a
+ percentage. <span style="font-weight: bold;">NOTE</span> that you
+ will probably get sub-optimal results if you force a device maximum
+ that is beyond the point of maximum response of a device channel,
+ since this will have the effect of <span style="text-decoration:
+ underline;">reducing</span> the device response. If you want to
+ set a conservative target to allow for recalibration later, see the
+ <b>-m</b> flag below.<br>
+ <br>
+ <a name="m"></a> The <b>-m</b> parameter allows modifying the
+ default auto maximum device target value for the initial
+ calibration. The auto maximum is computed as described above, and is
+ then scaled by the <b>-m</b> parameter value. Typically this will
+ be a scale down (ie. <b>90%</b>) to allow some margin to increase
+ the channel value if the channel density drops in a future
+ recalibration. Scaling the maximum down will reduce gamut, but
+ allows scope for stable behaviour using calibration. The <span
+ style="font-weight: bold;">-m</span> paramater can be used
+ multiple times, once for each channel that is being set. The <span
+ style="font-weight: bold;">-m</span> should be followed by the
+ channel number between 0 and 15, or the aliases <span
+ style="font-weight: bold;">r</span>, <span style="font-weight:
+ bold;">g</span> or <span style="font-weight: bold;">g</span>, or
+ <span style="font-weight: bold;">c</span>, <span
+ style="font-weight: bold;">m</span>, <span style="font-weight:
+ bold;">y</span> or <span style="font-weight: bold;">k,</span> and
+ the channel number should then be followed by the deltaE value.<span
+ style="font-family: monospace;"></span><br>
+ <br>
+ <a name="n"></a> The <b>-n</b> parameter allows overriding the
+ default minimum deltaE of a colorant to white of 0. This can be used
+ to set a minimum colorant level in order to emulate media darker or
+ of a different tint. The <span style="font-weight: bold;">-n</span>
+ paramater can be used multiple times, once for each channel that is
+ being set. The <span style="font-weight: bold;">-n</span> should be
+ followed by the channel number between 0 and 15, or the aliases <span
+ style="font-weight: bold;">r</span>, <span style="font-weight:
+ bold;">g</span> or <span style="font-weight: bold;">g</span>, or
+ <span style="font-weight: bold;">c</span>, <span
+ style="font-weight: bold;">m</span>, <span style="font-weight:
+ bold;">y</span> or <span style="font-weight: bold;">k,</span> and
+ the channel number should then be followed by the deltaE value.<span
+ style="font-family: monospace;"></span><br>
+ <br>
+ <a name="t"></a> The <b>-t</b> parameter allows setting a target
+ linearization curve that is other than purely visual linear. The
+ default is to create a calibration curve that results in a perfectly
+ even change in output for each change in the calibrated device
+ value, as measured by steps in delta E94. The <span
+ style="font-weight: bold;">-x</span> parameter allows setting a
+ target curve above or below the perfectly visual linear, by setting
+ the aim value at 50% input. An aim higher than 50% will cause that
+ channel to become more intense by the 50% mark, while a value lower
+ than 50% will cause the channel to become less intense by the 50%
+ mark than perfectly linear.The <span style="font-weight: bold;">-x</span>
+ should be followed by the channel number between 0 and 15, or the
+ aliases <span style="font-weight: bold;">r</span>, <span
+ style="font-weight: bold;">g</span> or <span style="font-weight:
+ bold;">g</span>, or <span style="font-weight: bold;">c</span>, <span
+ style="font-weight: bold;">m</span>, <span style="font-weight:
+ bold;">y</span> or <span style="font-weight: bold;">k,</span> and
+ the channel number should then be followed by the device value as a
+ percentage.<br>
+ <br>
+ <a name="a"></a><span style="font-weight: bold;">-a</span> Creates
+ an Adobe Photoshop <span style="font-weight: bold;">.AMP</span>
+ format curves file as well as a .cal.<br>
+ <span style="font-weight: bold;"></span><br>
+ <a name="p1"></a> The optional second last parameter is the file
+ base name for a previous <a href="File_Formats.html#CAL">.cal</a>
+ calibration file, used as the target reference for recalibrate and
+ verify modes. <br>
+ <br>
+ <a name="p2"></a> The final parameter is the file base name for the
+ <a href="File_Formats.html#.ti3">.ti3</a> input test point data, and
+ the resulting <a href="File_Formats.html#CAL">.cal</a> calibration
+ file output. <br>
+ <h3><a name="DISCUSSION"></a>Discussion</h3>
+ <span style="font-weight: bold;">Printcal</span> is a tool for
+ creating per device channel linearization curves for printing
+ devices.<br>
+ <br>
+ As input it takes a .ti3 file containing the results of printing a
+ test chart on the <span style="text-decoration: underline;">non-color
+
+ managed</span>, <span style="text-decoration: underline;">non-calibrated</span>
+ device, and measuring it. The test chart consists of step wedges for
+ each of the device primary colors, from the media white to full
+ individual colorant intensity.<br>
+ <br>
+ For the initial calibration (<span style="font-weight: bold;">-i</span>),
+the
+range
+
+ of device values to be used and the shape of the target
+ linearization curve are established, as well as creating the first
+ set of calibration curves. For subsequent re-calibrations (<span
+ style="font-weight: bold;">-r</span>), the calibration curves aim
+ to reproduce the same response as the original calibration. If a
+ test chart is printed with calibration enabled and then is measured,
+ it can be used to verify the calibration against the expected
+ response (<span style="font-weight: bold;">-e</span>).<br>
+ <br>
+ As each colorant steps through the test wedge patches from media
+ white, they trace out a measured locus in CIE L*a*b* colorspace.
+ Each channel response is evaluated by computing the CIE DeltaE to
+ media white of the response to a change in each individual channel
+ of each locus. This measure is used to determine when the devices
+ response to a colorant level is reaching diminishing returns,
+ setting a maximum colorant value. This measure can also be used to
+ set a minimum colorant value for the purposes of emulating a
+ different media color. The default maximum and minimum values for
+ each colorant can be overridden using the <span style="font-weight:
+ bold;">-x</span> and <span style="font-weight: bold;">-n</span>
+ parameters. The automatically determined maximum may be modified
+ (scaled) using the <b>-m</b> parameter, which can be useful in
+ allowing some margin for future calibrations to compensate for a
+ drop in density.<br>
+ <br>
+ The actual linearization uses a subtly different measure, which is
+ the CIE DelataE 94 along each colorant response locus, ensuring that
+ after linearization each step in colorant value is subjectively
+ even. The linearization aim can be altered from a purely linear
+ curve by using the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-t</span></span> parameters.<br>
+ <br>
+ After the initial calibration, the device can be re-calibrated (<span
+ style="font-weight: bold;">-r</span>) by printing a calibration
+ test chart under the same conditions as the initial one, but with
+ the calibration aimed at reproducing the same response as the
+ initial calibration, rather that setting new targets.<br>
+ <br>
+ The calibration can be verified (<span style="font-weight: bold;">-e</span>)
+ by printing a calibration test chart on <span
+ style="text-decoration: underline;">non-color managed</span>, <span
+ style="text-decoration: underline;"></span>but calibrated device,
+ the verification evaluating any discrepancy between the device
+ response achieved, and the device response expected. For a numerical
+ evaluation the verbose flag (<span style="font-weight: bold;">-v</span>)
+ should be used, and for a visual evaluation the plot flag (<span
+ style="font-weight: bold;">-p</span>) should be used.<br>
+ <br>
+ If there are several devices of the same or similar model, then one
+ device can be used to set the initial calibration target, and then
+ the other devices can be re-calibrated against the same .cal file,
+ to create matching responses. An alternative to creating an initial
+ linear target for calibration, is to use the <span
+ style="font-weight: bold;">-I</span> option with an initial
+ device, which sets the initial target to be that devices absolute
+ response. Naturally the corresponding calibration will be linear
+ (null). The calibration target can then be used to later return that
+ device to its initial response, or to make another similar device
+ have the same response. Note though, that bad things will happen if
+ the imitated devices response is non-monotonic, or if on
+ re-calibration the device is unable to reach the same density
+ levels.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/printtarg.html b/doc/printtarg.html
new file mode 100644
index 0000000..5faab76
--- /dev/null
+++ b/doc/printtarg.html
@@ -0,0 +1,681 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>printtarg</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>target/printtarg</b></h2>
+ <h3>Summary</h3>
+ Create a PostScript (PS), Embedded PostScript (EPS) or Tagged Image
+ File Format (TIFF) file containing profile test patch values, ready
+ for printing.<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">printtarg [options]
+ basename</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Verbose mode</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#i">-i 20 | 22 | 41 | 51 |
+ SS | i1 | CM</a><span style="font-family: monospace;"> Select
+ target instrument (default DTP41)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+20
+=
+DTP20,
+22
+=
+
+
+ DTP22, 41 = DTP41, 51 = DTP51, SS = SpectroScan,<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ i1 = i1Pro, CM = ColorMunki</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#a">-a scale</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Scale
+patch
+and
+spacer
+size
+
+
+ by factor (e.g. 0.857 or 1.5 etc.)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#A">-A scale</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Scale
+spacer
+size
+by
+additional
+
+
+ factor (e.g. 0.857 or 1.5 etc.)</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#h">-h</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Use hexagon patches for SS, double density for CM</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#r">-r</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Don't randomize patch location</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#s">-s</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Create
+a
+scan
+image
+recognition
+
+
+ (.cht) file</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#S">-S</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Same
+as
+-s,
+but
+don't
+
+
+ generate wide orientation strip.</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Force colored spacers</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#b">-b</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Force B&amp;W spacers</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#n">-n</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Force no spacers</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#f">-f</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Create PostScript DeviceN Color fallback</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#w">-w g|r|s|n</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ White colorspace encoding DeviceGray (def), DeviceRGB,
+ Separation or DeviceN</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#k">-k g|c|s|n</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Black colorspace encoding DeviceGray (def), DeviceCMYK,
+ Separation or DeviceN<br>
+ &nbsp;<a href="#o">-o k|n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ CMY colorspace encoding DefiveCMYK (def), inverted DeviceRGB or
+ DeviceN<br style="font-family: monospace;">
+ </span> <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#e">-e</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Output EPS compatible file<br>
+ &nbsp;<a href="#t">-t [res]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Output
+8
+bit
+TIFF
+raster
+
+
+ file, optional res DPI (default 200)<br>
+ &nbsp;<a href="#T">-T [res]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Output
+16
+bit
+TIFF
+raster
+
+
+ file, optional res DPI (default 200)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;<a
+ href="#C">-C</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Don't use TIFF compression</span></small><br>
+ <small><span style="font-family: monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+TIFF
+alpha
+N
+channels
+
+
+ more than 4<br>
+ &nbsp;<a href="#D">-D</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Dither 8 bit TIFF values down from 16 bit<br>
+ &nbsp;<a href="#Q">-Q nbits</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Quantize
+test
+values
+to
+fit
+
+
+ in nbits<br>
+ </span></small><small style="font-family: monospace;">&nbsp;<span
+ style="text-decoration: underline;">-</span><a href="#K">K
+ file.cal</a>&nbsp;&nbsp;&nbsp;&nbsp; Apply printer calibration
+ to patch values and include in .ti2<br>
+ &nbsp;<a href="#I">-I file.cal</a>&nbsp;&nbsp;&nbsp;&nbsp; Include
+ calibration in .ti2 (but don't apply it)<br style="font-family:
+ monospace;">
+ </small><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#R">-R rsnum</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Use given random start number</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#x">-x pattern</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Use given strip indexing pattern (Default = "A-Z, A-Z")</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#y">-y pattern</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Use given patch indexing pattern (Default = "0-9,@-9,@-9;1-999")</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#m">-m margin</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set
+
+
+ a page margin in mm (default 6.0 mm)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#M">-M margin</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ </span></small><small><span style="font-family: monospace;">Set a
+ page margin in mm and include it in TIFF</span><span
+ style="font-family: monospace;"></span></small><br>
+ <small><span style="font-family: monospace;">&nbsp;<a href="#P">-P</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Don't limit strip length</span></small><br>
+ <small><span style="font-family: monospace;">&nbsp;<a href="#L">-L</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Suppress
+any
+left
+paper
+clip
+
+
+ border<br style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p">-p size</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Select page size from:</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+A4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ [210.0 x 297.0 mm]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+A4R&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ [297.0 x 210.0 mm]<br>
+ &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+A3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ [297.0 x 420.0 mm] (default)<br>
+ &nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ A2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [420.0 x 594.0 mm]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Letter&nbsp;&nbsp; [215.9 x 279.4 mm]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; LetterR&nbsp; [279.4 x
+ 215.9 mm]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+
+ &nbsp; &nbsp;&nbsp;&nbsp; Legal&nbsp;&nbsp;&nbsp; [215.9 x 355.6
+ mm]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+
+ &nbsp;&nbsp; 4x6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [101.6 x 152.4
+ mm]<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+11x17&nbsp;&nbsp;&nbsp;
+
+
+ [279.4 x 431.8 mm]<br style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#pp">-p WWWxHHH</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Custom size, WWW mm wide by HHH mm high<br>
+ </span></small><small style="font-family: monospace;"></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span>&nbsp; <span
+ style="font-family: monospace;"></span><a style="font-family:
+ monospace;" href="#p1"><i>basename</i></a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ Base name for input(</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti1">.ti1</a><span style="font-family:
+ monospace;">), output(</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti2">.ti2</a><span style="font-family:
+ monospace;">) and output(.ps/.eps/.tif)</span></small><br>
+ <h3>Usage Details and Discussion</h3>
+ <b> printtarg</b> is used to generate a PostScript or TIFF print
+ file from device test values in a .ti1 file. It output both a
+ PostScript/EPS/TIFF file, and a .ti2 file containing the device test
+ values together with the layout information needed to identify the
+ patch location. This module can also generate the image recognition
+ templates needed to read the print targets in using a scanner.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag turns on verbose mode. Prints
+ information about how many patches there are in a row, how many
+ patches in a set,&nbsp; and how many pages will be generated. Good
+ for figuring out what the magic number of patches should be for a
+ particular page size.<br>
+ <br>
+ <a name="i"></a> The <b>-i</b> parameter should be used to tell
+ printtarg which instrument it should lay the patches out for. Each
+ instrument has a slightly different requirement, and will lead to a
+ different number of patches ending up on a particular page size. For
+ a generic type of chart, try <span style="font-weight: bold;">SS</span>.<br>
+ <br>
+ <a name="a"></a><a name="A"></a> <span style="font-weight: bold;">-a,
+-A:
+
+
+ </span>Normally, <b>printtarg</b> prints test patches that are the
+ minimum size that can be reliably and accurately read by the
+ instrument.&nbsp; For some media, it might be desirable to use test
+ patches that are larger than this minimum (e.g. if the media has
+ poor registration, gets physically distorted in the print production
+ process, or if it has a coarse screen, and there are few samples per
+ patch), and the <span style="font-weight: bold;">-a</span> flag
+ should be given an argument greater than 1.0 to increase the patch
+ length, patch width, and spacer size between patches, if it is
+ appropriate for the type of instrument. A value of 1.5 would make
+ the patch 50% larger for instance. For the strip reading instruments
+ the patch is made longer, the strip spacing remaining the same,
+ while for XY scanning instruments, both the width and height will be
+ increased. If a value less than 1.0 is given as an argument, then
+ the patches will be made smaller. For instance, using the
+ SpectroScan instrument it is possible to reduce the test patches to
+ 6mm rather than the default 7mm by supplying an argument of 0.857.
+ Note that this make lining up of the scan head very critical, and
+ increases the amount of bleed through from adjacent squares. For an
+ instrument that needs color spacers between patches, <span
+ style="font-weight: bold;">-a scale</span> also scales the spacer
+ length. For some situations, this may be insufficient, and the&nbsp;<span
+ style="font-weight: bold;"> -A scale</span> option can be used to
+ additionally scale the spacer length.<br>
+ Note that the for the <span style="font-weight: bold;">DTP20</span>
+ only <span style="font-weight: bold;">-a </span>values of 1.0,
+ 1.08, 1.54, 1.92, 2.0 and that the patch width will be made no
+ smaller than its length.<br>
+ <br>
+ <a name="h"></a> Normally, <b>printtarg</b> creates a regular grid
+ of test patches, but for instruments that support arbitrary X, Y
+ addressing (such as the SpectroScan). For the <span
+ style="font-weight: bold;">SpectroScan</span> it can also create a
+ chart using regular hexagonal patches, allowing more patches to be
+ fitted into a single sheet if the <span style="font-weight: bold;">-h</span>
+ flag is used.&nbsp; For the <span style="font-weight: bold;">ColorMunki</span>
+ instrument, <span style="font-weight: bold;">-h</span> doubles the
+ normal number of patches is printed by halving the row width. The
+ patches are also staggered to improve the detection of a poor scan.<br>
+ <br>
+ <a name="r"></a> Normally, <b>printtarg</b> randomizes the patch
+ locations, which helps strip reading instruments detect patch
+ boundaries and the direction the strip was read in, as well as being
+ able to detect incorrect strips being fed into strip reading
+ instruments, and also assists in randomizing any systematic printing
+ errors introduced into the test chart due to print engine
+ unevenness, inkjet banding, or printing press ink key settings etc.
+ The <b>-r</b> flag turns this off, and lays the test squares out in
+ the order the values appear in, in the .ti1 file. Note that if you
+ turn this off you probably want to <a href="chartread.html#B">disable
+
+
+ bi-directional</a> strip reading in instruments such as the i1pro.<br>
+ <br>
+ <a name="s"></a> The <b>-s</b> flag does two things. One is that it
+ causes printtarg to output a chart recognition file (<a
+ href="File_Formats.html#.cht">.cht</a>) so that <a
+ href="scanin.html"> scanin</a> can recognize the chart, and
+ convert rasterized patches into patch values, and the second is that
+ is expands the size of the leading row of patches by 50%, to help
+ make sure that each sheet can be oriented correctly by <a
+ href="scanin.html"> scanin</a>. <a name="S"></a>If <b>-S</b> is
+ used rather than <b>-s</b>, then the recognition chart will be
+ created, but the leading row will be the same size as all the other
+ rows.<br>
+ <br>
+ <a name="c"></a> For strip reading instruments, the contrast with
+ the spacers is important in ensuring that a reading will be
+ successful. Normally <span style="font-weight: bold;">printtarg</span>
+ ensures this by printing optimally contrasting colored spacers
+ between each measurement patch. The <b>-c</b> flag is therefore the
+ default behaviour. <a name="b"></a>If the <b>-b</b> flag is used,
+ then contrasting neutral colored spacers will be used, but these
+ generally work less reliably than colored spacers. <a name="n"></a>The
+
+ <b>-n</b> flag will cause spacers to be omitted, which may still
+ work with smaller numbers of test values when the patch selection is
+ randomized, but won't work successfully when a large number of test
+ points is being used (&gt;200), or when the patches are not
+ randomized in location.<br>
+ <br>
+ <a name="f"></a><b>-f</b>: When creating a test chart for more than
+ CMYK inks, a PostScript file normally contains color settings that
+ use the PostScript level 3 "Device N" color specifications. Such
+ color specifications have a "fallback" color, for PostScript
+ interpreters that don't handle Device N specifications. Such
+ fallback colors are normally set to a grayscale estimate of the
+ patch color, so that it is possible to tell if the PostScript
+ interpreter is not rendering the Device N values correctly. <a
+ name="f"></a>The <b>-f</b> flag, causes the fallback color to be
+ a color estimate of the Device N test patch color, which is useful
+ for diagnostic purposes.<br>
+ <br>
+ <a name="e"></a> The <b>-e</b> flag gives EPS output, rather than
+ PostScript, allowing the charts to be included in other
+ applications. Because EPS disallows the showpage command, multiple
+ EPS files will result for a multi-page test chart, each one having a
+ two digit number sequence in it's name, so if the input file name is
+ <span style="font-weight: bold;">chart</span>, then file <span
+ style="font-weight: bold;">chart.ti1</span> will be read, and file
+ <span style="font-weight: bold;">chart.ti2</span> written, together
+ with <span style="font-weight: bold;">chart.eps</span> if there is
+ only one page, or <span style="font-weight: bold;">chart_01.eps</span>,
+ <span style="font-weight: bold;">chart_02.eps</span>, etc. if there
+ is more than one page.<br>
+ <br>
+ <a name="t"></a><a name="T"></a><span style="font-weight: bold;">-t
+ [res], -T [res]</span> The <b>-t</b> flag gives TIFF raster
+ output rather than PostScript, allowing the charts to be printed to
+ systems that do not accept PostScript input. Because few systems
+ understand multi-page TIFF files, multiple TIFF files will result
+ for a multi-page test chart, each one having a two digit number
+ sequence in it's name, so if the input file name is <span
+ style="font-weight: bold;">chart</span>, then file <span
+ style="font-weight: bold;">chart.ti1</span> will be read, and file
+ <span style="font-weight: bold;">chart.ti2</span> written, together
+ with <span style="font-weight: bold;">chart.eps</span> if there is
+ only one page, or <span style="font-weight: bold;">chart_01.tif</span>,
+ <span style="font-weight: bold;">chart_02.tif</span>, etc. if there
+ is more than one page. By default the resolution of the chart will
+ be 100 Dots Per Inch (DPI), but this can be changed by providing an
+ optional DPI argument after the <span style="font-weight: bold;">-t</span>
+ or <span style="font-weight: bold;">-T</span> flag. If the <span
+ style="font-weight: bold;">-t</span> flag is used, than an 8 bit
+ per component TIFF file will be created. If the <span
+ style="font-weight: bold;">-T</span> flag is used, then a 16 bit
+ per component TIFF file will be created.<br>
+ <br>
+ <a name="C"></a><span style="font-weight: bold;">-C:</span> Normally
+ the TIFF files created will be compressed using LZW compression to
+ save space. Some systems may not support this compression, so it can
+ be disabled by using the <span style="font-weight: bold;">-C</span>
+ flag.<br>
+ <br>
+ <a name="N"></a><span style="font-weight: bold;">-N:</span> When
+ creating TIFF files with more than 4 colorants, the normal Separated
+ mode is used. Some systems don't cope well with extra colorants
+ presented in this manner, and the <span style="font-weight: bold;">-N</span>
+ flag causes all the channels greater than 4 to be labelled as
+ "Alpha" channels, which may be more palatable.<br>
+ <br>
+ <a name="D"></a><span style="font-weight: bold;">-D:</span> When
+ creating TIFF files with 8 bit output, dither the values to give
+ effective 16 bit precision. Note this is applied after any
+ quantization of the test values (see <a href="#Q">-Q</a>). Note
+ that this might interfere (i.e. give alias/moire patterns) in
+ printed output if the printer uses screening that happens to clash.
+ Note also that dithering is effectively linearly interpolating
+ between the 8 bit values using spatial averaging, and that therefore
+ the device response may also be a linear interpolation between its 8
+ bit output values, adding no effective extra precision to the device
+ measurement. <br>
+ <br>
+ <a name="Q"></a><span style="font-weight: bold;">-Q:</span> Normally
+ the target device values are floating point numbers that may get
+ rounded and quantized in the process of printing them or reproducing
+ them on the printing or display device. If some of this quantization
+ can be accounted for, it may improve the accuracy of the resulting
+ profile, and the <span style="font-weight: bold;">Q</span>
+ parameter allows this quantization to be specified. The parameter is
+ the number of binary digits (bits) that the device values should be
+ quantized to. In many systems the right value would be 8 bits. Note
+ that if 8 bit TIFF<span style="font-weight: bold;"></span> output is
+ selected (<span style="font-weight: bold;">-t</span>) without
+ dithering (no <span style="font-weight: bold;">-D) </span>that the
+ values will by default be quantized to 8 bits, and that if 16 bit
+ TIFF<span style="font-weight: bold;"></span> output is selected (<span
+ style="font-weight: bold;">-T</span>) or 8 bit TIFF with dithering
+ (<span style="font-weight: bold;">-D) </span>that the values will
+ by default be quantized to 16 bits.<br>
+ <br>
+ <a name="K"></a> The <b>-K file.cal</b> parameter specifies a
+ printer calibration file created by <a href="printcal.html">printcal</a>,
+ and the supplied calibration curves will be applied to the test
+ patch values. This allows profiling of a printing system that
+ doesn't natively support calibration. The calibration curves will
+ also be included in the resulting .ti2 file, so that they can be
+ passed through to .ti3 file and ICC profile, to allow accurate
+ computation of ink limits.<br>
+ <br>
+ <a name="I"></a> The <b>-I file.cal</b> parameter specifies a
+ printer calibration file created by <a href="printcal.html">printcal</a>,
+ and the calibration curves will be included in the included in the
+ resulting .ti2 file, so that they can be passed through to .ti3 file
+ and ICC profile, to allow accurate computation of ink limits. The
+ calibration <span style="font-weight: bold;">is not applied</span>
+ to the test patch values, but is assumed to be applied somewhere
+ else in the printing workflow when printing the profile test chart.<br>
+ <br>
+ <a name="R"></a> The <b>-R</b> parameter allows setting the random
+ layout seed. Normally the seed is chosen at random, but sometimes it
+ is useful to be able to generate a chart with the same layout, so a
+ specific seed can be specified this way. The seed (ID) used to
+ generate a chart is recorded in the .ti2 file, and is also in the
+ label printed on the right hand side of each chart.<br>
+ <br>
+ <a name="x"></a> The <b>-x</b> parameter allows specifying the
+ labelling sequence used for strips (e.g. the X axis of the chart).
+ By default this will be a character sequence A, B, C .. Z. AA, AB,
+ AC .. ZZ, but this can be changed by specifying an alternate
+ labelling sequence pattern. The pattern specifies the labelling
+ sequence as follows: First comes the definition of the symbols for
+ each digit location, least significant to most significant, each
+ digit separated by the ',' character. Note that space is a valid
+ character. The number of definitions declares the maximum number of
+ digits. For example, for a 2 digit numerical sequence: "0123456789,
+ 123456789" would define 0..99 with the most significant digit
+ suppressed when it is 0 (because it uses a space rather than 0).
+ Ranges can be used for brevity: "0-9, 1-9". As a special case, the
+ '@' character can be used to instead of '0' to indicate suppression
+ of the leading zero: "0-9,@-9". Leading ' ' characters in the
+ resulting generated sequence are omitted. Optionally following this
+ and delimited by a ';' character, are the definitions of valid
+ segments of the index sequence. For instance, to define the index
+ range to be 1..19, 30..39 one could use the pattern "0-9,
+ 1-9;1-19,30-39". Of course most of the time an alphabetic sequence
+ will be wanted, to distinguish it from the numerical sequence used
+ to number the patches in a strip. For a sequence A, B, C .. AA, AB,
+ AC etc. (the default used in Argyll), the following patter would be
+ used: "A-Z, A-Z". For a some ECI2002R charts that skip columns Y and
+ Z, and use a leading numeric digits for addressing strips over 26,
+ the following might be used: "A-Z, 2-9;A-X,2A-9Z".<br>
+ <br>
+ <a name="y"></a> The <b>-y</b> parameter allows specifying the
+ labelling sequence used for patches (e.g. the Y axis of the chart).
+ By default this will be a number sequence 1, 2, ..10, 11, ... 999,
+ but this can be changed by specifying an alternate labelling
+ sequence pattern. See the above description for the labelling
+ sequence encoding.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that the pattern chosen
+ for the X and Y axes of the chart must be distinguishable, e.g. if
+ they are both numbers or both letters then reading the chart will
+ fail.<br>
+ <br>
+ <a name="w"></a> The <b>-w</b> parameter changes how a white
+ colorspace test chart (ie. Additive Grey monochrome) will be
+ represented in the Postscript or TIFF output. The default is to use
+ the DeviceGray representation (<span style="font-weight: bold;">-wg</span>),
+
+ but Device RGB can also be used, where the R, G &amp;B values are
+ all set to the same value (<span style="font-weight: bold;">-wr</span>),
+
+ a <span style="font-weight: bold;">White</span> separation color
+ can be specified (<span style="font-weight: bold;">-ws</span>), or a
+ DeviceN <span style="font-weight: bold;">White</span> color can be
+ used (<span style="font-weight: bold;">-wn</span>).<br>
+ <br>
+ <a name="k"></a> The <b>-k</b> parameter changes how a black
+ colorspace test chart (ie. Subtractive Grey monochrome ) will be
+ represented in the Postscript or TIFF output. The default is to use
+ the DeviceGray representation (<span style="font-weight: bold;">-kg</span>),
+but
+Device
+CMYK
+can
+also
+
+
+ be used, where the CMY values are zero, and just the K channel is
+ used (<span style="font-weight: bold;">-kc</span>), a <span
+ style="font-weight: bold;">Black</span> separation color can be
+ specified (<span style="font-weight: bold;">-ks</span>), or a
+ DeviceN <span style="font-weight: bold;">Black</span> color can be
+ used (<span style="font-weight: bold;">-kn</span>).<br>
+ <br>
+ <a name="o"></a> The <b>-o</b> parameter changes how a CMY
+ colorspace test chart will be represented in the Postscript or TIFF
+ output. The default is to use the DeviceCMYK representation (<span
+ style="font-weight: bold;">-ok</span>) where the K value is always
+ zero, or inverted Device RGB (<span style="font-weight: bold;">-or</span>),
+ or as a 3 channel DeviceN colorsoace can be used (<span
+ style="font-weight: bold;">-on</span>).<br>
+ <br>
+ <a name="m"></a> The <b>-m</b> parameter sets the page margin for
+ all sides. If the printer has print margins larger than the default
+ assumed by <span style="font-weight: bold;">printtarg,</span> then
+ critical parts of the test chart may be cropped or scaled, and not
+ printed properly.<span style="font-weight: bold;"></span> Increasing
+ the margin from the default of 6 mm to 10 or 15 mm, may alleviate
+ this problem. (Note that the number of patches per page may be
+ reduced as a consequence.) Decreasing the margin below 6 mm may be
+ possible for printers that have smaller or no margins, increasing
+ the number of patches possible on each page. A TIFF chart raster
+ will be the size of the paper minus the margin, so that it can be
+ placed on a page that size without cropping or inadvertent scaling.<br>
+ <br>
+ <a name="M"></a> The <b>-M</b> parameter sets the page margin for
+ all sides the same as <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-m</span></span>, but for a TIFF
+ chart the margin will be <span style="font-weight: bold;">included</span>
+ in the raster, meaning that the TIFF will have to be printed&nbsp;
+ right to the edge of the paper, or on paper larger than the raster
+ size. (Having the raster be the full page size may be useful in
+ certain situations.)<br>
+ &nbsp; <br>
+ <a name="P"></a> The <b>-P</b> flag disables any normal limiting of
+ strip length that would normally be imposed due to guide or
+ instrument limitations. There is still an upper limit of around 500
+ patches or 2Meters though. Note that if you generate a strip larger
+ than the instrument can cope with, it may be unable to read the
+ strip.<br>
+ <br>
+ <a name="L"></a> The <b>-L</b> flag suppresses the left margin that
+ is added for instruments that have a paper holder that has a clip to
+ hold the chart in place, while it is being read. (Currently this is
+ only the Eye-One Pro).<br>
+ <br>
+ <a name="p"></a> The <b>-p</b> parameter specifies the paper size.
+ The size can either be one of the default sizes, <a name="pp"></a>or
+
+
+ can be specified in millimeters. Limitations of the instrument may
+ limit the maximum number of patches in a strip. For SpectroScan, a
+ size of &nbsp;A4 or Letter (or smaller) should be used. Useful
+ combinations of number of patches and paper size are listed <a
+ href="targen.html#Table">here</a>. The printed parts of the chart
+ will be the size of paper minus the page margin. A TIFF chart will
+ be the size of the paper minus the margin, so that it can be placed
+ on a page that size without cropping or inadvertent scaling, but
+ also see the <span style="font-weight: bold;">-M</span> flag.<br>
+ <br>
+ <a name="p1"></a><i>basename</i> is the base file name of the&nbsp;<a
+ href="File_Formats.html#.ti1">.ti1</a> file that contains the
+ device values to be put on the test chart. <b>printtarg</b> will
+ output a <i>basename.ps</i> or one or more <i>basename_NN.eps</i>
+ or <i>basename_NN.tif </i>files files that should be printed on
+ the devices, as well as a <i>basename.ti2</i> file that contains
+ both the device test point values, and the location of the
+ corresponding patch on the test chart. If the <b>-s</b> or <b>-S</b>
+ flag was specified, then&nbsp; one or more <i>basename_NN.cht</i>
+ files will also be generated.<br>
+ <br>
+ <a href="http://www.ghostgum.com.au/">GSview</a> or <a
+ href="http://www.cs.wisc.edu/%7Eghost/gv/index.htm">GhostView</a>
+ are good programs to use to check what the PostScript or EPS file
+ will look like, without actually printing it out. Alternatively, use
+ the TIFF raster output for non-PostScript printers.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/profcheck.html b/doc/profcheck.html
new file mode 100644
index 0000000..ebb719b
--- /dev/null
+++ b/doc/profcheck.html
@@ -0,0 +1,251 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>profcheck</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>profile/profcheck</b></h2>
+ <h3>Summary</h3>
+ Check an&nbsp;<a href="File_Formats.html#ICC">ICC</a> profile
+ against&nbsp;<a href="File_Formats.html#.ti3">.ti3</a> test chart
+ data.<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">profcheck&nbsp;
+ [-options]
+ data.ti3 iccprofile.icm</span><br style="font-family:
+ monospace;">
+ &nbsp;
+ <span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">-v
+ [level]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Verbosity level (default 1), 2 to print each DE</span></small><small><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;-c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+Show
+ CIE94 delta E values</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-k
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; Show CIEDE2000 delta E values</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+create
+ VRML visualization (iccprofile.wrl)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+Use
+ VRML axes<br>
+ &nbsp;-m&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Make
+VRML
+ lines a minimum of 0.5<br style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;-e&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Color
+vectors
+ acording to delta E</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-d
+ devval1,deval2,devvalN</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+Specify
+ a device value to sort
+ against</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+Sort
+ device value by PCS/Lab target</span><br style="font-family:
+ monospace;">
+ &nbsp;
+ <span style="font-family: monospace;">-f
+ [illum]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use Fluorescent Whitening
+ Agent compensation [opt. simulated inst. illum.:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or
+ file.sp]<br>
+ &nbsp;-i illum&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Choose
+ illuminant for computation of CIE XYZ from spectral data &amp;
+ FWA:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp</span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;-o
+ observ&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; Choose CIE
+ Observer
+ for spectral data:</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 1931_2
+ </span></small><small><span style="font-family: monospace;">(def.)</span></small><small><span
+ style="font-family: monospace;">,
+ 1964_10, S&amp;B
+ 1955_2, shaw, J&amp;V 1978_2</span></small><small><span
+ style="font-family: monospace;"><br>
+ &nbsp;-I intent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; r = relative
+ colorimetric, a = absolute (default)<br style="font-family:
+ monospace;">
+ </span><i style="font-family: monospace;"> &nbsp;data.ti3</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;
+ Test
+ point data file</span><br style="font-family: monospace;">
+ <i style="font-family: monospace;">&nbsp;iccprofile.icm</i><span
+ style="font-family: monospace;">&nbsp; Profile to check</span></small>
+ <br>
+ <h3>Usage Details and Discussion</h3>
+ <b> profcheck</b> provides a way of checking how well an&nbsp;<a
+ href="File_Formats.html#ICC">ICC</a> profile conforms to the test
+ sample data that was used to create it (or other test samples
+ that are from the same device). This is the same sort of check done
+ within
+ the profile making tool (<a href="colprof.html">colprof</a>), but
+ having a
+ separate tool provides some flexibility.&nbsp; The absolute forward
+ table in the profile is used to create PCS values from the sample
+ points, and the profiles PCS value then compared to the PCS values
+ of
+ the measured sample points. Note the lower delta E values are not
+ always a better measure of how good a profile is. The aim of a
+ profile
+ is to model the underlying characteristics of a device, not to
+ slavishly reproduce the sampled data point values. Sampled data
+ point
+ values contain device variation and instrument reading inaccuracies,
+ and a good profiler will try and filter out this noise, resulting in
+ some deliberate differences between the profile and the sample
+ points
+ used to create it.<br>
+ <br>
+ The <b>-v</b> flag prints out extra information during the
+ checking. A
+ value greater than 1 will print the color values of each test point.<br>
+ <br>
+ The <b>-c</b> option causes the differences between the test values
+ and
+ the profile prediction of the color for each device value to be
+ displayed
+ in CIE94 delta E, rather than plain L*a*b* delta E. CIE94 delta E
+ has a
+ closer
+ correspondence with perceived color differences than the default
+ CIE76
+ delta E values.<br>
+ <br>
+ The <b>-k</b> option causes the differences between the test values
+ and
+ the profile prediction of the color for each device value to be
+ displayed
+ in CIEDE2000 delta E, rather than plain L*a*b* delta E. CIEDE2000
+ delta
+ E has a
+ closer
+ correspondence with perceived color differences than either CIE76 or
+ CIE94 delta E values.<br>
+ <br>
+ The <b>-w</b> creates a <a href="File_Formats.html#VRML">VRML</a>
+ 3D
+ visualization
+ of the differences between the test points and the profiles
+ prediction
+ of
+ the resulting colors.<br>
+ <br>
+ The <b>-x</b> flag adds Lab axes to the VRML output.<br>
+ <br>
+ The <b>-m</b> flag makes each error line a minimum of 0.5 delta E
+ long, so that all the points are visible. This makes it easier to
+ view
+ the distribution of test points in the reference set.<br>
+ <br>
+ The <span style="font-weight: bold;">-e</span> flag causes the
+ error
+ vectors in the VRML output to be color coded according to their
+ lengths, from longest to shortest: yellow, red, magenta, blue, cyan
+ and
+ green.<br>
+ <br>
+ The <b>-d</b> parameters allow the specification of a particular
+ device value,
+ and the test point by test point output will be sorted by distance
+ from
+ the
+ given device value. This can be useful in determining how well
+ "supported"
+ the profile is in a particular area of the colorspace.<br>
+ <br>
+ If the <b>-p </b>flag is used in combination with the <b>-d</b>
+ parameters,
+ then the test point by test point output will be sorted by distance
+ in
+ PCS
+ (Lab) space rather than distance in device space.<br>
+ <br>
+ The <b>-f</b> flag enables Fluorescent Whitening Agent (FWA)
+ compensation. This only works if spectral data is available and, the
+ instrument is not UV filtered.&nbsp; FWA compensation adjusts the
+ spectral samples so that they appear to have been measured using an
+ illuminant that has a different level of Ultra Violet to the one the
+ instrument actually used in the measurement. The optional
+ illumination parameter allows specifying a standard or custom
+ illumination spectrum to be used as the similated instrument
+ illuminant, overriding the default <b>D50</b> or CIE computation
+ illuminant used for FWA (see <b>-i</b> below<b>). </b>See <a
+ href="file:///D:/src/argyll/doc/colprof.html#f">colprof -f</a> for
+ a fuller explanation. The same value should be used as was used
+ during the creation of the
+ profile.<br>
+ <br>
+ The <b>-i</b> flag allows specifying a standard or custom
+ illumination
+ spectrum, applied to the spectral test point values to compute CIE
+ tristimulus values. <b>A</b>, <b>D50</b>, <b>D50M2, D65</b>, <b>F5</b>,
+ <b>F8</b>, <b>F10</b> are a selection of standard illuminant
+ spectrums, with <b>D50</b> being the default. If a filename is
+ specified instead, it will be assumed to be an Argyll specific <a
+ href="file:///D:/src/argyll/doc/File_Formats.html#.sp">.sp</a>
+ spectrum file. If FWA compensation is used during measurement, this
+ illuminant will be used by default as the simulated instrument
+ illuminant. The same value should be used as was used during the
+ creation of the
+ profile.<br>
+ <br>
+ <a name="o"></a> The <b>-o</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer.
+ The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ <br>
+ The same parameter value should be used as was used during the
+ creation
+ of the profile.<br>
+ <br>
+ The <span style="font-weight: bold;">-I</span> parameter allows
+ changing the intent used in looking up the ICC profile colors to
+ relative colorimetric. This would <span style="text-decoration:
+ underline;">not</span> be used if you are
+ checking a profile against the .ti3 file that was used to create it,
+ since, since profiles are always made
+ from absolute colorimetric measurement values.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/refine.html b/doc/refine.html
new file mode 100644
index 0000000..cfe18b9
--- /dev/null
+++ b/doc/refine.html
@@ -0,0 +1,354 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>refine</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>tweak/refine</b></h2>
+ <h3>Summary</h3>
+ <span style="font-weight: bold;">Refine</span> creates an abstract
+ profile, by comparing CIE measurement values from two test charts.
+ The charts will usually be in <a href="File_Formats.html#.ti3">.ti3</a>
+ format, but only XYZ, Lab or spectral values will be used (ie. all
+ device space values are ignored). Typically the charts would be
+ printed on a target system (the one being emulated, say a printing
+ press), and the proofing system (the one that is being profiled).
+ The abstract profile that <span style="font-weight: bold;">refine</span>
+ produces will be a correction that makes the proofing system behave
+ more like the target. This can then be used to recreate the proofing
+ systems ICC profile, or device link. By feeding a previous abstract
+ correction profile in as well, iterative improvement can be made to
+ the proofing reproduction.<br>
+ <br>
+ <a href="verify.html">verify</a> is a useful tool to use on the two
+ test charts, to check how well the refinement is proceeding. If a
+ white point relative match is being created (refine -R), then use
+ veryify -N.<br>
+ <h3>Usage Summary</h3>
+ <tt><small>usage: refine [-options] cietarget ciecurrent [outdevicc]
+ [inabs] outabs<br>
+ &nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Verbose<br>
+ &nbsp;-c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Create
+
+ initial abstract correction profile<br>
+ &nbsp;-g&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't
+
+ impose output device gamut limit<br>
+ &nbsp;-r res&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set
+ abstract profile clut resolution (default 33)<br>
+ &nbsp;-d factor&nbsp;&nbsp;&nbsp;&nbsp; Override default damping
+ factor (default 0.950000)<br>
+ &nbsp;-R&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Aim
+
+ for white point relative match rather than absolute<br>
+ &nbsp;</small></tt><tt><small><small></small><small><small>-f
+ [illum]&nbsp;&nbsp;&nbsp; Use Fluorescent Whitening Agent
+ compensation [opt. simulated inst. illum.:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or
+ file.sp]<br>
+ &nbsp;-i illum&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Choose
+ illuminant for computation of CIE XYZ from spectral data
+ &amp; FWA:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+ A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp</small></small><br>
+ &nbsp;-o observ&nbsp;&nbsp;&nbsp;&nbsp; Choose CIE Observer for
+ spectral data:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+1931_2,
+
+ 1964_10, S&amp;B 1955_2, J&amp;V 1978_2 (def.)<br>
+ &nbsp;<span style="font-style: italic;">cietarget&nbsp;</span>&nbsp;&nbsp;&nbsp;
+ Target CIE or spectral values, CGATS file (e.g. .ti3)<br>
+ &nbsp;<span style="font-style: italic;">ciecurrent</span>&nbsp;&nbsp;&nbsp;
+ Actual CIE or spectral values, CGATS file (e.g. .ti3)<br>
+ &nbsp;[<span style="font-style: italic;">outdevicc</span>]&nbsp;&nbsp;
+ Output device ICC profile to set gamut limit (not used if -g)<br>
+ &nbsp;[<span style="font-style: italic;">inabs</span>]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Previous
+
+ abstract correction ICC profile (not used if -c)<br>
+ &nbsp;<span style="font-style: italic;">outabs</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Created/refined
+
+ abstract correction ICC profile</small></tt><br>
+ <h3>Usage Details</h3>
+ <b>refine</b> provides a way of improving the profile accuracy of a
+ proofing system.<br>
+ <br>
+ The <b>-v</b> flag prints out extra information during the
+ checking, and prints each patch value, rather than just a summary.<br>
+ <br>
+ The <b>-c</b> option is used when refine is being used for the
+ first time, and there is no previous abstract profile to continue
+ refining. If <span style="font-weight: bold;">-c</span> is used,
+ then the name of the previous abstract correction profile should not
+ be supplied.<br>
+ <br>
+ If the <b>-g </b>flag indicates that an output device profile is
+ not being supplied, and that corrections should be attempted, even
+ if the colors are outside the devices gamut. Normally an output
+ device profile is supplied, and corrections aren't applied to colors
+ outside the devices gamut, since this will not achieve anything
+ useful, and can distort the results.<br>
+ <br>
+ If the <b>-r </b>parameter overrides the resolution of the CLUT
+ grid used in the abstract profile. By default the value is 33, but
+ other<br>
+ values can be chosen. An odd number is recommended. <br>
+ <br>
+ If the <b>-d </b>parameter sets how aggressively refine should try
+ and correct errors. Normally it will try and exactly compensate for
+ the color errors revealed in comparing the two measurement files,
+ but if the device behaviour is unusual, or not very repeatable, this
+ may result in successive applications of refine making things worse,
+ rather than better. If this is the case, try using a smaller number,
+ such as 0.8, or 0.5.<br>
+ <br>
+ If the <span style="font-weight: bold;">-R</span> flag is used,
+ then refine creates an abstract profile for improving the match of
+ the patch values when&nbsp; interpreted in a white point relative
+ (ie. Relative Colorimetric) intent. If used to create a corrected
+ device link profile using <a href="collink.html">collink</a>,
+ remember to create a Relative colorimetric intent device link
+ profile.<br>
+ <br>
+ The <b>-f</b> flag enables Fluorescent Whitening Agent (FWA)
+ compensation. This only works if spectral data is available and, the
+ instrument is not UV filtered.&nbsp; FWA compensation adjusts the
+ spectral samples so that they appear to have been measured using an
+ illuminant that has a different level of Ultra Violet to the one the
+ instrument actually used in the measurement. The optional
+ illumination parameter allows specifying a standard or custom
+ illumination spectrum to be used as the similated instrument
+ illuminant, overriding the default <b>D50</b> or CIE computation
+ illuminant used for FWA (see <b>-i</b> below<b>). </b>See <a
+ href="file:///D:/src/argyll/doc/colprof.html#f">colprof -f</a> for
+ a fuller explanation. The same value should be used as was used
+ during the creation of the profile.<br>
+ <br>
+ The <b>-i</b> flag allows specifying a standard or custom
+ illumination spectrum, applied to the spectral test point values to
+ compute CIE tristimulus values. <b>A</b>, <b>D50</b>, <b>D50M2,
+ D65</b>, <b>F5</b>, <b>F8</b>, <b>F10</b> are a selection of
+ standard illuminant spectrums, with <b>D50</b> being the default.
+ If a filename is specified instead, it will be assumed to be an
+ Argyll specific <a
+ href="file:///D:/src/argyll/doc/File_Formats.html#.sp">.sp</a>
+ spectrum file. If FWA compensation is used during measurement, this
+ illuminant will be used by default as the simulated instrument
+ illuminant. The same value should be used as was used during the
+ creation of the profile.<br>
+ <br>
+ The <b>-o</b> flag allows specifying a tristimulus observer, and is
+ used to compute CIE tristimulus values. The following choices are
+ available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ <br>
+ If both CIE and spectral values are present in the input files, the
+ CIE values will be used by default. Using the <span
+ style="font-weight: bold;">-i</span>, <span style="font-weight:
+ bold;">-o</span> or <span style="font-weight: bold;">-f</span>
+ flag will force spectral values to be used. The the <span
+ style="font-weight: bold;">-i</span>, <span style="font-weight:
+ bold;">-o</span> or <span style="font-weight: bold;">-f</span>
+ flags will apply to both the target and measured input files.<br>
+ <br>
+ <span style="font-style: italic; font-weight: bold;">cietarget</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Is
+
+ the filename of the target CIE or spectral values. This is a <a
+ href="File_Formats.html#CGATS">CGATS</a> file (e.g. a <a
+ href="File_Formats.html#.ti3">.ti3</a> made using <a
+ href="chartread.html">chartread</a>). These are the color values
+ wanted for each patch in the test chart, typically the product of
+ the target print system.<br>
+ <br>
+ <span style="font-style: italic; font-weight: bold;">ciecurrent</span>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Is the filename of the
+ actual, current measured CIE or spectral values. This is a <a
+ href="File_Formats.html#CGATS">CGATS</a> file (e.g. a <a
+ href="File_Formats.html#.ti3">.ti3</a> made using <a
+ href="chartread.html">chartread</a>). The errors between these
+ patches and the patches in the <span style="font-style: italic;
+ font-weight: bold;">cietarget</span> file will be used to create a
+ correction profile.<br>
+ <br>
+ &nbsp;[<span style="font-style: italic; font-weight: bold;">outdevicc</span>]&nbsp;&nbsp;&nbsp;&nbsp;
+If
+
+ the <span style="font-weight: bold;">-g</span> flag is not used,
+ then the output device ICC profile should be supplied here, to allow
+ <span style="font-weight: bold;">refine</span> to limit its
+ corrections to colors that are within the gamut of the device.<br>
+ <br>
+ &nbsp;[<span style="font-weight: bold; font-style: italic;">inabs</span>]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+After
+
+ the first correction has been created, subsequent corrections need
+ to improve upon previous ones, so the previous correction profile
+ should be provided here. For the first correction, the <span
+ style="font-weight: bold;">-c</span> flag should be used, and this
+ argument is omitted.<br>
+ <br>
+ &nbsp;<span style="font-weight: bold; font-style: italic;">outabs</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+The
+
+ name of the created or refined abstract correction ICC profile<br>
+ <br>
+ <h3> Discussion</h3>
+ <span style="font-weight: bold;">Refine</span> is typically used in
+ a proofing situation, in which a verification chart is being used to
+ check the accuracy of a proofing system. (It might also be used for
+ more arbitrary color alterations by created two test chart files by
+ hand.) By using the errors between the target chart and the measured
+ values, refine attempts to improve the match between the proofing
+ system and its target.<br>
+ <br>
+ There is facility in <a href="collink.html">collink</a>, <a
+ href="colprof.html">colprof</a> and <a href="revfix.html">revfix</a>
+ to incorporate an abstract profile. <br>
+ <br>
+ For systems using two device profiles or a device link to convert
+ between the target space printing files and the proofing device
+ space, the following would be a typical scenario:<br>
+ <br>
+ <div style="margin-left: 40px;">We have a reference set of test
+ chart values, read from the target system <span
+ style="font-weight: bold;">reference.ti3</span>. The ICC profile
+ for the target system is <span style="font-weight: bold;">target.icm</span>.
+ The ICC profile for the proofing system is <span
+ style="font-weight: bold;">proofer.icm</span>. If using a device
+ link, the device link used to print proofer test charts is
+ currently <span style="font-weight: bold;">target_proofer.icm</span>:<br>
+ <br>
+ <br>
+ First we print the test chart out on the proofing system and read
+ it in, resulting in a <span style="font-weight: bold;">chart1.ti3</span>
+ file.<br>
+ <br>
+ Lets check how well the proofing system current matches using
+ verify:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; verify&nbsp; reference.ti3 chart1.ti3<br>
+ <br>
+ We then create our initial abstract correction fix profile <span
+ style="font-weight: bold;">fix1.icm</span> using refine:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; refine -v -c&nbsp; reference.ti3 chart1.ti3
+ proofer.icm fix1.icm<br>
+ <br>
+ Applying this to your process for creating the proofer device
+ profile or target to proofing device link (choose one of the three
+ options below, depending whether you are using the proofer profile
+ and just want to alter its colorimetric B2A table using <span
+ style="font-weight: bold;">revfix</span>, whether you are going
+ to recreate the proofer file from the original measurement data
+ using&nbsp; <span style="font-weight: bold;">colprof</span>, or
+ whether you are using a device link profile created using <span
+ style="font-weight: bold;">collink</span>):<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; revfix -v -1 -ke -p fix1.icm proofer.icm
+ proofer_fix1.icm<br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; copy proofer.ti3 proofer_fix1.ti3<br>
+ &nbsp;&nbsp;&nbsp; colprof -v -p fix1.icm proofer_fix1<br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; collink -v -s -ia -oa -p fix1.icm target.icm
+ proofer.icm target_proofer_fix1.icm<br>
+ <br>
+ Note that the above example is a simple one - you should use all
+ the same options as you used to create your initial <span
+ style="font-weight: bold;"><span style="font-weight: bold;"></span>proofer.icm&nbsp;
+
+ </span>or <span style="font-weight: bold;">target_proofer.icm</span>,
+ with the addition of the "-p fix1.icm" option to specify the
+ abstract correction profile be applied.<br>
+ <br>
+ Use the <span style="font-weight: bold;">proofer_fix1.icm</span>
+ or <span style="font-weight: bold;">target_proofer_fix1.icm</span>
+ to print out the test chart again, and read it in, resulting in <span
+ style="font-weight: bold;">chart2.ti3</span> file.<br>
+ <br>
+ Lets check how well the proofing system matches after this first
+ round of refinement using verify:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; verify&nbsp; reference.ti3 chart2.ti3<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;">&gt;&gt;&gt;</span></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span><br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;">&nbsp;</span></span>We
+can
+
+ then start another round of improvement:<br>
+ <br>
+ We refine our previous abstract correction fix profile using
+ refine:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; refine -v&nbsp; reference.ti3 chart2.ti3
+ proofer.icm fix1.icm fix2.icm<br>
+ <br>
+ Applying this new abstract profile to our process for creating the
+ proofing device profile or link again:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; revfix -v -1 -ke -p fix2.icm proofer.icm
+ proofer_fix2.icm<br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; copy proofer.ti3 proofer_fix2.ti3<br>
+ &nbsp;&nbsp;&nbsp; colprof -v -p fix2.icm proofer_fix2<br>
+ or<br>
+ &nbsp;&nbsp;&nbsp; collink -v -s -ia -oa -p fix2.icm target.icm
+ proofer.icm target_proofer_fix2.icm<br>
+ <br>
+ Use the <span style="font-weight: bold;">proofer_fix2.icm</span>
+ or <span style="font-weight: bold;">target_proofer_fix2.icm</span>
+ to print out the test chart again, and read it in, resulting in <span
+ style="font-weight: bold;">chart3.ti3</span> file.<br>
+ <br>
+ Check again how well the proofing system matches after this first
+ round of refinement using verify:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; verify&nbsp; reference.ti3 chart3.ti3<br>
+ <br>
+ Rounds of improvements can be continues by looping back to <span
+ style="font-weight: bold;">&gt;&gt;&gt;</span>, being careful to
+ increment the names of the <span style="font-weight: bold;">fixN.icm</span>,&nbsp;
+
+ <span style="font-weight: bold;">proofer_fixN.icm</span> or <span
+ style="font-weight: bold;">target_proofer_fixN.icm</span> and <span
+ style="font-weight: bold;">chartN.ti3</span>files. Stop when
+ exhausted, or if it looks like things are getting worse, rather
+ than better. If the latter happens, it might be good to revert to
+ the results from a previous round.<br>
+ </div>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/revfix.html b/doc/revfix.html
new file mode 100644
index 0000000..4892de2
--- /dev/null
+++ b/doc/revfix.html
@@ -0,0 +1,252 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>revfix</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>xicc/revfix</b></h2>
+<h3>Summary</h3>
+Regenerate a CLUT device profiles B2A table data by inverting the A2B
+table.<br>
+<h3>Usage Summary</h3>
+<small><span style="font-family: monospace;">revfix [-options] iccin
+iccout</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Verbose</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Process perceptual</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Process absolute/relative colorimetric</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Process saturation</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-r res&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Override BtoA1
+CLUT res.</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#k">-k</a><span
+ style="font-family: monospace;"> [ezhxr]
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; e =
+same K as existing BtoA table (def)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; z =
+zero, h = 0.5 K, x = max K, r = ramp K</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#kp">-k p stle stpo enle enpo
+shape</a><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; p =
+curve parameters</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; stle: K
+level at White 0.0 - 1.0</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; stpo:
+start point of transition Wh 0.0 - Bk 1.0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; enpo:
+End point of transition Wh 0.0 - Bk 1.0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; enle: K level at Black 0.0 - 1.0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; shape:
+1.0 = straight, 0.0-1.0 concave, 1.0-2.0
+convex</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#K">-K parameters</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Same as
+-k, but
+target is K locus rather than K value itself</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#l">-l tlimit</a><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp; set total ink limit, 0
+- 400%
+(estimate by default)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#L">-L klimit</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set black ink limit, 0
+- 100%
+(estimate by default)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p">-p aprof.icm</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Include abstract
+profile in output tables</span></small><br>
+<h3>Usage Details and Discussion</h3>
+Existing ICC profiles may not contain accurately inverted AtoB table
+data in their B2A tables, and this tool provides a means of
+addressing this, or regenerating the B2A information with a different
+black generation and/or ink limit, or applying an abstract correction
+profile to the B2A table, without completely recreating the profile.<br>
+<br>
+Currently <b>revfix</b> does not support creating real perceptual or
+saturation B2A tables, but can only create &nbsp;relative colorimetric
+tables. It also will not handle CLUT profile that use a matrix element
+in them.<br>
+<br>
+<b>-v</b>&nbsp; Turn on verbose mode. Gives progress information as the
+table is created. Since B2A tables can take a long time to generate,
+this is often useful to monitor progress.<br>
+<br>
+The B2A table to be re-creating can be specified by using the <b>-0</b>,
+<b>-1</b>, and <b>-2</b>f lags. Normally only the <b>-1</b> flag
+should be specified, but the perceptual and saturation tables can be
+replaces instead/as well, if their respective flags are specified.<br>
+<br>
+Normally the re-created B2A table will have the same CLUT resolution as
+the existing table, but this can be overridden by using the <b>-r</b>
+flag.
+Typically a resolution of 9 might be used for a medium quality CMYK
+table,
+with 17 being used for a high quality CMYK table. For an RGB profile, a
+resolution of 17 might be used for a medium quality table, and 33 being
+used for a high quality table.<br>
+<tt></tt><br>
+<a name="k"></a> -<b>k</b> parameter sets the target level of black (K)
+when creating a B2A CMYK output tables. This is often called a black
+level, a black inking rule, black generation, or under color
+removal.&nbsp; These set the target black level.<br>
+<br>
+&nbsp;Possible arguments to the <b>-k</b> flag are:<br>
+<br>
+<b> -kz</b> selects minimum black (0.0)<br>
+<b> -kh</b> selects a black value of 0.5<br>
+<b> -kx</b> selects the maximum possible black (1.0)<br>
+<b> -kr</b> selects a linear black ramp, starting at minimum black for
+highlight, and maximum black for shadow (equivalent to -kp 0 0 1 1 1).
+This is the default.<br>
+<br>
+<b><a name="kp"></a>-k p stle stpo enpo enle shape</b>&nbsp; allows an
+arbitrary black value ramp to be defined, consisting of a starting
+value (stle) for highlights, a breakpoint L value (stpo) where it
+starts to transition to the shadow level, an end breakpoint L (enpo)
+where it flattens out again, and the finishing black level (enle) for
+the shadows. There is also a curve parameter, that modifies the
+transition from stle to enle to either be concave (ie.&nbsp; the
+transition starts gradually and and finished more abruptly) using
+values 0.0-1.0, with 0.0 being most concave, or convex (the transition
+starts more abruptly but finishes gradually), using values 1.0-2.0,
+with 2.0 being the most convex.<br>
+<br>
+Typical black value generation curve with parameters something
+like: -kp 0 .1 .9 1 .5<br>
+<br>
+<tt> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0 K &nbsp; |
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;enpo<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp;_______&nbsp;
+enle<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;/<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; /<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;/<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; /<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stle&nbsp;
+| ------/<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp; +-------------------<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0 K&nbsp;
+0.0&nbsp;&nbsp;&nbsp; stpo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Black<br>
+</tt>
+<br>
+For minimum sensitivity of printed output to the lighting spectrum, it
+currently seems best to use the maximum possible black, but other black
+generation levels (ie. 0.3 to 0.5) may well be preferred if one wants
+to
+minimize the noisy appearance of black on an inkjet device, or
+if the banding behaviour or other rendering flaws of the printer is to
+be minimized. <br>
+&nbsp;
+<br>
+The <a href="xicclu.html">xicclu</a> tool can be used to plot out
+the resulting black level for a given set of parameters, by using the <a
+ href="xicclu.html#g">-g</a> flag of a profile already created from the
+same .ti3 file.<br>
+<br>
+<a name="K"></a> <span style="font-weight: bold;">-K parameters.</span>
+Any of the <span style="font-weight: bold;">-k</span> options above
+can use the <span style="font-weight: bold;">-K</span> version, in
+which rather than a black value target being defined by the inking
+rule, a black <span style="text-decoration: underline;">locus</span>
+target is defined. For each lookup, the minimum possible black level
+and the maximum possible black level is determined, the former
+corresponding to a locus target of 0, and the latter corresponding to a
+locus target of 1. For instance, at
+the
+white point, no black will be used in the output, even if the black
+locus specifies a maximum (since the maximum amount of black that
+can be used to print white is actually zero). Similarly, at the black
+point, black may well be used, even if the black locus specifies
+zero black (since a certain amount of black is needed to achieve the
+desired density of color). <br>
+<tt> </tt><br>
+<a name="l"></a>The <b>-l</b> <i>tlimit</i> parameter sets the ink
+limit (TAC, Total
+Area Coverage) for the CMYK separation, as a total percentage from 0%
+to 400%. By default, this value will be estimated from the profile. The
+limit value should generally be set a little below the value used in
+the test chart
+generation, to avoid the very edges of the gamut. If the test chart ink
+limit has been chosen to be a little beyond an acceptable level, then
+this
+number should be the acceptable level. Although limits can be set below
+200%, this will generally restrict the color gamut noticeably, as fully
+saturated
+secondary colors will not be reproduced. Values are between 220% and
+300%
+for typical printing devices. The ink limit
+will be in final calibrated device values if the profile includes
+calibration information.<br>
+<br>
+<br>
+<a name="L"></a> The <b>-L</b> <i>klimit</i> parameter sets the black
+channel ink limit for the CMYK separation, as a total percentage from
+0%
+to 100%. By default, this value will be estimated from the profile. For
+printing press like devices, this can be used to prevent
+the
+black channel screening pattern "filling in". Typical values might be
+from
+95% to 99%. The ink limit
+will be in final calibrated device values if the profile includes
+calibration information.<br>
+<br>
+<br>
+The <b><a name="p"></a>-p</b> option allows specifying an abstract
+profile be applied to all of the output tables. An abstract
+profile is a way of specifying a color adjustment in a device
+independent way. The abstract profile might have been created using one
+of the <span style="font-weight: bold;">tweak</span> tools, such as <a
+ href="refine.html">refine</a>.<br>
+<br>
+<br>
+&nbsp;<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/scanin.html b/doc/scanin.html
new file mode 100644
index 0000000..db5091f
--- /dev/null
+++ b/doc/scanin.html
@@ -0,0 +1,582 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>scanin</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>scanin/scanin</b></h2>
+ <h3>Summary</h3>
+ Convert an 8 or 16 bit per component <a
+ href="File_Formats.html#TIFF">TIFF</a>
+ image of a
+ test chart into&nbsp;<a href="File_Formats.html#.ti3">.ti3</a>
+ device
+ values
+ using automatic pattern recognition, or manual chart alignment.<br>
+ Performs other tasks associated with turning a TIFF raster of test
+ patches into numeric values. <br>
+ <h3>Usage Summary<br>
+ </h3>
+ <small><a style="font-family: monospace;" href="#_"> usage</a><span
+ style="font-family: monospace;">: scanin [options] input.tif
+ recogin.cht
+ valin.cie [diag.tif]</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; :- inputs
+ 'input.tif',&nbsp; and outputs scanner
+ 'input.ti3', or</span><br style="font-family: monospace;">
+ <br style="font-family: monospace;">
+ <a style="font-family: monospace;" href="#g"> usage</a><span
+ style="font-family: monospace;">: scanin -g [options] input.tif
+ recogout.cht
+ [diag.tif]</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; :- outputs file
+ 'recogout.cht', or</span><br style="font-family: monospace;">
+ <br style="font-family: monospace;">
+ <a style="font-family: monospace;" href="#o"> usage</a><span
+ style="font-family: monospace;">: scanin -o [options] input.tif
+ recogin.cht
+ [diag.tif]</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; :- outputs file
+ 'input.val', or</span><br style="font-family: monospace;">
+ <br style="font-family: monospace;">
+ <a style="font-family: monospace;" href="#c"> usage</a><span
+ style="font-family: monospace;">: scanin -c [options] input.tif
+ recogin.cht
+ scanprofile.[icm|mpp] pbase [diag.tif]</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; :- inputs
+ pbase.ti2
+ and outputs printer pbase.ti3, or</span><br style="font-family:
+ monospace;">
+ <br style="font-family: monospace;">
+ <a style="font-family: monospace;" href="#r"> usage</a><span
+ style="font-family: monospace;">: scanin -r [options] input.tif
+ recogin.cht
+ pbase [diag.tif]</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; :- inputs
+ pbase.ti2+.ti3 and outputs pbase.ti3</span><br
+ style="font-family: monospace;">
+ <br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#g">-g</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Generate
+ a chart reference (.cht) file</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#o">-o</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Output
+ patch values in .val file</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+ image to measure color to convert printer pbase .ti2 to .ti3</span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#ca">-ca</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Same
+ as -c, but accumulates more values to pbase .ti3</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+from
+ subsequent pages</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#r">-r</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Replace
+ device values in pbase .ti3</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Default
+ is to create a scanner .ti3 file<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#F">-F
+ x1,y1,x2,y2,x3,y3,x4,y4</a><span style="font-family: monospace;">
+ <br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't
+ auto recognize, locate using four fiducual marks<br>
+ &nbsp;<a href="#p">-p</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Compensate
+ for perspective distortion<br style="font-family: monospace;">
+ </span></small><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#a">-a</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Recognize
+ chart in normal orientation only</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Default
+ is to recognize all possible chart angles<br>
+ &nbsp;<a href="#m">-m</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Return
+ true mean (default is robust mean)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;<a
+ href="#G">-G gamma</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Approximate
+gamma
+ encoding of image</span></small><br style="font-family:
+ monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v [n]</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbosity
+ level 0-9</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#d">-d</a><span
+ style="font-family: monospace;"> [ihvglLIcrsonap]&nbsp;&nbsp;
+ generate
+ diagnostic output (try -dipn)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#di">i</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - B&amp;W of input image</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#dh">h</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - Horizontal edge detection</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#dv">v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - Vertical edge detection</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#dg">g</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - Groups detected</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#dl">l</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - Lines detected</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#dL">L</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - All lines detected<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ </span><span style="font-family: monospace;"><a href="#dI">I</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - lines used to improve fit<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ </span><a style="font-family: monospace;" href="#dc">c</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - lines perspective corrected</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#dr">r</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - lines rotated</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#ds">s</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - sample boxes rotated</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#do">o</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - sample box outlines</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#dn">n</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - sample box names</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#da">a</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - sample box areas</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; </span><a
+ style="font-family: monospace;" href="#dp">p</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+diag
+ - pixel areas sampled</span></small>
+ <br>
+ <small><span style="font-family: monospace;">&nbsp;
+ <a href="#O">-O</a>
+ outputfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Override the default output filename
+ &amp; extension.</span></small><br>
+ <h3>Usage Details and Discussion</h3>
+ <span style="font-weight: bold;">scanin</span> 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 is
+ usually no need to rotate or crop the image any more finely.] The
+ 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 600DPI, you
+ should consider down sampling the scan using a filtering downsample,
+ before submitting the file to scanin. Similarly, any file with a
+ large
+ level of noise (due to screening or scanner artefacts) should
+ consider
+ 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.<br>
+ <br>
+ There are 5 basic modes that <b>scanin</b> operates in.<br>
+ <ul>
+ <li><a name="_"></a>When no special argument is given scanin is
+ assumed to be parsing an input device characterization chart
+ (ie. an
+ IT8.7/2 chart), for the purpose of creating a <a
+ href="File_Formats.html#.ti3">.ti3</a> data file containing
+ the CIE test values and the corresponding RGB scanner values.
+ The <a href="File_Formats.html#.ti3">.ti3</a> file can then be
+ used for
+ creating
+ an input profile using <a href="colprof.html">colprof</a>. The
+ file
+ arguments are: <a name="_p1"></a>The TIFF file that is to be
+ processed, <a name="_p2"></a>the image recognition template
+ file, <a name="_p3"></a>the CIE reference value definitions for
+ the test chart
+ (sometimes labeled a ".q60" file), <a name="_p4"></a>and an
+ optional
+ name for the image recognition
+ diagnostic output. The resulting .ti3 file will have the same
+ base name
+ as the input TIFF file.</li>
+ <li><a name="g"></a>If the<b> -g</b> flag is specified, then
+ scanin
+ is operating in a mode designed to create the necessary image
+ recognition template file (<a href="File_Formats.html#.cht">.cht</a>)
+ boilerplate information. Patch
+ location and labeling information would need to be added
+ manually to
+ such
+ a generated file, to make a complete and useable recognition
+ template
+ file. <a href="cht_format.html">CHT file format.</a> The input
+ TIFF
+ file in
+ this situation, should be a good quality image, perhaps
+ synthetically
+ generated
+ (rather than being scanned), and perfectly oriented, to make
+ specification
+ of the patch locations easier. The file arguments are: <a
+ name="gp1"></a>The
+ TIFF file that
+ is to be processed, <a name="gp2"></a>the image recognition
+ template
+ file to be created, <a name="gp3"></a>and
+ an optional name for the image recognition diagnostic output.</li>
+ <li><a name="o"></a>If the <b>-o</b> flag is used, then scanin
+ will
+ process the input TIFF file and produce a generic&nbsp;<a
+ href="File_Formats.html#CGATS">CGATS</a>
+ &nbsp;style file containing just the patch values (a <span
+ style="font-weight: bold;">.val</span> file). The file
+ arguments
+ are: <a name="op1"></a>The TIFF file that is to be processed, <a
+ name="op2"></a>the image recognition template file
+ to be created, <a name="op3"></a>and an optional name for the
+ image
+ recognition diagnostic
+ output.</li>
+ <li><a name="c"></a>If the <b>-c</b> flag is used, then an input
+ image
+ of a print test chart can be used
+ in combination with a device profile, to estimate the CIE
+ tristimulus
+ values of the patches. This allows RGB
+ input devices to be used as a crude replacement for a color
+ measuring
+ instrument. The icc or mpp profile has
+ (presumably) been
+ created by scanning an IT8.7/2 chart (or similar) through the
+ RGB input
+ device,
+ and
+ then using scanin to create the .ti3 file needed to feed to
+ colprof to
+ create
+ the input device profile. The file arguments in -c mode are: <a
+ name="cp1"></a>The
+ TIFF file that
+ is to be processed containing the image of a print test chart, <a
+ name="cp2"></a>the image recognition template file for the
+ test chart
+ generated by the <a href="printtarg.html"> printtarg</a> tool,
+ <a name="cp3"></a>the input device ICC or MPP profile, <a
+ name="cp4"></a>the
+ base
+ name for the .ti2 file containing the
+ test chart printer device
+ values and their patch identifiers and the base name for the
+ resulting
+ .ti3
+ file, <a name="cp5"></a>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 chart, then scanin
+ will need
+ to be run multiple times, once for each scan file made from each
+ test
+ chart. <a name="ca"></a>The <b>-ca</b> flag combination should
+ be
+ used
+ for all pages after the first,
+ as this then adds that pages test values to the .ti3 file,
+ rather than
+ creating
+ a .ti3 file that contains only that pages test values. If the
+ incoming
+ .ti2 file contains per-channel calibration
+ curves, these will be passed through to the .ti3 so that
+ accurate ink
+ limits can be computed during profiling. </li>
+ <li><a name="r"></a>If the <span style="font-weight: bold;">-r</span>
+ flag is used, then the input TIFF value
+ is used as a source of device values to replace any existing
+ device
+ values in the given .ti3
+ file. This is intended for use in the situation in which the
+ device
+ values
+ being fed into an output device are altered in some way that is
+ difficult
+ to predict (ie. such as being screened and then de-screened),
+ and this
+ alteration
+ to the device values needs to be taken into account in creating
+ a
+ profile
+ for such a device. The file arguments in -r mode are: <a
+ name="rp1"></a>The
+ TIFF file that
+ is to be processed containing a rasterized image of an output
+ test
+ chart, <a name="rp2"></a>the image recognition template file
+ for the
+ test
+ chart generated by the <a href="printtarg.html"> printtarg</a>
+ tool,&nbsp; <a name="rp3"></a>the base name for
+ the .ti2 file containing the output test chart device values and
+ their
+ patch
+ identifiers and the base name for the .ti3 file that is to have
+ its
+ device
+ values replaced, <a name="rp4"></a>and finally an optional name
+ for
+ the
+ image recognition diagnostic
+ output.<br>
+ </li>
+ </ul>
+ A number of flags and options are available, that are independent of
+ the
+ mode that scanin is in.<br>
+ <br>
+ Normally scanin will try and recognize a chart, irrespective of its
+ orientation. For charts that have some asymmetric patch size or
+ arrangement (such as an IT8.7/2, or a chart generated by <a
+ href="printtarg.html"> printtarg</a>
+ with the <b>-s</b> option), this is both flexible and reliable.
+ Other
+ charts
+ may be symmetrical, and therefore having scanin figure out the
+ orientation
+ automatically is a problem if the recognition template does not
+ contain
+ expected patch values, since it will have an equal chance of
+ orienting
+ it incorrectly as correctly. To solve this, the <a name="a"></a><b>-a</b>
+ flag can be
+ used,
+ and care taken to provide a raster file that is within 45 degrees of
+ "no
+ rotation".<br>
+ <br>
+ <a name="F"></a>Normally scanin will use automatic chart recognition
+ to
+ identify the location of the test patches and extract their values.
+ If
+ the chart <a href="cht_format.html">CHT file</a>&nbsp;
+ has four fiducial marks defined, then the chart can be manually
+ aligned by specifying the pixel location of the four marks as
+ arguments to the <span style="font-weight: bold;"><span
+ style="font-weight: bold;">-F</span></span> flag. The top left,
+ top
+ right, bottom right and bottom left fiducial marks X and Y
+ co-ordinates
+ should be
+ specified as a single concatenated argument, separated by comma's,
+ e.g:
+ -F 10,20,435,22,432,239,10,239&nbsp; The coodinates may be
+ fractional using a decimal point.
+ Four fiducial marks allows for compensation for perspective
+ distortion.<br>
+ <br>
+ <a name="p"></a>By default the automatic chart recognition copes
+ with
+ rotation, scale and stretch in the chart image, making it suitable
+ for
+ charts that have been scanned, or shot squarely with a camera. If a
+ chart has been shot not exactly facing the camera (perhaps to avoid
+ reflection, or to get more even lighting), then it will suffer from
+ perspective distortion as well. The <span style="font-weight:
+ bold;"><span style="font-weight: bold;">-p</span></span> flag
+ enables automatic
+ compensation for perspective distortion.<br>
+ <br>
+ <a name="m"></a>Normally scanin computes an average of the pixel
+ values
+ within a sample square, using a "robust" mean, that discards pixel
+ values that are too far from the average ("outlier" pixel values).
+ This
+ is done in an attempt to discard value that are due to scanning
+ artefacts such as dust, scratches etc. You can force scanin to
+ return
+ the true mean values for the sample squares that includes all the
+ pixel
+ values, by using the <span style="font-weight: bold;">-m</span>
+ flag.<br>
+ <br>
+ <a name="G"></a>Normally scanin has reasonably robust feature
+ recognition, but the default assumption is that the input chart has
+ an
+ approximately even visual distribution of patch values, and has been
+ scanned and converted to a typical gamma 2.2 corrected image,
+ meaning
+ that the average patch pixel value is expected to be about 50%. If
+ this
+ is not the case (for instance if the input chart has been scanned
+ with
+ linear light or "raw" encoding), then it may enhance the image
+ recognition to provide the approximate gamma encoding of the image.
+ For
+ instance, if linear light encoding ("Raw") is used, a <span
+ style="font-weight: bold;">-G</span> value of 1.0 would be
+ appropriate. Values less than 2.2 should be tried if the chart is
+ particularly dark, or greater than 2.2 if the chart is particularly
+ light. Generally it is only necessary to provide this is there are
+ problems in recognizing the chart.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag enables extra verbosity in
+ processing. This can aid debugging, if a chart fails to be
+ recognized.<br>
+ <br>
+ <a name="d"></a> The <b>-d</b> flag enables the generation of an
+ image
+ recognition diagnostic raster. The name of diagnostic raster can be
+ specified as the last in the
+ command line, or if not, will default to <span style="font-weight:
+ bold;">diag.tif</span>. Various flags control what
+ is written to the diagnostic
+ raster.
+ Note that at least one flag must be specified for a diagnostic
+ raster
+ to be produced.<br>
+ <b><a name="di"></a>i</b>&nbsp;&nbsp;&nbsp; creates a black and
+ white
+ version of the input raster in the diagnostic output, to be able to
+ compare with the feature extraction.<br>
+ <b><a name="dh"></a>h</b>&nbsp;&nbsp;&nbsp; will show pixels in the
+ input image classified as being on horizontal edges, in red.<br>
+ <b><a name="dv"></a>v</b>&nbsp;&nbsp;&nbsp; will show pixels in the
+ input image classified as being vertical edges, in green.<br>
+ <b><a name="dg"></a>g</b>&nbsp;&nbsp;&nbsp; will show groups of
+ pixels
+ that will be used
+ to estimate edge lines, each group in a different color.<br>
+ <b><a name="dl"></a>l</b>&nbsp;&nbsp;&nbsp; will show valid lines
+ estimated from the vertical and horizontal pixel groups, in white.<br>
+ <b><a name="dL"></a>L</b>&nbsp;&nbsp;&nbsp; will show all lines
+ (valid
+ and invalid) estimated from the vertical and horizontal pixel
+ groups,
+ in white.<br>
+ <b><a name="dI"></a>I</b> &nbsp;&nbsp; will show valid lines lines
+ used
+ to improve the final fit,
+ in blue.<br>
+ <b><a name="dc"></a>c</b> &nbsp;&nbsp; will show the lines with
+ perspective correction applied in cyan.<br>
+ <b><a name="dr"></a>r</b>&nbsp;&nbsp;&nbsp; will show the lines
+ rotated
+ to the reference
+ chart orientation, in yellow.<br>
+ <b><a name="ds"></a>s</b>&nbsp;&nbsp;&nbsp; will show the diagnostic
+ sampling box edge outlines, rotated to the reference chart
+ orientation,
+ in orange.<br>
+ <b><a name="do"></a>o</b>&nbsp;&nbsp;&nbsp; will show all the
+ sampling
+ box edge outlines, in orange.<br>
+ <b><a name="dn"></a>n</b>&nbsp;&nbsp;&nbsp; will show the ID names
+ of
+ the sampling boxes, plus the diagnostic sample boxes, using a simple
+ stroke font, in orange.<br>
+ <b><a name="da"></a>a</b>&nbsp;&nbsp;&nbsp; will show the sampling
+ areas as crossed boxes, plus the diagnostic sample boxes, in orange.<br>
+ <b><a name="dp"></a>p</b>&nbsp;&nbsp;&nbsp; will show the sampling
+ areas as colored pixels.<br>
+ <br>
+ The combination of <b>-dipn</b> is usually a good place to start.<br>
+ <br>
+ The <a href="File_Formats.html#TIFF">TIFF</a> file can be either 8
+ or
+ 16 bits per color component, with 16 bit files being slower to
+ process,
+ but yielding more precise results.<br>
+ <br>
+ If at all in doubt that the file has been recognized correctly, use
+ the
+ <span style="font-weight: bold;">-dipn</span> diagnostic flag
+ combination, and check the resulting diagnostic raster file.<br>
+ [ A badly recognised image will typically result in high self fit
+ delta E's when used with colprof. ]<br>
+ <br>
+ <a name="O"></a>The <span style="font-weight: bold;">-O</span>
+ parameter allows the
+ output file name &amp; extension to be specified independently of
+ the
+ last tiff
+ filename. Note that the full filename must be specified, including
+ the
+ extension.<br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/sl.jpg b/doc/sl.jpg
new file mode 100644
index 0000000..aaf330f
--- /dev/null
+++ b/doc/sl.jpg
Binary files differ
diff --git a/doc/spec2cie.html b/doc/spec2cie.html
new file mode 100644
index 0000000..192ee64
--- /dev/null
+++ b/doc/spec2cie.html
@@ -0,0 +1,207 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>fakeread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/</b><span style="text-decoration: underline;"></span>spec2cie</h2>
+ <h3>Summary</h3>
+ Convert spectral <a href="File_Formats.html#.ti3">.ti3</a>
+ readings into CIE XYZ or L*a*b* readings. FWA compensation may be
+ applied.<br>
+ <h3>Usage</h3>
+ <tt><small>spec2cie [options] <span style="font-style: italic;">input.ti3
+ output.ti3<br>
+ &nbsp;</span></small></tt><tt><small>-v
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Verbose mode</small></tt><br>
+ <tt><small><small>&nbsp;<a
+ href="file:///D:/src/argyll/doc/spec2cie.html#I">-I <i>illum</i></a>&nbsp;&nbsp;
+ &nbsp;&nbsp; Override
+ actual instrument illuminant
+ in .ti3 file:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp; A, C, D50, D50M2, D65, F5,
+ F8, F10 or file.sp<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ (only
+ used in conjunction with <span style="font-weight: bold;">-f</span>)<br>
+ </small></small></tt><tt><small><small>&nbsp;<a
+ href="file:///D:/src/argyll/doc/colprof.html#f">-f [<i>illum</i>]</a>
+ &nbsp;&nbsp; Use Fluorescent Whitening Agent compensation
+ [simulated inst. illum.:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or
+ file.sp]<br>
+ </small></small></tt><tt><small><small><small>&nbsp;<a
+ href="file:///D:/src/argyll/doc/spec2cie.html#i">-i <i>illum</i></a>&nbsp;&nbsp;
+ &nbsp;&nbsp; Choose illuminant for computation of CIE XYZ
+ from spectral data &amp; FWA:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp;
+ A, C, D50 (def.), D50M2, D65, F5,
+ F8, F10 or file.sp<br>
+ &nbsp;</small></small><a href="#o">-o
+ <i>observ</i></a>&nbsp;
+ &nbsp;&nbsp; Choose CIE Observer for spectral
+ data:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;&nbsp;
+ 1931_2 </small></tt><tt><small> (def.)</small></tt><tt><small>,
+ 1964_10, S&amp;B
+ 1955_2, shaw, J&amp;V 1978_2<br>
+ &nbsp;<a href="#p">-n</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't
+output
+ spectral values<br>
+ </small></tt><tt><small>&nbsp;<a href="#p">-p</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Plot
+ each values spectrum</small></tt><tt><br>
+ </tt><tt>
+ </tt><tt><small>&nbsp;<span style="font-style: italic;">input.ti3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Measurement
+ file<br>
+ &nbsp;<span style="font-style: italic;">output.ti3</span>&nbsp;&nbsp;&nbsp;&nbsp;
+ Converted
+ measurement file</small></tt><br>
+ <h3>Comments</h3>
+ This program takes the spectral data in a .ti3 file, converts them
+ to
+ XYZ and Lab and fills the XYZ_[XYZ] and LAB_[LAB] columns in the
+ output
+ .ti3 file with the computed XYZ and Lab values. If the columns
+ XYZ_[XYZ] and/or LAB_[LAB] are missing in the input file, they are
+ added to the output file.<br>
+ <br>
+ All other columns are copied from the input to the output .ti3 file.<br>
+ <br>
+ <br>
+ <a name="I"></a>The <b>-I</b> parameter allows specifying a an
+ illumination
+ spectrum for the actual instrument illuminant, overriding that
+ computed from
+ the type of instrument (recorded in the .ti3 file). This is rarely
+ used. This parameter is can
+ only be used in combination with the <span style="font-weight:
+ bold;">-f</span>
+ flag. If a
+ filename is specified instead, it will be assumed to be an Argyll
+ specific <a href="file:///D:/src/argyll/doc/File_Formats.html#.sp">.sp</a>
+ custom spectrum file.
+ Illuminant details are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A&nbsp;&nbsp; CIE
+ tungsten
+ filament lamp 2848K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D50 CIE daylight 5000K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D65 CIE daylight 6500K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F5&nbsp; CIE Fluorescent
+ 6350K, CRI 72<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F8&nbsp; CIE Fluorescent
+ 5000K, CRI 95<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F10 CIE Fluorescent
+ 5000K,
+ CRI 81<br>
+ <br>
+ <br>
+ <a name="f"></a> The <b>-f</b> flag enables Fluorescent Whitening
+ Agent (FWA) compensation. This only works if spectral data is
+ available and, the instrument is not UV filtered.&nbsp; FWA
+ compensation adjusts the spectral samples so that they appear to
+ have been measured using an illuminant that has a different level of
+ Ultra Violet to the one the instrument actually used in the
+ measurement. The optional illumination parameter allows specifying a
+ standard or custom illumination spectrum to be used as the similated
+ instrument illuminant, overriding the default <b>D50</b> or CIE
+ computation illuminant used for FWA (see <b>-i</b> below<b>). </b>See
+ <a href="colprof.html#f">colprof -f</a> for a fuller explanation. <br>
+ <br>
+ <a name="i"></a>The <b>-i</b> parameter allows specifying a
+ standard or custom illumination spectrum, applied to spectral .ti3
+ data to compute PCS (Profile Connection Space) tristimulus values. <b>A</b>,
+ <b>D50</b>, <b>D65</b>, <b>F5</b>, <b>F8</b>, <b>F10</b> are a
+ selection of standard illuminant spectrums, with <b>D50</b> being
+ the default. If a filename is specified instead, it will be assumed
+ to be an Argyll specific <a
+ href="file:///D:/src/argyll/doc/File_Formats.html#.sp">.sp</a>
+ custom spectrum file. This only works if spectral data is available.
+ Illuminant details are:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; A&nbsp;&nbsp; CIE
+ tungsten filament lamp 2848K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D50 CIE daylight 5000K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D65 CIE daylight 6500K<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F5&nbsp; CIE Fluorescent
+ 6350K, CRI 72<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F8&nbsp; CIE Fluorescent
+ 5000K, CRI 95<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; F10 CIE Fluorescent
+ 5000K, CRI 81<br>
+ <br>
+ Custom illuminants are most often used when a&nbsp; viewing booth or
+ other known viewing conditions is going to be used to view results.
+ Other illuminant reference files could be created using a suitable
+ measuring instrument such as a spectrolino, or an eyeone using <a
+ href="spotread.html">spotread</a>, although such instruments do
+ not themselves provide the necessary response down to Ultra Violet
+ that is needed for accurate operation of Fluorescent Whitening Agent
+ compensation. The best way of measuring a custom illuminant is to
+ use <a href="illumread.html">illumread</a>, since it uses a special
+ method to estimate the illuminant UV in a way that complements FWA
+ compensation. (See the discussion above for the <b>-f</b> flag).<br>
+ <br>
+ Note that if an illuminant other than D50 is chosen, the resulting
+ ICC profile will not be standard, and may not work perfectly with
+ other profiles that that use&nbsp; the standard ICC D50 illuminant,
+ particularly if the absolute rendering intent is used. Profiles
+ should generally be linked with other profiles that have the same
+ illuminant and observer.<br>
+ <br>
+ <a name="o"></a> The <b>-o</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values. The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree observer
+ (the default).<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ <br>
+ Note that if an observer other than 1931 2 degree is chosen, the
+ resulting ICC profile will not be standard, and cannot be freely
+ interchanged with other profiles that that us the standard 1931 2
+ degree
+ observer. Profiles should only be linked with other profiles that
+ have
+ the same illuminant and observer.<br>
+ <br>
+ <br>
+ <br>
+ <a name="n"></a>The <span style="font-weight: bold;">-n</span> flag
+ disables the output of the spectral values. If just the XYZ and
+ L*a*b*
+ values are needed, this makes for a smaller, easier to read file.<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ causes each spectrum to be plotted. If FWA compensation is used,
+ then
+ the before/after compensation spectrums will be shown.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/specplot.html b/doc/specplot.html
new file mode 100644
index 0000000..05b260b
--- /dev/null
+++ b/doc/specplot.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>specplot</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>xicc/specplot</b></h2>
+ <h3>Summary</h3>
+ A simple tool to plot spectrum files (.sp, .cmf, .ccss etc.), and
+ compute the&nbsp; CCT and VCT, CRI, XYZ, x,y and L*a*b* values.<br>
+ <h3>Usage summary<br>
+ </h3>
+ <tt><small>specplot [<span style="font-style: italic;">infile1.sp,
+ infile2.sp, ...</span>]</small></tt><tt><br>
+ </tt><tt>&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ verbose</tt><tt><br>
+ </tt><tt>&nbsp;-c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ combine multiple files into one plot</tt><tt><br>
+ </tt><tt>&nbsp;-z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+don't
+ make range cover zero</tt><tt><br>
+ </tt><tt>&nbsp;-u
+ level&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; plot effect
+ of adding estimated UV level</tt><tt><br>
+ </tt><tt>&nbsp;-U&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ plot effect of adding range of estimated UV level</tt><tt><br>
+ </tt><tt>&nbsp;[infile.sp ...]&nbsp; spectrum files to plot</tt><tt><br>
+ </tt><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ default is all built in illuminants</tt><br>
+ <h3></h3>
+ <h3>Usage Details and Discussion</h3>
+ <span style="font-weight: bold;"></span>Run without an argument,
+ each built in illuminant is plotted in turn. If an argument is
+ given, then just that<br>
+ spectrum will be plotted. <br>
+ <br>
+ Hit a key in the plot window to advance to the next spectrum.<br>
+ </body>
+</html>
diff --git a/doc/splitti3.html b/doc/splitti3.html
new file mode 100644
index 0000000..05bad37
--- /dev/null
+++ b/doc/splitti3.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>splitti3</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>profile/splitti3</b></h2>
+<h3>Summary</h3>
+Split the first table of data in a CGATS format file, into two files,
+choosing the sets randomly. Usually the CGATS file will be a <a
+ href="File_Formats.html#.ti3">.ti3</a>
+format file, and the intent is to create a test and reference data set,
+to verify the operation of <a href="colprof.html">colprof</a>.<br>
+<h3>Usage Summary</h3>
+<small><span style="font-family: monospace;">usage: splitti3
+[-options] input.ti3 output1.ti3 output2.ti3</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose - print each patch value</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-n
+no&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Put no sets in
+first file, and balance in second file.</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-p
+percent&nbsp;&nbsp;&nbsp;&nbsp; Put percentage% in first file,
+and balance in second file. (def. 50%)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-r
+seed&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use
+given random seed.</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><span
+ style="font-style: italic; font-family: monospace;">input.ti3</span><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; File to
+be split up.</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><span
+ style="font-style: italic; font-family: monospace;">output1.ti3</span><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; First output file</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><span
+ style="font-style: italic; font-family: monospace;">output2.ti3</span><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; Second output file</span></small><br>
+<h3>Usage Details and Discussion</h3>
+<b>splitti3</b> together with <a href="profcheck.html">profcheck</a>
+provides a way of verifying how well the profiling process is working.
+By splitting up a <span style="font-weight: bold;">.ti3</span> test
+set into two parts, one that will be the data file that the profile is
+created from, and the other being the independent set used for
+verification, some measure can made of how well a devices underlying
+behaviour is being modelled by colprof. Only the first table is
+transferred from input to output.<br>
+<br>
+The <b>-v</b> flag prints out extra information during operation..<br>
+<br>
+The <b>-n</b> parameter specifies the split between the first and
+second output files as a given number of sets of data for the first
+table.<br>
+<br>
+The <b>-p</b> parameter specifies the split between the first and
+second output files as a percentage in favour of the first table.<br>
+<br>
+The <span style="font-weight: bold;">-r</span> parameter provides a
+way of making the random split reproducible, by allowing the random
+number seed to be specified.<br>
+<br>
+<br>
+Typically a large test set might be partitioned into two files, the
+first used to generate a profile, and then the second used with <span
+ style="font-weight: bold;">profcheck</span> to check how well the
+profile patches the balance of the test set points.<br>
+</body>
+</html>
diff --git a/doc/spotread.html b/doc/spotread.html
new file mode 100644
index 0000000..0259530
--- /dev/null
+++ b/doc/spotread.html
@@ -0,0 +1,1011 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>spotread</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>spectro/spotread</b></h2>
+ <h3>Summary</h3>
+ Use an instrument to read a single color value. This can be a useful
+ diagnostic aid.
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">spotread [-options]
+ [logfile]</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; Verbose mode</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span></small><small><span
+ style="font-family: monospace;"></span><a style=" font-family:
+ monospace;" href="#s">-s</a><span style="font-family:
+ monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; Print spectrum for each reading.</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#S">-S</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; &nbsp; Plot the spectrum in a graph window.</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c comport</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set COM port, 1..4 (default 1)</span><span style="font-family:
+ monospace;"></span><span style="font-family: monospace;"><br
+ style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#t">-t</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; Use transmission measurement mode</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a style="
+ font-family: monospace;" href="#e">-e</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use emissive measurement mode (absolute results)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#eb">-eb</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use display white brightness relative measurement mode<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#ew">-ew</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use display white relative measurement mode<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#p">-p</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use telephoto measurement mode (absolute results)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#pb">-pb</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use </span></small><small><span style="font-family: monospace;">projector</span></small><small><span
+ style="font-family: monospace;"> white brightness relative
+ measurement mode<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#pw">-pw</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use </span></small><small><span style="font-family: monospace;">projector</span></small><small><span
+ style="font-family: monospace;"> white relative measurement mode</span></small><small><span
+ style="font-family: monospace;"></span></small><br>
+ <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#a">-a</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use ambient measurement mode (absolute results)<br>
+ &nbsp;<a href="#f">-f</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Use ambient flash measurement mode (absolute results)<br>
+ </span></small><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#y">-y X</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display type - instrument specific list to choose from.</span></font><br>
+ <small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="spotread.html#I">-I illum</a><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; Set simulated instrument illumination
+ using FWA (def -i illum):</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;&nbsp;
+M0,
+
+ M1, M2, A, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#i">-i illum</a><span
+ style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp;&nbsp; Choose illuminant for computation of
+ CIE XYZ from spectral data &amp; FWA:</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;&nbsp;
+A,
+D50
+(def.),
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ D50M2, D65, F5, F8, F10 or file.sp</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a style="
+ font-family: monospace;" href="#Q">-Q observ</a><span
+ style="font-family: monospace;">&nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Choose CIE Observer for
+ spectral data or CCSS instrument:</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span></small><small><span
+ style="font-family: monospace;">1931_2 </span></small><small><span
+ style="font-family: monospace;"> (def.)</span></small><small><span
+ style="font-family: monospace;">, 1964_10, S&amp;B 1955_2, shaw,
+ J&amp;V 1978_2</span></small><small><span style="font-family:
+ monospace;"></span></small><font size="-1"><span
+ style="font-family: monospace;"><br>
+ &nbsp;<a href="#F">-F filter</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Set filter configuration:<br>
+ &nbsp;&nbsp;
+ n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ None<br>
+ &nbsp;&nbsp;
+ p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Polarising filter<br>
+ &nbsp;&nbsp;
+ 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ D65<br>
+ &nbsp;&nbsp;
+ u&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ U.V. Cut<br>
+ &nbsp;<a href="#E">-E extrafilterfile</a>&nbsp;&nbsp;&nbsp;
+ Apply extra filter compensation file<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#x">-x</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display Yxy instead of Lab<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#h">-h</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display LCh instead of Lab</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#V">-V</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Show running average and std. devation from ref.</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#T">-T</a>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Display correlated color temperatures and CRI<br>
+ </span></font><font size="-1"><span style="font-family:
+ monospace;">&nbsp;<a href="#N">-N</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Disable initial calibration of instrument if possible</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#H">-H</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use high resolution spectrum mode
+ (if available)<br>
+ &nbsp;</span></font><font size="-1"><span style="font-family:
+ monospace;"><a href="#X1">-X file.ccmx</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Apply Colorimeter Correction Matrix</span></font><br>
+ <span style="font-family: monospace;">&nbsp;<a href="#X2">-X
+ file.ccss</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+Colorimeter
+Calibration
+Spectral
+Samples
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ for calibration</span><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#Yrn">-<font size="-1">Y</font>
+ r|n</a><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+ &nbsp;&nbsp;&nbsp;&nbsp; Override refresh, non-refresh display
+ mode</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;</span><a
+ style=" font-family: monospace;" href="#YA">-<font size="-1">Y</font>A</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; Use non-adaptive integration time mode
+ (if available).</span></font><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#W">-W n|h|x</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Override
+serial
+port
+flow
+control:
+n
+=
+none,
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ h = HW, x = Xon/Xoff</span></font><br>
+ <small><span style="font-family: monospace;">&nbsp;</span><a style="
+ font-family: monospace;" href="#D">-D [level]</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Print debug diagnostics to stderr</span></small><br>
+ <font size="-1"><span style="font-family: monospace;">&nbsp;<a
+ href="#log"><span style="font-style: italic;">logfile</span></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Optional file to save reading results<br style="font-family:
+ monospace;">
+ </span></font><small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><br>
+ <h3>Usage Details and Discussion</h3>
+ <b>spotread</b> operates in a similar fashion to <a
+ href="chartread.html"> chartread</a>, but allows the reading of a
+ succession of single color values. This can be useful in diagnosing
+ issues with profile creation and operation.<br>
+ <br>
+ <a name="v"></a>The <b>-v</b> flag causes extra information to be
+ printed out during chartread operation.<br>
+ <br>
+ <a name="s"></a>The <b>-s</b> flag enables the printing out
+ spectral reflectance/transmittance values, if the instrument
+ supports this.<br>
+ <br>
+ <a name="S"></a>The <b>-S</b> flag enables the plotting of the
+ spectral reflectance/transmittance values, if the instrument
+ supports this. If a reference is taken, this will be plotted in red.
+ You must strike a key in the plot window to continue with another
+ measurement.<br>
+ <br>
+ <a name="c"></a> The instrument is assumed to communicate through a
+ USB or serial communication port, and the port can be selected with
+ the <b>-c</b> option, if the instrument is not connected to the
+ first port. If you invoke <span style="font-weight: bold;">spotread</span>
+ so as to display the usage information (i.e. "spotread -?" or
+ "spotread --"), then the discovered USB and serial ports will be
+ listed. On UNIX/Linux, a list of all possible serial ports are
+ shown, but not all of them may actually be present on your system.<br>
+ <br>
+ <a name="t"></a>If using an Xrite DTP41T or SpectroScanT, and
+ printing onto transparent or back lit media, use the <b>-t</b> flag
+ to operate the instrument in transparency mode. If using the
+ Spectroscan, this triggers a fake transparency mode, that uses a
+ separate backlight (such as a light box). The&nbsp; instrument will
+ be used to calibrate the level of backlight, and use this to compute
+ the transparency of the test chart samples. Note that for good
+ transparency values, the backlight level needs to be neither too
+ bright not too dark, should ideally be incandescent rather than
+ fluorescent (since fluorescent lights often have big dips in their
+ spectrum), and ideally should be of uniform brightness over the
+ measurement area.<br>
+ <br>
+ <a name="e"></a>The <span style="font-weight: bold;">-e</span> flag
+ allows measuring in emission mode (e.g. displays or illuminants)
+ using instruments that support this mode. An adaptive integration
+ time will be used in devices that support it by default (see the <a
+ href="#ZA">-ZA</a> flag). Values returned are absolute.<br>
+ <br>
+ <a name="eb"></a>The <span style="font-weight: bold;">-eb</span>
+ flag allows measuring in emission mode using instruments that
+ support this mode, with the brightness reading being relative to the
+ white value read as the first reading. While the brightness values
+ are then relative to the white, the readings are otherwise absolute.
+ This corresponds to the raw ICC absolute readings created by <a
+ href="dispread.html">spotread</a>.<br>
+ <br>
+ <a name="ew"></a>The <span style="font-weight: bold;">-ew</span>
+ flag allows measuring in emissive mode using instruments that
+ support this mode, with the reading being relative to the white
+ value read as the first reading.<br>
+ <br>
+ <a name="p"></a>The <span style="font-weight: bold;">-p</span> flag
+ allows measuring in telephoto mode, using instruments that support
+ this mode, e.g. the ColorMunki. Values returned are absolute.<br>
+ &nbsp;Note that you would use normal emissive mode to measure
+ projectors using instruments without a specific telephoto mode.<br>
+ <br>
+ <a name="pb"></a>The <span style="font-weight: bold;">-pb</span>
+ flag allows measuring in telephoto mode using instruments that
+ support this mode, with the brightness reading being relative to the
+ white value read as the first reading. While the brightness values
+ are then relative to the white, the readings are otherwise absolute.
+ This corresponds to the raw ICC absolute readings created by <a
+ href="dispread.html">spotread</a>.<br>
+ <br>
+ <a name="pw"></a>The <span style="font-weight: bold;">-pw</span>
+ flag allows measuring in telephoto mode using instruments that
+ support this mode, with the reading being relative to the white
+ value read as the first reading.<br>
+ <br>
+ <a name="a"></a>The <span style="font-weight: bold;">-a</span> flag
+ allows measuring in ambient illumination mode using instruments that
+ support this mode (i.e. Eye-One Display 2). Values returned are
+ absolute, and include the various color temperatures and Color
+ Rendering Index (see <span style="font-weight: bold;">-T</span>).
+ If the instrument does not support ambient mode, emissive mode will
+ be used instead. An adaptive integration time will be used in
+ devices that support it. <br>
+ <br>
+ <a name="f"></a>The <span style="font-weight: bold;">-f</span> flag
+ allows measuring a flash with those instruments that support
+ scanning emissive measurements. The instrument needs to be triggered
+ by holding down its button, triggering the flash, then releasing the
+ button, similar to how a reflective strip is read.<br>
+ <br>
+ <a name="y"></a>&nbsp; The <span style="font-weight: bold;">-y</span>
+ flag allows setting the Display Type. The selection typically
+ determines two aspects of of the instrument operation: <span
+ style="font-weight: bold;">1)</span> It may set the measuring mode
+ to suite <a
+ href="http://en.wikipedia.org/wiki/Comparison_of_display_technology"><span
+ style="font-weight: bold;">refresh</span> or <span
+ style="font-weight: bold;">non-refresh</span> displays</a>.
+ Typically only LCD (Liquid Crystal) displays have a non-refresh
+ nature. <span style="font-weight: bold;">2)</span> It may select an
+ instrument calibration matrix suitable for a particular display
+ type. The selections available depends on the type and model of
+ instrument, and a list of the options for the discovered instruments
+ will be shown in the <a href="ArgyllDoc.html#CmdLine">usage</a>
+ information. For more details on what particular instruments support
+ and how this works, see <a href="instruments.html">Operation of
+ particular instruments</a>. <b>3)</b> Any installed CCSS files
+ (if applicable), or CCMX files. These files are typically created
+ using <a href="file:///D:/src/argyll/doc/ccxxmake.html">ccxxmake</a>,
+ and installed using <a
+ href="file:///D:/src/argyll/doc/oeminst.html">oeminst</a>. The
+ default and Base Calibration types will be indicated in the usage.<br>
+ <br>
+ <a name="I"></a>The <b>-I</b> parameter allows specifying a
+ standard or custom illumination spectrum to be used as the similated
+ instrument illuminant when FWA compensation is used during
+ measurement, overriding the default <b>D50</b> or CIE computation
+ illuminant used for FWA (see <b>-i</b> below<b>). </b>See <a
+ href="colprof.html#f">colprof -f</a> for a fuller explanation. <br>
+ <br>
+ <a name="i"></a>The <b>-i</b> parameter allows specifying a
+ standard or custom illumination spectrum applied to <span
+ style="text-decoration: underline;">reflective</span> or <u>transmissive</u>
+ spectral data to compute CIE tristimulus values. <b>A</b>, <b>D50</b>,
+ <b>D50M2, D65</b>, <b>F5</b>, <b>F8</b>, <b>F10</b> are a
+ selection of standard illuminant spectrums, with <b>D50</b> being
+ the default. If a filename is specified instead, it will be assumed
+ to be an Argyll specific <a href="File_Formats.html#.sp">.sp</a>
+ spectrum file. If FWA compensation is used during measurement, this
+ illuminant will be used by default as the simulated instrument
+ illuminant.<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag allows specifying a tristimulus
+ observer, and is used to compute PCS (Profile Connection Space)
+ tristimulus values. This is possible for a spectral instrument, or a
+ colorimeter that has CCSS capability. The following choices are
+ available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ <br>
+ <a name="F"></a>The <b>-F</b> options allows configuring the
+ instrument to have a particular filter fitted to it. Some
+ instruments (i.e. the Gretag Spectrolino) allow the fitting of
+ various filters, such as a polarizing filter, D65 illuminant
+ simulation, or Ultra Violet Cut filter, and this option allows the
+ instrument to be configured appropriately.<br>
+ <br>
+ <a name="E"></a>The <b>-E</b> option allows the setting of an extra
+ filter compensation file, that allows for the filtration of the
+ spectral readings through a medium of some kind, when in emission
+ mode. This is useful in allowing for such things as telescopic
+ adapters that use a glass of acrylic lens in the optical path. [<span
+ style="font-weight: bold;">Note</span> that this is currently only
+ supported by the Spectrolino driver.]<br>
+ <br>
+ <a name="x"></a>The <b>-x</b> option causes the reading to be
+ displayed as XYZ and Yxy values, rather than the default XYZ and
+ L*a*b*<br>
+ <br>
+ <a name="h"></a>The <b>-h</b> option causes the reading to be
+ displayed as XYZ and LCh values, rather than the default XYZ and
+ L*a*b*<br>
+ <br>
+ <a name="V"></a>The <b>-V</b> enables average and standard
+ deviation statistics on the XYZ and L*a*b* values. This start and is
+ reset whenever a reference is taken ('r' key). A side effect of this
+ option is to disable the clamping of XYZ and L*a*b* value to
+ positive, so that a valid average of black can be obtained.This is
+ useful in quantifying repeatability.<br>
+ <br>
+ <a name="T"></a>The <b>-T</b> option causes various color
+ temperatures to be displayed, plus the Color Rendering Index. Three
+ color temperatures will be shown. The first is the classic
+ Correlated Color Temperature, which is the black body (Plankian)
+ color closest to the measured color in the CIE 1960 UCS color space.
+ The second is the black body (Plankian) color that has a minimum
+ CIEDE2000 error to the measured color. The last is the daylight
+ color that has a minimum CIEDE2000 error to the measured color. The
+ delta E between the closest temperature and the measured color is
+ also shown for each. The Color Rendering Index (CRI Ra) is also
+ computed if the instrument is capable of spectral measurement. If
+ the notation <span style="font-weight: bold;">(Invalid)</span> is
+ displayed after the CRI, then this means that the the spectrum white
+ point is to far from the black body and Daylight locus to be
+ meaningful.<br>
+ <br>
+ <a name="N"></a> <span style="font-weight: bold;">-N</span> Any
+ instrument that requires regular calibration will ask for
+ calibration on initial start-up. Sometimes this can be awkward if
+ the instrument is being mounted in some sort of measuring jig, or
+ annoying if several sets of readings are being taken in quick
+ succession. The -<span style="font-weight: bold;">N</span>
+ suppresses this initial calibration if a valid and not timed out
+ previous calibration is recorded in the instrument or on the host
+ computer. It is advisable to only use this option on the second and
+ subsequent measurements in a single session.<br>
+ <br>
+ <a name="H"></a> The -<span style="font-weight: bold;">H</span>
+ option turns on high resolution spectral mode, if the instrument
+ supports it. See <a href="instruments.html">Operation of particular
+ instruments</a> for more details.<br>
+ <br>
+ <a name="X1"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccmx</span></span> option reads
+ a <a href="File_Formats.html#.ccmx">Colorimeter Correction Matrix</a>
+ from the given file, and applies it to the colorimeter instruments
+ readings. This can improve a colorimeters accuracy for a particular
+ type of display. A list of contributed <span style="font-weight:
+ bold;">ccmx</span> files is <a href="ccmxs.html">here</a>.<br>
+ <br>
+ <a name="X2"></a> The -<span style="font-weight: bold;">X <span
+ style="font-style: italic;">file.ccss</span></span> option reads
+ a <a href="File_Formats.html#.ccss">Colorimeter Calibration
+ Spectral Sample</a> from the given file, and uses it to set the
+ colorimeter instruments calibration. This will only work with
+ colorimeters that rely on sensor spectral sensitivity calibration
+ information (ie. the X-Rite <span style="font-weight: bold;">i1d3</span>,
+ or the DataColor <span style="font-weight: bold;">Spyder4</span>).This
+can
+improve
+a
+
+
+
+
+
+
+
+
+
+
+
+
+
+ colorimeters accuracy for a particular type of display.<br>
+ <br>
+ <a name="Yrn"></a> The -<span style="font-weight: bold;">Y r </span>and
+
+
+
+
+
+
+ <b>-Y n</b> options overrides the refresh display mode set by the <a
+ href="#y">-y display type selection</a>, with <b>-Y</b><span
+ style="font-weight: bold;"> r</span> forcing refresh display mode,
+ and <b>-Y n</b> forcing a non-refresh display mode. Not all
+ instruments support a display measurement refresh mode, or the
+ ability to override the mode set by the display type selection.<br>
+ <br>
+ <a name="YA"></a> The -<span style="font-weight: bold;">Y A</span>
+ option uses a non-adaptive integration time emission measurement
+ mode, if the instrument supports it, such as the Eye-One Pro or
+ ColorMunki. By default an adaptive integration time measurement mode
+ will be used for emission measurements, but some instruments support
+ a fixed integration time mode that can be used with display devices.
+ This may give increased consistency and faster measurement times,
+ but may also give less accurate low level readings.<br>
+ <br>
+ <a name="W"></a>The <b>-W</b> <span style="font-weight: bold;">n|h|x</span>
+ parameter overrides the default serial communications flow control
+ setting. The value <span style="font-weight: bold;">n</span> turns
+ all flow control off, <span style="font-weight: bold;">h</span>
+ sets hardware handshaking, and <span style="font-weight: bold;">x</span>
+ sets Xon/Xoff handshaking. This commend may be useful in workaround
+ serial communications issues with some systems and cables. <br>
+ <br>
+ <a name="D"></a>The <b>-D</b> flag causes communications and other
+ instrument diagnostics to be printed to stdout. A level can be set
+ between 1 .. 9, that may give progressively more verbose
+ information, depending on the instrument. This can be useful in
+ tracking down why an instrument can't connect.<br>
+ <br>
+ <a name="log"></a>The <span style="font-weight: bold; font-style:
+ italic;">logfile</span> is an optional file that can be specified
+ to capture each reading taken. There will be column headers printed
+ to the first row, and then each reading will be on a separate line
+ with tab separators.<br>
+ <br>
+ All instruments will be used in a spot mode. For the SpectroScan
+ instrument, the samples can be placed on the table, and the
+ measuring head positioned before taking a measurement. Note that the
+ default mode (reflectance measurement) may not be supported by the
+ instrument, so a mode it does support will be selected
+ automatically. Override this on the command line if desired. Note
+ that the DTP51, DTP92, DTP94 and Eye-One Display are colorimeters,
+ and cannot read spectral information, and that the DTP92 can only
+ read CRT type displays.<br>
+ <br>
+ <hr style="width: 100%; height: 2px;"><br>
+ Once <b>spotread</b> has established communications with the
+ instrument, it awaits a command from the user, indicated by the user
+ hitting a key or activating the instrument switch. XYZ values are in
+ the range 0 .. 100 for reflective or transmissive readings, and
+ absolute cd/m^2 for display, emissive and ambient readings.<br>
+ <br>
+ The L*a*b* values are computed relative to a D50 100 scale white
+ point. (Note that using display white relative mode makes the L*a*b
+ relative to the display white point.)<br>
+ &nbsp;<br>
+ If Fluorescent Whiter Additive (FWA) compensated readings are to be
+ made, then this needs to be enabled with the correct command line
+ switches, and then setup for each paper white background color, to
+ establish an FWA reference. There is one FWA reference locations
+ available for each alphabetic character not used for a special
+ function (ie. not <span style="font-weight: bold;">H, K, N, Q, R,
+ S, F)</span>, keyed to the capital letters <b>A-</b><b>Z</b>,
+ allowing FWA corrected comparisons between many different media.<br>
+ <br>
+ Once a particular reference location is initialized with the FWA
+ paper color, subsequent readings triggered by using the
+ corresponding lower case letter <span style="font-weight: bold;">a-z</span>
+ will use FWA compensation for that keyed location. Note that
+ readings that are triggered some other way (ie. using a non
+ alphabetic key, or using the instrument switch) will not be FWA
+ corrected readings.<br>
+ <br>
+ If a non-FWA readings is to be performed, then a reading for a
+ location that has not been initialised for paper white should be
+ used, or a non alphabetic key (such as space or return) or
+ instrument switch trigger should be used.<br>
+ <br>
+ If the instrument supports a high resolution spectral mode, then it
+ can be toggled on and off using the <span style="font-weight:
+ bold;">h</span> key.<br>
+ <br>
+ If the instrument supports stored readings (ie. DTP20), then these
+ can be ignored using the <span style="font-weight: bold;">n</span>
+ key.<br>
+ <br>
+ The previous reading can be stored as a reference, and delta E's
+ computed for each reading, using the <b>r</b> key.<br>
+ <br>
+ A previous spectral reading can be saved in a spectrum CGATS file
+ (spectrum.sp) using the <span style="font-weight: bold;">s</span>
+ key, making this a convenient way of creating a custom illuminant
+ spectrum.<br>
+ <br>
+ A calibration can be initiated using the <span style="font-weight:
+ bold;">k</span> key.<br>
+ <br>
+ For instruments that support it and are in a refresh display mode,
+ the calibrated refresh rate can be read back using the <b>f</b>
+ key.<br>
+ <br>
+ For instruments that support it and are in an emissive measurement
+ mode, a display refresh rate measurement can be made by using the <b>F</b>
+ key.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/srgbplot.gif b/doc/srgbplot.gif
new file mode 100644
index 0000000..6226a97
--- /dev/null
+++ b/doc/srgbplot.gif
Binary files differ
diff --git a/doc/ss.jpg b/doc/ss.jpg
new file mode 100644
index 0000000..93875a5
--- /dev/null
+++ b/doc/ss.jpg
Binary files differ
diff --git a/doc/surface.jpg b/doc/surface.jpg
new file mode 100644
index 0000000..cf412fb
--- /dev/null
+++ b/doc/surface.jpg
Binary files differ
diff --git a/doc/synthcal.html b/doc/synthcal.html
new file mode 100644
index 0000000..89f3fed
--- /dev/null
+++ b/doc/synthcal.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>synthcal</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>spectro/synthcal</b></h2>
+<h3>Summary</h3>
+Create synthetic calibration file. The default is a linear calibration
+file.<br>
+<h3>Usage</h3>
+<font size="-1"><span style="font-family: monospace;">synthcal</span><i
+ style="font-family: monospace;"> </i><span
+ style="font-family: monospace;">[-options] </span><i
+ style="font-family: monospace;">basename<br>
+&nbsp;-t
+N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i =
+input, o = output, d = display (default)<br>
+&nbsp;-d col_comb&nbsp;&nbsp;&nbsp;&nbsp; choose colorant combination
+from the following:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+0:
+Print grey<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+1:
+Video grey<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+2:
+Print RGB<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+3:
+Video RGB<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+4:
+CMYK<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+5:
+CMY<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+6:
+CMYK + Light CM<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+7:
+CMYK + Light CMK<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+8:
+CMYK + Red + Blue<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+9:
+CMYK + Orange + Green<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+10:
+CMYK + Light CMK + Light Light K<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+11:
+CMYK + Orange + Green + Light CM<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+12:
+CMYK + Light CM + Medium CM<br>
+&nbsp;-D colorant&nbsp;&nbsp;&nbsp;&nbsp; Add or delete colorant from
+combination:<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+(Use
+-?? to list known colorants)<br>
+</i></font><font size="-1"><i style="font-family: monospace;">&nbsp;-o
+o1,o2,o3,&nbsp;&nbsp;&nbsp; Set non-linear curve offset
+(default 0.0)</i></font><br>
+<font size="-1"><i style="font-family: monospace;">&nbsp;-s
+s1,s2,s3,&nbsp;&nbsp;&nbsp; Set non-linear curve scale
+(default 1.0)<br>
+&nbsp;-p p1,p2,p3,&nbsp;&nbsp;&nbsp; Set non-linear curve powers
+(default 1.0)<br>
+&nbsp;outfile&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Base name
+for output .cal file</i></font><br>
+<h3>Comments<br>
+</h3>
+This is the tool creates a calibration (<a href="File_Formats.html#.cal">.cal</a>)
+file that has a linear table
+for each channel. This is useful in setting up a display for
+evaluation, disabling printer calibration, testing, or to recover a
+display that has a strange set of
+Video LUTs loaded.<br>
+<br>
+<a name="t"></a>The <span style="font-weight: bold;">-t</span> option
+selects the type of device the calibration file is intended for.
+Default is display.<br>
+<br>
+<a name="d"></a>The <span style="font-weight: bold;">-d</span> option
+selects the device colorspace. The default for input and display is <font
+ style="font-weight: bold;" size="-1"><span
+ style="font-family: monospace;">Video RGB</span></font><font size="-1"><span
+ style="font-family: monospace;">, while the default for output is <span
+ style="font-weight: bold;">CMYK</span>.<br>
+</span></font><br>
+<a name="D"></a> The <b>-D</b> parameter modifies the colorspace set
+by <span style="font-weight: bold;">-d</span> by allowing individual
+colorants to be added or subtracted from the colorspace.<br>
+<br>
+Optionally it can be used to create a non-linear calibration file,
+useful for diagnostics. Each of the device channel curves can be
+given a gamma (power curve) shape, scaled to a maximum other than
+1.0, and offset from a value other than 0.0.<br>
+<br>
+</body>
+</html>
diff --git a/doc/synthread.html b/doc/synthread.html
new file mode 100644
index 0000000..116a43d
--- /dev/null
+++ b/doc/synthread.html
@@ -0,0 +1,166 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>fakeread</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>spectro/synthread</b></h2>
+<h3>Summary</h3>
+Simulate the measurement of a devices response using a synthetic device
+model. This is intended for testing of profile creation accuracy. A
+device link
+separation or color space conversion can be applied before the
+print/measure simulation.<br>
+<h3>Usage</h3>
+<small><span style="font-family: monospace;">synthread [-v] </span></small><small><span
+ style="font-family: monospace;">[<span style="font-style: italic;">separation.ic<span
+ style="font-family: monospace;">m</span></span>]</span></small><small><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;"> </span><i
+ style="font-family: monospace;">inoutfile</i><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp; &nbsp; Verbose mode</span><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-p&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use separation profile</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Output Lab rather than XYZ<br>
+<br style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;-0
+pow&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Apply power to input device chanel 0-9 (after sep.)<br>
+<br style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;-r
+level&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Add average random deviation of &lt;level&gt;% to input device values
+(after sep.)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-R
+level&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Add average random deviation of &lt;level&gt;% to output PCS values<br>
+</span></small><small><span style="font-family: monospace;">&nbsp;-u
+&nbsp; &nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Make random deviations have uniform distributions rather than normal</span></small><br
+ style="font-family: monospace;">
+<small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;-b
+L,a,b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Scale black point to target Lab value</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;[<span
+ style="font-style: italic;">separation.icm</span>]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Device link separation profile</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><i
+ style="font-family: monospace;">profile.</i><span
+ style="font-family: monospace;">[icm|mpp|ti3] &nbsp; &nbsp; </span><a
+ style="font-family: monospace;" href="File_Formats.html#ICC">ICC</a><span
+ style="font-family: monospace;">, </span><a
+ style="font-family: monospace;" href="File_Formats.html#MPP">MPP</a><span
+ style="font-family: monospace;">
+or&nbsp;</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">
+profile/file to use</span><br style="font-family: monospace;">
+&nbsp;
+<span style="font-family: monospace;"></span><i
+ style="font-family: monospace;">inoutfile</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp; &nbsp; Base name for
+input[</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti1">.ti1</a><span
+ style="font-family: monospace;">]/output[</span><a
+ style="font-family: monospace;" href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;">] file</span></small><br>
+<b><br>
+Examples</b><br>
+<br>
+synthread xxxx testvalues<br>
+synthread -p xxx separation.icm testvalues<br>
+<h3>Comments<br>
+</h3>
+The <span style="font-weight: bold;">-v</span> flag does nothing at
+the moment.<br>
+The <span style="font-weight: bold;">-p</span> flag enables a device
+to device value conversion before
+converting to expected PCS values.<br>
+The <span style="font-weight: bold;">-l</span> flag causes the CIE
+output values to be L*a*b* rather than the
+default XYZ values.<br>
+<br>
+The <span style="font-weight: bold;">-0, -1, -2 .. -9</span>
+parameters are a way of simulating changes in the
+behaviour of the simulated printing system. The parameter supplied to
+the flag will be used to modify the device values (after any separation
+is applied) by raising them to the power of the parameter. This applies
+a transfer curve to the simulated device response.<br>
+<br>
+The <span style="font-weight: bold;">-r</span> parameter is a way of
+simulating instability in the behaviour of
+the simulated
+printing system. The parameter supplied to the flag will be used to
+scale a random offset added to the device values (after any separation
+is applied). The offset will be a normally distributed error with an
+average deviation of level%. A typically value supplied
+might be 1.0 to simulate 1% randomness.<br>
+<br>
+The <span style="font-weight: bold;">-R</span> parameter is a way of
+simulating instability in the behaviour of
+the simulated
+measuring system. The parameter supplied to the flag will be used to
+scale a random offset added to the PCS values. The offset will be a
+normally distributed error with an average deviation of level%. A
+typically value supplied
+might be 1.0 to simulate 1% randomness. <br>
+<br>
+The <span style="font-weight: bold;">-u</span> flag changes the
+distribution of the random offsets applied using the <span
+ style="font-weight: bold;">-r</span> or <span
+ style="font-weight: bold;">-R</span> flags, from the default standard
+deviation, to a uniform deviation distribution. The level is still
+specified as an average deviation.<br>
+<br>
+The <span style="font-weight: bold;">-b</span> parameter is a way of
+simulating devices that have a different black point to the profile
+used. This only works if an ICC profile is used, and scales the black
+point to the parameter value. This will be done in XYZ space by
+default, and in L*a*b* space if the <span style="font-weight: bold;">-l</span>
+flag is used.<br>
+<br>
+synthread is useful in creating artificial test value for testing <a
+ href="colprof.html">colprof</a>, as well as providing one path for
+turning an MPP profile into an ICC profile. If a <a
+ href="File_Formats.html#.ti3">.ti3</a> file is
+specified instead of an <a href="File_Formats.html#ICC">ICC</a> or <a
+ href="File_Formats.html#MPP">MPP</a> profile,
+then the closest matching measured points in the .<a
+ href="File_Formats.html#.ti3">.ti3</a> are substituted
+for the test values in the <a href="File_Formats.html#.ti1">.ti1</a>
+file on
+output. If the <a href="File_Formats.html#.ti1">.ti1</a>
+file is a monochrome test file with a White device value, then an RGB <a
+ href="File_Formats.html#ICC">ICC</a> profile, <a
+ href="File_Formats.html#MPP">MPP</a> or <a
+ href="File_Formats.html#.ti3">.ti3</a> may be used, and the White
+values will be translated to equal RGB values. If the <a
+ href="File_Formats.html#.ti1">.ti1</a>
+file is a monochrome test file with a Black device value, then a CMYK <a
+ href="File_Formats.html#ICC">ICC</a> profile, <a
+ href="File_Formats.html#MPP">MPP</a> or <a
+ href="File_Formats.html#.ti3">.ti3</a> may be used, and the Black
+values will be translated to equal CMY = 0, K = grey values. <br>
+<br>
+If a separation device profile is provided (e.g. from CMY -&gt; CMYK,
+or perhaps CMYK-&gt;CMYK, to simulate a color correction step before
+"printing"), then this will be applied to the .ti1 device values,
+before converting the the device values into .ti3 PCS values.<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/targen.html b/doc/targen.html
new file mode 100644
index 0000000..d03416f
--- /dev/null
+++ b/doc/targen.html
@@ -0,0 +1,1024 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>targen</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>target/targen</b></h2>
+ <h3>Summary</h3>
+ Generate a profiling test target values&nbsp;<a
+ href="File_Formats.html#.ti1">.ti1</a> file. &nbsp;<b>targen</b>
+ is
+ used to generate the device channel test point values for grayscale,
+ RGB, CMY, CMYK or N-color output or display devices.&nbsp;
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">targen [options]
+ outfile</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v [level]</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp; Verbose mode [optional
+ verbose level, 1..n]</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#d">-d col_comb</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; choose
+ colorant combination from the following:</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 0:
+ Print
+ grey</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;
+ 1:
+ Video
+ grey</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 2:
+ Print
+ RGB</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;
+ &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3:
+ Video RGB</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 4: CMYK<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 5:
+ CMY<br style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;&nbsp; &nbsp;
+ &nbsp;
+ &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6:
+ CMYK + Light CM</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7: CMYK + Light CMK</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;
+8:
+CMYK
++
+Red
+ + Blue</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 9: CMYK +
+ Orange + Green</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10: CMYK +
+ Light CMK + Light Light K</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11: CMYK +
+ Orange + Green + Light CM</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 12: CMYK + Light
+ CM + Medium CM</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#D">-D colorant</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp; Add or
+ delete colorant from combination:</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 0:
+ Additive</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 1:
+ Cyan</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2:
+ Magenta</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3:
+ Yellow</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 4:
+ Black</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 5:
+ Orange</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 6:
+ Red</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 7:
+ Green</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 8:
+ Blue</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 9:
+ White</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 10:
+ Light
+ Cyan</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 11:
+ Light
+ Magenta</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 12:
+ Light
+ Yellow</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;
+ 13:
+ Light
+ Black</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 14:
+ Medium
+ Cyan</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 15:
+ Medium
+ Magenta</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 16:
+ Medium
+ Yellow</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;
+ 17:
+ Medium
+ Black</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ 18:
+ Light
+ Light
+ Black<br>
+ &nbsp;<a href="#G">-G</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Generate
+ good
+ optimzed
+ points
+ rather
+ than
+ Fast<br style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#e">-e patches</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp; White
+ color test patches (default 4)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#s">-s steps</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Single
+ channel
+ steps
+ (default
+ 0)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#g">-g steps</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Gray
+axis
+RGB
+or
+CMY
+steps
+(default
+ 0)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#m">-m steps</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Multidimensional
+ device
+ space
+ cube
+ steps
+ (default
+ 2)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#f">-f patches</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Add
+ iterative &amp; adaptive full spread patches to total (default
+ 836)<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Default
+ is
+ Optimised
+ Farthest
+ Point
+ Sampling
+ (OFPS)<br style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#t">-t</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+Use
+incremental
+far
+point
+for
+ full spread</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#r">-r</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+Use
+device
+space
+random
+for
+ full spread</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#R">-R</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+Use
+perceptual
+space
+random
+for
+ full spread</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#q">-q</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+Use
+device
+space-filling
+quasi-random
+for
+ full spread<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;
+ </span><a style="font-family: monospace;" href="#Q">-Q</a><span
+ style="font-family: monospace;">
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; Use perceptual space-filling quasi-random for full spread</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#i">-i</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+Use
+device
+space
+body
+centered
+ cubic grid for full spread</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#I">-I</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp;
+Use
+perceptual
+space
+body
+centered
+ cubic grid for full
+ spread</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#a">-a angle</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Simplex
+grid
+angle
+0.0
+-
+0.5
+for
+ B.C.C. grid, default -2047840407</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp; </span><a
+ style="font-family: monospace;" href="#A">-A adaptation</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Degree
+ of adaptation of OFPS 0.0 - 1.0 (default 0.1, 1.0 if -c profile
+ provided)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#t">-t</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+incremental
+far
+point
+for
+full
+spread
+ (default
+ iterative)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#l">-l ilimit</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Total
+ink
+ limit in %(default = none, or estimated from profile)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p">-p power</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Optional
+power-like
+value
+applied
+to
+all
+device
+ values.</span></small><br style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c profile</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Optional device ICC or MPP pre-conditioning profile filename<br>
+ &nbsp;<a href="#N">-N emphasis</a>&nbsp;&nbsp;&nbsp;&nbsp;
+ Degree of
+ neutral axis patch concentration 0-1. (default 0.50)<br
+ style="font-family: monospace;">
+ </span>&nbsp;
+ <a style="font-family: monospace;" href="#F">-F L,a,b,rad</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; Filter out
+ samples
+ outside Lab sphere.</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#w">-w</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Dump
+ diagnostic
+ outfile.wrl
+ file
+ (Lab
+ locations)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#W">-W</a><span
+ style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Dump
+ diagnostic
+ outfile.wrl
+ file
+ (Device
+ locations)</span></small><br style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p1">outfile</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Base
+ name
+ for
+ output(.ti1)</span></small>
+ <br>
+ <h3>Usage Details and Discussion<br>
+ </h3>
+ The number of target patches needs to be chosen, depending on the
+ media
+ size, the type of device, and the quality of profile required. For
+ an
+ inkjet device, something like 3000 test points or more is desirable
+ for high quality profiles, while 500-1000 will probably suffice for
+ a
+ medium quality profile. A few hundred may be sufficient for a
+ preliminary profile. Well behaved printing devices (such as a
+ chemical
+ proof, or a high quality printing press) may produce good profiles
+ with
+ 1000 to 2000 test points. Well behaved RGB devices such as CRT
+ monitors
+ may need only a few
+ hundred points, if a shaper/matrix type profile is to be produced,
+ while pseudo RGB printers, or other RGB devices that a CLUT type
+ profile may be used
+ with, should probably choose somewhere between 500 and 3000 patches.
+ For 'N' color profile creation,
+ 3000 or more test points should probably be used.<br>
+ <br>
+ <a name="v"></a> The <b>-v</b> flag turns on extra verbosity when
+ generating patch values. Extra diagnostics and verbosity may be
+ available if a parameter is provided with a value greater than 1.<br>
+ <br>
+ <a name="d"></a> The <b>-d</b> parameter sets the colorspace the
+ test
+ values will be generated in. Video gray space is assumed to be an
+ additive space, where a zero device value will be black, and a
+ maximum
+ device value will be white. A print gray space is assumed to be a
+ subtractive space,
+ in which a zero device value will be white, and a maximum device
+ value
+ will
+ be black. If no colorspace is specified, subtractive CMYK is assumed
+ as
+ a default.<br>
+ <br>
+ <a name="D"></a> The <b>-D</b> parameter modifies the colorspace
+ set
+ by <span style="font-weight: bold;">-d</span> by allowing
+ individual
+ colorants to be added or subtracted from the colorspace.<br>
+ <br>
+ <a name="G"></a> The <b>-G</b> flag changes the Incremental Far
+ Point
+ Distribution
+ algorithm from fast to good mode. Fast mode uses a limited number of
+ iterations to optimize the patch locations, while good mode strives
+ for
+ a more even patch distribution by using more iterations.<br>
+ <br>
+ The composition of the test patches is controlled by the following
+ flags and parameters:<br>
+ <br>
+ <a name="e"></a> The <b>-e</b> parameter sets the number of white
+ colored test patches, defaulting to 4 if the -e flag isn't used. The
+ white patches are usually very important in establishing white point
+ that the ICC data is made relative to, so it improves robustness to
+ use
+ more than a
+ single point.<br>
+ <br>
+ <a name="s"></a> The <b>-s</b> parameter sets the number of patches
+ in a set of per colorant wedges. The steps are evenly spaced in
+ device
+ space by default, and the total number of test patches will be the
+ number of
+ colorants
+ times the value specified with the -s flag. If the <span
+ style="font-weight: bold;">-p</span> parameter is provided, then,
+ then the steps will be distributed according to the power value.
+ e.g.
+ the option <span style="font-weight: bold;">-s 5</span> will
+ generate
+ steps at 0.0 0.25 0.5 0.75 and 1.0, while the option <span
+ style="font-weight: bold;">-s 5 -p 2.0</span> will generate steps
+ at
+ 0.0
+ 0.0625 0.25 0.5625 and 1.0. By default, no per colorant
+ test wedge values are generated. When creating a test chart for a
+ device
+ that will be used as a source colorspace, it is often useful to
+ generated
+ some per colorant wedge values.<br>
+ <br>
+ <a name="g"></a> The <b>-g</b> parameter sets the number of patches
+ in a set of combined (nominally gray) wedges. This will typically be
+ equal RGB or CMY values, and by default will be equally spaced steps
+ in
+ device
+ space. If the <span style="font-weight: bold;">-p</span> parameter
+ is
+ provided, then,
+ then the steps will be distributed according to the power value.
+ e.g.
+ the option <span style="font-weight: bold;">-g 5</span>
+ will generate steps at 0.0 0.25 0.5 0.75 and 1.0, while the option <span
+ style="font-weight: bold;">-g 5 -p 2.0</span> will generate steps
+ at
+ 0.0
+ 0.0625 0.25 0.5625 and 1.0. By
+ default, no gray combination values are generated. When creating a
+ test
+ chart for a device that will be used as a source colorspace, it is
+ often
+ useful to generated some per colorant wedge values.<br>
+ <br>
+ <a name="m"></a> The <b>-m</b> parameter sets the edge size of the
+ multidimensional grid of test values. The total number of patches of
+ this type will be the -m parameter value to the power of the number
+ of
+ colorants. The grid steps are evenly spaced in device space by
+ default,
+ but if the <span style="font-weight: bold;">-p</span> parameter is
+ provided, then,
+ then the steps will be distributed according to the power value.
+ e.g.
+ the option <span style="font-weight: bold;">-m 5</span>
+ will generate steps at 0.0 0.25 0.5 0.75 and 1.0, while the option <span
+ style="font-weight: bold;">-m 5 -p 2.0</span> will generate steps
+ at
+ 0.0
+ 0.0625 0.25 0.5625 and 1.0. By
+ default, all the device primary color combinations that fall within
+ the
+ ink limit are generated..<br>
+ <br>
+ The behavior of the <b>-e</b>, <b>-s</b>, <b>-g</b> and <b>-m</b>
+ flags, is not to duplicate test values already created by a previous
+ type.<br>
+ <br>
+ <a name="f"></a> The <b>-f</b> parameter sets the number of full
+ spread test patches. Full spread patches are distributed according
+ to
+ the default or chosen algorithm. The default algorithm will optimize
+ the point locations to minimize the distance from any point in
+ device
+ space, to the nearest
+ sample point. This is called Optimized Farthest Point Sampling
+ (OFPS) .
+ This can be overridden by specifying the <b>-t. -r, -R,
+ -q,
+ -i or -I</b> flags. If the default OFPS algorithm is used, then
+ adaptive
+ test
+ point distribution can be fully enabled by supplying a previous or
+ typical profile with the <span style="font-weight: bold;">-c</span>
+ option. The total number patches specified will
+ include any
+ patches
+ generated using the <b>-e</b>, <b>-s</b>, <b>-g</b> and <b>-m</b>
+ flags (i.e.
+ full spread patches will be added to bring the total number of
+ patches
+ including
+ those generated using the <b>-e</b>, <b>-s</b>, <b>-g</b> and <b>-m</b>
+ flags
+ up to the specified number). When there are more than four device
+ channels,
+ the full spread distribution algorithm can't deal with so many
+ dimensions,
+ and <b>targen</b> falls back on an incremental far point
+ distribution
+ algorithm
+ by default, that doesn't generate such evenly spread points. This
+ behaviour
+ can be forced using the <b>-t</b> flag. A <a href="#Table">table</a>
+ of useful total patch counts for different paper sizes is shown
+ below.
+ Note that it's occasionally the case that the OFPS algorithm will
+ fail
+ to complete, or make very slow progress if the <span
+ style="font-weight: bold;">-c</span> profile is poor, non-smooth,
+ or
+ has unusual behaviour. In these cases a different algorithm should
+ be
+ chosen (ie. <span style="font-weight: bold;">-Q</span> or <span
+ style="font-weight: bold;">-I</span>), or perhaps a smoother or
+ lower
+ resolution ("quality") previous profile may overcome the problem. <br>
+ <br>
+ <a name="t"></a> The <b>-t</b> flag overrides the default full
+ spread
+ test patch algorithm, and makes use of the Incremental Far Point
+ Distribution
+ algorithm, which incrementally searches for test points that are as
+ far
+ away
+ as possible from any existing points. This is used as the default
+ for
+ dimensions
+ higher than 4.<br>
+ <br>
+ <a name="r"></a> The <b>-r</b> flag overrides the default full
+ spread
+ test patch algorithm, and chooses test points with an even random
+ distribution in device space.<br>
+ <br>
+ <a name="R"></a> The <b>-R</b> flag overrides the default full
+ spread
+ test patch algorithm, and chooses test points with an even random
+ distribution in perceptual space.<br>
+ <br>
+ <a name="q"></a> The <b>-q</b> flag overrides the default full
+ spread
+ test patch algorithm, and chooses test points with a quasi-random,
+ space filling distribution in device space.<br>
+ <br>
+ <a name="Q"></a> The <b>-Q</b> flag overrides the default full
+ spread
+ test patch algorithm, and chooses test points with a quasi-random,
+ space filling distribution in perceptual space.<br>
+ <br>
+ <a name="i"></a> The <b>-i</b> flag overrides the default full
+ spread
+ test patch algorithm, and chooses test points with body centered
+ cubic
+ distribution in device space.<br>
+ <br>
+ <a name="I"></a> The <b>-I</b> flag overrides the default full
+ spread
+ test patch algorithm, and chooses test points with body centered
+ cubic
+ distribution in perceptual space.<br>
+ <br>
+ <a name="a"></a> The <b>-a <i>angle</i></b> parameter sets the
+ overall
+ angle that the body centered grid distribution has.<br>
+ <br>
+ <a name="A"></a> The <b>-A <i>adaptation</i></b> parameter sets
+ the
+ degree of adaptation to the known device characteristics, used by
+ the
+ default full spread OFPS algorithm. A profile
+ should be provided using the <span style="font-weight: bold;">-c</span>
+ parameter if <span style="font-weight: bold; font-style: italic;">adaptation</span>
+ is set above a low level. By
+ default the adaptation is 0.1 (low), and 1.0 (maximum) if <span
+ style="font-weight: bold;">-c profile</span> is provided, but
+ these
+ defaults can be overridden using this option. For instance, if the <span
+ style="font-weight: bold;">-c profile</span> doesn't represent the
+ device behavior very well, a lower adaption than 1.0 might be
+ appropriate.<br>
+ <br>
+ <a name="l"></a> The <b>-l</b> flag and parameter sets a total ink
+ limit (Total
+ Area Coverage or TAC), which is adhered to for all the generated
+ points. It is generally good practice to set a test chart ink limit
+ at
+ least 10% higher than the ink limit that will be applied when making
+ the resulting profile. In the case of device cube points, this can
+ generate extra test
+ values that lie at the ink limit boundary. For gray wedge values,
+ any
+ that exceed the ink limit are omitted. Full spread test values are
+ all
+ generated to lie
+ within the ink limit. Although it doesn't make much sense, this
+ parameter has an affect on additive device spaces (such as RGB), but
+ should not normally be used with such devices. The total ink limit
+ value will be written to the
+ .ti1 file, and carried through automatically to the .ti3 file, so
+ that
+ it
+ can be used during profile creation. If a profile is provided using
+ the
+ <span style="font-weight: bold;">-c</span> flag, then this will be
+ used
+ to estimate an ink limit, if none is provided with the <span
+ style="font-weight: bold;">-l</span> flag. Ink limits are, as far
+ as
+ possible, always in final calibrated device values, and the
+ calibration
+ curves from the profile provided to the <span style="font-weight:
+ bold;">-c</span> flag will be used to estimate the
+ equivalent limit in the underlying pre-calibration device space
+ values
+ that targen creates.<br>
+ <br>
+ <a name="p"></a> The <b>-p</b> flag and parameter sets a power-like
+ value
+ applied to all of the device values after they are generated, <span
+ style="font-weight: bold;"></span><span style="font-weight: bold;"></span>the
+spacer
+colors.
+This
+can
+be
+useful
+in
+ creating calibration charts for
+ very non-linearly behaved devices. A value greater than 1.0 will
+ cause
+ a tighter spacing of test values near device value 0.0, while a
+ value
+ less than 1.0 will cause a tighter spacing near device value 1.0. <span
+ style="font-weight: bold;">printcal</span> will recommend a
+ power-like
+ value if the verbose option is used. [ <span style="font-weight:
+ bold;">Note</span>
+ that for Print RGB space this
+ is reversed, since internally a Print RGB space is treated as a CMY
+ space. ]. <span style="font-weight: bold;">Note</span> that the
+ device
+ model used to create the expected patch values will not take into
+ account the applied power, nor will the more complex full spread
+ algorithms correctly take into account the power in generating
+ values
+ up to the ink limits. (A power-like function is used, to avoid the
+ excessive compression that a real power function would apply).<br>
+ <br>
+ <a name="c"></a> The <b>-c</b> flag and parameter is used to
+ specify
+ an <a href="File_Formats.html#ICC">ICC</a> or <a
+ href="File_Formats.html#MPP">MPP</a> pre-conditioning profile, for
+ estimating perceptual distances and colorspace curvature, used in
+ optimizing the full spread test point placement,or in creating
+ perceptualy spaced distributions. Normally a previous
+ profile for this or a similar device will be used, or a simpler,
+ preliminary profile will be created and used. If no such profile is
+ specified, a default device space model is used. Note that this
+ will only have an effect if an algorithm that uses perceptual
+ placement (such as <span style="font-weight: bold;">-R, -Q, -I</span>
+ or the default OFPS with an
+ <span style="font-weight: bold;">-A</span> value &gt; 0.0) is being
+ used.<br>
+ <br>
+ <a name="N"></a> The <b>-N emphasis</b> parameter allows changing
+ the
+ degree to which the patch distribution should emphasise the neutral
+ axis. Since the neutral axis is regarded as the most visually
+ critical
+ are of the color space, it can help maximize the quality of the
+ resulting profile to place more measurement patches in this region.
+ This emphasis is only effective for perceptual patch distributions,
+ and
+ for the default OFPS distribution if the <a href="#A">adaptation</a>
+ parameter is set to a high value. It is also most effective when a <a
+ href="#c">pre-conditioning</a> profile is provided, since this is
+ the
+ only way that neutral can be determined. The default value of 0.5
+ provides an affect about twice the emphasis of the CIE94 Delta E
+ formula.<br>
+ <br>
+ <a name="F"></a> The <b>-F</b> flag and parameters is used to
+ define
+ an L*a*b* sphere to filter the test points through. Only test points
+ within the sphere (defined by it's center and radius) will be
+ written
+ to the .ti1 file. This can be good for targeting supplemental test
+ points at a troublesome area of a device. The accuracy of the L*a*b*
+ target will be best when the <span style="font-weight: bold;">-c</span>
+ option is used to specify a reasonably accurate profile for the
+ device.
+ Note that the actual number of points generated can be hard to
+ predict,
+ and will depend on the type of generation used. All means of
+ generating
+ points except the -f N &amp; -r, -R and -q will generate a smaller
+ number of test points than expected. If the -f N &amp; -r, -R and -q
+ methods are used, then the target number of points will be achieved.
+ For this reason, the -f N -q method is probably the easiest to use.<br>
+ <br>
+ <a name="w"></a> The <b>-w</b> flag causes a diagnostic <a
+ href="File_Formats.html#VRML">VRML</a> .wrl file to be created, in
+ which the test points are plotted as small spheres in L*a*b*
+ colorspace. Note that for a CMYK device, the point spacing may seem
+ strange, since the extra K dimension is compressed into the 3
+ dimensional L*a*b* space. <a name="W"></a>If the <span
+ style="font-weight: bold;">-W</span> flag is given, the plot will
+ be
+ in device space, with only the first 3 dimensions of each point
+ being
+ plotted.<br>
+ <br>
+ <a name="p1"></a> The final parameter on the command line is the
+ base
+ filename for the <a href="File_Formats.html#.ti1">.ti1</a> output
+ file. <b>targen</b> will add the .ti1 extension automatically.<br>
+ <br>
+ Some typical total patch number/paper size combinations are shown
+ below. These "magic" numbers are found by using <a
+ href="printtarg.html">printtarg</a> to compute the row length and
+ number of rows, and then adjusting the total number of patches to
+ fill
+ the last row or paper size, in an iterative fashion.<br>
+ <br>
+ <a name="Table"></a> &nbsp;&nbsp; &nbsp; Size (mm/Standard Name),
+ &nbsp;
+ No. Patches<br>
+ <br>
+ DTP20:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 540<br>
+ &nbsp; &nbsp; &nbsp; 2 x A4 &nbsp; &nbsp; &nbsp; 1080<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 3 x A4&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; 1620<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 4 x A4&nbsp; &nbsp;
+ &nbsp;&nbsp; 2160<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp; 1 x Letter &nbsp;&nbsp; 570<br>
+ &nbsp; &nbsp; &nbsp; 2 x Letter&nbsp;&nbsp; 1140<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;3 x Letter&nbsp;&nbsp; 1710<br>
+ &nbsp; &nbsp; &nbsp; 4 x Letter&nbsp;&nbsp; 2280<br>
+ <br>
+ DTP 22:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 782<br>
+ &nbsp; &nbsp; &nbsp; 2 x A4 &nbsp; &nbsp; &nbsp; 1564<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp; 1 x Letter &nbsp;&nbsp; 736<br>
+ &nbsp; &nbsp; &nbsp; 2 x Letter&nbsp;&nbsp; 1472<br>
+ <br>
+ &nbsp; DTP41:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;
+ &nbsp; &nbsp; 375<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 x A4 &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; 750<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 x A4 &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp; 1125<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 x A4 &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp; 1500<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x Letter &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;
+ &nbsp; 345<br>
+ &nbsp; &nbsp; &nbsp; 2 x Letter &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;
+ 690<br>
+ &nbsp; &nbsp; &nbsp; 3 x Letter &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;
+ 1035<br>
+ &nbsp; &nbsp; &nbsp; 4 x Letter &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;
+ 1380<br>
+ <br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 1 x A3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 836<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 2 x A3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1672<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x 11x17 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp; 780<br>
+ &nbsp; &nbsp; &nbsp; 2 x 11x17 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; 1560<br>
+ <br>
+ <br>
+ &nbsp; DTP51:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; 266<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2 x A4 &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; 532<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3 x A4 &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; 798<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4 x A4 &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; &nbsp;
+ &nbsp;
+ &nbsp;&nbsp; 1064<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x Letter &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;
+ 252<br>
+ &nbsp; &nbsp; &nbsp; 2 x Letter &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;
+ 504<br>
+ &nbsp; &nbsp; &nbsp; 3 x Letter &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;
+ 756<br>
+ &nbsp; &nbsp; &nbsp; 4 x Letter &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; 1008<br>
+ <br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 1 x A3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 580<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 2 x A3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; 1160<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x 11x17 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp; 570<br>
+ &nbsp; &nbsp; &nbsp; 2 x 11x17 &nbsp; &nbsp; &nbsp; &nbsp;
+ &nbsp;&nbsp;
+ 1140<br>
+ <br>
+ &nbsp; SpectroScan with square patches:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4R&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 1014<br>
+ &nbsp; &nbsp; &nbsp; 2 x A4R &nbsp; &nbsp; &nbsp; 2028<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 3 x A4R&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; 3042<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 4 x A4R&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; 4056<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp; 1 x LetterR &nbsp;&nbsp; 999<br>
+ &nbsp; &nbsp; &nbsp; 2 x LetterR&nbsp;&nbsp; 1998<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;3 x LetterR&nbsp;&nbsp; 2997<br>
+ &nbsp; &nbsp; &nbsp; 4 x LetterR&nbsp;&nbsp; 3996<br>
+ <br>
+ &nbsp; SpectroScan with hexagonal patches:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4R&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; 1170<br>
+ &nbsp; &nbsp; &nbsp; 2 x A4R &nbsp; &nbsp; &nbsp; 2340<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 3 x A4R&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; 3510<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 4 x A4R&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; 4680<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp; 1 x LetterR&nbsp;&nbsp; 1092<br>
+ &nbsp; &nbsp; &nbsp; 2 x LetterR&nbsp;&nbsp; 2184<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;3 x LetterR&nbsp;&nbsp; 3276<br>
+ &nbsp; &nbsp; &nbsp; 4 x LetterR&nbsp;&nbsp; 4368<br>
+ <br>
+ &nbsp; Eye-One Pro:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 441<br>
+ &nbsp; &nbsp; &nbsp; 2 x A4 &nbsp; &nbsp; &nbsp;&nbsp; 882<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 3 x A4&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; 1323<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 4 x A4&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; 1764<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp; 1 x Letter &nbsp;&nbsp; 462<br>
+ &nbsp; &nbsp; &nbsp; 2 x Letter&nbsp;&nbsp;&nbsp; 924<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;3 x Letter&nbsp;&nbsp; 1386<br>
+ &nbsp; &nbsp; &nbsp; 4 x Letter&nbsp;&nbsp; 1848<br>
+ <br>
+ &nbsp; ColorMunki:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; 90<br>
+ &nbsp; &nbsp; &nbsp; 2 x A4 &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; 180<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 3 x A4&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; 270<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 4 x A4&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp; 360<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp; 1 x Letter &nbsp;&nbsp;&nbsp;&nbsp; 98<br>
+ &nbsp; &nbsp; &nbsp; 2 x Letter&nbsp;&nbsp;&nbsp;&nbsp; 196<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;3 x Letter&nbsp;&nbsp;&nbsp;&nbsp; 294<br>
+ &nbsp; &nbsp; &nbsp; 4 x Letter&nbsp;&nbsp;&nbsp;&nbsp; 392<br>
+ <br>
+ &nbsp; ColorMunki -h:<br>
+ <br>
+ &nbsp; &nbsp; &nbsp; 1 x A4&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 210<br>
+ &nbsp; &nbsp; &nbsp; 2 x A4 &nbsp; &nbsp; &nbsp;&nbsp; 420<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 3 x A4&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp; 630<br>
+ &nbsp;&nbsp; &nbsp;&nbsp; 4 x A4&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; 840<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp; 1 x Letter &nbsp;&nbsp; 196<br>
+ &nbsp; &nbsp; &nbsp; 2 x Letter&nbsp;&nbsp;&nbsp; 392<br>
+ &nbsp; &nbsp;&nbsp; &nbsp;3 x Letter&nbsp;&nbsp;&nbsp; 588<br>
+ &nbsp; &nbsp; &nbsp; 4 x Letter&nbsp;&nbsp;&nbsp; 784<br>
+ <br>
+ &nbsp; Scanner (printtarg with -iSS -s options):<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 1 x A4R &nbsp; &nbsp;&nbsp; 1014<br>
+ &nbsp; &nbsp; &nbsp; &nbsp;2 x A4R &nbsp; &nbsp;&nbsp; 2028<br>
+ &nbsp; &nbsp; &nbsp; &nbsp;3 x A4R &nbsp; &nbsp;&nbsp; 3042<br>
+ &nbsp; &nbsp; &nbsp; &nbsp;4 x A4R &nbsp; &nbsp;&nbsp; 4056<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; 1 x LetterR&nbsp;&nbsp; 962<br>
+ &nbsp; &nbsp; &nbsp; &nbsp;2 x LetterR&nbsp; 1924<br>
+ &nbsp; &nbsp; &nbsp; &nbsp;3 x LetterR&nbsp; 2886<br>
+ &nbsp; &nbsp; &nbsp; &nbsp;4 x LetterR&nbsp; 3848<br>
+ &nbsp; &nbsp; &nbsp; &nbsp;<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/ti3_format.html b/doc/ti3_format.html
new file mode 100644
index 0000000..c42a124
--- /dev/null
+++ b/doc/ti3_format.html
@@ -0,0 +1,311 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>Target Information 3 Format File (.ti3)</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2>Description of the .ti3 format</h2>
+ This is an ASCII text, <a href="File_Formats.html#CGATS">CGATS</a>,
+ Argyll specific format, used to hold device value and CIE/Spectral
+ value pairs, the raw information needed to create device profiles.
+ This file is typically created using the <a href="chartread.html">chartread</a>,&nbsp;<a
+ href="dispread.html"> dispread</a>, <a href="filmread.html">filmread</a>,
+ <a href="scanin.html"> scanin</a>, <a href="fakeread.html">
+ fakeread</a> or one of the conversion tools such as <a
+ href="cb2ti3.html">cb2ti3</a>, <a href="kodak2ti3.html">kodak2ti3</a>,
+ <a href="txt2ti3.html">txt2ti3</a>.<br>
+ <br>
+ While fully compatible with the CGATS.5 Data Exchange Format, the
+ particular required keywords and fields are unique to Argyll, hence
+ an Argyll specific file identifier <span style="font-weight: bold;">CTI3</span>
+ is used to avoid confusion with standard ANSI or CGATS files.<br>
+ <br>
+ The <span style="font-weight: bold;">.ti3</span> format changes
+ from time to time with new releases, to add new functionality, but
+ generally retains backwards compatibility. Note that in the
+ description below, the word "may" indicates an optional component,
+ while the word "shall" indicates a necessary component.<br>
+ <br>
+ Generally a .ti3 file contains only one table, the table containing
+ the colorimetric information. The exception is for a display in
+ which a set of RAMDAC values (most likely the result of display
+ calibration, or simply the video LUT (RAMDAC) values present in the
+ display when the test values were read) are recorded in a second
+ table.<br>
+ <br>
+ <br>
+ The first table contains the following:<br>
+ <br>
+ The file identifier (First 7 characters) shall be <span
+ style="font-weight: bold;">CTI3</span>.<br>
+ <br>
+ A <span style="font-weight: bold;">#</span> character introduces a
+ comment.<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;"></span></span></span>There may be <span
+ style="font-weight: bold;">DESCRIPTOR</span>, <span
+ style="font-weight: bold;">ORIGINATOR</span>, or <span
+ style="font-weight: bold;">CREATED</span> keywords and values (as
+ per CGATS).<br>
+ <br>
+ There shall be a <span style="font-weight: bold;">DEVICE_CLASS</span>
+ keyword that has a value of <span style="font-weight: bold;">"OUTPUT</span>",
+
+ "<span style="font-weight: bold;">DISPLAY</span>" or <span
+ style="font-weight: bold;">"INPUT"</span>.<br>
+ This indicates to the profile program what type of device the color
+ information is from.<br>
+ <br>
+ An <span style="font-weight: bold;">"OUTPUT"</span> type device may
+ have a <span style="font-weight: bold;">TOTAL_INK_LIMIT</span>
+ keyword that has a numeric value indicating the maximum sum of the
+ device channel values as a percentage (T.A.C.), used in creating the
+ test chart. This will be used by the profiler as a value indicating
+ what the valid device gamut is, and what total ink limit should be
+ used in creating the profile tables.<br>
+ <br>
+ A <span style="font-weight: bold;">"DISPLAY"</span> type device may
+ have a <span style="font-weight: bold;">LUMINANCE_XYZ_CDM2</span>
+ keyword that contains the absolute XYZ value of white in candelas
+ per meter squared, e.g. <span style="font-weight: bold;">"112.334770
+
+ 119.657745 121.474236".<br>
+ <br>
+ </span>A display device may also have a <span style="font-weight:
+ bold;">NORMALIZED_TO_Y_100</span> keyword that must have a value
+ of "<span style="font-weight: bold;">NO</span>" or "<span
+ style="font-weight: bold;">YES</span>", to indicate whether the
+ CIE values have been normalised so that the largest has a Y value of
+ 100. If this is a display type device and there is no <span
+ style="font-weight: bold;">NORMALIZED_TO_Y_100</span> keyword,
+ then it can be assumed that the value <span style="font-weight:
+ bold;">are</span> normalized to Y = 100. If the values are
+ normalized to Y = 100, then the absolute values can be restored by
+ multiplying the XYZ values by the <span style="font-weight: bold;">LUMINANCE_XYZ_CDM2</span>
+ Y value and dividing by 100.<br>
+ <br>
+ There may be a keyword <span style="font-weight: bold;">TARGET_INSTRUMENT</span>
+ which will identify the instrument used to read the test values.
+ This is used by the profiling program to determine the spectral
+ characteristics of the instrument illuminant if Fluorescent Whitener
+ Compensation is desired. The value shall be one of:<br>
+ <br>
+ <b>&nbsp;&nbsp;&nbsp; "Xrite DTP20"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "Xrite DTP22"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "Xrite DTP41"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "Xrite DTP51"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "Xrite DTP92"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "Xrite DTP94"</b><b><br>
+ </b><b> &nbsp;&nbsp; "GretagMacbeth Spectrolino"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "GretagMacbeth SpectroScan"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "GretagMacbeth SpectroScanT"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "Spectrocam"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "GretagMacbeth i1 Display 1"</b><b><br>
+ </b><b>&nbsp;&nbsp;&nbsp; "GretagMacbeth i1 Display 2"</b><b><br>
+ </b><b>&nbsp;&nbsp;&nbsp; "Xrite i1 DisplayPro, ColorMunki Display"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "GretagMacbeth i1 Monitor"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "GretagMacbeth i1 Pro"</b><b><br>
+ </b><b>&nbsp;&nbsp;&nbsp; "X-Rite i1 Pro 2"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "X-Rite ColorMunki"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "Colorimtre HCFR"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "ColorVision Spyder2"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "Datacolor Spyder3"</b><b><br>
+ </b><b>&nbsp;&nbsp;&nbsp; "Datacolor Spyder4"</b><b><br>
+ </b><b> &nbsp;&nbsp;&nbsp; "GretagMacbeth Huey"</b><b><br>
+ </b><b>&nbsp;&nbsp;&nbsp; "ColorMunki Smile"</b><b><br>
+ </b><b>&nbsp;&nbsp;&nbsp; "Hughski ColorHug"</b><br>
+ <br>
+ All instruments except the Spectrocam are assumed to have an "A"
+ type illuminant (incandescent lamp of&nbsp; 2850 degrees Kelvin.)<br>
+ <br>
+ There may be a <span style="font-weight: bold;">INSTRUMENT_TYPE_SPECTRAL</span>
+ keyword that must have a value of "<span style="font-weight: bold;">NO</span>"
+ or "<span style="font-weight: bold;">YES</span>", to indicate
+ whether the instrument is based on spectral measurement or not.<br>
+ <br>
+ There may be a <span style="font-weight: bold;">DISPLAY_TYPE_REFRESH</span>
+ keyword that must have a value of "<span style="font-weight: bold;">NO</span>"
+ or "<span style="font-weight: bold;">YES</span>", to indicate
+ whether the instrument was used in a display refresh mode during
+ measurement. <br>
+ <br>
+ There may be keywords with associated values <span
+ style="font-weight: bold;">SINGLE_DIM_STEPS</span>, <span
+ style="font-weight: bold;">COMP_GREY_STEPS</span>, <span
+ style="font-weight: bold;">MULTI_DIM_STEPS</span> or <span
+ style="font-weight: bold;">FULL_SPREAD_PATCHES</span>, that
+ document the composition of the test chart patches.<br>
+ <br>
+ There shall be a keyword <span style="font-weight: bold;">COLOR_REP</span>
+ that has a value that indicates what colorspaces the test values
+ connect. The colorspaces shall be encoded with one&nbsp; or two
+ letters per component, and the two color spaces shall then separated
+ by an <span style="font-weight: bold;"><span style="font-weight:
+ bold;">_</span></span> (underscore) character. For output and
+ display devices, the device space shall come first, followed by the
+ PCS space. For an input device, the PCS shall come first, followed
+ by the device space. The PCS space shall be either XYZ space,
+ indicated by <span style="font-weight: bold;">XYZ</span>, or D50
+ while point L*a*b* space, indicated by <span style="font-weight:
+ bold;">LAB</span>. The device spaces shall use the following
+ letter encoding:<br>
+ <br>
+ <span style="font-weight: bold;"><span style="font-weight: bold;"></span></span>&nbsp;&nbsp;&nbsp;
+Cyan
+
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ C<br>
+ &nbsp;&nbsp;&nbsp; Magenta &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; M<br>
+ &nbsp;&nbsp;&nbsp; Yellow &nbsp; &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ Y<br>
+ &nbsp;&nbsp;&nbsp; Black &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ K<br>
+ &nbsp;&nbsp;&nbsp; Orange &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ O<br>
+ &nbsp;&nbsp;&nbsp; Red
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ R<br>
+ &nbsp;&nbsp;&nbsp; Green &nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ G<br>
+ &nbsp;&nbsp;&nbsp; Blue &nbsp;&nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ B<br>
+ &nbsp;&nbsp;&nbsp; White &nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; W<br>
+ &nbsp;&nbsp;&nbsp; Light Cyan
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ c<br>
+ &nbsp;&nbsp;&nbsp; Light
+ Magenta&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ m<br>
+ &nbsp;&nbsp;&nbsp; Light
+ Yellow&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ y<br>
+ &nbsp;&nbsp;&nbsp; Light
+ Black&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ k<br>
+ &nbsp;&nbsp;&nbsp; Medium Cyan&nbsp;
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2c<br>
+ &nbsp;&nbsp;&nbsp; Medium Magenta
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2m<br>
+ &nbsp;&nbsp;&nbsp; Medium Yellow
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2y<br>
+ &nbsp;&nbsp;&nbsp; Medium Black
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2k<br>
+ &nbsp;&nbsp;&nbsp; Light Light Black &nbsp; &nbsp; &nbsp;&nbsp; 1k<br>
+ <br>
+ There may be an a previx <span style="font-weight: bold;">i</span>
+ preceeding the device space letter encoding, indicating that
+ although the space appears to be an additive space, it is in fact a
+ subtractive device.<br>
+ <br>
+ Typical values might be: "<span style="font-weight: bold;">RGB_XYZ</span>"
+ or "<span style="font-weight: bold;">RGB_LAB</span>" for an RGB
+ display, "<span style="font-weight: bold;">iRGB_XYZ</span>" or "<span
+ style="font-weight: bold;">iRGB_LAB</span>" for an RGB printer, "<span
+ style="font-weight: bold;">CMYK_XYZ</span>" for a printer, "<span
+ style="font-weight: bold;">XYZ_RGB"</span> for an RGB scanner.<br>
+ <br>
+ If spectral values are going to be included in the file, the
+ following keywords and values shall be used:<br>
+ <br>
+ <span style="font-weight: bold;">&nbsp; SPECTRAL_BANDS</span> shall
+ contain the number of spectral bands in the readings, e.g. <span
+ style="font-weight: bold;">"36"</span>.<br>
+ &nbsp; <span style="font-weight: bold;">SPECTRAL_START_NM</span>
+ shall contain the wavelength in nanometers of the first band, e.g. <span
+ style="font-weight: bold;"><span style="font-weight: bold;"><span
+ style="font-weight: bold;">"380.0"</span></span></span>.<br>
+ &nbsp; <span style="font-weight: bold;">SPECTRAL_END_NM</span>
+ shall contain the wavelength in nanometers of the last band, e.g. <span
+ style="font-weight: bold;">"730.0"</span>.<br>
+ <br>
+ The <span style="font-weight: bold;">NUMBER_OF_FIELDS</span>
+ keyword shall have a value that indicates the number of fields in
+ each data set, e.g. <span style="font-weight: bold;">43</span> (as
+ per CGATS).<br>
+ <br>
+ The start of the declaration of the fields shall be marked by the <span
+ style="font-weight: bold;">BEGIN_DATA_FORMAT</span> keyword (as
+ per CGATS).<br>
+ Then shall follow the names of the fields. Standard CGATS field
+ names such as:<br>
+ <br>
+ <span style="font-weight: bold;">&nbsp;SAMPLE_ID</span>, <span
+ style="font-weight: bold;">RGB_R</span>, <span
+ style="font-weight: bold;">RGB_G</span>, <span
+ style="font-weight: bold;">RGB_B</span>, <span
+ style="font-weight: bold;">CMYK_C</span>, <span
+ style="font-weight: bold;">CMYK_M</span>, <span
+ style="font-weight: bold;">CMYK_Y</span>, <span
+ style="font-weight: bold;">CMYK_K</span>, <span
+ style="font-weight: bold;">XYZ_X</span>, <span
+ style="font-weight: bold;">XYZ_Y</span>, <span
+ style="font-weight: bold;">XYZ_Z</span>, <span
+ style="font-weight: bold;">LAB_L</span>, <span
+ style="font-weight: bold;">LAB_A</span> or <span
+ style="font-weight: bold;">LAB_B</span><br>
+ <br>
+ shall be used where appropriate. Other device fields shall use the
+ appropriate pattern, e.g. <span style="font-weight: bold;">CMYKOG_G</span>
+ etc. Spectral band values shall be named <span style="font-weight:
+ bold;">SPEC_XXX</span>, where <span style="font-weight: bold;">XXX</span>
+ is the nearest integer values of the number of nanometers of the
+ band.<br>
+ <br>
+ Optional patch location information shall use the&nbsp; <span
+ style="font-weight: bold;">SAMPLE_LOC</span> field and shall be of
+ quoted string type.<br>
+ <br>
+ The definition of the fields shall be terminated by the <span
+ style="font-weight: bold;">END_DATA_FORMAT</span> keyword (as per
+ CGATS).<br>
+ <br>
+ The <span style="font-weight: bold;">NUMBER_OF_SETS</span> keyword
+ shall have a value that indicates the number of sets of data, e.g. <span
+ style="font-weight: bold;">1000</span> (as per CGATS).<br>
+ <br>
+ The start of the values of the data sets shall be marked by the <span
+ style="font-weight: bold;">BEGIN_DATA</span> keyword (as per
+ CGATS).<br>
+ <br>
+ Each set of data shall be on one line, and shall be separated by
+ white space. All device values shall be percentages (e.g. values
+ from 0.0 to 100.0). XYZ values shall normalized to a Y value of
+ 100.0. L*a*b* values will have their normal range (L* 0.0 to 100.0,
+ a* and b* typically -128.0 to 128.0).<br>
+ <br>
+ The end of the values of the data sets shall be marked by the <span
+ style="font-weight: bold;">END_DATA</span> keyword (as per CGATS).<br>
+ <br>
+ Generally any other keywords and values will be ignored.<br>
+ <br>
+ If a second table is present, and it is a display RAMDAC
+ calibration, printers or input devices per channel calibration
+ curves, and will be of the <a href="cal_format.html">CAL file
+ format</a>..<br>
+ <br>
+ </body>
+</html>
diff --git a/doc/tiffgamut.html b/doc/tiffgamut.html
new file mode 100644
index 0000000..bc63ce7
--- /dev/null
+++ b/doc/tiffgamut.html
@@ -0,0 +1,357 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>tiffgamut</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>xicc/tiffgamut</b></h2>
+ <h3>Summary</h3>
+ Create a gamut file or VRML file of the color gamut of the
+ contents of a set of TIFF or JPEG image.<br>
+ <br>
+ <span style="font-weight: bold;">tiffgamut</span> allows creation of
+ gamut files from the pixel values in a
+ set of TIFF and/or JPEG raster images, as defined by an ICC profile,
+ in L*a*b* or
+ CIECAM02
+ Jab
+ colorspace, and can also represent the gamut as a VRML file. This
+ can be used for visualizing and comparing the gamut of an image to
+ the
+ colorspace it is
+ in, or a colorspace it might get transformed into, and can also be
+ used
+ to create an image source gamut for use with <a href="collink.html">
+ collink</a>.<br>
+ <br>
+ <span style="font-weight: bold;">NOTE</span> that if you are
+ creating
+ an image gamut suitable for use with the <a href="collink.html">collink</a>
+ <a href="collink.html#g">-g</a> or <a href="collink.html#G">-G</a>
+ flags, or <a href="colprof.html#g">colprof
+ -g</a>, use the Jab appearance space intent for appearance space
+ gamut
+ mappings, and the same input viewing
+ conditions to be used in <span style="font-weight: bold;">collink</span>
+ or <span style="font-weight: bold;">colprof</span>
+ using
+ the -c flag, i.e. "tiffgamut -pj -cmt sRGB.icm image.tif"<br>
+ <h3>Usage Summary</h3>
+ <small><span style="font-family: monospace;">tiffgamut [-v level]
+ [profile.icm | embedded.tif/jpg] infile1.tif/jpg
+ [infile2.tif/jpg ...]</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Verbose</span><br style="font-family: monospace;">
+ &nbsp;
+ <span style="font-family: monospace;">-d
+ sres&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Surface
+ resolution details 1.0 - 50.0</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;-w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+emit
+ VRML .wrl file as well as CGATS .gam file</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't
+ add VRML axes or white/black point</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;-k&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Add
+ markers for prim. &amp; sec. "cusp" points<br>
+ &nbsp;-f perc&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Filter by
+ popularity,
+ perc = percent to use<br style="font-family: monospace;">
+ </span><span style="font-family: monospace;">&nbsp;-i
+ intent&nbsp;&nbsp;&nbsp;&nbsp; p =
+ perceptual, r = relative colorimetric,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+s
+ = saturation, a = absolute (default), d = profile default</span></small><small><span
+ style="font-family: monospace;"></span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;-o
+ order&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n = normal
+ (priority: lut &gt; matrix &gt; monochrome)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+r
+ = reverse (priority: monochrome &gt;
+ matrix &gt; lut)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;</span><span
+ style="font-family: monospace;">-p oride</span><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l
+ =
+ Lab_PCS (default), j = CIECAM02 Appearance Jab</span></small><br
+ style="font-family: monospace;">
+ <small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;">&nbsp;-c viewcond&nbsp;&nbsp;
+ set
+ appearance mode and viewing conditions for CIECAM02,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+either
+ an enumerated choice, or a parameter:value change</span><span
+ style="font-family: monospace;"></span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;
+ &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; pp - Practical Reflection
+ Print
+ (ISO-3664 P2)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+ pe - Print evaluation environment (CIE 116-1995)<br>
+ </span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+ pc - Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
+ style="font-family: monospace;"></span><span style="font-family:
+ monospace;"></span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp;
+ &nbsp; &nbsp; &nbsp; mt - Monitor in typical work environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; mb - Monitor in bright work environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; md - Monitor in darkened work
+ environment</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; jm - Projector in dim environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; jd - Projector in dark environment</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp; &nbsp;&nbsp;
+ &nbsp;&nbsp;&nbsp; pcd - Photo CD - original scene
+ outdoors</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; ob - Original scene - Bright Outdoors</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp;
+ &nbsp;&nbsp;&nbsp; cx - Cut Sheet Transparencies on a viewing
+ box</span></small><br style="font-family: monospace;">
+ <small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+s:surround&nbsp;&nbsp;
+ n = auto, a = average, m = dim, d = dark,</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+ &nbsp; &nbsp;&nbsp; c = transparency (default average)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+w:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Adapted white point
+ as XYZ (default media white)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+w:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Adapted white point as
+ x, y</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+a:adaptation
+ Adaptation luminance in
+ cd.m^2
+ (default 50.0)</span><br style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+b:background
+ Background % of image luminance (default 20)<br>
+ &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; l:scenewhite Scene
+ white in
+ cd.m^2 if surround = auto (default 250)<br style="font-family:
+ monospace;">
+ </span><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Flare
+ light % of image luminance (default 1)</span><br
+ style="font-family: monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+ &nbsp;&nbsp;
+ f:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Flare color as
+ XYZ (default media white)</span><br style="font-family:
+ monospace;">
+ <span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Flare color as x, y<br>
+ &nbsp;-O outputfile Override the default output filename &amp;
+ extension.<br style="font-family: monospace;">
+ </span></small><br>
+ <h3>Usage Details and Discussion<br>
+ </h3>
+ The<b> -v</b> flag dumps out the ICC profile header information.<br>
+ <br>
+ The <b>-d</b> parameter controls the level of detail displayed in
+ the
+ surface. The parameter roughly corresponds to a deltaE value, so
+ smaller
+ values
+ give greater detail. The default value is around 10, and is a good
+ place
+ to start. Small values may take a lot of time to generate, and will
+ produce
+ big files.<br>
+ <br>
+ The <b>-w</b> flag causes a VRML file to be produced, as well as a
+ gamut file.<br>
+ <br>
+ The <b>-n</b> flag suppresses the L*a*b* axes being created in
+ the
+ VRML.<br>
+ <br>
+ The <span style="font-weight: bold;">-k</span> flag adds markers
+ for
+ each of the primary and secondary "cusp" points (Red, Yellow, Green,
+ Cyan, Blue &amp; Magenta). No markers will be displayed if the cusps
+ cannot be determined.<br>
+ <br>
+ The <span style="font-weight: bold;">-f</span> <span
+ style="font-weight: bold;">perc</span> parameter turns on
+ filtering of
+ the raster colors. The colors from the image are clustered, and then
+ sorted according to popularity, and then the <span
+ style="font-weight: bold;">perc</span> most common percentage of
+ colors are used to create the gamut surface. This may be useful in
+ creating a source gamut mapping surface that favors the important
+ colors within an image, and doesn't attempt to compress the color
+ reproduction in order to reproduce the little used colors. A value
+ of <span style="font-weight: bold;">perc</span> of 90 or 80 may be
+ a good place
+ to start. Note that the filtering is performed independently on each
+ raster image processed, with the final gamut being the union of all
+ the
+ filtered image gamuts.<br>
+ <br>
+ The <b>-i</b> flag selects the intent transform used for a lut
+ based
+ profile. It also selects between relative and absolute colorimetric
+ for
+ non-lut base profiles. Note that anything other than colorimetric
+ may
+ not represent the
+ native capabilities of the device. The default intent will be
+ absolute
+ colorimetic for L*a*b* output, and CIECAM02 appearance for Jab
+ output.<br>
+ <br>
+ An ICC profile is allowed to contain more than the minimum number of
+ elements or table needed to describe a certain transform, and may
+ contain redundant descriptions. &nbsp;By default, LUT based table
+ information will be used first if present, followed by matrix/shaper
+ information, and only using monochrome
+ information if it is all that is present. The <b>-o</b> flag,
+ reverses
+ this
+ order.&nbsp;&nbsp;&nbsp; <br>
+ <br>
+ <span style="font-weight: bold;">-p</span>: By default the gamut
+ will
+ be created in L*a*b* colorspace. If&nbsp; <span style="font-weight:
+ bold;">-pj</span> is selected, then CIECAM02
+ appearance space Jab will be used for the output, and the viewing
+ conditions will be taken into account. Jab space is what is normally
+ needed to be compatible with the default intents used in <a
+ href="colprof.html">colprof</a>. <span style="font-weight: bold;"><br>
+ </span>Note that the CIECAM02 output space selection by default uses
+ the colorimetric transform of the profile resulting in the
+ appearance
+ of the native device, but that the perceptual or
+ saturation transforms may be used by selecting them using the <span
+ style="font-weight: bold;">-i</span> parameter, which may give a
+ different result with some profiles. This may be desirable if an
+ image
+ is to be transformed through the perceptual or saturation tables of
+ a
+ profile as part of a link with an Argyll generated output profile,
+ since it will then represent the apparent gamut of the image when
+ subject to these tables. If the absolute colorimetric intent is
+ chosen
+ using <span style="font-weight: bold;">-ia</span> in combinations
+ with
+ <span style="font-weight: bold;">-pj</span>, then&nbsp; Jab with
+ a fixed white reference is used, which emulates an absolute CIECAM02
+ Jab
+ appearance space. <br>
+ <br>
+ The <span style="font-weight: bold;">-c</span> parameter sets the
+ output space to CIECAM02 appearance Jab values, and also allows
+ choosing
+ a set of viewing conditions, either by choosing a typical viewing
+ environment, or controlling
+ particular viewing condition parameters. This is only functional if
+ an
+ ICC profile is provided.<br>
+ <br>
+ The <span style="font-weight: bold;">-O</span> parameter allows the
+ output file name &amp; extension to be specified independently of
+ the
+ last tiff/jpeg
+ filename. Note that the full filename must be specified, including
+ the
+ extension.<br>
+ <br>
+ If the TIFF or JPEG files are in a device space (ie. RGB, CMYK
+ etc.), then it
+ is
+ necessary to supply an ICC profile to translate the device space
+ values
+ to a CIE space value such as L*a*b* or CIECAM02 Jab space for
+ creating
+ a gamut surface. For the ICC profile provided it is then possible to
+ select exactly what type of conversion is used. A TIFF or JPEGfile
+ with an
+ embedded ICC profile may be supplied as the profile argument - e.g.
+ to
+ get the gamut of a tiff file that contains an embedded profile use
+ something like:<br>
+ <br>
+ &nbsp;&nbsp;&nbsp; tiffgamut image.tif image.tif<br>
+ <br>
+ If a TIFF file is
+ already in a CIE space such as CIELab or ICCLab, then it is not
+ necessary to select an ICC profile,&nbsp; although a PCS to PCS
+ colorspace profile may be chosen. All the TIFF and JPEG files
+ must be in the same colorspace.<br>
+ <br>
+ One or more TIFF and/or JPEG files may be specified, and the gamut
+ is the union of
+ the gamuts of each file. This is useful for creating an image
+ specific
+ gamut mapping that can be applied to a set of images with consistent
+ results between the images. Note that the output gamut file name
+ will
+ by default be taken from the last TIFF or JPEG file specified, with
+ the .gam
+ extension added automatically. The <span style="font-weight: bold;">-O</span>
+ parameter will override this default.<br>
+ <br>
+ <span style="font-weight: bold;">NOTES</span><br>
+ <br>
+ The white and black points put in the gamut are the colorspace white
+ and black points. For the purposes of latter gamut mapping, it is
+ assumed that the image should retain it's position within the
+ colorspace dynamic range. For an L*a*b* image, the values value
+ 100,0,0
+ and 0,0,0 for white and black are assumed. An image in L*a*b* should
+ be
+ adjusted be neutral to, and sit within the dynamic range of those
+ white
+ and black points.<br>
+ <br>
+ <br>
+ <span style="font-weight: bold;"></span><br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/timage.html b/doc/timage.html
new file mode 100644
index 0000000..2daed27
--- /dev/null
+++ b/doc/timage.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>timage</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>render/timage</b></h2>
+<h3>Summary</h3>
+Create TIFF test image, suitable for evaluating various color
+transformations. By default a test image consisting of two hexagons and
+a grey wedge is produced. The two hexagons are the white and black
+corners of the RGB cube surface. This is useful in checking gamut
+mapping behaviour applied to an RGB colorspace.<br>
+<br>
+<img alt="RGB cube surface" src="cube.jpg"
+ style="width: 200px; height: 101px;"><br>
+<br>
+&nbsp;An alternate rectangular "rainbow" representation of the surface
+of an RGB
+cube can also be created. <br>
+<br>
+<img alt="RGB rectangular surface" src="surface.jpg"
+ style="width: 200px; height: 148px;"><br>
+<br>
+A third type is a set of stepped rectangles that explore the L*a*b*
+space, useful for testing profiles B2A tables (-p 6):<br>
+<br>
+<img alt="Lab steps image" src="LabSteps.jpg"
+ style="width: 150px; height: 150px;"><br>
+<h3>Usage Summary</h3>
+<small><span style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;">usage: timage [-options] outfile.tif</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbose</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Generate rectangular boundary test chart<br>
+&nbsp;-p steps&nbsp;&nbsp;&nbsp;&nbsp; Generate a colorspace step chart
+with L* steps^2<br style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;-r
+res&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Resolution
+in DPI (default 200)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Smooth blend</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+16 bit output</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-g
+prop&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Percentage towards grey
+(default 0%)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;outfile.tif&nbsp; Profile
+to check against</span></small><br>
+<h3>Usage Details and Discussion<br>
+</h3>
+The<b> -v</b> flag increases verbosity.&nbsp;&nbsp; <br>
+<br>
+The default behaviour is to create the two hexagon plus grey wedge test
+image. If the <span style="font-weight: bold;">-t</span> flag is used,
+the alternate single rectangular surface test image&nbsp; is generated.
+If the <span style="font-weight: bold;">-p steps</span> parameter is
+given, than an L*a*b* test chart is generated.<br>
+<br>
+The dots per inch of the image can be set using the <span
+ style="font-weight: bold;">-r</span> parameter. Increasing this,
+increases the size and detail of the image.<br>
+<br>
+Normally the images are generated using linear blending of the RGB
+values. If the <span style="font-weight: bold;">-s</span> flag is
+used, a smoother blending is employed. This is most desirable when
+generating the rectangular test image.<br>
+<br>
+Normally an 8 bit per color component image is generated. If the <span
+ style="font-weight: bold;">-x</span> flag is use, a 16 bit per color
+component image will be generated, giving smoother blends, particularly
+if a higher resolution (DPI) image is created.<br>
+<br>
+The hexagon and surface test images are normally the surface colors of
+the RGB colorspace
+cube. If a percentage greater than 0% is given as an argument to the <span
+ style="font-weight: bold;">-g</span> option, a test chart composed of
+colors away from the RGB cube surface, towards the center grey point
+will be generated. 100% will generate a completely grey image. Values
+of 10, 20 to 50% are more usual.<br>
+<br>
+The L*a*b* step chart explores the range of L*a*b* values that are
+handled by an L*a*b* PCS B2A table, with the L* stepping from 0 to 100
+in steps from the top left to the bottom right square, while the a*
+values range from -127 to 127 left to right in each square, and the b*
+values range from -127 to 127 bottom to top in each square.<br>
+<br>
+The last argument on the command line is the name of the TIFF file to
+save the resulting image to.<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/txt2ti3.html b/doc/txt2ti3.html
new file mode 100644
index 0000000..744a576
--- /dev/null
+++ b/doc/txt2ti3.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>txt2ti3</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>profile/txt2ti3</b></h2>
+<h3>Summary</h3>
+<small><big>Convert
+Gretag/Logo/X-Rite or other CGATS format RGB or CMYK test chart results
+into</big></small> Argyll&nbsp;<a href="File_Formats.html#.ti3">.ti3</a>
+CGATS
+format.&nbsp;
+<h3>Usage Summary</h3>
+<small><span style="font-family: monospace;">txt2ti3 [-v] [-l limit]
+[-d] [devfile] infile [specfile] outfile</span><br
+ style="font-family: monospace;">
+<br style="font-family: monospace;">
+<span style="font-family: monospace;">-2<span
+ style="font-style: italic;"> &nbsp; &nbsp; &nbsp;</span>
+&nbsp;&nbsp;&nbsp;&nbsp; create a dummy .ti2 file as well.<br>
+</span></small><small><span style="font-family: monospace;">-l </span><i
+ style="font-family: monospace;">limit</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set ink
+limit, 0
+-
+400% (default max in file)<br>
+-d&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set type of device as Display, not Output<br>
+-i&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set type of device as Input, not Output<br
+ style="font-family: monospace;">
+</span></small><small><span style="font-family: monospace;"></span><i
+ style="font-family: monospace;">[devfile]</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; Input Device
+CMYK
+target file (typically file.txt)</span><br
+ style="font-family: monospace;">
+<i style="font-family: monospace;">infile&nbsp;</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Input
+CIE, Spectral or Device &amp; Spectral file (typically file.txt)</span><br
+ style="font-family: monospace;">
+<i style="font-family: monospace;">[specfile]</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; Input Spectral
+file (typically file.txt)</span><br style="font-family: monospace;">
+<i style="font-family: monospace;">outbasefile</i><span
+ style="font-family: monospace;">&nbsp;&nbsp; Base name for
+output</span><a style="font-family: monospace;"
+ href="File_Formats.html#.ti3">.ti3</a><span
+ style="font-family: monospace;"> and <a href="File_Formats.html#.ti2">.ti2</a>
+file</span></small>
+<br>
+<h3>Usage Details and Discussion</h3>
+txt2ti3 takes the Gretag/Logo/X-Rite/etc. test chart
+results, and converts them
+into Argyll&nbsp;<a href="File_Formats.html#.ti3">.ti3</a> CGATS files.<br>
+It is quite common to find profile test chart data from various
+standards bodies and industry organizations in one of these formats,
+so it is
+useful to be able to convert them for use with Argyll. ICC profiles
+created using Gretag Profile Maker also commonly contain the test chart
+results embedded in the profile, inside an ICC tag.<br>
+<br>
+A variety of different packaging of Gretag/Logo data can be accepted: <br>
+<br>
+1&nbsp;source files, consisting of a combined device value and CIE
+and/or spectral values.<br>
+2 source files, consisting of &nbsp;a file containing the device
+values, and a file containing the CIE and/or spectral values.<br>
+2 source files, consisting of a file containing the device values and
+the CIE values, and a file containing the spectral values.<br>
+3 source files, consisting of a file containing the device values, a
+file containing the CIE values, and a file containing the spectral
+values.<br>
+<br>
+X-Rite ColorPort seems to produce a single source file containing
+combined device value and CIE
+and/or spectral values.<br>
+<br>
+The Gretag/Logo test chart results format seem to change with each
+minor release of Profile Maker, so this tool may not work in all
+cases.<br>
+<br>
+The <span style="font-style: italic;">outbasefile</span> is the base
+of the output file(s), to which txt2ti3 will automatically append a
+.ti3 and .ti2 extension.<br>
+<br>
+The input files may have data that is scaled to one of three levels:
+1.0, 100.0 or 255.0, and txt2ti3 attempts to guess what the appropriate
+range is, in order to scale to Argyll's standard range 0 .. 100.0.<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/doc/ucmm.html b/doc/ucmm.html
new file mode 100644
index 0000000..31d95cb
--- /dev/null
+++ b/doc/ucmm.html
@@ -0,0 +1,122 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>ucmm conventions and format.</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2>ucmm organization and conventions.<br>
+</h2>
+ucmm (Unix micro Color Management Module) is a color management module
+designed just to handle the necessary configuration needed to track the
+installation and association of ICC profiles with Unix/Linux X11
+displays. It could be expanded at some point to also hold the
+associations for other devices such as scanner and printers.<br>
+<br>
+It consists primarily of a small configuration database that associates
+a display monitor (identified by its EDID or the X11 display name if an
+EDID is not known) with an ICC Display profile.<br>
+<br>
+There are two configuration contexts, <span style="font-weight: bold;">local
+system</span> and <span style="font-weight: bold;">per user</span>,
+the latter taking
+precedence when both are present.<br>
+<br>
+ucmm follows the <a
+ href="http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html">XDG
+Base Directory specifications</a> for the location of the configuration
+file and display profiles.<br>
+<br>
+For the <span style="font-weight: bold;">local system</span> context,
+the ucmm configuration file is located at:<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $XDG_CONFIG_DIRS/color.jcnf<br>
+or&nbsp;&nbsp; /etc/xdg/color.jcnf<br>
+<br>
+and display profiles are stored in<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $XDG_DATA_DIRS/color/icc/devices/display/<br>
+or&nbsp;&nbsp; /usr/local/share/color/icc/devices/display/<br>
+<br>
+For <span style="font-weight: bold;">per user</span> contents, the
+ucmm configuration file is located at:<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $XDG_CONFIG_HOME/color.jcnf<br>
+or&nbsp;&nbsp; $HOME/.config/color.jcnf<br>
+<br>
+and display profiles are stored in<br>
+<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $XDG_DATA_HOME/color/icc/devices/display/<br>
+or&nbsp;&nbsp; $HOME/.local/share/color/icc/devices/display/<br>
+<br>
+The configuration format of the <span style="font-weight: bold;">color.jcnf</span>
+files uses the <a href="http://www.json.org/">JSON JavaScript Object
+Notation</a>,
+a lightweight data-interchange format.<br>
+<br>
+A hierarchy of members is used to represent a hierarchical key/value
+pair format.<br>
+<br>
+The monitor to ICC profile association is organized as independent
+records, having the form:<br>
+<br>
+&nbsp; <span style="font-weight: bold;">key</span>&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+<span style="font-weight: bold;">value</span><br>
+<br>
+&nbsp; devices/display/<span style="font-weight: bold;">N</span>/EDID&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp; Monitor EDID&nbsp; in upper case Hexadecimal <br>
+&nbsp; devices/display/<span style="font-weight: bold;">N</span>/ICC_PROFILE&nbsp;&nbsp;
+&nbsp;&nbsp; Full path to the associated ICC profile<br>
+<br>
+or<br>
+<br>
+&nbsp; devices/display/<span style="font-weight: bold;">N</span>/NAME
+&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; X11 display name <br>
+&nbsp; devices/display/<span style="font-weight: bold;">N</span>/ICC_PROFILE&nbsp;&nbsp;
+&nbsp;&nbsp; Full path to the associated ICC profile<br>
+<br>
+where <span style="font-weight: bold;">N</span> is a number starting
+from 1, that distinguishes each record, but otherwise has no special
+meaning.<br>
+<br>
+The first form is the preferred form, since it associates the profile
+with the actual display, and therefore it is possible to have the
+profile track the display, no matter which X11 screen it is plugged
+into. The second form is a fallback, for situations in which a monitor
+does not have an EDID, or where the X11 server is configured in a way
+that does not permit access to the EDID (i.e.., on a second screen when
+Xinerama is running).<br>
+<br>
+The following is an example of a per user color.jcnf:<br>
+<br>
+{<br>
+&nbsp; "devices": {<br>
+&nbsp;&nbsp;&nbsp; "display": {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "1": {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "EDID":
+"0x00FFFFFFFFFFFF0034A1731751720000150901010C1F17CDE8A11E9E554A982712474FA4CE0045598180315961590101010101010101000000FE004D6F6E69746F720A2020202020000000FE004D6F6E69746F720A2020202020000000FE004D6F6E69746F720A2020202020000000FE004D6F6E69746F720A2020202020003D",<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "ICC_PROFILE":
+"/home/graeme/.local/share/color/devices/display/mon1.icc"<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "2": {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "NAME": ":0.1",<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "ICC_PROFILE":
+"/home/graeme/.local/share/color/devices/display/mon2.icc"<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
+&nbsp;&nbsp;&nbsp; }<br>
+&nbsp; }<br>
+}<br>
+<br>
+<h3>Implementation</h3>
+The configuration file format is in the <span
+ style="font-weight: bold;"></span>Argyll
+source in the jcnf sub directories, and the ucmm functionality in the
+ucmm sub directories, and is made available under an MIT like free use
+license.
+</body>
+</html>
diff --git a/doc/verify.html b/doc/verify.html
new file mode 100644
index 0000000..bd4a953
--- /dev/null
+++ b/doc/verify.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+ <head>
+ <title>verify</title>
+ <meta http-equiv="content-type" content="text/html;
+ charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+ </head>
+ <body>
+ <h2><b>profile/verify</b></h2>
+ <h3>Summary</h3>
+ Verify a color transform by comparing CIE measurement values from
+ two test charts. The charts can be any suitably formatted CGATS or <a
+ href="File_Formats.html#.ti3">.ti3</a> format that contains
+ corresponding XYZ, Lab or spectral values. The overall average and
+ worst case delta E will be reported, as well as the worst 10% and
+ best 90% of values.<br>
+ <h3>Usage Summary</h3>
+ <tt><small>verify&nbsp; [-options] target.ti3 measured.ti3<br>
+ &nbsp;-v&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+ &nbsp; Verbose - print each patch value<br>
+ &nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Normalise
+
+ each files reading to white Y<br>
+ &nbsp;-N&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Normalise
+
+ each files reading to white XYZ<br>
+ &nbsp;-D&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Use
+
+ D50 100.0 as L*a*b* white reference<br>
+ &nbsp;-c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+ &nbsp; Show CIE94 delta E values<br>
+ &nbsp;-k &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; Show CIEDE2000 delta E values<br>
+ &nbsp;-s &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; Sort patch value by error<br>
+ &nbsp;-w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+ &nbsp; create VRML vector visualisation (measured.wrl)<br>
+ </small></tt><tt><small>&nbsp;-W
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ &nbsp; &nbsp; create VRML marker &amp; vector visualisation
+ (measured.wrl)</small></tt><tt><br>
+ </tt><tt> </tt><tt><small>&nbsp;-x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+
+ &nbsp; Use VRML axes<br>
+ &nbsp;</small></tt><tt><small><small>-f
+ [illum]&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Use Fluorescent
+ Whitening Agent compensation [opt. simulated inst. illum.:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or
+ file.sp]<br>
+ &nbsp;-i illum&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+ Choose illuminant for computation of CIE XYZ from spectral
+ data &amp; FWA:<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp<br>
+ &nbsp;-o observ&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Choose
+ CIE Observer for spectral data:<br>
+ </small><small>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+
+ 1931_2 </small><small>(def.)</small><small>, 1964_10, S&amp;B
+ 1955_2, shaw, J&amp;V 1978_2</small><br>
+ &nbsp;<i>target.ti3</i>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; Target or
+ reference patch data file<br>
+ &nbsp;<i>measured.ti3</i> &nbsp; &nbsp; Measured or actual patch
+ data file</small></tt><br>
+ <h3>Usage Details and Discussion</h3>
+ <b> verify</b> provides a way of verifying how well a color
+ transformation (such a proofing) performs.<br>
+ <br>
+ The <b>-v</b> flag prints out extra information during the
+ checking, and prints each patch value, rather than just a summary.<br>
+ <br>
+ The <b>-n</b> flag causes the two sets of values to be normalized
+ to the Y value of white for each set before comparison. White is
+ assumed to be the patch with the largest Y value.<br>
+ <br>
+ The <b>-N</b> flag causes the two sets of values to be normalized
+ to the XYZ of white for each set before comparison. White is assumed
+ to be the patch with the largest Y value.<br>
+ <br>
+ The <b>-D</b> flag causes the white reference point for the
+ conversion to L*a*b* to be D50 with a Y value of 100%. By default
+ the sample with the largest Y value is found, and the L*a*b* white
+ reference scaled to have that Y value. This allows sensible delta E
+ values when comparing absolute color values, such as those from
+ emission or display measurements.<br>
+ <br>
+ The <b>-c</b> option causes the differences between the test values
+ and the profile prediction of the color for each device value to be
+ displayed in CIE94 delta E, rather than plain L*a*b* delta E. CIE94
+ delta E has a closer correspondence with perceived color differences
+ than the default CIE76 delta E values.<br>
+ <br>
+ The <b>-k</b> option causes the differences between the test values
+ and the profile prediction of the color for each device value to be
+ displayed in CIEDE2000 delta E, rather than plain L*a*b* delta E.
+ CIEDE2000 delta E has a closer correspondence with perceived color
+ differences than either CIE76 or CIE94 delta E values.<br>
+ <br>
+ If the <b>-s </b>flag is used in combination with the <b>-v</b>
+ flag, then the test point by test point output will be sorted from
+ worst to best.<br>
+ <br>
+ The <b>-w</b> creates a <a href="File_Formats.html#VRML">VRML</a>
+ 3D visualization of the differences between the test points in D50
+ L*a*b* space, each difference being shown as a line vector. If the <span
+ style="font-weight: bold;">-W</span> flag is used, then the target
+ and measured values will also be marked by a small sphere. This can
+ be used to visualize the placement of values in a .ti3 (or other
+ CGATS file) by using the same file for both "target" and "measured"
+ values.<br>
+ <br>
+ The <b>-x</b> flag adds Lab axes to the VRML output.<br>
+ <br>
+ The <b>-f</b> flag enables Fluorescent Whitening Agent (FWA)
+ compensation. This only works if spectral data is available and, the
+ instrument is not UV filtered.&nbsp; FWA compensation adjusts the
+ spectral samples so that they appear to have been measured using an
+ illuminant that has a different level of Ultra Violet to the one the
+ instrument actually used in the measurement. The optional
+ illumination parameter allows specifying a standard or custom
+ illumination spectrum to be used as the similated instrument
+ illuminant, overriding the default <b>D50</b> or CIE computation
+ illuminant used for FWA (see <b>-i</b> below<b>). </b>See <a
+ href="colprof.html#f">colprof -f</a> for a fuller explanation. The
+ same value should be used as was used during the creation of the
+ profile.<br>
+ <br>
+ The <b>-i</b> flag allows specifying a standard or custom
+ illumination spectrum, applied to the spectral test point values to
+ compute CIE tristimulus values. <b>A</b>, <b>D50</b>, <b>D50M2,
+ D65</b>, <b>F5</b>, <b>F8</b>, <b>F10</b> are a selection of
+ standard illuminant spectrums, with <b>D50</b> being the default.
+ If a filename is specified instead, it will be assumed to be an
+ Argyll specific <a href="File_Formats.html#.sp">.sp</a> spectrum
+ file. If FWA compensation is used during measurement, this
+ illuminant will be used by default as the simulated instrument
+ illuminant. The same value should be used as was used during the
+ creation of the profile.<br>
+ <br>
+ The <b>-o</b> flag allows specifying a tristimulus observer, and is
+ used to compute PCS (Profile Connection Space) tristimulus values.
+ The following choices are available:<br>
+ <b>&nbsp; 1931_2</b> selects the standard CIE 1931 2 degree
+ observer. The default.<br>
+ &nbsp; <b>1964_10</b> selects the standard CIE 1964 10 degree
+ observer.<br>
+ &nbsp; <b>1955_2</b> selects the Stiles and Birch 1955 2 degree
+ observer<br>
+ &nbsp; <b>1978_2 </b>selects the Judd and Voss 1978 2 degree
+ observer<br>
+ &nbsp; <b>shaw</b> selects the Shaw and Fairchild 1997 2 degree
+ observer<br>
+ <br>
+ The same parameter value should be used as was used during the
+ creation of the profile.<br>
+ <br>
+ If both CIE and spectral values are present in the input files, the
+ CIE values will be used by default. Using the <span
+ style="font-weight: bold;">-i</span>, <span style="font-weight:
+ bold;">-o</span> or <span style="font-weight: bold;">-f</span>
+ flag will force spectral values to be used. The the <span
+ style="font-weight: bold;">-i</span>, <span style="font-weight:
+ bold;">-o</span> or <span style="font-weight: bold;">-f</span>
+ flags will apply to both the target and measured input files.<br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ <br>
+ </body>
+</html>
diff --git a/doc/viewgam.html b/doc/viewgam.html
new file mode 100644
index 0000000..0bf5c04
--- /dev/null
+++ b/doc/viewgam.html
@@ -0,0 +1,125 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>viewgam</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>gamut/viewgam</b></h2>
+<h3>Summary</h3>
+Convert one or more gamuts into a&nbsp;<a href="File_Formats.html#VRML">VRML</a>
+3D visualization
+file. &nbsp;This allows visual comparison of several gamut surfaces.<br>
+Also allows creating the intersection (overlap) between two gamuts.
+This is useful in measuring and visualizing the coverage of one gamut
+of another.<br>
+<h3>Usage<br>
+</h3>
+<small><span style="font-family: monospace;">viewgam { [-c color] [-t
+trans] [-w|s] </span><span
+ style="font-style: italic; font-family: monospace;">infile.gam</span><span
+ style="font-family: monospace;"> } ... </span><span
+ style="font-style: italic; font-family: monospace;">outfile.wrl</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+For each input gamut file:</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-c </span><i
+ style="font-family: monospace;">color</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Color
+to
+make gamut,
+r = red, g = green, b = blue</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+c = cyan, m = magenta, y = yellow, w = white</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+n = natural color</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-t </span><i
+ style="font-family: monospace;">trans</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Set
+transparency
+from 0.0 (opaque) to 1.0 (invisible)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-w&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Show as a wireframe</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Show as a solid surface</span><br style="font-family: monospace;">
+<i style="font-family: monospace;"> &nbsp;infile.gam</i><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name
+of </span><i style="font-family: monospace;">infile</i><a
+ style="font-family: monospace;" href="File_Formats.html#.gam">.gam</a><span
+ style="font-family: monospace;"> file</span><br
+ style="font-family: monospace;">
+<br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;-n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Don't add Lab axes<br>
+&nbsp;-i &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Compute
+and print intersecting volume of first 2 gamuts<br>
+&nbsp;-I isect.gam&nbsp;&nbsp; Same as -i, but save intersection gamut
+to isect.gam<br style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;</span><i
+ style="font-family: monospace;">outfile.wrl</i><span
+ style="font-family: monospace;"> Name of output
+</span><i style="font-family: monospace;">outfile.wrl</i><span
+ style="font-family: monospace;"> file</span></small>
+<br>
+<h3>Usage Details and Discussion</h3>
+<b>viewgam</b> creates a VRML file that allows the &nbsp;viewing and
+comparing
+of multiple gamut files by representing them as solid surfaces,
+wireframes,
+etc. It takes as input a list of gamut files, each file preceded by any
+options that are to apply to the display of &nbsp;that particular
+gamut.
+<br>
+<br>
+The options that can be specified for each input gamut are:<br>
+<br>
+<b>-c</b> <i>color</i> allows the color of the surface or wireframe to
+be
+specified. Any of a number of predefined colors (red, green, blue,
+cyan,
+magenta, yellow, white) can be used, as well as allowing the color to
+reflect
+the natural color of that point in the colorspace.<br>
+<br>
+<b>-t</b> <i>trans</i> allows the transparency of the surface&nbsp; to
+be
+specified. A value of 0.2 might be a good place to start. Using
+transparency
+generally leads to a slower display than the default opaque surface
+treatment, but can make it possible to see within a solid gamut surface.<br>
+<br>
+<b>-w</b> forces the gamut surface to be rendered as a wireframe.<br>
+<br>
+<b>-s</b> forces the gamut surface to be rendered as a solid surface.<br>
+<br>
+By default, the first gamut is treated as a solid with natural
+coloring,
+with the second and subsequent gamuts being wireframes with colors of
+white,
+red, cyan, yellow, green and blue, with decreasing visibility.<br>
+<br>
+The <b>-n</b> flag turns off display of the default L*a*b* axes in the
+output.<br>
+<br>
+The <span style="font-weight: bold;">-i</span> flag computes the
+intersecting volume of the first two gamuts (in cubic color units,
+usually L*a*b*), as well as the volumes of the two gamuts and the
+percentage the intersection is of the two gamuts. This is a useful
+measure of the coverage one gamut has of another. If <span
+ style="font-weight: bold;">-I</span> is used, then as well as printing
+the volume, the intersecting gamut will be saved to the <span
+ style="font-style: italic;">isect.gam</span> file.<br>
+<br>
+The final argument is the name of the VRML file to save the resulting
+composite
+3D visualization file to.<br>
+<br>
+</body>
+</html>
diff --git a/doc/xicclu.html b/doc/xicclu.html
new file mode 100644
index 0000000..8377c69
--- /dev/null
+++ b/doc/xicclu.html
@@ -0,0 +1,551 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>xicclu</title>
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="author" content="Graeme Gill">
+</head>
+<body>
+<h2><b>xicc/xicclu</b>&nbsp; </h2>
+<h3>Summary&nbsp;<br>
+</h3>
+Lookup individual color values forward or inverted though an ICC
+profile table. <b>xicclu</b> is the analogue of the icclib tool <a
+ href="icclu.html">icclu</a>, but expands the capability to reverse
+lookup the Lut tables, and displaying PCS values in CIECAM02 Jab space.
+<b>xicclu</b>
+can also be used to plot the device value composition down the neutral
+axis,
+for device profiles.<br>
+<h3>Usage Summary</h3>
+&nbsp;<small><span style="font-family: monospace;">xicclu [-</span><i
+ style="font-family: monospace;">options</i><span
+ style="font-family: monospace;">] profile</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#v">-v level</a><span
+ style="font-family: monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Verbosity level 0 - 2 (default = 1)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#g">-g</a><span
+ style="font-family: monospace;"> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
+&nbsp; Plot slice instead of looking colors up. (Default white to black)<br>
+&nbsp;<a href="#Gs">-G s:L:a:b</a>&nbsp;&nbsp;&nbsp;&nbsp; Override
+plot slice start with Lab or Jab co-ordinate<br>
+&nbsp;<a href="#Ge">-G e:L:a:b</a>&nbsp;&nbsp;&nbsp;&nbsp; Override
+plot slice end with Lab or Jab co-ordinate<br
+ style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#f">-f function</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; f = forward, b =
+backwards, g = gamut, p = preview</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+if
+= inverted forward, ib = inverted backwards</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#i">-i intent</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a =
+absolute, r = relative colorimetric,</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+</span></small><small><span style="font-family: monospace;"> p =
+perceptual, </span></small><small><span style="font-family: monospace;">s
+=
+saturation</span><span style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#o">-o order</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; n
+= normal (priority: lut &gt; matrix &gt; monochrome)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+r
+= reverse (priority: monochrome &gt; matrix &gt;
+lut)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#p">-p oride</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; x
+= XYZ_PCS, X = XYZ * 100, l = Lab_PCS, L = LCh, y = Yxy,<br>
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; j = CIECAM02
+Appearance Jab, J = CIECAM02 Appearance JCh<br>
+</span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#s">-s scale</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Scale device range 0.0 - scale rather than 0.0 - 1.0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#k">-k [zhxrlv]</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; Black generation: z
+= zero K,</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+h = 0.5 K, x = max K, r = ramp K (def.)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+l = extra PCS input is portion of K locus</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+v = extra PCS input is K target value</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#kp">-k p stle stpo enpo enle
+shape</a><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+stle: K level at White 0.0 - 1.0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+stpo: start point of transition Wh 0.0 - Bk 1.0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+enpo: End point of transition Wh 0.0 - Bk 1.0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+enle: K level at Black 0.0 - 1.0</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+shape: 1.0 = straight, 0.0-1.0 concave, 1.0-2.0
+convex</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#kq">-k q stle0 stpo0 enpo0
+enle0 shape0 stle2 stpo2
+enpo2 enle2 shape2</a><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Transfer
+extra PCS input to dual curve limits</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#K">-K parameters</a><span
+ style="font-family: monospace;">&nbsp; Same as -k, but target is K
+locus rather than K value itself</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#l">-l tlimit</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set
+total ink limit, 0 - 400% (estimate by default)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#L">-L klimit</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set
+black ink limit, 0 - 100% (estimate by default)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#a">-a</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+show
+actual target values if clipped<br>
+&nbsp;<a href="#b">-b</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+use
+CAM Jab for clipping<br style="font-family: monospace;">
+</span><span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#m">-m</a><span
+ style="font-family: monospace;">
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+merge output processing into clut</span><span
+ style="font-family: monospace;"></span><span
+ style="font-weight: bold; font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;</span><a
+ style="font-family: monospace;" href="#c">-c viewcond</a><span
+ style="font-family: monospace;">&nbsp;&nbsp;&nbsp; set viewing
+conditions
+for CIECAM02,</span><br style="font-family: monospace;">
+&nbsp;&nbsp;</small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+either an enumerated choice, or a parameter:value change</span><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;"></span></small><small><span
+ style="font-family: monospace;">&nbsp;
+&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; pp - Practical Reflection Print
+(ISO-3664 P2)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+pe - Print evaluation environment (CIE 116-1995)<br>
+</span></small><small><span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;
+pc - Critical print evaluation environment (ISO-3664 P1)</span></small><small><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp; mt - Monitor in typical work environment</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp; mb - Monitor in bright work environment</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp; md - Monitor in darkened work
+environment</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp; jm - Projector in dim environment</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp; jd - Projector in dark environment</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp; pcd - Photo CD - original scene
+outdoors</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp; ob - Original scene - Bright Outdoors</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp; cx - Cut Sheet Transparencies on a viewing box</span></small><small><span
+ style="font-family: monospace;"></span><span
+ style="font-family: monospace;"></span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+s:surround&nbsp;&nbsp;
+n = auto, a = average, m = dim, d = dark,</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;
+&nbsp; &nbsp;&nbsp;&nbsp; c = transparency (default average)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+w:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Adapted white point
+as XYZ (default media white, Abs: D50)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+w:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Adapted white point as
+x, y</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+a:adaptation
+Adaptation luminance in
+cd.m^2
+(default 50.0)</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b:background Background %
+of image luminance (default 20)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:flare&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Flare
+light % of image luminance (default 1)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;
+&nbsp;
+f:X:Y:Z&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Flare color
+as XYZ (default media white, Abs: D50)</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+f:x:y&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Flare color as x, y</span><br style="font-family: monospace;">
+<br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;
+</span><a style="font-family: monospace;" href="#p1"><i>inoutfile</i></a><span
+ style="font-family: monospace;"> &nbsp;&nbsp; &nbsp;&nbsp; The input
+ICC profile</span><br style="font-family: monospace;">
+<br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; The colors to
+be translated should be fed into
+standard in,</span><br style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; one input
+color per line, white space separated.</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; A line
+starting with a # will be ignored.</span><br
+ style="font-family: monospace;">
+<span style="font-family: monospace;">&nbsp;&nbsp;&nbsp; A line not
+starting with a number will terminate the
+program.</span></small>
+<br>
+<h3>Flags and Parameters</h3>
+<a name="v"></a> The <b>-v</b> parameter sets the level of verbosity.
+Default is level 1, which repeats each input value, the colorspaces of
+input and output, the type of conversion algorithm used, and if the
+result was clipped. Level 2 adds prints extra information about the
+profile before doing the conversions. Level 0 turns off all verbosity,
+just outputting the results of each conversion. Use the latter to
+capture batch output ready for further processing.<br>
+<br>
+<a name="g"></a>The <b>-g</b> flag causes a plot of the device values
+along a slice through the Lab or Jab colorspace, rather than allowing
+the interactive looking up of color
+values. By default this will be the neutral axis
+from the white point to the black point, but the start and end can be
+overridden using the <span style="font-weight: bold;">-G</span>
+parameters.
+This is useful in determining the existing black generation in a CMYK
+profile,
+or exploring the behavior of various black generation options using
+the
+<b>-k</b> parameters. The profile must be a device profile, and the PCS
+must
+be either Lab or Jab. The default plot is up the neutral axis is from
+the white to
+the black point (scale 0 to 100%), and shows the percentage of each
+device colorant. To examine a profiles B2A table black
+generation,
+use the flag <b>-fb</b> to select the B2A table, or to invert the A2B
+table,
+and be able to explore black generation behavior, use the <b>-fif</b>
+flag.
+The appropriate intent can be selected with the <b>-i</b> flag,
+&nbsp;as
+can other flags appropriate to the function selected.&nbsp; See <a
+ href="#xg">example</a>.<br>
+<br>
+<a name="Gs"></a>The <span style="font-weight: bold;">-G </span><small><span
+ style="font-family: monospace;"><span style="font-weight: bold;">s:L:a:b</span></span></small>
+parameter overrides the plot slice start point of white, with some
+other point specified in Lab or Jab Profile Connection Space. The
+parameter must be a single string that combines<span
+ style="font-weight: bold;"> s:</span> with the three numbers separated
+by the '<span style="font-weight: bold;">:'</span> character (no
+spaces).<br>
+<br>
+<a name="Ge"></a>The <span style="font-weight: bold;">-G </span><small><span
+ style="font-family: monospace;"><span style="font-weight: bold;">e:L:a:b</span></span></small>
+parameter overrides the plot slice end point of black, with some
+other point specified in Lab or Jab Profile Connection Space. The
+parameter must be a single string that combines<span
+ style="font-weight: bold;"> s:</span> with the three numbers separated
+by the '<span style="font-weight: bold;">:'</span> character (no
+spaces).<br>
+<br>
+<a name="f"></a> The <b>-f</b> flag selects which type of table or
+conversion is to be used. In addition to the usual four tables that can
+be accessed in a fully populated Lut based profile, two additional
+options are available in <b>xicclu</b>. One is to invert the forward
+table, and the other is to invert the backward table. For non Lut based
+profiles, -fif is equivalent to -fb, and -fib is equivalent to -ff.
+Note that the -fib combination may not be fully supported.<br>
+<br>
+<a name="i"></a> The <b>-i</b> flag selects the intent table used for
+a lut based
+profile. It also selects between relative and absolute colorimetric for
+non-lut base profiles.<br>
+<br>
+<a name="o"></a> A profile is allowed to contain more than the minimum
+number of elements or table needed to describe a certain transform, and
+may contain redundant descriptions. &nbsp;By default, Lut based table
+information will be used first if present, followed by matrix/shaper
+information, and only using monochrome information if it is all that is
+present. The <b>-o</b> flag, reverses this order.&nbsp;&nbsp;&nbsp; <br>
+<br>
+<a name="p"></a> Normally the native PCS (Profile Connection Space) of
+a device or abstract profile is used, but the <b>-p</b> flag allows
+this to be overridden: <span style="font-weight: bold;">-px</span>:
+XYZ (scaled to 1.0), <span style="font-weight: bold;">-pX</span>: XYZ
+scaled to 100, <span style="font-weight: bold;">-pl</span>: L*a*b*, <span
+ style="font-weight: bold;">-pL</span>: LCh, <span
+ style="font-weight: bold;">-py</span>: Yxy space, <span
+ style="font-weight: bold;">-pj</span>: CIECAM02 appearance space Jab,
+or <span style="font-weight: bold;">-pJ</span>: CIECAM02 appearance
+space JCh.<span style="font-weight: bold;"><br>
+</span>Note that the CIECAM02 output space selection by default uses
+the colorimetric table of the profile, but that the perceptual or
+saturation tables may be used by selecting them using the <span
+ style="font-weight: bold;">-i</span> parameter. If the absolute
+colorimetric intent is chosen using <span style="font-weight: bold;">-ia</span>
+in combinations with <span style="font-weight: bold;">-pj</span>,
+then&nbsp; Jab with
+a fixed white reference is used, which emulates an absolute CIECAM02
+Jab
+appearance space. <br>
+<br>
+<a name="s"></a> Usually device values are processed and displayed
+using a normalized value range between 0.0 and 1.0 Sometimes other
+systems scale them to some other range (such as 100 or 255) due to an
+underlying binary representation. The <span style="font-weight: bold;">-s</span>
+flag lets you input and display such data in its normal range. For
+instance, if your device values have a range between 0 and 255, use <span
+ style="font-weight: bold;">-s 255.</span><br>
+<br>
+<a name="k"></a> When inverting a CMYK profile, (ie. using the -fif
+flag), an input PCS value can have many possible CMYK solutions. To be
+able to return a unique solution, a black level (or black inking rule)
+should be chosen. The choice here reflect similar choices in black
+generation available in other tools (eg. <a href="colprof.html">colprof</a>,
+<a href="collink.html"> collink</a>), with the addition of two extra
+options.<br>
+<br>
+&nbsp;Possible arguments to the <b>-k</b> option are:<br>
+<br>
+<b> -kz</b> selects minimum black (0.0)<br>
+<b> -kh</b> selects a black value of 0.5<br>
+<b> -kx</b> selects the maximum possible black (1.0)<br>
+<b> -kr</b> selects a linear black ramp, starting at minimum black for
+highlight, and maximum black for shadow (equivalent to -kp 0 0 1 1 1).
+This is the default.<br>
+<b> -kl</b> uses an extra (fourth) value entered after the input PCS
+value, to select a black locus target between 0.0 and 1.0.<br>
+<b> -kv</b> uses an extra (fourth) value entered after the input PCS
+value, to select a black value target value between 0.0 and 1.0.<br>
+<br>
+<b><a name="kp"></a>-k p stle stpo enpo enle shape</b>&nbsp; allows an
+arbitrary black value ramp to be defined, consisting of a starting
+value (stle) for highlights, a breakpoint L value (stpo) where it
+starts to transition to the shadow level, an end breakpoint L (enpo)
+where it flattens out again, and the finishing black level (enle) for
+the shadows. There is also a curve parameter, that modifies the
+transition from stle to enle to either be concave (ie.&nbsp; the
+transition starts gradually and and finished more abruptly) using
+values 0.0-1.0, with 0.0 being most concave, or convex (the transition
+starts more abruptly but finishes gradually), using values 1.0-2.0,
+with 2.0 being the most convex.<br>
+<br>
+Typical black value generation curve with parameters something
+like: -kp 0 .05 1 .9 .8<br>
+<br>
+<tt> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0 K &nbsp; |
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;enpo<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp; &nbsp; &nbsp;_______&nbsp;
+enle<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp; &nbsp;/<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp; &nbsp; /<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; &nbsp;/<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp; /<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; stle&nbsp;
+| ------/<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp; +-------------------<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0 K&nbsp;
+0.0&nbsp;&nbsp;&nbsp; stpo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.0<br>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+White&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+Black<br>
+</tt><br>
+<b><a name="kq"></a>-k q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2
+enpo2 enle2 shape2</b> is a combination of the <b>-kv</b> and <b>-kp</b>
+functionality, with the black being preserved in CMYK to CMYK linking,
+with the output black constrained to be between the first and second
+set of curve parameters.<br>
+<br>
+<a name="K"></a> <span style="font-weight: bold;">-K parameters.</span>
+Any of the <span style="font-weight: bold;">-k</span> options above
+can use the <span style="font-weight: bold;">-K</span> version, in
+which rather than a black value target being defined by the inking
+rule, a black <span style="text-decoration: underline;">locus</span>
+target is defined. For each lookup, the minimum possible black level
+and the maximum possible black level is determined, the former
+corresponding to a locus target of 0, and the latter corresponding to a
+locus target of 1. For instance, at
+the
+white point, no black will be used in the output, even if the black
+locus specifies a maximum (since the maximum amount of black that
+can be used to print white is actually zero). Similarly, at the black
+point, black may well be used, even if the black locus specifies
+zero black (since a certain amount of black is needed to achieve the
+desired density of color). <br>
+<tt> </tt><span style="text-decoration: underline;"></span><br>
+&nbsp;The <b>-g</b> flag can be used together with the <b>-fif</b>
+flag, to plot
+out the resulting black channel behaviour for various <b>-k</b>
+or <span style="font-weight: bold;">-K </span>parameter
+values.<br>
+<br>
+<b><a name="l"></a>-l</b> <i>tlimit</i>&nbsp; &nbsp;&nbsp; Sets the
+total ink limit (TAC, Total Area Coverage) for the CMYK inverse forward
+lookup, as a total percentage from 0% to 400%. If none is provided, it
+will be estimated from the profile relcolor B2A table. The ink limit
+will be in final calibrated device values if the profile includes
+calibration information.<br>
+<br>
+<b><a name="L"></a>-L</b> <i>klimit</i>&nbsp; &nbsp; Sets the black
+ink limit for the CMYK inverse forward lookup, as a total percentage
+from 0% to 100%. If none is provided, it will be estimated from the
+profile relcolor B2A table. The ink limit
+will be in final calibrated device values if the profile includes
+calibration information.<br>
+<br>
+<a name="a"></a> If the <b>-a</b> flag is used for inverse forward
+lookups, then if
+the target PCS value cannot be reproduced by the device (ie. it clips),
+then the achievable, clipped PCS value is displayed.<br>
+<br>
+<a name="b"></a> If the <b>-b</b> flag is used for inverse forward
+lookups, then out of gamut clipping will be performed in the CIECAM02
+Jab appearance colorspace, rather than L*a*b* colorspace.<br>
+<br>
+<a name="m"></a> The <b>-m</b> flag turns on an internal processing
+option, in which the per device curve lookup table processing is merged
+into the main multi-dimensional interpolation lut lookup.<br>
+<br>
+<a name="c"></a>Whenever PCS values are to be specified or displayed in
+Jab/CIECAM02
+colorspace, a set of viewing conditions will be used to determine the
+details of the conversion. The <b>-c</b> parameter allows the
+specification of the viewing conditions. Viewing conditions can be
+specified in two basic ways. One
+is to select from the list of "pre canned", enumerated viewing
+conditions, choosing one that is closest to the conditions that are
+appropriate for the media type and situation. Alternatively, the
+viewing conditions parameters can be specified in detail individually.
+If both methods are used, them the chosen enumerated condition will be
+used as a base, and its parameters will then be individually overridden.<br>
+<br>
+<a name="p1"></a> The final parameter is the name of the <a
+ href="File_Formats.html#ICC">ICC</a> profile to be used. On the
+MSWindows platform a .icm extension is generally used, and on Apple or
+Unix/Linux platforms a .icc extension is often used.<br>
+<h3>Usage and Discussion</h3>
+Typical usage for an output profile might be:<br>
+<br>
+&nbsp;&nbsp;&nbsp; xicclu -ff -ip profile.icm<br>
+<br>
+Normally the program is interactive, allowing the user to type in input
+color
+values, each number separated by a space, and the resulting output
+color
+being looked up and displayed after pressing return. To batch process
+a
+group of color values, prepare a text file containing each input value
+on
+a
+separate line, and use the input indirection facilities of your command
+line
+shell to redirect this input file into the standard input of xicclu.
+The
+output can be captured to a file by redirecting standard output to a
+file.
+In most shells this would be done something like this:<br>
+<br>
+&nbsp;&nbsp;&nbsp; xicclu -ff -ip profile.icm &lt; inputvalues.txt &gt;
+outputvalues.txt<br>
+<br>
+<a name="xg"></a>When plotting the neutral axis behavior, plotting the
+existing B2A table
+behavior would typically be done something like this:<br>
+<br>
+&nbsp;&nbsp;&nbsp; xicclu -g -fb profile.icm<br>
+<br>
+Exploring possible black generation and ink limiting behavior might be
+done
+like this:<br>
+<br>
+&nbsp;&nbsp;&nbsp; xicclu -g -fif -kp 0 .1 .9 1 .5 -l230 -L95
+profile.icm<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+<br>
+</body>
+</html>
diff --git a/firmware-package-builder/argyll-firmware-spyder2/debian/changelog b/firmware-package-builder/argyll-firmware-spyder2/debian/changelog
new file mode 100644
index 0000000..f29f51f
--- /dev/null
+++ b/firmware-package-builder/argyll-firmware-spyder2/debian/changelog
@@ -0,0 +1,12 @@
+argyll-firmware-spyder2 (1.1) unstable; urgency=low
+
+ * Moved firmware to /usr/share/color, which is freedesktop.org-compliant
+ and (more to the point) where Argyll 1.2.0 looks for it.
+
+ -- Roland Mas <lolando@debian.org> Thu, 05 Aug 2010 15:32:53 +0200
+
+argyll-firmware-spyder2 (1.0) unstable; urgency=low
+
+ * Package automatically generated from the Spyder2 driver CD.
+
+ -- Roland Mas <lolando@debian.org> Fri, 17 Apr 2009 22:28:37 +0200
diff --git a/firmware-package-builder/argyll-firmware-spyder2/debian/compat b/firmware-package-builder/argyll-firmware-spyder2/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/firmware-package-builder/argyll-firmware-spyder2/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/firmware-package-builder/argyll-firmware-spyder2/debian/control b/firmware-package-builder/argyll-firmware-spyder2/debian/control
new file mode 100644
index 0000000..74bb71a
--- /dev/null
+++ b/firmware-package-builder/argyll-firmware-spyder2/debian/control
@@ -0,0 +1,17 @@
+Source: argyll-firmware-spyder2
+Section: non-free/graphics
+Priority: optional
+Maintainer: Roland Mas <lolando@debian.org>
+Build-Depends: debhelper (>= 7)
+Standards-Version: 3.9.1
+
+Package: argyll-firmware-spyder2
+Architecture: all
+Recommends: argyll
+Depends: ${misc:Depends}
+Description: ColorVision Spyder2 firmware for Argyll
+ Argyll is an open source, ICC compatible color management system. It
+ can drive display calibrators such as the ColorVision Spyder2, which
+ requires a firmware to be uploaded to the device. This package is
+ generated from the drivers CD provided with the Spyder2, and contains
+ the firmware ready to be used by Argyll.
diff --git a/firmware-package-builder/argyll-firmware-spyder2/debian/copyright b/firmware-package-builder/argyll-firmware-spyder2/debian/copyright
new file mode 100644
index 0000000..944cd3f
--- /dev/null
+++ b/firmware-package-builder/argyll-firmware-spyder2/debian/copyright
@@ -0,0 +1,8 @@
+The binary package contains the proprietary firmware for the
+ColorVision Spyder2 device. As such, it is not meant to be
+distributed.
+
+The source package itself (which builds the binary package) is
+Copyright 2009, Roland Mas, and can be distributed under the terms of
+the GNU General Public License, version 2 or (at your option) any
+later version published by the Free Software Foundation.
diff --git a/firmware-package-builder/argyll-firmware-spyder2/debian/install b/firmware-package-builder/argyll-firmware-spyder2/debian/install
new file mode 100644
index 0000000..ec9b7fa
--- /dev/null
+++ b/firmware-package-builder/argyll-firmware-spyder2/debian/install
@@ -0,0 +1 @@
+spyd2PLD.bin usr/share/color
diff --git a/firmware-package-builder/argyll-firmware-spyder2/debian/rules b/firmware-package-builder/argyll-firmware-spyder2/debian/rules
new file mode 100644
index 0000000..dac5410
--- /dev/null
+++ b/firmware-package-builder/argyll-firmware-spyder2/debian/rules
@@ -0,0 +1,10 @@
+#! /usr/bin/make -f
+
+%:
+ dh $@
+
+override_dh_auto_build:
+ cp /usr/local/share/color/spyd2PLD.bin .
+
+override_dh_auto_clean:
+ rm -f spyd2PLD.bin
diff --git a/gamut/GenRMGam.c b/gamut/GenRMGam.c
new file mode 100644
index 0000000..5a62eee
--- /dev/null
+++ b/gamut/GenRMGam.c
@@ -0,0 +1,786 @@
+
+/* Convert the proposed ISO 12640-3 Reference Medium Gamut to Argyll Lab Gamut */
+/* Copyright 2005 by Graeme W. Gill */
+/* All rights reserved. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "gamut.h"
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+
+/* Gamut surface points in LCh space */
+/* + black and white points */
+#define NPOINTS (684+2+3)
+
+double points[NPOINTS][3] = {
+ { 100, 0, 0 }, /* White */
+ { 3.1373, 0, 0 }, /* Black */
+ { 98.75, 30.75, 90 }, /* Three extra values along yellow ridge */
+ { 97.5, 61.5, 90 },
+ { 96.25, 92.25, 90 },
+ { 5, 10, 0 },
+ { 10, 25, 0 },
+ { 15, 38, 0 },
+ { 20, 50, 0 },
+ { 25, 62, 0 },
+ { 30, 73, 0 },
+ { 35, 80, 0 },
+ { 40, 86, 0 },
+ { 45, 89, 0 },
+ { 50, 86, 0 },
+ { 55, 85, 0 },
+ { 60, 81, 0 },
+ { 65, 73, 0 },
+ { 70, 65, 0 },
+ { 75, 55, 0 },
+ { 80, 45, 0 },
+ { 85, 34, 0 },
+ { 90, 23, 0 },
+ { 95, 12, 0 },
+ { 5, 10, 10 },
+ { 10, 24, 10 },
+ { 15, 37, 10 },
+ { 20, 50, 10 },
+ { 25, 61, 10 },
+ { 30, 71, 10 },
+ { 35, 80, 10 },
+ { 40, 88, 10 },
+ { 45, 90, 10 },
+ { 50, 89, 10 },
+ { 55, 85, 10 },
+ { 60, 81, 10 },
+ { 65, 73, 10 },
+ { 70, 65, 10 },
+ { 75, 55, 10 },
+ { 80, 45, 10 },
+ { 85, 34, 10 },
+ { 90, 22, 10 },
+ { 95, 11, 10 },
+ { 5, 10, 20 },
+ { 10, 22, 20 },
+ { 15, 36, 20 },
+ { 20, 50, 20 },
+ { 25, 62, 20 },
+ { 30, 73, 20 },
+ { 35, 80, 20 },
+ { 40, 90, 20 },
+ { 45, 93, 20 },
+ { 50, 91, 20 },
+ { 55, 86, 20 },
+ { 60, 83, 20 },
+ { 65, 73, 20 },
+ { 70, 70, 20 },
+ { 75, 55, 20 },
+ { 80, 50, 20 },
+ { 85, 35, 20 },
+ { 90, 25, 20 },
+ { 95, 11, 20 },
+ { 5, 9, 30 },
+ { 10, 22, 30 },
+ { 15, 34, 30 },
+ { 20, 48, 30 },
+ { 25, 61, 30 },
+ { 30, 74, 30 },
+ { 35, 86, 30 },
+ { 40, 98, 30 },
+ { 45, 99, 30 },
+ { 50, 101, 30 },
+ { 55, 95, 30 },
+ { 60, 90, 30 },
+ { 65, 81, 30 },
+ { 70, 73, 30 },
+ { 75, 65, 30 },
+ { 80, 52, 30 },
+ { 85, 35, 30 },
+ { 90, 30, 30 },
+ { 95, 12, 30 },
+ { 5, 8, 40 },
+ { 10, 20, 40 },
+ { 15, 33, 40 },
+ { 20, 46, 40 },
+ { 25, 60, 40 },
+ { 30, 73, 40 },
+ { 35, 83, 40 },
+ { 40, 93, 40 },
+ { 45, 96, 40 },
+ { 50, 101, 40 },
+ { 55, 99, 40 },
+ { 60, 97, 40 },
+ { 65, 90, 40 },
+ { 70, 83, 40 },
+ { 75, 71, 40 },
+ { 80, 60, 40 },
+ { 85, 44, 40 },
+ { 90, 30, 40 },
+ { 95, 15, 40 },
+ { 5, 8, 50 },
+ { 10, 20, 50 },
+ { 15, 30, 50 },
+ { 20, 42, 50 },
+ { 25, 54, 50 },
+ { 30, 66, 50 },
+ { 35, 77, 50 },
+ { 40, 88, 50 },
+ { 45, 95, 50 },
+ { 50, 99, 50 },
+ { 55, 101, 50 },
+ { 60, 100, 50 },
+ { 65, 97, 50 },
+ { 70, 92, 50 },
+ { 75, 83, 50 },
+ { 80, 72, 50 },
+ { 85, 55, 50 },
+ { 90, 37, 50 },
+ { 95, 19, 50 },
+ { 5, 7, 60 },
+ { 10, 17, 60 },
+ { 15, 26, 60 },
+ { 20, 36, 60 },
+ { 25, 46, 60 },
+ { 30, 55, 60 },
+ { 35, 64, 60 },
+ { 40, 75, 60 },
+ { 45, 80, 60 },
+ { 50, 90, 60 },
+ { 55, 95, 60 },
+ { 60, 100, 60 },
+ { 65, 101, 60 },
+ { 70, 102, 60 },
+ { 75, 98, 60 },
+ { 80, 90, 60 },
+ { 85, 72, 60 },
+ { 90, 50, 60 },
+ { 95, 25, 60 },
+ { 5, 6, 70 },
+ { 10, 15, 70 },
+ { 15, 25, 70 },
+ { 20, 32, 70 },
+ { 25, 42, 70 },
+ { 30, 50, 70 },
+ { 35, 58, 70 },
+ { 40, 68, 70 },
+ { 45, 75, 70 },
+ { 50, 82, 70 },
+ { 55, 90, 70 },
+ { 60, 95, 70 },
+ { 65, 100, 70 },
+ { 70, 104, 70 },
+ { 75, 107, 70 },
+ { 80, 109, 70 },
+ { 85, 100, 70 },
+ { 90, 74, 70 },
+ { 95, 34, 70 },
+ { 5, 5, 80 },
+ { 10, 13, 80 },
+ { 15, 23, 80 },
+ { 20, 30, 80 },
+ { 25, 37, 80 },
+ { 30, 47, 80 },
+ { 35, 55, 80 },
+ { 40, 62, 80 },
+ { 45, 70, 80 },
+ { 50, 77, 80 },
+ { 55, 85, 80 },
+ { 60, 90, 80 },
+ { 65, 95, 80 },
+ { 70, 103, 80 },
+ { 75, 106, 80 },
+ { 80, 110, 80 },
+ { 85, 113, 80 },
+ { 90, 110, 80 },
+ { 95, 70, 80 },
+ { 5, 5, 90 },
+ { 10, 13, 90 },
+ { 15, 21, 90 },
+ { 20, 30, 90 },
+ { 25, 36, 90 },
+ { 30, 45, 90 },
+ { 35, 55, 90 },
+ { 40, 60, 90 },
+ { 45, 64, 90 },
+ { 50, 73, 90 },
+ { 55, 80, 90 },
+ { 60, 88, 90 },
+ { 65, 95, 90 },
+ { 70, 100, 90 },
+ { 75, 106, 90 },
+ { 80, 111, 90 },
+ { 85, 117, 90 },
+ { 90, 120, 90 },
+ { 95, 123, 90 },
+ { 5, 5, 100 },
+ { 10, 14, 100 },
+ { 15, 21, 100 },
+ { 20, 30, 100 },
+ { 25, 35, 100 },
+ { 30, 45, 100 },
+ { 35, 53, 100 },
+ { 40, 60, 100 },
+ { 45, 65, 100 },
+ { 50, 73, 100 },
+ { 55, 80, 100 },
+ { 60, 87, 100 },
+ { 65, 94, 100 },
+ { 70, 100, 100 },
+ { 75, 106, 100 },
+ { 80, 109, 100 },
+ { 85, 113, 100 },
+ { 90, 108, 100 },
+ { 95, 90, 100 },
+ { 5, 6, 110 },
+ { 10, 14, 110 },
+ { 15, 22, 110 },
+ { 20, 30, 110 },
+ { 25, 37, 110 },
+ { 30, 46, 110 },
+ { 35, 52, 110 },
+ { 40, 61, 110 },
+ { 45, 67, 110 },
+ { 50, 75, 110 },
+ { 55, 82, 110 },
+ { 60, 89, 110 },
+ { 65, 96, 110 },
+ { 70, 100, 110 },
+ { 75, 103, 110 },
+ { 80, 106, 110 },
+ { 85, 107, 110 },
+ { 90, 102, 110 },
+ { 95, 75, 110 },
+ { 5, 6, 120 },
+ { 10, 15, 120 },
+ { 15, 22, 120 },
+ { 20, 31, 120 },
+ { 25, 40, 120 },
+ { 30, 49, 120 },
+ { 35, 57, 120 },
+ { 40, 65, 120 },
+ { 45, 73, 120 },
+ { 50, 80, 120 },
+ { 55, 87, 120 },
+ { 60, 93, 120 },
+ { 65, 98, 120 },
+ { 70, 100, 120 },
+ { 75, 101, 120 },
+ { 80, 96, 120 },
+ { 85, 88, 120 },
+ { 90, 73, 120 },
+ { 95, 50, 120 },
+ { 5, 6, 130 },
+ { 10, 15, 130 },
+ { 15, 24, 130 },
+ { 20, 34, 130 },
+ { 25, 44, 130 },
+ { 30, 53, 130 },
+ { 35, 63, 130 },
+ { 40, 72, 130 },
+ { 45, 80, 130 },
+ { 50, 87, 130 },
+ { 55, 93, 130 },
+ { 60, 97, 130 },
+ { 65, 101, 130 },
+ { 70, 99, 130 },
+ { 75, 94, 130 },
+ { 80, 84, 130 },
+ { 85, 72, 130 },
+ { 90, 55, 130 },
+ { 95, 30, 130 },
+ { 5, 7, 140 },
+ { 10, 18, 140 },
+ { 15, 27, 140 },
+ { 20, 37, 140 },
+ { 25, 47, 140 },
+ { 30, 57, 140 },
+ { 35, 67, 140 },
+ { 40, 77, 140 },
+ { 45, 85, 140 },
+ { 50, 95, 140 },
+ { 55, 98, 140 },
+ { 60, 101, 140 },
+ { 65, 97, 140 },
+ { 70, 93, 140 },
+ { 75, 85, 140 },
+ { 80, 75, 140 },
+ { 85, 61, 140 },
+ { 90, 42, 140 },
+ { 95, 21, 140 },
+ { 5, 7, 150 },
+ { 10, 18, 150 },
+ { 15, 29, 150 },
+ { 20, 40, 150 },
+ { 25, 51, 150 },
+ { 30, 61, 150 },
+ { 35, 71, 150 },
+ { 40, 81, 150 },
+ { 45, 92, 150 },
+ { 50, 97, 150 },
+ { 55, 99, 150 },
+ { 60, 96, 150 },
+ { 65, 91, 150 },
+ { 70, 85, 150 },
+ { 75, 76, 150 },
+ { 80, 66, 150 },
+ { 85, 52, 150 },
+ { 90, 37, 150 },
+ { 95, 19, 150 },
+ { 5, 7, 160 },
+ { 10, 20, 160 },
+ { 15, 30, 160 },
+ { 20, 42, 160 },
+ { 25, 53, 160 },
+ { 30, 66, 160 },
+ { 35, 79, 160 },
+ { 40, 92, 160 },
+ { 45, 96, 160 },
+ { 50, 99, 160 },
+ { 55, 97, 160 },
+ { 60, 90, 160 },
+ { 65, 87, 160 },
+ { 70, 79, 160 },
+ { 75, 69, 160 },
+ { 80, 59, 160 },
+ { 85, 46, 160 },
+ { 90, 32, 160 },
+ { 95, 19, 160 },
+ { 5, 8, 170 },
+ { 10, 20, 170 },
+ { 15, 30, 170 },
+ { 20, 41, 170 },
+ { 25, 52, 170 },
+ { 30, 63, 170 },
+ { 35, 73, 170 },
+ { 40, 83, 170 },
+ { 45, 91, 170 },
+ { 50, 96, 170 },
+ { 55, 93, 170 },
+ { 60, 89, 170 },
+ { 65, 82, 170 },
+ { 70, 75, 170 },
+ { 75, 65, 170 },
+ { 80, 55, 170 },
+ { 85, 42, 170 },
+ { 90, 29, 170 },
+ { 95, 15, 170 },
+ { 5, 8, 180 },
+ { 10, 20, 180 },
+ { 15, 29, 180 },
+ { 20, 40, 180 },
+ { 25, 51, 180 },
+ { 30, 62, 180 },
+ { 35, 72, 180 },
+ { 40, 81, 180 },
+ { 45, 86, 180 },
+ { 50, 92, 180 },
+ { 55, 90, 180 },
+ { 60, 86, 180 },
+ { 65, 79, 180 },
+ { 70, 71, 180 },
+ { 75, 61, 180 },
+ { 80, 51, 180 },
+ { 85, 38, 180 },
+ { 90, 25, 180 },
+ { 95, 13, 180 },
+ { 5, 8, 190 },
+ { 10, 20, 190 },
+ { 15, 29, 190 },
+ { 20, 40, 190 },
+ { 25, 49, 190 },
+ { 30, 60, 190 },
+ { 35, 68, 190 },
+ { 40, 76, 190 },
+ { 45, 81, 190 },
+ { 50, 87, 190 },
+ { 55, 85, 190 },
+ { 60, 82, 190 },
+ { 65, 75, 190 },
+ { 70, 69, 190 },
+ { 75, 60, 190 },
+ { 80, 50, 190 },
+ { 85, 38, 190 },
+ { 90, 26, 190 },
+ { 95, 13, 190 },
+ { 5, 8, 200 },
+ { 10, 20, 200 },
+ { 15, 28, 200 },
+ { 20, 38, 200 },
+ { 25, 47, 200 },
+ { 30, 56, 200 },
+ { 35, 63, 200 },
+ { 40, 70, 200 },
+ { 45, 75, 200 },
+ { 50, 80, 200 },
+ { 55, 78, 200 },
+ { 60, 78, 200 },
+ { 65, 72, 200 },
+ { 70, 66, 200 },
+ { 75, 58, 200 },
+ { 80, 49, 200 },
+ { 85, 38, 200 },
+ { 90, 27, 200 },
+ { 95, 14, 200 },
+ { 5, 8, 210 },
+ { 10, 20, 210 },
+ { 15, 28, 210 },
+ { 20, 37, 210 },
+ { 25, 45, 210 },
+ { 30, 53, 210 },
+ { 35, 60, 210 },
+ { 40, 66, 210 },
+ { 45, 72, 210 },
+ { 50, 79, 210 },
+ { 55, 80, 210 },
+ { 60, 76, 210 },
+ { 65, 69, 210 },
+ { 70, 64, 210 },
+ { 75, 57, 210 },
+ { 80, 49, 210 },
+ { 85, 38, 210 },
+ { 90, 27, 210 },
+ { 95, 14, 210 },
+ { 5, 8, 220 },
+ { 10, 20, 220 },
+ { 15, 27, 220 },
+ { 20, 37, 220 },
+ { 25, 44, 220 },
+ { 30, 51, 220 },
+ { 35, 57, 220 },
+ { 40, 64, 220 },
+ { 45, 70, 220 },
+ { 50, 76, 220 },
+ { 55, 73, 220 },
+ { 60, 71, 220 },
+ { 65, 68, 220 },
+ { 70, 63, 220 },
+ { 75, 56, 220 },
+ { 80, 48, 220 },
+ { 85, 38, 220 },
+ { 90, 27, 220 },
+ { 95, 14, 220 },
+ { 5, 8, 230 },
+ { 10, 20, 230 },
+ { 15, 28, 230 },
+ { 20, 38, 230 },
+ { 25, 45, 230 },
+ { 30, 52, 230 },
+ { 35, 57, 230 },
+ { 40, 65, 230 },
+ { 45, 69, 230 },
+ { 50, 75, 230 },
+ { 55, 72, 230 },
+ { 60, 71, 230 },
+ { 65, 66, 230 },
+ { 70, 61, 230 },
+ { 75, 54, 230 },
+ { 80, 46, 230 },
+ { 85, 36, 230 },
+ { 90, 26, 230 },
+ { 95, 13, 230 },
+ { 5, 9, 240 },
+ { 10, 20, 240 },
+ { 15, 29, 240 },
+ { 20, 40, 240 },
+ { 25, 48, 240 },
+ { 30, 55, 240 },
+ { 35, 61, 240 },
+ { 40, 66, 240 },
+ { 45, 71, 240 },
+ { 50, 74, 240 },
+ { 55, 70, 240 },
+ { 60, 66, 240 },
+ { 65, 61, 240 },
+ { 70, 56, 240 },
+ { 75, 49, 240 },
+ { 80, 41, 240 },
+ { 85, 32, 240 },
+ { 90, 23, 240 },
+ { 95, 12, 240 },
+ { 5, 11, 250 },
+ { 10, 22, 250 },
+ { 15, 32, 250 },
+ { 20, 42, 250 },
+ { 25, 50, 250 },
+ { 30, 59, 250 },
+ { 35, 65, 250 },
+ { 40, 70, 250 },
+ { 45, 73, 250 },
+ { 50, 70, 250 },
+ { 55, 68, 250 },
+ { 60, 62, 250 },
+ { 65, 58, 250 },
+ { 70, 52, 250 },
+ { 75, 45, 250 },
+ { 80, 38, 250 },
+ { 85, 29, 250 },
+ { 90, 21, 250 },
+ { 95, 11, 250 },
+ { 5, 14, 260 },
+ { 10, 27, 260 },
+ { 15, 38, 260 },
+ { 20, 48, 260 },
+ { 25, 56, 260 },
+ { 30, 63, 260 },
+ { 35, 67, 260 },
+ { 40, 72, 260 },
+ { 45, 73, 260 },
+ { 50, 69, 260 },
+ { 55, 65, 260 },
+ { 60, 60, 260 },
+ { 65, 56, 260 },
+ { 70, 50, 260 },
+ { 75, 43, 260 },
+ { 80, 35, 260 },
+ { 85, 27, 260 },
+ { 90, 20, 260 },
+ { 95, 10, 260 },
+ { 5, 16, 270 },
+ { 10, 32, 270 },
+ { 15, 44, 270 },
+ { 20, 55, 270 },
+ { 25, 62, 270 },
+ { 30, 70, 270 },
+ { 35, 75, 270 },
+ { 40, 74, 270 },
+ { 45, 72, 270 },
+ { 50, 68, 270 },
+ { 55, 66, 270 },
+ { 60, 59, 270 },
+ { 65, 54, 270 },
+ { 70, 48, 270 },
+ { 75, 41, 270 },
+ { 80, 33, 270 },
+ { 85, 26, 270 },
+ { 90, 18, 270 },
+ { 95, 9, 270 },
+ { 5, 21, 280 },
+ { 10, 42, 280 },
+ { 15, 55, 280 },
+ { 20, 68, 280 },
+ { 25, 73, 280 },
+ { 30, 81, 280 },
+ { 35, 80, 280 },
+ { 40, 78, 280 },
+ { 45, 76, 280 },
+ { 50, 70, 280 },
+ { 55, 67, 280 },
+ { 60, 60, 280 },
+ { 65, 55, 280 },
+ { 70, 49, 280 },
+ { 75, 41, 280 },
+ { 80, 33, 280 },
+ { 85, 26, 280 },
+ { 90, 18, 280 },
+ { 95, 9, 280 },
+ { 5, 26, 290 },
+ { 10, 52, 290 },
+ { 15, 66, 290 },
+ { 20, 83, 290 },
+ { 25, 84, 290 },
+ { 30, 89, 290 },
+ { 35, 87, 290 },
+ { 40, 84, 290 },
+ { 45, 80, 290 },
+ { 50, 75, 290 },
+ { 55, 69, 290 },
+ { 60, 63, 290 },
+ { 65, 57, 290 },
+ { 70, 50, 290 },
+ { 75, 42, 290 },
+ { 80, 34, 290 },
+ { 85, 26, 290 },
+ { 90, 18, 290 },
+ { 95, 9, 290 },
+ { 5, 25, 300 },
+ { 10, 65, 300 },
+ { 15, 79, 300 },
+ { 20, 95, 300 },
+ { 25, 93, 300 },
+ { 30, 92, 300 },
+ { 35, 90, 300 },
+ { 40, 87, 300 },
+ { 45, 85, 300 },
+ { 50, 77, 300 },
+ { 55, 73, 300 },
+ { 60, 66, 300 },
+ { 65, 59, 300 },
+ { 70, 52, 300 },
+ { 75, 44, 300 },
+ { 80, 36, 300 },
+ { 85, 28, 300 },
+ { 90, 19, 300 },
+ { 95, 10, 300 },
+ { 5, 20, 310 },
+ { 10, 50, 310 },
+ { 15, 67, 310 },
+ { 20, 91, 310 },
+ { 25, 97, 310 },
+ { 30, 100, 310 },
+ { 35, 98, 310 },
+ { 40, 95, 310 },
+ { 45, 90, 310 },
+ { 50, 84, 310 },
+ { 55, 77, 310 },
+ { 60, 70, 310 },
+ { 65, 63, 310 },
+ { 70, 55, 310 },
+ { 75, 47, 310 },
+ { 80, 39, 310 },
+ { 85, 30, 310 },
+ { 90, 20, 310 },
+ { 95, 10, 310 },
+ { 5, 18, 320 },
+ { 10, 41, 320 },
+ { 15, 60, 320 },
+ { 20, 79, 320 },
+ { 25, 90, 320 },
+ { 30, 102, 320 },
+ { 35, 101, 320 },
+ { 40, 98, 320 },
+ { 45, 94, 320 },
+ { 50, 89, 320 },
+ { 55, 83, 320 },
+ { 60, 76, 320 },
+ { 65, 68, 320 },
+ { 70, 60, 320 },
+ { 75, 51, 320 },
+ { 80, 42, 320 },
+ { 85, 32, 320 },
+ { 90, 21, 320 },
+ { 95, 11, 320 },
+ { 5, 16, 330 },
+ { 10, 35, 330 },
+ { 15, 53, 330 },
+ { 20, 71, 330 },
+ { 25, 82, 330 },
+ { 30, 91, 330 },
+ { 35, 99, 330 },
+ { 40, 104, 330 },
+ { 45, 102, 330 },
+ { 50, 98, 330 },
+ { 55, 90, 330 },
+ { 60, 84, 330 },
+ { 65, 76, 330 },
+ { 70, 67, 330 },
+ { 75, 57, 330 },
+ { 80, 47, 330 },
+ { 85, 36, 330 },
+ { 90, 24, 330 },
+ { 95, 12, 330 },
+ { 5, 14, 340 },
+ { 10, 31, 340 },
+ { 15, 45, 340 },
+ { 20, 61, 340 },
+ { 25, 71, 340 },
+ { 30, 82, 340 },
+ { 35, 91, 340 },
+ { 40, 101, 340 },
+ { 45, 103, 340 },
+ { 50, 99, 340 },
+ { 55, 95, 340 },
+ { 60, 89, 340 },
+ { 65, 80, 340 },
+ { 70, 71, 340 },
+ { 75, 61, 340 },
+ { 80, 50, 340 },
+ { 85, 38, 340 },
+ { 90, 26, 340 },
+ { 95, 13, 340 },
+ { 5, 12, 350 },
+ { 10, 28, 350 },
+ { 15, 41, 350 },
+ { 20, 54, 350 },
+ { 25, 65, 350 },
+ { 30, 76, 350 },
+ { 35, 83, 350 },
+ { 40, 93, 350 },
+ { 45, 95, 350 },
+ { 50, 92, 350 },
+ { 55, 90, 350 },
+ { 60, 85, 350 },
+ { 65, 77, 350 },
+ { 70, 68, 350 },
+ { 75, 58, 350 },
+ { 80, 48, 350 },
+ { 85, 36, 350 },
+ { 90, 24, 350 },
+ { 95, 12, 350 }
+};
+
+/* selected "cusp" points */
+double cpoints[6][3] = {
+ { 50, 101, 36 },
+ { 95, 123, 90 },
+ { 60, 101, 140 },
+ { 55, 80, 210 },
+ { 20, 95, 300 },
+ { 40, 104, 330 },
+};
+
+/* Our idealised cusp point angles for Lab in degrees: */
+/* 36.0, Red */
+/* 101.0, Yellow */
+/* 149.0, Green */
+/* 225.0, Cyan */
+/* 300.0, Blue */
+/* 337.0 Magenta */
+
+#define GAMRES 1.0 /* Default surface resolution */
+
+int
+main(int argc, char *argv[]) {
+ int i;
+ char out_name[MAXNAMEL+1]; /* VRML output file */
+
+ double gamres = GAMRES; /* Surface resolution */
+ gamut *gam;
+
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+#endif
+
+ if (argc < 2) {
+ strcpy(out_name, "RefMediumGamut.gam");
+ } else {
+ strncpy(out_name,argv[1],MAXNAMEL); out_name[MAXNAMEL] = '\000';
+ }
+
+ /* Creat a gamut surface */
+ gam = new_gamut(gamres, 0, 0);
+
+ /* For all the supplied surface points, */
+ /* add them to the gamut */
+ for (i = 0; i < NPOINTS; i++) {
+ double lab[3];
+
+ icmLCh2Lab(lab, points[i]);
+//printf("~1 LCh %f %f %f -> Lab %f %f %f\n", points[i][0], points[i][1], points[i][2], lab[0], lab[1], lab[2]);
+ gam->expand(gam, lab);
+ }
+
+ /* Add selected cusp points to set cusp values */
+ gam->setcusps(gam, 0, NULL);
+ for (i = 0; i < 6; i++) {
+ double lab[3];
+
+ icmLCh2Lab(lab, cpoints[i]);
+//printf("~1 LCh %f %f %f -> Lab %f %f %f\n", points[i][0], points[i][1], points[i][2], lab[0], lab[1], lab[2]);
+ gam->setcusps(gam, 1, lab);
+ }
+ gam->setcusps(gam, 2, NULL);
+
+ if (gam->write_gam(gam, out_name))
+ error ("write gamut failed on '%s'",out_name);
+
+ gam->del(gam);
+
+ return 0;
+}
+
diff --git a/gamut/GenVisGam.c b/gamut/GenVisGam.c
new file mode 100644
index 0000000..12d8d9d
--- /dev/null
+++ b/gamut/GenVisGam.c
@@ -0,0 +1,189 @@
+
+/* Generate the visual gamut in L*a*b* space */
+/* Copyright 2006 by Graeme W. Gill */
+/* All rights reserved. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "numlib.h"
+#include "icc.h"
+#include "gamut.h"
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+
+/* 2 degree spectrum locus in xy coordinates */
+/* nm, x, y, Y CMC */
+double sl[65][4] = {
+ { 380, 0.1741, 0.0050, 0.000039097450 },
+ { 385, 0.1740, 0.0050, 0.000065464490 },
+ { 390, 0.1738, 0.0049, 0.000121224052 },
+ { 395, 0.1736, 0.0049, 0.000221434140 },
+ { 400, 0.1733, 0.0048, 0.000395705080 },
+ { 405, 0.1730, 0.0048, 0.000656030940 },
+ { 410, 0.1726, 0.0048, 0.001222776600 },
+ { 415, 0.1721, 0.0048, 0.002210898200 },
+ { 420, 0.1714, 0.0051, 0.004069952000 },
+ { 425, 0.1703, 0.0058, 0.007334133400 },
+ { 430, 0.1689, 0.0069, 0.011637600000 },
+ { 435, 0.1669, 0.0086, 0.016881322000 },
+ { 440, 0.1644, 0.0109, 0.023015402000 },
+ { 445, 0.1611, 0.0138, 0.029860866000 },
+ { 450, 0.1566, 0.0177, 0.038072300000 },
+ { 455, 0.1510, 0.0227, 0.048085078000 },
+ { 460, 0.1440, 0.0297, 0.060063754000 },
+ { 465, 0.1355, 0.0399, 0.074027114000 },
+ { 470, 0.1241, 0.0578, 0.091168598000 },
+ { 475, 0.1096, 0.0868, 0.112811680000 },
+ { 480, 0.0913, 0.1327, 0.139122260000 },
+ { 485, 0.0686, 0.2007, 0.169656160000 },
+ { 490, 0.0454, 0.2950, 0.208513180000 },
+ { 495, 0.0235, 0.4127, 0.259083420000 },
+ { 500, 0.0082, 0.5384, 0.323943280000 },
+ { 505, 0.0039, 0.6548, 0.407645120000 },
+ { 510, 0.0139, 0.7502, 0.503483040000 },
+ { 515, 0.0389, 0.8120, 0.608101540000 },
+ { 520, 0.0743, 0.8338, 0.709073280000 },
+ { 525, 0.1142, 0.8262, 0.792722560000 },
+ { 530, 0.1547, 0.8059, 0.861314320000 },
+ { 535, 0.1929, 0.7816, 0.914322820000 },
+ { 540, 0.2296, 0.7543, 0.953482260000 },
+ { 545, 0.2658, 0.7243, 0.979818740000 },
+ { 550, 0.3016, 0.6923, 0.994576720000 },
+ { 555, 0.3373, 0.6589, 0.999604300000 },
+ { 560, 0.3731, 0.6245, 0.994513460000 },
+ { 565, 0.4087, 0.5896, 0.978204680000 },
+ { 570, 0.4441, 0.5547, 0.951588260000 },
+ { 575, 0.4788, 0.5202, 0.915060800000 },
+ { 580, 0.5125, 0.4866, 0.869647940000 },
+ { 585, 0.5448, 0.4544, 0.816076000000 },
+ { 590, 0.5752, 0.4242, 0.756904640000 },
+ { 595, 0.6029, 0.3965, 0.694818180000 },
+ { 600, 0.6270, 0.3725, 0.630997820000 },
+ { 605, 0.6482, 0.3514, 0.566802360000 },
+ { 610, 0.6658, 0.3340, 0.503096860000 },
+ { 615, 0.6801, 0.3197, 0.441279360000 },
+ { 620, 0.6915, 0.3083, 0.380961920000 },
+ { 625, 0.7006, 0.2993, 0.321156580000 },
+ { 630, 0.7079, 0.2920, 0.265374180000 },
+ { 635, 0.7140, 0.2859, 0.217219520000 },
+ { 640, 0.7190, 0.2809, 0.175199900000 },
+ { 645, 0.7230, 0.2770, 0.138425720000 },
+ { 650, 0.7260, 0.2740, 0.107242628000 },
+ { 655, 0.7283, 0.2717, 0.081786794000 },
+ { 660, 0.7300, 0.2700, 0.061166218000 },
+ { 665, 0.7311, 0.2689, 0.044729418000 },
+ { 670, 0.7320, 0.2680, 0.032160714000 },
+ { 675, 0.7327, 0.2673, 0.023307860000 },
+ { 680, 0.7334, 0.2666, 0.017028548000 },
+ { 685, 0.7340, 0.2660, 0.011981432000 },
+ { 690, 0.7344, 0.2656, 0.008259734600 },
+ { 695, 0.7346, 0.2654, 0.005758363200 },
+ { 700, 0.7347, 0.2653, 0.004117206200 }
+};
+
+#define GAMRES 5.0 /* Default surface resolution */
+
+int
+main(int argc, char *argv[]) {
+ int i, j, e;
+ double Yxy[3], XYZ[3], Lab[3];
+ char out_name[100]; /* VRML output file */
+ double big[3] = { 0.0, 0.0, 0.0 }, bc;
+ double low[3] = { 1e6, 1e6, 1e6 };
+ double high[3] = { -1e6, -1e6, -1e6 };
+// double limit = 5.0; /* Limit multiplier of light at maximum sensitivity */
+
+ double gamres = GAMRES; /* Surface resolution */
+ gamut *gam;
+
+ strcpy(out_name, "VisGamut.gam");
+
+ /* Creat a gamut surface */
+ gam = new_gamut(gamres, 0, 0);
+
+ bc = 0.0;
+
+ /* The monochromic boundary with a unit energy monochromic source */
+ for (j = 0; j < 50; j++) {
+ double Y = j/(50 - 1.0);
+
+ Y = Y * Y;
+
+ for (i = 0; i < 65; i++) {
+// Yxy[0] = Y * limit * sl[i][3];
+// if (Yxy[0] > Y)
+ Yxy[0] = Y;
+ Yxy[1] = sl[i][1];
+ Yxy[2] = sl[i][2];
+
+ icmYxy2XYZ(XYZ, Yxy);
+ icmXYZ2Lab(&icmD50, Lab, XYZ);
+
+ gam->expand(gam, Lab);
+
+ for (e = 0; e < 3; e++) {
+ if (Lab[e] < low[e])
+ low[e] = Lab[e];
+ if (Lab[e] > high[e])
+ high[e] = Lab[e];
+ }
+ if ((Lab[1] * Lab[1] + Lab[2] * Lab[2]) > bc) {
+ bc = Lab[1] * Lab[1] + Lab[2] * Lab[2];
+ big[0] = Lab[0], big[1] = Lab[1], big[2] = Lab[2];
+ }
+ }
+
+ /* Do the purple line */
+ for (i = 0; i < 20; i++) {
+ double b = i/(20 - 1.0);
+
+// Yxy[0] = (b * sl[0][3] + (1.0 - b) * sl[64][3]) * limit * Y;
+// if (Yxy[0] > Y)
+ Yxy[0] = Y;
+ Yxy[1] = b * sl[0][1] + (1.0 - b) * sl[64][1];
+ Yxy[2] = b * sl[0][2] + (1.0 - b) * sl[64][2];
+ icmYxy2XYZ(XYZ, Yxy);
+ icmXYZ2Lab(&icmD50, Lab, XYZ);
+
+ gam->expand(gam, Lab);
+
+ for (e = 0; e < 3; e++) {
+ if (Lab[e] < low[e])
+ low[e] = Lab[e];
+ if (Lab[e] > high[e])
+ high[e] = Lab[e];
+ }
+ if ((Lab[1] * Lab[1] + Lab[2] * Lab[2]) > bc) {
+ bc = Lab[1] * Lab[1] + Lab[2] * Lab[2];
+ big[0] = Lab[0], big[1] = Lab[1], big[2] = Lab[2];
+ }
+ }
+ }
+
+ /* How to fill in less saturated, lighter area of gamut within */
+ /* our maximum monochrome level limit ? */
+ /* ~~~999 */
+
+ /* Fill in white point */
+ Lab[0] = 100.0;
+ Lab[1] = 0.0;
+ Lab[2] = 0.0;
+ gam->expand(gam, Lab);
+
+ printf("Bigest = %f %f %f\n",big[0],big[1],big[2]);
+ printf("Low = %f %f %f\n",low[0],low[1],low[2]);
+ printf("High = %f %f %f\n",high[0],high[1],high[2]);
+
+ if (gam->write_gam(gam, out_name))
+ error ("write gamut failed on '%s'",out_name);
+
+ gam->del(gam);
+
+ return 0;
+}
+
diff --git a/gamut/Jamfile b/gamut/Jamfile
new file mode 100644
index 0000000..a7273f3
--- /dev/null
+++ b/gamut/Jamfile
@@ -0,0 +1,93 @@
+
+
+# Optimization and Debug flags
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Link with debug info
+#PREF_CCFLAGS += $(CCPROFFLAG) ; # Profile flags
+#PREF_LINKFLAGS += $(LINKPROFFLAG) ; # Profile flags
+
+#Products
+Libraries = libgamut libgammap ;
+Executables = viewgam ;
+Samples = RefMediumGamut.gam ;
+Headers = gammap.h gamut.h ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+InstallFile $(DESTDIR)$(PREFIX)/$(REFSUBDIR) : $(Samples) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)lib : $(Libraries) ;
+
+# Header search path
+HDRS = ../h ../icc ../rspl ../numlib ../plot ../xicc ../cgats ../spectro ../gamut ;
+
+# Gamut handling library
+Library libgamut : gamut.c ;
+
+# Gamut mapping library
+Library libgammap : gammap.c nearsmth.c ;
+
+LINKLIBS = libgammap libgamut ../rspl/librspl ../icc/libicc ../cgats/libcgats ../numlib/libnum
+ ../plot/libvrml ;
+
+# Utilities
+Main viewgam : viewgam.c ;
+
+# Link all the tests and utils with these libraries
+
+# Smoothed nearpoint test routine
+Main smthtest : smthtest.c ;
+
+# Preliminary ICC V4 Reference Medium Gamut
+Main GenRMGam : GenRMGam.c ;
+
+# Generate referenec medium gamut the kernel files
+# (NoUpdate so that Cross Compile Win64 hack works)
+NNoUpdate RefMediumGamut.gam ;
+GenFile RefMediumGamut.gam : GenRMGam ;
+
+# Visual gamut
+Main GenVisGam : GenVisGam.c ;
+
+# Develop hue sensitive parameter interpolation */
+#Main tttt : tttt.c ;
+
+LINKLIBS = libgammap libgamut ../icc/libicc ../cgats/libcgats ../xicc/libxicc
+ ../rspl/librspl ../numlib/libnum ../plot/libplot ../plot/libvrml ;
+
+# Mapping test routine
+Main maptest : maptest.c ;
+
+# Fake test gamut generatio
+Main fakegam : fakegam.c ;
+
+# Surfacing test routine
+Main surftest : surftest.c ;
+
+# Filtering test cpde
+#Main filt : filt.c ;
+
+#Main tt : tt.c ;
+
+if $(BUILD_JUNK) {
+
+ # Gamut creation test routine
+ Main gamtest : gamtest.c ;
+
+ # Group finding test.
+ Main gtest : gtest.c ;
+
+ # Test routine
+ Main test : test.c ;
+
+ Main tt : tt.c ;
+
+ # Atan aproximation test
+ Main xtan : xtan.c ;
+
+ # Bit vector class test
+ Main bvtest : bvtest.c ;
+}
diff --git a/gamut/License.txt b/gamut/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/gamut/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/gamut/Makefile.am b/gamut/Makefile.am
new file mode 100644
index 0000000..266ae82
--- /dev/null
+++ b/gamut/Makefile.am
@@ -0,0 +1,27 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libgamut.la libgammap.la
+privatelibdir = $(pkglibdir)
+
+libgamut_la_SOURCES = gamut.h gamut.c
+libgamut_la_LIBADD = ../cgats/libcgats.la $(ICC_LIBS) \
+ ../numlib/libargyllnum.la
+
+libgammap_la_SOURCES = gammap.h gammap.c nearsmth.c nearsmth.h
+libgammap_la_LIBADD = ./libgamut.la $(ICC_LIBS) \
+ ../numlib/libargyllnum.la ../plot/libvrml.la \
+ ../rspl/librspl.la ../libargyll.la ../cgats/libcgats.la
+
+LDADD = ./libgamut.la ./libgammap.la $(ICC_LIBS) ../cgats/libcgats.la \
+ ../rspl/librspl.la ../plot/libvrml.la ../xicc/libxicc.la \
+ ../spectro/libinsttypes.la ../numlib/libargyllnum.la
+
+bin_PROGRAMS = viewgam
+
+check_PROGRAMS = smthtest GenRMGam GenVisGam maptest surftest fakegam
+
+refdir = $(datadir)/color/argyll/ref
+
+##ref_DATA = RefMediumGamut.gam
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/gamut/Readme.txt b/gamut/Readme.txt
new file mode 100644
index 0000000..56e7e13
--- /dev/null
+++ b/gamut/Readme.txt
@@ -0,0 +1,25 @@
+This directory contains the gamut boundary
+finding, and gamut mapping code.
+It also contains utilities for generating
+3D visualisations of gamut boundaries.
+
+ iccgamut:
+ Take an icc profile, and derive a gamut surface from one
+ of the forward or reverse transforms, using the desired
+ intent. Output the result as a CGATS format .gam file,
+ and optionaly as a VRML model file.
+
+ tiffgamut:
+ Take an tiff file and an icc profile, and derive a gamut
+ surface from the forward absolute profile and the tiff
+ image. Output the result as a CGATS format .gam file,
+ and optionaly as a VRML model file.
+
+ viewgam:
+
+ This program reads one or more CGATS format triangular gamut
+ surface descriptions (.gam), and combines them into a VRML file,
+ so that the gamuts can be visually compared.
+ Allowance is made for representing the gamuts as solid or
+ tranparent surfaces, wire frames, and coloring the gamut
+ with natural or uniform colors.
diff --git a/gamut/afiles b/gamut/afiles
new file mode 100644
index 0000000..951926b
--- /dev/null
+++ b/gamut/afiles
@@ -0,0 +1,19 @@
+Readme.txt
+gammap.txt
+License.txt
+afiles
+Jamfile
+gamut.c
+gamut.h
+isecvol.c
+viewgam.c
+gammap.c
+gammap.h
+nearsmth.c
+nearsmth.h
+maptest.c
+smthtest.c
+surftest.c
+fakegam.c
+GenRMGam.c
+GenVisGam.c
diff --git a/gamut/fakegam.c b/gamut/fakegam.c
new file mode 100644
index 0000000..ec40457
--- /dev/null
+++ b/gamut/fakegam.c
@@ -0,0 +1,325 @@
+
+/*
+ * Gamut test code. Generate a fake gamut surface
+ *
+ * Author: Graeme W. Gill
+ * Date: 23/10/2008
+ * Version: 1.00
+ *
+ * Copyright 2008, 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.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "gamut.h"
+
+int get_value(double val[3]);
+
+#define DEF_POINTS 10
+
+void usage(char *diag) {
+ fprintf(stderr,"Generate a test gamut Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: gamtest [options] outputname\n");
+ if (diag != NULL)
+ fprintf(stderr,"Diagnostic: %s\n",diag);
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -n num Number of points to use (default %d)\n",DEF_POINTS);
+ fprintf(stderr," -c rad Create a cube\n");
+ fprintf(stderr," -p rad Create a sphere\n");
+ fprintf(stderr," -s w,d,h Create a sphereoid\n");
+ fprintf(stderr," -b w,d,h Create a box\n");
+ fprintf(stderr," -S nw,pw,nd,pd,nh,ph Create an asymetric sphereoid\n");
+ fprintf(stderr," -B nw,pw,nd,pd,nh,ph Create an asymetric box\n");
+ fprintf(stderr," -o x,y,z Offset the shape\n");
+ fprintf(stderr," -w Create WRL\n");
+ fprintf(stderr," -x No WRL axes\n");
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char *xl, out_name[500];
+ int npoints = DEF_POINTS;
+ gamut *gam;
+ int shape = 1; /* 0 = sphereoid, 1 = box */
+ double bsize[6] = { 20.0, 20.0, 20.0, 20.0, 20.0, 20.0 }; /* box/spheroid size */
+ double goff[3] = { 0.0, 0.0, 0.0 }; /* Gamut position offset */
+ double co[3];
+ double wp[3] = { -1e6, 0.0, 0.0 }, bp[3] = { 1e6, 0.0, 0.0 };
+ int verb = 0;
+ int dowrl = 0;
+ int doaxes = 1;
+ int i;
+
+#ifdef NUMSUP_H
+ error_program = "fakegam";
+#endif
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage(NULL);
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ /* VRML */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ dowrl = 1;
+ }
+ /* No axis output */
+ else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ doaxes = 0;
+ }
+ /* Sphere */
+ else if (argv[fa][1] == 'p') {
+ double radius;
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -h");
+ radius = atof(na);
+ bsize[0] = bsize[2] = bsize[4] = 2.0 * radius;
+ bsize[1] = bsize[3] = bsize[5] = 2.0 * radius;
+ shape = 0;
+ }
+ /* Cube */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ double radius;
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -h");
+ radius = atof(na);
+ bsize[0] = bsize[2] = bsize[4] = 2.0 * radius;
+ bsize[1] = bsize[3] = bsize[5] = 2.0 * radius;
+ shape = 1;
+ }
+ /* Sphereoid */
+ else if (argv[fa][1] == 's') {
+ if (na == NULL) usage("Expect parameter to -b");
+
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf ",&bsize[1], &bsize[3], &bsize[5]) == 3) {
+ bsize[0] = bsize[1];
+ bsize[2] = bsize[3];
+ bsize[4] = bsize[5];
+ } else
+ usage("Couldn't parse sphereoid size (-b) values");
+ shape = 0;
+ }
+ /* Box */
+ else if (argv[fa][1] == 'b') {
+ if (na == NULL) usage("Expect parameter to -b");
+
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf ",&bsize[1], &bsize[3], &bsize[5]) == 3) {
+ bsize[0] = bsize[1];
+ bsize[2] = bsize[3];
+ bsize[4] = bsize[5];
+ } else
+ usage("Couldn't parse box size (-b) values");
+ shape = 1;
+ }
+ /* Asymetric Sphereoid */
+ else if (argv[fa][1] == 'S') {
+ if (na == NULL) usage("Expect parameter to -S");
+
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf , %lf , %lf , %lf ",
+ &bsize[0], &bsize[1], &bsize[2], &bsize[3], &bsize[4], &bsize[5]) == 6) {
+ bsize[0] *= 2.0;
+ bsize[1] *= 2.0;
+ bsize[2] *= 2.0;
+ bsize[3] *= 2.0;
+ bsize[4] *= 2.0;
+ bsize[5] *= 2.0;
+ } else
+ usage("Couldn't parse sphereoid size (-S) values");
+ shape = 0;
+ }
+ /* Asymetric Box */
+ else if (argv[fa][1] == 'B') {
+ if (na == NULL) usage("Expect parameter to -B");
+
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf , %lf , %lf , %lf ",
+ &bsize[0], &bsize[1], &bsize[2], &bsize[3], &bsize[4], &bsize[5]) == 6) {
+ bsize[0] *= 2.0;
+ bsize[1] *= 2.0;
+ bsize[2] *= 2.0;
+ bsize[3] *= 2.0;
+ bsize[4] *= 2.0;
+ bsize[5] *= 2.0;
+ } else
+ usage("Couldn't parse box size (-B) values");
+ shape = 1;
+ }
+ /* Number of construction points */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -t");
+ npoints = atoi(na);
+ }
+ /* Gamut offset */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ if (na == NULL) usage("Expect parameter to -o");
+
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf ",&goff[0], &goff[1], &goff[2]) == 3) {
+ } else
+ usage("Couldn't parse gamut offset (-o) value");
+ }
+ else
+ usage("Unknown flag");
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Output filename expected");
+ strcpy(out_name,argv[fa++]);
+
+ if ((xl = strrchr(out_name, '.')) == NULL) { /* Add .gam extention if there isn't one */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".gam");
+ }
+
+ if (verb) {
+ printf("Number of construction points = %d\n",npoints * npoints * npoints);
+ }
+
+ /* Creat a gamut object */
+ if ((gam = new_gamut(5.0, 0, 0)) == NULL)
+ error("Failed to create aa gamut object\n");
+
+ /* Create and add our gridded test points */
+ for (co[0] = 0; co[0] < npoints; co[0]++) {
+ for (co[1] = 0; co[1] < npoints; co[1]++) {
+ for (co[2] = 0; co[2] < npoints; co[2]++) {
+ double pp[3], sum, rad;
+ int m, n;
+
+ /* Make sure at least one coords are 0 & 1 */
+ for (n = m = 0; m < 3; m++) {
+ if (co[m] == 0 || co[m] == (npoints-1))
+ n++;
+ }
+ if (n < 1)
+ continue;
+
+ if (shape == 0) { /* Sphereoid */
+
+ pp[0] = (co[0]/(npoints-1.0) - 0.5);
+ pp[1] = (co[1]/(npoints-1.0) - 0.5);
+ pp[2] = (co[2]/(npoints-1.0) - 0.5);
+
+ /* vector length */
+ for (sum = 0.0, m = 0; m < 3; m++) {
+ sum += pp[m] * pp[m];
+ }
+ if (sum < 1e-6)
+ continue;
+ sum = sqrt(sum);
+
+ /* Make sum of squares == 0.5 */
+ for (m = 0; m < 3; m++) {
+ pp[m] /= sum;
+ pp[m] *= 0.5;
+ }
+ /* And then scale it */
+ if (pp[0] < 0.0)
+ pp[0] = bsize[4] * pp[0];
+ else
+ pp[0] = bsize[5] * pp[0];
+
+ if (pp[1] < 0.0)
+ pp[1] = bsize[0] * pp[1];
+ else
+ pp[1] = bsize[1] * pp[1];
+
+ if (pp[2] < 0.0)
+ pp[2] = bsize[2] * pp[2];
+ else
+ pp[2] = bsize[3] * pp[2];
+ } else { /* Box */
+ if (co[0] < 0.0)
+ pp[0] = bsize[4] * (co[0]/(npoints-1.0) - 0.5);
+ else
+ pp[0] = bsize[4] * (co[0]/(npoints-1.0) - 0.5);
+
+ if (co[1] < 0.0)
+ pp[1] = bsize[0] * (co[1]/(npoints-1.0) - 0.5);
+ else
+ pp[1] = bsize[1] * (co[1]/(npoints-1.0) - 0.5);
+
+ if (co[2] < 0.0)
+ pp[2] = bsize[1] * (co[2]/(npoints-1.0) - 0.5);
+ else
+ pp[2] = bsize[2] * (co[2]/(npoints-1.0) - 0.5);
+ }
+
+ pp[0] += 50.0 + goff[2];
+ pp[1] += goff[0];
+ pp[2] += goff[1];
+//printf("~1 point %f %f %f\n",pp[0],pp[1],pp[2]);
+ gam->expand(gam, pp);
+
+ if (pp[0] > wp[0])
+ wp[0] = pp[0];
+ if (pp[0] < bp[0])
+ bp[0] = pp[0];
+ }
+ }
+ }
+
+ gam->setwb(gam, wp, bp, NULL);
+
+ /* Write out the gamut */
+ if (gam->write_gam(gam, out_name))
+ error ("write gamut failed on '%s'",out_name);
+
+ if (dowrl) {
+ strcpy(xl,".wrl");
+ if (gam->write_vrml(gam, out_name, doaxes, 0))
+ error ("write vrml failed on '%s'",out_name);
+ }
+
+ if (verb)
+ printf("Written out the gamut surface\n");
+
+ gam->del(gam);
+
+ return 0;
+}
+
diff --git a/gamut/gammap.c b/gamut/gammap.c
new file mode 100644
index 0000000..a9bef1e
--- /dev/null
+++ b/gamut/gammap.c
@@ -0,0 +1,2552 @@
+
+/*
+ * Argyll Gamut Mapping Library
+ *
+ * Author: Graeme W. Gill
+ * Date: 1/10/00
+ * Version: 2.00
+ *
+ * Copyright 2000 - 2006 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.
+ *
+ * For a discussion of gamut mapping strategy used,
+ * see gammap.txt
+ */
+
+/*
+ * TTBD:
+ * Improve error handling.
+ *
+ * There is a general expectation (especially in comparing products)
+ * that the profile colorimetric intent be not strictly minimum delta E,
+ * but that it correct neutral axis, luminence range and keep hue
+ * proportionality. Ideally there should be an intent that matches
+ * this, that can be selected for the colorimetric table (or perhaps be default).
+ *
+ * It might be good to offer the black mapping method as an option (gmm_BPmap),
+ * as well as offering different profile (xicc/xlut.c) black point options
+ * (neutral, K hue max density, CMY max density, any max density).
+ *
+ * The gamut mapping code here and the near smooth code don't actually mesh
+ * very well. For instance, the black point bend approach in < V1.3.4
+ * means that the dest gamut isn't actually contained within the source,
+ * messing up the guide vector mappings. Even if this is fixed, the
+ * actual neutral aim point within nearsmooth is Jab 0,0, while
+ * the mapping in gammap is from the source neutral to the chosen
+ * ??????
+ */
+
+
+
+#define VERBOSE /* [Def] Print out extra interesting information when verbose is set */
+#undef PLOT_DIAG_WRL /* [Und] Always plot "gammap.wrl" */
+
+ /* What do display when user requests disgnostic .wrl */
+#define PLOT_SRC_GMT /* [Def] Plot the source surface to "gammap.wrl" as well */
+#define PLOT_DST_GMT /* [Def] Plot the dest surface to "gammap.wrl" as well */
+#undef PLOT_SRC_CUSPS /* [Und] Plot the source surface cusps to "gammap.wrl" as well */
+#undef PLOT_DST_CUSPS /* [Und] Plot the dest surface cusps to "gammap.wrl" as well */
+#undef PLOT_TRANSSRC_CUSPS /* [Und] Plot the gamut mapped source surface cusps to "gammap.wrl" */
+#undef PLOT_AXES /* [Und] Plot the axes to "gammap.wrl" as well */
+#undef SHOW_VECTOR_INDEXES /* [Und] Show the mapping vector index numbers */
+#define SHOW_MAP_VECTORS /* [Def] Show the mapping vectors */
+#undef SHOW_SUB_SURF /* [Und] Show the sub-surface mapping vector */
+#undef SHOW_CUSPMAP /* [Und] Show the cusp mapped vectors rather than final vectors */
+#undef SHOW_ACTUAL_VECTORS /* [Und?] Show how the source vectors actually map thought xform */
+#undef SHOW_ACTUAL_VEC_DIFF /* [Und] Show how the difference between guide and actual vectors */
+
+#undef PLOT_LMAP /* [Und] Plot L map */
+#undef PLOT_GAMUTS /* [Und] Save (part mapped) input and output gamuts as */
+ /* src.wrl, img.wrl, dst.wrl, gmsrc.wrl */
+#undef PLOT_3DKNEES /* [Und] Plot the 3D compression knees */
+#undef CHECK_NEARMAP /* [Und] Check how accurately near map vectors are represented by rspl */
+
+#define USE_GLUMKNF /* [Define] Enable luminence knee function points */
+#define USE_GREYMAP /* [Define] Enable 3D->3D mapping points down the grey axis */
+#define USE_GAMKNF /* [Define] Enable 3D knee function points */
+#define USE_BOUND /* [Define] Enable grid boundary anchor points */
+
+#undef SHOW_NEIGBORS /* [Und] Show nearsmth neigbors in gammap.wrl */
+
+#undef PLOT_DIGAM /* [Und] Rather than DST_GMT - don't free it (#def in nearsmth.c too) */
+
+
+#define XRES 100 /* Res of plots */
+
+/* Optional marker points for gamut mapping diagnosotic */
+struct {
+ int type; /* 1 = src point (xlate), 2 = dst point (no xlate) */
+ /* 0 = end marker */
+ double pos[3]; /* Position, (usually in Jab space) */
+ double col[3]; /* RGB color */
+} markers[] = {
+ { 0, }, /* End marker */
+ { 1, { 12.062, -0.87946, 0.97008 }, { 1.0, 0.3, 0.3 } }, /* Black point */
+ { 1, { 67.575411, -37.555250, -36.612862 }, { 1.0, 0.3, 0.3 } }, /* bad source in red (Red) */
+ { 1, { 61.003078, -44.466554, 1.922585 }, { 0.0, 1.0, 0.3 } }, /* good source in green */
+ { 2, { 49.294793, 50.749543, -51.383167 }, { 1.0, 0.0, 0.0 } },
+ { 2, { 42.783425, 49.089363, -37.823712 }, { 0.0, 1.0, 0.0 } },
+ { 2, { 41.222695, 63.911823, 37.695310 }, { 0.0, 1.0, 0.3 } }, /* destination in green */
+ { 1, { 41.951770, 60.220284, 34.788195 }, { 1.0, 0.3, 0.3 } }, /* source in red (Red) */
+ { 2, { 41.222695, 63.911823, 37.695310 }, { 0.3, 1.3, 0.3 } }, /* Dest in green */
+ { 1, { 85.117353, -60.807580, -22.195118 }, { 0.3, 0.3, 1 } }, /* Cyan Source (Blue) */
+ { 2, { 61.661622, -38.164411, -18.090824 }, { 1.0, 0.3, 0.3 } }, /* CMYK destination (Red) */
+ { 0 } /* End marker */
+};
+
+/* Optional marker rings for gamut mapping diagnosotic */
+struct {
+ int type; /* 1 = src ring point, 2 = ignore, */
+ /* 0 = end marker */
+ double ppoint[3]; /* Location of a point on the plane in source space */
+ double pnorm[3]; /* Plane normal direction in source space */
+ int nverts; /* Number of points to make ring */
+ double rad; /* Relative Radius from neutral to source surface (0.0 - 1.0) */
+ double scol[3]; /* Source RGB color */
+ double dcol[3]; /* Destination RGB color */
+} rings[] = {
+ { 0 }, /* End marker */
+ { 1,
+ { 60.0, 0.0, 0.0 }, { 1.0, 0.8, 0.0 }, /* plane point and normal */
+ 100, 1.0, /* 20 vertexes at source radius */
+ { 0.0, 1.0, 0.0 }, /* Green source */
+ { 1.0, 0.0, 0.0 } /* Red destination */
+ },
+ { 1,
+ { 60.0, 0.0, 0.0 }, { 1.0, 0.8, 0.0 }, /* plane point and normal */
+ 100, 0.9, /* 20 vertexes at source radius */
+ { 0.0, 1.0, 0.0 }, /* Green source */
+ { 1.0, 0.0, 0.0 } /* Red destination */
+ },
+ { 1,
+ { 60.0, 0.0, 0.0 }, { 1.0, 0.8, 0.0 }, /* plane point and normal */
+ 100, 0.8, /* 20 vertexes at source radius */
+ { 0.0, 1.0, 0.0 }, /* Green source */
+ { 1.0, 0.0, 0.0 } /* Red destination */
+ },
+ { 0 } /* End marker */
+};
+
+/* Degree to which the hue & saturation of the black point axes should be aligned: */
+#define GREYBPHSMF 0.0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "counters.h"
+#include "icc.h"
+#include "numlib.h"
+#include "xicc.h"
+#include "gamut.h"
+#include "rspl.h"
+#include "gammap.h"
+#include "nearsmth.h"
+#include "vrml.h"
+#ifdef PLOT_LMAP
+#include "plot.h"
+#endif
+
+/* Callback context for enhancing the saturation of the clut values */
+typedef struct {
+ gamut *dst; /* Destination colorspace gamut */
+ double wp[3], bp[3];/* Destination colorspace white and black points */
+ double satenh; /* Saturation engancement value */
+} adjustsat;
+
+/* Callback context for making clut relative to white and black points */
+typedef struct {
+ double mat[3][4];
+} adjustwb;
+
+static void inv_grey_func(void *pp, double *out, double *in);
+static void adjust_wb_func(void *pp, double *out, double *in);
+static void adjust_sat_func(void *pp, double *out, double *in);
+
+#define XVRA 4.0 /* Extra mapping vertex ratio over no. tri verts from gamut */
+
+/* The smoothed near weighting control values. */
+/* These weightings setup the detailed behaviour of the */
+/* gamut mapping for the fully perceptual and saturation intents. */
+/* They are ordered here by increasing priority. A -ve value is ignored */
+
+/* Perceptual mapping weights, where smoothness and proportionality are important.. */
+gammapweights pweights[] = {
+ {
+ gmm_default, /* Non hue specific defaults */
+ { /* Cusp alignment control */
+ {
+ 0.1, /* Cusp luminance alignment weighting 0 = none, 1 = full */
+ 0.0, /* Cusp chroma alignment weighting 0 = none, 1 = full */
+ 0.3 /* Cusp hue alignment weighting 0 = none, 1 = full */
+ },
+ 1.00 /* Chroma expansion 1 = none */
+ },
+ { /* Radial weighting */
+ 0.0, /* Radial error overall weight, 0 + */
+ 0.5, /* Radial hue dominance vs l+c, 0 - 1 */
+ 0.5 /* Radial l dominance vs, c, 0 - 1 */
+ },
+ { /* Weighting of absolute error of destination from source */
+ 1.0, /* Absolute error overall weight */
+ 0.6, /* Hue dominance vs l+c, 0 - 1 */
+
+ 0.8, /* White l dominance vs, c, 0 - 1 */
+ 0.5, /* Grey l dominance vs, c, 0 - 1 */
+ 0.97, /* Black l dominance vs, c, 0 - 1 */
+
+ 0.4, /* White l blend start radius, 0 - 1, at white = 0 */
+ 0.7, /* Black l blend power, linear = 1.0, enhance < 1.0 */
+
+ 1.5, /* L error extra power with size, none = 1.0 */
+ 10.0 /* L error extra xover threshold in DE */
+ },
+ { /* Relative vector smoothing */
+ 25.0, 35.0 /* Relative Smoothing radius L* H* */
+ },
+ { /* Weighting of excessive compression error, which is */
+ /* the src->dst vector length over the available dst depth. */
+ /* The depth is half the distance to the intersection of the */
+ /* vector to the other side of the gamut. (doesn't get triggered much ?) */
+ 10.0, /* Compression depth weight */
+ 10.0 /* Expansion depth weight */
+ },
+ {
+ 0.0 /* Fine tuning expansion weight, 0 - 1 */
+ }
+ },
+#ifdef NEVER
+ {
+ gmm_l_d_blue, /* Increase maintaining hue importance for blue */
+ {
+ {
+ -1.0, /* Cusp luminance alignment weighting 0 = none, 1 = full */
+ -1.0, /* Cusp chroma alignment weighting 0 = none, 1 = full */
+ 0.0 /* Cusp hue alignment weighting 0 = none, 1 = full */
+ },
+ -1.0 /* Chroma expansion 1 = none */
+ },
+ { /* Radial weighting */
+ -1.0, /* Radial error overall weight, 0 + */
+ -1.0, /* Radial hue dominance vs l+c, 0 - 1 */
+ -1.0 /* Radial l dominance vs, c, 0 - 1 */
+ },
+ { /* Weighting of absolute error of destination from source */
+ -1.0, /* Absolute error overall weight */
+ 0.8, /* Hue dominance vs l+c, 0 - 1 */
+
+ -1.0, /* White l dominance vs, c, 0 - 1 */
+ -1.0, /* Grey l dominance vs, c, 0 - 1 */
+ -1.0, /* Black l dominance vs, c, 0 - 1 */
+
+ -1.0, /* White l threshold ratio to grey distance, 0 - 1 */
+ -1.0, /* Black l threshold ratio to grey distance, 0 - 1 */
+
+ -1.0, /* L error extra power, none = 1.0 */
+ -1.0 /* L error xover threshold in DE */
+ },
+ { /* Relative error preservation using smoothing */
+ -1.0, 25.0 /* Relative Smoothing radius L* H* */
+ },
+ { /* Weighting of excessive compression error, which is */
+ /* the src->dst vector length over the available dst depth. */
+ /* The depth is half the distance to the intersection of the */
+ /* vector to the other side of the gamut. (doesn't get triggered much ?) */
+ -1.0, /* Compression depth weight */
+ -1.0 /* Expansion depth weight */
+ },
+ {
+ -1.0 /* Fine tuning expansion weight, 0 - 1 */
+ }
+ },
+#endif /* NEVER */
+ {
+ gmm_light_yellow, /* Treat yellow differently, to get purer result. */
+ {
+ {
+ 0.9, /* Cusp luminance alignment weighting 0 = none, 1 = full */
+ 0.8, /* Cusp chroma alignment weighting 0 = none, 1 = full */
+ 0.7 /* Cusp hue alignment weighting 0 = none, 1 = full */
+ },
+ 1.15 /* Chroma expansion 1 = none */
+ },
+ { /* Radial weighting */
+ -1.0, /* Radial error overall weight, 0 + */
+ -1.0, /* Radial hue dominance vs l+c, 0 - 1 */
+ -1.0 /* Radial l dominance vs, c, 0 - 1 */
+ },
+ { /* Weighting of absolute error of destination from source */
+ -1.0, /* Absolute error overall weight */
+ -1.0, /* Hue dominance vs l+c, 0 - 1 */
+
+ -1.0, /* White l dominance vs, c, 0 - 1 */
+ -1.0, /* Grey l dominance vs, c, 0 - 1 */
+ -1.0, /* Black l dominance vs, c, 0 - 1 */
+
+ -1.0, /* White l threshold ratio to grey distance, 0 - 1 */
+ -1.0, /* Black l threshold ratio to grey distance, 0 - 1 */
+
+ -1.0, /* L error extra power, none = 1.0 */
+ -1.0 /* L error xover threshold in DE */
+ },
+ { /* Relative error preservation using smoothing */
+ 20.0, 20.0 /* Relative Smoothing radius L* H* */
+ },
+ { /* Weighting of excessive compression error, which is */
+ /* the src->dst vector length over the available dst depth. */
+ /* The depth is half the distance to the intersection of the */
+ /* vector to the other side of the gamut. (doesn't get triggered much ?) */
+ -1.0, /* Compression depth weight */
+ -1.0 /* Expansion depth weight */
+ },
+ {
+ 0.5 /* Fine tuning expansion weight, 0 - 1 */
+ }
+ },
+ {
+ gmm_end,
+ }
+};
+double psmooth = 5.0; /* [5.0] Level of RSPL smoothing for perceptual, 1 = nominal */
+
+/* Saturation mapping weights, where saturation has priority over smoothness */
+gammapweights sweights[] = {
+ {
+ gmm_default, /* Non hue specific defaults */
+ { /* Cusp alignment control */
+ {
+ 0.6, /* Cusp luminance alignment weighting 0 = none, 1 = full */
+ 0.5, /* Cusp chroma alignment weighting 0 = none, 1 = full */
+ 0.6 /* Cusp hue alignment weighting 0 = none, 1 = full */
+ },
+ 1.05 /* Chroma expansion 1 = none */
+ },
+ { /* Radial weighting */
+ 0.0, /* Radial error overall weight, 0 + */
+ 0.5, /* Radial hue dominance vs l+c, 0 - 1 */
+ 0.5 /* Radial l dominance vs, c, 0 - 1 */
+ },
+ { /* Weighting of absolute error of destination from source */
+ 1.0, /* Absolute error overall weight */
+ 0.4, /* Hue dominance vs l+c, 0 - 1 */
+
+ 0.6, /* White l dominance vs, c, 0 - 1 */
+ 0.4, /* Grey l dominance vs, c, 0 - 1 */
+ 0.6, /* Black l dominance vs, c, 0 - 1 */
+
+ 0.5, /* wl blend start radius, 0 - 1 */
+ 1.0, /* bl blend power, linear = 1.0, enhance < 1.0 */
+
+ 1.0, /* L error extra power with size, none = 1.0 */
+ 10.0 /* L error extra xover threshold in DE */
+ },
+ { /* Relative vector smoothing */
+ 15.0, 20.0 /* Relative Smoothing radius L* H* */
+ },
+ { /* Weighting of excessive compression error, which is */
+ /* the src->dst vector length over the available dst depth. */
+ /* The depth is half the distance to the intersection of the */
+ /* vector to the other side of the gamut. (doesn't get triggered much ?) */
+ 10.0, /* Compression depth weight */
+ 10.0 /* Expansion depth weight */
+ },
+ {
+ 0.5 /* Fine tuning expansion weight, 0 - 1 */
+ }
+ },
+ {
+ gmm_light_yellow, /* Treat yellow differently, to get purer result. */
+ {
+ {
+ 1.0, /* Cusp luminance alignment weighting 0 = none, 1 = full */
+ 1.0, /* Cusp chroma alignment weighting 0 = none, 1 = full */
+ 1.0 /* Cusp hue alignment weighting 0 = none, 1 = full */
+ },
+ 1.20 /* Chroma expansion 1 = none */
+ },
+ { /* Radial weighting */
+ -1.0, /* Radial error overall weight, 0 + */
+ -1.0, /* Radial hue dominance vs l+c, 0 - 1 */
+ -1.0 /* Radial l dominance vs, c, 0 - 1 */
+ },
+ { /* Weighting of absolute error of destination from source */
+ 1.0, /* Absolute error overall weight */
+ 0.3, /* Hue dominance vs l+c, 0 - 1 */
+
+ -1.0, /* White l dominance vs, c, 0 - 1 */
+ -1.0, /* Grey l dominance vs, c, 0 - 1 */
+ -1.0, /* Black l dominance vs, c, 0 - 1 */
+
+ -1.0, /* White l threshold ratio to grey distance, 0 - 1 */
+ -1.0, /* Black l threshold ratio to grey distance, 0 - 1 */
+
+ -1.0, /* L error extra power, none = 1.0 */
+ -1.0 /* L error xover threshold in DE */
+ },
+ { /* Relative error preservation using smoothing */
+ 10.0, 15.0 /* Relative smoothing radius */
+ },
+ { /* Weighting of excessive compression error, which is */
+ /* the src->dst vector length over the available dst depth. */
+ /* The depth is half the distance to the intersection of the */
+ /* vector to the other side of the gamut. (doesn't get triggered much ?) */
+ -1.0, /* Compression depth weight */
+ -1.0 /* Expansion depth weight */
+ },
+ {
+ -1.0 /* Fine tuning expansion weight, 0 - 1 */
+ }
+ },
+ {
+ gmm_end
+ }
+};
+double ssmooth = 2.0; /* Level of RSPL smoothing for saturation */
+
+/*
+ * Notes:
+ * The "knee" shape produced by the rspl (regular spline) code
+ * is not what one would expect for expansion. It is not
+ * symetrical with compression, and is less "sharp". This
+ * is due to the rspl "smoothness" criteria being based on
+ * grid value difference rather than smoothness being measured,
+ * as curvature. This means that the spline gets "stiffer" as
+ * it increases in slope.
+ * Possibly rspl could be improved in this respect ???
+ * (Doesn't matter for L compression now, because rspl is
+ * being inverted for expansion).
+ */
+
+static void del_gammap(gammap *s);
+static void domap(gammap *s, double *out, double *in);
+static void dopartialmap1(gammap *s, double *out, double *in);
+static void dopartialmap2(gammap *s, double *out, double *in);
+static gamut *parttransgamut(gammap *s, gamut *src);
+#ifdef PLOT_GAMUTS
+static void map_trans(void *cntx, double out[3], double in[3]);
+#endif
+
+/* Return a gammap to map from the input space to the output space */
+/* Return NULL on error. */
+gammap *new_gammap(
+ int verb, /* Verbose flag */
+ gamut *sc_gam, /* Source colorspace gamut */
+ gamut *si_gam, /* Source image gamut (NULL if none) */
+ gamut *d_gam, /* Destination colorspace gamut */
+ icxGMappingIntent *gmi, /* Gamut mapping specification */
+ int src_kbp, /* Use K only black point as src gamut black point */
+ int dst_kbp, /* Use K only black point as dst gamut black point */
+ int dst_cmymap, /* masks C = 1, M = 2, Y = 4 to force 100% cusp map */
+ int rel_oride, /* 0 = normal, 1 = clip like, 2 = max relative */
+ int mapres, /* Gamut map resolution, typically 9 - 33 */
+ double *mn, /* If not NULL, set minimum mapping input range */
+ double *mx, /* for rspl grid. */
+ char *diagname /* If non-NULL, write a gamut mapping diagnostic WRL */
+) {
+ gmm_BPmap bph = gmm_bendBP; /* Prefered algorithm */
+// gmm_BPmap bph = gmm_clipBP; /* Alternatives tried */
+// gmm_BPmap bph = gmm_BPadpt;
+// gmm_BPmap bph = gmm_noBPadpt;
+
+ gammap *s; /* This */
+ gamut *scl_gam; /* Source colorspace gamut with rotation and L mapping applied */
+ gamut *sil_gam; /* Source image gamut with rotation and L mapping applied */
+
+ double s_cs_wp[3]; /* Source colorspace white point */
+ double s_cs_bp[3]; /* Source colorspace black point */
+ double s_ga_wp[3]; /* Source (image) gamut white point */
+ double s_ga_bp[3]; /* Source (image) gamut black point */
+ double d_cs_wp[3]; /* Destination colorspace white point */
+ double d_cs_bp[3]; /* Destination colorspace black point */
+
+ double sr_cs_wp[3]; /* Source rotated colorspace white point */
+ double sr_cs_bp[3]; /* Source rotated colorspace black point */
+ double sr_ga_wp[3]; /* Source rotated (image) gamut white point */
+ double sr_ga_bp[3]; /* Source rotated (image) gamut black point */
+ double dr_cs_wp[3]; /* Target (gmi->greymf aligned) white point */
+ double dr_cs_bp[3]; /* Target (gmi->greymf aligned) black point */
+ double dr_be_bp[3]; /* Bend at start in source neutral axis direction */
+ /* Target black point (Same as dr_cs_bp[] otherwise) */
+
+ double sl_cs_wp[3]; /* Source rotated and L mapped colorspace white point */
+ double sl_cs_bp[3]; /* Source rotated and L mapped colorspace black point */
+
+ double s_mt_wp[3]; /* Overall source mapping target white point (used for finetune) */
+ double s_mt_bp[3]; /* Overall source mapping target black point (used for finetune) */
+ double d_mt_wp[3]; /* Overall destination mapping white point (used for finetune) */
+ double d_mt_bp[3]; /* Overall destination mapping black point (used for finetune) */
+
+ int defrgrid = 6; /* mapping range surface default anchor point resolution */
+ int nres = 512; /* Neutral axis resolution */
+ cow lpnts[10]; /* Mapping points to create grey axis map */
+ int revrspl = 0; /* Reverse grey axis rspl construction */
+ int ngreyp = 0; /* Number of grey axis mapping points */
+ int ngamp = 0; /* Number of gamut mapping points */
+ double xvra = XVRA; /* Extra ss vertex ratio to src gamut vertex count */
+ int j;
+
+#if defined(PLOT_LMAP) || defined(PLOT_GAMUTS) || defined(PLOT_3DKNEES)
+ fprintf(stderr,"##### A gammap.c PLOT is #defined ####\n");
+#endif
+
+ if (verb) {
+ xicc_dump_gmi(gmi);
+ printf("Gamut map resolution: %d\n",mapres);
+ if (si_gam != NULL)
+ printf("Image gamut supplied\n");
+ switch(bph) {
+ case gmm_clipBP: printf("Neutral axis no-adapt extend and clip\n"); break;
+ case gmm_BPadpt: printf("Neutral axis fully adapt\n"); break;
+ case gmm_bendBP: printf("Neutral axis no-adapt extend and bend\n"); break;
+ case gmm_noBPadpt: printf("Neutral axis no-adapt\n"); break;
+ }
+ }
+
+ /* Allocate the object */
+ if ((s = (gammap *)calloc(1, sizeof(gammap))) == NULL)
+ error("gammap: calloc failed on gammap object");
+
+ /* Setup methods */
+ s->del = del_gammap;
+ s->domap = domap;
+
+ /* Now create everything */
+
+ /* Grab the white and black points */
+ if (src_kbp) {
+ // ~~99 Hmm. Shouldn't this be colorspace rather than gamut ????
+ if (sc_gam->getwb(sc_gam, NULL, NULL, NULL, s_cs_wp, NULL, s_cs_bp)) {
+// if (sc_gam->getwb(sc_gam, s_cs_wp, NULL, s_cs_bp, NULL, NULL, NULL))
+ fprintf(stderr,"gamut map: Unable to read source colorspace white and black points\n");
+ free(s);
+ return NULL;
+ }
+ } else {
+ if (sc_gam->getwb(sc_gam, NULL, NULL, NULL, s_cs_wp, s_cs_bp, NULL)) {
+// if (sc_gam->getwb(sc_gam, s_cs_wp, s_cs_bp, NULL, NULL, NULL, NULL))
+ fprintf(stderr,"gamut map: Unable to read source colorspace white and black points\n");
+ free(s);
+ return NULL;
+ }
+ }
+
+ /* If source space is source gamut */
+ if (si_gam == NULL) {
+ si_gam = sc_gam;
+ for (j = 0; j < 3; j++) {
+ s_ga_wp[j] = s_cs_wp[j];
+ s_ga_bp[j] = s_cs_bp[j];
+ }
+
+ /* Else have explicit sourcegamut */
+ } else {
+
+ if (src_kbp) {
+ if (si_gam->getwb(si_gam, NULL, NULL, NULL, s_ga_wp, NULL, s_ga_bp)) {
+ fprintf(stderr,"gamut map: Unable to read source gamut white and black points\n");
+ free(s);
+ return NULL;
+ }
+ } else {
+ if (si_gam->getwb(si_gam, NULL, NULL, NULL, s_ga_wp, s_ga_bp, NULL)) {
+ fprintf(stderr,"gamut map: Unable to read source gamut white and black points\n");
+ free(s);
+ return NULL;
+ }
+ }
+
+ /* Guard against silliness. Image must be within colorspace */
+ if (s_ga_wp[0] > s_cs_wp[0]) {
+ int j;
+ double t;
+#ifdef VERBOSE
+ if (verb)
+ printf("Fixing wayward image white point\n");
+#endif
+ t = (s_cs_wp[0] - s_ga_bp[0])/(s_ga_wp[0] - s_ga_bp[0]);
+ for (j = 0; j < 3; j++)
+ s_ga_wp[j] = s_ga_bp[j] + t * (s_ga_wp[j] - s_ga_bp[j]);
+
+ }
+ if (s_ga_bp[0] < s_cs_bp[0]) {
+ int j;
+ double t;
+#ifdef VERBOSE
+ if (verb)
+ printf("Fixing wayward image black point\n");
+#endif
+ t = (s_cs_bp[0] - s_ga_wp[0])/(s_ga_bp[0] - s_ga_wp[0]);
+ for (j = 0; j < 3; j++)
+ s_ga_bp[j] = s_ga_wp[j] + t * (s_ga_bp[j] - s_ga_wp[j]);
+ }
+ }
+
+ if (dst_kbp) {
+ if (d_gam->getwb(d_gam, NULL, NULL, NULL, d_cs_wp, NULL, d_cs_bp)) {
+ fprintf(stderr,"gamut map: Unable to read destination white and black points\n");
+ free(s);
+ return NULL;
+ }
+ } else {
+ if (d_gam->getwb(d_gam, NULL, NULL, NULL, d_cs_wp, d_cs_bp, NULL)) {
+ fprintf(stderr,"gamut map: Unable to read destination white and black points\n");
+ free(s);
+ return NULL;
+ }
+ }
+
+#ifdef VERBOSE
+ if (verb) {
+ if (src_kbp)
+ printf("Using Src K only black point\n");
+
+ if (dst_kbp)
+ printf("Using Dst K only black point\n");
+
+ printf("Src colorspace white/black are %f %f %f, %f %f %f\n",
+ s_cs_wp[0], s_cs_wp[1], s_cs_wp[2], s_cs_bp[0], s_cs_bp[1], s_cs_bp[2]);
+
+ printf("Src gamut white/black are %f %f %f, %f %f %f\n",
+ s_ga_wp[0], s_ga_wp[1], s_ga_wp[2], s_ga_bp[0], s_ga_bp[1], s_ga_bp[2]);
+
+ printf("Dst colorspace white/black are %f %f %f, %f %f %f\n",
+ d_cs_wp[0], d_cs_wp[1], d_cs_wp[2], d_cs_bp[0], d_cs_bp[1], d_cs_bp[2]);
+ }
+#endif /* VERBOSE */
+
+ /* ------------------------------------ */
+ /* Figure out the destination grey axis alignment */
+ /* This is all done using colorspace white & black points */
+ {
+ double t, svl, dvl;
+ double wrot[3][3]; /* Rotation about 0,0,0 to match white points */
+ double sswp[3], ssbp[3]; /* Temporary source white & black points */
+ double fawp[3], fabp[3]; /* Fully adapted destination white & black */
+ double hawp[3], habp[3]; /* Half (full white, not black) adapted destination w & b */
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* The first task is to decide what our target destination */
+ /* white and black points are going to be. */
+
+ /* Figure out what our initial target destination white point is going to be: */
+
+ /* Compute source white and black points with same L value as the destination */
+ t = (d_cs_wp[0] - s_cs_bp[0])/(s_cs_wp[0] - s_cs_bp[0]);
+ for (j = 0; j < 3; j++)
+ sswp[j] = s_cs_bp[j] + t * (s_cs_wp[j] - s_cs_bp[j]);
+
+ t = (d_cs_bp[0] - s_cs_wp[0])/(s_cs_bp[0] - s_cs_wp[0]);
+ for (j = 0; j < 3; j++)
+ ssbp[j] = s_cs_wp[j] + t * (s_cs_bp[j] - s_cs_wp[j]);
+
+ /* The raw grey axis alignment target is a blend between the */
+ /* source colorspace (NOT gamut) and the destination */
+ /* colorspace. */
+
+ for (j = 0; j < 3; j++) {
+ dr_cs_wp[j] = gmi->greymf * d_cs_wp[j] + (1.0 - gmi->greymf) * sswp[j];
+ dr_cs_bp[j] = gmi->greymf * d_cs_bp[j] + (1.0 - gmi->greymf) * ssbp[j];
+ }
+
+#ifdef VERBOSE
+ if (verb) {
+ printf("Target (blended) dst wp/bp = %f %f %f, %f %f %f\n",
+ dr_cs_wp[0], dr_cs_wp[1], dr_cs_wp[2], dr_cs_bp[0], dr_cs_bp[1], dr_cs_bp[2]);
+ }
+#endif /* VERBOSE */
+
+ /* Compute full adaptation target destinations */
+ for (j = 0; j < 3; j++) {
+ fawp[j] = dr_cs_wp[j]; /* White fully adapted */
+ fabp[j] = dr_cs_bp[j]; /* Black fully adapted */
+ }
+
+ /* Clip the target grey axis to the destination gamut */
+ if (d_gam->vector_isect(d_gam, fabp, fawp, fabp, fawp, NULL, NULL, NULL, NULL) == 0)
+ error("gamut: vector_isect failed!");
+
+ /* To work around the problem that vector_isect() is not entirely accurate, */
+ /* special case the situation where gmi->greymf == 1.0 */
+ if (gmi->greymf > 0.99) {
+ for (j = 0; j < 3; j++) {
+ fawp[j] = d_cs_wp[j];
+ fabp[j] = d_cs_bp[j];
+ }
+ }
+
+ /* If dst_kbp is set, then clipping to the dest gamut doesn't do what we want, */
+ /* since it extends the black to a full composite black point. */
+ /* A "K only" gamut is hard to define, so do a hack: */
+ /* scale fabp[] towards fawp[] so that it has the same L as */
+ /* the destination K only black point. */
+ if (dst_kbp && fabp[0] < d_cs_bp[0]) {
+ t = (d_cs_bp[0] - fawp[0])/(fabp[0] - fawp[0]);
+
+ for (j = 0; j < 3; j++)
+ fabp[j] = fawp[j] + t * (fabp[j] - fawp[j]);
+ }
+
+ /* Compute half adapted (full white, not black) target destinations */
+ for (j = 0; j < 3; j++)
+ hawp[j] = dr_cs_wp[j]; /* White fully adapted */
+
+ /* Compute the rotation matrix that maps the source white point */
+ /* onto the target white point. */
+ icmRotMat(wrot, sswp, dr_cs_wp);
+
+ /* Compute the target black point as the rotated source black point */
+ icmMulBy3x3(habp, wrot, s_cs_bp);
+
+ /* Now intersect the target white and black points with the destination */
+ /* colorspace gamut to arrive at the best possible in gamut values for */
+ /* the target white and black points. */
+ if (d_gam->vector_isect(d_gam, habp, hawp, habp, hawp, NULL, NULL, NULL, NULL) == 0)
+ error("gamut: vector_isect failed!");
+
+ /* To work around the problem that vector_isect() is not entirely accurate, */
+ /* special case the situation where gmi->greymf == 1.0 */
+ if (gmi->greymf > 0.99) {
+ for (j = 0; j < 3; j++) {
+ hawp[j] = d_cs_wp[j];
+ }
+ }
+
+ /* If dst_kbp is set, then clipping to the dest gamut doesn't do what we want, */
+ /* since it extends the black to a full composite black point. */
+ /* A "K only" gamut is hard to define, so do a hack: */
+ /* scale habp[] towards hawp[] so that it has the same L as */
+ /* the destination K only black point. */
+ if (dst_kbp && habp[0] < d_cs_bp[0]) {
+ t = (d_cs_bp[0] - hawp[0])/(habp[0] - hawp[0]);
+
+ for (j = 0; j < 3; j++)
+ habp[j] = hawp[j] + t * (habp[j] - hawp[j]);
+ }
+
+ /* Now decide the detail of the white and black alignment */
+ if (bph == gmm_BPadpt || bph == gmm_bendBP) { /* Adapt to destination white and black */
+
+
+ /* Use the fully adapted white and black points */
+ for (j = 0; j < 3; j++) {
+ dr_cs_wp[j] = fawp[j];
+ dr_cs_bp[j] = fabp[j];
+ }
+
+ if (bph == gmm_bendBP) {
+
+ /* Extend the half adapted (white = dst, black = src) black point */
+ /* to the same L as the target (dst), to use as the initial (bent) black point */
+ t = (dr_cs_bp[0] - dr_cs_wp[0])/(habp[0] - dr_cs_wp[0]);
+ for (j = 0; j < 3; j++)
+ dr_be_bp[j] = dr_cs_wp[j] + t * (habp[j] - dr_cs_wp[j]);
+
+ } else {
+
+ /* Set bent black point target to be the same as our actual */
+ /* black point target, so that the "bend" code does nothing. */
+ for (j = 0; j < 3; j++)
+ dr_be_bp[j] = dr_cs_bp[j];
+ }
+
+ } else { /* Adapt to destination white but not black */
+
+ /* Use the half adapted (white = dst, black = src) white and black points */
+ for (j = 0; j < 3; j++) {
+ dr_cs_wp[j] = hawp[j];
+ dr_cs_bp[j] = habp[j];
+ }
+
+#ifdef VERBOSE
+ if (verb) {
+ printf("Adapted target wp/bp = %f %f %f, %f %f %f\n",
+ dr_cs_wp[0], dr_cs_wp[1], dr_cs_wp[2], dr_cs_bp[0], dr_cs_bp[1], dr_cs_bp[2]);
+ }
+#endif
+ if (bph == gmm_clipBP) {
+
+ /* Extend the target black point to accomodate the */
+ /* bent or clipped destination space L* range */
+ if (fabp[0] < dr_cs_bp[0]) {
+ t = (fabp[0] - dr_cs_wp[0])/(dr_cs_bp[0] - dr_cs_wp[0]);
+ for (j = 0; j < 3; j++)
+ dr_cs_bp[j] = dr_cs_wp[j] + t * (dr_cs_bp[j] - d_cs_wp[j]);
+ }
+ }
+
+ /* Set the bent black point target to be the same as our actual */
+ /* black point target, so that the "bend" code does nothing. */
+ for (j = 0; j < 3; j++)
+ dr_be_bp[j] = dr_cs_bp[j];
+ }
+
+#ifdef VERBOSE
+ if (verb) {
+ printf("Adapted & extended tgt wp/bp = %f %f %f, %f %f %f\n",
+ dr_cs_wp[0], dr_cs_wp[1], dr_cs_wp[2], dr_cs_bp[0], dr_cs_bp[1], dr_cs_bp[2]);
+ }
+#endif /* VERBOSE */
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Now we need to figure out what origin alignment is needed, as well as */
+ /* making sure the vectors are the same length to avoid rescaling. */
+ /* (Scaling is meant to be done with the L curve though.) */
+
+ /* Create temporary source white point that has the same L as the */
+ /* target destination white point. */
+ t = (dr_cs_wp[0] - s_cs_bp[0])/(s_cs_wp[0] - s_cs_bp[0]);
+ for (j = 0; j < 3; j++)
+ sswp[j] = s_cs_bp[j] + t * (s_cs_wp[j] - s_cs_bp[j]);
+
+ /* Create temporary source black point that will form a vector to the src white */
+ /* point with same length as the target destination black->white vector. */
+ for (svl = dvl = 0.0, j = 0; j < 3; j++) {
+ double tt;
+ tt = sswp[j] - s_cs_bp[j];
+ svl += tt * tt;
+ tt = dr_cs_wp[j] - dr_cs_bp[j];
+ dvl += tt * tt;
+ }
+ svl = sqrt(svl);
+ dvl = sqrt(dvl);
+ for (j = 0; j < 3; j++)
+ ssbp[j] = sswp[j] + dvl/svl * (s_cs_bp[j] - sswp[j]);
+
+#ifdef VERBOSE
+ if (verb) {
+ printf("Rotate matrix src wp/bp = %f %f %f, %f %f %f\n",
+ sswp[0], sswp[1], sswp[2], ssbp[0], ssbp[1], ssbp[2]);
+ printf("Rotate matrix dst wp/bp = %f %f %f, %f %f %f\n",
+ dr_cs_wp[0], dr_cs_wp[1], dr_cs_wp[2], dr_cs_bp[0], dr_cs_bp[1], dr_cs_bp[2]);
+ }
+#endif /* VERBOSE */
+
+ /* Now create the general rotation and translation to map the source grey */
+ /* axis to our destination grey axis. */
+ icmVecRotMat(s->grot, sswp, ssbp, dr_cs_wp, dr_cs_bp);
+
+ /* And create the inverse as well: */
+ icmVecRotMat(s->igrot, dr_cs_wp, dr_cs_bp, sswp, ssbp);
+
+ /* Create rotated versions of source colorspace & image white and */
+ /* black points for use from now on, given that rotation will */
+ /* be applied first to all source points. */
+ icmMul3By3x4(sr_cs_wp, s->grot, s_cs_wp);
+ icmMul3By3x4(sr_cs_bp, s->grot, s_cs_bp);
+ icmMul3By3x4(sr_ga_wp, s->grot, s_ga_wp);
+ icmMul3By3x4(sr_ga_bp, s->grot, s_ga_bp);
+
+#ifdef VERBOSE
+ if (verb) {
+ printf("Bend target bp = %f %f %f\n",
+ dr_be_bp[0], dr_be_bp[1], dr_be_bp[2]);
+ printf("Rotated source grey axis wp/bp %f %f %f, %f %f %f\n",
+ sr_cs_wp[0], sr_cs_wp[1], sr_cs_wp[2], sr_cs_bp[0], sr_cs_bp[1], sr_cs_bp[2]);
+ printf("Rotated gamut grey axis wp/bp %f %f %f, %f %f %f\n",
+ sr_ga_wp[0], sr_ga_wp[1], sr_ga_wp[2], sr_ga_bp[0], sr_ga_bp[1], sr_ga_bp[2]);
+ printf("Destination axis target wp/bp %f %f %f, %f %f %f\n",
+ dr_cs_wp[0], dr_cs_wp[1], dr_cs_wp[2], dr_cs_bp[0], dr_cs_bp[1], dr_cs_bp[2]);
+ }
+#endif
+ }
+
+#ifdef NEVER
+sr_cs_wp[0] = 100.0;
+sr_cs_bp[0] = 30.0;
+dr_cs_wp[0] = 80.0;
+dr_cs_bp[0] = 10.0;
+glumknf = 1.0;
+#endif /* NEVER */
+
+ /* Create the mapping points needed to build the 1D L mapping rspl. */
+ /* If we have a gamut (ie. image) range that is smaller than the */
+ /* L range of the colorspace, then use its white and black L values */
+ /* as the source to be compressed to the destination L range. */
+ /* We expand only a colorspace range, not a gamut/image range. */
+ {
+ double swL, dwL; /* Source and destination white point L */
+ double sbL, dbL; /* Source and destination black point L */
+ int j;
+ double t;
+
+ /* Setup white point mapping */
+ if (sr_cs_wp[0] <= dr_cs_wp[0]) { /* Needs possible expansion */
+ swL = sr_cs_wp[0];
+ dwL = gmi->glumwexf * dr_cs_wp[0] + (1.0 - gmi->glumwexf) * sr_cs_wp[0];
+
+ } else {
+ if (sr_ga_wp[0] > dr_cs_wp[0]) { /* Gamut or colorspace needs compression */
+
+ swL = (1.0 - gmi->glumwcpf) * dr_cs_wp[0] + gmi->glumwcpf * sr_ga_wp[0];
+ dwL = dr_cs_wp[0];
+
+ } else { /* Neither needed */
+ swL = sr_ga_wp[0];
+ dwL = sr_ga_wp[0];
+ }
+ }
+
+ /* Setup black point mapping */
+ if (sr_cs_bp[0] >= dr_cs_bp[0]) { /* Needs possible expansion */
+ sbL = sr_cs_bp[0];
+ dbL = gmi->glumbexf * dr_cs_bp[0] + (1.0 - gmi->glumbexf) * sr_cs_bp[0];
+
+ } else {
+ if (sr_ga_bp[0] < dr_cs_bp[0]) { /* Gamut or colorspace needs compression */
+
+ sbL = (1.0 - gmi->glumbcpf) * dr_cs_bp[0] + gmi->glumbcpf * sr_ga_bp[0];
+ dbL = dr_cs_bp[0];
+
+ } else { /* Neither needed */
+ sbL = sr_ga_bp[0];
+ dbL = sr_ga_bp[0];
+ }
+ }
+
+ /* To ensure symetry between compression and expansion, always create RSPL */
+ /* for compression and its inverse, and then swap grey and igrey rspl to compensate. */
+ if ((dwL - dbL) > (swL - sbL))
+ revrspl = 1;
+
+ /* White point end */
+ lpnts[ngreyp].p[0] = swL;
+ lpnts[ngreyp].v[0] = dwL;
+ lpnts[ngreyp++].w = 10.0; /* Must go through here */
+
+ /* Black point end */
+ lpnts[ngreyp].p[0] = sbL;
+ lpnts[ngreyp].v[0] = dbL;
+ lpnts[ngreyp++].w = 10.0; /* Must go through here */
+
+//printf("~1 white loc %f, val %f\n",swL,dwL);
+//printf("~1 black loc %f, val %f\n",sbL,dbL);
+
+#ifdef USE_GLUMKNF
+ if (gmi->glumknf < 0.05)
+#endif /* USE_GLUMKNF */
+ { /* make sure curve is firmly anchored */
+ lpnts[ngreyp].p[0] = 0.3 * lpnts[ngreyp-1].p[0] + 0.7 * lpnts[ngreyp-2].p[0];
+ lpnts[ngreyp].v[0] = 0.3 * lpnts[ngreyp-1].v[0] + 0.7 * lpnts[ngreyp-2].v[0];
+ lpnts[ngreyp++].w = 1.0;
+
+ lpnts[ngreyp].p[0] = 0.7 * lpnts[ngreyp-2].p[0] + 0.3 * lpnts[ngreyp-3].p[0];
+ lpnts[ngreyp].v[0] = 0.7 * lpnts[ngreyp-2].v[0] + 0.3 * lpnts[ngreyp-3].v[0];
+ lpnts[ngreyp++].w = 1.0;
+ }
+#ifdef USE_GLUMKNF
+ else { /* There is at least some weight in knee points */
+ double cppos = 0.50; /* Center point ratio between black and white */
+ double cplv; /* Center point location and value */
+ double kppos = 0.30; /* Knee point ratio between white/black & center */
+ double kwl, kbl, kwv, kbv; /* Knee point values and locations */
+ double kwx, kbx; /* Knee point extra */
+
+
+//printf("sbL = %f, swL = %f\n",sbL,swL);
+//printf("dbL = %f, dwL = %f\n",dbL,dwL);
+
+ /* Center point */
+ cplv = cppos * (swL - sbL) + sbL;
+//printf("~1 computed cplv = %f\n",cplv);
+
+#ifdef NEVER /* Don't use a center point */
+ lpnts[ngreyp].p[0] = cplv;
+ lpnts[ngreyp].v[0] = cplv;
+ lpnts[ngreyp++].w = 0.5;
+#endif
+
+//printf("~1 black half diff = %f\n",dbL - sbL);
+//printf("~1 white half diff = %f\n",dwL - swL);
+
+ /* Knee point locations */
+ kwl = kppos * (cplv - swL) + swL;
+ kbl = kppos * (cplv - sbL) + sbL;
+
+ /* Extra compression for white and black knees */
+ kwx = 0.6 * (dbL - sbL) + 1.0 * (swL - dwL);
+ kbx = 1.0 * (dbL - sbL) + 0.6 * (swL - dwL);
+
+//kwx = 0.0;
+//kbx = 0.0;
+//glumknf = 0.0;
+
+ /* Knee point values */
+ kwv = (dwL + kwx - cplv) * (kwl - cplv)/(swL - cplv) + cplv;
+ if (kwv > dwL) /* Sanity check */
+ kwv = dwL;
+
+ kbv = (dbL - kbx - cplv) * (kbl - cplv)/(sbL - cplv) + cplv;
+ if (kbv < dbL) /* Sanity check */
+ kbv = dbL;
+
+
+//printf("~1 kbl = %f, kbv = %f\n",kbl, kbv);
+//printf("~1 kwl = %f, kwv = %f\n",kwl, kwv);
+
+ /* Emphasise points to cause "knee" curve */
+ lpnts[ngreyp].p[0] = kwl;
+ lpnts[ngreyp].v[0] = kwv;
+ lpnts[ngreyp++].w = gmi->glumknf * gmi->glumknf;
+
+ lpnts[ngreyp].p[0] = kbl;
+ lpnts[ngreyp].v[0] = kbv;
+ lpnts[ngreyp++].w = 1.5 * gmi->glumknf * 1.5 * gmi->glumknf;
+ }
+#endif /* USE_GLUMKNF */
+
+ /* Remember our source and destinatio mapping targets */
+ /* so that we can use them for fine tuning later. */
+
+ /* We scale the source and target white and black */
+ /* points to match the L values of the source and destination */
+ /* L curve mapping, as this is how we have chosen the */
+ /* white and black point mapping for the link. */
+ /* Put them back in pre-rotated space, so that we can */
+ /* check the overall transform of the white and black points. */
+ t = (swL - sr_cs_bp[0])/(sr_cs_wp[0] - sr_cs_bp[0]);
+ for (j = 0; j < 3; j++)
+ s_mt_wp[j] = sr_cs_bp[j] + t * (sr_cs_wp[j] - sr_cs_bp[j]);
+ icmMul3By3x4(s_mt_wp, s->igrot, s_mt_wp);
+
+ t = (sbL - sr_cs_wp[0])/(sr_cs_bp[0] - sr_cs_wp[0]);
+ for (j = 0; j < 3; j++)
+ s_mt_bp[j] = sr_cs_wp[j] + t * (sr_cs_bp[j] - sr_cs_wp[j]);
+//printf("~1 check black point rotated = %f %f %f\n",s_mt_bp[0],s_mt_bp[1],s_mt_bp[2]);
+ icmMul3By3x4(s_mt_bp, s->igrot, s_mt_bp);
+//printf("~1 check black point prerotated = %f %f %f\n",s_mt_bp[0],s_mt_bp[1],s_mt_bp[2]);
+
+ t = (dwL - dr_cs_bp[0])/(dr_cs_wp[0] - dr_cs_bp[0]);
+ for (j = 0; j < 3; j++)
+ d_mt_wp[j] = dr_cs_bp[j] + t * (dr_cs_wp[j] - dr_cs_bp[j]);
+
+ for (j = 0; j < 3; j++)
+ d_mt_bp[j] = dr_cs_wp[j] + t * (dr_cs_bp[j] - dr_cs_wp[j]);
+ }
+
+ /* We now create the 1D rspl L map, that compresses or expands the luminence */
+ /* range, independent of grey axis alignment, or gamut compression. */
+ /* Because the rspl isn't symetrical when we swap X & Y, and we would */
+ /* like a conversion from profile A to B to be the inverse of profile B to A */
+ /* (as much as possible), we contrive here to always create a compression */
+ /* RSPL, and create an inverse for it, and swap the two of them so that */
+ /* the transform is correct and has an accurate inverse available. */
+ {
+ datai il, ih;
+ datao ol, oh;
+ double avgdev[MXDO];
+ int gres = 256;
+
+ if (revrspl) { /* Invert creation and usage for symetry between compress and exp. */
+ int i;
+ for (i = 0; i < ngreyp; i++) {
+ double tt = lpnts[i].p[0]; /* Swap source and dest */
+ lpnts[i].p[0] = lpnts[i].v[0];
+ lpnts[i].v[0] = tt;
+ }
+ }
+
+ /* Create a 1D rspl, that is used to */
+ /* form the overall L compression mapping. */
+ if ((s->grey = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) /* Allocate 1D -> 1D */
+ error("gamut: grey new_rspl failed");
+
+ il[0] = -1.0; /* Set possible input range */
+ ih[0] = 101.0;
+ ol[0] = 0.0; /* Set normalisation output range */
+ oh[0] = 100.0;
+
+#ifdef NEVER /* Dump out the L mapping points */
+ {
+ int i;
+ printf("1D rspl L mapping points:\n");
+ for (i = 0; i < ngreyp; i++)
+ printf("%d %f -> %f (w %f)\n",i,lpnts[i].p[0],lpnts[i].v[0],lpnts[i].w);
+ }
+#endif
+ /* Create spline from the data points, with appropriate smoothness. */
+ avgdev[0] = GAMMAP_RSPLAVGDEV;
+ if (s->grey->fit_rspl_w(s->grey, GAMMAP_RSPLFLAGS, lpnts, ngreyp, il, ih, &gres, ol, oh, 5.0, avgdev, NULL)) {
+ fprintf(stderr,"Warning: Grey axis mapping is non-monotonic - may not be very smooth ?\n");
+ }
+
+ /* Create an inverse mapping too, for reverse gamut and/or expansion. */
+ il[0] = -1.0; /* Set possible input range */
+ ih[0] = 101.0;
+ ol[0] = 0.0; /* Set normalisation output range */
+ oh[0] = 100.0;
+
+ if ((s->igrey = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) /* Allocate 1D -> 1D */
+ error("gamut: igrey new_rspl failed");
+
+ /* Create it from inverse lookups of s->grey */
+ s->igrey->set_rspl(s->igrey, 0, (void *)s->grey, inv_grey_func, il, ih, &gres, ol, oh);
+
+ if (revrspl) { /* Swap to compensate for expansion */
+ rspl *tt = s->grey;
+ s->grey = s->igrey;
+ s->igrey = tt;
+ }
+ }
+
+#ifdef PLOT_LMAP
+ { /* Plot the 1D mapping */
+ double xx[XRES];
+ double y1[XRES];
+ int i;
+
+ for (i = 0; i < XRES; i++) {
+ double x;
+ co cp; /* Conversion point */
+ x = sr_cs_bp[0] + (i/(double)(XRES-1)) * (sr_cs_wp[0] - sr_cs_bp[0]);
+ xx[i] = x;
+ cp.p[0] = x;
+ s->grey->interp(s->grey, &cp);
+ y1[i] = cp.v[0];
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+#endif /* PLOT_LMAP */
+
+ {
+ /* We want to rotate and then map L independently of everything else, */
+ /* so transform source csape & image gamuts through the rotation and L mapping */
+ /* before we create the surface 3D mapping from them */
+
+ /* Create L mapped versions of rotated src colorspace white/black points */
+#ifdef NEVER
+ co cp;
+ double t;
+ int i;
+
+ cp.p[0] = sr_cs_wp[0];
+ s->grey->interp(s->grey, &cp);
+
+ t = (cp.v[0] - sr_cs_bp[0])/(sr_cs_wp[0] - sr_cs_bp[0]);
+ for (j = 0; j < 3; j++)
+ sl_cs_wp[j] = sr_cs_bp[j] + t * (sr_cs_wp[j] - sr_cs_bp[j]);
+
+ cp.p[0] = sr_cs_bp[0];
+ s->grey->interp(s->grey, &cp);
+ t = (cp.v[0] - sr_cs_wp[0])/(sr_cs_bp[0] - sr_cs_wp[0]);
+ for (j = 0; j < 3; j++)
+ sl_cs_bp[j] = sr_cs_wp[j] + t * (sr_cs_bp[j] - sr_cs_wp[j]);
+#else
+ dopartialmap1(s, sl_cs_wp, s_cs_wp);
+ dopartialmap1(s, sl_cs_bp, s_cs_bp);
+#endif
+
+#ifdef VERBOSE
+ if (verb) {
+ printf("Mapped source grey axis wp/bp %f %f %f, %f %f %f\n",
+ sl_cs_wp[0], sl_cs_wp[1], sl_cs_wp[2], sl_cs_bp[0], sl_cs_bp[1], sl_cs_bp[2]);
+ }
+#endif
+
+ if ((scl_gam = parttransgamut(s, sc_gam)) == NULL) {
+ fprintf(stderr,"gamut map: parttransgamut failed\n");
+ free(s);
+ return NULL;
+ }
+
+ if (sc_gam == si_gam)
+ sil_gam = scl_gam;
+
+ else {
+ if ((sil_gam = parttransgamut(s, si_gam)) == NULL) {
+ fprintf(stderr,"gamut map: parttransgamut failed\n");
+ free(s);
+ return NULL;
+ }
+ }
+ }
+
+ /* Create all the 3D->3D gamut mapping points and 3D rspl, */
+ /* if there is any compression or expansion to do. */
+ if (gmi->gamcpf > 1e-6 || gmi->gamexf > 1e-6) {
+ cow *gpnts = NULL; /* Mapping points to create gamut mapping */
+ int nspts; /* Number of source gamut surface points */
+ int rgridpts; /* Number of range surface grid points */
+ int i, j;
+ datai il, ih;
+ datao ol, oh;
+ int gres[MXDI];
+ double avgdev[MXDO];
+ nearsmth *nsm = NULL; /* Returned list of near smooth points */
+ int nnsm; /* Number of near smoothed points */
+ double brad = 0.0; /* Black bend radius */
+ gammapweights xpweights[14], xsweights[14]; /* Explicit perceptial and sat. weights */
+ gammapweights xwh[14]; /* Structure holding blended weights */
+ double smooth = 1.0; /* Level of 3D RSPL smoothing, blend of psmooth and ssmooth */
+ vrml *wrl = NULL; /* Gamut mapping illustration (hulls + guide vectors) */
+ cgats *locus = NULL; /* Diagnostic locus to plot in wrl, NULL if none */
+
+#ifdef PLOT_3DKNEES
+typedef struct {
+ double v0[3], v1[3];
+} p3dk_lpoint;
+ p3dk_lpoint *p3dk_locus;
+ int p3dk_ix = 0;
+#endif /* PLOT_3DKNEES */
+
+ /* Get the maximum number of points that will be created */
+ nspts = near_smooth_np(scl_gam, sil_gam, d_gam, xvra);
+
+ rgridpts = 0;
+#ifdef USE_BOUND
+ if (defrgrid >= 2) {
+ rgridpts = defrgrid * defrgrid * defrgrid
+ - (defrgrid -2) * (defrgrid -2) * (defrgrid -2);
+ }
+#endif
+
+ if ((gpnts = (cow *)malloc((nres + 3 * nspts + rgridpts) * sizeof(cow))) == NULL) {
+ fprintf(stderr,"gamut map: Malloc of mapping setup points failed\n");
+ s->grey->del(s->grey);
+ s->igrey->del(s->igrey);
+ if (sil_gam != scl_gam)
+ sil_gam->del(sil_gam);
+ scl_gam->del(scl_gam);
+ free(s);
+ return NULL;
+ }
+
+#ifdef PLOT_3DKNEES
+ if ((p3dk_locus = (p3dk_lpoint *)malloc((2 * nspts) * sizeof(p3dk_lpoint))) == NULL)
+ error("gamut: Diagnostic array p3dk_locus malloc failed");
+#endif /* PLOT_3DKNEES */
+
+ /* ------------------------------------------- */
+ /* Finish off the grey axis mapping by creating the */
+ /* grey axis 3D->3D mapping points */
+ /* We use 4 times the grid density, and create */
+ /* points that span the source colorspace (this may exceed) */
+ /* the source image gamut, and map to points outside the */
+ /* destination gamut) */
+
+ /* See how much to bend the black - compute the color difference */
+ /* We start out in the direction of dr_be_bp at white, and at */
+ /* the end we bend towards the overall bp dr_cs_bp */
+ /* (brad will be 0 for non gmm_bendBP because dr_be_bp dr_cs_bp */
+ for (brad = 0.0, i = 1; i < 3; i++) {
+ double tt = dr_be_bp[i] - dr_cs_bp[i];
+ brad += tt * tt;
+ }
+ brad = sqrt(brad);
+
+//printf("~1 brad = %f, Bend target = %f %f %f, straight = %f %f %f\n",
+//brad, dr_be_bp[0], dr_be_bp[1], dr_be_bp[2], dr_cs_bp[0], dr_cs_bp[1], dr_cs_bp[2]);
+
+#ifdef USE_GREYMAP
+ for (i = 0; i < nres; i++) { /* From black to white */
+ double t;
+ double bv[3]; /* Bent (initial) destination value */
+ double dv[3]; /* Straight (final) destination value */
+ double wt = 1.0; /* Default grey axis point weighting */
+
+ /* Create source grey axis point */
+ t = i/(nres - 1.0);
+
+ /* Cover L = 0.0 to 100.0 */
+ t = ((100.0 * t) - sl_cs_bp[0])/(sl_cs_wp[0] - sl_cs_bp[0]);
+ for (j = 0; j < 3; j++)
+ gpnts[ngamp].p[j] = sl_cs_bp[j] + t * (sl_cs_wp[j] - sl_cs_bp[j]);
+
+ /* L values are the same, as they have been mapped prior to 3D */
+ gpnts[ngamp].v[0] = gpnts[ngamp].p[0];
+
+ /* Figure destination point on initial bent grey axis */
+ t = (gpnts[ngamp].v[0] - dr_cs_wp[0])/(dr_be_bp[0] - dr_cs_wp[0]);
+ for (j = 0; j < 3; j++)
+ bv[j] = dr_cs_wp[j] + t * (dr_be_bp[j] - dr_cs_wp[j]);
+//printf("~1 t = %f, bent dest %f %f %f\n",t, bv[0], bv[1],bv[2]);
+
+ /* Figure destination point on final straight grey axis */
+ t = (gpnts[ngamp].v[0] - dr_cs_wp[0])/(dr_cs_bp[0] - dr_cs_wp[0]);
+ for (j = 0; j < 3; j++)
+ dv[j] = dr_cs_wp[j] + t * (dr_cs_bp[j] - dr_cs_wp[j]);
+//printf("~1 t = %f, straight dest %f %f %f\n",t, dv[0], dv[1],dv[2]);
+
+ /* Figure out a blend value between the bent value */
+ /* and the straight value, so that it curves smoothly from */
+ /* one to the other. */
+ if (brad > 0.001) {
+ double ty;
+ t = ((dr_cs_bp[0] + brad) - gpnts[ngamp].v[0])/brad;
+ if (t < 0.0)
+ t = 0.0;
+ else if (t > 1.0)
+ t = 1.0;
+ /* Make it a spline ? */
+ t = t * t * (3.0 - 2.0 * t);
+ ty = t * t * (3.0 - 2.0 * t); /* spline blend value */
+ t = (1.0 - t) * ty + t * t; /* spline at t == 0, linear at t == 1 */
+
+ wt *= (1.0 + t * brad); /* Increase weigting with the bend */
+
+ } else {
+ t = 0.0; /* stick to straight, it will be close anyway. */
+ }
+
+ for (j = 0; j < 3; j++) /* full straight when t == 1 */
+ gpnts[ngamp].v[j] = t * dv[j] + (1.0 - t) * bv[j];
+ gpnts[ngamp].w = wt;
+//printf("~1 t = %f, blended %f %f %f\n",t, gpnts[ngamp].v[0], gpnts[ngamp].v[1],gpnts[ngamp].v[2]);
+
+#ifdef NEVER
+ printf("Grey axis %d maps %f %f %f -> %f %f %f wit %f\n",ngamp,
+ gpnts[ngamp].p[0], gpnts[ngamp].p[1], gpnts[ngamp].p[2],
+ gpnts[ngamp].v[0], gpnts[ngamp].v[1], gpnts[ngamp].v[2],
+ gpnts[ngamp].w);
+#endif
+ ngamp++;
+ }
+#endif /* USE_GREYMAP */
+
+ /* ---------------------------------------------------- */
+ /* Do preliminary computation of the rspl input and output bounding values */
+ for (j = 0; j < 3; j++) {
+ il[j] = ol[j] = 1e60;
+ ih[j] = oh[j] = -1e60;
+ }
+
+ /* From grey axis points */
+ for (i = 0; i < ngamp; i++) {
+ for (j = 0; j < 3; j++) {
+ if (gpnts[i].p[j] < il[j])
+ il[j] = gpnts[i].p[j];
+ if (gpnts[i].p[j] > ih[j])
+ ih[j] = gpnts[i].p[j];
+ }
+ }
+
+ /* From the source gamut */
+ {
+ double tmx[3], tmn[3];
+ scl_gam->getrange(scl_gam, tmn, tmx);
+ for (j = 0; j < 3; j++) {
+ if (tmn[j] < il[j])
+ il[j] = tmn[j];
+ if (tmx[j] > ih[j])
+ ih[j] = tmx[j];
+ }
+ }
+
+ /* from input arguments override */
+ if (mn != NULL && mx != NULL) {
+
+ for (j = 0; j < 3; j++) {
+ if (mn[j] < il[j])
+ il[j] = mn[j];
+ if (mx[j] > ih[j])
+ ih[j] = mx[j];
+ }
+ }
+
+ /* From the destination gamut */
+ {
+ double tmx[3], tmn[3];
+ d_gam->getrange(d_gam, tmn, tmx);
+ for (j = 0; j < 3; j++) {
+ if (tmn[j] < ol[j])
+ ol[j] = tmn[j];
+ if (tmx[j] > oh[j])
+ oh[j] = tmx[j];
+ }
+ }
+
+ /* ---------------------------------------------------- */
+ /* Deal with gamut hull guide vector creation. */
+
+ /* For compression, create a mapping for each vertex of */
+ /* the source gamut (image) surface towards the destination gamut */
+ /* For expansion, do the opposite. */
+
+ /* Convert from compact to explicit hextant weightings */
+ if (expand_weights(xpweights, pweights)
+ || expand_weights(xsweights, sweights)) {
+ fprintf(stderr,"gamut map: expand_weights() failed\n");
+ s->grey->del(s->grey);
+ s->igrey->del(s->igrey);
+ if (sil_gam != scl_gam)
+ sil_gam->del(sil_gam);
+ scl_gam->del(scl_gam);
+ free(s);
+ return NULL;
+ }
+ /* Create weights as blend between perceptual and saturation */
+ near_xwblend(xwh, xpweights, gmi->gampwf, xsweights, gmi->gamswf);
+ if ((gmi->gampwf + gmi->gamswf) > 0.1)
+ smooth = (gmi->gampwf * psmooth) + (gmi->gamswf * ssmooth);
+
+ /* Tweak gamut mappings according to extra cmy cusp flags or rel override */
+ if (dst_cmymap != 0 || rel_oride != 0) {
+ tweak_weights(xwh, dst_cmymap, rel_oride);
+ }
+
+ /* Create the near point mapping, which is our fundamental gamut */
+ /* hull to gamut hull mapping. */
+ nsm = near_smooth(verb, &nnsm, scl_gam, sil_gam, d_gam, src_kbp, dst_kbp,
+ dr_cs_bp, xwh, gmi->gamcknf, gmi->gamxknf,
+ gmi->gamcpf > 1e-6, gmi->gamexf > 1e-6,
+ xvra, mapres, smooth, il, ih, ol, oh);
+ if (nsm == NULL) {
+ fprintf(stderr,"Creating smoothed near points failed\n");
+ s->grey->del(s->grey);
+ s->igrey->del(s->igrey);
+ if (sil_gam != scl_gam)
+ sil_gam->del(sil_gam);
+ scl_gam->del(scl_gam);
+ free(s);
+ return NULL;
+ }
+ /* --------------------------- */
+
+ /* Make sure the input range to encompasss the guide vectors. */
+ for (i = 0; i < nnsm; i++) {
+ for (j = 0; j < 3; j++) {
+ if (nsm[i].sv[j] < il[j])
+ il[j] = nsm[i].sv[j];;
+ if (nsm[i].sv[j] > ih[j])
+ ih[j] = nsm[i].sv[j];
+ }
+ }
+
+#ifdef NEVER
+ if (verb) {
+ fprintf(stderr,"Input bounding box:\n");
+ fprintfstderr,("%f -> %f, %f -> %f, %f -> %f\n",
+ il[0], ih[0], il[1], ih[1], il[2], ih[2]);
+ }
+#endif
+
+ /* Now expand the bounding box by aprox 5% margin, but scale grid res */
+ /* to match, so that the natural or given boundary still lies on the grid. */
+ {
+ int xmapres;
+ double scale;
+
+ xmapres = (int) ((mapres-1) * 0.05 + 0.5);
+ if (xmapres < 1)
+ xmapres = 1;
+
+ scale = (double)(mapres-1 + xmapres)/(double)(mapres-1);
+
+ for (j = 0; j < 3; j++) {
+ double low, high;
+ high = ih[j];
+ low = il[j];
+ ih[j] = (scale * (high - low)) + low;
+ il[j] = (scale * (low - high)) + high;
+ }
+
+ mapres += 2 * xmapres;
+#ifdef NEVER
+ if (verb) {
+ fprintf(stderr,"After incresing mapres to %d, input bounding box for 3D gamut mapping is:\n",mapres);
+ fprintf(stderr,"%f -> %f, %f -> %f, %f -> %f\n",
+ il[0], ih[0], il[1], ih[1], il[2], ih[2]);
+ }
+#endif
+ }
+
+ /* ---------------------------------------------------- */
+ /* Setup for diagnostic plot, that will have elements added */
+ /* as we create the final 3D gamut mapping rspl */
+ /* (The plot is of the already rotated and L mapped source space) */
+ {
+ int doaxes = 0;
+
+#ifdef PLOT_AXES
+ doaxes = 1;
+#endif
+ if (diagname != NULL)
+ wrl = new_vrml(diagname, doaxes, 0);
+#ifdef PLOT_DIAG_WRL
+ else
+ wrl = new_vrml("gammap.wrl", doaxes, 0);
+#endif
+ }
+
+ if (wrl != NULL) {
+ /* See if there is a diagnostic locus to plot too */
+ if ((locus = new_cgats()) == NULL)
+ error("Failed to create cgats object");
+
+ locus->add_other(locus, "TS");
+
+ if (locus->read_name(locus, "locus.ts")) {
+ locus->del(locus);
+ locus = NULL;
+ } else {
+ if (verb)
+ printf("!! Found diagnostic locus.ts file !!\n");
+ /* locus will be added later */
+ }
+
+ /* Add diagnostic markers from markers structure */
+ for (i = 0; ; i++) {
+ double pp[3];
+ co cp;
+ if (markers[i].type == 0)
+ break;
+
+ if (markers[i].type == 1) { /* Src point - do luminance mapping */
+ dopartialmap1(s, pp, markers[i].pos);
+ } else {
+ pp[0] = markers[i].pos[0];
+ pp[1] = markers[i].pos[1];
+ pp[2] = markers[i].pos[2];
+ }
+ wrl->add_marker(wrl, pp, markers[i].col, 1.0);
+ }
+ }
+
+ /* --------------------------- */
+ /* Now computue our 3D mapping points from the near point mapping. */
+ for (i = 0; i < nnsm; i++) {
+ double cpexf; /* The effective compression or expansion factor */
+
+ if (nsm[i].vflag == 0) { /* Unclear whether compression or expansion */
+ /* Use larger to the the two factors */
+ cpexf = gmi->gamcpf > gmi->gamexf ? gmi->gamcpf : gmi->gamexf;
+
+ } else if (nsm[i].vflag == 1) { /* Compression */
+ cpexf = gmi->gamcpf;
+
+ } else if (nsm[i].vflag == 2) { /* Expansion */
+ cpexf = gmi->gamexf;
+
+ } else {
+ error("gammap: internal, unknown guide point flag");
+ }
+
+ /* Compute destination value which is a blend */
+ /* between the source value and the fully mapped destination value. */
+ icmBlend3(nsm[i].div, nsm[i].sv, nsm[i].dv, cpexf);
+
+#ifdef NEVER
+ printf("%s mapping:\n",nsm[i].vflag == 0 ? "Unclear" : nsm[i].vflag == 1 ? "Compression" : "Expansion");
+ printf("Src point = %f %f %f radius %f\n",nsm[i].sv[0], nsm[i].sv[1], nsm[i].sv[2], nsm[i].sr);
+ printf("Dst point = %f %f %f radius %f\n",nsm[i].dv[0], nsm[i].dv[1], nsm[i].dv[2], nsm[i].dr);
+ printf("Blended dst point = %f %f %f\n",nsm[i].div[0], nsm[i].div[1], nsm[i].div[2]);
+#endif /* NEVER */
+ /* Set the main gamut hull mapping point */
+ for (j = 0; j < 3; j++) {
+ gpnts[ngamp].p[j] = nsm[i].sv[j];
+ gpnts[ngamp].v[j] = nsm[i].div[j];
+ }
+ gpnts[ngamp++].w = 1.01; /* Main gamut surface mapping point */
+ /* (Use 1.01 as a marker value) */
+
+#ifdef USE_GAMKNF
+ /* Add sub surface mapping point if available */
+ if (nsm[i].vflag != 0) { /* Sub surface point is available */
+
+ /* Compute destination value which is a blend */
+ /* between the source value and the fully mapped destination value. */
+ icmBlend3(nsm[i].div2, nsm[i].sv2, nsm[i].dv2, cpexf);
+
+#ifdef NEVER
+ printf("Src2 point = %f %f %f radius %f\n",nsm[i].sv2[0], nsm[i].sv2[1], nsm[i].sv2[2], nsm[i].sr);
+ printf("Dst2 point = %f %f %f radius %f\n",nsm[i].dv2[0], nsm[i].dv2[1], nsm[i].dv2[2], nsm[i].dr);
+ printf("Blended dst2 point = %f %f %f\n",nsm[i].div2[0], nsm[i].div2[1], nsm[i].div2[2]);
+ printf("\n");
+#endif /* NEVER */
+ /* Set the sub-surface gamut hull mapping point */
+ for (j = 0; j < 3; j++) {
+ gpnts[ngamp].p[j] = nsm[i].sv2[j];
+ gpnts[ngamp].v[j] = nsm[i].div2[j];
+ }
+ gpnts[ngamp++].w = nsm[i].w2; /* Sub-suface mapping points */
+ }
+#endif /* USE_GAMKNF */
+ }
+
+ /* Create preliminary gamut mapping rspl, without grid boundary values. */
+ /* We use this to lookup the mapping for points on the source space gamut */
+ /* that result from clipping our grid boundary points */
+#ifdef USE_BOUND
+ for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+ gres[j] = (mapres+1)/2;
+ avgdev[j] = GAMMAP_RSPLAVGDEV;
+ }
+ s->map = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
+ s->map->fit_rspl_w(s->map, GAMMAP_RSPLFLAGS, gpnts, ngamp, il, ih, gres, ol, oh, smooth, avgdev, NULL);
+
+ /* Add input range grid surface anchor points to improve clipping behaviour. */
+ if (defrgrid >= 2) {
+ DCOUNT(gc, 3, 3, 0, 0, defrgrid);
+ double cent[3];
+
+ sc_gam->getcent(d_gam, cent);
+
+ DC_INIT(gc);
+ for (;;) {
+ /* If point is on the grid surface */
+ if ( gc[0] == 0 || gc[0] == (defrgrid-1)
+ || gc[1] == 0 || gc[1] == (defrgrid-1)
+ || gc[2] == 0 || gc[2] == (defrgrid-1)) {
+ double grid2gamut, gamut2cent, ww;
+ co cp;
+
+ /* Clip the point to the closest location on the source */
+ /* colorspace gamut. */
+ for (j = 0; j < 3; j++)
+ gpnts[ngamp].p[j] = il[j] + gc[j]/(defrgrid-1.0) * (ih[j] - il[j]);
+ sc_gam->nearest(sc_gam, cp.p, gpnts[ngamp].p);
+
+ /* Then lookup the equivalent gamut mapped value */
+ s->map->interp(s->map, &cp);
+
+ for (j = 0; j < 3; j++)
+ gpnts[ngamp].v[j] = cp.v[j];
+
+ /* Compute the distance of the grid surface point to the to the */
+ /* source colorspace gamut, as well as the distance from there */
+ /* to the gamut center point. */
+ for (grid2gamut = gamut2cent = 0.0, j = 0; j < 3; j++) {
+ double tt;
+ tt = gpnts[ngamp].p[j] - cp.p[j];
+ grid2gamut += tt * tt;
+ tt = cp.p[j] - cent[j];
+ gamut2cent += tt * tt;
+ }
+ grid2gamut = sqrt(grid2gamut);
+ gamut2cent = sqrt(gamut2cent);
+
+ /* Make the weighting inversely related to distance, */
+ /* to reduce influence on in gamut mapping shape, */
+ /* while retaining some influence at the edge of the */
+ /* grid. */
+ ww = grid2gamut / gamut2cent;
+ if (ww > 1.0)
+ ww = 1.0;
+
+ /* A low weight seems to be enough ? */
+ /* the lower the better in terms of geting best hull mapping fidelity */
+ gpnts[ngamp++].w = 0.05 * ww;
+ }
+ DC_INC(gc);
+ if (DC_DONE(gc))
+ break;
+ }
+ }
+#else /* !USE_BOUND */
+ printf("!!!! Warning - gammap boundary points disabled !!!!\n");
+#endif /* !USE_BOUND */
+
+ /* --------------------------- */
+ /* Compute the output bounding values, and check input range hasn't changed */
+ for (i = 0; i < ngamp; i++) {
+ for (j = 0; j < 3; j++) {
+ if (gpnts[i].p[j] < (il[j]-1e-5) || gpnts[i].p[j] > (ih[j]+1e-5))
+ warning("gammap internal: input bounds has changed! %f <> %f <> %f",il[j],gpnts[i].p[j],ih[j]);
+ if (gpnts[i].v[j] < ol[j])
+ ol[j] = gpnts[i].v[j];
+ if (gpnts[i].v[j] > oh[j])
+ oh[j] = gpnts[i].v[j];
+ }
+ }
+
+ /* --------------------------- */
+
+#ifdef NEVER /* Dump out all the mapping points */
+ {
+ for (i = 0; i < ngamp; i++) {
+ printf("%d: %f %f %f -> %f %f %f\n",i,
+ gpnts[i].p[0], gpnts[i].p[1], gpnts[i].p[2],
+ gpnts[i].v[0], gpnts[i].v[1], gpnts[i].v[2]);
+ }
+ }
+#endif
+
+ /* Create the final gamut mapping rspl. */
+ /* [ The smoothing is not as useful as it should be, because */
+ /* if it is increased it tends to push colors out of gamut */
+ /* where they get clipped. Some cleverer scheme which makes */
+ /* sure that smoothness errs on the side of more compression */
+ /* is needed. - Addressed in nearsmth now ? ] */
+ /* How about converting to a delta filer ? ie. */
+ /* create curren filter, then create point list of delta from */
+ /* smoothed value, filtering that and then un-deltering it ?? */
+ if (s->map != NULL)
+ s->map->del(s->map);
+ if (verb)
+ printf("Creating rspl..\n");
+ for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+ gres[j] = mapres;
+ avgdev[j] = GAMMAP_RSPLAVGDEV;
+ }
+ s->map = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
+ if (s->map->fit_rspl_w(s->map, GAMMAP_RSPLFLAGS, gpnts, ngamp, il, ih, gres, ol, oh, smooth, avgdev, NULL)) {
+ if (verb)
+ fprintf(stderr,"Warning: Gamut mapping is non-monotonic - may not be very smooth !\n");
+ }
+ /* return the min and max of the input values valid in the grid */
+ s->map->get_in_range(s->map, s->imin, s->imax);
+
+#ifdef CHECK_NEARMAP
+ /* Check how accurate gamut shell mapping is against nsm */
+ /* (This isn't a good indication now that vectors have been adjusted */
+ /* to counteract the rspl smoothing at the edges.) */
+ if (verb) {
+ double de, avgde = 0.0, maxde = 0.0; /* DE stats */
+
+ for (i = 0; i < nnsm; i++) {
+ double av[3];
+
+ /* Compute the mapping error */
+ dopartialmap2(s, av, nsm[i].sv); /* Just the rspl */
+
+ de = icmLabDE(nsm[i].div, av);
+ avgde += de;
+ if (de > maxde)
+ maxde = de;
+ }
+ printf("Gamut hull fit to guides: = avg %f, max %f\n",avgde/nnsm,maxde);
+ }
+#endif /* CHECK_NEARMAP */
+
+ /* If requested, enhance the saturation of the output values. */
+ if (gmi->satenh > 0.0) {
+ adjustsat cx; /* Adjustment context */
+
+ /* Compute what our source white and black points actually maps to */
+ s->domap(s, cx.wp, s_mt_wp);
+ s->domap(s, cx.bp, s_mt_bp);
+
+ cx.dst = d_gam;
+ cx.satenh = gmi->satenh;
+
+ /* Saturation enhance the output values */
+ s->map->re_set_rspl(
+ s->map, /* this */
+ 0, /* Combination of flags */
+ (void *)&cx, /* Opaque function context */
+ adjust_sat_func /* Function to set from */
+ );
+ }
+
+ /* Test the gamut white and black point mapping, and "fine tune" */
+ /* the mapping, to ensure an accurate transform of the white */
+ /* and black points to the destination colorspace. */
+ /* This compensates for any inacuracy introduced in the */
+ /* various rspl mappings. */
+ {
+ adjustwb cx; /* Adjustment context */
+ double a_wp[3]; /* actual white point */
+ double a_bp[3]; /* actual black point */
+
+ if (verb)
+ printf("Fine tuning white and black point mapping\n");
+
+ /* Check what the source white and black points actually maps to */
+ s->domap(s, a_wp, s_mt_wp);
+ s->domap(s, a_bp, s_mt_bp);
+
+#ifdef VERBOSE
+ if (verb) {
+ printf("White is %f %f %f, should be %f %f %f\n",
+ a_wp[0], a_wp[1], a_wp[2], d_mt_wp[0], d_mt_wp[1], d_mt_wp[2]);
+ printf("Black is %f %f %f, should be %f %f %f\n",
+ a_bp[0], a_bp[1], a_bp[2], d_mt_bp[0], d_mt_bp[1], d_mt_bp[2]);
+ }
+#endif /* VERBOSE */
+
+ /* Setup the fine tune transform */
+
+ /* We've decided not to fine tune the black point if we're */
+ /* bending to the destination black, as the bend is not */
+ /* followed perfectly (too sharp, or in conflict with */
+ /* the surface mapping ?) and we don't want to shift */
+ /* mid neutrals due to this. */
+ /* We do fine tune it if dst_kbp is set though, since */
+ /* we would like perfect K only out. */
+
+ /* Compute rotation/scale relative white point matrix */
+ icmVecRotMat(cx.mat, a_wp, a_bp, d_mt_wp, d_mt_bp); /* wp & bp */
+
+ /* Fine tune the 3D->3D mapping */
+ s->map->re_set_rspl(
+ s->map, /* this */
+ 0, /* Combination of flags */
+ (void *)&cx, /* Opaque function context */
+ adjust_wb_func /* Function to set from */
+ );
+
+#ifdef VERBOSE
+ if (verb) {
+ /* Check what the source white and black points actually maps to */
+ s->domap(s, a_wp, s_mt_wp);
+ s->domap(s, a_bp, s_mt_bp);
+
+ printf("After fine tuning:\n");
+ printf("White is %f %f %f, should be %f %f %f\n",
+ a_wp[0], a_wp[1], a_wp[2], d_mt_wp[0], d_mt_wp[1], d_mt_wp[2]);
+ printf("Black is %f %f %f, should be %f %f %f\n",
+ a_bp[0], a_bp[1], a_bp[2], d_mt_bp[0], d_mt_bp[1], d_mt_bp[2]);
+ }
+#endif /* VERBOSE */
+ }
+
+ if (wrl != NULL) {
+ int arerings = 0;
+ double cc[3] = { 0.7, 0.7, 0.7 };
+ double nc[3] = { 1.0, 0.4, 0.7 }; /* Pink for neighbors */
+ int nix = -1; /* Index of point to show neighbour */
+
+#ifdef SHOW_NEIGBORS
+#ifdef NEVER
+ /* Show all neighbours */
+ wrl->start_line_set(wrl, 0);
+ for (i = 0; i < nnsm; i++) {
+ for (j = 0; j < XNNB; j++) {
+ nearsmth *np = nsm[i].n[j]; /* Pointer to neighbor */
+
+ if (np == NULL)
+ break;
+
+ wrl->add_col_vertex(wrl, 0, nsm[i].sv, nc); /* Source value */
+ wrl->add_col_vertex(wrl, 0, np->sv, nc); /* Neighbpor value */
+ }
+ }
+ wrl->make_lines(wrl, 0, 2);
+#else
+ /* Show neighbours of points near source markers */
+ for (i = 0; ; i++) { /* Add diagnostic markers */
+ double pp[3];
+ co cp;
+ int ix, bix;
+ double bdist = 1e6;
+
+ if (markers[i].type == 0)
+ break;
+
+ if (markers[i].type != 1)
+ continue;
+
+ /* Rotate and map marker point the same as the src gamuts */
+ icmMul3By3x4(pp, s->grot, markers[i].pos);
+ cp.p[0] = pp[0]; /* L value */
+ s->grey->interp(s->grey, &cp);
+ pp[0] = cp.v[0];
+//printf("~1 looking for closest point to marker %d at %f %f %f\n",i,pp[0],pp[1],pp[2]);
+
+ /* Locate the nearest source point */
+ for (ix = 0; ix < nnsm; ix++) {
+ double dist = icmNorm33(pp, nsm[ix].sv);
+ if (dist < bdist) {
+ bdist = dist;
+ bix = ix;
+ }
+ }
+//printf("~1 closest src point ix %d at %f %f %f\n",bix,nsm[bix].sv[0],nsm[bix].sv[1],nsm[bix].sv[2]);
+//printf("~1 there are %d neighbours\n",nsm[bix].nnb);
+
+ wrl->start_line_set(wrl, 0);
+ for (j = 0; j < nsm[bix].nnb; j++) {
+ nearsmth *np = nsm[bix].n[j].n; /* Pointer to neighbor */
+
+ wrl->add_col_vertex(wrl, 0, nsm[bix].sv, nc); /* Source value */
+ wrl->add_col_vertex(wrl, 0, np->sv, nc); /* Neighbpor value */
+ }
+ wrl->make_lines(wrl, 0, 2);
+ }
+#endif
+#endif /* SHOW_NEIGBORS */
+
+ /* Add the source and dest gamut surfaces */
+#ifdef PLOT_SRC_GMT
+ wrl->make_gamut_surface_2(wrl, sil_gam, 0.6, 0, cc);
+#endif /* PLOT_SRC_GMT */
+#ifdef PLOT_DST_GMT
+ cc[0] = -1.0;
+ wrl->make_gamut_surface(wrl, d_gam, 0.2, cc);
+#endif /* PLOT_DST_GMT */
+#ifdef PLOT_DIGAM
+ if (nsm[0].dgam == NULL)
+ error("Need to #define PLOT_DIGAM in nearsmth.c!");
+ cc[0] = -1.0;
+ wrl->make_gamut_surface(wrl, nsm[0].dgam, 0.2, cc);
+#endif /* PLOT_DIGAM */
+#ifdef PLOT_SRC_CUSPS
+ wrl->add_cusps(wrl, sil_gam, 0.6, NULL);
+#endif /* PLOT_SRC_CUSPS */
+#ifdef PLOT_DST_CUSPS
+ wrl->add_cusps(wrl, d_gam, 0.3, NULL);
+#endif /* PLOT_DST_CUSPS */
+
+#ifdef PLOT_TRANSSRC_CUSPS
+ /* Add transformed source cusp markers */
+ {
+ int i;
+ double cusps[6][3];
+ double ccolors[6][3] = {
+ { 1.0, 0.1, 0.1 }, /* Red */
+ { 1.0, 1.0, 0.1 }, /* Yellow */
+ { 0.1, 1.0, 0.1 }, /* Green */
+ { 0.1, 1.0, 1.0 }, /* Cyan */
+ { 0.1, 0.1, 1.0 }, /* Blue */
+ { 1.0, 0.1, 1.0 } /* Magenta */
+ };
+
+ if (sc_gam->getcusps(sc_gam, cusps) == 0) {
+
+ for (i = 0; i < 6; i++) {
+ double val[3];
+
+ s->domap(s, val, cusps[i]);
+ wrl->add_marker(wrl, val, ccolors[i], 2.5);
+ }
+ }
+ }
+#endif
+
+#if defined(SHOW_MAP_VECTORS) || defined(SHOW_SUB_SURF) || defined(SHOW_ACTUAL_VECTORS) || defined(SHOW_ACTUAL_VEC_DIFF)
+ /* Start of guide vector plot */
+ wrl->start_line_set(wrl, 0);
+
+ for (i = 0; i < nnsm; i++) {
+ double cpexf; /* The effective compression or expansion factor */
+ double yellow[3] = { 1.0, 1.0, 0.0 };
+ double red[3] = { 1.0, 0.0, 0.0 };
+ double green[3] = { 0.0, 1.0, 0.0 };
+ double lgrey[3] = { 0.8, 0.8, 0.8 };
+ double purp[3] = { 0.6, 0.0, 1.0 };
+ double blue[3] = { 0.2, 0.2, 1.0 };
+ double *ccc;
+ double mdst[3];
+
+#if defined(SHOW_ACTUAL_VECTORS) || defined(SHOW_ACTUAL_VEC_DIFF)
+# ifdef SHOW_ACTUAL_VECTORS
+ wrl->add_col_vertex(wrl, 0, nsm[i].sv, yellow);
+# else /* SHOW_ACTUAL_VEC_DIFF */
+ wrl->add_col_vertex(wrl, 0, nsm[i].div, yellow);
+# endif
+ dopartialmap2(s, mdst, nsm[i].sv);
+ wrl->add_col_vertex(wrl, 0, mdst, red);
+
+#else
+# ifdef SHOW_MAP_VECTORS
+ ccc = yellow;
+
+ if (nsm[i].gflag == 0)
+ ccc = green; /* Mark "no clear direction" vectors in green->red */
+# ifdef SHOW_CUSPMAP
+ wrl->add_col_vertex(wrl, 0, nsm[i].csv, ccc); /* Cusp mapped source value */
+# else
+ wrl->add_col_vertex(wrl, 0, nsm[i].sv, ccc); /* Source value */
+# endif
+ wrl->add_col_vertex(wrl, 0, nsm[i].div, red); /* Blended destination value */
+# endif /* SHOW_MAP_VECTORS */
+
+# ifdef SHOW_SUB_SURF
+ if (nsm[i].vflag != 0) { /* Sub surface point is available */
+
+ wrl->add_col_vertex(wrl, 0, nsm[i].sv2, lgrey); /* Subs-surf Source value */
+ wrl->add_col_vertex(wrl, 0, nsm[i].div2, purp); /* Blended destination value */
+ }
+# endif /* SHOW_SUB_SURF */
+#endif /* !SHOW_ACTUAL_VECTORS */
+ }
+ wrl->make_lines(wrl, 0, 2); /* Guide vectors */
+#endif /* Show vectors */
+
+#ifdef SHOW_VECTOR_INDEXES
+ for (i = 0; i < nnsm; i++) {
+ double cream[3] = { 0.7, 0.7, 0.5 };
+ char buf[100];
+ sprintf(buf, "%d", i);
+ wrl->add_text(wrl, buf, nsm[i].sv, cream, 0.5);
+ }
+#endif /* SHOW_VECTOR_INDEXES */
+
+ /* add the locus from locus.ts file */
+ if (locus != NULL) {
+ int table, npoints;
+ char *fnames[3] = { "LAB_L", "LAB_A", "LAB_B" };
+ int ix[3];
+ double v0[3], v1[3];
+ double rgb[3];
+
+ /* Each table holds a separate locus */
+ for (table = 0; table < locus->ntables; table++) {
+
+ if ((npoints = locus->t[table].nsets) <= 0)
+ error("No sets of data in diagnostic locus");
+
+ for (j = 0; j < 3; j++) {
+ if ((ix[j] = locus->find_field(locus, 0, fnames[j])) < 0)
+ error ("Locus file doesn't contain field %s",fnames[j]);
+ if (locus->t[table].ftype[ix[j]] != r_t)
+ error ("Field %s is wrong type",fnames[j]);
+ }
+
+ /* Source locus */
+ rgb[0] = 1.0;
+ rgb[1] = 0.5;
+ rgb[2] = 0.5;
+ for (i = 0; i < npoints; i++) {
+ co cp;
+
+ for (j = 0; j < 3; j++)
+ v1[j] = *((double *)locus->t[table].fdata[i][ix[j]]);
+
+ /* Rotate and locus verticies the same as the src gamuts */
+ dopartialmap1(s, v1, v1);
+ if (i > 0 )
+ wrl->add_cone(wrl, v0, v1, rgb, 0.5);
+ icmAry2Ary(v0,v1);
+ }
+
+ /* Gamut mapped locus */
+ rgb[0] = 1.0;
+ rgb[1] = 1.0;
+ rgb[2] = 1.0;
+ for (i = 0; i < npoints; i++) {
+ co cp;
+
+ for (j = 0; j < 3; j++)
+ v1[j] = *((double *)locus->t[table].fdata[i][ix[j]]);
+
+ s->domap(s, v1, v1);
+ if (i > 0 )
+ wrl->add_cone(wrl, v0, v1, rgb, 0.5);
+ icmAry2Ary(v0,v1);
+ }
+ }
+
+ locus->del(locus);
+ locus = NULL;
+ }
+
+ /* Add any ring mapping diagnostics */
+ for (i = 0; ; i++) {
+ if (rings[i].type == 0)
+ break;
+
+ if (rings[i].type == 2)
+ continue;
+
+ if (rings[i].type == 1) {
+ double pconst;
+ double cpoint[3];
+ double mat[3][4]; /* translate to our plane */
+ double imat[3][4]; /* translate from our plane */
+ double s1[3], s0[3], t1[3];
+ int j;
+ double maxa, mina;
+ double maxb, minb;
+
+ if (arerings == 0) {
+ arerings = 1;
+ wrl->start_line_set(wrl, 1); /* Source ring */
+ wrl->start_line_set(wrl, 2); /* Destination ring */
+ }
+
+ if (icmNormalize3(rings[i].pnorm, rings[i].pnorm, 1.0))
+ error("Ring %d diagnostic plane normal failed",i);
+
+ pconst = -icmDot3(rings[i].ppoint, rings[i].pnorm);
+
+ /* Locate intersection of source neautral axis and plane */
+ if (icmVecPlaneIsect(cpoint, pconst, rings[i].pnorm, s_cs_wp, s_cs_bp))
+ error("Ring %d diagnostic center point intersection failed",i);
+
+ /* Compute the rotation and translation between */
+ /* a plane in ab and the plane we are using */
+ s0[0] = s0[1] = s0[2] = 0.0;
+ s1[0] = 1.0, s1[1] = s1[2] = 0.0;
+ t1[0] = cpoint[0] + rings[i].pnorm[0];
+ t1[1] = cpoint[1] + rings[i].pnorm[1];
+ t1[2] = cpoint[2] + rings[i].pnorm[2];
+ icmVecRotMat(mat, s1, s0, t1, cpoint);
+ icmVecRotMat(imat, t1, cpoint, s1, s0);
+
+ /* Do a min/max of a circle of vectors so as to */
+ /* establish an offset to the centroid for this slice */
+ maxa = maxb = -1e60;
+ mina = minb = 1e60;
+ for (j = 0; j < 20; j++) {
+ double ang = 2 * 3.1415926 * j/(20 - 1.0);
+ double vec[3], isect[3];
+ double pp[3];
+ co cp;
+ int k;
+
+ vec[0] = 0.0;
+ vec[1] = sin(ang);
+ vec[2] = cos(ang);
+ icmMul3By3x4(vec, mat, vec);
+
+ /* Intersect it with the source gamut */
+ if (si_gam->vector_isect(si_gam, vec, cpoint, isect,
+ NULL, NULL, NULL, NULL, NULL) == 0) {
+ continue;
+ }
+
+ /* Translate back to plane */
+ icmMul3By3x4(pp, imat, isect);
+
+ if (pp[1] > maxa)
+ maxa = pp[1];
+ if (pp[1] < mina)
+ mina = pp[1];
+ if (pp[2] > maxb)
+ maxb = pp[2];
+ if (pp[2] < minb)
+ minb = pp[2];
+ }
+ /* Move center to centroid of min/max box */
+ t1[0] = 0.0;
+ t1[1] = (maxa + mina) * 0.5;
+ t1[2] = (maxb + minb) * 0.5;
+ if (t1[1] < -200.0 || t1[1] > 200.0
+ || t1[2] < -200.0 || t1[2] > 200.0)
+ error("Failed to locate centroid of slice");
+ icmMul3By3x4(cpoint, mat, t1);
+
+//printf("~1 ring centroid point = %f %f %f\n", cpoint[0],cpoint[1],cpoint[2]);
+
+ /* Recompute the rotation and translation between */
+ /* a plane in ab and the plane we are using */
+ s0[0] = s0[1] = s0[2] = 0.0;
+ s1[0] = 1.0, s1[1] = s1[2] = 0.0;
+ t1[0] = cpoint[0] + rings[i].pnorm[0];
+ t1[1] = cpoint[1] + rings[i].pnorm[1];
+ t1[2] = cpoint[2] + rings[i].pnorm[2];
+ icmVecRotMat(mat, s1, s0, t1, cpoint);
+ icmVecRotMat(imat, t1, cpoint, s1, s0);
+
+//printf("~1 generating %d ring verts\n",rings[i].nverts);
+ /* Create a circle of vectors in the plane from the center */
+ /* point, to intersect with the source gamut surface. */
+ /* (Duplicate start and end vertex) */
+ for (j = 0; j <= rings[i].nverts; j++) {
+ double ang = 2 * 3.1415926 * j/((double) rings[i].nverts);
+ double vec[3], isect[3];
+ double pp[3];
+ co cp;
+ int k;
+
+ vec[0] = 0.0;
+ vec[1] = sin(ang);
+ vec[2] = cos(ang);
+ icmMul3By3x4(vec, mat, vec);
+
+ /* Intersect it with the source gamut */
+ if (si_gam->vector_isect(si_gam, vec, cpoint, isect,
+ NULL, NULL, NULL, NULL, NULL) == 0) {
+ warning("Ring %d vect %d diagnostic vector intersect failed",i,j);
+ continue;
+ }
+
+//printf("~1 vec %d = %f %f %f\n",j,isect[0],isect[1],isect[2]);
+
+ /* Scale them to the ratio */
+ for (k = 0; k < 3; k++)
+ vec[k] = isect[k] * rings[i].rad + (1.0 - rings[i].rad) * cpoint[k];
+
+//printf("~1 rad vec %d = %f %f %f\n",j,vec[0],vec[1],vec[2]);
+
+ /* Transform them into rotated and scaled destination space */
+ dopartialmap1(s, vec, vec);
+//printf("~1 trans vec %d = %f %f %f\n",j,vec[0],vec[1],vec[2]);
+
+ /* Add to plot */
+ wrl->add_col_vertex(wrl, 1, vec, rings[i].scol);
+//printf("~1 src vec %d = %f %f %f\n",j,vec[0],vec[1],vec[2]);
+
+ /* Gamut map and add to plot */
+ s->domap(s, vec, vec);
+//printf("~1 dst vec %d = %f %f %f\n",j,vec[0],vec[1],vec[2]);
+ wrl->add_col_vertex(wrl, 2, vec, rings[i].dcol);
+ }
+ wrl->make_last_vertex(wrl, 1); /* Source ring */
+ wrl->make_last_vertex(wrl, 2); /* Destination ring */
+ }
+ if (arerings) {
+ wrl->make_lines(wrl, 1, 1000000); /* Source ring */
+ wrl->make_lines(wrl, 2, 1000000); /* Destination ring */
+ }
+ }
+
+ wrl->del(wrl); /* Write and delete */
+ wrl = NULL;
+ }
+
+#ifdef PLOT_3DKNEES
+ /* Plot one graph per 3D gamut boundary mapping point */
+ for (j = 0; j < p3dk_ix; j++) {
+ double xx[XRES];
+ double yy[XRES];
+
+ printf("Vector %f %f %f -> %f %f %f\n", p3dk_locus[j].v0[0], p3dk_locus[j].v0[1], p3dk_locus[j].v0[2], p3dk_locus[j].v1[0], p3dk_locus[j].v1[1], p3dk_locus[j].v1[2]);
+
+ for (i = 0; i < XRES; i++) {
+ double v;
+ co cp; /* Conversion point */
+ v = (i/(double)(XRES-1.0));
+ cp.p[0] = p3dk_locus[j].v0[0] + v * (p3dk_locus[j].v1[0] - p3dk_locus[j].v0[0]);
+ cp.p[1] = p3dk_locus[j].v0[1] + v * (p3dk_locus[j].v1[1] - p3dk_locus[j].v0[1]);
+ cp.p[2] = p3dk_locus[j].v0[2] + v * (p3dk_locus[j].v1[2] - p3dk_locus[j].v0[2]);
+ xx[i] = sqrt(cp.p[1] * cp.p[1] + cp.p[2] * cp.p[2]);
+ s->map->interp(s->map, &cp);
+ yy[i] = sqrt(cp.v[1] * cp.v[1] + cp.v[2] * cp.v[2]);
+ }
+ do_plot(xx,yy,NULL,NULL,XRES);
+ }
+ free(p3dk_locus);
+#endif /* PLOT_3DKNEES */
+
+
+ free(gpnts);
+ free_nearsmth(nsm, nnsm);
+
+ } else if (diagname != NULL && verb) {
+ printf("Warning: Won't create '%s' because there is no 3D gamut mapping\n",diagname);
+ }
+
+#ifdef PLOT_GAMUTS
+ scl_gam->write_vrml(scl_gam, "src.wrl", 1, 0);
+ sil_gam->write_vrml(sil_gam, "img.wrl", 1, 0);
+ d_gam->write_vrml(d_gam, "dst.wrl", 1, 0);
+ sc_gam->write_trans_vrml(sc_gam, "gmsrc.wrl", 1, 0, map_trans, s);
+#endif
+
+ if (sil_gam != scl_gam)
+ sil_gam->del(sil_gam);
+ scl_gam->del(scl_gam);
+
+ return s;
+}
+
+#ifdef PLOT_GAMUTS
+
+/* Debug */
+static void map_trans(void *cntx, double out[3], double in[3]) {
+ gammap *map = (gammap *)cntx;
+
+ map->domap(map, out, in);
+}
+
+#endif
+
+/* Object methods */
+static void del_gammap(
+gammap *s
+) {
+ if (s->grey != NULL)
+ s->grey->del(s->grey);
+ if (s->igrey != NULL)
+ s->igrey->del(s->igrey);
+ if (s->map != NULL)
+ s->map->del(s->map);
+
+ free(s);
+}
+
+/* Apply the gamut mapping to the given color value */
+static void domap(
+gammap *s,
+double *out,
+double *in
+) {
+ double rin[3];
+ co cp;
+
+ if (s->dbg) printf("domap: got input %f %f %f\n",in[0],in[1],in[2]);
+ icmMul3By3x4(rin, s->grot, in); /* Rotate */
+
+ if (s->dbg) printf("domap: after rotate %f %f %f\n",rin[0],rin[1],rin[2]);
+ cp.p[0] = rin[0];
+ s->grey->interp(s->grey, &cp); /* L map */
+
+ if (s->dbg) printf("domap: after L map %f %f %f\n",cp.v[0],rin[1],rin[2]);
+
+ /* If there is a 3D->3D mapping */
+ if (s->map != NULL) {
+ int e;
+
+ /* Clip out of range a, b proportionately */
+ if (rin[1] < s->imin[1] || rin[1] > s->imax[1]
+ || rin[2] < s->imin[2] || rin[2] > s->imax[2]) {
+ double as = 1.0, bs = 1.0;
+ if (rin[1] < s->imin[1])
+ as = s->imin[1]/rin[1];
+ else if (rin[1] > s->imax[1])
+ as = s->imax[1]/rin[1];
+ if (rin[2] < s->imin[2])
+ bs = s->imin[2]/rin[2];
+ else if (rin[2] > s->imax[2])
+ bs = s->imax[2]/rin[2];
+ if (bs < as)
+ as = bs;
+ rin[1] *= as;
+ rin[2] *= as;
+ }
+
+ cp.p[0] = cp.v[0]; /* 3D map */
+ cp.p[1] = rin[1];
+ cp.p[2] = rin[2];
+ s->map->interp(s->map, &cp);
+
+ for (e = 0; e < s->map->fdi; e++)
+ out[e] = cp.v[e];
+
+ if (s->dbg) printf("domap: after 3D map %s\n\n",icmPdv(s->map->fdi, out));
+ } else {
+ out[0] = cp.v[0];
+ out[1] = rin[1];
+ out[2] = rin[2];
+ }
+}
+
+/* Apply the matrix and grey mapping to the given color value */
+static void dopartialmap1(
+gammap *s,
+double *out,
+double *in
+) {
+ double rin[3];
+ co cp;
+
+ icmMul3By3x4(rin, s->grot, in); /* Rotate */
+ cp.p[0] = rin[0];
+ s->grey->interp(s->grey, &cp); /* L map */
+ out[0] = cp.v[0];
+ out[1] = rin[1];
+ out[2] = rin[2];
+}
+
+/* Apply just the rspl mapping to the given color value */
+/* (ie. to a color already rotated and L mapped) */
+static void dopartialmap2(
+gammap *s,
+double *out,
+double *in
+) {
+ co cp;
+
+ /* If there is a 3D->3D mapping */
+ if (s->map != NULL) {
+ int e;
+
+ icmCpy3(cp.p, in);
+
+ /* Clip out of range a, b proportionately */
+ if (cp.p[1] < s->imin[1] || cp.p[1] > s->imax[1]
+ || cp.p[2] < s->imin[2] || cp.p[2] > s->imax[2]) {
+ double as = 1.0, bs = 1.0;
+ if (cp.p[1] < s->imin[1])
+ as = s->imin[1]/cp.p[1];
+ else if (cp.p[1] > s->imax[1])
+ as = s->imax[1]/cp.p[1];
+ if (cp.p[2] < s->imin[2])
+ bs = s->imin[2]/cp.p[2];
+ else if (cp.p[2] > s->imax[2])
+ bs = s->imax[2]/cp.p[2];
+ if (bs < as)
+ as = bs;
+ cp.p[1] *= as;
+ cp.p[2] *= as;
+ }
+
+ s->map->interp(s->map, &cp);
+
+ icmCpy3(out, cp.v);
+ } else {
+ icmCpy3(out, in);
+ }
+}
+
+/* Function to pass to rspl to invert grey curve */
+static void inv_grey_func(
+ void *cntx,
+ double *out,
+ double *in
+) {
+ rspl *fwd = (rspl *)cntx;
+ int nsoln; /* Number of solutions found */
+ co pp[2]; /* Room for all the solutions found */
+
+ pp[0].p[0] =
+ pp[0].v[0] = in[0];
+
+ nsoln = fwd->rev_interp(
+ fwd,
+ RSPL_NEARCLIP, /* Clip to nearest (faster than vector) */
+ 2, /* Maximum number of solutions allowed for */
+ NULL, /* No auxiliary input targets */
+ NULL, /* Clip vector direction and length */
+ pp); /* Input and output values */
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln != 1)
+ error("gammap: Unexpected failure to find reverse solution for grey axis lookup");
+
+ out[0] = pp[0].p[0];
+}
+
+/* Function to pass to rspl to alter output values, */
+/* to enhance the saturation. */
+static void
+adjust_sat_func(
+ void *pp, /* adjustsat structure */
+ double *out, /* output value to be adjusted */
+ double *in /* corresponding input value */
+) {
+ adjustsat *p = (adjustsat *)pp;
+ double cp[3]; /* Center point */
+ double rr, t1[3], p1;
+ double t2[3], p2;
+
+ /* Locate center point on the white/black axis corresponding to this color */
+ cp[0] = out[0];
+ rr = (out[0] - p->bp[0])/(p->wp[0] - p->bp[0]); /* Relative location on the white/black axis */
+ cp[1] = p->bp[1] + rr * (p->wp[1] - p->bp[1]);
+ cp[2] = p->bp[2] + rr * (p->wp[2] - p->bp[2]);
+
+ /* Locate the point on the destination gamut surface in the direction */
+ /* from the center point to the point being processed. */
+ if (p->dst->vector_isect(p->dst, cp, out, t2, t1, &p2, &p1, NULL, NULL) != 0) {
+
+ if (p1 > 1.0) { /* If this point is within gamut */
+ double ep1, bf;
+
+//printf("\n");
+//printf("~1 cp %f %f %f input %f %f %f\n",cp[0],cp[1],cp[2], out[0], out[1], out[2]);
+//printf("~1 min %f %f %f mint %f\n",t2[0],t2[1],t2[2],p2);
+//printf("~1 max %f %f %f maxt %f\n",t1[0],t1[1],t1[2],p1);
+
+ p1 = 1.0/p1; /* Position of out from cp to t1 */
+
+#ifdef NEVER
+ /* Enhanced parameter value */
+ ep1 = (p1 + p->satenh * p1)/(1.0 + p->satenh * p1);
+ /* Make blend between linear p1 and enhanced p1, */
+ /* to reduce effects on near neutrals. */
+ p1 = (1.0 - p1) * p1 + p1 * ep1;
+#else
+ /* Compute Enhanced p1 */
+ ep1 = (p1 + p->satenh * p1)/(1.0 + p->satenh * p1);
+
+ /* Make blend factor between linear p1 and enhanced p1, */
+ /* to reduce effects on near neutrals. */
+ {
+ double pp = 4.0; /* Sets where the 50% transition is */
+ double g = 2.0; /* Sets rate of transition */
+ double sec, vv = p1;
+
+ vv = vv/(pp - pp * vv + 1.0);
+
+ vv *= 2.0;
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv *= 0.5;
+
+ bf = (vv + pp * vv)/(1.0 + pp * vv);
+ }
+ /* Do the blend */
+ p1 = (1.0 - bf) * p1 + bf * ep1;
+#endif
+ /* Compute enhanced values position */
+ out[0] = cp[0] + (t1[0] - cp[0]) * p1;
+ out[1] = cp[1] + (t1[1] - cp[1]) * p1;
+ out[2] = cp[2] + (t1[2] - cp[2]) * p1;
+//printf("~1 output %f %f %f, param %f\n",out[0],out[1],out[2],p1);
+ }
+ }
+}
+
+/* Function to pass to rspl to re-set output values, */
+/* to adjust the white and black points */
+static void
+adjust_wb_func(
+ void *pp, /* adjustwb structure */
+ double *out, /* output value to be adjusted */
+ double *in /* corresponding input value */
+) {
+ adjustwb *p = (adjustwb *)pp;
+
+ /* Do a linear mapping from swp -> dwp and sbp -> dbp, */
+ /* to compute the adjusted value. */
+ icmMul3By3x4(out, p->mat, out);
+}
+
+
+/* Create a new gamut that the the given gamut transformed by the */
+/* gamut mappings rotation and grey curve mapping. Return NULL on error. */
+static gamut *parttransgamut(gammap *s, gamut *src) {
+ gamut *dst;
+ double cusps[6][3];
+ double wp[3], bp[3], kp[3];
+ double p[3];
+ int i;
+
+ if ((dst = new_gamut(src->getsres(src), src->getisjab(src), src->getisrast(src))) == NULL)
+ return NULL;
+
+ dst->setnofilt(dst);
+
+ /* Translate all the surface nodes */
+ for (i = 0;;) {
+ if ((i = src->getrawvert(src, p, i)) < 0)
+ break;
+
+ dopartialmap1(s, p, p);
+ dst->expand(dst, p);
+ }
+ /* Translate cusps */
+ if (src->getcusps(src, cusps) == 0) {
+ dst->setcusps(dst, 0, NULL);
+ for (i = 0; i < 6; i++) {
+ dopartialmap1(s, p, cusps[i]);
+ dst->setcusps(dst, 1, p);
+ }
+ dst->setcusps(dst, 2, NULL);
+ }
+ /* Translate white and black points */
+ if (src->getwb(src, wp, bp, kp, NULL, NULL, NULL) == 0) {
+ dopartialmap1(s, wp, wp);
+ dopartialmap1(s, bp, bp);
+ dopartialmap1(s, kp, kp);
+ dst->setwb(dst, wp, bp, kp);
+ }
+
+ return dst;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gamut/gammap.h b/gamut/gammap.h
new file mode 100644
index 0000000..b59e821
--- /dev/null
+++ b/gamut/gammap.h
@@ -0,0 +1,68 @@
+#ifndef GAMMAP_H
+#define GAMMAP_H
+
+/*
+ * Argyll Gamut Mapping Library
+ *
+ * Author: Graeme W. Gill
+ * Date: 1/10/2000
+ * Version: 2.00
+ *
+ * Copyright 2000 - 2006 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.
+ */
+
+
+/* Gamut mapping object */
+struct _gammap {
+
+/* Private: */
+ int dbg; /* NZ to turn on debug messages */
+ /* neutral axis alignment transform applied to source: */
+ double grot[3][4]; /* Incoming grey axis rotation matrix */
+ double igrot[3][4]; /* Inverse of above */
+ rspl *grey; /* Forward L map */
+ rspl *igrey; /* Inverse L map */
+ /* Source to destination gamut map applied */
+ /* to transformed source: */
+ rspl *map; /* Rotated, L mapped Lab -> Lab gamut map */
+ double imin[3], imax[3]; /* Input range limits of map */
+
+/* Public: */
+
+ /* Methods */
+ void (*del)(struct _gammap *s); /* Free ourselves */
+ void (*domap)(struct _gammap *s, double *out, double *in); /* Do the mapping */
+
+}; typedef struct _gammap gammap;
+
+/* Method of black point adaptation */
+typedef enum {
+ gmm_BPadpt = 0, /* Adapt source black point to destination */
+ gmm_noBPadpt = 1, /* Don't adapt black point to destination */
+ gmm_bendBP = 2, /* Don't adapt black point, bend it to dest. at end */
+ gmm_clipBP = 3 /* Don't adapt black point, clip it to dest. at end */
+} gmm_BPmap;
+
+/* Creator */
+gammap *new_gammap(
+ int verb, /* Verbose flag */
+ gamut *sc_gam, /* Source colorspace gamut */
+ gamut *s_gam, /* Source image gamut (NULL if none) */
+ gamut *d_gam, /* Destination colorspace gamut */
+ icxGMappingIntent *gmi, /* Gamut mapping specification */
+ int src_kbp, /* Use K only black point as src gamut black point */
+ int dst_kbp, /* Use K only black point as dst gamut black point */
+ int dst_cmymap, /* masks C = 1, M = 2, Y = 4 to force 100% cusp map */
+ int rel_oride, /* 0 = normal, 1 = override min relative, 2 = max relative */
+ int mapres, /* Gamut map resolution, typically 9 - 33 */
+ double *mn, /* If not NULL, set minimum mapping input range */
+ double *mx, /* for rspl grid */
+ char *diagname /* If non-NULL, write a gamut mapping diagnostic WRL */
+);
+
+
+#endif /* GAMMAP_H */
diff --git a/gamut/gammap.txt b/gamut/gammap.txt
new file mode 100644
index 0000000..f751248
--- /dev/null
+++ b/gamut/gammap.txt
@@ -0,0 +1,259 @@
+
+Author: Graeme W. Gill
+Date: 2000/10/28
+Updated: 2006/1/17
+
+Discussion of the gamut mapping algorithm used in Argyll:
+
+
+ Jam Morovic provides an extensive summary of previous Gamut Mapping Algoriths
+ (GMA) in his thesis "To Develop a Universal Gamut Mapping Algorithm".
+
+ Mark Fairchild and Gustav Braun also discuss some interesting aspects of
+ gamut mapping in "General-Purpose Gamut-Mapping Algorithms: Evaluation
+ of Contrast-Preserving Rescaling Functions for Color Gamut Mapping".
+
+ One thing that is striking in reading the current Gamut Mapping
+ literature, is the schism between gamut mapping, and gammut clipping.
+
+ A number of studies have indicated the satisfactory results from performing
+ gamut clipping by mapping out of gamut points to the closest point
+ within gamut, using a minumim delta E criteria. Ideally this would be
+ in a perceptually uniform space, and in practical spaces (ie L*a*b* space),
+ it appears a mapping that weightes luminance errors twice as much as
+ hue and saturation errors is the most satisfactory
+ (ie. Katoh & Ito 1996, Ebner & Fairchild 1997).
+ This approach makes perfect sense if the perceptually linear
+ delta E spaces is working as its should :- providing a means of
+ computing the minimal perceptual error between two colors.
+
+ Almost all the gamut mapping algorithms on the other hand, take a
+ completely different approach. They are dominated by algorithms with
+ appeal for their mathematical and algorithmic simplicity, rather than
+ any objective sense. Clipping along a line of constant hue, in a
+ particular direction, with some sort of compression along line
+ length curve seems to be a favourite.
+ My own experience with such an approach used for gamut clipping
+ shows up the logical flaws in this approach. In printed media, for
+ instance, the yellow dye tends to have a very sharp cusp in (say) Lab
+ space. When mapping along a line towards the neutral axis, it is almost
+ impossible to come up with a choice of line direction that
+ doesn't severly distort the clipped color. It is often extremely
+ de-saturated at the point the line hits the gamut boundary. Line
+ directions that take some account of the equivalent yellow cusp
+ in the target gamut improve the situation, but it seems highly
+ illogical to choosing an algorithm that gives a result with such
+ high delta E's, measured in any colorspace !
+
+ My conclusion is this: If we are working in a good perceptually
+ uniform space (ie. L*a*b*, Luv or CIECAM02), then we want to minimise
+ the delta E of the gamut mapped points at all times (this is the point
+ of using a perceptually uniform space !). This means that points
+ on the source gamut surface, should map to the target surface in
+ a very similar way to which they would be mapped using gamut clipping,
+ ie. minimum delta E. The distinction between gamut mapping and clipping
+ only becomes evident then, when we consider points that fall within
+ both gamuts. For pure gamut clipping, these points should not be
+ modified. For gamut mapping they should be modified in a way that
+ trades off increased absolute delta E, for reduced delta E relative
+ to surrounding colors.
+
+ [ Saturation intent brings some factors other than minimum
+ delta E into the picture, but minumum delta E is a good
+ starting point. ]
+
+ Gamut clipping should not be something separate to gamut mapping,
+ but should just be one extreme in a continuum of gamut mapping
+ choices.
+
+ A consideration revealed by Jam Morovic's work, is that it may be
+ desirable to treat colors on and close to the neutral axis a little
+ differently that those saturated colors near the gamut surface.
+ It seems desirable to align and compress the neutral axis to
+ give a good gray-scale mapping, as well as preserving the
+ relative colorimetry of low saturation colors.
+
+ Mark fairchild's work also indicates the desirablility of
+ trying to maintain the relative contrast of image data after
+ compression. This can be achieved by using a sigmoidal
+ mapping during compression (often called a soft knee compression
+ characteristic), rather than linear compression. Gamut
+ clipping can be considered to be an extreme example of
+ knee compression, where the knee is "hard".
+
+ A final consideration is how the various user intents are going
+ to be accomodated. One of the nice features of a consistent
+ clipping/compression approach is that many of the distinctions
+ between different intents seems to disappear.
+
+ Description of algorithms used:
+
+ The algorithm chosen here is (as far as I am aware) a new one,
+ that tries to combine all the considerations made above.
+
+ The gamut mapping is divided into two parts, mapping the luminance
+ axis orthogonally to other considerations, and then dealling
+ with any remaining gamut compression or expansion.
+
+ The basic transform mechanism is broken down into three part;
+ Aligning the neutral axes, mapping the luminence coordinate,
+ performing an overall 3D -> 3D mapping to compress and/or
+ expand the gamut surface. The rotation uses a matrix, the 1D -> 1D
+ luminence mapping uses a RSPL regular spline that is available
+ in Argyll, and the 3D -> 3D mapping also uses a RSPL.
+ By controlling the number, extent and strength of the sample
+ point mapping used to create the RSPL, it is possible to arrive
+ at a smooth mapping that has (controllable) areas of influence
+ between different regions, and can achieve sigmoid like "soft"
+ clipping curves.
+
+
+ Aligning the neutral axes.
+
+ The first step is to align the neutral axes. If the
+ colorspace used is an appearance space (Such as CIECAM02 Jab),
+ then the white points will already be close together, but may not
+ exactly cooincide. The black points will also probably differ.
+ There are a number of options for dealing with this. One
+ option would be to assume that people adapt to black points
+ the same way they adapt to the white points of a colorspace
+ or image. Research and experiemnce indicates that this
+ 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
+ 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
+ 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
+ to line them up. The minimum J value on the other hand,
+ is mapped as if the black points were being fully
+ adapted to, and at the point that the source
+ neutral axis would leave the destination gamut,
+ it is clipped to the destination.
+
+ This gives a neutral axis in the destination that looks
+ the same as that of the source, while fully exploiting the
+ dynamic range of the destination colorspace. Since
+ the departure of the mapped neutral axis from neutral
+ only occurs in very dark colors, its deviation is not
+ usually visible.
+
+ [ The code allows for 4 possible black point/neutral
+ axis mapping algorithm, set by the value of bph:
+ Adapt source black point to destination, giving full black range.
+ Don't adapt black point to destination, giving compromised black range.
+ Don't adapt black point, bend it to dest. at end, giving full black range.
+ Don't adapt black point, clip it to dest. at end, giving full black range.
+ ]
+
+ Note that the black point mapping is performed by manipulating
+ J independently of the color components (a & b). In adapting
+ color from one space to another, this proves to be the correct
+ approach, maintaining the appearance of an image when
+ transformed to different device colorspaces.
+ This should not be confused with the situation where
+ optical flare or haze is being removed or simulated,
+ in which case the black point mapping should be done in a
+ linear light colorspace (such as XYZ), and will have an
+ effect simulaniously on lightness and saturation.
+
+
+ Mapping the luminence range.
+
+ The luminence mapping is acheived by created a small number of
+ mapping points, and then created a detailed RSPL (Regular Spline)
+ based on the points. The end points (which are heavily weighted
+ to ensure the overall range mapping is useful) are created
+ simply from the known J values of the source and destination
+ white and black points (taking into consuideration what
+ J values will result from possible gamut boundary clipping).
+
+ Middle points are introduced to either give a linear mapping (in J),
+ or to introduce a slight range compression aimed at preserving
+ the contrast ratio of the image.
+
+
+ Maping 3D gamut points.
+
+ The mapping points created for determinining the 3D compression or
+ expansioin are created from the source gamut surface verticies
+ that lie outside the destinatio gamut. The raw mapping for the
+ outside of the gamut is created by itterative optimisation,
+ that strikes a weighted balance between three different
+ factors: Mapping to the closest point on the destination surface,
+ Mapping in a way that is smoothly consistent with neighbour
+ mapping rays, and Mapping radially to the center of the colorspace.
+ By manipulating the weighting factors (held in a gammapweights
+ structure), it is possible to control to some degree the
+ nature of the gamut mapping.
+
+ Some compensation is applied to the vectors to try and counteract
+ the effects of the vector and (subsequent) RSPL smoothing.
+ This smoothing may cause the mapping to end up outside the
+ destination gamut, so we try and make sure that such smoothing
+ effects over rather than under-compress.
+
+ In addition to the suface mapping points, the 1D neutral axis
+ mapping is maintained by introducing a string of points
+ down the 3D neutral axis, to ensure that the 3D surface mappings
+ do not alter it.
+
+ Closer to the surface, optional "knee" mapping points
+ are also added, in an attempt to cause the inner
+ 3D mapping to be more linear, with the compression (or
+ expansion) being concentrated near the surface of the
+ gamuts ("Sigma" compression).
+
+Limitations and future challenges:
+
+ After re-working the gamut mapping in December 2005/January 2006,
+ the following challenges remain:
+
+ 1) For saturation mapping in particular, the handling of hue
+ mapping using the "nearest" weighting isn't very flexible.
+ It's not possible to map RGB Cyan to CMYK Cyan without
+ introducing unacceptable side effects.
+
+ To solve this, I would have to add some extra mapping controls
+ and gamut information. For each gamut the 6 major "cusps" would
+ have to be identified (either directly from the colorant
+ combinations, or indrectly by locating the point on the gamut
+ surface with the largest C (?) in each hextant), and
+ then a means of warping the hue angle (and Luminence ??)
+ in each hextant.
+
+ 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]
+
+
+ 2) There is not much flexibility in what the gammapweights
+ weightings can achive. Some controls simply don't work
+ very well. Often increases in saturation in one area (at
+ the transitions between major colors) are bought at the
+ expense of the middle of the major colors becomming
+ very "flat" and desaturated. This is generally when we
+ are in a region in which the source gamut is within the
+ destination gamut.
+
+ 3) Geting smoothness and saturation is very difficult
+ for some reason. The "relative error" weights do spread
+ things out, but at the cost of obvious banding (why ? -
+ possible answer - reflects the roughness of the gamut surface.
+ Solution is to use better algorithm for gamut surface extraction ?? ).
+ Increasing the 3D RSPL smoothness seems to have no
+ effect (why ?). Reducing absolute chroma weight improves
+ smoothness, but at the cost of reduced saturation and increased
+ lightness.
+
+
+
+
+
diff --git a/gamut/gamut.c b/gamut/gamut.c
new file mode 100644
index 0000000..052b8d8
--- /dev/null
+++ b/gamut/gamut.c
@@ -0,0 +1,7136 @@
+
+/*
+ * gamut
+ *
+ * Gamut support routines.
+ *
+ * Author: Graeme W. Gill
+ * Date: 9/3/2000
+ * Version: 1.00
+ *
+ * Copyright 2000 - 2006 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.
+ */
+
+/*
+ The gamut boundary is comuted using a variation of
+ Jan Morovic's Segment Maximum approach. The variations
+ are:
+
+ The segments are filtered with an adaptive depth structure,
+ so that approximately the same detail is kept on the gamut
+ surface. Multiple direction vectors at each point are retained.
+ The resultant points are used to create the overal convex
+ jull, but in an adaptive, non-linearly scaled radial space,
+ that allows for convexity in the PCS result.
+*/
+
+/* TTBD:
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include "icc.h"
+#include "numlib.h"
+#include "vrml.h"
+#include "gamut.h"
+#include "cgats.h"
+#include "sort.h" /* ../h sort macro */
+#include "counters.h" /* ../h counter macros */
+#include "xlist.h" /* ../h expandable list macros */
+
+#define COLORED_VRML
+
+#define DO_TWOPASS /* Second pass with adjustment based on first pass */
+
+#define FAKE_SEED_SIZE 0.1 /* Usually 0.1 */
+#define TRIANG_TOL 1e-10 /* Triangulation tollerance, usually 1e-10 */
+
+#define NORM_LOG_POW 0.25 /* Normal, colorspace lopow value */
+#define RAST_LOG_POW 0.05 /* Raster lopow value */
+
+#undef TEST_CONVEX_HULL /* Use pure convex hull, not log hull */
+
+#undef DEBUG_TRIANG /* Enable detailed triangulation debugging */
+#undef DEBUG_TRIANG_VRML /* Create debug.wrl for each step of triangulation */
+ /* (Only on second pass if #define DO_TWOPASS) */
+#undef DEBUG_TRIANG_VRML_STEP /* Wait for return after each step */
+
+#undef DEBUG_SPLIT_VRML /* Create debug.wrl for each step of triangle plane split */
+
+#undef TEST_LOOKUP
+#undef TEST_NEAREST
+#undef TEST_NOSORT /* Turn off sorted insersion of verticies */
+
+#undef SHOW_BUCKETS /* Show vertex buckets as surface */
+#undef SHOW_SPHERE /* Show surface on sphere */
+#undef SHOW_HULL_PNTS /* Show log() length convex hull points */
+
+#undef ASSERTS /* Do internal checking */
+
+#undef INTERSECT_DEBUG /* Turn on compute_vector_isect debugging, inc isect.wrl plot */
+#undef INTERSECT_VERIFY /* Verify compute_vector_isect against brute force search */
+
+/* These routines support:
+
+ representing the 3D gamut boundary of a device or image as
+ radial surface height, described by a triangular poligon hull.
+
+ Interogate the surface to find the point lying on the hull
+ in the same radial direction as the query point.
+
+ Interogate the surface to find the point lying on the hull
+ that is the closest to the query point.
+
+ Save the gamut as a vrml format viewable file.
+ Save the gamut as a CGATS format .gam file.
+
+ */
+
+/* TTBD:
+ *
+ * Would be nice to take the exact colorspace specification
+ * (ie. Lab vs. Jab + viewing conditions), and store them
+ * in the .gam file, so that a warning can be issued if
+ * the gamut colorspace is a mismatch in icclink, or to be able
+ * to translate the verticies into the correct colorespace.
+ *
+ * Add interface to transform all the nodes, while
+ * keeping structure (For use within gamut map, or
+ * transforming existing gamut from Lab to Jab etc.)
+ *
+ * Add inteface to fetch the triangle information ?
+ *
+ * Need to cleanup error handling. We just exit() at the moment.
+ *
+ * Replace BSP tree optmisation with ball tree, to speedup
+ * radial, nearest, and vector search ?
+ *
+ * The log surface stuff is a compromise, that ends up with
+ * some dings and nicks, and a not fully detailed/smooth surface.
+ * The fundamental limitation is the use of the Delaunay triangulation
+ * criteria, and the triangulation algorithm dependence on it for consistency.
+ * Want to switch to triangulation algorithm that doesn't
+ * depend on this, and can triangulate concave objects,
+ * so that something like alpha-shapes criteria can be
+ * used to filter out non surface points. Inserting verticies
+ * from largest radius to smallest seems to do the right thing
+ * with cusp ridges, and this property needs to be retained.
+ *
+ */
+
+
+#ifndef M_PI
+#define M_PI (3.1415926535897932384626433832795)
+#endif
+
+static void triangulate(gamut *s);
+static void del_gamut(gamut *s);
+static gvert *expand_gamut(gamut *s, double in[3]);
+static double getsres(gamut *s);
+static int getisjab(gamut *s);
+static int getisrast(gamut *s);
+static void setnofilt(gamut *s);
+static void getcent(gamut *s, double *cent);
+static void getrange(gamut *s, double *min, double *max);
+static int compatible(gamut *s, gamut *t);
+static int nrawverts(gamut *s);
+static int getrawvert(gamut *s, double pos[3], int ix);
+static int nraw0verts(gamut *s);
+static int getraw0vert(gamut *s, double pos[3], int ix);
+static int nverts(gamut *s);
+static int getvert(gamut *s, double *rad, double pos[3], int ix);
+static int nssverts(gamut *s, double xvra);
+static int getssvert(gamut *s, double *rad, double pos[3], double norm[3], int ix);
+static void startnexttri(gamut *s);
+static int getnexttri(gamut *s, int v[3]);
+static double volume(gamut *s);
+static int write_trans_vrml(gamut *s, char *filename, int doaxes, int docusps,
+ void (*transform)(void *cntx, double out[3], double in[3]), void *cntx);
+static int write_vrml(gamut *s, char *filename, int doaxes, int docusps);
+static int write_gam(gamut *s, char *filename);
+static int read_gam(gamut *s, char *filename);
+static double radial(gamut *s, double out[3], double in[3]);
+static double nradial(gamut *s, double out[3], double in[3]);
+static void nearest(gamut *s, double out[3], double in[3]);
+static void nearest_tri(gamut *s, double out[3], double in[3], gtri **ctri);
+static void setwb(gamut *s, double *wp, double *bp, double *kp);
+static int getwb(gamut *s, double *cswp, double *csbp, double *cskp, double *gawp, double *gabp, double *gakp);
+static void setcusps(gamut *s, int flag, double in[3]);
+static int getcusps(gamut *s, double cusps[6][3]);
+static int compute_vector_isect(gamut *s, double *p1, double *p2, double *min, double *max,
+ double *mint, double *maxt, gtri **mntri, gtri **mxtri);
+static int compute_vector_isectns(gamut *s, double *p1, double *p2, gispnt *lp, int ll);
+static double log_scale(gamut *s, double ss);
+static int intersect(gamut *s, gamut *s1, gamut *s2);
+static int compdstgamut(gamut *s, gamut *img, gamut *src, gamut *dst, int docomp, int doexp,
+ gamut *nedst, void (*cvect)(void *cntx, double *vec, double *pos), void *cntx);
+static int vect_intersect(gamut *s, double *rvp, double *ip, double *p1, double *p2, gtri *t);
+
+/* in isecvol.c: */
+extern double isect_volume(gamut *s1, gamut *s2);
+
+/* ------------------------------------ */
+
+/* Generic hue directions in degrees for Lab and Jab */
+/* Must be in increasing order */
+double gam_hues[2][7] = {
+ {
+ /* Lab */
+ 36.0, /* Red */
+ 101.0, /* Yellow */
+ 149.0, /* Green */
+ 225.0, /* Cyan */
+ 300.0, /* Blue */
+ 337.0, /* Magenta */
+ 36.0 + 360.0 /* Red */
+ },
+ {
+ /* Jab */
+ 28.0, /* Red */
+ 101.0, /* Yellow */
+ 148.0, /* Green */
+ 211.0, /* Cyan */
+// 269.0, /* Blue */
+ 250.0, /* Blue */
+ 346.0, /* Magenta */
+ 28.0 + 360.0 /* Red */
+ }
+};
+
+
+/* ------------------------------------ */
+static
+gvert *new_gvert(
+gamut *s,
+gquad *p, /* Parent quad (may be NULL) */
+int i, /* Intended node in quad */
+int f, /* Flag value to be OR'ed */
+double pp[3], /* Point in xyz rectangular coordinates, absolute */
+double rr[3], /* Radial coordinates */
+double lrr0, /* log scaled rr[0] */
+double sp[3], /* Point mapped to surface of unit sphere, relative to center */
+double ch[3] /* Point mapped for convex hull testing, relative to center */
+) {
+ gvert *v;
+
+ if (s->doingfake == 0 && s->ul != NULL) { /* There is an unused one available */
+ v = s->ul;
+ s->ul = v->ul;
+
+ } else { /* Allocate a new one */
+
+ if (s->nv >= s->na) { /* We need a new slot in the list */
+ if (s->na == 0) {
+ s->na = 5;
+ if ((s->verts = (gvert **)malloc(s->na * sizeof(gvert *))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed on %d gvert pointer\n",s->na);
+ exit (-1);
+ }
+ } else {
+ s->na *= 2;
+ if ((s->verts = (gvert **)realloc(s->verts, s->na * sizeof(gvert *))) == NULL) {
+ fprintf(stderr,"gamut: realloc failed on %d gvert pointer\n",s->na);
+ exit (-1);
+ }
+ }
+ }
+
+ if ((v = (gvert *)calloc(1, sizeof(gvert))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed on gvert object\n");
+ exit (-1);
+ }
+ s->verts[s->nv] = v;
+ v->n = s->nv++;
+ }
+ v->tag = 1;
+
+ if (p != NULL) {
+ v->w = 0.5 * p->w;
+ v->h = 0.5 * p->h;
+
+ v->hc = p->hc;
+ if (i & 1)
+ v->hc += 0.5 * v->w;
+ else
+ v->hc -= 0.5 * v->w;
+
+ v->vc = p->vc;
+ if (i & 2)
+ v->vc += 0.5 * v->h;
+ else
+ v->vc -= 0.5 * v->h;
+ } else {
+ v->w = 0.0;
+ v->h = 0.0;
+ v->hc = 0.0;
+ v->vc = 0.0;
+ }
+
+ v->f = GVERT_NONE | f;
+ v->ul = NULL;
+ v->rc = 1;
+
+ v->p[0] = pp[0];
+ v->p[1] = pp[1];
+ v->p[2] = pp[2];
+ v->r[0] = rr[0];
+ v->r[1] = rr[1];
+ v->r[2] = rr[2];
+ v->lr0 = lrr0;
+ v->sp[0] = sp[0];
+ v->sp[1] = sp[1];
+ v->sp[2] = sp[2];
+ v->ch[0] = ch[0];
+ v->ch[1] = ch[1];
+ v->ch[2] = ch[2];
+
+ return v;
+}
+
+/* Set the size of gvert angular segment */
+static
+void set_gvert(
+gvert *v, /* gvert to set */
+gquad *p, /* Parent quad */
+int i /* Intended node in quad */
+) {
+ v->w = 0.5 * p->w;
+ v->h = 0.5 * p->h;
+
+ v->hc = p->hc;
+ if (i & 1)
+ v->hc += 0.5 * v->w;
+ else
+ v->hc -= 0.5 * v->w;
+
+ v->vc = p->vc;
+ if (i & 2)
+ v->vc += 0.5 * v->h;
+ else
+ v->vc -= 0.5 * v->h;
+}
+
+/* Increment the reference count on a gvert */
+static gvert *inc_gvert(gamut *s, gvert *v) {
+ if (v == NULL)
+ return v;
+ v->rc++;
+//printf("~1 incremented count on 0x%x to %d\n",v,v->rc);
+ return v;
+}
+
+/* Decrement the reference count on a gvert */
+/* Copes with NULL gvert. */
+/* If the reference count goes to 0, place the */
+/* vert on the unused list. */
+static void dec_gvert(gamut *s, gvert *v) {
+ if (v == NULL)
+ return;
+
+ v->rc--;
+//printf("~1 decremended count on 0x%x to %d\n",v,v->rc);
+
+#ifdef ASSERTS
+ if (v->tag != 1)
+ error("Assert: doing decremented on gquad node");
+
+ if (v->rc < 0)
+ error("Assert: decremented gvert ref count too far");
+#endif
+
+ if (v->rc <= 0) { /* Add it to the unused list */
+ memset((void *)v, 0, sizeof(gvert));
+ v->ul = s->ul;
+ s->ul = v;
+ }
+}
+
+/* Delete all the gverts */
+static void del_gverts(gamut *s) {
+ int i;
+ for (i = 0; i < s->nv; i++) {
+ free(s->verts[i]);
+ }
+ if (s->verts != NULL) {
+ free(s->verts);
+ s->na = 0;
+ s->nv = 0;
+ }
+}
+
+/* ------------------------------------ */
+
+static
+gquad *new_gquad(
+gquad *p, /* Parent quad */
+int i /* Intended node in quad */
+) {
+ gquad *q;
+ if ((q = (gquad *)calloc(1, sizeof(gquad))) == NULL) {
+ fprintf(stderr,"gamut: calloc failed on gquad object\n");
+ exit (-1);
+ }
+ q->tag = 2;
+
+ q->w = 0.5 * p->w;
+ q->h = 0.5 * p->h;
+
+ q->hc = p->hc;
+ if (i & 1)
+ q->hc += 0.5 * q->w;
+ else
+ q->hc -= 0.5 * q->w;
+
+ q->vc = p->vc;
+ if (i & 2)
+ q->vc += 0.5 * q->h;
+ else
+ q->vc -= 0.5 * q->h;
+
+ return q;
+}
+
+/* Same as above, but create with explicit size */
+static
+gquad *new_gquad2(
+double l, /* Left border */
+double r, /* Right border */
+double b, /* Top border */
+double t /* Bottom border */
+) {
+ gquad *q;
+ if ((q = (gquad *)calloc(1, sizeof(gquad))) == NULL) {
+ fprintf(stderr,"gamut: calloc failed on gquad object\n");
+ exit (-1);
+ }
+ q->tag = 2;
+ q->w = r - l;
+ q->h = t - b;
+ q->hc = (l + r) * 0.5;
+ q->vc = (t + b) * 0.5;
+ return q;
+}
+
+static void
+del_gquad(gquad *q) {
+ int i;
+
+ if (q == NULL)
+ return;
+ for (i = 0; i < 4; i++) {
+ gnode *n = (gnode *)q->qt[i][0];
+ if (n != NULL && n->tag == 2)
+ del_gquad((gquad *)n); /* Recurse */
+ }
+ free(q);
+}
+
+/* Helper functions */
+
+/* Given a gquad and a location, decide which quandrant we're in */
+static int gquad_quadrant(gquad *q, double p[3]) {
+ int i;
+
+#ifdef ASSERTS
+ if (p[1] < (q->hc - q->w * 0.5 - 1e-10)
+ || p[1] > (q->hc + q->w * 0.5 + 1e-10)
+ || p[2] < (q->vc - q->h * 0.5 - 1e-10)
+ || p[2] > (q->vc + q->h * 0.5 + 1e-10)) {
+ fprintf(stderr,"error! point doesn't fall into bucket chosen for it!!!\n");
+ fprintf(stderr,"point x: %f < %f\n", p[1], (q->hc - q->w * 0.5));
+ fprintf(stderr,"point x: %f > %f\n", p[1], (q->hc + q->w * 0.5));
+ fprintf(stderr,"point y: %f < %f\n", p[2], (q->vc - q->h * 0.5));
+ fprintf(stderr,"point y: %f > %f\n", p[2], (q->vc + q->h * 0.5));
+ exit(-1);
+ }
+#endif
+
+ i = 0;
+ if (p[1] >= q->hc)
+ i |= 1;
+ if (p[2] >= q->vc)
+ i |= 2;
+
+ return i;
+}
+
+/* ------------------------------------ */
+/* Allocate a BSP decision node structure */
+gbspn *new_gbspn(void) {
+ gbspn *t;
+ static int n = 0; /* Serial number */
+ if ((t = (gbspn *) calloc(1, sizeof(gbspn))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed - bspn node\n");
+ exit(-1);
+ }
+ t->tag = 1; /* bspn decision node */
+ t->n = n++;
+
+ return t;
+}
+
+/* Delete a BSP decision node struture */
+void del_gbspn(gbspn *t) {
+ free(t);
+}
+
+/* ------------------------------------ */
+/* Allocate a BSP tree triangle list node structure */
+gbspl *new_gbspl(
+int nt, /* Number of triangles in the list */
+gtri **t /* List of triangles to copy into structure */
+) {
+ gbspl *l;
+ int i;
+ static int n = 0; /* Serial number */
+ if ((l = (gbspl *) calloc(1, sizeof(gbspl) + nt * sizeof(gtri *))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed - bspl triangle tree node\n");
+ exit(-1);
+ }
+ l->tag = 3; /* bspl triangle list node */
+ l->n = n++;
+ l->nt = nt;
+ for (i = 0; i < nt; i++)
+ l->t[i] = t[i];
+
+ return l;
+}
+
+/* Delete a BSP tree triangle list structure */
+void del_gbspl(gbspl *l) {
+ free(l);
+}
+
+/* ------------------------------------ */
+/* Allocate a triangle structure */
+gtri *new_gtri(void) {
+ gtri *t;
+ static int n = 0; /* Serial number */
+ if ((t = (gtri *) calloc(1, sizeof(gtri))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed - gamut surface triangle\n");
+ exit(-1);
+ }
+ t->tag = 2; /* Triangle */
+ t->n = n++;
+
+ return t;
+}
+
+/* Delete a triangle struture */
+void del_gtri(gtri *t) {
+ free(t);
+}
+
+/* ------------------------------------ */
+/* Allocate an edge structure */
+gedge *new_gedge(void) {
+ gedge *t;
+ static int n = 0; /* Serial number */
+ if ((t = (gedge *) calloc(1, sizeof(gedge))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed - triangle edge\n");
+ exit(-1);
+ }
+ t->n = n++;
+ return t;
+}
+
+/* Delete an edge struture */
+void del_gedge(gedge *t) {
+ free(t);
+}
+
+/* ------------------------------------ */
+
+/* Create a standard gamut map */
+gamut *new_gamut(
+double sres, /* Resolution (in rect coord units) of surface triangles */
+ /* 0.0 = default */
+int isJab, /* Flag indicating Jab space */
+int isRast /* Flag indicating Raster rather than colorspace */
+) {
+ gamut *s;
+
+#ifdef ASSERTS
+ fprintf(stderr,">>>>>>> ASSERTS ARE COMPILED INTO GAMUT.C <<<<<<<\n");
+#endif /* ASSERTS */
+#ifdef TEST_LOOKUP
+ fprintf(stderr,">>>>>>> TEST_LOOKUP IS COMPILED INTO GAMUT.C <<<<<<<\n");
+#endif
+#ifdef TEST_NEAREST
+ fprintf(stderr,">>>>>>> TEST_NEAREST IS COMPILED INTO GAMUT.C <<<<<<<\n");
+#endif
+#ifdef TEST_NOSORT /* Turn off sorted insersion of verticies */
+ fprintf(stderr,">>>>>>> TEST_NOSORT IS COMPILED INTO GAMUT.C <<<<<<<\n");
+#endif
+#ifdef INTERSECT_VERIFY
+ fprintf(stderr,">>>>>>> INTERSECT_VERIFY IS COMPILED INTO GAMUT.C <<<<<<<\n");
+#endif
+
+ if ((s = (gamut *)calloc(1, sizeof(gamut))) == NULL) {
+ fprintf(stderr,"gamut: calloc failed on gamut object\n");
+ exit (-1);
+ }
+
+ if (sres <= 0.0)
+ sres = 10.0; /* default */
+ if (sres > 15.0) /* Anything less is very poor */
+ sres = 15.0;
+ s->sres = sres;
+
+ if (isJab != 0) {
+ s->isJab = 1;
+ }
+
+ if (isRast != 0) {
+ s->isRast = 1;
+ }
+
+ if (s->isRast) {
+ s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
+ s->no2pass = 1; /* Only do one pass */
+ } else {
+ s->logpow = NORM_LOG_POW; /* Convex hull compression power */
+ s->no2pass = 0; /* Do two passes */
+ }
+
+ /* Center point for radial values, surface creation etc. */
+ /* To compare two gamuts using radial values, their cent must */
+ /* be the same. */
+ s->cent[0] = 50.0;
+ s->cent[1] = 0.0;
+ s->cent[2] = 0.0;
+
+ s->mx[0] = -1e38;
+ s->mx[1] = -1e38;
+ s->mx[2] = -1e38;
+ s->mn[0] = 1e38;
+ s->mn[1] = 1e38;
+ s->mn[2] = 1e38;
+
+ /* Create top level quadtree nodes */
+ s->tl = new_gquad2(-M_PI, 0.0, -M_PI/2.0, M_PI/2.0); /* Left one */
+ s->tr = new_gquad2(0.0, M_PI, -M_PI/2.0, M_PI/2.0); /* Right one */
+
+ INIT_LIST(s->tris); /* Init triangle list */
+ INIT_LIST(s->edges); /* Init edge list (?) */
+ s->read_inited = 0;
+ s->lu_inited = 0;
+ s->ne_inited = 0;
+ s->cswbset = 0;
+ s->gawbset = 0;
+
+ /* Setup methods */
+ s->del = del_gamut;
+ s->expand = expand_gamut;
+ s->getsres = getsres;
+ s->getisjab = getisjab;
+ s->getisrast = getisrast;
+ s->setnofilt = setnofilt;
+ s->getcent = getcent;
+ s->getrange = getrange;
+ s->compatible = compatible;
+ s->nrawverts = nrawverts;
+ s->getrawvert = getrawvert;
+ s->nraw0verts = nraw0verts;
+ s->getraw0vert = getraw0vert;
+ s->nssverts = nssverts;
+ s->getssvert = getssvert;
+ s->nverts = nverts;
+ s->getvert = getvert;
+ s->startnexttri = startnexttri;
+ s->getnexttri = getnexttri;
+ s->getvert = getvert;
+ s->volume = volume;
+ s->intersect = intersect;
+ s->compdstgamut = compdstgamut;
+ s->radial = radial;
+ s->nradial = nradial;
+ s->nearest = nearest;
+ s->nearest_tri = nearest_tri;
+ s->vector_isect = compute_vector_isect;
+ s->vector_isectns = compute_vector_isectns;
+ s->setwb = setwb;
+ s->getwb = getwb;
+ s->setcusps = setcusps;
+ s->getcusps = getcusps;
+ s->write_vrml = write_vrml;
+ s->write_trans_vrml = write_trans_vrml;
+ s->write_gam = write_gam;
+ s->read_gam = read_gam;
+
+ return s;
+}
+
+static void del_gnn(gnn *p);
+static void del_gbsp(gbsp *n);
+
+/* Free and clear the triangulation structures, */
+/* and clear the triangulation vertex flags. */
+static void del_triang(gamut *s) {
+ int i;
+ gtri *tp; /* Triangle pointer */
+ gedge *ep;
+
+ /* Recursively free radial lookup acceleration structures */
+ /* Do this before we delete triangles, because there may */
+ /* be triangles in the tree. */
+ if (s->lutree != NULL) {
+ del_gbsp(s->lutree);
+ s->lutree = NULL;
+ }
+
+ if (s->tris != NULL) {
+ tp = s->tris; /* Delete all the triangles */
+ FOR_ALL_ITEMS(gtri, tp) {
+ DEL_LINK(s->tris, tp);
+ del_gtri(tp);
+ } END_FOR_ALL_ITEMS(tp);
+
+ INIT_LIST(s->tris); /* Init triangle list */
+ }
+
+ if (s->edges != NULL) {
+ ep = s->edges; /* Delete all the edges */
+ FOR_ALL_ITEMS(gedge, ep) {
+ DEL_LINK(s->edges, ep);
+ del_gedge(ep);
+ } END_FOR_ALL_ITEMS(ep);
+ INIT_LIST(s->edges); /* Init edge list */
+ }
+
+ s->lu_inited = 0;
+
+ if (s->nns != NULL) {
+ del_gnn(s->nns);
+ s->nns = NULL;
+ }
+ s->ne_inited = 0;
+
+ /* Reset the vertex flags triangulation changes */
+ for (i = 0; i < s->nv; i++) {
+ s->verts[i]->f &= ~GVERT_TRI;
+ s->verts[i]->f &= ~GVERT_INSIDE;
+ }
+}
+
+static void
+del_gamut(gamut *s) {
+ del_gquad(s->tl);
+ del_gquad(s->tr);
+
+ del_triang(s);
+ del_gverts(s);
+
+ if (s->ss != NULL)
+ s->ss->del(s->ss);
+
+ free(s);
+}
+
+/* ===================================================== */
+/* Segmented maxima filter code */
+/* ===================================================== */
+
+/*
+ This implementation has two twists on the usual
+ segmented maxima filtering:
+
+ * Rather than using a uniform radial grid, it
+ uses an adaptive, quadtree structure, so that
+ rather than having a constant angular resolution
+ for the segments, the sements are chosen so as to
+ aproximately correspond to a constant surface detail
+ level. [ A subtle problem with this approach is that
+ some points will be discarded early on, that wouldn't
+ be discarded later, when the quadtree is finer. A hack
+ is to run the points throught twice.]
+
+ * Rather than keep the single sample with the
+ largest radius in each radial segment,
+ four samples are kept, each being the largest
+ in a different direction. This helps avoid
+ "knicks" in edges, where a non edge sample
+ displaces an edge sample within a segment.
+
+ */
+
+/* Helper function that returns nz if v1 should replace v2 */
+static int smreplace(
+gamut *s,
+int d, /* Slot number */
+gvert *v1, /* Candidate vertex */
+gvert *v2 /* Existing vertex */
+) {
+ double xx, w[3], c[3];
+ int j;
+ if (v2 == NULL)
+ return 1;
+
+ /* Filter out any points that are almost identical */
+ /* This can cause numerical problems in the triangle BSP tree creation. */
+ for (xx = 0.0, j = 0; j < 3; j++) {
+ double tt = v1->p[j] - v2->p[j];
+ xx += tt * tt;
+ }
+ if (xx < (1e-4 * 1e-4))
+ return 0;
+
+ c[0] = s->cent[0];
+ c[1] = s->cent[1];
+ c[2] = s->cent[2];
+
+ /* Set L, a & b weighting depending on the slot */
+ switch(d) {
+ case 1:
+ w[0] = 0.5;
+ w[1] = 1.0;
+ w[2] = 1.0;
+ break;
+ case 2:
+ w[0] = 2.0;
+ w[1] = 1.0;
+ w[2] = 1.0;
+ break;
+ case 3:
+ w[0] = 4.0;
+ w[1] = 1.0;
+ w[2] = 1.0;
+ break;
+ case 4:
+ w[0] = 0.0;
+ w[1] = 1.0;
+ w[2] = 0.1;
+ break;
+ case 5:
+ w[0] = 0.0;
+ w[1] = 0.1;
+ w[2] = 1.0;
+ break;
+ default:
+ w[0] = 1.0;
+ w[1] = 1.0;
+ w[2] = 1.0;
+ break;
+ }
+ w[0] *= w[0]; /* Because we're weighting the squares */
+ w[1] *= w[1];
+ w[2] *= w[2];
+ return ( w[0] * (v1->p[0] - c[0]) * (v1->p[0] - c[0])
+ + w[1] * (v1->p[1] - c[1]) * (v1->p[1] - c[1])
+ + w[2] * (v1->p[2] - c[2]) * (v1->p[2] - c[2]))
+ > ( w[0] * (v2->p[0] - c[0]) * (v2->p[0] - c[0])
+ + w[1] * (v2->p[1] - c[1]) * (v2->p[1] - c[1])
+ + w[2] * (v2->p[2] - c[2]) * (v2->p[2] - c[2]));
+}
+
+
+/* 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 */
+static gvert *expand_gamut(
+gamut *s,
+double pp[3] /* rectangular coordinate of point */
+) {
+ gnode *n; /* Current node */
+ gvert *nv, *ov; /* new vertex, old vertex */
+ gquad *q; /* Parent quad */
+ int i; /* Sub element within quad */
+ int k; /* Index of direction slot */
+ double rr[3]; /* Radial coordinate version of pp[] */
+ double sp[3]; /* Unit shere mapped version of pp[] relative to center */
+ double ch[3]; /* Convex hull testing mapped version of pp[] relative to center */
+ double lrr0; /* log scaled rr[0] */
+ double hang, vang; /* Critical angles for this points depth */
+ double aa;
+ int j;
+
+ if (s->tris != NULL || s->read_inited || s->lu_inited || s->ne_inited) {
+ fprintf(stderr,"Can't add points to gamut now!\n");
+ exit(-1);
+ }
+
+ if (s->doingfake == 0)
+ s->cu_inited = 0; /* Invalidate cust info */
+
+ /* Tracl bounding range */
+ for (j = 0; j < 3; j++) {
+ if (pp[j] > s->mx[j])
+ s->mx[j] = pp[j];
+ if (pp[j] < s->mn[j])
+ s->mn[j] = pp[j];
+ }
+
+ /* Convert to radial coords */
+ gamut_rect2radial(s, rr, pp);
+
+ if (rr[0] < 1e-6) /* Ignore a point right at the center */
+ return NULL;
+
+ /* Figure log scaled radius */
+ lrr0 = log_scale(s, rr[0]);
+
+ /* Compute unit shere mapped location */
+ aa = 1.0/rr[0]; /* Adjustment to put in on unit sphere */
+ for (j = 0; j < 3; j++)
+ sp[j] = (pp[j] - s->cent[j]) * aa;
+
+ /* Compute hull testing mapped version */
+ for (j = 0; j < 3; j++)
+ ch[j] = sp[j] * lrr0;
+
+ /* compute twice angle resolution required (will compare to parent size) */
+ hang = pow(rr[0], 1.01) * fabs(cos(rr[2]));
+ if (hang < 1e-9)
+ hang = 1e-9;
+ hang = 4.0 * s->sres/hang;
+ vang = 4.0 * s->sres/pow(rr[0], 1.01);
+
+//printf("~1 Point at %f %f %f, radial %f %f %f\n", pp[0], pp[1], pp[2], rr[0], rr[1], rr[2]);
+//printf("~1 shere at %f %f %f, log %f %f %f, vhang %f %f\n", sp[0], sp[1], sp[2], ch[0], ch[1], ch[2], vang, hang);
+
+ /* If nofilter flag is set, add all points as verticies */
+ if (s->nofilter) {
+
+ /* Filter out any points that are almost identical. */
+ /* This can cause numerical problems in the triangle BSP tree creation. */
+ for (i = 0; i < s->nv; i++) {
+ double xx;
+
+ for (xx = 0.0, j = 0; j < 3; j++) {
+ double tt = pp[j] - s->verts[i]->p[j];
+ xx += tt * tt;
+ }
+ if (xx < (1e-4 * 1e-4)) {
+ if (s->doingfake)
+ s->verts[i]->f |= GVERT_ESTP;
+
+ return s->verts[i]; /* Existing point becomes added point */
+ }
+ }
+
+ /* Create a vertex for the point we're possibly adding */
+ nv = new_gvert(s, NULL, 0, GVERT_SET | (s->doingfake ? (GVERT_FAKE | GVERT_ESTP) : 0),
+ pp, rr, lrr0, sp, ch);
+
+ return nv;
+ }
+ /* else filter using adaptive segmented maxima */
+
+ /* Start by looking at the top level quads */
+ if (rr[1] >= 0.0) {
+ q = s->tr;
+ } else {
+ q = s->tl;
+ }
+ n = (gnode *)q;
+//printf("~1 Starting with quad 0x%x, width %f, height %f\n",q, q->w, q->h);
+
+ /* Now recurse until we have a virtex at the right location and depth */
+ for (;;) {
+ /* Recurse into quad node n */
+ q = (gquad *)n; /* Parent node */
+ i = gquad_quadrant(q, rr); /* Quadrand of parent */
+ n = q->qt[i][0]; /* Child node in quadrant */
+
+//printf("~1 Current quad 0x%x, width %f, height %f\n",q, q->w, q->h);
+//printf("~1 Current child in quadrant %d, node 0x%x, type %d\n", i, n, n != NULL ? n->tag : 0);
+
+ /* If we're at the right depth to create a vertex, break out of decent loop. */
+
+ if (n == NULL) { /* Create new node */
+ if (q->w <= hang && q->h <= vang) {
+//printf("~1 We're at the right depth to add vertex\n");
+ break;
+ }
+ /* Else create a new quad */
+ n = (gnode *)new_gquad(q, i);
+ q->qt[i][0] = n;
+//printf("~1 Empty child node not deep enough, creating new quad node 0x%x\n",n);
+
+ /* If we've found verticies at this node */
+ } else if (n->tag == 1) {
+ int j;
+ gquad *qq; /* New child quad */
+ gvert *vv[NSLOTS]; /* Existing verticies at this level */
+
+ if (q->w <= hang && q->h <= vang) {
+//printf("~1 We're at the right depth to replace vertex\n");
+ break;
+ }
+//printf("~1 deepening verticies\n");
+
+ for (k = 0; k < NSLOTS; k++)
+ vv[k] = (gvert *)q->qt[i][k]; /* Save pointers to current verticies */
+
+//printf("~1 existing verticies are 0x%x, 0x%x, 0x%x, 0x%x\n", vv[0], vv[1], vv[2], vv[3]);
+
+ /* make a quad to replace the current verticies */
+ qq = new_gquad(q, i);
+ n = (gnode *)qq;
+ q->qt[i][0] = n;
+ for (k = 1; k < NSLOTS; k++)
+ q->qt[i][k] = NULL;
+
+//printf("~1 added quad 0x%x to quadrant %d\n",i,q);
+
+ /* Distribute verticies that were here, into new quad */
+ for (j = 0; j < NSLOTS; j++) { /* For all existing verticies */
+
+ if (vv[j] == NULL)
+ continue;
+
+//printf("~1 re-distributing verticy 0x%x\n",vv[j]);
+ i = gquad_quadrant(qq, vv[j]->r); /* Quadrant for existing vertex */
+
+ set_gvert(vv[j], qq, i); /* Update vertex node location */
+
+ nv = vv[j];
+ for (k = 0; nv != NULL && k < NSLOTS; k++) { /* For direction slot */
+ ov = (gvert *)qq->qt[i][k];
+ if (smreplace(s, k, nv, ov)) {
+ if (k == 0) { /* Track points that are in k == 0 direction */
+ if (ov != NULL && ov->k0 > 0)
+ ov->k0--;
+ nv->k0++;
+ }
+#ifndef NEVER
+ qq->qt[i][k] = (gnode *)inc_gvert(s, nv);
+ dec_gvert(s, ov);
+#else
+ /* Use slots for best, 2nd best, etc */
+ qq->qt[i][k] = (gnode *)inc_gvert(s, nv);
+ dec_gvert(s, nv);
+ nv = ov;
+#endif
+//printf("Node 0x%x rc %d at %f %f %f is replacing\n",nv, nv->rc, nv->p[0], nv->p[1], nv->p[2]);
+//if (ov != NULL) printf(" replacing node 0x%x rc %d at %f %f %f\n",ov, ov->rc, ov->p[0], ov->p[1], ov->p[2]);
+//else printf(" NULL\n");
+ }
+ }
+ dec_gvert(s, nv);
+ }
+ }
+ /* Else it's a quad, and we will decend into it */
+
+ } /* keep decending until we find right depth */
+
+//printf("~1 Got parent quad 0x%x, quadrant %d, vertex 0x%x\n", q, i, n);
+
+ /* Create a vertex for the point we're possibly adding */
+ nv = new_gvert(s, q, i, GVERT_SET, pp, rr, lrr0, sp, ch);
+
+ /* Replace any existing gverts with this one */
+ for (k = 0; k < NSLOTS; k++) { /* For direction slot */
+ ov = (gvert *)q->qt[i][k];
+ if (smreplace(s, k, nv, ov)) {
+ if (k == 0) { /* Track points that are in k == 0 direction */
+ if (ov != NULL && ov->k0 > 0)
+ ov->k0--;
+ nv->k0++;
+ }
+#ifndef NEVER
+ q->qt[i][k] = (gnode *)inc_gvert(s, nv);
+ dec_gvert(s, ov);
+#else
+ /* Use slots for best, 2nd best, etc */
+ q->qt[i][k] = (gnode *)inc_gvert(s, nv);
+ dec_gvert(s, nv);
+ nv = ov;
+#endif
+ }
+ }
+ dec_gvert(s, nv); /* Make sure it's reclaimed if wasn't used */
+
+//printf("~1 Point is done\n\n");
+
+ return NULL;
+}
+
+/* ------------------------------------ */
+/* Initialise this gamut with the intersection of the */
+/* the two given gamuts. Return NZ on error. */
+/* Return 1 if gamuts are not compatible */
+/* (We assume that the this gamut is currently empty) */
+static int intersect(gamut *s, gamut *sa, gamut *sb) {
+ int i, j, k;
+ gamut *s1, *s2;
+
+ if (sa->compatible(sa, sb) == 0)
+ return 1;
+
+ if IS_LIST_EMPTY(sa->tris)
+ triangulate(sa);
+ if IS_LIST_EMPTY(sb->tris)
+ triangulate(sb);
+
+ s->isJab = sa->isJab;
+
+ if (sa->isRast || sb->isRast)
+ s->isRast = 1;
+
+ for (j = 0; j < 3; j++)
+ s->cent[j] = sa->cent[j];
+
+ /* Clear some flags */
+ s->cswbset = 0;
+ s->cswbset = 0;
+ s->dcuspixs = 0;
+
+ /* If either is a raster gamut, make it a raster gamut */
+ if (s->isRast)
+ s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
+ else
+ s->logpow = NORM_LOG_POW;
+
+ /* Don't filter the points (gives a more accurate result ?) */
+ s->nofilter = 1;
+
+ /* Add each source gamuts verticies that lie within */
+ /* the other gamut */
+ for (k = 0; k < 2; k++) {
+ gtri *tp1, *tp2; /* Triangle pointers */
+
+ if (k == 0) {
+ s1 = sa;
+ s2 = sb;
+ } else {
+ s1 = sb;
+ s2 = sa;
+ }
+ for (i = 0; i < s1->nv; i++) {
+ double pl;
+
+ if (!(s1->verts[i]->f & GVERT_TRI))
+ continue;
+
+ pl = s2->nradial(s2, NULL, s1->verts[i]->p);
+ if (pl <= (1.0 + 1e-9)) {
+ expand_gamut(s, s1->verts[i]->p);
+ s1->verts[i]->f &= ~GVERT_ISOS; /* s1 vert is not outside s2 */
+ } else {
+ s1->verts[i]->f |= GVERT_ISOS; /* s1 vert is outside s2 */
+ }
+ }
+
+ /* Now find the edges that intersect the other gamut */
+ tp1 = s1->tris;
+ FOR_ALL_ITEMS(gtri, tp1) { /* For all s1 triangles */
+
+ for (j = 0; j < 3; j++) { /* For all edges in s1 triangle */
+ /* If edge passes through the other gamut */
+ if ((tp1->e[j]->v[0]->f ^ tp1->e[j]->v[1]->f) & GVERT_ISOS) {
+
+ /* Exhaustive search of other triangles in s2, */
+ /* to find the one that the edge intersects with. */
+ tp2 = s2->tris;
+ FOR_ALL_ITEMS(gtri, tp2) {
+ double pv;
+ double tt[3];
+
+ /* Do a min/max intersection elimination test */
+ for (i = 0; i < 3; i++) {
+ if (tp2->mix[1][i] < tp1->mix[0][i]
+ || tp2->mix[0][i] > tp1->mix[1][i])
+ break; /* min/max don't overlap */
+ }
+ if (i < 3)
+ continue; /* Skip this triangle, it can't intersect */
+
+ if (vect_intersect(s1, &pv, tt, tp1->e[j]->v[0]->p, tp1->e[j]->v[1]->p, tp2)
+ && pv >= (0.0 - 1e-10) && pv <= (1.0 + 1e-10)) {
+ expand_gamut(s, tt);
+ }
+ } END_FOR_ALL_ITEMS(tp2);
+ }
+ }
+
+ } END_FOR_ALL_ITEMS(tp1);
+ }
+
+ s->nofilter = 0;
+
+ return 0;
+}
+
+/* ------------------------------------ */
+/*
+ Initialise this gamut with a destination mapping gamut.
+ s1 is the image gamut (a possible sub-set of the src gamut)
+ s2 is the source gamut
+ s3 is the destination gamut
+
+ if docomp:
+ this gamut will be set to the smaller of the img & dst gamuts
+ else
+ this gamut will be the img gamut
+
+ if doexp
+ this gamut will be expanded by the amount dst is outside the src gamut.
+
+ The vector direction of "inwards" is that returned by the
+ callback function if it is supplied, or radially inwards
+ if it is not.
+
+ Return 1 if gamuts are not compatible.
+ (We assume that the this gamut is currently empty)
+
+ */
+#define MXNIS 40 /* Maximum raw intersections handled */
+
+static int compdstgamut(
+gamut *s, /* This */
+gamut *s1, /* Image gamut, assumed to be a subset of source gamut */
+gamut *s2, /* The source space gamut */
+gamut *s3, /* The destination space gamut */
+int docomp, /* Flag, nz if compression is enabled */
+int doexp, /* Flag, nz if expansion is enabled. */
+gamut *nedst, /* Optional - if doexp, then expand nedst with non-expanded dst gamut */
+void (*cvect)(void *cntx, double *p2, double *p1), /* Compression direction callback */
+void *cntx /* Returns p2 which is in desired direction from given p1 */
+) {
+#ifdef STATS
+ int tedges, edgestested, testhits;
+#endif
+ int i, j, k;
+ gamut *ss[3];
+ gispnt lp1[MXNIS], lp2[MXNIS], lp3[MXNIS]; /* Intersection lists */
+ int ll1, ll2, ll3; /* Returned list length */
+ int ii, jj, kk; /* List indexes */
+
+ if (s1->compatible(s1, s2) == 0
+ || s1->compatible(s2, s3) == 0)
+ return 1;
+
+ if IS_LIST_EMPTY(s1->tris)
+ triangulate(s1);
+ if IS_LIST_EMPTY(s2->tris)
+ triangulate(s2);
+ if IS_LIST_EMPTY(s3->tris)
+ triangulate(s3);
+
+ s->isJab = s1->isJab;
+ s->isRast = s1->isRast;
+
+ for (j = 0; j < 3; j++)
+ s->cent[j] = s1->cent[j];
+
+ /* Clear some flags */
+ s->cswbset = 0;
+ s->cswbset = 0;
+ s->dcuspixs = 0;
+
+ /* If s1 is a raster gamut, make output a raster gamut */
+ if (s->isRast)
+ s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
+ else
+ s->logpow = NORM_LOG_POW;
+
+ /* Don't filter the points (gives a more accurate result ?) */
+ s->nofilter = 1;
+
+ ss[0] = s1;
+ ss[1] = s2;
+ ss[2] = s3;
+
+//printf("~1 compdstgamut docomp %d, doexp %d\n",docomp,doexp);
+ /* Reset the above/below flags */
+ /* 1 = img above dst */
+ /* 2 = img below dst */
+ /* 4 = src above dst */
+ /* 8 = src below dst */
+ for (k = 0; k < 3; k++) { /* For img, src & dst */
+ for (i = 0; i < ss[k]->nv; i++) {
+ if (!(ss[k]->verts[i]->f & GVERT_TRI))
+ continue;
+
+ ss[k]->verts[i]->as = 0;
+ }
+ }
+
+ /* Use all the triangle vertices from the three gamuts */
+ /* as candidate points, because any of them might */
+ /* determine a surface feature. */
+ for (k = 0; k < 3; k++) { /* For img, src & dst */
+
+ for (i = 0; i < ss[k]->nv; i++) {
+ double pp[3], ppv, p2[3];
+ double rr, r4;
+
+ if (!(ss[k]->verts[i]->f & GVERT_TRI))
+ continue;
+
+ icmCpy3(pp, ss[k]->verts[i]->p); /* Point in question */
+
+//printf("\n~1 k %d, point %d: %f %f %f\n", k,i,pp[0],pp[1],pp[2]);
+ if (cvect != NULL)
+ cvect(cntx, p2, pp); /* Get mapping direction */
+ else
+ icmCpy3(p2, ss[k]->cent); /* Radial vector */
+ icmNormalize33(p2, p2, pp, 1.0);
+
+ /* Locate the intersecting segments for each gamut */
+ ll1 = ll2 = ll3 = 0;
+ ll1 = s1->vector_isectns(s1, pp, p2, lp1, MXNIS); /* Image gamut */
+ if (doexp) /* For dst - src expansion */
+ ll2 = s2->vector_isectns(s2, pp, p2, lp2, MXNIS); /* Src gamut */
+ if (docomp || doexp) /* For img ^ dst or dst - src */
+ ll3 = s3->vector_isectns(s3, pp, p2, lp3, MXNIS); /* Dst gamut */
+
+//printf("~1 ll1 %d, ll2 %d, ll3 %d\n",ll1,ll2,ll3);
+#ifdef NEVER
+ printf("img segments:\n");
+ for (ii = 0; ii < ll1; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp1[ii].pv,lp1[ii].dir,lp1[ii].edge,lp1[ii].tri->n);
+ printf("src segments:\n");
+ for (ii = 0; ii < ll2; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp2[ii].pv,lp2[ii].dir,lp2[ii].edge,lp2[ii].tri->n);
+ printf("dst segments:\n");
+ for (ii = 0; ii < ll3; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp3[ii].pv,lp3[ii].dir,lp3[ii].edge,lp3[ii].tri->n);
+#endif
+ /* Now go through each image segment */
+ for (ii = 0; ii < ll1; ii += 2) {
+
+ icmCpy3(pp, lp1[ii].ip);
+ ppv = lp1[ii].pv;
+
+//printf("~1 img pnt at %f\n",lp1[ii].pv);
+ if (docomp) {
+
+ /* Locate a dst segment around or below img point */
+ for (kk = 0; kk < ll3; kk += 2) {
+ if ((lp1[kk+1].pv + 1e-8) >= ppv)
+ break;
+ }
+
+ if (kk >= ll3) { /* No dst segments or none below */
+ ss[k]->verts[i]->as |= 1; /* img above dst */
+//printf("~1 img pnt is outside dst\n");
+ continue;
+ } else {
+//printf("~1 ing %f - %f, dst %f - %f\n", lp1[ii].pv,lp1[ii+1].pv,lp3[kk].pv,lp3[kk+1].pv);
+ /* Use the dst point if it is smaller */
+ if (ppv < lp3[kk].pv) {
+ icmCpy3(pp, lp3[kk].ip);
+ ppv = lp3[kk].pv;
+//printf("~1 dst is smaller %f\n",ppv);
+ ss[k]->verts[i]->as |= 1; /* img above dst */
+ } else {
+//printf("~1 ing is smaller %f\n",ppv);
+ ss[k]->verts[i]->as |= 2; /* img below dst */
+ }
+ }
+ }
+
+ if (nedst != NULL)
+ expand_gamut(nedst, pp);
+
+ while (doexp) {
+ /* Locate a src segment that ing point lies in. */
+ for (jj = 0; jj < ll2; jj += 2) {
+ if (lp1[ii].pv >= (lp2[jj].pv - 1e-8)
+ && lp1[ii].pv <= (lp2[jj+1].pv + 1e-8))
+ break;
+ }
+ if (jj >= ll2) {
+ ss[k]->verts[i]->as |= 4; /* src above dst ?? */
+ break; /* No overlapping segment */
+ }
+
+ /* Locate a dst segment that src point lies in */
+ for (kk = 0; kk < ll3; kk += 2) {
+ if (lp2[jj].pv >= (lp3[kk].pv - 1e-8)
+ && lp2[jj].pv <= (lp3[kk+1].pv + 1e-8))
+ break;
+ }
+ if (kk >= ll2) {
+ ss[k]->verts[i]->as |= 4; /* src above dst ?? */
+ break; /* No overlapping segment */
+ }
+
+ /* if src is outside dst, do nothing */
+ if (lp3[kk].pv >= lp2[jj].pv) {
+ ss[k]->verts[i]->as |= 4; /* src above dst */
+ break;
+ }
+
+ /* Expand point by dst - src */
+ icmAdd3(pp, pp, lp3[kk].ip);
+ icmSub3(pp, pp, lp2[jj].ip);
+ ss[k]->verts[i]->as |= 8; /* src below dst */
+//printf("~1 expanding point by %f - %f\nb",lp3[kk].pv,lp2[jj].pv);
+ break;
+ }
+ expand_gamut(s, pp);
+ }
+ }
+ }
+
+#ifdef STATS
+ tedges = edgestested = testhits = 0;
+#endif
+
+ /* Add any intersection points between img/dst, and src/dst */
+ for (k = 0; k < 4; k++) {
+ int mask;
+ gamut *sa, *sb;
+ gtri *tpa, *tpb; /* Triangle pointers */
+
+ if (k == 0) {
+ if (!docomp)
+ continue;
+ mask = 3;
+ sa = s1; /* img */
+ sb = s3; /* dst */
+ } else if (k == 1) {
+ if (!docomp)
+ continue;
+ mask = 3;
+ sa = s3; /* dst */
+ sb = s1; /* img */
+ } else if (k == 2) {
+ if (!doexp)
+ continue;
+ mask = 12;
+ sa = s2; /* src */
+ sb = s3; /* dst */
+ } else if (k == 3) {
+ if (!doexp)
+ continue;
+ mask = 12;
+ sa = s3; /* dst */
+ sb = s2; /* src */
+ }
+
+ /* Now find the edges that intersect the other gamut */
+ tpa = sa->tris;
+ FOR_ALL_ITEMS(gtri, tpa) {
+
+ for (j = 0; j < 3; j++) { /* For each edge */
+#ifdef STATS
+ tedges++;
+#endif
+ /* If edge disposition flags aren't the same */
+ if ((tpa->e[j]->v[0]->as ^ tpa->e[j]->v[1]->as) & mask
+ || (tpa->e[j]->v[0]->as & mask) == 3 || (tpa->e[j]->v[0]->as & mask) == 12
+ || (tpa->e[j]->v[1]->as & mask) == 3 || (tpa->e[j]->v[1]->as & mask) == 12) {
+#ifdef STATS
+ edgestested++;
+#endif
+ /* Exhaustive search of other triangles */
+ tpb = sb->tris;
+ FOR_ALL_ITEMS(gtri, tpb) {
+ double pv;
+ double pp[3];
+
+ /* Do a min/max intersection elimination test */
+ for (i = 0; i < 3; i++) {
+ if (tpb->mix[1][i] < tpa->mix[0][i]
+ || tpb->mix[0][i] > tpa->mix[1][i])
+ break; /* min/max don't overlap */
+ }
+ if (i < 3)
+ continue; /* Skip this triangle, it can't intersect */
+
+ if (vect_intersect(sa, &pv, pp, tpa->e[j]->v[0]->p, tpa->e[j]->v[1]->p, tpb)
+ && pv >= (0.0 - 1e-10) && pv <= (1.0 + 1e-10)) {
+ /* Process intersection point pp the same as the first loop */
+ double ppv, p2[3];
+ double rr, r4;
+#ifdef STATS
+ testhits++;
+#endif
+//printf("\n~1 tri isxn point %f %f %f\n", pp[0],pp[1],pp[2]);
+ if (cvect != NULL)
+ cvect(cntx, p2, pp); /* Get mapping direction */
+ else
+ icmCpy3(p2, sa->cent); /* Radial vector */
+ icmNormalize33(p2, p2, pp, 1.0);
+
+ /* Locate the intersecting segments for each gamut */
+ ll1 = ll2 = ll3 = 0;
+ ll1 = s1->vector_isectns(s1, pp, p2, lp1, MXNIS); /* Image gamut */
+ if (doexp) /* For dst - src expansion */
+ ll2 = s2->vector_isectns(s2, pp, p2, lp2, MXNIS); /* Src gamut */
+ if (docomp || doexp) /* For img ^ dst or dst - src */
+ ll3 = s3->vector_isectns(s3, pp, p2, lp3, MXNIS); /* Dst gamut */
+
+//printf("~1 ll1 %d, ll2 %d, ll3 %d\n",ll1,ll2,ll3);
+#ifdef NEVER
+ printf("img segments:\n");
+ for (ii = 0; ii < ll1; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp1[ii].pv,lp1[ii].dir,lp1[ii].edge,lp1[ii].tri->n);
+ printf("src segments:\n");
+ for (ii = 0; ii < ll2; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp2[ii].pv,lp2[ii].dir,lp2[ii].edge,lp2[ii].tri->n);
+ printf("dst segments:\n");
+ for (ii = 0; ii < ll3; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp3[ii].pv,lp3[ii].dir,lp3[ii].edge,lp3[ii].tri->n);
+#endif
+ /* Now go through each image segment */
+ for (ii = 0; ii < ll1; ii += 2) {
+
+ icmCpy3(pp, lp1[ii].ip);
+ ppv = lp1[ii].pv;
+
+//printf("~1 img pnt at %f\n",lp1[ii].pv);
+ if (docomp) {
+
+ /* Locate a dst segment around or below img point */
+ for (kk = 0; kk < ll3; kk += 2) {
+ if ((lp1[kk+1].pv + 1e-8) >= ppv)
+ break;
+ }
+
+ if (kk >= ll3) { /* No dst segments or none below */
+//printf("~1 img pnt is outside dst\n");
+ continue;
+ } else {
+//printf("~1 ing %f - %f, dst %f - %f\n", lp1[ii].pv,lp1[ii+1].pv,lp3[kk].pv,lp3[kk+1].pv);
+ /* Use the dst point if it is smaller */
+ if (ppv < lp3[kk].pv) {
+ icmCpy3(pp, lp3[kk].ip);
+ ppv = lp3[kk].pv;
+//printf("~1 dst is smaller %f\n",ppv);
+ } else {
+//printf("~1 ing is smaller %f\n",ppv);
+ }
+ }
+ }
+
+ if (nedst != NULL)
+ expand_gamut(nedst, pp);
+
+ while (doexp) {
+ /* Locate a src segment that ing point lies in */
+ for (jj = 0; jj < ll2; jj += 2) {
+ if (lp1[ii].pv >= (lp2[jj].pv - 1e-8)
+ && lp1[ii].pv <= (lp2[jj+1].pv + 1e-8))
+ break;
+ }
+ if (jj >= ll2) {
+ break; /* No overlapping segment */
+ }
+
+ /* Locate a dst segment that src point lies in */
+ for (kk = 0; kk < ll3; kk += 2) {
+ if (lp2[jj].pv >= (lp3[kk].pv - 1e-8)
+ && lp2[jj].pv <= (lp3[kk+1].pv + 1e-8))
+ break;
+ }
+ if (kk >= ll2) {
+ break; /* No overlapping segment */
+ }
+
+ /* if src is outside dst, do nothing */
+ if (lp3[kk].pv >= lp2[jj].pv) {
+ break;
+ }
+
+ /* Expand point by dst - src */
+ icmAdd3(pp, pp, lp3[kk].ip);
+ icmSub3(pp, pp, lp2[jj].ip);
+//printf("~1 expanding point by %f - %f\nb",lp3[kk].pv,lp2[jj].pv);
+ break;
+ }
+ expand_gamut(s, pp);
+ }
+ }
+ } END_FOR_ALL_ITEMS(tpb);
+ }
+ }
+
+ } END_FOR_ALL_ITEMS(tpa);
+ }
+
+#ifdef STATS
+ printf("Total edges %d, edges tested %d, edge hits %d\n", tedges, edgestested, testhits);
+#endif
+ s->nofilter = 0;
+
+ return 0;
+}
+#undef MXNIS
+
+/* ------------------------------------ */
+/* Locate the vertices most likely to correspond to the */
+/* primary and secondary colors (cusps) */
+/*
+ * Notes:
+ *
+ * To better support gamuts of devices with more than 4 colorants,
+ * it may be necessary to add another flag type that expands
+ * the cusps to lie on the actual gamut surface, as for
+ * some devices this lies outside the pure colorant combinations.
+ *
+ * Flinging a grid of values at this doesn't always
+ * return sensible results. Sometimes two "cusps" might be
+ * unreasonable close to each other (ie. one isn't a real cusp).
+ * This can cause gammut mapping to fail ...
+ *
+ * How could this be made more robust ?
+ *
+ */
+
+static void setcusps(gamut *s, int flag, double in[3]) {
+ int i, j;
+
+ /* - - - - - - - - - - - - - - - - - - - - - - */
+ if (flag == 0) { /* Reset */
+ for (j = 0; j < 6; j++) {
+ s->cusps[j][0] = 0.0; /* Marker values */
+ s->cusps[j][1] = 0.0;
+ s->cusps[j][2] = 0.0;
+ }
+ s->dcuspixs = 0;
+ s->cu_inited = 0;
+ return;
+
+ /* - - - - - - - - - - - - - - - - - - - - - - */
+ } else if (flag == 2) { /* Finalize */
+
+ if (s->dcuspixs > 0) {
+ double JCh[3];
+ double hues[6];
+ int r, br = 0.0;
+ double berr;
+
+ /* Figure out where to put the ones we got */
+ for (j = 0; j < 6; j++) { /* Compute the hues */
+ icmLab2LCh(JCh, s->dcusps[j]);
+ hues[j] = JCh[2];
+ }
+
+ /* Sort them into hue order */
+ for (j = 0; j < 5; j++) {
+ for (i = j+1; i < 6; i++) {
+ if (hues[j] > hues[i]) {
+ double tt;
+ tt = hues[j]; hues[j] = hues[i]; hues[i] = tt;
+ tt = s->dcusps[j][0]; s->dcusps[j][0] = s->dcusps[i][0]; s->dcusps[i][0] = tt;
+ tt = s->dcusps[j][1]; s->dcusps[j][1] = s->dcusps[i][1]; s->dcusps[i][1] = tt;
+ tt = s->dcusps[j][2]; s->dcusps[j][2] = s->dcusps[i][2]; s->dcusps[i][2] = tt;
+ }
+ }
+ }
+
+ /* Figure out which is the best match by rotation */
+ berr = 1e6;
+ for (r = 0; r < 6; r++) {
+ double terr = 0.0;
+ for (j = 0; j < 6; j++) {
+ double tt;
+
+ tt = fabs(gam_hues[s->isJab][j] - hues[(j + r) % 6]);
+ if (tt > 180.0)
+ tt = 360.0 - tt;
+ terr += tt;
+ }
+ if (terr < berr) {
+ br = r;
+ berr = terr;
+ }
+ }
+ /* Place them at that rotation */
+ for (j = 0; j < 6; j++) { /* Compute the hues */
+//printf("~1 placing hue %f ix %d into hue %f ix %d\n", hues[(j + br) % 6],(j + br) % 6, gam_hues[s->isJab][j] ,j);
+
+ s->cusps[j][0] = s->dcusps[(j + br) % 6][0];
+ s->cusps[j][1] = s->dcusps[(j + br) % 6][1];
+ s->cusps[j][2] = s->dcusps[(j + br) % 6][2];
+ }
+ }
+
+ /* Check we've got a cusp */
+ for (j = 0; j < 6; j++) {
+ if (s->cusps[j][0] == 0.0
+ && s->cusps[j][1] == 0.0
+ && s->cusps[j][2] == 0.0) {
+ s->cu_inited = 0;
+ return; /* Not all have been set */
+ }
+ }
+
+ {
+ double JCh[3];
+ double hues[6];
+
+ /* Check how far appart the cusps are in hue angle */
+ // ~~999
+ for (j = 0; j < 6; j++) {
+ icmLab2LCh(JCh, s->cusps[j]);
+ hues[j] = JCh[2];
+//printf("~1 cusp %d = hue %f\n",j,hues[j]);
+ }
+ for (j = 0; j < 6; j++) {
+ int k = j < 5 ? j + 1 : 0;
+ double rh, h;
+ rh = gam_hues[s->isJab][k] - gam_hues[s->isJab][j];
+ if (rh < 0.0)
+ rh = 360 + rh;
+ h = hues[k] - hues[j];
+ if (h < 0.0)
+ h = 360 + h;
+//printf("~1 cusp %d - %d = ref dh %f, dh %f\n",j,k,rh,h);
+
+ /* if our delta is less than half reference, */
+ /* assume the cusps are bad. */
+ if ((2.0 * h) < rh) {
+
+ s->cu_inited = 0; /* Not trustworthy */
+//printf("~1 cusps are not trustworthy\n");
+ return;
+ }
+ }
+ }
+
+ s->cu_inited = 1;
+ return;
+
+ /* - - - - - - - - - - - - - - - - - - - - - - */
+ } else if (flag == 3) { /* Definite 1/6 cusp */
+
+ if (s->dcuspixs >= 6) {
+//printf("~1 too many cusp values added\n");
+ return; /* Error - extra cusp ignored */
+ }
+ s->dcusps[s->dcuspixs][0] = in[0];
+ s->dcusps[s->dcuspixs][1] = in[1];
+ s->dcusps[s->dcuspixs++][2] = in[2];
+
+ } else { /* Consider another point as a cusp point */
+ double JCh[3];
+ int bj = 0, sbj = 0;
+ double bh = 1e6, sbh = 1e6;
+ double ns, es;
+
+ icmLab2LCh(JCh, in);
+
+//printf("~1 cusp at %f %f %f\n",JCh[0],JCh[1],JCh[2]);
+ /* See which hue it is closest and 2nd closet to cusp hue. */
+ for (j = 0; j < 6; j++) {
+ double tt;
+
+ tt = fabs(gam_hues[s->isJab][j] - JCh[2]);
+ if (tt > 180.0)
+ tt = 360.0 - tt;
+
+ if (tt < bh) {
+ if (bh < sbh) {
+ sbh = bh;
+ sbj = bj;
+ }
+ bh = tt;
+ bj = j;
+ } else if (tt < sbh) {
+ sbh = tt;
+ sbj = j;
+ }
+ }
+
+ /* Compute distance of existing and new */
+ es = s->cusps[bj][1] * s->cusps[bj][1] + s->cusps[bj][2] * s->cusps[bj][2];
+ ns = in[1] * in[1] + in[2] * in[2];
+//printf("~1 chroma dist of existing %f, new %f\n",es,ns);
+ if (ns > es) {
+//printf("~1 New closest\n");
+ s->cusps[bj][0] = in[0];
+ s->cusps[bj][1] = in[1];
+ s->cusps[bj][2] = in[2];
+
+ } else { /* If 2nd best has no entry, use this to fill it */
+ if (s->cusps[sbj][0] == 0.0
+ && s->cusps[sbj][1] == 0.0
+ && s->cusps[sbj][2] == 0.0) {
+//printf("~1 Fill with 2nd closest\n");
+ s->cusps[sbj][0] = in[0];
+ s->cusps[sbj][1] = in[1];
+ s->cusps[sbj][2] = in[2];
+ }
+ }
+ }
+}
+
+
+/* Get the cusp values for red, yellow, green, cyan, blue & magenta */
+/* Return nz if there are no cusps available */
+static int getcusps(
+gamut *s,
+double cusps[6][3]
+) {
+ int i, j;
+
+ if (s->cu_inited == 0) {
+ return 1;
+ }
+
+ for (i = 0; i < 6; i++)
+ for (j = 0; j < 3; j++)
+ cusps[i][j] = s->cusps[i][j];
+
+ return 0;
+}
+
+/* ===================================================== */
+/* Triangulation code */
+/* ===================================================== */
+
+static double ne_point_on_tri(gamut *s, gtri *t, double *out, double *in);
+
+/* Given three points, compute the normalised plane equation */
+/* of a surface through them. */
+/* Return non-zero on error */
+static int plane_equation(
+double *eq, /* Return equation parameters */
+double *p0, /* The three points */
+double *p1,
+double *p2
+) {
+ double ll, v1[3], v2[3];
+
+ /* Compute vectors along edges */
+ v1[0] = p1[0] - p0[0];
+ v1[1] = p1[1] - p0[1];
+ v1[2] = p1[2] - p0[2];
+
+ v2[0] = p2[0] - p0[0];
+ v2[1] = p2[1] - p0[1];
+ v2[2] = p2[2] - p0[2];
+
+ /* Compute cross products v1 x v2, which will be the normal */
+ eq[0] = v1[1] * v2[2] - v1[2] * v2[1];
+ eq[1] = v1[2] * v2[0] - v1[0] * v2[2];
+ eq[2] = v1[0] * v2[1] - v1[1] * v2[0];
+
+ /* Normalise the equation */
+ ll = sqrt(eq[0] * eq[0] + eq[1] * eq[1] + eq[2] * eq[2]);
+ if (ll < 1e-10) {
+ return 1;
+ }
+ eq[0] /= ll;
+ eq[1] /= ll;
+ eq[2] /= ll;
+
+ /* Compute the plane equation constant */
+ eq[3] = - (eq[0] * p0[0])
+ - (eq[1] * p0[1])
+ - (eq[2] * p0[2]);
+
+#ifdef NEVER
+ /* Veritify the plane equation */
+ {
+ double c;
+ c = eq[0] * p0[0]
+ + eq[1] * p0[1]
+ + eq[2] * p0[2]
+ + eq[3];
+ if (fabs(c) > 1e-10) {
+ printf("Plane equation check 0 failed by %f\n",c);
+ }
+ c = eq[0] * p1[0]
+ + eq[1] * p1[1]
+ + eq[2] * p1[2]
+ + eq[3];
+ if (fabs(c) > 1e-10) {
+ printf("Plane equation check 1 failed by %f\n",c);
+ }
+ c = eq[0] * p2[0]
+ + eq[1] * p2[1]
+ + eq[2] * p2[2]
+ + eq[3];
+ if (fabs(c) > 1e-10) {
+ printf("Plane equation check 2 failed by %f\n",c);
+ }
+ }
+#endif /* NEVER */
+ return 0;
+}
+
+/* Compute the log surface plane equation for the triangle */
+/* and other triangle attributes. (Doesn't depend on edge info.) */
+void
+comptriattr(
+gamut *s,
+gtri *t
+) {
+ int j;
+ static double v0[3] = {0.0, 0.0, 0.0};
+ double cp[3]; /* Closest point - not used */
+
+ /* Compute the plane equation for the absolute triangle. */
+ /* This is used for testing if a point is inside the gamut hull. */
+ plane_equation(t->pe, t->v[0]->p, t->v[1]->p, t->v[2]->p);
+
+ /* Compute the plane equation for the triangle */
+ /* based on the log compressed convex hull verticies. */
+ /* This is used for convex hull construction. */
+ plane_equation(t->che, t->v[0]->ch, t->v[1]->ch, t->v[2]->ch);
+
+ /* Compute the plane equation for the triangle */
+ /* mapped to the surface of the sphere */
+ /* This can be used for point in triangle testing ?? */
+ plane_equation(t->spe, t->v[0]->sp, t->v[1]->sp, t->v[2]->sp);
+
+ /* Compute the plane equations of the spherical mapped vertex */
+ /* values with regard to the center of the sphere, so that */
+ /* a point in triangle test can be performed, and baricentric, */
+ /* coordinates can be computed. */
+ plane_equation(t->ee[0], v0, t->v[1]->sp, t->v[2]->sp);
+ plane_equation(t->ee[1], v0, t->v[2]->sp, t->v[0]->sp);
+ plane_equation(t->ee[2], v0, t->v[0]->sp, t->v[1]->sp);
+
+ /* Compute the radius range of the triangle to the center */
+ /* Compute the maximum from the vertexes */
+ t->rs1 = -1.0;
+ for (j = 0; j < 3; j++) {
+ int k;
+ double rs, tt;
+ for (rs = 0.0, k = 0;k < 3; k++) {
+ tt = t->v[j]->p[k] - s->cent[k];
+ rs += tt * tt;
+ }
+ if (rs > t->rs1)
+ t->rs1 = rs;
+ }
+ /* The minimum may be on the plane, an edge or a vertex, */
+ /* so use closest point in triangle function. */
+ t->rs0 = ne_point_on_tri(s, t, cp, s->cent);
+
+ /* Allow a tollerance around the radius squareds */
+ t->rs0 -= 1e-4;
+ t->rs1 += 1e-4;
+
+#ifdef NEVER // ???
+#ifdef ASSERTS
+ {
+ double tt[3]; /* Triangle test point */
+ double ds;
+ for (j = 0; j < 3; j++) {
+ tt[j] = (t->v[0]->p[j] + t->v[1]->p[j] + t->v[2]->p[j])/3.0;
+ tt[j] -= s->cent[j]; /* Make it center relative */
+ }
+ for (j = 0; j < 3; j++) {
+ ds = t->ee[j][0] * tt[0] /* Point we know is inside */
+ + t->ee[j][1] * tt[1]
+ + t->ee[j][2] * tt[2]
+ + t->ee[j][3];
+ if (ds > 1e-8)
+ break; /* Not within triangle */
+ }
+ if (j < 3) {
+ fprintf(stderr,"Assert: point expected to be within triangle %d (vx %d %d %d) is not\n",
+ t->n, t->v[0]->n, t->v[1]->n, t->v[2]->n);
+ fprintf(stderr,"Known point is %f, expect -ve\n",ds);
+ exit(-1);
+ }
+ }
+#endif /* ASSERTS */
+#endif /* NEVER */
+
+}
+
+/* By using the pow() or log() of the radial distance, */
+/* blended with a sphere surface, we try and strike a compromise */
+/* between a pure convex hull surface, and a pure Delaunay triangulation */
+/* the latter which would show dings and nicks from points */
+/* that fall withing the "real" gamut. */
+static double log_scale(gamut *s, double rr) {
+ double aa;
+
+#ifdef TEST_CONVEX_HULL
+ return rr;
+#else
+#ifdef NEVER /* (Not using this version, doesn't work reliably) */
+ aa = (2.0 + rr)/3.0; /* Blend with sphere */
+ aa = log(aa); /* Allow for concave slope */
+ if (aa < 0.0) /* but constrain to be +ve */
+ aa = 0.0;
+#else /* (Using simpler version) */
+ aa = 20.0 * pow(rr, s->logpow); /* Default 0.25 */
+#endif
+#endif /* TEST_CONVEX_HULL */
+
+ return aa;
+}
+
+/* Comput r[], lr0, sp[] and ch[] from p[] for all verticies */
+/* (Note that lr0 will be the first cut, log_scale() value) */
+static void
+compute_vertex_coords(
+gamut *s
+) {
+ int i, j;
+
+ for (i = 0; i < s->nv; i++) {
+ gamut_rect2radial(s, s->verts[i]->r, s->verts[i]->p);
+
+ if (s->verts[i]->r[0] < 1e-6) { /* Ignore a point right at the center */
+ s->verts[i]->lr0 = 0.0;
+ for (j = 0; j < 3; j++) {
+ s->verts[i]->sp[j] = 0.0;
+ s->verts[i]->ch[j] = 0.0;
+ }
+ } else {
+ double aa;
+
+ /* Figure log scaled radius */
+ s->verts[i]->lr0 = log_scale(s, s->verts[i]->r[0]);
+
+ /* Compute unit shere mapped location */
+ aa = 1.0/s->verts[i]->r[0]; /* Adjustment to put in on unit sphere */
+ for (j = 0; j < 3; j++)
+ s->verts[i]->sp[j] = (s->verts[i]->p[j] - s->cent[j]) * aa;
+
+ /* Compute hull testing mapped version */
+ for (j = 0; j < 3; j++)
+ s->verts[i]->ch[j] = s->verts[i]->p[j] * s->verts[i]->lr0;
+ }
+ }
+}
+
+/* Sort the verticies from maximum radius */
+static void sort_verticies(
+gamut *s
+) {
+ int i;
+
+#ifndef TEST_NOSORT
+
+ /* Sort them */
+//#define HEAP_COMPARE(A,B) (A->r[0] > B->r[0])
+#define HEAP_COMPARE(A,B) (A->lr0 > B->lr0)
+ HEAPSORT(gvert *, s->verts, s->nv)
+#undef HEAP_COMPARE
+
+#endif /* !TEST_NOSORT */
+
+ /* Renumber them */
+ for (i = 0; i < s->nv; i++) {
+ s->verts[i]->n = i;
+ }
+}
+
+/* Number just the verticies that have been set, */
+/* and those that have been used in the convex hull */
+static void renumber_verticies(
+gamut *s
+) {
+ int i, j;
+
+ for (j = i = 0; i < s->nv; i++) {
+ if (!(s->verts[i]->f & GVERT_SET))
+ continue;
+
+ s->verts[i]->sn = j;
+ j++;
+ }
+ s->nsv = j;
+
+ for (j = i = 0; i < s->nv; i++) {
+ if (!(s->verts[i]->f & GVERT_TRI))
+ continue;
+
+ s->verts[i]->tn = j;
+ j++;
+ }
+ s->ntv = j;
+}
+
+#ifdef ASSERTS
+
+/* Diagnpostic aid */
+/* Check that the triangulation adjacenty info is OK */
+static void check_triangulation(gamut *s, int final) {
+ int i, j;
+ gtri *tp; /* Triangle pointer */
+ gedge *ep; /* Edge pointer */
+ int failed = 0;
+
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+
+ /* Check verticies for duplication */
+ for (i = 0; i < 3; i++) {
+ for (j = i+1; j < 3; j++) {
+ if (tp->v[i] == tp->v[j]) {
+ failed = 1;
+ printf("Validation failed - duplicate verticies:\n");
+ printf("Triangle %d, has verticies %d %d %d\n", tp->n, tp->v[0]->n, tp->v[1]->n, tp->v[2]->n);
+ fflush(stdout);
+ }
+ }
+ }
+
+ /* Check edges for duplication */
+ for (i = 0; i < 3; i++) {
+ for (j = i+1; j < 3; j++) {
+ if (tp->e[i] == tp->e[j]) {
+ failed = 1;
+ printf("Validation failed - duplicate connectivity:\n");
+ printf("Triangle %d, has verticies %d %d %d\n", tp->n, tp->v[0]->n, tp->v[1]->n, tp->v[2]->n);
+ printf("Triangle %d, has edges %d %d %d\n", tp->n, tp->e[0]->n, tp->e[1]->n, tp->e[2]->n);
+ fflush(stdout);
+ }
+ }
+ }
+
+ /* Check connectivity */
+ for (i = 0; i < 3; i++) {
+ gtri *t1, *t2;
+ gedge *e;
+ int ei1, ei2;
+ int tei; /* Edges index for this triangle [0..1] */
+
+ e = tp->e[i]; /* The edge in question */
+ tei = tp->ei[i];
+ ei1 = e->ti[tei]; /* Edges record of edge index withing this triangle */
+
+ /* Check that the edges reconing of what index edge it is */
+ /* for this triangle is correct */
+ if (ei1 != i) {
+ failed = 1;
+ printf("Validation failed - triangle edge index doesn't match record withing edge:\n");
+ printf("Triangle %d, edge index %d edge %d has record %d\n", tp->n, i, e->n, ei1);
+ fflush(stdout);
+ }
+
+ /* Check that the edges pointer to the triangle is this triangle */
+ if (tp != e->t[tei]) {
+ failed = 1;
+ printf("Validation failed - edge doesn't point back to triangle:\n");
+ printf("Triangle %d, edge index %d is edge %d\n",tp->n, i, e->n);
+ printf("Edge %d, triangle index %d is triangle %d\n", e->n, tei, e->t[tei]->n);
+ printf("Edge %d, triangle index %d is triangle %d\n", e->n, tei^1, e->t[tei^1]->n);
+ fflush(stdout);
+ }
+
+ /* Check the verticies for this edge match edge record */
+ if ((e->v[0] != tp->v[i] || e->v[1] != tp->v[(i+1) % 3])
+ && (e->v[1] != tp->v[i] || e->v[0] != tp->v[(i+1) % 3])) {
+ failed = 1;
+ printf("Validation failed - edge doesn't have same verticies as triangle expects:\n");
+ printf("Triangle %d, has verticies %d %d\n", tp->n, tp->v[i]->n, tp->v[(i+1) % 3]->n);
+ printf("Edge %d, has verticies %d %d\n", e->n, e->v[0]->n, e->v[1]->n);
+ fflush(stdout);
+ }
+
+ t2 = e->t[tei ^ 1]; /* The other triangle */
+ ei2 = e->ti[tei ^ 1]; /* Edges index number withing triangle t2 */
+
+ if (t2 == tp) {
+ failed = 1;
+ printf("Validation failed - connects to itself:\n");
+ printf("Triangle %d, has edges %d %d %d\n", tp->n, tp->e[0]->n, tp->e[1]->n, tp->e[2]->n);
+ fflush(stdout);
+ }
+
+ /* Check that the connection is reflective */
+ if (e != t2->e[ei2]) {
+ failed = 1;
+ printf("Validation failed - connectivity not reflected:\n");
+ printf("Triangle %d, edge index %d points to edge %d\n",tp->n, i, e->n);
+ printf("Triangle %d, edge index %d points to edge %d\n",t2->n, ei2, t2->e[ei2]->n);
+ fflush(stdout);
+ }
+ }
+ } END_FOR_ALL_ITEMS(tp);
+ if (failed) {
+ exit(-1);
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Check that every point is part of a triangle and edge */
+
+ for (i = 0; i < s->nv; i++) { /* Reset the assert flag */
+ gvert *v = s->verts[i];
+
+ v->as = 0;
+
+ /* Check out the flags */
+ if (!(v->f & GVERT_SET)) {
+ if ((v->f & GVERT_TRI)
+ || (v->f & GVERT_INSIDE)) {
+ printf("Validation failed - vertex %d has strange flags 0x%x\n",i, v->f);
+ fflush(stdout);
+ failed = 1;
+ }
+ } else {
+ if ((v->f & GVERT_TRI) && (v->f & GVERT_INSIDE)) {
+ printf("Validation failed - vertex %d has strange flags 0x%x\n",i, v->f);
+ fflush(stdout);
+ failed = 1;
+ }
+ }
+ }
+
+ FOR_ALL_ITEMS(gtri, tp) {
+ for (i = 0; i < 3; i++)
+ tp->v[i]->as |= 1; /* Vertex is in a triangle */
+ } END_FOR_ALL_ITEMS(tp);
+
+ ep = s->edges;
+ FOR_ALL_ITEMS(gedge, ep) {
+ ep->v[0]->as |= 2; /* Vertex is in an edge */
+ ep->v[1]->as |= 2;
+ ep->as = 0; /* Reset the assert flag */
+ } END_FOR_ALL_ITEMS(ep);
+
+ for (i = 0; i < s->nv; i++) {
+ if (s->verts[i]->f & GVERT_TRI) {
+ if ((s->verts[i]->as & 1) == 0) {
+ printf("Validation failed - vertex %d is not in any triangles\n",i);
+ fflush(stdout);
+ failed = 1;
+ }
+ if ((s->verts[i]->as & 2) == 0) {
+ printf("Validation failed - vertex %d is not in any edge\n",i);
+ fflush(stdout);
+ failed = 1;
+ }
+ }
+ }
+
+
+ /* - - - - - - - - - - - - - - - - - - - - - - */
+ /* Check that every edge is part of a triangle */
+
+ /* as flag in triangle was reset above */
+ FOR_ALL_ITEMS(gtri, tp) {
+ for (i = 0; i < 3; i++)
+ tp->e[i]->as |= 1; /* Mark edge used in triangle */
+ } END_FOR_ALL_ITEMS(tp);
+
+ ep = s->edges;
+ FOR_ALL_ITEMS(gedge, ep) {
+ if (ep->as != 1) {
+ printf("Validation failed - edge %d is not in any triangle\n",ep->n);
+ fflush(stdout);
+ failed = 1;
+ }
+ } END_FOR_ALL_ITEMS(ep);
+
+ if (failed) {
+ exit(-1);
+ }
+}
+
+#endif /* ASSERTS */
+
+/* -------------------------------------- */
+/* Add a face to the hit list, if it is not a duplicate. */
+static void add_to_hit_list(
+gamut *s,
+gtri **hlp, /* Hit list */
+gtri *cf /* Face to be added (triangle verts 0, 1) */
+) {
+ gtri *tp; /* Triangle pointer */
+ gvert *c0 = cf->v[0];
+ gvert *c1 = cf->v[1];
+
+//printf("Adding face to hit list %d: %d %d\n",
+//cf->n, cf->v[0]->n, cf->v[1]->n);
+
+ tp = *hlp;
+ /* Search current faces in hit list */
+ FOR_ALL_ITEMS(gtri, tp) {
+ gvert *v0 = tp->v[0];
+ gvert *v1 = tp->v[1];
+ if ((c0 == v0 && c1 == v1) /* Same face from other side */
+ || (c0 == v1 && c1 == v0)) {
+ /* Duplicate found */
+//printf("Duplicate found %d: %d %d\n",
+//tp->n, tp->v[0]->n, tp->v[1]->n);
+ DEL_LINK(*hlp, tp); /* Delete from the hit list */
+
+ /* Check face is common */
+ if (cf->e[0] != tp->e[0]) {
+ fprintf(stderr,"gamut: internal error - face match inconsistency\n");
+ exit(-1);
+ }
+ /* Delete edge */
+ DEL_LINK(s->edges, cf->e[0]);
+ del_gedge(cf->e[0]);
+
+ /* Delete the two faces */
+ del_gtri(tp);
+ del_gtri(cf);
+ return;
+ }
+ } END_FOR_ALL_ITEMS(tp);
+
+ /* Safe to add it to face hit list */
+ /* This removes triangle from triangles list ? */
+ ADD_ITEM_TO_BOT(*hlp, cf);
+//printf("Face added\n");
+}
+
+/* Add a triangles faces to the hit list. */
+static void add_tri_to_hit_list(
+gamut *s,
+gtri **hlp, /* Hit list */
+gtri *tp /* Triangle faces to be added */
+) {
+ int j;
+ gtri *t1, *t2;
+
+ /* In case some verticies disapear below the log surface, */
+ /* and don't remain part of the triangulation, we mark them off. */
+ for (j = 0; j < 3 ; j++) {
+ tp->v[j]->f &= ~GVERT_TRI;
+ tp->v[j]->f |= GVERT_INSIDE;
+ }
+
+ /* Decompose the triangle into three faces, each face being stored */
+ /* into a triangle created on the hit list, using verticices 0, 1. */
+ /* The edges adjacency info remains valid for the three faces, */
+ /* as does the edge plane equation. */
+ DEL_LINK(s->tris, tp); /* Delete it from the triangulation list */
+ t1 = new_gtri();
+ t1->v[0] = tp->v[1]; /* Duplicate with rotated faces */
+ t1->v[1] = tp->v[2];
+ t1->e[0] = tp->e[1]; /* Edge adjacency for this edge */
+ t1->ei[0] = tp->ei[1]; /* Edge index of this triangle */
+ t1->e[0]->t[t1->ei[0]] = t1; /* Fixup reverse adjacency for valid edge */
+ t1->e[0]->ti[t1->ei[0]] = 0; /* Rotated index of new triangles edge */
+ t1->e[1] = t1->e[2] = NULL; /* be safe */
+ for (j = 0; j < 4; j++) /* Copy edge plane equation */
+ t1->ee[2][j] = tp->ee[0][j];
+
+ t2 = new_gtri();
+ t2->v[0] = tp->v[2]; /* Duplicate with rotated faces */
+ t2->v[1] = tp->v[0];
+ t2->e[0] = tp->e[2]; /* Edge adjacency for this edge */
+ t2->ei[0] = tp->ei[2]; /* Edge index of this triangle */
+ t2->e[0]->t[t2->ei[0]] = t2; /* Fixup reverse adjacency for valid edge */
+ t2->e[0]->ti[t2->ei[0]] = 0; /* Rotated index of new triangles edge */
+ t2->e[1] = t2->e[2] = NULL; /* be safe */
+ for (j = 0; j < 4; j++) /* Copy edge plane equation */
+ t2->ee[2][j] = tp->ee[1][j];
+
+ tp->e[1] = tp->e[2] = NULL; /* be safe */
+ add_to_hit_list(s, hlp, tp); /* Add edge 0 to hit list as is */
+ add_to_hit_list(s, hlp, t1); /* Add edge 1 to hit list */
+ add_to_hit_list(s, hlp, t2); /* Add edge 2 to hit list */
+}
+
+#ifdef DEBUG_TRIANG
+ typedef struct {
+ int tix[3]; /* Triangle indexes */
+ int type; /* 0 = hit, 1 = added */
+ } tidxs;
+#endif
+
+/* Insert a vertex into the triangulation */
+static void insert_vertex(
+gamut *s,
+gvert *v /* Vertex to insert */
+) {
+ gtri *tp, *tp2; /* Triangle pointers */
+ gtri *hl; /* Triangle face hit list (polygon faces) */
+ double tol = TRIANG_TOL;
+ int hit = 0; /* Vertex expands hull flag */
+#ifdef DEBUG_TRIANG
+ int intri = 0; /* Vertex landed in a triangle */
+ XLIST(tidxs, hittris)
+ tidxs xxs;
+
+ XLIST_INIT(tidxs, &hittris);
+#endif
+
+#ifdef DEBUG_TRIANG
+ printf("Adding vertex %d: %f %f %f to triangles\n", v->n, v->p[0], v->p[1], v->p[2]);
+#endif
+
+ /* First we search the current triangles, and convert */
+ /* any trianges that are visible from the new point, */
+ /* into a list of faces stored on the face */
+ /* hit list. */
+ /* We are using a brute force search, which will make the */
+ /* algorithm speed proportional to n^2. For better performance */
+ /* with a large number of verticies, an acceleration structure */
+ /* should be used to speed circumradius hit detection. */
+ v->f &= ~GVERT_INSIDE; /* Reset flags */
+ v->f &= ~GVERT_TRI;
+ INIT_LIST(hl);
+ hit = 0;
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ double c;
+
+ /* Check the depth out compared to this triangle log plane equation */
+ c = tp->che[0] * v->ch[0]
+ + tp->che[1] * v->ch[1]
+ + tp->che[2] * v->ch[2]
+ + tp->che[3];
+
+ /* If vertex is above the log hull surface, add triangle to the hit list. */
+ if (c < -tol) {
+#ifdef DEBUG_TRIANG
+ int j;
+ double bds = -1e10;
+#endif
+ hit = 1;
+
+#ifdef DEBUG_TRIANG
+ printf("Got a hit on triangle %d: %d %d %d by %f\n",
+ tp->n, tp->v[0]->n, tp->v[1]->n, tp->v[2]->n,c);
+#endif
+
+#ifdef DEBUG_TRIANG
+ for (j = 0; j < 3; j++) {
+ double ds;
+ ds = tp->ee[j][0] * v->ch[0]
+ + tp->ee[j][1] * v->ch[1]
+ + tp->ee[j][2] * v->ch[2]
+ + tp->ee[j][3];
+ if (ds > tol) {
+ printf("Vertex is not in triangle by %e\n",ds);
+ break;
+ }
+ if (ds > bds)
+ bds = ds;
+ }
+ if (j >= 3) {
+ printf("Vertex is in triangle by %e\n",bds);
+ intri = 1; /* Landed in this triangle */
+ }
+
+ xxs.tix[0] = tp->v[0]->n, xxs.tix[1] = tp->v[1]->n, xxs.tix[2] = tp->v[2]->n;
+ xxs.type = 0;
+ XLIST_ADD(&hittris, xxs)
+#endif
+ add_tri_to_hit_list(s, &hl, tp);
+ }
+ } END_FOR_ALL_ITEMS(tp);
+
+ if (hit == 0) {
+
+//printf("No hits - must be inside the log hull\n");
+ v->f |= GVERT_INSIDE; /* This point is inside the log hull */
+ v->f &= ~GVERT_TRI;
+ } else {
+ int changed = 1;
+
+#ifdef DEBUG_TRIANG
+ /* Point doesn't lie radially within any of the triangles it is */
+ /* above the plane of. This is a geometric conundrum. (?) */
+if (!intri) printf("~1 ###### vertex didn't land in any triangle! ########\n");
+#endif
+
+//printf("Checking out hit polygon edges:\n");
+ /* Now we must make a pass though the hit list, checking that each */
+ /* hit list face will make a correctly oriented, non-sliver triangle */
+ /* when joined to the vertex. */
+ /* Do this check until there are no changes */
+ for (;changed != 0 ;) {
+ tp = hl;
+ changed = 0;
+ FOR_ALL_ITEMS(gtri, tp) {
+ /* Check which side of the edge our vertex is */
+ double ds;
+ ds = tp->ee[2][0] * v->ch[0]
+ + tp->ee[2][1] * v->ch[1]
+ + tp->ee[2][2] * v->ch[2]
+ + tp->ee[2][3];
+//printf("Vertex margin to edge = %e\n",ds);
+ /* If vertex is not to the right of this edge by tol */
+ /* add associated triangle to the hit list. */
+ if (ds > -tol) {
+ gtri *xtp;
+//printf("~1 ###### vertex on wrong side by %e - expand hit list ######\n",ds);
+ if (tp->e[0]->t[0] != tp)
+ xtp = tp->e[0]->t[0];
+ else
+ xtp = tp->e[0]->t[1];
+//printf("Got a hit on triangle %d: %d %d %d\n", xtp->n, xtp->v[0]->n, xtp->v[1]->n, xtp->v[2]->n);
+
+#ifdef DEBUG_TRIANG
+ xxs.tix[0] = xtp->v[0]->n, xxs.tix[1] = xtp->v[1]->n, xxs.tix[2] = xtp->v[2]->n;
+ xxs.type = 1;
+ XLIST_ADD(&hittris, xxs)
+#endif
+
+ add_tri_to_hit_list(s, &hl, xtp);
+ changed = 1;
+ break;
+ }
+ } END_FOR_ALL_ITEMS(tp);
+ }
+
+#ifdef DEBUG_TRIANG_VRML
+ write_diag_vrml(s, v->ch, hittris.no, hittris.list, hl);
+#endif
+
+//printf("About to turn polygon faces into triangles\n");
+ /* Turn all the faces that made it to the */
+ /* hit list, into triangles using the new vertex. */
+ tp = hl;
+ FOR_ALL_ITEMS(gtri, tp) {
+ tp->v[2] = v; /* Add third vertex to face to make triangle */
+ comptriattr(s, tp); /* Compute triangle attributes */
+
+ /* Find the new adjacent triangles from the triangles being formed, */
+ /* to maintain edge adjacency information. */
+ /* Do only one edge at a time, since each adjacency */
+ /* will be visited twice. */
+ tp2 = hl;
+ FOR_ALL_ITEMS(gtri, tp2) {
+ if (tp2->v[0] == tp->v[1]) { /* Found 1/2 tp/tp2 edge adjacency */
+ gedge *e;
+ e = new_gedge();
+ ADD_ITEM_TO_BOT(s->edges, e); /* Append to edge list */
+ tp->e[1] = e; /* Point to edge */
+ tp->ei[1] = 0; /* edges 0th triangle */
+ e->t[0] = tp; /* triangles 1st edge */
+ e->ti[0] = 1; /* triangles 1st edge */
+ tp2->e[2] = e; /* Point to edge */
+ tp2->ei[2] = 1; /* edges 1st triangle */
+ e->t[1] = tp2; /* Triangles 2nd edge */
+ e->ti[1] = 2; /* Triangles 2nd edge */
+ e->v[0] = v; /* Add the two verticies */
+ e->v[1] = tp->v[1];
+ }
+ } END_FOR_ALL_ITEMS(tp2);
+
+//printf("~1 Creating new triangle %d: %d %d %d\n", tp->n, tp->v[0]->n, tp->v[1]->n, tp->v[2]->n);
+ } END_FOR_ALL_ITEMS(tp);
+
+#ifdef DEBUG_TRIANG_VRML
+ tp = hl;
+ hittris.no = 0;
+ FOR_ALL_ITEMS(gtri, tp) {
+ xxs.tix[0] = tp->v[0]->n, xxs.tix[1] = tp->v[1]->n, xxs.tix[2] = tp->v[2]->n;
+ xxs.type = 2;
+ XLIST_ADD(&hittris, xxs)
+ } END_FOR_ALL_ITEMS(tp);
+ write_diag_vrml(s, v->ch, hittris.no, hittris.list, NULL);
+#ifdef DEBUG_TRIANG_VRML_STEP
+#ifdef DO_TWOPASS
+ if (s->pass > 0)
+#endif /* DO_TWOPASS */
+ getchar();
+#endif
+#endif
+
+ /* Move them to the triangulation. */
+ tp = hl;
+ FOR_ALL_ITEMS(gtri, tp) {
+ int j;
+ DEL_LINK(hl, tp); /* Gone from the hit list */
+ ADD_ITEM_TO_BOT(s->tris, tp); /* Append to triangulation list */
+ for (j = 0; j < 3 ; j++) { /* Verticies weren't dropped from triangulation */
+ tp->v[j]->f |= GVERT_TRI;
+ tp->v[j]->f &= ~GVERT_INSIDE;
+ }
+ } END_FOR_ALL_ITEMS(tp);
+
+ v->f |= GVERT_TRI; /* This vertex has been added to triangulation */
+ v->f &= ~GVERT_INSIDE; /* and it's not inside */
+ }
+
+#ifdef DEBUG_TRIANG
+ XLIST_FREE(&hittris);
+#endif
+}
+
+/* - - - - - - - - - - - - - - - - */
+
+/* Create the convex hull surface triangulation */
+static void triangulate_ch(
+gamut *s
+) {
+ /* Establish the base triangulation */
+ {
+ int i, j;
+ gvert *tvs[4]; /* Initial verticies */
+ gtri *tr[4]; /* Initial triangles */
+ gedge *ed[6]; /* Initial edges */
+ double fsz = FAKE_SEED_SIZE; /* Initial tetra size */
+ double ff[3];
+ int onf;
+ static double foffs[4][3] = { /* tetrahedral offsets */
+ { 0.0, 0.0, 1.0 },
+ { 0.0, 0.80254, -0.5 },
+ { 0.75, -0.330127, -0.5 },
+ { -0.75, -0.330127, -0.5 }
+ };
+
+ /* Delete any current fake verticies */
+ for (j = i = 0; i < s->nv; i++) {
+ s->verts[i]->f &= ~GVERT_ESTP; /* Unmark non-fake establishment points */
+ if (!(s->verts[i]->f & GVERT_FAKE))
+ s->verts[j++] = s->verts[i];
+ else
+ free(s->verts[i]);
+ }
+ s->nv = j;
+
+ /* Re-create fake points on each pass */
+ onf = s->nofilter;
+ s->nofilter = 1; /* Turn off filtering */
+ s->doingfake = 1; /* Adding fake points */
+
+ for (j = i = 0; i < 4; i++) {
+ ff[0] = fsz * foffs[i][2] + s->cent[0];
+ ff[1] = fsz * foffs[i][0] + s->cent[1];
+ ff[2] = fsz * foffs[i][1] + s->cent[2];
+ if ((tvs[j++] = expand_gamut(s, ff)) == NULL) {
+ fprintf(stderr,"gamut: internal error - failed to register a fake initial verticies!\n");
+ exit (-1);
+ }
+ }
+
+ s->nofilter = onf;
+ s->doingfake = 0;
+
+#ifdef NEVER
+ printf("Initial verticies:\n");
+ for (i = 0; i < 4; i++) {
+ printf(" %d: %f %f %f\n",tvs[i]->n, tvs[i]->p[0], tvs[i]->p[1], tvs[i]->p[2]);
+ }
+#endif
+ /* Setup the initial triangulation */
+ for (i = 0; i < 4; i++) {
+ tr[i] = new_gtri();
+ }
+
+ for (i = 0; i < 6; i++) {
+ ed[i] = new_gedge();
+ ADD_ITEM_TO_BOT(s->edges, ed[i]);
+ }
+
+ /* Enter the edge verticies */
+ ed[0]->v[0] = tvs[0];
+ ed[0]->v[1] = tvs[1];
+ ed[1]->v[0] = tvs[1];
+ ed[1]->v[1] = tvs[2];
+ ed[2]->v[0] = tvs[0];
+ ed[2]->v[1] = tvs[2];
+ ed[3]->v[0] = tvs[0];
+ ed[3]->v[1] = tvs[3];
+ ed[4]->v[0] = tvs[1];
+ ed[4]->v[1] = tvs[3];
+ ed[5]->v[0] = tvs[2];
+ ed[5]->v[1] = tvs[3];
+
+ /* Triangle facing in the +x, +y +z direction */
+ tr[0]->v[0] = tvs[0];
+ tr[0]->v[1] = tvs[1];
+ tr[0]->v[2] = tvs[2];
+
+ tr[0]->e[0] = ed[0]; /* Should make edge joining a function ? */
+ tr[0]->ei[0] = 0;
+ ed[0]->t[0] = tr[0];
+ ed[0]->ti[0] = 0;
+
+ tr[0]->e[1] = ed[1];
+ tr[0]->ei[1] = 0;
+ ed[1]->t[0] = tr[0];
+ ed[1]->ti[0] = 1;
+
+ tr[0]->e[2] = ed[2];
+ tr[0]->ei[2] = 0;
+ ed[2]->t[0] = tr[0];
+ ed[2]->ti[0] = 2;
+
+ comptriattr(s, tr[0]); /* Compute triangle attributes */
+ ADD_ITEM_TO_BOT(s->tris, tr[0]); /* Append to list */
+
+ /* Triangle facing in the -x, +y +z direction */
+ tr[1]->v[0] = tvs[0];
+ tr[1]->v[1] = tvs[3];
+ tr[1]->v[2] = tvs[1];
+
+ tr[1]->e[0] = ed[3];
+ tr[1]->ei[0] = 0;
+ ed[3]->t[0] = tr[1];
+ ed[3]->ti[0] = 0;
+
+ tr[1]->e[1] = ed[4];
+ tr[1]->ei[1] = 0;
+ ed[4]->t[0] = tr[1];
+ ed[4]->ti[0] = 1;
+
+ tr[1]->e[2] = ed[0];
+ tr[1]->ei[2] = 1;
+ ed[0]->t[1] = tr[1];
+ ed[0]->ti[1] = 2;
+
+ comptriattr(s, tr[1]); /* Compute triangle attributes */
+ ADD_ITEM_TO_BOT(s->tris, tr[1]); /* Append to list */
+
+ /* Triangle facing in the -y +z direction */
+ tr[2]->v[0] = tvs[0];
+ tr[2]->v[1] = tvs[2];
+ tr[2]->v[2] = tvs[3];
+
+ tr[2]->e[0] = ed[2];
+ tr[2]->ei[0] = 1;
+ ed[2]->t[1] = tr[2];
+ ed[2]->ti[1] = 0;
+
+ tr[2]->e[1] = ed[5];
+ tr[2]->ei[1] = 0;
+ ed[5]->t[0] = tr[2];
+ ed[5]->ti[0] = 1;
+
+ tr[2]->e[2] = ed[3];
+ tr[2]->ei[2] = 1;
+ ed[3]->t[1] = tr[2];
+ ed[3]->ti[1] = 2;
+
+ comptriattr(s, tr[2]); /* Compute triangle attributes */
+ ADD_ITEM_TO_BOT(s->tris, tr[2]); /* Append to list */
+
+ /* Triangle facing in the -z direction */
+ tr[3]->v[0] = tvs[1];
+ tr[3]->v[1] = tvs[3];
+ tr[3]->v[2] = tvs[2];
+
+ tr[3]->e[0] = ed[4];
+ tr[3]->ei[0] = 1;
+ ed[4]->t[1] = tr[3];
+ ed[4]->ti[1] = 0;
+
+ tr[3]->e[1] = ed[5];
+ tr[3]->ei[1] = 1;
+ ed[5]->t[1] = tr[3];
+ ed[5]->ti[1] = 1;
+
+ tr[3]->e[2] = ed[1];
+ tr[3]->ei[2] = 1;
+ ed[1]->t[1] = tr[3];
+ ed[1]->ti[1] = 2;
+
+ comptriattr(s, tr[3]); /* Compute triangle attributes */
+ ADD_ITEM_TO_BOT(s->tris, tr[3]); /* Append to list */
+
+ /* The four used verticies are now part of the triangulation */
+ for (i = 0; i < 4; i++) {
+ tvs[i]->f |= GVERT_TRI;
+//printf("Base triangle %d: %d %d %d (Verticies 0x%x, 0x%x, 0x%x, 0x%x)\n", tr[i]->n, tr[i]->v[0]->n, tr[i]->v[1]->n, tr[i]->v[2]->n, tr[i]->v[0], tr[i]->v[1], tr[i]->v[2]);
+ }
+#ifdef ASSERTS
+ check_triangulation(s, 0);
+#endif
+ }
+
+ /* Sort the verticies from maximum radius, */
+ /* to make our log convex hull logic work */
+ sort_verticies(s);
+
+ {
+ int i;
+ /* Complete the triangulation by adding all the remaining verticies */
+ /* in order of decreasing radius, so that those below the log */
+ /* convex hull get discarded. */
+ for (i = 0; i < s->nv; i++) {
+ if (!(s->verts[i]->f & GVERT_SET)
+ || (s->verts[i]->f & GVERT_TRI)
+ || (s->verts[i]->f & GVERT_INSIDE)) {
+ continue;
+ }
+
+ insert_vertex(s, s->verts[i]);
+#ifdef ASSERTS
+ check_triangulation(s, 0);
+#endif
+ }
+ }
+
+ /* Number the used verticies */
+ renumber_verticies(s);
+
+#ifdef ASSERTS
+ check_triangulation(s, 1);
+#endif
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute a new convex hull mapping radius for the sample points, */
+/* on the basis of the initial mapping. */
+static void compute_smchrad(
+gamut *s
+) {
+ int i, j;
+ double zz[3] = { 0.0, 0.0, 1.0 };
+ double rot[3][3];
+ double ssr = 0.5 * s->sres; /* Sample size radius in delta E */
+// double ssr = 10.0;
+ int res = 4; /* resolution of sample grid */
+
+//printf("~1 computing smoothed chrads\n");
+
+ /* Compute the new log surface value */
+ for (i = 0; i < s->nv; i++) {
+ double pr; /* Current surface radius at this vertex */
+ double rad, rw; /* Smoothed radius, weight */
+ double out[3]; /* Point on surface for this vertex */
+ int x, y;
+
+ if (!(s->verts[i]->f & GVERT_SET)) {
+ continue;
+ }
+
+//printf("~1 vertex %d, %f %f %f\n",i, s->verts[i]->p[0], s->verts[i]->p[1], s->verts[i]->p[2]);
+
+ /* Find the average surface level near this point */
+ pr = s->radial(s, out, s->verts[i]->p);
+
+//printf("~1 surface radius %f, location %f %f %f\n",pr, out[0],out[1],out[2]);
+
+ /* Compute a rotation that lines Z up with the radial direction */
+ out[0] -= s->cent[0]; /* Radial vector through point to surface */
+ out[1] -= s->cent[1];
+ out[2] -= s->cent[2];
+ zz[2] = pr; /* Z vector of same length */
+ icmRotMat(rot, zz, out); /* Compute vector from Z to radial */
+ out[0] += s->cent[0];
+ out[1] += s->cent[1];
+ out[2] += s->cent[2];
+ rad = rw = 0.0;
+
+ /* Sample a rectangular array orthogonal to radial vector, */
+ /* and weight samples appropriately */
+ for (x = 0; x < res; x++) {
+ for (y = 0; y < res; y++) {
+ double tt, off[3], rv, in[3];
+
+ off[0] = 2.0 * (x/(res-1.0) - 0.5); /* -1.0 to 1.0 */
+ off[1] = 2.0 * (y/(res-1.0) - 0.5); /* -1.0 to 1.0 */
+ off[2] = 0.0;
+
+ rv = off[0] * off[0] + off[1] * off[1];
+ if (rv > 1.0)
+ continue; /* Outside circle */
+#ifdef NEVER
+ rv = 1.0 - sqrt(rv); /* Radius from center */
+ rv = rv * rv * (3.0 - 2.0 * rv); /* Spline weight it */
+#else
+ rv = 1.0; /* Moving average weighting */
+#endif
+
+ off[0] *= ssr; /* Scale offset to sampling radius */
+ off[1] *= ssr;
+
+ /* Rotate offset to be orthogonal to radial vector */
+ icmMulBy3x3(off, rot, off);
+
+ /* Add offset to surface point over current vertex */
+ in[0] = out[0] + off[0];
+ in[1] = out[1] + off[1];
+ in[2] = out[2] + off[2];
+
+//printf("~1 grid %d %d, weight %f, offset %f %f %f\n",x,y,rv,off[0],off[1],off[2]);
+
+ /* Sum weighted radius at sample point */
+ tt = s->radial(s, NULL, in);
+ tt = log_scale(s, tt);
+ rad += rv * tt;
+ rw += rv;
+
+ }
+ }
+ /* Compute sample filtered radius at the sample point */
+ rad /= rw;
+//printf("~1 sampled radius = %f\n\n",rad);
+
+ /* Now compute new hull mapping radius for this point, */
+ /* based on dividing out the sampled radius */
+
+// s->verts[i]->lr0 = 40.0 + s->verts[i]->lr0 - rad;
+ s->verts[i]->lr0 = 40.0 + log_scale(s, s->verts[i]->r[0]) - rad;
+ /* Prevent silliness */
+ if (s->verts[i]->lr0 < (2.0 * FAKE_SEED_SIZE))
+ s->verts[i]->lr0 = (2.0 * FAKE_SEED_SIZE);
+
+//printf("~1 new lr0 = %f\n\n",s->verts[i]->lr0);
+
+ /* recompute ch[] for new lr0 */
+ for (j = 0; j < 3; j++)
+ s->verts[i]->ch[j] = s->verts[i]->sp[j] * s->verts[i]->lr0;
+ }
+}
+
+/* ===================================================== */
+/* Overall triangulation */
+static void triangulate(
+gamut *s
+) {
+
+ /* Create the convex hull */
+ triangulate_ch(s);
+
+#if defined(DO_TWOPASS) && !defined(TEST_CONVEX_HULL)
+ if (s->no2pass == 0) {
+#ifdef DEBUG_TRIANG
+ printf("############ Starting second pass ###################\n");
+#endif
+ compute_smchrad(s);
+ del_triang(s);
+ s->pass++;
+ triangulate_ch(s);
+
+ /* Three passes is typically slightly better, but slower... */
+// compute_smchrad(s);
+// del_triang(s);
+// s->pass++;
+// triangulate_ch(s);
+ }
+#endif /* DO_TWOPASS && !TEST_CONVEX_HULL */
+}
+
+/* ===================================================== */
+/* Code that makes use of the triangulation */
+/* ===================================================== */
+
+/* return the current surface resolution */
+static double getsres(
+gamut *s
+) {
+ return s->sres;
+}
+
+/* return the isJab flag value */
+static int getisjab(
+gamut *s
+) {
+ return s->isJab;
+}
+
+/* return the isRast flag value */
+static int getisrast(
+gamut *s
+) {
+ return s->isRast;
+}
+
+/* Disable segmented maxima filtering */
+static void setnofilt(gamut *s) {
+ s->nofilter = 1;
+}
+
+/* return the gamut center value */
+static void getcent(gamut *s, double *cent) {
+ cent[0] = s->cent[0];
+ cent[1] = s->cent[1];
+ cent[2] = s->cent[2];
+}
+
+/* Return the gamut min/max range */
+static void getrange(gamut *s, double *min, double *max) {
+
+ if (min != NULL) {
+ min[0] = s->mn[0];
+ min[1] = s->mn[1];
+ min[2] = s->mn[2];
+ }
+ if (max != NULL) {
+ max[0] = s->mx[0];
+ max[1] = s->mx[1];
+ max[2] = s->mx[2];
+ }
+}
+
+/* return nz if the two gamut are compatible */
+static int compatible(
+gamut *s, struct _gamut *t) {
+ int j;
+
+ /* The same colorspace ? */
+ if ((s->isJab && !t->isJab)
+ || (!s->isJab && t->isJab)) {
+ return 0;
+ }
+
+ /* The same gamut center ? */
+ for (j = 0; j < 3; j++) {
+ if (fabs(s->cent[j] - t->cent[j]) > 1e-9) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/* Return the number of raw verticies used to construct surface */
+static int nrawverts(
+gamut *s
+) {
+ int i, nrv = 0;
+
+ /* Sort them so that triangulate doesn't mess indexing up */
+ sort_verticies(s);
+
+ /* Count them */
+ for (i = 0; i < s->nv; i++) {
+ if (s->verts[i]->f & GVERT_SET)
+ nrv++;
+ }
+
+ return nrv;
+}
+
+/* Return the raw (triangle and non-triangle surface) verticies */
+/* location given its index. */
+/* return the next (sparse) index, or -1 if beyond last */
+static int getrawvert(
+gamut *s,
+double pos[3], /* Return absolute position */
+int ix /* Input index */
+) {
+ if (ix < 0)
+ return -1;
+
+ /* Find then next used in the triangulation */
+ for (; ix < s->nv; ix++) {
+ if (!(s->verts[ix]->f & GVERT_SET))
+ continue;
+ break;
+ }
+
+ if (ix >= s->nv)
+ return -1;
+
+ pos[0] = s->verts[ix]->p[0];
+ pos[1] = s->verts[ix]->p[1];
+ pos[2] = s->verts[ix]->p[2];
+
+ return ix+1;
+}
+
+/* Return the number of raw direction 0 verticies used */
+/* to construct surface. (Direction 0 is radial direction maxima) */
+static int nraw0verts(
+gamut *s
+) {
+ int i, nrv = 0;
+
+ /* Sort them so that triangulate doesn't mess indexing up */
+ sort_verticies(s);
+
+ /* Count them */
+ for (i = 0; i < s->nv; i++) {
+ if ((s->verts[i]->f & GVERT_SET)
+ && (s->verts[i]->k0 > 0))
+ nrv++;
+ }
+
+ return nrv;
+}
+
+/* Return the raw (triangle and non-triangle surface) direction 0 */
+/* verticies location given its index. (Direction 0 is radial direction maxima) */
+/* return the next (sparse) index, or -1 if beyond last */
+static int getraw0vert(
+gamut *s,
+double pos[3], /* Return absolute position */
+int ix /* Input index */
+) {
+ if (ix < 0)
+ return -1;
+
+ /* Find then next used in the triangulation and direction 0 */
+ for (; ix < s->nv; ix++) {
+ if (!(s->verts[ix]->f & GVERT_SET)
+ || !(s->verts[ix]->k0 > 0))
+ continue;
+ break;
+ }
+
+ if (ix >= s->nv)
+ return -1;
+
+ pos[0] = s->verts[ix]->p[0];
+ pos[1] = s->verts[ix]->p[1];
+ pos[2] = s->verts[ix]->p[2];
+
+ return ix+1;
+}
+
+/* Return the number of stratified sampling surface verticies, */
+/* for the given verticies per unit area parameter. */
+static int nssverts(
+gamut *s,
+double xvra /* Extra vertex ratio */
+) {
+
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+//printf("~1 nssverts called with xvra = %f\n",xvra);
+ if (s->xvra != xvra) {
+ int i, j;
+ gtri *tp; /* Triangle pointer */
+ double tarea; /* Total area */
+ double tnverts; /* Target number of verticies */
+ int anverts; /* Actual number of verticies */
+
+ /* Calculate the total surface area of the triangulation */
+ tarea = 0.0;
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ double sp, ss[3]; /* Triangle side lengths */
+ double dp; /* Dot product of point in triangle and normal */
+
+ for (i = 0; i < 3; i++) { /* For each edge */
+ for (ss[i] = 0.0, j = 0; j < 3; j++) {
+ double dd = tp->e[i]->v[1]->p[j] - tp->e[i]->v[0]->p[j];
+ ss[i] += dd * dd;
+ }
+ ss[i] = sqrt(ss[i]);
+ }
+
+ /* semi-perimeter */
+ sp = 0.5 * (ss[0] + ss[1] + ss[2]);
+
+ /* Area of triangle */
+ tp->area = sqrt(sp * (sp - ss[0]) * (sp - ss[1]) * (sp - ss[2]));
+
+ tarea += tp->area;
+ } END_FOR_ALL_ITEMS(tp);
+
+ /* target number of vectors */
+ tnverts = xvra * s->ntv;
+//printf("~1 total area = %f, tnverts = %f\n",tarea, tnverts);
+
+ /* Number that need to be added using stratified sampling */
+ tnverts -= (double)s->ntv;
+ anverts = 0;
+
+ /* Compute number of extra verticies for each triangle */
+ if (tnverts > 0.0) {
+ double exvpua; /* Extra verticies per unit area to create */
+
+ exvpua = tnverts/tarea;
+//printf("~1 extra verts = %f\n",exvpua);
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ tp->ssverts = (int)(exvpua * tp->area + 0.5);
+ anverts += tp->ssverts;
+ } END_FOR_ALL_ITEMS(tp);
+ }
+ anverts += s->ntv;
+ s->xvra = xvra;
+ s->ssnverts = anverts;
+ }
+
+//printf("~1 returning total verts %d\n",s->ssnverts);
+ return s->ssnverts;
+}
+
+/* Return the stratified sampling surface verticies */
+/* location and radius. nssverts() sets vpua */
+static int getssvert(
+gamut *s,
+double *rad, /* Return radial radius */
+double pos[3], /* Return absolute position */
+double norm[3], /* Return normal of triangle it orginates from */
+int ix /* Input index */
+) {
+ int sskip = 0; /* Number of points to skip after each reset of pseudo rand */
+
+//printf("getssvert called\n");
+
+ if (ix < 0)
+ return -1;
+
+ if (ix < s->nv) {
+
+ /* Find then next used vertex in the triangulation */
+ for (; ix < s->nv; ix++) {
+ if (!(s->verts[ix]->f & GVERT_TRI))
+ continue;
+ break;
+ }
+ }
+
+ if (ix < s->nv) { /* returning verticies */
+
+ if (rad != NULL)
+ *rad = s->verts[ix]->r[0];
+ if (pos != NULL) {
+ pos[0] = s->verts[ix]->p[0];
+ pos[1] = s->verts[ix]->p[1];
+ pos[2] = s->verts[ix]->p[2];
+ }
+ if (norm != NULL) {
+ gvert *vp = s->verts[ix];
+ gtri *tp;
+ int i, j, nt = 0;
+ for (j = 0; j < 3; j++)
+ norm[j] = 0.0;
+
+ /* Slow, but search all triangles for this vertex. */
+ /* Return the average normal of all the triangles it is part of */
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ for (i = 0; i < 3; i++) {
+ if (tp->v[i] == vp) {
+ for (j = 0; j < 3; j++)
+ norm[j] += tp->pe[j];
+ nt++;
+ break;
+ }
+ }
+ } END_FOR_ALL_ITEMS(tp);
+ if (nt == 0)
+ error("gamut::getssvert() vertex doesn't have a triangle");
+ for (j = 0; j < 3; j++)
+ norm[j] /= (double)nt;
+ }
+//printf("~1 returning tri vertex %f %f %f\n", pos[0],pos[1],pos[2]);
+
+ } else { /* We're generating ss points for each triangle */
+ int i, j;
+ double tt;
+ double uv[2];
+ double tr[3]; /* Baricentric weighting */
+ double vv[3];
+
+ if (s->ss == NULL) {
+ if ((s->ss = new_sobol(2)) == NULL)
+ error("gamut::getssvert() new_sobol() failed");
+ for (i = 0; i < sskip; i++)
+ s->ss->next(s->ss, uv);
+ }
+ if (ix == s->nv) { /* Start of generating verticies in triangles */
+
+//printf("~1 setting up for scan through triangles\n");
+ s->nexttri = s->tris;
+ if (s->nexttri == NULL)
+ return -1;
+ s->ssvertn = 0;
+ s->ss->reset(s->ss);
+ }
+ if (s->ssvertn >= s->nexttri->ssverts) {
+ do {
+//printf("~1 skipping to next triangle\n");
+ s->nexttri = NEXT_FWD(s->nexttri);
+ if (s->nexttri == s->tris)
+ return -1;
+ } while(s->nexttri->ssverts <= 0);
+ s->ssvertn = 0;
+ s->ss->reset(s->ss);
+ for (i = 0; i < sskip; i++)
+ s->ss->next(s->ss, uv);
+ }
+//printf("~1 generating ss vert %d out of %d\n",s->ssvertn+1,s->nexttri->ssverts);
+ s->ss->next(s->ss, uv);
+
+ tt = sqrt(uv[0]);
+ tr[0] = 1 - tt;
+ tr[1] = uv[1] * tt;
+ tr[2] = 1.0 - tr[0] - tr[1];
+
+ vv[0] = vv[1] = vv[2] = 0.0;
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++)
+ vv[j] += s->nexttri->v[i]->p[j] * tr[i];
+ }
+
+ if (rad != NULL)
+ *rad = icmNorm33(vv, s->cent);
+ if (pos != NULL) {
+ pos[0] = vv[0];
+ pos[1] = vv[1];
+ pos[2] = vv[2];
+ }
+ if (norm != NULL) {
+ norm[0] = s->nexttri->pe[0];
+ norm[1] = s->nexttri->pe[1];
+ norm[2] = s->nexttri->pe[2];
+ }
+ s->ssvertn++;
+//printf("~1 returning ss vertex %f %f %f\n", pos[0],pos[1],pos[2]);
+ }
+
+ return ix+1;
+}
+
+/* Return the number of verticies in the triangulated surface */
+static int nverts(
+gamut *s
+) {
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ return s->ntv;
+}
+
+/* Return the verticies location and radius given its index. */
+/* return the next (sparse) index, or -1 if beyond last */
+static int getvert(
+gamut *s,
+double *rad, /* Return radial radius */
+double pos[3], /* Return absolute position */
+int ix /* Input index */
+) {
+ if (ix >= s->nv)
+ return -1;
+
+ /* Find then next used in the triangulation */
+ for (; ix < s->nv; ix++) {
+ if (!(s->verts[ix]->f & GVERT_TRI))
+ continue;
+ break;
+ }
+ if (ix >= s->nv)
+ return -1;
+
+ if (rad != NULL)
+ *rad = s->verts[ix]->r[0];
+ if (pos != NULL) {
+ pos[0] = s->verts[ix]->p[0];
+ pos[1] = s->verts[ix]->p[1];
+ pos[2] = s->verts[ix]->p[2];
+ }
+
+ return ix+1;
+}
+
+
+/* Reset indexing through triangles for getnexttri() */
+static void startnexttri(gamut *s) {
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ s->nexttri = NULL;
+}
+
+/* Return the next surface triange, nz on no more */
+static int getnexttri(
+gamut *s,
+int v[3] /* Return indexes for same order as getvert() */
+) {
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ if (s->nexttri == NULL) {
+ s->nexttri = s->tris;
+ if (s->nexttri == NULL)
+ return 1;
+ } else {
+ s->nexttri = NEXT_FWD(s->nexttri);
+ if (s->nexttri == s->tris)
+ return 1;
+ }
+
+ v[0] = s->nexttri->v[0]->tn;
+ v[1] = s->nexttri->v[1]->tn;
+ v[2] = s->nexttri->v[2]->tn;
+ return 0;
+}
+
+/* ===================================================== */
+
+/* Return the total volume of the gamut */
+/* [ We use the formula from "Area of planar polygons and */
+/* volume of polyhedra" by Ronald N. Goldman, */
+/* Graphics Gems II, pp 170 ] */
+static double volume(
+gamut *s
+) {
+ int i, j;
+ gtri *tp; /* Triangle pointer */
+ double vol; /* Gamut volume */
+
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ /* Compute the area of each triangle in the list, */
+ /* and accumulate the gamut volume. */
+ tp = s->tris;
+ vol = 0.0;
+ FOR_ALL_ITEMS(gtri, tp) {
+ double sp, ss[3]; /* Triangle side lengths */
+ double area; /* Area of this triangle */
+ double dp; /* Dot product of point in triangle and normal */
+
+ for (i = 0; i < 3; i++) { /* For each edge */
+ for (ss[i] = 0.0, j = 0; j < 3; j++) {
+ double dd = tp->e[i]->v[1]->p[j] - tp->e[i]->v[0]->p[j];
+ ss[i] += dd * dd;
+ }
+ ss[i] = sqrt(ss[i]);
+ }
+
+ /* semi-perimeter */
+ sp = 0.5 * (ss[0] + ss[1] + ss[2]);
+
+ /* Area of triangle */
+ area = sqrt(sp * (sp - ss[0]) * (sp - ss[1]) * (sp - ss[2]));
+
+ /* Dot product between first vertex in triangle and the unit normal vector */
+ dp = tp->v[0]->p[0] * tp->pe[0]
+ + tp->v[0]->p[1] * tp->pe[1]
+ + tp->v[0]->p[2] * tp->pe[2];
+
+ /* Accumulate gamut volume */
+ vol += dp * area;
+
+ } END_FOR_ALL_ITEMS(tp);
+
+ vol = fabs(vol)/3.0;
+
+ return vol;
+}
+
+/* ===================================================== */
+/* ===================================================== */
+/* Given a point, */
+/* return the distance to the gamut surface. */
+
+static void init_lu(gamut *s);
+static gtri *radial_point_triang(gamut *s, gbsp *np, double in[3]);
+static double radial_point(gamut *s, gbsp *np, double in[3]);
+
+/* Given a point, return the point in that direction */
+/* that lies on the gamut surface. Return the radial */
+/* radius to the surface point */
+/* Brute force search version. */
+static double
+radial_bf(
+gamut *s,
+double *out, /* result point (absolute)*/
+double *in /* input point (absolute)*/
+) {
+ gtri *tp;
+ int j;
+ double ss, rv;
+ double nin[3]; /* Normalised input vector */
+
+//printf("~1 radial called with %f %f %f\n", in[0], in[1], in[2]);
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ /* Compute vector length to center point */
+ for (ss = 0.0, j = 0; j < 3; j++)
+ ss += (in[j] - s->cent[j]) * (in[j] - s->cent[j]);
+ ss = 1.0/sqrt(ss); /* Normalising factor */
+ for (ss = 0.0, j = 0; j < 3; j++)
+ nin[j] = s->cent[j] + (in[j] - s->cent[j]) * ss;
+
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ if (vect_intersect(s, &rv, out, s->cent, nin, tp)) {
+ if (rv > 0.0) /* Expect only one intersection */
+ break;
+ }
+ } END_FOR_ALL_ITEMS(tp);
+
+//printf("~1 result = %f %f %f\n",out[0], out[1], out[2]);
+
+ return rv;
+}
+
+/* Implementation for following two functions: */
+/* Given a point, return the point in that direction */
+/* that lies on the gamut surface. Use the BSP accellerated search. */
+/* Return the radial length of the input and radial length of result */
+static void
+_radial(
+gamut *s,
+double *ir, /* return input radius (may be NULL) */
+double *or, /* return output radius (may be NULL) */
+double *out, /* result point (absolute) (may be NULL) */
+double *in /* input point (absolute)*/
+) {
+ int j;
+ double ss, rv;
+ double nin[3]; /* Normalised input vector */
+
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ /* We have to find out which triangle the point is in */
+ if (s->lu_inited == 0) {
+ init_lu(s); /* Init BSP search tree */
+ }
+//if (trace) printf("~1 radial called with %f %f %f\n", in[0], in[1], in[2]);
+
+ for (j = 0; j < 3; j++)
+ nin[j] = in[j] - s->cent[j]; /* relative to gamut center */
+
+ for (ss = 0.0, j = 0; j < 3; j++)
+ ss += nin[j] * nin[j];
+ ss = sqrt(ss);
+ if (ss > 1e-9) { /* Normalise to 1.0 */
+ for (j = 0; j < 3; j++)
+ nin[j] /= ss;
+ } else {
+ nin[0] = 1.0;
+ nin[1] = nin[2] = 0.0;
+ }
+
+//if (trace) printf("~1 Normalised in = %f %f %f\n", nin[0], nin[1], nin[2]);
+ rv = radial_point(s, s->lutree, nin);
+
+ if (rv < 0.0) {
+ error("gamut: radial internal error - failed to find triangle\n");
+ }
+
+ if (out != NULL) {
+ for (j = 0; j < 3; j++)
+ out[j] = nin[j] * rv + s->cent[j]; /* Scale out to surface length, absolute */
+//if (trace) printf("~1 result = %f %f %f\n",out[0], out[1], out[2]);
+ }
+
+ if (ir != NULL) {
+//if (trace) printf("~1 input radius res = %f\n",ss);
+ *ir = ss;
+ }
+
+ if (or != NULL) {
+//if (trace) printf("~1 output radius res = %f\n",rv);
+ *or = rv;
+ }
+}
+
+/* Given a point, return the point in that direction */
+/* that lies on the gamut surface */
+/* Return the normalised radial radius to the surface point */
+static double
+nradial(
+gamut *s,
+double *out, /* result point (absolute) (May be NULL) */
+double *in /* input point (absolute)*/
+) {
+ double ss, rv;
+
+ _radial(s, &ss, &rv, out, in);
+ return ss/rv;
+}
+
+/* Given a point, return the point in that direction */
+/* that lies on the gamut surface */
+/* Return the radial radius to the surface point */
+static double
+radial(
+gamut *s,
+double *out, /* result point (absolute) (May be NULL) */
+double *in /* input point (absolute)*/
+) {
+ double ss, rv;
+
+ _radial(s, &ss, &rv, out, in);
+ return rv;
+}
+
+void lu_split(gamut *s, gbsp **np, int rdepth, gtri **list, int llen);
+
+/* Setup the radial lookup function acceleration structure */
+static void
+init_lu(
+gamut *s
+) {
+ static double v0[3] = {0.0, 0.0, 0.0};
+ static
+ gedge *ep; /* Edge pointer */
+ gtri *tp; /* Triangle pointer */
+ gtri **tlist;
+ int ntris;
+
+//printf("~1 init_lu called\n");
+
+ /* Create mean angle dividing plane equations */
+ ep = s->edges;
+ FOR_ALL_ITEMS(gedge, ep) {
+ plane_equation(ep->re, v0, ep->v[0]->sp, ep->v[1]->sp);
+ } END_FOR_ALL_ITEMS(ep);
+
+ /* Create the initial triangle list */
+ /* First count them */
+ ntris = 0;
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ ntris++;
+ } END_FOR_ALL_ITEMS(tp);
+
+ /* Allocate a list */
+ if ((tlist = (gtri **) malloc(ntris * sizeof(gtri *))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed - top level triangle list (%d entries)\n",ntris);
+ exit(-1);
+ }
+
+ /* Then add them to the list */
+ ntris = 0;
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ tlist[ntris] = tp;
+ ntris++;
+ } END_FOR_ALL_ITEMS(tp);
+
+ /* Recursively split them, and add objects to leaves */
+ lu_split(s, &s->lutree, 0, tlist, ntris);
+
+ free(tlist);
+
+//printf("~1 init_lu done\n");
+ s->lu_inited = 1;
+}
+
+/*
+ * BSP accellerator:
+ * This is setup specifically to accellerate finding
+ * the radial point on the gamut surface. To do this, all
+ * the BSP plains pass through the gamut center, creating
+ * wedge shaped sub-division regions.
+ *
+ * For accellerating the vector intersect code, this isn't
+ * so fabulous, and a general unconstrained BSP tree would
+ * be better. To address this, an orhogonal element to the
+ * radial BSP's is provided in the radius squared range
+ * of each set of elements below a BSP node.
+ */
+
+/* Recursive routine to choose a partition plane, */
+/* and then split the triangle list between the */
+/* +ve and -ve sides, or add triangles as leaves. */
+void
+lu_split(
+gamut *s,
+gbsp **np, /* Address of node pointer to be set */
+int rdepth, /* Current recursion depth */
+gtri **list, /* Current triangle list */
+int llen /* Number of triangles in the list */
+) {
+ double rs0, rs1; /* Radius squared range of elements */
+ int ii, jj; /* Progress through edges */
+ int pcount; /* Current best scored try */
+ int ncount;
+ int bcount;
+ int mcount;
+ double peqs[4] = { 0.0, 0.0, 0.0, 0.0 };
+ gtri **plist, **nlist; /* New sub-lists */
+ int pix, nix; /* pos/ned sublist indexes */
+ gbspn *bspn; /* BSP decision node */
+
+//printf("~1\nlu_split called at depth %d with %d triangles\n",rdepth, llen);
+#ifdef DEBUG
+ if (llen <= 3) {
+ int i;
+ for (i = 0; i < llen; i++) {
+ printf("Triang index %d = %d\n",i, list[i]->n);
+ printf("Triang verts %d %d %d\n",
+ list[i]->v[0]->tn, list[i]->v[1]->tn, list[i]->v[2]->tn);
+ printf("Vert 0 at %.18f %.18f %.18f\n",list[i]->v[0]->sp[0], list[i]->v[0]->sp[1], list[i]->v[0]->sp[2]);
+ printf("Vert 1 at %.18f %.18f %.18f\n",list[i]->v[1]->sp[0], list[i]->v[1]->sp[1], list[i]->v[1]->sp[2]);
+ printf("Vert 2 at %.18f %.18f %.18f\n",list[i]->v[2]->sp[0], list[i]->v[2]->sp[1], list[i]->v[2]->sp[2]);
+ }
+ }
+#endif /* DEBUG */
+
+ if ((rdepth+1) >= BSPDEPTH) { /* Oops */
+ printf("gamut internal error: ran out of recursion depth in BSP\n");
+ exit (-1);
+ }
+
+ /* Scan our list or triangles and figure out radius squared range */
+ {
+ int i, j, e;
+ double rs;
+
+ rs0 = 1e120;
+ rs1 = -1.0;
+ for (i = 0; i < llen; i++) {
+ if (list[i]->rs0 < rs0)
+ rs0 = list[i]->rs0;
+ if (list[i]->rs1 > rs1)
+ rs1 = list[i]->rs1;
+ }
+//printf("~1 no triangs %d, rs range %f - %f\n",llen,rs0,rs1);
+ }
+
+ pcount = ncount = bcount = -1;
+ mcount = 0;
+ /* test every edge in turn */
+ for (ii = jj = 0;ii < llen;) {
+ double eqs[4];
+ int i;
+ gedge *ep; /* Edge pointer */
+ int pc, nc, bc; /* Score a try, postive count, negative count, both count */
+ int mc; /* Minumum count */
+
+ ep = list[ii]->e[jj];
+ eqs[0] = ep->re[0]; /* Use this edge */
+ eqs[1] = ep->re[1];
+ eqs[2] = ep->re[2];
+ eqs[3] = ep->re[3];
+ if (++jj > 2) {
+ jj = 0;
+ ii++;
+ }
+
+ /* Do the trial split */
+ pc = nc = bc = 0;
+ for (i = 0; i < llen; i++) {
+ int j;
+ int po, ne;
+
+ /* Compute distance from plane of all verticies in triangle */
+ po = ne = 0;
+ for (j = 0; j < 3; j++) { /* For triangle verticies */
+ double ds;
+ /* Compute distance to dividing plane of this vertex */
+ ds = eqs[0] * list[i]->v[j]->sp[0]
+ + eqs[1] * list[i]->v[j]->sp[1]
+ + eqs[2] * list[i]->v[j]->sp[2]
+ + eqs[3];
+ /* Figure if the verticies are clearly to one side of the plane */
+ if (ds > 1e-10) {
+ po++;
+ } else if (ds < -1e-10) {
+ ne++;
+ }
+ }
+ /* Score this split */
+ if (po) {
+ pc++;
+ if (ne) {
+ nc++;
+ bc++;
+ list[i]->sort = 3; /* Both */
+ } else {
+ list[i]->sort = 1; /* +ve */
+ }
+ } else if (ne) {
+ nc++;
+ list[i]->sort = 2; /* -ve */
+ } else { /* Hmm. Neither */
+ bc++;
+ list[i]->sort = 3; /* Assume both */
+ }
+ }
+ mc = pc < nc ? pc : nc; /* Size of smallest group */
+ mc -= bc;
+//printf("~1 lu_split trial %d, mc %d, pc %d, nc %d, bc %d\n",ii * 3 + jj, mc, pc, nc, bc);
+ if (mc > mcount) { /* New largest small group */
+ mcount = mc;
+ pcount = pc;
+ ncount = nc;
+ bcount = bc;
+ peqs[0] = eqs[0];
+ peqs[1] = eqs[1];
+ peqs[2] = eqs[2];
+ peqs[3] = eqs[3];
+//printf("~1 new best - plane mc = %d, %f %f %f %f\n",mc, peqs[0], peqs[1], peqs[2], peqs[3]);
+ for (i = 0; i < llen; i++) {
+ list[i]->bsort = list[i]->sort;
+ }
+ }
+ }
+
+#ifdef DEBUG_SPLIT_VRML
+ write_split_diag_vrml(s, list, llen);
+ getchar();
+#endif /* DEBUG_SPLIT_VRML */
+
+ if (ii >= llen && bcount < 0) { /* We failed to find a split plane. */
+ /* This is usually a result of the list being 2 or more triangles */
+ /* that do not share any edges (disconected from each other), and */
+ /* lying so that any split plane formed from an edge of one, */
+ /* intersects one of the others. */
+ /* In theory we could solve this by picking some */
+ /* other radial split plane ? */
+
+ /* Instead leave our list of triangles as the leaf node, */
+ /* and let the search algorithms deal with this. */
+
+ *np = (gbsp *)new_gbspl(llen, list);
+ (*np)->rs0 = rs0; /* Radius squared range */
+ (*np)->rs1 = rs1;
+//printf("~1 lu_split returning with a non split list of %d triangles\n",llen);
+ return;
+ }
+
+ /* Divide the triangles into two lists */
+ bspn = new_gbspn(); /* Next node */
+ *np = (gbsp *)bspn; /* Put it in place */
+ bspn->rs0 = rs0; /* Radius squared range */
+ bspn->rs1 = rs1;
+ bspn->pe[0] = peqs[0]; /* Plane equation */
+ bspn->pe[1] = peqs[1];
+ bspn->pe[2] = peqs[2];
+ bspn->pe[3] = peqs[3];
+
+ /* Allocate the sub lists */
+ if ((plist = (gtri **) malloc(pcount * sizeof(gtri *))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed - pos sub-list\n");
+ exit(-1);
+ }
+ if ((nlist = (gtri **) malloc(ncount * sizeof(gtri *))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed - neg sub-list\n");
+ exit(-1);
+ }
+
+ /* Fill them in */
+ for (pix = nix = ii = 0; ii < llen; ii++) {
+ if (list[ii]->bsort & 1) { /* Positive */
+ plist[pix] = list[ii];
+ pix++;
+ }
+ if (list[ii]->bsort & 2) { /* Negative */
+ nlist[nix] = list[ii];
+ nix++;
+ }
+ }
+
+ /* Recurse if there are more triangles to split */
+ if (pix == 1) {
+ bspn->po = (gbsp *)plist[0]; /* leaf node */
+//printf("~1 pos leaf with triangle %d\n",plist[0]->n);
+ } else if (pix > 1) {
+//printf("~1 About to recurse on positive with list of %d\n",pix);
+ lu_split(s, &bspn->po, rdepth+1, plist, pix);
+ }
+
+ if (nix == 1) {
+//printf("~1 neg leaf with triangle %d\n",nlist[0]->n);
+ bspn->ne = (gbsp *)nlist[0]; /* leaf node */
+ } else if (nix > 1) {
+//printf("~1 About to recurse on negative with list of %d\n",nix);
+ lu_split(s, &bspn->ne, rdepth+1, nlist, nix);
+ }
+
+ free(plist);
+ free(nlist);
+//printf("~1 lu_split returning\n");
+}
+
+/* Given a point and a node in the BSP tree, recurse down */
+/* the tree, or return the triangle it lies in. */
+/* Return NULL if it wasn't in any triangle (shouldn't happen with a closed gamut ?). */
+static gtri *radial_point_triang(
+gamut *s,
+gbsp *np, /* BSP node pointer we're at */
+double *nin /* Normalised center relative point */
+) {
+ gtri *rv;
+//if (trace) printf("~1 rad_pnt_tri: BSP 0x%x tag = %d, point %f %f %f\n", np,np->tag,nin[0],nin[1],nin[2]);
+ if (np->tag == 1) { /* It's a BSP node */
+ gbspn *n = (gbspn *)np;
+ double ds;
+
+ ds = n->pe[0] * nin[0]
+ + n->pe[1] * nin[1]
+ + n->pe[2] * nin[2]
+ + n->pe[3];
+
+//if (trace) printf("~1 checking against BSP plane, ds = %e\n",ds);
+ /* Recurse down both sides it might be in */
+ if (ds > -1e-12) {
+ if ((rv = radial_point_triang(s, n->po, nin)) != NULL)
+ return rv;
+ }
+ if (ds < 1e-12) {
+ if ((rv = radial_point_triang(s, n->ne, nin)) != NULL)
+ return rv;
+ }
+ return NULL; /* Hmm */
+
+ } else { /* It's a triangle or list of triangles */
+ int nt; /* Number of triangles in list */
+ gtri **tpp; /* Pointer to list of triangles */
+ int i, j;
+
+ if (np->tag == 2) { /* It's a triangle */
+ tpp = (gtri **)&np;
+ nt = 1;
+ } else if (np->tag == 3) { /* It's a triangle list */
+ gbspl *n = (gbspl *)np;
+ tpp = n->t;
+ nt = n->nt;
+ }
+
+ /* Go through the list and stop at the first triangle */
+ /* that the node lies in. */
+ for (i = 0; i < nt; i++, tpp++) {
+ gtri *t = *tpp;
+
+ /* Check if the point is within this triangle */
+ for (j = 0; j < 3; j++) {
+ double ds;
+ ds = t->ee[j][0] * nin[0]
+ + t->ee[j][1] * nin[1]
+ + t->ee[j][2] * nin[2]
+ + t->ee[j][3];
+ if (ds > 1e-10)
+ break; /* Not within triangle */
+ }
+ if (j >= 3) {
+//if (trace) printf("~1 located triangle from list that we're in %d\n",n->t[i]->n);
+ return t;
+ }
+ }
+ /* Hmm. */
+ }
+
+//if (trace) printf("~1 failed to find a triangle\n");
+ return NULL;
+}
+
+/* Return the location on the surface of the triangle */
+/* that is intersected by the radial direction */
+/* of the given relative point. Return the distance to */
+/* the gamut surface. */
+static double radial_point(
+gamut *s,
+gbsp *np, /* BSP node pointer we're at */
+double *nin /* Normalised center relative point */
+) {
+ gtri *t;
+ double rv;
+
+//if (trace) printf("~1 radial_point: BSP 0x%x tag = %d, point %f %f %f\n", np,np->tag,nin[0],nin[1],nin[2]);
+
+ t = radial_point_triang(s, np, nin);
+
+ /* If we failed to find a triangle, or the result was incorrect, do a */
+ /* brute force search to be sure of the result. */
+ if (t == NULL) {
+ error("rspl.radial: failed to find radial triangle\n");
+ }
+
+ /* Compute the intersection of the input vector with the triangle plane */
+ /* (Since nin[] is already relative, we don't need to subtract cent[] from it) */
+ rv = -(t->pe[0] * s->cent[0] + t->pe[1] * s->cent[1] + t->pe[2] * s->cent[2] + t->pe[3])/
+ (t->pe[0] * nin[0] + t->pe[1] * nin[1] + t->pe[2] * nin[2]);
+
+#ifdef ASSERTS
+ /* check the result */
+ {
+ double tt[3];
+ double ds;
+ int j;
+ for (j = 0; j < 3; j++) /* Compute result, absolute */
+ tt[j] = nin[j] * rv + s->cent[j];
+
+ ds = t->pe[0] * tt[0]
+ + t->pe[1] * tt[1]
+ + t->pe[2] * tt[2]
+ + t->pe[3];
+
+ if (fabs(ds) > 1e-6) {
+ fprintf(stderr,"radial: distance to plane not zero! %e\n",ds);
+ exit(-1);
+ }
+
+ /* Check if the closest point is within this triangle */
+ for (j = 0; j < 3; j++) {
+ double ds;
+ ds = t->ee[j][0] * (tt[0] - s->cent[0])
+ + t->ee[j][1] * (tt[1] - s->cent[1])
+ + t->ee[j][2] * (tt[2] - s->cent[2])
+ + t->ee[j][3];
+ if (ds > 1e-8) {
+ fprintf(stderr,"radial: lookup point wasn't within its triangle (%f) !!\n",ds);
+ exit(-1);
+ }
+ }
+ }
+#endif /* ASSERTS */
+
+//if (trace) printf("~1 radial_point: rv = %f\n",rv);
+ return rv;
+}
+
+/* Recursively free a gbsp node and all its children */
+static void del_gbsp(gbsp *n) {
+ int tag = n->tag;
+
+ if (tag == 1) { /* Another decision node */
+ gbspn *dn = (gbspn *)n;
+ del_gbsp(dn->po); /* Delete children */
+ del_gbsp(dn->ne);
+ del_gbspn(dn); /* And itself */
+
+ } else if (tag == 3) { /* If a triangle list */
+ gbspl *dl = (gbspl *)n;
+ del_gbspl(dl); /* Delete itself */
+ }
+
+ /* Don't delete triangles (tag == 2) since they */
+ /* have their own linked list, and may have already been deleted. */
+ /* Note we need to be called _before_ triangles are deleted though, */
+ /* since we access them to get the tag. */
+}
+
+/* =================================== */
+/* Given a point, */
+/* return the nearest point on the gamut surface. */
+
+#define GNN_INF 1e307
+static void init_ne(gamut *s);
+
+/* Given an absolute point, return the point on the gamut */
+/* surface that is closest to it. */
+/* Use a brute force search */
+static void
+nearest_bf(
+gamut *s,
+double *out, /* result point (absolute) */
+double *q /* Target point (absolute) */
+) {
+ gtri *tp;
+ double bdist = 1e308; /* Best possible distance to an object outside the window */
+
+
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ double r[3]; /* Possible solution point */
+ double tdist;
+
+ /* Compute distance from query point to this object */
+ tdist = ne_point_on_tri(s, tp, r, q);
+
+ if (tdist < bdist) { /* New best point */
+ bdist = tdist;
+ out[0] = r[0];
+ out[1] = r[1];
+ out[2] = r[2];
+ }
+ } END_FOR_ALL_ITEMS(tp);
+}
+
+/* Using nearest neighbourhood accelleration structure: */
+
+/* Given an absolute point, return the point on the gamut */
+/* surface that is closest to it. */
+static void
+nearest_tri(
+gamut *s,
+double *rout, /* result point (absolute) */
+double *q, /* Target point (absolute) */
+gtri **ctri /* If not NULL, return pointer to nearest triangle */
+) {
+ gnn *p; /* Pointer to nearest neighbor structure */
+ int e, i;
+ double r[3] = {0.0, 0.0, 0.0 }; /* Possible solution point */
+ double out[3] = {0.0, 0.0, 0.0}; /* Current best output value */
+ int wex[3 * 2]; /* Current window edge indexes */
+ double wed[3 * 2]; /* Current window edge distances */
+ /* Indexes are axis * 2 +0 for lower edge, */
+ /* +1 for upper edge of search box. */
+ /* We are comparing lower edge of search box */
+ /* with upper edge of bounding box etc. */
+
+//printf("~1 nearest called\n");
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ /* We have to find out which triangle the point will be nearest */
+ if (s->ne_inited == 0) {
+ init_ne(s); /* Init nn structure */
+ }
+ p = s->nns;
+
+ if ((p->tbase + 3) < p->tbase) { /* Overflow of touch count */
+ for (i = 0; i < p->n; i++)
+ p->sax[0][i]->touch = 0; /* reset it in all the objects */
+ p->tbase = 0;
+ }
+ p->ttarget = p->tbase + 3; /* Target touch value */
+
+//printf("\n");
+//printf("Query point is %f %f %f\n",q[0], q[1], q[2]);
+
+ /* Find starting indexes within axis arrays */
+ for (e = 0; e < (2 * 3); e++) { /* For all axes min & max */
+ int f = e/2; /* Axis */
+ int mm = (e ^ 1) & 1; /* Min/Max index used for edges */
+ int i0, i1, i2;
+ double v0, v1, v2;
+ double qf, ww;
+
+ /* Binary search this edge */
+ qf = q[f]; /* strength reduced q[f] */
+
+//printf("\n");
+//printf("isearching axis %d %s for %f\n",f, e & 1 ? "max" : "min", qf);
+ i0 = 0;
+ i2 = p->n - 1;
+ v0 = p->sax[e][i0]->mix[mm][f];
+ v2 = p->sax[e][i2]->mix[mm][f];
+//printf("start points %d - %d, bound %f - %f\n",i0, i2, v0, v2);
+
+ if (qf <= v0) {
+ i2 = i0;
+ v2 = v0;
+ } else if (qf >= v2) {
+ i0 = i2;
+ v0 = v2;
+ } else {
+ do {
+ i1 = (i2 + i0)/2; /* Trial point */
+ v1 = p->sax[e][i1]->mix[mm][f]; /* Value at trial */
+ if (v1 < qf) {
+ i0 = i1; /* Take top half */
+ v0 = v1;
+ } else {
+ i2 = i1; /* Take bottom half */
+ v2 = v1;
+ }
+//printf("current point %d - %d, bound %f - %f\n",i0, i2, v0, v2);
+ } while ((i2 - i0) > 1);
+ }
+
+ if (e & 1) { /* Max side of window */
+ int tc; /* total object count */
+
+ ww = v2 - qf;
+ wed[e] = fabs(ww) * ww;
+ wex[e] = i2;
+
+ /* Check that min and max together will cover at least p->n objects */
+ tc = p->n - i2 + wex[e ^ 1] + 1;
+//printf("got %d, expected %d\n",tc, p->n);
+
+ /* (I don't really understand why this works!) */
+ if (tc < p->n) { /* We haven't accounted for all the objects */
+ int el = e ^ 1; /* Low side sax */
+ int ti0, ti2;
+ double tv0, tv2;
+
+ ti0 = wex[el];
+ ti2 = i2;
+//printf("We have straddling objects, initial indexes are %d - %d\n",ti0, ti2);
+
+ /* While straddling objects remain undiscovered: */
+ while (tc < p->n) {
+ tv0 = GNN_INF; /* Guard values */
+ tv2 = -GNN_INF;
+
+ /* Increment low side until we find a straddler */
+ while (ti0 < (p->n-1)) {
+ ww = p->sax[el][++ti0]->mix[0][f]; /* Position of the other end */
+ if (ww < qf) {
+//printf("found low object %d at index %d that straddles\n",p->sax[el][ti0]->n,ti0);
+ tv0 = qf - p->sax[el][ti0]->mix[1][f];
+ break;
+ }
+ }
+
+ /* Decrement high side until we find a straddler */
+ while (ti2 > 0) {
+ ww = p->sax[e][--ti2]->mix[1][f]; /* Position of the other end */
+ if (ww > qf) {
+//printf("found high object %d at index %d that straddles\n",p->sax[e][ti2]->n,ti2);
+ tv2 = p->sax[e][ti2]->mix[0][f] - qf;
+ break;
+ }
+ }
+ /* Choose the closest */
+ if (tv0 > tv2) {
+ wed[el] = fabs(tv0) * tv0;
+ wex[el] = ti0;
+ tc++;
+ } else {
+ wed[e] = fabs(tv2) * tv2;
+ wex[e] = ti2;
+ tc++;
+ }
+ }
+//printf("After correction we have %d - %d\n",wex[e^1], wex[e]);
+ }
+ } else { /* Min side of window */
+ ww = q[f] - v0;
+ wed[e] = fabs(ww) * ww;
+ wex[e] = i0;
+ }
+ }
+
+ /* Expand a 3 dimenstional cube centered on the target point, */
+ /* jumping to the next nearest point on any axis, discovering */
+ /* any bounding boxes that are within the expanding window */
+ /* by checking their touch count. */
+
+ /* The first point found establishes the initial best distance. */
+ /* When the window expands beyond the point where it can improve */
+ /* the best distance, stop */
+
+ {
+ double bw = 0.0; /* Current window distance */
+ double bdist = 1e308; /* Best possible distance to an object outside the window */
+ gtri *bobj = NULL;
+ int ptested = 0; /* Stats */
+ int pcalced = 0; /* Stats */
+
+ /* Until we're done */
+ for (;;ptested++) {
+ int ee; /* Axis & expanding box edge */
+ int ff; /* Axis */
+ int ii; /* Index of chosen point */
+ gtri *ob; /* Current object */
+ unsigned int ctv; /* Current touch value */
+//printf("\n");
+//printf("wwidth = %f, bdist = %f, window = %d-%d, %d-%d, %d-%d\n",
+//bw, bobj == NULL ? 0.0 : bdist, wex[0], wex[1], wex[2], wex[3], wex[4], wex[5]);
+//printf("window edge distances are = %f-%f, %f-%f, %f-%f\n",
+//wed[0], wed[1], wed[2], wed[3], wed[4], wed[5]);
+
+ /* find next (smallest) window increment axis and direction */
+ ee = 0;
+ ii = wex[ee];
+ bw = wed[ee];
+ for (e = 1; e < (2 * 3); e++) {
+ if (wed[e] < bw) {
+ ee = e;
+ ii = wex[e];
+ bw = wed[e];
+ }
+ }
+//printf("Next best is axisdir %d, object %d, axis index %d, best possible dist %f\n",
+//ee, p->sax[ee][ii]->n, ii, bw);
+
+ if (bw == GNN_INF || bw > bdist) {
+ break; /* Can't got any further, or further points will be worse */
+ }
+
+#ifdef ASSERTS
+ if (ii < 0 || ii >= p->n) {
+ printf("Assert: went out of bounds of sorted axis array\n");
+ exit(0);
+ }
+#endif
+ /* Chosen point on ee axis/direction, index ii */
+ ff = ee / 2; /* Axis only */
+
+ ob = p->sax[ee][ii];
+
+ /* Touch value of current object */
+ ctv = ob->touch;
+
+ if (ctv < p->ttarget) { /* Not been dealt with before */
+
+ /* Touch this new window boundary point */
+ ob->touch = ctv = ((ctv < p->tbase) ? p->tbase : ctv) + 1;
+
+//printf("New touch count on %d is %d, target %d\n", ob->n, p->sax[ee][ii]->touch, p->ttarget);
+
+ /* Check the point out */
+ if (ctv == (p->tbase + 3)) { /* Is within window on all axes */
+ double tdist;
+
+ pcalced++; /* Stats */
+
+ /* Compute distance from query point to this object */
+ tdist = ne_point_on_tri(s, ob, r, q);
+
+//printf("Got new best point %d, dist %f\n",i,tdist);
+ if (tdist < bdist) { /* New best point */
+ bobj = ob;
+ bdist = tdist;
+ out[0] = r[0];
+ out[1] = r[1];
+ out[2] = r[2];
+ }
+ }
+ }
+
+ /* Increment next window edge candidate, and figure new edge distance */
+ if (ee & 1) { /* Top */
+ if (++wex[ee] >= p->n) {
+ wed[ee] = GNN_INF;
+ wex[ee]--;
+ } else {
+ double ww = p->sax[ee][wex[ee]]->mix[0][ff] - q[ff];
+ wed[ee] = fabs(ww) * ww;
+ }
+ } else {
+ if (--wex[ee] < 0) {
+ wed[ee] = GNN_INF;
+ wex[ee]++;
+ } else {
+ double ww = q[ff] - p->sax[ee][wex[ee]]->mix[1][ff];
+ wed[ee] = fabs(ww) * ww;
+ }
+ }
+ }
+
+//printf("Searched %d points out of %d = %f%%\n",ptested, p->n, 100.0 * ptested/p->n);
+
+ p->tbase += 3; /* Next touch */
+
+ if (rout != NULL) {
+ rout[0] = out[0]; /* Copy results to output */
+ rout[1] = out[1];
+ rout[2] = out[2];
+ }
+
+ if (ctri != NULL)
+ *ctri = bobj;
+
+ return;
+ }
+}
+
+/* Given an absolute point, return the point on the gamut */
+/* surface that is closest to it. */
+static void
+nearest(
+gamut *s,
+double *rout, /* result point (absolute) */
+double *q /* Target point (absolute) */
+) {
+ nearest_tri(s, rout, q, NULL);
+}
+
+/* Perturb the containment points to avoid */
+/* numerical co-incidence */
+double perturb[21] = {
+ 8.9919295344233395e-283, 1.1639766020018968e+224, 1.2554893023590904e+232,
+ 2.3898157055642966e+190, 1.5697612415774029e-076, 6.6912978722191457e+281,
+ 1.2369092402930559e+277, 1.4430907501246712e-153, 3.0017439193018232e+238,
+ 1.2978311824382444e+161, 5.5068703318775818e-311, 7.7791723264448801e-260,
+ 4.4296571592384350e+281, 8.9481529920968425e+165, 1.2845894914769635e-153,
+ 2.0835868791190880e-076, 5.4310198502711138e+241, 4.8689849775675438e+275,
+ 9.2709981544886391e+122, 3.7958270103353899e-153, 7.1366083837501666e-154
+};
+
+/* Setup the nearest function acceleration structure */
+static void
+init_ne(
+gamut *s
+) {
+ gnn *p;
+ int i, k;
+ gtri *tp; /* Triangle pointer */
+ int ntris;
+ double psf;
+
+//printf("~1 init_ne called\n");
+
+ /* Allocate the nearest neighbor acceleration structure */
+ if ((s->nns = p = (gnn *) calloc(1, sizeof(gnn))) == NULL) {
+ fprintf(stderr,"gamut: calloc failed - gnn structure\n");
+ exit(-1);
+ }
+
+ /* Count triangles */
+ ntris = 0;
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ ntris++;
+ } END_FOR_ALL_ITEMS(tp);
+
+ p->n = ntris;
+ p->tbase = 0; /* Initialse touch flag */
+
+ /* Allocate the arrays spaces */
+ for (k = 0; k < (3 * 2); k++) {
+ if ((p->sax[k] = (gtri **)malloc(sizeof(gtri *) * ntris)) == NULL)
+ error("Failed to allocate sorted index array");
+ }
+
+ /* Compute pertbation factor */
+ for (psf = 0.0, i = 1; i < 21; i++)
+ psf += perturb[i];
+ psf *= perturb[0];
+
+ /* For each triangle, create the triangle bounding box values, */
+ /* and add them to the axis lists. */
+ tp = s->tris;
+ i = 0;
+ FOR_ALL_ITEMS(gtri, tp) {
+ int j;
+ for (j = 0; j < 3; j++) { /* Init */
+ tp->mix[0][j] = 1e38;
+ tp->mix[1][j] = -1e38;
+ }
+ for (k = 0; k < 3; k++) {
+ for (j = 0; j < 3; j++) {
+ if (tp->v[k]->p[j] < tp->mix[0][j]) /* New min */
+ tp->mix[0][j] = psf * tp->v[k]->p[j];
+ if (tp->v[k]->p[j] > tp->mix[1][j]) /* New max */
+ tp->mix[1][j] = psf * tp->v[k]->p[j];
+ }
+ p->sax[k * 2 + 0][i] = tp;
+ p->sax[k * 2 + 1][i] = tp;
+ }
+//printf("~1 tri %d has bb %f - %f, %f - %f, %f - %f\n", i, tp->mix[0][0], tp->mix[1][0], tp->mix[0][1], tp->mix[1][1], tp->mix[0][2], tp->mix[1][2]);
+ i++;
+ } END_FOR_ALL_ITEMS(tp);
+
+
+ /* Sort the axis arrays */
+ for (k = 0; k < 3; k++) {
+
+ /* Sort upper edges of bounding box */
+#define HEAP_COMPARE(A,B) (A->mix[1][k] < B->mix[1][k])
+ HEAPSORT(gtri *, &p->sax[k * 2 + 0][0], ntris)
+#undef HEAP_COMPARE
+
+ /* Sort lower edges of bounding box */
+#define HEAP_COMPARE(A,B) (A->mix[0][k] < B->mix[0][k])
+ HEAPSORT(gtri *, &p->sax[k * 2 + 1][0], ntris)
+#undef HEAP_COMPARE
+ }
+ s->ne_inited = 1;
+
+//printf("~1 init_ne done\n");
+}
+
+/* Free everything */
+static void del_gnn(gnn *p) {
+ int k;
+
+ for (k = 0; k < (3 * 2); k++) {
+ free (p->sax[k]);
+ }
+
+ free(p);
+}
+
+/* ===================================================== */
+/* Define the colorspaces white and black point. May be NULL if unknown. */
+/* Note that as in all of the gamut library, we assume that we are in */
+/* an L*a*b* or Jab type color space. */
+static void setwb(
+gamut *s,
+double *wp,
+double *bp,
+double *kp
+) {
+ if (wp != NULL) {
+ s->cs_wp[0] = wp[0];
+ s->cs_wp[1] = wp[1];
+ s->cs_wp[2] = wp[2];
+ } else {
+ s->cs_wp[0] = 100.0;
+ s->cs_wp[1] = 0.0;
+ s->cs_wp[2] = 0.0;
+ }
+
+ if (bp != NULL) {
+ s->cs_bp[0] = bp[0];
+ s->cs_bp[1] = bp[1];
+ s->cs_bp[2] = bp[2];
+ } else {
+ s->cs_bp[0] = 0.0;
+ s->cs_bp[1] = 0.0;
+ s->cs_bp[2] = 0.0;
+ }
+
+ if (kp != NULL) {
+ s->cs_kp[0] = kp[0];
+ s->cs_kp[1] = kp[1];
+ s->cs_kp[2] = kp[2];
+ } else {
+ s->cs_kp[0] = s->cs_bp[0];
+ s->cs_kp[1] = s->cs_bp[1];
+ s->cs_kp[2] = s->cs_bp[2];
+ }
+
+ s->cswbset = 1;
+}
+
+
+/* Compute the gamut white/black points, assuming */
+/* that the colorspace white/black points have been set. */
+/* The gamut white/black are the points on the colorspace */
+/* white/black axis that have the same L values as the */
+/* extremes within the gamut. */
+static void compgawb(gamut *s) {
+ int i;
+ double ff, Lmax, Lmin, LKmin;
+
+ if (s->cswbset == 0 || s->gawbset != 0)
+ return; /* Nothing to do */
+
+ Lmax = -1000.0;
+ Lmin = 1000.0;
+
+ /* Discover min and max L values */
+ for (i = 0; i < s->nv; i++) {
+ if ((s->verts[i]->f & GVERT_SET) == 0 )
+ continue;
+
+ if (s->verts[i]->p[0] > Lmax)
+ Lmax = s->verts[i]->p[0];
+ if (s->verts[i]->p[0] < Lmin)
+ Lmin = s->verts[i]->p[0];
+ }
+
+ LKmin = Lmin;
+
+ if (Lmax > s->cs_wp[0]) /* Slightly Strange */
+ Lmax = s->cs_wp[0];
+ if (Lmin < s->cs_bp[0]) /* Also Slightly strange */
+ Lmin = s->cs_bp[0];
+ if (LKmin < s->cs_kp[0]) /* Expected */
+ LKmin = s->cs_kp[0];
+
+ /* Locate points along colorspace grey axis */
+ /* that correspond to the L extremes */
+ ff = (Lmax - s->cs_bp[0])/(s->cs_wp[0] - s->cs_bp[0]);
+ s->ga_wp[0] = Lmax;
+ s->ga_wp[1] = ff * (s->cs_wp[1] - s->cs_bp[1]) + s->cs_bp[1];
+ s->ga_wp[2] = ff * (s->cs_wp[2] - s->cs_bp[2]) + s->cs_bp[2];
+
+ ff = (Lmin - s->cs_bp[0])/(s->cs_wp[0] - s->cs_bp[0]);
+ s->ga_bp[0] = Lmin;
+ s->ga_bp[1] = ff * (s->cs_wp[1] - s->cs_bp[1]) + s->cs_bp[1];
+ s->ga_bp[2] = ff * (s->cs_wp[2] - s->cs_bp[2]) + s->cs_bp[2];
+
+ ff = (LKmin - s->cs_kp[0])/(s->cs_wp[0] - s->cs_kp[0]);
+ s->ga_kp[0] = LKmin;
+ s->ga_kp[1] = ff * (s->cs_wp[1] - s->cs_kp[1]) + s->cs_kp[1];
+ s->ga_kp[2] = ff * (s->cs_wp[2] - s->cs_kp[2]) + s->cs_kp[2];
+
+ s->gawbset = 1;
+}
+
+/* Get the colorspace and gamut white & black points. */
+/* Return pointers may be NULL */
+/* Return non-zero if not possible. */
+static int getwb(
+gamut *s,
+double *cswp, /* Color space */
+double *csbp,
+double *cskp,
+double *gawp, /* Gamut */
+double *gabp,
+double *gakp
+) {
+//printf("~1 getwb() called\n");
+ if (s->cswbset == 0) {
+ return 1;
+ }
+
+ if (cswp != NULL) {
+ cswp[0] = s->cs_wp[0];
+ cswp[1] = s->cs_wp[1];
+ cswp[2] = s->cs_wp[2];
+ }
+
+ if (csbp != NULL) {
+ csbp[0] = s->cs_bp[0];
+ csbp[1] = s->cs_bp[1];
+ csbp[2] = s->cs_bp[2];
+ }
+
+ if (cskp != NULL) {
+ cskp[0] = s->cs_kp[0];
+ cskp[1] = s->cs_kp[1];
+ cskp[2] = s->cs_kp[2];
+ }
+//printf("~1 colorspace white %f %f %f, black %f %f %f, kblack %f %f %f\n", s->cs_wp[0], s->cs_wp[1], s->cs_wp[2], s->cs_bp[0], s->cs_bp[1], s->cs_bp[2], s->cs_kp[0],s->cs_kp[1],s->cs_kp[2]);
+
+ if (gawp != NULL || gabp != NULL) {
+//printf("~1 computing gamut white & black\n");
+ compgawb(s); /* make sure we have gamut white/black available */
+ }
+
+ if (gawp != NULL) {
+ gawp[0] = s->ga_wp[0];
+ gawp[1] = s->ga_wp[1];
+ gawp[2] = s->ga_wp[2];
+ }
+
+ if (gabp != NULL) {
+ gabp[0] = s->ga_bp[0];
+ gabp[1] = s->ga_bp[1];
+ gabp[2] = s->ga_bp[2];
+ }
+
+ if (gakp != NULL) {
+ gakp[0] = s->ga_kp[0];
+ gakp[1] = s->ga_kp[1];
+ gakp[2] = s->ga_kp[2];
+ }
+//printf("~1 gamut white %f %f %f, black %f %f %f, kblack %f %f %f\n", s->ga_wp[0], s->ga_wp[1], s->ga_wp[2], s->ga_bp[0], s->ga_bp[1], s->ga_bp[2], s->ga_kp[0],s->ga_kp[1],s->ga_kp[2]);
+
+ return 0;
+}
+
+
+/* ---------------------------------------------------- */
+/* Per-triangle primitives used to compute brute force */
+/* radial & vector intersection and nearest point, */
+/* as well as gamut surface intersections. */
+/* See if the given triangle intersect the given vector. */
+/* Return 1 if it does, 0 if it doesn't */
+static int vect_intersect(
+gamut *s,
+double *rvp, /* parameter, 0.0 = p1, 1.0 = p2 */
+double *ip, /* return intersection point */
+double *p1, /* First point of vector (ie black) */
+double *p2, /* Second point of vector (ie white) */
+gtri *t /* Triangle in question */
+) {
+ double ti; /* Axis parameter value */
+ double vv[3]; /* vector vector */
+ double ival[3]; /* Intersection value */
+ double den;
+ int j;
+
+ vv[0] = p2[0] - p1[0];
+ vv[1] = p2[1] - p1[1];
+ vv[2] = p2[2] - p1[2];
+
+ den = t->pe[0] * vv[0] + t->pe[1] * vv[1] + t->pe[2] * vv[2];
+ if (fabs(den) < 1e-10) {
+ return 0;
+ }
+
+ /* Compute the intersection of the grey axis vector with the triangle plane */
+ ti = -(t->pe[0] * p1[0] + t->pe[1] * p1[1] + t->pe[2] * p1[2] + t->pe[3])/den;
+
+ /* Compute the actual intersection point */
+ ival[0] = p1[0] + ti * vv[0];
+ ival[1] = p1[1] + ti * vv[1];
+ ival[2] = p1[2] + ti * vv[2];
+
+ /* Check if the intersection point is within the triangle */
+ for (j = 0; j < 3; j++) {
+ double ds;
+ ds = t->ee[j][0] * (ival[0] - s->cent[0]) /* Convert to relative for edge check */
+ + t->ee[j][1] * (ival[1] - s->cent[1])
+ + t->ee[j][2] * (ival[2] - s->cent[2])
+ + t->ee[j][3];
+ if (ds > 1e-8) {
+ return 0; /* Not within triangle */
+ }
+ }
+//printf("~1 vect_intersect got intersection with tri %d at %f\n",t->n,ti);
+
+ /* Got an intersection point */
+ ip[0] = ival[0];
+ ip[1] = ival[1];
+ ip[2] = ival[2];
+
+ *rvp = ti;
+
+ return 1;
+}
+
+/* Given a point and a triangle, return the closest point on */
+/* the triangle closest to the given point. Also return the distance squared */
+/* (Doesn't depend on triangle edge info) */
+static double ne_point_on_tri(
+gamut *s,
+gtri *t, /* Triangle to use */
+double *out, /* Absolute output point */
+double *in /* Absolute input point */
+) {
+ int j;
+ double rv;
+ double bdist;
+
+ /* Compute the point on the triangles plane, that is orthogonal */
+ /* (closest) to the target point. */
+ rv = (t->pe[0] * in[0] + t->pe[1] * in[1] + t->pe[2] * in[2] + t->pe[3])/
+ (t->pe[0] * t->pe[0] + t->pe[1] * t->pe[1] + t->pe[2] * t->pe[2]);
+
+ out[0] = in[0] - rv * t->pe[0];
+ out[1] = in[1] - rv * t->pe[1];
+ out[2] = in[2] - rv * t->pe[2];
+
+ /* Check if the closest point is within this triangle */
+ for (j = 0; j < 3; j++) {
+ double ds;
+ ds = t->ee[j][0] * (out[0] - s->cent[0]) /* Convert to relative for edge check */
+ + t->ee[j][1] * (out[1] - s->cent[1])
+ + t->ee[j][2] * (out[2] - s->cent[2])
+ + t->ee[j][3];
+ if (ds > 1e-8) {
+ break; /* Not within triangle */
+ }
+ }
+ if (j >= 3) { /* It's OK */
+ return rv * rv; /* rv is distance since pe length is 1.0 */
+ }
+
+ /* Not in triangle, so find closest point along any edge, */
+ /* or at the verticies. (don't use edge info, it may not be set up) */
+ bdist = 1e38;
+ for (j = 0; j < 3; j++) { /* For each edge */
+ gvert *v0 = t->v[j], *v1 = t->v[j >= 2 ? 0 : j+1];
+ int k;
+ double nu, de, ds;
+ for (de = 0.0, k = 0; k < 3; k++) {
+ double tt = v1->p[k] - v0->p[k];
+ de += tt * tt;
+ }
+ for (nu = 0.0, k = 0; k < 3; k++)
+ nu += (v1->p[k] - v0->p[k]) * (in[k] - v0->p[k]);
+
+ ds = nu/de;
+
+ if (ds >= 0.0 && ds <= 1.0) { /* Valid edge */
+ double tout[3], ss;
+ for (ss = 0.0, k = 0; k < 3; k++) {
+ tout[k] = v0->p[k] + ds * (v1->p[k] - v0->p[k]);
+ ss += (in[k] - tout[k]) * (in[k] - tout[k]);
+ }
+ if (ss < bdist) {
+ bdist = ss;
+ out[0] = tout[0];
+ out[1] = tout[1];
+ out[2] = tout[2];
+ }
+ }
+ }
+
+ for (j = 0; j < 3; j++) { /* For each vertex */
+ int k;
+ double ss;
+ for (ss = 0.0, k = 0; k < 3; k++) {
+ double tt;
+ tt = in[k] - t->v[j]->p[k];
+ ss += tt * tt;
+ }
+
+ if (ss < bdist) {
+ bdist = ss;
+ out[0] = t->v[j]->p[0];
+ out[1] = t->v[j]->p[1];
+ out[2] = t->v[j]->p[2];
+ }
+ }
+
+ return bdist;
+}
+
+/* ----------------------------------------------------- */
+/* Arbitrary vector intersect */
+
+/* Given a vector, find the two extreme intersection with */
+/* the gamut surface using a brute force search. */
+/* Return 0 if there is no intersection */
+static int compute_vector_isect_bf(
+gamut *s,
+double *p1, /* First point (ie black) */
+double *p2, /* Second point (ie white) */
+double *omin, /* Return gamut surface points, min = closest to p1 */
+double *omax, /* max = farthest from p1 */
+double *omnt, /* Return parameter values for p1 and p2, 0 being at p1, */
+double *omxt, /* and 1 being at p2 */
+gtri **omntri, /* Return the intersection triangles */
+gtri **omxtri
+) {
+ gtri *tp, *t0, *t1;
+ double ip[3], min[3], max[3];
+ double mint, maxt;
+ int j;
+
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ maxt = -1e68; /* Setup to find min/max */
+ mint = 1e68;
+
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ double rv;
+ if (vect_intersect(s, &rv, ip, p1, p2, tp)) {
+ if (rv < mint) {
+ min[0] = ip[0];
+ min[1] = ip[1];
+ min[2] = ip[2];
+ mint = rv;
+ t0 = tp;
+ }
+ if (rv > maxt) {
+ max[0] = ip[0];
+ max[1] = ip[1];
+ max[2] = ip[2];
+ maxt = rv;
+ t1 = tp;
+ }
+ }
+ } END_FOR_ALL_ITEMS(tp);
+
+ if (((omin != NULL || omnt != NULL || omntri != NULL) && mint == 1e68)
+ || ((omax != NULL || omxt != NULL || omxtri != NULL) && maxt == -1e68)) {
+ return 0;
+ }
+
+ if (omin != NULL)
+ for (j = 0; j < 3; j++)
+ omin[j] = min[j];
+
+ if (omax != NULL)
+ for (j = 0; j < 3; j++)
+ omax[j] = max[j];
+
+ if (omnt != NULL)
+ *omnt = mint;
+
+ if (omxt != NULL)
+ *omxt = maxt;
+
+ if (omntri != NULL)
+ *omntri = t0;
+
+ if (omxtri != NULL)
+ *omxtri = t1;
+
+ return 1;
+}
+
+
+#ifdef INTERSECT_DEBUG
+
+#define ISDBG(xxx) if (deb_insect) printf xxx
+
+int deb_insect = 0; /* Do vrml plot */
+
+/* Debug - given a BSP node, add all the triangles vertexes indexes */
+/* below this node to the diagnosti wrl */
+static void debug_bsp_triangl_wrl(
+gamut *s,
+gbsp *np, /* BSP node pointer we're at */
+vrml *wrl /* Diagnostic plot */
+) {
+ if (np->tag == 1) { /* It's a BSP node */
+ gbspn *n = (gbspn *)np;
+
+ debug_bsp_triangl_wrl(s, n->po, wrl);
+ debug_bsp_triangl_wrl(s, n->ne, wrl);
+
+ } else {
+ int nt; /* Number of triangles in list */
+ gtri **tpp; /* Pointer to list of triangles */
+ int i, j;
+
+ if (np->tag == 2) { /* It's a triangle */
+ tpp = &((gtri *)np);
+ nt = 1;
+ } else if (np->tag == 3) { /* It's a triangle list */
+ gbspl *n = (gbspl *)np;
+ tpp = n->t;
+ nt = n->nt;
+ }
+ /* Go through the list of triangles and intersect with vector */
+ for (i = 0; i < nt; i++, tpp++) {
+ gtri *t = *tpp;
+ int ix[3];
+
+ ix[0] = t->v[0]->tn;
+ ix[1] = t->v[1]->tn;
+ ix[2] = t->v[2]->tn;
+
+ wrl->add_triangle(wrl, 0, ix);
+ }
+ }
+}
+#else /* !INTERSECT_DEBUG */
+# define ISDBG(xxx)
+#endif /* !INTERSECT_DEBUG */
+
+/* Recursive vector intersect using BSP accelleration. */
+static void vector_isect_rec(
+gamut *s,
+gbsp *np, /* BSP node pointer we're at */
+double *vb, /* Center relative base point of vector */
+double *vv, /* Vector direction from base */
+double t0, /* Start parameter value of line */
+double rs0, /* line start point radius squared */
+double t1, /* End parameter value of line */
+double rs1, /* line end point radius squared */
+double tc, /* Parameter value of closest point on line to center */
+double rsc, /* Radius squared of closest point on line to center */
+double rse0, /* Effective radius squared minimum */
+double rse1, /* Effective radius squared maximum */
+gispnt *lp, /* List to set intersections in. */
+int ll, /* Size of list. 0 == 2, min and max only */
+int *lu /* Number used in list */
+) {
+ double den; /* Intersection denominator */
+ double ti; /* Intersection parameter value */
+ double rsi; /* Radius squared of intersection point */
+ double ip[3]; /* Intersection point */
+
+#ifdef INTERSECT_DEBUG
+ if (ll == 0)
+ printf("\nvector_isect_rec got seg %f - %f (%e), best %f, %f\n",t0,t1,t1-t0,lp[0].pv,lp[1].pv);
+ else
+ printf("\nvector_isect_rec got seg %f - %f (%e), no isects %d\n",t0,t1,t1-t0,*lu);
+ printf(" rs %f, %f, tc %f, rsc %f, rse0 %f, rse1 %f, BSP rs %f - %f\n",rs0, rs1, tc, rsc, rse0, rse1, np->rs0, np->rs1);
+#endif
+#ifdef INTERSECT_DEBUG
+ if (deb_insect) {
+ vrml *wrl = NULL;
+ double cc[3] = { 1.0, 1.0, 0.0 };
+ double red[3] = { 1.0, 0.0, 0.0 };
+ double green[3] = { 0.0, 1.0, 0.0 };
+ double blue[3] = { 0.0, 0.0, 1.0 };
+ double p1[3], p2[3];
+ int i;
+
+ unlink("isect2.wrl");
+ rename("isect.wrl", "isect2.wrl");
+
+ if ((wrl = new_vrml("isect.wrl", 0)) == NULL)
+ error("New vrml failed");
+
+ /* The triangles below the BSP */
+ for (i = 0; i < s->nv; i++) {
+ if (!(s->verts[i]->f & GVERT_TRI))
+ continue;
+ wrl->add_vertex(wrl, 0, s->verts[i]->p);
+ }
+ debug_bsp_triangl_wrl(s, np, wrl);
+ wrl->make_triangles(wrl, 0, 0.0, cc);
+
+ /* The segment. The vrml browser can go crazy if the line */
+ /* is too long, so limit it to +/- 100 */
+ {
+ double vbl = icmNorm3(vb);
+ double tt0 = t0, tt1 = t1;
+ if (tt0 > 0.0) {
+ if ((tt0 * vbl) > 100.0)
+ tt0 = 100.0/vbl;
+ } else {
+ if ((tt0 * vbl) < -100.0)
+ tt0 = -100.0/vbl;
+ }
+ if (tt1 > 0.0) {
+ if ((tt1 * vbl) > 100.0)
+ tt1 = 100.0/vbl;
+ } else {
+ if ((tt1 * vbl) < -100.0)
+ tt1 = -100.0/vbl;
+ }
+ for (i = 0; i < 3; i++) {
+ p1[i] = s->cent[i] + vb[i] + tt0 * vv[i];
+ p2[i] = s->cent[i] + vb[i] + tt1 * vv[i];
+ }
+ }
+ wrl->add_col_vertex(wrl, 1, p1, red);
+ wrl->add_col_vertex(wrl, 1, p2, red);
+ wrl->make_lines(wrl, 1, 2);
+
+ /* Add two initial points */
+ for (i = 0; i < 3; i++) {
+ p1[i] = s->cent[i] + vb[i] + 0.0 * vv[i];
+ p2[i] = s->cent[i] + vb[i] + 1.0 * vv[i];
+ }
+ wrl->add_marker(wrl, p1, green, 0.5);
+ wrl->add_marker(wrl, p2, blue, 0.5);
+
+ wrl->del(wrl);
+ printf("Waiting for input after writing 'isect.wrl':\n");
+ getchar();
+
+ }
+#endif
+
+ if (np->tag == 1) { /* It's a BSP node */
+ int j;
+ gbspn *n = (gbspn *)np;
+ double ds;
+ gbsp *n1, *n2; /* next bsp to recurse to */
+ double ti1, ti2; /* Intersection parameters for recursion */
+ double rse1_0, rse1_1, rse2_0, rse2_1;
+
+ ISDBG(("vector_isect_rec at bsp node %d\n"));
+
+ /* Try and compute intersection with BSP */
+
+ den = n->pe[0] * vv[0] + n->pe[1] * vv[1] + n->pe[2] * vv[2];
+ if (fabs(den) > 1e-12) {
+ /* Compute the intersection point */
+ ti = -(n->pe[0] * vb[0] + n->pe[1] * vb[1] + n->pe[2] * vb[2] + n->pe[3])/den;
+ ISDBG(("intersects BSP plane at ti %f\n",ti));
+ }
+ if (fabs(den) < 1e-12 || ti < (t0 - 1e-6) || ti > (t1 + 1e-6)) { /* Doesn't intersect */
+ double ds; /* or intersects outside segment */
+
+ ISDBG(("doesn't intersect BSP plane within segment\n"));
+ /* Figure which side of the BSP segment is on */
+ ds = n->pe[0] * (vb[0] + 0.5 * (t0 + t1) * vv[0])
+ + n->pe[1] * (vb[1] + 0.5 * (t0 + t1) * vv[1])
+ + n->pe[2] * (vb[2] + 0.5 * (t0 + t1) * vv[2])
+ + n->pe[3];
+
+ ISDBG(("recursing down side that segment is on\n"));
+ /* And recurse approproately if it can be improved */
+ /* ???? Shouldn't we recurse down both if ds ~= 0.0 ? */
+ if (ds >= 0.0) {
+ if (rse0 <= n->po->rs1
+ && rse1 >= n->po->rs0
+ && (ll > 0 || t0 < lp[0].pv || t1 > lp[1].pv))
+ vector_isect_rec(s, n->po, vb, vv, t0, rs0, t1, rs1, tc, rsc, rse0, rse1,
+ lp, ll, lu);
+ } else {
+ if (rse0 <= n->ne->rs1
+ && rse1 >= n->ne->rs0
+ && (ll > 0 || t0 < lp[0].pv || t1 > lp[1].pv))
+ vector_isect_rec(s, n->ne, vb, vv, t0, rs0, t1, rs1, tc, rsc, rse0, rse1,
+ lp, ll, lu);
+ }
+ ISDBG(("vector_isect_rec returning\n"));
+ return;
+ }
+
+ /* Compute radius squared to center point at split point */
+ for (rsi = 0.0, j = 0; j < 3; j++) {
+ den = vb[j] + ti * vv[j];
+ rsi += den * den;
+ }
+
+ /* Compute the effective radius squared range for each segment */
+ rse1_0 = rs0;
+ rse1_1 = rs0;
+ if (rsi < rse1_0)
+ rse1_0 = rsi;
+ if (rsi > rse1_1)
+ rse1_1 = rsi;
+ if (tc >= t0 && tc <= ti) { /* Closest point is within segment */
+ if (rsc < rse1_0)
+ rse1_0 = rsc;
+ if (rsc > rse1_1)
+ rse1_1 = rsc;
+ }
+
+ rse2_0 = rsi;
+ rse2_1 = rsi;
+ if (rs1 < rse2_0)
+ rse2_0 = rs1;
+ if (rs1 > rse2_1)
+ rse2_1 = rs1;
+ if (tc >= ti && tc <= t1) { /* Closest point is within segment */
+ if (rsc < rse2_0)
+ rse2_0 = rsc;
+ if (rsc > rse2_1)
+ rse2_1 = rsc;
+ }
+
+ /* Test t0-1.0 to see what side of the BSP t0..ti is. */
+ ip[0] = vb[0] + (t0-1.0) * vv[0];
+ ip[1] = vb[1] + (t0-1.0) * vv[1];
+ ip[2] = vb[2] + (t0-1.0) * vv[2];
+
+ ds = n->pe[0] * ip[0]
+ + n->pe[1] * ip[1]
+ + n->pe[2] * ip[2]
+ + n->pe[3];
+
+ /* Because we're intersecting a line segment, we don't */
+ /* have to recurse down both sides of the BSP tree ? */
+ if (ds >= 0.0) {
+ n1 = n->po;
+ n2 = n->ne;
+ } else {
+ n1 = n->ne;
+ n2 = n->po;
+ }
+
+ /* Make sure that touching segments get properly tested */
+ ti1 = ti + 1e-7;
+ ti2 = ti - 1e-7;
+
+ /* Split the line into two segments and recurse for each. */
+ /* Don't recurse if the line can't improve either min or max. */
+ if (rse1_0 <= n1->rs1
+ && rse1_1 >= n1->rs0
+ && (ll > 0 || t0 < lp[0].pv || ti1 > lp[1].pv)) {
+ ISDBG(("recursing segment 1/2 %f .. %f\n",t0,ti1));
+ vector_isect_rec(s, n1, vb, vv, t0, rs0, ti1, rsi, tc, rsc, rse1_0, rse1_1,
+ lp, ll, lu);
+ }
+#ifdef INTERSECT_DEBUG
+ else if (deb_insect) {
+ printf("Skipped seg 1/2 because rse1_0 %f > n1->rs1 %f ? || rse1_1 %f < n1->rs0 %f\n",rse1_0,n1->rs1,rse1_1, n1->rs0);
+ if (ll == 0)
+ printf("|| ti1 %f <= t0 %f ? || ti1 %f <= omxt %f && t0 %f <= omnt %f ?\n",ti1,t0,ti1,lp[1].pv,t0,lp[0].pv);
+ else
+ printf("|| ti1 %f <= t0 %f ?\n",ti1,t0);
+ }
+#endif
+ if (rse2_0 <= n2->rs1
+ && rse2_1 >= n2->rs0
+ && (ll > 0 || ti2 < lp[0].pv || t1 > lp[1].pv)) {
+ ISDBG(("recursing segment 2/2 %f .. %f\n",ti2,t1));
+ vector_isect_rec(s, n2, vb, vv, ti2, rsi, t1, rs1, tc, rsc, rse2_0, rse2_1,
+ lp, ll, lu);
+ }
+#ifdef INTERSECT_DEBUG
+ else if (deb_insect) {
+ printf("Skipped seg 2/2 because rse2_0 %f > n2->rs1 %f ? || rse2_1 %f < n2->rs0 %f\n",rse2_0,n2->rs1,rse2_1, n2->rs0);
+ if (ll == 0)
+ printf("|| t1 %f <= ti2 %f ? || t1 %f <= omxt %f && ti2 %f <= omnt %f ?\n",t1,ti2,t1,lp[1].pv,ti2,lp[0].pv);
+ else
+ printf("|| t1 %f <= ti2 %f ?\n",t1,ti2);
+ }
+#endif
+
+ ISDBG(("vector_isect_rec returning\n"));
+ return;
+
+ /* It's a list of triangles */
+ } else {
+ int nt; /* Number of triangles in list */
+ gtri **tpp; /* Pointer to list of triangles */
+ int i, j;
+
+ if (np->tag == 2) { /* It's a triangle */
+ tpp = (gtri **)&np;
+ nt = 1;
+ } else if (np->tag == 3) { /* It's a triangle list */
+ gbspl *n = (gbspl *)np;
+ tpp = n->t;
+ nt = n->nt;
+ }
+ ISDBG(("vector_isect_rec at triangle(s) %d\n",nt));
+ /* Go through the list of triangles and intersect with vector */
+ for (i = 0; i < nt; i++, tpp++) {
+ double bds;
+ gtri *t = *tpp;
+
+ ISDBG(("triangle no %d\n",t->n));
+
+ den = t->pe[0] * vv[0] + t->pe[1] * vv[1] + t->pe[2] * vv[2];
+ if (fabs(den) < 1e-12) {
+ ISDBG(("segment is tangent to triangle\n"));
+ continue;
+ }
+
+ /* Compute the intersection of vector with the BSP plane */
+ ti = -(t->pe[0] * (vb[0] + s->cent[0])
+ + t->pe[1] * (vb[1] + s->cent[1])
+ + t->pe[2] * (vb[2] + s->cent[2])
+ + t->pe[3])/den;
+ ISDBG(("segment intersects at %f\n",ti));
+
+ /* Compute the actual (center relative) intersection point */
+ ip[0] = vb[0] + ti * vv[0];
+ ip[1] = vb[1] + ti * vv[1];
+ ip[2] = vb[2] + ti * vv[2];
+ ISDBG(("triangle intersection point %f %f %f\n",ip[0]+s->cent[0],ip[1]+s->cent[1],ip[2]+s->cent[2]));
+
+ /* Check if the intersection point is within the triangle */
+ bds = -1e6;
+ for (j = 0; j < 3; j++) {
+ double ds;
+ ds = t->ee[j][0] * ip[0]
+ + t->ee[j][1] * ip[1]
+ + t->ee[j][2] * ip[2]
+ + t->ee[j][3];
+ if (ds > 1e-8)
+ break; /* Not within triangle */
+ if (ds > bds)
+ bds = ds;
+ }
+ if (j < 3) {
+ ISDBG(("intersection not within triangle\n"));
+ continue; /* Not within triangle, so ignore */
+ }
+
+ /* Add intersection to list */
+ if (ll > 0) { /* List of all */
+ if (*lu < ll) {
+ lp[*lu].pv = ti;
+ icmAdd3(lp[*lu].ip,ip,s->cent); /* Abs. intersection point */
+ lp[*lu].dir = den > 0.0 ? 1 : 0;
+ lp[*lu].edge = bds > 0.0 ? 1 : 0;
+ lp[*lu].tri = t;
+ ISDBG(("new isect %d: pv %f, dir %d, edge %d\n",*lu,ti,lp[*lu].dir,lp[*lu].edge));
+ (*lu)++;
+ } else {
+ ISDBG(("new isect %d: List Too Short %d!!!\n",*lu,ll));
+ }
+ } else { /* Bigest/smallest list of 2 */
+ if (ti < lp[0].pv) {
+ ISDBG(("new min %f\n",ti));
+ lp[0].pv = ti;
+ icmAdd3(lp[0].ip,ip,s->cent); /* Abs. intersection point */
+ lp[0].dir = den > 0.0 ? 1 : 0;
+ lp[0].edge = bds > 0.0 ? 1 : 0;
+ lp[0].tri = t;
+ }
+ if (ti > lp[1].pv) {
+ ISDBG(("new max %f\n",ti));
+ lp[1].pv = ti;
+ icmAdd3(lp[1].ip,ip,s->cent); /* Abs. intersection point */
+ lp[1].dir = den > 0.0 ? 1 : 0;
+ lp[1].edge = bds > 0.0 ? 1 : 0;
+ lp[1].tri = t;
+ }
+ }
+ }
+ ISDBG(("vector_isect_rec returning\n"));
+ return;
+ }
+}
+
+/* Re-evaluate the intersections with an offset */
+static void reevaluate_isectns(
+gamut *s,
+gispnt *lp, /* List to set intersections in. */
+int n, /* Number to re-evaluate */
+double offset, /* Amount to offset vector */
+double *ivb, /* Center relative base point of vector */
+double *vv /* Vector direction from base */
+) {
+ double vb[3]; /* Offset vb */
+ double sv;
+ int sj, j, i;
+
+ /* Decide which way to offset base */
+ sv = -1e20;
+ for (j = 0; j < 3; j++) {
+ if (fabs(vv[j]) > sv) { /* Locate largest direction */
+ sv = fabs(vv[j]);
+ sj = j;
+ }
+ }
+
+ /* Apply the offset to other than largest */
+ for (j = 0; j < 3; j++) {
+ vb[j] = ivb[j];
+ if (j == sj)
+ continue;
+ vb[j] += offset;
+ }
+
+ for (i = 0; i < n; i++) {
+ double den, ti, ip[3], bds;
+ gtri *t = lp[i].tri;
+
+ lp[i].dir = 0;
+ lp[i].edge = 2; /* Assume no intersect */
+
+ den = t->pe[0] * vv[0] + t->pe[1] * vv[1] + t->pe[2] * vv[2];
+ if (fabs(den) < 1e-12) {
+ continue;
+ }
+
+ /* Compute the intersection of vector with the BSP plane */
+ ti = -(t->pe[0] * (vb[0] + s->cent[0])
+ + t->pe[1] * (vb[1] + s->cent[1])
+ + t->pe[2] * (vb[2] + s->cent[2])
+ + t->pe[3])/den;
+
+ /* Compute the actual intersection point */
+ ip[0] = vb[0] + ti * vv[0];
+ ip[1] = vb[1] + ti * vv[1];
+ ip[2] = vb[2] + ti * vv[2];
+
+ /* Check if the intersection point is within the triangle */
+ bds = -1e6;
+ for (j = 0; j < 3; j++) {
+ double ds;
+ ds = t->ee[j][0] * ip[0]
+ + t->ee[j][1] * ip[1]
+ + t->ee[j][2] * ip[2]
+ + t->ee[j][3];
+ if (ds > 1e-8)
+ break; /* Not within triangle */
+ if (ds > bds)
+ bds = ds;
+ }
+ if (j < 3) {
+ continue; /* Not within triangle, so ignore */
+ }
+
+ /* Update intersection info */
+ lp[i].dir = den > 0.0 ? 1 : 0;
+ lp[i].edge = bds > 0.0 ? 1 : 0;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#ifdef INTERSECT_VERIFY
+#define compute_vector_isect _compute_vector_isect
+#endif
+
+/* Given a vector, find the two extreme intersection with */
+/* the gamut surface. */
+/* BSP accellerated version */
+/* Return 0 if there is no intersection */
+static int compute_vector_isect(
+gamut *s,
+double *p1, /* First point (ie param value 0.0) */
+double *p2, /* Second point (ie param value 1.0) */
+double *omin, /* Return gamut surface points, min = closest to p1 */
+double *omax, /* max = farthest from p1 */
+double *omnt, /* Return parameter values for p1 and p2, 0 being at p1, */
+double *omxt, /* and 1 being at p2 */
+gtri **omntri, /* Return the intersection triangles */
+gtri **omxtri
+) {
+ gtri *tp;
+ double vb[3], vv[3]; /* Center relative base of vector, vector of vector */
+ double tt, t0, rs0, t1, rs1, tc, rsc;
+ double rse0, rse1; /* Effective radius squared min & max */
+ gispnt islist[2]; /* min and max result */
+ int lu = 0, j;
+ int rv = 0;
+
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ if (s->lu_inited == 0)
+ init_lu(s); /* Init BSP search tree */
+
+ /* Convert twp points to center relative base + vector direction */
+ for (tt = 0.0, j = 0; j < 3; j++) {
+ vv[j] = p2[j] - p1[j];
+ tt += vv[j] * vv[j];
+ vb[j] = p1[j] - s->cent[j]; /* relative to gamut center */
+ }
+ /* If vector is too small to have a valid direction */
+ if (tt < 1e-12) {
+ return 0;
+ }
+
+ islist[0].pv = 1e68;
+ islist[1].pv = -1e68; /* Setup to find min/max */
+ t0 = -1e6;
+ t1 = 1e6;
+
+ /* Compute radius range of segment */
+ for (rs0 = rs1 = 0.0, j = 0; j < 3; j++) {
+ tt = vb[j] + t0 * vv[j];
+ rs0 += tt * tt;
+ tt = vb[j] + t1 * vv[j];
+ rs1 += tt * tt;
+ }
+
+ /* Compute the point closest to the center */
+ tc = -(vv[0] * vb[0] + vv[1] * vb[1] + vv[2] * vb[2])
+ / (vv[0] * vv[0] + vv[1] * vv[1] + vv[2] * vv[2]);
+
+#ifdef INTERSECT_VERIFY
+ /* Check that this is correct */
+ for (tt = 0.0, j = 0; j < 3; j++) {
+ double pp;
+ pp = vb[j] + tc * vv[j];
+ tt += pp * vv[j];
+ }
+ if (fabs(tt) > 1e-5)
+ error("Failed to locate closest point on vector");
+#endif /* INTERSECT_VERIFY */
+
+ for (rsc = 0.0, j = 0; j < 3; j++) {
+ tt = vb[j] + tc * vv[j];
+ rsc += tt * tt;
+ }
+
+ /* Compute the effective min/max radius squared */
+ rse0 = rs0;
+ rse1 = rs0;
+ if (rs1 < rse0)
+ rse0 = rs1;
+ if (rs1 > rse1)
+ rse1 = rs1;
+ if (tc >= t0 && tc <= t1) { /* Closest point is within segment */
+ if (rsc < rse0)
+ rse0 = rsc;
+ if (rsc > rse1)
+ rse1 = rsc;
+ }
+
+ vector_isect_rec(s, s->lutree, vb, vv, t0, rs0, t1, rs1, tc, rsc, rse0, rse1,
+ islist, 0, &lu);
+
+ /* If we failed to locate a requested intersection */
+ if (((omin != NULL || omnt != NULL || omntri != NULL) && islist[0].pv == 1e68)
+ || ((omax != NULL || omxt != NULL || omxtri != NULL) && islist[1].pv == -1e68)) {
+ rv = 0;
+
+ } else {
+
+ if (omin != NULL) {
+ for (j = 0; j < 3; j++)
+ icmCpy3(omin,islist[0].ip);
+ ISDBG(("Fast min = %f %f %f\n", omin[0], omin[1], omin[2]));
+ }
+
+ if (omax != NULL) {
+ icmCpy3(omax,islist[1].ip);
+ ISDBG(("Fast max = %f %f %f\n", omax[0], omax[1], omax[2]));
+ }
+
+ if (omnt != NULL)
+ *omnt = islist[0].pv;
+
+ if (omxt != NULL)
+ *omxt = islist[1].pv;
+
+ if (omntri != NULL)
+ *omntri = islist[0].tri;
+
+ if (omxtri != NULL)
+ *omxtri = islist[1].tri;
+
+ rv = 1;
+ }
+
+ return rv;
+}
+
+#ifdef INTERSECT_VERIFY
+#undef compute_vector_isect
+
+/* Verifying version of above */
+static int compute_vector_isect(
+gamut *s,
+double *p1, /* First point (ie param value 0.0) */
+double *p2, /* Second point (ie param value 1.0) */
+double *omin, /* Return gamut surface points, min = closest to p1 */
+double *omax, /* max = farthest from p1 */
+double *omnt, /* Return parameter values for p1 and p2, 0 being at p1, */
+double *omxt, /* and 1 being at p2 */
+gtri **omintri, /* Return the intersection triangles */
+gtri **omaxtri
+) {
+ int rv, _rv;
+ double _omin[3];
+ double _omax[3];
+ double _omnt;
+ double _omxt;
+ gtri *_omintri;
+ gtri *_omaxtri;
+ int fail = 0;
+
+ ISDBG(("\n\n###########################################\n"));
+
+ /* Call the routine we're checking */
+ rv = _compute_vector_isect(s, p1, p2, omin, omax, omnt, omxt, omintri, omaxtri);
+
+ _rv = compute_vector_isect_bf(s, p1, p2, _omin, _omax, &_omnt, &_omxt, &_omintri, &_omaxtri);
+
+ if (rv != _rv) {
+ warning("compute_vector_isect verify: rv %d != _rv %d\n",rv,_rv);
+ fail = 1;
+ }
+
+ if (rv == 1) {
+ int j;
+ if (omnt != NULL)
+ if (fabs (*omnt - _omnt) > 1e-4) {
+ warning("compute_vector_isect verify:\n omnt %f != _omnt %f\n",*omnt,_omnt);
+ fail = 1;
+ }
+ if (omxt != NULL)
+ if (fabs (*omxt - _omxt) > 1e-4) {
+ warning("compute_vector_isect verify:\n omxt %f != _omxt %f\n",*omxt,_omxt);
+ fail = 1;
+ }
+ if (omin != NULL) {
+ ISDBG(("bf min = %f %f %f\n", _omin[0], _omin[1], _omin[2]));
+ for (j = 0; j < 3; j++) {
+ if (fabs (omin[j] - _omin[j]) > 1e-4)
+ break;
+ }
+ if (j < 3) {
+ warning("compute_vector_isect verify:\n omin %f %f %f != _omin %f %f %f\n", omin[0], omin[1], omin[2], _omin[0], _omin[1], _omin[2]);
+ fail = 1;
+ }
+ }
+ if (omax != NULL) {
+ ISDBG(("bf max = %f %f %f\n", _omax[0], _omax[1], _omax[2]));
+ for (j = 0; j < 3; j++) {
+ if (fabs (omax[j] - _omax[j]) > 1e-4)
+ break;
+ }
+ if (j < 3) {
+ warning("compute_vector_isect verify:\n omax %f %f %f != _omax %f %f %f\n", omax[0], omax[1], omax[2], _omax[0], _omax[1], _omax[2]);
+ fail = 1;
+ }
+ }
+#ifdef NEVER
+ if (omintri != NULL)
+ if (*omintri != _omintri) {
+ warning("compute_vector_isect verify:\n omintri %d != _omintri %d\n",(*omintri)->n, _omintri->n);
+ }
+ if (omaxtri != NULL)
+ if (*omaxtri != _omaxtri) {
+ warning("compute_vector_isect verify:\n omaxtri %d != _omaxtri %d\n",(*omaxtri)->n, _omaxtri->n);
+ }
+#endif /* NEVER */
+ }
+ if (fail) {
+#ifdef INTERSECT_DEBUG
+ printf("Re-running intersect with debug trace on\n");
+ deb_insect = 1;
+ _compute_vector_isect(s, p1, p2, _omin, _omax, &_omnt, &_omxt, &_omintri, &_omaxtri);
+#endif /* INTERSECT_DEBUG */
+ error("Verify failed");
+ }
+ return rv;
+}
+
+#endif /* INTERSECT_VERIFY */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute all the intersection pairs of the vector p1->p2 with */
+/* the gamut surface. lp points to an array of ll gispnt to be */
+/* filled in. If the list is too small, intersections will be */
+/* arbitrarily ignored. */
+/* Return the number of intersections set in list. This will always be even, */
+/* and there will be pairs of in/out intersections in the direction p1->p2. */
+static int compute_vector_isectns(
+gamut *s,
+double *p1, /* First point (ie param value 0.0) */
+double *p2, /* Second point (ie param value 1.0) */
+gispnt *lp, /* List to return in/out intersection pairs */
+int ll /* Size of list. */
+) {
+ gtri *tp;
+ double vb[3], vv[3]; /* Center relative base of vector, vector of vector */
+ double tt, t0, rs0, t1, rs1, tc, rsc, vscale;
+ double rse0, rse1; /* Effective radius squared min & max */
+ int lu = 0, i, j, k, m, pdir;
+ int rv = 0;
+
+#ifdef INTERSECT_DEBUG
+ printf("compute_vector_isectns p1 %f %f %f, p2 %f %f %f\n", p1[0], p1[1], p1[2], p2[0], p2[1], p2[2]);
+#endif
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ if (s->lu_inited == 0)
+ init_lu(s); /* Init BSP search tree */
+
+ /* Convert twp points to relative base + vector direction */
+ for (tt = 0.0, j = 0; j < 3; j++) {
+ vv[j] = p2[j] - p1[j];
+ tt += vv[j] * vv[j];
+ vb[j] = p1[j] - s->cent[j]; /* relative to gamut center */
+ }
+ /* If vector is too small to have a valid direction, give up */
+ if (tt < 1e-12) {
+#ifdef INTERSECT_DEBUG
+ printf("p2 too close to p1\n");
+#endif
+ return 0;
+ }
+
+ /* Scale factor to make parameter delta = gamut space unit */
+ vscale = 1.0/sqrt(tt);
+
+ t0 = -1e6 * vscale; /* Set the parameter search space */
+ t1 = 1e6 * vscale;
+
+ /* Compute radius range of segment */
+ for (rs0 = rs1 = 0.0, j = 0; j < 3; j++) {
+ tt = vb[j] + t0 * vv[j];
+ rs0 += tt * tt;
+ tt = vb[j] + t1 * vv[j];
+ rs1 += tt * tt;
+ }
+
+ /* Compute the point closest to the center */
+ tc = -(vv[0] * vb[0] + vv[1] * vb[1] + vv[2] * vb[2])
+ / (vv[0] * vv[0] + vv[1] * vv[1] + vv[2] * vv[2]);
+
+#ifdef INTERSECT_DEBUG
+ /* Check that this is correct */
+ for (tt = 0.0, j = 0; j < 3; j++) {
+ double pp;
+ pp = vb[j] + tc * vv[j];
+ tt += pp * vv[j];
+ }
+ if (fabs(tt) > 1e-5)
+ error("Failed to locate closest point on vector");
+#endif /* INTERSECT_DEBUG */
+
+ for (rsc = 0.0, j = 0; j < 3; j++) {
+ tt = vb[j] + tc * vv[j];
+ rsc += tt * tt;
+ }
+
+ /* Compute the effective min/max radius squared */
+ rse0 = rs0;
+ rse1 = rs0;
+ if (rs1 < rse0)
+ rse0 = rs1;
+ if (rs1 > rse1)
+ rse1 = rs1;
+ if (tc >= t0 && tc <= t1) { /* Closest point is within segment */
+ if (rsc < rse0)
+ rse0 = rsc;
+ if (rsc > rse1)
+ rse1 = rsc;
+ }
+
+ /* Recursively locate all the triangle intersections using BSP */
+ vector_isect_rec(s, s->lutree, vb, vv, t0, rs0, t1, rs1, tc, rsc, rse0, rse1,
+ lp, ll, &lu);
+
+ if (lu <= 1) {
+#ifdef INTERSECT_DEBUG
+ printf("%d intersections found\n",lu);
+#endif
+ return 0; /* Too few to be useful */
+ }
+
+ /* Now we need to turn th raw intersections into sanitized segment pairs. */
+
+ /* Sort the intersections by parameter value */
+#define HEAP_COMPARE(A,B) (A.pv < B.pv)
+ HEAPSORT(gispnt, lp, lu)
+#undef HEAP_COMPARE
+
+#ifdef INTERSECT_DEBUG
+ printf("Before sanitizing %d\n",lu);
+ for (i = 0; i < lu; i++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",i,lp[i].pv,lp[i].dir,lp[i].edge,lp[i].tri->n);
+#endif
+
+ /* Remove any duplicate intersections (triangles) */
+ for (j = i = 0; i < lu; i++) {
+
+ for (k = i+1; k < lu; k++) {
+ if (lp[k].tri == lp[i].tri) {
+ lp[k].edge &= lp[i].edge; /* Keep non-edge status */
+ break;
+ }
+ }
+ if (k < lu)
+ continue; /* Skip this one */
+
+ /* Accept this intersection */
+ memmove(&lp[j], &lp[i], sizeof(gispnt));
+ j++;
+ }
+ lu = j;
+
+ if (lu <= 1) {
+#ifdef INTERSECT_DEBUG
+ printf("%d intersections after removing duplicates\n",lu);
+#endif
+ return 0; /* Too few to be useful */
+ }
+
+#ifdef INTERSECT_DEBUG
+ printf("After removing duplicates %d\n",lu);
+ for (i = 0; i < lu; i++) {
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",i,lp[i].pv,lp[i].dir,lp[i].edge,lp[i].tri->n);
+ }
+#endif
+
+ /* Sanitize the intersections. */
+ /* We must end up with in/out segment pairs. */
+ /* j = output index, i = current index */
+ pdir = 0; /* Previous isection direction = "out" */
+ for (j = i = 0; i < lu;) {
+ int nin, nout; /* Number fully in/out */
+ int inx, outx; /* Indexes of representative in/out */
+ int npin, npout; /* Number partially in/out */
+ int pinx, poutx; /* Indexes of representative in/out */
+
+//printf("~1 at %d out of %d, %d saved\n",i,lu,j);
+ /* Two tries, re-evaluate before second try */
+ for (m = 0; m < 2; m++) {
+
+ /* See how many we have at the next pv, and */
+ /* decide if they're in, or out or both. */
+ nin = nout = npin = npout = 0;
+ for (k = i; k < lu; k++) {
+ if (i != k && fabs((lp[i].pv - lp[k].pv) * vscale) >= 0.0001)
+ break;
+ if (lp[k].dir) { /* In */
+ if (lp[k].edge == 0) {
+ nin++;
+ inx = k;
+ } else if (lp[k].edge == 1) {
+ npin++;
+ pinx = k;
+ }
+ } else { /* Out */
+ if (lp[k].edge == 0) {
+ nout++;
+ outx = k;
+ } else if (lp[k].edge == 1) {
+ npout++;
+ poutx = k;
+ }
+ }
+ }
+
+ if (m == 1 /* We've already re-evaluated */
+ || (k - i) <= 2 /* Not worth re-evaluating */
+ || (npin == 0 && npout == 0)) /* All definite */
+ break;
+
+ /* Re-evaluate the intersections with an offset. */
+ /* (We need this because often the point of interest */
+ /* is a vertex, and there are lots of intersections */
+ /* with the edges of the triangles that share that vertex) */
+ reevaluate_isectns(s, lp+i, k-i, 1e-5, vb, vv);
+
+#ifdef INTERSECT_DEBUG
+ {
+ int ii;
+ printf("After re-evaluating intersections\n");
+ for (ii = i; ii < k; ii++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",ii,lp[ii].pv,lp[ii].dir,lp[ii].edge,lp[ii].tri->n);
+ }
+#endif
+ }
+
+//printf("~1 nin %d, nout %d, npin %d, npout %d\n",nin,nout,npin,npout);
+ /* Create a zero length segment */
+ if ((k-i) > 1
+ && ((nin >= 1 && nout >= 1) /* both are definite */
+ || (nin == 0 && nout == 0 && npin >= 1 && npout >= 1) /* Both glancing */
+ || (nin == 0 && nout == 0 && npin == 0 && npout == 0)) /* No intersections now */
+ ) {
+ if (pdir != 0) { /* Not correct for segment */
+ i = k;
+//printf("~1 neither or both or uncertain\n");
+ continue; /* Discard them all */
+ }
+//printf("~1 creating zero length segment\n");
+ /* Hmm. For reasonable triangles we should really */
+ /* grab in/out from original evaluation... */
+ memmove(&lp[j], &lp[i], sizeof(gispnt));
+ lp[j].dir = 1;
+ lp[j].edge = 1;
+ j++;
+ memmove(&lp[j], &lp[i+1], sizeof(gispnt));
+ lp[j].dir = 0;
+ lp[j].edge = 1;
+ j++;
+ i = k;
+ continue;
+ }
+
+ /* We expect one conclusion */
+ if (nin >= 1)
+ i = inx;
+ else if (nout >= 1)
+ i = outx;
+ else if (npin >= 1)
+ i = pinx;
+ else /* npout >= 1 */
+ i = poutx;
+//printf("~1 using %d\n",i);
+
+ if ((lp[i].dir ^ pdir) == 0) { /* Not opposite to previous */
+//printf("~1 not opposite, discard it\n");
+ /* This shouldn't happen. */
+ i = k;
+ continue; /* Discard it */
+ }
+//printf("~1 save %d\n",i);
+ /* Accept this intersection */
+ memmove(&lp[j], &lp[i], sizeof(gispnt));
+ pdir = lp[j].dir;
+ j++;
+ i = k;
+ }
+ if (j & 1) /* Hmm. We ended up odd. This shouldn't happen. */
+ j--;
+ rv = j;
+
+#ifdef INTERSECT_DEBUG
+ if (rv == 0)
+ printf("No intersections left\n");
+ else {
+ printf("After sanitizing %d\n",rv);
+ for (i = 0; i < rv; i++)
+ printf("Isect %d: pv %f, dir %d, edge %d, tri %d\n",i,lp[i].pv,lp[i].dir,lp[i].edge,lp[i].tri->n);
+ }
+#endif
+ return rv;
+}
+
+#ifdef INTERSECT_DEBUG
+#undef ISDBG
+#endif /* INTERSECT_DEBUG */
+
+/* ===================================================== */
+/* Write to a VRML .wrl file */
+/* Return non-zero on error */
+static int write_vrml(
+gamut *s,
+char *filename,
+int doaxes, /* Non-zero if axes are to be written */
+int docusps /* Non-zero if cusp points are to be marked */
+) {
+ return write_trans_vrml(s, filename, doaxes, docusps, NULL, NULL);
+}
+
+/* Write to a VRML .wrl file */
+/* Return non-zero on error */
+static int write_trans_vrml(
+gamut *s,
+char *filename,
+int doaxes, /* Non-zero if axes are to be written */
+int docusps, /* Non-zero if cusp points are to be marked */
+void (*transform)(void *cntx, double out[3], double in[3]), /* Optional transformation callback */
+void *cntx
+) {
+ int i;
+ gtri *tp; /* Triangle pointer */
+ FILE *wrl;
+ struct {
+ double x, y, z;
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[5] = {
+ { 0 - s->cent[1], 0 - s->cent[2], 50 - s->cent[0], 2, 2, 100, .7, .7, .7 },
+ /* L axis */
+ { 50 - s->cent[1], 0 - s->cent[2], 0 - s->cent[0], 100, 2, 2, 1, 0, 0 },
+ /* +a (red) axis */
+ { 0 - s->cent[1], -50 - s->cent[2], 0 - s->cent[0], 2, 100, 2, 0, 0, 1 },
+ /* -b (blue) axis */
+ { -50 - s->cent[1], 0 - s->cent[2], 0 - s->cent[0], 100, 2, 2, 0, 1, 0 },
+ /* -a (green) axis */
+ { 0 - s->cent[1], 50 - s->cent[2], 0 - s->cent[0], 2, 100, 2, 1, 1, 0 },
+ /* +b (yellow) axis */
+ };
+
+ /* Define the labels */
+ struct {
+ double x, y, z;
+ double size;
+ char *string;
+ double r, g, b;
+ } labels[6] = {
+ { -2 - s->cent[1], 2 - s->cent[2], - s->cent[0] + 100 + 10, 10, "+L*", .7, .7, .7 },
+ /* Top of L axis */
+ { -2 - s->cent[1], 2 - s->cent[2], - s->cent[0] - 10, 10, "0", .7, .7, .7 },
+ /* Bottom of L axis */
+ { 100 + 5 - s->cent[1], -3 - s->cent[2], 0 - s->cent[0], 10, "+a*", 1, 0, 0 },
+ /* +a (red) axis */
+ { -5 - s->cent[1], -100 - 10 - s->cent[2], 0 - s->cent[0], 10, "-b*", 0, 0, 1 },
+ /* -b (blue) axis */
+ { -100 - 15 - s->cent[1], -3 - s->cent[2], 0 - s->cent[0], 10, "-a*", 0, 0, 1 },
+ /* -a (green) axis */
+ { -5 - s->cent[1], 100 + 5 - s->cent[2], 0 - s->cent[0], 10, "+b*", 1, 1, 0 },
+ /* +b (yellow) axis */
+ };
+
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ if ((wrl = fopen(filename,"w")) == NULL) {
+ fprintf(stderr,"Error opening output file '%s'\n",filename);
+ return 2;
+ }
+
+ /* Spit out a VRML 2 Object surface of gamut */
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," intensity 0.2\n");
+ fprintf(wrl," ambientIntensity 0.1\n");
+ fprintf(wrl," direction -1 -1 -1\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," intensity 0.6\n");
+ fprintf(wrl," ambientIntensity 0.2\n");
+ fprintf(wrl," direction 1 1 1\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 250 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ fprintf(wrl,"# Lab axes as boxes:\n");
+ for (i = 0; i < 5; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape {\n");
+ fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
+ axes[i].wx, axes[i].wy, axes[i].wz);
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"# Axes identification:\n");
+ for (i = 0; i < 6; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", labels[i].x, labels[i].y, labels[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape {\n");
+ fprintf(wrl,"\t\t\tgeometry Text { string [\"%s\"]\n",labels[i].string);
+ fprintf(wrl,"\t\t\t\tfontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n",
+ labels[i].size);
+ fprintf(wrl,"\t\t\t\t}\n");
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", labels[i].r, labels[i].g, labels[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"\n");
+ }
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation 0 0 0\n");
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry IndexedFaceSet {\n");
+ fprintf(wrl," ccw FALSE\n");
+ fprintf(wrl," convex TRUE\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [ # Verticy coordinates\n");
+
+ /* Spit out the point values, in order. */
+ /* Note that a->x, b->y, L->z */
+ for (i = 0; i < s->nv; i++) {
+ double out[3];
+
+#ifdef SHOW_BUCKETS /* Show vertex buckets as surface */
+ if (!(s->verts[i]->f & GVERT_SET))
+#else
+ if (!(s->verts[i]->f & GVERT_TRI))
+#endif
+ continue;
+
+#ifdef SHOW_BUCKETS /* Show vertex buckets as surface */
+ {
+ double cc[3], rr[3];
+# ifdef SHOW_SPHERE /* Show surface on sphere */
+ rr[0] = 50.0; /* Sphere radius */
+# else
+ rr[0] = s->verts[i]->r[0],
+# endif /* SHOW_SPHERE */
+
+ rr[1] = s->verts[i]->hc - 0.5 * s->verts[i]->w;
+ rr[2] = s->verts[i]->vc - 0.5 * s->verts[i]->h;
+ gamut_radial2rect(s, cc, rr);
+ fprintf(wrl,"%f %f %f,\n",cc[1], cc[2], cc[0]);
+
+ rr[1] = s->verts[i]->hc - 0.5 * s->verts[i]->w;
+ rr[2] = s->verts[i]->vc + 0.5 * s->verts[i]->h;
+ gamut_radial2rect(s, cc, rr);
+ fprintf(wrl,"%f %f %f,\n",cc[1], cc[2], cc[0]);
+
+ rr[1] = s->verts[i]->hc + 0.5 * s->verts[i]->w;
+ rr[2] = s->verts[i]->vc + 0.5 * s->verts[i]->h;
+ gamut_radial2rect(s, cc, rr);
+ fprintf(wrl,"%f %f %f,\n",cc[1], cc[2], cc[0]);
+
+ rr[1] = s->verts[i]->hc + 0.5 * s->verts[i]->w;
+ rr[2] = s->verts[i]->vc - 0.5 * s->verts[i]->h;
+ gamut_radial2rect(s, cc, rr);
+ fprintf(wrl,"%f %f %f,\n",cc[1], cc[2], cc[0]);
+ }
+
+#else /* Show point data */
+
+# ifdef SHOW_SPHERE /* Show surface on sphere */
+ fprintf(wrl,"%f %f %f,\n",s->verts[i]->sp[1], s->verts[i]->sp[2],
+ s->verts[i]->sp[0]);
+# else
+# ifdef SHOW_HULL_PNTS
+ fprintf(wrl,"%f %f %f,\n",s->verts[i]->ch[1], s->verts[i]->ch[2],
+ s->verts[i]->ch[0]);
+# else
+ /* Show normal gamut surface */
+ out[0] = s->verts[i]->p[0];
+ out[1] = s->verts[i]->p[1];
+ out[2] = s->verts[i]->p[2];
+
+ if (transform)
+ transform(cntx, out, out); /* Do transform */
+
+ fprintf(wrl,"%f %f %f,\n",out[1]-s->cent[1], out[2]-s->cent[2], out[0]-s->cent[0]);
+
+# endif /* SHOW_HULL_PNTS */
+# endif /* SHOW_SPHERE */
+
+#endif /* SHOW_BUCKETS */
+
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coordIndex [ # Indexes of poligon Verticies \n");
+
+#ifdef SHOW_BUCKETS /* Show vertex buckets as surface */
+ for (i = 0; i < s->nv; i++) {
+ int j = s->verts[i]->sn;
+ if (!(s->verts[i]->f & GVERT_SET))
+ continue;
+ fprintf(wrl,"%d, %d, %d, %d, -1\n", j * 4, j * 4 + 1, j * 4 + 2, j * 4 + 3);
+ }
+#else /* Show gamut triangular surface */
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ fprintf(wrl,"%d, %d, %d, -1\n", tp->v[0]->tn, tp->v[1]->tn, tp->v[2]->tn);
+ } END_FOR_ALL_ITEMS(tp);
+#endif /* SHOW_BUCKETS */
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ /* Spit out the colors for each vertex */
+ for (i = 0; i < s->nv; i++) {
+ double rgb[3];
+#ifdef SHOW_BUCKETS /* Show vertex buckets as surface */
+ if (!(s->verts[i]->f & GVERT_SET))
+#else
+ if (!(s->verts[i]->f & GVERT_TRI))
+#endif
+ continue;
+
+#ifdef COLORED_VRML
+ gamut_Lab2RGB(rgb, s->verts[i]->p);
+#else
+ rgb[0] = rgb[1] = rgb[2] = 1.0;
+#endif
+ fprintf(wrl,"%f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+#ifdef SHOW_BUCKETS /* Show vertex buckets as surface */
+ fprintf(wrl,"%f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ fprintf(wrl,"%f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ fprintf(wrl,"%f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+#endif /* SHOW_BUCKETS */
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," appearance Appearance { \n");
+ fprintf(wrl," material Material {\n");
+ fprintf(wrl," transparency 0.0\n");
+ fprintf(wrl," ambientIntensity 0.3\n");
+ fprintf(wrl," shininess 0.5\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," } # end Shape\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+
+
+ if (s->gawbset && doaxes) {
+
+ /* Show the gamut white and black points */
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation %f %f %f\n",s->ga_wp[1]-s->cent[1], s->ga_wp[2]-s->cent[2], s->ga_wp[0]-s->cent[0]);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry Sphere { radius 2.0 }\n");
+ fprintf(wrl," appearance Appearance { material Material { diffuseColor 0.9 0.9 0.9 } }\n");
+ fprintf(wrl," } \n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation %f %f %f\n",s->ga_bp[1]-s->cent[1], s->ga_bp[2]-s->cent[2], s->ga_bp[0]-s->cent[0]);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry Sphere { radius 2.0 }\n");
+ fprintf(wrl," appearance Appearance { material Material { diffuseColor 0.9 0.9 0.9 } }\n");
+ fprintf(wrl," } \n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+
+ if (docusps && s->cu_inited != 0) {
+ double ccolors[6][3] = {
+ { 1.0, 0.1, 0.1 }, /* Red */
+ { 1.0, 1.0, 0.1 }, /* Yellow */
+ { 0.1, 1.0, 0.1 }, /* Green */
+ { 0.1, 1.0, 1.0 }, /* Cyan */
+ { 0.1, 0.1, 1.0 }, /* Blue */
+ { 1.0, 0.1, 1.0 } /* Magenta */
+ };
+
+ for (i = 0; i < 6; i++) {
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation %f %f %f\n",s->cusps[i][1]-s->cent[1], s->cusps[i][2]-s->cent[2], s->cusps[i][0]-s->cent[0]);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry Sphere { radius 2.0 }\n");
+ fprintf(wrl," appearance Appearance { material Material { diffuseColor %f %f %f } }\n", ccolors[i][0],ccolors[i][1],ccolors[i][2]);
+ fprintf(wrl," } \n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+ }
+
+#ifdef TEST_LOOKUP
+ {
+ int i, j;
+ double in[3], out[3];
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry PointSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+
+ for (i = 0; i < 10; i++) {
+ double ss;
+ /* Create random vector relative to center, absolute */
+ in[0] = (rand() / (double)RAND_MAX) - 0.5 + s->cent[0];
+ in[1] = (rand() / (double)RAND_MAX) - 0.5 + s->cent[1];
+ in[2] = (rand() / (double)RAND_MAX) - 0.5 + s->cent[2];
+
+ s->radial(s, out, in); /* Lookup point on gamut surface */
+
+ out[0] = (out[0] - s->cent[0]) * 1.01 + s->cent[0];
+ out[1] = (out[1] - s->cent[1]) * 1.01 + s->cent[1];
+ out[2] = (out[2] - s->cent[2]) * 1.01 + s->cent[2];
+ fprintf(wrl,"%f %f %f,\n",out[1]-s->cent[1], out[2]-s->cent[2], out[0]-s->cent[0]);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+
+ }
+#endif /* TEST_LOOKUP */
+
+#ifdef TEST_NEAREST
+ {
+#define NTPTS 500
+ int i, j;
+ double in[3], out[3];
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+
+ for (i = 0; i < NTPTS; i++) {
+ double ss;
+ /* Create random vector relative to center */
+ in[0] = (rand() / (double)RAND_MAX) - 0.5;
+ in[1] = (rand() / (double)RAND_MAX) - 0.5;
+ in[2] = (rand() / (double)RAND_MAX) - 0.5;
+
+#ifndef NEVER /* Make points just above surface */
+ in[0] += s->cent[0]; /* Make absolute */
+ in[1] += s->cent[1];
+ in[2] += s->cent[2];
+ s->radial(s, in, in); /* Lookup point on gamut surface */
+ in[0] = (in[0] - s->cent[0]) * 1.20 + s->cent[0]; /* Extend by 10% */
+ in[1] = (in[1] - s->cent[1]) * 1.20 + s->cent[1];
+ in[2] = (in[2] - s->cent[2]) * 1.20 + s->cent[2];
+#else
+ /* Make distance 150 */
+ ss = sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]);
+ in[0] = 60.0/ss * in[0] + s->cent[0];
+ in[1] = 60.0/ss * in[1] + s->cent[1];
+ in[2] = 60.0/ss * in[2] + s->cent[2];
+#endif
+
+// s->radial(s, out, in); /* Lookup point on gamut surface */
+
+ s->nearest(s, out, in); /* Nearest point on gamut surface */
+
+ fprintf(wrl,"%f %f %f,\n",in[1]-s->cent[1], in[2]-s->cent[2], in[0]-s->cent[0]);
+ fprintf(wrl,"%f %f %f,\n",out[1]-s->cent[1], out[2]-s->cent[2], out[0]-s->cent[0]);
+ }
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (i = 0; i < NTPTS; i++) {
+ fprintf(wrl,"%d, %d, -1,\n", i * 2, i * 2 + 1);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+
+ }
+#endif /* TEST_NEAREST */
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0) {
+ fprintf(stderr,"Error closing output file '%s'\n",filename);
+ return 2;
+ }
+
+ return 0;
+}
+
+
+/* ----------------------------------- */
+/* Write to a CGATS .gam file */
+/* Return non-zero on error */
+static int write_gam(
+gamut *s,
+char *filename
+) {
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ int i;
+ gtri *tp; /* Triangle pointer */
+ cgats *gam;
+ char buf[100];
+
+ if IS_LIST_EMPTY(s->tris)
+ triangulate(s);
+
+ gam = new_cgats(); /* Create a CGATS structure */
+ gam->add_other(gam, "GAMUT");
+
+ gam->add_table(gam, tt_other, 0); /* Start the first table as type "GAMUT" */
+
+ gam->add_kword(gam, 0, "DESCRIPTOR", "Argyll Gamut surface poligon data", NULL);
+ gam->add_kword(gam, 0, "ORIGINATOR", "Argyll CMS gamut library", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ gam->add_kword(gam, 0, "CREATED",atm, NULL);
+
+#ifdef NEVER
+ /* would be nice to add extra info like description, source (ie icc filename) etc. */
+ gam->add_kword(gam, 0, "DEVICE_CLASS","INPUT", NULL); /* What sort of device this is */
+#endif
+ if (s->isJab)
+ gam->add_kword(gam, 0, "COLOR_REP","JAB", NULL);
+ else
+ gam->add_kword(gam, 0, "COLOR_REP","LAB", NULL);
+
+ if (s->isRast)
+ gam->add_kword(gam, 0, "SURF_TYPE","RASTER", NULL);
+
+ sprintf(buf,"%f %f %f", s->cent[0], s->cent[1], s->cent[2]);
+ gam->add_kword(gam, 0, "GAMUT_CENTER",buf, NULL);
+
+ /* If the white and black points are known, put them in the file */
+ if (s->cswbset) {
+
+ compgawb(s); /* make sure we have gamut white/black available */
+
+ sprintf(buf,"%f %f %f", s->cs_wp[0], s->cs_wp[1], s->cs_wp[2]);
+ gam->add_kword(gam, 0, "CSPACE_WHITE",buf, NULL);
+
+ sprintf(buf,"%f %f %f", s->ga_wp[0], s->ga_wp[1], s->ga_wp[2]);
+ gam->add_kword(gam, 0, "GAMUT_WHITE",buf, NULL);
+
+ sprintf(buf,"%f %f %f", s->cs_bp[0], s->cs_bp[1], s->cs_bp[2]);
+ gam->add_kword(gam, 0, "CSPACE_BLACK",buf, NULL);
+
+ sprintf(buf,"%f %f %f", s->ga_bp[0], s->ga_bp[1], s->ga_bp[2]);
+ gam->add_kword(gam, 0, "GAMUT_BLACK",buf, NULL);
+ }
+
+ /* If cusp values are known, put them in the file */
+ if (s->cu_inited != 0) {
+ char buf1[50], buf2[100];
+ char *cnames[6] = { "RED", "YELLOW", "GREEN", "CYAN", "BLUE", "MAGENTA" };
+
+ for (i = 0; i < 6; i++) {
+ sprintf(buf1,"CUSP_%s", cnames[i]);
+ sprintf(buf2,"%f %f %f", s->cusps[i][0], s->cusps[i][1], s->cusps[i][2]);
+ gam->add_kword(gam, 0, buf1, buf2, NULL);
+ }
+ }
+
+ gam->add_kword(gam, 0, NULL, NULL, "First come the triangle verticy location");
+
+ gam->add_field(gam, 0, "VERTEX_NO", i_t);
+ gam->add_field(gam, 0, "LAB_L", r_t);
+ gam->add_field(gam, 0, "LAB_A", r_t);
+ gam->add_field(gam, 0, "LAB_B", r_t);
+
+ /* Spit out the vertex values, in order. */
+ for (i = 0; i < s->nv; i++) {
+ if (!(s->verts[i]->f & GVERT_TRI))
+ continue;
+ gam->add_set(gam, 0, s->verts[i]->tn,
+ s->verts[i]->p[0], s->verts[i]->p[1], s->verts[i]->p[2]);
+ }
+
+ gam->add_table(gam, tt_other, 0); /* Start the second table */
+ gam->set_table_flags(gam, 1, 1, 1, 0); /* Suppress id & kwords */
+ gam->add_kword(gam, 1, NULL, NULL, "And then come the triangles");
+
+ gam->add_field(gam, 1, "VERTEX_0", i_t);
+ gam->add_field(gam, 1, "VERTEX_1", i_t);
+ gam->add_field(gam, 1, "VERTEX_2", i_t);
+
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ gam->add_set(gam, 1, tp->v[0]->tn, tp->v[1]->tn, tp->v[2]->tn);
+ } END_FOR_ALL_ITEMS(tp);
+
+
+ if (gam->write_name(gam, filename)) {
+ fprintf(stderr,"Error writing to file '%s' : '%s'\n",filename, gam->err);
+ return 2;
+ }
+
+ gam->del(gam); /* Clean up */
+ return 0;
+}
+
+/* ----------------------------------- */
+/* Read from a CGATS .gam file */
+/* Return non-zero on error */
+static int read_gam(
+gamut *s,
+char *filename
+) {
+ int i;
+ cgats *gam;
+ gtri *tp;
+ int nverts;
+ int ntris;
+ int Lf, af, bf; /* Fields holding L, a & b data */
+ int v0f, v1f, v2f; /* Fields holding verticies 0, 1 & 2 */
+ int cw, cb; /* Colorspace white, black keyword indexes */
+ int gw, gb; /* Gamut white, black keyword indexes */
+
+ if (s->tris != NULL || s->read_inited || s->lu_inited || s->ne_inited) {
+ fprintf(stderr,"Can't add read into gamut after it is initialised!\n");
+ return 1;
+ }
+
+ gam = new_cgats(); /* Create a CGATS structure */
+
+ gam->add_other(gam, "GAMUT"); /* Setup to cope with a gamut file */
+
+ if (gam->read_name(gam, filename)) {
+ fprintf(stderr,"Input file '%s' error : %s",filename, gam->err);
+ return 1;
+ }
+
+ if (gam->t[0].tt != tt_other || gam->t[0].oi != 0) {
+ fprintf(stderr,"Input file isn't a GAMUT format file");
+ return 1;
+ }
+ if (gam->ntables != 2) {
+ fprintf(stderr,"Input file doesn't contain exactly two tables");
+ return 1;
+ }
+
+ /* Figure the basic colorspace information */
+ s->isJab = 0;
+ if ((cw = gam->find_kword(gam, 0, "COLOR_REP")) >= 0) {
+ if (strcmp(gam->t[0].kdata[cw], "JAB") == 0)
+ s->isJab = 1;
+ }
+
+ /* Figure the surface type */
+ s->isRast = 0;
+ if ((cw = gam->find_kword(gam, 0, "SURF_TYPE")) >= 0) {
+ if (strcmp(gam->t[0].kdata[cw], "RASTER") == 0)
+ s->isRast = 1;
+ }
+ if (s->isRast) {
+ s->logpow = RAST_LOG_POW; /* Wrap the surface more closely */
+ s->no2pass = 1; /* Only do one pass */
+ } else {
+ s->logpow = NORM_LOG_POW; /* Convex hull compression power */
+ s->no2pass = 0; /* Do two passes */
+ }
+
+ /* If we can find the the colorspace white and black points, add them to the gamut */
+ cw = gam->find_kword(gam, 0, "CSPACE_WHITE");
+ cb = gam->find_kword(gam, 0, "CSPACE_BLACK");
+ if (cw >= 0 && cb >= 0) {
+ int ok = 1;
+ if (sscanf(gam->t[0].kdata[cw], "%lf %lf %lf",
+ &s->cs_wp[0], &s->cs_wp[1], &s->cs_wp[2]) != 3) {
+ ok = 0;
+ }
+
+ if (sscanf(gam->t[0].kdata[cb], "%lf %lf %lf",
+ &s->cs_bp[0], &s->cs_bp[1], &s->cs_bp[2]) != 3) {
+ ok = 0;
+ }
+
+ if (ok) {
+ s->cswbset = 1;
+ }
+ }
+
+ /* If we can find the the gamut white and black points, add them to the gamut */
+ gw = gam->find_kword(gam, 0, "GAMUT_WHITE");
+ gb = gam->find_kword(gam, 0, "GAMUT_BLACK");
+ if (gw >= 0 && gb >= 0) {
+ int ok = 1;
+ if (sscanf(gam->t[0].kdata[gw], "%lf %lf %lf",
+ &s->ga_wp[0], &s->ga_wp[1], &s->ga_wp[2]) != 3) {
+ ok = 0;
+ }
+
+ if (sscanf(gam->t[0].kdata[gb], "%lf %lf %lf",
+ &s->ga_bp[0], &s->ga_bp[1], &s->ga_bp[2]) != 3) {
+ ok = 0;
+ }
+
+ if (ok) {
+ s->gawbset = 1;
+ }
+ }
+
+ /* See if there are cusp values */
+ {
+ int kk;
+ char buf1[50];
+ char *cnames[6] = { "RED", "YELLOW", "GREEN", "CYAN", "BLUE", "MAGENTA" };
+
+ for (i = 0; i < 6; i++) {
+ sprintf(buf1,"CUSP_%s", cnames[i]);
+ if ((kk = gam->find_kword(gam, 0, buf1)) < 0)
+ break;
+
+ if (sscanf(gam->t[0].kdata[kk], "%lf %lf %lf",
+ &s->cusps[i][0], &s->cusps[i][1], &s->cusps[i][2]) != 3) {
+ break;
+ }
+ }
+ if (i >= 6)
+ s->cu_inited = 1;
+ }
+
+
+ if ((nverts = gam->t[0].nsets) <= 0) {
+ fprintf(stderr,"No verticies");
+ return 1;
+ }
+ if ((ntris = gam->t[1].nsets) <= 0) {
+ fprintf(stderr,"No triangles");
+ return 1;
+ }
+
+ /* Get ready to read the verticy data */
+ if ((Lf = gam->find_field(gam, 0, "LAB_L")) < 0) {
+ fprintf(stderr,"Input file doesn't contain field LAB_L");
+ return 1;
+ }
+ if (gam->t[0].ftype[Lf] != r_t) {
+ fprintf(stderr,"Field LAB_L is wrong type");
+ return 1;
+ }
+ if ((af = gam->find_field(gam, 0, "LAB_A")) < 0) {
+ fprintf(stderr,"Input file doesn't contain field LAB_A");
+ return 1;
+ }
+ if (gam->t[0].ftype[af] != r_t) {
+ fprintf(stderr,"Field LAB_A is wrong type");
+ return 1;
+ }
+ if ((bf = gam->find_field(gam, 0, "LAB_B")) < 0) {
+ fprintf(stderr,"Input file doesn't contain field LAB_B");
+ return 1;
+ }
+ if (gam->t[0].ftype[bf] != r_t) {
+ fprintf(stderr,"Field LAB_B is wrong type");
+ return 1;
+ }
+
+ /* Allocate an array to point at the verts */
+ if ((s->verts = (gvert **)malloc(nverts * sizeof(gvert *))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed on gvert pointer\n");
+ return 2;
+ }
+ s->nv = s->na = nverts;
+
+ for (i = 0; i < nverts; i++) {
+ gvert *v;
+
+ /* Allocate and fill in each verticies basic information */
+ if ((v = (gvert *)calloc(1, sizeof(gvert))) == NULL) {
+ fprintf(stderr,"gamut: malloc failed on gvert object\n");
+ return 2;
+ }
+ s->verts[i] = v;
+ v->tag = 1;
+ v->tn = v->n = i;
+ v->f = GVERT_SET | GVERT_TRI; /* Will be part of the triangulation */
+
+ v->p[0] = *((double *)gam->t[0].fdata[i][Lf]);
+ v->p[1] = *((double *)gam->t[0].fdata[i][af]);
+ v->p[2] = *((double *)gam->t[0].fdata[i][bf]);
+
+ gamut_rect2radial(s, v->r, v->p);
+ }
+ s->ntv = i;
+
+ /* Compute the other vertex values */
+ compute_vertex_coords(s);
+
+ /* Get ready to read the triangle data */
+ if ((v0f = gam->find_field(gam, 1, "VERTEX_0")) < 0) {
+ fprintf(stderr,"Input file doesn't contain field VERTEX_0");
+ return 1;
+ }
+ if (gam->t[1].ftype[v0f] != i_t) {
+ fprintf(stderr,"Field VERTEX_0 is wrong type");
+ return 1;
+ }
+ if ((v1f = gam->find_field(gam, 1, "VERTEX_1")) < 0) {
+ fprintf(stderr,"Input file doesn't contain field VERTEX_1");
+ return 1;
+ }
+ if (gam->t[1].ftype[v1f] != i_t) {
+ fprintf(stderr,"Field VERTEX_1 is wrong type");
+ return 1;
+ }
+ if ((v2f = gam->find_field(gam, 1, "VERTEX_2")) < 0) {
+ fprintf(stderr,"Input file doesn't contain field VERTEX_2");
+ return 1;
+ }
+ if (gam->t[1].ftype[v2f] != i_t) {
+ fprintf(stderr,"Field VERTEX_2 is wrong type");
+ return 1;
+ }
+
+ /* Create all the triangles */
+ for (i = 0; i < ntris; i++) {
+ gtri *t;
+ int v0, v1, v2;
+
+ t = new_gtri();
+ ADD_ITEM_TO_BOT(s->tris, t); /* Append to triangulation list */
+
+ v0 = *((int *)gam->t[1].fdata[i][v0f]);
+ v1 = *((int *)gam->t[1].fdata[i][v1f]);
+ v2 = *((int *)gam->t[1].fdata[i][v2f]);
+
+ t->v[0] = s->verts[v0];
+ t->v[1] = s->verts[v1];
+ t->v[2] = s->verts[v2];
+
+ comptriattr(s, t); /* Compute triangle attributes */
+ }
+
+ /* Connect edge information */
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ int en;
+
+ for (en = 0; en < 3; en++) { /* For each edge */
+ gedge *e;
+ gvert *v0, *v1; /* The two verticies of the edge */
+ gtri *tp2; /* The other triangle */
+ int em; /* The other edge */
+ gvert *w0, *w1; /* The other verticies */
+
+ v0 = tp->v[en];
+ v1 = tp->v[en < 2 ? en+1 : 0];
+
+ if (v0->n > v1->n)
+ continue; /* Skip every other edge */
+
+ /* Find the corresponding edge of the other triangle */
+ w0 = w1 = NULL;
+ tp2 = s->tris;
+ FOR_ALL_ITEMS(gtri, tp2) {
+ for (em = 0; em < 3; em++) { /* For each edge */
+ w0 = tp2->v[em];
+ w1 = tp2->v[em < 2 ? em+1 : 0];
+ if (v0 == w1 && v1 == w0) /* Found it */
+ break;
+ }
+ if (em < 3)
+ break;
+ } END_FOR_ALL_ITEMS(tp2);
+ if (w0 == NULL) {
+ /* Should clean up ? */
+ fprintf(stderr,".gam file triangle data is not consistent\n");
+ return 1;
+ }
+
+ if (tp->e[en] != NULL
+ || tp2->e[em] != NULL) {
+ fprintf(stderr,".gam file triangle data is not consistent\n");
+ fprintf(stderr,"tp1->e[%d] = 0x%p, tp2->e[%d]= 0x%p\n",en,
+ (void *)tp->e[en],em,(void *)tp2->e[em]);
+ return 1;
+ }
+
+ /* Creat the edge structure */
+ e = new_gedge();
+ ADD_ITEM_TO_BOT(s->edges, e); /* Append to edge list */
+ tp->e[en] = e; /* This edge */
+ tp->ei[en] = 0; /* 0th triangle in edge */
+ e->t[0] = tp; /* 0th triangle is tp */
+ e->ti[0] = en; /* 0th triangles en edge */
+ tp2->e[em] = e; /* This edge */
+ tp2->ei[em] = 1; /* 1st triangle in edge */
+ e->t[1] = tp2; /* 1st triangle is tp2 */
+ e->ti[1] = em; /* 1st triangles em edge */
+ e->v[0] = v0; /* The two verticies */
+ e->v[1] = v1;
+ }
+ } END_FOR_ALL_ITEMS(tp);
+
+ gam->del(gam); /* Clean up */
+
+ s->read_inited = 1; /* It's now valid */
+
+#ifdef ASSERTS
+ check_triangulation(s, 1); /* Check out our work */
+#endif
+
+ return 0;
+}
+
+/* ===================================================== */
+/* ===================================================== */
+
+/* Convert from rectangular to radial coordinates */
+void
+gamut_rect2radial(
+gamut *s,
+double out[3], /* Radius, longitude, lattitude out */
+double in[3] /* Lab in */
+) {
+ double L, a, b; /* Lab values */
+ double R, g, t; /* Radial value */
+ double c; /* Chromatic length */
+
+
+ L = in[0] - s->cent[0]; /* Offset value */
+ a = in[1] - s->cent[1];
+ b = in[2] - s->cent[2];
+ c = a * a + b * b;
+ R = c + L * L;
+ c = sqrt(c); /* Saturation */
+ R = sqrt(R); /* Vector length */
+
+ if (R < 1e-6) { /* Hmm, a point at the center */
+ g = t = 0.0;
+ } else {
+
+ /* Figure out the longitude, -pi to +pi */
+ if (c < 1e-6) {
+ g = 0.0;
+ } else {
+ g = asin(b/c);
+ if (a < 0.0) {
+ if (b >= 0.0)
+ g = M_PI - g;
+ else
+ g = -g - M_PI;
+ }
+ }
+
+ /* Figure out the lattitude, -pi/2 to +pi/2 */
+ t = asin(L/R);
+ }
+ out[0] = R;
+ out[1] = g;
+ out[2] = t;
+}
+
+/* Convert from radial to rectangular coordinates */
+void
+gamut_radial2rect(
+gamut *s,
+double out[3], /* Lab out */
+double in[3] /* Radius, longitude, lattitude in */
+) {
+ double R, g, t; /* Radial value */
+ double L, a, b; /* Lab values */
+ double c; /* Chromatic length */
+
+ R = in[0];
+ g = in[1];
+ t = in[2];
+
+ L = R * sin(t);
+ c = R * cos(t);
+
+ a = c * cos(g);
+ b = c * sin(g);
+
+ out[0] = L + s->cent[0];
+ out[1] = a + s->cent[1];
+ out[2] = b + s->cent[2];
+}
+
+
+/* -------------------------------------------------- */
+
+/* Convert a gamut Lab value to an RGB value for display purposes */
+void
+gamut_Lab2RGB(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+ double R, G, B;
+
+ /* Scale so that black is visible */
+ L = L * (100 - 40.0)/100.0 + 40.0;
+
+ /* First convert to XYZ using D50 white point */
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ x *= 0.9642; /* Multiply by white point, D50 */
+ y *= 1.0;
+ z *= 0.8249;
+
+ /* Now convert to sRGB values */
+ R = x * 3.2410 + y * -1.5374 + z * -0.4986;
+ G = x * -0.9692 + y * 1.8760 + z * 0.0416;
+ B = x * 0.0556 + y * -0.2040 + z * 1.0570;
+
+ if (R < 0.0)
+ R = 0.0;
+ else if (R > 1.0)
+ R = 1.0;
+
+ if (G < 0.0)
+ G = 0.0;
+ else if (G > 1.0)
+ G = 1.0;
+
+ if (B < 0.0)
+ B = 0.0;
+ else if (B > 1.0)
+ B = 1.0;
+
+ R = pow(R, 1.0/2.2);
+ G = pow(G, 1.0/2.2);
+ B = pow(B, 1.0/2.2);
+
+ out[0] = R;
+ out[1] = G;
+ out[2] = B;
+}
+
+
+/* -------------------------------------------------- */
+
+#ifdef DEBUG_TRIANG
+
+/* Write a surface contrsuction diagnostic VRML .wrl file */
+static int write_diag_vrml(
+gamut *s,
+double vv[3], /* Vertex being added */
+int nh, /* Number of hit triangles */
+tidxs *hixs, /* verticy indexes of hit triangles */
+gtri *hl /* Edge hit list (may be NULL) */
+) {
+ char *filename;
+ int i, j;
+ gtri *tp; /* Triangle pointer */
+ FILE *wrl;
+
+ if (hl)
+ filename = "diag1.wrl"; /* Triangles hit */
+ else
+ filename = "diag2.wrl"; /* Triangles formed */
+
+ if ((wrl = fopen(filename,"w")) == NULL) {
+ fprintf(stderr,"Error opening output file '%s'\n",filename);
+ return 2;
+ }
+
+ /* Spit out a VRML 2 Object surface of gamut */
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 200 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation 0 0 0\n");
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry IndexedFaceSet {\n");
+ fprintf(wrl," ccw FALSE\n");
+ fprintf(wrl," convex TRUE\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [ # Verticy coordinates\n");
+
+ /* Spit out the vertex values, in order. */
+ /* Note that a->x, b->y, L->z */
+ for (i = 0; i < s->nv; i++) {
+ double out[3];
+
+ /* Show normal gamut surface */
+ out[0] = s->verts[i]->ch[0];
+ out[1] = s->verts[i]->ch[1];
+ out[2] = s->verts[i]->ch[2];
+
+ fprintf(wrl,"%f %f %f,\n",out[1], out[2], out[0]);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coordIndex [ # Indexes of poligon Verticies \n");
+
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ fprintf(wrl,"%d, %d, %d, -1\n", tp->v[0]->n, tp->v[1]->n, tp->v[2]->n);
+ } END_FOR_ALL_ITEMS(tp);
+
+ for (i = 0; i < nh; i++) {
+ fprintf(wrl,"%d, %d, %d, -1\n", hixs[i].tix[0], hixs[i].tix[1], hixs[i].tix[2]);
+ }
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," colorPerVertex FALSE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ /* Spit out the colors for each face */
+ tp = s->tris;
+ FOR_ALL_ITEMS(gtri, tp) {
+ fprintf(wrl,"%f %f %f,\n", 0.7, 0.7, 0.7);
+ } END_FOR_ALL_ITEMS(tp);
+ for (i = 0; i < nh; i++) {
+ if (hixs[i].type == 0)
+ fprintf(wrl,"%f %f %f,\n", 0.4, 1.0, 0.4); /* Green for hit */
+ else if (hixs[i].type == 1)
+ fprintf(wrl,"%f %f %f,\n", 0.4, 0.4, 1.0); /* Blue for extra */
+ else
+ fprintf(wrl,"%f %f %f,\n", 0.8, 0.8, 0.2); /* Yellow for new */
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," } # end IndexedFaceSet\n");
+
+ fprintf(wrl," appearance Appearance { \n");
+ fprintf(wrl," material Material {\n");
+ fprintf(wrl," transparency 0.0\n");
+ fprintf(wrl," ambientIntensity 0.3\n");
+ fprintf(wrl," shininess 0.5\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," } # end Shape\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," } # end of transform\n");
+
+ /* center of gamut */
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation %f %f %f\n",0.0, 0.0, 0.0);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry Sphere { radius 1.5 }\n");
+ fprintf(wrl," appearance Appearance { material Material { diffuseColor %f %f %f } }\n", 1.0, 1.0, 0.0);
+ fprintf(wrl," } \n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+
+ /* vertex being added */
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation %f %f %f\n",vv[1], vv[2], vv[0]);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry Sphere { radius 1.5 }\n");
+ fprintf(wrl," appearance Appearance { material Material { diffuseColor %f %f %f } }\n", 1.0, 0.0, 0.0);
+ fprintf(wrl," } \n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+
+
+ /* Verticies for Polygon edges, marked by directional cones */
+ if (hl != NULL) {
+ double base[3] = { 0.0, 0.0, 1.0 }; /* Default orientation of cone is b axis */
+ tp = hl;
+ FOR_ALL_ITEMS(gtri, tp) {
+ double len;
+ double loc[3];
+ double vec[3];
+ double axis[3]; /* Axis to rotate around */
+ double rot; /* In radians */
+
+//printf("~1 edge vert %d to %d\n",tp->v[0]->n, tp->v[1]->n);
+//printf("~1 edge %f %f %f to %f %f %f\n",
+//tp->v[0]->ch[0], tp->v[0]->ch[1], tp->v[0]->ch[2],
+//tp->v[1]->ch[0], tp->v[1]->ch[1], tp->v[1]->ch[2]);
+
+ icmAdd3(loc, tp->v[1]->ch, tp->v[0]->ch);
+ icmScale3(loc, loc, 0.5);
+ icmSub3(vec, tp->v[1]->ch, tp->v[0]->ch);
+ len = icmNorm3(vec);
+
+ if (len < 1.0)
+ len = 1.0;
+
+ icmNormalize3(base, base, 1.0);
+ icmNormalize3(vec, vec, 1.0);
+ icmCross3(axis, base, vec);
+ rot = icmDot3(base, vec);
+//printf("~1 Axis = %f %f %f\n",axis[0],axis[1],axis[2]);
+ if (icmNorm3sq(axis) < 1e-10) { /* 0 or 180 degrees */
+ double base2[3];
+ int mxi = 0;
+ base2[0] = vec[1]; /* Comute vector in a different direction */
+ base2[1] = vec[2];
+ base2[2] = vec[0];
+ for (j = 1; j < 3; j++) {
+ if (fabs(base2[j]) > fabs(base2[mxi]))
+ mxi = j;
+ }
+ base2[mxi] = -base2[mxi];
+
+ icmCross3(axis, base2, vec);
+ if (icmNorm3sq(axis) < 1e-10) { /* 0 or 180 degrees */
+ error("VRML rotate axis still too small");
+ }
+ if (rot < 0.0)
+ rot = 3.1415926;
+ else
+ rot = 0.0;
+ } else {
+ rot = acos(rot);
+//printf("~1 rotation %f\n",rot);
+ }
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," rotation %f %f %f %f\n",axis[1], axis[2], axis[0], rot);
+ fprintf(wrl," translation %f %f %f\n",loc[1], loc[2], loc[0]);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry Cone { bottomRadius 0.5 height %f }\n",len);
+ fprintf(wrl," appearance Appearance { material Material { diffuseColor 0.7 0.0 1.0 } }\n");
+ fprintf(wrl," } \n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ } END_FOR_ALL_ITEMS(tp);
+ }
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0) {
+ fprintf(stderr,"Error closing output file '%s'\n",filename);
+ return 2;
+ }
+
+ return 0;
+}
+
+#endif /* DEBUG_TRIANG */
+
+
+#ifdef DEBUG_SPLIT_VRML
+
+/* Write a triangle split diagnostic VRML .wrl file */
+static int write_split_diag_vrml(
+gamut *s,
+gtri **list, /* Triangle list */
+int llen /* Number of triangles in the list */
+) {
+ char *filename;
+ int i, j;
+ FILE *wrl;
+
+ filename = "diag3.wrl"; /* Triangles split */
+
+ if ((wrl = fopen(filename,"w")) == NULL) {
+ fprintf(stderr,"Error opening output file '%s'\n",filename);
+ return 2;
+ }
+
+ /* Spit out a VRML 2 Object surface of gamut */
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," ambientIntensity 0.3 # Ambient light illuminating the scene\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 5 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation 0 0 0\n");
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry IndexedFaceSet {\n");
+ fprintf(wrl," ccw FALSE\n");
+ fprintf(wrl," convex TRUE\n");
+ fprintf(wrl," solid FALSE\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [ # Verticy coordinates\n");
+
+ /* Spit out the vertex values, in order. */
+ for (i = 0; i < llen; i++) {
+ fprintf(wrl,"%f %f %f,\n",list[i]->v[0]->sp[0], list[i]->v[0]->sp[1], list[i]->v[0]->sp[2]);
+ fprintf(wrl,"%f %f %f,\n",list[i]->v[1]->sp[0], list[i]->v[1]->sp[1], list[i]->v[1]->sp[2]);
+ fprintf(wrl,"%f %f %f,\n",list[i]->v[2]->sp[0], list[i]->v[2]->sp[1], list[i]->v[2]->sp[2]);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coordIndex [ # Indexes of poligon Verticies \n");
+
+ for (i = 0; i < llen; i++) {
+ fprintf(wrl,"%d, %d, %d, -1\n", i * 3 + 0, i * 3 + 1, i * 3 + 2);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," colorPerVertex FALSE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ /* Spit out the colors for each face */
+ for (i = 0; i < llen; i++) {
+ if (list[i]->bsort == 1) { /* Positive */
+ fprintf(wrl,"%f %f %f,\n", 1.0, 0.3, 0.3); /* Red */
+ } else if (list[i]->bsort == 2) { /* Negative */
+ fprintf(wrl,"%f %f %f,\n", 0.3, 1.0, 0.3); /* Green */
+ } else if (list[i]->bsort == 3) { /* Both */
+ fprintf(wrl,"%f %f %f,\n", 1.0, 1.0, 0.3); /* Yellow */
+ } else { /* Neither */
+ fprintf(wrl,"%f %f %f,\n", 0.3, 0.3, 1.0); /* Blue */
+ }
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," } # end IndexedFaceSet\n");
+
+ fprintf(wrl," appearance Appearance { \n");
+ fprintf(wrl," material Material {\n");
+ fprintf(wrl," transparency 0.0\n");
+ fprintf(wrl," ambientIntensity 0.3\n");
+ fprintf(wrl," shininess 0.5\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," } # end Shape\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," } # end of transform\n");
+
+ /* center of gamut */
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation %f %f %f\n",0.0, 0.0, 0.0);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry Sphere { radius 0.05 }\n");
+ fprintf(wrl," appearance Appearance { material Material { diffuseColor %f %f %f } }\n", 1.0, 1.0, 0.0);
+ fprintf(wrl," } \n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0) {
+ fprintf(stderr,"Error closing output file '%s'\n",filename);
+ return 2;
+ }
+
+ return 0;
+}
+
+#endif /* DEBUG_SPLIT_VRML */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gamut/gamut.h b/gamut/gamut.h
new file mode 100644
index 0000000..8f9f00e
--- /dev/null
+++ b/gamut/gamut.h
@@ -0,0 +1,406 @@
+#ifndef GAMUT_H
+#define GAMUT_H
+
+/*
+ * gamut
+ *
+ * Gamut support routines.
+ *
+ * Author: Graeme W. Gill
+ * Date: 9/3/2000
+ * Version: 1.00
+ *
+ * Copyright 2000-2006 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.
+ */
+
+
+
+/*
+ Note that the input and output are expected to be Lab style
+ color coordinates, and that L->Z, a->X, b->Y.
+
+*/
+
+#include "../h/llist.h"
+
+#define BSPDEPTH 100 /* Maximum BSP tree depth */
+
+#define PFARNDIST 0.1 /* Positive (inwards) far "near" distance */
+#define NFARNDIST -200.0 /* Negative (outwards) far "near" distance */
+#define MFARNDIST PFARNDIST /* Minimum (absolute) of the two */
+
+#define MAXGAMN 10 /* Maximum gamut point neighbors returned */
+#define NSLOTS 6 /* Number of maximum direction slots */
+
+/* ------------------------------------ */
+#define NODE_STRUCT \
+ int tag; /* Type of node, 1 = vertex, 2 = quad */ \
+ double w, h; /* longitude width, latitude height of this box */ \
+ double hc, vc; /* longitude center, latitude center of this box */ \
+
+struct _gnode {
+ NODE_STRUCT
+}; typedef struct _gnode gnode;
+
+/* ------------------------------------ */
+/* Vertex node */
+struct _gvert {
+ NODE_STRUCT
+ int rc; /* reference count */
+ struct _gvert *ul; /* Unused list */
+
+ int n; /* Index number of vertex */
+ int sn; /* Set Index number of vertex */
+ int tn; /* Triangulated Index number of vertex */
+ int f; /* Flag value */
+#define GVERT_NONE 0x0000 /* No flags */
+#define GVERT_SET 0x0001 /* Value has been set */
+#define GVERT_TRI 0x0002 /* Vertex has been added to triangulation (Exclsv with _INSIDE) */
+#define GVERT_INSIDE 0x0004 /* Vertex is inside the log hull (Exclusive with _TRI) */
+#define GVERT_ISOS 0x0008 /* Intersecting gamuts "outside other gamut" flag */
+#define GVERT_ESTP 0x0010 /* Non-fake establishment point */
+#define GVERT_FAKE 0x0020 /* Fake establishment point */
+ int k0; /* k0 direction reference count */
+
+ double p[3]; /* Point in xyz rectangular coordinates, absolute */
+ double r[3]; /* Radial coordinates */
+ double lr0; /* log scaled r[0] */
+ double sp[3]; /* Point mapped to surface of unit sphere, relative to center */
+ double ch[3]; /* Point mapped for convex hull testing, relative to center */
+
+ int as; /* Assert checking flag, compdstgamut flag */
+}; typedef struct _gvert gvert;
+
+/* ------------------------------------ */
+/* Quadtree node */
+struct _gquad {
+ NODE_STRUCT
+ gnode *qt[4][NSLOTS];
+
+ /* Child nodes, NULL if none, */
+ /* Nodes are ordered: */
+ /* --------- */
+ /* | 2 | 3 | */
+ /* --------- */
+ /* | 0 | 1 | */
+ /* --------- */
+ /* and each node contains NSLOTS slots. */
+ /* If the quadtree recurses, the first slot containts another */
+ /* quadtree, otherwise the slots contain pointers to the */
+ /* four best verticies in the various directions. */
+
+}; typedef struct _gquad gquad;
+
+/* ------------------------------------ */
+
+/* Common base class of BSP nodes */
+#define BSP_STRUCT \
+ int tag; /* Type of node, 1 = bsp node, 2 = triangle, 3 = list */ \
+ double rs0, rs1; /* min/max radius squared from origin of all contained triangles */
+
+struct _gbsp {
+ BSP_STRUCT
+}; typedef struct _gbsp gbsp;
+
+/* ------------------------------------ */
+
+/* A BSP tree decision node */
+struct _gbspn {
+ BSP_STRUCT
+ int n; /* Serial number */
+ double pe[4]; /* Plane equation values (center relative) */
+ struct _gbsp *po; /* Positive branch */
+ struct _gbsp *ne; /* Negative branch */
+}; typedef struct _gbspn gbspn;
+
+/* ------------------------------------ */
+
+/* A BSP tree triangle list node */
+struct _gbspl {
+ BSP_STRUCT
+ int n; /* Serial number */
+ int nt; /* Number of triangles in the list */
+ struct _gtri *t[]; /* List of triangles - allocated with struct */
+}; typedef struct _gbspl gbspl;
+
+/* ------------------------------------ */
+
+/* A triangle in the surface mesh */
+struct _gtri {
+ BSP_STRUCT
+ int n; /* Serial number */
+ struct _gvert *v[3]; /* Verticies in cw order */
+ struct _gedge *e[3]; /* Edges v[n] - v[n+1] */
+ int ei[3]; /* Index within edge structure of this triangle [0..1] */
+
+ double pe[4]; /* Vertex plane equation (absolute) */
+ /* (The first three elements is the unit normal vector to the plane, */
+ /* which points inwards) */
+ double che[4]; /* convex hull testing triangle plane equation (relative) */
+ double spe[4]; /* sphere mapped triangle plane equation (relative) */
+ double ee[3][4]; /* sphere sp[] Edge triangle plane equations for opposite edge (relative) */
+
+ int sort; /* lookup: Plane sorting result for each try */
+ int bsort; /* lookup: Current best tries sort */
+
+ unsigned int touch; /* nn: Per value touch count */
+ double mix[2][3]; /* nn: Bounding box min and max */
+
+ double area; /* Area - computed by nssverts() */
+ int ssverts; /* Number of stratified sampling verts needed - computed by nssverts() */
+
+ LINKSTRUCT(struct _gtri); /* Linked list structure */
+}; typedef struct _gtri gtri;
+
+/* ------------------------------------ */
+
+/* An edge shared by two triangle in the mesh */
+struct _gedge {
+ int n; /* Serial number */
+ struct _gvert *v[2]; /* Verticies of edge */
+ struct _gtri *t[2]; /* Triangles edge is part of */
+ int ti[2]; /* record of indexes of edge within the triangles [0..2]*/
+ double re[4]; /* Radial edge plane equation (relative) */
+
+ int as; /* Assert checking flag */
+
+ LINKSTRUCT(struct _gedge); /* Linked list structure */
+}; typedef struct _gedge gedge;
+
+/* ------------------------------------ */
+
+/* The gamut nearest neighbor search structure */
+struct _gnn {
+ struct _gamut *s; /* Base gamut object */
+ int n; /* Number of points stored */
+ gtri **sax[3 * 2]; /* Sorted axis pointers, one for each direction */
+ unsigned int tbase; /* Touch base value for this pass */
+ unsigned int ttarget; /* Touch target value for this pass */
+}; typedef struct _gnn gnn;
+
+/* ------------------------------------ */
+
+/* A vector intersction point */
+struct _gispnt {
+ double ip[3]; /* Intersecion Point */
+ double pv; /* Parameter value at intersection */
+ int dir; /* Direction: 1 = into gamut, 0 = out or gamut */
+ int edge; /* Edge: 2 = no isect, 1 = on edge, 0 = not on edge */
+ gtri *tri; /* Pointer to intersection triangle */
+}; typedef struct _gispnt gispnt;
+
+/* Gamut object */
+struct _gamut {
+
+/* Private: */
+ double sres; /* Surface triangle resolution */
+ int isJab; /* nz if Jab CIECAM02 type space rather than L*a*b* */
+ int isRast; /* nz if raster file point cloud, else colorspace */
+ /* (This affects convex hull filtering) */
+ double cent[3]; /* Gamut center for radial conversion. Default 50.0,0,0 */
+ /* Must be same to compare radial values. */
+
+ int nv; /* Number of verticies used out of allocation */
+ gvert *ul; /* Linked list of unused verticies */
+ int na; /* Number of verticies allocated */
+ int nsv; /* Number of verticies that have been set */
+ int ntv; /* Number of verticies used in triangulation */
+ gvert **verts; /* Pointers to allocated verticies */
+ int read_inited; /* Flag set if gamut was initialised from a read */
+ int lu_inited; /* Flag set if radial surface lookup is inited */
+ int ne_inited; /* Flag set if nearest lookup is inited */
+ int cu_inited; /* Flag set if cusp values inited and trustworthy */
+ int nofilter; /* Flag, skip segmented maxima filtering */
+ int no2pass; /* Flag, do only one pass of convex hull */
+ int doingfake; /* Internal transient state */
+ int pass; /* Pass number for multi-pass */
+ double logpow; /* Convex hull compression power (default 0.25) */
+
+ gquad *tl, *tr; /* Top left and quadtree elements */
+
+ gtri *tris; /* Surface triangles linked list */
+ gedge *edges; /* Edges between the triangles linked list */
+
+ gbsp *lutree; /* Lookup function BSP tree root */
+ gnn *nns; /* nearest neighbor acceleration structure */
+
+ int cswbset; /* Flag to indicate that the cs white & black points are set */
+ double cs_wp[3]; /* Color spaces white point */
+ double cs_bp[3]; /* Color spaces black point */
+ double cs_kp[3]; /* Color spaces K only black point */
+ int gawbset; /* Flag to indicate that the gamut white & black points are set */
+ double ga_wp[3]; /* Gamut white point */
+ double ga_bp[3]; /* Gamut black point */
+ double ga_kp[3]; /* Gamut K only black point */
+
+ int dcuspixs; /* Cusp we're up to */
+ double dcusps[6][3];/* Entered cusp values to setcusps(, 3, ) */
+ double cusps[6][3]; /* Cusp values for red, yellow, green, cyan, blue & magenta */
+ /* if cu_inited nz */
+
+ double mx[3], mn[3]; /* Range covered by input points */
+
+ double xvra; /* Extra vertex ratio - set/used by nssverts() */
+ int ssnverts; /* total ss verticies - set/used by nssverts() */
+ int ssvertn; /* Number of verts created for current triangle */
+ sobol *ss; /* Sibol ss generator currently being used */
+
+ gtri *nexttri; /* Context for getnexttri() */
+
+/* Public: */
+ /* Methods */
+ void (*del)(struct _gamut *s); /* Free ourselves */
+
+ gvert *(*expand)(struct _gamut *s, double in[3]); /* Expand the gamut surface */
+
+ int (*getisjab)(struct _gamut *s); /* Return the isJab flag value */
+
+ int (*getisrast)(struct _gamut *s); /* Return the isRast flag value */
+
+ void (*setnofilt)(struct _gamut *s); /* Disable segmented maxima filtering */
+
+ void (*getcent)(struct _gamut *s, double *cent); /* Return the gamut center location */
+
+ void (*getrange)(struct _gamut *s, double *min, double *max); /* Return the gamut range */
+
+ double (*getsres)(struct _gamut *s); /* Return the surface resolution */
+
+ int (*compatible)(struct _gamut *s, struct _gamut *t); /* Return the nz if compatible gamuts */
+
+ int (*nrawverts)(struct _gamut *s); /* Return the number of raw verticies */
+
+ int (*getrawvert)(struct _gamut *s, double pos[3], int ix);
+ /* Return the raw verticies location */
+
+ int (*nraw0verts)(struct _gamut *s); /* Return the number of raw verticies in */
+ /* the radial maxima direction*/
+
+ int (*getraw0vert)(struct _gamut *s, double pos[3], int ix);
+ /* Return the raw 0 direction verticies location */
+
+ int (*nverts)(struct _gamut *s); /* Return the number of surface verticies */
+
+ int (*getvert)(struct _gamut *s, double *rad, double pos[3], int ix);
+ /* Return the surface triangle verticies location and radius */
+ /* start at 0, and returns value is next index or -1 if last */
+
+ int (*nssverts)(struct _gamut *s, double vpua);
+ /* Return the number of stratified sampling surface verticies, */
+ /* for the given verticies per unit area parameter. */
+
+ int (*getssvert)(struct _gamut *s, double *rad, double pos[3], double norn[3], int ix);
+ /* Return the stratified sampling surface verticies */
+ /* location and radius. nssverts() sets vpua */
+ /* norm will contain the normal of the triangle */
+ /* the point originates from. */
+
+ void (*startnexttri)(struct _gamut *s); /* Reset indexing through triangles for getnexttri() */
+
+ int (*getnexttri)(struct _gamut *s, int v[3]);
+ /* Return the next surface triange, nz on no more */
+ /* Index v[] corresponds to order of getvert() */
+
+ double (*volume)(struct _gamut *s);
+ /* Return the total volume enclosed by the gamut */
+
+ int (*intersect)(struct _gamut *s, struct _gamut *s1, struct _gamut *s2);
+ /* Initialise this gamut with the intersection of the */
+ /* the two given gamuts. */
+
+#ifdef NEVER /* Deprecated */
+ int (*expandbydiff)(struct _gamut *s, struct _gamut *s1, struct _gamut *s2, struct _gamut *s3, int docomp);
+ /* Initialise this gamut with a gamut which is s1 expanded */
+ /* (but never reduced) by the distance from s2 to s3. */
+ /* If docomp != 0, make gamut trace s3 if it's smaller than s1 */
+#endif
+
+ int (*compdstgamut)(struct _gamut *s, struct _gamut *img, struct _gamut *src,
+ struct _gamut *dst, int docomp, int doexpp, struct _gamut *nedst,
+ void (*cvect)(void *cntx, double *p2, double *p1), void *cntx);
+ /* Initialise this gamut with a destination mapping gamut. */
+
+ double (*radial)(struct _gamut *s, double out[3], double in[3]);
+ /* return point on surface in same radial direction. */
+ /* Return the radial radius to the surface point in */
+ /* colorspace units. out[] may be NULL */
+
+ double (*nradial)(struct _gamut *s, double out[3], double in[3]);
+ /* return point on surface in same radial direction, */
+ /* and normalised radial radius. This will be <= 1.0 if within */
+ /* gamut, and > 1.0 if out of gamut. out[] may be NULL */
+
+ void (*nearest)(struct _gamut *s, double out[3], double in[3]);
+ /* return point on surface closest to input */
+
+ void (*nearest_tri)(struct _gamut *s, double out[3], double in[3], gtri **ctri);
+ /* return point on surface closest to input & triangle */
+
+ int (*vector_isect)(struct _gamut *s, double *p1, double *p2, double *min, double *max,
+ double *mint, double *maxt,
+ gtri **mntri, gtri **mxtri);
+ /* Compute the intersection of the vector p1->p2 with */
+ /* the gamut surface. min is the intersection in the p1 direction, */
+ /* max is intersection in the p2 direction. mint and maxt are */
+ /* the parameter values at the two intersection points, a value of 0 */
+ /* being at p1 and 1 being at p2. mintri and maxtri return the */
+ /* intersection triangles. min, max, mint, maxt, */
+ /* mintri & maxtri may be NULL */
+ /* Return 0 if there is no intersection with the gamut. */
+
+ int (*vector_isectns)(struct _gamut *s, double *p1, double *p2, gispnt *lp, int ll);
+ /* Compute all the intersection pairs of the vector p1->p2 with */
+ /* the gamut surface. lp points to an array of ll gispnt to be */
+ /* filled in. If the list is too small, intersections will be */
+ /* arbitrarily ignored. */
+ /* Return the number of intersections set in list. Will be even. */
+ /* These will all be in then out pairs in direction p1->p2. */
+
+ void (*setwb)(struct _gamut *s, double *wp, double *bp, double *kp);
+ /* Define the colorspaces white, black and K only black points. */
+ /* May be NULL if unknown, and will be set to a default. */
+ /* Same colorspace as gamut */
+
+ int (*getwb)(struct _gamut *s, double *cswp, double *csbp, double *cskp,
+ double *gawp, double *gabp, double *gakp);
+ /* Get the colorspace and gamut white, black and K only black points. */
+ /* Return non-zero if not possible. Same colorspace as gamut */
+
+ void (*setcusps)(struct _gamut *s, int flag, double in[3]); /* Set potential cusp values. */
+ /* flag == 0 = reset, */
+ /* flag == 1 = add general point, */
+ /* flag == 3 = add definite point, */
+ /* flag == 2 = finish */
+
+ int (*getcusps)(struct _gamut *s, double cusps[6][3]); /* Get the cusp values for */
+ /* red, yellow, green, cyan, */
+ /* blue & magenta. Return */
+ /* nz if no cusps available. */
+
+ /* Following return nz on error: */
+ int (*write_vrml)(struct _gamut *s, char *filename,
+ int doaxes, int docusps); /* Write to a VRML .wrl file */
+ int (*write_gam)(struct _gamut *s, char *filename); /* Write to a CGATS .gam file */
+ int (*read_gam)(struct _gamut *s, char *filename); /* Read from a CGATS .gam file */
+
+ int (*write_trans_vrml)(struct _gamut *s, char *filename, /* Write transformed VRML .wrl */
+ int doaxes, int docusps, void (*transform)(void *cntx, double out[3], double in[3]), /* with xform */
+ void *cntx);
+
+}; typedef struct _gamut gamut;
+
+/* Creator */
+gamut *new_gamut(double sres, int isJab, int isRast); /* Surface resolution, 0.0 = default */
+
+/* Utility */
+void gamut_rect2radial(gamut *s, double out[3], double in[3]);
+void gamut_radial2rect(gamut *s, double out[3], double in[3]);
+void gamut_Lab2RGB(double *in, double *out);
+extern double gam_hues[2][7]; /* Generic Lab & Jab color hues in degrees */
+
+
+#endif /* GAMUT_H */
+
diff --git a/gamut/isecvol.c b/gamut/isecvol.c
new file mode 100644
index 0000000..71d918a
--- /dev/null
+++ b/gamut/isecvol.c
@@ -0,0 +1,320 @@
+
+/*
+ * Compute the intersection volume of two gamuts.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/1/7
+ * Version: 1.00
+ *
+ * Copyright 2008 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.
+ */
+
+/*
+ * TTBD:
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+#include "numlib.h"
+#include "gamut.h"
+
+/* Compute a triangles area */
+static double tri_area(
+double v1[3],
+double v2[3],
+double v3[3]) {
+ int i, j;
+ double sp, ss[3]; /* Triangle side lengths */
+ double area; /* Area of this triangle */
+ double *vv[3]; /* Pointers to vertexes */
+
+ vv[0] = v1;
+ vv[1] = v2;
+ vv[2] = v3;
+ /* Compute the full triangles area */
+ for (i = 0; i < 3; i++) { /* For each edge */
+ for (ss[i] = 0.0, j = 0; j < 3; j++) {
+ double dd = vv[i][j] - vv[(i+1) % 3][j];
+ ss[i] += dd * dd;
+ }
+ ss[i] = sqrt(ss[i]);
+ }
+ sp = 0.5 * (ss[0] + ss[1] + ss[2]); /* semi-perimeter */
+ area = sqrt(fabs(sp * (sp - ss[0]) * (sp - ss[1]) * (sp - ss[2]))); /* Area of triangle */
+
+ return area;
+}
+
+/* See if the given edge intersects a given triangle. */
+/* Return 1 if it does, 0 if it doesn't */
+static int edge_tri_isect(
+gamut *s, /* Gamut the triangle is in */
+double *ip, /* return intersection point */
+gtri *t, /* Triangle in question */
+gedge *e /* edge to test (may be from another gamut) */
+) {
+ double rv; /* Axis parameter value */
+ double gv[3]; /* Grey axis vector */
+ double ival[3]; /* Intersection value */
+ double den;
+ int j;
+
+ gv[0] = e->v[1]->p[0] - e->v[0]->p[0];
+ gv[1] = e->v[1]->p[1] - e->v[0]->p[1];
+ gv[2] = e->v[1]->p[2] - e->v[0]->p[2];
+
+ den = t->pe[0] * gv[0] + t->pe[1] * gv[1] + t->pe[2] * gv[2];
+ if (fabs(den) < 1e-10) {
+ return 0;
+ }
+
+ /* Compute the intersection of the grey axis vector with the triangle plane */
+ rv = -(t->pe[0] * e->v[0]->p[0]
+ + t->pe[1] * e->v[0]->p[1]
+ + t->pe[2] * e->v[0]->p[2]
+ + t->pe[3])/den;
+
+ /* Compute the actual intersection point */
+ ival[0] = e->v[0]->p[0] + rv * gv[0];
+ ival[1] = e->v[0]->p[1] + rv * gv[1];
+ ival[2] = e->v[0]->p[2] + rv * gv[2];
+
+ /* Check if the intersection is on the edge */
+ if (rv < 0.0 || rv > 1.0)
+ return 0;
+
+ /* Check if the intersection point is within the triangle */
+ for (j = 0; j < 3; j++) {
+ double ds;
+ ds = t->ee[j][0] * (ival[0] - s->cent[0]) /* Convert to relative for edge check */
+ + t->ee[j][1] * (ival[1] - s->cent[1])
+ + t->ee[j][2] * (ival[2] - s->cent[2])
+ + t->ee[j][3];
+ if (ds > 1e-8) {
+ return 0; /* Not within triangle */
+ }
+ }
+
+ /* Got an intersection point */
+ ip[0] = ival[0];
+ ip[1] = ival[1];
+ ip[2] = ival[2];
+
+ return 1;
+}
+
+
+/* Return the total volume of the gamut */
+/* Return -1.0 if incomaptible gamuts */
+double isect_volume(
+gamut *s1,
+gamut *s2
+) {
+ int i, j, k;
+ gtri *tp1, *tp2; /* Triangle pointer */
+ double vol; /* Gamut volume */
+
+ if (s1->compatible(s1, s2) == 0)
+ return -1.0;
+
+ if IS_LIST_EMPTY(s1->tris)
+ s1->triangulate(s1);
+ if IS_LIST_EMPTY(s2->tris)
+ s2->triangulate(s2);
+
+ vol = 0.0;
+
+ /* For first gamut then second gamut */
+ for (k = 0; k < 2; k++) {
+
+ if (k == 1) { /* Swap the two gamuts roles */
+ gamut *st = s1;
+ s1 = s2;
+ s2 = st;
+printf("~1 doing second gamut inside first\n");
+ } else {
+printf("~1 doing first gamut inside second\n");
+ }
+
+ /* Compute the area of each triangle in the list that is within, */
+ /* the other gamut, and accumulate the gamut volume. */
+ tp1 = s1->tris;
+ FOR_ALL_ITEMS(gtri, tp1) {
+ double sp, ss[3]; /* Triangle side lengths */
+ double area; /* Area of this triangle */
+ double dp; /* Dot product of point in triangle and normal */
+ int inout[3]; /* 0 = inside, 1 = outside */
+ int nout; /* Number that are out */
+
+printf("~1 doing triangle %d from %s gamut\n",tp1->n,k == 0 ? "first" : "second");
+ /* See how many verticies in the triangle are contained within */
+ /* the other gamut. */
+ nout = 0;
+ for (i = 0; i < 3; i++) { /* For each vertex */
+ double pl;
+ pl = s2->nradial(s2, NULL, tp1->v[i]->p);
+
+ /* We add a slight hysterysis to avoid issues */
+ /* with identical triangles in two gamuts. */
+ if ((k == 0 && pl > (1.0 + 1e-10))
+ || (k == 1 && pl > (1.0 - 1e-10))) {
+ nout++;
+ inout[i] = 1;
+ } else
+ inout[i] = 0;
+ }
+
+printf("~1 verticies outside = %d\n",nout);
+
+ /* If none are in, skip this triangle */
+ if (nout == 3)
+ continue;
+
+ /* Compute the full triangles area */
+ area = tri_area(tp1->v[0]->p, tp1->v[1]->p, tp1->v[2]->p);
+printf("~1 full triangle area = %f\n",area);
+
+ /* If the triangle is not completely in, locate all the intersections */
+ /* between it and triangles in the other gamut */
+ if (nout != 0) {
+ gvert *opv; /* Pointer to the one "in" or "out" vertex */
+ double parea = 0.0; /* Total partial area */
+
+ /* Locate the odd point out of the three */
+ if (nout == 2) { /* Look for the one "in" point */
+ for (j = 0; j < 3; j++) {
+ if (inout[j] == 0)
+ break;
+ }
+ } else { /* Look for the one "out" point */
+ for (j = 0; j < 3; j++) {
+ if (inout[j] == 1)
+ break;
+ }
+ }
+ opv = tp1->v[j];
+
+ tp2 = s2->tris;
+ FOR_ALL_ITEMS(gtri, tp2) { /* Other gamut triangles */
+ double isps[2][3]; /* Intersection npoints */
+ int nisps; /* Number of intersection points */
+ double isp[3]; /* New intersection point */
+ int kk;
+
+ /* Do a min/max intersection elimination test */
+ for (i = 0; i < 3; i++) {
+ if (tp2->mix[1][i] < tp1->mix[0][i]
+ || tp2->mix[0][i] > tp1->mix[1][i])
+ break; /* min/max don't overlap */
+ }
+ if (i < 3)
+ continue; /* Skip this triangle, it can't intersect */
+
+//printf("~1 located possible intersecting triangle %d\n",tp2->n);
+
+ /* Locate intersection of all sides of one triangle with */
+ /* the plane of the other. Keep the two points of */
+ /* intersection that lie within the triangles. */
+ nisps = 0;
+//printf("~1 initial nisps = %d\n",nisps);
+ for (kk = 0; kk < 2; kk++) {
+ gamut *ts; /* Triangle gamut */
+ gtri *tpa; /* Triangle pointer */
+ gtri *tpb; /* Other triangle pointer */
+ if (kk == 0) {
+ ts = s1;
+ tpa = tp1;
+ tpb = tp2;
+ } else {
+ ts = s2;
+ tpa = tp2;
+ tpb = tp1;
+ }
+
+ /* For each edge */
+ for (j = 0; j < 3; j++) {
+ if (edge_tri_isect(ts, isp, tpa, tpb->e[j]) != 0) {
+//printf("~1 isect %f %f %f\n", isp[0],isp[1],isp[2]);
+ if (nisps < 2) {
+//printf("~1 added at %d\n",nisps);
+ icmAry2Ary(isps[nisps], isp);
+ nisps++;
+ } else { /* Figure which one to replace */
+ int xx;
+ /* Replace the one closest to the new one, */
+ /* if the new one is further from the other one */
+
+ if (icmNorm33sq(isps[0], isp) < icmNorm33sq(isps[1], isp))
+ xx = 0;
+ else
+ xx = 1;
+
+ if (icmNorm33sq(isps[xx ^ 1], isp)
+ > icmNorm33sq(isps[xx ^ 1], isps[xx])) {
+//printf("~1 replaced %d\n",xx);
+ icmAry2Ary(isps[xx], isp);
+ }
+ }
+ }
+ }
+ }
+ if (nisps == 0) {
+//printf("~1 no intersection\n");
+ continue;
+
+ } else if (nisps == 2) {
+ double sarea;
+
+printf("~1 sub triangle =\n");
+printf("~1 com %f %f %f\n", opv->p[0], opv->p[1], opv->p[2]);
+printf("~1 1st %f %f %f\n", isps[0][0], isps[0][1], isps[0][2]);
+printf("~1 2nd %f %f %f\n", isps[1][0], isps[1][1], isps[1][2]);
+
+ /* Accumulate area of these two points + odd point */
+ sarea = tri_area(opv->p, isps[0], isps[1]);
+printf("~1 located intersecting triangle %d\n",tp2->n);
+printf("~1 got sub area %f\n",sarea);
+ parea += sarea;
+ } else { /* Hmm */
+printf("~1 unexpectedly got %d intersection points in triangle\n",nisps);
+ }
+ } END_FOR_ALL_ITEMS(tp2);
+
+ if (nout == 2) { /* One "in" point */
+ area = parea;
+ } else { /* One "out" point */
+ area = area - parea;
+ }
+printf("~1 partial area = %f\n",area);
+ }
+
+ /* Dot product between first vertex in triangle and the unit normal vector */
+ dp = tp1->v[0]->p[0] * tp1->pe[0]
+ + tp1->v[0]->p[1] * tp1->pe[1]
+ + tp1->v[0]->p[2] * tp1->pe[2];
+
+printf("~1 vector volume = %f\n",dp * area);
+ /* Accumulate gamut volume */
+ vol += dp * area;
+
+ } END_FOR_ALL_ITEMS(tp1);
+ }
+
+printf("~1 volume sum = %f\n",vol);
+ vol = fabs(vol)/3.0;
+
+printf("~1 final volume = %f\n",vol);
+ return vol;
+}
+
+
diff --git a/gamut/maptest.c b/gamut/maptest.c
new file mode 100644
index 0000000..1c595b6
--- /dev/null
+++ b/gamut/maptest.c
@@ -0,0 +1,240 @@
+
+/*
+ * Gamut mapping test code. Test the gamut mapping library.
+ *
+ * Author: Graeme W. Gill
+ * Date: 29/10/00
+ * Version: 1.00
+ *
+ * Copyright 2000, 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.
+ */
+
+/* TTBD:
+ *
+ */
+
+#undef DEBUG /* test a single value out */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "xicc.h"
+#include "gamut.h"
+#include "rspl.h"
+#include "gammap.h"
+
+void usage(void) {
+ fprintf(stderr,"Map bteween two gamuts, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: maptest [options] ingamut outgamut diag_gamut\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -s Do saturation style expand/compress\n");
+ fprintf(stderr," -i imggamut.gam Use an image gamut\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa, nfa, mfa;
+ char *xl;
+ char in_name[100];
+ char img_name[MAXNAMEL+1] = "";
+ char out_name[100];
+ char diag_name[100];
+ int sat = 0;
+ int verb = 0;
+ gammap *map; /* Regular split gamut mapping */
+ icxGMappingIntent gmi;
+
+ gamut *gin, *gout; /* Input and Output gamuts */
+ gamut *gimg = NULL; /* Optional image gamut */
+
+ error_program = argv[0];
+
+ if (argc < 3)
+ usage();
+
+ /* Process the arguments */
+ mfa = 3; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ /* Saturation */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ sat = 1;
+ }
+
+ /* Image gamut */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ if (na == NULL) usage();
+ fa = nfa;
+ strncpy(img_name,na,MAXNAMEL); img_name[MAXNAMEL] = '\000';
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(out_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(diag_name,argv[fa++]);
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* read the input device gamut */
+
+ gin = new_gamut(0.0, 0, 0);
+
+ if ((xl = strrchr(in_name, '.')) == NULL) { /* Add .gam extention if there isn't one */
+ xl = in_name + strlen(in_name);
+ strcpy(xl,".gam");
+ }
+
+ if (gin->read_gam(gin, in_name))
+ error("Reading input gamut failed");
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* read the optional image gamut */
+
+ if (img_name[0] != '\000') {
+
+ gimg = new_gamut(0.0, 0, 0);
+
+ if ((xl = strrchr(img_name, '.')) == NULL) { /* Add .gam extention if there isn't one */
+ xl = img_name + strlen(img_name);
+ strcpy(xl,".gam");
+ }
+
+ if (gimg->read_gam(gimg, img_name))
+ error("Reading image gamut failed");
+ } else {
+ gimg = gin;
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* read the output device gamut */
+
+ gout = new_gamut(0.0, 0, 0);
+
+ if ((xl = strrchr(out_name, '.')) == NULL) { /* Add .gam extention if there isn't one */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".gam");
+ }
+
+ if (gout->read_gam(gout, out_name))
+ error("Reading output gamut failed");
+
+ /* - - - - - - - - - - - - - - - - - - - */
+
+ /* Create the gamut mapping */
+ gmi.usecas = 0;
+ gmi.usemap = 1;
+ gmi.greymf = 1.0; /* Gray axis hue matching factor, 0.0 - 1.0 */
+ gmi.glumwcpf = 1.0; /* Grey axis luminance white compression factor, 0.0 - 1.0 */
+ gmi.glumwexf = 1.0; /* Grey axis luminance white expansion factor, 0.0 - 1.0 */
+ gmi.glumbcpf = 1.0; /* Grey axis luminance black compression factor, 0.0 - 1.0 */
+ gmi.glumbexf = 1.0; /* Grey axis luminance black expansion factor, 0.0 - 1.0 */
+ gmi.glumknf = 0.7; /* Gray axis luminance knee factor, 0.0 - 1.0 */
+ gmi.gamcpf = 1.0; /* Gamut compression factor, 0.0 - 1.0 */
+ if (sat)
+ gmi.gamexf = 1.0; /* Gamut expansion factor, 0.0 - 1.0 */
+ else
+ gmi.gamexf = 0.0; /* Gamut expansion factor, 0.0 - 1.0 */
+ gmi.gamcknf = 0.1; /* Gamut comp. knee factor, 0.0 - 1.0 */
+ gmi.gamxknf = 0.1; /* Gamut exp. knee factor, 0.0 - 1.0 */
+ if (sat) {
+ gmi.gampwf = 0.0; /* Gamut Perceptual Map weighting factor, 0.0 - 1.0 */
+ gmi.gamswf = 1.0; /* Gamut Saturation Map weighting factor, 0.0 - 1.0 */
+ } else {
+ gmi.gampwf = 1.0; /* Gamut Perceptual Map weighting factor, 0.0 - 1.0 */
+ gmi.gamswf = 0.0; /* Gamut Saturation Map weighting factor, 0.0 - 1.0 */
+ }
+ gmi.satenh = 0.0; /* Saturation enhancement factor */
+ gmi.desc = "mapetest";
+ gmi.icci = 0;
+
+ map = new_gammap(
+ verb,
+ gin, /* Source gamut */
+ gimg, /* Image gamut */
+ gout, /* Destination gamut */
+ &gmi,
+ 0, 0, /* Normal black points */
+ 0, /* Normal CMY cusp mapping */
+ 0, /* No relative weighting override */
+ 17, /* rspl resolution of 17 */
+ NULL, /* No input range override */
+ NULL,
+ "gammap.wrl" /* Diagnostic plot */
+ );
+
+ if (map == NULL) {
+ error("new_gammap() failed\n");
+ }
+
+ if (verb)
+ printf("Got gamut mapping\n");
+
+ /* Transform the input gamut by the gamut mapping */
+ { /* Bad - delving inside gamut! */
+ int i;
+ for (i = 0; i < gin->nv; i++) {
+
+ /* transform the input gamutboundary points */
+ map->domap(map, gin->verts[i]->p, gin->verts[i]->p);
+ }
+ }
+
+ /* Output a transformed gamut */
+ if ((xl = strrchr(diag_name, '.')) == NULL) { /* Add .gam extention if there isn't one */
+ xl = diag_name + strlen(diag_name);
+ strcpy(xl,".gam");
+ }
+ gin->write_gam(gin, diag_name);
+
+ /* Clean up */
+ gout->del(gout);
+ gin->del(gin);
+ if (gimg != gin)
+ gimg->del(gimg);
+
+ return 0;
+}
+
diff --git a/gamut/nearsmth.c b/gamut/nearsmth.c
new file mode 100644
index 0000000..1f48f20
--- /dev/null
+++ b/gamut/nearsmth.c
@@ -0,0 +1,3570 @@
+
+/*
+ * nearsmth
+ *
+ * Gamut mapping support routine that creates a list of
+ * guide vectors that map from a source to destination
+ * gamut, smoothed to retain reasonably even spacing.
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/1/2002
+ * Version: 1.00
+ *
+ * Copyright 2002 - 2006 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.
+ */
+
+/*
+ Description:
+
+ We create a set of "guide vectors" that map the source gamut to
+ the destination, for use by the gammap code in creating
+ a 3D gamut mapping.
+
+ (See gammap.txt for a more detailed descrition)
+
+ */
+
+/*
+ * TTBD:
+ *
+ * It might work better if the cusp mapping had separate control
+ * over the L and h degree of map, as well as the L and h effective radius ?
+ * That way, saturation hue distortions with L might be reduced.
+ *
+ * Improve error handling.
+ *
+ * Major defect with some gamut combinations is "button" around
+ * cusps. Not sure what the mechanism is, since it's not obvious
+ * from the 3D vector plots what the cause is. (fixed ?)
+ * Due to poor internal control ?
+ *
+ * Mapping to very small, odd shaped gamuts (ie. Bonet) is poor -
+ * there are various bugs and artefacts to be figured out.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+#include "numlib.h"
+#include "rspl.h"
+#include "gamut.h"
+#include "nearsmth.h"
+#include "vrml.h"
+
+#undef SAVE_VRMLS /* [Und] Save various vrml's */
+#undef PLOT_MAPPING_INFLUENCE /* [Und] Plot sci_gam colored by dominant guide influence: */
+ /* Absolute = red, Relative = yellow, Radial = blue, Depth = green */
+#undef PLOT_AXES /* [Und] */
+#undef PLOT_EVECTS /* [Und] Create VRML of error correction vectors */
+#undef VERB /* [Und] [0] If <= 1, print progress headings */
+ /* if > 1, print information about everything */
+#undef SHOW_NEIGB_WEIGHTS /* [Und] Show the weighting for each point of neighbours */
+
+#undef DIAG_POINTS /* [Und] Short circuite mapping and show vectors of various */
+ /* intermediate points (see #ifdef DIAG_POINTS) */
+
+#undef PLOT_DIGAM /* [Und] Rather than DST_GMT - don't free it (#def in gammap.c too) */
+
+#define SUM_POW 2.0 /* Delta's are sum of component deltas ^ SUM_POW */
+#define LIGHT_L 70.0 /* "light" L/J value */
+#define DARK_L 5.0 /* "dark" L/J value */
+#define NEUTRAL_C 20.0 /* "neutral" C value */
+#define NO_TRIALS 6 /* [6] Number of random trials */
+#define VECSMOOTHING /* [Def] Enable vector smoothing */
+#define VECADJPASSES 3 /* [3] Adjust vectors after smoothing to be on dest gamut */
+#define RSPLPASSES 4 /* [4] Number of rspl adjustment passes */
+#define RSPLSCALE 1.8 /* [1.8] Offset within gamut for rspl smoothingto aim for */
+#define SHRINK 5.0 /* Shrunk destination evect surface factor */
+#define CYLIN_SUBVEC /* [Def] Make sub-vectors always cylindrical direction */
+#define SUBVEC_SMOOTHING /* [Def] Smooth the sub-vectors */
+
+ /* Experimental - not used: */
+
+ /* This has similar effects to lowering SUM_POW without the side effects */
+ /* and improves hue detail for small destination gamuts. */
+ /* (This and lxpow are pretty hacky. Is there a better way ?) */
+#undef EMPH_NEUTRAL //0.5 /* Emphasis strength near neutral */
+#undef EMPH_THR //10.0 /* delta C threshold above which it kicks in */
+
+#undef LINEAR_HUE_SUM /* Make delta^2 = (sqrt(l^2 + c^2) + h)^2 */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#if defined(VERB)
+# define VA(xxxx) printf xxxx
+# if VERB > 1
+# define VB(xxxx) printf xxxx
+# else
+# define VB(xxxx)
+# endif
+#else
+# define VA(xxxx)
+# define VB(xxxx)
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#if defined(SAVE_VRMLS) && defined(PLOT_MAPPING_INFLUENCE)
+static void create_influence_plot(nearsmth *smp, int nmpts);
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the weighted delta E squared of in1 - in2 */
+/* (This is like the CIE DE94) */
+static double wdesq(
+double in1[3], /* Destination location */
+double in2[3], /* Source location */
+double lweight,
+double cweight,
+double hweight,
+double sumpow /* Sum power. 0.0 == 2.0 */
+) {
+ double desq, dhsq;
+ double dlsq, dcsq;
+ double vv;
+ double dc, c1, c2;
+
+//printf("~1 wdesq got %f %f %f and %f %f %f\n", in1[0], in1[1], in1[2], in2[0], in2[1], in2[2]);
+ /* Compute delta L squared and delta E squared */
+ {
+ double dl, da, db;
+ dl = in1[0] - in2[0];
+ dlsq = dl * dl; /* dl squared */
+ da = in1[1] - in2[1];
+ db = in1[2] - in2[2];
+
+ desq = dlsq + da * da + db * db;
+ }
+
+ /* compute delta chromanance squared */
+ {
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(in1[1] * in1[1] + in1[2] * in1[2]);
+ c2 = sqrt(in2[1] * in2[1] + in2[2] * in2[2]);
+
+ dc = c1 - c2;
+ dcsq = dc * dc;
+
+ /* [ Making dcsq = sqrt(dcsq) here seemes */
+ /* to improve the saturation result. Subsumed by a.xl ? ] */
+ }
+
+ /* Compute delta hue squared */
+ if ((dhsq = desq - dlsq - dcsq) < 0.0)
+ dhsq = 0.0;
+
+#ifdef EMPH_NEUTRAL /* Emphasise hue differences whenc dc is large and we are */
+ /* close to the neutral axis */
+ vv = 3.0 / (1.0 + 0.03 * c1); /* Full strength scale factor from dest location */
+ vv = 1.0 + EMPH_NEUTRAL * (vv - 1.0); /* Reduced strength scale factor */
+ vv *= (dc + EMPH_THR)/EMPH_THR;
+ dhsq *= vv * vv; /* Scale squared hue delta */
+#endif
+
+ if (sumpow == 0.0 || sumpow == 2.0) { /* Normal sum of squares */
+#ifdef HACK
+ vv = sqrt(lweight * dlsq + cweight * dcsq) + sqrt(hweight * dhsq);
+ vv *= vv;
+ vv = fabs(vv); /* Avoid -0.0 */
+#else
+ vv = lweight * dlsq + cweight * dcsq + hweight * dhsq;
+ vv = fabs(vv); /* Avoid -0.0 */
+#endif
+ } else {
+ sumpow *= 0.5;
+ vv = lweight * pow(dlsq, sumpow) + cweight * pow(dcsq,sumpow) + hweight * pow(dhsq,sumpow);
+ vv = fabs(vv); /* Avoid -0.0 */
+ vv = pow(vv, 1.0/sumpow);
+ }
+
+//printf("~1 returning wdesq %f from %f * %f + %f * %f + %f * %f\n", fabs(vv),lweight, dlsq, cweight, dcsq, hweight, dhsq);
+
+ return vv;
+}
+
+/* Compute the LCh differences squared of in1 - in2 */
+/* (This is like the CIE DE94) */
+static void diffLCh(
+double out[3],
+double in1[3], /* Destination location */
+double in2[3] /* Source location */
+) {
+ double desq, dhsq;
+ double dlsq, dcsq;
+ double vv;
+ double dc, c1, c2;
+
+ /* Compute delta L squared and delta E squared */
+ {
+ double dl, da, db;
+ dl = in1[0] - in2[0];
+ dlsq = dl * dl; /* dl squared */
+ da = in1[1] - in2[1];
+ db = in1[2] - in2[2];
+
+ desq = dlsq + da * da + db * db;
+ }
+
+ /* compute delta chromanance squared */
+ {
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(in1[1] * in1[1] + in1[2] * in1[2]);
+ c2 = sqrt(in2[1] * in2[1] + in2[2] * in2[2]);
+
+ dc = c1 - c2;
+ dcsq = dc * dc;
+
+ /* [ Making dcsq = sqrt(dcsq) here seemes */
+ /* to improve the saturation result. Subsumed by a.xl ? ] */
+ }
+
+ /* Compute delta hue squared */
+ if ((dhsq = desq - dlsq - dcsq) < 0.0)
+ dhsq = 0.0;
+
+#ifdef EMPH_NEUTRAL /* Emphasise hue differences whenc dc is large and we are */
+ /* close to the neutral axis */
+ vv = 3.0 / (1.0 + 0.03 * c1); /* Full strength scale factor from dest location */
+ vv = 1.0 + EMPH_NEUTRAL * (vv - 1.0); /* Reduced strength scale factor */
+ vv *= (dc + EMPH_THR)/EMPH_THR;
+ dhsq *= vv * vv; /* Scale squared hue delta */
+#endif
+
+ out[0] = dlsq;
+ out[1] = dcsq;
+ out[2] = dhsq;
+}
+
+/* Given the weighting structure and the relevant point locations */
+/* return the total weighted error squared. */
+static double comperr(
+nearsmth *p, /* Guide point data */
+gammapweights *w, /* weightings */
+double dtp[3], /* Dest test point being evaluated */
+double aodv[3], /* Weighted destination closest value to source */
+double drv[3], /* Source mapped radially to dest */
+double dcratio, /* Depth compression ratio of mapping */
+double dxratio /* Depth expansion ratio of mapping */
+) {
+ double a_o;
+ double va, vr = 0.0, vl, vd, vv = 0.0;
+
+ /* Absolute, Delta E^2 between test point and destination closest */
+ /* aodv is already positioned acording to the LCh weights, */
+ /* so weight as per average of these */
+ a_o = w->a.o;
+ va = wdesq(dtp, aodv, a_o, a_o, a_o, SUM_POW);
+
+ /* Radial. Delta E^2 between test point and source mapped radially to dest gamut */
+ vl = wdesq(dtp, drv, w->rl.l, w->rl.c, w->rl.h, SUM_POW);
+
+ /* Depth ratio error^2. */
+ vd = w->d.co * dcratio * dcratio
+ + w->d.xo * dxratio * dxratio;
+
+ /* Diagnostic values */
+ p->dbgv[0] = va;
+ p->dbgv[1] = vr;
+ p->dbgv[2] = vl;
+ p->dbgv[3] = vd;
+
+ vv = va + vr + vl + vd; /* Sum of squares */
+// vv = sqrt(va) + sqrt(vr) + sqrt(vl) + sqrt(vd); /* Linear sum is better ? */
+// vv = pow(va, 0.7) + pow(vr, 0.7) + pow(vl, 0.7) + pow(vd, 0.7); /* Linear sum is better ? */
+
+#ifdef NEVER
+ printf("~1 dtp %f %f %f\n", dtp[0], dtp[1], dtp[2]);
+ printf("~1 va = %f from aodv %f %f %f, weight %f\n", va, aodv[0], aodv[1], aodv[2], a_o);
+ printf("~1 vl = %f from drv %f %f %f, weights %f %f %f\n", vl, drv[0], drv[1], drv[2], w->rl.l, w->rl.c, w->rl.h);
+ printf("~1 vd = %f from d.co %f d.xo %f, weights %f %f\n", vd, w->d.co,w->d.xo,dcratio * dcratio,dxratio * dxratio);
+ printf("~1 return vv = %f\n", vv);
+#endif /* NEVER */
+
+ return vv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Structure to hold context for powell optimisation */
+/* and cusp mapping function. */
+struct _smthopt {
+ /* optimisation */
+ int pass; /* Itteration round */
+ int ix; /* Index of point being optimized */
+ nearsmth *p; /* Point being optimised */
+ int useexp; /* Flag indicating whether expansion is permitted */
+ int debug; /* debug flag */
+ gamut *shgam; /* for optfunc1a */
+
+ /* Setup state */
+ int isJab; /* Flag indicating Jab rather than Lab space */
+ int donaxis; /* Flag indicating whether neutral axis information is real */
+ int docusp; /* Flag indicating whether cusp information is present */
+ gammapweights *xwh; /* Structure holding expanded hextant weightings */
+ gamut *sgam; /* Source colorspace gamut */
+
+ /* Cusp alignment mapping */
+ /* 0 = src, 1 = dst, then cusp then value(s) */
+ double cusps[2][9][3]; /* raw cusp values - red .. magenta, white [6], black [7] & grey [8] */
+ double rot[2][3][4]; /* Rotation to align to black/white center */
+ double irot[2][3][4]; /* Inverse rotation */
+ double cusp_lab[2][9][3]; /* Cusp + B&W + grey rotated Lab value */
+ double cusp_lch[2][6][3]; /* Cusp LCH value */
+ double cusp_pe[2][6][4]; /* L direction plane equations per segment */
+ double cusp_bc[2][6][2][3][3]; /* light/dark to/from 3x3 baricentic transform matrix */
+
+ /* Inversion support */
+ double tv[3];
+ gammapweights *wt; /* Weights for this inversion */
+
+ double mm[3][4]; /* Direction alignment rotation */
+ double m2[2][2]; /* Additional matrix to alight a with L axis */
+ double manv[3]; /* anv[] transformed by mm and m2 */
+
+}; typedef struct _smthopt smthopt;
+
+static void init_ce(smthopt *s, gamut *sc_gam, gamut *d_gam, int src_kbp, int dst_kbp, double d_bp[3]);
+static void comp_ce(smthopt *s, double out[3], double in[3], gammapweights *wt);
+static void inv_comp_ce(smthopt *s, double out[3], double in[3], gammapweights *wt);
+static double comp_naxbf(smthopt *s, double in[3]);
+static double comp_lvc(smthopt *s, double in[3]);
+
+static double spow(double arg, double ex) {
+ if (arg < 0.0)
+ return -pow(-arg, ex);
+ else
+ return pow(arg, ex);
+}
+
+static void spow3(double *out, double *in, double ex) {
+ int j;
+ for (j = 0; j < 3; j++) {
+ if (in[j] < 0.0)
+ out[j] = -pow(-in[j], ex);
+ else
+ out[j] = pow(in[j], ex);
+ }
+}
+
+/* Powell optimisation function for setting minimal absolute error target point. */
+/* We get a 2D plane in the 3D space, of the destination point, */
+/* who's location we are optimizing. */
+static double optfunc1(
+void *fdata,
+double *_dv
+) {
+ smthopt *s = (smthopt *)fdata;
+ nearsmth *p = s->p; /* Point being optimised */
+ int i, j, k;
+ double dv[3]; /* 3D point in question */
+ double ddv[3]; /* Point in question mapped to dst surface */
+ double delch[3];
+ double rv; /* Out of gamut, return value */
+
+ /* Convert from 2D to 3D. */
+ dv[2] = _dv[1];
+ dv[1] = _dv[0];
+ dv[0] = 50.0;
+ icmMul3By3x4(dv, p->m3d, dv);
+
+//printf("~1 optfunc1 got 2D %f %f -> 3D %f %f %f\n", _dv[0], _dv[1], dv[0], dv[1], dv[2]);
+ p->dgam->radial(p->dgam, ddv, dv); /* Map to dst surface to check current location */
+//printf("~1 optfunc1 got %f %f %f -> surface %f %f %f\n", dv[0], dv[1], dv[2], ddv[0], ddv[1], ddv[2]);
+
+ if (p->swap) {
+ /* This is actually a point on the real source gamut, so */
+ /* convert to cusp mapped rotated, elevated source gamut value */
+ comp_ce(s, ddv, ddv, &p->wt);
+// printf("~1 after rot & elevate got %f %f %f\n",ddv[0],ddv[1],ddv[2]);
+ }
+
+#ifdef NEVER
+ /* Absolute weighted delta E between source and dest test point */
+ rv = wdesq(ddv, p->sv, p->wt.ra.l, p->wt.ra.c, p->wt.ra.h, SUM_POW);
+#else
+ {
+ double ppp = p->wt.a.lxpow;
+ double thr = p->wt.a.lxthr; /* Xover between normal and power */
+ double sumpow = SUM_POW;
+
+ diffLCh(delch, ddv, p->sv);
+
+ if (sumpow == 0.0 || sumpow == 2.0) { /* Normal sum of squares */
+#ifdef LINEAR_HUE_SUM
+ double ll, cc, hh;
+ ll = p->wt.ra.l * pow(delch[0], ppp) * thr/pow(thr, ppp);
+ cc = p->wt.ra.c * delch[1];
+ hh = p->wt.ra.h * delch[2];
+ rv = sqrt(ll + cc) + sqrt(hh);
+ rv *= rv;
+#else
+ rv = p->wt.ra.l * pow(delch[0], ppp) * thr/pow(thr, ppp)
+ + p->wt.ra.c * delch[1]
+ + p->wt.ra.h * delch[2];
+#endif
+ } else {
+ sumpow *= 0.5;
+
+ rv = p->wt.ra.l * pow(delch[0], ppp * sumpow) * thr/pow(thr, ppp * sumpow)
+ + p->wt.ra.c * pow(delch[1], sumpow)
+ + p->wt.ra.h * pow(delch[2], sumpow);
+ }
+ }
+#endif
+
+ if (s->debug)
+ printf("debug: rv = %f from %f %f %f\n",rv, ddv[0], ddv[1], ddv[2]);
+
+//printf("~1 sv %4.2f %4.2f %4.2f, ddv %4.2f %4.2f %4.2f\n", p->sv[0], p->sv[1], p->sv[2], ddv[0], ddv[1], ddv[2]);
+//printf("~1 rv = %f\n",rv);
+ return rv;
+}
+
+/* Powell optimisation function for setting minimal absolute error target point, */
+/* from dest gamut to shrunk destination gamut. */
+/* We get a 2D plane in the 3D space, of the destination point, */
+/* who's location we are optimizing. */
+static double optfunc1a(
+void *fdata,
+double *_dv
+) {
+ smthopt *s = (smthopt *)fdata;
+ nearsmth *p = s->p; /* Point being optimised */
+ int i, j, k;
+ double dv[3]; /* 3D point in question */
+ double ddv[3]; /* Point in question mapped to shgam surface */
+ double delch[3];
+ double rv; /* Out of gamut, return value */
+
+ /* Convert from 2D to 3D. */
+ dv[2] = _dv[1];
+ dv[1] = _dv[0];
+ dv[0] = 50.0;
+ icmMul3By3x4(dv, p->m3d, dv);
+
+//printf("~1 optfunc1a got 2D %f %f -> 3D %f %f %f\n", _dv[0], _dv[1], dv[0], dv[1], dv[2]);
+ s->shgam->radial(s->shgam, ddv, dv); /* Map to shgam surface to check current location */
+//printf("~1 optfunc1a got %f %f %f -> surface %f %f %f\n", dv[0], dv[1], dv[2], ddv[0], ddv[1], ddv[2]);
+
+#ifdef NEVER
+ /* Absolute weighted delta E between source and dest test point */
+ rv = wdesq(ddv, p->sv, p->wt.ra.l, p->wt.ra.c, p->wt.ra.h, SUM_POW);
+#else
+ {
+ double ppp = p->wt.a.lxpow;
+ double thr = p->wt.a.lxthr; /* Xover between normal and power */
+ double sumpow = SUM_POW;
+
+ diffLCh(delch, ddv, p->dv);
+
+ if (sumpow == 0.0 || sumpow == 2.0) { /* Normal sum of squares */
+#ifdef LINEAR_HUE_SUM
+ double ll, cc, hh;
+ ll = p->wt.ra.l * pow(delch[0], ppp) * thr/pow(thr, ppp);
+ cc = p->wt.ra.c * delch[1];
+ hh = p->wt.ra.h * delch[2];
+ rv = sqrt(ll + cc) + sqrt(hh);
+ rv *= rv;
+#else
+ rv = p->wt.ra.l * pow(delch[0], ppp) * thr/pow(thr, ppp)
+ + p->wt.ra.c * delch[1]
+ + p->wt.ra.h * delch[2];
+#endif
+ } else {
+ sumpow *= 0.5;
+
+ rv = p->wt.ra.l * pow(delch[0], ppp * sumpow) * thr/pow(thr, ppp * sumpow)
+ + p->wt.ra.c * pow(delch[1], sumpow)
+ + p->wt.ra.h * pow(delch[2], sumpow);
+ }
+ }
+#endif
+
+ if (s->debug)
+ printf("debug: rv = %f from %f %f %f\n",rv, ddv[0], ddv[1], ddv[2]);
+
+//printf("~1 sv %4.2f %4.2f %4.2f, ddv %4.2f %4.2f %4.2f\n", p->sv[0], p->sv[1], p->sv[2], ddv[0], ddv[1], ddv[2]);
+//printf("~1 rv = %f\n",rv);
+ return rv;
+}
+
+
+/* Compute available depth errors p->dcratio and p->dxratio */
+static void comp_depth(
+smthopt *s,
+nearsmth *p, /* Point being optimized */
+double *dv /* 3D Location being evaluated */
+) {
+ double *sv, nv[3], nl; /* Source, dest points, normalized vector between them */
+ double mint, maxt;
+ gtri *mintri = NULL, *maxtri = NULL;
+
+ sv = p->_sv;
+
+ p->dcratio = p->dxratio = 0.0; /* default, no depth error */
+
+ icmSub3(nv, dv, sv); /* Mapping vector */
+ nl = icmNorm3(nv); /* It's length */
+ if (nl > 0.1) { /* If mapping is non trivial */
+
+ icmScale3(nv, nv, 1.0/nl); /* Make mapping vector normal */
+
+ /* Compute actual depth of ray into destination (norm) or from source (expansion) gamut */
+ if (p->dgam->vector_isect(p->dgam, sv, dv, NULL, NULL, &mint, &maxt, &mintri, &maxtri) != 0) {
+ double angle;
+
+ /* The scale factor discounts the depth ratio as the mapping */
+ /* vector gets more angled. It has a sin^2 characteristic */
+ /* This is so that the depth error has some continuity if it */
+ /* gets closer to being parallel to the destination gamut surface. */
+
+//printf("\n~1 ix %d: %f %f %f -> %f %f %f\n isect at t %f and %f\n", s->ix, sv[0], sv[1], sv[2], dv[0], dv[1], dv[2], mint, maxt);
+ p->gflag = p->vflag = 0;
+
+ if (mint < -1e-8 && maxt < -1e-8) {
+ p->gflag = 1; /* Gamut compression but */
+ p->vflag = 2; /* vector is expanding */
+
+ } else if (mint > 1e-8 && maxt > -1e-8) {
+ p->gflag = 1; /* Gamut compression and */
+ p->vflag = 1; /* vector compression */
+ angle = icmDot3(nv, mintri->pe);
+ angle *= angle; /* sin squared */
+ p->dcratio = angle * 2.0/(maxt + mint - 2.0);
+//printf("~1 %d: comp depth ratio %f, angle %f\n", s->ix, p->dratio, angle);
+
+ } else if (mint < -1e-8 && maxt > -1e-8) {
+ if (fabs(mint) < (fabs(maxt) - 1e-8)) {
+ p->gflag = 2; /* Gamut expansion but */
+ p->vflag = 1; /* vector is compressing */
+
+ } else if (fabs(mint) > (fabs(maxt) + 1e-8)) {
+ p->gflag = 2; /* Gamut expansion and */
+ p->vflag = 2; /* vector is expanding */
+ angle = icmDot3(nv, maxtri->pe);
+ angle *= angle; /* sin squared */
+ p->dxratio = angle * 2.0/-mint;
+//printf("~1 %d: exp depth ratio %f, angle %f\n", s->ix, p->dratio, angle);
+
+ }
+ }
+ }
+ }
+}
+
+/* Powell optimisation function for non-relative error optimization. */
+/* We get a 2D point in the 3D space. */
+static double optfunc2(
+void *fdata,
+double *_dv
+) {
+ smthopt *s = (smthopt *)fdata;
+ nearsmth *p = s->p; /* Point being optimised */
+ double dv[3], ddv[3]; /* Dest point */
+ double rv; /* Return value */
+
+ /* Convert from 2D to 3D. */
+ dv[2] = _dv[1];
+ dv[1] = _dv[0];
+ dv[0] = 50.0;
+ icmMul3By3x4(dv, p->m3d, dv);
+//printf("~1 optfunc2 got 2D %f %f -> 3D %f %f %f\n", _dv[0], _dv[1], dv[0], dv[1], dv[2]);
+
+ p->dgam->radial(p->dgam, ddv, dv); /* Map to dst surface to check current location */
+//printf("~1 optfunc2 got %f %f %f -> surface %f %f %f\n", dv[0], dv[1], dv[2], ddv[0], ddv[1], ddv[2]);
+
+//printf("~1 optfunc2 sv %4.2f %4.2f %4.2f, dv %4.2f %4.2f %4.2f\n", p->sv[0], p->sv[1], p->sv[2], ddv[0], ddv[1], ddv[2]);
+
+ /* Compute available depth errors p->dcratio and p->dxratio */
+ comp_depth(s, p, ddv);
+
+ /* Compute weighted delta E being minimised. */
+ rv = comperr(p, &p->wt, ddv, p->aodv, p->drv, p->dcratio, p->dxratio);
+
+ if (s->debug) {
+ printf("~1 sv = %f %f %f\n", p->sv[0], p->sv[1], p->sv[2]);
+ printf("~1 dv = %f %f %f\n", ddv[0], ddv[1], ddv[2]);
+ printf("~1 aodv = %f %f %f\n", p->aodv[0], p->aodv[1], p->aodv[2]);
+ printf("~1 drv = %f %f %f\n", p->drv[0], p->drv[1], p->drv[2]);
+ printf("debug:%d: rv = %f from %f %f %f\n",s->ix, rv, dv[0], dv[1], dv[2]);
+ }
+
+//printf("~1 rv = %f from %f %f\n",rv, _dv[0], _dv[1]);
+
+//printf("~1 rv = %f\n\n",rv);
+ return rv;
+}
+
+/* -------------------------------------------- */
+
+/* Setup the neutral axis and cusp mapping structure information */
+static void init_ce(
+smthopt *s, /* Context for cusp mapping being set. */
+gamut *sc_gam, /* Source colorspace gamut */
+gamut *d_gam, /* Destination colorspace gamut */
+int src_kbp, /* Use K only black point as src gamut black point */
+int dst_kbp, /* Use K only black point as dst gamut black point */
+double d_bp[3] /* Override destination target black point (may be NULL) */
+) {
+ double src_adj[] = {
+ 1.1639766020018968e+224, 1.0605092189369252e-153, 3.5252483622572622e+257,
+ 1.3051549117649167e+214, 3.2984590678749676e-033, 1.8786244212510033e-153,
+ 1.2018790902224465e+049, 1.0618629743651763e-153, 5.5513445545255624e+233,
+ 3.3509081077514219e+242, 2.0076462988863408e-139, 3.2823498214286135e-318,
+ 7.7791723264448801e-260, 9.5956158769288055e+281, 2.5912667577703660e+161,
+ 5.2030128643503829e-085, 5.8235640814905865e+180, 4.0784546104861075e-033,
+ 3.6621812661291286e+098, 1.6417826055515754e-086, 8.2656018530749330e+097,
+ 9.3028116527073026e+242, 2.9127574654725916e+180, 1.9984697356129145e-139,
+ -2.1117351731638832e+003 };
+ double saval;
+ int sd;
+ int i, j, k;
+
+ VA(("init_ce called\n"));
+
+ s->donaxis = 1; /* Assume real neutral axis info */
+ s->docusp = 1; /* Assume real cusp info */
+
+ s->isJab = sc_gam->isJab;
+
+ /* Set some default values for src white/black/grey */
+
+ /* Get the white and black point info */
+ if (src_kbp) {
+ if (sc_gam->getwb(sc_gam, NULL, NULL, NULL, s->cusps[0][6], NULL, s->cusps[0][7]) != 0) {
+ VB(("getting src wb points failed\n"));
+ s->cusps[0][6][0] = 100.0;
+ s->cusps[0][7][0] = 0.0;
+ s->cusps[0][8][0] = 50.0;
+ s->donaxis = 0;
+ }
+ } else {
+ if (sc_gam->getwb(sc_gam, NULL, NULL, NULL, s->cusps[0][6], s->cusps[0][7], NULL) != 0) {
+ VB(("getting src wb points failed\n"));
+ s->cusps[0][6][0] = 100.0;
+ s->cusps[0][7][0] = 0.0;
+ s->cusps[0][8][0] = 50.0;
+ s->donaxis = 0;
+ }
+ }
+
+ if (dst_kbp) {
+ if (d_gam->getwb(d_gam, NULL, NULL, NULL, s->cusps[1][6], NULL, s->cusps[1][7]) != 0) {
+ VB(("getting dest wb points failed\n"));
+ s->cusps[1][6][0] = 100.0;
+ s->cusps[1][7][0] = 0.0;
+ s->cusps[1][8][0] = 50.0;
+ s->donaxis = 0;
+ }
+ } else {
+ if (d_gam->getwb(d_gam, NULL, NULL, NULL, s->cusps[1][6], s->cusps[1][7], NULL) != 0) {
+ VB(("getting dest wb points failed\n"));
+ s->cusps[1][6][0] = 100.0;
+ s->cusps[1][7][0] = 0.0;
+ s->cusps[1][8][0] = 50.0;
+ s->donaxis = 0;
+ }
+ }
+ if (d_bp != NULL) { /* Use override destination black point */
+ icmCpy3(s->cusps[1][7], d_bp);
+ }
+
+ /* Get the cusp info */
+ if (sc_gam->getcusps(sc_gam, s->cusps[0]) != 0 || d_gam->getcusps(d_gam, s->cusps[1]) != 0) {
+ int isJab;
+
+ VB(("getting cusp info failed\n"));
+ s->docusp = 0;
+
+ /* ????? Should we use generic cusp information as a fallback ?????? */
+ }
+
+ /* Compute source adjustment value */
+ for (saval = 0.0, i = 0; i < (sizeof(src_adj)/sizeof(double)-1); i++)
+ saval += log(src_adj[i]);
+ saval += src_adj[i];
+
+ /* For source and dest */
+ for (sd = 0; sd < 2; sd++) {
+ double ta[3] = { 100.0, 0.0, 0.0 };
+ double tc[3] = { 0.0, 0.0, 0.0 };
+
+ /* Compute rotation to rotate/translate so that */
+ /* black -> white becomes 0 -> 100 */
+ ta[0] *= saval; /* Make source adjustment */
+ icmVecRotMat(s->rot[sd], s->cusps[sd][6], s->cusps[sd][7], ta, tc);
+
+ /* And inverse */
+ icmVecRotMat(s->irot[sd], ta, tc, s->cusps[sd][6], s->cusps[sd][7]);
+
+ /* Compute a grey */
+ if (s->docusp) {
+ double aL = 0.0;
+ /* Compute cusp average L value as grey */
+ for (k = 0; k < 6; k++)
+ aL += s->cusps[sd][k][0];
+ aL /= 6.0;
+//printf("~1 src/dst %d cusp average L %f\n",sd, aL);
+
+ aL = (aL - s->cusps[sd][7][0])/(s->cusps[sd][6][0] - s->cusps[sd][7][0]); /* Param */
+ if (aL < 0.0)
+ aL = 0.0;
+ else if (aL > 1.0)
+ aL = 1.0;
+//printf("~1 src/dst %d grey param %f\n",sd,aL);
+ icmBlend3(s->cusps[sd][8], s->cusps[sd][6], s->cusps[sd][7], aL);
+
+ } else {
+ icmBlend3(s->cusps[sd][8], s->cusps[sd][6], s->cusps[sd][7], 0.5);
+ }
+
+ /* For white, black and grey */
+ icmMul3By3x4(s->cusp_lab[sd][6], s->rot[sd], s->cusps[sd][6]);
+ icmMul3By3x4(s->cusp_lab[sd][7], s->rot[sd], s->cusps[sd][7]);
+ icmMul3By3x4(s->cusp_lab[sd][8], s->rot[sd], s->cusps[sd][8]);
+
+ if (!s->docusp)
+ continue; /* No cusp information */
+
+ /* For each cusp */
+ for (k = 0; k < 6; k++) {
+
+ /* Black/white normalized value */
+ icmMul3By3x4(s->cusp_lab[sd][k], s->rot[sd], s->cusps[sd][k]);
+
+ /* Compute LCh value */
+ icmLab2LCh(s->cusp_lch[sd][k], s->cusp_lab[sd][k]);
+ VB(("cusp[%d][%d] %f %f %f LCh %f %f %ff\n", sd, k, s->cusps[sd][k][0], s->cusps[sd][k][1], s->cusps[sd][k][2], s->cusp_lch[sd][k][0], s->cusp_lch[sd][k][1], s->cusp_lch[sd][k][2]));
+ }
+
+ /* For each pair of cusps */
+ for (k = 0; k < 6; k++) {
+ int m = k < 5 ? k + 1 : 0;
+ int n;
+
+ /* Plane of grey & 2 cusp points, so as to be able to decide light/dark cone. */
+ if (icmPlaneEqn3(s->cusp_pe[sd][k], s->cusp_lab[sd][8], s->cusp_lab[sd][m],
+ s->cusp_lab[sd][k]))
+ error("gamut, init_ce: failed to compute plane equation between cusps\n");
+
+ VB(("dist to white = %f\n",icmPlaneDist3(s->cusp_pe[sd][k], s->cusp_lab[sd][6])));
+ VB(("dist to black = %f\n",icmPlaneDist3(s->cusp_pe[sd][k], s->cusp_lab[sd][7])));
+ VB(("dist to grey = %f\n",icmPlaneDist3(s->cusp_pe[sd][k], s->cusp_lab[sd][8])));
+ VB(("dist to c0 = %f\n",icmPlaneDist3(s->cusp_pe[sd][k], s->cusp_lab[sd][m])));
+ VB(("dist to c1 = %f\n",icmPlaneDist3(s->cusp_pe[sd][k], s->cusp_lab[sd][k])));
+
+ /* For light and dark, create transformation matrix to (src) */
+ /* or from (dst) the Baricentric values. The base is always */
+ /* the grey point. */
+ for (n = 0; n < 2; n++) {
+
+ /* Create from Baricentric matrix */
+ icmCpy3(s->cusp_bc[sd][k][n][0], s->cusp_lab[sd][k]);
+ icmCpy3(s->cusp_bc[sd][k][n][1], s->cusp_lab[sd][m]);
+ icmCpy3(s->cusp_bc[sd][k][n][2], s->cusp_lab[sd][6 + n]); /* [7] & [8] */
+ for (j = 0; j < 3; j++) /* Subtract grey base */
+ icmSub3(s->cusp_bc[sd][k][n][j], s->cusp_bc[sd][k][n][j], s->cusp_lab[sd][8]);
+
+ /* Compute matrix transform */
+ icmTranspose3x3(s->cusp_bc[sd][k][n], s->cusp_bc[sd][k][n]);
+
+ if (sd == 0) { /* If src, invert matrix */
+ if (icmInverse3x3(s->cusp_bc[sd][k][n], s->cusp_bc[sd][k][n]) != 0)
+ error("gamut, init_ce: failed to invert baricentric matrix\n");
+ }
+ }
+ }
+ }
+
+#ifdef NEVER /* Sanity check */
+
+ for (k = 0; k < 6; k++) {
+ double tt[3];
+
+ comp_ce(s, tt, s->cusps[0][k], NULL);
+
+ VB(("cusp %d, %f %f %f -> %f %f %f, de %f\n", k, cusps[0][k][0], cusps[0][k][1], cusps[0][k][2], tt[0], tt[1], tt[2], icmNorm33(tt, cusps[1][k])));
+
+ }
+#endif /* NEVER */
+
+#ifdef NEVER /* Sanity check */
+
+ {
+ for (k = 0; k < 9; k++) {
+ double tt;
+
+ tt = comp_lvc(s, s->cusps[0][k]);
+
+ printf("cusp %d, %f %f %f -> %f\n\n", k, s->cusps[0][k][0], s->cusps[0][k][1], s->cusps[0][k][2], tt);
+
+ }
+
+ /* For light and dark */
+ for (sd = 0; sd < 2; sd++) {
+ /* for each segment */
+ for (k = 0; k < 6; k++) {
+ int m = k < 5 ? k + 1 : 0;
+ double pos[3], tt;
+
+ pos[0] = pos[1] = pos[2] = 0.0;
+
+ icmAdd3(pos, pos, s->cusps[0][k]);
+ icmAdd3(pos, pos, s->cusps[0][m]);
+ icmAdd3(pos, pos, s->cusps[0][6 + sd]);
+ icmAdd3(pos, pos, s->cusps[0][8]);
+ icmScale3(pos, pos, 1.0/4.0);
+
+ tt = comp_lvc(s, pos);
+
+ printf("cusps %d & %d, grey %d, %f %f %f -> %f\n\n", k, m, sd, pos[0], pos[1], pos[2], tt);
+ }
+ }
+ }
+#endif /* NEVER */
+}
+
+/* Compute cusp mapping value */
+static void comp_ce(
+smthopt *s, /* Context for cusp mapping */
+double out[3],
+double in[3],
+gammapweights *wt /* If NULL, assume 100% */
+) {
+ double cw_l = 1.0;
+ double cw_c = 1.0;
+ double cw_h = 1.0;
+ double ccx = 1.0;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+
+ if (wt != NULL) {
+ cw_l = wt->c.w.l;
+ cw_c = wt->c.w.c;
+ cw_h = wt->c.w.h;
+ ccx = wt->c.cx;
+ }
+
+ /* Compute source changes due to any cusp mapping */
+ if (s->docusp && (cw_l > 0.0 || cw_c > 0.0 || cw_h > 0.0)) {
+ double lab[3], lch[3]; /* Normalized source values */
+ double bb[3]; /* Baricentric coords */
+ double olch[3]; /* Destination transformed LCh source value */
+ double mlab[3], mlch[3]; /* Fully mapped value */
+ int c0, c1; /* Cusp indexes */
+ int ld; /* light/dark index */
+
+//printf("\n~1 in = %f %f %f, ccx = %f\n",in[0],in[1],in[2],ccx);
+
+ /* Compute src cusp normalized LCh */
+ icmMul3By3x4(lab, s->rot[0], in);
+ icmLab2LCh(lch, lab);
+//printf("~1 lab = %f %f %f, lch = %f %f %f\n",lab[0],lab[1],lab[2],lch[0],lch[1],lch[2]);
+
+ /* Locate the source cusps that this point lies between */
+ for (c0 = 0; c0 < 6; c0++) {
+ double sh, h0, h1;
+
+ sh = lch[2];
+ c1 = c0 < 5 ? c0 + 1 : 0;
+
+ h0 = s->cusp_lch[0][c0][2];
+ h1 = s->cusp_lch[0][c1][2];
+
+ if (h1 < h0) {
+ if (sh < h1)
+ sh += 360.0;
+ h1 += 360.0;
+ }
+ if (sh >= (h0 - 1e-12) && sh < (h1 + 1e-12))
+ break;
+ }
+ if (c0 >= 6) /* Assert */
+ error("gamut, comp_ce: unable to locate hue %f cusps\n",lch[2]);
+
+ /* See whether this is light or dark */
+ ld = icmPlaneDist3(s->cusp_pe[0][c0], lab) >= 0 ? 0 : 1;
+//printf("~1 cusp %d, ld %d (dist %f)\n",c0,ld,icmPlaneDist3(s->cusp_pe[0][c0], lab));
+
+ /* Compute baricentric for input point in simplex */
+ icmSub3(bb, lab, s->cusp_lab[0][8]);
+ icmMulBy3x3(bb, s->cusp_bc[0][c0][ld], bb);
+
+//printf("~1 bb %f %f %f\n",bb[0],bb[1],bb[2]);
+
+ /* Then compute value for output from baricentric */
+ icmMulBy3x3(mlab, s->cusp_bc[1][c0][ld], bb);
+ icmAdd3(mlab, mlab, s->cusp_lab[1][8]);
+ icmLab2LCh(mlch, mlab);
+
+//printf("~1 fully cusp mapped point %f %f %f\n", mlab[0], mlab[1], mlab[2]);
+
+ /* Compute the unchanged source in dest space */
+ icmMul3By3x4(olch, s->rot[1], in);
+ icmLab2LCh(olch, olch);
+
+ /* Then compute weighted output */
+ mlch[0] = cw_l * mlch[0] + (1.0 - cw_l) * olch[0];
+ mlch[1] = cw_c * mlch[1] + (1.0 - cw_c) * olch[1];
+ mlch[1] *= ccx; /* Chroma expansion */
+
+ if (lch[2] > mlch[2] && (lch[2] - mlch[2]) > 180.0)
+ mlch[2] += 360.0;
+ else if (mlch[2] > lch[2] && (mlch[2] - lch[2]) > 180.0)
+ lch[2] += 360.0;
+ mlch[2] = cw_c * mlch[2] + (1.0 - cw_c) * lch[2];
+ if (mlch[2] >= 360.0)
+ mlch[2] -= 360.0;
+
+//printf("~1 weighted cusp mapped point %f %f %f\n", mlch[0], mlch[1], mlch[2]);
+ icmLCh2Lab(mlch, mlch);
+ icmMul3By3x4(out, s->irot[1], mlch);
+//printf("~1 returning %f %f %f\n", out[0], out[1], out[2]);
+ }
+}
+
+/* Return a blend factor that measures how close to the white or */
+/* black point the location is. Return 1.0 if as far from the */
+/* point as is grey, 0.0 when at the white or black points. */
+static double comp_naxbf(
+smthopt *s, /* Context for cusp mapping */
+double in[3] /* Non-cusp mapped source value */
+) {
+ double rin[3]; /* Rotated/scaled to neutral axis 0 to 100 */
+ double ll;
+
+//printf("~1 comp_naxbf, %d: in = %f %f %f\n",s->ix, in[0],in[1],in[2]);
+
+ /* Convert to neutral axis 0 to 100 */
+ icmMul3By3x4(rin, s->rot[0], in);
+
+//printf("~1 rotate L %f, white %f grey %f black %f\n",rin[0],s->cusp_lab[0][6][0],s->cusp_lab[0][8][0],s->cusp_lab[0][7][0]);
+
+ if (rin[0] >= s->cusp_lab[0][8][0]) { /* Closer to white */
+ ll = icmNorm33(s->cusp_lab[0][6], rin); /* Distance to white */
+ ll = 1.0 - ll/(100.0 - s->cusp_lab[0][8][0]); /* Normalized to grey distance */
+ } else { /* Closer to black */
+ ll = icmNorm33(s->cusp_lab[0][7], rin); /* Distance to black */
+ ll = 1.0 - ll/s->cusp_lab[0][8][0]; /* Normalized to grey distance */
+ }
+ if (ll < 0.0)
+ ll = 0.0;
+ else if (ll > 1.0)
+ ll = 1.0;
+
+ /* Weight so that it goes to 0.0 close to W & B */
+ ll = sqrt(1.0 - ll);
+
+//printf("~1 returning ll %f\n",ll);
+ return ll;
+}
+
+/* Return a value suitable for blending between the wl, gl and bl L dominance values */
+/* The value is a linear blend value, 0.0 at cusp local grey, 1.0 at white L value */
+/* and -1.0 at black L value. */
+static double comp_lvc(
+smthopt *s, /* Context for cusp mapping */
+double in[3] /* Non-cusp mapped source value */
+) {
+ double Lg;
+ double ll;
+
+//printf("~1 comp_lvc, %d: in = %f %f %f\n",s->ix, in[0],in[1],in[2]);
+
+ /* Compute the cusp local grey value. */
+ if (s->docusp) {
+ double lab[3], lch[3]; /* Normalized source values */
+ double bb[3]; /* Baricentric coords */
+ int c0, c1; /* Cusp indexes */
+ int ld; /* light/dark index */
+
+ /* Compute src cusp normalized LCh */
+ icmMul3By3x4(lab, s->rot[0], in);
+ icmLab2LCh(lch, lab);
+//printf("~1 lab = %f %f %f, lch = %f %f %f\n",lab[0],lab[1],lab[2],lch[0],lch[1],lch[2]);
+
+ /* Locate the source cusps that this point lies between */
+ for (c0 = 0; c0 < 6; c0++) {
+ double sh, h0, h1;
+
+ sh = lch[2];
+ c1 = c0 < 5 ? c0 + 1 : 0;
+
+ h0 = s->cusp_lch[0][c0][2];
+ h1 = s->cusp_lch[0][c1][2];
+
+ if (h1 < h0) {
+ if (sh < h1)
+ sh += 360.0;
+ h1 += 360.0;
+ }
+ if (sh >= (h0 - 1e-12) && sh < (h1 + 1e-12))
+ break;
+ }
+ if (c0 >= 6) /* Assert */
+ error("gamut, comp_lvc: unable to locate hue %f cusps\n",lch[2]);
+
+ /* See whether this is light or dark */
+ ld = icmPlaneDist3(s->cusp_pe[0][c0], lab) >= 0 ? 0 : 1;
+//printf("~1 cusp %d, ld %d (dist %f)\n",c0,ld,icmPlaneDist3(s->cusp_pe[0][c0], lab));
+
+ /* Compute baricentric for input point in simplex */
+ icmSub3(bb, lab, s->cusp_lab[0][8]);
+ icmMulBy3x3(bb, s->cusp_bc[0][c0][ld], bb);
+
+//printf("~1 baricentric %f %f %f\n",bb[0],bb[1],bb[2]);
+
+ /* Compute the grey level */
+ Lg = s->cusps[0][8][0]
+ + bb[0] * (s->cusps[0][c0][0] - s->cusps[0][8][0])
+ + bb[1] * (s->cusps[0][c1][0] - s->cusps[0][8][0]);
+
+ } else {
+ /* Non-cusp sensitive grey L */
+ Lg = s->cusps[0][8][0];
+ }
+//printf("~1 grey = %f\n",Lg);
+
+ if (in[0] > Lg) {
+ ll = (in[0] - Lg)/(s->cusps[0][6][0] - Lg);
+
+ } else {
+ ll = -(in[0] - Lg)/(s->cusps[0][7][0] - Lg);
+ }
+//printf("~1 returnin ll %f\n",ll);
+ return ll;
+}
+
+static double invfunc(
+void *fdata,
+double *tp
+) {
+ smthopt *s = (smthopt *)fdata;
+ double cv[3]; /* Converted value */
+ double tt, rv = 0.0;
+
+ comp_ce(s, cv, tp, s->wt);
+
+ tt = s->tv[0] - cv[0];
+ rv += tt * tt;
+ tt = s->tv[1] - cv[1];
+ rv += tt * tt;
+ tt = s->tv[2] - cv[2];
+ rv += tt * tt;
+
+//printf("~1 rv %f from %f %f %f -> %f %f %f\n",rv,tp[0],tp[1],tp[2],cv[0],cv[1],cv[2]);
+ return rv;
+}
+
+/* Inverse of com_ce. We do this by inverting com_ce numerically (slow) */
+static void inv_comp_ce(
+smthopt *s, /* Context for cusp mapping */
+double out[3],
+double in[3],
+gammapweights *wt /* If NULL, assume 100% */
+) {
+ double ss[3] = { 20.0, 20.0, 20.0 }; /* search area */
+ double tp[3], rv;
+
+ s->tv[0] = tp[0] = in[0];
+ s->tv[1] = tp[1] = in[1];
+ s->tv[2] = tp[2] = in[2];
+ s->wt = wt;
+
+ /* Optimise the point */
+ if (powell(&rv, 3, tp, ss, 0.001, 1000, invfunc, (void *)s, NULL, NULL) != 0) {
+ error("gammap::nearsmth: inv_comp_ce powell failed on %f %f %f\n", in[0], in[1], in[2]);
+ }
+
+//printf("~1 inv_comp_ce: %f %f %f -> %f %f %f\n", s->tv[0], s->tv[1], s->tv[2], tp[0], tp[1], tp[2]);
+//comp_ce(s, out, tp, wt);
+//printf("~1 check: %f %f %f, DE %f\n", out[0], out[1], out[2], icmNorm33(s->tv,out));
+
+ out[0] = tp[0];
+ out[1] = tp[1];
+ out[2] = tp[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A set of functions to help handle the weighting configuration */
+
+/* Copy non-negative values from one set of weights to another */
+void near_wcopy(
+gammapweights *dst,
+gammapweights *src
+) {
+
+#define NSCOPY(xxx) dst->xxx = src->xxx >= 0.0 ? src->xxx : dst->xxx
+//#define NSCOPY(xxx) if (src->xxx >= 0.0) { \
+// printf("Setting %s to %f\n",#xxx, src->xxx); \
+// dst->xxx = src->xxx; \
+// }
+
+ NSCOPY(c.w.l);
+ NSCOPY(c.w.c);
+ NSCOPY(c.w.h);
+ NSCOPY(c.cx);
+
+ NSCOPY(l.o);
+ NSCOPY(l.h);
+ NSCOPY(l.l);
+
+ NSCOPY(a.o);
+ NSCOPY(a.h);
+ NSCOPY(a.wl);
+ NSCOPY(a.gl);
+ NSCOPY(a.bl);
+
+ NSCOPY(a.wlth);
+ NSCOPY(a.blpow);
+
+ NSCOPY(a.lxpow);
+ NSCOPY(a.lxthr);
+
+ NSCOPY(r.rdl);
+ NSCOPY(r.rdh);
+
+ NSCOPY(d.co);
+ NSCOPY(d.xo);
+
+ NSCOPY(f.x);
+#undef NSCOPY
+}
+
+/* Blend a two groups of individual weights into one, given two weightings */
+void near_wblend(
+gammapweights *dst,
+gammapweights *src1, double wgt1,
+gammapweights *src2, double wgt2
+) {
+
+#define NSBLEND(xxx) dst->xxx = wgt1 * src1->xxx + wgt2 * src2->xxx
+
+ NSBLEND(c.w.l);
+ NSBLEND(c.w.c);
+ NSBLEND(c.w.h);
+ NSBLEND(c.cx);
+
+ NSBLEND(l.o);
+ NSBLEND(l.h);
+ NSBLEND(l.l);
+
+ NSBLEND(a.o);
+ NSBLEND(a.h);
+ NSBLEND(a.wl);
+ NSBLEND(a.gl);
+ NSBLEND(a.bl);
+
+ NSBLEND(a.wlth);
+ NSBLEND(a.blpow);
+
+ NSBLEND(a.lxpow);
+ NSBLEND(a.lxthr);
+
+ NSBLEND(r.rdl);
+ NSBLEND(r.rdh);
+
+ NSBLEND(d.co);
+ NSBLEND(d.xo);
+
+ NSBLEND(f.x);
+#undef NSBLEND
+}
+
+/* Expand the compact form of weights into the explicit form. */
+/* The explicit form is light and dark of red, yellow, green, cyan, blue, magenta & neutral*/
+/* Return nz on error */
+int expand_weights(gammapweights out[14], gammapweights *in) {
+ int i, j;
+
+ /* Set the usage of each slot */
+ out[0].ch = gmm_light_red;
+ out[1].ch = gmm_light_yellow;
+ out[2].ch = gmm_light_green;
+ out[3].ch = gmm_light_cyan;
+ out[4].ch = gmm_light_blue;
+ out[5].ch = gmm_light_magenta;
+ out[6].ch = gmm_light_neutral;
+
+ out[7].ch = gmm_dark_red;
+ out[8].ch = gmm_dark_yellow;
+ out[9].ch = gmm_dark_green;
+ out[10].ch = gmm_dark_cyan;
+ out[11].ch = gmm_dark_blue;
+ out[12].ch = gmm_dark_magenta;
+ out[13].ch = gmm_dark_neutral;
+
+//printf("\n~1 expand weights called\n");
+
+ /* mark output so we can recognise having been set or not */
+ for (i = 0; i < 14; i++)
+ out[i].set = 0;
+
+ /* Expand the compact form to explicit. */
+
+ /* First is default */
+ for (i = 0; in[i].ch != gmm_end; i++) {
+ if (in[i].ch == gmm_end)
+ break;
+ if (in[i].ch == gmm_ignore)
+ continue;
+
+ if (in[i].ch == gmm_default) {
+ for (j = 0; j < 14; j++) {
+//printf("~1 Setting %d 0x%x with 0x%x (default)\n",j,out[j].ch,in[i].ch);
+ if ((in[i].ch & out[j].ch) == out[j].ch) {
+ near_wcopy(&out[j], &in[i]);
+ out[j].set = 1;
+ }
+ }
+ }
+ }
+
+ /* Then light or dark */
+ for (i = 0; in[i].ch != gmm_end; i++) {
+ if (in[i].ch == gmm_end)
+ break;
+ if (in[i].ch == gmm_ignore)
+ continue;
+
+ if (in[i].ch == gmm_light_colors
+ || in[i].ch == gmm_dark_colors) {
+ for (j = 0; j < 14; j++) {
+ if ((in[i].ch & out[j].ch) == out[j].ch) {
+//printf("~1 Setting %d 0x%x with 0x%x (light or dark)\n",j,out[j].ch,in[i].ch);
+ near_wcopy(&out[j], &in[i]);
+ out[j].set = 1;
+ }
+ }
+ }
+ }
+
+ /* Then light and dark colors */
+ for (i = 0; in[i].ch != gmm_end; i++) {
+ if (in[i].ch == gmm_end)
+ break;
+ if (in[i].ch == gmm_ignore)
+ continue;
+
+ if ((in[i].ch & gmc_l_d) == gmc_l_d
+ && (in[i].ch & gmc_colors) != gmc_colors) {
+ for (j = 0; j < 14; j++) {
+ if ((in[i].ch & out[j].ch) == out[j].ch) {
+//printf("~1 Setting %d 0x%x with 0x%x (light and dark color)\n",j,out[j].ch,in[i].ch);
+ near_wcopy(&out[j], &in[i]);
+ out[j].set = 1;
+ }
+ }
+ }
+ }
+
+ /* Last pass is light or dark colors */
+ for (i = 0; in[i].ch != gmm_end; i++) {
+ if (in[i].ch == gmm_end)
+ break;
+ if (in[i].ch == gmm_ignore)
+ continue;
+
+ if (((in[i].ch & gmc_l_d) == gmc_light
+ || (in[i].ch & gmc_l_d) == gmc_dark)
+ && (in[i].ch & gmc_colors) != gmc_colors) {
+ for (j = 0; j < 14; j++) {
+ if ((in[i].ch & out[j].ch) == out[j].ch) {
+//printf("~1 Setting %d 0x%x with 0x%x (light or dark color)\n",j,out[j].ch,in[i].ch);
+ near_wcopy(&out[j], &in[i]);
+ out[j].set = 1;
+ }
+ }
+ }
+ }
+
+ /* Check every slot has been set */
+ for (i = 0; i < 14; i++) {
+ if (out[i].set == 0) {
+//printf("~1 set %d hasn't been initialized\n",i);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Tweak weights acording to extra cmy cusp flags or rel override */
+void tweak_weights(gammapweights out[14], int dst_cmymap, int rel_oride) {
+ int i;
+
+ for (i = 0; i < 14; i++) {
+ if (((dst_cmymap & 0x1) && (out[i].ch & gmc_cyan))
+ || ((dst_cmymap & 0x2) && (out[i].ch & gmc_magenta))
+ || ((dst_cmymap & 0x4) && (out[i].ch & gmc_yellow))) {
+//printf("~1 Setting %d 0x%x to 100% cusp map\n",i,out[i].ch);
+ out[i].c.w.l = 1.0; /* 100% mapping */
+ out[i].c.w.c = 1.0;
+ out[i].c.w.h = 1.0;
+ out[i].c.cx = 1.0; /* No expansion */
+ }
+
+ if (rel_oride == 1) { /* A high saturation "clip" like mapping */
+ out[i].r.rdl = 1.0; /* No relative neighbourhood */
+ out[i].r.rdh = 1.0; /* No relative neighbourhood */
+ out[i].d.co = 0.0; /* No depth weighting */
+ out[i].d.xo = 0.0; /* No depth weighting */
+
+ } else if (rel_oride == 2) { /* A maximal feature preserving mapping */
+ out[i].r.rdl *= 1.6; /* Extra neighbourhood size */
+ out[i].r.rdh *= 1.6; /* Extra neighbourhood size */
+ }
+ }
+}
+
+/* Blend a two expanded groups of individual weights into one */
+void near_xwblend(
+gammapweights *dst,
+gammapweights *src1, double wgt1,
+gammapweights *src2, double wgt2
+) {
+ int i;
+ for (i = 0; i < 14; i++)
+ near_wblend(&dst[i], &src1[i], wgt1, &src2[i], wgt2);
+}
+
+/* Convert overall, hue dom & l dom to iweight */
+static void comp_iweight(iweight *iw, double o, double h, double l) {
+ double c, lc;
+
+ if (h < 0.0)
+ h = 0.0;
+ else if (h > 1.0)
+ h = 1.0;
+
+ if (l < 0.0)
+ l = 0.0;
+ else if (l > 1.0)
+ l = 1.0;
+
+ lc = 1.0 - h;
+ c = (1.0 - l) * lc;
+ l = l * lc;
+
+ o /= sqrt(l * l + c * c + h * h);
+
+ iw->l = o * l;
+ iw->c = o * c;
+ iw->h = o * h;
+}
+
+/* Given a point location, return the interpolated weighting values at that point. */
+/* (Typically non-cusp mapped source location assumed, and source gamut cusps used) */
+/* (Assume init_ce() has been called to setip smthopt!) */
+void interp_xweights(gamut *gam, gammapweights *out, double pos[3],
+ gammapweights in[14], smthopt *s, int cvec) {
+ double h, JCh[3], tmp[3];
+ int li, ui; /* The two hue indexes the color is between */
+ double lh, uh; /* Lower/upper hue of two colors */
+ double lw, uw; /* Lower/upper blend values */
+ double cusps[6][3];
+ gammapweights light, dark;
+
+ /* Convert to polar */
+ icmLab2LCh(JCh, pos);
+
+ if (gam->getcusps(gam, cusps) != 0) { /* Failed */
+ int isJab = gam->isJab ? 1 : 0;
+
+ /* Figure out what hextant we're between using generic cusps */
+ for (li = 0; li < 6; li++) {
+ ui = li < 5 ? li + 1 : 0;
+ h = JCh[2];
+
+ lh = gam_hues[isJab][li]; /* use generic ones */
+ uh = gam_hues[isJab][ui];
+ if (uh < lh) {
+ if (h < uh)
+ h += 360.0;
+ uh += 360.0;
+ }
+ if (h >= (lh - 1e-12) && h < (uh + 1e-12))
+ break;
+ }
+
+ } else {
+
+ /* Locate the source cusps that this point lies between */
+ for (li = 0; li < 6; li++) {
+ double tt[3];
+ ui = li < 5 ? li + 1 : 0;
+ h = JCh[2];
+
+ icmLab2LCh(tt, cusps[li]);
+ lh = tt[2];
+ icmLab2LCh(tt, cusps[ui]);
+ uh = tt[2];
+
+ if (uh < lh) {
+ if (h < uh)
+ h += 360.0;
+ uh += 360.0;
+ }
+ if (h >= (lh - 1e-12) && h < (uh + 1e-12))
+ break;
+ }
+ }
+ if (li >= 6) /* Assert */
+ error("gamut, interp_xweights: unable to locate hue %f cusps\n",JCh[2]);
+
+ /* Compute hue angle blend weights */
+ uw = (h - lh)/(uh - lh);
+ if (uw < 0.0)
+ uw = 0.0;
+ else if (uw > 1.0)
+ uw = 1.0;
+ uw = uw * uw * (3.0 - 2.0 * uw); /* Apply spline to smooth interpolation */
+ lw = (1.0 - uw);
+
+ /* Blend weights at the two hues */
+ near_wblend(&light, &in[li], lw, &in[ui], uw);
+ near_wblend(&dark, &in[7 + li], lw, &in[7 + ui], uw);
+
+ /* If we're close to the center, blend to the neutral weight */
+ if (JCh[1] < NEUTRAL_C) {
+ lw = (NEUTRAL_C - JCh[1])/NEUTRAL_C;
+ uw = (1.0 - lw);
+ near_wblend(&light, &in[6], lw, &light, uw);
+ near_wblend(&dark, &in[7 + 6], lw, &dark, uw);
+ }
+
+ /* Figure out where we are between light and dark, */
+ /* and create blend between their weightings */
+ uw = (JCh[0] - DARK_L)/(LIGHT_L - DARK_L);
+ if (uw > 1.0)
+ uw = 1.0;
+ else if (uw < 0.0)
+ uw = 0.0;
+ uw = uw * uw * (3.0 - 2.0 * uw); /* Apply spline to smooth interpolation */
+ lw = (1.0 - uw);
+ near_wblend(out, &dark, lw, &light, uw);
+
+ /* Convert radial dominance weights into raw weights */
+ comp_iweight(&out->rl, out->l.o, out->l.h, out->l.l);
+
+//printf("~1 %d: src %f %f %f (cvec %d)\n",s->ix, pos[0],pos[1],pos[2],cvec);
+ /* Compute l dominance value vs. closness to white or black point */
+ {
+ double wl, gl, bl, uw, l;
+
+ /* Closness to white and black points */
+ uw = comp_lvc(s, pos);
+
+//printf("~1 uw = %f\n",uw);
+ if (uw >= 0) {
+
+ /* Scale to threshold */
+ if (uw > (1.0 - out->a.wlth))
+ uw = (uw - 1.0 + out->a.wlth)/out->a.wlth;
+ else
+ uw = 0.0;
+//printf("~1 white, thresholded uw %f\n",uw);
+
+ /* Blend in log ratio space */
+ wl = log((1.0 - out->a.wl + 1e-5)/(out->a.wl + 1e-5));
+ gl = log((1.0 - out->a.gl + 1e-5)/(out->a.gl + 1e-5));
+ l = exp(uw * wl + (1.0 - uw) * gl);
+ l = ((1.0 - l) * 1e-5 + 1.0)/(l + 1.0);
+
+ } else {
+ uw = -uw;
+
+ /* Apply power */
+ uw = pow(uw, out->a.blpow);
+//printf("~1 black with power uw %f\n",uw);
+
+ /* Blend in log ratio space */
+ gl = log((1.0 - out->a.gl + 1e-5)/(out->a.gl + 1e-5));
+ bl = log((1.0 - out->a.bl + 1e-5)/(out->a.bl + 1e-5));
+ l = exp(uw * bl + (1.0 - uw) * gl);
+ l = ((1.0 - l) * 1e-5 + 1.0)/(l + 1.0);
+ }
+//printf("~1 wl %f, gl %f, bl %f -> %f\n",out->a.wl,out->a.gl,out->a.bl,l);
+
+ /* Convert absolute dominance weights into raw weights */
+ comp_iweight(&out->ra, out->a.o, out->a.h, l);
+//printf("~1 l %f, h %f, ra l %f c %f h %f\n\n", l, out->a.h, out->ra.l, out->ra.c, out->ra.h);
+ }
+}
+
+/* Callback used by compdstgamut() to establish the expected compression */
+/* mapping direction. */
+static void cvect(
+void *cntx, /* smthopt * */
+double *p2, /* Return point displaced from p1 in desired direction */
+double *p1 /* Given point */
+) {
+ double vv, gv[3], lv[3];
+ smthopt *s = (smthopt *)cntx;
+ gammapweights out;
+
+ interp_xweights(s->sgam, &out, p1, s->xwh, s, 1);
+
+//printf("~1 at %f %f %f, lch weight %f %f %f\n", p1[0], p1[1], p1[2], out.ra.l, out.ra.c, out.ra.h);
+ /* Now we need to convert the absolute weighting out.ra into a vector */
+ /* We do this in a very simple minded fashion. The hue weighting is ignored, */
+ /* because we assume a direction towards the neutral axis. The C weight is */
+ /* assumed to be the weight towards the grey point, while the L weight */
+ /* assumed to be the weight towards the point on the neutral axis with */
+ /* the same L value. */
+
+ /* Parameter along neutral axis black to white */
+ vv = (p1[0] - s->cusps[0][7][0])/(s->cusps[0][6][0] - s->cusps[0][7][0]);
+ /* lv is point at same L on neutral axis */
+ lv[0] = p1[0];
+ lv[1] = vv * (s->cusps[0][6][1] - s->cusps[0][7][1]) + s->cusps[0][7][1];
+ lv[2] = vv * (s->cusps[0][6][2] - s->cusps[0][7][2]) + s->cusps[0][7][2];
+ icmSub3(lv, lv, p1); /* Vector */
+ icmNormalize3(lv, lv, out.ra.l);
+
+ icmSub3(gv, s->cusps[0][8], p1); /* Grey vector */
+ icmNormalize3(gv, gv, out.ra.c);
+
+ icmAdd3(p2, gv, p1);
+ icmAdd3(p2, lv, p2); /* Combined destination */
+//printf("~1 p2 %f %f %f\n", p2[0], p2[1], p2[2]);
+}
+
+/* Shrink function */
+static void doshrink(smthopt *s, double *out, double *in, double shrink) {
+ double rad, len, p2[3];
+
+ cvect((void *)s, p2, in); /* Get shrink direction */
+
+ /* Conservative radius of point */
+ rad = sqrt(in[1] * in[1] + in[2] * in[2]);
+
+ len = shrink;
+ if (rad < (2.0 * shrink))
+ len = rad * 0.5;
+
+ icmNormalize33(out, p2, in, len);
+}
+
+/* Convenience function. Given a mapping vector, return the */
+/* intersection with the given gamut that is in the mapping */
+/* direction. Return NZ if no intersection */
+static int vintersect(
+gamut *g,
+int *p1out, /* Return nz if p1 is outside the gamut */
+double isec[3], /* Return intersection point */
+double p1[3], /* First point */
+double p2[3] /* Second point */
+) {
+ gispnt lp[40];
+ int ll, i, bi;
+
+ if ((ll = g->vector_isectns(g, p1, p2, lp, 40)) == 0)
+ return 1;
+
+ /* Locate the segment or non-segment the source lies in */
+ for (bi = -1, i = 0; i < ll; i += 2) {
+
+ if ((i == 0 || lp[i-1].pv < 0.0) /* p1 is outside gamut */
+ && lp[i].pv >= -1e-2) {
+ bi = i;
+ if (p1out != NULL)
+ *p1out = 1;
+ break;
+ }
+
+ if (lp[i].pv <= 0.0 /* p1 is inside gamut */
+ && lp[i+1].pv >= -1e-2) {
+ bi = i+1;
+ if (p1out != NULL)
+ *p1out = 0;
+ break;
+ }
+ }
+ if (bi < 0)
+ return 1;
+
+ if (isec != NULL)
+ icmCpy3(isec, lp[bi].ip);
+
+ return 0;
+}
+
+/* Convenience function. Given a point and an inwards mapping vector, */
+/* if the point is within the gamut, return the first intersection in */
+/* the opposite to vector direction. If the point is outside the gamut, */
+/* return the first intersction in the vector direction. */
+/* Return NZ if no intersection */
+static int vintersect2(
+gamut *g,
+int *p1out, /* Return nz if p1 is outside the gamut */
+double isec[3], /* Return intersection point */
+double vec[3], /* Vector */
+double p1[3] /* Point */
+) {
+ gispnt lp[40];
+ double p2[3];
+ int ll, i, bi;
+
+ icmAdd3(p2, p1, vec);
+
+ if ((ll = g->vector_isectns(g, p1, p2, lp, 40)) == 0)
+ return 1;
+
+ /* Locate the segment or non-segment the source lies in */
+ for (bi = -1, i = 0; i < ll; i += 2) {
+
+ if ((i == 0 || lp[i-1].pv < 0.0) /* p1 is outside gamut, */
+ && lp[i].pv >= 0.0) { /* so look in +ve pv direction. */
+ bi = i;
+ if (p1out != NULL)
+ *p1out = 1;
+ break;
+ }
+
+ if (lp[i].pv <= 0.0 /* p1 is inside gamut, */
+ && lp[i+1].pv >= 0.0) { /* so look in -ve pv direction. */
+ bi = i;
+ if (p1out != NULL)
+ *p1out = 0;
+ break;
+ }
+ }
+ if (bi < 0)
+ return 1;
+
+ if (isec != NULL)
+ icmCpy3(isec, lp[bi].ip);
+
+ return 0;
+}
+
+
+/* ============================================ */
+
+/* Return the maximum number of points that will be generated */
+int near_smooth_np(
+ gamut *sc_gam, /* Source colorspace gamut */
+ gamut *si_gam, /* Source image gamut (== sc_gam if none) */
+ gamut *d_gam, /* Destination colorspace gamut */
+ double xvra /* Extra vertex ratio */
+) {
+ gamut *p_gam; /* Gamut used for points - either source colorspace or image */
+ int ntpts, nmpts, nspts, nipts, ndpts;
+
+ nspts = sc_gam->nverts(sc_gam);
+ nipts = si_gam->nverts(si_gam);
+ ndpts = d_gam->nverts(d_gam);
+ p_gam = sc_gam;
+
+ /* Target number of points is max of any gamut */
+ ntpts = nspts > nipts ? nspts : nipts;
+ ntpts = ntpts > ndpts ? ntpts : ndpts;
+ ntpts = (int)(ntpts * xvra + 0.5);
+
+ /* Use image gamut if it exists */
+ if (nspts < nipts || si_gam != sc_gam) {
+ nspts = nipts; /* Use image gamut instead */
+ p_gam = si_gam;
+ }
+ xvra = ntpts/(double)nspts;
+ nmpts = p_gam->nssverts(p_gam, xvra); /* Stratified Sampling source points */
+
+ return nmpts;
+}
+
+
+/* ============================================ */
+/* Return a list of points. Free list after use */
+/* Return NULL on error */
+nearsmth *near_smooth(
+int verb, /* Verbose flag */
+int *npp, /* Return the actual number of points returned */
+gamut *sc_gam, /* Source colorspace gamut - uses cusp info if availablle */
+gamut *si_gam, /* Source image gamut (== sc_gam if none), just used for surface. */
+gamut *d_gam, /* Destination colorspace gamut */
+int src_kbp, /* Use K only black point as src gamut black point */
+int dst_kbp, /* Use K only black point as dst gamut black point */
+double d_bp[3], /* Override destination target black point - may be NULL */
+gammapweights xwh[14],/* Structure holding expanded hextant weightings */
+double gamcknf, /* Gamut compression knee factor, 0.0 - 1.0 */
+double gamxknf, /* Gamut expansion knee factor, 0.0 - 1.0 */
+int usecomp, /* Flag indicating whether smoothed compressed value will be used */
+int useexp, /* Flag indicating whether smoothed expanded value will be used */
+double xvra, /* Extra number of vertexes ratio */
+int mapres, /* Grid res for 3D RSPL */
+double mapsmooth, /* Target smoothing for 3D RSPL */
+datai map_il, /* Preliminary rspl input range */
+datai map_ih,
+datao map_ol, /* Preliminary rspl output range */
+datao map_oh
+) {
+ smthopt opts; /* optimisation and cusp mapping context */
+ int ix, i, j, k;
+ gamut *p_gam; /* Gamut used for points - either source colorspace or image */
+ gamut *sci_gam; /* Intersection of src and img gamut gamut */
+ gamut *di_gam; /* Modified destination gamut suitable for mapping from sci_gam. */
+ /* If just compression, this is the smaller of sci_gam and d_gam. */
+ /* If just expansion, this is the sci_gam expanded by d_gam - sc_gam. */
+ /* If both exp & comp, then where
+ d_gam is outside sci_gam this is sci_gam expanded by d_gam - sc_gam
+ else it is the smaller of sci_gam and d_gam */
+ gamut *nedi_gam;/* Same as above, but not expanded. */
+ int nmpts; /* Number of mapping gamut points */
+ nearsmth *smp; /* Absolute delta E weighting */
+ int pass;
+ int it;
+ rspl *evectmap = NULL; /* evector map */
+ double codf; /* Itteration overshoot/damping factor */
+ double mxmv; /* Maximum a point gets moved */
+ int nmxmv; /* Number of maxmoves less than stopping threshold */
+
+ /* Check gamuts are compatible */
+ if (sc_gam->compatible(sc_gam, d_gam) == 0
+ || (si_gam != NULL && sc_gam->compatible(sc_gam, si_gam) == 0)) {
+ fprintf(stderr,"gamut map: Gamuts aren't compatible\n");
+ *npp = 0;
+ return NULL;
+ }
+
+ {
+ int ntpts, nspts, nipts, ndpts;
+
+ nspts = sc_gam->nverts(sc_gam);
+ nipts = si_gam->nverts(si_gam);
+ ndpts = d_gam->nverts(d_gam);
+ p_gam = sc_gam;
+
+ /* Target number of points is max of any gamut */
+ ntpts = nspts > nipts ? nspts : nipts;
+ ntpts = ntpts > ndpts ? ntpts : ndpts;
+ ntpts = (int)(ntpts * xvra + 0.5);
+
+ /* Use image gamut if it exists */
+ if (nspts < nipts || si_gam != sc_gam) {
+ nspts = nipts; /* Use image gamut instead */
+ p_gam = si_gam;
+ }
+ xvra = ntpts/(double)nspts;
+ nmpts = p_gam->nssverts(p_gam, xvra); /* Stratified Sampling source points */
+
+ if (verb) printf("Vertex count: mult. = %f, src %d, img %d dst %d, target %d\n",
+ xvra,nspts,nipts,ndpts,nmpts);
+ }
+
+ /* Setup opts structure */
+ opts.useexp = useexp; /* Expansion used ? */
+ opts.debug = 0; /* No debug powell() failure */
+ opts.xwh = xwh; /* Weightings */
+ opts.sgam = sc_gam; /* Source colorspace gamut */
+
+ /* Setup source & dest neutral axis transform if white/black available. */
+ /* If cusps are available, also figure out the transformations */
+ /* needed to map source cusps to destination cusps */
+ init_ce(&opts, sc_gam, d_gam, src_kbp, dst_kbp, d_bp);
+
+ /* Allocate our guide points */
+ if ((smp = (nearsmth *)calloc(nmpts, sizeof(nearsmth))) == NULL) {
+ fprintf(stderr,"gamut map: Malloc of near smooth points failed\n");
+ *npp = 0;
+ return NULL;
+ }
+
+ /* Create a source gamut surface that is the intersection of the src colorspace */
+ /* and image gamut, in case (for some strange reason) the image gamut. */
+ /* exceeds the source colorspace size. */
+ sci_gam = sc_gam; /* Alias to source space gamut */
+ if (si_gam != sc_gam) {
+ if ((sci_gam = new_gamut(0.0, 0, 0)) == NULL) {
+ fprintf(stderr,"gamut map: new_gamut failed\n");
+ *npp = 0;
+ return NULL;
+ }
+ sci_gam->intersect(sci_gam, sc_gam, si_gam);
+#ifdef SAVE_VRMLS
+ printf("###### gamut/nearsmth.c: writing diagnostic sci_gam.wrl and di_gam.wrl\n");
+ sci_gam->write_vrml(sci_gam, "sci_gam.wrl", 1, 0);
+#endif
+ }
+
+ di_gam = sci_gam; /* Default no compress or expand */
+ if (usecomp || useexp) {
+ if ((di_gam = new_gamut(0.0, 0, 0)) == NULL) {
+ fprintf(stderr,"gamut map: new_gamut failed\n");
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ *npp = 0;
+ return NULL;
+ }
+ if (useexp) {
+ /* Non-expand di_gam for testing double back img points against */
+ if ((nedi_gam = new_gamut(0.0, 0, 0)) == NULL) {
+ fprintf(stderr,"gamut map: new_gamut failed\n");
+ di_gam->del(di_gam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ *npp = 0;
+ return NULL;
+ }
+ } else {
+ nedi_gam = di_gam;
+ }
+
+ /* Initialise this gamut with a destination mapping gamut. */
+ /* This will be the smaller of the image and destination gamut if compressing, */
+ /* and will be expanded by the (dst - src) if expanding. */
+ di_gam->compdstgamut(di_gam, sci_gam, sc_gam, d_gam, usecomp, useexp, nedi_gam,
+ cvect, &opts);
+ }
+
+#ifdef SAVE_VRMLS
+ di_gam->write_vrml(di_gam, "di_gam.wrl", 1, 0);
+#endif
+
+ /* Create a list of the mapping guide points, setup for a null mapping */
+ VA(("Creating the mapping guide point list\n"));
+ for (ix = i = 0; i < nmpts; i++) {
+ double imv[3], imr; /* Image gamut source point and radius */
+ double inorm[3]; /* Normal of image gamut surface at src point */
+
+ /* Get the source color/image space vertex value we are going */
+ /* to use as a sample point. */
+ if ((ix = p_gam->getssvert(p_gam, &imr, imv, inorm, ix)) < 0) {
+ break;
+ }
+//printf("~1 got point %d out of %d\n",i+1,nmpts);
+
+ if (p_gam != sc_gam) { /* If src colorspace point, map to img gamut surface */
+ imr = sci_gam->radial(sci_gam, imv, imv);
+ }
+
+ /* If point is within non-expanded modified destination gamut, */
+ /* then it is a "double back" image point, and should be ignored. */
+ if (nedi_gam->radial(nedi_gam, NULL, imv) > (imr + 1e-4)) {
+ VB(("Rejecting point %d because it's inside destination\n",i));
+ i--;
+ continue;
+ }
+
+ /* Lookup radialy equivalent point on modified destination gamut, */
+ /* in case we need it for compression or expansion */
+ smp[i].drr = di_gam->radial(di_gam, smp[i].drv, imv);
+
+ /* Default setup a null mapping of source image space point to source image point */
+ smp[i].vflag = smp[i].gflag = 0;
+ smp[i].dr = smp[i].sr = smp[i]._sr = imr;
+ smp[i].dv[0] = smp[i].sv[0] = smp[i]._sv[0] = imv[0];
+ smp[i].dv[1] = smp[i].sv[1] = smp[i]._sv[1] = imv[1];
+ smp[i].dv[2] = smp[i].sv[2] = smp[i]._sv[2] = imv[2];
+ smp[i].sgam = sci_gam;
+ smp[i].dgam = sci_gam;
+
+ VB(("In Src %d = %f %f %f\n",i,smp[i].sv[0],smp[i].sv[1],smp[i].sv[2]));
+
+ /* If we're going to comp. or exp., check that the guide vertex is not */
+ /* on the wrong side of the image gamut, due to the it being */
+ /* a small subset of the source colorspace, displaced to one side. */
+ /* Because of the gamut convexity limitations, this amounts */
+ /* to the source surface at the vertex being in the direction */
+ /* of the center. */
+ if (usecomp != 0 || useexp != 0) {
+ double mv[3], ml; /* Radial inward mapping vector */
+ double dir;
+
+ icmSub3(mv, sci_gam->cent, smp[i].sv); /* Vector to center */
+ ml = icmNorm3(mv); /* It's length */
+
+ if (ml > 0.001) {
+ dir = icmDot3(mv, inorm); /* Compare to normal of src triangle */
+//printf("~1 ix %d, dir = %f, dir/len = %f\n",i,dir, dir/ml);
+ dir /= ml;
+ if (dir < 0.02) { /* If very shallow */
+//printf("~1 rejecting point %d because it's oblique\n",i);
+ VB(("Rejecting point %d because it's oblique\n",i));
+ i--;
+ continue;
+ }
+ }
+ }
+
+ /* Set some default extra guide point values */
+ smp[i].anv[0] = smp[i].aodv[0] = smp[i].dv[0];
+ smp[i].anv[1] = smp[i].aodv[1] = smp[i].dv[1];
+ smp[i].anv[2] = smp[i].aodv[2] = smp[i].dv[2];
+
+ VB(("Src %d = %f %f %f\n",i,smp[i].sv[0],smp[i].sv[1],smp[i].sv[2]));
+ VB(("Dst %d = %f %f %f\n",i,smp[i].dv[0],smp[i].dv[1],smp[i].dv[2]));
+ }
+ nmpts = i; /* Number of points after rejecting any */
+ *npp = nmpts;
+
+ /* Don't need this anymore */
+ if (nedi_gam != di_gam)
+ nedi_gam->del(nedi_gam);
+ nedi_gam = NULL;
+
+ /* If nothing to be compressed or expanded, then return */
+ if (usecomp == 0 && useexp == 0) {
+ VB(("Neither compression nor expansion defined\n"));
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ return smp;
+ }
+
+ /* Set the parameter weights for each point */
+ for (i = 0; i < nmpts; i++) {
+ opts.ix = i; /* Point in question */
+ opts.p = &smp[i];
+
+ /* Determine the parameter weighting for this point */
+ interp_xweights(opts.sgam, &smp[i].wt, smp[i]._sv, opts.xwh, &opts, 0);
+ }
+
+ VA(("Setting up cusp rotated compression or expansion mappings\n"));
+ VB(("rimv = Cusp rotated cspace/image gamut source point\n"));
+ VB(("imv = cspace/image gamut source point\n"));
+ VB(("drv = Destination space radial point and radius \n"));
+
+ /* Setup the cusp rotated compression or expansion mappings */
+ for (i = 0; i < nmpts; i++) {
+ double imv[3], imr; /* cspace/image gamut source point and radius */
+ double rimv[3], rimr; /* Cusp rotated cspace/image gamut source point and radius */
+
+ opts.ix = i; /* Point in question */
+ opts.p = &smp[i];
+
+ /* Grab the source image point */
+ imr = smp[i]._sr;
+ imv[0] = smp[i]._sv[0];
+ imv[1] = smp[i]._sv[1];
+ imv[2] = smp[i]._sv[2];
+
+ /* Compute the cusp rotated version of the cspace/image points */
+ /* Note that we're not elevating yet! */
+ comp_ce(&opts, rimv, imv, &smp[i].wt);
+ VB(("%f de, ix %d: cusp mapped %f %f %f -> %f %f %f\n", icmNorm33(rimv,imv), i, imv[0], imv[1], imv[2], rimv[0], rimv[1], rimv[2]));
+ rimr = icmNorm33(rimv, sci_gam->cent);
+
+ /* Default setup a no compress or expand mapping of */
+ /* source space/image point to modified destination gamut. */
+ smp[i].sr = rimr;
+ smp[i].sv[0] = rimv[0]; /* Temporary rotated src point */
+ smp[i].sv[1] = rimv[1];
+ smp[i].sv[2] = rimv[2];
+ smp[i].sgam = sci_gam;
+ smp[i].dgam = di_gam;
+
+ VB(("\n"));
+ VB(("point %d:, rimv = %f %f %f, rimr = %f\n",i,rimv[0],rimv[1],rimv[2],rimr));
+ VB(("point %d:, imv = %f %f %f, imr = %f\n",i,imv[0],imv[1],imv[2],imr));
+ VB(("point %d:, drv = %f %f %f, drr = %f\n",i,smp[i].drv[0],smp[i].drv[1],smp[i].drv[2],smp[i].drr));
+
+ /* Set a starting point for the optimisation */
+ smp[i].dgam->nearest(smp[i].dgam, smp[i].dv, smp[i].sv);
+ smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
+
+ /* Re-lookup radialy equivalent point on destination gamut, */
+ /* to match rotated/elevated source */
+ smp[i].drr = smp[i].dgam->radial(smp[i].dgam, smp[i].drv, smp[i].sv);
+
+ /* A default average neighbour value */
+ smp[i].anv[0] = smp[i].drv[0];
+ smp[i].anv[1] = smp[i].drv[1];
+ smp[i].anv[2] = smp[i].drv[2];
+ }
+
+ /* Setup the white & black point blend factor, that makes sure the white and black */
+ /* points are not displaced. */
+ for (i = 0; i < nmpts; i++) {
+ smp[i].naxbf = comp_naxbf(&opts, smp[i]._sv);
+//printf("~1 point %d, comp_lvc = %f, naxbf = %f\n",i,comp_lvc(&opts, smp[i]._sv),smp[i].naxbf);
+ }
+
+ /* Setup the 3D -> 2D tangent conversion ready for guide vector optimization */
+ {
+ double ta[3] = { 50.0, 0.0, 0.0 };
+ double tc[3] = { 0.0, 0.0, 0.0 };
+
+ for (ix = 0; ix < nmpts; ix++) {
+ /* Coompute a rotation that brings the target point location to 50,0,0 */
+ icmVecRotMat(smp[ix].m2d, smp[ix].sv, sc_gam->cent, ta, tc);
+
+ /* And inverse */
+ icmVecRotMat(smp[ix].m3d, ta, tc, smp[ix].sv, sc_gam->cent);
+ }
+ }
+
+ /* Figure out which neighbors of the source values to use */
+ /* for the relative error calculations. */
+ /* Locate the neighbor within the radius for this point, */
+ /* and weight them with a Gausian filter weight. */
+ /* The radius is computed on the normalised surface for this point. */
+ VA(("Establishing filter neighbourhoods\n"));
+ {
+ double mm[3][4]; /* Tangent alignment rotation */
+ double m2[2][2]; /* Additional matrix to alight a with L axis */
+ double ta[3] = { 50.0, 0.0, 0.0 };
+ double tc[3] = { 0.0, 0.0, 0.0 };
+ double avgnd = 0.0; /* Total the average number of neighbours */
+ int minnd = 1e6; /* Minimum number of neighbours */
+
+ for (ix = 0; ix < nmpts; ix++) {
+ double tt[3], rrdl, rrdh, rrdc, dd;
+ double msv[3], ndx[4]; /* Midpoint source value, quadrant distance */
+ double pr; /* Average point radius */
+
+//printf("~1 computing neigbourhood for point %d at %f %f %f\n",ix, smp[ix].sv[0], smp[ix].sv[1], smp[ix].sv[2]);
+ /* Compute a rotation that brings the target point location to 50,0,0 */
+ icmNormalize33(tt, smp[ix].sv, smp[ix].sgam->cent, 1.0);
+ icmVecRotMat(mm, tt, smp[ix].sgam->cent, ta, tc);
+
+ /* Add another rotation to orient it so that [1] corresponds */
+ /* with the L direction, and [2] corresponds with the */
+ /* hue direction. */
+ m2[0][0] = m2[1][1] = 1.0;
+ m2[0][1] = m2[1][0] = 0.0;
+ tt[0] = smp[ix].sv[0] + 1.0;
+ tt[1] = smp[ix].sv[1];
+ tt[2] = smp[ix].sv[2];
+ icmNormalize33(tt, tt, smp[ix].sgam->cent, 1.0);
+ icmMul3By3x4(tt, mm, tt);
+ dd = tt[1] * tt[1] + tt[2] * tt[2];
+ if (dd > 1e-6) { /* There is a sense of L direction */
+
+ /* Create the 2x2 rotation matrix */
+ dd = sqrt(dd);
+ tt[1] /= dd;
+ tt[2] /= dd;
+
+ m2[0][0] = m2[1][1] = tt[1];
+ m2[0][1] = tt[2];
+ m2[1][0] = -tt[2];
+ }
+
+ /* Make rr inversely proportional to radius, so that */
+ /* filter scope is constant delta E */
+ rrdl = smp[ix].wt.r.rdl;
+ rrdh = smp[ix].wt.r.rdh;
+//printf("~1 rdl %f, rdh %f\n",smp[ix].wt.r.rdl,smp[ix].wt.r.rdh);
+ if (rrdl < 1e-3) rrdl = 1e-3;
+ if (rrdh < 1e-3) rrdh = 1e-3;
+
+ /* Average radius of source and destination */
+ pr = 0.5 * (smp[ix]._sr + smp[ix].dr);
+
+//printf("~1 pr = %f from _sr %f & dr %f\n",pr,smp[ix]._sr,smp[ix].dr);
+ if (pr < 5.0)
+ pr = 5.0;
+ rrdl *= 50.0/pr;
+ rrdh *= 50.0/pr;
+ rrdc = 0.5 * (rrdl + rrdh); /* Chrominance radius */
+
+ /* Scale the filter radius by the L/C value, */
+ /* so that the filters are largest at the equator, and smallest */
+ /* at the white & black points. This allows the wt.a.lx wt.a.cx to work. */
+ pr = smp[ix].naxbf + 0.1; /* "spherical" type weighting, 0.707 at 45 degrees */
+ rrdl *= pr;
+ rrdh *= pr;
+ rrdc *= pr;
+//printf("~1 at %f %f %f, rrdl = %f, rrdh = %f\n",smp[ix]._sv[0], smp[ix]._sv[1], smp[ix]._sv[2], rrdl, rrdh);
+
+ smp[ix].nnd = 0; /* Nothing in lists */
+
+ /* Search for points within the gausian radius */
+ for (i = 0; i < nmpts; i++) {
+ double x, y, z, tv[3];
+
+ /* compute rotated location */
+ icmNormalize33(tt, smp[i].sv, smp[ix].sgam->cent, 1.0);
+ icmMul3By3x4(tv, mm, tt);
+ icmMulBy2x2(&tv[1], m2, &tv[1]);
+
+ x = tv[1]/rrdl;
+ y = tv[2]/rrdh;
+ z = (tv[0] - 50.0)/rrdc;
+
+ /* Compute normalized delta normalized tangent surface */
+ dd = x * x + y * y + z * z;
+
+ /* If we're within the direction filtering radius, */
+ /* and not of the opposite hue */
+ if (dd <= 1.0 && tv[0] > 0.0) {
+ double w;
+
+ dd = sqrt(dd); /* Convert to radius <= 1.0 */
+
+ /* Add this point into the list */
+ if (smp[ix].nnd >= smp[ix]._nnd) {
+ neighb *nd;
+ int _nnd;
+ _nnd = 5 + smp[ix]._nnd * 2;
+ if ((nd = (neighb *)realloc(smp[ix].nd, _nnd * sizeof(neighb))) == NULL) {
+ VB(("realloc of neighbs at vector %d failed\n",ix));
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ return NULL;
+ }
+ smp[ix].nd = nd;
+ smp[ix]._nnd = _nnd;
+ }
+ smp[ix].nd[smp[ix].nnd].n = &smp[i];
+
+ /* Box filter */
+// w = 1.0;
+
+ /* Triangle filter */
+// w = 1.0 - dd;
+
+// /* Cubic spline filter */
+// w = 1.0 - dd;
+// w = w * w * (3.0 - 2.0 * w);
+
+ /* Gaussian filter (default) */
+ w = exp(-9.0 * dd/2.0);
+
+ /* Sphere filter */
+// w = sqrt(1.0 - dd * dd);
+
+ /* Sinc^2 filter */
+// w = 3.1415926 * dd;
+// if (w < 1e-9)
+// w = 1e-9;
+// w = sin(w)/w;
+// w = w * w;
+
+ smp[ix].nd[smp[ix].nnd].w = w; /* Will be normalized to sum to 1.0 */
+
+// /* Sphere filter for depth */
+// w = sqrt(1.0 - dd * dd);
+
+ /* Cubic spline filter for depth */
+// w = 1.0 - dd;
+// w = w * w * (3.0 - 2.0 * w);
+
+ /* Gaussian filter for depth (default) */
+ w = exp(-9.0 * dd/2.0);
+
+ smp[ix].nd[smp[ix].nnd].rw = w; /* Won't be normalized */
+
+//printf("~1 adding %d at %f %f %f, rad %f L %f, w %f dir.\n",i, smp[i].sv[0], smp[i].sv[1], smp[i].sv[2],sqrt(dd),tv[0],smp[ix].nd[smp[ix].nnd].w);
+
+ smp[ix].nnd++;
+ }
+ }
+ if (smp[ix].nnd < minnd)
+ minnd = smp[ix].nnd;
+ avgnd += (double)smp[ix].nnd;
+//printf("~1 total of %d dir neigbours\n\n",smp[ix].nnd);
+
+ }
+ avgnd /= (double)nmpts;
+
+ if (verb) printf("Average number of direction guide neigbours = %f, min = %d\n",avgnd,minnd);
+
+ /* Now normalize each points weighting */
+ for (i = 0; i < nmpts; i++) {
+ double tw;
+
+ /* Adjust direction weights to sum to 1.0 */
+ for (tw = 0.0, j = 0; j < smp[i].nnd; j++) {
+ tw += smp[i].nd[j].w;
+ }
+ for (j = 0; j < smp[i].nnd; j++) {
+ smp[i].nd[j].w /= tw;
+ }
+
+ }
+ }
+
+#ifdef SHOW_NEIGB_WEIGHTS
+ {
+ vrml *wrl = NULL;
+ double yellow[3] = { 1.0, 1.0, 0.0 };
+ double red[3] = { 1.0, 0.0, 0.0 };
+ double green[3] = { 0.0, 1.0, 0.0 };
+ double pp[3];
+
+ for (i = 0; i < nmpts; i++) {
+ double maxw;
+
+ if ((wrl = new_vrml("weights.wrl", 1)) == NULL)
+ error("New vrml failed");
+
+ maxw = 0.0;
+ for (j = 0; j < smp[i].nnd; j++) {
+ if (smp[i].nd[j].w > maxw)
+ maxw = smp[i].nd[j].w;
+ }
+ for (j = 0; j < smp[i].nnd; j++) {
+ wrl->add_col_vertex(wrl, 0, smp[i].sgam->cent, smp[i].nd[j].n == &smp[i] ? red : yellow);
+ icmNormalize33(pp, smp[i].nd[j].n->_sv, smp[i].sgam->cent, smp[i].nd[j].w * 50.0/maxw);
+ wrl->add_col_vertex(wrl, 0, pp, smp[i].nd[j].n == &smp[i] ? red : yellow);
+ }
+ wrl->make_lines(wrl, 0, 2);
+
+ wrl->del(wrl);
+ printf("Waiting for input after writing 'weights.wrl' for point %d:\n",i);
+ getchar();
+ }
+ }
+#endif /* SHOW_NEIGB_WEIGHTS */
+
+ /* Optimise the location of the source to destination mapping. */
+ if (verb) printf("Optimizing source to destination mapping...\n");
+
+ VA(("Doing first pass to locate the nearest point\n"));
+ /* First pass to locate the weighted nearest point, to use in subsequent passes */
+ {
+ double s[2] = { 20.0, 20.0 }; /* 2D search area */
+ double iv[3]; /* Initial start value */
+ double nv[2]; /* 2D New value */
+ double tp[3]; /* Resultint value */
+ double ne; /* New error */
+ int notrials = NO_TRIALS;
+
+ for (i = 0; i < nmpts; i++) { /* Move all the points */
+ double bnv[2]; /* Best 2d value */
+ double brv; /* Best return value */
+ int trial;
+ double mv;
+
+ opts.pass = 0; /* Itteration pass */
+ opts.ix = i; /* Point to optimise */
+ opts.p = &smp[i];
+
+ /* If the img point is within the destination, then we're */
+ /* expanding, so temporarily swap src and radial dest. */
+ /* (??? should we use the cvect() direction to determine swap, */
+ /* rather than radial ???) */
+ smp[i].swap = 0;
+ if (useexp && smp[i].dr > (smp[i].sr + 1e-9)) {
+ gamut *tt;
+ double dd;
+
+ smp[i].swap = 1;
+ tt = smp[i].dgam; smp[i].dgam = smp[i].sgam; smp[i].sgam = tt;
+
+ smp[i].dr = smp[i].sr;
+ smp[i].dv[0] = smp[i].sv[0];
+ smp[i].dv[1] = smp[i].sv[1];
+ smp[i].dv[2] = smp[i].sv[2];
+
+ smp[i].sr = smp[i].drr;
+ smp[i].sv[0] = smp[i].drv[0];
+ smp[i].sv[1] = smp[i].drv[1];
+ smp[i].sv[2] = smp[i].drv[2];
+ }
+
+ /* Convert our start value from 3D to 2D for speed. */
+ icmMul3By3x4(iv, smp[i].m2d, smp[i].dv);
+ nv[0] = iv[0] = iv[1];
+ nv[1] = iv[1] = iv[2];
+
+ /* Do several trials from different starting points to avoid */
+ /* any local minima, particularly with nearest mapping. */
+ brv = 1e38;
+ for (trial = 0; trial < notrials; trial++) {
+ double rv; /* Temporary */
+
+ /* Optimise the point */
+ if (powell(&rv, 2, nv, s, 0.01, 1000, optfunc1, (void *)(&opts), NULL, NULL) == 0
+ && rv < brv) {
+ brv = rv;
+//printf("~1 point %d, trial %d, new best %f\n",i,trial,sqrt(rv));
+ bnv[0] = nv[0];
+ bnv[1] = nv[1];
+ }
+//else printf("~1 powell failed with rv = %f\n",rv);
+ /* Adjust the starting point with a random offset to avoid local minima */
+ nv[0] = iv[0] + d_rand(-20.0, 20.0);
+ nv[1] = iv[1] + d_rand(-20.0, 20.0);
+ }
+ if (brv == 1e38) { /* We failed to get a result */
+ VB(("multiple powells failed to get a result\n"));
+#ifdef NEVER
+ /* Optimise the point with debug on */
+ opts.debug = 1;
+ icmMul3By3x4(iv, smp[i].m2d, smp[i].dv);
+ nv[0] = iv[0] = iv[1];
+ nv[1] = iv[1] = iv[2];
+ powell(NULL, 2, nv, s, 0.01, 1000, optfunc1, (void *)(&opts), NULL, NULL);
+#endif
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ return NULL;
+ }
+
+ /* Convert best result 2D -> 3D */
+ tp[2] = bnv[1];
+ tp[1] = bnv[0];
+ tp[0] = 50.0;
+ icmMul3By3x4(tp, smp[i].m3d, tp);
+
+ /* Remap it to the destinaton gamut surface */
+ smp[i].dgam->radial(smp[i].dgam, tp, tp);
+ icmCpy3(smp[i].aodv, tp);
+
+ /* Undo any swap */
+ if (smp[i].swap) {
+ gamut *tt;
+ double dd;
+
+ tt = smp[i].dgam; smp[i].dgam = smp[i].sgam; smp[i].sgam = tt;
+
+ /* We get the point on the real src gamut out when swap */
+ smp[i]._sv[0] = smp[i].aodv[0];
+ smp[i]._sv[1] = smp[i].aodv[1];
+ smp[i]._sv[2] = smp[i].aodv[2];
+
+ /* So we need to compute cusp mapped sv */
+ comp_ce(&opts, smp[i].sv, smp[i]._sv, &smp[i].wt);
+ smp[i].sr = icmNorm33(smp[i].sv, smp[i].sgam->cent);
+
+ VB(("Exp Src %d = %f %f %f\n",i,smp[i]._sv[0],smp[i]._sv[1],smp[i]._sv[2]));
+ smp[i].aodv[0] = smp[i].drv[0];
+ smp[i].aodv[1] = smp[i].drv[1];
+ smp[i].aodv[2] = smp[i].drv[2];
+ }
+ }
+ if (verb) {
+ printf("."); fflush(stdout);
+ }
+ }
+
+ VA(("Locating weighted mapping vectors without smoothing:\n"));
+ /* Second pass to locate the optimized overall weighted point nrdv[], */
+ /* not counting relative error. */
+ {
+ double s[2] = { 20.0, 20.0 }; /* 2D search area */
+ double iv[3]; /* Initial start value */
+ double nv[2]; /* 2D New value */
+ double tp[3]; /* Resultint value */
+ double ne; /* New error */
+ int notrials = NO_TRIALS;
+
+ for (i = 0; i < nmpts; i++) { /* Move all the points */
+ double bnv[2]; /* Best 2d value */
+ double brv; /* Best return value */
+ int trial;
+ double mv;
+
+ opts.pass = 0; /* Itteration pass */
+ opts.ix = i; /* Point to optimise */
+ opts.p = &smp[i];
+
+//printf("~1 point %d, sv %f %f %f\n",i,smp[i].sv[0],smp[i].sv[1],smp[i].sv[2]);
+
+ /* Convert our start value from 3D to 2D for speed. */
+ icmMul3By3x4(iv, smp[i].m2d, smp[i].aodv);
+
+ nv[0] = iv[0] = iv[1];
+ nv[1] = iv[1] = iv[2];
+//printf("~1 point %d, iv %f %f %f, 2D %f %f\n",i, smp[i].aodv[0], smp[i].aodv[1], smp[i].aodv[2], iv[0], iv[1]);
+
+ /* Do several trials from different starting points to avoid */
+ /* any local minima, particularly with nearest mapping. */
+ brv = 1e38;
+ for (trial = 0; trial < notrials; trial++) {
+ double rv; /* Temporary */
+
+ /* Optimise the point */
+ if (powell(&rv, 2, nv, s, 0.01, 1000, optfunc2, (void *)(&opts), NULL, NULL) == 0
+ && rv < brv) {
+ brv = rv;
+//printf("~1 point %d, trial %d, new best %f at xy %f %f\n",i,trial,sqrt(rv), nv[0],nv[1]);
+ bnv[0] = nv[0];
+ bnv[1] = nv[1];
+ }
+//else printf("~1 powell failed with rv = %f\n",rv);
+ /* Adjust the starting point with a random offset to avoid local minima */
+ nv[0] = iv[0] + d_rand(-20.0, 20.0);
+ nv[1] = iv[1] + d_rand(-20.0, 20.0);
+ }
+ if (brv == 1e38) { /* We failed to get a result */
+ VB(("multiple powells failed to get a result\n"));
+#ifdef NEVER
+ /* Optimise the point with debug on */
+ opts.debug = 1;
+ icmMul3By3x4(iv, smp[i].m2d, smp[i].dv);
+ nv[0] = iv[0] = iv[1];
+ nv[1] = iv[1] = iv[2];
+ powell(NULL, 2, nv, s, 0.01, 1000, optfunc2, (void *)(&opts), NULL, NULL);
+#endif
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ return NULL;
+ }
+
+ /* Convert best result 3D -> 2D */
+ tp[2] = bnv[1];
+ tp[1] = bnv[0];
+ tp[0] = 50.0;
+ icmMul3By3x4(tp, smp[i].m3d, tp);
+
+ /* Remap it to the destinaton gamut surface */
+ smp[i].dgam->radial(smp[i].dgam, tp, tp);
+
+ icmCpy3(smp[i].nrdv, tp); /* Non smoothed result */
+ icmCpy3(smp[i].anv, tp); /* Starting point for smoothing */
+ icmCpy3(smp[i].dv, tp); /* Default current solution */
+ smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
+//printf("~1 %d: dv %f %f %f\n", i, smp[i].dv[0], smp[i].dv[1], smp[i].dv[2]);
+
+ }
+ if (verb) {
+ printf("."); fflush(stdout);
+ }
+ }
+
+#ifdef DIAG_POINTS
+ /* Show just the closest vectors etc. */
+ for (i = 0; i < nmpts; i++) { /* Move all the points */
+// icmCpy3(smp[i].dv, smp[i].drv); /* Radial */
+ icmCpy3(smp[i].dv, smp[i].aodv); /* Nearest */
+// icmCpy3(smp[i].dv, smp[i].nrdv); /* No smoothed weighted */
+// icmCpy3(smp[i].dv, smp[i].dv); /* pre-filter smooothed */
+ smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
+ }
+#else
+ /* The smoothed direction and raw depth is a single pass, */
+ /* but we use multiple passes to determine the extra depth that */
+ /* needs to be added so that the smoothed result lies within */
+ /* the destination gamut. */
+
+#if VECADJPASSES > 0 || RSPLPASSES > 0
+ /* We will need inward pointing correction vectors */
+ {
+ gamut *shgam; /* Shrunken di_gam */
+ double cusps[6][3];
+ double wp[3], bp[3], kp[3];
+ double p[3], p2[3], rad;
+ int i;
+
+ double s[2] = { 20.0, 20.0 }; /* 2D search area */
+ double iv[3]; /* Initial start value */
+ double nv[2]; /* 2D New value */
+ double tp[3]; /* Resultint value */
+ double ne; /* New error */
+ int notrials = NO_TRIALS;
+
+ cow *gpnts = NULL; /* Mapping points to create 3D -> 3D mapping */
+ datai il, ih;
+ datao ol, oh;
+ int gres[MXDI];
+ double avgdev[MXDO];
+
+ /* Create a gamut that is a shrunk version of the destination */
+
+ if ((shgam = new_gamut(di_gam->getsres(di_gam), di_gam->getisjab(di_gam),
+ di_gam->getisrast(di_gam))) == NULL) {
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ return NULL;
+ }
+
+ shgam->setnofilt(shgam);
+
+ /* Translate all the surface nodes */
+ for (i = 0;;) {
+ double len;
+
+ if ((i = di_gam->getrawvert(di_gam, p, i)) < 0)
+ break;
+
+ doshrink(&opts, p, p, SHRINK);
+ shgam->expand(shgam, p);
+ }
+ /* Translate cusps */
+ if (di_gam->getcusps(di_gam, cusps) == 0) {
+ shgam->setcusps(shgam, 0, NULL);
+ for (i = 0; i < 6; i++) {
+ doshrink(&opts, p, cusps[i], SHRINK);
+ shgam->setcusps(shgam, 1, p);
+ }
+ shgam->setcusps(shgam, 2, NULL);
+ }
+ /* Translate white and black points */
+ if (di_gam->getwb(di_gam, wp, bp, kp, NULL, NULL, NULL) == 0) {
+ doshrink(&opts, wp, wp, SHRINK);
+ doshrink(&opts, bp, bp, SHRINK);
+ doshrink(&opts, kp, kp, SHRINK);
+ shgam->setwb(shgam, wp, bp, kp);
+ }
+
+ if ((gpnts = (cow *)malloc(nmpts * sizeof(cow))) == NULL) {
+ fprintf(stderr,"gamut map: Malloc of near smooth points failed\n");
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ shgam->del(shgam);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ return NULL;
+ }
+
+ /* Now locate the closest points on the shrunken gamut */
+ /* and set them up for creating a rspl */
+ opts.shgam = shgam;
+ for (i = 0; i < nmpts; i++) { /* Move all the points */
+ gtri *ctri = NULL;
+ double tmp[3];
+ double bnv[2]; /* Best 2d value */
+ double brv; /* Best return value */
+ int trial;
+ double mv;
+
+ opts.pass = 0; /* Itteration pass */
+ opts.ix = i; /* Point to optimise */
+ opts.p = &smp[i];
+
+ /* Convert our start value from 3D to 2D for speed. */
+ icmMul3By3x4(iv, smp[i].m2d, smp[i].dv);
+ nv[0] = iv[0] = iv[1];
+ nv[1] = iv[1] = iv[2];
+
+ /* Do several trials from different starting points to avoid */
+ /* any local minima, particularly with nearest mapping. */
+ brv = 1e38;
+ for (trial = 0; trial < notrials; trial++) {
+ double rv; /* Temporary */
+
+ /* Optimise the point */
+ if (powell(&rv, 2, nv, s, 0.01, 1000, optfunc1a, (void *)(&opts), NULL, NULL) == 0
+ && rv < brv) {
+ brv = rv;
+ bnv[0] = nv[0];
+ bnv[1] = nv[1];
+ }
+ /* Adjust the starting point with a random offset to avoid local minima */
+ nv[0] = iv[0] + d_rand(-20.0, 20.0);
+ nv[1] = iv[1] + d_rand(-20.0, 20.0);
+ }
+ if (brv == 1e38) { /* We failed to get a result */
+ VB(("multiple powells failed to get a result\n"));
+ shgam->del(shgam); /* Done with this */
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ return NULL;
+ }
+
+ /* Convert best result 2D -> 3D */
+ tp[2] = bnv[1];
+ tp[1] = bnv[0];
+ tp[0] = 50.0;
+ icmMul3By3x4(tp, smp[i].m3d, tp);
+
+ /* Remap it to the destinaton gamut surface */
+ shgam->radial(shgam, tp, tp);
+
+ /* Compute mapping vector from dst to shdst */
+ icmSub3(smp[i].temp, tp, smp[i].dv);
+
+
+ /* In case shrunk vector is very short, add a small part */
+ /* of the nearest normal. */
+ smp[i].dgam->nearest_tri(smp[i].dgam, NULL, smp[i].dv, &ctri);
+ icmScale3(tmp, ctri->pe, 0.1); /* Scale to small inwards */
+ icmAdd3(smp[i].temp, smp[i].temp, tmp);
+
+ /* evector */
+ icmNormalize3(smp[i].temp, smp[i].temp, 1.0);
+
+ /* Place it in rspl setup array */
+ icmCpy3(gpnts[i].p, smp[i].dv);
+ icmCpy3(gpnts[i].v, smp[i].temp);
+ gpnts[i].w = 1.0;
+ }
+
+ for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+// gres[j] = (mapres+1)/2; /* Half resolution */
+ gres[j] = mapres; /* Full resolution */
+ avgdev[j] = GAMMAP_RSPLAVGDEV;
+ }
+
+ evectmap = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
+ evectmap->fit_rspl_w(evectmap, GAMMAP_RSPLFLAGS, gpnts, nmpts,
+ map_il, map_ih, gres, map_ol, map_oh, 1.0, avgdev, NULL);
+
+// ~~999
+#ifdef PLOT_EVECTS /* Create VRML of error correction vectors */
+ {
+ vrml *wrl = NULL;
+ int doaxes = 0;
+ double cc[3] = { 0.7, 0.7, 0.7 };
+ double red[3] = { 1.0, 0.0, 0.0 };
+ double green[3] = { 0.0, 1.0, 0.0 };
+ double tmp[3];
+ co cp;
+#ifdef PLOT_AXES
+ doaxes = 1;
+#endif
+
+ printf("###### gamut/nearsmth.c: writing diagnostic evects.wrl\n");
+ wrl = new_vrml("evects.wrl", doaxes);
+ wrl->make_gamut_surface_2(wrl, di_gam, 0.6, 0, cc);
+ cc[0] = -1.0;
+ wrl->make_gamut_surface(wrl, shgam, 0.2, cc);
+
+ /* Start of guide vector plot */
+ wrl->start_line_set(wrl, 0);
+
+ for (i = 0; i < nmpts; i++) {
+ wrl->add_col_vertex(wrl, 0, smp[i].dv, red);
+#ifdef NEVER /* Plot created vectors */
+ icmScale3(tmp, smp[i].temp, 4.0);
+ icmSub3(tmp, smp[i].dv, tmp);
+#else
+ /* Plot interpolated vectors */
+ icmCpy3(cp.p, smp[i].dv);
+ evectmap->interp(evectmap, &cp);
+ icmScale3(tmp, cp.v, 4.0);
+ icmSub3(tmp, smp[i].dv, tmp);
+#endif
+ wrl->add_col_vertex(wrl, 0, tmp, green);
+ }
+ wrl->make_lines(wrl, 0, 2); /* Guide vectors */
+ wrl->del(wrl); /* Write and delete */
+ }
+#endif /* PLOT_EVECTS */
+ shgam->del(shgam); /* Done with this */
+ free(gpnts);
+ }
+#endif /* VECADJPASSES > 0 || RSPLPASSES > 0 */
+
+#ifdef VECSMOOTHING
+ VA(("Smoothing guide vectors:\n"));
+
+ /* Compute the neighbourhood smoothed anv[] from dv[] */
+ for (i = 0; i < nmpts; i++) {
+ double anv[3]; /* new anv[] */
+ double tmp[3];
+
+ /* Compute filtered value */
+ anv[0] = anv[1] = anv[2] = 0.0;
+ for (j = 0; j < smp[i].nnd; j++) {
+ nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
+ double nw = smp[i].nd[j].w; /* Weight */
+ double tmp[3];
+
+ icmSub3(tmp, smp[i].sv, np->sv); /* Vector from neighbour src to src */
+ icmAdd3(tmp, tmp, np->dv); /* Neigbour dst + vector */
+
+ icmScale3(tmp, tmp, nw); /* weight for filter */
+ icmAdd3(anv, anv, tmp); /* sum filtered value */
+ }
+
+ /* Blend to un-smoothed value on neutral axis */
+ icmBlend3(anv, smp[i].dv, anv, smp[i].naxbf);
+
+ icmCpy3(smp[i].dv, anv);
+ icmCpy3(smp[i].anv, anv);
+ smp[i].rext = 0.0; /* No correction */
+ }
+
+#if VECADJPASSES > 0
+ /* Fine tune vectors to compensate for side effects of vector smoothing */
+
+ VA(("Fine tuning out of gamut guide vectors:\n"));
+
+ /* Loopkup correction vectors */
+ VA(("Computing fine tuning direction:\n"));
+ for (i = 0; i < nmpts; i++) {
+ co cp;
+ double nd, id, tmp[3];
+
+ icmCpy3(cp.p, smp[i].dv);
+ evectmap->interp(evectmap, &cp);
+ icmNormalize3(smp[i].evect, cp.v, 1.0);
+
+ /* ~~99 ?? should we deal with white & black direction here ?? */
+
+ /* Use closest as a default */
+ smp[i].dgam->nearest(smp[i].dgam, smp[i].tdst, smp[i].dv);
+ nd = icmNorm33(smp[i].tdst, smp[i].dv); /* Dist to nearest */
+
+ /* Compute intersection with dest gamut as tdst */
+ if (!vintersect2(smp[i].dgam, NULL, tmp, smp[i].evect, smp[i].dv)) {
+ /* Got an intersection */
+ id = icmNorm33(tmp, smp[i].dv); /* Dist to intersection */
+ if (id <= (nd + 5.0)) /* And it seems sane */
+ icmCpy3(smp[i].tdst, tmp);
+ }
+
+ smp[i].rext = 0.0;
+ }
+
+ VA(("Fine tuning guide vectors:\n"));
+ for (it = 0; it < VECADJPASSES; it++) {
+ double avgog = 0.0, maxog = 0.0, nog = 0.0;
+ double avgig = 0.0, maxig = 0.0, nig = 0.0;
+
+ /* Filter the level of out/in gamut, and apply correction vector */
+ for (i = 0; i < nmpts; i++) {
+ double cvec[3], clen;
+ double minext = 1e80;
+ double maxext = -1e80; /* Max weighted depth extension */
+ double dext, gain;
+
+ minext = -20.0;
+
+ /* Compute filtered value */
+ for (j = 0; j < smp[i].nnd; j++) {
+ nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
+ double nw = smp[i].nd[j].rw; /* Weight */
+ double tmpl;
+
+ icmSub3(cvec, np->tdst, np->anv); /* Vector needed to target for neighbour */
+ clen = icmDot3(smp[i].evect, cvec); /* Error in this direction */
+
+ tmpl = nw * (clen - minext); /* Track maximum weighted extra depth */
+ if (tmpl < 0.0)
+ tmpl = 0.0;
+ if (tmpl > maxext)
+ maxext = tmpl;
+ }
+ maxext += minext;
+
+ if (it == 0)
+ gain = 1.2;
+ else
+ gain = 0.8;
+
+ /* Accumulate correction with damping */
+ smp[i].rext += gain * maxext;
+
+ /* Error for just this point */
+ icmSub3(cvec, smp[i].tdst, smp[i].anv);
+ clen = icmDot3(smp[i].evect, cvec);
+
+ /* Blend to individual correction on neutral axis */
+ dext = smp[i].naxbf * smp[i].rext + (1.0 - smp[i].naxbf) * clen;
+
+ /* Apply integrated correction */
+ icmScale3(cvec, smp[i].evect, dext);
+ icmAdd3(smp[i].anv, smp[i].dv, cvec);
+
+ if (clen > 0.0) { /* Compression */
+ if (clen > maxog)
+ maxog = clen;
+ avgog += clen;
+ nog++;
+
+ } else { /* Expansion */
+ if (-clen > maxig)
+ maxig = -clen;
+ avgig += -clen;
+ nig++;
+ }
+ }
+ if (verb)
+ printf("No og %4.0f max %f avg %f, No ig %4.0f max %f avg %f\n",
+ nog,maxog,nog > 1 ? avgog/nog : 0.0, nig,maxig,nig > 1 ? avgig/nig : 0.0);
+ }
+
+ /* Copy final results */
+ for (i = 0; i < nmpts; i++) {
+ icmCpy3(smp[i].dv, smp[i].anv);
+ smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
+ }
+
+ if (verb) {
+ double avgog = 0.0, maxog = 0.0, nog = 0.0;
+ double avgig = 0.0, maxig = 0.0, nig = 0.0;
+
+ /* Check the result */
+ for (i = 0; i < nmpts; i++) {
+ double cvec[3], clen;
+
+ /* Error for just this point, for stats */
+ icmSub3(cvec, smp[i].tdst, smp[i].anv);
+ clen = icmDot3(smp[i].evect, cvec);
+
+ if (clen > 0.0) { /* Compression */
+ if (clen > maxog)
+ maxog = clen;
+ avgog += clen;
+ nog++;
+
+ } else { /* Expansion */
+ if (-clen > maxig)
+ maxig = -clen;
+ avgig += -clen;
+ nig++;
+ }
+ }
+ printf("No og %4.0f max %f avg %f, No ig %4.0f max %f avg %f\n",
+ nog,maxog,nog > 1 ? avgog/nog : 0.0, nig,maxig,nig > 1 ? avgig/nig : 0.0);
+ }
+#endif /* VECADJUST */
+#endif /* VECADJPASSES > 0 */
+
+#if RSPLPASSES > 0
+ /* We need to adjust the vectors with extra depth to compensate for */
+ /* for the effect of rspl smoothing. */
+ {
+ cow *gpnts = NULL; /* Mapping points to create 3D -> 3D mapping */
+ rspl *map = NULL; /* Test map */
+ datai il, ih;
+ datao ol, oh;
+ int gres[MXDI];
+ double avgdev[MXDO];
+ double icgain, ixgain; /* Initial compression, expansion gain */
+ double fcgain, fxgain; /* Final compression, expansion gain */
+
+ VA(("Fine tuning vectors to allow for rspl smoothing:\n"));
+
+ for (j = 0; j < 3; j++) { /* Copy ranges */
+ il[j] = map_il[j];
+ ih[j] = map_ih[j];
+ ol[j] = map_ol[j];
+ oh[j] = map_oh[j];
+ }
+
+ /* Adjust the input ranges for guide vectors */
+ for (i = 0; i < nmpts; i++) {
+ for (j = 0; j < 3; j++) {
+ if (smp[i]._sv[j] < il[j])
+ il[j] = smp[i]._sv[j];
+ if (smp[i]._sv[j] > ih[j])
+ ih[j] = smp[i]._sv[j];
+ }
+ }
+
+ /* Now expand the bounding box by aprox 5% margin, but scale grid res */
+ /* to match, so that the natural or given boundary still lies on the grid. */
+ /* (This duplicates code in gammap applied after near_smooth() returns) */
+ /* (We are assuming that our changes to the giude vectprs won't expand the ranges) */
+ {
+ int xmapres;
+ double scale;
+
+ xmapres = (int) ((mapres-1) * 0.05 + 0.5);
+ if (xmapres < 1)
+ xmapres = 1;
+
+ scale = (double)(mapres-1 + xmapres)/(double)(mapres-1);
+
+ for (j = 0; j < 3; j++) {
+ double low, high;
+ high = ih[j];
+ low = il[j];
+ ih[j] = (scale * (high - low)) + low;
+ il[j] = (scale * (low - high)) + high;
+ }
+
+ mapres += 2 * xmapres;
+ }
+
+ if ((gpnts = (cow *)malloc(nmpts * sizeof(cow))) == NULL) {
+ fprintf(stderr,"gamut map: Malloc of near smooth points failed\n");
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ if (evectmap != NULL)
+ evectmap->del(evectmap);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ return NULL;
+ }
+
+ /* Loopkup correction vectors */
+ VA(("Computing fine tuning direction for vectors:\n"));
+ for (i = 0; i < nmpts; i++) {
+ co cp;
+ double nd, id, tmp[3];
+
+ icmCpy3(cp.p, smp[i].dv);
+ evectmap->interp(evectmap, &cp);
+ icmNormalize3(smp[i].evect, cp.v, 1.0);
+
+ /* ~~99 ?? should we deal with white & black direction here ?? */
+
+ /* Use closest as a default */
+ smp[i].dgam->nearest(smp[i].dgam, smp[i].tdst, smp[i].dv);
+ nd = icmNorm33(smp[i].tdst, smp[i].dv); /* Dist to nearest */
+
+ /* Compute intersection with dest gamut as tdst */
+ if (!vintersect2(smp[i].dgam, NULL, tmp, smp[i].evect, smp[i].dv)) {
+ /* Got an intersection */
+ id = icmNorm33(tmp, smp[i].dv); /* Dist to intersection */
+ if (id <= (nd + 5.0)) /* And it seems sane */
+ icmCpy3(smp[i].tdst, tmp);
+ }
+
+ smp[i].coff[0] = smp[i].coff[1] = smp[i].coff[2] = 0.0;
+ smp[i].rext = 0.0;
+ }
+
+ /* We know initially that dv == anv */
+ /* Each pass computes a rext for each point, then */
+ /* anv[] = dv[] + smooth(rext * evect[]) to try and avoid clipping */
+ VA(("Fine tune guide vectors for rspl:\n"));
+ for (it = 0; it < RSPLPASSES; it++) {
+ double tmp[3];
+ double avgog = 0.0, maxog = 0.0, nog = 0.0;
+ double avgig = 0.0, maxig = 0.0, nig = 0.0;
+ double avgrext = 0.0;
+ double ovlen;
+
+ /* Setup the rspl guide points for creating rspl */
+ for (i = 0; i < nmpts; i++) {
+ icmCpy3(gpnts[i].p, smp[i]._sv); /* The orgininal src point */
+ icmCpy3(gpnts[i].v, smp[i].anv); /* current dst from previous results */
+ gpnts[i].w = 1.0;
+ }
+
+ for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+// gres[j] = (mapres+1)/2; /* Half resolution for speed */
+ gres[j] = mapres; /* Full resolution */
+ avgdev[j] = GAMMAP_RSPLAVGDEV;
+ }
+ map = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
+ map->fit_rspl_w(map, GAMMAP_RSPLFLAGS, gpnts, nmpts,
+ il, ih, gres, ol, oh, mapsmooth, avgdev, NULL);
+
+ /* See what the source actually maps to via rspl, and how far from */
+ /* the target point they are. */
+ for (i = 0; i < nmpts; i++) {
+ co cp;
+ double cvec[3];
+
+ /* Lookup rspl smoothed destination value */
+ icmCpy3(cp.p, smp[i]._sv);
+ map->interp(map, &cp);
+ icmCpy3(smp[i].temp, cp.v);
+
+ /* Compute the correction needed and it's signed length */
+ icmSub3(cvec, smp[i].tdst, smp[i].temp);
+ smp[i].clen = icmDot3(smp[i].evect, cvec);
+ }
+
+ /* Compute local correction */
+ for (i = 0; i < nmpts; i++) {
+ double minext = 1e80;
+ double maxext = -1e80; /* Max weighted depth extension */
+ double clen;
+ double tpoint[3], cvect[3];
+ double tt;
+ double cgain, xgain; /* This itters compression, expansion gain */
+ double gain; /* Gain used */
+
+ /* See what the worst case is in the local area, and */
+ /* aim to lower the whole local area by enough to */
+ /* cause the max to be 0.0 (just on the gamut) */
+
+ /* Compute local depth value */
+ minext = -20.0; /* Base to measure max from */
+ for (j = 0; j < smp[i].nnd; j++) {
+ nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
+ double nw = smp[i].nd[j].rw; /* Weight */
+ double tmpl;
+
+ tmpl = nw * (np->clen - minext); /* Track maximum weighted extra depth */
+ if (tmpl < 0.0)
+ tmpl = 0.0;
+ if (tmpl > maxext)
+ maxext = tmpl;
+ }
+ maxext += minext;
+
+ /* maxext is the current effective error at this point with rext aim point */
+ if (it == 0) { /* Set target on first itteration */
+ if (smp[i].rext <= 0.0) /* Expand direction */
+ smp[i].rext += maxext;
+ else
+ smp[i].rext += RSPLSCALE * maxext;
+ }
+ avgrext += smp[i].rext;
+
+ /* Compute offset target point at maxlen from tdst in evect dir. */
+ icmScale3(tpoint, smp[i].evect, smp[i].rext);
+ icmAdd3(tpoint, tpoint, smp[i].tdst);
+
+ /* Expansion/compression gain program */
+ icgain = 1.4; /* Initial itteration compression gain */
+ ixgain = smp[i].wt.f.x * icgain; /* Initial itteration expansion gain */
+ fcgain = 0.5 * icgain; /* Final itteration compression gain */
+ fxgain = 0.5 * ixgain; /* Final itteration expansion gain */
+
+ /* Set the gain */
+ tt = it/(RSPLPASSES - 1.0);
+ cgain = (1.0 - tt) * icgain + tt * fcgain;
+ xgain = (1.0 - tt) * ixgain + tt * fxgain;
+ if (it != 0) /* Expand only on first itter */
+ xgain = 0.0;
+
+//if (i == 0) printf("~1 i %d, it %d, wt.f.x = %f, cgain %f, xgain %f\n",i,it,smp[i].wt.f.x, cgain, xgain);
+ if (smp[i].rext > 0.0) /* Compress direction */
+ gain = cgain;
+ else
+ gain = xgain;
+
+ /* Keep stats of this point */
+ clen = smp[i].clen;
+ if (clen > 0.0) {
+ if (clen > maxog)
+ maxog = clen;
+ avgog += clen;
+ nog++;
+
+ } else { /* Expand */
+ if (-clen > maxig)
+ maxig = -clen;
+ avgig += -clen;
+ nig++;
+ }
+
+ /* Compute needed correction from current rspl smoothed anv */
+ /* to offset target point. */
+ icmSub3(cvect, tpoint, smp[i].temp); /* Correction still needed */
+ icmScale3(cvect, cvect, gain); /* Times gain */
+ icmAdd3(smp[i].coff, smp[i].coff, cvect); /* Accumulated */
+
+ icmCpy3(gpnts[i].p, smp[i].dv);
+ icmCpy3(gpnts[i].v, smp[i].coff);
+ gpnts[i].w = 1.0;
+ }
+
+ for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+// gres[j] = (mapres+1)/2; /* Half resolution */
+ gres[j] = mapres; /* Full resolution */
+ avgdev[j] = GAMMAP_RSPLAVGDEV;
+ }
+ map = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
+ map->fit_rspl_w(map, GAMMAP_RSPLFLAGS, gpnts, nmpts,
+ il, ih, gres, ol, oh, 2.0, avgdev, NULL);
+
+ /* Lookup the smoothed extension vector for each point and apply it */
+ for (i = 0; i < nmpts; i++) {
+ double tt;
+ co cp;
+
+ icmCpy3(cp.p, smp[i].dv);
+ map->interp(map, &cp);
+#ifdef RSPLUSEPOW
+ spow3(smp[i].coff, cp.v, 1.0/2.0); /* Filtered value is current value */
+#else
+ icmCpy3(smp[i].coff, cp.v); /* Filtered value is current value */
+#endif
+
+ /* Make sure anv[] is on the destination gamut at neutral axis */
+ icmScale3(cp.v, cp.v, smp[i].naxbf);
+
+ /* Apply accumulated offset */
+ icmAdd3(smp[i].anv, smp[i].dv, cp.v);
+ }
+ map->del(map);
+
+ if (verb)
+ printf("No og %4.0f max %f avg %f, No ig %4.0f max %f avg %f, avg rext %f\n",
+ nog,maxog,nog > 1 ? avgog/nog : 0.0, nig,maxig,nig > 1 ? avgig/nig : 0.0, avgrext/nmpts);
+ } /* Next pass */
+ free(gpnts);
+
+ /* Copy last anv to dv for result */
+ for (i = 0; i < nmpts; i++) {
+// ~~99
+// Normal target
+ icmCpy3(smp[i].dv, smp[i].anv);
+
+// Show evect direction
+// icmCpy3(smp[i]._sv, smp[i].dv);
+// icmScale3(smp[i].evect, smp[i].evect, 4.0);
+// icmAdd3(smp[i].dv, smp[i].evect, smp[i].dv);
+
+// Show target point destination
+// icmCpy3(smp[i].dv, smp[i].tdst);
+
+// Show offset target destination
+// icmScale3(smp[i].dv, smp[i].evect, smp[i].rext);
+// icmAdd3(smp[i].dv, smp[i].dv, smp[i].tdst);
+
+ smp[i].dr = icmNorm33(smp[i].dv, smp[i].dgam->cent);
+ }
+ }
+
+#endif /* RSPLPASSES > 0 */
+#endif /* NEVER (show debug values) */
+
+ VA(("Smoothing passes done, doing final houskeeping\n"));
+
+ if (verb)
+ printf("\n");
+
+#if defined(SAVE_VRMLS) && defined(PLOT_MAPPING_INFLUENCE)
+ create_influence_plot(smp, nmpts);
+#endif
+
+ VB(("Final guide points:\n"));
+
+ /* Restore the actual non elevated and cust rotated source point */
+ for (i = 0; i < nmpts; i++) {
+
+ VB(("Src %d = %f %f %f\n",i,smp[i].sv[0],smp[i].sv[1],smp[i].sv[2]));
+ VB(("Dst %d = %f %f %f\n",i,smp[i].dv[0],smp[i].dv[1],smp[i].dv[2]));
+
+ /* Save the cusp mapped source value */
+ icmCpy3(smp[i].csv, smp[i].sv);
+
+ /* Finally un cusp map the source point */
+// inv_comp_ce(&opts, smp[i].sv, smp[i].sv, &smp[i].wt);
+// smp[i].sr = icmNorm33(smp[i].sv, smp[i].sgam->cent);
+ icmCpy3(smp[i].sv, smp[i]._sv);
+ smp[i].sr = smp[i]._sr;
+ }
+
+ VB(("Creating sub-surface guide points:\n"));
+
+ /* Create sub-surface points. */
+ for (i = 0; i < nmpts; i++) {
+
+ /* Create a sub-surface mapping point too. */
+ /* Note that not every mapping point has a sub-surface point, */
+ /* and that the gflag and vflag will be nz if it does. */
+ /* We're assuming here that the dv is close to being on the */
+ /* destination gamut, so that the vector_isect param will be */
+ /* close to 1.0 at the intended destination gamut. */
+ {
+ double mv[3], ml, nv[3]; /* Mapping vector & length, noralized mv */
+ double minv[3], maxv[3];
+ double mint, maxt;
+ gtri *mintri, *maxtri;
+
+ smp[i].vflag = smp[i].gflag = 0; /* Default unknown */
+ smp[i].w2 = 0.0;
+ icmSub3(mv, smp[i].dv, smp[i].sv); /* Mapping vector */
+ ml = icmNorm3(mv); /* It's length */
+ if (ml > 0.1) { /* If mapping is non trivial */
+
+//#define PFCOND i == 802
+
+//if (PFCOND) printf("~1 mapping %d = %f %f %f -> %f %f %f\n", i, smp[i].sv[0],smp[i].sv[1],smp[i].sv[2],smp[i].dv[0],smp[i].dv[1],smp[i].dv[2]);
+//if (PFCOND) printf("~1 vector %f %f %f, len %f\n", mv[0], mv[1], mv[2],ml);
+ /* Compute actual depth of ray into destination gamut */
+ if (di_gam->vector_isect(di_gam, smp[i].sv, smp[i].dv,
+ minv, maxv, &mint, &maxt, &mintri, &maxtri) != 0) {
+ double wp[3], bp[3]; /* Gamut white and black points */
+ double p1, napoint[3] = { 50.0, 0.0, 0.0 }; /* Neutral axis point */
+ double natarg[3]; /* Neutral axis sub target */
+ double adepth1, adepth2 = 1000.0; /* Directional depth, radial depth */
+ double adepth; /* Minimum available depth */
+ double mv2[3], sml; /* Sub-surface mapping vector & norm. length */
+
+ /* Locate the point on the neutral axis that is closest to */
+ /* the guide ray. We use this as a destination direction */
+ /* if the sub surface ray gets very long, and to compute */
+ /* a sanity check on the available depth. */
+ if (d_gam->getwb(d_gam, NULL, NULL, NULL, wp, dst_kbp ? NULL : bp, dst_kbp ? bp : NULL) == 0) {
+ if (icmLineLineClosest(napoint, NULL, &p1, NULL, bp, wp,
+ smp[i].sv,smp[i].dv) == 0) {
+ /* Clip it */
+ if (p1 < 0.0)
+ icmCpy3(napoint, bp);
+ else if (p1 > 1.0)
+ icmCpy3(napoint, wp);
+
+//if (PFCOND) printf("~1 neutral axis point = %f %f %f\n", napoint[0], napoint[1], napoint[2]);
+ /* Compute a normalized available depth from distance */
+ /* to closest to neautral axis point */
+ if (maxt > 1.0) /* Compression */
+ if ((mint > 1e-8 && maxt > -1e-8) /* G. & V. Compression */
+ || ((mint < -1e-8 && maxt > -1e-8) /* G. Exp & V. comp. */
+ && (fabs(mint) < (fabs(maxt) - 1e-8))))
+ adepth2 = icmNorm33(napoint, smp[i].dv);
+ else /* Expansion */
+ adepth2 = icmNorm33(napoint, smp[i].sv);
+ }
+#ifdef VERB
+ else {
+ printf("icmLineLineClosest failed\n");
+ }
+#endif
+ }
+#ifdef VERB
+ else {
+ printf("d_gam->getwb failed\n");
+ }
+#endif
+
+//printf("\n~1 i %d: %f %f %f -> %f %f %f\n isect at t %f and %f\n", i, smp[i].sv[0], smp[i].sv[1], smp[i].sv[2], smp[i].dv[0], smp[i].dv[1], smp[i].dv[2], mint, maxt);
+
+ /* Only create sub-surface mapping vectors if it makes sense. */
+ /* If mapping vector is pointing away from destination gamut, */
+ /* (which shouldn't happen), ignore it. If the directional depth */
+ /* is very thin compared to the radial depth, indicating that we're */
+ /* near a "lip", ignore it. */
+ if (mint >= -1e-8 && maxt > 1e-8) {
+
+ /* Gamut compression and vector compression */
+ if (fabs(mint - 1.0) < fabs(maxt) - 1.0
+ && smp[i].dgam->radial(smp[i].dgam, NULL, smp[i].dv)
+ < smp[i].sgam->radial(smp[i].sgam, NULL, smp[i].dv)) {
+
+//if (PFCOND) printf("~1 point is gamut comp & vect comp.\n");
+//if (PFCOND) printf("~1 point is gamut comp & vect comp. mint %f maxt %f\n",mint,maxt);
+ adepth1 = ml * 0.5 * (maxt + mint - 2.0);
+#ifdef CYLIN_SUBVEC
+ adepth = adepth2; /* Always cylindrical depth */
+#else
+ adepth = adepth1 < adepth2 ? adepth1 : adepth2; /* Smaller of the two */
+#endif
+ if (adepth1 < (0.5 * adepth2))
+ continue;
+//if (PFCOND) printf("~1 dir adepth %f, radial adapeth %f\n",adepth1,adepth2);
+ adepth *= 0.9; /* Can't use 100% */
+ smp[i].gflag = 1; /* Gamut compression and */
+ smp[i].vflag = 1; /* vector compression */
+
+ /* Compute available depth and knee factor adjusted sub-vector */
+ icmCpy3(smp[i].sv2, smp[i].dv); /* Sub source is guide dest */
+ ml *= (1.0 - gamcknf); /* Scale by knee */
+ adepth *= (1.0 - gamcknf);
+ sml = ml < adepth ? ml : adepth; /* Smaller of two */
+//if (PFCOND) printf("~1 adjusted subvec len %f\n",sml);
+ icmNormalize3(mv2, mv, sml); /* Full sub-surf disp. == no knee */
+ icmAdd3(mv2, smp[i].sv2, mv2); /* Knee adjusted destination */
+
+//if (PFCOND) printf("~1 before blend sv2 %f %f %f, dv2 %f %f %f\n", smp[i].sv2[0], smp[i].sv2[1], smp[i].sv2[2], mv2[0], mv2[1], mv2[2]);
+ /* Blend towards n.axis as length of sub vector approaches */
+ /* distance to neutral axis. */
+ icmSub3(natarg, napoint, smp[i].sv2);
+ icmNormalize3(natarg, natarg, sml); /* Sub vector towards n.axis */
+ icmAdd3(natarg, natarg, smp[i].sv2); /* n.axis target */
+#ifdef CYLIN_SUBVEC
+ icmCpy3(mv2, natarg); /* cylindrical direction vector */
+#else
+ icmBlend3(mv2, mv2, natarg, sml/adepth2);
+#endif /* CYLIN_SUBVEC */
+//if (PFCOND) printf("~1 after blend sv2 %f %f %f, dv2 %f %f %f\n", smp[i].sv2[0], smp[i].sv2[1], smp[i].sv2[2], mv2[0], mv2[1], mv2[2]);
+
+ icmCpy3(smp[i].dv2, mv2); /* Destination */
+ icmCpy3(smp[i].temp, smp[i].dv2); /* Save a copy to temp */
+ smp[i].w2 = 0.8;
+ } else {
+//if (PFCOND) printf("~1 point is gamut exp & vect exp. mint %f maxt %f\n",mint,maxt);
+ smp[i].gflag = 2; /* Gamut expansion and */
+ smp[i].vflag = 0; /* vector expansion, */
+ /* but crossing over, so no sub vect. */
+//if (PFCOND) printf("~1 point is crossover point\n",mint,maxt);
+ }
+
+ /* Gamut expansion and vector expansion */
+ } else if (mint < -1e-8 && maxt > 1e-8) {
+
+//if (PFCOND) printf("~1 point is gamut exp & vect exp. mint %f maxt %f\n",mint,maxt);
+ /* This expand/expand case has reversed src/dst sense to above */
+ adepth1 = ml * 0.5 * -mint;
+#ifdef CYLIN_SUBVEC
+ adepth = adepth2; /* Always cylindrical depth */
+#else
+ adepth = adepth1 < adepth2 ? adepth1 : adepth2;
+#endif
+//if (PFCOND) printf("~1 dir adepth %f, radial adapeth %f\n",adepth1,adepth2);
+ adepth *= 0.9; /* Can't use 100% */
+
+ if (adepth1 < (0.6 * adepth2))
+ continue;
+
+ smp[i].gflag = 2; /* Gamut expansion */
+ smp[i].vflag = 2; /* vector is expanding */
+
+ icmCpy3(smp[i].dv2, smp[i].sv); /* Sub dest is guide src */
+ ml *= (1.0 - gamxknf); /* Scale by knee */
+ adepth *= (1.0 - gamxknf);
+ sml = ml < adepth ? ml : adepth;/* Smaller of two */
+ icmNormalize3(mv2, mv, sml); /* Full sub-surf disp. == no knee */
+ icmSub3(mv2, smp[i].dv2, mv2); /* Knee adjusted source */
+
+ /* Blend towards n.axis as length of sub vector approaches */
+ /* distance to neutral axis. */
+ icmSub3(natarg, smp[i].dv2, napoint);
+ icmNormalize3(natarg, natarg, sml); /* Sub vector away n.axis */
+ icmSub3(natarg, smp[i].dv2, natarg);/* n.axis oriented source */
+#ifdef CYLIN_SUBVEC
+ icmCpy3(mv2, natarg); /* cylindrical direction vector */
+#else
+ icmBlend3(mv2, mv2, natarg, sml/adepth2); /* dir adjusted src */
+#endif /* CYLIN_SUBVEC */
+
+ icmCpy3(smp[i].sv2, mv2); /* Source */
+ icmCpy3(smp[i].temp, smp[i].dv2); /* Save a copy to temp */
+ smp[i].w2 = 0.8;
+
+ /* Conflicted case */
+ } else {
+ /* Nonsense vector */
+ smp[i].gflag = 0; /* Gamut compression but */
+ smp[i].vflag = 0; /* vector is expanding */
+//if (PFCOND) printf("~1 point is nonsense vector mint %f maxt %f\n",mint,maxt);
+
+ icmCpy3(smp[i].dv, smp[i].aodv); /* Clip to the destination gamut */
+ }
+ }
+ }
+ }
+
+#ifdef NEVER // Diagnostic
+ smp[i].vflag = 0; /* Disable sub-points */
+#endif /* NEVER */
+
+ VB(("Out Src %d = %f %f %f\n",i,smp[i].sv[0],smp[i].sv[1],smp[i].sv[2]));
+ VB(("Out Dst %d = %f %f %f\n",i,smp[i].dv[0],smp[i].dv[1],smp[i].dv[2]));
+ if (smp[i].vflag != 0) {
+ VB(("Out Src2 %d = %f %f %f\n",i,smp[i].sv2[0],smp[i].sv2[1],smp[i].sv2[2]));
+ VB(("Out Dst2 %d = %f %f %f\n",i,smp[i].dv2[0],smp[i].dv2[1],smp[i].dv2[2]));
+ }
+ }
+
+#ifdef SUBVEC_SMOOTHING
+ VB(("Smoothing sub-surface guide points:\n"));
+
+ /* Smooth the sub-surface mapping points */
+ /* dv2[] is duplicated in temp[], so use temp[] as the values to be filtered */
+ for (i = 0; i < nmpts; i++) {
+ double tmp[3];
+ double fdv2[3]; /* Filtered dv2[] */
+ double tw; /* Total weight */
+ int rc;
+
+ if (smp[i].vflag == 0)
+ continue;
+
+ /* Compute filtered value */
+ tw = fdv2[0] = fdv2[1] = fdv2[2] = 0.0;
+ for (j = 0; j < smp[i].nnd; j++) {
+ nearsmth *np = smp[i].nd[j].n; /* Pointer to neighbor */
+ double nw = smp[i].nd[j].w; /* Weight */
+ double tmp[3];
+
+ if (np->vflag) {
+ icmSub3(tmp, smp[i].sv2, np->sv2); /* Vector from neighbour src to src */
+ icmAdd3(tmp, tmp, np->dv2); /* Neigbour dst + vector */
+
+ icmScale3(tmp, tmp, nw); /* weight for filter */
+ icmAdd3(fdv2, fdv2, tmp); /* sum filtered value */
+ tw += nw;
+ }
+ }
+
+ if (tw > 0.0) {
+//printf("~1 %d: moved %f %f %f -> %f %f %f de %f\n", i, smp[i].dv2[0], smp[i].dv2[1], smp[i].dv2[2], fdv2[0], fdv2[1], fdv2[2], icmNorm33(smp[i].dv2,fdv2));
+ icmScale3(smp[i].dv2, fdv2, 1.0/tw);
+ }
+ }
+#endif /* SUBVEC_SMOOTHING */
+
+ VB(("near_smooth is done\n"));
+
+ if (evectmap != NULL)
+ evectmap->del(evectmap);
+#ifndef PLOT_DIGAM
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ for (i = 0; i < nmpts; i++) {
+ smp[i].sgam = NULL;
+ smp[i].dgam = NULL;
+ }
+#else /* !PLOT_DIGAM */
+ warning("!!!!! PLOT_DIGAM defined !!!!!");
+#endif /* !PLOT_DIGAM */
+ *npp = nmpts;
+ return smp;
+}
+
+/* Free the list of points that was returned */
+void free_nearsmth(nearsmth *smp, int nmpts) {
+ int i;
+
+ for (i = 0; i < nmpts; i++) {
+ if (smp[i].nd != NULL)
+ free(smp[i].nd);
+ }
+ free(smp);
+}
+
+
+/* =================================================================== */
+
+#if defined(SAVE_VRMLS) && defined(PLOT_MAPPING_INFLUENCE)
+/* Create a plot indicating how the source mapping has been guided by the */
+/* various weighting forces */
+static void create_influence_plot(nearsmth *smp, int nmpts) {
+ gamut *gam;
+ int src = 0; /* 1 = src, 0 = dst gamuts */
+ vrml *wrl = NULL;
+ co *fpnts = NULL; /* Mapping points to create diagnostic color mapping */
+ rspl *swdiag = NULL;
+ int gres[3];
+ double avgdev[3];
+ double cols[4][3] = { { 1.0, 0.0, 0.0 }, /* Absolute = red */
+ { 1.0, 1.0, 0.0 }, /* Relative = yellow */
+ { 0.0, 0.0, 1.0 }, /* Radial = blue */
+ { 0.0, 1.0, 0.0 } }; /* Depth = green */
+ double grey[3] = { 0.5, 0.5, 0.5 }; /* Grey */
+ double max, min;
+ int ix;
+
+ if (src)
+ gam = sci_gam;
+ else
+ gam = di_gam;
+
+ /* Setup the scattered data points */
+ if ((fpnts = (co *)malloc((nmpts) * sizeof(co))) == NULL) {
+ fprintf(stderr,"gamut map: Malloc of diagnostic mapping setup points failed\n");
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ return NULL;
+ }
+
+ /* Compute error values and diagnostic color */
+ /* for each guide vector */
+ for (i = 0; i < nmpts; i++) {
+ double dv[4], gv;
+ double rgb[3];
+
+ /* Source value location */
+ if (src) {
+ for (j = 0; j < 3; j++)
+ fpnts[i].p[j] = smp[i]._sv[j]; /* Non rotated and elevated */
+ } else { /* Dest value location */
+ for (j = 0; j < 3; j++)
+ fpnts[i].p[j] = smp[i].dv[j];
+ }
+
+ /* Diagnostic color */
+ max = -1e60; min = 1e60;
+ for (k = 0; k < 4; k++) { /* Find max and min error value */
+ dv[k] = smp[i].dbgv[k];
+ if (dv[k] > max)
+ max = dv[k];
+ if (dv[k] < min)
+ min = dv[k];
+ }
+ for (k = 0; k < 4; k++) /* Scale to max */
+ dv[k] /= max;
+ max /= max;
+ min /= max;
+ max -= min; /* reduce min to zero */
+ for (k = 0; k < 4; k++)
+ dv[k] /= max;
+ for (gv = 1.0, k = 0; k < 4; k++) /* Blend remainder with grey */
+ gv -= dv[k];
+
+ for (j = 0; j < 3; j++) /* Compute interpolated color */
+ fpnts[i].v[j] = 0.0;
+ for (k = 0; k < 4; k++) {
+ for (j = 0; j < 3; j++)
+ fpnts[i].v[j] += dv[k] * cols[k][j];
+ }
+ for (j = 0; j < 3; j++)
+ fpnts[i].v[j] += gv * grey[j];
+ }
+
+ /* Create the diagnostic color rspl */
+ for (j = 0; j < 3; j++) { /* Set resolution for all axes */
+ gres[j] = mapres;
+ avgdev[j] = 0.001;
+ }
+ swdiag = new_rspl(RSPL_NOFLAGS, 3, 3); /* Allocate 3D -> 3D */
+ swdiag->fit_rspl(swdiag, RSPL_NOFLAGS, fpnts, nmpts, NULL, NULL, gres, NULL, NULL, 1.0, avgdev, NULL);
+
+ /* Now create a plot of the sci_gam with the vertexes colored acording to the */
+ /* diagnostic map. */
+ if ((wrl = new_vrml("sci_gam_wt.wrl", 1)) == NULL) {
+ fprintf(stderr,"gamut map: new_vrml failed\n");
+ if (fpnts != NULL)
+ free(fpnts);
+ if (swdiag != NULL)
+ swdiag->del(swdiag);
+ if (si_gam != sc_gam)
+ sci_gam->del(sci_gam);
+ if (di_gam != sci_gam && di_gam != sci_gam)
+ di_gam->del(di_gam);
+ free_nearsmth(smp, nmpts);
+ *npp = 0;
+ return NULL;
+ }
+
+ /* Plot the gamut triangle vertexes */
+ for (ix = 0; ix >= 0;) {
+ co pp;
+ double col[3];
+
+ ix = gam->getvert(gam, NULL, pp.p, ix);
+ swdiag->interp(swdiag, &pp);
+ wrl->add_col_vertex(wrl, 0, pp.p, pp.v);
+ }
+ gam->startnexttri(gam);
+ for (;;) {
+ int vix[3];
+ if (gam->getnexttri(gam, vix))
+ break;
+ wrl->add_triangle(wrl, 0, vix);
+ }
+ wrl->make_triangles_vc(wrl, 0, 0.0);
+
+ printf("Writing sci_gam_wt.wrl file\n");
+ wrl->del(wrl); /* Write file */
+ free(fpnts);
+ swdiag->del(swdiag);
+}
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gamut/nearsmth.h b/gamut/nearsmth.h
new file mode 100644
index 0000000..6e94969
--- /dev/null
+++ b/gamut/nearsmth.h
@@ -0,0 +1,274 @@
+#ifndef NEARSMTH_H
+#define NEARSMTH_H
+
+/*
+ * nearsmth
+ *
+ * Gamut mapping support routine that creates a list of
+ * guide vectors from the source to destination
+ * gamut, smoothed to retain reasonably even spacing.
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/1/2002
+ * Version: 1.00
+ *
+ * Copyright 2002 - 2006 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.
+ */
+
+
+/* Settings for nearsmth & gammap */
+
+#define GAMMAP_RSPLFLAGS (0) /* Default rspl flags */
+#define GAMMAP_RSPLAVGDEV 0.005 /* Default average deviation */
+
+/* Structures to hold weightings */
+
+/* Color x light & dark = 14 combinations */
+typedef enum {
+ /* Combinations in prioroty order */
+ gmm_light_red = 0x101,
+ gmm_light_yellow = 0x102,
+ gmm_light_green = 0x104,
+ gmm_light_cyan = 0x108,
+ gmm_light_blue = 0x110,
+ gmm_light_magenta = 0x120,
+ gmm_light_neutral = 0x140,
+
+ gmm_dark_red = 0x201,
+ gmm_dark_yellow = 0x202,
+ gmm_dark_green = 0x204,
+ gmm_dark_cyan = 0x208,
+ gmm_dark_blue = 0x210,
+ gmm_dark_magenta = 0x220,
+ gmm_dark_neutral = 0x240,
+
+ gmm_l_d_red = 0x301,
+ gmm_l_d_yellow = 0x302,
+ gmm_l_d_green = 0x304,
+ gmm_l_d_cyan = 0x308,
+ gmm_l_d_blue = 0x310,
+ gmm_l_d_magenta = 0x320,
+ gmm_l_d_neutral = 0x340,
+
+ gmm_light_colors = 0x17f, /* All light colors */
+ gmm_dark_colors = 0x27f, /* All dark colors */
+
+ gmm_default = 0x37f, /* All light and dark colors */
+
+ gmm_end = 0x0000, /* Mark the end of the list */
+ gmm_ignore = 0x1001, /* Ignore this entry */
+
+ /* Components */
+ gmc_light = 0x100,
+ gmc_dark = 0x200,
+ gmc_l_d = 0x300, /* Both Light and dark */
+ gmc_red = 0x001,
+ gmc_yellow = 0x002,
+ gmc_green = 0x004,
+ gmc_cyan = 0x008,
+ gmc_blue = 0x010,
+ gmc_magenta = 0x020,
+ gmc_neutral = 0x040,
+ gmc_colors = 0x07f /* All colors */
+
+} gmm_chex;
+
+/* Single weight */
+typedef struct {
+ double l,c,h;
+} iweight;
+
+/* Group of complete weights */
+/* (Remeber to alter near_wcopy() and near_wblend() !!) */
+typedef struct {
+
+ gmm_chex ch; /* Color hextant this applies to */
+
+ /* Cusp alignment control */
+ struct {
+ iweight w; /* Component alignment weights, 0 - 1 */
+ double cx; /* Chroma expansion, 1 = none, > 1 = more */
+ } c;
+
+ /* Radial weighting */
+ /* Weight to give to minimizing delta E to source mapped radially */
+ struct {
+ double o; /* Overall Radial weight */
+ double h; /* Hue dominance vs l+c, 0 - 1 */
+ double l; /* l dominance vs, c, 0 - 1 */
+ } l;
+
+ /* Absolute error weighting */
+ /* Weight given to minimizing delta E to destination closest point */
+ struct {
+ double o; /* Overall Absolute weight */
+
+ double h; /* Hue dominance vs l+c, 0 - 1 */
+
+ double wl; /* White l dominance vs, c, 0 - 1 */
+ double gl; /* Grey l dominance vs, c, 0 - 1 */
+ double bl; /* Black l dominance vs, c, 0 - 1 */
+
+ double wlth; /* White l blend start radius, 0 - 1, at white = 0 */
+ double blpow; /* Black l blend power, linear = 1.0, enhance < 1.0 */
+
+ double lxpow; /* L error extra power, none = 1.0 */
+ double lxthr; /* L error xover threshold in DE */
+ } a;
+
+ /* Relative vector smoothing. */
+ struct {
+ double rdl; /* Direction smoothing radius L* dir. (delta E radius at src point)*/
+ double rdh; /* Direction smoothing radius H* (delta E radius at src point)*/
+ } r;
+
+ /* depth weighting */
+ /* Weighing to give to minimizing depth ratio by mapping to/from adequate dest/src depth */
+ struct {
+ double co; /* Overall compression weighting */
+ double xo; /* Overall expansion weighting */
+ } d;
+
+ /* Fine tuning destination gamut mapping */
+ struct {
+ double x; /* Final expansion weight, 0 - 1 */
+ } f; /* Weights fine tuning to expand rather than just compress */
+
+ /* Internal use */
+ iweight rl; /* Resolved radial weight */
+ iweight ra; /* Resolved absolute weight */
+
+ int set; /* Whether this has been set */
+} gammapweights;
+
+
+/* Blend a two groups of weights into one, given two weightings */
+void near_wblend(gammapweights *dst,
+ gammapweights *src1, double wgt1, gammapweights *src2, double wgt2);
+
+
+/* A neighbour and it's weight for relative error */
+typedef struct {
+ struct _nearsmth *n; /* Pointer to neigbor */
+ double rw; /* Raw neighbor interpolation weight (1.0 at point) */
+ double w; /* Neighbor interpolation weight (sums to 1.0) */
+} neighb;
+
+/* Returned point values. */
+/* Note that source == input point, destination == output point */
+/* (All the source values are in rotated L mapped partial gamut mapped space) */
+struct _nearsmth {
+
+ /* Public: */
+ int gflag; /* Gamut direction flag. 0 = not determinable, 1 = comp., 2 = exp. */
+ int vflag; /* Vector direction flag. 0 = not determinable, 1 = comp., 2 = exp. */
+ /* sv2 & dv2 are valid if vflag != 0 */
+
+ /* Gamut surface mapping guide point */
+ double sv[3]; /* Source value (input, cusp aligned during fwd optimization) */
+ double sr; /* Corresponding source radius from center */
+ double drv[3]; /* Destination radial value (starting point & reference) */
+ double drr; /* Destination radial value radius from center */
+ double dv[3]; /* Output destination value */
+ double dr; /* Output destination value radius from center */
+ double div[3]; /* gam[cx]pf moderated dv[] value */
+
+ /* Gamut sub-surface mapping guide point (knee shape controlled by gamcknf & gamxknf) */
+ double sv2[3]; /* Sub-surface source value */
+ double dv2[3]; /* Sub-surface destination value */
+ double div2[3]; /* gam[cx]pf moderated dv2[] value */
+ double w2; /* Sub-surface weight */
+
+ /* Diagnostic points */
+ double csv[3]; /* Non-cusp mapped source value */
+
+ /* Private to nearsmth: */
+ gammapweights wt; /* Weight for this point determined from original source location */
+ int swap; /* Swapped during nearest finding */
+ double mL, fmL; /* Mid point L value, filtered mid point L value */
+ double m2d[3][4]; /* Tangent alignment rotation for sv[] 3D -> 2D */
+ double m3d[3][4]; /* Tangent alignment rotation for 2D -> sv[] 3D */
+ double _sv[3]; /* Original (non cusp aligned) source value (input) */
+ double _sr; /* Original source radius */
+ double naxbf; /* Blend factor that goes to 0.0 at white & black points. */
+ double aodv[3]; /* Absolute error optimized destination value */
+ double nrdv[3]; /* No relative weight optimized destination value */
+ double anv[3]; /* Average neighborhood target point (relative target) */
+
+ double tdst[3]; /* Target destination on gamut */
+ double evect[3]; /* Accumulated extension vector direction */
+ double clen; /* Current correction length needed */
+ double coff[3]; /* Correction offset */
+ double rext;
+
+ double temp[3]; /* General temporary */
+ gamut *sgam; /* Source gamut sci_gam = intersection of src and img gamut gamut */
+ gamut *dgam; /* Destination gamut di_gam */
+
+ int nnd, _nnd; /* No & size of direction neighbour list */
+ neighb *nd; /* Allocated list of neighbours */
+
+ double dcratio; /* Depth compression ratio */
+ double dxratio; /* Depth expansion ratio */
+
+ int debug;
+ double dbgv[4]; /* Error components va, vr, vl, vd on last itteration */
+
+}; typedef struct _nearsmth nearsmth;
+
+
+/* Return the upper bound on the number of points that will be generated */
+int near_smooth_np(
+ gamut *sc_gam, /* Source colorspace gamut */
+ gamut *s_gam, /* Source image gamut (== sc_gam if none) */
+ gamut *d_gam, /* Destination colorspace gamut */
+ double xvra /* Extra vertex ratio */
+);
+
+/* Return a list of points. Call free_nearsmth() after use */
+/* Return NULL on error */
+nearsmth *near_smooth(
+ int verb, /* Verbose flag */
+ int *npp, /* Return the number of points returned */
+ gamut *sc_gam, /* Source colorspace gamut */
+ gamut *s_gam, /* Source image gamut (== sc_gam if none) */
+ gamut *d_gam, /* Destination colorspace gamut */
+ int src_kbp, /* Use K only black point as src gamut black point */
+ int dst_kbp, /* Use K only black point as dst gamut black point */
+ double d_bp[3], /* Destination target black point - may be NULL */
+ gammapweights *wh, /* Structure holding weights */
+ double gamcknf, /* Gamut compression knee factor, 0.0 - 1.0 */
+ double gamxknf, /* Gamut expansion knee factor, 0.0 - 1.0 */
+ int usecomp, /* Flag indicating whether smoothed compressed value will be used */
+ int useexp, /* Flag indicating whether smoothed expanded value will be used */
+ double xvra, /* Extra vertex ratio */
+ int mapres, /* Target grid res for 3D RSPL */
+ double mapsmooth, /* Target smoothing for 3D RSPL */
+ datai map_il, /* Preliminary rspl input range */
+ datai map_ih,
+ datao map_ol, /* Preliminary rspl output range */
+ datao map_oh
+);
+
+/* Free the list of points that was returned */
+void free_nearsmth(nearsmth *smp, int npp);
+
+/* Expand the compact form of weights into the explicit form. */
+int expand_weights(gammapweights out[14], gammapweights *in);
+
+/* Blend a two expanded groups of individual weights into one */
+void near_xwblend(
+gammapweights *dst,
+gammapweights *src1, double wgt1,
+gammapweights *src2, double wgt2
+);
+
+/* Tweak weights acording to extra cmy cusp flags or rel override */
+void tweak_weights(gammapweights out[14], int dst_cmymap, int rel_oride);
+
+#endif /* NEARSMTH_H */
+
diff --git a/gamut/smthtest.c b/gamut/smthtest.c
new file mode 100644
index 0000000..24fdfef
--- /dev/null
+++ b/gamut/smthtest.c
@@ -0,0 +1,460 @@
+
+/*
+ * nearsmth test code. Test the smoothed nearpoint routine.
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/1/2002
+ * Version: 1.00
+ *
+ * Copyright 2002, 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.
+ */
+
+/* TTBD:
+ *
+ */
+
+#undef DEBUG /* test a single value out */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "rspl.h"
+#include "gamut.h"
+#include "nearsmth.h"
+
+double m21po[3] = { 2.0, 1.0, 2.0 }; /* Many to 1 filter mixing power LCh (theoretically 2) */
+
+/* Mapping weights */
+gammapweights weights[] = {
+ {
+ gmm_default, /* Non hue specific defaults */
+ { /* Cusp alignment control */
+ {
+ 0.0, /* Cusp luminance alignment weighting 0 = none, 1 = full */
+ 0.0, /* Cusp chroma alignment weighting 0 = none, 1 = full */
+ 0.2 /* Cusp hue alignment weighting 0 = none, 1 = full */
+ },
+ 1.00 /* Chroma expansion 1 = none */
+ },
+ { /* Radial weighting */
+ 0.0, /* Radial error overall weight, 0 + */
+ 0.5, /* Radial hue dominance vs l+c, 0 - 1 */
+ 0.5 /* Radial l dominance vs, c, 0 - 1 */
+ },
+ { /* Weighting of absolute error of destination from source */
+ 1.0, /* Absolute error overall weight */
+ 0.5, /* Hue dominance vs l+c, 0 - 1 */
+
+ 0.9, /* Light l dominance vs, c, 0 - 1 */
+ 0.9, /* Medium l dominance vs, c, 0 - 1 */
+ 0.9, /* Dark l dominance vs, c, 0 - 1 */
+
+ 0.5, /* l/c dominance breakpoint, 0 - 1 */
+ 0.0, /* l dominance exageration, 0+ */
+ 0.0 /* c dominance exageration, 0+ */
+ },
+ { /* Relative vector smoothing */
+ 30.0, 20.0 /* Relative Smoothing radius L* H* */
+ },
+ { /* Weighting of excessive compression error, which is */
+ /* the src->dst vector length over the available dst depth. */
+ /* The depth is half the distance to the intersection of the */
+ /* vector to the other side of the gamut. (doesn't get triggered much ?) */
+ 100.0, /* Compression depth weight */
+ 100.0 /* Expansion depth weight */
+ }
+ }
+};
+
+#define OVERSHOOT 1.0
+
+void usage(void) {
+ fprintf(stderr,"Create smoothed near mapping between two gamuts, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: smthtest [options] ingamut outgamut diag_vrml\n");
+ fprintf(stderr," -v Verbose\n");
+// fprintf(stderr," -s nearf Absolute delta E weighting\n");
+ exit(1);
+}
+
+FILE *start_vrml(char *name, int doaxes);
+void start_line_set(FILE *wrl);
+void add_vertex(FILE *wrl, double pp[3]);
+void make_lines(FILE *wrl, int ppset);
+void end_vrml(FILE *wrl);
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char *xl;
+ char in_name[100];
+ char out_name[100];
+ char diag_name[100];
+ int verb = 0;
+ double nearf = 1.0; /* Absolute delta E weightign */
+ datai il, ih; /* rspl input range */
+ datao ol, oh; /* rspl output range */
+
+ gamut *gin, *gout; /* Input and Output gamuts */
+ nearsmth *nsm; /* Returned list of near smooth points */
+ int nnsm; /* Number of near smoothed points */
+ FILE *wrl; /* VRML output file */
+
+ gammapweights xweights[14];
+
+ int i;
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+#endif
+
+ error_program = argv[0];
+
+ if (argc < 3)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ /* Smoothing factor */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ fa = nfa;
+ if (na == NULL) usage();
+ nearf = atof(na);
+ }
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(out_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(diag_name,argv[fa++]);
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* read the input device gamut */
+
+ gin = new_gamut(0.0, 0, 0);
+
+ if ((xl = strrchr(in_name, '.')) == NULL) { /* Add .gam extention if there isn't one */
+ xl = in_name + strlen(in_name);
+ strcpy(xl,".gam");
+ }
+
+ if (gin->read_gam(gin, in_name))
+ error("Reading input gamut failed");
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* read the output device gamut */
+
+ gout = new_gamut(0.0, 0, 0);
+
+ if ((xl = strrchr(out_name, '.')) == NULL) { /* Add .gam extention if there isn't one */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".gam");
+ }
+
+ if (gout->read_gam(gout, out_name))
+ error("Reading output gamut failed");
+
+ /* - - - - - - - - - - - - - - - - - - - */
+
+ il[0] = ol[0] = 0.0;
+ il[1] = ol[1] = -128.0;
+ il[2] = ol[2] = -128.0;
+ ih[0] = oh[0] = 100.0;
+ ih[1] = oh[1] = 128.0;
+ ih[2] = oh[2] = 128.0;
+
+ /* Convert from compact to explicit hextant weightings */
+ expand_weights(xweights, weights);
+
+ /* Create the near point mapping */
+ nsm = near_smooth(verb, &nnsm, gin, gin, gout, 0, 0, NULL, xweights,
+ 0.1, 0.1, 1, 1, 2.0, 17, 10.0, il, ih, ol, oh);
+ if (nsm == NULL)
+ error("Creating smoothed near points failed");
+
+ /* Output the src to smoothed near point vectors */
+ if ((xl = strrchr(diag_name, '.')) == NULL) { /* Add .wrl extention if there isn't one */
+ xl = diag_name + strlen(diag_name);
+ strcpy(xl,".wrl");
+ }
+
+ wrl = start_vrml(diag_name, 1);
+ start_line_set(wrl);
+
+ for (i = 0; i < nnsm; i++) {
+ add_vertex(wrl, nsm[i].sv); /* Source gamut point */
+ add_vertex(wrl, nsm[i].dv); /* Smoother destination value */
+
+// add_vertex(wrl, nsm[i].drv); /* Radial points */
+ }
+ make_lines(wrl, 2);
+ end_vrml(wrl);
+
+ /* Clean up */
+ free_nearsmth(nsm, nnsm);
+
+ gout->del(gout);
+ gin->del(gin);
+
+ return 0;
+}
+
+/* ------------------------------------------------ */
+/* Some simple functions to do basic VRML work */
+
+#ifndef GAMUT_LCENT
+#define GAMUT_LCENT 50.0
+#endif
+static int npoints = 0;
+static int paloc = 0;
+static struct { double pp[3]; } *pary;
+
+static void Lab2RGB(double *out, double *in);
+
+FILE *start_vrml(char *name, int doaxes) {
+ FILE *wrl;
+ struct {
+ double x, y, z;
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+ int i;
+
+ if ((wrl = fopen(name,"w")) == NULL)
+ error("Error opening VRML file '%s'\n",name);
+
+ npoints = 0;
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ fprintf(wrl,"# Lab axes as boxes:\n");
+ for (i = 0; i < 5; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape{\n");
+ fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
+ axes[i].wx, axes[i].wy, axes[i].wz);
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"\n");
+ }
+
+ return wrl;
+}
+
+void
+start_line_set(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+}
+
+void add_vertex(FILE *wrl, double pp[3]) {
+
+ fprintf(wrl,"%f %f %f,\n",pp[1], pp[2], pp[0]-GAMUT_LCENT);
+
+ if (paloc < (npoints+1)) {
+ paloc = (paloc + 10) * 2;
+ if (pary == NULL)
+ pary = malloc(paloc * 3 * sizeof(double));
+ else
+ pary = realloc(pary, paloc * 3 * sizeof(double));
+
+ if (pary == NULL)
+ error ("Malloc failed");
+ }
+ pary[npoints].pp[0] = pp[0];
+ pary[npoints].pp[1] = pp[1];
+ pary[npoints].pp[2] = pp[2];
+ npoints++;
+}
+
+
+void make_lines(FILE *wrl, int ppset) {
+ int i, j;
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (i = 0; i < npoints;) {
+ for (j = 0; j < ppset; j++, i++) {
+ fprintf(wrl,"%d, ", i);
+ }
+ fprintf(wrl,"-1,\n");
+ }
+ fprintf(wrl," ]\n");
+
+ /* Color */
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < npoints; i++) {
+ double rgb[3], Lab[3];
+ Lab[0] = pary[i].pp[0];
+ Lab[1] = pary[i].pp[1];
+ Lab[2] = pary[i].pp[2];
+ Lab2RGB(rgb, Lab);
+ fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ /* End color */
+
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+
+}
+
+void end_vrml(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0)
+ error("Error closing VRML file\n");
+}
+
+
+/* Convert a gamut Lab value to an RGB value for display purposes */
+static void
+Lab2RGB(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+ double R, G, B;
+
+ /* Scale so that black is visible */
+ L = L * (100 - 40.0)/100.0 + 40.0;
+
+ /* First convert to XYZ using D50 white point */
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ x *= 0.9642; /* Multiply by white point, D50 */
+ y *= 1.0;
+ z *= 0.8249;
+
+ /* Now convert to sRGB values */
+ R = x * 3.2410 + y * -1.5374 + z * -0.4986;
+ G = x * -0.9692 + y * 1.8760 + z * 0.0416;
+ B = x * 0.0556 + y * -0.2040 + z * 1.0570;
+
+ if (R < 0.0)
+ R = 0.0;
+ else if (R > 1.0)
+ R = 1.0;
+
+ if (G < 0.0)
+ G = 0.0;
+ else if (G > 1.0)
+ G = 1.0;
+
+ if (B < 0.0)
+ B = 0.0;
+ else if (B > 1.0)
+ B = 1.0;
+
+ R = pow(R, 1.0/2.2);
+ G = pow(G, 1.0/2.2);
+ B = pow(B, 1.0/2.2);
+
+ out[0] = R;
+ out[1] = G;
+ out[2] = B;
+}
+
+
diff --git a/gamut/surftest.c b/gamut/surftest.c
new file mode 100644
index 0000000..ca2a786
--- /dev/null
+++ b/gamut/surftest.c
@@ -0,0 +1,255 @@
+
+/*
+ * surftest
+ *
+ * Do a torture test of the gamut surfacing algorithm in gamut.
+ *
+ * Author: Graeme W. Gill
+ * Date: 11/11/2006
+ * Version: 1.00
+ *
+ * Copyright 2000, 2006 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.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+//#include "xicc.h"
+#include "gamut.h"
+
+#define DEF_POINTS 5
+#define DEF_TPOINTS 50
+#define DEF_HEIGHT 5.0
+
+void usage(char *diag) {
+ fprintf(stderr,"Do gamut surface torture test, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: surftest [options] npoints\n");
+ if (diag != NULL)
+ fprintf(stderr,"Diagnostic: %s\n",diag);
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -r Random points\n");
+ fprintf(stderr," -n Don't add VRML axes or white/black point\n");
+ fprintf(stderr," -h height Height above sqhere (default %f)\n",DEF_HEIGHT);
+ fprintf(stderr," -f Do segemented maxima filtering (default is not)\n");
+ fprintf(stderr," -t ntpoints Number of test points (default %d)\n",DEF_TPOINTS);
+ fprintf(stderr," npoints Number of random points, default %d^3\n",DEF_POINTS);
+ fprintf(stderr," Outputs surftest.wrl");
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char out_name[100];
+ int npoints = DEF_POINTS;
+ int ntpoints = DEF_TPOINTS;
+ double height = DEF_HEIGHT;
+ gamut *gam;
+ int rand = 0;
+ int verb = 0;
+ int doaxes = 1;
+ int dofilt = 0;
+ int i;
+
+#ifdef NUMSUP_H
+ error_program = "surftest";
+#endif
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage(NULL);
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ /* Random */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ rand = 1;
+ }
+ /* No axis output */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ doaxes = 0;
+ }
+ /* Segmented maxima filtering */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ dofilt = 1;
+ }
+ /* Height */
+ else if (argv[fa][1] == 'h' || argv[fa][1] == 'H') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -h");
+ height = atof(na);
+ }
+ /* Number of test points */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -t");
+ ntpoints = atoi(na);
+ }
+ else
+ usage("Unknown flag");
+ } else
+ break;
+ }
+
+ if (fa < argc && argv[fa][0] != '-')
+ npoints = atoi(argv[fa]);
+
+ strcpy(out_name,"surftest.wrl");
+
+ if (verb) {
+ printf("Number of surface points = %d\n",npoints * npoints * npoints);
+ printf("Number of test points = %d\n",ntpoints);
+ }
+
+ /* Creat a gamut object */
+ if ((gam = new_gamut(0.0, 0, 0)) == NULL)
+ error("Failed to create aa gamut object\n");
+
+ if (dofilt == 0)
+ gam->setnofilt(gam);
+
+ if (rand) {
+ npoints = npoints * npoints * npoints;
+
+ /* Create and add our random test points */
+ for (i = 0; i < npoints;) {
+ int j;
+ double pp[3], sum, rad;
+
+ /* Make normalzed random direction vector on sphere radius 30 */
+ for (sum = 0.0, j = 0; j < 3; j++) {
+ double tt = d_rand(-1.0, 1.0);
+ pp[j] = tt;
+ sum += tt * tt;
+ }
+ if (sum < 1e-6)
+ continue;
+ sum = sqrt(sum);
+ rad = d_rand(30.0, 30.0 + height);
+ for (j = 0; j < 3; j++) {
+ pp[j] /= sum;
+ pp[j] *= rad;
+ }
+ pp[0] += 50.0;
+//printf("~1 point %f %f %f\n",pp[0],pp[1],pp[2]);
+// if (verb) printf("\r%d",i+1); fflush(stdout);
+ gam->expand(gam, pp);
+ i++;
+ }
+// if (verb) printf("\n");
+ } else {
+ int co[3];
+
+ /* Create and add our gridded test points */
+ for (co[0] = 0; co[0] < npoints; co[0]++) {
+ for (co[1] = 0; co[1] < npoints; co[1]++) {
+ for (co[2] = 0; co[2] < npoints; co[2]++) {
+ double pp[3], sum, rad;
+ int m, n;
+
+#ifndef NEVER
+ /* Make sure at least one coords are 0 & 1 */
+ for (n = m = 0; m < 3; m++) {
+ if (co[m] == 0 || co[m] == (npoints-1))
+ n++;
+ }
+ if (n < 1)
+ continue;
+#endif
+ pp[0] = 2.0 * (co[0]/(npoints-1.0) - 0.5);
+ pp[1] = 2.0 * (co[1]/(npoints-1.0) - 0.5);
+ pp[2] = 2.0 * (co[2]/(npoints-1.0) - 0.5);
+
+#ifdef NEVER
+ /* Make normalzed random direction vector on sphere radius 30 */
+ for (sum = 0.0, m = 0; m < 3; m++) {
+ sum += pp[m] * pp[m];
+ }
+ if (sum < 1e-6)
+ continue;
+ sum = sqrt(sum);
+#else
+
+ sum = 1.0;
+#endif /* NEVER */
+ rad = d_rand(30.0, 30.0 + height);
+ for (m = 0; m < 3; m++) {
+ pp[m] /= sum;
+ pp[m] *= rad;
+ }
+ pp[0] += 50.0;
+//printf("~1 point %f %f %f\n",pp[0],pp[1],pp[2]);
+ gam->expand(gam, pp);
+ }
+ }
+ }
+ }
+
+ /* Write out the gamut surface */
+ if (gam->write_vrml(gam, out_name, doaxes, 0))
+ error ("write vrml failed on '%s'",out_name);
+
+ if (verb)
+ printf("Written out the gamut surface\n");
+
+ /* Test the gamut surface */
+ for (i = 0; i < ntpoints;) {
+ int j;
+ double pp[3], sum;
+ double r, out[3];
+
+ /* Make normalzed random direction vector on sphere */
+ for (sum = 0.0, j = 0; j < 3; j++) {
+ double tt = d_rand(-1.0, 1.0);
+ pp[j] = tt;
+ sum += tt * tt;
+ }
+ if (sum < 1e-6)
+ continue;
+ sum = sqrt(sum);
+ for (j = 0; j < 3; j++) {
+ pp[j] /= sum;
+ }
+
+ /* Test surface */
+ r = gam->radial(gam, out, pp);
+ i++;
+ }
+
+ gam->del(gam);
+
+ return 0;
+}
+
+
diff --git a/gamut/viewgam.c b/gamut/viewgam.c
new file mode 100644
index 0000000..0b58269
--- /dev/null
+++ b/gamut/viewgam.c
@@ -0,0 +1,700 @@
+
+/*
+ * viewgam
+ *
+ * Gamut support routines.
+ *
+ * Author: Graeme W. Gill
+ * Date: 4/10/00
+ * Version: 1.00
+ *
+ * Copyright 2000 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "gamut.h"
+#include "cgats.h"
+
+/*
+ This program reads one or more CGATS format triangular gamut
+ surface descriptions, and combines them into a VRML file,
+ so that the gamuts can be visually compared.
+
+ */
+
+/* TTBD:
+ *
+ */
+
+#undef DEBUG
+
+#undef HALF_HACK /* 27.0 */
+
+void usage(char *diag, ...) {
+ fprintf(stderr,"View gamuts Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: viewgam { [-c color] [-t trans] [-w|s] infile.gam } ... outfile.wrl\n");
+ fprintf(stderr," -c color Color to make gamut, r = red, g = green, b = blue\n");
+ fprintf(stderr," c = cyan, m = magenta, y = yellow, e = grey, w = white\n");
+ fprintf(stderr," n = natural color\n");
+ fprintf(stderr," -t trans Set transparency from 0.0 (opaque) to 1.0 (invisible)\n");
+ 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," -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");
+ fprintf(stderr," -I isect.gam Same as -i, but save intersection gamut to isect.gam\n");
+ fprintf(stderr," outfile.wrl Name of output .wrl file\n");
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+#define GCENT 50.0 /* Center of object view */
+
+typedef enum {
+ gam_red = 0,
+ gam_green = 1,
+ gam_blue = 2,
+ gam_cyan = 3,
+ gam_magenta = 4,
+ gam_yellow = 5,
+ gam_grey = 6,
+ gam_white = 7,
+ gam_natural = 8
+} gam_colors;
+
+struct {
+ double r, g, b;
+} color_rgb[8] = {
+ { 1, 0, 0 }, /* gam_red */
+ { 0, 1, 0 }, /* gam_green */
+ { 0, 0, 1 }, /* gam_blue */
+ { 0, 1, 1 }, /* gam_cyan */
+ { 1, 0, 1 }, /* gam_magenta */
+ { 1, 1, 0 }, /* gam_yellow */
+ { .1, .1, .1 }, /* gam_grey */
+ { .7, .7, .7 } /* gam_white */
+};
+
+typedef enum {
+ gam_solid = 0,
+ gam_wire = 1,
+ gam_points = 2
+} gam_reps;
+
+struct _gamdisp {
+ char in_name[MAXNAMEL+1];
+ gam_colors in_colors; /* Color enum for each input */
+ double in_trans; /* Transparency for each input */
+ gam_reps in_rep; /* Representation enum for each input */
+}; typedef struct _gamdisp gamdisp;
+
+
+/* Set a default for a given gamut */
+static void set_default(gamdisp *gds, int n) {
+ gds[n].in_name[0] = '\000';
+ switch(n) {
+ case 0:
+ gds[n].in_colors = gam_natural;
+ gds[n].in_rep = gam_solid;
+ gds[n].in_trans = 0.0;
+ break;
+ case 1:
+ gds[n].in_colors = gam_white;
+ gds[n].in_rep = gam_wire;
+ gds[n].in_trans = 0.0;
+ break;
+ case 2:
+ gds[n].in_colors = gam_red;
+ gds[n].in_rep = gam_wire;
+ gds[n].in_trans = 0.0;
+ break;
+ case 3:
+ gds[n].in_colors = gam_cyan;
+ gds[n].in_rep = gam_wire;
+ gds[n].in_trans = 0.0;
+ break;
+ case 4:
+ gds[n].in_colors = gam_yellow;
+ gds[n].in_rep = gam_wire;
+ gds[n].in_trans = 0.2;
+ break;
+ case 5:
+ gds[n].in_colors = gam_green;
+ gds[n].in_rep = gam_wire;
+ gds[n].in_trans = 0.3;
+ break;
+ case 6:
+ gds[n].in_colors = gam_blue;
+ gds[n].in_rep = gam_wire;
+ gds[n].in_trans = 0.4;
+ break;
+ case 7:
+ gds[n].in_colors = gam_magenta;
+ gds[n].in_rep = gam_wire;
+ gds[n].in_trans = 0.5;
+ break;
+ default:
+ gds[n].in_colors = n % 6;
+ gds[n].in_rep = gam_wire;
+ gds[n].in_trans = 0.6;
+ break;
+ }
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa, nfa, mfa; /* argument we're looking at */
+ int n, ng = 0; /* Current allocation, number of input gamuts */
+ gamdisp *gds; /* Definition of each gamut */
+ int doaxes = 1;
+ int docusps = 0;
+ int isect = 0;
+ FILE *wrl;
+ char out_name[MAXNAMEL+1];
+ char iout_name[MAXNAMEL+1] = "\000";;
+ if (argc < 3)
+ usage("Too few arguments, got %d expect at least 2",argc-1);
+
+ mfa = 1; /* Minimum final arguments */
+
+ if ((gds = (gamdisp *)malloc((ng+1) * sizeof(gamdisp))) == NULL)
+ error("Malloc failed on gamdisp");
+ set_default(gds, 0);
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ /* Color */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument after flag -c");
+ switch (na[0]) {
+ case 'r':
+ case 'R':
+ gds[ng].in_colors = gam_red;
+ break;
+ case 'g':
+ case 'G':
+ gds[ng].in_colors = gam_green;
+ break;
+ case 'b':
+ case 'B':
+ gds[ng].in_colors = gam_blue;
+ break;
+ case 'c':
+ case 'C':
+ gds[ng].in_colors = gam_cyan;
+ break;
+ case 'm':
+ case 'M':
+ gds[ng].in_colors = gam_magenta;
+ break;
+ case 'y':
+ case 'Y':
+ gds[ng].in_colors = gam_yellow;
+ break;
+ case 'e':
+ case 'E':
+ gds[ng].in_colors = gam_grey;
+ break;
+ case 'w':
+ case 'W':
+ gds[ng].in_colors = gam_white;
+ break;
+ case 'n':
+ case 'N':
+ gds[ng].in_colors = gam_natural;
+ break;
+ default:
+ usage("Unknown argument after flag -c '%c'",na[0]);
+ }
+ }
+
+ /* Transparency */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ double v;
+ fa = nfa;
+ if (na == NULL) usage("Expect argument after flag -t");
+ v = atof(na);
+ if (v < 0.0)
+ v = 0.0;
+ else if (v > 1.0)
+ v = 1.0;
+ gds[ng].in_trans = v;
+ }
+
+ /* Solid output */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ gds[ng].in_rep = gam_solid;
+ }
+
+ /* Wireframe output */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ gds[ng].in_rep = gam_wire;
+ }
+
+ /* No axis output */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ doaxes = 0;
+ }
+
+ /* Add cusp markers */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ docusps = 1;
+ }
+
+ /* Print intersecting volume */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ isect = 1;
+
+ /* There is an intersection output gamut file */
+ if (argv[fa][1] == 'I' && na != NULL) {
+ fa = nfa;
+ strncpy(iout_name, na, MAXNAMEL); iout_name[MAXNAMEL] = '\000';
+ }
+ }
+
+ else
+ usage("Unknown flag '%c'",argv[fa][1]);
+
+ } else if (argv[fa][0] != '\000') { /* Got a non-flag */
+ strncpy(gds[ng].in_name,argv[fa],MAXNAMEL); gds[ng].in_name[MAXNAMEL] = '\000';
+
+ ng++;
+ if ((gds = (gamdisp *)realloc(gds, (ng+1) * sizeof(gamdisp))) == NULL)
+ error("Realloc failed on gamdisp");
+ set_default(gds, ng);
+ } else {
+ break;
+ }
+ }
+
+ /* The last "gamut" is actually the output VRML filename, */
+ /* so unwind it. */
+
+ if (ng < 2)
+ usage("Not enough arguments to specify output VRML files");
+
+ strncpy(out_name,gds[--ng].in_name,MAXNAMEL); out_name[MAXNAMEL] = '\000';
+
+#ifdef DEBUG
+ for (n = 0; n < ng; n++) {
+ printf("Input file %d is '%s'\n",n,gds[n].in_name);
+ printf("Input file %d has color %d\n",n,gds[n].in_colors);
+ printf("Input file %d has rep %d\n",n,gds[n].in_rep);
+ printf("Input file %d has trans %f\n",n,gds[n].in_trans);
+
+ }
+ printf("Output file is '%s'\n",out_name);
+#endif /* DEBUG */
+
+ /* Open up the output file */
+ if ((wrl = fopen(out_name,"w")) == NULL)
+ error("Error opening output file '%s'\n",out_name);
+
+ /* Write the header info */
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl," children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+#ifdef NEVER
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+#else
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," intensity 0.2\n");
+ fprintf(wrl," ambientIntensity 0.1\n");
+ fprintf(wrl," direction -1 -1 -1\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," intensity 0.6\n");
+ fprintf(wrl," ambientIntensity 0.2\n");
+ fprintf(wrl," direction 1 1 1\n");
+ fprintf(wrl," }\n");
+#endif
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes) {
+ /* Define the axis boxes */
+ struct {
+ double x, y, z; /* Box center */
+ double wx, wy, wz; /* Box size */
+ double r, g, b; /* Box color */
+ } axes[5] = {
+ { 0, 0, 50-GCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+
+ /* Define the labels */
+ struct {
+ double x, y, z;
+ double size;
+ char *string;
+ double r, g, b;
+ } labels[6] = {
+ { -2, 2, -GCENT + 100 + 10, 10, "+L*", .7, .7, .7 }, /* Top of L axis */
+ { -2, 2, -GCENT - 10, 10, "0", .7, .7, .7 }, /* Bottom of L axis */
+ { 100 + 5, -3, 0-GCENT, 10, "+a*", 1, 0, 0 }, /* +a (red) axis */
+ { -5, -100 - 10, 0-GCENT, 10, "-b*", 0, 0, 1 }, /* -b (blue) axis */
+ { -100 - 15, -3, 0-GCENT, 10, "-a*", 0, 0, 1 }, /* -a (green) axis */
+ { -5, 100 + 5, 0-GCENT, 10, "+b*", 1, 1, 0 }, /* +b (yellow) axis */
+ };
+
+ fprintf(wrl," # Lab axes as boxes:\n");
+ for (n = 0; n < 5; n++) {
+ fprintf(wrl," Transform { translation %f %f %f\n", axes[n].x, axes[n].y, axes[n].z);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape{\n");
+ fprintf(wrl," geometry Box { size %f %f %f }\n",
+ axes[n].wx, axes[n].wy, axes[n].wz);
+ fprintf(wrl," appearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[n].r, axes[n].g, axes[n].b);
+ fprintf(wrl," }\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+ fprintf(wrl," # Axes identification:\n");
+ for (n = 0; n < 6; n++) {
+ fprintf(wrl," Transform { translation %f %f %f\n", labels[n].x, labels[n].y, labels[n].z);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape{\n");
+ fprintf(wrl," geometry Text { string [\"%s\"]\n",labels[n].string);
+ fprintf(wrl," fontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n",
+ labels[n].size);
+ fprintf(wrl," }\n");
+ fprintf(wrl," appearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", labels[n].r, labels[n].g, labels[n].b);
+ fprintf(wrl," }\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+ }
+
+ /* Read each input in turn */
+ for (n = 0; n < ng; n++) {
+ int i;
+ cgats *pp;
+ int nverts;
+ int ntris;
+ int Lf, af, bf; /* Fields holding L, a & b data */
+ int v0f, v1f, v2f; /* Fields holding verticies 0, 1 & 2 */
+
+ pp = new_cgats(); /* Create a CGATS structure */
+
+ /* Setup to cope with a gamut file */
+ pp->add_other(pp, "GAMUT");
+
+ if (pp->read_name(pp, gds[n].in_name))
+ error("Input file '%s' error : %s",gds[n].in_name, pp->err);
+
+ if (pp->t[0].tt != tt_other || pp->t[0].oi != 0)
+ error("Input file isn't a GAMUT format file");
+ if (pp->ntables != 2)
+ error("Input file doesn't contain exactly two tables");
+
+ if ((nverts = pp->t[0].nsets) <= 0)
+ error("No verticies");
+ if ((ntris = pp->t[1].nsets) <= 0)
+ error("No triangles");
+
+ if ((Lf = pp->find_field(pp, 0, "LAB_L")) < 0)
+ error("Input file doesn't contain field LAB_L");
+ if (pp->t[0].ftype[Lf] != r_t)
+ error("Field LAB_L is wrong type");
+ if ((af = pp->find_field(pp, 0, "LAB_A")) < 0)
+ error("Input file doesn't contain field LAB_A");
+ if (pp->t[0].ftype[af] != r_t)
+ error("Field LAB_A is wrong type");
+ if ((bf = pp->find_field(pp, 0, "LAB_B")) < 0)
+ error("Input file doesn't contain field LAB_B");
+ if (pp->t[0].ftype[bf] != r_t)
+ error("Field LAB_B is wrong type");
+
+ /* Write the vertexes out */
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation 0 0 0\n");
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ if (gds[n].in_rep == gam_wire) {
+ fprintf(wrl," geometry IndexedLineSet {\n");
+ } else {
+ fprintf(wrl," geometry IndexedFaceSet {\n");
+ fprintf(wrl," ccw FALSE\n");
+ fprintf(wrl," convex TRUE\n");
+ }
+ fprintf(wrl,"\n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [ # Verticy coordinates\n");
+
+ /* Spit out the point values, in order. */
+ /* Note that a->x, b->y, L->z */
+ for (i = 0; i < nverts; i++) {
+ double L, a, b;
+ L = *((double *)pp->t[0].fdata[i][Lf]);
+ a = *((double *)pp->t[0].fdata[i][af]);
+ b = *((double *)pp->t[0].fdata[i][bf]);
+ fprintf(wrl," %f %f %f,\n",a, b, L - GCENT);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+
+ /* Write the triangles/wires out */
+ if ((v0f = pp->find_field(pp, 1, "VERTEX_0")) < 0)
+ error("Input file doesn't contain field VERTEX_0");
+ if (pp->t[1].ftype[v0f] != i_t)
+ error("Field VERTEX_0 is wrong type");
+ if ((v1f = pp->find_field(pp, 1, "VERTEX_1")) < 0)
+ error("Input file doesn't contain field VERTEX_1");
+ if (pp->t[1].ftype[v1f] != i_t)
+ error("Field VERTEX_1 is wrong type");
+ if ((v2f = pp->find_field(pp, 1, "VERTEX_2")) < 0)
+ error("Input file doesn't contain field VERTEX_2");
+ if (pp->t[1].ftype[v2f] != i_t)
+ error("Field VERTEX_2 is wrong type");
+
+ fprintf(wrl," coordIndex [ # Indexes of poligon Verticies \n");
+
+ for (i = 0; i < ntris; i++) {
+ int v0, v1, v2;
+ v0 = *((int *)pp->t[1].fdata[i][v0f]);
+ v1 = *((int *)pp->t[1].fdata[i][v1f]);
+ v2 = *((int *)pp->t[1].fdata[i][v2f]);
+
+#ifdef HALF_HACK
+ if (*((double *)pp->t[0].fdata[v0][Lf]) < HALF_HACK
+ || *((double *)pp->t[0].fdata[v1][Lf]) < HALF_HACK
+ || *((double *)pp->t[0].fdata[v2][Lf]) < HALF_HACK)
+ continue;
+#endif /* HALF_HACK */
+
+ if (gds[n].in_rep == gam_wire) {
+ if (v0 < v1) /* Only output 1 wire of two on an edge */
+ fprintf(wrl," %d, %d, -1\n", v0, v1);
+ if (v1 < v2)
+ fprintf(wrl," %d, %d, -1\n", v1, v2);
+ if (v2 < v0)
+ fprintf(wrl," %d, %d, -1\n", v2, v0);
+ } else {
+ fprintf(wrl," %d, %d, %d, -1\n", v0, v1, v2);
+ }
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl,"\n");
+
+ /* Write the colors out */
+ if (gds[n].in_colors == gam_natural) {
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < nverts; i++) {
+ double rgb[3], Lab[3];
+ Lab[0] = *((double *)pp->t[0].fdata[i][Lf]);
+ Lab[1] = *((double *)pp->t[0].fdata[i][af]);
+ Lab[2] = *((double *)pp->t[0].fdata[i][bf]);
+ gamut_Lab2RGB(rgb, Lab);
+ fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ }
+ fprintf(wrl," }\n");
+ fprintf(wrl," appearance Appearance { \n");
+ fprintf(wrl," material Material {\n");
+ if (gds[n].in_trans > 0.0) {
+ fprintf(wrl," transparency %f\n", gds[n].in_trans);
+ }
+ fprintf(wrl," ambientIntensity 0.3\n");
+ fprintf(wrl," shininess 0.5\n");
+ if (gds[n].in_colors != gam_natural) {
+ fprintf(wrl," emissiveColor %f %f %f\n",
+ color_rgb[gds[n].in_colors].r, color_rgb[gds[n].in_colors].g, color_rgb[gds[n].in_colors].b);
+ }
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," } # end Shape\n");
+ fprintf(wrl," ] # end children\n");
+ fprintf(wrl," } # end Transform\n");
+ fprintf(wrl,"\n");
+
+ /* See if there are cusp values */
+ if (docusps) {
+ int kk;
+ double rgb[3], Lab[3];
+ char buf1[50];
+ char *cnames[6] = { "RED", "YELLOW", "GREEN", "CYAN", "BLUE", "MAGENTA" };
+
+ for (i = 0; i < 6; i++) {
+ sprintf(buf1,"CUSP_%s", cnames[i]);
+ if ((kk = pp->find_kword(pp, 0, buf1)) < 0)
+ break;
+
+ if (sscanf(pp->t[0].kdata[kk], "%lf %lf %lf",
+ &Lab[0], &Lab[1], &Lab[2]) != 3) {
+ break;
+ }
+
+ gamut_Lab2RGB(rgb, Lab);
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation %f %f %f\n",Lab[1], Lab[2], Lab[0]-GCENT);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry Sphere { radius 2.0 }\n");
+ fprintf(wrl," appearance Appearance { material Material {\n");
+ if (gds[n].in_trans > 0.0)
+ fprintf(wrl," transparency %f\n", gds[n].in_trans);
+ if (gds[n].in_colors != gam_natural)
+ fprintf(wrl," diffuseColor %f %f %f\n", color_rgb[gds[n].in_colors].r, color_rgb[gds[n].in_colors].g, color_rgb[gds[n].in_colors].b);
+ else
+ fprintf(wrl," diffuseColor %f %f %f\n", rgb[0], rgb[1], rgb[2]);
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+ fprintf(wrl,"\n");
+ }
+
+ pp->del(pp); /* Clean up */
+ }
+
+ /* Write the trailer */
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ /* Close the file */
+ fclose(wrl);
+
+ if (isect && ng >= 2) {
+ gamut *s, *s1, *s2;
+ double v1, v2, vi;
+
+ if ((s = new_gamut(0.0, 0, 0)) == NULL)
+ error("Creating gamut object failed");
+
+ if ((s1 = new_gamut(0.0, 0, 0)) == NULL)
+ error("Creating gamut object failed");
+
+ if ((s2 = new_gamut(0.0, 0, 0)) == NULL)
+ error("Creating gamut object failed");
+
+ if (s1->read_gam(s1, gds[0].in_name))
+ error("Input file '%s' read failed",gds[n].in_name[0]);
+
+ if (s2->read_gam(s2, gds[1].in_name))
+ error("Input file '%s' read failed",gds[n].in_name[1]);
+
+ v1 = s1->volume(s1);
+ v2 = s2->volume(s2);
+
+ if (s->intersect(s, s1, s2))
+ error("Gamuts are not compatible! (Colorspace, gamut center ?)");
+ vi = s->volume(s);
+
+ if (iout_name[0] != '\000') {
+ if (s->write_gam(s, iout_name))
+ error("Writing intersection gamut to '%s' failed",iout_name);
+ }
+
+ printf("Intersecting volume = %.1f cubic units\n",vi);
+ printf("'%s' volume = %.1f cubic units, intersect = %.2f%%\n",gds[0].in_name,v1,100.0 * vi/v1);
+ printf("'%s' volume = %.1f cubic units, intersect = %.2f%%\n",gds[1].in_name,v2,100.0 * vi/v2);
+
+ s1->del(s1);
+ s2->del(s2);
+ }
+
+ if (ng > 0)
+ free(gds);
+
+ return 0;
+}
+
+#ifdef NEVER
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icclu: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icclu: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#endif /* NEVER */
diff --git a/h/License.txt b/h/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/h/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/h/Makefile.am b/h/Makefile.am
new file mode 100644
index 0000000..7052ce4
--- /dev/null
+++ b/h/Makefile.am
@@ -0,0 +1,3 @@
+EXTRA_DIST = Readme.txt copyright.h config.h sort.h llist.h xlist.h \
+ counters.h
+
diff --git a/h/Readme.txt b/h/Readme.txt
new file mode 100644
index 0000000..fecc33a
--- /dev/null
+++ b/h/Readme.txt
@@ -0,0 +1 @@
+Copies of the include headers are installed here.
diff --git a/h/aconfig.h b/h/aconfig.h
new file mode 100644
index 0000000..0de524f
--- /dev/null
+++ b/h/aconfig.h
@@ -0,0 +1,29 @@
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+/* General project wide configuration */
+
+/* Version of Argyll release */
+/* Bug fix = 4 bits */
+/* minor number = 8 bits */
+/* major number = 8 bits */
+
+#define ARGYLL_VERSION 0x01051
+#define ARGYLL_VERSION_STR "1.5.1"
+
+/* Maximum file path length */
+#define MAXNAMEL 1024
+
+/* A simpler #define to remove __APPLE__ from non OS X code */
+#if defined(UNIX) && !defined(__APPLE__)
+# define UNIX_X11 /* Unix like using X11 */
+#else
+# undef UNIX_X11
+#endif
+
+#if defined(UNIX) && !defined(__APPLE__)
+#define USE_UCMM /* Enable the Unix micro CMM */
+#endif
+
+#endif /* __CONFIG_H__ */
diff --git a/h/afiles b/h/afiles
new file mode 100644
index 0000000..86572ca
--- /dev/null
+++ b/h/afiles
@@ -0,0 +1,9 @@
+Readme.txt
+License.txt
+afiles
+copyright.h
+aconfig.h
+sort.h
+llist.h
+xlist.h
+counters.h
diff --git a/h/copyright.h b/h/copyright.h
new file mode 100644
index 0000000..7dc880e
--- /dev/null
+++ b/h/copyright.h
@@ -0,0 +1,5 @@
+
+/* Embed a copyright string */
+static volatile char __copyright__[] = "Copyright 1995-2013 Graeme W. Gill";
+
+
diff --git a/h/counters.h b/h/counters.h
new file mode 100644
index 0000000..3a3e71c
--- /dev/null
+++ b/h/counters.h
@@ -0,0 +1,246 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional counter macros.
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/96
+ *
+ * Copyright 1996 - 2006, 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.
+ */
+
+#ifndef COUNTERS_H
+
+/* ------------------------------------------------------- */
+/* Macros for a multi-dimensional counter. */
+/* Declare the counter name nn, maximum di mxdi, dimensions di, & count */
+
+#define DCOUNT(nn, mxdi, di, start, reset, endp1) \
+ int nn[mxdi]; /* counter value */ \
+ int nn##_di = (di); /* Number of dimensions */ \
+ int nn##_stt = (start); /* start count value */ \
+ int nn##_rst = (reset); /* reset on carry value */ \
+ int nn##_res = (endp1); /* last count +1 */ \
+ int nn##_e /* dimension index */
+
+#define DRECONF(nn, start, reset, endp1) \
+ nn##_stt = (start); /* start count value */ \
+ nn##_rst = (reset); /* reset on carry value */ \
+ nn##_res = (endp1); /* last count +1 */
+
+/* Set the counter value to 0 */
+#define DC_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
+ nn[nn##_e] = nn##_stt; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define DC_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < nn##_res) \
+ break; /* No carry */ \
+ nn[nn##_e] = nn##_rst; \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define DC_DONE(nn) \
+ (nn##_e >= nn##_di)
+
+/* (Do we need a version of the above that tracks the actual input coords ?) */
+/* ------------------------------------------------------- */
+/* Similar to abovem but each dimension range can be clipped. */
+
+#define FCOUNT(nn, mxdi, di) \
+ int nn[mxdi]; /* counter value */ \
+ int nn##_di = (di); /* Number of dimensions */ \
+ int nn##_stt[mxdi]; /* start count value */ \
+ int nn##_res[mxdi]; /* last count +1 */ \
+ int nn##_e /* dimension index */
+
+#define FRECONF(nn, start, endp1) \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn##_stt[nn##_e] = (start); /* start count value */ \
+ nn##_res[nn##_e] = (endp1); /* last count +1 */ \
+ }
+
+/* Set the counter value to 0 */
+#define FC_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
+ nn[nn##_e] = nn##_stt[nn##_e]; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define FC_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < nn##_res[nn##_e]) \
+ break; /* No carry */ \
+ nn[nn##_e] = nn##_stt[nn##_e]; \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define FC_DONE(nn) \
+ (nn##_e >= nn##_di)
+
+/* ------------------------------------------------------- */
+/* Same as above, but allows for variable resolution on each axis. */
+/* End offset is added to count[] */
+
+#define ECOUNT(nn, mxdi, di, start, endp1, end_offst) \
+ int nn[mxdi]; /* counter value */ \
+ int nn##_di = (di); /* Number of dimensions */ \
+ int nn##_start = (start);/* Start value*/ \
+ int *nn##_res = (endp1);/* last count +1 */ \
+ int nn##_endo = (end_offst);/* Count offset */ \
+ int nn##_e /* dimension index */
+
+/* Set the counter value to start */
+#define EC_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
+ nn[nn##_e] = nn##_start; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define EC_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < (nn##_res[nn##_e] + nn##_endo)) \
+ break; /* No carry */ \
+ nn[nn##_e] = nn##_start; \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define EC_DONE(nn) \
+ (nn##_e >= nn##_di)
+
+/* (Do we need a version of the above that tracks the actual input coords ?) */
+
+/* ------------------------------------------------------- */
+/* Macros combination counter */
+/* Declare the counter name nn, combinations out of total */
+/* mxdi should be set to maximum combinations */
+
+#define COMBO(nn, mxdi, comb, total) \
+ int nn[mxdi+2]; /* counter value */ \
+ int nn##_cmb = (comb); /* number of combinations */ \
+ int nn##_tot = (total); /* out of total possible */ \
+ int nn##_e /* dimension index */
+
+/* Set total to new setting */
+#define CB_SETT(nn, total) \
+ nn##_tot = (total) /* total possible */
+
+/* Set combinations to new setting */
+#define CB_SETC(nn, comb) \
+ nn##_cmb = (comb) /* number of combinations*/
+
+/* Set the counter to its initial value */
+#define CB_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) \
+ nn[nn##_e] = nn##_cmb-nn##_e-1; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define CB_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < (nn##_tot-nn##_e)) { \
+ int nn##_ee; /* No carry */ \
+ for (nn##_ee = nn##_e-1; nn##_ee >= 0; nn##_ee--) \
+ nn[nn##_ee] = nn[nn##_ee+1] + 1; \
+ break; \
+ } \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define CB_DONE(nn) \
+ (nn##_e >= nn##_cmb)
+
+/* ------------------------------------------------------- */
+/* Macros simplex combination counter. */
+/* Based on COMBO, but skips invalid simplex combinations */
+
+#define XCOMBO(nn, mxdi, comb, total) \
+ COMBO(nn, mxdi, comb, total)
+
+/* Set total to new setting */
+#define XCB_SETT(nn, total) \
+ CB_SETT(nn, total)
+
+/* Set combinations to new setting */
+#define XCB_SETC(nn, comb) \
+ CB_SETC(nn, comb)
+
+
+/* Set the counter to its initial value */
+#define XCB_INIT(nn) \
+{ \
+ int nn##_ii; \
+ \
+ for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) \
+ nn[nn##_e] = nn##_cmb-nn##_e-1; \
+ for (nn##_ii = 1; nn##_ii < nn##_cmb; nn##_ii++) { \
+ if ((nn[nn##_ii-1] ^ nn[nn##_ii]) & nn[nn##_ii])\
+ break; /* Went from 0 to 1 */ \
+ } \
+ if (nn##_ii < nn##_cmb) { /* Fix invalid combination */ \
+ XCB_INC(nn); \
+ } \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define XCB_INC(nn) \
+{ \
+ int nn##_ii = 0; \
+ \
+ while (nn##_ii < nn##_cmb) { \
+ for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < (nn##_tot-nn##_e)) { \
+ int nn##_ee; /* No carry */ \
+ for (nn##_ee = nn##_e-1; nn##_ee >= 0; nn##_ee--) \
+ nn[nn##_ee] = nn[nn##_ee+1] + 1; \
+ break; \
+ } \
+ } \
+ if (nn##_e >= nn##_cmb) \
+ break; /* Done */ \
+ \
+ /* Reject invalid combinations */ \
+ for (nn##_ii = 1; nn##_ii < nn##_cmb; nn##_ii++) { \
+ if ((nn[nn##_ii-1] ^ nn[nn##_ii]) & nn[nn##_ii]) \
+ break; /* Went from 0 to 1 */ \
+ } \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define XCB_DONE(nn) \
+ CB_DONE(nn)
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#define COUNTERS_H
+#endif /* COUNTERS_H */
diff --git a/h/llist.h b/h/llist.h
new file mode 100644
index 0000000..1af31bf
--- /dev/null
+++ b/h/llist.h
@@ -0,0 +1,92 @@
+/* A set of linked list utilities, implimented as macros. */
+/* Copyright 1995, 2000 Graeme W. Gill */
+
+#ifndef _LLIST_H_
+
+/* A link list structure */
+#define LINKSTRUCT(obj) \
+struct { \
+ obj *fwd; /* Forward link */ \
+ obj *bwd; /* Backwards link */ \
+} _llistp
+
+/* Initialize the linked list */
+#define INIT_LIST(head) \
+ ((head) = NULL)
+
+/* test if the list is empty */
+#define IS_LIST_EMPTY(head) \
+ ((head) == NULL)
+
+/* Add an item to the top of a list */
+#define ADD_ITEM_TO_TOP(head,objp) \
+ (IS_LIST_EMPTY(head) ? (INIT_LINK(objp), (head) = objp) : \
+ (ADD_LINK_BWD((head),(objp)), (head) = objp))
+
+/* Add an item to the bottom of a list */
+#define ADD_ITEM_TO_BOT(head,objp) \
+ (IS_LIST_EMPTY(head) ? (INIT_LINK(objp), (head) = objp) : \
+ (ADD_LINK_BWD((head),(objp))))
+
+/* Insert a new item forward of the old one in linked list */
+#define ADD_LINK_FWD(oob,nob) \
+ ((nob)->_llistp.fwd = (oob)->_llistp.fwd, \
+ (nob)->_llistp.bwd = (oob), \
+ (oob)->_llistp.fwd->_llistp.bwd = (nob), \
+ (oob)->_llistp.fwd = (nob))
+
+/* Insert a new item backward of the old one in linked list */
+#define ADD_LINK_BWD(oob,nob) \
+ ((nob)->_llistp.bwd = (oob)->_llistp.bwd, \
+ (nob)->_llistp.fwd = (oob), \
+ (oob)->_llistp.bwd->_llistp.fwd = (nob), \
+ (oob)->_llistp.bwd = (nob))
+
+/* Delete an object from the list. */
+#define DEL_LINK(head,objp) \
+ (IS_ONE_ITEM(objp) ? (head) = NULL : \
+ ((objp) == (head) ? (head) = (head)->_llistp.fwd : 0, \
+ (objp)->_llistp.fwd->_llistp.bwd = (objp)->_llistp.bwd, \
+ (objp)->_llistp.bwd->_llistp.fwd = (objp)->_llistp.fwd, \
+ (objp)->_llistp.fwd = (objp)->_llistp.bwd = (objp)))
+
+/* Combine two linked lists. Doesn't fix parent/child stuff */
+/* Breaks lists backward of oob, and forward of nob */
+#define MERGE_LINK(oob,nob) \
+ (((nob)->_llistp.fwd)->_llistp.bwd = (oob)->_llistp.bwd, \
+ ((oob)->_llistp.bwd)->_llistp.fwd = (nob)->_llistp.fwd, \
+ (nob)->_llistp.fwd = (oob), \
+ (oob)->_llistp.bwd = (nob))
+
+
+/* Scan through all of the items in a linked list */
+/* (Robust version, copes with deleting the items) */
+#define FOR_ALL_ITEMS(objtype, objp) \
+ if (objp != NULL) \
+ { \
+ objtype *_end, *_next; \
+ _end = objp->_llistp.bwd; \
+ _next = objp->_llistp.fwd; \
+ do {
+
+#define END_FOR_ALL_ITEMS(objp) \
+ } while (objp == _end ? 0 : \
+ (objp = _next, _next = objp->_llistp.fwd, 1)); \
+ }
+
+#define NEXT_FWD(objp) \
+ (objp == NULL ? NULL : objp->_llistp.fwd)
+
+/* ----------------------------- */
+
+/* initialise a list to have only one entry */
+#define INIT_LINK(objp) \
+ ((objp)->_llistp.fwd = (objp)->_llistp.bwd = (objp))
+
+/* test if the given object is the only one */
+#define IS_ONE_ITEM(objp) \
+ ((objp) == (objp)->_llistp.fwd)
+
+#define _LLIST_H_
+#endif /* _LLIST_H_ */
+
diff --git a/h/sort.h b/h/sort.h
new file mode 100644
index 0000000..98bee8f
--- /dev/null
+++ b/h/sort.h
@@ -0,0 +1,62 @@
+
+/*
+ * Copyright 1996 - 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ * Heapsort macro - sort smallest to largest.
+ * Heapsort is guaranteed nlogn, doesn't need any
+ * extra storage, but often isn't as fast as quicksort.
+ */
+
+/* Need to #define HEAP_COMPARE(A,B) so it returns true if A < B */
+/* Note that A will be ARRAY[a], and B will be ARRAY[b] where a and b are indexes. */
+/* TYPE should be the type of each entry of the ARRAY */
+#define HEAPSORT(TYPE,ARRAY,NUMBER) \
+ { \
+ TYPE *hs_ncb = ARRAY; \
+ int hs_l,hs_j,hs_ir,hs_i; \
+ TYPE hs_rra; \
+ \
+ if (NUMBER >= 2) \
+ { \
+ hs_l = NUMBER >> 1; \
+ hs_ir = NUMBER-1; \
+ for (;;) \
+ { \
+ if (hs_l > 0) \
+ hs_rra = hs_ncb[--hs_l]; \
+ else \
+ { \
+ hs_rra = hs_ncb[hs_ir]; \
+ hs_ncb[hs_ir] = hs_ncb[0]; \
+ if (--hs_ir == 0) \
+ { \
+ hs_ncb[0] = hs_rra; \
+ break; \
+ } \
+ } \
+ hs_i = hs_l; \
+ hs_j = hs_l+hs_l+1; \
+ while (hs_j <= hs_ir) \
+ { \
+ if (hs_j < hs_ir && HEAP_COMPARE(hs_ncb[hs_j],hs_ncb[hs_j+1])) \
+ hs_j++; \
+ if (HEAP_COMPARE(hs_rra,hs_ncb[hs_j])) \
+ { \
+ hs_ncb[hs_i] = hs_ncb[hs_j]; \
+ hs_i = hs_j; \
+ hs_j = hs_j+hs_j+1; \
+ } \
+ else \
+ hs_j = hs_ir + 1; \
+ } \
+ hs_ncb[hs_i] = hs_rra; \
+ } \
+ } \
+ }
+
diff --git a/h/xlist.h b/h/xlist.h
new file mode 100644
index 0000000..dc03019
--- /dev/null
+++ b/h/xlist.h
@@ -0,0 +1,56 @@
+/* A set of expandable list utilities, implimented as macros. */
+/* Copyright 2006 Graeme W. Gill */
+
+#ifndef _XLIST_H_
+
+/* An expanding list structure */
+#define XLIST(objtype, name) \
+struct { \
+ int no; /* Number of items in list */ \
+ int _no; /* Allocated size of list */ \
+ int objsz; /* Size of object */ \
+ objtype *list; /* list */ \
+} name;
+
+/* Initialize the list */
+#define XLIST_INIT(objtype, xlp) \
+ ((xlp)->no = (xlp)->_no = 0, \
+ (xlp)->objsz = sizeof(objtype), \
+ (xlp)->list = NULL \
+ )
+
+/* test if the list is empty */
+#define IS_XLIST_EMPTY(xlp) \
+ ((xlp)->no == 0)
+
+/* Return the number of items in the list */
+#define XLIST_NO(xlp) \
+ ((xlp)->no)
+
+/* Return the n'th item in the list */
+#define XLIST_ITEM(xlp, n) \
+ ((xlp)->list[n])
+
+/* Add an item to the end of a list */
+/* We call error() if malloc failes */
+#define XLIST_ADD(xlp, obj) \
+ { \
+ if ((xlp)->_no <= 0) { \
+ (xlp)->_no = 10; \
+ if (((xlp)->list = malloc((xlp)->objsz * (xlp)->_no)) == NULL) \
+ error("XLIST malloc failed on %d items of size %d", (xlp)->objsz, (xlp)->_no); \
+ } else if ((xlp)->_no <= (xlp)->no) { \
+ (xlp)->_no *= 2; \
+ if (((xlp)->list = realloc((xlp)->list, (xlp)->objsz * (xlp)->_no)) == NULL) \
+ error("XLIST realloc failed on %d items of size %d", (xlp)->objsz, (xlp)->_no); \
+ } \
+ (xlp)->list[(xlp)->no++] = (obj); \
+ }
+
+/* Free up the list */
+#define XLIST_FREE(xlp) \
+ { if ((xlp)->_no > 0) free((xlp)->list); }
+
+#define _XLIST_H_
+#endif /* _XLIST_H_ */
+
diff --git a/icc/ClayRGB1998.icm b/icc/ClayRGB1998.icm
new file mode 100644
index 0000000..1eedf09
--- /dev/null
+++ b/icc/ClayRGB1998.icm
Binary files differ
diff --git a/icc/Jamfile b/icc/Jamfile
new file mode 100644
index 0000000..abbeddb
--- /dev/null
+++ b/icc/Jamfile
@@ -0,0 +1,58 @@
+
+# JAM style makefile for icclib and friends
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags
+
+#if stdio is not wanted in icclib:
+#DEFINES = SEPARATE_STD ;
+
+#Products
+Libraries = libicc ;
+Executables = iccdump icclu ;
+Headers = icc.h ;
+Samples = sRGB.icm ClayRGB1998.icm lab2lab.icm ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+InstallFile $(DESTDIR)$(PREFIX)/$(REFSUBDIR) : $(Samples) ;
+
+# ICC library
+Library libicc : icc.c ;
+
+# Executable support if SEPARATED_STD
+if SEPARATE_STD in $(DEFINES) {
+ Objects iccstd.c ;
+ LINKOBJS = iccstd ; # Link all utilities here with iccstd
+}
+
+# Link all utilities here with libicc
+LINKLIBS = libicc ;
+
+# All utils are made from a single source file
+MainsFromSources icctest.c lutest.c iccdump.c icclu.c iccrw.c ;
+
+if $(BUILD_JUNK) {
+
+# MainsFromSources tt.c ;
+
+ MainsFromSources mksRGB.c ;
+ MainsFromSources mkAdobeRGB.c ;
+ MainsFromSources mklab2lab.c ;
+# MainsFromSources icm2ary.c ;
+
+ # Check library is compatible with C++
+ Main cppcheck : cppcheck.cpp ;
+
+ # chech CIEDE2000
+ MainsFromSources testDE2K.c ;
+
+ #Monotonic behaviour checker
+ MainsFromSources mcheck.c ;
+}
+
+
diff --git a/icc/License.txt b/icc/License.txt
new file mode 100644
index 0000000..9de79da
--- /dev/null
+++ b/icc/License.txt
@@ -0,0 +1,22 @@
+*************************************************************************
+Copyright (c) 1997-2009 Graeme W. Gill
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+*************************************************************************
diff --git a/icc/Makefile b/icc/Makefile
new file mode 100644
index 0000000..dbb9992
--- /dev/null
+++ b/icc/Makefile
@@ -0,0 +1,82 @@
+# UNIX style makefile, for icclib and friends.
+# "include" the right environment for your system,
+# by uncommenting the appropriate line:
+
+# Microsoft C++, WinNT setup
+include Makefile.WNT
+
+# IBM C++, WinNT setup
+#include Makefile.IBMNT
+
+# Generic UNIX setup
+#include Makefile.UNIX
+
+# Apple OSX
+#include Makefile.OSX
+
+###############################
+
+#Compile with separate stdio
+#CCDEFINES = $(DEFFLAG)SEPARATE_STD
+
+#Set optimisation on
+CCFLAGS = $(CCFLAGSDEF) $(CCOPTFLAG) $(CCDEFINES)
+
+#Set debugging on
+#CCFLAGS = $(CCFLAGSDEF) $(CCDEBUGFLAG) $(CCDEFINES)
+
+STDHDRS = $(STDHDRSDEF)
+LINKFLAGS = $(LINKFLAGSDEF) $(LINKDEBUGFLAG)
+
+all:: libicc$(SUFLIB) icctest$(SUFEXE) lutest$(SUFEXE) icclu$(SUFEXE) iccdump$(SUFEXE) iccrw$(SUFEXE)
+
+
+icc$(SUFOBJ): icc.c icc.h
+ $(CC) $(CCOF)icc$(SUFOBJ) icc.c
+
+libicc$(SUFLIB): icc$(SUFOBJ)
+ $(LIBU) $(LIBOF)libicc$(SUFLIB) icc$(SUFOBJ)
+ $(RANLIB) libicc$(SUFLIB)
+
+
+# Separate for executables
+iccstd$(SUFOBJ): iccstd.c icc.h
+ $(CC) $(CCOF)iccstd$(SUFOBJ) iccstd.c
+
+
+icctest$(SUFOBJ): icctest.c icc.h
+ $(CC) $(CCOF)icctest$(SUFOBJ) icctest.c
+
+icctest$(SUFEXE): icctest$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+ $(LINK) $(LINKOF)icctest$(SUFEXE) icctest$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+
+
+lutest$(SUFOBJ): lutest.c icc.h
+ $(CC) $(CCOF)lutest$(SUFOBJ) lutest.c
+
+lutest$(SUFEXE): lutest$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+ $(LINK) $(LINKOF)lutest$(SUFEXE) lutest$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+
+
+icclu$(SUFOBJ): icclu.c icc.h
+ $(CC) $(CCOF)icclu$(SUFOBJ) icclu.c
+
+icclu$(SUFEXE): icclu$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+ $(LINK) $(LINKOF)icclu$(SUFEXE) icclu$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+
+
+iccdump$(SUFOBJ): iccdump.c icc.h
+ $(CC) $(CCOF)iccdump$(SUFOBJ) iccdump.c
+
+iccdump$(SUFEXE): iccdump$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+ $(LINK) $(LINKOF)iccdump$(SUFEXE) iccdump$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+
+
+iccrw$(SUFOBJ): iccrw.c icc.h
+ $(CC) $(CCOF)iccrw$(SUFOBJ) iccrw.c
+
+iccrw$(SUFEXE): iccrw$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+ $(LINK) $(LINKOF)iccrw$(SUFEXE) iccrw$(SUFOBJ) iccstd$(SUFOBJ) libicc$(SUFLIB)
+
+
+
diff --git a/icc/Makefile.IBMNT b/icc/Makefile.IBMNT
new file mode 100644
index 0000000..26a2bd2
--- /dev/null
+++ b/icc/Makefile.IBMNT
@@ -0,0 +1,41 @@
+# IBM C++, WinNT setup
+
+SLASH = \
+SUFLIB = .lib
+SUFOBJ = .obj
+SUFEXE = .exe
+CMDSEP = &
+
+INCFLAG = /I
+DEFFLAG = /D
+UNDEFFLAG = "/U _"
+CCOPTFLAG = /O+ /qtune=pentiumpro
+CCDEBUGFLAG = /Ti+ /O- /Oi- /DEbug
+CCPROFFLAG = /Ti+ /Gh+
+LINKDEBUGFLAG = /DEbug
+LINKPROFFLAG = /DE /NOE cppwpa3.obj
+
+STDHDRSDEF = $(IPF_PATH32)\\include $(IPF_PATH32)\\sdk\\winh
+
+MAKEU = nmake
+LIBU = ilib /Q
+LIBOF = /OUT:
+RANLIB = rem
+AS = masm386
+CCFLAGSDEF = /DNT /c
+CC = icc /Q $(CCFLAGS) $(INCFLAG)$(STDHDRS)
+CCOF = /Fo
+LINKLIBS = $(IPF_PATH32)\\sdk\\lib\\*.lib
+LINKFLAGSDEF =
+LINK = ilink /NOLogo $(LINKFLAGS)
+LINKOF = /OUT:
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
+
+
+
diff --git a/icc/Makefile.OSX b/icc/Makefile.OSX
new file mode 100644
index 0000000..fb1c88f
--- /dev/null
+++ b/icc/Makefile.OSX
@@ -0,0 +1,38 @@
+# MAC OSX, derived from UNIX setup
+
+SLASH = /
+SUFLIB = .a
+SUFOBJ = .o
+SUFEXE =
+CMDSEP = ;
+
+INCFLAG = -I
+DEFFLAG = -D
+UNDEFFLAG = "-u _"
+CCOPTFLAG = -O
+CCDEBUGFLAG = -g
+CCPROFFLAG =
+LINKDEBUGFLAG =
+LINKPROFFLAG =
+
+STDHDRSDEF = /usr/include
+
+MAKEU = make
+LIBU = ar -r
+LIBOF =
+RANLIB = ranlib
+AS = as
+CCFLAGSDEF = -DUNIX -c
+CC = cc $(CCFLAGS) $(INCFLAG)$(STDHDRS)
+CCOF = -o
+LINKFLAGSDEF = -lm
+LINKLIBS =
+LINK = cc $(LINKFLAGS) $(LINKLIBS)
+LINKOF = -o
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/icc/Makefile.UNIX b/icc/Makefile.UNIX
new file mode 100644
index 0000000..91d6005
--- /dev/null
+++ b/icc/Makefile.UNIX
@@ -0,0 +1,38 @@
+# Generic UNIX setup
+
+SLASH = /
+SUFLIB = .a
+SUFOBJ = .o
+SUFEXE =
+CMDSEP = ;
+
+INCFLAG = -I
+DEFFLAG = -D
+UNDEFFLAG = "-u _"
+CCOPTFLAG = -O
+CCDEBUGFLAG = -g
+CCPROFFLAG =
+LINKDEBUGFLAG =
+LINKPROFFLAG =
+
+STDHDRSDEF = /usr/include
+
+MAKEU = make
+LIBU = ar -r
+LIBOF = -o
+RANLIB = echo
+AS = as
+CCFLAGSDEF = -DUNIX -c
+CC = cc $(CCFLAGS) $(INCFLAG)$(STDHDRS)
+CCOF = -o
+LINKFLAGSDEF = -lm
+LINKLIBS =
+LINK = cc $(LINKFLAGS) $(LINKLIBS)
+LINKOF = -o
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/icc/Makefile.WNT b/icc/Makefile.WNT
new file mode 100644
index 0000000..4ca291d
--- /dev/null
+++ b/icc/Makefile.WNT
@@ -0,0 +1,38 @@
+# Microsoft C++, WinNT setup
+
+SLASH = \
+SUFLIB = .lib
+SUFOBJ = .obj
+SUFEXE = .exe
+CMDSEP = &
+
+INCFLAG = /I
+DEFFLAG = /D
+UNDEFFLAG = "/u _"
+CCOPTFLAG = /Ox /GB
+CCDEBUGFLAG = /Z7 /Od
+CCPROFFLAG = /Z7
+LINKDEBUGFLAG = /DEBUG
+LINKPROFFLAG = /PROFILE
+
+STDHDRSDEF = $(MSVCNT)\include
+
+MAKEU = nmake
+LIBU = lib
+LIBOF = /OUT:
+RANLIB = rem
+AS = masm386
+CCFLAGSDEF = /DNT /c
+CC = cl /nologo $(CCFLAGS) $(INCFLAG)$(STDHDRS)
+CCOF = /Fo
+LINKLIBS = $(MSVCNT)/lib/user32.lib $(MSVCNT)/lib/gdi32.lib
+LINKFLAGSDEF = /link /INCREMENTAL:NO
+LINK = link $(LINKFLAGS)
+LINKOF = /OUT:
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/icc/Makefile.am b/icc/Makefile.am
new file mode 100644
index 0000000..a9ae092
--- /dev/null
+++ b/icc/Makefile.am
@@ -0,0 +1,22 @@
+include $(top_srcdir)/Makefile.shared
+
+LIBICC_VERSION=2.12
+
+lib_LTLIBRARIES = libicc.la
+
+libicc_la_SOURCES = icc.h iccV42.h icc.c iccstd.c
+libicc_la_LDFLAGS = -version-number $(shell echo $(LIBICC_VERSION) | tr . :):0
+
+include_HEADERS = icc.h iccV42.h
+
+LDADD = libicc.la
+
+bin_PROGRAMS = iccdump icclu
+
+check_PROGRAMS = icctest iccrw lutest
+
+refdir = $(datadir)/color/argyll/ref
+
+ref_DATA = $(wildcard *.icm)
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/icc/Readme.txt b/icc/Readme.txt
new file mode 100644
index 0000000..0ec425e
--- /dev/null
+++ b/icc/Readme.txt
@@ -0,0 +1,150 @@
+ICC profile I/O library (icclib), README file
+---------------------------------------------
+
+This version is part of Argyll V 1.50
+
+-------------------------------------------
+
+Date 22 September 2012, Version 2.14
+
+This distribution contains source code which implements the reading and
+writing of color profile files that conform to the International Color
+Consortium (ICC) Profile Format Specification, Version 3.4.
+
+For more information about the ICC, and for copies of the specification,
+please refer to <http://www.color.org/>
+
+(Note that this software is written from the ICC V3.4 standard, but the
+software and its author are not affiliated with, or otherwise connected
+with the ICC.)
+
+The ICC profile I/O library archive is kept at <http://www.argyllcms.com/>
+
+Motivation
+
+Color is still very much a black art to many programmers dealing with
+computer graphics. The ICC Profile Format is an industry attempt to provide
+an interchange format to help solve the problems of specifying color, and
+in transferring color graphics from, and between systems and devices.
+Although the ICC format has been around a number of years, and has long
+been adopted by companies in the business of providing systems for
+publishing and printing, and is now widely used as part of commercial
+operating system support for device independent color, its uptake in the
+general world of computer graphics has been slow.
+
+The writing of this library was prompted by my private and professional
+enthusiasm for computer graphics, and color. Inspired by other examples of
+freely usable software (notably the Independent JPEG Group's free JPEG
+software, and Sam Leffler's TIFF library), I have decided to make this
+library available under similar terms. I hope that this library will
+provide a starting point for including ICC profile support more widely that
+is currently the case, particularly in open source code projects.
+
+Overview
+
+This package contains a C software implementation of the ICC Profile
+Format, Version 3.4. The ICC Profile Format attempts to provide a
+cross-platform device profile format, that can be used to translate color
+data created on one device into another device's native color space. For a
+fuller explanation of what the ICC Profile Format is all about, please
+refer to http://www.color.org, and the profile specification.
+
+In summary this library provides:
+
+ * Full source code, free for commercial and non-commercial use.
+ * Support for all version 3.4 header elements, Tags and Tag Types.
+ * Conversion to/from machine native representation of all data
+ types.
+ * Support for user defined Tags.
+ * Support for adding/deleting Tags.
+ * Support for Tag type sharing within a file (often used for
+ sharing LUTs amongst intents).
+ * Support for reading/writing embedded profiles, including from/to
+ a memory buffer, rather than a file.
+ * Provides a single function for transforming color values through
+ a profile, including support for intents, forward and reverse
+ transforms, gamut lookup or preview lookup.
+ * Provides support and code examples for creating all profile
+ types, monochrome, matrix and Lut.
+ * Attempts to be platform neutral, and flexibility in its use of
+ system file and memory sub-systems.
+ * Loads Tag Types on demand to conserve memory space.
+
+Changes from V2.11
+
+Many changes have been made to support ArgyllCMS.
+A double memory free bug when iccdump'ing a profile
+that has duplicate tags has been fixed.
+
+Package contents:
+
+ icclib.zip ZIP archive of the following files
+ README.txt This file.
+ License.txt Important! - Permissions for use of this package.
+ icc.c Library source file.
+ iccstd.c Library source that uses stdio and malloc system calls.
+
+ icc.h Library include file. Note machine dependent defines.
+ Includes iccV42.h.
+ iccV42.h Standard ICC header file modified up to Version 4.2 spec.
+ iccdump.c Program that dumps ASCII description of a profile.
+
+ icclu.c Program that allows interactive or batch translation of
+ color values though a profile.
+
+ icctest.c Basic library tag Read/Write example and regression test
+ code.
+
+ lutest.c Color lookup regression test code, and example for creating
+ color profiles.
+
+ iccrw.c Source code skeleton for reading and then re-writing a
+ profile.
+
+ Jamfile JAM style "makefile" see
+ http://www.perforce.com/jam/jam.html
+
+ Makefile Generic style makefile. Edit this to select the appropriate
+ system makefile rules.
+ Makefile.IBMNTMakefile ruleset for Windows NT using the IBM compiler.
+ Makefile.OSX Makefile ruleset for Mac OSX environment.
+ Makefile.UNIX Makefile ruleset for Linux style environment.
+
+ Makefile.WNT Makefile ruleset for Windows NT using the Microsoft Visual
+ C++ compiler.
+
+Style
+
+For handling convenience, I have included all the library source code in
+two files. The down side is that they are both hard to read and navigate
+through. The code could do with some cleaning up and rearrangement, to make
+clear the distinction between public and private elements. (C++ would help
+here, but is less portable.) The code attempts to be ANSI C compliant,
+written in an object oriented style. A tutorial on how to use the library
+would also be a good thing !
+
+The best way to learn how to use the library, is to take a look at
+icctest.c, lutest.c and iccrw.c. The first is used to test writing and
+reading to every type of element, with every possible variation of usage.
+You will need a copy of the ICC spec. handy to understand what it all
+means. The second source file specifically creates and then tests various
+types of profiles, including monochrome, matrix and Lut style profiles. The
+last is a source code skeleton, that reads a profile completely into
+memory, and then writes it out again to a different file.
+
+With the release of version 2.00 of icclib, the library is now as useful as
+it is likely to be, allowing convenient color conversion between PCS
+(profile connection spaces, either XYZ or Lab) and device specific color
+spaces. The library does not attempt to be a complete color management
+system however, lacking profile creation and linking functionality. Icclib
+is part of the Argyll CMS, which does attempt to be a complete color
+management system. Argyll can be used as a more realistic example of the
+use of icclib. I plan at some stage to upgrade icclib to be compatible with
+the recently released ICC V4 spec., but will probably get around to this
+sometime after the next major release of Argyll.
+
+I welcome feedback, positive or negative, so please mail me at
+
+ Graeme at argyllcms dot com
+
+Graeme Gill
diff --git a/icc/afiles b/icc/afiles
new file mode 100644
index 0000000..7df3ba5
--- /dev/null
+++ b/icc/afiles
@@ -0,0 +1,26 @@
+Readme.txt
+License.txt
+todo.txt
+log.txt
+Jamfile
+Makefile
+Makefile.WNT
+Makefile.IBMNT
+Makefile.UNIX
+Makefile.OSX
+afiles
+icc.c
+iccstd.c
+icc.h
+iccV42.h
+iccdump.c
+icclu.c
+iccrw.c
+icctest.c
+lutest.c
+mcheck.c
+testDE2K.c
+makezip.ksh
+sRGB.icm
+ClayRGB1998.icm
+lab2lab.icm
diff --git a/icc/icc.c b/icc/icc.c
new file mode 100644
index 0000000..95dc0e9
--- /dev/null
+++ b/icc/icc.c
@@ -0,0 +1,17838 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * For ICC profile version 3.4
+ *
+ * Author: Graeme W. Gill
+ * Date: 2002/04/22
+ * Version: 2.15
+ *
+ * Copyright 1997 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/*
+ * TTBD:
+ *
+ * Add a "warning mode" to file reading, in which file format
+ * errors are ignored where possible, rather than generating
+ * a fatal error (see ICM_STRICT #define).
+ *
+ * NameColor Dump doesn't handle device space correctly -
+ * should use appropriate interpretation in case device is Lab etc.
+ *
+ * Should recognise & honour unicode 0xFFFE endian marker.
+ * Should generate it on writing too ?
+ *
+ * Add support for copying tags from one icc to another.
+ *
+ * Should fix all write_number failure errors to indicate failed value.
+ * (Partially implemented - need to check all write_number functions)
+ *
+ * Make write fail error messages be specific on which element failed.
+ *
+ * Should add named color space lookup function support.
+ *
+ * Would be nice to add generic ability to add new tag type handling,
+ * so that the base library doesn't need to be modified (ie. VideoCardGamma) ?
+ *
+ * Need to add DeviceSettings and OutputResponse tags to bring up to
+ * ICC.1:1998-09 [started but not complete]
+ *
+ */
+
+#undef ICM_STRICT /* Not fully implimented - switch off strict checking of file format */
+
+/* Make the default grid points of the Lab clut be symetrical about */
+/* a/b 0.0, and also make L = 100.0 fall on a grid point. */
+#define SYMETRICAL_DEFAULT_LAB_RANGE
+
+#define _ICC_C_ /* Turn on implimentation code */
+
+#undef DEBUG_SETLUT /* Show each value being set in setting lut contents */
+#undef DEBUG_SETLUT_CLIP /* Show clipped values when setting LUT */
+#undef DEBUG_LULUT /* Show each value being looked up from lut contents */
+#undef DEBUG_LLULUT /* Debug individual lookup steps (not fully implemented) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <time.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "icc.h"
+
+#ifdef _MSC_VER
+#define vsnprintf _vsnprintf
+#define snprintf _snprintf
+#endif
+
+/* ========================================================== */
+/* Default system interface object implementations */
+
+#ifndef SEPARATE_STD
+#define COMBINED_STD
+
+#include "iccstd.c"
+
+#undef COMBINED_STD
+#endif /* SEPARATE_STD */
+
+/* Forced byte alignment for tag table and tags */
+#define ALIGN_SIZE 4
+
+/* =========================================================== */
+
+#ifdef DEBUG_SETLUT
+#undef DBGSL
+#define DBGSL(xxx) printf xxx ;
+#else
+#undef DBGSL
+#define DBGSL(xxx)
+#endif
+
+#if defined(DEBUG_SETLUT) || defined(DEBUG_SETLUT_CLIP)
+#undef DBGSLC
+#define DBGSLC(xxx) printf xxx ;
+#else
+#undef DBGSLC
+#define DBGSLC(xxx)
+#endif
+
+#ifdef DEBUG_LULUT
+#undef DBGLL
+#define DBGLL(xxx) printf xxx ;
+#else
+#undef DBGLL
+#define DBGLL(xxx)
+#endif
+
+#ifdef DEBUG_LLULUT
+#undef DBLLL
+#define DBLLL(xxx) printf xxx ;
+#else
+#undef DBLLL
+#define DBLLL(xxx)
+#endif
+
+/* =========================================================== */
+/* Overflow protected unsigned int arithmatic functions. */
+/* These functions saturate rather than wrapping around. */
+/* (Divide doesn't need protection) */
+/* They return UINT_MAX if there was an overflow */
+
+/* a + b */
+static unsigned int sat_add(unsigned int a, unsigned int b) {
+ if (b > (UINT_MAX - a))
+ return UINT_MAX;
+ return a + b;
+}
+
+/* a - b */
+static unsigned int sat_sub(unsigned int a, unsigned int b) {
+ if (a < b)
+ return UINT_MAX;
+ return a - b;
+}
+
+/* a * b */
+static unsigned int sat_mul(unsigned int a, unsigned int b) {
+ unsigned int c;
+
+ if (a == 0 || b == 0)
+ return 0;
+
+ if (a > (UINT_MAX/b))
+ return UINT_MAX;
+ else
+ return a * b;
+}
+
+/* A + B + C */
+#define sat_addadd(A, B, C) sat_add(A, sat_add(B, C))
+
+/* A + B * C */
+#define sat_addmul(A, B, C) sat_add(A, sat_mul(B, C))
+
+/* A + B + C * D */
+#define sat_addaddmul(A, B, C, D) sat_add(A, sat_add(B, sat_mul(C, D)))
+
+/* A * B * C */
+#define sat_mul3(A, B, C) sat_mul(A, sat_mul(B, C))
+
+/* a ^ b */
+static unsigned int sat_pow(unsigned int a, unsigned int b) {
+ unsigned int c = 1;
+ for (; b > 0; b--) {
+ c = sat_mul(c, a);
+ if (c == UINT_MAX)
+ break;
+ }
+ return c;
+}
+
+/* Alignment */
+static unsigned int sat_align(unsigned int align_size, unsigned int a) {
+ align_size--;
+
+ if (align_size > (UINT_MAX - a))
+ return UINT_MAX;
+
+ return (a + align_size) & ~align_size;
+}
+
+/* These test functions detect whether an overflow would occur */
+
+/* Return nz if add would overflow */
+static int ovr_add(unsigned int a, unsigned int b) {
+
+ if (b > (UINT_MAX - a))
+ return 1;
+ return 0;
+}
+
+/* Return nz if sub would overflow */
+static int ovr_sub(unsigned int a, unsigned int b) {
+ if (a < b)
+ return 1;
+ return 0;
+}
+
+/* Return nz if mult would overflow */
+static int ovr_mul(unsigned int a, unsigned int b) {
+ if (a > (UINT_MAX/b))
+ return 1;
+ return 0;
+}
+
+
+/* size_t versions of saturating arithmatic */
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t)(-1))
+#endif
+
+/* a + b */
+static size_t ssat_add(size_t a, size_t b) {
+ if (b > (SIZE_MAX - a))
+ return SIZE_MAX;
+ return a + b;
+}
+
+/* a - b */
+static size_t ssat_sub(size_t a, size_t b) {
+ if (a < b)
+ return SIZE_MAX;
+ return a - b;
+}
+
+/* a * b */
+static size_t ssat_mul(size_t a, size_t b) {
+ size_t c;
+
+ if (a == 0 || b == 0)
+ return 0;
+
+ if (a > (SIZE_MAX/b))
+ return SIZE_MAX;
+ else
+ return a * b;
+}
+
+/* ------------------------------------------------- */
+/* Memory image icmFile compatible class */
+/* Buffer is assumed to have been allocated by the given allocator, */
+/* and will be expanded on write. */
+
+/* Get the size of the file */
+static size_t icmFileMem_get_size(icmFile *pp) {
+ icmFileMem *p = (icmFileMem *)pp;
+
+ return p->end - p->start;
+}
+
+/* Set current position to offset. Return 0 on success, nz on failure. */
+static int icmFileMem_seek(
+icmFile *pp,
+unsigned int offset
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ unsigned char *np;
+
+ np = p->start + offset;
+ if (np < p->start || np >= p->end)
+ return 1;
+ p->cur = np;
+ return 0;
+}
+
+/* Read count items of size length. Return number of items successfully read. */
+static size_t icmFileMem_read(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ size_t len;
+
+ len = ssat_mul(size, count);
+ if (len > (p->end - p->cur)) { /* Too much */
+ if (size > 0)
+ count = (p->end - p->cur)/size;
+ else
+ count = 0;
+ }
+ len = size * count;
+ if (len > 0)
+ memmove(buffer, p->cur, len);
+ p->cur += len;
+ return count;
+}
+
+/* Expand the memory buffer file to hold up to pointer ep */
+/* Don't expand if realloc fails */
+static void icmFileMem_filemem_resize(icmFileMem *p, unsigned char *ep) {
+ size_t na, co, ce;
+ unsigned char *nstart;
+
+ /* No need to realloc */
+ if (ep <= p->aend) {
+ return;
+ }
+
+ co = p->cur - p->start; /* Current offset */
+ ce = p->end - p->start; /* Current end */
+ na = ep - p->start; /* new allocated size */
+
+ /* Round new allocation up */
+ if (na <= 1024)
+ na += 1024;
+ else
+ na += 4096;
+
+ if ((nstart = p->al->realloc(p->al, p->start, na)) != NULL) {
+ p->start = nstart;
+ p->cur = nstart + co;
+ p->end = nstart + ce;
+ p->aend = nstart + na;
+ }
+}
+
+/* write count items of size length. Return number of items successfully written. */
+static size_t icmFileMem_write(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ size_t len;
+
+ len = ssat_mul(size, count);
+ if (len > (size_t)(p->aend - p->cur)) /* Try and expand buffer */
+ icmFileMem_filemem_resize(p, p->start + len);
+
+ if (len > (size_t)(p->aend - p->cur)) {
+ if (size > 0)
+ count = (p->aend - p->cur)/size;
+ else
+ count = 0;
+ }
+ len = size * count;
+ if (len > 0)
+ memmove(p->cur, buffer, len);
+ p->cur += len;
+ if (p->end < p->cur)
+ p->end = p->cur;
+ return count;
+}
+
+/* do a printf */
+static int icmFileMem_printf(
+icmFile *pp,
+const char *format,
+...
+) {
+ int rv;
+ va_list args;
+ icmFileMem *p = (icmFileMem *)pp;
+ int len;
+
+ va_start(args, format);
+
+ rv = 1;
+ len = 100; /* Initial allocation for printf */
+ icmFileMem_filemem_resize(p, p->cur + len);
+
+ /* We have to use the available printf functions to resize the buffer if needed. */
+ for (;rv != 0;) {
+ /* vsnprintf() either returns -1 if it doesn't fit, or */
+ /* returns the size-1 needed in order to fit. */
+ len = vsnprintf((char *)p->cur, (p->aend - p->cur), format, args);
+
+ if (len > -1 && ((p->cur + len +1) <= p->aend)) /* Fitted in current allocation */
+ break;
+
+ if (len > -1) /* vsnprintf returned needed size-1 */
+ len = len+2; /* (In case vsnprintf returned 1 less than it needs) */
+ else
+ len *= 2; /* We just have to guess */
+
+ /* Attempt to resize */
+ icmFileMem_filemem_resize(p, p->cur + len);
+
+ /* If resize failed */
+ if ((p->aend - p->cur) < len) {
+ rv = 0;
+ break;
+ }
+ }
+ if (rv != 0) {
+ /* Figure out where end of printf is */
+ len = strlen((char *)p->cur); /* Length excluding nul */
+ p->cur += len;
+ if (p->cur > p->end)
+ p->end = p->cur;
+ rv = len;
+ }
+ va_end(args);
+ return rv;
+}
+
+/* flush all write data out to secondary storage. Return nz on failure. */
+static int icmFileMem_flush(
+icmFile *pp
+) {
+ return 0;
+}
+
+/* Return the memory buffer. Error if not icmFileMem */
+static int icmFileMem_get_buf(
+icmFile *pp,
+unsigned char **buf,
+size_t *len
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ if (buf != NULL)
+ *buf = p->start;
+ if (len != NULL)
+ *len = p->end - p->start;
+ return 0;
+}
+
+/* we're done with the file object, return nz on failure */
+static int icmFileMem_delete(
+icmFile *pp
+) {
+ icmFileMem *p = (icmFileMem *)pp;
+ icmAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ if (p->del_buf) /* Free the memory buffer */
+ al->free(al, p->start);
+ al->free(al, p); /* Free object */
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+ return 0;
+}
+
+/* Create a memory image file access class with allocator */
+/* Buffer is used as is. */
+icmFile *new_icmFileMem_a(
+void *base, /* Pointer to base of memory buffer */
+size_t length, /* Number of bytes in buffer */
+icmAlloc *al /* heap allocator */
+) {
+ icmFileMem *p;
+
+ if ((p = (icmFileMem *) al->calloc(al, 1, sizeof(icmFileMem))) == NULL) {
+ return NULL;
+ }
+ p->al = al; /* Heap allocator */
+ p->get_size = icmFileMem_get_size;
+ p->seek = icmFileMem_seek;
+ p->read = icmFileMem_read;
+ p->write = icmFileMem_write;
+ p->gprintf = icmFileMem_printf;
+ p->flush = icmFileMem_flush;
+ p->get_buf = icmFileMem_get_buf;
+ p->del = icmFileMem_delete;
+
+ p->start = (unsigned char *)base;
+ p->cur = p->start;
+ p->aend = p->end = p->start + length;
+
+ return (icmFile *)p;
+}
+
+/* Create a memory image file access class with given allocator */
+/* and delete base when icmFile is deleted. */
+icmFile *new_icmFileMem_ad(void *base, size_t length, icmAlloc *al) {
+ icmFile *fp;
+
+ if ((fp = new_icmFileMem_a(base, length, al)) != NULL) {
+ ((icmFileMem *)fp)->del_buf = 1;
+ }
+
+ return fp;
+}
+
+/* ========================================================== */
+/* Conversion support functions */
+/* Convert between ICC storage types and native C types */
+/* Write routine return non-zero if numbers can't be represented */
+
+/* Unsigned */
+static unsigned int read_UInt8Number(char *p) {
+ unsigned int rv;
+ rv = (unsigned int)((ORD8 *)p)[0];
+ return rv;
+}
+
+static int write_UInt8Number(unsigned int d, char *p) {
+ if (d > 255)
+ return 1;
+ ((ORD8 *)p)[0] = (ORD8)d;
+ return 0;
+}
+
+static unsigned int read_UInt16Number(char *p) {
+ unsigned int rv;
+ rv = 256 * (unsigned int)((ORD8 *)p)[0]
+ + (unsigned int)((ORD8 *)p)[1];
+ return rv;
+}
+
+static int write_UInt16Number(unsigned int d, char *p) {
+ if (d > 65535)
+ return 1;
+ ((ORD8 *)p)[0] = (ORD8)(d >> 8);
+ ((ORD8 *)p)[1] = (ORD8)(d);
+ return 0;
+}
+
+static unsigned int read_UInt32Number(char *p) {
+ unsigned int rv;
+ rv = 16777216 * (unsigned int)((ORD8 *)p)[0]
+ + 65536 * (unsigned int)((ORD8 *)p)[1]
+ + 256 * (unsigned int)((ORD8 *)p)[2]
+ + (unsigned int)((ORD8 *)p)[3];
+ return rv;
+}
+
+static int write_UInt32Number(unsigned int d, char *p) {
+ ((ORD8 *)p)[0] = (ORD8)(d >> 24);
+ ((ORD8 *)p)[1] = (ORD8)(d >> 16);
+ ((ORD8 *)p)[2] = (ORD8)(d >> 8);
+ ((ORD8 *)p)[3] = (ORD8)(d);
+ return 0;
+}
+
+static void read_UInt64Number(icmUint64 *d, char *p) {
+ d->h = 16777216 * (unsigned int)((ORD8 *)p)[0]
+ + 65536 * (unsigned int)((ORD8 *)p)[1]
+ + 256 * (unsigned int)((ORD8 *)p)[2]
+ + (unsigned int)((ORD8 *)p)[3];
+ d->l = 16777216 * (unsigned int)((ORD8 *)p)[4]
+ + 65536 * (unsigned int)((ORD8 *)p)[5]
+ + 256 * (unsigned int)((ORD8 *)p)[6]
+ + (unsigned int)((ORD8 *)p)[7];
+}
+
+static int write_UInt64Number(icmUint64 *d, char *p) {
+ ((ORD8 *)p)[0] = (ORD8)(d->h >> 24);
+ ((ORD8 *)p)[1] = (ORD8)(d->h >> 16);
+ ((ORD8 *)p)[2] = (ORD8)(d->h >> 8);
+ ((ORD8 *)p)[3] = (ORD8)(d->h);
+ ((ORD8 *)p)[4] = (ORD8)(d->l >> 24);
+ ((ORD8 *)p)[5] = (ORD8)(d->l >> 16);
+ ((ORD8 *)p)[6] = (ORD8)(d->l >> 8);
+ ((ORD8 *)p)[7] = (ORD8)(d->l);
+ return 0;
+}
+
+static double read_U8Fixed8Number(char *p) {
+ ORD32 o32;
+ o32 = 256 * (ORD32)((ORD8 *)p)[0] /* Read big endian 16 bit unsigned */
+ + (ORD32)((ORD8 *)p)[1];
+ return (double)o32/256.0;
+}
+
+static int write_U8Fixed8Number(double d, char *p) {
+ ORD32 o32;
+ d = d * 256.0 + 0.5;
+ if (d >= 65536.0)
+ return 1;
+ if (d < 0.0)
+ return 1;
+ o32 = (ORD32)d;
+ ((ORD8 *)p)[0] = (ORD8)((o32) >> 8);
+ ((ORD8 *)p)[1] = (ORD8)((o32));
+ return 0;
+}
+
+static double read_U16Fixed16Number(char *p) {
+ ORD32 o32;
+ o32 = 16777216 * (ORD32)((ORD8 *)p)[0] /* Read big endian 32 bit unsigned */
+ + 65536 * (ORD32)((ORD8 *)p)[1]
+ + 256 * (ORD32)((ORD8 *)p)[2]
+ + (ORD32)((ORD8 *)p)[3];
+ return (double)o32/65536.0;
+}
+
+static int write_U16Fixed16Number(double d, char *p) {
+ ORD32 o32;
+ d = d * 65536.0 + 0.5;
+ if (d >= 4294967296.0)
+ return 1;
+ if (d < 0.0)
+ return 1;
+ o32 = (ORD32)d;
+ ((ORD8 *)p)[0] = (ORD8)((o32) >> 24);
+ ((ORD8 *)p)[1] = (ORD8)((o32) >> 16);
+ ((ORD8 *)p)[2] = (ORD8)((o32) >> 8);
+ ((ORD8 *)p)[3] = (ORD8)((o32));
+ return 0;
+}
+
+
+/* Signed numbers */
+static int read_SInt8Number(char *p) {
+ int rv;
+ rv = (int)((INR8 *)p)[0];
+ return rv;
+}
+
+static int write_SInt8Number(int d, char *p) {
+ if (d > 127)
+ return 1;
+ else if (d < -128)
+ return 1;
+ ((INR8 *)p)[0] = (INR8)d;
+ return 0;
+}
+
+static int read_SInt16Number(char *p) {
+ int rv;
+ rv = 256 * (int)((INR8 *)p)[0]
+ + (int)((ORD8 *)p)[1];
+ return rv;
+}
+
+static int write_SInt16Number(int d, char *p) {
+ if (d > 32767)
+ return 1;
+ else if (d < -32768)
+ return 1;
+ ((INR8 *)p)[0] = (INR8)(d >> 8);
+ ((ORD8 *)p)[1] = (ORD8)(d);
+ return 0;
+}
+
+static int read_SInt32Number(char *p) {
+ int rv;
+ rv = 16777216 * (int)((INR8 *)p)[0]
+ + 65536 * (int)((ORD8 *)p)[1]
+ + 256 * (int)((ORD8 *)p)[2]
+ + (int)((ORD8 *)p)[3];
+ return rv;
+}
+
+static int write_SInt32Number(int d, char *p) {
+ ((INR8 *)p)[0] = (INR8)(d >> 24);
+ ((ORD8 *)p)[1] = (ORD8)(d >> 16);
+ ((ORD8 *)p)[2] = (ORD8)(d >> 8);
+ ((ORD8 *)p)[3] = (ORD8)(d);
+ return 0;
+}
+
+static void read_SInt64Number(icmInt64 *d, char *p) {
+ d->h = 16777216 * (int)((INR8 *)p)[0]
+ + 65536 * (int)((ORD8 *)p)[1]
+ + 256 * (int)((ORD8 *)p)[2]
+ + (int)((ORD8 *)p)[3];
+ d->l = 16777216 * (unsigned int)((ORD8 *)p)[4]
+ + 65536 * (unsigned int)((ORD8 *)p)[5]
+ + 256 * (unsigned int)((ORD8 *)p)[6]
+ + (unsigned int)((ORD8 *)p)[7];
+}
+
+static int write_SInt64Number(icmInt64 *d, char *p) {
+ ((INR8 *)p)[0] = (INR8)(d->h >> 24);
+ ((ORD8 *)p)[1] = (ORD8)(d->h >> 16);
+ ((ORD8 *)p)[2] = (ORD8)(d->h >> 8);
+ ((ORD8 *)p)[3] = (ORD8)(d->h);
+ ((ORD8 *)p)[4] = (ORD8)(d->l >> 24);
+ ((ORD8 *)p)[5] = (ORD8)(d->l >> 16);
+ ((ORD8 *)p)[6] = (ORD8)(d->l >> 8);
+ ((ORD8 *)p)[7] = (ORD8)(d->l);
+ return 0;
+}
+
+static double read_S15Fixed16Number(char *p) {
+ INR32 i32;
+ i32 = 16777216 * (INR32)((INR8 *)p)[0] /* Read big endian 32 bit signed */
+ + 65536 * (INR32)((ORD8 *)p)[1]
+ + 256 * (INR32)((ORD8 *)p)[2]
+ + (INR32)((ORD8 *)p)[3];
+ return (double)i32/65536.0;
+}
+
+static int write_S15Fixed16Number(double d, char *p) {
+ INR32 i32;
+ d = floor(d * 65536.0 + 0.5); /* Beware! (int)(d + 0.5) doesn't work! */
+ if (d >= 2147483648.0)
+ return 1;
+ if (d < -2147483648.0)
+ return 1;
+ i32 = (INR32)d;
+ ((INR8 *)p)[0] = (INR8)((i32) >> 24); /* Write big endian 32 bit signed */
+ ((ORD8 *)p)[1] = (ORD8)((i32) >> 16);
+ ((ORD8 *)p)[2] = (ORD8)((i32) >> 8);
+ ((ORD8 *)p)[3] = (ORD8)((i32));
+ return 0;
+}
+
+/* Device coordinate as 8 bit value range 0.0 - 1.0 */
+static double read_DCS8Number(char *p) {
+ unsigned int rv;
+ rv = (unsigned int)((ORD8 *)p)[0];
+ return (double)rv/255.0;
+}
+
+static int write_DCS8Number(double d, char *p) {
+ ORD32 o32;
+ d = d * 255.0 + 0.5;
+ if (d >= 256.0)
+ return 1;
+ if (d < 0.0)
+ return 1;
+ o32 = (ORD32)d;
+ ((ORD8 *)p)[0] = (ORD8)(o32);
+ return 0;
+}
+
+/* Device coordinate as 16 bit value range 0.0 - 1.0 */
+static double read_DCS16Number(char *p) {
+ unsigned int rv;
+ rv = 256 * (unsigned int)((ORD8 *)p)[0]
+ + (unsigned int)((ORD8 *)p)[1];
+ return (double)rv/65535.0;
+}
+
+static int write_DCS16Number(double d, char *p) {
+ ORD32 o32;
+ d = d * 65535.0 + 0.5;
+ if (d >= 65536.0)
+ return 1;
+ if (d < 0.0)
+ return 1;
+ o32 = (ORD32)d;
+ ((ORD8 *)p)[0] = (ORD8)(o32 >> 8);
+ ((ORD8 *)p)[1] = (ORD8)(o32);
+ return 0;
+}
+
+static void Lut_Lut2XYZ(double *out, double *in);
+static void Lut_XYZ2Lut(double *out, double *in);
+static void Lut_Lut2Lab_8(double *out, double *in);
+static void Lut_Lab2Lut_8(double *out, double *in);
+static void Lut_Lut2LabV2_16(double *out, double *in);
+static void Lut_Lab2LutV2_16(double *out, double *in);
+static void Lut_Lut2LabV4_16(double *out, double *in);
+static void Lut_Lab2LutV4_16(double *out, double *in);
+
+static void Lut_Lut2Y(double *out, double *in);
+static void Lut_Y2Lut(double *out, double *in);
+static void Lut_Lut2L_8(double *out, double *in);
+static void Lut_L2Lut_8(double *out, double *in);
+static void Lut_Lut2LV2_16(double *out, double *in);
+static void Lut_L2LutV2_16(double *out, double *in);
+static void Lut_Lut2LV4_16(double *out, double *in);
+static void Lut_L2LutV4_16(double *out, double *in);
+
+//~~~~888888
+/* read a PCS number. PCS can be profile PCS, profile version Lab, */
+/* or a specific type of Lab, depending on the value of csig: */
+/* icmSigPCSData, icSigXYZData, icmSigLab8Data, icSigLabData, */
+/* icmSigLabV2Data or icmSigLabV4Data */
+/* Do nothing if not one of the above. */
+static void read_PCSNumber(icc *icp, icColorSpaceSignature csig, double pcs[3], char *p) {
+
+ if (csig == icmSigPCSData)
+ csig = icp->header->pcs;
+ if (csig == icSigLabData) {
+ if (icp->ver != 0)
+ csig = icmSigLabV4Data;
+ else
+ csig = icmSigLabV2Data;
+ }
+
+ if (csig == icmSigLab8Data) {
+ pcs[0] = read_DCS8Number(p);
+ pcs[1] = read_DCS8Number(p+1);
+ pcs[2] = read_DCS8Number(p+2);
+ } else {
+ pcs[0] = read_DCS16Number(p);
+ pcs[1] = read_DCS16Number(p+2);
+ pcs[2] = read_DCS16Number(p+4);
+ }
+ switch (csig) {
+ case icSigXYZData:
+ Lut_Lut2XYZ(pcs, pcs);
+ break;
+ case icmSigLab8Data:
+ Lut_Lut2Lab_8(pcs, pcs);
+ break;
+ case icmSigLabV2Data:
+ Lut_Lut2LabV2_16(pcs, pcs);
+ break;
+ case icmSigLabV4Data:
+ Lut_Lut2LabV4_16(pcs, pcs);
+ break;
+ default:
+ break;
+ }
+}
+
+/* write a PCS number. PCS can be profile PCS, profile version Lab, */
+/* or a specific type of Lab, depending on the value of csig: */
+/* icmSigPCSData, icSigXYZData, icmSigLab8Data, icSigLabData, */
+/* icmSigLabV2Data or icmSigLabV4Data */
+/* Return 1 if error */
+static int write_PCSNumber(icc *icp, icColorSpaceSignature csig, double pcs[3], char *p) {
+ double v[3];
+ int j;
+
+ if (csig == icmSigPCSData)
+ csig = icp->header->pcs;
+ if (csig == icSigLabData) {
+ if (icp->ver != 0)
+ csig = icmSigLabV4Data;
+ else
+ csig = icmSigLabV2Data;
+ }
+
+ switch (csig) {
+ case icSigXYZData:
+ Lut_XYZ2Lut(v, pcs);
+ break;
+ case icmSigLab8Data:
+ Lut_Lab2Lut_8(v, pcs);
+ break;
+ case icmSigLabV2Data:
+ Lut_Lab2LutV2_16(v, pcs);
+ break;
+ case icmSigLabV4Data:
+ Lut_Lab2LutV4_16(v, pcs);
+ break;
+ default:
+ return 1;
+ }
+ if (csig == icmSigLab8Data) {
+ for (j = 0; j < 3; j++) {
+ if (write_DCS8Number(v[j], p+j))
+ return 1;
+ }
+ } else {
+ for (j = 0; j < 3; j++) {
+ if (write_DCS16Number(v[j], p+(2 * j)))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Read a given primitive type. Return non-zero on error */
+/* (Not currently used internaly ?) */
+/* Public: */
+int read_Primitive(icc *icp, icmPrimType ptype, void *prim, char *p) {
+
+ switch(ptype) {
+ case icmUInt8Number:
+ *((unsigned int *)prim) = read_UInt8Number(p);
+ return 0;
+ case icmUInt16Number:
+ *((unsigned int *)prim) = read_UInt16Number(p);
+ return 0;
+ case icmUInt32Number:
+ *((unsigned int *)prim) = read_UInt32Number(p);
+ return 0;
+ case icmUInt64Number:
+ read_UInt64Number((icmUint64 *)prim, p);
+ return 0;
+ case icmU8Fixed8Number:
+ *((double *)prim) = read_U8Fixed8Number(p);
+ return 0;
+ case icmU16Fixed16Number:
+ *((double *)prim) = read_U16Fixed16Number(p);
+ return 0;
+ case icmSInt8Number:
+ *((int *)prim) = read_SInt8Number(p);
+ return 0;
+ case icmSInt16Number:
+ *((int *)prim) = read_SInt16Number(p);
+ return 0;
+ case icmSInt32Number:
+ *((int *)prim) = read_SInt32Number(p);
+ return 0;
+ case icmSInt64Number:
+ read_SInt64Number((icmInt64 *)prim, p);
+ return 0;
+ case icmS15Fixed16Number:
+ *((double *)prim) = read_S15Fixed16Number(p);
+ return 0;
+ case icmDCS8Number:
+ *((double *)prim) = read_DCS8Number(p);
+ return 0;
+ case icmDCS16Number:
+ *((double *)prim) = read_DCS16Number(p);
+ return 0;
+ case icmPCSNumber:
+ read_PCSNumber(icp, icmSigPCSData, ((double *)prim), p);
+ return 0;
+ case icmPCSXYZNumber:
+ read_PCSNumber(icp, icSigXYZData, ((double *)prim), p);
+ return 0;
+ case icmPCSLab8Number:
+ read_PCSNumber(icp, icmSigLab8Data, ((double *)prim), p);
+ return 0;
+ case icmPCSLabNumber:
+ read_PCSNumber(icp, icSigLabData, ((double *)prim), p);
+ return 0;
+ case icmPCSLabV2Number:
+ read_PCSNumber(icp, icmSigLabV2Data, ((double *)prim), p);
+ return 0;
+ case icmPCSLabV4Number:
+ read_PCSNumber(icp, icmSigLabV4Data, ((double *)prim), p);
+ return 0;
+ }
+
+ return 2;
+}
+
+/* Write a given primitive type. Return non-zero on error */
+/* (Not currently used internaly ?) */
+/* Public: */
+int write_Primitive(icc *icp, icmPrimType ptype, char *p, void *prim) {
+
+ switch(ptype) {
+ case icmUInt8Number:
+ return write_UInt8Number(*((unsigned int *)prim), p);
+ case icmUInt16Number:
+ return write_UInt16Number(*((unsigned int *)prim), p);
+ case icmUInt32Number:
+ return write_UInt32Number(*((unsigned int *)prim), p);
+ case icmUInt64Number:
+ return write_UInt64Number((icmUint64 *)prim, p);
+ case icmU8Fixed8Number:
+ return write_U8Fixed8Number(*((double *)prim), p);
+ case icmU16Fixed16Number:
+ return write_U16Fixed16Number(*((double *)prim), p);
+ case icmSInt8Number:
+ return write_SInt8Number(*((int *)prim), p);
+ case icmSInt16Number:
+ return write_SInt16Number(*((int *)prim), p);
+ case icmSInt32Number:
+ return write_SInt32Number(*((int *)prim), p);
+ case icmSInt64Number:
+ return write_SInt64Number((icmInt64 *)prim, p);
+ case icmS15Fixed16Number:
+ return write_S15Fixed16Number(*((double *)prim), p);
+ case icmDCS8Number:
+ return write_DCS8Number(*((double *)prim), p);
+ case icmDCS16Number:
+ return write_DCS16Number(*((double *)prim), p);
+ case icmPCSNumber:
+ return write_PCSNumber(icp, icmSigPCSData, ((double *)prim), p);
+ case icmPCSXYZNumber:
+ return write_PCSNumber(icp, icSigXYZData, ((double *)prim), p);
+ case icmPCSLab8Number:
+ return write_PCSNumber(icp, icmSigLab8Data, ((double *)prim), p);
+ case icmPCSLabNumber:
+ return write_PCSNumber(icp, icSigLabData, ((double *)prim), p);
+ case icmPCSLabV2Number:
+ return write_PCSNumber(icp, icmSigLabV2Data, ((double *)prim), p);
+ case icmPCSLabV4Number:
+ return write_PCSNumber(icp, icmSigLabV4Data, ((double *)prim), p);
+ }
+
+ return 2;
+}
+
+/* ---------------------------------------------------------- */
+/* Auiliary function - return a string that represents a tag */
+/* Note - returned buffers are static, can only be used 5 */
+/* times before buffers get reused. */
+char *tag2str(
+ int tag
+) {
+ int i;
+ static int si = 0; /* String buffer index */
+ static char buf[5][20]; /* String buffers */
+ char *bp;
+ unsigned char c[4];
+
+ bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ c[0] = 0xff & (tag >> 24);
+ c[1] = 0xff & (tag >> 16);
+ c[2] = 0xff & (tag >> 8);
+ c[3] = 0xff & (tag >> 0);
+ for (i = 0; i < 4; i++) { /* Can we represent it as a string ? */
+ if (!isprint(c[i]))
+ break;
+ }
+ if (i < 4) { /* Not printable - use hex */
+ sprintf(bp,"0x%x",tag);
+ } else { /* Printable */
+ sprintf(bp,"'%c%c%c%c'",c[0],c[1],c[2],c[3]);
+ }
+ return bp;
+}
+
+/* Auiliary function - return a tag created from a string */
+/* Note there is also the icmMakeTag() macro */
+unsigned int str2tag(
+ const char *str
+) {
+ unsigned int tag;
+ tag = (((unsigned int)str[0]) << 24)
+ + (((unsigned int)str[1]) << 16)
+ + (((unsigned int)str[2]) << 8)
+ + (((unsigned int)str[3]));
+ return tag;
+}
+
+/* helper - return 1 if the string doesn't have a */
+/* null terminator within len, return 0 has null at exactly len, */
+/* and 2 if it has null before len. */
+/* Note: will return 1 if len == 0 */
+static int check_null_string(char *cp, int len) {
+ for (; len > 0; len--) {
+ if (cp[0] == '\000')
+ break;
+ cp++;
+ }
+ if (len == 0)
+ return 1;
+ if (len > 1)
+ return 2;
+ return 0;
+}
+
+/* helper - return 1 if the string doesn't have a */
+/* null terminator within len, return 0 has null at exactly len, */
+/* and 2 if it has null before len. */
+/* Note: will return 1 if len == 0 */
+/* Unicode version */
+static int check_null_string16(char *cp, int len) {
+ for (; len > 0; len--) { /* Length is in characters */
+ if (cp[0] == 0 && cp[1] == 0)
+ break;
+ cp += 2;
+ }
+ if (len == 0)
+ return 1;
+ if (len > 1)
+ return 2;
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Color Space to number of component conversion */
+/* Return 0 on error */
+static unsigned int number_ColorSpaceSignature(icColorSpaceSignature sig) {
+ switch(sig) {
+ case icSigXYZData:
+ return 3;
+ case icSigLabData:
+ return 3;
+ case icSigLuvData:
+ return 3;
+ case icSigYCbCrData:
+ return 3;
+ case icSigYxyData:
+ return 3;
+ case icSigRgbData:
+ return 3;
+ case icSigGrayData:
+ return 1;
+ case icSigHsvData:
+ return 3;
+ case icSigHlsData:
+ return 3;
+ case icSigCmykData:
+ return 4;
+ case icSigCmyData:
+ return 3;
+ case icSig2colorData:
+ return 2;
+ case icSig3colorData:
+ return 3;
+ case icSig4colorData:
+ return 4;
+ case icSig5colorData:
+ case icSigMch5Data:
+ return 5;
+ case icSig6colorData:
+ case icSigMch6Data:
+ return 6;
+ case icSig7colorData:
+ case icSigMch7Data:
+ return 7;
+ case icSig8colorData:
+ case icSigMch8Data:
+ return 8;
+ case icSig9colorData:
+ return 9;
+ case icSig10colorData:
+ return 10;
+ case icSig11colorData:
+ return 11;
+ case icSig12colorData:
+ return 12;
+ case icSig13colorData:
+ return 13;
+ case icSig14colorData:
+ return 14;
+ case icSig15colorData:
+ return 15;
+
+ /* Non-standard and Pseudo spaces */
+ case icmSigYData:
+ return 1;
+ case icmSigLData:
+ return 1;
+ case icmSigL8Data:
+ return 1;
+ case icmSigLV2Data:
+ return 1;
+ case icmSigLV4Data:
+ return 1;
+ case icmSigPCSData:
+ return 3;
+ case icmSigLab8Data:
+ return 3;
+ case icmSigLabV2Data:
+ return 3;
+ case icmSigLabV4Data:
+ return 3;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* Public version of above */
+
+/* Return the number of channels for the given color space. Return 0 if unknown. */
+ICCLIB_API unsigned int icmCSSig2nchan(icColorSpaceSignature sig) {
+ return number_ColorSpaceSignature(sig);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return the individual channel names and number of channels give a colorspace signature. */
+/* Return 0 if it is not a colorspace that itself defines particular channels, */
+/* 1 if it is a colorant based colorspace, and 2 if it is not a colorant based space */
+static int chnames_ColorSpaceSignature(
+icColorSpaceSignature sig,
+char *cvals[] /* Pointers to return for each channel */
+) {
+ switch (sig) {
+ case icSigXYZData:
+ cvals[0] = "CIE X";
+ cvals[1] = "CIE Y";
+ cvals[2] = "CIE Z";
+ return 2;
+
+ case icSigLabData:
+ cvals[0] = "CIE L*";
+ cvals[1] = "CIE a*";
+ cvals[2] = "CIE b*";
+ return 2;
+
+ case icSigLuvData:
+ cvals[0] = "CIE L*";
+ cvals[1] = "CIE u*";
+ cvals[2] = "CIE v*";
+ return 2;
+
+ /* Usually ITU-R BT.601 (was CCIR 601) */
+ case icSigYCbCrData:
+ cvals[0] = "ITU Y";
+ cvals[1] = "ITU Cb";
+ cvals[2] = "ITU Cr";
+ return 2;
+
+ case icSigYxyData:
+ cvals[0] = "CIE Y";
+ cvals[1] = "CIE x";
+ cvals[2] = "CIE y";
+ return 2;
+
+ /* Alvy Ray Smith ? */
+ case icSigHsvData:
+ cvals[0] = "RGB Hue";
+ cvals[1] = "RGB Saturation";
+ cvals[2] = "RGB Value";
+ return 2;
+
+ /* GSPC ? */
+ case icSigHlsData:
+ cvals[0] = "RGB Hue";
+ cvals[1] = "RGB Lightness";
+ cvals[2] = "RGB Saturation";
+ return 2;
+
+ case icSigCmyData:
+ cvals[0] = "Cyan";
+ cvals[1] = "Magenta";
+ cvals[2] = "Yellow";
+ return 1;
+
+ case icSigRgbData:
+ cvals[0] = "Red";
+ cvals[1] = "Green";
+ cvals[2] = "Blue";
+ return 1;
+
+ case icSigCmykData:
+ cvals[0] = "Cyan";
+ cvals[1] = "Magenta";
+ cvals[2] = "Yellow";
+ cvals[3] = "Black";
+ return 1;
+
+
+ /* Non-standard and Pseudo spaces */
+ case icmSigYData:
+ cvals[0] = "CIE Y";
+ return 2;
+
+ case icmSigLData:
+ cvals[0] = "CIE L*";
+ return 2;
+
+ default:
+ break;
+
+ }
+ return 0;
+}
+
+/* Public version of above */
+
+/* Return the individual channel names and number of channels give a colorspace signature. */
+/* Return 0 if it is not a colorspace that itself defines particular channels, */
+/* 1 if it is a colorant based colorspace, and 2 if it is not a colorant based space */
+ICCLIB_API unsigned int icmCSSig2chanNames(icColorSpaceSignature sig, char *cvals[]) {
+
+ return chnames_ColorSpaceSignature(sig, cvals);
+}
+
+/* ------------------------------------------------------- */
+/* Flag dump functions */
+/* Note - returned buffers are static, can only be used 5 */
+/* times before buffers get reused. */
+
+/* Screening Encodings */
+static char *string_ScreenEncodings(unsigned int flags) {
+ static int si = 0; /* String buffer index */
+ static char buf[5][80]; /* String buffers */
+ char *bp, *cp;
+
+ cp = bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ if (flags & icPrtrDefaultScreensTrue) {
+ sprintf(cp,"Default Screen");
+ } else {
+ sprintf(cp,"No Default Screen");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icLinesPerInch) {
+ sprintf(cp,", Lines Per Inch");
+ } else {
+ sprintf(cp,", Lines Per cm");
+ }
+ cp = cp + strlen(cp);
+
+ return bp;
+}
+
+/* Device attributes */
+static char *string_DeviceAttributes(unsigned int flags) {
+ static int si = 0; /* String buffer index */
+ static char buf[5][80]; /* String buffers */
+ char *bp, *cp;
+
+ cp = bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ if (flags & icTransparency) {
+ sprintf(cp,"Transparency");
+ } else {
+ sprintf(cp,"Reflective");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icMatte) {
+ sprintf(cp,", Matte");
+ } else {
+ sprintf(cp,", Glossy");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icNegative) {
+ sprintf(cp,", Negative");
+ } else {
+ sprintf(cp,", Positive");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icBlackAndWhite) {
+ sprintf(cp,", BlackAndWhite");
+ } else {
+ sprintf(cp,", Color");
+ }
+ cp = cp + strlen(cp);
+
+ return bp;
+}
+
+/* Profile header flags */
+static char *string_ProfileHeaderFlags(unsigned int flags) {
+ static int si = 0; /* String buffer index */
+ static char buf[5][80]; /* String buffers */
+ char *bp, *cp;
+
+ cp = bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ if (flags & icEmbeddedProfileTrue) {
+ sprintf(cp,"Embedded Profile");
+ } else {
+ sprintf(cp,"Not Embedded Profile");
+ }
+ cp = cp + strlen(cp);
+ if (flags & icUseWithEmbeddedDataOnly) {
+ sprintf(cp,", Use with embedded data only");
+ } else {
+ sprintf(cp,", Use anywhere");
+ }
+ cp = cp + strlen(cp);
+
+ return bp;
+}
+
+
+static char *string_AsciiOrBinaryData(unsigned int flags) {
+ static int si = 0; /* String buffer index */
+ static char buf[5][80]; /* String buffers */
+ char *bp, *cp;
+
+ cp = bp = buf[si++];
+ si %= 5; /* Rotate through buffers */
+
+ if (flags & icBinaryData) {
+ sprintf(cp,"Binary");
+ } else {
+ sprintf(cp,"Ascii");
+ }
+ cp = cp + strlen(cp);
+
+ return bp;
+}
+
+/* ------------------------------------------------------------ */
+/* Enumeration dump functions */
+/* Note - returned buffers are static, can only be used once */
+/* before buffers get reused if type is unknown. */
+
+/* public tags and sizes */
+static const char *string_TagSignature(icTagSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigAToB0Tag:
+ return "AToB0 Multidimentional Transform";
+ case icSigAToB1Tag:
+ return "AToB1 Multidimentional Transform";
+ case icSigAToB2Tag:
+ return "AToB2 Multidimentional Transform";
+ case icSigBlueColorantTag:
+ return "Blue Colorant";
+ case icSigBlueTRCTag:
+ return "Blue Tone Reproduction Curve";
+ case icSigBToA0Tag:
+ return "BToA0 Multidimentional Transform";
+ case icSigBToA1Tag:
+ return "BToA1 Multidimentional Transform";
+ case icSigBToA2Tag:
+ return "BToA2 Multidimentional Transform";
+ case icSigCalibrationDateTimeTag:
+ return "Calibration Date & Time";
+ case icSigCharTargetTag:
+ return "Characterization Target";
+ case icSigCopyrightTag:
+ return "Copyright";
+ case icSigCrdInfoTag:
+ return "CRD Info";
+ case icSigDeviceMfgDescTag:
+ return "Device Manufacturer Description";
+ case icSigDeviceModelDescTag:
+ return "Device Model Description";
+ case icSigGamutTag:
+ return "Gamut";
+ case icSigGrayTRCTag:
+ return "Gray Tone Reproduction Curve";
+ case icSigGreenColorantTag:
+ return "Green Colorant";
+ case icSigGreenTRCTag:
+ return "Green Tone Reproduction Curve";
+ case icSigLuminanceTag:
+ return "Luminance";
+ case icSigMeasurementTag:
+ return "Measurement";
+ case icSigMediaBlackPointTag:
+ return "Media Black Point";
+ case icSigMediaWhitePointTag:
+ return "Media White Point";
+ case icSigNamedColorTag:
+ return "Named Color";
+ case icSigNamedColor2Tag:
+ return "Named Color 2";
+ case icSigPreview0Tag:
+ return "Preview0";
+ case icSigPreview1Tag:
+ return "Preview1";
+ case icSigPreview2Tag:
+ return "Preview2";
+ case icSigProfileDescriptionTag:
+ return "Profile Description";
+ case icSigProfileSequenceDescTag:
+ return "Profile Sequence";
+ case icSigPs2CRD0Tag:
+ return "PS Level 2 CRD perceptual";
+ case icSigPs2CRD1Tag:
+ return "PS Level 2 CRD colorimetric";
+ case icSigPs2CRD2Tag:
+ return "PS Level 2 CRD saturation";
+ case icSigPs2CRD3Tag:
+ return "PS Level 2 CRD absolute";
+ case icSigPs2CSATag:
+ return "PS Level 2 color space array";
+ case icSigPs2RenderingIntentTag:
+ return "PS Level 2 Rendering Intent";
+ case icSigRedColorantTag:
+ return "Red Colorant";
+ case icSigRedTRCTag:
+ return "Red Tone Reproduction Curve";
+ case icSigScreeningDescTag:
+ return "Screening Description";
+ case icSigScreeningTag:
+ return "Screening Attributes";
+ case icSigTechnologyTag:
+ return "Device Technology";
+ case icSigUcrBgTag:
+ return "Under Color Removal & Black Generation";
+ case icSigVideoCardGammaTag:
+ return "Video Card Gamma Curve";
+ case icSigViewingCondDescTag:
+ return "Viewing Condition Description";
+ case icSigViewingConditionsTag:
+ return "Viewing Condition Paramaters";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* technology signature descriptions */
+static const char *string_TechnologySignature(icTechnologySignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigDigitalCamera:
+ return "Digital Camera";
+ case icSigFilmScanner:
+ return "Film Scanner";
+ case icSigReflectiveScanner:
+ return "Reflective Scanner";
+ case icSigInkJetPrinter:
+ return "InkJet Printer";
+ case icSigThermalWaxPrinter:
+ return "Thermal WaxPrinter";
+ case icSigElectrophotographicPrinter:
+ return "Electrophotographic Printer";
+ case icSigElectrostaticPrinter:
+ return "Electrostatic Printer";
+ case icSigDyeSublimationPrinter:
+ return "DyeSublimation Printer";
+ case icSigPhotographicPaperPrinter:
+ return "Photographic Paper Printer";
+ case icSigFilmWriter:
+ return "Film Writer";
+ case icSigVideoMonitor:
+ return "Video Monitor";
+ case icSigVideoCamera:
+ return "Video Camera";
+ case icSigProjectionTelevision:
+ return "Projection Television";
+ case icSigCRTDisplay:
+ return "Cathode Ray Tube Display";
+ case icSigPMDisplay:
+ return "Passive Matrix Display";
+ case icSigAMDisplay:
+ return "Active Matrix Display";
+ case icSigPhotoCD:
+ return "Photo CD";
+ case icSigPhotoImageSetter:
+ return "Photo ImageSetter";
+ case icSigGravure:
+ return "Gravure";
+ case icSigOffsetLithography:
+ return "Offset Lithography";
+ case icSigSilkscreen:
+ return "Silkscreen";
+ case icSigFlexography:
+ return "Flexography";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* type signatures */
+static const char *string_TypeSignature(icTagTypeSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigCurveType:
+ return "Curve";
+ case icSigDataType:
+ return "Data";
+ case icSigDateTimeType:
+ return "DateTime";
+ case icSigLut16Type:
+ return "Lut16";
+ case icSigLut8Type:
+ return "Lut8";
+ case icSigMeasurementType:
+ return "Measurement";
+ case icSigNamedColorType:
+ return "Named Color";
+ case icSigProfileSequenceDescType:
+ return "Profile Sequence Desc";
+ case icSigS15Fixed16ArrayType:
+ return "S15Fixed16 Array";
+ case icSigScreeningType:
+ return "Screening";
+ case icSigSignatureType:
+ return "Signature";
+ case icSigTextType:
+ return "Text";
+ case icSigTextDescriptionType:
+ return "Text Description";
+ case icSigU16Fixed16ArrayType:
+ return "U16Fixed16 Array";
+ case icSigUcrBgType:
+ return "Under Color Removal & Black Generation";
+ case icSigUInt16ArrayType:
+ return "UInt16 Array";
+ case icSigUInt32ArrayType:
+ return "UInt32 Array";
+ case icSigUInt64ArrayType:
+ return "UInt64 Array";
+ case icSigUInt8ArrayType:
+ return "UInt8 Array";
+ case icSigVideoCardGammaType:
+ return "Video Card Gamma";
+ case icSigViewingConditionsType:
+ return "Viewing Conditions";
+ case icSigXYZType:
+ return "XYZ (Array?)";
+ case icSigNamedColor2Type:
+ return "Named Color 2";
+ case icSigCrdInfoType:
+ return "CRD Info";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* Color Space Signatures */
+static const char *string_ColorSpaceSignature(icColorSpaceSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigXYZData:
+ return "XYZ";
+ case icSigLabData:
+ return "Lab";
+ case icSigLuvData:
+ return "Luv";
+ case icSigYCbCrData:
+ return "YCbCr";
+ case icSigYxyData:
+ return "Yxy";
+ case icSigRgbData:
+ return "RGB";
+ case icSigGrayData:
+ return "Gray";
+ case icSigHsvData:
+ return "HSV";
+ case icSigHlsData:
+ return "HLS";
+ case icSigCmykData:
+ return "CMYK";
+ case icSigCmyData:
+ return "CMY";
+ case icSig2colorData:
+ return "2 Color";
+ case icSig3colorData:
+ return "3 Color";
+ case icSig4colorData:
+ return "4 Color";
+ case icSig5colorData:
+ case icSigMch5Data:
+ return "5 Color";
+ case icSig6colorData:
+ case icSigMch6Data:
+ return "6 Color";
+ case icSig7colorData:
+ case icSigMch7Data:
+ return "7 Color";
+ case icSig8colorData:
+ case icSigMch8Data:
+ return "8 Color";
+ case icSig9colorData:
+ return "9 Color";
+ case icSig10colorData:
+ return "10 Color";
+ case icSig11colorData:
+ return "11 Color";
+ case icSig12colorData:
+ return "12 Color";
+ case icSig13colorData:
+ return "13 Color";
+ case icSig14colorData:
+ return "14 Color";
+ case icSig15colorData:
+ return "15 Color";
+
+ /* Non-standard and Pseudo spaces */
+ case icmSigYData:
+ return "Y";
+ case icmSigLData:
+ return "L";
+ case icmSigL8Data:
+ return "L";
+ case icmSigLV2Data:
+ return "L";
+ case icmSigLV4Data:
+ return "L";
+ case icmSigPCSData:
+ return "PCS";
+ case icmSigLab8Data:
+ return "Lab";
+ case icmSigLabV2Data:
+ return "Lab";
+ case icmSigLabV4Data:
+ return "Lab";
+
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+#ifdef NEVER
+/* Public version of above */
+char *ColorSpaceSignature2str(icColorSpaceSignature sig) {
+ return string_ColorSpaceSignature(sig);
+}
+#endif
+
+
+/* profileClass enumerations */
+static const char *string_ProfileClassSignature(icProfileClassSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigInputClass:
+ return "Input";
+ case icSigDisplayClass:
+ return "Display";
+ case icSigOutputClass:
+ return "Output";
+ case icSigLinkClass:
+ return "Link";
+ case icSigAbstractClass:
+ return "Abstract";
+ case icSigColorSpaceClass:
+ return "Color Space";
+ case icSigNamedColorClass:
+ return "Named Color";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* Platform Signatures */
+static const char *string_PlatformSignature(icPlatformSignature sig) {
+ static char buf[80];
+ switch(sig) {
+ case icSigMacintosh:
+ return "Macintosh";
+ case icSigMicrosoft:
+ return "Microsoft";
+ case icSigSolaris:
+ return "Solaris";
+ case icSigSGI:
+ return "SGI";
+ case icSigTaligent:
+ return "Taligent";
+ case icmSig_nix:
+ return "*nix";
+ default:
+ sprintf(buf,"Unrecognized - %s",tag2str(sig));
+ return buf;
+ }
+}
+
+/* Measurement Geometry, used in the measurmentType tag */
+static const char *string_MeasurementGeometry(icMeasurementGeometry sig) {
+ static char buf[30];
+ switch(sig) {
+ case icGeometryUnknown:
+ return "Unknown";
+ case icGeometry045or450:
+ return "0/45 or 45/0";
+ case icGeometry0dord0:
+ return "0/d or d/0";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Rendering Intents, used in the profile header */
+static const char *string_RenderingIntent(icRenderingIntent sig) {
+ static char buf[30];
+ switch(sig) {
+ case icPerceptual:
+ return "Perceptual";
+ case icRelativeColorimetric:
+ return "Relative Colorimetric";
+ case icSaturation:
+ return "Saturation";
+ case icAbsoluteColorimetric:
+ return "Absolute Colorimetric";
+ case icmAbsolutePerceptual: /* icclib specials */
+ return "Absolute Perceptual";
+ case icmAbsoluteSaturation: /* icclib specials */
+ return "Absolute Saturation";
+ case icmDefaultIntent: /* icclib specials */
+ return "Default Intent";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Transform Lookup function */
+static const char *string_LookupFunc(icmLookupFunc sig) {
+ static char buf[30];
+ switch(sig) {
+ case icmFwd:
+ return "Forward";
+ case icmBwd:
+ return "Backward";
+ case icmGamut:
+ return "Gamut";
+ case icmPreview:
+ return "Preview";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+
+/* Different Spot Shapes currently defined, used for screeningType */
+static const char *string_SpotShape(icSpotShape sig) {
+ static char buf[30];
+ switch(sig) {
+ case icSpotShapeUnknown:
+ return "Unknown";
+ case icSpotShapePrinterDefault:
+ return "Printer Default";
+ case icSpotShapeRound:
+ return "Round";
+ case icSpotShapeDiamond:
+ return "Diamond";
+ case icSpotShapeEllipse:
+ return "Ellipse";
+ case icSpotShapeLine:
+ return "Line";
+ case icSpotShapeSquare:
+ return "Square";
+ case icSpotShapeCross:
+ return "Cross";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Standard Observer, used in the measurmentType tag */
+static const char *string_StandardObserver(icStandardObserver sig) {
+ static char buf[30];
+ switch(sig) {
+ case icStdObsUnknown:
+ return "Unknown";
+ case icStdObs1931TwoDegrees:
+ return "1931 Two Degrees";
+ case icStdObs1964TenDegrees:
+ return "1964 Ten Degrees";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Pre-defined illuminants, used in measurement and viewing conditions type */
+static const char *string_Illuminant(icIlluminant sig) {
+ static char buf[30];
+ switch(sig) {
+ case icIlluminantUnknown:
+ return "Unknown";
+ case icIlluminantD50:
+ return "D50";
+ case icIlluminantD65:
+ return "D65";
+ case icIlluminantD93:
+ return "D93";
+ case icIlluminantF2:
+ return "F2";
+ case icIlluminantD55:
+ return "D55";
+ case icIlluminantA:
+ return "A";
+ case icIlluminantEquiPowerE:
+ return "Equi-Power(E)";
+ case icIlluminantF8:
+ return "F8";
+ default:
+ sprintf(buf,"Unrecognized - 0x%x",sig);
+ return buf;
+ }
+}
+
+/* Return a text abreviation of a color lookup algorithm */
+static const char *string_LuAlg(icmLuAlgType alg) {
+ static char buf[80];
+
+ switch(alg) {
+ case icmMonoFwdType:
+ return "MonoFwd";
+ case icmMonoBwdType:
+ return "MonoBwd";
+ case icmMatrixFwdType:
+ return "MatrixFwd";
+ case icmMatrixBwdType:
+ return "MatrixBwd";
+ case icmLutType:
+ return "Lut";
+ default:
+ sprintf(buf,"Unrecognized - %d",alg);
+ return buf;
+ }
+}
+
+/* Return a string description of the given enumeration value */
+/* Public: */
+const char *icm2str(icmEnumType etype, int enumval) {
+
+ switch(etype) {
+ case icmScreenEncodings:
+ return string_ScreenEncodings((unsigned int) enumval);
+ case icmDeviceAttributes:
+ return string_DeviceAttributes((unsigned int) enumval);
+ case icmProfileHeaderFlags:
+ return string_ProfileHeaderFlags((unsigned int) enumval);
+ case icmAsciiOrBinaryData:
+ return string_AsciiOrBinaryData((unsigned int) enumval);
+ case icmTagSignature:
+ return string_TagSignature((icTagSignature) enumval);
+ case icmTechnologySignature:
+ return string_TechnologySignature((icTechnologySignature) enumval);
+ case icmTypeSignature:
+ return string_TypeSignature((icTagTypeSignature) enumval);
+ case icmColorSpaceSignature:
+ return string_ColorSpaceSignature((icColorSpaceSignature) enumval);
+ case icmProfileClassSignature:
+ return string_ProfileClassSignature((icProfileClassSignature) enumval);
+ case icmPlatformSignature:
+ return string_PlatformSignature((icPlatformSignature) enumval);
+ case icmMeasurementGeometry:
+ return string_MeasurementGeometry((icMeasurementGeometry) enumval);
+ case icmRenderingIntent:
+ return string_RenderingIntent((icRenderingIntent) enumval);
+ case icmTransformLookupFunc:
+ return string_LookupFunc((icmLookupFunc) enumval);
+ case icmSpotShape:
+ return string_SpotShape((icSpotShape) enumval);
+ case icmStandardObserver:
+ return string_StandardObserver((icStandardObserver) enumval);
+ case icmIlluminant:
+ return string_Illuminant((icIlluminant) enumval);
+ case icmLuAlg:
+ return string_LuAlg((icmLuAlgType) enumval);
+ default:
+ return "enum2str got unknown type";
+ }
+}
+
+/* ========================================================== */
+/* Object I/O routines */
+/* ========================================================== */
+/* icmUnknown object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUnknown_get_size(
+ icmBase *pp
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 1); /* 1 byte for each unknown data */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUnknown_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUnknown_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUnknown_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUnknown_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/1; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ p->uttype = (icTagTypeSignature)read_SInt32Number(bp);
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 1) {
+ p->data[i] = read_UInt8Number(bp);
+ }
+ icp->al->free(p->icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUnknown_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUnknown_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUnknown_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->uttype,bp)) != 0) {
+ sprintf(icp->err,"icmUnknown_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp += 8; /* Skip padding */
+
+ /* Write all the data to the buffer */
+ for (i = 0; i < p->size; i++, bp += 1) {
+ if ((rv = write_UInt8Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUnknown_write: write_UInt8umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUnknown_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUnknown_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ unsigned int i, ii, r, ph;
+
+ if (verb <= 1)
+ return;
+
+ op->gprintf(op,"Unknown:\n");
+ op->gprintf(op," Payload size in bytes = %u\n",p->size);
+
+ /* Print one row of binary and ASCII interpretation if verb == 2, All if == 3 */
+ /* else print all of it. */
+ ii = i = ph = 0;
+ for (r = 1;; r++) { /* count rows */
+ int c = 1; /* Character location */
+
+ c = 1;
+ if (ph != 0) { /* Print ASCII under binary */
+ op->gprintf(op," ");
+ i = ii; /* Swap */
+ c += 12;
+ } else {
+ op->gprintf(op," 0x%04lx: ",i);
+ ii = i; /* Swap */
+ c += 12;
+ }
+ while (i < p->size && c < 60) {
+ if (ph == 0)
+ op->gprintf(op,"%02x ",p->data[i]);
+ else {
+ if (isprint(p->data[i]))
+ op->gprintf(op,"%c ",p->data[i]);
+ else
+ op->gprintf(op," ",p->data[i]);
+ }
+ c += 3;
+ i++;
+ }
+ if (ph == 0 || i < p->size)
+ op->gprintf(op,"\n");
+
+ if (ph == 1 && i >= p->size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (ph == 1 && r > 1 && verb < 3) {
+ op->gprintf(op," ...\n");
+ break; /* Print 1 row if not verbose */
+ }
+
+ if (ph == 0)
+ ph = 1;
+ else
+ ph = 0;
+
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUnknown_allocate(
+ icmBase *pp
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned char))) {
+ sprintf(icp->err,"icmUnknown_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned char *) icp->al->calloc(icp->al, p->size, sizeof(unsigned char)))
+ == NULL) {
+ sprintf(icp->err,"icmUnknown_alloc: malloc() of icmUnknown data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUnknown_delete(
+ icmBase *pp
+) {
+ icmUnknown *p = (icmUnknown *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUnknown(
+ icc *icp
+) {
+ icmUnknown *p;
+ if ((p = (icmUnknown *) icp->al->calloc(icp->al,1,sizeof(icmUnknown))) == NULL)
+ return NULL;
+ p->ttype = icmSigUnknownType;
+ p->uttype = icmSigUnknownType;
+ p->refcount = 1;
+ p->get_size = icmUnknown_get_size;
+ p->read = icmUnknown_read;
+ p->write = icmUnknown_write;
+ p->dump = icmUnknown_dump;
+ p->allocate = icmUnknown_allocate;
+ p->del = icmUnknown_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUInt8Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUInt8Array_get_size(
+ icmBase *pp
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 1); /* 1 byte for each UInt8 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUInt8Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUInt8Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt8Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUInt8Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/1; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ icp->al->free(icp->al, buf);
+ sprintf(icp->err,"icmUInt8Array_read: Wrong tag type for icmUInt8Array");
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 1) {
+ p->data[i] = read_UInt8Number(bp);
+ }
+ icp->al->free(p->icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUInt8Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUInt8Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt8Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUInt8Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp += 8; /* Skip padding */
+
+ /* Write all the data to the buffer */
+ for (i = 0; i < p->size; i++, bp += 1) {
+ if ((rv = write_UInt8Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUInt8Array_write: write_UInt8umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUInt8Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUInt8Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"UInt8Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %u\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUInt8Array_allocate(
+ icmBase *pp
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned int))) {
+ sprintf(icp->err,"icmUInt8Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned int *) icp->al->calloc(icp->al, p->size, sizeof(unsigned int)))
+ == NULL) {
+ sprintf(icp->err,"icmUInt8Array_alloc: malloc() of icmUInt8Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUInt8Array_delete(
+ icmBase *pp
+) {
+ icmUInt8Array *p = (icmUInt8Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUInt8Array(
+ icc *icp
+) {
+ icmUInt8Array *p;
+ if ((p = (icmUInt8Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt8Array))) == NULL)
+ return NULL;
+ p->ttype = icSigUInt8ArrayType;
+ p->refcount = 1;
+ p->get_size = icmUInt8Array_get_size;
+ p->read = icmUInt8Array_read;
+ p->write = icmUInt8Array_write;
+ p->dump = icmUInt8Array_dump;
+ p->allocate = icmUInt8Array_allocate;
+ p->del = icmUInt8Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUInt16Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUInt16Array_get_size(
+ icmBase *pp
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 2); /* 2 bytes for each UInt16 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUInt16Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUInt16Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt16Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUInt16Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/2; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmUInt16Array_read: Wrong tag type for icmUInt16Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 2) {
+ p->data[i] = read_UInt16Number(bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUInt16Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUInt16Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt16Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUInt16Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 2) {
+ if ((rv = write_UInt16Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUInt16Array_write: write_UInt16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUInt16Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUInt16Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"UInt16Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %u\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUInt16Array_allocate(
+ icmBase *pp
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned int))) {
+ sprintf(icp->err,"icmUInt16Array_alloc:: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned int *) icp->al->calloc(icp->al, p->size, sizeof(unsigned int)))
+ == NULL) {
+ sprintf(icp->err,"icmUInt16Array_alloc: malloc() of icmUInt16Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUInt16Array_delete(
+ icmBase *pp
+) {
+ icmUInt16Array *p = (icmUInt16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUInt16Array(
+ icc *icp
+) {
+ icmUInt16Array *p;
+ if ((p = (icmUInt16Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt16Array))) == NULL)
+ return NULL;
+ p->ttype = icSigUInt16ArrayType;
+ p->refcount = 1;
+ p->get_size = icmUInt16Array_get_size;
+ p->read = icmUInt16Array_read;
+ p->write = icmUInt16Array_write;
+ p->dump = icmUInt16Array_dump;
+ p->allocate = icmUInt16Array_allocate;
+ p->del = icmUInt16Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUInt32Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUInt32Array_get_size(
+ icmBase *pp
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 4); /* 4 bytes for each UInt32 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUInt32Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUInt32Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt32Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUInt32Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/4; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmUInt32Array_read: Wrong tag type for icmUInt32Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 4) {
+ p->data[i] = read_UInt32Number(bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUInt32Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUInt32Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt32Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUInt32Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 4) {
+ if ((rv = write_UInt32Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUInt32Array_write: write_UInt32umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUInt32Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUInt32Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"UInt32Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %u\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUInt32Array_allocate(
+ icmBase *pp
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned int))) {
+ sprintf(icp->err,"icmUInt32Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned int *) icp->al->calloc(icp->al, p->size, sizeof(unsigned int)))
+ == NULL) {
+ sprintf(icp->err,"icmUInt32Array_alloc: malloc() of icmUInt32Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUInt32Array_delete(
+ icmBase *pp
+) {
+ icmUInt32Array *p = (icmUInt32Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUInt32Array(
+ icc *icp
+) {
+ icmUInt32Array *p;
+ if ((p = (icmUInt32Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt32Array))) == NULL)
+ return NULL;
+ p->ttype = icSigUInt32ArrayType;
+ p->refcount = 1;
+ p->get_size = icmUInt32Array_get_size;
+ p->read = icmUInt32Array_read;
+ p->write = icmUInt32Array_write;
+ p->dump = icmUInt32Array_dump;
+ p->allocate = icmUInt32Array_allocate;
+ p->del = icmUInt32Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUInt64Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUInt64Array_get_size(
+ icmBase *pp
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 8); /* 8 bytes for each UInt64 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUInt64Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmUInt64Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt64Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUInt64Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/8; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmUInt64Array_read: Wrong tag type for icmUInt64Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 8) {
+ read_UInt64Number(&p->data[i], bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUInt64Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUInt64Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUInt64Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUInt64Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 8) {
+ if ((rv = write_UInt64Number(&p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmUInt64Array_write: write_UInt64umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUInt64Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUInt64Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"UInt64Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: h=%lu, l=%lu\n",i,p->data[i].h,p->data[i].l);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUInt64Array_allocate(
+ icmBase *pp
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(icmUint64))) {
+ sprintf(icp->err,"icmUInt64Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmUint64 *) icp->al->calloc(icp->al, p->size, sizeof(icmUint64)))
+ == NULL) {
+ sprintf(icp->err,"icmUInt64Array_alloc: malloc() of icmUInt64Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUInt64Array_delete(
+ icmBase *pp
+) {
+ icmUInt64Array *p = (icmUInt64Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUInt64Array(
+ icc *icp
+) {
+ icmUInt64Array *p;
+ if ((p = (icmUInt64Array *) icp->al->calloc(icp->al,1,sizeof(icmUInt64Array))) == NULL)
+ return NULL;
+ p->ttype = icSigUInt64ArrayType;
+ p->refcount = 1;
+ p->get_size = icmUInt64Array_get_size;
+ p->read = icmUInt64Array_read;
+ p->write = icmUInt64Array_write;
+ p->dump = icmUInt64Array_dump;
+ p->allocate = icmUInt64Array_allocate;
+ p->del = icmUInt64Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmU16Fixed16Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmU16Fixed16Array_get_size(
+ icmBase *pp
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 4); /* 4 byte for each U16Fixed16 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmU16Fixed16Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmU16Fixed16Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmU16Fixed16Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmU16Fixed16Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/4; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmU16Fixed16Array_read: Wrong tag type for icmU16Fixed16Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 4) {
+ p->data[i] = read_U16Fixed16Number(bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmU16Fixed16Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmU16Fixed16Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmU16Fixed16Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmU16Fixed16Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 4) {
+ if ((rv = write_U16Fixed16Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmU16Fixed16Array_write: write_U16Fixed16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmU16Fixed16Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmU16Fixed16Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"U16Fixed16Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %f\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmU16Fixed16Array_allocate(
+ icmBase *pp
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(double))) {
+ sprintf(icp->err,"icmU16Fixed16Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (double *) icp->al->calloc(icp->al, p->size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmU16Fixed16Array_alloc: malloc() of icmU16Fixed16Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmU16Fixed16Array_delete(
+ icmBase *pp
+) {
+ icmU16Fixed16Array *p = (icmU16Fixed16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmU16Fixed16Array(
+ icc *icp
+) {
+ icmU16Fixed16Array *p;
+ if ((p = (icmU16Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmU16Fixed16Array))) == NULL)
+ return NULL;
+ p->ttype = icSigU16Fixed16ArrayType;
+ p->refcount = 1;
+ p->get_size = icmU16Fixed16Array_get_size;
+ p->read = icmU16Fixed16Array_read;
+ p->write = icmU16Fixed16Array_write;
+ p->dump = icmU16Fixed16Array_dump;
+ p->allocate = icmU16Fixed16Array_allocate;
+ p->del = icmU16Fixed16Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmS15Fixed16Array object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmS15Fixed16Array_get_size(
+ icmBase *pp
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 4); /* 4 byte for each S15Fixed16 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmS15Fixed16Array_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmS15Fixed16Array_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmS15Fixed16Array_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmS15Fixed16Array_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/4; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmS15Fixed16Array_read: Wrong tag type for icmS15Fixed16Array");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 4) {
+ p->data[i] = read_S15Fixed16Number(bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmS15Fixed16Array_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmS15Fixed16Array_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmS15Fixed16Array_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmS15Fixed16Array_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 4) {
+ if ((rv = write_S15Fixed16Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmS15Fixed16Array_write: write_S15Fixed16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmS15Fixed16Array_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmS15Fixed16Array_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"S15Fixed16Array:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %lu: %f\n",i,p->data[i]);
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmS15Fixed16Array_allocate(
+ icmBase *pp
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(double))) {
+ sprintf(icp->err,"icmS15Fixed16Array_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (double *) icp->al->calloc(icp->al, p->size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmS15Fixed16Array_alloc: malloc() of icmS15Fixed16Array data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmS15Fixed16Array_delete(
+ icmBase *pp
+) {
+ icmS15Fixed16Array *p = (icmS15Fixed16Array *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmS15Fixed16Array(
+ icc *icp
+) {
+ icmS15Fixed16Array *p;
+ if ((p = (icmS15Fixed16Array *) icp->al->calloc(icp->al,1,sizeof(icmS15Fixed16Array))) == NULL)
+ return NULL;
+ p->ttype = icSigS15Fixed16ArrayType;
+ p->refcount = 1;
+ p->get_size = icmS15Fixed16Array_get_size;
+ p->read = icmS15Fixed16Array_read;
+ p->write = icmS15Fixed16Array_write;
+ p->dump = icmS15Fixed16Array_dump;
+ p->allocate = icmS15Fixed16Array_allocate;
+ p->del = icmS15Fixed16Array_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Data conversion support functions */
+static int write_XYZNumber(icmXYZNumber *p, char *d) {
+ int rv;
+ if ((rv = write_S15Fixed16Number(p->X, d + 0)) != 0)
+ return rv;
+ if ((rv = write_S15Fixed16Number(p->Y, d + 4)) != 0)
+ return rv;
+ if ((rv = write_S15Fixed16Number(p->Z, d + 8)) != 0)
+ return rv;
+ return 0;
+}
+
+static int read_XYZNumber(icmXYZNumber *p, char *d) {
+ p->X = read_S15Fixed16Number(d + 0);
+ p->Y = read_S15Fixed16Number(d + 4);
+ p->Z = read_S15Fixed16Number(d + 8);
+ return 0;
+}
+
+
+/* Helper: Return a string that shows the XYZ number value */
+static char *string_XYZNumber(icmXYZNumber *p) {
+ static char buf[40];
+
+ sprintf(buf,"%f, %f, %f", p->X, p->Y, p->Z);
+ return buf;
+}
+
+/* Helper: Return a string that shows the XYZ number value, */
+/* and the Lab D50 number in paren. Note the buffer will be re-used on every call. */
+static char *string_XYZNumber_and_Lab(icmXYZNumber *p) {
+ static char buf[100];
+ double lab[3];
+ lab[0] = p->X;
+ lab[1] = p->Y;
+ lab[2] = p->Z;
+ icmXYZ2Lab(&icmD50, lab, lab);
+ snprintf(buf,sizeof(buf),"%f, %f, %f [Lab %f, %f, %f]", p->X, p->Y, p->Z, lab[0], lab[1], lab[2]);
+ return buf;
+}
+
+/* icmXYZArray object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmXYZArray_get_size(
+ icmBase *pp
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 12); /* 12 bytes for each XYZ */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmXYZArray_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, size;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmXYZArray_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmXYZArray_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmXYZArray_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 8)/12; /* Number of elements in the array */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmXYZArray_read: Wrong tag type for icmXYZArray");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < size; i++, bp += 12) {
+ read_XYZNumber(&p->data[i], bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmXYZArray_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmXYZArray_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmXYZArray_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmXYZArray_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ for (i = 0; i < p->size; i++, bp += 12) {
+ if ((rv = write_XYZNumber(&p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmXYZArray_write: write_XYZumber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmXYZArray_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmXYZArray_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"XYZArray:\n");
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++) {
+ op->gprintf(op," %lu: %s\n",i,string_XYZNumber_and_Lab(&p->data[i]));
+
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmXYZArray_allocate(
+ icmBase *pp
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(icmXYZNumber))) {
+ sprintf(icp->err,"icmXYZArray_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmXYZNumber *) icp->al->malloc(icp->al, sat_mul(p->size, sizeof(icmXYZNumber)))) == NULL) {
+ sprintf(icp->err,"icmXYZArray_alloc: malloc() of icmXYZArray data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmXYZArray_delete(
+ icmBase *pp
+) {
+ icmXYZArray *p = (icmXYZArray *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmXYZArray(
+ icc *icp
+) {
+ icmXYZArray *p;
+ if ((p = (icmXYZArray *) icp->al->calloc(icp->al,1,sizeof(icmXYZArray))) == NULL)
+ return NULL;
+ p->ttype = icSigXYZArrayType;
+ p->refcount = 1;
+ p->get_size = icmXYZArray_get_size;
+ p->read = icmXYZArray_read;
+ p->write = icmXYZArray_write;
+ p->dump = icmXYZArray_dump;
+ p->allocate = icmXYZArray_allocate;
+ p->del = icmXYZArray_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmCurve object */
+
+/* Do a forward lookup through the curve */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmCurve_lookup_fwd(
+ icmCurve *p,
+ double *out,
+ double *in
+) {
+ int rv = 0;
+ if (p->flag == icmCurveLin) {
+ *out = *in;
+ } else if (p->flag == icmCurveGamma) {
+ double val = *in;
+ if (val <= 0.0)
+ *out = 0.0;
+ else
+ *out = pow(val, p->data[0]);
+ } else if (p->size == 0) { /* Table of 0 size */
+ *out = *in;
+ } else { /* Use linear interpolation */
+ unsigned int ix;
+ double val, w;
+ double inputEnt_1 = (double)(p->size-1);
+
+ val = *in * inputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > inputEnt_1) {
+ val = inputEnt_1;
+ rv |= 1;
+ }
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (p->size-2))
+ ix = (p->size-2);
+ w = val - (double)ix; /* weight */
+ val = p->data[ix];
+ *out = val + w * (p->data[ix+1] - val);
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - */
+/* Support for reverse interpolation of 1D lookup tables */
+
+/* Create a reverse curve lookup acceleration table */
+/* return non-zero on error, 2 = malloc error. */
+static int icmTable_setup_bwd(
+ icc *icp, /* Base icc object */
+ icmRevTable *rt, /* Reverse table data to setup */
+ unsigned int size, /* Size of fwd table */
+ double *data /* Table */
+) {
+ unsigned int i;
+
+ rt->size = size; /* Stash pointers to these away */
+ rt->data = data;
+
+ /* Find range of output values */
+ rt->rmin = 1e300;
+ rt->rmax = -1e300;
+ for (i = 0; i < rt->size; i++) {
+ if (rt->data[i] > rt->rmax)
+ rt->rmax = rt->data[i];
+ if (rt->data[i] < rt->rmin)
+ rt->rmin = rt->data[i];
+ }
+
+ /* Decide on reverse granularity */
+ rt->rsize = sat_add(rt->size,2)/2;
+ rt->qscale = (double)rt->rsize/(rt->rmax - rt->rmin); /* Scale factor to quantize to */
+
+ if (ovr_mul(rt->size, sizeof(unsigned int *))) {
+ return 2;
+ }
+ /* Initialize the reverse lookup structures, and get overall min/max */
+ if ((rt->rlists = (unsigned int **) icp->al->calloc(icp->al, rt->rsize, sizeof(unsigned int *))) == NULL) {
+ return 2;
+ }
+
+ /* Assign each output value range bucket lists it intersects */
+ for (i = 0; i < (rt->size-1); i++) {
+ unsigned int s, e, j; /* Start and end indexes (inclusive) */
+ s = (unsigned int)((rt->data[i] - rt->rmin) * rt->qscale);
+ e = (unsigned int)((rt->data[i+1] - rt->rmin) * rt->qscale);
+ if (s >= rt->rsize)
+ s = rt->rsize-1;
+ if (e >= rt->rsize)
+ e = rt->rsize-1;
+ if (s > e) { /* swap */
+ unsigned int t;
+ t = s; s = e; e = t;
+ }
+
+ /* For all buckets that may contain this output range, add index of this output */
+ for (j = s; j <= e; j++) {
+ unsigned int as; /* Allocation size */
+ unsigned int nf; /* Next free slot */
+ if (rt->rlists[j] == NULL) { /* No allocation */
+ as = 5; /* Start with space for 5 */
+ if ((rt->rlists[j] = (unsigned int *) icp->al->calloc(icp->al, as, sizeof(unsigned int))) == NULL) {
+ return 2;
+ }
+ rt->rlists[j][0] = as;
+ nf = rt->rlists[j][1] = 2;
+ } else {
+ as = rt->rlists[j][0]; /* Allocate space for this list */
+ nf = rt->rlists[j][1]; /* Next free location in list */
+ if (nf >= as) { /* need to expand space */
+ if ((as = sat_mul(as, 2)) == UINT_MAX
+ || ovr_mul(as, sizeof(unsigned int))) {
+ return 2;
+ }
+ rt->rlists[j] = (unsigned int *) icp->al->realloc(icp->al,rt->rlists[j], as * sizeof(unsigned int));
+ if (rt->rlists[j] == NULL) {
+ return 2;
+ }
+ rt->rlists[j][0] = as;
+ }
+ }
+ rt->rlists[j][nf++] = i;
+ rt->rlists[j][1] = nf;
+ }
+ }
+ rt->inited = 1;
+ return 0;
+}
+
+/* Free up any data */
+static void icmTable_delete_bwd(
+ icc *icp, /* Base icc */
+ icmRevTable *rt /* Reverse table data to setup */
+) {
+ if (rt->inited != 0) {
+ while (rt->rsize > 0)
+ icp->al->free(icp->al, rt->rlists[--rt->rsize]);
+ icp->al->free(icp->al, rt->rlists);
+ rt->size = 0; /* Don't keep these */
+ rt->data = NULL;
+ }
+}
+
+/* Do a reverse lookup through the curve */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmTable_lookup_bwd(
+ icmRevTable *rt,
+ double *out,
+ double *in
+) {
+ int rv = 0;
+ unsigned int ix, k, i;
+ double oval, ival = *in, val;
+ double rsize_1;
+
+ /* Find appropriate reverse list */
+ rsize_1 = (double)(rt->rsize-1);
+ val = ((ival - rt->rmin) * rt->qscale);
+ if (val < 0.0)
+ val = 0.0;
+ else if (val > rsize_1)
+ val = rsize_1;
+ ix = (unsigned int)floor(val); /* Coordinate */
+
+ if (ix > (rt->size-2))
+ ix = (rt->size-2);
+ if (rt->rlists[ix] != NULL) { /* There is a list of fwd candidates */
+ /* For each candidate forward range */
+ for (i = 2; i < rt->rlists[ix][1]; i++) { /* For all fwd indexes */
+ double lv,hv;
+ k = rt->rlists[ix][i]; /* Base index */
+ lv = rt->data[k];
+ hv = rt->data[k+1];
+ if ((ival >= lv && ival <= hv) /* If this slot contains output value */
+ || (ival >= hv && ival <= lv)) {
+ /* Reverse linear interpolation */
+ if (hv == lv) { /* Technically non-monotonic - due to quantization ? */
+ oval = (k + 0.5)/(rt->size-1.0);
+ } else
+ oval = (k + ((ival - lv)/(hv - lv)))/(rt->size-1.0);
+ /* If we kept looking, we would find multiple */
+ /* solution for non-monotonic curve */
+ *out = oval;
+ return rv;
+ }
+ }
+ }
+
+ /* We have failed to find an exact value, so return the nearest value */
+ /* (This is slow !) */
+ val = fabs(ival - rt->data[0]);
+ for (k = 0, i = 1; i < rt->size; i++) {
+ double er;
+ er = fabs(ival - rt->data[i]);
+ if (er < val) { /* new best */
+ val = er;
+ k = i;
+ }
+ }
+ *out = k/(rt->size-1.0);
+ rv |= 1;
+ return rv;
+}
+
+
+/* - - - - - - - - - - - - */
+
+/* Do a reverse lookup through the curve */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmCurve_lookup_bwd(
+ icmCurve *p,
+ double *out,
+ double *in
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+ if (p->flag == icmCurveLin) {
+ *out = *in;
+ } else if (p->flag == icmCurveGamma) {
+ double val = *in;
+ if (val <= 0.0)
+ *out = 0.0;
+ else
+ *out = pow(val, 1.0/p->data[0]);
+ } else if (p->size == 0) { /* Table of 0 size */
+ *out = *in;
+ } else { /* Use linear interpolation */
+ if (p->rt.inited == 0) {
+ rv = icmTable_setup_bwd(icp, &p->rt, p->size, p->data);
+ if (rv != 0) {
+ sprintf(icp->err,"icmCurve_lookup: Malloc failure in reverse lookup init.");
+ return icp->errc = rv;
+ }
+ }
+ rv = icmTable_lookup_bwd(&p->rt, out, in);
+ }
+ return rv;
+}
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmCurve_get_size(
+ icmBase *pp
+) {
+ icmCurve *p = (icmCurve *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 12); /* 12 bytes for tag, padding and count */
+ len = sat_addmul(len, p->size, 2); /* 2 bytes for each UInt16 */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmCurve_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmCurve *p = (icmCurve *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i;
+ char *bp, *buf, *end;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmCurve_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmCurve_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmCurve_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmCurve_read: Wrong tag type for icmCurve");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ p->size = read_UInt32Number(bp+8);
+ bp = bp + 12;
+
+ /* Set flag up before allocating */
+ if (p->size == 0) { /* Linear curve */
+ p->flag = icmCurveLin;
+ } else if (p->size == 1) { /* Gamma curve */
+ p->flag = icmCurveGamma;
+ } else {
+ p->flag = icmCurveSpec;
+ if (p->size > (len - 12)/2) {
+ sprintf(icp->err,"icmCurve_read: size overflow");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ if (p->flag == icmCurveGamma) { /* Gamma curve */
+ if (bp > end || 1 > (end - bp)) {
+ sprintf(icp->err,"icmCurve_read: Data too short for curve gamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->data[0] = read_U8Fixed8Number(bp);
+ } else if (p->flag == icmCurveSpec) {
+ /* Read all the data from the buffer */
+ for (i = 0; i < p->size; i++, bp += 2) {
+ if (bp > end || 2 > (end - bp)) {
+ sprintf(icp->err,"icmCurve_read: Data too short for curve value");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->data[i] = read_DCS16Number(bp);
+ }
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmCurve_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmCurve *p = (icmCurve *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmCurve_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmCurve_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmCurve_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write count */
+ if ((rv = write_UInt32Number(p->size,bp+8)) != 0) {
+ sprintf(icp->err,"icmCurve_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write all the data to the buffer */
+ bp += 12; /* Skip padding */
+ if (p->flag == icmCurveLin) {
+ if (p->size != 0) {
+ sprintf(icp->err,"icmCurve_write: Must be exactly 0 entry for Linear");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ } else if (p->flag == icmCurveGamma) {
+ if (p->size != 1) {
+ sprintf(icp->err,"icmCurve_write: Must be exactly 1 entry for Gamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if ((rv = write_U8Fixed8Number(p->data[0],bp)) != 0) {
+ sprintf(icp->err,"icmCurve_write: write_U8Fixed8umber(%f) failed",p->data[0]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ } else if (p->flag == icmCurveSpec) {
+ if (p->size < 2) {
+ sprintf(icp->err,"icmCurve_write: Must be 2 or more entries for Specified curve");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ for (i = 0; i < p->size; i++, bp += 2) {
+ if ((rv = write_DCS16Number(p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmCurve_write: write_UInt16umber(%f) failed",p->data[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmCurve_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmCurve_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmCurve *p = (icmCurve *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Curve:\n");
+
+ if (p->flag == icmCurveLin) {
+ op->gprintf(op," Curve is linear\n");
+ } else if (p->flag == icmCurveGamma) {
+ op->gprintf(op," Curve is gamma of %f\n",p->data[0]);
+ } else {
+ op->gprintf(op," No. elements = %lu\n",p->size);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->size; i++)
+ op->gprintf(op," %3lu: %f\n",i,p->data[i]);
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmCurve_allocate(
+ icmBase *pp
+) {
+ icmCurve *p = (icmCurve *)pp;
+ icc *icp = p->icp;
+
+ if (p->flag == icmCurveUndef) {
+ sprintf(icp->err,"icmCurve_alloc: flag not set");
+ return icp->errc = 1;
+ } else if (p->flag == icmCurveLin) {
+ p->size = 0;
+ } else if (p->flag == icmCurveGamma) {
+ p->size = 1;
+ }
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(double))) {
+ sprintf(icp->err,"icmCurve_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (double *) icp->al->calloc(icp->al, p->size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmCurve_alloc: malloc() of icmCurve data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmCurve_delete(
+ icmBase *pp
+) {
+ icmCurve *p = (icmCurve *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icmTable_delete_bwd(icp, &p->rt); /* Free reverse table info */
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmCurve(
+ icc *icp
+) {
+ icmCurve *p;
+ if ((p = (icmCurve *) icp->al->calloc(icp->al,1,sizeof(icmCurve))) == NULL)
+ return NULL;
+ p->ttype = icSigCurveType;
+ p->refcount = 1;
+ p->get_size = icmCurve_get_size;
+ p->read = icmCurve_read;
+ p->write = icmCurve_write;
+ p->dump = icmCurve_dump;
+ p->allocate = icmCurve_allocate;
+ p->del = icmCurve_delete;
+ p->icp = icp;
+
+ p->lookup_fwd = icmCurve_lookup_fwd;
+ p->lookup_bwd = icmCurve_lookup_bwd;
+
+ p->rt.inited = 0;
+
+ p->flag = icmCurveUndef;
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmData object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmData_get_size(
+ icmBase *pp
+) {
+ icmData *p = (icmData *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 12); /* 12 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 1); /* 1 byte for each data element */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmData_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmData *p = (icmData *)pp;
+ icc *icp = p->icp;
+ int rv;
+ unsigned size, f;
+ char *bp, *buf;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmData_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmData_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmData_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = size = (len - 12)/1; /* Number of elements in the array */
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmData_read: Wrong tag type for icmData");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Read the data type flag */
+ f = read_UInt32Number(bp+8);
+ if (f == 0) {
+ p->flag = icmDataASCII;
+ } else if (f == 1) {
+ p->flag = icmDataBin;
+#ifndef ICM_STRICT /* Profile maker sometimes has a problem */
+ } else if (f == 0x01000000) {
+ p->flag = icmDataBin;
+#endif
+ } else {
+ sprintf(icp->err,"icmData_read: Unknown flag value 0x%x",f);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 12; /* Skip padding and flag */
+
+ if (p->size > 0) {
+ if (p->flag == icmDataASCII) {
+ if ((rv = check_null_string(bp,p->size)) == 1) {
+ sprintf(icp->err,"icmData_read: ACSII is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ }
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ memmove((void *)p->data, (void *)bp, p->size);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmData_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmData *p = (icmData *)pp;
+ icc *icp = p->icp;
+ unsigned int len, f;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmData_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmData_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmData_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ switch(p->flag) {
+ case icmDataASCII:
+ f = 0;
+ break;
+ case icmDataBin:
+ f = 1;
+ break;
+ default:
+ sprintf(icp->err,"icmData_write: Unknown Data Flag value");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Write data flag descriptor to the buffer */
+ if ((rv = write_UInt32Number(f,bp+8)) != 0) {
+ sprintf(icp->err,"icmData_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 12; /* Skip padding */
+
+ if (p->data != NULL) {
+ if (p->flag == icmDataASCII) {
+ if ((rv = check_null_string((char *)p->data, p->size)) == 1) {
+ sprintf(icp->err,"icmData_write: ASCII is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ }
+ memmove((void *)bp, (void *)p->data, p->size);
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmData_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmData_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmData *p = (icmData *)pp;
+ unsigned int i, r, c, ii, size = 0;
+ int ph = 0; /* Phase */
+
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Data:\n");
+ switch(p->flag) {
+ case icmDataASCII:
+ op->gprintf(op," ASCII data\n");
+ size = p->size > 0 ? p->size-1 : 0;
+ break;
+ case icmDataBin:
+ op->gprintf(op," Binary data\n");
+ size = p->size;
+ break;
+ case icmDataUndef:
+ op->gprintf(op," Undefined data\n");
+ size = p->size;
+ break;
+ }
+ op->gprintf(op," No. elements = %lu\n",p->size);
+
+ ii = i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+
+ c = 1;
+ if (ph != 0) { /* Print ASCII under binary */
+ op->gprintf(op," ");
+ i = ii;
+ c += 11;
+ } else {
+ op->gprintf(op," 0x%04lx: ",i);
+ ii = i;
+ c += 10;
+ }
+ while (i < size && c < 75) {
+ if (p->flag == icmDataASCII) {
+ if (isprint(p->data[i])) {
+ op->gprintf(op,"%c",p->data[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->data[i]);
+ c += 4;
+ }
+ } else {
+ if (ph == 0)
+ op->gprintf(op,"%02x ",p->data[i]);
+ else {
+ if (isprint(p->data[i]))
+ op->gprintf(op," %c ",p->data[i]);
+ else
+ op->gprintf(op," ",p->data[i]);
+ }
+ c += 3;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ if (verb > 2 && p->flag != icmDataASCII && ph == 0)
+ ph = 1;
+ else
+ ph = 0;
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmData_allocate(
+ icmBase *pp
+) {
+ icmData *p = (icmData *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(unsigned char))) {
+ sprintf(icp->err,"icmData_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (unsigned char *) icp->al->calloc(icp->al, p->size, sizeof(unsigned char))) == NULL) {
+ sprintf(icp->err,"icmData_alloc: malloc() of icmData data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmData_delete(
+ icmBase *pp
+) {
+ icmData *p = (icmData *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmData(
+ icc *icp
+) {
+ icmData *p;
+ if ((p = (icmData *) icp->al->calloc(icp->al,1,sizeof(icmData))) == NULL)
+ return NULL;
+ p->ttype = icSigDataType;
+ p->refcount = 1;
+ p->get_size = icmData_get_size;
+ p->read = icmData_read;
+ p->write = icmData_write;
+ p->dump = icmData_dump;
+ p->allocate = icmData_allocate;
+ p->del = icmData_delete;
+ p->icp = icp;
+
+ p->flag = icmDataUndef;
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmText object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmText_get_size(
+ icmBase *pp
+) {
+ icmText *p = (icmText *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addmul(len, p->size, 1); /* 1 byte for each character element (inc. null) */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmText_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmText *p = (icmText *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf;
+
+ if (len < 8) {
+ sprintf(icp->err,"icmText_read: Tag too short to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmText_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmText_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = (len - 8)/1; /* Number of elements in the array */
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmText_read: Wrong tag type for icmText");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp = bp + 8;
+
+ if (p->size > 0) {
+ if ((rv = check_null_string(bp,p->size)) == 1) {
+ sprintf(icp->err,"icmText_read: text is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ memmove((void *)p->data, (void *)bp, p->size);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmText_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmText *p = (icmText *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmText_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmText_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmText_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp = bp + 8;
+
+ if (p->data != NULL) {
+ if ((rv = check_null_string(p->data, p->size)) == 1) {
+ sprintf(icp->err,"icmText_write: text is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ memmove((void *)bp, (void *)p->data, p->size);
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmText_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmText_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmText *p = (icmText *)pp;
+ unsigned int i, r, c, size;
+
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Text:\n");
+ op->gprintf(op," No. chars = %lu\n",p->size);
+
+ size = p->size > 0 ? p->size-1 : 0;
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 75) {
+ if (isprint(p->data[i])) {
+ op->gprintf(op,"%c",p->data[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->data[i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmText_allocate(
+ icmBase *pp
+) {
+ icmText *p = (icmText *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(char))) {
+ sprintf(icp->err,"icmText_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (char *) icp->al->calloc(icp->al, p->size, sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmText_alloc: malloc() of icmText data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmText_delete(
+ icmBase *pp
+) {
+ icmText *p = (icmText *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmText(
+ icc *icp
+) {
+ icmText *p;
+ if ((p = (icmText *) icp->al->calloc(icp->al,1,sizeof(icmText))) == NULL)
+ return NULL;
+ p->ttype = icSigTextType;
+ p->refcount = 1;
+ p->get_size = icmText_get_size;
+ p->read = icmText_read;
+ p->write = icmText_write;
+ p->dump = icmText_dump;
+ p->allocate = icmText_allocate;
+ p->del = icmText_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Data conversion support functions */
+static int write_DateTimeNumber(icmDateTimeNumber *p, char *d) {
+ int rv;
+ if (p->year < 1900 || p->year > 3000
+ || p->month == 0 || p->month > 12
+ || p->day == 0 || p->day > 31
+ || p->hours > 23
+ || p->minutes > 59
+ || p->seconds > 59)
+ return 1;
+
+ if ((rv = write_UInt16Number(p->year, d + 0)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->month, d + 2)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->day, d + 4)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->hours, d + 6)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->minutes, d + 8)) != 0)
+ return rv;
+ if ((rv = write_UInt16Number(p->seconds, d + 10)) != 0)
+ return rv;
+ return 0;
+}
+
+static int read_DateTimeNumber(icmDateTimeNumber *p, char *d) {
+
+ p->year = read_UInt16Number(d + 0);
+ p->month = read_UInt16Number(d + 2);
+ p->day = read_UInt16Number(d + 4);
+ p->hours = read_UInt16Number(d + 6);
+ p->minutes = read_UInt16Number(d + 8);
+ p->seconds = read_UInt16Number(d + 10);
+
+ /* Sanity check the date and time */
+ if (p->year >= 1900 && p->year <= 3000
+ && p->month != 0 && p->month <= 12
+ && p->day != 0 && p->day <= 31
+ && p->hours <= 23
+ && p->minutes <= 59
+ && p->seconds <= 59)
+ return 0;
+
+#ifdef NEVER
+ printf("Raw year = %d, month = %d, day = %d\n",p->year, p->month, p->day);
+ printf("Raw hour = %d, minutes = %d, seconds = %d\n", p->hours, p->minutes, p->seconds);
+#endif /* NEVER */
+
+#ifdef ICM_STRICT
+ return 1; /* Not legal */
+
+#else
+ /* Be more forgiving */
+
+ /* Check for Adobe problem */
+ if (p->month >= 1900 && p->month <= 3000
+ && p->year != 0 && p->year <= 12
+ && p->hours != 0 && p->hours <= 31
+ && p->day <= 23
+ && p->seconds <= 59
+ && p->minutes <= 59) {
+ unsigned int tt;
+
+ /* Correct Adobe's faulty profile */
+ tt = p->month; p->month = p->year; p->year = tt;
+ tt = p->hours; p->hours = p->day; p->day = tt;
+ tt = p->seconds; p->seconds = p->minutes; p->minutes = tt;
+
+ return 0;
+ }
+
+ /* Hmm. some other sort of corruption. Limit values to sane */
+ if (p->year < 1900) {
+ if (p->year < 100) /* Hmm. didn't use 4 digit year, guess it's 19xx ? */
+ p->year += 1900;
+ else
+ p->year = 1900;
+ } else if (p->year > 3000)
+ p->year = 3000;
+
+ if (p->month == 0)
+ p->month = 1;
+ else if (p->month > 12)
+ p->month = 12;
+
+ if (p->day == 0)
+ p->day = 1;
+ else if (p->day > 31)
+ p->day = 31;
+
+ if (p->hours > 23)
+ p->hours = 23;
+
+ if (p->minutes > 59)
+ p->minutes = 59;
+
+ if (p->seconds > 59)
+ p->seconds = 59;
+
+ return 0;
+#endif
+}
+
+/* Return a string that shows the given date and time */
+static char *string_DateTimeNumber(icmDateTimeNumber *p) {
+ static const char *mstring[13] = {"Bad", "Jan","Feb","Mar","Apr","May","Jun",
+ "Jul","Aug","Sep","Oct","Nov","Dec"};
+ static char buf[80];
+
+ sprintf(buf,"%d %s %4d, %d:%02d:%02d",
+ p->day, mstring[p->month > 12 ? 0 : p->month], p->year,
+ p->hours, p->minutes, p->seconds);
+ return buf;
+}
+
+/* Set the DateTime structure to the current date and time */
+static void setcur_DateTimeNumber(icmDateTimeNumber *p) {
+ time_t cclk;
+ struct tm *ctm;
+
+ cclk = time(NULL);
+ ctm = localtime(&cclk);
+
+ p->year = ctm->tm_year + 1900;
+ p->month = ctm->tm_mon + 1;
+ p->day = ctm->tm_mday;
+ p->hours = ctm->tm_hour;
+ p->minutes = ctm->tm_min;
+ p->seconds = ctm->tm_sec;
+}
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmDateTimeNumber_get_size(
+ icmBase *pp
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 12); /* 12 bytes for Date & Time */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmDateTimeNumber_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf;
+
+ if (len < 20) {
+ sprintf(icp->err,"icmDateTimeNumber_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmDateTimeNumber_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmDateTimeNumber_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmDateTimeNumber_read: Wrong tag type for icmDateTimeNumber");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ /* Read the time and date from buffer */
+ if((rv = read_DateTimeNumber(p, bp)) != 0) {
+ sprintf(icp->err,"icmDateTimeNumber_read: Corrupted DateTime");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmDateTimeNumber_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmDateTimeNumber_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmDateTimeNumber_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmDateTimeNumber_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write all the data to the buffer */
+ bp += 8; /* Skip padding */
+ if ((rv = write_DateTimeNumber(p, bp)) != 0) {
+ sprintf(icp->err,"icmDateTimeNumber_write: write_DateTimeNumber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmDateTimeNumber_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmDateTimeNumber_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"DateTimeNumber:\n");
+ op->gprintf(op," Date = %s\n", string_DateTimeNumber(p));
+}
+
+/* Allocate variable sized data elements */
+static int icmDateTimeNumber_allocate(
+ icmBase *pp
+) {
+ /* Nothing to do */
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmDateTimeNumber_delete(
+ icmBase *pp
+) {
+ icmDateTimeNumber *p = (icmDateTimeNumber *)pp;
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmDateTimeNumber(
+ icc *icp
+) {
+ icmDateTimeNumber *p;
+ if ((p = (icmDateTimeNumber *) icp->al->calloc(icp->al,1,sizeof(icmDateTimeNumber))) == NULL)
+ return NULL;
+ p->ttype = icSigDateTimeType;
+ p->refcount = 1;
+ p->get_size = icmDateTimeNumber_get_size;
+ p->read = icmDateTimeNumber_read;
+ p->write = icmDateTimeNumber_write;
+ p->dump = icmDateTimeNumber_dump;
+ p->allocate = icmDateTimeNumber_allocate;
+ p->del = icmDateTimeNumber_delete;
+ p->icp = icp;
+
+ setcur_DateTimeNumber(p); /* Default to current date and time */
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmLut object */
+
+/* Check if the matrix is non-zero */
+static int icmLut_nu_matrix(
+ icmLut *p /* Pointer to Lut object */
+) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) { /* Rows */
+ for (i = 0; i < 3; i++) { /* Columns */
+ if ( (i == j && p->e[j][i] != 1.0)
+ || (i != j && p->e[j][i] != 0.0))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* return the locations of the minimum and */
+/* maximum values of the given channel, in the clut */
+static void icmLut_min_max(
+ icmLut *p, /* Pointer to Lut object */
+ double *minp, /* Return position of min/max */
+ double *maxp,
+ int chan /* Channel, -1 for average of all */
+) {
+ double *tp;
+ double minv, maxv; /* Values */
+ unsigned int e, ee, f;
+ int gc[MAX_CHAN]; /* Grid coordinate */
+
+ minv = 1e6;
+ maxv = -1e6;
+
+ for (e = 0; e < p->inputChan; e++)
+ gc[e] = 0; /* init coords */
+
+ /* Search the whole table */
+ for (tp = p->clutTable, e = 0; e < p->inputChan; tp += p->outputChan) {
+ double v;
+ if (chan == -1) {
+ for (v = 0.0, f = 0; f < p->outputChan; f++)
+ v += tp[f];
+ } else {
+ v = tp[chan];
+ }
+ if (v < minv) {
+ minv = v;
+ for (ee = 0; ee < p->inputChan; ee++)
+ minp[ee] = gc[ee]/(p->clutPoints-1.0);
+ }
+ if (v > maxv) {
+ maxv = v;
+ for (ee = 0; ee < p->inputChan; ee++)
+ maxp[ee] = gc[ee]/(p->clutPoints-1.0);
+ }
+
+ /* Increment coord */
+ for (e = 0; e < p->inputChan; e++) {
+ if (++gc[e] < p->clutPoints)
+ break; /* No carry */
+ gc[e] = 0;
+ }
+ }
+}
+
+/* Convert XYZ throught Luts matrix */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmLut_lookup_matrix(
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[outputChan] in ICC order - see Table 39 in 6.5.5 */
+double *in /* Input array[inputChan] */
+) {
+ double t0,t1; /* Take care if out == in */
+ t0 = p->e[0][0] * in[0] + p->e[0][1] * in[1] + p->e[0][2] * in[2];
+ t1 = p->e[1][0] * in[0] + p->e[1][1] * in[1] + p->e[1][2] * in[2];
+ out[2] = p->e[2][0] * in[0] + p->e[2][1] * in[1] + p->e[2][2] * in[2];
+ out[0] = t0;
+ out[1] = t1;
+
+ return 0;
+}
+
+/* Convert normalized numbers though this Luts input tables. */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmLut_lookup_input(
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[inputChan] */
+double *in /* Input array[inputChan] */
+) {
+ int rv = 0;
+ unsigned int ix, n;
+ double inputEnt_1 = (double)(p->inputEnt-1);
+ double *table = p->inputTable;
+
+ if (p->inputEnt == 0) { /* Hmm. */
+ for (n = 0; n < p->inputChan; n++)
+ out[n] = in[n];
+ } else {
+ /* Use linear interpolation */
+ for (n = 0; n < p->inputChan; n++, table += p->inputEnt) {
+ double val, w;
+ val = in[n] * inputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > inputEnt_1) {
+ val = inputEnt_1;
+ rv |= 1;
+ }
+ ix = (unsigned int)floor(val); /* Grid coordinate */
+ if (ix > (p->inputEnt-2))
+ ix = (p->inputEnt-2);
+ w = val - (double)ix; /* weight */
+ val = table[ix];
+ out[n] = val + w * (table[ix+1] - val);
+ }
+ }
+ return rv;
+}
+
+/* Convert normalized numbers though this Luts multi-dimensional table. */
+/* using multi-linear interpolation. */
+static int icmLut_lookup_clut_nl(
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[inputChan] */
+double *in /* Input array[outputChan] */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+ double *gp; /* Pointer to grid cube base */
+ double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
+ double *gw, GW[1 << 8]; /* weight for each grid cube corner */
+
+ if (p->inputChan <= 8) {
+ gw = GW; /* Use stack allocation */
+ } else {
+ if ((gw = (double *) icp->al->malloc(icp->al, sat_mul((1 << p->inputChan), sizeof(double)))) == NULL) {
+ sprintf(icp->err,"icmLut_lookup_clut: malloc() failed");
+ return icp->errc = 2;
+ }
+ }
+
+ /* We are using an multi-linear (ie. Trilinear for 3D input) interpolation. */
+ /* The implementation here uses more multiplies that some other schemes, */
+ /* (for instance, see "Tri-Linear Interpolation" by Steve Hill, */
+ /* Graphics Gems IV, page 521), but has less involved bookeeping, */
+ /* needs less local storage for intermediate output values, does fewer */
+ /* output and intermediate value reads, and fp multiplies are fast on */
+ /* todays processors! */
+
+ /* Compute base index into grid and coordinate offsets */
+ {
+ unsigned int e;
+ double clutPoints_1 = (double)(p->clutPoints-1);
+ int clutPoints_2 = p->clutPoints-2;
+ gp = p->clutTable; /* Base of grid array */
+
+ for (e = 0; e < p->inputChan; e++) {
+ unsigned int x;
+ double val;
+ val = in[e] * clutPoints_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > clutPoints_1) {
+ val = clutPoints_1;
+ rv |= 1;
+ }
+ x = (unsigned int)floor(val); /* Grid coordinate */
+ if (x > clutPoints_2)
+ x = clutPoints_2;
+ co[e] = val - (double)x; /* 1.0 - weight */
+ gp += x * p->dinc[e]; /* Add index offset for base of cube */
+ }
+ }
+ /* Compute corner weights needed for interpolation */
+ {
+ unsigned int e;
+ int i, g = 1;
+ gw[0] = 1.0;
+ for (e = 0; e < p->inputChan; e++) {
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * co[e];
+ gw[i] *= (1.0 - co[e]);
+ }
+ g *= 2;
+ }
+ }
+ /* Now compute the output values */
+ {
+ int i;
+ unsigned int f;
+ double w = gw[0];
+ double *d = gp + p->dcube[0];
+ for (f = 0; f < p->outputChan; f++) /* Base of cube */
+ out[f] = w * d[f];
+ for (i = 1; i < (1 << p->inputChan); i++) { /* For all other corners of cube */
+ w = gw[i]; /* Strength reduce */
+ d = gp + p->dcube[i];
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * d[f];
+ }
+ }
+ if (gw != GW)
+ icp->al->free(icp->al, (void *)gw);
+ return rv;
+}
+
+/* Convert normalized numbers though this Luts multi-dimensional table */
+/* using simplex interpolation. */
+static int icmLut_lookup_clut_sx(
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[inputChan] */
+double *in /* Input array[outputChan] */
+) {
+ int rv = 0;
+ double *gp; /* Pointer to grid cube base */
+ double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
+ int si[MAX_CHAN]; /* co[] Sort index, [0] = smalest */
+
+ /* We are using a simplex (ie. tetrahedral for 3D input) interpolation. */
+ /* This method is more appropriate for XYZ/RGB/CMYK input spaces, */
+
+ /* Compute base index into grid and coordinate offsets */
+ {
+ unsigned int e;
+ double clutPoints_1 = (double)(p->clutPoints-1);
+ int clutPoints_2 = p->clutPoints-2;
+ gp = p->clutTable; /* Base of grid array */
+
+ for (e = 0; e < p->inputChan; e++) {
+ unsigned int x;
+ double val;
+ val = in[e] * clutPoints_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > clutPoints_1) {
+ val = clutPoints_1;
+ rv |= 1;
+ }
+ x = (unsigned int)floor(val); /* Grid coordinate */
+ if (x > clutPoints_2)
+ x = clutPoints_2;
+ co[e] = val - (double)x; /* 1.0 - weight */
+ gp += x * p->dinc[e]; /* Add index offset for base of cube */
+ }
+ }
+#ifdef NEVER
+ /* Do selection sort on coordinates, smallest to largest. */
+ {
+ int e, f;
+ for (e = 0; e < p->inputChan; e++)
+ si[e] = e; /* Initial unsorted indexes */
+ for (e = 0; e < (p->inputChan-1); e++) {
+ double cosn;
+ cosn = co[si[e]]; /* Current smallest value */
+ for (f = e+1; f < p->inputChan; f++) { /* Check against rest */
+ int tt;
+ tt = si[f];
+ if (cosn > co[tt]) {
+ si[f] = si[e]; /* Exchange */
+ si[e] = tt;
+ cosn = co[tt];
+ }
+ }
+ }
+ }
+#else
+ /* Do insertion sort on coordinates, smallest to largest. */
+ {
+ int f, vf;
+ unsigned int e;
+ double v;
+ for (e = 0; e < p->inputChan; e++)
+ si[e] = e; /* Initial unsorted indexes */
+
+ for (e = 1; e < p->inputChan; e++) {
+ f = e;
+ v = co[si[f]];
+ vf = f;
+ while (f > 0 && co[si[f-1]] > v) {
+ si[f] = si[f-1];
+ f--;
+ }
+ si[f] = vf;
+ }
+ }
+#endif
+ /* Now compute the weightings, simplex vertices and output values */
+ {
+ unsigned int e, f;
+ double w; /* Current vertex weight */
+
+ w = 1.0 - co[si[p->inputChan-1]]; /* Vertex at base of cell */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] = w * gp[f];
+
+ for (e = p->inputChan-1; e > 0; e--) { /* Middle verticies */
+ w = co[si[e]] - co[si[e-1]];
+ gp += p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * gp[f];
+ }
+
+ w = co[si[0]];
+ gp += p->dinc[si[0]]; /* Far corner from base of cell */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * gp[f];
+ }
+ return rv;
+}
+
+#ifdef NEVER // ~~~99 development code
+
+/* Convert normalized numbers though this Luts multi-dimensional table */
+/* using optimised simplex interpolation. */
+/* This version optimses the simplex split axis depending on the input */
+/* colorspace. */
+static int icmLut_lookup_clut_osx(
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[inputChan] */
+double *in /* Input array[outputChan] */
+) {
+ int rv = 0;
+ double *gp; /* Pointer to grid cube base */
+ double co[MAX_CHAN]; /* Coordinate offset with the grid cell */
+ int si[MAX_CHAN]; /* co[] Sort index, [0] = smalest */
+ char xflip[MAX_CHAN]; /* Optimised simplex axis flip flags */
+
+ /* Compute base index into grid and coordinate offsets */
+ {
+ unsigned int e;
+ double clutPoints_1 = (double)(p->clutPoints-1);
+ int clutPoints_2 = p->clutPoints-2;
+ gp = p->clutTable; /* Base of grid array */
+
+ for (e = 0; e < p->inputChan; e++) {
+ unsigned int x;
+ double val;
+// ~~~999
+#ifdef NEVER
+ xflip[e] = p->finfo[e].bthff;
+ if (in[e] >= p->finfo[e].fth)
+ xflip[e] = p->finfo[e].athff;
+#else
+
+ xflip[e] = 0;
+ if (e == 0)
+ xflip[e] = 1;
+#endif
+ val = in[e] * clutPoints_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > clutPoints_1) {
+ val = clutPoints_1;
+ rv |= 1;
+ }
+ x = (unsigned int)floor(val); /* Grid coordinate */
+ if (x > clutPoints_2)
+ x = clutPoints_2;
+ co[e] = val - (double)x; /* 1.0 - weight */
+ gp += x * p->dinc[e]; /* Add index offset for base of cube */
+ if (xflip[e]) { /* Reverse sense of direction for this axis */
+ co[e] = 1.0 - co[e];
+ gp += p->dinc[e];
+ }
+ }
+ }
+//printf("*");fflush(stdout);
+#ifdef NEVER
+ /* Do selection sort on coordinates, smallest to largest. */
+ {
+ int e, f;
+ for (e = 0; e < p->inputChan; e++)
+ si[e] = e; /* Initial unsorted indexes */
+ for (e = 0; e < (p->inputChan-1); e++) {
+ double cosn;
+ cosn = co[si[e]]; /* Current smallest value */
+ for (f = e+1; f < p->inputChan; f++) { /* Check against rest */
+ int tt;
+ tt = si[f];
+ if (cosn > co[tt]) {
+ si[f] = si[e]; /* Exchange */
+ si[e] = tt;
+ cosn = co[tt];
+ }
+ }
+ }
+ }
+#else
+ /* Do insertion sort on coordinates, smallest to largest. */
+ {
+ int f, vf;
+ unsigned int e;
+ double v;
+ for (e = 0; e < p->inputChan; e++)
+ si[e] = e; /* Initial unsorted indexes */
+
+ for (e = 1; e < p->inputChan; e++) {
+ f = e;
+ v = co[si[f]];
+ vf = f;
+ while (f > 0 && co[si[f-1]] > v) {
+ si[f] = si[f-1];
+ f--;
+ }
+ si[f] = vf;
+ }
+ }
+#endif
+ /* Now compute the weightings, simplex vertices and output values */
+ {
+ unsigned int e, f;
+ double w; /* Current vertex weight */
+
+ w = 1.0 - co[si[p->inputChan-1]]; /* Vertex at base of cell */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] = w * gp[f];
+
+ for (e = p->inputChan-1; e > 0; e--) { /* Middle verticies */
+ w = co[si[e]] - co[si[e-1]];
+ if (xflip[e])
+ gp -= p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
+ else
+ gp += p->dinc[si[e]]; /* Move to top of cell in next largest dimension */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * gp[f];
+ }
+
+ w = co[si[0]];
+ if (xflip[0])
+ gp -= p->dinc[si[0]]; /* Far corner from base of cell */
+ else
+ gp += p->dinc[si[0]]; /* Far corner from base of cell */
+ for (f = 0; f < p->outputChan; f++)
+ out[f] += w * gp[f];
+ }
+ return rv;
+}
+
+#endif /* NEVER */ // ~~~99 development code
+
+
+/* Convert normalized numbers though this Luts output tables. */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+static int icmLut_lookup_output(
+icmLut *p, /* Pointer to Lut object */
+double *out, /* Output array[outputChan] */
+double *in /* Input array[outputChan] */
+) {
+ int rv = 0;
+ unsigned int ix, n;
+ double outputEnt_1 = (double)(p->outputEnt-1);
+ double *table = p->outputTable;
+
+ if (p->outputEnt == 0) { /* Hmm. */
+ for (n = 0; n < p->outputChan; n++)
+ out[n] = in[n];
+ } else {
+ /* Use linear interpolation */
+ for (n = 0; n < p->outputChan; n++, table += p->outputEnt) {
+ double val, w;
+ val = in[n] * outputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ rv |= 1;
+ } else if (val > outputEnt_1) {
+ val = outputEnt_1;
+ rv |= 1;
+ }
+ ix = (unsigned int)floor(val); /* Grid coordinate */
+ if (ix > (p->outputEnt-2))
+ ix = (p->outputEnt-2);
+ w = val - (double)ix; /* weight */
+ val = table[ix];
+ out[n] = val + w * (table[ix+1] - val);
+ }
+ }
+ return rv;
+}
+
+/* ----------------------------------------------- */
+/* Pseudo - Hilbert count sequencer */
+
+/* This multi-dimensional count sequence is a distributed */
+/* Gray code sequence, with direction reversal on every */
+/* alternate power of 2 scale. */
+/* It is intended to aid cache coherence in multi-dimensional */
+/* regular sampling. It approximates the Hilbert curve sequence. */
+
+/* Initialise, returns total usable count */
+unsigned
+psh_init(
+psh *p, /* Pointer to structure to initialise */
+int di, /* Dimensionality */
+unsigned int res, /* Size per coordinate */
+int co[] /* Coordinates to initialise (May be NULL) */
+) {
+ int e;
+
+ p->di = di;
+ p->res = res;
+
+ /* Compute bits */
+ for (p->bits = 0; (1u << p->bits) < res; p->bits++)
+ ;
+
+ /* Compute the total count mask */
+ p->tmask = ((((unsigned)1) << (p->bits * di))-1);
+
+ /* Compute usable count */
+ p->count = 1;
+ for (e = 0; e < di; e++)
+ p->count *= res;
+
+ p->ix = 0;
+
+ if (co != NULL) {
+ for (e = 0; e < di; e++)
+ co[e] = 0;
+ }
+
+ return p->count;
+}
+
+/* Reset the counter */
+void
+psh_reset(
+psh *p /* Pointer to structure */
+) {
+ p->ix = 0;
+}
+
+/* Increment pseudo-hilbert coordinates */
+/* Return non-zero if count rolls over to 0 */
+int
+psh_inc(
+psh *p, /* Pointer to structure */
+int co[] /* Coordinates to return */
+) {
+ int di = p->di;
+ unsigned int res = p->res;
+ unsigned int bits = p->bits;
+ int e;
+
+ do {
+ unsigned int b;
+ int gix; /* Gray code index */
+
+ p->ix = (p->ix + 1) & p->tmask;
+
+ gix = p->ix ^ (p->ix >> 1); /* Convert to gray code index */
+
+ for (e = 0; e < di; e++)
+ co[e] = 0;
+
+ for (b = 0; b < bits; b++) { /* Distribute bits */
+ if (b & 1) {
+ for (e = di-1; e >= 0; e--) { /* In reverse order */
+ co[e] |= (gix & 1) << b;
+ gix >>= 1;
+ }
+ } else {
+ for (e = 0; e < di; e++) { /* In normal order */
+ co[e] |= (gix & 1) << b;
+ gix >>= 1;
+ }
+ }
+ }
+
+ /* Convert from Gray to binary coordinates */
+ for (e = 0; e < di; e++) {
+ unsigned int sh, tv;
+
+ for(sh = 1, tv = co[e];; sh <<= 1) {
+ unsigned ptv = tv;
+ tv ^= (tv >> sh);
+ if (ptv <= 1 || sh == 16)
+ break;
+ }
+ if (tv >= res) /* Dumbo filter - increment again if outside cube range */
+ break;
+ co[e] = tv;
+ }
+
+ } while (e < di);
+
+ return (p->ix == 0);
+}
+
+/* ------------------------------------------------------- */
+
+#ifndef COUNTERS_H
+
+/* Macros for a multi-dimensional counter. */
+
+/* Declare the counter name nn, maximum di mxdi, dimensions di, & count */
+/* This counter can have each dimension range clipped */
+
+#define FCOUNT(nn, mxdi, di) \
+ int nn[mxdi]; /* counter value */ \
+ int nn##_di = (di); /* Number of dimensions */ \
+ int nn##_stt[mxdi]; /* start count value */ \
+ int nn##_res[mxdi]; /* last count +1 */ \
+ int nn##_e /* dimension index */
+
+#define FRECONF(nn, start, endp1) \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn##_stt[nn##_e] = (start); /* start count value */ \
+ nn##_res[nn##_e] = (endp1); /* last count +1 */ \
+ }
+
+/* Set the counter value to 0 */
+#define FC_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
+ nn[nn##_e] = nn##_stt[nn##_e]; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define FC_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < nn##_res[nn##_e]) \
+ break; /* No carry */ \
+ nn[nn##_e] = nn##_stt[nn##_e]; \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define FC_DONE(nn) \
+ (nn##_e >= nn##_di)
+
+#endif /* COUNTERS_H */
+
+/* Parameter to getNormFunc function */
+typedef enum {
+ icmFromLuti = 0, /* return "fromo Lut normalized index" conversion function */
+ icmToLuti = 1, /* return "to Lut normalized index" conversion function */
+ icmFromLutv = 2, /* return "from Lut normalized value" conversion function */
+ icmToLutv = 3 /* return "to Lut normalized value" conversion function */
+} icmNormFlag;
+
+/* Return an appropriate color space normalization function, */
+/* given the color space and Lut type */
+/* Return 0 on success, 1 on match failure */
+static int getNormFunc(
+ icc *icp,
+ icColorSpaceSignature csig,
+ icTagTypeSignature tagSig,
+ icmNormFlag flag,
+ void (**nfunc)(double *out, double *in)
+);
+
+#define CLIP_MARGIN 0.005 /* Margine to allow before reporting clipping = 0.5% */
+
+/* Helper function to set multiple Lut tables simultaneously. */
+/* Note that these tables all have to be compatible in */
+/* having the same configuration and resolution. */
+/* Set errc and return error number in underlying icc */
+/* Set warnc if there is clipping in the output values */
+/* 1 = input table, 2 = main clut, 3 = clut midpoin, 4 = midpoint interp, 5 = output table */
+int icmSetMultiLutTables(
+ int ntables, /* Number of tables to be set, 1..n */
+ icmLut **pp, /* Pointer to array of Lut objects */
+ int flags, /* Setting flags */
+ void *cbctx, /* Opaque callback context pointer value */
+ icColorSpaceSignature insig, /* Input color space */
+ icColorSpaceSignature outsig, /* Output color space */
+ void (*infunc)(void *cbctx, double *out, double *in),
+ /* Input transfer function, inspace->inspace' (NULL = default) */
+ /* Will be called ntables times for each input grid value */
+ double *inmin, double *inmax, /* Maximum range of inspace' values */
+ /* (NULL = default) */
+ void (*clutfunc)(void *cbntx, double *out, double *in),
+ /* inspace' -> outspace[ntables]' transfer function */
+ /* will be called once for each input' grid value, and */
+ /* ntables output values should be written consecutively */
+ /* to out[]. */
+ double *clutmin, double *clutmax, /* Maximum range of outspace' values */
+ /* (NULL = default) */
+ void (*outfunc)(void *cbntx, double *out, double *in))
+ /* Output transfer function, outspace'->outspace (NULL = deflt) */
+ /* Will be called ntables times on each output value */
+{
+ icmLut *p, *pn; /* Pointer to 0'th nd tn'th Lut object */
+ icc *icp; /* Pointer to common icc */
+ int tn;
+ unsigned int e, f, i, n;
+ double **clutTable2 = NULL; /* Cell center values for ICM_CLUT_SET_APXLS */
+ double *clutTable3 = NULL; /* Vertex smoothing radius values [ntables] per entry */
+ int dinc3[MAX_CHAN]; /* Dimensional increment through clut3 (in doubles) */
+ int dcube3[1 << MAX_CHAN]; /* Hyper cube offsets throught clut3 (in doubles) */
+ int ii[MAX_CHAN]; /* Index value */
+ psh counter; /* Pseudo-Hilbert counter */
+// double _iv[4 * MAX_CHAN], *iv = &_iv[MAX_CHAN], *ivn; /* Real index value/table value */
+ int maxchan; /* Actual max of input and output */
+ double *_iv, *iv, *ivn; /* Real index value/table value */
+ double imin[MAX_CHAN], imax[MAX_CHAN];
+ double omin[MAX_CHAN], omax[MAX_CHAN];
+ void (*ifromindex)(double *out, double *in); /* Index to input color space function */
+ void (*itoentry)(double *out, double *in); /* Input color space to entry function */
+ void (*ifromentry)(double *out, double *in); /* Entry to input color space function */
+ void (*otoentry)(double *out, double *in); /* Output colorspace to table value function */
+ void (*ofromentry)(double *out, double *in); /* Table value to output color space function */
+ int clip = 0;
+
+ /* Check that everything is OK to proceed */
+ if (ntables < 1 || ntables > MAX_CHAN) {
+ if (ntables >= 1) {
+ icp = pp[0]->icp;
+ sprintf(icp->err,"icmSetMultiLutTables has illegal number of tables %d",ntables);
+ return icp->errc = 1;
+ } else {
+ /* Can't write error message anywhere */
+ return 1;
+ }
+ }
+
+ p = pp[0];
+ icp = p->icp;
+
+ for (tn = 1; tn < ntables; tn++) {
+ if (pp[tn]->icp != icp) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables base icc is different");
+ return icp->errc = 1;
+ }
+ if (pp[tn]->ttype != p->ttype) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables have different Tage Type");
+ return icp->errc = 1;
+ }
+
+ if (pp[tn]->inputChan != p->inputChan) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables have different inputChan");
+ return icp->errc = 1;
+ }
+ if (pp[tn]->outputChan != p->outputChan) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables have different outputChan");
+ return icp->errc = 1;
+ }
+ if (pp[tn]->clutPoints != p->clutPoints) {
+ sprintf(icp->err,"icmSetMultiLutTables Tables have different clutPoints");
+ return icp->errc = 1;
+ }
+ }
+
+ if (getNormFunc(icp, insig, p->ttype, icmFromLuti, &ifromindex) != 0) {
+ sprintf(icp->err,"icmLut_set_tables index to input colorspace function lookup failed");
+ return icp->errc = 1;
+ }
+ if (getNormFunc(icp, insig, p->ttype, icmToLutv, &itoentry) != 0) {
+ sprintf(icp->err,"icmLut_set_tables input colorspace to table entry function lookup failed");
+ return icp->errc = 1;
+ }
+ if (getNormFunc(icp, insig, p->ttype, icmFromLutv, &ifromentry) != 0) {
+ sprintf(icp->err,"icmLut_set_tables table entry to input colorspace function lookup failed");
+ return icp->errc = 1;
+ }
+
+ if (getNormFunc(icp, outsig, p->ttype, icmToLutv, &otoentry) != 0) {
+ sprintf(icp->err,"icmLut_set_tables output colorspace to table entry function lookup failed");
+ return icp->errc = 1;
+ }
+ if (getNormFunc(icp, outsig, p->ttype, icmFromLutv, &ofromentry) != 0) {
+ sprintf(icp->err,"icmLut_set_tables table entry to output colorspace function lookup failed");
+ return icp->errc = 1;
+ }
+
+ /* Allocate an array to hold the input and output values. */
+ /* It needs to be able to hold di "index under valus as in[], */
+ /* and ntables ICM_CLUT_SET_FILTER values as out[], so we assume maxchan >= di */
+ maxchan = p->inputChan > p->outputChan ? p->inputChan : p->outputChan;
+ if ((_iv = (double *) icp->al->malloc(icp->al, sizeof(double) * maxchan * (ntables+1)))
+ == NULL) {
+ sprintf(icp->err,"icmLut_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ iv = _iv + maxchan; /* Allow for "index under" and smoothing radius values */
+
+ /* Setup input table value min-max */
+ if (inmin == NULL || imax == NULL) {
+#ifdef SYMETRICAL_DEFAULT_LAB_RANGE /* Symetrical default range. */
+ /* We are assuming V2 Lab16 encoding, since this is a lut16type that always uses */
+ /* this encoding */
+ if (insig == icSigLabData) { /* Special case Lab */
+ double mn[3], mx[3];
+ /* This is to ensure that Lab 100,0,0 maps exactly to a clut grid point. */
+ /* This should work well if there is an odd grid resolution, */
+ /* and icclib is being used, as input lookup will */
+ /* be computed using floating point, so that the CLUT input value */
+ /* 0.5 can be represented exactly. */
+ /* Because the symetric range will cause slight clipping, */
+ /* only do it if the input table has sufficient resolution */
+ /* to represent the clipping faithfuly. */
+ if (p->inputEnt >= 64) {
+ if (p->ttype == icSigLut8Type) {
+ mn[0] = 0.0, mn[1] = mn[2] = -127.0;
+ mx[0] = 100.0, mx[1] = mx[2] = 127.0;
+ } else {
+ mn[0] = 0.0, mn[1] = mn[2] = -127.0 - 255.0/256.0;
+ mx[0] = 100.0, mx[1] = mx[2] = 127.0 + 255.0/256.0;
+ }
+ itoentry(imin, mn); /* Convert from input color space to table representation */
+ itoentry(imax, mx);
+ } else {
+ for (e = 0; e < p->inputChan; e++) {
+ imin[e] = 0.0;
+ imax[e] = 1.0;
+ }
+ }
+ } else
+#endif
+ {
+ for (e = 0; e < p->inputChan; e++) {
+ imin[e] = 0.0; /* We are assuming this is true for all other color spaces. */
+ imax[e] = 1.0;
+ }
+ }
+ } else {
+ itoentry(imin, inmin); /* Convert from input color space to table representation */
+ itoentry(imax, inmax);
+ }
+
+ /* Setup output table value min-max */
+ if (clutmin == NULL || clutmax == NULL) {
+#ifdef SYMETRICAL_DEFAULT_LAB_RANGE
+ /* This really isn't doing much, since the full range encoding doesn't need */
+ /* any adjustment to map a*b* 0 to an integer value. */
+ /* We are tweaking the 16 bit L* = 100 to the last index into */
+ /* the output table, which may help its accuracy slightly. */
+ /* We are assuming V2 Lab16 encoding, since this is a lut16type that always uses */
+ /* this encoding */
+ if (outsig == icSigLabData) { /* Special case Lab */
+ double mn[3], mx[3];
+ /* The output of the CLUT will be an 8 or 16 bit value, and we want to */
+ /* adjust the range so that the input grid point holding the white */
+ /* point can encode 0.0 exactly. */
+ /* Note that in the case of the a & b values, the range equates to */
+ /* normalised 0.0 .. 1.0, since 0 can be represented exactly in it. */
+ if (p->outputEnt >= 64) {
+ if (p->ttype == icSigLut8Type) {
+ mn[0] = 0.0, mn[1] = mn[2] = -128.0;
+ mx[0] = 100.0, mx[1] = mx[2] = 127.0;
+ } else {
+ mn[0] = 0.0, mn[1] = mn[2] = -128.0;
+ mx[0] = 100.0, mx[1] = mx[2] = (65535.0 * 255.0)/65280.0 - 128.0;
+ }
+ otoentry(omin, mn);/* Convert from output color space to table representation */
+ otoentry(omax, mx);
+ } else {
+ for (e = 0; e < p->inputChan; e++) {
+ omin[e] = 0.0;
+ omax[e] = 1.0;
+ }
+ }
+ } else
+#endif
+ {
+ for (f = 0; f < p->outputChan; f++) {
+ omin[f] = 0.0; /* We are assuming this is true for all other color spaces. */
+ omax[f] = 1.0;
+ }
+ }
+ } else {
+ otoentry(omin, clutmin);/* Convert from output color space to table representation */
+ otoentry(omax, clutmax);
+ }
+
+ /* Create the input table entry values */
+ for (tn = 0; tn < ntables; tn++) {
+ pn = pp[tn];
+ for (n = 0; n < pn->inputEnt; n++) {
+ double fv;
+ fv = n/(pn->inputEnt-1.0);
+ for (e = 0; e < pn->inputChan; e++)
+ iv[e] = fv;
+
+ ifromindex(iv,iv); /* Convert from index value to input color space value */
+
+ if (infunc != NULL)
+ infunc(cbctx, iv, iv); /* In colorspace -> input table -> In colorspace. */
+
+ itoentry(iv,iv); /* Convert from input color space value to table value */
+
+ /* Expand used range to 0.0 - 1.0, and clip to legal values */
+ /* Note that if the range is reduced, and clipping occurs, */
+ /* then there should be enough resolution within the input */
+ /* table, to represent the sharp edges of the clipping. */
+ for (e = 0; e < pn->inputChan; e++) {
+ double tt;
+ tt = (iv[e] - imin[e])/(imax[e] - imin[e]);
+ if (tt < 0.0) {
+ DBGSLC(("iclip: tt = %f, iv = %f, omin = %f, omax = %f\n",tt,iv[e],omin[e],omax[e]));
+ if (tt < -CLIP_MARGIN)
+ clip = 1;
+ tt = 0.0;
+ } else if (tt > 1.0) {
+ DBGSLC(("iclip: tt = %f, iv = %f, omin = %f, omax = %f\n",tt,iv[e],omin[e],omax[e]));
+ if (tt > (1.0 + CLIP_MARGIN))
+ clip = 1;
+ tt = 1.0;
+ }
+ iv[e] = tt;
+ }
+
+ for (e = 0; e < pn->inputChan; e++) /* Input tables */
+ pn->inputTable[e * pn->inputEnt + n] = iv[e];
+ }
+ }
+
+ /* Allocate space for cell center value lookup */
+ if (flags & ICM_CLUT_SET_APXLS) {
+ if ((clutTable2 = (double **) icp->al->calloc(icp->al,sizeof(double *), ntables)) == NULL) {
+ sprintf(icp->err,"icmLut_set_tables malloc of cube center array failed");
+ icp->al->free(icp->al, _iv);
+ return icp->errc = 1;
+ }
+ for (tn = 0; tn < ntables; tn++) {
+ if ((clutTable2[tn] = (double *) icp->al->calloc(icp->al,sizeof(double),
+ p->clutTable_size)) == NULL) {
+ for (--tn; tn >= 0; tn--)
+ icp->al->free(icp->al, clutTable2[tn]);
+ icp->al->free(icp->al, _iv);
+ icp->al->free(icp->al, clutTable2);
+ sprintf(icp->err,"icmLut_set_tables malloc of cube center array failed");
+ return icp->errc = 1;
+ }
+ }
+ }
+
+ /* Allocate space for smoothing radius values */
+ if (flags & ICM_CLUT_SET_FILTER) {
+ unsigned int j, g, size;
+
+ /* Private: compute dimensional increment though clut3 */
+ i = p->inputChan-1;
+ dinc3[i--] = ntables;
+ for (; i < p->inputChan; i--)
+ dinc3[i] = dinc3[i+1] * p->clutPoints;
+
+ /* Private: compute offsets from base of cube to other corners */
+ for (dcube3[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
+ for (i = 0; i < g; i++)
+ dcube3[g+i] = dcube3[i] + dinc3[j];
+ g *= 2;
+ }
+
+ if ((size = sat_mul(ntables, sat_pow(p->clutPoints,p->inputChan))) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_alloc size overflow");
+ if (flags & ICM_CLUT_SET_APXLS) {
+ for (tn = 0; tn < ntables; tn++)
+ icp->al->free(icp->al, clutTable2[tn]);
+ }
+ icp->al->free(icp->al, clutTable2);
+ icp->al->free(icp->al, _iv);
+ return icp->errc = 1;
+ }
+
+ if ((clutTable3 = (double *) icp->al->calloc(icp->al,sizeof(double),
+ size)) == NULL) {
+ if (flags & ICM_CLUT_SET_APXLS) {
+ for (tn = 0; tn < ntables; tn++)
+ icp->al->free(icp->al, clutTable2[tn]);
+ }
+ icp->al->free(icp->al, clutTable2);
+ icp->al->free(icp->al, _iv);
+ sprintf(icp->err,"icmLut_set_tables malloc of vertex smoothing value array failed");
+ return icp->errc = 1;
+ }
+ }
+
+ /* Create the multi-dimensional lookup table values */
+
+ /* To make this clut function cache friendly, we use the pseudo-hilbert */
+ /* count sequence. This keeps each point close to the last in the */
+ /* multi-dimensional space. This is the point of setting multiple Luts at */
+ /* once too - the assumption is that these tables are all related (different */
+ /* gamut compressions for instance), and hence calling the clutfunc() with */
+ /* close values will maximise reverse lookup cache hit rate. */
+
+ psh_init(&counter, p->inputChan, p->clutPoints, ii); /* Initialise counter */
+
+ /* Itterate through all verticies in the grid */
+ for (;;) {
+ int ti, ti3; /* Table indexes */
+
+ for (ti = e = 0; e < p->inputChan; e++) { /* Input tables */
+ ti += ii[e] * p->dinc[e]; /* Clut index */
+ iv[e] = ii[e]/(p->clutPoints-1.0); /* Vertex coordinates */
+ iv[e] = iv[e] * (imax[e] - imin[e]) + imin[e]; /* Undo expansion to 0.0 - 1.0 */
+ *((int *)&iv[-((int)e)-1]) = ii[e]; /* Trick to supply grid index in iv[] */
+ }
+
+ if (flags & ICM_CLUT_SET_FILTER) {
+ for (ti3 = e = 0; e < p->inputChan; e++) /* Input tables */
+ ti3 += ii[e] * dinc3[e]; /* Clut3 index */
+ }
+
+ DBGSL(("\nix %s\n",icmPiv(p->inputChan, ii)));
+ DBGSL(("raw itv %s to iv'",icmPdv(p->inputChan, iv)));
+ ifromentry(iv,iv); /* Convert from table value to input color space */
+ DBGSL((" %s\n",icmPdv(p->inputChan, iv)));
+
+ /* Apply incolor -> outcolor function we want to represent for all tables */
+ DBGSL(("iv: %s to ov'",icmPdv(p->inputChan, iv)));
+ clutfunc(cbctx, iv, iv);
+ DBGSL((" %s\n",icmPdv(p->outputChan, iv)));
+
+ /* Save the results to the output tables */
+ for (tn = 0, ivn = iv; tn < ntables; ivn += p->outputChan, tn++) {
+ pn = pp[tn];
+
+ DBGSL(("tn %d, ov' %s -> otv",tn,icmPdv(p->outputChan, ivn)));
+ otoentry(ivn,ivn); /* Convert from output color space value to table value */
+ DBGSL((" %s\n -> oval",icmPdv(p->outputChan, ivn)));
+
+ /* Expand used range to 0.0 - 1.0, and clip to legal values */
+ for (f = 0; f < pn->outputChan; f++) {
+ double tt;
+ tt = (ivn[f] - omin[f])/(omax[f] - omin[f]);
+ if (tt < 0.0) {
+ DBGSLC(("lclip: tt = %f, ivn= %f, omin = %f, omax = %f\n",tt,ivn[f],omin[f],omax[f]));
+ if (tt < -CLIP_MARGIN)
+ clip = 2;
+ tt = 0.0;
+ } else if (tt > 1.0) {
+ DBGSLC(("lclip: tt = %f, ivn= %f, omin = %f, omax = %f\n",tt,ivn[f],omin[f],omax[f]));
+ if (tt > (1.0 + CLIP_MARGIN))
+ clip = 2;
+ tt = 1.0;
+ }
+ ivn[f] = tt;
+ }
+
+ for (f = 0; f < pn->outputChan; f++) /* Output chans */
+ pn->clutTable[ti + f] = ivn[f];
+ DBGSL((" %s\n",icmPdv(pn->outputChan, ivn)));
+
+ if (flags & ICM_CLUT_SET_FILTER) {
+ clutTable3[ti3 + tn] = iv[-1 -tn]; /* Filter radiuses */
+ }
+ }
+
+ /* Lookup cell center value if ICM_CLUT_SET_APXLS */
+ if (clutTable2 != NULL) {
+
+ for (e = 0; e < p->inputChan; e++) {
+ if (ii[e] >= (p->clutPoints-1))
+ break; /* Don't lookup beyond last */
+ iv[e] = (ii[e] + 0.5)/(p->clutPoints-1.0); /* Vertex coordinates + 0.5 */
+ iv[e] = iv[e] * (imax[e] - imin[e]) + imin[e]; /* Undo expansion to 0.0 - 1.0 */
+ *((int *)&iv[-((int)e)-1]) = ii[e]; /* Trick to supply grid index in iv[] */
+ /* (Not this is only the base for +0.5) */
+ }
+
+ if (e >= p->inputChan) { /* We're not on the last row */
+
+ ifromentry(iv,iv); /* Convert from table value to input color space */
+
+ /* Apply incolor -> outcolor function we want to represent */
+ clutfunc(cbctx, iv, iv);
+
+ /* Save the results to the output tables */
+ for (tn = 0, ivn = iv; tn < ntables; ivn += p->outputChan, tn++) {
+ pn = pp[tn];
+
+ otoentry(ivn,ivn); /* Convert from output color space value to table value */
+
+ /* Expand used range to 0.0 - 1.0, and clip to legal values */
+ for (f = 0; f < pn->outputChan; f++) {
+ double tt;
+ tt = (ivn[f] - omin[f])/(omax[f] - omin[f]);
+ if (tt < 0.0) {
+ DBGSLC(("lclip: tt = %f, ivn= %f, omin = %f, omax = %f\n",tt,ivn[f],omin[f],omax[f]));
+ if (tt < -CLIP_MARGIN)
+ clip = 3;
+ tt = 0.0;
+ } else if (tt > 1.0) {
+ DBGSLC(("lclip: tt = %f, ivn= %f, omin = %f, omax = %f\n",tt,ivn[f],omin[f],omax[f]));
+ if (tt > (1.0 + CLIP_MARGIN))
+ clip = 3;
+ tt = 1.0;
+ }
+ ivn[f] = tt;
+ }
+
+ for (f = 0; f < pn->outputChan; f++) /* Output chans */
+ clutTable2[tn][ti + f] = ivn[f];
+ }
+ }
+ }
+
+ /* Increment index within block (Reverse index significancd) */
+ if (psh_inc(&counter, ii))
+ break;
+ }
+
+#define APXLS_WHT 0.5
+#define APXLS_DIFF_THRHESH 0.2
+ /* Deal with cell center value, aproximate least squares adjustment. */
+ /* Subtract some of the mean of the surrounding center values from each grid value. */
+ /* Skip the edges so that things like the white point are not changed. */
+ /* Avoid modifying the value if the difference between the */
+ /* interpolated value and the current value is too great, */
+ /* and there is the possibility of different color aliases. */
+ if (clutTable2 != NULL) {
+ int ti; /* cube vertex table index */
+ int ti2; /* cube center table2 index */
+ int ee;
+ double cw = 1.0/(double)(1 << p->inputChan); /* Weight for each cube corner */
+
+ /* For each cell center point except last row */
+ for (e = 0; e < p->inputChan; e++)
+ ii[e] = 0; /* init coords */
+
+ /* Compute linear interpolated value from center values */
+ for (ee = 0; ee < p->inputChan;) {
+
+ /* Compute base index for table2 */
+ for (ti2 = e = 0; e < p->inputChan; e++) /* Input tables */
+ ti2 += ii[e] * p->dinc[e]; /* Clut index */
+
+ ti = ti2 + p->dcube[(1 << p->inputChan)-1]; /* +1 to each coord for vertex index */
+
+ for (tn = 0; tn < ntables; tn++) {
+ double mval[MAX_CHAN], vv;
+ double maxd = 0.0;
+
+ pn = pp[tn];
+
+ /* Compute mean of center values */
+ for (f = 0; f < pn->outputChan; f++) { /* Output chans */
+
+ mval[f] = 0.0;
+ for (i = 0; i < (1 << p->inputChan); i++) { /* For surrounding center values */
+ mval[f] += clutTable2[tn][ti2 + p->dcube[i] + f];
+ }
+ mval[f] = pn->clutTable[ti + f] - mval[f] * cw; /* Diff to mean */
+ vv = fabs(mval[f]);
+ if (vv > maxd)
+ maxd = vv;
+ }
+
+ if (pn->outputChan <= 3 || maxd < APXLS_DIFF_THRHESH) {
+ for (f = 0; f < pn->outputChan; f++) { /* Output chans */
+
+ vv = pn->clutTable[ti + f] + APXLS_WHT * mval[f];
+
+ /* Hmm. This is a bit crude. How do we know valid range is 0-1 ? */
+ /* What about an ink limit ? */
+ if (vv < 0.0) {
+ vv = 0.0;
+ } else if (vv > 1.0) {
+ vv = 1.0;
+ }
+ pn->clutTable[ti + f] = vv;
+ }
+ }
+ }
+
+ /* Increment coord */
+ for (ee = 0; ee < p->inputChan; ee++) {
+ if (++ii[ee] < (p->clutPoints-2)) /* Don't go through upper edge */
+ break; /* No carry */
+ ii[ee] = 0;
+ }
+ }
+
+ /* Done with center values */
+ for (tn = 0; tn < ntables; tn++)
+ icp->al->free(icp->al, clutTable2[tn]);
+ icp->al->free(icp->al, clutTable2);
+ }
+
+ /* Apply any smoothing in the clipped region to the resulting clutTable */
+ if (clutTable3 != NULL) {
+ double *clutTable1; /* Copy of current unfilted values */
+ FCOUNT(cc, MAX_CHAN, p->inputChan); /* Surrounding counter */
+
+ if ((clutTable1 = (double *) icp->al->calloc(icp->al,sizeof(double),
+ p->clutTable_size)) == NULL) {
+ icp->al->free(icp->al, clutTable3);
+ icp->al->free(icp->al, _iv);
+ sprintf(icp->err,"icmLut_set_tables malloc of grid copy failed");
+ return icp->errc = 1;
+ }
+
+ for (tn = 0; tn < ntables; tn++) {
+ int aa;
+ int ee;
+ int ti, ti3; /* Table indexes */
+
+ pn = pp[tn];
+
+ /* For each pass */
+ for (aa = 0; aa < 2; aa++) {
+
+ /* Copy current values */
+ memcpy(clutTable1, pn->clutTable, sizeof(double) * pn->clutTable_size);
+
+ /* Filter each point */
+ for (e = 0; e < pn->inputChan; e++)
+ ii[e] = 0; /* init coords */
+
+ /* Compute linear interpolated error to actual cell center value */
+ for (ee = 0; ee < pn->inputChan;) {
+ double rr; /* Filter radius */
+ int ir; /* Integer radius */
+ double tw; /* Total weight */
+
+ /* Compute base index for this cell */
+ for (ti3 = ti = e = 0; e < pn->inputChan; e++) { /* Input tables */
+ ti += ii[e] * pn->dinc[e]; /* Clut index */
+ ti3 += ii[e] * dinc3[e]; /* Clut3 index */
+ }
+ rr = clutTable3[ti3 + tn] * (pn->clutPoints-1.0);
+ ir = (int)floor(rr + 0.5); /* Don't bother unless 1/2 over vertex */
+
+ if (ir < 1)
+ goto next_vert;
+
+ //FRECONF(cc, -ir, ir + 1); /* Set size of surroundign grid */
+
+ /* Clip scanning cube to be within grid */
+ for (e = 0; e < pn->inputChan; e++) {
+ int cr = ir;
+ if ((ii[e] - ir) < 0)
+ cr = ii[e];
+ if ((ii[e] + ir) >= pn->clutPoints)
+ cr = pn->clutPoints -1 -ii[e];
+
+ cc_stt[e] = -cr;
+ cc_res[e] = cr + 1;
+ }
+
+ for (f = 0; f < pn->outputChan; f++)
+ pn->clutTable[ti + f] = 0.0;
+ tw = 0.0;
+
+ FC_INIT(cc)
+ for (tw = 0.0; !FC_DONE(cc);) {
+ double r;
+ int tti;
+
+ /* Radius of this cell */
+ for (r = 0.0, tti = e = 0; e < pn->inputChan; e++) {
+ int ix;
+ r += cc[e] * cc[e];
+ tti += (ii[e] + cc[e]) * p->dinc[e];
+ }
+ r = sqrt(r);
+
+ if (r <= rr && e >= pn->inputChan) {
+ double w = (rr - r)/rr; /* Triangle weighting */
+ w = sqrt(w);
+ for (f = 0; f < pn->outputChan; f++)
+ pn->clutTable[ti+f] += w * clutTable1[tti + f];
+ tw += w;
+ }
+ FC_INC(cc);
+ }
+ for (f = 0; f < pn->outputChan; f++) {
+ double vv = pn->clutTable[ti+f] / tw;
+ if (vv < 0.0) {
+ vv = 0.0;
+ } else if (vv > 1.0) {
+ vv = 1.0;
+ }
+ pn->clutTable[ti+f] = vv;
+ }
+
+ /* Increment coord */
+ next_vert:;
+ for (ee = 0; ee < pn->inputChan; ee++) {
+ if (++ii[ee] < (pn->clutPoints-1)) /* Don't go through upper edge */
+ break; /* No carry */
+ ii[ee] = 0;
+ }
+ } /* Next grid point to filter */
+ } /* Next pass */
+ } /* Next table */
+
+ free(clutTable1);
+ free(clutTable3);
+ }
+
+ /* Create the output table entry values */
+ for (tn = 0; tn < ntables; tn++) {
+ pn = pp[tn];
+ for (n = 0; n < pn->outputEnt; n++) {
+ double fv;
+ fv = n/(pn->outputEnt-1.0);
+ for (f = 0; f < pn->outputChan; f++)
+ iv[f] = fv;
+
+ /* Undo expansion to 0.0 - 1.0 */
+ for (f = 0; f < pn->outputChan; f++) /* Output tables */
+ iv[f] = iv[f] * (omax[f] - omin[f]) + omin[f];
+
+ ofromentry(iv,iv); /* Convert from table value to output color space value */
+
+ if (outfunc != NULL)
+ outfunc(cbctx, iv, iv); /* Out colorspace -> output table -> out colorspace. */
+
+ otoentry(iv,iv); /* Convert from output color space value to table value */
+
+ /* Clip to legal values */
+ for (f = 0; f < pn->outputChan; f++) {
+ double tt;
+ tt = iv[f];
+ if (tt < 0.0) {
+ DBGSLC(("oclip: tt = %f\n",tt));
+ if (tt < -CLIP_MARGIN)
+ clip = 5;
+ tt = 0.0;
+ } else if (tt > 1.0) {
+ DBGSLC(("oclip: tt = %f\n",tt));
+ if (tt > (1.0 + CLIP_MARGIN))
+ clip = 5;
+ tt = 1.0;
+ }
+ iv[f] = tt;
+ }
+
+ for (f = 0; f < pn->outputChan; f++) /* Input tables */
+ pn->outputTable[f * pn->outputEnt + n] = iv[f];
+ }
+ }
+
+ icp->al->free(icp->al, _iv);
+
+ icp->warnc = 0;
+ if (clip) {
+ DBGSLC(("Returning clip status = %d\n",clip));
+ icp->warnc = clip;
+ }
+
+ return 0;
+}
+
+/* Helper function to initialize a Lut tables contents */
+/* from supplied transfer functions. */
+/* Set errc and return error number */
+/* Set warnc if there is clipping in the output values */
+static int icmLut_set_tables (
+icmLut *p, /* Pointer to Lut object */
+int flags, /* Setting flags */
+void *cbctx, /* Opaque callback context pointer value */
+icColorSpaceSignature insig, /* Input color space */
+icColorSpaceSignature outsig, /* Output color space */
+void (*infunc)(void *cbcntx, double *out, double *in),
+ /* Input transfer function, inspace->inspace' (NULL = default) */
+double *inmin, double *inmax, /* Maximum range of inspace' values (NULL = default) */
+void (*clutfunc)(void *cbctx, double *out, double *in),
+ /* inspace' -> outspace' transfer function */
+double *clutmin, double *clutmax, /* Maximum range of outspace' values (NULL = default) */
+void (*outfunc)(void *cbctx, double *out, double *in)
+ /* Output transfer function, outspace'->outspace (NULL = deflt) */
+) {
+ struct _icmLut *pp[3];
+
+ /* Simply call the multiple table function with one table */
+ pp[0] = p;
+ return icmSetMultiLutTables(1, pp, flags,
+ cbctx, insig, outsig,
+ infunc,
+ inmin, inmax,
+ clutfunc,
+ clutmin, clutmax,
+ outfunc);
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmLut_get_size(
+ icmBase *pp
+) {
+ icmLut *p = (icmLut *)pp;
+ unsigned int len = 0;
+
+ if (p->ttype == icSigLut8Type) {
+ len = sat_add(len, 48); /* tag and header */
+ len = sat_add(len, sat_mul3(1, p->inputChan, p->inputEnt));
+ len = sat_add(len, sat_mul3(1, p->outputChan, sat_pow(p->clutPoints,p->inputChan)));
+ len = sat_add(len, sat_mul3(1, p->outputChan, p->outputEnt));
+ } else {
+ len = sat_add(len, 52); /* tag and header */
+ len = sat_add(len, sat_mul3(2, p->inputChan, p->inputEnt));
+ len = sat_add(len, sat_mul3(2, p->outputChan, sat_pow(p->clutPoints,p->inputChan)));
+ len = sat_add(len, sat_mul3(2, p->outputChan, p->outputEnt));
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmLut_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmLut *p = (icmLut *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i, j, g, size;
+ char *bp, *buf;
+
+ if (len < 4) {
+ sprintf(icp->err,"icmLut_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmLut_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmLut_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
+ if (p->ttype != icSigLut8Type && p->ttype != icSigLut16Type) {
+ sprintf(icp->err,"icmLut_read: Wrong tag type for icmLut");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ if (p->ttype == icSigLut8Type) {
+ if (len < 48) {
+ sprintf(icp->err,"icmLut_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ } else {
+ if (len < 52) {
+ sprintf(icp->err,"icmLut_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+
+ /* Read in the info common to 8 and 16 bit Lut */
+ p->inputChan = read_UInt8Number(bp+8);
+ p->outputChan = read_UInt8Number(bp+9);
+ p->clutPoints = read_UInt8Number(bp+10);
+
+ /* Sanity check */
+ if (p->inputChan < 1) {
+ sprintf(icp->err,"icmLut_read: No input channels!");
+ return icp->errc = 1;
+ }
+
+ if (p->inputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_read: Can't handle > %d input channels\n",MAX_CHAN);
+ return icp->errc = 1;
+ }
+
+ if (p->outputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_read: Can't handle > %d output channels\n",MAX_CHAN);
+ return icp->errc = 1;
+ }
+
+ /* Read 3x3 transform matrix */
+ for (j = 0; j < 3; j++) { /* Rows */
+ for (i = 0; i < 3; i++) { /* Columns */
+ p->e[j][i] = read_S15Fixed16Number(bp + 12 + ((j * 3 + i) * 4));
+ }
+ }
+ /* Read 16 bit specific stuff */
+ if (p->ttype == icSigLut8Type) {
+ p->inputEnt = 256; /* By definition */
+ p->outputEnt = 256; /* By definition */
+ bp = buf+48;
+ } else {
+ p->inputEnt = read_UInt16Number(bp+48);
+ p->outputEnt = read_UInt16Number(bp+50);
+ bp = buf+52;
+ }
+
+ /* Sanity check dimensions. This protects against */
+ /* subsequent integer overflows involving the dimensions. */
+ if ((size = icmLut_get_size((icmBase *)p)) == UINT_MAX
+ || size > len) {
+ sprintf(icp->err,"icmLut_read: Tag wrong size for contents");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read the input tables */
+ size = (p->inputChan * p->inputEnt);
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1)
+ p->inputTable[i] = read_DCS8Number(bp);
+ } else {
+ for (i = 0; i < size; i++, bp += 2)
+ p->inputTable[i] = read_DCS16Number(bp);
+ }
+
+ /* Read the clut table */
+ size = (p->outputChan * sat_pow(p->clutPoints,p->inputChan));
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1)
+ p->clutTable[i] = read_DCS8Number(bp);
+ } else {
+ for (i = 0; i < size; i++, bp += 2)
+ p->clutTable[i] = read_DCS16Number(bp);
+ }
+
+ /* Read the output tables */
+ size = (p->outputChan * p->outputEnt);
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1)
+ p->outputTable[i] = read_DCS8Number(bp);
+ } else {
+ for (i = 0; i < size; i++, bp += 2)
+ p->outputTable[i] = read_DCS16Number(bp);
+ }
+
+ /* Private: compute dimensional increment though clut */
+ /* Note that first channel varies least rapidly. */
+ i = p->inputChan-1;
+ p->dinc[i--] = p->outputChan;
+ for (; i < p->inputChan; i--)
+ p->dinc[i] = p->dinc[i+1] * p->clutPoints;
+
+ /* Private: compute offsets from base of cube to other corners */
+ for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
+ for (i = 0; i < g; i++)
+ p->dcube[g+i] = p->dcube[i] + p->dinc[j];
+ g *= 2;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmLut_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmLut *p = (icmLut *)pp;
+ icc *icp = p->icp;
+ unsigned int i,j;
+ unsigned int len, size;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmLut_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write the info common to 8 and 16 bit Lut */
+ if ((rv = write_UInt8Number(p->inputChan, bp+8)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt8Number(p->outputChan, bp+9)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt8Number(p->clutPoints, bp+10)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ write_UInt8Number(0, bp+11); /* Set padding to 0 */
+
+ /* Write 3x3 transform matrix */
+ for (j = 0; j < 3; j++) { /* Rows */
+ for (i = 0; i < 3; i++) { /* Columns */
+ if ((rv = write_S15Fixed16Number(p->e[j][i],bp + 12 + ((j * 3 + i) * 4))) != 0) {
+ sprintf(icp->err,"icmLut_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write 16 bit specific stuff */
+ if (p->ttype == icSigLut8Type) {
+ if (p->inputEnt != 256 || p->outputEnt != 256) {
+ sprintf(icp->err,"icmLut_write: 8 bit Input and Output tables must be 256 entries");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp = buf+48;
+ } else {
+ if (p->inputEnt > 4096 || p->outputEnt > 4096) {
+ sprintf(icp->err,"icmLut_write: 16 bit Input and Output tables must each be less than 4096 entries");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if ((rv = write_UInt16Number(p->inputEnt, bp+48)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt16Number(p->outputEnt, bp+50)) != 0) {
+ sprintf(icp->err,"icmLut_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp = buf+52;
+ }
+
+ /* Write the input tables */
+ size = (p->inputChan * p->inputEnt);
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1) {
+ if ((rv = write_DCS8Number(p->inputTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: inputTable write_DCS8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ } else {
+ for (i = 0; i < size; i++, bp += 2) {
+ if ((rv = write_DCS16Number(p->inputTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: inputTable write_DCS16Number(%f) failed",p->inputTable[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write the clut table */
+ size = (p->outputChan * sat_pow(p->clutPoints,p->inputChan));
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1) {
+ if ((rv = write_DCS8Number(p->clutTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: clutTable write_DCS8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ } else {
+ for (i = 0; i < size; i++, bp += 2) {
+ if ((rv = write_DCS16Number(p->clutTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: clutTable write_DCS16Number(%f) failed",p->clutTable[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write the output tables */
+ size = (p->outputChan * p->outputEnt);
+ if (p->ttype == icSigLut8Type) {
+ for (i = 0; i < size; i++, bp += 1) {
+ if ((rv = write_DCS8Number(p->outputTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: outputTable write_DCS8Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ } else {
+ for (i = 0; i < size; i++, bp += 2) {
+ if ((rv = write_DCS16Number(p->outputTable[i], bp)) != 0) {
+ sprintf(icp->err,"icmLut_write: outputTable write_DCS16Number(%f) failed",p->outputTable[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write buffer to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmLut_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmLut_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmLut *p = (icmLut *)pp;
+ if (verb <= 0)
+ return;
+
+ if (p->ttype == icSigLut8Type) {
+ op->gprintf(op,"Lut8:\n");
+ } else {
+ op->gprintf(op,"Lut16:\n");
+ }
+ op->gprintf(op," Input Channels = %u\n",p->inputChan);
+ op->gprintf(op," Output Channels = %u\n",p->outputChan);
+ op->gprintf(op," CLUT resolution = %u\n",p->clutPoints);
+ op->gprintf(op," Input Table entries = %u\n",p->inputEnt);
+ op->gprintf(op," Output Table entries = %u\n",p->outputEnt);
+ op->gprintf(op," XYZ matrix = %f, %f, %f\n",p->e[0][0],p->e[0][1],p->e[0][2]);
+ op->gprintf(op," %f, %f, %f\n",p->e[1][0],p->e[1][1],p->e[1][2]);
+ op->gprintf(op," %f, %f, %f\n",p->e[2][0],p->e[2][1],p->e[2][2]);
+
+ if (verb >= 2) {
+ unsigned int i, j, size;
+ unsigned int ii[MAX_CHAN]; /* maximum no of input channels */
+
+ op->gprintf(op," Input table:\n");
+ for (i = 0; i < p->inputEnt; i++) {
+ op->gprintf(op," %3u: ",i);
+ for (j = 0; j < p->inputChan; j++)
+ op->gprintf(op," %1.10f",p->inputTable[j * p->inputEnt + i]);
+ op->gprintf(op,"\n");
+ }
+
+ op->gprintf(op,"\n CLUT table:\n");
+ if (p->inputChan > MAX_CHAN) {
+ op->gprintf(op," !!Can't dump > %d input channel CLUT table!!\n",MAX_CHAN);
+ } else {
+ size = (p->outputChan * sat_pow(p->clutPoints,p->inputChan));
+ for (j = 0; j < p->inputChan; j++)
+ ii[j] = 0;
+ for (i = 0; i < size;) {
+ unsigned int k;
+ /* Print table entry index */
+ op->gprintf(op," ");
+ for (j = p->inputChan-1; j < p->inputChan; j--)
+ op->gprintf(op," %2u",ii[j]);
+ op->gprintf(op,":");
+ /* Print table entry contents */
+ for (k = 0; k < p->outputChan; k++, i++)
+ op->gprintf(op," %1.10f",p->clutTable[i]);
+ op->gprintf(op,"\n");
+
+ for (j = 0; j < p->inputChan; j++) { /* Increment index */
+ ii[j]++;
+ if (ii[j] < p->clutPoints)
+ break; /* No carry */
+ ii[j] = 0;
+ }
+ }
+ }
+
+ op->gprintf(op,"\n Output table:\n");
+ for (i = 0; i < p->outputEnt; i++) {
+ op->gprintf(op," %3u: ",i);
+ for (j = 0; j < p->outputChan; j++)
+ op->gprintf(op," %1.10f",p->outputTable[j * p->outputEnt + i]);
+ op->gprintf(op,"\n");
+ }
+
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmLut_allocate(
+ icmBase *pp
+) {
+ unsigned int i, j, g, size;
+ icmLut *p = (icmLut *)pp;
+ icc *icp = p->icp;
+
+ /* Sanity check */
+ if (p->inputChan < 1) {
+ sprintf(icp->err,"icmLut_alloc: Can't handle %d input channels\n",p->inputChan);
+ return icp->errc = 1;
+ }
+
+ if (p->inputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_alloc: Can't handle > %d input channels\n",MAX_CHAN);
+ return icp->errc = 1;
+ }
+
+ if (p->outputChan > MAX_CHAN) {
+ sprintf(icp->err,"icmLut_alloc: Can't handle > %d output channels\n",MAX_CHAN);
+ return icp->errc = 1;
+ }
+
+ if ((size = sat_mul(p->inputChan, p->inputEnt)) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_alloc size overflow");
+ return icp->errc = 1;
+ }
+ if (size != p->inputTable_size) {
+ if (ovr_mul(size, sizeof(double))) {
+ sprintf(icp->err,"icmLut_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->inputTable != NULL)
+ icp->al->free(icp->al, p->inputTable);
+ if ((p->inputTable = (double *) icp->al->calloc(icp->al,size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmLut_alloc: calloc() of Lut inputTable data failed");
+ return icp->errc = 2;
+ }
+ p->inputTable_size = size;
+ }
+ if ((size = sat_mul(p->outputChan, sat_pow(p->clutPoints,p->inputChan))) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_alloc size overflow");
+ return icp->errc = 1;
+ }
+ if (size != p->clutTable_size) {
+ if (ovr_mul(size, sizeof(double))) {
+ sprintf(icp->err,"icmLut_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->clutTable != NULL)
+ icp->al->free(icp->al, p->clutTable);
+ if ((p->clutTable = (double *) icp->al->calloc(icp->al,size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmLut_alloc: calloc() of Lut clutTable data failed");
+ return icp->errc = 2;
+ }
+ p->clutTable_size = size;
+ }
+ if ((size = sat_mul(p->outputChan, p->outputEnt)) == UINT_MAX) {
+ sprintf(icp->err,"icmLut_alloc size overflow");
+ return icp->errc = 1;
+ }
+ if (size != p->outputTable_size) {
+ if (ovr_mul(size, sizeof(double))) {
+ sprintf(icp->err,"icmLut_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->outputTable != NULL)
+ icp->al->free(icp->al, p->outputTable);
+ if ((p->outputTable = (double *) icp->al->calloc(icp->al,size, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmLut_alloc: calloc() of Lut outputTable data failed");
+ return icp->errc = 2;
+ }
+ p->outputTable_size = size;
+ }
+
+ /* Private: compute dimensional increment though clut */
+ /* Note that first channel varies least rapidly. */
+ i = p->inputChan-1;
+ p->dinc[i--] = p->outputChan;
+ for (; i < p->inputChan; i--)
+ p->dinc[i] = p->dinc[i+1] * p->clutPoints;
+
+ /* Private: compute offsets from base of cube to other corners */
+ for (p->dcube[0] = 0, g = 1, j = 0; j < p->inputChan; j++) {
+ for (i = 0; i < g; i++)
+ p->dcube[g+i] = p->dcube[i] + p->dinc[j];
+ g *= 2;
+ }
+
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmLut_delete(
+ icmBase *pp
+) {
+ icmLut *p = (icmLut *)pp;
+ icc *icp = p->icp;
+ int i;
+
+ if (p->inputTable != NULL)
+ icp->al->free(icp->al, p->inputTable);
+ if (p->clutTable != NULL)
+ icp->al->free(icp->al, p->clutTable);
+ if (p->outputTable != NULL)
+ icp->al->free(icp->al, p->outputTable);
+ for (i = 0; i < p->inputChan; i++)
+ icmTable_delete_bwd(icp, &p->rit[i]);
+ for (i = 0; i < p->outputChan; i++)
+ icmTable_delete_bwd(icp, &p->rot[i]);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmLut(
+ icc *icp
+) {
+ int i,j;
+ icmLut *p;
+ if ((p = (icmLut *) icp->al->calloc(icp->al,1,sizeof(icmLut))) == NULL)
+ return NULL;
+ p->ttype = icSigLut16Type;
+ p->refcount = 1;
+ p->get_size = icmLut_get_size;
+ p->read = icmLut_read;
+ p->write = icmLut_write;
+ p->dump = icmLut_dump;
+ p->allocate = icmLut_allocate;
+ p->del = icmLut_delete;
+
+ /* Lookup methods */
+ p->nu_matrix = icmLut_nu_matrix;
+ p->min_max = icmLut_min_max;
+ p->lookup_matrix = icmLut_lookup_matrix;
+ p->lookup_input = icmLut_lookup_input;
+ p->lookup_clut_nl = icmLut_lookup_clut_nl;
+ p->lookup_clut_sx = icmLut_lookup_clut_sx;
+ p->lookup_output = icmLut_lookup_output;
+
+ /* Set method */
+ p->set_tables = icmLut_set_tables;
+
+ p->icp = icp;
+
+ /* Set matrix to reasonable default */
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++) {
+ if (i == j)
+ p->e[i][j] = 1.0;
+ else
+ p->e[i][j] = 0.0;
+ }
+
+ /* Init lookups to non-dangerous values */
+ for (i = 0; i < MAX_CHAN; i++)
+ p->dinc[i] = 0;
+
+ for (i = 0; i < (1 << MAX_CHAN); i++)
+ p->dcube[i] = 0;
+
+ for (i = 0; i < MAX_CHAN; i++) {
+ p->rit[i].inited = 0;
+ p->rot[i].inited = 0;
+ }
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* Measurement */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmMeasurement_get_size(
+ icmBase *pp
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for standard observer */
+ len = sat_add(len, 12); /* 12 for XYZ of measurement backing */
+ len = sat_add(len, 4); /* 4 for measurement geometry */
+ len = sat_add(len, 4); /* 4 for measurement flare */
+ len = sat_add(len, 4); /* 4 for standard illuminant */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmMeasurement_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmMeasurement *p = (icmMeasurement *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf;
+
+ if (len < 36) {
+ sprintf(icp->err,"icmMeasurement_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmMeasurement_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmMeasurement_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmMeasurement_read: Wrong tag type for icmMeasurement");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read the encoded standard observer */
+ p->observer = (icStandardObserver)read_SInt32Number(bp + 8);
+
+ /* Read the XYZ values for measurement backing */
+ if ((rv = read_XYZNumber(&p->backing, bp+12)) != 0) {
+ sprintf(icp->err,"icmMeasurement: read_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Read the encoded measurement geometry */
+ p->geometry = (icMeasurementGeometry)read_SInt32Number(bp + 24);
+
+ /* Read the proportion of flare */
+ p->flare = read_U16Fixed16Number(bp + 28);
+
+ /* Read the encoded standard illuminant */
+ p->illuminant = (icIlluminant)read_SInt32Number(bp + 32);
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmMeasurement_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmMeasurement *p = (icmMeasurement *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmMeasurement_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmMeasurement_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmMeasurement_write, type: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write the encoded standard observer */
+ if ((rv = write_SInt32Number((int)p->observer, bp + 8)) != 0) {
+ sprintf(icp->err,"icmMeasurementa_write, observer: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the XYZ values for measurement backing */
+ if ((rv = write_XYZNumber(&p->backing, bp+12)) != 0) {
+ sprintf(icp->err,"icmMeasurement, backing: write_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the encoded measurement geometry */
+ if ((rv = write_SInt32Number((int)p->geometry, bp + 24)) != 0) {
+ sprintf(icp->err,"icmMeasurementa_write, geometry: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the proportion of flare */
+ if ((rv = write_U16Fixed16Number(p->flare, bp + 28)) != 0) {
+ sprintf(icp->err,"icmMeasurementa_write, flare: write_U16Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the encoded standard illuminant */
+ if ((rv = write_SInt32Number((int)p->illuminant, bp + 32)) != 0) {
+ sprintf(icp->err,"icmMeasurementa_write, illuminant: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmMeasurement_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmMeasurement_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmMeasurement *p = (icmMeasurement *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Measurement:\n");
+ op->gprintf(op," Standard Observer = %s\n", string_StandardObserver(p->observer));
+ op->gprintf(op," XYZ for Measurement Backing = %s\n", string_XYZNumber_and_Lab(&p->backing));
+ op->gprintf(op," Measurement Geometry = %s\n", string_MeasurementGeometry(p->geometry));
+ op->gprintf(op," Measurement Flare = %5.1f%%\n", p->flare * 100.0);
+ op->gprintf(op," Standard Illuminant = %s\n", string_Illuminant(p->illuminant));
+}
+
+/* Allocate variable sized data elements */
+static int icmMeasurement_allocate(
+ icmBase *pp
+) {
+ /* Nothing to do */
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmMeasurement_delete(
+ icmBase *pp
+) {
+ icmMeasurement *p = (icmMeasurement *)pp;
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmMeasurement(
+ icc *icp
+) {
+ icmMeasurement *p;
+ if ((p = (icmMeasurement *) icp->al->calloc(icp->al,1,sizeof(icmMeasurement))) == NULL)
+ return NULL;
+ p->ttype = icSigMeasurementType;
+ p->refcount = 1;
+ p->get_size = icmMeasurement_get_size;
+ p->read = icmMeasurement_read;
+ p->write = icmMeasurement_write;
+ p->dump = icmMeasurement_dump;
+ p->allocate = icmMeasurement_allocate;
+ p->del = icmMeasurement_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Named color structure read/write support */
+static int read_NamedColorVal(
+ icmNamedColorVal *p,
+ char *bp,
+ char *end,
+ icColorSpaceSignature pcs, /* Header Profile Connection Space */
+ unsigned int ndc /* Number of device corrds */
+) {
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int mxl; /* Max possible string length */
+ int rv;
+
+ if (bp > end) {
+ sprintf(icp->err,"icmNamedColorVal_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ mxl = (end - bp) < 32 ? (end - bp) : 32;
+ if ((rv = check_null_string(bp,mxl)) == 1) {
+ sprintf(icp->err,"icmNamedColorVal_read: Root name string not terminated");
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ strcpy(p->root, bp);
+ bp += strlen(p->root) + 1;
+ if (bp > end || ndc > (end - bp)) {
+ sprintf(icp->err,"icmNamedColorVal_read: Data too short to read device coords");
+ return icp->errc = 1;
+ }
+ for (i = 0; i < ndc; i++) {
+ p->deviceCoords[i] = read_DCS8Number(bp);
+ bp += 1;
+ }
+ return 0;
+}
+
+static int read_NamedColorVal2(
+ icmNamedColorVal *p,
+ char *bp,
+ char *end,
+ icColorSpaceSignature pcs, /* Header Profile Connection Space */
+ unsigned int ndc /* Number of device coords */
+) {
+ int rv;
+ icc *icp = p->icp;
+ unsigned int i;
+
+ if (bp > end
+ || (32 + 6) > (end - bp)
+ || ndc > (end - bp - 32 - 6)/2) {
+ sprintf(icp->err,"icmNamedColorVal2_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,32)) == 1) {
+ sprintf(icp->err,"icmNamedColorVal2_read: Root name string not terminated");
+ return icp->errc = 1;
+ }
+ memmove((void *)p->root,(void *)(bp + 0),32);
+ switch(pcs) {
+ case icSigXYZData:
+ read_PCSNumber(icp, icSigXYZData, p->pcsCoords, bp+32);
+ break;
+ case icSigLabData:
+ /* namedColor2Type retains legacy Lab encoding */
+ read_PCSNumber(icp, icmSigLabV2Data, p->pcsCoords, bp+32);
+ break;
+ default:
+ return 1; /* Unknown PCS */
+ }
+ for (i = 0; i < ndc; i++)
+ p->deviceCoords[i] = read_DCS16Number(bp + 32 + 6 + 2 * i);
+ return 0;
+}
+
+static int write_NamedColorVal(
+ icmNamedColorVal *p,
+ char *d,
+ icColorSpaceSignature pcs, /* Header Profile Connection Space */
+ unsigned int ndc /* Number of device corrds */
+) {
+ icc *icp = p->icp;
+ unsigned int i;
+ int rv;
+
+ if ((rv = check_null_string(p->root,32)) == 1) {
+ sprintf(icp->err,"icmNamedColorVal_write: Root string names is unterminated");
+ return icp->errc = 1;
+ }
+ strcpy(d, p->root);
+ d += strlen(p->root) + 1;
+ for (i = 0; i < ndc; i++) {
+ if ((rv = write_DCS8Number(p->deviceCoords[i], d)) != 0) {
+ sprintf(icp->err,"icmNamedColorVal_write: write of device coord failed");
+ return icp->errc = 1;
+ }
+ d += 1;
+ }
+ return 0;
+}
+
+static int write_NamedColorVal2(
+ icmNamedColorVal *p,
+ char *bp,
+ icColorSpaceSignature pcs, /* Header Profile Connection Space */
+ unsigned int ndc /* Number of device coords */
+) {
+ icc *icp = p->icp;
+ unsigned int i;
+ int rv;
+
+ if ((rv = check_null_string(p->root,32)) == 1) {
+ sprintf(icp->err,"icmNamedColorVal2_write: Root string names is unterminated");
+ return icp->errc = 1;
+ }
+ rv = 0;
+ memmove((void *)(bp + 0),(void *)p->root,32);
+ switch(pcs) {
+ case icSigXYZData:
+ rv |= write_PCSNumber(icp, icSigXYZData, p->pcsCoords, bp+32);
+ break;
+ case icSigLabData:
+ /* namedColor2Type retains legacy Lab encoding */
+ rv |= write_PCSNumber(icp, icmSigLabV2Data, p->pcsCoords, bp+32);
+ break;
+ default:
+ sprintf(icp->err,"icmNamedColorVal2_write: Unknown PCS");
+ return icp->errc = 1;
+ }
+ if (rv) {
+ sprintf(icp->err,"icmNamedColorVal2_write: write of PCS coord failed");
+ return icp->errc = 1;
+ }
+ for (i = 0; i < ndc; i++) {
+ if ((rv = write_DCS16Number(p->deviceCoords[i], bp + 32 + 6 + 2 * i)) != 0) {
+ sprintf(icp->err,"icmNamedColorVal2_write: write of device coord failed");
+ return icp->errc = 1;
+ }
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - */
+/* icmNamedColor object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmNamedColor_get_size(
+ icmBase *pp
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ unsigned int len = 0;
+ if (p->ttype == icSigNamedColorType) {
+ unsigned int i;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for vendor specific flags */
+ len = sat_add(len, 4); /* 4 for count of named colors */
+ len = sat_add(len, strlen(p->prefix) + 1); /* prefix of color names */
+ len = sat_add(len, strlen(p->suffix) + 1); /* suffix of color names */
+ for (i = 0; i < p->count; i++) {
+ len = sat_add(len, strlen(p->data[i].root) + 1); /* color names */
+ len = sat_add(len, p->nDeviceCoords * 1); /* bytes for each named color */
+ }
+ } else { /* Named Color 2 */
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for vendor specific flags */
+ len = sat_add(len, 4); /* 4 for count of named colors */
+ len = sat_add(len, 4); /* 4 for number of device coords */
+ len = sat_add(len, 32); /* 32 for prefix of color names */
+ len = sat_add(len, 32); /* 32 for suffix of color names */
+ len = sat_add(len, sat_mul(p->count, (32 + 6 + p->nDeviceCoords * 2)));
+ /* bytes for each named color */
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmNamedColor_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ char *bp, *buf, *end;
+ int rv;
+
+ if (len < 4) {
+ sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmNamedColor_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmNamedColor_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
+ if (p->ttype != icSigNamedColorType && p->ttype != icSigNamedColor2Type) {
+ sprintf(icp->err,"icmNamedColor_read: Wrong tag type for icmNamedColor");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ if (p->ttype == icSigNamedColorType) {
+ if (len < 16) {
+ sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Make sure that the number of device coords in known */
+ p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace);
+ if (p->nDeviceCoords > MAX_CHAN) {
+ sprintf(icp->err,"icmNamedColor_read: Can't handle more than %d device channels",MAX_CHAN);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ } else { /* icmNC2 */
+ if (len < 84) {
+ sprintf(icp->err,"icmNamedColor_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+
+ /* Read vendor specific flag */
+ p->vendorFlag = read_UInt32Number(bp+8);
+
+ /* Read count of named colors */
+ p->count = read_UInt32Number(bp+12);
+
+ if (p->ttype == icSigNamedColorType) {
+ unsigned int mxl; /* Max possible string length */
+ bp = bp + 16;
+
+ /* Prefix for each color name */
+ if (bp > end) {
+ sprintf(icp->err,"icmNamedColor_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ mxl = (end - bp) < 32 ? (end - bp) : 32;
+ if ((rv = check_null_string(bp,mxl)) == 1) {
+ sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ strcpy(p->prefix, bp);
+ bp += strlen(p->prefix) + 1;
+
+ /* Suffix for each color name */
+ if (bp > end) {
+ sprintf(icp->err,"icmNamedColor_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ mxl = (end - bp) < 32 ? (end - bp) : 32;
+ if ((rv = check_null_string(bp,mxl)) == 1) {
+ sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ strcpy(p->suffix, bp);
+ bp += strlen(p->suffix) + 1;
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < p->count; i++) {
+ if ((rv = read_NamedColorVal(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ bp += strlen(p->data[i].root) + 1;
+ bp += p->nDeviceCoords * 1;
+ }
+ } else { /* icmNC2 */
+ /* Number of device coords per color */
+ p->nDeviceCoords = read_UInt32Number(bp+16);
+ if (p->nDeviceCoords > MAX_CHAN) {
+ sprintf(icp->err,"icmNamedColor_read: Can't handle more than %d device channels",MAX_CHAN);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Prefix for each color name */
+ memmove((void *)p->prefix, (void *)(bp + 20), 32);
+ if ((rv = check_null_string(p->prefix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_read: Color prefix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Suffix for each color name */
+ memmove((void *)p->suffix, (void *)(bp + 52), 32);
+ if ((rv = check_null_string(p->suffix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_read: Color suffix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read all the data from the buffer */
+ bp = bp + 84;
+ for (i = 0; i < p->count; i++) {
+ if ((rv = read_NamedColorVal2(p->data+i, bp, end, icp->header->pcs, p->nDeviceCoords)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ bp += 32 + 6 + p->nDeviceCoords * 2;
+ }
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmNamedColor_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmNamedColor_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmNamedColor_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmNamedColor_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write vendor specific flag */
+ if ((rv = write_UInt32Number(p->vendorFlag, bp+8)) != 0) {
+ sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write count of named colors */
+ if ((rv = write_UInt32Number(p->count, bp+12)) != 0) {
+ sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ if (p->ttype == icSigNamedColorType) {
+ bp = bp + 16;
+
+ /* Prefix for each color name */
+ if ((rv = check_null_string(p->prefix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ strcpy(bp, p->prefix);
+ bp += strlen(p->prefix) + 1;
+
+ /* Suffix for each color name */
+ if ((rv = check_null_string(p->suffix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ strcpy(bp, p->suffix);
+ bp += strlen(p->suffix) + 1;
+
+ /* Write all the data to the buffer */
+
+ for (i = 0; i < p->count; i++) {
+ if ((rv = write_NamedColorVal(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ bp += strlen(p->data[i].root) + 1;
+ bp += p->nDeviceCoords * 1;
+ }
+ } else { /* icmNC2 */
+ /* Number of device coords per color */
+ if ((rv = write_UInt32Number(p->nDeviceCoords, bp+16)) != 0) {
+ sprintf(icp->err,"icmNamedColor_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Prefix for each color name */
+ if ((rv = check_null_string(p->prefix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_write: Color prefix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ memmove((void *)(bp + 20), (void *)p->prefix, 32);
+
+ /* Suffix for each color name */
+ if ((rv = check_null_string(p->suffix,32)) == 1) {
+ sprintf(icp->err,"icmNamedColor_write: Color sufix is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ memmove((void *)(bp + 52), (void *)p->suffix, 32);
+
+ /* Write all the data to the buffer */
+ bp = bp + 84;
+ for (i = 0; i < p->count; i++, bp += (32 + 6 + p->nDeviceCoords * 2)) {
+ if ((rv = write_NamedColorVal2(p->data+i, bp, icp->header->pcs, p->nDeviceCoords)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmNamedColor_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmNamedColor_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+ if (verb <= 0)
+ return;
+
+ if (p->ttype == icSigNamedColorType)
+ op->gprintf(op,"NamedColor:\n");
+ else
+ op->gprintf(op,"NamedColor2:\n");
+ op->gprintf(op," Vendor Flag = 0x%x\n",p->vendorFlag);
+ op->gprintf(op," No. colors = %u\n",p->count);
+ op->gprintf(op," No. dev. coords = %u\n",p->nDeviceCoords);
+ op->gprintf(op," Name prefix = '%s'\n",p->prefix);
+ op->gprintf(op," Name suffix = '%s'\n",p->suffix);
+ if (verb >= 2) {
+ unsigned int i, n;
+ icmNamedColorVal *vp;
+ for (i = 0; i < p->count; i++) {
+ vp = p->data + i;
+ op->gprintf(op," Color %lu:\n",i);
+ op->gprintf(op," Name root = '%s'\n",vp->root);
+
+ if (p->ttype == icSigNamedColor2Type) {
+ switch(icp->header->pcs) {
+ case icSigXYZData:
+ op->gprintf(op," XYZ = %f, %f, %f\n",
+ vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
+ break;
+ case icSigLabData:
+ op->gprintf(op," Lab = %f, %f, %f\n",
+ vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
+ break;
+ default:
+ op->gprintf(op," Unexpected PCS\n");
+ break;
+ }
+ }
+ if (p->nDeviceCoords > 0) {
+ op->gprintf(op," Device Coords = ");
+ for (n = 0; n < p->nDeviceCoords; n++) {
+ if (n > 0)
+ op->gprintf(op,", ");
+ op->gprintf(op,"%f",vp->deviceCoords[n]);
+ }
+ op->gprintf(op,"\n");
+ }
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmNamedColor_allocate(
+ icmBase *pp
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+
+ if (p->count != p->_count) {
+ unsigned int i;
+ if (ovr_mul(p->count, sizeof(icmNamedColorVal))) {
+ sprintf(icp->err,"icmNamedColor_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmNamedColorVal *) icp->al->calloc(icp->al,p->count, sizeof(icmNamedColorVal))) == NULL) {
+ sprintf(icp->err,"icmNamedColor_alloc: malloc() of icmNamedColor data failed");
+ return icp->errc = 2;
+ }
+ for (i = 0; i < p->count; i++) {
+ p->data[i].icp = icp; /* Do init */
+ }
+ p->_count = p->count;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmNamedColor_delete(
+ icmBase *pp
+) {
+ icmNamedColor *p = (icmNamedColor *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmNamedColor(
+ icc *icp
+) {
+ icmNamedColor *p;
+ if ((p = (icmNamedColor *) icp->al->calloc(icp->al,1,sizeof(icmNamedColor))) == NULL)
+ return NULL;
+ p->ttype = icSigNamedColor2Type;
+ p->refcount = 1;
+ p->get_size = icmNamedColor_get_size;
+ p->read = icmNamedColor_read;
+ p->write = icmNamedColor_write;
+ p->dump = icmNamedColor_dump;
+ p->allocate = icmNamedColor_allocate;
+ p->del = icmNamedColor_delete;
+ p->icp = icp;
+
+ /* Default the the number of device coords appropriately for NamedColorType */
+ p->nDeviceCoords = number_ColorSpaceSignature(icp->header->colorSpace);
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* Colorant table structure read/write support */
+/* (Contribution from Piet Vandenborre) */
+
+static int read_ColorantTableVal(
+ icmColorantTableVal *p,
+ char *bp,
+ char *end,
+ icColorSpaceSignature pcs /* Header Profile Connection Space */
+) {
+ int rv;
+ icc *icp = p->icp;
+ if (bp > end || (32 + 6) > (end - bp)) {
+ sprintf(icp->err,"icmColorantTableVal_read: Data too short to read");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,32)) == 1) {
+ sprintf(icp->err,"icmColorantTableVal_read: Name string not terminated");
+ return icp->errc = 1;
+ }
+ memmove((void *)p->name,(void *)(bp + 0),32);
+ switch(pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ read_PCSNumber(icp, pcs, p->pcsCoords, bp+32);
+ break;
+ default:
+ return 1; /* Unknown PCS */
+ }
+ return 0;
+}
+
+static int write_ColorantTableVal(
+ icmColorantTableVal *p,
+ char *bp,
+ icColorSpaceSignature pcs /* Header Profile Connection Space */
+) {
+ int rv;
+ icc *icp = p->icp;
+
+ if ((rv = check_null_string(p->name,32)) == 1) {
+ sprintf(icp->err,"icmColorantTableVal_write: Name string is unterminated");
+ return icp->errc = 1;
+ }
+ memmove((void *)(bp + 0),(void *)p->name,32);
+ rv = 0;
+ switch(pcs) {
+ case icSigXYZData:
+ case icSigLabData:
+ rv |= write_PCSNumber(icp, pcs, p->pcsCoords, bp+32);
+ break;
+ default:
+ sprintf(icp->err,"icmColorantTableVal_write: Unknown PCS");
+ return icp->errc = 1;
+ }
+ if (rv) {
+ sprintf(icp->err,"icmColorantTableVal_write: write of PCS coord failed");
+ return icp->errc = 1;
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - */
+/* icmColorantTable object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmColorantTable_get_size(
+ icmBase *pp
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ unsigned int len = 0;
+ if (p->ttype == icSigColorantTableType
+ || p->ttype == icmSigAltColorantTableType) {
+ unsigned int i;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for count of colorants */
+ for (i = 0; i < p->count; i++) {
+ len = sat_add(len, 32); /* colorant names - 32 bytes*/
+ len = sat_add(len, 6); /* colorant pcs value - 3 x 16bit number*/
+ }
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmColorantTable_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+ icColorSpaceSignature pcs;
+ unsigned int i;
+ char *bp, *buf, *end;
+ int rv = 0;
+
+ if (icp->header->deviceClass != icSigLinkClass)
+ pcs = icp->header->pcs;
+ else
+ pcs = icSigLabData;
+
+ if (len < 4) {
+ sprintf(icp->err,"icmColorantTable_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmColorantTable_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmColorantTable_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ p->ttype = (icTagTypeSignature)read_SInt32Number(bp);
+ if (p->ttype != icSigColorantTableType
+ && p->ttype != icmSigAltColorantTableType) {
+ sprintf(icp->err,"icmColorantTable_read: Wrong tag type for icmColorantTable");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ if (len < 12) {
+ sprintf(icp->err,"icmColorantTable_read: Tag too small to be legal");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read count of colorants */
+ if (p->ttype == icmSigAltColorantTableType)
+ p->count = read_UInt8Number(bp+8); /* Hmm. This is Little Endian */
+ else
+ p->count = read_UInt32Number(bp+8);
+
+ if (p->count > ((len - 12) / (32 + 6))) {
+ sprintf(icp->err,"icmColorantTable_read count overflow, count %x, len %d",p->count,len);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ bp = bp + 12;
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < p->count; i++, bp += (32 + 6)) {
+ if (p->ttype == icmSigAltColorantTableType /* Hack to reverse little endian */
+ && (end - bp) >= 38) {
+ int tt;
+ tt = *(bp + 32);
+ *(bp+32) = *(bp+33);
+ *(bp+33) = tt;
+ tt = *(bp + 34);
+ *(bp+34) = *(bp+35);
+ *(bp+35) = tt;
+ tt = *(bp + 36);
+ *(bp+36) = *(bp+37);
+ *(bp+37) = tt;
+ }
+ if ((rv = read_ColorantTableVal(p->data+i, bp, end, pcs)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+
+ icp->al->free(icp->al, buf);
+ return rv;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmColorantTable_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+ icColorSpaceSignature pcs;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ if (icp->header->deviceClass != icSigLinkClass)
+ pcs = icp->header->pcs;
+ else
+ pcs = icSigLabData;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmColorantTable_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmColorantTable_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmColorantTable_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write count of colorants */
+ if ((rv = write_UInt32Number(p->count, bp+8)) != 0) {
+ sprintf(icp->err,"icmColorantTable_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ bp = bp + 12;
+
+ /* Write all the data to the buffer */
+ for (i = 0; i < p->count; i++, bp += (32 + 6)) {
+ if ((rv = write_ColorantTableVal(p->data+i, bp, pcs)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmColorantTable_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmColorantTable_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+ icColorSpaceSignature pcs;
+
+ if (icp->header->deviceClass != icSigLinkClass)
+ pcs = icp->header->pcs;
+ else
+ pcs = icSigLabData;
+
+ if (verb <= 0)
+ return;
+
+ if (p->ttype == icSigColorantTableType
+ || p->ttype == icmSigAltColorantTableType)
+ op->gprintf(op,"ColorantTable:\n");
+ op->gprintf(op," No. colorants = %u\n",p->count);
+ if (verb >= 2) {
+ unsigned int i;
+ icmColorantTableVal *vp;
+ for (i = 0; i < p->count; i++) {
+ vp = p->data + i;
+ op->gprintf(op," Colorant %lu:\n",i);
+ op->gprintf(op," Name = '%s'\n",vp->name);
+
+ if (p->ttype == icSigColorantTableType
+ || p->ttype == icmSigAltColorantTableType) {
+
+ switch(pcs) {
+ case icSigXYZData:
+ op->gprintf(op," XYZ = %f, %f, %f\n",
+ vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
+ break;
+ case icSigLabData:
+ op->gprintf(op," Lab = %f, %f, %f\n",
+ vp->pcsCoords[0],vp->pcsCoords[1],vp->pcsCoords[2]);
+ break;
+ default:
+ op->gprintf(op," Unexpected PCS\n");
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmColorantTable_allocate(
+ icmBase *pp
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+
+ if (p->count != p->_count) {
+ unsigned int i;
+ if (ovr_mul(p->count, sizeof(icmColorantTableVal))) {
+ sprintf(icp->err,"icmColorantTable_alloc: count overflow (%d of %ld bytes)",p->count,sizeof(icmColorantTableVal));
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmColorantTableVal *) icp->al->calloc(icp->al,p->count, sizeof(icmColorantTableVal))) == NULL) {
+ sprintf(icp->err,"icmColorantTable_alloc: malloc() of icmColorantTable data failed");
+ return icp->errc = 2;
+ }
+ for (i = 0; i < p->count; i++) {
+ p->data[i].icp = icp; /* Do init */
+ }
+ p->_count = p->count;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmColorantTable_delete(
+ icmBase *pp
+) {
+ icmColorantTable *p = (icmColorantTable *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmColorantTable(
+ icc *icp
+) {
+ icmColorantTable *p;
+ if ((p = (icmColorantTable *) icp->al->calloc(icp->al,1,sizeof(icmColorantTable))) == NULL)
+ return NULL;
+ p->ttype = icSigColorantTableType;
+ p->refcount = 1;
+ p->get_size = icmColorantTable_get_size;
+ p->read = icmColorantTable_read;
+ p->write = icmColorantTable_write;
+ p->dump = icmColorantTable_dump;
+ p->allocate = icmColorantTable_allocate;
+ p->del = icmColorantTable_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* textDescription */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmTextDescription_get_size(
+ icmBase *pp
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addadd(len, 4, p->size); /* Ascii string length + ascii string */
+ len = sat_addaddmul(len, 8, 2, p->ucSize); /* Unicode language code + length + string */
+ len = sat_addadd(len, 3, 67); /* ScriptCode code, length string */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmTextDescription_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf, *end;
+
+#ifdef ICM_STRICT
+ if (len < (8 + 4 + 8 + 3 /* + 67 */)) {
+#else
+ if (len < (8 + 4 + 8 + 3)) {
+#endif
+ sprintf(icp->err,"icmTextDescription_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmTextDescription_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmTextDescription_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read from the buffer into the structure */
+ if ((rv = p->core_read(p, &bp, end)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* core read the object, return 0 on success, error code on fail */
+static int icmTextDescription_core_read(
+ icmTextDescription *p,
+ char **bpp, /* Pointer to buffer pointer, returns next after read */
+ char *end /* Pointer to past end of read buffer */
+) {
+ icc *icp = p->icp;
+ int rv;
+ char *bp = *bpp;
+
+ if (bp > end || 8 > (end - bp)) {
+ sprintf(icp->err,"icmTextDescription_read: Data too short to type descriptor");
+ *bpp = bp;
+ return icp->errc = 1;
+ }
+
+ p->size = read_UInt32Number(bp);
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Wrong tag type ('%s') for icmTextDescription",
+ tag2str((icTagTypeSignature)read_SInt32Number(bp)));
+ return icp->errc = 1;
+ }
+ bp = bp + 8;
+
+ /* Read the Ascii string */
+ if (bp > end || 4 > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read Ascii header");
+ return icp->errc = 1;
+ }
+ p->size = read_UInt32Number(bp);
+ bp += 4;
+ if (p->size > 0) {
+ if (bp > end || p->size > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read Ascii string");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,p->size)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: ascii string is not terminated");
+ return icp->errc = 1;
+ }
+#ifdef ICM_STRICT
+ if (rv == 2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: ascii string is shorter than count");
+ return icp->errc = 1;
+ }
+#endif
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ return rv;
+ }
+ strcpy(p->desc, bp);
+ bp += p->size;
+ }
+
+ /* Read the Unicode string */
+ if (bp > end || 8 > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
+ return icp->errc = 1;
+ }
+ p->ucLangCode = read_UInt32Number(bp);
+ bp += 4;
+ p->ucSize = read_UInt32Number(bp);
+ bp += 4;
+ if (p->ucSize > 0) {
+ ORD16 *up;
+ char *tbp;
+ if (bp > end || p->ucSize > (end - bp)/2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read Unicode string");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string16(bp,p->ucSize)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Unicode string is not terminated");
+ return icp->errc = 1;
+ }
+#ifdef ICM_STRICT
+ if (rv == 2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Unicode string is shorter than count");
+ return icp->errc = 1;
+ }
+#endif
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ return rv;
+ }
+ for (up = p->ucDesc, tbp = bp; tbp[0] != 0 || tbp[1] != 0; up++, tbp += 2)
+ *up = read_UInt16Number(tbp);
+ *up = 0; /* Unicode null */
+ bp += p->ucSize * 2;
+ }
+
+ /* Read the ScriptCode string */
+ if (bp > end || 3 > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode header");
+ return icp->errc = 1;
+ }
+ p->scCode = read_UInt16Number(bp);
+ bp += 2;
+ p->scSize = read_UInt8Number(bp);
+ bp += 1;
+ if (p->scSize > 0) {
+ if (p->scSize > 67) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: ScriptCode string too long");
+ return icp->errc = 1;
+ }
+ if (bp > end || p->scSize > (end - bp)) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: Data too short to read ScriptCode string");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,p->scSize)) == 1) {
+#ifdef ICM_STRICT
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_read: ScriptCode string is not terminated");
+ return icp->errc = 1;
+#else
+ /* Patch it up */
+ bp[p->scSize-1] = '\000';
+#endif
+ }
+ memmove((void *)p->scDesc, (void *)bp, p->scSize);
+ } else {
+ memset((void *)p->scDesc, 0, 67);
+ }
+ bp += 67;
+
+ *bpp = bp;
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmTextDescription_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmTextDescription_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmTextDescription_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write to the buffer from the structure */
+ if ((rv = p->core_write(p, &bp)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmTextDescription_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Core write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmTextDescription_core_write(
+ icmTextDescription *p,
+ char **bpp /* Pointer to buffer pointer, returns next after read */
+) {
+ icc *icp = p->icp;
+ char *bp = *bpp;
+ int rv;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_SInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp = bp + 8;
+
+ /* Write the Ascii string */
+ if ((rv = write_UInt32Number(p->size,bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if (p->size > 0) {
+ if ((rv = check_null_string(p->desc,p->size)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: ascii string is not terminated");
+ return icp->errc = 1;
+ }
+ if (rv == 2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: ascii string is shorter than length");
+ return icp->errc = 1;
+ }
+ strcpy(bp, p->desc);
+ bp += strlen(p->desc) + 1;
+ }
+
+ /* Write the Unicode string */
+ if ((rv = write_UInt32Number(p->ucLangCode, bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if ((rv = write_UInt32Number(p->ucSize, bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if (p->ucSize > 0) {
+ ORD16 *up;
+ if ((rv = check_null_string16((char *)p->ucDesc,p->ucSize)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: Unicode string is not terminated");
+ return icp->errc = 1;
+ }
+ if (rv == 2) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: Unicode string is shorter than length");
+ return icp->errc = 1;
+ }
+ for(up = p->ucDesc; *up != 0; up++, bp += 2) {
+ if ((rv = write_UInt16Number(((unsigned int)*up), bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ }
+ bp[0] = 0; /* null */
+ bp[1] = 0;
+ bp += 2;
+ }
+
+ /* Write the ScriptCode string */
+ if ((rv = write_UInt16Number(p->scCode, bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt16Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 2;
+ if ((rv = write_UInt8Number(p->scSize, bp)) != 0) {
+ sprintf(icp->err,"icmTextDescription_write: write_UInt8Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ bp += 1;
+ if (p->scSize > 0) {
+ if (p->scSize > 67) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: ScriptCode string too long");
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string((char *)p->scDesc,p->scSize)) == 1) {
+ *bpp = bp;
+ sprintf(icp->err,"icmTextDescription_write: ScriptCode string is not terminated");
+ return icp->errc = 1;
+ }
+ memmove((void *)bp, (void *)p->scDesc, 67);
+ } else {
+ memset((void *)bp, 0, 67);
+ }
+ bp += 67;
+
+ *bpp = bp;
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmTextDescription_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ unsigned int i, r, c;
+
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"TextDescription:\n");
+
+ if (p->size > 0) {
+ unsigned int size = p->size > 0 ? p->size-1 : 0;
+ op->gprintf(op," ASCII data, length %lu chars:\n",p->size);
+
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 75) {
+ if (isprint(p->desc[i])) {
+ op->gprintf(op,"%c",p->desc[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->desc[i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ } else {
+ op->gprintf(op," No ASCII data\n");
+ }
+
+ /* Can't dump Unicode or ScriptCode as text with portable code */
+ if (p->ucSize > 0) {
+ unsigned int size = p->ucSize;
+ op->gprintf(op," Unicode Data, Language code 0x%x, length %lu chars\n",
+ p->ucLangCode, p->ucSize);
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 75) {
+ op->gprintf(op,"%04x ",p->ucDesc[i]);
+ c += 5;
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ } else {
+ op->gprintf(op," No Unicode data\n");
+ }
+ if (p->scSize > 0) {
+ unsigned int size = p->scSize;
+ op->gprintf(op," ScriptCode Data, Code 0x%x, length %lu chars\n",
+ p->scCode, p->scSize);
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 75) {
+ op->gprintf(op,"%02x ",p->scDesc[i]);
+ c += 3;
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ } else {
+ op->gprintf(op," No ScriptCode data\n");
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmTextDescription_allocate(
+ icmBase *pp
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ icc *icp = p->icp;
+
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(char))) {
+ sprintf(icp->err,"icmTextDescription_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->desc != NULL)
+ icp->al->free(icp->al, p->desc);
+ if ((p->desc = (char *) icp->al->calloc(icp->al, p->size, sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmTextDescription_alloc: malloc() of Ascii description failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ if (p->ucSize != p->uc_size) {
+ if (ovr_mul(p->ucSize, sizeof(ORD16))) {
+ sprintf(icp->err,"icmTextDescription_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->ucDesc != NULL)
+ icp->al->free(icp->al, p->ucDesc);
+ if ((p->ucDesc = (ORD16 *) icp->al->calloc(icp->al, p->ucSize, sizeof(ORD16))) == NULL) {
+ sprintf(icp->err,"icmTextDescription_alloc: malloc() of Unicode description failed");
+ return icp->errc = 2;
+ }
+ p->uc_size = p->ucSize;
+ }
+ return 0;
+}
+
+/* Free all variable sized elements */
+static void icmTextDescription_unallocate(
+ icmTextDescription *p
+) {
+ icc *icp = p->icp;
+
+ if (p->desc != NULL)
+ icp->al->free(icp->al, p->desc);
+ if (p->ucDesc != NULL)
+ icp->al->free(icp->al, p->ucDesc);
+}
+
+/* Free all storage in the object */
+static void icmTextDescription_delete(
+ icmBase *pp
+) {
+ icmTextDescription *p = (icmTextDescription *)pp;
+ icc *icp = p->icp;
+
+ icmTextDescription_unallocate(p);
+ icp->al->free(icp->al, p);
+}
+
+/* Initialze a named object */
+static void icmTextDescription_init(
+ icmTextDescription *p,
+ icc *icp
+) {
+ memset((void *)p, 0, sizeof(icmTextDescription)); /* Imitate calloc */
+
+ p->ttype = icSigTextDescriptionType;
+ p->refcount = 1;
+ p->get_size = icmTextDescription_get_size;
+ p->read = icmTextDescription_read;
+ p->write = icmTextDescription_write;
+ p->dump = icmTextDescription_dump;
+ p->allocate = icmTextDescription_allocate;
+ p->del = icmTextDescription_delete;
+ p->icp = icp;
+
+ p->core_read = icmTextDescription_core_read;
+ p->core_write = icmTextDescription_core_write;
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmTextDescription(
+ icc *icp
+) {
+ icmTextDescription *p;
+ if ((p = (icmTextDescription *) icp->al->calloc(icp->al,1,sizeof(icmTextDescription))) == NULL)
+ return NULL;
+
+ icmTextDescription_init(p,icp);
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Support for icmDescStruct */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmDescStruct_get_size(
+ icmDescStruct *p
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 20); /* 20 bytes for header info */
+ len = sat_add(len, p->device.get_size((icmBase *)&p->device));
+ if (p->device.size == 0)
+ len = sat_add(len, 1); /* Extra 1 because of zero length desciption */
+ len = sat_add(len, p->model.get_size((icmBase *)&p->model));
+ if (p->model.size == 0)
+ len = sat_add(len, 1); /* Extra 1 because of zero length desciption */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmDescStruct_read(
+ icmDescStruct *p,
+ char **bpp, /* Pointer to buffer pointer, returns next after read */
+ char *end /* Pointer to past end of read buffer */
+) {
+ icc *icp = p->icp;
+ char *bp = *bpp;
+ int rv = 0;
+
+ if (bp > end || 20 > (end - bp)) {
+ sprintf(icp->err,"icmDescStruct_read: Data too short read header");
+ *bpp = bp;
+ return icp->errc = 1;
+ }
+
+ p->deviceMfg = read_SInt32Number(bp + 0);
+ p->deviceModel = read_UInt32Number(bp + 4);
+ read_UInt64Number(&p->attributes, bp + 8);
+ p->technology = (icTechnologySignature) read_UInt32Number(bp + 16);
+ *bpp = bp += 20;
+
+ /* Read the device text description */
+ if ((rv = p->device.core_read(&p->device, bpp, end)) != 0) {
+ return rv;
+ }
+
+ /* Read the model text description */
+ if ((rv = p->model.core_read(&p->model, bpp, end)) != 0) {
+ return rv;
+ }
+
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmDescStruct_write(
+ icmDescStruct *p,
+ char **bpp /* Pointer to buffer pointer, returns next after read */
+) {
+ icc *icp = p->icp;
+ char *bp = *bpp;
+ int rv = 0;
+ char *ttd = NULL;
+ unsigned int tts = 0;
+
+ if ((rv = write_SInt32Number(p->deviceMfg, bp + 0)) != 0) {
+ sprintf(icp->err,"icmDescStruct_write: write_SInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->deviceModel, bp + 4)) != 0) {
+ sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt64Number(&p->attributes, bp + 8)) != 0) {
+ sprintf(icp->err,"icmDescStruct_write: write_UInt64Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->technology, bp + 16)) != 0) {
+ sprintf(icp->err,"icmDescStruct_write: write_UInt32Number() failed");
+ *bpp = bp;
+ return icp->errc = rv;
+ }
+ *bpp = bp += 20;
+
+ /* Make sure the ASCII device text is a minimum size of 1, as per the spec. */
+ ttd = p->device.desc;
+ tts = p->device.size;
+
+ if (p->device.size == 0) {
+ p->device.desc = "";
+ p->device.size = 1;
+ }
+
+ /* Write the device text description */
+ if ((rv = p->device.core_write(&p->device, bpp)) != 0) {
+ return rv;
+ }
+
+ p->device.desc = ttd;
+ p->device.size = tts;
+
+ /* Make sure the ASCII model text is a minimum size of 1, as per the spec. */
+ ttd = p->model.desc;
+ tts = p->model.size;
+
+ if (p->model.size == 0) {
+ p->model.desc = "";
+ p->model.size = 1;
+ }
+
+ /* Write the model text description */
+ if ((rv = p->model.core_write(&p->model, bpp)) != 0) {
+ return rv;
+ }
+
+ p->model.desc = ttd;
+ p->model.size = tts;
+
+ /* Make sure the ASCII model text is a minimum size of 1, as per the spec. */
+ ttd = p->device.desc;
+ tts = p->device.size;
+
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmDescStruct_dump(
+ icmDescStruct *p,
+ icmFile *op, /* Output to dump to */
+ int verb, /* Verbosity level */
+ int index /* Description index */
+) {
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"DescStruct %u:\n",index);
+ if (verb >= 1) {
+ op->gprintf(op," Dev. Mnfctr. = %s\n",tag2str(p->deviceMfg)); /* ~~~ */
+ op->gprintf(op," Dev. Model = %s\n",tag2str(p->deviceModel)); /* ~~~ */
+ op->gprintf(op," Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l));
+ op->gprintf(op," Dev. Technology = %s\n", string_TechnologySignature(p->technology));
+ p->device.dump((icmBase *)&p->device, op,verb);
+ p->model.dump((icmBase *)&p->model, op,verb);
+ op->gprintf(op,"\n");
+ }
+}
+
+/* Allocate variable sized data elements (ie. descriptions) */
+static int icmDescStruct_allocate(
+ icmDescStruct *p
+) {
+ int rv;
+
+ if ((rv = p->device.allocate((icmBase *)&p->device)) != 0) {
+ return rv;
+ }
+ if ((rv = p->model.allocate((icmBase *)&p->model)) != 0) {
+ return rv;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmDescStruct_delete(
+ icmDescStruct *p
+) {
+ icmTextDescription_unallocate(&p->device);
+ icmTextDescription_unallocate(&p->model);
+}
+
+/* Init a DescStruct object */
+static void icmDescStruct_init(
+ icmDescStruct *p,
+ icc *icp
+) {
+
+ p->allocate = icmDescStruct_allocate;
+ p->icp = icp;
+
+ icmTextDescription_init(&p->device, icp);
+ icmTextDescription_init(&p->model, icp);
+}
+
+/* - - - - - - - - - - - - - - - */
+/* icmProfileSequenceDesc object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmProfileSequenceDesc_get_size(
+ icmBase *pp
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ unsigned int len = 0;
+ unsigned int i;
+ len = sat_add(len, 12); /* 12 bytes for tag, padding and count */
+ for (i = 0; i < p->count; i++) { /* All the description structures */
+ len = sat_add(len, icmDescStruct_get_size(&p->data[i]));
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmProfileSequenceDesc_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ char *bp, *buf, *end;
+ int rv = 0;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmProfileSequenceDesc_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmProfileSequenceDesc_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmProfileSequenceDesc_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmProfileSequenceDesc_read: Wrong tag type for icmProfileSequenceDesc");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp += 8; /* Skip padding */
+
+ p->count = read_UInt32Number(bp); /* Number of sequence descriptions */
+ bp += 4;
+
+ /* Read all the sequence descriptions */
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ for (i = 0; i < p->count; i++) {
+ if ((rv = icmDescStruct_read(&p->data[i], &bp, end)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmProfileSequenceDesc_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ if ((rv = write_UInt32Number(p->count,bp+8)) != 0) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp = bp + 12;
+
+ /* Write all the description structures */
+ for (i = 0; i < p->count; i++) {
+ if ((rv = icmDescStruct_write(&p->data[i], &bp)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmProfileSequenceDesc_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmProfileSequenceDesc_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"ProfileSequenceDesc:\n");
+ op->gprintf(op," No. elements = %u\n",p->count);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->count; i++)
+ icmDescStruct_dump(&p->data[i], op, verb-1, i);
+ }
+}
+
+/* Allocate variable sized data elements (ie. count of profile descriptions) */
+static int icmProfileSequenceDesc_allocate(
+ icmBase *pp
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+
+ if (p->count != p->_count) {
+ if (ovr_mul(p->count, sizeof(icmDescStruct))) {
+ sprintf(icp->err,"icmProfileSequenceDesc_allocate: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmDescStruct *) icp->al->calloc(icp->al, p->count, sizeof(icmDescStruct))) == NULL) {
+ sprintf(icp->err,"icmProfileSequenceDesc_allocate Allocation of DescStruct array failed");
+ return icp->errc = 2;
+ }
+ /* Now init the DescStructs */
+ for (i = 0; i < p->count; i++) {
+ icmDescStruct_init(&p->data[i], icp);
+ }
+ p->_count = p->count;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmProfileSequenceDesc_delete(
+ icmBase *pp
+) {
+ icmProfileSequenceDesc *p = (icmProfileSequenceDesc *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++) {
+ icmDescStruct_delete(&p->data[i]); /* Free allocated contents */
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmProfileSequenceDesc(
+ icc *icp
+) {
+ icmProfileSequenceDesc *p;
+ if ((p = (icmProfileSequenceDesc *) icp->al->calloc(icp->al,1,sizeof(icmProfileSequenceDesc))) == NULL)
+ return NULL;
+ p->ttype = icSigProfileSequenceDescType;
+ p->refcount = 1;
+ p->get_size = icmProfileSequenceDesc_get_size;
+ p->read = icmProfileSequenceDesc_read;
+ p->write = icmProfileSequenceDesc_write;
+ p->dump = icmProfileSequenceDesc_dump;
+ p->allocate = icmProfileSequenceDesc_allocate;
+ p->del = icmProfileSequenceDesc_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* Signature */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmSignature_get_size(
+ icmBase *pp
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for signature */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmSignature_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmSignature *p = (icmSignature *)pp;
+ icc *icp = p->icp;
+ char *bp, *buf;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmSignature_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmSignature_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmSignature_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmSignaturSignatureng tag type for icmSignature");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read the encoded measurement geometry */
+ p->sig = (icTechnologySignature)read_SInt32Number(bp + 8);
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmSignature_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmSignature *p = (icmSignature *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmSignature_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmSignature_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmSignature_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write the signature */
+ if ((rv = write_SInt32Number((int)p->sig, bp + 8)) != 0) {
+ sprintf(icp->err,"icmSignaturea_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmSignature_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmSignature_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmSignature *p = (icmSignature *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Signature\n");
+ op->gprintf(op," Technology = %s\n", string_TechnologySignature(p->sig));
+}
+
+/* Allocate variable sized data elements */
+static int icmSignature_allocate(
+ icmBase *pp
+) {
+ /* Nothing to do */
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmSignature_delete(
+ icmBase *pp
+) {
+ icmSignature *p = (icmSignature *)pp;
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmSignature(
+ icc *icp
+) {
+ icmSignature *p;
+ if ((p = (icmSignature *) icp->al->calloc(icp->al,1,sizeof(icmSignature))) == NULL)
+ return NULL;
+ p->ttype = icSigSignatureType;
+ p->refcount = 1;
+ p->get_size = icmSignature_get_size;
+ p->read = icmSignature_read;
+ p->write = icmSignature_write;
+ p->dump = icmSignature_dump;
+ p->allocate = icmSignature_allocate;
+ p->del = icmSignature_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+
+/* Data conversion support functions */
+static int read_ScreeningData(icmScreeningData *p, char *d) {
+ p->frequency = read_S15Fixed16Number(d + 0);
+ p->angle = read_S15Fixed16Number(d + 4);
+ p->spotShape = (icSpotShape)read_SInt32Number(d + 8);
+ return 0;
+}
+
+static int write_ScreeningData(icmScreeningData *p, char *d) {
+ int rv;
+ if ((rv = write_S15Fixed16Number(p->frequency, d + 0)) != 0)
+ return rv;
+ if ((rv = write_S15Fixed16Number(p->angle, d + 4)) != 0)
+ return rv;
+ if ((rv = write_SInt32Number((int)p->spotShape, d + 8)) != 0)
+ return rv;
+ return 0;
+}
+
+
+/* icmScreening object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmScreening_get_size(
+ icmBase *pp
+) {
+ icmScreening *p = (icmScreening *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 16); /* 16 bytes for tag, padding, flag & channeles */
+ len = sat_addmul(len, p->channels, 12); /* 12 bytes for each channel */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmScreening_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmScreening *p = (icmScreening *)pp;
+ icc *icp = p->icp;
+ int rv = 0;
+ unsigned int i;
+ char *bp, *buf, *end;
+
+ if (len < 12) {
+ sprintf(icp->err,"icmScreening_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmScreening_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmScreening_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmScreening_read: Wrong tag type for icmScreening");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->screeningFlag = read_UInt32Number(bp+8); /* Flags */
+ p->channels = read_UInt32Number(bp+12); /* Number of channels */
+ bp = bp + 16;
+
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+
+ /* Read all the data from the buffer */
+ for (i = 0; i < p->channels; i++, bp += 12) {
+ if (bp > end || 12 > (end - bp)) {
+ sprintf(icp->err,"icmScreening_read: Data too short to read Screening Data");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ read_ScreeningData(&p->data[i], bp);
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmScreening_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmScreening *p = (icmScreening *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmScreening_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmScreening_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmScreening_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ if ((rv = write_UInt32Number(p->screeningFlag,bp+8)) != 0) {
+ sprintf(icp->err,"icmScreening_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->channels,bp+12)) != 0) {
+ sprintf(icp->err,"icmScreening_write: write_UInt32NumberXYZumber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp = bp + 16;
+
+ /* Write all the data to the buffer */
+ for (i = 0; i < p->channels; i++, bp += 12) {
+ if ((rv = write_ScreeningData(&p->data[i],bp)) != 0) {
+ sprintf(icp->err,"icmScreening_write: write_ScreeningData() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmScreening_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmScreening_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmScreening *p = (icmScreening *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Screening:\n");
+ op->gprintf(op," Flags = %s\n", string_ScreenEncodings(p->screeningFlag));
+ op->gprintf(op," No. channels = %u\n",p->channels);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->channels; i++) {
+ op->gprintf(op," %lu:\n",i);
+ op->gprintf(op," Frequency: %f\n",p->data[i].frequency);
+ op->gprintf(op," Angle: %f\n",p->data[i].angle);
+ op->gprintf(op," Spot shape: %s\n", string_SpotShape(p->data[i].spotShape));
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmScreening_allocate(
+ icmBase *pp
+) {
+ icmScreening *p = (icmScreening *)pp;
+ icc *icp = p->icp;
+
+ if (p->channels != p->_channels) {
+ if (ovr_mul(p->channels, sizeof(icmScreeningData))) {
+ sprintf(icp->err,"icmScreening_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ if ((p->data = (icmScreeningData *) icp->al->malloc(icp->al, p->channels * sizeof(icmScreeningData))) == NULL) {
+ sprintf(icp->err,"icmScreening_alloc: malloc() of icmScreening data failed");
+ return icp->errc = 2;
+ }
+ p->_channels = p->channels;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmScreening_delete(
+ icmBase *pp
+) {
+ icmScreening *p = (icmScreening *)pp;
+ icc *icp = p->icp;
+
+ if (p->data != NULL)
+ icp->al->free(icp->al, p->data);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmScreening(
+ icc *icp
+) {
+ icmScreening *p;
+ if ((p = (icmScreening *) icp->al->calloc(icp->al,1,sizeof(icmScreening))) == NULL)
+ return NULL;
+ p->ttype = icSigScreeningType;
+ p->refcount = 1;
+ p->get_size = icmScreening_get_size;
+ p->read = icmScreening_read;
+ p->write = icmScreening_write;
+ p->dump = icmScreening_dump;
+ p->allocate = icmScreening_allocate;
+ p->del = icmScreening_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmUcrBg object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmUcrBg_get_size(
+ icmBase *pp
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addaddmul(len, 4, p->UCRcount, 2); /* Undercolor Removal */
+ len = sat_addaddmul(len, 4, p->BGcount, 2); /* Black Generation */
+ len = sat_add(len, p->size); /* Description string */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmUcrBg_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ int rv;
+ char *bp, *buf, *end;
+
+ if (len < 16) {
+ sprintf(icp->err,"icmUcrBg_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUcrBg_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmUcrBg_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmUcrBg_read: Wrong tag type for icmUcrBg");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->UCRcount = read_UInt32Number(bp+8); /* First curve count */
+ bp = bp + 12;
+
+ if (p->UCRcount > 0) {
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ for (i = 0; i < p->UCRcount; i++, bp += 2) {
+ if (bp > end || 2 > (end - bp)) {
+ sprintf(icp->err,"icmUcrBg_read: Data too short to read UCR Data");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if (p->UCRcount == 1) /* % */
+ p->UCRcurve[i] = (double)read_UInt16Number(bp);
+ else /* 0.0 - 1.0 */
+ p->UCRcurve[i] = read_DCS16Number(bp);
+ }
+ } else {
+ p->UCRcurve = NULL;
+ }
+
+ if (bp > end || 4 > (end - bp)) {
+ sprintf(icp->err,"icmData_read: Data too short to read Black Gen count");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->BGcount = read_UInt32Number(bp); /* First curve count */
+ bp += 4;
+
+ if (p->BGcount > 0) {
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ for (i = 0; i < p->BGcount; i++, bp += 2) {
+ if (bp > end || 2 > (end - bp)) {
+ sprintf(icp->err,"icmUcrBg_read: Data too short to read BG Data");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if (p->BGcount == 1) /* % */
+ p->BGcurve[i] = (double)read_UInt16Number(bp);
+ else /* 0.0 - 1.0 */
+ p->BGcurve[i] = read_DCS16Number(bp);
+ }
+ } else {
+ p->BGcurve = NULL;
+ }
+
+ p->size = end - bp; /* Nominal string length */
+ if (p->size > 0) {
+ if ((rv = check_null_string(bp, p->size)) == 1) {
+ sprintf(icp->err,"icmUcrBg_read: string is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->size = strlen(bp) + 1;
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ memmove((void *)p->string, (void *)bp, p->size);
+ bp += p->size;
+ } else {
+ p->string = NULL;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmUcrBg_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ icc *icp = p->icp;
+ unsigned int i;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmUcrBg_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmUcrBg_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp = bp + 8;
+
+ /* Write UCR curve */
+ if ((rv = write_UInt32Number(p->UCRcount,bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 4;
+
+ for (i = 0; i < p->UCRcount; i++, bp += 2) {
+ if (p->UCRcount == 1) { /* % */
+ if ((rv = write_UInt16Number((unsigned int)(p->UCRcurve[i]+0.5),bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ } else {
+ if ((rv = write_DCS16Number(p->UCRcurve[i],bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->UCRcurve[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ /* Write BG curve */
+ if ((rv = write_UInt32Number(p->BGcount,bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 4;
+
+ for (i = 0; i < p->BGcount; i++, bp += 2) {
+ if (p->BGcount == 1) { /* % */
+ if ((rv = write_UInt16Number((unsigned int)(p->BGcurve[i]+0.5),bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_UInt16umber() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ } else {
+ if ((rv = write_DCS16Number(p->BGcurve[i],bp)) != 0) {
+ sprintf(icp->err,"icmUcrBg_write: write_DCS16umber(%f) failed",p->BGcurve[i]);
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ if (p->string != NULL) {
+ if ((rv = check_null_string(p->string,p->size)) == 1) {
+ sprintf(icp->err,"icmUcrBg_write: text is not null terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if (rv == 2) {
+ sprintf(icp->err,"icmUcrBg_write: text is shorter than length");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ memmove((void *)bp, (void *)p->string, p->size);
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmUcrBg_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmUcrBg_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Undercolor Removal Curve & Black Generation:\n");
+
+ if (p->UCRcount == 0) {
+ op->gprintf(op," UCR: Not specified\n");
+ } else if (p->UCRcount == 1) {
+ op->gprintf(op," UCR: %f%%\n",p->UCRcurve[0]);
+ } else {
+ op->gprintf(op," UCR curve no. elements = %u\n",p->UCRcount);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->UCRcount; i++)
+ op->gprintf(op," %3lu: %f\n",i,p->UCRcurve[i]);
+ }
+ }
+ if (p->BGcount == 0) {
+ op->gprintf(op," BG: Not specified\n");
+ } else if (p->BGcount == 1) {
+ op->gprintf(op," BG: %f%%\n",p->BGcurve[0]);
+ } else {
+ op->gprintf(op," BG curve no. elements = %u\n",p->BGcount);
+ if (verb >= 2) {
+ unsigned int i;
+ for (i = 0; i < p->BGcount; i++)
+ op->gprintf(op," %3lu: %f\n",i,p->BGcurve[i]);
+ }
+ }
+
+ {
+ unsigned int i, r, c, size;
+ op->gprintf(op," Description:\n");
+ op->gprintf(op," No. chars = %lu\n",p->size);
+
+ size = p->size > 0 ? p->size-1 : 0;
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 73) {
+ if (isprint(p->string[i])) {
+ op->gprintf(op,"%c",p->string[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->string[i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmUcrBg_allocate(
+ icmBase *pp
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ icc *icp = p->icp;
+
+ if (p->UCRcount != p->UCR_count) {
+ if (ovr_mul(p->UCRcount, sizeof(double))) {
+ sprintf(icp->err,"icmUcrBg_allocate: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->UCRcurve != NULL)
+ icp->al->free(icp->al, p->UCRcurve);
+ if ((p->UCRcurve = (double *) icp->al->calloc(icp->al, p->UCRcount, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmUcrBg_allocate: malloc() of UCR curve data failed");
+ return icp->errc = 2;
+ }
+ p->UCR_count = p->UCRcount;
+ }
+ if (p->BGcount != p->BG_count) {
+ if (ovr_mul(p->BGcount, sizeof(double))) {
+ sprintf(icp->err,"icmUcrBg_allocate: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->BGcurve != NULL)
+ icp->al->free(icp->al, p->BGcurve);
+ if ((p->BGcurve = (double *) icp->al->calloc(icp->al, p->BGcount, sizeof(double))) == NULL) {
+ sprintf(icp->err,"icmUcrBg_allocate: malloc() of BG curve data failed");
+ return icp->errc = 2;
+ }
+ p->BG_count = p->BGcount;
+ }
+ if (p->size != p->_size) {
+ if (ovr_mul(p->size, sizeof(char))) {
+ sprintf(icp->err,"icmUcrBg_allocate: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->string != NULL)
+ icp->al->free(icp->al, p->string);
+ if ((p->string = (char *) icp->al->calloc(icp->al, p->size, sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmUcrBg_allocate: malloc() of string data failed");
+ return icp->errc = 2;
+ }
+ p->_size = p->size;
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmUcrBg_delete(
+ icmBase *pp
+) {
+ icmUcrBg *p = (icmUcrBg *)pp;
+ icc *icp = p->icp;
+
+ if (p->UCRcurve != NULL)
+ icp->al->free(icp->al, p->UCRcurve);
+ if (p->BGcurve != NULL)
+ icp->al->free(icp->al, p->BGcurve);
+ if (p->string != NULL)
+ icp->al->free(icp->al, p->string);
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmUcrBg(
+ icc *icp
+) {
+ icmUcrBg *p;
+ if ((p = (icmUcrBg *) icp->al->calloc(icp->al,1,sizeof(icmUcrBg))) == NULL)
+ return NULL;
+ p->ttype = icSigUcrBgType;
+ p->refcount = 1;
+ p->get_size = icmUcrBg_get_size;
+ p->read = icmUcrBg_read;
+ p->write = icmUcrBg_write;
+ p->dump = icmUcrBg_dump;
+ p->allocate = icmUcrBg_allocate;
+ p->del = icmUcrBg_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* VideoCardGamma (ColorSync 2.5 specific - c/o Neil Okamoto) */
+/* 'vcgt' */
+
+static unsigned int icmVideoCardGamma_get_size(
+ icmBase *pp
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ unsigned int len = 0;
+
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 4); /* 4 for gamma type */
+
+ /* compute size of remainder */
+ if (p->tagType == icmVideoCardGammaTableType) {
+ len = sat_add(len, 2); /* 2 bytes for channels */
+ len = sat_add(len, 2); /* 2 for entry count */
+ len = sat_add(len, 2); /* 2 for entry size */
+ len = sat_add(len, sat_mul3(p->u.table.channels, /* compute table size */
+ p->u.table.entryCount, p->u.table.entrySize));
+ }
+ else if (p->tagType == icmVideoCardGammaFormulaType) {
+ len = sat_add(len, 12); /* 4 bytes each for red gamma, min, & max */
+ len = sat_add(len, 12); /* 4 bytes each for green gamma, min & max */
+ len = sat_add(len, 12); /* 4 bytes each for blue gamma, min & max */
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmVideoCardGamma_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ icc *icp = p->icp;
+ int rv, c;
+ char *bp, *buf;
+ ORD8 *pchar;
+ ORD16 *pshort;
+
+ if (len < 18) {
+ sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmVideoCardGamma_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmVideoCardGamma_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmVideoCardGamma_read: Wrong tag type for icmVideoCardGamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read gamma format (eg. table or formula) from the buffer */
+ p->tagType = (icmVideoCardGammaTagType)read_UInt32Number(bp+8);
+
+ /* Read remaining gamma data based on format */
+ if (p->tagType == icmVideoCardGammaTableType) {
+ p->u.table.channels = read_UInt16Number(bp+12);
+ p->u.table.entryCount = read_UInt16Number(bp+14);
+ p->u.table.entrySize = read_UInt16Number(bp+16);
+ if ((len-18) < sat_mul3(p->u.table.channels, p->u.table.entryCount,
+ p->u.table.entrySize)) {
+ sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+ if ((rv = pp->allocate(pp)) != 0) { /* make space for table */
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ /* ~~~~ This should be a table of doubles like the rest of icclib ! ~~~~ */
+ pchar = (ORD8 *)p->u.table.data;
+ pshort = (ORD16 *)p->u.table.data;
+ for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) {
+ switch (p->u.table.entrySize) {
+ case 1:
+ *pchar++ = read_UInt8Number(bp);
+ bp++;
+ break;
+ case 2:
+ *pshort++ = read_UInt16Number(bp);
+ bp+=2;
+ break;
+ default:
+ sprintf(icp->err,"icmVideoCardGamma_read: unsupported table entry size");
+ pp->del(pp);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+ } else if (p->tagType == icmVideoCardGammaFormulaType) {
+ if (len < 48) {
+ sprintf(icp->err,"icmVideoCardGamma_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+ p->u.table.channels = 3; /* Always 3 for formula */
+ p->u.formula.redGamma = read_S15Fixed16Number(bp+12);
+ p->u.formula.redMin = read_S15Fixed16Number(bp+16);
+ p->u.formula.redMax = read_S15Fixed16Number(bp+20);
+ p->u.formula.greenGamma = read_S15Fixed16Number(bp+24);
+ p->u.formula.greenMin = read_S15Fixed16Number(bp+28);
+ p->u.formula.greenMax = read_S15Fixed16Number(bp+32);
+ p->u.formula.blueGamma = read_S15Fixed16Number(bp+36);
+ p->u.formula.blueMin = read_S15Fixed16Number(bp+40);
+ p->u.formula.blueMax = read_S15Fixed16Number(bp+44);
+ } else {
+ sprintf(icp->err,"icmVideoCardGammaTable_read: Unknown gamma format for icmVideoCardGamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmVideoCardGamma_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0, c;
+ ORD8 *pchar;
+ ORD16 *pshort;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmViewingConditions_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmViewingConditions_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write gamma format (eg. table of formula) */
+ if ((rv = write_UInt32Number(p->tagType,bp+8)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write remaining gamma data based on format */
+ if (p->tagType == icmVideoCardGammaTableType) {
+ if ((rv = write_UInt16Number(p->u.table.channels,bp+12)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt16Number(p->u.table.entryCount,bp+14)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt16Number(p->u.table.entrySize,bp+16)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_UInt16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ pchar = (ORD8 *)p->u.table.data;
+ pshort = (ORD16 *)p->u.table.data;
+ for (c=0, bp=bp+18; c<p->u.table.channels*p->u.table.entryCount; c++) {
+ switch (p->u.table.entrySize) {
+ case 1:
+ write_UInt8Number(*pchar++,bp);
+ bp++;
+ break;
+ case 2:
+ write_UInt16Number(*pshort++,bp);
+ bp+=2;
+ break;
+ default:
+ sprintf(icp->err,"icmVideoCardGamma_write: unsupported table entry size");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ }
+ } else if (p->tagType == icmVideoCardGammaFormulaType) {
+ if ((rv = write_S15Fixed16Number(p->u.formula.redGamma,bp+12)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.redMin,bp+16)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.redMax,bp+20)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.greenGamma,bp+24)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.greenMin,bp+28)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.greenMax,bp+32)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.blueGamma,bp+36)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.blueMin,bp+40)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_S15Fixed16Number(p->u.formula.blueMax,bp+44)) != 0) {
+ sprintf(icp->err,"icmVideoCardGamma_write: write_S15Fixed16Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ } else {
+ sprintf(icp->err,"icmVideoCardGammaTable_write: Unknown gamma format for icmVideoCardGamma");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmVideoCardGamma_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ int c,i;
+
+ if (verb <= 0)
+ return;
+
+ if (p->tagType == icmVideoCardGammaTableType) {
+ op->gprintf(op,"VideoCardGammaTable:\n");
+ op->gprintf(op," channels = %d\n", p->u.table.channels);
+ op->gprintf(op," entries = %d\n", p->u.table.entryCount);
+ op->gprintf(op," entrysize = %d\n", p->u.table.entrySize);
+ if (verb >= 2) {
+ /* dump array contents also */
+ for (c=0; c<p->u.table.channels; c++) {
+ op->gprintf(op," channel #%d\n",c);
+ for (i=0; i<p->u.table.entryCount; i++) {
+ if (p->u.table.entrySize == 1) {
+ op->gprintf(op," %d: %d\n",i,((ORD8 *)p->u.table.data)[c*p->u.table.entryCount+i]);
+ }
+ else if (p->u.table.entrySize == 2) {
+ op->gprintf(op," %d: %d\n",i,((ORD16 *)p->u.table.data)[c*p->u.table.entryCount+i]);
+ }
+ }
+ }
+ }
+ } else if (p->tagType == icmVideoCardGammaFormulaType) {
+ op->gprintf(op,"VideoCardGammaFormula:\n");
+ op->gprintf(op," red gamma = %f\n", p->u.formula.redGamma);
+ op->gprintf(op," red min = %f\n", p->u.formula.redMin);
+ op->gprintf(op," red max = %f\n", p->u.formula.redMax);
+ op->gprintf(op," green gamma = %f\n", p->u.formula.greenGamma);
+ op->gprintf(op," green min = %f\n", p->u.formula.greenMin);
+ op->gprintf(op," green max = %f\n", p->u.formula.greenMax);
+ op->gprintf(op," blue gamma = %f\n", p->u.formula.blueGamma);
+ op->gprintf(op," blue min = %f\n", p->u.formula.blueMin);
+ op->gprintf(op," blue max = %f\n", p->u.formula.blueMax);
+ } else {
+ op->gprintf(op," Unknown tag format\n");
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmVideoCardGamma_allocate(
+ icmBase *pp
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ icc *icp = p->icp;
+ unsigned int size;
+
+ /* note: allocation is only relevant for table type
+ * and in that case the channels, entryCount, and entrySize
+ * fields must all be set prior to getting here
+ */
+
+ if (p->tagType == icmVideoCardGammaTableType) {
+ size = sat_mul(p->u.table.channels, p->u.table.entryCount);
+ switch (p->u.table.entrySize) {
+ case 1:
+ size = sat_mul(size, sizeof(ORD8));
+ break;
+ case 2:
+ size = sat_mul(size, sizeof(unsigned short));
+ break;
+ default:
+ sprintf(icp->err,"icmVideoCardGamma_alloc: unsupported table entry size");
+ return icp->errc = 1;
+ }
+ if (size == UINT_MAX) {
+ sprintf(icp->err,"icmVideoCardGamma_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->u.table.data != NULL)
+ icp->al->free(icp->al, p->u.table.data);
+ if ((p->u.table.data = (void*) icp->al->malloc(icp->al, size)) == NULL) {
+ sprintf(icp->err,"icmVideoCardGamma_alloc: malloc() of table data failed");
+ return icp->errc = 2;
+ }
+ }
+
+ return 0;
+}
+
+/* Read a value */
+static double icmVideoCardGamma_lookup(
+ icmVideoCardGamma *p,
+ int chan, /* Channel, 0, 1 or 2 */
+ double iv /* Input value 0.0 - 1.0 */
+) {
+ double ov = 0.0;
+
+ if (chan < 0 || chan > (p->u.table.channels-1)
+ || iv < 0.0 || iv > 1.0)
+ return iv;
+
+ if (p->tagType == icmVideoCardGammaTableType && p->u.table.entryCount == 0) {
+ /* Deal with siliness */
+ ov = iv;
+ } else if (p->tagType == icmVideoCardGammaTableType) {
+ /* Use linear interpolation */
+ unsigned int ix;
+ double val0, val1, w;
+ double inputEnt_1 = (double)(p->u.table.entryCount-1);
+
+ val0 = iv * inputEnt_1;
+ if (val0 < 0.0)
+ val0 = 0.0;
+ else if (val0 > inputEnt_1)
+ val0 = inputEnt_1;
+ ix = (unsigned int)floor(val0); /* Coordinate */
+ if (ix > (p->u.table.entryCount-2))
+ ix = (p->u.table.entryCount-2);
+ w = val0 - (double)ix; /* weight */
+ if (p->u.table.entrySize == 1) {
+ val0 = ((ORD8 *)p->u.table.data)[chan * p->u.table.entryCount + ix]/255.0;
+ val1 = ((ORD8 *)p->u.table.data)[chan * p->u.table.entryCount + ix + 1]/255.0;
+ } else if (p->u.table.entrySize == 2) {
+ val0 = ((ORD16 *)p->u.table.data)[chan * p->u.table.entryCount + ix]/65535.0;
+ val1 = ((ORD16 *)p->u.table.data)[chan * p->u.table.entryCount + ix + 1]/65535.0;
+ } else {
+ val0 = val1 = iv;
+ }
+ ov = val0 + w * (val1 - val0);
+
+ } else if (p->tagType == icmVideoCardGammaFormulaType) {
+ double min, max, gam;
+
+ if (iv == 0) {
+ min = p->u.formula.redMin;
+ max = p->u.formula.redMax;
+ gam = p->u.formula.redGamma;
+ } else if (iv == 1) {
+ min = p->u.formula.greenMin;
+ max = p->u.formula.greenMax;
+ gam = p->u.formula.greenGamma;
+ } else {
+ min = p->u.formula.blueMin;
+ max = p->u.formula.blueMax;
+ gam = p->u.formula.blueGamma;
+ }
+
+ /* The Apple OSX doco confirms this is the formula */
+ ov = min + (max - min) * pow(iv, gam);
+ }
+ return ov;
+}
+
+/* Free all storage in the object */
+static void icmVideoCardGamma_delete(
+ icmBase *pp
+) {
+ icmVideoCardGamma *p = (icmVideoCardGamma *)pp;
+ icc *icp = p->icp;
+
+ if (p->tagType == icmVideoCardGammaTableType && p->u.table.data != NULL)
+ icp->al->free(icp->al, p->u.table.data);
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmVideoCardGamma(
+ icc *icp
+) {
+ icmVideoCardGamma *p;
+ if ((p = (icmVideoCardGamma *) icp->al->calloc(icp->al,1,sizeof(icmVideoCardGamma))) == NULL)
+ return NULL;
+ p->ttype = icSigVideoCardGammaType;
+ p->refcount = 1;
+ p->get_size = icmVideoCardGamma_get_size;
+ p->read = icmVideoCardGamma_read;
+ p->write = icmVideoCardGamma_write;
+ p->lookup = icmVideoCardGamma_lookup;
+ p->dump = icmVideoCardGamma_dump;
+ p->allocate = icmVideoCardGamma_allocate;
+ p->del = icmVideoCardGamma_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* ViewingConditions */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmViewingConditions_get_size(
+ icmBase *pp
+) {
+ unsigned int len = 0;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_add(len, 12); /* 12 for XYZ of illuminant */
+ len = sat_add(len, 12); /* 12 for XYZ of surround */
+ len = sat_add(len, 4); /* 4 for illuminant type */
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmViewingConditions_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmViewingConditions *p = (icmViewingConditions *)pp;
+ icc *icp = p->icp;
+ int rv;
+ char *bp, *buf;
+
+ if (len < 36) {
+ sprintf(icp->err,"icmViewingConditions_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmViewingConditions_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmViewingConditions_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmViewingConditions_read: Wrong tag type for icmViewingConditions");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read the XYZ values for the illuminant */
+ if ((rv = read_XYZNumber(&p->illuminant, bp+8)) != 0) {
+ sprintf(icp->err,"icmViewingConditions: read_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Read the XYZ values for the surround */
+ if ((rv = read_XYZNumber(&p->surround, bp+20)) != 0) {
+ sprintf(icp->err,"icmViewingConditions: read_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Read the encoded standard illuminant */
+ p->stdIlluminant = (icIlluminant)read_SInt32Number(bp + 32);
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmViewingConditions_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmViewingConditions *p = (icmViewingConditions *)pp;
+ icc *icp = p->icp;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmViewingConditions_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmViewingConditions_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmViewingConditions_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+
+ /* Write the XYZ values for the illuminant */
+ if ((rv = write_XYZNumber(&p->illuminant, bp+8)) != 0) {
+ sprintf(icp->err,"icmViewingConditions: write_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the XYZ values for the surround */
+ if ((rv = write_XYZNumber(&p->surround, bp+20)) != 0) {
+ sprintf(icp->err,"icmViewingConditions: write_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write the encoded standard illuminant */
+ if ((rv = write_SInt32Number((int)p->stdIlluminant, bp + 32)) != 0) {
+ sprintf(icp->err,"icmViewingConditionsa_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmViewingConditions_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmViewingConditions_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmViewingConditions *p = (icmViewingConditions *)pp;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Viewing Conditions:\n");
+ op->gprintf(op," XYZ value of illuminant in cd/m^2 = %s\n", string_XYZNumber(&p->illuminant));
+ op->gprintf(op," XYZ value of surround in cd/m^2 = %s\n", string_XYZNumber(&p->surround));
+ op->gprintf(op," Illuminant type = %s\n", string_Illuminant(p->stdIlluminant));
+}
+
+/* Allocate variable sized data elements */
+static int icmViewingConditions_allocate(
+ icmBase *pp
+) {
+ /* Nothing to do */
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmViewingConditions_delete(
+ icmBase *pp
+) {
+ icmViewingConditions *p = (icmViewingConditions *)pp;
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmViewingConditions(
+ icc *icp
+) {
+ icmViewingConditions *p;
+ if ((p = (icmViewingConditions *) icp->al->calloc(icp->al,1,sizeof(icmViewingConditions))) == NULL)
+ return NULL;
+ p->ttype = icSigViewingConditionsType;
+ p->refcount = 1;
+ p->get_size = icmViewingConditions_get_size;
+ p->read = icmViewingConditions_read;
+ p->write = icmViewingConditions_write;
+ p->dump = icmViewingConditions_dump;
+ p->allocate = icmViewingConditions_allocate;
+ p->del = icmViewingConditions_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ---------------------------------------------------------- */
+/* icmCrdInfo object */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmCrdInfo_get_size(
+ icmBase *pp
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ unsigned int len = 0, t;
+ len = sat_add(len, 8); /* 8 bytes for tag and padding */
+ len = sat_addadd(len, 4, p->ppsize); /* Postscript product name */
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ len = sat_addadd(len, 4, p->crdsize[t]); /* crd names */
+ }
+ return len;
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmCrdInfo_read(
+ icmBase *pp,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ icc *icp = p->icp;
+ unsigned int t;
+ int rv;
+ char *bp, *buf, *end;
+
+ if (len < 28) {
+ sprintf(icp->err,"icmCrdInfo_read: Tag too small to be legal");
+ return icp->errc = 1;
+ }
+
+ /* Allocate a file read buffer */
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmCrdInfo_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+ end = buf + len;
+
+ /* Read portion of file into buffer */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, bp, 1, len) != len) {
+ sprintf(icp->err,"icmCrdInfo_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Read type descriptor from the buffer */
+ if (((icTagTypeSignature)read_SInt32Number(bp)) != p->ttype) {
+ sprintf(icp->err,"icmCrdInfo_read: Wrong tag type for icmCrdInfo");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ bp = bp + 8;
+
+ /* Postscript product name */
+ if (bp > end || 4 > (end - bp)) {
+ sprintf(icp->err,"icmCrdInfo_read: Data too short to read Postscript product name");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->ppsize = read_UInt32Number(bp);
+ bp += 4;
+ if (p->ppsize > 0) {
+ if (p->ppsize > (end - bp)) {
+ sprintf(icp->err,"icmCrdInfo_read: Data to short to read Postscript product string");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,p->ppsize)) == 1) {
+ sprintf(icp->err,"icmCrdInfo_read: Postscript product name is not terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ memmove((void *)p->ppname, (void *)bp, p->ppsize);
+ bp += p->ppsize;
+ }
+
+ /* CRD names for the four rendering intents */
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ if (bp > end || 4 > (end - bp)) {
+ sprintf(icp->err,"icmCrdInfo_read: Data too short to read CRD%d name",t);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->crdsize[t] = read_UInt32Number(bp);
+ bp += 4;
+ if (p->crdsize[t] > 0) {
+ if (p->crdsize[t] > (end - bp)) {
+ sprintf(icp->err,"icmCrdInfo_read: Data to short to read CRD%d string",t);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ if ((rv = check_null_string(bp,p->crdsize[t])) == 1) {
+ sprintf(icp->err,"icmCrdInfo_read: CRD%d name is not terminated",t);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ if ((rv = p->allocate((icmBase *)p)) != 0) {
+ icp->al->free(icp->al, buf);
+ return rv;
+ }
+ memmove((void *)p->crdname[t], (void *)bp, p->crdsize[t]);
+ bp += p->crdsize[t];
+ }
+ }
+
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmCrdInfo_write(
+ icmBase *pp,
+ unsigned int of /* File offset to write from */
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ icc *icp = p->icp;
+ unsigned int t;
+ unsigned int len;
+ char *bp, *buf; /* Buffer to write from */
+ int rv;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size((icmBase *)p)) == UINT_MAX) {
+ sprintf(icp->err,"icmCrdInfo_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmCrdInfo_write malloc() failed");
+ return icp->errc = 2;
+ }
+ bp = buf;
+
+ /* Write type descriptor to the buffer */
+ if ((rv = write_SInt32Number((int)p->ttype,bp)) != 0) {
+ sprintf(icp->err,"icmCrdInfo_write: write_SInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ write_SInt32Number(0,bp+4); /* Set padding to 0 */
+ bp = bp + 8;
+
+ /* Postscript product name */
+ if ((rv = write_UInt32Number(p->ppsize,bp)) != 0) {
+ sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if (p->ppsize > 0) {
+ if ((rv = check_null_string(p->ppname,p->ppsize)) == 1) {
+ sprintf(icp->err,"icmCrdInfo_write: Postscript product name is not terminated");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ memmove((void *)bp, (void *)p->ppname, p->ppsize);
+ bp += p->ppsize;
+ }
+
+ /* CRD names for the four rendering intents */
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ if ((rv = write_UInt32Number(p->crdsize[t],bp)) != 0) {
+ sprintf(icp->err,"icmCrdInfo_write: write_UInt32Number() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ bp += 4;
+ if (p->ppsize > 0) {
+ if ((rv = check_null_string(p->crdname[t],p->crdsize[t])) == 1) {
+ sprintf(icp->err,"icmCrdInfo_write: CRD%d name is not terminated",t);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ /* Haven't checked if rv == 2 is legal or not */
+ memmove((void *)bp, (void *)p->crdname[t], p->crdsize[t]);
+ bp += p->crdsize[t];
+ }
+ }
+
+ /* Write to the file */
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmCrdInfo_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+ icp->al->free(icp->al, buf);
+ return 0;
+}
+
+/* Dump a text description of the object */
+static void icmCrdInfo_dump(
+ icmBase *pp,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ unsigned int i, r, c, size, t;
+
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"PostScript Product name and CRD names:\n");
+
+ op->gprintf(op," Product name:\n");
+ op->gprintf(op," No. chars = %lu\n",p->ppsize);
+
+ size = p->ppsize > 0 ? p->ppsize-1 : 0;
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 73) {
+ if (isprint(p->ppname[i])) {
+ op->gprintf(op,"%c",p->ppname[i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->ppname[i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ op->gprintf(op," CRD%ld name:\n",t);
+ op->gprintf(op," No. chars = %lu\n",p->crdsize[t]);
+
+ size = p->crdsize[t] > 0 ? p->crdsize[t]-1 : 0;
+ i = 0;
+ for (r = 1;; r++) { /* count rows */
+ if (i >= size) {
+ op->gprintf(op,"\n");
+ break;
+ }
+ if (r > 1 && verb < 2) {
+ op->gprintf(op,"...\n");
+ break; /* Print 1 row if not verbose */
+ }
+ c = 1;
+ op->gprintf(op," 0x%04lx: ",i);
+ c += 10;
+ while (i < size && c < 73) {
+ if (isprint(p->crdname[t][i])) {
+ op->gprintf(op,"%c",p->crdname[t][i]);
+ c++;
+ } else {
+ op->gprintf(op,"\\%03o",p->crdname[t][i]);
+ c += 4;
+ }
+ i++;
+ }
+ if (i < size)
+ op->gprintf(op,"\n");
+ }
+ }
+}
+
+/* Allocate variable sized data elements */
+static int icmCrdInfo_allocate(
+ icmBase *pp
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ icc *icp = p->icp;
+ unsigned int t;
+
+ if (p->ppsize != p->_ppsize) {
+ if (ovr_mul(p->ppsize, sizeof(char))) {
+ sprintf(icp->err,"icmCrdInfo_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->ppname != NULL)
+ icp->al->free(icp->al, p->ppname);
+ if ((p->ppname = (char *) icp->al->calloc(icp->al, p->ppsize, sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmCrdInfo_alloc: malloc() of string data failed");
+ return icp->errc = 2;
+ }
+ p->_ppsize = p->ppsize;
+ }
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ if (p->crdsize[t] != p->_crdsize[t]) {
+ if (ovr_mul(p->crdsize[t], sizeof(char))) {
+ sprintf(icp->err,"icmCrdInfo_alloc: size overflow");
+ return icp->errc = 1;
+ }
+ if (p->crdname[t] != NULL)
+ icp->al->free(icp->al, p->crdname[t]);
+ if ((p->crdname[t] = (char *) icp->al->calloc(icp->al, p->crdsize[t], sizeof(char))) == NULL) {
+ sprintf(icp->err,"icmCrdInfo_alloc: malloc() of CRD%d name string failed",t);
+ return icp->errc = 2;
+ }
+ p->_crdsize[t] = p->crdsize[t];
+ }
+ }
+ return 0;
+}
+
+/* Free all storage in the object */
+static void icmCrdInfo_delete(
+ icmBase *pp
+) {
+ icmCrdInfo *p = (icmCrdInfo *)pp;
+ icc *icp = p->icp;
+ unsigned int t;
+
+ if (p->ppname != NULL)
+ icp->al->free(icp->al, p->ppname);
+ for (t = 0; t < 4; t++) { /* For all 4 intents */
+ if (p->crdname[t] != NULL)
+ icp->al->free(icp->al, p->crdname[t]);
+ }
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmBase *new_icmCrdInfo(
+ icc *icp
+) {
+ icmCrdInfo *p;
+ if ((p = (icmCrdInfo *) icp->al->calloc(icp->al,1,sizeof(icmCrdInfo))) == NULL)
+ return NULL;
+ p->ttype = icSigCrdInfoType;
+ p->refcount = 1;
+ p->get_size = icmCrdInfo_get_size;
+ p->read = icmCrdInfo_read;
+ p->write = icmCrdInfo_write;
+ p->dump = icmCrdInfo_dump;
+ p->allocate = icmCrdInfo_allocate;
+ p->del = icmCrdInfo_delete;
+ p->icp = icp;
+
+ return (icmBase *)p;
+}
+
+/* ========================================================== */
+/* icmHeader object */
+/* ========================================================== */
+
+/* Return the number of bytes needed to write this tag */
+static unsigned int icmHeader_get_size(
+ icmHeader *p
+) {
+ return 128; /* By definition */
+}
+
+/* read the object, return 0 on success, error code on fail */
+static int icmHeader_read(
+ icmHeader *p,
+ unsigned int len, /* tag length */
+ unsigned int of /* start offset within file */
+) {
+ icc *icp = p->icp;
+ char *buf;
+ unsigned int tt;
+ int rv = 0;
+
+ if (len != 128) {
+ sprintf(icp->err,"icmHeader_read: Length expected to be 128");
+ return icp->errc = 1;
+ }
+
+ if ((buf = (char *) icp->al->malloc(icp->al, len)) == NULL) {
+ sprintf(icp->err,"icmHeader_read: malloc() failed");
+ return icp->errc = 2;
+ }
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->read(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmHeader_read: fseek() or fread() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Check that the magic number is right */
+ tt = read_SInt32Number(buf+36);
+ if (tt != icMagicNumber) { /* Check magic number */
+ sprintf(icp->err,"icmHeader_read: wrong magic number 0x%x",tt);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+
+ /* Fill in the in-memory structure */
+ p->size = read_UInt32Number(buf + 0); /* Profile size in bytes */
+ if (p->size < (128 + 4)) {
+ sprintf(icp->err,"icmHeader_read: file size %d too small to be legal",p->size);
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ p->cmmId = read_SInt32Number(buf + 4); /* CMM for profile */
+ tt = read_UInt8Number(buf + 8); /* Raw major version number */
+ p->majv = (tt >> 4) * 10 + (tt & 0xf); /* Integer major version number */
+ icp->ver = p->majv > 3 ? 1 : 0; /* Set major version flag in icc */
+ tt = read_UInt8Number(buf + 9); /* Raw minor/bug fix version numbers */
+ p->minv = (tt >> 4); /* Integer minor version number */
+ p->bfv = (tt & 0xf); /* Integer bug fix version number */
+ p->deviceClass = (icProfileClassSignature)
+ read_SInt32Number(buf + 12); /* Type of profile */
+ p->colorSpace = (icColorSpaceSignature)
+ read_SInt32Number(buf + 16); /* Color space of data */
+ p->pcs = (icColorSpaceSignature)
+ read_SInt32Number(buf + 20); /* PCS: XYZ or Lab */
+ if ((rv = read_DateTimeNumber(&p->date, buf + 24)) != 0) { /* Creation Date */
+ sprintf(icp->err,"icmHeader_read: read_DateTimeNumber corrupted");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ p->platform = (icPlatformSignature)
+ read_SInt32Number(buf + 40); /* Primary platform */
+ p->flags = read_UInt32Number(buf + 44); /* Various bits */
+ p->manufacturer = read_SInt32Number(buf + 48); /* Dev manufacturer */
+ p->model = read_SInt32Number(buf + 52); /* Dev model */
+ read_UInt64Number(&p->attributes, buf + 56); /* Device attributes */
+ p->renderingIntent = (icRenderingIntent)
+ read_SInt32Number(buf + 64); /* Rendering intent */
+ if ((rv = read_XYZNumber(&p->illuminant, buf + 68)) != 0) { /* Profile illuminant */
+ sprintf(icp->err,"icmHeader_read: read_XYZNumber error");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ p->creator = read_SInt32Number(buf + 80); /* Profile creator */
+
+ for (tt = 0; tt < 16; tt++)
+ p->id[tt] = icp->ver ? read_UInt8Number(buf + 84 + tt) : 0; /* Profile ID */
+
+ icp->al->free(icp->al, buf);
+
+#ifndef ENABLE_V4
+ if (icp->ver) {
+ sprintf(icp->err,"icmHeader_read: ICC V4 not supported!");
+ return icp->errc = 1;
+ }
+#endif
+ return 0;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+static int icmHeader_write(
+ icmHeader *p,
+ unsigned int of, /* File offset to write from */
+ int doid /* Flag, nz = writing to compute ID */
+) {
+ icc *icp = p->icp;
+ char *buf; /* Buffer to write from */
+ unsigned int len;
+ unsigned int tt;
+ int rv = 0;
+
+ /* Allocate a file write buffer */
+ if ((len = p->get_size(p)) == UINT_MAX) {
+ sprintf(icp->err,"icmHeader_write get_size overflow");
+ return icp->errc = 1;
+ }
+ if ((buf = (char *) icp->al->calloc(icp->al,1,len)) == NULL) { /* Zero it - some CMS are fussy */
+ sprintf(icp->err,"icmHeader_write calloc() failed");
+ return icp->errc = 2;
+ }
+
+ /* Fill in the write buffer */
+ if ((rv = write_UInt32Number(p->size, buf + 0)) != 0) { /* Profile size in bytes */
+ sprintf(icp->err,"icmHeader_write: profile size");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+
+ if ((rv = write_SInt32Number(p->cmmId, buf + 4)) != 0) { /* CMM for profile */
+ sprintf(icp->err,"icmHeader_write: cmmId");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if (p->majv < 0 || p->majv > 99 /* Sanity check version numbers */
+ || p->minv < 0 || p->minv > 9
+ || p->bfv < 0 || p->bfv > 9) {
+ sprintf(icp->err,"icmHeader_write: version number");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 1;
+ }
+ tt = ((p->majv/10) << 4) + (p->majv % 10);
+ if ((rv = write_UInt8Number(tt, buf + 8)) != 0) { /* Raw major version number */
+ sprintf(icp->err,"icmHeader_write: Uint8Number major version");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ tt = (p->minv << 4) + p->bfv;
+ if ((rv = write_UInt8Number(tt, buf + 9)) != 0) { /* Raw minor/bug fix version numbers */
+ sprintf(icp->err,"icmHeader_write: Uint8Number minor/bug fix");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number((int)p->deviceClass, buf + 12)) != 0) { /* Type of profile */
+ sprintf(icp->err,"icmHeader_write: SInt32Number deviceClass");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number((int)p->colorSpace, buf + 16)) != 0) { /* Color space of data */
+ sprintf(icp->err,"icmHeader_write: SInt32Number data color space");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number((int)p->pcs, buf + 20)) != 0) { /* PCS: XYZ or Lab */
+ sprintf(icp->err,"icmHeader_write: SInt32Number PCS");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_DateTimeNumber(&p->date, buf + 24)) != 0) { /* Creation Date */
+ sprintf(icp->err,"icmHeader_write: DateTimeNumber creation");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number(icMagicNumber, buf+36)) != 0) { /* Magic number */
+ sprintf(icp->err,"icmHeader_write: SInt32Number magic");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number((int)p->platform, buf + 40)) != 0) { /* Primary platform */
+ sprintf(icp->err,"icmHeader_write: SInt32Number platform");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt32Number(doid ? 0 : p->flags, buf + 44)) != 0) { /* Various flag bits */
+ sprintf(icp->err,"icmHeader_write: UInt32Number flags");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number(p->manufacturer, buf + 48)) != 0) { /* Dev manufacturer */
+ sprintf(icp->err,"icmHeader_write: SInt32Number manufaturer");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((write_SInt32Number(p->model, buf + 52)) != 0) { /* Dev model */
+ sprintf(icp->err,"icmHeader_write: SInt32Number model");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_UInt64Number(&p->attributes, buf + 56)) != 0) { /* Device attributes */
+ sprintf(icp->err,"icmHeader_write: UInt64Number attributes");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number(doid ? 0 : (int)p->renderingIntent, buf + 64)) != 0) { /* Rendering intent */
+ sprintf(icp->err,"icmHeader_write: SInt32Number rendering intent");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_XYZNumber(&p->illuminant, buf + 68)) != 0) { /* Profile illuminant */
+ sprintf(icp->err,"icmHeader_write: XYZNumber illuminant");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if ((rv = write_SInt32Number(p->creator, buf + 80)) != 0) { /* Profile creator */
+ sprintf(icp->err,"icmHeader_write: SInt32Number creator");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ if (doid == 0 && icp->ver) { /* ID is V4.0+ feature */
+ for (tt = 0; tt < 16; tt++) {
+ if ((rv = write_UInt8Number(p->id[tt], buf + 84 + tt)) != 0) { /* Profile ID */
+ sprintf(icp->err,"icmHeader_write: UInt8Number creator");
+ icp->al->free(icp->al, buf);
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ if ( icp->fp->seek(icp->fp, of) != 0
+ || icp->fp->write(icp->fp, buf, 1, len) != len) {
+ sprintf(icp->err,"icmHeader_write fseek() or fwrite() failed");
+ icp->al->free(icp->al, buf);
+ return icp->errc = 2;
+ }
+
+ icp->al->free(icp->al, buf);
+ return rv;
+}
+
+static void icmHeader_dump(
+ icmHeader *p,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ int i;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"Header:\n");
+ op->gprintf(op," size = %d bytes\n",p->size);
+ op->gprintf(op," CMM = %s\n",tag2str(p->cmmId));
+ op->gprintf(op," Version = %d.%d.%d\n",p->majv, p->minv, p->bfv);
+ op->gprintf(op," Device Class = %s\n", string_ProfileClassSignature(p->deviceClass));
+ op->gprintf(op," Color Space = %s\n", string_ColorSpaceSignature(p->colorSpace));
+ op->gprintf(op," Conn. Space = %s\n", string_ColorSpaceSignature(p->pcs));
+ op->gprintf(op," Date, Time = %s\n", string_DateTimeNumber(&p->date));
+ op->gprintf(op," Platform = %s\n", string_PlatformSignature(p->platform));
+ op->gprintf(op," Flags = %s\n", string_ProfileHeaderFlags(p->flags));
+ op->gprintf(op," Dev. Mnfctr. = %s\n", tag2str(p->manufacturer)); /* ~~~ */
+ op->gprintf(op," Dev. Model = %s\n", tag2str(p->model)); /* ~~~ */
+ op->gprintf(op," Dev. Attrbts = %s\n", string_DeviceAttributes(p->attributes.l));
+ op->gprintf(op," Rndrng Intnt = %s\n", string_RenderingIntent(p->renderingIntent));
+ op->gprintf(op," Illuminant = %s\n", string_XYZNumber_and_Lab(&p->illuminant));
+ op->gprintf(op," Creator = %s\n", tag2str(p->creator)); /* ~~~ */
+ if (p->icp->ver) { /* V4.0+ feature */
+ for (i = 0; i < 16; i++) { /* Check if ID has been set */
+ if (p->id[i] != 0)
+ break;
+ }
+ if (i < 16)
+ op->gprintf(op," ID = %02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X%02X%02X%02X%02X\n",
+ p->id[0], p->id[1], p->id[2], p->id[3], p->id[4], p->id[5], p->id[6], p->id[7],
+ p->id[8], p->id[9], p->id[10], p->id[11], p->id[12], p->id[13], p->id[14], p->id[15]);
+ else
+ op->gprintf(op," ID = <Not set>\n");
+ }
+ op->gprintf(op,"\n");
+}
+
+static void icmHeader_delete(
+ icmHeader *p
+) {
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* Create an empty object. Return null on error */
+static icmHeader *new_icmHeader(
+ icc *icp
+) {
+ icmHeader *p;
+ if ((p = (icmHeader *) icp->al->calloc(icp->al,1,sizeof(icmHeader))) == NULL)
+ return NULL;
+ p->icp = icp;
+ p->get_size = icmHeader_get_size;
+ p->read = icmHeader_read;
+ p->write = icmHeader_write;
+ p->dump = icmHeader_dump;
+ p->del = icmHeader_delete;
+
+ return p;
+}
+
+/* ---------------------------------------------------------- */
+/* Type vector table. Match the Tag type against the object creator */
+static struct {
+ icTagTypeSignature ttype; /* The tag type signature */
+ icmBase * (*new_obj)(icc *icp);
+} typetable[] = {
+ {icSigColorantTableType, new_icmColorantTable},
+ {icmSigAltColorantTableType, new_icmColorantTable},
+ {icSigCrdInfoType, new_icmCrdInfo},
+ {icSigCurveType, new_icmCurve},
+ {icSigDataType, new_icmData},
+ {icSigDateTimeType, new_icmDateTimeNumber},
+ {icSigLut16Type, new_icmLut},
+ {icSigLut8Type, new_icmLut},
+ {icSigMeasurementType, new_icmMeasurement},
+ {icSigNamedColorType, new_icmNamedColor},
+ {icSigNamedColor2Type, new_icmNamedColor},
+ {icSigProfileSequenceDescType, new_icmProfileSequenceDesc},
+ {icSigS15Fixed16ArrayType, new_icmS15Fixed16Array},
+ {icSigScreeningType, new_icmScreening},
+ {icSigSignatureType, new_icmSignature},
+ {icSigTextDescriptionType, new_icmTextDescription},
+ {icSigTextType, new_icmText},
+ {icSigU16Fixed16ArrayType, new_icmU16Fixed16Array},
+ {icSigUcrBgType, new_icmUcrBg},
+ {icSigVideoCardGammaType, new_icmVideoCardGamma},
+ {icSigUInt16ArrayType, new_icmUInt16Array},
+ {icSigUInt32ArrayType, new_icmUInt32Array},
+ {icSigUInt64ArrayType, new_icmUInt64Array},
+ {icSigUInt8ArrayType, new_icmUInt8Array},
+ {icSigViewingConditionsType, new_icmViewingConditions},
+ {icSigXYZArrayType, new_icmXYZArray},
+ {icMaxEnumType, NULL}
+};
+
+/* Table that lists the legal Types for each Tag Signature */
+static struct {
+ icTagSignature sig;
+ icTagTypeSignature ttypes[4]; /* Arbitrary max of 4 */
+} sigtypetable[] = {
+ {icSigAToB0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigAToB1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigAToB2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigBlueColorantTag, {icSigXYZType,icMaxEnumType}},
+ {icSigBlueTRCTag, {icSigCurveType,icMaxEnumType}},
+ {icSigBToA0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigBToA1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigBToA2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigCalibrationDateTimeTag, {icSigDateTimeType,icMaxEnumType}},
+ {icSigCharTargetTag, {icSigTextType,icMaxEnumType}},
+ {icSigColorantTableTag, {icSigColorantTableType,icmSigAltColorantTableType,
+ icMaxEnumType}},
+ {icSigColorantTableOutTag, {icSigColorantTableType,icmSigAltColorantTableType,
+ icMaxEnumType}},
+ {icSigCopyrightTag, {icSigTextType,icMaxEnumType}},
+ {icSigCrdInfoTag, {icSigCrdInfoType,icMaxEnumType}},
+ {icSigDeviceMfgDescTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigDeviceModelDescTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigGamutTag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigGrayTRCTag, {icSigCurveType,icMaxEnumType}},
+ {icSigGreenColorantTag, {icSigXYZType,icMaxEnumType}},
+ {icSigGreenTRCTag, {icSigCurveType,icMaxEnumType}},
+ {icSigLuminanceTag, {icSigXYZType,icMaxEnumType}},
+ {icSigMeasurementTag, {icSigMeasurementType,icMaxEnumType}},
+ {icSigMediaBlackPointTag, {icSigXYZType,icMaxEnumType}},
+ {icSigMediaWhitePointTag, {icSigXYZType,icMaxEnumType}},
+ {icSigNamedColorTag, {icSigNamedColorType,icMaxEnumType}},
+ {icSigNamedColor2Tag, {icSigNamedColor2Type,icMaxEnumType}},
+ {icSigPreview0Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigPreview1Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigPreview2Tag, {icSigLut8Type,icSigLut16Type,icMaxEnumType}},
+ {icSigProfileDescriptionTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigProfileSequenceDescTag, {icSigProfileSequenceDescType,icMaxEnumType}},
+ {icSigPs2CRD0Tag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2CRD1Tag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2CRD2Tag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2CRD3Tag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2CSATag, {icSigDataType,icMaxEnumType}},
+ {icSigPs2RenderingIntentTag, {icSigDataType,icMaxEnumType}},
+ {icSigRedColorantTag, {icSigXYZType,icMaxEnumType}},
+ {icSigRedTRCTag, {icSigCurveType,icMaxEnumType}},
+ {icSigScreeningDescTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigScreeningTag, {icSigScreeningType,icMaxEnumType}},
+ {icSigTechnologyTag, {icSigSignatureType,icMaxEnumType}},
+ {icSigUcrBgTag, {icSigUcrBgType,icMaxEnumType}},
+ {icSigVideoCardGammaTag, {icSigVideoCardGammaType,icMaxEnumType}},
+ {icSigViewingCondDescTag, {icSigTextDescriptionType,icMaxEnumType}},
+ {icSigViewingConditionsTag, {icSigViewingConditionsType,icMaxEnumType}},
+ {icMaxEnumTag, {icMaxEnumType}}
+};
+
+/* Fake color tag for specifying PCS */
+#define icSigPCSData ((icColorSpaceSignature) 0x50435320L)
+
+/* Table that lists the required tags for various profiles */
+static struct {
+ icProfileClassSignature sig; /* Profile signature */
+ int chans; /* Data Color channels, -ve for match but try next, */
+ /* -100 for ignore, -200 for ignore and try next */
+ icColorSpaceSignature colsig; /* Data Color space signature, icMaxEnumData for ignore, */
+ /* icSigPCSData for XYZ of Lab */
+ icColorSpaceSignature pcssig; /* PCS Color space signature, icMaxEnumData for ignore, */
+ /* icSigPCSData for XYZ or Lab */
+ icTagSignature tags[12]; /* Arbitrary max of 12 */
+} tagchecktable[] = {
+ {icSigInputClass, -1, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigGrayTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigInputClass, -3, icMaxEnumData, icSigXYZData,
+ {icSigProfileDescriptionTag,
+ icSigRedColorantTag,
+ icSigGreenColorantTag,
+ icSigBlueColorantTag,
+ icSigRedTRCTag,
+ icSigGreenTRCTag,
+ icSigBlueTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigInputClass, -100, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigDisplayClass, -1, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigGrayTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigDisplayClass, -3, icSigRgbData, icSigXYZData, /* Rgb or any 3 component space ?? */
+ {icSigProfileDescriptionTag,
+ icSigRedColorantTag,
+ icSigGreenColorantTag,
+ icSigBlueColorantTag,
+ icSigRedTRCTag,
+ icSigGreenTRCTag,
+ icSigBlueTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ /* Non-3 component Display device */
+ {icSigDisplayClass, -100, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag, /* BToA doesn't seem to be required, which is strange... */
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -1, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigGrayTRCTag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -1, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigBToA0Tag,
+ icSigGamutTag,
+ icSigAToB1Tag,
+ icSigBToA1Tag,
+ icSigAToB2Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -2, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigBToA0Tag,
+ icSigGamutTag,
+ icSigAToB1Tag,
+ icSigBToA1Tag,
+ icSigAToB2Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -3, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigBToA0Tag,
+ icSigGamutTag,
+ icSigAToB1Tag,
+ icSigBToA1Tag,
+ icSigAToB2Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -4, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigBToA0Tag,
+ icSigGamutTag,
+ icSigAToB1Tag,
+ icSigBToA1Tag,
+ icSigAToB2Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigOutputClass, -100, icMaxEnumData, icSigPCSData, /* Assumed from Hexachrome examples */
+ {icSigProfileDescriptionTag,
+ icSigBToA0Tag,
+ icSigBToA1Tag,
+ icSigBToA2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigLinkClass, -100, icMaxEnumData, icMaxEnumData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigProfileSequenceDescTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigColorSpaceClass, -100, icMaxEnumData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigBToA0Tag,
+ icSigAToB0Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigAbstractClass, -100, icSigPCSData, icSigPCSData,
+ {icSigProfileDescriptionTag,
+ icSigAToB0Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigNamedColorClass, -200, icMaxEnumData, icMaxEnumData,
+ {icSigProfileDescriptionTag,
+ icSigNamedColor2Tag,
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icSigNamedColorClass, -100, icMaxEnumData, icMaxEnumData,
+ {icSigProfileDescriptionTag,
+ icSigNamedColorTag, /* Not strictly V3.4 */
+ icSigMediaWhitePointTag,
+ icSigCopyrightTag, icMaxEnumTag}},
+
+ {icMaxEnumClass,-1,icMaxEnumData, icMaxEnumData, {icMaxEnumTag}}
+};
+
+/* ------------------------------------------------------------- */
+
+/* Return the current read fp (if any) */
+static icmFile *icc_get_rfp(icc *p) {
+ return p->fp;
+}
+
+/* Change the version to be non-default (ie. not 2.2.0), */
+/* e.g. ICC V4 (used for creation) */
+/* Return 0 if OK */
+/* Return 1 on error */
+static int icc_set_version(icc *p, icmICCVersion ver) {
+
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_set_version: Header is missing");
+ return p->errc = 1;
+ }
+
+ switch (ver) {
+ case icmVersionDefault:
+ p->header->majv = 2;
+ p->header->minv = 2;
+ p->header->bfv = 0;
+ break;
+ case icmVersion2_3:
+ p->header->majv = 2;
+ p->header->minv = 3;
+ p->header->bfv = 0;
+ break;
+ case icmVersion2_4:
+ p->header->majv = 2;
+ p->header->minv = 4;
+ p->header->bfv = 0;
+ break;
+#ifdef ENABLE_V4
+ case icmVersion4_1:
+ p->header->majv = 4;
+ p->header->minv = 1;
+ p->header->bfv = 0;
+ break;
+#endif
+ default:
+ sprintf(p->err,"icc_set_version: Unsupported version 0x%x",ver);
+ return p->errc = 1;
+ }
+ return 0;
+}
+
+
+/* Check that the ICC profile looks like it will be legal. */
+/* Return non-zero and set error string if not */
+static int check_icc_legal(
+ icc *p
+) {
+ int i, j;
+ icProfileClassSignature sig;
+ icColorSpaceSignature colsig;
+ icColorSpaceSignature pcssig;
+ int dchans;
+
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_check_legal: Header is missing");
+ return p->errc = 1;
+ }
+
+ sig = p->header->deviceClass;
+ colsig = p->header->colorSpace;
+ dchans = number_ColorSpaceSignature(colsig);
+ pcssig = p->header->pcs;
+
+ /* Find a matching table entry */
+ for (i = 0; tagchecktable[i].sig != icMaxEnumType; i++) {
+ if ( tagchecktable[i].sig == sig
+ && ( tagchecktable[i].chans == dchans /* Exactly matches */
+ || tagchecktable[i].chans == -dchans /* Exactly matches, but can try next table */
+ || tagchecktable[i].chans < -99) /* Doesn't have to match or try next table */
+ && ( tagchecktable[i].colsig == colsig
+ || (tagchecktable[i].colsig == icSigPCSData
+ && (colsig == icSigXYZData || colsig == icSigLabData))
+ || tagchecktable[i].colsig == icMaxEnumData)
+ && ( tagchecktable[i].pcssig == pcssig
+ || (tagchecktable[i].pcssig == icSigPCSData
+ && (pcssig == icSigXYZData || pcssig == icSigLabData))
+ || tagchecktable[i].pcssig == icMaxEnumData)) {
+
+ /* Found entry, so now check that all the required tags are present. */
+ for (j = 0; tagchecktable[i].tags[j] != icMaxEnumType; j++) {
+ if (p->find_tag(p, tagchecktable[i].tags[j]) != 0) { /* Not present! */
+ if (tagchecktable[i].chans == -200
+ || tagchecktable[i].chans == -dchans) { /* But can try next table */
+ break;
+ }
+ sprintf(p->err,"icc_check_legal: deviceClass %s is missing required tag %s",
+ tag2str(sig), tag2str(tagchecktable[i].tags[j]));
+ return p->errc = 1;
+ }
+ }
+ if (tagchecktable[i].tags[j] == icMaxEnumType) {
+ break; /* Fount all required tags */
+ }
+ }
+ }
+
+ /* According to the spec. if the deviceClass is:
+ an Abstract Class: both in and out color spaces should be PCS
+ an Link Class: both in and out color spaces can be any, and should
+ be the input space of the first profile in the link, and the
+ input space of the last profile in the link respectively.
+ a Named Class: in and out color spaces are not defined in the spec.
+ Input, Display, Output and ColorSpace Classes, input color
+ space can be any, and the output space must be PCS.
+ ~~ should check this here ???
+ */
+
+ return 0; /* Assume anything is ok */
+}
+
+
+/* read the object, return 0 on success, error code on fail */
+/* NOTE: this doesn't read the tag types, they should be read on demand. */
+/* NOTE: fp ownership is taken even if the function fails. */
+static int icc_read_x(
+ icc *p,
+ icmFile *fp, /* File to read from */
+ unsigned int of, /* File offset to read from */
+ int take_fp /* NZ if icc is to take ownership of fp */
+) {
+ char tcbuf[4]; /* Tag count read buffer */
+ unsigned int i, len;
+ unsigned int minoff, maxoff; /* Minimum and maximum offsets of tag data */
+ int er = 0; /* Error code */
+
+ p->fp = fp;
+ if (take_fp)
+ p->del_fp = 1;
+ p->of = of;
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_read: No header defined");
+ return p->errc = 1;
+ }
+
+ /* Read the header */
+ if (p->header->read(p->header, 128, of)) {
+ return 1;
+ }
+
+ /* Read the tag count */
+ if ( p->fp->seek(p->fp, of + 128) != 0
+ || p->fp->read(p->fp, tcbuf, 1, 4) != 4) {
+ sprintf(p->err,"icc_read: fseek() or fread() failed on tag count");
+ return p->errc = 1;
+ }
+ p->count = read_UInt32Number(tcbuf);
+
+ /* Sanity check it */
+ if (p->count > 357913940 /* (2^32-5)/12 */
+ || (p->count > ((p->header->size - 128 - 4) / 12))) {
+ sprintf(p->err,"icc_read: tag count %d is too large to be legal",p->count);
+ return p->errc = 1;
+ }
+ minoff = 128 + 4 + p->count * 12;
+ maxoff = p->header->size;
+
+ if (p->count > 0) {
+ char *bp, *buf;
+
+ if (ovr_mul(p->count, sizeof(icmTag))) {
+ sprintf(p->err,"icc_read: size overflow");
+ return p->errc = 1;
+ }
+
+ /* Read the table into memory */
+ if ((p->data = (icmTag *) p->al->calloc(p->al, p->count, sizeof(icmTag))) == NULL) {
+ sprintf(p->err,"icc_read: Tag table malloc() failed");
+ return p->errc = 2;
+ }
+
+ len = sat_mul(p->count, 12);
+ if ((buf = (char *) p->al->malloc(p->al, len)) == NULL) {
+ sprintf(p->err,"icc_read: Tag table read buffer malloc() failed");
+ p->al->free(p->al, p->data);
+ p->data = NULL;
+ return p->errc = 2;
+ }
+ if ( p->fp->seek(p->fp, of + 128 + 4) != 0
+ || p->fp->read(p->fp, buf, 1, len) != len) {
+ sprintf(p->err,"icc_read: fseek() or fread() failed on tag table");
+ p->al->free(p->al, p->data);
+ p->data = NULL;
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+
+ /* Fill in the tag table structure for each tag */
+ for (bp = buf, i = 0; i < p->count; i++, bp += 12) {
+ p->data[i].sig = (icTagSignature)read_SInt32Number(bp + 0);
+ p->data[i].offset = read_UInt32Number(bp + 4);
+ p->data[i].size = read_UInt32Number(bp + 8);
+ }
+ p->al->free(p->al, buf);
+
+ /* Check that each tag lies within the nominated space available, */
+ /* and has a reasonable size. */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].offset < minoff
+ || p->data[i].offset > maxoff
+ || p->data[i].size < 4
+ || p->data[i].size > (maxoff - minoff)
+ || (p->data[i].offset + p->data[i].size) < p->data[i].offset /* Overflow */
+ || (p->data[i].offset + p->data[i].size) > p->header->size) {
+ sprintf(p->err,"icc_read: tag %d is out of range of the nominated file size",i);
+ p->al->free(p->al, p->data);
+ p->data = NULL;
+ return p->errc = 1;
+ }
+ }
+
+ /* Read each tag type */
+ for (i = 0; i < p->count; i++) {
+ if ( p->fp->seek(p->fp, of + p->data[i].offset) != 0
+ || p->fp->read(p->fp, tcbuf, 1, 4) != 4) {
+ sprintf(p->err,"icc_read: fseek() or fread() failed on tag headers");
+ p->al->free(p->al, p->data);
+ p->data = NULL;
+ return p->errc = 1;
+ }
+ p->data[i].ttype = (icTagTypeSignature) read_SInt32Number(tcbuf); /* Tag type */
+ p->data[i].objp = NULL; /* Read on demand */
+ }
+ } /* p->count > 0 */
+
+ return er;
+}
+
+/* read the object, return 0 on success, error code on fail */
+/* NOTE: this doesn't read the tag types, they should be read on demand. */
+/* (backward compatible version) */
+static int icc_read(
+ icc *p,
+ icmFile *fp, /* File to read from */
+ unsigned int of /* File offset to read from */
+) {
+ return icc_read_x(p, fp, of, 0);
+}
+
+/* Check the profiles ID. We assume the file has already been read. */
+/* Return 0 if OK, 1 if no ID to check, 2 if doesn't match, 3 if some other error. */
+/* NOTE: this reads the whole file again, to compute the checksum. */
+static int icc_check_id(
+ icc *p,
+ ORD8 *rid /* Optionaly return computed ID */
+) {
+ unsigned char buf[128];
+ ORD8 id[16];
+ icmMD5 *md5 = NULL;
+ unsigned int len;
+
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_check_id: No header defined");
+ return p->errc = 3;
+ }
+ len = p->header->size; /* Claimed size of profile */
+
+ /* See if there is an ID to compare against */
+ for (len = 0; len < 16; len++) {
+ if (p->header->id[len] != 0)
+ break;
+ }
+ if (len >= 16) {
+ return 1;
+ }
+
+ if ((md5 = new_icmMD5(p->al)) == NULL) {
+ sprintf(p->err,"icc_check_id: new_icmMD5 failed");
+ return p->errc = 3;
+ }
+
+ /* Check the header */
+ if ( p->fp->seek(p->fp, p->of) != 0
+ || p->fp->read(p->fp, buf, 1, 128) != 128) {
+ sprintf(p->err,"icc_check_id: fseek() or fread() failed");
+ return p->errc = 3;
+ }
+
+ /* Zero the appropriate bytes in the header */
+ buf[44] = buf[45] = buf[46] = buf[47] = 0;
+ buf[64] = buf[65] = buf[66] = buf[67] = 0;
+ buf[84] = buf[85] = buf[86] = buf[87] =
+ buf[88] = buf[89] = buf[90] = buf[91] =
+ buf[92] = buf[93] = buf[94] = buf[95] =
+ buf[96] = buf[97] = buf[98] = buf[99] = 0;
+
+ md5->add(md5, buf, 128);
+
+ /* Suck in the rest of the profile */
+ for (;len > 0;) {
+ unsigned int rsize = 128;
+ if (rsize > len)
+ rsize = len;
+ if (p->fp->read(p->fp, buf, 1, rsize) != rsize) {
+ sprintf(p->err,"icc_check_id: fread() failed");
+ return p->errc = 3;
+ }
+ md5->add(md5, buf, rsize);
+ len -= rsize;
+ }
+
+ md5->get(md5, id);
+ md5->del(md5);
+
+ if (rid != NULL) {
+ for (len = 0; len < 16; len++)
+ rid[len] = id[len];
+ }
+
+ /* Check the ID */
+ for (len = 0; len < 16; len++) {
+ if (p->header->id[len] != id[len])
+ break;
+ }
+ if (len >= 16) {
+ return 0; /* Matched */
+ }
+ return 2; /* Didn't match */
+}
+
+/* Return the total size needed for the profile */
+/* Return 0 on error. */
+static unsigned int icc_get_size(
+ icc *p
+) {
+ unsigned int i, size = 0;
+
+#ifdef ICM_STRICT
+ /* Check that the right tags etc. are present for a legal ICC profile */
+ if (check_icc_legal(p) != 0) {
+ return 0;
+ }
+#endif /* ICM_STRICT */
+
+ /* Compute the total size and tag element data offsets */
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_get_size: No header defined");
+ p->errc = 1;
+ return 0;
+ }
+
+ size = sat_add(size, p->header->get_size(p->header));
+ /* Assume header is aligned */
+ size = sat_addaddmul(size, 4, p->count, 12); /* Tag table length */
+ size = sat_align(ALIGN_SIZE, size);
+
+ if (size == UINT_MAX) {
+ sprintf(p->err,"icc_get_size: size overflow");
+ return p->errc = 1;
+ }
+
+ /* Reset touched flag for each tag type */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp == NULL) {
+ sprintf(p->err,"icc_get_size: Internal error - NULL tag element");
+ p->errc = 1;
+ return 0;
+ }
+ p->data[i].objp->touched = 0;
+ }
+ /* Get size for each tag type, skipping links */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp->touched == 0) { /* Not alllowed for previously */
+ size = sat_add(size, p->data[i].objp->get_size(p->data[i].objp));
+ size = sat_align(ALIGN_SIZE, size);
+ p->data[i].objp->touched = 1; /* Don't account for this again */
+ }
+ }
+
+ return size; /* Total size needed, or UINT_MAX if overflow */
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+/* NOTE: fp ownership is taken even if the function fails. */
+static int icc_write_x(
+ icc *p,
+ icmFile *fp, /* File to write to */
+ unsigned int of, /* File offset to write to */
+ int take_fp /* NZ if icc is to take ownership of fp */
+) {
+ char *bp, *buf; /* tag table buffer */
+ unsigned int len;
+ int rv = 0;
+ unsigned int i, size = 0;
+ unsigned char pbuf[ALIGN_SIZE];
+
+ p->fp = fp; /* Open file pointer */
+ if (take_fp)
+ p->del_fp = 1;
+ p->of = of; /* Offset of ICC profile */
+
+ for (i = 0; i < ALIGN_SIZE; i++)
+ pbuf[i] = 0;
+
+ /* Check that the right tags etc. are present for a legal ICC profile */
+ if ((rv = check_icc_legal(p)) != 0) {
+ return rv;
+ }
+
+ /* Compute the total size and tag element data offsets */
+ if (p->header == NULL) {
+ sprintf(p->err,"icc_write: No header defined");
+ return p->errc = 1;
+ }
+
+ size = sat_add(size, p->header->get_size(p->header));
+ /* Assume header is aligned */
+ len = sat_addmul(4, p->count, 12); /* Tag table length */
+ len = sat_sub(sat_align(ALIGN_SIZE, sat_add(size, len)), size); /* Aligned size */
+ size = sat_align(ALIGN_SIZE, sat_add(size, len));
+
+ if (len == UINT_MAX) {
+ sprintf(p->err,"icc_write get_size overflow");
+ return p->errc = 1;
+ }
+
+ /* Allocate memory buffer for tag table */
+ if ((buf = (char *) p->al->calloc(p->al, 1, len)) == NULL) {
+ sprintf(p->err,"icc_write calloc() failed");
+ return p->errc = 2;
+ }
+ bp = buf;
+
+ if ((rv = write_UInt32Number(p->count, bp)) != 0) { /* Tag count */
+ sprintf(p->err,"icc_write: write_UInt32Number() failed on tag count");
+ p->al->free(p->al, buf);
+ return p->errc = rv;
+ }
+ bp += 4;
+ /* Reset touched flag for each tag type */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp == NULL) {
+ sprintf(p->err,"icc_write: Internal error - NULL tag element");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+ p->data[i].objp->touched = 0;
+ }
+ /* Set the offset and size for each tag type, create the tag table write data */
+ /* and compute the total profile size. */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp->touched == 0) { /* Allocate space for tag type */
+ p->data[i].offset = size; /* Profile relative target */
+ p->data[i].size = p->data[i].objp->get_size(p->data[i].objp);
+ size = sat_add(size, p->data[i].size);
+ p->data[i].pad = sat_sub(sat_align(ALIGN_SIZE, size), size);
+ size = sat_align(ALIGN_SIZE, size);
+ p->data[i].objp->touched = 1; /* Allocated space for it */
+ if (size == UINT_MAX) {
+ sprintf(p->err,"icc_write: size overflow");
+ return p->errc = 1;
+ }
+ } else { /* must be linked - copy allocation */
+ unsigned int k;
+ for (k = 0; k < p->count; k++) { /* Find linked tag */
+ if (p->data[k].objp == p->data[i].objp)
+ break;
+ }
+ if (k == p->count) {
+ sprintf(p->err,"icc_write: corrupted link");
+ return p->errc = 2;
+ }
+ p->data[i].offset = p->data[k].offset;
+ p->data[i].size = p->data[k].size;
+ p->data[i].pad = p->data[k].pad;
+ }
+ /* Write tag table entry for this tag */
+ if ((rv = write_SInt32Number((int)p->data[i].sig,bp + 0)) != 0) {
+ sprintf(p->err,"icc_write: write_SInt32Number() failed on tag signature");
+ p->al->free(p->al, buf);
+ return p->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->data[i].offset, bp + 4)) != 0) {
+ sprintf(p->err,"icc_write: write_UInt32Number() failed on tag offset");
+ p->al->free(p->al, buf);
+ return p->errc = rv;
+ }
+ if ((rv = write_UInt32Number(p->data[i].size, bp + 8)) != 0) {
+ sprintf(p->err,"icc_write: write_UInt32Number() failed on tag size");
+ p->al->free(p->al, buf);
+ return p->errc = rv;
+ }
+ bp += 12;
+ }
+ p->header->size = size; /* Record total icc padded size */
+
+
+ /* If V4.0+, Compute the MD5 id for the profile. */
+ /* We do this by writing to a fake icmFile */
+ if (p->ver) {
+ icmMD5 *md5 = NULL;
+ icmFile *ofp, *dfp = NULL;
+
+ if ((md5 = new_icmMD5(p->al)) == NULL) {
+ sprintf(p->err,"icc_write: new_icmMD5 failed");
+ p->al->free(p->al, buf);
+ return p->errc = 2;
+ }
+
+ if ((dfp = new_icmFileMD5_a(md5, p->al)) == NULL) {
+ sprintf(p->err,"icc_write: new_icmFileMD5 failed");
+ md5->del(md5);
+ p->al->free(p->al, buf);
+ return p->errc = 2;
+ }
+
+ ofp = p->fp;
+ p->fp = dfp;
+
+ /* Dumy write the header */
+ if ((rv = p->header->write(p->header, 0, 1)) != 0) {
+ p->al->free(p->al, buf);
+ return rv;
+ }
+
+ /* Dumy write the tag table */
+ if ( p->fp->seek(p->fp, 128) != 0
+ || p->fp->write(p->fp, buf, 1, len) != len) {
+ sprintf(p->err,"icc_write: seek() or write() failed");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+
+ /* Dumy write all the tag element data */
+ /* (We invert meaning of touched here) */
+ for (i = 0; i < p->count; i++) { /* For all the tag element data */
+ if (p->data[i].objp->touched == 0)
+ continue; /* Must be linked, and we've already written it */
+ if ((rv = p->data[i].objp->write(p->data[i].objp, p->data[i].offset)) != 0) {
+ p->al->free(p->al, buf);
+ return rv;
+ }
+ /* Pad with 0 to next boundary */
+ if (p->data[i].pad > 0) {
+ if (p->fp->write(p->fp, pbuf, 1, p->data[i].pad) != p->data[i].pad) {
+ sprintf(p->err,"icc_write: write() failed");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+ }
+ p->data[i].objp->touched = 0; /* Written it, so don't write it again. */
+ }
+
+ if (p->fp->flush(p->fp) != 0) {
+ sprintf(p->err,"icc_write flush() failed");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+
+ if ((p->errc = ((icmFileMD5 *)dfp)->get_errc(dfp)) != 0) {
+ sprintf(p->err,"icc_write compute ID failed with code %d", p->errc);
+ p->al->free(p->al, buf);
+ return p->errc;
+ }
+
+ /* Get the MD5 checksum ID */
+ md5->get(md5, p->header->id);
+
+ dfp->del(dfp);
+ md5->del(md5);
+ p->fp = ofp;
+
+ /* Reset the touched flags */
+ for (i = 0; i < p->count; i++)
+ p->data[i].objp->touched = 1;
+ }
+
+ /* Now write out the profile for real. */
+ /* Although it may appear like we're seeking for each element, */
+ /* in fact elements will be written in file order. */
+
+ /* Write the header */
+ if ((rv = p->header->write(p->header, of, 0)) != 0) {
+ p->al->free(p->al, buf);
+ return rv;
+ }
+
+ /* Write the tag table */
+ if ( p->fp->seek(p->fp, of + 128) != 0
+ || p->fp->write(p->fp, buf, 1, len) != len) {
+ sprintf(p->err,"icc_write: seek() or write() failed");
+ p->al->free(p->al, buf);
+ return p->errc = 1;
+ }
+ p->al->free(p->al, buf);
+
+ /* Write all the tag element data */
+ /* (We invert the meaning of touched here) */
+ for (i = 0; i < p->count; i++) { /* For all the tag element data */
+ if (p->data[i].objp->touched == 0)
+ continue; /* Must be linked, and we've already written it */
+ if ((rv = p->data[i].objp->write(p->data[i].objp, of + p->data[i].offset)) != 0) {
+ return rv;
+ }
+ /* Pad with 0 to next boundary */
+ if (p->data[i].pad > 0) {
+ if (p->fp->write(p->fp, pbuf, 1, p->data[i].pad) != p->data[i].pad) {
+ sprintf(p->err,"icc_write: write() failed");
+ return p->errc = 1;
+ }
+ }
+ p->data[i].objp->touched = 0; /* Written it, so don't write it again. */
+ }
+
+ if (p->fp->flush(p->fp) != 0) {
+ sprintf(p->err,"icc_write flush() failed");
+ return p->errc = 1;
+ }
+
+ return rv;
+}
+
+/* Write the contents of the object. Return 0 on sucess, error code on failure */
+/* (backwards compatible version) */
+static int icc_write(
+ icc *p,
+ icmFile *fp, /* File to write to */
+ unsigned int of /* File offset to write to */
+) {
+ return icc_write_x(p, fp, of, 0);
+}
+
+/* Create and add a tag with the given signature. */
+/* Returns a pointer to the element object */
+/* Returns NULL if error - icc->errc will contain */
+/* 2 on system error, */
+/* 3 if unknown tag */
+/* NOTE: that we prevent tag duplication */
+/* NOTE: to create a tag type icmSigUnknownType, set ttype to icmSigUnknownType, */
+/* and set the actual tag type in icmSigUnknownType->uttype */
+static icmBase *icc_add_tag(
+ icc *p,
+ icTagSignature sig, /* Tag signature - may be unknown */
+ icTagTypeSignature ttype /* Tag type */
+) {
+ icmBase *tp;
+ icmBase *nob;
+ int i = 0, ok = 1;
+ unsigned int j;
+
+ if (ttype != icmSigUnknownType) { /* Check only for possibly known types */
+
+ /* Check that a known signature has an acceptable type */
+ for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
+ if (sigtypetable[i].sig == sig) { /* recognized signature */
+ ok = 0;
+ for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
+ if (sigtypetable[i].ttypes[j] == ttype) /* recognized type */
+ ok = 1;
+ }
+ break;
+ }
+ }
+ if (!ok) {
+ sprintf(p->err,"icc_add_tag: wrong tag type for signature");
+ p->errc = 1;
+ return NULL;
+ }
+
+ /* Check that we know how to handle this type */
+ for (i = 0; typetable[i].ttype != icMaxEnumType; i++) {
+ if (typetable[i].ttype == ttype)
+ break;
+ }
+ if (typetable[i].ttype == icMaxEnumType) {
+ sprintf(p->err,"icc_add_tag: unsupported tag type");
+ p->errc = 1;
+ return NULL;
+ }
+ }
+
+ /* Check that this tag doesn't already exist */
+ /* (Perhaps we should simply replace it, rather than erroring ?) */
+ for (j = 0; j < p->count; j++) {
+ if (p->data[j].sig == sig) {
+ sprintf(p->err,"icc_add_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig));
+ p->errc = 1;
+ return NULL;
+ }
+ }
+
+ /* Make space in tag table for new tag item */
+ if (ovr_mul(sat_add(p->count,1), sizeof(icmTag))) {
+ sprintf(p->err,"icc_add_tag: size overflow");
+ p->errc = 1;
+ return NULL;
+ }
+ if (p->data == NULL)
+ tp = (icmBase *)p->al->malloc(p->al, (p->count+1) * sizeof(icmTag));
+ else
+ tp = (icmBase *)p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag));
+ if (tp == NULL) {
+ sprintf(p->err,"icc_add_tag: Tag table realloc() failed");
+ p->errc = 2;
+ return NULL;
+ }
+ p->data = (icmTag *)tp;
+
+ if (ttype == icmSigUnknownType) {
+ if ((nob = new_icmUnknown(p)) == NULL)
+ return NULL;
+ } else {
+ /* Allocate the empty object */
+ if ((nob = typetable[i].new_obj(p)) == NULL)
+ return NULL;
+ }
+
+ /* Fill out our tag table entry */
+ p->data[p->count].sig = sig; /* The tag signature */
+ p->data[p->count].ttype = nob->ttype = ttype; /* The tag type signature */
+ p->data[p->count].offset = 0; /* Unknown offset yet */
+ p->data[p->count].size = 0; /* Unknown size yet */
+ p->data[p->count].objp = nob; /* Empty object */
+ p->count++;
+
+ return nob;
+}
+
+/* Create and add a tag which is a link to an existing tag. */
+/* Returns a pointer to the element object */
+/* Returns NULL if error - icc->errc will contain */
+/* 3 if incompatible tag */
+/* NOTE: that we prevent tag duplication */
+static icmBase *icc_link_tag(
+ icc *p,
+ icTagSignature sig, /* Tag signature - may be unknown */
+ icTagSignature ex_sig /* Tag signature of tag to link to */
+) {
+ icmBase *tp;
+ unsigned int j, exi;
+ int i, ok = 1;
+
+ /* Search for existing signature */
+ for (exi = 0; exi < p->count; exi++) {
+ if (p->data[exi].sig == ex_sig) /* Found it */
+ break;
+ }
+ if (exi == p->count) {
+ sprintf(p->err,"icc_link_tag: Can't find existing tag '%s'",tag2str(ex_sig));
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (p->data[exi].objp == NULL) {
+ sprintf(p->err,"icc_link_tag: Existing tag '%s' isn't loaded",tag2str(ex_sig));
+ p->errc = 1;
+ return NULL;
+ }
+
+ /* Check that a known signature has an acceptable type */
+ for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
+ if (sigtypetable[i].sig == sig) { /* recognized signature */
+ ok = 0;
+ for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
+ if (sigtypetable[i].ttypes[j] == p->data[exi].ttype) /* recognized type */
+ ok = 1;
+ }
+ break;
+ }
+ }
+ if (!ok) {
+ sprintf(p->err,"icc_link_tag: wrong tag type for signature");
+ p->errc = 1;
+ return NULL;
+ }
+
+ /* Check that this tag doesn't already exits */
+ for (j = 0; j < p->count; j++) {
+ if (p->data[j].sig == sig) {
+ sprintf(p->err,"icc_link_tag: Already have tag '%s' in profile",tag2str(p->data[j].sig));
+ p->errc = 1;
+ return NULL;
+ }
+ }
+
+ /* Make space in tag table for new tag item */
+ if (p->data == NULL)
+ tp = (icmBase *)p->al->malloc(p->al, (p->count+1) * sizeof(icmTag));
+ else
+ tp = (icmBase *)p->al->realloc(p->al, (void *)p->data, (p->count+1) * sizeof(icmTag));
+ if (tp == NULL) {
+ sprintf(p->err,"icc_link_tag: Tag table realloc() failed");
+ p->errc = 2;
+ return NULL;
+ }
+ p->data = (icmTag *)tp;
+
+ /* Fill out our tag table entry */
+ p->data[p->count].sig = sig; /* The tag signature */
+ p->data[p->count].ttype = p->data[exi].ttype; /* The tag type signature */
+ p->data[p->count].offset = p->data[exi].offset; /* Same offset (may not be allocated yet) */
+ p->data[p->count].size = p->data[exi].size; /* Same size (may not be allocated yet) */
+ p->data[p->count].objp = p->data[exi].objp; /* Shared object */
+ p->data[exi].objp->refcount++; /* Bump reference count on tag type */
+ p->count++;
+
+ return p->data[exi].objp;
+}
+
+/* Search for tag signature */
+/* return: */
+/* 0 if found */
+/* 1 if found but not handled type */
+/* 2 if not found */
+/* NOTE: doesn't set icc->errc or icc->err[] */
+/* NOTE: we don't handle tag duplication - you'll always get the first in the file. */
+static int icc_find_tag(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+ int j;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i == p->count)
+ return 2;
+
+ /* See if we can handle this type */
+ for (j = 0; typetable[j].ttype != icMaxEnumType; j++) {
+ if (typetable[j].ttype == p->data[i].ttype)
+ break;
+ }
+ if (typetable[j].ttype == icMaxEnumType)
+ return 1;
+
+ return 0;
+}
+
+/* Read the specific tag element data, and return a pointer to the object */
+/* (This is an internal function) */
+/* Returns NULL if error - icc->errc will contain: */
+/* 2 if not found */
+/* Returns an icmSigUnknownType object if the tag type isn't handled by a */
+/* specific object and alow_unk is NZ */
+/* NOTE: we don't handle tag duplication - you'll always get the first in the file */
+static icmBase *icc_read_tag_ix(
+ icc *p,
+ unsigned int i, /* Index from 0.. p->count-1 */
+ int alow_unk /* NZ to allow unknown tag to load */
+) {
+ icTagTypeSignature ttype; /* Tag type we will create */
+ icmBase *nob;
+ unsigned int k;
+ int j;
+
+ if (i >= p->count) {
+ sprintf(p->err,"icc_read_tag_ix: index %d is out of range",i);
+ p->errc = 2;
+ return NULL;
+ }
+
+ /* See if it's already been read */
+ if (p->data[i].objp != NULL) {
+ return p->data[i].objp; /* Just return it */
+ }
+
+ /* See if this should be a link */
+ for (k = 0; k < p->count; k++) {
+ if (i == k)
+ continue;
+ if (p->data[i].ttype == p->data[k].ttype /* Exact match and already read */
+ && p->data[i].offset == p->data[k].offset
+ && p->data[i].size == p->data[k].size
+ && p->data[k].objp != NULL)
+ break;
+ }
+ if (k < p->count) { /* Make this a link */
+ p->data[i].objp = p->data[k].objp;
+ p->data[k].objp->refcount++; /* Bump reference count */
+ return p->data[k].objp; /* Done */
+ }
+
+ /* See if we can handle this type */
+ for (j = 0; typetable[j].ttype != icMaxEnumType; j++) {
+ if (typetable[j].ttype == p->data[i].ttype)
+ break;
+ }
+
+ if (typetable[j].ttype == icMaxEnumType) {
+ if (!alow_unk) {
+ p->errc = 2;
+ return NULL;
+ }
+ ttype = icmSigUnknownType; /* Use the Unknown type to handle an unknown tag type */
+ } else {
+ ttype = p->data[i].ttype; /* We known this type */
+ }
+
+ /* Create and read in the object */
+ if (ttype == icmSigUnknownType)
+ nob = new_icmUnknown(p);
+ else
+ nob = typetable[j].new_obj(p);
+
+ if (nob == NULL)
+ return NULL;
+
+ if ((nob->read(nob, p->data[i].size, p->of + p->data[i].offset)) != 0) {
+ nob->del(nob); /* Failed, so destroy it */
+ return NULL;
+ }
+ p->data[i].objp = nob;
+ return nob;
+}
+
+/* Read the tag element data of the first matching, and return a pointer to the object */
+/* Returns NULL if error - icc->errc will contain: */
+/* 2 if not found */
+/* Doesn't read uknown type tags */
+static icmBase *icc_read_tag(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i >= p->count) {
+ sprintf(p->err,"icc_read_tag: Tag '%s' not found",string_TagSignature(sig));
+ p->errc = 2;
+ return NULL;
+ }
+
+ /* Let read_tag_ix do all the work */
+ return icc_read_tag_ix(p, i, 0);
+}
+
+/* Read the tag element data of the first matching, and return a pointer to the object */
+/* Returns NULL if error.
+/* Returns an icmSigUnknownType object if the tag type isn't handled by a specific object. */
+/* NOTE: we don't handle tag duplication - you'll always get the first in the file. */
+static icmBase *icc_read_tag_any(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i >= p->count) {
+ sprintf(p->err,"icc_read_tag: Tag '%s' not found",string_TagSignature(sig));
+ p->errc = 2;
+ return NULL;
+ }
+
+ /* Let read_tag_ix do all the work */
+ return icc_read_tag_ix(p, i, 1);
+}
+
+/* Rename a tag signature */
+static int icc_rename_tag(
+ icc *p,
+ icTagSignature sig, /* Existing Tag signature - may be unknown */
+ icTagSignature sigNew /* New Tag signature - may be unknown */
+) {
+ unsigned int k;
+ int i, j, ok = 1;
+
+ /* Search for signature */
+ for (k = 0; k < p->count; k++) {
+ if (p->data[k].sig == sig) /* Found it */
+ break;
+ }
+ if (k >= p->count) {
+ sprintf(p->err,"icc_rename_tag: Tag '%s' not found",string_TagSignature(sig));
+ return p->errc = 2;
+ }
+
+ /* Check that a known new signature has an acceptable type */
+ for (i = 0; sigtypetable[i].sig != icMaxEnumType; i++) {
+ if (sigtypetable[i].sig == sigNew) { /* recognized signature */
+ ok = 0;
+ for (j = 0; sigtypetable[i].ttypes[j] != icMaxEnumType; j++) {
+ if (sigtypetable[i].ttypes[j] == p->data[k].ttype) /* recognized type */
+ ok = 1;
+ }
+ break;
+ }
+ }
+
+ if (!ok) {
+ sprintf(p->err,"icc_rename_tag: wrong signature for tag type");
+ p->errc = 1;
+ return p->errc;
+ }
+
+ /* change its signature */
+ p->data[k].sig = sigNew;
+
+ return 0;
+}
+
+/* Unread a specific tag, and free the underlying tag type data */
+/* if this was the last reference to it. */
+/* (This is an internal function) */
+/* Returns non-zero on error: */
+/* tag not found - icc->errc will contain 2 */
+/* tag not read - icc->errc will contain 2 */
+static int icc_unread_tag_ix(
+ icc *p,
+ unsigned int i /* Index from 0.. p->count-1 */
+) {
+ if (i >= p->count) {
+ sprintf(p->err,"icc_unread_tag_ix: index %d is out of range",i);
+ return p->errc = 2;
+ }
+
+ /* See if it's been read */
+ if (p->data[i].objp == NULL) {
+ sprintf(p->err,"icc_unread_tag: Tag '%s' not currently loaded",string_TagSignature(p->data[i].sig));
+ return p->errc = 2;
+ }
+
+ if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
+ (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
+ p->data[i].objp = NULL;
+
+ return 0;
+}
+
+/* Unread the tag, and free the underlying tag type */
+/* if this was the last reference to it. */
+/* Returns non-zero on error: */
+/* tag not found - icc->errc will contain 2 */
+/* tag not read - icc->errc will contain 2 */
+/* NOTE: we don't handle tag duplication - you'll always get the first in the file */
+static int icc_unread_tag(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i >= p->count) {
+ sprintf(p->err,"icc_unread_tag: Tag '%s' not found",string_TagSignature(sig));
+ return p->errc = 2;
+ }
+
+ return icc_unread_tag(p, i);
+}
+
+/* Delete the tag, and free the underlying tag type, */
+/* if this was the last reference to it. */
+/* Note this finds the first tag with a matching signature */
+/* Returns non-zero on error: */
+/* tag not found - icc->errc will contain 2 */
+static int icc_delete_tag_ix(
+ icc *p,
+ unsigned int i /* Index from 0.. p->count-1 */
+) {
+ if (i >= p->count) {
+ sprintf(p->err,"icc_delete_tag_ix: index %d of range",i);
+ return p->errc = 2;
+ }
+
+ /* If it's been read into memory, decrement the reference count */
+ if (p->data[i].objp != NULL) {
+ if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
+ (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
+ p->data[i].objp = NULL;
+ }
+
+ /* Now remove it from the tag list */
+ for (; i < (p->count-1); i++)
+ p->data[i] = p->data[i+1]; /* Copy the structure down */
+
+ p->count--; /* One less tag in list */
+
+ return 0;
+}
+
+/* Delete the tag, and free the underlying tag type, */
+/* if this was the last reference to it. */
+/* Note this finds the first tag with a matching signature. */
+/* Returns non-zero on error: */
+/* tag not found - icc->errc will contain 2 */
+static int icc_delete_tag(
+ icc *p,
+ icTagSignature sig /* Tag signature - may be unknown */
+) {
+ unsigned int i;
+
+ /* Search for signature */
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].sig == sig) /* Found it */
+ break;
+ }
+ if (i >= p->count) {
+ sprintf(p->err,"icc_delete_tag: Tag '%s' not found",string_TagSignature(sig));
+ return p->errc = 2;
+ }
+
+ return icc_delete_tag_ix(p, i);
+}
+
+/* Read all the tags into memory, including unknown types. */
+/* Returns non-zero on error. */
+static int icc_read_all_tags(
+ icc *p
+) {
+ unsigned int i;
+
+ for (i = 0; i < p->count; i++) { /* For all the tag element data */
+ if (icc_read_tag_ix(p, i, 1) == NULL)
+ return p->errc;
+ }
+ return 0;
+}
+
+
+static void icc_dump(
+ icc *p,
+ icmFile *op, /* Output to dump to */
+ int verb /* Verbosity level */
+) {
+ unsigned int i;
+ if (verb <= 0)
+ return;
+
+ op->gprintf(op,"icc:\n");
+
+ /* Dump the header */
+ if (p->header != NULL)
+ p->header->dump(p->header,op,verb);
+
+ /* Dump all the tag elements */
+ for (i = 0; i < p->count; i++) { /* For all the tag element data */
+ icmBase *ob;
+ int tr;
+ op->gprintf(op,"tag %d:\n",i);
+ op->gprintf(op," sig %s\n",tag2str(p->data[i].sig));
+ op->gprintf(op," type %s\n",tag2str(p->data[i].ttype));
+ op->gprintf(op," offset %d\n", p->data[i].offset);
+ op->gprintf(op," size %d\n", p->data[i].size);
+ tr = 0;
+ if (p->data[i].objp == NULL) {
+ /* The object is not loaded, so load it then free it */
+ if (icc_read_tag_ix(p, i, 1) == NULL)
+ op->gprintf(op,"Unable to read: %d, %s\n",p->errc,p->err);
+ tr = 1;
+ }
+ if ((ob = p->data[i].objp) != NULL) {
+ /* op->gprintf(op," refcount %d\n", ob->refcount); */
+ ob->dump(ob,op,verb-1);
+
+ if (tr != 0) { /* Cleanup if temporary */
+ icc_unread_tag_ix(p, i);
+ }
+ }
+ op->gprintf(op,"\n");
+ }
+}
+
+static void icc_delete(
+ icc *p
+) {
+ unsigned int i;
+ icmAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ /* Free up the header */
+ if (p->header != NULL)
+ (p->header->del)(p->header);
+
+ /* Free up the tag data objects */
+ if (p->data != NULL) {
+ for (i = 0; i < p->count; i++) {
+ if (p->data[i].objp != NULL) {
+ if (--(p->data[i].objp->refcount) == 0) /* decrement reference count */
+ (p->data[i].objp->del)(p->data[i].objp); /* Last reference */
+ p->data[i].objp = NULL;
+ }
+ }
+ /* Free tag table */
+ al->free(al, p->data);
+ }
+
+ /* We are responsible for deleting the file object */
+ if (p->del_fp && p->fp != NULL)
+ p->fp->del(p->fp);
+
+ /* This object */
+ al->free(al, p);
+
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+}
+
+/* ================================================== */
+/* Lut Color normalizing and de-normalizing functions */
+
+/* As a rule, I am representing Lut in memory as values in machine form as real */
+/* numbers in the range 0.0 - 1.0. For many color spaces (ie. RGB, Gray, */
+/* hsv, hls, cmyk and other device coords), this is entirely appropriate. */
+/* For CIE based spaces though, this is not correct, since (I assume!) the binary */
+/* representation will be consistent with the encoding in Annex A, page 74 */
+/* of the standard. Note that the standard doesn't specify the encoding of */
+/* many color spaces (ie. Yuv, Yxy etc.), and is unclear about PCS. */
+
+/* The following functions convert to and from the CIE base spaces */
+/* and the real Lut input/output values. These are used to convert real color */
+/* space values into/out of the raw lut 0.0-1.0 representation (which subsequently */
+/* get converted to ICC integer values in the obvious way as a mapping to 0 .. 2^n-1). */
+
+/* This is used internally to support the Lut->lookup() function, */
+/* and can also be used by someone writing a Lut based profile to determine */
+/* the colorspace range that the input lut indexes cover, as well */
+/* as processing the output luts values into normalized form ready */
+/* for writing. */
+
+/* These functions should be accessed by calling icc.getNormFuncs() */
+
+/* - - - - - - - - - - - - - - - - */
+/* According to 6.5.5 and 6.5.6 of the spec., */
+/* XYZ index values are represented the same as their table */
+/* values, ie. as a u1.15 representation, with a value */
+/* range from 0.0 -> 1.999969482422 */
+
+/* Convert Lut index/value to XYZ coord. */
+static void Lut_Lut2XYZ(double *out, double *in) {
+ out[0] = in[0] * (1.0 + 32767.0/32768); /* X */
+ out[1] = in[1] * (1.0 + 32767.0/32768); /* Y */
+ out[2] = in[2] * (1.0 + 32767.0/32768); /* Z */
+}
+
+/* Convert XYZ coord to Lut index/value. */
+static void Lut_XYZ2Lut(double *out, double *in) {
+ out[0] = in[0] * (1.0/(1.0 + 32767.0/32768));
+ out[1] = in[1] * (1.0/(1.0 + 32767.0/32768));
+ out[2] = in[2] * (1.0/(1.0 + 32767.0/32768));
+}
+
+/* Convert Lut index/value to Y coord. */
+static void Lut_Lut2Y(double *out, double *in) {
+ out[0] = in[0] * (1.0 + 32767.0/32768); /* Y */
+}
+
+/* Convert Y coord to Lut index/value. */
+static void Lut_Y2Lut(double *out, double *in) {
+ out[0] = in[0] * (1.0/(1.0 + 32767.0/32768));
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Convert 8 bit Lab to Lut numbers */
+/* Annex A specifies 8 and 16 bit encoding, but is */
+/* silent on the Lut index normalization. */
+/* Following Michael Bourgoin's 1998 SIGGRAPH course comment on this, */
+/* we assume here that the index encoding is the same as the */
+/* value encoding. */
+
+/* Convert Lut8 table index/value to Lab */
+static void Lut_Lut2Lab_8(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+ out[1] = (in[1] * 255.0) - 128.0; /* a */
+ out[2] = (in[2] * 255.0) - 128.0; /* b */
+}
+
+/* Convert Lab to Lut8 table index/value */
+static void Lut_Lab2Lut_8(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+ out[1] = (in[1] + 128.0) * 1.0/255.0; /* a */
+ out[2] = (in[2] + 128.0) * 1.0/255.0; /* b */
+}
+
+/* Convert Lut8 table index/value to L */
+static void Lut_Lut2L_8(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+}
+
+/* Convert L to Lut8 table index/value */
+static void Lut_L2Lut_8(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Convert 16 bit Lab to Lut numbers, V2 */
+
+/* Convert Lut16 table index/value to Lab */
+static void Lut_Lut2LabV2_16(double *out, double *in) {
+ out[0] = in[0] * (100.0 * 65535.0)/65280.0; /* L */
+ out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0; /* a */
+ out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0; /* b */
+}
+
+/* Convert Lab to Lut16 table index/value */
+static void Lut_Lab2LutV2_16(double *out, double *in) {
+ out[0] = in[0] * 65280.0/(100.0 * 65535.0); /* L */
+ out[1] = (in[1] + 128.0) * 65280.0/(255.0 * 65535.0); /* a */
+ out[2] = (in[2] + 128.0) * 65280.0/(255.0 * 65535.0); /* b */
+}
+
+/* Convert Lut16 table index/value to L */
+static void Lut_Lut2LV2_16(double *out, double *in) {
+ out[0] = in[0] * (100.0 * 65535.0)/65280.0; /* L */
+}
+
+/* Convert Lab to Lut16 table index/value */
+static void Lut_L2LutV2_16(double *out, double *in) {
+ out[0] = in[0] * 65280.0/(100.0 * 65535.0); /* L */
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Convert 16 bit Lab to Lut numbers, V4 */
+
+/* Convert Lut16 table index/value to Lab */
+static void Lut_Lut2LabV4_16(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+ out[1] = (in[1] * 255.0) - 128.0; /* a */
+ out[2] = (in[2] * 255.0) - 128.0; /* b */
+}
+
+/* Convert Lab to Lut16 table index/value */
+static void Lut_Lab2LutV4_16(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+ out[1] = (in[1] + 128.0) * 1.0/255.0; /* a */
+ out[2] = (in[2] + 128.0) * 1.0/255.0; /* b */
+}
+
+/* Convert Lut16 table index/value to L */
+static void Lut_Lut2LV4_16(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+}
+
+/* Convert L to Lut16 table index/value */
+static void Lut_L2LutV4_16(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Convert Luv to Lut number */
+/* This data normalization is taken from Apples */
+/* Colorsync specification. */
+/* As per other color spaces, we assume that the index */
+/* normalization is the same as the data normalization. */
+
+/* Convert Lut table index/value to Luv */
+static void Lut_Lut2Luv(double *out, double *in) {
+ out[0] = in[0] * 100.0; /* L */
+ out[1] = (in[1] * 65535.0/256.0) - 128.0; /* u */
+ out[2] = (in[2] * 65535.0/256.0) - 128.0; /* v */
+}
+
+/* Convert Luv to Lut table index/value */
+static void Lut_Luv2Lut(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0; /* L */
+ out[1] = (in[1] + 128.0) * 256.0/65535.0; /* u */
+ out[2] = (in[2] + 128.0) * 256.0/65535.0; /* v */
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Default N component conversions */
+static void Lut_N(double *out, double *in, int nc) {
+ for (--nc; nc >= 0; nc--)
+ out[nc] = in[nc];
+}
+
+/* 1 */
+static void Lut_1(double *out, double *in) {
+ out[0] = in[0];
+}
+
+/* 2 */
+static void Lut_2(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+}
+
+/* 3 */
+static void Lut_3(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+}
+
+/* 4 */
+static void Lut_4(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+/* 5 */
+static void Lut_5(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[4] = in[4];
+}
+
+/* 6 */
+static void Lut_6(double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+ out[4] = in[4];
+ out[5] = in[5];
+}
+
+/* 7 */
+static void Lut_7(double *out, double *in) {
+ Lut_N(out, in, 7);
+}
+
+/* 8 */
+static void Lut_8(double *out, double *in) {
+ Lut_N(out, in, 8);
+}
+
+/* 9 */
+static void Lut_9(double *out, double *in) {
+ Lut_N(out, in, 9);
+}
+
+/* 10 */
+static void Lut_10(double *out, double *in) {
+ Lut_N(out, in, 10);
+}
+
+/* 11 */
+static void Lut_11(double *out, double *in) {
+ Lut_N(out, in, 11);
+}
+
+/* 12 */
+static void Lut_12(double *out, double *in) {
+ Lut_N(out, in, 12);
+}
+
+/* 13 */
+static void Lut_13(double *out, double *in) {
+ Lut_N(out, in, 13);
+}
+
+/* 14 */
+static void Lut_14(double *out, double *in) {
+ Lut_N(out, in, 14);
+}
+
+/* 15 */
+static void Lut_15(double *out, double *in) {
+ Lut_N(out, in, 15);
+}
+
+/* Function table - match conversions to color spaces. */
+/* Anything not here, we don't know how to convert. */
+/* (ie. YCbCr) */
+static struct {
+ icColorSpaceSignature csig;
+ void (*fromLut)(double *out, double *in); /* from Lut index/entry */
+ void (*toLut)(double *out, double *in); /* to Lut index/entry */
+} colnormtable[] = {
+ {icSigXYZData, Lut_Lut2XYZ, Lut_XYZ2Lut },
+ {icmSigYData, Lut_Lut2Y, Lut_Y2Lut },
+ {icmSigLab8Data, Lut_Lut2Lab_8, Lut_Lab2Lut_8 },
+ {icmSigLabV2Data, Lut_Lut2LabV2_16, Lut_Lab2LutV2_16 },
+ {icmSigLabV4Data, Lut_Lut2LabV4_16, Lut_Lab2LutV4_16 },
+ {icmSigL8Data, Lut_Lut2L_8, Lut_L2Lut_8 },
+ {icmSigLV2Data, Lut_Lut2LV2_16, Lut_L2LutV2_16 },
+ {icmSigLV4Data, Lut_Lut2LV4_16, Lut_L2LutV4_16 },
+ {icSigLuvData, Lut_Lut2Luv, Lut_Luv2Lut },
+ {icSigYxyData, Lut_3, Lut_3 },
+ {icSigRgbData, Lut_3, Lut_3 },
+ {icSigGrayData, Lut_1, Lut_1 },
+ {icSigHsvData, Lut_3, Lut_3 },
+ {icSigHlsData, Lut_3, Lut_3 },
+ {icSigCmykData, Lut_4, Lut_4 },
+ {icSigCmyData, Lut_3, Lut_3 },
+ {icSigMch6Data, Lut_6, Lut_6 },
+ {icSig2colorData, Lut_2, Lut_2 },
+ {icSig3colorData, Lut_3, Lut_3 },
+ {icSig4colorData, Lut_4, Lut_4 },
+ {icSig5colorData, Lut_5, Lut_5 },
+ {icSig6colorData, Lut_6, Lut_6 },
+ {icSig7colorData, Lut_7, Lut_7 },
+ {icSigMch5Data, Lut_5, Lut_5 },
+ {icSigMch6Data, Lut_6, Lut_6 },
+ {icSigMch7Data, Lut_7, Lut_7 },
+ {icSigMch8Data, Lut_8, Lut_8 },
+ {icSig8colorData, Lut_8, Lut_8 },
+ {icSig9colorData, Lut_9, Lut_9 },
+ {icSig10colorData, Lut_10, Lut_10 },
+ {icSig11colorData, Lut_11, Lut_11 },
+ {icSig12colorData, Lut_12, Lut_12 },
+ {icSig13colorData, Lut_13, Lut_13 },
+ {icSig14colorData, Lut_14, Lut_14 },
+ {icSig15colorData, Lut_15, Lut_15 },
+ {icMaxEnumData, NULL, NULL }
+};
+
+/*
+ Legacy Lab encoding:
+
+ The V4 specificatins are misleading on this, since they assume in this
+ instance that all devices spaces, however labeled, have no defined
+ ICC encoding. The end result is simple enough though:
+
+ ICC V2 Lab encoding should be used in all PCS encodings in
+ a icSigLut16Type or icSigNamedColor2Type tag, and can be used
+ for Lab encoding in device spaces for these tags.
+
+ ICC V4 Lab encoding should be used in all PCS encodings in
+ all other situations, and can be used for Lab encoding in
+ device spaces for all other situtaions.
+
+ [ Since the ICC spec. doesn't cover device spaces labeled as Lab,
+ these are ripe for mis-matches between different implementations.]
+
+ This logic has yet to be fully implemented here.
+*/
+
+/* Find appropriate conversion functions from the normalised */
+/* Lut data range 0.0 - 1.0 to/from a given colorspace value, */
+/* given the color space and Lut type. */
+/* Return 0 on success, 1 on match failure. */
+/* NOTE: doesn't set error value, message etc.! */
+static int getNormFunc(
+ icc *icp,
+// icProfileClassSignature psig, /* Profile signature to use */
+ icColorSpaceSignature csig, /* Colorspace to use. */
+// int lutin, /* 0 if this is for a icSigLut16Type input, nz for output */
+// icTagSignature tagSig, /* Tag signature involved (AtoB or B2A etc.) */
+ icTagTypeSignature tagType, /* icSigLut8Type or icSigLut16Type or V4 lut */
+ icmNormFlag flag, /* icmFromLuti, icmFromLutv or icmToLuti, icmToLutv */
+ void (**nfunc)(double *out, double *in)
+) {
+ int i;
+ if (tagType == icSigLut8Type && csig == icSigLabData) {
+ csig = icmSigLab8Data;
+ }
+ if (csig == icSigLabData) {
+ if (tagType == icSigLut16Type) /* Lut16 retains legacy encoding */
+ csig = icmSigLabV2Data;
+ else { /* Other tag types use version specific encoding */
+ if (icp->ver)
+ csig = icmSigLabV4Data;
+ else
+ csig = icmSigLabV2Data;
+ }
+ }
+
+ for (i = 0; colnormtable[i].csig != icMaxEnumData; i++) {
+ if (colnormtable[i].csig == csig)
+ break; /* Found it */
+ }
+ if (colnormtable[i].csig == icMaxEnumData) { /* Oops */
+ *nfunc = NULL;
+ return 1;
+ }
+
+ if (flag == icmFromLuti || flag == icmFromLutv) { /* Table index/value decoding functions */
+ *nfunc = colnormtable[i].fromLut;
+ return 0;
+ } else if (flag == icmToLuti || flag == icmToLutv) { /* Table index/value encoding functions */
+ *nfunc = colnormtable[i].toLut;
+ return 0;
+ }
+ *nfunc = NULL;
+ return 1;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Colorspace ranges - used instead of norm/denorm by Mono, Matrix and */
+/* override PCS */
+
+/* Function table - match ranges to color spaces. */
+/* Anything not here, we don't know how to convert. */
+/* (ie. YCbCr) */
+/* Hmm. we're not handling Lab8 properly ?? ~~~8888 */
+static struct {
+ icColorSpaceSignature csig;
+ int same; /* Non zero if first entry applies to all channels */
+ double min[3]; /* Minimum value for this colorspace */
+ double max[3]; /* Maximum value for this colorspace */
+} colorrangetable[] = {
+ {icSigXYZData, 1, { 0.0 } , { 1.0 + 32767.0/32768.0 } },
+ {icmSigLab8Data, 0, { 0.0, -128.0, -128.0 }, { 100.0, 127.0, 127.0 } },
+ {icmSigLabV2Data, 0, { 0.0, -128.0, -128.0 },
+ { 100.0 + 25500.0/65280.0, 127.0 + 255.0/256.0, 127.0 + 255.0/256.0 } },
+ {icmSigLabV4Data, 0, { 0.0, -128.0, -128.0 }, { 100.0, 127.0, 127.0 } },
+ {icmSigYData, 1, { 0.0 }, { 1.0 + 32767.0/32768.0 } },
+ {icmSigL8Data, 1, { 0.0 }, { 100.0 } },
+ {icmSigLV2Data, 1, { 0.0 }, { 100.0 + 25500.0/65280.0 } },
+ {icmSigLV4Data, 1, { 0.0 }, { 100.0 } },
+ {icSigLuvData, 0, { 0.0, -128.0, -128.0 },
+ { 100.0, 127.0 + 255.0/256.0, 127.0 + 255.0/256.0 } },
+ {icSigYCbCrData, 1, { 0.0 }, { 1.0 } }, /* ??? */
+ {icSigYxyData, 1, { 0.0 }, { 1.0 } }, /* ??? */
+ {icSigRgbData, 1, { 0.0 }, { 1.0 } },
+ {icSigGrayData, 1, { 0.0 }, { 1.0 } },
+ {icSigHsvData, 1, { 0.0 }, { 1.0 } },
+ {icSigHlsData, 1, { 0.0 }, { 1.0 } },
+ {icSigCmykData, 1, { 0.0 }, { 1.0 } },
+ {icSigCmyData, 1, { 0.0 }, { 1.0 } },
+ {icSigMch6Data, 1, { 0.0 }, { 1.0 } },
+ {icSig2colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig3colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig4colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig5colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig6colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig7colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig8colorData, 1, { 0.0 }, { 1.0 } },
+ {icSigMch5Data, 1, { 0.0 }, { 1.0 } },
+ {icSigMch6Data, 1, { 0.0 }, { 1.0 } },
+ {icSigMch7Data, 1, { 0.0 }, { 1.0 } },
+ {icSigMch8Data, 1, { 0.0 }, { 1.0 } },
+ {icSig9colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig10colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig11colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig12colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig13colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig14colorData, 1, { 0.0 }, { 1.0 } },
+ {icSig15colorData, 1, { 0.0 }, { 1.0 } },
+ {icMaxEnumData, 1, { 0.0 }, { 1.0 } }
+};
+
+/* Find appropriate typical encoding ranges for a */
+/* colorspace given the color space. */
+/* Return 0 on success, 1 on match failure */
+static int getRange(
+ icc *icp,
+// icProfileClassSignature psig, /* Profile signature to use */
+ icColorSpaceSignature csig, /* Colorspace to use. */
+// int lutin, /* 0 if this is for a icSigLut16Type input, nz for output */
+// icTagSignature tagSig, /* Tag signature involved (AtoB or B2A etc.) */
+ icTagTypeSignature tagType, /* icSigLut8Type or icSigLut16Type or V4 lut */
+ double *min, double *max /* Return range values */
+) {
+ int i, e, ee;
+
+ if (tagType == icSigLut8Type && csig == icSigLabData) {
+ csig = icmSigLab8Data;
+ }
+ if (csig == icSigLabData) {
+ if (tagType == icSigLut16Type) /* Lut16 retains legacy encoding */
+ csig = icmSigLabV2Data;
+ else { /* Other tag types use version specific encoding */
+ if (icp->ver)
+ csig = icmSigLabV4Data;
+ else
+ csig = icmSigLabV2Data;
+ }
+ }
+
+ for (i = 0; colorrangetable[i].csig != icMaxEnumData; i++) {
+ if (colorrangetable[i].csig == csig)
+ break; /* Found it */
+ }
+ if (colorrangetable[i].csig == icMaxEnumData) { /* Oops */
+ return 1;
+ }
+ ee = number_ColorSpaceSignature(csig); /* Get number of components */
+
+ if (colorrangetable[i].same) { /* All channels are the same */
+ for (e = 0; e < ee; e++) {
+ if (min != NULL)
+ min[e] = colorrangetable[i].min[0];
+ if (max != NULL)
+ max[e] = colorrangetable[i].max[0];
+ }
+ } else {
+ for (e = 0; e < ee; e++) {
+ if (min != NULL)
+ min[e] = colorrangetable[i].min[e];
+ if (max != NULL)
+ max[e] = colorrangetable[i].max[e];
+ }
+ }
+ return 0;
+}
+
+/* ============================================= */
+/* Misc. support functions. */
+
+/* Clamp a 3 vector to be +ve */
+void icmClamp3(double out[3], double in[3]) {
+ int i;
+ for (i = 0; i < 3; i++)
+ out[i] = in[i] < 0.0 ? 0.0 : in[i];
+}
+
+/* Add two 3 vectors */
+void icmAdd3(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];
+}
+
+/* Subtract two 3 vectors, out = in1 - in2 */
+void icmSub3(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];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Set a 3x3 matrix to unity */
+void icmSetUnity3x3(double mat[3][3]) {
+ int i, j;
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ if (i == j)
+ mat[j][i] = 1.0;
+ else
+ mat[j][i] = 0.0;
+ }
+ }
+
+}
+
+/* Copy a 3x3 transform matrix */
+void icmCpy3x3(double dst[3][3], double src[3][3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src[j][i];
+ }
+}
+
+/* Scale each element of a 3x3 transform matrix */
+void icmScale3x3(double dst[3][3], double src[3][3], double scale) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src[j][i] * scale;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/*
+
+ mat in out
+
+[ ] [] []
+[ ] * [] => []
+[ ] [] []
+
+ */
+
+/* Multiply 3 array by 3x3 transform matrix */
+void icmMulBy3x3(double out[3], double mat[3][3], double in[3]) {
+ double tt[3];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
+ tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Add one 3x3 to another */
+/* dst = src1 + src2 */
+void icmAdd3x3(double dst[3][3], double src1[3][3], double src2[3][3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src1[j][i] + src2[j][i];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Tensor product. Multiply two 3 vectors to form a 3x3 matrix */
+/* src1[] forms the colums, and src2[] forms the rows in the result */
+void icmTensMul3(double dst[3][3], double src1[3], double src2[3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src1[j] * src2[i];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Multiply one 3x3 with another */
+/* dst = src * dst */
+void icmMul3x3(double dst[3][3], double src[3][3]) {
+ int i, j, k;
+ double td[3][3]; /* Temporary dest */
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ double tt = 0.0;
+ for (k = 0; k < 3; k++)
+ tt += src[j][k] * dst[k][i];
+ td[j][i] = tt;
+ }
+ }
+
+ /* Copy result out */
+ for (j = 0; j < 3; j++)
+ for (i = 0; i < 3; i++)
+ dst[j][i] = td[j][i];
+}
+
+/* Multiply one 3x3 with another #2 */
+/* dst = src1 * src2 */
+void icmMul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]) {
+ int i, j, k;
+ double td[3][3]; /* Temporary dest */
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ double tt = 0.0;
+ for (k = 0; k < 3; k++)
+ tt += src1[j][k] * src2[k][i];
+ td[j][i] = tt;
+ }
+ }
+
+ /* Copy result out */
+ for (j = 0; j < 3; j++)
+ for (i = 0; i < 3; i++)
+ dst[j][i] = td[j][i];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+ Matrix Inversion
+ by Richard Carling
+ from "Graphics Gems", Academic Press, 1990
+*/
+
+/*
+ * adjoint( original_matrix, inverse_matrix )
+ *
+ * calculate the adjoint of a 3x3 matrix
+ *
+ * Let a denote the minor determinant of matrix A obtained by
+ * ij
+ *
+ * deleting the ith row and jth column from A.
+ *
+ * i+j
+ * Let b = (-1) a
+ * ij ji
+ *
+ * The matrix B = (b ) is the adjoint of A
+ * ij
+ */
+
+#define det2x2(a, b, c, d) (a * d - b * c)
+
+static void adjoint(
+double out[3][3],
+double in[3][3]
+) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+
+ /* assign to individual variable names to aid */
+ /* selecting correct values */
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ /* row column labeling reversed since we transpose rows & columns */
+
+ out[0][0] = det2x2(b2, b3, c2, c3);
+ out[1][0] = - det2x2(a2, a3, c2, c3);
+ out[2][0] = det2x2(a2, a3, b2, b3);
+
+ out[0][1] = - det2x2(b1, b3, c1, c3);
+ out[1][1] = det2x2(a1, a3, c1, c3);
+ out[2][1] = - det2x2(a1, a3, b1, b3);
+
+ out[0][2] = det2x2(b1, b2, c1, c2);
+ out[1][2] = - det2x2(a1, a2, c1, c2);
+ out[2][2] = det2x2(a1, a2, b1, b2);
+}
+
+/*
+ * double = icmDet3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3 )
+ *
+ * calculate the determinant of a 3x3 matrix
+ * in the form
+ *
+ * | a1, b1, c1 |
+ * | a2, b2, c2 |
+ * | a3, b3, c3 |
+ */
+
+double icmDet3x3(double in[3][3]) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+ double ans;
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ ans = a1 * det2x2(b2, b3, c2, c3)
+ - b1 * det2x2(a2, a3, c2, c3)
+ + c1 * det2x2(a2, a3, b2, b3);
+ return ans;
+}
+
+#define ICM_SMALL_NUMBER 1.e-8
+/*
+ * inverse( original_matrix, inverse_matrix )
+ *
+ * calculate the inverse of a 4x4 matrix
+ *
+ * -1
+ * A = ___1__ adjoint A
+ * det A
+ */
+
+/* Return non-zero if not invertable */
+int icmInverse3x3(
+double out[3][3],
+double in[3][3]
+) {
+ int i, j;
+ double det;
+
+ /* calculate the 3x3 determinant
+ * if the determinant is zero,
+ * then the inverse matrix is not unique.
+ */
+ det = icmDet3x3(in);
+
+ if ( fabs(det) < ICM_SMALL_NUMBER)
+ return 1;
+
+ /* calculate the adjoint matrix */
+ adjoint(out, in);
+
+ /* scale the adjoint matrix to get the inverse */
+ for (i = 0; i < 3; i++)
+ for(j = 0; j < 3; j++)
+ out[i][j] /= det;
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Transpose a 3x3 matrix */
+void icmTranspose3x3(double out[3][3], double in[3][3]) {
+ int i, j;
+ if (out != in) {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = in[j][i];
+ } else {
+ double tt[3][3];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ tt[i][j] = in[j][i];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = tt[i][j];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the dot product of two 3 vectors */
+double icmDot3(double in1[3], double in2[3]) {
+ return in1[0] * in2[0] + in1[1] * in2[1] + in1[2] * in2[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the cross product of two 3D vectors, out = in1 x in2 */
+void icmCross3(double out[3], double in1[3], double in2[3]) {
+ double tt[3];
+ tt[0] = (in1[1] * in2[2]) - (in1[2] * in2[1]);
+ tt[1] = (in1[2] * in2[0]) - (in1[0] * in2[2]);
+ tt[2] = (in1[0] * in2[1]) - (in1[1] * in2[0]);
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the norm (length) squared of a 3 vector */
+double icmNorm3sq(double in[3]) {
+ return in[0] * in[0] + in[1] * in[1] + in[2] * in[2];
+}
+
+/* Compute the norm (length) of a 3 vector */
+double icmNorm3(double in[3]) {
+ return sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]);
+}
+
+/* Scale a 3 vector by the given ratio */
+void icmScale3(double out[3], double in[3], double rat) {
+ out[0] = in[0] * rat;
+ out[1] = in[1] * rat;
+ out[2] = in[2] * rat;
+}
+
+/* Compute a blend between in0 and in1 */
+void icmBlend3(double out[3], double in0[3], double in1[3], double bf) {
+ out[0] = (1.0 - bf) * in0[0] + bf * in1[0];
+ out[1] = (1.0 - bf) * in0[1] + bf * in1[1];
+ out[2] = (1.0 - bf) * in0[2] + bf * in1[2];
+}
+
+/* Normalise a 3 vector to the given length. Return nz if not normalisable */
+int icmNormalize3(double out[3], double in[3], double len) {
+ double tt = sqrt(in[0] * in[0] + in[1] * in[1] + in[2] * in[2]);
+
+ if (tt < ICM_SMALL_NUMBER)
+ return 1;
+ tt = len/tt;
+ out[0] = in[0] * tt;
+ out[1] = in[1] * tt;
+ out[2] = in[2] * tt;
+ return 0;
+}
+
+/* Compute the norm (length) squared of a vector define by two points */
+double icmNorm33sq(double in1[3], double in0[3]) {
+ int j;
+ double rv;
+ for (rv = 0.0, j = 0; j < 3; j++) {
+ double tt = in1[j] - in0[j];
+ rv += tt * tt;
+ }
+ return rv;
+}
+
+/* Compute the norm (length) of a vector define by two points */
+double icmNorm33(double in1[3], double in0[3]) {
+ int j;
+ double rv;
+ for (rv = 0.0, j = 0; j < 3; j++) {
+ double tt = in1[j] - in0[j];
+ rv += tt * tt;
+ }
+ return sqrt(rv);
+}
+
+/* Scale a two point vector by the given ratio. in0[] is the origin */
+void icmScale33(double out[3], double in1[3], double in0[3], double rat) {
+ out[0] = in0[0] + (in1[0] - in0[0]) * rat;
+ out[1] = in0[1] + (in1[1] - in0[1]) * rat;
+ out[2] = in0[2] + (in1[2] - in0[2]) * rat;
+}
+
+/* Normalise a two point vector to the given length. */
+/* The new location of in1[] is returned in out[]. */
+/* Return nz if not normalisable */
+int icmNormalize33(double out[3], double in1[3], double in0[3], double len) {
+ int j;
+ double vl;
+
+ for (vl = 0.0, j = 0; j < 3; j++) {
+ double tt = in1[j] - in0[j];
+ vl += tt * tt;
+ }
+ vl = sqrt(vl);
+ if (vl < ICM_SMALL_NUMBER)
+ return 1;
+
+ vl = len/vl;
+ for (j = 0; j < 3; j++) {
+ out[j] = in0[j] + (in1[j] - in0[j]) * vl;
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given two 3D points, create a matrix that rotates */
+/* and scales one onto the other about the origin 0,0,0. */
+/* The maths is from page 52 of Tomas Moller and Eric Haines "Real-Time Rendering". */
+/* s is source vector, t is target vector. */
+/* Usage of icmRotMat: */
+/* t[0] == mat[0][0] * s[0] + mat[0][1] * s[1] + mat[0][2] * s[2]; */
+/* t[1] == mat[1][0] * s[0] + mat[1][1] * s[1] + mat[1][2] * s[2]; */
+/* t[2] == mat[2][0] * s[0] + mat[2][1] * s[1] + mat[2][2] * s[2]; */
+/* i.e. use icmMulBy3x3 */
+void icmRotMat(double m[3][3], double s[3], double t[3]) {
+ double sl, tl, sn[3], tn[3];
+ double v[3]; /* Cross product */
+ double e; /* Dot product */
+ double h; /* 1-e/Cross product dot squared */
+
+ /* Normalise input vectors */
+ /* The rotation will be about 0,0,0 */
+ sl = sqrt(s[0] * s[0] + s[1] * s[1] + s[2] * s[2]);
+ tl = sqrt(t[0] * t[0] + t[1] * t[1] + t[2] * t[2]);
+
+ if (sl < 1e-12 || tl < 1e-12) { /* Hmm. Do nothing */
+ m[0][0] = 1.0;
+ m[0][1] = 0.0;
+ m[0][2] = 0.0;
+ m[1][0] = 0.0;
+ m[1][1] = 1.0;
+ m[1][2] = 0.0;
+ m[2][0] = 0.0;
+ m[2][1] = 0.0;
+ m[2][2] = 1.0;
+ return;
+ }
+
+ sn[0] = s[0]/sl; sn[1] = s[1]/sl; sn[2] = s[2]/sl;
+ tn[0] = t[0]/tl; tn[1] = t[1]/tl; tn[2] = t[2]/tl;
+
+ /* Compute the cross product */
+ v[0] = (sn[1] * tn[2]) - (sn[2] * tn[1]);
+ v[1] = (sn[2] * tn[0]) - (sn[0] * tn[2]);
+ v[2] = (sn[0] * tn[1]) - (sn[1] * tn[0]);
+
+ /* Compute the dot product */
+ e = sn[0] * tn[0] + sn[1] * tn[1] + sn[2] * tn[2];
+
+ /* Cross product dot squared */
+ h = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
+
+ /* If the two input vectors are close to being parallel, */
+ /* then h will be close to zero. */
+ if (fabs(h) < 1e-12) {
+ m[0][0] = tl/sl;
+ m[0][1] = 0.0;
+ m[0][2] = 0.0;
+ m[1][0] = 0.0;
+ m[1][1] = tl/sl;
+ m[1][2] = 0.0;
+ m[2][0] = 0.0;
+ m[2][1] = 0.0;
+ m[2][2] = tl/sl;
+ } else {
+ /* 1-e/Cross product dot squared */
+ h = (1.0 - e) / h;
+
+ m[0][0] = tl/sl * (e + h * v[0] * v[0]);
+ m[0][1] = tl/sl * (h * v[0] * v[1] - v[2]);
+ m[0][2] = tl/sl * (h * v[0] * v[2] + v[1]);
+ m[1][0] = tl/sl * (h * v[0] * v[1] + v[2]);
+ m[1][1] = tl/sl * (e + h * v[1] * v[1]);
+ m[1][2] = tl/sl * (h * v[1] * v[2] - v[0]);
+ m[2][0] = tl/sl * (h * v[0] * v[2] - v[1]);
+ m[2][1] = tl/sl * (h * v[1] * v[2] + v[0]);
+ m[2][2] = tl/sl * (e + h * v[2] * v[2]);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Multiply 2 array by 2x2 transform matrix */
+void icmMulBy2x2(double out[2], double mat[2][2], double in[2]) {
+ double tt[2];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Copy a 3x4 transform matrix */
+void icmCpy3x4(double dst[3][4], double src[3][4]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 4; i++)
+ dst[j][i] = src[j][i];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Multiply 3 array by 3x4 transform matrix */
+void icmMul3By3x4(double out[3], double mat[3][4], double in[3]) {
+ double tt[3];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2] + mat[0][3];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2] + mat[1][3];
+ tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2] + mat[2][3];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given two 3D vectors, create a matrix that translates, */
+/* rotates and scales one onto the other. */
+/* The maths is from page 52 of Tomas Moller and Eric Haines */
+/* "Real-Time Rendering". */
+/* s0 -> s1 is source vector, t0 -> t1 is target vector. */
+/* Usage of icmRotMat: */
+/* t[0] == mat[0][0] * s[0] + mat[0][1] * s[1] + mat[0][2] * s[2] + mat[0][3]; */
+/* t[1] == mat[1][0] * s[0] + mat[1][1] * s[1] + mat[1][2] * s[2] + mat[1][3]; */
+/* t[2] == mat[2][0] * s[0] + mat[2][1] * s[1] + mat[2][2] * s[2] + mat[2][3]; */
+/* i.e. use icmMul3By3x4 */
+void icmVecRotMat(double m[3][4], double s1[3], double s0[3], double t1[3], double t0[3]) {
+ int i, j;
+ double ss[3], tt[3], rr[3][3];
+
+ /* Create the rotation matrix: */
+ for (i = 0; i < 3; i++) {
+ ss[i] = s1[i] - s0[i];
+ tt[i] = t1[i] - t0[i];
+ }
+ icmRotMat(rr, ss, tt);
+
+ /* Create rotated version of s0: */
+ icmMulBy3x3(ss, rr, s0);
+
+ /* Create 4x4 matrix */
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 4; i++) {
+ if (i < 3 && j < 3)
+ m[j][i] = rr[j][i];
+ else if (i == 3 && j < 3)
+ m[j][i] = t0[j] - ss[j];
+ else if (i == j)
+ m[j][i] = 1.0;
+ else
+ m[j][i] = 0.0;
+ }
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the 3D intersection of a vector and a plane */
+/* return nz if there is no intersection */
+int icmVecPlaneIsect(
+double isect[3], /* return intersection point */
+double pl_const, /* Plane equation constant */
+double pl_norm[3], /* Plane normal vector */
+double ve_1[3], /* Point on line */
+double ve_0[3] /* Second point on line */
+) {
+ double den; /* denominator */
+ double rv; /* Vector parameter value */
+ double vvec[3]; /* Vector vector */
+ double ival[3]; /* Intersection value */
+
+ /* Compute vector between the two points */
+ vvec[0] = ve_1[0] - ve_0[0];
+ vvec[1] = ve_1[1] - ve_0[1];
+ vvec[2] = ve_1[2] - ve_0[2];
+
+ /* Compute the denominator */
+ den = pl_norm[0] * vvec[0] + pl_norm[1] * vvec[1] + pl_norm[2] * vvec[2];
+
+ /* Too small to intersect ? */
+ if (fabs(den) < 1e-12) {
+ return 1;
+ }
+
+ /* Compute the parameterized intersction point */
+ rv = -(pl_norm[0] * ve_0[0] + pl_norm[1] * ve_0[1] + pl_norm[2] * ve_0[2] + pl_const)/den;
+
+ /* Compute the actual intersection point */
+ isect[0] = ve_0[0] + rv * vvec[0];
+ isect[1] = ve_0[1] + rv * vvec[1];
+ isect[2] = ve_0[2] + rv * vvec[2];
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the closest points between two lines a and b. */
+/* Return closest points and parameter values if not NULL. */
+/* Return nz if they are paralel. */
+/* The maths is from page 338 of Tomas Moller and Eric Haines "Real-Time Rendering". */
+int icmLineLineClosest(double ca[3], double cb[3], double *pa, double * pb,
+ double la0[3], double la1[3], double lb0[3], double lb1[3]) {
+ double va[3], vb[3];
+ double vvab[3], vvabns; /* Cross product of va and vb and its norm squared */
+ double vba0[3]; /* lb0 - la0 */
+ double tt[3];
+ double a, b; /* Parameter values */
+
+ icmSub3(va, la1, la0);
+ icmSub3(vb, lb1, lb0);
+ icmCross3(vvab, va, vb);
+ vvabns = icmNorm3sq(vvab);
+
+ if (vvabns < 1e-12)
+ return 1;
+
+ icmSub3(vba0, lb0, la0);
+ icmCross3(tt, vba0, vb);
+ a = icmDot3(tt, vvab) / vvabns;
+
+ icmCross3(tt, vba0, va);
+ b = icmDot3(tt, vvab) / vvabns;
+
+ if (pa != NULL)
+ *pa = a;
+
+ if (pb != NULL)
+ *pb = b;
+
+ if (ca != NULL) {
+ ca[0] = la0[0] + a * va[0];
+ ca[1] = la0[1] + a * va[1];
+ ca[2] = la0[2] + a * va[2];
+ }
+
+ if (cb != NULL) {
+ cb[0] = lb0[0] + b * vb[0];
+ cb[1] = lb0[1] + b * vb[1];
+ cb[2] = lb0[2] + b * vb[2];
+ }
+
+#ifdef NEVER /* Verify */
+ {
+ double vab[3]; /* Vector from ca to cb */
+
+ vab[0] = lb0[0] + b * vb[0] - la0[0] - a * va[0];
+ vab[1] = lb0[1] + b * vb[1] - la0[1] - a * va[1];
+ vab[2] = lb0[2] + b * vb[2] - la0[2] - a * va[2];
+
+ if (icmDot3(va, vab) > 1e-6
+ || icmDot3(vb, vab) > 1e-6)
+ warning("icmLineLineClosest verify failed\n");
+ }
+#endif
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given 3 3D points, compute a plane equation. */
+/* The normal will be right handed given the order of the points */
+/* The plane equation will be the 3 normal components and the constant. */
+/* Return nz if any points are cooincident or co-linear */
+int icmPlaneEqn3(double eq[4], double p0[3], double p1[3], double p2[3]) {
+ double ll, v1[3], v2[3];
+
+ /* Compute vectors along edges */
+ v2[0] = p1[0] - p0[0];
+ v2[1] = p1[1] - p0[1];
+ v2[2] = p1[2] - p0[2];
+
+ v1[0] = p2[0] - p0[0];
+ v1[1] = p2[1] - p0[1];
+ v1[2] = p2[2] - p0[2];
+
+ /* Compute cross products v1 x v2, which will be the normal */
+ eq[0] = v1[1] * v2[2] - v1[2] * v2[1];
+ eq[1] = v1[2] * v2[0] - v1[0] * v2[2];
+ eq[2] = v1[0] * v2[1] - v1[1] * v2[0];
+
+ /* Normalise the equation */
+ ll = sqrt(eq[0] * eq[0] + eq[1] * eq[1] + eq[2] * eq[2]);
+ if (ll < 1e-10) {
+ return 1;
+ }
+ eq[0] /= ll;
+ eq[1] /= ll;
+ eq[2] /= ll;
+
+ /* Compute the plane equation constant */
+ eq[3] = - (eq[0] * p0[0])
+ - (eq[1] * p0[1])
+ - (eq[2] * p0[2]);
+
+ return 0;
+}
+
+/* Given a 3D point and a plane equation, return the signed */
+/* distance from the plane */
+double icmPlaneDist3(double eq[4], double p[3]) {
+ double rv;
+
+ rv = eq[0] * p[0]
+ + eq[1] * p[1]
+ + eq[2] * p[2]
+ + eq[3];
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* CIE Y (range 0 .. 1) to perceptual CIE 1976 L* (range 0 .. 100) */
+double
+icmY2L(double val) {
+ if (val > 0.008856451586)
+ val = pow(val,1.0/3.0);
+ else
+ val = 7.787036979 * val + 16.0/116.0;
+
+ val = (116.0 * val - 16.0);
+ return val;
+}
+
+/* Perceptual CIE 1976 L* (range 0 .. 100) to CIE Y (range 0 .. 1) */
+double
+icmL2Y(double val) {
+ val = (val + 16.0)/116.0;
+
+ if (val > 24.0/116.0)
+ val = pow(val,3.0);
+ else
+ val = (val - 16.0/116.0)/7.787036979;
+ return val;
+}
+
+/* CIE XYZ to perceptual CIE 1976 L*a*b* */
+void
+icmXYZ2Lab(icmXYZNumber *w, double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/w->X;
+ y = Y/w->Y;
+ z = Z/w->Z;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+/* Perceptual CIE 1976 L*a*b* to CIE XYZ */
+void
+icmLab2XYZ(icmXYZNumber *w, double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+
+ fy = (L + 16.0)/116.0;
+ fx = a/500.0 + fy;
+ fz = fy - b/200.0;
+
+ if (fy > 24.0/116.0)
+ y = pow(fy,3.0);
+ else
+ y = (fy - 16.0/116.0)/7.787036979;
+
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ out[0] = x * w->X;
+ out[1] = y * w->Y;
+ out[2] = z * w->Z;
+}
+
+
+/* LCh to Lab */
+void icmLCh2Lab(double *out, double *in) {
+ double C, h;
+
+ C = in[1];
+ h = 3.14159265359/180.0 * in[2];
+
+ out[0] = in[0];
+ out[1] = C * cos(h);
+ out[2] = C * sin(h);
+}
+
+/* Lab to LCh */
+void icmLab2LCh(double *out, double *in) {
+ double C, h;
+
+ C = sqrt(in[1] * in[1] + in[2] * in[2]);
+
+ h = (180.0/3.14159265359) * atan2(in[2], in[1]);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ out[0] = in[0];
+ out[1] = C;
+ out[2] = h;
+}
+
+/* XYZ to Yxy */
+extern ICCLIB_API void icmXYZ2Yxy(double *out, double *in) {
+ double sum = in[0] + in[1] + in[2];
+ double Y, x, y;
+
+ if (sum < 1e-9) {
+ Y = 0.0;
+ y = 0.333333333;
+ x = 0.333333333;
+ } else {
+ Y = in[1];
+ x = in[0]/sum;
+ y = in[1]/sum;
+ }
+ out[0] = Y;
+ out[1] = x;
+ out[2] = y;
+}
+
+/* Yxy to XYZ */
+extern ICCLIB_API void icmYxy2XYZ(double *out, double *in) {
+ double Y = in[0];
+ double x = in[1];
+ double y = in[2];
+ double z = 1.0 - x - y;
+ double sum;
+ if (y < 1e-9) {
+ out[0] = out[1] = out[2] = 0.0;
+ } else {
+ sum = Y/y;
+ out[0] = x * sum;
+ out[1] = Y;
+ out[2] = z * sum;
+ }
+}
+
+
+/* CIE XYZ to perceptual CIE 1976 L*u*v* */
+extern ICCLIB_API void icmXYZ2Luv(icmXYZNumber *w, double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double un, vn, u, v, fl, fu, fv;
+
+ un = (4.0 * w->X) / (w->X + 15.0 * w->Y + 3.0 * w->Z);
+ vn = (9.0 * w->Y) / (w->X + 15.0 * w->Y + 3.0 * w->Z);
+ u = (4.0 * X) / (X + 15.0 * Y + 3.0 * Z);
+ v = (9.0 * Y) / (X + 15.0 * Y + 3.0 * Z);
+
+ Y /= w->Y;
+
+ if (Y > 0.008856451586)
+ fl = pow(Y,1.0/3.0);
+ else
+ fl = 7.787036979 * Y + 16.0/116.0;
+
+ fu = u - un;
+ fv = v - vn;
+
+ out[0] = 116.0 * fl - 16.0;
+ out[1] = 13.0 * out[0] * fu;
+ out[2] = 13.0 * out[0] * fv;
+}
+
+/* Perceptual CIE 1976 L*u*v* to CIE XYZ */
+extern ICCLIB_API void icmLuv2XYZ(icmXYZNumber *w, double *out, double *in) {
+ double un, vn, u, v, fl, fu, fv, sum, X, Y, Z;
+
+ fl = (in[0] + 16.0)/116.0;
+ fu = in[1] / (13.0 * in[0]);
+ fv = in[2] / (13.0 * in[0]);
+
+ un = (4.0 * w->X) / (w->X + 15.0 * w->Y + 3.0 * w->Z);
+ vn = (9.0 * w->Y) / (w->X + 15.0 * w->Y + 3.0 * w->Z);
+
+ u = fu + un;
+ v = fv + vn;
+
+ if (fl > 24.0/116.0)
+ Y = pow(fl,3.0);
+ else
+ Y = (fl - 16.0/116.0)/7.787036979;
+ Y *= w->Y;
+
+ sum = (9.0 * Y)/v;
+ X = (u * sum)/4.0;
+ Z = (sum - X - 15.0 * Y)/3.0;
+
+ out[0] = X;
+ out[1] = Y;
+ out[2] = Z;
+}
+
+/* NOTE :- none of the following seven have been protected */
+/* against arithmmetic issues (ie. for black) */
+
+/* CIE XYZ to perceptual CIE 1976 UCS diagram Yu'v'*/
+/* (Yu'v' is a better chromaticity space than Yxy) */
+extern ICCLIB_API void icmXYZ21976UCS(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double den, u, v;
+
+ den = (X + 15.0 * Y + 3.0 * Z);
+ u = (4.0 * X) / den;
+ v = (9.0 * Y) / den;
+
+ out[0] = Y;
+ out[1] = u;
+ out[2] = v;
+}
+
+/* Perceptual CIE 1976 UCS diagram Yu'v' to CIE XYZ */
+extern ICCLIB_API void icm1976UCS2XYZ(double *out, double *in) {
+ double u, v, fl, fu, fv, sum, X, Y, Z;
+
+ Y = in[0];
+ u = in[1];
+ v = in[2];
+
+ X = ((9.0 * u * Y)/(4.0 * v));
+ Z = -(((20.0 * v + 3.0 * u - 12.0) * Y)/(4.0 * v));
+
+ out[0] = X;
+ out[1] = Y;
+ out[2] = Z;
+}
+
+/* CIE XYZ to perceptual CIE 1960 UCS */
+/* (This was obsoleted by the 1976UCS, but is still used */
+/* in computing color temperatures.) */
+extern ICCLIB_API void icmXYZ21960UCS(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double u, v;
+
+ u = (4.0 * X) / (X + 15.0 * Y + 3.0 * Z);
+ v = (6.0 * Y) / (X + 15.0 * Y + 3.0 * Z);
+
+ out[0] = Y;
+ out[1] = u;
+ out[2] = v;
+}
+
+/* Perceptual CIE 1960 UCS to CIE XYZ */
+extern ICCLIB_API void icm1960UCS2XYZ(double *out, double *in) {
+ double u, v, fl, fu, fv, sum, X, Y, Z;
+
+ Y = in[0];
+ u = in[1];
+ v = in[2];
+
+ X = ((3.0 * u * Y)/(2.0 * v));
+ Z = -(((10.0 * v + u - 4.0) * Y)/(2.0 * v));
+
+ out[0] = X;
+ out[1] = Y;
+ out[2] = Z;
+}
+
+/* CIE XYZ to perceptual CIE 1964 WUV (U*V*W*) */
+/* (This is obsolete but still used in computing CRI) */
+extern ICCLIB_API void icmXYZ21964WUV(icmXYZNumber *w, double *out, double *in) {
+ double W, U, V;
+ double wucs[3];
+ double iucs[3];
+
+ icmXYZ2Ary(wucs, *w);
+ icmXYZ21960UCS(wucs, wucs);
+ icmXYZ21960UCS(iucs, in);
+
+ W = 25.0 * pow(iucs[0] * 100.0/wucs[0], 1.0/3.0) - 17.0;
+ U = 13.0 * W * (iucs[1] - wucs[1]);
+ V = 13.0 * W * (iucs[2] - wucs[2]);
+
+ out[0] = W;
+ out[1] = U;
+ out[2] = V;
+}
+
+/* Perceptual CIE 1964 WUV (U*V*W*) to CIE XYZ */
+extern ICCLIB_API void icm1964WUV2XYZ(icmXYZNumber *w, double *out, double *in) {
+ double W, U, V;
+ double wucs[3];
+ double iucs[3];
+
+ icmXYZ2Ary(wucs, *w);
+ icmXYZ21960UCS(wucs, wucs);
+
+ W = in[0];
+ U = in[1];
+ V = in[2];
+
+ iucs[0] = pow((W + 17.0)/25.0, 3.0) * wucs[0]/100.0;
+ iucs[1] = U / (13.0 * W) + wucs[1];
+ iucs[2] = V / (13.0 * W) + wucs[2];
+
+ icm1960UCS2XYZ(out, iucs);
+}
+
+/* CIE CIE1960 UCS to perceptual CIE 1964 WUV (U*V*W*) */
+extern ICCLIB_API void icm1960UCS21964WUV(icmXYZNumber *w, double *out, double *in) {
+ double W, U, V;
+ double wucs[3];
+
+ icmXYZ2Ary(wucs, *w);
+ icmXYZ21960UCS(wucs, wucs);
+
+ W = 25.0 * pow(in[0] * 100.0/wucs[0], 1.0/3.0) - 17.0;
+ U = 13.0 * W * (in[1] - wucs[1]);
+ V = 13.0 * W * (in[2] - wucs[2]);
+
+ out[0] = W;
+ out[1] = U;
+ out[2] = V;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* available D50 Illuminant */
+icmXYZNumber icmD50 = { /* Profile illuminant - D50 */
+ 0.9642, 1.0000, 0.8249
+};
+
+icmXYZNumber icmD50_100 = { /* Profile illuminant - D50, scaled to 100 */
+ 96.42, 100.00, 82.49
+};
+
+double icmD50_ary3[3] = { /* Profile illuminant - D50 */
+ 0.9642, 1.0000, 0.8249
+};
+
+double icmD50_100_ary3[3] = { /* Profile illuminant - D50, scaled to 100 */
+ 96.42, 100.00, 82.49
+};
+
+/* available D65 Illuminant */
+icmXYZNumber icmD65 = { /* Profile illuminant - D65 */
+ 0.9505, 1.0000, 1.0890
+};
+
+icmXYZNumber icmD65_100 = { /* Profile illuminant - D65, scaled to 100 */
+ 95.05, 100.00, 108.90
+};
+
+double icmD65_ary3[3] = { /* Profile illuminant - D65 */
+ 0.9505, 1.0000, 1.0890
+};
+
+double icmD65_100_ary3[3] = { /* Profile illuminant - D65, scaled to 100 */
+ 95.05, 100.00, 108.90
+};
+
+/* Default black point */
+icmXYZNumber icmBlack = {
+ 0.0000, 0.0000, 0.0000
+};
+
+/* Return the normal Delta E given two Lab values */
+double icmLabDE(double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ rv += tt * tt;
+
+ return sqrt(rv);
+}
+
+/* Return the normal Delta E squared, given two Lab values */
+double icmLabDEsq(double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ rv += tt * tt;
+
+ return rv;
+}
+
+/* Return the normal Delta E given two XYZ values */
+extern ICCLIB_API double icmXYZLabDE(icmXYZNumber *w, double *in0, double *in1) {
+ double lab0[3], lab1[3], rv;
+
+ icmXYZ2Lab(w, lab0, in0);
+ icmXYZ2Lab(w, lab1, in1);
+ rv = icmLabDE(lab0, lab1);
+ return rv;
+}
+
+/* (Note that CIE94 can give odd results for very large delta E's, */
+/* when one of the two points is near the neutral axis: */
+/* ie DE(A,B + del) != DE(A,B) + DE(del) */
+#ifdef NEVER
+{
+ double w1[3] = { 99.996101, -0.058417, -0.010557 };
+ double c1[3] = { 60.267956, 98.845863, -61.163277 };
+ double w2[3] = { 100.014977, -0.138339, 0.089744 };
+ double c2[3] = { 60.294464, 98.117104, -60.843159 };
+
+ printf("DE 1 = %f, 2 = %f\n", icmLabDE(c1, w1), icmLabDE(c2, w2));
+ printf("DE94 1 = %f, 2 = %f\n", icmCIE94(c1, w1), icmCIE94(c2, w2));
+}
+#endif
+
+
+/* Return the CIE94 Delta E color difference measure, squared */
+double icmCIE94sq(double Lab0[3], double Lab1[3]) {
+ double desq, dhsq;
+ double dlsq, dcsq;
+ double c12;
+
+ {
+ double dl, da, db;
+ dl = Lab0[0] - Lab1[0];
+ dlsq = dl * dl; /* dl squared */
+ da = Lab0[1] - Lab1[1];
+ db = Lab0[2] - Lab1[2];
+
+ /* Compute normal Lab delta E squared */
+ desq = dlsq + da * da + db * db;
+ }
+
+ {
+ double c1, c2, dc;
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ c2 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ c12 = sqrt(c1 * c2); /* Symetric chromanance */
+
+ /* delta chromanance squared */
+ dc = c2 - c1;
+ dcsq = dc * dc;
+ }
+
+ /* Compute delta hue squared */
+ if ((dhsq = desq - dlsq - dcsq) < 0.0)
+ dhsq = 0.0;
+ {
+ double sc, sh;
+
+ /* Weighting factors for delta chromanance & delta hue */
+ sc = 1.0 + 0.048 * c12;
+ sh = 1.0 + 0.014 * c12;
+ return dlsq + dcsq/(sc * sc) + dhsq/(sh * sh);
+ }
+}
+
+/* Return the CIE94 Delta E color difference measure */
+double icmCIE94(double Lab0[3], double Lab1[3]) {
+ return sqrt(icmCIE94sq(Lab0, Lab1));
+}
+
+/* Return the CIE94 Delta E color difference measure for two XYZ values */
+extern ICCLIB_API double icmXYZCIE94(icmXYZNumber *w, double *in0, double *in1) {
+ double lab0[3], lab1[3];
+
+ icmXYZ2Lab(w, lab0, in0);
+ icmXYZ2Lab(w, lab1, in1);
+ return sqrt(icmCIE94sq(lab0, lab1));
+}
+
+
+/* From the paper "The CIEDE2000 Color-Difference Formula: Implementation Notes, */
+/* Supplementary Test Data, and Mathematical Observations", by */
+/* Gaurav Sharma, Wencheng Wu and Edul N. Dalal, */
+/* Color Res. Appl., vol. 30, no. 1, pp. 21-30, Feb. 2005. */
+
+/* Return the CIEDE2000 Delta E color difference measure squared, for two Lab values */
+double icmCIE2Ksq(double *Lab0, double *Lab1) {
+ double C1, C2;
+ double h1, h2;
+ double dL, dC, dH;
+ double dsq;
+
+ /* The trucated value of PI is needed to ensure that the */
+ /* test cases pass, as one of them lies on the edge of */
+ /* a mathematical discontinuity. The precision is still */
+ /* enough for any practical use. */
+#define RAD2DEG(xx) (180.0/3.14159265358979 * (xx))
+#define DEG2RAD(xx) (3.14159265358979/180.0 * (xx))
+
+ /* Compute Cromanance and Hue angles */
+ {
+ double C1ab, C2ab;
+ double Cab, Cab7, G;
+ double a1, a2;
+
+ C1ab = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ C2ab = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ Cab = 0.5 * (C1ab + C2ab);
+ Cab7 = pow(Cab,7.0);
+ G = 0.5 * (1.0 - sqrt(Cab7/(Cab7 + 6103515625.0)));
+ a1 = (1.0 + G) * Lab0[1];
+ a2 = (1.0 + G) * Lab1[1];
+ C1 = sqrt(a1 * a1 + Lab0[2] * Lab0[2]);
+ C2 = sqrt(a2 * a2 + Lab1[2] * Lab1[2]);
+
+ if (C1 < 1e-9)
+ h1 = 0.0;
+ else {
+ h1 = RAD2DEG(atan2(Lab0[2], a1));
+ if (h1 < 0.0)
+ h1 += 360.0;
+ }
+
+ if (C2 < 1e-9)
+ h2 = 0.0;
+ else {
+ h2 = RAD2DEG(atan2(Lab1[2], a2));
+ if (h2 < 0.0)
+ h2 += 360.0;
+ }
+ }
+
+ /* Compute delta L, C and H */
+ {
+ double dh;
+
+ dL = Lab1[0] - Lab0[0];
+ dC = C2 - C1;
+ if (C1 < 1e-9 || C2 < 1e-9) {
+ dh = 0.0;
+ } else {
+ dh = h2 - h1;
+ if (dh > 180.0)
+ dh -= 360.0;
+ else if (dh < -180.0)
+ dh += 360.0;
+ }
+
+ dH = 2.0 * sqrt(C1 * C2) * sin(DEG2RAD(0.5 * dh));
+ }
+
+ {
+ double L, C, h, T;
+ double hh, ddeg;
+ double C7, RC, L50sq, SL, SC, SH, RT;
+ double dLsq, dCsq, dHsq, RCH;
+
+ L = 0.5 * (Lab0[0] + Lab1[0]);
+ C = 0.5 * (C1 + C2);
+ if (C1 < 1e-9 || C2 < 1e-9) {
+ h = h1 + h2;
+ } else {
+ h = h1 + h2;
+ if (fabs(h1 - h2) > 180.0) {
+ if (h < 360.0)
+ h += 360.0;
+ else if (h >= 360.0)
+ h -= 360.0;
+ }
+ h *= 0.5;
+ }
+ T = 1.0 - 0.17 * cos(DEG2RAD(h-30.0)) + 0.24 * cos(DEG2RAD(2.0 * h))
+ + 0.32 * cos(DEG2RAD(3.0 * h + 6.0)) - 0.2 * cos(DEG2RAD(4.0 * h - 63.0));
+ hh = (h - 275.0)/25.0;
+ ddeg = 30.0 * exp(-hh * hh);
+ C7 = pow(C,7.0);
+ RC = 2.0 * sqrt(C7/(C7 + 6103515625.0));
+ L50sq = (L - 50.0) * (L - 50.0);
+ SL = 1.0 + (0.015 * L50sq)/sqrt(20.0 + L50sq);
+ SC = 1.0 + 0.045 * C;
+ SH = 1.0 + 0.015 * C * T;
+ RT = -sin(DEG2RAD(2 * ddeg)) * RC;
+
+ dLsq = dL/SL;
+ dCsq = dC/SC;
+ dHsq = dH/SH;
+
+ RCH = RT * dCsq * dHsq;
+
+ dLsq *= dLsq;
+ dCsq *= dCsq;
+ dHsq *= dHsq;
+
+ dsq = dLsq + dCsq + dHsq + RCH;
+ }
+
+ return dsq;
+
+#undef RAD2DEG
+#undef DEG2RAD
+}
+
+/* Return the CIE2DE000 Delta E color difference measure for two Lab values */
+double icmCIE2K(double *Lab0, double *Lab1) {
+ return sqrt(icmCIE2Ksq(Lab0, Lab1));
+}
+
+/* Return the CIEDE2000 Delta E color difference measure for two XYZ values */
+extern ICCLIB_API double icmXYZCIE2K(icmXYZNumber *w, double *in0, double *in1) {
+ double lab0[3], lab1[3];
+
+ icmXYZ2Lab(w, lab0, in0);
+ icmXYZ2Lab(w, lab1, in1);
+ return sqrt(icmCIE2Ksq(lab0, lab1));
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Chromatic adaptation transform utility */
+/* Return a 3x3 chromatic adaptation matrix */
+/* Use icmMulBy3x3(dst, mat, src) */
+void icmChromAdaptMatrix(
+ int flags, /* Use bradford, Transform given matrix flags */
+ icmXYZNumber d_wp, /* Destination white point */
+ icmXYZNumber s_wp, /* Source white point */
+ double mat[3][3] /* Destination matrix */
+) {
+ double dst[3], src[3]; /* Source & destination white points */
+ double vkmat[3][3]; /* Von Kries matrix */
+#ifdef NEVER
+ static double bradford[3][3] = { /* Linear cone space matrix */
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+#endif /* NEVER */
+ static double bradford[3][3] = { /* Bradford cone space matrix */
+ { 0.8951, 0.2664, -0.1614 },
+ { -0.7502, 1.7135, 0.0367 },
+ { 0.0389, -0.0685, 1.0296 }
+ };
+ static int inited = 0; /* Compute inverse bradford once */
+ static double ibradford[3][3]; /* Inverse Bradford */
+
+ /* Set initial matrix to unity */
+ if (!(flags & ICM_CAM_MULMATRIX)) {
+ icmSetUnity3x3(mat);
+ }
+
+ icmXYZ2Ary(src, s_wp);
+ icmXYZ2Ary(dst, d_wp);
+
+ if (flags & ICM_CAM_BRADFORD) {
+ icmMulBy3x3(src, bradford, src);
+ icmMulBy3x3(dst, bradford, dst);
+ }
+
+ /* Setup the Von Kries white point adaptation matrix */
+ vkmat[0][0] = dst[0]/src[0];
+ vkmat[1][1] = dst[1]/src[1];
+ vkmat[2][2] = dst[2]/src[2];
+ vkmat[0][1] = vkmat[0][2] = 0.0;
+ vkmat[1][0] = vkmat[1][2] = 0.0;
+ vkmat[2][0] = vkmat[2][1] = 0.0;
+
+ /* Transform to Bradford space if requested */
+ if (flags & ICM_CAM_BRADFORD) {
+ icmMul3x3(mat, bradford);
+ }
+
+ /* Apply chromatic adaptation */
+ icmMul3x3(mat, vkmat);
+
+ /* Transform from Bradford space */
+ if (flags & ICM_CAM_BRADFORD) {
+ if (inited == 0) {
+ icmInverse3x3(ibradford, bradford);
+ inited = 1;
+ }
+ icmMul3x3(mat, ibradford);
+ }
+
+ /* We're done */
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* RGB primaries device to RGB->XYZ transform matrix. */
+/* We assume that the device is perfectly additive, but that */
+/* there may be a scale factor applied to the channels to */
+/* match the white point at RGB = 1. */
+
+/* Return non-zero if matrix would be singular */
+int icmRGBprim2matrix(
+ icmXYZNumber white, /* White point */
+ icmXYZNumber red, /* Red colorant */
+ icmXYZNumber green, /* Green colorant */
+ icmXYZNumber blue, /* Blue colorant */
+ double mat[3][3] /* Destination matrix */
+) {
+ double tmat[3][3];
+ double t[3];
+
+ /* Assemble the colorants into a matrix */
+ tmat[0][0] = red.X;
+ tmat[0][1] = green.X;
+ tmat[0][2] = blue.X;
+ tmat[1][0] = red.Y;
+ tmat[1][1] = green.Y;
+ tmat[1][2] = blue.Y;
+ tmat[2][0] = red.Z;
+ tmat[2][1] = green.Z;
+ tmat[2][2] = blue.Z;
+
+ /* Compute the inverse */
+ if (icmInverse3x3(mat, tmat))
+ return 1;
+
+ /* Compute scale vector that maps colorants to white point */
+ t[0] = mat[0][0] * white.X
+ + mat[0][1] * white.Y
+ + mat[0][2] * white.Z;
+ t[1] = mat[1][0] * white.X
+ + mat[1][1] * white.Y
+ + mat[1][2] * white.Z;
+ t[2] = mat[2][0] * white.X
+ + mat[2][1] * white.Y
+ + mat[2][2] * white.Z;
+
+ /* Now formulate the transform matrix */
+ mat[0][0] = red.X * t[0];
+ mat[0][1] = green.X * t[1];
+ mat[0][2] = blue.X * t[2];
+ mat[1][0] = red.Y * t[0];
+ mat[1][1] = green.Y * t[1];
+ mat[1][2] = blue.Y * t[2];
+ mat[2][0] = red.Z * t[0];
+ mat[2][1] = green.Z * t[1];
+ mat[2][2] = blue.Z * t[2];
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Some PCS utility functions */
+
+/* Clip Lab, while maintaining hue angle. */
+/* Return nz if clipping occured */
+int icmClipLab(double out[3], double in[3]) {
+ double C;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+
+ if (out[0] >= 0.0 && out[0] <= 100.0
+ && out[1] >= -128.0 && out[1] <= 127.0
+ && out[2] >= -128.0 && out[2] <= 127.0)
+ return 0;
+
+ /* Clip L */
+ if (out[0] < 0.0)
+ out[0] = 0.0;
+ else if (out[0] > 100.0)
+ out[0] = 100.0;
+
+ C = out[1];
+ if (fabs(out[2]) > fabs(C))
+ C = out[2];
+ if (C < -128.0 || C > 127.0) {
+ if (C < 0.0)
+ C = -128.0/C;
+ else
+ C = 127.0/C;
+ out[1] *= C;
+ out[2] *= C;
+ }
+
+ return 1;
+}
+
+/* Clip XYZ, while maintaining hue angle */
+/* Return nz if clipping occured */
+int icmClipXYZ(double out[3], double in[3]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+
+ if (out[0] >= 0.0 && out[0] <= 1.9999
+ && out[1] >= 0.0 && out[1] <= 1.9999
+ && out[2] >= 0.0 && out[2] <= 1.9999)
+ return 0;
+
+ /* Clip Y and scale X and Z similarly */
+
+ if (out[1] > 1.9999) {
+ out[0] *= 1.9999/out[1];
+ out[2] *= 1.9999/out[1];
+ out[1] = 1.9999;
+ } else if (out[1] < 0.0) {
+ out[0] = 0.0;
+ out[1] = 0.0;
+ out[2] = 0.0;
+ }
+
+ if (out[0] < 0.0 || out[0] > 1.9999
+ || out[2] < 0.0 || out[2] > 1.9999) {
+ double D50[3] = { 0.9642, 1.0000, 0.8249 };
+ double bb = 0.0;
+
+ /* Scale the D50 so that it has the same Y value as our color */
+ D50[0] *= out[1];
+ D50[1] *= out[1];
+ D50[2] *= out[1];
+
+ /* Figure out what blend factor with Y scaled D50, brings our */
+ /* color X and Z values into range */
+
+ if (out[0] < 0.0) {
+ double b;
+ b = (0.0 - out[0])/(D50[0] - out[0]);
+ if (b > bb)
+ bb = b;
+ } else if (out[0] > 1.9999) {
+ double b;
+ b = (1.9999 - out[0])/(D50[0] - out[0]);
+ if (b > bb)
+ bb = b;
+ }
+ if (out[2] < 0.0) {
+ double b;
+ b = (0.0 - out[2])/(D50[2] - out[2]);
+ if (b > bb)
+ bb = b;
+ } else if (out[2] > 1.9999) {
+ double b;
+ b = (1.9999 - out[2])/(D50[2] - out[2]);
+ if (b > bb)
+ bb = b;
+ }
+ /* Do the desaturation */
+ out[0] = D50[0] * bb + (1.0 - bb) * out[0];
+ out[2] = D50[2] * bb + (1.0 - bb) * out[2];
+ }
+ return 1;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Object for computing RFC 1321 MD5 checksums. */
+/* Derived from Colin Plumb's 1993 public domain code. */
+
+/* Reset the checksum */
+static void icmMD5_reset(icmMD5 *p) {
+ p->tlen = 0;
+
+ p->sum[0] = 0x67452301;
+ p->sum[1] = 0xefcdab89;
+ p->sum[2] = 0x98badcfe;
+ p->sum[3] = 0x10325476;
+
+ p->fin = 0;
+}
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, pp, xtra, s) \
+ data = (pp)[0] + ((pp)[3] << 24) + ((pp)[2] << 16) + ((pp)[1] << 8); \
+ w += f(x, y, z) + data + xtra; \
+ w = (w << s) | (w >> (32-s)); \
+ w += x;
+
+/* Add another 64 bytes to the checksum */
+static void icmMD5_accume(icmMD5 *p, ORD8 *in) {
+ ORD32 data, a, b, c, d;
+
+ a = p->sum[0];
+ b = p->sum[1];
+ c = p->sum[2];
+ d = p->sum[3];
+
+ MD5STEP(F1, a, b, c, d, in + (4 * 0), 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 1), 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 2), 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 3), 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 4), 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 5), 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 6), 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 7), 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 8), 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 9), 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 10), 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 11), 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in + (4 * 12), 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in + (4 * 13), 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in + (4 * 14), 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in + (4 * 15), 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in + (4 * 1), 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 6), 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 11), 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 0), 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 5), 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 10), 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 15), 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 4), 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 9), 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 14), 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 3), 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 8), 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in + (4 * 13), 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in + (4 * 2), 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in + (4 * 7), 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in + (4 * 12), 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in + (4 * 5), 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 8), 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 11), 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 14), 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 1), 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 4), 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 7), 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 10), 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 13), 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 0), 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 3), 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 6), 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in + (4 * 9), 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in + (4 * 12), 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in + (4 * 15), 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in + (4 * 2), 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in + (4 * 0), 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 7), 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 14), 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 5), 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 12), 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 3), 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 10), 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 1), 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 8), 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 15), 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 6), 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 13), 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in + (4 * 4), 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in + (4 * 11), 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in + (4 * 2), 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in + (4 * 9), 0xeb86d391, 21);
+
+ p->sum[0] += a;
+ p->sum[1] += b;
+ p->sum[2] += c;
+ p->sum[3] += d;
+}
+
+#undef F1
+#undef F2
+#undef F3
+#undef F4
+#undef MD5STEP
+
+/* Add some bytes */
+static void icmMD5_add(icmMD5 *p, ORD8 *ibuf, unsigned int len) {
+ unsigned int bs;
+
+ if (p->fin)
+ return; /* This is actually an error */
+
+ bs = p->tlen; /* Current bytes added */
+ p->tlen = bs + len; /* Update length after adding this buffer */
+ bs &= 0x3f; /* Bytes already in buffer */
+
+ /* Deal with any existing partial bytes in p->buf */
+ if (bs) {
+ ORD8 *np = (ORD8 *)p->buf + bs; /* Next free location in partial buffer */
+
+ bs = 64 - bs; /* Free space in partial buffer */
+
+ if (len < bs) { /* Not enought new to make a full buffer */
+ memmove(np, ibuf, len);
+ return;
+ }
+
+ memmove(np, ibuf, bs); /* Now got one full buffer */
+ icmMD5_accume(p, np);
+ ibuf += bs;
+ len -= bs;
+ }
+
+ /* Deal with input data 64 bytes at a time */
+ while (len >= 64) {
+ icmMD5_accume(p, ibuf);
+ ibuf += 64;
+ len -= 64;
+ }
+
+ /* Deal with any remaining bytes */
+ memmove(p->buf, ibuf, len);
+}
+
+/* Finalise the checksum and return the result. */
+static void icmMD5_get(icmMD5 *p, ORD8 chsum[16]) {
+ int i;
+ unsigned count;
+ ORD32 bits1, bits0;
+ ORD8 *pp;
+
+ if (p->fin == 0) {
+
+ /* Compute number of bytes processed mod 64 */
+ count = p->tlen & 0x3f;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ pp = p->buf + count;
+ *pp++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64, allowing 8 bytes for length in bits. */
+ if (count < 8) { /* Not enough space for padding and length */
+
+ memset(pp, 0, count);
+ icmMD5_accume(p, p->buf);
+
+ /* Now fill the next block with 56 bytes */
+ memset(p->buf, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(pp, 0, count - 8);
+ }
+
+ /* Compute number of bits */
+ bits1 = 0x7 & (p->tlen >> (32 - 3));
+ bits0 = p->tlen << 3;
+
+ /* Append number of bits */
+ p->buf[64 - 8] = bits0 & 0xff;
+ p->buf[64 - 7] = (bits0 >> 8) & 0xff;
+ p->buf[64 - 6] = (bits0 >> 16) & 0xff;
+ p->buf[64 - 5] = (bits0 >> 24) & 0xff;
+ p->buf[64 - 4] = bits1 & 0xff;
+ p->buf[64 - 3] = (bits1 >> 8) & 0xff;
+ p->buf[64 - 2] = (bits1 >> 16) & 0xff;
+ p->buf[64 - 1] = (bits1 >> 24) & 0xff;
+
+ icmMD5_accume(p, p->buf);
+
+ p->fin = 1;
+ }
+
+ /* Return the result, lsb to msb */
+ pp = chsum;
+ for (i = 0; i < 4; i++) {
+ *pp++ = p->sum[i] & 0xff;
+ *pp++ = (p->sum[i] >> 8) & 0xff;
+ *pp++ = (p->sum[i] >> 16) & 0xff;
+ *pp++ = (p->sum[i] >> 24) & 0xff;
+ }
+}
+
+
+/* Delete the instance */
+static void icmMD5_del(icmMD5 *p) {
+ p->al->free(p->al, p);
+}
+
+/* Create a new MD5 checksumming object, with a reset checksum value */
+/* Return it or NULL if there is an error */
+icmMD5 *new_icmMD5(icmAlloc *al) {
+ icmMD5 *p;
+
+ if ((p = (icmMD5 *)al->calloc(al,1,sizeof(icmMD5))) == NULL)
+ return NULL;
+
+ p->al = al;
+ p->reset = icmMD5_reset;
+ p->add = icmMD5_add;
+ p->get = icmMD5_get;
+ p->del = icmMD5_del;
+
+ p->reset(p);
+
+ return p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Dumy icmFile used to compute MD5 checksum on write */
+
+/* Get the size of the file (Only valid for reading file. */
+static size_t icmFileMD5_get_size(icmFile *pp) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+
+ return p->size;
+}
+
+/* Set current position to offset. Return 0 on success, nz on failure. */
+/* Seek can't be supported for MD5, so and seek must be to current location. */
+static int icmFileMD5_seek(
+icmFile *pp,
+unsigned int offset
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+
+ if (p->of != offset) {
+ p->errc = 1;
+ }
+ if (p->of > p->size)
+ p->size = p->of;
+ return 0;
+}
+
+/* Read count items of size length. Return number of items successfully read. */
+/* Read is not implemented */
+static size_t icmFileMD5_read(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ return 0;
+}
+
+/* write count items of size length. Return number of items successfully written. */
+/* Simply pass to MD5 to compute checksum */
+static size_t icmFileMD5_write(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+ size_t len = size * count;
+
+ p->md5->add(p->md5, (ORD8 *)buffer, len);
+ p->of += len;
+ if (p->of > p->size)
+ p->size = p->of;
+ return count;
+}
+
+/* do a printf */
+/* Not implemented */
+static int icmFileMD5_printf(
+icmFile *pp,
+const char *format,
+...
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+ p->errc = 2;
+ return 0;
+}
+
+/* flush all write data out to secondary storage. Return nz on failure. */
+static int icmFileMD5_flush(
+icmFile *pp
+) {
+ return 0;
+}
+
+/* we're done with the file object, return nz on failure */
+static int icmFileMD5_delete(
+icmFile *pp
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+
+ p->al->free(p->al, p); /* Free object */
+ return 0;
+}
+
+/* Return the error code. Error code will usually be set */
+/* if we did a seek to other than the current location, */
+/* or did a printf. */
+static int icmFileMD5_geterrc(
+icmFile *pp
+) {
+ icmFileMD5 *p = (icmFileMD5 *)pp;
+
+ return p->errc;
+}
+
+/* Create a checksum dump file access class with allocator */
+icmFile *new_icmFileMD5_a(
+icmMD5 *md5, /* MD5 object to use */
+icmAlloc *al /* heap allocator */
+) {
+ icmFileMD5 *p;
+
+ if ((p = (icmFileMD5 *) al->calloc(al, 1, sizeof(icmFileMD5))) == NULL) {
+ return NULL;
+ }
+ p->md5 = md5; /* MD5 compute object */
+ p->al = al; /* Heap allocator */
+ p->get_size = icmFileMD5_get_size;
+ p->seek = icmFileMD5_seek;
+ p->read = icmFileMD5_read;
+ p->write = icmFileMD5_write;
+ p->gprintf = icmFileMD5_printf;
+ p->flush = icmFileMD5_flush;
+ p->del = icmFileMD5_delete;
+ p->get_errc = icmFileMD5_geterrc;
+
+ p->of = 0;
+ p->errc = 0;
+
+ return (icmFile *)p;
+}
+
+
+/* ============================================= */
+/* Implementation of color transform lookups. */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Methods common to all transforms (icmLuBase) : */
+
+/* Return information about the native lut in/out/pcs colorspaces. */
+/* Any pointer may be NULL if value is not to be returned */
+static void
+icmLutSpaces(
+ struct _icmLuBase *p, /* This */
+ icColorSpaceSignature *ins, /* Return Native input color space */
+ int *inn, /* Return number of input components */
+ icColorSpaceSignature *outs, /* Return Native output color space */
+ int *outn, /* Return number of output components */
+ icColorSpaceSignature *pcs /* Return Native PCS color space */
+ /* (this will be the same as ins or outs */
+ /* depending on the lookup direction) */
+) {
+ if (ins != NULL)
+ *ins = p->inSpace;
+ if (inn != NULL)
+ *inn = (int)number_ColorSpaceSignature(p->inSpace);
+
+ if (outs != NULL)
+ *outs = p->outSpace;
+ if (outn != NULL)
+ *outn = (int)number_ColorSpaceSignature(p->outSpace);
+ if (pcs != NULL)
+ *pcs = p->pcs;
+}
+
+/* Return information about the effective lookup in/out colorspaces, */
+/* including allowance for PCS override. */
+/* Any pointer may be NULL if value is not to be returned */
+static void
+icmLuSpaces(
+ struct _icmLuBase *p, /* This */
+ icColorSpaceSignature *ins, /* Return effective input color space */
+ int *inn, /* Return number of input components */
+ icColorSpaceSignature *outs, /* Return effective output color space */
+ int *outn, /* Return number of output components */
+ icmLuAlgType *alg, /* Return type of lookup algorithm used */
+ icRenderingIntent *intt, /* Return the intent being implented */
+ icmLookupFunc *fnc, /* Return the profile function being implemented */
+ icColorSpaceSignature *pcs, /* Return the profile effective PCS */
+ icmLookupOrder *ord /* return the search Order */
+) {
+ if (ins != NULL)
+ *ins = p->e_inSpace;
+ if (inn != NULL)
+ *inn = (int)number_ColorSpaceSignature(p->e_inSpace);
+
+ if (outs != NULL)
+ *outs = p->e_outSpace;
+ if (outn != NULL)
+ *outn = (int)number_ColorSpaceSignature(p->e_outSpace);
+
+ if (alg != NULL)
+ *alg = p->ttype;
+
+ if (intt != NULL)
+ *intt = p->intent;
+
+ if (fnc != NULL)
+ *fnc = p->function;
+
+ if (pcs != NULL)
+ *pcs = p->e_pcs;
+
+ if (ord != NULL)
+ *ord = p->order;
+}
+
+/* Relative to Absolute for this WP in XYZ */
+static void icmLuXYZ_Rel2Abs(icmLuBase *p, double *out, double *in) {
+ icmMulBy3x3(out, p->toAbs, in);
+}
+
+/* Absolute to Relative for this WP in XYZ */
+static void icmLuXYZ_Abs2Rel(icmLuBase *p, double *out, double *in) {
+ icmMulBy3x3(out, p->fromAbs, in);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Methods common to all non-named transforms (icmLuBase) : */
+
+/* Initialise the LU white and black points from the ICC tags, */
+/* and the corresponding absolute<->relative conversion matrices */
+/* return nz on error */
+static int icmLuInit_Wh_bk(
+struct _icmLuBase *lup
+) {
+ icmXYZArray *whitePointTag, *blackPointTag;
+ icc *p = lup->icp;
+
+ if ((whitePointTag = (icmXYZArray *)p->read_tag(p, icSigMediaWhitePointTag)) == NULL
+ || whitePointTag->ttype != icSigXYZType || whitePointTag->size < 1) {
+ if (p->header->deviceClass != icSigLinkClass
+ && (lup->intent == icAbsoluteColorimetric
+ || lup->intent == icmAbsolutePerceptual
+ || lup->intent == icmAbsoluteSaturation)) {
+ sprintf(p->err,"icc_lookup: Profile is missing Media White Point Tag");
+ p->errc = 1;
+ return 1;
+ }
+ p->err[0] = '\000';
+ p->errc = 0;
+ lup->whitePoint = icmD50; /* safe value */
+ } else
+ lup->whitePoint = whitePointTag->data[0]; /* Copy structure */
+
+ if ((blackPointTag = (icmXYZArray *)p->read_tag(p, icSigMediaBlackPointTag)) == NULL
+ || blackPointTag->ttype != icSigXYZType || blackPointTag->size < 1) {
+ p->err[0] = '\000';
+ p->errc = 0;
+ lup->blackPoint = icmBlack; /* default */
+ lup->blackisassumed = 1; /* We assumed the default */
+ } else {
+ lup->blackPoint = blackPointTag->data[0]; /* Copy structure */
+ lup->blackisassumed = 0; /* The black is from the tag */
+ }
+
+ /* Create absolute <-> relative conversion matricies */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, lup->whitePoint, icmD50, lup->toAbs);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, lup->whitePoint, lup->fromAbs);
+ DBLLL(("toAbs and fromAbs created from wp %f %f %f and D50 %f %f %f\n", lup->whitePoint.X, lup->whitePoint.Y, lup->whitePoint.Z, icmD50.X, icmD50.Y, icmD50.Z));
+ DBLLL(("toAbs = %f %f %f\n %f %f %f\n %f %f %f\n", lup->toAbs[0][0], lup->toAbs[0][1], lup->toAbs[0][2], lup->toAbs[1][0], lup->toAbs[1][1], lup->toAbs[1][2], lup->toAbs[2][0], lup->toAbs[2][1], lup->toAbs[2][2]));
+ DBLLL(("fromAbs = %f %f %f\n %f %f %f\n %f %f %f\n", lup->fromAbs[0][0], lup->fromAbs[0][1], lup->fromAbs[0][2], lup->fromAbs[1][0], lup->fromAbs[1][1], lup->fromAbs[1][2], lup->fromAbs[2][0], lup->fromAbs[2][1], lup->fromAbs[2][2]));
+
+ return 0;
+}
+
+/* Return the media white and black points in absolute XYZ space. */
+/* Note that if not in the icc, the black point will be returned as 0, 0, 0, */
+/* and the function will return nz. */
+/* Any pointer may be NULL if value is not to be returned */
+static int icmLuWh_bk_points(
+struct _icmLuBase *p,
+double *wht,
+double *blk
+) {
+ if (wht != NULL) {
+ icmXYZ2Ary(wht,p->whitePoint);
+ }
+
+ if (blk != NULL) {
+ icmXYZ2Ary(blk,p->blackPoint);
+ }
+ if (p->blackisassumed)
+ return 1;
+ return 0;
+}
+
+/* Get the LU white and black points in LU PCS space, converted to XYZ. */
+/* (ie. white and black will be relative if LU is relative intent etc.) */
+/* Return nz if the black point is being assumed to be 0,0,0 rather */
+/* than being from the tag. */ \
+static int icmLuLu_wh_bk_points(
+struct _icmLuBase *p,
+double *wht,
+double *blk
+) {
+ if (wht != NULL) {
+ icmXYZ2Ary(wht,p->whitePoint);
+ }
+
+ if (blk != NULL) {
+ icmXYZ2Ary(blk,p->blackPoint);
+ }
+ if (p->intent != icAbsoluteColorimetric
+ && p->intent != icmAbsolutePerceptual
+ && p->intent != icmAbsoluteSaturation) {
+ if (wht != NULL)
+ icmMulBy3x3(wht, p->fromAbs, wht);
+ if (blk != NULL)
+ icmMulBy3x3(blk, p->fromAbs, blk);
+ }
+ if (p->blackisassumed)
+ return 1;
+ return 0;
+}
+
+/* Get the native (internal) ranges for the Monochrome or Matrix profile */
+/* Arguments may be NULL */
+static void
+icmLu_get_lutranges (
+ struct _icmLuBase *p,
+ double *inmin, double *inmax, /* Return maximum range of inspace values */
+ double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ icTagTypeSignature tagType;
+
+ if (p->ttype == icmLutType) {
+ icmLuLut *pp = (icmLuLut *)p;
+ tagType = pp->lut->ttype;
+ } else {
+ tagType = icMaxEnumType;
+ }
+
+ /* Hmm. we have no way of handling an error from getRange. */
+ /* It shouldn't ever return one unless there is a mismatch between */
+ /* getRange and Lu creation... */
+ getRange(p->icp, p->inSpace, tagType, inmin, inmax);
+ getRange(p->icp, p->outSpace, tagType, outmin, outmax);
+}
+
+/* Get the effective (externally visible) ranges for the all profile types */
+/* Arguments may be NULL */
+static void
+icmLu_get_ranges (
+ struct _icmLuBase *p,
+ double *inmin, double *inmax, /* Return maximum range of inspace values */
+ double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ icTagTypeSignature tagType;
+
+ if (p->ttype == icmLutType) {
+ icmLuLut *pp = (icmLuLut *)p;
+ tagType = pp->lut->ttype;
+ } else {
+ tagType = icMaxEnumType;
+ }
+ /* Hmm. we have no way of handling an error from getRange. */
+ /* It shouldn't ever return one unless there is a mismatch between */
+ /* getRange and Lu creation... */
+ getRange(p->icp, p->e_inSpace, tagType, inmin, inmax);
+ getRange(p->icp, p->e_outSpace, tagType, outmin, outmax);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Forward and Backward Monochrome type methods: */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* Individual components of Fwd conversion: */
+
+/* Actual device to linearised device */
+static int
+icmLuMonoFwd_curve (
+icmLuMono *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+
+ /* Translate from device to PCS scale */
+ if ((rv |= p->grayCurve->lookup_fwd(p->grayCurve,&out[0],&in[0])) > 1) {
+ sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed");
+ icp->errc = rv;
+ return 2;
+ }
+
+ return rv;
+}
+
+/* Linearised device to relative PCS */
+static int
+icmLuMonoFwd_map (
+icmLuMono *p, /* This */
+double *out, /* Vector of output values (native space) */
+double *in /* Vector of input values (native space) */
+) {
+ int rv = 0;
+ double Y = in[0]; /* In case out == in */
+
+ out[0] = p->pcswht.X;
+ out[1] = p->pcswht.Y;
+ out[2] = p->pcswht.Z;
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out); /* in Lab */
+
+ /* Scale linearized device level to PCS white */
+ out[0] *= Y;
+ out[1] *= Y;
+ out[2] *= Y;
+
+ return rv;
+}
+
+/* relative PCS to absolute PCS (if required) */
+static int
+icmLuMonoFwd_abs ( /* Abs comes last in Fwd conversion */
+icmLuMono *p, /* This */
+double *out, /* Vector of output values in Effective PCS */
+double *in /* Vector of input values in Native PCS */
+) {
+ int rv = 0;
+
+ if (out != in) { /* Don't alter input values */
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+
+ /* Do absolute conversion */
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+
+ if (p->pcs == icSigLabData) /* Convert L to Y */
+ icmLab2XYZ(&p->pcswht, out, out);
+
+ /* Convert from Relative to Absolute colorimetric */
+ icmMulBy3x3(out, p->toAbs, out);
+
+ if (p->e_pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+
+ } else {
+
+ /* Convert from Native to Effective output space */
+ if (p->pcs == icSigLabData && p->e_pcs == icSigXYZData)
+ icmLab2XYZ(&p->pcswht, out, out);
+ else if (p->pcs == icSigXYZData && p->e_pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+ }
+
+ return rv;
+}
+
+
+/* Overall Fwd conversion routine (Dev->PCS) */
+static int
+icmLuMonoFwd_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Input value */
+) {
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoFwd_curve(p, out, in);
+ rv |= icmLuMonoFwd_map(p, out, out);
+ rv |= icmLuMonoFwd_abs(p, out, out);
+ return rv;
+}
+
+/* Three stage conversion routines */
+static int
+icmLuMonoFwd_lookup_in(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoFwd_curve(p, out, in);
+ return rv;
+}
+
+static int
+icmLuMonoFwd_lookup_core(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoFwd_map(p, out, in);
+ rv |= icmLuMonoFwd_abs(p, out, out);
+ return rv;
+}
+
+static int
+icmLuMonoFwd_lookup_out(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ return rv;
+}
+
+
+/* - - - - - - - - - - - - - - */
+/* Individual components of Bwd conversion: */
+
+/* Convert from relative PCS to absolute PCS (if required) */
+static int
+icmLuMonoBwd_abs ( /* Abs comes first in Bwd conversion */
+icmLuMono *p, /* This */
+double *out, /* Vector of output values in Native PCS */
+double *in /* Vector of input values in Effective PCS */
+) {
+ int rv = 0;
+
+ if (out != in) { /* Don't alter input values */
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+
+ /* Force to monochrome locus in correct space */
+ if (p->e_pcs == icSigLabData) {
+ double wp[3];
+
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+ wp[0] = p->whitePoint.X;
+ wp[1] = p->whitePoint.Y;
+ wp[2] = p->whitePoint.Z;
+ } else {
+ wp[0] = p->pcswht.X;
+ wp[1] = p->pcswht.Y;
+ wp[2] = p->pcswht.Z;
+ }
+ icmXYZ2Lab(&p->pcswht, wp, wp); /* Convert to Lab white point */
+ out[1] = out[0]/wp[0] * wp[1];
+ out[2] = out[0]/wp[0] * wp[2];
+
+ } else {
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+ out[0] = out[1]/p->whitePoint.Y * p->whitePoint.X;
+ out[2] = out[1]/p->whitePoint.Y * p->whitePoint.Z;
+ } else {
+ out[0] = out[1]/p->pcswht.Y * p->pcswht.X;
+ out[2] = out[1]/p->pcswht.Y * p->pcswht.Z;
+ }
+ }
+
+ /* Do absolute conversion, and conversion to effective PCS */
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+
+ if (p->e_pcs == icSigLabData)
+ icmLab2XYZ(&p->pcswht, out, out);
+
+ icmMulBy3x3(out, p->fromAbs, out);
+
+ /* Convert from Effective to Native input space */
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+
+ } else {
+
+ /* Convert from Effective to Native input space */
+ if (p->e_pcs == icSigLabData && p->pcs == icSigXYZData)
+ icmLab2XYZ(&p->pcswht, out, out);
+ else if (p->e_pcs == icSigXYZData && p->pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+ }
+
+ return rv;
+}
+
+/* Map from relative PCS to linearised device */
+static int
+icmLuMonoBwd_map (
+icmLuMono *p, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values (native space) */
+) {
+ int rv = 0;
+ double pcsw[3];
+
+ pcsw[0] = p->pcswht.X;
+ pcsw[1] = p->pcswht.Y;
+ pcsw[2] = p->pcswht.Z;
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, pcsw, pcsw); /* in Lab (should be 100.0!) */
+
+ /* Divide linearized device level into PCS white luminence */
+ if (p->pcs == icSigLabData)
+ out[0] = in[0]/pcsw[0];
+ else
+ out[0] = in[1]/pcsw[1];
+
+ return rv;
+}
+
+/* Map from linearised device to actual device */
+static int
+icmLuMonoBwd_curve (
+icmLuMono *p, /* This */
+double *out, /* Output value */
+double *in /* Input value */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+
+ /* Convert to device value through curve */
+ if ((rv = p->grayCurve->lookup_bwd(p->grayCurve,&out[0],&in[0])) > 1) {
+ sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed");
+ icp->errc = rv;
+ return 2;
+ }
+
+ return rv;
+}
+
+/* Overall Bwd conversion routine (PCS->Dev) */
+static int
+icmLuMonoBwd_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ double temp[3];
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoBwd_abs(p, temp, in);
+ rv |= icmLuMonoBwd_map(p, out, temp);
+ rv |= icmLuMonoBwd_curve(p, out, out);
+ return rv;
+}
+
+/* Three stage conversion routines */
+static int
+icmLuMonoBwd_lookup_in(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ return rv;
+}
+
+static int
+icmLuMonoBwd_lookup_core(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ double temp[3];
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoBwd_abs(p, temp, in);
+ rv |= icmLuMonoBwd_map(p, out, temp);
+ return rv;
+}
+
+static int
+icmLuMonoBwd_lookup_out(
+icmLuBase *pp, /* This */
+double *out, /* Output value */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMono *p = (icmLuMono *)pp;
+ rv |= icmLuMonoBwd_curve(p, out, in);
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - */
+
+static void
+icmLuMono_delete(
+icmLuBase *p
+) {
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+static icmLuBase *
+new_icmLuMono(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func, /* Functionality requested */
+ int dir /* 0 = fwd, 1 = bwd */
+) {
+ icmLuMono *p;
+
+ if ((p = (icmLuMono *) icp->al->calloc(icp->al,1,sizeof(icmLuMono))) == NULL)
+ return NULL;
+ p->icp = icp;
+ p->del = icmLuMono_delete;
+ p->lutspaces= icmLutSpaces;
+ p->spaces = icmLuSpaces;
+ p->XYZ_Rel2Abs = icmLuXYZ_Rel2Abs;
+ p->XYZ_Abs2Rel = icmLuXYZ_Abs2Rel;
+ p->get_lutranges = icmLu_get_lutranges;
+ p->get_ranges = icmLu_get_ranges;
+ p->init_wh_bk = icmLuInit_Wh_bk;
+ p->wh_bk_points = icmLuWh_bk_points;
+ p->lu_wh_bk_points = icmLuLu_wh_bk_points;
+ p->fwd_lookup = icmLuMonoFwd_lookup;
+ p->fwd_curve = icmLuMonoFwd_curve;
+ p->fwd_map = icmLuMonoFwd_map;
+ p->fwd_abs = icmLuMonoFwd_abs;
+ p->bwd_lookup = icmLuMonoBwd_lookup;
+ p->bwd_abs = icmLuMonoFwd_abs;
+ p->bwd_map = icmLuMonoFwd_map;
+ p->bwd_curve = icmLuMonoFwd_curve;
+ if (dir) {
+ p->ttype = icmMonoBwdType;
+ p->lookup = icmLuMonoBwd_lookup;
+ p->lookup_in = icmLuMonoBwd_lookup_in;
+ p->lookup_core = icmLuMonoBwd_lookup_core;
+ p->lookup_out = icmLuMonoBwd_lookup_out;
+ p->lookup_inv_in = icmLuMonoFwd_lookup_out; /* Opposite of Bwd_lookup_in */
+ } else {
+ p->ttype = icmMonoFwdType;
+ p->lookup = icmLuMonoFwd_lookup;
+ p->lookup_in = icmLuMonoFwd_lookup_in;
+ p->lookup_core = icmLuMonoFwd_lookup_core;
+ p->lookup_out = icmLuMonoFwd_lookup_out;
+ p->lookup_inv_in = icmLuMonoBwd_lookup_out; /* Opposite of Fwd_lookup_in */
+ }
+
+ /* Lookup the white and black points */
+ if (p->init_wh_bk((icmLuBase *)p)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* See if the color spaces are appropriate for the mono type */
+ if (number_ColorSpaceSignature(icp->header->colorSpace) != 1
+ || ( icp->header->pcs != icSigXYZData && icp->header->pcs != icSigLabData)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Find the appropriate tags */
+ if ((p->grayCurve = (icmCurve *)icp->read_tag(icp, icSigGrayTRCTag)) == NULL
+ || p->grayCurve->ttype != icSigCurveType) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ p->pcswht = icp->header->illuminant;
+ p->intent = intent;
+ p->function = func;
+ p->inSpace = inSpace;
+ p->outSpace = outSpace;
+ p->pcs = pcs;
+ p->e_inSpace = e_inSpace;
+ p->e_outSpace = e_outSpace;
+ p->e_pcs = e_pcs;
+
+ return (icmLuBase *)p;
+}
+
+static icmLuBase *
+new_icmLuMonoFwd(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func /* Functionality requested */
+) {
+ return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
+ intent, func, 0);
+}
+
+
+static icmLuBase *
+new_icmLuMonoBwd(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func /* Functionality requested */
+) {
+ return new_icmLuMono(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
+ intent, func, 1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Forward and Backward Matrix type conversion */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* Individual components of Fwd conversion: */
+static int
+icmLuMatrixFwd_curve (
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+
+ /* Curve lookups */
+ if ((rv |= p->redCurve->lookup_fwd( p->redCurve, &out[0],&in[0])) > 1
+ || (rv |= p->greenCurve->lookup_fwd(p->greenCurve,&out[1],&in[1])) > 1
+ || (rv |= p->blueCurve->lookup_fwd( p->blueCurve, &out[2],&in[2])) > 1) {
+ sprintf(icp->err,"icc_lookup: Curve->lookup_fwd() failed");
+ icp->errc = rv;
+ return 2;
+ }
+
+ return rv;
+}
+
+static int
+icmLuMatrixFwd_matrix (
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ double tt[3];
+
+ /* Matrix */
+ tt[0] = p->mx[0][0] * in[0] + p->mx[0][1] * in[1] + p->mx[0][2] * in[2];
+ tt[1] = p->mx[1][0] * in[0] + p->mx[1][1] * in[1] + p->mx[1][2] * in[2];
+ tt[2] = p->mx[2][0] * in[0] + p->mx[2][1] * in[1] + p->mx[2][2] * in[2];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+
+ return rv;
+}
+
+static int
+icmLuMatrixFwd_abs (/* Abs comes last in Fwd conversion */
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+
+ if (out != in) { /* Don't alter input values */
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+
+ /* If required, convert from Relative to Absolute colorimetric */
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+ icmMulBy3x3(out, p->toAbs, out);
+ }
+
+ /* If e_pcs is Lab, then convert XYZ to Lab */
+ if (p->e_pcs == icSigLabData)
+ icmXYZ2Lab(&p->pcswht, out, out);
+
+ return rv;
+}
+
+
+/* Overall Fwd conversion (Dev->PCS)*/
+static int
+icmLuMatrixFwd_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixFwd_curve(p, out, in);
+ rv |= icmLuMatrixFwd_matrix(p, out, out);
+ rv |= icmLuMatrixFwd_abs(p, out, out);
+ return rv;
+}
+
+/* Three stage conversion routines */
+static int
+icmLuMatrixFwd_lookup_in (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixFwd_curve(p, out, in);
+ return rv;
+}
+
+static int
+icmLuMatrixFwd_lookup_core (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixFwd_matrix(p, out, in);
+ rv |= icmLuMatrixFwd_abs(p, out, out);
+ return rv;
+}
+
+static int
+icmLuMatrixFwd_lookup_out (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - */
+/* Individual components of Bwd conversion: */
+
+static int
+icmLuMatrixBwd_abs (/* Abs comes first in Bwd conversion */
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+
+ if (out != in) { /* Don't alter input values */
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+
+ /* If e_pcs is Lab, then convert Lab to XYZ */
+ if (p->e_pcs == icSigLabData)
+ icmLab2XYZ(&p->pcswht, out, out);
+
+ /* If required, convert from Absolute to Relative colorimetric */
+ if (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation) {
+ icmMulBy3x3(out, p->fromAbs, out);
+ }
+
+ return rv;
+}
+
+static int
+icmLuMatrixBwd_matrix (
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ double tt[3];
+
+ tt[0] = in[0];
+ tt[1] = in[1];
+ tt[2] = in[2];
+
+ /* Matrix */
+ out[0] = p->bmx[0][0] * tt[0] + p->bmx[0][1] * tt[1] + p->bmx[0][2] * tt[2];
+ out[1] = p->bmx[1][0] * tt[0] + p->bmx[1][1] * tt[1] + p->bmx[1][2] * tt[2];
+ out[2] = p->bmx[2][0] * tt[0] + p->bmx[2][1] * tt[1] + p->bmx[2][2] * tt[2];
+
+ return rv;
+}
+
+static int
+icmLuMatrixBwd_curve (
+icmLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ icc *icp = p->icp;
+ int rv = 0;
+
+ /* Curves */
+ if ((rv |= p->redCurve->lookup_bwd(p->redCurve,&out[0],&in[0])) > 1
+ || (rv |= p->greenCurve->lookup_bwd(p->greenCurve,&out[1],&in[1])) > 1
+ || (rv |= p->blueCurve->lookup_bwd(p->blueCurve,&out[2],&in[2])) > 1) {
+ sprintf(icp->err,"icc_lookup: Curve->lookup_bwd() failed");
+ icp->errc = rv;
+ return 2;
+ }
+ return rv;
+}
+
+/* Overall Bwd conversion (PCS->Dev) */
+static int
+icmLuMatrixBwd_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixBwd_abs(p, out, in);
+ rv |= icmLuMatrixBwd_matrix(p, out, out);
+ rv |= icmLuMatrixBwd_curve(p, out, out);
+ return rv;
+}
+
+/* Three stage conversion routines */
+static int
+icmLuMatrixBwd_lookup_in (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ return rv;
+}
+
+static int
+icmLuMatrixBwd_lookup_core (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixBwd_abs(p, out, in);
+ rv |= icmLuMatrixBwd_matrix(p, out, out);
+ return rv;
+}
+
+static int
+icmLuMatrixBwd_lookup_out (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuMatrix *p = (icmLuMatrix *)pp;
+ rv |= icmLuMatrixBwd_curve(p, out, in);
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - */
+
+static void
+icmLuMatrix_delete(
+icmLuBase *p
+) {
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+/* We setup valid fwd and bwd component conversions, */
+/* but setup only the asked for overal conversion. */
+static icmLuBase *
+new_icmLuMatrix(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func, /* Functionality requested */
+ int dir /* 0 = fwd, 1 = bwd */
+) {
+ icmLuMatrix *p;
+
+ if ((p = (icmLuMatrix *) icp->al->calloc(icp->al,1,sizeof(icmLuMatrix))) == NULL)
+ return NULL;
+ p->icp = icp;
+ p->del = icmLuMatrix_delete;
+ p->lutspaces= icmLutSpaces;
+ p->spaces = icmLuSpaces;
+ p->XYZ_Rel2Abs = icmLuXYZ_Rel2Abs;
+ p->XYZ_Abs2Rel = icmLuXYZ_Abs2Rel;
+ p->get_lutranges = icmLu_get_lutranges;
+ p->get_ranges = icmLu_get_ranges;
+ p->init_wh_bk = icmLuInit_Wh_bk;
+ p->wh_bk_points = icmLuWh_bk_points;
+ p->lu_wh_bk_points = icmLuLu_wh_bk_points;
+ p->fwd_lookup = icmLuMatrixFwd_lookup;
+ p->fwd_curve = icmLuMatrixFwd_curve;
+ p->fwd_matrix = icmLuMatrixFwd_matrix;
+ p->fwd_abs = icmLuMatrixFwd_abs;
+ p->bwd_lookup = icmLuMatrixBwd_lookup;
+ p->bwd_abs = icmLuMatrixBwd_abs;
+ p->bwd_matrix = icmLuMatrixBwd_matrix;
+ p->bwd_curve = icmLuMatrixBwd_curve;
+ if (dir) {
+ p->ttype = icmMatrixBwdType;
+ p->lookup = icmLuMatrixBwd_lookup;
+ p->lookup_in = icmLuMatrixBwd_lookup_in;
+ p->lookup_core = icmLuMatrixBwd_lookup_core;
+ p->lookup_out = icmLuMatrixBwd_lookup_out;
+ p->lookup_inv_in = icmLuMatrixFwd_lookup_out; /* Opposite of Bwd_lookup_in */
+ } else {
+ p->ttype = icmMatrixFwdType;
+ p->lookup = icmLuMatrixFwd_lookup;
+ p->lookup_in = icmLuMatrixFwd_lookup_in;
+ p->lookup_core = icmLuMatrixFwd_lookup_core;
+ p->lookup_out = icmLuMatrixFwd_lookup_out;
+ p->lookup_inv_in = icmLuMatrixBwd_lookup_out; /* Opposite of Fwd_lookup_in */
+ }
+
+ /* Lookup the white and black points */
+ if (p->init_wh_bk((icmLuBase *)p)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Note that we can use matrix type even if PCS is Lab, */
+ /* by simply converting it. */
+
+ /* Find the appropriate tags */
+ if ((p->redCurve = (icmCurve *)icp->read_tag(icp, icSigRedTRCTag)) == NULL
+ || p->redCurve->ttype != icSigCurveType
+ || (p->greenCurve = (icmCurve *)icp->read_tag(icp, icSigGreenTRCTag)) == NULL
+ || p->greenCurve->ttype != icSigCurveType
+ || (p->blueCurve = (icmCurve *)icp->read_tag(icp, icSigBlueTRCTag)) == NULL
+ || p->blueCurve->ttype != icSigCurveType
+ || (p->redColrnt = (icmXYZArray *)icp->read_tag(icp, icSigRedColorantTag)) == NULL
+ || p->redColrnt->ttype != icSigXYZType || p->redColrnt->size < 1
+ || (p->greenColrnt = (icmXYZArray *)icp->read_tag(icp, icSigGreenColorantTag)) == NULL
+ || p->greenColrnt->ttype != icSigXYZType || p->greenColrnt->size < 1
+ || (p->blueColrnt = (icmXYZArray *)icp->read_tag(icp, icSigBlueColorantTag)) == NULL
+ || p->blueColrnt->ttype != icSigXYZType || p->blueColrnt->size < 1) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Setup the matrix */
+ p->mx[0][0] = p->redColrnt->data[0].X;
+ p->mx[0][1] = p->greenColrnt->data[0].X;
+ p->mx[0][2] = p->blueColrnt->data[0].X;
+ p->mx[1][1] = p->greenColrnt->data[0].Y;
+ p->mx[1][0] = p->redColrnt->data[0].Y;
+ p->mx[1][2] = p->blueColrnt->data[0].Y;
+ p->mx[2][1] = p->greenColrnt->data[0].Z;
+ p->mx[2][0] = p->redColrnt->data[0].Z;
+ p->mx[2][2] = p->blueColrnt->data[0].Z;
+
+#ifndef ICM_STRICT
+ /* Workaround for buggy Kodak RGB profiles. Their matrix values */
+ /* may be scaled to 100 rather than 1.0, and the colorant curves */
+ /* may be scaled by 0.5 */
+ if (icp->header->cmmId == str2tag("KCMS")) {
+ int i, j, oc = 0;
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ if (p->mx[i][j] > 5.0)
+ oc++;
+ if (oc > 4) { /* Looks like it */
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ p->mx[i][j] /= 100.0;
+ }
+ }
+#endif /* ICM_STRICT */
+
+ if (icmInverse3x3(p->bmx, p->mx) != 0) { /* Compute inverse */
+ sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable");
+ icp->errc = 2;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ p->pcswht = icp->header->illuminant;
+ p->intent = intent;
+ p->function = func;
+ p->inSpace = inSpace;
+ p->outSpace = outSpace;
+ p->pcs = pcs;
+ p->e_inSpace = e_inSpace;
+ p->e_outSpace = e_outSpace;
+ p->e_pcs = e_pcs;
+
+ /* Lookup the white and black points */
+ if (p->init_wh_bk((icmLuBase *)p)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ return (icmLuBase *)p;
+}
+
+static icmLuBase *
+new_icmLuMatrixFwd(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func /* Functionality requested */
+) {
+ return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
+ intent, func, 0);
+}
+
+
+static icmLuBase *
+new_icmLuMatrixBwd(
+ struct _icc *icp,
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent */
+ icmLookupFunc func /* Functionality requested */
+) {
+ return new_icmLuMatrix(icp, inSpace, outSpace, pcs, e_inSpace, e_outSpace, e_pcs,
+ intent, func, 1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Forward and Backward Multi-Dimensional Interpolation type conversion */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* Components of overall lookup, in order */
+static int icmLuLut_in_abs(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ DBLLL(("icm in_abs: input %s\n",icmPdv(lut->inputChan, in)));
+ if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */
+ out[i] = in[i];
+ }
+
+ /* If Bwd Lut, take care of Absolute color space and effective input space */
+ if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation)) {
+
+ if (p->e_inSpace == icSigLabData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm in_abs: after Lab2XYZ %s\n",icmPdv(lut->inputChan, out)));
+ }
+
+ /* Convert from Absolute to Relative colorimetric */
+ icmMulBy3x3(out, p->fromAbs, out);
+ DBLLL(("icm in_abs: after fromAbs %s\n",icmPdv(lut->inputChan, out)));
+
+ if (p->inSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm in_abs: after XYZ2Lab %s\n",icmPdv(lut->inputChan, out)));
+ }
+
+ } else {
+
+ /* Convert from Effective to Native input space */
+ if (p->e_inSpace == icSigLabData && p->inSpace == icSigXYZData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm in_abs: after Lab2XYZ %s\n",icmPdv(lut->inputChan, out)));
+ } else if (p->e_inSpace == icSigXYZData && p->inSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm in_abs: after XYZ2Lab %s\n",icmPdv(lut->inputChan, out)));
+ }
+ }
+ DBLLL(("icm in_abs: returning %s\n",icmPdv(lut->inputChan, out)));
+
+ return rv;
+}
+
+/* Possible matrix lookup */
+static int icmLuLut_matrix(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ if (p->usematrix)
+ rv |= lut->lookup_matrix(lut,out,in);
+ else if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++)
+ out[i] = in[i];
+ }
+ return rv;
+}
+
+/* Do input -> input' lookup */
+static int icmLuLut_input(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ p->in_normf(out, in); /* Normalize from input color space */
+ rv |= lut->lookup_input(lut,out,out); /* Lookup though input tables */
+ p->in_denormf(out,out); /* De-normalize to input color space */
+ return rv;
+}
+
+/* Do input'->output' lookup */
+static int icmLuLut_clut(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ double temp[MAX_CHAN];
+ int rv = 0;
+
+ p->in_normf(temp, in); /* Normalize from input color space */
+ rv |= p->lookup_clut(lut,out,temp); /* Lookup though clut tables */
+ p->out_denormf(out,out); /* De-normalize to output color space */
+ return rv;
+}
+
+/* Do output'->output lookup */
+static int icmLuLut_output(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ p->out_normf(out,in); /* Normalize from output color space */
+ rv |= lut->lookup_output(lut,out,out); /* Lookup though output tables */
+ p->out_denormf(out, out); /* De-normalize to output color space */
+ return rv;
+}
+
+static int icmLuLut_out_abs(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ DBLLL(("icm out_abs: input %s\n",icmPdv(lut->outputChan, in)));
+ if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->outputChan; i++) /* Don't alter input values */
+ out[i] = in[i];
+ }
+
+ /* If Fwd Lut, take care of Absolute color space */
+ /* and convert from native to effective out PCS */
+ if ((p->function == icmFwd || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation)) {
+
+ if (p->outSpace == icSigLabData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm out_abs: after Lab2XYZ %s\n",icmPdv(lut->outputChan, out)));
+ }
+
+ /* Convert from Relative to Absolute colorimetric XYZ */
+ icmMulBy3x3(out, p->toAbs, out);
+ DBLLL(("icm out_abs: after toAbs %s\n",icmPdv(lut->outputChan, out)));
+
+ if (p->e_outSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm out_abs: after XYZ2Lab %s\n",icmPdv(lut->outputChan, out)));
+ }
+ } else {
+
+ /* Convert from Native to Effective output space */
+ if (p->outSpace == icSigLabData && p->e_outSpace == icSigXYZData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm out_abs: after Lab2 %s\n",icmPdv(lut->outputChan, out)));
+ } else if (p->outSpace == icSigXYZData && p->e_outSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm out_abs: after XYZ2Lab %s\n",icmPdv(lut->outputChan, out)));
+ }
+ }
+ DBLLL(("icm out_abs: returning %s\n",icmPdv(lut->outputChan, out)));
+ return rv;
+}
+
+
+/* Overall lookup */
+static int
+icmLuLut_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+ double temp[MAX_CHAN];
+
+ DBGLL(("icmLuLut_lookup: in = %s\n", icmPdv(p->inputChan, in)));
+ rv |= p->in_abs(p,temp,in); /* Possible absolute conversion */
+ DBGLL(("icmLuLut_lookup: in_abs = %s\n", icmPdv(p->inputChan, temp)));
+ if (p->usematrix) {
+ rv |= lut->lookup_matrix(lut,temp,temp);/* If XYZ, multiply by non-unity matrix */
+ DBGLL(("icmLuLut_lookup: matrix = %s\n", icmPdv(p->inputChan, temp)));
+ }
+ p->in_normf(temp, temp); /* Normalize for input color space */
+ DBGLL(("icmLuLut_lookup: norm = %s\n", icmPdv(p->inputChan, temp)));
+ rv |= lut->lookup_input(lut,temp,temp); /* Lookup though input tables */
+ DBGLL(("icmLuLut_lookup: input = %s\n", icmPdv(p->inputChan, temp)));
+ rv |= p->lookup_clut(lut,out,temp); /* Lookup though clut tables */
+ DBGLL(("icmLuLut_lookup: clut = %s\n", icmPdv(p->outputChan, out)));
+ rv |= lut->lookup_output(lut,out,out); /* Lookup though output tables */
+ DBGLL(("icmLuLut_lookup: output = %s\n", icmPdv(p->outputChan, out)));
+ p->out_denormf(out,out); /* Normalize for output color space */
+ DBGLL(("icmLuLut_lookup: denorm = %s\n", icmPdv(p->outputChan, out)));
+ rv |= p->out_abs(p,out,out); /* Possible absolute conversion */
+ DBGLL(("icmLuLut_lookup: out_abse = %s\n", icmPdv(p->outputChan, out)));
+
+ return rv;
+}
+
+#ifdef NEVER /* The following should be identical in effect to the above. */
+
+/* Overall lookup */
+static int
+icmLuLut_lookup (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int i, rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+ double temp[MAX_CHAN];
+
+ rv |= p->in_abs(p,temp,in);
+ rv |= p->matrix(p,temp,temp);
+ rv |= p->input(p,temp,temp);
+ rv |= p->clut(p,out,temp);
+ rv |= p->output(p,out,out);
+ rv |= p->out_abs(p,out,out);
+
+ return rv;
+}
+
+#endif /* NEVER */
+
+/* Three stage conversion */
+static int
+icmLuLut_lookup_in (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+
+ /* If in_abs() or matrix() are active, then we can't have a per component input curve */
+ if (((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->e_inSpace != p->inSpace)
+ || (p->usematrix)) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++)
+ out[i] = in[i];
+ } else {
+ rv |= p->input(p,out,in);
+ }
+ return rv;
+}
+
+static int
+icmLuLut_lookup_core (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+
+ /* If in_abs() or matrix() are active, then we have to do the per component input curve here */
+ if (((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->e_inSpace != p->inSpace)
+ || (p->usematrix)) {
+ double temp[MAX_CHAN];
+ rv |= p->in_abs(p,temp,in);
+ rv |= p->matrix(p,temp,temp);
+ rv |= p->input(p,temp,temp);
+ rv |= p->clut(p,out,temp);
+ } else {
+ rv |= p->clut(p,out,in);
+ }
+
+ /* If out_abs() is active, then we can't have do per component out curve here */
+ if (((p->function == icmFwd || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->outSpace != p->e_outSpace)) {
+ rv |= p->output(p,out,out);
+ rv |= p->out_abs(p,out,out);
+ }
+
+ return rv;
+}
+
+static int
+icmLuLut_lookup_out (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+
+ /* If out_abs() is active, then we can't have a per component out curve */
+ if (((p->function == icmFwd || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->outSpace != p->e_outSpace)) {
+ unsigned int i;
+ for (i = 0; i < lut->outputChan; i++)
+ out[i] = in[i];
+ } else {
+ rv |= p->output(p,out,in);
+ }
+
+ return rv;
+}
+
+/* Inverse three stage conversion (partly implemented) */
+static int
+icmLuLut_lookup_inv_in (
+icmLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icmLuLut *p = (icmLuLut *)pp;
+ icmLut *lut = p->lut;
+
+ /* If in_abs() or matrix() are active, then we can't have a per component input curve */
+ if (((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation))
+ || (p->e_inSpace != p->inSpace)
+ || (p->usematrix)) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++)
+ out[i] = in[i];
+ } else {
+ rv |= p->inv_input(p,out,in);
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Some components of inverse lookup, in order */
+/* ~~ should these be in icmLut (like all the fwd transforms)? */
+
+static int icmLuLut_inv_out_abs(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ DBLLL(("icm inv_out_abs: input %s\n",icmPdv(lut->outputChan, in)));
+ if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->outputChan; i++) /* Don't alter input values */
+ out[i] = in[i];
+ }
+
+ /* If Fwd Lut, take care of Absolute color space */
+ /* and convert from effective to native inverse output PCS */
+ /* OutSpace must be PCS: XYZ or Lab */
+ if ((p->function == icmFwd || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation)) {
+
+ if (p->e_outSpace == icSigLabData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm inv_out_abs: after Lab2XYZ %s\n",icmPdv(lut->outputChan, out)));
+ }
+
+ /* Convert from Absolute to Relative colorimetric */
+ icmMulBy3x3(out, p->fromAbs, out);
+ DBLLL(("icm inv_out_abs: after fromAbs %s\n",icmPdv(lut->outputChan, out)));
+
+ if (p->outSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm inv_out_abs: after XYZ2Lab %s\n",icmPdv(lut->outputChan, out)));
+ }
+
+ } else {
+
+ /* Convert from Effective to Native output space */
+ if (p->e_outSpace == icSigLabData && p->outSpace == icSigXYZData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm inv_out_abs: after Lab2XYZ %s\n",icmPdv(lut->outputChan, out)));
+ } else if (p->e_outSpace == icSigXYZData && p->outSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm inv_out_abs: after XYZ2Lab %s\n",icmPdv(lut->outputChan, out)));
+ }
+ }
+ return rv;
+}
+
+/* Do output->output' inverse lookup */
+static int icmLuLut_inv_output(icmLuLut *p, double *out, double *in) {
+ icc *icp = p->icp;
+ icmLut *lut = p->lut;
+ int i;
+ int rv = 0;
+
+ if (lut->rot[0].inited == 0) {
+ for (i = 0; i < lut->outputChan; i++) {
+ rv = icmTable_setup_bwd(icp, &lut->rot[i], lut->outputEnt,
+ lut->outputTable + i * lut->outputEnt);
+ if (rv != 0) {
+ sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init.");
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ p->out_normf(out,in); /* Normalize from output color space */
+ for (i = 0; i < lut->outputChan; i++) {
+ /* Reverse lookup though output tables */
+ rv |= icmTable_lookup_bwd(&lut->rot[i], &out[i], &out[i]);
+ }
+ p->out_denormf(out, out); /* De-normalize to output color space */
+ return rv;
+}
+
+/* No output' -> input inverse lookup. */
+/* This is non-trivial ! */
+
+/* Do input' -> input inverse lookup */
+static int icmLuLut_inv_input(icmLuLut *p, double *out, double *in) {
+ icc *icp = p->icp;
+ icmLut *lut = p->lut;
+ int i;
+ int rv = 0;
+
+ if (lut->rit[0].inited == 0) {
+ for (i = 0; i < lut->inputChan; i++) {
+ rv = icmTable_setup_bwd(icp, &lut->rit[i], lut->inputEnt,
+ lut->inputTable + i * lut->inputEnt);
+ if (rv != 0) {
+ sprintf(icp->err,"icc_Lut_inv_input: Malloc failure in inverse lookup init.");
+ return icp->errc = rv;
+ }
+ }
+ }
+
+ p->in_normf(out, in); /* Normalize from input color space */
+ for (i = 0; i < lut->inputChan; i++) {
+ /* Reverse lookup though input tables */
+ rv |= icmTable_lookup_bwd(&lut->rit[i], &out[i], &out[i]);
+ }
+ p->in_denormf(out,out); /* De-normalize to input color space */
+ return rv;
+}
+
+/* Possible inverse matrix lookup */
+static int icmLuLut_inv_matrix(icmLuLut *p, double *out, double *in) {
+ icc *icp = p->icp;
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ if (p->usematrix) {
+ double tt[3];
+ if (p->imx_valid == 0) {
+ if (icmInverse3x3(p->imx, lut->e) != 0) { /* Compute inverse */
+ sprintf(icp->err,"icc_new_iccLuMatrix: Matrix wasn't invertable");
+ icp->errc = 2;
+ return 2;
+ }
+ p->imx_valid = 1;
+ }
+ /* Matrix multiply */
+ tt[0] = p->imx[0][0] * in[0] + p->imx[0][1] * in[1] + p->imx[0][2] * in[2];
+ tt[1] = p->imx[1][0] * in[0] + p->imx[1][1] * in[1] + p->imx[1][2] * in[2];
+ tt[2] = p->imx[2][0] * in[0] + p->imx[2][1] * in[1] + p->imx[2][2] * in[2];
+ out[0] = tt[0], out[1] = tt[1], out[2] = tt[2];
+ } else if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++)
+ out[i] = in[i];
+ }
+ return rv;
+}
+
+static int icmLuLut_inv_in_abs(icmLuLut *p, double *out, double *in) {
+ icmLut *lut = p->lut;
+ int rv = 0;
+
+ DBLLL(("icm inv_in_abs: input %s\n",icmPdv(lut->inputChan, in)));
+ if (out != in) {
+ unsigned int i;
+ for (i = 0; i < lut->inputChan; i++) /* Don't alter input values */
+ out[i] = in[i];
+ }
+
+ /* If Bwd Lut, take care of Absolute color space, and */
+ /* convert from native to effective input space */
+ if ((p->function == icmBwd || p->function == icmGamut || p->function == icmPreview)
+ && (p->intent == icAbsoluteColorimetric
+ || p->intent == icmAbsolutePerceptual
+ || p->intent == icmAbsoluteSaturation)) {
+
+ if (p->inSpace == icSigLabData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm inv_in_abs: after Lab2XYZ %s\n",icmPdv(lut->inputChan, out)));
+ }
+
+ /* Convert from Relative to Absolute colorimetric XYZ */
+ icmMulBy3x3(out, p->toAbs, out);
+ DBLLL(("icm inv_in_abs: after toAbs %s\n",icmPdv(lut->inputChan, out)));
+
+ if (p->e_inSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm inv_in_abs: after XYZ2Lab %s\n",icmPdv(lut->inputChan, out)));
+ }
+ } else {
+
+ /* Convert from Native to Effective input space */
+ if (p->inSpace == icSigLabData && p->e_inSpace == icSigXYZData) {
+ icmLab2XYZ(&p->pcswht, out, out);
+ DBLLL(("icm inv_in_abs: after Lab2XYZ %s\n",icmPdv(lut->inputChan, out)));
+ } else if (p->inSpace == icSigXYZData && p->e_inSpace == icSigLabData) {
+ icmXYZ2Lab(&p->pcswht, out, out);
+ DBLLL(("icm inv_in_abs: after XYZ2Lab %s\n",icmPdv(lut->inputChan, out)));
+ }
+ }
+ DBLLL(("icm inv_in_abs: returning %s\n",icmPdv(lut->inputChan, out)));
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return LuLut information */
+static void icmLuLut_get_info(
+ icmLuLut *p, /* this */
+ icmLut **lutp, /* Pointer to icc lut type */
+ icmXYZNumber *pcswhtp, /* Pointer to profile PCS white point */
+ icmXYZNumber *whitep, /* Pointer to profile absolute white point */
+ icmXYZNumber *blackp /* Pointer to profile absolute black point */
+) {
+ if (lutp != NULL)
+ *lutp = p->lut;
+ if (pcswhtp != NULL)
+ *pcswhtp = p->pcswht;
+ if (whitep != NULL)
+ *whitep = p->whitePoint;
+ if (blackp != NULL)
+ *blackp = p->blackPoint;
+}
+
+/* Get the native ranges for the LuLut */
+/* This is computed differently to the mono & matrix types, to */
+/* accurately take into account the different range for 8 bit Lab */
+/* lut type. The range returned for the effective PCS is not so accurate. */
+static void
+icmLuLut_get_lutranges (
+ struct _icmLuBase *pp,
+ double *inmin, double *inmax, /* Return maximum range of inspace values */
+ double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ icmLuLut *p = (icmLuLut *)pp;
+ unsigned int i;
+
+ for (i = 0; i < p->lut->inputChan; i++) {
+ inmin[i] = 0.0; /* Normalized range of input space values */
+ inmax[i] = 1.0;
+ }
+ p->in_denormf(inmin,inmin); /* Convert to real colorspace range */
+ p->in_denormf(inmax,inmax);
+
+ /* Make sure min and max are so. */
+ for (i = 0; i < p->lut->inputChan; i++) {
+ if (inmin[i] > inmax[i]) {
+ double tt;
+ tt = inmin[i];
+ inmin[i] = inmax[i];
+ inmax[i] = tt;
+ }
+ }
+
+ for (i = 0; i < p->lut->outputChan; i++) {
+ outmin[i] = 0.0; /* Normalized range of output space values */
+ outmax[i] = 1.0;
+ }
+ p->out_denormf(outmin,outmin); /* Convert to real colorspace range */
+ p->out_denormf(outmax,outmax);
+
+ /* Make sure min and max are so. */
+ for (i = 0; i < p->lut->outputChan; i++) {
+ if (outmin[i] > outmax[i]) {
+ double tt;
+ tt = outmin[i];
+ outmin[i] = outmax[i];
+ outmax[i] = tt;
+ }
+ }
+}
+
+/* Get the effective (externaly visible) ranges for the LuLut */
+/* This will be accurate if there is no override, but only */
+/* aproximate if a PCS override is in place. */
+static void
+icmLuLut_get_ranges (
+ struct _icmLuBase *pp,
+ double *inmin, double *inmax, /* Return maximum range of inspace values */
+ double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ icmLuLut *p = (icmLuLut *)pp;
+
+ /* Get the native ranges first */
+ icmLuLut_get_lutranges(pp, inmin, inmax, outmin, outmax);
+
+ /* And replace them if the effective space is different */
+ if (p->e_inSpace != p->inSpace)
+ getRange(p->icp, p->e_inSpace, p->lut->ttype, inmin, inmax);
+
+ if (p->e_outSpace != p->outSpace)
+ getRange(p->icp, p->e_outSpace, p->lut->ttype, outmin, outmax);
+}
+
+/* Return the underlying Lut matrix */
+static void
+icmLuLut_get_matrix (
+ struct _icmLuLut *p,
+ double m[3][3]
+) {
+ int i, j;
+ icmLut *lut = p->lut;
+
+ if (p->usematrix) {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ m[i][j] = lut->e[i][j]; /* Copy from Lut */
+
+ } else { /* return unity matrix */
+ icmSetUnity3x3(m);
+ }
+}
+
+
+static void
+icmLuLut_delete(
+icmLuBase *p
+) {
+ icc *icp = p->icp;
+
+ icp->al->free(icp->al, p);
+}
+
+icmLuBase *
+icc_new_icmLuLut(
+ icc *icp,
+ icTagSignature ttag, /* Target Lut tag */
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS (from header) */
+ icColorSpaceSignature e_inSpace, /* Effective Input color space */
+ icColorSpaceSignature e_outSpace, /* Effective Output color space */
+ icColorSpaceSignature e_pcs, /* Effective PCS */
+ icRenderingIntent intent, /* Rendering intent (For absolute) */
+ icmLookupFunc func /* Functionality requested (for icmLuSpaces()) */
+) {
+ icmLuLut *p;
+
+ if ((p = (icmLuLut *) icp->al->calloc(icp->al,1,sizeof(icmLuLut))) == NULL)
+ return NULL;
+ p->ttype = icmLutType;
+ p->icp = icp;
+ p->del = icmLuLut_delete;
+ p->lutspaces= icmLutSpaces;
+ p->spaces = icmLuSpaces;
+ p->XYZ_Rel2Abs = icmLuXYZ_Rel2Abs;
+ p->XYZ_Abs2Rel = icmLuXYZ_Abs2Rel;
+ p->init_wh_bk = icmLuInit_Wh_bk;
+ p->wh_bk_points = icmLuWh_bk_points;
+ p->lu_wh_bk_points = icmLuLu_wh_bk_points;
+
+ p->lookup = icmLuLut_lookup;
+ p->lookup_in = icmLuLut_lookup_in;
+ p->lookup_core = icmLuLut_lookup_core;
+ p->lookup_out = icmLuLut_lookup_out;
+ p->lookup_inv_in = icmLuLut_lookup_inv_in;
+
+ p->in_abs = icmLuLut_in_abs;
+ p->matrix = icmLuLut_matrix;
+ p->input = icmLuLut_input;
+ p->clut = icmLuLut_clut;
+ p->output = icmLuLut_output;
+ p->out_abs = icmLuLut_out_abs;
+
+ p->inv_in_abs = icmLuLut_inv_in_abs;
+ p->inv_matrix = icmLuLut_inv_matrix;
+ p->inv_input = icmLuLut_inv_input;
+ p->inv_output = icmLuLut_inv_output;
+ p->inv_out_abs = icmLuLut_inv_out_abs;
+
+ p->pcswht = icp->header->illuminant;
+ p->intent = intent; /* used to trigger absolute processing */
+ p->function = func;
+ p->inSpace = inSpace;
+ p->outSpace = outSpace;
+ p->pcs = pcs;
+ p->e_inSpace = e_inSpace;
+ p->e_outSpace = e_outSpace;
+ p->e_pcs = e_pcs;
+ p->get_info = icmLuLut_get_info;
+ p->get_lutranges = icmLuLut_get_lutranges;
+ p->get_ranges = icmLuLut_get_ranges;
+ p->get_matrix = icmLuLut_get_matrix;
+
+ /* Lookup the white and black points */
+ if (p->init_wh_bk((icmLuBase *)p)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Get the Lut tag, & check that it is expected type */
+ if ((p->lut = (icmLut *)icp->read_tag(icp, ttag)) == NULL
+ || (p->lut->ttype != icSigLut8Type && p->lut->ttype != icSigLut16Type)) {
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Check if matrix should be used */
+ if (inSpace == icSigXYZData && p->lut->nu_matrix(p->lut))
+ p->usematrix = 1;
+ else
+ p->usematrix = 0;
+
+ /* Lookup input color space to normalized index function */
+ if (getNormFunc(icp, inSpace, p->lut->ttype, icmToLuti, &p->in_normf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Lookup normalized index to input color space function */
+ if (getNormFunc(icp, inSpace, p->lut->ttype, icmFromLuti, &p->in_denormf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Lookup output color space to normalized Lut entry value function */
+ if (getNormFunc(icp, outSpace, p->lut->ttype, icmToLutv, &p->out_normf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Lookup normalized Lut entry value to output color space function */
+ if (getNormFunc(icp, outSpace, p->lut->ttype, icmFromLutv, &p->out_denormf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Note that the following two are only used in computing the expected */
+ /* value ranges of the effective PCS. This might not be the best way of */
+ /* doing this. */
+ /* Lookup normalized index to effective input color space function */
+ if (getNormFunc(icp, e_inSpace, p->lut->ttype, icmFromLuti, &p->e_in_denormf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+ /* Lookup normalized Lut entry value to effective output color space function */
+ if (getNormFunc(icp, e_outSpace, p->lut->ttype, icmFromLutv, &p->e_out_denormf)) {
+ sprintf(icp->err,"icc_get_luobj: Unknown effective colorspace");
+ icp->errc = 1;
+ p->del((icmLuBase *)p);
+ return NULL;
+ }
+
+// ~~~999
+#ifndef NEVER
+ /* Standard code */
+ /* Determine appropriate clut lookup algorithm */
+ {
+ int use_sx; /* -1 = undecided, 0 = N-linear, 1 = Simplex lookup */
+ icColorSpaceSignature ins, outs; /* In and out Lut color spaces */
+ int inn, outn; /* in and out number of Lut components */
+
+ p->lutspaces((icmLuBase *)p, &ins, &inn, &outs, &outn, NULL);
+
+ /* Determine if the input space is "Device" like, */
+ /* ie. luminance will be expected to vary most strongly */
+ /* with the diagonal change in input coordinates. */
+ switch(ins) {
+
+ /* Luminence is carried by the sum of all the output channels, */
+ /* so output luminence will dominantly be in diagonal direction. */
+ case icSigXYZData: /* This seems to be appropriate ? */
+ case icSigRgbData:
+ case icSigGrayData:
+ case icSigCmykData:
+ case icSigCmyData:
+ case icSigMch6Data:
+ use_sx = 1; /* Simplex interpolation is appropriate */
+ break;
+
+ /* A single channel carries the luminence information */
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigHlsData:
+ case icSigHsvData:
+ use_sx = 0; /* N-linear interpolation is appropriate */
+ break;
+ default:
+ use_sx = -1; /* undecided */
+ break;
+ }
+
+ /* If we couldn't figure it out from the input space, */
+ /* check output luminance variation with a diagonal input */
+ /* change. */
+ if (use_sx == -1) {
+ int lc; /* Luminance channel */
+
+ /* Determine where the luminence is carried in the output */
+ switch(outs) {
+
+ /* Luminence is carried by the sum of all the output channels */
+ case icSigRgbData:
+ case icSigGrayData:
+ case icSigCmykData:
+ case icSigCmyData:
+ case icSigMch6Data:
+ lc = -1; /* Average all channels */
+ break;
+
+ /* A single channel carries the luminence information */
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ lc = 0;
+ break;
+
+ case icSigXYZData:
+ case icSigHlsData:
+ lc = 1;
+ break;
+
+ case icSigHsvData:
+ lc = 2;
+ break;
+
+ /* default means give up and use N-linear type lookup */
+ default:
+ lc = -2;
+ break;
+ }
+
+ /* If we know how luminance is represented in output space */
+ if (lc != -2) {
+ double tout1[MAX_CHAN]; /* Test output values */
+ double tout2[MAX_CHAN];
+ double tt, diag;
+ int n;
+
+ /* Determine input space location of min and max of */
+ /* given output channel (chan = -1 means average of all) */
+ p->lut->min_max(p->lut, tout1, tout2, lc);
+
+ /* Convert to vector and then calculate normalized */
+ /* dot product with diagonal vector (1,1,1...) */
+ for (tt = 0.0, n = 0; n < inn; n++) {
+ tout1[n] = tout2[n] - tout1[n];
+ tt += tout1[n] * tout1[n];
+ }
+ if (tt > 0.0)
+ tt = sqrt(tt); /* normalizing factor for maximum delta */
+ else
+ tt = 1.0; /* Hmm. */
+ tt *= sqrt((double)inn); /* Normalizing factor for diagonal vector */
+ for (diag = 0.0, n = 0; n < outn; n++)
+ diag += tout1[n] / tt;
+ diag = fabs(diag);
+
+ /* I'm not really convinced that this is a reliable */
+ /* indicator of whether simplex interpolation should be used ... */
+ /* It does seem to do the right thing with YCC space though. */
+ if (diag > 0.8) /* Diagonal is dominant ? */
+ use_sx = 1;
+
+ /* If we couldn't figure it out, use N-linear interpolation */
+ if (use_sx == -1)
+ use_sx = 0;
+ }
+ }
+
+ if (use_sx) {
+ p->lookup_clut = p->lut->lookup_clut_sx;
+ } else {
+ p->lookup_clut = p->lut->lookup_clut_nl;
+ }
+ }
+#else /* Development code */
+ /* Determine appropriate clut lookup algorithm, */
+ /* and set optimised simplex tables */
+ {
+ int lualg = 0; /* 0 = simplex, 1 = multi-linear, 2 = optimised simlpex */
+ icColorSpaceSignature ins, outs; /* In and out Lut color spaces */
+ int inn, outn; /* in and out number of Lut components */
+
+ p->lutspaces((icmLuBase *)p, &ins, &inn, &outs, &outn, NULL);
+
+ /* Determine which type of Lut lookup algorithm is likely to give */
+ /* minimal interpolation errors. */
+ /* To use the optimised simplex, we should ideally determine */
+ /* the simplex cell orientation that makes the simplex split diagonal */
+ /* always point towards the white or black points. */
+ switch(ins) {
+
+ case icSigXYZData: /* This seems to be appropriate ? */
+ case icSigRgbData:
+ case icSigGrayData:
+ case icSigCmykData:
+ case icSigCmyData:
+ case icSigMch6Data:
+ lualg = 0; /* Simplex interpolation is appropriate */
+ break;
+
+ case icSigLabData:
+// ~~~~9999 this isn't right! need to lookup Lab 50,0,0 through input curves then */
+/* quantize to clut nodes to figure threshold for axis flips */
+ p->lut->finfo[0].fth = 0.5; p->lut->finfo[0].bthff = 0; p->lut->finfo[0].athff = 1;
+ p->lut->finfo[1].fth = 0.5; p->lut->finfo[1].bthff = 1; p->lut->finfo[1].athff = 0;
+ p->lut->finfo[2].fth = 0.5; p->lut->finfo[2].bthff = 1; p->lut->finfo[2].athff = 0;
+ lualg = 2;
+ break;
+
+ /* !!! Should switch to optimised simplex for these too !!! */
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigHlsData:
+ case icSigHsvData:
+ lualg = 1; /* Multi-linear is best as a default for these ? */
+ break;
+
+ default:
+ lualg = 0; /* Simplex is best if we known nothing. */
+ break;
+ }
+
+ if (lualg == 2) {
+ p->lookup_clut = icmLut_lookup_clut_osx;
+ } else if (lualg == 1) {
+ p->lookup_clut = p->lut->lookup_clut_nl;
+ } else {
+ p->lookup_clut = p->lut->lookup_clut_sx;
+ }
+ }
+#endif
+ return (icmLuBase *)p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return an appropriate lookup object */
+/* Return NULL on error, and detailed error in icc */
+static icmLuBase* icc_get_luobj (
+ icc *p, /* ICC */
+ icmLookupFunc func, /* Conversion functionality */
+ icRenderingIntent intent, /* Rendering intent, including icmAbsoluteColorimetricXYZ */
+ icColorSpaceSignature pcsor,/* PCS override (0 = def) */
+ icmLookupOrder order /* Conversion representation search Order */
+) {
+ icmLuBase *luobj = NULL; /* Lookup object to return */
+ icColorSpaceSignature pcs, e_pcs; /* PCS and effective PCS */
+
+#ifdef ICM_STRICT
+ int rv;
+ /* Check that the profile is legal, since we depend on it ? */
+ if ((rv = check_icc_legal(p)) != 0)
+ return NULL;
+#endif /* ICM_STRICT */
+
+ /* Figure out the native and effective PCS */
+ e_pcs = pcs = p->header->pcs;
+ if (pcsor != icmSigDefaultData)
+ e_pcs = pcsor; /* Override */
+
+ /* How we expect to execute the request depends firstly on the type of profile */
+ switch (p->header->deviceClass) {
+ case icSigInputClass:
+ case icSigDisplayClass:
+ case icSigColorSpaceClass:
+
+ /* Look for Intent based AToBX profile + optional BToAX reverse */
+ /* or for AToB0 based profile + optional BToA0 reverse */
+ /* or three component matrix profile (reversable) */
+ /* or momochrome table profile (reversable) */
+ /* No Lut intent for ICC < V2.4, but possible for >= V2.4, */
+ /* so fall back if we can't find the chosen Lut intent.. */
+ /* Device <-> PCS */
+ /* Determine the algorithm and set its parameters */
+
+ switch (func) {
+ icRenderingIntent fbintent; /* Fallback intent */
+ icTagSignature ttag, fbtag;
+
+ case icmFwd: /* Device to PCS */
+ if (intent == icmDefaultIntent)
+ intent = icPerceptual; /* Make this the default */
+
+ switch (intent) {
+ case icAbsoluteColorimetric:
+ ttag = icSigAToB1Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = intent;
+ break;
+ case icRelativeColorimetric:
+ ttag = icSigAToB1Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icPerceptual:
+ ttag = icSigAToB0Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icSaturation:
+ ttag = icSigAToB2Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ ttag = icSigAToB0Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = intent;
+ break;
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ ttag = icSigAToB2Tag;
+ fbtag = icSigAToB0Tag;
+ fbintent = intent;
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (order != icmLuOrdRev) {
+ /* Try Lut type lookup with the chosen intent first */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try the fallback tag */
+ if ((luobj = icc_new_icmLuLut(p, fbtag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ fbintent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ } else {
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try Lut type lookup last */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try the fallback tag */
+ if ((luobj = icc_new_icmLuLut(p, fbtag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ fbintent, func)) != NULL)
+ break;
+ }
+ break;
+
+ case icmBwd: /* PCS to Device */
+ if (intent == icmDefaultIntent)
+ intent = icPerceptual; /* Make this the default */
+
+ switch (intent) {
+ case icAbsoluteColorimetric:
+ ttag = icSigBToA1Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = intent;
+ break;
+ case icRelativeColorimetric:
+ ttag = icSigBToA1Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icPerceptual:
+ ttag = icSigBToA0Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icSaturation:
+ ttag = icSigBToA2Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = icmDefaultIntent;
+ break;
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ ttag = icSigBToA0Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = intent;
+ break;
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ ttag = icSigBToA2Tag;
+ fbtag = icSigBToA0Tag;
+ fbintent = intent;
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+
+ if (order != icmLuOrdRev) {
+ /* Try Lut type lookup first */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try the fallback Lut */
+ if ((luobj = icc_new_icmLuLut(p, fbtag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ fbintent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+ } else {
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try Lut type lookup last */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try the fallback Lut */
+ if ((luobj = icc_new_icmLuLut(p, fbtag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ fbintent, func)) != NULL)
+ break;
+ }
+ break;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
+ p->errc = 1;
+ return NULL;
+ }
+ break;
+
+ case icSigOutputClass:
+ /* Expect BToA Lut and optional AToB Lut, All intents, expect gamut */
+ /* or momochrome table profile (reversable) */
+ /* Device <-> PCS */
+ /* Gamut Lut - no intent */
+ /* Optional preview links PCS <-> PCS */
+
+ /* Determine the algorithm and set its parameters */
+ switch (func) {
+ icTagSignature ttag;
+
+ case icmFwd: /* Device to PCS */
+
+ if (intent == icmDefaultIntent)
+ intent = icPerceptual; /* Make this the default */
+
+ switch (intent) {
+ case icRelativeColorimetric:
+ case icAbsoluteColorimetric:
+ ttag = icSigAToB1Tag;
+ break;
+ case icPerceptual:
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ ttag = icSigAToB0Tag;
+ break;
+ case icSaturation:
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ ttag = icSigAToB2Tag;
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (order != icmLuOrdRev) {
+ /* Try Lut type lookup first */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL) {
+ break;
+ }
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+ } else {
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixFwd(p,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try Lut type lookup last */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, e_pcs, e_pcs,
+ intent, func)) != NULL)
+ break;
+ }
+ break;
+
+ case icmBwd: /* PCS to Device */
+
+ if (intent == icmDefaultIntent)
+ intent = icPerceptual; /* Make this the default */
+
+ switch (intent) {
+ case icRelativeColorimetric:
+ case icAbsoluteColorimetric:
+ ttag = icSigBToA1Tag;
+ break;
+ case icPerceptual:
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ ttag = icSigBToA0Tag;
+ break;
+ case icSaturation:
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ ttag = icSigBToA2Tag;
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (order != icmLuOrdRev) {
+ /* Try Lut type lookup first */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+ } else {
+ /* See if it could be a monochrome lookup */
+ if ((luobj = new_icmLuMonoBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* See if it could be a matrix lookup */
+ if ((luobj = new_icmLuMatrixBwd(p,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+
+ /* Try Lut type lookup last */
+ if ((luobj = icc_new_icmLuLut(p, ttag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, p->header->colorSpace, e_pcs,
+ intent, func)) != NULL)
+ break;
+ }
+ break;
+
+ case icmGamut: /* PCS to 1D */
+
+#ifdef ICM_STRICT /* Allow only default and absolute */
+ if (intent != icmDefaultIntent
+ && intent != icAbsoluteColorimetric) {
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Gamut table");
+ p->errc = 1;
+ return NULL;
+ }
+#else /* Be more forgiving */
+ switch (intent) {
+ case icAbsoluteColorimetric:
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ break;
+ case icmDefaultIntent:
+ case icRelativeColorimetric:
+ case icPerceptual:
+ case icSaturation:
+ intent = icmDefaultIntent; /* Make all other look like default */
+ break;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent (0x%x)",intent);
+ p->errc = 1;
+ return NULL;
+ }
+
+#endif
+ /* If the target tag exists, and it is a Lut */
+ luobj = icc_new_icmLuLut(p, icSigGamutTag,
+ pcs, icSigGrayData, pcs,
+ e_pcs, icSigGrayData, e_pcs,
+ intent, func);
+ break;
+
+ case icmPreview: /* PCS to PCS */
+
+ switch (intent) {
+ case icRelativeColorimetric:
+ ttag = icSigPreview1Tag;
+ break;
+ case icPerceptual:
+ ttag = icSigPreview0Tag;
+ break;
+ case icSaturation:
+ ttag = icSigPreview2Tag;
+ break;
+ case icAbsoluteColorimetric:
+ case icmAbsolutePerceptual: /* Special icclib intent */
+ case icmAbsoluteSaturation: /* Special icclib intent */
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for preview table");
+ p->errc = 1;
+ return NULL;
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown intent");
+ p->errc = 1;
+ return NULL;
+ }
+
+ /* If the target tag exists, and it is a Lut */
+ luobj = icc_new_icmLuLut(p, ttag,
+ pcs, pcs, pcs,
+ e_pcs, e_pcs, e_pcs,
+ intent, func);
+ break;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
+ p->errc = 1;
+ return NULL;
+ }
+ break;
+
+ case icSigLinkClass:
+ /* Expect AToB0 Lut and optional BToA0 Lut, One intent in header */
+ /* Device <-> Device */
+
+ if (intent != p->header->renderingIntent
+ && intent != icmDefaultIntent) {
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Link profile");
+ p->errc = 1;
+ return NULL;
+ }
+ intent = p->header->renderingIntent;
+
+ /* Determine the algorithm and set its parameters */
+ switch (func) {
+ case icmFwd: /* Device to PCS (== Device) */
+
+ luobj = icc_new_icmLuLut(p, icSigAToB0Tag,
+ p->header->colorSpace, pcs, pcs,
+ p->header->colorSpace, pcs, pcs,
+ intent, func);
+ break;
+
+ case icmBwd: /* PCS (== Device) to Device */
+
+ luobj = icc_new_icmLuLut(p, icSigBToA0Tag,
+ pcs, p->header->colorSpace, pcs,
+ pcs, p->header->colorSpace, pcs,
+ intent, func);
+ break;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
+ p->errc = 1;
+ return NULL;
+ }
+ break;
+
+ case icSigAbstractClass:
+ /* Expect AToB0 Lut and option BToA0 Lut, with either relative or absolute intent. */
+ /* PCS <-> PCS */
+ /* Determine the algorithm and set its parameters */
+
+ if (intent != icmDefaultIntent
+ && intent != icRelativeColorimetric
+ && intent != icAbsoluteColorimetric) {
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Abstract profile");
+ p->errc = 1;
+ return NULL;
+ }
+
+ switch (func) {
+ case icmFwd: /* PCS (== Device) to PCS */
+
+ luobj = icc_new_icmLuLut(p, icSigAToB0Tag,
+ p->header->colorSpace, pcs, pcs,
+ e_pcs, e_pcs, e_pcs,
+ intent, func);
+ break;
+
+ case icmBwd: /* PCS to PCS (== Device) */
+
+ luobj = icc_new_icmLuLut(p, icSigBToA0Tag,
+ pcs, p->header->colorSpace, pcs,
+ e_pcs, e_pcs, e_pcs,
+ intent, func);
+ break;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Inaproptiate function requested");
+ p->errc = 1;
+ return NULL;
+ }
+ break;
+
+ case icSigNamedColorClass:
+ /* Expect Name -> Device, Optional PCS */
+ /* and a reverse lookup would be useful */
+ /* (ie. PCS or Device coords to closest named color) */
+ /* ~~ to be implemented ~~ */
+
+ /* ~~ Absolute intent is valid for processing of */
+ /* PCS from named Colors. Also allow for e_pcs */
+ if (intent != icmDefaultIntent
+ && intent != icRelativeColorimetric
+ && intent != icAbsoluteColorimetric) {
+ sprintf(p->err,"icc_get_luobj: Intent is inappropriate for Named Color profile");
+ p->errc = 1;
+ return NULL;
+ }
+
+ sprintf(p->err,"icc_get_luobj: Named Colors not handled yet");
+ p->errc = 1;
+ return NULL;
+
+ default:
+ sprintf(p->err,"icc_get_luobj: Unknown profile class");
+ p->errc = 1;
+ return NULL;
+ }
+
+ if (luobj == NULL) {
+ sprintf(p->err,"icc_get_luobj: Unable to locate usable conversion");
+ p->errc = 1;
+ } else {
+ luobj->order = order;
+ }
+
+ return luobj;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Returns total ink limit and channel maximums. */
+/* Returns -1.0 if not applicable for this type of profile. */
+/* Returns -1.0 for grey, additive, or any profiles < 4 channels. */
+/* This is a place holder that uses a heuristic, */
+/* until there is a private or standard tag for this information */
+static double icm_get_tac( /* return TAC */
+icc *p,
+double *chmax, /* device return channel sums. May be NULL */
+void (*calfunc)(void *cntx, double *out, double *in), /* Optional calibration func. */
+void *cntx
+) {
+ icmHeader *rh = p->header;
+ icmLuBase *luo;
+ icmLuLut *ll;
+ icmLut *lut;
+ icColorSpaceSignature outs; /* Type of output space */
+ int inn, outn; /* Number of components */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ double tac = 0.0;
+ double max[MAX_CHAN]; /* Channel maximums */
+ int i, f;
+ unsigned int uf;
+ int size; /* Lut table size */
+ double *gp; /* Pointer to grid cube base */
+
+ /* If not something that can really have a TAC */
+ if (rh->deviceClass != icSigDisplayClass
+ && rh->deviceClass != icSigOutputClass
+ && rh->deviceClass != icSigLinkClass) {
+ return -1.0;
+ }
+
+ /* If not a suitable color space */
+ switch (rh->colorSpace) {
+ /* Not applicable */
+ case icSigXYZData:
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ return -1.0;
+
+ /* Assume no limit */
+ case icSigGrayData:
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSigRgbData:
+ return -1.0;
+
+ default:
+ break;
+ }
+
+ /* Get a PCS->device colorimetric lookup */
+ if ((luo = p->get_luobj(p, icmBwd, icRelativeColorimetric, icmSigDefaultData, icmLuOrdNorm)) == NULL) {
+ if ((luo = p->get_luobj(p, icmBwd, icmDefaultIntent, icmSigDefaultData, icmLuOrdNorm)) == NULL) {
+ return -1.0;
+ }
+ }
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ luo->spaces(luo, NULL, &inn, &outs, &outn, &alg, NULL, NULL, NULL, NULL);
+
+ /* Assume any non-Lut type doesn't have a TAC */
+ if (alg != icmLutType) {
+ return -1.0;
+ }
+
+ ll = (icmLuLut *)luo;
+
+ /* We have a Lut type. Search the lut for the largest values */
+ for (f = 0; f < outn; f++)
+ max[f] = 0.0;
+
+ lut = ll->lut;
+ gp = lut->clutTable; /* Base of grid array */
+ size = sat_pow(lut->clutPoints,lut->inputChan);
+ for (i = 0; i < size; i++) {
+ double tot, vv[MAX_CHAN];
+
+ lut->lookup_output(lut,vv,gp); /* Lookup though output tables */
+ ll->out_denormf(vv,vv); /* Normalize for output color space */
+
+ if (calfunc != NULL)
+ calfunc(cntx, vv, vv); /* Apply device calibration */
+
+ for (tot = 0.0, uf = 0; uf < lut->outputChan; uf++) {
+ tot += vv[uf];
+ if (vv[uf] > max[uf])
+ max[uf] = vv[uf];
+ }
+ if (tot > tac)
+ tac = tot;
+ gp += lut->outputChan;
+ }
+
+ if (chmax != NULL) {
+ for (f = 0; f < outn; f++)
+ chmax[f] = max[f];
+ }
+
+ luo->del(luo);
+
+ return tac;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Create an empty object. Return NULL on error */
+icc *new_icc_a(
+icmAlloc *al /* Memory allocator */
+) {
+ unsigned int i;
+ icc *p;
+
+ if ((p = (icc *) al->calloc(al, 1,sizeof(icc))) == NULL) {
+ return NULL;
+ }
+ p->ver = 0; /* default is V2 profile */
+
+ p->al = al; /* Heap allocator */
+
+ p->get_rfp = icc_get_rfp;
+ p->set_version = icc_set_version;
+ p->get_size = icc_get_size;
+ p->read = icc_read;
+ p->read_x = icc_read_x;
+ p->write = icc_write;
+ p->write_x = icc_write_x;
+ p->dump = icc_dump;
+ p->del = icc_delete;
+ p->add_tag = icc_add_tag;
+ p->link_tag = icc_link_tag;
+ p->find_tag = icc_find_tag;
+ p->read_tag = icc_read_tag;
+ p->read_tag_any = icc_read_tag_any;
+ p->rename_tag = icc_rename_tag;
+ p->unread_tag = icc_unread_tag;
+ p->read_all_tags = icc_read_all_tags;
+ p->delete_tag = icc_delete_tag;
+ p->check_id = icc_check_id;
+ p->get_tac = icm_get_tac;
+ p->get_luobj = icc_get_luobj;
+ p->new_clutluobj = icc_new_icmLuLut;
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+#endif
+
+ /* Allocate a header object */
+ if ((p->header = new_icmHeader(p)) == NULL) {
+ al->free(al, p);
+ return NULL;
+ }
+
+ /* Values that must be set before writing */
+ p->header->deviceClass = icMaxEnumClass;/* Type of profile - must be set! */
+ p->header->colorSpace = icMaxEnumData; /* Clr space of data - must be set! */
+ p->header->pcs = icMaxEnumData; /* PCS: XYZ or Lab - must be set! */
+ p->header->renderingIntent = icMaxEnumIntent; /* Rendering intent - must be set ! */
+
+ /* Values that should be set before writing */
+ p->header->manufacturer = -1; /* Dev manufacturer - should be set ! */
+ p->header->model = -1; /* Dev model number - should be set ! */
+ p->header->attributes.l = 0; /* ICC Device attributes - should set ! */
+ p->header->flags = 0; /* Embedding flags - should be set ! */
+
+ /* Values that may be set before writing */
+ p->header->attributes.h = 0; /* Dev Device attributes - may be set ! */
+ p->header->creator = str2tag("argl"); /* Profile creator - Argyll - may be set ! */
+
+ /* Init default values in header */
+ p->header->cmmId = str2tag("argl"); /* CMM for profile - Argyll CMM */
+ p->header->majv = 2; /* Current version 2.2.0 */
+ p->header->minv = 2;
+ p->header->bfv = 0;
+ setcur_DateTimeNumber(&p->header->date);/* Creation Date */
+ p->header->platform = icSigMicrosoft; /* Primary Platform */
+ p->header->illuminant = icmD50; /* Profile illuminant - D50 */
+
+ /* Values that will be created automatically */
+ for (i = 0; i < 16; i++)
+ p->header->id[i] = 0;
+
+ return p;
+}
+
+
+/* ---------------------------------------------------------- */
+/* Print an int vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPiv(int di, int *p) {
+ static char buf[5][MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > MAX_CHAN)
+ di = MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%d", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print a double color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPdv(int di, double *p) {
+ static char buf[5][MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > MAX_CHAN)
+ di = MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%f", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print a float color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPfv(int di, float *p) {
+ static char buf[5][MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (di > MAX_CHAN)
+ di = MAX_CHAN; /* Make sure that buf isn't overrun */
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%f", p[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Print an 0..1 range XYZ as a D50 Lab string */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPLab(double *p) {
+ static char buf[5][MAX_CHAN * 16];
+ static int ix = 0;
+ int e;
+ char *bp;
+ double lab[3];
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ icmXYZ2Lab(&icmD50, lab, p);
+
+ for (e = 0; e < 3; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%f", lab[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+
+/* ---------------------------------------------------------- */
+
diff --git a/icc/icc.h b/icc/icc.h
new file mode 100644
index 0000000..7c3a65b
--- /dev/null
+++ b/icc/icc.h
@@ -0,0 +1,1992 @@
+#ifndef ICC_H
+#define ICC_H
+
+/*
+ * International Color Consortium Format Library (icclib)
+ *
+ * Author: Graeme W. Gill
+ * Date: 1999/11/29
+ * Version: 2.15
+ *
+ * Copyright 1997 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/* We can get some subtle errors if certain headers aren't included */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include <limits.h>
+#include <sys/types.h>
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Version of icclib release */
+
+#define ICCLIB_VERSION 0x020016
+#define ICCLIB_VERSION_STR "2.16"
+
+#undef ENABLE_V4 /* V4 is not fully implemented */
+
+/*
+ * Note XYZ scaling to 1.0, not 100.0
+ */
+
+#undef ICC_DEBUG_MALLOC /* Turns on partial support for filename and linenumber capture */
+
+/* Make allowance for shared library use */
+#ifdef ICCLIB_SHARED /* Compiling or Using shared library version */
+# ifdef ICCLIB_EXPORTS /* Compiling shared library */
+# ifdef NT
+# define ICCLIB_API __declspec(dllexport)
+# endif /* NT */
+# else /* Using shared library */
+# ifdef NT
+# define ICCLIB_API __declspec(dllimport)
+# ifdef ICCLIB_DEBUG
+# pragma comment (lib, "icclibd.lib")
+# else
+# pragma comment (lib, "icclib.lib")
+# endif /* DEBUG */
+# endif /* NT */
+# endif
+#else /* Using static library */
+# define ICCLIB_API /* empty */
+#endif
+
+/* =========================================================== */
+/* Platform specific primitive defines. */
+/* This really needs checking for each different platform. */
+/* Using C99 and MSC covers a lot of cases, */
+/* and the fallback default is pretty reliable with modern compilers and machines. */
+
+/* Note that the code assume that int is at least 32 bits, */
+/* and avoid using long as it is uncertain whether this is */
+/* the same size as an int or larger, opening the scope */
+/* for oveflow errors. */
+
+#if UINT_MAX < 0xffffffff
+# error "icclib: integer size is too small, must be at least 32 bit"
+#endif
+
+#ifndef ORD32 /* If not defined elsewhere */
+
+#if (__STDC_VERSION__ >= 199901L) /* C99 */
+
+#include <stdint.h>
+
+#define INR8 int8_t /* 8 bit signed */
+#define INR16 int16_t /* 16 bit signed */
+#define INR32 int32_t /* 32 bit signed */
+#define INR64 int64_t /* 64 bit signed - not used in icclib */
+#define ORD8 uint8_t /* 8 bit unsigned */
+#define ORD16 uint16_t /* 16 bit unsigned */
+#define ORD32 uint32_t /* 32 bit unsigned */
+#define ORD64 uint64_t /* 64 bit unsigned - not used in icclib */
+
+#define PNTR intptr_t
+
+/* printf format precision specifier */
+#define PF64PREC "ll"
+
+/* Constant precision specifier */
+#define CF64PREC "LL"
+
+#else /* !__STDC_VERSION__ */
+#ifdef _MSC_VER
+
+#define INR8 __int8 /* 8 bit signed */
+#define INR16 __int16 /* 16 bit signed */
+#define INR32 __int32 /* 32 bit signed */
+#define INR64 __int64 /* 64 bit signed - not used in icclib */
+#define ORD8 unsigned __int8 /* 8 bit unsigned */
+#define ORD16 unsigned __int16 /* 16 bit unsigned */
+#define ORD32 unsigned __int32 /* 32 bit unsigned */
+#define ORD64 unsigned __int64 /* 64 bit unsigned - not used in icclib */
+
+#define PNTR UINT_PTR
+
+#define vsnprintf _vsnprintf
+
+/* printf format precision specifier */
+#define PF64PREC "I64"
+
+/* Constant precision specifier */
+#define CF64PREC "LL"
+
+#else /* !_MSC_VER */
+
+/* The following works on a lot of modern systems, including */
+/* LP64 model 64 bit modes */
+
+#define INR8 signed char /* 8 bit signed */
+#define INR16 signed short /* 16 bit signed */
+#define INR32 signed int /* 32 bit signed */
+#define ORD8 unsigned char /* 8 bit unsigned */
+#define ORD16 unsigned short /* 16 bit unsigned */
+#define ORD32 unsigned int /* 32 bit unsigned */
+
+#ifdef __GNUC__
+#define INR64 long long /* 64 bit signed - not used in icclib */
+#define ORD64 unsigned long long /* 64 bit unsigned - not used in icclib */
+
+/* printf format precision specifier */
+#define PF64PREC "ll"
+
+#endif
+
+#define PNTR unsigned long
+
+#endif /* !_MSC_VER */
+#endif /* !__STDC_VERSION__ */
+#endif /* !defined(ORD32) */
+
+/* =========================================================== */
+#include "iccV42.h" /* ICC Version 4.2 definitions. */
+
+/* Note that the prefix icm is used for the native Machine */
+/* equivalents of the ICC binary file structures, and other icclib */
+/* specific definitions. */
+
+/* ---------------------------------------------- */
+/* System interface objects. The defaults can be replaced */
+/* for adaption to different system environments */
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Heap allocator class interface definition */
+#ifdef ICC_DEBUG_MALLOC
+
+#define ICM_ALLOC_BASE \
+ /* Public: */ \
+ \
+ void *(*dmalloc) (struct _icmAlloc *p, size_t size, char *file, int line); \
+ void *(*dcalloc) (struct _icmAlloc *p, size_t num, size_t size, char *file, int line); \
+ void *(*drealloc)(struct _icmAlloc *p, void *ptr, size_t size, char *file, int line); \
+ void (*dfree) (struct _icmAlloc *p, void *ptr, char *file, int line); \
+ \
+ /* we're done with the allocator object */ \
+ void (*del)(struct _icmAlloc *p); \
+
+#ifdef _ICC_C_ /* only inside icc.c */
+#define malloc( p, size ) dmalloc( p, size, __FILE__, __LINE__ )
+#define calloc( p, num, size ) dcalloc( p, num, size, __FILE__, __LINE__ )
+#define realloc( p, ptr, size ) drealloc( p, ptr, size, __FILE__, __LINE__ )
+#define free( p, ptr ) dfree( p, ptr , __FILE__, __LINE__ )
+#endif /* _ICC_C */
+
+#else /* !ICC_DEBUG_MALLOC */
+
+/* Heap allocator class interface definition */
+#define ICM_ALLOC_BASE \
+ /* Public: */ \
+ \
+ void *(*malloc) (struct _icmAlloc *p, size_t size); \
+ void *(*calloc) (struct _icmAlloc *p, size_t num, size_t size); \
+ void *(*realloc)(struct _icmAlloc *p, void *ptr, size_t size); \
+ void (*free) (struct _icmAlloc *p, void *ptr); \
+ \
+ /* we're done with the allocator object */ \
+ void (*del)(struct _icmAlloc *p); \
+
+#endif /* !ICC_DEBUG_MALLOC */
+
+/* Common heap allocator interface class */
+struct _icmAlloc {
+ ICM_ALLOC_BASE
+}; typedef struct _icmAlloc icmAlloc;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+/* Implementation of heap class based on standard system malloc */
+struct _icmAllocStd {
+ ICM_ALLOC_BASE
+}; typedef struct _icmAllocStd icmAllocStd;
+
+/* Create a standard alloc object */
+icmAlloc *new_icmAllocStd(void);
+
+/* File access class interface definition */
+#define ICM_FILE_BASE \
+ /* Public: */ \
+ \
+ /* Get the size of the file (Typically valid after read only) */ \
+ size_t (*get_size) (struct _icmFile *p); \
+ \
+ /* Set current position to offset. Return 0 on success, nz on failure. */ \
+ int (*seek) (struct _icmFile *p, unsigned int offset); \
+ \
+ /* Read count items of size length. Return number of items successfully read. */ \
+ size_t (*read) (struct _icmFile *p, void *buffer, size_t size, size_t count); \
+ \
+ /* write count items of size length. Return number of items successfully written. */ \
+ size_t (*write)(struct _icmFile *p, void *buffer, size_t size, size_t count); \
+ \
+ /* printf to the file */ \
+ int (*gprintf)(struct _icmFile *p, const char *format, ...); \
+ \
+ /* flush all write data out to secondary storage. Return nz on failure. */ \
+ int (*flush)(struct _icmFile *p); \
+ \
+ /* Return the memory buffer. Error if not icmFileMem */ \
+ int (*get_buf)(struct _icmFile *p, unsigned char **buf, size_t *len); \
+ \
+ /* we're done with the file object, return nz on failure */ \
+ int (*del)(struct _icmFile *p); \
+
+/* Common file interface class */
+struct _icmFile {
+ ICM_FILE_BASE
+}; typedef struct _icmFile icmFile;
+
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+/* These are avalailable if SEPARATE_STD is not defined: */
+
+/* Implementation of file access class based on standard file I/O */
+struct _icmFileStd {
+ ICM_FILE_BASE
+
+ /* Private: */
+ icmAlloc *al; /* Heap allocator */
+ int del_al; /* NZ if heap allocator should be deleted */
+ FILE *fp;
+ int doclose; /* nz if free should close */
+
+ /* Private: */
+ size_t size; /* Size of the file (For read) */
+
+}; typedef struct _icmFileStd icmFileStd;
+
+/* Create given a file name */
+icmFile *new_icmFileStd_name(char *name, char *mode);
+
+/* Create given a (binary) FILE* */
+icmFile *new_icmFileStd_fp(FILE *fp);
+
+/* Create given a file name with allocator */
+icmFile *new_icmFileStd_name_a(char *name, char *mode, icmAlloc *al);
+
+/* Create given a (binary) FILE* and allocator */
+icmFile *new_icmFileStd_fp_a(FILE *fp, icmAlloc *al);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Implementation of file access class based on a memory image */
+/* The buffer is assumed to be allocated with the given heap allocator */
+/* Pass base = NULL, length = 0 for no initial buffer */
+
+struct _icmFileMem {
+ ICM_FILE_BASE
+
+ /* Private: */
+ icmAlloc *al; /* Heap allocator */
+ int del_al; /* NZ if heap allocator should be deleted */
+ int del_buf; /* NZ if memory file buffer should be deleted */
+ unsigned char *start, *cur, *end, *aend;
+
+}; typedef struct _icmFileMem icmFileMem;
+
+/* Create a memory image file access class with given allocator */
+/* The buffer is not delete with the object. */
+icmFile *new_icmFileMem_a(void *base, size_t length, icmAlloc *al);
+
+/* Create a memory image file access class with given allocator */
+/* and delete buffer when icmFile is deleted. */
+icmFile *new_icmFileMem_ad(void *base, size_t length, icmAlloc *al);
+
+/* This is avalailable if SEPARATE_STD is not defined: */
+
+/* Create a memory image file access class */
+icmFile *new_icmFileMem(void *base, size_t length);
+
+/* Create a memory image file access class */
+/* and delete buffer when icmFile is deleted. */
+icmFile *new_icmFileMem_d(void *base, size_t length);
+
+/* --------------------------------- */
+/* Assumed constants */
+
+#define MAX_CHAN 15 /* Maximum number of color channels */
+
+/* --------------------------------- */
+/* tag and other compound structures */
+
+typedef int icmSig; /* Otherwise un-enumerated 4 byte signature */
+
+/* Non-standard Color Space Signatures - will be incompatible outside icclib! */
+
+/* A monochrome CIE L* space */
+#define icmSigLData ((icColorSpaceSignature) icmMakeTag('L',' ',' ',' '))
+
+/* A monochrome CIE Y space */
+#define icmSigYData ((icColorSpaceSignature) icmMakeTag('Y',' ',' ',' '))
+
+
+/* Pseudo Color Space Signatures - just used within icclib */
+
+/* Pseudo PCS colospace of profile */
+#define icmSigPCSData ((icColorSpaceSignature) icmMakeTag('P','C','S',' '))
+
+/* Pseudo PCS colospace to signal 8 bit Lab */
+#define icmSigLab8Data ((icColorSpaceSignature) icmMakeTag('L','a','b','8'))
+
+/* Pseudo PCS colospace to signal V2 16 bit Lab */
+#define icmSigLabV2Data ((icColorSpaceSignature) icmMakeTag('L','a','b','2'))
+
+/* Pseudo PCS colospace to signal V4 16 bit Lab */
+#define icmSigLabV4Data ((icColorSpaceSignature) icmMakeTag('L','a','b','4'))
+
+/* Pseudo PCS colospace to signal 8 bit L */
+#define icmSigL8Data ((icColorSpaceSignature) icmMakeTag('L',' ',' ','8'))
+
+/* Pseudo PCS colospace to signal V2 16 bit L */
+#define icmSigLV2Data ((icColorSpaceSignature) icmMakeTag('L',' ',' ','2'))
+
+/* Pseudo PCS colospace to signal V4 16 bit L */
+#define icmSigLV4Data ((icColorSpaceSignature) icmMakeTag('L',' ',' ','4'))
+
+/* Non-standard Platform Signature */
+#define icmSig_nix ((icPlatformSignature) icmMakeTag('*','n','i','x'))
+
+
+/* Alias for icSigColorantTableType found in LOGO profiles (Byte swapped clrt !) */
+#define icmSigAltColorantTableType ((icTagTypeSignature)icmMakeTag('t','r','l','c'))
+
+/* Tag Type signature, used to handle any tag that */
+/* isn't handled with a specific type object. */
+/* Also used in manufacturer & model header fields */
+/* Old: #define icmSigUnknownType ((icTagTypeSignature)icmMakeTag('?','?','?','?')) */
+#define icmSigUnknownType ((icTagTypeSignature) 0)
+
+
+typedef struct {
+ ORD32 l; /* High and low components of signed 64 bit */
+ INR32 h;
+} icmInt64;
+
+typedef struct {
+ ORD32 l,h; /* High and low components of unsigned 64 bit */
+} icmUint64;
+
+/* XYZ Number */
+typedef struct {
+ double X;
+ double Y;
+ double Z;
+} icmXYZNumber;
+
+/* Response 16 number */
+typedef struct {
+ double deviceValue; /* The device value in range 0.0 - 1.0 */
+ double measurement; /* The reading value */
+} icmResponse16Number;
+
+/*
+ * read and write method error codes:
+ * 0 = sucess
+ * 1 = file format/logistical error
+ * 2 = system error
+ */
+
+#define ICM_BASE_MEMBERS \
+ /* Private: */ \
+ icTagTypeSignature ttype; /* The tag type signature */ \
+ struct _icc *icp; /* Pointer to ICC we're a part of */ \
+ int touched; /* Flag for write bookeeping */ \
+ int refcount; /* Reference count for sharing */ \
+ unsigned int (*get_size)(struct _icmBase *p); \
+ int (*read)(struct _icmBase *p, unsigned int len, unsigned int of); \
+ int (*write)(struct _icmBase *p, unsigned int of); \
+ void (*del)(struct _icmBase *p); \
+ \
+ /* Public: */ \
+ void (*dump)(struct _icmBase *p, icmFile *op, int verb); \
+ int (*allocate)(struct _icmBase *p);
+
+/* Base tag element data object */
+struct _icmBase {
+ ICM_BASE_MEMBERS
+}; typedef struct _icmBase icmBase;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Tag type to hold an unknown tag type, */
+/* so that it can be read and copied. */
+struct _icmUnknown {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* size of data currently allocated */
+
+ /* Public: */
+ icTagTypeSignature uttype; /* The unknown tag type signature */
+ unsigned int size; /* Allocated and used size of the array */
+ unsigned char *data; /* tag data */
+}; typedef struct _icmUnknown icmUnknown;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* UInt8 Array */
+struct _icmUInt8Array {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of the array */
+ unsigned int *data; /* Pointer to array of data */
+}; typedef struct _icmUInt8Array icmUInt8Array;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* uInt16 Array */
+struct _icmUInt16Array {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of the array */
+ unsigned int *data; /* Pointer to array of data */
+}; typedef struct _icmUInt16Array icmUInt16Array;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* uInt32 Array */
+struct _icmUInt32Array {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of the array */
+ unsigned int *data; /* Pointer to array of data */
+}; typedef struct _icmUInt32Array icmUInt32Array;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* UInt64 Array */
+struct _icmUInt64Array {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of the array */
+ icmUint64 *data; /* Pointer to array of hight data */
+}; typedef struct _icmUInt64Array icmUInt64Array;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* u16Fixed16 Array */
+struct _icmU16Fixed16Array {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of the array */
+ double *data; /* Pointer to array of hight data */
+}; typedef struct _icmU16Fixed16Array icmU16Fixed16Array;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* s15Fixed16 Array */
+struct _icmS15Fixed16Array {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of the array */
+ double *data; /* Pointer to array of hight data */
+}; typedef struct _icmS15Fixed16Array icmS15Fixed16Array;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* XYZ Array */
+struct _icmXYZArray {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of the array */
+ icmXYZNumber *data; /* Pointer to array of data */
+}; typedef struct _icmXYZArray icmXYZArray;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Curve */
+typedef enum {
+ icmCurveUndef = -1, /* Undefined curve */
+ icmCurveLin = 0, /* Linear transfer curve */
+ icmCurveGamma = 1, /* Gamma power transfer curve */
+ icmCurveSpec = 2 /* Specified curve */
+} icmCurveStyle;
+
+/* Curve reverse lookup information */
+typedef struct {
+ int inited; /* Flag */
+ double rmin, rmax; /* Range of reverse grid */
+ double qscale; /* Quantising scale factor */
+ int rsize; /* Number of reverse lists */
+ unsigned int **rlists; /* Array of list of fwd values that may contain output value */
+ /* Offset 0 = allocated size */
+ /* Offset 1 = next free index */
+ /* Offset 2 = first fwd index */
+ unsigned int size; /* Copy of forward table size */
+ double *data; /* Copy of forward table data */
+} icmRevTable;
+
+struct _icmCurve {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+ icmRevTable rt; /* Reverse table information */
+
+ /* Public: */
+ icmCurveStyle flag; /* Style of curve */
+ unsigned int size; /* Allocated and used size of the array */
+ double *data; /* Curve data scaled to range 0.0 - 1.0 */
+ /* or data[0] = gamma value */
+ /* Translate a value through the curve, return warning flags */
+ int (*lookup_fwd) (struct _icmCurve *p, double *out, double *in); /* Forwards */
+ int (*lookup_bwd) (struct _icmCurve *p, double *out, double *in); /* Backwards */
+
+}; typedef struct _icmCurve icmCurve;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Data */
+typedef enum {
+ icmDataUndef = -1, /* Undefined data */
+ icmDataASCII = 0, /* ASCII data */
+ icmDataBin = 1 /* Binary data */
+} icmDataStyle;
+
+struct _icmData {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ icmDataStyle flag; /* Style of data */
+ unsigned int size; /* Allocated and used size of the array (inc ascii null) */
+ unsigned char *data; /* data or string, NULL if size == 0 */
+}; typedef struct _icmData icmData;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* text */
+struct _icmText {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of data, inc null */
+ char *data; /* ascii string (null terminated), NULL if size==0 */
+
+}; typedef struct _icmText icmText;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* The base date time number */
+struct _icmDateTimeNumber {
+ ICM_BASE_MEMBERS
+
+ /* Public: */
+ unsigned int year;
+ unsigned int month;
+ unsigned int day;
+ unsigned int hours;
+ unsigned int minutes;
+ unsigned int seconds;
+}; typedef struct _icmDateTimeNumber icmDateTimeNumber;
+
+#ifdef NEW
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* DeviceSettings */
+
+/*
+ I think this all works like this:
+
+Valid setting = ( (platform == platform1 and platform1.valid)
+ or (platform == platform2 and platform2.valid)
+ or ...
+ )
+
+where
+ platformN.valid = ( platformN.combination1.valid
+ or platformN.combination2.valid
+ or ...
+ )
+
+where
+ platformN.combinationM.valid = ( platformN.combinationM.settingstruct1.valid
+ and platformN.combinationM.settingstruct2.valid
+ and ...
+ )
+
+where
+ platformN.combinationM.settingstructP.valid = ( platformN.combinationM.settingstructP.setting1.valid
+ or platformN.combinationM.settingstructP.setting2.valid
+ or ...
+ )
+
+ */
+
+/* The Settings Structure holds an array of settings of a particular type */
+struct _icmSettingStruct {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _num; /* Size currently allocated */
+
+ /* Public: */
+ icSettingsSig settingSig; /* Setting identification */
+ unsigned int numSettings; /* number of setting values */
+ union { /* Setting values - type depends on Sig */
+ icUInt64Number *resolution;
+ icDeviceMedia *media;
+ icDeviceDither *halftone;
+ }
+}; typedef struct _icmSettingStruct icmSettingStruct;
+
+/* A Setting Combination holds all arrays of different setting types */
+struct _icmSettingComb {
+ /* Private: */
+ unsigned int _num; /* number currently allocated */
+
+ /* Public: */
+ unsigned int numStructs; /* num of setting structures */
+ icmSettingStruct *data;
+}; typedef struct _icmSettingComb icmSettingComb;
+
+/* A Platform Entry holds all setting combinations */
+struct _icmPlatformEntry {
+ /* Private: */
+ unsigned int _num; /* number currently allocated */
+
+ /* Public: */
+ icPlatformSignature platform;
+ unsigned int numCombinations; /* num of settings and allocated array size */
+ icmSettingComb *data;
+}; typedef struct _icmPlatformEntry icmPlatformEntry;
+
+/* The Device Settings holds all platform settings */
+struct _icmDeviceSettings {
+ /* Private: */
+ unsigned int _num; /* number currently allocated */
+
+ /* Public: */
+ unsigned int numPlatforms; /* num of platforms and allocated array size */
+ icmPlatformEntry *data; /* Array of pointers to platform entry data */
+}; typedef struct _icmDeviceSettings icmDeviceSettings;
+
+#endif /* NEW */
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* optimised simplex Lut lookup axis flipping structure */
+typedef struct {
+ double fth; /* Flip threshold */
+ char bthff; /* Below threshold flip flag value */
+ char athff; /* Above threshold flip flag value */
+} sx_flip_info;
+
+/* Set method flags */
+#define ICM_CLUT_SET_EXACT 0x0000 /* Set clut node values exactly from callback */
+#define ICM_CLUT_SET_APXLS 0x0001 /* Set clut node values to aproximate least squares fit */
+
+#define ICM_CLUT_SET_FILTER 0x0002 /* Post filter values (icmSetMultiLutTables() only) */
+
+
+/* lut */
+struct _icmLut {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ /* Cache appropriate normalization routines */
+ int dinc[MAX_CHAN]; /* Dimensional increment through clut (in doubles) */
+ int dcube[1 << MAX_CHAN]; /* Hyper cube offsets (in doubles) */
+ icmRevTable rit[MAX_CHAN]; /* Reverse input table information */
+ icmRevTable rot[MAX_CHAN]; /* Reverse output table information */
+ sx_flip_info finfo[MAX_CHAN]; /* Optimised simplex flip information */
+
+ unsigned int inputTable_size; /* size allocated to input table */
+ unsigned int clutTable_size; /* size allocated to clut table */
+ unsigned int outputTable_size; /* size allocated to output table */
+
+ /* Optimised simplex orientation information. oso_ffa is NZ if valid. */
+ /* Only valid if inputChan > 1 && clutPoints > 1 */
+ /* oso_ff[01] will be NULL if not valid */
+ unsigned short *oso_ffa; /* Flip flags for inputChan-1 dimensions, organised */
+ /* [inputChan 0, 0..cp-2]..[inputChan ic-2, 0..cp-2] */
+ unsigned short *oso_ffb; /* Flip flags for dimemension inputChan-1, organised */
+ /* [0..cp-2] */
+ int odinc[MAX_CHAN]; /* Dimensional increment through oso_ffa */
+
+ /* return the minimum and maximum values of the given channel in the clut */
+ void (*min_max) (struct _icmLut *pp, double *minv, double *maxv, int chan);
+
+ /* Translate color values through 3x3 matrix, input tables only, multi-dimensional lut, */
+ /* or output tables, */
+ int (*lookup_matrix) (struct _icmLut *pp, double *out, double *in);
+ int (*lookup_input) (struct _icmLut *pp, double *out, double *in);
+ int (*lookup_clut_nl) (struct _icmLut *pp, double *out, double *in);
+ int (*lookup_clut_sx) (struct _icmLut *pp, double *out, double *in);
+ int (*lookup_output) (struct _icmLut *pp, double *out, double *in);
+
+ /* Public: */
+
+ /* return non zero if matrix is non-unity */
+ int (*nu_matrix) (struct _icmLut *pp);
+
+ unsigned int inputChan; /* Num of input channels */
+ unsigned int outputChan; /* Num of output channels */
+ unsigned int clutPoints; /* Num of grid points */
+ unsigned int inputEnt; /* Num of in-table entries (must be 256 for Lut8) */
+ unsigned int outputEnt; /* Num of out-table entries (must be 256 for Lut8) */
+ double e[3][3]; /* 3 * 3 array */
+ double *inputTable; /* The in-table: [inputChan * inputEnt] */
+ double *clutTable; /* The clut: [(clutPoints ^ inputChan) * outputChan] */
+ double *outputTable; /* The out-table: [outputChan * outputEnt] */
+ /* inputTable is organized [inputChan 0..ic-1][inputEnt 0..ie-1] */
+ /* clutTable is organized [inputChan 0, 0..cp-1]..[inputChan ic-1, 0..cp-1]
+ [outputChan 0..oc-1] */
+ /* outputTable is organized [outputChan 0..oc-1][outputEnt 0..oe-1] */
+
+ /* Helper function to setup a Lut tables contents */
+ int (*set_tables) (
+ struct _icmLut *p, /* Pointer to Lut object */
+ int flags, /* Setting flags */
+ void *cbctx, /* Opaque callback context pointer value */
+ icColorSpaceSignature insig, /* Input color space */
+ icColorSpaceSignature outsig, /* Output color space */
+ void (*infunc)(void *cbctx, double *out, double *in),
+ /* Input transfer function, inspace->inspace' (NULL = default) */
+ double *inmin, double *inmax, /* Maximum range of inspace' values */
+ /* (NULL = default) */
+ void (*clutfunc)(void *cbntx, double *out, double *in),
+ /* inspace' -> outspace' transfer function */
+ double *clutmin, double *clutmax, /* Maximum range of outspace' values */
+ /* (NULL = default) */
+ void (*outfunc)(void *cbntx, double *out, double *in));
+ /* Output transfer function, outspace'->outspace (NULL = deflt) */
+
+}; typedef struct _icmLut icmLut;
+
+/* Helper function to set multiple Lut tables simultaneously. */
+/* Note that these tables all have to be compatible in */
+/* having the same configuration and resolutions, and the */
+/* same per channel input and output curves. */
+/* Set errc and return error number in underlying icc */
+/* Note that clutfunc in[] value has "index under". */
+/* If ICM_CLUT_SET_FILTER is set, the per grid node filtering radius */
+/* is returned in clutfunc out[-1], out[-2] etc for each table */
+int icmSetMultiLutTables(
+ int ntables, /* Number of tables to be set, 1..n */
+ struct _icmLut **p, /* Pointer to Lut object */
+ int flags, /* Setting flags */
+ void *cbctx, /* Opaque callback context pointer value */
+ icColorSpaceSignature insig, /* Input color space */
+ icColorSpaceSignature outsig, /* Output color space */
+ void (*infunc)(void *cbctx, double *out, double *in),
+ /* Input transfer function, inspace->inspace' (NULL = default) */
+ /* Will be called ntables times each input grid value */
+ double *inmin, double *inmax, /* Maximum range of inspace' values */
+ /* (NULL = default) */
+ void (*clutfunc)(void *cbntx, double *out, double *in),
+ /* inspace' -> outspace[ntables]' transfer function */
+ /* will be called once for each input' grid value, and */
+ /* ntables output values should be written consecutively */
+ /* to out[]. */
+ double *clutmin, double *clutmax, /* Maximum range of outspace' values */
+ /* (NULL = default) */
+ void (*outfunc)(void *cbntx, double *out, double *in)
+ /* Output transfer function, outspace'->outspace (NULL = deflt) */
+ /* Will be called ntables times on each output value */
+);
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Measurement Data */
+struct _icmMeasurement {
+ ICM_BASE_MEMBERS
+
+ /* Public: */
+ icStandardObserver observer; /* Standard observer */
+ icmXYZNumber backing; /* XYZ for backing */
+ icMeasurementGeometry geometry; /* Meas. geometry */
+ double flare; /* Measurement flare */
+ icIlluminant illuminant; /* Illuminant */
+}; typedef struct _icmMeasurement icmMeasurement;
+
+#ifdef NEW
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* MultiLocalizedUnicode */
+
+struct _icmMultiLocalizedUnicode {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ ~~~999
+
+ /* Public: */
+ ~~~999
+
+}; typedef struct _icmMultiLocalizedUnicode icmMultiLocalizedUnicode;
+
+#endif /* NEW */
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Named color */
+
+/* Structure that holds each named color data */
+typedef struct {
+ struct _icc *icp; /* Pointer to ICC we're a part of */
+ char root[32]; /* Root name for color */
+ double pcsCoords[3]; /* icmNC2: PCS coords of color */
+ double deviceCoords[MAX_CHAN]; /* Dev coords of color */
+} icmNamedColorVal;
+
+struct _icmNamedColor {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _count; /* Count currently allocated */
+
+ /* Public: */
+ unsigned int vendorFlag; /* Bottom 16 bits for IC use */
+ unsigned int count; /* Count of named colors */
+ unsigned int nDeviceCoords; /* Num of device coordinates */
+ char prefix[32]; /* Prefix for each color name (null terminated) */
+ char suffix[32]; /* Suffix for each color name (null terminated) */
+ icmNamedColorVal *data; /* Array of [count] color values */
+}; typedef struct _icmNamedColor icmNamedColor;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Colorant table */
+/* (Contribution from Piet Vandenborre, derived from NamedColor) */
+
+/* Structure that holds colorant table data */
+typedef struct {
+ struct _icc *icp; /* Pointer to ICC we're a part of */
+ char name[32]; /* Name for colorant */
+ double pcsCoords[3]; /* PCS coords of colorant */
+} icmColorantTableVal;
+
+struct _icmColorantTable {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _count; /* Count currently allocated */
+
+ /* Public: */
+ unsigned int count; /* Count of colorants */
+ icmColorantTableVal *data; /* Array of [count] colorants */
+}; typedef struct _icmColorantTable icmColorantTable;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* textDescription */
+struct _icmTextDescription {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _size; /* Size currently allocated */
+ unsigned int uc_size; /* uc Size currently allocated */
+ int (*core_read)(struct _icmTextDescription *p, char **bpp, char *end);
+ int (*core_write)(struct _icmTextDescription *p, char **bpp);
+
+ /* Public: */
+ unsigned int size; /* Allocated and used size of desc, inc null */
+ char *desc; /* ascii string (null terminated) */
+
+ unsigned int ucLangCode; /* UniCode language code */
+ unsigned int ucSize; /* Allocated and used size of ucDesc in wchars, inc null */
+ ORD16 *ucDesc; /* The UniCode description (null terminated) */
+
+ /* See <http://unicode.org/Public/MAPPINGS/VENDORS/APPLE/ReadMe.txt> */
+ ORD16 scCode; /* ScriptCode code */
+ unsigned int scSize; /* Used size of scDesc in bytes, inc null */
+ ORD8 scDesc[67]; /* ScriptCode Description (null terminated, max 67) */
+}; typedef struct _icmTextDescription icmTextDescription;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Profile sequence structure */
+struct _icmDescStruct {
+ /* Private: */
+ struct _icc *icp; /* Pointer to ICC we're a part of */
+
+ /* Public: */
+ int (*allocate)(struct _icmDescStruct *p); /* Allocate method */
+ icmSig deviceMfg; /* Dev Manufacturer */
+ unsigned int deviceModel; /* Dev Model */
+ icmUint64 attributes; /* Dev attributes */
+ icTechnologySignature technology; /* Technology sig */
+ icmTextDescription device; /* Manufacturer text (sub structure) */
+ icmTextDescription model; /* Model text (sub structure) */
+}; typedef struct _icmDescStruct icmDescStruct;
+
+/* Profile sequence description */
+struct _icmProfileSequenceDesc {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _count; /* number currently allocated */
+
+ /* Public: */
+ unsigned int count; /* Number of descriptions */
+ icmDescStruct *data; /* array of [count] descriptions */
+}; typedef struct _icmProfileSequenceDesc icmProfileSequenceDesc;
+
+#ifdef NEW
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* ResponseCurveSet16 */
+
+struct _icmResponseCurveSet16 {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ ~~~999
+
+ /* Public: */
+ ~~~999
+
+}; typedef struct _icmResponseCurveSet16 icmResponseCurveSet16;
+
+#endif /* NEW */
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* signature (only ever used for technology ??) */
+struct _icmSignature {
+ ICM_BASE_MEMBERS
+
+ /* Public: */
+ icTechnologySignature sig; /* Signature */
+}; typedef struct _icmSignature icmSignature;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Per channel Screening Data */
+typedef struct {
+ /* Public: */
+ double frequency; /* Frequency */
+ double angle; /* Screen angle */
+ icSpotShape spotShape; /* Spot Shape encodings below */
+} icmScreeningData;
+
+struct _icmScreening {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int _channels; /* number currently allocated */
+
+ /* Public: */
+ unsigned int screeningFlag; /* Screening flag */
+ unsigned int channels; /* Number of channels */
+ icmScreeningData *data; /* Array of screening data */
+}; typedef struct _icmScreening icmScreening;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Under color removal, black generation */
+struct _icmUcrBg {
+ ICM_BASE_MEMBERS
+
+ /* Private: */
+ unsigned int UCR_count; /* Currently allocated UCR count */
+ unsigned int BG_count; /* Currently allocated BG count */
+ unsigned int _size; /* Currently allocated string size */
+
+ /* Public: */
+ unsigned int UCRcount; /* Undercolor Removal Curve length */
+ double *UCRcurve; /* The array of UCR curve values, 0.0 - 1.0 */
+ /* or 0.0 - 100 % if count = 1 */
+ unsigned int BGcount; /* Black generation Curve length */
+ double *BGcurve; /* The array of BG curve values, 0.0 - 1.0 */
+ /* or 0.0 - 100 % if count = 1 */
+ unsigned int size; /* Allocated and used size of desc, inc null */
+ char *string; /* UcrBg description (null terminated) */
+}; typedef struct _icmUcrBg icmUcrBg;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* viewingConditionsType */
+struct _icmViewingConditions {
+ ICM_BASE_MEMBERS
+
+ /* Public: */
+ icmXYZNumber illuminant; /* In candelas per sq. meter */
+ icmXYZNumber surround; /* In candelas per sq. meter */
+ icIlluminant stdIlluminant; /* See icIlluminant defines */
+}; typedef struct _icmViewingConditions icmViewingConditions;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Postscript Color Rendering Dictionary names type */
+struct _icmCrdInfo {
+ ICM_BASE_MEMBERS
+ /* Private: */
+ unsigned int _ppsize; /* Currently allocated size */
+ unsigned int _crdsize[4]; /* Currently allocated sizes */
+
+ /* Public: */
+ unsigned int ppsize; /* Postscript product name size (including null) */
+ char *ppname; /* Postscript product name (null terminated) */
+ unsigned int crdsize[4]; /* Rendering intent 0-3 CRD names sizes (icluding null) */
+ char *crdname[4]; /* Rendering intent 0-3 CRD names (null terminated) */
+}; typedef struct _icmCrdInfo icmCrdInfo;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Apple ColorSync 2.5 video card gamma type (vcgt) */
+struct _icmVideoCardGammaTable {
+ unsigned short channels; /* No of gamma channels (1 or 3) */
+ unsigned short entryCount; /* Number of entries per channel */
+ unsigned short entrySize; /* Size in bytes of each entry */
+ void *data; /* Variable size data */
+}; typedef struct _icmVideoCardGammaTable icmVideoCardGammaTable;
+
+struct _icmVideoCardGammaFormula {
+ unsigned short channels; /* No of gamma channels (always 3) */
+ double redGamma; /* must be > 0.0 */
+ double redMin; /* must be > 0.0 and < 1.0 */
+ double redMax; /* must be > 0.0 and < 1.0 */
+ double greenGamma; /* must be > 0.0 */
+ double greenMin; /* must be > 0.0 and < 1.0 */
+ double greenMax; /* must be > 0.0 and < 1.0 */
+ double blueGamma; /* must be > 0.0 */
+ double blueMin; /* must be > 0.0 and < 1.0 */
+ double blueMax; /* must be > 0.0 and < 1.0 */
+}; typedef struct _icmVideoCardGammaFormula icmVideoCardGammaFormula;
+
+typedef enum {
+ icmVideoCardGammaTableType = 0,
+ icmVideoCardGammaFormulaType = 1
+} icmVideoCardGammaTagType;
+
+struct _icmVideoCardGamma {
+ ICM_BASE_MEMBERS
+ icmVideoCardGammaTagType tagType; /* eg. table or formula, use above enum */
+ union {
+ icmVideoCardGammaTable table;
+ icmVideoCardGammaFormula formula;
+ } u;
+
+ double (*lookup)(struct _icmVideoCardGamma *p, int chan, double iv); /* Read a value */
+
+}; typedef struct _icmVideoCardGamma icmVideoCardGamma;
+
+/* ------------------------------------------------- */
+/* The Profile header */
+struct _icmHeader {
+
+ /* Private: */
+ unsigned int (*get_size)(struct _icmHeader *p);
+ int (*read)(struct _icmHeader *p, unsigned int len, unsigned int of);
+ int (*write)(struct _icmHeader *p, unsigned int of, int doid);
+ void (*del)(struct _icmHeader *p);
+ struct _icc *icp; /* Pointer to ICC we're a part of */
+ unsigned int size; /* Profile size in bytes */
+
+ /* public: */
+ void (*dump)(struct _icmHeader *p, icmFile *op, int verb);
+
+ /* Values that must be set before writing */
+ icProfileClassSignature deviceClass; /* Type of profile */
+ icColorSpaceSignature colorSpace; /* Clr space of data (Cannonical input space) */
+ icColorSpaceSignature pcs; /* PCS: XYZ or Lab (Cannonical output space) */
+ icRenderingIntent renderingIntent;/* Rendering intent */
+
+ /* Values that should be set before writing */
+ icmSig manufacturer; /* Dev manufacturer */
+ icmSig model; /* Dev model */
+ icmUint64 attributes; /* Device attributes */
+ unsigned int flags; /* Various bits */
+
+ /* Values that may optionally be set before writing */
+ /* icmUint64 attributes; Device attributes.h (see above) */
+ icmSig creator; /* Profile creator */
+
+ /* Values that are not normally set, since they have defaults */
+ icmSig cmmId; /* CMM for profile */
+ int majv, minv, bfv;/* Format version - major, minor, bug fix */
+ /* Default is majv = 2, alternate value is 4 */
+ icmDateTimeNumber date; /* Creation Date */
+ icPlatformSignature platform; /* Primary Platform */
+ icmXYZNumber illuminant; /* Profile illuminant */
+
+ /* Values that are created automatically */
+ unsigned char id[16]; /* MD5 fingerprint value, lsB to msB <V4.0+> */
+
+}; typedef struct _icmHeader icmHeader;
+
+/* ---------------------------------------------------------- */
+/* Objects for accessing lookup functions. */
+/* Note that the "effective" PCS colorspace is the one specified by the */
+/* PCS override, and visible in the overal profile conversion. */
+/* The "native" PCS colorspace is the one that the underlying tags actually */
+/* represent, and the PCS that the individual stages within each profile type handle. */
+/* The conversion between the native and effective PCS is done in the to/from_abs() */
+/* conversions. */
+
+/* Public: Parameter to get_luobj function */
+typedef enum {
+ icmFwd = 0, /* Device to PCS, or Device 1 to Last Device */
+ icmBwd = 1, /* PCS to Device, or Last Device to Device */
+ icmGamut = 2, /* PCS Gamut check */
+ icmPreview = 3 /* PCS to PCS preview */
+} icmLookupFunc;
+
+/* Public: Parameter to get_luobj function */
+typedef enum {
+ icmLuOrdNorm = 0, /* Normal profile preference: Lut, matrix, monochrome */
+ icmLuOrdRev = 1 /* Reverse profile preference: monochrome, matrix, monochrome */
+} icmLookupOrder;
+
+/* Public: Lookup algorithm object type */
+typedef enum {
+ icmMonoFwdType = 0, /* Monochrome, Forward */
+ icmMonoBwdType = 1, /* Monochrome, Backward */
+ icmMatrixFwdType = 2, /* Matrix, Forward */
+ icmMatrixBwdType = 3, /* Matrix, Backward */
+ icmLutType = 4, /* Multi-dimensional Lookup Table */
+ icmNamedType = 5 /* Named color data */
+} icmLuAlgType;
+
+/* Lookup class members common to named and non-named color types */
+#define LU_ICM_BASE_MEMBERS \
+ /* Private: */ \
+ icmLuAlgType ttype; /* The object tag */ \
+ struct _icc *icp; /* Pointer to ICC we're a part of */ \
+ icRenderingIntent intent; /* Effective (externaly visible) intent */ \
+ icmLookupFunc function; /* Functionality being used */ \
+ icmLookupOrder order; /* Conversion representation search Order */ \
+ icmXYZNumber pcswht, whitePoint, blackPoint; /* White and black point info (absolute XYZ) */ \
+ int blackisassumed; /* nz if black point tag is missing from profile */ \
+ double toAbs[3][3]; /* Matrix to convert from relative to absolute */ \
+ double fromAbs[3][3]; /* Matrix to convert from absolute to relative */ \
+ icColorSpaceSignature inSpace; /* Native Clr space of input */ \
+ icColorSpaceSignature outSpace; /* Native Clr space of output */ \
+ icColorSpaceSignature pcs; /* Native PCS */ \
+ icColorSpaceSignature e_inSpace; /* Effective Clr space of input */ \
+ icColorSpaceSignature e_outSpace; /* Effective Clr space of output */ \
+ icColorSpaceSignature e_pcs; /* Effective PCS */ \
+ \
+ /* Public: */ \
+ void (*del)(struct _icmLuBase *p); \
+ \
+ /* Internal native colorspaces: */ \
+ void (*lutspaces) (struct _icmLuBase *p, icColorSpaceSignature *ins, int *inn, \
+ icColorSpaceSignature *outs, int *outn, \
+ icColorSpaceSignature *pcs); \
+ \
+ /* External effecive colorspaces */ \
+ void (*spaces) (struct _icmLuBase *p, icColorSpaceSignature *ins, int *inn, \
+ icColorSpaceSignature *outs, int *outn, \
+ icmLuAlgType *alg, icRenderingIntent *intt, \
+ icmLookupFunc *fnc, icColorSpaceSignature *pcs, \
+ icmLookupOrder *ord); \
+ \
+ /* Relative to Absolute for this WP in XYZ */ \
+ void (*XYZ_Rel2Abs)(struct _icmLuBase *p, double *xyzout, double *xyzin); \
+ \
+ /* Absolute to Relative for this WP in XYZ */ \
+ void (*XYZ_Abs2Rel)(struct _icmLuBase *p, double *xyzout, double *xyzin); \
+
+
+/* Non-algorithm specific lookup class. Used as base class of algorithm specific class. */
+#define LU_ICM_NN_BASE_MEMBERS \
+ LU_ICM_BASE_MEMBERS \
+ \
+ /* Public: */ \
+ \
+ /* Get the native input space and output space ranges */ \
+ /* This is an accurate number of what the underlying profile can hold. */ \
+ void (*get_lutranges) (struct _icmLuBase *p, \
+ double *inmin, double *inmax, /* Range of inspace values */ \
+ double *outmin, double *outmax); /* Range of outspace values */ \
+ \
+ /* Get the effective input space and output space ranges */ \
+ /* This may not be accurate when the effective type is different to the native type */ \
+ void (*get_ranges) (struct _icmLuBase *p, \
+ double *inmin, double *inmax, /* Range of inspace values */ \
+ double *outmin, double *outmax); /* Range of outspace values */ \
+ \
+ /* Initialise the white and black points from the ICC tags */ \
+ /* and the corresponding absolute<->relative conversion matrices */ \
+ /* Return nz on error */ \
+ int (*init_wh_bk)(struct _icmLuBase *p); \
+ \
+ /* Get the LU white and black points in absolute XYZ space. */ \
+ /* Return nz if the black point is being assumed to be 0,0,0 rather */ \
+ /* than being from the tag. */ \
+ int (*wh_bk_points)(struct _icmLuBase *p, double *wht, double *blk); \
+ \
+ /* Get the LU white and black points in LU PCS space, converted to XYZ. */ \
+ /* (ie. white and black will be relative if LU is relative intent etc.) */ \
+ /* Return nz if the black point is being assumed to be 0,0,0 rather */ \
+ /* than being from the tag. */ \
+ int (*lu_wh_bk_points)(struct _icmLuBase *p, double *wht, double *blk); \
+ \
+ /* Translate color values through profile in effective in and out colorspaces, */ \
+ /* return values: */ \
+ /* 0 = success, 1 = warning: clipping occured, 2 = fatal: other error */ \
+ /* Note that clipping is not a reliable means of detecting out of gamut */ \
+ /* in the lookup(bwd) call for clut based profiles. */ \
+ int (*lookup) (struct _icmLuBase *p, double *out, double *in); \
+ \
+ \
+ /* Alternate to above, splits color conversion into three steps. */ \
+ /* Colorspace of _in and _out and _core are the effective in and out */ \
+ /* colorspaces. Note that setting colorspace overrides will probably. */ \
+ /* force _in and/or _out to be dumy (unity) transforms. */ \
+ \
+ /* Per channel input lookup (may be unity): */ \
+ int (*lookup_in) (struct _icmLuBase *p, double *out, double *in); \
+ \
+ /* Intra channel conversion: */ \
+ int (*lookup_core) (struct _icmLuBase *p, double *out, double *in); \
+ \
+ /* Per channel output lookup (may be unity): */ \
+ int (*lookup_out) (struct _icmLuBase *p, double *out, double *in); \
+ \
+ /* Inverse versions of above - partially implemented */ \
+ /* Inverse per channel input lookup (may be unity): */ \
+ int (*lookup_inv_in) (struct _icmLuBase *p, double *out, double *in); \
+ \
+
+
+/* Base lookup object */
+struct _icmLuBase {
+ LU_ICM_NN_BASE_MEMBERS
+}; typedef struct _icmLuBase icmLuBase;
+
+
+/* Algorithm specific lookup classes */
+
+/* Monochrome Fwd & Bwd type object */
+struct _icmLuMono {
+ LU_ICM_NN_BASE_MEMBERS
+ icmCurve *grayCurve;
+
+ /* Overall lookups */
+ int (*fwd_lookup) (struct _icmLuBase *p, double *out, double *in);
+ int (*bwd_lookup) (struct _icmLuBase *p, double *out, double *in);
+
+ /* Components of lookup */
+ int (*fwd_curve) (struct _icmLuMono *p, double *out, double *in);
+ int (*fwd_map) (struct _icmLuMono *p, double *out, double *in);
+ int (*fwd_abs) (struct _icmLuMono *p, double *out, double *in);
+ int (*bwd_abs) (struct _icmLuMono *p, double *out, double *in);
+ int (*bwd_map) (struct _icmLuMono *p, double *out, double *in);
+ int (*bwd_curve) (struct _icmLuMono *p, double *out, double *in);
+
+}; typedef struct _icmLuMono icmLuMono;
+
+/* 3D Matrix Fwd & Bwd type object */
+struct _icmLuMatrix {
+ LU_ICM_NN_BASE_MEMBERS
+ icmCurve *redCurve, *greenCurve, *blueCurve;
+ icmXYZArray *redColrnt, *greenColrnt, *blueColrnt;
+ double mx[3][3]; /* 3 * 3 conversion matrix */
+ double bmx[3][3]; /* 3 * 3 backwards conversion matrix */
+
+ /* Overall lookups */
+ int (*fwd_lookup) (struct _icmLuBase *p, double *out, double *in);
+ int (*bwd_lookup) (struct _icmLuBase *p, double *out, double *in);
+
+ /* Components of lookup */
+ int (*fwd_curve) (struct _icmLuMatrix *p, double *out, double *in);
+ int (*fwd_matrix) (struct _icmLuMatrix *p, double *out, double *in);
+ int (*fwd_abs) (struct _icmLuMatrix *p, double *out, double *in);
+ int (*bwd_abs) (struct _icmLuMatrix *p, double *out, double *in);
+ int (*bwd_matrix) (struct _icmLuMatrix *p, double *out, double *in);
+ int (*bwd_curve) (struct _icmLuMatrix *p, double *out, double *in);
+
+}; typedef struct _icmLuMatrix icmLuMatrix;
+
+/* Multi-D. Lut type object */
+struct _icmLuLut {
+ LU_ICM_NN_BASE_MEMBERS
+
+ /* private: */
+ icmLut *lut; /* Lut to use */
+ int usematrix; /* non-zero if matrix should be used */
+ double imx[3][3]; /* 3 * 3 inverse conversion matrix */
+ int imx_valid; /* Inverse matrix is valid */
+ void (*in_normf)(double *out, double *in); /* Lut input data normalizing function */
+ void (*in_denormf)(double *out, double *in);/* Lut input data de-normalizing function */
+ void (*out_normf)(double *out, double *in); /* Lut output data normalizing function */
+ void (*out_denormf)(double *out, double *in);/* Lut output de-normalizing function */
+ void (*e_in_denormf)(double *out, double *in);/* Effective input de-normalizing function */
+ void (*e_out_denormf)(double *out, double *in);/* Effecive output de-normalizing function */
+ /* function chosen out of lut->lookup_clut_sx and lut->lookup_clut_nl to imp. clut() */
+ int (*lookup_clut) (struct _icmLut *pp, double *out, double *in); /* clut function */
+
+ /* public: */
+
+ /* Components of lookup */
+ int (*in_abs) (struct _icmLuLut *p, double *out, double *in); /* Should be in icmLut ? */
+ int (*matrix) (struct _icmLuLut *p, double *out, double *in);
+ int (*input) (struct _icmLuLut *p, double *out, double *in);
+ int (*clut) (struct _icmLuLut *p, double *out, double *in);
+ int (*output) (struct _icmLuLut *p, double *out, double *in);
+ int (*out_abs) (struct _icmLuLut *p, double *out, double *in); /* Should be in icmLut ? */
+
+ /* Some inverse components, in reverse order */
+ /* Should be in icmLut ??? */
+ int (*inv_out_abs) (struct _icmLuLut *p, double *out, double *in);
+ int (*inv_output) (struct _icmLuLut *p, double *out, double *in);
+ /* inv_clut is beyond scope of icclib. See argyll for solution! */
+ int (*inv_input) (struct _icmLuLut *p, double *out, double *in);
+ int (*inv_matrix) (struct _icmLuLut *p, double *out, double *in);
+ int (*inv_in_abs) (struct _icmLuLut *p, double *out, double *in);
+
+ /* Get various types of information about the LuLut */
+ /* (Note that there's no reason why white/black point info */
+ /* isn't being made available for other Lu types) */
+ void (*get_info) (struct _icmLuLut *p, icmLut **lutp,
+ icmXYZNumber *pcswhtp, icmXYZNumber *whitep,
+ icmXYZNumber *blackp);
+
+ /* Get the matrix contents */
+ void (*get_matrix) (struct _icmLuLut *p, double m[3][3]);
+
+}; typedef struct _icmLuLut icmLuLut;
+
+/* Named colors lookup object */
+struct _icmLuNamed {
+ LU_ICM_BASE_MEMBERS
+
+ /* Private: */
+
+ /* Public: */
+
+ /* Get various types of information about the Named lookup */
+ void (*get_info) (struct _icmLuLut *p,
+ icmXYZNumber *pcswhtp, icmXYZNumber *whitep,
+ icmXYZNumber *blackp,
+ int *maxnamesize,
+ int *num_colors, char *prefix, char *suffix);
+
+
+ /* Lookup a name that includes prefix and suffix */
+ int (*fullname_lookup) (struct _icmLuNamed *p, double *pcs, double *dev, char *in);
+
+ /* Lookup a name that doesn't include prefix and suffix */
+ int (*name_lookup) (struct _icmLuNamed *p, double *pcs, double *dev, char *in);
+
+ /* Fill in a list with the nout closest named colors to the pcs target */
+ int (*pcs_lookup) (struct _icmLuNamed *p, char **out, int nout, double *in);
+
+ /* Fill in a list with the nout closest named colors to the device target */
+ int (*dev_lookup) (struct _icmLuNamed *p, char **out, int nout, double *in);
+
+}; typedef struct _icmLuNamed icmLuNamed;
+
+/* ---------------------------------------------------------- */
+/* A tag */
+typedef struct {
+ icTagSignature sig; /* The tag signature */
+ icTagTypeSignature ttype; /* The tag type signature */
+ unsigned int offset; /* File offset to start header */
+ unsigned int size; /* Size in bytes (not including padding) */
+ unsigned int pad; /* Padding in bytes */
+ icmBase *objp; /* In memory data structure */
+} icmTag;
+
+/* Pseudo enumerations valid as parameter to get_luobj(): */
+
+/* Special purpose Perceptual intent */
+#define icmAbsolutePerceptual ((icRenderingIntent)97)
+
+/* Special purpose Saturation intent */
+#define icmAbsoluteSaturation ((icRenderingIntent)98)
+
+/* To be specified where an intent is not appropriate */
+#define icmDefaultIntent ((icRenderingIntent)99)
+
+/* Pseudo PCS colospace used to indicate the native PCS */
+#define icmSigDefaultData ((icColorSpaceSignature) 0x0)
+
+/* Pseudo colospace used to indicate a named colorspace */
+#define icmSigNamedData ((icColorSpaceSignature) 0x1)
+
+
+/* Arguments to set a non-default creation version */
+typedef enum {
+ icmVersionDefault = 0, /* Version 2.2.0 is default */
+ icmVersion2_3 = 1, /* Version 2.3.0 - Chromaticity Tag */
+ icmVersion2_4 = 2, /* Version 2.4.0 - Display etc. have intents */
+ icmVersion4_1 = 3, /* Version 4.1.0 - General V4 features */
+} icmICCVersion;
+
+/* The ICC object */
+struct _icc {
+ /* Public: */
+ icmFile *(*get_rfp)(struct _icc *p); /* Return the current read fp (if any) */
+ int (*set_version)(struct _icc *p, icmICCVersion ver);
+ /* For creation, use ICC V4 etc. */
+ unsigned int (*get_size)(struct _icc *p); /* Return total size needed, 0 = err. */
+ int (*read)(struct _icc *p, icmFile *fp, unsigned int of); /* Returns error code */
+ int (*read_x)(struct _icc *p, icmFile *fp, unsigned int of, int take_fp);
+ int (*write)(struct _icc *p, icmFile *fp, unsigned int of);/* Returns error code */
+ int (*write_x)(struct _icc *p, icmFile *fp, unsigned int of, int take_fp);
+ void (*dump)(struct _icc *p, icmFile *op, int verb); /* Dump whole icc */
+ void (*del)(struct _icc *p); /* Free whole icc */
+ int (*find_tag)(struct _icc *p, icTagSignature sig);
+ /* Returns 0 if found, 1 if found but not readable, 2 of not found */
+ icmBase * (*read_tag)(struct _icc *p, icTagSignature sig);
+ /* Returns pointer to object */
+ icmBase * (*read_tag_any)(struct _icc *p, icTagSignature sig);
+ /* Returns pointer to object, but may be icmSigUnknownType! */
+ icmBase * (*add_tag)(struct _icc *p, icTagSignature sig, icTagTypeSignature ttype);
+ /* Returns pointer to object */
+ int (*rename_tag)(struct _icc *p, icTagSignature sig, icTagSignature sigNew);
+ /* Rename and existing tag */
+ icmBase * (*link_tag)(struct _icc *p, icTagSignature sig, icTagSignature ex_sig);
+ /* Returns pointer to object */
+ int (*unread_tag)(struct _icc *p, icTagSignature sig);
+ /* Unread a tag (free on refcount == 0 */
+ int (*read_all_tags)(struct _icc *p); /* Read all the tags, non-zero on error. */
+
+ int (*delete_tag)(struct _icc *p, icTagSignature sig);
+ /* Returns 0 if deleted OK */
+ int (*check_id)(struct _icc *p, ORD8 *id); /* Returns 0 if ID is OK, 1 if not present etc. */
+ double (*get_tac)(struct _icc *p, double *chmax, /* Returns total ink limit and channel maximums */
+ void (*calfunc)(void *cntx, double *out, double *in), void *cntx); /* optional cal. lookup */
+
+ /* Get a particular color conversion function */
+ icmLuBase * (*get_luobj) (struct _icc *p,
+ icmLookupFunc func, /* Functionality */
+ icRenderingIntent intent, /* Intent */
+ icColorSpaceSignature pcsor, /* PCS override (0 = def) */
+ icmLookupOrder order); /* Search Order */
+ /* Return appropriate lookup object */
+ /* NULL on error, check errc+err for reason */
+
+ /* Low level - load specific cLUT conversion */
+ icmLuBase * (*new_clutluobj)(struct _icc *p,
+ icTagSignature ttag, /* Target Lut tag */
+ icColorSpaceSignature inSpace, /* Native Input color space */
+ icColorSpaceSignature outSpace, /* Native Output color space */
+ icColorSpaceSignature pcs, /* Native PCS (from header) */
+ icColorSpaceSignature e_inSpace, /* Override Inpt color space */
+ icColorSpaceSignature e_outSpace, /* Override Outpt color space */
+ icColorSpaceSignature e_pcs, /* Override PCS */
+ icRenderingIntent intent, /* Rendering intent (For abs.) */
+ icmLookupFunc func); /* For icmLuSpaces() */
+ /* Return appropriate lookup object */
+ /* NULL on error, check errc+err for reason */
+
+ icmHeader *header; /* The header */
+ char err[512]; /* Error message */
+ int errc; /* Error code */
+ int warnc; /* Warning code */
+
+ /* Private: ? */
+ icmAlloc *al; /* Heap allocator */
+ int del_al; /* NZ if heap allocator should be deleted */
+ icmFile *fp; /* File associated with object */
+ int del_fp; /* NZ if File should be deleted */
+ unsigned int of; /* Offset of the profile within the file */
+ unsigned int count; /* Num tags in the profile */
+ icmTag *data; /* The tagTable and tagData */
+ icmICCVersion ver; /* Version class, see icmICCVersion enum */
+
+ }; typedef struct _icc icc;
+
+/* ========================================================== */
+/* Utility structures and declarations */
+
+/* Type of primitives that can be read or written */
+typedef enum {
+ icmUInt8Number,
+ icmUInt16Number,
+ icmUInt32Number,
+ icmUInt64Number,
+ icmU8Fixed8Number,
+ icmU16Fixed16Number,
+ icmSInt8Number,
+ icmSInt16Number,
+ icmSInt32Number,
+ icmSInt64Number,
+ icmS15Fixed16Number,
+ icmDCS8Number,
+ icmDCS16Number,
+ icmPCSNumber, /* 16 bit PCS of profile */
+ icmPCSXYZNumber, /* 16 bit XYZ */
+ icmPCSLab8Number, /* 8 bit Lab */
+ icmPCSLabNumber, /* 16 bit Lab of profile */
+ icmPCSLabV2Number, /* 16 bit Lab Version 2 */
+ icmPCSLabV4Number /* 16 bit Lab Version 4 */
+} icmPrimType;
+
+/* Structure to hold pseudo-hilbert counter info */
+struct _psh {
+ int di; /* Dimensionality */
+ unsigned int res; /* Resolution per coordinate */
+ unsigned int bits; /* Bits per coordinate */
+ unsigned int ix; /* Current binary index */
+ unsigned int tmask; /* Total 2^n count mask */
+ unsigned int count; /* Usable count */
+}; typedef struct _psh psh;
+
+/* Type of encoding to be returned as a string */
+typedef enum {
+ icmScreenEncodings,
+ icmDeviceAttributes,
+ icmProfileHeaderFlags,
+ icmAsciiOrBinaryData,
+ icmTagSignature,
+ icmTechnologySignature,
+ icmTypeSignature,
+ icmColorSpaceSignature,
+ icmProfileClassSignature,
+ icmPlatformSignature,
+ icmMeasurementFlare,
+ icmMeasurementGeometry,
+ icmRenderingIntent,
+ icmTransformLookupFunc,
+ icmSpotShape,
+ icmStandardObserver,
+ icmIlluminant,
+ icmLuAlg
+} icmEnumType;
+
+
+/* A helper object that computes MD5 checksums */
+struct _icmMD5 {
+ /* Private: */
+// icc *icp; /* ICC we're part of */
+ icmAlloc *al; /* Heap allocator */
+ int fin; /* Flag, nz if final has been called */
+ ORD32 sum[4]; /* Current/final checksum */
+ unsigned int tlen; /* Total length added in bytes */
+ ORD8 buf[64]; /* Partial buffer */
+
+ /* Public: */
+ void (*reset)(struct _icmMD5 *p); /* Reset the checksum */
+ void (*add)(struct _icmMD5 *p, ORD8 *buf, unsigned int len); /* Add some bytes */
+ void (*get)(struct _icmMD5 *p, ORD8 chsum[16]); /* Finalise and get the checksum */
+ void (*del)(struct _icmMD5 *p); /* We're done with the object */
+
+}; typedef struct _icmMD5 icmMD5;
+
+/* Create a new MD5 checksumming object, with a reset checksum value */
+/* Return it or NULL if there is an error */
+icmMD5 *new_icmMD5(icmAlloc *al);
+
+
+/* Implementation of file access class to compute an MD5 checksum */
+struct _icmFileMD5 {
+ ICM_FILE_BASE
+ int (*get_errc)(struct _icmFile *p); /* Check if there was an error */
+
+ /* Private: */
+ icmAlloc *al; /* Heap allocator */
+ icmMD5 *md5; /* MD5 object */
+ unsigned int of; /* Current offset */
+ int errc; /* Error code, 0 for OK */
+
+ /* Private: */
+ size_t size; /* Size of the file (For read) */
+
+}; typedef struct _icmFileMD5 icmFileMD5;
+
+/* Create a dumy file access class with allocator */
+icmFile *new_icmFileMD5_a(icmMD5 *md5, icmAlloc *al);
+
+
+/* ========================================================== */
+/* Public function declarations */
+/* Create an empty object. Return null on error */
+extern ICCLIB_API icc *new_icc_a(icmAlloc *al); /* With allocator class */
+
+/* If SEPARATE_STD not defined: */
+extern ICCLIB_API icc *new_icc(void); /* Default allocator */
+
+/* - - - - - - - - - - - - - */
+/* Some useful utilities: */
+
+/* Default ICC profile file extension string */
+
+#if defined (UNIX) || defined(__APPLE__)
+#define ICC_FILE_EXT ".icc"
+#define ICC_FILE_EXT_ND "icc"
+#else
+#define ICC_FILE_EXT ".icm"
+#define ICC_FILE_EXT_ND "icm"
+#endif
+
+/* Read a given primitive type. Return non-zero on error */
+extern ICCLIB_API int read_Primitive(icc *icpp, icmPrimType ptype, void *prim, char *p);
+
+/* Write a given primitive type. Return non-zero on error */
+extern ICCLIB_API int write_Primitive(icc *icp, icmPrimType ptype, char *p, void *prim);
+
+/* Return a string that represents a tag */
+extern ICCLIB_API char *tag2str(int tag);
+
+/* Return a tag created from a string */
+extern ICCLIB_API unsigned int str2tag(const char *str);
+
+/* Utility to define a non-standard tag, arguments are 4 character constants */
+#define icmMakeTag(A,B,C,D) \
+ ( (((ORD32)(ORD8)(A)) << 24) \
+ | (((ORD32)(ORD8)(B)) << 16) \
+ | (((ORD32)(ORD8)(C)) << 8) \
+ | ((ORD32)(ORD8)(D)) )
+
+/* Return a string description of the given enumeration value */
+extern ICCLIB_API const char *icm2str(icmEnumType etype, int enumval);
+
+/* Return the number of channels for the given color space. Return 0 if unknown. */
+extern ICCLIB_API unsigned int icmCSSig2nchan(icColorSpaceSignature sig);
+
+/* Return the individual channel names and number of channels give a colorspace signature. */
+/* Return 0 if it is not a colorspace that itself defines particular channels, */
+/* 1 if it is a colorant based colorspace, and 2 if it is not a colorant based space */
+extern ICCLIB_API unsigned int icmCSSig2chanNames( icColorSpaceSignature sig, char *cvals[]);
+
+
+/* Simple macro to transfer an array to an XYZ number */
+#define icmAry2XYZ(xyz, ary) ((xyz).X = (ary)[0], (xyz).Y = (ary)[1], (xyz).Z = (ary)[2])
+
+/* And the reverse */
+#define icmXYZ2Ary(ary, xyz) ((ary)[0] = (xyz).X, (ary)[1] = (xyz).Y, (ary)[2] = (xyz).Z)
+
+/* Simple macro to transfer an XYZ number to an XYZ number */
+#define icmXYZ2XYZ(d_xyz, s_xyz) ((d_xyz).X = (s_xyz).X, (d_xyz).Y = (s_xyz).Y, \
+ (d_xyz).Z = (s_xyz).Z)
+
+/* Simple macro to transfer an 3array to 3array */
+/* Hmm. Same as icmCpy3 */
+#define icmAry2Ary(d_ary, s_ary) ((d_ary)[0] = (s_ary)[0], (d_ary)[1] = (s_ary)[1], \
+ (d_ary)[2] = (s_ary)[2])
+
+/* CIE Y (range 0 .. 1) to perceptual CIE 1976 L* (range 0 .. 100) */
+double icmY2L(double val);
+
+/* Perceptual CIE 1976 L* (range 0 .. 100) to CIE Y (range 0 .. 1) */
+double icmL2Y(double val);
+
+/* CIE XYZ to perceptual Lab */
+extern ICCLIB_API void icmXYZ2Lab(icmXYZNumber *w, double *out, double *in);
+
+/* Perceptual Lab to CIE XYZ */
+extern ICCLIB_API void icmLab2XYZ(icmXYZNumber *w, double *out, double *in);
+
+/* LCh to Lab */
+extern ICCLIB_API void icmLCh2Lab(double *out, double *in);
+
+/* Lab to LCh */
+extern ICCLIB_API void icmLab2LCh(double *out, double *in);
+
+/* XYZ to Yxy */
+extern ICCLIB_API void icmXYZ2Yxy(double *out, double *in);
+
+/* Yxy to XYZ */
+extern ICCLIB_API void icmYxy2XYZ(double *out, double *in);
+
+/* CIE XYZ to perceptual Luv */
+extern ICCLIB_API void icmXYZ2Luv(icmXYZNumber *w, double *out, double *in);
+
+/* Perceptual Luv to CIE XYZ */
+extern ICCLIB_API void icmLuv2XYZ(icmXYZNumber *w, double *out, double *in);
+
+
+/* NOTE :- none of the following seven have been protected */
+/* against arithmmetic issues (ie. for black) */
+
+/* CIE XYZ to perceptual CIE 1976 UCS diagram Yu'v'*/
+/* (Yu'v' is a better chromaticity space than Yxy) */
+extern ICCLIB_API void icmXYZ21976UCS(double *out, double *in);
+
+/* Perceptual CIE 1976 UCS diagram Yu'v' to CIE XYZ */
+extern ICCLIB_API void icm1976UCS2XYZ(double *out, double *in);
+
+/* CIE XYZ to perceptual CIE 1960 UCS */
+/* (This was obsoleted by the 1976UCS, but is still used */
+/* in computing color temperatures.) */
+extern ICCLIB_API void icmXYZ21960UCS(double *out, double *in);
+
+/* Perceptual CIE 1960 UCS to CIE XYZ */
+extern ICCLIB_API void icm1960UCS2XYZ(double *out, double *in);
+
+/* CIE XYZ to perceptual CIE 1964 WUV (U*V*W*) */
+/* (This is obsolete but still used in computing CRI) */
+extern ICCLIB_API void icmXYZ21964WUV(icmXYZNumber *w, double *out, double *in);
+
+/* Perceptual CIE 1964 WUV (U*V*W*) to CIE XYZ */
+extern ICCLIB_API void icm1964WUV2XYZ(icmXYZNumber *w, double *out, double *in);
+
+/* CIE CIE1960 UCS to perceptual CIE 1964 WUV (U*V*W*) */
+extern ICCLIB_API void icm1960UCS21964WUV(icmXYZNumber *w, double *out, double *in);
+
+
+/* The standard D50 illuminant value */
+extern icmXYZNumber icmD50;
+extern icmXYZNumber icmD50_100; /* Scaled to 100 */
+double icmD50_ary3[3]; /* As an array */
+double icmD50_100_ary3[3]; /* Scaled to 100 as an array */
+
+/* The standard D65 illuminant value */
+extern icmXYZNumber icmD65;
+extern icmXYZNumber icmD65_100; /* Scaled to 100 */
+double icmD65_ary3[3]; /* As an array */
+double icmD65_100_ary3[3]; /* Scaled to 100 as an array */
+
+/* The default black value */
+extern icmXYZNumber icmBlack;
+
+
+/* Initialise a pseudo-hilbert grid counter, return total usable count. */
+extern ICCLIB_API unsigned psh_init(psh *p, int di, unsigned int res, int co[]);
+
+/* Reset the counter */
+extern ICCLIB_API void psh_reset(psh *p);
+
+/* Increment pseudo-hilbert coordinates */
+/* Return non-zero if count rolls over to 0 */
+extern ICCLIB_API int psh_inc(psh *p, int co[]);
+
+
+/* RGB primaries to device to RGB->XYZ transform matrix */
+/* Return non-zero if matrix would be singular */
+int icmRGBprim2matrix(
+ icmXYZNumber white, /* White point */
+ icmXYZNumber red, /* Red colorant */
+ icmXYZNumber green, /* Green colorant */
+ icmXYZNumber blue, /* Blue colorant */
+ double mat[3][3] /* Destination matrix */
+);
+
+/* Chromatic Adaption transform utility */
+/* Return a 3x3 chromatic adaption matrix */
+/* Use icmMulBy3x3(dst, mat, src) */
+
+#define ICM_CAM_BRADFORD 0x0001 /* Use Bradford sharpened response space */
+#define ICM_CAM_MULMATRIX 0x0002 /* Transform the given matrix */
+
+void icmChromAdaptMatrix(
+ int flags, /* Flags as defined below */
+ icmXYZNumber d_wp, /* Destination white point */
+ icmXYZNumber s_wp, /* Source white point */
+ double mat[3][3] /* Destination matrix */
+);
+
+/* - - - - - - - - - - - - - - */
+/* Set a 3 vector */
+#define icmSet3(d_ary, s_val) ((d_ary)[0] = (s_val), (d_ary)[1] = (s_val), \
+ (d_ary)[2] = (s_val))
+
+/* Copy a 3 vector */
+#define icmCpy3(d_ary, s_ary) ((d_ary)[0] = (s_ary)[0], (d_ary)[1] = (s_ary)[1], \
+ (d_ary)[2] = (s_ary)[2])
+
+/* Clamp a 3 vector to be +ve */
+void icmClamp3(double out[3], double in[3]);
+
+/* Add two 3 vectors */
+void icmAdd3(double out[3], double in1[3], double in2[3]);
+
+#define ICMADD3(o, i, j) ((o)[0] = (i)[0] + (j)[0], (o)[1] = (i)[1] + (j)[1], (o)[2] = (i)[2] + (j)[2])
+
+/* Subtract two 3 vectors, out = in1 - in2 */
+void icmSub3(double out[3], double in1[3], double in2[3]);
+
+#define ICMSUB3(o, i, j) ((o)[0] = (i)[0] - (j)[0], (o)[1] = (i)[1] - (j)[1], (o)[2] = (i)[2] - (j)[2])
+
+/* Compute the dot product of two 3 vectors */
+double icmDot3(double in1[3], double in2[3]);
+
+#define ICMDOT3(o, i, j) ((o) = (i)[0] * (j)[0] + (i)[1] * (j)[1] + (i)[2] * (j)[2])
+
+/* Compute the cross product of two 3D vectors, out = in1 x in2 */
+void icmCross3(double out[3], double in1[3], double in2[3]);
+
+/* Compute the norm squared (length squared) of a 3 vector */
+double icmNorm3sq(double in[3]);
+
+#define ICMNORM3SQ(i) ((i)[0] * (i)[0] + (i)[1] * (i)[1] + (i)[2] * (i)[2])
+
+/* Compute the norm (length) of a 3 vector */
+double icmNorm3(double in[3]);
+
+#define ICMNORM3(i) sqrt((i)[0] * (i)[0] + (i)[1] * (i)[1] + (i)[2] * (i)[2])
+
+/* Scale a 3 vector by the given ratio */
+void icmScale3(double out[3], double in[3], double rat);
+
+/* Compute a blend between in0 and in1 */
+void icmBlend3(double out[3], double in0[3], double in1[3], double bf);
+
+#define ICMSCALE3(o, i, j) ((o)[0] = (i)[0] * (j), (o)[1] = (i)[1] * (j), (o)[2] = (i)[2] * (j))
+
+/* Normalise a 3 vector to the given length. Return nz if not normalisable */
+int icmNormalize3(double out[3], double in[3], double len);
+
+/* Compute the norm squared (length squared) of a vector defined by two points */
+double icmNorm33sq(double in1[3], double in0[3]);
+
+/* Compute the norm (length) of of a vector defined by two points */
+double icmNorm33(double in1[3], double in0[3]);
+
+/* Scale a two point vector by the given ratio. in0[] is the origin. */
+void icmScale33(double out[3], double in1[3], double in0[3], double rat);
+
+/* Normalise a two point vector to the given length. */
+/* The new location of in1[] is returned in out[], in0[] is the origin. */
+/* Return nz if not normalisable */
+int icmNormalize33(double out[3], double in1[3], double in0[3], double len);
+
+
+/* Set a 3x3 matrix to unity */
+void icmSetUnity3x3(double mat[3][3]);
+
+/* Copy a 3x3 transform matrix */
+void icmCpy3x3(double out[3][3], double mat[3][3]);
+
+/* Scale each element of a 3x3 transform matrix */
+void icmScale3x3(double dst[3][3], double src[3][3], double scale);
+
+/* Multiply 3 vector by 3x3 transform matrix */
+/* Organization is mat[out][in] */
+void icmMulBy3x3(double out[3], double mat[3][3], double in[3]);
+
+/* Add one 3x3 to another */
+/* dst = src1 + src2 */
+void icmAdd3x3(double dst[3][3], double src1[3][3], double src2[3][3]);
+
+/* Tensor product. Multiply two 3 vectors to form a 3x3 matrix */
+/* src1[] forms the colums, and src2[] forms the rows in the result */
+void icmTensMul3(double dst[3][3], double src1[3], double src2[3]);
+
+/* Multiply one 3x3 with another */
+/* dst = src * dst */
+void icmMul3x3(double dst[3][3], double src[3][3]);
+
+/* Multiply one 3x3 with another #2 */
+/* dst = src1 * src2 */
+void icmMul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]);
+
+/* Compute the determinant of a 3x3 matrix */
+double icmDet3x3(double in[3][3]);
+
+/* Invert a 3x3 transform matrix. Return 1 if error. */
+int icmInverse3x3(double out[3][3], double in[3][3]);
+
+/* Transpose a 3x3 matrix */
+void icmTranspose3x3(double out[3][3], double in[3][3]);
+
+/* Given two 3D points, create a matrix that rotates */
+/* and scales one onto the other about the origin 0,0,0. */
+/* Use icmMulBy3x3() to apply this to other points */
+void icmRotMat(double mat[3][3], double src[3], double targ[3]);
+
+/* Copy a 3x4 transform matrix */
+void icmCpy3x4(double out[3][4], double mat[3][4]);
+
+/* Multiply 3 array by 3x4 transform matrix */
+void icmMul3By3x4(double out[3], double mat[3][4], double in[3]);
+
+/* Given two 3D vectors, create a matrix that translates, */
+/* rotates and scales one onto the other. */
+/* Use icmMul3By3x4 to apply this to other points */
+void icmVecRotMat(double m[3][4], double s1[3], double s0[3], double t1[3], double t0[3]);
+
+
+/* Compute the intersection of a vector and a plane */
+/* return nz if there is no intersection */
+int icmVecPlaneIsect(double isect[3], double pl_const, double pl_norm[3], double ve_1[3], double ve_0[3]);
+
+/* Compute the closest points between two lines a and b. */
+/* Return closest points and parameter values if not NULL. */
+/* Return nz if they are paralel. */
+int icmLineLineClosest(double ca[3], double cb[3], double *pa, double *pb,
+ double la0[3], double la1[3], double lb0[3], double lb1[3]);
+
+/* Given 3 3D points, compute a plane equation. */
+/* The normal will be right handed given the order of the points */
+/* The plane equation will be the 3 normal components and the constant. */
+/* Return nz if any points are cooincident or co-linear */
+int icmPlaneEqn3(double eq[4], double p0[3], double p1[3], double p2[3]);
+
+/* Given a 3D point and a plane equation, return the signed */
+/* distance from the plane */
+double icmPlaneDist3(double eq[4], double p[3]);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Multiply 2 array by 2x2 transform matrix */
+void icmMulBy2x2(double out[2], double mat[2][2], double in[2]);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return the normal Delta E given two Lab values */
+extern ICCLIB_API double icmLabDE(double *in0, double *in1);
+
+/* Return the normal Delta E squared, given two Lab values */
+extern ICCLIB_API double icmLabDEsq(double *in0, double *in1);
+
+/* Return the normal Delta E given two XYZ values */
+extern ICCLIB_API double icmXYZLabDE(icmXYZNumber *w, double *in0, double *in1);
+
+
+/* Return the CIE94 Delta E color difference measure for two Lab values */
+extern ICCLIB_API double icmCIE94(double *in0, double *in1);
+
+/* Return the CIE94 Delta E color difference measure squared, for two Lab values */
+extern ICCLIB_API double icmCIE94sq(double *in0, double *in1);
+
+/* Return the CIE94 Delta E color difference measure for two XYZ values */
+extern ICCLIB_API double icmXYZCIE94(icmXYZNumber *w, double *in0, double *in1);
+
+
+/* Return the CIEDE2000 Delta E color difference measure for two Lab values */
+extern ICCLIB_API double icmCIE2K(double *in0, double *in1);
+
+/* Return the CIEDE2000 Delta E color difference measure squared, for two Lab values */
+extern ICCLIB_API double icmCIE2Ksq(double *in0, double *in1);
+
+/* Return the CIEDE2000 Delta E color difference measure for two XYZ values */
+extern ICCLIB_API double icmXYZCIE2K(icmXYZNumber *w, double *in0, double *in1);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Clip Lab, while maintaining hue angle. */
+/* Return nz if clipping occured */
+int icmClipLab(double out[3], double in[3]);
+
+/* Clip XYZ, while maintaining hue angle */
+/* Return nz if clipping occured */
+int icmClipXYZ(double out[3], double in[3]);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Print an int vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPiv(int di, int *p);
+
+/* Print a double color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPdv(int di, double *p);
+
+/* Print a float color vector to a string. */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPfv(int di, float *p);
+
+/* Print an 0..1 range XYZ as a D50 Lab string */
+/* Returned static buffer is re-used every 5 calls. */
+char *icmPLab(double *p);
+
+/* ---------------------------------------------------------- */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* ICC_H */
+
diff --git a/icc/iccV42.h b/icc/iccV42.h
new file mode 100644
index 0000000..ee3fefb
--- /dev/null
+++ b/icc/iccV42.h
@@ -0,0 +1,555 @@
+
+/*
+ * This file started out as the standard ICC header provided by
+ * the ICC. Since this file no longer seems to be maintained,
+ * I've added new entries from the ICC spec., but dropped
+ * things that are not needed for icclib.
+ *
+ * This version of the header file corresponds to the profile
+ * Specification ICC.1:2003-09 (Version 4.2.0)
+ *
+ * All header file entries are pre-fixed with "ic" to help
+ * avoid name space collisions. Signatures are pre-fixed with
+ * icSig.
+ *
+ * Version numbers used within file are file format version numers,
+ * not spec. version numbers.
+ *
+ * Portions of this file are Copyright 2004 - 2005 Graeme W. Gill,
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ *
+ * Graeme Gill.
+ */
+
+/* Header file guard bands */
+#ifndef ICCV42_H
+#define ICCV42_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*****************************************************************
+ Copyright (c) 1994-1998 SunSoft, Inc.
+
+ Rights Reserved
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without restrict-
+ion, including without limitation the rights to use, copy, modify,
+merge, publish distribute, sublicense, and/or sell copies of the
+Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-
+INFRINGEMENT. IN NO EVENT SHALL SUNSOFT, INC. OR ITS PARENT
+COMPANY BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of SunSoft, Inc.
+shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without written
+authorization from SunSoft Inc.
+******************************************************************/
+
+/*
+ Spec name/version/file version relationship.
+
+ Spec. Name Spec. Version ICC File Version
+ ---------- ------------- ----------------
+ ICC.1:2004-10 4.2 4.2.0
+ ICC.1:2003-09 4.1 4.1.0
+ ICC.1:2001-12 4.0 4.0.0
+ ICC.1:2001-04 (3.7?) 2.4.0
+ ICC.1A:1999-04 (3.6?) 2.3.0
+ ICC.1:1998-09 (3.5?) 2.2.0
+ (Version 3.4) 3.4 2.1.0 (a)
+ (Version 3.3) 3.3 2.1.0
+ (Version 3.2) 3.2 2.0.0 (b)
+ (Version 3.01) 3.01 2.0.0 (a)
+ (Version 3.0) 3.0 2.0.0
+*/
+
+
+#define icMaxTagVal -1
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Defines used in the specification
+ */
+
+#define icMagicNumber 0x61637370L /* 'acsp' */
+#define icVersionNumber 0x02200000L /* 2.2.0, BCD */
+#define icVersionNumberV41 0x04100000L /* 4.1.0, BCD */
+
+/* Screening Encodings */
+#define icPrtrDefaultScreensFalse 0x00000000L /* Bit pos 0 */
+#define icPrtrDefaultScreensTrue 0x00000001L /* Bit pos 0 */
+#define icLinesPerInch 0x00000002L /* Bit pos 1 */
+#define icLinesPerCm 0x00000000L /* Bit pos 1 */
+
+/*
+ * Device attributes, currently defined values correspond
+ * to the least-significant 4 bytes of the 8 byte attribute
+ * quantity, see the header for their location.
+ */
+
+#define icReflective 0x00000000L /* Bit pos 0 */
+#define icTransparency 0x00000001L /* Bit pos 0 */
+#define icGlossy 0x00000000L /* Bit pos 1 */
+#define icMatte 0x00000002L /* Bit pos 1 */
+#define icPositive 0x00000000L /* Bit pos 2 */
+#define icNegative 0x00000004L /* Bit pos 2 */
+#define icColor 0x00000000L /* Bit pos 3 */
+#define icBlackAndWhite 0x00000008L /* Bit pos 3 */
+
+/*
+ * Profile header flags, the least-significant 16 bits are reserved
+ * for consortium use.
+ */
+
+#define icEmbeddedProfileFalse 0x00000000L /* Bit pos 0 */
+#define icEmbeddedProfileTrue 0x00000001L /* Bit pos 0 */
+#define icUseAnywhere 0x00000000L /* Bit pos 1 */
+#define icUseWithEmbeddedDataOnly 0x00000002L /* Bit pos 1 */
+
+/* Ascii or Binary data */
+#define icAsciiData 0x00000000L
+#define icBinaryData 0x00000001L
+
+/* Phosphor or Colorant sets */
+#define icPhColUnknown 0x0000 /* Specified */
+#define icPhColITU_R_BT_709 0x0001 /* ITU-R BT.709 */
+#define icPhColSMPTE_RP145_1994 0x0002 /* SMPTE RP145-1994 */
+#define icPhColEBU_Tech_3213_E 0x0003 /* EBU Tech.3213-E */
+#define icPhColP22 0x0004 /* P22 */
+
+/* Video card gamma formats (ColorSync 2.5 specific) */
+#define icVideoCardGammaTable 0x00000000
+#define icVideoCardGammaFormula 0x00000001
+
+
+/*------------------------------------------------------------------------*/
+/*
+ * Use this area to translate platform definitions of long
+ * etc into icXXX form. The rest of the header uses the icXXX
+ * typedefs. Signatures are 4 byte quantities.
+ */
+#ifdef ORD32 /* Formal sizes defined elsewhere */
+
+typedef INR32 icSignature;
+
+/* Unsigned integer numbers */
+typedef ORD8 icUInt8Number;
+typedef ORD16 icUInt16Number;
+typedef ORD32 icUInt32Number;
+typedef ORD32 icUInt64Number[2];
+
+/* Signed numbers */
+typedef INR8 icInt8Number;
+typedef INR16 icInt16Number;
+typedef INR32 icInt32Number;
+typedef INR32 icInt64Number[2];
+
+/* Fixed numbers */
+typedef INR32 icS15Fixed16Number;
+typedef ORD32 icU16Fixed16Number;
+
+#else /* default definitions for typical 32 bit architecture */
+
+typedef long icSignature;
+
+/* Unsigned integer numbers */
+typedef unsigned char icUInt8Number;
+typedef unsigned short icUInt16Number;
+typedef unsigned long icUInt32Number;
+typedef unsigned long icUInt64Number[2];
+
+/* Signed numbers */
+typedef char icInt8Number;
+typedef short icInt16Number;
+typedef long icInt32Number;
+typedef long icInt64Number[2];
+
+/* Fixed numbers */
+typedef long icS15Fixed16Number;
+typedef unsigned long icU16Fixed16Number;
+
+#endif /* Not formal */
+
+/*------------------------------------------------------------------------*/
+/* public tags and sizes */
+typedef enum {
+ icSigAToB0Tag = 0x41324230L, /* 'A2B0' */
+ icSigAToB1Tag = 0x41324231L, /* 'A2B1' */
+ icSigAToB2Tag = 0x41324232L, /* 'A2B2' */
+ icSigBlueMatrixColumnTag = 0x6258595AL, /* 'bXYZ' */
+ icSigBlueTRCTag = 0x62545243L, /* 'bTRC' */
+ icSigBToA0Tag = 0x42324130L, /* 'B2A0' */
+ icSigBToA1Tag = 0x42324131L, /* 'B2A1' */
+ icSigBToA2Tag = 0x42324132L, /* 'B2A2' */
+ icSigCalibrationDateTimeTag = 0x63616C74L, /* 'calt' */
+ icSigCharTargetTag = 0x74617267L, /* 'targ' */
+ icSigChromaticAdaptationTag = 0x63686164L, /* 'chad' V2.4+ */
+ icSigChromaticityTag = 0x6368726DL, /* 'chrm' V2.3+ */
+ icSigColorantOrderTag = 0x636C726FL, /* 'clro' V4.0+ */
+ icSigColorantTableTag = 0x636C7274L, /* 'clrt' V4.0+ */
+ icSigColorantTableOutTag = 0x636C6F74L, /* 'clot' V4.0+ */
+ icSigCopyrightTag = 0x63707274L, /* 'cprt' */
+ icSigCrdInfoTag = 0x63726469L, /* 'crdi' V2.1 - V4.0 */
+ icSigDataTag = 0x64617461L, /* 'data' ??? */
+ icSigDateTimeTag = 0x6474696DL, /* 'dtim' ??? */
+ icSigDeviceMfgDescTag = 0x646D6E64L, /* 'dmnd' */
+ icSigDeviceModelDescTag = 0x646D6464L, /* 'dmdd' */
+ icSigDeviceSettingsTag = 0x64657673L, /* 'devs' V2.2 - V4.0 */
+ icSigGamutTag = 0x67616D74L, /* 'gamt' */
+ icSigGrayTRCTag = 0x6b545243L, /* 'kTRC' */
+ icSigGreenMatrixColumnTag = 0x6758595AL, /* 'gXYZ' */
+ icSigGreenTRCTag = 0x67545243L, /* 'gTRC' */
+ icSigLuminanceTag = 0x6C756d69L, /* 'lumi' */
+ icSigMeasurementTag = 0x6D656173L, /* 'meas' */
+ icSigMediaBlackPointTag = 0x626B7074L, /* 'bkpt' */
+ icSigMediaWhitePointTag = 0x77747074L, /* 'wtpt' */
+ icSigNamedColorTag = 0x6E636f6CL, /* 'ncol' V2.0 */
+ icSigNamedColor2Tag = 0x6E636C32L, /* 'ncl2' V2.1+ */
+ icSigOutputResponseTag = 0x72657370L, /* 'resp' V2.2+ */
+ icSigPerceptualRenderingIntentGamutTag = 0x72696730L, /* 'rig0' ??? */
+ icSigPreview0Tag = 0x70726530L, /* 'pre0' */
+ icSigPreview1Tag = 0x70726531L, /* 'pre1' */
+ icSigPreview2Tag = 0x70726532L, /* 'pre2' */
+ icSigProfileDescriptionTag = 0x64657363L, /* 'desc' */
+ icSigProfileSequenceDescTag = 0x70736571L, /* 'pseq' */
+ icSigPs2CRD0Tag = 0x70736430L, /* 'psd0' V2.0 - V4.0 */
+ icSigPs2CRD1Tag = 0x70736431L, /* 'psd1' V2.0 - V4.0 */
+ icSigPs2CRD2Tag = 0x70736432L, /* 'psd2' V2.0 - V4.0 */
+ icSigPs2CRD3Tag = 0x70736433L, /* 'psd3' V2.0 - V4.0 */
+ icSigPs2CSATag = 0x70733273L, /* 'ps2s' V2.0 - V4.0 */
+ icSigPs2RenderingIntentTag = 0x70733269L, /* 'ps2i' V2.0 - V4.0 */
+ icSigRedMatrixColumnTag = 0x7258595AL, /* 'rXYZ' */
+ icSigRedTRCTag = 0x72545243L, /* 'rTRC' */
+ icSigSaturationRenderingIntentGamutTag = 0x72696732L, /* 'rig2' ??? */
+ icSigScreeningDescTag = 0x73637264L, /* 'scrd' V2.0 - V4.0 */
+ icSigScreeningTag = 0x7363726EL, /* 'scrn' V2.0 - V4.0 */
+ icSigTechnologyTag = 0x74656368L, /* 'tech' */
+ icSigUcrBgTag = 0x62666420L, /* 'bfd ' V2.0 - V4.0 */
+ icSigVideoCardGammaTag = 0x76636774L, /* 'vcgt' ColorSync 2.5+ */
+ icSigViewingCondDescTag = 0x76756564L, /* 'vued' */
+ icSigViewingConditionsTag = 0x76696577L, /* 'view' */
+ icMaxEnumTag = icMaxTagVal
+} icTagSignature;
+
+/* Aliases for backwards compatibility */
+#define icSigBlueColorantTag icSigBlueMatrixColumnTag /* Prior to V4.0 */
+#define icSigGreenColorantTag icSigGreenMatrixColumnTag /* Prior to V4.0 */
+#define icSigRedColorantTag icSigRedMatrixColumnTag /* Prior to V4.0 */
+
+/* technology signature descriptions */
+typedef enum {
+ icSigDigitalCamera = 0x6463616DL, /* 'dcam' */
+ icSigFilmScanner = 0x6673636EL, /* 'fscn' */
+ icSigReflectiveScanner = 0x7273636EL, /* 'rscn' */
+ icSigInkJetPrinter = 0x696A6574L, /* 'ijet' */
+ icSigThermalWaxPrinter = 0x74776178L, /* 'twax' */
+ icSigElectrophotographicPrinter = 0x6570686FL, /* 'epho' */
+ icSigElectrostaticPrinter = 0x65737461L, /* 'esta' */
+ icSigDyeSublimationPrinter = 0x64737562L, /* 'dsub' */
+ icSigPhotographicPaperPrinter = 0x7270686FL, /* 'rpho' */
+ icSigFilmWriter = 0x6670726EL, /* 'fprn' */
+ icSigVideoMonitor = 0x7669646DL, /* 'vidm' */
+ icSigVideoCamera = 0x76696463L, /* 'vidc' */
+ icSigProjectionTelevision = 0x706A7476L, /* 'pjtv' */
+ icSigCRTDisplay = 0x43525420L, /* 'CRT ' */
+ icSigPMDisplay = 0x504D4420L, /* 'PMD ' */
+ icSigAMDisplay = 0x414D4420L, /* 'AMD ' */
+ icSigPhotoCD = 0x4B504344L, /* 'KPCD' */
+ icSigPhotoImageSetter = 0x696D6773L, /* 'imgs' */
+ icSigGravure = 0x67726176L, /* 'grav' */
+ icSigOffsetLithography = 0x6F666673L, /* 'offs' */
+ icSigSilkscreen = 0x73696C6BL, /* 'silk' */
+ icSigFlexography = 0x666C6578L, /* 'flex' */
+ icMaxEnumTechnology = icMaxTagVal
+} icTechnologySignature;
+
+/* type signatures */
+typedef enum {
+ icSigChromaticityType = 0x6368726DL, /* 'chrm' */
+ icSigColorantOrderType = 0x636C726FL, /* 'clro' V4.0+ */
+ icSigColorantTableType = 0x636C7274L, /* 'clrt' V4.0+ */
+ icSigCrdInfoType = 0x63726469L, /* 'crdi' V2.1 - V4.0 */
+ icSigCurveType = 0x63757276L, /* 'curv' */
+ icSigDataType = 0x64617461L, /* 'data' */
+ icSigDateTimeType = 0x6474696DL, /* 'dtim' */
+ icSigDeviceSettingsType = 0x64657673L, /* 'devs' V2.2 - V4.0 */
+ icSigLut16Type = 0x6d667432L, /* 'mft2' */
+ icSigLut8Type = 0x6d667431L, /* 'mft1' */
+ icSigLutAtoBType = 0x6d414220L, /* 'mAB ' V4.0+ */
+ icSigLutBtoAType = 0x6d424120L, /* 'mBA ' V4.0+ */
+ icSigMeasurementType = 0x6D656173L, /* 'meas' */
+ icSigMultiLocalizedUnicodeType = 0x6D6C7563L, /* 'mluc' V4.0+ */
+ icSigNamedColorType = 0x6E636f6CL, /* 'ncol' V2.0 */
+ icSigNamedColor2Type = 0x6E636C32L, /* 'ncl2' V2.0+ */
+ icSigParametricCurveType = 0x70617261L, /* 'para' V4.0+ */
+ icSigProfileSequenceDescType = 0x70736571L, /* 'pseq' */
+ icSigResponseCurveSet16Type = 0x72637332L, /* 'rcs2' V2.2 - V4.0 */
+ icSigS15Fixed16ArrayType = 0x73663332L, /* 'sf32' */
+ icSigScreeningType = 0x7363726EL, /* 'scrn' V2.0 - V4.0 */
+ icSigSignatureType = 0x73696720L, /* 'sig ' */
+ icSigTextType = 0x74657874L, /* 'text' */
+ icSigTextDescriptionType = 0x64657363L, /* 'desc' V2.0 - V2.4 */
+ icSigU16Fixed16ArrayType = 0x75663332L, /* 'uf32' */
+ icSigUcrBgType = 0x62666420L, /* 'bfd ' V2.0 - V4.0 */
+ icSigUInt16ArrayType = 0x75693136L, /* 'ui16' */
+ icSigUInt32ArrayType = 0x75693332L, /* 'ui32' */
+ icSigUInt64ArrayType = 0x75693634L, /* 'ui64' */
+ icSigUInt8ArrayType = 0x75693038L, /* 'ui08' */
+ icSigVideoCardGammaType = 0x76636774L, /* 'vcgt' ColorSync 2.5+ */
+ icSigViewingConditionsType = 0x76696577L, /* 'view' */
+ icSigXYZType = 0x58595A20L, /* 'XYZ ' */
+ icSigXYZArrayType = 0x58595A20L, /* 'XYZ ' */
+ icMaxEnumType = icMaxTagVal
+} icTagTypeSignature;
+
+/*
+ * Color Space Signatures
+ * Note that only icSigXYZData and icSigLabData are valid
+ * Profile Connection Spaces (PCSs)
+ */
+typedef enum {
+ icSigXYZData = 0x58595A20L, /* 'XYZ ' */
+ icSigLabData = 0x4C616220L, /* 'Lab ' */
+ icSigLuvData = 0x4C757620L, /* 'Luv ' */
+ icSigYCbCrData = 0x59436272L, /* 'YCbr' */
+ icSigYxyData = 0x59787920L, /* 'Yxy ' */
+ icSigRgbData = 0x52474220L, /* 'RGB ' */
+ icSigGrayData = 0x47524159L, /* 'GRAY' */
+ icSigHsvData = 0x48535620L, /* 'HSV ' */
+ icSigHlsData = 0x484C5320L, /* 'HLS ' */
+ icSigCmykData = 0x434D594BL, /* 'CMYK' */
+ icSigCmyData = 0x434D5920L, /* 'CMY ' */
+
+ icSig2colorData = 0x32434C52L, /* '2CLR' */
+ icSig3colorData = 0x33434C52L, /* '3CLR' */
+ icSig4colorData = 0x34434C52L, /* '4CLR' */
+ icSig5colorData = 0x35434C52L, /* '5CLR' */
+ icSig6colorData = 0x36434C52L, /* '6CLR' */
+ icSig7colorData = 0x37434C52L, /* '7CLR' */
+ icSig8colorData = 0x38434C52L, /* '8CLR' */
+ icSig9colorData = 0x39434C52L, /* '9CLR' */
+ icSig10colorData = 0x41434C52L, /* 'ACLR' */
+ icSig11colorData = 0x42434C52L, /* 'BCLR' */
+ icSig12colorData = 0x43434C52L, /* 'CCLR' */
+ icSig13colorData = 0x44434C52L, /* 'DCLR' */
+ icSig14colorData = 0x45434C52L, /* 'ECLR' */
+ icSig15colorData = 0x46434C52L, /* 'FCLR' */
+
+ icSigMch5Data = 0x4D434835L, /* 'MCH5' Colorsync ? */
+ icSigMch6Data = 0x4D434836L, /* 'MCH6' Hexachrome: CMYKOG */
+ icSigMch7Data = 0x4D434837L, /* 'MCH7' Colorsync ? */
+ icSigMch8Data = 0x4D434838L, /* 'MCH8' Colorsync ? */
+ icSigNamedData = 0x6e6d636cL, /* 'nmcl' ??? */
+
+ icMaxEnumData = icMaxTagVal
+} icColorSpaceSignature;
+
+/* profileClass enumerations */
+typedef enum {
+ icSigInputClass = 0x73636E72L, /* 'scnr' */
+ icSigDisplayClass = 0x6D6E7472L, /* 'mntr' */
+ icSigOutputClass = 0x70727472L, /* 'prtr' */
+ icSigLinkClass = 0x6C696E6BL, /* 'link' */
+ icSigAbstractClass = 0x61627374L, /* 'abst' */
+ icSigColorSpaceClass = 0x73706163L, /* 'spac' */
+ icSigNamedColorClass = 0x6e6d636cL, /* 'nmcl' */
+ icMaxEnumClass = icMaxTagVal
+} icProfileClassSignature;
+
+/* Platform Signatures */
+typedef enum {
+ icSigMacintosh = 0x4150504CL, /* 'APPL' */
+ icSigMicrosoft = 0x4D534654L, /* 'MSFT' */
+ icSigSolaris = 0x53554E57L, /* 'SUNW' */
+ icSigSGI = 0x53474920L, /* 'SGI ' */
+ icSigTaligent = 0x54474E54L, /* 'TGNT' */
+ icMaxEnumPlatform = icMaxTagVal
+} icPlatformSignature;
+
+/* Rendering Intent Gamut Signatures */
+typedef enum {
+ icSigPerceptualReferenceMediumGamut = 0x70726d67L, /* 'prmg' */
+ icMaxEnumReferenceMediumGamut = icMaxTagVal
+} icReferenceMediumGamutSignature;
+
+/*------------------------------------------------------------------------*/
+/*
+ * Other enums
+ */
+
+/* Measurement Flare, used in the measurmentType tag */
+typedef enum {
+ icFlare0 = 0x00000000L, /* 0% flare */
+ icFlare100 = 0x00000001L, /* 100% flare */
+ icMaxFlare = icMaxTagVal
+} icMeasurementFlare;
+
+/* Measurement Geometry, used in the measurmentType tag */
+typedef enum {
+ icGeometryUnknown = 0x00000000L, /* Unknown */
+ icGeometry045or450 = 0x00000001L, /* 0/45, 45/0 */
+ icGeometry0dord0 = 0x00000002L, /* 0/d or d/0 */
+ icMaxGeometry = icMaxTagVal
+} icMeasurementGeometry;
+
+/* Rendering Intents, used in the profile header */
+typedef enum {
+ icPerceptual = 0,
+ icRelativeColorimetric = 1,
+ icSaturation = 2,
+ icAbsoluteColorimetric = 3,
+ icMaxEnumIntent = icMaxTagVal
+} icRenderingIntent;
+
+/* Different Spot Shapes currently defined, used for screeningType */
+typedef enum {
+ icSpotShapeUnknown = 0,
+ icSpotShapePrinterDefault = 1,
+ icSpotShapeRound = 2,
+ icSpotShapeDiamond = 3,
+ icSpotShapeEllipse = 4,
+ icSpotShapeLine = 5,
+ icSpotShapeSquare = 6,
+ icSpotShapeCross = 7,
+ icMaxEnumSpot = icMaxTagVal
+} icSpotShape;
+
+/* Standard Observer, used in the measurmentType tag */
+typedef enum {
+ icStdObsUnknown = 0x00000000L, /* Unknown */
+ icStdObs1931TwoDegrees = 0x00000001L, /* 2 deg */
+ icStdObs1964TenDegrees = 0x00000002L, /* 10 deg */
+ icMaxStdObs = icMaxTagVal
+} icStandardObserver;
+
+/* Pre-defined illuminants, used in measurement and viewing conditions type */
+typedef enum {
+ icIlluminantUnknown = 0x00000000L,
+ icIlluminantD50 = 0x00000001L,
+ icIlluminantD65 = 0x00000002L,
+ icIlluminantD93 = 0x00000003L,
+ icIlluminantF2 = 0x00000004L,
+ icIlluminantD55 = 0x00000005L,
+ icIlluminantA = 0x00000006L,
+ icIlluminantEquiPowerE = 0x00000007L,
+ icIlluminantF8 = 0x00000008L,
+ icMaxEnumIlluminant = icMaxTagVal
+} icIlluminant;
+
+/* A not so exhaustive list of language codes */
+typedef enum {
+ icLanguageCodeEnglish = 0x656E, /* 'en' */
+ icLanguageCodeGerman = 0x6465, /* 'de' */
+ icLanguageCodeItalian = 0x6974, /* 'it' */
+ icLanguageCodeDutch = 0x6E6C, /* 'nl' */
+ icLanguageCodeSweden = 0x7376, /* 'sv' */
+ icLanguageCodeSpanish = 0x6573, /* 'es' */
+ icLanguageCodeDanish = 0x6461, /* 'da' */
+ icLanguageCodeNorwegian = 0x6E6F, /* 'no' */
+ icLanguageCodeJapanese = 0x6A61, /* 'ja' */
+ icLanguageCodeFinish = 0x6669, /* 'fi' */
+ icLanguageCodeTurkish = 0x7472, /* 'tr' */
+ icLanguageCodeKorean = 0x6B6F, /* 'ko' */
+ icLanguageCodeChienese = 0x7A68, /* 'zh' */
+ icLanguageCodeFrench = 0x6672, /* 'fr' */
+ icMaxEnumLanguageCode = 0xFFFF
+} icEnumLanguageCode;
+
+/* A not so exhaustive list of region codes. */
+typedef enum {
+ icRegionCodeUSA = 0x5553, /* 'US' */
+ icRegionCodeUnitedKingdom = 0x554B, /* 'UK' */
+ icRegionCodeGermany = 0x4445, /* 'DE' */
+ icRegionCodeItaly = 0x4954, /* 'IT' */
+ icRegionCodeNetherlands = 0x4E4C, /* 'NL' */
+ icRegionCodeSpain = 0x4543, /* 'ES' */
+ icRegionCodeDenmark = 0x444B, /* 'DK' */
+ icRegionCodeNorway = 0x4E4F, /* 'ND' */
+ icRegionCodeJapan = 0x4A50, /* 'JP' */
+ icRegionCodeFinland = 0x4649, /* 'FI' */
+ icRegionCodeTurkey = 0x5452, /* 'TR' */
+ icRegionCodeKorea = 0x4B52, /* 'KR' */
+ icRegionCodeChina = 0x434E, /* 'CN' */
+ icRegionCodeTaiwan = 0x5457, /* 'TW' */
+ icRegionCodeFrance = 0x4652, /* 'FR' */
+ icMaxEnumRegionCode = 0xFFFF
+} icEnumRegionCode;
+
+/* media type for icSigDeviceSettingsTag */
+typedef enum {
+ icStandard = 1,
+ icTrans = 2, /* transparency */
+ icGloss = 3,
+ icUser1 = 256,
+ icMaxDeviceMedia = icMaxTagVal
+} icDeviceMedia;
+
+/* halftone settings for icSigDeviceSettingTag */
+typedef enum {
+ icNone = 1,
+ icCoarse = 2,
+ icFine = 3,
+ icLineArt = 4,
+ icErrorDiffusion = 5,
+ icReserved6 = 6,
+ icReserved7 = 7,
+ icReserved8 = 8,
+ icReserved9 = 9,
+ icGrayScale = 10,
+ icUser2 = 256,
+ icMaxDither = icMaxTagVal
+} icDeviceDither;
+
+/* signatures for icSigDeviceSettingsTag */
+typedef enum {
+ icSigResolution = 0x72736c6eL, /* 'rsln' */
+ icSigMedia = 0x6d747970L, /* 'mtyp' */
+ icSigHalftone = 0x6866746eL, /* 'hftn' */
+ icMaxSettings = icMaxTagVal
+} icSettingsSig;
+
+/* measurement units for the icResponseCurveSet16Type */
+typedef enum {
+ icStaA = 0x53746141L, /* 'StaA' */
+ icStaE = 0x53746145L, /* 'StaE' */
+ icStaI = 0x53746149L, /* 'StaI' */
+ icStaT = 0x53746154L, /* 'StaT' */
+ icStaM = 0x5374614dL, /* 'StaM' */
+ icDN = 0x444e2020L, /* 'DN ' */
+ icDNP = 0x444e2050L, /* 'DN P' */
+ icDNN = 0x444e4e20L, /* 'DNN ' */
+ icDNNP = 0x444e4e50L, /* 'DNNP' */
+ icMaxUnits = icMaxTagVal
+} icMeasUnitsSig;
+
+/* Parametric curve types for icSigParametricCurveType */
+typedef enum {
+ icCurveFunction1 = 0x0000,
+ icCurveFunction3 = 0x0001,
+ icCurveFunction4 = 0x0002,
+ icCurveFunction5 = 0x0003,
+ icCurveFunction7 = 0x0004
+} icParametricCurveFunctionType;
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* ICCV42_H */
diff --git a/icc/iccdump.c b/icc/iccdump.c
new file mode 100644
index 0000000..aaf14f0
--- /dev/null
+++ b/icc/iccdump.c
@@ -0,0 +1,269 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * File dump utility.
+ *
+ * Author: Graeme W. Gill
+ * Date: 1999/11/29
+ * Version: 2.15
+ *
+ * Copyright 1997 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/*
+ * TTBD:
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include "icc.h"
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+void usage(void) {
+ fprintf(stderr,"Dump an ICC file in human readable form, V%s\n",ICCLIB_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: iccdump [-v level] [-t tagname] [-s] infile\n");
+ fprintf(stderr," -v level Verbose level 1-3 (default 2)\n");
+ fprintf(stderr," -t tag Dump this tag only (can be used multiple times)\n");
+ fprintf(stderr," -s Search for embedded profile\n");
+ fprintf(stderr," -i Check V4 ID value\n");
+ exit(1);
+}
+
+#define MXTGNMS 30
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char in_name[500];
+ int ntag_names = 0;
+ char tag_names[MXTGNMS][5];
+ int verb = 2;
+ int search = 0;
+ int chid = 0; /* Check V4 ID */
+ int ecount = 1; /* Embedded count */
+ int offset = 0; /* Offset to read profile from */
+ int found;
+ icmFile *fp, *op;
+ icc *icco;
+ int rv = 0;
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ fa = nfa;
+ if (na == NULL) usage();
+ verb = atoi(na);
+ }
+ /* Tag name */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (ntag_names >= MXTGNMS)
+ usage();
+ strncpy(tag_names[ntag_names],na,4);
+ tag_names[ntag_names++][4] = '\000';
+ }
+ /* Search */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ search = 1;
+ }
+ /* Check ID */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ chid = 1;
+ }
+
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa]);
+
+ /* Open up the file for reading */
+ if ((fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Can't open file '%s'",in_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* open output stream */
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout stream");
+
+ do {
+ found = 0;
+
+ /* Dumb search for magic number */
+ if (search) {
+ int fc = 0;
+ char c;
+
+ if (fp->seek(fp, offset) != 0)
+ break;
+
+ while(found == 0) {
+ if (fp->read(fp, &c, 1, 1) != 1) {
+ break;
+ }
+ offset++;
+
+ switch (fc) {
+ case 0:
+ if (c == 'a')
+ fc++;
+ else
+ fc = 0;
+ break;
+ case 1:
+ if (c == 'c')
+ fc++;
+ else
+ fc = 0;
+ break;
+ case 2:
+ if (c == 's')
+ fc++;
+ else
+ fc = 0;
+ break;
+ case 3:
+ if (c == 'p') {
+ found = 1;
+ offset -= 40;
+ }
+ else
+ fc = 0;
+ break;
+ }
+ }
+ }
+
+ if (search == 0 || found != 0) {
+ ecount++;
+
+ if (search)
+ printf("Embedded profile found at file offset %d (0x%x)\n",offset,offset);
+
+ if ((rv = icco->read(icco,fp,offset)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ if (ntag_names > 0) {
+ int i;
+ for (i = 0; i < ntag_names; i++) {
+
+ icTagSignature sig = str2tag(tag_names[i]);
+
+ /* Try and locate that particular tag */
+ if ((rv = icco->find_tag(icco,sig)) != 0 && rv != 1) {
+ warning ("icc->find_tag() can't find tag '%s' in file", tag2str(sig));
+ } else {
+ icmBase *ob;
+
+ if (rv == 1)
+ warning ("icc->find_tag() tag '%s' found but unknown type", tag_names[i]);
+ if ((ob = icco->read_tag_any(icco, sig)) == NULL) {
+ warning("Failed to read tag '%s': %d, %s",tag_names[i], icco->errc,icco->err);
+ } else {
+ ob->dump(ob, op, verb-1);
+ }
+ }
+ }
+ } else {
+ icco->dump(icco, op, verb);
+ if (chid && icco->header->majv >= 4) {
+ unsigned char id[16];
+ rv = icco->check_id(icco, id);
+ if (rv == 0)
+ printf("Id checks\n");
+ else if (rv == 1)
+ printf("Id can't be checked because it's not set\n");
+ else if (rv == 2) {
+ icmHeader *p = icco->header;
+ printf("Id check fails:\n");
+ op->gprintf(op," ID is = %02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X%02X%02X%02X%02X\n",
+ p->id[0], p->id[1], p->id[2], p->id[3],
+ p->id[4], p->id[5], p->id[6], p->id[7],
+ p->id[8], p->id[9], p->id[10], p->id[11],
+ p->id[12], p->id[13], p->id[14], p->id[15]);
+ op->gprintf(op," ID should be = %02X%02X%02X%02X%02X%02X%02X%02X"
+ "%02X%02X%02X%02X%02X%02X%02X%02X\n",
+ id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7],
+ id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15]);
+ } else
+ warning("Failed to do ID check %d, %s",icco->errc,icco->err);
+ }
+ }
+ offset += 128;
+ }
+ } while (found != 0);
+
+ icco->del(icco);
+ op->del(op);
+ fp->del(fp);
+
+ return 0;
+}
+
+
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"iccdump: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"iccdump: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/icc/icclu.c b/icc/icclu.c
new file mode 100644
index 0000000..ea32da0
--- /dev/null
+++ b/icc/icclu.c
@@ -0,0 +1,424 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * Profile color lookup utility.
+ *
+ * Author: Graeme W. Gill
+ * Date: 1999/11/29
+ * Version: 2.15
+ *
+ * Copyright 1998 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/* TTBD:
+ *
+ */
+
+/*
+
+ This file is intended to exercise the ability
+ of the icc library to translate colors through a profile.
+ It also serves as a concise example of how to do this.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+void usage(void) {
+ fprintf(stderr,"Translate colors through an ICC profile, V%s\n",ICCLIB_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: icclu [-v level] [-f func] [-i intent] [-o order] profile\n");
+ fprintf(stderr," -v level Verbosity level 0 - 2 (default = 1)\n");
+ fprintf(stderr," -f function f = forward, b = backwards, g = gamut, p = preview\n");
+ fprintf(stderr," -i intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute\n");
+// fprintf(stderr," P = absolute perceptual, S = absolute saturation\n");
+ fprintf(stderr," -p oride x = XYZ_PCS, l = Lab_PCS, y = Yxy,\n");
+ fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
+ fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
+ fprintf(stderr," -s scale Scale device range 0.0 - scale rather than 0.0 - 1.0\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr," The colors to be translated should be fed into standard input,\n");
+ fprintf(stderr," one input color per line, white space separated.\n");
+ fprintf(stderr," A line starting with a # will be ignored.\n");
+ fprintf(stderr," A line not starting with a number will terminate the program.\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char prof_name[500];
+ icmFile *fp;
+ icc *icco;
+ int verb = 1;
+ double scale = 0.0; /* Device value scale factor */
+ int rv = 0;
+ int repYxy = 0; /* Report Yxy */
+ char buf[200];
+ double oin[MAX_CHAN], in[MAX_CHAN], out[MAX_CHAN];
+
+ icmLuBase *luo;
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int inn, outn; /* Number of components */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+
+ /* Lookup parameters */
+ icmLookupFunc func = icmFwd; /* Default */
+ icRenderingIntent intent = icmDefaultIntent; /* Default */
+ icColorSpaceSignature pcsor = icmSigDefaultData; /* Default */
+ icmLookupOrder order = icmLuOrdNorm; /* Default */
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ fa = nfa;
+ if (na == NULL)
+ verb = 2;
+ else {
+ if (na[0] == '0')
+ verb = 0;
+ else if (na[0] == '1')
+ verb = 1;
+ else if (na[0] == '2')
+ verb = 2;
+ else
+ usage();
+ }
+ }
+
+ /* function */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'f':
+ case 'F':
+ func = icmFwd;
+ break;
+ case 'b':
+ case 'B':
+ func = icmBwd;
+ break;
+ case 'g':
+ case 'G':
+ func = icmGamut;
+ break;
+ case 'p':
+ case 'P':
+ func = icmPreview;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Intent */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'p':
+ intent = icPerceptual;
+ break;
+ case 'r':
+ intent = icRelativeColorimetric;
+ break;
+ case 's':
+ intent = icSaturation;
+ break;
+ case 'a':
+ intent = icAbsoluteColorimetric;
+ break;
+ /* Special function icclib intents */
+ case 'P':
+ intent = icmAbsolutePerceptual;
+ break;
+ case 'S':
+ intent = icmAbsoluteSaturation;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Search order */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'n':
+ case 'N':
+ order = icmLuOrdNorm;
+ break;
+ case 'r':
+ case 'R':
+ order = icmLuOrdRev;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* PCS override */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'x':
+ case 'X':
+ pcsor = icSigXYZData;
+ repYxy = 0;
+ break;
+ case 'l':
+ case 'L':
+ pcsor = icSigLabData;
+ repYxy = 0;
+ break;
+ case 'y':
+ case 'Y':
+ pcsor = icSigXYZData;
+ repYxy = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Device scale */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ fa = nfa;
+ if (na == NULL) usage();
+ scale = atof(na);
+ if (scale <= 0.0) usage();
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(prof_name,argv[fa]);
+
+ /* Open up the profile for reading */
+ if ((fp = new_icmFileStd_name(prof_name,"r")) == NULL)
+ error ("Can't open file '%s'",prof_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ if ((rv = icco->read(icco,fp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ if (verb > 1) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ icco->header->dump(icco->header, op, 1);
+ op->del(op);
+ }
+
+ /* Get a conversion object */
+ if ((luo = icco->get_luobj(icco, func, intent, pcsor, order)) == NULL)
+ error ("%d, %s",icco->errc, icco->err);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ luo->spaces(luo, &ins, &inn, &outs, &outn, &alg, NULL, NULL, NULL, NULL);
+
+ if (repYxy) { /* report Yxy rather than XYZ */
+ if (ins == icSigXYZData)
+ ins = icSigYxyData;
+ if (outs == icSigXYZData)
+ outs = icSigYxyData;
+ }
+
+ /* Process colors to translate */
+ for (;;) {
+ int i,j;
+ char *bp, *nbp;
+
+ /* Init default input values */
+ for (i = 0; i < MAX_CHAN; i++) {
+ in[i] = oin[i] = 0.0;
+ }
+
+ /* Read in the next line */
+ if (fgets(buf, 200, stdin) == NULL)
+ break;
+ if (buf[0] == '#') {
+ if (verb > 0)
+ fprintf(stdout,"%s\n",buf);
+ continue;
+ }
+ /* For each input number */
+ for (bp = buf-1, nbp = buf, i = 0; i < MAX_CHAN; i++) {
+ bp = nbp;
+ in[i] = oin[i] = strtod(bp, &nbp);
+ if (nbp == bp)
+ break; /* Failed */
+ }
+ if (i == 0)
+ break;
+
+ /* If device data and scale */
+ if(scale > 0.0
+ && ins != icSigXYZData
+ && ins != icSigLabData
+ && ins != icSigLuvData
+ && ins != icSigYCbCrData
+ && ins != icSigYxyData
+ && ins != icSigHsvData
+ && ins != icSigHlsData) {
+ for (i = 0; i < MAX_CHAN; i++) {
+ in[i] /= scale;
+ }
+ }
+
+ if (repYxy && ins == icSigYxyData) {
+ double Y = in[0];
+ double x = in[1];
+ double y = in[2];
+ double z = 1.0 - x - y;
+ double sum;
+ if (y < 1e-6) {
+ in[0] = in[1] = in[2] = 0.0;
+ } else {
+ sum = Y/y;
+ in[0] = x * sum;
+ in[1] = Y;
+ in[2] = z * sum;
+ }
+ }
+
+ /* Do conversion */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ /* Output the results */
+ if (verb > 0) {
+ for (j = 0; j < inn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",oin[j]);
+ else
+ fprintf(stdout,"%f",oin[j]);
+ }
+ printf(" [%s] -> %s -> ", icm2str(icmColorSpaceSignature, ins),
+ icm2str(icmLuAlg, alg));
+ }
+
+ if (repYxy && outs == icSigYxyData) {
+ double X = out[0];
+ double Y = out[1];
+ double Z = out[2];
+ double sum = X + Y + Z;
+ if (sum < 1e-6) {
+ out[0] = out[1] = out[2] = 0.0;
+ } else {
+ out[0] = Y;
+ out[1] = X/sum;
+ out[2] = Y/sum;
+ }
+ }
+
+ /* If device data and scale */
+ if(scale > 0.0
+ && outs != icSigXYZData
+ && outs != icSigLabData
+ && outs != icSigLuvData
+ && outs != icSigYCbCrData
+ && outs != icSigYxyData
+ && outs != icSigHsvData
+ && outs != icSigHlsData) {
+ for (i = 0; i < MAX_CHAN; i++) {
+ out[i] *= scale;
+ }
+ }
+
+ for (j = 0; j < outn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",out[j]);
+ else
+ fprintf(stdout,"%f",out[j]);
+ }
+ if (verb > 0)
+ printf(" [%s]", icm2str(icmColorSpaceSignature, outs));
+
+ if (verb > 0 && rv != 0)
+ fprintf(stdout," (clip)");
+
+ fprintf(stdout,"\n");
+
+ }
+
+ /* Done with lookup object */
+ luo->del(luo);
+
+ icco->del(icco);
+
+ fp->del(fp);
+
+ return 0;
+}
+
+
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icclu: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icclu: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/icc/iccrw.c b/icc/iccrw.c
new file mode 100644
index 0000000..807c5f4
--- /dev/null
+++ b/icc/iccrw.c
@@ -0,0 +1,311 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * Profile read then re-write skeleton utility.
+ *
+ * Author: Graeme W. Gill
+ * Date: 1999/11/29
+ * Version: 2.15
+ *
+ * Copyright 1997 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+
+#undef TEST_VIDGAMTAG /* Add ColorSync 2.5 VideoCardGamma tag with linear table */
+#undef TEST_SRGB_FIX /* Some test code */
+#undef WP_PATCH /* Overwrite the white point */
+#undef INVERT_GRAY /* Invert single TRC gray profile */
+#undef MOD_A2B /* 0 */ /* Modify A2B RGB tables */
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+void usage(void) {
+ fprintf(stderr,"Read and then re-write an ICC profile V%s\n",ICCLIB_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: iccrw readprofile writeprofile\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char in_name[500];
+ char out_name[500];
+ icmFile *rd_fp, *wr_fp;
+ icc *icco;
+ int verb = 0;
+ int rv = 0;
+
+ if (argc < 3)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ /* No options */
+ usage();
+
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(out_name,argv[fa]);
+
+ /* Open up the profile for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Can't open file '%s'",in_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = icco->read(icco,rd_fp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ /* Read every tag */
+ if (icco->read_all_tags(icco) != 0) {
+ error("Unable to read all tags: %d, %s",icco->errc,icco->err);
+ }
+
+ rd_fp->del(rd_fp);
+
+ /* ======================================= */
+ /* Change profile in here. */
+
+#ifdef TEST_SRGB_FIX /* Some test code */
+ /* Try deleting the black point tag */
+ {
+ if (icco->delete_tag(icco, icSigMediaBlackPointTag) != 0) {
+ error("Unable to delete blackpoint tag: %d, %s",icco->errc,icco->err);
+ }
+ }
+
+ /* Fix up sRGB profile curve */
+ {
+ icmCurve *ro;
+ int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmCurve *)icco->read_tag(icco, icSigRedTRCTag);
+ if (ro == NULL)
+ error("Unable to read rTRC");
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigCurveType)
+ error("rTRC is not CurveType");
+
+ for (i = 0; i < ro->size; i++) {
+ double vi, vo;
+ vi = i/(double)(ro->size-1);
+
+ if (vi < 0.04045) {
+ vo = vi/12.92;
+ } else {
+ vo = pow((0.055+vi)/1.055,2.4);
+ }
+ ro->data[i] = vo;
+ }
+ }
+
+ /* Show we modified this ICC file */
+ icco->header->cmmId = str2tag("argl"); /* CMM for profile - Argyll CMM */
+#endif
+
+#ifdef TEST_VIDGAMTAG
+ /* delete video card gamma tag (c/o Neil Okamoto) */
+ {
+ if (icco->find_tag(icco, icSigVideoCardGammaTag) == 0)
+ if (icco->delete_tag(icco, icSigVideoCardGammaTag) != 0)
+ error("Unable to delete videocardgamma tag: %d, %s",icco->errc,icco->err);
+ }
+ /* Add a video card gamma table */
+ {
+ int c,i;
+ icmVideoCardGamma *wo;
+ wo = (icmVideoCardGamma *)icco->add_tag(icco, icSigVideoCardGammaTag, icSigVideoCardGammaType);
+ if (wo == NULL)
+ error ("Unable to add VideoCardGamma tag");
+
+ wo->tagType = icmVideoCardGammaTableType;
+ wo->u.table.channels = 3; /* rgb */
+ wo->u.table.entryCount = 256; /* full lut */
+ wo->u.table.entrySize = 1; /* byte */
+ wo->allocate((icmBase*)wo);
+ for (c=0; c<3; c++)
+ for (i=0; i<256; i++)
+ ((unsigned char*)wo->u.table.data)[256*c+i] = 255-i;
+ }
+
+ /* Show we modified this ICC file */
+ icco->header->cmmId = str2tag("argl"); /* CMM for profile - Argyll CMM */
+#endif
+
+#ifdef WP_PATCH /* Overwrite the white point */
+ /* delete white point tag */
+ {
+ if (icco->find_tag(icco, icSigMediaWhitePointTag) == 0)
+ if (icco->delete_tag(icco, icSigMediaWhitePointTag) != 0)
+ error("Unable to delete white point tag tag: %d, %s",icco->errc,icco->err);
+ }
+ /* Add a new white point tag */
+ {
+ double lab[3];
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)icco->add_tag(
+ icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",icco->errc, icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ lab[0] = 79.8296;
+ lab[1] = -0.004042 + 0.842312;
+ lab[2] = 3.019928 + 0.810044;
+ icmLab2XYZ(&icmD50, lab, lab);
+ icmAry2XYZ(wo->data[0], lab);
+ }
+
+ /* Show we modified this ICC file */
+ icco->header->cmmId = str2tag("argl"); /* CMM for profile - Argyll CMM */
+#endif
+#ifdef INVERT_GRAY /* Invert single TRC gray profile */
+ {
+ icmCurve *ro;
+ int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmCurve *)icco->read_tag(icco, icSigGrayTRCTag);
+ if (ro == NULL)
+ error("Unable to read GrayTRC");
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigCurveType)
+ error("GrayTRC is not CurveType");
+
+ /* Swap the curve entries from top to bottom */
+ for (i = 0; i < (ro->size/2); i++) {
+ double temp;
+ int ii = 255 - i;
+
+ temp = ro->data[ii];
+ ro->data[ii] = ro->data[i];
+ ro->data[i] = temp;
+ }
+ }
+
+#endif
+
+#ifdef MOD_A2B
+ {
+ icmLut *ro;
+ unsigned long size;
+ unsigned int i, j;
+ icTagSignature sig;
+
+ if (MOD_A2B == 0)
+ sig = icSigAToB0Tag;
+ else if (MOD_A2B == 1)
+ sig = icSigAToB1Tag;
+ else
+ sig = icSigAToB2Tag;
+
+ /* Try and read the tag from the file */
+ ro = (icmLut *)icco->read_tag(icco, sig);
+ if (ro == NULL)
+ error("Failed to read A2B tag");
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigLut16Type)
+ error("A2B is not 16 bitg");
+
+ /* Simply apply a gamma to the corresponding input curve */
+ for (i = 0; i < ro->inputChan; i++) { /* Input tables */
+ double val;
+ j = MOD_A2B;
+ val = ro->inputTable[i * ro->inputEnt + j];
+ val = pow(val, 2.0);
+ ro->inputTable[i * ro->inputEnt + j] = val;
+ }
+ }
+#endif /* MOD_A2B */
+
+ /* ======================================= */
+
+ /* Open up the other profile for writing */
+ if ((wr_fp = new_icmFileStd_name(out_name,"w")) == NULL)
+ error ("Can't open file '%s'",out_name);
+
+ if ((rv = icco->write(icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,icco->err);
+
+ icco->del(icco);
+ wr_fp->del(wr_fp);
+
+ return 0;
+}
+
+/* ------------------------------------------------ */
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"iccrw: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"iccrw: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/icc/iccstd.c b/icc/iccstd.c
new file mode 100644
index 0000000..742be4d
--- /dev/null
+++ b/icc/iccstd.c
@@ -0,0 +1,443 @@
+
+/*
+ * ICC library stdio and malloc utility classes.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2002/10/24
+ * Version: 2.15
+ *
+ * Copyright 1997 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ *
+ * These are kept in a separate file to allow them to be
+ * selectively ommitted from the icc library.
+ *
+ */
+
+#ifndef COMBINED_STD
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <time.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "icc.h"
+
+#endif /* !COMBINED_STD */
+
+#if defined(SEPARATE_STD) || defined(COMBINED_STD)
+
+#ifdef _MSC_VER
+#define fileno _fileno
+#endif
+
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t)(-1))
+#endif
+
+/* ------------------------------------------------- */
+/* Standard Heap allocator icmAlloc compatible class */
+/* Just call the standard system function */
+
+#ifdef ICC_DEBUG_MALLOC
+
+/* Make sure that inline malloc #defines are turned off for this file */
+#undef was_debug_malloc
+#ifdef malloc
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+#define was_debug_malloc
+#endif /* dmalloc */
+
+static void *icmAllocStd_dmalloc(
+struct _icmAlloc *pp,
+size_t size,
+char *name,
+int line
+) {
+ return malloc(size);
+}
+
+static void *icmAllocStd_dcalloc(
+struct _icmAlloc *pp,
+size_t num,
+size_t size,
+char *name,
+int line
+) {
+ if (size != 0 && num > (SIZE_MAX/size))
+ return NULL;
+ calloc(num, size);
+}
+
+static void *icmAllocStd_drealloc(
+struct _icmAlloc *pp,
+void *ptr,
+size_t size,
+char *name,
+int line
+) {
+ return realloc(ptr, size);
+}
+
+
+static void icmAllocStd_dfree(
+struct _icmAlloc *pp,
+void *ptr,
+char *name,
+int line
+) {
+ free(ptr);
+}
+
+/* we're done with the AllocStd object */
+static void icmAllocStd_delete(
+icmAlloc *pp
+) {
+ icmAllocStd *p = (icmAllocStd *)pp;
+
+ free(p);
+}
+
+/* Create icmAllocStd */
+icmAlloc *new_icmAllocStd() {
+ icmAllocStd *p;
+ if ((p = (icmAllocStd *) calloc(1,sizeof(icmAllocStd))) == NULL)
+ return NULL;
+ p->dmalloc = icmAllocStd_dmalloc;
+ p->dcalloc = icmAllocStd_dcalloc;
+ p->drealloc = icmAllocStd_drealloc;
+ p->dfree = icmAllocStd_dfree;
+ p->del = icmAllocStd_delete;
+
+ return (icmAlloc *)p;
+}
+
+#ifdef was_debug_malloc
+#undef was_debug_malloc
+#define malloc( p, size ) dmalloc( p, size, __FILE__, __LINE__ )
+#define calloc( p, num, size ) dcalloc( p, num, size, __FILE__, __LINE__ )
+#define realloc( p, ptr, size ) drealloc( p, ptr, size, __FILE__, __LINE__ )
+#define free( p, ptr ) dfree( p, ptr , __FILE__, __LINE__ )
+#endif /* was_debug_malloc */
+
+#else /* !DEBUG_MALLOC */
+
+static void *icmAllocStd_malloc(
+struct _icmAlloc *pp,
+size_t size
+) {
+ return malloc(size);
+}
+
+static void *icmAllocStd_calloc(
+struct _icmAlloc *pp,
+size_t num,
+size_t size
+) {
+ if (size != 0 && num > (SIZE_MAX/size))
+ return NULL;
+ return calloc(num, size);
+}
+
+static void *icmAllocStd_realloc(
+struct _icmAlloc *pp,
+void *ptr,
+size_t size
+) {
+ return realloc(ptr, size);
+}
+
+
+static void icmAllocStd_free(
+struct _icmAlloc *pp,
+void *ptr
+) {
+ free(ptr);
+}
+
+/* we're done with the AllocStd object */
+static void icmAllocStd_delete(
+icmAlloc *pp
+) {
+ icmAllocStd *p = (icmAllocStd *)pp;
+
+ free(p);
+}
+
+/* Create icmAllocStd */
+icmAlloc *new_icmAllocStd() {
+ icmAllocStd *p;
+ if ((p = (icmAllocStd *) calloc(1,sizeof(icmAllocStd))) == NULL)
+ return NULL;
+ p->malloc = icmAllocStd_malloc;
+ p->calloc = icmAllocStd_calloc;
+ p->realloc = icmAllocStd_realloc;
+ p->free = icmAllocStd_free;
+ p->del = icmAllocStd_delete;
+
+ return (icmAlloc *)p;
+}
+
+#endif /* ICC_DEBUG_MALLOC */
+
+/* ------------------------------------------------- */
+/* Standard Stream file I/O icmFile compatible class */
+
+/* Get the size of the file (Only valid for reading file. */
+static size_t icmFileStd_get_size(icmFile *pp) {
+ icmFileStd *p = (icmFileStd *)pp;
+
+ return p->size;
+}
+
+/* Set current position to offset. Return 0 on success, nz on failure. */
+static int icmFileStd_seek(
+icmFile *pp,
+unsigned int offset
+) {
+ icmFileStd *p = (icmFileStd *)pp;
+
+ return fseek(p->fp, offset, SEEK_SET);
+}
+
+/* Read count items of size length. Return number of items successfully read. */
+static size_t icmFileStd_read(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ icmFileStd *p = (icmFileStd *)pp;
+
+ return fread(buffer, size, count, p->fp);
+}
+
+/* write count items of size length. Return number of items successfully written. */
+static size_t icmFileStd_write(
+icmFile *pp,
+void *buffer,
+size_t size,
+size_t count
+) {
+ icmFileStd *p = (icmFileStd *)pp;
+
+ return fwrite(buffer, size, count, p->fp);
+}
+
+
+/* do a printf */
+static int icmFileStd_printf(
+icmFile *pp,
+const char *format,
+...
+) {
+ int rv;
+ va_list args;
+ icmFileStd *p = (icmFileStd *)pp;
+
+ va_start(args, format);
+ rv = vfprintf(p->fp, format, args);
+ va_end(args);
+ return rv;
+}
+
+/* flush all write data out to secondary storage. Return nz on failure. */
+static int icmFileStd_flush(
+icmFile *pp
+) {
+ icmFileStd *p = (icmFileStd *)pp;
+
+ return fflush(p->fp);
+}
+
+/* Return the memory buffer. Error if not icmFileMem */
+static int icmFileStd_get_buf(
+icmFile *pp,
+unsigned char **buf,
+size_t *len
+) {
+ return 1;
+}
+
+/* we're done with the file object, return nz on failure */
+static int icmFileStd_delete(
+icmFile *pp
+) {
+ int rv = 0;
+ icmFileStd *p = (icmFileStd *)pp;
+ icmAlloc *al = p->al;
+ int del_al = p->del_al;
+
+ if (p->doclose != 0) {
+ if (fclose(p->fp) != 0)
+ rv = 2;
+ }
+
+ al->free(al, p); /* Free object */
+ if (del_al) /* We are responsible for deleting allocator */
+ al->del(al);
+
+ return rv;
+}
+
+/* Create icmFile given a (binary) FILE* */
+icmFile *new_icmFileStd_fp(
+FILE *fp
+) {
+ return new_icmFileStd_fp_a(fp, NULL);
+}
+
+/* Create icmFile given a (binary) FILE* and allocator */
+icmFile *new_icmFileStd_fp_a(
+FILE *fp,
+icmAlloc *al /* heap allocator, NULL for default */
+) {
+ icmFileStd *p;
+ int del_al = 0;
+ struct stat sbuf;
+
+ if (al == NULL) { /* None provided, create default */
+ if ((al = new_icmAllocStd()) == NULL)
+ return NULL;
+ del_al = 1; /* We need to delete the allocator we created */
+ }
+
+ if ((p = (icmFileStd *) al->calloc(al, 1, sizeof(icmFileStd))) == NULL) {
+ if (del_al)
+ al->del(al);
+ return NULL;
+ }
+ p->al = al; /* Heap allocator */
+ p->del_al = del_al; /* Flag noting whether we delete it */
+ p->get_size = icmFileStd_get_size;
+ p->seek = icmFileStd_seek;
+ p->read = icmFileStd_read;
+ p->write = icmFileStd_write;
+ p->gprintf = icmFileStd_printf;
+ p->flush = icmFileStd_flush;
+ p->get_buf = icmFileStd_get_buf;
+ p->del = icmFileStd_delete;
+
+ if (fstat(fileno(fp), &sbuf) == 0) {
+ p->size = sbuf.st_size;
+ } else {
+ p->size = 0;
+ }
+
+ p->fp = fp;
+ p->doclose = 0;
+
+ return (icmFile *)p;
+}
+
+/* Create icmFile given a file name */
+icmFile *new_icmFileStd_name(
+char *name,
+char *mode
+) {
+ return new_icmFileStd_name_a(name, mode, NULL);
+}
+
+/* Create given a file name and allocator */
+icmFile *new_icmFileStd_name_a(
+char *name,
+char *mode,
+icmAlloc *al /* heap allocator, NULL for default */
+) {
+ FILE *fp;
+ icmFile *p;
+ char nmode[50];
+
+ strcpy(nmode, mode);
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ strcat(nmode, "b");
+#endif
+
+ if ((fp = fopen(name,nmode)) == NULL)
+ return NULL;
+
+ p = new_icmFileStd_fp_a(fp, al);
+
+ if (p != NULL) {
+ icmFileStd *pp = (icmFileStd *)p;
+ pp->doclose = 1;
+ }
+ return p;
+}
+
+/* ------------------------------------------------- */
+
+/* Create a memory image file access class with the std allocator */
+icmFile *new_icmFileMem(
+void *base, /* Pointer to base of memory buffer */
+size_t length /* Number of bytes in buffer */
+) {
+ icmFile *p;
+ icmAlloc *al; /* memory allocator */
+
+ if ((al = new_icmAllocStd()) == NULL)
+ return NULL;
+
+ if ((p = new_icmFileMem_a(base, length, al)) == NULL) {
+ al->del(al);
+ return NULL;
+ }
+
+ ((icmFileMem *)p)->del_al = 1; /* Get icmFileMem->del to cleanup allocator */
+ return p;
+}
+
+/* Create a memory image file access class with the std allocator */
+/* and delete buffer when icmFile is deleted. */
+icmFile *new_icmFileMem_d(
+void *base, /* Pointer to base of memory buffer */
+size_t length /* Number of bytes in buffer */
+) {
+ icmFile *fp;
+
+ if ((fp = new_icmFileMem(base, length)) != NULL) {
+ ((icmFileMem *)fp)->del_buf = 1;
+ }
+ return fp;
+}
+
+/* ------------------------------------------------- */
+
+/* Create an icc with the std allocator */
+icc *new_icc(void) {
+ icc *p;
+ icmAlloc *al; /* memory allocator */
+
+ if ((al = new_icmAllocStd()) == NULL)
+ return NULL;
+
+ if ((p = new_icc_a(al)) == NULL) {
+ al->del(al);
+ return NULL;
+ }
+
+ p->del_al = 1; /* Get icc->del to cleanup allocator */
+ return p;
+}
+
+
+#endif /* defined(SEPARATE_STD) || defined(COMBINED_STD) */
diff --git a/icc/icctest.c b/icc/icctest.c
new file mode 100644
index 0000000..97a3f62
--- /dev/null
+++ b/icc/icctest.c
@@ -0,0 +1,2393 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * Library Read/Write test and example code.
+ *
+ * Author: Graeme W. Gill
+ * Date: 1999/11/29
+ * Version: 2.15
+ *
+ * Copyright 1997 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/* TTBD:
+ *
+ * Fix enums to be selected randomly (ie. header)
+ *
+ * Should add test of ->delete_tag()
+ * Should add test of ->rename_tag()
+ *
+ * Add many extra comments and explanations.
+ *
+ */
+
+/*
+
+ This file is intended to serve two purposes. One
+ is to minimally test the ability of the icc library
+ to read and write all tag types. The other is as
+ a source code example of how to read and write
+ each tag type, since icc.h might otherwise take
+ some effort to understand.
+
+ Note XYZ scaling to 1.0, not 100.0
+
+ */
+
+#define NTRIALS 100
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#include "icc.h"
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+/* Rounded floating test numbers */
+int rand_int(int low, int high);
+unsigned int rand_o8(void), rand_o16(void), rand_o32(void);
+double rand_8f(void), rand_L8(void), rand_ab8(void);
+double rand_16f(void), rand_XYZ16(void), rand_u8f8(void), rand_L16(void), rand_ab16(void);
+double rand_u16f16(void), rand_s15f16(void);
+int dcomp(double a, double b);
+
+/* random ICC specific values */
+unsigned int rand_ScreenEncodings(void);
+unsigned int rand_DeviceAttributes(void);
+unsigned int rand_ProfileHeaderFlags(void);
+unsigned int rand_AsciiOrBinaryData(void);
+icColorSpaceSignature rand_ColorSpaceSignature(void);
+icColorSpaceSignature rand_PCS(void);
+icTechnologySignature rand_TechnologySignature(void);
+icProfileClassSignature rand_ProfileClassSignature(void);
+icPlatformSignature rand_PlatformSignature(void);
+icMeasurementFlare rand_MeasurementFlare(void);
+icMeasurementGeometry rand_MeasurementGeometry(void);
+icRenderingIntent rand_RenderingIntent(void);
+icSpotShape rand_SpotShape(void);
+icStandardObserver rand_StandardObserver(void);
+icIlluminant rand_Illuminant(void);
+
+/* declare some test functions */
+int md5_test(void);
+
+/*
+ I've split the functionality up into two pieces.
+ The main() code does the overall file write/read,
+ while the tag type code is all in the doit() function.
+ The write/read logic is all sandwiched together (distinguished
+ by the state of the mode flag), so that the code for each
+ tag type is kept adjacent.
+
+ In a real application, one wouldn't do it this way.
+*/
+
+int doit(int mode, icc *wr_icco, icc *rd_icco);
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ char *file_name = "xxxx.icm";
+ icmFile *wr_fp, *rd_fp;
+ icc *wr_icco, *rd_icco; /* Keep object separate */
+ int rv = 0;
+ int i;
+ unsigned int offset = 0; /* File write/read offset, 0 for standard icc */
+
+ printf("ICC library regression test, V%s\n",ICCLIB_VERSION_STR);
+
+ /* Do any internal code tests. */
+
+ if (md5_test() != 0)
+ error ("MD5 checksum routine is faulty");
+
+ /* Outer loop does a number of file write/reads, */
+ /* in order to exercise random tests, and to test file offsets. */
+
+ for (i = 0; i < NTRIALS; i++) {
+ unsigned int size; /* Expected write size */
+
+ printf(".");
+ fflush(stdout);
+
+ /* -------------------------- */
+ /* Deal with writing the file */
+
+ /* Open up the file for writing */
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags with their tag types */
+ if ((rv = doit(0, wr_icco, NULL)) != 0)
+ error ("Write tags: %d, %s",rv,wr_icco->err);
+
+ /* Write the file (including all tags) out */
+ /* The last parameter is the offset to write the */
+ /* ICC profile into the file. For a standard ICC profile, */
+ /* this needs to be 0, but it might be non-zero if you are writing */
+ /* an embedded profile. */
+
+ /* Check that get_size() is working too. */
+ if ((size = wr_icco->get_size(wr_icco)) == 0)
+ error ("Write size: %d, %s",wr_icco->errc,wr_icco->err);
+
+ if ((rv = wr_icco->write(wr_icco,wr_fp,offset)) != 0)
+ error ("Write file: %d, %s",rv,wr_icco->err);
+
+ /* To check that get_size() is correct: */
+ {
+ icmFileStd *pp = (icmFileStd *)wr_fp; /* Cheat - Look inside icmFile */
+
+ if (fseek(pp->fp, 0, SEEK_END))
+ error ("Write: seek to EOF failed");
+ if ((unsigned int)ftell(pp->fp) != offset + size)
+ error ("Write: get_size function didn't return correct value - got %d, expected %d",
+ ftell(pp->fp),offset+size);
+ }
+
+ /*
+ Would normally call icco->free(wr_icco);
+ but leave it, so that we can verify the read.
+ */
+
+ wr_fp->del(wr_fp);
+
+ /* -------------------------- */
+ /* Deal with reading and verifying the file */
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ /* The last parameter is the offset to read the */
+ /* ICC profile from the file. For a standard ICC proifile, */
+ /* this needs to be 0, but it might be non-zero if you are writing */
+ /* an embedded profile this needs to be 0, but it might be non-zero */
+ /* if you are writing an embedded profile. */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,offset)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Read and verify all the tags and their tag types */
+ if ((rv = doit(1, wr_icco, rd_icco)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* -------- */
+ /* Clean up */
+ wr_icco->del(wr_icco);
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ /* choose another file offset to test */
+ offset = rand_int(0,72789);
+ }
+
+ printf("\nTest completed OK\n");
+
+ return 0;
+}
+
+/* -------------------------------------------------------------- */
+/* Internal routine checks. */
+
+/* Test the MD5 function. Return nz if fail. */
+int md5_test() {
+ int rv = 0;
+ int i, j;
+ icc *icco;
+ icmMD5 *m;
+
+ unsigned char chs1[16];
+ unsigned char chs2[16];
+
+ /* Standard RFC 1321 test cases */
+ struct {
+ char *s;
+ ORD32 sum[4];
+ } tc[] = {
+ { "", { 0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e } },
+ { "a", { 0x0cc175b9, 0xc0f1b6a8, 0x31c399e2, 0x69772661 } },
+ { "abc", { 0x90015098, 0x3cd24fb0, 0xd6963f7d, 0x28e17f72 } },
+ { "message digest", { 0xf96b697d, 0x7cb7938d, 0x525a2f31, 0xaaf161d0 } },
+ { "abcdefghijklmnopqrstuvwxyz", { 0xc3fcd3d7, 0x6192e400, 0x7dfb496c, 0xca67e13b } },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ { 0xd174ab98, 0xd277d9f5, 0xa5611c2c, 0x9f419d9f } },
+ { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ { 0x57edf4a2, 0x2be3c955, 0xac49da2e, 0x2107b67a } },
+ { NULL, { 0,0,0,0 } }
+ };
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ m = new_icmMD5(icco->al);
+
+ for (i = 0; ; i++) {
+ if (tc[i].s == NULL)
+ break;
+
+ m->reset(m);
+
+ m->add(m, (unsigned char *)tc[i].s, strlen(tc[i].s));
+ m->get(m, chs2);
+
+ /* Convert reference to a byte stream */
+ chs1[0] = (tc[i].sum[0] >> 24) & 0xff,
+ chs1[1] = (tc[i].sum[0] >> 16) & 0xff,
+ chs1[2] = (tc[i].sum[0] >> 8) & 0xff,
+ chs1[3] = tc[i].sum[0] & 0xff,
+ chs1[4] = (tc[i].sum[1] >> 24) & 0xff,
+ chs1[5] = (tc[i].sum[1] >> 16) & 0xff,
+ chs1[6] = (tc[i].sum[1] >> 8) & 0xff,
+ chs1[7] = tc[i].sum[1] & 0xff,
+ chs1[8] = (tc[i].sum[2] >> 24) & 0xff,
+ chs1[9] = (tc[i].sum[2] >> 16) & 0xff,
+ chs1[10] = (tc[i].sum[2] >> 8) & 0xff,
+ chs1[11] = tc[i].sum[2] & 0xff,
+ chs1[12] = (tc[i].sum[3] >> 24) & 0xff,
+ chs1[13] = (tc[i].sum[3] >> 16) & 0xff,
+ chs1[14] = (tc[i].sum[3] >> 8) & 0xff,
+ chs1[15] = tc[i].sum[3] & 0xff;
+
+ for (j = 0; j < 16; j++) {
+ if (chs1[j] != chs2[j]) {
+ printf("MD5 check on '%s' fails at %d with:\n",tc[i].s,j);
+ printf("Sum is %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ chs2[0], chs2[1], chs2[2], chs2[3], chs2[4], chs2[5], chs2[6], chs2[7],
+ chs2[8], chs2[9], chs2[10], chs2[11], chs2[12], chs2[13], chs2[14], chs2[15]);
+ printf("Should be %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ chs1[0], chs1[1], chs1[2], chs1[3], chs1[4], chs1[5], chs1[6], chs1[7],
+ chs1[8], chs1[9], chs1[10], chs1[11], chs1[12], chs1[13], chs1[14], chs1[15]);
+ rv = 1;
+ break;
+ }
+ }
+
+ }
+ m->del(m);
+ icco->del(icco);
+
+ return rv;
+}
+
+/* -------------------------------------------------------------- */
+/* This is the code that inits and checks the header and tag data. */
+/* Note that to undestand this, you need a copy of the ICC profile */
+/* spec., and a copy of the icc header file (icc34.h in this code) */
+/* All items that begin "icXXX" are from the ICC generic icc34.h file, */
+/* while the items that begin "icmXXX" are machine versions of structures */
+/* that are specific to this library. */
+
+int doit(
+ int mode, /* 0 - write, 1 = read/verify */
+ icc *wr_icco, /* The write icc object */
+ icc *rd_icco /* The read icc object */
+) {
+ int rv = 0;
+
+ /* ----------- */
+ /* The header: */
+ if (mode == 0) {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigAbstractClass;
+ wh->colorSpace = rand_ColorSpaceSignature();
+ wh->pcs = rand_PCS();
+ wh->renderingIntent = rand_RenderingIntent();
+
+ /* Values that should be set before writing */
+ wh->manufacturer = str2tag("tst1");
+ wh->model = str2tag("1234");
+ wh->attributes.l = rand_DeviceAttributes();
+ wh->flags = rand_ProfileHeaderFlags();
+
+ /* Values that may optionally be set before writing */
+ wh->attributes.h = 0x12345678;
+ wh->creator = str2tag("tst2");
+
+ /* Values that are not normally set. Set them to non-defaults for testing */
+ wh->cmmId = str2tag("tst3");
+ wh->majv = 3; /* Default version 2.1.0 */
+ wh->minv = 2;
+ wh->bfv = 1;
+ wh->date.year = rand_int(1900,3000); /* Defaults to current date */
+ wh->date.month = rand_int(1,12);
+ wh->date.day = rand_int(1,31);
+ wh->date.hours = rand_int(0,23);
+ wh->date.minutes = rand_int(0,59);
+ wh->date.seconds = rand_int(0,59);
+ wh->platform = rand_PlatformSignature();
+ wh->illuminant.X = rand_XYZ16(); /* Defaults to D50 */
+ wh->illuminant.Y = rand_XYZ16();
+ wh->illuminant.Z = rand_XYZ16();
+ } else {
+ icmHeader *rh = rd_icco->header;
+ icmHeader *wh = wr_icco->header;
+
+ /* Check all the values */
+ rv |= (rh->deviceClass != wh->deviceClass);
+ rv |= (rh->colorSpace != wh->colorSpace);
+ rv |= (rh->pcs != wh->pcs);
+ rv |= (rh->renderingIntent != wh->renderingIntent);
+ rv |= (rh->manufacturer != wh->manufacturer);
+ rv |= (rh->model != wh->model);
+ rv |= (rh->attributes.l != wh->attributes.l);
+ rv |= (rh->attributes.h != wh->attributes.h);
+ rv |= (rh->flags != wh->flags);
+ rv |= (rh->creator != wh->creator);
+ rv |= (rh->cmmId != wh->cmmId);
+ rv |= (rh->majv != wh->majv);
+ rv |= (rh->minv != wh->minv);
+ rv |= (rh->bfv != wh->bfv);
+ rv |= (rh->date.year != wh->date.year);
+ rv |= (rh->date.month != wh->date.month);
+ rv |= (rh->date.day != wh->date.day);
+ rv |= (rh->date.hours != wh->date.hours);
+ rv |= (rh->date.minutes != wh->date.minutes);
+ rv |= (rh->date.seconds != wh->date.seconds);
+ rv |= (rh->platform != wh->platform);
+ rv |= dcomp(rh->illuminant.X, wh->illuminant.X);
+ rv |= dcomp(rh->illuminant.Y, wh->illuminant.Y);
+ rv |= dcomp(rh->illuminant.Z, wh->illuminant.Z);
+ if (rv)
+ error ("Header verify failed");
+ }
+ /* ------------- */
+ /* CrdInfo info: */
+ {
+ char *str1 = "Product Name";
+ char *str2[4] = { "Intent zero CRD Name",
+ "Intent one CRD Name",
+ "Intent two CRD Name",
+ "Intent three CRD Name" };
+ static icmCrdInfo *wo;
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmCrdInfo *)wr_icco->add_tag(
+ wr_icco, icSigCrdInfoTag, icSigCrdInfoType)) == NULL)
+ return 1;
+
+ wo->ppsize = strlen(str1)+1; /* Allocated and used size of text, inc null */
+ for (i = 0; i < 4; i++)
+ wo->crdsize[i] = strlen(str2[i])+1; /* Allocated and used size of text, inc null */
+
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ /* Note we could allocate and copy as we go, rather than doing them all at once. */
+
+ strcpy(wo->ppname, str1); /* Copy the text in */
+ for (i = 0; i < 4; i++)
+ strcpy(wo->crdname[i], str2[i]); /* Copy the text in */
+ } else {
+ icmCrdInfo *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmCrdInfo *)rd_icco->read_tag(rd_icco, icSigCrdInfoTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigCrdInfoType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->ppsize != wo->ppsize)
+ for (i = 0; i < 4; i++) {
+ if (ro->crdsize[i] != wo->crdsize[i])
+ error ("CrdInfo crdsize[%d] doesn't match",i);
+ }
+
+ rv |= strcmp(ro->ppname, wo->ppname);
+ for (i = 0; i < 4; i++) {
+ rv |= strcmp(ro->crdname[i], wo->crdname[i]);
+ }
+
+ if (rv)
+ error ("CrdInfo verify failed");
+ }
+ }
+ /* ---------------------- */
+ /* Curve - Linear version */
+ {
+ static icmCurve *wo;
+ if (mode == 0) {
+ if ((wo = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigRedTRCTag, icSigCurveType)) == NULL)
+ return 1;
+
+ wo->flag = icmCurveLin; /* Linear version */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ } else {
+ icmCurve *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigRedTRCTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigCurveType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->flag != wo->flag)
+ error ("Curve flag doesn't match for Linear");
+
+ if (ro->size != wo->size)
+ error ("Curve size doesn't match");
+
+ if (rv)
+ error ("Curve verify failed");
+ }
+ }
+ /* --------------------- */
+ /* Curve - Gamma version */
+ {
+ static icmCurve *wo;
+ if (mode == 0) {
+ if ((wo = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigGreenTRCTag, icSigCurveType)) == NULL)
+ return 1;
+
+ wo->flag = icmCurveGamma; /* Gamma version */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0] = rand_u8f8(); /* Gamma value */
+ } else {
+ icmCurve *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigGreenTRCTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigCurveType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->flag != wo->flag)
+ error ("Curve flag doesn't match for Gamma");
+
+ if (ro->size != wo->size)
+ error ("Curve size doesn't match");
+
+ rv |= dcomp(ro->data[0], wo->data[0]);
+
+ if (rv)
+ error ("Curve verify failed");
+ }
+ }
+ /* ------------------------- */
+ /* Curve - Specified version */
+ {
+ static icmCurve *wo;
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigBlueTRCTag, icSigCurveType)) == NULL)
+ return 1;
+
+ wo->flag = icmCurveSpec; /* Specified version */
+ wo->size = rand_int(2,23); /* Number of entries (min must be 2!) */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ for (i = 0; i < wo->size; i++)
+ wo->data[i] = rand_16f(); /* Curve values 0.0 - 1.0 */
+ } else {
+ icmCurve *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigBlueTRCTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigCurveType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->flag != wo->flag)
+ error ("Curve flag doesn't match for specified");
+
+ if (ro->size != wo->size)
+ error ("Curve size doesn't match");
+
+ for (i = 0; i < wo->size; i++)
+ rv |= dcomp(ro->data[i], wo->data[i]);
+
+ if (rv)
+ error ("Curve verify failed");
+ }
+ }
+ /* ------------------- */
+ /* Data - text version */
+ {
+ static icmData *wo;
+ char *ts1 = "This is a data string";
+ if (mode == 0) {
+ if ((wo = (icmData *)wr_icco->add_tag(
+ wr_icco, icSigPs2CRD0Tag, icSigDataType)) == NULL)
+ return 1;
+
+ wo->flag = icmDataASCII; /* Holding ASCII data */
+ wo->size = strlen(ts1)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy((char *)wo->data, ts1); /* Copy the text in */
+ } else {
+ icmData *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmData *)rd_icco->read_tag(rd_icco, icSigPs2CRD0Tag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigDataType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->flag != wo->flag)
+ error ("Data size doesn't match");
+
+ if (ro->size != wo->size)
+ error ("Data size doesn't match");
+
+ rv |= strcmp((char *)ro->data, (char *)wo->data);
+
+ if (rv)
+ error ("Data verify failed");
+ }
+ }
+ /* --------------------- */
+ /* Data - Binary version */
+ {
+ static icmData *wo;
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmData *)wr_icco->add_tag(
+ wr_icco, icSigPs2CRD1Tag, icSigDataType)) == NULL)
+ return 1;
+
+ wo->flag = icmDataBin; /* Holding binary data */
+ wo->size = rand_int(0,43); /* Space we need for data */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ for (i = 0; i < wo->size; i ++)
+ wo->data[i] = rand_o8();
+ } else {
+ icmData *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmData *)rd_icco->read_tag(rd_icco, icSigPs2CRD1Tag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigDataType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->flag != wo->flag)
+ error ("Data size doesn't match");
+
+ if (ro->size != wo->size)
+ error ("Data size doesn't match");
+
+ for (i = 0; i < wo->size; i++)
+ rv |= (ro->data[i] != wo->data[i]);
+
+ if (rv)
+ error ("Data verify failed");
+ }
+ }
+ /* --------- */
+ /* DateTime: */
+ {
+ static icmDateTimeNumber *wo;
+ if (mode == 0) {
+ if ((wo = (icmDateTimeNumber *)wr_icco->add_tag(
+ wr_icco, icSigCalibrationDateTimeTag, icSigDateTimeType)) == NULL)
+ return 1;
+
+ wo->year = rand_int(1900, 3000);
+ wo->month = rand_int(1, 12);
+ wo->day = rand_int(1, 31);
+ wo->hours = rand_int(0, 23);
+ wo->minutes = rand_int(0, 59);
+ wo->seconds = rand_int(0, 59);
+ } else {
+ icmDateTimeNumber *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmDateTimeNumber *)rd_icco->read_tag(rd_icco, icSigCalibrationDateTimeTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigDateTimeType)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->year != wo->year);
+ rv |= (ro->month != wo->month);
+ rv |= (ro->day != wo->day);
+ rv |= (ro->hours != wo->hours);
+ rv |= (ro->minutes != wo->minutes);
+ rv |= (ro->seconds != wo->seconds);
+
+ if (rv)
+ error ("DateTime verify failed");
+ }
+ }
+ /* ----------- */
+ /* 16 bit lut: */
+ {
+ static icmLut *wo;
+ if (mode == 0) {
+ unsigned int i, j, k;
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigAToB0Tag, icSigLut16Type)) == NULL)
+ return 1;
+
+ wo->inputChan = 2;
+ wo->outputChan = 3;
+ wo->clutPoints = 5;
+ wo->inputEnt = 56;
+ wo->outputEnt = 73;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space */
+ for (i = 0; i < 3; i++) /* Matrix */
+ for (j = 0; j < 3; j++)
+ wo->e[i][j] = rand_s15f16();
+
+ /* See icc.getNormFuncs() for normalizing functions */
+ /* The input table index range is over the normalized range 0.0 - 1.0. */
+ /* The range in input color space can be determined by denormalizing */
+ /* the values 0.0 - 1.0. */
+ for (i = 0; i < wo->inputChan; i++) /* Input tables */
+ for (j = 0; j < wo->inputEnt; j++)
+ wo->inputTable[i * wo->inputEnt + j] = rand_16f();
+
+ /* Lut */
+ /* The multidimentional lut has a normalized index range */
+ /* of 0.0 - 1.0 in each dimension. Its entry values are also */
+ /* normalized values in the range 0.0 - 1.0. */
+ for (i = 0; i < wo->clutPoints; i++) /* Input chan 0 - slow changing */
+ for (j = 0; j < wo->clutPoints; j++) /* Input chan 1 - faster changing */
+ for (k = 0; k < wo->outputChan; k++) /* Output chans */
+ wo->clutTable[(i * wo->clutPoints + j) * wo->outputChan + k] = rand_16f();
+
+ /* The output color space values should be normalized to the */
+ /* range 0.0 - 1.0 for use as output table entry values. */
+ for (i = 0; i < wo->outputChan; i++) /* Output tables */
+ for (j = 0; j < wo->outputEnt; j++)
+ wo->outputTable[i * wo->outputEnt + j] = rand_16f();
+
+ } else {
+ icmLut *ro;
+ unsigned int size;
+ unsigned int i, j;
+
+ /* Try and read the tag from the file */
+ ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB0Tag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigLut16Type)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->inputChan != wo->inputChan);
+ rv |= (ro->outputChan != wo->outputChan);
+ rv |= (ro->clutPoints != wo->clutPoints);
+ rv |= (ro->inputEnt != wo->inputEnt);
+ rv |= (ro->outputEnt != wo->outputEnt);
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ rv |= dcomp(ro->e[i][j], wo->e[i][j]);
+
+ size = (wo->inputChan * wo->inputEnt);
+ for (i = 0; i < size; i++)
+ rv |= dcomp(ro->inputTable[i], wo->inputTable[i]);
+
+ size = wo->outputChan;
+ for (i = 0; i < wo->inputChan; i++)
+ size *= wo->clutPoints;
+ for (i = 0; i < size; i++)
+ rv |= dcomp(ro->clutTable[i], wo->clutTable[i]);
+
+ size = (wo->outputChan * wo->outputEnt);
+ for (i = 0; i < size; i++)
+ rv |= dcomp(ro->outputTable[i], wo->outputTable[i]);
+ if (rv)
+ error ("Lut16 verify failed");
+ }
+ }
+ /* ------------------ */
+ /* 16 bit lut - link: */
+ {
+ static icmLut *wo;
+ if (mode == 0) {
+ /* Just link to the existing LUT. This is often used when there */
+ /* is no distinction between intents, and saves file and memory space. */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB1Tag, icSigAToB0Tag)) == NULL)
+ return 1;
+ } else {
+ icmLut *ro;
+ unsigned int size;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB1Tag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigLut16Type)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->inputChan != wo->inputChan);
+ rv |= (ro->outputChan != wo->outputChan);
+ rv |= (ro->clutPoints != wo->clutPoints);
+ rv |= (ro->inputEnt != wo->inputEnt);
+ rv |= (ro->outputEnt != wo->outputEnt);
+
+ size = (wo->inputChan * wo->inputEnt);
+ for (i = 0; i < size; i++)
+ rv |= (ro->inputTable[i] != wo->inputTable[i]);
+
+ size = wo->outputChan;
+ for (i = 0; i < wo->inputChan; i++)
+ size *= wo->clutPoints;
+ for (i = 0; i < size; i++)
+ rv |= (ro->clutTable[i] != wo->clutTable[i]);
+
+ size = (wo->outputChan * wo->outputEnt);
+ for (i = 0; i < size; i++)
+ rv |= (ro->outputTable[i] != wo->outputTable[i]);
+ if (rv)
+ error ("Lut16 link verify failed");
+ }
+ }
+ /* ---------- */
+ /* 8 bit lut: */
+ {
+ static icmLut *wo;
+ if (mode == 0) {
+ unsigned int i, j, m, k;
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigAToB2Tag, icSigLut8Type)) == NULL)
+ return 1;
+
+ wo->inputChan = 3;
+ wo->outputChan = 2;
+ wo->clutPoints = 4;
+ wo->inputEnt = 256; /* Must be 256 for Lut8 */
+ wo->outputEnt = 256;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ for (i = 0; i < 3; i++) /* Matrix */
+ for (j = 0; j < 3; j++)
+ wo->e[i][j] = rand_s15f16();
+
+ for (i = 0; i < wo->inputChan; i++) /* Input tables */
+ for (j = 0; j < wo->inputEnt; j++)
+ wo->inputTable[i * wo->inputEnt + j] = rand_8f();
+
+ /* Lut */
+ for (i = 0; i < wo->clutPoints; i++) /* Input chan 0 */
+ for (j = 0; j < wo->clutPoints; j++) /* Input chan 1 */
+ for (m = 0; m < wo->clutPoints; m++) /* Input chan 2 */
+ for (k = 0; k < wo->outputChan; k++) { /* Output chans */
+ int idx = ((i * wo->clutPoints + j)
+ * wo->clutPoints + m)
+ * wo->outputChan + k;
+ wo->clutTable[idx] = rand_8f();
+ }
+
+ for (i = 0; i < wo->outputChan; i++) /* Output tables */
+ for (j = 0; j < wo->outputEnt; j++)
+ wo->outputTable[i * wo->outputEnt + j] = rand_8f();
+
+ } else {
+ icmLut *ro;
+ unsigned int size;
+ unsigned int i, j;
+
+ /* Try and read the tag from the file */
+ ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB2Tag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigLut8Type)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->inputChan != wo->inputChan);
+ rv |= (ro->outputChan != wo->outputChan);
+ rv |= (ro->clutPoints != wo->clutPoints);
+ rv |= (ro->inputEnt != wo->inputEnt);
+ rv |= (ro->outputEnt != wo->outputEnt);
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ rv |= dcomp(ro->e[i][j], wo->e[i][j]);
+
+ size = (wo->inputChan * wo->inputEnt);
+ for (i = 0; i < size; i++)
+ rv |= dcomp(ro->inputTable[i], wo->inputTable[i]);
+
+ size = wo->outputChan;
+ for (i = 0; i < wo->inputChan; i++)
+ size *= wo->clutPoints;
+ for (i = 0; i < size; i++)
+ rv |= dcomp(ro->clutTable[i], wo->clutTable[i]);
+
+ size = (wo->outputChan * wo->outputEnt);
+ for (i = 0; i < size; i++)
+ rv |= dcomp(ro->outputTable[i], wo->outputTable[i]);
+ if (rv)
+ error ("Lut8 verify failed");
+ }
+ }
+ /* ----------------- */
+ /* Measurement: */
+ {
+ static icmMeasurement *wo;
+ if (mode == 0) {
+ if ((wo = (icmMeasurement *)wr_icco->add_tag(
+ wr_icco, icSigMeasurementTag, icSigMeasurementType)) == NULL)
+ return 1;
+
+ /* Standard observer */
+ switch(rand_int(0,2)) {
+ case 0:
+ wo->observer = icStdObsUnknown;
+ break;
+ case 1:
+ wo->observer = icStdObs1931TwoDegrees;
+ break;
+ case 2:
+ wo->observer = icStdObs1964TenDegrees;
+ break;
+ }
+
+ /* XYZ for backing color */
+ wo->backing.X = rand_XYZ16();
+ wo->backing.Y = rand_XYZ16();
+ wo->backing.Z = rand_XYZ16();
+
+ /* Measurement geometry */
+ switch(rand_int(0,2)) {
+ case 0:
+ wo->geometry = icGeometryUnknown;
+ break;
+ case 1:
+ wo->geometry = icGeometry045or450;
+ break;
+ case 2:
+ wo->geometry = icGeometry0dord0;
+ break;
+ }
+
+ /* Measurement flare */
+ wo->flare = rand_u16f16();
+
+ /* Illuminant */
+ switch(rand_int(0,8)) {
+ case 0:
+ wo->illuminant = icIlluminantUnknown;
+ break;
+ case 1:
+ wo->illuminant = icIlluminantD50;
+ break;
+ case 2:
+ wo->illuminant = icIlluminantD65;
+ break;
+ case 3:
+ wo->illuminant = icIlluminantD93;
+ break;
+ case 4:
+ wo->illuminant = icIlluminantF2;
+ break;
+ case 5:
+ wo->illuminant = icIlluminantD55;
+ break;
+ case 6:
+ wo->illuminant = icIlluminantA;
+ break;
+ case 7:
+ wo->illuminant = icIlluminantEquiPowerE;
+ break;
+ case 8:
+ wo->illuminant = icIlluminantF8;
+ break;
+ }
+ } else {
+ icmMeasurement *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmMeasurement *)rd_icco->read_tag(rd_icco, icSigMeasurementTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigMeasurementType)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->observer != wo->observer);
+ rv |= dcomp(ro->backing.X, wo->backing.X);
+ rv |= dcomp(ro->backing.Y, wo->backing.Y);
+ rv |= dcomp(ro->backing.Z, wo->backing.Z);
+ rv |= (ro->geometry != wo->geometry);
+ rv |= dcomp(ro->flare, wo->flare);
+ rv |= (ro->illuminant != wo->illuminant);
+
+ if (rv)
+ error ("Measurement verify failed");
+ }
+ }
+ /* ----------------- */
+ /* Old style NamedColor: */
+ {
+ static icmNamedColor *wo;
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmNamedColor *)wr_icco->add_tag(
+ wr_icco, icSigNamedColorTag, icSigNamedColorType)) == NULL)
+ return 1;
+
+ wo->vendorFlag = rand_int(0,65535) << 16; /* Bottom 16 bits for IC use */
+ wo->count = 3; /* Count of named colors */
+ strcpy(wo->prefix,"Prefix"); /* Prefix for each color name, max 32, null terminated */
+ strcpy(wo->suffix,"Suffix"); /* Suffix for each color name, max 32, null terminated */
+
+ wo->allocate((icmBase *)wo); /* Allocate named color structures */
+
+ for (i = 0; i < wo->count; i++) {
+ unsigned int j;
+ sprintf(wo->data[i].root,"Color %d",i); /* Root name, max 32, null terminated */
+ for (j = 0; j < wo->nDeviceCoords; j++) /* nDeviceCoords defaults appropriately */
+ wo->data[i].deviceCoords[j] = rand_8f(); /* Device coords of color */
+ }
+ } else {
+ icmNamedColor *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmNamedColor *)rd_icco->read_tag(rd_icco, icSigNamedColorTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigNamedColorType)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->vendorFlag != wo->vendorFlag);
+ rv |= (ro->count != wo->count);
+ rv |= (ro->nDeviceCoords != wo->nDeviceCoords);
+ rv |= strcmp(ro->prefix, wo->prefix);
+ rv |= strcmp(ro->suffix, wo->suffix);
+
+ if (rv)
+ error ("NamedColor verify failed");
+
+ for (i = 0; i < wo->count; i++) {
+ unsigned int j;
+ rv |= strcmp(ro->data[i].root, wo->data[i].root);
+ for (j = 0; j < wo->nDeviceCoords; j++)
+ rv |= dcomp(ro->data[i].deviceCoords[j], wo->data[i].deviceCoords[j]);
+ }
+
+ if (rv)
+ error ("NamedColor verify failed");
+ }
+ }
+ /* ----------------- */
+ /* NamedColor2: */
+ {
+ static icmNamedColor *wo; /* Shares same machine specific structure */
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmNamedColor *)wr_icco->add_tag(
+ wr_icco, icSigNamedColor2Tag, icSigNamedColor2Type)) == NULL)
+ return 1;
+
+ wo->vendorFlag = rand_int(0,65535) << 16; /* Bottom 16 bits for ICC use */
+ wo->count = 4; /* Count of named colors */
+ wo->nDeviceCoords = 3; /* Num of device coordinates */
+ /* Could set this different to that implied by wr_icco->header->colorSpace */
+ strcpy(wo->prefix,"Prefix-ix"); /* Prefix for each color name, max 32, null terminated */
+ strcpy(wo->suffix,"Suffix-ixix"); /* Suffix for each color name, max 32, null terminated */
+
+ wo->allocate((icmBase *)wo); /* Allocate named color structures */
+
+ for (i = 0; i < wo->count; i++) {
+ unsigned int j;
+ sprintf(wo->data[i].root,"Pigment %d",i); /* Root name, max 32, null terminated */
+ for (j = 0; j < wo->nDeviceCoords; j++)
+ wo->data[i].deviceCoords[j] = rand_8f(); /* Device coords of color */
+ switch(wo->icp->header->pcs) {
+ case icSigXYZData:
+ wo->data[i].pcsCoords[0] = rand_XYZ16();
+ wo->data[i].pcsCoords[1] = rand_XYZ16();
+ wo->data[i].pcsCoords[2] = rand_XYZ16();
+ break;
+ case icSigLabData:
+ wo->data[i].pcsCoords[0] = rand_L16();
+ wo->data[i].pcsCoords[1] = rand_ab16();
+ wo->data[i].pcsCoords[2] = rand_ab16();
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ icmNamedColor *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmNamedColor *)rd_icco->read_tag(rd_icco, icSigNamedColor2Tag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigNamedColor2Type)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->vendorFlag != wo->vendorFlag);
+ rv |= (ro->count != wo->count);
+ rv |= (ro->nDeviceCoords != wo->nDeviceCoords);
+ rv |= strcmp(ro->prefix, wo->prefix);
+ rv |= strcmp(ro->suffix, wo->suffix);
+
+ if (rv)
+ error ("NamedColor2 verify failed");
+
+ for (i = 0; i < wo->count; i++) {
+ unsigned int j;
+ rv |= strcmp(ro->data[i].root, wo->data[i].root);
+ for (j = 0; j < wo->nDeviceCoords; j++)
+ rv |= dcomp(ro->data[i].deviceCoords[j], wo->data[i].deviceCoords[j]);
+ for (j = 0; j < 3; j++) {
+ rv |= dcomp(ro->data[i].pcsCoords[j], wo->data[i].pcsCoords[j]);
+ }
+ }
+
+ if (rv)
+ error ("NamedColor2 verify failed");
+ }
+ }
+ /* ----------------- */
+ /* ColorantTable: */
+ {
+ static icmColorantTable *wo;
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmColorantTable *)wr_icco->add_tag(
+ wr_icco, icSigColorantTableTag, icSigColorantTableType)) == NULL)
+ return 1;
+
+ wo->count = 4; /* Count of colorants - should be same as implied by device space */
+ wo->allocate((icmBase *)wo); /* Allocate ColorantTable structures */
+
+ for (i = 0; i < wo->count; i++) {
+ sprintf(wo->data[i].name,"Color %d",i); /* Colorant name, max 32, null terminated */
+ switch(wo->icp->header->pcs) {
+ case icSigXYZData:
+ wo->data[i].pcsCoords[0] = rand_XYZ16();
+ wo->data[i].pcsCoords[1] = rand_XYZ16();
+ wo->data[i].pcsCoords[2] = rand_XYZ16();
+ break;
+ case icSigLabData:
+ wo->data[i].pcsCoords[0] = rand_L16();
+ wo->data[i].pcsCoords[1] = rand_ab16();
+ wo->data[i].pcsCoords[2] = rand_ab16();
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ icmColorantTable *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmColorantTable *)rd_icco->read_tag(rd_icco, icSigColorantTableTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigColorantTableType)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->count != wo->count);
+
+ if (rv)
+ error ("ColorantTable verify failed");
+
+ for (i = 0; i < wo->count; i++) {
+ int j;
+ rv |= strcmp(ro->data[i].name, wo->data[i].name);
+ for (j = 0; j < 3; j++) {
+ rv |= dcomp(ro->data[i].pcsCoords[j], wo->data[i].pcsCoords[j]);
+ }
+ }
+
+ if (rv)
+ error ("ColorantTable verify failed");
+ }
+ }
+ /* ----------------- */
+ /* ProfileSequenceDescTag: */
+ {
+ unsigned short ts2a[29] = {'T','h','i','s',' ','i','s',' ','a',' ','d','e','v','i','c','e',
+ ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000};
+ unsigned short ts2b[28] = {'T','h','i','s',' ','i','s',' ','a',' ','m','o','d','e','l',
+ ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000};
+ char *ts3a = "This is a device description";
+ char *ts3b = "This is a model description";
+ static icmProfileSequenceDesc*wo;
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmProfileSequenceDesc *)wr_icco->add_tag(
+ wr_icco, icSigProfileSequenceDescTag, icSigProfileSequenceDescType)) == NULL)
+ return 1;
+
+ wo->count = 3; /* Number of descriptions in sequence */
+ wo->allocate((icmBase *)wo); /* Allocate space for all the DescStructures */
+
+ /* Fill in each description structure in sequence */
+ for (i = 0; i < wo->count; i++) {
+ char ts1[100];
+ wo->data[i].deviceMfg = str2tag("mfg7");
+ wo->data[i].deviceModel = str2tag("2345");
+ wo->data[i].attributes.l = icTransparency | icMatte;
+ wo->data[i].attributes.h = 0x98765432;
+ wo->data[i].technology = rand_TechnologySignature();
+
+ /* device Text description */
+ sprintf(ts1,"This is device descrption %d",i);
+ wo->data[i].device.size = strlen(ts1)+1;
+ wo->data[i].allocate(&wo->data[i]); /* Allocate space */
+ strcpy(wo->data[i].device.desc, ts1); /* Copy the string in */
+
+ /* We'll fudge up the Unicode string */
+ wo->data[i].device.ucLangCode = 8765; /* UniCode language code */
+ wo->data[i].device.ucSize = 29; /* Size in chars inc null */
+ wo->data[i].allocate(&wo->data[i]); /* Allocate space */
+ memmove(wo->data[i].device.ucDesc, ts2a, 2 * 29); /* Copy string in */
+
+ wo->data[i].device.scCode = 67; /* Fudge scriptCode code */
+ wo->data[i].device.scSize = strlen(ts3a)+1; /* Used size of scDesc in bytes, inc null */
+ if (wo->data[i].device.scSize > 67)
+ error("ScriptCode string longer than 67");
+ strcpy((char *)wo->data[i].device.scDesc, ts3a); /* Copy the string in */
+
+ /* model Text description */
+ sprintf(ts1,"This is model descrption %d",i);
+ wo->data[i].model.size = strlen(ts1)+1;
+ wo->data[i].allocate(&wo->data[i]); /* Allocate space */
+ strcpy(wo->data[i].model.desc, ts1); /* Copy the string in */
+
+ /* We'll fudge up the Unicode string */
+ wo->data[i].model.ucLangCode = 7856; /* UniCode language code */
+ wo->data[i].model.ucSize = 28; /* Size in chars inc null */
+ wo->data[i].allocate(&wo->data[i]); /* Allocate space */
+ memmove(wo->data[i].model.ucDesc, ts2b, 2 * 28); /* Copy string in */
+
+ wo->data[i].model.scCode = 67; /* Fudge scriptCode code */
+ wo->data[i].model.scSize = strlen(ts3b)+1; /* Used size of scDesc in bytes, inc null */
+ if (wo->data[i].model.scSize > 67)
+ error("ScriptCode string longer than 67");
+ strcpy((char *)wo->data[i].model.scDesc, ts3b); /* Copy the string in */
+ }
+ } else {
+ icmProfileSequenceDesc *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmProfileSequenceDesc *)rd_icco->read_tag(rd_icco, icSigProfileSequenceDescTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigProfileSequenceDescType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->count != wo->count)
+ error ("ProfileSequenceDesc count doesn't match");
+
+ for (i = 0; i < wo->count; i++) {
+ rv |= (ro->data[i].deviceMfg != wo->data[i].deviceMfg);
+ rv |= (ro->data[i].deviceModel != wo->data[i].deviceModel);
+ rv |= (ro->data[i].attributes.l != wo->data[i].attributes.l);
+ rv |= (ro->data[i].attributes.h != wo->data[i].attributes.h);
+ rv |= (ro->data[i].technology != wo->data[i].technology);
+
+ /* device Text description */
+ rv |= (ro->data[i].device.size != wo->data[i].device.size);
+ rv |= strcmp(ro->data[i].device.desc, wo->data[i].device.desc);
+
+ rv |= (ro->data[i].device.ucLangCode != wo->data[i].device.ucLangCode);
+ rv |= (ro->data[i].device.ucSize != wo->data[i].device.ucSize);
+ rv |= memcmp(ro->data[i].device.ucDesc, wo->data[i].device.ucDesc, wo->data[i].device.ucSize * 2);
+
+ rv |= (ro->data[i].device.scCode != wo->data[i].device.scCode);
+ rv |= (ro->data[i].device.scSize != wo->data[i].device.scSize);
+ rv |= strcmp((char *)ro->data[i].device.scDesc, (char *)wo->data[i].device.scDesc);
+
+ /* model Text description */
+ rv |= (ro->data[i].model.size != wo->data[i].model.size);
+ rv |= strcmp(ro->data[i].model.desc, wo->data[i].model.desc);
+
+ rv |= (ro->data[i].model.ucLangCode != wo->data[i].model.ucLangCode);
+ rv |= (ro->data[i].model.ucSize != wo->data[i].model.ucSize);
+ rv |= memcmp(ro->data[i].model.ucDesc, wo->data[i].model.ucDesc, wo->data[i].model.ucSize * 2);
+
+ rv |= (ro->data[i].model.scCode != wo->data[i].model.scCode);
+ rv |= (ro->data[i].model.scSize != wo->data[i].model.scSize);
+ rv |= strcmp((char *)ro->data[i].model.scDesc, (char *)wo->data[i].model.scDesc);
+ }
+
+ if (rv)
+ error ("ProfileSequenceDesc verify failed");
+ }
+ }
+ /* ----------------- */
+ /* S15Fixed16Array: */
+ {
+ static icmS15Fixed16Array *wo;
+ if (mode == 0) {
+ unsigned int i;
+ /* There is no standard Tag that uses icSigS15Fixed16ArrayType, so use a 'custom' tag */
+ if ((wo = (icmS15Fixed16Array *)wr_icco->add_tag(
+ wr_icco, str2tag("sf32"), icSigS15Fixed16ArrayType)) == NULL)
+ return 1;
+
+ wo->size = rand_int(0,17); /* Number in array */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) {
+ wo->data[i] = rand_s15f16(); /* Set numbers value */
+ }
+ } else {
+ icmS15Fixed16Array *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmS15Fixed16Array *)rd_icco->read_tag(rd_icco, str2tag("sf32"));
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigS15Fixed16ArrayType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->size != wo->size)
+ error ("S15Fixed16Array size doesn't match");
+
+ for (i = 0; i < wo->size; i++) {
+ rv |= dcomp(ro->data[i], wo->data[i]);
+ }
+
+ if (rv)
+ error ("S15Fixed16Array verify failed");
+ }
+ }
+ /* ----------------- */
+ /* Screening: */
+ {
+ static icmScreening *wo;
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmScreening *)wr_icco->add_tag(
+ wr_icco, icSigScreeningTag, icSigScreeningType)) == NULL)
+ return 1;
+
+ wo->screeningFlag = rand_ScreenEncodings();
+ wo->channels = rand_int(1,4); /* Number of channels */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->channels; i++) {
+ wo->data[i].frequency = rand_s15f16(); /* Set screening frequency */
+ wo->data[i].angle = rand_s15f16(); /* Set screening angle */
+ wo->data[i].spotShape = rand_SpotShape(); /* Set spot shape */
+ }
+ } else {
+ icmScreening *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmScreening *)rd_icco->read_tag(rd_icco, icSigScreeningTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigScreeningType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->channels != wo->channels)
+ error ("Screening channels doesn't match");
+
+ rv |= (ro->screeningFlag != wo->screeningFlag);
+
+ for (i = 0; i < wo->channels; i++) {
+ rv |= dcomp(ro->data[i].frequency, wo->data[i].frequency);
+ rv |= dcomp(ro->data[i].angle, wo->data[i].angle);
+ rv |= (ro->data[i].spotShape != wo->data[i].spotShape);
+ }
+
+ if (rv)
+ error ("Screening verify failed");
+ }
+ }
+ /* ----------------- */
+ /* Signature: */
+ {
+ static icmSignature *wo;
+ if (mode == 0) {
+ if ((wo = (icmSignature *)wr_icco->add_tag(
+ wr_icco, icSigTechnologyTag, icSigSignatureType)) == NULL)
+ return 1;
+
+ wo->sig = rand_TechnologySignature();
+ } else {
+ icmSignature *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmSignature *)rd_icco->read_tag(rd_icco, icSigTechnologyTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigSignatureType)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->sig != wo->sig);
+
+ if (rv)
+ error ("Signature verify failed");
+ }
+ }
+ /* ----------------- */
+ /* Text Description: */
+ {
+ static icmTextDescription *wo;
+ char *ts1 = "This is a test description";
+ unsigned short ts2[27] = {'T','h','i','s',' ','i','s',' ','a',' ','t','e','s','t',
+ ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000};
+ char *ts3 = "This is a test3 description";
+ if (mode == 0) {
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ return 1;
+
+ /* Data in tag type wojects is always allocated and freed by the woject */
+ wo->size = strlen(ts1)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, ts1); /* Copy the string in */
+
+ /* We'll fudge up the Unicode string */
+ wo->ucLangCode = 1234; /* UniCode language code */
+ wo->ucSize = 27; /* Allocated and used size of ucDesc in characters, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ memmove(wo->ucDesc, ts2, 2 * 27); /* Copy string in */
+
+ /* Don't really know anything about scriptCode, but fudge some values */
+ wo->scCode = 23; /* ScriptCode code */
+ wo->scSize = strlen(ts3)+1; /* Used size of scDesc in bytes, inc null */
+ /* No allocations, since this has a fixed max of 67 bytes */
+ if (wo->scSize > 67)
+ error("ScriptCode string longer than 67");
+ strcpy((char *)wo->scDesc, ts3); /* Copy the string in */
+ } else {
+ icmTextDescription *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmTextDescription *)rd_icco->read_tag(rd_icco, icSigProfileDescriptionTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ /* We could have left it icmBase, switched on ro->ttype, & then cast appropriately. */
+ if (ro->ttype != icSigTextDescriptionType)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->size != wo->size);
+ rv |= strcmp(ro->desc, wo->desc);
+
+ rv |= (ro->ucLangCode != wo->ucLangCode);
+ rv |= (ro->ucSize != wo->ucSize);
+ rv |= memcmp(ro->ucDesc, wo->ucDesc, wo->ucSize * 2);
+
+ rv |= (ro->scCode != wo->scCode);
+ rv |= (ro->scSize != wo->scSize);
+ rv |= strcmp((char *)ro->scDesc, (char *)wo->scDesc);
+ if (rv)
+ error ("Text Description verify failed4");
+ }
+ }
+ /* ----- */
+ /* Text: */
+ {
+ static icmText *wo;
+ char *ts1 = "This is Copyright by me!";
+ if (mode == 0) {
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ return 1;
+
+ wo->size = strlen(ts1)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, ts1); /* Copy the text in */
+ } else {
+ icmText *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmText *)rd_icco->read_tag(rd_icco, icSigCopyrightTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigTextType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->size != wo->size)
+ error ("Text size doesn't match");
+
+ rv |= strcmp(ro->data, wo->data);
+
+ if (rv)
+ error ("Text verify failed");
+ }
+ }
+ /* ---------------- */
+ /* U16Fixed16Array: */
+ {
+ static icmU16Fixed16Array *wo;
+ if (mode == 0) {
+ unsigned int i;
+ /* There is no standard Tag that uses icSigU16Fixed16ArrayType, so use a 'custom' tag */
+ if ((wo = (icmU16Fixed16Array *)wr_icco->add_tag(
+ wr_icco, str2tag("uf32"), icSigU16Fixed16ArrayType)) == NULL)
+ return 1;
+
+ wo->size = rand_int(0,17); /* Number in array */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) {
+ wo->data[i] = rand_u16f16(); /* Set numbers value */
+ }
+ } else {
+ icmU16Fixed16Array *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmU16Fixed16Array *)rd_icco->read_tag(rd_icco, str2tag("uf32"));
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigU16Fixed16ArrayType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->size != wo->size)
+ error ("U16Fixed16Array size doesn't match");
+
+ for (i = 0; i < wo->size; i++) {
+ rv |= dcomp(ro->data[i], wo->data[i]);
+ }
+
+ if (rv)
+ error ("U16Fixed16Array verify failed");
+ }
+ }
+ /* ------------------- */
+ /* UcrBg - full curve: */
+ {
+ static icmUcrBg *wo;
+ char *ts1 = "UcrBg - full curve info";
+ if (mode == 0) {
+ unsigned int i;
+ if ((wo = (icmUcrBg *)wr_icco->add_tag(
+ wr_icco, icSigUcrBgTag, icSigUcrBgType)) == NULL)
+ return 1;
+
+ wo->UCRcount = rand_int(2,55); /* Number in UCR curve */
+ wo->BGcount = rand_int(2,32); /* Number in BG array */
+ wo->allocate((icmBase *)wo); /* Allocate space for both curves */
+ for (i = 0; i < wo->UCRcount; i++)
+ wo->UCRcurve[i] = rand_16f(); /* Set numbers value */
+ for (i = 0; i < wo->BGcount; i++)
+ wo->BGcurve[i] = rand_16f(); /* Set numbers value */
+ wo->size = strlen(ts1)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ strcpy(wo->string, ts1); /* Copy the text in */
+ } else {
+ icmUcrBg *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmUcrBg *)rd_icco->read_tag(rd_icco, icSigUcrBgTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigUcrBgType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->UCRcount != wo->UCRcount)
+ error ("UcrBg UCRcount doesn't match");
+
+ if (ro->BGcount != wo->BGcount)
+ error ("UcrBg BGcount doesn't match");
+
+ for (i = 0; i < wo->UCRcount; i++)
+ rv |= dcomp(ro->UCRcurve[i], wo->UCRcurve[i]);
+
+ for (i = 0; i < wo->BGcount; i++)
+ rv |= dcomp(ro->BGcurve[i], wo->BGcurve[i]);
+
+ if (ro->size != wo->size)
+ error ("Text size doesn't match");
+
+ rv |= strcmp(ro->string, wo->string);
+
+ if (rv)
+ error ("UcrBg verify failed");
+ }
+ }
+ /* ------------------- */
+ /* UcrBg - percentage: */
+ {
+ static icmUcrBg *wo;
+ char *ts1 = "UcrBg - percentage info";
+ if (mode == 0) {
+ if ((wo = (icmUcrBg *)wr_icco->add_tag(
+ wr_icco, str2tag("bfd%"), icSigUcrBgType)) == NULL)
+ return 1;
+
+ wo->UCRcount = 1; /* 1 == UCR percentage */
+ wo->BGcount = 1; /* 1 == BG percentage */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ wo->UCRcurve[0] = (double) rand_int(0,65535);
+ wo->BGcurve[0] = (double) rand_int(0,65535);
+ wo->size = strlen(ts1)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->string, ts1); /* Copy the text in */
+ } else {
+ icmUcrBg *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmUcrBg *)rd_icco->read_tag(rd_icco, str2tag("bfd%"));
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigUcrBgType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->UCRcount != wo->UCRcount)
+ error ("UcrBg UCRcount doesn't match");
+
+ if (ro->BGcount != wo->BGcount)
+ error ("UcrBg BGcount doesn't match");
+
+ rv |= (ro->UCRcurve[0] != wo->UCRcurve[0]);
+ rv |= (ro->BGcurve[0] != wo->BGcurve[0]);
+
+ if (ro->size != wo->size)
+ error ("Text size doesn't match");
+
+ rv |= strcmp(ro->string, wo->string);
+
+ if (rv)
+ error ("UcrBg verify failed");
+ }
+ }
+ /* ------------ */
+ /* UInt16Array: */
+ {
+ static icmUInt16Array *wo;
+ if (mode == 0) {
+ unsigned int i;
+ /* There is no standard Tag that uses icSigUInt16ArrayType, so use a 'custom' tag */
+ if ((wo = (icmUInt16Array *)wr_icco->add_tag(
+ wr_icco, str2tag("ui16"), icSigUInt16ArrayType)) == NULL)
+ return 1;
+
+ wo->size = rand_int(0,17); /* Number in array */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) {
+ wo->data[i] = rand_o16(); /* Set numbers value */
+ }
+ } else {
+ icmUInt16Array *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmUInt16Array *)rd_icco->read_tag(rd_icco, str2tag("ui16"));
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigUInt16ArrayType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->size != wo->size)
+ error ("UInt16Array size doesn't match");
+
+ for (i = 0; i < wo->size; i++) {
+ rv |= (ro->data[i] != wo->data[i]);
+ }
+
+ if (rv)
+ error ("UInt16Array verify failed");
+ }
+ }
+ /* ------------ */
+ /* UInt32Array: */
+ {
+ static icmUInt32Array *wo;
+ if (mode == 0) {
+ unsigned int i;
+ /* There is no standard Tag that uses icSigUInt32ArrayType, so use a 'custom' tag */
+ if ((wo = (icmUInt32Array *)wr_icco->add_tag(
+ wr_icco, str2tag("ui32"), icSigUInt32ArrayType)) == NULL)
+ return 1;
+
+ wo->size = rand_int(0,18); /* Number in array */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) {
+ wo->data[i] = rand_o32(); /* Set numbers value */
+ }
+ } else {
+ icmUInt32Array *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmUInt32Array *)rd_icco->read_tag(rd_icco, str2tag("ui32"));
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigUInt32ArrayType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->size != wo->size)
+ error ("UInt32Array size doesn't match");
+
+ for (i = 0; i < wo->size; i++) {
+ rv |= (ro->data[i] != wo->data[i]);
+ }
+
+ if (rv)
+ error ("UInt32Array verify failed");
+ }
+ }
+ /* ------------ */
+ /* UInt64Array: */
+ {
+ static icmUInt64Array *wo;
+ if (mode == 0) {
+ unsigned int i;
+ /* There is no standard Tag that uses icSigUInt64ArrayType, so use a 'custom' tag */
+ if ((wo = (icmUInt64Array *)wr_icco->add_tag(
+ wr_icco, str2tag("ui64"), icSigUInt64ArrayType)) == NULL)
+ return 1;
+
+ wo->size = rand_int(0,19); /* Number in array */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) {
+ wo->data[i].l = rand_o32(); /* Set numbers value - low 32 bits */
+ wo->data[i].h = rand_o32(); /* Set numbers value - low 32 bits */
+ }
+ } else {
+ icmUInt64Array *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmUInt64Array *)rd_icco->read_tag(rd_icco, str2tag("ui64"));
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigUInt64ArrayType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->size != wo->size)
+ error ("UInt64Array size doesn't match");
+
+ for (i = 0; i < wo->size; i++) {
+ rv |= (ro->data[i].l != wo->data[i].l);
+ rv |= (ro->data[i].h != wo->data[i].h);
+ }
+
+ if (rv)
+ error ("UInt64Array verify failed");
+ }
+ }
+ /* ----------- */
+ /* UInt8Array: */
+ {
+ static icmUInt8Array *wo;
+ if (mode == 0) {
+ unsigned int i;
+ /* There is no standard Tag that uses icSigUInt8ArrayType, so use a 'custom' tag */
+ if ((wo = (icmUInt8Array *)wr_icco->add_tag(
+ wr_icco, str2tag("ui08"), icSigUInt8ArrayType)) == NULL)
+ return 1;
+
+ wo->size = rand_int(0,18); /* Number in array */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) {
+ wo->data[i] = rand_o8(); /* Set numbers value */
+ }
+ } else {
+ icmUInt8Array *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmUInt8Array *)rd_icco->read_tag(rd_icco, str2tag("ui08"));
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigUInt8ArrayType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->size != wo->size)
+ error ("UInt8Array size doesn't match");
+
+ for (i = 0; i < wo->size; i++) {
+ rv |= (ro->data[i] != wo->data[i]);
+ }
+
+ if (rv)
+ error ("UInt8Array verify failed");
+ }
+ }
+ /* --------------- */
+ /* VideoCardGamma: (ColorSync specific) */
+ {
+ static icmVideoCardGamma *wo;
+ if (mode == 0) {
+ int i;
+ if ((wo = (icmVideoCardGamma *)wr_icco->add_tag(
+ wr_icco, icSigVideoCardGammaTag, icSigVideoCardGammaType)) == NULL)
+ return 1;
+
+ wo->tagType = icmVideoCardGammaTableType;
+ wo->u.table.channels = rand_int(1,3);
+ wo->u.table.entryCount = rand_int(2,1024);
+ wo->u.table.entrySize = rand_int(1,2);
+ wo->allocate((icmBase *)wo);
+ if (wo->u.table.entrySize == 1) {
+ unsigned char *cp = wo->u.table.data;
+ for (i=0; i<wo->u.table.channels*wo->u.table.entryCount;i++,cp++)
+ *cp = (unsigned char)rand_int(0,255);
+ } else {
+ unsigned short *sp = wo->u.table.data;
+ for (i=0; i<wo->u.table.channels*wo->u.table.entryCount;i++,sp++)
+ *sp = (unsigned short)rand_int(0,65535);
+ }
+ } else {
+ icmVideoCardGamma *ro;
+ int i;
+
+ /* Try and read tag from the file */
+ ro = (icmVideoCardGamma *)rd_icco->read_tag(rd_icco, icSigVideoCardGammaTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate */
+ if (ro->ttype != icSigVideoCardGammaType)
+ return 1;
+
+ /* Now check it out */
+ rv |= (ro->tagType != wo->tagType);
+ rv |= (ro->u.table.channels != wo->u.table.channels);
+ rv |= (ro->u.table.entryCount != wo->u.table.entryCount);
+ rv |= (ro->u.table.entrySize != wo->u.table.entrySize);
+ for (i=0; i<ro->u.table.channels*ro->u.table.entryCount*ro->u.table.entrySize; i++) {
+ rv |= (((char*)ro->u.table.data)[i] != ((char*)wo->u.table.data)[i]);
+ if (rv) break;
+ }
+ if (rv)
+ error ("VideoCardGamma verify failed");
+ }
+ }
+ /* ------------------ */
+ /* ViewingConditions: */
+ {
+ static icmViewingConditions *wo;
+ if (mode == 0) {
+ if ((wo = (icmViewingConditions *)wr_icco->add_tag(
+ wr_icco, icSigViewingConditionsTag, icSigViewingConditionsType)) == NULL)
+ return 1;
+
+ wo->illuminant.X = rand_XYZ16(); /* XYZ of illuminant in cd/m^2 */
+ wo->illuminant.Y = rand_XYZ16();
+ wo->illuminant.Z = rand_XYZ16();
+ wo->surround.X = rand_XYZ16(); /* XYZ of surround in cd/m^2 */
+ wo->surround.Y = rand_XYZ16();
+ wo->surround.Z = rand_XYZ16();
+ wo->stdIlluminant = rand_Illuminant(); /* Standard illuminent type */
+ } else {
+ icmViewingConditions *ro;
+
+ /* Try and read the tag from the file */
+ ro = (icmViewingConditions *)rd_icco->read_tag(rd_icco, icSigViewingConditionsTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigViewingConditionsType)
+ return 1;
+
+ /* Now check it out */
+ rv |= dcomp(ro->illuminant.X, wo->illuminant.X);
+ rv |= dcomp(ro->illuminant.Y, wo->illuminant.Y);
+ rv |= dcomp(ro->illuminant.Z, wo->illuminant.Z);
+ rv |= dcomp(ro->surround.X , wo->surround.X);
+ rv |= dcomp(ro->surround.Y , wo->surround.Y);
+ rv |= dcomp(ro->surround.Z , wo->surround.Z);
+ rv |= (ro->stdIlluminant != wo->stdIlluminant);
+
+ if (rv)
+ error ("ViewingConditions verify failed");
+ }
+ }
+ /* ---------- */
+ /* XYZ array: */
+ {
+ static icmXYZArray *wo;
+ if (mode == 0) {
+ unsigned int i;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ return 1;
+
+ wo->size = rand_int(1,7); /* Should be one XYZ number, but test more */
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) {
+ wo->data[i].X = rand_XYZ16(); /* Set numbers value */
+ wo->data[i].Y = rand_XYZ16();
+ wo->data[i].Z = rand_XYZ16();
+ }
+ } else {
+ icmXYZArray *ro;
+ unsigned int i;
+
+ /* Try and read the tag from the file */
+ ro = (icmXYZArray *)rd_icco->read_tag(rd_icco, icSigMediaWhitePointTag);
+ if (ro == NULL)
+ return 1;
+
+ /* Need to check that the cast is appropriate. */
+ if (ro->ttype != icSigXYZArrayType)
+ return 1;
+
+ /* Now check it out */
+ if (ro->size != wo->size)
+ error ("XYZArray size doesn't match");
+
+ for (i = 0; i < wo->size; i++) {
+ rv |= dcomp(ro->data[i].X, wo->data[i].X);
+ rv |= dcomp(ro->data[i].Y, wo->data[i].Y);
+ rv |= dcomp(ro->data[i].Z, wo->data[i].Z);
+ }
+
+ if (rv)
+ error ("XYZArray verify failed");
+ }
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------ */
+/* Floating point random number generators */
+/* These are appropriate for the underlying integer */
+/* representations in the icc format. */
+/* This is simply as a convenience so that we can */
+/* test the full range of representation, and */
+/* get away with exact verification. */
+
+/* 32 bit pseudo random sequencer */
+static unsigned int seed = 0x12345678;
+
+/* #define PSRAND(S) ((S) * 1103515245 + 12345) */
+#define PSRAND(S) (((S) & 0x80000000) ? (((S) << 1) ^ 0xa398655d) : ((S) << 1))
+
+unsigned int rand_o8() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed & 0xff;
+ return o32;
+}
+
+unsigned int rand_o16() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed & 0xffff;
+ return o32;
+}
+
+unsigned int rand_o32() {
+ ORD32 o32;
+ o32 = seed = PSRAND(seed);
+ return o32;
+}
+
+int rand_int(int low, int high) {
+ int i;
+ seed = PSRAND(seed);
+ i = seed % (high - low + 1);
+ return i + low;
+}
+
+double rand_u8f8() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed & 0xffff;
+ return (double)o32/256.0;
+}
+
+double rand_u16f16() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed;
+ return (double)o32/65536.0;
+}
+
+double rand_s15f16() {
+ INR32 i32;
+ seed = PSRAND(seed);
+ i32 = seed;
+ return (double)i32/65536.0;
+}
+
+double rand_XYZ16() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed & 0xffff;
+ return (double)o32/32768.0;
+}
+
+double rand_L8() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed & 0xff;
+ return (double)o32/2.550;
+}
+
+double rand_ab8() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed & 0xff;
+ return (double)o32-128.0;
+}
+
+double rand_L16() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed & 0xffff;
+ return (double)o32/652.800; /* 0xff00/100.0 */
+}
+
+double rand_ab16() {
+ ORD32 o32;
+ seed = PSRAND(seed);
+ o32 = seed & 0xffff;
+ return ((double)o32/256.0)-128.0;
+}
+
+double rand_8f() {
+ unsigned int rv;
+ seed = PSRAND(seed);
+ rv = seed & 0xff;
+ return (double)rv/255.0;
+}
+
+double rand_16f() {
+ unsigned int rv;
+ seed = PSRAND(seed);
+ rv = seed & 0xffff;
+ return (double)rv/65535.0;
+}
+
+/* Random selectors for ICC flags and enumerayions */
+
+unsigned int rand_ScreenEncodings() {
+ unsigned int flags = 0;
+
+ if (rand_int(0,1) == 0)
+ flags |= icPrtrDefaultScreensTrue;
+
+ if (rand_int(0,1) == 0)
+ flags |= icLinesPerInch;
+
+ return flags;
+}
+
+/* Device attributes */
+unsigned int rand_DeviceAttributes() {
+ unsigned int flags = 0;
+
+ if (rand_int(0,1) == 0)
+ flags |= icTransparency;
+
+ if (rand_int(0,1) == 0)
+ flags |= icMatte;
+
+ return flags;
+}
+
+/* Profile header flags */
+unsigned int rand_ProfileHeaderFlags() {
+ unsigned int flags = 0;
+
+ if (rand_int(0,1) == 0)
+ flags |= icEmbeddedProfileTrue;
+
+ if (rand_int(0,1) == 0)
+ flags |= icUseWithEmbeddedDataOnly;
+
+ return flags;
+}
+
+
+unsigned int rand_AsciiOrBinaryData() {
+ unsigned int flags = 0;
+
+ if (rand_int(0,1) == 0)
+ flags |= icBinaryData;
+
+ return flags;
+}
+
+icColorSpaceSignature rand_ColorSpaceSignature() {
+ switch(rand_int(0,25)) {
+ case 0:
+ return icSigXYZData;
+ case 1:
+ return icSigLabData;
+ case 2:
+ return icSigLuvData;
+ case 3:
+ return icSigYCbCrData;
+ case 4:
+ return icSigYxyData;
+ case 5:
+ return icSigRgbData;
+ case 6:
+ return icSigGrayData;
+ case 7:
+ return icSigHsvData;
+ case 8:
+ return icSigHlsData;
+ case 9:
+ return icSigCmykData;
+ case 10:
+ return icSigCmyData;
+ case 11:
+ return icSigMch6Data;
+ case 12:
+ return icSig2colorData;
+ case 13:
+ return icSig3colorData;
+ case 14:
+ return icSig4colorData;
+ case 15:
+ return icSig5colorData;
+ case 16:
+ return icSig6colorData;
+ case 17:
+ return icSig7colorData;
+ case 18:
+ return icSig8colorData;
+ case 19:
+ return icSig9colorData;
+ case 20:
+ return icSig10colorData;
+ case 21:
+ return icSig11colorData;
+ case 22:
+ return icSig12colorData;
+ case 23:
+ return icSig13colorData;
+ case 24:
+ return icSig14colorData;
+ case 25:
+ return icSig15colorData;
+ }
+ return icMaxEnumData;
+}
+
+icColorSpaceSignature rand_PCS() {
+ switch(rand_int(0,1)) {
+ case 0:
+ return icSigXYZData;
+ case 1:
+ return icSigLabData;
+ }
+ return icMaxEnumData;
+}
+
+icTechnologySignature rand_TechnologySignature() {
+ switch(rand_int(0,21)) {
+ case 0:
+ return icSigDigitalCamera;
+ case 1:
+ return icSigFilmScanner;
+ case 2:
+ return icSigReflectiveScanner;
+ case 3:
+ return icSigInkJetPrinter;
+ case 4:
+ return icSigThermalWaxPrinter;
+ case 5:
+ return icSigElectrophotographicPrinter;
+ case 6:
+ return icSigElectrostaticPrinter;
+ case 7:
+ return icSigDyeSublimationPrinter;
+ case 8:
+ return icSigPhotographicPaperPrinter;
+ case 9:
+ return icSigFilmWriter;
+ case 10:
+ return icSigVideoMonitor;
+ case 11:
+ return icSigVideoCamera;
+ case 12:
+ return icSigProjectionTelevision;
+ case 13:
+ return icSigCRTDisplay;
+ case 14:
+ return icSigPMDisplay;
+ case 15:
+ return icSigAMDisplay;
+ case 16:
+ return icSigPhotoCD;
+ case 17:
+ return icSigPhotoImageSetter;
+ case 18:
+ return icSigGravure;
+ case 19:
+ return icSigOffsetLithography;
+ case 20:
+ return icSigSilkscreen;
+ case 21:
+ return icSigFlexography;
+ }
+ return icMaxEnumTechnology;
+}
+
+icProfileClassSignature rand_ProfileClassSignature() {
+ switch(rand_int(0,6)) {
+ case 0:
+ return icSigInputClass;
+ case 1:
+ return icSigDisplayClass;
+ case 2:
+ return icSigOutputClass;
+ case 3:
+ return icSigLinkClass;
+ case 4:
+ return icSigAbstractClass;
+ case 5:
+ return icSigColorSpaceClass;
+ case 6:
+ return icSigNamedColorClass;
+ }
+ return icMaxEnumClass;
+}
+
+icPlatformSignature rand_PlatformSignature() {
+ switch(rand_int(0,4)) {
+ case 0:
+ return icSigMacintosh;
+ case 1:
+ return icSigMicrosoft;
+ case 2:
+ return icSigSolaris;
+ case 3:
+ return icSigSGI;
+ case 4:
+ return icSigTaligent;
+ }
+ return icMaxEnumPlatform;
+}
+
+icMeasurementFlare rand_MeasurementFlare() {
+ switch(rand_int(0,1)) {
+ case 0:
+ return icFlare0;
+ case 1:
+ return icFlare100;
+ }
+ return icMaxFlare;
+}
+
+icMeasurementGeometry rand_MeasurementGeometry() {
+ switch(rand_int(0,2)) {
+ case 0:
+ return icGeometryUnknown;
+ case 1:
+ return icGeometry045or450;
+ case 2:
+ return icGeometry0dord0;
+ }
+ return icMaxGeometry;
+}
+
+icRenderingIntent rand_RenderingIntent() {
+ switch(rand_int(0,3)) {
+ case 0:
+ return icPerceptual;
+ case 1:
+ return icRelativeColorimetric;
+ case 2:
+ return icSaturation;
+ case 3:
+ return icAbsoluteColorimetric;
+ }
+ return icMaxEnumIntent;
+}
+
+icSpotShape rand_SpotShape() {
+ switch(rand_int(0,7)) {
+ case 0:
+ return icSpotShapeUnknown;
+ case 1:
+ return icSpotShapePrinterDefault;
+ case 2:
+ return icSpotShapeRound;
+ case 3:
+ return icSpotShapeDiamond;
+ case 4:
+ return icSpotShapeEllipse;
+ case 5:
+ return icSpotShapeLine;
+ case 6:
+ return icSpotShapeSquare;
+ case 7:
+ return icSpotShapeCross;
+ }
+ return icMaxEnumSpot;
+}
+
+icStandardObserver rand_StandardObserver() {
+ switch(rand_int(0,2)) {
+ case 0:
+ return icStdObsUnknown;
+ case 1:
+ return icStdObs1931TwoDegrees;
+ case 2:
+ return icStdObs1964TenDegrees;
+ }
+ return icMaxStdObs;
+}
+
+icIlluminant rand_Illuminant() {
+ switch(rand_int(0,8)) {
+ case 0:
+ return icIlluminantUnknown;
+ case 1:
+ return icIlluminantD50;
+ case 2:
+ return icIlluminantD65;
+ case 3:
+ return icIlluminantD93;
+ case 4:
+ return icIlluminantF2;
+ case 5:
+ return icIlluminantD55;
+ case 6:
+ return icIlluminantA;
+ case 7:
+ return icIlluminantEquiPowerE;
+ case 8:
+ return icIlluminantF8;
+ }
+ return icMaxEnumIlluminant;
+}
+
+/* Compare doubles with a margine to allow */
+/* for floating point handling funnies */
+int dcomp(double a, double b) {
+ double dif = fabs(a - b);
+ double mag = fabs(a) + fabs(b);
+
+ return dif > (mag * 1e-10) ? 1 : 0;
+}
+
+/* ------------------------------------------------ */
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icctest: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icctest: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/icc/lab2lab.icm b/icc/lab2lab.icm
new file mode 100644
index 0000000..fe518e6
--- /dev/null
+++ b/icc/lab2lab.icm
Binary files differ
diff --git a/icc/log.txt b/icc/log.txt
new file mode 100644
index 0000000..97435b6
--- /dev/null
+++ b/icc/log.txt
@@ -0,0 +1,173 @@
+
+ Change History: (See ArgyllCMS log.txt too)
+
+ 2.15
+ Change icc->read_tag() to only succeed if the tag type is
+ known, since the standard expectation of a non NULL
+ return type is that it is of a known type. Added new
+ method icc->read_tag_any() which will return a
+ icmSigUnknownType if the tag type is unknown.
+
+ 2.14
+ Fix potential array bounds violation in icc/icc.c for malformed
+ cLUT profiles with zero input channels.
+
+ 2.10
+
+ Added protection against crafted file integer overflows.
+
+ Many minor additions to support ArgyllCMS.
+
+ Further add V4 compatibility, with changes to PCS encoding.
+
+ 2.06
+
+ Added MD5 checksum code for profile ID support.
+
+ 2.05
+ Version in Argyll V0.51 release.
+
+ Started adding support for ICC V4. Not enabled yet.
+
+ Expanded internal/effective colorspace/ranges support
+ to be uniform between all the lookup types.
+
+ 2.04
+
+ Fixed minor casting nits picked up by some compilers
+ (thanks to Keith Trummel).
+
+ Make intent selection for Matrix profiles and Gamut tables
+ more forgiving if not ICM_STRICT.
+
+ 2.03
+ Added simple extention when dumping binary data tag to
+ dump ASCII as well if verb >= 4.
+
+ Added Makefile support for compiling under MAC OSX.
+
+ Added access to primitive read and write functions, so custom tag
+ data can be marshalled using standard encodings.
+
+ Expanded ICM_STRICT to encompass bad DateTime information in the header,
+ and also disable required tag checking on reading or lookups.
+ Changed default intent for Output profiles to perceptual from
+ colorimetric, since this would usually be expected.
+
+ Added workaround for faulty Kodak RGB matrix profiles, that
+ have their primary XYZ coordinates scaled to 100.0 rather than
+ 1.0. This is enabled if ICM_STRICT is not defined.
+
+ Replaced Lab<->XYZ functions with simpler versions.
+
+ Expand icmFile implimentation to handle icmAlloc
+
+ Do check for header Magic number first.
+
+ Add convenience function that creates an RGB to XYZ transform
+ matrix from the device primaries and the white point.
+
+ Separated stdio versions of file and alloc to allow
+ compile without these.
+
+ Non-standard (ie. Apple) 5,6,7 & 8 channel color signatures
+ weren't being handled properly thruout the library.
+
+ 2.02
+ Merged rename of [u]int64 to icm[Ui][I]nt64 (to work around
+ AIX 5.1L portability bug) from Raph Levien.
+
+ Fixed stray , in icmLookupOrder structure definition (from Dan Coby)
+
+ 2.01
+ Change TextDescription code to not barf if #undef ICM_STRICT and
+ Apple scriptcode not padded to 67 bytes.
+
+ Add get_ranges() method to all Lu types, not just LuLut.
+ Fix bug in PCS override logic that was causing
+ reverse conversions to apply the wrong conversion.
+
+ Added Delta E convenience functions icmLabDE() and
+ icmCIE94() etc.
+
+ Merged Raph Levien's cleanups, to quiet gcc warnings.
+
+ Merged another couple of warning cleanups from Jouk Jansen.
+
+ 2.00
+ Change absolute conversion to be white point only, and use
+ Bradford transform by default. (ie. we are now ignoring the
+ comment in section 6.4.22 of the 1998 spec. about the
+ media black point being used for absolute colorimetry,
+ ignoring the recommendation on page 118 in section E.5,
+ and are taking up the recommendation on page 124 in section
+ E.16 that a more sophisticated chromatic adaptation model be used.)
+
+ This is for better compatibility with other CMM's, and to
+ improve the results when using simple links between
+ profiles with non-D50 white points. Standard profiles
+ like sRGB will also be more accurate when interpreted
+ with absolute colorimetric intent.
+ This will cause some slight incompatibilty with previous
+ versions of icclib.
+
+ Added ColorSync 2.5 specific VideoCardGamma tag support
+ (from Neil Okamoto)
+
+ 1.31
+ Added file I/O class to allow substitution of alternative ICC profile
+ file access. Provide standard file class instance, and memory image
+ instance of file I/O class as default and example.
+ Added an optional new_icc_a() object creator, that takes a memory
+ allocator class instance. This allows an alternate memory heap to
+ be used with the icc class.
+ Renamed object free() methods to del() for more consistency with new().
+
+ 1.30
+ Added workaround for reading some Adobe profiles with confused header DateTime.
+ Enhanced tag allocate() methods so that they can resize allocations.
+ Enhanced icmLut_set_tables() to access grid points in a cache friendly order.
+ Fixed bug in check_icc_legal() that caused bogus errors, removed
+ uneccessary static declarations in icc.h, and fixed a bug in
+ icmTable_lookup_bwd() that effected both accuracy and speed. (Thanks to Andrei Frolov)
+ Removed icmAbsoluteColorimetricXYZ intent, and replaced it with
+ a PCS override capability. This adds a new parameter to get_luobj()
+ Added Lab translations of some XYZ "dump" strings.
+ Fix memory leak after failed tag read + rename_tag function
+ + shared library support changes. (Thanks to Carles Llopis).
+ Changed all the public 2str utility routines to a single function
+ that can be used to interpret an enumeration or tag in a human
+ readable form.
+
+ 1.23
+ Fixed important bug in Lut read/write. The matrix values had their
+ rows and columns switched. Not many profiles exercise this code.
+ Thanks to David Gillman for discovering this problem.
+ Fixup compiler complains about illegal enum values for icmCurveStyle,
+ and icmDataStyle. Malloc memory icmLut_lookup_clut_nl for gw[], so that
+ it is more friendly to systems with a limited stack. (Thanks to Dave White)
+
+ 1.22 99/11/11 Snapshot of current code.
+ Added more hooks to support inherited implementation of
+ color conversion, used in Argyll to support reversing
+ multi-dimentional table lookups.
+ Cleaned up color conversion code to make it easier to follow.
+ Adding simplex interpolation for non-Lab style input space interpolation.
+ Fix Sun misalignment and realloc problems (Thanks to Allan N. Hessenflow)
+ Fixed endian problem with Unicode on read and write.
+ Expanded icmTextDescription_dump() to do hex dump of Unicode and ScriptCode.
+ Changed over to ICC.1:1998-09 .h file.
+ Started implementing ICC.1:1998-09, but not complete yet!
+
+ 1.21 99/2/14
+ After re-reading Michael Bourgoin's 1998 SIGGRAPH notes,
+ I have consolidated the Lut input index, and table value encodings.
+ The default set_tables() scaling has been adjusted appropriately
+ for this correction of Lab encoding.
+ Trying to create an 8 bit XYZ Lut will now fail if icclib helper
+ functions are used to create it.
+
+ 1.20 99/2/7
+ Added profile color lookup functon.
+ Added set_tables() support.
+ Various bug fixes and enhancements.
diff --git a/icc/lutest.c b/icc/lutest.c
new file mode 100644
index 0000000..e43fbc5
--- /dev/null
+++ b/icc/lutest.c
@@ -0,0 +1,3506 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * Lookup test code, and profile creation examples.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2000/6/18
+ * Version: 2.15
+ *
+ * Copyright 1998 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/* TTBD:
+ *
+ */
+
+/*
+
+ This file is intended to serve two purposes. One is to do some
+ basic regression testing of the lookup function of the icc
+ library, by creating profiles with known mapping characteristics,
+ and then checking that lookup displays those characteristics.
+ Given the huge possible number of combinations of color spaces,
+ profile variations, number of input and output channels, intents etc.
+ the tests done here are far from exaustive.
+
+ The other purpose is as a very basic source code example of how
+ to create various styles of ICC profiles from mapping information,
+ since extracting this information from the source code can take some
+ doing. The example code here is still not perfect, since
+ it doesn't cover the finer points of how to handle various intents,
+ gamut compression etc. Such things are really the domain of a
+ CMS, and would be dependent on the exact nature of the
+ profile representation that the ICC file is being created from.
+ (See examples in the Argyll CMS for these sorts of details.)
+
+ (Note XYZ scaling to 1.0, not 100.0, as per ICC)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "icc.h"
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+/* Some debuging aids */
+#define STOPONERROR /* stop if errors are excessive */
+#undef TESTLIN1 /* test linear in curves */
+#undef TESTLIN2 /* test linear clut (fails with Lab) */
+#undef TESTLIN3 /* test linear out curves */
+
+/* These two assist the accuracy of our BToA Lut tests, using our simplistic test functions */
+/* They probably shouldn't be used on any real profile. */
+#define REVLUTSCALE1 /* Define this for pre-clut gamut bounding box scaling */
+#define REVLUTSCALE2 /* Define this for post-clut gamut quantization scaling */
+
+/*
+ * We start with a mathematically defined transfer characteristic, that
+ * we create profiles from, and then check that the lookup function
+ * matches the mathematical characteristic we started with.
+ *
+ * Use a matrix style 3D to 3D XYZ transfer as the core, to be
+ * compatible with a matrix and Lut style profile.
+ */
+
+/* - - - - - - - - - - - - - */
+/* Some support functions */
+
+/* Clip value to range 0.0 to 1.0 */
+void clip(double inout[3]) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ if (inout[i] < 0.0)
+ inout[i] = 0.0;
+ else if (inout[i] > 1.0)
+ inout[i] = 1.0;
+ }
+}
+
+/* Protected power function */
+double ppow(double num, double p) {
+ if (num < 0.0)
+ return -pow(-num, p);
+ else
+ return pow(num, p);
+}
+
+#define D50_X 0.9642
+#define D50_Y 1.0000
+#define D50_Z 0.8249
+
+#define D50_BX ( 0.8951 * D50_X + 0.2664 * D50_Y + -0.1614 * D50_Z)
+#define D50_BY (-0.7502 * D50_X + 1.7135 * D50_Y + 0.0367 * D50_Z)
+#define D50_BZ ( 0.0389 * D50_X + -0.0685 * D50_Y + 1.0296 * D50_Z)
+
+#define ABS_X 0.83
+#define ABS_Y 0.95
+#define ABS_Z 1.05
+
+#define ABS_BX ( 0.8951 * ABS_X + 0.2664 * ABS_Y + -0.1614 * ABS_Z)
+#define ABS_BY (-0.7502 * ABS_X + 1.7135 * ABS_Y + 0.0367 * ABS_Z)
+#define ABS_BZ ( 0.0389 * ABS_X + -0.0685 * ABS_Y + 1.0296 * ABS_Z)
+
+/* Convert from normalized to relative XYZ */
+static void to_rel(double out[3], double in[3]) {
+ /* Scale to relative white and black points */
+ out[0] = D50_X * in[0];
+ out[1] = D50_Y * in[1];
+ out[2] = D50_Z * in[2];
+}
+
+/* Convert from relative to normalized XYZ */
+static void from_rel(double out[3], double in[3]) {
+ /* Remove white and black points scale */
+ out[0] = in[0]/D50_X;
+ out[1] = in[1]/D50_Y;
+ out[2] = in[2]/D50_Z;
+}
+
+/* Convert from relative to absolute XYZ */
+static void rel_to_abs(double out[3], double in[3]) {
+ double tt[3];
+
+ /* Multiply by bradford */
+ tt[0] = 0.8951 * in[0] + 0.2664 * in[1] + -0.1614 * in[2];
+ tt[1] = -0.7502 * in[0] + 1.7135 * in[1] + 0.0367 * in[2];
+ tt[2] = 0.0389 * in[0] + -0.0685 * in[1] + 1.0296 * in[2];
+
+ /* Scale from D50 to absolute white point */
+ tt[0] = tt[0] * ABS_BX/D50_BX;
+ tt[1] = tt[1] * ABS_BY/D50_BY;
+ tt[2] = tt[2] * ABS_BZ/D50_BZ;
+
+ /* Inverse bradford */
+ out[0] = 0.986993 * tt[0] + -0.147054 * tt[1] + 0.159963 * tt[2];
+ out[1] = 0.432305 * tt[0] + 0.518360 * tt[1] + 0.049291 * tt[2];
+ out[2] = -0.008529 * tt[0] + 0.040043 * tt[1] + 0.968487 * tt[2];
+}
+
+/* Convert from normalized to absolute XYZ */
+static void to_abs(double out[3], double in[3]) {
+
+ to_rel(out, in); /* Convert to relative */
+ rel_to_abs(out, out); /* Convert to absolute */
+
+}
+
+/* Convert from absolute to relative XYZ */
+static void abs_to_rel(double out[3], double in[3]) {
+ double tt[3];
+
+ /* Multiply by bradford */
+ tt[0] = 0.8951 * in[0] + 0.2664 * in[1] + -0.1614 * in[2];
+ tt[1] = -0.7502 * in[0] + 1.7135 * in[1] + 0.0367 * in[2];
+ tt[2] = 0.0389 * in[0] + -0.0685 * in[1] + 1.0296 * in[2];
+
+ /* Scale from absolute white point to D50 */
+ tt[0] = tt[0] * D50_BX/ABS_BX;
+ tt[1] = tt[1] * D50_BY/ABS_BY;
+ tt[2] = tt[2] * D50_BZ/ABS_BZ;
+
+ /* Inverse bradford */
+ out[0] = 0.986993 * tt[0] + -0.147054 * tt[1] + 0.159963 * tt[2];
+ out[1] = 0.432305 * tt[0] + 0.518360 * tt[1] + 0.049291 * tt[2];
+ out[2] = -0.008529 * tt[0] + 0.040043 * tt[1] + 0.968487 * tt[2];
+}
+
+#ifdef NEVER /* Not currently used */
+/* Convert from absolute to normalized XYZ */
+static void from_abs(double out[3], double in[3]) {
+
+ abs_to_rel(out, in); /* Convert to relative */
+ from_rel(out, out); /* Convert to normalised */
+}
+#endif /* NEVER */
+
+/* CIE XYZ to perceptual Lab with ICC D50 white point */
+static void
+XYZ2Lab(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+ double L;
+
+ x = X/D50_X;
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ y = Y/D50_Y;
+ if (y > 0.008856451586) {
+ fy = pow(y,1.0/3.0);
+ L = 116.0 * fy - 16.0;
+ } else {
+ fy = 7.787036979 * y + 16.0/116.0;
+ L = 903.2963058 * y;
+ }
+
+ z = Z/D50_Z;
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = L;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+/* Perceptual Lab with ICC D50 white point to CIE XYZ */
+static void
+Lab2XYZ(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ out[0] = x * D50_X;
+ out[1] = y * D50_Y;
+ out[2] = z * D50_Z;
+}
+
+/* - - - - - - - - - - - - - */
+
+/* Return maximum difference */
+static double maxdiff(double in1[3], double in2[3]) {
+ double tt, rv = 0.0;
+ if ((tt = fabs(in1[0] - in2[0])) > rv)
+ rv = tt;
+ if ((tt = fabs(in1[1] - in2[1])) > rv)
+ rv = tt;
+ if ((tt = fabs(in1[2] - in2[2])) > rv)
+ rv = tt;
+ return rv;
+}
+
+/* Return absolute difference */
+static double absdiff(double in1[3], double in2[3]) {
+ double tt, rv = 0.0;
+ tt = in1[0] - in2[0];
+ rv += tt * tt;
+ tt = in1[1] - in2[1];
+ rv += tt * tt;
+ tt = in1[2] - in2[2];
+ rv += tt * tt;
+ return sqrt(rv);
+}
+
+/* - - - - - - - - - - - - - - - - - */
+/* Overall Monochrome XYZ device model is */
+/* Gray -> GrayY -> XYZ */
+/* Where GrayY is assumed to directly Scale Y */
+
+/* Gray -> GrayY */
+static double Gray_GrayY(double in) {
+#ifdef TESTLIN1
+ return in;
+#else
+ return ppow(in,1.6);
+#endif
+}
+
+/* GrayY -> Gray */
+static double GrayY_Gray(double in) {
+#ifdef TESTLIN1
+ return in;
+#else
+ return ppow(in,1.0/1.6);
+#endif
+}
+
+/* Gray -> XYZ */
+static void Gray_XYZ(double out[3], double in) {
+ double temp[3];
+ temp[0] = temp[1] = temp[2] = Gray_GrayY(in);
+
+ /* Scale to relative white and black points */
+ to_rel(out, temp);
+}
+
+/* XYZ -> Device gray space */
+static double XYZ_Gray(double in[3]) {
+ double temp[3];
+
+ /* Remove relative white and black points scale */
+ from_rel(temp, in);
+
+ /* Do calculation just from Y value */
+ return GrayY_Gray(temp[1]);
+}
+
+/* Gray -> XYZ absolute */
+static void aGray_XYZ(double out[3], double in) {
+ double temp[3];
+ temp[0] = temp[1] = temp[2] = Gray_GrayY(in);
+
+ /* Scale to absolute white and black points */
+ to_abs(out, temp);
+
+}
+
+/* XYZ -> Gray absolute */
+static double aXYZ_Gray(double in[3]) {
+ double tt, temp[3];
+
+ /* Remove absolute white and black points scale */
+ abs_to_rel(temp, in); /* Convert to relative */
+
+ from_rel(temp, temp); /* Convert to normalised */
+
+ /* Do calculation just from Y value */
+ tt = GrayY_Gray(temp[1]);
+
+ return tt;
+}
+
+/* - - - - - - - - - - - */
+/* Overall Monochrome Lab device model is */
+/* Gray -> GrayL -> Lab */
+/* Where GrayL is assumed to directly scale L */
+
+
+/* Gray -> GrayL */
+static double Gray_GrayL(double in) {
+#ifdef TESTLIN1
+ return in; /* normalized L */
+#else
+ return ppow(in,1.6);
+#endif
+}
+
+/* GrayL -> Gray */
+static double GrayL_Gray(double in) {
+#ifdef TESTLIN1
+ return in;
+#else
+ return ppow(in,1.0/1.6); /* Y */
+#endif
+}
+
+/* Gray -> Lab */
+static void Gray_Lab(double out[3], double in) {
+ double tt, wp[3];
+
+ wp[0] = D50_X;
+ wp[1] = D50_Y;
+ wp[2] = D50_Z;
+ XYZ2Lab(wp, wp); /* Lab white point */
+
+ tt = Gray_GrayL(in); /* Raw L value */
+
+ /* Scale to relative Lab white point */
+ out[0] = wp[0] * tt;
+ out[1] = wp[1] * tt;
+ out[2] = wp[2] * tt;
+}
+
+/* Lab -> Gray */
+static double Lab_Gray(double in[3]) {
+ double tt, wp[3];
+
+ wp[0] = D50_X;
+ wp[1] = D50_Y;
+ wp[2] = D50_Z;
+ XYZ2Lab(wp, wp); /* Lab white point */
+
+ /* Scale from relative Lab white point */
+ tt = in[0]/wp[0];
+
+ return GrayL_Gray(tt); /* Raw L value */
+
+}
+
+/* Gray -> Lab absolute */
+static void aGray_Lab(double out[3], double in) {
+
+ /* Generate relative Lab */
+ Gray_Lab(out, in);
+
+ Lab2XYZ(out, out);
+ rel_to_abs(out, out);
+ XYZ2Lab(out, out);
+}
+
+/* Lab -> Gray absolute */
+static double aLab_Gray(double in[3]) {
+ double tt[3];
+
+ Lab2XYZ(tt, in);
+ abs_to_rel(tt, tt);
+ XYZ2Lab(tt, tt);
+
+ return Lab_Gray(tt);
+}
+
+/* - - - - - - - - - - - - - - - - - */
+/* RGB -> XYZ test transfer curves */
+/* Note that overall model is: */
+/* RBG -> RGB' -> XYZ' -> XYZ */
+
+/* Device space linearization */
+/* RGB -> RGB' */
+static void RGB_RGBp(void *cntx, double out[3], double in[3]) {
+#ifdef TESTLIN1
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+#else
+ out[0] = ppow(in[0],1.6);
+ out[1] = ppow(in[1],1.5);
+ out[2] = ppow(in[2],1.4);
+#endif
+}
+
+/* RGB' -> RGB */
+static void RGBp_RGB(void *cntx, double out[3], double in[3]) {
+#ifdef TESTLIN1
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+#else
+ out[0] = ppow(in[0],1.0/1.6);
+ out[1] = ppow(in[1],1.0/1.5);
+ out[2] = ppow(in[2],1.0/1.4);
+#endif
+}
+
+#ifdef TESTLIN2
+static double matrix[3][3] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 },
+};
+#else
+static double matrix[3][3] = {
+ { 0.4361, 0.3851, 0.1431 },
+ { 0.2225, 0.7169, 0.0606 },
+ { 0.0139, 0.0971, 0.7141 },
+};
+#endif
+
+/* 3x3 matrix conversion */
+/* RGB' -> XYZ' */
+static void RGBp_XYZp(void *cntx, double out[3], double in[3]) {
+ double o0,o1,o2;
+
+#ifdef TESTLIN2
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+#else
+ o0 = matrix[0][0] * in[0] + matrix[0][1] * in[1] + matrix[0][2] * in[2];
+ o1 = matrix[1][0] * in[0] + matrix[1][1] * in[1] + matrix[1][2] * in[2];
+ o2 = matrix[2][0] * in[0] + matrix[2][1] * in[1] + matrix[2][2] * in[2];
+
+ out[0] = o0;
+ out[1] = o1;
+ out[2] = o2;
+#endif
+}
+
+/* XYZ' -> RGB' */
+static void XYZp_RGBp(void *cntx, double out[3], double in[3]) {
+ double o0,o1,o2;
+
+#ifdef TESTLIN2
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+#else
+ o0 = 3.13360257102309000 * in[0] + -1.61682140135654430 * in[1] + -0.49074240441282400 * in[2];
+ o1 = -0.97865031588250000 * in[0] + 1.91606100412532800 * in[1] + 0.03351290204844009 * in[2];
+ o2 = 0.07207655781398956 * in[0] + -0.22906554547222160 * in[1] + 1.40535949675456500 * in[2];
+
+ out[0] = o0;
+ out[1] = o1;
+ out[2] = o2;
+#endif
+}
+
+/* Output linearization curves */
+/* XYZ' -> XYZ */
+static void XYZp_XYZ(void *cntx, double out[3], double in[3]) {
+#ifdef TESTLIN3
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+#else
+ out[0] = ppow(in[0],0.9);
+ out[1] = ppow(in[1],0.8);
+ out[2] = ppow(in[2],1.1);
+#endif
+}
+
+/* XYZ -> XYZ' */
+static void XYZ_XYZp(void *cntx, double out[3], double in[3]) {
+#ifdef TESTLIN3
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+#else
+ out[0] = ppow(in[0],1.0/0.9);
+ out[1] = ppow(in[1],1.0/0.8);
+ out[2] = ppow(in[2],1.0/1.1);
+#endif
+}
+
+/* RGB -> XYZ' */
+static void RGB_XYZp(void *cntx, double out[3], double in[3]) {
+ RGB_RGBp(cntx, out, in);
+ RGBp_XYZp(cntx, out, out);
+}
+
+/* RGB -> XYZ', absolute (for matrix profile test) */
+static void aRGB_XYZp(void *cntx, double out[3], double in[3]) {
+ RGB_RGBp(cntx, out, in);
+ RGBp_XYZp(cntx, out, out);
+ from_rel(out, out);
+ to_abs(out, out);
+}
+
+/* RGB -> XYZ */
+static void RGB_XYZ(void *cntx, double out[3], double in[3]) {
+ RGB_RGBp(cntx, out, in);
+ RGBp_XYZp(cntx, out, out);
+ XYZp_XYZ(cntx, out, out);
+}
+
+/* XYZ -> RGB */
+static void XYZ_RGB(void *cntx, double out[3], double in[3]) {
+ XYZ_XYZp(cntx, out, in);
+ XYZp_RGBp(cntx, out, out);
+ RGBp_RGB(cntx, out, out);
+}
+
+/* RGB -> XYZ, absolute */
+static void aRGB_XYZ(void *cntx, double out[3], double in[3]) {
+ RGB_XYZ(cntx, out, in);
+ from_rel(out, out);
+ to_abs(out, out);
+}
+
+#ifdef NEVER /* Not currently used */
+
+/* XYZ -> RGB, absolute */
+static void aXYZ_RGB(void *cntx, double out[3], double in[3]) {
+ from_abs(out, in);
+ to_rel(out, out);
+ XYZ_RGB(cntx, out, out);
+}
+
+/* XYZ -> RGB, gamut constrained */
+static void cXYZ_RGB(void *cntx, double out[3], double in[3]) {
+ XYZ_RGB(cntx, out, in);
+ clip(out);
+}
+
+#endif /* NEVER */
+
+/* XYZ' -> distance to gamut boundary */
+static void XYZp_BDIST(void *cntx, double out[1], double in[3]) {
+ double gdst; /* Gamut error */
+ int m, mini = 0, outg;
+ double tt, mind;
+ double pcs[3]; /* PCS value of input */
+ double dev[3]; /* Device value */
+ double pgb[3]; /* PCS gamut boundary point */
+ double dgb[3]; /* device gamut boundary point */
+
+ /* Do XYZ' -> XYZ */
+ XYZp_XYZ(cntx, pcs, in);
+
+ /* Do XYZ -> RGB transform */
+ XYZ_RGB(NULL, dev, pcs);
+
+ /* Compute nearest point on gamut boundary, */
+ /* and whether it is in or out of gamut. */
+ /* This should be nearest in PCS space, but */
+ /* we'll cheat and find the nearest point in */
+ /* device space, and then compute the distance in PCS space. */
+
+ for (m = 0; m < 3; m++)
+ dgb[m] = dev[m];
+
+ for (mind = 10000.0, outg = 0, m = 0; m < 3; m++) {
+ if (dev[m] < 0.0) { /* Clip any coordinates outside device limits */
+ dgb[m] = 0.0;
+ outg = 1; /* Out of gamut */
+ } else if (dev[m] > 1.0) {
+ dgb[m] = 1.0;
+ outg = 1; /* Out of gamut */
+ } else { /* Note closest cood to boundary if within limits */
+ if (dev[m] < 0.5)
+ tt = 0.5 - dev[m];
+ else /* >= 0.5 */
+ tt = dev[m] - 0.5;
+ if (tt < mind) {
+ mind = tt;
+ mini = m;
+ }
+ }
+ }
+ if (!outg) { /* If point is within gamut, set to closest point */
+ if (dev[mini] < 0.5)
+ dgb[mini] = 0.0;
+ else
+ dgb[mini] = 1.0;
+ }
+
+ /* Do RGB -> XYZ transform on nearest gamut boundary point */
+ RGB_XYZ(NULL, pgb, dgb);
+
+ /* Distance to nearest gamut point in PCS (XYZ) space */
+ gdst = absdiff(pcs, pgb);
+ if (!outg) /* If within gamut */
+ gdst = -gdst;
+
+ /* Distance in PCS space will be roughly -0.866 -> 0.866 */
+ /* Convert so that 0.5 is on boundary, and then clip. */
+ gdst += 0.5;
+ if (gdst < 0.0)
+ gdst = 0.0;
+ else if (gdst > 1.0)
+ gdst = 1.0;
+
+ out[0] = gdst;
+}
+
+/* The output table is usually a special for the gamut table, returning */
+/* a value of 0 for all inputs <= 0.5, and then outputing between */
+/* 0.0 and 1.0 for the input range 0.5 to 1.0. This is so a graduated */
+/* "gamut boundary distance" number from the multi-d lut can be */
+/* translated into the ICC "0.0 if in gamut, > 0.0 if not" number. */
+static void BDIST_GAMMUT(void *cntx, double out[1], double in[1]) {
+ double iv, ov;
+ iv = in[0];
+ if (iv <= 0.5)
+ ov = 0.0;
+ else
+ ov = (iv - 0.5) * 2.0;
+ out[0] = ov;
+}
+
+/* - - - - - - - - - - - - - */
+/* Lab versions for Lut profile, built on top of XYZ model */
+/* The overall model is: */
+/* RBG -> RGB' -> Lab' -> Lab */
+
+/* 3x3 matrix conversion */
+/* RGB' -> Lab' */
+static void RGBp_Labp(void *cntx, double out[3], double in[3]) {
+ RGBp_XYZp(cntx, out, in);
+ XYZ2Lab(out, out);
+}
+
+/* Lab' -> RGB' */
+static void Labp_RGBp(void *cntx, double out[3], double in[3]) {
+ Lab2XYZ(out, in);
+ XYZp_RGBp(cntx, out, out);
+}
+
+/* Lab' -> Lab */
+/* (We are using linear) */
+static void Labp_Lab(void *cntx, double out[3], double in[3]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+}
+
+/* Lab -> Lab' */
+static void Lab_Labp(void *cntx, double out[3], double in[3]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+}
+
+/* RGB -> Lab */
+static void RGB_Lab(void *cntx, double out[3], double in[3]) {
+ RGB_RGBp(cntx, out, in);
+ RGBp_Labp(cntx, out, out);
+ Labp_Lab(cntx, out, out);
+}
+
+/* Lab -> RGB */
+static void Lab_RGB(void *cntx, double out[3], double in[3]) {
+ Lab_Labp(cntx, out, in);
+ Labp_RGBp(cntx, out, out);
+ RGBp_RGB(cntx, out, out);
+}
+
+/* RGB -> Lab, absolute */
+static void aRGB_Lab(void *cntx, double out[3], double in[3]) {
+ RGB_Lab(cntx, out, in);
+ Lab2XYZ(out, out);
+ from_rel(out, out);
+ to_abs(out, out);
+ XYZ2Lab(out, out);
+}
+
+#ifdef NEVER /* Not currently used */
+
+/* Lab -> RGB, absolute */
+static void aLab_RGB(void *cntx, double out[3], double in[3]) {
+ Lab2XYZ(out, in);
+ from_abs(out, out);
+ to_rel(out, out);
+ XYZ2Lab(out, out);
+ Lab_RGB(cntx, out, out);
+}
+
+/* Lab -> RGB, gamut constrained */
+static void cLab_RGB(void *cntx, double out[3], double in[3]) {
+ Lab_RGB(cntx, out, in);
+ clip(out);
+}
+
+#endif /* NEVER */
+
+/* Lab' -> distance to gamut boundary */
+static void Labp_BDIST(void *cntx, double out[1], double in[3]) {
+ double gdst; /* Gamut error */
+ int m, mini = 0, outg;
+ double tt, mind;
+ double pcs[3]; /* PCS value of input */
+ double dev[3]; /* Device value */
+ double pgb[3]; /* PCS gamut boundary point */
+ double dgb[3]; /* device gamut boundary point */
+
+ /* Do Lab' -> Lab */
+ Labp_Lab(cntx, pcs, in);
+
+ /* Do Lab -> RGB transform */
+ Lab_RGB(cntx, dev, pcs);
+
+ /* Compute nearest point on gamut boundary, */
+ /* and whether it is in or out of gamut. */
+ /* This should be nearest in PCS space, but */
+ /* we'll cheat and find the nearest point in */
+ /* device space, and then compute the distance in PCS space. */
+
+ for (m = 0; m < 3; m++)
+ dgb[m] = dev[m];
+
+ for (mind = 10000.0, outg = 0, m = 0; m < 3; m++) {
+ if (dev[m] < 0.0) { /* Clip any coordinates outside device limits */
+ dgb[m] = 0.0;
+ outg = 1; /* Out of gamut */
+ } else if (dev[m] > 1.0) {
+ dgb[m] = 1.0;
+ outg = 1; /* Out of gamut */
+ } else { /* Note closest cood to boundary if within limits */
+ if (dev[m] < 0.5)
+ tt = 0.5 - dev[m];
+ else /* >= 0.5 */
+ tt = dev[m] - 0.5;
+ if (tt < mind) {
+ mind = tt;
+ mini = m;
+ }
+ }
+ }
+ if (!outg) { /* If point is within gamut, set to closest point */
+ if (dev[mini] < 0.5)
+ dgb[mini] = 0.0;
+ else
+ dgb[mini] = 1.0;
+ }
+
+ /* Do RGB -> Lab transform on nearest gamut boundary point */
+ RGB_Lab(NULL, pgb, dgb);
+
+ /* Distance to nearest gamut point in PCS (Lab) space */
+ gdst = absdiff(pcs, pgb);
+ if (!outg) /* If within gamut */
+ gdst = -gdst;
+
+ /* Distance in PCS space will be roughly -86 -> 86 */
+ /* Convert so that 0.5 is on boundary, and then clip. */
+ gdst /= 100.0;
+ gdst += 0.5;
+ if (gdst < 0.0)
+ gdst = 0.0;
+ else if (gdst > 1.0)
+ gdst = 1.0;
+
+ out[0] = gdst;
+}
+
+/* - - - - - - - - - - - - - */
+
+#define TRES 10
+#define MON_POINTS 8101 /* Number of test points in monochrome tests */
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ char *file_name;
+ icmFile *wr_fp, *rd_fp;
+ icc *wr_icco, *rd_icco; /* Keep object separate */
+ int rv = 0;
+
+ /* Check variables */
+ int co[3];
+ double in[3], out[3], check[3];
+
+ {
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+#endif
+ printf("Starting lookup function test - V%s\n",ICCLIB_VERSION_STR);
+
+ /* Do a check that our reference function is reversable */
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do device -> XYZ transform */
+ RGB_XYZ(NULL, out, in);
+
+ /* Do XYZ -> Device transform */
+ XYZ_RGB(NULL, check, out);
+
+ /* Check the result */
+ mxd = maxdiff(in, check);
+ if (mxd > 0.00001)
+#ifdef STOPONERROR
+ error ("Excessive error %f > 0.00001",mxd);
+#else
+ warning ("Excessive error %f > 0.00001",mxd);
+#endif /* STOPONERROR */
+ }
+ }
+ }
+ printf("Self check complete\n");
+ }
+
+ /* ---------------------------------------- */
+ /* Create a monochrome XYZ profile to test */
+ /* ---------------------------------------- */
+
+ /* Open up the file for writing */
+ file_name = "xxxx_mono_XYZ.icm";
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigDisplayClass; /* Could use Output or Input too */
+ wh->colorSpace = icSigGrayData; /* It's a gray space */
+ wh->pcs = icSigXYZData; /* Test XYZ monochrome profile */
+ wh->renderingIntent = icRelativeColorimetric;
+
+ /* Values that should be set before writing */
+ wh->manufacturer = str2tag("tst2");
+ wh->model = str2tag("test");
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst = "This is a test monochrome XYZ style Display Profile";
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt = "Copyright 1998 Graeme Gill";
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = ABS_X; /* Set some silly numbers */
+ wo->data[0].Y = ABS_Y;
+ wo->data[0].Z = ABS_Z;
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.02; /* Doesn't take part in Absolute anymore */
+ wo->data[0].Y = 0.04;
+ wo->data[0].Z = 0.03;
+ }
+ /* Gray Tone Reproduction Curve Tags: */
+ {
+ icmCurve *wog;
+ unsigned int i;
+ if ((wog = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigGrayTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wog->flag = icmCurveSpec; /* Specified version */
+ wog->size = 256; /* Number of entries (min must be 2!) */
+ wog->allocate((icmBase *)wog); /* Allocate space */
+ for (i = 0; i < wog->size; i++) {
+ double vv;
+ vv = i/(wog->size-1.0);
+ wog->data[i] = Gray_GrayY(vv);
+ }
+ }
+
+ /* Write the file out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icco->err);
+
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+
+ /* - - - - - - - - - - - - - - */
+ /* Deal with reading and verifying the monochrome XYZ profile */
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Check the lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = co[0]/(MON_POINTS-1.0);
+
+ /* Do reference conversion of device -> XYZ transform */
+ Gray_XYZ(check,in[0]);
+
+ /* Do lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 0.00005)
+#ifdef STOPONERROR
+ error ("Excessive error in Monochrome XYZ Fwd %f > 0.00005",mxd);
+#else
+ warning ("Excessive error in Monochrome XYZ Fwd %f > 0.00005",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome XYZ fwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse lookup function */
+ {
+ double min[3], range[3];
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Establish the range */
+ Gray_XYZ(min,0.0);
+ Gray_XYZ(range,1.0);
+ range[0] -= min[0];
+ range[1] -= min[1];
+ range[2] -= min[2];
+
+ /* Get a bwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = range[0] * co[0]/(MON_POINTS-1.0) + min[0];
+ in[1] = range[1] * co[0]/(MON_POINTS-1.0) + min[1];
+ in[2] = range[2] * co[0]/(MON_POINTS-1.0) + min[2];
+
+ /* Do reference conversion of XYZ -> device transform */
+ check[0] = XYZ_Gray(in);
+
+ /* Do reverse lookup of XYZ -> device transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = fabs(check[0] - out[0]);
+ if (mxd > 0.00018)
+#ifdef STOPONERROR
+ error ("Excessive error in Monochrome XYZ Bwd %f > 0.00018",mxd);
+#else
+ warning ("Excessive error in Monochrome XYZ Bwd %f > 0.00018",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome XYZ bwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the lookup function, absolute colorimetric */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = co[0]/(MON_POINTS-1.0);
+
+ /* Do reference conversion of device -> XYZ transform */
+ aGray_XYZ(check,in[0]);
+
+ /* Do lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 0.00005)
+#ifdef STOPONERROR
+ error ("Excessive error in Monochrome XYZ Abs Fwd %f > 0.00005",mxd);
+#else
+ warning ("Excessive error in Monochrome XYZ Abs Fwd %f > 0.00005",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome XYZ fwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse lookup function, absolute colorimetric */
+ {
+ double min[3], range[3];
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Establish the range */
+ /* Establish the range */
+ aGray_XYZ(min,0.0);
+ aGray_XYZ(range,1.0);
+ range[0] -= min[0];
+ range[1] -= min[1];
+ range[2] -= min[2];
+
+ /* Get a bwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = range[0] * co[0]/(MON_POINTS-1.0) + min[0];
+ in[1] = range[1] * co[0]/(MON_POINTS-1.0) + min[1];
+ in[2] = range[2] * co[0]/(MON_POINTS-1.0) + min[2];
+
+ /* Do reference conversion of XYZ -> device transform */
+ check[0] = aXYZ_Gray(in);
+
+ /* Do reverse lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = fabs(check[0] - out[0]);
+ if (mxd > 0.0002)
+#ifdef STOPONERROR
+ error ("Excessive error in Monochrome XYZ Abs Bwd %f > 0.0002",mxd);
+#else
+ warning ("Excessive error in Monochrome XYZ Abs Bwd %f > 0.0002",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome XYZ bwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ /* ---------------------------------------- */
+ /* Create a monochrome Lab profile to test */
+ /* ---------------------------------------- */
+
+ /* Open up the file for writing */
+ file_name = "xxxx_mono_Lab.icm";
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigDisplayClass; /* Could use Output or Input too */
+ wh->colorSpace = icSigGrayData; /* It's a gray space */
+ wh->pcs = icSigLabData; /* Use Lab for this monochrome profile */
+ wh->renderingIntent = icRelativeColorimetric;
+
+ /* Values that should be set before writing */
+ wh->manufacturer = str2tag("tst2");
+ wh->model = str2tag("test");
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst = "This is a test monochrome Lab style Display Profile";
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt = "Copyright 1998 Graeme Gill";
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = ABS_X; /* Set some silly numbers */
+ wo->data[0].Y = ABS_Y;
+ wo->data[0].Z = ABS_Z;
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.02; /* Doesn't take part in Absolute anymore */
+ wo->data[0].Y = 0.04;
+ wo->data[0].Z = 0.03;
+ }
+ /* Gray Tone Reproduction Curve Tags: */
+ {
+ icmCurve *wog;
+ unsigned int i;
+ if ((wog = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigGrayTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wog->flag = icmCurveSpec; /* Specified version */
+ wog->size = 256; /* Number of entries (min must be 2!) */
+ wog->allocate((icmBase *)wog); /* Allocate space */
+ for (i = 0; i < wog->size; i++) {
+ double vv;
+ vv = i/(wog->size-1.0);
+ wog->data[i] = Gray_GrayL(vv);
+ }
+ }
+
+ /* Write the file out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icco->err);
+
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+
+ /* - - - - - - - - - - - - - - */
+ /* Deal with reading and verifying the monochrome Lab profile */
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Check the lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = co[0]/(MON_POINTS-1.0);
+
+ /* Do reference conversion of device -> Lab transform */
+ Gray_Lab(check,in[0]);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 0.0025)
+#ifdef STOPONERROR
+ error ("Excessive error in Monochrome Lab Fwd %f > 0.0025",mxd);
+#else
+ warning ("Excessive error in Monochrome Lab Fwd %f > 0.0025",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome Lab fwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse lookup function */
+ {
+ double min, range;
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Establish the range */
+ Gray_Lab(out,0.0);
+ min = out[0];
+ Gray_Lab(out,1.0);
+ range = out[0] - min;
+
+ /* Get a bwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = range * co[0]/(MON_POINTS-1.0) + min;
+
+ /* Do reference conversion of Lab -> device transform */
+ check[0] = Lab_Gray(in);
+
+ /* Do reverse lookup of Lab -> device transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = fabs(check[0] - out[0]);
+ if (mxd > 0.0002)
+#ifdef STOPONERROR
+ error ("Excessive error in Monochrome Lab Bwd %f > 0.0002",mxd);
+#else
+ warning ("Excessive error in Monochrome Lab Bwd %f > 0.0002",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome Lab bwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+#ifdef NEVER
+ /* Check the fwd/bwd accuracy */
+ {
+ double merr = 0.0;
+ icmLuBase *luof, *luob;
+
+ /* Get a fwd conversion object */
+ if ((luof = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ /* Get a bwd conversion object */
+ if ((luob = rd_icco->get_luobj(rd_icco, icmBwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ /* Check it out */
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = co[0]/(MON_POINTS-1.0);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luof->lookup(luof, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Do reverse lookup of device -> Lab transform */
+ if ((rv = luob->lookup(luob, check, out)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ mxd = fabs(in[0] - check[0]);
+ if (mxd > 1e-6) {
+ printf("co %d, in %f, out %f, check %f, err %f\n",
+ co[0],in[0],out[0],check[0], fabs(in[0] - check[0]));
+ }
+
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome Lab fwd/bwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup objects */
+ luof->del(luof);
+ luob->del(luob);
+ }
+
+ /* Benchmark the routines */
+ {
+ int ii;
+ icmLuBase *luo;
+ double no_pixels = 0.0;
+ clock_t stime,ttime;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ stime = clock();
+ no_pixels = 1000.0 * 2048.0;
+
+ for (ii = 0; ii < 1000; ii++) {
+ for (co[0] = 0; co[0] < 2048; co[0]++) {
+ double mxd;
+ in[0] = co[0]/(2048-1.0);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+ }
+ }
+ ttime = clock() - stime;
+ printf("Done - %f seconds, rate = %f Mpix/sec\n",
+ (double)ttime/CLOCKS_PER_SEC,no_pixels * CLOCKS_PER_SEC/ttime);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ {
+ int ii;
+ icmLuBase *luo;
+ double no_pixels = 0.0;
+ clock_t stime,ttime;
+
+ /* Get a bwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ stime = clock();
+ no_pixels = 1000.0 * 2048.0;
+
+ for (ii = 0; ii < 1000; ii++) {
+ for (co[0] = 0; co[0] < 2048; co[0]++) {
+ double mxd;
+ in[0] = 100.0 * co[0]/(2048-1.0);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+ }
+ }
+ ttime = clock() - stime;
+ printf("Done - %f seconds, rate = %f Mpix/sec\n",
+ (double)ttime/CLOCKS_PER_SEC,no_pixels * CLOCKS_PER_SEC/ttime);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+#endif /* NEVER */
+
+ /* Check the lookup function, absolute colorimetric */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = co[0]/(MON_POINTS-1.0);
+
+ /* Do reference conversion of device -> Lab transform */
+ aGray_Lab(check,in[0]);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 0.003)
+#ifdef STOPONERROR
+ error ("Excessive error in Monochrome Lab Fwd Abs %f > 0.003",mxd);
+#else
+ warning ("Excessive error in Monochrome Lab Fwd Abs %f > 0.003",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome Lab fwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse lookup function, absolute colorimetric*/
+ {
+ double min, range;
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Establish the range */
+ aGray_Lab(out,0.0);
+ min = out[0];
+ aGray_Lab(out,1.0);
+ range = out[0] - min;
+
+ /* Get a bwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < MON_POINTS; co[0]++) {
+ double mxd;
+ in[0] = range * co[0]/(MON_POINTS-1.0) + min;
+ in[1] = in[2] = 0.0;
+
+ /* Do reference conversion of Lab -> device transform */
+ check[0] = aLab_Gray(in);
+
+ /* Do reverse lookup of Lab -> device transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = fabs(check[0] - out[0]);
+ if (mxd > 0.005)
+#ifdef STOPONERROR
+ error ("Excessive error in Monochrome Lab Bwd Abs %f > 0.005",mxd);
+#else
+ warning ("Excessive error in Monochrome Lab Bwd Abs %f > 0.005",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ printf("Monochrome Lab bwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ /* ---------------------------------------- */
+ /* Create a matrix based profile to test */
+ /* ---------------------------------------- */
+
+ /* Open up the file for writing */
+ file_name = "xxxx_matrix.icm";
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigDisplayClass; /* Could use Output or Input too */
+ wh->colorSpace = icSigRgbData; /* It's and RGBish space */
+ wh->pcs = icSigXYZData; /* Must be XYZ for matrix based profile */
+ wh->renderingIntent = icRelativeColorimetric;
+
+ /* Values that should be set before writing */
+ wh->manufacturer = str2tag("tst2");
+ wh->model = str2tag("test");
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst = "This is a test matrix style Display Profile";
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt = "Copyright 1998 Graeme Gill";
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = ABS_X; /* Set some silly numbers */
+ wo->data[0].Y = ABS_Y;
+ wo->data[0].Z = ABS_Z;
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.02; /* Doesn't take part in Absolute anymore */
+ wo->data[0].Y = 0.04;
+ wo->data[0].Z = 0.03;
+ }
+ /* Red, Green and Blue Colorant Tags: */
+ {
+ icmXYZArray *wor, *wog, *wob;
+ if ((wor = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigRedColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wog = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigGreenColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigBlueColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wor->size = wog->size = wob->size = 1;
+ wor->allocate((icmBase *)wor); /* Allocate space */
+ wog->allocate((icmBase *)wog);
+ wob->allocate((icmBase *)wob);
+ wor->data[0].X = matrix[0][0]; wor->data[0].Y = matrix[1][0]; wor->data[0].Z = matrix[2][0];
+ wog->data[0].X = matrix[0][1]; wog->data[0].Y = matrix[1][1]; wog->data[0].Z = matrix[2][1];
+ wob->data[0].X = matrix[0][2]; wob->data[0].Y = matrix[1][2]; wob->data[0].Z = matrix[2][2];
+ }
+ /* Red, Green and Blue Tone Reproduction Curve Tags: */
+ {
+ icmCurve *wor, *wog, *wob;
+ unsigned int i;
+ if ((wor = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigRedTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wog = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigGreenTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigBlueTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wor->flag = wog->flag = wob->flag = icmCurveSpec; /* Specified version */
+ wor->size = wog->size = wob->size = 256; /* Number of entries (min must be 2!) */
+ wor->allocate((icmBase *)wor); /* Allocate space */
+ wog->allocate((icmBase *)wog);
+ wob->allocate((icmBase *)wob);
+ for (i = 0; i < wor->size; i++) {
+ double vv[3];
+ vv[0] = vv[1] = vv[2] = i/(wor->size-1.0);
+ RGB_RGBp(NULL, vv, vv); /* Transfer function we want */
+ wor->data[i] = vv[0]; /* Curve values 0.0 - 1.0 */
+ wog->data[i] = vv[1];
+ wob->data[i] = vv[2];
+ }
+ }
+
+ /* Write the file out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icco->err);
+
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+
+ /* - - - - - - - - - - - - - - */
+ /* Deal with reading and verifying the Matrix based profile */
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Check the forward lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> XYZ transform */
+ RGB_XYZp(NULL, check,in);
+
+ /* Do lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 0.00005)
+#ifdef STOPONERROR
+ error ("Excessive error in Matrix Fwd %f > 0.00005",mxd);
+#else
+ warning ("Excessive error in Matrix Fwd %f > 0.00005",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Matrix fwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> XYZ */
+ RGB_XYZp(NULL, check,in);
+
+ /* Do reverse lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, check)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(in, out);
+ if (mxd > 0.0002)
+#ifdef STOPONERROR
+ error ("Excessive error in Matrix Bwd %f > 0.0002",mxd);
+#else
+ warning ("Excessive error in Matrix Bwd %f > 0.0002",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Matrix bwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the forward absolute lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> abs XYZ transform */
+ aRGB_XYZp(NULL, check,in);
+
+ /* Do lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 0.00005)
+#ifdef STOPONERROR
+ error ("Excessive error in Abs Matrix Fwd %f > 0.00005",mxd);
+#else
+ warning ("Excessive error in Abs Matrix Fwd %f > 0.00005",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Matrix fwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse absolute lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> abs XYZ */
+ aRGB_XYZp(NULL, check,in);
+
+ /* Do reverse lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, check)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(in, out);
+ if (mxd > 0.001)
+#ifdef STOPONERROR
+ error ("Excessive error in Abs Matrix Bwd %f > 0.001",mxd);
+#else
+ warning ("Excessive error in Abs Matrix Bwd %f > 0.001",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Matrix bwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ /* ---------------------------------------- */
+ /* Create a Lut16 based XYZ profile to test */
+ /* ---------------------------------------- */
+
+ /* Open up the file for writing */
+ file_name = "xxxx_lut16_XYZ.icm";
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigOutputClass;
+ wh->colorSpace = icSigRgbData; /* It's and RGBish space */
+ wh->pcs = icSigXYZData;
+ wh->renderingIntent = icRelativeColorimetric; /* For want of something */
+
+ /* Values that should be set before writing */
+ wh->manufacturer = str2tag("tst2");
+ wh->model = str2tag("test");
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst = "This is a test Lut XYZ style Output Profile";
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt = "Copyright 1998 Graeme Gill";
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = ABS_X; /* Set some silly numbers */
+ wo->data[0].Y = ABS_Y;
+ wo->data[0].Z = ABS_Z;
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.02; /* Doesn't take part in Absolute anymore */
+ wo->data[0].Y = 0.04;
+ wo->data[0].Z = 0.03;
+ }
+
+ /* 16 bit dev -> pcs lut: */
+ {
+ icmLut *wo;
+ double xyzmin[3] = {0.0, 0.0, 0.0};
+ double xyzmax[3] = {1.0, 1.0, 1.0}; /* Override default XYZ max of 1.999969482422 */
+
+ /* Intent 1 = relative colorimetric */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigAToB1Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ wo->clutPoints = 33;
+ wo->inputEnt = 256;
+ wo->outputEnt = 4096;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* So we can't use it for this lut. */
+
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigRgbData, /* Input color space */
+ icSigXYZData, /* Output color space */
+ RGB_RGBp, /* Input transfer function, RGB->RGB' (NULL = default) */
+ NULL, NULL, /* Use default Maximum range of RGB' values */
+ RGBp_XYZp, /* RGB' -> XYZ' transfer function */
+ xyzmin, xyzmax, /* Make XYZ' range 0.0 - 1.0 for better precision */
+ XYZp_XYZ) != 0) /* Output transfer function, XYZ'->XYZ (NULL = deflt) */
+ error("Setting 16 bit RGB->XYZ Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 16 bit dev -> pcs lut - link intent 0 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB0Tag, icSigAToB1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 16 dev -> pcs bit lut - link intent 2 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 2 = saturation */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB2Tag, icSigAToB1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 16 bit pcs -> dev lut: */
+ {
+ icmLut *wo;
+ double xyzmin[3] = {0.0, 0.0, 0.0}; /* XYZ' range */
+ double xyzmax[3] = {1.0, 1.0, 1.0}; /* Override default XYZ max of 1.999969482422 */
+ double rgbmin[3] = {0.0, 0.0, 0.0}; /* RGB' range */
+ double rgbmax[3] = {1.0, 1.0, 1.0};
+
+ /* Intent 1 = relative colorimetric */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigBToA1Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ wo->clutPoints = 33;
+ wo->inputEnt = 1024; /* (power curves are hard to represent in tables at small values) */
+ wo->outputEnt = 4096;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* (so it could be used here) */
+ /* Matrix not tested:
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ wo->e[i][j] = ??;
+ */
+
+#ifdef REVLUTSCALE1
+ {
+ /* In any any real profile, you will probably be providing a clut */
+ /* function that carefully maps out of gamut PCS values to in-gamut */
+ /* device values, so the scaling done here won't be appropriate. */
+ /* */
+ /* For this regresion test, we are interested in maximizing accuracy */
+ /* over the known gamut of the device. It is an advantage therefore */
+ /* to scale the internal lut values to this end. */
+
+ /* We'll do a really simple sampling search of the device gamut to */
+ /* establish the XYZ' bounding box. */
+
+ int co[3];
+ double in[3], out[3];
+
+ xyzmin[0] = xyzmin[1] = xyzmin[2] = 1.0;
+ xyzmax[0] = xyzmax[1] = xyzmax[2] = 0.0;
+ for (co[0] = 0; co[0] < 11; co[0]++) {
+ in[0] = co[0]/(11-1.0);
+ for (co[1] = 0; co[1] < 11; co[1]++) {
+ in[1] = co[1]/(11-1.0);
+ for (co[2] = 0; co[2] < 11; co[2]++) {
+ in[2] = co[2]/(11-1.0);
+
+ /* Do RGB -> XYZ' transform */
+ RGB_XYZp(NULL, out,in);
+ if (out[0] < xyzmin[0])
+ xyzmin[0] = out[0];
+ if (out[0] > xyzmax[0])
+ xyzmax[0] = out[0];
+ if (out[1] < xyzmin[1])
+ xyzmin[1] = out[1];
+ if (out[1] > xyzmax[1])
+ xyzmax[1] = out[1];
+ if (out[2] < xyzmin[2])
+ xyzmin[2] = out[2];
+ if (out[2] > xyzmax[2])
+ xyzmax[2] = out[2];
+ }
+ }
+ }
+ }
+#endif
+
+#ifdef REVLUTSCALE2
+ {
+ /* In any any real profile, you will probably be providing a clut */
+ /* function that carefully maps out of gamut PCS values to in-gamut */
+ /* device values, so the scaling done here won't be appropriate. */
+ /* */
+ /* For this regresion test, we are interested in maximizing accuracy */
+ /* over the known gamut of the device. */
+ /* By setting the min/max to a larger range than will actually be */
+ /* used, we can make sure that the extreme table values of the */
+ /* clut are not actually used, and therefore we won't see the */
+ /* rounding effects of these extreme values being clipped */
+ /* by the numerical limits of the ICC representation. */
+ /* Instead the extreme values will be clipped by the the */
+ /* higher resolution output table. */
+ /* */
+ /* This all assumes that the multi-d reverse transform we are trying */
+ /* to represent in the profile extrapolates beyond the legal device */
+ /* value range. */
+ /* */
+ /* The scaling was chosen by experiment to make sure that the full */
+ /* gamut is surrounded by one row of extrapolated, unclipped clut */
+ /* table entries. */
+
+ int i;
+ for (i = 0; i < 3; i++) {
+ rgbmin[i] = -0.1667; /* Magic numbers */
+ rgbmax[i] = 1.1667;
+ }
+ }
+#endif
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigXYZData, /* Input color space */
+ icSigRgbData, /* Output color space */
+ XYZ_XYZp, /* Input transfer function, XYZ->XYZ' (NULL = default) */
+ xyzmin, xyzmax, /* Make XYZ' range 0.0 - 1.0 for better precision */
+ XYZp_RGBp, /* XYZ' -> RGB' transfer function */
+ rgbmin, rgbmax, /* Make RGB' range 0.0 - 1.333 for less clip rounding */
+ RGBp_RGB) != 0) /* Output transfer function, RGB'->RGB (NULL = deflt) */
+ error("Setting 16 bit XYZ->RGB Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ }
+ /* 16 bit pcs -> dev lut - link intent 0 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA0Tag, icSigBToA1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 16 pcs -> dev bit lut - link intent 2 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 2 = saturation */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA2Tag, icSigBToA1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ /* 16 bit pcs -> gamut lut: */
+ {
+ icmLut *wo;
+ double xyzmin[3] = {0.0, 0.0, 0.0}; /* XYZ' range */
+ double xyzmax[3] = {1.0, 1.0, 1.0}; /* Override default XYZ max of 1.999969482422 */
+
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigGamutTag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 1;
+ wo->clutPoints = 33;
+ wo->inputEnt = 256;
+ wo->outputEnt = 256;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* (so it could be used here) */
+ /* Matrix not tested:
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ wo->e[i][j] = ??;
+ */
+
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigXYZData, /* Input color space */
+ icSigGrayData, /* Output color space */
+ XYZ_XYZp, /* Input transfer function, XYZ->XYZ' (NULL = default) */
+ xyzmin, xyzmax, /* Make XYZ' range 0.0 - 1.0 for better precision */
+ XYZp_BDIST, /* XYZ' -> Boundary Distance transfer function */
+ NULL, NULL, /* Default range from clut to output table */
+ BDIST_GAMMUT /* Boundary Distance -> Out of gamut distance */
+ ) != 0)
+ error("Setting 16 bit XYZ->Gammut Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ /* Write the file out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icco->err);
+
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+
+ /* - - - - - - - - - - - - - - */
+ /* Deal with reading and verifying the Lut XYZ style profile */
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Check the Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icRelativeColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> XYZ transform */
+ RGB_XYZ(NULL, check, in);
+
+ /* Do lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 0.00005)
+#ifdef STOPONERROR
+ error ("Excessive error in XYZ Lut Fwd %f > 0.00005",mxd);
+#else
+ warning ("Excessive error in XYZ Lut Fwd %f > 0.00005",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut XYZ fwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+ int co[3];
+ double in[3], out[3], check[3];
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icRelativeColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of XYZ -> device transform */
+ RGB_XYZ(NULL, check, in);
+
+ /* Do reverse lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, check)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(in, out);
+ if (mxd > 0.002) {
+#ifdef STOPONERROR
+ error ("Excessive error in XYZ Lut Bwd %f > 0.002",mxd);
+#else
+ warning ("Excessive error in XYZ Lut Bwd %f > 0.002",mxd);
+#endif /* STOPONERROR */
+ }
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut XYZ bwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the Absolute Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> XYZ transform */
+ aRGB_XYZ(NULL, check,in);
+
+ /* Do lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 0.00005)
+#ifdef STOPONERROR
+ error ("Excessive error in XYZ Abs Lut Fwd %f > 0.00005",mxd);
+#else
+ warning ("Excessive error in XYZ Abs Lut Fwd %f > 0.00005",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut XYZ fwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the Absolute reverse Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of XYZ -> device transform */
+ aRGB_XYZ(NULL, check,in);
+
+ /* Do reverse lookup of device -> XYZ transform */
+ if ((rv = luo->lookup(luo, out, check)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(in, out);
+ if (mxd > 0.002)
+#ifdef STOPONERROR
+ error ("Excessive error in XYZ Abs Lut Bwd %f > 0.002",mxd);
+#else
+ warning ("Excessive error in XYZ Abs Lut Bwd %f > 0.002",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut XYZ bwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the XYZ gamut function */
+ {
+ int ino,ono,iok,ook;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmGamut, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ ino = ono = iok = ook = 0;
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ int outgamut;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do gamut lookup of XYZ transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Do reference conversion of XYZ -> RGB */
+ XYZ_RGB(NULL, check,in);
+
+ /* Check the result */
+ outgamut = 1; /* assume on edge */
+ if (check[0] < -0.01 || check[0] > 1.01
+ || check[1] < -0.01 || check[1] > 1.01
+ || check[2] < -0.01 || check[2] > 1.01)
+ outgamut = 2; /* Definitely out of gamut */
+ if (check[0] > 0.01 && check[0] < 0.99
+ && check[1] > 0.01 && check[1] < 0.99
+ && check[2] > 0.01 && check[2] < 0.99)
+ outgamut = 0; /* Definitely in gamut */
+
+ /* Keep record of agree/disagree */
+ if (outgamut <= 1) {
+ ino++;
+ if (out[0] <= 0.01)
+ iok++;
+ } else {
+ ono++;
+ if (out[0] > 0.01)
+ ook++;
+ }
+ }
+ }
+ }
+ printf("Lut XYZ gamut check inside correct = %f%%\n",100.0 * iok/ino);
+ printf("Lut XYZ gamut check outside correct = %f%%\n",100.0 * ook/ono);
+ printf("Lut XYZ gamut check total correct = %f%%\n",100.0 * (iok+ook)/(ino+ono));
+ if (((double)iok/ino) < 0.99 || ((double)ook/ono) < 0.98)
+#ifdef STOPONERROR
+ error ("Gamut XYZ lookup has excessive error");
+#else
+ warning ("Gamut XYZ lookup has excessive error");
+#endif /* STOPONERROR */
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ /* ---------------------------------------- */
+ /* Create a Lut16 based Lab profile to test */
+ /* ---------------------------------------- */
+
+ /* Open up the file for writing */
+ file_name = "xxxx_lut16_Lab.icm";
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigOutputClass;
+ wh->colorSpace = icSigRgbData; /* It's and RGBish space */
+ wh->pcs = icSigLabData;
+ wh->renderingIntent = icRelativeColorimetric; /* For want of something */
+
+ /* Values that should be set before writing */
+ wh->manufacturer = str2tag("tst2");
+ wh->model = str2tag("test");
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst = "This is a test Lut style Lab Output Profile";
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt = "Copyright 1998 Graeme Gill";
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = ABS_X; /* Set some silly numbers */
+ wo->data[0].Y = ABS_Y;
+ wo->data[0].Z = ABS_Z;
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.02; /* Doesn't take part in Absolute anymore */
+ wo->data[0].Y = 0.04;
+ wo->data[0].Z = 0.03;
+ }
+ /* 16 bit dev -> pcs lut: */
+ {
+ icmLut *wo;
+
+ /* Intent 1 = relative colorimetric */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigAToB1Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ wo->clutPoints = 33;
+ wo->inputEnt = 256;
+ wo->outputEnt = 256; /* I'm not going to use the output Lut */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* so it is not used here. */
+
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigRgbData, /* Input color space */
+ icSigLabData, /* Output color space */
+ RGB_RGBp, /* Input transfer function, RGB->RGB' (NULL = default) */
+ NULL, NULL, /* Use default Maximum range of RGB' values */
+ RGBp_Labp, /* RGB' -> Lab' transfer function */
+ NULL, NULL, /* Use default Maximum range of Lab' values */
+ Labp_Lab /* Linear output transform Lab'->Lab */
+ ) != 0)
+ error("Setting 16 bit RGB->Lab Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 16 bit dev -> pcs lut - link intent 0 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB0Tag, icSigAToB1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 16 dev -> pcs bit lut - link intent 2 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 2 = saturation */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB2Tag, icSigAToB1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 16 bit pcs -> dev lut: */
+ {
+ icmLut *wo;
+ double rgbmin[3] = {0.0, 0.0, 0.0}; /* RGB' range */
+ double rgbmax[3] = {1.0, 1.0, 1.0};
+
+ /* Intent 1 = relative colorimetric */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigBToA1Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ wo->clutPoints = 33;
+ wo->inputEnt = 256; /* Not using this for Lab test */
+ wo->outputEnt = 4096;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* so it is not used here. */
+
+
+ /* REVLUTSCALE1 could be used here, but in this case it hardly */
+ /* makes any difference. */
+
+#ifdef REVLUTSCALE2
+ {
+ /* In any any real profile, you will probably be providing a clut */
+ /* function that carefully maps out of gamut PCS values to in-gamut */
+ /* device values, so the scaling done here won't be appropriate. */
+ /* */
+ /* For this regresion test, we are interested in maximizing accuracy */
+ /* over the known gamut of the device. */
+ /* By setting the min/max to a larger range than will actually be */
+ /* used, we can make sure that the extreme table values of the */
+ /* clut are not actually used, and therefore we won't see the */
+ /* rounding effects of these extreme values being clipped to */
+ /* by the numerical limits of the ICC representation. */
+ /* Instead the extreme values will be clipped by the the higher */
+ /* higher resolution output table. */
+ /* */
+ /* This all assumes that the multi-d reverse transform we are trying */
+ /* to represent in the profile extrapolates beyond the legal device */
+ /* value range. */
+ /* */
+ /* The scaling was chosen by experiment to make sure that the full */
+ /* gamut is surrounded by one row of extrapolated, unclipped clut */
+ /* table entries. */
+
+ int i;
+ for (i = 0; i < 3; i++) {
+ rgbmin[i] = -0.1667; /* Magic numbers */
+ rgbmax[i] = 1.1667;
+ }
+ }
+#endif
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigLabData, /* Input color space */
+ icSigRgbData, /* Output color space */
+ Lab_Labp, /* Linear input transform Lab->Lab' */
+ NULL, NULL, /* Use default Lab' range */
+ Labp_RGBp, /* Lab' -> RGB' transfer function */
+ rgbmin, rgbmax, /* Make RGB' range 0.0 - 1.333 for less clip rounding */
+ RGBp_RGB) != 0) /* Output transfer function, RGB'->RGB (NULL = deflt) */
+ error("Setting 16 bit Lab->RGB Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ }
+ /* 16 bit pcs -> dev lut - link intent 0 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA0Tag, icSigBToA1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 16 pcs -> dev bit lut - link intent 2 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 2 = saturation */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA2Tag, icSigBToA1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ /* 16 bit pcs -> gamut lut: */
+ {
+ icmLut *wo;
+
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigGamutTag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 1;
+ wo->clutPoints = 33;
+ wo->inputEnt = 256;
+ wo->outputEnt = 256;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* so it can't be used here. */
+
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigLabData, /* Input color space */
+ icSigGrayData, /* Output color space */
+ Lab_Labp, /* Linear input transform Lab->Lab' */
+ NULL, NULL , /* Default Lab' range */
+ Labp_BDIST, /* Lab' -> Boundary Distance transfer function */
+ NULL, NULL, /* Default range from clut to output table */
+ BDIST_GAMMUT /* Boundary Distance -> Out of gamut distance */
+ ) != 0)
+ error("Setting 16 bit Lab->Gammut Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ /* Write the file out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icco->err);
+
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+
+ /* - - - - - - - - - - - - - - */
+ /* Deal with reading and verifying the Lut Lab 16bit style profile */
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Check the Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icRelativeColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> Lab transform */
+ RGB_Lab(NULL, check,in);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 1.0)
+#ifdef STOPONERROR
+ error ("Excessive error in Lab16 Lut Fwd %f",mxd);
+#else
+ warning ("Excessive error in Lab16 Lut Fwd %f",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut Lab16 fwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icRelativeColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> Lab */
+ RGB_Lab(NULL, check,in);
+
+ /* Do reverse lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, check)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(in, out);
+ if (mxd > 0.02)
+#ifdef STOPONERROR
+ error ("Excessive error in Lab16 Lut Bwd %f > 0.02",mxd);
+#else
+ warning ("Excessive error in Lab16 Lut Bwd %f > 0.02",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut Lab16 bwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the Absolute Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> Lab transform */
+ aRGB_Lab(NULL, check,in);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 1.0)
+#ifdef STOPONERROR
+ error ("Excessive error in Abs Lab16 Lut Fwd %f > 1.0",mxd);
+#else
+ warning ("Excessive error in Abs Lab16 Lut Fwd %f > 1.0",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut Lab16 fwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the Absolute reverse Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> Lab transform */
+ aRGB_Lab(NULL, check,in);
+
+ /* Do reverse lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, check)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(in, out);
+ if (mxd > 0.02)
+#ifdef STOPONERROR
+ error ("Excessive error in Abs Lab16 Lut Bwd %f > 0.02",mxd);
+#else
+ warning ("Excessive error in Abs Lab16 Lut Bwd %f > 0.02",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut Lab16 bwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the Lab gamut function */
+ {
+ int ino,ono,iok,ook;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmGamut, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ ino = ono = iok = ook = 0;
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = (co[0]/(TRES-1.0)) * 100.0; /* L */
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = ((co[1]/(TRES-1.0)) - 0.5) * 256.0; /* a */
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ int outgamut;
+ in[2] = ((co[2]/(TRES-1.0)) - 0.5) * 256.0; /* b */
+
+ /* Do gamut lookup of Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Do reference conversion of Lab -> RGB */
+ Lab_RGB(NULL, check,in);
+
+ /* Check the result */
+ outgamut = 1; /* assume on edge */
+ if (check[0] < -0.01 || check[0] > 1.01
+ || check[1] < -0.01 || check[1] > 1.01
+ || check[2] < -0.01 || check[2] > 1.01)
+ outgamut = 2; /* Definitely out of gamut */
+ if (check[0] > 0.01 && check[0] < 0.99
+ && check[1] > 0.01 && check[1] < 0.99
+ && check[2] > 0.01 && check[2] < 0.99)
+ outgamut = 0; /* Definitely in gamut */
+
+ /* Keep record of agree/disagree */
+ if (outgamut <= 1) {
+ ino++;
+ if (out[0] <= 0.01)
+ iok++;
+ } else {
+ ono++;
+ if (out[0] > 0.01)
+ ook++;
+ }
+ }
+ }
+ }
+ printf("Lut Lab16 gamut check inside correct = %f%%\n",100.0 * iok/ino);
+ printf("Lut Lab16 gamut check outside correct = %f%%\n",100.0 * ook/ono);
+ printf("Lut Lab16 gamut check total correct = %f%%\n",100.0 * (iok+ook)/(ino+ono));
+ if (((double)iok/ino) < 0.98 || ((double)ook/ono) < 0.98)
+#ifdef STOPONERROR
+ error ("Gamut Lab16 lookup has excessive error");
+#else
+ warning ("Gamut Lab16 lookup has excessive error");
+#endif /* STOPONERROR */
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ /* ---------------------------------------- */
+ /* Create a Lut8 based Lab profile to test */
+ /* ---------------------------------------- */
+
+ /* Open up the file for writing */
+ file_name = "xxxx_lut8_Lab.icm";
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigOutputClass;
+ wh->colorSpace = icSigRgbData; /* It's and RGBish space */
+ wh->pcs = icSigLabData;
+ wh->renderingIntent = icRelativeColorimetric; /* For want of something */
+
+ /* Values that should be set before writing */
+ wh->manufacturer = str2tag("tst2");
+ wh->model = str2tag("test");
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst = "This is a test Lut style Lab Output Profile";
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt = "Copyright 1998 Graeme Gill";
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = ABS_X; /* Set some silly numbers */
+ wo->data[0].Y = ABS_Y;
+ wo->data[0].Z = ABS_Z;
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.02; /* Doesn't take part in Absolute anymore */
+ wo->data[0].Y = 0.04;
+ wo->data[0].Z = 0.03;
+ }
+ /* 8 bit dev -> pcs lut: */
+ {
+ icmLut *wo;
+
+ /* Intent 1 = relative colorimetric */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigAToB1Tag, icSigLut8Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ wo->clutPoints = 33;
+ wo->inputEnt = 256;
+ wo->outputEnt = 256;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* so it is not used here. */
+
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigRgbData, /* Input color space */
+ icSigLabData, /* Output color space */
+ RGB_RGBp, /* Input transfer function, RGB->RGB' (NULL = default) */
+ NULL, NULL, /* Use default Maximum range of RGB' values */
+ RGBp_Labp, /* RGB' -> Lab' transfer function */
+ NULL, NULL, /* Use default Maximum range of Lab' values */
+ Labp_Lab /* Linear output transform Lab'->Lab */
+ ) != 0)
+ error("Setting 8 bit RGB->Lab Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 8 bit dev -> pcs lut - link intent 0 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB0Tag, icSigAToB1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 8 dev -> pcs bit lut - link intent 2 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 2 = saturation */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB2Tag, icSigAToB1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 8 bit pcs -> dev lut: */
+ {
+ icmLut *wo;
+ double rgbmin[3] = {0.0, 0.0, 0.0}; /* RGB' range */
+ double rgbmax[3] = {1.0, 1.0, 1.0};
+
+ /* Intent 1 = relative colorimetric */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigBToA1Tag, icSigLut8Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ wo->clutPoints = 33;
+ wo->inputEnt = 256;
+ wo->outputEnt = 256;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* so it is not used here. */
+
+
+ /* REVLUTSCALE1 could be used here, but in this case it hardly */
+ /* makes any difference. */
+
+#ifdef REVLUTSCALE2
+ {
+ /* In any any real profile, you will probably be providing a clut */
+ /* function that carefully maps out of gamut PCS values to in-gamut */
+ /* device values, so the scaling done here won't be appropriate. */
+ /* */
+ /* For this regresion test, we are interested in maximizing accuracy */
+ /* over the known gamut of the device. */
+ /* By setting the min/max to a larger range than will actually be */
+ /* used, we can make sure that the extreme table values of the */
+ /* clut are not actually used, and therefore we won't see the */
+ /* rounding effects of these extreme values being clipped to */
+ /* by the numerical limits of the ICC representation. */
+ /* Instead the extreme values will be clipped by the the higher */
+ /* higher resolution output table. */
+ /* */
+ /* This all assumes that the multi-d reverse transform we are trying */
+ /* to represent in the profile extrapolates beyond the legal device */
+ /* value range. */
+ /* */
+ /* The scaling was chosen by experiment to make sure that the full */
+ /* gamut is surrounded by one row of extrapolated, unclipped clut */
+ /* table entries. */
+
+ int i;
+ for (i = 0; i < 3; i++) {
+ rgbmin[i] = -0.1667; /* Magic numbers */
+ rgbmax[i] = 1.1667;
+ }
+ }
+#endif
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigLabData, /* Input color space */
+ icSigRgbData, /* Output color space */
+ Lab_Labp, /* Linear input transform Lab->Lab' */
+ NULL, NULL, /* Use default Lab' range */
+ Labp_RGBp, /* Lab' -> RGB' transfer function */
+ rgbmin, rgbmax, /* Make RGB' range 0.0 - 1.333 for less clip rounding */
+ RGBp_RGB) != 0) /* Output transfer function, RGB'->RGB (NULL = deflt) */
+ error("Setting 8 bit Lab->RGB Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ }
+ /* 8 bit pcs -> dev lut - link intent 0 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA0Tag, icSigBToA1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ /* 8 pcs -> dev bit lut - link intent 2 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 2 = saturation */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA2Tag, icSigBToA1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ /* 8 bit pcs -> gamut lut: */
+ {
+ icmLut *wo;
+
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigGamutTag, icSigLut8Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 1;
+ wo->clutPoints = 33;
+ wo->inputEnt = 256;
+ wo->outputEnt = 256;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* so it can't be used here. */
+
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo, ICM_CLUT_SET_EXACT, NULL,
+ icSigLabData, /* Input color space */
+ icSigGrayData, /* Output color space */
+ Lab_Labp, /* Linear input transform Lab->Lab' */
+ NULL, NULL , /* Default Lab' range */
+ Labp_BDIST, /* Lab' -> Boundary Distance transfer function */
+ NULL, NULL, /* Default range from clut to output table */
+ BDIST_GAMMUT /* Boundary Distance -> Out of gamut distance */
+ ) != 0)
+ error("Setting 16 bit Lab->Gammut Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ /* Write the file out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icco->err);
+
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+
+ /* - - - - - - - - - - - - - - */
+ /* Deal with reading and verifying the Lut Lab 8bit style profile */
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Check the Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icRelativeColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> Lab transform */
+ RGB_Lab(NULL, check,in);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 2.1)
+#ifdef STOPONERROR
+ error ("Excessive error in Lab8 Lut Fwd %f > 2.1",mxd);
+#else
+ warning ("Excessive error in Lab8 Lut Fwd %f > 2.1",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut Lab8 fwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the reverse Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icRelativeColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> Lab */
+ RGB_Lab(NULL, check,in);
+
+ /* Do reverse lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, check)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(in, out);
+ if (mxd > 0.03)
+#ifdef STOPONERROR
+ error ("Excessive error in Lab8 Lut Bwd %f > 0.03",mxd);
+#else
+ warning ("Excessive error in Lab8 Lut Bwd %f > 0.03",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut Lab8 bwd default intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the Absolute Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> Lab transform */
+ aRGB_Lab(NULL, check,in);
+
+ /* Do lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(out, check);
+ if (mxd > 2.3)
+#ifdef STOPONERROR
+ error ("Excessive error in Abs Lab8 Lut Fwd %f > 2.3",mxd);
+#else
+ warning ("Excessive error in Abs Lab8 Lut Fwd %f > 2.3",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut Lab8 fwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the Absolute reverse Lut lookup function */
+ {
+ double merr = 0.0;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icAbsoluteColorimetric,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = co[0]/(TRES-1.0);
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = co[1]/(TRES-1.0);
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ double mxd;
+ in[2] = co[2]/(TRES-1.0);
+
+ /* Do reference conversion of device -> Lab transform */
+ aRGB_Lab(NULL, check,in);
+
+ /* Do reverse lookup of device -> Lab transform */
+ if ((rv = luo->lookup(luo, out, check)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Check the result */
+ mxd = maxdiff(in, out);
+ if (mxd > 0.03)
+#ifdef STOPONERROR
+ error ("Excessive error in Abs Lab8 Lut Bwd %f > 0.03",mxd);
+#else
+ warning ("Excessive error in Abs Lab8 Lut Bwd %f > 0.03",mxd);
+#endif /* STOPONERROR */
+ if (mxd > merr)
+ merr = mxd;
+ }
+ }
+ }
+ printf("Lut Lab8 bwd absolute intent check complete, peak error = %f\n",merr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ /* Check the Lab gamut function */
+ {
+ int ino,ono,iok,ook;
+ icmLuBase *luo;
+
+ /* Get a fwd conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmGamut, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+
+ ino = ono = iok = ook = 0;
+ for (co[0] = 0; co[0] < TRES; co[0]++) {
+ in[0] = (co[0]/(TRES-1.0)) * 100.0; /* L */
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ in[1] = ((co[1]/(TRES-1.0)) - 0.5) * 256.0; /* a */
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ int outgamut;
+ in[2] = ((co[2]/(TRES-1.0)) - 0.5) * 256.0; /* b */
+
+ /* Do gamut lookup of Lab transform */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Do reference conversion of Lab -> RGB */
+ Lab_RGB(NULL, check,in);
+
+ /* Check the result */
+ outgamut = 1; /* assume on edge */
+ if (check[0] < -0.01 || check[0] > 1.01
+ || check[1] < -0.01 || check[1] > 1.01
+ || check[2] < -0.01 || check[2] > 1.01)
+ outgamut = 2; /* Definitely out of gamut */
+ if (check[0] > 0.01 && check[0] < 0.99
+ && check[1] > 0.01 && check[1] < 0.99
+ && check[2] > 0.01 && check[2] < 0.99)
+ outgamut = 0; /* Definitely in gamut */
+
+ /* Keep record of agree/disagree */
+ if (outgamut <= 1) {
+ ino++;
+ if (out[0] <= 0.01)
+ iok++;
+ } else {
+ ono++;
+ if (out[0] > 0.01)
+ ook++;
+ }
+ }
+ }
+ }
+ printf("Lut Lab8 gamut check inside correct = %f%%\n",100.0 * iok/ino);
+ printf("Lut Lab8 gamut check outside correct = %f%%\n",100.0 * ook/ono);
+ printf("Lut Lab8 gamut check total correct = %f%%\n",100.0 * (iok+ook)/(ino+ono));
+ if (((double)iok/ino) < 0.98 || ((double)ook/ono) < 0.98)
+#ifdef STOPONERROR
+ error ("Gamut Lab8 lookup has excessive error");
+#else
+ warning ("Gamut Lab8 lookup has excessive error");
+#endif /* STOPONERROR */
+
+ /* Done with lookup object */
+ luo->del(luo);
+ }
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ /* ---------------------------------------- */
+
+ printf("Lookup test completed OK\n");
+ return 0;
+}
+
+/* ------------------------------------------------ */
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"lutest: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"lutest: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/icc/makezip.ksh b/icc/makezip.ksh
new file mode 100644
index 0000000..f06efa4
--- /dev/null
+++ b/icc/makezip.ksh
@@ -0,0 +1,6 @@
+# Create icclib source distribution
+#jam
+#zip nt_iccdump.zip iccdump.exe
+#zip nt_icclu.zip icclu.exe
+rm icclib.zip
+zip -9 -ll icclib.zip Readme.txt License.txt todo.txt log.txt Jamfile Makefile Makefile.WNT Makefile.IBMNT Makefile.UNIX Makefile.OSX icc.c iccstd.c icc.h iccV42.h iccdump.c icclu.c iccrw.c icctest.c lutest.c
diff --git a/icc/mcheck.c b/icc/mcheck.c
new file mode 100644
index 0000000..9000650
--- /dev/null
+++ b/icc/mcheck.c
@@ -0,0 +1,541 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * Check the device chanel to PCS monotonicity.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2000/12/11
+ * Version: 2.15
+ *
+ * Copyright 2000 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/* TTBD:
+ *
+ * Make general device input, not just CMYK
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+void usage(void) {
+ fprintf(stderr,"Check device to PCS monotonicity of a CMYK ICC file, V%s\n",ICCLIB_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: kcheck [-v] [-w] infile\n");
+ fprintf(stderr," -v verbose\n");
+ fprintf(stderr," -c Check just Cyan monotonicity\n");
+ fprintf(stderr," -m Check just Magenta monotonicity\n");
+ fprintf(stderr," -y Check just Yellow monotonicity\n");
+ fprintf(stderr," -k Check just Black monotonicity\n");
+ fprintf(stderr," -w create VRML visualisation\n");
+ exit(1);
+}
+
+#define MGR 50 /* Maximum grid resolution handled */
+
+
+FILE *start_vrml(char *name, int doaxes);
+void start_line_set(FILE *wrl);
+void add_vertex(FILE *wrl, double pp[3]);
+void make_lines(FILE *wrl, int ppset);
+void end_vrml(FILE *wrl);
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int cchan = -1; /* default all */
+ int dovrml = 0;
+ int doaxes = 0;
+ char in_name[500];
+ char out_name[500], *xl;
+ icmFile *rd_fp;
+ icc *wr_icco, *rd_icco; /* Keep object separate */
+ int rv = 0;
+
+ /* Check variables */
+ icmLuBase *luo;
+ icmLuLut *luluto; /* Lookup xLut type object */
+ int gres; /* Grid resolution */
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int inn; /* Number of input chanels */
+ icmLuAlgType alg;
+ FILE *wrl;
+ int dx[4]; /* Device index mapping */
+ int chan, cs, ce;
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ /* VRML */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ dovrml = 1;
+ }
+ /* Cyan */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ cchan = 0;
+ }
+ /* Magenta */
+ else if (argv[fa][1] == 'm' || argv[fa][1] == 'M') {
+ cchan = 1;
+ }
+ /* Yellow */
+ else if (argv[fa][1] == 'y' || argv[fa][1] == 'Y') {
+ cchan = 2;
+ }
+ /* Black */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ cchan = 3;
+ }
+ else if (argv[fa][1] == '?')
+ usage();
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa]);
+
+ strcpy(out_name, in_name);
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".wrl");
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Get a Device to PCS conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icRelativeColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+ /* Get details of conversion */
+ luo->spaces(luo, &ins, &inn, &outs, NULL, &alg, NULL, NULL, NULL);
+
+ if (alg != icmLutType) {
+ error("Expecting Lut based profile");
+ }
+
+ if (ins != icSigCmykData) {
+ error("Expecting CMYK device");
+ }
+
+ if (outs != icSigLabData) {
+ error("Expecting Lab PCS");
+ }
+
+ luluto = (icmLuLut *)luo; /* Lookup xLut type object */
+
+ gres = luluto->lut->clutPoints;
+ if (gres > MGR) {
+ error("Can't handle grid resolution greater than %d\n",MGR);
+ }
+
+ if (dovrml) {
+ wrl = start_vrml(out_name, doaxes);
+ start_line_set(wrl);
+ }
+
+ /* For all the device chanels chosen */
+ if (cchan < 0) {
+ cs = 0;
+ ce = inn;
+ } else {
+ cs = cchan;
+ ce = cs + 1;
+ }
+ for (chan = cs; chan < ce; chan++) {
+
+ /* Check the monotonicity of the output for a given device input */
+ int co[4];
+ if (chan == 0) {
+ dx[0] = 1;
+ dx[1] = 2;
+ dx[2] = 3;
+ dx[3] = 0; /* Cyan is variable */
+ } else if (chan == 1) {
+ dx[0] = 0;
+ dx[1] = 2;
+ dx[2] = 3;
+ dx[3] = 1; /* Magenta is variable */
+ } else if (chan == 2) {
+ dx[0] = 0;
+ dx[1] = 1;
+ dx[2] = 3;
+ dx[3] = 2; /* Yellow is variable */
+ } else if (chan == 3) {
+ dx[0] = 0;
+ dx[1] = 1;
+ dx[2] = 2;
+ dx[3] = 3; /* Black is variable */
+ }
+
+ /* Itterate throught the CMY clut grid points */
+ for (co[0] = 0; co[0] < gres; co[0]++) {
+ for (co[1] = 0; co[1] < gres; co[1]++) {
+ for (co[2] = 0; co[2] < gres; co[2]++) {
+ int j, k, ck, nm;
+ double dev[MGR][4];
+ double pcs[MGR][3];
+ double apcs[3], ss;
+
+ /* Run up the variable axis */
+ for (ck = 0; ck < gres; ck++) {
+
+ dev[ck][dx[0]] = co[0]/(gres-1.0);
+ dev[ck][dx[1]] = co[1]/(gres-1.0);
+ dev[ck][dx[2]] = co[2]/(gres-1.0);
+ dev[ck][dx[3]] = ck/(gres-1.0);
+
+ /* Device to PCS */
+ if ((rv = luluto->clut(luluto, pcs[ck], dev[ck])) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+// if (dovrml)
+// add_vertex(wrl, pcs[ck]);
+ }
+
+ /* Compute average vector direction */
+ for (ss = 0.0, k = 0; k < 3; k++) {
+ double tt;
+ tt = pcs[gres-1][k] - pcs[0][k];
+ ss += tt * tt;
+ apcs[k] = tt;
+ }
+ for (k = 0; k < 3; k++)
+ apcs[k] /= ss;
+
+ /* Now compute the dot product for each vector, */
+ /* and check for reversals. */
+ j = 0;
+//printf("Checking CMYK %f %f %f %f Lab %f %f %f\n",
+// dev[j][0], dev[j][1], dev[j][2], dev[j][3],
+// pcs[j][0], pcs[j][1], pcs[j][2]);
+ for (nm = 0, j = 1; j < gres; j++) {
+ for (ss = 0.0, k = 0; k < 3; k++) /* Dot product */
+ ss += (pcs[j][k] - pcs[j-1][k]) * apcs[k];
+
+//printf("Checking %f CMYK %f %f %f %f Lab %f %f %f\n",
+// ss, dev[j][0], dev[j][1], dev[j][2], dev[j][3],
+// pcs[j][0], pcs[j][1], pcs[j][2]);
+
+ if (ss <= 0.0) {
+ nm = 1;
+ printf("NonMon %f at CMYK %f %f %f %f Lab %f %f %f\n",
+ ss, dev[j][0], dev[j][1], dev[j][2], dev[j][3],
+ pcs[j][0], pcs[j][1], pcs[j][2]);
+ }
+ }
+//printf("\n");
+
+ /* Display just the non mono threads */
+ if (nm && dovrml) {
+ for (j = 0; j < gres; j++)
+ add_vertex(wrl, pcs[j]);
+ }
+ if (verb) {
+ printf("."); fflush(stdout);
+ }
+ }
+ }
+ }
+ }
+
+ if (dovrml) {
+ make_lines(wrl, gres);
+ end_vrml(wrl);
+ }
+
+ /* Done with lookup object */
+ luo->del(luo);
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ return 0;
+}
+
+/* ------------------------------------------------ */
+/* Some simple functions to do basix VRML work */
+
+#define GAMUT_LCENT 50.0
+static int npoints = 0;
+static int paloc = 0;
+static struct { double pp[3]; } *pary;
+
+static void Lab2RGB(double *out, double *in);
+
+FILE *start_vrml(char *name, int doaxes) {
+ FILE *wrl;
+ struct {
+ double x, y, z;
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+ int i;
+
+ if ((wrl = fopen(name,"w")) == NULL)
+ error("Error opening VRML file '%s'\n",name);
+
+ npoints = 0;
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ fprintf(wrl,"# Lab axes as boxes:\n");
+ for (i = 0; i < 5; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape{\n");
+ fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
+ axes[i].wx, axes[i].wy, axes[i].wz);
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"\n");
+ }
+
+ return wrl;
+}
+
+void
+start_line_set(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+}
+
+void add_vertex(FILE *wrl, double pp[3]) {
+
+ fprintf(wrl,"%f %f %f,\n",pp[1], pp[2], pp[0]-GAMUT_LCENT);
+
+ if (paloc < (npoints+1)) {
+ paloc = (paloc + 10) * 2;
+ if (pary == NULL)
+ pary = malloc(paloc * 3 * sizeof(double));
+ else
+ pary = realloc(pary, paloc * 3 * sizeof(double));
+
+ if (pary == NULL)
+ error ("Malloc failed");
+ }
+ pary[npoints].pp[0] = pp[0];
+ pary[npoints].pp[1] = pp[1];
+ pary[npoints].pp[2] = pp[2];
+ npoints++;
+}
+
+
+void make_lines(FILE *wrl, int ppset) {
+ int i, j;
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (i = 0; i < npoints;) {
+ for (j = 0; j < ppset; j++, i++) {
+ fprintf(wrl,"%d, ", i);
+ }
+ fprintf(wrl,"-1,\n");
+ }
+ fprintf(wrl," ]\n");
+
+ /* Color */
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < npoints; i++) {
+ double rgb[3], Lab[3];
+ Lab[0] = pary[i].pp[0];
+ Lab[1] = pary[i].pp[1];
+ Lab[2] = pary[i].pp[2];
+ Lab2RGB(rgb, Lab);
+ fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ /* End color */
+
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+
+}
+
+void end_vrml(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0)
+ error("Error closing VRML file\n");
+}
+
+
+/* Convert a gamut Lab value to an RGB value for display purposes */
+static void
+Lab2RGB(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+ double R, G, B;
+
+ /* Scale so that black is visible */
+ L = L * (100 - 40.0)/100.0 + 40.0;
+
+ /* First convert to XYZ using D50 white point */
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ x *= 0.9642; /* Multiply by white point, D50 */
+ y *= 1.0;
+ z *= 0.8249;
+
+ /* Now convert to sRGB values */
+ R = x * 3.2410 + y * -1.5374 + z * -0.4986;
+ G = x * -0.9692 + y * 1.8760 + z * 0.0416;
+ B = x * 0.0556 + y * -0.2040 + z * 1.0570;
+
+ if (R < 0.0)
+ R = 0.0;
+ else if (R > 1.0)
+ R = 1.0;
+
+ if (G < 0.0)
+ G = 0.0;
+ else if (G > 1.0)
+ G = 1.0;
+
+ if (B < 0.0)
+ B = 0.0;
+ else if (B > 1.0)
+ B = 1.0;
+
+ R = pow(R, 1.0/2.2);
+ G = pow(G, 1.0/2.2);
+ B = pow(B, 1.0/2.2);
+
+ out[0] = R;
+ out[1] = G;
+ out[2] = B;
+}
+
+
+/* ------------------------------------------------ */
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icctest: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icctest: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/icc/sRGB.icm b/icc/sRGB.icm
new file mode 100644
index 0000000..db0355f
--- /dev/null
+++ b/icc/sRGB.icm
Binary files differ
diff --git a/icc/testDE2K.c b/icc/testDE2K.c
new file mode 100644
index 0000000..11a4201
--- /dev/null
+++ b/icc/testDE2K.c
@@ -0,0 +1,226 @@
+
+/* Test the CIE delta E 2000 code */
+
+#include <stdio.h>
+#include <math.h>
+#include "icc.h"
+
+
+/* Reference data */
+
+#define NTESTS 34
+
+/* From the Sharma, Wu and Dalal "Implementation Notes" etc. paper: */
+struct {
+ double Lab1[3];
+ double Lab2[3];
+ double de;
+} ref[NTESTS] = {
+ { 50.0000, 2.6772, -79.7751, 50.0000, 0.0000, -82.7485, 2.0425 },
+ { 50.0000, 3.1571, -77.2803, 50.0000, 0.0000, -82.7485, 2.8615 },
+ { 50.0000, 2.8361, -74.0200, 50.0000, 0.0000, -82.7485, 3.4412 },
+ { 50.0000, -1.3802, -84.2814, 50.0000, 0.0000, -82.7485, 1.0000 },
+ { 50.0000, -1.1848, -84.8006, 50.0000, 0.0000, -82.7485, 1.0000 },
+ { 50.0000, -0.9009, -85.5211, 50.0000, 0.0000, -82.7485, 1.0000 },
+ { 50.0000, 0.0000, 0.0000, 50.0000, -1.0000, 2.0000, 2.3669 },
+ { 50.0000, -1.0000, 2.0000, 50.0000, 0.0000, 0.0000, 2.3669 },
+ { 50.0000, 2.4900, -0.0010, 50.0000, -2.4900, 0.0009, 7.1792 },
+ { 50.0000, 2.4900, -0.0010, 50.0000, -2.4900, 0.0010, 7.1792 },
+ { 50.0000, 2.4900, -0.0010, 50.0000, -2.4900, 0.0011, 7.2195 },
+ { 50.0000, 2.4900, -0.0010, 50.0000, -2.4900, 0.0012, 7.2195 },
+ { 50.0000, -0.0010, 2.4900, 50.0000, 0.0009, -2.4900, 4.8045 },
+ { 50.0000, -0.0010, 2.4900, 50.0000, 0.0010, -2.4900, 4.8045 },
+ { 50.0000, -0.0010, 2.4900, 50.0000, 0.0011, -2.4900, 4.7461 },
+ { 50.0000, 2.5000, 0.0000, 50.0000, 0.0000, -2.5000, 4.3065 },
+ { 50.0000, 2.5000, 0.0000, 73.0000, 25.0000, -18.0000, 27.1492 },
+ { 50.0000, 2.5000, 0.0000, 61.0000, -5.0000, 29.0000, 22.8977 },
+ { 50.0000, 2.5000, 0.0000, 56.0000, -27.0000, -3.0000, 31.9030 },
+ { 50.0000, 2.5000, 0.0000, 58.0000, 24.0000, 15.0000, 19.4535 },
+ { 50.0000, 2.5000, 0.0000, 50.0000, 3.1736, 0.5854, 1.0000 },
+ { 50.0000, 2.5000, 0.0000, 50.0000, 3.2972, 0.0000, 1.0000 },
+ { 50.0000, 2.5000, 0.0000, 50.0000, 1.8634, 0.5757, 1.0000 },
+ { 50.0000, 2.5000, 0.0000, 50.0000, 3.2592, 0.3350, 1.0000 },
+ { 60.2574, -34.0099, 36.2677, 60.4626, -34.1751, 39.4387, 1.2644 },
+ { 63.0109, -31.0961, -5.8663, 62.8187, -29.7946, -4.0864, 1.2630 },
+ { 61.2901, 3.7196, -5.3901, 61.4292, 2.2480, -4.9620, 1.8731 },
+ { 35.0831, -44.1164, 3.7933, 35.0232, -40.0716, 1.5901, 1.8645 },
+ { 22.7233, 20.0904, -46.6940, 23.0331, 14.9730, -42.5619, 2.0373 },
+ { 36.4612, 47.8580, 18.3852, 36.2715, 50.5065, 21.2231, 1.4146 },
+ { 90.8027, -2.0831, 1.4410, 91.1528, -1.6435, 0.0447, 1.4441 },
+ { 90.9257, -0.5406, -0.9208, 88.6381, -0.8985, -0.7239, 1.5381 },
+ { 6.7747, -0.2908, -2.4247, 5.8714, -0.0985, -2.2286, 0.6377 },
+ { 2.0776, 0.0795, -1.1350, 0.9033, -0.0636, -0.5514, 0.9082 }
+};
+
+double icmCIE2K(double *Lab1, double *Lab2);
+
+int main(void) {
+ int rv = 0;
+ int i;
+
+ printf("Starting Test:\n");
+
+#ifdef NEVER
+ for (i = 0; i < NTESTS; i++) {
+ printf("Lab1 = %f %f %f\n", ref[i].Lab1[0], ref[i].Lab1[1], ref[i].Lab1[2]);
+ printf("Lab2 = %f %f %f\n", ref[i].Lab2[0], ref[i].Lab2[1], ref[i].Lab2[2]);
+ printf("de = %f\n",ref[i].de);
+ }
+#endif
+
+ /* Test it all out */
+ for (i = 0; i < NTESTS; i++) {
+ double de;
+
+ de = icmCIE2K(ref[i].Lab1, ref[i].Lab2);
+ if (fabs(de - ref[i].de) > 0.0001) {
+ printf("Error at index %d:\n",i);
+ printf("Lab1 = %f %f %f\n", ref[i].Lab1[0], ref[i].Lab1[1], ref[i].Lab1[2]);
+ printf("Lab2 = %f %f %f\n", ref[i].Lab2[0], ref[i].Lab2[1], ref[i].Lab2[2]);
+ printf("DeltaE is %f, should be %f\n\n",de,ref[i].de);
+ rv = 1;
+ }
+ de = icmCIE2K(ref[i].Lab2, ref[i].Lab1);
+ if (fabs(de - ref[i].de) > 0.0001) {
+ printf("Error at index %d:\n",i);
+ printf("Lab1 = %f %f %f\n", ref[i].Lab2[0], ref[i].Lab2[1], ref[i].Lab2[2]);
+ printf("Lab2 = %f %f %f\n", ref[i].Lab1[0], ref[i].Lab1[1], ref[i].Lab1[2]);
+ printf("DeltaE is %f, should be %f\n\n",de,ref[i].de);
+ rv = 1;
+ }
+ }
+
+ printf("Test Finished\n");
+ return rv;
+}
+
+#ifdef NEVER /* Test implementation in icc.c */
+
+/* From the paper "The CIEDE2000 Color-Difference Formula: Implementation Notes, */
+/* Supplementary Test Data, and Mathematical Observations", by */
+/* Gaurav Sharma, Wencheng Wu and Edul N. Dalal, */
+/* Color Res. Appl., vol. 30, no. 1, pp. 21-30, Feb. 2005. */
+
+/* Return the CIEDE2000 Delta E color difference measure squared, for two Lab values */
+double icmCIE2Ksq(double *Lab0, double *Lab1) {
+ double C1, C2;
+ double h1, h2;
+ double dL, dC, dH;
+ double dsq;
+
+ /* The trucated value of PI is needed to ensure that the */
+ /* test cases pass, as one of them lies on the edge of */
+ /* a mathematical discontinuity. The precision is still */
+ /* enough for any practical use. */
+#define RAD2DEG(xx) (180.0/3.14159265358979 * (xx))
+#define DEG2RAD(xx) (3.14159265358979/180.0 * (xx))
+
+ /* Compute Cromanance and Hue angles */
+ {
+ double C1ab, C2ab;
+ double Cab, Cab7, G;
+ double a1, a2;
+
+ C1ab = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ C2ab = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ Cab = 0.5 * (C1ab + C2ab);
+ Cab7 = pow(Cab,7.0);
+ G = 0.5 * (1.0 - sqrt(Cab7/(Cab7 + 6103515625.0)));
+ a1 = (1.0 + G) * Lab0[1];
+ a2 = (1.0 + G) * Lab1[1];
+ C1 = sqrt(a1 * a1 + Lab0[2] * Lab0[2]);
+ C2 = sqrt(a2 * a2 + Lab1[2] * Lab1[2]);
+
+ if (C1 < 1e-9)
+ h1 = 0.0;
+ else {
+ h1 = RAD2DEG(atan2(Lab0[2], a1));
+ if (h1 < 0.0)
+ h1 += 360.0;
+ }
+
+ if (C2 < 1e-9)
+ h2 = 0.0;
+ else {
+ h2 = RAD2DEG(atan2(Lab1[2], a2));
+ if (h2 < 0.0)
+ h2 += 360.0;
+ }
+ }
+
+ /* Compute delta L, C and H */
+ {
+ double dh;
+
+ dL = Lab1[0] - Lab0[0];
+ dC = C2 - C1;
+ if (C1 < 1e-9 || C2 < 1e-9) {
+ dh = 0.0;
+ } else {
+ dh = h2 - h1;
+ if (dh > 180.0)
+ dh -= 360.0;
+ else if (dh < -180.0)
+ dh += 360.0;
+ }
+
+ dH = 2.0 * sqrt(C1 * C2) * sin(DEG2RAD(0.5 * dh));
+ }
+
+ {
+ double L, C, h, T;
+ double hh, ddeg;
+ double C7, RC, L50sq, SL, SC, SH, RT;
+ double dLsq, dCsq, dHsq, RCH;
+
+ L = 0.5 * (Lab0[0] + Lab1[0]);
+ C = 0.5 * (C1 + C2);
+ if (C1 < 1e-9 || C2 < 1e-9) {
+ h = h1 + h2;
+ } else {
+ h = h1 + h2;
+ if (fabs(h1 - h2) > 180.0) {
+ if (h < 360.0)
+ h += 360.0;
+ else if (h >= 360.0)
+ h -= 360.0;
+ }
+ h *= 0.5;
+ }
+ T = 1.0 - 0.17 * cos(DEG2RAD(h-30.0)) + 0.24 * cos(DEG2RAD(2.0 * h))
+ + 0.32 * cos(DEG2RAD(3.0 * h + 6.0)) - 0.2 * cos(DEG2RAD(4.0 * h - 63.0));
+ hh = (h - 275.0)/25.0;
+ ddeg = 30.0 * exp(-hh * hh);
+ C7 = pow(C,7.0);
+ RC = 2.0 * sqrt(C7/(C7 + 6103515625.0));
+ L50sq = (L - 50.0) * (L - 50.0);
+ SL = 1.0 + (0.015 * L50sq)/sqrt(20.0 + L50sq);
+ SC = 1.0 + 0.045 * C;
+ SH = 1.0 + 0.015 * C * T;
+ RT = -sin(DEG2RAD(2 * ddeg)) * RC;
+
+ dLsq = dL/SL;
+ dCsq = dC/SC;
+ dHsq = dH/SH;
+
+ RCH = RT * dCsq * dHsq;
+
+ dLsq *= dLsq;
+ dCsq *= dCsq;
+ dHsq *= dHsq;
+
+ dsq = dLsq + dCsq + dHsq + RCH;
+ }
+
+ return dsq;
+
+#undef RAD2DEG
+#undef DEG2RAD
+}
+
+/* Return the CIE2DE000 Delta E color difference measure for two Lab values */
+double icmCIE2K(double *Lab0, double *Lab1) {
+ return sqrt(icmCIE2Ksq(Lab0, Lab1));
+}
+
+#endif /* NEVER */
diff --git a/icc/todo.txt b/icc/todo.txt
new file mode 100644
index 0000000..bdbaa5e
--- /dev/null
+++ b/icc/todo.txt
@@ -0,0 +1,197 @@
+
+Notes on changes needed for V4.2
+
+--------------------------------------------
+Spec name/version/file version relationship.
+This is more complicated that it really should be:
+
+Spec. Name Spec. Version File Version
+---------- ------------- ------------
+ICC.1:2004-10 4.2 4.2.0 <-- target icclib4
+ICC.1:2003-09 4.1 4.1.0
+ICC.1:2001-12 4.0 4.0.0
+ICC.1:2001-04 (3.7?) 2.4.0
+ICC.1A:1999-04 (3.6?) 2.3.0
+ICC.1:1998-09 (3.5?) 2.2.0
+(Version 3.4) 3.4 2.1.0 (a) <-- current icclib
+(Version 3.3) 3.3 2.1.0
+(Version 3.2) 3.2 2.0.0 (b)
+(Version 3.01) 3.01 2.0.0 (a)
+(Version 3.0) 3.0 2.0.0
+
+-----------------------------
+There are other changes from V2.1 in later versions,
+such as:
+
+ 2.3.0
+ Chromaticity Tag added
+
+ 2.4.0
+ Lut tables now allowed for monochrome
+
+ Added chromaticAdaptationTag
+
+ Input, Display, Output and Colorspace LUT profiles
+ now support all 3 intents.
+
+Can this be made backwards compatible without
+messing about with specific code for other versions ??
+
+This doesn't seem possible. The profile generator code and icclib
+would seem to need to know which version they were generating,
+for assured backwards compatibility with other CMMs.
+-----------------------------
+Should add "guess ink limit" support to ease gamut finding
+from profiles. (Implemented in xicc at the moment) ?
+-----------------------------
+
+Add usage of #def icVersionNumberV41 when "V4" flag is active.
+
+Tags needed since V2.1
+
+ icSigChromaticAdaptationTag = 0x63686164L, /* 'chad' V2.4+ */
+ icSigChromaticityTag = 0x6368726DL, /* 'chrm' V2.3+ */
+ icSigColorantOrderTag = 0x636C726FL, /* 'clro' V4.0+ */
+ icSigColorantTableTag = 0x636C7274L, /* 'clrt' V4.0+ */
+ icSigColorantTableOutTag = 0x636C6F74L, /* 'clot' V4.0+ */
+ icSigDeviceSettingsTag = 0x64657673L, /* 'devs' V2.2 - V4.0 */
+ icSigOutputResponseTag = 0x72657370L, /* 'resp' V2.2+ */
+
+
+Tag types needed since V2.1
+
+ icSigDeviceSettingsType = 0x64657673L, /* 'devs' V2.2 - V4.0 */
+ icSigChromaticityTag = 0x6368726DL, /* 'chrm' V2.3+ */
+ icSigColorantOrderType = 0x636C726FL, /* 'clro' V4.0+ */
+ icSigColorantTableType = 0x636C7274L, /* 'clrt' V4.0+ */
+ icSigLutAtoBType = 0x6d414220L, /* 'mAB ' V4.0+ */
+ icSigLutBtoAType = 0x6d424120L, /* 'mBA ' V4.0+ */
+ icSigMultiLocalizedUnicodeType = 0x6D6C7563L, /* 'mluc' V4.0+ */
+ icSigParametricCurveType = 0x70617261L, /* 'para' V4.0+ */
+ icSigResponseCurveSet16Type = 0x72637332L, /* 'rcs2' V2.2 - V4.0 */
+
+Stuff to deal with in implementing ICCV4:
+-------------------
+
+Make sure DLL/SO version is compilable ??
+
+Add V4 flag in main icc struct (DONE), and some way of setting it before tags
+are added.
+
+Date & time being UTC.
+ - add flag when setting ?
+ - display both when dumping ?
+ - have both in structure when reading ?
+ - or simply not handle this ??
+
+Check all padding is zero during writing - DONE
+
+Implement MD5 generation on profile writing - DONE
+Implement MD5 check method on read profile ?
+Cross check MD5 against external V4 profiles. Cross check with cygwin md5sum!
+
+Colorant table tag needed in V4 for xCLR devices.
+colorantTableTag requirement for xCLR device link profiles.
+
+Add check that tags are unique within a profile ?
+
+Configure conformance to run as V4.2 or V2.4 on writing, and accept V4.X or V2.X on
+reading. Don't try and implement detailed minor version behaviour.
+
+Have some sort of table to embody valid tags and tag types within the two major
+version numbers (2 & 4) ??
+
+Check that non A2B0 and B2A0 intents are allowed for Input, Display & Colorspace
+profiles ??
+
+V4 mandates a chromatic adaptation tag for any profile that requires a white point
+tag & not D50. Add to V4 check, & generate chromatic adaptation tag for V2 & V4
+creation (method ?). Need to carefully read spec. to understand what chromatic
+adaptation tag is meant to represent.
+Implement absolute<->PCS object to represent functionality of chramatic adaptation,
+analogous to conversion object.
+
+
+Check mono profile black and white interpretation.
+
+
+Matrix/shaper in V4 has clipping requirements. Should these be honoured ??
+Maybe make this optional via a run time flag ?
+May be best to have multiple conformance flags (Absolute Intent etc. ?)
+
+Check icclink set header rendering intents correctly for device links.
+
+Implemenmt parametric curve type as extra icmCurveStyle(s), and use icmCurve object to
+do the work.
+
+
+Implement MultiLocalizedUnicodeType as overload of icmTextDescription, or new tagtype ??
+
+
+
+- - - - -
+Implement icSigLutAtoBType and icSigLutBtoAType as overloads of icmLut ??
+If so, add new icmLuAlgType types for AtoB and BtoA conversions (NO - more complicated)
+
+ - OR -
+
+switch to single superset Lut type ?? (YES - best solution) :-
+
+Should a more extensive general model be considered, as a superset of V4 ?? (YES)
+
+ pcs/abs -> Curves -> matrix -> curves -> lut -> curves -> matrix -> curves -> pcs/abs
+
+[ or asymetric ??: (NO)
+
+ pcs->curves->lut->3x3+3matrix->curves->pcs/abs (dev->PCS, PCS->PCS, dev->dev)
+ pcs/abs->curves->3x3+3matrix->curves->lut->curves (PCS->dev) ]
+
+Could use this as universal transform method, even for matrix profiles (don't use old style
+matrix/shaper or LUT at all internaly ?) (YES - need to accomodate V2 & V4 though).
+
+Add new methods to setup the transform stages, with current set mathods implemented
+as backwards compatible ? Have multiple methods rather than a single "set" ?
+( - how are ranges determined in latter case ?)
+
+Finish support for generic 3 stage conversion view (input per chan, cross chan, output per chan.),
+and support this in icclib4.
+
+Use bit flags to indicate which stages are valid.
+Flags effectively replace "algorithm" flag.
+Flag combination set determines how transform can be represented by a profile
+(Mono, Matrix, V2Lut, V4Lut etc.).
+
+Have flags for "separable" (i.e. channel independent) and
+"reversable".
+
+Support implementing a universal transform both forwards and
+backwards from a given set of ICC tags (backwards won't be
+valid for some tags, ie. Lut).
+
+lookup object acts as ideal abstract above exact tag representation within
+a profile. Use this model for other aspects of ICC profiles.
+Extend to simplify xicc/icc relationship - make xicc a true inheriting
+class, and add whatever hooks are needed into icclib4 to make this work.
+ICC tags -> luo -> transform
+ICC tags <- luo <- Set transform
+
+What impact does this have on memory usage though ?
+- Makes sure transform is completely independent of
+ tags or profile after setting up, so that tags and/or
+ profile can be released.
+
+- - - - - -
+
+Split icc.c into 3 levels:
+
+ 1 Basic support (I/O, primitives)
+ Toolkit for buiding ICC like file formats, but not
+ specic to the actual ICC file. Can be used to
+ create custom tags, and custom ICC like files (e.g. calibration)
+
+ 2 Specific to ICC format, tags etc.
+
+ 3 ICC color transform objects etc.
+ Allow for inheretance, so that xicc can be implemented
+ much more elegantly.
+
diff --git a/imdi/Jamfile b/imdi/Jamfile
new file mode 100644
index 0000000..a2b3796
--- /dev/null
+++ b/imdi/Jamfile
@@ -0,0 +1,90 @@
+
+# JAM style makefile for integer interpolation code, cctiff etc.
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCPROFFLAG) ; # Profile flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Link debugging flags
+#PREF_LINKFLAGS += $(LINKPROFFLAG) ; # Profile flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+
+#Products
+Libraries = libimdi ;
+Executables = cctiff greytiff ;
+Headers = imdi.h ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+HDRS = ../h ;
+
+# Hack! Make cross compile of MingW64 on 32 bit host work.
+# (This doesn't work - 32 bit libraries are not provided :-()
+#if $(NT) && $(MINGW64) {
+# ObjectCcFlags ctest imdi_make imdi_gen cgen : -m32 ;
+# MainLinkFlags ctest imdi_make : -m32 -L $(MINGW64_LIB32) ;
+#}
+if $(NT) && $(MINGW64) {
+ IMDI_MAKE_OPT = -f ; # Force 64 bits
+}
+
+# imdi low level cgen test code
+Main ctest : ctest.c cgen.c ;
+
+# make imdi code program
+Main imdi_make : imdi_make.c imdi_gen.c cgen.c ;
+
+HDRS = ../h ../numlib ;
+LINKLIBS = ../numlib/libnum ;
+
+# GenFile source.c : program args ; make custom file
+# Generate all the kernel files
+GenFileND imdi_k.h : imdi_make $(IMDI_MAKE_OPT) -d [ NormPaths $(DOT) ] ;
+
+# imdi library
+Library libimdi : imdi.c imdi_tab.c ;
+
+HDRS += ../icc ../rspl ../gamut ../cgats ../spectro ;
+LINKLIBS = $(LINKLIBS) libimdi ../icc/libicc ../numlib/libnum ;
+
+# imdi test code
+Main itest : itest.c refi.c : : : ../rspl : : ../rspl/librspl ../plot/libvrml ;
+
+# TIFF file color correction utlity
+Main cctiff : cctiff.c : : : ../xicc $(TIFFINC) $(JPEGINC) : : ../xicc/libxicc ../rspl/librspl ../cgats/libcgats ../plot/libvrml $(TIFFLIB) $(JPEGLIB) ;
+
+# Old TIFF file color correction utlity
+#Main cctiffo : cctiffo.c : : : $(TIFFINC) : : $(TIFFLIB) ;
+
+# TIFF file monochrome conversion utlity
+#Main greytiff : greytiff.c ;
+Main greytiff : greytiff.c : : : ../spectro ../xicc ../gamut ../rspl ../cgats $(TIFFINC)
+ : : ../xicc/libxicc ../gamut/libgamut ../rspl/librspl ../cgats/libcgats
+ ../plot/libplot ../plot/libvrml $(TIFFLIB) $(JPEGLIB) ;
+
+# ssort generation code
+#Main ssort : ssort.c ;
+
+#Main shsort : shsort.c ;
+
+# code generated by shsort
+#Main ttt : ttt.c ;
+
+if $(BUILD_JUNK) {
+
+ Main f2test : f2test.c : : : ../spectro ../xicc ../gamut ../rspl ../cgats $(TIFFINC)
+ : : ../xicc/libxicc ../gamut/libgamut ../rspl/librspl ../cgats/libcgats
+ ../plot/libplot ../plot/libvrml $(TIFFLIB) $(JPEGLIB) ;
+
+
+ CCFLAGS += -msse3 ;
+
+ Main tvec : tvec.c ;
+ Main tvec2 : tvec2.c ;
+
+ # test code
+ Main tsort : tsort.c ;
+}
+
diff --git a/imdi/License.txt b/imdi/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/imdi/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/imdi/Makefile b/imdi/Makefile
new file mode 100644
index 0000000..5523893
--- /dev/null
+++ b/imdi/Makefile
@@ -0,0 +1,66 @@
+
+# Boilerplate Makefile for compiling imdi
+
+# Copyright 2000 - 2007 Graeme W. Gill
+# This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+# see the License.txt file for licencing details.
+
+# "include" the right environment for your system,
+# by uncommenting the appropriate line:
+
+# Microsoft VC++, WinNT setup
+include Makefile.WNT
+
+# Generic UNIX setup
+#include Makefile.UNIX
+
+# Apple OS X
+#include Makefile.OSX
+
+
+###############################
+
+#Set optimisation on
+CCFLAGS = $(CCFLAGSDEF) $(CCOPTFLAG) $(CCDEFINES) $(BCONFIG)
+
+#Set debugging on
+#CCFLAGS = $(CCFLAGSDEF) $(CCDEBUGFLAG) $(CCDEFINES) $(BCONFIG)
+# debugging #define
+#CCFLAGS = $(CCFLAGSDEF) $(CCDEBUGFLAG) $(CCDEFINES) $(DEFFLAG)DEBUG
+LINKFLAGS = $(LINKFLAGSDEF) $(LINKDEBUGFLAG)
+
+STDHDRS = $(INCFLAG)$(STDHDRSDEF)
+
+all:: libimdi$(SUFLIB)
+
+# Used by both code generator and runtime
+imdi_make$(SUFEXE): imdi_make$(SUFOBJ) imdi_gen$(SUFOBJ) cgen$(SUFOBJ)
+ $(LINK) $(LINKOF)imdi_make$(SUFEXE) imdi_make$(SUFOBJ) imdi_gen$(SUFOBJ) cgen$(SUFOBJ)
+
+
+# The code generator program
+
+cgen$(SUFOBJ): cgen.c imdi_utl.h imdi_arch.h imdi_gen.h imdi_tab.h
+ $(CC) cgen.c
+
+imdi_gen$(SUFOBJ): imdi_gen.c imdi_utl.h imdi_arch.h imdi_gen.h
+ $(CC) imdi_gen.c
+
+# Generate the kernel files
+imdi_k.h imdi_k.c : imdi_make$(SUFEXE)
+ .$(SLASH)imdi_make$(SUFEXE)
+
+
+# imdi runtime library
+
+imdi$(SUFOBJ): imdi.c imdi.h imdi_tab.h imdi_k.h imdi_k.c
+ $(CC) imdi.c
+
+libimdi$(SUFLIB): imdi$(SUFOBJ) imdi_tab$(SUFOBJ)
+ $(LIBU) $(LIBOF)$@ imdi$(SUFOBJ) imdi_tab$(SUFOBJ)
+ $(RANLIB) libimdi$(SUFLIB)
+
+
+
+
+
diff --git a/imdi/Makefile.OSX b/imdi/Makefile.OSX
new file mode 100644
index 0000000..1e03a43
--- /dev/null
+++ b/imdi/Makefile.OSX
@@ -0,0 +1,42 @@
+# MAC OSX, derived from UNIX setup
+
+# Copyright 2000 - 2007 Graeme W. Gill
+# This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+# see the License.txt file for licencing details.
+
+SLASH = /
+SUFLIB = .a
+SUFOBJ = .o
+SUFEXE =
+CMDSEP = ;
+
+INCFLAG = -I
+DEFFLAG = -D
+UNDEFFLAG = -U
+CCOPTFLAG = -O
+CCDEBUGFLAG = -g
+CCPROFFLAG =
+LINKDEBUGFLAG =
+LINKPROFFLAG =
+
+STDHDRSDEF = /usr/include
+
+MAKEU = make
+LIBU = ar -r
+LIBOF =
+RANLIB = ranlib
+AS = as
+CCFLAGSDEF = -DUNIX -c
+CC = cc $(CCFLAGS) $(STDHDRS)
+CCOF = -o
+LINKFLAGSDEF = -lm
+LINKLIBS =
+LINK = cc $(LINKFLAGS) $(LINKLIBS)
+LINKOF = -o
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/imdi/Makefile.UNIX b/imdi/Makefile.UNIX
new file mode 100644
index 0000000..37aab1a
--- /dev/null
+++ b/imdi/Makefile.UNIX
@@ -0,0 +1,42 @@
+# Generic UNIX setup
+
+# Copyright 2000 - 2007 Graeme W. Gill
+# This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+# see the License.txt file for licencing details.
+
+SLASH = /
+SUFLIB = .a
+SUFOBJ = .o
+SUFEXE =
+CMDSEP = ;
+
+INCFLAG = -I
+DEFFLAG = -D
+UNDEFFLAG = -U
+CCOPTFLAG = -O
+CCDEBUGFLAG = -g
+CCPROFFLAG =
+LINKDEBUGFLAG =
+LINKPROFFLAG =
+
+STDHDRSDEF = /usr/include
+
+MAKEU = make
+LIBU = ar -r
+LIBOF =
+RANLIB = echo
+AS = as
+CCFLAGSDEF = -DUNIX -c
+CC = cc $(CCFLAGS) $(STDHDRS)
+CCOF = -o
+LINKFLAGSDEF = -lm
+LINKLIBS =
+LINK = cc $(LINKFLAGS) $(LINKLIBS)
+LINKOF = -o
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/imdi/Makefile.WNT b/imdi/Makefile.WNT
new file mode 100644
index 0000000..601e1f6
--- /dev/null
+++ b/imdi/Makefile.WNT
@@ -0,0 +1,42 @@
+# Microsoft VC++, WinNT setup
+
+# Copyright 2000 - 2007 Graeme W. Gill
+# This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+# see the License.txt file for licencing details.
+
+SLASH = \
+SUFLIB = .lib
+SUFOBJ = .obj
+SUFEXE = .exe
+CMDSEP = &
+
+INCFLAG = /I
+DEFFLAG = /D
+UNDEFFLAG = /U
+CCOPTFLAG = /Ox /GB
+CCDEBUGFLAG = /Z7 /Od
+CCPROFFLAG = /Z7
+LINKDEBUGFLAG = /DEBUG
+LINKPROFFLAG = /PROFILE
+
+STDHDRSDEF = $(MSVCNT)\include
+
+MAKEU = nmake
+LIBU = lib
+LIBOF = /OUT:
+RANLIB = rem
+AS = masm386
+CCFLAGSDEF = /DNT /c
+CC = cl /nologo $(CCFLAGS) $(STDHDRS)
+CCOF = /Fo
+LINKLIBS = $(MSVCNT)/lib/user32.lib $(MSVCNT)/lib/gdi32.lib
+LINKFLAGSDEF = /link /INCREMENTAL:NO
+LINK = link $(LINKFLAGS)
+LINKOF = /OUT:
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/imdi/Makefile.am b/imdi/Makefile.am
new file mode 100644
index 0000000..94ca112
--- /dev/null
+++ b/imdi/Makefile.am
@@ -0,0 +1,40 @@
+include $(top_srcdir)/Makefile.shared
+
+lib_LTLIBRARIES = libimdi.la
+
+LIBIMDI_VERSION=0.0
+
+libimdi_la_SOURCES = imdi.c imdi_tab.c imdi_arch.h imdi_gen.h imdi.h \
+ imdi_tab.h imdi_utl.h refi.h imdi_k.h
+libimdi_la_LDFLAGS = -version $(shell echo $(LIBIMDI_VERSION) | tr . :):0
+
+include_HEADERS = imdi_arch.h imdi_gen.h imdi.h imdi_tab.h \
+ imdi_utl.h refi.h
+
+bin_PROGRAMS = cctiff greytiff
+
+BINLDADD = ./libimdi.la ../spectro/libinsttypes.la ../plot/libvrml.la \
+ ../xicc/libxicc.la ../xicc/libxutils.la ../gamut/libgamut.la \
+ ../gamut/libgammap.la ../rspl/librspl.la $(ICC_LIBS) \
+ ../cgats/libcgats.la ../numlib/libargyllnum.la ../libargyll.la \
+ $(TIFF_LIBS) -ljpeg
+
+cctiff_LDADD = $(BINLDADD)
+greytiff_LDADD = $(BINLDADD)
+
+check_PROGRAMS = ctest
+
+ctest_SOURCES = ctest.c cgen.c
+
+noinst_PROGRAMS = imdi_make
+
+imdi_make_SOURCES = imdi_make.c imdi_gen.c cgen.c
+##imdi_make_CFLAGS = $(CFLAGS) -O
+
+BUILT_SOURCES = imdi_k.h
+
+imdi.c: imdi_k.h
+imdi_k.h: imdi_make
+ ./imdi_make
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/imdi/Readme.txt b/imdi/Readme.txt
new file mode 100644
index 0000000..a12d649
--- /dev/null
+++ b/imdi/Readme.txt
@@ -0,0 +1,114 @@
+
+This is the development area for IMDI, the
+Integer Multi-Dimensional Interpolation routines.
+
+They provide a flexible and high performance
+system for applying color transforms to typical
+raster pixel data. Because they provide a means of
+applying arbitrary combination dependent mappings
+of multi-channel pixel data, there are many other
+possible uses for these sorts of routines as well,
+including high quality matting/compositing. For instance,
+one could create a smooth, proportional "chroma key"
+type of matt for matting one RGB image onto another
+by creating a 6 channel to 3 dimensional transform,
+that its applied to each pair of pixels from the
+source images and produces one combined output pixel.
+Additional input or output alpha channels are easy
+to add by simply adding more input and/or output
+dimensions. The matting calculatons can be almost
+arbitrarily complex, and the imdi will apply them
+to the pixel data at very high speed.
+
+The system has two parts, one that generates taylored,
+optimised source code for the transformation kernels,
+and the run time code that matches a transform request
+to a compiled kernel, and initialises the appropriate
+run time lookup tables.
+
+The kernel source generator is intended to accomodate
+various optimisations, such as assembly code, vector
+instruction set (ie. MMX, AltiVec etc.) versions, but
+at present only generates the more portable 'C' code
+kernels.
+
+Both 8 bit per component and 16 bit per component
+pixel data is handled, up to 8 input and output
+dimensions (but this limit could be trivially raised).
+
+imdi_make.exe is the module that triggers the generation of
+ optimised source code as configured for the color spaces
+ and pixel formats selected. By default creates
+ a single imdi_k.c and imdi_k.h file, but if
+ given the -i flag, creates a separate file
+ for each kernel variant.
+
+cgen.c C code generator module.
+
+itest.c regresion test routine.
+ Normally runs speed and accuracy tests for
+ all configured kernel variants.
+ The -q flag makes it run quicker,
+ but makes the benchmarking inacurate,
+ the -s flag will cause it to stop
+ if any routine has unexpectedly low
+ accuracy.
+
+cctiff.c is the utility that takes an ICC device
+ profile link, and converts a TIFF file
+ from the input colorspace to the output
+ space. Both 8 bit and 16 bit TIFF files
+ are handled, as well as colorspaces up to
+ 8 channels in and out.
+ This accepts either a device link ICC profile,
+ or links an input and output devce ICC profile
+ to define the color transform.
+
+
+greytiff.c is a utility similar to cctiff, that
+ is an example of how to colorimetrically
+ convert an RGB file into a monochrome RGB file.
+
+
+
+Misc. Notes
+-----------
+
+ ITU-T Rec. T.42 specifies the ITULAB encoding in terms of a range
+ and offset for each component, which are related to the minimum and
+ maximum values as follows:
+
+ minimum = - (range x offset) / 2^n - 1
+ maximum = minimum + range
+
+ The Decode field default values depend on the color space. For the
+ ITULAB color space encoding, the default values correspond to the
+ base range and offset, as specified in ITU-T Rec. T.42 [T.42]. The
+ following table gives the base range and offset values for
+ BitsPerSample=8 and 12, and the corresponding default minimum and
+ maximum default values for the Decode field, calculated using the
+ equations above when PhotometricInterpetation=10.
+
+ +-----------------------------------------------+
+ | ITU-T Rec. T.42 | Decode |
+ +---------+-----------| base values | default values |
+ | BitsPer + Component +------------------+----------------------------+
+ | -Sample | | Range | Offset | Min | Max |
+ +---------+-----------+--------+---------+--------------+-------------+
+ | 8 | L* | 100 | 0 | 0 | 100 |
+ | +-----------+--------+---------+--------------+-------------+
+ | | a* | 170 | 128 | -21760/255 | 21590/255 |
+ | +-----------+--------+---------+--------------+-------------+
+ | | b* | 200 | 96 | -19200/255 | 31800/255 |
+ +---------+-----------+--------+---------+--------------+-------------+
+ | 12 | L* | 100 | 0 | 0 | 100 |
+ | +-----------+--------+---------+--------------+-------------+
+ | | a* | 170 | 2048 | -348160/4095 | 347990/4095 |
+ | +-----------+--------+---------+--------------+-------------+
+ | | b* | 200 | 1536 | -307200/4095 | 511800/4095 |
+ +---------+-----------+--------+---------+--------------+-------------+
+
+ For example, when PhotometricInterpretation=10 and BitsPerSample=8,
+ the default value for Decode is (0, 100, -21760/255, 21590/255,
+ -19200/255, 31800/255).
+
diff --git a/imdi/afiles b/imdi/afiles
new file mode 100644
index 0000000..81f6220
--- /dev/null
+++ b/imdi/afiles
@@ -0,0 +1,26 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+Makefile
+Makefile.OSX
+Makefile.UNIX
+Makefile.WNT
+cctiff.c
+cctiffo.c
+greytiff.c
+cgen.c
+ctest.c
+imdi.c
+imdi.h
+imdi_make.c
+imdi_arch.h
+imdi_gen.h
+imdi_gen.c
+imdi_utl.h
+imdi_tab.c
+imdi_tab.h
+itest.c
+refi.c
+refi.h
+ssort.c
diff --git a/imdi/cctiff.c b/imdi/cctiff.c
new file mode 100644
index 0000000..1f3eb9e
--- /dev/null
+++ b/imdi/cctiff.c
@@ -0,0 +1,2320 @@
+
+/*
+ * Color Correct a TIFF or JPEG file, using an ICC Device link profile.
+ * Version #2, that allows an arbitrary string of profiles, and
+ * copes with TIFF L*a*b* input and output.
+ *
+ * Author: Graeme W. Gill
+ * Date: 29/5/2004
+ * Version: 2.00
+ *
+ * Copyright 2000 - 2006, 2012 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.
+ */
+
+/* TTBD:
+
+ Should make -d option default to the last device
+ profile.
+
+ Should add support for getting TIFF ink names from
+ the ICC profile colorantTable if it exists,
+ or guessing them if they don't, and
+ then matching them to the incoming TIFF, and
+ embedding them in the outgoing TIFF.
+ Add flag to ignore inkname mismatches.
+
+
+ Should add support for transfering any extra alpha
+ planes from input to output, rather than simply ignoring them.
+
+
+ Question: Should this be changed to also function as
+ a dedicated simple linker, capable of outputing
+ a device link formed from a sequence ?
+ If argyll functionality was properly modularized,
+ it would be possible to have a single arbitrary
+ smart link sequence for both purposes.
+
+
+ There's the sugggestion that the CIELab and ICCLab encodings
+ have different white points (D65 and D50 respecively -
+ see <http://www.asmail.be/msg0055212264.html>). Should
+ we convert the white point to D65 for CIELab, or make this
+ an option ? Probably a bad idea if we regard the Lab in/out
+ as relative colorimetric representation ??
+
+ Ideally should automatically generate optimized per channel
+ input and output curves, rather than depending on
+ reasonable behaviour from the profiles.
+
+ I don't think that the idea of an XYZ input/output space
+ has been properly implemented, since the TIFF format
+ doesn't have an encoding for it, and hence the l2y_curve
+ and u2l_curve scaling is probably incorrect.
+
+ Forcing XYZ or Lab input & output spaces to be [io]combined
+ is also not actually necessary, if the necessary profile
+ curves were applied and the colorspace ranges properly allowed for.
+
+ JPEG FAX encoding is not currently implemented.
+
+ */
+
+/*
+ This program is a framework that exercises the
+ IMDI code, as well as a demonstration of profile linking.
+ It can also do the raster data conversion using the
+ floating point code in ICCLIB as a reference.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "tiffio.h"
+#include "jpeglib.h"
+#include "iccjpeg.h"
+#include "icc.h"
+#include "xicc.h"
+#include "imdi.h"
+
+#undef DEBUG /* Print detailed debug info */
+
+
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+
+#define DEFJPGQ 80 /* Default JPEG quality */
+
+void usage(char *diag, ...) {
+ fprintf(stderr,"Color Correct a TIFF or JPEG file using any sequence of ICC profiles or Calibrations, V%s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: cctiff [-options] { [-i intent] profile%s | calbrtn.cal ...} infile.tif/jpg outfile.tif/jpg\n",ICC_FILE_EXT);
+ fprintf(stderr," -v Verbose.\n");
+ fprintf(stderr," -c Combine linearisation curves into one transform.\n");
+ fprintf(stderr," -p Use slow precise correction.\n");
+ fprintf(stderr," -k Check fast result against precise, and report.\n");
+ fprintf(stderr," -r n Override the default CLUT resolution\n");
+ fprintf(stderr," -t n Choose output encoding from 1..n\n");
+ fprintf(stderr," -f [T|J] Set output format to Tiff or Jpeg (Default is same as input)\n");
+ fprintf(stderr," -q quality Set JPEG quality 1..100 (Default %d)\n",DEFJPGQ);
+ fprintf(stderr," -a Read and Write planes > 4 as alpha planes\n");
+ fprintf(stderr," -I Ignore any file or profile colorspace mismatches\n");
+ fprintf(stderr," -D Don't append or set the output TIFF or JPEG description\n");
+ fprintf(stderr," -e profile.[%s | tiff | jpg] Optionally embed a profile in the destination TIFF or JPEG file.\n",ICC_FILE_EXT_ND);
+ fprintf(stderr,"\n");
+ fprintf(stderr," Then for each profile in sequence:\n");
+ fprintf(stderr," -i intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute colorimetric\n");
+ fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
+ fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
+ fprintf(stderr," profile.[%s | tiff] Device, Link or Abstract profile\n",ICC_FILE_EXT_ND);
+ fprintf(stderr," ( May be embedded profile in TIFF/JPEG file)\n");
+ fprintf(stderr," or each calibration file in sequence:\n");
+ fprintf(stderr," -d dir f = forward cal. (default), b = backwards cal.\n");
+ fprintf(stderr," calbrtn.cal Device calibration file.\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr," infile.tif/jpg Input TIFF/JPEG file in appropriate color space\n");
+ fprintf(stderr," outfile.tif/jpg Output TIFF/JPEG file\n");
+ exit(1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Conversion functions from direct binary 0..n^2-1 == 0.0 .. 1.0 range */
+/* to ICC luo input range, and the reverse. */
+/* Note that all these functions are per-component, */
+/* so the can be included in per-component input or output curves, */
+/* if they PCS values were rescaled to be within the range 0.0 .. 1.0. */
+/* Since we're not currently doing this, we always set i/ocpmbine */
+/* if the input/output is PCS, so that real PCS values don't */
+/* appear in the input/output curves. */
+
+/* TIFF 8 bit CIELAB to standard L*a*b* */
+/* Assume that a & b have been converted from signed to offset */
+static void cvt_CIELAB8_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = in[1] * 255.0 - 128.0;
+ out[2] = in[2] * 255.0 - 128.0;
+}
+
+/* Standard L*a*b* to TIFF 8 bit CIELAB */
+/* Assume that a & b will be converted from offset to signed */
+static void cvt_Lab_to_CIELAB8(double *out, double *in) {
+ out[0] = in[0] / 100.0;
+ out[1] = (in[1] + 128.0) * 1.0/255.0;
+ out[2] = (in[2] + 128.0) * 1.0/255.0;
+}
+
+
+/* TIFF 16 bit CIELAB to standard L*a*b* */
+/* Assume that a & b have been converted from signed to offset */
+static void cvt_CIELAB16_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = (in[1] - 32768.0/65535.0) * 256.0;
+ out[2] = (in[2] - 32768.0/65535.0) * 256.0;
+}
+
+/* Standard L*a*b* to TIFF 16 bit CIELAB */
+/* Assume that a & b will be converted from offset to signed */
+static void cvt_Lab_to_CIELAB16(double *out, double *in) {
+ out[0] = in[0] / 100.0;
+ out[1] = in[1]/256.0 + 32768.0/65535.0;
+ out[2] = in[2]/256.0 + 32768.0/65535.0;
+}
+
+
+/* TIFF 8 bit ICCLAB to standard L*a*b* */
+static void cvt_ICCLAB8_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = (in[1] * 255.0) - 128.0;
+ out[2] = (in[2] * 255.0) - 128.0;
+}
+
+/* Standard L*a*b* to TIFF 8 bit ICCLAB */
+static void cvt_Lab_to_ICCLAB8(double *out, double *in) {
+ out[0] = in[0] * 1.0/100.0;
+ out[1] = (in[1] + 128.0) * 1.0/255.0;
+ out[2] = (in[2] + 128.0) * 1.0/255.0;
+}
+
+
+/* TIFF 16 bit ICCLAB to standard L*a*b* */
+static void cvt_ICCLAB16_to_Lab(double *out, double *in) {
+ out[0] = in[0] * (100.0 * 65535.0)/65280.0;
+ out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0;
+ out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0;
+}
+
+/* Standard L*a*b* to TIFF 16 bit ICCLAB */
+static void cvt_Lab_to_ICCLAB16(double *out, double *in) {
+ out[0] = in[0] * 65280.0/(100.0 * 65535.0);
+ out[1] = (in[1] + 128.0) * 65280.0/(255.0 * 65535.0);
+ out[2] = (in[2] + 128.0) * 65280.0/(255.0 * 65535.0);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Convert a TIFF Photometric tag to an ICC colorspace. */
+/* return 0 if not possible or applicable. */
+icColorSpaceSignature
+TiffPhotometric2ColorSpaceSignature(
+void (**ocvt)(double *out, double *in), /* Return write conversion function, NULL if none */
+void (**icvt)(double *out, double *in), /* Return read conversion function, NULL if none */
+int *smsk, /* Return signed handling mask, 0x0 if none */
+int pmtc, /* Input TIFF photometric */
+int bps, /* Input Bits per sample */
+int spp, /* Input Samples per pixel */
+int extra /* Extra Samples per pixel, if any */
+) {
+ if (icvt != NULL)
+ *icvt = NULL; /* Default return values */
+ if (ocvt != NULL)
+ *ocvt = NULL; /* Default return values */
+ if (smsk != NULL)
+ *smsk = 0x0;
+
+// if (extra > 0 && pmtc != PHOTOMETRIC_SEPARATED)
+// return 0x0; /* We don't handle this */
+
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE: /* Subtractive Gray */
+ return icSigGrayData;
+
+ case PHOTOMETRIC_MINISBLACK: /* Additive Gray */
+ return icSigGrayData;
+
+ case PHOTOMETRIC_RGB:
+ return icSigRgbData;
+
+ case PHOTOMETRIC_PALETTE:
+ return 0x0;
+
+ case PHOTOMETRIC_MASK:
+ return 0x0;
+
+ case PHOTOMETRIC_SEPARATED:
+ /* Should look at the colorant names to figure out if this is CMY, CMYK */
+ /* Should at least return both Cmy/3 or Cmyk/4 ! */
+ switch(spp) {
+ case 2:
+ return icSig2colorData;
+ case 3:
+// return icSig3colorData;
+ return icSigCmyData;
+ case 4:
+// return icSig4colorData;
+ return icSigCmykData;
+ case 5:
+ return icSig5colorData;
+ case 6:
+ return icSig6colorData;
+ case 7:
+ return icSig7colorData;
+ case 8:
+ return icSig8colorData;
+ case 9:
+ return icSig9colorData;
+ case 10:
+ return icSig10colorData;
+ case 11:
+ return icSig11colorData;
+ case 12:
+ return icSig12colorData;
+ case 13:
+ return icSig13colorData;
+ case 14:
+ return icSig14colorData;
+ case 15:
+ return icSig15colorData;
+ }
+
+ case PHOTOMETRIC_YCBCR:
+ return icSigYCbCrData;
+
+ case PHOTOMETRIC_CIELAB:
+ if (bps == 8) {
+ if (icvt != NULL)
+ *icvt = cvt_CIELAB8_to_Lab;
+ if (ocvt != NULL)
+ *ocvt = cvt_Lab_to_CIELAB8;
+ } else {
+ if (icvt != NULL)
+ *icvt = cvt_CIELAB16_to_Lab;
+ if (ocvt != NULL)
+ *ocvt = cvt_Lab_to_CIELAB16;
+ }
+ *smsk = 0x6; /* Treat a & b as signed */
+ return icSigLabData;
+
+ case PHOTOMETRIC_ICCLAB:
+ if (bps == 8) {
+ if (icvt != NULL)
+ *icvt = cvt_ICCLAB8_to_Lab;
+ if (ocvt != NULL)
+ *ocvt = cvt_Lab_to_ICCLAB8;
+ } else {
+ if (icvt != NULL)
+ *icvt = cvt_ICCLAB16_to_Lab;
+ if (ocvt != NULL)
+ *ocvt = cvt_Lab_to_ICCLAB16;
+ }
+ return icSigLabData;
+
+ case PHOTOMETRIC_ITULAB:
+ return 0x0; /* Could add this with a conversion function */
+ /* but have to allow for variable ITU gamut */
+ /* (Tag 433, "Decode") */
+
+ case PHOTOMETRIC_LOGL:
+ return 0x0; /* Could add this with a conversion function */
+
+ case PHOTOMETRIC_LOGLUV:
+ return 0x0; /* Could add this with a conversion function */
+ }
+ return 0x0;
+}
+
+
+/* Convert an ICC colorspace to the corresponding possible TIFF Photometric tags. */
+/* Return the number of matching tags, and 0 if there is no corresponding tag. */
+int
+ColorSpaceSignature2TiffPhotometric(
+uint16 tags[10], /* Pointer to return array, up to 10 */
+icColorSpaceSignature cspace /* Input ICC colorspace */
+) {
+ switch(cspace) {
+ case icSigGrayData:
+ tags[0] = PHOTOMETRIC_MINISBLACK;
+ return 1;
+ case icSigRgbData:
+ tags[0] = PHOTOMETRIC_RGB;
+ return 1;
+ case icSigCmyData:
+ case icSigCmykData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+ case icSigYCbCrData:
+ tags[0] = PHOTOMETRIC_YCBCR;
+ return 1;
+ case icSigXYZData:
+ case icSigLabData:
+ tags[0] = PHOTOMETRIC_CIELAB;
+ tags[1] = PHOTOMETRIC_ICCLAB;
+#ifdef NEVER
+ tags[2] = PHOTOMETRIC_ITULAB;
+#endif
+ return 2;
+
+ case icSigLuvData:
+ case icSigYxyData: /* Could handle this with a conversion ?? */
+ case icSigHsvData:
+ case icSigHlsData:
+ return 0;
+
+ case icSig2colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig3colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig4colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig5colorData:
+ case icSigMch5Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig6colorData:
+ case icSigMch6Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig7colorData:
+ case icSigMch7Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig8colorData:
+ case icSigMch8Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig9colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig10colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig11colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig12colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig13colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig14colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ case icSig15colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Compute the length of a double nul terminated string, including */
+/* the nuls. */
+static int zzstrlen(char *s) {
+ int i;
+ for (i = 0;; i++) {
+ if (s[i] == '\000' && s[i+1] == '\000')
+ return i+2;
+ }
+ return 0;
+}
+
+/* Convert an ICC colorspace to the corresponding TIFF Inkset tag */
+/* return 0xffff if not possible or applicable. */
+static int
+ColorSpaceSignature2TiffInkset(
+icColorSpaceSignature cspace,
+int *len, /* Return length of ASCII inknames */
+char **inknames /* Return ASCII inknames if non NULL */
+) {
+ switch(cspace) {
+ case icSigCmyData:
+ return 0xffff;
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return 0; /* Not CMYK */
+ case icSigCmykData:
+ if (inknames != NULL) {
+ *inknames = NULL; /* No inknames */
+ *len = 0;
+ }
+ return INKSET_CMYK;
+
+ case icSigGrayData:
+ case icSigRgbData:
+ case icSigYCbCrData:
+ case icSigLabData:
+ case icSigXYZData:
+ case icSigLuvData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSigMch5Data:
+ return 0xffff;
+
+ case icSig6colorData:
+ case icSigMch6Data:
+ /* This is a cheat and a hack. Should really make use of the */
+ /* ColorantTable to determine the colorant names. */
+ /* allowing cctiff to read it. */
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000black\000orange\000green\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return INKSET_MULTIINK;
+
+ case icSig7colorData:
+ case icSigMch7Data:
+ return 0xffff;
+
+ case icSig8colorData:
+ case icSigMch8Data:
+ /* This is a cheat and a hack. Should really make use of the */
+ /* ColorantTable to determine the colorant names. */
+ /* allowing cctiff to read it. */
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000black\000orange\000green\000lightcyan\000lightmagenta\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return INKSET_MULTIINK;
+ case icSig9colorData:
+ case icSig10colorData:
+ case icSig11colorData:
+ case icSig12colorData:
+ case icSig13colorData:
+ case icSig14colorData:
+ case icSig15colorData:
+ default:
+ return 0xffff;
+ }
+ return 0xffff;
+}
+
+static char *
+Photometric2str(
+int pmtc
+) {
+ static char buf[80];
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE:
+ return "Subtractive Gray";
+ case PHOTOMETRIC_MINISBLACK:
+ return "Additive Gray";
+ case PHOTOMETRIC_RGB:
+ return "RGB";
+ case PHOTOMETRIC_PALETTE:
+ return "Indexed";
+ case PHOTOMETRIC_MASK:
+ return "Transparency Mask";
+ case PHOTOMETRIC_SEPARATED:
+ return "Separated";
+ case PHOTOMETRIC_YCBCR:
+ return "YCbCr";
+ case PHOTOMETRIC_CIELAB:
+ return "CIELab";
+ case PHOTOMETRIC_ICCLAB:
+ return "ICCLab";
+ case PHOTOMETRIC_ITULAB:
+ return "ITULab";
+ case PHOTOMETRIC_LOGL:
+ return "CIELog2L";
+ case PHOTOMETRIC_LOGLUV:
+ return "CIELog2Luv";
+ }
+ sprintf(buf,"Unknown Photometric Tag %d",pmtc);
+ return buf;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#define YSCALE (2.0/1.3)
+
+/* Extra non-linearity applied to BtoA XYZ PCS */
+/* This distributes the LUT indexes more evenly in */
+/* perceptual space, greatly improving the B2A accuracy of XYZ LUT */
+/* Since typically XYZ doesn't use the full range of 0-2.0 allowed */
+/* for in the encoding, we scale the cLUT index values to use the 0-1.3 range */
+
+/* (For these functions the encoded XYZ 0.0 - 2.0 range is 0.0 - 1.0 ??) */
+
+/* Y to L* */
+static void y2l_curve(double *out, double *in, int isXYZ) {
+ int i;
+ double val;
+ double isc = 1.0, osc = 1.0;
+
+ /* Scale from 0.0 .. 1.999969 to 0.0 .. 1.0 and back */
+ /* + range adjustment */
+ if (isXYZ) {
+ isc = 32768.0/65535.0 * YSCALE;
+ osc = 65535.0/32768.0;
+ }
+
+ for (i = 0; i < 3; i++) {
+ val = in[i] * isc;
+ if (val > 0.008856451586)
+ val = 1.16 * pow(val,1.0/3.0) - 0.16;
+ else
+ val = 9.032962896 * val;
+ if (val > 1.0)
+ val = 1.0;
+ out[i] = val * osc;
+ }
+}
+
+/* L* to Y */
+static void l2y_curve(double *out, double *in, int isXYZ) {
+ int i;
+ double val;
+ double isc = 1.0, osc = 1.0;
+
+ /* Scale from 0.0 .. 1.999969 to 0.0 .. 1.0 and back */
+ /* + range adjustment */
+ if (isXYZ) {
+ isc = 32768.0/65535.0;
+ osc = 65535.0/32768.0 / YSCALE;
+ }
+
+ /* Use an L* like curve, scaled to the maximum XYZ value */
+ for (i = 0; i < 3; i++) {
+ val = in[i] * isc;
+ if (val > 0.08)
+ val = pow((val + 0.16)/1.16, 3.0);
+ else
+ val = val/9.032962896;
+ out[i] = val * osc;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Callbacks used to initialise imdi */
+
+
+/* Information needed from a single profile */
+struct _profinfo {
+ char name[MAXNAMEL+1];
+ icc *c; /* If non-NULL, ICC profile. */
+ xcal *cal; /* if non-NULL, xcal rather than profile */
+
+ /* Valid for both icc and xcal: */
+ icColorSpaceSignature ins, outs; /* Colorspace of conversion */
+ int id, od; /* Dimensions of conversion */
+
+ /* Valid only for icc: */
+ icmHeader *h;
+ icRenderingIntent intent; /* Rendering intent chosen */
+ icmLookupFunc func; /* Type of function to use in lookup */
+ icmLookupOrder order; /* tag search order to use */
+ icmLuAlgType alg; /* Type of lookup algorithm used */
+ int clutres; /* If this profile uses a clut, what's it's res. ? */
+ icColorSpaceSignature natpcs; /* Underlying natural PCS */
+ icmLuBase *luo; /* Base Lookup type object */
+
+}; typedef struct _profinfo profinfo;
+
+/* Context for imdi setup callbacks */
+typedef struct {
+ /* Overall parameters */
+ int verb; /* Non-zero if verbose */
+ icColorSpaceSignature ins, outs; /* Input/Output spaces */
+ int iinv, oinv; /* Space inversion */
+ int id, od, md; /* Input/Output dimensions and max(id,od) */
+ int width, height; /* Width and heigh of raster */
+ int isign_mask; /* Input sign mask */
+ int osign_mask; /* Output sign mask */
+ int icombine; /* Non-zero if input curves are to be combined */
+ int ocombine; /* Non-zero if output curves are to be combined */
+ int ilcurve; /* 1 if input curves are to be concatenated with Y like ->L* curve */
+ /* (2 if input curves are to be concatenated with Y->L* curve) */
+ int olcurve; /* 1 if output curves are to be concatenated with L*->Y like curve */
+ /* (2 if output curves are to be concatenated with L*->Y curve) */
+ void (*icvt)(double *out, double *in); /* If non-NULL, Input format conversion */
+ void (*ocvt)(double *out, double *in); /* If non-NULL, Output format conversion */
+
+ int nprofs; /* Number of profiles in the sequence */
+ int first, last; /* index of first and last profiles/cals, 0 and nprofs-1 */
+ int fclut, lclut; /* first and last profiles/cals that are part of multi-d table */
+ profinfo *profs; /* Profile information */
+} sucntx;
+
+
+/* Input curve function */
+static void input_curves(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ int i;
+ sucntx *rx = (sucntx *)cntx;
+
+//printf("~1 incurve in %f %f %f %f\n",in_vals[0],in_vals[1],in_vals[2],in_vals[3]);
+
+ for (i = 0; i < rx->id; i++)
+ out_vals[i] = in_vals[i]; /* Default to nothing */
+
+ if (rx->icombine == 0) { /* Not combined into multi-d table */
+
+ /* TIFF input format conversion */
+ if (rx->icvt != NULL) { /* (Never used because PCS < 0.0 > 1.0) */
+ rx->icvt(out_vals, out_vals);
+ }
+
+ /* Any concatinated input calibrations */
+ for (i = rx->first; i < rx->fclut; i++) {
+ if (rx->profs[i].func == icmFwd)
+ rx->profs[i].cal->interp(rx->profs[i].cal, out_vals, out_vals);
+ else
+ rx->profs[i].cal->inv_interp(rx->profs[i].cal, out_vals, out_vals);
+ }
+
+ /* The input table of the first profile */
+ /* (icombine is set if input is PCS) */
+ if (rx->fclut <= rx->lclut)
+ rx->profs[rx->fclut].luo->lookup_in(rx->profs[rx->fclut].luo, out_vals, out_vals);
+ }
+
+ /* If input curve converts to Y like space, apply Y->L* curve */
+ /* so as to index CLUT perceptually. */
+ if (rx->ilcurve != 0) {
+ y2l_curve(out_vals, out_vals, rx->ilcurve == 2);
+ }
+//printf("~1 incurve out %f %f %f %f\n",out_vals[0],out_vals[1],out_vals[2],out_vals[3]);
+}
+
+/* Multi-dim table function */
+static void md_table(
+void *cntx,
+double *out_vals,
+double *in_vals
+) {
+ sucntx *rx = (sucntx *)cntx;
+ double vals[MAX_CHAN];
+ icColorSpaceSignature prs; /* Previous colorspace */
+ int i, j;
+
+ for (i = 0; i < rx->id; i++)
+ vals[i] = in_vals[i]; /* default is do nothing */
+
+//printf("~1 md_table in %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+
+ if (rx->ilcurve) {
+ /* Apply L*->Y curve to compensate for curve applied after input curve */
+ l2y_curve(vals, vals, rx->ilcurve == 2);
+ }
+
+ prs = rx->ins;
+
+ /* If the input curves are being combined into clut: */
+ if (rx->icombine != 0) {
+
+ /* Any needed TIFF file format conversion */
+ if (rx->icvt != NULL) {
+ rx->icvt(vals, vals);
+//printf("~1 md_table after icvt %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ }
+
+ /* Any concatinated input calibrations */
+ for (j = rx->first; j < rx->fclut; j++) {
+ if (rx->profs[j].func == icmFwd)
+ rx->profs[j].cal->interp(rx->profs[j].cal, vals, vals);
+ else
+ rx->profs[j].cal->inv_interp(rx->profs[j].cal, vals, vals);
+ }
+//printf("~1 md_table after in cals %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ }
+
+ /* Do all the profile links in-between (if any) */
+ for (j = rx->fclut; j <= rx->lclut; j++) {
+
+ /* If it's a calibration */
+ if (rx->profs[j].cal != NULL) {
+ if (rx->profs[j].func == icmFwd)
+ rx->profs[j].cal->interp(rx->profs[j].cal, vals, vals);
+ else
+ rx->profs[j].cal->inv_interp(rx->profs[j].cal, vals, vals);
+
+ /* Else it's a profile */
+ } else {
+ /* Convert PCS for this profile */
+ if (prs == icSigXYZData && rx->profs[j].ins == icSigLabData) {
+ icmXYZ2Lab(&icmD50, vals, vals);
+//printf("~1 md_table after XYZ2Lab %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ } else if (prs == icSigLabData && rx->profs[j].ins == icSigXYZData) {
+ icmLab2XYZ(&icmD50, vals, vals);
+//printf("~1 md_table after Lab2XYZ %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ }
+
+ /* If first or last profile */
+ if (j == rx->fclut || j == rx->lclut) {
+ if (j != rx->fclut || rx->icombine) {
+ rx->profs[j].luo->lookup_in(rx->profs[j].luo, vals, vals);
+//printf("~1 md_table after input curve %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ }
+ rx->profs[j].luo->lookup_core(rx->profs[j].luo, vals, vals);
+//printf("~1 md_table after core %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ if (j != rx->lclut || rx->ocombine) {
+ rx->profs[j].luo->lookup_out(rx->profs[j].luo, vals, vals);
+ }
+//printf("~1 md_table after output curve %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ /* Middle of chain */
+ } else {
+ rx->profs[j].luo->lookup(rx->profs[j].luo, vals, vals);
+//printf("~1 md_table after middle %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ }
+ }
+ prs = rx->profs[j].outs;
+ }
+
+ /* convert last PCS to rx->outs PCS if needed */
+ if (prs == icSigXYZData
+ && rx->outs == icSigLabData) {
+ icmXYZ2Lab(&icmD50, vals, vals);
+//printf("~1 md_table after out XYZ2Lab %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ } else if (prs == icSigLabData
+ && rx->outs == icSigXYZData) {
+ icmLab2XYZ(&icmD50, vals, vals);
+//printf("~1 md_table after out Lab2XYZ %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ }
+
+ /* If the output curves are being combined into clut: */
+ if (rx->ocombine != 0) {
+
+ /* Any concatinated output calibrations */
+ for (j = rx->lclut+1; j <= rx->last; j++) {
+ if (rx->profs[j].func == icmFwd)
+ rx->profs[j].cal->interp(rx->profs[j].cal, vals, vals);
+ else
+ rx->profs[j].cal->inv_interp(rx->profs[j].cal, vals, vals);
+ }
+//printf("~1 md_table after out cals %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+
+ /* Any needed TIFF file format conversion */
+ if (rx->ocvt != NULL) {
+ rx->ocvt(vals, vals);
+//printf("~1 md_table after out ocvt %f %f %f %f\n",vals[0],vals[1],vals[2],vals[3]);
+ }
+
+ }
+
+ if (rx->olcurve) {
+ /* Add Y->L* curve to cause interpolation in perceptual space */
+ y2l_curve(vals, vals, rx->olcurve == 2);
+ }
+
+ for (i = 0; i < rx->od; i++)
+ out_vals[i] = vals[i];
+//printf("~1 md_table returns %f %f %f %f\n",out_vals[0],out_vals[1],out_vals[2],out_vals[3]);
+}
+
+/* Output curve function */
+static void output_curves(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ sucntx *rx = (sucntx *)cntx;
+ int i;
+
+//printf("~1 outurve in %f %f %f %f\n",in_vals[0],in_vals[1],in_vals[2],in_vals[3]);
+ for (i = 0; i < rx->od; i++)
+ out_vals[i] = in_vals[i];
+
+ /* Apply L* -> Y curve to undo curve applied at CLUT output. */
+ if (rx->olcurve != 0) {
+ l2y_curve(out_vals, out_vals, rx->olcurve == 2);
+ }
+
+ if (rx->ocombine == 0) { /* Not combined into multi-d table */
+
+ /* The output table of the last profile */
+ /* (ocombine is set if output is PCS) */
+ if (rx->fclut <= rx->lclut) {
+ rx->profs[rx->lclut].luo->lookup_out(rx->profs[rx->lclut].luo, out_vals, out_vals);
+//printf("~1 md_table after out curve %f %f %f %f\n",out_vals[0],out_vals[1],out_vals[2],out_vals[3]);
+ }
+
+ /* Any concatinated output calibrations */
+ for (i = rx->lclut+1; i <= rx->last; i++) {
+ if (rx->profs[i].func == icmFwd)
+ rx->profs[i].cal->interp(rx->profs[i].cal, out_vals, out_vals);
+ else
+ rx->profs[i].cal->inv_interp(rx->profs[i].cal, out_vals, out_vals);
+ }
+
+ /* Any needed file format conversion */
+ if (rx->ocvt != NULL) { /* (Never used because PCS < 0.0 > 1.0) */
+ rx->ocvt(out_vals, out_vals);
+//printf("~1 md_table after out ocvt %f %f %f %f\n",out_vals[0],out_vals[1],out_vals[2],out_vals[3]);
+ }
+ }
+//printf("~1 outurve out %f %f %f %f\n",out_vals[0],out_vals[1],out_vals[2],out_vals[3]);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+/* Check whether two colorspaces appear compatible */
+/* return NZ if they match, Z if they don't. */
+/* Compatible means any PCS == any PCS, or exact match */
+int CSMatch(icColorSpaceSignature s1, icColorSpaceSignature s2) {
+ if (s1 == s2)
+ return 1;
+
+ if ((s1 == icSigXYZData || s1 == icSigLabData)
+ && (s2 == icSigXYZData || s2 == icSigLabData))
+ return 1;
+
+ if ((s1 == icSig5colorData || s1 == icSigMch5Data)
+ && (s2 == icSig5colorData || s2 == icSigMch5Data))
+ return 1;
+
+ if ((s1 == icSig6colorData || s1 == icSigMch6Data)
+ && (s2 == icSig6colorData || s2 == icSigMch6Data))
+ return 1;
+
+ if ((s1 == icSig7colorData || s1 == icSigMch7Data)
+ && (s2 == icSig7colorData || s2 == icSigMch7Data))
+ return 1;
+
+ if ((s1 == icSig8colorData || s1 == icSigMch8Data)
+ && (s2 == icSig8colorData || s2 == icSigMch8Data))
+ return 1;
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* JPEG error information */
+typedef struct {
+ jmp_buf env; /* setjmp/longjmp environment */
+ char message[JMSG_LENGTH_MAX];
+} jpegerrorinfo;
+
+/* JPEG error handler */
+static void jpeg_error(j_common_ptr cinfo) {
+ jpegerrorinfo *p = (jpegerrorinfo *)cinfo->client_data;
+ (*cinfo->err->format_message) (cinfo, p->message);
+ longjmp(p->env, 1);
+}
+
+static char *
+JPEG_cspace2str(
+J_COLOR_SPACE cspace
+) {
+ static char buf[80];
+ switch (cspace) {
+ case JCS_UNKNOWN:
+ return "Unknown";
+ case JCS_GRAYSCALE:
+ return "Monochrome";
+ case JCS_RGB:
+ return "RGB";
+ case JCS_YCbCr:
+ return "YCbCr";
+ case JCS_CMYK:
+ return "CMYK";
+ case JCS_YCCK:
+ return "YCCK";
+ }
+ sprintf(buf,"Unknown JPEG colorspace %d",cspace);
+ return buf;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+int
+main(int argc, char *argv[]) {
+ int fa, nfa; /* argument we're looking at */
+ char in_name[MAXNAMEL+1] = ""; /* Input raster file name */
+ char out_name[MAXNAMEL+1] = ""; /* Output raster file name */
+ char dst_pname[MAXNAMEL+1] = ""; /* Destination embedded profile file name */
+ icc *deicc = NULL; /* Destination embedded profile (if any) */
+ icRenderingIntent next_intent; /* Rendering intent for next profile */
+ icmLookupOrder next_order; /* tag search order for next profile */
+ icmLookupFunc next_func; /* Direction for next calibration */
+ int last_dim; /* Next dimentionality between conversions */
+ icColorSpaceSignature last_colorspace; /* Next colorspace between conversions */
+ char *last_cs_file; /* Name of the file the last colorspace came from */
+ int dojpg = -1; /* 0 = tiff, 1 = jpg, -1 = same as input */
+ int jpgq = -1; /* Jpeg quality, default DEFJPGQ */
+ int doimdi = 1; /* Use the fast overall integer conversion */
+ int dofloat = 0; /* Use the slow precice (float). */
+ int check = 0; /* Check fast (int) against slow (float) */
+ int ochoice = 0; /* Output encoding choice 1..n */
+ int alpha = 0; /* Use alpha for extra planes */
+ int ignoremm = 0; /* Ignore any colorspace mismatches */
+ int nodesc = 0; /* Don't append or set the description */
+ int i, j, rv = 0;
+
+ /* TIFF file info */
+ TIFFErrorHandler olderrh, oldwarnh;
+ TIFFErrorHandlerExt olderrhx, oldwarnhx;
+ TIFF *rh = NULL, *wh = NULL;
+
+ int x, y, width, height; /* Common size of image */
+ uint16 bitspersample; /* Bits per sample */
+ uint16 resunits;
+ float resx, resy;
+ uint16 pconfig; /* Planar configuration */
+
+ uint16 rsamplesperpixel, wsamplesperpixel; /* Channels per sample */
+ uint16 rphotometric, wphotometric; /* Photometrics */
+ uint16 rextrasamples, wextrasamples; /* Extra "alpha" samples */
+ uint16 *rextrainfo, wextrainfo[MAX_CHAN]; /* Info about extra samples */
+ char *rdesc = NULL; /* Existing description */
+ char *ddesc = "[ Color corrected by ArgyllCMS ]"; /* Default description */
+ char *wdesc = NULL; /* Written desciption */
+
+ tdata_t *inbuf = NULL, *outbuf = NULL, *hprecbuf = NULL;
+ int inbpix, outbpix; /* Number of pixels in jpeg in/out buf */
+
+ /* JPEG file info */
+ jpegerrorinfo jpeg_rerr, jpeg_werr;
+ FILE *rf = NULL, *wf = NULL;
+ struct jpeg_decompress_struct rj;
+ struct jpeg_compress_struct wj;
+ struct jpeg_error_mgr jerr;
+
+ /* IMDI */
+ imdi *s = NULL;
+ sucntx su; /* Setup context */
+ unsigned char *inp[MAX_CHAN];
+ unsigned char *outp[MAX_CHAN];
+ int clutres = 0; /* Default */
+
+ /* Error check */
+ int mxerr = 0;
+ double avgerr = 0.0;
+ double avgcount = 0.0;
+
+ error_program = "cctiff";
+ if (argc < 2)
+ usage("Too few arguments");
+
+ /* Set defaults */
+ memset((void *)&su, 0, sizeof(sucntx));
+ next_intent = icmDefaultIntent;
+ next_func = icmFwd;
+ next_order = icmLuOrdNorm;
+
+ /* JPEG */
+ jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ /* Slow, Precise, not integer */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ doimdi = 0;
+ dofloat = 1;
+ }
+
+ /* Combine per channel curves */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ su.icombine = 1;
+ su.ocombine = 1;
+ }
+
+ /* Check curves */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ doimdi = 1;
+ dofloat = 1;
+ check = 1;
+ }
+
+ /* Use alpha planes for any over 4 */
+ else if (argv[fa][1] == 'a' || argv[fa][1] == 'A') {
+ alpha = 1;
+ }
+
+ /* CLUT resolution */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -r flag");
+ clutres = atoi(na);
+ if (clutres < 2)
+ usage("-r argument must be >= 2");
+ }
+
+ /* Output file encoding choice */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -t flag");
+ ochoice = atoi(na);
+ }
+
+ /* Output file format override */
+ else if (argv[fa][1] == 'f') {
+ fa = nfa;
+ if (na == NULL) usage("Missing argument to -f flag");
+ switch (na[0]) {
+ case 't':
+ case 'T':
+ dojpg = 0;
+ break;
+ case 'j':
+ case 'J':
+ dojpg = 1;
+ break;
+ default:
+ usage("Unknown argument '%c' to -f flag",na[0]);
+ }
+ }
+
+ /* JPEG quality */
+ else if (argv[fa][1] == 'q') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -q flag");
+ jpgq = atoi(na);
+ if (jpgq < 1 || jpgq > 100)
+ usage("-q argument must 1..100");
+ }
+
+ /* Destination TIFF embedded profile */
+ else if (argv[fa][1] == 'e' || argv[fa][1] == 'E') {
+ fa = nfa;
+ if (na == NULL) usage("Expect profile name argument to -e flag");
+ strncpy(dst_pname,na, MAXNAMEL); dst_pname[MAXNAMEL] = '\000';
+ }
+
+ /* Next profile Intent */
+ else if (argv[fa][1] == 'i') {
+ fa = nfa;
+ if (na == NULL) usage("Missing argument to -i flag");
+ switch (na[0]) {
+ case 'p':
+ case 'P':
+ next_intent = icPerceptual;
+ break;
+ case 'r':
+ case 'R':
+ next_intent = icRelativeColorimetric;
+ break;
+ case 's':
+ case 'S':
+ next_intent = icSaturation;
+ break;
+ case 'a':
+ case 'A':
+ next_intent = icAbsoluteColorimetric;
+ break;
+ default:
+ usage("Unknown argument '%c' to -i flag",na[0]);
+ }
+ }
+
+ /* Next profile search order */
+ else if (argv[fa][1] == 'o') {
+ fa = nfa;
+ if (na == NULL) usage("Missing argument to -o flag");
+ switch (na[0]) {
+ case 'n':
+ case 'N':
+ next_order = icmLuOrdNorm;
+ break;
+ case 'r':
+ case 'R':
+ next_order = icmLuOrdRev;
+ break;
+ default:
+ usage("Unknown argument '%c' to -o flag",na[0]);
+ }
+ }
+
+ /* Next calibraton direction */
+ else if (argv[fa][1] == 'd') {
+ fa = nfa;
+ if (na == NULL) usage("Missing argument to -i flag");
+ switch (na[0]) {
+ case 'f':
+ case 'F':
+ next_func = icmFwd;
+ break;
+ case 'b':
+ case 'B':
+ next_func = icmBwd;
+ break;
+ default:
+ usage("Unknown argument '%c' to -d flag",na[0]);
+ }
+ }
+
+ else if (argv[fa][1] == 'I')
+ ignoremm = 1;
+
+ else if (argv[fa][1] == 'D')
+ nodesc = 1;
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ su.verb = 1;
+ }
+
+ else {
+ usage("Unknown flag '%c'",argv[fa][1]);
+ }
+
+ } else if (argv[fa][0] != '\000') {
+ /* Get the next filename */
+
+ if (su.nprofs == 0)
+ su.profs = (profinfo *)malloc(sizeof(profinfo));
+ else
+ su.profs = (profinfo *)realloc(su.profs, (su.nprofs+1) * sizeof(profinfo));
+ if (su.profs == NULL)
+ error("Malloc failed in allocating space for profile info.");
+
+ memset((void *)&su.profs[su.nprofs], 0, sizeof(profinfo));
+ strncpy(su.profs[su.nprofs].name,argv[fa],MAXNAMEL);
+ su.profs[su.nprofs].name[MAXNAMEL] = '\000';
+ su.profs[su.nprofs].intent = next_intent;
+ su.profs[su.nprofs].func = next_func;
+ su.profs[su.nprofs].order = next_order;
+
+ su.nprofs++;
+ next_intent = icmDefaultIntent;
+ next_func = icmFwd;
+ next_order = icmLuOrdNorm;
+ } else {
+ break;
+ }
+ }
+
+ /* The last two "profiles" are actually the input and output TIFF filenames */
+ /* Unwind them */
+ if (su.nprofs < 2)
+ usage("Not enough arguments to specify input and output TIFF files");
+
+ strncpy(out_name,su.profs[--su.nprofs].name, MAXNAMEL); out_name[MAXNAMEL] = '\000';
+ strncpy(in_name,su.profs[--su.nprofs].name, MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ su.fclut = su.first = 0;
+ su.lclut = su.last = su.nprofs-1;
+
+ if (check && (!doimdi || !dofloat))
+ error("Can't do check unless both integera and float processing are enabled");
+
+/*
+
+ Logic required:
+
+ Discover input TIFF colorspace and set as (ICC) "next_space"
+ Set any special input space encoding transform (ie. device, Lab flavour)
+
+ For each profile:
+
+ case abstract:
+ set dir = fwd, intent = default
+ check next_space == CIE
+ next_space = CIE
+
+ case dev link:
+ set dir = fwd, intent = default
+ check next_space == profile.in_devspace
+ next_space = profile.out_devspace
+
+ case cal file:
+ check next_space == cal.devspace
+ next_space = cal.devspace
+
+ case colorspace/input/display/output:
+ if colorspace
+ set intent = default
+
+ if next_space == CIE
+ set dir = fwd
+ next_space = profile.devspace
+ else
+ set dir = bwd
+ check next_space == profile.devspace
+ next_space = CIE
+
+ create luo
+
+ Make output TIFF colorspace match next_space
+
+ Figure out how many calibrations can be concatinated into the input
+ and output curves.
+
+ Set any special output space encoding transform (ie. device, Lab flavour)
+
+*/
+ /* - - - - - - - - - - - - - - - */
+ /* Open up input tiff file ready for reading */
+ /* Discover input TIFF colorspace and set as (ICC) "last_colorspace" */
+ /* Set any special input space encoding transform (ie. device, Lab flavour) */
+
+ /* Supress TIFF messages */
+ olderrh = TIFFSetErrorHandler(NULL);
+ oldwarnh = TIFFSetWarningHandler(NULL);
+ olderrhx = TIFFSetErrorHandlerExt(NULL);
+ oldwarnhx = TIFFSetWarningHandlerExt(NULL);
+
+ if ((rh = TIFFOpen(in_name, "r")) != NULL) {
+
+ TIFFSetErrorHandler(olderrh);
+ TIFFSetWarningHandler(oldwarnh);
+ TIFFSetErrorHandlerExt(olderrhx);
+ TIFFSetWarningHandlerExt(oldwarnhx);
+
+ TIFFGetField(rh, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);
+
+ TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8 && bitspersample != 16) {
+ error("TIFF Input file must be 8 or 16 bits/channel");
+ }
+
+ TIFFGetFieldDefaulted(rh, TIFFTAG_EXTRASAMPLES, &rextrasamples, &rextrainfo);
+// if (rextrasamples > 0 && alpha == 0)
+// error("TIFF Input file has extra samples per pixel - cctiff can't handle that");
+
+ TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &rphotometric);
+ TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &rsamplesperpixel);
+
+ /* Figure out how to handle the input TIFF colorspace */
+ if ((su.ins = TiffPhotometric2ColorSpaceSignature(NULL, &su.icvt, &su.isign_mask, rphotometric,
+ bitspersample, rsamplesperpixel, rextrasamples)) == 0)
+ error("Can't handle TIFF file photometric %s", Photometric2str(rphotometric));
+ su.iinv = 0;
+ su.id = rsamplesperpixel;
+
+ TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
+ if (pconfig != PLANARCONFIG_CONTIG)
+ error ("TIFF Input file must be planar");
+
+ TIFFGetField(rh, TIFFTAG_RESOLUTIONUNIT, &resunits);
+ TIFFGetField(rh, TIFFTAG_XRESOLUTION, &resx);
+ TIFFGetField(rh, TIFFTAG_YRESOLUTION, &resy);
+
+ last_dim = su.id;
+ last_colorspace = su.ins;
+ last_cs_file = in_name;
+
+ su.width = width;
+ su.height = height;
+
+ if (TIFFGetField(rh, TIFFTAG_IMAGEDESCRIPTION, &rdesc) != 0) {
+ if ((rdesc = strdup(rdesc)) == NULL)
+ error("Malloc of input file description string failed");
+ } else
+ rdesc = NULL;
+
+ if (dojpg < 0)
+ dojpg = 0;
+
+ /* See if it is a JPEG File */
+ } else {
+ jpeg_saved_marker_ptr mlp;
+
+ TIFFSetErrorHandler(olderrh);
+ TIFFSetWarningHandler(oldwarnh);
+ TIFFSetErrorHandlerExt(olderrhx);
+ TIFFSetWarningHandlerExt(oldwarnhx);
+
+//printf("~1 TIFFOpen failed on '%s'\n",in_name);
+
+ /* We cope with the horrible ijg jpeg library error handling */
+ /* by using a setjmp/longjmp. */
+ if (setjmp(jpeg_rerr.env)) {
+ /* Something went wrong with opening the file */
+ jpeg_destroy_decompress(&rj);
+ error("error opening read file '%s' [%s]",in_name,jpeg_rerr.message);
+ }
+
+ rj.err = &jerr;
+ rj.client_data = &jpeg_rerr;
+ jpeg_create_decompress(&rj);
+
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((rf = fopen(in_name,"rb")) == NULL)
+#else
+ if ((rf = fopen(in_name,"r")) == NULL)
+#endif
+ {
+ jpeg_destroy_decompress(&rj);
+ error("error opening read file '%s'",in_name);
+ }
+
+ jpeg_stdio_src(&rj, rf);
+ jpeg_save_markers(&rj, JPEG_COM, 0xFFFF);
+
+ /* we'll longjmp on error */
+ jpeg_read_header(&rj, TRUE);
+
+ bitspersample = rj.data_precision;
+ if (bitspersample != 8 && bitspersample != 16) {
+ error("JPEG Input file must be 8 or 16 bit/channel");
+ }
+
+ /* No extra samples */
+ rextrasamples = 0;
+ su.iinv = 0;
+
+ switch (rj.jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ rj.out_color_space = JCS_GRAYSCALE;
+ su.ins = icSigGrayData;
+ su.id = 1;
+ break;
+
+ case JCS_YCbCr: /* get libjpg to convert to RGB */
+ rj.out_color_space = JCS_RGB;
+ su.ins = icSigRgbData;
+ su.id = 3;
+ if (ochoice == 0)
+ ochoice = 1;
+ break;
+
+ case JCS_RGB:
+ rj.out_color_space = JCS_RGB;
+ su.ins = icSigRgbData;
+ su.id = 3;
+ if (ochoice == 0)
+ ochoice = 2;
+ break;
+
+ case JCS_YCCK: /* libjpg to convert to CMYK */
+ rj.out_color_space = JCS_CMYK;
+ su.ins = icSigCmykData;
+ su.id = 4;
+ if (rj.saw_Adobe_marker)
+ su.iinv = 1;
+ if (ochoice == 0)
+ ochoice = 1;
+ break;
+
+ case JCS_CMYK:
+ rj.out_color_space = JCS_CMYK;
+ su.ins = icSigCmykData;
+ su.id = 4;
+ if (rj.saw_Adobe_marker) /* Adobe inverts CMYK */
+ su.iinv = 1;
+ if (ochoice == 0)
+ ochoice = 2;
+ break;
+
+ default:
+ error("Can't handle JPEG file colorspace 0x%x", rj.jpeg_color_space);
+ }
+
+ if (rj.density_unit == 1)
+ resunits = RESUNIT_INCH;
+ else if (rj.density_unit == 2)
+ resunits = RESUNIT_CENTIMETER;
+ else
+ resunits = RESUNIT_NONE;
+ resx = rj.X_density;
+ resy = rj.Y_density;
+
+ last_dim = su.id;
+ last_colorspace = su.ins;
+ last_cs_file = in_name;
+
+ jpeg_calc_output_dimensions(&rj);
+ su.width = width = rj.output_width;
+ su.height = height = rj.output_height;
+
+ /* Locate any comment */
+ rdesc = NULL;
+ for (mlp = rj.marker_list; mlp != NULL; mlp = mlp->next) {
+ if (mlp->marker == JPEG_COM && mlp->data_length > 0) {
+ if ((rdesc = malloc(mlp->data_length+1)) == NULL)
+ error("Malloc of input file description string failed");
+ memcpy(rdesc, mlp->data, mlp->data_length-1);
+ rdesc[mlp->data_length] = '\000';
+ break;
+ }
+ }
+
+ if (dojpg < 0)
+ dojpg = 1;
+
+ /* ~~ Should determine deafult jpgq from tables of this file */
+
+ jpeg_start_decompress(&rj);
+ }
+
+
+ /* - - - - - - - - - - - - - - - */
+ /* Check and setup the sequence of ICC profiles */
+
+ /* For each profile in the sequence, configure it to transform the color */
+ /* appropriately */
+ for (i = su.first; i <= su.last; i++) {
+
+ /* First see if it's a calibration file */
+ if ((su.profs[i].cal = new_xcal()) == NULL)
+ error("new_xcal failed");
+
+ if ((su.profs[i].cal->read(su.profs[i].cal, su.profs[i].name)) == 0) {
+
+ su.profs[i].ins = su.profs[i].outs = icx_colorant_comb_to_icc(su.profs[i].cal->devmask);
+ if (su.profs[i].outs == 0)
+ error ("Calibration file '%s' has unhandled device mask %s",su.profs[i].name,icx_inkmask2char(su.profs[i].cal->devmask,1));
+ su.profs[i].id = su.profs[i].od = su.profs[i].cal->devchan;
+ /* We use the user provided direction */
+
+ /* else see if it's an ICC or embedded ICC */
+ } else {
+
+ su.profs[i].cal->del(su.profs[i].cal); /* Clean up */
+ su.profs[i].cal = NULL;
+
+ if ((su.profs[i].c = read_embedded_icc(su.profs[i].name)) == NULL)
+ error ("Can't read profile or calibration from file '%s'",su.profs[i].name);
+
+ su.profs[i].h = su.profs[i].c->header;
+
+ /* Deal with different profile classes, */
+ /* and set the profile function and intent. */
+ switch (su.profs[i].h->deviceClass) {
+ case icSigAbstractClass:
+ case icSigLinkClass:
+ su.profs[i].func = icmFwd;
+ su.profs[i].intent = icmDefaultIntent;
+ break;
+
+ case icSigColorSpaceClass:
+ su.profs[i].func = icmFwd;
+ su.profs[i].intent = icmDefaultIntent;
+ /* Fall through */
+
+ case icSigInputClass:
+ case icSigDisplayClass:
+ case icSigOutputClass:
+ /* Note we don't handle an ambigious (both directions match) case. */
+ /* We would need direction from the user to resolve this. */
+ if (CSMatch(last_colorspace, su.profs[i].h->colorSpace)) {
+ su.profs[i].func = icmFwd;
+ } else {
+ su.profs[i].func = icmBwd; /* PCS -> Device */
+ }
+ break;
+ /* Use the user provided intent */
+
+ default:
+ error("Can't handle deviceClass %s from file '%s'",
+ icm2str(icmProfileClassSignature,su.profs[i].h->deviceClass),
+ su.profs[i].c->err,su.profs[i].name);
+ }
+
+ /* Get a conversion object */
+ if ((su.profs[i].luo = su.profs[i].c->get_luobj(su.profs[i].c, su.profs[i].func,
+ su.profs[i].intent, icmSigDefaultData, su.profs[i].order)) == NULL)
+ error ("%d, %s from '%s'",su.profs[i].c->errc, su.profs[i].c->err, su.profs[i].name);
+
+ /* Get details of conversion */
+ su.profs[i].luo->spaces(su.profs[i].luo, &su.profs[i].ins, &su.profs[i].id,
+ &su.profs[i].outs, &su.profs[i].od, &su.profs[i].alg, NULL, NULL, NULL, NULL);
+
+ /* Get native PCS space */
+ su.profs[i].luo->lutspaces(su.profs[i].luo, NULL, NULL, NULL, NULL, &su.profs[i].natpcs);
+
+ /* If this is a lut transform, find out its resolution */
+ if (su.profs[i].alg == icmLutType) {
+ icmLut *lut;
+ icmLuLut *luluo = (icmLuLut *)su.profs[i].luo; /* Safe to coerce */
+ luluo->get_info(luluo, &lut, NULL, NULL, NULL); /* Get some details */
+ su.profs[i].clutres = lut->clutPoints; /* Desired table resolution */
+ } else
+ su.profs[i].clutres = 0;
+
+ }
+
+ /* Check that we can join to previous correctly */
+ if (!ignoremm && !CSMatch(last_colorspace, su.profs[i].ins))
+ error("Last colorspace %s from file '%s' doesn't match input space %s of profile %s",
+ icm2str(icmColorSpaceSignature,last_colorspace),
+ last_cs_file,
+ icm2str(icmColorSpaceSignature,su.profs[i].h->colorSpace),
+ su.profs[i].name);
+
+ last_dim = icmCSSig2nchan(su.profs[i].outs);
+ last_colorspace = su.profs[i].outs;
+ last_cs_file = su.profs[i].name;
+ }
+
+ su.od = last_dim;
+ su.oinv = 0;
+ su.outs = last_colorspace;
+
+ /* Go though the sequence again, and count the number of leading and */
+ /* trailing calibrations that can be combined into the input and output */
+ /* lookup curves */
+ for (i = su.first; ; i++) {
+ if (i > su.last || su.profs[i].c != NULL) {
+ su.fclut = i;
+ break;
+ }
+ }
+ for (i = su.last; ; i--) {
+ if (i < su.first || su.profs[i].c != NULL) {
+ su.lclut = i;
+ break;
+ }
+ }
+
+ if (su.fclut > su.lclut) { /* Hmm. All calibs, no profiles */
+ su.fclut = su.first; /* None at start */
+ su.lclut = su.first-1; /* All at the end */
+ }
+
+//printf("~1 first = %d, fclut = %d, lclut = %d, last = %d\n", su.first, su.fclut, su.lclut, su.last);
+
+ su.md = su.id > su.od ? su.id : su.od;
+
+ /* - - - - - - - - - - - - - - - */
+ /* Create a TIFF file */
+ if (dojpg == 0) {
+ /* Open up the output TIFF file for writing */
+ if ((wh = TIFFOpen(out_name, "w")) == NULL)
+ error("Can\'t create TIFF file '%s'!",out_name);
+
+ wsamplesperpixel = su.od;
+
+ wextrasamples = 0;
+ if (alpha && wsamplesperpixel > 4) {
+ wextrasamples = wsamplesperpixel - 4; /* Call samples > 4 "alpha" samples */
+ for (j = 0; j < wextrasamples; j++)
+ wextrainfo[j] = EXTRASAMPLE_UNASSALPHA;
+ }
+
+ /* Configure the output TIFF file appropriately */
+ TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(wh, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, wsamplesperpixel);
+ TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, bitspersample);
+ TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+
+ TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ if (resunits) {
+ TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, resunits);
+ TIFFSetField(wh, TIFFTAG_XRESOLUTION, resx);
+ TIFFSetField(wh, TIFFTAG_YRESOLUTION, resy);
+ }
+ /* Perhaps the description could be more informative ? */
+ if (rdesc != NULL) {
+ if ((wdesc = malloc(sizeof(char) * (strlen(rdesc) + strlen(ddesc) + 2))) == NULL)
+ error("malloc failed on new desciption string");
+
+ strcpy(wdesc, rdesc);
+ if (nodesc == 0 && su.nprofs > 0) {
+ strcat(wdesc, " ");
+ strcat(wdesc, ddesc);
+ }
+ TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, wdesc);
+ } else if (nodesc == 0 && su.nprofs > 0) {
+ if ((wdesc = strdup(ddesc)) == NULL)
+ error("malloc failed on new desciption string");
+ TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, ddesc);
+ }
+
+ /* Lookup and decide what TIFF photometric suites the output colorspace */
+ {
+ int no_pmtc; /* Number of possible photometrics */
+ uint16 pmtc[10]; /* Photometrics of output file */
+ if ((no_pmtc = ColorSpaceSignature2TiffPhotometric(pmtc,
+ last_colorspace)) == 0)
+ error("TIFF file can't handle output colorspace '%s'!",
+ icm2str(icmColorSpaceSignature, last_colorspace));
+
+ if (no_pmtc > 1) { /* Need to choose a photometric */
+ if (ochoice < 1 || ochoice > no_pmtc ) {
+ printf("Possible Output Encodings for output colorspace %s are:\n",
+ icm2str(icmColorSpaceSignature,last_colorspace));
+ for (i = 0; i < no_pmtc; i++)
+ printf("%d: %s%s\n",i+1, Photometric2str(pmtc[i]), i == 0 ? " (Default)" : "");
+ ochoice = 1;
+ }
+ wphotometric = pmtc[ochoice-1];
+ } else {
+ wphotometric = pmtc[0];
+ }
+ }
+
+ /* Lookup what we need to handle this. */
+ if ((su.outs = TiffPhotometric2ColorSpaceSignature(&su.ocvt, NULL, &su.osign_mask, wphotometric,
+ bitspersample, wsamplesperpixel, wextrasamples)) == 0)
+ error("Can't handle TIFF file photometric %s", Photometric2str(wphotometric));
+ TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, wphotometric);
+
+ if (alpha && wextrasamples > 0) {
+ TIFFSetField(wh, TIFFTAG_EXTRASAMPLES, wextrasamples, wextrainfo);
+
+ } else {
+
+ if (wphotometric == PHOTOMETRIC_SEPARATED) {
+ icc *c = su.profs[su.lclut].c;
+ icmColorantTable *ct;
+ int iset;
+ int inlen;
+ char *inames = NULL;
+
+ if (c == NULL
+ || ((ct = (icmColorantTable *)c->read_tag(c, icSigColorantTableOutTag)) == NULL
+ && (ct = (icmColorantTable *)c->read_tag(c, icSigColorantTableTag)) == NULL)
+ || ct->count != wsamplesperpixel
+ ) {
+ iset = ColorSpaceSignature2TiffInkset(su.outs, &inlen, &inames);
+ } else {
+ int i;
+ char *cp;
+ inlen = 0;
+ for (i = 0; i < ct->count; i++)
+ inlen += strlen(ct->data[i].name) + 1;
+ inlen += 1;
+ if ((inames = malloc(inlen)) == NULL)
+ error("malloc failed on inknames string");
+ cp = inames;
+ for (i = 0; i < ct->count; i++) {
+ int slen = strlen(ct->data[i].name) + 1;
+ memcpy(cp, ct->data[i].name, slen);
+ cp += slen;
+ }
+ *cp = '\000';
+ iset = INKSET_MULTIINK;
+ }
+ if (iset != 0xffff && inlen > 0 && inames != NULL) {
+ TIFFSetField(wh, TIFFTAG_INKSET, iset);
+ if (inames != NULL) {
+ TIFFSetField(wh, TIFFTAG_INKNAMES, inlen, inames);
+ }
+ }
+ }
+ }
+
+ /* Create JPEG file */
+ } else {
+ jpeg_saved_marker_ptr mlp;
+ int jpeg_color_space;
+
+ /* We cope with the horrible ijg jpeg library error handling */
+ /* by using a setjmp/longjmp. */
+ if (setjmp(jpeg_werr.env)) {
+ /* Something went wrong with opening the file */
+ jpeg_destroy_compress(&wj);
+ error("Can\'t create JPEG file '%s'! [%s]",out_name, jpeg_werr.message);
+ }
+
+ wj.err = &jerr;
+ wj.client_data = &jpeg_werr;
+ jpeg_create_compress(&wj);
+
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((wf = fopen(out_name,"wb")) == NULL)
+#else
+ if ((wf = fopen(out_name,"w")) == NULL)
+#endif
+ {
+ jpeg_destroy_compress(&wj);
+ error("Can\'t create JPEG file '%s'!",out_name);
+ }
+
+ jpeg_stdio_dest(&wj, wf);
+
+ wj.image_width = width;
+ wj.image_height = height;
+ wj.input_components = su.od;
+
+ switch (last_colorspace) {
+ case icSigGrayData:
+ wj.in_color_space = JCS_GRAYSCALE;
+ jpeg_color_space = JCS_GRAYSCALE;
+ break;
+
+ case icSigRgbData:
+ wj.in_color_space = JCS_RGB;
+ if (ochoice < 0 || ochoice > 2) {
+ printf("Possible JPEG Output Encodings for output colorspace icSigRgbData are\n"
+ "1: YCbCr (Default)\n" "2: RGB\n");
+ ochoice = 1;
+ }
+ if (ochoice == 2)
+ jpeg_color_space = JCS_RGB;
+ else
+ jpeg_color_space = JCS_YCbCr;
+ break;
+
+ case icSigCmykData:
+ wj.in_color_space = JCS_CMYK;
+ if (ochoice < 0 || ochoice > 2) {
+ printf("Possible JPEG Output Encodings for output colorspace icSigCmykData are\n"
+ "1: YCCK (Default)\n" "2: CMYK\n");
+ ochoice = 1;
+ }
+ if (ochoice == 2)
+ jpeg_color_space = JCS_CMYK;
+ else
+ jpeg_color_space = JCS_YCCK;
+ break;
+
+ default:
+ error("JPEG file can't handle output colorspace '%s'!",
+ icm2str(icmColorSpaceSignature, last_colorspace));
+ }
+
+ if (resunits != RESUNIT_NONE) {
+ if (resunits == RESUNIT_INCH)
+ wj.density_unit = 1;
+ else if (resunits == RESUNIT_CENTIMETER)
+ wj.density_unit = 2;
+ wj.X_density = resx;
+ wj.Y_density = resy;
+ }
+
+ jpeg_set_defaults(&wj);
+ jpeg_set_colorspace(&wj, jpeg_color_space);
+
+ if (jpgq < 0)
+ jpgq = DEFJPGQ;
+ jpeg_set_quality(&wj, jpgq, TRUE);
+
+ /* The default sub-sampling sub-samples the CC and K of YCC & YCCK */
+ /* while not sub-sampling RGB or CMYK */
+
+ if (wj.write_Adobe_marker)
+ su.oinv = 1;
+
+ jpeg_start_compress(&wj, TRUE);
+
+ /* Perhaps the description could be more informative ? */
+ if (rdesc != NULL) {
+ if ((wdesc = malloc(sizeof(char) * (strlen(rdesc) + strlen(ddesc) + 2))) == NULL)
+ error("malloc failed on new desciption string");
+
+ strcpy(wdesc, rdesc);
+ if (nodesc == 0 && su.nprofs > 0) {
+ strcat(wdesc, " ");
+ strcat(wdesc, ddesc);
+ }
+ jpeg_write_marker(&wj, JPEG_COM, (const JOCTET *)wdesc, strlen(wdesc)+1);
+ } else if (nodesc == 0 && su.nprofs > 0) {
+ if ((wdesc = strdup(ddesc)) == NULL)
+ error("malloc failed on new desciption string");
+ jpeg_write_marker(&wj, JPEG_COM, (const JOCTET *)wdesc, strlen(wdesc)+1);
+ }
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Setup any destination embedded profile */
+ if (dst_pname[0] != '\000') {
+ icmFile *fp; /* Read fp for the profile */
+ unsigned char *buf;
+ int size;
+
+ if ((deicc = read_embedded_icc(dst_pname)) == NULL)
+ error("Unable to open profile for destination embedding '%s'",dst_pname);
+
+ /* Check that it is compatible with the destination raster file */
+ if (deicc->header->deviceClass != icSigColorSpaceClass
+ && deicc->header->deviceClass != icSigInputClass
+ && deicc->header->deviceClass != icSigDisplayClass
+ && deicc->header->deviceClass != icSigOutputClass) {
+ error("Destination embedded profile is wrong device class for embedding");
+ }
+
+ if (deicc->header->colorSpace != su.outs
+ || (deicc->header->pcs != icSigXYZData
+ && deicc->header->pcs != icSigLabData)) {
+ error("Destination embedded profile colorspaces don't match TIFF");
+ }
+
+ if ((fp = deicc->get_rfp(deicc)) == NULL)
+ error("Failed to be able to read destination embedded profile");
+
+ if ((size = fp->get_size(fp)) == 0)
+ error("Failed to be able to get size of destination embedded profile");
+
+ if ((buf = malloc(size)) == NULL)
+ error("malloc failed on destination embedded profile size %d",size);
+
+ if (fp->seek(fp,0))
+ error("rewind on destination embedded profile failed");
+
+ if (fp->read(fp, buf, 1, size) != size)
+ error("reading destination embedded profile failed");
+
+ /* (For iccv4 we would now fp->del(fp) because we got a reference) */
+
+ if (wh != NULL) {
+ if (TIFFSetField(wh, TIFFTAG_ICCPROFILE, size, buf) == 0)
+ error("setting TIFF embedded ICC profile field failed");
+ } else {
+ if (setjmp(jpeg_werr.env)) {
+ jpeg_destroy_compress(&wj);
+ error("setting JPEG embedded ICC profile marker failed");
+ }
+ write_icc_profile(&wj, buf, size);
+ }
+
+ free(buf);
+ deicc->del(deicc);
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ if ((su.fclut <= su.lclut
+ && (su.profs[su.fclut].natpcs == icSigXYZData) && (su.profs[su.fclut].alg == icmMatrixFwdType))
+ || su.profs[su.fclut].ins == icSigXYZData) {
+ su.ilcurve = 1; /* Index CLUT with L* curve rather than Y */
+ }
+
+ /* Setup input/output curve use. */
+ if (su.ins == icSigLabData || su.ins == icSigXYZData) {
+ su.icombine = 1; /* CIE can't be conveyed through 0..1 domain lookup */
+ }
+
+ if ((su.fclut <= su.lclut
+ && (su.profs[su.lclut].natpcs == icSigXYZData && su.profs[su.lclut].alg == icmMatrixBwdType))
+ || (su.profs[su.lclut].outs == icSigXYZData)) {
+ su.olcurve = 1; /* Interpolate in L* space rather than Y */
+ }
+
+ if (su.outs == icSigLabData || su.outs == icSigXYZData) {
+ su.ocombine = 1; /* CIE can't be conveyed through 0..1 domain lookup */
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Report the connection sequence details */
+
+ if (su.verb) {
+
+ if (rh) {
+ printf("Input raster file '%s' is TIFF\n",in_name);
+ printf("Input TIFF file photometric is %s\n",Photometric2str(rphotometric));
+ } else {
+ printf("Input raster file '%s' is JPEG\n",in_name);
+ printf("Input JPEG file original colorspace is %s\n",JPEG_cspace2str(rj.jpeg_color_space));
+ }
+ printf("Input raster file ICC colorspace is %s\n",icm2str(icmColorSpaceSignature,su.ins));
+ printf("Input raster file is %d x %d pixels\n",su.width, su.height);
+ if (rdesc != NULL)
+ printf("Input raster file description: '%s'\n",rdesc);
+ printf("\n");
+
+ printf("There are %d profiles/calibrations in the sequence:\n\n",su.nprofs);
+
+ for (i = su.first; i <= su.last; i++) {
+ if (su.profs[i].c != NULL) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ printf("Profile %d '%s':\n",i,su.profs[i].name);
+ su.profs[i].h->dump(su.profs[i].h, op, 1);
+ op->del(op);
+ printf("Direction = %s\n",icm2str(icmTransformLookupFunc, su.profs[i].func));
+ printf("Intent = %s\n",icm2str(icmRenderingIntent, su.profs[i].intent));
+ printf("Algorithm = %s\n",icm2str(icmLuAlg, su.profs[i].alg));
+ } else {
+ printf("Calibration %d '%s':\n",i,su.profs[i].name);
+ printf("Direction = %s\n",icm2str(icmTransformLookupFunc, su.profs[i].func));
+ if (su.profs[i].cal->xpi.deviceMfgDesc != NULL)
+ printf("Manufacturer: '%s'\n",su.profs[i].cal->xpi.deviceMfgDesc);
+ if (su.profs[i].cal->xpi.modelDesc != NULL)
+ printf("Model: '%s'\n",su.profs[i].cal->xpi.modelDesc);
+ if (su.profs[i].cal->xpi.profDesc != NULL)
+ printf("Description: '%s'\n",su.profs[i].cal->xpi.profDesc);
+ if (su.profs[i].cal->xpi.copyright != NULL)
+ printf("Copyright: '%s'\n",su.profs[i].cal->xpi.copyright);
+ }
+
+ if (i == 0 && su.icombine)
+ printf("Input curves being combined\n");
+ if (i == 0 && su.ilcurve)
+ printf("Input curves being post-converted to L*\n");
+ printf("Input space = %s\n",icm2str(icmColorSpaceSignature, su.profs[i].ins));
+ printf("Output space = %s\n",icm2str(icmColorSpaceSignature, su.profs[i].outs));
+ if (i == (su.last) && su.olcurve)
+ printf("Output curves being pre-converted from L*\n");
+ if (i == (su.last) && su.ocombine)
+ printf("Output curves being combined\n");
+ printf("\n");
+ }
+
+ if (wh != NULL) {
+ printf("Output TIFF file '%s'\n",out_name);
+ printf("Ouput raster file ICC colorspace is %s\n",icm2str(icmColorSpaceSignature,su.outs));
+ printf("Output TIFF file photometric is %s\n",Photometric2str(wphotometric));
+ } else {
+ printf("Output JPEG file '%s'\n",out_name);
+ printf("Ouput raster file ICC colorspace is %s\n",icm2str(icmColorSpaceSignature,su.outs));
+ printf("Output JPEG file colorspace is %s\n",JPEG_cspace2str(wj.jpeg_color_space));
+ if (wdesc != NULL)
+ printf("Output raster file description: '%s'\n",wdesc);
+ }
+ printf("\n");
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Setup the imdi */
+
+ if (check)
+ doimdi = dofloat = 1;
+
+ if (doimdi && su.nprofs > 0) {
+ int aclutres = 0; /* Automatically set res */
+ imdi_options opts = opts_none;
+
+ if (rextrasamples > 0) { /* We need to skip the alpha */
+ opts |= opts_istride;
+ }
+
+ /* Setup the imdi resolution */
+ /* Choose the resolution from the highest lut resolution in the sequence, */
+ /* or choose a default. */
+ for (i = su.first; i <= su.last; i++) {
+ if (su.profs[i].c != NULL
+ && su.profs[i].clutres > aclutres)
+ aclutres = su.profs[i].clutres;
+ }
+ if (aclutres == 0) {
+ aclutres = dim_to_clutres(su.id, 2); /* High quality */
+
+ } else if (aclutres < dim_to_clutres(su.id, 1)) { /* Worse than medium */
+ aclutres = dim_to_clutres(su.id, 1);
+ }
+
+ if (clutres == 0)
+ clutres = aclutres;
+
+ if (su.verb)
+ printf("Using CLUT resolution %d\n",clutres);
+
+ s = new_imdi(
+ su.id, /* Number of input dimensions */
+ su.od, /* Number of output dimensions */
+ /* Input pixel representation */
+ bitspersample == 8 ? pixint8 : pixint16,
+ /* Output pixel representation */
+ su.isign_mask, /* Treat appropriate channels as signed */
+ NULL, /* No raster to callback channel mapping */
+ prec_min, /* Minimum of input and output precision */
+ bitspersample == 8 ? pixint8 : pixint16,
+ su.osign_mask, /* Treat appropriate channels as signed */
+ NULL, /* No raster to callback channel mapping */
+ clutres, /* Desired table resolution */
+ oopts_none, /* Desired per channel output options */
+ NULL, /* Output channel check values */
+ opts, /* Desired processing direction and stride support */
+ input_curves, /* Callback functions */
+ md_table,
+ output_curves,
+ (void *)&su /* Context to callbacks */
+ );
+
+ if (s == NULL) {
+ #ifdef NEVER
+ printf("id = %d\n",su.id);
+ printf("od = %d\n",su.od);
+ printf("in bps = %d\n",bitspersample);
+ printf("out bps = %d\n",bitspersample);
+ printf("in signs = %d\n",su.isign_mask);
+ printf("out signs = %d\n",su.osign_mask);
+ printf("clutres = %d\n",clutres);
+ #endif
+ error("new_imdi failed");
+ }
+ }
+
+ if (rh != NULL)
+ inbuf = _TIFFmalloc(TIFFScanlineSize(rh));
+ else {
+ inbpix = rj.output_width * rj.num_components;
+ if ((inbuf = (tdata_t *)malloc(inbpix)) == NULL)
+ error("Malloc failed on input line buffer");
+ }
+
+ if (wh != NULL)
+ outbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+ else {
+ outbpix = wj.image_width * wj.input_components;
+ if ((outbuf = (tdata_t *)malloc(outbpix)) == NULL)
+ error("Malloc failed on output line buffer");
+ }
+
+ inp[0] = (unsigned char *)inbuf;
+ outp[0] = (unsigned char *)outbuf;
+
+ if (dofloat || su.nprofs == 0) {
+ if (wh != NULL)
+ hprecbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+ else {
+ if ((hprecbuf = (tdata_t *)malloc(outbpix)) == NULL)
+ error("Malloc failed on high precision line buffer");
+ }
+ }
+
+ if (rh == NULL) {
+ if (setjmp(jpeg_rerr.env)) {
+ /* Something went wrong with reading the file */
+ jpeg_destroy_decompress(&rj);
+ error("failed to read JPEG line [%s]",jpeg_rerr.message);
+ }
+ }
+
+ if (wh == NULL) {
+ if (setjmp(jpeg_werr.env)) {
+ /* Something went wrong with writing the file */
+ jpeg_destroy_compress(&wj);
+ error("failed to write JPEG line [%s]", jpeg_werr.message);
+ }
+ }
+
+
+ /* - - - - - - - - - - - - - - - */
+ /* Process colors to translate */
+ /* (Should fix this to process a group of lines at a time ?) */
+
+ for (y = 0; y < height; y++) {
+ tdata_t *obuf;
+
+ /* Read in the next line */
+ if (rh) {
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+ } else {
+ jpeg_read_scanlines(&rj, (JSAMPARRAY)&inbuf, 1);
+ if (su.iinv) {
+ unsigned char *cp, *ep = (unsigned char *)inbuf + inbpix;
+ for (cp = (unsigned char *)inbuf; cp < ep; cp++)
+ *cp = ~*cp;
+ }
+ }
+
+ if (doimdi && su.nprofs > 0) {
+ /* Do fast conversion */
+ s->interp(s, (void **)outp, 0, (void **)inp, su.id, width);
+ }
+
+ if (dofloat || su.nprofs == 0) {
+ /* Do floating point conversion into the hprecbuf[] */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+//printf("\n");
+ if (bitspersample == 8) {
+ for (i = 0; i < su.id; i++) {
+ int v = ((unsigned char *)inbuf)[x * su.id + i];
+//printf("~1 8 bit pixel value chan %d = %d\n",i,v);
+ if (su.isign_mask & (1 << i)) /* Treat input as signed */
+ v = (v & 0x80) ? v - 0x80 : v + 0x80;
+//printf("~1 8 bit after treat as signed chan %d = %d\n",i,v);
+ in[i] = v/255.0;
+//printf("~1 8 bit fp chan %d value = %f\n",i,in[i]);
+ }
+ } else {
+ for (i = 0; i < su.id; i++) {
+ int v = ((unsigned short *)inbuf)[x * su.id + i];
+//printf("~1 16 bit pixel value chan %d = %d\n",i,v);
+ if (su.isign_mask & (1 << i)) /* Treat input as signed */
+ v = (v & 0x8000) ? v - 0x8000 : v + 0x8000;
+//printf("~1 16 bit after treat as signed chan %d = %d\n",i,v);
+ in[i] = v/65535.0;
+//printf("~1 16 bit fp chan %d value = %f\n",i,in[i]);
+ }
+ }
+
+ if (su.nprofs > 0) {
+ /* Apply the reference conversion */
+ input_curves((void *)&su, out, in);
+//for (i = 0; i < su.id; i++) printf("~1 after input curve chan %d = %f\n",i,out[i]);
+ md_table((void *)&su, out, out);
+//for (i = 0; i < su.od; i++) printf("~1 after md table chan %d = %f\n",i,out[i]);
+ output_curves((void *)&su, out, out);
+//for (i = 0; i < su.od; i++) printf("~1 after output curve chan %d = %f\n",i,out[i]);
+ } else {
+ for (i = 0; i < su.od; i++)
+ out[i] = in[i];
+ }
+
+ if (bitspersample == 8) {
+ for (i = 0; i < su.od; i++) {
+ int v = (int)(out[i] * 255.0 + 0.5);
+//printf("~1 8 bit chan %d = %d\n",i,v);
+ if (v < 0)
+ v = 0;
+ else if (v > 255)
+ v = 255;
+//printf("~1 8 bit after clip curve chan %d = %d\n",i,v);
+ if (su.osign_mask & (1 << i)) /* Treat input as offset */
+ v = (v & 0x80) ? v - 0x80 : v + 0x80;
+//printf("~1 8 bit after treat as offset chan %d = %d\n",i,v);
+ ((unsigned char *)hprecbuf)[x * su.od + i] = v;
+ }
+ } else {
+ for (i = 0; i < su.od; i++) {
+ int v = (int)(out[i] * 65535.0 + 0.5);
+//printf("~1 16 bit chan %d = %d\n",i,v);
+ if (v < 0)
+ v = 0;
+ else if (v > 65535)
+ v = 65535;
+//printf("~1 16 bit after clip curve chan %d = %d\n",i,v);
+ if (su.osign_mask & (1 << i)) /* Treat input as offset */
+ v = (v & 0x8000) ? v - 0x8000 : v + 0x8000;
+//printf("~1 16 bit after treat as offset chan %d = %d\n",i,v);
+ ((unsigned short *)hprecbuf)[x * su.od + i] = v;
+ }
+ }
+ }
+
+ if (check) {
+ /* Compute the errors */
+ for (x = 0; x < (width * su.od); x++) {
+ int err;
+ if (bitspersample == 8)
+ err = ((unsigned char *)outbuf)[x] - ((unsigned char *)hprecbuf)[x];
+ else
+ err = ((unsigned short *)outbuf)[x] - ((unsigned short *)hprecbuf)[x];
+ if (err < 0)
+ err = -err;
+ if (err > mxerr)
+ mxerr = err;
+ avgerr += (double)err;
+ avgcount++;
+ }
+ }
+ }
+
+ if (dofloat || su.nprofs == 0) /* Use the results of the f.p. conversion */
+ obuf = hprecbuf;
+ else
+ obuf = outbuf;
+
+ if (wh != NULL) {
+ if (TIFFWriteScanline(wh, obuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+ } else {
+ if (su.oinv) {
+ unsigned char *cp, *ep = (unsigned char *)obuf + outbpix;
+ for (cp = (unsigned char *)obuf; cp < ep; cp++)
+ *cp = ~(*cp);
+ }
+ jpeg_write_scanlines(&wj, (JSAMPARRAY)&obuf, 1);
+ }
+ }
+
+ if (check) {
+ printf("Worst error = %d bits, average error = %f bits\n", mxerr, avgerr/avgcount);
+ if (bitspersample == 8)
+ printf("Worst error = %f%%, average error = %f%%\n",
+ mxerr/2.55, avgerr/(2.55 * avgcount));
+ else
+ printf("Worst error = %f%%, average error = %f%%\n",
+ mxerr/655.35, avgerr/(655.35 * avgcount));
+ }
+
+
+ /* Release buffers and close files */
+ if (rh != NULL) {
+ if (inbuf != NULL)
+ _TIFFfree(inbuf);
+ TIFFClose(rh); /* Close Input file */
+ } else {
+ jpeg_finish_decompress(&rj);
+ jpeg_destroy_decompress(&rj);
+ if (inbuf != NULL)
+ free(inbuf);
+ if (fclose(rf))
+ error("Error closing JPEG input file '%s'\n",in_name);
+ }
+
+ if (wh != NULL) {
+ if (outbuf != NULL)
+ _TIFFfree(outbuf);
+ if (hprecbuf != NULL)
+ _TIFFfree(hprecbuf);
+ TIFFClose(wh);
+ } else {
+ jpeg_finish_compress(&wj);
+ jpeg_destroy_compress(&wj);
+ if (outbuf != NULL)
+ free(outbuf);
+ if (hprecbuf != NULL)
+ free(hprecbuf);
+ if (fclose(wf))
+ error("Error closing output file '%s'\n",out_name);
+ }
+
+ /* Done with lookup object */
+ if (s != NULL)
+ s->del(s);
+
+ /* Free up all the profiles etc. in the sequence. */
+ for (i = 0; i < su.nprofs; i++) {
+ if (su.profs[i].c != NULL) { /* Has an ICC profile */
+ su.profs[i].luo->del(su.profs[i].luo); /* Lookup */
+ su.profs[i].c->del(su.profs[i].c);
+ } else {
+ su.profs[i].cal->del(su.profs[i].cal); /* Calibration */
+ }
+ }
+
+ if (rdesc != NULL)
+ free(rdesc);
+ if (wdesc != NULL)
+ free(wdesc);
+
+ return 0;
+}
+
diff --git a/imdi/cctiffo.c b/imdi/cctiffo.c
new file mode 100644
index 0000000..c155e03
--- /dev/null
+++ b/imdi/cctiffo.c
@@ -0,0 +1,1097 @@
+
+/*
+ * Color Correct a TIFF file, using an ICC Device link profile.
+ *
+ * Author: Graeme W. Gill
+ * Date: 00/3/8
+ * Version: 1.30
+ *
+ * Copyright 2000 - 2004 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.
+ */
+
+/*
+ * Thanks to Neil Okamoto for the 16 bit TIFF mods.
+ */
+
+/* TTBD:
+ */
+
+/*
+ This program is a framework that exercises the
+ IMDI code, as well as a demonstration of simple
+ profile linking. It can also do the conversion using the
+ floating point code in ICCLIB as a reference.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "tiffio.h"
+#include "icc.h"
+#include "imdi.h"
+
+#undef TREAT_CMY_AS_RGB
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+void usage(void) {
+ fprintf(stderr,"Color Correct a TIFF file using an ICC device link profile, V%s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: cctiff [-options] devlinkprofile.icm infile.tif outfile.tif\n");
+ fprintf(stderr,"usage: cctiff [-options] -l inprofile.icm outprofile.icm infile.tif outfile.tif\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -c Combine linearisation curves into one transform\n");
+ fprintf(stderr," -p Use slow precise correction\n");
+ fprintf(stderr," -k Check fast result against precise, and report\n");
+ fprintf(stderr," -l Link input and output profiles\n");
+ fprintf(stderr," -i in_intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute colorimetric\n");
+ fprintf(stderr," -o out_intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute colorimetric\n");
+ exit(1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Convert an ICC colorspace to the corresponding possible TIFF Photometric tags. */
+/* Return the number of matching tags, and 0 if there is no corresponding tag. */
+int
+ColorSpaceSignature2TiffPhotometric(
+uint16 tags[10], /* Pointer to return array, up to 10 */
+icColorSpaceSignature cspace /* Input ICC colorspace */
+) {
+ switch(cspace) {
+ case icSigGrayData:
+ tags[0] = PHOTOMETRIC_MINISBLACK;
+ return 1;
+ case icSigRgbData:
+#ifdef TREAT_CMY_AS_RGB
+ case icSigCmyData:
+#endif
+ tags[0] = PHOTOMETRIC_RGB;
+ return 1;
+#ifndef TREAT_CMY_AS_RGB
+ case icSigCmyData:
+#endif
+ case icSigCmykData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+ case icSigYCbCrData:
+ tags[0] = PHOTOMETRIC_YCBCR;
+ return 1;
+ case icSigLabData:
+ tags[0] = PHOTOMETRIC_CIELAB;
+#ifdef PHOTOMETRIC_ICCLAB
+ tags[1] = PHOTOMETRIC_ICCLAB;
+ tags[2] = PHOTOMETRIC_ITULAB;
+#endif
+ return 3;
+
+ case icSigXYZData:
+ case icSigLuvData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ return 0;
+
+ case icSig2colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 2; /* Cheat */
+ return 1;
+
+ case icSig3colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 3; /* Cheat */
+ return 1;
+
+ case icSig4colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 4; /* Cheat */
+ return 1;
+
+ case icSig5colorData:
+ case icSigMch5Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 5; /* Cheat */
+ return 1;
+
+ case icSig6colorData:
+ case icSigMch6Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 6; /* Cheat */
+ return 1;
+
+ case icSig7colorData:
+ case icSigMch7Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 7; /* Cheat */
+ return 1;
+
+ case icSig8colorData:
+ case icSigMch8Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 8; /* Cheat */
+ return 1;
+
+ case icSig9colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 9; /* Cheat */
+ return 1;
+
+ case icSig10colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 10; /* Cheat */
+ return 1;
+
+ case icSig11colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 11; /* Cheat */
+ return 1;
+
+ case icSig12colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 12; /* Cheat */
+ return 1;
+
+ case icSig13colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 13; /* Cheat */
+ return 1;
+
+ case icSig14colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 14; /* Cheat */
+ return 1;
+
+ case icSig15colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 15; /* Cheat */
+ return 1;
+
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+
+/* Compute the length of a double nul terminated string, including */
+/* the nuls. */
+static int zzstrlen(char *s) {
+ int i;
+ for (i = 0;; i++) {
+ if (s[i] == '\000' && s[i+1] == '\000')
+ return i+2;
+ }
+ return 0;
+}
+
+/* Convert an ICC colorspace to the corresponding TIFF Inkset tag */
+/* return 0xffff if not possible or applicable. */
+
+int
+ColorSpaceSignature2TiffInkset(
+icColorSpaceSignature cspace,
+int *len, /* Return length of ASCII inknames */
+char **inknames /* Return ASCII inknames if non NULL */
+) {
+ switch(cspace) {
+ case icSigCmyData:
+ return 0xffff; // ~~9999
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return 0; /* Not CMYK */
+ case icSigCmykData:
+ if (inknames != NULL) {
+ *inknames = NULL; /* No inknames */
+ *len = 0;
+ }
+ return INKSET_CMYK;
+
+ case icSigGrayData:
+ case icSigRgbData:
+ case icSigYCbCrData:
+ case icSigLabData:
+ case icSigXYZData:
+ case icSigLuvData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSigMch5Data:
+ return 0xffff;
+
+ case icSig6colorData:
+ case icSigMch6Data:
+ /* This is a cheat and a hack. Should really make use of the */
+ /* ColorantTable to determine the colorant names. */
+ /* allowing cctiff to read it. */
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000black\000orange\000green\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return 0; /* Not CMYK */
+
+ case icSig7colorData:
+ case icSigMch7Data:
+ return 0xffff;
+
+ case icSig8colorData:
+ case icSigMch8Data:
+ /* This is a cheat and a hack. Should really make use of the */
+ /* ColorantTable to determine the colorant names. */
+ /* allowing cctiff to read it. */
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000black\000orange\000green\000lightcyan\000lightmagenta\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return 0; /* Not CMYK */
+ case icSig9colorData:
+ case icSig10colorData:
+ case icSig11colorData:
+ case icSig12colorData:
+ case icSig13colorData:
+ case icSig14colorData:
+ case icSig15colorData:
+ default:
+ return 0xffff;
+ }
+ return 0xffff;
+}
+
+char *
+Photometric2str(
+int pmtc
+) {
+ static char buf[80];
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE:
+ return "Subtractive Gray";
+ case PHOTOMETRIC_MINISBLACK:
+ return "Additive Gray";
+ case PHOTOMETRIC_RGB:
+ return "RGB";
+ case PHOTOMETRIC_PALETTE:
+ return "Indexed";
+ case PHOTOMETRIC_MASK:
+ return "Transparency Mask";
+ case PHOTOMETRIC_SEPARATED:
+ return "Separated";
+ case PHOTOMETRIC_YCBCR:
+ return "YCbCr";
+ case PHOTOMETRIC_CIELAB:
+ return "CIELab";
+#ifdef PHOTOMETRIC_ICCLAB
+ case PHOTOMETRIC_ICCLAB:
+ return "ICCLab";
+ case PHOTOMETRIC_ITULAB:
+ return "ITULab";
+#endif
+ case PHOTOMETRIC_LOGL:
+ return "CIELog2L";
+ case PHOTOMETRIC_LOGLUV:
+ return "CIELog2Luv";
+ }
+ sprintf(buf,"Unknonw Tag %d",pmtc);
+ return buf;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Callbacks used to initialise imdi */
+
+/* Information needed from a profile */
+struct _profinfo {
+ char name[100];
+ icmFile *fp;
+ icc *c;
+ icmHeader *h;
+ icRenderingIntent intent;
+ icmLuBase *luo; /* Base Lookup type object */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ int chan; /* Device channels */
+}; typedef struct _profinfo profinfo;
+
+/* Context for imdi setup callbacks */
+typedef struct {
+ /* Overall parameters */
+ int verb; /* Non-zero if verbose */
+ icColorSpaceSignature ins, outs; /* Input/Output spaces */
+ int id, od; /* Input/Output dimensions */
+ int icombine; /* Non-zero if input curves are to be combined */
+ int ocombine; /* Non-zero if output curves are to be combined */
+ int dolink; /* Non-zero if input and output profiles are to be linked */
+
+ profinfo dev; /* Device link profile */
+ profinfo in; /* Device to PCS profile */
+ profinfo out; /* PCS to Device profile */
+} sucntx;
+
+/* Input curve function */
+static void input_curves(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ sucntx *rx = (sucntx *)cntx;
+
+//printf("~1 incurve in %f %f %f %f\n",in_vals[0],in_vals[1],in_vals[2],in_vals[3]);
+ if (rx->icombine) {
+ int i;
+ for (i = 0; i < rx->id; i++)
+ out_vals[i] = in_vals[i];
+ } else {
+ if (rx->dolink) { /* Two ICC profiles */
+ rx->in.luo->lookup_in(rx->in.luo, out_vals, in_vals);
+ } else { /* Device link */
+ rx->dev.luo->lookup_in(rx->dev.luo, out_vals, in_vals);
+ }
+ }
+//printf("~1 incurve out %f %f %f %f\n",out_vals[0],out_vals[1],out_vals[2],out_vals[3]);
+}
+
+/* Multi-dim table function */
+static void md_table(
+void *cntx,
+double *out_vals,
+double *in_vals
+) {
+ sucntx *rx = (sucntx *)cntx;
+ double vals[MAX_CHAN];
+
+//printf("~1 md_table in %f %f %f %f\n",in_vals[0],in_vals[1],in_vals[2]);
+ if (rx->dolink) { /* Two ICC profiles */
+
+ if (rx->icombine) {
+ rx->in.luo->lookup_in(rx->in.luo, vals, in_vals);
+ rx->in.luo->lookup_core(rx->in.luo, vals, vals);
+ } else {
+ rx->in.luo->lookup_core(rx->in.luo, vals, in_vals);
+ }
+ rx->in.luo->lookup_out(rx->in.luo, vals, vals);
+ rx->out.luo->lookup_in(rx->out.luo, vals, vals);
+ rx->out.luo->lookup_core(rx->out.luo, out_vals, vals);
+ if (rx->ocombine)
+ rx->out.luo->lookup_out(rx->out.luo, out_vals, out_vals);
+
+ } else { /* Device link */
+
+ if (rx->icombine) {
+ rx->dev.luo->lookup_in(rx->dev.luo, vals, in_vals);
+ rx->dev.luo->lookup_core(rx->dev.luo, out_vals, vals);
+ } else {
+ rx->dev.luo->lookup_core(rx->dev.luo, out_vals, in_vals);
+ }
+ if (rx->ocombine)
+ rx->dev.luo->lookup_out(rx->dev.luo, out_vals, out_vals);
+ }
+//printf("~1 md_table returns %f %f %f %f\n",out_vals[0],out_vals[1],out_vals[2],out_vals[3]);
+}
+
+/* Output curve function */
+static void output_curves(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ sucntx *rx = (sucntx *)cntx;
+
+//printf("~1 outurve in %f %f %f %f\n",in_vals[0],in_vals[1],in_vals[2],in_vals[3]);
+ if (rx->ocombine) {
+ int i;
+ for (i = 0; i < rx->od; i++)
+ out_vals[i] = in_vals[i];
+ } else {
+ if (rx->dolink) { /* Two ICC profiles */
+ rx->out.luo->lookup_out(rx->out.luo, out_vals, in_vals);
+ } else { /* Device link */
+ rx->dev.luo->lookup_out(rx->dev.luo, out_vals, in_vals);
+ }
+ }
+//printf("~1 outurve out %f %f %f %f\n",out_vals[0],out_vals[1],out_vals[2],out_vals[3]);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char in_name[100]; /* Raster file name */
+ char out_name[100]; /* Raster file name */
+ int slow = 0;
+ int check = 0;
+ int i, rv = 0;
+
+ TIFF *rh = NULL, *wh = NULL;
+ int x, y, width, height; /* Size of image */
+ uint16 samplesperpixel, bitspersample;
+ int no_pmtc; /* Number of input photometrics */
+ uint16 photometric, pmtc[10]; /* Photometrics of input file, and input profile */
+ uint16 pconfig; /* Planar configuration */
+ uint16 resunits;
+ float resx, resy;
+ tdata_t *inbuf, *outbuf, *checkbuf = NULL;
+
+ /* IMDI */
+ imdi *s = NULL;
+ sucntx su; /* Setup context */
+ unsigned char *inp[MAX_CHAN];
+ unsigned char *outp[MAX_CHAN];
+ int clutres = 33;
+
+ /* Error check */
+ int mxerr = 0;
+ double avgerr = 0.0;
+ double avgcount = 0.0;
+
+ if (argc < 2)
+ usage();
+
+ su.verb = 0;
+ su.icombine = 0;
+ su.ocombine = 0;
+ su.dolink = 0;
+ su.in.intent = icmDefaultIntent;
+ su.out.intent = icmDefaultIntent;
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Slow, Precise */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ slow = 1;
+ }
+
+ /* Combine per channel curves */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ su.icombine = 1;
+ su.ocombine = 1;
+ }
+
+ /* Check curves */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ check = 1;
+ }
+
+ /* Link profiles */
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') {
+ su.dolink = 1;
+ }
+
+ /* Input profile Intent */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'p':
+ case 'P':
+ su.in.intent = icPerceptual;
+ break;
+ case 'r':
+ case 'R':
+ su.in.intent = icRelativeColorimetric;
+ break;
+ case 's':
+ case 'S':
+ su.in.intent = icSaturation;
+ break;
+ case 'a':
+ case 'A':
+ su.in.intent = icAbsoluteColorimetric;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Output profile Intent */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'p':
+ case 'P':
+ su.out.intent = icPerceptual;
+ break;
+ case 'r':
+ case 'R':
+ su.out.intent = icRelativeColorimetric;
+ break;
+ case 's':
+ case 'S':
+ su.out.intent = icSaturation;
+ break;
+ case 'a':
+ case 'A':
+ su.out.intent = icAbsoluteColorimetric;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ su.verb = 1;
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (su.dolink) {
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(su.in.name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(su.out.name,argv[fa++]);
+ } else {
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(su.dev.name,argv[fa++]);
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(out_name,argv[fa++]);
+
+ /* - - - - - - - - - - - - - - - - */
+
+ if (su.dolink) {
+ icColorSpaceSignature natpcs;
+
+ /* Open up the input device profile for reading */
+ if ((su.in.fp = new_icmFileStd_name(su.in.name,"r")) == NULL)
+ error ("Can't open file '%s'",su.in.name);
+
+ if ((su.in.c = new_icc()) == NULL)
+ error ("Creation of Input profile ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = su.in.c->read(su.in.c,su.in.fp,0)) != 0)
+ error ("%d, %s on file '%s'",rv,su.in.c->err,su.in.name);
+ su.in.h = su.in.c->header;
+
+ /* Check that it is a suitable device input icc */
+ if (su.in.h->deviceClass != icSigInputClass
+ && su.in.h->deviceClass != icSigDisplayClass
+ && su.in.h->deviceClass != icSigOutputClass
+ && su.in.h->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
+ error("Input profile isn't a device profile");
+
+ /* Get a conversion object */
+ if ((su.in.luo = su.in.c->get_luobj(su.in.c, icmFwd, su.in.intent,
+ icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s for profile '%s'",su.in.c->errc, su.in.c->err, su.in.name);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ su.in.luo->spaces(su.in.luo, &su.ins, &su.id, NULL, NULL, &su.in.alg, NULL, NULL, NULL);
+
+ /* Get native PCS space */
+ su.in.luo->lutspaces(su.in.luo, NULL, NULL, NULL, NULL, &natpcs);
+
+ if (natpcs == icSigXYZData) {
+ su.icombine = 1; /* XYZ is to non-linear to be a benefit */
+ }
+
+ /* Open up the output device profile for reading */
+ if ((su.out.fp = new_icmFileStd_name(su.out.name,"r")) == NULL)
+ error ("Can't open file '%s'",su.out.name);
+
+ if ((su.out.c = new_icc()) == NULL)
+ error ("Creation of Output profile ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = su.out.c->read(su.out.c,su.out.fp,0)) != 0)
+ error ("%d, %s on file '%s'",rv,su.out.c->err,su.out.name);
+ su.out.h = su.out.c->header;
+
+ /* Check that it is a suitable device output icc */
+ if (su.out.h->deviceClass != icSigInputClass
+ && su.out.h->deviceClass != icSigDisplayClass
+ && su.out.h->deviceClass != icSigOutputClass
+ && su.out.h->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
+ error("Output profile isn't a device profile");
+
+ /* Get a conversion object */
+ if ((su.out.luo = su.out.c->get_luobj(su.out.c, icmBwd, su.out.intent,
+ icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s for profile '%s'",su.out.c->errc, su.out.c->err, su.out.name);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ su.out.luo->spaces(su.out.luo, NULL, NULL, &su.outs, &su.od, &su.out.alg, NULL, NULL, NULL);
+
+ /* Get native PCS space */
+ su.out.luo->lutspaces(su.out.luo, NULL, NULL, NULL, NULL, &natpcs);
+
+ if (natpcs == icSigXYZData) {
+ su.ocombine = 1; /* XYZ is to non-linear to be a benefit */
+ }
+
+ /* See discussion in imdi/imdi_gen.c for ideal numbers */
+ /* Use "high quality" resolution numbers */
+ switch (su.id) {
+ case 0:
+ error ("Illegal number of input chanels");
+ case 1:
+ clutres = 256;
+ break;
+ case 2:
+ clutres = 256;
+ break;
+ case 3:
+ clutres = 33;
+ break;
+ case 4:
+ clutres = 18;
+ break;
+ case 5:
+ clutres = 16;
+ break;
+ case 6:
+ clutres = 9;
+ break;
+ case 7:
+ clutres = 7;
+ break;
+ case 8:
+ clutres = 6;
+ break;
+ default: /* > 8 chan */
+ clutres = 3;
+ break;
+ }
+
+ } else {
+ icmLut *lut; /* ICC LUT table */
+ icmLuLut *luluo; /* LUT lookup object */
+
+ /* Open up the device link profile for reading */
+ if ((su.dev.fp = new_icmFileStd_name(su.dev.name,"r")) == NULL)
+ error ("Can't open file '%s'",su.dev.name);
+
+ if ((su.dev.c = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ if ((rv = su.dev.c->read(su.dev.c, su.dev.fp, 0)) != 0)
+ error ("%d, %s",rv,su.dev.c->err);
+ su.dev.h = su.dev.c->header;
+
+ if (su.verb) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ su.dev.h->dump(su.dev.h, op, 1);
+ op->del(op);
+ }
+
+ /* Check that the profile is appropriate */
+ if (su.dev.h->deviceClass != icSigLinkClass)
+ error("Profile isn't a device link profile");
+
+ /* Get a conversion object */
+ if ((su.dev.luo = su.dev.c->get_luobj(su.dev.c, icmFwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",su.dev.c->errc, su.dev.c->err);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ su.dev.luo->spaces(su.dev.luo, &su.ins, &su.id, &su.outs, &su.od, &su.dev.alg, NULL, NULL, NULL);
+
+ if (su.dev.alg != icmLutType)
+ error ("DeviceLink profile doesn't have Lut !");
+
+ luluo = (icmLuLut *)su.dev.luo; /* Safe to coerce */
+ luluo->get_info(luluo, &lut, NULL, NULL, NULL); /* Get some details */
+ clutres = lut->clutPoints; /* Desired table resolution */
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Open up input tiff file ready for reading */
+ /* Got arguments, so setup to process the file */
+ if ((rh = TIFFOpen(in_name, "r")) == NULL)
+ error("error opening read file '%s'",in_name);
+
+ TIFFGetField(rh, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);
+
+ TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8 && bitspersample != 16) {
+ error("TIFF Input file must be 8 or 16 bit/channel");
+ }
+
+ TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &photometric);
+ if ((no_pmtc = ColorSpaceSignature2TiffPhotometric(pmtc, su.ins)) == 0)
+ error("ICC input colorspace '%s' can't be handled by a TIFF file!",
+ icm2str(icmColorSpaceSignature, su.ins));
+ for (i = 0; i < no_pmtc; i++) {
+ if (pmtc[i] == photometric)
+ break; /* Matches */
+ }
+ if (i >= no_pmtc) {
+ /* These error reports are a bit sloppy */
+ switch (no_pmtc) {
+ case 1:
+ error("TIFF colorspace '%s' doesn't match ICC colorspace '%s'!",
+ Photometric2str(photometric), Photometric2str(pmtc[0]));
+ case 2:
+ error("TIFF colorspace '%s' doesn't match ICC colorspace '%s' or '%s'!",
+ Photometric2str(photometric), Photometric2str(pmtc[0]),
+ Photometric2str(pmtc[1]));
+ default:
+ error("TIFF colorspace '%s' doesn't match ICC colorspace '%s', '%s' or '%s'!",
+ Photometric2str(photometric), Photometric2str(pmtc[0]),
+ Photometric2str(pmtc[1]), Photometric2str(pmtc[2]));
+ }
+ }
+
+ TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (su.id != samplesperpixel)
+ error ("TIFF Input file has %d input channels mismatched to colorspace '%s'",
+ samplesperpixel, icm2str(icmColorSpaceSignature, su.ins));
+
+ TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
+ if (pconfig != PLANARCONFIG_CONTIG)
+ error ("TIFF Input file must be planar");
+
+ TIFFGetField(rh, TIFFTAG_RESOLUTIONUNIT, &resunits);
+ TIFFGetField(rh, TIFFTAG_XRESOLUTION, &resx);
+ TIFFGetField(rh, TIFFTAG_YRESOLUTION, &resy);
+
+ /* - - - - - - - - - - - - - - - */
+ if ((wh = TIFFOpen(out_name, "w")) == NULL)
+ error("Can\'t create TIFF file '%s'!",out_name);
+
+ TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(wh, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, su.od);
+ TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, bitspersample);
+ TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ if ((no_pmtc = ColorSpaceSignature2TiffPhotometric(pmtc, su.outs)) == 0)
+ error("TIFF file can't handle output colorspace '%s'!",
+ icm2str(icmColorSpaceSignature, su.outs));
+ TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, pmtc[0]); /* Use first returned */
+ if (pmtc[0] == PHOTOMETRIC_SEPARATED) {
+ int iset;
+ int inlen;
+ char *inames;
+ iset = ColorSpaceSignature2TiffInkset(su.outs, &inlen, &inames);
+ if (iset != 0xffff && inlen > 0 && inames != NULL) {
+ TIFFSetField(wh, TIFFTAG_INKSET, iset);
+ if (inames != NULL) {
+ TIFFSetField(wh, TIFFTAG_INKNAMES, inlen, inames);
+ }
+ }
+ }
+ TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ if (resunits) {
+ TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, resunits);
+ TIFFSetField(wh, TIFFTAG_XRESOLUTION, resx);
+ TIFFSetField(wh, TIFFTAG_YRESOLUTION, resy);
+ }
+ TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, "Color corrected by Argyll");
+
+ /* - - - - - - - - - - - - - - - */
+ /* Setup the imdi */
+
+ if (!slow) {
+ s = new_imdi(
+ su.id, /* Number of input dimensions */
+ su.od, /* Number of output dimensions */
+ /* Input pixel representation */
+ bitspersample == 8 ? pixint8 : pixint16,
+ /* Output pixel representation */
+ 0x0, /* Treat every channel as unsigned */
+ NULL, /* No raster to callback mapping */
+ prec_min, /* Minimum of input and output precision */
+ bitspersample == 8 ? pixint8 : pixint16,
+ 0x0, /* Treat every channel as unsigned */
+ NULL, /* No raster to callback mapping */
+ clutres, /* Desired table resolution */
+ oopts_none, /* Desired per channel output options */
+ NULL, /* Output channel check values */
+ opts_none, /* Desired processing direction and stride support */
+ input_curves, /* Callback functions */
+ md_table,
+ output_curves,
+ (void *)&su /* Context to callbacks */
+ );
+
+ if (s == NULL)
+ error("new_imdi failed");
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Process colors to translate */
+ /* (Should fix this to process a group of lines at a time ?) */
+
+ inbuf = _TIFFmalloc(TIFFScanlineSize(rh));
+ outbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+ if (check)
+ checkbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+
+ inp[0] = (unsigned char *)inbuf;
+ outp[0] = (unsigned char *)outbuf;
+
+ if (!slow) { /* Fast */
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do fast conversion */
+ s->interp(s, (void **)outp, 0, (void **)inp, 0, width);
+
+ if (check) {
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+ if (bitspersample == 8)
+ for (i = 0; i < su.id; i++)
+ in[i] = ((unsigned char *)inbuf)[x * su.id + i]/255.0;
+ else
+ for (i = 0; i < su.id; i++)
+ in[i] = ((unsigned short *)inbuf)[x * su.id + i]/65535.0;
+
+#ifdef NEVER
+ if (su.dolink) {
+ if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ } else {
+ if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ }
+#else
+ /* Apply the reference conversion */
+ input_curves((void *)&su, out, in);
+ md_table((void *)&su, out, out);
+ output_curves((void *)&su, out, out);
+#endif
+ if (bitspersample == 8)
+ for (i = 0; i < su.od; i++)
+ ((unsigned char *)checkbuf)[x * su.od + i] = (int)(out[i] * 255.0 + 0.5);
+ else
+ for (i = 0; i < su.od; i++)
+ ((unsigned short *)checkbuf)[x * su.od + i] = (int)(out[i] * 65535.0 + 0.5);
+ }
+ /* Compute the errors */
+ for (x = 0; x < (width * su.od); x++) {
+ int err;
+ if (bitspersample == 8)
+ err = ((unsigned char *)outbuf)[x] - ((unsigned char *)checkbuf)[x];
+ else
+ err = ((unsigned short *)outbuf)[x] - ((unsigned short *)checkbuf)[x];
+ if (err < 0)
+ err = -err;
+ if (err > mxerr)
+ mxerr = err;
+ avgerr += (double)err;
+ avgcount++;
+ }
+ }
+
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+
+ }
+
+ } else { /* Slow but precise */
+ if (bitspersample == 8) {
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+ for (i = 0; i < su.id; i++) {
+ in[i] = ((unsigned char *)inbuf)[x * su.id + i]/255.0;
+ }
+
+#ifdef NEVER
+ if (su.dolink) {
+ if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ } else {
+ if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ }
+#else
+ /* Apply the reference conversion */
+ input_curves((void *)&su, out, in);
+ md_table((void *)&su, out, out);
+ output_curves((void *)&su, out, out);
+#endif
+
+ for (i = 0; i < su.od; i++) {
+ double outi = out[i];
+ if (outi < 0.0) /* Protect against sillies */
+ outi = 0.0;
+ else if (outi > 1.0)
+ outi = 1.0;
+ ((unsigned char *)outbuf)[x * su.od + i] = (int)(outi * 255.0 + 0.5);
+ }
+ }
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+ }
+ } else if (bitspersample == 16) {
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+ for (i = 0; i < su.id; i++) {
+ in[i] = ((unsigned short *)inbuf)[x * su.id + i]/65535.0;
+ }
+
+#ifdef NEVER
+ if (su.dolink) {
+ if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ } else {
+ if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ }
+#else
+ /* Apply the reference conversion */
+ input_curves((void *)&su, out, in);
+ md_table((void *)&su, out, out);
+ output_curves((void *)&su, out, out);
+#endif
+
+ for (i = 0; i < su.od; i++) {
+ double outi = out[i];
+ if (outi < 0.0) /* Protect against sillies */
+ outi = 0.0;
+ else if (outi > 1.0)
+ outi = 1.0;
+ ((unsigned short *)outbuf)[x * su.od + i] = (int)(outi * 65535.0 + 0.5);
+ }
+ }
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+ }
+ }
+ }
+
+ if (check) {
+ printf("Worst error = %d bits, average error = %f bits\n", mxerr, avgerr/avgcount);
+ if (bitspersample == 8)
+ printf("Worst error = %f%%, average error = %f%%\n",
+ mxerr/2.55, avgerr/(2.55 * avgcount));
+ else
+ printf("Worst error = %f%%, average error = %f%%\n",
+ mxerr/655.35, avgerr/(655.35 * avgcount));
+ }
+
+ /* Done with lookup object */
+ if (s != NULL)
+ s->del(s);
+
+ if (su.dolink) {
+ su.in.luo->del(su.in.luo);
+ su.in.c->del(su.in.c);
+ su.in.fp->del(su.in.fp);
+ su.out.luo->del(su.out.luo);
+ su.out.c->del(su.out.c);
+ su.out.fp->del(su.out.fp);
+ } else {
+ su.dev.luo->del(su.dev.luo);
+ su.dev.c->del(su.dev.c);
+ su.dev.fp->del(su.dev.fp);
+ }
+
+ _TIFFfree(inbuf);
+ _TIFFfree(outbuf);
+ if (check)
+ _TIFFfree(checkbuf);
+
+ TIFFClose(rh); /* Close Input file */
+ TIFFClose(wh); /* Close Output file */
+
+ return 0;
+}
+
+
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"cctiff: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"cctiff: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/imdi/cgen.c b/imdi/cgen.c
new file mode 100644
index 0000000..b186dd6
--- /dev/null
+++ b/imdi/cgen.c
@@ -0,0 +1,2150 @@
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+/* 'C' code color transform kernel code generator. */
+
+/*
+ This module generates C code routines which implement
+ an integer multi-channel transform. The input values
+ are read, passed through per channel lookup tables,
+ a multi-dimentional interpolation table, and then
+ a per channel output lookup table, before being written.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "imdi.h"
+#include "imdi_tab.h"
+
+#undef VERBOSE
+#define INSTHRESH 4 /* Use inserion sort of di >= INSTHRESH for best performance. */
+#undef ROUND /* Round the division after accumulation */
+ /* Improves accuracy at the cost of a little speed */
+
+/* ------------------------------------ */
+/* Generator context */
+typedef struct {
+ FILE *of; /* Output file */
+ int indt; /* Indent */
+
+ /* Other info */
+ genspec *g; /* Generation specifications */
+ tabspec *t; /* Table setup data */
+ mach_arch *a; /* Machine architecture and tuning data */
+
+ /* Code generation information */
+ /* if() conditions are for entry usage */
+
+ /* Pixel read information */
+ int ipt[IXDI]; /* Input pointer types */
+ int nip; /* Actual number of input pointers, accounting for pint */
+ int chv_bits; /* Bits in chv temp variable ?? */
+
+ /* Input table entry */
+ int itet; /* Input table entry type */
+ int itvt; /* Input table variable type */
+ int itmnb; /* Input table minimum bits (actual is it_ab) */
+
+ /* Interpolation index */
+ int ixet; /* Interpolation index entry type */
+ int ixvt; /* Interpolation index variable type */
+ int ixmnb; /* Interpolation index minimum bits (actual is ix_ab ???) */
+ int ixmxres; /* Interpolation table maximum resolution */
+
+ /* Simplex index: if(!sort && it_xs) */
+ int sxet; /* Simplex index entry type */
+ int sxvt; /* Simplex index variable type */
+ int sxmnb; /* Simplex index bits minimum (actual is sx_ab) */
+ int sxmxres; /* Simplex table maximum resolution (0 if sort) */
+
+ /* Combination Weighting + Vertex offset values: if(it_xs && !wo_xs) */
+ int woet; /* Weighting+offset entry type */
+ int wovt; /* Weighting+offset variable type */
+ int womnb; /* Weighting+offset index bits minimum (actual is wo_ab) */
+
+ /* Weighting value: if(it_xs && wo_xs) */
+ int weet; /* Weighting entry type */
+ int wevt; /* Weighting variable type */
+ int wemnb; /* Weighting index bits minimum (actual is we_ab) */
+
+ /* Vertex offset value: if(it_xs && wo_xs) */
+ int voet; /* Vertex offset entry type */
+ int vovt; /* Vertex offset variable type */
+ int vomnb; /* Vertex offset index bits minimum (actual is vo_ab) */
+
+ /* Interpolation table entry: */
+ int imovb; /* Interpolation output value bits per channel required */
+ int imfvt; /* Interpolation full entry & variable type */
+ int impvt; /* Interpolation partial entry variable type */
+
+ /* Interpolation accumulators: */
+ int iaovb; /* Interpolation output value bits per channel required */
+ int iafvt; /* Interpolation full entry & variable type */
+ int iapvt; /* Interpolation partial entry variable type */
+ int ian; /* Total number of accumulators */
+
+ /* Output table lookup */
+ int otit; /* Output table index type */
+ int otvt; /* Output table value type (size is ot_ts bytes) */
+
+ /* Write information */
+ int opt[IXDO]; /* Output pointer types */
+ int nop; /* Actual number of output pointers, accounting for pint */
+
+} fileo;
+
+void line(fileo *f, char *fmt, ...); /* Output one line */
+void sline(fileo *f, char *fmt, ...); /* Output start of line */
+void mline(fileo *f, char *fmt, ...); /* Output middle of line */
+void eline(fileo *f, char *fmt, ...); /* Output end of line */
+void niline(fileo *f, char *fmt, ...); /* Output one line, no indent */
+void cr(fileo *f) { line(f,""); } /* Output a blank line */
+void inc(fileo *f) { f->indt++; } /* Increment the indent level */
+void dec(fileo *f) { f->indt--; } /* Decrement the indent level */
+void lineinc(fileo *f, char *fmt, ...); /* Output one line and increment indent */
+void decline(fileo *f, char *fmt, ...); /* Decrement indent and output one line */
+/* ------------------------------------ */
+
+int findord(fileo *f, int bits); /* Find ordinal with bits or more */
+int nord(fileo *f, int ov); /* Round ordinal type up to natural size */
+int findnord(fileo *f, int bits); /* Find ordinal with bits, or natural larger */
+int findint(fileo *f, int bits); /* Find integer with bits or more */
+int nint(fileo *f, int iv); /* Round integer type up to natural size */
+int findnint(fileo *f, int bits); /* Find integer with bits, or natural larger */
+static void doheader(fileo *f);
+
+static int calc_bits(int dim, int res);
+static int calc_res(int dim, int bits);
+static int calc_obits(int dim, int res, int esize);
+static int calc_ores(int dim, int bits, int esize);
+
+
+/* return a hexadecimal mask string */
+/* take care of the case when bits >= 32 */
+char *hmask(int bits) {
+ static char buf[20];
+
+ if (bits < 32) {
+ sprintf(buf, "0x%x",(1 << bits)-1);
+ } else if (bits == 32) {
+ return "0xffffffff";
+ } else if (bits == 64) {
+ return "0xffffffffffffffff";
+ } else { /* Bits > 32 */
+ sprintf(buf, "0x%xffffffff",(1 << (bits-32))-1);
+ }
+ return buf;
+}
+
+/* Generate a source file to implement the specified */
+/* interpolation kernel. Fill in return values and return 0 if OK. */
+/* g->opt should be set to opts_splx_sort or opts_sort_splx if both */
+/* are being generated, but opts_splx is what actually chooses simplex */
+/* when available, and is not recorded in the resulting table. */
+/* Return 1 if this kernel could be generated with a simplex table algorithm, */
+/* and some other non-zero on another error. */
+int gen_c_kernel(
+ genspec *g, /* Specification of what to generate */
+ tabspec *t, /* Tablspec that will be filled in */
+ mach_arch *a,
+ FILE *fp, /* File to write to */
+ int index, /* Identification index, 1 = first */
+ genspec *og, /* Previous tables genspec (for diff) */
+ tabspec *ot /* Previous tables tabspec (for diff) */
+) {
+ int frv = 0; /* Function return value */
+ unsigned char kk[] = { 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68,
+ 0x74, 0x20, 0x32, 0x30, 0x30, 0x34, 0x20, 0x47,
+ 0x72, 0x61, 0x65, 0x6D, 0x65, 0x20, 0x57, 0x2E,
+ 0x20, 0x47, 0x69, 0x6C, 0x6C, 0x00 };
+ fileo f[1];
+ int e, i;
+ int timp = 0; /* Flag to use temporary imp pointer. */
+ /* Seem to make x86 MSVC++ slower */
+ /* Has no effect on x86 IBMCC */
+
+ sprintf(g->kname, "imdi_k%d",index); /* Kernel routine base name */
+ strcpy(g->kkeys, (char *)kk); /* Kernel keys for this session */
+
+ /* Setup the file output context */
+ f->of = fp;
+ f->indt = 0; /* Start with no indentation */
+ f->g = g;
+ f->t = t;
+ f->a = a;
+
+ /* (prec is currently permitted to be only 8 or 16) */
+ if (g->prec == 8) {
+ if (g->id <= 4) { /* Simplex table can be used */
+ frv = 1; /* Signal caller that simplex is possible */
+ if (g->opt & opts_splx)
+ t->sort = 0; /* Implicit sort using simplex table lookup */
+ else
+ t->sort = 1; /* Explicit sort */
+ } else {
+ t->sort = 1; /* Explicit sort */
+ }
+
+ } else if (g->prec == 16) {
+ t->sort = 1; /* Explit sort, no simplex table */
+
+ } else {
+ fprintf(stderr,"Can't cope with requested precision of %d bits\n",g->prec);
+ exit(-1);
+ }
+
+ /* Compute input read and input table lookup stuff */
+
+ /* Compute number of input pointers */
+ if (g->in.pint != 0) /* Pixel interleaved */
+ f->nip = 1;
+ else
+ f->nip = g->id;
+
+ /* Figure out the input pointer types */
+ for (e = 0; e < f->nip; e++) {
+ if ((f->ipt[e] = findord(f, g->in.bpch[e])) < 0) {
+ fprintf(stderr,"Input channel size can't be handled\n");
+ exit(-1);
+ }
+ }
+
+ /* Do the rest of the input table size calculations after figuring */
+ /* out simplex and interpolation table sizes. */
+
+ /* Figure out the interpolation multi-dimentional table structure */
+ /* and output accumulation variable sizes. Note that the accumulator */
+ /* size needs to be greater than the basic precision by soem factor, */
+ /* if we are not to get rounding errors due to each value being the sum */
+ /* of di+1 parts with weighting that sum to 1.0. It's convenient in */
+ /* C code case to simply double the basic precision size. */
+ if (g->prec == 8
+ || (g->prec == 16 && a->ords[a->nords-1].bits >= (g->prec * 4))) {
+ int tiby; /* Total interpolation bytes needed */
+
+ /* We assume that we can normally compute more than one */
+ /* output value at a time, so we need to hold the interpolation */
+ /* output data in the expanded fixed point format in both the */
+ /* table and accumulator. */
+ t->im_cd = 1;
+ f->imovb = g->prec * 2; /* 16 bits needed for 8 bit precision, */
+ f->iaovb = g->prec * 2; /* 32 bits needed for 16 bit precision */
+ f->imfvt = a->nords-1; /* Full variable entry type is biggest available */
+ f->iafvt = a->nords-1; /* Full variable accum. type is same */
+
+ if (a->ords[f->imfvt].bits < f->imovb) {
+ fprintf(stderr,"Interpolation table entry size can't be handled\n");
+ exit(-1);
+ }
+
+ /* Compute details of table entry sizes, number */
+ tiby = (f->imovb * g->od)/8; /* Total table bytes needed */
+ t->im_fs = a->ords[f->imfvt].bits/8; /* Full entry bytes */
+ t->im_fv = (t->im_fs * 8)/f->imovb; /* output values per full entry . */
+ t->im_fn = tiby/t->im_fs; /* Number of full entries (may be 0) */
+ t->im_ts = t->im_fn * t->im_fs; /* Structure size so far */
+ tiby -= t->im_fn * t->im_fs; /* Remaining bytes */
+
+ if (tiby <= 0) {
+ t->im_pn = 0; /* No partials */
+ t->im_ps = 0;
+ t->im_pv = 0;
+ f->impvt = 0;
+ f->iapvt = 0;
+
+ } else {
+ t->im_pn = 1; /* Must be just 1 partial */
+ t->im_pv = (tiby * 8)/f->imovb; /* Partial holds remaining entries */
+
+#ifdef NEVER /* For better performance ??? */
+ if ((f->impvt = findnord(f, tiby * 8)) < 0) {
+#else /* Better memory footprint - minimise multi-D entry sizes */
+ /* (but only if structure is alowed to be mis-aligned!) */
+ if ((f->impvt = findord(f, tiby * 8)) < 0) {
+#endif
+ fprintf(stderr,"Can't find partial interp table entry variable size\n");
+ exit(-1);
+ }
+ f->iapvt = f->impvt;
+ t->im_ps = a->ords[f->impvt].bits/8;/* Partial entry bytes */
+
+ if (a->ords[f->imfvt].align) /* If full entry's need to be aligned */
+ t->im_ts += t->im_fs; /* Round out struct size by full entry */
+ else
+ t->im_ts += t->im_ps; /* Round out to natural size */
+ }
+
+ } else {
+ /* One 16 bit output value per entry + 32 bit accumulator. */
+ /* We can conserve table space by not holding the table data in expanded */
+ /* fixed point format, but expanding it when it is read. */
+ /* Without resorting to compicated code, this restricts us */
+ /* to only computing one output value per accumulator. */
+ t->im_cd = 0;
+ f->imovb = g->prec; /* Table holds 16 bit entries with no fractions */
+ f->iaovb = g->prec * 2; /* 32 bits needed for 16 bit precision in comp. */
+
+ if ((f->imfvt = findord(f, f->imovb)) < 0) {
+ fprintf(stderr,"Interpolation table entry size can't be handled\n");
+ exit(-1);
+ }
+ if ((f->iafvt = findord(f, f->iaovb)) < 0) {
+ fprintf(stderr,"Interpolation accumulator size can't be handled\n");
+ exit(-1);
+ }
+
+ /* Compute details of table entry sizes, number */
+ t->im_fs = a->ords[f->imfvt].bits/8; /* Full entry bytes */
+ t->im_fv = 1; /* output values per full entry . */
+ t->im_fn = g->od; /* Number of full entries */
+ t->im_ts = t->im_fn * t->im_fs; /* Total structure size */
+
+ t->im_pn = 0; /* No partials */
+ t->im_ps = 0;
+ t->im_pv = 0;
+ f->impvt = 0;
+ f->iapvt = 0;
+ }
+ f->ian = t->im_fn + t->im_pn; /* Total number of output accumulators */
+
+ /* Figure out how much of the interpolation entry offset to put in the */
+ /* vertex offset value, and how much to make explicit in accessing the */
+ /* interpolation table enty. */
+ if (a->oscale > 0) { /* We have a scaled index mode */
+ /* Use as much of the scaled index mode as possible */
+ /* and then do the balance by scaling the simplex index entry. */
+ for (t->im_oc = a->oscale; ; t->im_oc >>= 1) {
+ t->vo_om = t->im_ts/t->im_oc; /* Simplex index multiplier */
+ if ((t->vo_om * t->im_oc) == t->im_ts)
+ break; /* Got appropriate offset scale */
+ }
+ } else if (a->smmul) { /* Architecure supports fast small multiply */
+ t->im_oc = t->im_ts; /* Do scale by structure size explicitly */
+ t->vo_om = 1; /* Do none in the Simplex index */
+ } else { /* We have no fast tricks */
+ t->im_oc = 1; /* Do none explicitly */
+ t->vo_om = t->im_ts; /* Do all in Simplex index */
+ }
+
+ /* Compute the number of bits needed to hold an index into */
+ /* the interpolation table (index is in terms of table entry size). */
+ /* This value is used to figure out the room needed in the input */
+ /* table to accumulate the interpolation cube base offset value. (IM_O macro) */
+ f->ixmnb = calc_bits(g->id, g->itres);
+
+#ifdef VERBOSE
+ /* Summarise the interpolation table arrangements */
+ printf("\n");
+ printf("Interpolation table structure:\n");
+ printf(" Minimum bits needed to index table %d\n", f->ixmnb);
+ printf(" Entry total size %d bytes\n", t->im_ts);
+ printf(" Simplex entry offset scale %d\n", t->vo_om);
+ printf(" Explicit entry offset scale %d\n", t->im_oc);
+ printf(" %d full entries, size %d bytes\n", t->im_fn, t->im_fs);
+ printf(" %d partial entries, size %d bytes\n", t->im_pn, t->im_ps);
+ printf(" to hold %d output values of %d bits\n", g->od, f->imovb);
+
+#endif /* VERBOSE */
+
+ /* Number of bits needed for the weighting value */
+ f->wemnb = g->prec+1; /* Need to hold a weighting factor of 0 - 256 for 8 bits */
+ /* Need to hold a weighting factor of 0 - 65536 for 16 bits */
+
+ /* Variable that would be used to hold it */
+ if ((f->wevt = findnord(f, f->wemnb)) < 0) {
+ fprintf(stderr,"Can't find entry size to hold weighting variable\n");
+ exit(-1);
+ }
+
+ /* Number of bits needed for vertex offset value */
+ f->vomnb = calc_obits(g->id, g->itres, t->vo_om);
+
+ /* Variable that would be used to hold it */
+ if ((f->vovt = findnord(f, f->vomnb)) < 0) {
+ fprintf(stderr,"Can't find entry size to hold vertex offset variable\n");
+ exit(-1);
+ }
+
+ if (t->sort) {
+ /* If we are using an explicit sort, we need to figure how many */
+ /* separate entries we need to use to hold the interpolation index, */
+ /* weighting factor and vertex offset values in the input table. */
+
+ /* First try all three in one entry */
+ if ((f->itet = findord(f, f->ixmnb + f->wemnb + f->vomnb)) >= 0) {/* size to read */
+ int rem; /* Remainder bits */
+
+ t->it_xs = 0; /* Combined interp+weight+offset */
+ t->wo_xs = 0;
+ t->it_ab = a->ords[f->itet].bits; /* Bits in combined input entry */
+ rem = t->it_ab - f->ixmnb - f->wemnb - f->vomnb; /* Spair bits */
+ t->we_ab = f->wemnb; /* Get minimum weight bits */
+ t->vo_ab = f->vomnb + rem/2; /* vertex offset index bits actually available */
+ t->ix_ab = t->it_ab - t->vo_ab - t->we_ab; /* interp index bits actually available */
+ t->wo_ab = t->we_ab + t->vo_ab; /* Weight & offset total bits */
+ t->it_ts = a->ords[f->itet].bits/8; /* total size in bytes */
+ f->itvt = nord(f, f->itet); /* Variable type */
+
+ if ((f->wovt = findnord(f, t->we_ab + t->vo_ab)) < 0) {
+ fprintf(stderr,"Can't find variable size to hold weight/offset\n");
+ exit(-1);
+ }
+ if ((f->wevt = findnord(f, t->we_ab)) < 0) {
+ fprintf(stderr,"Can't find variable size to hold weighting factor\n");
+ exit(-1);
+ }
+ if ((f->vovt = findnord(f, t->vo_ab)) < 0) {
+ fprintf(stderr,"Can't find variable size to hold vertex offset index\n");
+ exit(-1);
+ }
+ if ((f->ixvt = findnord(f, t->ix_ab)) < 0) {
+ fprintf(stderr,"Interp index variable size can't be handled\n");
+ exit(-1);
+ }
+ } else { /* Interp index will be a separate entry */
+ int wit, oft, bigt; /* weighting type, offset type, biggest type */
+ int combt; /* Combined type */
+ int sepbits, combits; /* Total separate, combined bits */
+
+ t->it_xs = 1; /* Separate interp index and weighting+offset */
+ if ((f->ixet = findord(f, f->ixmnb)) < 0) {
+ fprintf(stderr,"Interp index entry size can't be handled\n");
+ exit(-1);
+ }
+ f->ixvt = nord(f, f->ixet); /* Variable type */
+ t->ix_ab = a->ords[f->ixet].bits;
+ t->ix_es = t->ix_ab/8;
+ t->ix_eo = 0;
+ t->it_ts = t->ix_es; /* Input table size so far */
+
+ /* Now figure weighting and vertex offset */
+
+ /* See if we can fit them into separately readable entries, or whether */
+ /* they should be combined to minimise overall table size. */
+
+ if ((wit = findord(f, f->wemnb)) < 0) {
+ fprintf(stderr,"Can't find entry size to hold weighting factor\n");
+ exit(-1);
+ }
+ if ((oft = findord(f, f->vomnb)) < 0) {
+ fprintf(stderr,"Can't find entry size to hold vertex offset index\n");
+ exit(-1);
+ }
+ bigt = wit > oft ? wit : oft; /* Bigest separate type */
+
+ if ((combt = findord(f, f->wemnb + f->vomnb)) < 0) {/* Combined isn't possible */
+ sepbits = 2 * a->ords[bigt].bits; /* Total separate bits */
+ combits = sepbits; /* Force separate entries */
+ } else {
+ sepbits = 2 * a->ords[bigt].bits; /* Total separate bits */
+ combits = a->ords[combt].bits; /* Total combined bits */
+ }
+
+ if (sepbits <= combits) { /* We will use separate entries */
+ t->wo_xs = 1;
+ t->we_es = a->ords[bigt].bits/8; /* size in bytes for weighting entry */
+ t->we_ab = a->ords[bigt].bits; /* bits available for weighting */
+ t->we_eo = t->ix_es; /* Entry offset in input table */
+ t->vo_es = a->ords[bigt].bits/8; /* size in bytes for vertex offset entry */
+ t->vo_ab = a->ords[bigt].bits; /* bits available for vertex offset */
+ t->vo_eo = t->ix_es + t->we_es; /* Entry offset in input table */
+ t->wo_es = t->we_es + t->vo_es; /* Total entry size for each vertex */
+ t->it_ts += t->we_es + t->vo_es; /* Total input entry size in bytes */
+
+ f->weet = bigt; /* Variable type for accessing weighting entry */
+ f->voet = bigt; /* Variable type for accessing vertex offset entry */
+ f->wevt = nord(f, wit); /* Variable type for holding weight value */
+ f->vovt = nord(f, oft); /* Variable type for holding offset value */
+
+ } else { /* We will combine the two entries */
+ t->wo_xs = 0;
+ t->wo_es = a->ords[combt].bits/8; /* entry size in bytes for each entry */
+ t->wo_ab = a->ords[combt].bits; /* bits in weightig + offset */
+ t->we_ab = f->wemnb; /* bits available for weighting */
+ t->vo_ab = t->wo_ab - t->we_ab; /* Allow all spare bits to vertex offset */
+ t->wo_eo = t->ix_es; /* entry offset in input table */
+ t->it_ts += t->wo_es; /* Final input table size */
+
+ f->woet = combt; /* Variable type for accessing combined entry */
+ f->wovt = nord(f, combt); /* Variable type holding weight/offset read value */
+
+ if ((f->wevt = findnord(f, t->we_ab)) < 0) {
+ fprintf(stderr,"Can't find variable size to hold weighting factor\n");
+ exit(-1);
+ }
+ if ((f->vovt = findnord(f, t->vo_ab)) < 0) {
+ fprintf(stderr,"Can't find variable size to hold vertex offset index\n");
+ exit(-1);
+ }
+ }
+ }
+#ifdef VERBOSE
+ /* Summarise the input table arrangements */
+ printf("\n");
+ printf("Input table structure:\n");
+ printf(" Input table entry size = %d bytes\n",t->it_ts);
+ if (t->it_ix) {
+ printf(" Input table extracts value from read values\n");
+ if (t->wo_xs) {
+ printf(" Separate Interp., Weighting and Offset values\n");
+ printf(" Interp. index is at offset %d, size %d bytes\n",t->ix_eo, t->ix_es);
+ printf(" Weighting is at offset %d, size %d bytes\n",t->we_eo, t->we_es);
+ printf(" Vertex offset is at offset %d, size %d bytes\n",t->vo_eo, t->vo_es);
+ } else {
+ printf(" Separate Interp. index and Weightint+Offset value\n");
+ printf(" Interp. index is at offset %d, size %d bytes\n",t->ix_eo, t->ix_es);
+ printf(" Weighting+Offset is at offset %d, size %d bytes\n",t->wo_eo, t->wo_es);
+ printf(" Weighting = %d bits\n",t->we_ab);
+ printf(" Vertex offset = %d bits\n",t->vo_ab);
+ }
+ } else {
+ printf(" Combined InterpIndex+Weighting+Voffset values\n");
+ printf(" Values are stored in size %d bytes\n",t->it_ts);
+ printf(" Interp. index = %d bits\n",t->ix_ab);
+ printf(" Weighting = %d bits\n",t->we_ab);
+ printf(" Vertex offset = %d bits\n",t->vo_ab);
+ }
+#endif /* VERBOSE */
+
+ } else { /* Simplex table */
+ /* If we are going to use a simplex table, figure out how we */
+ /* will store the weighting value and vertex offset values in it, */
+ /* as well as the size of index we'll need to address it. */
+ int wit, oft, bigt; /* weighting type, offset type, biggest type */
+ int combt; /* Combined type */
+ int sepbits, combits; /* Total separate, combined bits */
+
+ /* See if we can fit them into separately readable entries, or whether */
+ /* they should be combined to minimise overall table size. */
+
+ if ((wit = findord(f, f->wemnb)) < 0) {
+ fprintf(stderr,"Can't find entry size to hold weighting factor\n");
+ exit(-1);
+ }
+ if ((oft = findord(f, f->vomnb)) < 0) {
+ fprintf(stderr,"Can't find entry size to hold vertex offset index\n");
+ exit(-1);
+ }
+ bigt = wit > oft ? wit : oft; /* Bigest separate type */
+
+ if ((combt = findord(f, f->wemnb + f->vomnb)) < 0) {/* Combined isn't possible */
+ sepbits = 2 * a->ords[bigt].bits; /* Total separate bits */
+ combits = sepbits; /* Force separate entries */
+ } else {
+ sepbits = 2 * a->ords[bigt].bits; /* Total separate bits */
+ combits = a->ords[combt].bits; /* Total combined bits */
+ }
+
+ if (sepbits <= combits) { /* We will use separate entries */
+ t->wo_xs = 1;
+ t->we_es = a->ords[bigt].bits/8; /* size in bytes for weighting entry */
+ t->we_ab = a->ords[bigt].bits; /* bits available for weighting */
+ t->we_eo = 0; /* Entry offset in simplex table */
+ t->vo_es = a->ords[bigt].bits/8; /* size in bytes for vertex offset entry */
+ t->vo_ab = a->ords[bigt].bits; /* bits available for vertex offset */
+ t->vo_eo = t->we_es; /* Entry offset in simplex table */
+ t->wo_es = t->we_es + t->vo_es; /* Total entry size for each vertex */
+ t->sm_ts = (g->id + 1) * (t->we_es + t->vo_es) ; /* Total size in bytes */
+
+ f->weet = bigt; /* Variable type for accessing weighting entry */
+ f->voet = bigt; /* Variable type for accessing vertex offset entry */
+ f->wevt = nord(f, wit); /* Variable type for holding weight value */
+ f->vovt = nord(f, oft); /* Variable type for holding offset value */
+
+ } else { /* We will combine the two entries */
+ t->wo_xs = 0;
+ t->wo_es = a->ords[combt].bits/8; /* entry size in bytes for each entry */
+ t->wo_ab = a->ords[combt].bits; /* bits in weightig + offset */
+ t->we_ab = f->wemnb; /* bits available for weighting */
+ t->vo_ab = t->wo_ab - t->we_ab; /* Allow all spare bits to vertex offset */
+ t->wo_eo = 0; /* entry offset in simplex table */
+ t->sm_ts = (g->id + 1) * t->wo_es; /* Total size in bytes */
+
+ f->woet = combt; /* Variable type for accessing combined entry */
+ f->wovt = nord(f, combt); /* Variable type holding weight/offset read value */
+
+ if ((f->wevt = findnord(f, t->we_ab)) < 0) {
+ fprintf(stderr,"Can't find variable size to hold weighting factor\n");
+ exit(-1);
+ }
+ if ((f->vovt = findnord(f, t->vo_ab)) < 0) {
+ fprintf(stderr,"Can't find variable size to hold vertex offset index\n");
+ exit(-1);
+ }
+ }
+
+ /* Compute the number of bits needed to hold an index into */
+ /* the simplex table (index is in terms of table entry size). */
+ /* This value is used to figure out the room needed in the input */
+ /* table to accumulate the simplex cube base offset value. (SW_O macro) */
+ f->sxmnb = calc_bits(g->id, g->stres);
+
+#ifdef VERBOSE
+ /* Summarise the simplex table arrangements */
+ printf("\n");
+ printf("Simplex table structure:\n");
+ printf(" Minimum bits needed to index table %d\n", f->sxmnb);
+ printf(" Total simplex entry size %d bytes to hold %d entries\n",t->sm_ts, g->id+1);
+ if (t->wo_xs) {
+ printf(" Separate entries for offset and weight\n");
+ printf(" Weighting entry size %d bytes\n",t->we_es);
+ printf(" Offset entry size %d bytes\n",t->vo_es);
+ } else {
+ printf(" Combined offset and weight entries in %d bytes\n",t->wo_es);
+ printf(" Weighting entry size %d bits\n",t->we_ab);
+ printf(" Offset entry size %d bits\n",t->vo_ab);
+ }
+ printf(" Vertex offset scale factor %d\n", t->vo_om);
+#endif /* VERBOSE */
+
+ /* We known how big the interpolation and simplex */
+ /* tables indexes are going to be, so complete figuring out */
+ /* how big the input table entries have to be. */
+ if ((f->itet = findord(f, f->sxmnb + f->ixmnb)) >= 0) {/* size to read */
+ int rem; /* Remainder bits */
+
+ t->it_xs = 0; /* Combined simplex+interp index */
+
+ t->it_ab = a->ords[f->itet].bits; /* Bits in combined input entry */
+ rem = t->it_ab - f->sxmnb - f->ixmnb;
+ t->sx_ab = f->sxmnb + rem/2; /* simplex index bits actually available */
+ t->ix_ab = t->it_ab - t->sx_ab; /* interp index bits actually available */
+ t->it_ts = a->ords[f->itet].bits/8; /* total size in bytes */
+ f->itvt = nord(f, f->itet); /* Variable type */
+
+ if ((f->sxvt = findnord(f, t->sx_ab)) < 0) {
+ fprintf(stderr,"Simplex index variable size can't be handled\n");
+ exit(-1);
+ }
+ if ((f->ixvt = findnord(f, t->ix_ab)) < 0) {
+ fprintf(stderr,"Interp index variable size can't be handled\n");
+ exit(-1);
+ }
+ } else { /* Separate entries */
+ int bbits; /* Largest number of bits needed */
+
+ t->it_xs = 1; /* Separate simplex+interp indexes */
+ bbits = f->sxmnb > f->ixmnb ? f->sxmnb : f->ixmnb;
+
+ /* Allocate same size for both so that total structure size is power of 2 */
+ if ((f->sxet = f->ixet = findord(f, bbits)) < 0) {
+ fprintf(stderr,"Interp/Simplex index entry size can't be handled\n");
+ exit(-1);
+ }
+
+ t->sx_ab = a->ords[f->sxet].bits; /* Actual bits available */
+ t->sx_es = t->sx_ab/8; /* Entry size in bytes */
+ t->ix_ab = a->ords[f->ixet].bits;
+ t->ix_es = t->sx_ab/8;
+ t->it_ts = t->sx_es + t->ix_es; /* total size in bytes */
+ t->sx_eo = 0; /* simplex index offset in bytes */
+ t->ix_eo = t->sx_es; /* interp. index offset in bytes */
+ f->sxvt = nord(f, f->sxet); /* Variable type */
+ f->ixvt = nord(f, f->ixet); /* Variable type */
+ }
+
+#ifdef VERBOSE
+ /* Summarise the input table arrangements */
+ printf("\n");
+ printf("Input table structure:\n");
+ if (t->it_ix) {
+ printf(" Input table extracts value from read values\n");
+ } else {
+ printf(" Value extraction read values is explicit\n");
+ }
+ printf(" Input table entry size = %d bytes\n",t->it_ts);
+ if (t->it_xs) {
+ printf(" Separate Interp. and Simplex index values\n");
+ printf(" Interp. index is at offset %d, size %d bytes\n",t->ix_eo, t->ix_es);
+ printf(" Simplex index is at offset %d, size %d bytes\n",t->sx_eo, t->sx_es);
+ } else {
+ printf(" Combined Interp. and Simplex index values\n");
+ printf(" Values are size %d bytes\n",t->it_ts);
+ printf(" Interp. index = %d bits\n",t->ix_ab);
+ printf(" Simplex index = %d bits\n",t->sx_ab);
+ }
+#endif /* VERBOSE */
+ }
+
+ /* Figure out output table stuff */
+ {
+ /* A variable to hold the index into an output table */
+ if ((f->otit = findord(f, g->prec)) < 0) {
+ fprintf(stderr,"Can't find output table index size\n");
+ exit(-1);
+ }
+ f->otit = nord(f,f->otit); /* Make temp variable natural size */
+
+ if (g->out.pint != 0) /* Pixel interleaved */
+ f->nop = 1; /* Use same pointers for every pixel */
+ else
+ f->nop = g->od; /* Use a separate pointer for each output value */
+
+ /* Figure out the output pointer types */
+ f->otvt = 0; /* Output table value type */
+ for (e = 0; e < f->nop; e++) {
+ if ((f->opt[e] = findord(f, g->out.bpch[e])) < 0) {
+ fprintf(stderr,"Output channel size can't be handled\n");
+ exit(-1);
+ }
+ if (f->opt[e] > f->otvt)
+ f->otvt = f->opt[e]; /* Make value type big enough for any channel size */
+ }
+ t->ot_ts = a->ords[f->otvt].bits/8; /* Output table entry size in bytes */
+
+ /* Setup information on data placement in output table entries */
+ for (e = 0; e < g->od; e++) {
+ t->ot_off[e] = g->out.bov[e]; /* Transfer info from generation spec. */
+ t->ot_bits[e] = g->out.bpv[e];
+ }
+ }
+
+#ifdef VERBOSE
+ /* Summarise the output table arrangements */
+ printf("Output table structure:\n");
+ printf(" Entry size = %d bytes\n",t->ot_ts);
+ printf(" Output value placement within each enry is:\n");
+ for (e = 0; e < f->nop; e++) {
+ printf(" %d: Offset %d bits, size %d bits\n", e, t->ot_off[e], t->ot_bits[e]);
+ }
+#endif /* VERBOSE */
+
+ /* Compute the maximum interpolation table resolution we will be able to handle */
+ {
+ int res, ores;
+
+ res = calc_res(g->id, t->ix_ab);
+ ores = calc_ores(g->id, t->vo_ab, t->vo_om);
+ f->ixmxres = res < ores ? res : ores;
+ }
+
+ /* Compute the maximum simplex table resolution we will be able to handle */
+ if (t->sort) {
+ f->sxmxres = 0;
+ } else {
+ f->sxmxres = calc_res(g->id, t->sx_ab);
+ }
+
+#ifdef VERBOSE
+ printf("Emitting introductory code\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ /* Start of code generation */
+ doheader(f); /* Output the header comments */
+
+ /* We need an include file */
+ line(f,"#ifndef IMDI_INCLUDED");
+ line(f,"#include <memory.h>");
+ line(f,"#include \"imdi_utl.h\"");
+ line(f,"#define IMDI_INCLUDED");
+ line(f,"#endif /* IMDI_INCLUDED */");
+ cr(f);
+
+ /* Declare our explicit pointer type */
+ line(f,"#ifndef DEFINED_pointer");
+ line(f,"#define DEFINED_pointer");
+ line(f,"typedef unsigned char * pointer;");
+ line(f,"#endif");
+ cr(f);
+
+ /* Declare our explicit structure access macros */
+
+#ifdef VERBOSE
+ printf("Declaring macros\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ /* Macros for accessing input table entries */
+ if (t->sort) {
+ if (t->it_xs) {
+ line(f,"/* Input table interp. index */");
+ line(f,"#define IT_IX(p, off) *((%s *)((p) + %d + (off) * %d))",
+ a->ords[f->ixet].name, t->ix_eo, t->it_ts);
+ cr(f);
+ if (t->wo_xs) {
+ line(f,"/* Input table input weighting enty */");
+ line(f,"#define IT_WE(p, off) *((%s *)((p) + %d + (off) * %d))",
+ a->ords[f->weet].name, t->we_eo, t->it_ts);
+ cr(f);
+ line(f,"/* Input table input offset value enty */");
+ line(f,"#define IT_VO(p, off) *((%s *)((p) + %d + (off) * %d))",
+ a->ords[f->voet].name, t->vo_eo, t->it_ts);
+ cr(f);
+ } else {
+ line(f,"/* Input table input weighting/offset value enty */");
+ line(f,"#define IT_WO(p, off) *((%s *)((p) + %d + (off) * %d))",
+ a->ords[f->woet].name, t->wo_eo, t->it_ts);
+ cr(f);
+ }
+ } else {
+ line(f,"/* Input table interp index, weighting and vertex offset */");
+ line(f,"#define IT_IT(p, off) *((%s *)((p) + %d + (off) * %d))",
+ a->ords[f->itet].name, 0, t->it_ts);
+ cr(f);
+ }
+
+ /* Sort primitive macro's */
+ line(f,"/* Sorting macros */");
+ if (t->wo_xs) {
+ line(f,"#define XFR(A, AA, B, BB) A = B; AA = BB;");
+ line(f,"#define CEX(A, AA, B, BB) if (A < B) { \\");
+ line(f," A ^= B; B ^= A; A ^= B; AA ^= BB; BB ^= AA; AA ^= BB; }");
+ line(f,"#define CXJ(A, B, BB, D, DD, L) if (A >= B) { D = B; DD = BB; goto L; }");
+ } else {
+ line(f,"#define XFR(A, B) A = B;");
+ line(f,"#define CEX(A, B) if (A < B) { A ^= B; B ^= A; A ^= B; }");
+ line(f,"#define CXJ(A, B, D, L) if (A >= B) { D = B; goto L; }");
+ }
+ line(f,"#define CJ(A, B, L) if (A >= B) goto L;");
+ cr(f);
+
+ } else { /* Simplex table */
+ if (t->it_xs) {
+ line(f,"/* Input table interp. index */");
+ line(f,"#define IT_IX(p, off) *((%s *)((p) + %d + (off) * %d))",
+ a->ords[f->ixet].name, t->ix_eo, t->it_ts);
+ cr(f);
+ line(f,"/* Input table simplex index enty */");
+ line(f,"#define IT_SX(p, off) *((%s *)((p) + %d + (off) * %d))",
+ a->ords[f->sxet].name, t->sx_eo, t->it_ts);
+ cr(f);
+ } else {
+ line(f,"/* Input table inter & simplex indexes */");
+ line(f,"#define IT_IT(p, off) *((%s *)((p) + %d + (off) * %d))",
+ a->ords[f->itet].name, 0, t->it_ts);
+ cr(f);
+ }
+ }
+
+ if (!t->sort) {
+ /* Macro for computing a simplex table entry */
+ line(f,"/* Simplex weighting table access */");
+ line(f,"#define SW_O(off) ((off) * %d)", t->sm_ts);
+ cr(f);
+
+ /* Macros for accessing the contents of the simplex table */
+ if (t->wo_xs) { /* If separate */
+ line(f,"/* Simplex table - get weighting value */");
+ line(f,"#define SX_WE(p, v) *((%s *)((p) + (v) * %d + %d))",
+ a->ords[f->weet].name, t->wo_es, t->we_eo);
+ cr(f);
+
+ line(f,"/* Simplex table - get offset value */");
+ line(f,"#define SX_VO(p, v) *((%s *)((p) + (v) * %d + %d))",
+ a->ords[f->voet].name, t->wo_es, t->vo_eo);
+ cr(f);
+
+ } else { /* Combined */
+ line(f,"/* Simplex table - get weighting/offset value */");
+ line(f,"#define SX_WO(p, v) *((%s *)((p) + (v) * %d))",
+ a->ords[f->woet].name, t->wo_es);
+ cr(f);
+ }
+ }
+
+ /* Macro for computing an interpolation table entry */
+ line(f,"/* Interpolation multi-dim. table access */");
+ line(f,"#define IM_O(off) ((off) * %d)", t->im_ts);
+ cr(f);
+
+ /* Macro for accessing an entry in the interpolation table */
+ line(f,"/* Interpolation table - get vertex values */");
+
+ if (t->im_fn > 0) {
+ /* Arguments to macro are cell base address, vertex offset, data offset */
+
+ if (f->imfvt == f->iafvt) { /* Table and accumulator are the same size */
+ if (!timp || t->im_fn == 1)
+ line(f,"#define IM_FE(p, v, c) *((%s *)((p) + (v) * %d + (c) * %d))",
+ a->ords[f->imfvt].name, t->im_oc, t->im_fs);
+ else {
+ line(f,"#define IM_TP(p, v) ((p) + (v) * %d)", t->im_oc);
+ line(f,"#define IM_FE(p, c) *((%s *)((p) + (c) * %d))",
+ a->ords[f->imfvt].name, t->im_fs);
+ }
+ } else { /* Expand single table entry to accumulator size */
+ if (!timp || t->im_fn == 1)
+ line(f,"#define IM_FE(p, v, c) ((%s)*((%s *)((p) + (v) * %d + (c) * %d)))",
+ a->ords[f->iafvt].name,
+ a->ords[f->imfvt].name, t->im_oc, t->im_fs);
+ else {
+ line(f,"#define IM_TP(p, v) ((p) + (v) * %d)", t->im_oc);
+ line(f,"#define IM_FE(p, c) ((%s)*((%s *)((p) + (c) * %d)))",
+ a->ords[f->iafvt].name,
+ a->ords[f->imfvt].name, t->im_fs);
+ }
+ }
+ }
+ if (t->im_pn > 0) {
+ /* Arguments to macro are cell base address, vertex offset */
+ /* There is no data offset since there can be only be one partial entry */
+
+ if (f->imfvt == f->iafvt) /* Table and accumulator are the same size */
+ line(f,"#define IM_PE(p, v) *((%s *)((p) + %d + (v) * %d))",
+ a->ords[f->impvt].name, t->im_fn * t->im_fs, t->im_oc);
+ else /* Expand single table entry to accumulator size */
+ line(f,"#define IM_PE(p, v) ((%s)*((%s *)((p) + %d + (v) * %d)))",
+ a->ords[f->iafvt].name,
+ a->ords[f->impvt].name, t->im_fn * t->im_fs, t->im_oc);
+ }
+ cr(f);
+
+ /* Macro for accessing an output table entry */
+ line(f,"/* Output table indexes */");
+ line(f,"#define OT_E(p, off) *((%s *)((p) + (off) * %d))",
+ a->ords[f->otvt].name, t->ot_ts);
+ cr(f);
+
+ /* =============================================== */
+
+#ifdef VERBOSE
+ printf("Starting interpolation function\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ /* Declare the function */
+ line(f,"void");
+ line(f, "imdi_k%d(",index);
+ line(f, "imdi *s, /* imdi context */");
+ line(f, "void **outp, /* pointer to output pointers */");
+ line(f, "int ostride, /* optional input component stride */");
+ line(f, "void **inp, /* pointer to input pointers */");
+ line(f, "int istride, /* optional input component stride */");
+ line(f, "unsigned int npix /* Number of pixels to process */");
+ line(f, ") {");
+ inc(f);
+
+ /* We need access to the imdi_imp */
+ line(f, "imdi_imp *p = (imdi_imp *)(s->impl);");
+
+ /* Declare the input pointers and init them */
+ for (e = 0; e < f->nip; e++) {
+ if (g->opt & opts_bwd) {
+ if (g->opt & opts_istride)
+ line(f, "%s *ip%d = (%s *)inp[%d] + (npix-1) * istride;",
+ a->ords[f->ipt[e]].name, e,
+ a->ords[f->ipt[e]].name, e);
+ else
+ line(f, "%s *ip%d = (%s *)inp[%d] + (npix-1) * %d;",
+ a->ords[f->ipt[e]].name, e,
+ a->ords[f->ipt[e]].name, e,
+ g->in.chi[e]);
+ } else {
+ g->opt |= opts_fwd; /* Make sure it's marked for what it is */
+ line(f, "%s *ip%d = (%s *)inp[%d];",
+ a->ords[f->ipt[e]].name, e, a->ords[f->ipt[e]].name, e);
+ }
+ }
+
+ /* Declare the output pointers and init them */
+ for (e = 0; e < f->nop; e++) {
+ if (g->opt & opts_bwd) {
+ if (g->opt & opts_ostride)
+ line(f, "%s *op%d = (%s *)outp[%d] + (npix-1) * ostride;",
+ a->ords[f->opt[e]].name, e,
+ a->ords[f->opt[e]].name, e);
+ else
+ line(f, "%s *op%d = (%s *)outp[%d] + (npix-1) * %d;",
+ a->ords[f->opt[e]].name, e,
+ a->ords[f->opt[e]].name, e,
+ g->out.chi[e]);
+ } else {
+ line(f, "%s *op%d = (%s *)outp[%d];",
+ a->ords[f->opt[e]].name, e, a->ords[f->opt[e]].name, e);
+ }
+ }
+
+ /* Declare and intialise the end pointer */
+ if (g->opt & opts_bwd) {
+ if (g->opt & opts_istride)
+ line(f, "%s *ep = (%s *)inp[0] - istride ;",
+ a->ords[f->ipt[0]].name,
+ a->ords[f->ipt[0]].name);
+ else
+ line(f, "%s *ep = (%s *)inp[0] - %d ;",
+ a->ords[f->ipt[0]].name,
+ a->ords[f->ipt[0]].name, g->in.chi[0]);
+ } else {
+ if (g->opt & opts_istride)
+ line(f, "%s *ep = (%s *)inp[0] + npix * istride ;",
+ a->ords[f->ipt[0]].name,
+ a->ords[f->ipt[0]].name);
+ else
+ line(f, "%s *ep = (%s *)inp[0] + npix * %d ;",
+ a->ords[f->ipt[0]].name,
+ a->ords[f->ipt[0]].name, g->in.chi[0]);
+ }
+
+ /* Declare and initialise the input table pointers */
+ for (e = 0; e < g->id; e++)
+ line(f,"pointer it%d = (pointer)p->in_tables[%d];",e,e);
+
+ /* Declare and initialise the output table pointers */
+ for (e = 0; e < g->od; e++)
+ line(f,"pointer ot%d = (pointer)p->out_tables[%d];",e,e);
+
+ if (!t->sort) {
+ /* Declare and initialise the Simplex weighting base pointer */
+ line(f,"pointer sw_base = (pointer)p->sw_table;");
+ }
+
+ /* Declare and initialise the Interpolation multidim base pointer */
+ line(f,"pointer im_base = (pointer)p->im_table;");
+
+ /* Figure out whether input channel reads can be used directly as table offsets */
+ t->it_ix = 1; /* Default use input table lookup to extract value */
+
+ if (g->in.packed != 0)
+ t->it_ix = 0; /* Extract will be done explicitly */
+
+ for (e = 0; e < g->id; e++) {
+ int ee = (g->in.pint != 0) ? 0 : e; /* bpch index */
+
+ if ((g->in.bov[e] + g->in.bpv[e]) <= 12)
+ continue; /* Table can do extract */
+
+ if (g->in.bov[e] != 0 || g->in.bpv[e] != g->in.bpch[ee]) {
+ t->it_ix = 0; /* Extract will be done explicitly */
+ break;
+ }
+ }
+
+ /* ------------------------------- */
+#ifdef VERBOSE
+ printf("Starting pixel processing loop\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ /* Start the pixel processing loop */
+ cr(f);
+ if (g->opt & opts_bwd) {
+ sline(f, "for(;ip0 != ep;");
+
+ if (g->opt & opts_istride)
+ for (e = 0; e < f->nip; e++)
+ mline(f, " ip%d -= istride,", e);
+ else
+ for (e = 0; e < f->nip; e++)
+ mline(f, " ip%d -= %d,", e, g->in.chi[e]);
+
+ if (g->opt & opts_ostride)
+ for (e = 0; e < f->nop; e++)
+ mline(f, " op%d -= ostride%s", e, ((e+1) < f->nop) ? "," : "");
+ else
+ for (e = 0; e < f->nop; e++)
+ mline(f, " op%d -= %d%s", e, g->out.chi[e], ((e+1) < f->nop) ? "," : "");
+ } else {
+ sline(f, "for(;ip0 != ep;");
+
+ if (g->opt & opts_istride)
+ for (e = 0; e < f->nip; e++)
+ mline(f, " ip%d += istride,", e);
+ else
+ for (e = 0; e < f->nip; e++)
+ mline(f, " ip%d += %d,", e, g->in.chi[e]);
+
+ if (g->opt & opts_ostride)
+ for (e = 0; e < f->nop; e++)
+ mline(f, " op%d += ostride%s", e, ((e+1) < f->nop) ? "," : "");
+ else
+ for (e = 0; e < f->nop; e++)
+ mline(f, " op%d += %d%s", e, g->out.chi[e], ((e+1) < f->nop) ? "," : "");
+ }
+ eline(f, ") {");
+ inc(f);
+
+ /* Declare output value accumulator(s) */
+ for (i = 0; i < t->im_fn; i++) {
+ line(f,"%s ova%d; /* Output value accumulator */",a->ords[f->iafvt].name,i);
+ }
+ for (; i < f->ian; i++) {
+ line(f,"%s ova%d; /* Output value partial accumulator */",a->ords[f->iapvt].name,i);
+ }
+
+ /* Context around interp/Simplex table lookup */
+ line(f, "{");
+ inc(f);
+
+ if (!t->sort)
+ line(f,"pointer swp;"); /* Declare Simplex weighting pointer */
+ line(f,"pointer imp;"); /* Declare Interpolation multidim pointer */
+
+ /* Declare the input weighting/vertex offset variables */
+ if (t->sort) {
+ for (e = 0; e < g->id; e++) {
+ if (t->wo_xs) {
+ line(f,"%s we%d; /* Weighting value variable */",
+ a->ords[f->wevt].name, e);
+ line(f,"%s vo%d; /* Vertex offset variable */",
+ a->ords[f->vovt].name, e);
+ } else {
+ line(f,"%s wo%d; /* Weighting value and vertex offset variable */",
+ a->ords[f->wovt].name, e);
+ }
+ }
+ }
+
+ /* Context around input table processing */
+ line(f, "{");
+ inc(f);
+
+ /* Declare the table index variables/input weighting/vertex offset variables */
+ if (t->sort) {
+ if (!t->it_xs)
+ line(f,"%s ti; /* Input table entry variable */",a->ords[f->itvt].name);
+ line(f,"%s ti_i; /* Interpolation index variable */",a->ords[f->ixvt].name);
+ } else {
+ if (t->it_xs) {
+ line(f,"%s ti_s; /* Simplex index variable */",a->ords[f->sxvt].name);
+ line(f,"%s ti_i; /* Interpolation index variable */",a->ords[f->ixvt].name);
+ } else {
+ line(f,"%s ti; /* Simplex+Interpolation index variable */",a->ords[f->itvt].name);
+ }
+ }
+
+ if (g->in.packed != 0) /* We need to unpack from a single read */
+ line(f,"%s rdv; /* Read value */",a->ords[f->ipt[0]].name);
+
+ if (t->it_ix == 0) {
+ int bv = 0;
+ for (e = 0; e < f->nip; e++) { /* Find largest input type */
+ if (f->ipt[e] > bv)
+ bv = f->ipt[e];
+ }
+ bv = nord(f, bv);
+ line(f,"%s chv; /* Channel value */",a->ords[bv].name);
+ f->chv_bits = a->ords[bv].bits;
+ }
+ cr(f);
+
+#ifdef VERBOSE
+ printf("Read code\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ /* For all the input channels */
+ for (e = 0; e < g->id; e++) {
+ char rde[50]; /* Read expression */
+ char toff[50]; /* Table offset expression */
+ int ee = (g->in.pint != 0) ? 0 : e; /* bpch index */
+
+ if (g->in.pint != 0) /* Pixel interleaved */
+ sprintf(rde,"ip0[%d]",e); /* Offset from single pointer */
+ else
+ sprintf(rde,"*ip%d",e); /* Pointer per channel */
+
+ if (g->in.packed != 0) {
+ if (e == 0)
+ line(f,"rdv = %s;",rde); /* Do single read */
+ sprintf(rde,"rdv"); /* Use read value for extraction */
+ }
+
+ if (t->it_ix == 0) {
+ if (g->in.bov[e] == 0 ) { /* No offset */
+ if (g->in.bpv[e] == g->in.bpch[ee]) /* No mask */
+ line(f,"chv = %s;",rde);
+ else /* Just mask */
+ line(f,"chv = (%s & %s);",rde, hmask(g->in.bpv[e]));
+ } else { /* Offset */
+ if ((g->in.bov[e] + g->in.bpv[e]) == g->in.bpch[ee])
+ line(f,"chv = (%s >> %d);",rde, g->in.bov[e]);
+ else { /* Offset and mask */
+ if (a->shfm || g->in.bpv[e] > 32) {
+ /* Extract using just shifts */
+ line(f,"chv = ((%s << %d) >> %d);", rde,
+ f->chv_bits - g->in.bpv[e] - g->in.bov[e],
+ f->chv_bits - g->in.bpv[e]);
+ } else {
+ /* Extract using shift and mask */
+ line(f,"chv = ((%s >> %d) & %s);",
+ rde, g->in.bov[e], hmask(g->in.bpv[e]));
+ }
+ }
+ }
+ sprintf(toff,"chv");
+ } else { /* No extraction */
+ sprintf(toff,"%s",rde);
+ }
+
+ if (t->sort) {
+ if (t->it_xs) {
+ line(f,"ti_i %s= IT_IX(it%d, %s);", e ? "+" : " ", e, toff);
+ if (t->wo_xs) {
+ line(f,"we%d = IT_WE(it%d, %s);", e, e, toff);
+ line(f,"vo%d = IT_VO(it%d, %s);", e, e, toff);
+ } else {
+ line(f,"wo%d = IT_WO(it%d, %s);", e, e, toff);
+ }
+ } else { /* All three combined */
+ line(f,"ti = IT_IT(it%d, %s);", e, toff);
+ if (a->shfm || t->wo_ab > 32) {
+ /* Extract using just shifts */
+ line(f,"wo%d = ((ti << %d) >> %d); "
+ "/* Extract weighting/vertex offset value */",
+ e, a->ords[f->wovt].bits - t->wo_ab, a->ords[f->wovt].bits - t->wo_ab);
+ line(f,"ti_i %s= (ti >> %d); "
+ "/* Extract interpolation table value */",
+ e ? "+" : " ", t->wo_ab);
+ } else {
+ /* Extract using shift and mask */
+ line(f,"wo%d = (ti & %s); "
+ "/* Extract weighting/vertex offset value */",
+ e, hmask(t->wo_ab));
+ line(f,"ti_i %s= (ti >> %d); "
+ "/* Extract interpolation table value */",
+ e ? "+" : " ", t->wo_ab);
+ }
+ }
+
+ } else { /* Simplex */
+ if (t->it_xs) {
+ /* ~~~~ should toff be forced to be a temp variable ?? */
+ /* (ie. force use of rde (above) if t->it_xs is nonz) */
+ line(f,"ti_i %s= IT_IX(it%d, %s);", e ? "+" : " ", e, toff);
+ line(f,"ti_s %s= IT_SX(it%d, %s);", e ? "+" : " ", e, toff);
+ } else {
+ line(f,"ti %s= IT_IT(it%d, %s);", e ? "+" : " ", e, toff);
+ }
+ }
+ }
+
+#ifdef VERBOSE
+ printf("Index extraction code\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ cr(f);
+
+ if (t->sort) {
+ /* Extract Simplex and Interpolation indexes from accumulator */
+ line(f,"imp = im_base + IM_O(ti_i); /* Compute interp. table entry pointer */");
+ } else {
+ if (t->it_xs) { /* Extract Simplex and Interpolation indexes from accumulator */
+ line(f,"swp = sw_base + SW_O(ti_s); /* Compute simplex table entry pointer */");
+ line(f,"imp = im_base + IM_O(ti_i); /* Compute interp. table entry pointer */");
+ } else {
+ line(f,"imp = im_base + IM_O(ti >> %d); "
+ "/* Extract interp. index and comp. entry */",
+ t->sx_ab);
+ if (a->shfm || t->sx_ab > 32) {
+ /* Extract using just shifts */
+ line(f,"swp = sw_base + SW_O((ti << %d) >> %d); "
+ "/* Extract simplex index & comp. entry */",
+ a->ords[f->itvt].bits - t->sx_ab, a->ords[f->itvt].bits - t->sx_ab);
+ } else {
+ /* Extract using shift and mask */
+ line(f,"swp = sw_base + SW_O(ti & %s); "
+ "/* Extract simplex index and comp. entry */",
+ hmask(t->sx_ab));
+ }
+ }
+ }
+
+ /* Do the explicit sort now */
+ if (t->sort) {
+ cr(f);
+ /* Sort from largest to smallest */
+ /* We can use a selection sort, or an insertions sort. */
+
+ line(f,"/* Sort weighting values and vertex offset values */");
+
+ if (g->id >= INSTHRESH) {
+ /* We do an insertion sort */
+ lineinc(f,"{");
+ if (t->wo_xs) {
+ line(f,"%s wet; /* Sort temporary */", a->ords[f->wevt].name);
+ line(f,"%s vot; /* Sort temporary */", a->ords[f->vovt].name);
+ } else
+ line(f,"%s wot; /* Sort temp variable */", a->ords[f->wovt].name);
+ cr(f);
+
+ for (i = 1; i < g->id; i++) {
+ int j;
+
+ j = i;
+ if (j < 2) { /* Only test & exchange needed */
+ if (t->wo_xs)
+ line(f,"CEX(we%d, vo%d, we%d, vo%d);",j-1,j-1,j,j);
+ else
+ line(f,"CEX(wo%d, wo%d);",j-1,j);
+
+ } else {
+ if (t->wo_xs)
+ line(f,"XFR(wet, vot, we%d, vo%d);",j,j);
+ else
+ line(f,"XFR(wot, wo%d);",j);
+ while (j > 0) {
+ if (j == i) { /* First test from i */
+ if (t->wo_xs)
+ line(f,"CJ(we%d, wet, shs%d);",j-1,i);
+ else
+ line(f,"CJ(wo%d, wot, shs%d);",j-1,i);
+ if (t->wo_xs)
+ line(f,"XFR(we%d, vo%d, we%d, vo%d);",j,j,j-1,j-1);
+ else
+ line(f,"XFR(wo%d, wo%d);",j,j-1);
+ } else {
+ if (t->wo_xs)
+ line(f,"CXJ(we%d, wet, vot, we%d, vo%d, shs%d);",j-1,j,j,i);
+ else
+ line(f,"CXJ(wo%d, wot, wo%d, shs%d);",j-1,j,i);
+ if (t->wo_xs)
+ line(f,"XFR(we%d, vo%d, we%d, vo%d);",j,j,j-1,j-1);
+ else
+ line(f,"XFR(wo%d, wo%d);",j,j-1);
+ }
+ j--;
+ }
+ if (t->wo_xs)
+ line(f,"XFR(we%d, vo%d, wet, vot);",j,j);
+ else
+ line(f,"XFR(wo%d, wot);",j);
+ niline(f,"shs%d:;",i);
+ }
+ }
+ decline(f,"}");
+
+ } else {
+ /* Use a selection sort */
+ for (i = 0; i < (g->id-1); i++) {
+ for (e = i+1; e < g->id; e++) {
+ if (t->wo_xs)
+ line(f,"CEX(we%d, vo%d, we%d, vo%d);",i,i,e,e);
+ else
+ line(f,"CEX(wo%d, wo%d);",i,e);
+ }
+ }
+ }
+ }
+
+ /* End of input table processing context */
+ dec(f);
+ line(f,"}");
+
+ line(f,"{"); /* Context around vertex lookup and accumulation */
+ inc(f);
+
+ /* Declare vertex offset and weight variables */
+ if (t->sort && t->wo_xs == 0) {
+ line(f,"%s nvof; /* Next vertex offset value */",a->ords[f->vovt].name);
+ } else {
+ if (!t->wo_xs) /* If combined in table */
+ line(f,"%s vowr; /* Vertex offset/weight value */",a->ords[f->wovt].name);
+ }
+ line(f,"%s vof; /* Vertex offset value */",a->ords[f->vovt].name);
+ line(f,"%s vwe; /* Vertex weighting */",a->ords[f->wevt].name);
+ if (timp && t->im_fn > 1)
+ line(f,"pointer timp; /* Temporary interpolation table pointer */");
+ cr(f);
+
+#ifdef VERBOSE
+ printf("Vertex offset and weight code\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ /* For each vertex in the simplex */
+ for (e = 0; e < (g->id +1); e++) {
+
+ if (t->sort) {
+
+ if (e == 0) {
+ line(f,"vof = 0; /* First vertex offset is 0 */");
+ } else {
+ if (t->wo_xs)
+ line(f,"vof += vo%d; /* Move to next vertex */",e-1);
+ else
+ line(f,"vof += nvof; /* Move to next vertex */");
+ }
+
+ /* Extract the vertex offset and weight values from the sorted input values */
+ if (e < g->id && !t->wo_xs) {
+ if (a->shfm || t->vo_ab > 32) {
+ /* Extract using just shifts */
+ line(f,"nvof = ((wo%d << %d) >> %d); "
+ "/* Extract offset value */",
+ e, a->ords[f->vovt].bits - t->vo_ab, a->ords[f->vovt].bits - t->vo_ab);
+ line(f,"wo%d = (wo%d >> %d); "
+ " /* Extract weighting value */",
+ e, e, t->vo_ab);
+ } else {
+ /* Extract using shift and mask */
+ line(f,"nvof = (wo%d & %s); "
+ "/* Extract offset value */",
+ e, hmask(t->vo_ab));
+ line(f,"wo%d = (wo%d >> %d); "
+ " /* Extract weighting value */",
+ e, e, t->vo_ab);
+ }
+ }
+ /* Compute the weighting value */
+ if (!t->wo_xs) {
+ if (e == 0) {
+ line(f,"vwe = %d - wo%d; /* Baricentric weighting */", 1 << g->prec, e);
+ } else if (e < g->id) {
+ line(f,"vwe = wo%d - wo%d; /* Baricentric weighting */", e-1, e);
+ } else {
+ line(f,"vwe = wo%d; /* Baricentric weighting */", e-1);
+ }
+ } else {
+ if (e == 0) {
+ line(f,"vwe = %d - we%d; /* Baricentric weighting */", 1 << g->prec, e);
+ } else if (e < g->id) {
+ line(f,"vwe = we%d - we%d; /* Baricentric weighting */", e-1, e);
+ } else {
+ line(f,"vwe = we%d; /* Baricentric weighting */", e-1);
+ }
+ }
+
+ } else { /* Not sort */
+ /* Read the vertex offset and weight values from the simplex table */
+ if (t->wo_xs) { /* If separate */
+ line(f,"vof = SX_VO(swp, %d); /* Read vertex offset value */", e);
+ line(f,"vwe = SX_WE(swp, %d); /* Read vertex weighting value */", e);
+ } else { /* If combined in table */
+ line(f,"vowr = SX_WO(swp, %d); /* Read vertex offset+weighting values */", e);
+ if (a->shfm || t->vo_ab > 32) {
+ /* Extract using just shifts */
+ line(f,"vof = ((vowr << %d) >> %d); "
+ "/* Extract offset value */",
+ a->ords[f->vovt].bits - t->vo_ab, a->ords[f->vovt].bits - t->vo_ab);
+ line(f,"vwe = (vowr >> %d); "
+ "/* Extract weighting value */",
+ t->vo_ab);
+ } else {
+ /* Extract using shift and mask */
+ line(f,"vof = (vowr & %s); "
+ "/* Extract offset value */",
+ hmask(t->vo_ab));
+ line(f,"vwe = (vowr >> %d); "
+ "/* Extract weighting value */",
+ t->vo_ab);
+ }
+ }
+ }
+
+ /* Lookup the vertex value, weight it, and accumulate it into output value */
+ if (timp && t->im_fn > 1)
+ line(f,"timp = IM_TP(imp, vof); /* Vertex address */");
+ for (i = 0; i < f->ian; i++) { /* For each output accumulation chunk */
+ if (i < t->im_fn) { /* Full entry */
+ if (!timp || t->im_fn == 1)
+ line(f,"ova%d %s= IM_FE(imp, vof, %d) * vwe; "
+ "/* Accumulate weighted output values */",
+ i, e ? "+" : " ", i);
+ else
+ line(f,"ova%d %s= IM_FE(timp, %d) * vwe; "
+ "/* Accumulate weighted output values */",
+ i, e ? "+" : " ", i);
+ } else /* One partial entry */
+ line(f,"ova%d %s= IM_PE(imp, vof) * vwe; "
+ "/* Accumulate last weighted output values */",
+ i, e ? "+" : " ");
+ }
+ }
+
+ dec(f);
+ line(f, "}"); /* End of output value lookup context */
+
+ dec(f);
+ line(f, "}"); /* End of output value accumulation context */
+
+ /* Start of output lookup and write */
+ line(f,"{");
+ inc(f);
+
+#ifdef VERBOSE
+ printf("Output table code\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ {
+ char wre[50]; /* Write destination expression */
+
+ if (g->out.packed != 0) /* We need to pack results into a single write */
+ line(f,"%s wrv; /* Write value */",a->ords[f->ipt[0]].name);
+
+ /* Declare temporary to hold index into output lookup table */
+ line(f,"%s oti; /* Vertex offset value */",a->ords[f->otit].name);
+ if (g->oopt & OOPTS_CHECK)
+ line(f,"%s otv; /* Output temporary value */",a->ords[f->otvt].name);
+
+ /* For each accumulator value */
+ /* (Assume they are in output order for the moment ?) */
+ for (e = i = 0; i < f->ian; i++) { /* For each output accumulation chunk */
+ int vpa = i < t->im_fn ? t->im_fv : t->im_pv; /* Chanel values per accumulator */
+ int oat = i < t->im_fn ? f->iafvt : f->iapvt; /* Output accumulator type */
+ int ee; /* Relative e to this accumulator */
+
+ /* For each output value in this accumulator */
+ for (ee = 0; ee < vpa && e < g->od; ee++, e++) {
+ int off, size; /* Bits to be extracted */
+
+ /* Extract wanted 8 bits from the 8.8 bit result in accumulator */
+ /* (or 16 bits from 16.16) */
+ off = ee * f->iaovb + (f->iaovb - g->prec);
+ size = g->prec;
+
+ if (e == 0 || g->out.packed == 0) {
+ if (g->out.pint != 0) /* Pixel interleaved */
+ sprintf(wre,"op0[%d]",e); /* Offset from single pointer */
+ else
+ sprintf(wre,"*op%d",e); /* Pointer per channel */
+ }
+
+ if (a->shfm || size > 32) {
+ /* Extract using just shifts */
+#ifdef ROUND
+ line(f,"oti = (((ova%d + (1 << %d)) << %d) >> %d); "
+ "/* Extract integer part of result */",
+ i, off-1, a->ords[oat].bits - off - size, a->ords[oat].bits - size);
+#else
+ line(f,"oti = ((ova%d << %d) >> %d); "
+ "/* Extract integer part of result */",
+ i, a->ords[oat].bits - off - size, a->ords[oat].bits - size);
+#endif
+ } else {
+ /* Extract using shift and mask */
+#ifdef ROUND
+ line(f,"oti = (((ova%d + 0x%x) >> %d) & %s); "
+ "/* Extract integer part of result */",
+ i, (1 << off-1), off, hmask(size));
+#else
+ line(f,"oti = ((ova%d >> %d) & %s); "
+ "/* Extract integer part of result */",
+ i, off, hmask(size));
+#endif
+ }
+
+ if (g->oopt & OOPT(oopts_check,e)) { /* Lookup with check */
+ line(f,"otv = OT_E(ot%d, oti); /* Fetch result */", e);
+ line(f,"if (otv != p->checkv[%d]) /* Do output value check */", e);
+ line(f," p->checkf |= (1 << %d); /* Set check flag */", e);
+ if (g->out.packed != 0) {
+ if (g->oopt & OOPT(oopts_skip,e))
+ return 2; /* Error, can't skip on pixel interleaved */
+ line(f,"wrv %s= otv;", e ? "+" : "", e);
+ } else {
+ if (g->oopt & OOPT(oopts_skip,e)) {
+ line(f,"if ((p->skipf & (1 << %d)) == 0) /* If not being skipped */", e);
+ line(f," %s = otv; /* Write result */", wre);
+ } else
+ line(f,"%s = otv; /* Write result */", wre);
+ }
+ } else { /* Normal lookup output table */
+ /* Lookup in output table and write to destination */
+ if (g->out.packed != 0) {
+ if (g->oopt & OOPT(oopts_skip,e))
+ return 2; /* Error, can't skip on pixel interleaved */
+ line(f,"wrv %s= OT_E(ot%d, oti);", e ? "+" : "", e);
+ } else {
+ if (g->oopt & OOPT(oopts_skip,e)) {
+ line(f,"if ((p->skipf & (1 << %d)) == 0) /* If not being skipped */", e);
+ line(f," %s = OT_E(ot%d, oti); /* Write result */", wre, e);
+ } else
+ line(f,"%s = OT_E(ot%d, oti); /* Write result */", wre, e);
+ }
+ }
+ }
+ }
+
+ if (g->out.packed != 0) { /* Write out the accumulated value */
+ line(f,"%s = wrv; /* Write result */", wre);
+ }
+ }
+
+ /* The end of the output lookup and write */
+ dec(f);
+ line(f, "}");
+
+ /* The end of the pixel processing loop */
+ dec(f);
+ line(f, "}");
+
+ /* The end of the function */
+ dec(f);
+ line(f, "}");
+
+ /* Undefine all the macros */
+ if (t->sort) {
+ if (t->it_xs) {
+ if (t->wo_xs) {
+ line(f,"#undef IT_WE");
+ line(f,"#undef IT_VO");
+ } else
+ line(f,"#undef IT_WO");
+ line(f,"#undef IT_IX");
+ } else {
+ line(f,"#undef IT_IT");
+ }
+ line(f,"#undef CXJ");
+ line(f,"#undef CJ");
+ line(f,"#undef XFR");
+ line(f,"#undef CEX");
+ } else {
+ if (t->it_xs) {
+ line(f,"#undef IT_IX");
+ line(f,"#undef IT_SX");
+ } else {
+ line(f,"#undef IT_IT");
+ }
+
+ line(f,"#undef SW_O");
+ if (t->wo_xs) {
+ line(f,"#undef SX_WE");
+ line(f,"#undef SX_VO");
+ } else {
+ line(f,"#undef SX_WO");
+ }
+ }
+ line(f,"#undef IM_O");
+ if (t->im_fn > 0) {
+ if (timp && t->im_fn > 1)
+ line(f,"#undef IM_TP");
+ line(f,"#undef IM_FE");
+ }
+ if (t->im_pn > 0) {
+ line(f,"#undef IM_PE");
+ }
+ line(f,"#undef OT_E");
+
+ /* =============================================== */
+#ifdef VERBOSE
+ printf("Done interpolation code\n"); fflush(stdout);
+#endif /* VERBOSE */
+
+ /* =============================================== */
+
+ /* !genspec and tabspec delta code! */
+ /* We generate code that updates any entries in the genspec and */
+ /* tabpsec strucures that are different for this kernel, */
+ /* compared to the previously generated kernel. */
+ /* In this way, we save a lot of space, at the price */
+ /* of having to access the table of kernels sequentially. */
+
+ /* If the genspec of tabspec structures are modified, */
+ /* then corresponding changes need to be made to the code here. */
+ {
+ int i;
+ int s_stres, s_itres; /* Save values */
+ imdi_options s_opt;
+
+ s_stres = g->stres;
+ s_itres = g->itres;
+ s_opt = g->opt;
+ g->stres = f->sxmxres; /* Set maximum values */
+ g->itres = f->ixmxres;
+ g->opt &= ~opts_splx; /* Don't care about this, only about opts_splx/sort */
+ if (frv == 0) { /* Simplex algorithm wasn't possible */
+ g->opt &= ~opts_splx_sort; /* Therefore we don't care about preference */
+ g->opt &= ~opts_sort_splx;
+ }
+
+ /* Declare the genspec & tabspec update function */
+ cr(f);
+ line(f,"void");
+ line(f, "imdi_k%d_gentab(",index);
+ line(f, "genspec *g, /* structure to be updated */");
+ line(f, "tabspec *t /* structure to be updated */");
+ line(f, ") {");
+ inc(f);
+
+#define GSET_ENTRY(KEY) if (g->KEY != og->KEY) line(f, "g->%s = %d;",#KEY,g->KEY)
+#define GSET_ARRAY(KEY,IX) if (g->KEY[IX] != og->KEY[IX]) line(f, "g->%s[%d] = %d;",#KEY,IX,g->KEY[IX])
+#define TSET_ENTRY(KEY) if (t->KEY != ot->KEY) line(f, "t->%s = %d;",#KEY,t->KEY)
+#define TSET_ARRAY(KEY,IX) if (t->KEY[IX] != ot->KEY[IX]) line(f, "t->%s[%d] = %d;",#KEY,IX,t->KEY[IX])
+
+ /* Create code that updates the genspec structure from og to g */
+ GSET_ENTRY(prec);
+ GSET_ENTRY(id);
+ GSET_ENTRY(od);
+ GSET_ENTRY(irep);
+ GSET_ENTRY(orep);
+ GSET_ENTRY(in_signed);
+ GSET_ENTRY(out_signed);
+
+ /* pixlayout structure */
+ for (i = 0; i < IXDIDO; i++) {
+ GSET_ARRAY(in.bpch,i);
+ GSET_ARRAY(in.chi,i);
+ GSET_ARRAY(in.bov,i);
+ GSET_ARRAY(in.bpv,i);
+ }
+ GSET_ENTRY(in.pint);
+ GSET_ENTRY(in.packed);
+
+ /* pixlayout structure */
+ for (i = 0; i < IXDIDO; i++) {
+ GSET_ARRAY(out.bpch,i);
+ GSET_ARRAY(out.chi,i);
+ GSET_ARRAY(out.bov,i);
+ GSET_ARRAY(out.bpv,i);
+ }
+ GSET_ENTRY(out.pint);
+ GSET_ENTRY(out.packed);
+
+ GSET_ENTRY(oopt);
+ GSET_ENTRY(opt);
+ GSET_ENTRY(itres);
+ GSET_ENTRY(stres);
+
+ for (i = 0; i < 100; i++) {
+ GSET_ARRAY(kkeys,i);
+ }
+ for (i = 0; i < 100; i++) {
+ GSET_ARRAY(kdesc,i);
+ }
+ for (i = 0; i < 100; i++) {
+ GSET_ARRAY(kname,i);
+ }
+
+ /* Create code that updates the tabspec structure from og to g */
+ TSET_ENTRY(sort);
+ TSET_ENTRY(it_xs);
+ TSET_ENTRY(wo_xs);
+ TSET_ENTRY(it_ix);
+ TSET_ENTRY(it_ab);
+ TSET_ENTRY(it_ts);
+ TSET_ENTRY(ix_ab);
+ TSET_ENTRY(ix_es);
+ TSET_ENTRY(ix_eo);
+ TSET_ENTRY(sx_ab);
+ TSET_ENTRY(sx_es);
+ TSET_ENTRY(sx_eo);
+ TSET_ENTRY(sm_ts);
+ TSET_ENTRY(wo_ab);
+ TSET_ENTRY(wo_es);
+ TSET_ENTRY(wo_eo);
+ TSET_ENTRY(we_ab);
+ TSET_ENTRY(we_es);
+ TSET_ENTRY(we_eo);
+ TSET_ENTRY(vo_ab);
+ TSET_ENTRY(vo_es);
+ TSET_ENTRY(vo_eo);
+ TSET_ENTRY(vo_om);
+ TSET_ENTRY(im_cd);
+ TSET_ENTRY(im_ts);
+ TSET_ENTRY(im_oc);
+ TSET_ENTRY(im_fs);
+ TSET_ENTRY(im_fn);
+ TSET_ENTRY(im_fv);
+ TSET_ENTRY(im_ps);
+ TSET_ENTRY(im_pn);
+ TSET_ENTRY(im_pv);
+ TSET_ENTRY(ot_ts);
+ for (i = 0; i < IXDO; i++) {
+ TSET_ARRAY(ot_off, i);
+ }
+ for (i = 0; i < IXDO; i++) {
+ TSET_ARRAY(ot_bits,i);
+ }
+
+#undef GSET_ENTRY
+#undef GSET_ARRAY
+#undef TSET_ENTRY
+#undef TSET_ARRAY
+
+ /* The end of the function */
+ dec(f);
+ line(f, "}");
+
+ g->opt = s_opt; /* Restore entry values */
+ g->stres = s_stres;
+ g->itres = s_itres;
+ }
+
+ /* =============================================== */
+
+ cr(f); cr(f); cr(f); cr(f); cr(f); cr(f);
+
+ return frv;
+}
+
+
+/* Return bits needed to store index into table of */
+/* given resolution and dimensionality. */
+static int
+calc_bits(
+int dim,
+int res) {
+
+ return (int)ceil(log((double)res) * (double)dim/log(2.0) - 1e-14);
+}
+
+/* Return maximum resolution possible given dimensionality */
+/* and number of index bits. */
+static int
+calc_res(
+int dim,
+int bits) {
+ double fres;
+
+ fres = log(2.0) * (double)bits/(double)dim;
+ if (fres > 12 || (fres = exp(fres)) > 65536.0)
+ fres = 65536.0; /* Limit to a sane value */
+ return (int)(fres + 1e-14);
+}
+
+/* Return bits needed to store a relative offset of 1, */
+/* into a table of given resolution, dimensionality , and */
+/* entry size. */
+static int
+calc_obits(
+int dim,
+int res,
+int esize) {
+ double off; /* Maximum diagonal offset value */
+ int bits;
+
+ if (res == 0 || res == 1)
+ return 0;
+ if (dim == 1)
+ off = esize;
+ else {
+ off = (double)esize * floor(exp(log((double)res) * dim - log(res-1.0)));
+ }
+
+ bits = (int)ceil(log(off)/log(2.0) - 1e-14);
+ return bits;
+}
+
+/* Return maximum resolution possible given dimensionality */
+/* number of index bits, and entry size */
+static int
+calc_ores(
+int dim,
+int bits,
+int esize) {
+ int res;
+
+ /* Find resolution. Stop at arbitrary 65536 */
+ for (res = 1; res < 65537; res++) {
+ int bn;
+ bn = calc_obits(dim, res, esize);
+ if (bn > bits) {
+ return res-1;
+ }
+ }
+ return res-1;
+}
+
+
+
+/* Output the introductory comments */
+static void
+doheader(
+ fileo *f
+) {
+ genspec *g = f->g;
+ tabspec *t = f->t;
+ mach_arch *a = f->a;
+ int e;
+
+ /* - - - - - - - - - - - - */
+ /* Output file title block */
+ line(f,"/* Integer Multi-Dimensional Interpolation */");
+ line(f,"/* Interpolation Kernel Code */");
+ line(f,"/* Generated by cgen */");
+ line(f,"/* Copyright 2000 - 2007 Graeme W. Gill */");
+ line(f,"/* All rights reserved. */");
+ line(f,"/* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- */\n");
+ line(f,"/* see the License.txt file for licencing details.*/\n");
+ cr(f);
+
+ /* - - - - - - - - - - - - */
+ /* Output the specification */
+ line(f,"/*");
+ line(f," Interpolation kernel specs:");
+ cr(f);
+ line(f," Input channels per pixel = %d",g->id);
+ for (e = 0; e < g->id; e++) {
+ line(f," Input channel %d bits = %d",e, g->in.bpch[e]);
+ line(f," Input channel %d increment = %d",e, g->in.chi[e]);
+ }
+ if (g->in.pint != 0)
+ line(f," Input is channel interleaved");
+ else
+ line(f," Input is plane interleaved");
+
+ if (g->in.packed != 0)
+ line(f," Input channels are packed into one word");
+ else
+ line(f," Input channels are separate words");
+
+ if (t->it_ix)
+ line(f," Input value extraction is done in input table lookup");
+ cr(f);
+
+ line(f," Output channels per pixel = %d",g->od);
+ for (e = 0; e < g->od; e++) {
+ line(f," Output channel %d bits = %d",e, g->out.bpch[e]);
+ line(f," Output channel %d increment = %d",e, g->out.chi[e]);
+ if (g->oopt & OOPT(oopts_check,e))
+ line(f," Output channel %d has value check",e);
+ if (g->oopt & OOPT(oopts_skip,e))
+ line(f," Output channel %d has skip available",e);
+ }
+ if (g->out.pint != 0)
+ line(f," Output is channel interleaved");
+ else
+ line(f," Output is plane interleaved");
+ if (g->out.packed != 0)
+ line(f," Output channels are packed into one word");
+ else
+ line(f," Output channels are separate words");
+ cr(f);
+
+ line(f," Basic Internal precision bits = %d",g->prec);
+ if (t->sort)
+ line(f," Weight+voffset bits = %d",t->sx_ab);
+ else
+ line(f," Simplex table index bits = %d",t->sx_ab);
+ line(f," Interpolation table index bits = %d",t->ix_ab);
+ if (!t->sort)
+ line(f," Simplex table max resolution = %d",f->sxmxres);
+ line(f," Interpolation table max resolution = %d",f->ixmxres);
+ cr(f);
+ line(f," Processing direction is %s",g->opt & opts_bwd ? "backwards" : "forwards" );
+ line(f," Input stride is %ssupported",g->opt & opts_istride ? "" : "not " );
+ line(f," Output stride is %ssupported",g->opt & opts_ostride ? "" : "not " );
+ if (g->opt & opts_splx_sort)
+ line(f," Prefer simplex over sort algorithm");
+ if (g->opt & opts_sort_splx)
+ line(f," Prefer sort over simplex");
+ line(f," */");
+ cr(f);
+
+ /* - - - - - - - - - - - - */
+ line(f,"/*");
+ line(f," Machine architecture specs:");
+ cr(f);
+ if (a->bigend != 0)
+ line(f," Big Endian");
+ else
+ line(f," Little endian");
+
+ if (a->uwa != 0)
+ line(f," Using maximum sized memory accesses where possible");
+ else
+ line(f," Reading and writing pixel values separately");
+
+ line(f," Pointer size = %d bits",a->pbits);
+ cr(f);
+
+ for (e = 0; e < a->nords; e++) {
+ line(f," Ordinal size %2d bits is known as '%s'",
+ a->ords[e].bits,a->ords[e].name);
+ }
+ line(f," Natural ordinal is '%s'", a->ords[a->natord].name);
+ cr(f);
+
+ for (e = 0; e < a->nints; e++) {
+ line(f," Integer size %2d bits is known as '%s'",
+ a->ints[e].bits,a->ints[e].name);
+ }
+ line(f," Natural integer is '%s'", a->ints[a->natint].name);
+ cr(f);
+
+ line(f," */");
+ cr(f);
+}
+
+
+/* ---------------------------------------- */
+/* Architecture support */
+/* Find an ordinal with at least bits size */
+/* Return -1 if failed */
+int findord(
+fileo *f,
+int bits
+) {
+ mach_arch *a = f->a;
+ int i;
+
+ for (i = 0; i < a->nords; i++) {
+ if (a->ords[i].bits >= bits)
+ return i;
+ }
+ return -1;
+}
+
+/* Round ordinal type up to natural size */
+int nord(
+ fileo *f,
+ int ov
+) {
+ if (ov >= 0 && ov < f->a->natord)
+ ov = f->a->natord;
+ return ov;
+}
+
+/* Find an ordinal with at least bits size, */
+/* or natural size, whichever is greater. */
+/* Return -1 if failed */
+int findnord(
+ fileo *f,
+ int bits
+) {
+ int ov;
+
+ ov = findord(f, bits);
+ ov = nord(f, ov);
+ return ov;
+}
+
+/* Find an integer with at least bits size */
+/* Return -1 if failed */
+int findint(
+ fileo *f,
+ int bits
+) {
+ mach_arch *a = f->a;
+ int i;
+
+ for (i = 0; i < a->nints; i++) {
+ if (a->ints[i].bits >= bits)
+ return i;
+ }
+ return -1;
+}
+
+/* Round integer type up to natural size */
+int nint(
+ fileo *f,
+ int iv
+) {
+ if (iv >= 0 && iv < f->a->natint)
+ iv = f->a->natint;
+ return iv;
+}
+
+/* Find an interger with at least bits size, */
+/* or natural size, whichever is greater. */
+/* Return -1 if failed */
+int findnint(
+ fileo *f,
+ int bits
+) {
+ int iv;
+
+ iv = findint(f, bits);
+ iv = nint(f, iv);
+ return iv;
+}
+
+
+/* ------------------------------------ */
+/* File output support */
+
+/* Output a line to the file (including trailing \n) */
+void
+line(fileo *f, char *fmt, ...)
+{
+ int i;
+ va_list args;
+
+ /* Indent to the correct level */
+ for (i = 0; i < f->indt; i++)
+ fprintf(f->of," ");
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+ fprintf(f->of, "\n");
+}
+
+/* Output the start of a line to the file) */
+void
+sline(fileo *f, char *fmt, ...)
+{
+ int i;
+ va_list args;
+
+ /* Indent to the correct level */
+ for (i = 0; i < f->indt; i++)
+ fprintf(f->of," ");
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+}
+
+/* Output the middle of a line to the file) */
+void
+mline(fileo *f, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+}
+
+/* Output the end of a line to the file (including trailing \n) */
+void
+eline(fileo *f, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+ fprintf(f->of, "\n");
+}
+
+/* Output a line to the file (including trailing \n) */
+/* No indent */
+void
+niline(fileo *f, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+ fprintf(f->of, "\n");
+}
+
+/* Output one line and increment indent */
+void lineinc(fileo *f, char *fmt, ...) {
+ int i;
+ va_list args;
+
+ /* Indent to the correct level */
+ for (i = 0; i < f->indt; i++)
+ fprintf(f->of," ");
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+ fprintf(f->of, "\n");
+ f->indt++;
+}
+
+/* Decrement indent and output one line */
+void decline(fileo *f, char *fmt, ...) {
+ int i;
+ va_list args;
+
+ f->indt--;
+ /* Indent to the correct level */
+ for (i = 0; i < f->indt; i++)
+ fprintf(f->of," ");
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+ fprintf(f->of, "\n");
+}
+
+
+/* ------------------------------------ */
+
+
+
+
diff --git a/imdi/ctest.c b/imdi/ctest.c
new file mode 100644
index 0000000..caf0692
--- /dev/null
+++ b/imdi/ctest.c
@@ -0,0 +1,156 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+
+/* Test frame for cgen.c IMDI generation code */
+/*
+ * Copyright 2000 - 2006 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.
+ */
+
+#include "imdi.h"
+#include "imdi_tab.h"
+
+
+int
+main(void) {
+ int rv;
+ genspec gs, ogs;
+ tabspec ts, ots;
+ mach_arch ar;
+ FILE *kcode;
+
+ /* Zero out the gen and tabspecs, to give diff a place to start */
+ memset((void *)&ogs, 0, sizeof(genspec));
+ memset((void *)&gs, 0, sizeof(genspec));
+ memset((void *)&ots, 0, sizeof(tabspec));
+ memset((void *)&ts, 0, sizeof(tabspec));
+
+ printf("Testing gen_c_kernel\n");
+
+ if ((kcode = fopen("imdi_k99.c","w")) == NULL) {
+ printf("Couldn't open 'imdi_k99.c'\n");
+ return -1;
+ }
+
+ /* Setup an interpolation kernel specification */
+ gs.id = 4; /* Number of input dimensions */
+
+ gs.in.pint = 1; /* Flag - nonz if pixel interleaved */
+ gs.in.packed = 0; /* Flag - nonz if channels packed into one read */
+
+ gs.in.bpch[0] = 8; /* Bits per channel */
+ gs.in.chi[0] = 4; /* Channel increment */
+ gs.in.bov[0] = 0; /* Bit offset to value within channel */
+ gs.in.bpv[0] = 8; /* Bits per value within channel */
+
+ gs.in.bpch[1] = 8; /* Bits per channel */
+ gs.in.chi[1] = 4; /* Channel increment */
+ gs.in.bov[1] = 0; /* Bit offset to value within channel */
+ gs.in.bpv[1] = 8; /* Bits per value within channel */
+
+ gs.in.bpch[2] = 8; /* Bits per channel */
+ gs.in.chi[2] = 4; /* Channel increment */
+ gs.in.bov[2] = 0; /* Bit offset to value within channel */
+ gs.in.bpv[2] = 8; /* Bits per value within channel */
+
+ gs.in.bpch[3] = 8; /* Bits per channel */
+ gs.in.chi[3] = 4; /* Channel increment */
+ gs.in.bov[3] = 0; /* Bit offset to value within channel */
+ gs.in.bpv[3] = 8; /* Bits per value within channel */
+
+ gs.od = 1; /* Number of output dimensions */
+
+ gs.out.pint = 1; /* Flag - nonz if pixel interleaved */
+ gs.out.packed = 0; /* Flag - nonz if channels packed into one write */
+
+ gs.out.bpch[0] = 8; /* Bits per channel */
+ gs.out.chi[0] = 1; /* Channel increment */
+ gs.out.bov[0] = 0; /* Bit offset to value within channel */
+ gs.out.bpv[0] = 8; /* Bits per value within channel */
+
+ gs.out.bpch[1] = 8; /* Bits per channel */
+ gs.out.chi[1] = 4; /* Channel increment */
+ gs.out.bov[1] = 0; /* Bit offset to value within channel */
+ gs.out.bpv[1] = 8; /* Bits per value within channel */
+
+ gs.out.bpch[2] = 8; /* Bits per channel */
+ gs.out.chi[2] = 4; /* Channel increment */
+ gs.out.bov[2] = 0; /* Bit offset to value within channel */
+ gs.out.bpv[2] = 8; /* Bits per value within channel */
+
+ gs.out.bpch[3] = 8; /* Bits per channel */
+ gs.out.chi[3] = 4; /* Channel increment */
+ gs.out.bov[3] = 0; /* Bit offset to value within channel */
+ gs.out.bpv[3] = 8; /* Bits per value within channel */
+
+ gs.out.bpch[4] = 8; /* Bits per channel */
+ gs.out.chi[4] = 4; /* Channel increment */
+ gs.out.bov[4] = 0; /* Bit offset to value within channel */
+ gs.out.bpv[4] = 8; /* Bits per value within channel */
+
+ gs.out.bpch[5] = 8; /* Bits per channel */
+ gs.out.chi[5] = 4; /* Channel increment */
+ gs.out.bov[5] = 0; /* Bit offset to value within channel */
+ gs.out.bpv[5] = 8; /* Bits per value within channel */
+
+ gs.opt = opts_none; /* Direction and stride options */
+
+ gs.prec = 8; /* Precsision needed */
+ gs.itres = 16; /* Interpolation table resolution */
+ gs.stres = 17; /* Simplex table resolution */
+
+ /* Setup a machine architecture */
+
+ ar.bigend = 0; /* Non-zero if this is a bigendian architecture */
+ ar.uwa = 0; /* Use wide memory access */
+ ar.shfm = 0; /* Use shifts to mask values */
+ ar.oscale = 8; /* Has scaled indexing up to * 8 */
+ ar.smmul = 0; /* Doesn't have fast small multiply for index scaling */
+
+ ar.pbits = 32; /* Number of bits in a pointer */
+
+ ar.nords = 3; /* Number of ord types */
+ ar.ords[0].bits = 8;
+ ar.ords[0].name = "unsigned char";
+ ar.ords[0].align = 1;
+ ar.ords[1].bits = 16;
+ ar.ords[1].name = "unsigned short";
+ ar.ords[1].align = 1;
+ ar.ords[2].bits = 32;
+ ar.ords[2].name = "unsigned int";
+ ar.ords[2].align = 1;
+#ifdef ALLOW64
+ ar.ords[3].bits = 64;
+ ar.ords[3].name = "unsigned longlong";
+ ar.ords[3].align = 0;
+#endif /* ALLOW64 */
+ ar.natord = 2; /* Most natural type */
+
+ ar.nints = 3; /* Number of int types */
+ ar.ints[0].bits = 8;
+ ar.ints[0].name = "signed char";
+ ar.ints[0].align = 1;
+ ar.ints[1].bits = 16;
+ ar.ints[1].name = "short";
+ ar.ints[1].align = 1;
+ ar.ints[2].bits = 32;
+ ar.ints[2].name = "int";
+ ar.ints[2].align = 1;
+#ifdef ALLOW64
+ ar.ints[3].bits = 64;
+ ar.ints[3].name = "longlong";
+ ar.ints[3].align = 0;
+#endif /* ALLOW64 */
+ ar.natint = 2; /* Most natural type */
+
+ rv = gen_c_kernel(&gs, &ts, &ar, kcode, 99, &ogs, &ots);
+
+ fclose(kcode);
+
+ return 0;
+}
diff --git a/imdi/greytiff.c b/imdi/greytiff.c
new file mode 100644
index 0000000..af52013
--- /dev/null
+++ b/imdi/greytiff.c
@@ -0,0 +1,575 @@
+
+/*
+ * Convert a TIFF to monochrome in a colorimetrically correct way.
+ *
+ * Author: Graeme W. Gill
+ * Date: 01/8/29
+ * Version: 1.00
+ *
+ * Copyright 2000, 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.
+ */
+
+/*
+ * Thanks to Neil Okamoto for the 16 bit TIFF mods.
+ */
+
+/* TTBD:
+ *
+ */
+
+/*
+
+ This program is a framework that exercises the
+ IMDI code. It can also do the conversion using the
+ floating point code in ICCLIB as a reference.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "tiffio.h"
+#include "icc.h"
+#include "numlib.h"
+#include "xicc.h"
+#include "imdi.h"
+
+#undef DO_CHECK /* Do floating point check */
+
+void usage(void) {
+ fprintf(stderr,"Convert a TIFF file to monochrome using an ICC device profile, V%s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: greytiff [-v level] profile.icm infile.tif outfile.tif\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -p Use slow precise correction\n");
+ fprintf(stderr," -j Use CIECAM02\n");
+ exit(1);
+}
+
+/* Convert an ICC colorspace to the corresponding TIFF Photometric tag */
+/* return 0xffff if not possible. */
+
+int
+ColorSpaceSignature2TiffPhotometric(
+icColorSpaceSignature cspace
+) {
+ switch(cspace) {
+ case icSigGrayData:
+ return PHOTOMETRIC_MINISBLACK;
+ case icSigRgbData:
+ return PHOTOMETRIC_RGB;
+ case icSigCmykData:
+ return PHOTOMETRIC_SEPARATED;
+ case icSigYCbCrData:
+ return PHOTOMETRIC_YCBCR;
+ case icSigLabData:
+ return PHOTOMETRIC_CIELAB;
+
+ case icSigXYZData:
+ case icSigLuvData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSigCmyData:
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSigMch5Data:
+ case icSig6colorData:
+ case icSigMch6Data:
+ case icSig7colorData:
+ case icSigMch7Data:
+ case icSig8colorData:
+ case icSigMch8Data:
+ case icSig9colorData:
+ case icSig10colorData:
+ case icSig11colorData:
+ case icSig12colorData:
+ case icSig13colorData:
+ case icSig14colorData:
+ case icSig15colorData:
+ default:
+ return 0xffff;
+ }
+ return 0xffff;
+}
+
+char *
+Photometric2str(
+int pmtc
+) {
+ static char buf[80];
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE:
+ return "Subtractive Gray";
+ case PHOTOMETRIC_MINISBLACK:
+ return "Additive Gray";
+ case PHOTOMETRIC_RGB:
+ return "RGB";
+ case PHOTOMETRIC_PALETTE:
+ return "Indexed";
+ case PHOTOMETRIC_MASK:
+ return "Transparency Mask";
+ case PHOTOMETRIC_SEPARATED:
+ return "CMYK";
+ case PHOTOMETRIC_YCBCR:
+ return "YCbCr";
+ case PHOTOMETRIC_CIELAB:
+ return "CIELab";
+ case PHOTOMETRIC_LOGL:
+ return "CIELog2L";
+ case PHOTOMETRIC_LOGLUV:
+ return "CIELog2Luv";
+ }
+ sprintf(buf,"Unknonw Tag %d",pmtc);
+ return buf;
+}
+
+/* Callbacks used to initialise imdi */
+
+/* Context for imdi setup callbacks */
+typedef struct {
+ int id, od;
+ icxLuBase *flu; /* Device -> Jab/Lab */
+ icxLuBase *blu; /* Jab/Lab -> Device */
+} sucntx;
+
+/* Input curve function */
+void input_curve(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ sucntx *rx = (sucntx *)cntx;
+ int e;
+
+ for (e = 0; e < rx->id; e++)
+ out_vals[e] = in_vals[e];
+}
+
+/* Multi-dim table function */
+void md_table(
+void *cntx,
+double *out_vals,
+double *in_vals
+) {
+ sucntx *rx = (sucntx *)cntx;
+ double Lab[3];
+
+ rx->flu->lookup(rx->flu, Lab, in_vals);
+ Lab[1] = Lab[2] = 0.0;
+ rx->blu->lookup(rx->blu, out_vals, Lab);
+}
+
+
+/* Output curve function */
+void output_curve(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ sucntx *rx = (sucntx *)cntx;
+ int e;
+
+ for (e = 0; e < rx->od; e++)
+ out_vals[e] = in_vals[e];
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char prof_name[100];
+ char in_name[100];
+ char out_name[100];
+
+ icmFile *p_fp;
+ icc *icco;
+ xicc *xicco;
+ int verb = 0;
+ int slow = 0;
+ int rv = 0;
+ icColorSpaceSignature pcsor = icSigLabData;
+
+ TIFF *rh = NULL, *wh = NULL;
+ int x, y, width, height; /* Size of image */
+ uint16 samplesperpixel, bitspersample;
+ uint16 pconfig, photometric, pmtc;
+ uint16 resunits;
+ float resx, resy;
+ tdata_t *inbuf, *outbuf, *checkbuf;
+
+ icColorSpaceSignature ins; /* Type of input spaces */
+ int inn; /* Number of device components */
+
+ /* IMDI */
+ imdi *s = NULL;
+ sucntx su; /* Setup context */
+ unsigned char *inp[MAX_CHAN];
+ unsigned char *outp[MAX_CHAN];
+
+#ifdef DO_CHECK
+ /* Error check */
+ int mxerr = 0;
+ double avgerr = 0.0;
+ double avgcount = 0.0;
+#endif /* DO_CHECK */
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Slow, Precise */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ slow = 1;
+ }
+
+ /* Use CIECAM02 */
+ else if (argv[fa][1] == 'j' || argv[fa][1] == 'J') {
+ pcsor = icxSigJabData;
+ }
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(prof_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(out_name,argv[fa++]);
+
+ /* - - - - - - - - - - - - - - - - */
+ /* Open up the profile for reading */
+ if ((p_fp = new_icmFileStd_name(prof_name,"r")) == NULL)
+ error ("Can't open file '%s'",prof_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* Wrap with an expanded icc */
+ if ((xicco = new_xicc(icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ if ((rv = icco->read(icco,p_fp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ if (verb) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ icco->header->dump(icco->header, op, 1);
+ op->del(op);
+ }
+
+ /* Check that the profile is appropriate */
+ if (icco->header->deviceClass != icSigInputClass
+ && icco->header->deviceClass != icSigDisplayClass
+ && icco->header->deviceClass != icSigOutputClass
+ && icco->header->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
+ error("Profile isn't a device profile");
+
+ /* Get a expanded color conversion object */
+ if ((su.flu = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmFwd, icRelativeColorimetric, pcsor, icmLuOrdNorm, NULL, NULL)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ su.flu->spaces(su.flu, &ins, &inn, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ su.id = inn;
+ su.od = inn;
+
+ /* Get a bwd conversion object */
+ if ((su.blu = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icRelativeColorimetric, pcsor, icmLuOrdNorm, NULL, NULL)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ /* - - - - - - - - - - - - - - - */
+ /* Open up input tiff file ready for reading */
+ /* Got arguments, so setup to process the file */
+ if ((rh = TIFFOpen(in_name, "r")) == NULL)
+ error("error opening read file '%s'",in_name);
+
+ TIFFGetField(rh, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);
+
+ TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8 && bitspersample != 16) {
+ error("TIFF Input file must be 8 or 16 bit/channel");
+ }
+
+ TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &photometric);
+ if ((pmtc = ColorSpaceSignature2TiffPhotometric(ins)) == 0xffff)
+ error("ICC input colorspace '%s' can't be handled by a TIFF file!",
+ icm2str(icmColorSpaceSignature, ins));
+ if (pmtc != photometric)
+ error("ICC input colorspace '%s' doesn't match TIFF photometric '%s'!",
+ icm2str(icmColorSpaceSignature, ins), Photometric2str(photometric));
+
+ TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (inn != samplesperpixel)
+ error ("TIFF Input file has %d input channels mismatched to colorspace '%s'",
+ samplesperpixel, icm2str(icmColorSpaceSignature, ins));
+
+ TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
+ if (pconfig != PLANARCONFIG_CONTIG)
+ error ("TIFF Input file must be planar");
+
+ TIFFGetField(rh, TIFFTAG_RESOLUTIONUNIT, &resunits);
+ TIFFGetField(rh, TIFFTAG_XRESOLUTION, &resx);
+ TIFFGetField(rh, TIFFTAG_YRESOLUTION, &resy);
+
+ /* - - - - - - - - - - - - - - - */
+ if ((wh = TIFFOpen(out_name, "w")) == NULL)
+ error("Can\'t create TIFF file '%s'!",out_name);
+
+ TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(wh, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, inn);
+ TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, bitspersample);
+ TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ if ((pmtc = ColorSpaceSignature2TiffPhotometric(ins)) == 0xffff)
+ error("TIFF file can't handle output colorspace '%s'!",
+ icm2str(icmColorSpaceSignature, ins));
+ TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, pmtc);
+ TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ if (resunits) {
+ TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, resunits);
+ TIFFSetField(wh, TIFFTAG_XRESOLUTION, resx);
+ TIFFSetField(wh, TIFFTAG_YRESOLUTION, resy);
+ }
+ TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, "Color corrected by Argyll");
+
+ /* - - - - - - - - - - - - - - - */
+ /* Setup the imdi */
+
+ if (!slow) {
+ s = new_imdi(
+ inn, /* Number of input dimensions */
+ inn, /* Number of output dimensions */
+ bitspersample == 8 ? pixint8 : pixint16,
+ /* Output pixel representation */
+ 0x0, /* Treat every channel as unsigned */
+ NULL, /* No raster to callback channel mapping */
+ prec_min, /* Minimum of input and output precision */
+ bitspersample == 8 ? pixint8 : pixint16,
+ 0x0, /* Treat every channel as unsigned */
+ NULL, /* No raster to callback channel mapping */
+ 17, /* Desired table resolution. 33 is also a good number */
+ oopts_none, /* Desired per channel output options */
+ NULL, /* Output channel check values */
+ opts_none, /* Desired processing direction and stride support */
+ input_curve, /* Callback functions */
+ md_table,
+ output_curve,
+ (void *)&su /* Context to callbacks */
+ );
+
+ if (s == NULL)
+ error("new_imdi failed");
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Process colors to translate */
+ /* (Should fix this to process a group of lines at a time ?) */
+
+ inbuf = _TIFFmalloc(TIFFScanlineSize(rh));
+ outbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+ checkbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+
+ inp[0] = (unsigned char *)inbuf;
+ outp[0] = (unsigned char *)outbuf;
+
+ if (!slow) { /* Fast */
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do fast conversion */
+ s->interp(s, (void **)outp, 0, (void **)inp, 0, width);
+
+#ifdef DO_CHECK
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+ double Lab[3];
+
+ if (bitspersample == 8)
+ for (i = 0; i < inn; i++)
+ in[i] = ((unsigned char *)inbuf)[x * inn + i]/255.0;
+ else
+ for (i = 0; i < inn; i++)
+ in[i] = ((unsigned short *)inbuf)[x * inn + i]/65535.0;
+
+ if ((rv = su.flu->lookup(su.flu, Lab, in)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ Lab[1] = Lab[2] = 0.0;
+
+ if ((rv = su.blu->lookup(su.blu, out, Lab)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ if (bitspersample == 8)
+ for (i = 0; i < inn; i++)
+ ((unsigned char *)checkbuf)[x * inn + i] = (int)(out[i] * 255.0 + 0.5);
+ else
+ for (i = 0; i < inn; i++)
+ ((unsigned short *)checkbuf)[x * inn + i] = (int)(out[i] * 65535.0 + 0.5);
+ }
+ /* Compute the errors */
+ for (x = 0; x < (width * inn); x++) {
+ int err;
+
+ if (bitspersample == 8)
+ err = ((unsigned char *)outbuf)[x] - ((unsigned char *)checkbuf)[x];
+ else
+ err = ((unsigned short *)outbuf)[x] - ((unsigned short *)checkbuf)[x];
+ if (err < 0)
+ err = -err;
+ if (err > mxerr)
+ mxerr = err;
+ avgerr += (double)err;
+ avgcount++;
+ }
+#endif /* DO_CHECK */
+
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+
+ }
+
+ } else { /* Slow but precise */
+ if (bitspersample == 8) {
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+ double Lab[3];
+
+ for (i = 0; i < inn; i++) {
+ in[i] = ((unsigned char *)inbuf)[x * inn + i]/255.0;
+ }
+
+ if ((rv = su.flu->lookup(su.flu, Lab, in)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ Lab[1] = Lab[2] = 0.0;
+
+ if ((rv = su.blu->lookup(su.blu, out, Lab)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ for (i = 0; i < inn; i++) {
+ ((unsigned char *)outbuf)[x * inn + i] = (int)(out[i] * 255.0 + 0.5);
+ }
+ }
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+ }
+ } else if (bitspersample == 16) {
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+ double Lab[3];
+
+ for (i = 0; i < inn; i++) {
+ in[i] = ((unsigned short *)inbuf)[x * inn + i]/65535.0;
+ }
+
+ if ((rv = su.flu->lookup(su.flu, Lab, in)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ Lab[1] = Lab[2] = 0.0;
+
+ if ((rv = su.blu->lookup(su.blu, out, Lab)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ for (i = 0; i < inn; i++) {
+ ((unsigned short *)outbuf)[x * inn + i] = (int)(out[i] * 65535.0 + 0.5);
+ }
+ }
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+ }
+ }
+ }
+
+
+#ifdef DO_CHECK
+ printf("Worst error = %d bits, average error = %f bits\n", mxerr, avgerr/avgcount);
+ if (bitspersample == 8)
+ printf("Worst error = %f%%, average error = %f%%\n",
+ mxerr/2.55, avgerr/(2.55 * avgcount));
+ else
+ printf("Worst error = %f%%, average error = %f%%\n",
+ mxerr/655.35, avgerr/(655.35 * avgcount));
+#endif /* DO_CHECK */
+
+ /* Done with lookup object */
+ if (s != NULL)
+ s->del(s);
+ su.flu->del(su.flu);
+ su.blu->del(su.blu);
+ xicco->del(xicco);
+ icco->del(icco);
+ p_fp->del(p_fp);
+
+ TIFFClose(rh); /* Close Input file */
+ TIFFClose(wh); /* Close Output file */
+
+ return 0;
+}
+
diff --git a/imdi/imdi.c b/imdi/imdi.c
new file mode 100644
index 0000000..8174c8e
--- /dev/null
+++ b/imdi/imdi.c
@@ -0,0 +1,605 @@
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+/*
+ * This is the implementation of the run time code.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "imdi.h"
+#include "imdi_tab.h"
+#include "imdi_k.h" /* Declaration of all the kernel functions */
+
+#undef VERBOSE
+#undef VVERBOSE
+
+static unsigned int imdi_get_check(imdi *im);
+static void imdi_reset_check(imdi *im);
+static void imdi_info(imdi *s, unsigned long *size, int *gres, int *sres);
+static void imdi_del(imdi *im);
+static void interp_match(imdi *s, void **outp, int outst, void **inp, int inst,
+ unsigned int npixels);
+
+
+/* Create a new imdi */
+/* Return NULL if request is not supported */
+/* Note that we use the high level pixel layout description to locate */
+/* a suitable run-time. */
+imdi *new_imdi(
+ int id, /* Number of input dimensions */
+ int od, /* Number of output lookup dimensions */
+ /* Number of output channels written = od - no. of oopt skip flags */
+ imdi_pixrep in, /* Input pixel representation */
+ int in_signed, /* Bit flag per channel, NZ if treat as signed */
+ int *inm, /* Input raster channel to callback channel mapping, NULL for none. */
+ imdi_iprec iprec, /* Internal processing precision */
+ imdi_pixrep out, /* Output pixel representation */
+ int out_signed, /* Bit flag per channel, NZ if treat as signed */
+ int *outm, /* Output raster channel to callback channel mapping, NULL for none. */
+ /* Mapping must include skipped channels. */
+ int res, /* Desired table resolution */
+ imdi_ooptions oopt, /* Output per channel options (by callback channel) */
+ unsigned int *checkv, /* Output channel check values (by callback channel, NULL == 0) */
+ imdi_options opt, /* Direction and stride options */
+
+ /* Callbacks to lookup the imdi table values. */
+ /* (Skip output channels are looked up) */
+ void (*input_curves) (void *cntx, double *out_vals, double *in_vals),
+ void (*md_table) (void *cntx, double *out_vals, double *in_vals),
+ void (*output_curves)(void *cntx, double *out_vals, double *in_vals),
+ void *cntx /* Context to callbacks */
+) {
+ int i;
+ int prec; /* Target internal precision */
+ int bk = -1; /* Best table */
+ int bfig = 0x7fffffff; /* Best tables figure of merit */
+ int bstres = 0; /* Best tables target stres */
+ genspec gs; /* Generation specification */
+ tabspec ts; /* Table specifications */
+ genspec bgs; /* Best gen spec */
+ tabspec bts; /* Best tab spec */
+ imdi_conv bcnv = conv_none; /* Best tables conversion flags */
+ imdi_ooptions Ooopt; /* oopt re-aranged to correspond to output channel index */
+
+ imdi *im;
+
+ /* Compute the Output channel index oopt mask */
+ if (outm == NULL)
+ Ooopt = oopt;
+ else {
+ int ff;
+ Ooopt = 0;
+ for (i = 0; i < od; i++) {
+ ff = OOPTX(oopt,outm[i]);
+ Ooopt |= OOPT(ff,i);
+ }
+ }
+
+#ifdef VERBOSE
+ printf("new_imdi called with id %d, od %d, res %d Ooopt 0x%x, opt 0x%x\n", id, od, res, Ooopt, opt);
+ printf("about to checking %d kernels\n", no_kfuncs);
+#endif
+
+ /* Figure out the internal precision requested */
+ COMPUTE_IPREC(prec, in, iprec, out)
+
+ /* Zero out the gen and tabspecs, to give diff a place to start */
+ memset((void *)&gs, 0, sizeof(genspec));
+ memset((void *)&ts, 0, sizeof(tabspec));
+
+ /* The first thing to do is see if there is an available kernel function */
+ for (i = 0; i < no_kfuncs; i++) {
+ int stres; /* Computed stres needed */
+ imdi_conv cnv = conv_none; /* Conversions needed for this choice */
+ int fig; /* Figure of merit - smaller is better */
+ ktable[i].gentab(&gs, &ts); /* Udate the kernel functions genspec and tabspec */
+
+#ifdef VERBOSE
+ printf("\n");
+ printf("kernel %d has id %d, od %d, irep %d orep %d oopt 0x%x, opt 0x%x\n",
+ i, gs.id, gs.od, gs.irep, gs.orep, gs.oopt, gs.opt);
+ printf("Input req is id %d, od %d, irep %d orep %d, oopt 0x%x, opt 0x%x\n",
+ id, od, in, out, Ooopt, opt);
+#endif
+ /* First check mandatory things */
+ if (!(
+ id == gs.id /* Input dimension */
+ && od == gs.od /* Output dimension */
+ )) {
+#ifdef VVERBOSE
+ printf(" Input or Output dimension mismatch\n");
+#endif
+ continue;
+ }
+
+ /* Check if we have an exact or conversion match for input stride */
+ if (!(
+ (opt & opts_istride) == (gs.opt & opts_istride)
+ || (!(opt & opts_istride) && (gs.opt & opts_istride))
+ )) {
+#ifdef VVERBOSE
+ printf(" Input stride mismatch\n");
+#endif
+ continue;
+ }
+
+ /* Check if we have an exact or conversion match for output stride */
+ if (!(
+ (opt & opts_ostride) == (gs.opt & opts_ostride)
+ || (!(opt & opts_ostride) && (gs.opt & opts_ostride))
+ )) {
+#ifdef VVERBOSE
+ printf(" Output stride mismatch\n");
+#endif
+ continue;
+ }
+
+ /* Check if we have an exact or conversion match for input representation */
+ if (!(
+ in == gs.irep
+ || (in == pixint8 && gs.irep == planeint8 && (gs.opt & opts_istride))
+ || (in == pixint16 && gs.irep == planeint16 && (gs.opt & opts_istride))
+ )) {
+#ifdef VVERBOSE
+ printf(" Input representation mismatch\n");
+#endif
+ continue;
+ }
+
+ /* Check if we have an exact or conversion match for output representation */
+ if (!(
+ out == gs.orep
+ || (out == pixint8 && gs.orep == planeint8 && (gs.opt & opts_ostride))
+ || (out == pixint16 && gs.orep == planeint16 && (gs.opt & opts_ostride))
+ )) {
+#ifdef VVERBOSE
+ printf(" Output representation mismatch\n");
+#endif
+ continue;
+ }
+
+ /* See if we have the output per channel options needed */
+ if (!((Ooopt & gs.oopt) == Ooopt)) {
+#ifdef VVERBOSE
+ printf(" Output per channel options mismatch\n");
+#endif
+ continue;
+ }
+
+ /* See if we have an exact or conversion match for reverse direction */
+ if (!(
+ ((!(opt & opts_bwd) && !(opt & opts_fwd))) /* Don't care */
+ || (((opt & opts_bwd) && (gs.opt & opts_bwd))) /* Match */
+ || (((opt & opts_fwd) && (gs.opt & opts_fwd))) /* Match */
+ || ((gs.opt & opts_istride) && (gs.opt & opts_ostride)) /* Can convert */
+ )) {
+#ifdef VVERBOSE
+ printf(" Direction mismatch\n");
+#endif
+ continue;
+ }
+
+#ifdef VERBOSE
+ printf(" found match\n");
+#endif
+ fig = 0;
+
+ /* Apply penalty if we will have to do a conversion match */
+ if ((opt & opts_istride) != (gs.opt & opts_istride)) {
+ cnv |= conv_istr;
+ fig += 1000;
+#ifdef VERBOSE
+ printf(" needs input stride conversion though\n");
+#endif
+ }
+
+ if ((opt & opts_ostride) != (gs.opt & opts_ostride)) {
+ cnv |= conv_ostr;
+ fig += 1000;
+#ifdef VERBOSE
+ printf(" needs output stride conversion though\n");
+#endif
+ }
+
+ if (in != gs.irep) {
+ cnv |= conv_irep;
+ fig += 5000;
+#ifdef VERBOSE
+ printf(" needs input representation conversion though\n");
+#endif
+ }
+
+ if (out != gs.orep) {
+ cnv |= conv_orep;
+ fig += 5000;
+#ifdef VERBOSE
+ printf(" needs output representation conversion though\n");
+#endif
+ }
+
+ /* If we don't need output checking or skipping, but we've got it */
+ if ((~Ooopt & gs.oopt) != 0) {
+ unsigned int tmp = (~Ooopt & gs.oopt);
+ /* Count number of bits set that we don't need */
+ /* (From HACKMEM 169) */
+ tmp = tmp - ((tmp >> 1) & 033333333333) - ((tmp >> 2) & 011111111111);
+ tmp = ((tmp + (tmp >> 3)) & 030707070707) % 63;
+ fig += tmp;
+#ifdef VERBOSE
+ printf(" has output options we don't need though\n");
+#endif
+ }
+
+ /* If we've got output skipping, we need to skip pointers in interp. */
+ if ((Ooopt & OOPTS_SKIP) != 0) {
+ cnv |= conv_skip;
+ }
+
+ if (((opt & opts_fwd) && (gs.opt & opts_bwd))
+ || ((opt & opts_bwd) && (gs.opt & opts_fwd))) {
+ cnv |= conv_rev;
+ fig += 1000;
+#ifdef VERBOSE
+ printf(" needs direction conversion though\n");
+#endif
+ }
+
+ if (prec != gs.prec) { /* Internal precision mismatch */
+ fig += 100000; /* Will have a major effect, so discourage using it */
+#ifdef VERBOSE
+ printf(" internal precision doesn't match though (want %d, got %d)\n",prec,gs.prec);
+#endif
+ }
+
+ /* If we've got a choice of algorithm possible */
+ if (gs.opt & (opts_splx_sort | opts_sort_splx)) {
+
+ /* If we've got a preference of algorithm, */
+ if ((opt & (opts_splx_sort | opts_sort_splx))) {
+
+ /* and there is a mismatch */
+ if (((opt & opts_splx_sort) && ts.sort != 0)
+ || ((opt & opts_sort_splx) && ts.sort == 0)) {
+ fig += 10000; /* Will have a great effect, so discourage using it */
+#ifdef VERBOSE
+ printf(" sort/simplex algorithm mismatch\n");
+#endif
+ }
+
+ } else { /* There is no preference chosen at run time, */
+ /* and there is a mismatch to the compile time preference */
+ if (((gs.opt & opts_splx_sort) && ts.sort != 0)
+ || ((gs.opt & opts_sort_splx) && ts.sort == 0)) {
+ fig += 10000; /* Will have a great effect, so discourage using it */
+#ifdef VERBOSE
+ printf(" sort/simplex algorithm mismatch\n");
+#endif
+ }
+ }
+ }
+
+ if (ts.sort) {
+ stres = 0;
+#ifdef VERBOSE
+ printf("gres = %d, gs.gres = %d\n",res,gs.itres);
+#endif
+ /* We want one that is equals or exceeds the desired */
+ /* resolution, but doesn't exceed it too much, or the code */
+ /* will be inefficient. */
+ /* If there are no routines that can meet the desired precision, */
+ /* then it is ok to use the one closest to the desired precision. */
+ if (gs.itres >= res) {
+ fig += 10 * (gs.itres - res);
+ } else {
+ fig += 10000 + 10 * (res - gs.itres);
+ }
+ } else {
+ /* compute the needed stres (Assuming not sort) */
+ stres = ((1 << gs.prec)-1 + res-2)/(res-1);
+
+#ifdef VERBOSE
+ printf("gres = %d, sres = %d, gs.gres = %d, gs.sres = %d\n",res,stres,gs.itres,gs.stres);
+#endif
+ /* We want one that is equals or exceeds the desired */
+ /* resolution, but doesn't exceed it too much, or the code */
+ /* will be inefficient. */
+ /* If there are no routines that can meet the desired precision, */
+ /* then it is ok to use the one closest to the desired precision. */
+ if (gs.itres >= res && gs.stres >= stres) {
+ fig += 10 * (gs.itres - res) + (gs.stres - stres);
+ } {
+ if (gs.itres < res) {
+ fig += 10000 + 10 * (res - gs.itres);
+ }
+ if (gs.stres < stres) {
+ fig += 1000 + 10 * (stres - gs.stres);
+ }
+ }
+ }
+
+#ifdef VERBOSE
+ printf(" figure of merit %d\n",fig);
+#endif
+ /* Is this the best one so far ? */
+ if (fig < bfig) {
+ bfig = fig;
+ bk = i;
+ bstres = stres;
+ bgs = gs; /* Structure copy */
+ bts = ts; /* Structure copy */
+ bcnv = cnv;
+#ifdef VERBOSE
+ printf(" best so far\n");
+#endif
+ }
+ }
+
+ if (bk < 0) {
+#ifdef VERBOSE
+ printf("new_imdi failed - dimensionality or representations couldn't be matched\n");
+#endif
+ return NULL; /* Nothing matches */
+ }
+
+ if ((im = (imdi *)calloc(1, sizeof(imdi))) == NULL) {
+#ifdef VERBOSE
+ printf("new_imdi malloc imdi failed\n");
+#endif
+ /* Should we return an error somehow ? */
+ return NULL;
+ }
+
+ /* We've decided kernel function bk is going to be the best, */
+ /* so now setup the appropriate tables to use with it. */
+ if (bgs.itres > res)
+ bgs.itres = res; /* Tell table create what the res is */
+ if (bgs.stres > bstres)
+ bgs.stres = bstres;
+
+ /* Tel table setup how to treat integer input in per channel lookups */
+ bgs.in_signed = in_signed;
+ bgs.out_signed = out_signed;
+
+#ifdef VERBOSE
+ if (!bts.sort) {
+ if ((bgs.stres * (bgs.itres-1)) < ((1 << bgs.prec)-1)) {
+ printf("Warning: table chosen doesn't reach desired precision!\n");
+ printf("Wanted %d, got %d\n", ((1 << bgs.prec)-1), (bgs.stres * (bgs.itres-1)));
+ }
+ }
+#endif
+
+ /* Allocate and initialise the appropriate tables */
+ im->impl = (void *)imdi_tab(&bgs, &bts, bcnv, in, out, ktable[bk].interp,
+ inm, outm, oopt, checkv, input_curves, md_table,
+ output_curves, cntx);
+
+ if (im->impl == NULL) {
+#ifdef VERBOSE
+ printf("imdi_tab failed\n");
+#endif
+ imdi_del(im);
+ return NULL;
+ }
+
+#ifdef VERBOSE
+ if (bcnv != conv_none)
+ printf("imdi_tab: using a runtime match, cnv flags 0x%x\n",bcnv);
+#endif
+
+ if (bcnv == conv_none) /* No runtime match conversion needed */
+ im->interp = ktable[bk].interp;
+ else
+ im->interp = interp_match;
+ im->get_check = imdi_get_check;
+ im->reset_check = imdi_reset_check;
+ im->info = imdi_info;
+ im->del = imdi_del;
+
+#ifdef VERBOSE
+ printf("new_imdi returning 0x%x\n", im);
+#endif
+ return im;
+}
+
+/* Runtime matching adapter */
+/* We can emulate many combinations of interpolation function */
+/* by converting to a routine that supports stride, or one that */
+/* supports plane interleaved and stride. */
+/* This also lets us emulate functions that can convert between */
+/* pixel and plane interleaved at the same time as doing the */
+/* color interpolation. Warp is in components (NOT bytes) */
+/* We cope with skipping writes to output channels by */
+/* only implementing that support in plane interleaved, */
+/* and depending on that being used for pixel interleaved. */
+static void interp_match(
+imdi *s,
+void **outp, int outst, /* Output pointers and stride */
+void **inp, int inst, /* Input pointers and stride */
+unsigned int npixels /* Number of pixels */
+) {
+ int j, i;
+ void *minp[IXDI];
+ void *moutp[IXDI];
+ imdi_imp *impl = (imdi_imp *)s->impl;
+ imdi_conv cnv = impl->cnv;
+
+ /* Need to supply default stride. */
+ /* This is simply the input dimension for pixel interleaved, */
+ /* and 1 for plane interleaved. */
+ if (cnv & conv_istr) {
+ if (impl->cirep == pixint8 || impl->cirep == pixint16)
+ inst = impl->id;
+ else
+ inst = 1;
+ }
+ if (cnv & conv_ostr) {
+ if (impl->corep == pixint8 || impl->corep == pixint16)
+ outst = impl->wod;
+ else
+ outst = 1;
+ }
+
+ /* Convert from pixel to plane by setting the plane pointers */
+ /* to each pixel component, and using the pixel interleaved stride */
+ if (cnv & conv_irep) {
+ if (impl->cirep == pixint8) { /* Convert from pix8 to plane8 */
+ for (j = 0; j < impl->id; j++)
+ minp[j] = (void *)((char *)inp[0] + j);
+ } else if (impl->cirep == pixint16) { /* Convert from pix16 to plane16 */
+ for (j = 0; j < impl->id; j++)
+ minp[j] = (void *)((char *)inp[0] + 2 * j);
+ }
+ } else { /* Copy pointers, because we call with them. */
+ if (impl->cirep == pixint8 || impl->cirep == pixint16) {
+ minp[0] = inp[0];
+ } else {
+ for (j = 0; j < impl->id; j++)
+ minp[j] = inp[j];
+ }
+ }
+ if (cnv & conv_orep) {
+ if (impl->corep == pixint8) { /* Convert from pix8 to plane8 */
+ for (j = i = 0; j < impl->od; j++) {
+ if ((impl->skipf & (1 << j)) == 0) /* If not skipped */
+ moutp[j] = (void *)((char *)outp[0] + i++);
+ else
+ moutp[j] = NULL;
+ }
+ } else if (impl->corep == pixint16) { /* Convert from pix16 to plane16 */
+ for (j = i = 0; j < impl->od; j++)
+ if ((impl->skipf & (1 << j)) == 0) /* If not skipped */
+ moutp[j] = (void *)((char *)outp[0] + 2 * i++);
+ else
+ moutp[j] = NULL;
+ }
+ } else { /* Copy pointers, because we call with them. */
+ if (impl->corep == pixint8 || impl->corep == pixint16) {
+ moutp[0] = outp[0];
+ } else { /* Plane interleaved */
+ for (j = i = 0; j < impl->od; j++) {
+ if ((impl->skipf & (1 << j)) == 0) /* If not skipped */
+ moutp[j] = outp[i++];
+ else
+ moutp[j] = NULL;
+ }
+ }
+ }
+
+ /* Convert fwd function to a backwards one, or visa-versa. */
+ /* Move the pointers to the last pixel, and reverse the stride */
+ if (cnv & conv_rev) {
+ if (impl->firep == pixint8) {
+ minp[0] = (void *)((char *)minp[0] + inst * (npixels - 1));
+ } else if (impl->firep == pixint16) {
+ minp[0] = (void *)((char *)minp[0] + inst * 2 * (npixels - 1));
+ } else if (impl->firep == planeint8) {
+ for (j = 0; j < impl->id; j++)
+ minp[j] = (void *)((char *)minp[j] + inst * (npixels - 1));
+ } else if (impl->firep == planeint16) {
+ for (j = 0; j < impl->id; j++)
+ minp[j] = (void *)((char *)minp[j] + inst * 2 * (npixels - 1));
+ }
+ inst = -inst;
+ if (impl->forep == pixint8) {
+ moutp[0] = (void *)((char *)moutp[0] + outst * (npixels - 1));
+ } else if (impl->forep == pixint16) {
+ moutp[0] = (void *)((char *)moutp[0] + outst * 2 * (npixels - 1));
+ } else if (impl->forep == planeint8) {
+ for (j = 0; j < impl->od; j++)
+ moutp[j] = (void *)((char *)moutp[j] + outst * (npixels - 1));
+ } else if (impl->forep == planeint16) {
+ for (j = 0; j < impl->od; j++)
+ moutp[j] = (void *)((char *)moutp[j] + outst * 2 * (npixels - 1));
+ }
+ outst = -outst;
+ }
+
+ /* Call the conversion routine we have */
+ impl->interp(s, moutp, outst, minp, inst, npixels);
+}
+
+/* Get the per output channel check flags - bit corresponds to output interpolation channel */
+static unsigned int imdi_get_check(imdi *im) {
+ imdi_imp *impl = (imdi_imp *)im->impl;
+ unsigned int rv;
+ int i;
+
+ /* Convert from output channel index to callback index */
+ for (rv = 0, i = 0; i < impl->od; i++) {
+ unsigned int b;
+ b = 1 & (impl->checkf >> i); /* Output index flag */
+ rv |= (b << impl->im_map[i]); /* to callback index */
+ }
+ return rv;
+}
+
+/* Reset the output check flags (not reset by interp) */
+static void imdi_reset_check(imdi *im) {
+ imdi_imp *impl = (imdi_imp *)im->impl;
+
+ impl->checkf = 0;
+}
+
+/* Return some information about the imdi */
+static void imdi_info(imdi *im, unsigned long *psize, int *pgres, int *psres) {
+ imdi_imp *impl = (imdi_imp *)im->impl;
+ unsigned long size;
+
+ size = sizeof(imdi);
+
+ if (impl != NULL) {
+ size += impl->size;
+ if (psize != NULL)
+ *psize = size;
+
+ if (pgres != NULL)
+ *pgres = impl->gres;
+
+ if (psres != NULL)
+ *psres = impl->sres;
+ }
+}
+
+
+/* Delete the object */
+static void imdi_del(imdi *im) {
+ /* Free all the allocated tables */
+ if (im->impl != NULL)
+ imdi_tab_free((imdi_imp *)im->impl);
+
+ /* Free this structure */
+ free(im);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/imdi/imdi.h b/imdi/imdi.h
new file mode 100644
index 0000000..1e72b8c
--- /dev/null
+++ b/imdi/imdi.h
@@ -0,0 +1,93 @@
+#ifndef IMDI_H
+#define IMDI_H
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+/*
+ * This file provides the common definitions for IMDI, and
+ * in particular, the runtime conversion object.
+ * Actual runtime details are kept opaque.
+ */
+
+#include "imdi_utl.h"
+#include "imdi_arch.h"
+#include "imdi_gen.h"
+
+/* IMDI Object */
+struct _imdi {
+ void *impl; /* Opaque pointer to implementation information (type imdi_imp *) */
+
+ /* Do the interpolation. */
+
+ /* Each pointer corresponds to the colors plane for plane interleaved. */
+ /* pointer[0] is used for pixel interleave. */
+
+ /* Stride is only obeyed if the appropriate option flag was set */
+ /* in new_imdi, and is in pixel components, and effectively defaults */
+ /* to 1 for plane interleaved, and id and od (adjusted for skip) for pixel interleave, */
+ /* so stride is in color components (NOT bytes) */
+ /* Output pointers and data must only reference non-skipped output channels. */
+
+ /* Note that once an imdi is created, multiple can call interp() without */
+ /* interfering with each other, allowing parallel execution. */
+ void (*interp)(struct _imdi *s, void **outp, int outst, /* Ouput pointers and stride */
+ void **inp, int inst, /* Input pointers and stride */
+ unsigned int npixels); /* Number of pixels */
+
+ /* Return some information about the imdi */
+ void (*info)(struct _imdi *s, unsigned long *size, int *gres, int *sres);
+
+ /* Get the per output channel check flags (bit is indexed by callback channel) */
+ /* Flag gets set if output != checkv */
+ unsigned int (*get_check)(struct _imdi *s);
+
+ /* Reset the output check flags (flag is not reset by interp) */
+ void (*reset_check)(struct _imdi *s);
+
+ /* Delete this object */
+ void (*del)(struct _imdi *s);
+
+}; typedef struct _imdi imdi;
+
+/* Create a new imdi. */
+/* Return NULL if request is not supported */
+imdi *new_imdi(
+ int id, /* Number of input dimensions */
+ int od, /* Number of output lookup dimensions */
+ /* Number of output channels written = od - no. of oopt skip flags */
+ imdi_pixrep in, /* Input pixel representation */
+ int in_signed, /* Bit flag per channel, NZ if treat as signed */
+ int *inm, /* Input raster channel to callback channel mapping, NULL for none. */
+ imdi_iprec iprec, /* Internal processing precision */
+ imdi_pixrep out, /* Output pixel representation */
+ int out_signed, /* Bit flag per channel, NZ if treat as signed */
+ int *outm, /* Output raster channel to callback channel mapping, NULL for none. */
+ /* Mapping must include skipped channels. */
+ int res, /* Desired table resolution */
+ imdi_ooptions oopt, /* Output per channel options (by callback channel) */
+ unsigned int *checkv, /* Output channel check values (by callback channel, NULL == 0) */
+ imdi_options opt, /* Direction and stride options */
+
+ /* Callbacks to lookup the imdi table values. */
+ /* (Skip output channels are looked up) */
+ void (*input_curves) (void *cntx, double *out_vals, double *in_vals),
+ void (*md_table) (void *cntx, double *out_vals, double *in_vals),
+ void (*output_curves)(void *cntx, double *out_vals, double *in_vals),
+ void *cntx /* Context to callbacks */
+);
+
+#endif /* IMDI_H */
+
+
+
+
+
+
diff --git a/imdi/imdi_arch.h b/imdi/imdi_arch.h
new file mode 100644
index 0000000..afceb73
--- /dev/null
+++ b/imdi/imdi_arch.h
@@ -0,0 +1,71 @@
+#ifndef IMDI_ARCH_H
+#define IMDI_ARCH_H
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+/*
+ * Contained here is any architecture/platform specific facilities,
+ * used by the runtime code, and used by the code generation code
+ * in generating the runtime code (used in the generation code itself
+ * only in discovering the architecture automatically),
+ * and the architecture table that describes the architecture to the
+ * code generation.
+ *
+ * The mach_arch structure is not used by the runtime, since it is implicit
+ * that the runtime is setup for the described architecture.
+ *
+ */
+
+#ifdef ALLOW64
+
+#define STR_DEF(def) #def
+
+/* Detect machine/compiler specifics here */
+#if defined(NT)
+#define longlong __int64
+#else /* !NT, assume standard */
+#define longlong long long
+#endif /* !NT */
+#define str_longlong STR_DEF(longlong)
+
+#endif /* ALLOW64 */
+
+/* Machine/Language architectural specifications */
+typedef struct {
+ int bits; /* Bits in this data type */
+ char *name; /* Name used to specify this type */
+ int align; /* Non-zero if this type should be accessed aligned */
+} dtypes;
+
+#define MXDTYPES 6
+
+typedef struct {
+ int bigend; /* Non-zero if this is a bigendian architecture */
+ int uwa; /* Use wide memory access */
+
+ int pbits; /* Number of bits in a pointer */
+
+ int nords; /* Number of ord types */
+ dtypes ords[MXDTYPES]; /* Ordinal types, in size order */
+ int natord; /* Index of natural machine ordinal */
+
+ int nints; /* Number of int types */
+ dtypes ints[MXDTYPES]; /* Integer types, in size order */
+ int natint; /* Index of natural machine integer */
+
+ /* Optimisation settings */
+ int shfm; /* Non-zero to use shifts for masking */
+ int oscale; /* Maximum power of 2 scaled indexing mode, 0 for none. */
+ int smmul; /* Has fast small multiply for index scaling */
+
+} mach_arch;
+
+#endif /* IMDI_ARCH_H */
diff --git a/imdi/imdi_gen.c b/imdi/imdi_gen.c
new file mode 100644
index 0000000..ab17ad3
--- /dev/null
+++ b/imdi/imdi_gen.c
@@ -0,0 +1,319 @@
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+/*
+ * Code generation support that translates between the higher level
+ * gendesc, and the low level genspec.
+ */
+
+#undef VERBOSE
+
+/*
+ Ideal grid resolutions for 8/16 bit precision calculations:
+
+ There are a limited number of grid resolution and grid cells
+ sub resolution values that work perfectly, and allow every possible
+ input value to map to a precise interpolation value. For any
+ system that deals with Lab data, it is also better if there is
+ a grid point near a,b == 0, meaning that an odd grid size is
+ preferable for 3 dimensional Lab input conversions. Reasonable memory
+ usage is usually somewhere between 100K and 1M entries for
+ the grid table, limiting the maximum grid resolution.
+ The following lists the some of the possible grid and sub grid
+ resolutions in order of best to worst. (Fewer jumps is better).
+
+
+ Grid Sub8 Round8 Sub16 Round16 Jumps
+ 4 85 85 21845 21845 0
+ 6 51 51 13107 13107 0
+ 16 17 17 4369 4369 0
+ 18 15 15 3855 3855 0
+ 52 5 5 1285 1285 0
+ 86 3 3 771 771 0
+ 256 1 1 257 257 0
+ 258 255 255 0
+ 772 85 85 0
+ 1286 51 51 0
+ 3856 17 17 0
+ 4370 15 15 0
+ 13108 5 5 0
+ 21846 3 3 0
+ 65536 1 1 0
+ 3 127.5 128 1
+ 5 63.75 64 1
+ 9 31.875 32 1
+ 17 15.937 16 1
+ 33 7.968 8 1
+ 65 3.984 4 1
+ 128 2.007 2 1
+ 129 1.992 2 1
+ 255 1.003 1 1
+ 12 23.188 23 2
+ 24 11.086 11 2
+ 254 1.007 1 2
+ 7 42.5 43 3
+ 8 36.428 36 3
+ 10 28.333 28 3
+ 13 21.25 21 3
+ 15 18.214 18 3
+ 19 14.166 14 3
+ 22 12.142 12 3
+ 29 9.107 9 3
+ 37 7.083 7 3
+ 43 6.071 6 3
+ 44 5.930 6 3
+ 64 4.047 4 3
+ 85 3.035 3 3
+ 87 2.965 3 3
+ 127 2.023 2 3
+ 130 1.976 2 3
+ 253 1.011 1 3
+
+ [8 bit: sub = 255/(grid-1), jumps = abs((grid-1)*round(sub)-255)]
+ [16 bit: sub = 65535/(grid-1), jumps = abs((grid-1)*round(sub)-65535)]
+
+ The above takes into consideration the mapping of the sub-cell or
+ simplex table resolution, but doesn't take into account the quantizing
+ of the sub-cell weighting values into the range 0..256 or 0..65536.
+
+ This will be best when round(sub) divides evenly into 256 or 65536,
+ so grid resolutions of 3, 5, 9, 17, 33, 65, 128, 129, 255 may be the
+ best choice for sort algorithm grid resolutions.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+
+#include "imdi_utl.h"
+#include "imdi_arch.h"
+#include "imdi_gen.h"
+
+static void translate_pixrep(pixlayout *pl, char **desc, int *prec, imdi_pixrep rep, int dim, mach_arch *a);
+
+/* Translate between a gendesc and genspec */
+int /* Return number of combinations possible */
+set_genspec(
+genspec *gs, /* Return specification */
+gendesc *gd, /* Input description */
+int comb, /* Combination index */
+mach_arch *a /* Machine architecture */
+) {
+ int nc = 1; /* Number of combinations */
+ int nidc, id; /* Number of input dimension combinations, current index */
+ int nodc, od; /* Number of output dimension combinations, current index */
+ int nirc, ir; /* Number of input, prec. & out representations combinations, cnt index */
+ int pc, or; /* Precision combination index, Output combination index */
+ int ndc, opt; /* Number of direction stride ombinations, current index */
+ int tt;
+
+ /* Figure out how many combinations there are */
+ for (nidc = 0; gd->idcombs[nidc] != 0; nidc++) /* Input dimension */
+ ;
+ nc *= nidc;
+ for (nodc = 0; gd->odcombs[nodc] != 0; nodc++) /* Output dimension */
+ ;
+ nc *= nodc;
+ for (nirc = 0; gd->incombs[nirc] != 0; nirc++) /* Input/Precision/Output representation */
+ ;
+ nc *= nirc;
+ for (tt = 0; gd->iprecs[tt] != 0; tt++) /* Internal precision representation */
+ ;
+ if (nirc != tt) {
+ fprintf(stderr,"imdi_gen: Must be equal numberof input and precision representations\n");
+ exit(-1);
+ }
+ for (tt = 0; gd->outcombs[tt] != 0; tt++) /* Output representation */
+ ;
+ if (nirc != tt) {
+ fprintf(stderr,"imdi_gen: Must be equal numberof input and output representations\n");
+ exit(-1);
+ }
+
+ for (ndc = 0; gd->optcombs[ndc] != opts_end; ndc++) /* Direction and stride options */
+ ;
+ nc *= ndc;
+
+ if (nc <= 0) {
+ fprintf(stderr,"imdi_gen: no valid combinations specified for kernel generation\n");
+ exit(-1);
+ }
+ if (comb < nc) { /* If we are within a legal combination */
+ int iprec, oprec;
+ char *idesc, *odesc; /* Representation descriptions */
+ char *ddesc; /* Direction description */
+
+ id = comb % nidc;
+ comb /= nidc;
+ od = comb % nodc;
+ comb /= nodc;
+ ir = comb % nirc;
+ comb /= nirc;
+ pc = ir; /* In and precision combs track together */
+ or = ir; /* In and out combs track together */
+ opt = comb % ndc;
+ comb /= ndc;
+#ifdef VERBOSE
+ printf("Combination id = %d, od = %d, ir = %d, pc = %d, or = %d, opt = %d\n",
+ id,od,ir,pc,or,opt);
+#endif /* VERBOSE */
+
+ gs->id = gd->idcombs[id]; /* Input dimensions */
+ gs->itres = gd->itres[id]; /* Interpolation table resolution */
+ gs->stres = gd->stres[id]; /* Simplex table resolution */
+ gs->od = gd->odcombs[od]; /* Output dimensions */
+ gs->oopt = gd->ooptcombs[od]; /* Output per channel options */
+
+ if (gs->id > IXDI) {
+ fprintf(stderr,"imdi_gen: Input dimension %d exceeds limit %d\n",gs->id,IXDI);
+ exit(-1);
+ }
+ if (gs->od > IXDO) {
+ fprintf(stderr,"imdi_gen: Output dimension %d exceeds limit %d\n",gs->od,IXDO);
+ exit(-1);
+ }
+ /* Input representation */
+ gs->irep = gd->incombs[ir]; /* Keep a copy of this */
+ translate_pixrep(&gs->in, &idesc, &iprec, gd->incombs[ir], gs->id, a);
+ gs->in_signed = 0x0; /* Not used during generation, used at runtime setup */
+
+ /* Output representation */
+ gs->orep = gd->outcombs[or]; /* Keep a copy of this */
+ translate_pixrep(&gs->out, &odesc, &oprec, gd->outcombs[or], gs->od, a);
+ gs->out_signed = 0x0; /* Not used during generation, used at runtime setup */
+
+ COMPUTE_IPREC(gs->prec, gs->irep, gd->iprecs[pc], gs->orep)
+
+ gs->opt = gd->optcombs[opt]; /* Direction and stride options */
+
+ if (((gs->opt & opts_splx_sort) && (gs->opt & opts_sort_splx))
+ || ((gs->opt & opts_splx_sort) && (gs->opt & opts_splx))
+ || ((gs->opt & opts_sort_splx) && (gs->opt & opts_splx))) {
+ fprintf(stderr,"imdi_gen: Conflict in simplex/sort preferences\n");
+ exit(-1);
+ }
+
+ ddesc = gs->opt & opts_bwd ? "b" : "f"; /* Direction description */
+
+#ifdef VERBOSE
+ printf("translates to prec = %d, id = %d, od = %d, itres %d, stdres %d\n",
+ gs->prec,gs->id,gs->od,gs->itres,gs->stres);
+#endif /* VERBOSE */
+
+ /* Create a concise description string */
+ sprintf(gs->kdesc,"%d_%d_%s_%s_%s", gs->id, gs->od, idesc, odesc, ddesc);
+ }
+ return nc;
+}
+
+/* Convert the high level pixrep into the lower level pixel layout */
+static void
+translate_pixrep(
+pixlayout *pl, /* pixlayout to initialise */
+char **desc, /* Return description identifier (may be NULL) */
+int *prec, /* Return basic precision specifier (may be NULL) */
+imdi_pixrep rep, /* Representation to be translated */
+int dim, /* Number of dimensions (values/pixel) */
+mach_arch *a /* Machine architecture */
+) {
+ switch (rep) {
+
+ case pixint8: { /* 8 Bits per value, pixel interleaved, no padding */
+ int i;
+
+ /* Could optimise this to packed for dim == 4 ~~~~ */
+
+ pl->pint = 1; /* pixel interleaved */
+ pl->packed = 0; /* Not packed */
+
+ for (i = 0; i < dim; i++) {
+ pl->bpch[i] = 8; /* Bits per channel */
+ pl->chi[i] = dim; /* Channel increment */
+ pl->bov[i] = 0; /* Bit offset to value within channel */
+ pl->bpv[i] = 8; /* Bits per value within channel */
+ }
+
+ if (prec != NULL)
+ *prec = 8; /* Basic 8 bit precision */
+ if (desc != NULL)
+ *desc = "i8"; /* Interleaved 8 bit */
+ } break;
+
+ case planeint8: { /* 8 bits per value, plane interleaved */
+ int i;
+
+ pl->pint = 0; /* Not pixel interleaved */
+ pl->packed = 0; /* Not packed */
+
+ for (i = 0; i < dim; i++) {
+ pl->bpch[i] = 8; /* Bits per channel */
+ pl->chi[i] = 1; /* Channel increment */
+ pl->bov[i] = 0; /* Bit offset to value within channel */
+ pl->bpv[i] = 8; /* Bits per value within channel */
+ }
+
+ if (prec != NULL)
+ *prec = 8; /* Basic 8 bit precision */
+ if (desc != NULL)
+ *desc = "p8"; /* Planar 8 bit */
+
+ } break;
+
+ case pixint16: { /* 16 Bits per value, pixel interleaved, no padding */
+ int i;
+
+ /* Could optimise this to packed for dim == 4 ~~~~ */
+
+ pl->pint = 1; /* pixel interleaved */
+ pl->packed = 0; /* Not packed */
+
+ for (i = 0; i < dim; i++) {
+ pl->bpch[i] = 16; /* Bits per channel */
+ pl->chi[i] = dim; /* Channel increment */
+ pl->bov[i] = 0; /* Bit offset to value within channel */
+ pl->bpv[i] = 16; /* Bits per value within channel */
+ }
+
+ if (prec != NULL)
+ *prec = 16; /* Basic 8 bit precision */
+ if (desc != NULL)
+ *desc = "i16"; /* Interleaved 16 bit */
+ } break;
+
+ case planeint16: { /* 16 bits per value, plane interleaved */
+ int i;
+
+ pl->pint = 0; /* Not pixel interleaved */
+ pl->packed = 0; /* Not packed */
+
+ for (i = 0; i < dim; i++) {
+ pl->bpch[i] = 16; /* Bits per channel */
+ pl->chi[i] = 1; /* Channel increment */
+ pl->bov[i] = 0; /* Bit offset to value within channel */
+ pl->bpv[i] = 16; /* Bits per value within channel */
+ }
+
+ if (prec != NULL)
+ *prec = 16; /* Basic 8 bit precision */
+
+ if (desc != NULL)
+ *desc = "p16"; /* Planar 8 bit */
+ } break;
+
+ default: {
+ fprintf(stderr,"Warning: Unknown pixel representation %d\n",rep);
+ } break;
+ }
+}
+
diff --git a/imdi/imdi_gen.h b/imdi/imdi_gen.h
new file mode 100644
index 0000000..8a7ced9
--- /dev/null
+++ b/imdi/imdi_gen.h
@@ -0,0 +1,271 @@
+#ifndef IMDI_GEN_H
+#define IMDI_GEN_H
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+/*
+ * Pixel code generation definitions.
+ *
+ * This defines a particular combination of pixel layout,
+ * number of channels, and other runtime requestable features.
+ * This is used by the code generation to setup anticipated
+ * support for these requests, used by the runtime to request
+ * the features, and by the runtime to identify the correct
+ * generated module to use.
+ *
+ */
+
+
+/* -------------------------------------------------- */
+/* High level kernel generation description */
+
+
+/* This is a high level macro desciption of the pixel layout. */
+/* It can be expanded by adding a new enumeration, and then */
+/* implementing the code in imdi_gen to translate the enumeration */
+/* into the exact pixlayout structure details. */
+
+typedef enum {
+ invalid_rep = 0x00,
+ pixint8 = 0x01, /* 8 Bits per value, pixel interleaved, no padding */
+ planeint8 = 0x02, /* 8 bits per value, plane interleaved */
+ pixint16 = 0x03, /* 16 Bits per value, pixel interleaved, no padding */
+ planeint16 = 0x04 /* 16 bits per value, plane interleaved */
+} imdi_pixrep;
+
+/* The internal processing precision */
+typedef enum {
+ prec_min = 0, /* Minimum of input and output precision */
+ prec_max = 1, /* Maximum of input and output precision */
+ prec_in = 2, /* Same as input */
+ prec_out = 3, /* Same as output */
+ prec_p8 = 4, /* 8 Bits precision */
+ prec_p16 = 5 /* 16 Bits precision */
+} imdi_iprec;
+
+/* Output per channel processing options. For the compiled */
+/* kernels, this is indexed by physical output channel, */
+/* (not to be confused with the runtime oopt which is indexed */
+/* by callback channel). */
+/* - shift left by channel no * 2 to access option. */
+/* Note that oopts_skip valid only for plane interleaved, */
+/* and doesn't change the number output channels looked up, */
+/* it changes the number of output channels written, hence */
+/* must be matched by the arguments to interp() (number of */
+/* output pointers, stride etc.) */
+typedef enum {
+ oopts_none = 0x0, /* No extra options */
+ oopts_check = 0x1, /* Test channel value against trigger */
+ oopts_skip = 0x2, /* Don't write channel value */
+ oopts_chskp = 0x3 /* oopts_check + oopts_skip */
+} imdi_ooptions;
+
+/* Macro to create an instance of imdi_ooptions for a particular channel */
+#define OOPT(flag,chan) ((flag) << (chan * 2))
+
+/* Macro to extract the flags particular channel */
+#define OOPTX(val,chan) (0x3 & ((val) >> (chan * 2)))
+
+/* Value of no oopt flags set */
+#define OOPTS_NONE 0x00000000
+
+/* Mask to detect any oopts_check flags that are set */
+#define OOPTS_CHECK 0x55555555
+
+/* Mask to ignore any oopts_check flags that are set */
+#define OOPTS_NOT_CHECK 0xAAAAAAAA
+
+/* Mask to detect any oopts_skip flags that are set */
+#define OOPTS_SKIP 0xAAAAAAAA
+
+/* Mask to ignore any oopts_skip flags that are set */
+#define OOPTS_NOT_SKIP 0x55555555
+
+/* Processing options */
+/* Note that there will be a choice between simplex lookup or sort algoritm for */
+/* only a subset of kernels (8 bits processing precision, <= 4 input channels) */
+typedef enum {
+ opts_none = 0x00, /* Forward direction, no stride */
+ opts_fwd = 0x01, /* Forwards direction (default is gen fwd/run don't care) */
+ opts_bwd = 0x02, /* Backwards direction (default is gen fwd/run don't care) */
+ opts_istride = 0x04, /* Stride on input */
+ opts_ostride = 0x08, /* Stride on output */
+
+ opts_splx_sort = 0x10, /* Prefer simplex over sort algorithm (generate both) */
+ opts_sort_splx = 0x20, /* Force sort algorithm, rather than simplex table (generate both) */
+ opts_splx = 0x40, /* Generate simplex only (when possible), default is sort only. */
+
+ opts_end = 0x80 /* End marker */
+} imdi_options;
+
+/* This sructure allows a series of related kernels to be generated */
+#define MX_GDCS 20
+ /* * means multiplies combination */
+ /* + means lockstep with previous line */
+typedef struct {
+ int idcombs[MX_GDCS]; /* * Input dimension combinations (0 at end) */
+ int itres[MX_GDCS]; /* + Interpolation table resolutions for */
+ int stres[MX_GDCS]; /* + Simplex table resolutions */
+
+ int odcombs[MX_GDCS]; /* * Output dimensions combinations (0 at end) */
+ imdi_ooptions ooptcombs[MX_GDCS]; /* + output per channel options */
+
+ imdi_pixrep incombs[MX_GDCS]; /* * Input pixel representation */
+ imdi_iprec iprecs[MX_GDCS]; /* + Internal precision */
+ imdi_pixrep outcombs[MX_GDCS]; /* + Output pixel representation */
+
+ imdi_options optcombs[MX_GDCS]; /* * Direction and stride options */
+} gendesc;
+
+/* -------------------------------------------------- */
+/* Detailed level of generation specification */
+
+/* Pixel layout: */
+/* Each channel value is assumed to be read with a */
+/* native machine single read of size bpch, */
+/* and bov and bpv being bit indexes into that value. */
+/* */
+/* If pint == 0, then each read will be of size bpch[], and will */
+/* have its own pointer, will be incremented by chi[]. */
+/* If pint != 0, then the reads will be size bpch[0], from successive */
+/* locations, chi[] apart. */
+/* */
+/* If packed == 0, then separate reads are needed for each input */
+/* channel. */
+/* If packed != 0, then the channel values will be extracted */
+/* from a single read of size bpch[0] */
+/* */
+/* Note that at all times the bit offset and size values */
+/* will be obeyed for each input value. */
+
+/* NOTE :- if you change this, you need to change the code in cgen.c */
+/* labeled !genspec and tabspec delta code! */
+typedef struct {
+ int bpch[IXDIDO]; /* Bits per channel read (must be divisible by 8) */
+ int chi[IXDIDO]; /* channel increment in multiples of bpch[] (0 == dimensionality) */
+ int bov[IXDIDO]; /* Bit offset to value within channel */
+ int bpv[IXDIDO]; /* Bits per value within channel */
+ int pint; /* Flag - nonz if pixel interleaved (ie. reads from successice locations) */
+ int packed; /* Flag - nonz if all channels are packed into a single read */
+} pixlayout;
+
+/* Structure that specifies the configuration of a generated interpolation kernel. */
+/* NOTE :- if you change this, you need to change the code in cgen.c */
+/* labeled !genspec and tabspec delta code! */
+typedef struct {
+ /* Input to code generator */
+ int prec; /* Internal precision:- either 8 or 16 bits */
+ int id; /* Number of input dimensions used for interpolation */
+ int od; /* Number of output dimensions created by interpolation */
+ imdi_pixrep irep; /* High level input pixel representation */
+ imdi_pixrep orep; /* High level output pixel representation */
+ int in_signed; /* Bit flag per channel, NZ if treat as signed (runtime setup) */
+ int out_signed; /* Bit flag per channel, NZ if treat as signed (runtime setup) */
+ pixlayout in; /* Input pixel layout */
+ pixlayout out; /* Output pixel layout */
+ imdi_ooptions oopt; /* output per channel options */
+ imdi_options opt; /* Direction and stride options */
+ int itres; /* Interpolation table resolution */
+ int stres; /* Simplex table resolution */
+
+ /* Returned value */
+ char kkeys[100]; /* Kernel keys */
+ char kdesc[100]; /* At genspec time */
+ char kname[100]; /* At generation time */
+} genspec;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Translate between high level and low level generation specification */
+int set_genspec(genspec *gs, gendesc *gd, int comb, mach_arch *a);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Convert the input and output pixel representation and the internal */
+/* precision choice into a precision in bits */
+/* (Used at code gen and code execution, hence defined as a macro) */
+#define COMPUTE_IPREC(PRECOUT, INREP, IPREC, OUTREP) \
+{ \
+ int _iprec, _oprec; \
+ \
+ switch (INREP) { \
+ default: \
+ case pixint8: \
+ case planeint8: \
+ _iprec = 8; \
+ break; \
+ case pixint16: \
+ case planeint16: \
+ _iprec = 16; \
+ break; \
+ } \
+ switch (OUTREP) { \
+ default: \
+ case pixint8: \
+ case planeint8: \
+ _oprec = 8; \
+ break; \
+ case pixint16: \
+ case planeint16: \
+ _oprec = 16; \
+ break; \
+ } \
+ switch (IPREC) { \
+ default: \
+ case prec_min: \
+ PRECOUT = _iprec < _oprec ? _iprec : _oprec; \
+ break; \
+ case prec_max: \
+ PRECOUT = _iprec > _oprec ? _iprec : _oprec; \
+ break; \
+ case prec_in: \
+ PRECOUT = _iprec; \
+ break; \
+ case prec_out: \
+ PRECOUT = _oprec; \
+ break; \
+ case prec_p8: \
+ PRECOUT = 8; \
+ break; \
+ case prec_p16: \
+ PRECOUT = 16; \
+ break; \
+ } \
+} \
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+struct _tabspec;
+
+/* Supported code generators: */
+
+/* The 'C' code generator */
+/* Generate a source file to implement the specified */
+/* interpolation kernel. Fill in return values and return 0 if OK. */
+/* Return 1 if this kernel should be skipped (ie. force sort and sort not forced) */
+/* and some other anon-zero on error. */
+int gen_c_kernel(genspec *g, struct _tabspec *t, mach_arch *a,
+ FILE *fp, int index, genspec *og, struct _tabspec *ot);
+
+/* asm, MMX, etc. generators declarations go here ! */
+
+#endif /* IMDI_GEN_H */
+
+
+
+
+
+
+
+
+
+
+
diff --git a/imdi/imdi_k.h b/imdi/imdi_k.h
new file mode 100644
index 0000000..79f60d5
--- /dev/null
+++ b/imdi/imdi_k.h
@@ -0,0 +1,910 @@
+/* Integer Multi-Dimensional Interpolation */
+/* Declarations for all the generated kernel functions */
+/* This file is generated by imdi_make */
+
+/* Copyright 2000 - 2007 Graeme W. Gill */
+/* All rights reserved. */
+/* This material is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- */
+/* see the License.txt file for licensing details.*/
+
+#include "imdi_k.c" /* All the kernel code */
+
+struct {
+ void (*interp)(imdi *s, void **outp, int ostride, void **inp, int istride, unsigned int npix);
+ void (*gentab)(genspec *g, tabspec *t);
+} ktable[891] = {
+ { imdi_k1, imdi_k1_gentab },
+ { imdi_k2, imdi_k2_gentab },
+ { imdi_k3, imdi_k3_gentab },
+ { imdi_k4, imdi_k4_gentab },
+ { imdi_k5, imdi_k5_gentab },
+ { imdi_k6, imdi_k6_gentab },
+ { imdi_k7, imdi_k7_gentab },
+ { imdi_k8, imdi_k8_gentab },
+ { imdi_k9, imdi_k9_gentab },
+ { imdi_k10, imdi_k10_gentab },
+ { imdi_k11, imdi_k11_gentab },
+ { imdi_k12, imdi_k12_gentab },
+ { imdi_k13, imdi_k13_gentab },
+ { imdi_k14, imdi_k14_gentab },
+ { imdi_k15, imdi_k15_gentab },
+ { imdi_k16, imdi_k16_gentab },
+ { imdi_k17, imdi_k17_gentab },
+ { imdi_k18, imdi_k18_gentab },
+ { imdi_k19, imdi_k19_gentab },
+ { imdi_k20, imdi_k20_gentab },
+ { imdi_k21, imdi_k21_gentab },
+ { imdi_k22, imdi_k22_gentab },
+ { imdi_k23, imdi_k23_gentab },
+ { imdi_k24, imdi_k24_gentab },
+ { imdi_k25, imdi_k25_gentab },
+ { imdi_k26, imdi_k26_gentab },
+ { imdi_k27, imdi_k27_gentab },
+ { imdi_k28, imdi_k28_gentab },
+ { imdi_k29, imdi_k29_gentab },
+ { imdi_k30, imdi_k30_gentab },
+ { imdi_k31, imdi_k31_gentab },
+ { imdi_k32, imdi_k32_gentab },
+ { imdi_k33, imdi_k33_gentab },
+ { imdi_k34, imdi_k34_gentab },
+ { imdi_k35, imdi_k35_gentab },
+ { imdi_k36, imdi_k36_gentab },
+ { imdi_k37, imdi_k37_gentab },
+ { imdi_k38, imdi_k38_gentab },
+ { imdi_k39, imdi_k39_gentab },
+ { imdi_k40, imdi_k40_gentab },
+ { imdi_k41, imdi_k41_gentab },
+ { imdi_k42, imdi_k42_gentab },
+ { imdi_k43, imdi_k43_gentab },
+ { imdi_k44, imdi_k44_gentab },
+ { imdi_k45, imdi_k45_gentab },
+ { imdi_k46, imdi_k46_gentab },
+ { imdi_k47, imdi_k47_gentab },
+ { imdi_k48, imdi_k48_gentab },
+ { imdi_k49, imdi_k49_gentab },
+ { imdi_k50, imdi_k50_gentab },
+ { imdi_k51, imdi_k51_gentab },
+ { imdi_k52, imdi_k52_gentab },
+ { imdi_k53, imdi_k53_gentab },
+ { imdi_k54, imdi_k54_gentab },
+ { imdi_k55, imdi_k55_gentab },
+ { imdi_k56, imdi_k56_gentab },
+ { imdi_k57, imdi_k57_gentab },
+ { imdi_k58, imdi_k58_gentab },
+ { imdi_k59, imdi_k59_gentab },
+ { imdi_k60, imdi_k60_gentab },
+ { imdi_k61, imdi_k61_gentab },
+ { imdi_k62, imdi_k62_gentab },
+ { imdi_k63, imdi_k63_gentab },
+ { imdi_k64, imdi_k64_gentab },
+ { imdi_k65, imdi_k65_gentab },
+ { imdi_k66, imdi_k66_gentab },
+ { imdi_k67, imdi_k67_gentab },
+ { imdi_k68, imdi_k68_gentab },
+ { imdi_k69, imdi_k69_gentab },
+ { imdi_k70, imdi_k70_gentab },
+ { imdi_k71, imdi_k71_gentab },
+ { imdi_k72, imdi_k72_gentab },
+ { imdi_k73, imdi_k73_gentab },
+ { imdi_k74, imdi_k74_gentab },
+ { imdi_k75, imdi_k75_gentab },
+ { imdi_k76, imdi_k76_gentab },
+ { imdi_k77, imdi_k77_gentab },
+ { imdi_k78, imdi_k78_gentab },
+ { imdi_k79, imdi_k79_gentab },
+ { imdi_k80, imdi_k80_gentab },
+ { imdi_k81, imdi_k81_gentab },
+ { imdi_k82, imdi_k82_gentab },
+ { imdi_k83, imdi_k83_gentab },
+ { imdi_k84, imdi_k84_gentab },
+ { imdi_k85, imdi_k85_gentab },
+ { imdi_k86, imdi_k86_gentab },
+ { imdi_k87, imdi_k87_gentab },
+ { imdi_k88, imdi_k88_gentab },
+ { imdi_k89, imdi_k89_gentab },
+ { imdi_k90, imdi_k90_gentab },
+ { imdi_k91, imdi_k91_gentab },
+ { imdi_k92, imdi_k92_gentab },
+ { imdi_k93, imdi_k93_gentab },
+ { imdi_k94, imdi_k94_gentab },
+ { imdi_k95, imdi_k95_gentab },
+ { imdi_k96, imdi_k96_gentab },
+ { imdi_k97, imdi_k97_gentab },
+ { imdi_k98, imdi_k98_gentab },
+ { imdi_k99, imdi_k99_gentab },
+ { imdi_k100, imdi_k100_gentab },
+ { imdi_k101, imdi_k101_gentab },
+ { imdi_k102, imdi_k102_gentab },
+ { imdi_k103, imdi_k103_gentab },
+ { imdi_k104, imdi_k104_gentab },
+ { imdi_k105, imdi_k105_gentab },
+ { imdi_k106, imdi_k106_gentab },
+ { imdi_k107, imdi_k107_gentab },
+ { imdi_k108, imdi_k108_gentab },
+ { imdi_k109, imdi_k109_gentab },
+ { imdi_k110, imdi_k110_gentab },
+ { imdi_k111, imdi_k111_gentab },
+ { imdi_k112, imdi_k112_gentab },
+ { imdi_k113, imdi_k113_gentab },
+ { imdi_k114, imdi_k114_gentab },
+ { imdi_k115, imdi_k115_gentab },
+ { imdi_k116, imdi_k116_gentab },
+ { imdi_k117, imdi_k117_gentab },
+ { imdi_k118, imdi_k118_gentab },
+ { imdi_k119, imdi_k119_gentab },
+ { imdi_k120, imdi_k120_gentab },
+ { imdi_k121, imdi_k121_gentab },
+ { imdi_k122, imdi_k122_gentab },
+ { imdi_k123, imdi_k123_gentab },
+ { imdi_k124, imdi_k124_gentab },
+ { imdi_k125, imdi_k125_gentab },
+ { imdi_k126, imdi_k126_gentab },
+ { imdi_k127, imdi_k127_gentab },
+ { imdi_k128, imdi_k128_gentab },
+ { imdi_k129, imdi_k129_gentab },
+ { imdi_k130, imdi_k130_gentab },
+ { imdi_k131, imdi_k131_gentab },
+ { imdi_k132, imdi_k132_gentab },
+ { imdi_k133, imdi_k133_gentab },
+ { imdi_k134, imdi_k134_gentab },
+ { imdi_k135, imdi_k135_gentab },
+ { imdi_k136, imdi_k136_gentab },
+ { imdi_k137, imdi_k137_gentab },
+ { imdi_k138, imdi_k138_gentab },
+ { imdi_k139, imdi_k139_gentab },
+ { imdi_k140, imdi_k140_gentab },
+ { imdi_k141, imdi_k141_gentab },
+ { imdi_k142, imdi_k142_gentab },
+ { imdi_k143, imdi_k143_gentab },
+ { imdi_k144, imdi_k144_gentab },
+ { imdi_k145, imdi_k145_gentab },
+ { imdi_k146, imdi_k146_gentab },
+ { imdi_k147, imdi_k147_gentab },
+ { imdi_k148, imdi_k148_gentab },
+ { imdi_k149, imdi_k149_gentab },
+ { imdi_k150, imdi_k150_gentab },
+ { imdi_k151, imdi_k151_gentab },
+ { imdi_k152, imdi_k152_gentab },
+ { imdi_k153, imdi_k153_gentab },
+ { imdi_k154, imdi_k154_gentab },
+ { imdi_k155, imdi_k155_gentab },
+ { imdi_k156, imdi_k156_gentab },
+ { imdi_k157, imdi_k157_gentab },
+ { imdi_k158, imdi_k158_gentab },
+ { imdi_k159, imdi_k159_gentab },
+ { imdi_k160, imdi_k160_gentab },
+ { imdi_k161, imdi_k161_gentab },
+ { imdi_k162, imdi_k162_gentab },
+ { imdi_k163, imdi_k163_gentab },
+ { imdi_k164, imdi_k164_gentab },
+ { imdi_k165, imdi_k165_gentab },
+ { imdi_k166, imdi_k166_gentab },
+ { imdi_k167, imdi_k167_gentab },
+ { imdi_k168, imdi_k168_gentab },
+ { imdi_k169, imdi_k169_gentab },
+ { imdi_k170, imdi_k170_gentab },
+ { imdi_k171, imdi_k171_gentab },
+ { imdi_k172, imdi_k172_gentab },
+ { imdi_k173, imdi_k173_gentab },
+ { imdi_k174, imdi_k174_gentab },
+ { imdi_k175, imdi_k175_gentab },
+ { imdi_k176, imdi_k176_gentab },
+ { imdi_k177, imdi_k177_gentab },
+ { imdi_k178, imdi_k178_gentab },
+ { imdi_k179, imdi_k179_gentab },
+ { imdi_k180, imdi_k180_gentab },
+ { imdi_k181, imdi_k181_gentab },
+ { imdi_k182, imdi_k182_gentab },
+ { imdi_k183, imdi_k183_gentab },
+ { imdi_k184, imdi_k184_gentab },
+ { imdi_k185, imdi_k185_gentab },
+ { imdi_k186, imdi_k186_gentab },
+ { imdi_k187, imdi_k187_gentab },
+ { imdi_k188, imdi_k188_gentab },
+ { imdi_k189, imdi_k189_gentab },
+ { imdi_k190, imdi_k190_gentab },
+ { imdi_k191, imdi_k191_gentab },
+ { imdi_k192, imdi_k192_gentab },
+ { imdi_k193, imdi_k193_gentab },
+ { imdi_k194, imdi_k194_gentab },
+ { imdi_k195, imdi_k195_gentab },
+ { imdi_k196, imdi_k196_gentab },
+ { imdi_k197, imdi_k197_gentab },
+ { imdi_k198, imdi_k198_gentab },
+ { imdi_k199, imdi_k199_gentab },
+ { imdi_k200, imdi_k200_gentab },
+ { imdi_k201, imdi_k201_gentab },
+ { imdi_k202, imdi_k202_gentab },
+ { imdi_k203, imdi_k203_gentab },
+ { imdi_k204, imdi_k204_gentab },
+ { imdi_k205, imdi_k205_gentab },
+ { imdi_k206, imdi_k206_gentab },
+ { imdi_k207, imdi_k207_gentab },
+ { imdi_k208, imdi_k208_gentab },
+ { imdi_k209, imdi_k209_gentab },
+ { imdi_k210, imdi_k210_gentab },
+ { imdi_k211, imdi_k211_gentab },
+ { imdi_k212, imdi_k212_gentab },
+ { imdi_k213, imdi_k213_gentab },
+ { imdi_k214, imdi_k214_gentab },
+ { imdi_k215, imdi_k215_gentab },
+ { imdi_k216, imdi_k216_gentab },
+ { imdi_k217, imdi_k217_gentab },
+ { imdi_k218, imdi_k218_gentab },
+ { imdi_k219, imdi_k219_gentab },
+ { imdi_k220, imdi_k220_gentab },
+ { imdi_k221, imdi_k221_gentab },
+ { imdi_k222, imdi_k222_gentab },
+ { imdi_k223, imdi_k223_gentab },
+ { imdi_k224, imdi_k224_gentab },
+ { imdi_k225, imdi_k225_gentab },
+ { imdi_k226, imdi_k226_gentab },
+ { imdi_k227, imdi_k227_gentab },
+ { imdi_k228, imdi_k228_gentab },
+ { imdi_k229, imdi_k229_gentab },
+ { imdi_k230, imdi_k230_gentab },
+ { imdi_k231, imdi_k231_gentab },
+ { imdi_k232, imdi_k232_gentab },
+ { imdi_k233, imdi_k233_gentab },
+ { imdi_k234, imdi_k234_gentab },
+ { imdi_k235, imdi_k235_gentab },
+ { imdi_k236, imdi_k236_gentab },
+ { imdi_k237, imdi_k237_gentab },
+ { imdi_k238, imdi_k238_gentab },
+ { imdi_k239, imdi_k239_gentab },
+ { imdi_k240, imdi_k240_gentab },
+ { imdi_k241, imdi_k241_gentab },
+ { imdi_k242, imdi_k242_gentab },
+ { imdi_k243, imdi_k243_gentab },
+ { imdi_k244, imdi_k244_gentab },
+ { imdi_k245, imdi_k245_gentab },
+ { imdi_k246, imdi_k246_gentab },
+ { imdi_k247, imdi_k247_gentab },
+ { imdi_k248, imdi_k248_gentab },
+ { imdi_k249, imdi_k249_gentab },
+ { imdi_k250, imdi_k250_gentab },
+ { imdi_k251, imdi_k251_gentab },
+ { imdi_k252, imdi_k252_gentab },
+ { imdi_k253, imdi_k253_gentab },
+ { imdi_k254, imdi_k254_gentab },
+ { imdi_k255, imdi_k255_gentab },
+ { imdi_k256, imdi_k256_gentab },
+ { imdi_k257, imdi_k257_gentab },
+ { imdi_k258, imdi_k258_gentab },
+ { imdi_k259, imdi_k259_gentab },
+ { imdi_k260, imdi_k260_gentab },
+ { imdi_k261, imdi_k261_gentab },
+ { imdi_k262, imdi_k262_gentab },
+ { imdi_k263, imdi_k263_gentab },
+ { imdi_k264, imdi_k264_gentab },
+ { imdi_k265, imdi_k265_gentab },
+ { imdi_k266, imdi_k266_gentab },
+ { imdi_k267, imdi_k267_gentab },
+ { imdi_k268, imdi_k268_gentab },
+ { imdi_k269, imdi_k269_gentab },
+ { imdi_k270, imdi_k270_gentab },
+ { imdi_k271, imdi_k271_gentab },
+ { imdi_k272, imdi_k272_gentab },
+ { imdi_k273, imdi_k273_gentab },
+ { imdi_k274, imdi_k274_gentab },
+ { imdi_k275, imdi_k275_gentab },
+ { imdi_k276, imdi_k276_gentab },
+ { imdi_k277, imdi_k277_gentab },
+ { imdi_k278, imdi_k278_gentab },
+ { imdi_k279, imdi_k279_gentab },
+ { imdi_k280, imdi_k280_gentab },
+ { imdi_k281, imdi_k281_gentab },
+ { imdi_k282, imdi_k282_gentab },
+ { imdi_k283, imdi_k283_gentab },
+ { imdi_k284, imdi_k284_gentab },
+ { imdi_k285, imdi_k285_gentab },
+ { imdi_k286, imdi_k286_gentab },
+ { imdi_k287, imdi_k287_gentab },
+ { imdi_k288, imdi_k288_gentab },
+ { imdi_k289, imdi_k289_gentab },
+ { imdi_k290, imdi_k290_gentab },
+ { imdi_k291, imdi_k291_gentab },
+ { imdi_k292, imdi_k292_gentab },
+ { imdi_k293, imdi_k293_gentab },
+ { imdi_k294, imdi_k294_gentab },
+ { imdi_k295, imdi_k295_gentab },
+ { imdi_k296, imdi_k296_gentab },
+ { imdi_k297, imdi_k297_gentab },
+ { imdi_k298, imdi_k298_gentab },
+ { imdi_k299, imdi_k299_gentab },
+ { imdi_k300, imdi_k300_gentab },
+ { imdi_k301, imdi_k301_gentab },
+ { imdi_k302, imdi_k302_gentab },
+ { imdi_k303, imdi_k303_gentab },
+ { imdi_k304, imdi_k304_gentab },
+ { imdi_k305, imdi_k305_gentab },
+ { imdi_k306, imdi_k306_gentab },
+ { imdi_k307, imdi_k307_gentab },
+ { imdi_k308, imdi_k308_gentab },
+ { imdi_k309, imdi_k309_gentab },
+ { imdi_k310, imdi_k310_gentab },
+ { imdi_k311, imdi_k311_gentab },
+ { imdi_k312, imdi_k312_gentab },
+ { imdi_k313, imdi_k313_gentab },
+ { imdi_k314, imdi_k314_gentab },
+ { imdi_k315, imdi_k315_gentab },
+ { imdi_k316, imdi_k316_gentab },
+ { imdi_k317, imdi_k317_gentab },
+ { imdi_k318, imdi_k318_gentab },
+ { imdi_k319, imdi_k319_gentab },
+ { imdi_k320, imdi_k320_gentab },
+ { imdi_k321, imdi_k321_gentab },
+ { imdi_k322, imdi_k322_gentab },
+ { imdi_k323, imdi_k323_gentab },
+ { imdi_k324, imdi_k324_gentab },
+ { imdi_k325, imdi_k325_gentab },
+ { imdi_k326, imdi_k326_gentab },
+ { imdi_k327, imdi_k327_gentab },
+ { imdi_k328, imdi_k328_gentab },
+ { imdi_k329, imdi_k329_gentab },
+ { imdi_k330, imdi_k330_gentab },
+ { imdi_k331, imdi_k331_gentab },
+ { imdi_k332, imdi_k332_gentab },
+ { imdi_k333, imdi_k333_gentab },
+ { imdi_k334, imdi_k334_gentab },
+ { imdi_k335, imdi_k335_gentab },
+ { imdi_k336, imdi_k336_gentab },
+ { imdi_k337, imdi_k337_gentab },
+ { imdi_k338, imdi_k338_gentab },
+ { imdi_k339, imdi_k339_gentab },
+ { imdi_k340, imdi_k340_gentab },
+ { imdi_k341, imdi_k341_gentab },
+ { imdi_k342, imdi_k342_gentab },
+ { imdi_k343, imdi_k343_gentab },
+ { imdi_k344, imdi_k344_gentab },
+ { imdi_k345, imdi_k345_gentab },
+ { imdi_k346, imdi_k346_gentab },
+ { imdi_k347, imdi_k347_gentab },
+ { imdi_k348, imdi_k348_gentab },
+ { imdi_k349, imdi_k349_gentab },
+ { imdi_k350, imdi_k350_gentab },
+ { imdi_k351, imdi_k351_gentab },
+ { imdi_k352, imdi_k352_gentab },
+ { imdi_k353, imdi_k353_gentab },
+ { imdi_k354, imdi_k354_gentab },
+ { imdi_k355, imdi_k355_gentab },
+ { imdi_k356, imdi_k356_gentab },
+ { imdi_k357, imdi_k357_gentab },
+ { imdi_k358, imdi_k358_gentab },
+ { imdi_k359, imdi_k359_gentab },
+ { imdi_k360, imdi_k360_gentab },
+ { imdi_k361, imdi_k361_gentab },
+ { imdi_k362, imdi_k362_gentab },
+ { imdi_k363, imdi_k363_gentab },
+ { imdi_k364, imdi_k364_gentab },
+ { imdi_k365, imdi_k365_gentab },
+ { imdi_k366, imdi_k366_gentab },
+ { imdi_k367, imdi_k367_gentab },
+ { imdi_k368, imdi_k368_gentab },
+ { imdi_k369, imdi_k369_gentab },
+ { imdi_k370, imdi_k370_gentab },
+ { imdi_k371, imdi_k371_gentab },
+ { imdi_k372, imdi_k372_gentab },
+ { imdi_k373, imdi_k373_gentab },
+ { imdi_k374, imdi_k374_gentab },
+ { imdi_k375, imdi_k375_gentab },
+ { imdi_k376, imdi_k376_gentab },
+ { imdi_k377, imdi_k377_gentab },
+ { imdi_k378, imdi_k378_gentab },
+ { imdi_k379, imdi_k379_gentab },
+ { imdi_k380, imdi_k380_gentab },
+ { imdi_k381, imdi_k381_gentab },
+ { imdi_k382, imdi_k382_gentab },
+ { imdi_k383, imdi_k383_gentab },
+ { imdi_k384, imdi_k384_gentab },
+ { imdi_k385, imdi_k385_gentab },
+ { imdi_k386, imdi_k386_gentab },
+ { imdi_k387, imdi_k387_gentab },
+ { imdi_k388, imdi_k388_gentab },
+ { imdi_k389, imdi_k389_gentab },
+ { imdi_k390, imdi_k390_gentab },
+ { imdi_k391, imdi_k391_gentab },
+ { imdi_k392, imdi_k392_gentab },
+ { imdi_k393, imdi_k393_gentab },
+ { imdi_k394, imdi_k394_gentab },
+ { imdi_k395, imdi_k395_gentab },
+ { imdi_k396, imdi_k396_gentab },
+ { imdi_k397, imdi_k397_gentab },
+ { imdi_k398, imdi_k398_gentab },
+ { imdi_k399, imdi_k399_gentab },
+ { imdi_k400, imdi_k400_gentab },
+ { imdi_k401, imdi_k401_gentab },
+ { imdi_k402, imdi_k402_gentab },
+ { imdi_k403, imdi_k403_gentab },
+ { imdi_k404, imdi_k404_gentab },
+ { imdi_k405, imdi_k405_gentab },
+ { imdi_k406, imdi_k406_gentab },
+ { imdi_k407, imdi_k407_gentab },
+ { imdi_k408, imdi_k408_gentab },
+ { imdi_k409, imdi_k409_gentab },
+ { imdi_k410, imdi_k410_gentab },
+ { imdi_k411, imdi_k411_gentab },
+ { imdi_k412, imdi_k412_gentab },
+ { imdi_k413, imdi_k413_gentab },
+ { imdi_k414, imdi_k414_gentab },
+ { imdi_k415, imdi_k415_gentab },
+ { imdi_k416, imdi_k416_gentab },
+ { imdi_k417, imdi_k417_gentab },
+ { imdi_k418, imdi_k418_gentab },
+ { imdi_k419, imdi_k419_gentab },
+ { imdi_k420, imdi_k420_gentab },
+ { imdi_k421, imdi_k421_gentab },
+ { imdi_k422, imdi_k422_gentab },
+ { imdi_k423, imdi_k423_gentab },
+ { imdi_k424, imdi_k424_gentab },
+ { imdi_k425, imdi_k425_gentab },
+ { imdi_k426, imdi_k426_gentab },
+ { imdi_k427, imdi_k427_gentab },
+ { imdi_k428, imdi_k428_gentab },
+ { imdi_k429, imdi_k429_gentab },
+ { imdi_k430, imdi_k430_gentab },
+ { imdi_k431, imdi_k431_gentab },
+ { imdi_k432, imdi_k432_gentab },
+ { imdi_k433, imdi_k433_gentab },
+ { imdi_k434, imdi_k434_gentab },
+ { imdi_k435, imdi_k435_gentab },
+ { imdi_k436, imdi_k436_gentab },
+ { imdi_k437, imdi_k437_gentab },
+ { imdi_k438, imdi_k438_gentab },
+ { imdi_k439, imdi_k439_gentab },
+ { imdi_k440, imdi_k440_gentab },
+ { imdi_k441, imdi_k441_gentab },
+ { imdi_k442, imdi_k442_gentab },
+ { imdi_k443, imdi_k443_gentab },
+ { imdi_k444, imdi_k444_gentab },
+ { imdi_k445, imdi_k445_gentab },
+ { imdi_k446, imdi_k446_gentab },
+ { imdi_k447, imdi_k447_gentab },
+ { imdi_k448, imdi_k448_gentab },
+ { imdi_k449, imdi_k449_gentab },
+ { imdi_k450, imdi_k450_gentab },
+ { imdi_k451, imdi_k451_gentab },
+ { imdi_k452, imdi_k452_gentab },
+ { imdi_k453, imdi_k453_gentab },
+ { imdi_k454, imdi_k454_gentab },
+ { imdi_k455, imdi_k455_gentab },
+ { imdi_k456, imdi_k456_gentab },
+ { imdi_k457, imdi_k457_gentab },
+ { imdi_k458, imdi_k458_gentab },
+ { imdi_k459, imdi_k459_gentab },
+ { imdi_k460, imdi_k460_gentab },
+ { imdi_k461, imdi_k461_gentab },
+ { imdi_k462, imdi_k462_gentab },
+ { imdi_k463, imdi_k463_gentab },
+ { imdi_k464, imdi_k464_gentab },
+ { imdi_k465, imdi_k465_gentab },
+ { imdi_k466, imdi_k466_gentab },
+ { imdi_k467, imdi_k467_gentab },
+ { imdi_k468, imdi_k468_gentab },
+ { imdi_k469, imdi_k469_gentab },
+ { imdi_k470, imdi_k470_gentab },
+ { imdi_k471, imdi_k471_gentab },
+ { imdi_k472, imdi_k472_gentab },
+ { imdi_k473, imdi_k473_gentab },
+ { imdi_k474, imdi_k474_gentab },
+ { imdi_k475, imdi_k475_gentab },
+ { imdi_k476, imdi_k476_gentab },
+ { imdi_k477, imdi_k477_gentab },
+ { imdi_k478, imdi_k478_gentab },
+ { imdi_k479, imdi_k479_gentab },
+ { imdi_k480, imdi_k480_gentab },
+ { imdi_k481, imdi_k481_gentab },
+ { imdi_k482, imdi_k482_gentab },
+ { imdi_k483, imdi_k483_gentab },
+ { imdi_k484, imdi_k484_gentab },
+ { imdi_k485, imdi_k485_gentab },
+ { imdi_k486, imdi_k486_gentab },
+ { imdi_k487, imdi_k487_gentab },
+ { imdi_k488, imdi_k488_gentab },
+ { imdi_k489, imdi_k489_gentab },
+ { imdi_k490, imdi_k490_gentab },
+ { imdi_k491, imdi_k491_gentab },
+ { imdi_k492, imdi_k492_gentab },
+ { imdi_k493, imdi_k493_gentab },
+ { imdi_k494, imdi_k494_gentab },
+ { imdi_k495, imdi_k495_gentab },
+ { imdi_k496, imdi_k496_gentab },
+ { imdi_k497, imdi_k497_gentab },
+ { imdi_k498, imdi_k498_gentab },
+ { imdi_k499, imdi_k499_gentab },
+ { imdi_k500, imdi_k500_gentab },
+ { imdi_k501, imdi_k501_gentab },
+ { imdi_k502, imdi_k502_gentab },
+ { imdi_k503, imdi_k503_gentab },
+ { imdi_k504, imdi_k504_gentab },
+ { imdi_k505, imdi_k505_gentab },
+ { imdi_k506, imdi_k506_gentab },
+ { imdi_k507, imdi_k507_gentab },
+ { imdi_k508, imdi_k508_gentab },
+ { imdi_k509, imdi_k509_gentab },
+ { imdi_k510, imdi_k510_gentab },
+ { imdi_k511, imdi_k511_gentab },
+ { imdi_k512, imdi_k512_gentab },
+ { imdi_k513, imdi_k513_gentab },
+ { imdi_k514, imdi_k514_gentab },
+ { imdi_k515, imdi_k515_gentab },
+ { imdi_k516, imdi_k516_gentab },
+ { imdi_k517, imdi_k517_gentab },
+ { imdi_k518, imdi_k518_gentab },
+ { imdi_k519, imdi_k519_gentab },
+ { imdi_k520, imdi_k520_gentab },
+ { imdi_k521, imdi_k521_gentab },
+ { imdi_k522, imdi_k522_gentab },
+ { imdi_k523, imdi_k523_gentab },
+ { imdi_k524, imdi_k524_gentab },
+ { imdi_k525, imdi_k525_gentab },
+ { imdi_k526, imdi_k526_gentab },
+ { imdi_k527, imdi_k527_gentab },
+ { imdi_k528, imdi_k528_gentab },
+ { imdi_k529, imdi_k529_gentab },
+ { imdi_k530, imdi_k530_gentab },
+ { imdi_k531, imdi_k531_gentab },
+ { imdi_k532, imdi_k532_gentab },
+ { imdi_k533, imdi_k533_gentab },
+ { imdi_k534, imdi_k534_gentab },
+ { imdi_k535, imdi_k535_gentab },
+ { imdi_k536, imdi_k536_gentab },
+ { imdi_k537, imdi_k537_gentab },
+ { imdi_k538, imdi_k538_gentab },
+ { imdi_k539, imdi_k539_gentab },
+ { imdi_k540, imdi_k540_gentab },
+ { imdi_k541, imdi_k541_gentab },
+ { imdi_k542, imdi_k542_gentab },
+ { imdi_k543, imdi_k543_gentab },
+ { imdi_k544, imdi_k544_gentab },
+ { imdi_k545, imdi_k545_gentab },
+ { imdi_k546, imdi_k546_gentab },
+ { imdi_k547, imdi_k547_gentab },
+ { imdi_k548, imdi_k548_gentab },
+ { imdi_k549, imdi_k549_gentab },
+ { imdi_k550, imdi_k550_gentab },
+ { imdi_k551, imdi_k551_gentab },
+ { imdi_k552, imdi_k552_gentab },
+ { imdi_k553, imdi_k553_gentab },
+ { imdi_k554, imdi_k554_gentab },
+ { imdi_k555, imdi_k555_gentab },
+ { imdi_k556, imdi_k556_gentab },
+ { imdi_k557, imdi_k557_gentab },
+ { imdi_k558, imdi_k558_gentab },
+ { imdi_k559, imdi_k559_gentab },
+ { imdi_k560, imdi_k560_gentab },
+ { imdi_k561, imdi_k561_gentab },
+ { imdi_k562, imdi_k562_gentab },
+ { imdi_k563, imdi_k563_gentab },
+ { imdi_k564, imdi_k564_gentab },
+ { imdi_k565, imdi_k565_gentab },
+ { imdi_k566, imdi_k566_gentab },
+ { imdi_k567, imdi_k567_gentab },
+ { imdi_k568, imdi_k568_gentab },
+ { imdi_k569, imdi_k569_gentab },
+ { imdi_k570, imdi_k570_gentab },
+ { imdi_k571, imdi_k571_gentab },
+ { imdi_k572, imdi_k572_gentab },
+ { imdi_k573, imdi_k573_gentab },
+ { imdi_k574, imdi_k574_gentab },
+ { imdi_k575, imdi_k575_gentab },
+ { imdi_k576, imdi_k576_gentab },
+ { imdi_k577, imdi_k577_gentab },
+ { imdi_k578, imdi_k578_gentab },
+ { imdi_k579, imdi_k579_gentab },
+ { imdi_k580, imdi_k580_gentab },
+ { imdi_k581, imdi_k581_gentab },
+ { imdi_k582, imdi_k582_gentab },
+ { imdi_k583, imdi_k583_gentab },
+ { imdi_k584, imdi_k584_gentab },
+ { imdi_k585, imdi_k585_gentab },
+ { imdi_k586, imdi_k586_gentab },
+ { imdi_k587, imdi_k587_gentab },
+ { imdi_k588, imdi_k588_gentab },
+ { imdi_k589, imdi_k589_gentab },
+ { imdi_k590, imdi_k590_gentab },
+ { imdi_k591, imdi_k591_gentab },
+ { imdi_k592, imdi_k592_gentab },
+ { imdi_k593, imdi_k593_gentab },
+ { imdi_k594, imdi_k594_gentab },
+ { imdi_k595, imdi_k595_gentab },
+ { imdi_k596, imdi_k596_gentab },
+ { imdi_k597, imdi_k597_gentab },
+ { imdi_k598, imdi_k598_gentab },
+ { imdi_k599, imdi_k599_gentab },
+ { imdi_k600, imdi_k600_gentab },
+ { imdi_k601, imdi_k601_gentab },
+ { imdi_k602, imdi_k602_gentab },
+ { imdi_k603, imdi_k603_gentab },
+ { imdi_k604, imdi_k604_gentab },
+ { imdi_k605, imdi_k605_gentab },
+ { imdi_k606, imdi_k606_gentab },
+ { imdi_k607, imdi_k607_gentab },
+ { imdi_k608, imdi_k608_gentab },
+ { imdi_k609, imdi_k609_gentab },
+ { imdi_k610, imdi_k610_gentab },
+ { imdi_k611, imdi_k611_gentab },
+ { imdi_k612, imdi_k612_gentab },
+ { imdi_k613, imdi_k613_gentab },
+ { imdi_k614, imdi_k614_gentab },
+ { imdi_k615, imdi_k615_gentab },
+ { imdi_k616, imdi_k616_gentab },
+ { imdi_k617, imdi_k617_gentab },
+ { imdi_k618, imdi_k618_gentab },
+ { imdi_k619, imdi_k619_gentab },
+ { imdi_k620, imdi_k620_gentab },
+ { imdi_k621, imdi_k621_gentab },
+ { imdi_k622, imdi_k622_gentab },
+ { imdi_k623, imdi_k623_gentab },
+ { imdi_k624, imdi_k624_gentab },
+ { imdi_k625, imdi_k625_gentab },
+ { imdi_k626, imdi_k626_gentab },
+ { imdi_k627, imdi_k627_gentab },
+ { imdi_k628, imdi_k628_gentab },
+ { imdi_k629, imdi_k629_gentab },
+ { imdi_k630, imdi_k630_gentab },
+ { imdi_k631, imdi_k631_gentab },
+ { imdi_k632, imdi_k632_gentab },
+ { imdi_k633, imdi_k633_gentab },
+ { imdi_k634, imdi_k634_gentab },
+ { imdi_k635, imdi_k635_gentab },
+ { imdi_k636, imdi_k636_gentab },
+ { imdi_k637, imdi_k637_gentab },
+ { imdi_k638, imdi_k638_gentab },
+ { imdi_k639, imdi_k639_gentab },
+ { imdi_k640, imdi_k640_gentab },
+ { imdi_k641, imdi_k641_gentab },
+ { imdi_k642, imdi_k642_gentab },
+ { imdi_k643, imdi_k643_gentab },
+ { imdi_k644, imdi_k644_gentab },
+ { imdi_k645, imdi_k645_gentab },
+ { imdi_k646, imdi_k646_gentab },
+ { imdi_k647, imdi_k647_gentab },
+ { imdi_k648, imdi_k648_gentab },
+ { imdi_k649, imdi_k649_gentab },
+ { imdi_k650, imdi_k650_gentab },
+ { imdi_k651, imdi_k651_gentab },
+ { imdi_k652, imdi_k652_gentab },
+ { imdi_k653, imdi_k653_gentab },
+ { imdi_k654, imdi_k654_gentab },
+ { imdi_k655, imdi_k655_gentab },
+ { imdi_k656, imdi_k656_gentab },
+ { imdi_k657, imdi_k657_gentab },
+ { imdi_k658, imdi_k658_gentab },
+ { imdi_k659, imdi_k659_gentab },
+ { imdi_k660, imdi_k660_gentab },
+ { imdi_k661, imdi_k661_gentab },
+ { imdi_k662, imdi_k662_gentab },
+ { imdi_k663, imdi_k663_gentab },
+ { imdi_k664, imdi_k664_gentab },
+ { imdi_k665, imdi_k665_gentab },
+ { imdi_k666, imdi_k666_gentab },
+ { imdi_k667, imdi_k667_gentab },
+ { imdi_k668, imdi_k668_gentab },
+ { imdi_k669, imdi_k669_gentab },
+ { imdi_k670, imdi_k670_gentab },
+ { imdi_k671, imdi_k671_gentab },
+ { imdi_k672, imdi_k672_gentab },
+ { imdi_k673, imdi_k673_gentab },
+ { imdi_k674, imdi_k674_gentab },
+ { imdi_k675, imdi_k675_gentab },
+ { imdi_k676, imdi_k676_gentab },
+ { imdi_k677, imdi_k677_gentab },
+ { imdi_k678, imdi_k678_gentab },
+ { imdi_k679, imdi_k679_gentab },
+ { imdi_k680, imdi_k680_gentab },
+ { imdi_k681, imdi_k681_gentab },
+ { imdi_k682, imdi_k682_gentab },
+ { imdi_k683, imdi_k683_gentab },
+ { imdi_k684, imdi_k684_gentab },
+ { imdi_k685, imdi_k685_gentab },
+ { imdi_k686, imdi_k686_gentab },
+ { imdi_k687, imdi_k687_gentab },
+ { imdi_k688, imdi_k688_gentab },
+ { imdi_k689, imdi_k689_gentab },
+ { imdi_k690, imdi_k690_gentab },
+ { imdi_k691, imdi_k691_gentab },
+ { imdi_k692, imdi_k692_gentab },
+ { imdi_k693, imdi_k693_gentab },
+ { imdi_k694, imdi_k694_gentab },
+ { imdi_k695, imdi_k695_gentab },
+ { imdi_k696, imdi_k696_gentab },
+ { imdi_k697, imdi_k697_gentab },
+ { imdi_k698, imdi_k698_gentab },
+ { imdi_k699, imdi_k699_gentab },
+ { imdi_k700, imdi_k700_gentab },
+ { imdi_k701, imdi_k701_gentab },
+ { imdi_k702, imdi_k702_gentab },
+ { imdi_k703, imdi_k703_gentab },
+ { imdi_k704, imdi_k704_gentab },
+ { imdi_k705, imdi_k705_gentab },
+ { imdi_k706, imdi_k706_gentab },
+ { imdi_k707, imdi_k707_gentab },
+ { imdi_k708, imdi_k708_gentab },
+ { imdi_k709, imdi_k709_gentab },
+ { imdi_k710, imdi_k710_gentab },
+ { imdi_k711, imdi_k711_gentab },
+ { imdi_k712, imdi_k712_gentab },
+ { imdi_k713, imdi_k713_gentab },
+ { imdi_k714, imdi_k714_gentab },
+ { imdi_k715, imdi_k715_gentab },
+ { imdi_k716, imdi_k716_gentab },
+ { imdi_k717, imdi_k717_gentab },
+ { imdi_k718, imdi_k718_gentab },
+ { imdi_k719, imdi_k719_gentab },
+ { imdi_k720, imdi_k720_gentab },
+ { imdi_k721, imdi_k721_gentab },
+ { imdi_k722, imdi_k722_gentab },
+ { imdi_k723, imdi_k723_gentab },
+ { imdi_k724, imdi_k724_gentab },
+ { imdi_k725, imdi_k725_gentab },
+ { imdi_k726, imdi_k726_gentab },
+ { imdi_k727, imdi_k727_gentab },
+ { imdi_k728, imdi_k728_gentab },
+ { imdi_k729, imdi_k729_gentab },
+ { imdi_k730, imdi_k730_gentab },
+ { imdi_k731, imdi_k731_gentab },
+ { imdi_k732, imdi_k732_gentab },
+ { imdi_k733, imdi_k733_gentab },
+ { imdi_k734, imdi_k734_gentab },
+ { imdi_k735, imdi_k735_gentab },
+ { imdi_k736, imdi_k736_gentab },
+ { imdi_k737, imdi_k737_gentab },
+ { imdi_k738, imdi_k738_gentab },
+ { imdi_k739, imdi_k739_gentab },
+ { imdi_k740, imdi_k740_gentab },
+ { imdi_k741, imdi_k741_gentab },
+ { imdi_k742, imdi_k742_gentab },
+ { imdi_k743, imdi_k743_gentab },
+ { imdi_k744, imdi_k744_gentab },
+ { imdi_k745, imdi_k745_gentab },
+ { imdi_k746, imdi_k746_gentab },
+ { imdi_k747, imdi_k747_gentab },
+ { imdi_k748, imdi_k748_gentab },
+ { imdi_k749, imdi_k749_gentab },
+ { imdi_k750, imdi_k750_gentab },
+ { imdi_k751, imdi_k751_gentab },
+ { imdi_k752, imdi_k752_gentab },
+ { imdi_k753, imdi_k753_gentab },
+ { imdi_k754, imdi_k754_gentab },
+ { imdi_k755, imdi_k755_gentab },
+ { imdi_k756, imdi_k756_gentab },
+ { imdi_k757, imdi_k757_gentab },
+ { imdi_k758, imdi_k758_gentab },
+ { imdi_k759, imdi_k759_gentab },
+ { imdi_k760, imdi_k760_gentab },
+ { imdi_k761, imdi_k761_gentab },
+ { imdi_k762, imdi_k762_gentab },
+ { imdi_k763, imdi_k763_gentab },
+ { imdi_k764, imdi_k764_gentab },
+ { imdi_k765, imdi_k765_gentab },
+ { imdi_k766, imdi_k766_gentab },
+ { imdi_k767, imdi_k767_gentab },
+ { imdi_k768, imdi_k768_gentab },
+ { imdi_k769, imdi_k769_gentab },
+ { imdi_k770, imdi_k770_gentab },
+ { imdi_k771, imdi_k771_gentab },
+ { imdi_k772, imdi_k772_gentab },
+ { imdi_k773, imdi_k773_gentab },
+ { imdi_k774, imdi_k774_gentab },
+ { imdi_k775, imdi_k775_gentab },
+ { imdi_k776, imdi_k776_gentab },
+ { imdi_k777, imdi_k777_gentab },
+ { imdi_k778, imdi_k778_gentab },
+ { imdi_k779, imdi_k779_gentab },
+ { imdi_k780, imdi_k780_gentab },
+ { imdi_k781, imdi_k781_gentab },
+ { imdi_k782, imdi_k782_gentab },
+ { imdi_k783, imdi_k783_gentab },
+ { imdi_k784, imdi_k784_gentab },
+ { imdi_k785, imdi_k785_gentab },
+ { imdi_k786, imdi_k786_gentab },
+ { imdi_k787, imdi_k787_gentab },
+ { imdi_k788, imdi_k788_gentab },
+ { imdi_k789, imdi_k789_gentab },
+ { imdi_k790, imdi_k790_gentab },
+ { imdi_k791, imdi_k791_gentab },
+ { imdi_k792, imdi_k792_gentab },
+ { imdi_k793, imdi_k793_gentab },
+ { imdi_k794, imdi_k794_gentab },
+ { imdi_k795, imdi_k795_gentab },
+ { imdi_k796, imdi_k796_gentab },
+ { imdi_k797, imdi_k797_gentab },
+ { imdi_k798, imdi_k798_gentab },
+ { imdi_k799, imdi_k799_gentab },
+ { imdi_k800, imdi_k800_gentab },
+ { imdi_k801, imdi_k801_gentab },
+ { imdi_k802, imdi_k802_gentab },
+ { imdi_k803, imdi_k803_gentab },
+ { imdi_k804, imdi_k804_gentab },
+ { imdi_k805, imdi_k805_gentab },
+ { imdi_k806, imdi_k806_gentab },
+ { imdi_k807, imdi_k807_gentab },
+ { imdi_k808, imdi_k808_gentab },
+ { imdi_k809, imdi_k809_gentab },
+ { imdi_k810, imdi_k810_gentab },
+ { imdi_k811, imdi_k811_gentab },
+ { imdi_k812, imdi_k812_gentab },
+ { imdi_k813, imdi_k813_gentab },
+ { imdi_k814, imdi_k814_gentab },
+ { imdi_k815, imdi_k815_gentab },
+ { imdi_k816, imdi_k816_gentab },
+ { imdi_k817, imdi_k817_gentab },
+ { imdi_k818, imdi_k818_gentab },
+ { imdi_k819, imdi_k819_gentab },
+ { imdi_k820, imdi_k820_gentab },
+ { imdi_k821, imdi_k821_gentab },
+ { imdi_k822, imdi_k822_gentab },
+ { imdi_k823, imdi_k823_gentab },
+ { imdi_k824, imdi_k824_gentab },
+ { imdi_k825, imdi_k825_gentab },
+ { imdi_k826, imdi_k826_gentab },
+ { imdi_k827, imdi_k827_gentab },
+ { imdi_k828, imdi_k828_gentab },
+ { imdi_k829, imdi_k829_gentab },
+ { imdi_k830, imdi_k830_gentab },
+ { imdi_k831, imdi_k831_gentab },
+ { imdi_k832, imdi_k832_gentab },
+ { imdi_k833, imdi_k833_gentab },
+ { imdi_k834, imdi_k834_gentab },
+ { imdi_k835, imdi_k835_gentab },
+ { imdi_k836, imdi_k836_gentab },
+ { imdi_k837, imdi_k837_gentab },
+ { imdi_k838, imdi_k838_gentab },
+ { imdi_k839, imdi_k839_gentab },
+ { imdi_k840, imdi_k840_gentab },
+ { imdi_k841, imdi_k841_gentab },
+ { imdi_k842, imdi_k842_gentab },
+ { imdi_k843, imdi_k843_gentab },
+ { imdi_k844, imdi_k844_gentab },
+ { imdi_k845, imdi_k845_gentab },
+ { imdi_k846, imdi_k846_gentab },
+ { imdi_k847, imdi_k847_gentab },
+ { imdi_k848, imdi_k848_gentab },
+ { imdi_k849, imdi_k849_gentab },
+ { imdi_k850, imdi_k850_gentab },
+ { imdi_k851, imdi_k851_gentab },
+ { imdi_k852, imdi_k852_gentab },
+ { imdi_k853, imdi_k853_gentab },
+ { imdi_k854, imdi_k854_gentab },
+ { imdi_k855, imdi_k855_gentab },
+ { imdi_k856, imdi_k856_gentab },
+ { imdi_k857, imdi_k857_gentab },
+ { imdi_k858, imdi_k858_gentab },
+ { imdi_k859, imdi_k859_gentab },
+ { imdi_k860, imdi_k860_gentab },
+ { imdi_k861, imdi_k861_gentab },
+ { imdi_k862, imdi_k862_gentab },
+ { imdi_k863, imdi_k863_gentab },
+ { imdi_k864, imdi_k864_gentab },
+ { imdi_k865, imdi_k865_gentab },
+ { imdi_k866, imdi_k866_gentab },
+ { imdi_k867, imdi_k867_gentab },
+ { imdi_k868, imdi_k868_gentab },
+ { imdi_k869, imdi_k869_gentab },
+ { imdi_k870, imdi_k870_gentab },
+ { imdi_k871, imdi_k871_gentab },
+ { imdi_k872, imdi_k872_gentab },
+ { imdi_k873, imdi_k873_gentab },
+ { imdi_k874, imdi_k874_gentab },
+ { imdi_k875, imdi_k875_gentab },
+ { imdi_k876, imdi_k876_gentab },
+ { imdi_k877, imdi_k877_gentab },
+ { imdi_k878, imdi_k878_gentab },
+ { imdi_k879, imdi_k879_gentab },
+ { imdi_k880, imdi_k880_gentab },
+ { imdi_k881, imdi_k881_gentab },
+ { imdi_k882, imdi_k882_gentab },
+ { imdi_k883, imdi_k883_gentab },
+ { imdi_k884, imdi_k884_gentab },
+ { imdi_k885, imdi_k885_gentab },
+ { imdi_k886, imdi_k886_gentab },
+ { imdi_k887, imdi_k887_gentab },
+ { imdi_k888, imdi_k888_gentab },
+ { imdi_k889, imdi_k889_gentab },
+ { imdi_k890, imdi_k890_gentab },
+ { imdi_k891, imdi_k891_gentab }
+};
+
+int no_kfuncs = 891;
+
diff --git a/imdi/imdi_make.c b/imdi/imdi_make.c
new file mode 100644
index 0000000..7990f53
--- /dev/null
+++ b/imdi/imdi_make.c
@@ -0,0 +1,514 @@
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/*
+ * Top level kernel code generator
+ *
+ * This module is invoked from the make system,
+ * and generates all the versions and configurations of
+ * the IMDI kernel code. It includes all the generated
+ * files in imdi_k.h, which also contains a table
+ * so that the run time code knows what kernels
+ * are available.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdarg.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+
+#include "imdi.h"
+#include "imdi_tab.h"
+
+#ifndef MAXNAMEL
+# define MAXNAMEL 512 /* Maximum command line filename lengths */
+#endif
+
+#undef VERBOSE
+#undef TEST1 /* Generate one test case */
+
+/*
+ Ideal grid resolutions for 8 bit precision calculations.
+ See imdi_gen.c for a more detailed list.
+
+ Grid Jumps
+ 4 0
+ 6 0
+ 16 0
+ 18 0
+ 52 0
+ 86 0
+ 256 0
+
+ 3 1
+ 5 1
+ 9 1
+ 17 1
+ 33 1
+ 65 1
+ 128 1
+ 129 1
+ 255 1
+
+ */
+
+/* The following structure initialisations define what kernel routines should be built */
+static
+gendesc descs[] = {
+#ifdef TEST1
+ {
+ { 3, 0 }, /* * Input dimension combinations */
+ { 33, 0 }, /* + Interpolation table resolutions */
+ { 8, 0 }, /* + Min Simplex table resolutions */
+ { 4, 0 }, /* * Output dimension combinations */
+ {OOPT(oopts_check,3), oopts_none}, /* + Output channel options */
+ {pixint8, 0 }, /* * Input pixel representation */
+ {prec_p16, 0}, /* + Internal precision */
+ {pixint8, 0}, /* + Output pixel representation */
+ {opts_sort_splx, opts_end} /* * Direction & stride combinations */
+// {opts_splx_sort, opts_end} /* * Direction & stride combinations */
+ }
+#else
+ /* A reasonably full set of combinations */
+ /* * means multiplies combination */
+ /* + means lockstep with previous line */
+ {
+ { 1, 3, 4, 5, 6, 7, 8, 9, 10, 0 }, /* * Input dimension combinations */
+ { 256, 33, 18, 16, 12, 8, 7, 6, 5, 0 }, /* + Min Interpolation table resolutions */
+ { 1, 8, 17, 1, 1, 1, 1, 1, 1, 0 }, /* + Min Simplex table resolutions */
+
+ { 1, 3, 4, 5, 6, 7, 8, 9, 10, 0 }, /* * Output dimension combinations */
+ {oopts_none, oopts_none, oopts_none, oopts_none, oopts_none, oopts_none,
+ oopts_none, oopts_none, oopts_none, oopts_none, oopts_none, oopts_none},
+ /* + Output channel options */
+
+ {pixint8, pixint16, pixint8, pixint16, pixint16, 0 }, /* * Input pixel representation */
+ {prec_p8, prec_p8, prec_p8, prec_p16, prec_p16, 0 }, /* + Internal precision */
+ {pixint8, pixint8, pixint16, pixint16, pixint16, 0 }, /* + Output pixel representation */
+
+ {
+ opts_splx_sort, /* (both, but default to simple alg, no stride) */
+ opts_istride | opts_ostride, /* + (Sort only with stride) */
+ opts_end } /* * Direction & stride combinations */
+ }
+#endif /* !TEST1 */
+};
+
+void set_architecture(mach_arch *ar, int use64);
+
+struct _knamestr {
+ char name[100];
+ char desc[100];
+ struct _knamestr *next;
+}; typedef struct _knamestr knamestr;
+
+knamestr *
+new_knamestr(char *name, char *desc) {
+ knamestr *kn;
+
+ if ((kn = (knamestr *)malloc(sizeof(knamestr))) == NULL) {
+ fprintf(stderr,"new_knamestr malloc failed\n");
+ exit(-1);
+ }
+ strcpy(kn->name, name);
+ strcpy(kn->desc, desc);
+ kn->next = NULL;
+ return kn;
+}
+
+void usage(void) {
+ fprintf(stderr,"Make imdi kernel code Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"usage: imdi_make [-i]\n");
+ fprintf(stderr," -d dir Directory to create them in (default .)\n");
+ fprintf(stderr," -i Individial Files\n");
+ fprintf(stderr," -f Force 64 bit\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int indiv = 0; /* Individual files */
+ int rv;
+ int dn, tnd;
+ genspec gs, ogs;
+ tabspec ts, ots;
+ mach_arch ar;
+ int ix = 1; /* kernel index */
+ knamestr *list = NULL, *lp = NULL;
+#if defined(ALLOW64) && defined(USE64)
+ int use64 = 1;
+#else
+ int use64 = 0;
+#endif
+ char dirname[MAXNAMEL+1+1] = ""; /* Output directory name */
+ char temp[MAXNAMEL+100+1]; /* Buffer to compose filenames in */
+ FILE *kcode = NULL; /* Kernel routine code file */
+ FILE *kheader; /* Kernel routine header file */
+
+ /* Zero out the gen and tabspecs, to give diff a place to start */
+ memset((void *)&ogs, 0, sizeof(genspec));
+ memset((void *)&gs, 0, sizeof(genspec));
+ memset((void *)&ots, 0, sizeof(tabspec));
+ memset((void *)&ts, 0, sizeof(tabspec));
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?') {
+ usage();
+
+ }
+ /* Destination directory */
+ else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ int len;
+ fa = nfa;
+ if (na == NULL) usage();
+ strncpy(dirname,na,MAXNAMEL); dirname[MAXNAMEL] = '\000';
+ len = strlen(dirname);
+ if (len > 0) {
+ if (dirname[len-1] != '/' && dirname[len-1] != '\\')
+ strcat(dirname, "/");
+ }
+ }
+ /* Individual files */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ indiv = 1;
+ }
+ /* Force 64 bit */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+#ifdef ALLOW64
+ use64 = 1;
+#else
+ fprintf(stderr,"ALLOW64 bits is undefined\n");
+ usage();
+#endif
+ }
+ else {
+ usage();
+ }
+ } else
+ break;
+ }
+
+ set_architecture(&ar, use64);
+
+ /* Open the file for kernel routine declaration header */
+ sprintf(temp, "%simdi_k.h",dirname);
+ if ((kheader = fopen(temp, "w")) == NULL) {
+ fprintf(stderr,"imdi_make: unable to open file '%s'\n",temp);
+ exit(-1);
+ }
+
+ if (!indiv) {
+ sprintf(temp, "%simdi_k.c",dirname);
+ if ((kcode = fopen(temp, "w")) == NULL) {
+ fprintf(stderr,"imdi_make: unable to open file '%s'\n",temp);
+ exit(-1);
+ }
+ }
+
+ tnd = sizeof(descs)/sizeof(gendesc); /* Total number of descriptions */
+#ifdef VERBOSE
+ printf("Number of descriptions = %d\n",tnd);
+#endif /* VERBOSE */
+
+ fprintf(kheader,"/* Integer Multi-Dimensional Interpolation */\n");
+ fprintf(kheader,"/* Declarations for all the generated kernel functions */\n");
+ fprintf(kheader,"/* This file is generated by imdi_make */\n\n");
+ fprintf(kheader,"/* Copyright 2000 - 2007 Graeme W. Gill */\n");
+ fprintf(kheader,"/* All rights reserved. */\n");
+ fprintf(kheader,"/* This material is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- */\n");
+ fprintf(kheader,"/* see the License.txt file for licensing details.*/\n");
+
+ fprintf(kheader,"\n");
+
+ /* For all the descriptions */
+ for (dn = 0; dn < tnd; dn++) {
+ int cb, ncb;
+
+ /* Do all combinations for that description */
+ for (cb = 0, ncb = 1; cb < ncb; cb++) {
+ int nalg, alg;
+ char ofname[100];
+
+ /* Compute generate spec. and number of combinations */
+ ncb = set_genspec(&gs, &descs[dn], cb, &ar);
+
+ if (indiv) {
+ sprintf(temp, "%s%s.c",dirname,ofname);
+ if ((kcode = fopen(temp, "w")) == NULL) {
+ fprintf(stderr,"imdi_make: unable to open file '%s'\n",temp);
+ exit(-1);
+ }
+ }
+
+ nalg = 2; /* By default generate just sort algorithm */
+ alg = 1;
+
+ if ((gs.opt & opts_splx_sort)
+ || (gs.opt & opts_sort_splx)) {
+ alg = 0; /* Generate both simplex and sort algorithms */
+ }
+ if (gs.opt & opts_splx) {
+ nalg = 1; /* Generate just simplex algorithm */
+ alg = 0;
+ }
+
+ for (; alg < nalg; alg++) {
+
+ if (alg == 0)
+ gs.opt |= opts_splx;
+ else
+ gs.opt &= ~opts_splx;
+
+ /* Generate it */
+ rv = gen_c_kernel(&gs, &ts, &ar, kcode, ix, &ogs, &ots);
+ if (rv != 0 && rv != 1) {
+ fprintf(stderr,"imdi_make: gen_c_kernel returned a err %d\n",rv);
+ exit(-1);
+ }
+
+ /* Add the name to the list */
+ if (list == NULL)
+ lp = list = new_knamestr(gs.kname, gs.kdesc);
+ else {
+ lp->next = new_knamestr(gs.kname, gs.kdesc);
+ lp = lp->next;
+ }
+ if (indiv) {
+ if (fclose(kcode) != 0) {
+ fprintf(stderr,"imdi_make: unable to close file '%s'\n",ofname);
+ exit(-1);
+ }
+ }
+ ogs = gs; /* Structure copy */
+ ots = ts;
+ ix++;
+
+ if (rv == 0)
+ break; /* there was only sort available */
+ }
+ }
+ }
+
+ /* Include the kernel functions in the header file */
+ if (indiv) {
+ for(lp = list; lp != NULL; lp = lp->next) {
+ fprintf(kheader,"#include \"%s_%s.c\"\n",lp->name,lp->desc);
+ }
+ } else {
+ fprintf(kheader,"#include \"imdi_k.c\" /* All the kernel code */\n");
+ }
+ fprintf(kheader,"\n");
+
+ /* Output function table */
+
+ fprintf(kheader,
+ "struct {\n"
+ " void (*interp)(imdi *s, void **outp, int ostride, void **inp, int istride, unsigned int npix);\n"
+ " void (*gentab)(genspec *g, tabspec *t);\n"
+ "} ktable[%d] = {\n",ix-1);
+
+ for(lp = list; lp != NULL; lp = lp->next) {
+ fprintf(kheader,"\t{ %s, %s_gentab }%s\n", lp->name, lp->name,
+ lp->next != NULL ? "," : "");
+ }
+ fprintf(kheader,"};\n");
+ fprintf(kheader,"\n");
+ fprintf(kheader,"int no_kfuncs = %d;\n",ix-1);
+ fprintf(kheader,"\n");
+
+ if (!indiv) {
+ if (fclose(kcode) != 0) {
+ fprintf(stderr,"imdi_make: unable to close file 'imdi_k.c'\n");
+ exit(-1);
+ }
+ }
+
+ if (fclose(kheader) != 0) {
+ fprintf(stderr,"imdi_make: unable to close file 'imdi_k.h'\n");
+ exit(-1);
+ }
+
+ /* Free the kname list */
+ for(lp = list; lp != NULL;) {
+ char *p = (char *)lp;
+ lp = lp->next;
+ free(p);
+ }
+
+ return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Initialse the architecture structure properly. */
+/* We're doing this purely at run time, on the assumption */
+/* that the target machine is the one we're running on. */
+/* We would have to do this differently in a cross development */
+/* environment. */
+void
+set_architecture(
+mach_arch *ar,
+int use64
+) {
+ unsigned long etest = 0xff;
+ char *machtype; /* Environment value */
+
+ if (*((unsigned char *)&etest) == 0xff) {
+ ar->bigend = 0; /* Little endian */
+ } else {
+ ar->bigend = 1; /* Big endian endian */
+ }
+
+ machtype = getenv("MACHTYPE");
+
+ /* Unfortunetaly many environments don't export MACHTYPE :-( */
+ /* so we implement a fall back */
+ if (machtype == NULL) {
+#ifdef __ppc__
+ machtype = "powerpc";
+#endif
+ }
+
+ if (machtype != NULL && strcmp(machtype, "powerpc") == 0) {
+
+ /* Section tunable for PowerPC */
+
+ ar->uwa = 0; /* Use wide memory access */
+ ar->shfm = 0; /* Use shifts to mask values */
+ ar->oscale = 8; /* Has scaled indexing up to * 8 */
+ ar->smmul = 0; /* Doesn't have fast small multiply for index scaling */
+ if (use64) {
+ ar->nords = 4; /* Number of ord types */
+ ar->nints = 4; /* Number of int types */
+ } else {
+ ar->nords = 3; /* Number of ord types */
+ ar->nints = 3; /* Number of int types */
+ }
+ ar->natord = 2; /* Most natural type (assume unsigned int) */
+ ar->natint = 2; /* Most natural type (assume int) */
+
+ ar->pbits = sizeof(void *) * 8; /* Number of bits in a pointer */
+
+ ar->ords[0].bits = 8 * sizeof(unsigned char);
+ ar->ords[0].name = "unsigned char";
+ ar->ords[0].align = 1;
+
+ ar->ords[1].bits = 8 * sizeof(unsigned short);
+ ar->ords[1].name = "unsigned short";
+ ar->ords[1].align = 1;
+
+ ar->ords[2].bits = 8 * sizeof(unsigned int);
+ ar->ords[2].name = "unsigned int";
+ ar->ords[2].align = 1;
+
+#ifdef ALLOW64
+ ar->ords[3].bits = 8 * sizeof(unsigned longlong);
+ ar->ords[3].name = "unsigned " str_longlong ;
+ ar->ords[3].align = 0;
+#endif /* ALLOW64 */
+
+ ar->ints[0].bits = 8 * sizeof(signed char);
+ ar->ints[0].name = "signed char";
+ ar->ints[0].align = 1;
+
+ ar->ints[1].bits = 8 * sizeof(short);
+ ar->ints[1].name = "short";
+ ar->ints[1].align = 1;
+
+ ar->ints[2].bits = 8 * sizeof(int);
+ ar->ints[2].name = "int";
+ ar->ints[2].align = 1;
+
+#ifdef ALLOW64
+ ar->ints[3].bits = 8 * sizeof(longlong);
+ ar->ints[3].name = str_longlong ;
+ ar->ints[3].align = 0;
+#endif /* ALLOW64 */
+
+ } else {
+
+ /* Currently assume x86 type */
+
+ ar->uwa = 0; /* Use wide memory access */
+ ar->shfm = 0; /* Use shifts to mask values */
+ ar->oscale = 8; /* Has scaled indexing up to * 8 */
+ ar->smmul = 0; /* Doesn't have fast small multiply for index scaling */
+ if (use64) {
+ ar->nords = 4; /* Number of ord types */
+ ar->nints = 4; /* Number of int types */
+ } else {
+ ar->nords = 3; /* Number of ord types */
+ ar->nints = 3; /* Number of int types */
+ }
+ ar->natord = 2; /* Most natural type (assume unsigned int) */
+ ar->natint = 2; /* Most natural type (assume int) */
+
+ ar->pbits = sizeof(void *) * 8; /* Number of bits in a pointer */
+
+ ar->ords[0].bits = 8 * sizeof(unsigned char);
+ ar->ords[0].name = "unsigned char";
+ ar->ords[0].align = 1;
+
+ ar->ords[1].bits = 8 * sizeof(unsigned short);
+ ar->ords[1].name = "unsigned short";
+ ar->ords[1].align = 1;
+
+ ar->ords[2].bits = 8 * sizeof(unsigned int);
+ ar->ords[2].name = "unsigned int";
+ ar->ords[2].align = 1;
+
+#ifdef ALLOW64
+ ar->ords[3].bits = 8 * sizeof(unsigned longlong);
+ ar->ords[3].name = "unsigned " str_longlong ;
+ ar->ords[3].align = 0;
+#endif /* ALLOW64 */
+
+ ar->ints[0].bits = 8 * sizeof(signed char);
+ ar->ints[0].name = "signed char";
+ ar->ints[0].align = 1;
+
+ ar->ints[1].bits = 8 * sizeof(short);
+ ar->ints[1].name = "short";
+ ar->ints[1].align = 1;
+
+ ar->ints[2].bits = 8 * sizeof(int);
+ ar->ints[2].name = "int";
+ ar->ints[2].align = 1;
+
+#ifdef ALLOW64
+ ar->ints[3].bits = 8 * sizeof(longlong);
+ ar->ints[3].name = str_longlong ;
+ ar->ints[3].align = 0;
+#endif /* ALLOW64 */
+ }
+}
+
+
diff --git a/imdi/imdi_tab.c b/imdi/imdi_tab.c
new file mode 100644
index 0000000..4f448f0
--- /dev/null
+++ b/imdi/imdi_tab.c
@@ -0,0 +1,803 @@
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+/*
+ * Run time table allocater and initialiser
+ *
+ * The function here that knows how to create the
+ * appropriate run time tables for our chosen kernel,
+ * and the type color mapping we want to perform.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "imdi.h"
+#include "imdi_tab.h"
+
+#undef VERBOSE
+#undef ASSERTS /* Check asserts */
+
+#ifdef ASSERTS
+#include <numlib.h>
+#endif
+
+
+
+typedef unsigned char byte;
+
+/* Left shift, handles >= 32 properly */
+#define LSHIFT(aa, bb) ((bb) <= 31 ? ((aa) << (bb)) : (((aa) << 31) << ((bb)-31)))
+
+/* The big value type used to represent table entries */
+#ifdef ALLOW64
+typedef unsigned longlong bvt;
+#else
+typedef unsigned long bvt;
+#endif
+
+/* Specific entry size write routine */
+
+void write_uchar(
+byte *p,
+bvt v
+) {
+ *((unsigned char *)p) = (unsigned char)v;
+}
+
+void write_ushort(
+byte *p,
+bvt v
+) {
+ *((unsigned short *)p) = (unsigned short)v;
+}
+
+void write_uint(
+byte *p,
+bvt v
+) {
+ *((unsigned int *)p) = (unsigned int)v;
+}
+
+void write_ulong(
+byte *p,
+bvt v
+) {
+ *((unsigned long *)p) = (unsigned long)v;
+}
+
+#ifdef ALLOW64
+void write_ulonglong(
+byte *p,
+bvt v
+) {
+ *((unsigned longlong *)p) = (unsigned longlong)v;
+}
+#endif /* ALLOW64 */
+
+void write_default(
+byte *p,
+bvt v
+) {
+ fprintf(stderr,"imdi_tabl: internal failure - unexpected write size!\n");
+ exit(-1);
+}
+
+/* Array of write routines */
+void (*write_entry[16])(byte *p, bvt v);
+
+static void
+init_write_tab(void) {
+ int i;
+
+ for (i = 0; i < 16; i++)
+ write_entry[i] = write_default; /* Make sure any un-inited access bombs */
+
+ write_entry[sizeof(unsigned char)] = write_uchar;
+ write_entry[sizeof(unsigned short)] = write_ushort;
+ write_entry[sizeof(unsigned int)] = write_uint;
+ write_entry[sizeof(unsigned long)] = write_ulong;
+#ifdef ALLOW64
+ write_entry[sizeof(unsigned longlong)] = write_ulonglong;
+#endif /* ALLOW64 */
+}
+
+
+/* Input offset adjustment table */
+double in_adj[] = {
+ 8.0324820232182659e+281, 1.3051220361353854e+214, 1.5654418860154115e-076,
+ 6.6912978722165055e+281, 1.2369092402930559e+277, 1.4097588049607207e-308,
+ 7.7791723264456369e-260, 3.6184161952648606e+238, 5.8235640814908141e+180,
+ 9.1271554315814989e-072, 5.4310198502711138e+241, 2.7935452404894958e+275,
+ -2.9408705449902027e+003
+};
+
+
+/* Table creation function */
+imdi_imp *
+imdi_tab(
+ genspec *gs, /* Pointer to gen spec */
+ tabspec *ts, /* Pointer to table spec */
+ imdi_conv cnv, /* Runtime argument conversion needed */
+ imdi_pixrep irep, /* High level input pixel representation to match */
+ imdi_pixrep orep, /* High level output pixel representation to match */
+ void (*interp)(struct _imdi *s, void **outp, int outst, /* Underlying conversion function */
+ void **inp, int inst,
+ unsigned int npixels),
+
+ int *inm, /* Input raster channel to callback channel mapping, NULL for none. */
+ int *outm, /* Output raster channel to callback channel mapping, NULL for none. */
+ imdi_ooptions oopt, /* Output per channel options (Callback channel, NOT output channel) */
+ unsigned int *checkv, /* Output channel check values (Callback channel, NULL for none == 0. */
+
+ /* Callbacks to lookup the mdi table values */
+ void (*input_curves) (void *cntx, double *out_vals, double *in_vals),
+ void (*md_table) (void *cntx, double *out_vals, double *in_vals),
+ void (*output_curves)(void *cntx, double *out_vals, double *in_vals),
+ void *cntx /* Context to callbacks */
+) {
+ static int inited = 0;
+ static int bigend = 0;
+ int i, e, f;
+ imdi_imp *it;
+ unsigned long etest = 0xff;
+ int idinc[IXDI+1]; /* Increment for each dimension of interp table. */
+ int ibdinc[IXDI+1]; /* idinc[] in bytes */
+ int sdinc[IXDI+1]; /* Increment for each dimension of simplex table. */
+ int sbdinc[IXDI+1]; /* sdinc[] in bytes */
+
+#ifdef VERBOSE
+ printf("imdi_tab called\n");
+#endif
+
+ if (inited == 0) {
+ init_write_tab();
+ if (*((unsigned char *)&etest) == 0xff)
+ bigend = 0; /* Little endian */
+ else
+ bigend = 1; /* Big endian */
+ inited = 1;
+ }
+
+ if ((it = (imdi_imp *)calloc(1, sizeof(imdi_imp))) == NULL) {
+#ifdef VERBOSE
+ printf("malloc imdi_imp size %d failed\n",sizeof(imdi_imp));
+#endif
+ return NULL; /* Should we signal error ? How ? */
+ }
+
+ it->size = sizeof(imdi_imp);
+#ifdef VERBOSE
+ printf("Allocated imdi_imp structure size %u\n",it->size);
+#endif /* VERBOSE */
+
+ /* Set runtime matching conversion provided */
+ it->cnv = cnv;
+ it->id = gs->id;
+ it->od = gs->od;
+ it->cirep = irep; /* Pixel representation interp is called with */
+ it->corep = orep;
+ it->firep = gs->irep; /* Pixel representation of function we are going to use */
+ it->forep = gs->orep;
+ it->interp = interp;
+ it->checkf = 0;
+
+ /* Compute number of written channels (allow for skip) */
+ it->wod = it->od;
+ for (i = 0; i < it->od; i++) {
+ if ((oopt & OOPT(oopts_skip,i)) != 0)
+ it->wod--;
+ }
+
+ /* Setup the raster to callback channel mappings */
+ if (inm != NULL) {
+ for (e = 0; e < it->id; e++)
+ it->it_map[e] = inm[e]; /* Copy input */
+ } else {
+ for (e = 0; e < it->id; e++)
+ it->it_map[e] = e; /* Direct mapping */
+ }
+ if (outm != NULL) {
+ for (e = 0; e < it->od; e++)
+ it->im_map[e] = outm[e]; /* Copy input */
+ } else {
+ for (e = 0; e < it->od; e++)
+ it->im_map[e] = e; /* Direct mapping */
+ }
+ if (checkv != NULL) {
+ for (e = 0; e < it->od; e++)
+ it->checkv[e] = checkv[it->im_map[e]]; /* Copy input and convert to Output index */
+ } else {
+ for (e = 0; e < it->od; e++)
+ it->checkv[e] = 0; /* Set to zero */
+ }
+
+ /* Compute interp and simplex table dimension increments & total sizes */
+ idinc[0] = 1;
+ ibdinc[0] = ts->im_ts;
+ for (e = 1; e <= it->id; e++) {
+ idinc[e] = idinc[e-1] * gs->itres;
+ ibdinc[e] = ibdinc[e-1] * gs->itres;
+ }
+
+ if (!ts->sort) {
+ sdinc[0] = 1;
+ sbdinc[0] = ts->sm_ts;
+ for (e = 1; e <= it->id; e++) {
+ sdinc[e] = sdinc[e-1] * gs->stres;
+ sbdinc[e] = sbdinc[e-1] * gs->stres;
+ }
+ }
+
+ /* First we setup the input tables */
+ for (e = 0; e < it->id; e++) {
+ byte *t, *p; /* Pointer to input table, entry pointer */
+ int ne; /* Number of entries */
+ int ex; /* Entry index */
+ double iaf;
+ int ix = 0; /* Extract flag */
+
+ /* Compute number of entries */
+ if (ts->it_ix && !gs->in.packed) { /* Input is the whole bpch[] size */
+ ix = 1; /* Need to do extraction in lookup */
+ if (gs->in.pint) {
+ ne = (1 << (gs->in.bpch[0])); /* Same size used for all input tables */
+ } else {
+ ne = (1 << (gs->in.bpch[e])); /* This input channels size */
+ }
+ } else { /* Input is the value size */
+ ne = (1 << (gs->in.bpv[e])); /* This input values size */
+ }
+
+ /* Allocate the table */
+ if ((t = (byte *)malloc(ts->it_ts * ne)) == NULL) {
+#ifdef VERBOSE
+ printf("malloc imdi input table size %d failed\n",ts->it_ts * ne);
+#endif
+ return NULL; /* Should we signal error ? How ? */
+ }
+ it->size += ts->it_ts * ne;
+#ifdef VERBOSE
+ printf("Allocated input table %d size %u = %u * %u\n",e, ts->it_ts * ne,ts->it_ts,ne);
+#endif /* VERBOSE */
+
+ /* Comput input adjustment factor */
+ for (iaf = 0.0, i = 0; i < (sizeof(in_adj)/sizeof(double)-1); i++)
+ iaf += log(in_adj[i]);
+ iaf += in_adj[i];
+
+ /* For each possible input value, compute the entry value */
+ for (ex = 0, p = t; ex < ne; ex++, p += ts->it_ts) {
+ int iiv; /* Integer input value */
+ int ivr; /* Input value range */
+ int isb; /* Input sign bit/signed to offset displacement */
+ double riv; /* Real input value, 0.0 - 1.0 */
+ double rtv; /* Real transformed value, 0.0 - 1.0 */
+ double rmi; /* Real interpolation table index */
+ double rsi; /* Real simplex index */
+ int imi; /* Interpiolation table index */
+ int isi = 0; /* Integer simplex index */
+ int iwe = 0; /* Integer weighting value */
+ int vo = 0; /* Vertex offset value */
+
+ if (ix) { /* Extract value from index */
+ ivr = ((1 << (gs->in.bpv[e])) -1);
+ iiv = (ex >> gs->in.bov[e]) & ((1 << (gs->in.bpv[e])) -1);
+ } else {
+ ivr = (ne - 1); /* (Should be bpv[e], but take no chances!) */
+ iiv = ex; /* Input value is simply index */
+ }
+ isb = ivr & ~(((unsigned int)ivr) >> 1); /* Top bit */
+ if (gs->in_signed & (1 << e)) /* Treat input as signed */
+ iiv = (iiv & isb) ? iiv - isb : iiv + isb; /* Convert to offset from signed */
+ riv = (double) iiv / (double)ivr; /* Compute floating point */
+ {
+ double civ[IXDI], cov[IXDI];
+ for (f = 0; f < it->id; f++)
+ civ[f] = riv;
+ input_curves(cntx, cov, civ); /* Lookup the input table transform */
+ rtv = iaf * cov[it->it_map[e]];
+ }
+ if (rtv < 0.0) /* Guard against sillies */
+ rtv = 0.0;
+ else if (rtv > 1.0)
+ rtv = 1.0;
+
+ /* divide into interp base and cube sub index */
+ rmi = rtv * (gs->itres - 1);
+ imi = (int)floor(rmi); /* Interp. entry coordinate */
+ if (imi >= (gs->itres-1)) /* Keep cube base one row back from far edge */
+ imi = gs->itres-2;
+ rsi = rmi - (double)imi; /* offset into entry cube */
+ if (ts->sort) {
+ iwe = (int)((rsi * (1 << gs->prec)) + 0.5); /* Weighting scale */
+ vo = idinc[e] * ts->vo_om; /* Vertex offset */
+ } else {
+ isi = (int)((rsi * gs->stres) + 0.5);
+ if (isi == gs->stres) { /* Keep simplex index within table */
+ isi = 0;
+ imi++; /* Move to next interp. lattice */
+ }
+ isi *= sdinc[e]; /* Convert the raw indexes into offset in this dim */
+ }
+ imi *= idinc[e]; /* Convert the raw indexes into offset in this dim */
+
+#ifdef ASSERTS
+ /* ~~~ needs fixing for sort ~~~~ */
+ if ((imi & (LSHIFT(1,ts->it_ab)-1)) != imi)
+ error("imdi_tab assert: (imi & ((1 << ts->it_ab)-1)) != imi, imi = 0x%x, it_ab = 0x%x\n",imi,ts->it_ab);
+ if (imi >= idinc[it->id])
+ error("imdi_tab assert: imi >= idinc[it->id]\n");
+ if ((isi & (LSHIFT(1,ts->sx_ab)-1)) != isi)
+ error("imdi_tab assert: (isi & ((1 << ts->sx_ab)-1)) != isi, isi = 0x%x, sx_ab = 0x%x\n",isi,ts->sx_ab);
+ if (!ts->sort && isi >= sdinc[it->id])
+ error("imdi_tab assert: isi >= sdinc[it->id]\n");
+#endif
+
+ /* Now stuff them into the table entry */
+ if (ts->sort) {
+ if (ts->it_xs) { /* Separate interp index and weight/offset*/
+ if (ts->wo_xs) { /* All 3 are separate */
+ write_entry[ts->ix_es](p + ts->ix_eo, imi);
+ write_entry[ts->we_es](p + ts->we_eo, iwe);
+ write_entry[ts->vo_es](p + ts->vo_eo, vo);
+ } else {
+ bvt iwo;
+
+ iwo = ((bvt)iwe << ts->vo_ab) | vo; /* Combined weight+vertex offset */
+ write_entry[ts->ix_es](p + ts->ix_eo, imi);
+ write_entry[ts->wo_es](p + ts->wo_eo, iwo);
+ }
+ } else { /* All 3 are combined */
+ bvt iit;
+
+ iit = ((((bvt)imi << ts->we_ab) | (bvt)iwe) << ts->vo_ab) | vo;
+ write_entry[ts->it_ts](p, iit);
+ }
+ } else {
+ if (ts->it_xs) { /* Separate interp index and weight/offset*/
+ write_entry[ts->ix_es](p + ts->ix_eo, imi);
+ write_entry[ts->sx_es](p + ts->sx_eo, isi);
+ } else {
+ bvt iit;
+
+ iit = ((bvt)imi << ts->sx_ab) | isi; /* Combine interp and simplex indexes */
+ write_entry[ts->it_ts](p, iit);
+ }
+ }
+ }
+
+ /* Put table into place */
+ it->in_tables[e] = (void *)t;
+ }
+ it->nintabs = e;
+
+ /* Setup the interpolation table */
+ {
+ byte *t, *p; /* Pointer to interp table, pointer to total entry */
+ PHILBERT(phc) /* Pseudo Hilbert counter */
+ double vscale; /* Value scale for fixed point */
+ int vsize; /* Fixed point storage size */
+
+ if (ts->im_cd)
+ vsize = (gs->prec * 2)/8; /* Fixed point entry & computation size */
+ else
+ vsize = gs->prec/8; /* Fixed point entry size */
+ vscale = (1 << gs->prec) -0.50000001;
+ /* Value scale for fixed point padding */
+ /* -0.5 is to prevent carry/rollover after accumulation */
+ /* Could get better accuracy with saturation arithmatic */
+
+ /* Allocate the table */
+ if ((t = (byte *)malloc(ibdinc[it->id])) == NULL) {
+#ifdef VERBOSE
+ printf("malloc imdi interpolation table size %d failed\n",ibdinc[it->id]);
+#endif
+ return NULL; /* Should we signal error ? How ? */
+ }
+ it->size += ibdinc[it->id];
+#ifdef VERBOSE
+ printf("Allocated grid table = %u bytes, composed of %d dim of res %d entry %d\n",ibdinc[it->id], it->id, gs->itres, ts->im_ts);
+#endif /* VERBOSE */
+
+ /* Get ready to access all the entries in the table */
+ p = t;
+ PH_INIT(phc, it->id, gs->itres)
+
+ /* Create all the interpolation table entry values */
+ do {
+ int ee, ff;
+ double riv[IXDI]; /* Real input values */
+ double rev[IXDO]; /* Real entry values */
+ unsigned long iev;
+ byte *pp; /* Pointer to sub-entry */
+
+ for (e = 0, p = t; e < it->id; e++) {
+ riv[e] = ((double)phc[e]) / (gs->itres - 1.0);
+ p += phc[e] * ibdinc[e]; /* Compute pointer to entry value */
+ }
+
+ /* Lookup this verticies value */
+ {
+ double mriv[IXDI]; /* Channel mapped real input values */
+ double mrev[IXDO]; /* Channel mapped real entry values */
+ for (e = 0; e < it->id; e++)
+ mriv[it->it_map[e]] = riv[e];
+ md_table(cntx, mrev, mriv);
+ for (e = 0; e < it->od; e++)
+ rev[e] = mrev[it->im_map[e]];
+ }
+
+ /* Create all the output values */
+
+ /* I'm trying to avoid having to declare the actual entry sized */
+ /* variables, since it is difficult dynamically. */
+
+ /* For all the full entries */
+ ff = 0;
+ pp = p;
+ for (e = 0; e < ts->im_fn; e++, pp += ts->im_fs) {
+ /* For all channels within full entry */
+ for (ee = 0; ee < ts->im_fv; ee++, ff++) {
+ double revf = rev[ff];
+ if (revf < 0.0) /* Guard against sillies */
+ revf = 0.0;
+ else if (revf > 1.0)
+ revf = 1.0;
+ iev = (unsigned long)(revf * vscale + 0.5);
+
+ if (bigend) {
+ write_entry[vsize](pp + (ts->im_fs - (ee+1) * vsize), iev);
+ } else {
+ write_entry[vsize](pp + ee * vsize, iev);
+ }
+ }
+ }
+
+ /* For all the 0 or 1 partial entry */
+ for (e = 0; e < ts->im_pn; e++) {
+ /* For all channels within partial entry */
+ for (ee = 0; ee < ts->im_pv; ee++, ff++) {
+ double revf = rev[ff];
+ if (revf < 0.0) /* Guard against sillies */
+ revf = 0.0;
+ else if (revf > 1.0)
+ revf = 1.0;
+ iev = (unsigned long)(revf * vscale + 0.5);
+
+ if (bigend) {
+ write_entry[vsize](pp + (ts->im_ps - (ee+1) * vsize), iev);
+ } else {
+ write_entry[vsize](pp + ee * vsize, iev);
+ }
+ }
+ }
+#ifdef ASSERTS
+ if (f != it->od)
+ fprintf(stderr,"imdi_tab assert: f == it->od\n");
+#endif
+
+ PH_INC(phc)
+
+ } while (!PH_LOOPED(phc));
+
+ /* Put table into place */
+ it->im_table = (void *)t;
+ }
+
+ /* Setup the simplex table */
+ if (ts->sort) {
+ it->sw_table = (void *)NULL;
+
+ } else {
+ byte *t, *p; /* Pointer to input table, pointer to total entry */
+ int nsplx; /* Total number of simplexes */
+ XCOMBO(vcmb, it->id+1, 1 << it->id);/* Simplex dimension id out of cube dimention id */
+ int comb[24][IXDI]; /* Parameter[id]->Absolute[id] coordinate index */
+ int ps[IXDI+1]; /* Base simplex parameter space counter */
+ int pse; /* Base simplex parameter space counter index */
+ int idioff; /* Interpolation table diagonal offset value */
+
+ if (it->id > 4) {
+ fprintf(stderr,"imdi_tabl: internal failure - trying to create simplex table with di > 4!\n");
+ exit(-1);
+ }
+
+ /* Allocate the table */
+ if ((t = (byte *)malloc(sbdinc[it->id])) == NULL) {
+#ifdef VERBOSE
+ printf("malloc imdi simplex table size %d failed\n",sbdinc[it->id]);
+#endif
+ return NULL; /* Should we signal error ? How ? */
+ }
+ it->size += sbdinc[it->id];
+#ifdef VERBOSE
+ printf("Allocated simplex table = %u bytes, composed of %d dim of res %d entry %d\n",sbdinc[it->id], it->id, gs->stres, ts->sm_ts);
+#endif /* VERBOSE */
+
+ /* Compute the interp table offset to the diagonal vertex */
+ for (idioff = 0, e = 0; e < it->id; e++)
+ idioff += idinc[e]; /* Sum one offset in each dimension */
+
+ /* Figure out how many simplexes fit into this dimension cube, */
+ /* and how to map from the base simplex to each actual simplex. */
+ XCB_INIT(vcmb);
+ for (nsplx = 0; ;) {
+ int i;
+
+ /* XCOMB generates verticies in order from max to min offest */
+
+ /* Compute Absolute -> Parameter mapping */
+ for (e = 0; e < it->id; e++) { /* For each absolute axis */
+ for (i = 0; i < it->id; i++) { /* For each verticy, order large to small */
+ if ((vcmb[i] & (1<<e)) != 0 &&
+ (vcmb[i+1] & (1<<e)) == 0) {/* Transition from offset 1 to 0 */
+ comb[nsplx][i] = e;
+ break;
+ }
+ }
+ }
+
+//printf("~~Verticies = ");
+//for (i = 0; i <= it->id; i++)
+// printf("%d ",vcmb[i]);
+//printf("\n");
+
+//printf("~~Parm -> Abs = ");
+//for (e = 0; e < it->id; e++)
+// printf("%d ",comb[nsplx][e]);
+//printf("\n");
+
+ /* Increment the counter value */
+ XCB_INC(vcmb);
+ nsplx++;
+ if (XCB_DONE(vcmb))
+ break;
+ }
+
+ /* Now generate the contents of the base simplex, */
+ /* and map it to all the symetrical simplexes */
+
+ /* Init parameter space counter. */
+ /* Note that ps[id-1] >= ps[id-2] >= ... >= ps[1] >= ps[0] */
+ for (pse = 0; pse < it->id; pse++)
+ ps[pse] = 0;
+ ps[pse] = gs->stres-1;
+
+ /* Itterate through the simplex parameter space */
+ for (pse = 0; pse < it->id;) {
+ int qps[IXDI]; /* Quantized parameter values */
+ int we[IXDI+1]; /* Baricentric coords/vertex weighting */
+ double wvscale = (1 << gs->prec); /* Weighting value scale */
+ int sx; /* Simplex */
+
+//printf("Param coord =");
+//for (e = it->id-1; e >= 0; e--) {
+// printf(" %d",ps[e]);
+//}
+//printf("\n");
+
+ for (e = 0; e < it->id; e++) {
+ /* (Should try wvscale + 0.49999999, or something ?) */
+ double tt = (wvscale * (double)ps[e])/((double)gs->stres);
+ qps[e] = (int)(tt + 0.5);
+ }
+
+ /* Convert quantized parameter values into weighting values */
+ we[it->id] = (1 << gs->prec) - qps[it->id-1];
+ for (e = it->id-1; e > 0; e--)
+ we[e] = qps[e] - qps[e-1];
+ we[0] = qps[0];
+
+#ifdef ASSERTS
+ {
+ int sow = 0;
+ for (e = it->id; e >= 0; e--)
+ sow += we[e];
+
+ if (sow != (1 << gs->prec))
+ fprintf(stderr,"imdi_tab assert: sum weights == (1 << gs->prec)\n");
+ }
+#endif
+
+//printf("Baricentric coord =");
+//for (e = it->id; e >= 0; e--) {
+// printf(" %d",we[e]);
+//}
+//printf("\n");
+
+ /* For each simplex, compute the interp. and */
+ /* and entry offsets, and write the entry. */
+ for (sx = 0; sx < nsplx; sx++ ) {
+ int v; /* Vertex index */
+ byte *pp; /* Pointer to sub-entry */
+ unsigned long vofb = 0; /* Vertex offset, base */
+ unsigned long vwe; /* Vertex weight */
+
+ for (e = 0, p = t; e < it->id; e++) {
+ int ee = comb[sx][e]; /* Absolute coord index */
+ p += ps[e] * sbdinc[ee]; /* Pointer to entry */
+ }
+
+ /* For each vertex entry */
+ for (v = 0, pp = p; v <= it->id; v++) {
+ unsigned long vof;
+ if (v == 0) {
+ vofb = idioff; /* Start at diagonal offset */
+ } else {
+ vofb -= idinc[comb[sx][v-1]];/* Move to next vertex */
+ }
+ vwe = we[v]; /* Weight for this vertex */
+
+ if (vwe == 0)
+ vof = 0; /* Use zero offset if weight is zero */
+ else
+ vof = vofb * ts->vo_om; /* Strength reduce kernel scaling */
+
+ /* Write vwe and vof to entry */
+ if (ts->wo_xs) { /* Separate entries */
+ write_entry[ts->we_es](pp + ts->we_eo, vwe);
+ write_entry[ts->vo_es](pp + ts->vo_eo, vof);
+ pp += ts->wo_es;
+ } else { /* Combined entries */
+ bvt iwo;
+
+ iwo = ((bvt)vwe << ts->vo_ab) | vof; /* Combined weight+vertex offset */
+ write_entry[ts->wo_es](pp + ts->wo_eo, iwo);
+ pp += ts->wo_es;
+ }
+ }
+
+ /* Assert vofb == 0 */
+#ifdef ASSERTS
+ if (vofb != 0)
+ fprintf(stderr,"imdi_tab assert: vofb == 0\n");
+#endif
+ } /* Next simplex */
+
+ /* Increment the parameter coords */
+ for (pse = 0; pse < it->id; pse++) {
+ ps[pse]++;
+ if (ps[pse] <= ps[pse+1])
+ break; /* No carry */
+ ps[pse] = 0;
+ }
+ }
+
+ /* Put table into place */
+ it->sw_table = (void *)t;
+ }
+
+ /* Last, setup the output tables */
+ for (e = 0; e < it->od; e++) {
+ byte *t, *p; /* Pointer to output table, entry pointer */
+ int ne; /* Number of entries */
+ int iiv; /* Integer input value */
+ double ivr = (double)((1 << gs->prec)-1); /* Input value range */
+ double ovr = (double)((1 << ts->ot_bits[e])-1); /* Output value range */
+ int osb = (1 << (ts->ot_bits[e]-1)); /* Output offset to signed displacement */
+ int ooff = ts->ot_off[e]; /* Output value bit offset */
+
+ ne = (1 << gs->prec); /* Output of clut is prec bits */
+
+ /* Allocate the table */
+ if ((t = (byte *)malloc(ts->ot_ts * ne)) == NULL) {
+#ifdef VERBOSE
+ printf("malloc imdi output table size %d failed\n",ts->ot_ts * ne);
+#endif
+ return NULL; /* Should we signal error ? How ? */
+ }
+ it->size += ts->ot_ts * ne;
+#ifdef VERBOSE
+ printf("Allocated output table %d size %u = %u * %u\n",e, ts->ot_ts * ne,ts->ot_ts,ne);
+#endif /* VERBOSE */
+
+ /* For each possible output value, compute the entry value */
+ for (iiv = 0, p = t; iiv < ne; iiv++, p += ts->ot_ts) {
+ double riv; /* Real input value, 0.0 - 1.0 */
+ double rtv; /* Real transformed value, 0.0 - 1.0 */
+ unsigned long iov; /* Integer output value */
+
+ riv = (double) iiv / ivr; /* Compute floating point */
+ {
+ double civ[IXDO], cov[IXDO];
+ for (f = 0; f < it->od; f++)
+ civ[f] = riv;
+ output_curves(cntx, cov, civ); /* Lookup the input table transform */
+ rtv = cov[it->im_map[e]];
+ }
+ if (rtv < 0.0) /* Guard against sillies */
+ rtv = 0.0;
+ else if (rtv > 1.0)
+ rtv = 1.0;
+ iov = (unsigned long)(rtv * ovr + 0.5); /* output value */
+ if (gs->out_signed & (1 << e)) /* Treat output as signed */
+ iov = (iov & osb) ? iov - osb : iov + osb; /* Convert to signed from offset */
+ iov <<= ooff; /* Aligned for output */
+
+ write_entry[ts->ot_ts](p, iov); /* Write entry */
+ }
+
+ /* Put table into place */
+ it->out_tables[e] = (void *)t;
+ }
+ it->nouttabs = e;
+
+ /* Adjust the check values for output value shift */
+ for (e = 0; e < it->od; e++) {
+ int ooff = ts->ot_off[e]; /* Output value bit offset */
+ it->checkv[e] <<= ooff; /* Aligned for output */
+ }
+
+ /* Setup the appropriate skip flags, indexed by Output channel */
+ it->skipf = 0;
+ if ((oopt & OOPTS_SKIP) != 0) {
+ int i;
+ for (i = 0; i < it->od; i++) {
+ if (oopt & OOPT(oopts_skip,it->im_map[i])) { /* Skip flag for this output chan */
+ it->skipf |= (1 << i);
+ }
+ }
+ }
+
+ /* Fill in some report information */
+ it->gres = gs->itres;
+ if (!ts->sort) {
+ it->sres = gs->stres;
+ } else {
+ it->sres = 0;
+ }
+
+#ifdef VERBOSE
+ printf("imdi_tabl returning OK\n");
+#endif
+ return it;
+}
+
+/* Free up the data allocated */
+void
+imdi_tab_free(
+imdi_imp *it
+) {
+ int e;
+
+ for (e = 0; e < it->nintabs; e++)
+ free(it->in_tables[e]);
+
+ if (it->sw_table != NULL)
+ free(it->sw_table);
+ if (it->im_table != NULL)
+ free(it->im_table);
+
+ for (e = 0; e < it->nouttabs; e++)
+ free(it->out_tables[e]);
+
+ free(it);
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/imdi/imdi_tab.h b/imdi/imdi_tab.h
new file mode 100644
index 0000000..403fcaa
--- /dev/null
+++ b/imdi/imdi_tab.h
@@ -0,0 +1,170 @@
+#ifndef IMDI_TAB_H
+#define IMDI_TAB_H
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+/*
+ * Implementation details needed for table initialisation for a particular
+ * kernel. This is private implementation for imdi.[ch]
+ *
+ * The tabspec structure holds detailed information on the algorithms used
+ * by the runtime code, and (implicit in this) the layout of the runtime
+ * tables needed to match the algorithm. There are also implicit dependencies on
+ * the genspec structure, since this determines the overall features
+ * supported by a particular pixel kernel module.
+ *
+ * This is effectively the product of the genspec, the architechure,
+ * and the coding choices made by the code generator
+ * (ie. gen_c_kernel() in cgen.c)
+ *
+ */
+
+/* entries marked with '#' are not currently used by imdi_tab() */
+/* NOTE :- if you change this, you need to change the code in cgen.c */
+/* labeled !genspec and tabspec delta code! */
+struct _tabspec {
+
+ int sort; /* NZ for explicit sort rather than simplex table lookup */
+ int it_xs; /* NZ if separate interp index and simplex index/Weighting+Offset values */
+ int wo_xs; /* NZ if separate weighting and vertex offset entries are to be used */
+
+ int it_ix; /* Non-zero if input value extraction should be done in input table */
+ int it_ab; /* Input table entry size in bits */
+ int it_ts; /* Input table :- total input table entry size in bytes */
+ /* Bit packing order is (ms to ls) :
+ sort: ix, we, vo
+ sort: ix, wo
+ !sort: ix, sx
+ */
+
+ /* Interpolation index is always in the input table */
+ int ix_ab; /* # Interpolation index entry size in bits */
+ int ix_es; /* Interpolation index entry size in bytes */
+ int ix_eo; /* Interpolation index entry offset in bytes */
+
+ /* Simplex Index is always in the input table */
+ int sx_ab; /* Simplex Index entry size in bits */
+ int sx_es; /* Simplex Index entry size in bytes */
+ int sx_eo; /* Simplex Index entry offset in bytes */
+
+ int sm_ts; /* Simplex table entry total size in bytes */
+ /* Bit packing order is (ms to ls) : we, vo */
+
+ /* Combined Weighting + Offset may be in input table or Simplex entry */
+ int wo_ab; /* Combined Weighting + Offset entry size in bits */
+ int wo_es; /* Combined Weighting + Offset entry size in bytes */
+ int wo_eo; /* Combined Weighting + Offset entry offset in bytes */
+
+ /* Weighting may be in input table or Simplex entry */
+ int we_ab; /* # Weighting entry size in bits */
+ int we_es; /* Weighting entry size in bytes */
+ int we_eo; /* Weighting entry offset in bytes */
+
+ /* Vertex offset may be in input table or Simplex entry */
+ int vo_ab; /* Vertex Offset entry size in bits */
+ int vo_es; /* Vertex Offset entry size in bytes */
+ int vo_eo; /* Vertex Offset entry offset in bytes */
+ int vo_om; /* Vertex Offset scaling multiplier */
+
+ int im_cd; /* Non-zero if interpolation table entries are padded with fraction */
+ int im_ts; /* Interp. multidim :- total interp table entry size in bytes */
+ int im_oc; /* # Interp. multidim :- offset scale to apply to index into interp entry */
+ int im_fs; /* Interp. multidim :- full table entry size in bytes */
+ int im_fn; /* Interp. multidim :- number of full entries */
+ int im_fv; /* Interp. multidim :- output values per full entry . */
+ int im_ps; /* Interp. multidim :- partial table entry size in bytes, used & unsused */
+ int im_pn; /* Interp. multidim :- number of partial entries - must be 0 or 1 */
+ int im_pv; /* Interp. multidim :- used output values per partial entry . */
+
+ int ot_ts; /* Output table :- total entry size in bytes of every table */
+ int ot_off[IXDO]; /* Offset for each output value within the output word needed */
+ int ot_bits[IXDO]; /* Number of bits for value within the output word needed */
+
+ /* Associated interpolation function */
+ void (*interp)(struct _imdi *s, void **inp, void **outp, unsigned int npix); /* At run time */
+}; typedef struct _tabspec tabspec;
+
+/* Runtime conversion needed */
+typedef enum {
+ conv_none = 0x00, /* No conversion needed */
+ conv_istr = 0x01, /* Input stride conversion */
+ conv_ostr = 0x02, /* Output stride conversion */
+ conv_irep = 0x04, /* Input representation conversion */
+ conv_orep = 0x08, /* Output representation conversion */
+ conv_rev = 0x10, /* Reverse direction conversion */
+ conv_skip = 0x20 /* Skip output channel write conversion */
+} imdi_conv;
+
+/* The actual run time table that tabspec describes */
+typedef struct {
+ /* Runtime setup */
+ int id; /* Number of input dimensions */
+ int od; /* Number of output dimensions (including skip channels) */
+ int wod; /* Number of written output dimensions ( < od if skipf != 0) */
+ int it_map[IXDI]; /* Mapping from input raster channels to callback channels. */
+ int im_map[IXDO]; /* Mapping from output raster channels to callback channels. */
+ imdi_pixrep cirep; /* High level input pixel representation called with */
+ imdi_pixrep corep; /* High level output pixel representation called with */
+ imdi_pixrep firep; /* High level input pixel representation of interp func. */
+ imdi_pixrep forep; /* High level output pixel representation of interp func. */
+ imdi_conv cnv; /* Runtime argument conversion needed */
+ void (*interp)(struct _imdi *s, void **outp, int outst, /* Underlying conversion function */
+ void **inp, int inst,
+ unsigned int npixels);
+ /* Output channel check data */
+ unsigned long checkv[IXDO]; /* Output per channel check values. Set flag if != checkv */
+ unsigned int checkf; /* Output per channel check flags (one per bit) */
+ unsigned int skipf; /* Output per channel skip flags (one per bit) */
+
+ /* Table data */
+ void *in_tables[IXDI]; /* Input dimension input lookup tables */
+ void *sw_table; /* Simplex weighting lookup table */
+ void *im_table; /* Interpolation Multi-dimensional lookup table */
+ void *out_tables[IXDO]; /* Output dimension output lookup tables */
+ int nintabs; /* Number of input tables */
+ int nouttabs; /* Number of output tables */
+
+ /* Extra reporting data */
+ unsigned long size; /* Number of bytes allocated to imdi_imp */
+ unsigned int gres, sres; /* Grid and simplex table resolutions. sres = 0 = sort */
+} imdi_imp;
+
+/*
+ * The runtime function that knows how to setup an imdi_imp
+ * table for for our chosen kernel and the color mapping we
+ * want to perform.
+ */
+
+imdi_imp *
+imdi_tab(
+ genspec *gs, /* Pointer to gen spec */
+ tabspec *ts, /* Pointer to table spec */
+ imdi_conv cnv, /* Runtime argument conversion needed */
+ imdi_pixrep irep, /* High level input pixel representation to match */
+ imdi_pixrep orep, /* High level output pixel representation to match */
+ void (*interp)(struct _imdi *s, void **outp, int outst, /* Underlying conversion function */
+ void **inp, int inst,
+ unsigned int npixels),
+ int *inm, /* Input raster channel to callback channel mapping, NULL for none. */
+ int *outm, /* Output raster channel to callback channel mapping, NULL for none. */
+ imdi_ooptions oopt, /* Output per channel options (Callback channel, NOT written channel) */
+ unsigned int *checkv, /* Output channel check values (Callback channel, NULL for none == 0. */
+
+ /* Callbacks to initialse the imdi table values */
+ void (*input_curves) (void *cntx, double *out_vals, double *in_vals),
+ void (*md_table) (void *cntx, double *out_vals, double *in_vals),
+ void (*output_curves)(void *cntx, double *out_vals, double *in_vals),
+ void *cntx /* Context of callbacks */
+);
+
+void imdi_tab_free(imdi_imp *it);
+
+#endif /* IMDI_TAB_H */
diff --git a/imdi/imdi_utl.h b/imdi/imdi_utl.h
new file mode 100644
index 0000000..f1a3ff5
--- /dev/null
+++ b/imdi/imdi_utl.h
@@ -0,0 +1,262 @@
+#ifndef IMDI_UTL_H
+#define IMDI_UTL_H
+
+/* Integer Multi-Dimensional Interpolation */
+
+/*
+ * Copyright 2000 - 2007 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.
+ */
+
+#include <limits.h>
+
+/* Common utility definitions used at both generation and runtime. */
+
+#define IXDI 10 /* maximum input channels/dimensions allowed */
+#define IXDO 10 /* maximum output channels/dimensions allowed */
+
+#if IXDI > IXDO /* Maximum of either DI or DO */
+# define IXDIDO IXDI
+#else
+# define IXDIDO IXDO
+#endif
+
+#define ALLOW64 /* Allow declarations but not use of 64 bit types */
+
+#ifndef FORCE64
+# undef FORCE64 /* Use 64 bit, even on architectures where it's */
+ /* not a native size. ALLOW64 must be defined */
+#endif
+
+/* ------------------------------------------------------ */
+
+#if defined(ALLOW64) && (ULONG_MAX == 0xffffffffffffffffUL || defined(FORCE64))
+#ifndef USE64
+#pragma message("Using 64 bit integer color kernel")
+#endif /* USE64 */
+#define USE64 /* Use 64 bits if it's natural or forced */
+#endif
+
+/* ------------------------------------------------------- */
+/* Macros combination counter */
+/* Declare the counter name nn, combinations out of total */
+/* Maximum combinations is DI+2 */
+
+#define COMBO(nn, comb, total) \
+ int nn[IXDI+2]; /* counter value */ \
+ int nn##_cmb = (comb); /* number of combinations*/ \
+ int nn##_tot = (total); /* out of total possible */ \
+ int nn##_e /* dimension index */
+
+/* Set total to new setting */
+#define CB_SETT(nn, total) \
+ nn##_tot = (total) /* total possible */
+
+/* Set combinations to new setting */
+#define CB_SETC(nn, comb) \
+ nn##_cmb = (comb) /* number of combinations*/
+
+/* Set the counter to its initial value */
+#define CB_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) \
+ nn[nn##_e] = nn##_cmb-nn##_e-1; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define CB_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < (nn##_tot-nn##_e)) { \
+ int nn##_ee; /* No carry */ \
+ for (nn##_ee = nn##_e-1; nn##_ee >= 0; nn##_ee--) \
+ nn[nn##_ee] = nn[nn##_ee+1] + 1; \
+ break; \
+ } \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define CB_DONE(nn) \
+ (nn##_e >= nn##_cmb)
+
+
+/* ------------------------------------------------------- */
+/* Macros simplex combination counter. */
+/* Based on COMBO, but skips invalid simplex combinations */
+
+#define XCOMBO(nn, comb, total) \
+ COMBO(nn, comb, total)
+
+/* Set total to new setting */
+#define XCB_SETT(nn, total) \
+ CB_SETT(nn, total)
+
+/* Set combinations to new setting */
+#define XCB_SETC(nn, comb) \
+ CB_SETC(nn, comb)
+
+
+/* Set the counter to its initial value */
+#define XCB_INIT(nn) \
+{ \
+ int nn##_ii; \
+ \
+ for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) \
+ nn[nn##_e] = nn##_cmb-nn##_e-1; \
+ for (nn##_ii = 1; nn##_ii < nn##_cmb; nn##_ii++) { \
+ if ((nn[nn##_ii-1] ^ nn[nn##_ii]) & nn[nn##_ii])\
+ break; /* Went from 0 to 1 */ \
+ } \
+ if (nn##_ii < nn##_cmb) { /* Fix invalid combination */ \
+ XCB_INC(nn); \
+ } \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define XCB_INC(nn) \
+{ \
+ int nn##_ii = 0; \
+ \
+ while (nn##_ii < nn##_cmb) { \
+ for (nn##_e = 0; nn##_e < nn##_cmb; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < (nn##_tot-nn##_e)) { \
+ int nn##_ee; /* No carry */ \
+ for (nn##_ee = nn##_e-1; nn##_ee >= 0; nn##_ee--) \
+ nn[nn##_ee] = nn[nn##_ee+1] + 1; \
+ break; \
+ } \
+ } \
+ if (nn##_e >= nn##_cmb) \
+ break; /* Done */ \
+ \
+ /* Reject invalid combinations */ \
+ for (nn##_ii = 1; nn##_ii < nn##_cmb; nn##_ii++) { \
+ if ((nn[nn##_ii-1] ^ nn[nn##_ii]) & nn[nn##_ii]) \
+ break; /* Went from 0 to 1 */ \
+ } \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define XCB_DONE(nn) \
+ CB_DONE(nn)
+
+/* ------------------------------------------------------- */
+/* Macro pseudo-hilbert counter */
+/* This multi-dimensional count sequence is a distributed */
+/* Gray code sequence, with direction reversal on every */
+/* alternate power of 2 scale. */
+/* It is intended to aid cache coherence in multi-dimensional */
+/* regular sampling. It approximates the Hilbert curve sequence. */
+
+#define PHILBERT(nn) \
+ int nn[IXDIDO];/* counter value */ \
+ int nn##di; /* Dimensionality */ \
+ unsigned nn##res; /* Resolution per coordinate */ \
+ unsigned nn##bits; /* Bits per coordinate */ \
+ unsigned nn##ix; /* Current binary index */ \
+ unsigned nn##tmask; /* Total 2^n count mask */ \
+ unsigned nn##count; /* Usable count */
+
+/* Init counter for dimenion di, resolution res */
+#define PH_INIT(nn, pdi, pres) \
+{ \
+ int nn##e; \
+ \
+ nn##di = pdi; \
+ nn##res = (unsigned)pres; \
+ \
+ /* Compute bits */ \
+ for (nn##bits = 0; (1u << nn##bits) < nn##res; nn##bits++) \
+ ; \
+ \
+ /* Compute the total count mask */ \
+ nn##tmask = ((1u << (nn##bits * nn##di))-1); \
+ \
+ /* Compute usable count */ \
+ nn##count = 1; \
+ for (nn##e = 0; nn##e < nn##di; nn##e++) \
+ nn##count *= nn##res; \
+ \
+ nn##ix = 0; \
+ for (nn##e = 0; nn##e < nn##di; nn##e++) \
+ nn[nn##e] = 0; \
+}
+
+/* Increment the counter value */
+#define PH_INC(nn) \
+{ \
+ int nn##e; \
+ do { \
+ unsigned int nn##b; \
+ int nn##gix; /* Gray code index */ \
+ \
+ nn##ix = (nn##ix + 1) & nn##tmask; \
+ \
+ /* Convert to gray code index */ \
+ nn##gix = nn##ix ^ (nn##ix >> 1); \
+ \
+ for (nn##e = 0; nn##e < nn##di; nn##e++) \
+ nn[nn##e] = 0; \
+ \
+ /* Distribute bits */ \
+ for (nn##b = 0; nn##b < nn##bits; nn##b++) { \
+ if (nn##b & 1) { /* In reverse order */ \
+ for (nn##e = nn##di-1; nn##e >= 0; nn##e--) { \
+ nn[nn##e] |= (nn##gix & 1) << nn##b; \
+ nn##gix >>= 1; \
+ } \
+ } else { /* In normal order */ \
+ for (nn##e = 0; nn##e < nn##di; nn##e++) { \
+ nn[nn##e] |= (nn##gix & 1) << nn##b; \
+ nn##gix >>= 1; \
+ } \
+ } \
+ } \
+ \
+ /* Convert from Gray to binary coordinates */ \
+ for (nn##e = 0; nn##e < nn##di; nn##e++) { \
+ unsigned nn##sh, nn##tv; \
+ \
+ for(nn##sh = 1, nn##tv = nn[nn##e];; nn##sh <<= 1) { \
+ unsigned nn##ptv = nn##tv; \
+ nn##tv ^= (nn##tv >> nn##sh); \
+ if (nn##ptv <= 1 || nn##sh == 16) \
+ break; \
+ } \
+ /* Filter - increment again if outside cube range */ \
+ if (nn##tv >= nn##res) \
+ break; \
+ nn[nn##e] = nn##tv; \
+ } \
+ \
+ } while (nn##e < nn##di); \
+ \
+}
+
+/* After increment, expression is TRUE if counter has looped back to start. */
+#define PH_LOOPED(nn) \
+ (nn##ix == 0) \
+
+/* ------------------------------------------------------- */
+
+#endif /* IMDI_UTL_H */
+
+
+
+
+
+
+
+
+
+
+
diff --git a/imdi/itest.c b/imdi/itest.c
new file mode 100644
index 0000000..8edcb8b
--- /dev/null
+++ b/imdi/itest.c
@@ -0,0 +1,652 @@
+
+/* Verify and benchmark the imdi code */
+/*
+ * Copyright 2000 - 2006 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "imdi.h"
+#include "refi.h"
+
+/* Test parameters */
+#undef TEST1 /* Test just one combination */
+#define FULL /* Test full range */
+#undef VERBOSE /* Report every conversion */
+#undef REPORT_ERRORS /* Report conversion with large errors */
+#define TRAND /* Test random in/out table contents */
+#define TCRAND /* Test random clut table contents */
+#undef QUANTIZE /* Quantize the target table values */
+#define TBUFSIZE (2 * 1024 * 1024) /* Default number of input bytes to test */
+#define ITERS 10 /* Itterations */
+
+double trans1(double in, double t);
+double trans2(double in, double t);
+
+/* Context for refi setup callbacks */
+typedef struct {
+ int id;
+ int od;
+ double icurve[MXDI]; /* Input curve factors */
+ double clut[MXDO][MXDI]; /* clut matrix factors */
+ double ocurve[MXDO]; /* Output curve factors */
+} rcntx;
+
+/* Input curve function */
+static void input_curves(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ int i;
+ rcntx *rx = (rcntx *)cntx;
+
+ for (i = 0; i < rx->id; i++) {
+ double val = in_vals[i];
+#ifdef TRAND
+ val = trans1(val, rx->icurve[i]);
+#ifdef QUANTIZE
+ val = ((int)(val * 255.0 + 0.5))/255.0; /* Quantize to 8 bits */
+#endif
+#endif
+ out_vals[i] = val;
+ }
+}
+
+/* Multi-dim table function */
+static void md_table(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ rcntx *rx = (rcntx *)cntx;
+ int i, j;
+
+#ifdef TCRAND
+ for (j = 0; j < rx->od; j++) {
+ double val = 0.0;
+ for (i = 0; i < rx->id; i++) {
+ val += rx->clut[j][i] * in_vals[i];
+ }
+#ifdef QUANTIZE
+ val = ((int)(val * 255.0 + 0.5))/255.0; /* Quantize to 8 bits */
+#endif
+ out_vals[j] = val;
+ }
+#else
+ for (j = 0; j < rx->od; j++)
+ out_vals[j] = in_vals[j % rx->id];
+#endif
+//printf("~1 out %f %f %f %f from %f\n", out_vals[0], out_vals[1], out_vals[2], out_vals[3], in_vals[0]);
+}
+
+/* Output curve function */
+static void output_curves(
+ void *cntx,
+ double *out_vals,
+ double *in_vals
+) {
+ int i;
+ rcntx *rx = (rcntx *)cntx;
+
+ for (i = 0; i < rx->od; i++) {
+ double val = in_vals[i];
+#ifdef TRAND
+ val = trans1(val, rx->ocurve[i]);
+#ifdef QUANTIZE
+ val = ((int)(val * 255.0 + 0.5))/255.0; /* Quantize to 8 bits */
+#endif
+#endif
+ out_vals[i] = val;
+ }
+}
+
+/* Complete reference interpolation */
+void refi_interp(refi *r, double *out_vals, double *in_vals);
+
+void usage(void) {
+ fprintf(stderr,"Regression test imdi code Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"usage: itest [-q] [-s]\n");
+ fprintf(stderr," -q Quick test\n");
+ fprintf(stderr," -s Stop on error\n");
+ fprintf(stderr," -r bits Specify bits of randomness in input data\n");
+ exit(1);
+}
+
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int quick = 0;
+ int stop = 0;
+ int rbits = 16;
+ int n, i, j, e;
+ int pix, iix, oix;
+ int ip, op, id, od;
+ int ires, cres, ores;
+ clock_t stime, ttime; /* Start and total times */
+ double xtime; /* Total execution time in seconds */
+ double npixels; /* Number of pixels processed */
+ rcntx rx;
+
+ refi *r;
+ double ribuf[MXDI];
+ double robuf[MXDO];
+
+ imdi *s;
+ int iters;
+ unsigned long tbufsize;
+ unsigned char *ibuf;
+ unsigned char *obuf;
+ unsigned char *inp[MXDI];
+ unsigned char *outp[MXDO];
+ unsigned short *ibuf2; /* 16 bit references */
+ unsigned short *obuf2;
+
+ double omxerr = 0; /* Overall max error /1.0 */
+
+ /* Define combinations to test */
+#ifdef TEST1
+#pragma message("!!!!!!!!!!!!!!!!! TEST1 is defined !!!!!!!!!!!!!!!1")
+ int ids[] = { 3, 0 }; /* Input dimensions */
+ int ods[] = { 3, 0 }; /* Output dimensions */
+ int iprs[] = { 16, 0 };
+ int oprs[] = { 16, 0 };
+#else
+#ifndef FULL
+ int ids[] = { 1, 3, 4, 8, 0 };
+ int ods[] = { 1, 3, 4, 8, 0 };
+ int iprs[] = { 8, 8, 16, 0};
+ int oprs[] = { 8, 16, 16, 0};
+#else
+ int ids[] = { 1, 3, 4, 5, 6, 7, /* 8, */ 0 };
+ int ods[] = { 1, 3, 4, 5, 6, 7, /* 8, */ 0 };
+ int iprs[] = { 8, 8, 16, 0};
+ int oprs[] = { 8, 16, 16, 0};
+#endif
+#endif
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Quick test */
+ else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') {
+ quick = 1;
+ }
+
+ /* Stop on error */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ stop = 1;
+ }
+
+ /* Degree of data randomness */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ rbits = atoi(na);
+ if (rbits < 0)
+ rbits = 1;
+ else if (rbits > 16)
+ rbits = 16;
+ }
+ else
+ usage();
+ } else
+ break;
+ }
+
+ for (iix = 0; ids[iix] > 0; iix++) { /* All input dimensions */
+ for (oix = 0; ods[oix] > 0; oix++) { /* All output dimensions */
+ for (pix = 0; iprs[pix] > 0; pix++) { /* All precisions */
+ int rmask = 0;
+ ip = iprs[pix]; /* Input precision */
+ op = oprs[pix]; /* Output precision */
+ id = ids[iix]; /* Input dimensions */
+ od = ods[oix]; /* Outpu dtimensions */
+
+ if (ip != 8 && ip != 16)
+ error("Can't handle input precision of %d in testing\n",ip);
+ if (op != 8 && op != 16)
+ error("Can't handle output precision of %d in testing\n",op);
+ if (id > MXDI)
+ error("Can't handle id greater than %d in testing\n",MXDI);
+ if (od > MXDO)
+ error("Can't handle od greater than %d in testing\n",MXDO);
+
+ printf("Testing id = %d, od = %d, ip = %d, op = %d\n",id,od,ip,op);
+
+ ires = 256;
+
+ switch (id) {
+ case 1:
+ cres = 257;
+ break;
+ case 2:
+ case 3:
+ cres = 33;
+ break;
+ case 4:
+ cres = 17;
+ break;
+ case 5:
+ cres = 7;
+ break;
+ case 6:
+ cres = 7;
+ break;
+ case 7:
+ cres = 5;
+ break;
+ case 8:
+ cres = 5;
+ break;
+ default:
+ cres = 3;
+ }
+ ores = 256;
+
+ /* Setup error messages */
+ error_program = "itest";
+
+ /* Create the reference first */
+ printf("About to create refi\n");
+
+ /* Create test curves */
+ rx.id = id;
+ rx.od = od;
+
+ rand32(0x1234);
+ for (i = 0; i < id; i++) {
+ rx.icurve[i] = d_rand(-1.0, 1.0);
+ }
+
+//printf("Matrix params =\n");
+ rand32(0x2345);
+ for (j = 0; j < od; j++) {
+ double s = 0.0;
+ for (i = 0; i < id; i++) {
+ double v = d_rand(1.0, 0.0);
+ rx.clut[j][i] = v; /* Make them sum to 1.0 */
+ s += v;
+ }
+ for (i = 0; i < id; i++) {
+ rx.clut[j][i] /= s;
+//printf(" %f",rx.clut[j][i]);
+ }
+//printf("\n");
+ }
+
+ rand32(0x3456);
+ for (j = 0; j < od; j++) {
+ rx.ocurve[j] = d_rand(-1.0, 1.0);
+ }
+
+ r = new_refi(
+ id, /* Number of input dimensions */
+ od, /* Number of output dimensions */
+ ires, /* Input table resolution */
+ cres, /* clut resolution */
+ ores, /* Output table resolution */
+ input_curves, /* Callback functions */
+ md_table,
+ output_curves,
+ (void *)&rx /* Context to callbacks */
+ );
+
+ if (r == NULL) {
+ error("new_refi failed");
+ }
+
+ /* Now crate the imdi we want to test, using the */
+ /* reference as a template */
+ printf("About to create imdi\n");
+
+ s = new_imdi(
+ id, /* Number of input dimensions */
+ od, /* Number of output dimensions */
+ ip == 8 ? pixint8 : pixint16, /* Input pixel representation */
+ 0x0, /* Treat every channel as unsigned */
+ NULL, /* No raster to callback mapping */
+ prec_min, /* Minimum of input and output precision */
+ op == 8 ? pixint8 : pixint16, /* Output pixel representation */
+ 0x0, /* Treat every channel as unsigned */
+ NULL, /* No raster to callback mapping */
+ cres, /* Desired table resolution */
+ oopts_none, /* Desired per channel output options */
+ NULL, /* Output channel check values */
+ opts_none, /* Desired processing direction and stride support */
+ refi_input, /* Callback functions */
+ refi_clut,
+ refi_output,
+ (void *)r /* Context to callbacks */
+ );
+
+ if (s == NULL) {
+ error("new_imdi failed");
+ }
+
+ if (quick) {
+ iters = 1;
+ tbufsize = 4096/id;
+ } else {
+ iters = ITERS;
+ tbufsize = TBUFSIZE/id;
+ }
+
+ /* Allocate the test buffers */
+ if ((ibuf = malloc(sizeof(unsigned char) * ip/8 * id * tbufsize)) == NULL)
+ error("Malloc of input buffer failed");
+ ibuf2 = (unsigned short *)ibuf;
+
+ if ((obuf = malloc(sizeof(unsigned char) * op/8 * od * tbufsize)) == NULL)
+ error("Malloc of output buffer failed");
+ obuf2 = (unsigned short *)obuf;
+
+ /* Initialise the input buffer contents */
+ rand32(0x12345678);
+ if (ip == 8) {
+ unsigned ui;
+ int rr = rbits;
+ if (rr > 8)
+ rr = 8;
+ rmask = ((1 << rr) -1) << (8-rr);
+ for (ui = 0; ui < tbufsize; ui += id) {
+ for (e = 0; e < id; e++) {
+ unsigned long ran = rand32(0);
+ ibuf[ui + e] = (unsigned char)(ran & rmask);
+ }
+ }
+ } else {
+ unsigned ui;
+ rmask = ((1 << rbits) -1) << (16-rbits);
+ for (ui = 0; ui < tbufsize; ui += id) {
+ for (e = 0; e < id; e++) {
+ unsigned long ran = rand32(0);
+ ibuf2[ui + e] = (unsigned short)(ran & rmask);
+ }
+ }
+ }
+
+ /* We are assuming packed pixel interleaved */
+ inp[0] = ibuf;
+ outp[0] = obuf;
+
+ /* Benchmark it */
+ stime = clock();
+ for (n = 0; n < iters; n++) {
+ s->interp(s, (void **)outp, 0, (void **)inp, 0, tbufsize);
+ }
+ ttime = clock() - stime;
+ xtime = (double)ttime/(double)CLOCKS_PER_SEC;
+ npixels = (double)iters * (double)tbufsize;
+
+ if (xtime > 0.0)
+ printf("Speed = rate = %f Mpix/sec\n",1e-6 * npixels / xtime);
+ else
+ printf("Speed - too fast!\n");
+
+ {
+ unsigned ui;
+ double mxerr = 0.0;
+ double avgerr = 0.0;
+
+ /* Verify the accuracy against refi of each sample */
+ for (ui = j = 0; ui < tbufsize; ui += id, j += od) {
+ int mxserr;
+
+ if (ip == 8) {
+ for (e = 0; e < id; e++) {
+ ribuf[e] = ibuf[ui + e]/255.0;
+ }
+ } else {
+ for (e = 0; e < id; e++) {
+ ribuf[e] = ibuf2[ui + e]/65535.0;
+ }
+ }
+ refi_interp(r, robuf, ribuf);
+
+ mxserr = 0;
+
+ if (op == 8) {
+ for (e = 0; e < od; e++) {
+ double err = robuf[e] * 255.0 - obuf[j + e];
+ if (err < 0)
+ err = -err;
+ if (err > mxerr)
+ mxerr = err;
+ if (err > mxserr)
+ mxserr = err;
+ avgerr += err;
+ }
+ } else {
+ for (e = 0; e < od; e++) {
+ double err = robuf[e] * 65535.0 - obuf2[j + e];
+ if (err < 0)
+ err = -err;
+ if (err > mxerr)
+ mxerr = err;
+ if (err > mxserr)
+ mxserr = err;
+ avgerr += err;
+ }
+ }
+#if defined(REPORT_ERRORS) || defined(VERBOSE)
+ if (mxserr >= 37) {
+ if (ip == 8) {
+ if (id == 1)
+ printf("in %d, ", ibuf[ui+0]);
+ if (id == 2)
+ printf("in %d %d, ", ibuf[ui+0], ibuf[ui+1]);
+ if (id == 3)
+ printf("in %d %d %d, ", ibuf[ui+0], ibuf[ui+1], ibuf[ui+2]);
+ if (id == 4)
+ printf("in %d %d %d, ",
+ ibuf[ui+0], ibuf[ui+1], ibuf[ui+2], ibuf[ui+3]);
+ } else {
+ if (id == 1)
+ printf("in %d, ", ibuf2[ui+0]);
+ if (id == 2)
+ printf("in %d %d, ", ibuf2[ui+0], ibuf2[ui+1]);
+ if (id == 3)
+ printf("~in %d %d %d, ", ibuf2[ui+0], ibuf2[ui+1], ibuf2[ui+2]);
+ if (id == 4)
+ printf("in %d %d %d, ",
+ ibuf2[ui+0], ibuf2[ui+1], ibuf2[ui+2], ibuf2[ui+3]);
+ }
+ if (ip == 8) {
+ if (od == 1)
+ printf("is %d, should be %d\n",
+ obuf[j+0],
+ (int)(robuf[0] * 255.0 + 0.5));
+ if (od == 2)
+ printf("is %d %d, should be %d %d\n",
+ obuf[j+0], obuf[j+1],
+ (int)(robuf[0] * 255.0 + 0.5),
+ (int)(robuf[1] * 255.0 + 0.5));
+ if (od == 3)
+ printf("is %d %d %d, should be %d %d %d\n",
+ obuf[j+0], obuf[j+1], obuf[j+2],
+ (int)(robuf[0] * 255.0 + 0.5),
+ (int)(robuf[1] * 255.0 + 0.5),
+ (int)(robuf[2] * 255.0 + 0.5));
+ if (od == 4)
+ printf("is %d %d %d %d, should be %d %d %d %d\n",
+ obuf[j+0], obuf[j+1], obuf[j+2], obuf[j+3],
+ (int)(robuf[0] * 255.0 + 0.5),
+ (int)(robuf[1] * 255.0 + 0.5),
+ (int)(robuf[2] * 255.0 + 0.5),
+ (int)(robuf[3] * 255.0 + 0.5));
+ } else {
+ if (od == 1)
+ printf("is %d, should be %d\n",
+ obuf2[j+0],
+ (int)(robuf[0] * 65535.0 + 0.5));
+ if (od == 2)
+ printf("is %d %d, should be %d %d\n",
+ obuf2[j+0], obuf2[j+1],
+ (int)(robuf[0] * 65535.0 + 0.5),
+ (int)(robuf[1] * 65535.0 + 0.5));
+ if (od == 3)
+ printf("is %d %d %d, should be %d %d %d\n",
+ obuf2[j+0], obuf2[j+1], obuf2[j+2],
+ (int)(robuf[0] * 65535.0 + 0.5),
+ (int)(robuf[1] * 65535.0 + 0.5),
+ (int)(robuf[2] * 65535.0 + 0.5));
+ if (od == 4)
+ printf("is %d %d %d %d, should be %d %d %d %d\n",
+ obuf2[j+0], obuf2[j+1], obuf2[j+2], obuf2[j+3],
+ (int)(robuf[0] * 65535.0 + 0.5),
+ (int)(robuf[1] * 65535.0 + 0.5),
+ (int)(robuf[2] * 65535.0 + 0.5),
+ (int)(robuf[3] * 65535.0 + 0.5));
+ }
+ }
+
+#endif /* VERBOSE || REPORT+ERRORS */
+ }
+ avgerr /= ((double)tbufsize * od);
+
+ {
+ double fmxerr; /* Relative maximum error */
+ double favgerr; /* Relative average error */
+
+ /* Always relative to basic precision */
+ fmxerr = mxerr / ((1 << op) - 1.0);
+ favgerr = avgerr / ((1 << op) - 1.0);
+
+ printf("Worst error = %f = %f%%, average error = %f%%\n",
+ mxerr, 100.0 * fmxerr, 100.0 * favgerr);
+ printf("\n");
+
+ if (fmxerr > omxerr)
+ omxerr = fmxerr;
+
+ }
+ }
+ /* Free everything up */
+ free(ibuf);
+ free(obuf);
+ refi_free(r);
+ s->del(s);
+
+ if (stop && (100.0 * omxerr) > 1.2) {
+ goto quit;
+ }
+ }
+ }
+ }
+
+ quit:;
+ printf("Overall worst error = %f%%\n", 100.0 * omxerr);
+
+ return 0;
+}
+
+
+
+
+/* ------------------------------------------------- */
+/* Support */
+
+/* Run an interpolation though the whole refi */
+void refi_interp(
+refi *r,
+double *out_vals,
+double *in_vals
+) {
+#ifdef QUANTIZE
+ int e;
+#endif
+ double ivals[MXDI];
+ double ovals[MXDO];
+
+ refi_input((void *)r, ivals, in_vals);
+#ifdef QUANTIZE
+ for (e = 0; e < r->id; e++)
+ ivals[e] = ((int)(ivals[e] * 255.0 + 0.5))/255.0; /* Quantize to 8 bits */
+#endif
+
+ refi_clut((void *)r, ovals, ivals);
+
+#ifdef QUANTIZE
+ for (e = 0; e < r->od; e++)
+ ovals[e] = ((int)(ovals[e] * 255.0 + 0.5))/255.0; /* Quantize to 8 bits */
+#endif
+ refi_output((void *)r, out_vals, ovals);
+}
+
+
+/* ------------------------------------------------- */
+/* Some test functions */
+
+/* Single bump version */
+double
+trans1(
+double in,
+double t /* Non-linearity factor. 0.0 to +/-1.0 */
+) {
+ double out;
+
+ out = in + t * in * (1.0 - in);
+ return out;
+}
+
+/* Double bump version */
+double
+trans2(
+double in,
+double t /* Non-linearity factor. 0.0 to +/-1.0 */
+) {
+ double nf, out;
+
+ if (in >= 0.5) {
+ nf = -2.0 * (in - 0.5) * (1.0 - in);
+ } else {
+ nf = 2.0 * in * (0.5 - in);
+ }
+ out = in + t * nf;
+ return out;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/imdi/refi.c b/imdi/refi.c
new file mode 100644
index 0000000..55fe449
--- /dev/null
+++ b/imdi/refi.c
@@ -0,0 +1,212 @@
+/* Test support code */
+/*
+ * Copyright 2000 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.
+ */
+
+#include "stdio.h"
+#include "stdlib.h"
+#include "refi.h"
+
+/* Callbackes used to setup rspl's */
+static void inputlu(
+void *cbctx,
+double *out,
+double *in
+) {
+ int i;
+ refi *r = (refi *)cbctx;
+ double ov[MXDI], iv[MXDI];
+
+ for (i = 0; i < r->id; i++)
+ iv[i] = *in;
+ r->input_curves(r->cntx, ov, iv);
+
+ *out = ov[r->chan];
+}
+
+static void clutlu(
+void *cbctx,
+double *out,
+double *in
+) {
+ refi *r = (refi *)cbctx;
+
+ r->md_table(r->cntx, out, in);
+}
+
+static void outputlu(
+void *cbctx,
+double *out,
+double *in
+) {
+ int i;
+ refi *r = (refi *)cbctx;
+ double ov[MXDO], iv[MXDO];
+
+ for (i = 0; i < r->od; i++)
+ iv[i] = *in;
+ r->output_curves(r->cntx, ov, iv);
+
+ *out = ov[r->chan];
+}
+
+
+refi *new_refi(
+int id, /* Number of input dimensions */
+int od, /* Number of output dimensions */
+int inres, /* Desired input table resolution */
+int clutres, /* Desired clut table resolution */
+int outres, /* Desired output table resolution */
+
+/* Callbacks to lookup the table values */
+void (*input_curves) (void *cntx, double *out_vals, double *in_vals),
+void (*md_table) (void *cntx, double *out_vals, double *in_vals),
+void (*output_curves)(void *cntx, double *out_vals, double *in_vals),
+void *cntx /* Context to callbacks */
+) {
+ refi *r;
+ int e;
+ int gres[MXDI];
+
+ if ((r = (refi *)malloc(sizeof(refi))) == NULL) {
+ fprintf(stderr,"Malloc of refi failed\n");
+ exit (-1);
+ }
+
+ r->id = id;
+ r->od = od;
+ r->inres = inres;
+ r->clutres = clutres;
+ r->outres = outres;
+ r->input_curves = input_curves;
+ r->md_table = md_table;
+ r->output_curves = output_curves;
+ r->cntx = cntx;
+
+ /* Create some input interpolations */
+ for (e = 0; e < id; e++) {
+ if ((r->in[e] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ fprintf(stderr,"new_rspl failed\n");
+ exit (-1);
+ }
+ r->chan = e;
+ r->in[e]->set_rspl(r->in[e], 0, (void *)r, inputlu, NULL, NULL, &inres, NULL, NULL);
+ }
+
+ /* Clut */
+ if ((r->clut = new_rspl(RSPL_NOFLAGS, id, od)) == NULL) {
+ fprintf(stderr,"new_rspl failed\n");
+ exit (-1);
+ }
+ for (e = 0; e < id; e++)
+ gres[e] = clutres;
+ r->clut->set_rspl(r->clut, 0, (void *)r, clutlu, NULL, NULL, gres, NULL, NULL);
+
+ /* Create some output interpolations */
+ for (e = 0; e < od; e++) {
+ if ((r->out[e] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ fprintf(stderr,"new_rspl failed\n");
+ exit (-1);
+ }
+ r->chan = e;
+ r->out[e]->set_rspl(r->out[e], 0, (void *)r, outputlu, NULL, NULL, &outres, NULL, NULL);
+ }
+
+ return r;
+}
+
+/* Run an interpolation through an input table */
+void refi_input(
+void *cntx,
+double *out_vals,
+double *in_vals
+) {
+ refi *r = (refi *)cntx;
+ int e;
+ co vals; /* Input and output values */
+
+ for (e = 0; e < r->id; e++) {
+ vals.p[0] = in_vals[e];
+ r->in[e]->interp(r->in[e], &vals);
+ out_vals[e] = vals.v[0];
+ }
+}
+
+/* Run an interpolation through an clut table */
+void refi_clut(
+void *cntx,
+double *out_vals,
+double *in_vals
+) {
+ refi *r = (refi *)cntx;
+ int e;
+ co vals; /* Input and output values */
+
+ for (e = 0; e < r->id; e++)
+ vals.p[e] = in_vals[e];
+ r->clut->interp(r->clut, &vals);
+ for (e = 0; e < r->od; e++)
+ out_vals[e] = vals.v[e];
+}
+
+/* Run an interpolation through an output table */
+void refi_output(
+void *cntx,
+double *out_vals,
+double *in_vals
+) {
+ refi *r = (refi *)cntx;
+ int e;
+ co vals; /* Input and output values */
+
+ for (e = 0; e < r->od; e++) {
+ vals.p[0] = in_vals[e];
+ r->out[e]->interp(r->out[e], &vals);
+ out_vals[e] = vals.v[0];
+ }
+}
+
+void
+refi_free(
+refi *r
+) {
+ int e;
+
+ for (e = 0; e < r->id; e++) {
+ r->in[e]->del(r->in[e]);
+ }
+
+ r->clut->del(r->clut);
+
+ for (e = 0; e < r->od; e++) {
+ r->out[e]->del(r->out[e]);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/imdi/refi.h b/imdi/refi.h
new file mode 100644
index 0000000..26570c4
--- /dev/null
+++ b/imdi/refi.h
@@ -0,0 +1,53 @@
+
+/* Reference floating point interpolator constructed out of rspl's */
+/* This provides imdi functionality in floating point */
+/*
+ * Copyright 2000 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.
+ */
+
+#include "../rspl/rspl.h"
+
+/* ------------------------------------------------ */
+
+typedef struct {
+ int id, od; /* Input and output dimensions */
+ int inres; /* Desired input table resolution */
+ int clutres; /* Desired clut table resolution */
+ int outres; /* Desired output table resolution */
+ rspl *in[MXDI];
+ rspl *clut;
+ rspl *out[MXDO];
+
+ void (*input_curves) (void *cntx, double *out_vals, double *in_vals);
+ void (*md_table) (void *cntx, double *out_vals, double *in_vals);
+ void (*output_curves)(void *cntx, double *out_vals, double *in_vals);
+ void *cntx; /* Context to callbacks */
+ int chan; /* Current callback channel */
+} refi;
+
+refi *new_refi(
+ int id, /* Number of input dimensions */
+ int od, /* Number of output dimensions */
+ int inres, /* Desired input table resolution */
+ int clutres, /* Desired clut table resolution */
+ int outres, /* Desired output table resolution */
+
+ /* Callbacks to lookup the table values */
+ void (*input_curves) (void *cntx, double *out_vals, double *in_vals),
+ void (*md_table) (void *cntx, double *out_vals, double *in_vals),
+ void (*output_curves)(void *cntx, double *out_vals, double *in_vals),
+ void *cntx /* Context to callbacks */
+);
+
+void refi_free(refi *r);
+
+
+/* Component interpolations */
+void refi_input(void *cntx, double *out_vals, double *in_vals);
+void refi_clut(void *cntx, double *out_vals, double *in_vals);
+void refi_output(void *cntx, double *out_vals, double *in_vals);
+
diff --git a/imdi/ssort.c b/imdi/ssort.c
new file mode 100644
index 0000000..f9a25fd
--- /dev/null
+++ b/imdi/ssort.c
@@ -0,0 +1,322 @@
+/* Test code that generates optimised C sorting */
+/* code, suitable for classifying an input vector */
+/* into a particular simplex. */
+
+/*
+ * Copyright 2000 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.
+ */
+
+/* Intended for inclusion in IMDI for 16 bit support */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+/* Sorting data */
+#define MAXSV 50 /* Maximum sort variables */
+typedef struct {
+ int bot; /* 0 if we are doing ==, 1 if >, 2 if else */
+ int dval; /* Difference value to apply */
+ int vals[MAXSV]; /* Variable values */
+ int sort[MAXSV]; /* Sorted index */
+} sortd;
+
+/* Context */
+typedef struct {
+ FILE *of; /* Output file */
+ int indt; /* Indent */
+
+ /* Sort data */
+ int nv; /* Number of variables to sort */
+ int sl; /* Non-zero to generate code for smallest to largest */
+ int eq; /* Non-zero to generate code for equal case */
+ int la; /* Non-zero to generate labels */
+ int rl; /* Recursion level */
+ sortd sd[MAXSV]; /* Data at each recursion level */
+ int ln; /* Label number */
+
+} fileo;
+
+void line(fileo *f, char *fmt, ...); /* Output one line */
+void niline(fileo *f, char *fmt, ...); /* Output one line, no indent */
+void sline(fileo *f, char *fmt, ...); /* Output start of line line */
+void mline(fileo *f, char *fmt, ...); /* Output middle of line */
+void eline(fileo *f, char *fmt, ...); /* Output end of line */
+
+void cr(fileo *f) { line(f,""); } /* Output a blank line */
+
+void inc(fileo *f) { f->indt++; } /* Increment the indent level */
+
+void dec(fileo *f) { f->indt--; } /* Decrement the indent level */
+
+int
+main(void) {
+ fileo f[1];
+
+ f->of = fopen("ttt.c","w");
+ f->indt = 0;
+
+ line(f,"/* This is the top */");
+ cr(f);
+ line(f,"#include <stdio.h>");
+ cr(f);
+ line(f,"void main(void) {");
+ inc(f);
+ line(f,"int v0, v1, v2, v3, v4;");
+ line(f,"printf(\"Hi there!\\n\");");
+
+ line(f,"v0 = 1;");
+ line(f,"v1 = 9;");
+ line(f,"v2 = 3;");
+ line(f,"v3 = 2;");
+ line(f,"v4 = 0;");
+
+ /* ================ */
+ /* Sort development */
+ {
+int xx;
+ int i, j;
+
+ f->nv = 6; /* No variables */
+ f->sl = 1; /* Smallest to largest */
+ f->eq = 0; /* No equals case */
+ f->la = 0; /* No labels */
+ f->rl = 0; /* Top recursion level */
+ f->ln = 0; /* Start label number */
+ f->sd[f->rl].bot = f->eq ? 0 : 1;
+ f->sd[f->rl].dval = 256;
+ for (i = 0; i < f->nv; i++) {
+ f->sd[f->rl].vals[i] = -99999; /* Initial sort value = unknown */
+ f->sd[f->rl].sort[i] = i; /* Initial sort order */
+ }
+ f->sd[f->rl].vals[0] = 0; /* Make sure one is known */
+
+ /* First label is for no known sort */
+ if (f->la)
+ niline(f," label%d:;",f->ln++);
+
+ /* Until we have done every sort condition */
+ for (;f->rl >= 0;) {
+ int ix, nix; /* Variable index that needs comparison */
+ int six, snix; /* Sorted references to ix, nix */
+
+//printf("\n~~recursion level %d\n",f->rl);
+//for (i = 0; i < f->nv; i++) {
+//xx = f->sd[f->rl].sort[i];
+//printf("Current = %d (index %d)\n",f->sd[f->rl].vals[xx],xx);
+//}
+ /* see if we have resolved a sort */
+ for (i = 1; i < f->nv; i++) {
+ six = i-1;
+ ix = f->sd[f->rl].sort[i-1];
+ snix = i;
+ nix = f->sd[f->rl].sort[i];
+ if (f->sd[f->rl].vals[ix] == f->sd[f->rl].vals[nix]
+ || f->sd[f->rl].vals[nix] == -99999) {
+ break; /* Not distinguishable or not known */
+ }
+ }
+//if (i < f->nv)
+//printf("~~Unresolved sort indexes %d %d\n",ix,nix);
+//else
+//printf("~~Resolved sort\n");
+
+ if (i < f->nv) {
+ /* We haven't fully sorted the variables yet. */
+ /* Compare ix to nix */
+ if (f->sd[f->rl].bot == 0) {
+//printf("~~ Unresolved at level %d, doing comparison for equals\n",f->rl);
+ line(f,"if (v%d == v%d) {",ix,nix); /* } */
+ inc(f);
+ f->sd[f->rl+1] = f->sd[f->rl]; /* Structure copy */
+ f->sd[f->rl+1].bot = 0;
+ f->sd[f->rl].bot = 1;
+ f->rl++;
+// ~~~~~9
+ /* Find next lowest value from nix */
+ for (i = snix+1; i < f->nv; i++) {
+ int si = f->sd[f->rl].sort[i];
+ if (f->sd[f->rl].vals[si] == -99999)
+ continue;
+ if (f->sd[f->rl].vals[si] < f->sd[f->rl].vals[nix]) {
+ f->sd[f->rl].vals[nix] =
+ (f->sd[f->rl].vals[si] + f->sd[f->rl].vals[nix])/2;
+ break;
+ }
+ }
+ if (i >= f->nv) { /* Not between next lowest */
+ f->sd[f->rl].vals[nix] = f->sd[f->rl].vals[ix] -256;
+ }
+ } else if (f->sd[f->rl].bot == 1) { /* { */
+//printf("~~ Unresolved at level %d, doing comparison for greater\n",f->rl);
+ if (f->eq) {
+ dec(f);
+ line(f,"} else if (v%d %c v%d) {",ix, f->sl ? '<':'>',nix); /* } */
+ } else
+ line(f,"if (v%d %c v%d) {",ix,f->sl ? '<':'>', nix); /* } */
+ inc(f);
+ if (f->la)
+ niline(f," label%d:;",f->ln++);
+ f->sd[f->rl+1] = f->sd[f->rl]; /* Structure copy */
+ f->sd[f->rl+1].bot = f->eq ? 0 : 1;
+ f->sd[f->rl].bot = 2;
+ f->rl++;
+ /* Find next lowest value from nix */
+ for (i = snix+1; i < f->nv; i++) {
+ int si = f->sd[f->rl].sort[i];
+ if (f->sd[f->rl].vals[si] == -99999)
+ continue;
+ if (f->sd[f->rl].vals[si] < f->sd[f->rl].vals[nix]) {
+ f->sd[f->rl].vals[nix] =
+ (f->sd[f->rl].vals[si] + f->sd[f->rl].vals[nix])/2;
+ break;
+ }
+ }
+ if (i >= f->nv) { /* Not between next lowest */
+ f->sd[f->rl].vals[nix] = f->sd[f->rl].vals[ix] -256;
+ }
+ } else if (f->sd[f->rl].bot == 2) { /* { */
+//printf("~~ Unresolved at level %d, doing else\n",f->rl);
+ dec(f);
+ line(f,"} else { /* v%d %c v%d */",ix,f->sl ? '>':'<', nix); /* } */
+ inc(f);
+ if (f->la)
+ niline(f," label%d:;",f->ln++);
+ f->sd[f->rl+1] = f->sd[f->rl]; /* Structure copy */
+ f->sd[f->rl+1].bot = f->eq ? 0 : 1;
+ f->sd[f->rl].bot = 3;
+ f->rl++;
+ if (six-1 >= 0) { /* If there is a higher value */
+ int si = f->sd[f->rl].sort[six-1];
+ /* Make equal to next highest, since never been compared */
+ f->sd[f->rl].vals[nix] = f->sd[f->rl].vals[si];
+ } else { /* Nothing above */
+ f->sd[f->rl].vals[nix] = f->sd[f->rl].vals[ix] + 256;
+ }
+ /* sort nix above ix */
+ j = f->sd[f->rl].sort[six];
+ f->sd[f->rl].sort[six] = f->sd[f->rl].sort[snix];
+ f->sd[f->rl].sort[snix] = j;
+ } else { /* We've done both cases - return from recursion */
+//printf("~~ Unresolved at level %d, going up a level\n",f->rl);
+ dec(f); /* { */
+ line(f,"}");
+ f->rl--; /* Back a recursion level */
+ }
+ } else {
+//printf("~~ Resolved at level %d, outputing sort code, up a level\n",f->rl);
+ /* We have a resolved sort */
+ /* So output the code for this sort combination */
+ sline(f,"/* Sorted ");
+ for (i = 0; i < f->nv; i++) {
+ mline(f," %d",f->sd[f->rl].sort[i]);
+ }
+ eline(f," */");
+
+#ifdef NEVER
+ sline(f,"printf(\"Sorted = %%d %%d %%d %%d %%d\\n\"");
+ for (i = 0; i < f->nv; i++) {
+ mline(f,",v%d",f->sd[f->rl].sort[i]);
+ }
+ eline(f,");");
+#else
+ for (i = 0; i < f->nv; i++) {
+ sline(f,"");
+ mline(f,"op[%d] = v%d",i,f->sd[f->rl].sort[i]);
+ eline(f,";");
+ }
+ line(f,"ip += %d;",f->nv);
+ line(f,"op += %d;",f->nv);
+ line(f,"continue;");
+#endif
+ f->rl--; /* Back a recursion level */
+ }
+ }
+ }
+ /* ================ */
+ dec(f);
+ line(f,"}");
+
+ fclose(f->of);
+
+ return 0;
+}
+
+
+/* Output a line to the file (including trailing \n) */
+void
+line(fileo *f, char *fmt, ...)
+{
+ int i;
+ va_list args;
+
+ /* Indent to the correct level */
+ for (i = 0; i < f->indt; i++)
+ fprintf(f->of," ");
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+ fprintf(f->of, "\n");
+}
+
+/* Output a line to the file (including trailing \n) */
+/* No indent */
+void
+niline(fileo *f, char *fmt, ...)
+{
+ int i;
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+ fprintf(f->of, "\n");
+}
+
+/* Output the start of a line to the file) */
+void
+sline(fileo *f, char *fmt, ...)
+{
+ int i;
+ va_list args;
+
+ /* Indent to the correct level */
+ for (i = 0; i < f->indt; i++)
+ fprintf(f->of," ");
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+}
+
+/* Output the middle of a line to the file) */
+void
+mline(fileo *f, char *fmt, ...)
+{
+ int i;
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+}
+
+/* Output the end of a line to the file (including trailing \n) */
+void
+eline(fileo *f, char *fmt, ...)
+{
+ int i;
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(f->of, fmt, args);
+ va_end(args);
+ fprintf(f->of, "\n");
+}
+
diff --git a/install-sh b/install-sh
new file mode 100644
index 0000000..377bb86
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-11-20.07; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/install.bat b/install.bat
new file mode 100644
index 0000000..4c27fda
--- /dev/null
+++ b/install.bat
@@ -0,0 +1,5 @@
+echo Simple batch file to invoke Jam install from the top
+jam -q -fJambase -j%NUMBER_OF_PROCESSORS% install
+rem If you have trouble with the parallel build, try the
+rem version with only one thread.
+rem jam -q -fJambase install
diff --git a/jam.patch b/jam.patch
new file mode 100644
index 0000000..7133c90
--- /dev/null
+++ b/jam.patch
@@ -0,0 +1,74 @@
+--- jam.old.c 2008-03-14 12:15:01.000000000 +1100
++++ jam.c 2008-03-29 17:59:14.000000000 +1100
+@@ -99,6 +99,7 @@
+ * 09/19/02 (seiwald) - new -d displays
+ * 10/22/02 (seiwald) - list_new() now does its own newstr()/copystr()
+ * 11/04/02 (seiwald) - const-ing for string literals
++ * 03/14/08 (gwg) - Added JAMBASE enviroment variable
+ */
+
+ # include "jam.h"
+@@ -333,7 +334,13 @@
+ parse_file( s );
+
+ if( !n )
+- parse_file( "+" );
++ {
++ char *jambase;
++ if ((jambase = getenv("JAMBASE")) != NULL)
++ parse_file( jambase );
++ else
++ parse_file( "+" );
++ }
+
+ status = yyanyerrors();
+
+--- filent.old.c 2008-03-29 17:41:58.000000000 +1100
++++ filent.c 2008-03-31 01:28:06.000000000 +1100
+@@ -26,6 +26,7 @@
+ * 01/08/01 (seiwald) - closure param for file_dirscan/file_archscan
+ * 11/04/02 (seiwald) - const-ing for string literals
+ * 01/23/03 (seiwald) - long long handles for NT IA64
++ * 03/29/08 (gwg) - fix MingW long library names
+ */
+
+ # include "jam.h"
+@@ -186,6 +187,7 @@
+ {
+ struct ar_hdr ar_hdr;
+ char *string_table = 0;
++ long stable_size = 0;
+ char buf[ MAXJPATH ];
+ long offset;
+ int fd;
+@@ -229,6 +231,7 @@
+ string_table = malloc(lar_size);
+ if (read(fd, string_table, lar_size) != lar_size)
+ printf("error reading string table\n");
++ stable_size = lar_size;
+ offset += SARHDR + lar_size;
+ continue;
+ }
+@@ -237,10 +240,20 @@
+ /* Long filenames are recognized by "/nnnn" where nnnn is
+ ** the offset of the string in the string table represented
+ ** in ASCII decimals.
++ ** However, the name end with 0 or '/', depending on
++ ** the librarian used to generate them (0 for Mingw,
++ ** '/' for Visual C++)
+ */
+
+- name = string_table + atoi( ar_hdr.ar_name + 1 );
+- endname = name + strlen( name );
++ long off = atoi( ar_hdr.ar_name + 1 );
++ name = string_table + off;
++ for ( ; off < stable_size; off++ )
++ {
++ int c = string_table[off];
++ if ( c == 0 || c == '/' )
++ break;
++ }
++ endname = string_table + off;
+ }
+ else
+ {
diff --git a/jcnf/Jamfile b/jcnf/Jamfile
new file mode 100644
index 0000000..cc9df79
--- /dev/null
+++ b/jcnf/Jamfile
@@ -0,0 +1,32 @@
+
+# JAM style makefile for yajl
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags
+
+SubInclude yajl ;
+
+#Products
+Libraries = libjcnf ;
+Executables = ;
+Headers = jcnf.h ;
+
+#Install
+#InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+# config parser based on yajl
+Library libjcnf : jcnf.c ;
+
+# Link all utilities here with libicc
+LINKLIBS = libjcnf yajl/libyajl ../numlib/libnum ;
+
+# All utils are made from a single source file
+MainsFromSources test.c ;
+
+
+
+
diff --git a/jcnf/Makefile.am b/jcnf/Makefile.am
new file mode 100644
index 0000000..1914fce
--- /dev/null
+++ b/jcnf/Makefile.am
@@ -0,0 +1,15 @@
+include $(top_srcdir)/Makefile.shared
+
+SUBDIRS = $(YAJL_SUBDIRS)
+
+privatelib_LTLIBRARIES = libjcnf.la
+privatelibdir = $(pkglibdir)
+
+libjcnf_la_SOURCES = jcnf.h jcnf.c
+libjcnf_la_LIBADD = $(YAJL_LIBS)
+
+LDADD = ./libjcnf.la $(YAJL_LIBS)
+
+check_PROGRAMS = test
+
+EXTRA_DIST = Readme.txt
diff --git a/jcnf/Readme.txt b/jcnf/Readme.txt
new file mode 100644
index 0000000..295c026
--- /dev/null
+++ b/jcnf/Readme.txt
@@ -0,0 +1,22 @@
+
+This is a library supporting system and application configuration stored in
+a flat file format based on the JSON format.
+
+JSON (JavaScript Object Notation) is a lightweight data-interchange format.
+It is easy for humans to read and write. It is easy for machines to parse
+and generate. It is based on a subset of the JavaScript Programming Language,
+Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is
+completely language independent but uses conventions that are familiar to
+programmers of the C-family of languages, including C, C++, C#, Java, JavaScript,
+Perl, Python, and many others. These properties make JSON an ideal data-interchange
+language.
+
+The jcnf library is designed to be used stand alone by applications,
+or as a template for a back end to Elektra, as an alternative to other
+simple flat file formats such as .ini
+
+It makes use of Lloyd Hilaiel's YAJL to do the generation
+and parsing of the JSON configuration files.
+
+- Graeme Gill.
+
diff --git a/jcnf/afiles b/jcnf/afiles
new file mode 100644
index 0000000..39508fa
--- /dev/null
+++ b/jcnf/afiles
@@ -0,0 +1,7 @@
+Jamfile
+Readme.txt
+afiles
+jcnf.c
+jcnf.h
+test.c
+test.jcnf
diff --git a/jcnf/jcnf.c b/jcnf/jcnf.c
new file mode 100644
index 0000000..c2fd4cc
--- /dev/null
+++ b/jcnf/jcnf.c
@@ -0,0 +1,1248 @@
+
+/*
+ * JSON based configuration format class.
+ */
+
+/*************************************************************************
+ Copyright 2008 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+#define LOCK_RETRIES 5
+
+/* We convert JSON arrays to numerical sub paths on reading, */
+/* but they get converted back to maps on writing. */
+/* Paths are grouped under common paths on writing, */
+/* but aren't sorted. */
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef NT
+#include <sys/file.h>
+#endif
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "yajl/yajl_common.h"
+#include "yajl/yajl_gen.h"
+#include "yajl/yajl_parse.h"
+
+#include "jcnf.h"
+
+#define BUF_SIZE 2048
+
+/* - - - - - - - - - - - - - - - - */
+/* Utilities */
+
+/* Construct a string that represents the current key path */
+/* Return NULL on error (malloc fail) */
+/* Free the returned string when done */
+static char *cur_keypath(jcnf *p) {
+ char *ckey = NULL;
+ int i, len;
+
+ if (p->nrecd <= 0) {
+ return strdup("");
+ }
+ for (len = i = 0; i < p->nrecd; i++) {
+ if (p->recds[i].aix > -2) {
+ len += 3 + (int)log10((double)p->recds[p->nrecd-1].aix);
+ } else {
+ len += strlen(p->recds[i].key) + 1;
+ }
+ }
+
+ if ((ckey = malloc(len)) == NULL)
+ return NULL;
+
+ for (len = i = 0; i < p->nrecd; i++) {
+ int sl;
+
+ if (p->recds[i].aix > -2) {
+ char num[13];
+ sprintf(num, "%d",p->recds[i].aix);
+ sl = strlen(num);
+ memmove(ckey + len, num, sl);
+ } else {
+ sl = strlen(p->recds[i].key);
+ memmove(ckey + len, p->recds[i].key, sl);
+ }
+ len += sl;
+
+ if ((i+1) >= p->nrecd)
+ ckey[len] = '\000';
+ else
+ ckey[len] = '/';
+ len++;
+ }
+ return ckey;
+}
+
+/* Diagnostic - Print the value of a key */
+static jc_error jcnf_print_key(jcnf *p, int ix, FILE *fp) {
+ jc_key *kp;
+
+ if (ix < 0 || ix >= p->nkeys)
+ return jc_ix_oorange;
+
+ kp = p->keys[ix];
+
+ fprintf(fp,"Key '%s' has value",kp->key);
+
+ switch(kp->type) {
+ case jc_null: {
+ fprintf(fp," null");
+ break;
+ }
+ case jc_boolean: {
+ fprintf(fp," %s",*((int *)kp->data) ? "true" : "false");
+ break;
+ }
+ case jc_real: {
+ fprintf(fp," %lf",*((double *)kp->data));
+ break;
+ }
+ case jc_integer: {
+ fprintf(fp," %ld",*((long *)kp->data));
+ break;
+ }
+ case jc_string: {
+ fprintf(fp," '%s'",kp->data);
+ break;
+ }
+ default: {
+ fprintf(fp," unknown type %d",kp->type);
+ break;
+ }
+ }
+ if (kp->c_comment != NULL) {
+ fprintf(fp," C comment = '%s'",kp->c_comment);
+ }
+ if (kp->cpp_comment != NULL) {
+ fprintf(fp," C++ comment = '%s'",kp->cpp_comment);
+ }
+ fprintf(fp,"\n");
+ return jc_ok;
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Free keys contents */
+static void free_key_contents(jc_key *p) {
+ if (p->key != NULL) {
+ free(p->key);
+ p->key = NULL;
+ }
+ if (p->c_comment != NULL) {
+ free(p->c_comment);
+ p->c_comment = NULL;
+ }
+ if (p->cpp_comment != NULL) {
+ free(p->cpp_comment);
+ p->cpp_comment = NULL;
+ }
+ if (p->data != NULL) {
+ free(p->data);
+ p->data = NULL;
+ }
+ p->type = -1;
+}
+
+/* Free key and its contents */
+static void free_key(jc_key *p) {
+ free_key_contents(p);
+ free(p);
+}
+
+/* Set a keyvalues (internal) */
+/* All parameters are copied */
+/* return NZ on error */
+static jc_error jcnf_set_key_internal(
+ jcnf *p,
+ jc_key *kp, /* Pointer to key */
+ char *key, /* Key path name */
+ jc_type type,
+ void *data,
+ size_t dataSize, /* Data size (including string nul) */
+ char *comment /* C++ style comment */
+) {
+ free_key_contents(kp);
+
+ if ((kp->key = strdup(key)) == NULL)
+ return jc_malloc;
+ kp->type = type;
+
+ if (type != jc_null) {
+ if (type == jc_string && ((char *)data)[dataSize-1] != '\000')
+ return jc_string_not_terminated;
+ if ((kp->data = malloc(dataSize)) == NULL)
+ return jc_malloc;
+ kp->dataSize = dataSize;
+ memmove(kp->data, data, dataSize);
+ }
+
+ if (comment != NULL) {
+ if ((kp->cpp_comment = strdup(comment)) == NULL)
+ return jc_malloc;
+ }
+ return jc_ok;
+}
+
+/* Add a key value to the jcnf (internal) */
+/* All parameters are copied */
+/* return NZ on error */
+static jc_error jcnf_add_key_internal(
+ jcnf *p,
+ char *key, /* Key path name */
+ jc_type type,
+ void *data,
+ size_t dataSize, /* Data size (including string nul) */
+ char *comment
+) {
+ jc_error ev;
+ jc_key *kp;
+
+ if (key == NULL || (type != jc_null && (data == NULL || dataSize == 0)))
+ return jc_bad_addkey_params;
+
+ if (p->nkeys >= p->akeys) { /* Need more pointer space */
+ p->akeys = p->akeys ? 2 * p->akeys : 10;
+ if ((p->keys = realloc(p->keys, p->akeys * sizeof(jc_key*))) == NULL) {
+ return jc_malloc;
+ }
+ }
+ if ((kp = p->keys[p->nkeys] = calloc(1, sizeof(jc_key))) == NULL) {
+ return jc_malloc;
+ }
+ p->nkeys++;
+
+ if ((ev = jcnf_set_key_internal(p, kp, key, type, data, dataSize, comment)) != jc_ok)
+ return ev;
+ p->lk = kp;
+ return jc_ok;
+}
+
+/* Locate the index of the next key matching the key name, starting */
+/* at the given index. Update the index to the matching key. */
+/* Look for an exact match if exact != 0, or leading match if exact = 0 */
+/* Search backwards if bwd != 0 or forwards if bwd = 0 */
+/* Set *ix = -1 to begin search from the start/end for fwd/bwd. */
+/* Return jc_ix_oorange if no more match. */
+static jc_error jcnf_locate_key(
+ jcnf *p,
+ int *pix,
+ char *key,
+ int exact,
+ int bwd
+) {
+ int ix = *pix;
+ int sl;
+
+ if (ix == -1) {
+ if (bwd)
+ ix = p->nkeys-1;
+ else
+ ix = 0;
+ }
+
+ if (ix < 0 || ix >= p->nkeys)
+ return jc_ix_oorange;
+
+ if (key == NULL)
+ return jc_no_keyname;
+
+ sl = strlen(key);
+
+ /* We're doing a simple linear search */
+ for (; ix >= 0 && ix < p->nkeys; ix += bwd ? -1 : 1) {
+ if (exact) {
+ if (strcmp(key, p->keys[ix]->key) == 0)
+ break;
+ } else {
+ if (strncmp(key, p->keys[ix]->key, sl) == 0)
+ break;
+ }
+ }
+
+ if (ix < 0 || ix >= p->nkeys)
+ return jc_ix_oorange;
+
+ *pix = ix;
+ return jc_ok;
+}
+
+/* Retrieve a keys information. Return pointers may be NULL. */
+/* If ix >= 0, return the key of the given index. */
+/* If ix == -1, return the first from the beginning exactly matching key name. */
+/* jc_ix_oorange is returned when past end. */
+/* (Do not modify anything returned) */
+static jc_error jcnf_get_key(
+ jcnf *p,
+ int ix,
+ char **key,
+ jc_type *type,
+ unsigned char **data,
+ size_t *dataSize, /* Data size (including string nul) */
+ char **comment
+) {
+ jc_error ev;
+
+ if (ix == -1) {
+ if (key == NULL || *key == NULL)
+ return jc_no_keyname;
+ if ((ev = jcnf_locate_key(p, &ix, *key, 1, 0)) != jc_ok)
+ return ev;
+ } else if (ix < 0 || ix >= p->nkeys)
+ return jc_ix_oorange;
+
+ if (key != NULL)
+ *key = p->keys[ix]->key;
+ if (type != NULL)
+ *type = p->keys[ix]->type;
+ if (data != NULL)
+ *data = p->keys[ix]->data;
+ if (dataSize != NULL)
+ *dataSize = p->keys[ix]->dataSize;
+ if (comment != NULL)
+ *comment = p->keys[ix]->cpp_comment;
+
+ return jc_ok;
+}
+
+/* Set a keys information. */
+/* If ix >= 0, set the key of the given index. */
+/* jc_ix_oorange is returned when past end. */
+/* If ix == -1, overwrite an existing key with the same name, */
+/* or add a new key with that name at the end if there is no existing key. */
+static jc_error jcnf_set_key(
+ jcnf *p,
+ int ix,
+ char *key,
+ jc_type type,
+ unsigned char *data,
+ size_t dataSize, /* Data size (including string nul) */
+ char *comment
+) {
+ jc_error ev;
+
+ if (ix == -1) {
+ if (key == NULL)
+ return jc_no_keyname;
+ if ((ev = jcnf_locate_key(p, &ix, key, 1, 0)) != jc_ok) {
+ if (ev != jc_ix_oorange)
+ return ev;
+ if (p->modify == 0)
+ return jc_update_nomod;
+ p->modified = 1;
+ return jcnf_add_key_internal(p, key, type, data, dataSize, comment);
+ }
+ } else if (ix < 0 || ix >= p->nkeys)
+ return jc_ix_oorange;
+
+ if (p->modify == 0)
+ return jc_update_nomod;
+ p->modified = 1;
+ return jcnf_set_key_internal(p, p->keys[ix], key, type, data, dataSize, comment);
+}
+
+/* Add a key value to the jcnf at the end, irrespective of whether there is */
+/* an existing key with that name. */
+static jc_error jcnf_add_key(
+ jcnf *p,
+ char *key,
+ jc_type type,
+ unsigned char *data,
+ size_t dataSize, /* Data size (including string nul) */
+ char *comment
+) {
+ jc_error ev;
+ if (p->modify == 0)
+ return jc_update_nomod;
+ if ((ev = jcnf_add_key_internal(p,key,type,data,dataSize,comment)) == jc_ok) {
+ p->modified = 1;
+ }
+ return ev;
+}
+
+/* Delete a key. */
+/* If ix >= 0, delete the key of the given index. */
+/* jc_ix_oorange is returned when past end. */
+/* If ix == -1, delete the key with the given name. */
+static jc_error jcnf_delete_key(
+ jcnf *p,
+ int ix,
+ char *key
+) {
+ jc_error ev;
+
+ if (ix == -1) {
+ if (key == NULL)
+ return jc_no_keyname;
+ if ((ev = jcnf_locate_key(p, &ix, key, 1, 0)) != jc_ok)
+ return ev;
+ } else if (ix < 0 || ix >= p->nkeys)
+ return jc_ix_oorange;
+
+ if (p->modify == 0)
+ return jc_update_nomod;
+ free_key_contents(p->keys[ix]);
+
+ if ((ix+1) < p->nkeys) {
+ memmove(p->keys+ix, p->keys+ix+1,sizeof(jc_key *) * p->nkeys-ix-1);
+ }
+ p->nkeys--;
+ p->modified = 1;
+
+ return jc_ok;
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* yajl parser callbacks */
+
+static int jcnf_yajl_null(void *ctx) {
+ jcnf *p = (jcnf *)ctx;
+ char *t1;
+
+// printf("null\n");
+
+ /* If current level is an array, bump the index */
+ if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2)
+ p->recds[p->nrecd-1].aix++;
+ if ((t1 = cur_keypath(p)) == NULL)
+ return 0;
+
+ if (jcnf_add_key_internal(p, t1, jc_null, NULL, 0, NULL) != jc_ok) {
+ free(t1);
+ return 0;
+ }
+ free(t1);
+
+ return 1;
+}
+
+static int jcnf_yajl_boolean(void * ctx, int boolVal) {
+ jcnf *p = (jcnf *)ctx;
+ char *t1;
+
+// printf("bool: %s\n", boolVal ? "true" : "false");
+
+ /* If current level is an array, bump the index */
+ if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2)
+ p->recds[p->nrecd-1].aix++;
+ if ((t1 = cur_keypath(p)) == NULL)
+ return 0;
+
+ if (jcnf_add_key_internal(p, t1, jc_boolean, (void *)&boolVal, sizeof(int), NULL) != jc_ok) {
+ free(t1);
+ return 0;
+ }
+ free(t1);
+
+ return 1;
+}
+
+static int jcnf_yajl_integer(void *ctx, long integerVal) {
+ jcnf *p = (jcnf *)ctx;
+ char *t1;
+
+// printf("integer: %lld\n", integerVal);
+
+ /* If current level is an array, bump the index */
+ if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2)
+ p->recds[p->nrecd-1].aix++;
+ if ((t1 = cur_keypath(p)) == NULL)
+ return 0;
+
+ if (jcnf_add_key_internal(p, t1, jc_integer, (void *)&integerVal, sizeof(long), NULL) != jc_ok) {
+ free(t1);
+ return 0;
+ }
+ free(t1);
+
+ return 1;
+}
+
+static int jcnf_yajl_double(void *ctx, double doubleVal) {
+ jcnf *p = (jcnf *)ctx;
+ char *t1;
+
+// printf("double: %lf\n", doubleVal);
+
+ /* If current level is an array, bump the index */
+ if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2)
+ p->recds[p->nrecd-1].aix++;
+ if ((t1 = cur_keypath(p)) == NULL)
+ return 0;
+
+ if (jcnf_add_key_internal(p, t1, jc_real, (void *)&doubleVal, sizeof(double), NULL) != jc_ok) {
+ free(t1);
+ return 0;
+ }
+ free(t1);
+
+ return 1;
+}
+
+static int jcnf_yajl_string(void *ctx, const unsigned char *stringVal,
+ unsigned int stringLen) {
+ jcnf *p = (jcnf *)ctx;
+ char *t1, *t2;
+
+// printf("string: '");
+// fwrite(stringVal, 1, stringLen, stdout);
+// printf("'\n");
+
+ /* If current level is an array, bump the index */
+ if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2)
+ p->recds[p->nrecd-1].aix++;
+ if ((t1 = cur_keypath(p)) == NULL)
+ return 0;
+
+ if ((t2 = malloc(stringLen + 1)) == NULL) /* Room to add implicit nul */
+ return 0;
+ memmove(t2, stringVal, stringLen);
+ t2[stringLen] = 0;
+
+ if (jcnf_add_key_internal(p, t1, jc_string, (void *)t2, stringLen+1, NULL) != jc_ok) {
+ free(t2);
+ free(t1);
+ return 0;
+ }
+ free(t2);
+ free(t1);
+
+ return 1;
+}
+
+static int jcnf_yajl_c_comment(void *ctx, const unsigned char * stringVal,
+ unsigned int stringLen) {
+ jcnf *p = (jcnf *)ctx;
+
+// printf("c_comment: '");
+// fwrite(stringVal, 1, stringLen, stdout);
+// printf("'\n");
+
+ if (p->lk != NULL && p->lk->c_comment == NULL) {
+ char *t1;
+ if ((t1 = malloc(stringLen + 1)) == NULL)
+ return 0;
+ memmove(t1, stringVal, stringLen);
+ t1[stringLen] = 0;
+
+ p->lk->c_comment = t1;
+ }
+
+ return 1;
+}
+
+static int jcnf_yajl_cpp_comment(void *ctx, const unsigned char * stringVal,
+ unsigned int stringLen) {
+ jcnf *p = (jcnf *)ctx;
+
+// printf("cpp_comment: '");
+// fwrite(stringVal, 1, stringLen, stdout);
+// printf("'\n");
+
+ if (p->lk != NULL && p->lk->cpp_comment == NULL) {
+ char *t1;
+ if ((t1 = malloc(stringLen + 1)) == NULL)
+ return 0;
+ memmove(t1, stringVal, stringLen);
+ t1[stringLen] = 0;
+
+ p->lk->cpp_comment = t1;
+ }
+
+ return 1;
+}
+
+static int jcnf_yajl_start_map(void *ctx) {
+ jcnf *p = (jcnf *)ctx;
+
+ /* Start another recursion level */
+ if (p->nrecd >= p->arecd) {
+ p->arecd *= 2;
+ if ((p->recds = (jc_recd *)realloc(p->recds, p->arecd * sizeof(jc_recd))) == NULL) {
+ /* realloc failed */
+ return 0;
+ }
+ }
+
+ /* If current level is an array, bump the index */
+ if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2)
+ p->recds[p->nrecd-1].aix++;
+
+ /* Move to new level */
+ p->recds[p->nrecd].key = NULL;
+ p->recds[p->nrecd].aix = -2;
+ p->nrecd++;
+
+#ifdef NEVER
+ printf("map open '{'\n");
+#endif
+
+ return 1;
+}
+
+static int jcnf_yajl_map_key(void *ctx, const unsigned char * stringVal,
+ unsigned int stringLen) {
+ jcnf *p = (jcnf *)ctx;
+ int i;
+
+ if (stringLen == 0) {
+ /* Zero length key */
+ return 0;
+ }
+
+ if (p->recds[p->nrecd-1].key != NULL) {
+ free(p->recds[p->nrecd-1].key);
+ p->recds[p->nrecd-1].key = NULL;
+ p->recds[p->nrecd-1].aix = -2;
+ }
+ if ((p->recds[p->nrecd-1].key = malloc(stringLen + 1)) == NULL)
+ return 0;
+
+ p->recds[p->nrecd-1].key[stringLen] = 0;
+ memmove(p->recds[p->nrecd-1].key, stringVal, stringLen);
+
+#ifdef NEVER
+ {
+ char *tt;
+
+ printf("Added path = '%s'\n", p->recds[p->nrecd-1].key);
+ if ((tt = cur_keypath(p)) != NULL) {
+ printf("Current path = '%s'\n",tt);
+ free(tt);
+ }
+ }
+#endif
+
+ return 1;
+}
+
+static int jcnf_yajl_end_map(void *ctx) {
+ jcnf *p = (jcnf *)ctx;
+
+ if (p->nrecd == 0) {
+ /* End of map without start of map */
+ return 0;
+ }
+ p->nrecd--;
+
+#ifdef NEVER
+ {
+ char *tt;
+ printf("map close '}'\n");
+ if ((tt = cur_keypath(p)) != NULL)
+ printf("Current path = '%s'\n",tt);
+ free(tt);
+ }
+#endif
+
+ return 1;
+}
+
+static int jcnf_yajl_start_array(void *ctx) {
+ jcnf *p = (jcnf *)ctx;
+
+#ifdef NEVER
+ printf("array open '['\n");
+#endif
+
+ /* Start another recursion level */
+ if (p->nrecd >= p->arecd) {
+ p->arecd *= 2;
+ if ((p->recds = (jc_recd *)realloc(p->recds, p->arecd * sizeof(jc_recd))) == NULL) {
+ /* realloc failed */
+ return 0;
+ }
+ }
+
+ /* If current level is an array, bump the index */
+ if (p->nrecd > 0 && p->recds[p->nrecd-1].aix > -2)
+ p->recds[p->nrecd-1].aix++;
+
+ /* Move to new level */
+ p->recds[p->nrecd].key = NULL;
+ p->recds[p->nrecd].aix = -1;
+ p->nrecd++;
+
+ return 1;
+}
+
+static int jcnf_yajl_end_array(void *ctx) {
+ jcnf *p = (jcnf *)ctx;
+
+#ifdef NEVER
+ printf("array close ']'\n");
+#endif
+ if (p->nrecd == 0) {
+ /* End of map without start of map */
+ return 0;
+ }
+ p->nrecd--;
+
+ return 1;
+}
+
+static yajl_callbacks callbacks = {
+ jcnf_yajl_null,
+ jcnf_yajl_boolean,
+ jcnf_yajl_integer,
+ jcnf_yajl_double,
+ NULL, /* number */
+ jcnf_yajl_string,
+ jcnf_yajl_c_comment,
+ jcnf_yajl_cpp_comment,
+ jcnf_yajl_start_map,
+ jcnf_yajl_map_key,
+ jcnf_yajl_end_map,
+ jcnf_yajl_start_array,
+ jcnf_yajl_end_array
+};
+
+/* - - - - - - - - - - - - - - - - */
+/* Lock the open fp */
+static jc_error jcnf_lock_file(jcnf *p) {
+#ifndef NT
+ int i, fh;
+ int lop;
+
+ fh = fileno(p->fp);
+
+ if (p->modify) {
+ lop = LOCK_EX | LOCK_NB;
+ } else {
+ lop = LOCK_SH | LOCK_NB;
+ }
+
+ for (i = 0; i < LOCK_RETRIES; i++) {
+ if (flock(fh, lop) == 0)
+ break;
+ sleep(1);
+ }
+ if (i >= LOCK_RETRIES)
+ return jc_locked;
+#endif
+ p->locked = 1;
+
+ return jc_ok;
+}
+
+/* Read a file into the object. */
+/* (Doesn't do locking) */
+/* Return NZ on error */
+static jc_error jcnf_read(
+ jcnf *p
+) {
+ jc_error ev;
+ yajl_handle hand;
+ yajl_parser_config cfg = { 0, 1 }; /* Validate UTF8 strings ? */
+ unsigned char buf[BUF_SIZE];
+ struct stat sbuf;
+
+ cfg.allowComments = 1;
+
+ if ((p->fp = fopen(p->fname, p->modify ? "r+" : "r")) == NULL) {
+ if (!p->modify)
+ return jc_noexisting;
+
+ if ((p->fp = fopen(p->fname, "w")) == NULL)
+ return jc_write_open;
+ if ((ev = jcnf_lock_file(p)) != jc_ok)
+ return ev;
+ return jc_ok;
+ }
+
+ if ((ev = jcnf_lock_file(p)) != jc_ok)
+ return ev;
+
+ hand = yajl_alloc(&callbacks, &cfg, NULL, (void *)p);
+
+ /* Parse the file */
+ for(;;) {
+ size_t rd;
+
+ rd = fread(buf, 1, BUF_SIZE, p->fp);
+
+ if (rd == 0) {
+ if (!feof(p->fp)) {
+ fprintf(stderr, "error reading from '%s'\n", p->fname);
+ return jc_read_fail;
+ }
+ break;
+ } else {
+ yajl_status stat;
+
+ /* read file data, pass to parser */
+ stat = yajl_parse(hand, buf, rd);
+ if (stat != yajl_status_insufficient_data &&
+ stat != yajl_status_ok)
+ {
+ unsigned char * str = yajl_get_error(hand, 1, buf, rd);
+ fflush(stdout);
+ fprintf(stderr, "%s", (char *) str);
+ yajl_free_error(hand, str);
+ return jc_parse_fail;
+ }
+ }
+ }
+
+ /* Record some things about the file so that we can */
+ /* recognized if it's been modified */
+ if (stat(p->fname, &sbuf) != 0) {
+ return jc_stat;
+ }
+ p->rsize = sbuf.st_size;
+ p->rtime = time(NULL);
+
+ yajl_free(hand);
+
+ /* We're not modifying it, so close it */
+ if (!p->modify) {
+ fclose(p->fp);
+ p->fp = NULL;
+ p->locked = 0;
+ }
+
+ return jc_ok;
+}
+
+/* Write an object into a file */
+/* Unlock it & close it afterwards. */
+/* Return NZ on error */
+static jc_error jcnf_write(
+ jcnf *p
+) {
+ FILE *fp; /* For temporary file */
+ char *tname = NULL;
+ yajl_gen_config conf = { 1, " " };
+ yajl_gen g;
+ yajl_status stat;
+ const unsigned char * buf;
+ unsigned int len;
+ int clevel = 0; /* Current level */
+ char *pkey = ""; /* Previous key */
+ char *ckey; /* Current key */
+ int i;
+
+ if (!p->locked && p->fp != NULL) {
+ return jc_update_nomod;
+ }
+
+#ifndef NT
+ {
+ int fh;
+
+ if ((tname = malloc(strlen(p->fname) + 8)) == NULL)
+ return jc_malloc;
+
+ /* Create temporary file, open it and lock it LOCK_EX */
+ strcpy(tname, p->fname);
+ strcat(tname,"-XXXXXX");
+ if ((fh = mkstemp(tname)) == -1) {
+ free(tname);
+ return jc_write_open;
+ }
+ if (fchmod(fh, 0644) != 0) {
+ free(tname);
+ return jc_write_open;
+ }
+ if ((fp = fdopen(fh, "w")) == NULL) {
+ free(tname);
+ return jc_write_open;
+ }
+ }
+#else
+ /* Open a temporary file in the same directory to write to */
+ if ((tname = malloc(strlen(p->fname) + 8)) == NULL)
+ return jc_malloc;
+
+ if (tmpnam(tname) == NULL) {
+ free(tname);
+ return jc_write_open;
+ }
+ if ((fp = fopen(tname, "w")) == NULL) {
+ free(tname);
+ return jc_write_open;
+ }
+#endif
+
+ g = yajl_gen_alloc(&conf, NULL);
+
+ /* Generate the file */
+ for (i = 0; i < p->nkeys; i++, pkey = ckey) {
+ char *pc, *cc, *dc;
+ int nplev; /* Number of previous different levels */
+ int ndlev; /* Number of new different levels */
+ int same;
+
+ ckey = p->keys[i]->key;
+
+ /* See how many keys are not in common */
+ nplev = ndlev = 0;
+ same = 1;
+ for(pc = pkey, dc = cc = ckey; *pc != '\000' || *cc != '\000';) {
+
+//printf("~1 pc = '%c', cc = '%c', same = %d\n",*pc,*cc,same);
+ if (same == 0 || *pc != *cc) {
+ same = 0;
+ if (*cc == '/') {
+ ndlev++;
+//printf("~1 ndlev now %d\n",ndlev);
+ }
+ if (*pc == '/') {
+ nplev++;
+//printf("~1 ndlev now %d\n",ndlev);
+ }
+
+ } else {
+ if (*cc == '/') {
+ dc = cc+1;
+ }
+ }
+ if (*pc != '\000') {
+ pc++;
+ if (same == 0 && *pc == '\000') {
+ nplev++;
+//printf("~1 nplev now %d\n",nplev);
+ }
+ }
+ if (*cc != '\000') {
+ cc++;
+ if (same == 0 && *cc == '\000') {
+ ndlev++;
+//printf("~1 ndlev now %d\n",ndlev);
+ }
+ }
+ }
+//printf("~1 Prev = '%s'\n",pkey);
+//printf("~1 Curr = '%s'\n",ckey);
+//printf("~1 New = '%s'\n",dc);
+//printf("~1 Old different = %d, new different = %d\n\n",nplev,ndlev);
+
+ while(nplev > 0) {
+ if (nplev > 1)
+ yajl_gen_map_close(g);
+ nplev--;
+ clevel--;
+ }
+ while(ndlev > 0) {
+ yajl_gen_map_open(g);
+ for (cc = dc; *cc != '\000' && *cc != '/'; cc++)
+ ;
+ yajl_gen_string(g, dc, cc-dc);
+ if (*cc != '\000')
+ dc = cc + 1;
+ ndlev--;
+ clevel++;
+ }
+
+ switch(p->keys[i]->type) {
+//printf("~1 key %d = type %d\n",i,p->keys[i]->type);
+ case jc_null:
+ yajl_gen_null(g);
+ break;
+
+ case jc_boolean:
+ yajl_gen_bool(g, *((int *)p->keys[i]->data));
+ break;
+
+ case jc_real:
+ yajl_gen_double(g, *((double *)p->keys[i]->data));
+ break;
+
+ case jc_integer:
+ yajl_gen_integer(g, *((long *)p->keys[i]->data));
+ break;
+
+ case jc_string:
+ yajl_gen_string(g, (char *)p->keys[i]->data, p->keys[i]->dataSize-1);
+ break;
+
+ default: {
+ free(tname);
+ return jc_unknown_key_type;
+ }
+ }
+
+ if (p->keys[i]->cpp_comment != NULL) {
+ yajl_gen_cpp_comment(g, p->keys[i]->cpp_comment, strlen(p->keys[i]->cpp_comment));
+ }
+ if (p->keys[i]->c_comment != NULL) {
+ yajl_gen_c_comment(g, p->keys[i]->c_comment, strlen(p->keys[i]->c_comment), 1);
+ }
+
+#ifdef NEVER
+ yajl_gen_map_open(g);
+ yajl_gen_string(g, "test", strlen("test"));
+ yajl_gen_string(g, "test value", strlen("test value"));
+ yajl_gen_c_comment(g, " A comment ", strlen(" A comment "));
+ yajl_gen_map_close(g);
+#endif
+
+ /* Do some writing */
+ yajl_gen_get_buf(g, &buf, &len);
+ if (len >= BUF_SIZE) {
+ if (fwrite(buf, 1, len, fp) != len)
+ return jc_write_fail;
+ yajl_gen_clear(g);
+ }
+ }
+
+ while(clevel > 0) {
+ yajl_gen_map_close(g);
+ clevel--;
+ }
+
+ yajl_gen_get_buf(g, &buf, &len);
+ if (len > 0) {
+ if (fwrite(buf, 1, len, fp) != len)
+ return jc_write_fail;
+ yajl_gen_clear(g);
+ }
+ yajl_gen_free(g);
+ if (fflush(fp) != 0) {
+ free(tname);
+ return jc_write_close;
+ }
+
+#ifdef NT
+ /* MSWindows rename won't replace existing or open files. */
+ /* Lucky this is just for testing, as this leaves a window */
+ if (fp != NULL) {
+ fclose(fp);
+ fp = NULL;
+ }
+ if (p->fp != NULL) {
+ fclose(p->fp);
+ p->fp = NULL;
+ }
+ unlink(p->fname);
+#endif
+
+//printf("~1 about to rename '%s' to '%s'\n",tname,p->fname);
+ /* Now atomicaly rename the file to replace the file we read */
+ if (rename(tname, p->fname) != 0) {
+ free(tname);
+ return jc_write_close;
+ }
+
+//printf("~1 closing files\n");
+ /* Close our files and release the locks */
+ if (fp != NULL && fclose(fp) != 0) {
+ free(tname);
+ return jc_write_close;
+ }
+ if (p->fp != NULL && fclose(p->fp) != 0) {
+ free(tname);
+ return jc_write_close;
+ }
+ p->fp = NULL;
+ p->locked = 0;
+ p->modify = 0;
+
+ free(tname);
+ return jc_ok;
+}
+
+/* Switch from read only to update of the config. */
+static jc_error jcnf_enable_modify(jcnf *p) {
+ jc_error ev;
+ struct stat sbuf;
+
+ if (p->modify)
+ return jc_ok; /* Nothing to do */
+
+ /* We need to re-open the file and lock it for modification */
+ if ((p->fp = fopen(p->fname, "r+")) == NULL) {
+ return jc_changed;
+ }
+ p->modify = 1;
+
+ if ((ev = jcnf_lock_file(p)) != jc_ok) {
+ p->modify = 0;
+ fclose(p->fp);
+ p->fp = NULL;
+ return ev;
+ }
+
+ /* Check that it hasn't been modified since it was first read */
+ if (stat(p->fname, &sbuf) != 0) {
+ p->modify = 0;
+ fclose(p->fp);
+ p->fp = NULL;
+ return jc_stat;
+ }
+
+ if (sbuf.st_size != p->rsize
+ || sbuf.st_mtime > p->rtime) {
+ p->modify = 0;
+ fclose(p->fp);
+ p->fp = NULL;
+ return jc_changed;
+ }
+
+ return jc_ok;
+}
+
+
+/* Update the file that was opened for modification, and unlock it. */
+static jc_error jcnf_update(jcnf *p) {
+ jc_error ev;
+ struct stat sbuf;
+
+ if (p->modified) {
+ if (p->modify == 0 || p->locked == 0) {
+
+ return jc_update_nomod; /* File wasn't opened for modification */
+ }
+ if ((ev = jcnf_write(p)) != jc_ok) {
+ return ev;
+ }
+ p->modified = 0;
+ }
+ p->modify = 0;
+
+ return jc_ok;
+}
+
+/* free the object */
+static void jcnf_del(jcnf *p) {
+
+ if (p->fp)
+ fclose(p->fp);
+
+ if (p->keys != NULL) {
+ int i;
+ for (i = 0; i < p->nkeys; i++) {
+ free_key(p->keys[i]);
+ }
+ free(p->keys);
+ }
+
+ if (p->recds != NULL) {
+ int i;
+ for (i = 0; i < p->nrecd; i++) {
+ free(p->recds[i].key);
+ }
+ free(p->recds);
+ }
+
+ if (p->fname)
+ free(p->fname);
+
+ free(p);
+}
+
+/* Create a new jconf. */
+/* Return NULL on error */
+jcnf *new_jcnf(
+ jc_error *pev, /* return error code on error */
+ char *fname, /* Corresponding filename */
+ jc_mod modify, /* Flag, nz to open for modification */
+ jc_crte create /* Flag, nz to create if it doesn't exist (modify must be set) */
+) {
+ jcnf *p;
+ jc_error ev;
+
+ if ((p = (jcnf *) calloc(1, sizeof(jcnf))) == NULL) {
+ if (pev != NULL) *pev = jc_malloc;
+ return NULL;
+ }
+
+ p->arecd = 10;
+ if ((p->recds = (jc_recd *) calloc(p->arecd, sizeof(jc_recd))) == NULL) {
+ if (pev != NULL) *pev = jc_malloc;
+ p->del(p);
+ return NULL;
+ }
+
+ if ((p->fname = strdup(fname)) == NULL) {
+ if (pev != NULL) *pev = jc_malloc;
+ p->del(p);
+ return NULL;
+ }
+
+ p->modify = modify == jc_modify ? 1 : 0;
+ p->create = create == jc_create ? 1 : 0;
+
+ p->locate_key = jcnf_locate_key;
+ p->get_key = jcnf_get_key;
+ p->set_key = jcnf_set_key;
+ p->add_key = jcnf_add_key;
+ p->delete_key = jcnf_delete_key;
+ p->print_key = jcnf_print_key;
+
+ p->enable_modify = jcnf_enable_modify;
+ p->update = jcnf_update;
+ p->del = jcnf_del;
+
+ if ((ev = jcnf_read(p)) != jc_ok) {
+ if (ev != jc_noexisting) {
+ if (pev != NULL) *pev = ev;
+ p->del(p);
+ return NULL;
+ }
+ }
+
+ if (pev != NULL) *pev = jc_ok;
+
+ return p;
+}
+
+/* ------------------------------- */
+/* Return a pointer to the nth element of the key name. */
+/* Return null if it is out of range or malloc failed. */
+/* Free the returned value when done. */
+char *jc_get_nth_elem(char *path, int n) {
+ int i;
+ char *p1, *p2, *rv;
+
+ if (path == NULL)
+ return NULL;
+
+ p1 = path;
+ if (*p1 == '/')
+ p1++;
+
+ for (i = 0; *p1 != '\000'; p1 = p2 + 1, i++) {
+ if ((p2 = strchr(p1, '/')) == NULL)
+ p2 = p1 + strlen(p1);
+ if (i >= n) {
+ if ((rv = malloc(p2 - p1 + 1)) == NULL)
+ return NULL;
+ strncpy(rv, p1, p2 - p1);
+ rv[p2-p1] = '\000';
+ return rv;
+ }
+ if (*p2 == '\000')
+ break;
+ }
+ return NULL;
+}
+
+
diff --git a/jcnf/jcnf.h b/jcnf/jcnf.h
new file mode 100644
index 0000000..d861d3d
--- /dev/null
+++ b/jcnf/jcnf.h
@@ -0,0 +1,199 @@
+
+#ifndef JCONF_H
+#define JCONF_H
+
+/*
+ * JSON based configuration format class.
+ */
+
+/*************************************************************************
+ Copyright 2008 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+
+/* General description:
+
+ Key names are UNIX style '/' separated paths, stored
+ in UTF8 format. The paths should not start with a '/'.
+
+ Duplicate key names are supported, but typically
+ will be avoided by the library user.
+
+ Five types are supported, NULL, 32 bit boolean, 64 bit real,
+ 64 bit integer and string. Strings are always nul terminated.
+
+ */
+
+/* jcnf error codes */
+typedef enum {
+ jc_ok = 0, /* No error */
+ jc_malloc, /* malloc, calloc or realloc failed */
+ jc_lock_error, /* Error opening lock file */
+ jc_locked, /* File is locked by someone else */
+ jc_unlock, /* Unlock failed */
+ jc_noexisting, /* No existing file to read */
+ jc_stat, /* Unable to stat file */
+ jc_changed, /* File has changed since it was read */
+ jc_read_fail, /* Failure to read from the file */
+ jc_parse_fail, /* Failure to parse from the file */
+ jc_write_open, /* Failed to open file for writing */
+ jc_write_fail, /* Failed to write to file */
+ jc_write_close, /* Failed to close file after writing */
+ jc_update_nomod, /* Attempt to update file that wasn't opened for modifications */
+ jc_bad_addkey_params, /* Bad add_key() parameters */
+ jc_unknown_key_type, /* An unrecognisd key type was encountered */
+ jc_ix_oorange, /* Key index is out of range */
+ jc_no_keyname, /* No key name provided when it is expected */
+ jc_string_not_terminated /* String doesn't include nul */
+} jc_error;
+
+/* Argument types */
+typedef enum {
+ jc_read = 0, /* Just read the config file */
+ jc_modify = 1 /* Read the config file in preparation to write it */
+} jc_mod;
+
+typedef enum {
+ jc_no_create = 0, /* Don't create the config if it doesn't exist */
+ jc_create = 1 /* Create the config if it doesn't exist */
+} jc_crte;
+
+/* Internal jcnf structure */
+
+/* The different type of values supported */
+typedef enum {
+ jc_null = 0, /* Null value */
+ jc_boolean = 1, /* Boolean */
+ jc_real = 2, /* double floating point */
+ jc_integer = 3, /* 64 bit integer */
+ jc_string = 4 /* UTF8 string, nul terminated */
+} jc_type;
+
+/* A value */
+struct _jc_key {
+ char *key; /* Key path */
+ jc_type type; /* Type of value */
+ char *c_comment; /* C Comment */
+ char *cpp_comment; /* C++ Comment */
+ unsigned char *data; /* Pointer to data */
+ size_t dataSize; /* Size of data */
+}; typedef struct _jc_key jc_key;
+
+/* A recursion depth record used during parsing */
+struct _jc_recd {
+ char *key; /* Key name, or */
+ int aix; /* Array index, -2 = no array */
+}; typedef struct _jc_recd jc_recd;
+
+/* jcnf Object, representing the keys in a jcnf file */
+struct _jcnf {
+ jc_key **keys; /* Array of pointers to keys */
+ int nkeys; /* Number of valid key pointers */
+ int akeys; /* Number of allocated key poiters */
+ jc_key *lk; /* Last key created */
+
+ /* Parsing support, key recursion depth */
+ jc_recd *recds;
+ int nrecd; /* Number of ised recd */
+ int arecd; /* Allocate rec depth */
+
+ /* Config & status */
+ char *fname; /* filename */
+ FILE *fp; /* opened, locked file */
+ off_t rsize; /* Size of file when read */
+ time_t rtime; /* Time the file was read */
+ int modify; /* Opened for modifications */
+ int create; /* Create if it doesn't exist */
+ int locked; /* nz if file is locked */
+ int modified; /* nz if keys have been modified */
+
+ /* Locate the index of the next key matching the key name, starting */
+ /* at the given index. Update the index to the matching key. */
+ /* Look for an exact match if exact != 0, or leading match if exact = 0 */
+ /* Search backwards if bwd != 0 or forwards if bwd = 0 */
+ /* Set *ix = -1 to begin search from the end. */
+ /* Return jc_ix_oorange if no more matchs. */
+ jc_error (*locate_key)(struct _jcnf *p, int *ix, char *key, int exact, int bwd);
+
+ /* Retrieve a keys information. Return pointers may be NULL. */
+ /* If ix >= 0, return the key of the given index. */
+ /* jc_ix_oorange is returned when past end. */
+ /* If ix == -1, return the first from the beginning matching key name. */
+ /* (Returned data is internal to jcnf object, so call must copy it). */
+ jc_error (*get_key)(struct _jcnf *p, int ix, char **key, jc_type *type, unsigned char **data,
+ size_t *dataSize, char **comment);
+
+ /* Set a keys information. */
+ /* If ix >= 0, set the key of the given index. */
+ /* jc_ix_oorange is returned when past end. */
+ /* If ix == -1, overwrite an existing key with the same name, */
+ /* or add a new key with that name at the end if there is no existing key. */
+ jc_error (*set_key)(struct _jcnf *p, int ix, char *key, jc_type type, unsigned char *data,
+ size_t dataSize, char *comment);
+
+ /* Add a key value to the jcnf at the end, irrespective of whether there is */
+ /* an existing key with that name. */
+ jc_error (*add_key)(struct _jcnf *p, char *key, jc_type type, unsigned char *data,
+ size_t dataSize, char *comment);
+
+ /* Delete a key. */
+ /* If ix >= 0, delete the key of the given index. */
+ /* jc_ix_oorange is returned when past end. */
+ /* If ix == -1, delete the key with the given name. */
+ jc_error (*delete_key)(struct _jcnf *p, int ix, char *key);
+
+ /* Diagnostic - Print the value of a key */
+ jc_error (*print_key)(struct _jcnf *p, int ix, FILE *fp);
+
+ /* Switch from read only to update of the config file. */
+ /* (This re-opens the file and checks that it hasn't been */
+ /* modified since it was read) */
+ jc_error (*enable_modify)(struct _jcnf *p);
+
+ /* Save and changes out to the file, unlock it and and close it. */
+ /* It can't be udated again after this. */
+ jc_error (*update)(struct _jcnf *p);
+
+ /* Delete this object */
+ void (*del)(struct _jcnf *p);
+
+}; typedef struct _jcnf jcnf;
+
+/* Create a new jcnf and read it's keys from the file. */
+/* Return NULL on error */
+jcnf *new_jcnf(
+ jc_error *pev, /* return error code on error */
+ char *fname, /* Corresponding filename */
+ jc_mod modify, /* Flag, nz to open for modification */
+ jc_crte create /* Flag, nz to create if it doesn't exist (modify must be set) */
+);
+
+/* Utilities */
+
+/* Return a pointer to the nth element of the key name. */
+/* Return null if it is out of range or malloc failed. */
+/* Free the returned value when done. */
+char *jc_get_nth_elem(char *path, int n);
+
+#endif /* JCNF_H */
+
+
diff --git a/jcnf/test.c b/jcnf/test.c
new file mode 100644
index 0000000..ddf4f5b
--- /dev/null
+++ b/jcnf/test.c
@@ -0,0 +1,161 @@
+
+
+/* Test out the jcnf object */
+
+/* Reads the file test.jcnf, and copies it to testo.jcnf */
+
+/*************************************************************************
+ Copyright 2008 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "jcnf.h"
+
+#undef TEST_PATH_PARSING
+#define TEST_ENABLE_MODIFY
+
+void error(char *fmt, ...);
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+
+ jcnf *jci, *jco;
+ jc_error ev;
+ int ix;
+
+ printf("Hi there\n");
+
+#ifdef TEST_PATH_PARSING
+ {
+ char *str;
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ if (i == 0)
+ str = "this/is/a/test";
+ else if (i == 1)
+ str = "/this/is/another//test/";
+ else if (i == 2)
+ str = "/";
+ else
+ str = "";
+
+ printf("String = '%s'\n",str);
+ for (j = 0; j < 10; j++) {
+ char *s;
+
+ s = jc_get_nth_elem(str, j);
+ if (s == NULL)
+ break;
+ printf("%d th element = '%s'\n",j,s);
+ free(s);
+ }
+ }
+ return 0;
+ }
+#endif /* TEST_PATH_PARSING */
+
+ if ((jci = new_jcnf(&ev, "test.jcnf",jc_read,jc_no_create)) == NULL) {
+ error("new_jcnf '%s' failed with error %d\n","test.jcnf",ev);
+ }
+
+#ifdef TEST_ENABLE_MODIFY
+ if ((jco = new_jcnf(&ev, "testo.jcnf",jc_read,jc_no_create)) == NULL) {
+ jci->del(jci);
+ error("new_jcnf '%s' failed with error %d\n","testo.jcnf",ev);
+ }
+ printf("Read output file, hit return to continue\n");
+ getchar();
+ if ((ev = jco->enable_modify(jco)) != jc_ok) {
+ jci->del(jci);
+ error("enable_modify '%s' failed with error %d\n","testo.jcnf",ev);
+ }
+#else
+ if ((jco = new_jcnf(&ev, "testo.jcnf",jc_modify,jc_create)) == NULL) {
+ jci->del(jci);
+ error("new_jcnf '%s' failed with error %d\n","testo.jcnf",ev);
+ }
+#endif
+
+ /* Delete everything from the second file */
+ for (ix = jco->nkeys-1; ix >= 0; ix--) {
+ if ((ev = jco->delete_key(jco, ix, NULL)) != jc_ok) {
+ jco->del(jco);
+ jci->del(jci);
+ error("deleting keys from '%s' failed with error %d\n","testo.jcnf",ev);
+ }
+ }
+
+ for (ix = 0; ; ix++) {
+ char *key;
+ jc_type type;
+ unsigned char *data;
+ size_t dataSize;
+ char *comment;
+
+ if ((ev = jci->get_key(jci, ix, &key, &type, &data, &dataSize, &comment)) != jc_ok) {
+ if (ev != jc_ix_oorange) {
+ jco->del(jco);
+ jci->del(jci);
+ error("get_key failed with %d\n",ev);
+ }
+ break;
+ }
+ jci->print_key(jci,ix, stderr);
+ if ((ev = jci->add_key(jco, key, type, data, dataSize, comment)) != jc_ok) {
+ jco->del(jco);
+ jci->del(jci);
+ error("add_key failed with %d\n",ev);
+ }
+ }
+ if ((ev = jco->update(jco)) != 0) {
+ jco->del(jco);
+ jci->del(jci);
+ error("jcnf write failed with error %d\n",ev);
+ }
+
+ jci->del(jci);
+ jco->del(jco);
+
+ printf("We're done\n");
+ return 0;
+}
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"test: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
diff --git a/jcnf/test.jcnf b/jcnf/test.jcnf
new file mode 100644
index 0000000..d37b286
--- /dev/null
+++ b/jcnf/test.jcnf
@@ -0,0 +1,33 @@
+
+{ "store": { /* First comment */
+ "book": [
+ { "category": "reference", /* Another comment */
+ "author": "Nigel Rees", /* A third comment */
+ "title": "Sayings of the Century",
+ "price": 8.95
+ },
+ { "category": "fiction",
+ "author": "Evelyn Waugh",
+ "title": "Sword of Honour",
+ "price": 12.99
+ },
+ { "category": "fiction",
+ "author": "Herman Melville",
+ "title": "Moby Dick",
+ "isbn": "0-553-21311-3",
+ "price": 8.99
+ },
+ { "category": "fiction",
+ "author": "J. R. R. Tolkien",
+ "title": "The Lord of the Rings",
+ "isbn": "0-395-19395-8",
+ "price": 22.99
+ }
+ ],
+ "bicycle": {
+ "color": "red",
+ "price": 19.95,
+ "price" : { "test1" : "test1 value", "test2" : "test2 value" }
+ }
+ }
+}
diff --git a/jcnf/yajl/COPYING b/jcnf/yajl/COPYING
new file mode 100644
index 0000000..fac48ba
--- /dev/null
+++ b/jcnf/yajl/COPYING
@@ -0,0 +1,29 @@
+Copyright 2007-2009, Lloyd Hilaiel.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ 3. Neither the name of Lloyd Hilaiel nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/jcnf/yajl/ChangeLog b/jcnf/yajl/ChangeLog
new file mode 100644
index 0000000..9acb334
--- /dev/null
+++ b/jcnf/yajl/ChangeLog
@@ -0,0 +1,88 @@
+1.0.5 mod ArgyllCMS
+
+ Flattened source code layout
+ Removed cmake files, and added Jamfile
+ Added support for reading and writing comments
+
+ (Graeme Gill)
+
+1.0.5
+ * lth several performance improvements related to function
+ inlinin'
+
+1.0.4
+ * lth fix broken utf8 validation for three & four byte represenations.
+ thanks to http://github.com/brianmario and
+ http://github.com/technoweenie
+
+1.0.3
+ * lth fix syntax error in cplusplus extern "C" statements for wider
+ compiler support
+
+1.0.2
+ * lth update doxygen documentation with new sample code, passing NULL
+ for allocation functions added in 1.0.0
+
+1.0.1
+ * lth resolve crash in json_reformatter due to incorrectly ordered
+ parameters.
+
+1.0.0
+ * lth add 'make install' rules, thaks to Andrei Soroker for the
+ contribution.
+ * lth client may override allocation routines at generator or parser
+ allocation time
+ * tjw add yajl_parse_complete routine to allow client to explicitly
+ specify end-of-input, solving the "lonely number" case, where
+ json text consists only of an element with no explicit syntactic
+ end.
+ * tjw many new test cases
+ * tjw cleanup of code for symmetry and ease of reading
+ * lth integration of patches from Robert Varga which cleanup
+ compilation warnings on 64 bit linux
+
+0.4.0
+ * lth buffer overflow bug in yajl_gen_double s/%lf/%g/ - thanks to
+ Eric Bergstrome
+ * lth yajl_number callback to allow passthrough of arbitrary precision
+ numbers to client. Thanks to Hatem Nassrat.
+ * lth yajl_integer now deals in long, instead of long long. This
+ combined with yajl_number improves compiler compatibility while
+ maintaining precision.
+ * lth better ./configure && make experience (still requires cmake and
+ ruby)
+ * lth fix handling of special characters hex 0F and 1F in yajl_encode
+ (thanks to Robert Geiger)
+ * lth allow leading zeros in exponents (thanks to Hatem Nassrat)
+
+0.3.0
+ * lth doxygen documentation (html & man) generated as part of the
+ build
+ * lth many documentation updates.
+ * lth fix to work with older versions of cmake (don't use LOOSE_LOOP
+ constructs)
+ * lth work around different behavior of freebsd 4 scanf. initialize
+ parameter to scanf to zero.
+ * lth all tests run 32x with ranging buffer sizes to stress stream
+ parsing
+ * lth yajl_test accepts -b option to allow read buffer size to be
+ set
+ * lth option to validate UTF8 added to parser (argument in
+ yajl_parser_cfg)
+ * lth fix buffer overrun when chunk ends inside \u escaped text
+ * lth support client cancelation
+
+0.2.2
+ * lth on windows build debug with C7 symbols and no pdb files.
+
+0.2.1
+ * fix yajl_reformat and yajl_verify to work on arbitrarily sized
+ inputs.
+ * fix win32 build break, clean up all errors and warnings.
+ * fix optimized build flags.
+
+0.2.0
+ * optionally support comments in input text
+
+0.1.0
+ * Initial release
diff --git a/jcnf/yajl/Jamfile b/jcnf/yajl/Jamfile
new file mode 100644
index 0000000..122253f
--- /dev/null
+++ b/jcnf/yajl/Jamfile
@@ -0,0 +1,30 @@
+
+# JAM style makefile for yajl
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags
+
+#Products
+Libraries = libyajl ;
+Executables = ;
+Headers = yajl_common.h yajl_gen.h yajl_parse.h ; # API headers
+
+#Install
+#InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+# config parser based on yajl
+Library libyajl : yajl.c yajl_alloc.c yajl_buf.c yajl_encode.c yajl_gen.c yajl_lex.c yajl_parser.c ;
+
+# Link all utilities here with libicc
+LINKLIBS = libyajl ;
+
+# All utils are made from a single source file
+MainsFromSources yajl_test.c json_verify.c ;
+
+
+
+
diff --git a/jcnf/yajl/Makefile.am b/jcnf/yajl/Makefile.am
new file mode 100644
index 0000000..5f477a9
--- /dev/null
+++ b/jcnf/yajl/Makefile.am
@@ -0,0 +1,13 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libyajl.la
+privatelibdir = $(pkglibdir)
+
+libyajl_la_SOURCES = yajl_common.h yajl_gen.h yajl_parse.h yajl.c \
+ yajl_alloc.c yajl_alloc.h yajl_buf.c yajl_buf.h yajl_encode.c \
+ yajl_encode.h yajl_gen.c yajl_lex.c yajl_lex.h yajl_parser.c \
+ yajl_parser.h
+
+LDADD = ./libyajl.la
+
+check_PROGRAMS = yajl_test json_verify
diff --git a/jcnf/yajl/README b/jcnf/yajl/README
new file mode 100644
index 0000000..93b3a1a
--- /dev/null
+++ b/jcnf/yajl/README
@@ -0,0 +1,68 @@
+Welcome to Yet Another JSON Library (YAJL)
+
+## Why does the world need another C library for parsing JSON?
+
+Good question. In a review of current C JSON parsing libraries I was
+unable to find one that satisfies my requirements. Those are,
+0. written in C
+1. portable
+2. robust -- as close to "crash proof" as possible
+3. data representation independent
+4. fast
+5. generates verbose, useful error messages including context of where
+ the error occurs in the input text.
+6. can parse JSON data off a stream, incrementally
+7. simple to use
+8. tiny
+
+Numbers 3, 5, 6, and 7 where particularly hard to find, and were what
+caused me to ultimately create YAJL. This document is a tour of some
+of the more important aspects of YAJL.
+
+## YAJL is Free.
+
+BSD licensing means you can use it in open source and commercial products
+alike. My request beyond the licensing is that if you find bugs drop
+me a email, or better yet, fork me on git and fix it!
+
+Porting YAJL should be trivial, the implementation is ANSI C. If you
+port to new systems I'd love to hear of it and integrate your patches.
+
+## YAJL is data representation independent.
+
+BYODR! Many JSON libraries impose a structure based data representation
+on you. This is a benefit in some cases and a drawback in others.
+YAJL uses callbacks to remain agnostic of the in-memory representation.
+So if you wish to build up an in-memory representation, you may do so
+using YAJL, but you must bring the code that defines and populates the
+in memory structure.
+
+This also means that YAJL can be used by other (higher level) JSON
+libraries if so desired.
+
+## YAJL supports stream parsing
+
+This means you do not need to hold the whole JSON representation in
+textual form in memory. This makes YAJL ideal for filtering projects,
+where you're converting YAJL from one form to another (i.e. XML). The
+included JSON pretty printer is an example of such a filter program.
+
+## YAJL is fast
+
+Minimal memory copying is performed. YAJL, when possible, returns
+pointers into the client provided text (i.e. for strings that have no
+embedded escape chars, hopefully the common case). I've put a lot of
+effort into profiling and tuning performance, but I have ignored a
+couple possible performance improvements to keep the interface clean,
+small, and flexible. My hope is that YAJL will perform comparably to
+the fastest JSON parser out there.
+
+YAJL should impose both minimal CPU and memory requirements on your
+application.
+
+## YAJL is tiny.
+
+Fat free. No whip.
+
+enjoy,
+Lloyd - July, 2007
diff --git a/jcnf/yajl/TODO b/jcnf/yajl/TODO
new file mode 100644
index 0000000..56c3dc0
--- /dev/null
+++ b/jcnf/yajl/TODO
@@ -0,0 +1,9 @@
+* add a test for 0x1F bug
+* numeric overflow in integers and double
+* line and char offsets in the lexer and in error messages
+* testing:
+ a. the permuter
+ b. some performance comparison against json_checker.
+* investigate pull instead of push parsing
+* Handle memory allocation failures gracefully
+* cygwin/msys support on win32
diff --git a/jcnf/yajl/YAJL.dxy b/jcnf/yajl/YAJL.dxy
new file mode 100644
index 0000000..680eb43
--- /dev/null
+++ b/jcnf/yajl/YAJL.dxy
@@ -0,0 +1,1258 @@
+# Doxyfile 1.5.2
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file that
+# follow. The default is UTF-8 which is also the encoding used for all text before
+# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into
+# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of
+# possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = YAJL
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = @YAJL_VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = yajl-@YAJL_VERSION@/share
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../src/yajl ../src/api
+
+# This tag can be used to specify the character encoding of the source files that
+# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
+# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding.
+# See http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the output.
+# The symbol name can be a fully qualified name, a word, or if the wildcard * is used,
+# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = doc/yajl-@YAJL_VERSION@
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to
+# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to
+# specify the directory where the mscgen tool resides. If left empty the tool is assumed to
+# be found in the default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen will always
+# show the root nodes and its direct children regardless of this setting.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/jcnf/yajl/YAJLDoc.cmake b/jcnf/yajl/YAJLDoc.cmake
new file mode 100644
index 0000000..049cdef
--- /dev/null
+++ b/jcnf/yajl/YAJLDoc.cmake
@@ -0,0 +1,26 @@
+FIND_PROGRAM(doxygenPath doxygen)
+
+IF (doxygenPath)
+ SET (YAJL_VERSION ${YAJL_MAJOR}.${YAJL_MINOR}.${YAJL_MICRO})
+ SET(yajlDirName yajl-${YAJL_VERSION})
+ SET(docPath
+ "${CMAKE_CURRENT_BINARY_DIR}/${yajlDirName}/share/doc/${yajlDirName}")
+ MESSAGE("** using doxygen at: ${doxygenPath}")
+ MESSAGE("** documentation output to: ${docPath}")
+
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/src/YAJL.dxy
+ ${CMAKE_CURRENT_BINARY_DIR}/YAJL.dxy @ONLY)
+
+ FILE(MAKE_DIRECTORY "${docPath}")
+
+ ADD_CUSTOM_TARGET(doc
+ ${doxygenPath} YAJL.dxy
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+ELSE (doxygenPath)
+ MESSAGE("!! doxygen not found, not generating documentation")
+ ADD_CUSTOM_TARGET(
+ doc
+ echo doxygen not installed, not generating documentation
+ )
+ENDIF (doxygenPath)
diff --git a/jcnf/yajl/afiles b/jcnf/yajl/afiles
new file mode 100644
index 0000000..23cf626
--- /dev/null
+++ b/jcnf/yajl/afiles
@@ -0,0 +1,84 @@
+afiles
+COPYING
+ChangeLog
+Jamfile
+README
+TODO
+YAJL.dxy
+YAJLDoc.cmake
+configure
+json_reformat.c
+json_verify.c
+rfc4627.txt
+run_tests.sh
+yajl.c
+yajl_alloc.c
+yajl_alloc.h
+yajl_buf.c
+yajl_buf.h
+yajl_bytestack.h
+yajl_common.h
+yajl_encode.c
+yajl_encode.h
+yajl_gen.c
+yajl_gen.h
+yajl_lex.c
+yajl_lex.h
+yajl_parse.h
+yajl_parser.c
+yajl_parser.h
+yajl_test.c
+cases/array.json
+cases/array.json.gold
+cases/bogus_char.json
+cases/bogus_char.json.gold
+cases/codepoints_from_unicode_org.json
+cases/codepoints_from_unicode_org.json.gold
+cases/dc_simple_with_comments.json
+cases/dc_simple_with_comments.json.gold
+cases/deep_arrays.json
+cases/deep_arrays.json.gold
+cases/difficult_json_c_test_case.json
+cases/difficult_json_c_test_case.json.gold
+cases/difficult_json_c_test_case_with_comments.json
+cases/difficult_json_c_test_case_with_comments.json.gold
+cases/doubles.json
+cases/doubles.json.gold
+cases/empty_array.json
+cases/empty_array.json.gold
+cases/escaped_bulgarian.json
+cases/escaped_bulgarian.json.gold
+cases/escaped_foobar.json
+cases/escaped_foobar.json.gold
+cases/integers.json
+cases/integers.json.gold
+cases/invalid_utf8.json
+cases/invalid_utf8.json.gold
+cases/isolated_surrogate_marker.json
+cases/isolated_surrogate_marker.json.gold
+cases/leading_zero_in_number.json
+cases/leading_zero_in_number.json.gold
+cases/lonely_minus_sign.json
+cases/lonely_minus_sign.json.gold
+cases/missing_integer_after_decimal_point.json
+cases/missing_integer_after_decimal_point.json.gold
+cases/missing_integer_after_exponent.json
+cases/missing_integer_after_exponent.json.gold
+cases/non_utf8_char_in_string.json
+cases/non_utf8_char_in_string.json.gold
+cases/nulls_and_bools.json
+cases/nulls_and_bools.json.gold
+cases/simple.json
+cases/simple.json.gold
+cases/simple_with_comments.json
+cases/simple_with_comments.json.gold
+cases/string_invalid_escape.json
+cases/string_invalid_escape.json.gold
+cases/string_invalid_hex_char.json
+cases/string_invalid_hex_char.json.gold
+cases/string_with_escapes.json
+cases/string_with_escapes.json.gold
+cases/string_with_invalid_newline.json
+cases/string_with_invalid_newline.json.gold
+cases/unescaped_bulgarian.json
+cases/unescaped_bulgarian.json.gold
diff --git a/jcnf/yajl/cases/array.json b/jcnf/yajl/cases/array.json
new file mode 100644
index 0000000..f76058d
--- /dev/null
+++ b/jcnf/yajl/cases/array.json
@@ -0,0 +1,6 @@
+["foo",
+ "bar", "baz",
+ true,false,null,{"key":"value"},
+ [null,null,null,[]],
+ "\n\r\\"
+]
diff --git a/jcnf/yajl/cases/array.json.gold b/jcnf/yajl/cases/array.json.gold
new file mode 100644
index 0000000..d77e716
--- /dev/null
+++ b/jcnf/yajl/cases/array.json.gold
@@ -0,0 +1,22 @@
+array open '['
+string: 'foo'
+string: 'bar'
+string: 'baz'
+bool: true
+bool: false
+null
+map open '{'
+key: 'key'
+string: 'value'
+map close '}'
+array open '['
+null
+null
+null
+array open '['
+array close ']'
+array close ']'
+string: '
+
+\'
+array close ']'
diff --git a/jcnf/yajl/cases/bogus_char.json b/jcnf/yajl/cases/bogus_char.json
new file mode 100644
index 0000000..8163bd8
--- /dev/null
+++ b/jcnf/yajl/cases/bogus_char.json
@@ -0,0 +1,4 @@
+["this","is","what","should","be",
+ "a happy bit of json",
+ "but someone, misspelled \"true\"", ture,
+ "who says JSON is easy for humans to generate?"]
diff --git a/jcnf/yajl/cases/bogus_char.json.gold b/jcnf/yajl/cases/bogus_char.json.gold
new file mode 100644
index 0000000..ccbeed5
--- /dev/null
+++ b/jcnf/yajl/cases/bogus_char.json.gold
@@ -0,0 +1,9 @@
+array open '['
+string: 'this'
+string: 'is'
+string: 'what'
+string: 'should'
+string: 'be'
+string: 'a happy bit of json'
+string: 'but someone, misspelled "true"'
+lexical error: invalid string in json text.
diff --git a/jcnf/yajl/cases/codepoints_from_unicode_org.json b/jcnf/yajl/cases/codepoints_from_unicode_org.json
new file mode 100644
index 0000000..f91f3be
--- /dev/null
+++ b/jcnf/yajl/cases/codepoints_from_unicode_org.json
@@ -0,0 +1 @@
+"\u004d\u0430\u4e8c\ud800\udf02"
diff --git a/jcnf/yajl/cases/codepoints_from_unicode_org.json.gold b/jcnf/yajl/cases/codepoints_from_unicode_org.json.gold
new file mode 100644
index 0000000..12b358a
--- /dev/null
+++ b/jcnf/yajl/cases/codepoints_from_unicode_org.json.gold
@@ -0,0 +1 @@
+string: 'Mа二𐌂'
diff --git a/jcnf/yajl/cases/dc_simple_with_comments.json b/jcnf/yajl/cases/dc_simple_with_comments.json
new file mode 100644
index 0000000..3b79bba
--- /dev/null
+++ b/jcnf/yajl/cases/dc_simple_with_comments.json
@@ -0,0 +1,11 @@
+{
+ "this": "is", // ignore this
+ "really": "simple",
+ /* ignore
+this
+too * /
+** //
+(/
+******/
+ "json": "right?"
+}
diff --git a/jcnf/yajl/cases/dc_simple_with_comments.json.gold b/jcnf/yajl/cases/dc_simple_with_comments.json.gold
new file mode 100644
index 0000000..92be7a5
--- /dev/null
+++ b/jcnf/yajl/cases/dc_simple_with_comments.json.gold
@@ -0,0 +1,4 @@
+map open '{'
+key: 'this'
+string: 'is'
+lexical error: probable comment found in input text, comments are not enabled.
diff --git a/jcnf/yajl/cases/deep_arrays.json b/jcnf/yajl/cases/deep_arrays.json
new file mode 100644
index 0000000..82d1b0d
--- /dev/null
+++ b/jcnf/yajl/cases/deep_arrays.json
@@ -0,0 +1 @@
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] \ No newline at end of file
diff --git a/jcnf/yajl/cases/deep_arrays.json.gold b/jcnf/yajl/cases/deep_arrays.json.gold
new file mode 100644
index 0000000..e549637
--- /dev/null
+++ b/jcnf/yajl/cases/deep_arrays.json.gold
@@ -0,0 +1,2048 @@
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array open '['
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
+array close ']'
diff --git a/jcnf/yajl/cases/difficult_json_c_test_case.json b/jcnf/yajl/cases/difficult_json_c_test_case.json
new file mode 100644
index 0000000..6998f55
--- /dev/null
+++ b/jcnf/yajl/cases/difficult_json_c_test_case.json
@@ -0,0 +1 @@
+{ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML", "markup"] } ] } } }
diff --git a/jcnf/yajl/cases/difficult_json_c_test_case.json.gold b/jcnf/yajl/cases/difficult_json_c_test_case.json.gold
new file mode 100644
index 0000000..eaaf41a
--- /dev/null
+++ b/jcnf/yajl/cases/difficult_json_c_test_case.json.gold
@@ -0,0 +1,35 @@
+map open '{'
+key: 'glossary'
+map open '{'
+key: 'title'
+string: 'example glossary'
+key: 'GlossDiv'
+map open '{'
+key: 'title'
+string: 'S'
+key: 'GlossList'
+array open '['
+map open '{'
+key: 'ID'
+string: 'SGML'
+key: 'SortAs'
+string: 'SGML'
+key: 'GlossTerm'
+string: 'Standard Generalized Markup Language'
+key: 'Acronym'
+string: 'SGML'
+key: 'Abbrev'
+string: 'ISO 8879:1986'
+key: 'GlossDef'
+string: 'A meta-markup language, used to create markup languages such as DocBook.'
+key: 'GlossSeeAlso'
+array open '['
+string: 'GML'
+string: 'XML'
+string: 'markup'
+array close ']'
+map close '}'
+array close ']'
+map close '}'
+map close '}'
+map close '}'
diff --git a/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json b/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json
new file mode 100644
index 0000000..2463c71
--- /dev/null
+++ b/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json
@@ -0,0 +1 @@
+{ "glossary": { /* you */ "title": /**/ "example glossary", /*should*/"GlossDiv": { "title": /*never*/"S", /*ever*/"GlossList": [ { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.", /*see*/"GlossSeeAlso"/*this*/:/*coming*/[/*out*/"GML"/*of*/,/*the*/"XML"/*parser!*/, "markup"] /*hey*/}/*ho*/]/*hey*/}/*ho*/} } // and the parser won't even get this far, so chill. /* hah!
diff --git a/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold b/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold
new file mode 100644
index 0000000..eaaf41a
--- /dev/null
+++ b/jcnf/yajl/cases/difficult_json_c_test_case_with_comments.json.gold
@@ -0,0 +1,35 @@
+map open '{'
+key: 'glossary'
+map open '{'
+key: 'title'
+string: 'example glossary'
+key: 'GlossDiv'
+map open '{'
+key: 'title'
+string: 'S'
+key: 'GlossList'
+array open '['
+map open '{'
+key: 'ID'
+string: 'SGML'
+key: 'SortAs'
+string: 'SGML'
+key: 'GlossTerm'
+string: 'Standard Generalized Markup Language'
+key: 'Acronym'
+string: 'SGML'
+key: 'Abbrev'
+string: 'ISO 8879:1986'
+key: 'GlossDef'
+string: 'A meta-markup language, used to create markup languages such as DocBook.'
+key: 'GlossSeeAlso'
+array open '['
+string: 'GML'
+string: 'XML'
+string: 'markup'
+array close ']'
+map close '}'
+array close ']'
+map close '}'
+map close '}'
+map close '}'
diff --git a/jcnf/yajl/cases/doubles.json b/jcnf/yajl/cases/doubles.json
new file mode 100644
index 0000000..626f21c
--- /dev/null
+++ b/jcnf/yajl/cases/doubles.json
@@ -0,0 +1 @@
+[ 0.1e2, 1e1, 3.141569, 10000000000000e-10]
diff --git a/jcnf/yajl/cases/doubles.json.gold b/jcnf/yajl/cases/doubles.json.gold
new file mode 100644
index 0000000..ab5f212
--- /dev/null
+++ b/jcnf/yajl/cases/doubles.json.gold
@@ -0,0 +1,6 @@
+array open '['
+double: 10.000000
+double: 10.000000
+double: 3.141569
+double: 1000.000000
+array close ']'
diff --git a/jcnf/yajl/cases/empty_array.json b/jcnf/yajl/cases/empty_array.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/jcnf/yajl/cases/empty_array.json
@@ -0,0 +1 @@
+[] \ No newline at end of file
diff --git a/jcnf/yajl/cases/empty_array.json.gold b/jcnf/yajl/cases/empty_array.json.gold
new file mode 100644
index 0000000..45924af
--- /dev/null
+++ b/jcnf/yajl/cases/empty_array.json.gold
@@ -0,0 +1,2 @@
+array open '['
+array close ']'
diff --git a/jcnf/yajl/cases/escaped_bulgarian.json b/jcnf/yajl/cases/escaped_bulgarian.json
new file mode 100644
index 0000000..9ce1d1c
--- /dev/null
+++ b/jcnf/yajl/cases/escaped_bulgarian.json
@@ -0,0 +1,4 @@
+["\u0414\u0430",
+ "\u041c\u0443",
+ "\u0415\u0431\u0430",
+ "\u041c\u0430\u0439\u043a\u0430\u0442\u0430"]
diff --git a/jcnf/yajl/cases/escaped_bulgarian.json.gold b/jcnf/yajl/cases/escaped_bulgarian.json.gold
new file mode 100644
index 0000000..9f2aa00
--- /dev/null
+++ b/jcnf/yajl/cases/escaped_bulgarian.json.gold
@@ -0,0 +1,6 @@
+array open '['
+string: 'Да'
+string: 'Му'
+string: 'Еба'
+string: 'Майката'
+array close ']'
diff --git a/jcnf/yajl/cases/escaped_foobar.json b/jcnf/yajl/cases/escaped_foobar.json
new file mode 100644
index 0000000..2c0e25f
--- /dev/null
+++ b/jcnf/yajl/cases/escaped_foobar.json
@@ -0,0 +1 @@
+"\u0066\u006f\u006f\u0062\u0061\u0072"
diff --git a/jcnf/yajl/cases/escaped_foobar.json.gold b/jcnf/yajl/cases/escaped_foobar.json.gold
new file mode 100644
index 0000000..774e867
--- /dev/null
+++ b/jcnf/yajl/cases/escaped_foobar.json.gold
@@ -0,0 +1 @@
+string: 'foobar'
diff --git a/jcnf/yajl/cases/integers.json b/jcnf/yajl/cases/integers.json
new file mode 100644
index 0000000..ca1393a
--- /dev/null
+++ b/jcnf/yajl/cases/integers.json
@@ -0,0 +1,3 @@
+[ 1,2,3,4,5,6,7,
+ 123456789 , -123456789,
+ 9223372036854775807, -9223372036854775807 ]
diff --git a/jcnf/yajl/cases/integers.json.gold b/jcnf/yajl/cases/integers.json.gold
new file mode 100644
index 0000000..f44b283
--- /dev/null
+++ b/jcnf/yajl/cases/integers.json.gold
@@ -0,0 +1,13 @@
+array open '['
+integer: 1
+integer: 2
+integer: 3
+integer: 4
+integer: 5
+integer: 6
+integer: 7
+integer: 123456789
+integer: -123456789
+integer: 9223372036854775807
+integer: -9223372036854775807
+array close ']'
diff --git a/jcnf/yajl/cases/invalid_utf8.json b/jcnf/yajl/cases/invalid_utf8.json
new file mode 100644
index 0000000..12f1718
--- /dev/null
+++ b/jcnf/yajl/cases/invalid_utf8.json
@@ -0,0 +1 @@
+["Да М Еба Майката"]
diff --git a/jcnf/yajl/cases/invalid_utf8.json.gold b/jcnf/yajl/cases/invalid_utf8.json.gold
new file mode 100644
index 0000000..0cabb13
--- /dev/null
+++ b/jcnf/yajl/cases/invalid_utf8.json.gold
@@ -0,0 +1,2 @@
+array open '['
+lexical error: invalid bytes in UTF8 string.
diff --git a/jcnf/yajl/cases/isolated_surrogate_marker.json b/jcnf/yajl/cases/isolated_surrogate_marker.json
new file mode 100644
index 0000000..36959f4
--- /dev/null
+++ b/jcnf/yajl/cases/isolated_surrogate_marker.json
@@ -0,0 +1 @@
+"\ud800"
diff --git a/jcnf/yajl/cases/isolated_surrogate_marker.json.gold b/jcnf/yajl/cases/isolated_surrogate_marker.json.gold
new file mode 100644
index 0000000..1ad9e8b
--- /dev/null
+++ b/jcnf/yajl/cases/isolated_surrogate_marker.json.gold
@@ -0,0 +1 @@
+string: '?'
diff --git a/jcnf/yajl/cases/leading_zero_in_number.json b/jcnf/yajl/cases/leading_zero_in_number.json
new file mode 100644
index 0000000..959f5ba
--- /dev/null
+++ b/jcnf/yajl/cases/leading_zero_in_number.json
@@ -0,0 +1 @@
+{ "bad thing": 01 }
diff --git a/jcnf/yajl/cases/leading_zero_in_number.json.gold b/jcnf/yajl/cases/leading_zero_in_number.json.gold
new file mode 100644
index 0000000..828aec8
--- /dev/null
+++ b/jcnf/yajl/cases/leading_zero_in_number.json.gold
@@ -0,0 +1,4 @@
+map open '{'
+key: 'bad thing'
+integer: 0
+parse error: after key and value, inside map, I expect ',' or '}'
diff --git a/jcnf/yajl/cases/lonely_minus_sign.json b/jcnf/yajl/cases/lonely_minus_sign.json
new file mode 100644
index 0000000..85f69bd
--- /dev/null
+++ b/jcnf/yajl/cases/lonely_minus_sign.json
@@ -0,0 +1,7 @@
+[
+ "foo", true,
+ true, "blue",
+ "baby where are you?", "oh boo hoo!",
+ -
+]
+
diff --git a/jcnf/yajl/cases/lonely_minus_sign.json.gold b/jcnf/yajl/cases/lonely_minus_sign.json.gold
new file mode 100644
index 0000000..4b23c61
--- /dev/null
+++ b/jcnf/yajl/cases/lonely_minus_sign.json.gold
@@ -0,0 +1,8 @@
+array open '['
+string: 'foo'
+bool: true
+bool: true
+string: 'blue'
+string: 'baby where are you?'
+string: 'oh boo hoo!'
+lexical error: malformed number, a digit is required after the minus sign.
diff --git a/jcnf/yajl/cases/missing_integer_after_decimal_point.json b/jcnf/yajl/cases/missing_integer_after_decimal_point.json
new file mode 100644
index 0000000..2369f4b
--- /dev/null
+++ b/jcnf/yajl/cases/missing_integer_after_decimal_point.json
@@ -0,0 +1 @@
+10.e2
diff --git a/jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold b/jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold
new file mode 100644
index 0000000..1d85c91
--- /dev/null
+++ b/jcnf/yajl/cases/missing_integer_after_decimal_point.json.gold
@@ -0,0 +1 @@
+lexical error: malformed number, a digit is required after the decimal point.
diff --git a/jcnf/yajl/cases/missing_integer_after_exponent.json b/jcnf/yajl/cases/missing_integer_after_exponent.json
new file mode 100644
index 0000000..a62b45d
--- /dev/null
+++ b/jcnf/yajl/cases/missing_integer_after_exponent.json
@@ -0,0 +1 @@
+10e
diff --git a/jcnf/yajl/cases/missing_integer_after_exponent.json.gold b/jcnf/yajl/cases/missing_integer_after_exponent.json.gold
new file mode 100644
index 0000000..b9f184f
--- /dev/null
+++ b/jcnf/yajl/cases/missing_integer_after_exponent.json.gold
@@ -0,0 +1 @@
+lexical error: malformed number, a digit is required after the exponent.
diff --git a/jcnf/yajl/cases/non_utf8_char_in_string.json b/jcnf/yajl/cases/non_utf8_char_in_string.json
new file mode 100644
index 0000000..253a664
--- /dev/null
+++ b/jcnf/yajl/cases/non_utf8_char_in_string.json
@@ -0,0 +1 @@
+{"CoreletAPIVersion":2,"CoreletType":"standalone","documentation":"A corelet that provides the capability to upload a folders contents into a users locker.","functions":[{"documentation":"Displays a dialog box that allows user to select a folder on the local system.","name":"ShowBrowseDialog","parameters":[{"documentation":"The callback function for results.","name":"callback","required":true,"type":"callback"}]},{"documentation":"Uploads all mp3 files in the folder provided.","name":"UploadFolder","parameters":[{"documentation":"The path to upload mp3 files from.","name":"path","required":true,"type":"string"},{"documentation":"The callback function for progress.","name":"callback","required":true,"type":"callback"}]},{"documentation":"Returns the server name to the current locker service.","name":"GetLockerService","parameters":[]},{"documentation":"Changes the name of the locker service.","name":"SetLockerService","parameters":[{"documentation":"The value of the locker service to set active.","name":"LockerService","required":true,"type":"string"}]},{"documentation":"Downloads locker files to the suggested folder.","name":"DownloadFile","parameters":[{"documentation":"The origin path of the locker file.","name":"path","required":true,"type":"string"},{"documentation":"The Window destination path of the locker file.","name":"destination","required":true,"type":"integer"},{"documentation":"The callback function for progress.","name":"callback","required":true,"type":"callback"}]}],"name":"LockerUploader","version":{"major":0,"micro":1,"minor":0},"versionString":"0.0.1"} \ No newline at end of file
diff --git a/jcnf/yajl/cases/non_utf8_char_in_string.json.gold b/jcnf/yajl/cases/non_utf8_char_in_string.json.gold
new file mode 100644
index 0000000..b3780ae
--- /dev/null
+++ b/jcnf/yajl/cases/non_utf8_char_in_string.json.gold
@@ -0,0 +1,7 @@
+map open '{'
+key: 'CoreletAPIVersion'
+integer: 2
+key: 'CoreletType'
+string: 'standalone'
+key: 'documentation'
+lexical error: invalid bytes in UTF8 string.
diff --git a/jcnf/yajl/cases/nulls_and_bools.json b/jcnf/yajl/cases/nulls_and_bools.json
new file mode 100644
index 0000000..65eb01f
--- /dev/null
+++ b/jcnf/yajl/cases/nulls_and_bools.json
@@ -0,0 +1,5 @@
+{
+ "boolean, true": true,
+ "boolean, false": false,
+ "null": null
+}
diff --git a/jcnf/yajl/cases/nulls_and_bools.json.gold b/jcnf/yajl/cases/nulls_and_bools.json.gold
new file mode 100644
index 0000000..8dc173c
--- /dev/null
+++ b/jcnf/yajl/cases/nulls_and_bools.json.gold
@@ -0,0 +1,8 @@
+map open '{'
+key: 'boolean, true'
+bool: true
+key: 'boolean, false'
+bool: false
+key: 'null'
+null
+map close '}'
diff --git a/jcnf/yajl/cases/simple.json b/jcnf/yajl/cases/simple.json
new file mode 100644
index 0000000..9ed80c9
--- /dev/null
+++ b/jcnf/yajl/cases/simple.json
@@ -0,0 +1,5 @@
+{
+ "this": "is",
+ "really": "simple",
+ "json": "right?"
+}
diff --git a/jcnf/yajl/cases/simple.json.gold b/jcnf/yajl/cases/simple.json.gold
new file mode 100644
index 0000000..59b7d6a
--- /dev/null
+++ b/jcnf/yajl/cases/simple.json.gold
@@ -0,0 +1,8 @@
+map open '{'
+key: 'this'
+string: 'is'
+key: 'really'
+string: 'simple'
+key: 'json'
+string: 'right?'
+map close '}'
diff --git a/jcnf/yajl/cases/simple_with_comments.json b/jcnf/yajl/cases/simple_with_comments.json
new file mode 100644
index 0000000..3b79bba
--- /dev/null
+++ b/jcnf/yajl/cases/simple_with_comments.json
@@ -0,0 +1,11 @@
+{
+ "this": "is", // ignore this
+ "really": "simple",
+ /* ignore
+this
+too * /
+** //
+(/
+******/
+ "json": "right?"
+}
diff --git a/jcnf/yajl/cases/simple_with_comments.json.gold b/jcnf/yajl/cases/simple_with_comments.json.gold
new file mode 100644
index 0000000..59b7d6a
--- /dev/null
+++ b/jcnf/yajl/cases/simple_with_comments.json.gold
@@ -0,0 +1,8 @@
+map open '{'
+key: 'this'
+string: 'is'
+key: 'really'
+string: 'simple'
+key: 'json'
+string: 'right?'
+map close '}'
diff --git a/jcnf/yajl/cases/string_invalid_escape.json b/jcnf/yajl/cases/string_invalid_escape.json
new file mode 100644
index 0000000..c554182
--- /dev/null
+++ b/jcnf/yajl/cases/string_invalid_escape.json
@@ -0,0 +1 @@
+["\n foo \/ bar \r\f\\\uffff\t\b\"\\ and you can't escape thi\s"]
diff --git a/jcnf/yajl/cases/string_invalid_escape.json.gold b/jcnf/yajl/cases/string_invalid_escape.json.gold
new file mode 100644
index 0000000..bdc473e
--- /dev/null
+++ b/jcnf/yajl/cases/string_invalid_escape.json.gold
@@ -0,0 +1,2 @@
+array open '['
+lexical error: inside a string, '\' occurs before a character which it may not.
diff --git a/jcnf/yajl/cases/string_invalid_hex_char.json b/jcnf/yajl/cases/string_invalid_hex_char.json
new file mode 100644
index 0000000..bde7ee9
--- /dev/null
+++ b/jcnf/yajl/cases/string_invalid_hex_char.json
@@ -0,0 +1 @@
+"foo foo, blah blah \u0123 \u4567 \u89ab \uc/ef \uABCD \uEFFE bar baz bing"
diff --git a/jcnf/yajl/cases/string_invalid_hex_char.json.gold b/jcnf/yajl/cases/string_invalid_hex_char.json.gold
new file mode 100644
index 0000000..d8b535e
--- /dev/null
+++ b/jcnf/yajl/cases/string_invalid_hex_char.json.gold
@@ -0,0 +1 @@
+lexical error: invalid (non-hex) character occurs after '\u' inside string.
diff --git a/jcnf/yajl/cases/string_with_escapes.json b/jcnf/yajl/cases/string_with_escapes.json
new file mode 100644
index 0000000..59cc940
--- /dev/null
+++ b/jcnf/yajl/cases/string_with_escapes.json
@@ -0,0 +1,3 @@
+["\n foo \/ bar \r\f\\\uffff\t\b\"\\",
+ "\"and this string has an escape at the beginning",
+ "and this string has no escapes" ]
diff --git a/jcnf/yajl/cases/string_with_escapes.json.gold b/jcnf/yajl/cases/string_with_escapes.json.gold
new file mode 100644
index 0000000..ac878a2
--- /dev/null
+++ b/jcnf/yajl/cases/string_with_escapes.json.gold
@@ -0,0 +1,6 @@
+array open '['
+string: '
+ foo / bar \￿ "\'
+string: '"and this string has an escape at the beginning'
+string: 'and this string has no escapes'
+array close ']'
diff --git a/jcnf/yajl/cases/string_with_invalid_newline.json b/jcnf/yajl/cases/string_with_invalid_newline.json
new file mode 100644
index 0000000..0e3ea0d
--- /dev/null
+++ b/jcnf/yajl/cases/string_with_invalid_newline.json
@@ -0,0 +1,2 @@
+"la di dah. this is a string, and I can do this, \n, but not this
+"
diff --git a/jcnf/yajl/cases/string_with_invalid_newline.json.gold b/jcnf/yajl/cases/string_with_invalid_newline.json.gold
new file mode 100644
index 0000000..80c1b8a
--- /dev/null
+++ b/jcnf/yajl/cases/string_with_invalid_newline.json.gold
@@ -0,0 +1 @@
+lexical error: invalid character inside string.
diff --git a/jcnf/yajl/cases/unescaped_bulgarian.json b/jcnf/yajl/cases/unescaped_bulgarian.json
new file mode 100644
index 0000000..f9a70a6
--- /dev/null
+++ b/jcnf/yajl/cases/unescaped_bulgarian.json
@@ -0,0 +1 @@
+["Да Му Еба Майката"]
diff --git a/jcnf/yajl/cases/unescaped_bulgarian.json.gold b/jcnf/yajl/cases/unescaped_bulgarian.json.gold
new file mode 100644
index 0000000..ac34442
--- /dev/null
+++ b/jcnf/yajl/cases/unescaped_bulgarian.json.gold
@@ -0,0 +1,3 @@
+array open '['
+string: 'Да Му Еба Майката'
+array close ']'
diff --git a/jcnf/yajl/configure b/jcnf/yajl/configure
new file mode 100644
index 0000000..bed8c28
--- /dev/null
+++ b/jcnf/yajl/configure
@@ -0,0 +1,94 @@
+#!/usr/bin/env ruby
+# Copyright 2007-2009, Lloyd Hilaiel.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+#
+# 3. Neither the name of Lloyd Hilaiel nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+require 'fileutils'
+require 'optparse'
+
+prefix = "/usr/local"
+options = {}
+OptionParser.new do |opts|
+ opts.banner = "Usage: configure [options]"
+ opts.on("-p", "--prefix PATH", "Set installation prefix") do |p|
+ prefix = p
+ end
+ opts.on_tail("-h", "--help", "Output usage summary") do
+ puts opts
+ exit
+ end
+
+ opts.parse!(ARGV)
+end
+
+puts "== removing old build files"
+FileUtils.rm_rf("build")
+FileUtils.rm_f("Makefile")
+puts "== running CMake in build directory"
+FileUtils.mkdir("build")
+FileUtils.cd("build") do
+ if (!system("cmake .."))
+ puts "The \"cmake\" program is required to configure yajl. It's"
+ puts "available from most ports/packaging systems and http://cmake.org"
+ exit 1
+ end
+end
+
+# now generate a Makefile
+puts "== Generating Makefile"
+File.open("Makefile", "w+") do |f|
+ f.puts ".PHONY: all clean distclean install package test distro"
+ f.puts "all: distro doc test"
+ f.puts
+ f.puts "distro:"
+ f.puts " @cd build && make"
+ f.puts
+ f.puts "doc:"
+ f.puts " @cd build && make doc"
+ f.puts
+ f.puts "test:"
+ f.puts " @cd build && make test"
+ f.puts
+ f.puts "clean:"
+ f.puts " @cd build && make clean"
+ f.puts
+ f.puts "distclean:"
+ f.puts " @rm -rf Makefile build"
+ f.puts " @rm -f yajl-*.tgz"
+ f.puts
+ f.puts "install: all"
+ f.puts " @cd build && make install"
+ f.puts
+ f.puts "package: all"
+ f.puts " @echo \"compressing to `basename build/yajl-*`.tgz\""
+ f.puts " @cd build && tar czf ../`basename yajl-*`.tgz yajl-*"
+end
+
+puts "== Configured with installation prefix: #{prefix}"
+
diff --git a/jcnf/yajl/json_reformat.c b/jcnf/yajl/json_reformat.c
new file mode 100644
index 0000000..156a61b
--- /dev/null
+++ b/jcnf/yajl/json_reformat.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2007, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_parse.h"
+#include "yajl_gen.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int reformat_null(void * ctx)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_null(g);
+ return 1;
+}
+
+int reformat_boolean(void * ctx, int boolVal)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_bool(g, boolVal);
+ return 1;
+}
+
+int reformat_integer(void * ctx, long long integerVal)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_integer(g, integerVal);
+ return 1;
+}
+
+int reformat_double(void * ctx, double doubleVal)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_double(g, doubleVal);
+ return 1;
+}
+
+int reformat_string(void * ctx, const unsigned char * stringVal,
+ unsigned int stringLen)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_string(g, stringVal, stringLen);
+ return 1;
+}
+
+int reformat_map_key(void * ctx, const unsigned char * stringVal,
+ unsigned int stringLen)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_string(g, stringVal, stringLen);
+ return 1;
+}
+
+int reformat_start_map(void * ctx)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_map_open(g);
+ return 1;
+}
+
+
+int reformat_end_map(void * ctx)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_map_close(g);
+ return 1;
+}
+
+int reformat_start_array(void * ctx)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_array_open(g);
+ return 1;
+}
+
+int reformat_end_array(void * ctx)
+{
+ yajl_gen g = (yajl_gen) ctx;
+ yajl_gen_array_close(g);
+ return 1;
+}
+
+static yajl_callbacks callbacks = {
+ reformat_null,
+ reformat_boolean,
+ reformat_integer,
+ reformat_double,
+ reformat_string,
+ reformat_start_map,
+ reformat_map_key,
+ reformat_end_map,
+ reformat_start_array,
+ reformat_end_array
+};
+
+static void
+usage(const char * progname)
+{
+ fprintf(stderr, "usage: %s <filename>\n"
+ " -m minimize json rather than beautify (default)\n"
+ " -u allow invalid UTF8 inside strings during parsing\n",
+ progname);
+ exit(1);
+
+}
+
+int
+main(int argc, char ** argv)
+{
+ yajl_handle hand;
+ static unsigned char fileData[65536];
+ /* generator config */
+ yajl_gen_config conf = { 1, " " };
+ yajl_gen g;
+ yajl_status stat;
+ size_t rd;
+ /* allow comments */
+ yajl_parser_config cfg = { 1, 1 };
+
+ /* check arguments. We expect exactly one! */
+ if (argc == 2) {
+ if (!strcmp("-m", argv[1])) {
+ conf.beautify = 0;
+
+ } else if (!strcmp("-u", argv[1])) {
+ cfg.checkUTF8 = 0;
+ } else {
+ usage(argv[0]);
+ }
+ } else if (argc != 1) {
+ usage(argv[0]);
+ }
+
+ g = yajl_gen_alloc(&conf);
+
+ /* ok. open file. let's read and parse */
+ hand = yajl_alloc(&callbacks, &cfg, (void *) g);
+
+ for (;;) {
+ rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);
+
+ if (rd == 0) {
+ if (feof(stdin)) {
+ break;
+ } else {
+ fprintf(stderr, "error on file read.\n");
+ break;
+ }
+ } else {
+ fileData[rd] = 0;
+
+ /* read file data, pass to parser */
+ stat = yajl_parse(hand, fileData, rd);
+ if (stat != yajl_status_ok &&
+ stat != yajl_status_insufficient_data)
+ {
+ unsigned char * str = yajl_get_error(hand, 1, fileData, rd);
+ fprintf(stderr, (const char *) str);
+ yajl_free_error(str);
+ } else {
+ const unsigned char * buf;
+ unsigned int len;
+ yajl_gen_get_buf(g, &buf, &len);
+ fwrite(buf, 1, len, stdout);
+ yajl_gen_clear(g);
+ }
+ }
+ }
+
+ yajl_gen_free(g);
+ yajl_free(hand);
+
+ return 0;
+}
diff --git a/jcnf/yajl/json_verify.c b/jcnf/yajl/json_verify.c
new file mode 100644
index 0000000..42b57a9
--- /dev/null
+++ b/jcnf/yajl/json_verify.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_parse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+usage(const char * progname)
+{
+ fprintf(stderr, "%s: validate json from stdin\n"
+ "usage: json_verify [options]\n"
+ " -q quiet mode\n"
+ " -c allow comments\n"
+ " -u allow invalid utf8 inside strings\n",
+ progname);
+ exit(1);
+}
+
+int
+main(int argc, char ** argv)
+{
+ yajl_status stat;
+ size_t rd;
+ yajl_handle hand;
+ static unsigned char fileData[65536];
+ int quiet = 0;
+ int retval = 0, done = 0;
+ yajl_parser_config cfg = { 0, 1 };
+
+ /* check arguments.*/
+ if (argc > 1 && argc < 4) {
+ int i;
+
+ for (i=1; i < argc;i++) {
+ if (!strcmp("-q", argv[i])) {
+ quiet = 1;
+ } else if (!strcmp("-c", argv[i])) {
+ cfg.allowComments = 1;
+ } else if (!strcmp("-u", argv[i])) {
+ cfg.checkUTF8 = 0;
+ } else {
+ fprintf(stderr, "unrecognized option: '%s'\n\n", argv[i]);
+ usage(argv[0]);
+ }
+ }
+ } else if (argc != 1) {
+ usage(argv[0]);
+ }
+
+ /* allocate a parser */
+ hand = yajl_alloc(NULL, &cfg, NULL, NULL);
+
+ while (!done) {
+ rd = fread((void *) fileData, 1, sizeof(fileData) - 1, stdin);
+
+ retval = 0;
+
+ if (rd == 0) {
+ if (!feof(stdin)) {
+ if (!quiet) {
+ fprintf(stderr, "error encountered on file read\n");
+ }
+ retval = 1;
+ break;
+ }
+ done = 1;
+ }
+ fileData[rd] = 0;
+
+ if (done)
+ /* parse any remaining buffered data */
+ stat = yajl_parse_complete(hand);
+ else
+ /* read file data, pass to parser */
+ stat = yajl_parse(hand, fileData, rd);
+
+ if (stat != yajl_status_ok &&
+ stat != yajl_status_insufficient_data)
+ {
+ if (!quiet) {
+ unsigned char * str = yajl_get_error(hand, 1, fileData, rd);
+ fprintf(stderr, "%s", (const char *) str);
+ yajl_free_error(hand, str);
+ }
+ retval = 1;
+ break;
+ }
+ }
+
+ yajl_free(hand);
+
+ if (!quiet) {
+ printf("JSON is %s\n", retval ? "invalid" : "valid");
+ }
+
+ return retval;
+}
diff --git a/jcnf/yajl/rfc4627.txt b/jcnf/yajl/rfc4627.txt
new file mode 100644
index 0000000..c3325a9
--- /dev/null
+++ b/jcnf/yajl/rfc4627.txt
@@ -0,0 +1,3 @@
+
+See <http://www.ietf.org/rfc/rfc4627.txt>
+
diff --git a/jcnf/yajl/run_tests.sh b/jcnf/yajl/run_tests.sh
new file mode 100644
index 0000000..174932f
--- /dev/null
+++ b/jcnf/yajl/run_tests.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+DIFF_FLAGS="-u"
+if [[ `uname` == *W32* ]] ; then
+ DIFF_FLAGS="-wu"
+fi
+
+# find test binary on both platforms. allow the caller to force a
+# particular test binary (useful for non-cmake build systems).
+if [ -z "$testBin" ]; then
+ testBin="../build/test/Debug/yajl_test.exe"
+ if [[ ! -x $testBin ]] ; then
+ testBin="../build/test/yajl_test"
+ if [[ ! -x $testBin ]] ; then
+ echo "cannot execute test binary: '$testBin'"
+ exit 1;
+ fi
+ fi
+fi
+
+echo "using test binary: $testBin"
+
+let testsSucceeded=0
+let testsTotal=0
+
+for file in cases/*.json ; do
+ allowComments="-c"
+
+ # if the filename starts with dc_, we disallow comments for this test
+ if [[ $(basename $file) == dc_* ]] ; then
+ allowComments=""
+ fi
+ echo -n " test case: '$file': "
+ let iter=1
+ success="success"
+
+ # parse with a read buffer size ranging from 1-31 to stress stream parsing
+ while (( $iter < 32 )) && [ $success == "success" ] ; do
+ $testBin $allowComments -b $iter < $file > ${file}.test 2>&1
+ diff ${DIFF_FLAGS} ${file}.gold ${file}.test
+ if [[ $? == 0 ]] ; then
+ if (( $iter == 31 )) ; then let testsSucceeded+=1 ; fi
+ else
+ success="FAILURE"
+ let iter=32
+ fi
+ let iter+=1
+ rm ${file}.test
+ done
+
+ echo $success
+ let testsTotal+=1
+done
+
+echo $testsSucceeded/$testsTotal tests successful
+
+if [[ $testsSucceeded != $testsTotal ]] ; then
+ exit 1
+fi
+
+exit 0
diff --git a/jcnf/yajl/yajl.c b/jcnf/yajl/yajl.c
new file mode 100644
index 0000000..b0dc991
--- /dev/null
+++ b/jcnf/yajl/yajl.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_parse.h"
+#include "yajl_lex.h"
+#include "yajl_parser.h"
+#include "yajl_alloc.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+const char *
+yajl_status_to_string(yajl_status stat)
+{
+ const char * statStr = "unknown";
+ switch (stat) {
+ case yajl_status_ok:
+ statStr = "ok, no error";
+ break;
+ case yajl_status_client_canceled:
+ statStr = "client canceled parse";
+ break;
+ case yajl_status_insufficient_data:
+ statStr = "eof was met before the parse could complete";
+ break;
+ case yajl_status_error:
+ statStr = "parse error";
+ break;
+ }
+ return statStr;
+}
+
+yajl_handle
+yajl_alloc(const yajl_callbacks * callbacks,
+ const yajl_parser_config * config,
+ const yajl_alloc_funcs * afs,
+ void * ctx)
+{
+ unsigned int allowComments = 0;
+ unsigned int validateUTF8 = 0;
+ yajl_handle hand = NULL;
+ yajl_alloc_funcs afsBuffer;
+
+ /* first order of business is to set up memory allocation routines */
+ if (afs != NULL) {
+ if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
+ {
+ return NULL;
+ }
+ } else {
+ yajl_set_default_alloc_funcs(&afsBuffer);
+ afs = &afsBuffer;
+ }
+
+ hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t));
+
+ /* copy in pointers to allocation routines */
+ memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
+
+ if (config != NULL) {
+ allowComments = config->allowComments;
+ validateUTF8 = config->checkUTF8;
+ }
+
+ hand->callbacks = callbacks;
+ hand->ctx = ctx;
+ hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8);
+ hand->errorOffset = 0;
+ hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
+ yajl_bs_init(hand->stateStack, &(hand->alloc));
+
+ yajl_bs_push(hand->stateStack, yajl_state_start);
+
+ return hand;
+}
+
+void
+yajl_free(yajl_handle handle)
+{
+ yajl_bs_free(handle->stateStack);
+ yajl_buf_free(handle->decodeBuf);
+ yajl_lex_free(handle->lexer);
+ YA_FREE(&(handle->alloc), handle);
+}
+
+yajl_status
+yajl_parse(yajl_handle hand, const unsigned char * jsonText,
+ unsigned int jsonTextLen)
+{
+ unsigned int offset = 0;
+ yajl_status status;
+ status = yajl_do_parse(hand, &offset, jsonText, jsonTextLen);
+ return status;
+}
+
+yajl_status
+yajl_parse_complete(yajl_handle hand)
+{
+ /* The particular case we want to handle is a trailing number.
+ * Further input consisting of digits could cause our interpretation
+ * of the number to change (buffered "1" but "2" comes in).
+ * A very simple approach to this is to inject whitespace to terminate
+ * any number in the lex buffer.
+ */
+ return yajl_parse(hand, (const unsigned char *)" ", 1);
+}
+
+unsigned char *
+yajl_get_error(yajl_handle hand, int verbose,
+ const unsigned char * jsonText, unsigned int jsonTextLen)
+{
+ return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose);
+}
+
+void
+yajl_free_error(yajl_handle hand, unsigned char * str)
+{
+ /* use memory allocation functions if set */
+ YA_FREE(&(hand->alloc), str);
+}
+
+/* XXX: add utility routines to parse from file */
diff --git a/jcnf/yajl/yajl_alloc.c b/jcnf/yajl/yajl_alloc.c
new file mode 100644
index 0000000..0b4bf37
--- /dev/null
+++ b/jcnf/yajl/yajl_alloc.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file yajl_alloc.h
+ * default memory allocation routines for yajl which use malloc/realloc and
+ * free
+ */
+
+#include "yajl_alloc.h"
+#include <stdlib.h>
+
+static void * yajl_internal_malloc(void *ctx, unsigned int sz)
+{
+ return malloc(sz);
+}
+
+static void * yajl_internal_realloc(void *ctx, void * previous,
+ unsigned int sz)
+{
+ return realloc(previous, sz);
+}
+
+static void yajl_internal_free(void *ctx, void * ptr)
+{
+ free(ptr);
+}
+
+void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf)
+{
+ yaf->malloc = yajl_internal_malloc;
+ yaf->free = yajl_internal_free;
+ yaf->realloc = yajl_internal_realloc;
+ yaf->ctx = NULL;
+}
+
diff --git a/jcnf/yajl/yajl_alloc.h b/jcnf/yajl/yajl_alloc.h
new file mode 100644
index 0000000..988a6c5
--- /dev/null
+++ b/jcnf/yajl/yajl_alloc.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file yajl_alloc.h
+ * default memory allocation routines for yajl which use malloc/realloc and
+ * free
+ */
+
+#ifndef __YAJL_ALLOC_H__
+#define __YAJL_ALLOC_H__
+
+#include "yajl_common.h"
+
+#define YA_MALLOC(afs, sz) (afs)->malloc((afs)->ctx, (sz))
+#define YA_FREE(afs, ptr) (afs)->free((afs)->ctx, (ptr))
+#define YA_REALLOC(afs, ptr, sz) (afs)->realloc((afs)->ctx, (ptr), (sz))
+
+void yajl_set_default_alloc_funcs(yajl_alloc_funcs * yaf);
+
+#endif
diff --git a/jcnf/yajl/yajl_buf.c b/jcnf/yajl/yajl_buf.c
new file mode 100644
index 0000000..97f1ced
--- /dev/null
+++ b/jcnf/yajl/yajl_buf.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_buf.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define YAJL_BUF_INIT_SIZE 2048
+
+struct yajl_buf_t {
+ unsigned int len;
+ unsigned int used;
+ unsigned char * data;
+ yajl_alloc_funcs * alloc;
+};
+
+static
+void yajl_buf_ensure_available(yajl_buf buf, unsigned int want)
+{
+ unsigned int need;
+
+ assert(buf != NULL);
+
+ /* first call */
+ if (buf->data == NULL) {
+ buf->len = YAJL_BUF_INIT_SIZE;
+ buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len);
+ buf->data[0] = 0;
+ }
+
+ need = buf->len;
+
+ while (want >= (need - buf->used)) need <<= 1;
+
+ if (need != buf->len) {
+ buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need);
+ buf->len = need;
+ }
+}
+
+yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc)
+{
+ yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t));
+ memset((void *) b, 0, sizeof(struct yajl_buf_t));
+ b->alloc = alloc;
+ return b;
+}
+
+void yajl_buf_free(yajl_buf buf)
+{
+ assert(buf != NULL);
+ if (buf->data) YA_FREE(buf->alloc, buf->data);
+ YA_FREE(buf->alloc, buf);
+}
+
+void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len)
+{
+ yajl_buf_ensure_available(buf, len);
+ if (len > 0) {
+ assert(data != NULL);
+ memcpy(buf->data + buf->used, data, len);
+ buf->used += len;
+ buf->data[buf->used] = 0;
+ }
+}
+
+void yajl_buf_clear(yajl_buf buf)
+{
+ buf->used = 0;
+ if (buf->data) buf->data[buf->used] = 0;
+}
+
+const unsigned char * yajl_buf_data(yajl_buf buf)
+{
+ return buf->data;
+}
+
+unsigned int yajl_buf_len(yajl_buf buf)
+{
+ return buf->used;
+}
+
+void
+yajl_buf_truncate(yajl_buf buf, unsigned int len)
+{
+ assert(len <= buf->used);
+ buf->used = len;
+}
diff --git a/jcnf/yajl/yajl_buf.h b/jcnf/yajl/yajl_buf.h
new file mode 100644
index 0000000..e5b2c82
--- /dev/null
+++ b/jcnf/yajl/yajl_buf.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __YAJL_BUF_H__
+#define __YAJL_BUF_H__
+
+#include "yajl_common.h"
+#include "yajl_alloc.h"
+
+/*
+ * Implementation/performance notes. If this were moved to a header
+ * only implementation using #define's where possible we might be
+ * able to sqeeze a little performance out of the guy by killing function
+ * call overhead. YMMV.
+ */
+
+/**
+ * yajl_buf is a buffer with exponential growth. the buffer ensures that
+ * you are always null padded.
+ */
+typedef struct yajl_buf_t * yajl_buf;
+
+/* allocate a new buffer */
+yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc);
+
+/* free the buffer */
+void yajl_buf_free(yajl_buf buf);
+
+/* append a number of bytes to the buffer */
+void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len);
+
+/* empty the buffer */
+void yajl_buf_clear(yajl_buf buf);
+
+/* get a pointer to the beginning of the buffer */
+const unsigned char * yajl_buf_data(yajl_buf buf);
+
+/* get the length of the buffer */
+unsigned int yajl_buf_len(yajl_buf buf);
+
+/* truncate the buffer */
+void yajl_buf_truncate(yajl_buf buf, unsigned int len);
+
+#endif
diff --git a/jcnf/yajl/yajl_bytestack.h b/jcnf/yajl/yajl_bytestack.h
new file mode 100644
index 0000000..9ce192f
--- /dev/null
+++ b/jcnf/yajl/yajl_bytestack.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * A header only implementation of a simple stack of bytes, used in YAJL
+ * to maintain parse state.
+ */
+
+#ifndef __YAJL_BYTESTACK_H__
+#define __YAJL_BYTESTACK_H__
+
+#include "yajl_common.h"
+
+#define YAJL_BS_INC 128
+
+typedef struct yajl_bytestack_t
+{
+ unsigned char * stack;
+ unsigned int size;
+ unsigned int used;
+ yajl_alloc_funcs * yaf;
+} yajl_bytestack;
+
+/* initialize a bytestack */
+#define yajl_bs_init(obs, _yaf) { \
+ (obs).stack = NULL; \
+ (obs).size = 0; \
+ (obs).used = 0; \
+ (obs).yaf = (_yaf); \
+ } \
+
+
+/* initialize a bytestack */
+#define yajl_bs_free(obs) \
+ if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack);
+
+#define yajl_bs_current(obs) \
+ (assert((obs).used > 0), (obs).stack[(obs).used - 1])
+
+#define yajl_bs_push(obs, byte) { \
+ if (((obs).size - (obs).used) == 0) { \
+ (obs).size += YAJL_BS_INC; \
+ (obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\
+ (void *) (obs).stack, (obs).size);\
+ } \
+ (obs).stack[((obs).used)++] = (byte); \
+}
+
+/* removes the top item of the stack, returns nothing */
+#define yajl_bs_pop(obs) { ((obs).used)--; }
+
+#define yajl_bs_set(obs, byte) \
+ (obs).stack[((obs).used) - 1] = (byte);
+
+
+#endif
diff --git a/jcnf/yajl/yajl_common.h b/jcnf/yajl/yajl_common.h
new file mode 100644
index 0000000..9ad5eb4
--- /dev/null
+++ b/jcnf/yajl/yajl_common.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __YAJL_COMMON_H__
+#define __YAJL_COMMON_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define YAJL_MAX_DEPTH 128
+
+/* msft dll export gunk. To build a DLL on windows, you
+ * must define WIN32, YAJL_SHARED, and YAJL_BUILD. To use a shared
+ * DLL, you must define YAJL_SHARED and WIN32 */
+#if defined(WIN32) && defined(YAJL_SHARED)
+# ifdef YAJL_BUILD
+# define YAJL_API __declspec(dllexport)
+# else
+# define YAJL_API __declspec(dllimport)
+# endif
+#else
+# define YAJL_API
+#endif
+
+/** pointer to a malloc function, supporting client overriding memory
+ * allocation routines */
+typedef void * (*yajl_malloc_func)(void *ctx, unsigned int sz);
+
+/** pointer to a free function, supporting client overriding memory
+ * allocation routines */
+typedef void (*yajl_free_func)(void *ctx, void * ptr);
+
+/** pointer to a realloc function which can resize an allocation. */
+typedef void * (*yajl_realloc_func)(void *ctx, void * ptr, unsigned int sz);
+
+/** A structure which can be passed to yajl_*_alloc routines to allow the
+ * client to specify memory allocation functions to be used. */
+typedef struct
+{
+ /** pointer to a function that can allocate uninitialized memory */
+ yajl_malloc_func malloc;
+ /** pointer to a function that can resize memory allocations */
+ yajl_realloc_func realloc;
+ /** pointer to a function that can free memory allocated using
+ * reallocFunction or mallocFunction */
+ yajl_free_func free;
+ /** a context pointer that will be passed to above allocation routines */
+ void * ctx;
+} yajl_alloc_funcs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/jcnf/yajl/yajl_encode.c b/jcnf/yajl/yajl_encode.c
new file mode 100644
index 0000000..184277b
--- /dev/null
+++ b/jcnf/yajl/yajl_encode.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_encode.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+static void CharToHex(unsigned char c, char * hexBuf)
+{
+ const char * hexchar = "0123456789ABCDEF";
+ hexBuf[0] = hexchar[c >> 4];
+ hexBuf[1] = hexchar[c & 0x0F];
+}
+
+void
+yajl_string_encode(yajl_buf buf, const unsigned char * str,
+ unsigned int len)
+{
+ unsigned int beg = 0;
+ unsigned int end = 0;
+ char hexBuf[7];
+ hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0';
+ hexBuf[6] = 0;
+
+ while (end < len) {
+ const char * escaped = NULL;
+ switch (str[end]) {
+ case '\r': escaped = "\\r"; break;
+ case '\n': escaped = "\\n"; break;
+ case '\\': escaped = "\\\\"; break;
+ /* case '/': escaped = "\\/"; break; */
+ case '"': escaped = "\\\""; break;
+ case '\f': escaped = "\\f"; break;
+ case '\b': escaped = "\\b"; break;
+ case '\t': escaped = "\\t"; break;
+ default:
+ if ((unsigned char) str[end] < 32) {
+ CharToHex(str[end], hexBuf + 4);
+ escaped = hexBuf;
+ }
+ break;
+ }
+ if (escaped != NULL) {
+ yajl_buf_append(buf, str + beg, end - beg);
+ yajl_buf_append(buf, escaped, strlen(escaped));
+ beg = ++end;
+ } else {
+ ++end;
+ }
+ }
+ yajl_buf_append(buf, str + beg, end - beg);
+}
+
+static void hexToDigit(unsigned int * val, const unsigned char * hex)
+{
+ unsigned int i;
+ for (i=0;i<4;i++) {
+ unsigned char c = hex[i];
+ if (c >= 'A') c = (c & ~0x20) - 7;
+ c -= '0';
+ assert(!(c & 0xF0));
+ *val = (*val << 4) | c;
+ }
+}
+
+static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf)
+{
+ if (codepoint < 0x80) {
+ utf8Buf[0] = (char) codepoint;
+ utf8Buf[1] = 0;
+ } else if (codepoint < 0x0800) {
+ utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0);
+ utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80);
+ utf8Buf[2] = 0;
+ } else if (codepoint < 0x10000) {
+ utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0);
+ utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80);
+ utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80);
+ utf8Buf[3] = 0;
+ } else if (codepoint < 0x200000) {
+ utf8Buf[0] =(char)((codepoint >> 18) | 0xF0);
+ utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80);
+ utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80);
+ utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80);
+ utf8Buf[4] = 0;
+ } else {
+ utf8Buf[0] = '?';
+ utf8Buf[1] = 0;
+ }
+}
+
+void yajl_string_decode(yajl_buf buf, const unsigned char * str,
+ unsigned int len)
+{
+ unsigned int beg = 0;
+ unsigned int end = 0;
+
+ while (end < len) {
+ if (str[end] == '\\') {
+ char utf8Buf[5];
+ const char * unescaped = "?";
+ yajl_buf_append(buf, str + beg, end - beg);
+ switch (str[++end]) {
+ case 'r': unescaped = "\r"; break;
+ case 'n': unescaped = "\n"; break;
+ case '\\': unescaped = "\\"; break;
+ case '/': unescaped = "/"; break;
+ case '"': unescaped = "\""; break;
+ case 'f': unescaped = "\f"; break;
+ case 'b': unescaped = "\b"; break;
+ case 't': unescaped = "\t"; break;
+ case 'u': {
+ unsigned int codepoint = 0;
+ hexToDigit(&codepoint, str + ++end);
+ end+=3;
+ /* check if this is a surrogate */
+ if ((codepoint & 0xFC00) == 0xD800) {
+ end++;
+ if (str[end] == '\\' && str[end + 1] == 'u') {
+ unsigned int surrogate = 0;
+ hexToDigit(&surrogate, str + end + 2);
+ codepoint =
+ (((codepoint & 0x3F) << 10) |
+ ((((codepoint >> 6) & 0xF) + 1) << 16) |
+ (surrogate & 0x3FF));
+ end += 5;
+ } else {
+ unescaped = "?";
+ break;
+ }
+ }
+
+ Utf32toUtf8(codepoint, utf8Buf);
+ unescaped = utf8Buf;
+ break;
+ }
+ default:
+ assert("this should never happen" == NULL);
+ }
+ yajl_buf_append(buf, unescaped, strlen(unescaped));
+ beg = ++end;
+ } else {
+ end++;
+ }
+ }
+ yajl_buf_append(buf, str + beg, end - beg);
+}
diff --git a/jcnf/yajl/yajl_encode.h b/jcnf/yajl/yajl_encode.h
new file mode 100644
index 0000000..8bd01af
--- /dev/null
+++ b/jcnf/yajl/yajl_encode.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __YAJL_ENCODE_H__
+#define __YAJL_ENCODE_H__
+
+#include "yajl_buf.h"
+
+void yajl_string_encode(yajl_buf buf, const unsigned char * str,
+ unsigned int length);
+
+void yajl_string_decode(yajl_buf buf, const unsigned char * str,
+ unsigned int length);
+
+#endif
diff --git a/jcnf/yajl/yajl_gen.c b/jcnf/yajl/yajl_gen.c
new file mode 100644
index 0000000..a400176
--- /dev/null
+++ b/jcnf/yajl/yajl_gen.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_gen.h"
+#include "yajl_buf.h"
+#include "yajl_encode.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+typedef enum {
+ yajl_gen_start,
+ yajl_gen_map_start,
+ yajl_gen_map_key,
+ yajl_gen_map_val,
+ yajl_gen_array_start,
+ yajl_gen_in_array,
+ yajl_gen_complete,
+ yajl_gen_error
+} yajl_gen_state;
+
+struct yajl_gen_t
+{
+ unsigned int depth;
+ unsigned int pretty;
+ const char * indentString;
+ yajl_gen_state state[YAJL_MAX_DEPTH];
+ yajl_buf buf;
+ unsigned char *pendingComment;
+ unsigned int pendingLen; /* Length of pending comment */
+ int pendingCpp; /* NZ if comment is C++ style, Z if C */
+ /* memory allocation routines */
+ yajl_alloc_funcs alloc;
+};
+
+yajl_gen
+yajl_gen_alloc(const yajl_gen_config * config,
+ const yajl_alloc_funcs * afs)
+{
+ yajl_gen g = NULL;
+ yajl_alloc_funcs afsBuffer;
+
+ /* first order of business is to set up memory allocation routines */
+ if (afs != NULL) {
+ if (afs->malloc == NULL || afs->realloc == NULL || afs->free == NULL)
+ {
+ return NULL;
+ }
+ } else {
+ yajl_set_default_alloc_funcs(&afsBuffer);
+ afs = &afsBuffer;
+ }
+
+ g = (yajl_gen) YA_MALLOC(afs, sizeof(struct yajl_gen_t));
+ memset((void *) g, 0, sizeof(struct yajl_gen_t));
+ /* copy in pointers to allocation routines */
+ memcpy((void *) &(g->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
+
+ if (config) {
+ g->pretty = config->beautify;
+ g->indentString = config->indentString ? config->indentString : " ";
+ }
+ g->buf = yajl_buf_alloc(&(g->alloc));
+
+ return g;
+}
+
+void
+yajl_gen_free(yajl_gen g)
+{
+ yajl_buf_free(g->buf);
+ YA_FREE(&(g->alloc), g);
+}
+
+#define INSERT_EOL \
+ if (g->pretty || g->pendingComment != NULL) \
+ yajl_insert_eol(g);
+
+#define INSERT_SEP \
+ if (g->state[g->depth] == yajl_gen_map_key || \
+ g->state[g->depth] == yajl_gen_in_array) { \
+ yajl_buf_append(g->buf, ",", 1); \
+ INSERT_EOL; \
+ } else if (g->state[g->depth] == yajl_gen_map_val) { \
+ yajl_buf_append(g->buf, ":", 1); \
+ if (g->pretty) yajl_buf_append(g->buf, " ", 1); \
+ }
+
+#define INSERT_WHITESPACE \
+ if (g->pretty) { \
+ if (g->state[g->depth] != yajl_gen_map_val) { \
+ unsigned int _i; \
+ for (_i=0;_i<g->depth;_i++) \
+ yajl_buf_append(g->buf, g->indentString, \
+ strlen(g->indentString)); \
+ } \
+ }
+
+#define INSERT_SOME_WHITESPACE \
+ if (g->pretty) { \
+ if (g->state[g->depth] != yajl_gen_map_val) { \
+ yajl_buf_append(g->buf, g->indentString, \
+ strlen(g->indentString)); \
+ } \
+ }
+
+#define ENSURE_NOT_KEY \
+ if (g->state[g->depth] == yajl_gen_map_key) { \
+ return yajl_gen_keys_must_be_strings; \
+ } \
+
+/* check that we're not complete, or in error state. in a valid state
+ * to be generating */
+#define ENSURE_VALID_STATE \
+ if (g->state[g->depth] == yajl_gen_error) { \
+ return yajl_gen_in_error_state;\
+ } else if (g->state[g->depth] == yajl_gen_complete) { \
+ return yajl_gen_generation_complete; \
+ }
+
+#define INCREMENT_DEPTH \
+ if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
+
+#define APPENDED_ATOM \
+ switch (g->state[g->depth]) { \
+ case yajl_gen_start: \
+ g->state[g->depth] = yajl_gen_complete; \
+ break; \
+ case yajl_gen_map_start: \
+ case yajl_gen_map_key: \
+ g->state[g->depth] = yajl_gen_map_val; \
+ break; \
+ case yajl_gen_array_start: \
+ g->state[g->depth] = yajl_gen_in_array; \
+ break; \
+ case yajl_gen_map_val: \
+ g->state[g->depth] = yajl_gen_map_key; \
+ break; \
+ default: \
+ break; \
+ } \
+
+#define FINAL_NEWLINE \
+ if (g->pretty && g->state[g->depth] == yajl_gen_complete) \
+ INSERT_EOL
+
+/* Insert an end of line, and take care of any */
+/* pending comments */
+static void yajl_insert_eol(yajl_gen g) {
+ if (g->pendingComment != NULL) {
+ INSERT_SOME_WHITESPACE;
+ if (g->pendingCpp)
+ yajl_buf_append(g->buf, "//", 2);
+ else
+ yajl_buf_append(g->buf, "/*", 2);
+ yajl_string_encode(g->buf, g->pendingComment, g->pendingLen);
+ if (!g->pendingCpp)
+ yajl_buf_append(g->buf, "*/", 2);
+ free(g->pendingComment);
+ g->pendingComment = NULL;
+ g->pendingLen = 0;
+ g->pendingCpp = 0;
+ }
+ yajl_buf_append(g->buf, "\n", 1);
+}
+
+/* Insert a comment at the end of the line. Append if there is already */
+/* one pending. */
+static void yajl_insert_pending_comment(
+yajl_gen g, const unsigned char * str, unsigned int len, int cpp) {
+ if (g->pendingComment != NULL) {
+ unsigned int tlen = g->pendingLen + 0 + len;
+ unsigned char *pendingComment;
+ pendingComment = (unsigned char *) realloc(g->pendingComment, sizeof(char) * tlen);
+ memcpy(pendingComment + g->pendingLen + 0, str, len);
+ g->pendingComment = pendingComment;
+ g->pendingLen = tlen;
+ } else {
+ g->pendingComment = (unsigned char *) malloc(sizeof(char) * len);
+ memcpy(g->pendingComment, str, len);
+ g->pendingLen = len;
+ }
+ g->pendingCpp = cpp;
+}
+
+yajl_gen_status
+yajl_gen_integer(yajl_gen g, long int number)
+{
+ char i[32];
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ sprintf(i, "%ld", number);
+ yajl_buf_append(g->buf, i, strlen(i));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_double(yajl_gen g, double number)
+{
+ char i[32];
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ sprintf(i, "%g", number);
+ yajl_buf_append(g->buf, i, strlen(i));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_number(yajl_gen g, const char * s, unsigned int l)
+{
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, s, l);
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_string(yajl_gen g, const unsigned char * str,
+ unsigned int len)
+{
+ ENSURE_VALID_STATE; INSERT_SEP; INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, "\"", 1);
+ yajl_string_encode(g->buf, str, len);
+ yajl_buf_append(g->buf, "\"", 1);
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_null(yajl_gen g)
+{
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, "null", strlen("null"));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_bool(yajl_gen g, int boolean)
+{
+ const char * val = boolean ? "true" : "false";
+
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, val, strlen(val));
+ APPENDED_ATOM;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_map_open(yajl_gen g)
+{
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ INCREMENT_DEPTH;
+
+ g->state[g->depth] = yajl_gen_map_start;
+ yajl_buf_append(g->buf, "{", 1);
+ INSERT_EOL;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_map_close(yajl_gen g)
+{
+ ENSURE_VALID_STATE;
+ (g->depth)--;
+ INSERT_EOL;
+ APPENDED_ATOM;
+ INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, "}", 1);
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_array_open(yajl_gen g)
+{
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
+ INCREMENT_DEPTH;
+ g->state[g->depth] = yajl_gen_array_start;
+ yajl_buf_append(g->buf, "[", 1);
+ INSERT_EOL;
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_array_close(yajl_gen g)
+{
+ ENSURE_VALID_STATE;
+ INSERT_EOL;
+ (g->depth)--;
+ APPENDED_ATOM;
+ INSERT_WHITESPACE;
+ yajl_buf_append(g->buf, "]", 1);
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_c_comment(yajl_gen g, const unsigned char * str,
+ unsigned int len, int dlytoeol)
+{
+ ENSURE_VALID_STATE;
+ if (dlytoeol) {
+ yajl_insert_pending_comment(g, str, len, 0);
+ } else {
+ if (g->pretty)
+ yajl_buf_append(g->buf, " /*", 3);
+ else
+ yajl_buf_append(g->buf, "/*", 2);
+ yajl_string_encode(g->buf, str, len);
+ if (g->pretty)
+ yajl_buf_append(g->buf, "*/ ", 3);
+ else
+ yajl_buf_append(g->buf, "*/", 2);
+ }
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_cpp_comment(yajl_gen g, const unsigned char * str,
+ unsigned int len)
+{
+ ENSURE_VALID_STATE;
+ yajl_insert_pending_comment(g, str, len, 1);
+ FINAL_NEWLINE;
+ return yajl_gen_status_ok;
+}
+
+yajl_gen_status
+yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf,
+ unsigned int * len)
+{
+ *buf = yajl_buf_data(g->buf);
+ *len = yajl_buf_len(g->buf);
+ return yajl_gen_status_ok;
+}
+
+void
+yajl_gen_clear(yajl_gen g)
+{
+ yajl_buf_clear(g->buf);
+}
diff --git a/jcnf/yajl/yajl_gen.h b/jcnf/yajl/yajl_gen.h
new file mode 100644
index 0000000..5bde0e8
--- /dev/null
+++ b/jcnf/yajl/yajl_gen.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file yajl_gen.h
+ * Interface to YAJL's JSON generation facilities.
+ */
+
+#include "yajl_common.h"
+
+#ifndef __YAJL_GEN_H__
+#define __YAJL_GEN_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /** generator status codes */
+ typedef enum {
+ /** no error */
+ yajl_gen_status_ok = 0,
+ /** at a point where a map key is generated, a function other than
+ * yajl_gen_string was called */
+ yajl_gen_keys_must_be_strings,
+ /** YAJL's maximum generation depth was exceeded. see
+ * YAJL_MAX_DEPTH */
+ yajl_max_depth_exceeded,
+ /** A generator function (yajl_gen_XXX) was called while in an error
+ * state */
+ yajl_gen_in_error_state,
+ /** A complete JSON document has been generated */
+ yajl_gen_generation_complete
+ } yajl_gen_status;
+
+ /** an opaque handle to a generator */
+ typedef struct yajl_gen_t * yajl_gen;
+
+ /** configuration structure for the generator */
+ typedef struct {
+ /** generate indented (beautiful) output */
+ unsigned int beautify;
+ /** an opportunity to define an indent string. such as \\t or
+ * some number of spaces. default is four spaces ' '. This
+ * member is only relevant when beautify is true */
+ const char * indentString;
+ } yajl_gen_config;
+
+ /** allocate a generator handle
+ * \param config a pointer to a structure containing parameters which
+ * configure the behavior of the json generator
+ * \param allocFuncs an optional pointer to a structure which allows
+ * the client to overide the memory allocation
+ * used by yajl. May be NULL, in which case
+ * malloc/free/realloc will be used.
+ *
+ * \returns an allocated handle on success, NULL on failure (bad params)
+ */
+ yajl_gen YAJL_API yajl_gen_alloc(const yajl_gen_config * config,
+ const yajl_alloc_funcs * allocFuncs);
+
+ /** free a generator handle */
+ void YAJL_API yajl_gen_free(yajl_gen handle);
+
+ yajl_gen_status YAJL_API yajl_gen_integer(yajl_gen hand, long int number);
+ yajl_gen_status YAJL_API yajl_gen_double(yajl_gen hand, double number);
+ yajl_gen_status YAJL_API yajl_gen_number(yajl_gen hand,
+ const char * num,
+ unsigned int len);
+ yajl_gen_status YAJL_API yajl_gen_string(yajl_gen hand,
+ const unsigned char * str,
+ unsigned int len);
+ yajl_gen_status YAJL_API yajl_gen_null(yajl_gen hand);
+ yajl_gen_status YAJL_API yajl_gen_bool(yajl_gen hand, int boolean);
+ yajl_gen_status YAJL_API yajl_gen_map_open(yajl_gen hand);
+ yajl_gen_status YAJL_API yajl_gen_map_close(yajl_gen hand);
+ yajl_gen_status YAJL_API yajl_gen_array_open(yajl_gen hand);
+ yajl_gen_status YAJL_API yajl_gen_array_close(yajl_gen hand);
+ yajl_gen_status YAJL_API yajl_gen_c_comment(yajl_gen hand,
+ const unsigned char * str,
+ unsigned int len, int dlytoeol);
+ yajl_gen_status YAJL_API yajl_gen_cpp_comment(yajl_gen hand,
+ const unsigned char * str,
+ unsigned int len);
+
+ /** access the null terminated generator buffer. If incrementally
+ * outputing JSON, one should call yajl_gen_clear to clear the
+ * buffer. This allows stream generation. */
+ yajl_gen_status YAJL_API yajl_gen_get_buf(yajl_gen hand,
+ const unsigned char ** buf,
+ unsigned int * len);
+
+ /** clear yajl's output buffer, but maintain all internal generation
+ * state. This function will not "reset" the generator state, and is
+ * intended to enable incremental JSON outputing. */
+ void YAJL_API yajl_gen_clear(yajl_gen hand);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/jcnf/yajl/yajl_lex.c b/jcnf/yajl/yajl_lex.c
new file mode 100644
index 0000000..56e563e
--- /dev/null
+++ b/jcnf/yajl/yajl_lex.c
@@ -0,0 +1,753 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_lex.h"
+#include "yajl_buf.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+
+#ifdef YAJL_LEXER_DEBUG
+static const char *
+tokToStr(yajl_tok tok)
+{
+ switch (tok) {
+ case yajl_tok_bool: return "bool";
+ case yajl_tok_colon: return "colon";
+ case yajl_tok_comma: return "comma";
+ case yajl_tok_eof: return "eof";
+ case yajl_tok_error: return "error";
+ case yajl_tok_left_brace: return "brace";
+ case yajl_tok_left_bracket: return "bracket";
+ case yajl_tok_null: return "null";
+ case yajl_tok_integer: return "integer";
+ case yajl_tok_double: return "double";
+ case yajl_tok_right_brace: return "brace";
+ case yajl_tok_right_bracket: return "bracket";
+ case yajl_tok_string: return "string";
+ case yajl_tok_string_with_escapes: return "string_with_escapes";
+ case yajl_tok_c_comment: return "C comment";
+ case yajl_tok_cpp_comment: return "C++ comment";
+ }
+ return "unknown";
+}
+#endif
+
+/* Impact of the stream parsing feature on the lexer:
+ *
+ * YAJL support stream parsing. That is, the ability to parse the first
+ * bits of a chunk of JSON before the last bits are available (still on
+ * the network or disk). This makes the lexer more complex. The
+ * responsibility of the lexer is to handle transparently the case where
+ * a chunk boundary falls in the middle of a token. This is
+ * accomplished is via a buffer and a character reading abstraction.
+ *
+ * Overview of implementation
+ *
+ * When we lex to end of input string before end of token is hit, we
+ * copy all of the input text composing the token into our lexBuf.
+ *
+ * Every time we read a character, we do so through the readChar function.
+ * readChar's responsibility is to handle pulling all chars from the buffer
+ * before pulling chars from input text
+ */
+
+struct yajl_lexer_t {
+ /* the overal line and char offset into the data */
+ unsigned int lineOff;
+ unsigned int charOff;
+
+ /* error */
+ yajl_lex_error error;
+
+ /* a input buffer to handle the case where a token is spread over
+ * multiple chunks */
+ yajl_buf buf;
+
+ /* in the case where we have data in the lexBuf, bufOff holds
+ * the current offset into the lexBuf. */
+ unsigned int bufOff;
+
+ /* are we using the lex buf? */
+ unsigned int bufInUse;
+
+ /* shall we allow comments? */
+ unsigned int allowComments;
+
+ /* shall we validate utf8 inside strings? */
+ unsigned int validateUTF8;
+
+ yajl_alloc_funcs * alloc;
+};
+
+#define readChar(lxr, txt, off) \
+ (((lxr)->bufInUse && yajl_buf_len((lxr)->buf) && lxr->bufOff < yajl_buf_len((lxr)->buf)) ? \
+ (*((const unsigned char *) yajl_buf_data((lxr)->buf) + ((lxr)->bufOff)++)) : \
+ ((txt)[(*(off))++]))
+
+#define unreadChar(lxr, off) ((*(off) > 0) ? (*(off))-- : ((lxr)->bufOff--))
+
+yajl_lexer
+yajl_lex_alloc(yajl_alloc_funcs * alloc,
+ unsigned int allowComments, unsigned int validateUTF8)
+{
+ yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t));
+ memset((void *) lxr, 0, sizeof(struct yajl_lexer_t));
+ lxr->buf = yajl_buf_alloc(alloc);
+ lxr->allowComments = allowComments;
+ lxr->validateUTF8 = validateUTF8;
+ lxr->alloc = alloc;
+ return lxr;
+}
+
+void
+yajl_lex_free(yajl_lexer lxr)
+{
+ yajl_buf_free(lxr->buf);
+ YA_FREE(lxr->alloc, lxr);
+ return;
+}
+
+/* a lookup table which lets us quickly determine three things:
+ * VEC - valid escaped conrol char
+ * IJC - invalid json char
+ * VHC - valid hex char
+ * note. the solidus '/' may be escaped or not.
+ * note. the
+ */
+#define VEC 1
+#define IJC 2
+#define VHC 4
+static const char charLookupTable[256] =
+{
+/*00*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
+/*08*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
+/*10*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
+/*18*/ IJC , IJC , IJC , IJC , IJC , IJC , IJC , IJC ,
+
+/*20*/ 0 , 0 , VEC|IJC, 0 , 0 , 0 , 0 , 0 ,
+/*28*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , VEC ,
+/*30*/ VHC , VHC , VHC , VHC , VHC , VHC , VHC , VHC ,
+/*38*/ VHC , VHC , 0 , 0 , 0 , 0 , 0 , 0 ,
+
+/*40*/ 0 , VHC , VHC , VHC , VHC , VHC , VHC , 0 ,
+/*48*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+/*50*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+/*58*/ 0 , 0 , 0 , 0 , VEC|IJC, 0 , 0 , 0 ,
+
+/*60*/ 0 , VHC , VEC|VHC, VHC , VHC , VHC , VEC|VHC, 0 ,
+/*68*/ 0 , 0 , 0 , 0 , 0 , 0 , VEC , 0 ,
+/*70*/ 0 , 0 , VEC , 0 , VEC , 0 , 0 , 0 ,
+/*78*/ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+
+/* include these so we don't have to always check the range of the char */
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
+};
+
+/** process a variable length utf8 encoded codepoint.
+ *
+ * returns:
+ * yajl_tok_string - if valid utf8 char was parsed and offset was
+ * advanced
+ * yajl_tok_eof - if end of input was hit before validation could
+ * complete
+ * yajl_tok_error - if invalid utf8 was encountered
+ *
+ * NOTE: on error the offset will point to the first char of the
+ * invalid utf8 */
+#define UTF8_CHECK_EOF if (*offset >= jsonTextLen) { return yajl_tok_eof; }
+
+static yajl_tok
+yajl_lex_utf8_char(yajl_lexer lexer, const unsigned char * jsonText,
+ unsigned int jsonTextLen, unsigned int * offset,
+ unsigned char curChar)
+{
+ if (curChar <= 0x7f) {
+ /* single byte */
+ return yajl_tok_string;
+ } else if ((curChar >> 5) == 0x6) {
+ /* two byte */
+ UTF8_CHECK_EOF;
+ curChar = readChar(lexer, jsonText, offset);
+ if ((curChar >> 6) == 0x2) return yajl_tok_string;
+ } else if ((curChar >> 4) == 0x0e) {
+ /* three byte */
+ UTF8_CHECK_EOF;
+ curChar = readChar(lexer, jsonText, offset);
+ if ((curChar >> 6) == 0x2) {
+ UTF8_CHECK_EOF;
+ curChar = readChar(lexer, jsonText, offset);
+ if ((curChar >> 6) == 0x2) return yajl_tok_string;
+ }
+ } else if ((curChar >> 3) == 0x1e) {
+ /* four byte */
+ UTF8_CHECK_EOF;
+ curChar = readChar(lexer, jsonText, offset);
+ if ((curChar >> 6) == 0x2) {
+ UTF8_CHECK_EOF;
+ curChar = readChar(lexer, jsonText, offset);
+ if ((curChar >> 6) == 0x2) {
+ UTF8_CHECK_EOF;
+ curChar = readChar(lexer, jsonText, offset);
+ if ((curChar >> 6) == 0x2) return yajl_tok_string;
+ }
+ }
+ }
+
+ return yajl_tok_error;
+}
+
+/* lex a string. input is the lexer, pointer to beginning of
+ * json text, and start of string (offset).
+ * a token is returned which has the following meanings:
+ * yajl_tok_string: lex of string was successful. offset points to
+ * terminating '"'.
+ * yajl_tok_eof: end of text was encountered before we could complete
+ * the lex.
+ * yajl_tok_error: embedded in the string were unallowable chars. offset
+ * points to the offending char
+ */
+#define STR_CHECK_EOF \
+if (*offset >= jsonTextLen) { \
+ tok = yajl_tok_eof; \
+ goto finish_string_lex; \
+}
+
+static yajl_tok
+yajl_lex_string(yajl_lexer lexer, const unsigned char * jsonText,
+ unsigned int jsonTextLen, unsigned int * offset)
+{
+ yajl_tok tok = yajl_tok_error;
+ int hasEscapes = 0;
+
+ for (;;) {
+ unsigned char curChar;
+
+ STR_CHECK_EOF;
+
+ curChar = readChar(lexer, jsonText, offset);
+
+ /* quote terminates */
+ if (curChar == '"') {
+ tok = yajl_tok_string;
+ break;
+ }
+ /* backslash escapes a set of control chars, */
+ else if (curChar == '\\') {
+ hasEscapes = 1;
+ STR_CHECK_EOF;
+
+ /* special case \u */
+ curChar = readChar(lexer, jsonText, offset);
+ if (curChar == 'u') {
+ unsigned int i = 0;
+
+ for (i=0;i<4;i++) {
+ STR_CHECK_EOF;
+ curChar = readChar(lexer, jsonText, offset);
+ if (!(charLookupTable[curChar] & VHC)) {
+ /* back up to offending char */
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_string_invalid_hex_char;
+ goto finish_string_lex;
+ }
+ }
+ } else if (!(charLookupTable[curChar] & VEC)) {
+ /* back up to offending char */
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_string_invalid_escaped_char;
+ goto finish_string_lex;
+ }
+ }
+ /* when not validating UTF8 it's a simple table lookup to determine
+ * if the present character is invalid */
+ else if(charLookupTable[curChar] & IJC) {
+ /* back up to offending char */
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_string_invalid_json_char;
+ goto finish_string_lex;
+ }
+ /* when in validate UTF8 mode we need to do some extra work */
+ else if (lexer->validateUTF8) {
+ yajl_tok t = yajl_lex_utf8_char(lexer, jsonText, jsonTextLen,
+ offset, curChar);
+
+ if (t == yajl_tok_eof) {
+ tok = yajl_tok_eof;
+ goto finish_string_lex;
+ } else if (t == yajl_tok_error) {
+ lexer->error = yajl_lex_string_invalid_utf8;
+ goto finish_string_lex;
+ }
+ }
+ /* accept it, and move on */
+ }
+ finish_string_lex:
+ /* tell our buddy, the parser, wether he needs to process this string
+ * again */
+ if (hasEscapes && tok == yajl_tok_string) {
+ tok = yajl_tok_string_with_escapes;
+ }
+
+ return tok;
+}
+
+#define RETURN_IF_EOF if (*offset >= jsonTextLen) return yajl_tok_eof;
+
+static yajl_tok
+yajl_lex_number(yajl_lexer lexer, const unsigned char * jsonText,
+ unsigned int jsonTextLen, unsigned int * offset)
+{
+ /** XXX: numbers are the only entities in json that we must lex
+ * _beyond_ in order to know that they are complete. There
+ * is an ambiguous case for integers at EOF. */
+
+ unsigned char c;
+
+ yajl_tok tok = yajl_tok_integer;
+
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+
+ /* optional leading minus */
+ if (c == '-') {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ }
+
+ /* a single zero, or a series of integers */
+ if (c == '0') {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ } else if (c >= '1' && c <= '9') {
+ do {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ } while (c >= '0' && c <= '9');
+ } else {
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_missing_integer_after_minus;
+ return yajl_tok_error;
+ }
+
+ /* optional fraction (indicates this is floating point) */
+ if (c == '.') {
+ int numRd = 0;
+
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+
+ while (c >= '0' && c <= '9') {
+ numRd++;
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ }
+
+ if (!numRd) {
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_missing_integer_after_decimal;
+ return yajl_tok_error;
+ }
+ tok = yajl_tok_double;
+ }
+
+ /* optional exponent (indicates this is floating point) */
+ if (c == 'e' || c == 'E') {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+
+ /* optional sign */
+ if (c == '+' || c == '-') {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ }
+
+ if (c >= '0' && c <= '9') {
+ do {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ } while (c >= '0' && c <= '9');
+ } else {
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_missing_integer_after_exponent;
+ return yajl_tok_error;
+ }
+ tok = yajl_tok_double;
+ }
+
+ /* we always go "one too far" */
+ unreadChar(lexer, offset);
+
+ return tok;
+}
+
+static yajl_tok
+yajl_lex_comment(yajl_lexer lexer, const unsigned char * jsonText,
+ unsigned int jsonTextLen, unsigned int * offset)
+{
+ unsigned char c;
+
+ yajl_tok tok;
+
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+
+ /* either slash or star expected */
+ if (c == '/') {
+ tok = yajl_tok_cpp_comment;
+ /* now we throw away until end of line */
+ do {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ } while (c != '\n');
+ } else if (c == '*') {
+ tok = yajl_tok_c_comment;
+ /* now we throw away until end of comment */
+ for (;;) {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ if (c == '*') {
+ RETURN_IF_EOF;
+ c = readChar(lexer, jsonText, offset);
+ if (c == '/') {
+ break;
+ } else {
+ unreadChar(lexer, offset);
+ }
+ }
+ }
+ } else {
+ lexer->error = yajl_lex_invalid_char;
+ tok = yajl_tok_error;
+ }
+
+ return tok;
+}
+
+yajl_tok
+yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
+ unsigned int jsonTextLen, unsigned int * offset,
+ const unsigned char ** outBuf, unsigned int * outLen)
+{
+ yajl_tok tok = yajl_tok_error;
+ unsigned char c;
+ unsigned int startOffset = *offset;
+
+ *outBuf = NULL;
+ *outLen = 0;
+
+ for (;;) {
+ assert(*offset <= jsonTextLen);
+
+ if (*offset >= jsonTextLen) {
+ tok = yajl_tok_eof;
+ goto lexed;
+ }
+
+ c = readChar(lexer, jsonText, offset);
+
+ switch (c) {
+ case '{':
+ tok = yajl_tok_left_bracket;
+ goto lexed;
+ case '}':
+ tok = yajl_tok_right_bracket;
+ goto lexed;
+ case '[':
+ tok = yajl_tok_left_brace;
+ goto lexed;
+ case ']':
+ tok = yajl_tok_right_brace;
+ goto lexed;
+ case ',':
+ tok = yajl_tok_comma;
+ goto lexed;
+ case ':':
+ tok = yajl_tok_colon;
+ goto lexed;
+ case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
+ startOffset++;
+ break;
+ case 't': {
+ const char * want = "rue";
+ do {
+ if (*offset >= jsonTextLen) {
+ tok = yajl_tok_eof;
+ goto lexed;
+ }
+ c = readChar(lexer, jsonText, offset);
+ if (c != *want) {
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_invalid_string;
+ tok = yajl_tok_error;
+ goto lexed;
+ }
+ } while (*(++want));
+ tok = yajl_tok_bool;
+ goto lexed;
+ }
+ case 'f': {
+ const char * want = "alse";
+ do {
+ if (*offset >= jsonTextLen) {
+ tok = yajl_tok_eof;
+ goto lexed;
+ }
+ c = readChar(lexer, jsonText, offset);
+ if (c != *want) {
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_invalid_string;
+ tok = yajl_tok_error;
+ goto lexed;
+ }
+ } while (*(++want));
+ tok = yajl_tok_bool;
+ goto lexed;
+ }
+ case 'n': {
+ const char * want = "ull";
+ do {
+ if (*offset >= jsonTextLen) {
+ tok = yajl_tok_eof;
+ goto lexed;
+ }
+ c = readChar(lexer, jsonText, offset);
+ if (c != *want) {
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_invalid_string;
+ tok = yajl_tok_error;
+ goto lexed;
+ }
+ } while (*(++want));
+ tok = yajl_tok_null;
+ goto lexed;
+ }
+ case '"': {
+ tok = yajl_lex_string(lexer, (const unsigned char *) jsonText,
+ jsonTextLen, offset);
+ goto lexed;
+ }
+ case '-':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': {
+ /* integer parsing wants to start from the beginning */
+ unreadChar(lexer, offset);
+ tok = yajl_lex_number(lexer, (const unsigned char *) jsonText,
+ jsonTextLen, offset);
+ goto lexed;
+ }
+ case '/':
+ /* hey, look, a probable comment! If comments are disabled
+ * it's an error. */
+ if (!lexer->allowComments) {
+ unreadChar(lexer, offset);
+ lexer->error = yajl_lex_unallowed_comment;
+ tok = yajl_tok_error;
+ goto lexed;
+ }
+ /* if comments are enabled, then we should try to lex
+ * the thing. possible outcomes are
+ * - successful lex (tok_comment, which means continue),
+ * - malformed comment opening (slash not followed by
+ * '*' or '/') (tok_error)
+ * - eof hit. (tok_eof) */
+ tok = yajl_lex_comment(lexer, (const unsigned char *) jsonText,
+ jsonTextLen, offset);
+ if (tok == yajl_tok_c_comment
+ || tok == yajl_tok_cpp_comment) {
+ goto lexed;
+ }
+ /* hit error or eof, bail */
+ goto lexed;
+ default:
+ lexer->error = yajl_lex_invalid_char;
+ tok = yajl_tok_error;
+ goto lexed;
+ }
+ }
+
+
+ lexed:
+ /* need to append to buffer if the buffer is in use or
+ * if it's an EOF token */
+ if (tok == yajl_tok_eof || lexer->bufInUse) {
+ if (!lexer->bufInUse) yajl_buf_clear(lexer->buf);
+ lexer->bufInUse = 1;
+ yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset);
+ lexer->bufOff = 0;
+
+ if (tok != yajl_tok_eof) {
+ *outBuf = yajl_buf_data(lexer->buf);
+ *outLen = yajl_buf_len(lexer->buf);
+ lexer->bufInUse = 0;
+ }
+ } else if (tok != yajl_tok_error) {
+ *outBuf = jsonText + startOffset;
+ *outLen = *offset - startOffset;
+ }
+
+ /* special case for strings. skip the quotes. */
+ if (tok == yajl_tok_string || tok == yajl_tok_string_with_escapes)
+ {
+ assert(*outLen >= 2);
+ (*outBuf)++;
+ *outLen -= 2;
+ }
+
+ /* remove comment delimeters */
+ if (tok == yajl_tok_c_comment)
+ {
+ assert(*outLen >= 4);
+ (*outBuf)+= 2;
+ *outLen -= 4;
+ }
+ if (tok == yajl_tok_cpp_comment)
+ {
+ assert(*outLen >= 2);
+ (*outBuf)+= 2;
+ *outLen -= 2;
+
+ if (*outLen >= 1 && (*outBuf)[(*outLen)-1] == 0x0a)
+ *outLen -= 1;
+ }
+
+
+#ifdef YAJL_LEXER_DEBUG
+ if (tok == yajl_tok_error) {
+ printf("lexical error: %s\n",
+ yajl_lex_error_to_string(yajl_lex_get_error(lexer)));
+ } else if (tok == yajl_tok_eof) {
+ printf("EOF hit\n");
+ } else {
+ printf("lexed %s: '", tokToStr(tok));
+ fwrite(*outBuf, 1, *outLen, stdout);
+ printf("'\n");
+ }
+#endif
+
+ return tok;
+}
+
+const char *
+yajl_lex_error_to_string(yajl_lex_error error)
+{
+ switch (error) {
+ case yajl_lex_e_ok:
+ return "ok, no error";
+ case yajl_lex_string_invalid_utf8:
+ return "invalid bytes in UTF8 string.";
+ case yajl_lex_string_invalid_escaped_char:
+ return "inside a string, '\\' occurs before a character "
+ "which it may not.";
+ case yajl_lex_string_invalid_json_char:
+ return "invalid character inside string.";
+ case yajl_lex_string_invalid_hex_char:
+ return "invalid (non-hex) character occurs after '\\u' inside "
+ "string.";
+ case yajl_lex_invalid_char:
+ return "invalid char in json text.";
+ case yajl_lex_invalid_string:
+ return "invalid string in json text.";
+ case yajl_lex_missing_integer_after_exponent:
+ return "malformed number, a digit is required after the exponent.";
+ case yajl_lex_missing_integer_after_decimal:
+ return "malformed number, a digit is required after the "
+ "decimal point.";
+ case yajl_lex_missing_integer_after_minus:
+ return "malformed number, a digit is required after the "
+ "minus sign.";
+ case yajl_lex_unallowed_comment:
+ return "probable comment found in input text, comments are "
+ "not enabled.";
+ }
+ return "unknown error code";
+}
+
+
+/** allows access to more specific information about the lexical
+ * error when yajl_lex_lex returns yajl_tok_error. */
+yajl_lex_error
+yajl_lex_get_error(yajl_lexer lexer)
+{
+ if (lexer == NULL) return (yajl_lex_error) -1;
+ return lexer->error;
+}
+
+unsigned int yajl_lex_current_line(yajl_lexer lexer)
+{
+ return lexer->lineOff;
+}
+
+unsigned int yajl_lex_current_char(yajl_lexer lexer)
+{
+ return lexer->charOff;
+}
+
+yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
+ unsigned int jsonTextLen, unsigned int offset)
+{
+ const unsigned char * outBuf;
+ unsigned int outLen;
+ unsigned int bufLen = yajl_buf_len(lexer->buf);
+ unsigned int bufOff = lexer->bufOff;
+ unsigned int bufInUse = lexer->bufInUse;
+ yajl_tok tok;
+
+ tok = yajl_lex_lex(lexer, jsonText, jsonTextLen, &offset,
+ &outBuf, &outLen);
+
+ lexer->bufOff = bufOff;
+ lexer->bufInUse = bufInUse;
+ yajl_buf_truncate(lexer->buf, bufLen);
+
+ return tok;
+}
diff --git a/jcnf/yajl/yajl_lex.h b/jcnf/yajl/yajl_lex.h
new file mode 100644
index 0000000..e1268ea
--- /dev/null
+++ b/jcnf/yajl/yajl_lex.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __YAJL_LEX_H__
+#define __YAJL_LEX_H__
+
+#include "yajl_common.h"
+
+typedef enum {
+ yajl_tok_bool,
+ yajl_tok_colon,
+ yajl_tok_comma,
+ yajl_tok_eof,
+ yajl_tok_error,
+ yajl_tok_left_brace,
+ yajl_tok_left_bracket,
+ yajl_tok_null,
+ yajl_tok_right_brace,
+ yajl_tok_right_bracket,
+
+ /* we differentiate between integers and doubles to allow the
+ * parser to interpret the number without re-scanning */
+ yajl_tok_integer,
+ yajl_tok_double,
+
+ /* we differentiate between strings which require further processing,
+ * and strings that do not */
+ yajl_tok_string,
+ yajl_tok_string_with_escapes,
+
+ /* we return the two types of comment tokens as well */
+ yajl_tok_c_comment,
+ yajl_tok_cpp_comment
+
+} yajl_tok;
+
+typedef struct yajl_lexer_t * yajl_lexer;
+
+yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc,
+ unsigned int allowComments,
+ unsigned int validateUTF8);
+
+void yajl_lex_free(yajl_lexer lexer);
+
+/**
+ * run/continue a lex. "offset" is an input/output parameter.
+ * It should be initialized to zero for a
+ * new chunk of target text, and upon subsetquent calls with the same
+ * target text should passed with the value of the previous invocation.
+ *
+ * the client may be interested in the value of offset when an error is
+ * returned from the lexer. This allows the client to render useful
+n * error messages.
+ *
+ * When you pass the next chunk of data, context should be reinitialized
+ * to zero.
+ *
+ * Finally, the output buffer is usually just a pointer into the jsonText,
+ * however in cases where the entity being lexed spans multiple chunks,
+ * the lexer will buffer the entity and the data returned will be
+ * a pointer into that buffer.
+ *
+ * This behavior is abstracted from client code except for the performance
+ * implications which require that the client choose a reasonable chunk
+ * size to get adequate performance.
+ */
+yajl_tok yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
+ unsigned int jsonTextLen, unsigned int * offset,
+ const unsigned char ** outBuf, unsigned int * outLen);
+
+/** have a peek at the next token, but don't move the lexer forward */
+yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
+ unsigned int jsonTextLen, unsigned int offset);
+
+
+typedef enum {
+ yajl_lex_e_ok = 0,
+ yajl_lex_string_invalid_utf8,
+ yajl_lex_string_invalid_escaped_char,
+ yajl_lex_string_invalid_json_char,
+ yajl_lex_string_invalid_hex_char,
+ yajl_lex_invalid_char,
+ yajl_lex_invalid_string,
+ yajl_lex_missing_integer_after_decimal,
+ yajl_lex_missing_integer_after_exponent,
+ yajl_lex_missing_integer_after_minus,
+ yajl_lex_unallowed_comment
+} yajl_lex_error;
+
+const char * yajl_lex_error_to_string(yajl_lex_error error);
+
+/** allows access to more specific information about the lexical
+ * error when yajl_lex_lex returns yajl_tok_error. */
+yajl_lex_error yajl_lex_get_error(yajl_lexer lexer);
+
+/** get the current offset into the most recently lexed json string. */
+unsigned int yajl_lex_current_offset(yajl_lexer lexer);
+
+/** get the number of lines lexed by this lexer instance */
+unsigned int yajl_lex_current_line(yajl_lexer lexer);
+
+/** get the number of chars lexed by this lexer instance since the last
+ * \n or \r */
+unsigned int yajl_lex_current_char(yajl_lexer lexer);
+
+#endif
diff --git a/jcnf/yajl/yajl_parse.h b/jcnf/yajl/yajl_parse.h
new file mode 100644
index 0000000..250d3e1
--- /dev/null
+++ b/jcnf/yajl/yajl_parse.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file yajl_parse.h
+ * Interface to YAJL's JSON parsing facilities.
+ */
+
+#include "yajl_common.h"
+
+#ifndef __YAJL_PARSE_H__
+#define __YAJL_PARSE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /** error codes returned from this interface */
+ typedef enum {
+ /** no error was encountered */
+ yajl_status_ok,
+ /** a client callback returned zero, stopping the parse */
+ yajl_status_client_canceled,
+ /** The parse cannot yet complete because more json input text
+ * is required, call yajl_parse with the next buffer of input text.
+ * (pertinent only when stream parsing) */
+ yajl_status_insufficient_data,
+ /** An error occured during the parse. Call yajl_get_error for
+ * more information about the encountered error */
+ yajl_status_error
+ } yajl_status;
+
+ /** attain a human readable, english, string for an error */
+ const char * YAJL_API yajl_status_to_string(yajl_status code);
+
+ /** an opaque handle to a parser */
+ typedef struct yajl_handle_t * yajl_handle;
+
+ /** yajl is an event driven parser. this means as json elements are
+ * parsed, you are called back to do something with the data. The
+ * functions in this table indicate the various events for which
+ * you will be called back. Each callback accepts a "context"
+ * pointer, this is a void * that is passed into the yajl_parse
+ * function which the client code may use to pass around context.
+ *
+ * All callbacks return an integer. If non-zero, the parse will
+ * continue. If zero, the parse will be canceled and
+ * yajl_status_client_canceled will be returned from the parse.
+ *
+ * Note about handling of numbers:
+ * yajl will only convert numbers that can be represented in a double
+ * or a long int. All other numbers will be passed to the client
+ * in string form using the yajl_number callback. Furthermore, if
+ * yajl_number is not NULL, it will always be used to return numbers,
+ * that is yajl_integer and yajl_double will be ignored. If
+ * yajl_number is NULL but one of yajl_integer or yajl_double are
+ * defined, parsing of a number larger than is representable
+ * in a double or long int will result in a parse error.
+ */
+ typedef struct {
+ int (* yajl_null)(void * ctx);
+ int (* yajl_boolean)(void * ctx, int boolVal);
+ int (* yajl_integer)(void * ctx, long integerVal);
+ int (* yajl_double)(void * ctx, double doubleVal);
+ /** A callback which passes the string representation of the number
+ * back to the client. Will be used for all numbers when present */
+ int (* yajl_number)(void * ctx, const char * numberVal,
+ unsigned int numberLen);
+
+ /** strings are returned as pointers into the JSON text when,
+ * possible, as a result, they are _not_ null padded */
+ int (* yajl_string)(void * ctx, const unsigned char * stringVal,
+ unsigned int stringLen);
+ int (* yajl_c_comment)(void * ctx, const unsigned char * stringVal,
+ unsigned int stringLen);
+
+ int (* yajl_cpp_comment)(void * ctx, const unsigned char * stringVal,
+ unsigned int stringLen);
+
+ int (* yajl_start_map)(void * ctx);
+ int (* yajl_map_key)(void * ctx, const unsigned char * key,
+ unsigned int stringLen);
+ int (* yajl_end_map)(void * ctx);
+
+ int (* yajl_start_array)(void * ctx);
+ int (* yajl_end_array)(void * ctx);
+ } yajl_callbacks;
+
+ /** configuration structure for the generator */
+ typedef struct {
+ /** if nonzero, javascript style comments will be allowed in
+ * the json input, both slash star and slash slash */
+ unsigned int allowComments;
+ /** if nonzero, invalid UTF8 strings will cause a parse
+ * error */
+ unsigned int checkUTF8;
+ } yajl_parser_config;
+
+ /** allocate a parser handle
+ * \param callbacks a yajl callbacks structure specifying the
+ * functions to call when different JSON entities
+ * are encountered in the input text. May be NULL,
+ * which is only useful for validation.
+ * \param config configuration parameters for the parse.
+ * \param ctx a context pointer that will be passed to callbacks.
+ */
+ yajl_handle YAJL_API yajl_alloc(const yajl_callbacks * callbacks,
+ const yajl_parser_config * config,
+ const yajl_alloc_funcs * allocFuncs,
+ void * ctx);
+
+ /** free a parser handle */
+ void YAJL_API yajl_free(yajl_handle handle);
+
+ /** Parse some json!
+ * \param hand - a handle to the json parser allocated with yajl_alloc
+ * \param jsonText - a pointer to the UTF8 json text to be parsed
+ * \param jsonTextLength - the length, in bytes, of input text
+ */
+ yajl_status YAJL_API yajl_parse(yajl_handle hand,
+ const unsigned char * jsonText,
+ unsigned int jsonTextLength);
+
+ /** Parse any remaining buffered json.
+ * Since yajl is a stream-based parser, without an explicit end of
+ * input, yajl sometimes can't decide if content at the end of the
+ * stream is valid or not. For example, if "1" has been fed in,
+ * yajl can't know whether another digit is next or some character
+ * that would terminate the integer token.
+ *
+ * \param hand - a handle to the json parser allocated with yajl_alloc
+ */
+ yajl_status yajl_parse_complete(yajl_handle hand);
+
+ /** get an error string describing the state of the
+ * parse.
+ *
+ * If verbose is non-zero, the message will include the JSON
+ * text where the error occured, along with an arrow pointing to
+ * the specific char.
+ *
+ * A dynamically allocated string will be returned which should
+ * be freed with yajl_free_error
+ */
+ unsigned char * YAJL_API yajl_get_error(yajl_handle hand, int verbose,
+ const unsigned char * jsonText,
+ unsigned int jsonTextLength);
+
+ /** free an error returned from yajl_get_error */
+ void YAJL_API yajl_free_error(yajl_handle hand, unsigned char * str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/jcnf/yajl/yajl_parser.c b/jcnf/yajl/yajl_parser.c
new file mode 100644
index 0000000..3d0f07f
--- /dev/null
+++ b/jcnf/yajl/yajl_parser.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_lex.h"
+#include "yajl_parser.h"
+#include "yajl_encode.h"
+#include "yajl_bytestack.h"
+
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <math.h>
+
+unsigned char *
+yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
+ unsigned int jsonTextLen, int verbose)
+{
+ unsigned int offset = hand->errorOffset;
+ unsigned char * str;
+ const char * errorType = NULL;
+ const char * errorText = NULL;
+ char text[72];
+ const char * arrow = " (right here) ------^\n";
+
+ if (yajl_bs_current(hand->stateStack) == yajl_state_parse_error) {
+ errorType = "parse";
+ errorText = hand->parseError;
+ } else if (yajl_bs_current(hand->stateStack) == yajl_state_lexical_error) {
+ errorType = "lexical";
+ errorText = yajl_lex_error_to_string(yajl_lex_get_error(hand->lexer));
+ } else {
+ errorType = "unknown";
+ }
+
+ {
+ unsigned int memneeded = 0;
+ memneeded += strlen(errorType);
+ memneeded += strlen(" error");
+ if (errorText != NULL) {
+ memneeded += strlen(": ");
+ memneeded += strlen(errorText);
+ }
+ str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2);
+ str[0] = 0;
+ strcat((char *) str, errorType);
+ strcat((char *) str, " error");
+ if (errorText != NULL) {
+ strcat((char *) str, ": ");
+ strcat((char *) str, errorText);
+ }
+ strcat((char *) str, "\n");
+ }
+
+ /* now we append as many spaces as needed to make sure the error
+ * falls at char 41, if verbose was specified */
+ if (verbose) {
+ unsigned int start, end, i;
+ unsigned int spacesNeeded;
+
+ spacesNeeded = (offset < 30 ? 40 - offset : 10);
+ start = (offset >= 30 ? offset - 30 : 0);
+ end = (offset + 30 > jsonTextLen ? jsonTextLen : offset + 30);
+
+ for (i=0;i<spacesNeeded;i++) text[i] = ' ';
+
+ for (;start < end;start++, i++) {
+ if (jsonText[start] != '\n' && jsonText[start] != '\r')
+ {
+ text[i] = jsonText[start];
+ }
+ else
+ {
+ text[i] = ' ';
+ }
+ }
+ assert(i <= 71);
+ text[i++] = '\n';
+ text[i] = 0;
+ {
+ char * newStr = (char *)
+ YA_MALLOC(&(hand->alloc), (strlen((char *) str) +
+ strlen((char *) text) +
+ strlen(arrow) + 1));
+ newStr[0] = 0;
+ strcat((char *) newStr, (char *) str);
+ strcat((char *) newStr, text);
+ strcat((char *) newStr, arrow);
+ YA_FREE(&(hand->alloc), str);
+ str = (unsigned char *) newStr;
+ }
+ }
+ return str;
+}
+
+/* check for client cancelation */
+#define _CC_CHK(x) \
+ if (!(x)) { \
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error); \
+ hand->parseError = \
+ "client cancelled parse via callback return value"; \
+ return yajl_status_client_canceled; \
+ }
+
+
+yajl_status
+yajl_do_parse(yajl_handle hand, unsigned int * offset,
+ const unsigned char * jsonText, unsigned int jsonTextLen)
+{
+ yajl_tok tok;
+ const unsigned char * buf;
+ unsigned int bufLen;
+
+ around_again:
+ switch (yajl_bs_current(hand->stateStack)) {
+ case yajl_state_parse_complete:
+ return yajl_status_ok;
+ case yajl_state_lexical_error:
+ case yajl_state_parse_error:
+ hand->errorOffset = *offset;
+ return yajl_status_error;
+ case yajl_state_start:
+ case yajl_state_map_need_val:
+ case yajl_state_array_need_val:
+ case yajl_state_array_start: {
+ /* for arrays and maps, we advance the state for this
+ * depth, then push the state of the next depth.
+ * If an error occurs during the parsing of the nesting
+ * enitity, the state at this level will not matter.
+ * a state that needs pushing will be anything other
+ * than state_start */
+ yajl_state stateToPush = yajl_state_start;
+
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
+ offset, &buf, &bufLen);
+
+ switch (tok) {
+ case yajl_tok_eof:
+ return yajl_status_insufficient_data;
+ case yajl_tok_error:
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
+ goto around_again;
+ case yajl_tok_c_comment:
+ if (hand->callbacks && hand->callbacks->yajl_c_comment) {
+ _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_cpp_comment:
+ if (hand->callbacks && hand->callbacks->yajl_cpp_comment) {
+ _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_string:
+ if (hand->callbacks && hand->callbacks->yajl_string) {
+ _CC_CHK(hand->callbacks->yajl_string(hand->ctx,
+ buf, bufLen));
+ }
+ break;
+ case yajl_tok_string_with_escapes:
+ if (hand->callbacks && hand->callbacks->yajl_string) {
+ yajl_buf_clear(hand->decodeBuf);
+ yajl_string_decode(hand->decodeBuf, buf, bufLen);
+ _CC_CHK(hand->callbacks->yajl_string(
+ hand->ctx, yajl_buf_data(hand->decodeBuf),
+ yajl_buf_len(hand->decodeBuf)));
+ }
+ break;
+ case yajl_tok_bool:
+ if (hand->callbacks && hand->callbacks->yajl_boolean) {
+ _CC_CHK(hand->callbacks->yajl_boolean(hand->ctx,
+ *buf == 't'));
+ }
+ break;
+ case yajl_tok_null:
+ if (hand->callbacks && hand->callbacks->yajl_null) {
+ _CC_CHK(hand->callbacks->yajl_null(hand->ctx));
+ }
+ break;
+ case yajl_tok_left_bracket:
+ if (hand->callbacks && hand->callbacks->yajl_start_map) {
+ _CC_CHK(hand->callbacks->yajl_start_map(hand->ctx));
+ }
+ stateToPush = yajl_state_map_start;
+ break;
+ case yajl_tok_left_brace:
+ if (hand->callbacks && hand->callbacks->yajl_start_array) {
+ _CC_CHK(hand->callbacks->yajl_start_array(hand->ctx));
+ }
+ stateToPush = yajl_state_array_start;
+ break;
+ case yajl_tok_integer:
+ /*
+ * note. strtol does not respect the length of
+ * the lexical token. in a corner case where the
+ * lexed number is a integer with a trailing zero,
+ * immediately followed by the end of buffer,
+ * sscanf could run off into oblivion and cause a
+ * crash. for this reason we copy the integer
+ * (and doubles), into our parse buffer (the same
+ * one used for unescaping strings), before
+ * calling strtol. yajl_buf ensures null padding,
+ * so we're safe.
+ */
+ if (hand->callbacks) {
+ if (hand->callbacks->yajl_number) {
+ _CC_CHK(hand->callbacks->yajl_number(
+ hand->ctx,(const char *) buf, bufLen));
+ } else if (hand->callbacks->yajl_integer) {
+ long int i = 0;
+ yajl_buf_clear(hand->decodeBuf);
+ yajl_buf_append(hand->decodeBuf, buf, bufLen);
+ buf = yajl_buf_data(hand->decodeBuf);
+ i = strtol((const char *) buf, NULL, 10);
+ if ((i == LONG_MIN || i == LONG_MAX) &&
+ errno == ERANGE)
+ {
+ yajl_bs_set(hand->stateStack,
+ yajl_state_parse_error);
+ hand->parseError = "integer overflow" ;
+ /* try to restore error offset */
+ if (*offset >= bufLen) *offset -= bufLen;
+ else *offset = 0;
+ goto around_again;
+ }
+ _CC_CHK(hand->callbacks->yajl_integer(hand->ctx,
+ i));
+ }
+ }
+ break;
+ case yajl_tok_double:
+ if (hand->callbacks) {
+ if (hand->callbacks->yajl_number) {
+ _CC_CHK(hand->callbacks->yajl_number(
+ hand->ctx, (const char *) buf, bufLen));
+ } else if (hand->callbacks->yajl_double) {
+ double d = 0.0;
+ yajl_buf_clear(hand->decodeBuf);
+ yajl_buf_append(hand->decodeBuf, buf, bufLen);
+ buf = yajl_buf_data(hand->decodeBuf);
+ d = strtod((char *) buf, NULL);
+ if ((d == HUGE_VAL || d == -HUGE_VAL) &&
+ errno == ERANGE)
+ {
+ yajl_bs_set(hand->stateStack,
+ yajl_state_parse_error);
+ hand->parseError = "numeric (floating point) "
+ "overflow";
+ /* try to restore error offset */
+ if (*offset >= bufLen) *offset -= bufLen;
+ else *offset = 0;
+ goto around_again;
+ }
+ _CC_CHK(hand->callbacks->yajl_double(hand->ctx,
+ d));
+ }
+ }
+ break;
+ case yajl_tok_right_brace: {
+ if (yajl_bs_current(hand->stateStack) ==
+ yajl_state_array_start)
+ {
+ if (hand->callbacks &&
+ hand->callbacks->yajl_end_array)
+ {
+ _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
+ }
+ yajl_bs_pop(hand->stateStack);
+ goto around_again;
+ }
+ /* intentional fall-through */
+ }
+ case yajl_tok_colon:
+ case yajl_tok_comma:
+ case yajl_tok_right_bracket:
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
+ hand->parseError =
+ "unallowed token at this point in JSON text";
+ goto around_again;
+ default:
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
+ hand->parseError = "invalid token, internal error";
+ goto around_again;
+ }
+ /* got a value. transition depends on the state we're in. */
+ {
+ yajl_state s = yajl_bs_current(hand->stateStack);
+ if (s == yajl_state_start) {
+ yajl_bs_set(hand->stateStack, yajl_state_parse_complete);
+ } else if (s == yajl_state_map_need_val) {
+ yajl_bs_set(hand->stateStack, yajl_state_map_got_val);
+ } else {
+ yajl_bs_set(hand->stateStack, yajl_state_array_got_val);
+ }
+ }
+ if (stateToPush != yajl_state_start) {
+ yajl_bs_push(hand->stateStack, stateToPush);
+ }
+
+ goto around_again;
+ }
+ case yajl_state_map_start:
+ case yajl_state_map_need_key: {
+ /* only difference between these two states is that in
+ * start '}' is valid, whereas in need_key, we've parsed
+ * a comma, and a string key _must_ follow */
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
+ offset, &buf, &bufLen);
+ switch (tok) {
+ case yajl_tok_eof:
+ return yajl_status_insufficient_data;
+ case yajl_tok_error:
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
+ goto around_again;
+ case yajl_tok_string_with_escapes:
+ if (hand->callbacks && hand->callbacks->yajl_map_key) {
+ yajl_buf_clear(hand->decodeBuf);
+ yajl_string_decode(hand->decodeBuf, buf, bufLen);
+ buf = yajl_buf_data(hand->decodeBuf);
+ bufLen = yajl_buf_len(hand->decodeBuf);
+ }
+ /* intentional fall-through */
+ case yajl_tok_string:
+ if (hand->callbacks && hand->callbacks->yajl_map_key) {
+ _CC_CHK(hand->callbacks->yajl_map_key(hand->ctx, buf,
+ bufLen));
+ }
+ yajl_bs_set(hand->stateStack, yajl_state_map_sep);
+ goto around_again;
+ case yajl_tok_c_comment:
+ if (hand->callbacks && hand->callbacks->yajl_c_comment) {
+ _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_cpp_comment:
+ if (hand->callbacks && hand->callbacks->yajl_cpp_comment) {
+ _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_right_bracket:
+ if (yajl_bs_current(hand->stateStack) ==
+ yajl_state_map_start)
+ {
+ if (hand->callbacks && hand->callbacks->yajl_end_map) {
+ _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
+ }
+ yajl_bs_pop(hand->stateStack);
+ goto around_again;
+ }
+ default:
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
+ hand->parseError =
+ "invalid object key (must be a string)";
+ goto around_again;
+ }
+ }
+ case yajl_state_map_sep: {
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
+ offset, &buf, &bufLen);
+ switch (tok) {
+ case yajl_tok_c_comment:
+ if (hand->callbacks && hand->callbacks->yajl_c_comment) {
+ _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_cpp_comment:
+ if (hand->callbacks && hand->callbacks->yajl_cpp_comment) {
+ _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_colon:
+ yajl_bs_set(hand->stateStack, yajl_state_map_need_val);
+ goto around_again;
+ case yajl_tok_eof:
+ return yajl_status_insufficient_data;
+ case yajl_tok_error:
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
+ goto around_again;
+ default:
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
+ hand->parseError = "object key and value must "
+ "be separated by a colon (':')";
+ goto around_again;
+ }
+ }
+ case yajl_state_map_got_val: {
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
+ offset, &buf, &bufLen);
+ switch (tok) {
+ case yajl_tok_c_comment:
+ if (hand->callbacks && hand->callbacks->yajl_c_comment) {
+ _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_cpp_comment:
+ if (hand->callbacks && hand->callbacks->yajl_cpp_comment) {
+ _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_right_bracket:
+ if (hand->callbacks && hand->callbacks->yajl_end_map) {
+ _CC_CHK(hand->callbacks->yajl_end_map(hand->ctx));
+ }
+ yajl_bs_pop(hand->stateStack);
+ goto around_again;
+ case yajl_tok_comma:
+ yajl_bs_set(hand->stateStack, yajl_state_map_need_key);
+ goto around_again;
+ case yajl_tok_eof:
+ return yajl_status_insufficient_data;
+ case yajl_tok_error:
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
+ goto around_again;
+ default:
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
+ hand->parseError = "after key and value, inside map, "
+ "I expect ',' or '}'";
+ /* try to restore error offset */
+ if (*offset >= bufLen) *offset -= bufLen;
+ else *offset = 0;
+ goto around_again;
+ }
+ }
+ case yajl_state_array_got_val: {
+ tok = yajl_lex_lex(hand->lexer, jsonText, jsonTextLen,
+ offset, &buf, &bufLen);
+ switch (tok) {
+ case yajl_tok_c_comment:
+ if (hand->callbacks && hand->callbacks->yajl_c_comment) {
+ _CC_CHK(hand->callbacks->yajl_c_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_cpp_comment:
+ if (hand->callbacks && hand->callbacks->yajl_cpp_comment) {
+ _CC_CHK(hand->callbacks->yajl_cpp_comment(hand->ctx,
+ buf, bufLen));
+ }
+ goto around_again;
+ case yajl_tok_right_brace:
+ if (hand->callbacks && hand->callbacks->yajl_end_array) {
+ _CC_CHK(hand->callbacks->yajl_end_array(hand->ctx));
+ }
+ yajl_bs_pop(hand->stateStack);
+ goto around_again;
+ case yajl_tok_comma:
+ yajl_bs_set(hand->stateStack, yajl_state_array_need_val);
+ goto around_again;
+ case yajl_tok_eof:
+ return yajl_status_insufficient_data;
+ case yajl_tok_error:
+ yajl_bs_set(hand->stateStack, yajl_state_lexical_error);
+ goto around_again;
+ default:
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error);
+ hand->parseError =
+ "after array element, I expect ',' or ']'";
+ goto around_again;
+ }
+ }
+ }
+
+ abort();
+ return yajl_status_error;
+}
+
diff --git a/jcnf/yajl/yajl_parser.h b/jcnf/yajl/yajl_parser.h
new file mode 100644
index 0000000..f8bc8ee
--- /dev/null
+++ b/jcnf/yajl/yajl_parser.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __YAJL_PARSER_H__
+#define __YAJL_PARSER_H__
+
+#include "yajl_parse.h"
+#include "yajl_bytestack.h"
+#include "yajl_buf.h"
+
+
+typedef enum {
+ yajl_state_start = 0,
+ yajl_state_parse_complete,
+ yajl_state_parse_error,
+ yajl_state_lexical_error,
+ yajl_state_map_start,
+ yajl_state_map_sep,
+ yajl_state_map_need_val,
+ yajl_state_map_got_val,
+ yajl_state_map_need_key,
+ yajl_state_array_start,
+ yajl_state_array_got_val,
+ yajl_state_array_need_val
+} yajl_state;
+
+struct yajl_handle_t {
+ const yajl_callbacks * callbacks;
+ void * ctx;
+ yajl_lexer lexer;
+ const char * parseError;
+ unsigned int errorOffset;
+ /* temporary storage for decoded strings */
+ yajl_buf decodeBuf;
+ /* a stack of states. access with yajl_state_XXX routines */
+ yajl_bytestack stateStack;
+ /* memory allocation routines */
+ yajl_alloc_funcs alloc;
+};
+
+yajl_status
+yajl_do_parse(yajl_handle handle, unsigned int * offset,
+ const unsigned char * jsonText, unsigned int jsonTextLen);
+
+unsigned char *
+yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
+ unsigned int jsonTextLen, int verbose);
+
+
+#endif
diff --git a/jcnf/yajl/yajl_test.c b/jcnf/yajl/yajl_test.c
new file mode 100644
index 0000000..de43570
--- /dev/null
+++ b/jcnf/yajl/yajl_test.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2007-2009, Lloyd Hilaiel.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "yajl_parse.h"
+#include "yajl_gen.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+
+/* memory debugging routines */
+typedef struct
+{
+ unsigned int numFrees;
+ unsigned int numMallocs;
+ /* XXX: we really need a hash table here with per-allocation
+ * information */
+} yajlTestMemoryContext;
+
+/* cast void * into context */
+#define TEST_CTX(vptr) ((yajlTestMemoryContext *) (vptr))
+
+static void yajlTestFree(void * ctx, void * ptr)
+{
+ assert(ptr != NULL);
+ TEST_CTX(ctx)->numFrees++;
+ free(ptr);
+}
+
+static void * yajlTestMalloc(void * ctx, unsigned int sz)
+{
+ assert(sz != 0);
+ TEST_CTX(ctx)->numMallocs++;
+ return malloc(sz);
+}
+
+static void * yajlTestRealloc(void * ctx, void * ptr, unsigned int sz)
+{
+ if (ptr == NULL) {
+ assert(sz != 0);
+ TEST_CTX(ctx)->numMallocs++;
+ } else if (sz == 0) {
+ TEST_CTX(ctx)->numFrees++;
+ }
+
+ return realloc(ptr, sz);
+}
+
+
+/* begin parsing callback routines */
+#define BUF_SIZE 2048
+
+static int test_yajl_null(void *ctx)
+{
+ printf("null\n");
+ return 1;
+}
+
+static int test_yajl_boolean(void * ctx, int boolVal)
+{
+ printf("bool: %s\n", boolVal ? "true" : "false");
+ return 1;
+}
+
+static int test_yajl_integer(void *ctx, long integerVal)
+{
+ printf("integer: %ld\n", integerVal);
+ return 1;
+}
+
+static int test_yajl_double(void *ctx, double doubleVal)
+{
+ printf("double: %g\n", doubleVal);
+ return 1;
+}
+
+static int test_yajl_string(void *ctx, const unsigned char * stringVal,
+ unsigned int stringLen)
+{
+ printf("string: '");
+ fwrite(stringVal, 1, stringLen, stdout);
+ printf("'\n");
+ return 1;
+}
+
+static int test_yajl_map_key(void *ctx, const unsigned char * stringVal,
+ unsigned int stringLen)
+{
+ char * str = (char *) malloc(stringLen + 1);
+ str[stringLen] = 0;
+ memcpy(str, stringVal, stringLen);
+ printf("key: '%s'\n", str);
+ free(str);
+ return 1;
+}
+
+static int test_yajl_start_map(void *ctx)
+{
+ printf("map open '{'\n");
+ return 1;
+}
+
+
+static int test_yajl_end_map(void *ctx)
+{
+ printf("map close '}'\n");
+ return 1;
+}
+
+static int test_yajl_start_array(void *ctx)
+{
+ printf("array open '['\n");
+ return 1;
+}
+
+static int test_yajl_end_array(void *ctx)
+{
+ printf("array close ']'\n");
+ return 1;
+}
+
+static yajl_callbacks callbacks = {
+ test_yajl_null,
+ test_yajl_boolean,
+ test_yajl_integer,
+ test_yajl_double,
+ NULL,
+ test_yajl_string,
+ NULL,
+ NULL,
+ test_yajl_start_map,
+ test_yajl_map_key,
+ test_yajl_end_map,
+ test_yajl_start_array,
+ test_yajl_end_array
+};
+
+static void usage(const char * progname)
+{
+ fprintf(stderr,
+ "usage: %s [options] <filename>\n"
+ " -c allow comments\n"
+ " -b set the read buffer size\n",
+ progname);
+ exit(1);
+}
+
+int
+main(int argc, char ** argv)
+{
+ yajl_handle hand;
+ const char * fileName;
+ static unsigned char * fileData = NULL;
+ unsigned int bufSize = BUF_SIZE;
+ yajl_status stat;
+ size_t rd;
+ yajl_parser_config cfg = { 0, 1 };
+ int i, j, done;
+
+ /* memory allocation debugging: allocate a structure which collects
+ * statistics */
+ yajlTestMemoryContext memCtx = { 0,0 };
+
+ /* memory allocation debugging: allocate a structure which holds
+ * allocation routines */
+ yajl_alloc_funcs allocFuncs = {
+ yajlTestMalloc,
+ yajlTestRealloc,
+ yajlTestFree,
+ (void *) NULL
+ };
+
+ allocFuncs.ctx = (void *) &memCtx;
+
+ /* check arguments. We expect exactly one! */
+ for (i=1;i<argc;i++) {
+ if (!strcmp("-c", argv[i])) {
+ cfg.allowComments = 1;
+ } else if (!strcmp("-b", argv[i])) {
+ if (++i >= argc) usage(argv[0]);
+
+ /* validate integer */
+ for (j=0;j<(int)strlen(argv[i]);j++) {
+ if (argv[i][j] <= '9' && argv[i][j] >= '0') continue;
+ fprintf(stderr, "-b requires an integer argument. '%s' "
+ "is invalid\n", argv[i]);
+ usage(argv[0]);
+ }
+
+ bufSize = atoi(argv[i]);
+ if (!bufSize) {
+ fprintf(stderr, "%d is an invalid buffer size\n",
+ bufSize);
+ }
+ } else {
+ fprintf(stderr, "invalid command line option: '%s'\n",
+ argv[i]);
+ usage(argv[0]);
+ }
+ }
+
+ fileData = (unsigned char *) malloc(bufSize);
+
+ if (fileData == NULL) {
+ fprintf(stderr,
+ "failed to allocate read buffer of %u bytes, exiting.",
+ bufSize);
+ exit(2);
+ }
+
+ fileName = argv[argc-1];
+
+ /* ok. open file. let's read and parse */
+ hand = yajl_alloc(&callbacks, &cfg, &allocFuncs, NULL);
+
+ done = 0;
+ while (!done) {
+ rd = fread((void *) fileData, 1, bufSize, stdin);
+
+ if (rd == 0) {
+ if (!feof(stdin)) {
+ fprintf(stderr, "error reading from '%s'\n", fileName);
+ break;
+ }
+ done = 1;
+ }
+
+ if (done)
+ /* parse any remaining buffered data */
+ stat = yajl_parse_complete(hand);
+ else
+ /* read file data, pass to parser */
+ stat = yajl_parse(hand, fileData, rd);
+
+ if (stat != yajl_status_insufficient_data &&
+ stat != yajl_status_ok)
+ {
+ unsigned char * str = yajl_get_error(hand, 0, fileData, rd);
+ fflush(stdout);
+ fprintf(stderr, "%s", (char *) str);
+ yajl_free_error(hand, str);
+ break;
+ }
+ }
+
+ yajl_free(hand);
+ free(fileData);
+
+ /* finally, print out some memory statistics */
+
+/* (lth) only print leaks here, as allocations and frees may vary depending
+ * on read buffer size, causing false failures.
+ *
+ * printf("allocations:\t%u\n", memCtx.numMallocs);
+ * printf("frees:\t\t%u\n", memCtx.numFrees);
+*/
+ fflush(stderr);
+ fflush(stdout);
+ printf("memory leaks:\t%u\n", memCtx.numMallocs - memCtx.numFrees);
+
+ return 0;
+}
diff --git a/jpg/Jamfile b/jpg/Jamfile
new file mode 100644
index 0000000..5f9a91c
--- /dev/null
+++ b/jpg/Jamfile
@@ -0,0 +1,26 @@
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ;
+
+# Run configure if it seems to be needed
+if $(UNIX) {
+ GenFileNND jconfig.h : "(cd $(SUBDIR); chmod +x configure ; ./configure)" : configure ;
+}
+
+# else copy them
+if $(NT) {
+ File jconfig.h : jconfig.vc ;
+}
+
+# jpg library
+LIBSRCS = jcapimin.c jcapistd.c jdapimin.c jdapistd.c jcomapi.c jcparam.c jctrans.c
+ jdtrans.c jcinit.c jcmaster.c jcmainct.c jcprepct.c jccoefct.c jccolor.c
+ jcsample.c jcdctmgr.c jfdctint.c jfdctfst.c jfdctflt.c jchuff.c jcarith.c
+ jcmarker.c jdatadst.c jdmaster.c jdinput.c jdmainct.c jdcoefct.c jdpostct.c
+ jdmarker.c jdhuff.c jdarith.c jddctmgr.c jidctint.c jidctfst.c jidctflt.c
+ jdsample.c jdcolor.c jdmerge.c jquant1.c jquant2.c jdatasrc.c jaricom.c
+ jerror.c jmemmgr.c jutils.c jmemmgr.c jmemnobs.c ;
+
+Library libjpeg : $(LIBSRCS) ;
+
diff --git a/jpg/Makefile.am b/jpg/Makefile.am
new file mode 100644
index 0000000..42cff57
--- /dev/null
+++ b/jpg/Makefile.am
@@ -0,0 +1,134 @@
+## Process this file with automake to produce Makefile.in
+#
+# Automake Makefile for the JPEG library
+#
+# This file is written by Bob Friesenhahn, Guido Vollbeding
+#
+
+# Sources to build library
+LIBSOURCES = jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c @MEMORYMGR@.c
+
+# System dependent sources
+SYSDEPSOURCES = jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+
+# Headers which are installed to support the library
+INSTINCLUDES = jerror.h jmorecfg.h jpeglib.h
+
+# Headers which are not installed
+OTHERINCLUDES = cderror.h cdjpeg.h jdct.h jinclude.h jmemsys.h jpegint.h \
+ jversion.h transupp.h
+
+# Manual pages (Automake uses 'MANS' for itself)
+DISTMANS= cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
+
+# Other documentation files
+DOCS= README install.txt usage.txt wizard.txt example.c libjpeg.txt \
+ structure.txt coderules.txt filelist.txt change.log
+
+# Makefiles for various systems
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+
+# Configuration files
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+
+# Support scripts for configure
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+
+# Miscellaneous support files
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+
+# Test support files
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+
+# libtool libraries to build
+lib_LTLIBRARIES = libjpeg.la
+
+# Library sources for libjpeg.la
+libjpeg_la_SOURCES = $(LIBSOURCES)
+
+# LDFLAGS for libjpeg.la
+libjpeg_la_LDFLAGS = -no-undefined \
+ -version-info $(JPEG_LIB_VERSION)
+
+if HAVE_LD_VERSION_SCRIPT
+ libjpeg_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libjpeg.map
+endif
+
+# Executables to build
+bin_PROGRAMS = cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+# Executable sources & libs
+cjpeg_SOURCES = cjpeg.c rdppm.c rdgif.c rdtarga.c rdrle.c rdbmp.c \
+ rdswitch.c cdjpeg.c
+cjpeg_LDADD = libjpeg.la
+djpeg_SOURCES = djpeg.c wrppm.c wrgif.c wrtarga.c wrrle.c wrbmp.c \
+ rdcolmap.c cdjpeg.c
+djpeg_LDADD = libjpeg.la
+jpegtran_SOURCES = jpegtran.c rdswitch.c cdjpeg.c transupp.c
+jpegtran_LDADD = libjpeg.la
+rdjpgcom_SOURCES = rdjpgcom.c
+wrjpgcom_SOURCES = wrjpgcom.c
+
+# Manual pages to install
+man_MANS = $(DISTMANS)
+
+# Headers to install
+include_HEADERS = $(INSTINCLUDES)
+
+# Other distributed headers
+noinst_HEADERS = $(OTHERINCLUDES)
+
+# Other distributed files
+EXTRA_DIST = $(DOCS) $(DISTMANS) $(MKFILES) $(CONFIGFILES) $(SYSDEPSOURCES) \
+ $(OTHERFILES) $(TESTFILES)
+
+# Files to be cleaned
+CLEANFILES = testout.ppm testout.bmp testout.jpg testoutp.ppm testoutp.jpg \
+ testoutt.jpg
+
+# Install jconfig.h
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(includedir)
+ $(INSTALL_HEADER) jconfig.h $(DESTDIR)$(includedir)/jconfig.h
+
+# Uninstall jconfig.h
+uninstall-local:
+ rm -f $(DESTDIR)$(includedir)/jconfig.h
+
+# Run tests
+test: check-local
+check-local:
+ rm -f testout*
+ ./djpeg -dct int -ppm -outfile testout.ppm $(srcdir)/testorig.jpg
+ ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp $(srcdir)/testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg $(srcdir)/testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm $(srcdir)/testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg $(srcdir)/testimg.ppm
+ ./jpegtran -outfile testoutt.jpg $(srcdir)/testprog.jpg
+ cmp $(srcdir)/testimg.ppm testout.ppm
+ cmp $(srcdir)/testimg.bmp testout.bmp
+ cmp $(srcdir)/testimg.jpg testout.jpg
+ cmp $(srcdir)/testimg.ppm testoutp.ppm
+ cmp $(srcdir)/testimgp.jpg testoutp.jpg
+ cmp $(srcdir)/testorig.jpg testoutt.jpg
diff --git a/jpg/Makefile.in b/jpg/Makefile.in
new file mode 100644
index 0000000..5bda1fb
--- /dev/null
+++ b/jpg/Makefile.in
@@ -0,0 +1,1094 @@
+# Makefile.in generated by automake 1.11.2 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Automake Makefile for the JPEG library
+#
+# This file is written by Bob Friesenhahn, Guido Vollbeding
+#
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+ANSI2KNR = @ANSI2KNR@
+@HAVE_LD_VERSION_SCRIPT_TRUE@am__append_1 = -Wl,--version-script=$(srcdir)/libjpeg.map
+bin_PROGRAMS = cjpeg$(EXEEXT) djpeg$(EXEEXT) jpegtran$(EXEEXT) \
+ rdjpgcom$(EXEEXT) wrjpgcom$(EXEEXT)
+subdir = .
+DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/configure $(am__configure_deps) \
+ $(srcdir)/jconfig.cfg ansi2knr.c ansi2knr.1 depcomp \
+ $(include_HEADERS) $(noinst_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = jconfig.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libjpeg_la_LIBADD =
+am__objects_1 = jaricom$U.lo jcapimin$U.lo jcapistd$U.lo jcarith$U.lo \
+ jccoefct$U.lo jccolor$U.lo jcdctmgr$U.lo jchuff$U.lo \
+ jcinit$U.lo jcmainct$U.lo jcmarker$U.lo jcmaster$U.lo \
+ jcomapi$U.lo jcparam$U.lo jcprepct$U.lo jcsample$U.lo \
+ jctrans$U.lo jdapimin$U.lo jdapistd$U.lo jdarith$U.lo \
+ jdatadst$U.lo jdatasrc$U.lo jdcoefct$U.lo jdcolor$U.lo \
+ jddctmgr$U.lo jdhuff$U.lo jdinput$U.lo jdmainct$U.lo \
+ jdmarker$U.lo jdmaster$U.lo jdmerge$U.lo jdpostct$U.lo \
+ jdsample$U.lo jdtrans$U.lo jerror$U.lo jfdctflt$U.lo \
+ jfdctfst$U.lo jfdctint$U.lo jidctflt$U.lo jidctfst$U.lo \
+ jidctint$U.lo jquant1$U.lo jquant2$U.lo jutils$U.lo \
+ jmemmgr$U.lo @MEMORYMGR@$U.lo
+am_libjpeg_la_OBJECTS = $(am__objects_1)
+libjpeg_la_OBJECTS = $(am_libjpeg_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libjpeg_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libjpeg_la_LDFLAGS) $(LDFLAGS) -o $@
+PROGRAMS = $(bin_PROGRAMS)
+am_cjpeg_OBJECTS = cjpeg$U.$(OBJEXT) rdppm$U.$(OBJEXT) \
+ rdgif$U.$(OBJEXT) rdtarga$U.$(OBJEXT) rdrle$U.$(OBJEXT) \
+ rdbmp$U.$(OBJEXT) rdswitch$U.$(OBJEXT) cdjpeg$U.$(OBJEXT)
+cjpeg_OBJECTS = $(am_cjpeg_OBJECTS)
+cjpeg_DEPENDENCIES = libjpeg.la
+am_djpeg_OBJECTS = djpeg$U.$(OBJEXT) wrppm$U.$(OBJEXT) \
+ wrgif$U.$(OBJEXT) wrtarga$U.$(OBJEXT) wrrle$U.$(OBJEXT) \
+ wrbmp$U.$(OBJEXT) rdcolmap$U.$(OBJEXT) cdjpeg$U.$(OBJEXT)
+djpeg_OBJECTS = $(am_djpeg_OBJECTS)
+djpeg_DEPENDENCIES = libjpeg.la
+am_jpegtran_OBJECTS = jpegtran$U.$(OBJEXT) rdswitch$U.$(OBJEXT) \
+ cdjpeg$U.$(OBJEXT) transupp$U.$(OBJEXT)
+jpegtran_OBJECTS = $(am_jpegtran_OBJECTS)
+jpegtran_DEPENDENCIES = libjpeg.la
+am_rdjpgcom_OBJECTS = rdjpgcom$U.$(OBJEXT)
+rdjpgcom_OBJECTS = $(am_rdjpgcom_OBJECTS)
+rdjpgcom_LDADD = $(LDADD)
+am_wrjpgcom_OBJECTS = wrjpgcom$U.$(OBJEXT)
+wrjpgcom_OBJECTS = $(am_wrjpgcom_OBJECTS)
+wrjpgcom_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libjpeg_la_SOURCES) $(cjpeg_SOURCES) $(djpeg_SOURCES) \
+ $(jpegtran_SOURCES) $(rdjpgcom_SOURCES) $(wrjpgcom_SOURCES)
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+HEADERS = $(include_HEADERS) $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JPEG_LIB_VERSION = @JPEG_LIB_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MEMORYMGR = @MEMORYMGR@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+U = @U@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Sources to build library
+LIBSOURCES = jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c @MEMORYMGR@.c
+
+
+# System dependent sources
+SYSDEPSOURCES = jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+
+# Headers which are installed to support the library
+INSTINCLUDES = jerror.h jmorecfg.h jpeglib.h
+
+# Headers which are not installed
+OTHERINCLUDES = cderror.h cdjpeg.h jdct.h jinclude.h jmemsys.h jpegint.h \
+ jversion.h transupp.h
+
+
+# Manual pages (Automake uses 'MANS' for itself)
+DISTMANS = cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
+
+# Other documentation files
+DOCS = README install.txt usage.txt wizard.txt example.c libjpeg.txt \
+ structure.txt coderules.txt filelist.txt change.log
+
+
+# Makefiles for various systems
+MKFILES = configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+
+
+# Configuration files
+CONFIGFILES = jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+
+
+# Support scripts for configure
+CONFIGUREFILES = config.guess config.sub install-sh ltmain.sh depcomp missing
+
+# Miscellaneous support files
+OTHERFILES = jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+
+
+# Test support files
+TESTFILES = testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+
+
+# libtool libraries to build
+lib_LTLIBRARIES = libjpeg.la
+
+# Library sources for libjpeg.la
+libjpeg_la_SOURCES = $(LIBSOURCES)
+
+# LDFLAGS for libjpeg.la
+libjpeg_la_LDFLAGS = -no-undefined -version-info $(JPEG_LIB_VERSION) \
+ $(am__append_1)
+
+# Executable sources & libs
+cjpeg_SOURCES = cjpeg.c rdppm.c rdgif.c rdtarga.c rdrle.c rdbmp.c \
+ rdswitch.c cdjpeg.c
+
+cjpeg_LDADD = libjpeg.la
+djpeg_SOURCES = djpeg.c wrppm.c wrgif.c wrtarga.c wrrle.c wrbmp.c \
+ rdcolmap.c cdjpeg.c
+
+djpeg_LDADD = libjpeg.la
+jpegtran_SOURCES = jpegtran.c rdswitch.c cdjpeg.c transupp.c
+jpegtran_LDADD = libjpeg.la
+rdjpgcom_SOURCES = rdjpgcom.c
+wrjpgcom_SOURCES = wrjpgcom.c
+
+# Manual pages to install
+man_MANS = $(DISTMANS)
+
+# Headers to install
+include_HEADERS = $(INSTINCLUDES)
+
+# Other distributed headers
+noinst_HEADERS = $(OTHERINCLUDES)
+
+# Other distributed files
+EXTRA_DIST = $(DOCS) $(DISTMANS) $(MKFILES) $(CONFIGFILES) $(SYSDEPSOURCES) \
+ $(OTHERFILES) $(TESTFILES)
+
+
+# Files to be cleaned
+CLEANFILES = testout.ppm testout.bmp testout.jpg testoutp.ppm testoutp.jpg \
+ testoutt.jpg
+
+all: jconfig.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+jconfig.h: stamp-h1
+ @if test ! -f $@; then rm -f stamp-h1; else :; fi
+ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi
+
+stamp-h1: $(srcdir)/jconfig.cfg $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status jconfig.h
+$(srcdir)/jconfig.cfg: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f jconfig.h stamp-h1
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libjpeg.la: $(libjpeg_la_OBJECTS) $(libjpeg_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libjpeg_la_LINK) -rpath $(libdir) $(libjpeg_la_OBJECTS) $(libjpeg_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+cjpeg$(EXEEXT): $(cjpeg_OBJECTS) $(cjpeg_DEPENDENCIES)
+ @rm -f cjpeg$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(cjpeg_OBJECTS) $(cjpeg_LDADD) $(LIBS)
+djpeg$(EXEEXT): $(djpeg_OBJECTS) $(djpeg_DEPENDENCIES)
+ @rm -f djpeg$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(djpeg_OBJECTS) $(djpeg_LDADD) $(LIBS)
+jpegtran$(EXEEXT): $(jpegtran_OBJECTS) $(jpegtran_DEPENDENCIES)
+ @rm -f jpegtran$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(jpegtran_OBJECTS) $(jpegtran_LDADD) $(LIBS)
+rdjpgcom$(EXEEXT): $(rdjpgcom_OBJECTS) $(rdjpgcom_DEPENDENCIES)
+ @rm -f rdjpgcom$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rdjpgcom_OBJECTS) $(rdjpgcom_LDADD) $(LIBS)
+wrjpgcom$(EXEEXT): $(wrjpgcom_OBJECTS) $(wrjpgcom_DEPENDENCIES)
+ @rm -f wrjpgcom$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(wrjpgcom_OBJECTS) $(wrjpgcom_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+./ansi2knr: ansi2knr.$(OBJEXT)
+ $(LINK) ansi2knr.$(OBJEXT) $(LIBS)
+ansi2knr.$(OBJEXT): $(CONFIG_HEADER)
+
+clean-krextra:
+ -rm -f ansi2knr
+
+mostlyclean-kr:
+ -test "$U" = "" || rm -f *_.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/@MEMORYMGR@$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdjpeg$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cjpeg$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/djpeg$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jaricom$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcapimin$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcapistd$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcarith$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jccoefct$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jccolor$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcdctmgr$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jchuff$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcinit$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcmainct$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcmarker$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcmaster$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcomapi$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcparam$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcprepct$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jcsample$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jctrans$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdapimin$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdapistd$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdarith$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdatadst$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdatasrc$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdcoefct$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdcolor$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jddctmgr$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdhuff$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdinput$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdmainct$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdmarker$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdmaster$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdmerge$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdpostct$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdsample$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jdtrans$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jerror$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jfdctflt$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jfdctfst$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jfdctint$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jidctflt$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jidctfst$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jidctint$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jmemmgr$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jpegtran$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jquant1$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jquant2$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jutils$U.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdbmp$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdcolmap$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdgif$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdjpgcom$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdppm$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdrle$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdswitch$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdtarga$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transupp$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrbmp$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrgif$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrjpgcom$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrppm$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrrle$U.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wrtarga$U.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+@MEMORYMGR@_.c: @MEMORYMGR@.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/@MEMORYMGR@.c; then echo $(srcdir)/@MEMORYMGR@.c; else echo @MEMORYMGR@.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+cdjpeg_.c: cdjpeg.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/cdjpeg.c; then echo $(srcdir)/cdjpeg.c; else echo cdjpeg.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+cjpeg_.c: cjpeg.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/cjpeg.c; then echo $(srcdir)/cjpeg.c; else echo cjpeg.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+djpeg_.c: djpeg.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/djpeg.c; then echo $(srcdir)/djpeg.c; else echo djpeg.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jaricom_.c: jaricom.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jaricom.c; then echo $(srcdir)/jaricom.c; else echo jaricom.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcapimin_.c: jcapimin.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcapimin.c; then echo $(srcdir)/jcapimin.c; else echo jcapimin.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcapistd_.c: jcapistd.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcapistd.c; then echo $(srcdir)/jcapistd.c; else echo jcapistd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcarith_.c: jcarith.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcarith.c; then echo $(srcdir)/jcarith.c; else echo jcarith.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jccoefct_.c: jccoefct.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jccoefct.c; then echo $(srcdir)/jccoefct.c; else echo jccoefct.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jccolor_.c: jccolor.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jccolor.c; then echo $(srcdir)/jccolor.c; else echo jccolor.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcdctmgr_.c: jcdctmgr.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcdctmgr.c; then echo $(srcdir)/jcdctmgr.c; else echo jcdctmgr.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jchuff_.c: jchuff.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jchuff.c; then echo $(srcdir)/jchuff.c; else echo jchuff.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcinit_.c: jcinit.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcinit.c; then echo $(srcdir)/jcinit.c; else echo jcinit.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcmainct_.c: jcmainct.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcmainct.c; then echo $(srcdir)/jcmainct.c; else echo jcmainct.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcmarker_.c: jcmarker.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcmarker.c; then echo $(srcdir)/jcmarker.c; else echo jcmarker.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcmaster_.c: jcmaster.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcmaster.c; then echo $(srcdir)/jcmaster.c; else echo jcmaster.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcomapi_.c: jcomapi.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcomapi.c; then echo $(srcdir)/jcomapi.c; else echo jcomapi.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcparam_.c: jcparam.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcparam.c; then echo $(srcdir)/jcparam.c; else echo jcparam.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcprepct_.c: jcprepct.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcprepct.c; then echo $(srcdir)/jcprepct.c; else echo jcprepct.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jcsample_.c: jcsample.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jcsample.c; then echo $(srcdir)/jcsample.c; else echo jcsample.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jctrans_.c: jctrans.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jctrans.c; then echo $(srcdir)/jctrans.c; else echo jctrans.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdapimin_.c: jdapimin.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdapimin.c; then echo $(srcdir)/jdapimin.c; else echo jdapimin.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdapistd_.c: jdapistd.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdapistd.c; then echo $(srcdir)/jdapistd.c; else echo jdapistd.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdarith_.c: jdarith.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdarith.c; then echo $(srcdir)/jdarith.c; else echo jdarith.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdatadst_.c: jdatadst.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdatadst.c; then echo $(srcdir)/jdatadst.c; else echo jdatadst.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdatasrc_.c: jdatasrc.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdatasrc.c; then echo $(srcdir)/jdatasrc.c; else echo jdatasrc.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdcoefct_.c: jdcoefct.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdcoefct.c; then echo $(srcdir)/jdcoefct.c; else echo jdcoefct.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdcolor_.c: jdcolor.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdcolor.c; then echo $(srcdir)/jdcolor.c; else echo jdcolor.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jddctmgr_.c: jddctmgr.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jddctmgr.c; then echo $(srcdir)/jddctmgr.c; else echo jddctmgr.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdhuff_.c: jdhuff.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdhuff.c; then echo $(srcdir)/jdhuff.c; else echo jdhuff.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdinput_.c: jdinput.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdinput.c; then echo $(srcdir)/jdinput.c; else echo jdinput.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdmainct_.c: jdmainct.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdmainct.c; then echo $(srcdir)/jdmainct.c; else echo jdmainct.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdmarker_.c: jdmarker.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdmarker.c; then echo $(srcdir)/jdmarker.c; else echo jdmarker.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdmaster_.c: jdmaster.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdmaster.c; then echo $(srcdir)/jdmaster.c; else echo jdmaster.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdmerge_.c: jdmerge.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdmerge.c; then echo $(srcdir)/jdmerge.c; else echo jdmerge.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdpostct_.c: jdpostct.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdpostct.c; then echo $(srcdir)/jdpostct.c; else echo jdpostct.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdsample_.c: jdsample.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdsample.c; then echo $(srcdir)/jdsample.c; else echo jdsample.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jdtrans_.c: jdtrans.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jdtrans.c; then echo $(srcdir)/jdtrans.c; else echo jdtrans.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jerror_.c: jerror.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jerror.c; then echo $(srcdir)/jerror.c; else echo jerror.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jfdctflt_.c: jfdctflt.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jfdctflt.c; then echo $(srcdir)/jfdctflt.c; else echo jfdctflt.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jfdctfst_.c: jfdctfst.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jfdctfst.c; then echo $(srcdir)/jfdctfst.c; else echo jfdctfst.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jfdctint_.c: jfdctint.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jfdctint.c; then echo $(srcdir)/jfdctint.c; else echo jfdctint.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jidctflt_.c: jidctflt.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jidctflt.c; then echo $(srcdir)/jidctflt.c; else echo jidctflt.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jidctfst_.c: jidctfst.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jidctfst.c; then echo $(srcdir)/jidctfst.c; else echo jidctfst.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jidctint_.c: jidctint.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jidctint.c; then echo $(srcdir)/jidctint.c; else echo jidctint.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jmemmgr_.c: jmemmgr.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jmemmgr.c; then echo $(srcdir)/jmemmgr.c; else echo jmemmgr.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jpegtran_.c: jpegtran.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jpegtran.c; then echo $(srcdir)/jpegtran.c; else echo jpegtran.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jquant1_.c: jquant1.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jquant1.c; then echo $(srcdir)/jquant1.c; else echo jquant1.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jquant2_.c: jquant2.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jquant2.c; then echo $(srcdir)/jquant2.c; else echo jquant2.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+jutils_.c: jutils.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/jutils.c; then echo $(srcdir)/jutils.c; else echo jutils.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+rdbmp_.c: rdbmp.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/rdbmp.c; then echo $(srcdir)/rdbmp.c; else echo rdbmp.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+rdcolmap_.c: rdcolmap.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/rdcolmap.c; then echo $(srcdir)/rdcolmap.c; else echo rdcolmap.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+rdgif_.c: rdgif.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/rdgif.c; then echo $(srcdir)/rdgif.c; else echo rdgif.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+rdjpgcom_.c: rdjpgcom.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/rdjpgcom.c; then echo $(srcdir)/rdjpgcom.c; else echo rdjpgcom.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+rdppm_.c: rdppm.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/rdppm.c; then echo $(srcdir)/rdppm.c; else echo rdppm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+rdrle_.c: rdrle.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/rdrle.c; then echo $(srcdir)/rdrle.c; else echo rdrle.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+rdswitch_.c: rdswitch.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/rdswitch.c; then echo $(srcdir)/rdswitch.c; else echo rdswitch.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+rdtarga_.c: rdtarga.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/rdtarga.c; then echo $(srcdir)/rdtarga.c; else echo rdtarga.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+transupp_.c: transupp.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/transupp.c; then echo $(srcdir)/transupp.c; else echo transupp.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+wrbmp_.c: wrbmp.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/wrbmp.c; then echo $(srcdir)/wrbmp.c; else echo wrbmp.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+wrgif_.c: wrgif.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/wrgif.c; then echo $(srcdir)/wrgif.c; else echo wrgif.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+wrjpgcom_.c: wrjpgcom.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/wrjpgcom.c; then echo $(srcdir)/wrjpgcom.c; else echo wrjpgcom.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+wrppm_.c: wrppm.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/wrppm.c; then echo $(srcdir)/wrppm.c; else echo wrppm.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+wrrle_.c: wrrle.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/wrrle.c; then echo $(srcdir)/wrrle.c; else echo wrrle.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+wrtarga_.c: wrtarga.c $(ANSI2KNR)
+ $(CPP) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) `if test -f $(srcdir)/wrtarga.c; then echo $(srcdir)/wrtarga.c; else echo wrtarga.c; fi` | sed 's/^# \([0-9]\)/#line \1/' | $(ANSI2KNR) > $@ || rm -f $@
+@MEMORYMGR@_.$(OBJEXT) @MEMORYMGR@_.lo cdjpeg_.$(OBJEXT) cdjpeg_.lo \
+cjpeg_.$(OBJEXT) cjpeg_.lo djpeg_.$(OBJEXT) djpeg_.lo \
+jaricom_.$(OBJEXT) jaricom_.lo jcapimin_.$(OBJEXT) jcapimin_.lo \
+jcapistd_.$(OBJEXT) jcapistd_.lo jcarith_.$(OBJEXT) jcarith_.lo \
+jccoefct_.$(OBJEXT) jccoefct_.lo jccolor_.$(OBJEXT) jccolor_.lo \
+jcdctmgr_.$(OBJEXT) jcdctmgr_.lo jchuff_.$(OBJEXT) jchuff_.lo \
+jcinit_.$(OBJEXT) jcinit_.lo jcmainct_.$(OBJEXT) jcmainct_.lo \
+jcmarker_.$(OBJEXT) jcmarker_.lo jcmaster_.$(OBJEXT) jcmaster_.lo \
+jcomapi_.$(OBJEXT) jcomapi_.lo jcparam_.$(OBJEXT) jcparam_.lo \
+jcprepct_.$(OBJEXT) jcprepct_.lo jcsample_.$(OBJEXT) jcsample_.lo \
+jctrans_.$(OBJEXT) jctrans_.lo jdapimin_.$(OBJEXT) jdapimin_.lo \
+jdapistd_.$(OBJEXT) jdapistd_.lo jdarith_.$(OBJEXT) jdarith_.lo \
+jdatadst_.$(OBJEXT) jdatadst_.lo jdatasrc_.$(OBJEXT) jdatasrc_.lo \
+jdcoefct_.$(OBJEXT) jdcoefct_.lo jdcolor_.$(OBJEXT) jdcolor_.lo \
+jddctmgr_.$(OBJEXT) jddctmgr_.lo jdhuff_.$(OBJEXT) jdhuff_.lo \
+jdinput_.$(OBJEXT) jdinput_.lo jdmainct_.$(OBJEXT) jdmainct_.lo \
+jdmarker_.$(OBJEXT) jdmarker_.lo jdmaster_.$(OBJEXT) jdmaster_.lo \
+jdmerge_.$(OBJEXT) jdmerge_.lo jdpostct_.$(OBJEXT) jdpostct_.lo \
+jdsample_.$(OBJEXT) jdsample_.lo jdtrans_.$(OBJEXT) jdtrans_.lo \
+jerror_.$(OBJEXT) jerror_.lo jfdctflt_.$(OBJEXT) jfdctflt_.lo \
+jfdctfst_.$(OBJEXT) jfdctfst_.lo jfdctint_.$(OBJEXT) jfdctint_.lo \
+jidctflt_.$(OBJEXT) jidctflt_.lo jidctfst_.$(OBJEXT) jidctfst_.lo \
+jidctint_.$(OBJEXT) jidctint_.lo jmemmgr_.$(OBJEXT) jmemmgr_.lo \
+jpegtran_.$(OBJEXT) jpegtran_.lo jquant1_.$(OBJEXT) jquant1_.lo \
+jquant2_.$(OBJEXT) jquant2_.lo jutils_.$(OBJEXT) jutils_.lo \
+rdbmp_.$(OBJEXT) rdbmp_.lo rdcolmap_.$(OBJEXT) rdcolmap_.lo \
+rdgif_.$(OBJEXT) rdgif_.lo rdjpgcom_.$(OBJEXT) rdjpgcom_.lo \
+rdppm_.$(OBJEXT) rdppm_.lo rdrle_.$(OBJEXT) rdrle_.lo \
+rdswitch_.$(OBJEXT) rdswitch_.lo rdtarga_.$(OBJEXT) rdtarga_.lo \
+transupp_.$(OBJEXT) transupp_.lo wrbmp_.$(OBJEXT) wrbmp_.lo \
+wrgif_.$(OBJEXT) wrgif_.lo wrjpgcom_.$(OBJEXT) wrjpgcom_.lo \
+wrppm_.$(OBJEXT) wrppm_.lo wrrle_.$(OBJEXT) wrrle_.lo \
+wrtarga_.$(OBJEXT) wrtarga_.lo : $(ANSI2KNR)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+install-man1: $(man_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+ @list=''; test -n "$(man1dir)" || exit 0; \
+ { for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.1[a-z]*$$/p'; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man1dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.1[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) jconfig.cfg $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) jconfig.cfg $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) jconfig.cfg $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) jconfig.cfg $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-local
+check: check-am
+all-am: Makefile $(ANSI2KNR) $(LTLIBRARIES) $(PROGRAMS) $(MANS) \
+ $(HEADERS) jconfig.h
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-krextra \
+ clean-libLTLIBRARIES clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-includeHEADERS install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic mostlyclean-kr \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-includeHEADERS \
+ uninstall-libLTLIBRARIES uninstall-local uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: all check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am am--refresh check check-am check-local \
+ clean clean-binPROGRAMS clean-generic clean-krextra \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags dvi dvi-am html html-am info \
+ info-am install install-am install-binPROGRAMS install-data \
+ install-data-am install-data-local install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-includeHEADERS install-info install-info-am \
+ install-libLTLIBRARIES install-man install-man1 install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-kr mostlyclean-libtool pdf \
+ pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-includeHEADERS \
+ uninstall-libLTLIBRARIES uninstall-local uninstall-man \
+ uninstall-man1
+
+
+# Install jconfig.h
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(includedir)
+ $(INSTALL_HEADER) jconfig.h $(DESTDIR)$(includedir)/jconfig.h
+
+# Uninstall jconfig.h
+uninstall-local:
+ rm -f $(DESTDIR)$(includedir)/jconfig.h
+
+# Run tests
+test: check-local
+check-local:
+ rm -f testout*
+ ./djpeg -dct int -ppm -outfile testout.ppm $(srcdir)/testorig.jpg
+ ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp $(srcdir)/testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg $(srcdir)/testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm $(srcdir)/testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg $(srcdir)/testimg.ppm
+ ./jpegtran -outfile testoutt.jpg $(srcdir)/testprog.jpg
+ cmp $(srcdir)/testimg.ppm testout.ppm
+ cmp $(srcdir)/testimg.bmp testout.bmp
+ cmp $(srcdir)/testimg.jpg testout.jpg
+ cmp $(srcdir)/testimg.ppm testoutp.ppm
+ cmp $(srcdir)/testimgp.jpg testoutp.jpg
+ cmp $(srcdir)/testorig.jpg testoutt.jpg
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/jpg/README b/jpg/README
new file mode 100644
index 0000000..0a23c19
--- /dev/null
+++ b/jpg/README
@@ -0,0 +1,351 @@
+The Independent JPEG Group's JPEG software
+==========================================
+
+README for release 8d of 15-Jan-2012
+====================================
+
+This distribution contains the eighth public release of the Independent JPEG
+Group's free JPEG software. You are welcome to redistribute this software and
+to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
+
+This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
+Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
+Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,
+and other members of the Independent JPEG Group.
+
+IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee
+(also known as JPEG, together with ITU-T SG16).
+
+
+DOCUMENTATION ROADMAP
+=====================
+
+This file contains the following sections:
+
+OVERVIEW General description of JPEG and the IJG software.
+LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
+REFERENCES Where to learn more about JPEG.
+ARCHIVE LOCATIONS Where to find newer versions of this software.
+ACKNOWLEDGMENTS Special thanks.
+FILE FORMAT WARS Software *not* to get.
+TO DO Plans for future IJG releases.
+
+Other documentation files in the distribution are:
+
+User documentation:
+ install.txt How to configure and install the IJG software.
+ usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
+ rdjpgcom, and wrjpgcom.
+ *.1 Unix-style man pages for programs (same info as usage.txt).
+ wizard.txt Advanced usage instructions for JPEG wizards only.
+ change.log Version-to-version change highlights.
+Programmer and internal documentation:
+ libjpeg.txt How to use the JPEG library in your own programs.
+ example.c Sample code for calling the JPEG library.
+ structure.txt Overview of the JPEG library's internal structure.
+ filelist.txt Road map of IJG files.
+ coderules.txt Coding style rules --- please read if you contribute code.
+
+Please read at least the files install.txt and usage.txt. Some information
+can also be found in the JPEG FAQ (Frequently Asked Questions) article. See
+ARCHIVE LOCATIONS below to find out where to obtain the FAQ article.
+
+If you want to understand how the JPEG code works, we suggest reading one or
+more of the REFERENCES, then looking at the documentation files (in roughly
+the order listed) before diving into the code.
+
+
+OVERVIEW
+========
+
+This package contains C software to implement JPEG image encoding, decoding,
+and transcoding. JPEG (pronounced "jay-peg") is a standardized compression
+method for full-color and gray-scale images.
+
+This software implements JPEG baseline, extended-sequential, and progressive
+compression processes. Provision is made for supporting all variants of these
+processes, although some uncommon parameter settings aren't implemented yet.
+We have made no provision for supporting the hierarchical or lossless
+processes defined in the standard.
+
+We provide a set of library routines for reading and writing JPEG image files,
+plus two sample applications "cjpeg" and "djpeg", which use the library to
+perform conversion between JPEG and some other popular image file formats.
+The library is intended to be reused in other applications.
+
+In order to support file conversion and viewing software, we have included
+considerable functionality beyond the bare JPEG coding/decoding capability;
+for example, the color quantization modules are not strictly part of JPEG
+decoding, but they are essential for output to colormapped file formats or
+colormapped displays. These extra functions can be compiled out of the
+library if not required for a particular application.
+
+We have also included "jpegtran", a utility for lossless transcoding between
+different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
+applications for inserting and extracting textual comments in JFIF files.
+
+The emphasis in designing this software has been on achieving portability and
+flexibility, while also making it fast enough to be useful. In particular,
+the software is not intended to be read as a tutorial on JPEG. (See the
+REFERENCES section for introductory material.) Rather, it is intended to
+be reliable, portable, industrial-strength code. We do not claim to have
+achieved that goal in every aspect of the software, but we strive for it.
+
+We welcome the use of this software as a component of commercial products.
+No royalty is required, but we do ask for an acknowledgement in product
+documentation, as described under LEGAL ISSUES.
+
+
+LEGAL ISSUES
+============
+
+In plain English:
+
+1. We don't promise that this software works. (But if you find any bugs,
+ please let us know!)
+2. You can use this software for whatever you want. You don't have to pay us.
+3. You may not pretend that you wrote this software. If you use it in a
+ program, you must acknowledge somewhere in your documentation that
+ you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose. This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library. If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it. This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+ansi2knr.c is included in this distribution by permission of L. Peter Deutsch,
+sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA.
+ansi2knr.c is NOT covered by the above copyright and conditions, but instead
+by the usual distribution terms of the Free Software Foundation; principally,
+that you must include source code if you redistribute it. (See the file
+ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part
+of any program generated from the IJG code, this does not limit you more than
+the foregoing paragraphs do.
+
+The Unix configuration script "configure" was produced with GNU Autoconf.
+It is copyright by the Free Software Foundation but is freely distributable.
+The same holds for its supporting scripts (config.guess, config.sub,
+ltmain.sh). Another support script, install-sh, is copyright by X Consortium
+but is also freely distributable.
+
+The IJG distribution formerly included code to read and write GIF files.
+To avoid entanglement with the Unisys LZW patent, GIF reading support has
+been removed altogether, and the GIF writer has been simplified to produce
+"uncompressed GIFs". This technique does not use the LZW algorithm; the
+resulting GIF files are larger than usual, but are readable by all standard
+GIF decoders.
+
+We are required to state that
+ "The Graphics Interchange Format(c) is the Copyright property of
+ CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ CompuServe Incorporated."
+
+
+REFERENCES
+==========
+
+We recommend reading one or more of these references before trying to
+understand the innards of the JPEG software.
+
+The best short technical introduction to the JPEG compression algorithm is
+ Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+ Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
+(Adjacent articles in that issue discuss MPEG motion picture compression,
+applications of JPEG, and related topics.) If you don't have the CACM issue
+handy, a PostScript file containing a revised version of Wallace's article is
+available at http://www.ijg.org/files/wallace.ps.gz. The file (actually
+a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
+omits the sample images that appeared in CACM, but it includes corrections
+and some added material. Note: the Wallace article is copyright ACM and IEEE,
+and it may not be used for commercial purposes.
+
+A somewhat less technical, more leisurely introduction to JPEG can be found in
+"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
+M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides
+good explanations and example C code for a multitude of compression methods
+including JPEG. It is an excellent source if you are comfortable reading C
+code but don't know much about data compression in general. The book's JPEG
+sample code is far from industrial-strength, but when you are ready to look
+at a full implementation, you've got one here...
+
+The best currently available description of JPEG is the textbook "JPEG Still
+Image Data Compression Standard" by William B. Pennebaker and Joan L.
+Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
+Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG
+standards (DIS 10918-1 and draft DIS 10918-2).
+Although this is by far the most detailed and comprehensive exposition of
+JPEG publicly available, we point out that it is still missing an explanation
+of the most essential properties and algorithms of the underlying DCT
+technology.
+If you think that you know about DCT-based JPEG after reading this book,
+then you are in delusion. The real fundamentals and corresponding potential
+of DCT-based JPEG are not publicly known so far, and that is the reason for
+all the mistaken developments taking place in the image coding domain.
+
+The original JPEG standard is divided into two parts, Part 1 being the actual
+specification, while Part 2 covers compliance testing methods. Part 1 is
+titled "Digital Compression and Coding of Continuous-tone Still Images,
+Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
+10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
+Continuous-tone Still Images, Part 2: Compliance testing" and has document
+numbers ISO/IEC IS 10918-2, ITU-T T.83.
+IJG JPEG 8 introduces an implementation of the JPEG SmartScale extension
+which is specified in two documents: A contributed document at ITU and ISO
+with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced
+Image Coding", April 2006, Geneva, Switzerland. The latest version of this
+document is Revision 3. And a contributed document ISO/IEC JTC1/SC29/WG1 N
+5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany.
+
+The JPEG standard does not specify all details of an interchangeable file
+format. For the omitted details we follow the "JFIF" conventions, revision
+1.02. JFIF 1.02 has been adopted as an Ecma International Technical Report
+and thus received a formal publication status. It is available as a free
+download in PDF format from
+http://www.ecma-international.org/publications/techreports/E-TR-098.htm.
+A PostScript version of the JFIF document is available at
+http://www.ijg.org/files/jfif.ps.gz. There is also a plain text version at
+http://www.ijg.org/files/jfif.txt.gz, but it is missing the figures.
+
+The TIFF 6.0 file format specification can be obtained by FTP from
+ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme
+found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
+IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
+Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
+(Compression tag 7). Copies of this Note can be obtained from
+http://www.ijg.org/files/. It is expected that the next revision
+of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
+Although IJG's own code does not support TIFF/JPEG, the free libtiff library
+uses our library to implement TIFF/JPEG per the Note.
+
+
+ARCHIVE LOCATIONS
+=================
+
+The "official" archive site for this software is www.ijg.org.
+The most recent released version can always be found there in
+directory "files". This particular version will be archived as
+http://www.ijg.org/files/jpegsrc.v8d.tar.gz, and in Windows-compatible
+"zip" archive format as http://www.ijg.org/files/jpegsr8d.zip.
+
+The JPEG FAQ (Frequently Asked Questions) article is a source of some
+general information about JPEG.
+It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
+and other news.answers archive sites, including the official news.answers
+archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
+If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu
+with body
+ send usenet/news.answers/jpeg-faq/part1
+ send usenet/news.answers/jpeg-faq/part2
+
+
+ACKNOWLEDGMENTS
+===============
+
+Thank to Juergen Bruder for providing me with a copy of the common DCT
+algorithm article, only to find out that I had come to the same result
+in a more direct and comprehensible way with a more generative approach.
+
+Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the
+ITU JPEG (Study Group 16) meeting in Geneva, Switzerland.
+
+Thank to Thomas Wiegand and Gary Sullivan for inviting me to the
+Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland.
+
+Thank to Thomas Richter and Daniel Lee for inviting me to the
+ISO/IEC JTC1/SC29/WG1 (also known as JPEG, together with ITU-T SG16)
+meeting in Berlin, Germany.
+
+Thank to John Korejwa and Massimo Ballerini for inviting me to
+fruitful consultations in Boston, MA and Milan, Italy.
+
+Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther
+Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel
+for corresponding business development.
+
+Thank to Nico Zschach and Dirk Stelling of the technical support team
+at the Digital Images company in Halle for providing me with extra
+equipment for configuration tests.
+
+Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful
+communication about JPEG configuration in Sigma Photo Pro software.
+
+Thank to Andrew Finkenstadt for hosting the ijg.org site.
+
+Last but not least special thank to Thomas G. Lane for the original
+design and development of this singular software package.
+
+
+FILE FORMAT WARS
+================
+
+The ISO/IEC JTC1/SC29/WG1 standards committee (also known as JPEG, together
+with ITU-T SG16) currently promotes different formats containing the name
+"JPEG" which is misleading because these formats are incompatible with
+original DCT-based JPEG and are based on faulty technologies.
+IJG therefore does not and will not support such momentary mistakes
+(see REFERENCES).
+There exist also distributions under the name "OpenJPEG" promoting such
+kind of formats which is misleading because they don't support original
+JPEG images.
+We have no sympathy for the promotion of inferior formats. Indeed, one of
+the original reasons for developing this free software was to help force
+convergence on common, interoperable format standards for JPEG files.
+Don't use an incompatible file format!
+(In any case, our decoder will remain capable of reading existing JPEG
+image files indefinitely.)
+
+Furthermore, the ISO committee pretends to be "responsible for the popular
+JPEG" in their public reports which is not true because they don't respond to
+actual requirements for the maintenance of the original JPEG specification.
+
+There are currently distributions in circulation containing the name
+"libjpeg" which claim to be a "derivative" or "fork" of the original
+libjpeg, but don't have the features and are incompatible with formats
+supported by actual IJG libjpeg distributions. Furthermore, they
+violate the license conditions as described under LEGAL ISSUES above.
+We have no sympathy for the release of misleading and illegal
+distributions derived from obsolete code bases.
+Don't use an obsolete code base!
+
+
+TO DO
+=====
+
+Version 8 is the first release of a new generation JPEG standard
+to overcome the limitations of the original JPEG specification.
+More features are being prepared for coming releases...
+
+Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.
diff --git a/jpg/aclocal.m4 b/jpg/aclocal.m4
new file mode 100644
index 0000000..9b38b97
--- /dev/null
+++ b/jpg/aclocal.m4
@@ -0,0 +1,9652 @@
+# generated automatically by aclocal 1.11.2 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
+# Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],,
+[m4_warning([this file was generated for autoconf 2.68.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable. If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins. After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script. The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ _LT_PROG_REPLACE_SHELLFNS
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Go], [_LT_LANG(GO)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_GO. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC], [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+ fi
+fi
+if test -z "$GOC"; then
+ AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+ [LT_LANG(GO)],
+ [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS="$save_LDFLAGS"
+ ])
+
+ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+ [lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+ echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+ $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+ [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ m4_if([$1], [CXX],
+[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+ lt_aix_libpath_sed='[
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }]'
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi],[])
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+ fi
+ ])
+ aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+case "$ECHO" in
+ printf*) AC_MSG_RESULT([printf]) ;;
+ print*) AC_MSG_RESULT([print -r]) ;;
+ *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test "X`printf %s $ECHO`" = "X$ECHO" \
+ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[ --with-sysroot[=DIR] Search for dependent libraries within DIR
+ (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted. We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+ if test "$GCC" = yes; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ AC_MSG_RESULT([${with_sysroot}])
+ AC_MSG_ERROR([The sysroot must be an absolute path.])
+ ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD="${LD-ld}_sol2"
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+ [lt_cv_ar_at_file=no
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+ [echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([lt_ar_try])
+ if test "$ac_status" -eq 0; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ AC_TRY_EVAL([lt_ar_try])
+ if test "$ac_status" -ne 0; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+ ])
+ ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+ [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+ [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+ [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+ test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='${libname}.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec="$LIB"
+ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[23]].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+ [lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [lt_cv_shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+ ])
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+ [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+ [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test "$GCC" != yes; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+ [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+ [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+ AC_SUBST([DUMPBIN])
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh
+ # decide which to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+ [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+ [lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+ MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+ esac
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT@&t@_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data. */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT@&t@_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+ [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+ if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Intel*\ [[CF]]*Compiler*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ *Portland\ Group*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global defined
+ # symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ case $cc_basename in
+ cl*)
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+ ;;
+ esac
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ m4_if($1, [], [
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ _LT_LINKER_OPTION([if $CC understands -b],
+ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+ [lt_cv_irix_exported_symbol],
+ [save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE(
+ [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+ [C++], [[int foo (void) { return 0; }]],
+ [Fortran 77], [[
+ subroutine foo
+ end]],
+ [Fortran], [[
+ subroutine foo
+ end]])])],
+ [lt_cv_irix_exported_symbol=yes],
+ [lt_cv_irix_exported_symbol=no])
+ LDFLAGS="$save_LDFLAGS"])
+ if test "$lt_cv_irix_exported_symbol" = yes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ fi
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+ [$RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ ])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+ [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report which library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_CFLAGS=$CFLAGS
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ CFLAGS=$CXXFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $GXX,$cc_basename in
+ ,cl* | no,cl*)
+ # Native MSVC
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # g++
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd2.*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ gnu*)
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+ '"$_LT_TAGVAR(reload_cmds, $1)"
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)="$GXX"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case ${prev}${p} in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ fi
+
+ # Expand the sysroot to ease extracting the directories later.
+ if test -z "$prev"; then
+ case $p in
+ -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+ -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+ -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+ esac
+ fi
+ case $p in
+ =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+ esac
+ if test "$pre_test_object_deps_done" = no; then
+ case ${prev} in
+ -L | -R)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ prev=
+ ;;
+
+ *.lto.$objext) ;; # Ignore GCC LTO objects
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+ _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${F77-"f77"}
+ CFLAGS=$FFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$G77"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+ CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+ _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${FC-"f95"}
+ CFLAGS=$FCFLAGS
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,b/c, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+ _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac])
+
+ _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+ func_basename_result="${1##*/}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+ func_split_long_opt_name=${1%%=*}
+ func_split_long_opt_arg=${1#*=}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+ func_split_short_opt_arg=${1#??}
+ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac])
+
+ _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo])
+
+ _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))])
+
+ _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+ _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+ func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+ eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+ # Save a `func_append' function call where possible by direct use of '+='
+ sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+else
+ # Save a `func_append' function call even when '+=' is not available
+ sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+ AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+ [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+ [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
+
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ ])
+])# _LT_SET_OPTIONS
+
+
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for lt_pkg in $withval; do
+ IFS="$lt_save_ifs"
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
+
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
+
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
+
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software
+# Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.11'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.11.2], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.11.2])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009,
+# 2010, 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 12
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 16
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.62])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES(OBJC)],
+ [define([AC_PROG_OBJC],
+ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation,
+# Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
+# 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless `enable' is passed literally.
+# For symmetry, `disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation,
+# Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+ [[\\/$]]* | ?:[[\\/]]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software
+# Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2006
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+AC_DEFUN([AM_C_PROTOTYPES],
+[AC_REQUIRE([AC_C_PROTOTYPES])
+AC_DIAGNOSE([obsolete],
+ [$0: automatic de-ANSI-fication support is deprecated])
+if test "$ac_cv_prog_cc_stdc" != no; then
+ U= ANSI2KNR=
+else
+ U=_ ANSI2KNR=./ansi2knr
+fi
+# Ensure some checks needed by ansi2knr itself.
+AC_REQUIRE([AC_HEADER_STDC])
+AC_CHECK_HEADERS([string.h])
+AC_SUBST([U])dnl
+AC_SUBST([ANSI2KNR])dnl
+_AM_SUBST_NOTMAKE([ANSI2KNR])dnl
+])
+
+AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# (`yes' being less verbose, `no' or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules],
+[ --enable-silent-rules less verbose build output (undo: `make V=1')
+ --disable-silent-rules verbose build output (undo: `make V=0')])
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no) AM_DEFAULT_VERBOSITY=1;;
+*) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 3
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
diff --git a/jpg/afiles b/jpg/afiles
new file mode 100644
index 0000000..a0e6ed4
--- /dev/null
+++ b/jpg/afiles
@@ -0,0 +1,185 @@
+afiles
+Jamfile
+Makefile.am
+Makefile.in
+README
+aclocal.m4
+ansi2knr.1
+ansi2knr.c
+cderror.h
+cdjpeg.c
+cdjpeg.h
+change.log
+cjpeg.1
+cjpeg.c
+ckconfig.c
+coderules.txt
+config.guess
+config.sub
+configure
+configure.ac
+depcomp
+djpeg.1
+djpeg.c
+example.c
+filelist.txt
+install-sh
+install.txt
+jaricom.c
+jcapimin.c
+jcapistd.c
+jcarith.c
+jccoefct.c
+jccolor.c
+jcdctmgr.c
+jchuff.c
+jcinit.c
+jcmainct.c
+jcmarker.c
+jcmaster.c
+jcomapi.c
+jconfig.bcc
+jconfig.cfg
+jconfig.dj
+jconfig.mac
+jconfig.manx
+jconfig.mc6
+jconfig.sas
+jconfig.st
+jconfig.txt
+jconfig.vc
+jconfig.vms
+jconfig.wat
+jcparam.c
+jcprepct.c
+jcsample.c
+jctrans.c
+jdapimin.c
+jdapistd.c
+jdarith.c
+jdatadst.c
+jdatasrc.c
+jdcoefct.c
+jdcolor.c
+jdct.h
+jddctmgr.c
+jdhuff.c
+jdinput.c
+jdmainct.c
+jdmarker.c
+jdmaster.c
+jdmerge.c
+jdosaobj.txt
+jdpostct.c
+jdsample.c
+jdtrans.c
+jerror.c
+jerror.h
+jfdctflt.c
+jfdctfst.c
+jfdctint.c
+jidctflt.c
+jidctfst.c
+jidctint.c
+jinclude.h
+jmemansi.c
+jmemdos.c
+jmemdosa.asm
+jmemmac.c
+jmemmgr.c
+jmemname.c
+jmemnobs.c
+jmemsys.h
+jmorecfg.h
+jpegint.h
+jpeglib.h
+jpegsr8d.zip
+jpegtran.1
+jpegtran.c
+jquant1.c
+jquant2.c
+jutils.c
+jversion.h
+libjpeg.map
+libjpeg.txt
+ltmain.sh
+makcjpeg.st
+makdjpeg.st
+makeadsw.vc6
+makeasln.v10
+makecdep.vc6
+makecdsp.vc6
+makecfil.v10
+makecmak.vc6
+makecvcx.v10
+makeddep.vc6
+makeddsp.vc6
+makedfil.v10
+makedmak.vc6
+makedvcx.v10
+makefile.ansi
+makefile.bcc
+makefile.dj
+makefile.manx
+makefile.mc6
+makefile.mms
+makefile.sas
+makefile.unix
+makefile.vc
+makefile.vms
+makefile.wat
+makejdep.vc6
+makejdsp.vc6
+makejdsw.vc6
+makejfil.v10
+makejmak.vc6
+makejsln.v10
+makejvcx.v10
+makeproj.mac
+makerdep.vc6
+makerdsp.vc6
+makerfil.v10
+makermak.vc6
+makervcx.v10
+maketdep.vc6
+maketdsp.vc6
+maketfil.v10
+maketmak.vc6
+maketvcx.v10
+makewdep.vc6
+makewdsp.vc6
+makewfil.v10
+makewmak.vc6
+makewvcx.v10
+makljpeg.st
+maktjpeg.st
+makvms.opt
+missing
+rdbmp.c
+rdcolmap.c
+rdgif.c
+rdjpgcom.1
+rdjpgcom.c
+rdppm.c
+rdrle.c
+rdswitch.c
+rdtarga.c
+readme.dos
+structure.txt
+testimg.bmp
+testimg.jpg
+testimg.ppm
+testimgp.jpg
+testorig.jpg
+testprog.jpg
+transupp.c
+transupp.h
+usage.txt
+wizard.txt
+wrbmp.c
+wrgif.c
+wrjpgcom.1
+wrjpgcom.c
+wrppm.c
+wrrle.c
+wrtarga.c
diff --git a/jpg/ansi2knr.1 b/jpg/ansi2knr.1
new file mode 100644
index 0000000..f9ee5a6
--- /dev/null
+++ b/jpg/ansi2knr.1
@@ -0,0 +1,36 @@
+.TH ANSI2KNR 1 "19 Jan 1996"
+.SH NAME
+ansi2knr \- convert ANSI C to Kernighan & Ritchie C
+.SH SYNOPSIS
+.I ansi2knr
+[--varargs] input_file [output_file]
+.SH DESCRIPTION
+If no output_file is supplied, output goes to stdout.
+.br
+There are no error messages.
+.sp
+.I ansi2knr
+recognizes function definitions by seeing a non-keyword identifier at the left
+margin, followed by a left parenthesis, with a right parenthesis as the last
+character on the line, and with a left brace as the first token on the
+following line (ignoring possible intervening comments). It will recognize a
+multi-line header provided that no intervening line ends with a left or right
+brace or a semicolon. These algorithms ignore whitespace and comments, except
+that the function name must be the first thing on the line.
+.sp
+The following constructs will confuse it:
+.br
+ - Any other construct that starts at the left margin and follows the
+above syntax (such as a macro or function call).
+.br
+ - Some macros that tinker with the syntax of the function header.
+.sp
+The --varargs switch is obsolete, and is recognized only for
+backwards compatibility. The present version of
+.I ansi2knr
+will always attempt to convert a ... argument to va_alist and va_dcl.
+.SH AUTHOR
+L. Peter Deutsch <ghost@aladdin.com> wrote the original ansi2knr and
+continues to maintain the current version; most of the code in the current
+version is his work. ansi2knr also includes contributions by Francois
+Pinard <pinard@iro.umontreal.ca> and Jim Avera <jima@netcom.com>.
diff --git a/jpg/ansi2knr.c b/jpg/ansi2knr.c
new file mode 100644
index 0000000..e84c210
--- /dev/null
+++ b/jpg/ansi2knr.c
@@ -0,0 +1,739 @@
+/* Copyright (C) 1989, 2000 Aladdin Enterprises. All rights reserved. */
+
+/*$Id: ansi2knr.c,v 1.14 2003/09/06 05:36:56 eggert Exp $*/
+/* Convert ANSI C function definitions to K&R ("traditional C") syntax */
+
+/*
+ansi2knr is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY. No author or distributor accepts responsibility to anyone for the
+consequences of using it or for whether it serves any particular purpose or
+works at all, unless he says so in writing. Refer to the GNU General Public
+License (the "GPL") for full details.
+
+Everyone is granted permission to copy, modify and redistribute ansi2knr,
+but only under the conditions described in the GPL. A copy of this license
+is supposed to have been given to you along with ansi2knr so you can know
+your rights and responsibilities. It should be in a file named COPYLEFT,
+or, if there is no file named COPYLEFT, a file named COPYING. Among other
+things, the copyright notice and this notice must be preserved on all
+copies.
+
+We explicitly state here what we believe is already implied by the GPL: if
+the ansi2knr program is distributed as a separate set of sources and a
+separate executable file which are aggregated on a storage medium together
+with another program, this in itself does not bring the other program under
+the GPL, nor does the mere fact that such a program or the procedures for
+constructing it invoke the ansi2knr executable bring any other part of the
+program under the GPL.
+*/
+
+/*
+ * Usage:
+ ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]
+ * --filename provides the file name for the #line directive in the output,
+ * overriding input_file (if present).
+ * If no input_file is supplied, input is read from stdin.
+ * If no output_file is supplied, output goes to stdout.
+ * There are no error messages.
+ *
+ * ansi2knr recognizes function definitions by seeing a non-keyword
+ * identifier at the left margin, followed by a left parenthesis, with a
+ * right parenthesis as the last character on the line, and with a left
+ * brace as the first token on the following line (ignoring possible
+ * intervening comments and/or preprocessor directives), except that a line
+ * consisting of only
+ * identifier1(identifier2)
+ * will not be considered a function definition unless identifier2 is
+ * the word "void", and a line consisting of
+ * identifier1(identifier2, <<arbitrary>>)
+ * will not be considered a function definition.
+ * ansi2knr will recognize a multi-line header provided that no intervening
+ * line ends with a left or right brace or a semicolon. These algorithms
+ * ignore whitespace, comments, and preprocessor directives, except that
+ * the function name must be the first thing on the line. The following
+ * constructs will confuse it:
+ * - Any other construct that starts at the left margin and
+ * follows the above syntax (such as a macro or function call).
+ * - Some macros that tinker with the syntax of function headers.
+ */
+
+/*
+ * The original and principal author of ansi2knr is L. Peter Deutsch
+ * <ghost@aladdin.com>. Other authors are noted in the change history
+ * that follows (in reverse chronological order):
+
+ lpd 2000-04-12 backs out Eggert's changes because of bugs:
+ - concatlits didn't declare the type of its bufend argument;
+ - concatlits didn't recognize when it was inside a comment;
+ - scanstring could scan backward past the beginning of the string; when
+ - the check for \ + newline in scanstring was unnecessary.
+
+ 2000-03-05 Paul Eggert <eggert@twinsun.com>
+
+ Add support for concatenated string literals.
+ * ansi2knr.c (concatlits): New decl.
+ (main): Invoke concatlits to concatenate string literals.
+ (scanstring): Handle backslash-newline correctly. Work with
+ character constants. Fix bug when scanning backwards through
+ backslash-quote. Check for unterminated strings.
+ (convert1): Parse character constants, too.
+ (appendline, concatlits): New functions.
+ * ansi2knr.1: Document this.
+
+ lpd 1999-08-17 added code to allow preprocessor directives
+ wherever comments are allowed
+ lpd 1999-04-12 added minor fixes from Pavel Roskin
+ <pavel_roskin@geocities.com> for clean compilation with
+ gcc -W -Wall
+ lpd 1999-03-22 added hack to recognize lines consisting of
+ identifier1(identifier2, xxx) as *not* being procedures
+ lpd 1999-02-03 made indentation of preprocessor commands consistent
+ lpd 1999-01-28 fixed two bugs: a '/' in an argument list caused an
+ endless loop; quoted strings within an argument list
+ confused the parser
+ lpd 1999-01-24 added a check for write errors on the output,
+ suggested by Jim Meyering <meyering@ascend.com>
+ lpd 1998-11-09 added further hack to recognize identifier(void)
+ as being a procedure
+ lpd 1998-10-23 added hack to recognize lines consisting of
+ identifier1(identifier2) as *not* being procedures
+ lpd 1997-12-08 made input_file optional; only closes input and/or
+ output file if not stdin or stdout respectively; prints
+ usage message on stderr rather than stdout; adds
+ --filename switch (changes suggested by
+ <ceder@lysator.liu.se>)
+ lpd 1996-01-21 added code to cope with not HAVE_CONFIG_H and with
+ compilers that don't understand void, as suggested by
+ Tom Lane
+ lpd 1996-01-15 changed to require that the first non-comment token
+ on the line following a function header be a left brace,
+ to reduce sensitivity to macros, as suggested by Tom Lane
+ <tgl@sss.pgh.pa.us>
+ lpd 1995-06-22 removed #ifndefs whose sole purpose was to define
+ undefined preprocessor symbols as 0; changed all #ifdefs
+ for configuration symbols to #ifs
+ lpd 1995-04-05 changed copyright notice to make it clear that
+ including ansi2knr in a program does not bring the entire
+ program under the GPL
+ lpd 1994-12-18 added conditionals for systems where ctype macros
+ don't handle 8-bit characters properly, suggested by
+ Francois Pinard <pinard@iro.umontreal.ca>;
+ removed --varargs switch (this is now the default)
+ lpd 1994-10-10 removed CONFIG_BROKETS conditional
+ lpd 1994-07-16 added some conditionals to help GNU `configure',
+ suggested by Francois Pinard <pinard@iro.umontreal.ca>;
+ properly erase prototype args in function parameters,
+ contributed by Jim Avera <jima@netcom.com>;
+ correct error in writeblanks (it shouldn't erase EOLs)
+ lpd 1989-xx-xx original version
+ */
+
+/* Most of the conditionals here are to make ansi2knr work with */
+/* or without the GNU configure machinery. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#if HAVE_CONFIG_H
+
+/*
+ For properly autoconfiguring ansi2knr, use AC_CONFIG_HEADER(config.h).
+ This will define HAVE_CONFIG_H and so, activate the following lines.
+ */
+
+# if STDC_HEADERS || HAVE_STRING_H
+# include <string.h>
+# else
+# include <strings.h>
+# endif
+
+#else /* not HAVE_CONFIG_H */
+
+/* Otherwise do it the hard way */
+
+# ifdef BSD
+# include <strings.h>
+# else
+# ifdef VMS
+ extern int strlen(), strncmp();
+# else
+# include <string.h>
+# endif
+# endif
+
+#endif /* not HAVE_CONFIG_H */
+
+#if STDC_HEADERS
+# include <stdlib.h>
+#else
+/*
+ malloc and free should be declared in stdlib.h,
+ but if you've got a K&R compiler, they probably aren't.
+ */
+# ifdef MSDOS
+# include <malloc.h>
+# else
+# ifdef VMS
+ extern char *malloc();
+ extern void free();
+# else
+ extern char *malloc();
+ extern int free();
+# endif
+# endif
+
+#endif
+
+/* Define NULL (for *very* old compilers). */
+#ifndef NULL
+# define NULL (0)
+#endif
+
+/*
+ * The ctype macros don't always handle 8-bit characters correctly.
+ * Compensate for this here.
+ */
+#ifdef isascii
+# undef HAVE_ISASCII /* just in case */
+# define HAVE_ISASCII 1
+#else
+#endif
+#if STDC_HEADERS || !HAVE_ISASCII
+# define is_ascii(c) 1
+#else
+# define is_ascii(c) isascii(c)
+#endif
+
+#define is_space(c) (is_ascii(c) && isspace(c))
+#define is_alpha(c) (is_ascii(c) && isalpha(c))
+#define is_alnum(c) (is_ascii(c) && isalnum(c))
+
+/* Scanning macros */
+#define isidchar(ch) (is_alnum(ch) || (ch) == '_')
+#define isidfirstchar(ch) (is_alpha(ch) || (ch) == '_')
+
+/* Forward references */
+char *ppdirforward();
+char *ppdirbackward();
+char *skipspace();
+char *scanstring();
+int writeblanks();
+int test1();
+int convert1();
+
+/* The main program */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{ FILE *in = stdin;
+ FILE *out = stdout;
+ char *filename = 0;
+ char *program_name = argv[0];
+ char *output_name = 0;
+#define bufsize 5000 /* arbitrary size */
+ char *buf;
+ char *line;
+ char *more;
+ char *usage =
+ "Usage: ansi2knr [--filename FILENAME] [INPUT_FILE [OUTPUT_FILE]]\n";
+ /*
+ * In previous versions, ansi2knr recognized a --varargs switch.
+ * If this switch was supplied, ansi2knr would attempt to convert
+ * a ... argument to va_alist and va_dcl; if this switch was not
+ * supplied, ansi2knr would simply drop any such arguments.
+ * Now, ansi2knr always does this conversion, and we only
+ * check for this switch for backward compatibility.
+ */
+ int convert_varargs = 1;
+ int output_error;
+
+ while ( argc > 1 && argv[1][0] == '-' ) {
+ if ( !strcmp(argv[1], "--varargs") ) {
+ convert_varargs = 1;
+ argc--;
+ argv++;
+ continue;
+ }
+ if ( !strcmp(argv[1], "--filename") && argc > 2 ) {
+ filename = argv[2];
+ argc -= 2;
+ argv += 2;
+ continue;
+ }
+ fprintf(stderr, "%s: Unrecognized switch: %s\n", program_name,
+ argv[1]);
+ fprintf(stderr, usage);
+ exit(1);
+ }
+ switch ( argc )
+ {
+ default:
+ fprintf(stderr, usage);
+ exit(0);
+ case 3:
+ output_name = argv[2];
+ out = fopen(output_name, "w");
+ if ( out == NULL ) {
+ fprintf(stderr, "%s: Cannot open output file %s\n",
+ program_name, output_name);
+ exit(1);
+ }
+ /* falls through */
+ case 2:
+ in = fopen(argv[1], "r");
+ if ( in == NULL ) {
+ fprintf(stderr, "%s: Cannot open input file %s\n",
+ program_name, argv[1]);
+ exit(1);
+ }
+ if ( filename == 0 )
+ filename = argv[1];
+ /* falls through */
+ case 1:
+ break;
+ }
+ if ( filename )
+ fprintf(out, "#line 1 \"%s\"\n", filename);
+ buf = malloc(bufsize);
+ if ( buf == NULL )
+ {
+ fprintf(stderr, "Unable to allocate read buffer!\n");
+ exit(1);
+ }
+ line = buf;
+ while ( fgets(line, (unsigned)(buf + bufsize - line), in) != NULL )
+ {
+test: line += strlen(line);
+ switch ( test1(buf) )
+ {
+ case 2: /* a function header */
+ convert1(buf, out, 1, convert_varargs);
+ break;
+ case 1: /* a function */
+ /* Check for a { at the start of the next line. */
+ more = ++line;
+f: if ( line >= buf + (bufsize - 1) ) /* overflow check */
+ goto wl;
+ if ( fgets(line, (unsigned)(buf + bufsize - line), in) == NULL )
+ goto wl;
+ switch ( *skipspace(ppdirforward(more), 1) )
+ {
+ case '{':
+ /* Definitely a function header. */
+ convert1(buf, out, 0, convert_varargs);
+ fputs(more, out);
+ break;
+ case 0:
+ /* The next line was blank or a comment: */
+ /* keep scanning for a non-comment. */
+ line += strlen(line);
+ goto f;
+ default:
+ /* buf isn't a function header, but */
+ /* more might be. */
+ fputs(buf, out);
+ strcpy(buf, more);
+ line = buf;
+ goto test;
+ }
+ break;
+ case -1: /* maybe the start of a function */
+ if ( line != buf + (bufsize - 1) ) /* overflow check */
+ continue;
+ /* falls through */
+ default: /* not a function */
+wl: fputs(buf, out);
+ break;
+ }
+ line = buf;
+ }
+ if ( line != buf )
+ fputs(buf, out);
+ free(buf);
+ if ( output_name ) {
+ output_error = ferror(out);
+ output_error |= fclose(out);
+ } else { /* out == stdout */
+ fflush(out);
+ output_error = ferror(out);
+ }
+ if ( output_error ) {
+ fprintf(stderr, "%s: error writing to %s\n", program_name,
+ (output_name ? output_name : "stdout"));
+ exit(1);
+ }
+ if ( in != stdin )
+ fclose(in);
+ return 0;
+}
+
+/*
+ * Skip forward or backward over one or more preprocessor directives.
+ */
+char *
+ppdirforward(p)
+ char *p;
+{
+ for (; *p == '#'; ++p) {
+ for (; *p != '\r' && *p != '\n'; ++p)
+ if (*p == 0)
+ return p;
+ if (*p == '\r' && p[1] == '\n')
+ ++p;
+ }
+ return p;
+}
+char *
+ppdirbackward(p, limit)
+ char *p;
+ char *limit;
+{
+ char *np = p;
+
+ for (;; p = --np) {
+ if (*np == '\n' && np[-1] == '\r')
+ --np;
+ for (; np > limit && np[-1] != '\r' && np[-1] != '\n'; --np)
+ if (np[-1] == 0)
+ return np;
+ if (*np != '#')
+ return p;
+ }
+}
+
+/*
+ * Skip over whitespace, comments, and preprocessor directives,
+ * in either direction.
+ */
+char *
+skipspace(p, dir)
+ char *p;
+ int dir; /* 1 for forward, -1 for backward */
+{
+ for ( ; ; ) {
+ while ( is_space(*p) )
+ p += dir;
+ if ( !(*p == '/' && p[dir] == '*') )
+ break;
+ p += dir; p += dir;
+ while ( !(*p == '*' && p[dir] == '/') ) {
+ if ( *p == 0 )
+ return p; /* multi-line comment?? */
+ p += dir;
+ }
+ p += dir; p += dir;
+ }
+ return p;
+}
+
+/* Scan over a quoted string, in either direction. */
+char *
+scanstring(p, dir)
+ char *p;
+ int dir;
+{
+ for (p += dir; ; p += dir)
+ if (*p == '"' && p[-dir] != '\\')
+ return p + dir;
+}
+
+/*
+ * Write blanks over part of a string.
+ * Don't overwrite end-of-line characters.
+ */
+int
+writeblanks(start, end)
+ char *start;
+ char *end;
+{ char *p;
+ for ( p = start; p < end; p++ )
+ if ( *p != '\r' && *p != '\n' )
+ *p = ' ';
+ return 0;
+}
+
+/*
+ * Test whether the string in buf is a function definition.
+ * The string may contain and/or end with a newline.
+ * Return as follows:
+ * 0 - definitely not a function definition;
+ * 1 - definitely a function definition;
+ * 2 - definitely a function prototype (NOT USED);
+ * -1 - may be the beginning of a function definition,
+ * append another line and look again.
+ * The reason we don't attempt to convert function prototypes is that
+ * Ghostscript's declaration-generating macros look too much like
+ * prototypes, and confuse the algorithms.
+ */
+int
+test1(buf)
+ char *buf;
+{ char *p = buf;
+ char *bend;
+ char *endfn;
+ int contin;
+
+ if ( !isidfirstchar(*p) )
+ return 0; /* no name at left margin */
+ bend = skipspace(ppdirbackward(buf + strlen(buf) - 1, buf), -1);
+ switch ( *bend )
+ {
+ case ';': contin = 0 /*2*/; break;
+ case ')': contin = 1; break;
+ case '{': return 0; /* not a function */
+ case '}': return 0; /* not a function */
+ default: contin = -1;
+ }
+ while ( isidchar(*p) )
+ p++;
+ endfn = p;
+ p = skipspace(p, 1);
+ if ( *p++ != '(' )
+ return 0; /* not a function */
+ p = skipspace(p, 1);
+ if ( *p == ')' )
+ return 0; /* no parameters */
+ /* Check that the apparent function name isn't a keyword. */
+ /* We only need to check for keywords that could be followed */
+ /* by a left parenthesis (which, unfortunately, is most of them). */
+ { static char *words[] =
+ { "asm", "auto", "case", "char", "const", "double",
+ "extern", "float", "for", "if", "int", "long",
+ "register", "return", "short", "signed", "sizeof",
+ "static", "switch", "typedef", "unsigned",
+ "void", "volatile", "while", 0
+ };
+ char **key = words;
+ char *kp;
+ unsigned len = endfn - buf;
+
+ while ( (kp = *key) != 0 )
+ { if ( strlen(kp) == len && !strncmp(kp, buf, len) )
+ return 0; /* name is a keyword */
+ key++;
+ }
+ }
+ {
+ char *id = p;
+ int len;
+ /*
+ * Check for identifier1(identifier2) and not
+ * identifier1(void), or identifier1(identifier2, xxxx).
+ */
+
+ while ( isidchar(*p) )
+ p++;
+ len = p - id;
+ p = skipspace(p, 1);
+ if (*p == ',' ||
+ (*p == ')' && (len != 4 || strncmp(id, "void", 4)))
+ )
+ return 0; /* not a function */
+ }
+ /*
+ * If the last significant character was a ), we need to count
+ * parentheses, because it might be part of a formal parameter
+ * that is a procedure.
+ */
+ if (contin > 0) {
+ int level = 0;
+
+ for (p = skipspace(buf, 1); *p; p = skipspace(p + 1, 1))
+ level += (*p == '(' ? 1 : *p == ')' ? -1 : 0);
+ if (level > 0)
+ contin = -1;
+ }
+ return contin;
+}
+
+/* Convert a recognized function definition or header to K&R syntax. */
+int
+convert1(buf, out, header, convert_varargs)
+ char *buf;
+ FILE *out;
+ int header; /* Boolean */
+ int convert_varargs; /* Boolean */
+{ char *endfn;
+ char *p;
+ /*
+ * The breaks table contains pointers to the beginning and end
+ * of each argument.
+ */
+ char **breaks;
+ unsigned num_breaks = 2; /* for testing */
+ char **btop;
+ char **bp;
+ char **ap;
+ char *vararg = 0;
+
+ /* Pre-ANSI implementations don't agree on whether strchr */
+ /* is called strchr or index, so we open-code it here. */
+ for ( endfn = buf; *(endfn++) != '('; )
+ ;
+top: p = endfn;
+ breaks = (char **)malloc(sizeof(char *) * num_breaks * 2);
+ if ( breaks == NULL )
+ { /* Couldn't allocate break table, give up */
+ fprintf(stderr, "Unable to allocate break table!\n");
+ fputs(buf, out);
+ return -1;
+ }
+ btop = breaks + num_breaks * 2 - 2;
+ bp = breaks;
+ /* Parse the argument list */
+ do
+ { int level = 0;
+ char *lp = NULL;
+ char *rp = NULL;
+ char *end = NULL;
+
+ if ( bp >= btop )
+ { /* Filled up break table. */
+ /* Allocate a bigger one and start over. */
+ free((char *)breaks);
+ num_breaks <<= 1;
+ goto top;
+ }
+ *bp++ = p;
+ /* Find the end of the argument */
+ for ( ; end == NULL; p++ )
+ { switch(*p)
+ {
+ case ',':
+ if ( !level ) end = p;
+ break;
+ case '(':
+ if ( !level ) lp = p;
+ level++;
+ break;
+ case ')':
+ if ( --level < 0 ) end = p;
+ else rp = p;
+ break;
+ case '/':
+ if (p[1] == '*')
+ p = skipspace(p, 1) - 1;
+ break;
+ case '"':
+ p = scanstring(p, 1) - 1;
+ break;
+ default:
+ ;
+ }
+ }
+ /* Erase any embedded prototype parameters. */
+ if ( lp && rp )
+ writeblanks(lp + 1, rp);
+ p--; /* back up over terminator */
+ /* Find the name being declared. */
+ /* This is complicated because of procedure and */
+ /* array modifiers. */
+ for ( ; ; )
+ { p = skipspace(p - 1, -1);
+ switch ( *p )
+ {
+ case ']': /* skip array dimension(s) */
+ case ')': /* skip procedure args OR name */
+ { int level = 1;
+ while ( level )
+ switch ( *--p )
+ {
+ case ']': case ')':
+ level++;
+ break;
+ case '[': case '(':
+ level--;
+ break;
+ case '/':
+ if (p > buf && p[-1] == '*')
+ p = skipspace(p, -1) + 1;
+ break;
+ case '"':
+ p = scanstring(p, -1) + 1;
+ break;
+ default: ;
+ }
+ }
+ if ( *p == '(' && *skipspace(p + 1, 1) == '*' )
+ { /* We found the name being declared */
+ while ( !isidfirstchar(*p) )
+ p = skipspace(p, 1) + 1;
+ goto found;
+ }
+ break;
+ default:
+ goto found;
+ }
+ }
+found: if ( *p == '.' && p[-1] == '.' && p[-2] == '.' )
+ { if ( convert_varargs )
+ { *bp++ = "va_alist";
+ vararg = p-2;
+ }
+ else
+ { p++;
+ if ( bp == breaks + 1 ) /* sole argument */
+ writeblanks(breaks[0], p);
+ else
+ writeblanks(bp[-1] - 1, p);
+ bp--;
+ }
+ }
+ else
+ { while ( isidchar(*p) ) p--;
+ *bp++ = p+1;
+ }
+ p = end;
+ }
+ while ( *p++ == ',' );
+ *bp = p;
+ /* Make a special check for 'void' arglist */
+ if ( bp == breaks+2 )
+ { p = skipspace(breaks[0], 1);
+ if ( !strncmp(p, "void", 4) )
+ { p = skipspace(p+4, 1);
+ if ( p == breaks[2] - 1 )
+ { bp = breaks; /* yup, pretend arglist is empty */
+ writeblanks(breaks[0], p + 1);
+ }
+ }
+ }
+ /* Put out the function name and left parenthesis. */
+ p = buf;
+ while ( p != endfn ) putc(*p, out), p++;
+ /* Put out the declaration. */
+ if ( header )
+ { fputs(");", out);
+ for ( p = breaks[0]; *p; p++ )
+ if ( *p == '\r' || *p == '\n' )
+ putc(*p, out);
+ }
+ else
+ { for ( ap = breaks+1; ap < bp; ap += 2 )
+ { p = *ap;
+ while ( isidchar(*p) )
+ putc(*p, out), p++;
+ if ( ap < bp - 1 )
+ fputs(", ", out);
+ }
+ fputs(") ", out);
+ /* Put out the argument declarations */
+ for ( ap = breaks+2; ap <= bp; ap += 2 )
+ (*ap)[-1] = ';';
+ if ( vararg != 0 )
+ { *vararg = 0;
+ fputs(breaks[0], out); /* any prior args */
+ fputs("va_dcl", out); /* the final arg */
+ fputs(bp[0], out);
+ }
+ else
+ fputs(breaks[0], out);
+ }
+ free((char *)breaks);
+ return 0;
+}
diff --git a/jpg/cderror.h b/jpg/cderror.h
new file mode 100644
index 0000000..e19c475
--- /dev/null
+++ b/jpg/cderror.h
@@ -0,0 +1,134 @@
+/*
+ * cderror.h
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the cjpeg/djpeg
+ * applications. These strings are not needed as part of the JPEG library
+ * proper.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ */
+
+/*
+ * To define the enum list of message codes, include this file without
+ * defining macro JMESSAGE. To create a message string table, include it
+ * again with a suitable JMESSAGE definition (see jerror.c for an example).
+ */
+#ifndef JMESSAGE
+#ifndef CDERROR_H
+#define CDERROR_H
+/* First time through, define the enum list */
+#define JMAKE_ENUM_LIST
+#else
+/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
+#define JMESSAGE(code,string)
+#endif /* CDERROR_H */
+#endif /* JMESSAGE */
+
+#ifdef JMAKE_ENUM_LIST
+
+typedef enum {
+
+#define JMESSAGE(code,string) code ,
+
+#endif /* JMAKE_ENUM_LIST */
+
+JMESSAGE(JMSG_FIRSTADDONCODE=1000, NULL) /* Must be first entry! */
+
+#ifdef BMP_SUPPORTED
+JMESSAGE(JERR_BMP_BADCMAP, "Unsupported BMP colormap format")
+JMESSAGE(JERR_BMP_BADDEPTH, "Only 8- and 24-bit BMP files are supported")
+JMESSAGE(JERR_BMP_BADHEADER, "Invalid BMP file: bad header length")
+JMESSAGE(JERR_BMP_BADPLANES, "Invalid BMP file: biPlanes not equal to 1")
+JMESSAGE(JERR_BMP_COLORSPACE, "BMP output must be grayscale or RGB")
+JMESSAGE(JERR_BMP_COMPRESSED, "Sorry, compressed BMPs not yet supported")
+JMESSAGE(JERR_BMP_EMPTY, "Empty BMP image")
+JMESSAGE(JERR_BMP_NOT, "Not a BMP file - does not start with BM")
+JMESSAGE(JTRC_BMP, "%ux%u 24-bit BMP image")
+JMESSAGE(JTRC_BMP_MAPPED, "%ux%u 8-bit colormapped BMP image")
+JMESSAGE(JTRC_BMP_OS2, "%ux%u 24-bit OS2 BMP image")
+JMESSAGE(JTRC_BMP_OS2_MAPPED, "%ux%u 8-bit colormapped OS2 BMP image")
+#endif /* BMP_SUPPORTED */
+
+#ifdef GIF_SUPPORTED
+JMESSAGE(JERR_GIF_BUG, "GIF output got confused")
+JMESSAGE(JERR_GIF_CODESIZE, "Bogus GIF codesize %d")
+JMESSAGE(JERR_GIF_COLORSPACE, "GIF output must be grayscale or RGB")
+JMESSAGE(JERR_GIF_IMAGENOTFOUND, "Too few images in GIF file")
+JMESSAGE(JERR_GIF_NOT, "Not a GIF file")
+JMESSAGE(JTRC_GIF, "%ux%ux%d GIF image")
+JMESSAGE(JTRC_GIF_BADVERSION,
+ "Warning: unexpected GIF version number '%c%c%c'")
+JMESSAGE(JTRC_GIF_EXTENSION, "Ignoring GIF extension block of type 0x%02x")
+JMESSAGE(JTRC_GIF_NONSQUARE, "Caution: nonsquare pixels in input")
+JMESSAGE(JWRN_GIF_BADDATA, "Corrupt data in GIF file")
+JMESSAGE(JWRN_GIF_CHAR, "Bogus char 0x%02x in GIF file, ignoring")
+JMESSAGE(JWRN_GIF_ENDCODE, "Premature end of GIF image")
+JMESSAGE(JWRN_GIF_NOMOREDATA, "Ran out of GIF bits")
+#endif /* GIF_SUPPORTED */
+
+#ifdef PPM_SUPPORTED
+JMESSAGE(JERR_PPM_COLORSPACE, "PPM output must be grayscale or RGB")
+JMESSAGE(JERR_PPM_NONNUMERIC, "Nonnumeric data in PPM file")
+JMESSAGE(JERR_PPM_NOT, "Not a PPM/PGM file")
+JMESSAGE(JTRC_PGM, "%ux%u PGM image")
+JMESSAGE(JTRC_PGM_TEXT, "%ux%u text PGM image")
+JMESSAGE(JTRC_PPM, "%ux%u PPM image")
+JMESSAGE(JTRC_PPM_TEXT, "%ux%u text PPM image")
+#endif /* PPM_SUPPORTED */
+
+#ifdef RLE_SUPPORTED
+JMESSAGE(JERR_RLE_BADERROR, "Bogus error code from RLE library")
+JMESSAGE(JERR_RLE_COLORSPACE, "RLE output must be grayscale or RGB")
+JMESSAGE(JERR_RLE_DIMENSIONS, "Image dimensions (%ux%u) too large for RLE")
+JMESSAGE(JERR_RLE_EMPTY, "Empty RLE file")
+JMESSAGE(JERR_RLE_EOF, "Premature EOF in RLE header")
+JMESSAGE(JERR_RLE_MEM, "Insufficient memory for RLE header")
+JMESSAGE(JERR_RLE_NOT, "Not an RLE file")
+JMESSAGE(JERR_RLE_TOOMANYCHANNELS, "Cannot handle %d output channels for RLE")
+JMESSAGE(JERR_RLE_UNSUPPORTED, "Cannot handle this RLE setup")
+JMESSAGE(JTRC_RLE, "%ux%u full-color RLE file")
+JMESSAGE(JTRC_RLE_FULLMAP, "%ux%u full-color RLE file with map of length %d")
+JMESSAGE(JTRC_RLE_GRAY, "%ux%u grayscale RLE file")
+JMESSAGE(JTRC_RLE_MAPGRAY, "%ux%u grayscale RLE file with map of length %d")
+JMESSAGE(JTRC_RLE_MAPPED, "%ux%u colormapped RLE file with map of length %d")
+#endif /* RLE_SUPPORTED */
+
+#ifdef TARGA_SUPPORTED
+JMESSAGE(JERR_TGA_BADCMAP, "Unsupported Targa colormap format")
+JMESSAGE(JERR_TGA_BADPARMS, "Invalid or unsupported Targa file")
+JMESSAGE(JERR_TGA_COLORSPACE, "Targa output must be grayscale or RGB")
+JMESSAGE(JTRC_TGA, "%ux%u RGB Targa image")
+JMESSAGE(JTRC_TGA_GRAY, "%ux%u grayscale Targa image")
+JMESSAGE(JTRC_TGA_MAPPED, "%ux%u colormapped Targa image")
+#else
+JMESSAGE(JERR_TGA_NOTCOMP, "Targa support was not compiled")
+#endif /* TARGA_SUPPORTED */
+
+JMESSAGE(JERR_BAD_CMAP_FILE,
+ "Color map file is invalid or of unsupported format")
+JMESSAGE(JERR_TOO_MANY_COLORS,
+ "Output file format cannot handle %d colormap entries")
+JMESSAGE(JERR_UNGETC_FAILED, "ungetc failed")
+#ifdef TARGA_SUPPORTED
+JMESSAGE(JERR_UNKNOWN_FORMAT,
+ "Unrecognized input file format --- perhaps you need -targa")
+#else
+JMESSAGE(JERR_UNKNOWN_FORMAT, "Unrecognized input file format")
+#endif
+JMESSAGE(JERR_UNSUPPORTED_FORMAT, "Unsupported output file format")
+
+#ifdef JMAKE_ENUM_LIST
+
+ JMSG_LASTADDONCODE
+} ADDON_MESSAGE_CODE;
+
+#undef JMAKE_ENUM_LIST
+#endif /* JMAKE_ENUM_LIST */
+
+/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
+#undef JMESSAGE
diff --git a/jpg/cdjpeg.c b/jpg/cdjpeg.c
new file mode 100644
index 0000000..b6250ff
--- /dev/null
+++ b/jpg/cdjpeg.c
@@ -0,0 +1,181 @@
+/*
+ * cdjpeg.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains common support routines used by the IJG application
+ * programs (cjpeg, djpeg, jpegtran).
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include <ctype.h> /* to declare isupper(), tolower() */
+#ifdef NEED_SIGNAL_CATCHER
+#include <signal.h> /* to declare signal() */
+#endif
+#ifdef USE_SETMODE
+#include <fcntl.h> /* to declare setmode()'s parameter macros */
+/* If you have setmode() but not <io.h>, just delete this line: */
+#include <io.h> /* to declare setmode() */
+#endif
+
+
+/*
+ * Signal catcher to ensure that temporary files are removed before aborting.
+ * NB: for Amiga Manx C this is actually a global routine named _abort();
+ * we put "#define signal_catcher _abort" in jconfig.h. Talk about bogus...
+ */
+
+#ifdef NEED_SIGNAL_CATCHER
+
+static j_common_ptr sig_cinfo;
+
+void /* must be global for Manx C */
+signal_catcher (int signum)
+{
+ if (sig_cinfo != NULL) {
+ if (sig_cinfo->err != NULL) /* turn off trace output */
+ sig_cinfo->err->trace_level = 0;
+ jpeg_destroy(sig_cinfo); /* clean up memory allocation & temp files */
+ }
+ exit(EXIT_FAILURE);
+}
+
+
+GLOBAL(void)
+enable_signal_catcher (j_common_ptr cinfo)
+{
+ sig_cinfo = cinfo;
+#ifdef SIGINT /* not all systems have SIGINT */
+ signal(SIGINT, signal_catcher);
+#endif
+#ifdef SIGTERM /* not all systems have SIGTERM */
+ signal(SIGTERM, signal_catcher);
+#endif
+}
+
+#endif
+
+
+/*
+ * Optional progress monitor: display a percent-done figure on stderr.
+ */
+
+#ifdef PROGRESS_REPORT
+
+METHODDEF(void)
+progress_monitor (j_common_ptr cinfo)
+{
+ cd_progress_ptr prog = (cd_progress_ptr) cinfo->progress;
+ int total_passes = prog->pub.total_passes + prog->total_extra_passes;
+ int percent_done = (int) (prog->pub.pass_counter*100L/prog->pub.pass_limit);
+
+ if (percent_done != prog->percent_done) {
+ prog->percent_done = percent_done;
+ if (total_passes > 1) {
+ fprintf(stderr, "\rPass %d/%d: %3d%% ",
+ prog->pub.completed_passes + prog->completed_extra_passes + 1,
+ total_passes, percent_done);
+ } else {
+ fprintf(stderr, "\r %3d%% ", percent_done);
+ }
+ fflush(stderr);
+ }
+}
+
+
+GLOBAL(void)
+start_progress_monitor (j_common_ptr cinfo, cd_progress_ptr progress)
+{
+ /* Enable progress display, unless trace output is on */
+ if (cinfo->err->trace_level == 0) {
+ progress->pub.progress_monitor = progress_monitor;
+ progress->completed_extra_passes = 0;
+ progress->total_extra_passes = 0;
+ progress->percent_done = -1;
+ cinfo->progress = &progress->pub;
+ }
+}
+
+
+GLOBAL(void)
+end_progress_monitor (j_common_ptr cinfo)
+{
+ /* Clear away progress display */
+ if (cinfo->err->trace_level == 0) {
+ fprintf(stderr, "\r \r");
+ fflush(stderr);
+ }
+}
+
+#endif
+
+
+/*
+ * Case-insensitive matching of possibly-abbreviated keyword switches.
+ * keyword is the constant keyword (must be lower case already),
+ * minchars is length of minimum legal abbreviation.
+ */
+
+GLOBAL(boolean)
+keymatch (char * arg, const char * keyword, int minchars)
+{
+ register int ca, ck;
+ register int nmatched = 0;
+
+ while ((ca = *arg++) != '\0') {
+ if ((ck = *keyword++) == '\0')
+ return FALSE; /* arg longer than keyword, no good */
+ if (isupper(ca)) /* force arg to lcase (assume ck is already) */
+ ca = tolower(ca);
+ if (ca != ck)
+ return FALSE; /* no good */
+ nmatched++; /* count matched characters */
+ }
+ /* reached end of argument; fail if it's too short for unique abbrev */
+ if (nmatched < minchars)
+ return FALSE;
+ return TRUE; /* A-OK */
+}
+
+
+/*
+ * Routines to establish binary I/O mode for stdin and stdout.
+ * Non-Unix systems often require some hacking to get out of text mode.
+ */
+
+GLOBAL(FILE *)
+read_stdin (void)
+{
+ FILE * input_file = stdin;
+
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+ fprintf(stderr, "Cannot reopen stdin\n");
+ exit(EXIT_FAILURE);
+ }
+#endif
+ return input_file;
+}
+
+
+GLOBAL(FILE *)
+write_stdout (void)
+{
+ FILE * output_file = stdout;
+
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdout), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "Cannot reopen stdout\n");
+ exit(EXIT_FAILURE);
+ }
+#endif
+ return output_file;
+}
diff --git a/jpg/cdjpeg.h b/jpg/cdjpeg.h
new file mode 100644
index 0000000..ed024ac
--- /dev/null
+++ b/jpg/cdjpeg.h
@@ -0,0 +1,187 @@
+/*
+ * cdjpeg.h
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains common declarations for the sample applications
+ * cjpeg and djpeg. It is NOT used by the core JPEG library.
+ */
+
+#define JPEG_CJPEG_DJPEG /* define proper options in jconfig.h */
+#define JPEG_INTERNAL_OPTIONS /* cjpeg.c,djpeg.c need to see xxx_SUPPORTED */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h" /* get library error codes too */
+#include "cderror.h" /* get application-specific error codes */
+
+
+/*
+ * Object interface for cjpeg's source file decoding modules
+ */
+
+typedef struct cjpeg_source_struct * cjpeg_source_ptr;
+
+struct cjpeg_source_struct {
+ JMETHOD(void, start_input, (j_compress_ptr cinfo,
+ cjpeg_source_ptr sinfo));
+ JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
+ cjpeg_source_ptr sinfo));
+ JMETHOD(void, finish_input, (j_compress_ptr cinfo,
+ cjpeg_source_ptr sinfo));
+
+ FILE *input_file;
+
+ JSAMPARRAY buffer;
+ JDIMENSION buffer_height;
+};
+
+
+/*
+ * Object interface for djpeg's output file encoding modules
+ */
+
+typedef struct djpeg_dest_struct * djpeg_dest_ptr;
+
+struct djpeg_dest_struct {
+ /* start_output is called after jpeg_start_decompress finishes.
+ * The color map will be ready at this time, if one is needed.
+ */
+ JMETHOD(void, start_output, (j_decompress_ptr cinfo,
+ djpeg_dest_ptr dinfo));
+ /* Emit the specified number of pixel rows from the buffer. */
+ JMETHOD(void, put_pixel_rows, (j_decompress_ptr cinfo,
+ djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied));
+ /* Finish up at the end of the image. */
+ JMETHOD(void, finish_output, (j_decompress_ptr cinfo,
+ djpeg_dest_ptr dinfo));
+
+ /* Target file spec; filled in by djpeg.c after object is created. */
+ FILE * output_file;
+
+ /* Output pixel-row buffer. Created by module init or start_output.
+ * Width is cinfo->output_width * cinfo->output_components;
+ * height is buffer_height.
+ */
+ JSAMPARRAY buffer;
+ JDIMENSION buffer_height;
+};
+
+
+/*
+ * cjpeg/djpeg may need to perform extra passes to convert to or from
+ * the source/destination file format. The JPEG library does not know
+ * about these passes, but we'd like them to be counted by the progress
+ * monitor. We use an expanded progress monitor object to hold the
+ * additional pass count.
+ */
+
+struct cdjpeg_progress_mgr {
+ struct jpeg_progress_mgr pub; /* fields known to JPEG library */
+ int completed_extra_passes; /* extra passes completed */
+ int total_extra_passes; /* total extra */
+ /* last printed percentage stored here to avoid multiple printouts */
+ int percent_done;
+};
+
+typedef struct cdjpeg_progress_mgr * cd_progress_ptr;
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jinit_read_bmp jIRdBMP
+#define jinit_write_bmp jIWrBMP
+#define jinit_read_gif jIRdGIF
+#define jinit_write_gif jIWrGIF
+#define jinit_read_ppm jIRdPPM
+#define jinit_write_ppm jIWrPPM
+#define jinit_read_rle jIRdRLE
+#define jinit_write_rle jIWrRLE
+#define jinit_read_targa jIRdTarga
+#define jinit_write_targa jIWrTarga
+#define read_quant_tables RdQTables
+#define read_scan_script RdScnScript
+#define set_quality_ratings SetQRates
+#define set_quant_slots SetQSlots
+#define set_sample_factors SetSFacts
+#define read_color_map RdCMap
+#define enable_signal_catcher EnSigCatcher
+#define start_progress_monitor StProgMon
+#define end_progress_monitor EnProgMon
+#define read_stdin RdStdin
+#define write_stdout WrStdout
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+/* Module selection routines for I/O modules. */
+
+EXTERN(cjpeg_source_ptr) jinit_read_bmp JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_bmp JPP((j_decompress_ptr cinfo,
+ boolean is_os2));
+EXTERN(cjpeg_source_ptr) jinit_read_gif JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_gif JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_ppm JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_ppm JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_rle JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_rle JPP((j_decompress_ptr cinfo));
+EXTERN(cjpeg_source_ptr) jinit_read_targa JPP((j_compress_ptr cinfo));
+EXTERN(djpeg_dest_ptr) jinit_write_targa JPP((j_decompress_ptr cinfo));
+
+/* cjpeg support routines (in rdswitch.c) */
+
+EXTERN(boolean) read_quant_tables JPP((j_compress_ptr cinfo, char * filename,
+ boolean force_baseline));
+EXTERN(boolean) read_scan_script JPP((j_compress_ptr cinfo, char * filename));
+EXTERN(boolean) set_quality_ratings JPP((j_compress_ptr cinfo, char *arg,
+ boolean force_baseline));
+EXTERN(boolean) set_quant_slots JPP((j_compress_ptr cinfo, char *arg));
+EXTERN(boolean) set_sample_factors JPP((j_compress_ptr cinfo, char *arg));
+
+/* djpeg support routines (in rdcolmap.c) */
+
+EXTERN(void) read_color_map JPP((j_decompress_ptr cinfo, FILE * infile));
+
+/* common support routines (in cdjpeg.c) */
+
+EXTERN(void) enable_signal_catcher JPP((j_common_ptr cinfo));
+EXTERN(void) start_progress_monitor JPP((j_common_ptr cinfo,
+ cd_progress_ptr progress));
+EXTERN(void) end_progress_monitor JPP((j_common_ptr cinfo));
+EXTERN(boolean) keymatch JPP((char * arg, const char * keyword, int minchars));
+EXTERN(FILE *) read_stdin JPP((void));
+EXTERN(FILE *) write_stdout JPP((void));
+
+/* miscellaneous useful macros */
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#define WRITE_BINARY "w"
+#else
+#ifdef VMS /* VMS is very nonstandard */
+#define READ_BINARY "rb", "ctx=stm"
+#define WRITE_BINARY "wb", "ctx=stm"
+#else /* standard ANSI-compliant case */
+#define READ_BINARY "rb"
+#define WRITE_BINARY "wb"
+#endif
+#endif
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+#ifdef VMS
+#define EXIT_SUCCESS 1 /* VMS is very nonstandard */
+#else
+#define EXIT_SUCCESS 0
+#endif
+#endif
+#ifndef EXIT_WARNING
+#ifdef VMS
+#define EXIT_WARNING 1 /* VMS is very nonstandard */
+#else
+#define EXIT_WARNING 2
+#endif
+#endif
diff --git a/jpg/change.log b/jpg/change.log
new file mode 100644
index 0000000..729bca6
--- /dev/null
+++ b/jpg/change.log
@@ -0,0 +1,346 @@
+CHANGE LOG for Independent JPEG Group's JPEG software
+
+
+Version 8d 15-Jan-2012
+-----------------------
+
+Add cjpeg -rgb option to create RGB JPEG files.
+Using this switch suppresses the conversion from RGB
+colorspace input to the default YCbCr JPEG colorspace.
+This feature allows true lossless JPEG coding of RGB color images.
+The recommended command for this purpose is currently
+cjpeg -rgb -block 1 -arithmetic.
+SmartScale capable decoder (introduced with IJG JPEG 8) required.
+Thank to Michael Koch for the initial suggestion.
+
+Add option to disable the region adjustment in the transupp crop code.
+Thank to Jeffrey Friedl for the suggestion.
+
+Thank to Richard Jones and Edd Dawson for various minor corrections.
+
+Thank to Akim Demaille for configure.ac cleanup.
+
+
+Version 8c 16-Jan-2011
+-----------------------
+
+Add option to compression library and cjpeg (-block N) to use
+different DCT block size.
+All N from 1 to 16 are possible. Default is 8 (baseline format).
+Larger values produce higher compression,
+smaller values produce higher quality.
+SmartScale capable decoder (introduced with IJG JPEG 8) required.
+
+
+Version 8b 16-May-2010
+-----------------------
+
+Repair problem in new memory source manager with corrupt JPEG data.
+Thank to Ted Campbell and Samuel Chun for the report.
+
+Repair problem in Makefile.am test target.
+Thank to anonymous user for the report.
+
+Support MinGW installation with automatic configure.
+Thank to Volker Grabsch for the suggestion.
+
+
+Version 8a 28-Feb-2010
+-----------------------
+
+Writing tables-only datastreams via jpeg_write_tables works again.
+
+Support 32-bit BMPs (RGB image with Alpha channel) for read in cjpeg.
+Thank to Brett Blackham for the suggestion.
+
+Improve accuracy in floating point IDCT calculation.
+Thank to Robert Hooke for the hint.
+
+
+Version 8 10-Jan-2010
+----------------------
+
+jpegtran now supports the same -scale option as djpeg for "lossless" resize.
+An implementation of the JPEG SmartScale extension is required for this
+feature. A (draft) specification of the JPEG SmartScale extension is
+available as a contributed document at ITU and ISO. Revision 2 or later
+of the document is required (latest document version is Revision 3).
+The SmartScale extension will enable more features beside lossless resize
+in future implementations, as described in the document (new compression
+options).
+
+Add sanity check in BMP reader module to avoid cjpeg crash for empty input
+image (thank to Isaev Ildar of ISP RAS, Moscow, RU for reporting this error).
+
+Add data source and destination managers for read from and write to
+memory buffers. New API functions jpeg_mem_src and jpeg_mem_dest.
+Thank to Roberto Boni from Italy for the suggestion.
+
+
+Version 7 27-Jun-2009
+----------------------
+
+New scaled DCTs implemented.
+djpeg now supports scalings N/8 with all N from 1 to 16.
+cjpeg now supports scalings 8/N with all N from 1 to 16.
+Scaled DCTs with size larger than 8 are now also used for resolving the
+common 2x2 chroma subsampling case without additional spatial resampling.
+Separate spatial resampling for those kind of files is now only necessary
+for N>8 scaling cases.
+Furthermore, separate scaled DCT functions are provided for direct resolving
+of the common asymmetric subsampling cases (2x1 and 1x2) without additional
+spatial resampling.
+
+cjpeg -quality option has been extended for support of separate quality
+settings for luminance and chrominance (or in general, for every provided
+quantization table slot).
+New API function jpeg_default_qtables() and q_scale_factor array in library.
+
+Added -nosmooth option to cjpeg, complementary to djpeg.
+New variable "do_fancy_downsampling" in library, complement to fancy
+upsampling. Fancy upsampling now uses direct DCT scaling with sizes
+larger than 8. The old method is not reversible and has been removed.
+
+Support arithmetic entropy encoding and decoding.
+Added files jaricom.c, jcarith.c, jdarith.c.
+
+Straighten the file structure:
+Removed files jidctred.c, jcphuff.c, jchuff.h, jdphuff.c, jdhuff.h.
+
+jpegtran has a new "lossless" cropping feature.
+
+Implement -perfect option in jpegtran, new API function
+jtransform_perfect_transform() in transupp. (DP 204_perfect.dpatch)
+
+Better error messages for jpegtran fopen failure.
+(DP 203_jpegtran_errmsg.dpatch)
+
+Fix byte order issue with 16bit PPM/PGM files in rdppm.c/wrppm.c:
+according to Netpbm, the de facto standard implementation of the PNM formats,
+the most significant byte is first. (DP 203_rdppm.dpatch)
+
+Add -raw option to rdjpgcom not to mangle the output.
+(DP 205_rdjpgcom_raw.dpatch)
+
+Make rdjpgcom locale aware. (DP 201_rdjpgcom_locale.dpatch)
+
+Add extern "C" to jpeglib.h.
+This avoids the need to put extern "C" { ... } around #include "jpeglib.h"
+in your C++ application. Defining the symbol DONT_USE_EXTERN_C in the
+configuration prevents this. (DP 202_jpeglib.h_c++.dpatch)
+
+
+Version 6b 27-Mar-1998
+-----------------------
+
+jpegtran has new features for lossless image transformations (rotation
+and flipping) as well as "lossless" reduction to grayscale.
+
+jpegtran now copies comments by default; it has a -copy switch to enable
+copying all APPn blocks as well, or to suppress comments. (Formerly it
+always suppressed comments and APPn blocks.) jpegtran now also preserves
+JFIF version and resolution information.
+
+New decompressor library feature: COM and APPn markers found in the input
+file can be saved in memory for later use by the application. (Before,
+you had to code this up yourself with a custom marker processor.)
+
+There is an unused field "void * client_data" now in compress and decompress
+parameter structs; this may be useful in some applications.
+
+JFIF version number information is now saved by the decoder and accepted by
+the encoder. jpegtran uses this to copy the source file's version number,
+to ensure "jpegtran -copy all" won't create bogus files that contain JFXX
+extensions but claim to be version 1.01. Applications that generate their
+own JFXX extension markers also (finally) have a supported way to cause the
+encoder to emit JFIF version number 1.02.
+
+djpeg's trace mode reports JFIF 1.02 thumbnail images as such, rather
+than as unknown APP0 markers.
+
+In -verbose mode, djpeg and rdjpgcom will try to print the contents of
+APP12 markers as text. Some digital cameras store useful text information
+in APP12 markers.
+
+Handling of truncated data streams is more robust: blocks beyond the one in
+which the error occurs will be output as uniform gray, or left unchanged
+if decoding a progressive JPEG. The appearance no longer depends on the
+Huffman tables being used.
+
+Huffman tables are checked for validity much more carefully than before.
+
+To avoid the Unisys LZW patent, djpeg's GIF output capability has been
+changed to produce "uncompressed GIFs", and cjpeg's GIF input capability
+has been removed altogether. We're not happy about it either, but there
+seems to be no good alternative.
+
+The configure script now supports building libjpeg as a shared library
+on many flavors of Unix (all the ones that GNU libtool knows how to
+build shared libraries for). Use "./configure --enable-shared" to
+try this out.
+
+New jconfig file and makefiles for Microsoft Visual C++ and Developer Studio.
+Also, a jconfig file and a build script for Metrowerks CodeWarrior
+on Apple Macintosh. makefile.dj has been updated for DJGPP v2, and there
+are miscellaneous other minor improvements in the makefiles.
+
+jmemmac.c now knows how to create temporary files following Mac System 7
+conventions.
+
+djpeg's -map switch is now able to read raw-format PPM files reliably.
+
+cjpeg -progressive -restart no longer generates any unnecessary DRI markers.
+
+Multiple calls to jpeg_simple_progression for a single JPEG object
+no longer leak memory.
+
+
+Version 6a 7-Feb-96
+--------------------
+
+Library initialization sequence modified to detect version mismatches
+and struct field packing mismatches between library and calling application.
+This change requires applications to be recompiled, but does not require
+any application source code change.
+
+All routine declarations changed to the style "GLOBAL(type) name ...",
+that is, GLOBAL, LOCAL, METHODDEF, EXTERN are now macros taking the
+routine's return type as an argument. This makes it possible to add
+Microsoft-style linkage keywords to all the routines by changing just
+these macros. Note that any application code that was using these macros
+will have to be changed.
+
+DCT coefficient quantization tables are now stored in normal array order
+rather than zigzag order. Application code that calls jpeg_add_quant_table,
+or otherwise manipulates quantization tables directly, will need to be
+changed. If you need to make such code work with either older or newer
+versions of the library, a test like "#if JPEG_LIB_VERSION >= 61" is
+recommended.
+
+djpeg's trace capability now dumps DQT tables in natural order, not zigzag
+order. This allows the trace output to be made into a "-qtables" file
+more easily.
+
+New system-dependent memory manager module for use on Apple Macintosh.
+
+Fix bug in cjpeg's -smooth option: last one or two scanlines would be
+duplicates of the prior line unless the image height mod 16 was 1 or 2.
+
+Repair minor problems in VMS, BCC, MC6 makefiles.
+
+New configure script based on latest GNU Autoconf.
+
+Correct the list of include files needed by MetroWerks C for ccommand().
+
+Numerous small documentation updates.
+
+
+Version 6 2-Aug-95
+-------------------
+
+Progressive JPEG support: library can read and write full progressive JPEG
+files. A "buffered image" mode supports incremental decoding for on-the-fly
+display of progressive images. Simply recompiling an existing IJG-v5-based
+decoder with v6 should allow it to read progressive files, though of course
+without any special progressive display.
+
+New "jpegtran" application performs lossless transcoding between different
+JPEG formats; primarily, it can be used to convert baseline to progressive
+JPEG and vice versa. In support of jpegtran, the library now allows lossless
+reading and writing of JPEG files as DCT coefficient arrays. This ability
+may be of use in other applications.
+
+Notes for programmers:
+* We changed jpeg_start_decompress() to be able to suspend; this makes all
+decoding modes available to suspending-input applications. However,
+existing applications that use suspending input will need to be changed
+to check the return value from jpeg_start_decompress(). You don't need to
+do anything if you don't use a suspending data source.
+* We changed the interface to the virtual array routines: access_virt_array
+routines now take a count of the number of rows to access this time. The
+last parameter to request_virt_array routines is now interpreted as the
+maximum number of rows that may be accessed at once, but not necessarily
+the height of every access.
+
+
+Version 5b 15-Mar-95
+---------------------
+
+Correct bugs with grayscale images having v_samp_factor > 1.
+
+jpeg_write_raw_data() now supports output suspension.
+
+Correct bugs in "configure" script for case of compiling in
+a directory other than the one containing the source files.
+
+Repair bug in jquant1.c: sometimes didn't use as many colors as it could.
+
+Borland C makefile and jconfig file work under either MS-DOS or OS/2.
+
+Miscellaneous improvements to documentation.
+
+
+Version 5a 7-Dec-94
+--------------------
+
+Changed color conversion roundoff behavior so that grayscale values are
+represented exactly. (This causes test image files to change.)
+
+Make ordered dither use 16x16 instead of 4x4 pattern for a small quality
+improvement.
+
+New configure script based on latest GNU Autoconf.
+Fix configure script to handle CFLAGS correctly.
+Rename *.auto files to *.cfg, so that configure script still works if
+file names have been truncated for DOS.
+
+Fix bug in rdbmp.c: didn't allow for extra data between header and image.
+
+Modify rdppm.c/wrppm.c to handle 2-byte raw PPM/PGM formats for 12-bit data.
+
+Fix several bugs in rdrle.c.
+
+NEED_SHORT_EXTERNAL_NAMES option was broken.
+
+Revise jerror.h/jerror.c for more flexibility in message table.
+
+Repair oversight in jmemname.c NO_MKTEMP case: file could be there
+but unreadable.
+
+
+Version 5 24-Sep-94
+--------------------
+
+Version 5 represents a nearly complete redesign and rewrite of the IJG
+software. Major user-visible changes include:
+ * Automatic configuration simplifies installation for most Unix systems.
+ * A range of speed vs. image quality tradeoffs are supported.
+ This includes resizing of an image during decompression: scaling down
+ by a factor of 1/2, 1/4, or 1/8 is handled very efficiently.
+ * New programs rdjpgcom and wrjpgcom allow insertion and extraction
+ of text comments in a JPEG file.
+
+The application programmer's interface to the library has changed completely.
+Notable improvements include:
+ * We have eliminated the use of callback routines for handling the
+ uncompressed image data. The application now sees the library as a
+ set of routines that it calls to read or write image data on a
+ scanline-by-scanline basis.
+ * The application image data is represented in a conventional interleaved-
+ pixel format, rather than as a separate array for each color channel.
+ This can save a copying step in many programs.
+ * The handling of compressed data has been cleaned up: the application can
+ supply routines to source or sink the compressed data. It is possible to
+ suspend processing on source/sink buffer overrun, although this is not
+ supported in all operating modes.
+ * All static state has been eliminated from the library, so that multiple
+ instances of compression or decompression can be active concurrently.
+ * JPEG abbreviated datastream formats are supported, ie, quantization and
+ Huffman tables can be stored separately from the image data.
+ * And not only that, but the documentation of the library has improved
+ considerably!
+
+
+The last widely used release before the version 5 rewrite was version 4A of
+18-Feb-93. Change logs before that point have been discarded, since they
+are not of much interest after the rewrite.
diff --git a/jpg/cjpeg.1 b/jpg/cjpeg.1
new file mode 100644
index 0000000..c10f971
--- /dev/null
+++ b/jpg/cjpeg.1
@@ -0,0 +1,348 @@
+.TH CJPEG 1 "28 August 2011"
+.SH NAME
+cjpeg \- compress an image file to a JPEG file
+.SH SYNOPSIS
+.B cjpeg
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B cjpeg
+compresses the named image file, or the standard input if no file is
+named, and produces a JPEG/JFIF file on the standard output.
+The currently supported input file formats are: PPM (PBMPLUS color
+format), PGM (PBMPLUS gray-scale format), BMP, Targa, and RLE (Utah Raster
+Toolkit format). (RLE is supported only if the URT library is available.)
+.SH OPTIONS
+All switch names may be abbreviated; for example,
+.B \-grayscale
+may be written
+.B \-gray
+or
+.BR \-gr .
+Most of the "basic" switches can be abbreviated to as little as one letter.
+Upper and lower case are equivalent (thus
+.B \-BMP
+is the same as
+.BR \-bmp ).
+British spellings are also accepted (e.g.,
+.BR \-greyscale ),
+though for brevity these are not mentioned below.
+.PP
+The basic switches are:
+.TP
+.BI \-quality " N[,...]"
+Scale quantization tables to adjust image quality. Quality is 0 (worst) to
+100 (best); default is 75. (See below for more info.)
+.TP
+.B \-grayscale
+Create monochrome JPEG file from color input. Be sure to use this switch when
+compressing a grayscale BMP file, because
+.B cjpeg
+isn't bright enough to notice whether a BMP file uses only shades of gray.
+By saying
+.BR \-grayscale ,
+you'll get a smaller JPEG file that takes less time to process.
+.TP
+.B \-rgb
+Create RGB JPEG file.
+Using this switch suppresses the conversion from RGB
+colorspace input to the default YCbCr JPEG colorspace.
+Use this switch in combination with the
+.BI \-block " N"
+switch (see below) for lossless JPEG coding.
+.TP
+.B \-optimize
+Perform optimization of entropy encoding parameters. Without this, default
+encoding parameters are used.
+.B \-optimize
+usually makes the JPEG file a little smaller, but
+.B cjpeg
+runs somewhat slower and needs much more memory. Image quality and speed of
+decompression are unaffected by
+.BR \-optimize .
+.TP
+.B \-progressive
+Create progressive JPEG file (see below).
+.TP
+.BI \-scale " M/N"
+Scale the output image by a factor M/N. Currently supported scale factors are
+M/N with all N from 1 to 16, where M is the destination DCT size, which is 8
+by default (see
+.BI \-block " N"
+switch below).
+.TP
+.B \-targa
+Input file is Targa format. Targa files that contain an "identification"
+field will not be automatically recognized by
+.BR cjpeg ;
+for such files you must specify
+.B \-targa
+to make
+.B cjpeg
+treat the input as Targa format.
+For most Targa files, you won't need this switch.
+.PP
+The
+.B \-quality
+switch lets you trade off compressed file size against quality of the
+reconstructed image: the higher the quality setting, the larger the JPEG file,
+and the closer the output image will be to the original input. Normally you
+want to use the lowest quality setting (smallest file) that decompresses into
+something visually indistinguishable from the original image. For this
+purpose the quality setting should be between 50 and 95; the default of 75 is
+often about right. If you see defects at
+.B \-quality
+75, then go up 5 or 10 counts at a time until you are happy with the output
+image. (The optimal setting will vary from one image to another.)
+.PP
+.B \-quality
+100 will generate a quantization table of all 1's, minimizing loss in the
+quantization step (but there is still information loss in subsampling, as well
+as roundoff error). This setting is mainly of interest for experimental
+purposes. Quality values above about 95 are
+.B not
+recommended for normal use; the compressed file size goes up dramatically for
+hardly any gain in output image quality.
+.PP
+In the other direction, quality values below 50 will produce very small files
+of low image quality. Settings around 5 to 10 might be useful in preparing an
+index of a large image library, for example. Try
+.B \-quality
+2 (or so) for some amusing Cubist effects. (Note: quality
+values below about 25 generate 2-byte quantization tables, which are
+considered optional in the JPEG standard.
+.B cjpeg
+emits a warning message when you give such a quality value, because some
+other JPEG programs may be unable to decode the resulting file. Use
+.B \-baseline
+if you need to ensure compatibility at low quality values.)
+.PP
+The
+.B \-quality
+option has been extended in IJG version 7 for support of separate quality
+settings for luminance and chrominance (or in general, for every provided
+quantization table slot). This feature is useful for high-quality
+applications which cannot accept the damage of color data by coarse
+subsampling settings. You can now easily reduce the color data amount more
+smoothly with finer control without separate subsampling. The resulting file
+is fully compliant with standard JPEG decoders.
+Note that the
+.B \-quality
+ratings refer to the quantization table slots, and that the last value is
+replicated if there are more q-table slots than parameters. The default
+q-table slots are 0 for luminance and 1 for chrominance with default tables as
+given in the JPEG standard. This is compatible with the old behaviour in case
+that only one parameter is given, which is then used for both luminance and
+chrominance (slots 0 and 1). More or custom quantization tables can be set
+with
+.B \-qtables
+and assigned to components with
+.B \-qslots
+parameter (see the "wizard" switches below).
+.B Caution:
+You must explicitly add
+.BI \-sample " 1x1"
+for efficient separate color
+quality selection, since the default value used by library is 2x2!
+.PP
+The
+.B \-progressive
+switch creates a "progressive JPEG" file. In this type of JPEG file, the data
+is stored in multiple scans of increasing quality. If the file is being
+transmitted over a slow communications link, the decoder can use the first
+scan to display a low-quality image very quickly, and can then improve the
+display with each subsequent scan. The final image is exactly equivalent to a
+standard JPEG file of the same quality setting, and the total file size is
+about the same --- often a little smaller.
+.PP
+Switches for advanced users:
+.TP
+.B \-arithmetic
+Use arithmetic coding.
+.B Caution:
+arithmetic coded JPEG is not yet widely implemented, so many decoders will be
+unable to view an arithmetic coded JPEG file at all.
+.TP
+.BI \-block " N"
+Set DCT block size. All N from 1 to 16 are possible.
+Default is 8 (baseline format).
+Larger values produce higher compression,
+smaller values produce higher quality
+(exact DCT stage possible with 1 or 2; with the default quality of 75 and
+default Luminance qtable the DCT+Quantization stage is lossless for N=1).
+.B Caution:
+An implementation of the JPEG SmartScale extension is required for this
+feature. SmartScale enabled JPEG is not yet widely implemented, so many
+decoders will be unable to view a SmartScale extended JPEG file at all.
+.TP
+.B \-dct int
+Use integer DCT method (default).
+.TP
+.B \-dct fast
+Use fast integer DCT (less accurate).
+.TP
+.B \-dct float
+Use floating-point DCT method.
+The float method is very slightly more accurate than the int method, but is
+much slower unless your machine has very fast floating-point hardware. Also
+note that results of the floating-point method may vary slightly across
+machines, while the integer methods should give the same results everywhere.
+The fast integer method is much less accurate than the other two.
+.TP
+.B \-nosmooth
+Don't use high-quality downsampling.
+.TP
+.BI \-restart " N"
+Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
+attached to the number.
+.B \-restart 0
+(the default) means no restart markers.
+.TP
+.BI \-smooth " N"
+Smooth the input image to eliminate dithering noise. N, ranging from 1 to
+100, indicates the strength of smoothing. 0 (the default) means no smoothing.
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images. Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number. For example,
+.B \-max 4m
+selects 4000000 bytes. If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout. More
+.BR \-v 's
+give more output. Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.PP
+The
+.B \-restart
+option inserts extra markers that allow a JPEG decoder to resynchronize after
+a transmission error. Without restart markers, any damage to a compressed
+file will usually ruin the image from the point of the error to the end of the
+image; with restart markers, the damage is usually confined to the portion of
+the image up to the next restart marker. Of course, the restart markers
+occupy extra space. We recommend
+.B \-restart 1
+for images that will be transmitted across unreliable networks such as Usenet.
+.PP
+The
+.B \-smooth
+option filters the input to eliminate fine-scale noise. This is often useful
+when converting dithered images to JPEG: a moderate smoothing factor of 10 to
+50 gets rid of dithering patterns in the input file, resulting in a smaller
+JPEG file and a better-looking image. Too large a smoothing factor will
+visibly blur the image, however.
+.PP
+Switches for wizards:
+.TP
+.B \-baseline
+Force baseline-compatible quantization tables to be generated. This clamps
+quantization values to 8 bits even at low quality settings. (This switch is
+poorly named, since it does not ensure that the output is actually baseline
+JPEG. For example, you can use
+.B \-baseline
+and
+.B \-progressive
+together.)
+.TP
+.BI \-qtables " file"
+Use the quantization tables given in the specified text file.
+.TP
+.BI \-qslots " N[,...]"
+Select which quantization table to use for each color component.
+.TP
+.BI \-sample " HxV[,...]"
+Set JPEG sampling factors for each color component.
+.TP
+.BI \-scans " file"
+Use the scan script given in the specified text file.
+.PP
+The "wizard" switches are intended for experimentation with JPEG. If you
+don't know what you are doing, \fBdon't use them\fR. These switches are
+documented further in the file wizard.txt.
+.SH EXAMPLES
+.LP
+This example compresses the PPM file foo.ppm with a quality factor of
+60 and saves the output as foo.jpg:
+.IP
+.B cjpeg \-quality
+.I 60 foo.ppm
+.B >
+.I foo.jpg
+.SH HINTS
+Color GIF files are not the ideal input for JPEG; JPEG is really intended for
+compressing full-color (24-bit) images. In particular, don't try to convert
+cartoons, line drawings, and other images that have only a few distinct
+colors. GIF works great on these, JPEG does not. If you want to convert a
+GIF to JPEG, you should experiment with
+.BR cjpeg 's
+.B \-quality
+and
+.B \-smooth
+options to get a satisfactory conversion.
+.B \-smooth 10
+or so is often helpful.
+.PP
+Avoid running an image through a series of JPEG compression/decompression
+cycles. Image quality loss will accumulate; after ten or so cycles the image
+may be noticeably worse than it was after one cycle. It's best to use a
+lossless format while manipulating an image, then convert to JPEG format when
+you are ready to file the image away.
+.PP
+The
+.B \-optimize
+option to
+.B cjpeg
+is worth using when you are making a "final" version for posting or archiving.
+It's also a win when you are using low quality settings to make very small
+JPEG files; the percentage improvement is often a lot more than it is on
+larger files. (At present,
+.B \-optimize
+mode is always selected when generating progressive JPEG files.)
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR djpeg (1),
+.BR jpegtran (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+.BR ppm (5),
+.BR pgm (5)
+.br
+Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+GIF input files are no longer supported, to avoid the Unisys LZW patent.
+(Conversion of GIF files to JPEG is usually a bad idea anyway.)
+.PP
+Not all variants of BMP and Targa file formats are supported.
+.PP
+The
+.B \-targa
+switch is not a bug, it's a feature. (It would be a bug if the Targa format
+designers had not been clueless.)
diff --git a/jpg/cjpeg.c b/jpg/cjpeg.c
new file mode 100644
index 0000000..9a9a09a
--- /dev/null
+++ b/jpg/cjpeg.c
@@ -0,0 +1,643 @@
+/*
+ * cjpeg.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for the JPEG compressor.
+ * It should work on any system with Unix- or MS-DOS-style command lines.
+ *
+ * Two different command line styles are permitted, depending on the
+ * compile-time switch TWO_FILE_COMMANDLINE:
+ * cjpeg [options] inputfile outputfile
+ * cjpeg [options] [inputfile]
+ * In the second style, output is always to standard output, which you'd
+ * normally redirect to a file or pipe to some other program. Input is
+ * either from a named file or from standard input (typically redirected).
+ * The second style is convenient on Unix but is unhelpful on systems that
+ * don't support pipes. Also, you MUST use the first style if your system
+ * doesn't do binary I/O to stdin/stdout.
+ * To simplify script writing, the "-outfile" switch is provided. The syntax
+ * cjpeg [options] -outfile outputfile inputfile
+ * works regardless of which command line style is used.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "jversion.h" /* for version message */
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+
+/* Create the add-on message string table. */
+
+#define JMESSAGE(code,string) string ,
+
+static const char * const cdjpeg_message_table[] = {
+#include "cderror.h"
+ NULL
+};
+
+
+/*
+ * This routine determines what format the input file is,
+ * and selects the appropriate input-reading module.
+ *
+ * To determine which family of input formats the file belongs to,
+ * we may look only at the first byte of the file, since C does not
+ * guarantee that more than one character can be pushed back with ungetc.
+ * Looking at additional bytes would require one of these approaches:
+ * 1) assume we can fseek() the input file (fails for piped input);
+ * 2) assume we can push back more than one character (works in
+ * some C implementations, but unportable);
+ * 3) provide our own buffering (breaks input readers that want to use
+ * stdio directly, such as the RLE library);
+ * or 4) don't put back the data, and modify the input_init methods to assume
+ * they start reading after the start of file (also breaks RLE library).
+ * #1 is attractive for MS-DOS but is untenable on Unix.
+ *
+ * The most portable solution for file types that can't be identified by their
+ * first byte is to make the user tell us what they are. This is also the
+ * only approach for "raw" file types that contain only arbitrary values.
+ * We presently apply this method for Targa files. Most of the time Targa
+ * files start with 0x00, so we recognize that case. Potentially, however,
+ * a Targa file could start with any byte value (byte 0 is the length of the
+ * seldom-used ID field), so we provide a switch to force Targa input mode.
+ */
+
+static boolean is_targa; /* records user -targa switch */
+
+
+LOCAL(cjpeg_source_ptr)
+select_file_type (j_compress_ptr cinfo, FILE * infile)
+{
+ int c;
+
+ if (is_targa) {
+#ifdef TARGA_SUPPORTED
+ return jinit_read_targa(cinfo);
+#else
+ ERREXIT(cinfo, JERR_TGA_NOTCOMP);
+#endif
+ }
+
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ if (ungetc(c, infile) == EOF)
+ ERREXIT(cinfo, JERR_UNGETC_FAILED);
+
+ switch (c) {
+#ifdef BMP_SUPPORTED
+ case 'B':
+ return jinit_read_bmp(cinfo);
+#endif
+#ifdef GIF_SUPPORTED
+ case 'G':
+ return jinit_read_gif(cinfo);
+#endif
+#ifdef PPM_SUPPORTED
+ case 'P':
+ return jinit_read_ppm(cinfo);
+#endif
+#ifdef RLE_SUPPORTED
+ case 'R':
+ return jinit_read_rle(cinfo);
+#endif
+#ifdef TARGA_SUPPORTED
+ case 0x00:
+ return jinit_read_targa(cinfo);
+#endif
+ default:
+ ERREXIT(cinfo, JERR_UNKNOWN_FORMAT);
+ break;
+ }
+
+ return NULL; /* suppress compiler warnings */
+}
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname; /* program name for error messages */
+static char * outfilename; /* for -outfile switch */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "inputfile outputfile\n");
+#else
+ fprintf(stderr, "[inputfile]\n");
+#endif
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -quality N[,...] Compression quality (0..100; 5-95 is useful range)\n");
+ fprintf(stderr, " -grayscale Create monochrome JPEG file\n");
+ fprintf(stderr, " -rgb Create RGB JPEG file\n");
+#ifdef ENTROPY_OPT_SUPPORTED
+ fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
+#endif
+#ifdef C_PROGRESSIVE_SUPPORTED
+ fprintf(stderr, " -progressive Create progressive JPEG file\n");
+#endif
+#ifdef DCT_SCALING_SUPPORTED
+ fprintf(stderr, " -scale M/N Scale image by fraction M/N, eg, 1/2\n");
+#endif
+#ifdef TARGA_SUPPORTED
+ fprintf(stderr, " -targa Input file is Targa format (usually not needed)\n");
+#endif
+ fprintf(stderr, "Switches for advanced users:\n");
+#ifdef C_ARITH_CODING_SUPPORTED
+ fprintf(stderr, " -arithmetic Use arithmetic coding\n");
+#endif
+#ifdef DCT_SCALING_SUPPORTED
+ fprintf(stderr, " -block N DCT block size (1..16; default is 8)\n");
+#endif
+#ifdef DCT_ISLOW_SUPPORTED
+ fprintf(stderr, " -dct int Use integer DCT method%s\n",
+ (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
+ (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
+ (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
+#endif
+ fprintf(stderr, " -nosmooth Don't use high-quality downsampling\n");
+ fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ fprintf(stderr, " -smooth N Smooth dithered input (N=1..100 is strength)\n");
+#endif
+ fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
+ fprintf(stderr, " -outfile name Specify name for output file\n");
+ fprintf(stderr, " -verbose or -debug Emit debug output\n");
+ fprintf(stderr, "Switches for wizards:\n");
+ fprintf(stderr, " -baseline Force baseline quantization tables\n");
+ fprintf(stderr, " -qtables file Use quantization tables given in file\n");
+ fprintf(stderr, " -qslots N[,...] Set component quantization tables\n");
+ fprintf(stderr, " -sample HxV[,...] Set component sampling factors\n");
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n");
+#endif
+ exit(EXIT_FAILURE);
+}
+
+
+LOCAL(int)
+parse_switches (j_compress_ptr cinfo, int argc, char **argv,
+ int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+ int argn;
+ char * arg;
+ boolean force_baseline;
+ boolean simple_progressive;
+ char * qualityarg = NULL; /* saves -quality parm if any */
+ char * qtablefile = NULL; /* saves -qtables filename if any */
+ char * qslotsarg = NULL; /* saves -qslots parm if any */
+ char * samplearg = NULL; /* saves -sample parm if any */
+ char * scansarg = NULL; /* saves -scans parm if any */
+
+ /* Set up default JPEG parameters. */
+
+ force_baseline = FALSE; /* by default, allow 16-bit quantizers */
+ simple_progressive = FALSE;
+ is_targa = FALSE;
+ outfilename = NULL;
+ cinfo->err->trace_level = 0;
+
+ /* Scan command line options, adjust parameters */
+
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (*arg != '-') {
+ /* Not a switch, must be a file name argument */
+ if (argn <= last_file_arg_seen) {
+ outfilename = NULL; /* -outfile applies to just one input file */
+ continue; /* ignore this name if previously processed */
+ }
+ break; /* else done parsing switches */
+ }
+ arg++; /* advance past switch marker character */
+
+ if (keymatch(arg, "arithmetic", 1)) {
+ /* Use arithmetic coding. */
+#ifdef C_ARITH_CODING_SUPPORTED
+ cinfo->arith_code = TRUE;
+#else
+ fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "baseline", 2)) {
+ /* Force baseline-compatible output (8-bit quantizer values). */
+ force_baseline = TRUE;
+
+ } else if (keymatch(arg, "block", 2)) {
+ /* Set DCT block size. */
+#if defined DCT_SCALING_SUPPORTED && JPEG_LIB_VERSION_MAJOR >= 8 && \
+ (JPEG_LIB_VERSION_MAJOR > 8 || JPEG_LIB_VERSION_MINOR >= 3)
+ int val;
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d", &val) != 1)
+ usage();
+ if (val < 1 || val > 16)
+ usage();
+ cinfo->block_size = val;
+#else
+ fprintf(stderr, "%s: sorry, block size setting not supported\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "dct", 2)) {
+ /* Select DCT algorithm. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "int", 1)) {
+ cinfo->dct_method = JDCT_ISLOW;
+ } else if (keymatch(argv[argn], "fast", 2)) {
+ cinfo->dct_method = JDCT_IFAST;
+ } else if (keymatch(argv[argn], "float", 2)) {
+ cinfo->dct_method = JDCT_FLOAT;
+ } else
+ usage();
+
+ } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+ /* Enable debug printouts. */
+ /* On first -d, print version identification */
+ static boolean printed_version = FALSE;
+
+ if (! printed_version) {
+ fprintf(stderr, "Independent JPEG Group's CJPEG, version %s\n%s\n",
+ JVERSION, JCOPYRIGHT);
+ printed_version = TRUE;
+ }
+ cinfo->err->trace_level++;
+
+ } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
+ /* Force a monochrome JPEG file to be generated. */
+ jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+
+ } else if (keymatch(arg, "rgb", 3)) {
+ /* Force an RGB JPEG file to be generated. */
+ jpeg_set_colorspace(cinfo, JCS_RGB);
+
+ } else if (keymatch(arg, "maxmemory", 3)) {
+ /* Maximum memory in Kb (or Mb with 'm'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (ch == 'm' || ch == 'M')
+ lval *= 1000L;
+ cinfo->mem->max_memory_to_use = lval * 1000L;
+
+ } else if (keymatch(arg, "nosmooth", 3)) {
+ /* Suppress fancy downsampling */
+ cinfo->do_fancy_downsampling = FALSE;
+
+ } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
+ /* Enable entropy parm optimization. */
+#ifdef ENTROPY_OPT_SUPPORTED
+ cinfo->optimize_coding = TRUE;
+#else
+ fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "outfile", 4)) {
+ /* Set output file name. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ outfilename = argv[argn]; /* save it away for later use */
+
+ } else if (keymatch(arg, "progressive", 1)) {
+ /* Select simple progressive mode. */
+#ifdef C_PROGRESSIVE_SUPPORTED
+ simple_progressive = TRUE;
+ /* We must postpone execution until num_components is known. */
+#else
+ fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "quality", 1)) {
+ /* Quality ratings (quantization table scaling factors). */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ qualityarg = argv[argn];
+
+ } else if (keymatch(arg, "qslots", 2)) {
+ /* Quantization table slot numbers. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ qslotsarg = argv[argn];
+ /* Must delay setting qslots until after we have processed any
+ * colorspace-determining switches, since jpeg_set_colorspace sets
+ * default quant table numbers.
+ */
+
+ } else if (keymatch(arg, "qtables", 2)) {
+ /* Quantization tables fetched from file. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ qtablefile = argv[argn];
+ /* We postpone actually reading the file in case -quality comes later. */
+
+ } else if (keymatch(arg, "restart", 1)) {
+ /* Restart interval in MCU rows (or in MCUs with 'b'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (lval < 0 || lval > 65535L)
+ usage();
+ if (ch == 'b' || ch == 'B') {
+ cinfo->restart_interval = (unsigned int) lval;
+ cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
+ } else {
+ cinfo->restart_in_rows = (int) lval;
+ /* restart_interval will be computed during startup */
+ }
+
+ } else if (keymatch(arg, "sample", 2)) {
+ /* Set sampling factors. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ samplearg = argv[argn];
+ /* Must delay setting sample factors until after we have processed any
+ * colorspace-determining switches, since jpeg_set_colorspace sets
+ * default sampling factors.
+ */
+
+ } else if (keymatch(arg, "scale", 4)) {
+ /* Scale the image by a fraction M/N. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d/%d",
+ &cinfo->scale_num, &cinfo->scale_denom) != 2)
+ usage();
+
+ } else if (keymatch(arg, "scans", 4)) {
+ /* Set scan script. */
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ scansarg = argv[argn];
+ /* We must postpone reading the file in case -progressive appears. */
+#else
+ fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "smooth", 2)) {
+ /* Set input smoothing factor. */
+ int val;
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d", &val) != 1)
+ usage();
+ if (val < 0 || val > 100)
+ usage();
+ cinfo->smoothing_factor = val;
+
+ } else if (keymatch(arg, "targa", 1)) {
+ /* Input file is Targa format. */
+ is_targa = TRUE;
+
+ } else {
+ usage(); /* bogus switch */
+ }
+ }
+
+ /* Post-switch-scanning cleanup */
+
+ if (for_real) {
+
+ /* Set quantization tables for selected quality. */
+ /* Some or all may be overridden if -qtables is present. */
+ if (qualityarg != NULL) /* process -quality if it was present */
+ if (! set_quality_ratings(cinfo, qualityarg, force_baseline))
+ usage();
+
+ if (qtablefile != NULL) /* process -qtables if it was present */
+ if (! read_quant_tables(cinfo, qtablefile, force_baseline))
+ usage();
+
+ if (qslotsarg != NULL) /* process -qslots if it was present */
+ if (! set_quant_slots(cinfo, qslotsarg))
+ usage();
+
+ if (samplearg != NULL) /* process -sample if it was present */
+ if (! set_sample_factors(cinfo, samplearg))
+ usage();
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+ if (simple_progressive) /* process -progressive; -scans can override */
+ jpeg_simple_progression(cinfo);
+#endif
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (scansarg != NULL) /* process -scans if it was present */
+ if (! read_scan_script(cinfo, scansarg))
+ usage();
+#endif
+ }
+
+ return argn; /* return index of next arg (file name) */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+#ifdef PROGRESS_REPORT
+ struct cdjpeg_progress_mgr progress;
+#endif
+ int file_index;
+ cjpeg_source_ptr src_mgr;
+ FILE * input_file;
+ FILE * output_file;
+ JDIMENSION num_scanlines;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "cjpeg"; /* in case C library doesn't provide it */
+
+ /* Initialize the JPEG compression object with default error handling. */
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ /* Add some application-specific error messages (from cderror.h) */
+ jerr.addon_message_table = cdjpeg_message_table;
+ jerr.first_addon_message = JMSG_FIRSTADDONCODE;
+ jerr.last_addon_message = JMSG_LASTADDONCODE;
+
+ /* Now safe to enable signal catcher. */
+#ifdef NEED_SIGNAL_CATCHER
+ enable_signal_catcher((j_common_ptr) &cinfo);
+#endif
+
+ /* Initialize JPEG parameters.
+ * Much of this may be overridden later.
+ * In particular, we don't yet know the input file's color space,
+ * but we need to provide some value for jpeg_set_defaults() to work.
+ */
+
+ cinfo.in_color_space = JCS_RGB; /* arbitrary guess */
+ jpeg_set_defaults(&cinfo);
+
+ /* Scan command line to find file names.
+ * It is convenient to use just one switch-parsing routine, but the switch
+ * values read here are ignored; we will rescan the switches after opening
+ * the input file.
+ */
+
+ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
+
+#ifdef TWO_FILE_COMMANDLINE
+ /* Must have either -outfile switch or explicit output file name */
+ if (outfilename == NULL) {
+ if (file_index != argc-2) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ outfilename = argv[file_index+1];
+ } else {
+ if (file_index != argc-1) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ }
+#else
+ /* Unix style: expect zero or one file name */
+ if (file_index < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+#endif /* TWO_FILE_COMMANDLINE */
+
+ /* Open the input file. */
+ if (file_index < argc) {
+ if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+ input_file = read_stdin();
+ }
+
+ /* Open the output file. */
+ if (outfilename != NULL) {
+ if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default output file is stdout */
+ output_file = write_stdout();
+ }
+
+#ifdef PROGRESS_REPORT
+ start_progress_monitor((j_common_ptr) &cinfo, &progress);
+#endif
+
+ /* Figure out the input file format, and set up to read it. */
+ src_mgr = select_file_type(&cinfo, input_file);
+ src_mgr->input_file = input_file;
+
+ /* Read the input file header to obtain file size & colorspace. */
+ (*src_mgr->start_input) (&cinfo, src_mgr);
+
+ /* Now that we know input colorspace, fix colorspace-dependent defaults */
+ jpeg_default_colorspace(&cinfo);
+
+ /* Adjust default compression parameters by re-parsing the options */
+ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
+
+ /* Specify data destination for compression */
+ jpeg_stdio_dest(&cinfo, output_file);
+
+ /* Start compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Process data */
+ while (cinfo.next_scanline < cinfo.image_height) {
+ num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr);
+ (void) jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines);
+ }
+
+ /* Finish compression and release memory */
+ (*src_mgr->finish_input) (&cinfo, src_mgr);
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+
+ /* Close files, if we opened them */
+ if (input_file != stdin)
+ fclose(input_file);
+ if (output_file != stdout)
+ fclose(output_file);
+
+#ifdef PROGRESS_REPORT
+ end_progress_monitor((j_common_ptr) &cinfo);
+#endif
+
+ /* All done. */
+ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/jpg/ckconfig.c b/jpg/ckconfig.c
new file mode 100644
index 0000000..e658623
--- /dev/null
+++ b/jpg/ckconfig.c
@@ -0,0 +1,402 @@
+/*
+ * ckconfig.c
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ */
+
+/*
+ * This program is intended to help you determine how to configure the JPEG
+ * software for installation on a particular system. The idea is to try to
+ * compile and execute this program. If your compiler fails to compile the
+ * program, make changes as indicated in the comments below. Once you can
+ * compile the program, run it, and it will produce a "jconfig.h" file for
+ * your system.
+ *
+ * As a general rule, each time you try to compile this program,
+ * pay attention only to the *first* error message you get from the compiler.
+ * Many C compilers will issue lots of spurious error messages once they
+ * have gotten confused. Go to the line indicated in the first error message,
+ * and read the comments preceding that line to see what to change.
+ *
+ * Almost all of the edits you may need to make to this program consist of
+ * changing a line that reads "#define SOME_SYMBOL" to "#undef SOME_SYMBOL",
+ * or vice versa. This is called defining or undefining that symbol.
+ */
+
+
+/* First we must see if your system has the include files we need.
+ * We start out with the assumption that your system has all the ANSI-standard
+ * include files. If you get any error trying to include one of these files,
+ * undefine the corresponding HAVE_xxx symbol.
+ */
+
+#define HAVE_STDDEF_H /* replace 'define' by 'undef' if error here */
+#ifdef HAVE_STDDEF_H /* next line will be skipped if you undef... */
+#include <stddef.h>
+#endif
+
+#define HAVE_STDLIB_H /* same thing for stdlib.h */
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <stdio.h> /* If you ain't got this, you ain't got C. */
+
+/* We have to see if your string functions are defined by
+ * strings.h (old BSD convention) or string.h (everybody else).
+ * We try the non-BSD convention first; define NEED_BSD_STRINGS
+ * if the compiler says it can't find string.h.
+ */
+
+#undef NEED_BSD_STRINGS
+
+#ifdef NEED_BSD_STRINGS
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+
+/* On some systems (especially older Unix machines), type size_t is
+ * defined only in the include file <sys/types.h>. If you get a failure
+ * on the size_t test below, try defining NEED_SYS_TYPES_H.
+ */
+
+#undef NEED_SYS_TYPES_H /* start by assuming we don't need it */
+#ifdef NEED_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+
+/* Usually type size_t is defined in one of the include files we've included
+ * above. If not, you'll get an error on the "typedef size_t my_size_t;" line.
+ * In that case, first try defining NEED_SYS_TYPES_H just above.
+ * If that doesn't work, you'll have to search through your system library
+ * to figure out which include file defines "size_t". Look for a line that
+ * says "typedef something-or-other size_t;". Then, change the line below
+ * that says "#include <someincludefile.h>" to instead include the file
+ * you found size_t in, and define NEED_SPECIAL_INCLUDE. If you can't find
+ * type size_t anywhere, try replacing "#include <someincludefile.h>" with
+ * "typedef unsigned int size_t;".
+ */
+
+#undef NEED_SPECIAL_INCLUDE /* assume we DON'T need it, for starters */
+
+#ifdef NEED_SPECIAL_INCLUDE
+#include <someincludefile.h>
+#endif
+
+typedef size_t my_size_t; /* The payoff: do we have size_t now? */
+
+
+/* The next question is whether your compiler supports ANSI-style function
+ * prototypes. You need to know this in order to choose between using
+ * makefile.ansi and using makefile.unix.
+ * The #define line below is set to assume you have ANSI function prototypes.
+ * If you get an error in this group of lines, undefine HAVE_PROTOTYPES.
+ */
+
+#define HAVE_PROTOTYPES
+
+#ifdef HAVE_PROTOTYPES
+int testfunction (int arg1, int * arg2); /* check prototypes */
+
+struct methods_struct { /* check method-pointer declarations */
+ int (*error_exit) (char *msgtext);
+ int (*trace_message) (char *msgtext);
+ int (*another_method) (void);
+};
+
+int testfunction (int arg1, int * arg2) /* check definitions */
+{
+ return arg2[arg1];
+}
+
+int test2function (void) /* check void arg list */
+{
+ return 0;
+}
+#endif
+
+
+/* Now we want to find out if your compiler knows what "unsigned char" means.
+ * If you get an error on the "unsigned char un_char;" line,
+ * then undefine HAVE_UNSIGNED_CHAR.
+ */
+
+#define HAVE_UNSIGNED_CHAR
+
+#ifdef HAVE_UNSIGNED_CHAR
+unsigned char un_char;
+#endif
+
+
+/* Now we want to find out if your compiler knows what "unsigned short" means.
+ * If you get an error on the "unsigned short un_short;" line,
+ * then undefine HAVE_UNSIGNED_SHORT.
+ */
+
+#define HAVE_UNSIGNED_SHORT
+
+#ifdef HAVE_UNSIGNED_SHORT
+unsigned short un_short;
+#endif
+
+
+/* Now we want to find out if your compiler understands type "void".
+ * If you get an error anywhere in here, undefine HAVE_VOID.
+ */
+
+#define HAVE_VOID
+
+#ifdef HAVE_VOID
+/* Caution: a C++ compiler will insist on complete prototypes */
+typedef void * void_ptr; /* check void * */
+#ifdef HAVE_PROTOTYPES /* check ptr to function returning void */
+typedef void (*void_func) (int a, int b);
+#else
+typedef void (*void_func) ();
+#endif
+
+#ifdef HAVE_PROTOTYPES /* check void function result */
+void test3function (void_ptr arg1, void_func arg2)
+#else
+void test3function (arg1, arg2)
+ void_ptr arg1;
+ void_func arg2;
+#endif
+{
+ char * locptr = (char *) arg1; /* check casting to and from void * */
+ arg1 = (void *) locptr;
+ (*arg2) (1, 2); /* check call of fcn returning void */
+}
+#endif
+
+
+/* Now we want to find out if your compiler knows what "const" means.
+ * If you get an error here, undefine HAVE_CONST.
+ */
+
+#define HAVE_CONST
+
+#ifdef HAVE_CONST
+static const int carray[3] = {1, 2, 3};
+
+#ifdef HAVE_PROTOTYPES
+int test4function (const int arg1)
+#else
+int test4function (arg1)
+ const int arg1;
+#endif
+{
+ return carray[arg1];
+}
+#endif
+
+
+/* If you get an error or warning about this structure definition,
+ * define INCOMPLETE_TYPES_BROKEN.
+ */
+
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifndef INCOMPLETE_TYPES_BROKEN
+typedef struct undefined_structure * undef_struct_ptr;
+#endif
+
+
+/* If you get an error about duplicate names,
+ * define NEED_SHORT_EXTERNAL_NAMES.
+ */
+
+#undef NEED_SHORT_EXTERNAL_NAMES
+
+#ifndef NEED_SHORT_EXTERNAL_NAMES
+
+int possibly_duplicate_function ()
+{
+ return 0;
+}
+
+int possibly_dupli_function ()
+{
+ return 1;
+}
+
+#endif
+
+
+
+/************************************************************************
+ * OK, that's it. You should not have to change anything beyond this
+ * point in order to compile and execute this program. (You might get
+ * some warnings, but you can ignore them.)
+ * When you run the program, it will make a couple more tests that it
+ * can do automatically, and then it will create jconfig.h and print out
+ * any additional suggestions it has.
+ ************************************************************************
+ */
+
+
+#ifdef HAVE_PROTOTYPES
+int is_char_signed (int arg)
+#else
+int is_char_signed (arg)
+ int arg;
+#endif
+{
+ if (arg == 189) { /* expected result for unsigned char */
+ return 0; /* type char is unsigned */
+ }
+ else if (arg != -67) { /* expected result for signed char */
+ printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ }
+ return 1; /* assume char is signed otherwise */
+}
+
+
+#ifdef HAVE_PROTOTYPES
+int is_shifting_signed (long arg)
+#else
+int is_shifting_signed (arg)
+ long arg;
+#endif
+/* See whether right-shift on a long is signed or not. */
+{
+ long res = arg >> 4;
+
+ if (res == -0x7F7E80CL) { /* expected result for signed shift */
+ return 1; /* right shift is signed */
+ }
+ /* see if unsigned-shift hack will fix it. */
+ /* we can't just test exact value since it depends on width of long... */
+ res |= (~0L) << (32-4);
+ if (res == -0x7F7E80CL) { /* expected result now? */
+ return 0; /* right shift is unsigned */
+ }
+ printf("Right shift isn't acting as I expect it to.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ return 0; /* try it with unsigned anyway */
+}
+
+
+#ifdef HAVE_PROTOTYPES
+int main (int argc, char ** argv)
+#else
+int main (argc, argv)
+ int argc;
+ char ** argv;
+#endif
+{
+ char signed_char_check = (char) (-67);
+ FILE *outfile;
+
+ /* Attempt to write jconfig.h */
+ if ((outfile = fopen("jconfig.h", "w")) == NULL) {
+ printf("Failed to write jconfig.h\n");
+ return 1;
+ }
+
+ /* Write out all the info */
+ fprintf(outfile, "/* jconfig.h --- generated by ckconfig.c */\n");
+ fprintf(outfile, "/* see jconfig.txt for explanations */\n\n");
+#ifdef HAVE_PROTOTYPES
+ fprintf(outfile, "#define HAVE_PROTOTYPES\n");
+#else
+ fprintf(outfile, "#undef HAVE_PROTOTYPES\n");
+#endif
+#ifdef HAVE_UNSIGNED_CHAR
+ fprintf(outfile, "#define HAVE_UNSIGNED_CHAR\n");
+#else
+ fprintf(outfile, "#undef HAVE_UNSIGNED_CHAR\n");
+#endif
+#ifdef HAVE_UNSIGNED_SHORT
+ fprintf(outfile, "#define HAVE_UNSIGNED_SHORT\n");
+#else
+ fprintf(outfile, "#undef HAVE_UNSIGNED_SHORT\n");
+#endif
+#ifdef HAVE_VOID
+ fprintf(outfile, "/* #define void char */\n");
+#else
+ fprintf(outfile, "#define void char\n");
+#endif
+#ifdef HAVE_CONST
+ fprintf(outfile, "/* #define const */\n");
+#else
+ fprintf(outfile, "#define const\n");
+#endif
+ if (is_char_signed((int) signed_char_check))
+ fprintf(outfile, "#undef CHAR_IS_UNSIGNED\n");
+ else
+ fprintf(outfile, "#define CHAR_IS_UNSIGNED\n");
+#ifdef HAVE_STDDEF_H
+ fprintf(outfile, "#define HAVE_STDDEF_H\n");
+#else
+ fprintf(outfile, "#undef HAVE_STDDEF_H\n");
+#endif
+#ifdef HAVE_STDLIB_H
+ fprintf(outfile, "#define HAVE_STDLIB_H\n");
+#else
+ fprintf(outfile, "#undef HAVE_STDLIB_H\n");
+#endif
+#ifdef NEED_BSD_STRINGS
+ fprintf(outfile, "#define NEED_BSD_STRINGS\n");
+#else
+ fprintf(outfile, "#undef NEED_BSD_STRINGS\n");
+#endif
+#ifdef NEED_SYS_TYPES_H
+ fprintf(outfile, "#define NEED_SYS_TYPES_H\n");
+#else
+ fprintf(outfile, "#undef NEED_SYS_TYPES_H\n");
+#endif
+ fprintf(outfile, "#undef NEED_FAR_POINTERS\n");
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+ fprintf(outfile, "#define NEED_SHORT_EXTERNAL_NAMES\n");
+#else
+ fprintf(outfile, "#undef NEED_SHORT_EXTERNAL_NAMES\n");
+#endif
+#ifdef INCOMPLETE_TYPES_BROKEN
+ fprintf(outfile, "#define INCOMPLETE_TYPES_BROKEN\n");
+#else
+ fprintf(outfile, "#undef INCOMPLETE_TYPES_BROKEN\n");
+#endif
+ fprintf(outfile, "\n#ifdef JPEG_INTERNALS\n\n");
+ if (is_shifting_signed(-0x7F7E80B1L))
+ fprintf(outfile, "#undef RIGHT_SHIFT_IS_UNSIGNED\n");
+ else
+ fprintf(outfile, "#define RIGHT_SHIFT_IS_UNSIGNED\n");
+ fprintf(outfile, "\n#endif /* JPEG_INTERNALS */\n");
+ fprintf(outfile, "\n#ifdef JPEG_CJPEG_DJPEG\n\n");
+ fprintf(outfile, "#define BMP_SUPPORTED /* BMP image file format */\n");
+ fprintf(outfile, "#define GIF_SUPPORTED /* GIF image file format */\n");
+ fprintf(outfile, "#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */\n");
+ fprintf(outfile, "#undef RLE_SUPPORTED /* Utah RLE image file format */\n");
+ fprintf(outfile, "#define TARGA_SUPPORTED /* Targa image file format */\n\n");
+ fprintf(outfile, "#undef TWO_FILE_COMMANDLINE /* You may need this on non-Unix systems */\n");
+ fprintf(outfile, "#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */\n");
+ fprintf(outfile, "#undef DONT_USE_B_MODE\n");
+ fprintf(outfile, "/* #define PROGRESS_REPORT */ /* optional */\n");
+ fprintf(outfile, "\n#endif /* JPEG_CJPEG_DJPEG */\n");
+
+ /* Close the jconfig.h file */
+ fclose(outfile);
+
+ /* User report */
+ printf("Configuration check for Independent JPEG Group's software done.\n");
+ printf("\nI have written the jconfig.h file for you.\n\n");
+#ifdef HAVE_PROTOTYPES
+ printf("You should use makefile.ansi as the starting point for your Makefile.\n");
+#else
+ printf("You should use makefile.unix as the starting point for your Makefile.\n");
+#endif
+
+#ifdef NEED_SPECIAL_INCLUDE
+ printf("\nYou'll need to change jconfig.h to include the system include file\n");
+ printf("that you found type size_t in, or add a direct definition of type\n");
+ printf("size_t if that's what you used. Just add it to the end.\n");
+#endif
+
+ return 0;
+}
diff --git a/jpg/coderules.txt b/jpg/coderules.txt
new file mode 100644
index 0000000..357929f
--- /dev/null
+++ b/jpg/coderules.txt
@@ -0,0 +1,118 @@
+IJG JPEG LIBRARY: CODING RULES
+
+Copyright (C) 1991-1996, Thomas G. Lane.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+Since numerous people will be contributing code and bug fixes, it's important
+to establish a common coding style. The goal of using similar coding styles
+is much more important than the details of just what that style is.
+
+In general we follow the recommendations of "Recommended C Style and Coding
+Standards" revision 6.1 (Cannon et al. as modified by Spencer, Keppel and
+Brader). This document is available in the IJG FTP archive (see
+jpeg/doc/cstyle.ms.tbl.Z, or cstyle.txt.Z for those without nroff/tbl).
+
+Block comments should be laid out thusly:
+
+/*
+ * Block comments in this style.
+ */
+
+We indent statements in K&R style, e.g.,
+ if (test) {
+ then-part;
+ } else {
+ else-part;
+ }
+with two spaces per indentation level. (This indentation convention is
+handled automatically by GNU Emacs and many other text editors.)
+
+Multi-word names should be written in lower case with underscores, e.g.,
+multi_word_name (not multiWordName). Preprocessor symbols and enum constants
+are similar but upper case (MULTI_WORD_NAME). Names should be unique within
+the first fifteen characters. (On some older systems, global names must be
+unique within six characters. We accommodate this without cluttering the
+source code by using macros to substitute shorter names.)
+
+We use function prototypes everywhere; we rely on automatic source code
+transformation to feed prototype-less C compilers. Transformation is done
+by the simple and portable tool 'ansi2knr.c' (courtesy of Ghostscript).
+ansi2knr is not very bright, so it imposes a format requirement on function
+declarations: the function name MUST BEGIN IN COLUMN 1. Thus all functions
+should be written in the following style:
+
+LOCAL(int *)
+function_name (int a, char *b)
+{
+ code...
+}
+
+Note that each function definition must begin with GLOBAL(type), LOCAL(type),
+or METHODDEF(type). These macros expand to "static type" or just "type" as
+appropriate. They provide a readable indication of the routine's usage and
+can readily be changed for special needs. (For instance, special linkage
+keywords can be inserted for use in Windows DLLs.)
+
+ansi2knr does not transform method declarations (function pointers in
+structs). We handle these with a macro JMETHOD, defined as
+ #ifdef HAVE_PROTOTYPES
+ #define JMETHOD(type,methodname,arglist) type (*methodname) arglist
+ #else
+ #define JMETHOD(type,methodname,arglist) type (*methodname) ()
+ #endif
+which is used like this:
+ struct function_pointers {
+ JMETHOD(void, init_entropy_encoder, (int somearg, jparms *jp));
+ JMETHOD(void, term_entropy_encoder, (void));
+ };
+Note the set of parentheses surrounding the parameter list.
+
+A similar solution is used for forward and external function declarations
+(see the EXTERN and JPP macros).
+
+If the code is to work on non-ANSI compilers, we cannot rely on a prototype
+declaration to coerce actual parameters into the right types. Therefore, use
+explicit casts on actual parameters whenever the actual parameter type is not
+identical to the formal parameter. Beware of implicit conversions to "int".
+
+It seems there are some non-ANSI compilers in which the sizeof() operator
+is defined to return int, yet size_t is defined as long. Needless to say,
+this is brain-damaged. Always use the SIZEOF() macro in place of sizeof(),
+so that the result is guaranteed to be of type size_t.
+
+
+The JPEG library is intended to be used within larger programs. Furthermore,
+we want it to be reentrant so that it can be used by applications that process
+multiple images concurrently. The following rules support these requirements:
+
+1. Avoid direct use of file I/O, "malloc", error report printouts, etc;
+pass these through the common routines provided.
+
+2. Minimize global namespace pollution. Functions should be declared static
+wherever possible. (Note that our method-based calling conventions help this
+a lot: in many modules only the initialization function will ever need to be
+called directly, so only that function need be externally visible.) All
+global function names should begin with "jpeg_", and should have an
+abbreviated name (unique in the first six characters) substituted by macro
+when NEED_SHORT_EXTERNAL_NAMES is set.
+
+3. Don't use global variables; anything that must be used in another module
+should be in the common data structures.
+
+4. Don't use static variables except for read-only constant tables. Variables
+that should be private to a module can be placed into private structures (see
+the system architecture document, structure.txt).
+
+5. Source file names should begin with "j" for files that are part of the
+library proper; source files that are not part of the library, such as cjpeg.c
+and djpeg.c, do not begin with "j". Keep source file names to eight
+characters (plus ".c" or ".h", etc) to make life easy for MS-DOSers. Keep
+compression and decompression code in separate source files --- some
+applications may want only one half of the library.
+
+Note: these rules (particularly #4) are not followed religiously in the
+modules that are used in cjpeg/djpeg but are not part of the JPEG library
+proper. Those modules are not really intended to be used in other
+applications.
diff --git a/jpg/config.guess b/jpg/config.guess
new file mode 100644
index 0000000..8152efd
--- /dev/null
+++ b/jpg/config.guess
@@ -0,0 +1,1522 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011 Free Software Foundation, Inc.
+
+timestamp='2011-11-11'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ hexagon:Linux:*:*)
+ echo hexagon-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/jpg/config.sub b/jpg/config.sub
new file mode 100644
index 0000000..e76eaf4
--- /dev/null
+++ b/jpg/config.sub
@@ -0,0 +1,1771 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011 Free Software Foundation, Inc.
+
+timestamp='2011-11-11'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | be32 | be64 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | epiphany \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | open8 \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pyramid \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | we32k \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pyramid-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i386-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/jpg/configure b/jpg/configure
new file mode 100644
index 0000000..9ba1383
--- /dev/null
+++ b/jpg/configure
@@ -0,0 +1,15928 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.68 for libjpeg 8.4.0.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ # Preserve -v and -x to the replacement shell.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+ esac
+ exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"}
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='libjpeg'
+PACKAGE_TARNAME='libjpeg'
+PACKAGE_VERSION='8.4.0'
+PACKAGE_STRING='libjpeg 8.4.0'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+JPEG_LIB_VERSION
+MEMORYMGR
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+ac_ct_AR
+AR
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+SED
+LIBTOOL
+OBJDUMP
+DLLTOOL
+AS
+HAVE_LD_VERSION_SCRIPT_FALSE
+HAVE_LD_VERSION_SCRIPT_TRUE
+LN_S
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+ANSI2KNR
+U
+EGREP
+GREP
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
+enable_maintainer_mode
+enable_ld_version_script
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+enable_maxmem
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used" >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures libjpeg 8.4.0 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/libjpeg]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of libjpeg 8.4.0:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-silent-rules less verbose build output (undo: `make V=1')
+ --disable-silent-rules verbose build output (undo: `make V=0')
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --enable-ld-version-script
+ enable linker version script (default is enabled
+ when possible)
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-static[=PKGS] build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --enable-maxmem=N enable use of temp files, set max mem usage to N MB
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-sysroot=DIR Search for dependent libraries within DIR
+ (or the compiler's sysroot if not specified).
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+libjpeg configure 8.4.0
+generated by GNU Autoconf 2.68
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by libjpeg $as_me 8.4.0, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+# Directory where autotools helper scripts lives.
+ac_aux_dir=
+for ac_dir in . "$srcdir"/.; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in . \"$srcdir\"/." "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+# Generate configuration headers.
+ac_config_headers="$ac_config_headers jconfig.h:jconfig.cfg"
+
+
+# Hack: disable autoheader so that it doesn't overwrite our cfg template.
+AUTOHEADER="echo autoheader ignored"
+
+# Check system type
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if ${ac_cv_target+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$target_alias" = x; then
+ ac_cv_target=$ac_cv_host
+else
+ ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+# Initialize Automake
+# Don't require all the GNU mandated files
+am__api_version='1.11'
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if ${ac_cv_path_mkdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+ [\\/$]* | ?:[\\/]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='libjpeg'
+ VERSION='8.4.0'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+# Make --enable-silent-rules the default.
+# To get verbose build output you may configure
+# with --disable-silent-rules or use "make V=1".
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no) AM_DEFAULT_VERBOSITY=1;;
+*) AM_DEFAULT_VERBOSITY=0;;
+esac
+AM_BACKSLASH='\'
+
+
+# This is required when using the de-ANSI-fication feature.
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for function prototypes" >&5
+$as_echo_n "checking for function prototypes... " >&6; }
+if test "$ac_cv_prog_cc_c89" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define PROTOTYPES 1" >>confdefs.h
+
+
+$as_echo "#define __PROTOTYPES 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+if test "$ac_cv_prog_cc_stdc" != no; then
+ U= ANSI2KNR=
+else
+ U=_ ANSI2KNR=./ansi2knr
+fi
+# Ensure some checks needed by ansi2knr itself.
+
+for ac_header in string.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default"
+if test "x$ac_cv_header_string_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STRING_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+# Add configure option --enable-maintainer-mode which enables
+# dependency checking and generation useful to package maintainers.
+# This is made an option to avoid confusing end users.
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+ # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+ if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+# Check for programs
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+ case $ac_cv_prog_cc_stdc in #(
+ no) :
+ ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #(
+ *) :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if ${ac_cv_prog_cc_c99+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+}
+
+int
+main ()
+{
+
+ // Check bool.
+ _Bool success = false;
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
+
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+else
+ ac_cv_prog_cc_stdc=no
+fi
+
+fi
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5
+$as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; }
+ if ${ac_cv_prog_cc_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+
+ case $ac_cv_prog_cc_stdc in #(
+ no) :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;; #(
+ '') :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;; #(
+ *) :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5
+$as_echo "$ac_cv_prog_cc_stdc" >&6; } ;;
+esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+
+# Check if LD supports linker scripts,
+# and define automake conditional HAVE_LD_VERSION_SCRIPT if so.
+# Check whether --enable-ld-version-script was given.
+if test "${enable_ld_version_script+set}" = set; then :
+ enableval=$enable_ld_version_script; have_ld_version_script=$enableval
+fi
+
+if test -z "$have_ld_version_script"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if LD -Wl,--version-script works" >&5
+$as_echo_n "checking if LD -Wl,--version-script works... " >&6; }
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map"
+ cat > conftest.map <<EOF
+VERS_1 {
+ global: sym;
+};
+
+VERS_2 {
+ global: sym;
+} VERS_1;
+EOF
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ have_ld_version_script=yes
+else
+ have_ld_version_script=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ rm -f conftest.map
+ LDFLAGS="$save_LDFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ld_version_script" >&5
+$as_echo "$have_ld_version_script" >&6; }
+fi
+ if test "$have_ld_version_script" = "yes"; then
+ HAVE_LD_VERSION_SCRIPT_TRUE=
+ HAVE_LD_VERSION_SCRIPT_FALSE='#'
+else
+ HAVE_LD_VERSION_SCRIPT_TRUE='#'
+ HAVE_LD_VERSION_SCRIPT_FALSE=
+fi
+
+
+# See if compiler supports prototypes.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for function prototypes" >&5
+$as_echo_n "checking for function prototypes... " >&6; }
+if ${ijg_cv_have_prototypes+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int testfunction (int arg1, int * arg2); /* check prototypes */
+struct methods_struct { /* check method-pointer declarations */
+ int (*error_exit) (char *msgtext);
+ int (*trace_message) (char *msgtext);
+ int (*another_method) (void);
+};
+int testfunction (int arg1, int * arg2) /* check definitions */
+{ return arg2[arg1]; }
+int test2function (void) /* check void arg list */
+{ return 0; }
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ijg_cv_have_prototypes=yes
+else
+ ijg_cv_have_prototypes=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ijg_cv_have_prototypes" >&5
+$as_echo "$ijg_cv_have_prototypes" >&6; }
+if test $ijg_cv_have_prototypes = yes; then
+
+$as_echo "#define HAVE_PROTOTYPES 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Your compiler does not seem to know about function prototypes.
+ Perhaps it needs a special switch to enable ANSI C mode.
+ If so, we recommend running configure like this:
+ ./configure CC='cc -switch'
+ where -switch is the proper switch." >&5
+$as_echo "$as_me: WARNING: Your compiler does not seem to know about function prototypes.
+ Perhaps it needs a special switch to enable ANSI C mode.
+ If so, we recommend running configure like this:
+ ./configure CC='cc -switch'
+ where -switch is the proper switch." >&2;}
+fi
+
+# Check header files
+for ac_header in stddef.h stdlib.h locale.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+ac_fn_c_check_header_mongrel "$LINENO" "string.h" "ac_cv_header_string_h" "$ac_includes_default"
+if test "x$ac_cv_header_string_h" = xyes; then :
+
+else
+
+$as_echo "#define NEED_BSD_STRINGS 1" >>confdefs.h
+
+fi
+
+
+
+# See whether type size_t is defined in any ANSI-standard places;
+# if not, perhaps it is defined in <sys/types.h>.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for size_t" >&5
+$as_echo_n "checking for size_t... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#ifdef NEED_BSD_STRINGS
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+typedef size_t my_size_t;
+
+int
+main ()
+{
+ my_size_t foovar;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ijg_size_t_ok=yes
+else
+ ijg_size_t_ok="not ANSI, perhaps it is in sys/types.h"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ijg_size_t_ok" >&5
+$as_echo "$ijg_size_t_ok" >&6; }
+if test "$ijg_size_t_ok" != yes; then
+ ac_fn_c_check_header_mongrel "$LINENO" "sys/types.h" "ac_cv_header_sys_types_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_types_h" = xyes; then :
+
+$as_echo "#define NEED_SYS_TYPES_H 1" >>confdefs.h
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "size_t" >/dev/null 2>&1; then :
+ ijg_size_t_ok="size_t is in sys/types.h"
+else
+ ijg_size_t_ok=no
+fi
+rm -f conftest*
+
+else
+ ijg_size_t_ok=no
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ijg_size_t_ok" >&5
+$as_echo "$ijg_size_t_ok" >&6; }
+ if test "$ijg_size_t_ok" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Type size_t is not defined in any of the usual places.
+ Try putting '\"typedef unsigned int size_t;\"' in jconfig.h." >&5
+$as_echo "$as_me: WARNING: Type size_t is not defined in any of the usual places.
+ Try putting '\"typedef unsigned int size_t;\"' in jconfig.h." >&2;}
+ fi
+fi
+
+# Check compiler characteristics
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for type unsigned char" >&5
+$as_echo_n "checking for type unsigned char... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+ unsigned char un_char;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_UNSIGNED_CHAR 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for type unsigned short" >&5
+$as_echo_n "checking for type unsigned short... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+ unsigned short un_short;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_UNSIGNED_SHORT 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for type void" >&5
+$as_echo_n "checking for type void... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Caution: a C++ compiler will insist on valid prototypes */
+typedef void * void_ptr; /* check void * */
+#ifdef HAVE_PROTOTYPES /* check ptr to function returning void */
+typedef void (*void_func) (int a, int b);
+#else
+typedef void (*void_func) ();
+#endif
+
+#ifdef HAVE_PROTOTYPES /* check void function result */
+void test3function (void_ptr arg1, void_func arg2)
+#else
+void test3function (arg1, arg2)
+ void_ptr arg1;
+ void_func arg2;
+#endif
+{
+ char * locptr = (char *) arg1; /* check casting to and from void * */
+ arg1 = (void *) locptr;
+ (*arg2) (1, 2); /* check call of fcn returning void */
+}
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define void char" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if ${ac_cv_c_const+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset cs;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+
+# Check for non-broken inline under various spellings
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+ijg_cv_inline=""
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+} __inline__ int foo() { return 0; }
+int bar() { return foo();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ijg_cv_inline="__inline__"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+} __inline int foo() { return 0; }
+int bar() { return foo();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ijg_cv_inline="__inline"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+} inline int foo() { return 0; }
+int bar() { return foo();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ijg_cv_inline="inline"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ijg_cv_inline" >&5
+$as_echo "$ijg_cv_inline" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define INLINE $ijg_cv_inline
+_ACEOF
+
+
+# We cannot check for bogus warnings, but at least we can check for errors
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken incomplete types" >&5
+$as_echo_n "checking for broken incomplete types... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+ typedef struct undefined_structure * undef_struct_ptr;
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: broken" >&5
+$as_echo "broken" >&6; }
+
+$as_echo "#define INCOMPLETE_TYPES_BROKEN 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+# Test whether global names are unique to at least 15 chars
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for short external names" >&5
+$as_echo_n "checking for short external names... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int possibly_duplicate_function () { return 0; }
+int possibly_dupli_function () { return 1; }
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: short" >&5
+$as_echo "short" >&6; }
+
+$as_echo "#define NEED_SHORT_EXTERNAL_NAMES 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+# Run-time checks
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if char is signed" >&5
+$as_echo_n "checking to see if char is signed... " >&6; }
+if test "$cross_compiling" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Assuming that char is signed on target machine.
+ If it is unsigned, this will be a little bit inefficient." >&5
+$as_echo "$as_me: WARNING: Assuming that char is signed on target machine.
+ If it is unsigned, this will be a little bit inefficient." >&2;}
+
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_PROTOTYPES
+int is_char_signed (int arg)
+#else
+int is_char_signed (arg)
+ int arg;
+#endif
+{
+ if (arg == 189) { /* expected result for unsigned char */
+ return 0; /* type char is unsigned */
+ }
+ else if (arg != -67) { /* expected result for signed char */
+ printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ }
+ return 1; /* assume char is signed otherwise */
+}
+char signed_char_check = (char) (-67);
+int main() {
+ exit(is_char_signed((int) signed_char_check));
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define CHAR_IS_UNSIGNED 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if right shift is signed" >&5
+$as_echo_n "checking to see if right shift is signed... " >&6; }
+if test "$cross_compiling" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Assuming that right shift is signed on target machine." >&5
+$as_echo "Assuming that right shift is signed on target machine." >&6; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#ifdef HAVE_PROTOTYPES
+int is_shifting_signed (long arg)
+#else
+int is_shifting_signed (arg)
+ long arg;
+#endif
+/* See whether right-shift on a long is signed or not. */
+{
+ long res = arg >> 4;
+
+ if (res == -0x7F7E80CL) { /* expected result for signed shift */
+ return 1; /* right shift is signed */
+ }
+ /* see if unsigned-shift hack will fix it. */
+ /* we can't just test exact value since it depends on width of long... */
+ res |= (~0L) << (32-4);
+ if (res == -0x7F7E80CL) { /* expected result now? */
+ return 0; /* right shift is unsigned */
+ }
+ printf("Right shift isn't acting as I expect it to.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ return 0; /* try it with unsigned anyway */
+}
+int main() {
+ exit(is_shifting_signed(-0x7F7E80B1L));
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define RIGHT_SHIFT_IS_UNSIGNED 1" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking to see if fopen accepts b spec" >&5
+$as_echo_n "checking to see if fopen accepts b spec... " >&6; }
+if test "$cross_compiling" = yes; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Assuming that it does." >&5
+$as_echo "Assuming that it does." >&6; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <stdio.h>
+int main() {
+ if (fopen("conftestdata", "wb") != NULL)
+ exit(0);
+ exit(1);
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define DONT_USE_B_MODE 1" >>confdefs.h
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+# Configure libtool
+enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
+set dummy ${ac_tool_prefix}as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AS+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AS"; then
+ ac_cv_prog_AS="$AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AS="${ac_tool_prefix}as"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AS=$ac_cv_prog_AS
+if test -n "$AS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
+$as_echo "$AS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AS"; then
+ ac_ct_AS=$AS
+ # Extract the first word of "as", so it can be a program name with args.
+set dummy as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AS+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AS"; then
+ ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_AS="as"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AS=$ac_cv_prog_ac_ct_AS
+if test -n "$ac_ct_AS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5
+$as_echo "$ac_ct_AS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AS" = x; then
+ AS="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AS=$ac_ct_AS
+ fi
+else
+ AS="$ac_cv_prog_AS"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DLLTOOL"; then
+ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+ ac_ct_DLLTOOL=$DLLTOOL
+ # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DLLTOOL"; then
+ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DLLTOOL" = x; then
+ DLLTOOL="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DLLTOOL=$ac_ct_DLLTOOL
+ fi
+else
+ DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+ ;;
+esac
+
+test -z "$AS" && AS=as
+
+
+
+
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case "$ECHO" in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in dumpbin "link -dump"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in dumpbin "link -dump"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,b/c, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test "$GCC" != yes; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DLLTOOL"; then
+ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+ ac_ct_DLLTOOL=$DLLTOOL
+ # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DLLTOOL"; then
+ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DLLTOOL" = x; then
+ DLLTOOL="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DLLTOOL=$ac_ct_DLLTOOL
+ fi
+else
+ DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh
+ # decide which to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in ar
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AR" && break
+ done
+fi
+if test -z "$AR"; then
+ ac_ct_AR=$AR
+ for ac_prog in ar
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_AR="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_AR" && break
+done
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ar_at_file=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -ne 0; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test "x$lt_cv_ar_at_file" = xno; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+ (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+ withval=$with_sysroot;
+else
+ with_sysroot=no
+fi
+
+
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+ if test "$GCC" = yes; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
+$as_echo "${with_sysroot}" >&6; }
+ as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+ ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD="${LD-ld}_sol2"
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$MANIFEST_TOOL"; then
+ ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+ ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+ # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_MANIFEST_TOOL"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_MANIFEST_TOOL" = x; then
+ MANIFEST_TOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+ fi
+else
+ MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&5
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+ MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&5
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+ echo "$AR cru libconftest.a conftest.o" >&5
+ $AR cru libconftest.a conftest.o 2>&5
+ echo "$RANLIB libconftest.a" >&5
+ $RANLIB libconftest.a 2>&5
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&5
+ elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[012]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+
+
+
+ enable_dlopen=no
+
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+ # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for lt_pkg in $withval; do
+ IFS="$lt_save_ifs"
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl='-Xlinker '
+ if test -n "$lt_prog_compiler_pic"; then
+ lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ lt_prog_compiler_wl='-Wl,-Wl,,'
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ *Intel*\ [CF]*Compiler*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ *Portland\ Group*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ export_dynamic_flag_spec='${wl}--export-all-symbols'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+ exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_="/usr/lib:/lib"
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_="/usr/lib:/lib"
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ fi
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ file_list_spec='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+ enable_shared_with_static_runtimes=yes
+ exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ old_postinstall_cmds='chmod 644 $oldlib'
+ postlink_cmds='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ enable_shared_with_static_runtimes=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+ else
+ whole_archive_flag_spec=''
+ fi
+ link_all_deplibs=yes
+ allow_undefined_flag="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler__b=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -b"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler__b=yes
+ fi
+ else
+ lt_cv_prog_compiler__b=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_irix_exported_symbol=yes
+else
+ lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+ if test "$lt_cv_irix_exported_symbol" = yes; then
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ fi
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc=no
+ else
+ lt_cv_archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='${libname}.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec="$LIB"
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[23].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+ test "$inherit_rpath" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+ lt_cv_dlopen="shl_load"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report which library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+# Select memory manager depending on user input.
+# If no "-enable-maxmem", use jmemnobs
+MEMORYMGR='jmemnobs'
+MAXMEM="no"
+# Check whether --enable-maxmem was given.
+if test "${enable_maxmem+set}" = set; then :
+ enableval=$enable_maxmem; MAXMEM="$enableval"
+fi
+
+if test "x$MAXMEM" = xyes; then
+ MAXMEM=1
+fi
+if test "x$MAXMEM" != xno; then
+ if test -n "`echo $MAXMEM | sed 's/[0-9]//g'`"; then
+ as_fn_error $? "non-numeric argument to --enable-maxmem" "$LINENO" 5
+ fi
+ DEFAULTMAXMEM=`expr $MAXMEM \* 1048576`
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_MAX_MEM ${DEFAULTMAXMEM}
+_ACEOF
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 'tmpfile()'" >&5
+$as_echo_n "checking for 'tmpfile()'... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+ FILE * tfile = tmpfile();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ MEMORYMGR='jmemansi'
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ MEMORYMGR='jmemname'
+
+ # Test for the need to remove temporary files using a signal handler
+ # (for cjpeg/djpeg)
+
+$as_echo "#define NEED_SIGNAL_CATCHER 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for 'mktemp()'" >&5
+$as_echo_n "checking for 'mktemp()'... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+ char fname[80]; mktemp(fname);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define NO_MKTEMP 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+
+
+# Extract the library version IDs from jpeglib.h.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking libjpeg version number" >&5
+$as_echo_n "checking libjpeg version number... " >&6; }
+major=`sed -ne 's/^#define JPEG_LIB_VERSION_MAJOR *\([0-9][0-9]*\).*$/\1/p' $srcdir/jpeglib.h`
+minor=`sed -ne 's/^#define JPEG_LIB_VERSION_MINOR *\([0-9][0-9]*\).*$/\1/p' $srcdir/jpeglib.h`
+JPEG_LIB_VERSION=`expr $major + $minor`:0:$minor
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $JPEG_LIB_VERSION" >&5
+$as_echo "$JPEG_LIB_VERSION" >&6; }
+
+ac_config_files="$ac_config_files Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_LD_VERSION_SCRIPT_TRUE}" && test -z "${HAVE_LD_VERSION_SCRIPT_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_LD_VERSION_SCRIPT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by libjpeg $as_me 8.4.0, which was
+generated by GNU Autoconf 2.68. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+libjpeg config.status 8.4.0
+configured by $0, generated by GNU Autoconf 2.68,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in AS \
+DLLTOOL \
+OBJDUMP \
+SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+nm_file_list_spec \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "jconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS jconfig.h:jconfig.cfg" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=""
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Assembler program.
+AS=$lt_AS
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Object dumper program.
+OBJDUMP=$lt_OBJDUMP
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ if test x"$xsi_shell" = xyes; then
+ sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\ case ${1} in\
+\ */*) func_dirname_result="${1%/*}${2}" ;;\
+\ * ) func_dirname_result="${3}" ;;\
+\ esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\ func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\ case ${1} in\
+\ */*) func_dirname_result="${1%/*}${2}" ;;\
+\ * ) func_dirname_result="${3}" ;;\
+\ esac\
+\ func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\ # positional parameters, so assign one to ordinary parameter first.\
+\ func_stripname_result=${3}\
+\ func_stripname_result=${func_stripname_result#"${1}"}\
+\ func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\ func_split_long_opt_name=${1%%=*}\
+\ func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\ func_split_short_opt_arg=${1#??}\
+\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\ case ${1} in\
+\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\ *) func_lo2o_result=${1} ;;\
+\ esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+ func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+ func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+ func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+ sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+ eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\ func_quote_for_eval "${2}"\
+\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ # Save a `func_append' function call where possible by direct use of '+='
+ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+else
+ # Save a `func_append' function call even when '+=' is not available
+ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/jpg/configure.ac b/jpg/configure.ac
new file mode 100644
index 0000000..12293b0
--- /dev/null
+++ b/jpg/configure.ac
@@ -0,0 +1,356 @@
+# IJG auto-configuration source file.
+# Process this file with autoconf to produce a configure script.
+
+#
+# Configure script for IJG libjpeg
+#
+
+AC_INIT([libjpeg], [8.4.0])
+
+# Directory where autotools helper scripts lives.
+AC_CONFIG_AUX_DIR([.])
+
+# Generate configuration headers.
+AC_CONFIG_HEADERS([jconfig.h:jconfig.cfg])
+
+# Hack: disable autoheader so that it doesn't overwrite our cfg template.
+AUTOHEADER="echo autoheader ignored"
+
+# Check system type
+AC_CANONICAL_TARGET
+
+# Initialize Automake
+# Don't require all the GNU mandated files
+AM_INIT_AUTOMAKE([-Wall -Werror -Wno-obsolete ansi2knr no-dist foreign])
+
+# Make --enable-silent-rules the default.
+# To get verbose build output you may configure
+# with --disable-silent-rules or use "make V=1".
+AM_SILENT_RULES([yes])
+
+# This is required when using the de-ANSI-fication feature.
+AM_C_PROTOTYPES
+
+# Add configure option --enable-maintainer-mode which enables
+# dependency checking and generation useful to package maintainers.
+# This is made an option to avoid confusing end users.
+AM_MAINTAINER_MODE
+
+# Check for programs
+AC_PROG_CC
+AC_PROG_CC_STDC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_LN_S
+
+# Check if LD supports linker scripts,
+# and define automake conditional HAVE_LD_VERSION_SCRIPT if so.
+AC_ARG_ENABLE([ld-version-script],
+ AS_HELP_STRING([--enable-ld-version-script],
+ [enable linker version script (default is enabled when possible)]),
+ [have_ld_version_script=$enableval], [])
+if test -z "$have_ld_version_script"; then
+ AC_MSG_CHECKING([if LD -Wl,--version-script works])
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map"
+ cat > conftest.map <<EOF
+VERS_1 {
+ global: sym;
+};
+
+VERS_2 {
+ global: sym;
+} VERS_1;
+EOF
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
+ [have_ld_version_script=yes], [have_ld_version_script=no])
+ rm -f conftest.map
+ LDFLAGS="$save_LDFLAGS"
+ AC_MSG_RESULT($have_ld_version_script)
+fi
+AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test "$have_ld_version_script" = "yes")
+
+# See if compiler supports prototypes.
+AC_MSG_CHECKING([for function prototypes])
+AC_CACHE_VAL([ijg_cv_have_prototypes],
+[AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+int testfunction (int arg1, int * arg2); /* check prototypes */
+struct methods_struct { /* check method-pointer declarations */
+ int (*error_exit) (char *msgtext);
+ int (*trace_message) (char *msgtext);
+ int (*another_method) (void);
+};
+int testfunction (int arg1, int * arg2) /* check definitions */
+{ return arg2[arg1]; }
+int test2function (void) /* check void arg list */
+{ return 0; }
+]])],
+ [ijg_cv_have_prototypes=yes],
+ [ijg_cv_have_prototypes=no])])
+AC_MSG_RESULT([$ijg_cv_have_prototypes])
+if test $ijg_cv_have_prototypes = yes; then
+ AC_DEFINE([HAVE_PROTOTYPES],[1],[Compiler supports function prototypes.])
+else
+ AC_MSG_WARN([Your compiler does not seem to know about function prototypes.
+ Perhaps it needs a special switch to enable ANSI C mode.
+ If so, we recommend running configure like this:
+ ./configure CC='cc -switch'
+ where -switch is the proper switch.])
+fi
+
+# Check header files
+AC_CHECK_HEADERS([stddef.h stdlib.h locale.h])
+AC_CHECK_HEADER([string.h], [],
+ [AC_DEFINE([NEED_BSD_STRINGS], [1],
+ [Compiler has <strings.h> rather than standard <string.h>.])])
+
+# See whether type size_t is defined in any ANSI-standard places;
+# if not, perhaps it is defined in <sys/types.h>.
+AC_MSG_CHECKING([for size_t])
+AC_TRY_COMPILE([
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#ifdef NEED_BSD_STRINGS
+#include <strings.h>
+#else
+#include <string.h>
+#endif
+typedef size_t my_size_t;
+],
+ [ my_size_t foovar; ],
+ [ijg_size_t_ok=yes],
+ [ijg_size_t_ok="not ANSI, perhaps it is in sys/types.h"])
+AC_MSG_RESULT([$ijg_size_t_ok])
+if test "$ijg_size_t_ok" != yes; then
+ AC_CHECK_HEADER([sys/types.h],
+ [AC_DEFINE([NEED_SYS_TYPES_H], [1],
+ [Need to include <sys/types.h> in order to obtain size_t.])
+ AC_EGREP_CPP([size_t], [#include <sys/types.h>],
+ [ijg_size_t_ok="size_t is in sys/types.h"],
+ [ijg_size_t_ok=no])],
+ [ijg_size_t_ok=no])
+ AC_MSG_RESULT([$ijg_size_t_ok])
+ if test "$ijg_size_t_ok" = no; then
+ AC_MSG_WARN([Type size_t is not defined in any of the usual places.
+ Try putting '"typedef unsigned int size_t;"' in jconfig.h.])
+ fi
+fi
+
+# Check compiler characteristics
+AC_MSG_CHECKING([for type unsigned char])
+AC_TRY_COMPILE([], [ unsigned char un_char; ],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_UNSIGNED_CHAR], [1],
+ [Compiler supports 'unsigned char'.])],
+ [AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING([for type unsigned short])
+AC_TRY_COMPILE([], [ unsigned short un_short; ],
+ [AC_MSG_RESULT(yes)
+ AC_DEFINE([HAVE_UNSIGNED_SHORT], [1],
+ [Compiler supports 'unsigned short'.])],
+ [AC_MSG_RESULT(no)])
+
+AC_MSG_CHECKING([for type void])
+AC_TRY_COMPILE([
+/* Caution: a C++ compiler will insist on valid prototypes */
+typedef void * void_ptr; /* check void * */
+#ifdef HAVE_PROTOTYPES /* check ptr to function returning void */
+typedef void (*void_func) (int a, int b);
+#else
+typedef void (*void_func) ();
+#endif
+
+#ifdef HAVE_PROTOTYPES /* check void function result */
+void test3function (void_ptr arg1, void_func arg2)
+#else
+void test3function (arg1, arg2)
+ void_ptr arg1;
+ void_func arg2;
+#endif
+{
+ char * locptr = (char *) arg1; /* check casting to and from void * */
+ arg1 = (void *) locptr;
+ (*arg2) (1, 2); /* check call of fcn returning void */
+}
+], [ ],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_RESULT(no)
+ AC_DEFINE([void], [char],
+ [Define 'void' as 'char' for archaic compilers
+ that don't understand it.])])
+AC_C_CONST
+
+# Check for non-broken inline under various spellings
+AC_MSG_CHECKING([for inline])
+ijg_cv_inline=""
+AC_TRY_COMPILE([], [} __inline__ int foo() { return 0; }
+int bar() { return foo();], ijg_cv_inline="__inline__",
+[AC_TRY_COMPILE(, [} __inline int foo() { return 0; }
+int bar() { return foo();], ijg_cv_inline="__inline",
+[AC_TRY_COMPILE(, [} inline int foo() { return 0; }
+int bar() { return foo();], ijg_cv_inline="inline")])])
+AC_MSG_RESULT($ijg_cv_inline)
+AC_DEFINE_UNQUOTED([INLINE], [$ijg_cv_inline],
+ [How to obtain function inlining.])
+
+# We cannot check for bogus warnings, but at least we can check for errors
+AC_MSG_CHECKING([for broken incomplete types])
+AC_TRY_COMPILE([ typedef struct undefined_structure * undef_struct_ptr; ],
+ [],
+ [AC_MSG_RESULT(ok)],
+ [AC_MSG_RESULT(broken)
+ AC_DEFINE([INCOMPLETE_TYPES_BROKEN], [1],
+ [Compiler does not support pointers to unspecified
+ structures.])])
+
+# Test whether global names are unique to at least 15 chars
+AC_MSG_CHECKING([for short external names])
+AC_TRY_LINK([
+int possibly_duplicate_function () { return 0; }
+int possibly_dupli_function () { return 1; }
+], [],
+ [AC_MSG_RESULT(ok)],
+ [AC_MSG_RESULT(short)
+ AC_DEFINE([NEED_SHORT_EXTERNAL_NAMES], [1],
+ [Linker requires that global names be unique in
+ first 15 characters.])])
+
+# Run-time checks
+AC_MSG_CHECKING([to see if char is signed])
+AC_TRY_RUN([
+#ifdef HAVE_PROTOTYPES
+int is_char_signed (int arg)
+#else
+int is_char_signed (arg)
+ int arg;
+#endif
+{
+ if (arg == 189) { /* expected result for unsigned char */
+ return 0; /* type char is unsigned */
+ }
+ else if (arg != -67) { /* expected result for signed char */
+ printf("Hmm, it seems 'char' is not eight bits wide on your machine.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ }
+ return 1; /* assume char is signed otherwise */
+}
+char signed_char_check = (char) (-67);
+int main() {
+ exit(is_char_signed((int) signed_char_check));
+}], [AC_MSG_RESULT(no)
+ AC_DEFINE([CHAR_IS_UNSIGNED], [1],
+ [Characters are unsigned])],
+ [AC_MSG_RESULT(yes)],
+[AC_MSG_WARN([Assuming that char is signed on target machine.
+ If it is unsigned, this will be a little bit inefficient.])
+])
+
+AC_MSG_CHECKING([to see if right shift is signed])
+AC_TRY_RUN([
+#ifdef HAVE_PROTOTYPES
+int is_shifting_signed (long arg)
+#else
+int is_shifting_signed (arg)
+ long arg;
+#endif
+/* See whether right-shift on a long is signed or not. */
+{
+ long res = arg >> 4;
+
+ if (res == -0x7F7E80CL) { /* expected result for signed shift */
+ return 1; /* right shift is signed */
+ }
+ /* see if unsigned-shift hack will fix it. */
+ /* we can't just test exact value since it depends on width of long... */
+ res |= (~0L) << (32-4);
+ if (res == -0x7F7E80CL) { /* expected result now? */
+ return 0; /* right shift is unsigned */
+ }
+ printf("Right shift isn't acting as I expect it to.\n");
+ printf("I fear the JPEG software will not work at all.\n\n");
+ return 0; /* try it with unsigned anyway */
+}
+int main() {
+ exit(is_shifting_signed(-0x7F7E80B1L));
+}],
+ [AC_MSG_RESULT(no)
+ AC_DEFINE([RIGHT_SHIFT_IS_UNSIGNED], [1],
+ [Broken compiler shifts signed values as an unsigned shift.])],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_RESULT(Assuming that right shift is signed on target machine.)])
+
+AC_MSG_CHECKING([to see if fopen accepts b spec])
+AC_TRY_RUN([
+#include <stdio.h>
+int main() {
+ if (fopen("conftestdata", "wb") != NULL)
+ exit(0);
+ exit(1);
+}],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_RESULT(no)
+ AC_DEFINE([DONT_USE_B_MODE], [1],
+ [Don't open files in binary mode.])],
+ [AC_MSG_RESULT(Assuming that it does.)])
+
+# Configure libtool
+AC_LIBTOOL_WIN32_DLL
+AC_PROG_LIBTOOL
+
+# Select memory manager depending on user input.
+# If no "-enable-maxmem", use jmemnobs
+MEMORYMGR='jmemnobs'
+MAXMEM="no"
+AC_ARG_ENABLE([maxmem],
+[ --enable-maxmem[=N] enable use of temp files, set max mem usage to N MB],
+[MAXMEM="$enableval"])
+dnl [# support --with-maxmem for backwards compatibility with IJG V5.]
+dnl AC_ARG_WITH(maxmem, , MAXMEM="$withval")
+if test "x$MAXMEM" = xyes; then
+ MAXMEM=1
+fi
+if test "x$MAXMEM" != xno; then
+ if test -n "`echo $MAXMEM | sed 's/[[0-9]]//g'`"; then
+ AC_MSG_ERROR(non-numeric argument to --enable-maxmem)
+ fi
+ DEFAULTMAXMEM=`expr $MAXMEM \* 1048576`
+ AC_DEFINE_UNQUOTED([DEFAULT_MAX_MEM], [${DEFAULTMAXMEM}],
+ [Maximum data space library will allocate.])
+ AC_MSG_CHECKING([for 'tmpfile()'])
+ AC_TRY_LINK([#include <stdio.h>], [ FILE * tfile = tmpfile(); ],
+ [AC_MSG_RESULT(yes)
+ MEMORYMGR='jmemansi'],
+ [AC_MSG_RESULT(no)
+ dnl if tmpfile is not present, must use jmemname.
+ MEMORYMGR='jmemname'
+
+ # Test for the need to remove temporary files using a signal handler
+ # (for cjpeg/djpeg)
+ AC_DEFINE([NEED_SIGNAL_CATCHER], [1],
+ [Need signal handler to clean up temporary files.])
+ AC_MSG_CHECKING([for 'mktemp()'])
+ AC_TRY_LINK([], [ char fname[80]; mktemp(fname); ],
+ [AC_MSG_RESULT(yes)],
+ [AC_MSG_RESULT(no)
+ AC_DEFINE([NO_MKTEMP], [1],
+ [The mktemp() function is not available.])])])
+fi
+AC_SUBST([MEMORYMGR])
+
+# Extract the library version IDs from jpeglib.h.
+AC_MSG_CHECKING([libjpeg version number])
+[major=`sed -ne 's/^#define JPEG_LIB_VERSION_MAJOR *\([0-9][0-9]*\).*$/\1/p' $srcdir/jpeglib.h`
+minor=`sed -ne 's/^#define JPEG_LIB_VERSION_MINOR *\([0-9][0-9]*\).*$/\1/p' $srcdir/jpeglib.h`]
+AC_SUBST([JPEG_LIB_VERSION],
+ [`expr $major + $minor`:0:$minor])
+AC_MSG_RESULT([$JPEG_LIB_VERSION])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/jpg/depcomp b/jpg/depcomp
new file mode 100644
index 0000000..bd0ac08
--- /dev/null
+++ b/jpg/depcomp
@@ -0,0 +1,688 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2011-12-04.11; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
+# 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> "$depfile"
+ echo >> "$depfile"
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add `dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mechanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test "$stat" = 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/ \1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/ /
+ G
+ p
+}' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/jpg/djpeg.1 b/jpg/djpeg.1
new file mode 100644
index 0000000..f3722d1
--- /dev/null
+++ b/jpg/djpeg.1
@@ -0,0 +1,252 @@
+.TH DJPEG 1 "3 October 2009"
+.SH NAME
+djpeg \- decompress a JPEG file to an image file
+.SH SYNOPSIS
+.B djpeg
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B djpeg
+decompresses the named JPEG file, or the standard input if no file is named,
+and produces an image file on the standard output. PBMPLUS (PPM/PGM), BMP,
+GIF, Targa, or RLE (Utah Raster Toolkit) output format can be selected.
+(RLE is supported only if the URT library is available.)
+.SH OPTIONS
+All switch names may be abbreviated; for example,
+.B \-grayscale
+may be written
+.B \-gray
+or
+.BR \-gr .
+Most of the "basic" switches can be abbreviated to as little as one letter.
+Upper and lower case are equivalent (thus
+.B \-BMP
+is the same as
+.BR \-bmp ).
+British spellings are also accepted (e.g.,
+.BR \-greyscale ),
+though for brevity these are not mentioned below.
+.PP
+The basic switches are:
+.TP
+.BI \-colors " N"
+Reduce image to at most N colors. This reduces the number of colors used in
+the output image, so that it can be displayed on a colormapped display or
+stored in a colormapped file format. For example, if you have an 8-bit
+display, you'd need to reduce to 256 or fewer colors.
+.TP
+.BI \-quantize " N"
+Same as
+.BR \-colors .
+.B \-colors
+is the recommended name,
+.B \-quantize
+is provided only for backwards compatibility.
+.TP
+.B \-fast
+Select recommended processing options for fast, low quality output. (The
+default options are chosen for highest quality output.) Currently, this is
+equivalent to \fB\-dct fast \-nosmooth \-onepass \-dither ordered\fR.
+.TP
+.B \-grayscale
+Force gray-scale output even if JPEG file is color. Useful for viewing on
+monochrome displays; also,
+.B djpeg
+runs noticeably faster in this mode.
+.TP
+.BI \-scale " M/N"
+Scale the output image by a factor M/N. Currently supported scale factors are
+M/N with all M from 1 to 16, where N is the source DCT size, which is 8 for
+baseline JPEG. If the /N part is omitted, then M specifies the DCT scaled
+size to be applied on the given input. For baseline JPEG this is equivalent
+to M/8 scaling, since the source DCT size for baseline JPEG is 8.
+Scaling is handy if the image is larger than your screen; also,
+.B djpeg
+runs much faster when scaling down the output.
+.TP
+.B \-bmp
+Select BMP output format (Windows flavor). 8-bit colormapped format is
+emitted if
+.B \-colors
+or
+.B \-grayscale
+is specified, or if the JPEG file is gray-scale; otherwise, 24-bit full-color
+format is emitted.
+.TP
+.B \-gif
+Select GIF output format. Since GIF does not support more than 256 colors,
+.B \-colors 256
+is assumed (unless you specify a smaller number of colors).
+.TP
+.B \-os2
+Select BMP output format (OS/2 1.x flavor). 8-bit colormapped format is
+emitted if
+.B \-colors
+or
+.B \-grayscale
+is specified, or if the JPEG file is gray-scale; otherwise, 24-bit full-color
+format is emitted.
+.TP
+.B \-pnm
+Select PBMPLUS (PPM/PGM) output format (this is the default format).
+PGM is emitted if the JPEG file is gray-scale or if
+.B \-grayscale
+is specified; otherwise PPM is emitted.
+.TP
+.B \-rle
+Select RLE output format. (Requires URT library.)
+.TP
+.B \-targa
+Select Targa output format. Gray-scale format is emitted if the JPEG file is
+gray-scale or if
+.B \-grayscale
+is specified; otherwise, colormapped format is emitted if
+.B \-colors
+is specified; otherwise, 24-bit full-color format is emitted.
+.PP
+Switches for advanced users:
+.TP
+.B \-dct int
+Use integer DCT method (default).
+.TP
+.B \-dct fast
+Use fast integer DCT (less accurate).
+.TP
+.B \-dct float
+Use floating-point DCT method.
+The float method is very slightly more accurate than the int method, but is
+much slower unless your machine has very fast floating-point hardware. Also
+note that results of the floating-point method may vary slightly across
+machines, while the integer methods should give the same results everywhere.
+The fast integer method is much less accurate than the other two.
+.TP
+.B \-dither fs
+Use Floyd-Steinberg dithering in color quantization.
+.TP
+.B \-dither ordered
+Use ordered dithering in color quantization.
+.TP
+.B \-dither none
+Do not use dithering in color quantization.
+By default, Floyd-Steinberg dithering is applied when quantizing colors; this
+is slow but usually produces the best results. Ordered dither is a compromise
+between speed and quality; no dithering is fast but usually looks awful. Note
+that these switches have no effect unless color quantization is being done.
+Ordered dither is only available in
+.B \-onepass
+mode.
+.TP
+.BI \-map " file"
+Quantize to the colors used in the specified image file. This is useful for
+producing multiple files with identical color maps, or for forcing a
+predefined set of colors to be used. The
+.I file
+must be a GIF or PPM file. This option overrides
+.B \-colors
+and
+.BR \-onepass .
+.TP
+.B \-nosmooth
+Don't use high-quality upsampling.
+.TP
+.B \-onepass
+Use one-pass instead of two-pass color quantization. The one-pass method is
+faster and needs less memory, but it produces a lower-quality image.
+.B \-onepass
+is ignored unless you also say
+.B \-colors
+.IR N .
+Also, the one-pass method is always used for gray-scale output (the two-pass
+method is no improvement then).
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images. Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number. For example,
+.B \-max 4m
+selects 4000000 bytes. If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout. More
+.BR \-v 's
+give more output. Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.SH EXAMPLES
+.LP
+This example decompresses the JPEG file foo.jpg, quantizes it to
+256 colors, and saves the output in 8-bit BMP format in foo.bmp:
+.IP
+.B djpeg \-colors 256 \-bmp
+.I foo.jpg
+.B >
+.I foo.bmp
+.SH HINTS
+To get a quick preview of an image, use the
+.B \-grayscale
+and/or
+.B \-scale
+switches.
+.B \-grayscale \-scale 1/8
+is the fastest case.
+.PP
+Several options are available that trade off image quality to gain speed.
+.B \-fast
+turns on the recommended settings.
+.PP
+.B \-dct fast
+and/or
+.B \-nosmooth
+gain speed at a small sacrifice in quality.
+When producing a color-quantized image,
+.B \-onepass \-dither ordered
+is fast but much lower quality than the default behavior.
+.B \-dither none
+may give acceptable results in two-pass mode, but is seldom tolerable in
+one-pass mode.
+.PP
+If you are fortunate enough to have very fast floating point hardware,
+\fB\-dct float\fR may be even faster than \fB\-dct fast\fR. But on most
+machines \fB\-dct float\fR is slower than \fB\-dct int\fR; in this case it is
+not worth using, because its theoretical accuracy advantage is too small to be
+significant in practice.
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR jpegtran (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+.BR ppm (5),
+.BR pgm (5)
+.br
+Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+To avoid the Unisys LZW patent,
+.B djpeg
+produces uncompressed GIF files. These are larger than they should be, but
+are readable by standard GIF decoders.
diff --git a/jpg/djpeg.c b/jpg/djpeg.c
new file mode 100644
index 0000000..bc544dc
--- /dev/null
+++ b/jpg/djpeg.c
@@ -0,0 +1,617 @@
+/*
+ * djpeg.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for the JPEG decompressor.
+ * It should work on any system with Unix- or MS-DOS-style command lines.
+ *
+ * Two different command line styles are permitted, depending on the
+ * compile-time switch TWO_FILE_COMMANDLINE:
+ * djpeg [options] inputfile outputfile
+ * djpeg [options] [inputfile]
+ * In the second style, output is always to standard output, which you'd
+ * normally redirect to a file or pipe to some other program. Input is
+ * either from a named file or from standard input (typically redirected).
+ * The second style is convenient on Unix but is unhelpful on systems that
+ * don't support pipes. Also, you MUST use the first style if your system
+ * doesn't do binary I/O to stdin/stdout.
+ * To simplify script writing, the "-outfile" switch is provided. The syntax
+ * djpeg [options] -outfile outputfile inputfile
+ * works regardless of which command line style is used.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "jversion.h" /* for version message */
+
+#include <ctype.h> /* to declare isprint() */
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+
+/* Create the add-on message string table. */
+
+#define JMESSAGE(code,string) string ,
+
+static const char * const cdjpeg_message_table[] = {
+#include "cderror.h"
+ NULL
+};
+
+
+/*
+ * This list defines the known output image formats
+ * (not all of which need be supported by a given version).
+ * You can change the default output format by defining DEFAULT_FMT;
+ * indeed, you had better do so if you undefine PPM_SUPPORTED.
+ */
+
+typedef enum {
+ FMT_BMP, /* BMP format (Windows flavor) */
+ FMT_GIF, /* GIF format */
+ FMT_OS2, /* BMP format (OS/2 flavor) */
+ FMT_PPM, /* PPM/PGM (PBMPLUS formats) */
+ FMT_RLE, /* RLE format */
+ FMT_TARGA, /* Targa format */
+ FMT_TIFF /* TIFF format */
+} IMAGE_FORMATS;
+
+#ifndef DEFAULT_FMT /* so can override from CFLAGS in Makefile */
+#define DEFAULT_FMT FMT_PPM
+#endif
+
+static IMAGE_FORMATS requested_fmt;
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname; /* program name for error messages */
+static char * outfilename; /* for -outfile switch */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "inputfile outputfile\n");
+#else
+ fprintf(stderr, "[inputfile]\n");
+#endif
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -colors N Reduce image to no more than N colors\n");
+ fprintf(stderr, " -fast Fast, low-quality processing\n");
+ fprintf(stderr, " -grayscale Force grayscale output\n");
+#ifdef IDCT_SCALING_SUPPORTED
+ fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n");
+#endif
+#ifdef BMP_SUPPORTED
+ fprintf(stderr, " -bmp Select BMP output format (Windows style)%s\n",
+ (DEFAULT_FMT == FMT_BMP ? " (default)" : ""));
+#endif
+#ifdef GIF_SUPPORTED
+ fprintf(stderr, " -gif Select GIF output format%s\n",
+ (DEFAULT_FMT == FMT_GIF ? " (default)" : ""));
+#endif
+#ifdef BMP_SUPPORTED
+ fprintf(stderr, " -os2 Select BMP output format (OS/2 style)%s\n",
+ (DEFAULT_FMT == FMT_OS2 ? " (default)" : ""));
+#endif
+#ifdef PPM_SUPPORTED
+ fprintf(stderr, " -pnm Select PBMPLUS (PPM/PGM) output format%s\n",
+ (DEFAULT_FMT == FMT_PPM ? " (default)" : ""));
+#endif
+#ifdef RLE_SUPPORTED
+ fprintf(stderr, " -rle Select Utah RLE output format%s\n",
+ (DEFAULT_FMT == FMT_RLE ? " (default)" : ""));
+#endif
+#ifdef TARGA_SUPPORTED
+ fprintf(stderr, " -targa Select Targa output format%s\n",
+ (DEFAULT_FMT == FMT_TARGA ? " (default)" : ""));
+#endif
+ fprintf(stderr, "Switches for advanced users:\n");
+#ifdef DCT_ISLOW_SUPPORTED
+ fprintf(stderr, " -dct int Use integer DCT method%s\n",
+ (JDCT_DEFAULT == JDCT_ISLOW ? " (default)" : ""));
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ fprintf(stderr, " -dct fast Use fast integer DCT (less accurate)%s\n",
+ (JDCT_DEFAULT == JDCT_IFAST ? " (default)" : ""));
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ fprintf(stderr, " -dct float Use floating-point DCT method%s\n",
+ (JDCT_DEFAULT == JDCT_FLOAT ? " (default)" : ""));
+#endif
+ fprintf(stderr, " -dither fs Use F-S dithering (default)\n");
+ fprintf(stderr, " -dither none Don't use dithering in quantization\n");
+ fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n");
+#ifdef QUANT_2PASS_SUPPORTED
+ fprintf(stderr, " -map FILE Map to colors used in named image file\n");
+#endif
+ fprintf(stderr, " -nosmooth Don't use high-quality upsampling\n");
+#ifdef QUANT_1PASS_SUPPORTED
+ fprintf(stderr, " -onepass Use 1-pass quantization (fast, low quality)\n");
+#endif
+ fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
+ fprintf(stderr, " -outfile name Specify name for output file\n");
+ fprintf(stderr, " -verbose or -debug Emit debug output\n");
+ exit(EXIT_FAILURE);
+}
+
+
+LOCAL(int)
+parse_switches (j_decompress_ptr cinfo, int argc, char **argv,
+ int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+ int argn;
+ char * arg;
+
+ /* Set up default JPEG parameters. */
+ requested_fmt = DEFAULT_FMT; /* set default output file format */
+ outfilename = NULL;
+ cinfo->err->trace_level = 0;
+
+ /* Scan command line options, adjust parameters */
+
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (*arg != '-') {
+ /* Not a switch, must be a file name argument */
+ if (argn <= last_file_arg_seen) {
+ outfilename = NULL; /* -outfile applies to just one input file */
+ continue; /* ignore this name if previously processed */
+ }
+ break; /* else done parsing switches */
+ }
+ arg++; /* advance past switch marker character */
+
+ if (keymatch(arg, "bmp", 1)) {
+ /* BMP output format. */
+ requested_fmt = FMT_BMP;
+
+ } else if (keymatch(arg, "colors", 1) || keymatch(arg, "colours", 1) ||
+ keymatch(arg, "quantize", 1) || keymatch(arg, "quantise", 1)) {
+ /* Do color quantization. */
+ int val;
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d", &val) != 1)
+ usage();
+ cinfo->desired_number_of_colors = val;
+ cinfo->quantize_colors = TRUE;
+
+ } else if (keymatch(arg, "dct", 2)) {
+ /* Select IDCT algorithm. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "int", 1)) {
+ cinfo->dct_method = JDCT_ISLOW;
+ } else if (keymatch(argv[argn], "fast", 2)) {
+ cinfo->dct_method = JDCT_IFAST;
+ } else if (keymatch(argv[argn], "float", 2)) {
+ cinfo->dct_method = JDCT_FLOAT;
+ } else
+ usage();
+
+ } else if (keymatch(arg, "dither", 2)) {
+ /* Select dithering algorithm. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "fs", 2)) {
+ cinfo->dither_mode = JDITHER_FS;
+ } else if (keymatch(argv[argn], "none", 2)) {
+ cinfo->dither_mode = JDITHER_NONE;
+ } else if (keymatch(argv[argn], "ordered", 2)) {
+ cinfo->dither_mode = JDITHER_ORDERED;
+ } else
+ usage();
+
+ } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+ /* Enable debug printouts. */
+ /* On first -d, print version identification */
+ static boolean printed_version = FALSE;
+
+ if (! printed_version) {
+ fprintf(stderr, "Independent JPEG Group's DJPEG, version %s\n%s\n",
+ JVERSION, JCOPYRIGHT);
+ printed_version = TRUE;
+ }
+ cinfo->err->trace_level++;
+
+ } else if (keymatch(arg, "fast", 1)) {
+ /* Select recommended processing options for quick-and-dirty output. */
+ cinfo->two_pass_quantize = FALSE;
+ cinfo->dither_mode = JDITHER_ORDERED;
+ if (! cinfo->quantize_colors) /* don't override an earlier -colors */
+ cinfo->desired_number_of_colors = 216;
+ cinfo->dct_method = JDCT_FASTEST;
+ cinfo->do_fancy_upsampling = FALSE;
+
+ } else if (keymatch(arg, "gif", 1)) {
+ /* GIF output format. */
+ requested_fmt = FMT_GIF;
+
+ } else if (keymatch(arg, "grayscale", 2) || keymatch(arg, "greyscale",2)) {
+ /* Force monochrome output. */
+ cinfo->out_color_space = JCS_GRAYSCALE;
+
+ } else if (keymatch(arg, "map", 3)) {
+ /* Quantize to a color map taken from an input file. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (for_real) { /* too expensive to do twice! */
+#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
+ FILE * mapfile;
+
+ if ((mapfile = fopen(argv[argn], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+ read_color_map(cinfo, mapfile);
+ fclose(mapfile);
+ cinfo->quantize_colors = TRUE;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+
+ } else if (keymatch(arg, "maxmemory", 3)) {
+ /* Maximum memory in Kb (or Mb with 'm'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (ch == 'm' || ch == 'M')
+ lval *= 1000L;
+ cinfo->mem->max_memory_to_use = lval * 1000L;
+
+ } else if (keymatch(arg, "nosmooth", 3)) {
+ /* Suppress fancy upsampling */
+ cinfo->do_fancy_upsampling = FALSE;
+
+ } else if (keymatch(arg, "onepass", 3)) {
+ /* Use fast one-pass quantization. */
+ cinfo->two_pass_quantize = FALSE;
+
+ } else if (keymatch(arg, "os2", 3)) {
+ /* BMP output format (OS/2 flavor). */
+ requested_fmt = FMT_OS2;
+
+ } else if (keymatch(arg, "outfile", 4)) {
+ /* Set output file name. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ outfilename = argv[argn]; /* save it away for later use */
+
+ } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
+ /* PPM/PGM output format. */
+ requested_fmt = FMT_PPM;
+
+ } else if (keymatch(arg, "rle", 1)) {
+ /* RLE output format. */
+ requested_fmt = FMT_RLE;
+
+ } else if (keymatch(arg, "scale", 1)) {
+ /* Scale the output image by a fraction M/N. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%d/%d",
+ &cinfo->scale_num, &cinfo->scale_denom) < 1)
+ usage();
+
+ } else if (keymatch(arg, "targa", 1)) {
+ /* Targa output format. */
+ requested_fmt = FMT_TARGA;
+
+ } else {
+ usage(); /* bogus switch */
+ }
+ }
+
+ return argn; /* return index of next arg (file name) */
+}
+
+
+/*
+ * Marker processor for COM and interesting APPn markers.
+ * This replaces the library's built-in processor, which just skips the marker.
+ * We want to print out the marker as text, to the extent possible.
+ * Note this code relies on a non-suspending data source.
+ */
+
+LOCAL(unsigned int)
+jpeg_getc (j_decompress_ptr cinfo)
+/* Read next byte */
+{
+ struct jpeg_source_mgr * datasrc = cinfo->src;
+
+ if (datasrc->bytes_in_buffer == 0) {
+ if (! (*datasrc->fill_input_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
+ datasrc->bytes_in_buffer--;
+ return GETJOCTET(*datasrc->next_input_byte++);
+}
+
+
+METHODDEF(boolean)
+print_text_marker (j_decompress_ptr cinfo)
+{
+ boolean traceit = (cinfo->err->trace_level >= 1);
+ INT32 length;
+ unsigned int ch;
+ unsigned int lastch = 0;
+
+ length = jpeg_getc(cinfo) << 8;
+ length += jpeg_getc(cinfo);
+ length -= 2; /* discount the length word itself */
+
+ if (traceit) {
+ if (cinfo->unread_marker == JPEG_COM)
+ fprintf(stderr, "Comment, length %ld:\n", (long) length);
+ else /* assume it is an APPn otherwise */
+ fprintf(stderr, "APP%d, length %ld:\n",
+ cinfo->unread_marker - JPEG_APP0, (long) length);
+ }
+
+ while (--length >= 0) {
+ ch = jpeg_getc(cinfo);
+ if (traceit) {
+ /* Emit the character in a readable form.
+ * Nonprintables are converted to \nnn form,
+ * while \ is converted to \\.
+ * Newlines in CR, CR/LF, or LF form will be printed as one newline.
+ */
+ if (ch == '\r') {
+ fprintf(stderr, "\n");
+ } else if (ch == '\n') {
+ if (lastch != '\r')
+ fprintf(stderr, "\n");
+ } else if (ch == '\\') {
+ fprintf(stderr, "\\\\");
+ } else if (isprint(ch)) {
+ putc(ch, stderr);
+ } else {
+ fprintf(stderr, "\\%03o", ch);
+ }
+ lastch = ch;
+ }
+ }
+
+ if (traceit)
+ fprintf(stderr, "\n");
+
+ return TRUE;
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+#ifdef PROGRESS_REPORT
+ struct cdjpeg_progress_mgr progress;
+#endif
+ int file_index;
+ djpeg_dest_ptr dest_mgr = NULL;
+ FILE * input_file;
+ FILE * output_file;
+ JDIMENSION num_scanlines;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "djpeg"; /* in case C library doesn't provide it */
+
+ /* Initialize the JPEG decompression object with default error handling. */
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+ /* Add some application-specific error messages (from cderror.h) */
+ jerr.addon_message_table = cdjpeg_message_table;
+ jerr.first_addon_message = JMSG_FIRSTADDONCODE;
+ jerr.last_addon_message = JMSG_LASTADDONCODE;
+
+ /* Insert custom marker processor for COM and APP12.
+ * APP12 is used by some digital camera makers for textual info,
+ * so we provide the ability to display it as text.
+ * If you like, additional APPn marker types can be selected for display,
+ * but don't try to override APP0 or APP14 this way (see libjpeg.doc).
+ */
+ jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker);
+ jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker);
+
+ /* Now safe to enable signal catcher. */
+#ifdef NEED_SIGNAL_CATCHER
+ enable_signal_catcher((j_common_ptr) &cinfo);
+#endif
+
+ /* Scan command line to find file names. */
+ /* It is convenient to use just one switch-parsing routine, but the switch
+ * values read here are ignored; we will rescan the switches after opening
+ * the input file.
+ * (Exception: tracing level set here controls verbosity for COM markers
+ * found during jpeg_read_header...)
+ */
+
+ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE);
+
+#ifdef TWO_FILE_COMMANDLINE
+ /* Must have either -outfile switch or explicit output file name */
+ if (outfilename == NULL) {
+ if (file_index != argc-2) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ outfilename = argv[file_index+1];
+ } else {
+ if (file_index != argc-1) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ }
+#else
+ /* Unix style: expect zero or one file name */
+ if (file_index < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+#endif /* TWO_FILE_COMMANDLINE */
+
+ /* Open the input file. */
+ if (file_index < argc) {
+ if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+ input_file = read_stdin();
+ }
+
+ /* Open the output file. */
+ if (outfilename != NULL) {
+ if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default output file is stdout */
+ output_file = write_stdout();
+ }
+
+#ifdef PROGRESS_REPORT
+ start_progress_monitor((j_common_ptr) &cinfo, &progress);
+#endif
+
+ /* Specify data source for decompression */
+ jpeg_stdio_src(&cinfo, input_file);
+
+ /* Read file header, set default decompression parameters */
+ (void) jpeg_read_header(&cinfo, TRUE);
+
+ /* Adjust default decompression parameters by re-parsing the options */
+ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE);
+
+ /* Initialize the output module now to let it override any crucial
+ * option settings (for instance, GIF wants to force color quantization).
+ */
+ switch (requested_fmt) {
+#ifdef BMP_SUPPORTED
+ case FMT_BMP:
+ dest_mgr = jinit_write_bmp(&cinfo, FALSE);
+ break;
+ case FMT_OS2:
+ dest_mgr = jinit_write_bmp(&cinfo, TRUE);
+ break;
+#endif
+#ifdef GIF_SUPPORTED
+ case FMT_GIF:
+ dest_mgr = jinit_write_gif(&cinfo);
+ break;
+#endif
+#ifdef PPM_SUPPORTED
+ case FMT_PPM:
+ dest_mgr = jinit_write_ppm(&cinfo);
+ break;
+#endif
+#ifdef RLE_SUPPORTED
+ case FMT_RLE:
+ dest_mgr = jinit_write_rle(&cinfo);
+ break;
+#endif
+#ifdef TARGA_SUPPORTED
+ case FMT_TARGA:
+ dest_mgr = jinit_write_targa(&cinfo);
+ break;
+#endif
+ default:
+ ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT);
+ break;
+ }
+ dest_mgr->output_file = output_file;
+
+ /* Start decompressor */
+ (void) jpeg_start_decompress(&cinfo);
+
+ /* Write output file header */
+ (*dest_mgr->start_output) (&cinfo, dest_mgr);
+
+ /* Process data */
+ while (cinfo.output_scanline < cinfo.output_height) {
+ num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer,
+ dest_mgr->buffer_height);
+ (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
+ }
+
+#ifdef PROGRESS_REPORT
+ /* Hack: count final pass as done in case finish_output does an extra pass.
+ * The library won't have updated completed_passes.
+ */
+ progress.pub.completed_passes = progress.pub.total_passes;
+#endif
+
+ /* Finish decompression and release memory.
+ * I must do it in this order because output module has allocated memory
+ * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory.
+ */
+ (*dest_mgr->finish_output) (&cinfo, dest_mgr);
+ (void) jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ /* Close files, if we opened them */
+ if (input_file != stdin)
+ fclose(input_file);
+ if (output_file != stdout)
+ fclose(output_file);
+
+#ifdef PROGRESS_REPORT
+ end_progress_monitor((j_common_ptr) &cinfo);
+#endif
+
+ /* All done. */
+ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/jpg/example.c b/jpg/example.c
new file mode 100644
index 0000000..1d6f6cc
--- /dev/null
+++ b/jpg/example.c
@@ -0,0 +1,433 @@
+/*
+ * example.c
+ *
+ * This file illustrates how to use the IJG code as a subroutine library
+ * to read or write JPEG image files. You should look at this code in
+ * conjunction with the documentation file libjpeg.txt.
+ *
+ * This code will not do anything useful as-is, but it may be helpful as a
+ * skeleton for constructing routines that call the JPEG library.
+ *
+ * We present these routines in the same coding style used in the JPEG code
+ * (ANSI function definitions, etc); but you are of course free to code your
+ * routines in a different style if you prefer.
+ */
+
+#include <stdio.h>
+
+/*
+ * Include file for users of JPEG library.
+ * You will need to have included system headers that define at least
+ * the typedefs FILE and size_t before you can include jpeglib.h.
+ * (stdio.h is sufficient on ANSI-conforming systems.)
+ * You may also wish to include "jerror.h".
+ */
+
+#include "jpeglib.h"
+
+/*
+ * <setjmp.h> is used for the optional error recovery mechanism shown in
+ * the second part of the example.
+ */
+
+#include <setjmp.h>
+
+
+
+/******************** JPEG COMPRESSION SAMPLE INTERFACE *******************/
+
+/* This half of the example shows how to feed data into the JPEG compressor.
+ * We present a minimal version that does not worry about refinements such
+ * as error recovery (the JPEG code will just exit() if it gets an error).
+ */
+
+
+/*
+ * IMAGE DATA FORMATS:
+ *
+ * The standard input image format is a rectangular array of pixels, with
+ * each pixel having the same number of "component" values (color channels).
+ * Each pixel row is an array of JSAMPLEs (which typically are unsigned chars).
+ * If you are working with color data, then the color values for each pixel
+ * must be adjacent in the row; for example, R,G,B,R,G,B,R,G,B,... for 24-bit
+ * RGB color.
+ *
+ * For this example, we'll assume that this data structure matches the way
+ * our application has stored the image in memory, so we can just pass a
+ * pointer to our image buffer. In particular, let's say that the image is
+ * RGB color and is described by:
+ */
+
+extern JSAMPLE * image_buffer; /* Points to large array of R,G,B-order data */
+extern int image_height; /* Number of rows in image */
+extern int image_width; /* Number of columns in image */
+
+
+/*
+ * Sample routine for JPEG compression. We assume that the target file name
+ * and a compression quality factor are passed in.
+ */
+
+GLOBAL(void)
+write_JPEG_file (char * filename, int quality)
+{
+ /* This struct contains the JPEG compression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ * It is possible to have several such structures, representing multiple
+ * compression/decompression processes, in existence at once. We refer
+ * to any one struct (and its associated working data) as a "JPEG object".
+ */
+ struct jpeg_compress_struct cinfo;
+ /* This struct represents a JPEG error handler. It is declared separately
+ * because applications often want to supply a specialized error handler
+ * (see the second half of this file for an example). But here we just
+ * take the easy way out and use the standard error handler, which will
+ * print a message on stderr and call exit() if compression fails.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ struct jpeg_error_mgr jerr;
+ /* More stuff */
+ FILE * outfile; /* target file */
+ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
+ int row_stride; /* physical row width in image buffer */
+
+ /* Step 1: allocate and initialize JPEG compression object */
+
+ /* We have to set up the error handler first, in case the initialization
+ * step fails. (Unlikely, but it could happen if you are out of memory.)
+ * This routine fills in the contents of struct jerr, and returns jerr's
+ * address which we place into the link field in cinfo.
+ */
+ cinfo.err = jpeg_std_error(&jerr);
+ /* Now we can initialize the JPEG compression object. */
+ jpeg_create_compress(&cinfo);
+
+ /* Step 2: specify data destination (eg, a file) */
+ /* Note: steps 2 and 3 can be done in either order. */
+
+ /* Here we use the library-supplied code to send compressed data to a
+ * stdio stream. You can also write your own code to do something else.
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+ * requires it in order to write binary files.
+ */
+ if ((outfile = fopen(filename, "wb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ exit(1);
+ }
+ jpeg_stdio_dest(&cinfo, outfile);
+
+ /* Step 3: set parameters for compression */
+
+ /* First we supply a description of the input image.
+ * Four fields of the cinfo struct must be filled in:
+ */
+ cinfo.image_width = image_width; /* image width and height, in pixels */
+ cinfo.image_height = image_height;
+ cinfo.input_components = 3; /* # of color components per pixel */
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+ /* Now use the library's routine to set default compression parameters.
+ * (You must set at least cinfo.in_color_space before calling this,
+ * since the defaults depend on the source color space.)
+ */
+ jpeg_set_defaults(&cinfo);
+ /* Now you can set any non-default parameters you wish to.
+ * Here we just illustrate the use of quality (quantization table) scaling:
+ */
+ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
+
+ /* Step 4: Start compressor */
+
+ /* TRUE ensures that we will write a complete interchange-JPEG file.
+ * Pass TRUE unless you are very sure of what you're doing.
+ */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Step 5: while (scan lines remain to be written) */
+ /* jpeg_write_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo.next_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ * To keep things simple, we pass one scanline per call; you can pass
+ * more if you wish, though.
+ */
+ row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ /* jpeg_write_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could pass
+ * more than one scanline at a time if that's more convenient.
+ */
+ row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+ (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+ /* Step 6: Finish compression */
+
+ jpeg_finish_compress(&cinfo);
+ /* After finish_compress, we can close the output file. */
+ fclose(outfile);
+
+ /* Step 7: release JPEG compression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_compress(&cinfo);
+
+ /* And we're done! */
+}
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above loop, we ignored the return value of jpeg_write_scanlines,
+ * which is the number of scanlines actually written. We could get away
+ * with this because we were only relying on the value of cinfo.next_scanline,
+ * which will be incremented correctly. If you maintain additional loop
+ * variables then you should be careful to increment them properly.
+ * Actually, for output to a stdio stream you needn't worry, because
+ * then jpeg_write_scanlines will write all the lines passed (or else exit
+ * with a fatal error). Partial writes can only occur if you use a data
+ * destination module that can demand suspension of the compressor.
+ * (If you don't know what that's for, you don't need it.)
+ *
+ * If the compressor requires full-image buffers (for entropy-coding
+ * optimization or a multi-scan JPEG file), it will create temporary
+ * files for anything that doesn't fit within the maximum-memory setting.
+ * (Note that temp files are NOT needed if you use the default parameters.)
+ * On some systems you may need to set up a signal handler to ensure that
+ * temporary files are deleted if the program is interrupted. See libjpeg.txt.
+ *
+ * Scanlines MUST be supplied in top-to-bottom order if you want your JPEG
+ * files to be compatible with everyone else's. If you cannot readily read
+ * your data in that order, you'll need an intermediate array to hold the
+ * image. See rdtarga.c or rdbmp.c for examples of handling bottom-to-top
+ * source data using the JPEG code's internal virtual-array mechanisms.
+ */
+
+
+
+/******************** JPEG DECOMPRESSION SAMPLE INTERFACE *******************/
+
+/* This half of the example shows how to read data from the JPEG decompressor.
+ * It's a bit more refined than the above, in that we show:
+ * (a) how to modify the JPEG library's standard error-reporting behavior;
+ * (b) how to allocate workspace using the library's memory manager.
+ *
+ * Just to make this example a little different from the first one, we'll
+ * assume that we do not intend to put the whole image into an in-memory
+ * buffer, but to send it line-by-line someplace else. We need a one-
+ * scanline-high JSAMPLE array as a work buffer, and we will let the JPEG
+ * memory manager allocate it for us. This approach is actually quite useful
+ * because we don't need to remember to deallocate the buffer separately: it
+ * will go away automatically when the JPEG object is cleaned up.
+ */
+
+
+/*
+ * ERROR HANDLING:
+ *
+ * The JPEG library's standard error handler (jerror.c) is divided into
+ * several "methods" which you can override individually. This lets you
+ * adjust the behavior without duplicating a lot of code, which you might
+ * have to update with each future release.
+ *
+ * Our example here shows how to override the "error_exit" method so that
+ * control is returned to the library's caller when a fatal error occurs,
+ * rather than calling exit() as the standard error_exit method does.
+ *
+ * We use C's setjmp/longjmp facility to return control. This means that the
+ * routine which calls the JPEG library must first execute a setjmp() call to
+ * establish the return point. We want the replacement error_exit to do a
+ * longjmp(). But we need to make the setjmp buffer accessible to the
+ * error_exit routine. To do this, we make a private extension of the
+ * standard JPEG error handler object. (If we were using C++, we'd say we
+ * were making a subclass of the regular error handler.)
+ *
+ * Here's the extended error handler struct:
+ */
+
+struct my_error_mgr {
+ struct jpeg_error_mgr pub; /* "public" fields */
+
+ jmp_buf setjmp_buffer; /* for return to caller */
+};
+
+typedef struct my_error_mgr * my_error_ptr;
+
+/*
+ * Here's the routine that will replace the standard error_exit method:
+ */
+
+METHODDEF(void)
+my_error_exit (j_common_ptr cinfo)
+{
+ /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
+ my_error_ptr myerr = (my_error_ptr) cinfo->err;
+
+ /* Always display the message. */
+ /* We could postpone this until after returning, if we chose. */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Return control to the setjmp point */
+ longjmp(myerr->setjmp_buffer, 1);
+}
+
+
+/*
+ * Sample routine for JPEG decompression. We assume that the source file name
+ * is passed in. We want to return 1 on success, 0 on error.
+ */
+
+
+GLOBAL(int)
+read_JPEG_file (char * filename)
+{
+ /* This struct contains the JPEG decompression parameters and pointers to
+ * working space (which is allocated as needed by the JPEG library).
+ */
+ struct jpeg_decompress_struct cinfo;
+ /* We use our private extension JPEG error handler.
+ * Note that this struct must live as long as the main JPEG parameter
+ * struct, to avoid dangling-pointer problems.
+ */
+ struct my_error_mgr jerr;
+ /* More stuff */
+ FILE * infile; /* source file */
+ JSAMPARRAY buffer; /* Output row buffer */
+ int row_stride; /* physical row width in output buffer */
+
+ /* In this example we want to open the input file before doing anything else,
+ * so that the setjmp() error recovery below can assume the file is open.
+ * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
+ * requires it in order to read binary files.
+ */
+
+ if ((infile = fopen(filename, "rb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ return 0;
+ }
+
+ /* Step 1: allocate and initialize JPEG decompression object */
+
+ /* We set up the normal JPEG error routines, then override error_exit. */
+ cinfo.err = jpeg_std_error(&jerr.pub);
+ jerr.pub.error_exit = my_error_exit;
+ /* Establish the setjmp return context for my_error_exit to use. */
+ if (setjmp(jerr.setjmp_buffer)) {
+ /* If we get here, the JPEG code has signaled an error.
+ * We need to clean up the JPEG object, close the input file, and return.
+ */
+ jpeg_destroy_decompress(&cinfo);
+ fclose(infile);
+ return 0;
+ }
+ /* Now we can initialize the JPEG decompression object. */
+ jpeg_create_decompress(&cinfo);
+
+ /* Step 2: specify data source (eg, a file) */
+
+ jpeg_stdio_src(&cinfo, infile);
+
+ /* Step 3: read file parameters with jpeg_read_header() */
+
+ (void) jpeg_read_header(&cinfo, TRUE);
+ /* We can ignore the return value from jpeg_read_header since
+ * (a) suspension is not possible with the stdio data source, and
+ * (b) we passed TRUE to reject a tables-only JPEG file as an error.
+ * See libjpeg.txt for more info.
+ */
+
+ /* Step 4: set parameters for decompression */
+
+ /* In this example, we don't need to change any of the defaults set by
+ * jpeg_read_header(), so we do nothing here.
+ */
+
+ /* Step 5: Start decompressor */
+
+ (void) jpeg_start_decompress(&cinfo);
+ /* We can ignore the return value since suspension is not possible
+ * with the stdio data source.
+ */
+
+ /* We may need to do some setup of our own at this point before reading
+ * the data. After jpeg_start_decompress() we have the correct scaled
+ * output image dimensions available, as well as the output colormap
+ * if we asked for color quantization.
+ * In this example, we need to make an output work buffer of the right size.
+ */
+ /* JSAMPLEs per row in output buffer */
+ row_stride = cinfo.output_width * cinfo.output_components;
+ /* Make a one-row-high sample array that will go away when done with image */
+ buffer = (*cinfo.mem->alloc_sarray)
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+
+ /* Step 6: while (scan lines remain to be read) */
+ /* jpeg_read_scanlines(...); */
+
+ /* Here we use the library's state variable cinfo.output_scanline as the
+ * loop counter, so that we don't have to keep track ourselves.
+ */
+ while (cinfo.output_scanline < cinfo.output_height) {
+ /* jpeg_read_scanlines expects an array of pointers to scanlines.
+ * Here the array is only one element long, but you could ask for
+ * more than one scanline at a time if that's more convenient.
+ */
+ (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+ /* Assume put_scanline_someplace wants a pointer and sample count. */
+ put_scanline_someplace(buffer[0], row_stride);
+ }
+
+ /* Step 7: Finish decompression */
+
+ (void) jpeg_finish_decompress(&cinfo);
+ /* We can ignore the return value since suspension is not possible
+ * with the stdio data source.
+ */
+
+ /* Step 8: Release JPEG decompression object */
+
+ /* This is an important step since it will release a good deal of memory. */
+ jpeg_destroy_decompress(&cinfo);
+
+ /* After finish_decompress, we can close the input file.
+ * Here we postpone it until after no more JPEG errors are possible,
+ * so as to simplify the setjmp error logic above. (Actually, I don't
+ * think that jpeg_destroy can do an error exit, but why assume anything...)
+ */
+ fclose(infile);
+
+ /* At this point you may want to check to see whether any corrupt-data
+ * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
+ */
+
+ /* And we're done! */
+ return 1;
+}
+
+
+/*
+ * SOME FINE POINTS:
+ *
+ * In the above code, we ignored the return value of jpeg_read_scanlines,
+ * which is the number of scanlines actually read. We could get away with
+ * this because we asked for only one line at a time and we weren't using
+ * a suspending data source. See libjpeg.txt for more info.
+ *
+ * We cheated a bit by calling alloc_sarray() after jpeg_start_decompress();
+ * we should have done it beforehand to ensure that the space would be
+ * counted against the JPEG max_memory setting. In some systems the above
+ * code would risk an out-of-memory error. However, in general we don't
+ * know the output image dimensions before jpeg_start_decompress(), unless we
+ * call jpeg_calc_output_dimensions(). See libjpeg.txt for more about this.
+ *
+ * Scanlines are returned in the same order as they appear in the JPEG file,
+ * which is standardly top-to-bottom. If you must emit data bottom-to-top,
+ * you can use one of the virtual arrays provided by the JPEG memory manager
+ * to invert the data. See wrbmp.c for an example.
+ *
+ * As with compression, some operating modes may require temporary files.
+ * On some systems you may need to set up a signal handler to ensure that
+ * temporary files are deleted if the program is interrupted. See libjpeg.txt.
+ */
diff --git a/jpg/filelist.txt b/jpg/filelist.txt
new file mode 100644
index 0000000..7e05386
--- /dev/null
+++ b/jpg/filelist.txt
@@ -0,0 +1,215 @@
+IJG JPEG LIBRARY: FILE LIST
+
+Copyright (C) 1994-2009, Thomas G. Lane, Guido Vollbeding.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+Here is a road map to the files in the IJG JPEG distribution. The
+distribution includes the JPEG library proper, plus two application
+programs ("cjpeg" and "djpeg") which use the library to convert JPEG
+files to and from some other popular image formats. A third application
+"jpegtran" uses the library to do lossless conversion between different
+variants of JPEG. There are also two stand-alone applications,
+"rdjpgcom" and "wrjpgcom".
+
+
+THE JPEG LIBRARY
+================
+
+Include files:
+
+jpeglib.h JPEG library's exported data and function declarations.
+jconfig.h Configuration declarations. Note: this file is not present
+ in the distribution; it is generated during installation.
+jmorecfg.h Additional configuration declarations; need not be changed
+ for a standard installation.
+jerror.h Declares JPEG library's error and trace message codes.
+jinclude.h Central include file used by all IJG .c files to reference
+ system include files.
+jpegint.h JPEG library's internal data structures.
+jdct.h Private declarations for forward & reverse DCT subsystems.
+jmemsys.h Private declarations for memory management subsystem.
+jversion.h Version information.
+
+Applications using the library should include jpeglib.h (which in turn
+includes jconfig.h and jmorecfg.h). Optionally, jerror.h may be included
+if the application needs to reference individual JPEG error codes. The
+other include files are intended for internal use and would not normally
+be included by an application program. (cjpeg/djpeg/etc do use jinclude.h,
+since its function is to improve portability of the whole IJG distribution.
+Most other applications will directly include the system include files they
+want, and hence won't need jinclude.h.)
+
+
+C source code files:
+
+These files contain most of the functions intended to be called directly by
+an application program:
+
+jcapimin.c Application program interface: core routines for compression.
+jcapistd.c Application program interface: standard compression.
+jdapimin.c Application program interface: core routines for decompression.
+jdapistd.c Application program interface: standard decompression.
+jcomapi.c Application program interface routines common to compression
+ and decompression.
+jcparam.c Compression parameter setting helper routines.
+jctrans.c API and library routines for transcoding compression.
+jdtrans.c API and library routines for transcoding decompression.
+
+Compression side of the library:
+
+jcinit.c Initialization: determines which other modules to use.
+jcmaster.c Master control: setup and inter-pass sequencing logic.
+jcmainct.c Main buffer controller (preprocessor => JPEG compressor).
+jcprepct.c Preprocessor buffer controller.
+jccoefct.c Buffer controller for DCT coefficient buffer.
+jccolor.c Color space conversion.
+jcsample.c Downsampling.
+jcdctmgr.c DCT manager (DCT implementation selection & control).
+jfdctint.c Forward DCT using slow-but-accurate integer method.
+jfdctfst.c Forward DCT using faster, less accurate integer method.
+jfdctflt.c Forward DCT using floating-point arithmetic.
+jchuff.c Huffman entropy coding.
+jcarith.c Arithmetic entropy coding.
+jcmarker.c JPEG marker writing.
+jdatadst.c Data destination managers for memory and stdio output.
+
+Decompression side of the library:
+
+jdmaster.c Master control: determines which other modules to use.
+jdinput.c Input controller: controls input processing modules.
+jdmainct.c Main buffer controller (JPEG decompressor => postprocessor).
+jdcoefct.c Buffer controller for DCT coefficient buffer.
+jdpostct.c Postprocessor buffer controller.
+jdmarker.c JPEG marker reading.
+jdhuff.c Huffman entropy decoding.
+jdarith.c Arithmetic entropy decoding.
+jddctmgr.c IDCT manager (IDCT implementation selection & control).
+jidctint.c Inverse DCT using slow-but-accurate integer method.
+jidctfst.c Inverse DCT using faster, less accurate integer method.
+jidctflt.c Inverse DCT using floating-point arithmetic.
+jdsample.c Upsampling.
+jdcolor.c Color space conversion.
+jdmerge.c Merged upsampling/color conversion (faster, lower quality).
+jquant1.c One-pass color quantization using a fixed-spacing colormap.
+jquant2.c Two-pass color quantization using a custom-generated colormap.
+ Also handles one-pass quantization to an externally given map.
+jdatasrc.c Data source managers for memory and stdio input.
+
+Support files for both compression and decompression:
+
+jaricom.c Tables for common use in arithmetic entropy encoding and
+ decoding routines.
+jerror.c Standard error handling routines (application replaceable).
+jmemmgr.c System-independent (more or less) memory management code.
+jutils.c Miscellaneous utility routines.
+
+jmemmgr.c relies on a system-dependent memory management module. The IJG
+distribution includes the following implementations of the system-dependent
+module:
+
+jmemnobs.c "No backing store": assumes adequate virtual memory exists.
+jmemansi.c Makes temporary files with ANSI-standard routine tmpfile().
+jmemname.c Makes temporary files with program-generated file names.
+jmemdos.c Custom implementation for MS-DOS (16-bit environment only):
+ can use extended and expanded memory as well as temp files.
+jmemmac.c Custom implementation for Apple Macintosh.
+
+Exactly one of the system-dependent modules should be configured into an
+installed JPEG library (see install.txt for hints about which one to use).
+On unusual systems you may find it worthwhile to make a special
+system-dependent memory manager.
+
+
+Non-C source code files:
+
+jmemdosa.asm 80x86 assembly code support for jmemdos.c; used only in
+ MS-DOS-specific configurations of the JPEG library.
+
+
+CJPEG/DJPEG/JPEGTRAN
+====================
+
+Include files:
+
+cdjpeg.h Declarations shared by cjpeg/djpeg/jpegtran modules.
+cderror.h Additional error and trace message codes for cjpeg et al.
+transupp.h Declarations for jpegtran support routines in transupp.c.
+
+C source code files:
+
+cjpeg.c Main program for cjpeg.
+djpeg.c Main program for djpeg.
+jpegtran.c Main program for jpegtran.
+cdjpeg.c Utility routines used by all three programs.
+rdcolmap.c Code to read a colormap file for djpeg's "-map" switch.
+rdswitch.c Code to process some of cjpeg's more complex switches.
+ Also used by jpegtran.
+transupp.c Support code for jpegtran: lossless image manipulations.
+
+Image file reader modules for cjpeg:
+
+rdbmp.c BMP file input.
+rdgif.c GIF file input (now just a stub).
+rdppm.c PPM/PGM file input.
+rdrle.c Utah RLE file input.
+rdtarga.c Targa file input.
+
+Image file writer modules for djpeg:
+
+wrbmp.c BMP file output.
+wrgif.c GIF file output (a mere shadow of its former self).
+wrppm.c PPM/PGM file output.
+wrrle.c Utah RLE file output.
+wrtarga.c Targa file output.
+
+
+RDJPGCOM/WRJPGCOM
+=================
+
+C source code files:
+
+rdjpgcom.c Stand-alone rdjpgcom application.
+wrjpgcom.c Stand-alone wrjpgcom application.
+
+These programs do not depend on the IJG library. They do use
+jconfig.h and jinclude.h, only to improve portability.
+
+
+ADDITIONAL FILES
+================
+
+Documentation (see README for a guide to the documentation files):
+
+README Master documentation file.
+*.txt Other documentation files.
+*.1 Documentation in Unix man page format.
+change.log Version-to-version change highlights.
+example.c Sample code for calling JPEG library.
+
+Configuration/installation files and programs (see install.txt for more info):
+
+configure Unix shell script to perform automatic configuration.
+configure.ac Source file for use with Autoconf to generate configure.
+ltmain.sh Support scripts for configure (from GNU libtool).
+config.guess
+config.sub
+depcomp
+missing
+install-sh Install shell script for those Unix systems lacking one.
+Makefile.in Makefile input for configure.
+Makefile.am Source file for use with Automake to generate Makefile.in.
+ckconfig.c Program to generate jconfig.h on non-Unix systems.
+jconfig.txt Template for making jconfig.h by hand.
+mak*.* Sample makefiles for particular systems.
+jconfig.* Sample jconfig.h for particular systems.
+libjpeg.map Script to generate shared library with versioned symbols.
+aclocal.m4 M4 macro definitions for use with Autoconf.
+ansi2knr.c De-ANSIfier for pre-ANSI C compilers (courtesy of
+ L. Peter Deutsch and Aladdin Enterprises).
+
+Test files (see install.txt for test procedure):
+
+test*.* Source and comparison files for confidence test.
+ These are binary image files, NOT text files.
diff --git a/jpg/install-sh b/jpg/install-sh
new file mode 100644
index 0000000..a9244eb
--- /dev/null
+++ b/jpg/install-sh
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-01-19.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ # Protect names problematic for `test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for `test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for `test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ if (umask $mkdir_umask &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writeable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ ls_ld_tmpdir=`ls -ld "$tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/d" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/jpg/install.txt b/jpg/install.txt
new file mode 100644
index 0000000..04bed91
--- /dev/null
+++ b/jpg/install.txt
@@ -0,0 +1,1096 @@
+INSTALLATION INSTRUCTIONS for the Independent JPEG Group's JPEG software
+
+Copyright (C) 1991-2011, Thomas G. Lane, Guido Vollbeding.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file explains how to configure and install the IJG software. We have
+tried to make this software extremely portable and flexible, so that it can be
+adapted to almost any environment. The downside of this decision is that the
+installation process is complicated. We have provided shortcuts to simplify
+the task on common systems. But in any case, you will need at least a little
+familiarity with C programming and program build procedures for your system.
+
+If you are only using this software as part of a larger program, the larger
+program's installation procedure may take care of configuring the IJG code.
+For example, Ghostscript's installation script will configure the IJG code.
+You don't need to read this file if you just want to compile Ghostscript.
+
+If you are on a Unix machine, you may not need to read this file at all.
+Try doing
+ ./configure
+ make
+ make test
+If that doesn't complain, do
+ make install
+(better do "make -n install" first to see if the makefile will put the files
+where you want them). Read further if you run into snags or want to customize
+the code for your system.
+
+
+TABLE OF CONTENTS
+-----------------
+
+Before you start
+Configuring the software:
+ using the automatic "configure" script
+ using one of the supplied jconfig and makefile files
+ by hand
+Building the software
+Testing the software
+Installing the software
+Optional stuff
+Optimization
+Hints for specific systems
+
+
+BEFORE YOU START
+================
+
+Before installing the software you must unpack the distributed source code.
+Since you are reading this file, you have probably already succeeded in this
+task. However, there is a potential for error if you needed to convert the
+files to the local standard text file format (for example, if you are on
+MS-DOS you may have converted LF end-of-line to CR/LF). You must apply
+such conversion to all the files EXCEPT those whose names begin with "test".
+The test files contain binary data; if you change them in any way then the
+self-test will give bad results.
+
+Please check the last section of this file to see if there are hints for the
+specific machine or compiler you are using.
+
+
+CONFIGURING THE SOFTWARE
+========================
+
+To configure the IJG code for your system, you need to create two files:
+ * jconfig.h: contains values for system-dependent #define symbols.
+ * Makefile: controls the compilation process.
+(On a non-Unix machine, you may create "project files" or some other
+substitute for a Makefile. jconfig.h is needed in any environment.)
+
+We provide three different ways to generate these files:
+ * On a Unix system, you can just run the "configure" script.
+ * We provide sample jconfig files and makefiles for popular machines;
+ if your machine matches one of the samples, just copy the right sample
+ files to jconfig.h and Makefile.
+ * If all else fails, read the instructions below and make your own files.
+
+
+Configuring the software using the automatic "configure" script
+---------------------------------------------------------------
+
+If you are on a Unix machine, you can just type
+ ./configure
+and let the configure script construct appropriate configuration files.
+If you're using "csh" on an old version of System V, you might need to type
+ sh configure
+instead to prevent csh from trying to execute configure itself.
+Expect configure to run for a few minutes, particularly on slower machines;
+it works by compiling a series of test programs.
+
+Configure was created with GNU Autoconf and it follows the usual conventions
+for GNU configure scripts. It makes a few assumptions that you may want to
+override. You can do this by providing optional switches to configure:
+
+* Configure will build both static and shared libraries, if possible.
+If you want to build libjpeg only as a static library, say
+ ./configure --disable-shared
+If you want to build libjpeg only as a shared library, say
+ ./configure --disable-static
+Configure uses GNU libtool to take care of system-dependent shared library
+building methods.
+
+* Configure will use gcc (GNU C compiler) if it's available, otherwise cc.
+To force a particular compiler to be selected, use the CC option, for example
+ ./configure CC='cc'
+The same method can be used to include any unusual compiler switches.
+For example, on HP-UX you probably want to say
+ ./configure CC='cc -Aa'
+to get HP's compiler to run in ANSI mode.
+
+* The default CFLAGS setting is "-g" for non-gcc compilers, "-g -O2" for gcc.
+You can override this by saying, for example,
+ ./configure CFLAGS='-O2'
+if you want to compile without debugging support.
+
+* Configure will set up the makefile so that "make install" will install files
+into /usr/local/bin, /usr/local/man, etc. You can specify an installation
+prefix other than "/usr/local" by giving configure the option "--prefix=PATH".
+
+* If you don't have a lot of swap space, you may need to enable the IJG
+software's internal virtual memory mechanism. To do this, give the option
+"--enable-maxmem=N" where N is the default maxmemory limit in megabytes.
+This is discussed in more detail under "Selecting a memory manager", below.
+You probably don't need to worry about this on reasonably-sized Unix machines,
+unless you plan to process very large images.
+
+Configure has some other features that are useful if you are cross-compiling
+or working in a network of multiple machine types; but if you need those
+features, you probably already know how to use them.
+
+
+Configuring the software using one of the supplied jconfig and makefile files
+-----------------------------------------------------------------------------
+
+If you have one of these systems, you can just use the provided configuration
+files:
+
+Makefile jconfig file System and/or compiler
+
+makefile.manx jconfig.manx Amiga, Manx Aztec C
+makefile.sas jconfig.sas Amiga, SAS C
+makeproj.mac jconfig.mac Apple Macintosh, Metrowerks CodeWarrior
+mak*jpeg.st jconfig.st Atari ST/STE/TT, Pure C or Turbo C
+makefile.bcc jconfig.bcc MS-DOS or OS/2, Borland C
+makefile.dj jconfig.dj MS-DOS, DJGPP (Delorie's port of GNU C)
+makefile.mc6 jconfig.mc6 MS-DOS, Microsoft C (16-bit only)
+makefile.wat jconfig.wat MS-DOS, OS/2, or Windows NT, Watcom C
+makefile.vc jconfig.vc Windows NT/95, MS Visual C++
+make*.vc6 jconfig.vc Windows NT/95, MS Visual C++ 6
+make*.v10 jconfig.vc Windows NT/95, MS Visual C++ 2010 (v10)
+makefile.mms jconfig.vms Digital VMS, with MMS software
+makefile.vms jconfig.vms Digital VMS, without MMS software
+
+Copy the proper jconfig file to jconfig.h and the makefile to Makefile (or
+whatever your system uses as the standard makefile name). For more info see
+the appropriate system-specific hints section near the end of this file.
+
+
+Configuring the software by hand
+--------------------------------
+
+First, generate a jconfig.h file. If you are moderately familiar with C,
+the comments in jconfig.txt should be enough information to do this; just
+copy jconfig.txt to jconfig.h and edit it appropriately. Otherwise, you may
+prefer to use the ckconfig.c program. You will need to compile and execute
+ckconfig.c by hand --- we hope you know at least enough to do that.
+ckconfig.c may not compile the first try (in fact, the whole idea is for it
+to fail if anything is going to). If you get compile errors, fix them by
+editing ckconfig.c according to the directions given in ckconfig.c. Once
+you get it to run, it will write a suitable jconfig.h file, and will also
+print out some advice about which makefile to use.
+
+You may also want to look at the canned jconfig files, if there is one for a
+system similar to yours.
+
+Second, select a makefile and copy it to Makefile (or whatever your system
+uses as the standard makefile name). The most generic makefiles we provide
+are
+ makefile.ansi: if your C compiler supports function prototypes
+ makefile.unix: if not.
+(You have function prototypes if ckconfig.c put "#define HAVE_PROTOTYPES"
+in jconfig.h.) You may want to start from one of the other makefiles if
+there is one for a system similar to yours.
+
+Look over the selected Makefile and adjust options as needed. In particular
+you may want to change the CC and CFLAGS definitions. For instance, if you
+are using GCC, set CC=gcc. If you had to use any compiler switches to get
+ckconfig.c to work, make sure the same switches are in CFLAGS.
+
+If you are on a system that doesn't use makefiles, you'll need to set up
+project files (or whatever you do use) to compile all the source files and
+link them into executable files cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom.
+See the file lists in any of the makefiles to find out which files go into
+each program. Note that the provided makefiles all make a "library" file
+libjpeg first, but you don't have to do that if you don't want to; the file
+lists identify which source files are actually needed for compression,
+decompression, or both. As a last resort, you can make a batch script that
+just compiles everything and links it all together; makefile.vms is an example
+of this (it's for VMS systems that have no make-like utility).
+
+Here are comments about some specific configuration decisions you'll
+need to make:
+
+Command line style
+------------------
+
+These programs can use a Unix-like command line style which supports
+redirection and piping, like this:
+ cjpeg inputfile >outputfile
+ cjpeg <inputfile >outputfile
+ source program | cjpeg >outputfile
+The simpler "two file" command line style is just
+ cjpeg inputfile outputfile
+You may prefer the two-file style, particularly if you don't have pipes.
+
+You MUST use two-file style on any system that doesn't cope well with binary
+data fed through stdin/stdout; this is true for some MS-DOS compilers, for
+example. If you're not on a Unix system, it's safest to assume you need
+two-file style. (But if your compiler provides either the Posix-standard
+fdopen() library routine or a Microsoft-compatible setmode() routine, you
+can safely use the Unix command line style, by defining USE_FDOPEN or
+USE_SETMODE respectively.)
+
+To use the two-file style, make jconfig.h say "#define TWO_FILE_COMMANDLINE".
+
+Selecting a memory manager
+--------------------------
+
+The IJG code is capable of working on images that are too big to fit in main
+memory; data is swapped out to temporary files as necessary. However, the
+code to do this is rather system-dependent. We provide five different
+memory managers:
+
+* jmemansi.c This version uses the ANSI-standard library routine tmpfile(),
+ which not all non-ANSI systems have. On some systems
+ tmpfile() may put the temporary file in a non-optimal
+ location; if you don't like what it does, use jmemname.c.
+
+* jmemname.c This version creates named temporary files. For anything
+ except a Unix machine, you'll need to configure the
+ select_file_name() routine appropriately; see the comments
+ near the head of jmemname.c. If you use this version, define
+ NEED_SIGNAL_CATCHER in jconfig.h to make sure the temp files
+ are removed if the program is aborted.
+
+* jmemnobs.c (That stands for No Backing Store :-).) This will compile on
+ almost any system, but it assumes you have enough main memory
+ or virtual memory to hold the biggest images you work with.
+
+* jmemdos.c This should be used with most 16-bit MS-DOS compilers.
+ See the system-specific notes about MS-DOS for more info.
+ IMPORTANT: if you use this, define USE_MSDOS_MEMMGR in
+ jconfig.h, and include the assembly file jmemdosa.asm in the
+ programs. The supplied makefiles and jconfig files for
+ 16-bit MS-DOS compilers already do both.
+
+* jmemmac.c Custom version for Apple Macintosh; see the system-specific
+ notes for Macintosh for more info.
+
+To use a particular memory manager, change the SYSDEPMEM variable in your
+makefile to equal the corresponding object file name (for example, jmemansi.o
+or jmemansi.obj for jmemansi.c).
+
+If you have plenty of (real or virtual) main memory, just use jmemnobs.c.
+"Plenty" means about ten bytes for every pixel in the largest images
+you plan to process, so a lot of systems don't meet this criterion.
+If yours doesn't, try jmemansi.c first. If that doesn't compile, you'll have
+to use jmemname.c; be sure to adjust select_file_name() for local conditions.
+You may also need to change unlink() to remove() in close_backing_store().
+
+Except with jmemnobs.c or jmemmac.c, you need to adjust the DEFAULT_MAX_MEM
+setting to a reasonable value for your system (either by adding a #define for
+DEFAULT_MAX_MEM to jconfig.h, or by adding a -D switch to the Makefile).
+This value limits the amount of data space the program will attempt to
+allocate. Code and static data space isn't counted, so the actual memory
+needs for cjpeg or djpeg are typically 100 to 150Kb more than the max-memory
+setting. Larger max-memory settings reduce the amount of I/O needed to
+process a large image, but too large a value can result in "insufficient
+memory" failures. On most Unix machines (and other systems with virtual
+memory), just set DEFAULT_MAX_MEM to several million and forget it. At the
+other end of the spectrum, for MS-DOS machines you probably can't go much
+above 300K to 400K. (On MS-DOS the value refers to conventional memory only.
+Extended/expanded memory is handled separately by jmemdos.c.)
+
+
+BUILDING THE SOFTWARE
+=====================
+
+Now you should be able to compile the software. Just say "make" (or
+whatever's necessary to start the compilation). Have a cup of coffee.
+
+Here are some things that could go wrong:
+
+If your compiler complains about undefined structures, you should be able to
+shut it up by putting "#define INCOMPLETE_TYPES_BROKEN" in jconfig.h.
+
+If you have trouble with missing system include files or inclusion of the
+wrong ones, read jinclude.h. This shouldn't happen if you used configure
+or ckconfig.c to set up jconfig.h.
+
+There are a fair number of routines that do not use all of their parameters;
+some compilers will issue warnings about this, which you can ignore. There
+are also a few configuration checks that may give "unreachable code" warnings.
+Any other warning deserves investigation.
+
+If you don't have a getenv() library routine, define NO_GETENV.
+
+Also see the system-specific hints, below.
+
+
+TESTING THE SOFTWARE
+====================
+
+As a quick test of functionality we've included a small sample image in
+several forms:
+ testorig.jpg Starting point for the djpeg tests.
+ testimg.ppm The output of djpeg testorig.jpg
+ testimg.bmp The output of djpeg -bmp -colors 256 testorig.jpg
+ testimg.jpg The output of cjpeg testimg.ppm
+ testprog.jpg Progressive-mode equivalent of testorig.jpg.
+ testimgp.jpg The output of cjpeg -progressive -optimize testimg.ppm
+(The first- and second-generation .jpg files aren't identical since the
+default compression parameters are lossy.) If you can generate duplicates
+of the testimg* files then you probably have working programs.
+
+With most of the makefiles, "make test" will perform the necessary
+comparisons.
+
+If you're using a makefile that doesn't provide the test option, run djpeg
+and cjpeg by hand and compare the output files to testimg* with whatever
+binary file comparison tool you have. The files should be bit-for-bit
+identical.
+
+If the programs complain "MAX_ALLOC_CHUNK is wrong, please fix", then you
+need to reduce MAX_ALLOC_CHUNK to a value that fits in type size_t.
+Try adding "#define MAX_ALLOC_CHUNK 65520L" to jconfig.h. A less likely
+configuration error is "ALIGN_TYPE is wrong, please fix": defining ALIGN_TYPE
+as long should take care of that one.
+
+If the cjpeg test run fails with "Missing Huffman code table entry", it's a
+good bet that you needed to define RIGHT_SHIFT_IS_UNSIGNED. Go back to the
+configuration step and run ckconfig.c. (This is a good plan for any other
+test failure, too.)
+
+If you are using Unix (one-file) command line style on a non-Unix system,
+it's a good idea to check that binary I/O through stdin/stdout actually
+works. You should get the same results from "djpeg <testorig.jpg >out.ppm"
+as from "djpeg -outfile out.ppm testorig.jpg". Note that the makefiles all
+use the latter style and therefore do not exercise stdin/stdout! If this
+check fails, try recompiling with USE_SETMODE or USE_FDOPEN defined.
+If it still doesn't work, better use two-file style.
+
+If you chose a memory manager other than jmemnobs.c, you should test that
+temporary-file usage works. Try "djpeg -bmp -colors 256 -max 0 testorig.jpg"
+and make sure its output matches testimg.bmp. If you have any really large
+images handy, try compressing them with -optimize and/or decompressing with
+-colors 256 to make sure your DEFAULT_MAX_MEM setting is not too large.
+
+NOTE: this is far from an exhaustive test of the JPEG software; some modules,
+such as 1-pass color quantization, are not exercised at all. It's just a
+quick test to give you some confidence that you haven't missed something
+major.
+
+
+INSTALLING THE SOFTWARE
+=======================
+
+Once you're done with the above steps, you can install the software by
+copying the executable files (cjpeg, djpeg, jpegtran, rdjpgcom, and wrjpgcom)
+to wherever you normally install programs. On Unix systems, you'll also want
+to put the man pages (cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1)
+in the man-page directory. The pre-fab makefiles don't support this step
+since there's such a wide variety of installation procedures on different
+systems.
+
+If you generated a Makefile with the "configure" script, you can just say
+ make install
+to install the programs and their man pages into the standard places.
+(You'll probably need to be root to do this.) We recommend first saying
+ make -n install
+to see where configure thought the files should go. You may need to edit
+the Makefile, particularly if your system's conventions for man page
+filenames don't match what configure expects.
+
+If you want to install the IJG library itself, for use in compiling other
+programs besides ours, then you need to put the four include files
+ jpeglib.h jerror.h jconfig.h jmorecfg.h
+into your include-file directory, and put the library file libjpeg.a
+(extension may vary depending on system) wherever library files go.
+If you generated a Makefile with "configure", it will do what it thinks
+is the right thing if you say
+ make install-lib
+
+
+OPTIONAL STUFF
+==============
+
+Progress monitor:
+
+If you like, you can #define PROGRESS_REPORT (in jconfig.h) to enable display
+of percent-done progress reports. The routine provided in cdjpeg.c merely
+prints percentages to stderr, but you can customize it to do something
+fancier.
+
+Utah RLE file format support:
+
+We distribute the software with support for RLE image files (Utah Raster
+Toolkit format) disabled, because the RLE support won't compile without the
+Utah library. If you have URT version 3.1 or later, you can enable RLE
+support as follows:
+ 1. #define RLE_SUPPORTED in jconfig.h.
+ 2. Add a -I option to CFLAGS in the Makefile for the directory
+ containing the URT .h files (typically the "include"
+ subdirectory of the URT distribution).
+ 3. Add -L... -lrle to LDLIBS in the Makefile, where ... specifies
+ the directory containing the URT "librle.a" file (typically the
+ "lib" subdirectory of the URT distribution).
+
+Support for 12-bit-deep pixel data:
+
+The JPEG standard allows either 8-bit or 12-bit data precision. (For color,
+this means 8 or 12 bits per channel, of course.) If you need to work with
+deeper than 8-bit data, you can compile the IJG code for 12-bit operation.
+To do so:
+ 1. In jmorecfg.h, define BITS_IN_JSAMPLE as 12 rather than 8.
+ 2. In jconfig.h, undefine BMP_SUPPORTED, RLE_SUPPORTED, and TARGA_SUPPORTED,
+ because the code for those formats doesn't handle 12-bit data and won't
+ even compile. (The PPM code does work, as explained below. The GIF
+ code works too; it scales 8-bit GIF data to and from 12-bit depth
+ automatically.)
+ 3. Compile. Don't expect "make test" to pass, since the supplied test
+ files are for 8-bit data.
+
+Currently, 12-bit support does not work on 16-bit-int machines.
+
+Note that a 12-bit version will not read 8-bit JPEG files, nor vice versa;
+so you'll want to keep around a regular 8-bit compilation as well.
+(Run-time selection of data depth, to allow a single copy that does both,
+is possible but would probably slow things down considerably; it's very low
+on our to-do list.)
+
+The PPM reader (rdppm.c) can read 12-bit data from either text-format or
+binary-format PPM and PGM files. Binary-format PPM/PGM files which have a
+maxval greater than 255 are assumed to use 2 bytes per sample, MSB first
+(big-endian order). As of early 1995, 2-byte binary format is not
+officially supported by the PBMPLUS library, but it is expected that a
+future release of PBMPLUS will support it. Note that the PPM reader will
+read files of any maxval regardless of the BITS_IN_JSAMPLE setting; incoming
+data is automatically rescaled to either maxval=255 or maxval=4095 as
+appropriate for the cjpeg bit depth.
+
+The PPM writer (wrppm.c) will normally write 2-byte binary PPM or PGM
+format, maxval 4095, when compiled with BITS_IN_JSAMPLE=12. Since this
+format is not yet widely supported, you can disable it by compiling wrppm.c
+with PPM_NORAWWORD defined; then the data is scaled down to 8 bits to make a
+standard 1-byte/sample PPM or PGM file. (Yes, this means still another copy
+of djpeg to keep around. But hopefully you won't need it for very long.
+Poskanzer's supposed to get that new PBMPLUS release out Real Soon Now.)
+
+Of course, if you are working with 12-bit data, you probably have it stored
+in some other, nonstandard format. In that case you'll probably want to
+write your own I/O modules to read and write your format.
+
+Note that a 12-bit version of cjpeg always runs in "-optimize" mode, in
+order to generate valid Huffman tables. This is necessary because our
+default Huffman tables only cover 8-bit data.
+
+Removing code:
+
+If you need to make a smaller version of the JPEG software, some optional
+functions can be removed at compile time. See the xxx_SUPPORTED #defines in
+jconfig.h and jmorecfg.h. If at all possible, we recommend that you leave in
+decoder support for all valid JPEG files, to ensure that you can read anyone's
+output. Taking out support for image file formats that you don't use is the
+most painless way to make the programs smaller. Another possibility is to
+remove some of the DCT methods: in particular, the "IFAST" method may not be
+enough faster than the others to be worth keeping on your machine. (If you
+do remove ISLOW or IFAST, be sure to redefine JDCT_DEFAULT or JDCT_FASTEST
+to a supported method, by adding a #define in jconfig.h.)
+
+
+OPTIMIZATION
+============
+
+Unless you own a Cray, you'll probably be interested in making the JPEG
+software go as fast as possible. This section covers some machine-dependent
+optimizations you may want to try. We suggest that before trying any of
+this, you first get the basic installation to pass the self-test step.
+Repeat the self-test after any optimization to make sure that you haven't
+broken anything.
+
+The integer DCT routines perform a lot of multiplications. These
+multiplications must yield 32-bit results, but none of their input values
+are more than 16 bits wide. On many machines, notably the 680x0 and 80x86
+CPUs, a 16x16=>32 bit multiply instruction is faster than a full 32x32=>32
+bit multiply. Unfortunately there is no portable way to specify such a
+multiplication in C, but some compilers can generate one when you use the
+right combination of casts. See the MULTIPLYxxx macro definitions in
+jdct.h. If your compiler makes "int" be 32 bits and "short" be 16 bits,
+defining SHORTxSHORT_32 is fairly likely to work. When experimenting with
+alternate definitions, be sure to test not only whether the code still works
+(use the self-test), but also whether it is actually faster --- on some
+compilers, alternate definitions may compute the right answer, yet be slower
+than the default. Timing cjpeg on a large PGM (grayscale) input file is the
+best way to check this, as the DCT will be the largest fraction of the runtime
+in that mode. (Note: some of the distributed compiler-specific jconfig files
+already contain #define switches to select appropriate MULTIPLYxxx
+definitions.)
+
+If your machine has sufficiently fast floating point hardware, you may find
+that the float DCT method is faster than the integer DCT methods, even
+after tweaking the integer multiply macros. In that case you may want to
+make the float DCT be the default method. (The only objection to this is
+that float DCT results may vary slightly across machines.) To do that, add
+"#define JDCT_DEFAULT JDCT_FLOAT" to jconfig.h. Even if you don't change
+the default, you should redefine JDCT_FASTEST, which is the method selected
+by djpeg's -fast switch. Don't forget to update the documentation files
+(usage.txt and/or cjpeg.1, djpeg.1) to agree with what you've done.
+
+If access to "short" arrays is slow on your machine, it may be a win to
+define type JCOEF as int rather than short. This will cost a good deal of
+memory though, particularly in some multi-pass modes, so don't do it unless
+you have memory to burn and short is REALLY slow.
+
+If your compiler can compile function calls in-line, make sure the INLINE
+macro in jmorecfg.h is defined as the keyword that marks a function
+inline-able. Some compilers have a switch that tells the compiler to inline
+any function it thinks is profitable (e.g., -finline-functions for gcc).
+Enabling such a switch is likely to make the compiled code bigger but faster.
+
+In general, it's worth trying the maximum optimization level of your compiler,
+and experimenting with any optional optimizations such as loop unrolling.
+(Unfortunately, far too many compilers have optimizer bugs ... be prepared to
+back off if the code fails self-test.) If you do any experimentation along
+these lines, please report the optimal settings to jpeg-info@jpegclub.org so
+we can mention them in future releases. Be sure to specify your machine and
+compiler version.
+
+
+HINTS FOR SPECIFIC SYSTEMS
+==========================
+
+We welcome reports on changes needed for systems not mentioned here. Submit
+'em to jpeg-info@jpegclub.org. Also, if configure or ckconfig.c is wrong
+about how to configure the JPEG software for your system, please let us know.
+
+
+Acorn RISC OS:
+
+(Thanks to Simon Middleton for these hints on compiling with Desktop C.)
+After renaming the files according to Acorn conventions, take a copy of
+makefile.ansi, change all occurrences of 'libjpeg.a' to 'libjpeg.o' and
+change these definitions as indicated:
+
+CFLAGS= -throwback -IC: -Wn
+LDLIBS=C:o.Stubs
+SYSDEPMEM=jmemansi.o
+LN=Link
+AR=LibFile -c -o
+
+Also add a new line '.c.o:; $(cc) $< $(cflags) -c -o $@'. Remove the
+lines '$(RM) libjpeg.o' and '$(AR2) libjpeg.o' and the 'jconfig.h'
+dependency section.
+
+Copy jconfig.txt to jconfig.h. Edit jconfig.h to define TWO_FILE_COMMANDLINE
+and CHAR_IS_UNSIGNED.
+
+Run the makefile using !AMU not !Make. If you want to use the 'clean' and
+'test' makefile entries then you will have to fiddle with the syntax a bit
+and rename the test files.
+
+
+Amiga:
+
+SAS C 6.50 reportedly is too buggy to compile the IJG code properly.
+A patch to update to 6.51 is available from SAS or AmiNet FTP sites.
+
+The supplied config files are set up to use jmemname.c as the memory
+manager, with temporary files being created on the device named by
+"JPEGTMP:".
+
+
+Atari ST/STE/TT:
+
+Copy the project files makcjpeg.st, makdjpeg.st, maktjpeg.st, and makljpeg.st
+to cjpeg.prj, djpeg.prj, jpegtran.prj, and libjpeg.prj respectively. The
+project files should work as-is with Pure C. For Turbo C, change library
+filenames "pc..." to "tc..." in each project file. Note that libjpeg.prj
+selects jmemansi.c as the recommended memory manager. You'll probably want to
+adjust the DEFAULT_MAX_MEM setting --- you want it to be a couple hundred K
+less than your normal free memory. Put "#define DEFAULT_MAX_MEM nnnn" into
+jconfig.h to do this.
+
+To use the 68881/68882 coprocessor for the floating point DCT, add the
+compiler option "-8" to the project files and replace pcfltlib.lib with
+pc881lib.lib in cjpeg.prj and djpeg.prj. Or if you don't have a
+coprocessor, you may prefer to remove the float DCT code by undefining
+DCT_FLOAT_SUPPORTED in jmorecfg.h (since without a coprocessor, the float
+code will be too slow to be useful). In that case, you can delete
+pcfltlib.lib from the project files.
+
+Note that you must make libjpeg.lib before making cjpeg.ttp, djpeg.ttp,
+or jpegtran.ttp. You'll have to perform the self-test by hand.
+
+We haven't bothered to include project files for rdjpgcom and wrjpgcom.
+Those source files should just be compiled by themselves; they don't
+depend on the JPEG library. You can use the default.prj project file
+of the Pure C distribution to make the programs.
+
+There is a bug in some older versions of the Turbo C library which causes the
+space used by temporary files created with "tmpfile()" not to be freed after
+an abnormal program exit. If you check your disk afterwards, you will find
+cluster chains that are allocated but not used by a file. This should not
+happen in cjpeg/djpeg/jpegtran, since we enable a signal catcher to explicitly
+close temp files before exiting. But if you use the JPEG library with your
+own code, be sure to supply a signal catcher, or else use a different
+system-dependent memory manager.
+
+
+Cray:
+
+Should you be so fortunate as to be running JPEG on a Cray YMP, there is a
+compiler bug in old versions of Cray's Standard C (prior to 3.1). If you
+still have an old compiler, you'll need to insert a line reading
+"#pragma novector" just before the loop
+ for (i = 1; i <= (int) htbl->bits[l]; i++)
+ huffsize[p++] = (char) l;
+in fix_huff_tbl (in V5beta1, line 204 of jchuff.c and line 176 of jdhuff.c).
+[This bug may or may not still occur with the current IJG code, but it's
+probably a dead issue anyway...]
+
+
+HP-UX:
+
+If you have HP-UX 7.05 or later with the "software development" C compiler,
+you should run the compiler in ANSI mode. If using the configure script,
+say
+ ./configure CC='cc -Aa'
+(or -Ae if you prefer). If configuring by hand, use makefile.ansi and add
+"-Aa" to the CFLAGS line in the makefile.
+
+If you have a pre-7.05 system, or if you are using the non-ANSI C compiler
+delivered with a minimum HP-UX system, then you must use makefile.unix
+(and do NOT add -Aa); or just run configure without the CC option.
+
+On HP 9000 series 800 machines, the HP C compiler is buggy in revisions prior
+to A.08.07. If you get complaints about "not a typedef name", you'll have to
+use makefile.unix, or run configure without the CC option.
+
+
+Macintosh, generic comments:
+
+The supplied user-interface files (cjpeg.c, djpeg.c, etc) are set up to
+provide a Unix-style command line interface. You can use this interface on
+the Mac by means of the ccommand() library routine provided by Metrowerks
+CodeWarrior or Think C. This is only appropriate for testing the library,
+however; to make a user-friendly equivalent of cjpeg/djpeg you'd really want
+to develop a Mac-style user interface. There isn't a complete example
+available at the moment, but there are some helpful starting points:
+1. Sam Bushell's free "To JPEG" applet provides drag-and-drop conversion to
+JPEG under System 7 and later. This only illustrates how to use the
+compression half of the library, but it does a very nice job of that part.
+The CodeWarrior source code is available from http://www.pobox.com/~jsam.
+2. Jim Brunner prepared a Mac-style user interface for both compression and
+decompression. Unfortunately, it hasn't been updated since IJG v4, and
+the library's API has changed considerably since then. Still it may be of
+some help, particularly as a guide to compiling the IJG code under Think C.
+Jim's code is available from the Info-Mac archives, at sumex-aim.stanford.edu
+or mirrors thereof; see file /info-mac/dev/src/jpeg-convert-c.hqx.
+
+jmemmac.c is the recommended memory manager back end for Macintosh. It uses
+NewPtr/DisposePtr instead of malloc/free, and has a Mac-specific
+implementation of jpeg_mem_available(). It also creates temporary files that
+follow Mac conventions. (That part of the code relies on System-7-or-later OS
+functions. See the comments in jmemmac.c if you need to run it on System 6.)
+NOTE that USE_MAC_MEMMGR must be defined in jconfig.h to use jmemmac.c.
+
+You can also use jmemnobs.c, if you don't care about handling images larger
+than available memory. If you use any memory manager back end other than
+jmemmac.c, we recommend replacing "malloc" and "free" by "NewPtr" and
+"DisposePtr", because Mac C libraries often have peculiar implementations of
+malloc/free. (For instance, free() may not return the freed space to the
+Mac Memory Manager. This is undesirable for the IJG code because jmemmgr.c
+already clumps space requests.)
+
+
+Macintosh, Metrowerks CodeWarrior:
+
+The Unix-command-line-style interface can be used by defining USE_CCOMMAND.
+You'll also need to define TWO_FILE_COMMANDLINE to avoid stdin/stdout.
+This means that when using the cjpeg/djpeg programs, you'll have to type the
+input and output file names in the "Arguments" text-edit box, rather than
+using the file radio buttons. (Perhaps USE_FDOPEN or USE_SETMODE would
+eliminate the problem, but I haven't heard from anyone who's tried it.)
+
+On 680x0 Macs, Metrowerks defines type "double" as a 10-byte IEEE extended
+float. jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power
+of 2. Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint.
+
+The supplied configuration file jconfig.mac can be used for your jconfig.h;
+it includes all the recommended symbol definitions. If you have AppleScript
+installed, you can run the supplied script makeproj.mac to create CodeWarrior
+project files for the library and the testbed applications, then build the
+library and applications. (Thanks to Dan Sears and Don Agro for this nifty
+hack, which saves us from trying to maintain CodeWarrior project files as part
+of the IJG distribution...)
+
+
+Macintosh, Think C:
+
+The documentation in Jim Brunner's "JPEG Convert" source code (see above)
+includes detailed build instructions for Think C; it's probably somewhat
+out of date for the current release, but may be helpful.
+
+If you want to build the minimal command line version, proceed as follows.
+You'll have to prepare project files for the programs; we don't include any
+in the distribution since they are not text files. Use the file lists in
+any of the supplied makefiles as a guide. Also add the ANSI and Unix C
+libraries in a separate segment. You may need to divide the JPEG files into
+more than one segment; we recommend dividing compression and decompression
+modules. Define USE_CCOMMAND in jconfig.h so that the ccommand() routine is
+called. You must also define TWO_FILE_COMMANDLINE because stdin/stdout
+don't handle binary data correctly.
+
+On 680x0 Macs, Think C defines type "double" as a 12-byte IEEE extended float.
+jmemmgr.c won't like this: it wants sizeof(ALIGN_TYPE) to be a power of 2.
+Add "#define ALIGN_TYPE long" to jconfig.h to eliminate the complaint.
+
+jconfig.mac should work as a jconfig.h configuration file for Think C,
+but the makeproj.mac AppleScript script is specific to CodeWarrior. Sorry.
+
+
+MIPS R3000:
+
+MIPS's cc version 1.31 has a rather nasty optimization bug. Don't use -O
+if you have that compiler version. (Use "cc -V" to check the version.)
+Note that the R3000 chip is found in workstations from DEC and others.
+
+
+MS-DOS, generic comments for 16-bit compilers:
+
+The IJG code is designed to work well in 80x86 "small" or "medium" memory
+models (i.e., data pointers are 16 bits unless explicitly declared "far";
+code pointers can be either size). You may be able to use small model to
+compile cjpeg or djpeg by itself, but you will probably have to use medium
+model for any larger application. This won't make much difference in
+performance. You *will* take a noticeable performance hit if you use a
+large-data memory model, and you should avoid "huge" model if at all
+possible. Be sure that NEED_FAR_POINTERS is defined in jconfig.h if you use
+a small-data memory model; be sure it is NOT defined if you use a large-data
+model. (The supplied makefiles and jconfig files for Borland and Microsoft C
+compile in medium model and define NEED_FAR_POINTERS.)
+
+The DOS-specific memory manager, jmemdos.c, should be used if possible.
+It needs some assembly-code routines which are in jmemdosa.asm; make sure
+your makefile assembles that file and includes it in the library. If you
+don't have a suitable assembler, you can get pre-assembled object files for
+jmemdosa by FTP from ftp.uu.net:/graphics/jpeg/jdosaobj.zip. (DOS-oriented
+distributions of the IJG source code often include these object files.)
+
+When using jmemdos.c, jconfig.h must define USE_MSDOS_MEMMGR and must set
+MAX_ALLOC_CHUNK to less than 64K (65520L is a typical value). If your
+C library's far-heap malloc() can't allocate blocks that large, reduce
+MAX_ALLOC_CHUNK to whatever it can handle.
+
+If you can't use jmemdos.c for some reason --- for example, because you
+don't have an assembler to assemble jmemdosa.asm --- you'll have to fall
+back to jmemansi.c or jmemname.c. You'll probably still need to set
+MAX_ALLOC_CHUNK in jconfig.h, because most DOS C libraries won't malloc()
+more than 64K at a time. IMPORTANT: if you use jmemansi.c or jmemname.c,
+you will have to compile in a large-data memory model in order to get the
+right stdio library. Too bad.
+
+wrjpgcom needs to be compiled in large model, because it malloc()s a 64KB
+work area to hold the comment text. If your C library's malloc can't
+handle that, reduce MAX_COM_LENGTH as necessary in wrjpgcom.c.
+
+Most MS-DOS compilers treat stdin/stdout as text files, so you must use
+two-file command line style. But if your compiler has either fdopen() or
+setmode(), you can use one-file style if you like. To do this, define
+USE_SETMODE or USE_FDOPEN so that stdin/stdout will be set to binary mode.
+(USE_SETMODE seems to work with more DOS compilers than USE_FDOPEN.) You
+should test that I/O through stdin/stdout produces the same results as I/O
+to explicitly named files... the "make test" procedures in the supplied
+makefiles do NOT use stdin/stdout.
+
+
+MS-DOS, generic comments for 32-bit compilers:
+
+None of the above comments about memory models apply if you are using a
+32-bit flat-memory-space environment, such as DJGPP or Watcom C. (And you
+should use one if you have it, as performance will be much better than
+8086-compatible code!) For flat-memory-space compilers, do NOT define
+NEED_FAR_POINTERS, and do NOT use jmemdos.c. Use jmemnobs.c if the
+environment supplies adequate virtual memory, otherwise use jmemansi.c or
+jmemname.c.
+
+You'll still need to be careful about binary I/O through stdin/stdout.
+See the last paragraph of the previous section.
+
+
+MS-DOS, Borland C:
+
+Be sure to convert all the source files to DOS text format (CR/LF newlines).
+Although Borland C will often work OK with unmodified Unix (LF newlines)
+source files, sometimes it will give bogus compile errors.
+"Illegal character '#'" is the most common such error. (This is true with
+Borland C 3.1, but perhaps is fixed in newer releases.)
+
+If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE.
+jconfig.bcc already includes #define USE_SETMODE to make this work.
+(fdopen does not work correctly.)
+
+
+MS-DOS, Microsoft C:
+
+makefile.mc6 works with Microsoft C, DOS Visual C++, etc. It should only
+be used if you want to build a 16-bit (small or medium memory model) program.
+
+If you want one-file command line style, just undefine TWO_FILE_COMMANDLINE.
+jconfig.mc6 already includes #define USE_SETMODE to make this work.
+(fdopen does not work correctly.)
+
+Note that this makefile assumes that the working copy of itself is called
+"makefile". If you want to call it something else, say "makefile.mak",
+be sure to adjust the dependency line that reads "$(RFILE) : makefile".
+Otherwise the make will fail because it doesn't know how to create "makefile".
+Worse, some releases of Microsoft's make utilities give an incorrect error
+message in this situation.
+
+Old versions of MS C fail with an "out of macro expansion space" error
+because they can't cope with the macro TRACEMS8 (defined in jerror.h).
+If this happens to you, the easiest solution is to change TRACEMS8 to
+expand to nothing. You'll lose the ability to dump out JPEG coefficient
+tables with djpeg -debug -debug, but at least you can compile.
+
+Original MS C 6.0 is very buggy; it compiles incorrect code unless you turn
+off optimization entirely (remove -O from CFLAGS). 6.00A is better, but it
+still generates bad code if you enable loop optimizations (-Ol or -Ox).
+
+MS C 8.0 crashes when compiling jquant1.c with optimization switch /Oo ...
+which is on by default. To work around this bug, compile that one file
+with /Oo-.
+
+
+Microsoft Windows (all versions), generic comments:
+
+Some Windows system include files define typedef boolean as "unsigned char".
+The IJG code also defines typedef boolean, but we make it "int" by default.
+This doesn't affect the IJG programs because we don't import those Windows
+include files. But if you use the JPEG library in your own program, and some
+of your program's files import one definition of boolean while some import the
+other, you can get all sorts of mysterious problems. A good preventive step
+is to make the IJG library use "unsigned char" for boolean. To do that,
+add something like this to your jconfig.h file:
+ /* Define "boolean" as unsigned char, not int, per Windows custom */
+ #ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+ typedef unsigned char boolean;
+ #endif
+ #define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+(This is already in jconfig.vc, by the way.)
+
+windef.h contains the declarations
+ #define far
+ #define FAR far
+Since jmorecfg.h tries to define FAR as empty, you may get a compiler
+warning if you include both jpeglib.h and windef.h (which windows.h
+includes). To suppress the warning, you can put "#ifndef FAR"/"#endif"
+around the line "#define FAR" in jmorecfg.h.
+(Something like this is already in jmorecfg.h, by the way.)
+
+When using the library in a Windows application, you will almost certainly
+want to modify or replace the error handler module jerror.c, since our
+default error handler does a couple of inappropriate things:
+ 1. it tries to write error and warning messages on stderr;
+ 2. in event of a fatal error, it exits by calling exit().
+
+A simple stopgap solution for problem 1 is to replace the line
+ fprintf(stderr, "%s\n", buffer);
+(in output_message in jerror.c) with
+ MessageBox(GetActiveWindow(),buffer,"JPEG Error",MB_OK|MB_ICONERROR);
+It's highly recommended that you at least do that much, since otherwise
+error messages will disappear into nowhere. (Beginning with IJG v6b, this
+code is already present in jerror.c; just define USE_WINDOWS_MESSAGEBOX in
+jconfig.h to enable it.)
+
+The proper solution for problem 2 is to return control to your calling
+application after a library error. This can be done with the setjmp/longjmp
+technique discussed in libjpeg.txt and illustrated in example.c. (NOTE:
+some older Windows C compilers provide versions of setjmp/longjmp that
+don't actually work under Windows. You may need to use the Windows system
+functions Catch and Throw instead.)
+
+The recommended memory manager under Windows is jmemnobs.c; in other words,
+let Windows do any virtual memory management needed. You should NOT use
+jmemdos.c nor jmemdosa.asm under Windows.
+
+For Windows 3.1, we recommend compiling in medium or large memory model;
+for newer Windows versions, use a 32-bit flat memory model. (See the MS-DOS
+sections above for more info about memory models.) In the 16-bit memory
+models only, you'll need to put
+ #define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */
+into jconfig.h to limit allocation chunks to 64Kb. (Without that, you'd
+have to use huge memory model, which slows things down unnecessarily.)
+jmemnobs.c works without modification in large or flat memory models, but to
+use medium model, you need to modify its jpeg_get_large and jpeg_free_large
+routines to allocate far memory. In any case, you might like to replace
+its calls to malloc and free with direct calls on Windows memory allocation
+functions.
+
+You may also want to modify jdatasrc.c and jdatadst.c to use Windows file
+operations rather than fread/fwrite. This is only necessary if your C
+compiler doesn't provide a competent implementation of C stdio functions.
+
+You might want to tweak the RGB_xxx macros in jmorecfg.h so that the library
+will accept or deliver color pixels in BGR sample order, not RGB; BGR order
+is usually more convenient under Windows. Note that this change will break
+the sample applications cjpeg/djpeg, but the library itself works fine.
+
+
+Many people want to convert the IJG library into a DLL. This is reasonably
+straightforward, but watch out for the following:
+
+ 1. Don't try to compile as a DLL in small or medium memory model; use
+large model, or even better, 32-bit flat model. Many places in the IJG code
+assume the address of a local variable is an ordinary (not FAR) pointer;
+that isn't true in a medium-model DLL.
+
+ 2. Microsoft C cannot pass file pointers between applications and DLLs.
+(See Microsoft Knowledge Base, PSS ID Number Q50336.) So jdatasrc.c and
+jdatadst.c don't work if you open a file in your application and then pass
+the pointer to the DLL. One workaround is to make jdatasrc.c/jdatadst.c
+part of your main application rather than part of the DLL.
+
+ 3. You'll probably need to modify the macros GLOBAL() and EXTERN() to
+attach suitable linkage keywords to the exported routine names. Similarly,
+you'll want to modify METHODDEF() and JMETHOD() to ensure function pointers
+are declared in a way that lets application routines be called back through
+the function pointers. These macros are in jmorecfg.h. Typical definitions
+for a 16-bit DLL are:
+ #define GLOBAL(type) type _far _pascal _loadds _export
+ #define EXTERN(type) extern type _far _pascal _loadds
+ #define METHODDEF(type) static type _far _pascal
+ #define JMETHOD(type,methodname,arglist) \
+ type (_far _pascal *methodname) arglist
+For a 32-bit DLL you may want something like
+ #define GLOBAL(type) __declspec(dllexport) type
+ #define EXTERN(type) extern __declspec(dllexport) type
+Although not all the GLOBAL routines are actually intended to be called by
+the application, the performance cost of making them all DLL entry points is
+negligible.
+
+The unmodified IJG library presents a very C-specific application interface,
+so the resulting DLL is only usable from C or C++ applications. There has
+been some talk of writing wrapper code that would present a simpler interface
+usable from other languages, such as Visual Basic. This is on our to-do list
+but hasn't been very high priority --- any volunteers out there?
+
+
+Microsoft Windows, Borland C:
+
+The provided jconfig.bcc should work OK in a 32-bit Windows environment,
+but you'll need to tweak it in a 16-bit environment (you'd need to define
+NEED_FAR_POINTERS and MAX_ALLOC_CHUNK). Beware that makefile.bcc will need
+alteration if you want to use it for Windows --- in particular, you should
+use jmemnobs.c not jmemdos.c under Windows.
+
+Borland C++ 4.5 fails with an internal compiler error when trying to compile
+jdmerge.c in 32-bit mode. If enough people complain, perhaps Borland will fix
+it. In the meantime, the simplest known workaround is to add a redundant
+definition of the variable range_limit in h2v1_merged_upsample(), at the head
+of the block that handles odd image width (about line 268 in v6 jdmerge.c):
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ register JSAMPLE * range_limit = cinfo->sample_range_limit; /* ADD THIS */
+ cb = GETJSAMPLE(*inptr1);
+Pretty bizarre, especially since the very similar routine h2v2_merged_upsample
+doesn't trigger the bug.
+Recent reports suggest that this bug does not occur with "bcc32a" (the
+Pentium-optimized version of the compiler).
+
+Another report from a user of Borland C 4.5 was that incorrect code (leading
+to a color shift in processed images) was produced if any of the following
+optimization switch combinations were used:
+ -Ot -Og
+ -Ot -Op
+ -Ot -Om
+So try backing off on optimization if you see such a problem. (Are there
+several different releases all numbered "4.5"??)
+
+
+Microsoft Windows, Microsoft Visual C++:
+
+jconfig.vc should work OK with any Microsoft compiler for a 32-bit memory
+model. makefile.vc is intended for command-line use. (If you are using
+the Developer Studio environment, you may prefer the DevStudio project
+files; see below.)
+
+IJG JPEG 7 adds extern "C" to jpeglib.h. This avoids the need to put
+extern "C" { ... } around #include "jpeglib.h" in your C++ application.
+You can also force VC++ to treat the library as C++ code by renaming
+all the *.c files to *.cpp (and adjusting the makefile to match).
+In this case you also need to define the symbol DONT_USE_EXTERN_C in
+the configuration to prevent jpeglib.h from using extern "C".
+
+
+Microsoft Windows, Microsoft Visual C++ 6 Developer Studio:
+
+We include makefiles that should work as project files in DevStudio 6.0 or
+later. There is a library makefile that builds the IJG library as a static
+Win32 library, and application makefiles that build the sample applications
+as Win32 console applications. (Even if you only want the library, we
+recommend building the applications so that you can run the self-test.)
+
+To use:
+1. Open the command prompt, change to the main directory and execute the
+ command line
+ NMAKE /f makefile.vc setup-vc6
+ This will move jconfig.vc to jconfig.h and makefiles to project files.
+ (Note that the renaming is critical!)
+2. Open the workspace file jpeg.dsw, build the library project.
+ (If you are using DevStudio more recent than 6.0, you'll probably
+ get a message saying that the project files are being updated.)
+3. Open the workspace file apps.dsw, build the application projects.
+4. To perform the self-test, execute the command line
+ NMAKE /f makefile.vc test-build
+5. Move the application .exe files from `app`\Release to an
+ appropriate location on your path.
+
+
+Microsoft Windows, Microsoft Visual C++ 2010 Developer Studio (v10):
+
+We include makefiles that should work as project files in Visual Studio
+2010 or later. There is a library makefile that builds the IJG library
+as a static Win32 library, and application makefiles that build the sample
+applications as Win32 console applications. (Even if you only want the
+library, we recommend building the applications so that you can run the
+self-test.)
+
+To use:
+1. Open the command prompt, change to the main directory and execute the
+ command line
+ NMAKE /f makefile.vc setup-v10
+ This will move jconfig.vc to jconfig.h and makefiles to project files.
+ (Note that the renaming is critical!)
+2. Open the solution file jpeg.sln, build the library project.
+ (If you are using Visual Studio more recent than 2010 (v10), you'll
+ probably get a message saying that the project files are being updated.)
+3. Open the solution file apps.sln, build the application projects.
+4. To perform the self-test, execute the command line
+ NMAKE /f makefile.vc test-build
+5. Move the application .exe files from `app`\Release to an
+ appropriate location on your path.
+
+Note:
+There seems to be an optimization bug in the compiler which causes the
+self-test to fail with the color quantization option.
+We have disabled optimization for the file jquant2.c in the library
+project file which causes the self-test to pass properly.
+
+
+OS/2, Borland C++:
+
+Watch out for optimization bugs in older Borland compilers; you may need
+to back off the optimization switch settings. See the comments in
+makefile.bcc.
+
+
+SGI:
+
+On some SGI systems, you may need to set "AR2= ar -ts" in the Makefile.
+If you are using configure, you can do this by saying
+ ./configure RANLIB='ar -ts'
+This change is not needed on all SGIs. Use it only if the make fails at the
+stage of linking the completed programs.
+
+On the MIPS R4000 architecture (Indy, etc.), the compiler option "-mips2"
+reportedly speeds up the float DCT method substantially, enough to make it
+faster than the default int method (but still slower than the fast int
+method). If you use -mips2, you may want to alter the default DCT method to
+be float. To do this, put "#define JDCT_DEFAULT JDCT_FLOAT" in jconfig.h.
+
+
+VMS:
+
+On an Alpha/VMS system with MMS, be sure to use the "/Marco=Alpha=1"
+qualifier with MMS when building the JPEG package.
+
+VAX/VMS v5.5-1 may have problems with the test step of the build procedure
+reporting differences when it compares the original and test images. If the
+error points to the last block of the files, it is most likely bogus and may
+be safely ignored. It seems to be because the files are Stream_LF and
+Backup/Compare has difficulty with the (presumably) null padded files.
+This problem was not observed on VAX/VMS v6.1 or AXP/VMS v6.1.
diff --git a/jpg/jaricom.c b/jpg/jaricom.c
new file mode 100644
index 0000000..6900688
--- /dev/null
+++ b/jpg/jaricom.c
@@ -0,0 +1,153 @@
+/*
+ * jaricom.c
+ *
+ * Developed 1997-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains probability estimation tables for common use in
+ * arithmetic entropy encoding and decoding routines.
+ *
+ * This data represents Table D.3 in the JPEG spec (D.2 in the draft),
+ * ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81, and Table 24
+ * in the JBIG spec, ISO/IEC IS 11544 and CCITT Recommendation ITU-T T.82.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+/* The following #define specifies the packing of the four components
+ * into the compact INT32 representation.
+ * Note that this formula must match the actual arithmetic encoder
+ * and decoder implementation. The implementation has to be changed
+ * if this formula is changed.
+ * The current organization is leaned on Markus Kuhn's JBIG
+ * implementation (jbig_tab.c).
+ */
+
+#define V(i,a,b,c,d) (((INT32)a << 16) | ((INT32)c << 8) | ((INT32)d << 7) | b)
+
+const INT32 jpeg_aritab[113+1] = {
+/*
+ * Index, Qe_Value, Next_Index_LPS, Next_Index_MPS, Switch_MPS
+ */
+ V( 0, 0x5a1d, 1, 1, 1 ),
+ V( 1, 0x2586, 14, 2, 0 ),
+ V( 2, 0x1114, 16, 3, 0 ),
+ V( 3, 0x080b, 18, 4, 0 ),
+ V( 4, 0x03d8, 20, 5, 0 ),
+ V( 5, 0x01da, 23, 6, 0 ),
+ V( 6, 0x00e5, 25, 7, 0 ),
+ V( 7, 0x006f, 28, 8, 0 ),
+ V( 8, 0x0036, 30, 9, 0 ),
+ V( 9, 0x001a, 33, 10, 0 ),
+ V( 10, 0x000d, 35, 11, 0 ),
+ V( 11, 0x0006, 9, 12, 0 ),
+ V( 12, 0x0003, 10, 13, 0 ),
+ V( 13, 0x0001, 12, 13, 0 ),
+ V( 14, 0x5a7f, 15, 15, 1 ),
+ V( 15, 0x3f25, 36, 16, 0 ),
+ V( 16, 0x2cf2, 38, 17, 0 ),
+ V( 17, 0x207c, 39, 18, 0 ),
+ V( 18, 0x17b9, 40, 19, 0 ),
+ V( 19, 0x1182, 42, 20, 0 ),
+ V( 20, 0x0cef, 43, 21, 0 ),
+ V( 21, 0x09a1, 45, 22, 0 ),
+ V( 22, 0x072f, 46, 23, 0 ),
+ V( 23, 0x055c, 48, 24, 0 ),
+ V( 24, 0x0406, 49, 25, 0 ),
+ V( 25, 0x0303, 51, 26, 0 ),
+ V( 26, 0x0240, 52, 27, 0 ),
+ V( 27, 0x01b1, 54, 28, 0 ),
+ V( 28, 0x0144, 56, 29, 0 ),
+ V( 29, 0x00f5, 57, 30, 0 ),
+ V( 30, 0x00b7, 59, 31, 0 ),
+ V( 31, 0x008a, 60, 32, 0 ),
+ V( 32, 0x0068, 62, 33, 0 ),
+ V( 33, 0x004e, 63, 34, 0 ),
+ V( 34, 0x003b, 32, 35, 0 ),
+ V( 35, 0x002c, 33, 9, 0 ),
+ V( 36, 0x5ae1, 37, 37, 1 ),
+ V( 37, 0x484c, 64, 38, 0 ),
+ V( 38, 0x3a0d, 65, 39, 0 ),
+ V( 39, 0x2ef1, 67, 40, 0 ),
+ V( 40, 0x261f, 68, 41, 0 ),
+ V( 41, 0x1f33, 69, 42, 0 ),
+ V( 42, 0x19a8, 70, 43, 0 ),
+ V( 43, 0x1518, 72, 44, 0 ),
+ V( 44, 0x1177, 73, 45, 0 ),
+ V( 45, 0x0e74, 74, 46, 0 ),
+ V( 46, 0x0bfb, 75, 47, 0 ),
+ V( 47, 0x09f8, 77, 48, 0 ),
+ V( 48, 0x0861, 78, 49, 0 ),
+ V( 49, 0x0706, 79, 50, 0 ),
+ V( 50, 0x05cd, 48, 51, 0 ),
+ V( 51, 0x04de, 50, 52, 0 ),
+ V( 52, 0x040f, 50, 53, 0 ),
+ V( 53, 0x0363, 51, 54, 0 ),
+ V( 54, 0x02d4, 52, 55, 0 ),
+ V( 55, 0x025c, 53, 56, 0 ),
+ V( 56, 0x01f8, 54, 57, 0 ),
+ V( 57, 0x01a4, 55, 58, 0 ),
+ V( 58, 0x0160, 56, 59, 0 ),
+ V( 59, 0x0125, 57, 60, 0 ),
+ V( 60, 0x00f6, 58, 61, 0 ),
+ V( 61, 0x00cb, 59, 62, 0 ),
+ V( 62, 0x00ab, 61, 63, 0 ),
+ V( 63, 0x008f, 61, 32, 0 ),
+ V( 64, 0x5b12, 65, 65, 1 ),
+ V( 65, 0x4d04, 80, 66, 0 ),
+ V( 66, 0x412c, 81, 67, 0 ),
+ V( 67, 0x37d8, 82, 68, 0 ),
+ V( 68, 0x2fe8, 83, 69, 0 ),
+ V( 69, 0x293c, 84, 70, 0 ),
+ V( 70, 0x2379, 86, 71, 0 ),
+ V( 71, 0x1edf, 87, 72, 0 ),
+ V( 72, 0x1aa9, 87, 73, 0 ),
+ V( 73, 0x174e, 72, 74, 0 ),
+ V( 74, 0x1424, 72, 75, 0 ),
+ V( 75, 0x119c, 74, 76, 0 ),
+ V( 76, 0x0f6b, 74, 77, 0 ),
+ V( 77, 0x0d51, 75, 78, 0 ),
+ V( 78, 0x0bb6, 77, 79, 0 ),
+ V( 79, 0x0a40, 77, 48, 0 ),
+ V( 80, 0x5832, 80, 81, 1 ),
+ V( 81, 0x4d1c, 88, 82, 0 ),
+ V( 82, 0x438e, 89, 83, 0 ),
+ V( 83, 0x3bdd, 90, 84, 0 ),
+ V( 84, 0x34ee, 91, 85, 0 ),
+ V( 85, 0x2eae, 92, 86, 0 ),
+ V( 86, 0x299a, 93, 87, 0 ),
+ V( 87, 0x2516, 86, 71, 0 ),
+ V( 88, 0x5570, 88, 89, 1 ),
+ V( 89, 0x4ca9, 95, 90, 0 ),
+ V( 90, 0x44d9, 96, 91, 0 ),
+ V( 91, 0x3e22, 97, 92, 0 ),
+ V( 92, 0x3824, 99, 93, 0 ),
+ V( 93, 0x32b4, 99, 94, 0 ),
+ V( 94, 0x2e17, 93, 86, 0 ),
+ V( 95, 0x56a8, 95, 96, 1 ),
+ V( 96, 0x4f46, 101, 97, 0 ),
+ V( 97, 0x47e5, 102, 98, 0 ),
+ V( 98, 0x41cf, 103, 99, 0 ),
+ V( 99, 0x3c3d, 104, 100, 0 ),
+ V( 100, 0x375e, 99, 93, 0 ),
+ V( 101, 0x5231, 105, 102, 0 ),
+ V( 102, 0x4c0f, 106, 103, 0 ),
+ V( 103, 0x4639, 107, 104, 0 ),
+ V( 104, 0x415e, 103, 99, 0 ),
+ V( 105, 0x5627, 105, 106, 1 ),
+ V( 106, 0x50e7, 108, 107, 0 ),
+ V( 107, 0x4b85, 109, 103, 0 ),
+ V( 108, 0x5597, 110, 109, 0 ),
+ V( 109, 0x504f, 111, 107, 0 ),
+ V( 110, 0x5a10, 110, 111, 1 ),
+ V( 111, 0x5522, 112, 109, 0 ),
+ V( 112, 0x59eb, 112, 111, 1 ),
+/*
+ * This last entry is used for fixed probability estimate of 0.5
+ * as suggested in Section 10.3 Table 5 of ITU-T Rec. T.851.
+ */
+ V( 113, 0x5a1d, 113, 113, 0 )
+};
diff --git a/jpg/jcapimin.c b/jpg/jcapimin.c
new file mode 100644
index 0000000..639ce86
--- /dev/null
+++ b/jpg/jcapimin.c
@@ -0,0 +1,288 @@
+/*
+ * jcapimin.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2003-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the compression half
+ * of the JPEG library. These are the "minimum" API routines that may be
+ * needed in either the normal full-compression case or the transcoding-only
+ * case.
+ *
+ * Most of the routines intended to be called directly by an application
+ * are in this file or in jcapistd.c. But also see jcparam.c for
+ * parameter-setup helper routines, jcomapi.c for routines shared by
+ * compression and decompression, and jctrans.c for the transcoding case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Initialization of a JPEG compression object.
+ * The error manager must already be set up (in case memory manager fails).
+ */
+
+GLOBAL(void)
+jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
+{
+ int i;
+
+ /* Guard against version mismatches between library and caller. */
+ cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
+ if (version != JPEG_LIB_VERSION)
+ ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+ if (structsize != SIZEOF(struct jpeg_compress_struct))
+ ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
+ (int) SIZEOF(struct jpeg_compress_struct), (int) structsize);
+
+ /* For debugging purposes, we zero the whole master structure.
+ * But the application has already set the err pointer, and may have set
+ * client_data, so we have to save and restore those fields.
+ * Note: if application hasn't set client_data, tools like Purify may
+ * complain here.
+ */
+ {
+ struct jpeg_error_mgr * err = cinfo->err;
+ void * client_data = cinfo->client_data; /* ignore Purify complaint here */
+ MEMZERO(cinfo, SIZEOF(struct jpeg_compress_struct));
+ cinfo->err = err;
+ cinfo->client_data = client_data;
+ }
+ cinfo->is_decompressor = FALSE;
+
+ /* Initialize a memory manager instance for this object */
+ jinit_memory_mgr((j_common_ptr) cinfo);
+
+ /* Zero out pointers to permanent structures. */
+ cinfo->progress = NULL;
+ cinfo->dest = NULL;
+
+ cinfo->comp_info = NULL;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ cinfo->quant_tbl_ptrs[i] = NULL;
+ cinfo->q_scale_factor[i] = 100;
+ }
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ cinfo->dc_huff_tbl_ptrs[i] = NULL;
+ cinfo->ac_huff_tbl_ptrs[i] = NULL;
+ }
+
+ /* Must do it here for emit_dqt in case jpeg_write_tables is used */
+ cinfo->block_size = DCTSIZE;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+
+ cinfo->script_space = NULL;
+
+ cinfo->input_gamma = 1.0; /* in case application forgets */
+
+ /* OK, I'm ready */
+ cinfo->global_state = CSTATE_START;
+}
+
+
+/*
+ * Destruction of a JPEG compression object
+ */
+
+GLOBAL(void)
+jpeg_destroy_compress (j_compress_ptr cinfo)
+{
+ jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Abort processing of a JPEG compression operation,
+ * but don't destroy the object itself.
+ */
+
+GLOBAL(void)
+jpeg_abort_compress (j_compress_ptr cinfo)
+{
+ jpeg_abort((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Forcibly suppress or un-suppress all quantization and Huffman tables.
+ * Marks all currently defined tables as already written (if suppress)
+ * or not written (if !suppress). This will control whether they get emitted
+ * by a subsequent jpeg_start_compress call.
+ *
+ * This routine is exported for use by applications that want to produce
+ * abbreviated JPEG datastreams. It logically belongs in jcparam.c, but
+ * since it is called by jpeg_start_compress, we put it here --- otherwise
+ * jcparam.o would be linked whether the application used it or not.
+ */
+
+GLOBAL(void)
+jpeg_suppress_tables (j_compress_ptr cinfo, boolean suppress)
+{
+ int i;
+ JQUANT_TBL * qtbl;
+ JHUFF_TBL * htbl;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ if ((qtbl = cinfo->quant_tbl_ptrs[i]) != NULL)
+ qtbl->sent_table = suppress;
+ }
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if ((htbl = cinfo->dc_huff_tbl_ptrs[i]) != NULL)
+ htbl->sent_table = suppress;
+ if ((htbl = cinfo->ac_huff_tbl_ptrs[i]) != NULL)
+ htbl->sent_table = suppress;
+ }
+}
+
+
+/*
+ * Finish JPEG compression.
+ *
+ * If a multipass operating mode was selected, this may do a great deal of
+ * work including most of the actual output.
+ */
+
+GLOBAL(void)
+jpeg_finish_compress (j_compress_ptr cinfo)
+{
+ JDIMENSION iMCU_row;
+
+ if (cinfo->global_state == CSTATE_SCANNING ||
+ cinfo->global_state == CSTATE_RAW_OK) {
+ /* Terminate first pass */
+ if (cinfo->next_scanline < cinfo->image_height)
+ ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+ (*cinfo->master->finish_pass) (cinfo);
+ } else if (cinfo->global_state != CSTATE_WRCOEFS)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Perform any remaining passes */
+ while (! cinfo->master->is_last_pass) {
+ (*cinfo->master->prepare_for_pass) (cinfo);
+ for (iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++) {
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) iMCU_row;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+ /* We bypass the main controller and invoke coef controller directly;
+ * all work is being done from the coefficient buffer.
+ */
+ if (! (*cinfo->coef->compress_data) (cinfo, (JSAMPIMAGE) NULL))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
+ (*cinfo->master->finish_pass) (cinfo);
+ }
+ /* Write EOI, do final cleanup */
+ (*cinfo->marker->write_file_trailer) (cinfo);
+ (*cinfo->dest->term_destination) (cinfo);
+ /* We can use jpeg_abort to release memory and reset global_state */
+ jpeg_abort((j_common_ptr) cinfo);
+}
+
+
+/*
+ * Write a special marker.
+ * This is only recommended for writing COM or APPn markers.
+ * Must be called after jpeg_start_compress() and before
+ * first call to jpeg_write_scanlines() or jpeg_write_raw_data().
+ */
+
+GLOBAL(void)
+jpeg_write_marker (j_compress_ptr cinfo, int marker,
+ const JOCTET *dataptr, unsigned int datalen)
+{
+ JMETHOD(void, write_marker_byte, (j_compress_ptr info, int val));
+
+ if (cinfo->next_scanline != 0 ||
+ (cinfo->global_state != CSTATE_SCANNING &&
+ cinfo->global_state != CSTATE_RAW_OK &&
+ cinfo->global_state != CSTATE_WRCOEFS))
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);
+ write_marker_byte = cinfo->marker->write_marker_byte; /* copy for speed */
+ while (datalen--) {
+ (*write_marker_byte) (cinfo, *dataptr);
+ dataptr++;
+ }
+}
+
+/* Same, but piecemeal. */
+
+GLOBAL(void)
+jpeg_write_m_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
+{
+ if (cinfo->next_scanline != 0 ||
+ (cinfo->global_state != CSTATE_SCANNING &&
+ cinfo->global_state != CSTATE_RAW_OK &&
+ cinfo->global_state != CSTATE_WRCOEFS))
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ (*cinfo->marker->write_marker_header) (cinfo, marker, datalen);
+}
+
+GLOBAL(void)
+jpeg_write_m_byte (j_compress_ptr cinfo, int val)
+{
+ (*cinfo->marker->write_marker_byte) (cinfo, val);
+}
+
+
+/*
+ * Alternate compression function: just write an abbreviated table file.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * To produce a pair of files containing abbreviated tables and abbreviated
+ * image data, one would proceed as follows:
+ *
+ * initialize JPEG object
+ * set JPEG parameters
+ * set destination to table file
+ * jpeg_write_tables(cinfo);
+ * set destination to image file
+ * jpeg_start_compress(cinfo, FALSE);
+ * write data...
+ * jpeg_finish_compress(cinfo);
+ *
+ * jpeg_write_tables has the side effect of marking all tables written
+ * (same as jpeg_suppress_tables(..., TRUE)). Thus a subsequent start_compress
+ * will not re-emit the tables unless it is passed write_all_tables=TRUE.
+ */
+
+GLOBAL(void)
+jpeg_write_tables (j_compress_ptr cinfo)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Initialize the marker writer ... bit of a crock to do it here. */
+ jinit_marker_writer(cinfo);
+ /* Write them tables! */
+ (*cinfo->marker->write_tables_only) (cinfo);
+ /* And clean up. */
+ (*cinfo->dest->term_destination) (cinfo);
+ /*
+ * In library releases up through v6a, we called jpeg_abort() here to free
+ * any working memory allocated by the destination manager and marker
+ * writer. Some applications had a problem with that: they allocated space
+ * of their own from the library memory manager, and didn't want it to go
+ * away during write_tables. So now we do nothing. This will cause a
+ * memory leak if an app calls write_tables repeatedly without doing a full
+ * compression cycle or otherwise resetting the JPEG object. However, that
+ * seems less bad than unexpectedly freeing memory in the normal case.
+ * An app that prefers the old behavior can call jpeg_abort for itself after
+ * each call to jpeg_write_tables().
+ */
+}
diff --git a/jpg/jcapistd.c b/jpg/jcapistd.c
new file mode 100644
index 0000000..c0320b1
--- /dev/null
+++ b/jpg/jcapistd.c
@@ -0,0 +1,161 @@
+/*
+ * jcapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the compression half
+ * of the JPEG library. These are the "standard" API routines that are
+ * used in the normal full-compression case. They are not used by a
+ * transcoding-only application. Note that if an application links in
+ * jpeg_start_compress, it will end up linking in the entire compressor.
+ * We thus must separate this file from jcapimin.c to avoid linking the
+ * whole compression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Compression initialization.
+ * Before calling this, all parameters and a data destination must be set up.
+ *
+ * We require a write_all_tables parameter as a failsafe check when writing
+ * multiple datastreams from the same compression object. Since prior runs
+ * will have left all the tables marked sent_table=TRUE, a subsequent run
+ * would emit an abbreviated stream (no tables) by default. This may be what
+ * is wanted, but for safety's sake it should not be the default behavior:
+ * programmers should have to make a deliberate choice to emit abbreviated
+ * images. Therefore the documentation and examples should encourage people
+ * to pass write_all_tables=TRUE; then it will take active thought to do the
+ * wrong thing.
+ */
+
+GLOBAL(void)
+jpeg_start_compress (j_compress_ptr cinfo, boolean write_all_tables)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (write_all_tables)
+ jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */
+
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Perform master selection of active modules */
+ jinit_compress_master(cinfo);
+ /* Set up for the first pass */
+ (*cinfo->master->prepare_for_pass) (cinfo);
+ /* Ready for application to drive first pass through jpeg_write_scanlines
+ * or jpeg_write_raw_data.
+ */
+ cinfo->next_scanline = 0;
+ cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
+}
+
+
+/*
+ * Write some scanlines of data to the JPEG compressor.
+ *
+ * The return value will be the number of lines actually written.
+ * This should be less than the supplied num_lines only in case that
+ * the data destination module has requested suspension of the compressor,
+ * or if more than image_height scanlines are passed in.
+ *
+ * Note: we warn about excess calls to jpeg_write_scanlines() since
+ * this likely signals an application programmer error. However,
+ * excess scanlines passed in the last valid call are *silently* ignored,
+ * so that the application need not adjust num_lines for end-of-image
+ * when using a multiple-scanline buffer.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_write_scanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines,
+ JDIMENSION num_lines)
+{
+ JDIMENSION row_ctr, rows_left;
+
+ if (cinfo->global_state != CSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->next_scanline >= cinfo->image_height)
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->image_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Give master control module another chance if this is first call to
+ * jpeg_write_scanlines. This lets output of the frame/scan headers be
+ * delayed so that application can write COM, etc, markers between
+ * jpeg_start_compress and jpeg_write_scanlines.
+ */
+ if (cinfo->master->call_pass_startup)
+ (*cinfo->master->pass_startup) (cinfo);
+
+ /* Ignore any extra scanlines at bottom of image. */
+ rows_left = cinfo->image_height - cinfo->next_scanline;
+ if (num_lines > rows_left)
+ num_lines = rows_left;
+
+ row_ctr = 0;
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
+ cinfo->next_scanline += row_ctr;
+ return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to write raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_write_raw_data (j_compress_ptr cinfo, JSAMPIMAGE data,
+ JDIMENSION num_lines)
+{
+ JDIMENSION lines_per_iMCU_row;
+
+ if (cinfo->global_state != CSTATE_RAW_OK)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->next_scanline >= cinfo->image_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->next_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->image_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Give master control module another chance if this is first call to
+ * jpeg_write_raw_data. This lets output of the frame/scan headers be
+ * delayed so that application can write COM, etc, markers between
+ * jpeg_start_compress and jpeg_write_raw_data.
+ */
+ if (cinfo->master->call_pass_startup)
+ (*cinfo->master->pass_startup) (cinfo);
+
+ /* Verify that at least one iMCU row has been passed. */
+ lines_per_iMCU_row = cinfo->max_v_samp_factor * DCTSIZE;
+ if (num_lines < lines_per_iMCU_row)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* Directly compress the row. */
+ if (! (*cinfo->coef->compress_data) (cinfo, data)) {
+ /* If compressor did not consume the whole row, suspend processing. */
+ return 0;
+ }
+
+ /* OK, we processed one iMCU row. */
+ cinfo->next_scanline += lines_per_iMCU_row;
+ return lines_per_iMCU_row;
+}
diff --git a/jpg/jcarith.c b/jpg/jcarith.c
new file mode 100644
index 0000000..033f670
--- /dev/null
+++ b/jpg/jcarith.c
@@ -0,0 +1,937 @@
+/*
+ * jcarith.c
+ *
+ * Developed 1997-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains portable arithmetic entropy encoding routines for JPEG
+ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
+ *
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Suspension is not currently supported in this module.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Expanded entropy encoder object for arithmetic encoding. */
+
+typedef struct {
+ struct jpeg_entropy_encoder pub; /* public fields */
+
+ INT32 c; /* C register, base of coding interval, layout as in sec. D.1.3 */
+ INT32 a; /* A register, normalized size of coding interval */
+ INT32 sc; /* counter for stacked 0xFF values which might overflow */
+ INT32 zc; /* counter for pending 0x00 output values which might *
+ * be discarded at the end ("Pacman" termination) */
+ int ct; /* bit shift counter, determines when next byte will be written */
+ int buffer; /* buffer for most recent output byte != 0xFF */
+
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+ int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
+
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+ int next_restart_num; /* next restart number to write (0-7) */
+
+ /* Pointers to statistics areas (these workspaces have image lifespan) */
+ unsigned char * dc_stats[NUM_ARITH_TBLS];
+ unsigned char * ac_stats[NUM_ARITH_TBLS];
+
+ /* Statistics bin for coding with fixed probability 0.5 */
+ unsigned char fixed_bin[4];
+} arith_entropy_encoder;
+
+typedef arith_entropy_encoder * arith_entropy_ptr;
+
+/* The following two definitions specify the allocation chunk size
+ * for the statistics area.
+ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
+ * 49 statistics bins for DC, and 245 statistics bins for AC coding.
+ *
+ * We use a compact representation with 1 byte per statistics bin,
+ * thus the numbers directly represent byte sizes.
+ * This 1 byte per statistics bin contains the meaning of the MPS
+ * (more probable symbol) in the highest bit (mask 0x80), and the
+ * index into the probability estimation state machine table
+ * in the lower bits (mask 0x7F).
+ */
+
+#define DC_STAT_BINS 64
+#define AC_STAT_BINS 256
+
+/* NOTE: Uncomment the following #define if you want to use the
+ * given formula for calculating the AC conditioning parameter Kx
+ * for spectral selection progressive coding in section G.1.3.2
+ * of the spec (Kx = Kmin + SRL (8 + Se - Kmin) 4).
+ * Although the spec and P&M authors claim that this "has proven
+ * to give good results for 8 bit precision samples", I'm not
+ * convinced yet that this is really beneficial.
+ * Early tests gave only very marginal compression enhancements
+ * (a few - around 5 or so - bytes even for very large files),
+ * which would turn out rather negative if we'd suppress the
+ * DAC (Define Arithmetic Conditioning) marker segments for
+ * the default parameters in the future.
+ * Note that currently the marker writing module emits 12-byte
+ * DAC segments for a full-component scan in a color image.
+ * This is not worth worrying about IMHO. However, since the
+ * spec defines the default values to be used if the tables
+ * are omitted (unlike Huffman tables, which are required
+ * anyway), one might optimize this behaviour in the future,
+ * and then it would be disadvantageous to use custom tables if
+ * they don't provide sufficient gain to exceed the DAC size.
+ *
+ * On the other hand, I'd consider it as a reasonable result
+ * that the conditioning has no significant influence on the
+ * compression performance. This means that the basic
+ * statistical model is already rather stable.
+ *
+ * Thus, at the moment, we use the default conditioning values
+ * anyway, and do not use the custom formula.
+ *
+#define CALCULATE_SPECTRAL_CONDITIONING
+ */
+
+/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
+ * We assume that int right shift is unsigned if INT32 right shift is,
+ * which should be safe.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS int ishift_temp;
+#define IRIGHT_SHIFT(x,shft) \
+ ((ishift_temp = (x)) < 0 ? \
+ (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
+ (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+
+LOCAL(void)
+emit_byte (int val, j_compress_ptr cinfo)
+/* Write next output byte; we do not support suspension in this module. */
+{
+ struct jpeg_destination_mgr * dest = cinfo->dest;
+
+ *dest->next_output_byte++ = (JOCTET) val;
+ if (--dest->free_in_buffer == 0)
+ if (! (*dest->empty_output_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+}
+
+
+/*
+ * Finish up at the end of an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass (j_compress_ptr cinfo)
+{
+ arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+ INT32 temp;
+
+ /* Section D.1.8: Termination of encoding */
+
+ /* Find the e->c in the coding interval with the largest
+ * number of trailing zero bits */
+ if ((temp = (e->a - 1 + e->c) & 0xFFFF0000L) < e->c)
+ e->c = temp + 0x8000L;
+ else
+ e->c = temp;
+ /* Send remaining bytes to output */
+ e->c <<= e->ct;
+ if (e->c & 0xF8000000L) {
+ /* One final overflow has to be handled */
+ if (e->buffer >= 0) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte(e->buffer + 1, cinfo);
+ if (e->buffer + 1 == 0xFF)
+ emit_byte(0x00, cinfo);
+ }
+ e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */
+ e->sc = 0;
+ } else {
+ if (e->buffer == 0)
+ ++e->zc;
+ else if (e->buffer >= 0) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte(e->buffer, cinfo);
+ }
+ if (e->sc) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ do {
+ emit_byte(0xFF, cinfo);
+ emit_byte(0x00, cinfo);
+ } while (--e->sc);
+ }
+ }
+ /* Output final bytes only if they are not 0x00 */
+ if (e->c & 0x7FFF800L) {
+ if (e->zc) /* output final pending zero bytes */
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte((e->c >> 19) & 0xFF, cinfo);
+ if (((e->c >> 19) & 0xFF) == 0xFF)
+ emit_byte(0x00, cinfo);
+ if (e->c & 0x7F800L) {
+ emit_byte((e->c >> 11) & 0xFF, cinfo);
+ if (((e->c >> 11) & 0xFF) == 0xFF)
+ emit_byte(0x00, cinfo);
+ }
+ }
+}
+
+
+/*
+ * The core arithmetic encoding routine (common in JPEG and JBIG).
+ * This needs to go as fast as possible.
+ * Machine-dependent optimization facilities
+ * are not utilized in this portable implementation.
+ * However, this code should be fairly efficient and
+ * may be a good base for further optimizations anyway.
+ *
+ * Parameter 'val' to be encoded may be 0 or 1 (binary decision).
+ *
+ * Note: I've added full "Pacman" termination support to the
+ * byte output routines, which is equivalent to the optional
+ * Discard_final_zeros procedure (Figure D.15) in the spec.
+ * Thus, we always produce the shortest possible output
+ * stream compliant to the spec (no trailing zero bytes,
+ * except for FF stuffing).
+ *
+ * I've also introduced a new scheme for accessing
+ * the probability estimation state machine table,
+ * derived from Markus Kuhn's JBIG implementation.
+ */
+
+LOCAL(void)
+arith_encode (j_compress_ptr cinfo, unsigned char *st, int val)
+{
+ register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+ register unsigned char nl, nm;
+ register INT32 qe, temp;
+ register int sv;
+
+ /* Fetch values from our compact representation of Table D.3(D.2):
+ * Qe values and probability estimation state machine
+ */
+ sv = *st;
+ qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */
+ nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */
+ nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */
+
+ /* Encode & estimation procedures per sections D.1.4 & D.1.5 */
+ e->a -= qe;
+ if (val != (sv >> 7)) {
+ /* Encode the less probable symbol */
+ if (e->a >= qe) {
+ /* If the interval size (qe) for the less probable symbol (LPS)
+ * is larger than the interval size for the MPS, then exchange
+ * the two symbols for coding efficiency, otherwise code the LPS
+ * as usual: */
+ e->c += e->a;
+ e->a = qe;
+ }
+ *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
+ } else {
+ /* Encode the more probable symbol */
+ if (e->a >= 0x8000L)
+ return; /* A >= 0x8000 -> ready, no renormalization required */
+ if (e->a < qe) {
+ /* If the interval size (qe) for the less probable symbol (LPS)
+ * is larger than the interval size for the MPS, then exchange
+ * the two symbols for coding efficiency: */
+ e->c += e->a;
+ e->a = qe;
+ }
+ *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
+ }
+
+ /* Renormalization & data output per section D.1.6 */
+ do {
+ e->a <<= 1;
+ e->c <<= 1;
+ if (--e->ct == 0) {
+ /* Another byte is ready for output */
+ temp = e->c >> 19;
+ if (temp > 0xFF) {
+ /* Handle overflow over all stacked 0xFF bytes */
+ if (e->buffer >= 0) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte(e->buffer + 1, cinfo);
+ if (e->buffer + 1 == 0xFF)
+ emit_byte(0x00, cinfo);
+ }
+ e->zc += e->sc; /* carry-over converts stacked 0xFF bytes to 0x00 */
+ e->sc = 0;
+ /* Note: The 3 spacer bits in the C register guarantee
+ * that the new buffer byte can't be 0xFF here
+ * (see page 160 in the P&M JPEG book). */
+ e->buffer = temp & 0xFF; /* new output byte, might overflow later */
+ } else if (temp == 0xFF) {
+ ++e->sc; /* stack 0xFF byte (which might overflow later) */
+ } else {
+ /* Output all stacked 0xFF bytes, they will not overflow any more */
+ if (e->buffer == 0)
+ ++e->zc;
+ else if (e->buffer >= 0) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ emit_byte(e->buffer, cinfo);
+ }
+ if (e->sc) {
+ if (e->zc)
+ do emit_byte(0x00, cinfo);
+ while (--e->zc);
+ do {
+ emit_byte(0xFF, cinfo);
+ emit_byte(0x00, cinfo);
+ } while (--e->sc);
+ }
+ e->buffer = temp & 0xFF; /* new output byte (can still overflow) */
+ }
+ e->c &= 0x7FFFFL;
+ e->ct += 8;
+ }
+ } while (e->a < 0x8000L);
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(void)
+emit_restart (j_compress_ptr cinfo, int restart_num)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ int ci;
+ jpeg_component_info * compptr;
+
+ finish_pass(cinfo);
+
+ emit_byte(0xFF, cinfo);
+ emit_byte(JPEG_RST0 + restart_num, cinfo);
+
+ /* Re-initialize statistics areas */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+ MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+ /* Reset DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ entropy->dc_context[ci] = 0;
+ }
+ /* AC needs no table when not present */
+ if (cinfo->Se) {
+ MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+ }
+ }
+
+ /* Reset arithmetic encoding variables */
+ entropy->c = 0;
+ entropy->a = 0x10000L;
+ entropy->sc = 0;
+ entropy->zc = 0;
+ entropy->ct = 11;
+ entropy->buffer = -1; /* empty */
+}
+
+
+/*
+ * MCU encoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int blkn, ci, tbl;
+ int v, v2, m;
+ ISHIFT_TEMPS
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+ /* Compute the DC value after the required point transform by Al.
+ * This is simply an arithmetic right shift.
+ */
+ m = IRIGHT_SHIFT((int) ((*block)[0]), cinfo->Al);
+
+ /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
+
+ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+ st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+ /* Figure F.4: Encode_DC_DIFF */
+ if ((v = m - entropy->last_dc_val[ci]) == 0) {
+ arith_encode(cinfo, st, 0);
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ } else {
+ entropy->last_dc_val[ci] = m;
+ arith_encode(cinfo, st, 1);
+ /* Figure F.6: Encoding nonzero value v */
+ /* Figure F.7: Encoding the sign of v */
+ if (v > 0) {
+ arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */
+ st += 2; /* Table F.4: SP = S0 + 2 */
+ entropy->dc_context[ci] = 4; /* small positive diff category */
+ } else {
+ v = -v;
+ arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */
+ st += 3; /* Table F.4: SN = S0 + 3 */
+ entropy->dc_context[ci] = 8; /* small negative diff category */
+ }
+ /* Figure F.8: Encoding the magnitude category of v */
+ m = 0;
+ if (v -= 1) {
+ arith_encode(cinfo, st, 1);
+ m = 1;
+ v2 = v;
+ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+ while (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st += 1;
+ }
+ }
+ arith_encode(cinfo, st, 0);
+ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+ if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+ entropy->dc_context[ci] += 8; /* large diff category */
+ /* Figure F.9: Encoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ arith_encode(cinfo, st, (m & v) ? 1 : 0);
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int tbl, k, ke;
+ int v, v2, m;
+ const int * natural_order;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+ tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+ /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
+
+ /* Establish EOB (end-of-block) index */
+ for (ke = cinfo->Se; ke > 0; ke--)
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value.
+ */
+ if ((v = (*block)[natural_order[ke]]) >= 0) {
+ if (v >>= cinfo->Al) break;
+ } else {
+ v = -v;
+ if (v >>= cinfo->Al) break;
+ }
+
+ /* Figure F.5: Encode_AC_Coefficients */
+ for (k = cinfo->Ss; k <= ke; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ arith_encode(cinfo, st, 0); /* EOB decision */
+ for (;;) {
+ if ((v = (*block)[natural_order[k]]) >= 0) {
+ if (v >>= cinfo->Al) {
+ arith_encode(cinfo, st + 1, 1);
+ arith_encode(cinfo, entropy->fixed_bin, 0);
+ break;
+ }
+ } else {
+ v = -v;
+ if (v >>= cinfo->Al) {
+ arith_encode(cinfo, st + 1, 1);
+ arith_encode(cinfo, entropy->fixed_bin, 1);
+ break;
+ }
+ }
+ arith_encode(cinfo, st + 1, 0); st += 3; k++;
+ }
+ st += 2;
+ /* Figure F.8: Encoding the magnitude category of v */
+ m = 0;
+ if (v -= 1) {
+ arith_encode(cinfo, st, 1);
+ m = 1;
+ v2 = v;
+ if (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st = entropy->ac_stats[tbl] +
+ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+ while (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st += 1;
+ }
+ }
+ }
+ arith_encode(cinfo, st, 0);
+ /* Figure F.9: Encoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ arith_encode(cinfo, st, (m & v) ? 1 : 0);
+ }
+ /* Encode EOB decision only if k <= cinfo->Se */
+ if (k <= cinfo->Se) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ arith_encode(cinfo, st, 1);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for DC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ unsigned char *st;
+ int Al, blkn;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ st = entropy->fixed_bin; /* use fixed probability estimation */
+ Al = cinfo->Al;
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ /* We simply emit the Al'th bit of the DC coefficient value. */
+ arith_encode(cinfo, st, (MCU_data[blkn][0][0] >> Al) & 1);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int tbl, k, ke, kex;
+ int v;
+ const int * natural_order;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+ tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+ /* Section G.1.3.3: Encoding of AC coefficients */
+
+ /* Establish EOB (end-of-block) index */
+ for (ke = cinfo->Se; ke > 0; ke--)
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value.
+ */
+ if ((v = (*block)[natural_order[ke]]) >= 0) {
+ if (v >>= cinfo->Al) break;
+ } else {
+ v = -v;
+ if (v >>= cinfo->Al) break;
+ }
+
+ /* Establish EOBx (previous stage end-of-block) index */
+ for (kex = ke; kex > 0; kex--)
+ if ((v = (*block)[natural_order[kex]]) >= 0) {
+ if (v >>= cinfo->Ah) break;
+ } else {
+ v = -v;
+ if (v >>= cinfo->Ah) break;
+ }
+
+ /* Figure G.10: Encode_AC_Coefficients_SA */
+ for (k = cinfo->Ss; k <= ke; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ if (k > kex)
+ arith_encode(cinfo, st, 0); /* EOB decision */
+ for (;;) {
+ if ((v = (*block)[natural_order[k]]) >= 0) {
+ if (v >>= cinfo->Al) {
+ if (v >> 1) /* previously nonzero coef */
+ arith_encode(cinfo, st + 2, (v & 1));
+ else { /* newly nonzero coef */
+ arith_encode(cinfo, st + 1, 1);
+ arith_encode(cinfo, entropy->fixed_bin, 0);
+ }
+ break;
+ }
+ } else {
+ v = -v;
+ if (v >>= cinfo->Al) {
+ if (v >> 1) /* previously nonzero coef */
+ arith_encode(cinfo, st + 2, (v & 1));
+ else { /* newly nonzero coef */
+ arith_encode(cinfo, st + 1, 1);
+ arith_encode(cinfo, entropy->fixed_bin, 1);
+ }
+ break;
+ }
+ }
+ arith_encode(cinfo, st + 1, 0); st += 3; k++;
+ }
+ }
+ /* Encode EOB decision only if k <= cinfo->Se */
+ if (k <= cinfo->Se) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ arith_encode(cinfo, st, 1);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Encode and output one MCU's worth of arithmetic-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+encode_mcu (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ jpeg_component_info * compptr;
+ JBLOCKROW block;
+ unsigned char *st;
+ int blkn, ci, tbl, k, ke;
+ int v, v2, m;
+ const int * natural_order;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ emit_restart(cinfo, entropy->next_restart_num);
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+
+ /* Sections F.1.4.1 & F.1.4.4.1: Encoding of DC coefficients */
+
+ tbl = compptr->dc_tbl_no;
+
+ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+ st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+ /* Figure F.4: Encode_DC_DIFF */
+ if ((v = (*block)[0] - entropy->last_dc_val[ci]) == 0) {
+ arith_encode(cinfo, st, 0);
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ } else {
+ entropy->last_dc_val[ci] = (*block)[0];
+ arith_encode(cinfo, st, 1);
+ /* Figure F.6: Encoding nonzero value v */
+ /* Figure F.7: Encoding the sign of v */
+ if (v > 0) {
+ arith_encode(cinfo, st + 1, 0); /* Table F.4: SS = S0 + 1 */
+ st += 2; /* Table F.4: SP = S0 + 2 */
+ entropy->dc_context[ci] = 4; /* small positive diff category */
+ } else {
+ v = -v;
+ arith_encode(cinfo, st + 1, 1); /* Table F.4: SS = S0 + 1 */
+ st += 3; /* Table F.4: SN = S0 + 3 */
+ entropy->dc_context[ci] = 8; /* small negative diff category */
+ }
+ /* Figure F.8: Encoding the magnitude category of v */
+ m = 0;
+ if (v -= 1) {
+ arith_encode(cinfo, st, 1);
+ m = 1;
+ v2 = v;
+ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+ while (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st += 1;
+ }
+ }
+ arith_encode(cinfo, st, 0);
+ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+ if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+ entropy->dc_context[ci] += 8; /* large diff category */
+ /* Figure F.9: Encoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ arith_encode(cinfo, st, (m & v) ? 1 : 0);
+ }
+
+ /* Sections F.1.4.2 & F.1.4.4.2: Encoding of AC coefficients */
+
+ if ((ke = cinfo->lim_Se) == 0) continue;
+ tbl = compptr->ac_tbl_no;
+
+ /* Establish EOB (end-of-block) index */
+ do {
+ if ((*block)[natural_order[ke]]) break;
+ } while (--ke);
+
+ /* Figure F.5: Encode_AC_Coefficients */
+ for (k = 0; k < ke;) {
+ st = entropy->ac_stats[tbl] + 3 * k;
+ arith_encode(cinfo, st, 0); /* EOB decision */
+ while ((v = (*block)[natural_order[++k]]) == 0) {
+ arith_encode(cinfo, st + 1, 0);
+ st += 3;
+ }
+ arith_encode(cinfo, st + 1, 1);
+ /* Figure F.6: Encoding nonzero value v */
+ /* Figure F.7: Encoding the sign of v */
+ if (v > 0) {
+ arith_encode(cinfo, entropy->fixed_bin, 0);
+ } else {
+ v = -v;
+ arith_encode(cinfo, entropy->fixed_bin, 1);
+ }
+ st += 2;
+ /* Figure F.8: Encoding the magnitude category of v */
+ m = 0;
+ if (v -= 1) {
+ arith_encode(cinfo, st, 1);
+ m = 1;
+ v2 = v;
+ if (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st = entropy->ac_stats[tbl] +
+ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+ while (v2 >>= 1) {
+ arith_encode(cinfo, st, 1);
+ m <<= 1;
+ st += 1;
+ }
+ }
+ }
+ arith_encode(cinfo, st, 0);
+ /* Figure F.9: Encoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ arith_encode(cinfo, st, (m & v) ? 1 : 0);
+ }
+ /* Encode EOB decision only if k < cinfo->lim_Se */
+ if (k < cinfo->lim_Se) {
+ st = entropy->ac_stats[tbl] + 3 * k;
+ arith_encode(cinfo, st, 1);
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Initialize for an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass (j_compress_ptr cinfo, boolean gather_statistics)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+
+ if (gather_statistics)
+ /* Make sure to avoid that in the master control logic!
+ * We are fully adaptive here and need no extra
+ * statistics gathering pass!
+ */
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+
+ /* We assume jcmaster.c already validated the progressive scan parameters. */
+
+ /* Select execution routines */
+ if (cinfo->progressive_mode) {
+ if (cinfo->Ah == 0) {
+ if (cinfo->Ss == 0)
+ entropy->pub.encode_mcu = encode_mcu_DC_first;
+ else
+ entropy->pub.encode_mcu = encode_mcu_AC_first;
+ } else {
+ if (cinfo->Ss == 0)
+ entropy->pub.encode_mcu = encode_mcu_DC_refine;
+ else
+ entropy->pub.encode_mcu = encode_mcu_AC_refine;
+ }
+ } else
+ entropy->pub.encode_mcu = encode_mcu;
+
+ /* Allocate & initialize requested statistics areas */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+ tbl = compptr->dc_tbl_no;
+ if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+ if (entropy->dc_stats[tbl] == NULL)
+ entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
+ MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+ /* Initialize DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ entropy->dc_context[ci] = 0;
+ }
+ /* AC needs no table when not present */
+ if (cinfo->Se) {
+ tbl = compptr->ac_tbl_no;
+ if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+ if (entropy->ac_stats[tbl] == NULL)
+ entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
+ MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+#ifdef CALCULATE_SPECTRAL_CONDITIONING
+ if (cinfo->progressive_mode)
+ /* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */
+ cinfo->arith_ac_K[tbl] = cinfo->Ss + ((8 + cinfo->Se - cinfo->Ss) >> 4);
+#endif
+ }
+ }
+
+ /* Initialize arithmetic encoding variables */
+ entropy->c = 0;
+ entropy->a = 0x10000L;
+ entropy->sc = 0;
+ entropy->zc = 0;
+ entropy->ct = 11;
+ entropy->buffer = -1; /* empty */
+
+ /* Initialize restart stuff */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num = 0;
+}
+
+
+/*
+ * Module initialization routine for arithmetic entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_arith_encoder (j_compress_ptr cinfo)
+{
+ arith_entropy_ptr entropy;
+ int i;
+
+ entropy = (arith_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(arith_entropy_encoder));
+ cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
+ entropy->pub.start_pass = start_pass;
+ entropy->pub.finish_pass = finish_pass;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ entropy->dc_stats[i] = NULL;
+ entropy->ac_stats[i] = NULL;
+ }
+
+ /* Initialize index for fixed probability estimation */
+ entropy->fixed_bin[0] = 113;
+}
diff --git a/jpg/jccoefct.c b/jpg/jccoefct.c
new file mode 100644
index 0000000..924a703
--- /dev/null
+++ b/jpg/jccoefct.c
@@ -0,0 +1,454 @@
+/*
+ * jccoefct.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2003-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the coefficient buffer controller for compression.
+ * This controller is the top level of the JPEG compressor proper.
+ * The coefficient buffer lies between forward-DCT and entropy encoding steps.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* We use a full-image coefficient buffer when doing Huffman optimization,
+ * and also for writing multiple-scan JPEG files. In all cases, the DCT
+ * step is run during the first pass, and subsequent passes need only read
+ * the buffered coefficients.
+ */
+#ifdef ENTROPY_OPT_SUPPORTED
+#define FULL_COEF_BUFFER_SUPPORTED
+#else
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+#define FULL_COEF_BUFFER_SUPPORTED
+#endif
+#endif
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_coef_controller pub; /* public fields */
+
+ JDIMENSION iMCU_row_num; /* iMCU row # within image */
+ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* For single-pass compression, it's sufficient to buffer just one MCU
+ * (although this may prove a bit slow in practice). We allocate a
+ * workspace of C_MAX_BLOCKS_IN_MCU coefficient blocks, and reuse it for each
+ * MCU constructed and sent. (On 80x86, the workspace is FAR even though
+ * it's not really very big; this is to keep the module interfaces unchanged
+ * when a large coefficient buffer is necessary.)
+ * In multi-pass modes, this array points to the current MCU's blocks
+ * within the virtual arrays.
+ */
+ JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
+
+ /* In multi-pass modes, we need a virtual block array for each component. */
+ jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+/* Forward declarations */
+METHODDEF(boolean) compress_data
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+METHODDEF(boolean) compress_first_pass
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+METHODDEF(boolean) compress_output
+ JPP((j_compress_ptr cinfo, JSAMPIMAGE input_buf));
+#endif
+
+
+LOCAL(void)
+start_iMCU_row (j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->mcu_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ coef->iMCU_row_num = 0;
+ start_iMCU_row(cinfo);
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (coef->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_data;
+ break;
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+ case JBUF_SAVE_AND_PASS:
+ if (coef->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_first_pass;
+ break;
+ case JBUF_CRANK_DEST:
+ if (coef->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ coef->pub.compress_data = compress_output;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data in the single-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the image.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(boolean)
+compress_data (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, bi, ci, yindex, yoffset, blockcnt;
+ JDIMENSION ypos, xpos;
+ jpeg_component_info *compptr;
+ forward_DCT_ptr forward_DCT;
+
+ /* Loop to write as much as one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num <= last_MCU_col;
+ MCU_col_num++) {
+ /* Determine where data comes from in input_buf and do the DCT thing.
+ * Each call on forward_DCT processes a horizontal row of DCT blocks
+ * as wide as an MCU; we rely on having allocated the MCU_buffer[] blocks
+ * sequentially. Dummy blocks at the right or bottom edge are filled in
+ * specially. The data in them does not matter for image reconstruction,
+ * so we fill them with values that will encode to the smallest amount of
+ * data, viz: all zeroes in the AC entries, DC entries equal to previous
+ * block's DC value. (Thanks to Thomas Kinsman for this idea.)
+ */
+ blkn = 0;
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ forward_DCT = cinfo->fdct->forward_DCT[compptr->component_index];
+ blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ xpos = MCU_col_num * compptr->MCU_sample_width;
+ ypos = yoffset * compptr->DCT_v_scaled_size;
+ /* ypos == (yoffset+yindex) * DCTSIZE */
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (coef->iMCU_row_num < last_iMCU_row ||
+ yoffset+yindex < compptr->last_row_height) {
+ (*forward_DCT) (cinfo, compptr,
+ input_buf[compptr->component_index],
+ coef->MCU_buffer[blkn],
+ ypos, xpos, (JDIMENSION) blockcnt);
+ if (blockcnt < compptr->MCU_width) {
+ /* Create some dummy blocks at the right edge of the image. */
+ FMEMZERO((void FAR *) coef->MCU_buffer[blkn + blockcnt],
+ (compptr->MCU_width - blockcnt) * SIZEOF(JBLOCK));
+ for (bi = blockcnt; bi < compptr->MCU_width; bi++) {
+ coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn+bi-1][0][0];
+ }
+ }
+ } else {
+ /* Create a row of dummy blocks at the bottom of the image. */
+ FMEMZERO((void FAR *) coef->MCU_buffer[blkn],
+ compptr->MCU_width * SIZEOF(JBLOCK));
+ for (bi = 0; bi < compptr->MCU_width; bi++) {
+ coef->MCU_buffer[blkn+bi][0][0] = coef->MCU_buffer[blkn-1][0][0];
+ }
+ }
+ blkn += compptr->MCU_width;
+ ypos += compptr->DCT_v_scaled_size;
+ }
+ }
+ /* Try to write the MCU. In event of a suspension failure, we will
+ * re-DCT the MCU on restart (a bit inefficient, could be fixed...)
+ */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+
+/*
+ * Process some data in the first pass of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the image.
+ * This amount of data is read from the source buffer, DCT'd and quantized,
+ * and saved into the virtual arrays. We also generate suitable dummy blocks
+ * as needed at the right and lower edges. (The dummy blocks are constructed
+ * in the virtual arrays, which have been padded appropriately.) This makes
+ * it possible for subsequent passes not to worry about real vs. dummy blocks.
+ *
+ * We must also emit the data to the entropy encoder. This is conveniently
+ * done by calling compress_output() after we've loaded the current strip
+ * of the virtual arrays.
+ *
+ * NB: input_buf contains a plane for each component in image. All
+ * components are DCT'd and loaded into the virtual arrays in this pass.
+ * However, it may be that only a subset of the components are emitted to
+ * the entropy encoder during this first pass; be careful about looking
+ * at the scan-dependent variables (MCU dimensions, etc).
+ */
+
+METHODDEF(boolean)
+compress_first_pass (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION blocks_across, MCUs_across, MCUindex;
+ int bi, ci, h_samp_factor, block_row, block_rows, ndummy;
+ JCOEF lastDC;
+ jpeg_component_info *compptr;
+ JBLOCKARRAY buffer;
+ JBLOCKROW thisblockrow, lastblockrow;
+ forward_DCT_ptr forward_DCT;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Align the virtual buffer for this component. */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (coef->iMCU_row_num < last_iMCU_row)
+ block_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here, since may not be set! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ }
+ blocks_across = compptr->width_in_blocks;
+ h_samp_factor = compptr->h_samp_factor;
+ /* Count number of dummy blocks to be added at the right margin. */
+ ndummy = (int) (blocks_across % h_samp_factor);
+ if (ndummy > 0)
+ ndummy = h_samp_factor - ndummy;
+ forward_DCT = cinfo->fdct->forward_DCT[ci];
+ /* Perform DCT for all non-dummy blocks in this iMCU row. Each call
+ * on forward_DCT processes a complete horizontal row of DCT blocks.
+ */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ thisblockrow = buffer[block_row];
+ (*forward_DCT) (cinfo, compptr, input_buf[ci], thisblockrow,
+ (JDIMENSION) (block_row * compptr->DCT_v_scaled_size),
+ (JDIMENSION) 0, blocks_across);
+ if (ndummy > 0) {
+ /* Create dummy blocks at the right edge of the image. */
+ thisblockrow += blocks_across; /* => first dummy block */
+ FMEMZERO((void FAR *) thisblockrow, ndummy * SIZEOF(JBLOCK));
+ lastDC = thisblockrow[-1][0];
+ for (bi = 0; bi < ndummy; bi++) {
+ thisblockrow[bi][0] = lastDC;
+ }
+ }
+ }
+ /* If at end of image, create dummy block rows as needed.
+ * The tricky part here is that within each MCU, we want the DC values
+ * of the dummy blocks to match the last real block's DC value.
+ * This squeezes a few more bytes out of the resulting file...
+ */
+ if (coef->iMCU_row_num == last_iMCU_row) {
+ blocks_across += ndummy; /* include lower right corner */
+ MCUs_across = blocks_across / h_samp_factor;
+ for (block_row = block_rows; block_row < compptr->v_samp_factor;
+ block_row++) {
+ thisblockrow = buffer[block_row];
+ lastblockrow = buffer[block_row-1];
+ FMEMZERO((void FAR *) thisblockrow,
+ (size_t) (blocks_across * SIZEOF(JBLOCK)));
+ for (MCUindex = 0; MCUindex < MCUs_across; MCUindex++) {
+ lastDC = lastblockrow[h_samp_factor-1][0];
+ for (bi = 0; bi < h_samp_factor; bi++) {
+ thisblockrow[bi][0] = lastDC;
+ }
+ thisblockrow += h_samp_factor; /* advance to next MCU in row */
+ lastblockrow += h_samp_factor;
+ }
+ }
+ }
+ }
+ /* NB: compress_output will increment iMCU_row_num if successful.
+ * A suspension return will result in redoing all the work above next time.
+ */
+
+ /* Emit data to the entropy encoder, sharing code with subsequent passes */
+ return compress_output(cinfo, input_buf);
+}
+
+
+/*
+ * Process some data in subsequent passes of a multi-pass case.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the entropy coder.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ int blkn, ci, xindex, yindex, yoffset;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan.
+ * NB: during first pass, this is safe only because the buffers will
+ * already be aligned properly, so jmemmgr.c won't need to do any I/O.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+ coef->MCU_buffer[blkn++] = buffer_ptr++;
+ }
+ }
+ }
+ /* Try to write the MCU. */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+#endif /* FULL_COEF_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize coefficient buffer controller.
+ */
+
+GLOBAL(void)
+jinit_c_coef_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_coef_ptr coef;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_c_coef_controller *) coef;
+ coef->pub.start_pass = start_pass_coef;
+
+ /* Create the coefficient buffer. */
+ if (need_full_buffer) {
+#ifdef FULL_COEF_BUFFER_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor DCT blocks in each direction. */
+ int ci;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+ (long) compptr->h_samp_factor),
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor),
+ (JDIMENSION) compptr->v_samp_factor);
+ }
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ } else {
+ /* We only need a single-MCU buffer. */
+ JBLOCKROW buffer;
+ int i;
+
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
+ coef->MCU_buffer[i] = buffer + i;
+ }
+ coef->whole_image[0] = NULL; /* flag for no virtual arrays */
+ }
+}
diff --git a/jpg/jccolor.c b/jpg/jccolor.c
new file mode 100644
index 0000000..3e2d0e9
--- /dev/null
+++ b/jpg/jccolor.c
@@ -0,0 +1,490 @@
+/*
+ * jccolor.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains input colorspace conversion routines.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_converter pub; /* public fields */
+
+ /* Private state for RGB->YCC conversion */
+ INT32 * rgb_ycc_tab; /* => table for RGB to YCbCr conversion */
+} my_color_converter;
+
+typedef my_color_converter * my_cconvert_ptr;
+
+
+/**************** RGB -> YCbCr conversion: most common case **************/
+
+/*
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
+ * Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
+ * Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
+ * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+ * Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
+ * rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
+ * negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
+ * were not represented exactly. Now we sacrifice exact representation of
+ * maximum red and maximum blue in order to get exact grayscales.
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times R,G,B for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 12-bit samples it is still acceptable. It's not very reasonable for
+ * 16-bit samples, but if you want lossless storage you shouldn't be changing
+ * colorspace anyway.
+ * The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
+ * in the tables to save adding them separately in the inner loop.
+ */
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define CBCR_OFFSET ((INT32) CENTERJSAMPLE << SCALEBITS)
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+/* We allocate one big table and divide it up into eight parts, instead of
+ * doing eight alloc_small requests. This lets us use a single table base
+ * address, which can be held in a register in the inner loops on many
+ * machines (more than can hold all eight addresses, anyway).
+ */
+
+#define R_Y_OFF 0 /* offset to R => Y section */
+#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */
+#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */
+#define R_CB_OFF (3*(MAXJSAMPLE+1))
+#define G_CB_OFF (4*(MAXJSAMPLE+1))
+#define B_CB_OFF (5*(MAXJSAMPLE+1))
+#define R_CR_OFF B_CB_OFF /* B=>Cb, R=>Cr are the same */
+#define G_CR_OFF (6*(MAXJSAMPLE+1))
+#define B_CR_OFF (7*(MAXJSAMPLE+1))
+#define TABLE_SIZE (8*(MAXJSAMPLE+1))
+
+
+/*
+ * Initialize for RGB->YCC colorspace conversion.
+ */
+
+METHODDEF(void)
+rgb_ycc_start (j_compress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ INT32 * rgb_ycc_tab;
+ INT32 i;
+
+ /* Allocate and fill in the conversion tables. */
+ cconvert->rgb_ycc_tab = rgb_ycc_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (TABLE_SIZE * SIZEOF(INT32)));
+
+ for (i = 0; i <= MAXJSAMPLE; i++) {
+ rgb_ycc_tab[i+R_Y_OFF] = FIX(0.29900) * i;
+ rgb_ycc_tab[i+G_Y_OFF] = FIX(0.58700) * i;
+ rgb_ycc_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
+ rgb_ycc_tab[i+R_CB_OFF] = (-FIX(0.16874)) * i;
+ rgb_ycc_tab[i+G_CB_OFF] = (-FIX(0.33126)) * i;
+ /* We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
+ * This ensures that the maximum output will round to MAXJSAMPLE
+ * not MAXJSAMPLE+1, and thus that we don't have to range-limit.
+ */
+ rgb_ycc_tab[i+B_CB_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
+/* B=>Cb and R=>Cr tables are the same
+ rgb_ycc_tab[i+R_CR_OFF] = FIX(0.50000) * i + CBCR_OFFSET + ONE_HALF-1;
+*/
+ rgb_ycc_tab[i+G_CR_OFF] = (-FIX(0.41869)) * i;
+ rgb_ycc_tab[i+B_CR_OFF] = (-FIX(0.08131)) * i;
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ *
+ * Note that we change from the application's interleaved-pixel format
+ * to our internal noninterleaved, one-plane-per-component format.
+ * The input buffer is therefore three times as wide as the output buffer.
+ *
+ * A starting row offset is provided only for the output buffer. The caller
+ * can easily adjust the passed input_buf value to accommodate any row
+ * offset required on that side.
+ */
+
+METHODDEF(void)
+rgb_ycc_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr0, outptr1, outptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr0 = output_buf[0][output_row];
+ outptr1 = output_buf[1][output_row];
+ outptr2 = output_buf[2][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = GETJSAMPLE(inptr[RGB_RED]);
+ g = GETJSAMPLE(inptr[RGB_GREEN]);
+ b = GETJSAMPLE(inptr[RGB_BLUE]);
+ inptr += RGB_PIXELSIZE;
+ /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ * must be too; we do not need an explicit range-limiting operation.
+ * Hence the value being shifted is never negative, and we don't
+ * need the general RIGHT_SHIFT macro.
+ */
+ /* Y */
+ outptr0[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ /* Cb */
+ outptr1[col] = (JSAMPLE)
+ ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
+ >> SCALEBITS);
+ /* Cr */
+ outptr2[col] = (JSAMPLE)
+ ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/**************** Cases other than RGB -> YCbCr **************/
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles RGB->grayscale conversion, which is the same
+ * as the RGB->Y portion of RGB->YCbCr.
+ * We assume rgb_ycc_start has been called (we only use the Y tables).
+ */
+
+METHODDEF(void)
+rgb_gray_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr = output_buf[0][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = GETJSAMPLE(inptr[RGB_RED]);
+ g = GETJSAMPLE(inptr[RGB_GREEN]);
+ b = GETJSAMPLE(inptr[RGB_BLUE]);
+ inptr += RGB_PIXELSIZE;
+ /* Y */
+ outptr[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles Adobe-style CMYK->YCCK conversion,
+ * where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same
+ * conversion as above, while passing K (black) unchanged.
+ * We assume rgb_ycc_start has been called.
+ */
+
+METHODDEF(void)
+cmyk_ycck_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_ycc_tab;
+ register JSAMPROW inptr;
+ register JSAMPROW outptr0, outptr1, outptr2, outptr3;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr0 = output_buf[0][output_row];
+ outptr1 = output_buf[1][output_row];
+ outptr2 = output_buf[2][output_row];
+ outptr3 = output_buf[3][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ r = MAXJSAMPLE - GETJSAMPLE(inptr[0]);
+ g = MAXJSAMPLE - GETJSAMPLE(inptr[1]);
+ b = MAXJSAMPLE - GETJSAMPLE(inptr[2]);
+ /* K passes through as-is */
+ outptr3[col] = inptr[3]; /* don't need GETJSAMPLE here */
+ inptr += 4;
+ /* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
+ * must be too; we do not need an explicit range-limiting operation.
+ * Hence the value being shifted is never negative, and we don't
+ * need the general RIGHT_SHIFT macro.
+ */
+ /* Y */
+ outptr0[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ /* Cb */
+ outptr1[col] = (JSAMPLE)
+ ((ctab[r+R_CB_OFF] + ctab[g+G_CB_OFF] + ctab[b+B_CB_OFF])
+ >> SCALEBITS);
+ /* Cr */
+ outptr2[col] = (JSAMPLE)
+ ((ctab[r+R_CR_OFF] + ctab[g+G_CR_OFF] + ctab[b+B_CR_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles grayscale output with no conversion.
+ * The source can be either plain grayscale or YCbCr (since Y == gray).
+ */
+
+METHODDEF(void)
+grayscale_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+ int instride = cinfo->input_components;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr = output_buf[0][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ outptr[col] = inptr[0]; /* don't need GETJSAMPLE() here */
+ inptr += instride;
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * No colorspace conversion, but change from interleaved
+ * to separate-planes representation.
+ */
+
+METHODDEF(void)
+rgb_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ register JSAMPROW inptr;
+ register JSAMPROW outptr0, outptr1, outptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ inptr = *input_buf++;
+ outptr0 = output_buf[0][output_row];
+ outptr1 = output_buf[1][output_row];
+ outptr2 = output_buf[2][output_row];
+ output_row++;
+ for (col = 0; col < num_cols; col++) {
+ /* We can dispense with GETJSAMPLE() here */
+ outptr0[col] = inptr[RGB_RED];
+ outptr1[col] = inptr[RGB_GREEN];
+ outptr2[col] = inptr[RGB_BLUE];
+ inptr += RGB_PIXELSIZE;
+ }
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the JPEG colorspace.
+ * This version handles multi-component colorspaces without conversion.
+ * We assume input_components == num_components.
+ */
+
+METHODDEF(void)
+null_convert (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows)
+{
+ register JSAMPROW inptr;
+ register JSAMPROW outptr;
+ register JDIMENSION col;
+ register int ci;
+ int nc = cinfo->num_components;
+ JDIMENSION num_cols = cinfo->image_width;
+
+ while (--num_rows >= 0) {
+ /* It seems fastest to make a separate pass for each component. */
+ for (ci = 0; ci < nc; ci++) {
+ inptr = *input_buf;
+ outptr = output_buf[ci][output_row];
+ for (col = 0; col < num_cols; col++) {
+ outptr[col] = inptr[ci]; /* don't need GETJSAMPLE() here */
+ inptr += nc;
+ }
+ }
+ input_buf++;
+ output_row++;
+ }
+}
+
+
+/*
+ * Empty method for start_pass.
+ */
+
+METHODDEF(void)
+null_method (j_compress_ptr cinfo)
+{
+ /* no work needed */
+}
+
+
+/*
+ * Module initialization routine for input colorspace conversion.
+ */
+
+GLOBAL(void)
+jinit_color_converter (j_compress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert;
+
+ cconvert = (my_cconvert_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_color_converter));
+ cinfo->cconvert = (struct jpeg_color_converter *) cconvert;
+ /* set start_pass to null method until we find out differently */
+ cconvert->pub.start_pass = null_method;
+
+ /* Make sure input_components agrees with in_color_space */
+ switch (cinfo->in_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->input_components != 1)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ case JCS_RGB:
+ if (cinfo->input_components != RGB_PIXELSIZE)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ case JCS_YCbCr:
+ if (cinfo->input_components != 3)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ if (cinfo->input_components != 4)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+
+ default: /* JCS_UNKNOWN can be anything */
+ if (cinfo->input_components < 1)
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ break;
+ }
+
+ /* Check num_components, set conversion method based on requested space */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->num_components != 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_GRAYSCALE ||
+ cinfo->in_color_space == JCS_YCbCr)
+ cconvert->pub.color_convert = grayscale_convert;
+ else if (cinfo->in_color_space == JCS_RGB) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = rgb_gray_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_RGB:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_RGB)
+ cconvert->pub.color_convert = rgb_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_YCbCr:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_RGB) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = rgb_ycc_convert;
+ } else if (cinfo->in_color_space == JCS_YCbCr)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_CMYK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_CMYK)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_YCCK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ if (cinfo->in_color_space == JCS_CMYK) {
+ cconvert->pub.start_pass = rgb_ycc_start;
+ cconvert->pub.color_convert = cmyk_ycck_convert;
+ } else if (cinfo->in_color_space == JCS_YCCK)
+ cconvert->pub.color_convert = null_convert;
+ else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ default: /* allow null conversion of JCS_UNKNOWN */
+ if (cinfo->jpeg_color_space != cinfo->in_color_space ||
+ cinfo->num_components != cinfo->input_components)
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ cconvert->pub.color_convert = null_convert;
+ break;
+ }
+}
diff --git a/jpg/jcdctmgr.c b/jpg/jcdctmgr.c
new file mode 100644
index 0000000..0bbdbb6
--- /dev/null
+++ b/jpg/jcdctmgr.c
@@ -0,0 +1,482 @@
+/*
+ * jcdctmgr.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the forward-DCT management logic.
+ * This code selects a particular DCT implementation to be used,
+ * and it performs related housekeeping chores including coefficient
+ * quantization.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+
+/* Private subobject for this module */
+
+typedef struct {
+ struct jpeg_forward_dct pub; /* public fields */
+
+ /* Pointer to the DCT routine actually in use */
+ forward_DCT_method_ptr do_dct[MAX_COMPONENTS];
+
+ /* The actual post-DCT divisors --- not identical to the quant table
+ * entries, because of scaling (especially for an unnormalized DCT).
+ * Each table is given in normal array order.
+ */
+ DCTELEM * divisors[NUM_QUANT_TBLS];
+
+#ifdef DCT_FLOAT_SUPPORTED
+ /* Same as above for the floating-point case. */
+ float_DCT_method_ptr do_float_dct[MAX_COMPONENTS];
+ FAST_FLOAT * float_divisors[NUM_QUANT_TBLS];
+#endif
+} my_fdct_controller;
+
+typedef my_fdct_controller * my_fdct_ptr;
+
+
+/* The current scaled-DCT routines require ISLOW-style divisor tables,
+ * so be sure to compile that code if either ISLOW or SCALING is requested.
+ */
+#ifdef DCT_ISLOW_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#else
+#ifdef DCT_SCALING_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#endif
+#endif
+
+
+/*
+ * Perform forward DCT on one or more blocks of a component.
+ *
+ * The input samples are taken from the sample_data[] array starting at
+ * position start_row/start_col, and moving to the right for any additional
+ * blocks. The quantized coefficients are returned in coef_blocks[].
+ */
+
+METHODDEF(void)
+forward_DCT (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks)
+/* This version is used for integer DCT implementations. */
+{
+ /* This routine is heavily used, so it's worth coding it tightly. */
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ forward_DCT_method_ptr do_dct = fdct->do_dct[compptr->component_index];
+ DCTELEM * divisors = fdct->divisors[compptr->quant_tbl_no];
+ DCTELEM workspace[DCTSIZE2]; /* work area for FDCT subroutine */
+ JDIMENSION bi;
+
+ sample_data += start_row; /* fold in the vertical offset once */
+
+ for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {
+ /* Perform the DCT */
+ (*do_dct) (workspace, sample_data, start_col);
+
+ /* Quantize/descale the coefficients, and store into coef_blocks[] */
+ { register DCTELEM temp, qval;
+ register int i;
+ register JCOEFPTR output_ptr = coef_blocks[bi];
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ qval = divisors[i];
+ temp = workspace[i];
+ /* Divide the coefficient value by qval, ensuring proper rounding.
+ * Since C does not specify the direction of rounding for negative
+ * quotients, we have to force the dividend positive for portability.
+ *
+ * In most files, at least half of the output values will be zero
+ * (at default quantization settings, more like three-quarters...)
+ * so we should ensure that this case is fast. On many machines,
+ * a comparison is enough cheaper than a divide to make a special test
+ * a win. Since both inputs will be nonnegative, we need only test
+ * for a < b to discover whether a/b is 0.
+ * If your machine's division is fast enough, define FAST_DIVIDE.
+ */
+#ifdef FAST_DIVIDE
+#define DIVIDE_BY(a,b) a /= b
+#else
+#define DIVIDE_BY(a,b) if (a >= b) a /= b; else a = 0
+#endif
+ if (temp < 0) {
+ temp = -temp;
+ temp += qval>>1; /* for rounding */
+ DIVIDE_BY(temp, qval);
+ temp = -temp;
+ } else {
+ temp += qval>>1; /* for rounding */
+ DIVIDE_BY(temp, qval);
+ }
+ output_ptr[i] = (JCOEF) temp;
+ }
+ }
+ }
+}
+
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+METHODDEF(void)
+forward_DCT_float (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks)
+/* This version is used for floating-point DCT implementations. */
+{
+ /* This routine is heavily used, so it's worth coding it tightly. */
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ float_DCT_method_ptr do_dct = fdct->do_float_dct[compptr->component_index];
+ FAST_FLOAT * divisors = fdct->float_divisors[compptr->quant_tbl_no];
+ FAST_FLOAT workspace[DCTSIZE2]; /* work area for FDCT subroutine */
+ JDIMENSION bi;
+
+ sample_data += start_row; /* fold in the vertical offset once */
+
+ for (bi = 0; bi < num_blocks; bi++, start_col += compptr->DCT_h_scaled_size) {
+ /* Perform the DCT */
+ (*do_dct) (workspace, sample_data, start_col);
+
+ /* Quantize/descale the coefficients, and store into coef_blocks[] */
+ { register FAST_FLOAT temp;
+ register int i;
+ register JCOEFPTR output_ptr = coef_blocks[bi];
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ /* Apply the quantization and scaling factor */
+ temp = workspace[i] * divisors[i];
+ /* Round to nearest integer.
+ * Since C does not specify the direction of rounding for negative
+ * quotients, we have to force the dividend positive for portability.
+ * The maximum coefficient size is +-16K (for 12-bit data), so this
+ * code should work for either 16-bit or 32-bit ints.
+ */
+ output_ptr[i] = (JCOEF) ((int) (temp + (FAST_FLOAT) 16384.5) - 16384);
+ }
+ }
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
+
+
+/*
+ * Initialize for a processing pass.
+ * Verify that all referenced Q-tables are present, and set up
+ * the divisor table for each one.
+ * In the current implementation, DCT of all components is done during
+ * the first pass, even if only some components will be output in the
+ * first scan. Hence all components should be examined here.
+ */
+
+METHODDEF(void)
+start_pass_fdctmgr (j_compress_ptr cinfo)
+{
+ my_fdct_ptr fdct = (my_fdct_ptr) cinfo->fdct;
+ int ci, qtblno, i;
+ jpeg_component_info *compptr;
+ int method = 0;
+ JQUANT_TBL * qtbl;
+ DCTELEM * dtbl;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Select the proper DCT routine for this component's scaling */
+ switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {
+#ifdef DCT_SCALING_SUPPORTED
+ case ((1 << 8) + 1):
+ fdct->do_dct[ci] = jpeg_fdct_1x1;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((2 << 8) + 2):
+ fdct->do_dct[ci] = jpeg_fdct_2x2;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((3 << 8) + 3):
+ fdct->do_dct[ci] = jpeg_fdct_3x3;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((4 << 8) + 4):
+ fdct->do_dct[ci] = jpeg_fdct_4x4;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((5 << 8) + 5):
+ fdct->do_dct[ci] = jpeg_fdct_5x5;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((6 << 8) + 6):
+ fdct->do_dct[ci] = jpeg_fdct_6x6;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((7 << 8) + 7):
+ fdct->do_dct[ci] = jpeg_fdct_7x7;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((9 << 8) + 9):
+ fdct->do_dct[ci] = jpeg_fdct_9x9;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((10 << 8) + 10):
+ fdct->do_dct[ci] = jpeg_fdct_10x10;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((11 << 8) + 11):
+ fdct->do_dct[ci] = jpeg_fdct_11x11;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((12 << 8) + 12):
+ fdct->do_dct[ci] = jpeg_fdct_12x12;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((13 << 8) + 13):
+ fdct->do_dct[ci] = jpeg_fdct_13x13;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((14 << 8) + 14):
+ fdct->do_dct[ci] = jpeg_fdct_14x14;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((15 << 8) + 15):
+ fdct->do_dct[ci] = jpeg_fdct_15x15;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((16 << 8) + 16):
+ fdct->do_dct[ci] = jpeg_fdct_16x16;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((16 << 8) + 8):
+ fdct->do_dct[ci] = jpeg_fdct_16x8;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((14 << 8) + 7):
+ fdct->do_dct[ci] = jpeg_fdct_14x7;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((12 << 8) + 6):
+ fdct->do_dct[ci] = jpeg_fdct_12x6;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((10 << 8) + 5):
+ fdct->do_dct[ci] = jpeg_fdct_10x5;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((8 << 8) + 4):
+ fdct->do_dct[ci] = jpeg_fdct_8x4;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((6 << 8) + 3):
+ fdct->do_dct[ci] = jpeg_fdct_6x3;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((4 << 8) + 2):
+ fdct->do_dct[ci] = jpeg_fdct_4x2;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((2 << 8) + 1):
+ fdct->do_dct[ci] = jpeg_fdct_2x1;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((8 << 8) + 16):
+ fdct->do_dct[ci] = jpeg_fdct_8x16;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((7 << 8) + 14):
+ fdct->do_dct[ci] = jpeg_fdct_7x14;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((6 << 8) + 12):
+ fdct->do_dct[ci] = jpeg_fdct_6x12;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((5 << 8) + 10):
+ fdct->do_dct[ci] = jpeg_fdct_5x10;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((4 << 8) + 8):
+ fdct->do_dct[ci] = jpeg_fdct_4x8;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((3 << 8) + 6):
+ fdct->do_dct[ci] = jpeg_fdct_3x6;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((2 << 8) + 4):
+ fdct->do_dct[ci] = jpeg_fdct_2x4;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+ case ((1 << 8) + 2):
+ fdct->do_dct[ci] = jpeg_fdct_1x2;
+ method = JDCT_ISLOW; /* jfdctint uses islow-style table */
+ break;
+#endif
+ case ((DCTSIZE << 8) + DCTSIZE):
+ switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+ case JDCT_ISLOW:
+ fdct->do_dct[ci] = jpeg_fdct_islow;
+ method = JDCT_ISLOW;
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ fdct->do_dct[ci] = jpeg_fdct_ifast;
+ method = JDCT_IFAST;
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ fdct->do_float_dct[ci] = jpeg_fdct_float;
+ method = JDCT_FLOAT;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ break;
+ default:
+ ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+ compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);
+ break;
+ }
+ qtblno = compptr->quant_tbl_no;
+ /* Make sure specified quantization table is present */
+ if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
+ cinfo->quant_tbl_ptrs[qtblno] == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+ qtbl = cinfo->quant_tbl_ptrs[qtblno];
+ /* Compute divisors for this quant table */
+ /* We may do this more than once for same table, but it's not a big deal */
+ switch (method) {
+#ifdef PROVIDE_ISLOW_TABLES
+ case JDCT_ISLOW:
+ /* For LL&M IDCT method, divisors are equal to raw quantization
+ * coefficients multiplied by 8 (to counteract scaling).
+ */
+ if (fdct->divisors[qtblno] == NULL) {
+ fdct->divisors[qtblno] = (DCTELEM *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(DCTELEM));
+ }
+ dtbl = fdct->divisors[qtblno];
+ for (i = 0; i < DCTSIZE2; i++) {
+ dtbl[i] = ((DCTELEM) qtbl->quantval[i]) << 3;
+ }
+ fdct->pub.forward_DCT[ci] = forward_DCT;
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ {
+ /* For AA&N IDCT method, divisors are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 8.
+ */
+#define CONST_BITS 14
+ static const INT16 aanscales[DCTSIZE2] = {
+ /* precomputed values scaled up by 14 bits */
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
+ 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
+ 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
+ 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
+ 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
+ };
+ SHIFT_TEMPS
+
+ if (fdct->divisors[qtblno] == NULL) {
+ fdct->divisors[qtblno] = (DCTELEM *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(DCTELEM));
+ }
+ dtbl = fdct->divisors[qtblno];
+ for (i = 0; i < DCTSIZE2; i++) {
+ dtbl[i] = (DCTELEM)
+ DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
+ (INT32) aanscales[i]),
+ CONST_BITS-3);
+ }
+ }
+ fdct->pub.forward_DCT[ci] = forward_DCT;
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ {
+ /* For float AA&N IDCT method, divisors are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 8.
+ * What's actually stored is 1/divisor so that the inner loop can
+ * use a multiplication rather than a division.
+ */
+ FAST_FLOAT * fdtbl;
+ int row, col;
+ static const double aanscalefactor[DCTSIZE] = {
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ };
+
+ if (fdct->float_divisors[qtblno] == NULL) {
+ fdct->float_divisors[qtblno] = (FAST_FLOAT *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ DCTSIZE2 * SIZEOF(FAST_FLOAT));
+ }
+ fdtbl = fdct->float_divisors[qtblno];
+ i = 0;
+ for (row = 0; row < DCTSIZE; row++) {
+ for (col = 0; col < DCTSIZE; col++) {
+ fdtbl[i] = (FAST_FLOAT)
+ (1.0 / (((double) qtbl->quantval[i] *
+ aanscalefactor[row] * aanscalefactor[col] * 8.0)));
+ i++;
+ }
+ }
+ }
+ fdct->pub.forward_DCT[ci] = forward_DCT_float;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Initialize FDCT manager.
+ */
+
+GLOBAL(void)
+jinit_forward_dct (j_compress_ptr cinfo)
+{
+ my_fdct_ptr fdct;
+ int i;
+
+ fdct = (my_fdct_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_fdct_controller));
+ cinfo->fdct = (struct jpeg_forward_dct *) fdct;
+ fdct->pub.start_pass = start_pass_fdctmgr;
+
+ /* Mark divisor tables unallocated */
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ fdct->divisors[i] = NULL;
+#ifdef DCT_FLOAT_SUPPORTED
+ fdct->float_divisors[i] = NULL;
+#endif
+ }
+}
diff --git a/jpg/jchuff.c b/jpg/jchuff.c
new file mode 100644
index 0000000..257d7aa
--- /dev/null
+++ b/jpg/jchuff.c
@@ -0,0 +1,1576 @@
+/*
+ * jchuff.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2006-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy encoding routines.
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Much of the complexity here has to do with supporting output suspension.
+ * If the data destination module demands suspension, we want to be able to
+ * back up to the start of the current MCU. To do this, we copy state
+ * variables into local working storage, and update them back to the
+ * permanent JPEG objects only upon successful completion of an MCU.
+ *
+ * We do not support output suspension for the progressive JPEG mode, since
+ * the library currently does not allow multiple-scan files to be written
+ * with output suspension.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* The legal range of a DCT coefficient is
+ * -1024 .. +1023 for 8-bit data;
+ * -16384 .. +16383 for 12-bit data.
+ * Hence the magnitude should always fit in 10 or 14 bits respectively.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MAX_COEF_BITS 10
+#else
+#define MAX_COEF_BITS 14
+#endif
+
+/* Derived data constructed for each Huffman table */
+
+typedef struct {
+ unsigned int ehufco[256]; /* code for each symbol */
+ char ehufsi[256]; /* length of code for each symbol */
+ /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */
+} c_derived_tbl;
+
+
+/* Expanded entropy encoder object for Huffman encoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ INT32 put_buffer; /* current bit-accumulation buffer */
+ int put_bits; /* # of bits now in it */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment. You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src) ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src) \
+ ((dest).put_buffer = (src).put_buffer, \
+ (dest).put_bits = (src).put_bits, \
+ (dest).last_dc_val[0] = (src).last_dc_val[0], \
+ (dest).last_dc_val[1] = (src).last_dc_val[1], \
+ (dest).last_dc_val[2] = (src).last_dc_val[2], \
+ (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+ struct jpeg_entropy_encoder pub; /* public fields */
+
+ savable_state saved; /* Bit buffer & DC state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+ int next_restart_num; /* next restart number to write (0-7) */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ c_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
+ c_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
+
+ /* Statistics tables for optimization */
+ long * dc_count_ptrs[NUM_HUFF_TBLS];
+ long * ac_count_ptrs[NUM_HUFF_TBLS];
+
+ /* Following fields used only in progressive mode */
+
+ /* Mode flag: TRUE for optimization, FALSE for actual data output */
+ boolean gather_statistics;
+
+ /* next_output_byte/free_in_buffer are local copies of cinfo->dest fields.
+ */
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+ j_compress_ptr cinfo; /* link to cinfo (needed for dump_buffer) */
+
+ /* Coding status for AC components */
+ int ac_tbl_no; /* the table number of the single component */
+ unsigned int EOBRUN; /* run length of EOBs */
+ unsigned int BE; /* # of buffered correction bits before MCU */
+ char * bit_buffer; /* buffer for correction bits (1 per char) */
+ /* packing correction bits tightly would save some space but cost time... */
+} huff_entropy_encoder;
+
+typedef huff_entropy_encoder * huff_entropy_ptr;
+
+/* Working state while writing an MCU (sequential mode).
+ * This struct contains all the fields that are needed by subroutines.
+ */
+
+typedef struct {
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+ savable_state cur; /* Current bit buffer & DC state */
+ j_compress_ptr cinfo; /* dump_buffer needs access to this */
+} working_state;
+
+/* MAX_CORR_BITS is the number of bits the AC refinement correction-bit
+ * buffer can hold. Larger sizes may slightly improve compression, but
+ * 1000 is already well into the realm of overkill.
+ * The minimum safe size is 64 bits.
+ */
+
+#define MAX_CORR_BITS 1000 /* Max # of correction bits I can buffer */
+
+/* IRIGHT_SHIFT is like RIGHT_SHIFT, but works on int rather than INT32.
+ * We assume that int right shift is unsigned if INT32 right shift is,
+ * which should be safe.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS int ishift_temp;
+#define IRIGHT_SHIFT(x,shft) \
+ ((ishift_temp = (x)) < 0 ? \
+ (ishift_temp >> (shft)) | ((~0) << (16-(shft))) : \
+ (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+
+/*
+ * Compute the derived values for a Huffman table.
+ * This routine also performs some validation checks on the table.
+ */
+
+LOCAL(void)
+jpeg_make_c_derived_tbl (j_compress_ptr cinfo, boolean isDC, int tblno,
+ c_derived_tbl ** pdtbl)
+{
+ JHUFF_TBL *htbl;
+ c_derived_tbl *dtbl;
+ int p, i, l, lastp, si, maxsymbol;
+ char huffsize[257];
+ unsigned int huffcode[257];
+ unsigned int code;
+
+ /* Note that huffsize[] and huffcode[] are filled in code-length order,
+ * paralleling the order of the symbols themselves in htbl->huffval[].
+ */
+
+ /* Find the input Huffman table */
+ if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+ htbl =
+ isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];
+ if (htbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+
+ /* Allocate a workspace if we haven't already done so. */
+ if (*pdtbl == NULL)
+ *pdtbl = (c_derived_tbl *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(c_derived_tbl));
+ dtbl = *pdtbl;
+
+ /* Figure C.1: make table of Huffman code length for each symbol */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ i = (int) htbl->bits[l];
+ if (i < 0 || p + i > 256) /* protect against table overrun */
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ while (i--)
+ huffsize[p++] = (char) l;
+ }
+ huffsize[p] = 0;
+ lastp = p;
+
+ /* Figure C.2: generate the codes themselves */
+ /* We also validate that the counts represent a legal Huffman code tree. */
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p]) {
+ while (((int) huffsize[p]) == si) {
+ huffcode[p++] = code;
+ code++;
+ }
+ /* code is now 1 more than the last code used for codelength si; but
+ * it must still fit in si bits, since no code is allowed to be all ones.
+ */
+ if (((INT32) code) >= (((INT32) 1) << si))
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ code <<= 1;
+ si++;
+ }
+
+ /* Figure C.3: generate encoding tables */
+ /* These are code and size indexed by symbol value */
+
+ /* Set all codeless symbols to have code length 0;
+ * this lets us detect duplicate VAL entries here, and later
+ * allows emit_bits to detect any attempt to emit such symbols.
+ */
+ MEMZERO(dtbl->ehufsi, SIZEOF(dtbl->ehufsi));
+
+ /* This is also a convenient place to check for out-of-range
+ * and duplicated VAL entries. We allow 0..255 for AC symbols
+ * but only 0..15 for DC. (We could constrain them further
+ * based on data depth and mode, but this seems enough.)
+ */
+ maxsymbol = isDC ? 15 : 255;
+
+ for (p = 0; p < lastp; p++) {
+ i = htbl->huffval[p];
+ if (i < 0 || i > maxsymbol || dtbl->ehufsi[i])
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ dtbl->ehufco[i] = huffcode[p];
+ dtbl->ehufsi[i] = huffsize[p];
+ }
+}
+
+
+/* Outputting bytes to the file.
+ * NB: these must be called only when actually outputting,
+ * that is, entropy->gather_statistics == FALSE.
+ */
+
+/* Emit a byte, taking 'action' if must suspend. */
+#define emit_byte_s(state,val,action) \
+ { *(state)->next_output_byte++ = (JOCTET) (val); \
+ if (--(state)->free_in_buffer == 0) \
+ if (! dump_buffer_s(state)) \
+ { action; } }
+
+/* Emit a byte */
+#define emit_byte_e(entropy,val) \
+ { *(entropy)->next_output_byte++ = (JOCTET) (val); \
+ if (--(entropy)->free_in_buffer == 0) \
+ dump_buffer_e(entropy); }
+
+
+LOCAL(boolean)
+dump_buffer_s (working_state * state)
+/* Empty the output buffer; return TRUE if successful, FALSE if must suspend */
+{
+ struct jpeg_destination_mgr * dest = state->cinfo->dest;
+
+ if (! (*dest->empty_output_buffer) (state->cinfo))
+ return FALSE;
+ /* After a successful buffer dump, must reset buffer pointers */
+ state->next_output_byte = dest->next_output_byte;
+ state->free_in_buffer = dest->free_in_buffer;
+ return TRUE;
+}
+
+
+LOCAL(void)
+dump_buffer_e (huff_entropy_ptr entropy)
+/* Empty the output buffer; we do not support suspension in this case. */
+{
+ struct jpeg_destination_mgr * dest = entropy->cinfo->dest;
+
+ if (! (*dest->empty_output_buffer) (entropy->cinfo))
+ ERREXIT(entropy->cinfo, JERR_CANT_SUSPEND);
+ /* After a successful buffer dump, must reset buffer pointers */
+ entropy->next_output_byte = dest->next_output_byte;
+ entropy->free_in_buffer = dest->free_in_buffer;
+}
+
+
+/* Outputting bits to the file */
+
+/* Only the right 24 bits of put_buffer are used; the valid bits are
+ * left-justified in this part. At most 16 bits can be passed to emit_bits
+ * in one call, and we never retain more than 7 bits in put_buffer
+ * between calls, so 24 bits are sufficient.
+ */
+
+INLINE
+LOCAL(boolean)
+emit_bits_s (working_state * state, unsigned int code, int size)
+/* Emit some bits; return TRUE if successful, FALSE if must suspend */
+{
+ /* This routine is heavily used, so it's worth coding tightly. */
+ register INT32 put_buffer = (INT32) code;
+ register int put_bits = state->cur.put_bits;
+
+ /* if size is 0, caller used an invalid Huffman table entry */
+ if (size == 0)
+ ERREXIT(state->cinfo, JERR_HUFF_MISSING_CODE);
+
+ put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
+
+ put_bits += size; /* new number of bits in buffer */
+
+ put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+ put_buffer |= state->cur.put_buffer; /* and merge with old buffer contents */
+
+ while (put_bits >= 8) {
+ int c = (int) ((put_buffer >> 16) & 0xFF);
+
+ emit_byte_s(state, c, return FALSE);
+ if (c == 0xFF) { /* need to stuff a zero byte? */
+ emit_byte_s(state, 0, return FALSE);
+ }
+ put_buffer <<= 8;
+ put_bits -= 8;
+ }
+
+ state->cur.put_buffer = put_buffer; /* update state variables */
+ state->cur.put_bits = put_bits;
+
+ return TRUE;
+}
+
+
+INLINE
+LOCAL(void)
+emit_bits_e (huff_entropy_ptr entropy, unsigned int code, int size)
+/* Emit some bits, unless we are in gather mode */
+{
+ /* This routine is heavily used, so it's worth coding tightly. */
+ register INT32 put_buffer = (INT32) code;
+ register int put_bits = entropy->saved.put_bits;
+
+ /* if size is 0, caller used an invalid Huffman table entry */
+ if (size == 0)
+ ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
+
+ if (entropy->gather_statistics)
+ return; /* do nothing if we're only getting stats */
+
+ put_buffer &= (((INT32) 1)<<size) - 1; /* mask off any extra bits in code */
+
+ put_bits += size; /* new number of bits in buffer */
+
+ put_buffer <<= 24 - put_bits; /* align incoming bits */
+
+ /* and merge with old buffer contents */
+ put_buffer |= entropy->saved.put_buffer;
+
+ while (put_bits >= 8) {
+ int c = (int) ((put_buffer >> 16) & 0xFF);
+
+ emit_byte_e(entropy, c);
+ if (c == 0xFF) { /* need to stuff a zero byte? */
+ emit_byte_e(entropy, 0);
+ }
+ put_buffer <<= 8;
+ put_bits -= 8;
+ }
+
+ entropy->saved.put_buffer = put_buffer; /* update variables */
+ entropy->saved.put_bits = put_bits;
+}
+
+
+LOCAL(boolean)
+flush_bits_s (working_state * state)
+{
+ if (! emit_bits_s(state, 0x7F, 7)) /* fill any partial byte with ones */
+ return FALSE;
+ state->cur.put_buffer = 0; /* and reset bit-buffer to empty */
+ state->cur.put_bits = 0;
+ return TRUE;
+}
+
+
+LOCAL(void)
+flush_bits_e (huff_entropy_ptr entropy)
+{
+ emit_bits_e(entropy, 0x7F, 7); /* fill any partial byte with ones */
+ entropy->saved.put_buffer = 0; /* and reset bit-buffer to empty */
+ entropy->saved.put_bits = 0;
+}
+
+
+/*
+ * Emit (or just count) a Huffman symbol.
+ */
+
+INLINE
+LOCAL(void)
+emit_dc_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol)
+{
+ if (entropy->gather_statistics)
+ entropy->dc_count_ptrs[tbl_no][symbol]++;
+ else {
+ c_derived_tbl * tbl = entropy->dc_derived_tbls[tbl_no];
+ emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
+ }
+}
+
+
+INLINE
+LOCAL(void)
+emit_ac_symbol (huff_entropy_ptr entropy, int tbl_no, int symbol)
+{
+ if (entropy->gather_statistics)
+ entropy->ac_count_ptrs[tbl_no][symbol]++;
+ else {
+ c_derived_tbl * tbl = entropy->ac_derived_tbls[tbl_no];
+ emit_bits_e(entropy, tbl->ehufco[symbol], tbl->ehufsi[symbol]);
+ }
+}
+
+
+/*
+ * Emit bits from a correction bit buffer.
+ */
+
+LOCAL(void)
+emit_buffered_bits (huff_entropy_ptr entropy, char * bufstart,
+ unsigned int nbits)
+{
+ if (entropy->gather_statistics)
+ return; /* no real work */
+
+ while (nbits > 0) {
+ emit_bits_e(entropy, (unsigned int) (*bufstart), 1);
+ bufstart++;
+ nbits--;
+ }
+}
+
+
+/*
+ * Emit any pending EOBRUN symbol.
+ */
+
+LOCAL(void)
+emit_eobrun (huff_entropy_ptr entropy)
+{
+ register int temp, nbits;
+
+ if (entropy->EOBRUN > 0) { /* if there is any pending EOBRUN */
+ temp = entropy->EOBRUN;
+ nbits = 0;
+ while ((temp >>= 1))
+ nbits++;
+ /* safety check: shouldn't happen given limited correction-bit buffer */
+ if (nbits > 14)
+ ERREXIT(entropy->cinfo, JERR_HUFF_MISSING_CODE);
+
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, nbits << 4);
+ if (nbits)
+ emit_bits_e(entropy, entropy->EOBRUN, nbits);
+
+ entropy->EOBRUN = 0;
+
+ /* Emit any buffered correction bits */
+ emit_buffered_bits(entropy, entropy->bit_buffer, entropy->BE);
+ entropy->BE = 0;
+ }
+}
+
+
+/*
+ * Emit a restart marker & resynchronize predictions.
+ */
+
+LOCAL(boolean)
+emit_restart_s (working_state * state, int restart_num)
+{
+ int ci;
+
+ if (! flush_bits_s(state))
+ return FALSE;
+
+ emit_byte_s(state, 0xFF, return FALSE);
+ emit_byte_s(state, JPEG_RST0 + restart_num, return FALSE);
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < state->cinfo->comps_in_scan; ci++)
+ state->cur.last_dc_val[ci] = 0;
+
+ /* The restart counter is not updated until we successfully write the MCU. */
+
+ return TRUE;
+}
+
+
+LOCAL(void)
+emit_restart_e (huff_entropy_ptr entropy, int restart_num)
+{
+ int ci;
+
+ emit_eobrun(entropy);
+
+ if (! entropy->gather_statistics) {
+ flush_bits_e(entropy);
+ emit_byte_e(entropy, 0xFF);
+ emit_byte_e(entropy, JPEG_RST0 + restart_num);
+ }
+
+ if (entropy->cinfo->Ss == 0) {
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < entropy->cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ } else {
+ /* Re-initialize all AC-related fields to 0 */
+ entropy->EOBRUN = 0;
+ entropy->BE = 0;
+ }
+}
+
+
+/*
+ * MCU encoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int temp, temp2;
+ register int nbits;
+ int blkn, ci;
+ int Al = cinfo->Al;
+ JBLOCKROW block;
+ jpeg_component_info * compptr;
+ ISHIFT_TEMPS
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart_e(entropy, entropy->next_restart_num);
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+
+ /* Compute the DC value after the required point transform by Al.
+ * This is simply an arithmetic right shift.
+ */
+ temp2 = IRIGHT_SHIFT((int) ((*block)[0]), Al);
+
+ /* DC differences are figured on the point-transformed values. */
+ temp = temp2 - entropy->saved.last_dc_val[ci];
+ entropy->saved.last_dc_val[ci] = temp2;
+
+ /* Encode the DC coefficient difference per section G.1.2.1 */
+ temp2 = temp;
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* For a negative input, want temp2 = bitwise complement of abs(input) */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range coefficient values.
+ * Since we're encoding a difference, the range limit is twice as much.
+ */
+ if (nbits > MAX_COEF_BITS+1)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count/emit the Huffman-coded symbol for the number of bits */
+ emit_dc_symbol(entropy, compptr->dc_tbl_no, nbits);
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (nbits) /* emit_bits rejects calls with size 0 */
+ emit_bits_e(entropy, (unsigned int) temp2, nbits);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_first (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int temp, temp2;
+ register int nbits;
+ register int r, k;
+ int Se, Al;
+ const int * natural_order;
+ JBLOCKROW block;
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart_e(entropy, entropy->next_restart_num);
+
+ Se = cinfo->Se;
+ Al = cinfo->Al;
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+
+ /* Encode the AC coefficients per section G.1.2.2, fig. G.3 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ if ((temp = (*block)[natural_order[k]]) == 0) {
+ r++;
+ continue;
+ }
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value; so the code is
+ * interwoven with finding the abs value (temp) and output bits (temp2).
+ */
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ temp >>= Al; /* apply the point transform */
+ /* For a negative coef, want temp2 = bitwise complement of abs(coef) */
+ temp2 = ~temp;
+ } else {
+ temp >>= Al; /* apply the point transform */
+ temp2 = temp;
+ }
+ /* Watch out for case that nonzero coef is zero after point transform */
+ if (temp == 0) {
+ r++;
+ continue;
+ }
+
+ /* Emit any pending EOBRUN */
+ if (entropy->EOBRUN > 0)
+ emit_eobrun(entropy);
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0);
+ r -= 16;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+ /* Check for out-of-range coefficient values */
+ if (nbits > MAX_COEF_BITS)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count/emit Huffman symbol for run length / number of bits */
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + nbits);
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ emit_bits_e(entropy, (unsigned int) temp2, nbits);
+
+ r = 0; /* reset zero run length */
+ }
+
+ if (r > 0) { /* If there are trailing zeroes, */
+ entropy->EOBRUN++; /* count an EOB */
+ if (entropy->EOBRUN == 0x7FFF)
+ emit_eobrun(entropy); /* force it out to avoid overflow */
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component, although the spec
+ * is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+encode_mcu_DC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int temp;
+ int blkn;
+ int Al = cinfo->Al;
+ JBLOCKROW block;
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart_e(entropy, entropy->next_restart_num);
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+
+ /* We simply emit the Al'th bit of the DC coefficient value. */
+ temp = (*block)[0];
+ emit_bits_e(entropy, (unsigned int) (temp >> Al), 1);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU encoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+encode_mcu_AC_refine (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int temp;
+ register int r, k;
+ int EOB;
+ char *BR_buffer;
+ unsigned int BR;
+ int Se, Al;
+ const int * natural_order;
+ JBLOCKROW block;
+ int absvalues[DCTSIZE2];
+
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval)
+ if (entropy->restarts_to_go == 0)
+ emit_restart_e(entropy, entropy->next_restart_num);
+
+ Se = cinfo->Se;
+ Al = cinfo->Al;
+ natural_order = cinfo->natural_order;
+
+ /* Encode the MCU data block */
+ block = MCU_data[0];
+
+ /* It is convenient to make a pre-pass to determine the transformed
+ * coefficients' absolute values and the EOB position.
+ */
+ EOB = 0;
+ for (k = cinfo->Ss; k <= Se; k++) {
+ temp = (*block)[natural_order[k]];
+ /* We must apply the point transform by Al. For AC coefficients this
+ * is an integer division with rounding towards 0. To do this portably
+ * in C, we shift after obtaining the absolute value.
+ */
+ if (temp < 0)
+ temp = -temp; /* temp is abs value of input */
+ temp >>= Al; /* apply the point transform */
+ absvalues[k] = temp; /* save abs value for main pass */
+ if (temp == 1)
+ EOB = k; /* EOB = index of last newly-nonzero coef */
+ }
+
+ /* Encode the AC coefficients per section G.1.2.3, fig. G.7 */
+
+ r = 0; /* r = run length of zeros */
+ BR = 0; /* BR = count of buffered bits added now */
+ BR_buffer = entropy->bit_buffer + entropy->BE; /* Append bits to buffer */
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ if ((temp = absvalues[k]) == 0) {
+ r++;
+ continue;
+ }
+
+ /* Emit any required ZRLs, but not if they can be folded into EOB */
+ while (r > 15 && k <= EOB) {
+ /* emit any pending EOBRUN and the BE correction bits */
+ emit_eobrun(entropy);
+ /* Emit ZRL */
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, 0xF0);
+ r -= 16;
+ /* Emit buffered correction bits that must be associated with ZRL */
+ emit_buffered_bits(entropy, BR_buffer, BR);
+ BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
+ BR = 0;
+ }
+
+ /* If the coef was previously nonzero, it only needs a correction bit.
+ * NOTE: a straight translation of the spec's figure G.7 would suggest
+ * that we also need to test r > 15. But if r > 15, we can only get here
+ * if k > EOB, which implies that this coefficient is not 1.
+ */
+ if (temp > 1) {
+ /* The correction bit is the next bit of the absolute value. */
+ BR_buffer[BR++] = (char) (temp & 1);
+ continue;
+ }
+
+ /* Emit any pending EOBRUN and the BE correction bits */
+ emit_eobrun(entropy);
+
+ /* Count/emit Huffman symbol for run length / number of bits */
+ emit_ac_symbol(entropy, entropy->ac_tbl_no, (r << 4) + 1);
+
+ /* Emit output bit for newly-nonzero coef */
+ temp = ((*block)[natural_order[k]] < 0) ? 0 : 1;
+ emit_bits_e(entropy, (unsigned int) temp, 1);
+
+ /* Emit buffered correction bits that must be associated with this code */
+ emit_buffered_bits(entropy, BR_buffer, BR);
+ BR_buffer = entropy->bit_buffer; /* BE bits are gone now */
+ BR = 0;
+ r = 0; /* reset zero run length */
+ }
+
+ if (r > 0 || BR > 0) { /* If there are trailing zeroes, */
+ entropy->EOBRUN++; /* count an EOB */
+ entropy->BE += BR; /* concat my correction bits to older ones */
+ /* We force out the EOB if we risk either:
+ * 1. overflow of the EOB counter;
+ * 2. overflow of the correction bit buffer during the next MCU.
+ */
+ if (entropy->EOBRUN == 0x7FFF || entropy->BE > (MAX_CORR_BITS-DCTSIZE2+1))
+ emit_eobrun(entropy);
+ }
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/* Encode a single block's worth of coefficients */
+
+LOCAL(boolean)
+encode_one_block (working_state * state, JCOEFPTR block, int last_dc_val,
+ c_derived_tbl *dctbl, c_derived_tbl *actbl)
+{
+ register int temp, temp2;
+ register int nbits;
+ register int k, r, i;
+ int Se = state->cinfo->lim_Se;
+ const int * natural_order = state->cinfo->natural_order;
+
+ /* Encode the DC coefficient difference per section F.1.2.1 */
+
+ temp = temp2 = block[0] - last_dc_val;
+
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* For a negative input, want temp2 = bitwise complement of abs(input) */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range coefficient values.
+ * Since we're encoding a difference, the range limit is twice as much.
+ */
+ if (nbits > MAX_COEF_BITS+1)
+ ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
+
+ /* Emit the Huffman-coded symbol for the number of bits */
+ if (! emit_bits_s(state, dctbl->ehufco[nbits], dctbl->ehufsi[nbits]))
+ return FALSE;
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (nbits) /* emit_bits rejects calls with size 0 */
+ if (! emit_bits_s(state, (unsigned int) temp2, nbits))
+ return FALSE;
+
+ /* Encode the AC coefficients per section F.1.2.2 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = 1; k <= Se; k++) {
+ if ((temp = block[natural_order[k]]) == 0) {
+ r++;
+ } else {
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ if (! emit_bits_s(state, actbl->ehufco[0xF0], actbl->ehufsi[0xF0]))
+ return FALSE;
+ r -= 16;
+ }
+
+ temp2 = temp;
+ if (temp < 0) {
+ temp = -temp; /* temp is abs value of input */
+ /* This code assumes we are on a two's complement machine */
+ temp2--;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+ /* Check for out-of-range coefficient values */
+ if (nbits > MAX_COEF_BITS)
+ ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
+
+ /* Emit Huffman symbol for run length / number of bits */
+ i = (r << 4) + nbits;
+ if (! emit_bits_s(state, actbl->ehufco[i], actbl->ehufsi[i]))
+ return FALSE;
+
+ /* Emit that number of bits of the value, if positive, */
+ /* or the complement of its magnitude, if negative. */
+ if (! emit_bits_s(state, (unsigned int) temp2, nbits))
+ return FALSE;
+
+ r = 0;
+ }
+ }
+
+ /* If the last coef(s) were zero, emit an end-of-block code */
+ if (r > 0)
+ if (! emit_bits_s(state, actbl->ehufco[0], actbl->ehufsi[0]))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Encode and output one MCU's worth of Huffman-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+encode_mcu_huff (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ working_state state;
+ int blkn, ci;
+ jpeg_component_info * compptr;
+
+ /* Load up working state */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ ASSIGN_STATE(state.cur, entropy->saved);
+ state.cinfo = cinfo;
+
+ /* Emit restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! emit_restart_s(&state, entropy->next_restart_num))
+ return FALSE;
+ }
+
+ /* Encode the MCU data blocks */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ if (! encode_one_block(&state,
+ MCU_data[blkn][0], state.cur.last_dc_val[ci],
+ entropy->dc_derived_tbls[compptr->dc_tbl_no],
+ entropy->ac_derived_tbls[compptr->ac_tbl_no]))
+ return FALSE;
+ /* Update last_dc_val */
+ state.cur.last_dc_val[ci] = MCU_data[blkn][0][0];
+ }
+
+ /* Completed MCU, so update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ ASSIGN_STATE(entropy->saved, state.cur);
+
+ /* Update restart-interval state too */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num++;
+ entropy->next_restart_num &= 7;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Finish up at the end of a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+finish_pass_huff (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ working_state state;
+
+ if (cinfo->progressive_mode) {
+ entropy->next_output_byte = cinfo->dest->next_output_byte;
+ entropy->free_in_buffer = cinfo->dest->free_in_buffer;
+
+ /* Flush out any buffered data */
+ emit_eobrun(entropy);
+ flush_bits_e(entropy);
+
+ cinfo->dest->next_output_byte = entropy->next_output_byte;
+ cinfo->dest->free_in_buffer = entropy->free_in_buffer;
+ } else {
+ /* Load up working state ... flush_bits needs it */
+ state.next_output_byte = cinfo->dest->next_output_byte;
+ state.free_in_buffer = cinfo->dest->free_in_buffer;
+ ASSIGN_STATE(state.cur, entropy->saved);
+ state.cinfo = cinfo;
+
+ /* Flush out the last data */
+ if (! flush_bits_s(&state))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+ /* Update state */
+ cinfo->dest->next_output_byte = state.next_output_byte;
+ cinfo->dest->free_in_buffer = state.free_in_buffer;
+ ASSIGN_STATE(entropy->saved, state.cur);
+ }
+}
+
+
+/*
+ * Huffman coding optimization.
+ *
+ * We first scan the supplied data and count the number of uses of each symbol
+ * that is to be Huffman-coded. (This process MUST agree with the code above.)
+ * Then we build a Huffman coding tree for the observed counts.
+ * Symbols which are not needed at all for the particular image are not
+ * assigned any code, which saves space in the DHT marker as well as in
+ * the compressed data.
+ */
+
+
+/* Process a single block's worth of coefficients */
+
+LOCAL(void)
+htest_one_block (j_compress_ptr cinfo, JCOEFPTR block, int last_dc_val,
+ long dc_counts[], long ac_counts[])
+{
+ register int temp;
+ register int nbits;
+ register int k, r;
+ int Se = cinfo->lim_Se;
+ const int * natural_order = cinfo->natural_order;
+
+ /* Encode the DC coefficient difference per section F.1.2.1 */
+
+ temp = block[0] - last_dc_val;
+ if (temp < 0)
+ temp = -temp;
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 0;
+ while (temp) {
+ nbits++;
+ temp >>= 1;
+ }
+ /* Check for out-of-range coefficient values.
+ * Since we're encoding a difference, the range limit is twice as much.
+ */
+ if (nbits > MAX_COEF_BITS+1)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count the Huffman symbol for the number of bits */
+ dc_counts[nbits]++;
+
+ /* Encode the AC coefficients per section F.1.2.2 */
+
+ r = 0; /* r = run length of zeros */
+
+ for (k = 1; k <= Se; k++) {
+ if ((temp = block[natural_order[k]]) == 0) {
+ r++;
+ } else {
+ /* if run length > 15, must emit special run-length-16 codes (0xF0) */
+ while (r > 15) {
+ ac_counts[0xF0]++;
+ r -= 16;
+ }
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ if (temp < 0)
+ temp = -temp;
+
+ /* Find the number of bits needed for the magnitude of the coefficient */
+ nbits = 1; /* there must be at least one 1 bit */
+ while ((temp >>= 1))
+ nbits++;
+ /* Check for out-of-range coefficient values */
+ if (nbits > MAX_COEF_BITS)
+ ERREXIT(cinfo, JERR_BAD_DCT_COEF);
+
+ /* Count Huffman symbol for run length / number of bits */
+ ac_counts[(r << 4) + nbits]++;
+
+ r = 0;
+ }
+ }
+
+ /* If the last coef(s) were zero, emit an end-of-block code */
+ if (r > 0)
+ ac_counts[0]++;
+}
+
+
+/*
+ * Trial-encode one MCU's worth of Huffman-compressed coefficients.
+ * No data is actually output, so no suspension return is possible.
+ */
+
+METHODDEF(boolean)
+encode_mcu_gather (j_compress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int blkn, ci;
+ jpeg_component_info * compptr;
+
+ /* Take care of restart intervals if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0) {
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ /* Update restart state */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ }
+ entropy->restarts_to_go--;
+ }
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ htest_one_block(cinfo, MCU_data[blkn][0], entropy->saved.last_dc_val[ci],
+ entropy->dc_count_ptrs[compptr->dc_tbl_no],
+ entropy->ac_count_ptrs[compptr->ac_tbl_no]);
+ entropy->saved.last_dc_val[ci] = MCU_data[blkn][0][0];
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Generate the best Huffman code table for the given counts, fill htbl.
+ *
+ * The JPEG standard requires that no symbol be assigned a codeword of all
+ * one bits (so that padding bits added at the end of a compressed segment
+ * can't look like a valid code). Because of the canonical ordering of
+ * codewords, this just means that there must be an unused slot in the
+ * longest codeword length category. Section K.2 of the JPEG spec suggests
+ * reserving such a slot by pretending that symbol 256 is a valid symbol
+ * with count 1. In theory that's not optimal; giving it count zero but
+ * including it in the symbol set anyway should give a better Huffman code.
+ * But the theoretically better code actually seems to come out worse in
+ * practice, because it produces more all-ones bytes (which incur stuffed
+ * zero bytes in the final file). In any case the difference is tiny.
+ *
+ * The JPEG standard requires Huffman codes to be no more than 16 bits long.
+ * If some symbols have a very small but nonzero probability, the Huffman tree
+ * must be adjusted to meet the code length restriction. We currently use
+ * the adjustment method suggested in JPEG section K.2. This method is *not*
+ * optimal; it may not choose the best possible limited-length code. But
+ * typically only very-low-frequency symbols will be given less-than-optimal
+ * lengths, so the code is almost optimal. Experimental comparisons against
+ * an optimal limited-length-code algorithm indicate that the difference is
+ * microscopic --- usually less than a hundredth of a percent of total size.
+ * So the extra complexity of an optimal algorithm doesn't seem worthwhile.
+ */
+
+LOCAL(void)
+jpeg_gen_optimal_table (j_compress_ptr cinfo, JHUFF_TBL * htbl, long freq[])
+{
+#define MAX_CLEN 32 /* assumed maximum initial code length */
+ UINT8 bits[MAX_CLEN+1]; /* bits[k] = # of symbols with code length k */
+ int codesize[257]; /* codesize[k] = code length of symbol k */
+ int others[257]; /* next symbol in current branch of tree */
+ int c1, c2;
+ int p, i, j;
+ long v;
+
+ /* This algorithm is explained in section K.2 of the JPEG standard */
+
+ MEMZERO(bits, SIZEOF(bits));
+ MEMZERO(codesize, SIZEOF(codesize));
+ for (i = 0; i < 257; i++)
+ others[i] = -1; /* init links to empty */
+
+ freq[256] = 1; /* make sure 256 has a nonzero count */
+ /* Including the pseudo-symbol 256 in the Huffman procedure guarantees
+ * that no real symbol is given code-value of all ones, because 256
+ * will be placed last in the largest codeword category.
+ */
+
+ /* Huffman's basic algorithm to assign optimal code lengths to symbols */
+
+ for (;;) {
+ /* Find the smallest nonzero frequency, set c1 = its symbol */
+ /* In case of ties, take the larger symbol number */
+ c1 = -1;
+ v = 1000000000L;
+ for (i = 0; i <= 256; i++) {
+ if (freq[i] && freq[i] <= v) {
+ v = freq[i];
+ c1 = i;
+ }
+ }
+
+ /* Find the next smallest nonzero frequency, set c2 = its symbol */
+ /* In case of ties, take the larger symbol number */
+ c2 = -1;
+ v = 1000000000L;
+ for (i = 0; i <= 256; i++) {
+ if (freq[i] && freq[i] <= v && i != c1) {
+ v = freq[i];
+ c2 = i;
+ }
+ }
+
+ /* Done if we've merged everything into one frequency */
+ if (c2 < 0)
+ break;
+
+ /* Else merge the two counts/trees */
+ freq[c1] += freq[c2];
+ freq[c2] = 0;
+
+ /* Increment the codesize of everything in c1's tree branch */
+ codesize[c1]++;
+ while (others[c1] >= 0) {
+ c1 = others[c1];
+ codesize[c1]++;
+ }
+
+ others[c1] = c2; /* chain c2 onto c1's tree branch */
+
+ /* Increment the codesize of everything in c2's tree branch */
+ codesize[c2]++;
+ while (others[c2] >= 0) {
+ c2 = others[c2];
+ codesize[c2]++;
+ }
+ }
+
+ /* Now count the number of symbols of each code length */
+ for (i = 0; i <= 256; i++) {
+ if (codesize[i]) {
+ /* The JPEG standard seems to think that this can't happen, */
+ /* but I'm paranoid... */
+ if (codesize[i] > MAX_CLEN)
+ ERREXIT(cinfo, JERR_HUFF_CLEN_OVERFLOW);
+
+ bits[codesize[i]]++;
+ }
+ }
+
+ /* JPEG doesn't allow symbols with code lengths over 16 bits, so if the pure
+ * Huffman procedure assigned any such lengths, we must adjust the coding.
+ * Here is what the JPEG spec says about how this next bit works:
+ * Since symbols are paired for the longest Huffman code, the symbols are
+ * removed from this length category two at a time. The prefix for the pair
+ * (which is one bit shorter) is allocated to one of the pair; then,
+ * skipping the BITS entry for that prefix length, a code word from the next
+ * shortest nonzero BITS entry is converted into a prefix for two code words
+ * one bit longer.
+ */
+
+ for (i = MAX_CLEN; i > 16; i--) {
+ while (bits[i] > 0) {
+ j = i - 2; /* find length of new prefix to be used */
+ while (bits[j] == 0)
+ j--;
+
+ bits[i] -= 2; /* remove two symbols */
+ bits[i-1]++; /* one goes in this length */
+ bits[j+1] += 2; /* two new symbols in this length */
+ bits[j]--; /* symbol of this length is now a prefix */
+ }
+ }
+
+ /* Remove the count for the pseudo-symbol 256 from the largest codelength */
+ while (bits[i] == 0) /* find largest codelength still in use */
+ i--;
+ bits[i]--;
+
+ /* Return final symbol counts (only for lengths 0..16) */
+ MEMCOPY(htbl->bits, bits, SIZEOF(htbl->bits));
+
+ /* Return a list of the symbols sorted by code length */
+ /* It's not real clear to me why we don't need to consider the codelength
+ * changes made above, but the JPEG spec seems to think this works.
+ */
+ p = 0;
+ for (i = 1; i <= MAX_CLEN; i++) {
+ for (j = 0; j <= 255; j++) {
+ if (codesize[j] == i) {
+ htbl->huffval[p] = (UINT8) j;
+ p++;
+ }
+ }
+ }
+
+ /* Set sent_table FALSE so updated table will be written to JPEG file. */
+ htbl->sent_table = FALSE;
+}
+
+
+/*
+ * Finish up a statistics-gathering pass and create the new Huffman tables.
+ */
+
+METHODDEF(void)
+finish_pass_gather (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+ JHUFF_TBL **htblptr;
+ boolean did_dc[NUM_HUFF_TBLS];
+ boolean did_ac[NUM_HUFF_TBLS];
+
+ /* It's important not to apply jpeg_gen_optimal_table more than once
+ * per table, because it clobbers the input frequency counts!
+ */
+ if (cinfo->progressive_mode)
+ /* Flush out buffered data (all we care about is counting the EOB symbol) */
+ emit_eobrun(entropy);
+
+ MEMZERO(did_dc, SIZEOF(did_dc));
+ MEMZERO(did_ac, SIZEOF(did_ac));
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+ tbl = compptr->dc_tbl_no;
+ if (! did_dc[tbl]) {
+ htblptr = & cinfo->dc_huff_tbl_ptrs[tbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->dc_count_ptrs[tbl]);
+ did_dc[tbl] = TRUE;
+ }
+ }
+ /* AC needs no table when not present */
+ if (cinfo->Se) {
+ tbl = compptr->ac_tbl_no;
+ if (! did_ac[tbl]) {
+ htblptr = & cinfo->ac_huff_tbl_ptrs[tbl];
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+ jpeg_gen_optimal_table(cinfo, *htblptr, entropy->ac_count_ptrs[tbl]);
+ did_ac[tbl] = TRUE;
+ }
+ }
+ }
+}
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ * If gather_statistics is TRUE, we do not output anything during the scan,
+ * just count the Huffman symbols used and generate Huffman code tables.
+ */
+
+METHODDEF(void)
+start_pass_huff (j_compress_ptr cinfo, boolean gather_statistics)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+
+ if (gather_statistics)
+ entropy->pub.finish_pass = finish_pass_gather;
+ else
+ entropy->pub.finish_pass = finish_pass_huff;
+
+ if (cinfo->progressive_mode) {
+ entropy->cinfo = cinfo;
+ entropy->gather_statistics = gather_statistics;
+
+ /* We assume jcmaster.c already validated the scan parameters. */
+
+ /* Select execution routine */
+ if (cinfo->Ah == 0) {
+ if (cinfo->Ss == 0)
+ entropy->pub.encode_mcu = encode_mcu_DC_first;
+ else
+ entropy->pub.encode_mcu = encode_mcu_AC_first;
+ } else {
+ if (cinfo->Ss == 0)
+ entropy->pub.encode_mcu = encode_mcu_DC_refine;
+ else {
+ entropy->pub.encode_mcu = encode_mcu_AC_refine;
+ /* AC refinement needs a correction bit buffer */
+ if (entropy->bit_buffer == NULL)
+ entropy->bit_buffer = (char *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ MAX_CORR_BITS * SIZEOF(char));
+ }
+ }
+
+ /* Initialize AC stuff */
+ entropy->ac_tbl_no = cinfo->cur_comp_info[0]->ac_tbl_no;
+ entropy->EOBRUN = 0;
+ entropy->BE = 0;
+ } else {
+ if (gather_statistics)
+ entropy->pub.encode_mcu = encode_mcu_gather;
+ else
+ entropy->pub.encode_mcu = encode_mcu_huff;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0) {
+ tbl = compptr->dc_tbl_no;
+ if (gather_statistics) {
+ /* Check for invalid table index */
+ /* (make_c_derived_tbl does this in the other path) */
+ if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
+ /* Allocate and zero the statistics tables */
+ /* Note that jpeg_gen_optimal_table expects 257 entries in each table! */
+ if (entropy->dc_count_ptrs[tbl] == NULL)
+ entropy->dc_count_ptrs[tbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 257 * SIZEOF(long));
+ MEMZERO(entropy->dc_count_ptrs[tbl], 257 * SIZEOF(long));
+ } else {
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ jpeg_make_c_derived_tbl(cinfo, TRUE, tbl,
+ & entropy->dc_derived_tbls[tbl]);
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+ /* AC needs no table when not present */
+ if (cinfo->Se) {
+ tbl = compptr->ac_tbl_no;
+ if (gather_statistics) {
+ if (tbl < 0 || tbl >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tbl);
+ if (entropy->ac_count_ptrs[tbl] == NULL)
+ entropy->ac_count_ptrs[tbl] = (long *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 257 * SIZEOF(long));
+ MEMZERO(entropy->ac_count_ptrs[tbl], 257 * SIZEOF(long));
+ } else {
+ jpeg_make_c_derived_tbl(cinfo, FALSE, tbl,
+ & entropy->ac_derived_tbls[tbl]);
+ }
+ }
+ }
+
+ /* Initialize bit buffer to empty */
+ entropy->saved.put_buffer = 0;
+ entropy->saved.put_bits = 0;
+
+ /* Initialize restart stuff */
+ entropy->restarts_to_go = cinfo->restart_interval;
+ entropy->next_restart_num = 0;
+}
+
+
+/*
+ * Module initialization routine for Huffman entropy encoding.
+ */
+
+GLOBAL(void)
+jinit_huff_encoder (j_compress_ptr cinfo)
+{
+ huff_entropy_ptr entropy;
+ int i;
+
+ entropy = (huff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(huff_entropy_encoder));
+ cinfo->entropy = (struct jpeg_entropy_encoder *) entropy;
+ entropy->pub.start_pass = start_pass_huff;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
+ entropy->dc_count_ptrs[i] = entropy->ac_count_ptrs[i] = NULL;
+ }
+
+ if (cinfo->progressive_mode)
+ entropy->bit_buffer = NULL; /* needed only in AC refinement scan */
+}
diff --git a/jpg/jcinit.c b/jpg/jcinit.c
new file mode 100644
index 0000000..0ba310f
--- /dev/null
+++ b/jpg/jcinit.c
@@ -0,0 +1,65 @@
+/*
+ * jcinit.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains initialization logic for the JPEG compressor.
+ * This routine is in charge of selecting the modules to be executed and
+ * making an initialization call to each one.
+ *
+ * Logically, this code belongs in jcmaster.c. It's split out because
+ * linking this routine implies linking the entire compression library.
+ * For a transcoding-only application, we want to be able to use jcmaster.c
+ * without linking in the whole library.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Master selection of compression modules.
+ * This is done once at the start of processing an image. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ */
+
+GLOBAL(void)
+jinit_compress_master (j_compress_ptr cinfo)
+{
+ /* Initialize master control (includes parameter checking/processing) */
+ jinit_c_master_control(cinfo, FALSE /* full compression */);
+
+ /* Preprocessing */
+ if (! cinfo->raw_data_in) {
+ jinit_color_converter(cinfo);
+ jinit_downsampler(cinfo);
+ jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */);
+ }
+ /* Forward DCT */
+ jinit_forward_dct(cinfo);
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code)
+ jinit_arith_encoder(cinfo);
+ else {
+ jinit_huff_encoder(cinfo);
+ }
+
+ /* Need a full-image coefficient buffer in any multi-pass mode. */
+ jinit_c_coef_controller(cinfo,
+ (boolean) (cinfo->num_scans > 1 || cinfo->optimize_coding));
+ jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+ jinit_marker_writer(cinfo);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Write the datastream header (SOI) immediately.
+ * Frame and scan headers are postponed till later.
+ * This lets application insert special markers after the SOI.
+ */
+ (*cinfo->marker->write_file_header) (cinfo);
+}
diff --git a/jpg/jcmainct.c b/jpg/jcmainct.c
new file mode 100644
index 0000000..7de75d1
--- /dev/null
+++ b/jpg/jcmainct.c
@@ -0,0 +1,293 @@
+/*
+ * jcmainct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the main buffer controller for compression.
+ * The main buffer lies between the pre-processor and the JPEG
+ * compressor proper; it holds downsampled data in the JPEG colorspace.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Note: currently, there is no operating mode in which a full-image buffer
+ * is needed at this step. If there were, that mode could not be used with
+ * "raw data" input, since this module is bypassed in that case. However,
+ * we've left the code here for possible use in special applications.
+ */
+#undef FULL_MAIN_BUFFER_SUPPORTED
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_main_controller pub; /* public fields */
+
+ JDIMENSION cur_iMCU_row; /* number of current iMCU row */
+ JDIMENSION rowgroup_ctr; /* counts row groups received in iMCU row */
+ boolean suspended; /* remember if we suspended output */
+ J_BUF_MODE pass_mode; /* current operating mode */
+
+ /* If using just a strip buffer, this points to the entire set of buffers
+ * (we allocate one for each component). In the full-image case, this
+ * points to the currently accessible strips of the virtual arrays.
+ */
+ JSAMPARRAY buffer[MAX_COMPONENTS];
+
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ /* If using full-image storage, this array holds pointers to virtual-array
+ * control blocks for each component. Unused if not full-image storage.
+ */
+ jvirt_sarray_ptr whole_image[MAX_COMPONENTS];
+#endif
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+
+/* Forward declarations */
+METHODDEF(void) process_data_simple_main
+ JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+METHODDEF(void) process_data_buffer_main
+ JPP((j_compress_ptr cinfo, JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail));
+#endif
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_main (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+
+ /* Do nothing in raw-data mode. */
+ if (cinfo->raw_data_in)
+ return;
+
+ main->cur_iMCU_row = 0; /* initialize counters */
+ main->rowgroup_ctr = 0;
+ main->suspended = FALSE;
+ main->pass_mode = pass_mode; /* save mode for use by process_data */
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ if (main->whole_image[0] != NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ main->pub.process_data = process_data_simple_main;
+ break;
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ case JBUF_SAVE_SOURCE:
+ case JBUF_CRANK_DEST:
+ case JBUF_SAVE_AND_PASS:
+ if (main->whole_image[0] == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ main->pub.process_data = process_data_buffer_main;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This routine handles the simple pass-through mode,
+ * where we have only a strip buffer.
+ */
+
+METHODDEF(void)
+process_data_simple_main (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+
+ while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
+ /* Read input data if we haven't filled the main buffer yet */
+ if (main->rowgroup_ctr < (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+ (*cinfo->prep->pre_process_data) (cinfo,
+ input_buf, in_row_ctr, in_rows_avail,
+ main->buffer, &main->rowgroup_ctr,
+ (JDIMENSION) cinfo->min_DCT_v_scaled_size);
+
+ /* If we don't have a full iMCU row buffered, return to application for
+ * more data. Note that preprocessor will always pad to fill the iMCU row
+ * at the bottom of the image.
+ */
+ if (main->rowgroup_ctr != (JDIMENSION) cinfo->min_DCT_v_scaled_size)
+ return;
+
+ /* Send the completed row to the compressor */
+ if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
+ /* If compressor did not consume the whole row, then we must need to
+ * suspend processing and return to the application. In this situation
+ * we pretend we didn't yet consume the last input row; otherwise, if
+ * it happened to be the last row of the image, the application would
+ * think we were done.
+ */
+ if (! main->suspended) {
+ (*in_row_ctr)--;
+ main->suspended = TRUE;
+ }
+ return;
+ }
+ /* We did finish the row. Undo our little suspension hack if a previous
+ * call suspended; then mark the main buffer empty.
+ */
+ if (main->suspended) {
+ (*in_row_ctr)++;
+ main->suspended = FALSE;
+ }
+ main->rowgroup_ctr = 0;
+ main->cur_iMCU_row++;
+ }
+}
+
+
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+
+/*
+ * Process some data.
+ * This routine handles all of the modes that use a full-size buffer.
+ */
+
+METHODDEF(void)
+process_data_buffer_main (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci;
+ jpeg_component_info *compptr;
+ boolean writing = (main->pass_mode != JBUF_CRANK_DEST);
+
+ while (main->cur_iMCU_row < cinfo->total_iMCU_rows) {
+ /* Realign the virtual buffers if at the start of an iMCU row. */
+ if (main->rowgroup_ctr == 0) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main->buffer[ci] = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, main->whole_image[ci],
+ main->cur_iMCU_row * (compptr->v_samp_factor * DCTSIZE),
+ (JDIMENSION) (compptr->v_samp_factor * DCTSIZE), writing);
+ }
+ /* In a read pass, pretend we just read some source data. */
+ if (! writing) {
+ *in_row_ctr += cinfo->max_v_samp_factor * DCTSIZE;
+ main->rowgroup_ctr = DCTSIZE;
+ }
+ }
+
+ /* If a write pass, read input data until the current iMCU row is full. */
+ /* Note: preprocessor will pad if necessary to fill the last iMCU row. */
+ if (writing) {
+ (*cinfo->prep->pre_process_data) (cinfo,
+ input_buf, in_row_ctr, in_rows_avail,
+ main->buffer, &main->rowgroup_ctr,
+ (JDIMENSION) DCTSIZE);
+ /* Return to application if we need more data to fill the iMCU row. */
+ if (main->rowgroup_ctr < DCTSIZE)
+ return;
+ }
+
+ /* Emit data, unless this is a sink-only pass. */
+ if (main->pass_mode != JBUF_SAVE_SOURCE) {
+ if (! (*cinfo->coef->compress_data) (cinfo, main->buffer)) {
+ /* If compressor did not consume the whole row, then we must need to
+ * suspend processing and return to the application. In this situation
+ * we pretend we didn't yet consume the last input row; otherwise, if
+ * it happened to be the last row of the image, the application would
+ * think we were done.
+ */
+ if (! main->suspended) {
+ (*in_row_ctr)--;
+ main->suspended = TRUE;
+ }
+ return;
+ }
+ /* We did finish the row. Undo our little suspension hack if a previous
+ * call suspended; then mark the main buffer empty.
+ */
+ if (main->suspended) {
+ (*in_row_ctr)++;
+ main->suspended = FALSE;
+ }
+ }
+
+ /* If get here, we are done with this iMCU row. Mark buffer empty. */
+ main->rowgroup_ctr = 0;
+ main->cur_iMCU_row++;
+ }
+}
+
+#endif /* FULL_MAIN_BUFFER_SUPPORTED */
+
+
+/*
+ * Initialize main buffer controller.
+ */
+
+GLOBAL(void)
+jinit_c_main_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_main_ptr main;
+ int ci;
+ jpeg_component_info *compptr;
+
+ main = (my_main_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_main_controller));
+ cinfo->main = (struct jpeg_c_main_controller *) main;
+ main->pub.start_pass = start_pass_main;
+
+ /* We don't need to create a buffer in raw-data mode. */
+ if (cinfo->raw_data_in)
+ return;
+
+ /* Create the buffer. It holds downsampled data, so each component
+ * may be of a different size.
+ */
+ if (need_full_buffer) {
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ /* Allocate a full-image virtual array for each component */
+ /* Note we pad the bottom to a multiple of the iMCU height */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main->whole_image[ci] = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor) * DCTSIZE,
+ (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
+ }
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif
+ } else {
+#ifdef FULL_MAIN_BUFFER_SUPPORTED
+ main->whole_image[0] = NULL; /* flag for no virtual arrays */
+#endif
+ /* Allocate a strip buffer for each component */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ main->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) (compptr->v_samp_factor * compptr->DCT_v_scaled_size));
+ }
+ }
+}
diff --git a/jpg/jcmarker.c b/jpg/jcmarker.c
new file mode 100644
index 0000000..606c19a
--- /dev/null
+++ b/jpg/jcmarker.c
@@ -0,0 +1,682 @@
+/*
+ * jcmarker.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write JPEG datastream markers.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+typedef enum { /* JPEG marker codes */
+ M_SOF0 = 0xc0,
+ M_SOF1 = 0xc1,
+ M_SOF2 = 0xc2,
+ M_SOF3 = 0xc3,
+
+ M_SOF5 = 0xc5,
+ M_SOF6 = 0xc6,
+ M_SOF7 = 0xc7,
+
+ M_JPG = 0xc8,
+ M_SOF9 = 0xc9,
+ M_SOF10 = 0xca,
+ M_SOF11 = 0xcb,
+
+ M_SOF13 = 0xcd,
+ M_SOF14 = 0xce,
+ M_SOF15 = 0xcf,
+
+ M_DHT = 0xc4,
+
+ M_DAC = 0xcc,
+
+ M_RST0 = 0xd0,
+ M_RST1 = 0xd1,
+ M_RST2 = 0xd2,
+ M_RST3 = 0xd3,
+ M_RST4 = 0xd4,
+ M_RST5 = 0xd5,
+ M_RST6 = 0xd6,
+ M_RST7 = 0xd7,
+
+ M_SOI = 0xd8,
+ M_EOI = 0xd9,
+ M_SOS = 0xda,
+ M_DQT = 0xdb,
+ M_DNL = 0xdc,
+ M_DRI = 0xdd,
+ M_DHP = 0xde,
+ M_EXP = 0xdf,
+
+ M_APP0 = 0xe0,
+ M_APP1 = 0xe1,
+ M_APP2 = 0xe2,
+ M_APP3 = 0xe3,
+ M_APP4 = 0xe4,
+ M_APP5 = 0xe5,
+ M_APP6 = 0xe6,
+ M_APP7 = 0xe7,
+ M_APP8 = 0xe8,
+ M_APP9 = 0xe9,
+ M_APP10 = 0xea,
+ M_APP11 = 0xeb,
+ M_APP12 = 0xec,
+ M_APP13 = 0xed,
+ M_APP14 = 0xee,
+ M_APP15 = 0xef,
+
+ M_JPG0 = 0xf0,
+ M_JPG13 = 0xfd,
+ M_COM = 0xfe,
+
+ M_TEM = 0x01,
+
+ M_ERROR = 0x100
+} JPEG_MARKER;
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_marker_writer pub; /* public fields */
+
+ unsigned int last_restart_interval; /* last DRI value emitted; 0 after SOI */
+} my_marker_writer;
+
+typedef my_marker_writer * my_marker_ptr;
+
+
+/*
+ * Basic output routines.
+ *
+ * Note that we do not support suspension while writing a marker.
+ * Therefore, an application using suspension must ensure that there is
+ * enough buffer space for the initial markers (typ. 600-700 bytes) before
+ * calling jpeg_start_compress, and enough space to write the trailing EOI
+ * (a few bytes) before calling jpeg_finish_compress. Multipass compression
+ * modes are not supported at all with suspension, so those two are the only
+ * points where markers will be written.
+ */
+
+LOCAL(void)
+emit_byte (j_compress_ptr cinfo, int val)
+/* Emit a byte */
+{
+ struct jpeg_destination_mgr * dest = cinfo->dest;
+
+ *(dest->next_output_byte)++ = (JOCTET) val;
+ if (--dest->free_in_buffer == 0) {
+ if (! (*dest->empty_output_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ }
+}
+
+
+LOCAL(void)
+emit_marker (j_compress_ptr cinfo, JPEG_MARKER mark)
+/* Emit a marker code */
+{
+ emit_byte(cinfo, 0xFF);
+ emit_byte(cinfo, (int) mark);
+}
+
+
+LOCAL(void)
+emit_2bytes (j_compress_ptr cinfo, int value)
+/* Emit a 2-byte integer; these are always MSB first in JPEG files */
+{
+ emit_byte(cinfo, (value >> 8) & 0xFF);
+ emit_byte(cinfo, value & 0xFF);
+}
+
+
+/*
+ * Routines to write specific marker types.
+ */
+
+LOCAL(int)
+emit_dqt (j_compress_ptr cinfo, int index)
+/* Emit a DQT marker */
+/* Returns the precision used (0 = 8bits, 1 = 16bits) for baseline checking */
+{
+ JQUANT_TBL * qtbl = cinfo->quant_tbl_ptrs[index];
+ int prec;
+ int i;
+
+ if (qtbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, index);
+
+ prec = 0;
+ for (i = 0; i <= cinfo->lim_Se; i++) {
+ if (qtbl->quantval[cinfo->natural_order[i]] > 255)
+ prec = 1;
+ }
+
+ if (! qtbl->sent_table) {
+ emit_marker(cinfo, M_DQT);
+
+ emit_2bytes(cinfo,
+ prec ? cinfo->lim_Se * 2 + 2 + 1 + 2 : cinfo->lim_Se + 1 + 1 + 2);
+
+ emit_byte(cinfo, index + (prec<<4));
+
+ for (i = 0; i <= cinfo->lim_Se; i++) {
+ /* The table entries must be emitted in zigzag order. */
+ unsigned int qval = qtbl->quantval[cinfo->natural_order[i]];
+ if (prec)
+ emit_byte(cinfo, (int) (qval >> 8));
+ emit_byte(cinfo, (int) (qval & 0xFF));
+ }
+
+ qtbl->sent_table = TRUE;
+ }
+
+ return prec;
+}
+
+
+LOCAL(void)
+emit_dht (j_compress_ptr cinfo, int index, boolean is_ac)
+/* Emit a DHT marker */
+{
+ JHUFF_TBL * htbl;
+ int length, i;
+
+ if (is_ac) {
+ htbl = cinfo->ac_huff_tbl_ptrs[index];
+ index += 0x10; /* output index has AC bit set */
+ } else {
+ htbl = cinfo->dc_huff_tbl_ptrs[index];
+ }
+
+ if (htbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, index);
+
+ if (! htbl->sent_table) {
+ emit_marker(cinfo, M_DHT);
+
+ length = 0;
+ for (i = 1; i <= 16; i++)
+ length += htbl->bits[i];
+
+ emit_2bytes(cinfo, length + 2 + 1 + 16);
+ emit_byte(cinfo, index);
+
+ for (i = 1; i <= 16; i++)
+ emit_byte(cinfo, htbl->bits[i]);
+
+ for (i = 0; i < length; i++)
+ emit_byte(cinfo, htbl->huffval[i]);
+
+ htbl->sent_table = TRUE;
+ }
+}
+
+
+LOCAL(void)
+emit_dac (j_compress_ptr cinfo)
+/* Emit a DAC marker */
+/* Since the useful info is so small, we want to emit all the tables in */
+/* one DAC marker. Therefore this routine does its own scan of the table. */
+{
+#ifdef C_ARITH_CODING_SUPPORTED
+ char dc_in_use[NUM_ARITH_TBLS];
+ char ac_in_use[NUM_ARITH_TBLS];
+ int length, i;
+ jpeg_component_info *compptr;
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++)
+ dc_in_use[i] = ac_in_use[i] = 0;
+
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0)
+ dc_in_use[compptr->dc_tbl_no] = 1;
+ /* AC needs no table when not present */
+ if (cinfo->Se)
+ ac_in_use[compptr->ac_tbl_no] = 1;
+ }
+
+ length = 0;
+ for (i = 0; i < NUM_ARITH_TBLS; i++)
+ length += dc_in_use[i] + ac_in_use[i];
+
+ if (length) {
+ emit_marker(cinfo, M_DAC);
+
+ emit_2bytes(cinfo, length*2 + 2);
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ if (dc_in_use[i]) {
+ emit_byte(cinfo, i);
+ emit_byte(cinfo, cinfo->arith_dc_L[i] + (cinfo->arith_dc_U[i]<<4));
+ }
+ if (ac_in_use[i]) {
+ emit_byte(cinfo, i + 0x10);
+ emit_byte(cinfo, cinfo->arith_ac_K[i]);
+ }
+ }
+ }
+#endif /* C_ARITH_CODING_SUPPORTED */
+}
+
+
+LOCAL(void)
+emit_dri (j_compress_ptr cinfo)
+/* Emit a DRI marker */
+{
+ emit_marker(cinfo, M_DRI);
+
+ emit_2bytes(cinfo, 4); /* fixed length */
+
+ emit_2bytes(cinfo, (int) cinfo->restart_interval);
+}
+
+
+LOCAL(void)
+emit_sof (j_compress_ptr cinfo, JPEG_MARKER code)
+/* Emit a SOF marker */
+{
+ int ci;
+ jpeg_component_info *compptr;
+
+ emit_marker(cinfo, code);
+
+ emit_2bytes(cinfo, 3 * cinfo->num_components + 2 + 5 + 1); /* length */
+
+ /* Make sure image isn't bigger than SOF field can handle */
+ if ((long) cinfo->jpeg_height > 65535L ||
+ (long) cinfo->jpeg_width > 65535L)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) 65535);
+
+ emit_byte(cinfo, cinfo->data_precision);
+ emit_2bytes(cinfo, (int) cinfo->jpeg_height);
+ emit_2bytes(cinfo, (int) cinfo->jpeg_width);
+
+ emit_byte(cinfo, cinfo->num_components);
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ emit_byte(cinfo, compptr->component_id);
+ emit_byte(cinfo, (compptr->h_samp_factor << 4) + compptr->v_samp_factor);
+ emit_byte(cinfo, compptr->quant_tbl_no);
+ }
+}
+
+
+LOCAL(void)
+emit_sos (j_compress_ptr cinfo)
+/* Emit a SOS marker */
+{
+ int i, td, ta;
+ jpeg_component_info *compptr;
+
+ emit_marker(cinfo, M_SOS);
+
+ emit_2bytes(cinfo, 2 * cinfo->comps_in_scan + 2 + 1 + 3); /* length */
+
+ emit_byte(cinfo, cinfo->comps_in_scan);
+
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ emit_byte(cinfo, compptr->component_id);
+
+ /* We emit 0 for unused field(s); this is recommended by the P&M text
+ * but does not seem to be specified in the standard.
+ */
+
+ /* DC needs no table for refinement scan */
+ td = cinfo->Ss == 0 && cinfo->Ah == 0 ? compptr->dc_tbl_no : 0;
+ /* AC needs no table when not present */
+ ta = cinfo->Se ? compptr->ac_tbl_no : 0;
+
+ emit_byte(cinfo, (td << 4) + ta);
+ }
+
+ emit_byte(cinfo, cinfo->Ss);
+ emit_byte(cinfo, cinfo->Se);
+ emit_byte(cinfo, (cinfo->Ah << 4) + cinfo->Al);
+}
+
+
+LOCAL(void)
+emit_pseudo_sos (j_compress_ptr cinfo)
+/* Emit a pseudo SOS marker */
+{
+ emit_marker(cinfo, M_SOS);
+
+ emit_2bytes(cinfo, 2 + 1 + 3); /* length */
+
+ emit_byte(cinfo, 0); /* Ns */
+
+ emit_byte(cinfo, 0); /* Ss */
+ emit_byte(cinfo, cinfo->block_size * cinfo->block_size - 1); /* Se */
+ emit_byte(cinfo, 0); /* Ah/Al */
+}
+
+
+LOCAL(void)
+emit_jfif_app0 (j_compress_ptr cinfo)
+/* Emit a JFIF-compliant APP0 marker */
+{
+ /*
+ * Length of APP0 block (2 bytes)
+ * Block ID (4 bytes - ASCII "JFIF")
+ * Zero byte (1 byte to terminate the ID string)
+ * Version Major, Minor (2 bytes - major first)
+ * Units (1 byte - 0x00 = none, 0x01 = inch, 0x02 = cm)
+ * Xdpu (2 bytes - dots per unit horizontal)
+ * Ydpu (2 bytes - dots per unit vertical)
+ * Thumbnail X size (1 byte)
+ * Thumbnail Y size (1 byte)
+ */
+
+ emit_marker(cinfo, M_APP0);
+
+ emit_2bytes(cinfo, 2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); /* length */
+
+ emit_byte(cinfo, 0x4A); /* Identifier: ASCII "JFIF" */
+ emit_byte(cinfo, 0x46);
+ emit_byte(cinfo, 0x49);
+ emit_byte(cinfo, 0x46);
+ emit_byte(cinfo, 0);
+ emit_byte(cinfo, cinfo->JFIF_major_version); /* Version fields */
+ emit_byte(cinfo, cinfo->JFIF_minor_version);
+ emit_byte(cinfo, cinfo->density_unit); /* Pixel size information */
+ emit_2bytes(cinfo, (int) cinfo->X_density);
+ emit_2bytes(cinfo, (int) cinfo->Y_density);
+ emit_byte(cinfo, 0); /* No thumbnail image */
+ emit_byte(cinfo, 0);
+}
+
+
+LOCAL(void)
+emit_adobe_app14 (j_compress_ptr cinfo)
+/* Emit an Adobe APP14 marker */
+{
+ /*
+ * Length of APP14 block (2 bytes)
+ * Block ID (5 bytes - ASCII "Adobe")
+ * Version Number (2 bytes - currently 100)
+ * Flags0 (2 bytes - currently 0)
+ * Flags1 (2 bytes - currently 0)
+ * Color transform (1 byte)
+ *
+ * Although Adobe TN 5116 mentions Version = 101, all the Adobe files
+ * now in circulation seem to use Version = 100, so that's what we write.
+ *
+ * We write the color transform byte as 1 if the JPEG color space is
+ * YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with
+ * whether the encoder performed a transformation, which is pretty useless.
+ */
+
+ emit_marker(cinfo, M_APP14);
+
+ emit_2bytes(cinfo, 2 + 5 + 2 + 2 + 2 + 1); /* length */
+
+ emit_byte(cinfo, 0x41); /* Identifier: ASCII "Adobe" */
+ emit_byte(cinfo, 0x64);
+ emit_byte(cinfo, 0x6F);
+ emit_byte(cinfo, 0x62);
+ emit_byte(cinfo, 0x65);
+ emit_2bytes(cinfo, 100); /* Version */
+ emit_2bytes(cinfo, 0); /* Flags0 */
+ emit_2bytes(cinfo, 0); /* Flags1 */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_YCbCr:
+ emit_byte(cinfo, 1); /* Color transform = 1 */
+ break;
+ case JCS_YCCK:
+ emit_byte(cinfo, 2); /* Color transform = 2 */
+ break;
+ default:
+ emit_byte(cinfo, 0); /* Color transform = 0 */
+ break;
+ }
+}
+
+
+/*
+ * These routines allow writing an arbitrary marker with parameters.
+ * The only intended use is to emit COM or APPn markers after calling
+ * write_file_header and before calling write_frame_header.
+ * Other uses are not guaranteed to produce desirable results.
+ * Counting the parameter bytes properly is the caller's responsibility.
+ */
+
+METHODDEF(void)
+write_marker_header (j_compress_ptr cinfo, int marker, unsigned int datalen)
+/* Emit an arbitrary marker header */
+{
+ if (datalen > (unsigned int) 65533) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ emit_marker(cinfo, (JPEG_MARKER) marker);
+
+ emit_2bytes(cinfo, (int) (datalen + 2)); /* total length */
+}
+
+METHODDEF(void)
+write_marker_byte (j_compress_ptr cinfo, int val)
+/* Emit one byte of marker parameters following write_marker_header */
+{
+ emit_byte(cinfo, val);
+}
+
+
+/*
+ * Write datastream header.
+ * This consists of an SOI and optional APPn markers.
+ * We recommend use of the JFIF marker, but not the Adobe marker,
+ * when using YCbCr or grayscale data. The JFIF marker should NOT
+ * be used for any other JPEG colorspace. The Adobe marker is helpful
+ * to distinguish RGB, CMYK, and YCCK colorspaces.
+ * Note that an application can write additional header markers after
+ * jpeg_start_compress returns.
+ */
+
+METHODDEF(void)
+write_file_header (j_compress_ptr cinfo)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+ emit_marker(cinfo, M_SOI); /* first the SOI */
+
+ /* SOI is defined to reset restart interval to 0 */
+ marker->last_restart_interval = 0;
+
+ if (cinfo->write_JFIF_header) /* next an optional JFIF APP0 */
+ emit_jfif_app0(cinfo);
+ if (cinfo->write_Adobe_marker) /* next an optional Adobe APP14 */
+ emit_adobe_app14(cinfo);
+}
+
+
+/*
+ * Write frame header.
+ * This consists of DQT and SOFn markers, and a conditional pseudo SOS marker.
+ * Note that we do not emit the SOF until we have emitted the DQT(s).
+ * This avoids compatibility problems with incorrect implementations that
+ * try to error-check the quant table numbers as soon as they see the SOF.
+ */
+
+METHODDEF(void)
+write_frame_header (j_compress_ptr cinfo)
+{
+ int ci, prec;
+ boolean is_baseline;
+ jpeg_component_info *compptr;
+
+ /* Emit DQT for each quantization table.
+ * Note that emit_dqt() suppresses any duplicate tables.
+ */
+ prec = 0;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prec += emit_dqt(cinfo, compptr->quant_tbl_no);
+ }
+ /* now prec is nonzero iff there are any 16-bit quant tables. */
+
+ /* Check for a non-baseline specification.
+ * Note we assume that Huffman table numbers won't be changed later.
+ */
+ if (cinfo->arith_code || cinfo->progressive_mode ||
+ cinfo->data_precision != 8 || cinfo->block_size != DCTSIZE) {
+ is_baseline = FALSE;
+ } else {
+ is_baseline = TRUE;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->dc_tbl_no > 1 || compptr->ac_tbl_no > 1)
+ is_baseline = FALSE;
+ }
+ if (prec && is_baseline) {
+ is_baseline = FALSE;
+ /* If it's baseline except for quantizer size, warn the user */
+ TRACEMS(cinfo, 0, JTRC_16BIT_TABLES);
+ }
+ }
+
+ /* Emit the proper SOF marker */
+ if (cinfo->arith_code) {
+ if (cinfo->progressive_mode)
+ emit_sof(cinfo, M_SOF10); /* SOF code for progressive arithmetic */
+ else
+ emit_sof(cinfo, M_SOF9); /* SOF code for sequential arithmetic */
+ } else {
+ if (cinfo->progressive_mode)
+ emit_sof(cinfo, M_SOF2); /* SOF code for progressive Huffman */
+ else if (is_baseline)
+ emit_sof(cinfo, M_SOF0); /* SOF code for baseline implementation */
+ else
+ emit_sof(cinfo, M_SOF1); /* SOF code for non-baseline Huffman file */
+ }
+
+ /* Check to emit pseudo SOS marker */
+ if (cinfo->progressive_mode && cinfo->block_size != DCTSIZE)
+ emit_pseudo_sos(cinfo);
+}
+
+
+/*
+ * Write scan header.
+ * This consists of DHT or DAC markers, optional DRI, and SOS.
+ * Compressed data will be written following the SOS.
+ */
+
+METHODDEF(void)
+write_scan_header (j_compress_ptr cinfo)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+ int i;
+ jpeg_component_info *compptr;
+
+ if (cinfo->arith_code) {
+ /* Emit arith conditioning info. We may have some duplication
+ * if the file has multiple scans, but it's so small it's hardly
+ * worth worrying about.
+ */
+ emit_dac(cinfo);
+ } else {
+ /* Emit Huffman tables.
+ * Note that emit_dht() suppresses any duplicate tables.
+ */
+ for (i = 0; i < cinfo->comps_in_scan; i++) {
+ compptr = cinfo->cur_comp_info[i];
+ /* DC needs no table for refinement scan */
+ if (cinfo->Ss == 0 && cinfo->Ah == 0)
+ emit_dht(cinfo, compptr->dc_tbl_no, FALSE);
+ /* AC needs no table when not present */
+ if (cinfo->Se)
+ emit_dht(cinfo, compptr->ac_tbl_no, TRUE);
+ }
+ }
+
+ /* Emit DRI if required --- note that DRI value could change for each scan.
+ * We avoid wasting space with unnecessary DRIs, however.
+ */
+ if (cinfo->restart_interval != marker->last_restart_interval) {
+ emit_dri(cinfo);
+ marker->last_restart_interval = cinfo->restart_interval;
+ }
+
+ emit_sos(cinfo);
+}
+
+
+/*
+ * Write datastream trailer.
+ */
+
+METHODDEF(void)
+write_file_trailer (j_compress_ptr cinfo)
+{
+ emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Write an abbreviated table-specification datastream.
+ * This consists of SOI, DQT and DHT tables, and EOI.
+ * Any table that is defined and not marked sent_table = TRUE will be
+ * emitted. Note that all tables will be marked sent_table = TRUE at exit.
+ */
+
+METHODDEF(void)
+write_tables_only (j_compress_ptr cinfo)
+{
+ int i;
+
+ emit_marker(cinfo, M_SOI);
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++) {
+ if (cinfo->quant_tbl_ptrs[i] != NULL)
+ (void) emit_dqt(cinfo, i);
+ }
+
+ if (! cinfo->arith_code) {
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ if (cinfo->dc_huff_tbl_ptrs[i] != NULL)
+ emit_dht(cinfo, i, FALSE);
+ if (cinfo->ac_huff_tbl_ptrs[i] != NULL)
+ emit_dht(cinfo, i, TRUE);
+ }
+ }
+
+ emit_marker(cinfo, M_EOI);
+}
+
+
+/*
+ * Initialize the marker writer module.
+ */
+
+GLOBAL(void)
+jinit_marker_writer (j_compress_ptr cinfo)
+{
+ my_marker_ptr marker;
+
+ /* Create the subobject */
+ marker = (my_marker_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_marker_writer));
+ cinfo->marker = (struct jpeg_marker_writer *) marker;
+ /* Initialize method pointers */
+ marker->pub.write_file_header = write_file_header;
+ marker->pub.write_frame_header = write_frame_header;
+ marker->pub.write_scan_header = write_scan_header;
+ marker->pub.write_file_trailer = write_file_trailer;
+ marker->pub.write_tables_only = write_tables_only;
+ marker->pub.write_marker_header = write_marker_header;
+ marker->pub.write_marker_byte = write_marker_byte;
+ /* Initialize private state */
+ marker->last_restart_interval = 0;
+}
diff --git a/jpg/jcmaster.c b/jpg/jcmaster.c
new file mode 100644
index 0000000..caf80a5
--- /dev/null
+++ b/jpg/jcmaster.c
@@ -0,0 +1,858 @@
+/*
+ * jcmaster.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2003-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG compressor.
+ * These routines are concerned with parameter validation, initial setup,
+ * and inter-pass control (determining the number of passes and the work
+ * to be done in each pass).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef enum {
+ main_pass, /* input data, also do first output step */
+ huff_opt_pass, /* Huffman code optimization pass */
+ output_pass /* data output pass */
+} c_pass_type;
+
+typedef struct {
+ struct jpeg_comp_master pub; /* public fields */
+
+ c_pass_type pass_type; /* the type of the current pass */
+
+ int pass_number; /* # of passes completed */
+ int total_passes; /* total # of passes needed */
+
+ int scan_number; /* current index in scan_info[] */
+} my_comp_master;
+
+typedef my_comp_master * my_master_ptr;
+
+
+/*
+ * Support routines that do various essential calculations.
+ */
+
+/*
+ * Compute JPEG image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+GLOBAL(void)
+jpeg_calc_jpeg_dimensions (j_compress_ptr cinfo)
+/* Do computations that are needed before master selection phase */
+{
+#ifdef DCT_SCALING_SUPPORTED
+
+ /* Sanity check on input image dimensions to prevent overflow in
+ * following calculation.
+ * We do check jpeg_width and jpeg_height in initial_setup below,
+ * but image_width and image_height can come from arbitrary data,
+ * and we need some space for multiplication by block_size.
+ */
+ if (((long) cinfo->image_width >> 24) || ((long) cinfo->image_height >> 24))
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* Compute actual JPEG image dimensions and DCT scaling choices. */
+ if (cinfo->scale_num >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/1 scaling */
+ cinfo->jpeg_width = cinfo->image_width * cinfo->block_size;
+ cinfo->jpeg_height = cinfo->image_height * cinfo->block_size;
+ cinfo->min_DCT_h_scaled_size = 1;
+ cinfo->min_DCT_v_scaled_size = 1;
+ } else if (cinfo->scale_num * 2 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/2 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 2L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 2L);
+ cinfo->min_DCT_h_scaled_size = 2;
+ cinfo->min_DCT_v_scaled_size = 2;
+ } else if (cinfo->scale_num * 3 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/3 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 3L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 3L);
+ cinfo->min_DCT_h_scaled_size = 3;
+ cinfo->min_DCT_v_scaled_size = 3;
+ } else if (cinfo->scale_num * 4 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/4 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 4L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 4L);
+ cinfo->min_DCT_h_scaled_size = 4;
+ cinfo->min_DCT_v_scaled_size = 4;
+ } else if (cinfo->scale_num * 5 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/5 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 5L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 5L);
+ cinfo->min_DCT_h_scaled_size = 5;
+ cinfo->min_DCT_v_scaled_size = 5;
+ } else if (cinfo->scale_num * 6 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/6 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 6L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 6L);
+ cinfo->min_DCT_h_scaled_size = 6;
+ cinfo->min_DCT_v_scaled_size = 6;
+ } else if (cinfo->scale_num * 7 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/7 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 7L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 7L);
+ cinfo->min_DCT_h_scaled_size = 7;
+ cinfo->min_DCT_v_scaled_size = 7;
+ } else if (cinfo->scale_num * 8 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/8 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 8L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 8L);
+ cinfo->min_DCT_h_scaled_size = 8;
+ cinfo->min_DCT_v_scaled_size = 8;
+ } else if (cinfo->scale_num * 9 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/9 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 9L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 9L);
+ cinfo->min_DCT_h_scaled_size = 9;
+ cinfo->min_DCT_v_scaled_size = 9;
+ } else if (cinfo->scale_num * 10 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/10 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 10L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 10L);
+ cinfo->min_DCT_h_scaled_size = 10;
+ cinfo->min_DCT_v_scaled_size = 10;
+ } else if (cinfo->scale_num * 11 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/11 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 11L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 11L);
+ cinfo->min_DCT_h_scaled_size = 11;
+ cinfo->min_DCT_v_scaled_size = 11;
+ } else if (cinfo->scale_num * 12 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/12 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 12L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 12L);
+ cinfo->min_DCT_h_scaled_size = 12;
+ cinfo->min_DCT_v_scaled_size = 12;
+ } else if (cinfo->scale_num * 13 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/13 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 13L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 13L);
+ cinfo->min_DCT_h_scaled_size = 13;
+ cinfo->min_DCT_v_scaled_size = 13;
+ } else if (cinfo->scale_num * 14 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/14 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 14L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 14L);
+ cinfo->min_DCT_h_scaled_size = 14;
+ cinfo->min_DCT_v_scaled_size = 14;
+ } else if (cinfo->scale_num * 15 >= cinfo->scale_denom * cinfo->block_size) {
+ /* Provide block_size/15 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 15L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 15L);
+ cinfo->min_DCT_h_scaled_size = 15;
+ cinfo->min_DCT_v_scaled_size = 15;
+ } else {
+ /* Provide block_size/16 scaling */
+ cinfo->jpeg_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * cinfo->block_size, 16L);
+ cinfo->jpeg_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * cinfo->block_size, 16L);
+ cinfo->min_DCT_h_scaled_size = 16;
+ cinfo->min_DCT_v_scaled_size = 16;
+ }
+
+#else /* !DCT_SCALING_SUPPORTED */
+
+ /* Hardwire it to "no scaling" */
+ cinfo->jpeg_width = cinfo->image_width;
+ cinfo->jpeg_height = cinfo->image_height;
+ cinfo->min_DCT_h_scaled_size = DCTSIZE;
+ cinfo->min_DCT_v_scaled_size = DCTSIZE;
+
+#endif /* DCT_SCALING_SUPPORTED */
+}
+
+
+LOCAL(void)
+jpeg_calc_trans_dimensions (j_compress_ptr cinfo)
+{
+ if (cinfo->min_DCT_h_scaled_size != cinfo->min_DCT_v_scaled_size)
+ ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+ cinfo->min_DCT_h_scaled_size, cinfo->min_DCT_v_scaled_size);
+
+ cinfo->block_size = cinfo->min_DCT_h_scaled_size;
+}
+
+
+LOCAL(void)
+initial_setup (j_compress_ptr cinfo, boolean transcode_only)
+/* Do computations that are needed before master selection phase */
+{
+ int ci, ssize;
+ jpeg_component_info *compptr;
+ long samplesperrow;
+ JDIMENSION jd_samplesperrow;
+
+ if (transcode_only)
+ jpeg_calc_trans_dimensions(cinfo);
+ else
+ jpeg_calc_jpeg_dimensions(cinfo);
+
+ /* Sanity check on block_size */
+ if (cinfo->block_size < 1 || cinfo->block_size > 16)
+ ERREXIT2(cinfo, JERR_BAD_DCTSIZE, cinfo->block_size, cinfo->block_size);
+
+ /* Derive natural_order from block_size */
+ switch (cinfo->block_size) {
+ case 2: cinfo->natural_order = jpeg_natural_order2; break;
+ case 3: cinfo->natural_order = jpeg_natural_order3; break;
+ case 4: cinfo->natural_order = jpeg_natural_order4; break;
+ case 5: cinfo->natural_order = jpeg_natural_order5; break;
+ case 6: cinfo->natural_order = jpeg_natural_order6; break;
+ case 7: cinfo->natural_order = jpeg_natural_order7; break;
+ default: cinfo->natural_order = jpeg_natural_order; break;
+ }
+
+ /* Derive lim_Se from block_size */
+ cinfo->lim_Se = cinfo->block_size < DCTSIZE ?
+ cinfo->block_size * cinfo->block_size - 1 : DCTSIZE2-1;
+
+ /* Sanity check on image dimensions */
+ if (cinfo->jpeg_height <= 0 || cinfo->jpeg_width <= 0 ||
+ cinfo->num_components <= 0 || cinfo->input_components <= 0)
+ ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+ /* Make sure image isn't bigger than I can handle */
+ if ((long) cinfo->jpeg_height > (long) JPEG_MAX_DIMENSION ||
+ (long) cinfo->jpeg_width > (long) JPEG_MAX_DIMENSION)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* Width of an input scanline must be representable as JDIMENSION. */
+ samplesperrow = (long) cinfo->image_width * (long) cinfo->input_components;
+ jd_samplesperrow = (JDIMENSION) samplesperrow;
+ if ((long) jd_samplesperrow != samplesperrow)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* For now, precision must match compiled-in value... */
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Check that number of components won't exceed internal array sizes */
+ if (cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+
+ /* Compute maximum sampling factors; check factor validity */
+ cinfo->max_h_samp_factor = 1;
+ cinfo->max_v_samp_factor = 1;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
+ compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
+ ERREXIT(cinfo, JERR_BAD_SAMPLING);
+ cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
+ compptr->h_samp_factor);
+ cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
+ compptr->v_samp_factor);
+ }
+
+ /* Compute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Fill in the correct component_index value; don't rely on application */
+ compptr->component_index = ci;
+ /* In selecting the actual DCT scaling for each component, we try to
+ * scale down the chroma components via DCT scaling rather than downsampling.
+ * This saves time if the downsampler gets to use 1:1 scaling.
+ * Note this code adapts subsampling ratios which are powers of 2.
+ */
+ ssize = 1;
+#ifdef DCT_SCALING_SUPPORTED
+ while (cinfo->min_DCT_h_scaled_size * ssize <=
+ (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
+ (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) {
+ ssize = ssize * 2;
+ }
+#endif
+ compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;
+ ssize = 1;
+#ifdef DCT_SCALING_SUPPORTED
+ while (cinfo->min_DCT_v_scaled_size * ssize <=
+ (cinfo->do_fancy_downsampling ? DCTSIZE : DCTSIZE / 2) &&
+ (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) {
+ ssize = ssize * 2;
+ }
+#endif
+ compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;
+
+ /* We don't support DCT ratios larger than 2. */
+ if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;
+ else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)
+ compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;
+
+ /* Size in DCT blocks */
+ compptr->width_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_width * (long) compptr->h_samp_factor,
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ compptr->height_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_height * (long) compptr->v_samp_factor,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+ /* Size in samples */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_width *
+ (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_height *
+ (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+ /* Mark component needed (this flag isn't actually used for compression) */
+ compptr->component_needed = TRUE;
+ }
+
+ /* Compute number of fully interleaved MCU rows (number of times that
+ * main controller will call coefficient controller).
+ */
+ cinfo->total_iMCU_rows = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_height,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+}
+
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+
+LOCAL(void)
+validate_script (j_compress_ptr cinfo)
+/* Verify that the scan script in cinfo->scan_info[] is valid; also
+ * determine whether it uses progressive JPEG, and set cinfo->progressive_mode.
+ */
+{
+ const jpeg_scan_info * scanptr;
+ int scanno, ncomps, ci, coefi, thisi;
+ int Ss, Se, Ah, Al;
+ boolean component_sent[MAX_COMPONENTS];
+#ifdef C_PROGRESSIVE_SUPPORTED
+ int * last_bitpos_ptr;
+ int last_bitpos[MAX_COMPONENTS][DCTSIZE2];
+ /* -1 until that coefficient has been seen; then last Al for it */
+#endif
+
+ if (cinfo->num_scans <= 0)
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, 0);
+
+ /* For sequential JPEG, all scans must have Ss=0, Se=DCTSIZE2-1;
+ * for progressive JPEG, no scan can have this.
+ */
+ scanptr = cinfo->scan_info;
+ if (scanptr->Ss != 0 || scanptr->Se != DCTSIZE2-1) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ cinfo->progressive_mode = TRUE;
+ last_bitpos_ptr = & last_bitpos[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (coefi = 0; coefi < DCTSIZE2; coefi++)
+ *last_bitpos_ptr++ = -1;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ cinfo->progressive_mode = FALSE;
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ component_sent[ci] = FALSE;
+ }
+
+ for (scanno = 1; scanno <= cinfo->num_scans; scanptr++, scanno++) {
+ /* Validate component indexes */
+ ncomps = scanptr->comps_in_scan;
+ if (ncomps <= 0 || ncomps > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, ncomps, MAX_COMPS_IN_SCAN);
+ for (ci = 0; ci < ncomps; ci++) {
+ thisi = scanptr->component_index[ci];
+ if (thisi < 0 || thisi >= cinfo->num_components)
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ /* Components must appear in SOF order within each scan */
+ if (ci > 0 && thisi <= scanptr->component_index[ci-1])
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ }
+ /* Validate progression parameters */
+ Ss = scanptr->Ss;
+ Se = scanptr->Se;
+ Ah = scanptr->Ah;
+ Al = scanptr->Al;
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ /* The JPEG spec simply gives the ranges 0..13 for Ah and Al, but that
+ * seems wrong: the upper bound ought to depend on data precision.
+ * Perhaps they really meant 0..N+1 for N-bit precision.
+ * Here we allow 0..10 for 8-bit data; Al larger than 10 results in
+ * out-of-range reconstructed DC values during the first DC scan,
+ * which might cause problems for some decoders.
+ */
+#if BITS_IN_JSAMPLE == 8
+#define MAX_AH_AL 10
+#else
+#define MAX_AH_AL 13
+#endif
+ if (Ss < 0 || Ss >= DCTSIZE2 || Se < Ss || Se >= DCTSIZE2 ||
+ Ah < 0 || Ah > MAX_AH_AL || Al < 0 || Al > MAX_AH_AL)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ if (Ss == 0) {
+ if (Se != 0) /* DC and AC together not OK */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ } else {
+ if (ncomps != 1) /* AC scans must be for only one component */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ }
+ for (ci = 0; ci < ncomps; ci++) {
+ last_bitpos_ptr = & last_bitpos[scanptr->component_index[ci]][0];
+ if (Ss != 0 && last_bitpos_ptr[0] < 0) /* AC without prior DC scan */
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ for (coefi = Ss; coefi <= Se; coefi++) {
+ if (last_bitpos_ptr[coefi] < 0) {
+ /* first scan of this coefficient */
+ if (Ah != 0)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ } else {
+ /* not first scan */
+ if (Ah != last_bitpos_ptr[coefi] || Al != Ah-1)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ }
+ last_bitpos_ptr[coefi] = Al;
+ }
+ }
+#endif
+ } else {
+ /* For sequential JPEG, all progression parameters must be these: */
+ if (Ss != 0 || Se != DCTSIZE2-1 || Ah != 0 || Al != 0)
+ ERREXIT1(cinfo, JERR_BAD_PROG_SCRIPT, scanno);
+ /* Make sure components are not sent twice */
+ for (ci = 0; ci < ncomps; ci++) {
+ thisi = scanptr->component_index[ci];
+ if (component_sent[thisi])
+ ERREXIT1(cinfo, JERR_BAD_SCAN_SCRIPT, scanno);
+ component_sent[thisi] = TRUE;
+ }
+ }
+ }
+
+ /* Now verify that everything got sent. */
+ if (cinfo->progressive_mode) {
+#ifdef C_PROGRESSIVE_SUPPORTED
+ /* For progressive mode, we only check that at least some DC data
+ * got sent for each component; the spec does not require that all bits
+ * of all coefficients be transmitted. Would it be wiser to enforce
+ * transmission of all coefficient bits??
+ */
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ if (last_bitpos[ci][0] < 0)
+ ERREXIT(cinfo, JERR_MISSING_DATA);
+ }
+#endif
+ } else {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ if (! component_sent[ci])
+ ERREXIT(cinfo, JERR_MISSING_DATA);
+ }
+ }
+}
+
+
+LOCAL(void)
+reduce_script (j_compress_ptr cinfo)
+/* Adapt scan script for use with reduced block size;
+ * assume that script has been validated before.
+ */
+{
+ jpeg_scan_info * scanptr;
+ int idxout, idxin;
+
+ /* Circumvent const declaration for this function */
+ scanptr = (jpeg_scan_info *) cinfo->scan_info;
+ idxout = 0;
+
+ for (idxin = 0; idxin < cinfo->num_scans; idxin++) {
+ /* After skipping, idxout becomes smaller than idxin */
+ if (idxin != idxout)
+ /* Copy rest of data;
+ * note we stay in given chunk of allocated memory.
+ */
+ scanptr[idxout] = scanptr[idxin];
+ if (scanptr[idxout].Ss > cinfo->lim_Se)
+ /* Entire scan out of range - skip this entry */
+ continue;
+ if (scanptr[idxout].Se > cinfo->lim_Se)
+ /* Limit scan to end of block */
+ scanptr[idxout].Se = cinfo->lim_Se;
+ idxout++;
+ }
+
+ cinfo->num_scans = idxout;
+}
+
+#endif /* C_MULTISCAN_FILES_SUPPORTED */
+
+
+LOCAL(void)
+select_scan_parameters (j_compress_ptr cinfo)
+/* Set up the scan parameters for the current scan */
+{
+ int ci;
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (cinfo->scan_info != NULL) {
+ /* Prepare for current scan --- the script is already validated */
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+ const jpeg_scan_info * scanptr = cinfo->scan_info + master->scan_number;
+
+ cinfo->comps_in_scan = scanptr->comps_in_scan;
+ for (ci = 0; ci < scanptr->comps_in_scan; ci++) {
+ cinfo->cur_comp_info[ci] =
+ &cinfo->comp_info[scanptr->component_index[ci]];
+ }
+ if (cinfo->progressive_mode) {
+ cinfo->Ss = scanptr->Ss;
+ cinfo->Se = scanptr->Se;
+ cinfo->Ah = scanptr->Ah;
+ cinfo->Al = scanptr->Al;
+ return;
+ }
+ }
+ else
+#endif
+ {
+ /* Prepare for single sequential-JPEG scan containing all components */
+ if (cinfo->num_components > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPS_IN_SCAN);
+ cinfo->comps_in_scan = cinfo->num_components;
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ cinfo->cur_comp_info[ci] = &cinfo->comp_info[ci];
+ }
+ }
+ cinfo->Ss = 0;
+ cinfo->Se = cinfo->block_size * cinfo->block_size - 1;
+ cinfo->Ah = 0;
+ cinfo->Al = 0;
+}
+
+
+LOCAL(void)
+per_scan_setup (j_compress_ptr cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo->comps_in_scan and cinfo->cur_comp_info[] are already set */
+{
+ int ci, mcublks, tmp;
+ jpeg_component_info *compptr;
+
+ if (cinfo->comps_in_scan == 1) {
+
+ /* Noninterleaved (single-component) scan */
+ compptr = cinfo->cur_comp_info[0];
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = compptr->width_in_blocks;
+ cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
+
+ /* For noninterleaved scan, always one block per MCU */
+ compptr->MCU_width = 1;
+ compptr->MCU_height = 1;
+ compptr->MCU_blocks = 1;
+ compptr->MCU_sample_width = compptr->DCT_h_scaled_size;
+ compptr->last_col_width = 1;
+ /* For noninterleaved scans, it is convenient to define last_row_height
+ * as the number of block rows present in the last iMCU row.
+ */
+ tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (tmp == 0) tmp = compptr->v_samp_factor;
+ compptr->last_row_height = tmp;
+
+ /* Prepare array describing MCU composition */
+ cinfo->blocks_in_MCU = 1;
+ cinfo->MCU_membership[0] = 0;
+
+ } else {
+
+ /* Interleaved (multi-component) scan */
+ if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
+ MAX_COMPS_IN_SCAN);
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_width,
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ cinfo->MCU_rows_in_scan = (JDIMENSION)
+ jdiv_round_up((long) cinfo->jpeg_height,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+
+ cinfo->blocks_in_MCU = 0;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Sampling factors give # of blocks of component in each MCU */
+ compptr->MCU_width = compptr->h_samp_factor;
+ compptr->MCU_height = compptr->v_samp_factor;
+ compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
+ compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;
+ /* Figure number of non-dummy blocks in last MCU column & row */
+ tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
+ if (tmp == 0) tmp = compptr->MCU_width;
+ compptr->last_col_width = tmp;
+ tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
+ if (tmp == 0) tmp = compptr->MCU_height;
+ compptr->last_row_height = tmp;
+ /* Prepare array describing MCU composition */
+ mcublks = compptr->MCU_blocks;
+ if (cinfo->blocks_in_MCU + mcublks > C_MAX_BLOCKS_IN_MCU)
+ ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+ while (mcublks-- > 0) {
+ cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
+ }
+ }
+
+ }
+
+ /* Convert restart specified in rows to actual MCU count. */
+ /* Note that count must fit in 16 bits, so we provide limiting. */
+ if (cinfo->restart_in_rows > 0) {
+ long nominal = (long) cinfo->restart_in_rows * (long) cinfo->MCUs_per_row;
+ cinfo->restart_interval = (unsigned int) MIN(nominal, 65535L);
+ }
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each pass. We determine which modules
+ * will be active during this pass and give them appropriate start_pass calls.
+ * We also set is_last_pass to indicate whether any more passes will be
+ * required.
+ */
+
+METHODDEF(void)
+prepare_for_pass (j_compress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ switch (master->pass_type) {
+ case main_pass:
+ /* Initial pass: will collect input data, and do either Huffman
+ * optimization or data output for the first scan.
+ */
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ if (! cinfo->raw_data_in) {
+ (*cinfo->cconvert->start_pass) (cinfo);
+ (*cinfo->downsample->start_pass) (cinfo);
+ (*cinfo->prep->start_pass) (cinfo, JBUF_PASS_THRU);
+ }
+ (*cinfo->fdct->start_pass) (cinfo);
+ (*cinfo->entropy->start_pass) (cinfo, cinfo->optimize_coding);
+ (*cinfo->coef->start_pass) (cinfo,
+ (master->total_passes > 1 ?
+ JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+ if (cinfo->optimize_coding) {
+ /* No immediate data output; postpone writing frame/scan headers */
+ master->pub.call_pass_startup = FALSE;
+ } else {
+ /* Will write frame/scan headers at first jpeg_write_scanlines call */
+ master->pub.call_pass_startup = TRUE;
+ }
+ break;
+#ifdef ENTROPY_OPT_SUPPORTED
+ case huff_opt_pass:
+ /* Do Huffman optimization for a scan after the first one. */
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ if (cinfo->Ss != 0 || cinfo->Ah == 0) {
+ (*cinfo->entropy->start_pass) (cinfo, TRUE);
+ (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
+ master->pub.call_pass_startup = FALSE;
+ break;
+ }
+ /* Special case: Huffman DC refinement scans need no Huffman table
+ * and therefore we can skip the optimization pass for them.
+ */
+ master->pass_type = output_pass;
+ master->pass_number++;
+ /*FALLTHROUGH*/
+#endif
+ case output_pass:
+ /* Do a data-output pass. */
+ /* We need not repeat per-scan setup if prior optimization pass did it. */
+ if (! cinfo->optimize_coding) {
+ select_scan_parameters(cinfo);
+ per_scan_setup(cinfo);
+ }
+ (*cinfo->entropy->start_pass) (cinfo, FALSE);
+ (*cinfo->coef->start_pass) (cinfo, JBUF_CRANK_DEST);
+ /* We emit frame/scan headers now */
+ if (master->scan_number == 0)
+ (*cinfo->marker->write_frame_header) (cinfo);
+ (*cinfo->marker->write_scan_header) (cinfo);
+ master->pub.call_pass_startup = FALSE;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ }
+
+ master->pub.is_last_pass = (master->pass_number == master->total_passes-1);
+
+ /* Set up progress monitor's pass info if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->completed_passes = master->pass_number;
+ cinfo->progress->total_passes = master->total_passes;
+ }
+}
+
+
+/*
+ * Special start-of-pass hook.
+ * This is called by jpeg_write_scanlines if call_pass_startup is TRUE.
+ * In single-pass processing, we need this hook because we don't want to
+ * write frame/scan headers during jpeg_start_compress; we want to let the
+ * application write COM markers etc. between jpeg_start_compress and the
+ * jpeg_write_scanlines loop.
+ * In multi-pass processing, this routine is not used.
+ */
+
+METHODDEF(void)
+pass_startup (j_compress_ptr cinfo)
+{
+ cinfo->master->call_pass_startup = FALSE; /* reset flag so call only once */
+
+ (*cinfo->marker->write_frame_header) (cinfo);
+ (*cinfo->marker->write_scan_header) (cinfo);
+}
+
+
+/*
+ * Finish up at end of pass.
+ */
+
+METHODDEF(void)
+finish_pass_master (j_compress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ /* The entropy coder always needs an end-of-pass call,
+ * either to analyze statistics or to flush its output buffer.
+ */
+ (*cinfo->entropy->finish_pass) (cinfo);
+
+ /* Update state for next pass */
+ switch (master->pass_type) {
+ case main_pass:
+ /* next pass is either output of scan 0 (after optimization)
+ * or output of scan 1 (if no optimization).
+ */
+ master->pass_type = output_pass;
+ if (! cinfo->optimize_coding)
+ master->scan_number++;
+ break;
+ case huff_opt_pass:
+ /* next pass is always output of current scan */
+ master->pass_type = output_pass;
+ break;
+ case output_pass:
+ /* next pass is either optimization or output of next scan */
+ if (cinfo->optimize_coding)
+ master->pass_type = huff_opt_pass;
+ master->scan_number++;
+ break;
+ }
+
+ master->pass_number++;
+}
+
+
+/*
+ * Initialize master compression control.
+ */
+
+GLOBAL(void)
+jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
+{
+ my_master_ptr master;
+
+ master = (my_master_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_comp_master));
+ cinfo->master = (struct jpeg_comp_master *) master;
+ master->pub.prepare_for_pass = prepare_for_pass;
+ master->pub.pass_startup = pass_startup;
+ master->pub.finish_pass = finish_pass_master;
+ master->pub.is_last_pass = FALSE;
+
+ /* Validate parameters, determine derived values */
+ initial_setup(cinfo, transcode_only);
+
+ if (cinfo->scan_info != NULL) {
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ validate_script(cinfo);
+ if (cinfo->block_size < DCTSIZE)
+ reduce_script(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ cinfo->progressive_mode = FALSE;
+ cinfo->num_scans = 1;
+ }
+
+ if ((cinfo->progressive_mode || cinfo->block_size < DCTSIZE) &&
+ !cinfo->arith_code) /* TEMPORARY HACK ??? */
+ /* assume default tables no good for progressive or downscale mode */
+ cinfo->optimize_coding = TRUE;
+
+ /* Initialize my private state */
+ if (transcode_only) {
+ /* no main pass in transcoding */
+ if (cinfo->optimize_coding)
+ master->pass_type = huff_opt_pass;
+ else
+ master->pass_type = output_pass;
+ } else {
+ /* for normal compression, first pass is always this type: */
+ master->pass_type = main_pass;
+ }
+ master->scan_number = 0;
+ master->pass_number = 0;
+ if (cinfo->optimize_coding)
+ master->total_passes = cinfo->num_scans * 2;
+ else
+ master->total_passes = cinfo->num_scans;
+}
diff --git a/jpg/jcomapi.c b/jpg/jcomapi.c
new file mode 100644
index 0000000..9b1fa75
--- /dev/null
+++ b/jpg/jcomapi.c
@@ -0,0 +1,106 @@
+/*
+ * jcomapi.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface routines that are used for both
+ * compression and decompression.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Abort processing of a JPEG compression or decompression operation,
+ * but don't destroy the object itself.
+ *
+ * For this, we merely clean up all the nonpermanent memory pools.
+ * Note that temp files (virtual arrays) are not allowed to belong to
+ * the permanent pool, so we will be able to close all temp files here.
+ * Closing a data source or destination, if necessary, is the application's
+ * responsibility.
+ */
+
+GLOBAL(void)
+jpeg_abort (j_common_ptr cinfo)
+{
+ int pool;
+
+ /* Do nothing if called on a not-initialized or destroyed JPEG object. */
+ if (cinfo->mem == NULL)
+ return;
+
+ /* Releasing pools in reverse order might help avoid fragmentation
+ * with some (brain-damaged) malloc libraries.
+ */
+ for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) {
+ (*cinfo->mem->free_pool) (cinfo, pool);
+ }
+
+ /* Reset overall state for possible reuse of object */
+ if (cinfo->is_decompressor) {
+ cinfo->global_state = DSTATE_START;
+ /* Try to keep application from accessing now-deleted marker list.
+ * A bit kludgy to do it here, but this is the most central place.
+ */
+ ((j_decompress_ptr) cinfo)->marker_list = NULL;
+ } else {
+ cinfo->global_state = CSTATE_START;
+ }
+}
+
+
+/*
+ * Destruction of a JPEG object.
+ *
+ * Everything gets deallocated except the master jpeg_compress_struct itself
+ * and the error manager struct. Both of these are supplied by the application
+ * and must be freed, if necessary, by the application. (Often they are on
+ * the stack and so don't need to be freed anyway.)
+ * Closing a data source or destination, if necessary, is the application's
+ * responsibility.
+ */
+
+GLOBAL(void)
+jpeg_destroy (j_common_ptr cinfo)
+{
+ /* We need only tell the memory manager to release everything. */
+ /* NB: mem pointer is NULL if memory mgr failed to initialize. */
+ if (cinfo->mem != NULL)
+ (*cinfo->mem->self_destruct) (cinfo);
+ cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */
+ cinfo->global_state = 0; /* mark it destroyed */
+}
+
+
+/*
+ * Convenience routines for allocating quantization and Huffman tables.
+ * (Would jutils.c be a more reasonable place to put these?)
+ */
+
+GLOBAL(JQUANT_TBL *)
+jpeg_alloc_quant_table (j_common_ptr cinfo)
+{
+ JQUANT_TBL *tbl;
+
+ tbl = (JQUANT_TBL *)
+ (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL));
+ tbl->sent_table = FALSE; /* make sure this is false in any new table */
+ return tbl;
+}
+
+
+GLOBAL(JHUFF_TBL *)
+jpeg_alloc_huff_table (j_common_ptr cinfo)
+{
+ JHUFF_TBL *tbl;
+
+ tbl = (JHUFF_TBL *)
+ (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL));
+ tbl->sent_table = FALSE; /* make sure this is false in any new table */
+ return tbl;
+}
diff --git a/jpg/jconfig.bcc b/jpg/jconfig.bcc
new file mode 100644
index 0000000..e4da3d7
--- /dev/null
+++ b/jpg/jconfig.bcc
@@ -0,0 +1,48 @@
+/* jconfig.bcc --- jconfig.h for Borland C (Turbo C) on MS-DOS or OS/2. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#ifdef __MSDOS__
+#define NEED_FAR_POINTERS /* for small or medium memory model */
+#endif
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN /* this assumes you have -w-stu in CFLAGS */
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#ifdef __MSDOS__
+#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */
+#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */
+#define USE_FMEM /* Borland has _fmemcpy() and _fmemset() */
+#endif
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define USE_SETMODE /* Borland has setmode() */
+#ifdef __MSDOS__
+#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */
+#endif
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.cfg b/jpg/jconfig.cfg
new file mode 100644
index 0000000..5269eb3
--- /dev/null
+++ b/jpg/jconfig.cfg
@@ -0,0 +1,53 @@
+/* jconfig.cfg --- source file edited by configure script */
+/* see jconfig.txt for explanations */
+
+#undef HAVE_PROTOTYPES
+#undef HAVE_UNSIGNED_CHAR
+#undef HAVE_UNSIGNED_SHORT
+#undef void
+#undef const
+#undef CHAR_IS_UNSIGNED
+#undef HAVE_STDDEF_H
+#undef HAVE_STDLIB_H
+#undef HAVE_LOCALE_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+/* Define this if you get warnings about undefined structures. */
+#undef INCOMPLETE_TYPES_BROKEN
+
+/* Define "boolean" as unsigned char, not int, on Windows systems. */
+#ifdef _WIN32
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+#endif
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+#undef INLINE
+/* These are for configuring the JPEG memory manager. */
+#undef DEFAULT_MAX_MEM
+#undef NO_MKTEMP
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#undef BMP_SUPPORTED /* BMP image file format */
+#undef GIF_SUPPORTED /* GIF image file format */
+#undef PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#undef TARGA_SUPPORTED /* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+
+/* Define this if you want percent-done progress reports from cjpeg/djpeg. */
+#undef PROGRESS_REPORT
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.dj b/jpg/jconfig.dj
new file mode 100644
index 0000000..a0d4092
--- /dev/null
+++ b/jpg/jconfig.dj
@@ -0,0 +1,38 @@
+/* jconfig.dj --- jconfig.h for DJGPP (Delorie's GNU C port) on MS-DOS. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS /* DJGPP uses flat 32-bit addressing */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE /* optional */
+#define USE_SETMODE /* Needed to make one-file style work in DJGPP */
+#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.mac b/jpg/jconfig.mac
new file mode 100644
index 0000000..70ed66c
--- /dev/null
+++ b/jpg/jconfig.mac
@@ -0,0 +1,43 @@
+/* jconfig.mac --- jconfig.h for CodeWarrior on Apple Macintosh */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define USE_MAC_MEMMGR /* Define this if you use jmemmac.c */
+
+#define ALIGN_TYPE long /* Needed for 680x0 Macs */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define USE_CCOMMAND /* Command line reader for Macintosh */
+#define TWO_FILE_COMMANDLINE /* Binary I/O thru stdin/stdout doesn't work */
+
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.manx b/jpg/jconfig.manx
new file mode 100644
index 0000000..cd529d7
--- /dev/null
+++ b/jpg/jconfig.manx
@@ -0,0 +1,43 @@
+/* jconfig.manx --- jconfig.h for Amiga systems using Manx Aztec C ver 5.x. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define TEMP_DIRECTORY "JPEGTMP:" /* recommended setting for Amiga */
+
+#define SHORTxSHORT_32 /* produces better DCT code with Aztec C */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#define signal_catcher _abort /* hack for Aztec C naming requirements */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.mc6 b/jpg/jconfig.mc6
new file mode 100644
index 0000000..6b05e81
--- /dev/null
+++ b/jpg/jconfig.mc6
@@ -0,0 +1,52 @@
+/* jconfig.mc6 --- jconfig.h for Microsoft C on MS-DOS, version 6.00A & up. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#define NEED_FAR_POINTERS /* for small or medium memory model */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define USE_MSDOS_MEMMGR /* Define this if you use jmemdos.c */
+
+#define MAX_ALLOC_CHUNK 65520L /* Maximum request to malloc() */
+
+#define USE_FMEM /* Microsoft has _fmemcpy() and _fmemset() */
+
+#define NEED_FHEAPMIN /* far heap management routines are broken */
+
+#define SHORTxLCONST_32 /* enable compiler-specific DCT optimization */
+/* Note: the above define is known to improve the code with Microsoft C 6.00A.
+ * I do not know whether it is good for later compiler versions.
+ * Please report any info on this point to jpeg-info@jpegclub.org.
+ */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define USE_SETMODE /* Microsoft has setmode() */
+#define NEED_SIGNAL_CATCHER /* Define this if you use jmemdos.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.sas b/jpg/jconfig.sas
new file mode 100644
index 0000000..b8a1819
--- /dev/null
+++ b/jpg/jconfig.sas
@@ -0,0 +1,43 @@
+/* jconfig.sas --- jconfig.h for Amiga systems using SAS C 6.0 and up. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define TEMP_DIRECTORY "JPEGTMP:" /* recommended setting for Amiga */
+
+#define NO_MKTEMP /* SAS C doesn't have mktemp() */
+
+#define SHORTxSHORT_32 /* produces better DCT code with SAS C */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE
+#define NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.st b/jpg/jconfig.st
new file mode 100644
index 0000000..5afa0b6
--- /dev/null
+++ b/jpg/jconfig.st
@@ -0,0 +1,42 @@
+/* jconfig.st --- jconfig.h for Atari ST/STE/TT using Pure C or Turbo C. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#define INCOMPLETE_TYPES_BROKEN /* suppress undefined-structure warnings */
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#define ALIGN_TYPE long /* apparently double is a weird size? */
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE /* optional -- undef if you like Unix style */
+/* Note: if you undef TWO_FILE_COMMANDLINE, you may need to define
+ * USE_SETMODE. Some Atari compilers require it, some do not.
+ */
+#define NEED_SIGNAL_CATCHER /* needed if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.txt b/jpg/jconfig.txt
new file mode 100644
index 0000000..b96d312
--- /dev/null
+++ b/jpg/jconfig.txt
@@ -0,0 +1,164 @@
+/*
+ * jconfig.txt
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file documents the configuration options that are required to
+ * customize the JPEG software for a particular system.
+ *
+ * The actual configuration options for a particular installation are stored
+ * in jconfig.h. On many machines, jconfig.h can be generated automatically
+ * or copied from one of the "canned" jconfig files that we supply. But if
+ * you need to generate a jconfig.h file by hand, this file tells you how.
+ *
+ * DO NOT EDIT THIS FILE --- IT WON'T ACCOMPLISH ANYTHING.
+ * EDIT A COPY NAMED JCONFIG.H.
+ */
+
+
+/*
+ * These symbols indicate the properties of your machine or compiler.
+ * #define the symbol if yes, #undef it if no.
+ */
+
+/* Does your compiler support function prototypes?
+ * (If not, you also need to use ansi2knr, see install.txt)
+ */
+#define HAVE_PROTOTYPES
+
+/* Does your compiler support the declaration "unsigned char" ?
+ * How about "unsigned short" ?
+ */
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+
+/* Define "void" as "char" if your compiler doesn't know about type void.
+ * NOTE: be sure to define void such that "void *" represents the most general
+ * pointer type, e.g., that returned by malloc().
+ */
+/* #define void char */
+
+/* Define "const" as empty if your compiler doesn't know the "const" keyword.
+ */
+/* #define const */
+
+/* Define this if an ordinary "char" type is unsigned.
+ * If you're not sure, leaving it undefined will work at some cost in speed.
+ * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
+ */
+#undef CHAR_IS_UNSIGNED
+
+/* Define this if your system has an ANSI-conforming <stddef.h> file.
+ */
+#define HAVE_STDDEF_H
+
+/* Define this if your system has an ANSI-conforming <stdlib.h> file.
+ */
+#define HAVE_STDLIB_H
+
+/* Define this if your system does not have an ANSI/SysV <string.h>,
+ * but does have a BSD-style <strings.h>.
+ */
+#undef NEED_BSD_STRINGS
+
+/* Define this if your system does not provide typedef size_t in any of the
+ * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
+ * <sys/types.h> instead.
+ */
+#undef NEED_SYS_TYPES_H
+
+/* For 80x86 machines, you need to define NEED_FAR_POINTERS,
+ * unless you are using a large-data memory model or 80386 flat-memory mode.
+ * On less brain-damaged CPUs this symbol must not be defined.
+ * (Defining this symbol causes large data structures to be referenced through
+ * "far" pointers and to be allocated with a special version of malloc.)
+ */
+#undef NEED_FAR_POINTERS
+
+/* Define this if your linker needs global names to be unique in less
+ * than the first 15 characters.
+ */
+#undef NEED_SHORT_EXTERNAL_NAMES
+
+/* Although a real ANSI C compiler can deal perfectly well with pointers to
+ * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
+ * and pseudo-ANSI compilers get confused. To keep one of these bozos happy,
+ * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you
+ * actually get "missing structure definition" warnings or errors while
+ * compiling the JPEG code.
+ */
+#undef INCOMPLETE_TYPES_BROKEN
+
+/* Define "boolean" as unsigned char, not int, on Windows systems.
+ */
+#ifdef _WIN32
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+#endif
+
+
+/*
+ * The following options affect code selection within the JPEG library,
+ * but they don't need to be visible to applications using the library.
+ * To minimize application namespace pollution, the symbols won't be
+ * defined unless JPEG_INTERNALS has been defined.
+ */
+
+#ifdef JPEG_INTERNALS
+
+/* Define this if your compiler implements ">>" on signed values as a logical
+ * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
+ * which is the normal and rational definition.
+ */
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+
+#endif /* JPEG_INTERNALS */
+
+
+/*
+ * The remaining options do not affect the JPEG library proper,
+ * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
+ * Other applications can ignore these.
+ */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+/* These defines indicate which image (non-JPEG) file formats are allowed. */
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+/* Define this if you want to name both input and output files on the command
+ * line, rather than using stdout and optionally stdin. You MUST do this if
+ * your system can't cope with binary I/O to stdin/stdout. See comments at
+ * head of cjpeg.c or djpeg.c.
+ */
+#undef TWO_FILE_COMMANDLINE
+
+/* Define this if your system needs explicit cleanup of temporary files.
+ * This is crucial under MS-DOS, where the temporary "files" may be areas
+ * of extended memory; on most other systems it's not as important.
+ */
+#undef NEED_SIGNAL_CATCHER
+
+/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb").
+ * This is necessary on systems that distinguish text files from binary files,
+ * and is harmless on most systems that don't. If you have one of the rare
+ * systems that complains about the "b" spec, define this symbol.
+ */
+#undef DONT_USE_B_MODE
+
+/* Define this if you want percent-done progress reports from cjpeg/djpeg.
+ */
+#undef PROGRESS_REPORT
+
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.vc b/jpg/jconfig.vc
new file mode 100644
index 0000000..55d2b00
--- /dev/null
+++ b/jpg/jconfig.vc
@@ -0,0 +1,45 @@
+/* jconfig.vc --- jconfig.h for Microsoft Visual C++ on Windows 95 or NT. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS /* we presume a 32-bit flat memory model */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+/* Define "boolean" as unsigned char, not int, per Windows custom */
+#ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+typedef unsigned char boolean;
+#endif
+#define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#undef BMP_SUPPORTED /* BMP image file format */
+#undef GIF_SUPPORTED /* GIF image file format */
+#undef PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#undef TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE /* optional */
+#define USE_SETMODE /* Microsoft has setmode() */
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.vms b/jpg/jconfig.vms
new file mode 100644
index 0000000..8337b0b
--- /dev/null
+++ b/jpg/jconfig.vms
@@ -0,0 +1,37 @@
+/* jconfig.vms --- jconfig.h for use on Digital VMS. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#undef CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#define TWO_FILE_COMMANDLINE /* Needed on VMS */
+#undef NEED_SIGNAL_CATCHER
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jconfig.wat b/jpg/jconfig.wat
new file mode 100644
index 0000000..190cc75
--- /dev/null
+++ b/jpg/jconfig.wat
@@ -0,0 +1,38 @@
+/* jconfig.wat --- jconfig.h for Watcom C/C++ on MS-DOS or OS/2. */
+/* see jconfig.txt for explanations */
+
+#define HAVE_PROTOTYPES
+#define HAVE_UNSIGNED_CHAR
+#define HAVE_UNSIGNED_SHORT
+/* #define void char */
+/* #define const */
+#define CHAR_IS_UNSIGNED
+#define HAVE_STDDEF_H
+#define HAVE_STDLIB_H
+#undef NEED_BSD_STRINGS
+#undef NEED_SYS_TYPES_H
+#undef NEED_FAR_POINTERS /* Watcom uses flat 32-bit addressing */
+#undef NEED_SHORT_EXTERNAL_NAMES
+#undef INCOMPLETE_TYPES_BROKEN
+
+#ifdef JPEG_INTERNALS
+
+#undef RIGHT_SHIFT_IS_UNSIGNED
+
+#endif /* JPEG_INTERNALS */
+
+#ifdef JPEG_CJPEG_DJPEG
+
+#define BMP_SUPPORTED /* BMP image file format */
+#define GIF_SUPPORTED /* GIF image file format */
+#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */
+#undef RLE_SUPPORTED /* Utah RLE image file format */
+#define TARGA_SUPPORTED /* Targa image file format */
+
+#undef TWO_FILE_COMMANDLINE /* optional */
+#define USE_SETMODE /* Needed to make one-file style work in Watcom */
+#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */
+#undef DONT_USE_B_MODE
+#undef PROGRESS_REPORT /* optional */
+
+#endif /* JPEG_CJPEG_DJPEG */
diff --git a/jpg/jcparam.c b/jpg/jcparam.c
new file mode 100644
index 0000000..c5e85dd
--- /dev/null
+++ b/jpg/jcparam.c
@@ -0,0 +1,632 @@
+/*
+ * jcparam.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2003-2008 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains optional default-setting code for the JPEG compressor.
+ * Applications do not have to use this file, but those that don't use it
+ * must know a lot more about the innards of the JPEG code.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Quantization table setup routines
+ */
+
+GLOBAL(void)
+jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
+ const unsigned int *basic_table,
+ int scale_factor, boolean force_baseline)
+/* Define a quantization table equal to the basic_table times
+ * a scale factor (given as a percentage).
+ * If force_baseline is TRUE, the computed quantization table entries
+ * are limited to 1..255 for JPEG baseline compatibility.
+ */
+{
+ JQUANT_TBL ** qtblptr;
+ int i;
+ long temp;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (which_tbl < 0 || which_tbl >= NUM_QUANT_TBLS)
+ ERREXIT1(cinfo, JERR_DQT_INDEX, which_tbl);
+
+ qtblptr = & cinfo->quant_tbl_ptrs[which_tbl];
+
+ if (*qtblptr == NULL)
+ *qtblptr = jpeg_alloc_quant_table((j_common_ptr) cinfo);
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ temp = ((long) basic_table[i] * scale_factor + 50L) / 100L;
+ /* limit the values to the valid range */
+ if (temp <= 0L) temp = 1L;
+ if (temp > 32767L) temp = 32767L; /* max quantizer needed for 12 bits */
+ if (force_baseline && temp > 255L)
+ temp = 255L; /* limit to baseline range if requested */
+ (*qtblptr)->quantval[i] = (UINT16) temp;
+ }
+
+ /* Initialize sent_table FALSE so table will be written to JPEG file. */
+ (*qtblptr)->sent_table = FALSE;
+}
+
+
+/* These are the sample quantization tables given in JPEG spec section K.1.
+ * The spec says that the values given produce "good" quality, and
+ * when divided by 2, "very good" quality.
+ */
+static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+};
+static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+
+
+GLOBAL(void)
+jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables
+ * and straight percentage-scaling quality scales.
+ * This entry point allows different scalings for luminance and chrominance.
+ */
+{
+ /* Set up two quantization tables using the specified scaling */
+ jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+ cinfo->q_scale_factor[0], force_baseline);
+ jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+ cinfo->q_scale_factor[1], force_baseline);
+}
+
+
+GLOBAL(void)
+jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
+ boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables
+ * and a straight percentage-scaling quality scale. In most cases it's better
+ * to use jpeg_set_quality (below); this entry point is provided for
+ * applications that insist on a linear percentage scaling.
+ */
+{
+ /* Set up two quantization tables using the specified scaling */
+ jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl,
+ scale_factor, force_baseline);
+ jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl,
+ scale_factor, force_baseline);
+}
+
+
+GLOBAL(int)
+jpeg_quality_scaling (int quality)
+/* Convert a user-specified quality rating to a percentage scaling factor
+ * for an underlying quantization table, using our recommended scaling curve.
+ * The input 'quality' factor should be 0 (terrible) to 100 (very good).
+ */
+{
+ /* Safety limit on quality factor. Convert 0 to 1 to avoid zero divide. */
+ if (quality <= 0) quality = 1;
+ if (quality > 100) quality = 100;
+
+ /* The basic table is used as-is (scaling 100) for a quality of 50.
+ * Qualities 50..100 are converted to scaling percentage 200 - 2*Q;
+ * note that at Q=100 the scaling is 0, which will cause jpeg_add_quant_table
+ * to make all the table entries 1 (hence, minimum quantization loss).
+ * Qualities 1..50 are converted to scaling percentage 5000/Q.
+ */
+ if (quality < 50)
+ quality = 5000 / quality;
+ else
+ quality = 200 - quality*2;
+
+ return quality;
+}
+
+
+GLOBAL(void)
+jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
+/* Set or change the 'quality' (quantization) setting, using default tables.
+ * This is the standard quality-adjusting entry point for typical user
+ * interfaces; only those who want detailed control over quantization tables
+ * would use the preceding three routines directly.
+ */
+{
+ /* Convert user 0-100 rating to percentage scaling */
+ quality = jpeg_quality_scaling(quality);
+
+ /* Set up standard quality tables */
+ jpeg_set_linear_quality(cinfo, quality, force_baseline);
+}
+
+
+/*
+ * Huffman table setup routines
+ */
+
+LOCAL(void)
+add_huff_table (j_compress_ptr cinfo,
+ JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val)
+/* Define a Huffman table */
+{
+ int nsymbols, len;
+
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+
+ /* Copy the number-of-symbols-of-each-code-length counts */
+ MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
+
+ /* Validate the counts. We do this here mainly so we can copy the right
+ * number of symbols from the val[] array, without risking marching off
+ * the end of memory. jchuff.c will do a more thorough test later.
+ */
+ nsymbols = 0;
+ for (len = 1; len <= 16; len++)
+ nsymbols += bits[len];
+ if (nsymbols < 1 || nsymbols > 256)
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+
+ MEMCOPY((*htblptr)->huffval, val, nsymbols * SIZEOF(UINT8));
+
+ /* Initialize sent_table FALSE so table will be written to JPEG file. */
+ (*htblptr)->sent_table = FALSE;
+}
+
+
+LOCAL(void)
+std_huff_tables (j_compress_ptr cinfo)
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+{
+ static const UINT8 bits_dc_luminance[17] =
+ { /* 0-base */ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_luminance[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_dc_chrominance[17] =
+ { /* 0-base */ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_chrominance[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_ac_luminance[17] =
+ { /* 0-base */ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
+ static const UINT8 val_ac_luminance[] =
+ { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa };
+
+ static const UINT8 bits_ac_chrominance[17] =
+ { /* 0-base */ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
+ static const UINT8 val_ac_chrominance[] =
+ { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa };
+
+ add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[0],
+ bits_dc_luminance, val_dc_luminance);
+ add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[0],
+ bits_ac_luminance, val_ac_luminance);
+ add_huff_table(cinfo, &cinfo->dc_huff_tbl_ptrs[1],
+ bits_dc_chrominance, val_dc_chrominance);
+ add_huff_table(cinfo, &cinfo->ac_huff_tbl_ptrs[1],
+ bits_ac_chrominance, val_ac_chrominance);
+}
+
+
+/*
+ * Default parameter setup for compression.
+ *
+ * Applications that don't choose to use this routine must do their
+ * own setup of all these parameters. Alternately, you can call this
+ * to establish defaults and then alter parameters selectively. This
+ * is the recommended approach since, if we add any new parameters,
+ * your code will still work (they'll be set to reasonable defaults).
+ */
+
+GLOBAL(void)
+jpeg_set_defaults (j_compress_ptr cinfo)
+{
+ int i;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Allocate comp_info array large enough for maximum component count.
+ * Array is made permanent in case application wants to compress
+ * multiple images at same param settings.
+ */
+ if (cinfo->comp_info == NULL)
+ cinfo->comp_info = (jpeg_component_info *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ MAX_COMPONENTS * SIZEOF(jpeg_component_info));
+
+ /* Initialize everything not dependent on the color space */
+
+ cinfo->scale_num = 1; /* 1:1 scaling */
+ cinfo->scale_denom = 1;
+ cinfo->data_precision = BITS_IN_JSAMPLE;
+ /* Set up two quantization tables using default quality of 75 */
+ jpeg_set_quality(cinfo, 75, TRUE);
+ /* Set up two Huffman tables */
+ std_huff_tables(cinfo);
+
+ /* Initialize default arithmetic coding conditioning */
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ cinfo->arith_dc_L[i] = 0;
+ cinfo->arith_dc_U[i] = 1;
+ cinfo->arith_ac_K[i] = 5;
+ }
+
+ /* Default is no multiple-scan output */
+ cinfo->scan_info = NULL;
+ cinfo->num_scans = 0;
+
+ /* Expect normal source image, not raw downsampled data */
+ cinfo->raw_data_in = FALSE;
+
+ /* Use Huffman coding, not arithmetic coding, by default */
+ cinfo->arith_code = FALSE;
+
+ /* By default, don't do extra passes to optimize entropy coding */
+ cinfo->optimize_coding = FALSE;
+ /* The standard Huffman tables are only valid for 8-bit data precision.
+ * If the precision is higher, force optimization on so that usable
+ * tables will be computed. This test can be removed if default tables
+ * are supplied that are valid for the desired precision.
+ */
+ if (cinfo->data_precision > 8)
+ cinfo->optimize_coding = TRUE;
+
+ /* By default, use the simpler non-cosited sampling alignment */
+ cinfo->CCIR601_sampling = FALSE;
+
+ /* By default, apply fancy downsampling */
+ cinfo->do_fancy_downsampling = TRUE;
+
+ /* No input smoothing */
+ cinfo->smoothing_factor = 0;
+
+ /* DCT algorithm preference */
+ cinfo->dct_method = JDCT_DEFAULT;
+
+ /* No restart markers */
+ cinfo->restart_interval = 0;
+ cinfo->restart_in_rows = 0;
+
+ /* Fill in default JFIF marker parameters. Note that whether the marker
+ * will actually be written is determined by jpeg_set_colorspace.
+ *
+ * By default, the library emits JFIF version code 1.01.
+ * An application that wants to emit JFIF 1.02 extension markers should set
+ * JFIF_minor_version to 2. We could probably get away with just defaulting
+ * to 1.02, but there may still be some decoders in use that will complain
+ * about that; saying 1.01 should minimize compatibility problems.
+ */
+ cinfo->JFIF_major_version = 1; /* Default JFIF version = 1.01 */
+ cinfo->JFIF_minor_version = 1;
+ cinfo->density_unit = 0; /* Pixel size is unknown by default */
+ cinfo->X_density = 1; /* Pixel aspect ratio is square by default */
+ cinfo->Y_density = 1;
+
+ /* Choose JPEG colorspace based on input space, set defaults accordingly */
+
+ jpeg_default_colorspace(cinfo);
+}
+
+
+/*
+ * Select an appropriate JPEG colorspace for in_color_space.
+ */
+
+GLOBAL(void)
+jpeg_default_colorspace (j_compress_ptr cinfo)
+{
+ switch (cinfo->in_color_space) {
+ case JCS_GRAYSCALE:
+ jpeg_set_colorspace(cinfo, JCS_GRAYSCALE);
+ break;
+ case JCS_RGB:
+ jpeg_set_colorspace(cinfo, JCS_YCbCr);
+ break;
+ case JCS_YCbCr:
+ jpeg_set_colorspace(cinfo, JCS_YCbCr);
+ break;
+ case JCS_CMYK:
+ jpeg_set_colorspace(cinfo, JCS_CMYK); /* By default, no translation */
+ break;
+ case JCS_YCCK:
+ jpeg_set_colorspace(cinfo, JCS_YCCK);
+ break;
+ case JCS_UNKNOWN:
+ jpeg_set_colorspace(cinfo, JCS_UNKNOWN);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BAD_IN_COLORSPACE);
+ }
+}
+
+
+/*
+ * Set the JPEG colorspace, and choose colorspace-dependent default values.
+ */
+
+GLOBAL(void)
+jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
+{
+ jpeg_component_info * compptr;
+ int ci;
+
+#define SET_COMP(index,id,hsamp,vsamp,quant,dctbl,actbl) \
+ (compptr = &cinfo->comp_info[index], \
+ compptr->component_id = (id), \
+ compptr->h_samp_factor = (hsamp), \
+ compptr->v_samp_factor = (vsamp), \
+ compptr->quant_tbl_no = (quant), \
+ compptr->dc_tbl_no = (dctbl), \
+ compptr->ac_tbl_no = (actbl) )
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* For all colorspaces, we use Q and Huff tables 0 for luminance components,
+ * tables 1 for chrominance components.
+ */
+
+ cinfo->jpeg_color_space = colorspace;
+
+ cinfo->write_JFIF_header = FALSE; /* No marker for non-JFIF colorspaces */
+ cinfo->write_Adobe_marker = FALSE; /* write no Adobe marker by default */
+
+ switch (colorspace) {
+ case JCS_GRAYSCALE:
+ cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+ cinfo->num_components = 1;
+ /* JFIF specifies component ID 1 */
+ SET_COMP(0, 1, 1,1, 0, 0,0);
+ break;
+ case JCS_RGB:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag RGB */
+ cinfo->num_components = 3;
+ SET_COMP(0, 0x52 /* 'R' */, 1,1, 0, 0,0);
+ SET_COMP(1, 0x47 /* 'G' */, 1,1, 0, 0,0);
+ SET_COMP(2, 0x42 /* 'B' */, 1,1, 0, 0,0);
+ break;
+ case JCS_YCbCr:
+ cinfo->write_JFIF_header = TRUE; /* Write a JFIF marker */
+ cinfo->num_components = 3;
+ /* JFIF specifies component IDs 1,2,3 */
+ /* We default to 2x2 subsamples of chrominance */
+ SET_COMP(0, 1, 2,2, 0, 0,0);
+ SET_COMP(1, 2, 1,1, 1, 1,1);
+ SET_COMP(2, 3, 1,1, 1, 1,1);
+ break;
+ case JCS_CMYK:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag CMYK */
+ cinfo->num_components = 4;
+ SET_COMP(0, 0x43 /* 'C' */, 1,1, 0, 0,0);
+ SET_COMP(1, 0x4D /* 'M' */, 1,1, 0, 0,0);
+ SET_COMP(2, 0x59 /* 'Y' */, 1,1, 0, 0,0);
+ SET_COMP(3, 0x4B /* 'K' */, 1,1, 0, 0,0);
+ break;
+ case JCS_YCCK:
+ cinfo->write_Adobe_marker = TRUE; /* write Adobe marker to flag YCCK */
+ cinfo->num_components = 4;
+ SET_COMP(0, 1, 2,2, 0, 0,0);
+ SET_COMP(1, 2, 1,1, 1, 1,1);
+ SET_COMP(2, 3, 1,1, 1, 1,1);
+ SET_COMP(3, 4, 2,2, 0, 0,0);
+ break;
+ case JCS_UNKNOWN:
+ cinfo->num_components = cinfo->input_components;
+ if (cinfo->num_components < 1 || cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ SET_COMP(ci, ci, 1,1, 0, 0,0);
+ }
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ }
+}
+
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+
+LOCAL(jpeg_scan_info *)
+fill_a_scan (jpeg_scan_info * scanptr, int ci,
+ int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for specified component */
+{
+ scanptr->comps_in_scan = 1;
+ scanptr->component_index[0] = ci;
+ scanptr->Ss = Ss;
+ scanptr->Se = Se;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ return scanptr;
+}
+
+LOCAL(jpeg_scan_info *)
+fill_scans (jpeg_scan_info * scanptr, int ncomps,
+ int Ss, int Se, int Ah, int Al)
+/* Support routine: generate one scan for each component */
+{
+ int ci;
+
+ for (ci = 0; ci < ncomps; ci++) {
+ scanptr->comps_in_scan = 1;
+ scanptr->component_index[0] = ci;
+ scanptr->Ss = Ss;
+ scanptr->Se = Se;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ }
+ return scanptr;
+}
+
+LOCAL(jpeg_scan_info *)
+fill_dc_scans (jpeg_scan_info * scanptr, int ncomps, int Ah, int Al)
+/* Support routine: generate interleaved DC scan if possible, else N scans */
+{
+ int ci;
+
+ if (ncomps <= MAX_COMPS_IN_SCAN) {
+ /* Single interleaved DC scan */
+ scanptr->comps_in_scan = ncomps;
+ for (ci = 0; ci < ncomps; ci++)
+ scanptr->component_index[ci] = ci;
+ scanptr->Ss = scanptr->Se = 0;
+ scanptr->Ah = Ah;
+ scanptr->Al = Al;
+ scanptr++;
+ } else {
+ /* Noninterleaved DC scan for each component */
+ scanptr = fill_scans(scanptr, ncomps, 0, 0, Ah, Al);
+ }
+ return scanptr;
+}
+
+
+/*
+ * Create a recommended progressive-JPEG script.
+ * cinfo->num_components and cinfo->jpeg_color_space must be correct.
+ */
+
+GLOBAL(void)
+jpeg_simple_progression (j_compress_ptr cinfo)
+{
+ int ncomps = cinfo->num_components;
+ int nscans;
+ jpeg_scan_info * scanptr;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Figure space needed for script. Calculation must match code below! */
+ if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
+ /* Custom script for YCbCr color images. */
+ nscans = 10;
+ } else {
+ /* All-purpose script for other color spaces. */
+ if (ncomps > MAX_COMPS_IN_SCAN)
+ nscans = 6 * ncomps; /* 2 DC + 4 AC scans per component */
+ else
+ nscans = 2 + 4 * ncomps; /* 2 DC scans; 4 AC scans per component */
+ }
+
+ /* Allocate space for script.
+ * We need to put it in the permanent pool in case the application performs
+ * multiple compressions without changing the settings. To avoid a memory
+ * leak if jpeg_simple_progression is called repeatedly for the same JPEG
+ * object, we try to re-use previously allocated space, and we allocate
+ * enough space to handle YCbCr even if initially asked for grayscale.
+ */
+ if (cinfo->script_space == NULL || cinfo->script_space_size < nscans) {
+ cinfo->script_space_size = MAX(nscans, 10);
+ cinfo->script_space = (jpeg_scan_info *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ cinfo->script_space_size * SIZEOF(jpeg_scan_info));
+ }
+ scanptr = cinfo->script_space;
+ cinfo->scan_info = scanptr;
+ cinfo->num_scans = nscans;
+
+ if (ncomps == 3 && cinfo->jpeg_color_space == JCS_YCbCr) {
+ /* Custom script for YCbCr color images. */
+ /* Initial DC scan */
+ scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+ /* Initial AC scan: get some luma data out in a hurry */
+ scanptr = fill_a_scan(scanptr, 0, 1, 5, 0, 2);
+ /* Chroma data is too small to be worth expending many scans on */
+ scanptr = fill_a_scan(scanptr, 2, 1, 63, 0, 1);
+ scanptr = fill_a_scan(scanptr, 1, 1, 63, 0, 1);
+ /* Complete spectral selection for luma AC */
+ scanptr = fill_a_scan(scanptr, 0, 6, 63, 0, 2);
+ /* Refine next bit of luma AC */
+ scanptr = fill_a_scan(scanptr, 0, 1, 63, 2, 1);
+ /* Finish DC successive approximation */
+ scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+ /* Finish AC successive approximation */
+ scanptr = fill_a_scan(scanptr, 2, 1, 63, 1, 0);
+ scanptr = fill_a_scan(scanptr, 1, 1, 63, 1, 0);
+ /* Luma bottom bit comes last since it's usually largest scan */
+ scanptr = fill_a_scan(scanptr, 0, 1, 63, 1, 0);
+ } else {
+ /* All-purpose script for other color spaces. */
+ /* Successive approximation first pass */
+ scanptr = fill_dc_scans(scanptr, ncomps, 0, 1);
+ scanptr = fill_scans(scanptr, ncomps, 1, 5, 0, 2);
+ scanptr = fill_scans(scanptr, ncomps, 6, 63, 0, 2);
+ /* Successive approximation second pass */
+ scanptr = fill_scans(scanptr, ncomps, 1, 63, 2, 1);
+ /* Successive approximation final pass */
+ scanptr = fill_dc_scans(scanptr, ncomps, 1, 0);
+ scanptr = fill_scans(scanptr, ncomps, 1, 63, 1, 0);
+ }
+}
+
+#endif /* C_PROGRESSIVE_SUPPORTED */
diff --git a/jpg/jcprepct.c b/jpg/jcprepct.c
new file mode 100644
index 0000000..be44cc4
--- /dev/null
+++ b/jpg/jcprepct.c
@@ -0,0 +1,358 @@
+/*
+ * jcprepct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the compression preprocessing controller.
+ * This controller manages the color conversion, downsampling,
+ * and edge expansion steps.
+ *
+ * Most of the complexity here is associated with buffering input rows
+ * as required by the downsampler. See the comments at the head of
+ * jcsample.c for the downsampler's needs.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* At present, jcsample.c can request context rows only for smoothing.
+ * In the future, we might also need context rows for CCIR601 sampling
+ * or other more-complex downsampling procedures. The code to support
+ * context rows should be compiled only if needed.
+ */
+#ifdef INPUT_SMOOTHING_SUPPORTED
+#define CONTEXT_ROWS_SUPPORTED
+#endif
+
+
+/*
+ * For the simple (no-context-row) case, we just need to buffer one
+ * row group's worth of pixels for the downsampling step. At the bottom of
+ * the image, we pad to a full row group by replicating the last pixel row.
+ * The downsampler's last output row is then replicated if needed to pad
+ * out to a full iMCU row.
+ *
+ * When providing context rows, we must buffer three row groups' worth of
+ * pixels. Three row groups are physically allocated, but the row pointer
+ * arrays are made five row groups high, with the extra pointers above and
+ * below "wrapping around" to point to the last and first real row groups.
+ * This allows the downsampler to access the proper context rows.
+ * At the top and bottom of the image, we create dummy context rows by
+ * copying the first or last real pixel row. This copying could be avoided
+ * by pointer hacking as is done in jdmainct.c, but it doesn't seem worth the
+ * trouble on the compression side.
+ */
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_prep_controller pub; /* public fields */
+
+ /* Downsampling input buffer. This buffer holds color-converted data
+ * until we have enough to do a downsample step.
+ */
+ JSAMPARRAY color_buf[MAX_COMPONENTS];
+
+ JDIMENSION rows_to_go; /* counts rows remaining in source image */
+ int next_buf_row; /* index of next row to store in color_buf */
+
+#ifdef CONTEXT_ROWS_SUPPORTED /* only needed for context case */
+ int this_row_group; /* starting row index of group to process */
+ int next_buf_stop; /* downsample when we reach this index */
+#endif
+} my_prep_controller;
+
+typedef my_prep_controller * my_prep_ptr;
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_prep (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+
+ if (pass_mode != JBUF_PASS_THRU)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ /* Initialize total-height counter for detecting bottom of image */
+ prep->rows_to_go = cinfo->image_height;
+ /* Mark the conversion buffer empty */
+ prep->next_buf_row = 0;
+#ifdef CONTEXT_ROWS_SUPPORTED
+ /* Preset additional state variables for context mode.
+ * These aren't used in non-context mode, so we needn't test which mode.
+ */
+ prep->this_row_group = 0;
+ /* Set next_buf_stop to stop after two row groups have been read in. */
+ prep->next_buf_stop = 2 * cinfo->max_v_samp_factor;
+#endif
+}
+
+
+/*
+ * Expand an image vertically from height input_rows to height output_rows,
+ * by duplicating the bottom row.
+ */
+
+LOCAL(void)
+expand_bottom_edge (JSAMPARRAY image_data, JDIMENSION num_cols,
+ int input_rows, int output_rows)
+{
+ register int row;
+
+ for (row = input_rows; row < output_rows; row++) {
+ jcopy_sample_rows(image_data, input_rows-1, image_data, row,
+ 1, num_cols);
+ }
+}
+
+
+/*
+ * Process some data in the simple no-context case.
+ *
+ * Preprocessor output data is counted in "row groups". A row group
+ * is defined to be v_samp_factor sample rows of each component.
+ * Downsampling will produce this much data from each max_v_samp_factor
+ * input rows.
+ */
+
+METHODDEF(void)
+pre_process_data (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int numrows, ci;
+ JDIMENSION inrows;
+ jpeg_component_info * compptr;
+
+ while (*in_row_ctr < in_rows_avail &&
+ *out_row_group_ctr < out_row_groups_avail) {
+ /* Do color conversion to fill the conversion buffer. */
+ inrows = in_rows_avail - *in_row_ctr;
+ numrows = cinfo->max_v_samp_factor - prep->next_buf_row;
+ numrows = (int) MIN((JDIMENSION) numrows, inrows);
+ (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION) prep->next_buf_row,
+ numrows);
+ *in_row_ctr += numrows;
+ prep->next_buf_row += numrows;
+ prep->rows_to_go -= numrows;
+ /* If at bottom of image, pad to fill the conversion buffer. */
+ if (prep->rows_to_go == 0 &&
+ prep->next_buf_row < cinfo->max_v_samp_factor) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
+ prep->next_buf_row, cinfo->max_v_samp_factor);
+ }
+ prep->next_buf_row = cinfo->max_v_samp_factor;
+ }
+ /* If we've filled the conversion buffer, empty it. */
+ if (prep->next_buf_row == cinfo->max_v_samp_factor) {
+ (*cinfo->downsample->downsample) (cinfo,
+ prep->color_buf, (JDIMENSION) 0,
+ output_buf, *out_row_group_ctr);
+ prep->next_buf_row = 0;
+ (*out_row_group_ctr)++;
+ }
+ /* If at bottom of image, pad the output to a full iMCU height.
+ * Note we assume the caller is providing a one-iMCU-height output buffer!
+ */
+ if (prep->rows_to_go == 0 &&
+ *out_row_group_ctr < out_row_groups_avail) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ numrows = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size;
+ expand_bottom_edge(output_buf[ci],
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (int) (*out_row_group_ctr * numrows),
+ (int) (out_row_groups_avail * numrows));
+ }
+ *out_row_group_ctr = out_row_groups_avail;
+ break; /* can exit outer loop without test */
+ }
+ }
+}
+
+
+#ifdef CONTEXT_ROWS_SUPPORTED
+
+/*
+ * Process some data in the context case.
+ */
+
+METHODDEF(void)
+pre_process_context (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int numrows, ci;
+ int buf_height = cinfo->max_v_samp_factor * 3;
+ JDIMENSION inrows;
+
+ while (*out_row_group_ctr < out_row_groups_avail) {
+ if (*in_row_ctr < in_rows_avail) {
+ /* Do color conversion to fill the conversion buffer. */
+ inrows = in_rows_avail - *in_row_ctr;
+ numrows = prep->next_buf_stop - prep->next_buf_row;
+ numrows = (int) MIN((JDIMENSION) numrows, inrows);
+ (*cinfo->cconvert->color_convert) (cinfo, input_buf + *in_row_ctr,
+ prep->color_buf,
+ (JDIMENSION) prep->next_buf_row,
+ numrows);
+ /* Pad at top of image, if first time through */
+ if (prep->rows_to_go == cinfo->image_height) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ int row;
+ for (row = 1; row <= cinfo->max_v_samp_factor; row++) {
+ jcopy_sample_rows(prep->color_buf[ci], 0,
+ prep->color_buf[ci], -row,
+ 1, cinfo->image_width);
+ }
+ }
+ }
+ *in_row_ctr += numrows;
+ prep->next_buf_row += numrows;
+ prep->rows_to_go -= numrows;
+ } else {
+ /* Return for more data, unless we are at the bottom of the image. */
+ if (prep->rows_to_go != 0)
+ break;
+ /* When at bottom of image, pad to fill the conversion buffer. */
+ if (prep->next_buf_row < prep->next_buf_stop) {
+ for (ci = 0; ci < cinfo->num_components; ci++) {
+ expand_bottom_edge(prep->color_buf[ci], cinfo->image_width,
+ prep->next_buf_row, prep->next_buf_stop);
+ }
+ prep->next_buf_row = prep->next_buf_stop;
+ }
+ }
+ /* If we've gotten enough data, downsample a row group. */
+ if (prep->next_buf_row == prep->next_buf_stop) {
+ (*cinfo->downsample->downsample) (cinfo,
+ prep->color_buf,
+ (JDIMENSION) prep->this_row_group,
+ output_buf, *out_row_group_ctr);
+ (*out_row_group_ctr)++;
+ /* Advance pointers with wraparound as necessary. */
+ prep->this_row_group += cinfo->max_v_samp_factor;
+ if (prep->this_row_group >= buf_height)
+ prep->this_row_group = 0;
+ if (prep->next_buf_row >= buf_height)
+ prep->next_buf_row = 0;
+ prep->next_buf_stop = prep->next_buf_row + cinfo->max_v_samp_factor;
+ }
+ }
+}
+
+
+/*
+ * Create the wrapped-around downsampling input buffer needed for context mode.
+ */
+
+LOCAL(void)
+create_context_buffer (j_compress_ptr cinfo)
+{
+ my_prep_ptr prep = (my_prep_ptr) cinfo->prep;
+ int rgroup_height = cinfo->max_v_samp_factor;
+ int ci, i;
+ jpeg_component_info * compptr;
+ JSAMPARRAY true_buffer, fake_buffer;
+
+ /* Grab enough space for fake row pointers for all the components;
+ * we need five row groups' worth of pointers for each component.
+ */
+ fake_buffer = (JSAMPARRAY)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (cinfo->num_components * 5 * rgroup_height) *
+ SIZEOF(JSAMPROW));
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Allocate the actual buffer space (3 row groups) for this component.
+ * We make the buffer wide enough to allow the downsampler to edge-expand
+ * horizontally within the buffer, if it so chooses.
+ */
+ true_buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (((long) compptr->width_in_blocks *
+ cinfo->min_DCT_h_scaled_size *
+ cinfo->max_h_samp_factor) / compptr->h_samp_factor),
+ (JDIMENSION) (3 * rgroup_height));
+ /* Copy true buffer row pointers into the middle of the fake row array */
+ MEMCOPY(fake_buffer + rgroup_height, true_buffer,
+ 3 * rgroup_height * SIZEOF(JSAMPROW));
+ /* Fill in the above and below wraparound pointers */
+ for (i = 0; i < rgroup_height; i++) {
+ fake_buffer[i] = true_buffer[2 * rgroup_height + i];
+ fake_buffer[4 * rgroup_height + i] = true_buffer[i];
+ }
+ prep->color_buf[ci] = fake_buffer + rgroup_height;
+ fake_buffer += 5 * rgroup_height; /* point to space for next component */
+ }
+}
+
+#endif /* CONTEXT_ROWS_SUPPORTED */
+
+
+/*
+ * Initialize preprocessing controller.
+ */
+
+GLOBAL(void)
+jinit_c_prep_controller (j_compress_ptr cinfo, boolean need_full_buffer)
+{
+ my_prep_ptr prep;
+ int ci;
+ jpeg_component_info * compptr;
+
+ if (need_full_buffer) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ prep = (my_prep_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_prep_controller));
+ cinfo->prep = (struct jpeg_c_prep_controller *) prep;
+ prep->pub.start_pass = start_pass_prep;
+
+ /* Allocate the color conversion buffer.
+ * We make the buffer wide enough to allow the downsampler to edge-expand
+ * horizontally within the buffer, if it so chooses.
+ */
+ if (cinfo->downsample->need_context_rows) {
+ /* Set up to provide context rows */
+#ifdef CONTEXT_ROWS_SUPPORTED
+ prep->pub.pre_process_data = pre_process_context;
+ create_context_buffer(cinfo);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ /* No context, just make it tall enough for one row group */
+ prep->pub.pre_process_data = pre_process_data;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ prep->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (((long) compptr->width_in_blocks *
+ cinfo->min_DCT_h_scaled_size *
+ cinfo->max_h_samp_factor) / compptr->h_samp_factor),
+ (JDIMENSION) cinfo->max_v_samp_factor);
+ }
+ }
+}
diff --git a/jpg/jcsample.c b/jpg/jcsample.c
new file mode 100644
index 0000000..4d36f85
--- /dev/null
+++ b/jpg/jcsample.c
@@ -0,0 +1,545 @@
+/*
+ * jcsample.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains downsampling routines.
+ *
+ * Downsampling input data is counted in "row groups". A row group
+ * is defined to be max_v_samp_factor pixel rows of each component,
+ * from which the downsampler produces v_samp_factor sample rows.
+ * A single row group is processed in each call to the downsampler module.
+ *
+ * The downsampler is responsible for edge-expansion of its output data
+ * to fill an integral number of DCT blocks horizontally. The source buffer
+ * may be modified if it is helpful for this purpose (the source buffer is
+ * allocated wide enough to correspond to the desired output width).
+ * The caller (the prep controller) is responsible for vertical padding.
+ *
+ * The downsampler may request "context rows" by setting need_context_rows
+ * during startup. In this case, the input arrays will contain at least
+ * one row group's worth of pixels above and below the passed-in data;
+ * the caller will create dummy rows at image top and bottom by replicating
+ * the first or last real pixel row.
+ *
+ * An excellent reference for image resampling is
+ * Digital Image Warping, George Wolberg, 1990.
+ * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+ *
+ * The downsampling algorithm used here is a simple average of the source
+ * pixels covered by the output pixel. The hi-falutin sampling literature
+ * refers to this as a "box filter". In general the characteristics of a box
+ * filter are not very good, but for the specific cases we normally use (1:1
+ * and 2:1 ratios) the box is equivalent to a "triangle filter" which is not
+ * nearly so bad. If you intend to use other sampling ratios, you'd be well
+ * advised to improve this code.
+ *
+ * A simple input-smoothing capability is provided. This is mainly intended
+ * for cleaning up color-dithered GIF input files (if you find it inadequate,
+ * we suggest using an external filtering program such as pnmconvol). When
+ * enabled, each input pixel P is replaced by a weighted sum of itself and its
+ * eight neighbors. P's weight is 1-8*SF and each neighbor's weight is SF,
+ * where SF = (smoothing_factor / 1024).
+ * Currently, smoothing is only supported for 2h2v sampling factors.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Pointer to routine to downsample a single component */
+typedef JMETHOD(void, downsample1_ptr,
+ (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data));
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_downsampler pub; /* public fields */
+
+ /* Downsampling method pointers, one per component */
+ downsample1_ptr methods[MAX_COMPONENTS];
+
+ /* Height of an output row group for each component. */
+ int rowgroup_height[MAX_COMPONENTS];
+
+ /* These arrays save pixel expansion factors so that int_downsample need not
+ * recompute them each time. They are unused for other downsampling methods.
+ */
+ UINT8 h_expand[MAX_COMPONENTS];
+ UINT8 v_expand[MAX_COMPONENTS];
+} my_downsampler;
+
+typedef my_downsampler * my_downsample_ptr;
+
+
+/*
+ * Initialize for a downsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_downsample (j_compress_ptr cinfo)
+{
+ /* no work for now */
+}
+
+
+/*
+ * Expand a component horizontally from width input_cols to width output_cols,
+ * by duplicating the rightmost samples.
+ */
+
+LOCAL(void)
+expand_right_edge (JSAMPARRAY image_data, int num_rows,
+ JDIMENSION input_cols, JDIMENSION output_cols)
+{
+ register JSAMPROW ptr;
+ register JSAMPLE pixval;
+ register int count;
+ int row;
+ int numcols = (int) (output_cols - input_cols);
+
+ if (numcols > 0) {
+ for (row = 0; row < num_rows; row++) {
+ ptr = image_data[row] + input_cols;
+ pixval = ptr[-1]; /* don't need GETJSAMPLE() here */
+ for (count = numcols; count > 0; count--)
+ *ptr++ = pixval;
+ }
+ }
+}
+
+
+/*
+ * Do downsampling for a whole row group (all components).
+ *
+ * In this version we simply downsample each component independently.
+ */
+
+METHODDEF(void)
+sep_downsample (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_index,
+ JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)
+{
+ my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
+ int ci;
+ jpeg_component_info * compptr;
+ JSAMPARRAY in_ptr, out_ptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ in_ptr = input_buf[ci] + in_row_index;
+ out_ptr = output_buf[ci] +
+ (out_row_group_index * downsample->rowgroup_height[ci]);
+ (*downsample->methods[ci]) (cinfo, compptr, in_ptr, out_ptr);
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * One row group is processed per call.
+ * This version handles arbitrary integral sampling ratios, without smoothing.
+ * Note that this version is not actually used for customary sampling ratios.
+ */
+
+METHODDEF(void)
+int_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ my_downsample_ptr downsample = (my_downsample_ptr) cinfo->downsample;
+ int inrow, outrow, h_expand, v_expand, numpix, numpix2, h, v;
+ JDIMENSION outcol, outcol_h; /* outcol_h == outcol*h_expand */
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ JSAMPROW inptr, outptr;
+ INT32 outvalue;
+
+ h_expand = downsample->h_expand[compptr->component_index];
+ v_expand = downsample->v_expand[compptr->component_index];
+ numpix = h_expand * v_expand;
+ numpix2 = numpix/2;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * h_expand);
+
+ inrow = outrow = 0;
+ while (inrow < cinfo->max_v_samp_factor) {
+ outptr = output_data[outrow];
+ for (outcol = 0, outcol_h = 0; outcol < output_cols;
+ outcol++, outcol_h += h_expand) {
+ outvalue = 0;
+ for (v = 0; v < v_expand; v++) {
+ inptr = input_data[inrow+v] + outcol_h;
+ for (h = 0; h < h_expand; h++) {
+ outvalue += (INT32) GETJSAMPLE(*inptr++);
+ }
+ }
+ *outptr++ = (JSAMPLE) ((outvalue + numpix2) / numpix);
+ }
+ inrow += v_expand;
+ outrow++;
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the special case of a full-size component,
+ * without smoothing.
+ */
+
+METHODDEF(void)
+fullsize_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ /* Copy the data */
+ jcopy_sample_rows(input_data, 0, output_data, 0,
+ cinfo->max_v_samp_factor, cinfo->image_width);
+ /* Edge-expand */
+ expand_right_edge(output_data, cinfo->max_v_samp_factor, cinfo->image_width,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size);
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the common case of 2:1 horizontal and 1:1 vertical,
+ * without smoothing.
+ *
+ * A note about the "bias" calculations: when rounding fractional values to
+ * integer, we do not want to always round 0.5 up to the next integer.
+ * If we did that, we'd introduce a noticeable bias towards larger values.
+ * Instead, this code is arranged so that 0.5 will be rounded up or down at
+ * alternate pixel locations (a simple ordered dither pattern).
+ */
+
+METHODDEF(void)
+h2v1_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow;
+ JDIMENSION outcol;
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ register JSAMPROW inptr, outptr;
+ register int bias;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * 2);
+
+ for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
+ outptr = output_data[inrow];
+ inptr = input_data[inrow];
+ bias = 0; /* bias = 0,1,0,1,... for successive samples */
+ for (outcol = 0; outcol < output_cols; outcol++) {
+ *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr) + GETJSAMPLE(inptr[1])
+ + bias) >> 1);
+ bias ^= 1; /* 0=>1, 1=>0 */
+ inptr += 2;
+ }
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+ * without smoothing.
+ */
+
+METHODDEF(void)
+h2v2_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow, outrow;
+ JDIMENSION outcol;
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ register JSAMPROW inptr0, inptr1, outptr;
+ register int bias;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data, cinfo->max_v_samp_factor,
+ cinfo->image_width, output_cols * 2);
+
+ inrow = outrow = 0;
+ while (inrow < cinfo->max_v_samp_factor) {
+ outptr = output_data[outrow];
+ inptr0 = input_data[inrow];
+ inptr1 = input_data[inrow+1];
+ bias = 1; /* bias = 1,2,1,2,... for successive samples */
+ for (outcol = 0; outcol < output_cols; outcol++) {
+ *outptr++ = (JSAMPLE) ((GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1])
+ + bias) >> 2);
+ bias ^= 3; /* 1=>2, 2=>1 */
+ inptr0 += 2; inptr1 += 2;
+ }
+ inrow += 2;
+ outrow++;
+ }
+}
+
+
+#ifdef INPUT_SMOOTHING_SUPPORTED
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the standard case of 2:1 horizontal and 2:1 vertical,
+ * with smoothing. One row of context is required.
+ */
+
+METHODDEF(void)
+h2v2_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow, outrow;
+ JDIMENSION colctr;
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ register JSAMPROW inptr0, inptr1, above_ptr, below_ptr, outptr;
+ INT32 membersum, neighsum, memberscale, neighscale;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
+ cinfo->image_width, output_cols * 2);
+
+ /* We don't bother to form the individual "smoothed" input pixel values;
+ * we can directly compute the output which is the average of the four
+ * smoothed values. Each of the four member pixels contributes a fraction
+ * (1-8*SF) to its own smoothed image and a fraction SF to each of the three
+ * other smoothed pixels, therefore a total fraction (1-5*SF)/4 to the final
+ * output. The four corner-adjacent neighbor pixels contribute a fraction
+ * SF to just one smoothed pixel, or SF/4 to the final output; while the
+ * eight edge-adjacent neighbors contribute SF to each of two smoothed
+ * pixels, or SF/2 overall. In order to use integer arithmetic, these
+ * factors are scaled by 2^16 = 65536.
+ * Also recall that SF = smoothing_factor / 1024.
+ */
+
+ memberscale = 16384 - cinfo->smoothing_factor * 80; /* scaled (1-5*SF)/4 */
+ neighscale = cinfo->smoothing_factor * 16; /* scaled SF/4 */
+
+ inrow = outrow = 0;
+ while (inrow < cinfo->max_v_samp_factor) {
+ outptr = output_data[outrow];
+ inptr0 = input_data[inrow];
+ inptr1 = input_data[inrow+1];
+ above_ptr = input_data[inrow-1];
+ below_ptr = input_data[inrow+2];
+
+ /* Special case for first column: pretend column -1 is same as column 0 */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[2]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[2]);
+ neighsum += neighsum;
+ neighsum += GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[2]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[2]);
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
+
+ for (colctr = output_cols - 2; colctr > 0; colctr--) {
+ /* sum of pixels directly mapped to this output element */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ /* sum of edge-neighbor pixels */
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[2]) +
+ GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[2]);
+ /* The edge-neighbors count twice as much as corner-neighbors */
+ neighsum += neighsum;
+ /* Add in the corner-neighbors */
+ neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[2]) +
+ GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[2]);
+ /* form final output scaled up by 2^16 */
+ membersum = membersum * memberscale + neighsum * neighscale;
+ /* round, descale and output it */
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ inptr0 += 2; inptr1 += 2; above_ptr += 2; below_ptr += 2;
+ }
+
+ /* Special case for last column */
+ membersum = GETJSAMPLE(*inptr0) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(*inptr1) + GETJSAMPLE(inptr1[1]);
+ neighsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(*below_ptr) + GETJSAMPLE(below_ptr[1]) +
+ GETJSAMPLE(inptr0[-1]) + GETJSAMPLE(inptr0[1]) +
+ GETJSAMPLE(inptr1[-1]) + GETJSAMPLE(inptr1[1]);
+ neighsum += neighsum;
+ neighsum += GETJSAMPLE(above_ptr[-1]) + GETJSAMPLE(above_ptr[1]) +
+ GETJSAMPLE(below_ptr[-1]) + GETJSAMPLE(below_ptr[1]);
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
+
+ inrow += 2;
+ outrow++;
+ }
+}
+
+
+/*
+ * Downsample pixel values of a single component.
+ * This version handles the special case of a full-size component,
+ * with smoothing. One row of context is required.
+ */
+
+METHODDEF(void)
+fullsize_smooth_downsample (j_compress_ptr cinfo, jpeg_component_info *compptr,
+ JSAMPARRAY input_data, JSAMPARRAY output_data)
+{
+ int inrow;
+ JDIMENSION colctr;
+ JDIMENSION output_cols = compptr->width_in_blocks * compptr->DCT_h_scaled_size;
+ register JSAMPROW inptr, above_ptr, below_ptr, outptr;
+ INT32 membersum, neighsum, memberscale, neighscale;
+ int colsum, lastcolsum, nextcolsum;
+
+ /* Expand input data enough to let all the output samples be generated
+ * by the standard loop. Special-casing padded output would be more
+ * efficient.
+ */
+ expand_right_edge(input_data - 1, cinfo->max_v_samp_factor + 2,
+ cinfo->image_width, output_cols);
+
+ /* Each of the eight neighbor pixels contributes a fraction SF to the
+ * smoothed pixel, while the main pixel contributes (1-8*SF). In order
+ * to use integer arithmetic, these factors are multiplied by 2^16 = 65536.
+ * Also recall that SF = smoothing_factor / 1024.
+ */
+
+ memberscale = 65536L - cinfo->smoothing_factor * 512L; /* scaled 1-8*SF */
+ neighscale = cinfo->smoothing_factor * 64; /* scaled SF */
+
+ for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) {
+ outptr = output_data[inrow];
+ inptr = input_data[inrow];
+ above_ptr = input_data[inrow-1];
+ below_ptr = input_data[inrow+1];
+
+ /* Special case for first column */
+ colsum = GETJSAMPLE(*above_ptr++) + GETJSAMPLE(*below_ptr++) +
+ GETJSAMPLE(*inptr);
+ membersum = GETJSAMPLE(*inptr++);
+ nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
+ GETJSAMPLE(*inptr);
+ neighsum = colsum + (colsum - membersum) + nextcolsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ lastcolsum = colsum; colsum = nextcolsum;
+
+ for (colctr = output_cols - 2; colctr > 0; colctr--) {
+ membersum = GETJSAMPLE(*inptr++);
+ above_ptr++; below_ptr++;
+ nextcolsum = GETJSAMPLE(*above_ptr) + GETJSAMPLE(*below_ptr) +
+ GETJSAMPLE(*inptr);
+ neighsum = lastcolsum + (colsum - membersum) + nextcolsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr++ = (JSAMPLE) ((membersum + 32768) >> 16);
+ lastcolsum = colsum; colsum = nextcolsum;
+ }
+
+ /* Special case for last column */
+ membersum = GETJSAMPLE(*inptr);
+ neighsum = lastcolsum + (colsum - membersum) + colsum;
+ membersum = membersum * memberscale + neighsum * neighscale;
+ *outptr = (JSAMPLE) ((membersum + 32768) >> 16);
+
+ }
+}
+
+#endif /* INPUT_SMOOTHING_SUPPORTED */
+
+
+/*
+ * Module initialization routine for downsampling.
+ * Note that we must select a routine for each component.
+ */
+
+GLOBAL(void)
+jinit_downsampler (j_compress_ptr cinfo)
+{
+ my_downsample_ptr downsample;
+ int ci;
+ jpeg_component_info * compptr;
+ boolean smoothok = TRUE;
+ int h_in_group, v_in_group, h_out_group, v_out_group;
+
+ downsample = (my_downsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_downsampler));
+ cinfo->downsample = (struct jpeg_downsampler *) downsample;
+ downsample->pub.start_pass = start_pass_downsample;
+ downsample->pub.downsample = sep_downsample;
+ downsample->pub.need_context_rows = FALSE;
+
+ if (cinfo->CCIR601_sampling)
+ ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+ /* Verify we can handle the sampling factors, and set up method pointers */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Compute size of an "output group" for DCT scaling. This many samples
+ * are to be converted from max_h_samp_factor * max_v_samp_factor pixels.
+ */
+ h_out_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /
+ cinfo->min_DCT_h_scaled_size;
+ v_out_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size;
+ h_in_group = cinfo->max_h_samp_factor;
+ v_in_group = cinfo->max_v_samp_factor;
+ downsample->rowgroup_height[ci] = v_out_group; /* save for use later */
+ if (h_in_group == h_out_group && v_in_group == v_out_group) {
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor) {
+ downsample->methods[ci] = fullsize_smooth_downsample;
+ downsample->pub.need_context_rows = TRUE;
+ } else
+#endif
+ downsample->methods[ci] = fullsize_downsample;
+ } else if (h_in_group == h_out_group * 2 &&
+ v_in_group == v_out_group) {
+ smoothok = FALSE;
+ downsample->methods[ci] = h2v1_downsample;
+ } else if (h_in_group == h_out_group * 2 &&
+ v_in_group == v_out_group * 2) {
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor) {
+ downsample->methods[ci] = h2v2_smooth_downsample;
+ downsample->pub.need_context_rows = TRUE;
+ } else
+#endif
+ downsample->methods[ci] = h2v2_downsample;
+ } else if ((h_in_group % h_out_group) == 0 &&
+ (v_in_group % v_out_group) == 0) {
+ smoothok = FALSE;
+ downsample->methods[ci] = int_downsample;
+ downsample->h_expand[ci] = (UINT8) (h_in_group / h_out_group);
+ downsample->v_expand[ci] = (UINT8) (v_in_group / v_out_group);
+ } else
+ ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+ }
+
+#ifdef INPUT_SMOOTHING_SUPPORTED
+ if (cinfo->smoothing_factor && !smoothok)
+ TRACEMS(cinfo, 0, JTRC_SMOOTH_NOTIMPL);
+#endif
+}
diff --git a/jpg/jctrans.c b/jpg/jctrans.c
new file mode 100644
index 0000000..f7d7b81
--- /dev/null
+++ b/jpg/jctrans.c
@@ -0,0 +1,382 @@
+/*
+ * jctrans.c
+ *
+ * Copyright (C) 1995-1998, Thomas G. Lane.
+ * Modified 2000-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains library routines for transcoding compression,
+ * that is, writing raw DCT coefficient arrays to an output JPEG file.
+ * The routines in jcapimin.c will also be needed by a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(void) transencode_master_selection
+ JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
+LOCAL(void) transencode_coef_controller
+ JPP((j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays));
+
+
+/*
+ * Compression initialization for writing raw-coefficient data.
+ * Before calling this, all parameters and a data destination must be set up.
+ * Call jpeg_finish_compress() to actually write the data.
+ *
+ * The number of passed virtual arrays must match cinfo->num_components.
+ * Note that the virtual arrays need not be filled or even realized at
+ * the time write_coefficients is called; indeed, if the virtual arrays
+ * were requested from this compression object's memory manager, they
+ * typically will be realized during this routine and filled afterwards.
+ */
+
+GLOBAL(void)
+jpeg_write_coefficients (j_compress_ptr cinfo, jvirt_barray_ptr * coef_arrays)
+{
+ if (cinfo->global_state != CSTATE_START)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Mark all tables to be written */
+ jpeg_suppress_tables(cinfo, FALSE);
+ /* (Re)initialize error mgr and destination modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->dest->init_destination) (cinfo);
+ /* Perform master selection of active modules */
+ transencode_master_selection(cinfo, coef_arrays);
+ /* Wait for jpeg_finish_compress() call */
+ cinfo->next_scanline = 0; /* so jpeg_write_marker works */
+ cinfo->global_state = CSTATE_WRCOEFS;
+}
+
+
+/*
+ * Initialize the compression object with default parameters,
+ * then copy from the source object all parameters needed for lossless
+ * transcoding. Parameters that can be varied without loss (such as
+ * scan script and Huffman optimization) are left in their default states.
+ */
+
+GLOBAL(void)
+jpeg_copy_critical_parameters (j_decompress_ptr srcinfo,
+ j_compress_ptr dstinfo)
+{
+ JQUANT_TBL ** qtblptr;
+ jpeg_component_info *incomp, *outcomp;
+ JQUANT_TBL *c_quant, *slot_quant;
+ int tblno, ci, coefi;
+
+ /* Safety check to ensure start_compress not called yet. */
+ if (dstinfo->global_state != CSTATE_START)
+ ERREXIT1(dstinfo, JERR_BAD_STATE, dstinfo->global_state);
+ /* Copy fundamental image dimensions */
+ dstinfo->image_width = srcinfo->image_width;
+ dstinfo->image_height = srcinfo->image_height;
+ dstinfo->input_components = srcinfo->num_components;
+ dstinfo->in_color_space = srcinfo->jpeg_color_space;
+ dstinfo->jpeg_width = srcinfo->output_width;
+ dstinfo->jpeg_height = srcinfo->output_height;
+ dstinfo->min_DCT_h_scaled_size = srcinfo->min_DCT_h_scaled_size;
+ dstinfo->min_DCT_v_scaled_size = srcinfo->min_DCT_v_scaled_size;
+ /* Initialize all parameters to default values */
+ jpeg_set_defaults(dstinfo);
+ /* jpeg_set_defaults may choose wrong colorspace, eg YCbCr if input is RGB.
+ * Fix it to get the right header markers for the image colorspace.
+ */
+ jpeg_set_colorspace(dstinfo, srcinfo->jpeg_color_space);
+ dstinfo->data_precision = srcinfo->data_precision;
+ dstinfo->CCIR601_sampling = srcinfo->CCIR601_sampling;
+ /* Copy the source's quantization tables. */
+ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+ if (srcinfo->quant_tbl_ptrs[tblno] != NULL) {
+ qtblptr = & dstinfo->quant_tbl_ptrs[tblno];
+ if (*qtblptr == NULL)
+ *qtblptr = jpeg_alloc_quant_table((j_common_ptr) dstinfo);
+ MEMCOPY((*qtblptr)->quantval,
+ srcinfo->quant_tbl_ptrs[tblno]->quantval,
+ SIZEOF((*qtblptr)->quantval));
+ (*qtblptr)->sent_table = FALSE;
+ }
+ }
+ /* Copy the source's per-component info.
+ * Note we assume jpeg_set_defaults has allocated the dest comp_info array.
+ */
+ dstinfo->num_components = srcinfo->num_components;
+ if (dstinfo->num_components < 1 || dstinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(dstinfo, JERR_COMPONENT_COUNT, dstinfo->num_components,
+ MAX_COMPONENTS);
+ for (ci = 0, incomp = srcinfo->comp_info, outcomp = dstinfo->comp_info;
+ ci < dstinfo->num_components; ci++, incomp++, outcomp++) {
+ outcomp->component_id = incomp->component_id;
+ outcomp->h_samp_factor = incomp->h_samp_factor;
+ outcomp->v_samp_factor = incomp->v_samp_factor;
+ outcomp->quant_tbl_no = incomp->quant_tbl_no;
+ /* Make sure saved quantization table for component matches the qtable
+ * slot. If not, the input file re-used this qtable slot.
+ * IJG encoder currently cannot duplicate this.
+ */
+ tblno = outcomp->quant_tbl_no;
+ if (tblno < 0 || tblno >= NUM_QUANT_TBLS ||
+ srcinfo->quant_tbl_ptrs[tblno] == NULL)
+ ERREXIT1(dstinfo, JERR_NO_QUANT_TABLE, tblno);
+ slot_quant = srcinfo->quant_tbl_ptrs[tblno];
+ c_quant = incomp->quant_table;
+ if (c_quant != NULL) {
+ for (coefi = 0; coefi < DCTSIZE2; coefi++) {
+ if (c_quant->quantval[coefi] != slot_quant->quantval[coefi])
+ ERREXIT1(dstinfo, JERR_MISMATCHED_QUANT_TABLE, tblno);
+ }
+ }
+ /* Note: we do not copy the source's Huffman table assignments;
+ * instead we rely on jpeg_set_colorspace to have made a suitable choice.
+ */
+ }
+ /* Also copy JFIF version and resolution information, if available.
+ * Strictly speaking this isn't "critical" info, but it's nearly
+ * always appropriate to copy it if available. In particular,
+ * if the application chooses to copy JFIF 1.02 extension markers from
+ * the source file, we need to copy the version to make sure we don't
+ * emit a file that has 1.02 extensions but a claimed version of 1.01.
+ * We will *not*, however, copy version info from mislabeled "2.01" files.
+ */
+ if (srcinfo->saw_JFIF_marker) {
+ if (srcinfo->JFIF_major_version == 1) {
+ dstinfo->JFIF_major_version = srcinfo->JFIF_major_version;
+ dstinfo->JFIF_minor_version = srcinfo->JFIF_minor_version;
+ }
+ dstinfo->density_unit = srcinfo->density_unit;
+ dstinfo->X_density = srcinfo->X_density;
+ dstinfo->Y_density = srcinfo->Y_density;
+ }
+}
+
+
+/*
+ * Master selection of compression modules for transcoding.
+ * This substitutes for jcinit.c's initialization of the full compressor.
+ */
+
+LOCAL(void)
+transencode_master_selection (j_compress_ptr cinfo,
+ jvirt_barray_ptr * coef_arrays)
+{
+ /* Initialize master control (includes parameter checking/processing) */
+ jinit_c_master_control(cinfo, TRUE /* transcode only */);
+
+ /* Entropy encoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code)
+ jinit_arith_encoder(cinfo);
+ else {
+ jinit_huff_encoder(cinfo);
+ }
+
+ /* We need a special coefficient buffer controller. */
+ transencode_coef_controller(cinfo, coef_arrays);
+
+ jinit_marker_writer(cinfo);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Write the datastream header (SOI, JFIF) immediately.
+ * Frame and scan headers are postponed till later.
+ * This lets application insert special markers after the SOI.
+ */
+ (*cinfo->marker->write_file_header) (cinfo);
+}
+
+
+/*
+ * The rest of this file is a special implementation of the coefficient
+ * buffer controller. This is similar to jccoefct.c, but it handles only
+ * output from presupplied virtual arrays. Furthermore, we generate any
+ * dummy padding blocks on-the-fly rather than expecting them to be present
+ * in the arrays.
+ */
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_c_coef_controller pub; /* public fields */
+
+ JDIMENSION iMCU_row_num; /* iMCU row # within image */
+ JDIMENSION mcu_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* Virtual block array for each component. */
+ jvirt_barray_ptr * whole_image;
+
+ /* Workspace for constructing dummy blocks at right/bottom edges. */
+ JBLOCKROW dummy_buffer[C_MAX_BLOCKS_IN_MCU];
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+
+LOCAL(void)
+start_iMCU_row (j_compress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (coef->iMCU_row_num < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->mcu_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_coef (j_compress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ if (pass_mode != JBUF_CRANK_DEST)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ coef->iMCU_row_num = 0;
+ start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Process some data.
+ * We process the equivalent of one fully interleaved MCU row ("iMCU" row)
+ * per call, ie, v_samp_factor block rows for each component in the scan.
+ * The data is obtained from the virtual arrays and fed to the entropy coder.
+ * Returns TRUE if the iMCU row is completed, FALSE if suspended.
+ *
+ * NB: input_buf is ignored; it is likely to be a NULL pointer.
+ */
+
+METHODDEF(boolean)
+compress_output (j_compress_ptr cinfo, JSAMPIMAGE input_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, ci, xindex, yindex, yoffset, blockcnt;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW MCU_buffer[C_MAX_BLOCKS_IN_MCU];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ coef->iMCU_row_num * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->mcu_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ blockcnt = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (coef->iMCU_row_num < last_iMCU_row ||
+ yindex+yoffset < compptr->last_row_height) {
+ /* Fill in pointers to real blocks in this row */
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < blockcnt; xindex++)
+ MCU_buffer[blkn++] = buffer_ptr++;
+ } else {
+ /* At bottom of image, need a whole row of dummy blocks */
+ xindex = 0;
+ }
+ /* Fill in any dummy blocks needed in this row.
+ * Dummy blocks are filled in the same way as in jccoefct.c:
+ * all zeroes in the AC entries, DC entries equal to previous
+ * block's DC value. The init routine has already zeroed the
+ * AC entries, so we need only set the DC entries correctly.
+ */
+ for (; xindex < compptr->MCU_width; xindex++) {
+ MCU_buffer[blkn] = coef->dummy_buffer[blkn];
+ MCU_buffer[blkn][0][0] = MCU_buffer[blkn-1][0][0];
+ blkn++;
+ }
+ }
+ }
+ /* Try to write the MCU. */
+ if (! (*cinfo->entropy->encode_mcu) (cinfo, MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->mcu_ctr = MCU_col_num;
+ return FALSE;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->mcu_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ coef->iMCU_row_num++;
+ start_iMCU_row(cinfo);
+ return TRUE;
+}
+
+
+/*
+ * Initialize coefficient buffer controller.
+ *
+ * Each passed coefficient array must be the right size for that
+ * coefficient: width_in_blocks wide and height_in_blocks high,
+ * with unitheight at least v_samp_factor.
+ */
+
+LOCAL(void)
+transencode_coef_controller (j_compress_ptr cinfo,
+ jvirt_barray_ptr * coef_arrays)
+{
+ my_coef_ptr coef;
+ JBLOCKROW buffer;
+ int i;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_c_coef_controller *) coef;
+ coef->pub.start_pass = start_pass_coef;
+ coef->pub.compress_data = compress_output;
+
+ /* Save pointer to virtual arrays */
+ coef->whole_image = coef_arrays;
+
+ /* Allocate and pre-zero space for dummy DCT blocks. */
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ FMEMZERO((void FAR *) buffer, C_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < C_MAX_BLOCKS_IN_MCU; i++) {
+ coef->dummy_buffer[i] = buffer + i;
+ }
+}
diff --git a/jpg/jdapimin.c b/jpg/jdapimin.c
new file mode 100644
index 0000000..7f1ce4c
--- /dev/null
+++ b/jpg/jdapimin.c
@@ -0,0 +1,396 @@
+/*
+ * jdapimin.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library. These are the "minimum" API routines that may be
+ * needed in either the normal full-decompression case or the
+ * transcoding-only case.
+ *
+ * Most of the routines intended to be called directly by an application
+ * are in this file or in jdapistd.c. But also see jcomapi.c for routines
+ * shared by compression and decompression, and jdtrans.c for the transcoding
+ * case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * Initialization of a JPEG decompression object.
+ * The error manager must already be set up (in case memory manager fails).
+ */
+
+GLOBAL(void)
+jpeg_CreateDecompress (j_decompress_ptr cinfo, int version, size_t structsize)
+{
+ int i;
+
+ /* Guard against version mismatches between library and caller. */
+ cinfo->mem = NULL; /* so jpeg_destroy knows mem mgr not called */
+ if (version != JPEG_LIB_VERSION)
+ ERREXIT2(cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version);
+ if (structsize != SIZEOF(struct jpeg_decompress_struct))
+ ERREXIT2(cinfo, JERR_BAD_STRUCT_SIZE,
+ (int) SIZEOF(struct jpeg_decompress_struct), (int) structsize);
+
+ /* For debugging purposes, we zero the whole master structure.
+ * But the application has already set the err pointer, and may have set
+ * client_data, so we have to save and restore those fields.
+ * Note: if application hasn't set client_data, tools like Purify may
+ * complain here.
+ */
+ {
+ struct jpeg_error_mgr * err = cinfo->err;
+ void * client_data = cinfo->client_data; /* ignore Purify complaint here */
+ MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct));
+ cinfo->err = err;
+ cinfo->client_data = client_data;
+ }
+ cinfo->is_decompressor = TRUE;
+
+ /* Initialize a memory manager instance for this object */
+ jinit_memory_mgr((j_common_ptr) cinfo);
+
+ /* Zero out pointers to permanent structures. */
+ cinfo->progress = NULL;
+ cinfo->src = NULL;
+
+ for (i = 0; i < NUM_QUANT_TBLS; i++)
+ cinfo->quant_tbl_ptrs[i] = NULL;
+
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ cinfo->dc_huff_tbl_ptrs[i] = NULL;
+ cinfo->ac_huff_tbl_ptrs[i] = NULL;
+ }
+
+ /* Initialize marker processor so application can override methods
+ * for COM, APPn markers before calling jpeg_read_header.
+ */
+ cinfo->marker_list = NULL;
+ jinit_marker_reader(cinfo);
+
+ /* And initialize the overall input controller. */
+ jinit_input_controller(cinfo);
+
+ /* OK, I'm ready */
+ cinfo->global_state = DSTATE_START;
+}
+
+
+/*
+ * Destruction of a JPEG decompression object
+ */
+
+GLOBAL(void)
+jpeg_destroy_decompress (j_decompress_ptr cinfo)
+{
+ jpeg_destroy((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Abort processing of a JPEG decompression operation,
+ * but don't destroy the object itself.
+ */
+
+GLOBAL(void)
+jpeg_abort_decompress (j_decompress_ptr cinfo)
+{
+ jpeg_abort((j_common_ptr) cinfo); /* use common routine */
+}
+
+
+/*
+ * Set default decompression parameters.
+ */
+
+LOCAL(void)
+default_decompress_parms (j_decompress_ptr cinfo)
+{
+ /* Guess the input colorspace, and set output colorspace accordingly. */
+ /* (Wish JPEG committee had provided a real way to specify this...) */
+ /* Note application may override our guesses. */
+ switch (cinfo->num_components) {
+ case 1:
+ cinfo->jpeg_color_space = JCS_GRAYSCALE;
+ cinfo->out_color_space = JCS_GRAYSCALE;
+ break;
+
+ case 3:
+ if (cinfo->saw_JFIF_marker) {
+ cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */
+ } else if (cinfo->saw_Adobe_marker) {
+ switch (cinfo->Adobe_transform) {
+ case 0:
+ cinfo->jpeg_color_space = JCS_RGB;
+ break;
+ case 1:
+ cinfo->jpeg_color_space = JCS_YCbCr;
+ break;
+ default:
+ WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ break;
+ }
+ } else {
+ /* Saw no special markers, try to guess from the component IDs */
+ int cid0 = cinfo->comp_info[0].component_id;
+ int cid1 = cinfo->comp_info[1].component_id;
+ int cid2 = cinfo->comp_info[2].component_id;
+
+ if (cid0 == 1 && cid1 == 2 && cid2 == 3)
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */
+ else if (cid0 == 82 && cid1 == 71 && cid2 == 66)
+ cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */
+ else {
+ TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2);
+ cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */
+ }
+ }
+ /* Always guess RGB is proper output colorspace. */
+ cinfo->out_color_space = JCS_RGB;
+ break;
+
+ case 4:
+ if (cinfo->saw_Adobe_marker) {
+ switch (cinfo->Adobe_transform) {
+ case 0:
+ cinfo->jpeg_color_space = JCS_CMYK;
+ break;
+ case 2:
+ cinfo->jpeg_color_space = JCS_YCCK;
+ break;
+ default:
+ WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform);
+ cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */
+ break;
+ }
+ } else {
+ /* No special markers, assume straight CMYK. */
+ cinfo->jpeg_color_space = JCS_CMYK;
+ }
+ cinfo->out_color_space = JCS_CMYK;
+ break;
+
+ default:
+ cinfo->jpeg_color_space = JCS_UNKNOWN;
+ cinfo->out_color_space = JCS_UNKNOWN;
+ break;
+ }
+
+ /* Set defaults for other decompression parameters. */
+ cinfo->scale_num = cinfo->block_size; /* 1:1 scaling */
+ cinfo->scale_denom = cinfo->block_size;
+ cinfo->output_gamma = 1.0;
+ cinfo->buffered_image = FALSE;
+ cinfo->raw_data_out = FALSE;
+ cinfo->dct_method = JDCT_DEFAULT;
+ cinfo->do_fancy_upsampling = TRUE;
+ cinfo->do_block_smoothing = TRUE;
+ cinfo->quantize_colors = FALSE;
+ /* We set these in case application only sets quantize_colors. */
+ cinfo->dither_mode = JDITHER_FS;
+#ifdef QUANT_2PASS_SUPPORTED
+ cinfo->two_pass_quantize = TRUE;
+#else
+ cinfo->two_pass_quantize = FALSE;
+#endif
+ cinfo->desired_number_of_colors = 256;
+ cinfo->colormap = NULL;
+ /* Initialize for no mode change in buffered-image mode. */
+ cinfo->enable_1pass_quant = FALSE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+}
+
+
+/*
+ * Decompression startup: read start of JPEG datastream to see what's there.
+ * Need only initialize JPEG object and supply a data source before calling.
+ *
+ * This routine will read as far as the first SOS marker (ie, actual start of
+ * compressed data), and will save all tables and parameters in the JPEG
+ * object. It will also initialize the decompression parameters to default
+ * values, and finally return JPEG_HEADER_OK. On return, the application may
+ * adjust the decompression parameters and then call jpeg_start_decompress.
+ * (Or, if the application only wanted to determine the image parameters,
+ * the data need not be decompressed. In that case, call jpeg_abort or
+ * jpeg_destroy to release any temporary space.)
+ * If an abbreviated (tables only) datastream is presented, the routine will
+ * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then
+ * re-use the JPEG object to read the abbreviated image datastream(s).
+ * It is unnecessary (but OK) to call jpeg_abort in this case.
+ * The JPEG_SUSPENDED return code only occurs if the data source module
+ * requests suspension of the decompressor. In this case the application
+ * should load more source data and then re-call jpeg_read_header to resume
+ * processing.
+ * If a non-suspending data source is used and require_image is TRUE, then the
+ * return code need not be inspected since only JPEG_HEADER_OK is possible.
+ *
+ * This routine is now just a front end to jpeg_consume_input, with some
+ * extra error checking.
+ */
+
+GLOBAL(int)
+jpeg_read_header (j_decompress_ptr cinfo, boolean require_image)
+{
+ int retcode;
+
+ if (cinfo->global_state != DSTATE_START &&
+ cinfo->global_state != DSTATE_INHEADER)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ retcode = jpeg_consume_input(cinfo);
+
+ switch (retcode) {
+ case JPEG_REACHED_SOS:
+ retcode = JPEG_HEADER_OK;
+ break;
+ case JPEG_REACHED_EOI:
+ if (require_image) /* Complain if application wanted an image */
+ ERREXIT(cinfo, JERR_NO_IMAGE);
+ /* Reset to start state; it would be safer to require the application to
+ * call jpeg_abort, but we can't change it now for compatibility reasons.
+ * A side effect is to free any temporary memory (there shouldn't be any).
+ */
+ jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */
+ retcode = JPEG_HEADER_TABLES_ONLY;
+ break;
+ case JPEG_SUSPENDED:
+ /* no work */
+ break;
+ }
+
+ return retcode;
+}
+
+
+/*
+ * Consume data in advance of what the decompressor requires.
+ * This can be called at any time once the decompressor object has
+ * been created and a data source has been set up.
+ *
+ * This routine is essentially a state machine that handles a couple
+ * of critical state-transition actions, namely initial setup and
+ * transition from header scanning to ready-for-start_decompress.
+ * All the actual input is done via the input controller's consume_input
+ * method.
+ */
+
+GLOBAL(int)
+jpeg_consume_input (j_decompress_ptr cinfo)
+{
+ int retcode = JPEG_SUSPENDED;
+
+ /* NB: every possible DSTATE value should be listed in this switch */
+ switch (cinfo->global_state) {
+ case DSTATE_START:
+ /* Start-of-datastream actions: reset appropriate modules */
+ (*cinfo->inputctl->reset_input_controller) (cinfo);
+ /* Initialize application's data source module */
+ (*cinfo->src->init_source) (cinfo);
+ cinfo->global_state = DSTATE_INHEADER;
+ /*FALLTHROUGH*/
+ case DSTATE_INHEADER:
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */
+ /* Set up default parameters based on header data */
+ default_decompress_parms(cinfo);
+ /* Set global state: ready for start_decompress */
+ cinfo->global_state = DSTATE_READY;
+ }
+ break;
+ case DSTATE_READY:
+ /* Can't advance past first SOS until start_decompress is called */
+ retcode = JPEG_REACHED_SOS;
+ break;
+ case DSTATE_PRELOAD:
+ case DSTATE_PRESCAN:
+ case DSTATE_SCANNING:
+ case DSTATE_RAW_OK:
+ case DSTATE_BUFIMAGE:
+ case DSTATE_BUFPOST:
+ case DSTATE_STOPPING:
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ break;
+ default:
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ return retcode;
+}
+
+
+/*
+ * Have we finished reading the input file?
+ */
+
+GLOBAL(boolean)
+jpeg_input_complete (j_decompress_ptr cinfo)
+{
+ /* Check for valid jpeg object */
+ if (cinfo->global_state < DSTATE_START ||
+ cinfo->global_state > DSTATE_STOPPING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return cinfo->inputctl->eoi_reached;
+}
+
+
+/*
+ * Is there more than one scan?
+ */
+
+GLOBAL(boolean)
+jpeg_has_multiple_scans (j_decompress_ptr cinfo)
+{
+ /* Only valid after jpeg_read_header completes */
+ if (cinfo->global_state < DSTATE_READY ||
+ cinfo->global_state > DSTATE_STOPPING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return cinfo->inputctl->has_multiple_scans;
+}
+
+
+/*
+ * Finish JPEG decompression.
+ *
+ * This will normally just verify the file trailer and release temp storage.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_decompress (j_decompress_ptr cinfo)
+{
+ if ((cinfo->global_state == DSTATE_SCANNING ||
+ cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) {
+ /* Terminate final pass of non-buffered mode */
+ if (cinfo->output_scanline < cinfo->output_height)
+ ERREXIT(cinfo, JERR_TOO_LITTLE_DATA);
+ (*cinfo->master->finish_output_pass) (cinfo);
+ cinfo->global_state = DSTATE_STOPPING;
+ } else if (cinfo->global_state == DSTATE_BUFIMAGE) {
+ /* Finishing after a buffered-image operation */
+ cinfo->global_state = DSTATE_STOPPING;
+ } else if (cinfo->global_state != DSTATE_STOPPING) {
+ /* STOPPING = repeat call after a suspension, anything else is error */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ /* Read until EOI */
+ while (! cinfo->inputctl->eoi_reached) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return FALSE; /* Suspend, come back later */
+ }
+ /* Do final cleanup */
+ (*cinfo->src->term_source) (cinfo);
+ /* We can use jpeg_abort to release memory and reset global_state */
+ jpeg_abort((j_common_ptr) cinfo);
+ return TRUE;
+}
diff --git a/jpg/jdapistd.c b/jpg/jdapistd.c
new file mode 100644
index 0000000..9d74537
--- /dev/null
+++ b/jpg/jdapistd.c
@@ -0,0 +1,275 @@
+/*
+ * jdapistd.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains application interface code for the decompression half
+ * of the JPEG library. These are the "standard" API routines that are
+ * used in the normal full-decompression case. They are not used by a
+ * transcoding-only application. Note that if an application links in
+ * jpeg_start_decompress, it will end up linking in the entire decompressor.
+ * We thus must separate this file from jdapimin.c to avoid linking the
+ * whole decompression library into a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(boolean) output_pass_setup JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Decompression initialization.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * If a multipass operating mode was selected, this will do all but the
+ * last pass, and thus may take a great deal of time.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_start_decompress (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ /* First call: initialize master control, select active modules */
+ jinit_master_decompress(cinfo);
+ if (cinfo->buffered_image) {
+ /* No more work here; expecting jpeg_start_output next */
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+ }
+ cinfo->global_state = DSTATE_PRELOAD;
+ }
+ if (cinfo->global_state == DSTATE_PRELOAD) {
+ /* If file has multiple scans, absorb them all into the coef buffer */
+ if (cinfo->inputctl->has_multiple_scans) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_SUSPENDED)
+ return FALSE;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* jdmaster underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+ }
+ cinfo->output_scan_number = cinfo->input_scan_number;
+ } else if (cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Perform any dummy output passes, and set up for the final pass */
+ return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Set up for an output pass, and perform any dummy pass(es) needed.
+ * Common subroutine for jpeg_start_decompress and jpeg_start_output.
+ * Entry: global_state = DSTATE_PRESCAN only if previously suspended.
+ * Exit: If done, returns TRUE and sets global_state for proper output mode.
+ * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN.
+ */
+
+LOCAL(boolean)
+output_pass_setup (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state != DSTATE_PRESCAN) {
+ /* First call: do pass setup */
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ cinfo->output_scanline = 0;
+ cinfo->global_state = DSTATE_PRESCAN;
+ }
+ /* Loop over any required dummy passes */
+ while (cinfo->master->is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Crank through the dummy pass */
+ while (cinfo->output_scanline < cinfo->output_height) {
+ JDIMENSION last_scanline;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+ /* Process some data */
+ last_scanline = cinfo->output_scanline;
+ (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL,
+ &cinfo->output_scanline, (JDIMENSION) 0);
+ if (cinfo->output_scanline == last_scanline)
+ return FALSE; /* No progress made, must suspend */
+ }
+ /* Finish up dummy pass, and set up for another one */
+ (*cinfo->master->finish_output_pass) (cinfo);
+ (*cinfo->master->prepare_for_output_pass) (cinfo);
+ cinfo->output_scanline = 0;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ }
+ /* Ready for application to drive output pass through
+ * jpeg_read_scanlines or jpeg_read_raw_data.
+ */
+ cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING;
+ return TRUE;
+}
+
+
+/*
+ * Read some scanlines of data from the JPEG decompressor.
+ *
+ * The return value will be the number of lines actually read.
+ * This may be less than the number requested in several cases,
+ * including bottom of image, data source suspension, and operating
+ * modes that emit multiple scanlines at a time.
+ *
+ * Note: we warn about excess calls to jpeg_read_scanlines() since
+ * this likely signals an application programmer error. However,
+ * an oversize buffer (max_lines > scanlines remaining) is not an error.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines,
+ JDIMENSION max_lines)
+{
+ JDIMENSION row_ctr;
+
+ if (cinfo->global_state != DSTATE_SCANNING)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->output_scanline >= cinfo->output_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Process some data */
+ row_ctr = 0;
+ (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines);
+ cinfo->output_scanline += row_ctr;
+ return row_ctr;
+}
+
+
+/*
+ * Alternate entry point to read raw data.
+ * Processes exactly one iMCU row per call, unless suspended.
+ */
+
+GLOBAL(JDIMENSION)
+jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data,
+ JDIMENSION max_lines)
+{
+ JDIMENSION lines_per_iMCU_row;
+
+ if (cinfo->global_state != DSTATE_RAW_OK)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ if (cinfo->output_scanline >= cinfo->output_height) {
+ WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
+ return 0;
+ }
+
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->pass_counter = (long) cinfo->output_scanline;
+ cinfo->progress->pass_limit = (long) cinfo->output_height;
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ }
+
+ /* Verify that at least one iMCU row can be returned. */
+ lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_v_scaled_size;
+ if (max_lines < lines_per_iMCU_row)
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* Decompress directly into user's buffer. */
+ if (! (*cinfo->coef->decompress_data) (cinfo, data))
+ return 0; /* suspension forced, can do nothing more */
+
+ /* OK, we processed one iMCU row. */
+ cinfo->output_scanline += lines_per_iMCU_row;
+ return lines_per_iMCU_row;
+}
+
+
+/* Additional entry points for buffered-image mode. */
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Initialize for an output pass in buffered-image mode.
+ */
+
+GLOBAL(boolean)
+jpeg_start_output (j_decompress_ptr cinfo, int scan_number)
+{
+ if (cinfo->global_state != DSTATE_BUFIMAGE &&
+ cinfo->global_state != DSTATE_PRESCAN)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ /* Limit scan number to valid range */
+ if (scan_number <= 0)
+ scan_number = 1;
+ if (cinfo->inputctl->eoi_reached &&
+ scan_number > cinfo->input_scan_number)
+ scan_number = cinfo->input_scan_number;
+ cinfo->output_scan_number = scan_number;
+ /* Perform any dummy output passes, and set up for the real pass */
+ return output_pass_setup(cinfo);
+}
+
+
+/*
+ * Finish up after an output pass in buffered-image mode.
+ *
+ * Returns FALSE if suspended. The return value need be inspected only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(boolean)
+jpeg_finish_output (j_decompress_ptr cinfo)
+{
+ if ((cinfo->global_state == DSTATE_SCANNING ||
+ cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) {
+ /* Terminate this pass. */
+ /* We do not require the whole pass to have been completed. */
+ (*cinfo->master->finish_output_pass) (cinfo);
+ cinfo->global_state = DSTATE_BUFPOST;
+ } else if (cinfo->global_state != DSTATE_BUFPOST) {
+ /* BUFPOST = repeat call after a suspension, anything else is error */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ }
+ /* Read markers looking for SOS or EOI */
+ while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+ ! cinfo->inputctl->eoi_reached) {
+ if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED)
+ return FALSE; /* Suspend, come back later */
+ }
+ cinfo->global_state = DSTATE_BUFIMAGE;
+ return TRUE;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
diff --git a/jpg/jdarith.c b/jpg/jdarith.c
new file mode 100644
index 0000000..092f8af
--- /dev/null
+++ b/jpg/jdarith.c
@@ -0,0 +1,776 @@
+/*
+ * jdarith.c
+ *
+ * Developed 1997-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains portable arithmetic entropy decoding routines for JPEG
+ * (implementing the ISO/IEC IS 10918-1 and CCITT Recommendation ITU-T T.81).
+ *
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Suspension is not currently supported in this module.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Expanded entropy decoder object for arithmetic decoding. */
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ INT32 c; /* C register, base of coding interval + input bit buffer */
+ INT32 a; /* A register, normalized size of coding interval */
+ int ct; /* bit shift counter, # of bits left in bit buffer part of C */
+ /* init: ct = -16 */
+ /* run: ct = 0..7 */
+ /* error: ct = -1 */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+ int dc_context[MAX_COMPS_IN_SCAN]; /* context index for DC conditioning */
+
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Pointers to statistics areas (these workspaces have image lifespan) */
+ unsigned char * dc_stats[NUM_ARITH_TBLS];
+ unsigned char * ac_stats[NUM_ARITH_TBLS];
+
+ /* Statistics bin for coding with fixed probability 0.5 */
+ unsigned char fixed_bin[4];
+} arith_entropy_decoder;
+
+typedef arith_entropy_decoder * arith_entropy_ptr;
+
+/* The following two definitions specify the allocation chunk size
+ * for the statistics area.
+ * According to sections F.1.4.4.1.3 and F.1.4.4.2, we need at least
+ * 49 statistics bins for DC, and 245 statistics bins for AC coding.
+ *
+ * We use a compact representation with 1 byte per statistics bin,
+ * thus the numbers directly represent byte sizes.
+ * This 1 byte per statistics bin contains the meaning of the MPS
+ * (more probable symbol) in the highest bit (mask 0x80), and the
+ * index into the probability estimation state machine table
+ * in the lower bits (mask 0x7F).
+ */
+
+#define DC_STAT_BINS 64
+#define AC_STAT_BINS 256
+
+
+LOCAL(int)
+get_byte (j_decompress_ptr cinfo)
+/* Read next input byte; we do not support suspension in this module. */
+{
+ struct jpeg_source_mgr * src = cinfo->src;
+
+ if (src->bytes_in_buffer == 0)
+ if (! (*src->fill_input_buffer) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+ src->bytes_in_buffer--;
+ return GETJOCTET(*src->next_input_byte++);
+}
+
+
+/*
+ * The core arithmetic decoding routine (common in JPEG and JBIG).
+ * This needs to go as fast as possible.
+ * Machine-dependent optimization facilities
+ * are not utilized in this portable implementation.
+ * However, this code should be fairly efficient and
+ * may be a good base for further optimizations anyway.
+ *
+ * Return value is 0 or 1 (binary decision).
+ *
+ * Note: I've changed the handling of the code base & bit
+ * buffer register C compared to other implementations
+ * based on the standards layout & procedures.
+ * While it also contains both the actual base of the
+ * coding interval (16 bits) and the next-bits buffer,
+ * the cut-point between these two parts is floating
+ * (instead of fixed) with the bit shift counter CT.
+ * Thus, we also need only one (variable instead of
+ * fixed size) shift for the LPS/MPS decision, and
+ * we can get away with any renormalization update
+ * of C (except for new data insertion, of course).
+ *
+ * I've also introduced a new scheme for accessing
+ * the probability estimation state machine table,
+ * derived from Markus Kuhn's JBIG implementation.
+ */
+
+LOCAL(int)
+arith_decode (j_decompress_ptr cinfo, unsigned char *st)
+{
+ register arith_entropy_ptr e = (arith_entropy_ptr) cinfo->entropy;
+ register unsigned char nl, nm;
+ register INT32 qe, temp;
+ register int sv, data;
+
+ /* Renormalization & data input per section D.2.6 */
+ while (e->a < 0x8000L) {
+ if (--e->ct < 0) {
+ /* Need to fetch next data byte */
+ if (cinfo->unread_marker)
+ data = 0; /* stuff zero data */
+ else {
+ data = get_byte(cinfo); /* read next input byte */
+ if (data == 0xFF) { /* zero stuff or marker code */
+ do data = get_byte(cinfo);
+ while (data == 0xFF); /* swallow extra 0xFF bytes */
+ if (data == 0)
+ data = 0xFF; /* discard stuffed zero byte */
+ else {
+ /* Note: Different from the Huffman decoder, hitting
+ * a marker while processing the compressed data
+ * segment is legal in arithmetic coding.
+ * The convention is to supply zero data
+ * then until decoding is complete.
+ */
+ cinfo->unread_marker = data;
+ data = 0;
+ }
+ }
+ }
+ e->c = (e->c << 8) | data; /* insert data into C register */
+ if ((e->ct += 8) < 0) /* update bit shift counter */
+ /* Need more initial bytes */
+ if (++e->ct == 0)
+ /* Got 2 initial bytes -> re-init A and exit loop */
+ e->a = 0x8000L; /* => e->a = 0x10000L after loop exit */
+ }
+ e->a <<= 1;
+ }
+
+ /* Fetch values from our compact representation of Table D.3(D.2):
+ * Qe values and probability estimation state machine
+ */
+ sv = *st;
+ qe = jpeg_aritab[sv & 0x7F]; /* => Qe_Value */
+ nl = qe & 0xFF; qe >>= 8; /* Next_Index_LPS + Switch_MPS */
+ nm = qe & 0xFF; qe >>= 8; /* Next_Index_MPS */
+
+ /* Decode & estimation procedures per sections D.2.4 & D.2.5 */
+ temp = e->a - qe;
+ e->a = temp;
+ temp <<= e->ct;
+ if (e->c >= temp) {
+ e->c -= temp;
+ /* Conditional LPS (less probable symbol) exchange */
+ if (e->a < qe) {
+ e->a = qe;
+ *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
+ } else {
+ e->a = qe;
+ *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
+ sv ^= 0x80; /* Exchange LPS/MPS */
+ }
+ } else if (e->a < 0x8000L) {
+ /* Conditional MPS (more probable symbol) exchange */
+ if (e->a < qe) {
+ *st = (sv & 0x80) ^ nl; /* Estimate_after_LPS */
+ sv ^= 0x80; /* Exchange LPS/MPS */
+ } else {
+ *st = (sv & 0x80) ^ nm; /* Estimate_after_MPS */
+ }
+ }
+
+ return sv >> 7;
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ */
+
+LOCAL(void)
+process_restart (j_decompress_ptr cinfo)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ int ci;
+ jpeg_component_info * compptr;
+
+ /* Advance past the RSTn marker */
+ if (! (*cinfo->marker->read_restart_marker) (cinfo))
+ ERREXIT(cinfo, JERR_CANT_SUSPEND);
+
+ /* Re-initialize statistics areas */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+ MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS);
+ /* Reset DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ entropy->dc_context[ci] = 0;
+ }
+ if ((! cinfo->progressive_mode && cinfo->lim_Se) ||
+ (cinfo->progressive_mode && cinfo->Ss)) {
+ MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS);
+ }
+ }
+
+ /* Reset arithmetic decoding variables */
+ entropy->c = 0;
+ entropy->a = 0;
+ entropy->ct = -16; /* force reading 2 initial bytes to fill C */
+
+ /* Reset restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Arithmetic MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * arithmetic-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int blkn, ci, tbl, sign;
+ int v, m;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ if (entropy->ct == -1) return TRUE; /* if error do nothing */
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ tbl = cinfo->cur_comp_info[ci]->dc_tbl_no;
+
+ /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
+
+ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+ st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+ /* Figure F.19: Decode_DC_DIFF */
+ if (arith_decode(cinfo, st) == 0)
+ entropy->dc_context[ci] = 0;
+ else {
+ /* Figure F.21: Decoding nonzero value v */
+ /* Figure F.22: Decoding the sign of v */
+ sign = arith_decode(cinfo, st + 1);
+ st += 2; st += sign;
+ /* Figure F.23: Decoding the magnitude category of v */
+ if ((m = arith_decode(cinfo, st)) != 0) {
+ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+ while (arith_decode(cinfo, st)) {
+ if ((m <<= 1) == 0x8000) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* magnitude overflow */
+ return TRUE;
+ }
+ st += 1;
+ }
+ }
+ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+ if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+ entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
+ else
+ entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */
+ v = m;
+ /* Figure F.24: Decoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ if (arith_decode(cinfo, st)) v |= m;
+ v += 1; if (sign) v = -v;
+ entropy->last_dc_val[ci] += v;
+ }
+
+ /* Scale and output the DC coefficient (assumes jpeg_natural_order[0]=0) */
+ (*block)[0] = (JCOEF) (entropy->last_dc_val[ci] << cinfo->Al);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ unsigned char *st;
+ int tbl, sign, k;
+ int v, m;
+ const int * natural_order;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ if (entropy->ct == -1) return TRUE; /* if error do nothing */
+
+ natural_order = cinfo->natural_order;
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+ /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
+
+ /* Figure F.20: Decode_AC_coefficients */
+ for (k = cinfo->Ss; k <= cinfo->Se; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ if (arith_decode(cinfo, st)) break; /* EOB flag */
+ while (arith_decode(cinfo, st + 1) == 0) {
+ st += 3; k++;
+ if (k > cinfo->Se) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* spectral overflow */
+ return TRUE;
+ }
+ }
+ /* Figure F.21: Decoding nonzero value v */
+ /* Figure F.22: Decoding the sign of v */
+ sign = arith_decode(cinfo, entropy->fixed_bin);
+ st += 2;
+ /* Figure F.23: Decoding the magnitude category of v */
+ if ((m = arith_decode(cinfo, st)) != 0) {
+ if (arith_decode(cinfo, st)) {
+ m <<= 1;
+ st = entropy->ac_stats[tbl] +
+ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+ while (arith_decode(cinfo, st)) {
+ if ((m <<= 1) == 0x8000) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* magnitude overflow */
+ return TRUE;
+ }
+ st += 1;
+ }
+ }
+ }
+ v = m;
+ /* Figure F.24: Decoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ if (arith_decode(cinfo, st)) v |= m;
+ v += 1; if (sign) v = -v;
+ /* Scale and output coefficient in natural (dezigzagged) order */
+ (*block)[natural_order[k]] = (JCOEF) (v << cinfo->Al);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ unsigned char *st;
+ int p1, blkn;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ st = entropy->fixed_bin; /* use fixed probability estimation */
+ p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ /* Encoded data is simply the next bit of the two's-complement DC value */
+ if (arith_decode(cinfo, st))
+ MCU_data[blkn][0][0] |= p1;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ JBLOCKROW block;
+ JCOEFPTR thiscoef;
+ unsigned char *st;
+ int tbl, k, kex;
+ int p1, m1;
+ const int * natural_order;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ if (entropy->ct == -1) return TRUE; /* if error do nothing */
+
+ natural_order = cinfo->natural_order;
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = cinfo->cur_comp_info[0]->ac_tbl_no;
+
+ p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
+
+ /* Establish EOBx (previous stage end-of-block) index */
+ for (kex = cinfo->Se; kex > 0; kex--)
+ if ((*block)[natural_order[kex]]) break;
+
+ for (k = cinfo->Ss; k <= cinfo->Se; k++) {
+ st = entropy->ac_stats[tbl] + 3 * (k - 1);
+ if (k > kex)
+ if (arith_decode(cinfo, st)) break; /* EOB flag */
+ for (;;) {
+ thiscoef = *block + natural_order[k];
+ if (*thiscoef) { /* previously nonzero coef */
+ if (arith_decode(cinfo, st + 2)) {
+ if (*thiscoef < 0)
+ *thiscoef += m1;
+ else
+ *thiscoef += p1;
+ }
+ break;
+ }
+ if (arith_decode(cinfo, st + 1)) { /* newly nonzero coef */
+ if (arith_decode(cinfo, entropy->fixed_bin))
+ *thiscoef = m1;
+ else
+ *thiscoef = p1;
+ break;
+ }
+ st += 3; k++;
+ if (k > cinfo->Se) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* spectral overflow */
+ return TRUE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Decode one MCU's worth of arithmetic-compressed coefficients.
+ */
+
+METHODDEF(boolean)
+decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ jpeg_component_info * compptr;
+ JBLOCKROW block;
+ unsigned char *st;
+ int blkn, ci, tbl, sign, k;
+ int v, m;
+ const int * natural_order;
+
+ /* Process restart marker if needed */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ process_restart(cinfo);
+ entropy->restarts_to_go--;
+ }
+
+ if (entropy->ct == -1) return TRUE; /* if error do nothing */
+
+ natural_order = cinfo->natural_order;
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+
+ /* Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients */
+
+ tbl = compptr->dc_tbl_no;
+
+ /* Table F.4: Point to statistics bin S0 for DC coefficient coding */
+ st = entropy->dc_stats[tbl] + entropy->dc_context[ci];
+
+ /* Figure F.19: Decode_DC_DIFF */
+ if (arith_decode(cinfo, st) == 0)
+ entropy->dc_context[ci] = 0;
+ else {
+ /* Figure F.21: Decoding nonzero value v */
+ /* Figure F.22: Decoding the sign of v */
+ sign = arith_decode(cinfo, st + 1);
+ st += 2; st += sign;
+ /* Figure F.23: Decoding the magnitude category of v */
+ if ((m = arith_decode(cinfo, st)) != 0) {
+ st = entropy->dc_stats[tbl] + 20; /* Table F.4: X1 = 20 */
+ while (arith_decode(cinfo, st)) {
+ if ((m <<= 1) == 0x8000) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* magnitude overflow */
+ return TRUE;
+ }
+ st += 1;
+ }
+ }
+ /* Section F.1.4.4.1.2: Establish dc_context conditioning category */
+ if (m < (int) ((1L << cinfo->arith_dc_L[tbl]) >> 1))
+ entropy->dc_context[ci] = 0; /* zero diff category */
+ else if (m > (int) ((1L << cinfo->arith_dc_U[tbl]) >> 1))
+ entropy->dc_context[ci] = 12 + (sign * 4); /* large diff category */
+ else
+ entropy->dc_context[ci] = 4 + (sign * 4); /* small diff category */
+ v = m;
+ /* Figure F.24: Decoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ if (arith_decode(cinfo, st)) v |= m;
+ v += 1; if (sign) v = -v;
+ entropy->last_dc_val[ci] += v;
+ }
+
+ (*block)[0] = (JCOEF) entropy->last_dc_val[ci];
+
+ /* Sections F.2.4.2 & F.1.4.4.2: Decoding of AC coefficients */
+
+ if (cinfo->lim_Se == 0) continue;
+ tbl = compptr->ac_tbl_no;
+ k = 0;
+
+ /* Figure F.20: Decode_AC_coefficients */
+ do {
+ st = entropy->ac_stats[tbl] + 3 * k;
+ if (arith_decode(cinfo, st)) break; /* EOB flag */
+ for (;;) {
+ k++;
+ if (arith_decode(cinfo, st + 1)) break;
+ st += 3;
+ if (k >= cinfo->lim_Se) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* spectral overflow */
+ return TRUE;
+ }
+ }
+ /* Figure F.21: Decoding nonzero value v */
+ /* Figure F.22: Decoding the sign of v */
+ sign = arith_decode(cinfo, entropy->fixed_bin);
+ st += 2;
+ /* Figure F.23: Decoding the magnitude category of v */
+ if ((m = arith_decode(cinfo, st)) != 0) {
+ if (arith_decode(cinfo, st)) {
+ m <<= 1;
+ st = entropy->ac_stats[tbl] +
+ (k <= cinfo->arith_ac_K[tbl] ? 189 : 217);
+ while (arith_decode(cinfo, st)) {
+ if ((m <<= 1) == 0x8000) {
+ WARNMS(cinfo, JWRN_ARITH_BAD_CODE);
+ entropy->ct = -1; /* magnitude overflow */
+ return TRUE;
+ }
+ st += 1;
+ }
+ }
+ }
+ v = m;
+ /* Figure F.24: Decoding the magnitude bit pattern of v */
+ st += 14;
+ while (m >>= 1)
+ if (arith_decode(cinfo, st)) v |= m;
+ v += 1; if (sign) v = -v;
+ (*block)[natural_order[k]] = (JCOEF) v;
+ } while (k < cinfo->lim_Se);
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Initialize for an arithmetic-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass (j_decompress_ptr cinfo)
+{
+ arith_entropy_ptr entropy = (arith_entropy_ptr) cinfo->entropy;
+ int ci, tbl;
+ jpeg_component_info * compptr;
+
+ if (cinfo->progressive_mode) {
+ /* Validate progressive scan parameters */
+ if (cinfo->Ss == 0) {
+ if (cinfo->Se != 0)
+ goto bad;
+ } else {
+ /* need not check Ss/Se < 0 since they came from unsigned bytes */
+ if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)
+ goto bad;
+ /* AC scans may have only one component */
+ if (cinfo->comps_in_scan != 1)
+ goto bad;
+ }
+ if (cinfo->Ah != 0) {
+ /* Successive approximation refinement scan: must have Al = Ah-1. */
+ if (cinfo->Ah-1 != cinfo->Al)
+ goto bad;
+ }
+ if (cinfo->Al > 13) { /* need not check for < 0 */
+ bad:
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+ }
+ /* Update progression status, and verify that scan order is legal.
+ * Note that inter-scan inconsistencies are treated as warnings
+ * not fatal errors ... not clear if this is right way to behave.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
+ int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+ if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+ for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+ int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+ if (cinfo->Ah != expected)
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+ coef_bit_ptr[coefi] = cinfo->Al;
+ }
+ }
+ /* Select MCU decoding routine */
+ if (cinfo->Ah == 0) {
+ if (cinfo->Ss == 0)
+ entropy->pub.decode_mcu = decode_mcu_DC_first;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_first;
+ } else {
+ if (cinfo->Ss == 0)
+ entropy->pub.decode_mcu = decode_mcu_DC_refine;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_refine;
+ }
+ } else {
+ /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+ * This ought to be an error condition, but we make it a warning.
+ */
+ if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
+ (cinfo->Se < DCTSIZE2 && cinfo->Se != cinfo->lim_Se))
+ WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+ /* Select MCU decoding routine */
+ entropy->pub.decode_mcu = decode_mcu;
+ }
+
+ /* Allocate & initialize requested statistics areas */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ if (! cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) {
+ tbl = compptr->dc_tbl_no;
+ if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+ if (entropy->dc_stats[tbl] == NULL)
+ entropy->dc_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, DC_STAT_BINS);
+ MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS);
+ /* Initialize DC predictions to 0 */
+ entropy->last_dc_val[ci] = 0;
+ entropy->dc_context[ci] = 0;
+ }
+ if ((! cinfo->progressive_mode && cinfo->lim_Se) ||
+ (cinfo->progressive_mode && cinfo->Ss)) {
+ tbl = compptr->ac_tbl_no;
+ if (tbl < 0 || tbl >= NUM_ARITH_TBLS)
+ ERREXIT1(cinfo, JERR_NO_ARITH_TABLE, tbl);
+ if (entropy->ac_stats[tbl] == NULL)
+ entropy->ac_stats[tbl] = (unsigned char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, AC_STAT_BINS);
+ MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS);
+ }
+ }
+
+ /* Initialize arithmetic decoding variables */
+ entropy->c = 0;
+ entropy->a = 0;
+ entropy->ct = -16; /* force reading 2 initial bytes to fill C */
+
+ /* Initialize restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Module initialization routine for arithmetic entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_arith_decoder (j_decompress_ptr cinfo)
+{
+ arith_entropy_ptr entropy;
+ int i;
+
+ entropy = (arith_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(arith_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
+ entropy->pub.start_pass = start_pass;
+
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ entropy->dc_stats[i] = NULL;
+ entropy->ac_stats[i] = NULL;
+ }
+
+ /* Initialize index for fixed probability estimation */
+ entropy->fixed_bin[0] = 113;
+
+ if (cinfo->progressive_mode) {
+ /* Create progression status table */
+ int *coef_bit_ptr, ci;
+ cinfo->coef_bits = (int (*)[DCTSIZE2])
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components*DCTSIZE2*SIZEOF(int));
+ coef_bit_ptr = & cinfo->coef_bits[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (i = 0; i < DCTSIZE2; i++)
+ *coef_bit_ptr++ = -1;
+ }
+}
diff --git a/jpg/jdatadst.c b/jpg/jdatadst.c
new file mode 100644
index 0000000..6981fb7
--- /dev/null
+++ b/jpg/jdatadst.c
@@ -0,0 +1,267 @@
+/*
+ * jdatadst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2012 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains compression data destination routines for the case of
+ * emitting JPEG data to memory or to a file (or any stdio stream).
+ * While these routines are sufficient for most applications,
+ * some will want to use a different destination manager.
+ * IMPORTANT: we assume that fwrite() will correctly transcribe an array of
+ * JOCTETs into 8-bit-wide elements on external storage. If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+
+/* Expanded data destination object for stdio output */
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ FILE * outfile; /* target stream */
+ JOCTET * buffer; /* start of buffer */
+} my_destination_mgr;
+
+typedef my_destination_mgr * my_dest_ptr;
+
+#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */
+
+
+/* Expanded data destination object for memory output */
+
+typedef struct {
+ struct jpeg_destination_mgr pub; /* public fields */
+
+ unsigned char ** outbuffer; /* target buffer */
+ unsigned long * outsize;
+ unsigned char * newbuffer; /* newly allocated buffer */
+ JOCTET * buffer; /* start of buffer */
+ size_t bufsize;
+} my_mem_destination_mgr;
+
+typedef my_mem_destination_mgr * my_mem_dest_ptr;
+
+
+/*
+ * Initialize destination --- called by jpeg_start_compress
+ * before any data is actually written.
+ */
+
+METHODDEF(void)
+init_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ /* Allocate the output buffer --- it will be released when done with image */
+ dest->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ OUTPUT_BUF_SIZE * SIZEOF(JOCTET));
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+}
+
+METHODDEF(void)
+init_mem_destination (j_compress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Empty the output buffer --- called whenever buffer fills up.
+ *
+ * In typical applications, this should write the entire output buffer
+ * (ignoring the current state of next_output_byte & free_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been dumped.
+ *
+ * In applications that need to be able to suspend compression due to output
+ * overrun, a FALSE return indicates that the buffer cannot be emptied now.
+ * In this situation, the compressor will return to its caller (possibly with
+ * an indication that it has not accepted all the supplied scanlines). The
+ * application should resume compression after it has made more room in the
+ * output buffer. Note that there are substantial restrictions on the use of
+ * suspension --- see the documentation.
+ *
+ * When suspending, the compressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_output_byte & free_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point will be regenerated after resumption, so do not
+ * write it out when emptying the buffer externally.
+ */
+
+METHODDEF(boolean)
+empty_output_buffer (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+
+ if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) !=
+ (size_t) OUTPUT_BUF_SIZE)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+
+ dest->pub.next_output_byte = dest->buffer;
+ dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
+
+ return TRUE;
+}
+
+METHODDEF(boolean)
+empty_mem_output_buffer (j_compress_ptr cinfo)
+{
+ size_t nextsize;
+ JOCTET * nextbuffer;
+ my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+ /* Try to allocate new buffer with double size */
+ nextsize = dest->bufsize * 2;
+ nextbuffer = (JOCTET *) malloc(nextsize);
+
+ if (nextbuffer == NULL)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+
+ MEMCOPY(nextbuffer, dest->buffer, dest->bufsize);
+
+ if (dest->newbuffer != NULL)
+ free(dest->newbuffer);
+
+ dest->newbuffer = nextbuffer;
+
+ dest->pub.next_output_byte = nextbuffer + dest->bufsize;
+ dest->pub.free_in_buffer = dest->bufsize;
+
+ dest->buffer = nextbuffer;
+ dest->bufsize = nextsize;
+
+ return TRUE;
+}
+
+
+/*
+ * Terminate destination --- called by jpeg_finish_compress
+ * after all data has been written. Usually needs to flush buffer.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_destination (j_compress_ptr cinfo)
+{
+ my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
+ size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
+
+ /* Write any data remaining in the buffer */
+ if (datacount > 0) {
+ if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ }
+ fflush(dest->outfile);
+ /* Make sure we wrote the output file OK */
+ if (ferror(dest->outfile))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+METHODDEF(void)
+term_mem_destination (j_compress_ptr cinfo)
+{
+ my_mem_dest_ptr dest = (my_mem_dest_ptr) cinfo->dest;
+
+ *dest->outbuffer = dest->buffer;
+ *dest->outsize = dest->bufsize - dest->pub.free_in_buffer;
+}
+
+
+/*
+ * Prepare for output to a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing compression.
+ */
+
+GLOBAL(void)
+jpeg_stdio_dest (j_compress_ptr cinfo, FILE * outfile)
+{
+ my_dest_ptr dest;
+
+ /* The destination object is made permanent so that multiple JPEG images
+ * can be written to the same file without re-executing jpeg_stdio_dest.
+ * This makes it dangerous to use this manager and a different destination
+ * manager serially with the same JPEG object, because their private object
+ * sizes may be different. Caveat programmer.
+ */
+ if (cinfo->dest == NULL) { /* first time for this JPEG object? */
+ cinfo->dest = (struct jpeg_destination_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_destination_mgr));
+ }
+
+ dest = (my_dest_ptr) cinfo->dest;
+ dest->pub.init_destination = init_destination;
+ dest->pub.empty_output_buffer = empty_output_buffer;
+ dest->pub.term_destination = term_destination;
+ dest->outfile = outfile;
+}
+
+
+/*
+ * Prepare for output to a memory buffer.
+ * The caller may supply an own initial buffer with appropriate size.
+ * Otherwise, or when the actual data output exceeds the given size,
+ * the library adapts the buffer size as necessary.
+ * The standard library functions malloc/free are used for allocating
+ * larger memory, so the buffer is available to the application after
+ * finishing compression, and then the application is responsible for
+ * freeing the requested memory.
+ */
+
+GLOBAL(void)
+jpeg_mem_dest (j_compress_ptr cinfo,
+ unsigned char ** outbuffer, unsigned long * outsize)
+{
+ my_mem_dest_ptr dest;
+
+ if (outbuffer == NULL || outsize == NULL) /* sanity check */
+ ERREXIT(cinfo, JERR_BUFFER_SIZE);
+
+ /* The destination object is made permanent so that multiple JPEG images
+ * can be written to the same buffer without re-executing jpeg_mem_dest.
+ */
+ if (cinfo->dest == NULL) { /* first time for this JPEG object? */
+ cinfo->dest = (struct jpeg_destination_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_mem_destination_mgr));
+ }
+
+ dest = (my_mem_dest_ptr) cinfo->dest;
+ dest->pub.init_destination = init_mem_destination;
+ dest->pub.empty_output_buffer = empty_mem_output_buffer;
+ dest->pub.term_destination = term_mem_destination;
+ dest->outbuffer = outbuffer;
+ dest->outsize = outsize;
+ dest->newbuffer = NULL;
+
+ if (*outbuffer == NULL || *outsize == 0) {
+ /* Allocate initial buffer */
+ dest->newbuffer = *outbuffer = (unsigned char *) malloc(OUTPUT_BUF_SIZE);
+ if (dest->newbuffer == NULL)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10);
+ *outsize = OUTPUT_BUF_SIZE;
+ }
+
+ dest->pub.next_output_byte = dest->buffer = *outbuffer;
+ dest->pub.free_in_buffer = dest->bufsize = *outsize;
+}
diff --git a/jpg/jdatasrc.c b/jpg/jdatasrc.c
new file mode 100644
index 0000000..7be59a8
--- /dev/null
+++ b/jpg/jdatasrc.c
@@ -0,0 +1,275 @@
+/*
+ * jdatasrc.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains decompression data source routines for the case of
+ * reading JPEG data from memory or from a file (or any stdio stream).
+ * While these routines are sufficient for most applications,
+ * some will want to use a different source manager.
+ * IMPORTANT: we assume that fread() will correctly transcribe an array of
+ * JOCTETs from 8-bit-wide elements on external storage. If char is wider
+ * than 8 bits on your machine, you may need to do some tweaking.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jerror.h"
+
+
+/* Expanded data source object for stdio input */
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ FILE * infile; /* source stream */
+ JOCTET * buffer; /* start of buffer */
+ boolean start_of_file; /* have we gotten any data yet? */
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+METHODDEF(void)
+init_source (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ /* We reset the empty-input-file flag for each image,
+ * but we don't clear the input buffer.
+ * This is correct behavior for reading a series of images from one source.
+ */
+ src->start_of_file = TRUE;
+}
+
+METHODDEF(void)
+init_mem_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In typical applications, this should read fresh data into the buffer
+ * (ignoring the current state of next_input_byte & bytes_in_buffer),
+ * reset the pointer & count to the start of the buffer, and return TRUE
+ * indicating that the buffer has been reloaded. It is not necessary to
+ * fill the buffer entirely, only to obtain at least one more byte.
+ *
+ * There is no such thing as an EOF return. If the end of the file has been
+ * reached, the routine has a choice of ERREXIT() or inserting fake data into
+ * the buffer. In most cases, generating a warning message and inserting a
+ * fake EOI marker is the best course of action --- this will allow the
+ * decompressor to output however much of the image is there. However,
+ * the resulting error message is misleading if the real problem is an empty
+ * input file, so we handle that case specially.
+ *
+ * In applications that need to be able to suspend compression due to input
+ * not being available yet, a FALSE return indicates that no more data can be
+ * obtained right now, but more may be forthcoming later. In this situation,
+ * the decompressor will return to its caller (with an indication of the
+ * number of scanlines it has read, if any). The application should resume
+ * decompression after it has loaded more data into the input buffer. Note
+ * that there are substantial restrictions on the use of suspension --- see
+ * the documentation.
+ *
+ * When suspending, the decompressor will back up to a convenient restart point
+ * (typically the start of the current MCU). next_input_byte & bytes_in_buffer
+ * indicate where the restart point will be if the current call returns FALSE.
+ * Data beyond this point must be rescanned after resumption, so move it to
+ * the front of the buffer rather than discarding it.
+ */
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+ size_t nbytes;
+
+ nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE);
+
+ if (nbytes <= 0) {
+ if (src->start_of_file) /* Treat empty input file as fatal error */
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_file = FALSE;
+
+ return TRUE;
+}
+
+METHODDEF(boolean)
+fill_mem_input_buffer (j_decompress_ptr cinfo)
+{
+ static const JOCTET mybuffer[4] = {
+ (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0
+ };
+
+ /* The whole JPEG data is expected to reside in the supplied memory
+ * buffer, so any request for more data beyond the given buffer size
+ * is treated as an error.
+ */
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+
+ /* Insert a fake EOI marker */
+
+ cinfo->src->next_input_byte = mybuffer;
+ cinfo->src->bytes_in_buffer = 2;
+
+ return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ * Writers of suspendable-input applications must note that skip_input_data
+ * is not granted the right to give a suspension return. If the skip extends
+ * beyond the data currently in the buffer, the buffer can be marked empty so
+ * that the next read will cause a fill_input_buffer call that can suspend.
+ * Arranging for additional bytes to be discarded before reloading the input
+ * buffer is the application writer's problem.
+ */
+
+METHODDEF(void)
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ struct jpeg_source_mgr * src = cinfo->src;
+
+ /* Just a dumb implementation for now. Could use fseek() except
+ * it doesn't work on pipes. Not clear that being smart is worth
+ * any trouble anyway --- large skips are infrequent.
+ */
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->bytes_in_buffer) {
+ num_bytes -= (long) src->bytes_in_buffer;
+ (void) (*src->fill_input_buffer) (cinfo);
+ /* note we assume that fill_input_buffer will never return FALSE,
+ * so suspension need not be handled.
+ */
+ }
+ src->next_input_byte += (size_t) num_bytes;
+ src->bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library. That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read. Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+METHODDEF(void)
+term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a stdio stream.
+ * The caller must have already opened the stream, and is responsible
+ * for closing it after finishing decompression.
+ */
+
+GLOBAL(void)
+jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile)
+{
+ my_src_ptr src;
+
+ /* The source object and input buffer are made permanent so that a series
+ * of JPEG images can be read from the same file by calling jpeg_stdio_src
+ * only before the first one. (If we discarded the buffer at the end of
+ * one image, we'd likely lose the start of the next one.)
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_source_mgr));
+ src = (my_src_ptr) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * SIZEOF(JOCTET));
+ }
+
+ src = (my_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = term_source;
+ src->infile = infile;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
+
+
+/*
+ * Prepare for input from a supplied memory buffer.
+ * The buffer must contain the whole JPEG data.
+ */
+
+GLOBAL(void)
+jpeg_mem_src (j_decompress_ptr cinfo,
+ unsigned char * inbuffer, unsigned long insize)
+{
+ struct jpeg_source_mgr * src;
+
+ if (inbuffer == NULL || insize == 0) /* Treat empty input as fatal error */
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+
+ /* The source object is made permanent so that a series of JPEG images
+ * can be read from the same buffer by calling jpeg_mem_src only before
+ * the first one.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(struct jpeg_source_mgr));
+ }
+
+ src = cinfo->src;
+ src->init_source = init_mem_source;
+ src->fill_input_buffer = fill_mem_input_buffer;
+ src->skip_input_data = skip_input_data;
+ src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->term_source = term_source;
+ src->bytes_in_buffer = (size_t) insize;
+ src->next_input_byte = (JOCTET *) inbuffer;
+}
diff --git a/jpg/jdcoefct.c b/jpg/jdcoefct.c
new file mode 100644
index 0000000..ed02fc3
--- /dev/null
+++ b/jpg/jdcoefct.c
@@ -0,0 +1,741 @@
+/*
+ * jdcoefct.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2002-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the coefficient buffer controller for decompression.
+ * This controller is the top level of the JPEG decompressor proper.
+ * The coefficient buffer lies between entropy decoding and inverse-DCT steps.
+ *
+ * In buffered-image mode, this controller is the interface between
+ * input-oriented processing and output-oriented processing.
+ * Also, the input side (only) is used when reading a file for transcoding.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+/* Block smoothing is only applicable for progressive JPEG, so: */
+#ifndef D_PROGRESSIVE_SUPPORTED
+#undef BLOCK_SMOOTHING_SUPPORTED
+#endif
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_coef_controller pub; /* public fields */
+
+ /* These variables keep track of the current location of the input side. */
+ /* cinfo->input_iMCU_row is also used for this. */
+ JDIMENSION MCU_ctr; /* counts MCUs processed in current row */
+ int MCU_vert_offset; /* counts MCU rows within iMCU row */
+ int MCU_rows_per_iMCU_row; /* number of such rows needed */
+
+ /* The output side's location is represented by cinfo->output_iMCU_row. */
+
+ /* In single-pass modes, it's sufficient to buffer just one MCU.
+ * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks,
+ * and let the entropy decoder write into that workspace each time.
+ * (On 80x86, the workspace is FAR even though it's not really very big;
+ * this is to keep the module interfaces unchanged when a large coefficient
+ * buffer is necessary.)
+ * In multi-pass modes, this array points to the current MCU's blocks
+ * within the virtual arrays; it is used only by the input side.
+ */
+ JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU];
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* In multi-pass modes, we need a virtual block array for each component. */
+ jvirt_barray_ptr whole_image[MAX_COMPONENTS];
+#endif
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ /* When doing block smoothing, we latch coefficient Al values here */
+ int * coef_bits_latch;
+#define SAVED_COEFS 6 /* we save coef_bits[0..5] */
+#endif
+} my_coef_controller;
+
+typedef my_coef_controller * my_coef_ptr;
+
+/* Forward declarations */
+METHODDEF(int) decompress_onepass
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+METHODDEF(int) decompress_data
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#endif
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+LOCAL(boolean) smoothing_ok JPP((j_decompress_ptr cinfo));
+METHODDEF(int) decompress_smooth_data
+ JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf));
+#endif
+
+
+LOCAL(void)
+start_iMCU_row (j_decompress_ptr cinfo)
+/* Reset within-iMCU-row counters for a new row (input side) */
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* In an interleaved scan, an MCU row is the same as an iMCU row.
+ * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows.
+ * But at the bottom of the image, process only what's left.
+ */
+ if (cinfo->comps_in_scan > 1) {
+ coef->MCU_rows_per_iMCU_row = 1;
+ } else {
+ if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1))
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor;
+ else
+ coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height;
+ }
+
+ coef->MCU_ctr = 0;
+ coef->MCU_vert_offset = 0;
+}
+
+
+/*
+ * Initialize for an input processing pass.
+ */
+
+METHODDEF(void)
+start_input_pass (j_decompress_ptr cinfo)
+{
+ cinfo->input_iMCU_row = 0;
+ start_iMCU_row(cinfo);
+}
+
+
+/*
+ * Initialize for an output processing pass.
+ */
+
+METHODDEF(void)
+start_output_pass (j_decompress_ptr cinfo)
+{
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+
+ /* If multipass, check to see whether to use block smoothing on this pass */
+ if (coef->pub.coef_arrays != NULL) {
+ if (cinfo->do_block_smoothing && smoothing_ok(cinfo))
+ coef->pub.decompress_data = decompress_smooth_data;
+ else
+ coef->pub.decompress_data = decompress_data;
+ }
+#endif
+ cinfo->output_iMCU_row = 0;
+}
+
+
+/*
+ * Decompress and return some data in the single-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Input and output must run in lockstep since we have only a one-MCU buffer.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image,
+ * which we index according to the component's SOF position.
+ */
+
+METHODDEF(int)
+decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ int blkn, ci, xindex, yindex, yoffset, useful_width;
+ JSAMPARRAY output_ptr;
+ JDIMENSION start_col, output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+
+ /* Loop to process as much as one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col;
+ MCU_col_num++) {
+ /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */
+ if (cinfo->lim_Se) /* can bypass in DC only case */
+ FMEMZERO((void FAR *) coef->MCU_buffer[0],
+ (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK)));
+ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ /* Determine where data should go in output_buf and do the IDCT thing.
+ * We skip dummy blocks at the right and bottom edges (but blkn gets
+ * incremented past them!). Note the inner loop relies on having
+ * allocated the MCU_buffer[] blocks sequentially.
+ */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed) {
+ blkn += compptr->MCU_blocks;
+ continue;
+ }
+ inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index];
+ useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width
+ : compptr->last_col_width;
+ output_ptr = output_buf[compptr->component_index] +
+ yoffset * compptr->DCT_v_scaled_size;
+ start_col = MCU_col_num * compptr->MCU_sample_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ if (cinfo->input_iMCU_row < last_iMCU_row ||
+ yoffset+yindex < compptr->last_row_height) {
+ output_col = start_col;
+ for (xindex = 0; xindex < useful_width; xindex++) {
+ (*inverse_DCT) (cinfo, compptr,
+ (JCOEFPTR) coef->MCU_buffer[blkn+xindex],
+ output_ptr, output_col);
+ output_col += compptr->DCT_h_scaled_size;
+ }
+ }
+ blkn += compptr->MCU_width;
+ output_ptr += compptr->DCT_v_scaled_size;
+ }
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ cinfo->output_iMCU_row++;
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Dummy consume-input routine for single-pass operation.
+ */
+
+METHODDEF(int)
+dummy_consume_data (j_decompress_ptr cinfo)
+{
+ return JPEG_SUSPENDED; /* Always indicate nothing was done */
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Consume input data and store it in the full-image coefficient buffer.
+ * We read as much as one fully interleaved MCU row ("iMCU" row) per call,
+ * ie, v_samp_factor block rows for each component in the scan.
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ */
+
+METHODDEF(int)
+consume_data (j_decompress_ptr cinfo)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION MCU_col_num; /* index of current MCU within row */
+ int blkn, ci, xindex, yindex, yoffset;
+ JDIMENSION start_col;
+ JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN];
+ JBLOCKROW buffer_ptr;
+ jpeg_component_info *compptr;
+
+ /* Align the virtual buffers for the components used in this scan. */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ buffer[ci] = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index],
+ cinfo->input_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ /* Note: entropy decoder expects buffer to be zeroed,
+ * but this is handled automatically by the memory manager
+ * because we requested a pre-zeroed array.
+ */
+ }
+
+ /* Loop to process one whole iMCU row */
+ for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row;
+ yoffset++) {
+ for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row;
+ MCU_col_num++) {
+ /* Construct list of pointers to DCT blocks belonging to this MCU */
+ blkn = 0; /* index of current DCT block within MCU */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ start_col = MCU_col_num * compptr->MCU_width;
+ for (yindex = 0; yindex < compptr->MCU_height; yindex++) {
+ buffer_ptr = buffer[ci][yindex+yoffset] + start_col;
+ for (xindex = 0; xindex < compptr->MCU_width; xindex++) {
+ coef->MCU_buffer[blkn++] = buffer_ptr++;
+ }
+ }
+ }
+ /* Try to fetch the MCU. */
+ if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) {
+ /* Suspension forced; update state counters and exit */
+ coef->MCU_vert_offset = yoffset;
+ coef->MCU_ctr = MCU_col_num;
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* Completed an MCU row, but perhaps not an iMCU row */
+ coef->MCU_ctr = 0;
+ }
+ /* Completed the iMCU row, advance counters for next one */
+ if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) {
+ start_iMCU_row(cinfo);
+ return JPEG_ROW_COMPLETED;
+ }
+ /* Completed the scan */
+ (*cinfo->inputctl->finish_input_pass) (cinfo);
+ return JPEG_SCAN_COMPLETED;
+}
+
+
+/*
+ * Decompress and return some data in the multi-pass case.
+ * Always attempts to emit one fully interleaved MCU row ("iMCU" row).
+ * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED.
+ *
+ * NB: output_buf contains a plane for each component in image.
+ */
+
+METHODDEF(int)
+decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION block_num;
+ int ci, block_row, block_rows;
+ JBLOCKARRAY buffer;
+ JBLOCKROW buffer_ptr;
+ JSAMPARRAY output_ptr;
+ JDIMENSION output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo->input_scan_number < cinfo->output_scan_number ||
+ (cinfo->input_scan_number == cinfo->output_scan_number &&
+ cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) {
+ if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed)
+ continue;
+ /* Align the virtual buffer for this component. */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ cinfo->output_iMCU_row * compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (cinfo->output_iMCU_row < last_iMCU_row)
+ block_rows = compptr->v_samp_factor;
+ else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ }
+ inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ output_ptr = output_buf[ci];
+ /* Loop over all DCT blocks to be processed. */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ buffer_ptr = buffer[block_row];
+ output_col = 0;
+ for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) {
+ (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr,
+ output_ptr, output_col);
+ buffer_ptr++;
+ output_col += compptr->DCT_h_scaled_size;
+ }
+ output_ptr += compptr->DCT_v_scaled_size;
+ }
+ }
+
+ if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+
+/*
+ * This code applies interblock smoothing as described by section K.8
+ * of the JPEG standard: the first 5 AC coefficients are estimated from
+ * the DC values of a DCT block and its 8 neighboring blocks.
+ * We apply smoothing only for progressive JPEG decoding, and only if
+ * the coefficients it can estimate are not yet known to full precision.
+ */
+
+/* Natural-order array positions of the first 5 zigzag-order coefficients */
+#define Q01_POS 1
+#define Q10_POS 8
+#define Q20_POS 16
+#define Q11_POS 9
+#define Q02_POS 2
+
+/*
+ * Determine whether block smoothing is applicable and safe.
+ * We also latch the current states of the coef_bits[] entries for the
+ * AC coefficients; otherwise, if the input side of the decompressor
+ * advances into a new scan, we might think the coefficients are known
+ * more accurately than they really are.
+ */
+
+LOCAL(boolean)
+smoothing_ok (j_decompress_ptr cinfo)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ boolean smoothing_useful = FALSE;
+ int ci, coefi;
+ jpeg_component_info *compptr;
+ JQUANT_TBL * qtable;
+ int * coef_bits;
+ int * coef_bits_latch;
+
+ if (! cinfo->progressive_mode || cinfo->coef_bits == NULL)
+ return FALSE;
+
+ /* Allocate latch area if not already done */
+ if (coef->coef_bits_latch == NULL)
+ coef->coef_bits_latch = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components *
+ (SAVED_COEFS * SIZEOF(int)));
+ coef_bits_latch = coef->coef_bits_latch;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* All components' quantization values must already be latched. */
+ if ((qtable = compptr->quant_table) == NULL)
+ return FALSE;
+ /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */
+ if (qtable->quantval[0] == 0 ||
+ qtable->quantval[Q01_POS] == 0 ||
+ qtable->quantval[Q10_POS] == 0 ||
+ qtable->quantval[Q20_POS] == 0 ||
+ qtable->quantval[Q11_POS] == 0 ||
+ qtable->quantval[Q02_POS] == 0)
+ return FALSE;
+ /* DC values must be at least partly known for all components. */
+ coef_bits = cinfo->coef_bits[ci];
+ if (coef_bits[0] < 0)
+ return FALSE;
+ /* Block smoothing is helpful if some AC coefficients remain inaccurate. */
+ for (coefi = 1; coefi <= 5; coefi++) {
+ coef_bits_latch[coefi] = coef_bits[coefi];
+ if (coef_bits[coefi] != 0)
+ smoothing_useful = TRUE;
+ }
+ coef_bits_latch += SAVED_COEFS;
+ }
+
+ return smoothing_useful;
+}
+
+
+/*
+ * Variant of decompress_data for use when doing block smoothing.
+ */
+
+METHODDEF(int)
+decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
+{
+ my_coef_ptr coef = (my_coef_ptr) cinfo->coef;
+ JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
+ JDIMENSION block_num, last_block_column;
+ int ci, block_row, block_rows, access_rows;
+ JBLOCKARRAY buffer;
+ JBLOCKROW buffer_ptr, prev_block_row, next_block_row;
+ JSAMPARRAY output_ptr;
+ JDIMENSION output_col;
+ jpeg_component_info *compptr;
+ inverse_DCT_method_ptr inverse_DCT;
+ boolean first_row, last_row;
+ JBLOCK workspace;
+ int *coef_bits;
+ JQUANT_TBL *quanttbl;
+ INT32 Q00,Q01,Q02,Q10,Q11,Q20, num;
+ int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9;
+ int Al, pred;
+
+ /* Force some input to be done if we are getting ahead of the input. */
+ while (cinfo->input_scan_number <= cinfo->output_scan_number &&
+ ! cinfo->inputctl->eoi_reached) {
+ if (cinfo->input_scan_number == cinfo->output_scan_number) {
+ /* If input is working on current scan, we ordinarily want it to
+ * have completed the current row. But if input scan is DC,
+ * we want it to keep one row ahead so that next block row's DC
+ * values are up to date.
+ */
+ JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0;
+ if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta)
+ break;
+ }
+ if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED)
+ return JPEG_SUSPENDED;
+ }
+
+ /* OK, output from the virtual arrays. */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Don't bother to IDCT an uninteresting component. */
+ if (! compptr->component_needed)
+ continue;
+ /* Count non-dummy DCT block rows in this iMCU row. */
+ if (cinfo->output_iMCU_row < last_iMCU_row) {
+ block_rows = compptr->v_samp_factor;
+ access_rows = block_rows * 2; /* this and next iMCU row */
+ last_row = FALSE;
+ } else {
+ /* NB: can't use last_row_height here; it is input-side-dependent! */
+ block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (block_rows == 0) block_rows = compptr->v_samp_factor;
+ access_rows = block_rows; /* this iMCU row only */
+ last_row = TRUE;
+ }
+ /* Align the virtual buffer for this component. */
+ if (cinfo->output_iMCU_row > 0) {
+ access_rows += compptr->v_samp_factor; /* prior iMCU row too */
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
+ (JDIMENSION) access_rows, FALSE);
+ buffer += compptr->v_samp_factor; /* point to current iMCU row */
+ first_row = FALSE;
+ } else {
+ buffer = (*cinfo->mem->access_virt_barray)
+ ((j_common_ptr) cinfo, coef->whole_image[ci],
+ (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE);
+ first_row = TRUE;
+ }
+ /* Fetch component-dependent info */
+ coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS);
+ quanttbl = compptr->quant_table;
+ Q00 = quanttbl->quantval[0];
+ Q01 = quanttbl->quantval[Q01_POS];
+ Q10 = quanttbl->quantval[Q10_POS];
+ Q20 = quanttbl->quantval[Q20_POS];
+ Q11 = quanttbl->quantval[Q11_POS];
+ Q02 = quanttbl->quantval[Q02_POS];
+ inverse_DCT = cinfo->idct->inverse_DCT[ci];
+ output_ptr = output_buf[ci];
+ /* Loop over all DCT blocks to be processed. */
+ for (block_row = 0; block_row < block_rows; block_row++) {
+ buffer_ptr = buffer[block_row];
+ if (first_row && block_row == 0)
+ prev_block_row = buffer_ptr;
+ else
+ prev_block_row = buffer[block_row-1];
+ if (last_row && block_row == block_rows-1)
+ next_block_row = buffer_ptr;
+ else
+ next_block_row = buffer[block_row+1];
+ /* We fetch the surrounding DC values using a sliding-register approach.
+ * Initialize all nine here so as to do the right thing on narrow pics.
+ */
+ DC1 = DC2 = DC3 = (int) prev_block_row[0][0];
+ DC4 = DC5 = DC6 = (int) buffer_ptr[0][0];
+ DC7 = DC8 = DC9 = (int) next_block_row[0][0];
+ output_col = 0;
+ last_block_column = compptr->width_in_blocks - 1;
+ for (block_num = 0; block_num <= last_block_column; block_num++) {
+ /* Fetch current DCT block into workspace so we can modify it. */
+ jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1);
+ /* Update DC values */
+ if (block_num < last_block_column) {
+ DC3 = (int) prev_block_row[1][0];
+ DC6 = (int) buffer_ptr[1][0];
+ DC9 = (int) next_block_row[1][0];
+ }
+ /* Compute coefficient estimates per K.8.
+ * An estimate is applied only if coefficient is still zero,
+ * and is not known to be fully accurate.
+ */
+ /* AC01 */
+ if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) {
+ num = 36 * Q00 * (DC4 - DC6);
+ if (num >= 0) {
+ pred = (int) (((Q01<<7) + num) / (Q01<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q01<<7) - num) / (Q01<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[1] = (JCOEF) pred;
+ }
+ /* AC10 */
+ if ((Al=coef_bits[2]) != 0 && workspace[8] == 0) {
+ num = 36 * Q00 * (DC2 - DC8);
+ if (num >= 0) {
+ pred = (int) (((Q10<<7) + num) / (Q10<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q10<<7) - num) / (Q10<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[8] = (JCOEF) pred;
+ }
+ /* AC20 */
+ if ((Al=coef_bits[3]) != 0 && workspace[16] == 0) {
+ num = 9 * Q00 * (DC2 + DC8 - 2*DC5);
+ if (num >= 0) {
+ pred = (int) (((Q20<<7) + num) / (Q20<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q20<<7) - num) / (Q20<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[16] = (JCOEF) pred;
+ }
+ /* AC11 */
+ if ((Al=coef_bits[4]) != 0 && workspace[9] == 0) {
+ num = 5 * Q00 * (DC1 - DC3 - DC7 + DC9);
+ if (num >= 0) {
+ pred = (int) (((Q11<<7) + num) / (Q11<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q11<<7) - num) / (Q11<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[9] = (JCOEF) pred;
+ }
+ /* AC02 */
+ if ((Al=coef_bits[5]) != 0 && workspace[2] == 0) {
+ num = 9 * Q00 * (DC4 + DC6 - 2*DC5);
+ if (num >= 0) {
+ pred = (int) (((Q02<<7) + num) / (Q02<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ } else {
+ pred = (int) (((Q02<<7) - num) / (Q02<<8));
+ if (Al > 0 && pred >= (1<<Al))
+ pred = (1<<Al)-1;
+ pred = -pred;
+ }
+ workspace[2] = (JCOEF) pred;
+ }
+ /* OK, do the IDCT */
+ (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) workspace,
+ output_ptr, output_col);
+ /* Advance for next column */
+ DC1 = DC2; DC2 = DC3;
+ DC4 = DC5; DC5 = DC6;
+ DC7 = DC8; DC8 = DC9;
+ buffer_ptr++, prev_block_row++, next_block_row++;
+ output_col += compptr->DCT_h_scaled_size;
+ }
+ output_ptr += compptr->DCT_v_scaled_size;
+ }
+ }
+
+ if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows)
+ return JPEG_ROW_COMPLETED;
+ return JPEG_SCAN_COMPLETED;
+}
+
+#endif /* BLOCK_SMOOTHING_SUPPORTED */
+
+
+/*
+ * Initialize coefficient buffer controller.
+ */
+
+GLOBAL(void)
+jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_coef_ptr coef;
+
+ coef = (my_coef_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_coef_controller));
+ cinfo->coef = (struct jpeg_d_coef_controller *) coef;
+ coef->pub.start_input_pass = start_input_pass;
+ coef->pub.start_output_pass = start_output_pass;
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ coef->coef_bits_latch = NULL;
+#endif
+
+ /* Create the coefficient buffer. */
+ if (need_full_buffer) {
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* Allocate a full-image virtual array for each component, */
+ /* padded to a multiple of samp_factor DCT blocks in each direction. */
+ /* Note we ask for a pre-zeroed array. */
+ int ci, access_rows;
+ jpeg_component_info *compptr;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ access_rows = compptr->v_samp_factor;
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+ /* If block smoothing could be used, need a bigger window */
+ if (cinfo->progressive_mode)
+ access_rows *= 3;
+#endif
+ coef->whole_image[ci] = (*cinfo->mem->request_virt_barray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE,
+ (JDIMENSION) jround_up((long) compptr->width_in_blocks,
+ (long) compptr->h_samp_factor),
+ (JDIMENSION) jround_up((long) compptr->height_in_blocks,
+ (long) compptr->v_samp_factor),
+ (JDIMENSION) access_rows);
+ }
+ coef->pub.consume_data = consume_data;
+ coef->pub.decompress_data = decompress_data;
+ coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ /* We only need a single-MCU buffer. */
+ JBLOCKROW buffer;
+ int i;
+
+ buffer = (JBLOCKROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK));
+ for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) {
+ coef->MCU_buffer[i] = buffer + i;
+ }
+ if (cinfo->lim_Se == 0) /* DC only case: want to bypass later */
+ FMEMZERO((void FAR *) buffer,
+ (size_t) (D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)));
+ coef->pub.consume_data = dummy_consume_data;
+ coef->pub.decompress_data = decompress_onepass;
+ coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */
+ }
+}
diff --git a/jpg/jdcolor.c b/jpg/jdcolor.c
new file mode 100644
index 0000000..83e4d06
--- /dev/null
+++ b/jpg/jdcolor.c
@@ -0,0 +1,512 @@
+/*
+ * jdcolor.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains output colorspace conversion routines.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_deconverter pub; /* public fields */
+
+ /* Private state for YCC->RGB conversion */
+ int * Cr_r_tab; /* => table for Cr to R conversion */
+ int * Cb_b_tab; /* => table for Cb to B conversion */
+ INT32 * Cr_g_tab; /* => table for Cr to G conversion */
+ INT32 * Cb_g_tab; /* => table for Cb to G conversion */
+
+ /* Private state for RGB->Y conversion */
+ INT32 * rgb_y_tab; /* => table for RGB to Y conversion */
+} my_color_deconverter;
+
+typedef my_color_deconverter * my_cconvert_ptr;
+
+
+/**************** YCbCr -> RGB conversion: most common case **************/
+/**************** RGB -> Y conversion: less common case **************/
+
+/*
+ * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
+ * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
+ * The conversion equations to be implemented are therefore
+ *
+ * R = Y + 1.40200 * Cr
+ * G = Y - 0.34414 * Cb - 0.71414 * Cr
+ * B = Y + 1.77200 * Cb
+ *
+ * Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
+ *
+ * where Cb and Cr represent the incoming values less CENTERJSAMPLE.
+ * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
+ *
+ * To avoid floating-point arithmetic, we represent the fractional constants
+ * as integers scaled up by 2^16 (about 4 digits precision); we have to divide
+ * the products by 2^16, with appropriate rounding, to get the correct answer.
+ * Notice that Y, being an integral input, does not contribute any fraction
+ * so it need not participate in the rounding.
+ *
+ * For even more speed, we avoid doing any multiplications in the inner loop
+ * by precalculating the constants times Cb and Cr for all possible values.
+ * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
+ * for 12-bit samples it is still acceptable. It's not very reasonable for
+ * 16-bit samples, but if you want lossless storage you shouldn't be changing
+ * colorspace anyway.
+ * The Cr=>R and Cb=>B values can be rounded to integers in advance; the
+ * values for the G calculation are left scaled up, since we must add them
+ * together before rounding.
+ */
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+/* We allocate one big table for RGB->Y conversion and divide it up into
+ * three parts, instead of doing three alloc_small requests. This lets us
+ * use a single table base address, which can be held in a register in the
+ * inner loops on many machines (more than can hold all three addresses,
+ * anyway).
+ */
+
+#define R_Y_OFF 0 /* offset to R => Y section */
+#define G_Y_OFF (1*(MAXJSAMPLE+1)) /* offset to G => Y section */
+#define B_Y_OFF (2*(MAXJSAMPLE+1)) /* etc. */
+#define TABLE_SIZE (3*(MAXJSAMPLE+1))
+
+
+/*
+ * Initialize tables for YCC->RGB colorspace conversion.
+ */
+
+LOCAL(void)
+build_ycc_rgb_table (j_decompress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ int i;
+ INT32 x;
+ SHIFT_TEMPS
+
+ cconvert->Cr_r_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ cconvert->Cb_b_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ cconvert->Cr_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+ cconvert->Cb_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+
+ for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>R value is nearest int to 1.40200 * x */
+ cconvert->Cr_r_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
+ /* Cb=>B value is nearest int to 1.77200 * x */
+ cconvert->Cb_b_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
+ /* Cr=>G value is scaled-up -0.71414 * x */
+ cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x;
+ /* Cb=>G value is scaled-up -0.34414 * x */
+ /* We also add in ONE_HALF so that need not do it in inner loop */
+ cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
+ }
+}
+
+
+/*
+ * Convert some rows of samples to the output colorspace.
+ *
+ * Note that we change from noninterleaved, one-plane-per-component format
+ * to interleaved-pixel format. The output buffer is therefore three times
+ * as wide as the input buffer.
+ * A starting row offset is provided only for the input buffer. The caller
+ * can easily adjust the passed output_buf value to accommodate any row
+ * offset required on that side.
+ */
+
+METHODDEF(void)
+ycc_rgb_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ y = GETJSAMPLE(inptr0[col]);
+ cb = GETJSAMPLE(inptr1[col]);
+ cr = GETJSAMPLE(inptr2[col]);
+ /* Range-limiting is essential due to noise introduced by DCT losses. */
+ outptr[RGB_RED] = range_limit[y + Crrtab[cr]];
+ outptr[RGB_GREEN] = range_limit[y +
+ ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+ SCALEBITS))];
+ outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
+ outptr += RGB_PIXELSIZE;
+ }
+ }
+}
+
+
+/**************** Cases other than YCbCr -> RGB **************/
+
+
+/*
+ * Initialize for RGB->grayscale colorspace conversion.
+ */
+
+LOCAL(void)
+build_rgb_y_table (j_decompress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ INT32 * rgb_y_tab;
+ INT32 i;
+
+ /* Allocate and fill in the conversion tables. */
+ cconvert->rgb_y_tab = rgb_y_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (TABLE_SIZE * SIZEOF(INT32)));
+
+ for (i = 0; i <= MAXJSAMPLE; i++) {
+ rgb_y_tab[i+R_Y_OFF] = FIX(0.29900) * i;
+ rgb_y_tab[i+G_Y_OFF] = FIX(0.58700) * i;
+ rgb_y_tab[i+B_Y_OFF] = FIX(0.11400) * i + ONE_HALF;
+ }
+}
+
+
+/*
+ * Convert RGB to grayscale.
+ */
+
+METHODDEF(void)
+rgb_gray_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int r, g, b;
+ register INT32 * ctab = cconvert->rgb_y_tab;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ r = GETJSAMPLE(inptr0[col]);
+ g = GETJSAMPLE(inptr1[col]);
+ b = GETJSAMPLE(inptr2[col]);
+ /* Y */
+ outptr[col] = (JSAMPLE)
+ ((ctab[r+R_Y_OFF] + ctab[g+G_Y_OFF] + ctab[b+B_Y_OFF])
+ >> SCALEBITS);
+ }
+ }
+}
+
+
+/*
+ * No colorspace change, but conversion from separate-planes
+ * to interleaved representation.
+ */
+
+METHODDEF(void)
+rgb_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ /* We can dispense with GETJSAMPLE() here */
+ outptr[RGB_RED] = inptr0[col];
+ outptr[RGB_GREEN] = inptr1[col];
+ outptr[RGB_BLUE] = inptr2[col];
+ outptr += RGB_PIXELSIZE;
+ }
+ }
+}
+
+
+/*
+ * Color conversion for no colorspace change: just copy the data,
+ * converting from separate-planes to interleaved representation.
+ */
+
+METHODDEF(void)
+null_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION count;
+ register int num_components = cinfo->num_components;
+ JDIMENSION num_cols = cinfo->output_width;
+ int ci;
+
+ while (--num_rows >= 0) {
+ for (ci = 0; ci < num_components; ci++) {
+ inptr = input_buf[ci][input_row];
+ outptr = output_buf[0] + ci;
+ for (count = num_cols; count > 0; count--) {
+ *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */
+ outptr += num_components;
+ }
+ }
+ input_row++;
+ output_buf++;
+ }
+}
+
+
+/*
+ * Color conversion for grayscale: just copy the data.
+ * This also works for YCbCr -> grayscale conversion, in which
+ * we just copy the Y (luminance) component and ignore chrominance.
+ */
+
+METHODDEF(void)
+grayscale_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0,
+ num_rows, cinfo->output_width);
+}
+
+
+/*
+ * Convert grayscale to RGB: just duplicate the graylevel three times.
+ * This is provided to support applications that don't want to cope
+ * with grayscale as a separate case.
+ */
+
+METHODDEF(void)
+gray_rgb_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+
+ while (--num_rows >= 0) {
+ inptr = input_buf[0][input_row++];
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ /* We can dispense with GETJSAMPLE() here */
+ outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
+ outptr += RGB_PIXELSIZE;
+ }
+ }
+}
+
+
+/*
+ * Adobe-style YCCK->CMYK conversion.
+ * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same
+ * conversion as above, while passing K (black) unchanged.
+ * We assume build_ycc_rgb_table has been called.
+ */
+
+METHODDEF(void)
+ycck_cmyk_convert (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert;
+ register int y, cb, cr;
+ register JSAMPROW outptr;
+ register JSAMPROW inptr0, inptr1, inptr2, inptr3;
+ register JDIMENSION col;
+ JDIMENSION num_cols = cinfo->output_width;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ register int * Crrtab = cconvert->Cr_r_tab;
+ register int * Cbbtab = cconvert->Cb_b_tab;
+ register INT32 * Crgtab = cconvert->Cr_g_tab;
+ register INT32 * Cbgtab = cconvert->Cb_g_tab;
+ SHIFT_TEMPS
+
+ while (--num_rows >= 0) {
+ inptr0 = input_buf[0][input_row];
+ inptr1 = input_buf[1][input_row];
+ inptr2 = input_buf[2][input_row];
+ inptr3 = input_buf[3][input_row];
+ input_row++;
+ outptr = *output_buf++;
+ for (col = 0; col < num_cols; col++) {
+ y = GETJSAMPLE(inptr0[col]);
+ cb = GETJSAMPLE(inptr1[col]);
+ cr = GETJSAMPLE(inptr2[col]);
+ /* Range-limiting is essential due to noise introduced by DCT losses. */
+ outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */
+ outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */
+ ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
+ SCALEBITS)))];
+ outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */
+ /* K passes through unchanged */
+ outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */
+ outptr += 4;
+ }
+ }
+}
+
+
+/*
+ * Empty method for start_pass.
+ */
+
+METHODDEF(void)
+start_pass_dcolor (j_decompress_ptr cinfo)
+{
+ /* no work needed */
+}
+
+
+/*
+ * Module initialization routine for output colorspace conversion.
+ */
+
+GLOBAL(void)
+jinit_color_deconverter (j_decompress_ptr cinfo)
+{
+ my_cconvert_ptr cconvert;
+ int ci;
+
+ cconvert = (my_cconvert_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_color_deconverter));
+ cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert;
+ cconvert->pub.start_pass = start_pass_dcolor;
+
+ /* Make sure num_components agrees with jpeg_color_space */
+ switch (cinfo->jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ if (cinfo->num_components != 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ case JCS_RGB:
+ case JCS_YCbCr:
+ if (cinfo->num_components != 3)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ if (cinfo->num_components != 4)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+
+ default: /* JCS_UNKNOWN can be anything */
+ if (cinfo->num_components < 1)
+ ERREXIT(cinfo, JERR_BAD_J_COLORSPACE);
+ break;
+ }
+
+ /* Set out_color_components and conversion method based on requested space.
+ * Also clear the component_needed flags for any unused components,
+ * so that earlier pipeline stages can avoid useless computation.
+ */
+
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo->out_color_components = 1;
+ if (cinfo->jpeg_color_space == JCS_GRAYSCALE ||
+ cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = grayscale_convert;
+ /* For color->grayscale conversion, only the Y (0) component is needed */
+ for (ci = 1; ci < cinfo->num_components; ci++)
+ cinfo->comp_info[ci].component_needed = FALSE;
+ } else if (cinfo->jpeg_color_space == JCS_RGB) {
+ cconvert->pub.color_convert = rgb_gray_convert;
+ build_rgb_y_table(cinfo);
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_RGB:
+ cinfo->out_color_components = RGB_PIXELSIZE;
+ if (cinfo->jpeg_color_space == JCS_YCbCr) {
+ cconvert->pub.color_convert = ycc_rgb_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_GRAYSCALE) {
+ cconvert->pub.color_convert = gray_rgb_convert;
+ } else if (cinfo->jpeg_color_space == JCS_RGB) {
+ cconvert->pub.color_convert = rgb_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ case JCS_CMYK:
+ cinfo->out_color_components = 4;
+ if (cinfo->jpeg_color_space == JCS_YCCK) {
+ cconvert->pub.color_convert = ycck_cmyk_convert;
+ build_ycc_rgb_table(cinfo);
+ } else if (cinfo->jpeg_color_space == JCS_CMYK) {
+ cconvert->pub.color_convert = null_convert;
+ } else
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+
+ default:
+ /* Permit null conversion to same output space */
+ if (cinfo->out_color_space == cinfo->jpeg_color_space) {
+ cinfo->out_color_components = cinfo->num_components;
+ cconvert->pub.color_convert = null_convert;
+ } else /* unsupported non-null conversion */
+ ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL);
+ break;
+ }
+
+ if (cinfo->quantize_colors)
+ cinfo->output_components = 1; /* single colormapped output component */
+ else
+ cinfo->output_components = cinfo->out_color_components;
+}
diff --git a/jpg/jdct.h b/jpg/jdct.h
new file mode 100644
index 0000000..360dec8
--- /dev/null
+++ b/jpg/jdct.h
@@ -0,0 +1,393 @@
+/*
+ * jdct.h
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This include file contains common declarations for the forward and
+ * inverse DCT modules. These declarations are private to the DCT managers
+ * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms.
+ * The individual DCT algorithms are kept in separate files to ease
+ * machine-dependent tuning (e.g., assembly coding).
+ */
+
+
+/*
+ * A forward DCT routine is given a pointer to an input sample array and
+ * a pointer to a work area of type DCTELEM[]; the DCT is to be performed
+ * in-place in that buffer. Type DCTELEM is int for 8-bit samples, INT32
+ * for 12-bit samples. (NOTE: Floating-point DCT implementations use an
+ * array of type FAST_FLOAT, instead.)
+ * The input data is to be fetched from the sample array starting at a
+ * specified column. (Any row offset needed will be applied to the array
+ * pointer before it is passed to the FDCT code.)
+ * Note that the number of samples fetched by the FDCT routine is
+ * DCT_h_scaled_size * DCT_v_scaled_size.
+ * The DCT outputs are returned scaled up by a factor of 8; they therefore
+ * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This
+ * convention improves accuracy in integer implementations and saves some
+ * work in floating-point ones.
+ * Quantization of the output coefficients is done by jcdctmgr.c.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef int DCTELEM; /* 16 or 32 bits is fine */
+#else
+typedef INT32 DCTELEM; /* must have 32 bits */
+#endif
+
+typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data,
+ JSAMPARRAY sample_data,
+ JDIMENSION start_col));
+typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data,
+ JSAMPARRAY sample_data,
+ JDIMENSION start_col));
+
+
+/*
+ * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer
+ * to an output sample array. The routine must dequantize the input data as
+ * well as perform the IDCT; for dequantization, it uses the multiplier table
+ * pointed to by compptr->dct_table. The output data is to be placed into the
+ * sample array starting at a specified column. (Any row offset needed will
+ * be applied to the array pointer before it is passed to the IDCT code.)
+ * Note that the number of samples emitted by the IDCT routine is
+ * DCT_h_scaled_size * DCT_v_scaled_size.
+ */
+
+/* typedef inverse_DCT_method_ptr is declared in jpegint.h */
+
+/*
+ * Each IDCT routine has its own ideas about the best dct_table element type.
+ */
+
+typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */
+#if BITS_IN_JSAMPLE == 8
+typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */
+#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */
+#else
+typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */
+#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */
+#endif
+typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */
+
+
+/*
+ * Each IDCT routine is responsible for range-limiting its results and
+ * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could
+ * be quite far out of range if the input data is corrupt, so a bulletproof
+ * range-limiting step is required. We use a mask-and-table-lookup method
+ * to do the combined operations quickly. See the comments with
+ * prepare_range_limit_table (in jdmaster.c) for more info.
+ */
+
+#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE)
+
+#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_fdct_islow jFDislow
+#define jpeg_fdct_ifast jFDifast
+#define jpeg_fdct_float jFDfloat
+#define jpeg_fdct_7x7 jFD7x7
+#define jpeg_fdct_6x6 jFD6x6
+#define jpeg_fdct_5x5 jFD5x5
+#define jpeg_fdct_4x4 jFD4x4
+#define jpeg_fdct_3x3 jFD3x3
+#define jpeg_fdct_2x2 jFD2x2
+#define jpeg_fdct_1x1 jFD1x1
+#define jpeg_fdct_9x9 jFD9x9
+#define jpeg_fdct_10x10 jFD10x10
+#define jpeg_fdct_11x11 jFD11x11
+#define jpeg_fdct_12x12 jFD12x12
+#define jpeg_fdct_13x13 jFD13x13
+#define jpeg_fdct_14x14 jFD14x14
+#define jpeg_fdct_15x15 jFD15x15
+#define jpeg_fdct_16x16 jFD16x16
+#define jpeg_fdct_16x8 jFD16x8
+#define jpeg_fdct_14x7 jFD14x7
+#define jpeg_fdct_12x6 jFD12x6
+#define jpeg_fdct_10x5 jFD10x5
+#define jpeg_fdct_8x4 jFD8x4
+#define jpeg_fdct_6x3 jFD6x3
+#define jpeg_fdct_4x2 jFD4x2
+#define jpeg_fdct_2x1 jFD2x1
+#define jpeg_fdct_8x16 jFD8x16
+#define jpeg_fdct_7x14 jFD7x14
+#define jpeg_fdct_6x12 jFD6x12
+#define jpeg_fdct_5x10 jFD5x10
+#define jpeg_fdct_4x8 jFD4x8
+#define jpeg_fdct_3x6 jFD3x6
+#define jpeg_fdct_2x4 jFD2x4
+#define jpeg_fdct_1x2 jFD1x2
+#define jpeg_idct_islow jRDislow
+#define jpeg_idct_ifast jRDifast
+#define jpeg_idct_float jRDfloat
+#define jpeg_idct_7x7 jRD7x7
+#define jpeg_idct_6x6 jRD6x6
+#define jpeg_idct_5x5 jRD5x5
+#define jpeg_idct_4x4 jRD4x4
+#define jpeg_idct_3x3 jRD3x3
+#define jpeg_idct_2x2 jRD2x2
+#define jpeg_idct_1x1 jRD1x1
+#define jpeg_idct_9x9 jRD9x9
+#define jpeg_idct_10x10 jRD10x10
+#define jpeg_idct_11x11 jRD11x11
+#define jpeg_idct_12x12 jRD12x12
+#define jpeg_idct_13x13 jRD13x13
+#define jpeg_idct_14x14 jRD14x14
+#define jpeg_idct_15x15 jRD15x15
+#define jpeg_idct_16x16 jRD16x16
+#define jpeg_idct_16x8 jRD16x8
+#define jpeg_idct_14x7 jRD14x7
+#define jpeg_idct_12x6 jRD12x6
+#define jpeg_idct_10x5 jRD10x5
+#define jpeg_idct_8x4 jRD8x4
+#define jpeg_idct_6x3 jRD6x3
+#define jpeg_idct_4x2 jRD4x2
+#define jpeg_idct_2x1 jRD2x1
+#define jpeg_idct_8x16 jRD8x16
+#define jpeg_idct_7x14 jRD7x14
+#define jpeg_idct_6x12 jRD6x12
+#define jpeg_idct_5x10 jRD5x10
+#define jpeg_idct_4x8 jRD4x8
+#define jpeg_idct_3x6 jRD3x8
+#define jpeg_idct_2x4 jRD2x4
+#define jpeg_idct_1x2 jRD1x2
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+/* Extern declarations for the forward and inverse DCT routines. */
+
+EXTERN(void) jpeg_fdct_islow
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_ifast
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_float
+ JPP((FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_7x7
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x6
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_5x5
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x4
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_3x3
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x2
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_1x1
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_9x9
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_10x10
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_11x11
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_12x12
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_13x13
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_14x14
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_15x15
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_16x16
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_16x8
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_14x7
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_12x6
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_10x5
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_8x4
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x3
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x2
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x1
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_8x16
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_7x14
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_6x12
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_5x10
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_4x8
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_3x6
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_2x4
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+EXTERN(void) jpeg_fdct_1x2
+ JPP((DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col));
+
+EXTERN(void) jpeg_idct_islow
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_ifast
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_float
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_7x7
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x6
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_5x5
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x4
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_3x3
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x2
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_1x1
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_9x9
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_10x10
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_11x11
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_12x12
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_13x13
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_14x14
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_15x15
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_16x16
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_16x8
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_14x7
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_12x6
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_10x5
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_8x4
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x3
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x2
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x1
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_8x16
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_7x14
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_6x12
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_5x10
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_4x8
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_3x6
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_2x4
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+EXTERN(void) jpeg_idct_1x2
+ JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col));
+
+
+/*
+ * Macros for handling fixed-point arithmetic; these are used by many
+ * but not all of the DCT/IDCT modules.
+ *
+ * All values are expected to be of type INT32.
+ * Fractional constants are scaled left by CONST_BITS bits.
+ * CONST_BITS is defined within each module using these macros,
+ * and may differ from one module to the next.
+ */
+
+#define ONE ((INT32) 1)
+#define CONST_SCALE (ONE << CONST_BITS)
+
+/* Convert a positive real constant to an integer scaled by CONST_SCALE.
+ * Caution: some C compilers fail to reduce "FIX(constant)" at compile time,
+ * thus causing a lot of useless floating-point operations at run time.
+ */
+
+#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5))
+
+/* Descale and correctly round an INT32 value that's scaled by N bits.
+ * We assume RIGHT_SHIFT rounds towards minus infinity, so adding
+ * the fudge factor is correct for either sign of X.
+ */
+
+#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n)
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * This macro is used only when the two inputs will actually be no more than
+ * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a
+ * full 32x32 multiply. This provides a useful speedup on many machines.
+ * Unfortunately there is no way to specify a 16x16->32 multiply portably
+ * in C, but some C compilers will do the right thing if you provide the
+ * correct combination of casts.
+ */
+
+#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
+#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const)))
+#endif
+#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */
+#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const)))
+#endif
+
+#ifndef MULTIPLY16C16 /* default definition */
+#define MULTIPLY16C16(var,const) ((var) * (const))
+#endif
+
+/* Same except both inputs are variables. */
+
+#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */
+#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2)))
+#endif
+
+#ifndef MULTIPLY16V16 /* default definition */
+#define MULTIPLY16V16(var1,var2) ((var1) * (var2))
+#endif
diff --git a/jpg/jddctmgr.c b/jpg/jddctmgr.c
new file mode 100644
index 0000000..0ded9d5
--- /dev/null
+++ b/jpg/jddctmgr.c
@@ -0,0 +1,384 @@
+/*
+ * jddctmgr.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2002-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the inverse-DCT management logic.
+ * This code selects a particular IDCT implementation to be used,
+ * and it performs related housekeeping chores. No code in this file
+ * is executed per IDCT step, only during output pass setup.
+ *
+ * Note that the IDCT routines are responsible for performing coefficient
+ * dequantization as well as the IDCT proper. This module sets up the
+ * dequantization multiplier table needed by the IDCT routine.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+
+/*
+ * The decompressor input side (jdinput.c) saves away the appropriate
+ * quantization table for each component at the start of the first scan
+ * involving that component. (This is necessary in order to correctly
+ * decode files that reuse Q-table slots.)
+ * When we are ready to make an output pass, the saved Q-table is converted
+ * to a multiplier table that will actually be used by the IDCT routine.
+ * The multiplier table contents are IDCT-method-dependent. To support
+ * application changes in IDCT method between scans, we can remake the
+ * multiplier tables if necessary.
+ * In buffered-image mode, the first output pass may occur before any data
+ * has been seen for some components, and thus before their Q-tables have
+ * been saved away. To handle this case, multiplier tables are preset
+ * to zeroes; the result of the IDCT will be a neutral gray level.
+ */
+
+
+/* Private subobject for this module */
+
+typedef struct {
+ struct jpeg_inverse_dct pub; /* public fields */
+
+ /* This array contains the IDCT method code that each multiplier table
+ * is currently set up for, or -1 if it's not yet set up.
+ * The actual multiplier tables are pointed to by dct_table in the
+ * per-component comp_info structures.
+ */
+ int cur_method[MAX_COMPONENTS];
+} my_idct_controller;
+
+typedef my_idct_controller * my_idct_ptr;
+
+
+/* Allocated multiplier tables: big enough for any supported variant */
+
+typedef union {
+ ISLOW_MULT_TYPE islow_array[DCTSIZE2];
+#ifdef DCT_IFAST_SUPPORTED
+ IFAST_MULT_TYPE ifast_array[DCTSIZE2];
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ FLOAT_MULT_TYPE float_array[DCTSIZE2];
+#endif
+} multiplier_table;
+
+
+/* The current scaled-IDCT routines require ISLOW-style multiplier tables,
+ * so be sure to compile that code if either ISLOW or SCALING is requested.
+ */
+#ifdef DCT_ISLOW_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#else
+#ifdef IDCT_SCALING_SUPPORTED
+#define PROVIDE_ISLOW_TABLES
+#endif
+#endif
+
+
+/*
+ * Prepare for an output pass.
+ * Here we select the proper IDCT routine for each component and build
+ * a matching multiplier table.
+ */
+
+METHODDEF(void)
+start_pass (j_decompress_ptr cinfo)
+{
+ my_idct_ptr idct = (my_idct_ptr) cinfo->idct;
+ int ci, i;
+ jpeg_component_info *compptr;
+ int method = 0;
+ inverse_DCT_method_ptr method_ptr = NULL;
+ JQUANT_TBL * qtbl;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Select the proper IDCT routine for this component's scaling */
+ switch ((compptr->DCT_h_scaled_size << 8) + compptr->DCT_v_scaled_size) {
+#ifdef IDCT_SCALING_SUPPORTED
+ case ((1 << 8) + 1):
+ method_ptr = jpeg_idct_1x1;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((2 << 8) + 2):
+ method_ptr = jpeg_idct_2x2;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((3 << 8) + 3):
+ method_ptr = jpeg_idct_3x3;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((4 << 8) + 4):
+ method_ptr = jpeg_idct_4x4;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((5 << 8) + 5):
+ method_ptr = jpeg_idct_5x5;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((6 << 8) + 6):
+ method_ptr = jpeg_idct_6x6;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((7 << 8) + 7):
+ method_ptr = jpeg_idct_7x7;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((9 << 8) + 9):
+ method_ptr = jpeg_idct_9x9;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((10 << 8) + 10):
+ method_ptr = jpeg_idct_10x10;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((11 << 8) + 11):
+ method_ptr = jpeg_idct_11x11;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((12 << 8) + 12):
+ method_ptr = jpeg_idct_12x12;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((13 << 8) + 13):
+ method_ptr = jpeg_idct_13x13;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((14 << 8) + 14):
+ method_ptr = jpeg_idct_14x14;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((15 << 8) + 15):
+ method_ptr = jpeg_idct_15x15;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((16 << 8) + 16):
+ method_ptr = jpeg_idct_16x16;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((16 << 8) + 8):
+ method_ptr = jpeg_idct_16x8;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((14 << 8) + 7):
+ method_ptr = jpeg_idct_14x7;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((12 << 8) + 6):
+ method_ptr = jpeg_idct_12x6;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((10 << 8) + 5):
+ method_ptr = jpeg_idct_10x5;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((8 << 8) + 4):
+ method_ptr = jpeg_idct_8x4;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((6 << 8) + 3):
+ method_ptr = jpeg_idct_6x3;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((4 << 8) + 2):
+ method_ptr = jpeg_idct_4x2;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((2 << 8) + 1):
+ method_ptr = jpeg_idct_2x1;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((8 << 8) + 16):
+ method_ptr = jpeg_idct_8x16;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((7 << 8) + 14):
+ method_ptr = jpeg_idct_7x14;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((6 << 8) + 12):
+ method_ptr = jpeg_idct_6x12;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((5 << 8) + 10):
+ method_ptr = jpeg_idct_5x10;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((4 << 8) + 8):
+ method_ptr = jpeg_idct_4x8;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((3 << 8) + 6):
+ method_ptr = jpeg_idct_3x6;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((2 << 8) + 4):
+ method_ptr = jpeg_idct_2x4;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+ case ((1 << 8) + 2):
+ method_ptr = jpeg_idct_1x2;
+ method = JDCT_ISLOW; /* jidctint uses islow-style table */
+ break;
+#endif
+ case ((DCTSIZE << 8) + DCTSIZE):
+ switch (cinfo->dct_method) {
+#ifdef DCT_ISLOW_SUPPORTED
+ case JDCT_ISLOW:
+ method_ptr = jpeg_idct_islow;
+ method = JDCT_ISLOW;
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ method_ptr = jpeg_idct_ifast;
+ method = JDCT_IFAST;
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ method_ptr = jpeg_idct_float;
+ method = JDCT_FLOAT;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ break;
+ default:
+ ERREXIT2(cinfo, JERR_BAD_DCTSIZE,
+ compptr->DCT_h_scaled_size, compptr->DCT_v_scaled_size);
+ break;
+ }
+ idct->pub.inverse_DCT[ci] = method_ptr;
+ /* Create multiplier table from quant table.
+ * However, we can skip this if the component is uninteresting
+ * or if we already built the table. Also, if no quant table
+ * has yet been saved for the component, we leave the
+ * multiplier table all-zero; we'll be reading zeroes from the
+ * coefficient controller's buffer anyway.
+ */
+ if (! compptr->component_needed || idct->cur_method[ci] == method)
+ continue;
+ qtbl = compptr->quant_table;
+ if (qtbl == NULL) /* happens if no data yet for component */
+ continue;
+ idct->cur_method[ci] = method;
+ switch (method) {
+#ifdef PROVIDE_ISLOW_TABLES
+ case JDCT_ISLOW:
+ {
+ /* For LL&M IDCT method, multipliers are equal to raw quantization
+ * coefficients, but are stored as ints to ensure access efficiency.
+ */
+ ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ for (i = 0; i < DCTSIZE2; i++) {
+ ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[i];
+ }
+ }
+ break;
+#endif
+#ifdef DCT_IFAST_SUPPORTED
+ case JDCT_IFAST:
+ {
+ /* For AA&N IDCT method, multipliers are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * For integer operation, the multiplier table is to be scaled by
+ * IFAST_SCALE_BITS.
+ */
+ IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table;
+#define CONST_BITS 14
+ static const INT16 aanscales[DCTSIZE2] = {
+ /* precomputed values scaled up by 14 bits */
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
+ 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
+ 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
+ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
+ 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
+ 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
+ 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
+ };
+ SHIFT_TEMPS
+
+ for (i = 0; i < DCTSIZE2; i++) {
+ ifmtbl[i] = (IFAST_MULT_TYPE)
+ DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[i],
+ (INT32) aanscales[i]),
+ CONST_BITS-IFAST_SCALE_BITS);
+ }
+ }
+ break;
+#endif
+#ifdef DCT_FLOAT_SUPPORTED
+ case JDCT_FLOAT:
+ {
+ /* For float AA&N IDCT method, multipliers are equal to quantization
+ * coefficients scaled by scalefactor[row]*scalefactor[col], where
+ * scalefactor[0] = 1
+ * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
+ * We apply a further scale factor of 1/8.
+ */
+ FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table;
+ int row, col;
+ static const double aanscalefactor[DCTSIZE] = {
+ 1.0, 1.387039845, 1.306562965, 1.175875602,
+ 1.0, 0.785694958, 0.541196100, 0.275899379
+ };
+
+ i = 0;
+ for (row = 0; row < DCTSIZE; row++) {
+ for (col = 0; col < DCTSIZE; col++) {
+ fmtbl[i] = (FLOAT_MULT_TYPE)
+ ((double) qtbl->quantval[i] *
+ aanscalefactor[row] * aanscalefactor[col] * 0.125);
+ i++;
+ }
+ }
+ }
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+ }
+}
+
+
+/*
+ * Initialize IDCT manager.
+ */
+
+GLOBAL(void)
+jinit_inverse_dct (j_decompress_ptr cinfo)
+{
+ my_idct_ptr idct;
+ int ci;
+ jpeg_component_info *compptr;
+
+ idct = (my_idct_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_idct_controller));
+ cinfo->idct = (struct jpeg_inverse_dct *) idct;
+ idct->pub.start_pass = start_pass;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Allocate and pre-zero a multiplier table for each component */
+ compptr->dct_table =
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(multiplier_table));
+ MEMZERO(compptr->dct_table, SIZEOF(multiplier_table));
+ /* Mark multiplier table not yet set up for any method */
+ idct->cur_method[ci] = -1;
+ }
+}
diff --git a/jpg/jdhuff.c b/jpg/jdhuff.c
new file mode 100644
index 0000000..06f92fe
--- /dev/null
+++ b/jpg/jdhuff.c
@@ -0,0 +1,1541 @@
+/*
+ * jdhuff.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2006-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains Huffman entropy decoding routines.
+ * Both sequential and progressive modes are supported in this single module.
+ *
+ * Much of the complexity here has to do with supporting input suspension.
+ * If the data source module demands suspension, we want to be able to back
+ * up to the start of the current MCU. To do this, we copy state variables
+ * into local working storage, and update them back to the permanent
+ * storage only upon successful completion of an MCU.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Derived data constructed for each Huffman table */
+
+#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */
+
+typedef struct {
+ /* Basic tables: (element [0] of each array is unused) */
+ INT32 maxcode[18]; /* largest code of length k (-1 if none) */
+ /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */
+ INT32 valoffset[17]; /* huffval[] offset for codes of length k */
+ /* valoffset[k] = huffval[] index of 1st symbol of code length k, less
+ * the smallest code of length k; so given a code of length k, the
+ * corresponding symbol is huffval[code + valoffset[k]]
+ */
+
+ /* Link to public Huffman table (needed only in jpeg_huff_decode) */
+ JHUFF_TBL *pub;
+
+ /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
+ * the input data stream. If the next Huffman code is no more
+ * than HUFF_LOOKAHEAD bits long, we can obtain its length and
+ * the corresponding symbol directly from these tables.
+ */
+ int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */
+ UINT8 look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */
+} d_derived_tbl;
+
+
+/*
+ * Fetching the next N bits from the input stream is a time-critical operation
+ * for the Huffman decoders. We implement it with a combination of inline
+ * macros and out-of-line subroutines. Note that N (the number of bits
+ * demanded at one time) never exceeds 15 for JPEG use.
+ *
+ * We read source bytes into get_buffer and dole out bits as needed.
+ * If get_buffer already contains enough bits, they are fetched in-line
+ * by the macros CHECK_BIT_BUFFER and GET_BITS. When there aren't enough
+ * bits, jpeg_fill_bit_buffer is called; it will attempt to fill get_buffer
+ * as full as possible (not just to the number of bits needed; this
+ * prefetching reduces the overhead cost of calling jpeg_fill_bit_buffer).
+ * Note that jpeg_fill_bit_buffer may return FALSE to indicate suspension.
+ * On TRUE return, jpeg_fill_bit_buffer guarantees that get_buffer contains
+ * at least the requested number of bits --- dummy zeroes are inserted if
+ * necessary.
+ */
+
+typedef INT32 bit_buf_type; /* type of bit-extraction buffer */
+#define BIT_BUF_SIZE 32 /* size of buffer in bits */
+
+/* If long is > 32 bits on your machine, and shifting/masking longs is
+ * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE
+ * appropriately should be a win. Unfortunately we can't define the size
+ * with something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8)
+ * because not all machines measure sizeof in 8-bit bytes.
+ */
+
+typedef struct { /* Bitreading state saved across MCUs */
+ bit_buf_type get_buffer; /* current bit-extraction buffer */
+ int bits_left; /* # of unused bits in it */
+} bitread_perm_state;
+
+typedef struct { /* Bitreading working state within an MCU */
+ /* Current data source location */
+ /* We need a copy, rather than munging the original, in case of suspension */
+ const JOCTET * next_input_byte; /* => next byte to read from source */
+ size_t bytes_in_buffer; /* # of bytes remaining in source buffer */
+ /* Bit input buffer --- note these values are kept in register variables,
+ * not in this struct, inside the inner loops.
+ */
+ bit_buf_type get_buffer; /* current bit-extraction buffer */
+ int bits_left; /* # of unused bits in it */
+ /* Pointer needed by jpeg_fill_bit_buffer. */
+ j_decompress_ptr cinfo; /* back link to decompress master record */
+} bitread_working_state;
+
+/* Macros to declare and load/save bitread local variables. */
+#define BITREAD_STATE_VARS \
+ register bit_buf_type get_buffer; \
+ register int bits_left; \
+ bitread_working_state br_state
+
+#define BITREAD_LOAD_STATE(cinfop,permstate) \
+ br_state.cinfo = cinfop; \
+ br_state.next_input_byte = cinfop->src->next_input_byte; \
+ br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \
+ get_buffer = permstate.get_buffer; \
+ bits_left = permstate.bits_left;
+
+#define BITREAD_SAVE_STATE(cinfop,permstate) \
+ cinfop->src->next_input_byte = br_state.next_input_byte; \
+ cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \
+ permstate.get_buffer = get_buffer; \
+ permstate.bits_left = bits_left
+
+/*
+ * These macros provide the in-line portion of bit fetching.
+ * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer
+ * before using GET_BITS, PEEK_BITS, or DROP_BITS.
+ * The variables get_buffer and bits_left are assumed to be locals,
+ * but the state struct might not be (jpeg_huff_decode needs this).
+ * CHECK_BIT_BUFFER(state,n,action);
+ * Ensure there are N bits in get_buffer; if suspend, take action.
+ * val = GET_BITS(n);
+ * Fetch next N bits.
+ * val = PEEK_BITS(n);
+ * Fetch next N bits without removing them from the buffer.
+ * DROP_BITS(n);
+ * Discard next N bits.
+ * The value N should be a simple variable, not an expression, because it
+ * is evaluated multiple times.
+ */
+
+#define CHECK_BIT_BUFFER(state,nbits,action) \
+ { if (bits_left < (nbits)) { \
+ if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \
+ { action; } \
+ get_buffer = (state).get_buffer; bits_left = (state).bits_left; } }
+
+#define GET_BITS(nbits) \
+ (((int) (get_buffer >> (bits_left -= (nbits)))) & BIT_MASK(nbits))
+
+#define PEEK_BITS(nbits) \
+ (((int) (get_buffer >> (bits_left - (nbits)))) & BIT_MASK(nbits))
+
+#define DROP_BITS(nbits) \
+ (bits_left -= (nbits))
+
+
+/*
+ * Code for extracting next Huffman-coded symbol from input bit stream.
+ * Again, this is time-critical and we make the main paths be macros.
+ *
+ * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits
+ * without looping. Usually, more than 95% of the Huffman codes will be 8
+ * or fewer bits long. The few overlength codes are handled with a loop,
+ * which need not be inline code.
+ *
+ * Notes about the HUFF_DECODE macro:
+ * 1. Near the end of the data segment, we may fail to get enough bits
+ * for a lookahead. In that case, we do it the hard way.
+ * 2. If the lookahead table contains no entry, the next code must be
+ * more than HUFF_LOOKAHEAD bits long.
+ * 3. jpeg_huff_decode returns -1 if forced to suspend.
+ */
+
+#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \
+{ register int nb, look; \
+ if (bits_left < HUFF_LOOKAHEAD) { \
+ if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \
+ get_buffer = state.get_buffer; bits_left = state.bits_left; \
+ if (bits_left < HUFF_LOOKAHEAD) { \
+ nb = 1; goto slowlabel; \
+ } \
+ } \
+ look = PEEK_BITS(HUFF_LOOKAHEAD); \
+ if ((nb = htbl->look_nbits[look]) != 0) { \
+ DROP_BITS(nb); \
+ result = htbl->look_sym[look]; \
+ } else { \
+ nb = HUFF_LOOKAHEAD+1; \
+slowlabel: \
+ if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \
+ { failaction; } \
+ get_buffer = state.get_buffer; bits_left = state.bits_left; \
+ } \
+}
+
+
+/*
+ * Expanded entropy decoder object for Huffman decoding.
+ *
+ * The savable_state subrecord contains fields that change within an MCU,
+ * but must not be updated permanently until we complete the MCU.
+ */
+
+typedef struct {
+ unsigned int EOBRUN; /* remaining EOBs in EOBRUN */
+ int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */
+} savable_state;
+
+/* This macro is to work around compilers with missing or broken
+ * structure assignment. You'll need to fix this code if you have
+ * such a compiler and you change MAX_COMPS_IN_SCAN.
+ */
+
+#ifndef NO_STRUCT_ASSIGN
+#define ASSIGN_STATE(dest,src) ((dest) = (src))
+#else
+#if MAX_COMPS_IN_SCAN == 4
+#define ASSIGN_STATE(dest,src) \
+ ((dest).EOBRUN = (src).EOBRUN, \
+ (dest).last_dc_val[0] = (src).last_dc_val[0], \
+ (dest).last_dc_val[1] = (src).last_dc_val[1], \
+ (dest).last_dc_val[2] = (src).last_dc_val[2], \
+ (dest).last_dc_val[3] = (src).last_dc_val[3])
+#endif
+#endif
+
+
+typedef struct {
+ struct jpeg_entropy_decoder pub; /* public fields */
+
+ /* These fields are loaded into local variables at start of each MCU.
+ * In case of suspension, we exit WITHOUT updating them.
+ */
+ bitread_perm_state bitstate; /* Bit buffer at start of MCU */
+ savable_state saved; /* Other state at start of MCU */
+
+ /* These fields are NOT loaded into local working state. */
+ boolean insufficient_data; /* set TRUE after emitting warning */
+ unsigned int restarts_to_go; /* MCUs left in this restart interval */
+
+ /* Following two fields used only in progressive mode */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl * derived_tbls[NUM_HUFF_TBLS];
+
+ d_derived_tbl * ac_derived_tbl; /* active table during an AC scan */
+
+ /* Following fields used only in sequential mode */
+
+ /* Pointers to derived tables (these workspaces have image lifespan) */
+ d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS];
+ d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS];
+
+ /* Precalculated info set up by start_pass for use in decode_mcu: */
+
+ /* Pointers to derived tables to be used for each block within an MCU */
+ d_derived_tbl * dc_cur_tbls[D_MAX_BLOCKS_IN_MCU];
+ d_derived_tbl * ac_cur_tbls[D_MAX_BLOCKS_IN_MCU];
+ /* Whether we care about the DC and AC coefficient values for each block */
+ int coef_limit[D_MAX_BLOCKS_IN_MCU];
+} huff_entropy_decoder;
+
+typedef huff_entropy_decoder * huff_entropy_ptr;
+
+
+static const int jpeg_zigzag_order[8][8] = {
+ { 0, 1, 5, 6, 14, 15, 27, 28 },
+ { 2, 4, 7, 13, 16, 26, 29, 42 },
+ { 3, 8, 12, 17, 25, 30, 41, 43 },
+ { 9, 11, 18, 24, 31, 40, 44, 53 },
+ { 10, 19, 23, 32, 39, 45, 52, 54 },
+ { 20, 22, 33, 38, 46, 51, 55, 60 },
+ { 21, 34, 37, 47, 50, 56, 59, 61 },
+ { 35, 36, 48, 49, 57, 58, 62, 63 }
+};
+
+static const int jpeg_zigzag_order7[7][7] = {
+ { 0, 1, 5, 6, 14, 15, 27 },
+ { 2, 4, 7, 13, 16, 26, 28 },
+ { 3, 8, 12, 17, 25, 29, 38 },
+ { 9, 11, 18, 24, 30, 37, 39 },
+ { 10, 19, 23, 31, 36, 40, 45 },
+ { 20, 22, 32, 35, 41, 44, 46 },
+ { 21, 33, 34, 42, 43, 47, 48 }
+};
+
+static const int jpeg_zigzag_order6[6][6] = {
+ { 0, 1, 5, 6, 14, 15 },
+ { 2, 4, 7, 13, 16, 25 },
+ { 3, 8, 12, 17, 24, 26 },
+ { 9, 11, 18, 23, 27, 32 },
+ { 10, 19, 22, 28, 31, 33 },
+ { 20, 21, 29, 30, 34, 35 }
+};
+
+static const int jpeg_zigzag_order5[5][5] = {
+ { 0, 1, 5, 6, 14 },
+ { 2, 4, 7, 13, 15 },
+ { 3, 8, 12, 16, 21 },
+ { 9, 11, 17, 20, 22 },
+ { 10, 18, 19, 23, 24 }
+};
+
+static const int jpeg_zigzag_order4[4][4] = {
+ { 0, 1, 5, 6 },
+ { 2, 4, 7, 12 },
+ { 3, 8, 11, 13 },
+ { 9, 10, 14, 15 }
+};
+
+static const int jpeg_zigzag_order3[3][3] = {
+ { 0, 1, 5 },
+ { 2, 4, 6 },
+ { 3, 7, 8 }
+};
+
+static const int jpeg_zigzag_order2[2][2] = {
+ { 0, 1 },
+ { 2, 3 }
+};
+
+
+/*
+ * Compute the derived values for a Huffman table.
+ * This routine also performs some validation checks on the table.
+ */
+
+LOCAL(void)
+jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, boolean isDC, int tblno,
+ d_derived_tbl ** pdtbl)
+{
+ JHUFF_TBL *htbl;
+ d_derived_tbl *dtbl;
+ int p, i, l, si, numsymbols;
+ int lookbits, ctr;
+ char huffsize[257];
+ unsigned int huffcode[257];
+ unsigned int code;
+
+ /* Note that huffsize[] and huffcode[] are filled in code-length order,
+ * paralleling the order of the symbols themselves in htbl->huffval[].
+ */
+
+ /* Find the input Huffman table */
+ if (tblno < 0 || tblno >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+ htbl =
+ isDC ? cinfo->dc_huff_tbl_ptrs[tblno] : cinfo->ac_huff_tbl_ptrs[tblno];
+ if (htbl == NULL)
+ ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, tblno);
+
+ /* Allocate a workspace if we haven't already done so. */
+ if (*pdtbl == NULL)
+ *pdtbl = (d_derived_tbl *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(d_derived_tbl));
+ dtbl = *pdtbl;
+ dtbl->pub = htbl; /* fill in back link */
+
+ /* Figure C.1: make table of Huffman code length for each symbol */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ i = (int) htbl->bits[l];
+ if (i < 0 || p + i > 256) /* protect against table overrun */
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ while (i--)
+ huffsize[p++] = (char) l;
+ }
+ huffsize[p] = 0;
+ numsymbols = p;
+
+ /* Figure C.2: generate the codes themselves */
+ /* We also validate that the counts represent a legal Huffman code tree. */
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+ while (huffsize[p]) {
+ while (((int) huffsize[p]) == si) {
+ huffcode[p++] = code;
+ code++;
+ }
+ /* code is now 1 more than the last code used for codelength si; but
+ * it must still fit in si bits, since no code is allowed to be all ones.
+ */
+ if (((INT32) code) >= (((INT32) 1) << si))
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ code <<= 1;
+ si++;
+ }
+
+ /* Figure F.15: generate decoding tables for bit-sequential decoding */
+
+ p = 0;
+ for (l = 1; l <= 16; l++) {
+ if (htbl->bits[l]) {
+ /* valoffset[l] = huffval[] index of 1st symbol of code length l,
+ * minus the minimum code of length l
+ */
+ dtbl->valoffset[l] = (INT32) p - (INT32) huffcode[p];
+ p += htbl->bits[l];
+ dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */
+ } else {
+ dtbl->maxcode[l] = -1; /* -1 if no codes of this length */
+ }
+ }
+ dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */
+
+ /* Compute lookahead tables to speed up decoding.
+ * First we set all the table entries to 0, indicating "too long";
+ * then we iterate through the Huffman codes that are short enough and
+ * fill in all the entries that correspond to bit sequences starting
+ * with that code.
+ */
+
+ MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits));
+
+ p = 0;
+ for (l = 1; l <= HUFF_LOOKAHEAD; l++) {
+ for (i = 1; i <= (int) htbl->bits[l]; i++, p++) {
+ /* l = current code's length, p = its index in huffcode[] & huffval[]. */
+ /* Generate left-justified code followed by all possible bit sequences */
+ lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);
+ for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {
+ dtbl->look_nbits[lookbits] = l;
+ dtbl->look_sym[lookbits] = htbl->huffval[p];
+ lookbits++;
+ }
+ }
+ }
+
+ /* Validate symbols as being reasonable.
+ * For AC tables, we make no check, but accept all byte values 0..255.
+ * For DC tables, we require the symbols to be in range 0..15.
+ * (Tighter bounds could be applied depending on the data depth and mode,
+ * but this is sufficient to ensure safe decoding.)
+ */
+ if (isDC) {
+ for (i = 0; i < numsymbols; i++) {
+ int sym = htbl->huffval[i];
+ if (sym < 0 || sym > 15)
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+ }
+ }
+}
+
+
+/*
+ * Out-of-line code for bit fetching.
+ * Note: current values of get_buffer and bits_left are passed as parameters,
+ * but are returned in the corresponding fields of the state struct.
+ *
+ * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
+ * of get_buffer to be used. (On machines with wider words, an even larger
+ * buffer could be used.) However, on some machines 32-bit shifts are
+ * quite slow and take time proportional to the number of places shifted.
+ * (This is true with most PC compilers, for instance.) In this case it may
+ * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the
+ * average shift distance at the cost of more calls to jpeg_fill_bit_buffer.
+ */
+
+#ifdef SLOW_SHIFT_32
+#define MIN_GET_BITS 15 /* minimum allowable value */
+#else
+#define MIN_GET_BITS (BIT_BUF_SIZE-7)
+#endif
+
+
+LOCAL(boolean)
+jpeg_fill_bit_buffer (bitread_working_state * state,
+ register bit_buf_type get_buffer, register int bits_left,
+ int nbits)
+/* Load up the bit buffer to a depth of at least nbits */
+{
+ /* Copy heavily used state fields into locals (hopefully registers) */
+ register const JOCTET * next_input_byte = state->next_input_byte;
+ register size_t bytes_in_buffer = state->bytes_in_buffer;
+ j_decompress_ptr cinfo = state->cinfo;
+
+ /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
+ /* (It is assumed that no request will be for more than that many bits.) */
+ /* We fail to do so only if we hit a marker or are forced to suspend. */
+
+ if (cinfo->unread_marker == 0) { /* cannot advance past a marker */
+ while (bits_left < MIN_GET_BITS) {
+ register int c;
+
+ /* Attempt to read a byte */
+ if (bytes_in_buffer == 0) {
+ if (! (*cinfo->src->fill_input_buffer) (cinfo))
+ return FALSE;
+ next_input_byte = cinfo->src->next_input_byte;
+ bytes_in_buffer = cinfo->src->bytes_in_buffer;
+ }
+ bytes_in_buffer--;
+ c = GETJOCTET(*next_input_byte++);
+
+ /* If it's 0xFF, check and discard stuffed zero byte */
+ if (c == 0xFF) {
+ /* Loop here to discard any padding FF's on terminating marker,
+ * so that we can save a valid unread_marker value. NOTE: we will
+ * accept multiple FF's followed by a 0 as meaning a single FF data
+ * byte. This data pattern is not valid according to the standard.
+ */
+ do {
+ if (bytes_in_buffer == 0) {
+ if (! (*cinfo->src->fill_input_buffer) (cinfo))
+ return FALSE;
+ next_input_byte = cinfo->src->next_input_byte;
+ bytes_in_buffer = cinfo->src->bytes_in_buffer;
+ }
+ bytes_in_buffer--;
+ c = GETJOCTET(*next_input_byte++);
+ } while (c == 0xFF);
+
+ if (c == 0) {
+ /* Found FF/00, which represents an FF data byte */
+ c = 0xFF;
+ } else {
+ /* Oops, it's actually a marker indicating end of compressed data.
+ * Save the marker code for later use.
+ * Fine point: it might appear that we should save the marker into
+ * bitread working state, not straight into permanent state. But
+ * once we have hit a marker, we cannot need to suspend within the
+ * current MCU, because we will read no more bytes from the data
+ * source. So it is OK to update permanent state right away.
+ */
+ cinfo->unread_marker = c;
+ /* See if we need to insert some fake zero bits. */
+ goto no_more_bytes;
+ }
+ }
+
+ /* OK, load c into get_buffer */
+ get_buffer = (get_buffer << 8) | c;
+ bits_left += 8;
+ } /* end while */
+ } else {
+ no_more_bytes:
+ /* We get here if we've read the marker that terminates the compressed
+ * data segment. There should be enough bits in the buffer register
+ * to satisfy the request; if so, no problem.
+ */
+ if (nbits > bits_left) {
+ /* Uh-oh. Report corrupted data to user and stuff zeroes into
+ * the data stream, so that we can produce some kind of image.
+ * We use a nonvolatile flag to ensure that only one warning message
+ * appears per data segment.
+ */
+ if (! ((huff_entropy_ptr) cinfo->entropy)->insufficient_data) {
+ WARNMS(cinfo, JWRN_HIT_MARKER);
+ ((huff_entropy_ptr) cinfo->entropy)->insufficient_data = TRUE;
+ }
+ /* Fill the buffer with zero bits */
+ get_buffer <<= MIN_GET_BITS - bits_left;
+ bits_left = MIN_GET_BITS;
+ }
+ }
+
+ /* Unload the local registers */
+ state->next_input_byte = next_input_byte;
+ state->bytes_in_buffer = bytes_in_buffer;
+ state->get_buffer = get_buffer;
+ state->bits_left = bits_left;
+
+ return TRUE;
+}
+
+
+/*
+ * Figure F.12: extend sign bit.
+ * On some machines, a shift and sub will be faster than a table lookup.
+ */
+
+#ifdef AVOID_TABLES
+
+#define BIT_MASK(nbits) ((1<<(nbits))-1)
+#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) - ((1<<(s))-1) : (x))
+
+#else
+
+#define BIT_MASK(nbits) bmask[nbits]
+#define HUFF_EXTEND(x,s) ((x) <= bmask[(s) - 1] ? (x) - bmask[s] : (x))
+
+static const int bmask[16] = /* bmask[n] is mask for n rightmost bits */
+ { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
+ 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF };
+
+#endif /* AVOID_TABLES */
+
+
+/*
+ * Out-of-line code for Huffman code decoding.
+ */
+
+LOCAL(int)
+jpeg_huff_decode (bitread_working_state * state,
+ register bit_buf_type get_buffer, register int bits_left,
+ d_derived_tbl * htbl, int min_bits)
+{
+ register int l = min_bits;
+ register INT32 code;
+
+ /* HUFF_DECODE has determined that the code is at least min_bits */
+ /* bits long, so fetch that many bits in one swoop. */
+
+ CHECK_BIT_BUFFER(*state, l, return -1);
+ code = GET_BITS(l);
+
+ /* Collect the rest of the Huffman code one bit at a time. */
+ /* This is per Figure F.16 in the JPEG spec. */
+
+ while (code > htbl->maxcode[l]) {
+ code <<= 1;
+ CHECK_BIT_BUFFER(*state, 1, return -1);
+ code |= GET_BITS(1);
+ l++;
+ }
+
+ /* Unload the local registers */
+ state->get_buffer = get_buffer;
+ state->bits_left = bits_left;
+
+ /* With garbage input we may reach the sentinel value l = 17. */
+
+ if (l > 16) {
+ WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE);
+ return 0; /* fake a zero as the safest result */
+ }
+
+ return htbl->pub->huffval[ (int) (code + htbl->valoffset[l]) ];
+}
+
+
+/*
+ * Check for a restart marker & resynchronize decoder.
+ * Returns FALSE if must suspend.
+ */
+
+LOCAL(boolean)
+process_restart (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci;
+
+ /* Throw away any unused bits remaining in bit buffer; */
+ /* include any full bytes in next_marker's count of discarded bytes */
+ cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8;
+ entropy->bitstate.bits_left = 0;
+
+ /* Advance past the RSTn marker */
+ if (! (*cinfo->marker->read_restart_marker) (cinfo))
+ return FALSE;
+
+ /* Re-initialize DC predictions to 0 */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++)
+ entropy->saved.last_dc_val[ci] = 0;
+ /* Re-init EOB run count, too */
+ entropy->saved.EOBRUN = 0;
+
+ /* Reset restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+
+ /* Reset out-of-data flag, unless read_restart_marker left us smack up
+ * against a marker. In that case we will end up treating the next data
+ * segment as empty, and we can avoid producing bogus output pixels by
+ * leaving the flag set.
+ */
+ if (cinfo->unread_marker == 0)
+ entropy->insufficient_data = FALSE;
+
+ return TRUE;
+}
+
+
+/*
+ * Huffman MCU decoding.
+ * Each of these routines decodes and returns one MCU's worth of
+ * Huffman-compressed coefficients.
+ * The coefficients are reordered from zigzag order into natural array order,
+ * but are not dequantized.
+ *
+ * The i'th block of the MCU is stored into the block pointed to by
+ * MCU_data[i]. WE ASSUME THIS AREA IS INITIALLY ZEROED BY THE CALLER.
+ * (Wholesale zeroing is usually a little faster than retail...)
+ *
+ * We return FALSE if data source requested suspension. In that case no
+ * changes have been made to permanent state. (Exception: some output
+ * coefficients may already have been assigned. This is harmless for
+ * spectral selection, since we'll just re-assign them on the next call.
+ * Successive approximation AC refinement has to be more careful, however.)
+ */
+
+/*
+ * MCU decoding for DC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int Al = cinfo->Al;
+ register int s, r;
+ int blkn, ci;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ savable_state state;
+ d_derived_tbl * tbl;
+ jpeg_component_info * compptr;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->insufficient_data) {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ tbl = entropy->derived_tbls[compptr->dc_tbl_no];
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ HUFF_DECODE(s, br_state, tbl, return FALSE, label1);
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+
+ /* Convert DC difference to actual value, update last_dc_val */
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Scale and output the coefficient (assumes jpeg_natural_order[0]=0) */
+ (*block)[0] = (JCOEF) (s << Al);
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC initial scan (either spectral selection,
+ * or first pass of successive approximation).
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_first (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int s, k, r;
+ unsigned int EOBRUN;
+ int Se, Al;
+ const int * natural_order;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+ d_derived_tbl * tbl;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->insufficient_data) {
+
+ Se = cinfo->Se;
+ Al = cinfo->Al;
+ natural_order = cinfo->natural_order;
+
+ /* Load up working state.
+ * We can avoid loading/saving bitread state if in an EOB run.
+ */
+ EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
+
+ /* There is always only one block per MCU */
+
+ if (EOBRUN > 0) /* if it's a band of zeroes... */
+ EOBRUN--; /* ...process it now (we do nothing) */
+ else {
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ block = MCU_data[0];
+ tbl = entropy->ac_derived_tbl;
+
+ for (k = cinfo->Ss; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, tbl, return FALSE, label2);
+ r = s >> 4;
+ s &= 15;
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Scale and output coefficient in natural (dezigzagged) order */
+ (*block)[natural_order[k]] = (JCOEF) (s << Al);
+ } else {
+ if (r == 15) { /* ZRL */
+ k += 15; /* skip 15 zeroes in band */
+ } else { /* EOBr, run length is 2^r + appended bits */
+ EOBRUN = 1 << r;
+ if (r) { /* EOBr, r > 0 */
+ CHECK_BIT_BUFFER(br_state, r, return FALSE);
+ r = GET_BITS(r);
+ EOBRUN += r;
+ }
+ EOBRUN--; /* this band is processed at this moment */
+ break; /* force end-of-band */
+ }
+ }
+ }
+
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ }
+
+ /* Completed MCU, so update state */
+ entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for DC successive approximation refinement scan.
+ * Note: we assume such scans can be multi-component, although the spec
+ * is not very clear on the point.
+ */
+
+METHODDEF(boolean)
+decode_mcu_DC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ int blkn;
+ JBLOCKROW block;
+ BITREAD_STATE_VARS;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* Not worth the cycles to check insufficient_data here,
+ * since we will not change the data anyway if we read zeroes.
+ */
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ block = MCU_data[blkn];
+
+ /* Encoded data is simply the next bit of the two's-complement DC value */
+ CHECK_BIT_BUFFER(br_state, 1, return FALSE);
+ if (GET_BITS(1))
+ (*block)[0] |= p1;
+ /* Note: since we use |=, repeating the assignment later is safe */
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * MCU decoding for AC successive approximation refinement scan.
+ */
+
+METHODDEF(boolean)
+decode_mcu_AC_refine (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ register int s, k, r;
+ unsigned int EOBRUN;
+ int Se, p1, m1;
+ const int * natural_order;
+ JBLOCKROW block;
+ JCOEFPTR thiscoef;
+ BITREAD_STATE_VARS;
+ d_derived_tbl * tbl;
+ int num_newnz;
+ int newnz_pos[DCTSIZE2];
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, don't modify the MCU.
+ */
+ if (! entropy->insufficient_data) {
+
+ Se = cinfo->Se;
+ p1 = 1 << cinfo->Al; /* 1 in the bit position being coded */
+ m1 = (-1) << cinfo->Al; /* -1 in the bit position being coded */
+ natural_order = cinfo->natural_order;
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ EOBRUN = entropy->saved.EOBRUN; /* only part of saved state we need */
+
+ /* There is always only one block per MCU */
+ block = MCU_data[0];
+ tbl = entropy->ac_derived_tbl;
+
+ /* If we are forced to suspend, we must undo the assignments to any newly
+ * nonzero coefficients in the block, because otherwise we'd get confused
+ * next time about which coefficients were already nonzero.
+ * But we need not undo addition of bits to already-nonzero coefficients;
+ * instead, we can test the current bit to see if we already did it.
+ */
+ num_newnz = 0;
+
+ /* initialize coefficient loop counter to start of band */
+ k = cinfo->Ss;
+
+ if (EOBRUN == 0) {
+ for (; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, tbl, goto undoit, label3);
+ r = s >> 4;
+ s &= 15;
+ if (s) {
+ if (s != 1) /* size of new coef should always be 1 */
+ WARNMS(cinfo, JWRN_HUFF_BAD_CODE);
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1))
+ s = p1; /* newly nonzero coef is positive */
+ else
+ s = m1; /* newly nonzero coef is negative */
+ } else {
+ if (r != 15) {
+ EOBRUN = 1 << r; /* EOBr, run length is 2^r + appended bits */
+ if (r) {
+ CHECK_BIT_BUFFER(br_state, r, goto undoit);
+ r = GET_BITS(r);
+ EOBRUN += r;
+ }
+ break; /* rest of block is handled by EOB logic */
+ }
+ /* note s = 0 for processing ZRL */
+ }
+ /* Advance over already-nonzero coefs and r still-zero coefs,
+ * appending correction bits to the nonzeroes. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ do {
+ thiscoef = *block + natural_order[k];
+ if (*thiscoef != 0) {
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1)) {
+ if ((*thiscoef & p1) == 0) { /* do nothing if already set it */
+ if (*thiscoef >= 0)
+ *thiscoef += p1;
+ else
+ *thiscoef += m1;
+ }
+ }
+ } else {
+ if (--r < 0)
+ break; /* reached target zero coefficient */
+ }
+ k++;
+ } while (k <= Se);
+ if (s) {
+ int pos = natural_order[k];
+ /* Output newly nonzero coefficient */
+ (*block)[pos] = (JCOEF) s;
+ /* Remember its position in case we have to suspend */
+ newnz_pos[num_newnz++] = pos;
+ }
+ }
+ }
+
+ if (EOBRUN > 0) {
+ /* Scan any remaining coefficient positions after the end-of-band
+ * (the last newly nonzero coefficient, if any). Append a correction
+ * bit to each already-nonzero coefficient. A correction bit is 1
+ * if the absolute value of the coefficient must be increased.
+ */
+ for (; k <= Se; k++) {
+ thiscoef = *block + natural_order[k];
+ if (*thiscoef != 0) {
+ CHECK_BIT_BUFFER(br_state, 1, goto undoit);
+ if (GET_BITS(1)) {
+ if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */
+ if (*thiscoef >= 0)
+ *thiscoef += p1;
+ else
+ *thiscoef += m1;
+ }
+ }
+ }
+ }
+ /* Count one block completed in EOB run */
+ EOBRUN--;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ entropy->saved.EOBRUN = EOBRUN; /* only part of saved state we need */
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+
+undoit:
+ /* Re-zero any output coefficients that we made newly nonzero */
+ while (num_newnz > 0)
+ (*block)[newnz_pos[--num_newnz]] = 0;
+
+ return FALSE;
+}
+
+
+/*
+ * Decode one MCU's worth of Huffman-compressed coefficients,
+ * partial blocks.
+ */
+
+METHODDEF(boolean)
+decode_mcu_sub (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ const int * natural_order;
+ int Se, blkn;
+ BITREAD_STATE_VARS;
+ savable_state state;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->insufficient_data) {
+
+ natural_order = cinfo->natural_order;
+ Se = cinfo->lim_Se;
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ JBLOCKROW block = MCU_data[blkn];
+ d_derived_tbl * htbl;
+ register int s, k, r;
+ int coef_limit, ci;
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ htbl = entropy->dc_cur_tbls[blkn];
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label1);
+
+ htbl = entropy->ac_cur_tbls[blkn];
+ k = 1;
+ coef_limit = entropy->coef_limit[blkn];
+ if (coef_limit) {
+ /* Convert DC difference to actual value, update last_dc_val */
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+ ci = cinfo->MCU_membership[blkn];
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Output the DC coefficient */
+ (*block)[0] = (JCOEF) s;
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* Since zeroes are skipped, output area must be cleared beforehand */
+ for (; k < coef_limit; k++) {
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label2);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Output coefficient in natural (dezigzagged) order.
+ * Note: the extra entries in natural_order[] will save us
+ * if k > Se, which could happen if the data is corrupted.
+ */
+ (*block)[natural_order[k]] = (JCOEF) s;
+ } else {
+ if (r != 15)
+ goto EndOfBlock;
+ k += 15;
+ }
+ }
+ } else {
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ }
+ }
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* In this path we just discard the values */
+ for (; k <= Se; k++) {
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label3);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+
+ EndOfBlock: ;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * Decode one MCU's worth of Huffman-compressed coefficients,
+ * full-size blocks.
+ */
+
+METHODDEF(boolean)
+decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int blkn;
+ BITREAD_STATE_VARS;
+ savable_state state;
+
+ /* Process restart marker if needed; may have to suspend */
+ if (cinfo->restart_interval) {
+ if (entropy->restarts_to_go == 0)
+ if (! process_restart(cinfo))
+ return FALSE;
+ }
+
+ /* If we've run out of data, just leave the MCU set to zeroes.
+ * This way, we return uniform gray for the remainder of the segment.
+ */
+ if (! entropy->insufficient_data) {
+
+ /* Load up working state */
+ BITREAD_LOAD_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(state, entropy->saved);
+
+ /* Outer loop handles each block in the MCU */
+
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ JBLOCKROW block = MCU_data[blkn];
+ d_derived_tbl * htbl;
+ register int s, k, r;
+ int coef_limit, ci;
+
+ /* Decode a single block's worth of coefficients */
+
+ /* Section F.2.2.1: decode the DC coefficient difference */
+ htbl = entropy->dc_cur_tbls[blkn];
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label1);
+
+ htbl = entropy->ac_cur_tbls[blkn];
+ k = 1;
+ coef_limit = entropy->coef_limit[blkn];
+ if (coef_limit) {
+ /* Convert DC difference to actual value, update last_dc_val */
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ }
+ ci = cinfo->MCU_membership[blkn];
+ s += state.last_dc_val[ci];
+ state.last_dc_val[ci] = s;
+ /* Output the DC coefficient */
+ (*block)[0] = (JCOEF) s;
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* Since zeroes are skipped, output area must be cleared beforehand */
+ for (; k < coef_limit; k++) {
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label2);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ r = GET_BITS(s);
+ s = HUFF_EXTEND(r, s);
+ /* Output coefficient in natural (dezigzagged) order.
+ * Note: the extra entries in jpeg_natural_order[] will save us
+ * if k >= DCTSIZE2, which could happen if the data is corrupted.
+ */
+ (*block)[jpeg_natural_order[k]] = (JCOEF) s;
+ } else {
+ if (r != 15)
+ goto EndOfBlock;
+ k += 15;
+ }
+ }
+ } else {
+ if (s) {
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ }
+ }
+
+ /* Section F.2.2.2: decode the AC coefficients */
+ /* In this path we just discard the values */
+ for (; k < DCTSIZE2; k++) {
+ HUFF_DECODE(s, br_state, htbl, return FALSE, label3);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s) {
+ k += r;
+ CHECK_BIT_BUFFER(br_state, s, return FALSE);
+ DROP_BITS(s);
+ } else {
+ if (r != 15)
+ break;
+ k += 15;
+ }
+ }
+
+ EndOfBlock: ;
+ }
+
+ /* Completed MCU, so update state */
+ BITREAD_SAVE_STATE(cinfo,entropy->bitstate);
+ ASSIGN_STATE(entropy->saved, state);
+ }
+
+ /* Account for restart interval (no-op if not using restarts) */
+ entropy->restarts_to_go--;
+
+ return TRUE;
+}
+
+
+/*
+ * Initialize for a Huffman-compressed scan.
+ */
+
+METHODDEF(void)
+start_pass_huff_decoder (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy;
+ int ci, blkn, tbl, i;
+ jpeg_component_info * compptr;
+
+ if (cinfo->progressive_mode) {
+ /* Validate progressive scan parameters */
+ if (cinfo->Ss == 0) {
+ if (cinfo->Se != 0)
+ goto bad;
+ } else {
+ /* need not check Ss/Se < 0 since they came from unsigned bytes */
+ if (cinfo->Se < cinfo->Ss || cinfo->Se > cinfo->lim_Se)
+ goto bad;
+ /* AC scans may have only one component */
+ if (cinfo->comps_in_scan != 1)
+ goto bad;
+ }
+ if (cinfo->Ah != 0) {
+ /* Successive approximation refinement scan: must have Al = Ah-1. */
+ if (cinfo->Ah-1 != cinfo->Al)
+ goto bad;
+ }
+ if (cinfo->Al > 13) { /* need not check for < 0 */
+ /* Arguably the maximum Al value should be less than 13 for 8-bit precision,
+ * but the spec doesn't say so, and we try to be liberal about what we
+ * accept. Note: large Al values could result in out-of-range DC
+ * coefficients during early scans, leading to bizarre displays due to
+ * overflows in the IDCT math. But we won't crash.
+ */
+ bad:
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+ }
+ /* Update progression status, and verify that scan order is legal.
+ * Note that inter-scan inconsistencies are treated as warnings
+ * not fatal errors ... not clear if this is right way to behave.
+ */
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ int coefi, cindex = cinfo->cur_comp_info[ci]->component_index;
+ int *coef_bit_ptr = & cinfo->coef_bits[cindex][0];
+ if (cinfo->Ss && coef_bit_ptr[0] < 0) /* AC without prior DC scan */
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, 0);
+ for (coefi = cinfo->Ss; coefi <= cinfo->Se; coefi++) {
+ int expected = (coef_bit_ptr[coefi] < 0) ? 0 : coef_bit_ptr[coefi];
+ if (cinfo->Ah != expected)
+ WARNMS2(cinfo, JWRN_BOGUS_PROGRESSION, cindex, coefi);
+ coef_bit_ptr[coefi] = cinfo->Al;
+ }
+ }
+
+ /* Select MCU decoding routine */
+ if (cinfo->Ah == 0) {
+ if (cinfo->Ss == 0)
+ entropy->pub.decode_mcu = decode_mcu_DC_first;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_first;
+ } else {
+ if (cinfo->Ss == 0)
+ entropy->pub.decode_mcu = decode_mcu_DC_refine;
+ else
+ entropy->pub.decode_mcu = decode_mcu_AC_refine;
+ }
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Make sure requested tables are present, and compute derived tables.
+ * We may build same derived table more than once, but it's not expensive.
+ */
+ if (cinfo->Ss == 0) {
+ if (cinfo->Ah == 0) { /* DC refinement needs no table */
+ tbl = compptr->dc_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
+ & entropy->derived_tbls[tbl]);
+ }
+ } else {
+ tbl = compptr->ac_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
+ & entropy->derived_tbls[tbl]);
+ /* remember the single active table */
+ entropy->ac_derived_tbl = entropy->derived_tbls[tbl];
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+
+ /* Initialize private state variables */
+ entropy->saved.EOBRUN = 0;
+ } else {
+ /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG.
+ * This ought to be an error condition, but we make it a warning because
+ * there are some baseline files out there with all zeroes in these bytes.
+ */
+ if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 ||
+ ((cinfo->is_baseline || cinfo->Se < DCTSIZE2) &&
+ cinfo->Se != cinfo->lim_Se))
+ WARNMS(cinfo, JWRN_NOT_SEQUENTIAL);
+
+ /* Select MCU decoding routine */
+ /* We retain the hard-coded case for full-size blocks.
+ * This is not necessary, but it appears that this version is slightly
+ * more performant in the given implementation.
+ * With an improved implementation we would prefer a single optimized
+ * function.
+ */
+ if (cinfo->lim_Se != DCTSIZE2-1)
+ entropy->pub.decode_mcu = decode_mcu_sub;
+ else
+ entropy->pub.decode_mcu = decode_mcu;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Compute derived values for Huffman tables */
+ /* We may do this more than once for a table, but it's not expensive */
+ tbl = compptr->dc_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, TRUE, tbl,
+ & entropy->dc_derived_tbls[tbl]);
+ if (cinfo->lim_Se) { /* AC needs no table when not present */
+ tbl = compptr->ac_tbl_no;
+ jpeg_make_d_derived_tbl(cinfo, FALSE, tbl,
+ & entropy->ac_derived_tbls[tbl]);
+ }
+ /* Initialize DC predictions to 0 */
+ entropy->saved.last_dc_val[ci] = 0;
+ }
+
+ /* Precalculate decoding info for each block in an MCU of this scan */
+ for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) {
+ ci = cinfo->MCU_membership[blkn];
+ compptr = cinfo->cur_comp_info[ci];
+ /* Precalculate which table to use for each block */
+ entropy->dc_cur_tbls[blkn] = entropy->dc_derived_tbls[compptr->dc_tbl_no];
+ entropy->ac_cur_tbls[blkn] = entropy->ac_derived_tbls[compptr->ac_tbl_no];
+ /* Decide whether we really care about the coefficient values */
+ if (compptr->component_needed) {
+ ci = compptr->DCT_v_scaled_size;
+ i = compptr->DCT_h_scaled_size;
+ switch (cinfo->lim_Se) {
+ case (1*1-1):
+ entropy->coef_limit[blkn] = 1;
+ break;
+ case (2*2-1):
+ if (ci <= 0 || ci > 2) ci = 2;
+ if (i <= 0 || i > 2) i = 2;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order2[ci - 1][i - 1];
+ break;
+ case (3*3-1):
+ if (ci <= 0 || ci > 3) ci = 3;
+ if (i <= 0 || i > 3) i = 3;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order3[ci - 1][i - 1];
+ break;
+ case (4*4-1):
+ if (ci <= 0 || ci > 4) ci = 4;
+ if (i <= 0 || i > 4) i = 4;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order4[ci - 1][i - 1];
+ break;
+ case (5*5-1):
+ if (ci <= 0 || ci > 5) ci = 5;
+ if (i <= 0 || i > 5) i = 5;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order5[ci - 1][i - 1];
+ break;
+ case (6*6-1):
+ if (ci <= 0 || ci > 6) ci = 6;
+ if (i <= 0 || i > 6) i = 6;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order6[ci - 1][i - 1];
+ break;
+ case (7*7-1):
+ if (ci <= 0 || ci > 7) ci = 7;
+ if (i <= 0 || i > 7) i = 7;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order7[ci - 1][i - 1];
+ break;
+ default:
+ if (ci <= 0 || ci > 8) ci = 8;
+ if (i <= 0 || i > 8) i = 8;
+ entropy->coef_limit[blkn] = 1 + jpeg_zigzag_order[ci - 1][i - 1];
+ break;
+ }
+ } else {
+ entropy->coef_limit[blkn] = 0;
+ }
+ }
+ }
+
+ /* Initialize bitread state variables */
+ entropy->bitstate.bits_left = 0;
+ entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */
+ entropy->insufficient_data = FALSE;
+
+ /* Initialize restart counter */
+ entropy->restarts_to_go = cinfo->restart_interval;
+}
+
+
+/*
+ * Module initialization routine for Huffman entropy decoding.
+ */
+
+GLOBAL(void)
+jinit_huff_decoder (j_decompress_ptr cinfo)
+{
+ huff_entropy_ptr entropy;
+ int i;
+
+ entropy = (huff_entropy_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(huff_entropy_decoder));
+ cinfo->entropy = (struct jpeg_entropy_decoder *) entropy;
+ entropy->pub.start_pass = start_pass_huff_decoder;
+
+ if (cinfo->progressive_mode) {
+ /* Create progression status table */
+ int *coef_bit_ptr, ci;
+ cinfo->coef_bits = (int (*)[DCTSIZE2])
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components*DCTSIZE2*SIZEOF(int));
+ coef_bit_ptr = & cinfo->coef_bits[0][0];
+ for (ci = 0; ci < cinfo->num_components; ci++)
+ for (i = 0; i < DCTSIZE2; i++)
+ *coef_bit_ptr++ = -1;
+
+ /* Mark derived tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->derived_tbls[i] = NULL;
+ }
+ } else {
+ /* Mark tables unallocated */
+ for (i = 0; i < NUM_HUFF_TBLS; i++) {
+ entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL;
+ }
+ }
+}
diff --git a/jpg/jdinput.c b/jpg/jdinput.c
new file mode 100644
index 0000000..2c5c717
--- /dev/null
+++ b/jpg/jdinput.c
@@ -0,0 +1,661 @@
+/*
+ * jdinput.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2002-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains input control logic for the JPEG decompressor.
+ * These routines are concerned with controlling the decompressor's input
+ * processing (marker reading and coefficient decoding). The actual input
+ * reading is done in jdmarker.c, jdhuff.c, and jdarith.c.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_input_controller pub; /* public fields */
+
+ int inheaders; /* Nonzero until first SOS is reached */
+} my_input_controller;
+
+typedef my_input_controller * my_inputctl_ptr;
+
+
+/* Forward declarations */
+METHODDEF(int) consume_markers JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Routines to calculate various quantities related to the size of the image.
+ */
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ */
+
+GLOBAL(void)
+jpeg_core_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase.
+ * This function is used for transcoding and full decompression.
+ */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+ int ci;
+ jpeg_component_info *compptr;
+
+ /* Compute actual output image dimensions and DCT scaling choices. */
+ if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom) {
+ /* Provide 1/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 1;
+ cinfo->min_DCT_v_scaled_size = 1;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 2) {
+ /* Provide 2/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 2L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 2L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 2;
+ cinfo->min_DCT_v_scaled_size = 2;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 3) {
+ /* Provide 3/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 3L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 3L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 3;
+ cinfo->min_DCT_v_scaled_size = 3;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 4) {
+ /* Provide 4/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 4L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 4L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 4;
+ cinfo->min_DCT_v_scaled_size = 4;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 5) {
+ /* Provide 5/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 5L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 5L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 5;
+ cinfo->min_DCT_v_scaled_size = 5;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 6) {
+ /* Provide 6/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 6L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 6L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 6;
+ cinfo->min_DCT_v_scaled_size = 6;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 7) {
+ /* Provide 7/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 7L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 7L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 7;
+ cinfo->min_DCT_v_scaled_size = 7;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 8) {
+ /* Provide 8/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 8L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 8L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 8;
+ cinfo->min_DCT_v_scaled_size = 8;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 9) {
+ /* Provide 9/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 9L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 9L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 9;
+ cinfo->min_DCT_v_scaled_size = 9;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 10) {
+ /* Provide 10/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 10L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 10L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 10;
+ cinfo->min_DCT_v_scaled_size = 10;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 11) {
+ /* Provide 11/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 11L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 11L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 11;
+ cinfo->min_DCT_v_scaled_size = 11;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 12) {
+ /* Provide 12/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 12L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 12L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 12;
+ cinfo->min_DCT_v_scaled_size = 12;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 13) {
+ /* Provide 13/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 13L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 13L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 13;
+ cinfo->min_DCT_v_scaled_size = 13;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 14) {
+ /* Provide 14/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 14L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 14L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 14;
+ cinfo->min_DCT_v_scaled_size = 14;
+ } else if (cinfo->scale_num * cinfo->block_size <= cinfo->scale_denom * 15) {
+ /* Provide 15/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 15L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 15L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 15;
+ cinfo->min_DCT_v_scaled_size = 15;
+ } else {
+ /* Provide 16/block_size scaling */
+ cinfo->output_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * 16L, (long) cinfo->block_size);
+ cinfo->output_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * 16L, (long) cinfo->block_size);
+ cinfo->min_DCT_h_scaled_size = 16;
+ cinfo->min_DCT_v_scaled_size = 16;
+ }
+
+ /* Recompute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size;
+ compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size;
+ }
+
+#else /* !IDCT_SCALING_SUPPORTED */
+
+ /* Hardwire it to "no scaling" */
+ cinfo->output_width = cinfo->image_width;
+ cinfo->output_height = cinfo->image_height;
+ /* jdinput.c has already initialized DCT_scaled_size,
+ * and has computed unscaled downsampled_width and downsampled_height.
+ */
+
+#endif /* IDCT_SCALING_SUPPORTED */
+}
+
+
+LOCAL(void)
+initial_setup (j_decompress_ptr cinfo)
+/* Called once, when first SOS marker is reached */
+{
+ int ci;
+ jpeg_component_info *compptr;
+
+ /* Make sure image isn't bigger than I can handle */
+ if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION ||
+ (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION)
+ ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION);
+
+ /* For now, precision must match compiled-in value... */
+ if (cinfo->data_precision != BITS_IN_JSAMPLE)
+ ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision);
+
+ /* Check that number of components won't exceed internal array sizes */
+ if (cinfo->num_components > MAX_COMPONENTS)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components,
+ MAX_COMPONENTS);
+
+ /* Compute maximum sampling factors; check factor validity */
+ cinfo->max_h_samp_factor = 1;
+ cinfo->max_v_samp_factor = 1;
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR ||
+ compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR)
+ ERREXIT(cinfo, JERR_BAD_SAMPLING);
+ cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor,
+ compptr->h_samp_factor);
+ cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor,
+ compptr->v_samp_factor);
+ }
+
+ /* Derive block_size, natural_order, and lim_Se */
+ if (cinfo->is_baseline || (cinfo->progressive_mode &&
+ cinfo->comps_in_scan)) { /* no pseudo SOS marker */
+ cinfo->block_size = DCTSIZE;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ } else
+ switch (cinfo->Se) {
+ case (1*1-1):
+ cinfo->block_size = 1;
+ cinfo->natural_order = jpeg_natural_order; /* not needed */
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (2*2-1):
+ cinfo->block_size = 2;
+ cinfo->natural_order = jpeg_natural_order2;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (3*3-1):
+ cinfo->block_size = 3;
+ cinfo->natural_order = jpeg_natural_order3;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (4*4-1):
+ cinfo->block_size = 4;
+ cinfo->natural_order = jpeg_natural_order4;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (5*5-1):
+ cinfo->block_size = 5;
+ cinfo->natural_order = jpeg_natural_order5;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (6*6-1):
+ cinfo->block_size = 6;
+ cinfo->natural_order = jpeg_natural_order6;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (7*7-1):
+ cinfo->block_size = 7;
+ cinfo->natural_order = jpeg_natural_order7;
+ cinfo->lim_Se = cinfo->Se;
+ break;
+ case (8*8-1):
+ cinfo->block_size = 8;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (9*9-1):
+ cinfo->block_size = 9;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (10*10-1):
+ cinfo->block_size = 10;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (11*11-1):
+ cinfo->block_size = 11;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (12*12-1):
+ cinfo->block_size = 12;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (13*13-1):
+ cinfo->block_size = 13;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (14*14-1):
+ cinfo->block_size = 14;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (15*15-1):
+ cinfo->block_size = 15;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ case (16*16-1):
+ cinfo->block_size = 16;
+ cinfo->natural_order = jpeg_natural_order;
+ cinfo->lim_Se = DCTSIZE2-1;
+ break;
+ default:
+ ERREXIT4(cinfo, JERR_BAD_PROGRESSION,
+ cinfo->Ss, cinfo->Se, cinfo->Ah, cinfo->Al);
+ break;
+ }
+
+ /* We initialize DCT_scaled_size and min_DCT_scaled_size to block_size.
+ * In the full decompressor,
+ * this will be overridden by jpeg_calc_output_dimensions in jdmaster.c;
+ * but in the transcoder,
+ * jpeg_calc_output_dimensions is not used, so we must do it here.
+ */
+ cinfo->min_DCT_h_scaled_size = cinfo->block_size;
+ cinfo->min_DCT_v_scaled_size = cinfo->block_size;
+
+ /* Compute dimensions of components */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->DCT_h_scaled_size = cinfo->block_size;
+ compptr->DCT_v_scaled_size = cinfo->block_size;
+ /* Size in DCT blocks */
+ compptr->width_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ compptr->height_in_blocks = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+ /* downsampled_width and downsampled_height will also be overridden by
+ * jdmaster.c if we are doing full decompression. The transcoder library
+ * doesn't use these values, but the calling application might.
+ */
+ /* Size in samples */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor,
+ (long) cinfo->max_h_samp_factor);
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor,
+ (long) cinfo->max_v_samp_factor);
+ /* Mark component needed, until color conversion says otherwise */
+ compptr->component_needed = TRUE;
+ /* Mark no quantization table yet saved for component */
+ compptr->quant_table = NULL;
+ }
+
+ /* Compute number of fully interleaved MCU rows. */
+ cinfo->total_iMCU_rows = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+
+ /* Decide whether file contains multiple scans */
+ if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode)
+ cinfo->inputctl->has_multiple_scans = TRUE;
+ else
+ cinfo->inputctl->has_multiple_scans = FALSE;
+}
+
+
+LOCAL(void)
+per_scan_setup (j_decompress_ptr cinfo)
+/* Do computations that are needed before processing a JPEG scan */
+/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */
+{
+ int ci, mcublks, tmp;
+ jpeg_component_info *compptr;
+
+ if (cinfo->comps_in_scan == 1) {
+
+ /* Noninterleaved (single-component) scan */
+ compptr = cinfo->cur_comp_info[0];
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = compptr->width_in_blocks;
+ cinfo->MCU_rows_in_scan = compptr->height_in_blocks;
+
+ /* For noninterleaved scan, always one block per MCU */
+ compptr->MCU_width = 1;
+ compptr->MCU_height = 1;
+ compptr->MCU_blocks = 1;
+ compptr->MCU_sample_width = compptr->DCT_h_scaled_size;
+ compptr->last_col_width = 1;
+ /* For noninterleaved scans, it is convenient to define last_row_height
+ * as the number of block rows present in the last iMCU row.
+ */
+ tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor);
+ if (tmp == 0) tmp = compptr->v_samp_factor;
+ compptr->last_row_height = tmp;
+
+ /* Prepare array describing MCU composition */
+ cinfo->blocks_in_MCU = 1;
+ cinfo->MCU_membership[0] = 0;
+
+ } else {
+
+ /* Interleaved (multi-component) scan */
+ if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN)
+ ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan,
+ MAX_COMPS_IN_SCAN);
+
+ /* Overall image size in MCUs */
+ cinfo->MCUs_per_row = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width,
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ cinfo->MCU_rows_in_scan = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height,
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+
+ cinfo->blocks_in_MCU = 0;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* Sampling factors give # of blocks of component in each MCU */
+ compptr->MCU_width = compptr->h_samp_factor;
+ compptr->MCU_height = compptr->v_samp_factor;
+ compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height;
+ compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_h_scaled_size;
+ /* Figure number of non-dummy blocks in last MCU column & row */
+ tmp = (int) (compptr->width_in_blocks % compptr->MCU_width);
+ if (tmp == 0) tmp = compptr->MCU_width;
+ compptr->last_col_width = tmp;
+ tmp = (int) (compptr->height_in_blocks % compptr->MCU_height);
+ if (tmp == 0) tmp = compptr->MCU_height;
+ compptr->last_row_height = tmp;
+ /* Prepare array describing MCU composition */
+ mcublks = compptr->MCU_blocks;
+ if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU)
+ ERREXIT(cinfo, JERR_BAD_MCU_SIZE);
+ while (mcublks-- > 0) {
+ cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci;
+ }
+ }
+
+ }
+}
+
+
+/*
+ * Save away a copy of the Q-table referenced by each component present
+ * in the current scan, unless already saved during a prior scan.
+ *
+ * In a multiple-scan JPEG file, the encoder could assign different components
+ * the same Q-table slot number, but change table definitions between scans
+ * so that each component uses a different Q-table. (The IJG encoder is not
+ * currently capable of doing this, but other encoders might.) Since we want
+ * to be able to dequantize all the components at the end of the file, this
+ * means that we have to save away the table actually used for each component.
+ * We do this by copying the table at the start of the first scan containing
+ * the component.
+ * The JPEG spec prohibits the encoder from changing the contents of a Q-table
+ * slot between scans of a component using that slot. If the encoder does so
+ * anyway, this decoder will simply use the Q-table values that were current
+ * at the start of the first scan for the component.
+ *
+ * The decompressor output side looks only at the saved quant tables,
+ * not at the current Q-table slots.
+ */
+
+LOCAL(void)
+latch_quant_tables (j_decompress_ptr cinfo)
+{
+ int ci, qtblno;
+ jpeg_component_info *compptr;
+ JQUANT_TBL * qtbl;
+
+ for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+ compptr = cinfo->cur_comp_info[ci];
+ /* No work if we already saved Q-table for this component */
+ if (compptr->quant_table != NULL)
+ continue;
+ /* Make sure specified quantization table is present */
+ qtblno = compptr->quant_tbl_no;
+ if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS ||
+ cinfo->quant_tbl_ptrs[qtblno] == NULL)
+ ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno);
+ /* OK, save away the quantization table */
+ qtbl = (JQUANT_TBL *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(JQUANT_TBL));
+ MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL));
+ compptr->quant_table = qtbl;
+ }
+}
+
+
+/*
+ * Initialize the input modules to read a scan of compressed data.
+ * The first call to this is done by jdmaster.c after initializing
+ * the entire decompressor (during jpeg_start_decompress).
+ * Subsequent calls come from consume_markers, below.
+ */
+
+METHODDEF(void)
+start_input_pass (j_decompress_ptr cinfo)
+{
+ per_scan_setup(cinfo);
+ latch_quant_tables(cinfo);
+ (*cinfo->entropy->start_pass) (cinfo);
+ (*cinfo->coef->start_input_pass) (cinfo);
+ cinfo->inputctl->consume_input = cinfo->coef->consume_data;
+}
+
+
+/*
+ * Finish up after inputting a compressed-data scan.
+ * This is called by the coefficient controller after it's read all
+ * the expected data of the scan.
+ */
+
+METHODDEF(void)
+finish_input_pass (j_decompress_ptr cinfo)
+{
+ cinfo->inputctl->consume_input = consume_markers;
+}
+
+
+/*
+ * Read JPEG markers before, between, or after compressed-data scans.
+ * Change state as necessary when a new scan is reached.
+ * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ *
+ * The consume_input method pointer points either here or to the
+ * coefficient controller's consume_data routine, depending on whether
+ * we are reading a compressed data segment or inter-segment markers.
+ *
+ * Note: This function should NOT return a pseudo SOS marker (with zero
+ * component number) to the caller. A pseudo marker received by
+ * read_markers is processed and then skipped for other markers.
+ */
+
+METHODDEF(int)
+consume_markers (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
+ int val;
+
+ if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */
+ return JPEG_REACHED_EOI;
+
+ for (;;) { /* Loop to pass pseudo SOS marker */
+ val = (*cinfo->marker->read_markers) (cinfo);
+
+ switch (val) {
+ case JPEG_REACHED_SOS: /* Found SOS */
+ if (inputctl->inheaders) { /* 1st SOS */
+ if (inputctl->inheaders == 1)
+ initial_setup(cinfo);
+ if (cinfo->comps_in_scan == 0) { /* pseudo SOS marker */
+ inputctl->inheaders = 2;
+ break;
+ }
+ inputctl->inheaders = 0;
+ /* Note: start_input_pass must be called by jdmaster.c
+ * before any more input can be consumed. jdapimin.c is
+ * responsible for enforcing this sequencing.
+ */
+ } else { /* 2nd or later SOS marker */
+ if (! inputctl->pub.has_multiple_scans)
+ ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */
+ if (cinfo->comps_in_scan == 0) /* unexpected pseudo SOS marker */
+ break;
+ start_input_pass(cinfo);
+ }
+ return val;
+ case JPEG_REACHED_EOI: /* Found EOI */
+ inputctl->pub.eoi_reached = TRUE;
+ if (inputctl->inheaders) { /* Tables-only datastream, apparently */
+ if (cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOF_NO_SOS);
+ } else {
+ /* Prevent infinite loop in coef ctlr's decompress_data routine
+ * if user set output_scan_number larger than number of scans.
+ */
+ if (cinfo->output_scan_number > cinfo->input_scan_number)
+ cinfo->output_scan_number = cinfo->input_scan_number;
+ }
+ return val;
+ case JPEG_SUSPENDED:
+ return val;
+ default:
+ return val;
+ }
+ }
+}
+
+
+/*
+ * Reset state to begin a fresh datastream.
+ */
+
+METHODDEF(void)
+reset_input_controller (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl;
+
+ inputctl->pub.consume_input = consume_markers;
+ inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
+ inputctl->pub.eoi_reached = FALSE;
+ inputctl->inheaders = 1;
+ /* Reset other modules */
+ (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
+ (*cinfo->marker->reset_marker_reader) (cinfo);
+ /* Reset progression state -- would be cleaner if entropy decoder did this */
+ cinfo->coef_bits = NULL;
+}
+
+
+/*
+ * Initialize the input controller module.
+ * This is called only once, when the decompression object is created.
+ */
+
+GLOBAL(void)
+jinit_input_controller (j_decompress_ptr cinfo)
+{
+ my_inputctl_ptr inputctl;
+
+ /* Create subobject in permanent pool */
+ inputctl = (my_inputctl_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_input_controller));
+ cinfo->inputctl = (struct jpeg_input_controller *) inputctl;
+ /* Initialize method pointers */
+ inputctl->pub.consume_input = consume_markers;
+ inputctl->pub.reset_input_controller = reset_input_controller;
+ inputctl->pub.start_input_pass = start_input_pass;
+ inputctl->pub.finish_input_pass = finish_input_pass;
+ /* Initialize state: can't use reset_input_controller since we don't
+ * want to try to reset other modules yet.
+ */
+ inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */
+ inputctl->pub.eoi_reached = FALSE;
+ inputctl->inheaders = 1;
+}
diff --git a/jpg/jdmainct.c b/jpg/jdmainct.c
new file mode 100644
index 0000000..02723ca
--- /dev/null
+++ b/jpg/jdmainct.c
@@ -0,0 +1,512 @@
+/*
+ * jdmainct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the main buffer controller for decompression.
+ * The main buffer lies between the JPEG decompressor proper and the
+ * post-processor; it holds downsampled data in the JPEG colorspace.
+ *
+ * Note that this code is bypassed in raw-data mode, since the application
+ * supplies the equivalent of the main buffer in that case.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * In the current system design, the main buffer need never be a full-image
+ * buffer; any full-height buffers will be found inside the coefficient or
+ * postprocessing controllers. Nonetheless, the main controller is not
+ * trivial. Its responsibility is to provide context rows for upsampling/
+ * rescaling, and doing this in an efficient fashion is a bit tricky.
+ *
+ * Postprocessor input data is counted in "row groups". A row group
+ * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size)
+ * sample rows of each component. (We require DCT_scaled_size values to be
+ * chosen such that these numbers are integers. In practice DCT_scaled_size
+ * values will likely be powers of two, so we actually have the stronger
+ * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.)
+ * Upsampling will typically produce max_v_samp_factor pixel rows from each
+ * row group (times any additional scale factor that the upsampler is
+ * applying).
+ *
+ * The coefficient controller will deliver data to us one iMCU row at a time;
+ * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or
+ * exactly min_DCT_scaled_size row groups. (This amount of data corresponds
+ * to one row of MCUs when the image is fully interleaved.) Note that the
+ * number of sample rows varies across components, but the number of row
+ * groups does not. Some garbage sample rows may be included in the last iMCU
+ * row at the bottom of the image.
+ *
+ * Depending on the vertical scaling algorithm used, the upsampler may need
+ * access to the sample row(s) above and below its current input row group.
+ * The upsampler is required to set need_context_rows TRUE at global selection
+ * time if so. When need_context_rows is FALSE, this controller can simply
+ * obtain one iMCU row at a time from the coefficient controller and dole it
+ * out as row groups to the postprocessor.
+ *
+ * When need_context_rows is TRUE, this controller guarantees that the buffer
+ * passed to postprocessing contains at least one row group's worth of samples
+ * above and below the row group(s) being processed. Note that the context
+ * rows "above" the first passed row group appear at negative row offsets in
+ * the passed buffer. At the top and bottom of the image, the required
+ * context rows are manufactured by duplicating the first or last real sample
+ * row; this avoids having special cases in the upsampling inner loops.
+ *
+ * The amount of context is fixed at one row group just because that's a
+ * convenient number for this controller to work with. The existing
+ * upsamplers really only need one sample row of context. An upsampler
+ * supporting arbitrary output rescaling might wish for more than one row
+ * group of context when shrinking the image; tough, we don't handle that.
+ * (This is justified by the assumption that downsizing will be handled mostly
+ * by adjusting the DCT_scaled_size values, so that the actual scale factor at
+ * the upsample step needn't be much less than one.)
+ *
+ * To provide the desired context, we have to retain the last two row groups
+ * of one iMCU row while reading in the next iMCU row. (The last row group
+ * can't be processed until we have another row group for its below-context,
+ * and so we have to save the next-to-last group too for its above-context.)
+ * We could do this most simply by copying data around in our buffer, but
+ * that'd be very slow. We can avoid copying any data by creating a rather
+ * strange pointer structure. Here's how it works. We allocate a workspace
+ * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number
+ * of row groups per iMCU row). We create two sets of redundant pointers to
+ * the workspace. Labeling the physical row groups 0 to M+1, the synthesized
+ * pointer lists look like this:
+ * M+1 M-1
+ * master pointer --> 0 master pointer --> 0
+ * 1 1
+ * ... ...
+ * M-3 M-3
+ * M-2 M
+ * M-1 M+1
+ * M M-2
+ * M+1 M-1
+ * 0 0
+ * We read alternate iMCU rows using each master pointer; thus the last two
+ * row groups of the previous iMCU row remain un-overwritten in the workspace.
+ * The pointer lists are set up so that the required context rows appear to
+ * be adjacent to the proper places when we pass the pointer lists to the
+ * upsampler.
+ *
+ * The above pictures describe the normal state of the pointer lists.
+ * At top and bottom of the image, we diddle the pointer lists to duplicate
+ * the first or last sample row as necessary (this is cheaper than copying
+ * sample rows around).
+ *
+ * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that
+ * situation each iMCU row provides only one row group so the buffering logic
+ * must be different (eg, we must read two iMCU rows before we can emit the
+ * first row group). For now, we simply do not support providing context
+ * rows when min_DCT_scaled_size is 1. That combination seems unlikely to
+ * be worth providing --- if someone wants a 1/8th-size preview, they probably
+ * want it quick and dirty, so a context-free upsampler is sufficient.
+ */
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_main_controller pub; /* public fields */
+
+ /* Pointer to allocated workspace (M or M+2 row groups). */
+ JSAMPARRAY buffer[MAX_COMPONENTS];
+
+ boolean buffer_full; /* Have we gotten an iMCU row from decoder? */
+ JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */
+
+ /* Remaining fields are only used in the context case. */
+
+ /* These are the master pointers to the funny-order pointer lists. */
+ JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */
+
+ int whichptr; /* indicates which pointer set is now in use */
+ int context_state; /* process_data state machine status */
+ JDIMENSION rowgroups_avail; /* row groups available to postprocessor */
+ JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */
+} my_main_controller;
+
+typedef my_main_controller * my_main_ptr;
+
+/* context_state values: */
+#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */
+#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */
+#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */
+
+
+/* Forward declarations */
+METHODDEF(void) process_data_simple_main
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+METHODDEF(void) process_data_context_main
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+#ifdef QUANT_2PASS_SUPPORTED
+METHODDEF(void) process_data_crank_post
+ JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail));
+#endif
+
+
+LOCAL(void)
+alloc_funny_pointers (j_decompress_ptr cinfo)
+/* Allocate space for the funny pointer lists.
+ * This is done only once, not once per pass.
+ */
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf;
+
+ /* Get top-level space for component array pointers.
+ * We alloc both arrays with one call to save a few cycles.
+ */
+ main->xbuffer[0] = (JSAMPIMAGE)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components * 2 * SIZEOF(JSAMPARRAY));
+ main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+ /* Get space for pointer lists --- M+4 row groups in each list.
+ * We alloc both pointer lists with one call to save a few cycles.
+ */
+ xbuf = (JSAMPARRAY)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW));
+ xbuf += rgroup; /* want one row group at negative offsets */
+ main->xbuffer[0][ci] = xbuf;
+ xbuf += rgroup * (M + 4);
+ main->xbuffer[1][ci] = xbuf;
+ }
+}
+
+
+LOCAL(void)
+make_funny_pointers (j_decompress_ptr cinfo)
+/* Create the funny pointer lists discussed in the comments above.
+ * The actual workspace is already allocated (in main->buffer),
+ * and the space for the pointer lists is allocated too.
+ * This routine just fills in the curiously ordered lists.
+ * This will be repeated at the beginning of each pass.
+ */
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY buf, xbuf0, xbuf1;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+ xbuf0 = main->xbuffer[0][ci];
+ xbuf1 = main->xbuffer[1][ci];
+ /* First copy the workspace pointers as-is */
+ buf = main->buffer[ci];
+ for (i = 0; i < rgroup * (M + 2); i++) {
+ xbuf0[i] = xbuf1[i] = buf[i];
+ }
+ /* In the second list, put the last four row groups in swapped order */
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i];
+ xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i];
+ }
+ /* The wraparound pointers at top and bottom will be filled later
+ * (see set_wraparound_pointers, below). Initially we want the "above"
+ * pointers to duplicate the first actual data line. This only needs
+ * to happen in xbuffer[0].
+ */
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup] = xbuf0[0];
+ }
+ }
+}
+
+
+LOCAL(void)
+set_wraparound_pointers (j_decompress_ptr cinfo)
+/* Set up the "wraparound" pointers at top and bottom of the pointer lists.
+ * This changes the pointer list state from top-of-image to the normal state.
+ */
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup;
+ int M = cinfo->min_DCT_v_scaled_size;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf0, xbuf1;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+ xbuf0 = main->xbuffer[0][ci];
+ xbuf1 = main->xbuffer[1][ci];
+ for (i = 0; i < rgroup; i++) {
+ xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i];
+ xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i];
+ xbuf0[rgroup*(M+2) + i] = xbuf0[i];
+ xbuf1[rgroup*(M+2) + i] = xbuf1[i];
+ }
+ }
+}
+
+
+LOCAL(void)
+set_bottom_pointers (j_decompress_ptr cinfo)
+/* Change the pointer lists to duplicate the last sample row at the bottom
+ * of the image. whichptr indicates which xbuffer holds the final iMCU row.
+ * Also sets rowgroups_avail to indicate number of nondummy row groups in row.
+ */
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ int ci, i, rgroup, iMCUheight, rows_left;
+ jpeg_component_info *compptr;
+ JSAMPARRAY xbuf;
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Count sample rows in one iMCU row and in one row group */
+ iMCUheight = compptr->v_samp_factor * compptr->DCT_v_scaled_size;
+ rgroup = iMCUheight / cinfo->min_DCT_v_scaled_size;
+ /* Count nondummy sample rows remaining for this component */
+ rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight);
+ if (rows_left == 0) rows_left = iMCUheight;
+ /* Count nondummy row groups. Should get same answer for each component,
+ * so we need only do it once.
+ */
+ if (ci == 0) {
+ main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1);
+ }
+ /* Duplicate the last real sample row rgroup*2 times; this pads out the
+ * last partial rowgroup and ensures at least one full rowgroup of context.
+ */
+ xbuf = main->xbuffer[main->whichptr][ci];
+ for (i = 0; i < rgroup * 2; i++) {
+ xbuf[rows_left + i] = xbuf[rows_left-1];
+ }
+ }
+}
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo->upsample->need_context_rows) {
+ main->pub.process_data = process_data_context_main;
+ make_funny_pointers(cinfo); /* Create the xbuffer[] lists */
+ main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */
+ main->context_state = CTX_PREPARE_FOR_IMCU;
+ main->iMCU_row_ctr = 0;
+ } else {
+ /* Simple case with no context needed */
+ main->pub.process_data = process_data_simple_main;
+ }
+ main->buffer_full = FALSE; /* Mark buffer empty */
+ main->rowgroup_ctr = 0;
+ break;
+#ifdef QUANT_2PASS_SUPPORTED
+ case JBUF_CRANK_DEST:
+ /* For last pass of 2-pass quantization, just crank the postprocessor */
+ main->pub.process_data = process_data_crank_post;
+ break;
+#endif
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This handles the simple case where no context is required.
+ */
+
+METHODDEF(void)
+process_data_simple_main (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+ JDIMENSION rowgroups_avail;
+
+ /* Read input data if we haven't filled the main buffer yet */
+ if (! main->buffer_full) {
+ if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer))
+ return; /* suspension forced, can do nothing more */
+ main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
+ }
+
+ /* There are always min_DCT_scaled_size row groups in an iMCU row. */
+ rowgroups_avail = (JDIMENSION) cinfo->min_DCT_v_scaled_size;
+ /* Note: at the bottom of the image, we may pass extra garbage row groups
+ * to the postprocessor. The postprocessor has to check for bottom
+ * of image anyway (at row resolution), so no point in us doing it too.
+ */
+
+ /* Feed the postprocessor */
+ (*cinfo->post->post_process_data) (cinfo, main->buffer,
+ &main->rowgroup_ctr, rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+
+ /* Has postprocessor consumed all the data yet? If so, mark buffer empty */
+ if (main->rowgroup_ctr >= rowgroups_avail) {
+ main->buffer_full = FALSE;
+ main->rowgroup_ctr = 0;
+ }
+}
+
+
+/*
+ * Process some data.
+ * This handles the case where context rows must be provided.
+ */
+
+METHODDEF(void)
+process_data_context_main (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_main_ptr main = (my_main_ptr) cinfo->main;
+
+ /* Read input data if we haven't filled the main buffer yet */
+ if (! main->buffer_full) {
+ if (! (*cinfo->coef->decompress_data) (cinfo,
+ main->xbuffer[main->whichptr]))
+ return; /* suspension forced, can do nothing more */
+ main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */
+ main->iMCU_row_ctr++; /* count rows received */
+ }
+
+ /* Postprocessor typically will not swallow all the input data it is handed
+ * in one call (due to filling the output buffer first). Must be prepared
+ * to exit and restart. This switch lets us keep track of how far we got.
+ * Note that each case falls through to the next on successful completion.
+ */
+ switch (main->context_state) {
+ case CTX_POSTPONED_ROW:
+ /* Call postprocessor using previously set pointers for postponed row */
+ (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
+ &main->rowgroup_ctr, main->rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+ if (main->rowgroup_ctr < main->rowgroups_avail)
+ return; /* Need to suspend */
+ main->context_state = CTX_PREPARE_FOR_IMCU;
+ if (*out_row_ctr >= out_rows_avail)
+ return; /* Postprocessor exactly filled output buf */
+ /*FALLTHROUGH*/
+ case CTX_PREPARE_FOR_IMCU:
+ /* Prepare to process first M-1 row groups of this iMCU row */
+ main->rowgroup_ctr = 0;
+ main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size - 1);
+ /* Check for bottom of image: if so, tweak pointers to "duplicate"
+ * the last sample row, and adjust rowgroups_avail to ignore padding rows.
+ */
+ if (main->iMCU_row_ctr == cinfo->total_iMCU_rows)
+ set_bottom_pointers(cinfo);
+ main->context_state = CTX_PROCESS_IMCU;
+ /*FALLTHROUGH*/
+ case CTX_PROCESS_IMCU:
+ /* Call postprocessor using previously set pointers */
+ (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr],
+ &main->rowgroup_ctr, main->rowgroups_avail,
+ output_buf, out_row_ctr, out_rows_avail);
+ if (main->rowgroup_ctr < main->rowgroups_avail)
+ return; /* Need to suspend */
+ /* After the first iMCU, change wraparound pointers to normal state */
+ if (main->iMCU_row_ctr == 1)
+ set_wraparound_pointers(cinfo);
+ /* Prepare to load new iMCU row using other xbuffer list */
+ main->whichptr ^= 1; /* 0=>1 or 1=>0 */
+ main->buffer_full = FALSE;
+ /* Still need to process last row group of this iMCU row, */
+ /* which is saved at index M+1 of the other xbuffer */
+ main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 1);
+ main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_v_scaled_size + 2);
+ main->context_state = CTX_POSTPONED_ROW;
+ }
+}
+
+
+/*
+ * Process some data.
+ * Final pass of two-pass quantization: just call the postprocessor.
+ * Source data will be the postprocessor controller's internal buffer.
+ */
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+METHODDEF(void)
+process_data_crank_post (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL,
+ (JDIMENSION *) NULL, (JDIMENSION) 0,
+ output_buf, out_row_ctr, out_rows_avail);
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
+
+
+/*
+ * Initialize main buffer controller.
+ */
+
+GLOBAL(void)
+jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_main_ptr main;
+ int ci, rgroup, ngroups;
+ jpeg_component_info *compptr;
+
+ main = (my_main_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_main_controller));
+ cinfo->main = (struct jpeg_d_main_controller *) main;
+ main->pub.start_pass = start_pass_main;
+
+ if (need_full_buffer) /* shouldn't happen */
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+
+ /* Allocate the workspace.
+ * ngroups is the number of row groups we need.
+ */
+ if (cinfo->upsample->need_context_rows) {
+ if (cinfo->min_DCT_v_scaled_size < 2) /* unsupported, see comments above */
+ ERREXIT(cinfo, JERR_NOTIMPL);
+ alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */
+ ngroups = cinfo->min_DCT_v_scaled_size + 2;
+ } else {
+ ngroups = cinfo->min_DCT_v_scaled_size;
+ }
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ rgroup = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size; /* height of a row group of component */
+ main->buffer[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ compptr->width_in_blocks * compptr->DCT_h_scaled_size,
+ (JDIMENSION) (rgroup * ngroups));
+ }
+}
diff --git a/jpg/jdmarker.c b/jpg/jdmarker.c
new file mode 100644
index 0000000..f2a9cc4
--- /dev/null
+++ b/jpg/jdmarker.c
@@ -0,0 +1,1406 @@
+/*
+ * jdmarker.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to decode JPEG datastream markers.
+ * Most of the complexity arises from our desire to support input
+ * suspension: if not all of the data for a marker is available,
+ * we must exit back to the application. On resumption, we reprocess
+ * the marker.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+typedef enum { /* JPEG marker codes */
+ M_SOF0 = 0xc0,
+ M_SOF1 = 0xc1,
+ M_SOF2 = 0xc2,
+ M_SOF3 = 0xc3,
+
+ M_SOF5 = 0xc5,
+ M_SOF6 = 0xc6,
+ M_SOF7 = 0xc7,
+
+ M_JPG = 0xc8,
+ M_SOF9 = 0xc9,
+ M_SOF10 = 0xca,
+ M_SOF11 = 0xcb,
+
+ M_SOF13 = 0xcd,
+ M_SOF14 = 0xce,
+ M_SOF15 = 0xcf,
+
+ M_DHT = 0xc4,
+
+ M_DAC = 0xcc,
+
+ M_RST0 = 0xd0,
+ M_RST1 = 0xd1,
+ M_RST2 = 0xd2,
+ M_RST3 = 0xd3,
+ M_RST4 = 0xd4,
+ M_RST5 = 0xd5,
+ M_RST6 = 0xd6,
+ M_RST7 = 0xd7,
+
+ M_SOI = 0xd8,
+ M_EOI = 0xd9,
+ M_SOS = 0xda,
+ M_DQT = 0xdb,
+ M_DNL = 0xdc,
+ M_DRI = 0xdd,
+ M_DHP = 0xde,
+ M_EXP = 0xdf,
+
+ M_APP0 = 0xe0,
+ M_APP1 = 0xe1,
+ M_APP2 = 0xe2,
+ M_APP3 = 0xe3,
+ M_APP4 = 0xe4,
+ M_APP5 = 0xe5,
+ M_APP6 = 0xe6,
+ M_APP7 = 0xe7,
+ M_APP8 = 0xe8,
+ M_APP9 = 0xe9,
+ M_APP10 = 0xea,
+ M_APP11 = 0xeb,
+ M_APP12 = 0xec,
+ M_APP13 = 0xed,
+ M_APP14 = 0xee,
+ M_APP15 = 0xef,
+
+ M_JPG0 = 0xf0,
+ M_JPG13 = 0xfd,
+ M_COM = 0xfe,
+
+ M_TEM = 0x01,
+
+ M_ERROR = 0x100
+} JPEG_MARKER;
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_marker_reader pub; /* public fields */
+
+ /* Application-overridable marker processing methods */
+ jpeg_marker_parser_method process_COM;
+ jpeg_marker_parser_method process_APPn[16];
+
+ /* Limit on marker data length to save for each marker type */
+ unsigned int length_limit_COM;
+ unsigned int length_limit_APPn[16];
+
+ /* Status of COM/APPn marker saving */
+ jpeg_saved_marker_ptr cur_marker; /* NULL if not processing a marker */
+ unsigned int bytes_read; /* data bytes read so far in marker */
+ /* Note: cur_marker is not linked into marker_list until it's all read. */
+} my_marker_reader;
+
+typedef my_marker_reader * my_marker_ptr;
+
+
+/*
+ * Macros for fetching data from the data source module.
+ *
+ * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect
+ * the current restart point; we update them only when we have reached a
+ * suitable place to restart if a suspension occurs.
+ */
+
+/* Declare and initialize local copies of input pointer/count */
+#define INPUT_VARS(cinfo) \
+ struct jpeg_source_mgr * datasrc = (cinfo)->src; \
+ const JOCTET * next_input_byte = datasrc->next_input_byte; \
+ size_t bytes_in_buffer = datasrc->bytes_in_buffer
+
+/* Unload the local copies --- do this only at a restart boundary */
+#define INPUT_SYNC(cinfo) \
+ ( datasrc->next_input_byte = next_input_byte, \
+ datasrc->bytes_in_buffer = bytes_in_buffer )
+
+/* Reload the local copies --- used only in MAKE_BYTE_AVAIL */
+#define INPUT_RELOAD(cinfo) \
+ ( next_input_byte = datasrc->next_input_byte, \
+ bytes_in_buffer = datasrc->bytes_in_buffer )
+
+/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.
+ * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+ * but we must reload the local copies after a successful fill.
+ */
+#define MAKE_BYTE_AVAIL(cinfo,action) \
+ if (bytes_in_buffer == 0) { \
+ if (! (*datasrc->fill_input_buffer) (cinfo)) \
+ { action; } \
+ INPUT_RELOAD(cinfo); \
+ }
+
+/* Read a byte into variable V.
+ * If must suspend, take the specified action (typically "return FALSE").
+ */
+#define INPUT_BYTE(cinfo,V,action) \
+ MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+ bytes_in_buffer--; \
+ V = GETJOCTET(*next_input_byte++); )
+
+/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
+ * V should be declared unsigned int or perhaps INT32.
+ */
+#define INPUT_2BYTES(cinfo,V,action) \
+ MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+ bytes_in_buffer--; \
+ V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
+ MAKE_BYTE_AVAIL(cinfo,action); \
+ bytes_in_buffer--; \
+ V += GETJOCTET(*next_input_byte++); )
+
+
+/*
+ * Routines to process JPEG markers.
+ *
+ * Entry condition: JPEG marker itself has been read and its code saved
+ * in cinfo->unread_marker; input restart point is just after the marker.
+ *
+ * Exit: if return TRUE, have read and processed any parameters, and have
+ * updated the restart point to point after the parameters.
+ * If return FALSE, was forced to suspend before reaching end of
+ * marker parameters; restart point has not been moved. Same routine
+ * will be called again after application supplies more input data.
+ *
+ * This approach to suspension assumes that all of a marker's parameters
+ * can fit into a single input bufferload. This should hold for "normal"
+ * markers. Some COM/APPn markers might have large parameter segments
+ * that might not fit. If we are simply dropping such a marker, we use
+ * skip_input_data to get past it, and thereby put the problem on the
+ * source manager's shoulders. If we are saving the marker's contents
+ * into memory, we use a slightly different convention: when forced to
+ * suspend, the marker processor updates the restart point to the end of
+ * what it's consumed (ie, the end of the buffer) before returning FALSE.
+ * On resumption, cinfo->unread_marker still contains the marker code,
+ * but the data source will point to the next chunk of marker data.
+ * The marker processor must retain internal state to deal with this.
+ *
+ * Note that we don't bother to avoid duplicate trace messages if a
+ * suspension occurs within marker parameters. Other side effects
+ * require more care.
+ */
+
+
+LOCAL(boolean)
+get_soi (j_decompress_ptr cinfo)
+/* Process an SOI marker */
+{
+ int i;
+
+ TRACEMS(cinfo, 1, JTRC_SOI);
+
+ if (cinfo->marker->saw_SOI)
+ ERREXIT(cinfo, JERR_SOI_DUPLICATE);
+
+ /* Reset all parameters that are defined to be reset by SOI */
+
+ for (i = 0; i < NUM_ARITH_TBLS; i++) {
+ cinfo->arith_dc_L[i] = 0;
+ cinfo->arith_dc_U[i] = 1;
+ cinfo->arith_ac_K[i] = 5;
+ }
+ cinfo->restart_interval = 0;
+
+ /* Set initial assumptions for colorspace etc */
+
+ cinfo->jpeg_color_space = JCS_UNKNOWN;
+ cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */
+
+ cinfo->saw_JFIF_marker = FALSE;
+ cinfo->JFIF_major_version = 1; /* set default JFIF APP0 values */
+ cinfo->JFIF_minor_version = 1;
+ cinfo->density_unit = 0;
+ cinfo->X_density = 1;
+ cinfo->Y_density = 1;
+ cinfo->saw_Adobe_marker = FALSE;
+ cinfo->Adobe_transform = 0;
+
+ cinfo->marker->saw_SOI = TRUE;
+
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_sof (j_decompress_ptr cinfo, boolean is_baseline, boolean is_prog,
+ boolean is_arith)
+/* Process a SOFn marker */
+{
+ INT32 length;
+ int c, ci;
+ jpeg_component_info * compptr;
+ INPUT_VARS(cinfo);
+
+ cinfo->is_baseline = is_baseline;
+ cinfo->progressive_mode = is_prog;
+ cinfo->arith_code = is_arith;
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE);
+ INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE);
+ INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE);
+ INPUT_BYTE(cinfo, cinfo->num_components, return FALSE);
+
+ length -= 8;
+
+ TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker,
+ (int) cinfo->image_width, (int) cinfo->image_height,
+ cinfo->num_components);
+
+ if (cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOF_DUPLICATE);
+
+ /* We don't support files in which the image height is initially specified */
+ /* as 0 and is later redefined by DNL. As long as we have to check that, */
+ /* might as well have a general sanity check. */
+ if (cinfo->image_height <= 0 || cinfo->image_width <= 0
+ || cinfo->num_components <= 0)
+ ERREXIT(cinfo, JERR_EMPTY_IMAGE);
+
+ if (length != (cinfo->num_components * 3))
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ if (cinfo->comp_info == NULL) /* do only once, even if suspend */
+ cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->num_components * SIZEOF(jpeg_component_info));
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ compptr->component_index = ci;
+ INPUT_BYTE(cinfo, compptr->component_id, return FALSE);
+ INPUT_BYTE(cinfo, c, return FALSE);
+ compptr->h_samp_factor = (c >> 4) & 15;
+ compptr->v_samp_factor = (c ) & 15;
+ INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE);
+
+ TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT,
+ compptr->component_id, compptr->h_samp_factor,
+ compptr->v_samp_factor, compptr->quant_tbl_no);
+ }
+
+ cinfo->marker->saw_SOF = TRUE;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_sos (j_decompress_ptr cinfo)
+/* Process a SOS marker */
+{
+ INT32 length;
+ int i, ci, n, c, cc;
+ jpeg_component_info * compptr;
+ INPUT_VARS(cinfo);
+
+ if (! cinfo->marker->saw_SOF)
+ ERREXIT(cinfo, JERR_SOS_NO_SOF);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */
+
+ TRACEMS1(cinfo, 1, JTRC_SOS, n);
+
+ if (length != (n * 2 + 6) || n > MAX_COMPS_IN_SCAN ||
+ (n == 0 && !cinfo->progressive_mode))
+ /* pseudo SOS marker only allowed in progressive mode */
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ cinfo->comps_in_scan = n;
+
+ /* Collect the component-spec parameters */
+
+ for (i = 0; i < n; i++) {
+ INPUT_BYTE(cinfo, cc, return FALSE);
+ INPUT_BYTE(cinfo, c, return FALSE);
+
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ if (cc == compptr->component_id)
+ goto id_found;
+ }
+
+ ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc);
+
+ id_found:
+
+ cinfo->cur_comp_info[i] = compptr;
+ compptr->dc_tbl_no = (c >> 4) & 15;
+ compptr->ac_tbl_no = (c ) & 15;
+
+ TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc,
+ compptr->dc_tbl_no, compptr->ac_tbl_no);
+ }
+
+ /* Collect the additional scan parameters Ss, Se, Ah/Al. */
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Ss = c;
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Se = c;
+ INPUT_BYTE(cinfo, c, return FALSE);
+ cinfo->Ah = (c >> 4) & 15;
+ cinfo->Al = (c ) & 15;
+
+ TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se,
+ cinfo->Ah, cinfo->Al);
+
+ /* Prepare to scan data & restart markers */
+ cinfo->marker->next_restart_num = 0;
+
+ /* Count another (non-pseudo) SOS marker */
+ if (n) cinfo->input_scan_number++;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+#ifdef D_ARITH_CODING_SUPPORTED
+
+LOCAL(boolean)
+get_dac (j_decompress_ptr cinfo)
+/* Process a DAC marker */
+{
+ INT32 length;
+ int index, val;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 0) {
+ INPUT_BYTE(cinfo, index, return FALSE);
+ INPUT_BYTE(cinfo, val, return FALSE);
+
+ length -= 2;
+
+ TRACEMS2(cinfo, 1, JTRC_DAC, index, val);
+
+ if (index < 0 || index >= (2*NUM_ARITH_TBLS))
+ ERREXIT1(cinfo, JERR_DAC_INDEX, index);
+
+ if (index >= NUM_ARITH_TBLS) { /* define AC table */
+ cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val;
+ } else { /* define DC table */
+ cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F);
+ cinfo->arith_dc_U[index] = (UINT8) (val >> 4);
+ if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index])
+ ERREXIT1(cinfo, JERR_DAC_VALUE, val);
+ }
+ }
+
+ if (length != 0)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+#else /* ! D_ARITH_CODING_SUPPORTED */
+
+#define get_dac(cinfo) skip_variable(cinfo)
+
+#endif /* D_ARITH_CODING_SUPPORTED */
+
+
+LOCAL(boolean)
+get_dht (j_decompress_ptr cinfo)
+/* Process a DHT marker */
+{
+ INT32 length;
+ UINT8 bits[17];
+ UINT8 huffval[256];
+ int i, index, count;
+ JHUFF_TBL **htblptr;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 16) {
+ INPUT_BYTE(cinfo, index, return FALSE);
+
+ TRACEMS1(cinfo, 1, JTRC_DHT, index);
+
+ bits[0] = 0;
+ count = 0;
+ for (i = 1; i <= 16; i++) {
+ INPUT_BYTE(cinfo, bits[i], return FALSE);
+ count += bits[i];
+ }
+
+ length -= 1 + 16;
+
+ TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+ bits[1], bits[2], bits[3], bits[4],
+ bits[5], bits[6], bits[7], bits[8]);
+ TRACEMS8(cinfo, 2, JTRC_HUFFBITS,
+ bits[9], bits[10], bits[11], bits[12],
+ bits[13], bits[14], bits[15], bits[16]);
+
+ /* Here we just do minimal validation of the counts to avoid walking
+ * off the end of our table space. jdhuff.c will check more carefully.
+ */
+ if (count > 256 || ((INT32) count) > length)
+ ERREXIT(cinfo, JERR_BAD_HUFF_TABLE);
+
+ for (i = 0; i < count; i++)
+ INPUT_BYTE(cinfo, huffval[i], return FALSE);
+
+ length -= count;
+
+ if (index & 0x10) { /* AC table definition */
+ index -= 0x10;
+ htblptr = &cinfo->ac_huff_tbl_ptrs[index];
+ } else { /* DC table definition */
+ htblptr = &cinfo->dc_huff_tbl_ptrs[index];
+ }
+
+ if (index < 0 || index >= NUM_HUFF_TBLS)
+ ERREXIT1(cinfo, JERR_DHT_INDEX, index);
+
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo);
+
+ MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits));
+ MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval));
+ }
+
+ if (length != 0)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dqt (j_decompress_ptr cinfo)
+/* Process a DQT marker */
+{
+ INT32 length, count, i;
+ int n, prec;
+ unsigned int tmp;
+ JQUANT_TBL *quant_ptr;
+ const int *natural_order;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ while (length > 0) {
+ length--;
+ INPUT_BYTE(cinfo, n, return FALSE);
+ prec = n >> 4;
+ n &= 0x0F;
+
+ TRACEMS2(cinfo, 1, JTRC_DQT, n, prec);
+
+ if (n >= NUM_QUANT_TBLS)
+ ERREXIT1(cinfo, JERR_DQT_INDEX, n);
+
+ if (cinfo->quant_tbl_ptrs[n] == NULL)
+ cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo);
+ quant_ptr = cinfo->quant_tbl_ptrs[n];
+
+ if (prec) {
+ if (length < DCTSIZE2 * 2) {
+ /* Initialize full table for safety. */
+ for (i = 0; i < DCTSIZE2; i++) {
+ quant_ptr->quantval[i] = 1;
+ }
+ count = length >> 1;
+ } else
+ count = DCTSIZE2;
+ } else {
+ if (length < DCTSIZE2) {
+ /* Initialize full table for safety. */
+ for (i = 0; i < DCTSIZE2; i++) {
+ quant_ptr->quantval[i] = 1;
+ }
+ count = length;
+ } else
+ count = DCTSIZE2;
+ }
+
+ switch (count) {
+ case (2*2): natural_order = jpeg_natural_order2; break;
+ case (3*3): natural_order = jpeg_natural_order3; break;
+ case (4*4): natural_order = jpeg_natural_order4; break;
+ case (5*5): natural_order = jpeg_natural_order5; break;
+ case (6*6): natural_order = jpeg_natural_order6; break;
+ case (7*7): natural_order = jpeg_natural_order7; break;
+ default: natural_order = jpeg_natural_order; break;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (prec)
+ INPUT_2BYTES(cinfo, tmp, return FALSE);
+ else
+ INPUT_BYTE(cinfo, tmp, return FALSE);
+ /* We convert the zigzag-order table to natural array order. */
+ quant_ptr->quantval[natural_order[i]] = (UINT16) tmp;
+ }
+
+ if (cinfo->err->trace_level >= 2) {
+ for (i = 0; i < DCTSIZE2; i += 8) {
+ TRACEMS8(cinfo, 2, JTRC_QUANTVALS,
+ quant_ptr->quantval[i], quant_ptr->quantval[i+1],
+ quant_ptr->quantval[i+2], quant_ptr->quantval[i+3],
+ quant_ptr->quantval[i+4], quant_ptr->quantval[i+5],
+ quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]);
+ }
+ }
+
+ length -= count;
+ if (prec) length -= count;
+ }
+
+ if (length != 0)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+get_dri (j_decompress_ptr cinfo)
+/* Process a DRI marker */
+{
+ INT32 length;
+ unsigned int tmp;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+
+ if (length != 4)
+ ERREXIT(cinfo, JERR_BAD_LENGTH);
+
+ INPUT_2BYTES(cinfo, tmp, return FALSE);
+
+ TRACEMS1(cinfo, 1, JTRC_DRI, tmp);
+
+ cinfo->restart_interval = tmp;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+/*
+ * Routines for processing APPn and COM markers.
+ * These are either saved in memory or discarded, per application request.
+ * APP0 and APP14 are specially checked to see if they are
+ * JFIF and Adobe markers, respectively.
+ */
+
+#define APP0_DATA_LEN 14 /* Length of interesting data in APP0 */
+#define APP14_DATA_LEN 12 /* Length of interesting data in APP14 */
+#define APPN_DATA_LEN 14 /* Must be the largest of the above!! */
+
+
+LOCAL(void)
+examine_app0 (j_decompress_ptr cinfo, JOCTET FAR * data,
+ unsigned int datalen, INT32 remaining)
+/* Examine first few bytes from an APP0.
+ * Take appropriate action if it is a JFIF marker.
+ * datalen is # of bytes at data[], remaining is length of rest of marker data.
+ */
+{
+ INT32 totallen = (INT32) datalen + remaining;
+
+ if (datalen >= APP0_DATA_LEN &&
+ GETJOCTET(data[0]) == 0x4A &&
+ GETJOCTET(data[1]) == 0x46 &&
+ GETJOCTET(data[2]) == 0x49 &&
+ GETJOCTET(data[3]) == 0x46 &&
+ GETJOCTET(data[4]) == 0) {
+ /* Found JFIF APP0 marker: save info */
+ cinfo->saw_JFIF_marker = TRUE;
+ cinfo->JFIF_major_version = GETJOCTET(data[5]);
+ cinfo->JFIF_minor_version = GETJOCTET(data[6]);
+ cinfo->density_unit = GETJOCTET(data[7]);
+ cinfo->X_density = (GETJOCTET(data[8]) << 8) + GETJOCTET(data[9]);
+ cinfo->Y_density = (GETJOCTET(data[10]) << 8) + GETJOCTET(data[11]);
+ /* Check version.
+ * Major version must be 1, anything else signals an incompatible change.
+ * (We used to treat this as an error, but now it's a nonfatal warning,
+ * because some bozo at Hijaak couldn't read the spec.)
+ * Minor version should be 0..2, but process anyway if newer.
+ */
+ if (cinfo->JFIF_major_version != 1)
+ WARNMS2(cinfo, JWRN_JFIF_MAJOR,
+ cinfo->JFIF_major_version, cinfo->JFIF_minor_version);
+ /* Generate trace messages */
+ TRACEMS5(cinfo, 1, JTRC_JFIF,
+ cinfo->JFIF_major_version, cinfo->JFIF_minor_version,
+ cinfo->X_density, cinfo->Y_density, cinfo->density_unit);
+ /* Validate thumbnail dimensions and issue appropriate messages */
+ if (GETJOCTET(data[12]) | GETJOCTET(data[13]))
+ TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL,
+ GETJOCTET(data[12]), GETJOCTET(data[13]));
+ totallen -= APP0_DATA_LEN;
+ if (totallen !=
+ ((INT32)GETJOCTET(data[12]) * (INT32)GETJOCTET(data[13]) * (INT32) 3))
+ TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) totallen);
+ } else if (datalen >= 6 &&
+ GETJOCTET(data[0]) == 0x4A &&
+ GETJOCTET(data[1]) == 0x46 &&
+ GETJOCTET(data[2]) == 0x58 &&
+ GETJOCTET(data[3]) == 0x58 &&
+ GETJOCTET(data[4]) == 0) {
+ /* Found JFIF "JFXX" extension APP0 marker */
+ /* The library doesn't actually do anything with these,
+ * but we try to produce a helpful trace message.
+ */
+ switch (GETJOCTET(data[5])) {
+ case 0x10:
+ TRACEMS1(cinfo, 1, JTRC_THUMB_JPEG, (int) totallen);
+ break;
+ case 0x11:
+ TRACEMS1(cinfo, 1, JTRC_THUMB_PALETTE, (int) totallen);
+ break;
+ case 0x13:
+ TRACEMS1(cinfo, 1, JTRC_THUMB_RGB, (int) totallen);
+ break;
+ default:
+ TRACEMS2(cinfo, 1, JTRC_JFIF_EXTENSION,
+ GETJOCTET(data[5]), (int) totallen);
+ break;
+ }
+ } else {
+ /* Start of APP0 does not match "JFIF" or "JFXX", or too short */
+ TRACEMS1(cinfo, 1, JTRC_APP0, (int) totallen);
+ }
+}
+
+
+LOCAL(void)
+examine_app14 (j_decompress_ptr cinfo, JOCTET FAR * data,
+ unsigned int datalen, INT32 remaining)
+/* Examine first few bytes from an APP14.
+ * Take appropriate action if it is an Adobe marker.
+ * datalen is # of bytes at data[], remaining is length of rest of marker data.
+ */
+{
+ unsigned int version, flags0, flags1, transform;
+
+ if (datalen >= APP14_DATA_LEN &&
+ GETJOCTET(data[0]) == 0x41 &&
+ GETJOCTET(data[1]) == 0x64 &&
+ GETJOCTET(data[2]) == 0x6F &&
+ GETJOCTET(data[3]) == 0x62 &&
+ GETJOCTET(data[4]) == 0x65) {
+ /* Found Adobe APP14 marker */
+ version = (GETJOCTET(data[5]) << 8) + GETJOCTET(data[6]);
+ flags0 = (GETJOCTET(data[7]) << 8) + GETJOCTET(data[8]);
+ flags1 = (GETJOCTET(data[9]) << 8) + GETJOCTET(data[10]);
+ transform = GETJOCTET(data[11]);
+ TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform);
+ cinfo->saw_Adobe_marker = TRUE;
+ cinfo->Adobe_transform = (UINT8) transform;
+ } else {
+ /* Start of APP14 does not match "Adobe", or too short */
+ TRACEMS1(cinfo, 1, JTRC_APP14, (int) (datalen + remaining));
+ }
+}
+
+
+METHODDEF(boolean)
+get_interesting_appn (j_decompress_ptr cinfo)
+/* Process an APP0 or APP14 marker without saving it */
+{
+ INT32 length;
+ JOCTET b[APPN_DATA_LEN];
+ unsigned int i, numtoread;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ /* get the interesting part of the marker data */
+ if (length >= APPN_DATA_LEN)
+ numtoread = APPN_DATA_LEN;
+ else if (length > 0)
+ numtoread = (unsigned int) length;
+ else
+ numtoread = 0;
+ for (i = 0; i < numtoread; i++)
+ INPUT_BYTE(cinfo, b[i], return FALSE);
+ length -= numtoread;
+
+ /* process it */
+ switch (cinfo->unread_marker) {
+ case M_APP0:
+ examine_app0(cinfo, (JOCTET FAR *) b, numtoread, length);
+ break;
+ case M_APP14:
+ examine_app14(cinfo, (JOCTET FAR *) b, numtoread, length);
+ break;
+ default:
+ /* can't get here unless jpeg_save_markers chooses wrong processor */
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
+ break;
+ }
+
+ /* skip any remaining data -- could be lots */
+ INPUT_SYNC(cinfo);
+ if (length > 0)
+ (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+ return TRUE;
+}
+
+
+#ifdef SAVE_MARKERS_SUPPORTED
+
+METHODDEF(boolean)
+save_marker (j_decompress_ptr cinfo)
+/* Save an APPn or COM marker into the marker list */
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+ jpeg_saved_marker_ptr cur_marker = marker->cur_marker;
+ unsigned int bytes_read, data_length;
+ JOCTET FAR * data;
+ INT32 length = 0;
+ INPUT_VARS(cinfo);
+
+ if (cur_marker == NULL) {
+ /* begin reading a marker */
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+ if (length >= 0) { /* watch out for bogus length word */
+ /* figure out how much we want to save */
+ unsigned int limit;
+ if (cinfo->unread_marker == (int) M_COM)
+ limit = marker->length_limit_COM;
+ else
+ limit = marker->length_limit_APPn[cinfo->unread_marker - (int) M_APP0];
+ if ((unsigned int) length < limit)
+ limit = (unsigned int) length;
+ /* allocate and initialize the marker item */
+ cur_marker = (jpeg_saved_marker_ptr)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(struct jpeg_marker_struct) + limit);
+ cur_marker->next = NULL;
+ cur_marker->marker = (UINT8) cinfo->unread_marker;
+ cur_marker->original_length = (unsigned int) length;
+ cur_marker->data_length = limit;
+ /* data area is just beyond the jpeg_marker_struct */
+ data = cur_marker->data = (JOCTET FAR *) (cur_marker + 1);
+ marker->cur_marker = cur_marker;
+ marker->bytes_read = 0;
+ bytes_read = 0;
+ data_length = limit;
+ } else {
+ /* deal with bogus length word */
+ bytes_read = data_length = 0;
+ data = NULL;
+ }
+ } else {
+ /* resume reading a marker */
+ bytes_read = marker->bytes_read;
+ data_length = cur_marker->data_length;
+ data = cur_marker->data + bytes_read;
+ }
+
+ while (bytes_read < data_length) {
+ INPUT_SYNC(cinfo); /* move the restart point to here */
+ marker->bytes_read = bytes_read;
+ /* If there's not at least one byte in buffer, suspend */
+ MAKE_BYTE_AVAIL(cinfo, return FALSE);
+ /* Copy bytes with reasonable rapidity */
+ while (bytes_read < data_length && bytes_in_buffer > 0) {
+ *data++ = *next_input_byte++;
+ bytes_in_buffer--;
+ bytes_read++;
+ }
+ }
+
+ /* Done reading what we want to read */
+ if (cur_marker != NULL) { /* will be NULL if bogus length word */
+ /* Add new marker to end of list */
+ if (cinfo->marker_list == NULL) {
+ cinfo->marker_list = cur_marker;
+ } else {
+ jpeg_saved_marker_ptr prev = cinfo->marker_list;
+ while (prev->next != NULL)
+ prev = prev->next;
+ prev->next = cur_marker;
+ }
+ /* Reset pointer & calc remaining data length */
+ data = cur_marker->data;
+ length = cur_marker->original_length - data_length;
+ }
+ /* Reset to initial state for next marker */
+ marker->cur_marker = NULL;
+
+ /* Process the marker if interesting; else just make a generic trace msg */
+ switch (cinfo->unread_marker) {
+ case M_APP0:
+ examine_app0(cinfo, data, data_length, length);
+ break;
+ case M_APP14:
+ examine_app14(cinfo, data, data_length, length);
+ break;
+ default:
+ TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker,
+ (int) (data_length + length));
+ break;
+ }
+
+ /* skip any remaining data -- could be lots */
+ INPUT_SYNC(cinfo); /* do before skip_input_data */
+ if (length > 0)
+ (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+ return TRUE;
+}
+
+#endif /* SAVE_MARKERS_SUPPORTED */
+
+
+METHODDEF(boolean)
+skip_variable (j_decompress_ptr cinfo)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ INT32 length;
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length);
+
+ INPUT_SYNC(cinfo); /* do before skip_input_data */
+ if (length > 0)
+ (*cinfo->src->skip_input_data) (cinfo, (long) length);
+
+ return TRUE;
+}
+
+
+/*
+ * Find the next JPEG marker, save it in cinfo->unread_marker.
+ * Returns FALSE if had to suspend before reaching a marker;
+ * in that case cinfo->unread_marker is unchanged.
+ *
+ * Note that the result might not be a valid marker code,
+ * but it will never be 0 or FF.
+ */
+
+LOCAL(boolean)
+next_marker (j_decompress_ptr cinfo)
+{
+ int c;
+ INPUT_VARS(cinfo);
+
+ for (;;) {
+ INPUT_BYTE(cinfo, c, return FALSE);
+ /* Skip any non-FF bytes.
+ * This may look a bit inefficient, but it will not occur in a valid file.
+ * We sync after each discarded byte so that a suspending data source
+ * can discard the byte from its buffer.
+ */
+ while (c != 0xFF) {
+ cinfo->marker->discarded_bytes++;
+ INPUT_SYNC(cinfo);
+ INPUT_BYTE(cinfo, c, return FALSE);
+ }
+ /* This loop swallows any duplicate FF bytes. Extra FFs are legal as
+ * pad bytes, so don't count them in discarded_bytes. We assume there
+ * will not be so many consecutive FF bytes as to overflow a suspending
+ * data source's input buffer.
+ */
+ do {
+ INPUT_BYTE(cinfo, c, return FALSE);
+ } while (c == 0xFF);
+ if (c != 0)
+ break; /* found a valid marker, exit loop */
+ /* Reach here if we found a stuffed-zero data sequence (FF/00).
+ * Discard it and loop back to try again.
+ */
+ cinfo->marker->discarded_bytes += 2;
+ INPUT_SYNC(cinfo);
+ }
+
+ if (cinfo->marker->discarded_bytes != 0) {
+ WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c);
+ cinfo->marker->discarded_bytes = 0;
+ }
+
+ cinfo->unread_marker = c;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+LOCAL(boolean)
+first_marker (j_decompress_ptr cinfo)
+/* Like next_marker, but used to obtain the initial SOI marker. */
+/* For this marker, we do not allow preceding garbage or fill; otherwise,
+ * we might well scan an entire input file before realizing it ain't JPEG.
+ * If an application wants to process non-JFIF files, it must seek to the
+ * SOI before calling the JPEG library.
+ */
+{
+ int c, c2;
+ INPUT_VARS(cinfo);
+
+ INPUT_BYTE(cinfo, c, return FALSE);
+ INPUT_BYTE(cinfo, c2, return FALSE);
+ if (c != 0xFF || c2 != (int) M_SOI)
+ ERREXIT2(cinfo, JERR_NO_SOI, c, c2);
+
+ cinfo->unread_marker = c2;
+
+ INPUT_SYNC(cinfo);
+ return TRUE;
+}
+
+
+/*
+ * Read markers until SOS or EOI.
+ *
+ * Returns same codes as are defined for jpeg_consume_input:
+ * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ *
+ * Note: This function may return a pseudo SOS marker (with zero
+ * component number) for treat by input controller's consume_input.
+ * consume_input itself should filter out (skip) the pseudo marker
+ * after processing for the caller.
+ */
+
+METHODDEF(int)
+read_markers (j_decompress_ptr cinfo)
+{
+ /* Outer loop repeats once for each marker. */
+ for (;;) {
+ /* Collect the marker proper, unless we already did. */
+ /* NB: first_marker() enforces the requirement that SOI appear first. */
+ if (cinfo->unread_marker == 0) {
+ if (! cinfo->marker->saw_SOI) {
+ if (! first_marker(cinfo))
+ return JPEG_SUSPENDED;
+ } else {
+ if (! next_marker(cinfo))
+ return JPEG_SUSPENDED;
+ }
+ }
+ /* At this point cinfo->unread_marker contains the marker code and the
+ * input point is just past the marker proper, but before any parameters.
+ * A suspension will cause us to return with this state still true.
+ */
+ switch (cinfo->unread_marker) {
+ case M_SOI:
+ if (! get_soi(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF0: /* Baseline */
+ if (! get_sof(cinfo, TRUE, FALSE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF1: /* Extended sequential, Huffman */
+ if (! get_sof(cinfo, FALSE, FALSE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF2: /* Progressive, Huffman */
+ if (! get_sof(cinfo, FALSE, TRUE, FALSE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF9: /* Extended sequential, arithmetic */
+ if (! get_sof(cinfo, FALSE, FALSE, TRUE))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_SOF10: /* Progressive, arithmetic */
+ if (! get_sof(cinfo, FALSE, TRUE, TRUE))
+ return JPEG_SUSPENDED;
+ break;
+
+ /* Currently unsupported SOFn types */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_JPG: /* Reserved for JPEG extensions */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker);
+ break;
+
+ case M_SOS:
+ if (! get_sos(cinfo))
+ return JPEG_SUSPENDED;
+ cinfo->unread_marker = 0; /* processed the marker */
+ return JPEG_REACHED_SOS;
+
+ case M_EOI:
+ TRACEMS(cinfo, 1, JTRC_EOI);
+ cinfo->unread_marker = 0; /* processed the marker */
+ return JPEG_REACHED_EOI;
+
+ case M_DAC:
+ if (! get_dac(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DHT:
+ if (! get_dht(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DQT:
+ if (! get_dqt(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_DRI:
+ if (! get_dri(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_APP0:
+ case M_APP1:
+ case M_APP2:
+ case M_APP3:
+ case M_APP4:
+ case M_APP5:
+ case M_APP6:
+ case M_APP7:
+ case M_APP8:
+ case M_APP9:
+ case M_APP10:
+ case M_APP11:
+ case M_APP12:
+ case M_APP13:
+ case M_APP14:
+ case M_APP15:
+ if (! (*((my_marker_ptr) cinfo->marker)->process_APPn[
+ cinfo->unread_marker - (int) M_APP0]) (cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_COM:
+ if (! (*((my_marker_ptr) cinfo->marker)->process_COM) (cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ case M_RST0: /* these are all parameterless */
+ case M_RST1:
+ case M_RST2:
+ case M_RST3:
+ case M_RST4:
+ case M_RST5:
+ case M_RST6:
+ case M_RST7:
+ case M_TEM:
+ TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker);
+ break;
+
+ case M_DNL: /* Ignore DNL ... perhaps the wrong thing */
+ if (! skip_variable(cinfo))
+ return JPEG_SUSPENDED;
+ break;
+
+ default: /* must be DHP, EXP, JPGn, or RESn */
+ /* For now, we treat the reserved markers as fatal errors since they are
+ * likely to be used to signal incompatible JPEG Part 3 extensions.
+ * Once the JPEG 3 version-number marker is well defined, this code
+ * ought to change!
+ */
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker);
+ break;
+ }
+ /* Successfully processed marker, so reset state variable */
+ cinfo->unread_marker = 0;
+ } /* end loop */
+}
+
+
+/*
+ * Read a restart marker, which is expected to appear next in the datastream;
+ * if the marker is not there, take appropriate recovery action.
+ * Returns FALSE if suspension is required.
+ *
+ * This is called by the entropy decoder after it has read an appropriate
+ * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder
+ * has already read a marker from the data source. Under normal conditions
+ * cinfo->unread_marker will be reset to 0 before returning; if not reset,
+ * it holds a marker which the decoder will be unable to read past.
+ */
+
+METHODDEF(boolean)
+read_restart_marker (j_decompress_ptr cinfo)
+{
+ /* Obtain a marker unless we already did. */
+ /* Note that next_marker will complain if it skips any data. */
+ if (cinfo->unread_marker == 0) {
+ if (! next_marker(cinfo))
+ return FALSE;
+ }
+
+ if (cinfo->unread_marker ==
+ ((int) M_RST0 + cinfo->marker->next_restart_num)) {
+ /* Normal case --- swallow the marker and let entropy decoder continue */
+ TRACEMS1(cinfo, 3, JTRC_RST, cinfo->marker->next_restart_num);
+ cinfo->unread_marker = 0;
+ } else {
+ /* Uh-oh, the restart markers have been messed up. */
+ /* Let the data source manager determine how to resync. */
+ if (! (*cinfo->src->resync_to_restart) (cinfo,
+ cinfo->marker->next_restart_num))
+ return FALSE;
+ }
+
+ /* Update next-restart state */
+ cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7;
+
+ return TRUE;
+}
+
+
+/*
+ * This is the default resync_to_restart method for data source managers
+ * to use if they don't have any better approach. Some data source managers
+ * may be able to back up, or may have additional knowledge about the data
+ * which permits a more intelligent recovery strategy; such managers would
+ * presumably supply their own resync method.
+ *
+ * read_restart_marker calls resync_to_restart if it finds a marker other than
+ * the restart marker it was expecting. (This code is *not* used unless
+ * a nonzero restart interval has been declared.) cinfo->unread_marker is
+ * the marker code actually found (might be anything, except 0 or FF).
+ * The desired restart marker number (0..7) is passed as a parameter.
+ * This routine is supposed to apply whatever error recovery strategy seems
+ * appropriate in order to position the input stream to the next data segment.
+ * Note that cinfo->unread_marker is treated as a marker appearing before
+ * the current data-source input point; usually it should be reset to zero
+ * before returning.
+ * Returns FALSE if suspension is required.
+ *
+ * This implementation is substantially constrained by wanting to treat the
+ * input as a data stream; this means we can't back up. Therefore, we have
+ * only the following actions to work with:
+ * 1. Simply discard the marker and let the entropy decoder resume at next
+ * byte of file.
+ * 2. Read forward until we find another marker, discarding intervening
+ * data. (In theory we could look ahead within the current bufferload,
+ * without having to discard data if we don't find the desired marker.
+ * This idea is not implemented here, in part because it makes behavior
+ * dependent on buffer size and chance buffer-boundary positions.)
+ * 3. Leave the marker unread (by failing to zero cinfo->unread_marker).
+ * This will cause the entropy decoder to process an empty data segment,
+ * inserting dummy zeroes, and then we will reprocess the marker.
+ *
+ * #2 is appropriate if we think the desired marker lies ahead, while #3 is
+ * appropriate if the found marker is a future restart marker (indicating
+ * that we have missed the desired restart marker, probably because it got
+ * corrupted).
+ * We apply #2 or #3 if the found marker is a restart marker no more than
+ * two counts behind or ahead of the expected one. We also apply #2 if the
+ * found marker is not a legal JPEG marker code (it's certainly bogus data).
+ * If the found marker is a restart marker more than 2 counts away, we do #1
+ * (too much risk that the marker is erroneous; with luck we will be able to
+ * resync at some future point).
+ * For any valid non-restart JPEG marker, we apply #3. This keeps us from
+ * overrunning the end of a scan. An implementation limited to single-scan
+ * files might find it better to apply #2 for markers other than EOI, since
+ * any other marker would have to be bogus data in that case.
+ */
+
+GLOBAL(boolean)
+jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired)
+{
+ int marker = cinfo->unread_marker;
+ int action = 1;
+
+ /* Always put up a warning. */
+ WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired);
+
+ /* Outer loop handles repeated decision after scanning forward. */
+ for (;;) {
+ if (marker < (int) M_SOF0)
+ action = 2; /* invalid marker */
+ else if (marker < (int) M_RST0 || marker > (int) M_RST7)
+ action = 3; /* valid non-restart marker */
+ else {
+ if (marker == ((int) M_RST0 + ((desired+1) & 7)) ||
+ marker == ((int) M_RST0 + ((desired+2) & 7)))
+ action = 3; /* one of the next two expected restarts */
+ else if (marker == ((int) M_RST0 + ((desired-1) & 7)) ||
+ marker == ((int) M_RST0 + ((desired-2) & 7)))
+ action = 2; /* a prior restart, so advance */
+ else
+ action = 1; /* desired restart or too far away */
+ }
+ TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action);
+ switch (action) {
+ case 1:
+ /* Discard marker and let entropy decoder resume processing. */
+ cinfo->unread_marker = 0;
+ return TRUE;
+ case 2:
+ /* Scan to the next marker, and repeat the decision loop. */
+ if (! next_marker(cinfo))
+ return FALSE;
+ marker = cinfo->unread_marker;
+ break;
+ case 3:
+ /* Return without advancing past this marker. */
+ /* Entropy decoder will be forced to process an empty segment. */
+ return TRUE;
+ }
+ } /* end loop */
+}
+
+
+/*
+ * Reset marker processing state to begin a fresh datastream.
+ */
+
+METHODDEF(void)
+reset_marker_reader (j_decompress_ptr cinfo)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+ cinfo->comp_info = NULL; /* until allocated by get_sof */
+ cinfo->input_scan_number = 0; /* no SOS seen yet */
+ cinfo->unread_marker = 0; /* no pending marker */
+ marker->pub.saw_SOI = FALSE; /* set internal state too */
+ marker->pub.saw_SOF = FALSE;
+ marker->pub.discarded_bytes = 0;
+ marker->cur_marker = NULL;
+}
+
+
+/*
+ * Initialize the marker reader module.
+ * This is called only once, when the decompression object is created.
+ */
+
+GLOBAL(void)
+jinit_marker_reader (j_decompress_ptr cinfo)
+{
+ my_marker_ptr marker;
+ int i;
+
+ /* Create subobject in permanent pool */
+ marker = (my_marker_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ SIZEOF(my_marker_reader));
+ cinfo->marker = (struct jpeg_marker_reader *) marker;
+ /* Initialize public method pointers */
+ marker->pub.reset_marker_reader = reset_marker_reader;
+ marker->pub.read_markers = read_markers;
+ marker->pub.read_restart_marker = read_restart_marker;
+ /* Initialize COM/APPn processing.
+ * By default, we examine and then discard APP0 and APP14,
+ * but simply discard COM and all other APPn.
+ */
+ marker->process_COM = skip_variable;
+ marker->length_limit_COM = 0;
+ for (i = 0; i < 16; i++) {
+ marker->process_APPn[i] = skip_variable;
+ marker->length_limit_APPn[i] = 0;
+ }
+ marker->process_APPn[0] = get_interesting_appn;
+ marker->process_APPn[14] = get_interesting_appn;
+ /* Reset marker processing state */
+ reset_marker_reader(cinfo);
+}
+
+
+/*
+ * Control saving of COM and APPn markers into marker_list.
+ */
+
+#ifdef SAVE_MARKERS_SUPPORTED
+
+GLOBAL(void)
+jpeg_save_markers (j_decompress_ptr cinfo, int marker_code,
+ unsigned int length_limit)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+ long maxlength;
+ jpeg_marker_parser_method processor;
+
+ /* Length limit mustn't be larger than what we can allocate
+ * (should only be a concern in a 16-bit environment).
+ */
+ maxlength = cinfo->mem->max_alloc_chunk - SIZEOF(struct jpeg_marker_struct);
+ if (((long) length_limit) > maxlength)
+ length_limit = (unsigned int) maxlength;
+
+ /* Choose processor routine to use.
+ * APP0/APP14 have special requirements.
+ */
+ if (length_limit) {
+ processor = save_marker;
+ /* If saving APP0/APP14, save at least enough for our internal use. */
+ if (marker_code == (int) M_APP0 && length_limit < APP0_DATA_LEN)
+ length_limit = APP0_DATA_LEN;
+ else if (marker_code == (int) M_APP14 && length_limit < APP14_DATA_LEN)
+ length_limit = APP14_DATA_LEN;
+ } else {
+ processor = skip_variable;
+ /* If discarding APP0/APP14, use our regular on-the-fly processor. */
+ if (marker_code == (int) M_APP0 || marker_code == (int) M_APP14)
+ processor = get_interesting_appn;
+ }
+
+ if (marker_code == (int) M_COM) {
+ marker->process_COM = processor;
+ marker->length_limit_COM = length_limit;
+ } else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15) {
+ marker->process_APPn[marker_code - (int) M_APP0] = processor;
+ marker->length_limit_APPn[marker_code - (int) M_APP0] = length_limit;
+ } else
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
+}
+
+#endif /* SAVE_MARKERS_SUPPORTED */
+
+
+/*
+ * Install a special processing method for COM or APPn markers.
+ */
+
+GLOBAL(void)
+jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code,
+ jpeg_marker_parser_method routine)
+{
+ my_marker_ptr marker = (my_marker_ptr) cinfo->marker;
+
+ if (marker_code == (int) M_COM)
+ marker->process_COM = routine;
+ else if (marker_code >= (int) M_APP0 && marker_code <= (int) M_APP15)
+ marker->process_APPn[marker_code - (int) M_APP0] = routine;
+ else
+ ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code);
+}
diff --git a/jpg/jdmaster.c b/jpg/jdmaster.c
new file mode 100644
index 0000000..fef72a2
--- /dev/null
+++ b/jpg/jdmaster.c
@@ -0,0 +1,531 @@
+/*
+ * jdmaster.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2002-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains master control logic for the JPEG decompressor.
+ * These routines are concerned with selecting the modules to be executed
+ * and with determining the number of passes and the work to be done in each
+ * pass.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private state */
+
+typedef struct {
+ struct jpeg_decomp_master pub; /* public fields */
+
+ int pass_number; /* # of passes completed */
+
+ boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */
+
+ /* Saved references to initialized quantizer modules,
+ * in case we need to switch modes.
+ */
+ struct jpeg_color_quantizer * quantizer_1pass;
+ struct jpeg_color_quantizer * quantizer_2pass;
+} my_decomp_master;
+
+typedef my_decomp_master * my_master_ptr;
+
+
+/*
+ * Determine whether merged upsample/color conversion should be used.
+ * CRUCIAL: this must match the actual capabilities of jdmerge.c!
+ */
+
+LOCAL(boolean)
+use_merged_upsample (j_decompress_ptr cinfo)
+{
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ /* Merging is the equivalent of plain box-filter upsampling */
+ if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling)
+ return FALSE;
+ /* jdmerge.c only supports YCC=>RGB color conversion */
+ if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 ||
+ cinfo->out_color_space != JCS_RGB ||
+ cinfo->out_color_components != RGB_PIXELSIZE)
+ return FALSE;
+ /* and it only handles 2h1v or 2h2v sampling ratios */
+ if (cinfo->comp_info[0].h_samp_factor != 2 ||
+ cinfo->comp_info[1].h_samp_factor != 1 ||
+ cinfo->comp_info[2].h_samp_factor != 1 ||
+ cinfo->comp_info[0].v_samp_factor > 2 ||
+ cinfo->comp_info[1].v_samp_factor != 1 ||
+ cinfo->comp_info[2].v_samp_factor != 1)
+ return FALSE;
+ /* furthermore, it doesn't work if we've scaled the IDCTs differently */
+ if (cinfo->comp_info[0].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+ cinfo->comp_info[1].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+ cinfo->comp_info[2].DCT_h_scaled_size != cinfo->min_DCT_h_scaled_size ||
+ cinfo->comp_info[0].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size ||
+ cinfo->comp_info[1].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size ||
+ cinfo->comp_info[2].DCT_v_scaled_size != cinfo->min_DCT_v_scaled_size)
+ return FALSE;
+ /* ??? also need to test for upsample-time rescaling, when & if supported */
+ return TRUE; /* by golly, it'll work... */
+#else
+ return FALSE;
+#endif
+}
+
+
+/*
+ * Compute output image dimensions and related values.
+ * NOTE: this is exported for possible use by application.
+ * Hence it mustn't do anything that can't be done twice.
+ * Also note that it may be called before the master module is initialized!
+ */
+
+GLOBAL(void)
+jpeg_calc_output_dimensions (j_decompress_ptr cinfo)
+/* Do computations that are needed before master selection phase.
+ * This function is used for full decompression.
+ */
+{
+#ifdef IDCT_SCALING_SUPPORTED
+ int ci;
+ jpeg_component_info *compptr;
+#endif
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_READY)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ /* Compute core output image dimensions and DCT scaling choices. */
+ jpeg_core_output_dimensions(cinfo);
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+ /* In selecting the actual DCT scaling for each component, we try to
+ * scale up the chroma components via IDCT scaling rather than upsampling.
+ * This saves time if the upsampler gets to use 1:1 scaling.
+ * Note this code adapts subsampling ratios which are powers of 2.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ int ssize = 1;
+ while (cinfo->min_DCT_h_scaled_size * ssize <=
+ (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) &&
+ (cinfo->max_h_samp_factor % (compptr->h_samp_factor * ssize * 2)) == 0) {
+ ssize = ssize * 2;
+ }
+ compptr->DCT_h_scaled_size = cinfo->min_DCT_h_scaled_size * ssize;
+ ssize = 1;
+ while (cinfo->min_DCT_v_scaled_size * ssize <=
+ (cinfo->do_fancy_upsampling ? DCTSIZE : DCTSIZE / 2) &&
+ (cinfo->max_v_samp_factor % (compptr->v_samp_factor * ssize * 2)) == 0) {
+ ssize = ssize * 2;
+ }
+ compptr->DCT_v_scaled_size = cinfo->min_DCT_v_scaled_size * ssize;
+
+ /* We don't support IDCT ratios larger than 2. */
+ if (compptr->DCT_h_scaled_size > compptr->DCT_v_scaled_size * 2)
+ compptr->DCT_h_scaled_size = compptr->DCT_v_scaled_size * 2;
+ else if (compptr->DCT_v_scaled_size > compptr->DCT_h_scaled_size * 2)
+ compptr->DCT_v_scaled_size = compptr->DCT_h_scaled_size * 2;
+ }
+
+ /* Recompute downsampled dimensions of components;
+ * application needs to know these if using raw downsampled data.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Size in samples, after IDCT scaling */
+ compptr->downsampled_width = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_width *
+ (long) (compptr->h_samp_factor * compptr->DCT_h_scaled_size),
+ (long) (cinfo->max_h_samp_factor * cinfo->block_size));
+ compptr->downsampled_height = (JDIMENSION)
+ jdiv_round_up((long) cinfo->image_height *
+ (long) (compptr->v_samp_factor * compptr->DCT_v_scaled_size),
+ (long) (cinfo->max_v_samp_factor * cinfo->block_size));
+ }
+
+#endif /* IDCT_SCALING_SUPPORTED */
+
+ /* Report number of components in selected colorspace. */
+ /* Probably this should be in the color conversion module... */
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ cinfo->out_color_components = 1;
+ break;
+ case JCS_RGB:
+ cinfo->out_color_components = RGB_PIXELSIZE;
+ break;
+ case JCS_YCbCr:
+ cinfo->out_color_components = 3;
+ break;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ cinfo->out_color_components = 4;
+ break;
+ default: /* else must be same colorspace as in file */
+ cinfo->out_color_components = cinfo->num_components;
+ break;
+ }
+ cinfo->output_components = (cinfo->quantize_colors ? 1 :
+ cinfo->out_color_components);
+
+ /* See if upsampler will want to emit more than one row at a time */
+ if (use_merged_upsample(cinfo))
+ cinfo->rec_outbuf_height = cinfo->max_v_samp_factor;
+ else
+ cinfo->rec_outbuf_height = 1;
+}
+
+
+/*
+ * Several decompression processes need to range-limit values to the range
+ * 0..MAXJSAMPLE; the input value may fall somewhat outside this range
+ * due to noise introduced by quantization, roundoff error, etc. These
+ * processes are inner loops and need to be as fast as possible. On most
+ * machines, particularly CPUs with pipelines or instruction prefetch,
+ * a (subscript-check-less) C table lookup
+ * x = sample_range_limit[x];
+ * is faster than explicit tests
+ * if (x < 0) x = 0;
+ * else if (x > MAXJSAMPLE) x = MAXJSAMPLE;
+ * These processes all use a common table prepared by the routine below.
+ *
+ * For most steps we can mathematically guarantee that the initial value
+ * of x is within MAXJSAMPLE+1 of the legal range, so a table running from
+ * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial
+ * limiting step (just after the IDCT), a wildly out-of-range value is
+ * possible if the input data is corrupt. To avoid any chance of indexing
+ * off the end of memory and getting a bad-pointer trap, we perform the
+ * post-IDCT limiting thus:
+ * x = range_limit[x & MASK];
+ * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit
+ * samples. Under normal circumstances this is more than enough range and
+ * a correct output will be generated; with bogus input data the mask will
+ * cause wraparound, and we will safely generate a bogus-but-in-range output.
+ * For the post-IDCT step, we want to convert the data from signed to unsigned
+ * representation by adding CENTERJSAMPLE at the same time that we limit it.
+ * So the post-IDCT limiting table ends up looking like this:
+ * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE,
+ * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times),
+ * 0,1,...,CENTERJSAMPLE-1
+ * Negative inputs select values from the upper half of the table after
+ * masking.
+ *
+ * We can save some space by overlapping the start of the post-IDCT table
+ * with the simpler range limiting table. The post-IDCT table begins at
+ * sample_range_limit + CENTERJSAMPLE.
+ *
+ * Note that the table is allocated in near data space on PCs; it's small
+ * enough and used often enough to justify this.
+ */
+
+LOCAL(void)
+prepare_range_limit_table (j_decompress_ptr cinfo)
+/* Allocate and fill in the sample_range_limit table */
+{
+ JSAMPLE * table;
+ int i;
+
+ table = (JSAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+ table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */
+ cinfo->sample_range_limit = table;
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE));
+ /* Main part of "simple" table: limit[x] = x */
+ for (i = 0; i <= MAXJSAMPLE; i++)
+ table[i] = (JSAMPLE) i;
+ table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++)
+ table[i] = MAXJSAMPLE;
+ /* Second half of post-IDCT table */
+ MEMZERO(table + (2 * (MAXJSAMPLE+1)),
+ (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE));
+ MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE),
+ cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE));
+}
+
+
+/*
+ * Master selection of decompression modules.
+ * This is done once at jpeg_start_decompress time. We determine
+ * which modules will be used and give them appropriate initialization calls.
+ * We also initialize the decompressor input side to begin consuming data.
+ *
+ * Since jpeg_read_header has finished, we know what is in the SOF
+ * and (first) SOS markers. We also have all the application parameter
+ * settings.
+ */
+
+LOCAL(void)
+master_selection (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+ boolean use_c_buffer;
+ long samplesperrow;
+ JDIMENSION jd_samplesperrow;
+
+ /* Initialize dimensions and other stuff */
+ jpeg_calc_output_dimensions(cinfo);
+ prepare_range_limit_table(cinfo);
+
+ /* Width of an output scanline must be representable as JDIMENSION. */
+ samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components;
+ jd_samplesperrow = (JDIMENSION) samplesperrow;
+ if ((long) jd_samplesperrow != samplesperrow)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+
+ /* Initialize my private state */
+ master->pass_number = 0;
+ master->using_merged_upsample = use_merged_upsample(cinfo);
+
+ /* Color quantizer selection */
+ master->quantizer_1pass = NULL;
+ master->quantizer_2pass = NULL;
+ /* No mode changes if not using buffered-image mode. */
+ if (! cinfo->quantize_colors || ! cinfo->buffered_image) {
+ cinfo->enable_1pass_quant = FALSE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ }
+ if (cinfo->quantize_colors) {
+ if (cinfo->raw_data_out)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+ /* 2-pass quantizer only works in 3-component color space. */
+ if (cinfo->out_color_components != 3) {
+ cinfo->enable_1pass_quant = TRUE;
+ cinfo->enable_external_quant = FALSE;
+ cinfo->enable_2pass_quant = FALSE;
+ cinfo->colormap = NULL;
+ } else if (cinfo->colormap != NULL) {
+ cinfo->enable_external_quant = TRUE;
+ } else if (cinfo->two_pass_quantize) {
+ cinfo->enable_2pass_quant = TRUE;
+ } else {
+ cinfo->enable_1pass_quant = TRUE;
+ }
+
+ if (cinfo->enable_1pass_quant) {
+#ifdef QUANT_1PASS_SUPPORTED
+ jinit_1pass_quantizer(cinfo);
+ master->quantizer_1pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+
+ /* We use the 2-pass code to map to external colormaps. */
+ if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) {
+#ifdef QUANT_2PASS_SUPPORTED
+ jinit_2pass_quantizer(cinfo);
+ master->quantizer_2pass = cinfo->cquantize;
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ }
+ /* If both quantizers are initialized, the 2-pass one is left active;
+ * this is necessary for starting with quantization to an external map.
+ */
+ }
+
+ /* Post-processing: in particular, color conversion first */
+ if (! cinfo->raw_data_out) {
+ if (master->using_merged_upsample) {
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+ jinit_merged_upsampler(cinfo); /* does color conversion too */
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif
+ } else {
+ jinit_color_deconverter(cinfo);
+ jinit_upsampler(cinfo);
+ }
+ jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant);
+ }
+ /* Inverse DCT */
+ jinit_inverse_dct(cinfo);
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code)
+ jinit_arith_decoder(cinfo);
+ else {
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Initialize principal buffer controllers. */
+ use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image;
+ jinit_d_coef_controller(cinfo, use_c_buffer);
+
+ if (! cinfo->raw_data_out)
+ jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ (*cinfo->inputctl->start_input_pass) (cinfo);
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+ /* If jpeg_start_decompress will read the whole file, initialize
+ * progress monitoring appropriately. The input step is counted
+ * as one pass.
+ */
+ if (cinfo->progress != NULL && ! cinfo->buffered_image &&
+ cinfo->inputctl->has_multiple_scans) {
+ int nscans;
+ /* Estimate number of scans to set pass_limit. */
+ if (cinfo->progressive_mode) {
+ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+ nscans = 2 + 3 * cinfo->num_components;
+ } else {
+ /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+ nscans = cinfo->num_components;
+ }
+ cinfo->progress->pass_counter = 0L;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+ cinfo->progress->completed_passes = 0;
+ cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2);
+ /* Count the input pass as done */
+ master->pass_number++;
+ }
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+}
+
+
+/*
+ * Per-pass setup.
+ * This is called at the beginning of each output pass. We determine which
+ * modules will be active during this pass and give them appropriate
+ * start_pass calls. We also set is_dummy_pass to indicate whether this
+ * is a "real" output pass or a dummy pass for color quantization.
+ * (In the latter case, jdapistd.c will crank the pass to completion.)
+ */
+
+METHODDEF(void)
+prepare_for_output_pass (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ if (master->pub.is_dummy_pass) {
+#ifdef QUANT_2PASS_SUPPORTED
+ /* Final pass of 2-pass quantization */
+ master->pub.is_dummy_pass = FALSE;
+ (*cinfo->cquantize->start_pass) (cinfo, FALSE);
+ (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST);
+ (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST);
+#else
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ if (cinfo->quantize_colors && cinfo->colormap == NULL) {
+ /* Select new quantization method */
+ if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) {
+ cinfo->cquantize = master->quantizer_2pass;
+ master->pub.is_dummy_pass = TRUE;
+ } else if (cinfo->enable_1pass_quant) {
+ cinfo->cquantize = master->quantizer_1pass;
+ } else {
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+ }
+ }
+ (*cinfo->idct->start_pass) (cinfo);
+ (*cinfo->coef->start_output_pass) (cinfo);
+ if (! cinfo->raw_data_out) {
+ if (! master->using_merged_upsample)
+ (*cinfo->cconvert->start_pass) (cinfo);
+ (*cinfo->upsample->start_pass) (cinfo);
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass);
+ (*cinfo->post->start_pass) (cinfo,
+ (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU));
+ (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU);
+ }
+ }
+
+ /* Set up progress monitor's pass info if present */
+ if (cinfo->progress != NULL) {
+ cinfo->progress->completed_passes = master->pass_number;
+ cinfo->progress->total_passes = master->pass_number +
+ (master->pub.is_dummy_pass ? 2 : 1);
+ /* In buffered-image mode, we assume one more output pass if EOI not
+ * yet reached, but no more passes if EOI has been reached.
+ */
+ if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) {
+ cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1);
+ }
+ }
+}
+
+
+/*
+ * Finish up at end of an output pass.
+ */
+
+METHODDEF(void)
+finish_output_pass (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ if (cinfo->quantize_colors)
+ (*cinfo->cquantize->finish_pass) (cinfo);
+ master->pass_number++;
+}
+
+
+#ifdef D_MULTISCAN_FILES_SUPPORTED
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+GLOBAL(void)
+jpeg_new_colormap (j_decompress_ptr cinfo)
+{
+ my_master_ptr master = (my_master_ptr) cinfo->master;
+
+ /* Prevent application from calling me at wrong times */
+ if (cinfo->global_state != DSTATE_BUFIMAGE)
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+
+ if (cinfo->quantize_colors && cinfo->enable_external_quant &&
+ cinfo->colormap != NULL) {
+ /* Select 2-pass quantizer for external colormap use */
+ cinfo->cquantize = master->quantizer_2pass;
+ /* Notify quantizer of colormap change */
+ (*cinfo->cquantize->new_color_map) (cinfo);
+ master->pub.is_dummy_pass = FALSE; /* just in case */
+ } else
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+#endif /* D_MULTISCAN_FILES_SUPPORTED */
+
+
+/*
+ * Initialize master decompression control and select active modules.
+ * This is performed at the start of jpeg_start_decompress.
+ */
+
+GLOBAL(void)
+jinit_master_decompress (j_decompress_ptr cinfo)
+{
+ my_master_ptr master;
+
+ master = (my_master_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_decomp_master));
+ cinfo->master = (struct jpeg_decomp_master *) master;
+ master->pub.prepare_for_output_pass = prepare_for_output_pass;
+ master->pub.finish_output_pass = finish_output_pass;
+
+ master->pub.is_dummy_pass = FALSE;
+
+ master_selection(cinfo);
+}
diff --git a/jpg/jdmerge.c b/jpg/jdmerge.c
new file mode 100644
index 0000000..3744446
--- /dev/null
+++ b/jpg/jdmerge.c
@@ -0,0 +1,400 @@
+/*
+ * jdmerge.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains code for merged upsampling/color conversion.
+ *
+ * This file combines functions from jdsample.c and jdcolor.c;
+ * read those files first to understand what's going on.
+ *
+ * When the chroma components are to be upsampled by simple replication
+ * (ie, box filtering), we can save some work in color conversion by
+ * calculating all the output pixels corresponding to a pair of chroma
+ * samples at one time. In the conversion equations
+ * R = Y + K1 * Cr
+ * G = Y + K2 * Cb + K3 * Cr
+ * B = Y + K4 * Cb
+ * only the Y term varies among the group of pixels corresponding to a pair
+ * of chroma samples, so the rest of the terms can be calculated just once.
+ * At typical sampling ratios, this eliminates half or three-quarters of the
+ * multiplications needed for color conversion.
+ *
+ * This file currently provides implementations for the following cases:
+ * YCbCr => RGB color conversion only.
+ * Sampling ratios of 2h1v or 2h2v.
+ * No scaling needed at upsample time.
+ * Corner-aligned (non-CCIR601) sampling alignment.
+ * Other special cases could be added, but in most applications these are
+ * the only common cases. (For uncommon cases we fall back on the more
+ * general code in jdsample.c and jdcolor.c.)
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef UPSAMPLE_MERGING_SUPPORTED
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_upsampler pub; /* public fields */
+
+ /* Pointer to routine to do actual upsampling/conversion of one row group */
+ JMETHOD(void, upmethod, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf));
+
+ /* Private state for YCC->RGB conversion */
+ int * Cr_r_tab; /* => table for Cr to R conversion */
+ int * Cb_b_tab; /* => table for Cb to B conversion */
+ INT32 * Cr_g_tab; /* => table for Cr to G conversion */
+ INT32 * Cb_g_tab; /* => table for Cb to G conversion */
+
+ /* For 2:1 vertical sampling, we produce two output rows at a time.
+ * We need a "spare" row buffer to hold the second output row if the
+ * application provides just a one-row buffer; we also use the spare
+ * to discard the dummy last row if the image height is odd.
+ */
+ JSAMPROW spare_row;
+ boolean spare_full; /* T if spare buffer is occupied */
+
+ JDIMENSION out_row_width; /* samples per output row */
+ JDIMENSION rows_to_go; /* counts rows remaining in image */
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
+
+#define SCALEBITS 16 /* speediest right-shift on some machines */
+#define ONE_HALF ((INT32) 1 << (SCALEBITS-1))
+#define FIX(x) ((INT32) ((x) * (1L<<SCALEBITS) + 0.5))
+
+
+/*
+ * Initialize tables for YCC->RGB colorspace conversion.
+ * This is taken directly from jdcolor.c; see that file for more info.
+ */
+
+LOCAL(void)
+build_ycc_rgb_table (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ int i;
+ INT32 x;
+ SHIFT_TEMPS
+
+ upsample->Cr_r_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ upsample->Cb_b_tab = (int *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(int));
+ upsample->Cr_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+ upsample->Cb_g_tab = (INT32 *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (MAXJSAMPLE+1) * SIZEOF(INT32));
+
+ for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>R value is nearest int to 1.40200 * x */
+ upsample->Cr_r_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS);
+ /* Cb=>B value is nearest int to 1.77200 * x */
+ upsample->Cb_b_tab[i] = (int)
+ RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS);
+ /* Cr=>G value is scaled-up -0.71414 * x */
+ upsample->Cr_g_tab[i] = (- FIX(0.71414)) * x;
+ /* Cb=>G value is scaled-up -0.34414 * x */
+ /* We also add in ONE_HALF so that need not do it in inner loop */
+ upsample->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF;
+ }
+}
+
+
+/*
+ * Initialize for an upsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_merged_upsample (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Mark the spare buffer empty */
+ upsample->spare_full = FALSE;
+ /* Initialize total-height counter for detecting bottom of image */
+ upsample->rows_to_go = cinfo->output_height;
+}
+
+
+/*
+ * Control routine to do upsampling (and color conversion).
+ *
+ * The control routine just handles the row buffering considerations.
+ */
+
+METHODDEF(void)
+merged_2v_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+/* 2:1 vertical sampling case: may need a spare row. */
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ JSAMPROW work_ptrs[2];
+ JDIMENSION num_rows; /* number of rows returned to caller */
+
+ if (upsample->spare_full) {
+ /* If we have a spare row saved from a previous cycle, just return it. */
+ jcopy_sample_rows(& upsample->spare_row, 0, output_buf + *out_row_ctr, 0,
+ 1, upsample->out_row_width);
+ num_rows = 1;
+ upsample->spare_full = FALSE;
+ } else {
+ /* Figure number of rows to return to caller. */
+ num_rows = 2;
+ /* Not more than the distance to the end of the image. */
+ if (num_rows > upsample->rows_to_go)
+ num_rows = upsample->rows_to_go;
+ /* And not more than what the client can accept: */
+ out_rows_avail -= *out_row_ctr;
+ if (num_rows > out_rows_avail)
+ num_rows = out_rows_avail;
+ /* Create output pointer array for upsampler. */
+ work_ptrs[0] = output_buf[*out_row_ctr];
+ if (num_rows > 1) {
+ work_ptrs[1] = output_buf[*out_row_ctr + 1];
+ } else {
+ work_ptrs[1] = upsample->spare_row;
+ upsample->spare_full = TRUE;
+ }
+ /* Now do the upsampling. */
+ (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr, work_ptrs);
+ }
+
+ /* Adjust counts */
+ *out_row_ctr += num_rows;
+ upsample->rows_to_go -= num_rows;
+ /* When the buffer is emptied, declare this input row group consumed */
+ if (! upsample->spare_full)
+ (*in_row_group_ctr)++;
+}
+
+
+METHODDEF(void)
+merged_1v_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+/* 1:1 vertical sampling case: much easier, never need a spare row. */
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Just do the upsampling. */
+ (*upsample->upmethod) (cinfo, input_buf, *in_row_group_ctr,
+ output_buf + *out_row_ctr);
+ /* Adjust counts */
+ (*out_row_ctr)++;
+ (*in_row_group_ctr)++;
+}
+
+
+/*
+ * These are the routines invoked by the control routines to do
+ * the actual upsampling/conversion. One row group is processed per call.
+ *
+ * Note: since we may be writing directly into application-supplied buffers,
+ * we have to be honest about the output width; we can't assume the buffer
+ * has been rounded up to an even width.
+ */
+
+
+/*
+ * Upsample and color convert for the case of 2:1 horizontal and 1:1 vertical.
+ */
+
+METHODDEF(void)
+h2v1_merged_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr;
+ JSAMPROW inptr0, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ SHIFT_TEMPS
+
+ inptr0 = input_buf[0][in_row_group_ctr];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr = output_buf[0];
+ /* Loop for each pair of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 2 Y values and emit 2 pixels */
+ y = GETJSAMPLE(*inptr0++);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr0++);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ outptr += RGB_PIXELSIZE;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr0);
+ outptr[RGB_RED] = range_limit[y + cred];
+ outptr[RGB_GREEN] = range_limit[y + cgreen];
+ outptr[RGB_BLUE] = range_limit[y + cblue];
+ }
+}
+
+
+/*
+ * Upsample and color convert for the case of 2:1 horizontal and 2:1 vertical.
+ */
+
+METHODDEF(void)
+h2v2_merged_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_group_ctr,
+ JSAMPARRAY output_buf)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ register int y, cred, cgreen, cblue;
+ int cb, cr;
+ register JSAMPROW outptr0, outptr1;
+ JSAMPROW inptr00, inptr01, inptr1, inptr2;
+ JDIMENSION col;
+ /* copy these pointers into registers if possible */
+ register JSAMPLE * range_limit = cinfo->sample_range_limit;
+ int * Crrtab = upsample->Cr_r_tab;
+ int * Cbbtab = upsample->Cb_b_tab;
+ INT32 * Crgtab = upsample->Cr_g_tab;
+ INT32 * Cbgtab = upsample->Cb_g_tab;
+ SHIFT_TEMPS
+
+ inptr00 = input_buf[0][in_row_group_ctr*2];
+ inptr01 = input_buf[0][in_row_group_ctr*2 + 1];
+ inptr1 = input_buf[1][in_row_group_ctr];
+ inptr2 = input_buf[2][in_row_group_ctr];
+ outptr0 = output_buf[0];
+ outptr1 = output_buf[1];
+ /* Loop for each group of output pixels */
+ for (col = cinfo->output_width >> 1; col > 0; col--) {
+ /* Do the chroma part of the calculation */
+ cb = GETJSAMPLE(*inptr1++);
+ cr = GETJSAMPLE(*inptr2++);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ /* Fetch 4 Y values and emit 4 pixels */
+ y = GETJSAMPLE(*inptr00++);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr00++);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ outptr0 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr01++);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1 += RGB_PIXELSIZE;
+ y = GETJSAMPLE(*inptr01++);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ outptr1 += RGB_PIXELSIZE;
+ }
+ /* If image width is odd, do the last output column separately */
+ if (cinfo->output_width & 1) {
+ cb = GETJSAMPLE(*inptr1);
+ cr = GETJSAMPLE(*inptr2);
+ cred = Crrtab[cr];
+ cgreen = (int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], SCALEBITS);
+ cblue = Cbbtab[cb];
+ y = GETJSAMPLE(*inptr00);
+ outptr0[RGB_RED] = range_limit[y + cred];
+ outptr0[RGB_GREEN] = range_limit[y + cgreen];
+ outptr0[RGB_BLUE] = range_limit[y + cblue];
+ y = GETJSAMPLE(*inptr01);
+ outptr1[RGB_RED] = range_limit[y + cred];
+ outptr1[RGB_GREEN] = range_limit[y + cgreen];
+ outptr1[RGB_BLUE] = range_limit[y + cblue];
+ }
+}
+
+
+/*
+ * Module initialization routine for merged upsampling/color conversion.
+ *
+ * NB: this is called under the conditions determined by use_merged_upsample()
+ * in jdmaster.c. That routine MUST correspond to the actual capabilities
+ * of this module; no safety checks are made here.
+ */
+
+GLOBAL(void)
+jinit_merged_upsampler (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample;
+
+ upsample = (my_upsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_upsampler));
+ cinfo->upsample = (struct jpeg_upsampler *) upsample;
+ upsample->pub.start_pass = start_pass_merged_upsample;
+ upsample->pub.need_context_rows = FALSE;
+
+ upsample->out_row_width = cinfo->output_width * cinfo->out_color_components;
+
+ if (cinfo->max_v_samp_factor == 2) {
+ upsample->pub.upsample = merged_2v_upsample;
+ upsample->upmethod = h2v2_merged_upsample;
+ /* Allocate a spare row buffer */
+ upsample->spare_row = (JSAMPROW)
+ (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) (upsample->out_row_width * SIZEOF(JSAMPLE)));
+ } else {
+ upsample->pub.upsample = merged_1v_upsample;
+ upsample->upmethod = h2v1_merged_upsample;
+ /* No spare row needed */
+ upsample->spare_row = NULL;
+ }
+
+ build_ycc_rgb_table(cinfo);
+}
+
+#endif /* UPSAMPLE_MERGING_SUPPORTED */
diff --git a/jpg/jdosaobj.txt b/jpg/jdosaobj.txt
new file mode 100644
index 0000000..4318362
--- /dev/null
+++ b/jpg/jdosaobj.txt
@@ -0,0 +1,16 @@
+This archive contains already-assembled object files for JMEMDOSA.ASM
+of the Independent JPEG Group's JPEG package. These files will be helpful
+if you want to compile the IJG code for DOS, but don't have an assembler.
+
+These files were prepared from the 3/13/1992 version of JMEMDOSA.ASM,
+which is still unchanged as of mid-1998. You can use these files with
+releases 3 through 6 of the IJG code, and probably future releases too.
+
+To use these files, copy the proper version to JMEMDOSA.OBJ. Make sure
+this file has a newer date than JMEMDOSA.ASM. Then compile the code as
+usual.
+
+Object files included:
+
+JDOSAMSC.OBJ For Microsoft C version 5 or later.
+JDOSABCC.OBJ For Borland C version 3.0 or later.
diff --git a/jpg/jdpostct.c b/jpg/jdpostct.c
new file mode 100644
index 0000000..571563d
--- /dev/null
+++ b/jpg/jdpostct.c
@@ -0,0 +1,290 @@
+/*
+ * jdpostct.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the decompression postprocessing controller.
+ * This controller manages the upsampling, color conversion, and color
+ * quantization/reduction steps; specifically, it controls the buffering
+ * between upsample/color conversion and color quantization/reduction.
+ *
+ * If no color quantization/reduction is required, then this module has no
+ * work to do, and it just hands off to the upsample/color conversion code.
+ * An integrated upsample/convert/quantize process would replace this module
+ * entirely.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Private buffer controller object */
+
+typedef struct {
+ struct jpeg_d_post_controller pub; /* public fields */
+
+ /* Color quantization source buffer: this holds output data from
+ * the upsample/color conversion step to be passed to the quantizer.
+ * For two-pass color quantization, we need a full-image buffer;
+ * for one-pass operation, a strip buffer is sufficient.
+ */
+ jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */
+ JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */
+ JDIMENSION strip_height; /* buffer size in rows */
+ /* for two-pass mode only: */
+ JDIMENSION starting_row; /* row # of first row in current strip */
+ JDIMENSION next_row; /* index of next row to fill/empty in strip */
+} my_post_controller;
+
+typedef my_post_controller * my_post_ptr;
+
+
+/* Forward declarations */
+METHODDEF(void) post_process_1pass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+#ifdef QUANT_2PASS_SUPPORTED
+METHODDEF(void) post_process_prepass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+METHODDEF(void) post_process_2pass
+ JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+#endif
+
+
+/*
+ * Initialize for a processing pass.
+ */
+
+METHODDEF(void)
+start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+
+ switch (pass_mode) {
+ case JBUF_PASS_THRU:
+ if (cinfo->quantize_colors) {
+ /* Single-pass processing with color quantization. */
+ post->pub.post_process_data = post_process_1pass;
+ /* We could be doing buffered-image output before starting a 2-pass
+ * color quantization; in that case, jinit_d_post_controller did not
+ * allocate a strip buffer. Use the virtual-array buffer as workspace.
+ */
+ if (post->buffer == NULL) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ (JDIMENSION) 0, post->strip_height, TRUE);
+ }
+ } else {
+ /* For single-pass processing without color quantization,
+ * I have no work to do; just call the upsampler directly.
+ */
+ post->pub.post_process_data = cinfo->upsample->upsample;
+ }
+ break;
+#ifdef QUANT_2PASS_SUPPORTED
+ case JBUF_SAVE_AND_PASS:
+ /* First pass of 2-pass quantization */
+ if (post->whole_image == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ post->pub.post_process_data = post_process_prepass;
+ break;
+ case JBUF_CRANK_DEST:
+ /* Second pass of 2-pass quantization */
+ if (post->whole_image == NULL)
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ post->pub.post_process_data = post_process_2pass;
+ break;
+#endif /* QUANT_2PASS_SUPPORTED */
+ default:
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+ break;
+ }
+ post->starting_row = post->next_row = 0;
+}
+
+
+/*
+ * Process some data in the one-pass (strip buffer) case.
+ * This is used for color precision reduction as well as one-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_1pass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION num_rows, max_rows;
+
+ /* Fill the buffer, but not more than what we can dump out in one go. */
+ /* Note we rely on the upsampler to detect bottom of image. */
+ max_rows = out_rows_avail - *out_row_ctr;
+ if (max_rows > post->strip_height)
+ max_rows = post->strip_height;
+ num_rows = 0;
+ (*cinfo->upsample->upsample) (cinfo,
+ input_buf, in_row_group_ctr, in_row_groups_avail,
+ post->buffer, &num_rows, max_rows);
+ /* Quantize and emit data. */
+ (*cinfo->cquantize->color_quantize) (cinfo,
+ post->buffer, output_buf + *out_row_ctr, (int) num_rows);
+ *out_row_ctr += num_rows;
+}
+
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+/*
+ * Process some data in the first pass of 2-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_prepass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION old_next_row, num_rows;
+
+ /* Reposition virtual buffer if at start of strip. */
+ if (post->next_row == 0) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ post->starting_row, post->strip_height, TRUE);
+ }
+
+ /* Upsample some data (up to a strip height's worth). */
+ old_next_row = post->next_row;
+ (*cinfo->upsample->upsample) (cinfo,
+ input_buf, in_row_group_ctr, in_row_groups_avail,
+ post->buffer, &post->next_row, post->strip_height);
+
+ /* Allow quantizer to scan new data. No data is emitted, */
+ /* but we advance out_row_ctr so outer loop can tell when we're done. */
+ if (post->next_row > old_next_row) {
+ num_rows = post->next_row - old_next_row;
+ (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row,
+ (JSAMPARRAY) NULL, (int) num_rows);
+ *out_row_ctr += num_rows;
+ }
+
+ /* Advance if we filled the strip. */
+ if (post->next_row >= post->strip_height) {
+ post->starting_row += post->strip_height;
+ post->next_row = 0;
+ }
+}
+
+
+/*
+ * Process some data in the second pass of 2-pass quantization.
+ */
+
+METHODDEF(void)
+post_process_2pass (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_post_ptr post = (my_post_ptr) cinfo->post;
+ JDIMENSION num_rows, max_rows;
+
+ /* Reposition virtual buffer if at start of strip. */
+ if (post->next_row == 0) {
+ post->buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, post->whole_image,
+ post->starting_row, post->strip_height, FALSE);
+ }
+
+ /* Determine number of rows to emit. */
+ num_rows = post->strip_height - post->next_row; /* available in strip */
+ max_rows = out_rows_avail - *out_row_ctr; /* available in output area */
+ if (num_rows > max_rows)
+ num_rows = max_rows;
+ /* We have to check bottom of image here, can't depend on upsampler. */
+ max_rows = cinfo->output_height - post->starting_row;
+ if (num_rows > max_rows)
+ num_rows = max_rows;
+
+ /* Quantize and emit data. */
+ (*cinfo->cquantize->color_quantize) (cinfo,
+ post->buffer + post->next_row, output_buf + *out_row_ctr,
+ (int) num_rows);
+ *out_row_ctr += num_rows;
+
+ /* Advance if we filled the strip. */
+ post->next_row += num_rows;
+ if (post->next_row >= post->strip_height) {
+ post->starting_row += post->strip_height;
+ post->next_row = 0;
+ }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
+
+
+/*
+ * Initialize postprocessing controller.
+ */
+
+GLOBAL(void)
+jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer)
+{
+ my_post_ptr post;
+
+ post = (my_post_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_post_controller));
+ cinfo->post = (struct jpeg_d_post_controller *) post;
+ post->pub.start_pass = start_pass_dpost;
+ post->whole_image = NULL; /* flag for no virtual arrays */
+ post->buffer = NULL; /* flag for no strip buffer */
+
+ /* Create the quantization buffer, if needed */
+ if (cinfo->quantize_colors) {
+ /* The buffer strip height is max_v_samp_factor, which is typically
+ * an efficient number of rows for upsampling to return.
+ * (In the presence of output rescaling, we might want to be smarter?)
+ */
+ post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor;
+ if (need_full_buffer) {
+ /* Two-pass color quantization: need full-image storage. */
+ /* We round up the number of rows to a multiple of the strip height. */
+#ifdef QUANT_2PASS_SUPPORTED
+ post->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ cinfo->output_width * cinfo->out_color_components,
+ (JDIMENSION) jround_up((long) cinfo->output_height,
+ (long) post->strip_height),
+ post->strip_height);
+#else
+ ERREXIT(cinfo, JERR_BAD_BUFFER_MODE);
+#endif /* QUANT_2PASS_SUPPORTED */
+ } else {
+ /* One-pass color quantization: just make a strip buffer. */
+ post->buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->output_width * cinfo->out_color_components,
+ post->strip_height);
+ }
+ }
+}
diff --git a/jpg/jdsample.c b/jpg/jdsample.c
new file mode 100644
index 0000000..7bc8885
--- /dev/null
+++ b/jpg/jdsample.c
@@ -0,0 +1,361 @@
+/*
+ * jdsample.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2002-2008 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains upsampling routines.
+ *
+ * Upsampling input data is counted in "row groups". A row group
+ * is defined to be (v_samp_factor * DCT_v_scaled_size / min_DCT_v_scaled_size)
+ * sample rows of each component. Upsampling will normally produce
+ * max_v_samp_factor pixel rows from each row group (but this could vary
+ * if the upsampler is applying a scale factor of its own).
+ *
+ * An excellent reference for image resampling is
+ * Digital Image Warping, George Wolberg, 1990.
+ * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Pointer to routine to upsample a single component */
+typedef JMETHOD(void, upsample1_ptr,
+ (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr));
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_upsampler pub; /* public fields */
+
+ /* Color conversion buffer. When using separate upsampling and color
+ * conversion steps, this buffer holds one upsampled row group until it
+ * has been color converted and output.
+ * Note: we do not allocate any storage for component(s) which are full-size,
+ * ie do not need rescaling. The corresponding entry of color_buf[] is
+ * simply set to point to the input data array, thereby avoiding copying.
+ */
+ JSAMPARRAY color_buf[MAX_COMPONENTS];
+
+ /* Per-component upsampling method pointers */
+ upsample1_ptr methods[MAX_COMPONENTS];
+
+ int next_row_out; /* counts rows emitted from color_buf */
+ JDIMENSION rows_to_go; /* counts rows remaining in image */
+
+ /* Height of an input row group for each component. */
+ int rowgroup_height[MAX_COMPONENTS];
+
+ /* These arrays save pixel expansion factors so that int_expand need not
+ * recompute them each time. They are unused for other upsampling methods.
+ */
+ UINT8 h_expand[MAX_COMPONENTS];
+ UINT8 v_expand[MAX_COMPONENTS];
+} my_upsampler;
+
+typedef my_upsampler * my_upsample_ptr;
+
+
+/*
+ * Initialize for an upsampling pass.
+ */
+
+METHODDEF(void)
+start_pass_upsample (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+
+ /* Mark the conversion buffer empty */
+ upsample->next_row_out = cinfo->max_v_samp_factor;
+ /* Initialize total-height counter for detecting bottom of image */
+ upsample->rows_to_go = cinfo->output_height;
+}
+
+
+/*
+ * Control routine to do upsampling (and color conversion).
+ *
+ * In this version we upsample each component independently.
+ * We upsample one row group into the conversion buffer, then apply
+ * color conversion a row at a time.
+ */
+
+METHODDEF(void)
+sep_upsample (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ int ci;
+ jpeg_component_info * compptr;
+ JDIMENSION num_rows;
+
+ /* Fill the conversion buffer, if it's empty */
+ if (upsample->next_row_out >= cinfo->max_v_samp_factor) {
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Invoke per-component upsample method. Notice we pass a POINTER
+ * to color_buf[ci], so that fullsize_upsample can change it.
+ */
+ (*upsample->methods[ci]) (cinfo, compptr,
+ input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]),
+ upsample->color_buf + ci);
+ }
+ upsample->next_row_out = 0;
+ }
+
+ /* Color-convert and emit rows */
+
+ /* How many we have in the buffer: */
+ num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out);
+ /* Not more than the distance to the end of the image. Need this test
+ * in case the image height is not a multiple of max_v_samp_factor:
+ */
+ if (num_rows > upsample->rows_to_go)
+ num_rows = upsample->rows_to_go;
+ /* And not more than what the client can accept: */
+ out_rows_avail -= *out_row_ctr;
+ if (num_rows > out_rows_avail)
+ num_rows = out_rows_avail;
+
+ (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf,
+ (JDIMENSION) upsample->next_row_out,
+ output_buf + *out_row_ctr,
+ (int) num_rows);
+
+ /* Adjust counts */
+ *out_row_ctr += num_rows;
+ upsample->rows_to_go -= num_rows;
+ upsample->next_row_out += num_rows;
+ /* When the buffer is emptied, declare this input row group consumed */
+ if (upsample->next_row_out >= cinfo->max_v_samp_factor)
+ (*in_row_group_ctr)++;
+}
+
+
+/*
+ * These are the routines invoked by sep_upsample to upsample pixel values
+ * of a single component. One row group is processed per call.
+ */
+
+
+/*
+ * For full-size components, we just make color_buf[ci] point at the
+ * input buffer, and thus avoid copying any data. Note that this is
+ * safe only because sep_upsample doesn't declare the input row group
+ * "consumed" until we are done color converting and emitting it.
+ */
+
+METHODDEF(void)
+fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ *output_data_ptr = input_data;
+}
+
+
+/*
+ * This is a no-op version used for "uninteresting" components.
+ * These components will not be referenced by color conversion.
+ */
+
+METHODDEF(void)
+noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ *output_data_ptr = NULL; /* safety check */
+}
+
+
+/*
+ * This version handles any integral sampling ratios.
+ * This is not used for typical JPEG files, so it need not be fast.
+ * Nor, for that matter, is it particularly accurate: the algorithm is
+ * simple replication of the input pixel onto the corresponding output
+ * pixels. The hi-falutin sampling literature refers to this as a
+ * "box filter". A box filter tends to introduce visible artifacts,
+ * so if you are actually going to use 3:1 or 4:1 sampling ratios
+ * you would be well advised to improve this code.
+ */
+
+METHODDEF(void)
+int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample;
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ register int h;
+ JSAMPROW outend;
+ int h_expand, v_expand;
+ int inrow, outrow;
+
+ h_expand = upsample->h_expand[compptr->component_index];
+ v_expand = upsample->v_expand[compptr->component_index];
+
+ inrow = outrow = 0;
+ while (outrow < cinfo->max_v_samp_factor) {
+ /* Generate one output row with proper horizontal expansion */
+ inptr = input_data[inrow];
+ outptr = output_data[outrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ for (h = h_expand; h > 0; h--) {
+ *outptr++ = invalue;
+ }
+ }
+ /* Generate any additional output rows by duplicating the first one */
+ if (v_expand > 1) {
+ jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+ v_expand-1, cinfo->output_width);
+ }
+ inrow++;
+ outrow += v_expand;
+ }
+}
+
+
+/*
+ * Fast processing for the common case of 2:1 horizontal and 1:1 vertical.
+ * It's still a box filter.
+ */
+
+METHODDEF(void)
+h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ JSAMPROW outend;
+ int outrow;
+
+ for (outrow = 0; outrow < cinfo->max_v_samp_factor; outrow++) {
+ inptr = input_data[outrow];
+ outptr = output_data[outrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ *outptr++ = invalue;
+ *outptr++ = invalue;
+ }
+ }
+}
+
+
+/*
+ * Fast processing for the common case of 2:1 horizontal and 2:1 vertical.
+ * It's still a box filter.
+ */
+
+METHODDEF(void)
+h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)
+{
+ JSAMPARRAY output_data = *output_data_ptr;
+ register JSAMPROW inptr, outptr;
+ register JSAMPLE invalue;
+ JSAMPROW outend;
+ int inrow, outrow;
+
+ inrow = outrow = 0;
+ while (outrow < cinfo->max_v_samp_factor) {
+ inptr = input_data[inrow];
+ outptr = output_data[outrow];
+ outend = outptr + cinfo->output_width;
+ while (outptr < outend) {
+ invalue = *inptr++; /* don't need GETJSAMPLE() here */
+ *outptr++ = invalue;
+ *outptr++ = invalue;
+ }
+ jcopy_sample_rows(output_data, outrow, output_data, outrow+1,
+ 1, cinfo->output_width);
+ inrow++;
+ outrow += 2;
+ }
+}
+
+
+/*
+ * Module initialization routine for upsampling.
+ */
+
+GLOBAL(void)
+jinit_upsampler (j_decompress_ptr cinfo)
+{
+ my_upsample_ptr upsample;
+ int ci;
+ jpeg_component_info * compptr;
+ boolean need_buffer;
+ int h_in_group, v_in_group, h_out_group, v_out_group;
+
+ upsample = (my_upsample_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_upsampler));
+ cinfo->upsample = (struct jpeg_upsampler *) upsample;
+ upsample->pub.start_pass = start_pass_upsample;
+ upsample->pub.upsample = sep_upsample;
+ upsample->pub.need_context_rows = FALSE; /* until we find out differently */
+
+ if (cinfo->CCIR601_sampling) /* this isn't supported */
+ ERREXIT(cinfo, JERR_CCIR601_NOTIMPL);
+
+ /* Verify we can handle the sampling factors, select per-component methods,
+ * and create storage as needed.
+ */
+ for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components;
+ ci++, compptr++) {
+ /* Compute size of an "input group" after IDCT scaling. This many samples
+ * are to be converted to max_h_samp_factor * max_v_samp_factor pixels.
+ */
+ h_in_group = (compptr->h_samp_factor * compptr->DCT_h_scaled_size) /
+ cinfo->min_DCT_h_scaled_size;
+ v_in_group = (compptr->v_samp_factor * compptr->DCT_v_scaled_size) /
+ cinfo->min_DCT_v_scaled_size;
+ h_out_group = cinfo->max_h_samp_factor;
+ v_out_group = cinfo->max_v_samp_factor;
+ upsample->rowgroup_height[ci] = v_in_group; /* save for use later */
+ need_buffer = TRUE;
+ if (! compptr->component_needed) {
+ /* Don't bother to upsample an uninteresting component. */
+ upsample->methods[ci] = noop_upsample;
+ need_buffer = FALSE;
+ } else if (h_in_group == h_out_group && v_in_group == v_out_group) {
+ /* Fullsize components can be processed without any work. */
+ upsample->methods[ci] = fullsize_upsample;
+ need_buffer = FALSE;
+ } else if (h_in_group * 2 == h_out_group &&
+ v_in_group == v_out_group) {
+ /* Special case for 2h1v upsampling */
+ upsample->methods[ci] = h2v1_upsample;
+ } else if (h_in_group * 2 == h_out_group &&
+ v_in_group * 2 == v_out_group) {
+ /* Special case for 2h2v upsampling */
+ upsample->methods[ci] = h2v2_upsample;
+ } else if ((h_out_group % h_in_group) == 0 &&
+ (v_out_group % v_in_group) == 0) {
+ /* Generic integral-factors upsampling method */
+ upsample->methods[ci] = int_upsample;
+ upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group);
+ upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group);
+ } else
+ ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL);
+ if (need_buffer) {
+ upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) jround_up((long) cinfo->output_width,
+ (long) cinfo->max_h_samp_factor),
+ (JDIMENSION) cinfo->max_v_samp_factor);
+ }
+ }
+}
diff --git a/jpg/jdtrans.c b/jpg/jdtrans.c
new file mode 100644
index 0000000..22dd47f
--- /dev/null
+++ b/jpg/jdtrans.c
@@ -0,0 +1,140 @@
+/*
+ * jdtrans.c
+ *
+ * Copyright (C) 1995-1997, Thomas G. Lane.
+ * Modified 2000-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains library routines for transcoding decompression,
+ * that is, reading raw DCT coefficient arrays from an input JPEG file.
+ * The routines in jdapimin.c will also be needed by a transcoder.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/* Forward declarations */
+LOCAL(void) transdecode_master_selection JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * Read the coefficient arrays from a JPEG file.
+ * jpeg_read_header must be completed before calling this.
+ *
+ * The entire image is read into a set of virtual coefficient-block arrays,
+ * one per component. The return value is a pointer to the array of
+ * virtual-array descriptors. These can be manipulated directly via the
+ * JPEG memory manager, or handed off to jpeg_write_coefficients().
+ * To release the memory occupied by the virtual arrays, call
+ * jpeg_finish_decompress() when done with the data.
+ *
+ * An alternative usage is to simply obtain access to the coefficient arrays
+ * during a buffered-image-mode decompression operation. This is allowed
+ * after any jpeg_finish_output() call. The arrays can be accessed until
+ * jpeg_finish_decompress() is called. (Note that any call to the library
+ * may reposition the arrays, so don't rely on access_virt_barray() results
+ * to stay valid across library calls.)
+ *
+ * Returns NULL if suspended. This case need be checked only if
+ * a suspending data source is used.
+ */
+
+GLOBAL(jvirt_barray_ptr *)
+jpeg_read_coefficients (j_decompress_ptr cinfo)
+{
+ if (cinfo->global_state == DSTATE_READY) {
+ /* First call: initialize active modules */
+ transdecode_master_selection(cinfo);
+ cinfo->global_state = DSTATE_RDCOEFS;
+ }
+ if (cinfo->global_state == DSTATE_RDCOEFS) {
+ /* Absorb whole file into the coef buffer */
+ for (;;) {
+ int retcode;
+ /* Call progress monitor hook if present */
+ if (cinfo->progress != NULL)
+ (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
+ /* Absorb some more input */
+ retcode = (*cinfo->inputctl->consume_input) (cinfo);
+ if (retcode == JPEG_SUSPENDED)
+ return NULL;
+ if (retcode == JPEG_REACHED_EOI)
+ break;
+ /* Advance progress counter if appropriate */
+ if (cinfo->progress != NULL &&
+ (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) {
+ if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) {
+ /* startup underestimated number of scans; ratchet up one scan */
+ cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows;
+ }
+ }
+ }
+ /* Set state so that jpeg_finish_decompress does the right thing */
+ cinfo->global_state = DSTATE_STOPPING;
+ }
+ /* At this point we should be in state DSTATE_STOPPING if being used
+ * standalone, or in state DSTATE_BUFIMAGE if being invoked to get access
+ * to the coefficients during a full buffered-image-mode decompression.
+ */
+ if ((cinfo->global_state == DSTATE_STOPPING ||
+ cinfo->global_state == DSTATE_BUFIMAGE) && cinfo->buffered_image) {
+ return cinfo->coef->coef_arrays;
+ }
+ /* Oops, improper usage */
+ ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
+ return NULL; /* keep compiler happy */
+}
+
+
+/*
+ * Master selection of decompression modules for transcoding.
+ * This substitutes for jdmaster.c's initialization of the full decompressor.
+ */
+
+LOCAL(void)
+transdecode_master_selection (j_decompress_ptr cinfo)
+{
+ /* This is effectively a buffered-image operation. */
+ cinfo->buffered_image = TRUE;
+
+ /* Compute output image dimensions and related values. */
+ jpeg_core_output_dimensions(cinfo);
+
+ /* Entropy decoding: either Huffman or arithmetic coding. */
+ if (cinfo->arith_code)
+ jinit_arith_decoder(cinfo);
+ else {
+ jinit_huff_decoder(cinfo);
+ }
+
+ /* Always get a full-image coefficient buffer. */
+ jinit_d_coef_controller(cinfo, TRUE);
+
+ /* We can now tell the memory manager to allocate virtual arrays. */
+ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo);
+
+ /* Initialize input side of decompressor to consume first scan. */
+ (*cinfo->inputctl->start_input_pass) (cinfo);
+
+ /* Initialize progress monitoring. */
+ if (cinfo->progress != NULL) {
+ int nscans;
+ /* Estimate number of scans to set pass_limit. */
+ if (cinfo->progressive_mode) {
+ /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */
+ nscans = 2 + 3 * cinfo->num_components;
+ } else if (cinfo->inputctl->has_multiple_scans) {
+ /* For a nonprogressive multiscan file, estimate 1 scan per component. */
+ nscans = cinfo->num_components;
+ } else {
+ nscans = 1;
+ }
+ cinfo->progress->pass_counter = 0L;
+ cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans;
+ cinfo->progress->completed_passes = 0;
+ cinfo->progress->total_passes = 1;
+ }
+}
diff --git a/jpg/jerror.c b/jpg/jerror.c
new file mode 100644
index 0000000..3da7be8
--- /dev/null
+++ b/jpg/jerror.c
@@ -0,0 +1,252 @@
+/*
+ * jerror.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains simple error-reporting and trace-message routines.
+ * These are suitable for Unix-like systems and others where writing to
+ * stderr is the right thing to do. Many applications will want to replace
+ * some or all of these routines.
+ *
+ * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile,
+ * you get a Windows-specific hack to display error messages in a dialog box.
+ * It ain't much, but it beats dropping error messages into the bit bucket,
+ * which is what happens to output to stderr under most Windows C compilers.
+ *
+ * These routines are used by both the compression and decompression code.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jversion.h"
+#include "jerror.h"
+
+#ifdef USE_WINDOWS_MESSAGEBOX
+#include <windows.h>
+#endif
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+
+
+/*
+ * Create the message string table.
+ * We do this from the master message list in jerror.h by re-reading
+ * jerror.h with a suitable definition for macro JMESSAGE.
+ * The message table is made an external symbol just in case any applications
+ * want to refer to it directly.
+ */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_std_message_table jMsgTable
+#endif
+
+#define JMESSAGE(code,string) string ,
+
+const char * const jpeg_std_message_table[] = {
+#include "jerror.h"
+ NULL
+};
+
+
+/*
+ * Error exit handler: must not return to caller.
+ *
+ * Applications may override this if they want to get control back after
+ * an error. Typically one would longjmp somewhere instead of exiting.
+ * The setjmp buffer can be made a private field within an expanded error
+ * handler object. Note that the info needed to generate an error message
+ * is stored in the error object, so you can generate the message now or
+ * later, at your convenience.
+ * You should make sure that the JPEG object is cleaned up (with jpeg_abort
+ * or jpeg_destroy) at some point.
+ */
+
+METHODDEF(void)
+error_exit (j_common_ptr cinfo)
+{
+ /* Always display the message */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Let the memory manager delete any temp files before we die */
+ jpeg_destroy(cinfo);
+
+ exit(EXIT_FAILURE);
+}
+
+
+/*
+ * Actual output of an error or trace message.
+ * Applications may override this method to send JPEG messages somewhere
+ * other than stderr.
+ *
+ * On Windows, printing to stderr is generally completely useless,
+ * so we provide optional code to produce an error-dialog popup.
+ * Most Windows applications will still prefer to override this routine,
+ * but if they don't, it'll do something at least marginally useful.
+ *
+ * NOTE: to use the library in an environment that doesn't support the
+ * C stdio library, you may have to delete the call to fprintf() entirely,
+ * not just not use this routine.
+ */
+
+METHODDEF(void)
+output_message (j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Create the message */
+ (*cinfo->err->format_message) (cinfo, buffer);
+
+#ifdef USE_WINDOWS_MESSAGEBOX
+ /* Display it in a message dialog box */
+ MessageBox(GetActiveWindow(), buffer, "JPEG Library Error",
+ MB_OK | MB_ICONERROR);
+#else
+ /* Send it to stderr, adding a newline */
+ fprintf(stderr, "%s\n", buffer);
+#endif
+}
+
+
+/*
+ * Decide whether to emit a trace or warning message.
+ * msg_level is one of:
+ * -1: recoverable corrupt-data warning, may want to abort.
+ * 0: important advisory messages (always display to user).
+ * 1: first level of tracing detail.
+ * 2,3,...: successively more detailed tracing messages.
+ * An application might override this method if it wanted to abort on warnings
+ * or change the policy about which messages to display.
+ */
+
+METHODDEF(void)
+emit_message (j_common_ptr cinfo, int msg_level)
+{
+ struct jpeg_error_mgr * err = cinfo->err;
+
+ if (msg_level < 0) {
+ /* It's a warning message. Since corrupt files may generate many warnings,
+ * the policy implemented here is to show only the first warning,
+ * unless trace_level >= 3.
+ */
+ if (err->num_warnings == 0 || err->trace_level >= 3)
+ (*err->output_message) (cinfo);
+ /* Always count warnings in num_warnings. */
+ err->num_warnings++;
+ } else {
+ /* It's a trace message. Show it if trace_level >= msg_level. */
+ if (err->trace_level >= msg_level)
+ (*err->output_message) (cinfo);
+ }
+}
+
+
+/*
+ * Format a message string for the most recent JPEG error or message.
+ * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX
+ * characters. Note that no '\n' character is added to the string.
+ * Few applications should need to override this method.
+ */
+
+METHODDEF(void)
+format_message (j_common_ptr cinfo, char * buffer)
+{
+ struct jpeg_error_mgr * err = cinfo->err;
+ int msg_code = err->msg_code;
+ const char * msgtext = NULL;
+ const char * msgptr;
+ char ch;
+ boolean isstring;
+
+ /* Look up message string in proper table */
+ if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
+ msgtext = err->jpeg_message_table[msg_code];
+ } else if (err->addon_message_table != NULL &&
+ msg_code >= err->first_addon_message &&
+ msg_code <= err->last_addon_message) {
+ msgtext = err->addon_message_table[msg_code - err->first_addon_message];
+ }
+
+ /* Defend against bogus message number */
+ if (msgtext == NULL) {
+ err->msg_parm.i[0] = msg_code;
+ msgtext = err->jpeg_message_table[0];
+ }
+
+ /* Check for string parameter, as indicated by %s in the message text */
+ isstring = FALSE;
+ msgptr = msgtext;
+ while ((ch = *msgptr++) != '\0') {
+ if (ch == '%') {
+ if (*msgptr == 's') isstring = TRUE;
+ break;
+ }
+ }
+
+ /* Format the message into the passed buffer */
+ if (isstring)
+ sprintf(buffer, msgtext, err->msg_parm.s);
+ else
+ sprintf(buffer, msgtext,
+ err->msg_parm.i[0], err->msg_parm.i[1],
+ err->msg_parm.i[2], err->msg_parm.i[3],
+ err->msg_parm.i[4], err->msg_parm.i[5],
+ err->msg_parm.i[6], err->msg_parm.i[7]);
+}
+
+
+/*
+ * Reset error state variables at start of a new image.
+ * This is called during compression startup to reset trace/error
+ * processing to default state, without losing any application-specific
+ * method pointers. An application might possibly want to override
+ * this method if it has additional error processing state.
+ */
+
+METHODDEF(void)
+reset_error_mgr (j_common_ptr cinfo)
+{
+ cinfo->err->num_warnings = 0;
+ /* trace_level is not reset since it is an application-supplied parameter */
+ cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */
+}
+
+
+/*
+ * Fill in the standard error-handling methods in a jpeg_error_mgr object.
+ * Typical call is:
+ * struct jpeg_compress_struct cinfo;
+ * struct jpeg_error_mgr err;
+ *
+ * cinfo.err = jpeg_std_error(&err);
+ * after which the application may override some of the methods.
+ */
+
+GLOBAL(struct jpeg_error_mgr *)
+jpeg_std_error (struct jpeg_error_mgr * err)
+{
+ err->error_exit = error_exit;
+ err->emit_message = emit_message;
+ err->output_message = output_message;
+ err->format_message = format_message;
+ err->reset_error_mgr = reset_error_mgr;
+
+ err->trace_level = 0; /* default = no tracing */
+ err->num_warnings = 0; /* no warnings emitted yet */
+ err->msg_code = 0; /* may be useful as a flag for "no error" */
+
+ /* Initialize message table pointers */
+ err->jpeg_message_table = jpeg_std_message_table;
+ err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;
+
+ err->addon_message_table = NULL;
+ err->first_addon_message = 0; /* for safety */
+ err->last_addon_message = 0;
+
+ return err;
+}
diff --git a/jpg/jerror.h b/jpg/jerror.h
new file mode 100644
index 0000000..1cfb2b1
--- /dev/null
+++ b/jpg/jerror.h
@@ -0,0 +1,304 @@
+/*
+ * jerror.h
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 1997-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the error and message codes for the JPEG library.
+ * Edit this file to add new codes, or to translate the message strings to
+ * some other language.
+ * A set of error-reporting macros are defined too. Some applications using
+ * the JPEG library may wish to include this file to get the error codes
+ * and/or the macros.
+ */
+
+/*
+ * To define the enum list of message codes, include this file without
+ * defining macro JMESSAGE. To create a message string table, include it
+ * again with a suitable JMESSAGE definition (see jerror.c for an example).
+ */
+#ifndef JMESSAGE
+#ifndef JERROR_H
+/* First time through, define the enum list */
+#define JMAKE_ENUM_LIST
+#else
+/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */
+#define JMESSAGE(code,string)
+#endif /* JERROR_H */
+#endif /* JMESSAGE */
+
+#ifdef JMAKE_ENUM_LIST
+
+typedef enum {
+
+#define JMESSAGE(code,string) code ,
+
+#endif /* JMAKE_ENUM_LIST */
+
+JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */
+
+/* For maintenance convenience, list is alphabetical by message code name */
+JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix")
+JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix")
+JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode")
+JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS")
+JMESSAGE(JERR_BAD_CROP_SPEC, "Invalid crop request")
+JMESSAGE(JERR_BAD_DCT_COEF, "DCT coefficient out of range")
+JMESSAGE(JERR_BAD_DCTSIZE, "DCT scaled block size %dx%d not supported")
+JMESSAGE(JERR_BAD_DROP_SAMPLING,
+ "Component index %d: mismatching sampling ratio %d:%d, %d:%d, %c")
+JMESSAGE(JERR_BAD_HUFF_TABLE, "Bogus Huffman table definition")
+JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace")
+JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace")
+JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length")
+JMESSAGE(JERR_BAD_LIB_VERSION,
+ "Wrong JPEG library version: library is %d, caller expects %d")
+JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan")
+JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d")
+JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d")
+JMESSAGE(JERR_BAD_PROGRESSION,
+ "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d")
+JMESSAGE(JERR_BAD_PROG_SCRIPT,
+ "Invalid progressive parameters at scan script entry %d")
+JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors")
+JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d")
+JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d")
+JMESSAGE(JERR_BAD_STRUCT_SIZE,
+ "JPEG parameter struct mismatch: library thinks size is %u, caller expects %u")
+JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access")
+JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small")
+JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here")
+JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet")
+JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d")
+JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request")
+JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d")
+JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x")
+JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d")
+JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d")
+JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)")
+JMESSAGE(JERR_EMS_READ, "Read from EMS failed")
+JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed")
+JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan")
+JMESSAGE(JERR_FILE_READ, "Input file read error")
+JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")
+JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet")
+JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow")
+JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry")
+JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels")
+JMESSAGE(JERR_INPUT_EMPTY, "Empty input file")
+JMESSAGE(JERR_INPUT_EOF, "Premature end of input file")
+JMESSAGE(JERR_MISMATCHED_QUANT_TABLE,
+ "Cannot transcode due to multiple use of quantization table %d")
+JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data")
+JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change")
+JMESSAGE(JERR_NOTIMPL, "Not implemented yet")
+JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time")
+JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined")
+JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported")
+JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined")
+JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image")
+JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined")
+JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x")
+JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)")
+JMESSAGE(JERR_QUANT_COMPONENTS,
+ "Cannot quantize more than %d color components")
+JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors")
+JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors")
+JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers")
+JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker")
+JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x")
+JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers")
+JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF")
+JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s")
+JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file")
+JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file")
+JMESSAGE(JERR_TFILE_WRITE,
+ "Write failed on temporary file --- out of disk space?")
+JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines")
+JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x")
+JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up")
+JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation")
+JMESSAGE(JERR_XMS_READ, "Read from XMS failed")
+JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed")
+JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT)
+JMESSAGE(JMSG_VERSION, JVERSION)
+JMESSAGE(JTRC_16BIT_TABLES,
+ "Caution: quantization tables are too coarse for baseline JPEG")
+JMESSAGE(JTRC_ADOBE,
+ "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d")
+JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u")
+JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u")
+JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x")
+JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x")
+JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d")
+JMESSAGE(JTRC_DRI, "Define Restart Interval %u")
+JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u")
+JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u")
+JMESSAGE(JTRC_EOI, "End Of Image")
+JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d")
+JMESSAGE(JTRC_JFIF, "JFIF APP0 marker: version %d.%02d, density %dx%d %d")
+JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE,
+ "Warning: thumbnail image size does not match data length %u")
+JMESSAGE(JTRC_JFIF_EXTENSION,
+ "JFIF extension marker: type 0x%02x, length %u")
+JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image")
+JMESSAGE(JTRC_MISC_MARKER, "Miscellaneous marker 0x%02x, length %u")
+JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x")
+JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u")
+JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors")
+JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors")
+JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization")
+JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d")
+JMESSAGE(JTRC_RST, "RST%d")
+JMESSAGE(JTRC_SMOOTH_NOTIMPL,
+ "Smoothing not supported with nonstandard sampling ratios")
+JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d")
+JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d")
+JMESSAGE(JTRC_SOI, "Start of Image")
+JMESSAGE(JTRC_SOS, "Start Of Scan: %d components")
+JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d")
+JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d")
+JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s")
+JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s")
+JMESSAGE(JTRC_THUMB_JPEG,
+ "JFIF extension marker: JPEG-compressed thumbnail image, length %u")
+JMESSAGE(JTRC_THUMB_PALETTE,
+ "JFIF extension marker: palette thumbnail image, length %u")
+JMESSAGE(JTRC_THUMB_RGB,
+ "JFIF extension marker: RGB thumbnail image, length %u")
+JMESSAGE(JTRC_UNKNOWN_IDS,
+ "Unrecognized component IDs %d %d %d, assuming YCbCr")
+JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u")
+JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u")
+JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d")
+JMESSAGE(JWRN_ARITH_BAD_CODE, "Corrupt JPEG data: bad arithmetic code")
+JMESSAGE(JWRN_BOGUS_PROGRESSION,
+ "Inconsistent progression sequence for component %d coefficient %d")
+JMESSAGE(JWRN_EXTRANEOUS_DATA,
+ "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x")
+JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment")
+JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")
+JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d")
+JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")
+JMESSAGE(JWRN_MUST_RESYNC,
+ "Corrupt JPEG data: found marker 0x%02x instead of RST%d")
+JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG")
+JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")
+
+#ifdef JMAKE_ENUM_LIST
+
+ JMSG_LASTMSGCODE
+} J_MESSAGE_CODE;
+
+#undef JMAKE_ENUM_LIST
+#endif /* JMAKE_ENUM_LIST */
+
+/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */
+#undef JMESSAGE
+
+
+#ifndef JERROR_H
+#define JERROR_H
+
+/* Macros to simplify using the error and trace message stuff */
+/* The first parameter is either type of cinfo pointer */
+
+/* Fatal errors (print message and exit) */
+#define ERREXIT(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT3(cinfo,code,p1,p2,p3) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (cinfo)->err->msg_parm.i[3] = (p4), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXIT6(cinfo,code,p1,p2,p3,p4,p5,p6) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (cinfo)->err->msg_parm.i[2] = (p3), \
+ (cinfo)->err->msg_parm.i[3] = (p4), \
+ (cinfo)->err->msg_parm.i[4] = (p5), \
+ (cinfo)->err->msg_parm.i[5] = (p6), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+#define ERREXITS(cinfo,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
+
+#define MAKESTMT(stuff) do { stuff } while (0)
+
+/* Nonfatal errors (we can keep going, but the data is probably corrupt) */
+#define WARNMS(cinfo,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS1(cinfo,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+#define WARNMS2(cinfo,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1))
+
+/* Informational/debugging messages */
+#define TRACEMS(cinfo,lvl,code) \
+ ((cinfo)->err->msg_code = (code), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS1(cinfo,lvl,code,p1) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS2(cinfo,lvl,code,p1,p2) \
+ ((cinfo)->err->msg_code = (code), \
+ (cinfo)->err->msg_parm.i[0] = (p1), \
+ (cinfo)->err->msg_parm.i[1] = (p2), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS5(cinfo,lvl,code,p1,p2,p3,p4,p5) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ _mp[4] = (p5); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \
+ MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \
+ _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \
+ _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \
+ (cinfo)->err->msg_code = (code); \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); )
+#define TRACEMSS(cinfo,lvl,code,str) \
+ ((cinfo)->err->msg_code = (code), \
+ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \
+ (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)))
+
+#endif /* JERROR_H */
diff --git a/jpg/jfdctflt.c b/jpg/jfdctflt.c
new file mode 100644
index 0000000..74d0d86
--- /dev/null
+++ b/jpg/jfdctflt.c
@@ -0,0 +1,174 @@
+/*
+ * jfdctflt.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2003-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a floating-point implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * This implementation should be more accurate than either of the integer
+ * DCT implementations. However, it may not give the same results on all
+ * machines because of differences in roundoff behavior. Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values. However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_float (FAST_FLOAT * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+ FAST_FLOAT z1, z2, z3, z4, z5, z11, z13;
+ FAST_FLOAT *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+
+ /* Pass 1: process rows. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Load data into workspace */
+ tmp0 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]));
+ tmp7 = (FAST_FLOAT) (GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]));
+ tmp1 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]));
+ tmp6 = (FAST_FLOAT) (GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]));
+ tmp2 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]));
+ tmp5 = (FAST_FLOAT) (GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]));
+ tmp3 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]));
+ tmp4 = (FAST_FLOAT) (GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]));
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */
+ dataptr[4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
+ dataptr[2] = tmp13 + z1; /* phase 5 */
+ dataptr[6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
+ z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
+ z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
+ z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[5] = z13 + z2; /* phase 6 */
+ dataptr[3] = z13 - z2;
+ dataptr[1] = z11 + z4;
+ dataptr[7] = z11 - z4;
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[DCTSIZE*4] = tmp10 - tmp11;
+
+ z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */
+ dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
+ dataptr[DCTSIZE*6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */
+ z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */
+ z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */
+ z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
+ dataptr[DCTSIZE*3] = z13 - z2;
+ dataptr[DCTSIZE*1] = z11 + z4;
+ dataptr[DCTSIZE*7] = z11 - z4;
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/jpg/jfdctfst.c b/jpg/jfdctfst.c
new file mode 100644
index 0000000..8cad5f2
--- /dev/null
+++ b/jpg/jfdctfst.c
@@ -0,0 +1,230 @@
+/*
+ * jfdctfst.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2003-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a fast, not so accurate integer implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with fixed-point math,
+ * accuracy is lost due to imprecise representation of the scaled
+ * quantization values. The smaller the quantization table entry, the less
+ * precise the scaled value, so this implementation does worse with high-
+ * quality-setting files than with low-quality ones.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_IFAST_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling decisions are generally the same as in the LL&M algorithm;
+ * see jfdctint.c for more details. However, we choose to descale
+ * (right shift) multiplication products as soon as they are formed,
+ * rather than carrying additional fractional bits into subsequent additions.
+ * This compromises accuracy slightly, but it lets us save a few shifts.
+ * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+ * everywhere except in the multiplications proper; this saves a good deal
+ * of work on 16-bit-int machines.
+ *
+ * Again to save a few shifts, the intermediate results between pass 1 and
+ * pass 2 are not upscaled, but are represented only to integral precision.
+ *
+ * A final compromise is to represent the multiplicative constants to only
+ * 8 fractional bits, rather than 13. This saves some shifting work on some
+ * machines, and may also reduce the cost of multiplication (since there
+ * are fewer one-bits in the constants).
+ */
+
+#define CONST_BITS 8
+
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 8
+#define FIX_0_382683433 ((INT32) 98) /* FIX(0.382683433) */
+#define FIX_0_541196100 ((INT32) 139) /* FIX(0.541196100) */
+#define FIX_0_707106781 ((INT32) 181) /* FIX(0.707106781) */
+#define FIX_1_306562965 ((INT32) 334) /* FIX(1.306562965) */
+#else
+#define FIX_0_382683433 FIX(0.382683433)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_707106781 FIX(0.707106781)
+#define FIX_1_306562965 FIX(1.306562965)
+#endif
+
+
+/* We can gain a little more speed, with a further compromise in accuracy,
+ * by omitting the addition in a descaling shift. This yields an incorrectly
+ * rounded result half the time...
+ */
+
+#ifndef USE_ACCURATE_ROUNDING
+#undef DESCALE
+#define DESCALE(x,n) RIGHT_SHIFT(x, n)
+#endif
+
+
+/* Multiply a DCTELEM variable by an INT32 constant, and immediately
+ * descale to yield a DCTELEM result.
+ */
+
+#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_ifast (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ DCTELEM tmp10, tmp11, tmp12, tmp13;
+ DCTELEM z1, z2, z3, z4, z5, z11, z13;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Load data into workspace */
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+ tmp7 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+ tmp6 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+ tmp5 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+ tmp4 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = tmp10 + tmp11 - 8 * CENTERJSAMPLE; /* phase 3 */
+ dataptr[4] = tmp10 - tmp11;
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+ dataptr[2] = tmp13 + z1; /* phase 5 */
+ dataptr[6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+ z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+ z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+ z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[5] = z13 + z2; /* phase 6 */
+ dataptr[3] = z13 - z2;
+ dataptr[1] = z11 + z4;
+ dataptr[7] = z11 - z4;
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns. */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ /* Even part */
+
+ tmp10 = tmp0 + tmp3; /* phase 2 */
+ tmp13 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp1 - tmp2;
+
+ dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */
+ dataptr[DCTSIZE*4] = tmp10 - tmp11;
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_707106781); /* c4 */
+ dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */
+ dataptr[DCTSIZE*6] = tmp13 - z1;
+
+ /* Odd part */
+
+ tmp10 = tmp4 + tmp5; /* phase 2 */
+ tmp11 = tmp5 + tmp6;
+ tmp12 = tmp6 + tmp7;
+
+ /* The rotator is modified from fig 4-8 to avoid extra negations. */
+ z5 = MULTIPLY(tmp10 - tmp12, FIX_0_382683433); /* c6 */
+ z2 = MULTIPLY(tmp10, FIX_0_541196100) + z5; /* c2-c6 */
+ z4 = MULTIPLY(tmp12, FIX_1_306562965) + z5; /* c2+c6 */
+ z3 = MULTIPLY(tmp11, FIX_0_707106781); /* c4 */
+
+ z11 = tmp7 + z3; /* phase 5 */
+ z13 = tmp7 - z3;
+
+ dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */
+ dataptr[DCTSIZE*3] = z13 - z2;
+ dataptr[DCTSIZE*1] = z11 + z4;
+ dataptr[DCTSIZE*7] = z11 - z4;
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#endif /* DCT_IFAST_SUPPORTED */
diff --git a/jpg/jfdctint.c b/jpg/jfdctint.c
new file mode 100644
index 0000000..1dde58c
--- /dev/null
+++ b/jpg/jfdctint.c
@@ -0,0 +1,4348 @@
+/*
+ * jfdctint.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modification developed 2003-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a slow-but-accurate integer implementation of the
+ * forward DCT (Discrete Cosine Transform).
+ *
+ * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT
+ * on each column. Direct algorithms are also available, but they are
+ * much more complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on an algorithm described in
+ * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ *
+ * We also provide FDCT routines with various input sample block sizes for
+ * direct resolution reduction or enlargement and for direct resolving the
+ * common 2x1 and 1x2 subsampling cases without additional resampling: NxN
+ * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 output DCT block.
+ *
+ * For N<8 we fill the remaining block coefficients with zero.
+ * For N>8 we apply a partial N-point FDCT on the input samples, computing
+ * just the lower 8 frequency coefficients and discarding the rest.
+ *
+ * We must scale the output coefficients of the N-point FDCT appropriately
+ * to the standard 8-point FDCT level by 8/N per 1-D pass. This scaling
+ * is folded into the constant multipliers (pass 2) and/or final/initial
+ * shifting.
+ *
+ * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases
+ * since there would be too many additional constants to pre-calculate.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_ISLOW_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */
+#endif
+
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D DCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true DCT outputs. The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm. The advantage of
+ * this arrangement is that we save two multiplications per 1-D DCT,
+ * because the y0 and y4 outputs need not be divided by sqrt(N).
+ * In the IJG code, this factor of 8 is removed by the quantization step
+ * (in jcdctmgr.c), NOT in this module.
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic. We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants). After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output. This division can be done
+ * cheaply as a right shift of CONST_BITS bits. We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision. These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling. (For 12-bit sample data, the intermediate
+ * array is INT32 anyway.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 13
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */
+#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */
+#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */
+#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
+#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
+#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */
+#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */
+#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
+#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */
+#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */
+#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
+#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */
+#else
+#define FIX_0_298631336 FIX(0.298631336)
+#define FIX_0_390180644 FIX(0.390180644)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_765366865 FIX(0.765366865)
+#define FIX_0_899976223 FIX(0.899976223)
+#define FIX_1_175875602 FIX(1.175875602)
+#define FIX_1_501321110 FIX(1.501321110)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_1_961570560 FIX(1.961570560)
+#define FIX_2_053119869 FIX(2.053119869)
+#define FIX_2_562915447 FIX(2.562915447)
+#define FIX_3_072711026 FIX(3.072711026)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const) ((var) * (const))
+#endif
+
+
+/*
+ * Perform the forward DCT on one block of samples.
+ */
+
+GLOBAL(void)
+jpeg_fdct_islow (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+ tmp10 = tmp0 + tmp3;
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ dataptr[2] = (DCTELEM) RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865),
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065),
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM)
+ RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM)
+ RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1));
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), CONST_BITS+PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+#ifdef DCT_SCALING_SUPPORTED
+
+
+/*
+ * Perform the forward DCT on a 7x7 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_7x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* cK represents sqrt(2) * cos(K*pi/14). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 7; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]);
+ tmp3 = GETJSAMPLE(elemptr[3]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]);
+
+ z1 = tmp0 + tmp2;
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp3 += tmp3;
+ z1 -= tmp3;
+ z1 -= tmp3;
+ z1 = MULTIPLY(z1, FIX(0.353553391)); /* (c2+c6-c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002)); /* (c2+c4-c6)/2 */
+ z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123)); /* c6 */
+ dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS);
+ z1 -= z2;
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734)); /* c4 */
+ dataptr[4] = (DCTELEM)
+ DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */
+ tmp1 += tmp2;
+ tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268)); /* c5 */
+ tmp0 += tmp3;
+ tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693)); /* c3+c1-c5 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/7)**2 = 64/49, which we fold
+ * into the constant multipliers:
+ * cK now represents sqrt(2) * cos(K*pi/14) * 64/49.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 7; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4];
+ tmp3 = dataptr[DCTSIZE*3];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5];
+ tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4];
+
+ z1 = tmp0 + tmp2;
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */
+ CONST_BITS+PASS1_BITS);
+ tmp3 += tmp3;
+ z1 -= tmp3;
+ z1 -= tmp3;
+ z1 = MULTIPLY(z1, FIX(0.461784020)); /* (c2+c6-c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084)); /* (c2+c4-c6)/2 */
+ z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS);
+ z1 -= z2;
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509)); /* c4 */
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */
+ tmp1 += tmp2;
+ tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310)); /* c5 */
+ tmp0 += tmp3;
+ tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355)); /* c3+c1-c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x6 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ INT32 tmp10, tmp11, tmp12;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* cK represents sqrt(2) * cos(K*pi/12). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+ tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */
+ CONST_BITS-PASS1_BITS);
+
+ dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS));
+ dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS);
+ dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS));
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/6)**2 = 16/9, which we fold
+ * into the constant multipliers:
+ * cK now represents sqrt(2) * cos(K*pi/12) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+ tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 5x5 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_5x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ INT32 tmp10, tmp11;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/10). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 5; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]);
+ tmp2 = GETJSAMPLE(elemptr[2]);
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ tmp11 = MULTIPLY(tmp11, FIX(0.790569415)); /* (c2+c4)/2 */
+ tmp10 -= tmp2 << 2;
+ tmp10 = MULTIPLY(tmp10, FIX(0.353553391)); /* (c2-c4)/2 */
+ dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS-1);
+ dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS-1);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876)); /* c3 */
+
+ dataptr[1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */
+ CONST_BITS-PASS1_BITS-1);
+ dataptr[3] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */
+ CONST_BITS-PASS1_BITS-1);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/5)**2 = 64/25, which we partially
+ * fold into the constant multipliers (other part was done in pass 1):
+ * cK now represents sqrt(2) * cos(K*pi/10) * 32/25.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 5; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3];
+ tmp2 = dataptr[DCTSIZE*2];
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)), /* 32/25 */
+ CONST_BITS+PASS1_BITS);
+ tmp11 = MULTIPLY(tmp11, FIX(1.011928851)); /* (c2+c4)/2 */
+ tmp10 -= tmp2 << 2;
+ tmp10 = MULTIPLY(tmp10, FIX(0.452548340)); /* (c2-c4)/2 */
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961)); /* c3 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x4 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+ INT32 tmp10, tmp11;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We must also scale the output by (8/4)**2 = 2**2, which we add here. */
+ /* cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+2));
+ dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+2));
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-3);
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS-2);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS-2);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1));
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 3x3 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_3x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We scale the results further by 2**2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/6). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 3; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]);
+ tmp1 = GETJSAMPLE(elemptr[1]);
+
+ tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+2));
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */
+ CONST_BITS-PASS1_BITS-2);
+
+ /* Odd part */
+
+ dataptr[1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2, FIX(1.224744871)), /* c1 */
+ CONST_BITS-PASS1_BITS-2);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/3)**2 = 64/9, which we partially
+ * fold into the constant multipliers (other part was done in pass 1):
+ * cK now represents sqrt(2) * cos(K*pi/6) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 3; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2];
+ tmp1 = dataptr[DCTSIZE*1];
+
+ tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2, FIX(2.177324216)), /* c1 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x2 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ JSAMPROW elemptr;
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+
+ /* Row 0 */
+ elemptr = sample_data[0] + start_col;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]);
+ tmp1 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]);
+
+ /* Row 1 */
+ elemptr = sample_data[1] + start_col;
+
+ tmp2 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[1]);
+ tmp3 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[1]);
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/2)**2 = 2**4.
+ */
+
+ /* Column 0 */
+ /* Apply unsigned->signed conversion */
+ data[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp2 - 4 * CENTERJSAMPLE) << 4);
+ data[DCTSIZE*1] = (DCTELEM) ((tmp0 - tmp2) << 4);
+
+ /* Column 1 */
+ data[DCTSIZE*0+1] = (DCTELEM) ((tmp1 + tmp3) << 4);
+ data[DCTSIZE*1+1] = (DCTELEM) ((tmp1 - tmp3) << 4);
+}
+
+
+/*
+ * Perform the forward DCT on a 1x1 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_1x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* We leave the result scaled up by an overall factor of 8. */
+ /* We must also scale the output by (8/1)**2 = 2**6. */
+ /* Apply unsigned->signed conversion */
+ data[0] = (DCTELEM)
+ ((GETJSAMPLE(sample_data[0][start_col]) - CENTERJSAMPLE) << 6);
+}
+
+
+/*
+ * Perform the forward DCT on a 9x9 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_9x9 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2;
+ DCTELEM workspace[8];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* we scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/18). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[8]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[7]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[6]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[5]);
+ tmp4 = GETJSAMPLE(elemptr[4]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[8]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[7]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[6]);
+ tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[5]);
+
+ z1 = tmp0 + tmp2 + tmp3;
+ z2 = tmp1 + tmp4;
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) ((z1 + z2 - 9 * CENTERJSAMPLE) << 1);
+ dataptr[6] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 - z2 - z2, FIX(0.707106781)), /* c6 */
+ CONST_BITS-1);
+ z1 = MULTIPLY(tmp0 - tmp2, FIX(1.328926049)); /* c2 */
+ z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(0.707106781)); /* c6 */
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.083350441)) /* c4 */
+ + z1 + z2, CONST_BITS-1);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.245575608)) /* c8 */
+ + z1 - z2, CONST_BITS-1);
+
+ /* Odd part */
+
+ dataptr[3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.224744871)), /* c3 */
+ CONST_BITS-1);
+
+ tmp11 = MULTIPLY(tmp11, FIX(1.224744871)); /* c3 */
+ tmp0 = MULTIPLY(tmp10 + tmp12, FIX(0.909038955)); /* c5 */
+ tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.483689525)); /* c7 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS-1);
+
+ tmp2 = MULTIPLY(tmp12 - tmp13, FIX(1.392728481)); /* c1 */
+
+ dataptr[5] = (DCTELEM) DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS-1);
+ dataptr[7] = (DCTELEM) DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS-1);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 9)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/9)**2 = 64/81, which we partially
+ * fold into the constant multipliers and final/initial shifting:
+ * cK now represents sqrt(2) * cos(K*pi/18) * 128/81.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*0];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*7];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*6];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*5];
+ tmp4 = dataptr[DCTSIZE*4];
+
+ tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*0];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*7];
+ tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*6];
+ tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*5];
+
+ z1 = tmp0 + tmp2 + tmp3;
+ z2 = tmp1 + tmp4;
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 + z2, FIX(1.580246914)), /* 128/81 */
+ CONST_BITS+2);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 - z2 - z2, FIX(1.117403309)), /* c6 */
+ CONST_BITS+2);
+ z1 = MULTIPLY(tmp0 - tmp2, FIX(2.100031287)); /* c2 */
+ z2 = MULTIPLY(tmp1 - tmp4 - tmp4, FIX(1.117403309)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2 - tmp3, FIX(1.711961190)) /* c4 */
+ + z1 + z2, CONST_BITS+2);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp3 - tmp0, FIX(0.388070096)) /* c8 */
+ + z1 - z2, CONST_BITS+2);
+
+ /* Odd part */
+
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12 - tmp13, FIX(1.935399303)), /* c3 */
+ CONST_BITS+2);
+
+ tmp11 = MULTIPLY(tmp11, FIX(1.935399303)); /* c3 */
+ tmp0 = MULTIPLY(tmp10 + tmp12, FIX(1.436506004)); /* c5 */
+ tmp1 = MULTIPLY(tmp10 + tmp13, FIX(0.764348879)); /* c7 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp11 + tmp0 + tmp1, CONST_BITS+2);
+
+ tmp2 = MULTIPLY(tmp12 - tmp13, FIX(2.200854883)); /* c1 */
+
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp0 - tmp11 - tmp2, CONST_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ DESCALE(tmp1 - tmp11 + tmp2, CONST_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 10x10 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_10x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ DCTELEM workspace[8*2];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* we scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/20). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]);
+ tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]);
+
+ tmp10 = tmp0 + tmp4;
+ tmp13 = tmp0 - tmp4;
+ tmp11 = tmp1 + tmp3;
+ tmp14 = tmp1 - tmp3;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << 1);
+ tmp12 += tmp12;
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */
+ MULTIPLY(tmp11 - tmp12, FIX(0.437016024)), /* c8 */
+ CONST_BITS-1);
+ tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876)); /* c6 */
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)), /* c2-c6 */
+ CONST_BITS-1);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)), /* c2+c6 */
+ CONST_BITS-1);
+
+ /* Odd part */
+
+ tmp10 = tmp0 + tmp4;
+ tmp11 = tmp1 - tmp3;
+ dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << 1);
+ tmp2 <<= CONST_BITS;
+ dataptr[1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) + /* c1 */
+ MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 + /* c3 */
+ MULTIPLY(tmp3, FIX(0.642039522)) + /* c7 */
+ MULTIPLY(tmp4, FIX(0.221231742)), /* c9 */
+ CONST_BITS-1);
+ tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) - /* (c3+c7)/2 */
+ MULTIPLY(tmp1 + tmp3, FIX(0.587785252)); /* (c1-c9)/2 */
+ tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) + /* (c3-c7)/2 */
+ (tmp11 << (CONST_BITS - 1)) - tmp2;
+ dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-1);
+ dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-1);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 10)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/10)**2 = 16/25, which we partially
+ * fold into the constant multipliers and final/initial shifting:
+ * cK now represents sqrt(2) * cos(K*pi/20) * 32/25.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0];
+ tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5];
+
+ tmp10 = tmp0 + tmp4;
+ tmp13 = tmp0 - tmp4;
+ tmp11 = tmp1 + tmp3;
+ tmp14 = tmp1 - tmp3;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6];
+ tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */
+ CONST_BITS+2);
+ tmp12 += tmp12;
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */
+ MULTIPLY(tmp11 - tmp12, FIX(0.559380511)), /* c8 */
+ CONST_BITS+2);
+ tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)), /* c2-c6 */
+ CONST_BITS+2);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)), /* c2+c6 */
+ CONST_BITS+2);
+
+ /* Odd part */
+
+ tmp10 = tmp0 + tmp4;
+ tmp11 = tmp1 - tmp3;
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)), /* 32/25 */
+ CONST_BITS+2);
+ tmp2 = MULTIPLY(tmp2, FIX(1.28)); /* 32/25 */
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) + /* c1 */
+ MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 + /* c3 */
+ MULTIPLY(tmp3, FIX(0.821810588)) + /* c7 */
+ MULTIPLY(tmp4, FIX(0.283176630)), /* c9 */
+ CONST_BITS+2);
+ tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) - /* (c3+c7)/2 */
+ MULTIPLY(tmp1 + tmp3, FIX(0.752365123)); /* (c1-c9)/2 */
+ tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) + /* (c3-c7)/2 */
+ MULTIPLY(tmp11, FIX(0.64)) - tmp2; /* 16/25 */
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on an 11x11 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_11x11 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 z1, z2, z3;
+ DCTELEM workspace[8*3];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* we scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* cK represents sqrt(2) * cos(K*pi/22). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[10]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[9]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[8]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[7]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[6]);
+ tmp5 = GETJSAMPLE(elemptr[5]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[10]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[9]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[8]);
+ tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[7]);
+ tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[6]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 - 11 * CENTERJSAMPLE) << 1);
+ tmp5 += tmp5;
+ tmp0 -= tmp5;
+ tmp1 -= tmp5;
+ tmp2 -= tmp5;
+ tmp3 -= tmp5;
+ tmp4 -= tmp5;
+ z1 = MULTIPLY(tmp0 + tmp3, FIX(1.356927976)) + /* c2 */
+ MULTIPLY(tmp2 + tmp4, FIX(0.201263574)); /* c10 */
+ z2 = MULTIPLY(tmp1 - tmp3, FIX(0.926112931)); /* c6 */
+ z3 = MULTIPLY(tmp0 - tmp1, FIX(1.189712156)); /* c4 */
+ dataptr[2] = (DCTELEM)
+ DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.018300590)) /* c2+c8-c6 */
+ - MULTIPLY(tmp4, FIX(1.390975730)), /* c4+c10 */
+ CONST_BITS-1);
+ dataptr[4] = (DCTELEM)
+ DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.062335650)) /* c4-c6-c10 */
+ - MULTIPLY(tmp2, FIX(1.356927976)) /* c2 */
+ + MULTIPLY(tmp4, FIX(0.587485545)), /* c8 */
+ CONST_BITS-1);
+ dataptr[6] = (DCTELEM)
+ DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.620527200)) /* c2+c4-c6 */
+ - MULTIPLY(tmp2, FIX(0.788749120)), /* c8+c10 */
+ CONST_BITS-1);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.286413905)); /* c3 */
+ tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.068791298)); /* c5 */
+ tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.764581576)); /* c7 */
+ tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.719967871)) /* c7+c5+c3-c1 */
+ + MULTIPLY(tmp14, FIX(0.398430003)); /* c9 */
+ tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.764581576)); /* -c7 */
+ tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.399818907)); /* -c1 */
+ tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.276416582)) /* c9+c7+c1-c3 */
+ - MULTIPLY(tmp14, FIX(1.068791298)); /* c5 */
+ tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.398430003)); /* c9 */
+ tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(1.989053629)) /* c9+c5+c3-c7 */
+ + MULTIPLY(tmp14, FIX(1.399818907)); /* c1 */
+ tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.305598626)) /* c1+c5-c9-c7 */
+ - MULTIPLY(tmp14, FIX(1.286413905)); /* c3 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-1);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-1);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-1);
+ dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS-1);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 11)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/11)**2 = 64/121, which we partially
+ * fold into the constant multipliers and final/initial shifting:
+ * cK now represents sqrt(2) * cos(K*pi/22) * 128/121.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*2];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*1];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*0];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*7];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*6];
+ tmp5 = dataptr[DCTSIZE*5];
+
+ tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*2];
+ tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*1];
+ tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*0];
+ tmp13 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*7];
+ tmp14 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*6];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5,
+ FIX(1.057851240)), /* 128/121 */
+ CONST_BITS+2);
+ tmp5 += tmp5;
+ tmp0 -= tmp5;
+ tmp1 -= tmp5;
+ tmp2 -= tmp5;
+ tmp3 -= tmp5;
+ tmp4 -= tmp5;
+ z1 = MULTIPLY(tmp0 + tmp3, FIX(1.435427942)) + /* c2 */
+ MULTIPLY(tmp2 + tmp4, FIX(0.212906922)); /* c10 */
+ z2 = MULTIPLY(tmp1 - tmp3, FIX(0.979689713)); /* c6 */
+ z3 = MULTIPLY(tmp0 - tmp1, FIX(1.258538479)); /* c4 */
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(z1 + z2 - MULTIPLY(tmp3, FIX(1.077210542)) /* c2+c8-c6 */
+ - MULTIPLY(tmp4, FIX(1.471445400)), /* c4+c10 */
+ CONST_BITS+2);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(z2 + z3 + MULTIPLY(tmp1, FIX(0.065941844)) /* c4-c6-c10 */
+ - MULTIPLY(tmp2, FIX(1.435427942)) /* c2 */
+ + MULTIPLY(tmp4, FIX(0.621472312)), /* c8 */
+ CONST_BITS+2);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(z1 + z3 - MULTIPLY(tmp0, FIX(1.714276708)) /* c2+c4-c6 */
+ - MULTIPLY(tmp2, FIX(0.834379234)), /* c8+c10 */
+ CONST_BITS+2);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.360834544)); /* c3 */
+ tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.130622199)); /* c5 */
+ tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.808813568)); /* c7 */
+ tmp0 = tmp1 + tmp2 + tmp3 - MULTIPLY(tmp10, FIX(1.819470145)) /* c7+c5+c3-c1 */
+ + MULTIPLY(tmp14, FIX(0.421479672)); /* c9 */
+ tmp4 = MULTIPLY(tmp11 + tmp12, - FIX(0.808813568)); /* -c7 */
+ tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.480800167)); /* -c1 */
+ tmp1 += tmp4 + tmp5 + MULTIPLY(tmp11, FIX(1.350258864)) /* c9+c7+c1-c3 */
+ - MULTIPLY(tmp14, FIX(1.130622199)); /* c5 */
+ tmp10 = MULTIPLY(tmp12 + tmp13, FIX(0.421479672)); /* c9 */
+ tmp2 += tmp4 + tmp10 - MULTIPLY(tmp12, FIX(2.104122847)) /* c9+c5+c3-c7 */
+ + MULTIPLY(tmp14, FIX(1.480800167)); /* c1 */
+ tmp3 += tmp5 + tmp10 + MULTIPLY(tmp13, FIX(1.381129125)) /* c1+c5-c9-c7 */
+ - MULTIPLY(tmp14, FIX(1.360834544)); /* c3 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 12x12 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_12x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ DCTELEM workspace[8*4];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* cK represents sqrt(2) * cos(K*pi/24). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]);
+
+ tmp10 = tmp0 + tmp5;
+ tmp13 = tmp0 - tmp5;
+ tmp11 = tmp1 + tmp4;
+ tmp14 = tmp1 - tmp4;
+ tmp12 = tmp2 + tmp3;
+ tmp15 = tmp2 - tmp3;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) (tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE);
+ dataptr[6] = (DCTELEM) (tmp13 - tmp14 - tmp15);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */
+ CONST_BITS);
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */
+ CONST_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100); /* c9 */
+ tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865); /* c3-c9 */
+ tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065); /* c3+c9 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054)); /* c5 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669)); /* c7 */
+ tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */
+ + MULTIPLY(tmp5, FIX(0.184591911)); /* c11 */
+ tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */
+ tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */
+ + MULTIPLY(tmp5, FIX(0.860918669)); /* c7 */
+ tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */
+ - MULTIPLY(tmp5, FIX(1.121971054)); /* c5 */
+ tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */
+ - MULTIPLY(tmp2 + tmp5, FIX_0_541196100); /* c9 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 12)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/12)**2 = 4/9, which we partially
+ * fold into the constant multipliers and final shifting:
+ * cK now represents sqrt(2) * cos(K*pi/24) * 8/9.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7];
+ tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6];
+
+ tmp10 = tmp0 + tmp5;
+ tmp13 = tmp0 - tmp5;
+ tmp11 = tmp1 + tmp4;
+ tmp14 = tmp1 - tmp4;
+ tmp12 = tmp2 + tmp3;
+ tmp15 = tmp2 - tmp3;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0];
+ tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7];
+ tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)), /* c4 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) + /* 8/9 */
+ MULTIPLY(tmp13 + tmp15, FIX(1.214244803)), /* c2 */
+ CONST_BITS+1);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200)); /* c9 */
+ tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102)); /* c3-c9 */
+ tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502)); /* c3+c9 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603)); /* c5 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039)); /* c7 */
+ tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */
+ + MULTIPLY(tmp5, FIX(0.164081699)); /* c11 */
+ tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */
+ tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */
+ + MULTIPLY(tmp5, FIX(0.765261039)); /* c7 */
+ tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */
+ - MULTIPLY(tmp5, FIX(0.997307603)); /* c5 */
+ tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */
+ - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+1);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 13x13 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_13x13 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 z1, z2;
+ DCTELEM workspace[8*5];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* cK represents sqrt(2) * cos(K*pi/26). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[12]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[11]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[10]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[9]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[8]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[7]);
+ tmp6 = GETJSAMPLE(elemptr[6]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[12]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[11]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[10]);
+ tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[9]);
+ tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[8]);
+ tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[7]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ (tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6 - 13 * CENTERJSAMPLE);
+ tmp6 += tmp6;
+ tmp0 -= tmp6;
+ tmp1 -= tmp6;
+ tmp2 -= tmp6;
+ tmp3 -= tmp6;
+ tmp4 -= tmp6;
+ tmp5 -= tmp6;
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.373119086)) + /* c2 */
+ MULTIPLY(tmp1, FIX(1.058554052)) + /* c6 */
+ MULTIPLY(tmp2, FIX(0.501487041)) - /* c10 */
+ MULTIPLY(tmp3, FIX(0.170464608)) - /* c12 */
+ MULTIPLY(tmp4, FIX(0.803364869)) - /* c8 */
+ MULTIPLY(tmp5, FIX(1.252223920)), /* c4 */
+ CONST_BITS);
+ z1 = MULTIPLY(tmp0 - tmp2, FIX(1.155388986)) - /* (c4+c6)/2 */
+ MULTIPLY(tmp3 - tmp4, FIX(0.435816023)) - /* (c2-c10)/2 */
+ MULTIPLY(tmp1 - tmp5, FIX(0.316450131)); /* (c8-c12)/2 */
+ z2 = MULTIPLY(tmp0 + tmp2, FIX(0.096834934)) - /* (c4-c6)/2 */
+ MULTIPLY(tmp3 + tmp4, FIX(0.937303064)) + /* (c2+c10)/2 */
+ MULTIPLY(tmp1 + tmp5, FIX(0.486914739)); /* (c8+c12)/2 */
+
+ dataptr[4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.322312651)); /* c3 */
+ tmp2 = MULTIPLY(tmp10 + tmp12, FIX(1.163874945)); /* c5 */
+ tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.937797057)) + /* c7 */
+ MULTIPLY(tmp14 + tmp15, FIX(0.338443458)); /* c11 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(tmp10, FIX(2.020082300)) + /* c3+c5+c7-c1 */
+ MULTIPLY(tmp14, FIX(0.318774355)); /* c9-c11 */
+ tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.937797057)) - /* c7 */
+ MULTIPLY(tmp11 + tmp12, FIX(0.338443458)); /* c11 */
+ tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(1.163874945)); /* -c5 */
+ tmp1 += tmp4 + tmp5 +
+ MULTIPLY(tmp11, FIX(0.837223564)) - /* c5+c9+c11-c3 */
+ MULTIPLY(tmp14, FIX(2.341699410)); /* c1+c7 */
+ tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.657217813)); /* -c9 */
+ tmp2 += tmp4 + tmp6 -
+ MULTIPLY(tmp12, FIX(1.572116027)) + /* c1+c5-c9-c11 */
+ MULTIPLY(tmp15, FIX(2.260109708)); /* c3+c7 */
+ tmp3 += tmp5 + tmp6 +
+ MULTIPLY(tmp13, FIX(2.205608352)) - /* c3+c5+c9-c7 */
+ MULTIPLY(tmp15, FIX(1.742345811)); /* c1+c11 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 13)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/13)**2 = 64/169, which we partially
+ * fold into the constant multipliers and final shifting:
+ * cK now represents sqrt(2) * cos(K*pi/26) * 128/169.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*3];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*2];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*1];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*0];
+ tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*7];
+ tmp6 = dataptr[DCTSIZE*6];
+
+ tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*4];
+ tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*3];
+ tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*2];
+ tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*1];
+ tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*0];
+ tmp15 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*7];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 + tmp1 + tmp2 + tmp3 + tmp4 + tmp5 + tmp6,
+ FIX(0.757396450)), /* 128/169 */
+ CONST_BITS+1);
+ tmp6 += tmp6;
+ tmp0 -= tmp6;
+ tmp1 -= tmp6;
+ tmp2 -= tmp6;
+ tmp3 -= tmp6;
+ tmp4 -= tmp6;
+ tmp5 -= tmp6;
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.039995521)) + /* c2 */
+ MULTIPLY(tmp1, FIX(0.801745081)) + /* c6 */
+ MULTIPLY(tmp2, FIX(0.379824504)) - /* c10 */
+ MULTIPLY(tmp3, FIX(0.129109289)) - /* c12 */
+ MULTIPLY(tmp4, FIX(0.608465700)) - /* c8 */
+ MULTIPLY(tmp5, FIX(0.948429952)), /* c4 */
+ CONST_BITS+1);
+ z1 = MULTIPLY(tmp0 - tmp2, FIX(0.875087516)) - /* (c4+c6)/2 */
+ MULTIPLY(tmp3 - tmp4, FIX(0.330085509)) - /* (c2-c10)/2 */
+ MULTIPLY(tmp1 - tmp5, FIX(0.239678205)); /* (c8-c12)/2 */
+ z2 = MULTIPLY(tmp0 + tmp2, FIX(0.073342435)) - /* (c4-c6)/2 */
+ MULTIPLY(tmp3 + tmp4, FIX(0.709910013)) + /* (c2+c10)/2 */
+ MULTIPLY(tmp1 + tmp5, FIX(0.368787494)); /* (c8+c12)/2 */
+
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - z2, CONST_BITS+1);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.001514908)); /* c3 */
+ tmp2 = MULTIPLY(tmp10 + tmp12, FIX(0.881514751)); /* c5 */
+ tmp3 = MULTIPLY(tmp10 + tmp13, FIX(0.710284161)) + /* c7 */
+ MULTIPLY(tmp14 + tmp15, FIX(0.256335874)); /* c11 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(tmp10, FIX(1.530003162)) + /* c3+c5+c7-c1 */
+ MULTIPLY(tmp14, FIX(0.241438564)); /* c9-c11 */
+ tmp4 = MULTIPLY(tmp14 - tmp15, FIX(0.710284161)) - /* c7 */
+ MULTIPLY(tmp11 + tmp12, FIX(0.256335874)); /* c11 */
+ tmp5 = MULTIPLY(tmp11 + tmp13, - FIX(0.881514751)); /* -c5 */
+ tmp1 += tmp4 + tmp5 +
+ MULTIPLY(tmp11, FIX(0.634110155)) - /* c5+c9+c11-c3 */
+ MULTIPLY(tmp14, FIX(1.773594819)); /* c1+c7 */
+ tmp6 = MULTIPLY(tmp12 + tmp13, - FIX(0.497774438)); /* -c9 */
+ tmp2 += tmp4 + tmp6 -
+ MULTIPLY(tmp12, FIX(1.190715098)) + /* c1+c5-c9-c11 */
+ MULTIPLY(tmp15, FIX(1.711799069)); /* c3+c7 */
+ tmp3 += tmp5 + tmp6 +
+ MULTIPLY(tmp13, FIX(1.670519935)) - /* c3+c5+c9-c7 */
+ MULTIPLY(tmp15, FIX(1.319646532)); /* c1+c11 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+1);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 14x14 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_14x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ DCTELEM workspace[8*6];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* cK represents sqrt(2) * cos(K*pi/28). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]);
+ tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]);
+
+ tmp10 = tmp0 + tmp6;
+ tmp14 = tmp0 - tmp6;
+ tmp11 = tmp1 + tmp5;
+ tmp15 = tmp1 - tmp5;
+ tmp12 = tmp2 + tmp4;
+ tmp16 = tmp2 - tmp4;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]);
+ tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ (tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE);
+ tmp13 += tmp13;
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */
+ MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */
+ MULTIPLY(tmp12 - tmp13, FIX(0.881747734)), /* c8 */
+ CONST_BITS);
+
+ tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686)); /* c6 */
+
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590)) /* c2-c6 */
+ + MULTIPLY(tmp16, FIX(0.613604268)), /* c10 */
+ CONST_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954)) /* c6+c10 */
+ - MULTIPLY(tmp16, FIX(1.378756276)), /* c2 */
+ CONST_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp1 + tmp2;
+ tmp11 = tmp5 - tmp4;
+ dataptr[7] = (DCTELEM) (tmp0 - tmp10 + tmp3 - tmp11 - tmp6);
+ tmp3 <<= CONST_BITS;
+ tmp10 = MULTIPLY(tmp10, - FIX(0.158341681)); /* -c13 */
+ tmp11 = MULTIPLY(tmp11, FIX(1.405321284)); /* c1 */
+ tmp10 += tmp11 - tmp3;
+ tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) + /* c5 */
+ MULTIPLY(tmp4 + tmp6, FIX(0.752406978)); /* c9 */
+ dataptr[5] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */
+ + MULTIPLY(tmp4, FIX(1.119999435)), /* c1+c11-c9 */
+ CONST_BITS);
+ tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) + /* c3 */
+ MULTIPLY(tmp5 - tmp6, FIX(0.467085129)); /* c11 */
+ dataptr[3] = (DCTELEM)
+ DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */
+ - MULTIPLY(tmp5, FIX(3.069855259)), /* c1+c5+c11 */
+ CONST_BITS);
+ dataptr[1] = (DCTELEM)
+ DESCALE(tmp11 + tmp12 + tmp3 + tmp6 -
+ MULTIPLY(tmp0 + tmp6, FIX(1.126980169)), /* c3+c5-c1 */
+ CONST_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 14)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/14)**2 = 16/49, which we partially
+ * fold into the constant multipliers and final shifting:
+ * cK now represents sqrt(2) * cos(K*pi/28) * 32/49.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3];
+ tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0];
+ tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7];
+
+ tmp10 = tmp0 + tmp6;
+ tmp14 = tmp0 - tmp6;
+ tmp11 = tmp1 + tmp5;
+ tmp15 = tmp1 - tmp5;
+ tmp12 = tmp2 + tmp4;
+ tmp16 = tmp2 - tmp4;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2];
+ tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1];
+ tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0];
+ tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13,
+ FIX(0.653061224)), /* 32/49 */
+ CONST_BITS+1);
+ tmp13 += tmp13;
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */
+ MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */
+ MULTIPLY(tmp12 - tmp13, FIX(0.575835255)), /* c8 */
+ CONST_BITS+1);
+
+ tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570)); /* c6 */
+
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691)) /* c2-c6 */
+ + MULTIPLY(tmp16, FIX(0.400721155)), /* c10 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725)) /* c6+c10 */
+ - MULTIPLY(tmp16, FIX(0.900412262)), /* c2 */
+ CONST_BITS+1);
+
+ /* Odd part */
+
+ tmp10 = tmp1 + tmp2;
+ tmp11 = tmp5 - tmp4;
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6,
+ FIX(0.653061224)), /* 32/49 */
+ CONST_BITS+1);
+ tmp3 = MULTIPLY(tmp3 , FIX(0.653061224)); /* 32/49 */
+ tmp10 = MULTIPLY(tmp10, - FIX(0.103406812)); /* -c13 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.917760839)); /* c1 */
+ tmp10 += tmp11 - tmp3;
+ tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) + /* c5 */
+ MULTIPLY(tmp4 + tmp6, FIX(0.491367823)); /* c9 */
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */
+ + MULTIPLY(tmp4, FIX(0.731428202)), /* c1+c11-c9 */
+ CONST_BITS+1);
+ tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) + /* c3 */
+ MULTIPLY(tmp5 - tmp6, FIX(0.305035186)); /* c11 */
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */
+ - MULTIPLY(tmp5, FIX(2.004803435)), /* c1+c5+c11 */
+ CONST_BITS+1);
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp11 + tmp12 + tmp3
+ - MULTIPLY(tmp0, FIX(0.735987049)) /* c3+c5-c1 */
+ - MULTIPLY(tmp6, FIX(0.082925825)), /* c9-c11-c13 */
+ CONST_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 15x15 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_15x15 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 z1, z2, z3;
+ DCTELEM workspace[8*7];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* cK represents sqrt(2) * cos(K*pi/30). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[14]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[13]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[12]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[11]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[10]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[9]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[8]);
+ tmp7 = GETJSAMPLE(elemptr[7]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[14]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[13]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[12]);
+ tmp13 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[11]);
+ tmp14 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[10]);
+ tmp15 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[9]);
+ tmp16 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[8]);
+
+ z1 = tmp0 + tmp4 + tmp5;
+ z2 = tmp1 + tmp3 + tmp6;
+ z3 = tmp2 + tmp7;
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) (z1 + z2 + z3 - 15 * CENTERJSAMPLE);
+ z3 += z3;
+ dataptr[6] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 - z3, FIX(1.144122806)) - /* c6 */
+ MULTIPLY(z2 - z3, FIX(0.437016024)), /* c12 */
+ CONST_BITS);
+ tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7;
+ z1 = MULTIPLY(tmp3 - tmp2, FIX(1.531135173)) - /* c2+c14 */
+ MULTIPLY(tmp6 - tmp2, FIX(2.238241955)); /* c4+c8 */
+ z2 = MULTIPLY(tmp5 - tmp2, FIX(0.798468008)) - /* c8-c14 */
+ MULTIPLY(tmp0 - tmp2, FIX(0.091361227)); /* c2-c4 */
+ z3 = MULTIPLY(tmp0 - tmp3, FIX(1.383309603)) + /* c2 */
+ MULTIPLY(tmp6 - tmp5, FIX(0.946293579)) + /* c8 */
+ MULTIPLY(tmp1 - tmp4, FIX(0.790569415)); /* (c6+c12)/2 */
+
+ dataptr[2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS);
+ dataptr[4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS);
+
+ /* Odd part */
+
+ tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16,
+ FIX(1.224744871)); /* c5 */
+ tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.344997024)) + /* c3 */
+ MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.831253876)); /* c9 */
+ tmp12 = MULTIPLY(tmp12, FIX(1.224744871)); /* c5 */
+ tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.406466353)) + /* c1 */
+ MULTIPLY(tmp11 + tmp14, FIX(1.344997024)) + /* c3 */
+ MULTIPLY(tmp13 + tmp15, FIX(0.575212477)); /* c11 */
+ tmp0 = MULTIPLY(tmp13, FIX(0.475753014)) - /* c7-c11 */
+ MULTIPLY(tmp14, FIX(0.513743148)) + /* c3-c9 */
+ MULTIPLY(tmp16, FIX(1.700497885)) + tmp4 + tmp12; /* c1+c13 */
+ tmp3 = MULTIPLY(tmp10, - FIX(0.355500862)) - /* -(c1-c7) */
+ MULTIPLY(tmp11, FIX(2.176250899)) - /* c3+c9 */
+ MULTIPLY(tmp15, FIX(0.869244010)) + tmp4 - tmp12; /* c11+c13 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp3, CONST_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 15)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/15)**2 = 64/225, which we partially
+ * fold into the constant multipliers and final shifting:
+ * cK now represents sqrt(2) * cos(K*pi/30) * 256/225.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*6];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*5];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*4];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*3];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*2];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*1];
+ tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*0];
+ tmp7 = dataptr[DCTSIZE*7];
+
+ tmp10 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*6];
+ tmp11 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*5];
+ tmp12 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*4];
+ tmp13 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*3];
+ tmp14 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*2];
+ tmp15 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*1];
+ tmp16 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*0];
+
+ z1 = tmp0 + tmp4 + tmp5;
+ z2 = tmp1 + tmp3 + tmp6;
+ z3 = tmp2 + tmp7;
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 + z2 + z3, FIX(1.137777778)), /* 256/225 */
+ CONST_BITS+2);
+ z3 += z3;
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 - z3, FIX(1.301757503)) - /* c6 */
+ MULTIPLY(z2 - z3, FIX(0.497227121)), /* c12 */
+ CONST_BITS+2);
+ tmp2 += ((tmp1 + tmp4) >> 1) - tmp7 - tmp7;
+ z1 = MULTIPLY(tmp3 - tmp2, FIX(1.742091575)) - /* c2+c14 */
+ MULTIPLY(tmp6 - tmp2, FIX(2.546621957)); /* c4+c8 */
+ z2 = MULTIPLY(tmp5 - tmp2, FIX(0.908479156)) - /* c8-c14 */
+ MULTIPLY(tmp0 - tmp2, FIX(0.103948774)); /* c2-c4 */
+ z3 = MULTIPLY(tmp0 - tmp3, FIX(1.573898926)) + /* c2 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.076671805)) + /* c8 */
+ MULTIPLY(tmp1 - tmp4, FIX(0.899492312)); /* (c6+c12)/2 */
+
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z3, CONST_BITS+2);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(z2 + z3, CONST_BITS+2);
+
+ /* Odd part */
+
+ tmp2 = MULTIPLY(tmp10 - tmp12 - tmp13 + tmp15 + tmp16,
+ FIX(1.393487498)); /* c5 */
+ tmp1 = MULTIPLY(tmp10 - tmp14 - tmp15, FIX(1.530307725)) + /* c3 */
+ MULTIPLY(tmp11 - tmp13 - tmp16, FIX(0.945782187)); /* c9 */
+ tmp12 = MULTIPLY(tmp12, FIX(1.393487498)); /* c5 */
+ tmp4 = MULTIPLY(tmp10 - tmp16, FIX(1.600246161)) + /* c1 */
+ MULTIPLY(tmp11 + tmp14, FIX(1.530307725)) + /* c3 */
+ MULTIPLY(tmp13 + tmp15, FIX(0.654463974)); /* c11 */
+ tmp0 = MULTIPLY(tmp13, FIX(0.541301207)) - /* c7-c11 */
+ MULTIPLY(tmp14, FIX(0.584525538)) + /* c3-c9 */
+ MULTIPLY(tmp16, FIX(1.934788705)) + tmp4 + tmp12; /* c1+c13 */
+ tmp3 = MULTIPLY(tmp10, - FIX(0.404480980)) - /* -(c1-c7) */
+ MULTIPLY(tmp11, FIX(2.476089912)) - /* c3+c9 */
+ MULTIPLY(tmp15, FIX(0.989006518)) + tmp4 - tmp12; /* c11+c13 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+2);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+2);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3, CONST_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 16x16 sample block.
+ */
+
+GLOBAL(void)
+jpeg_fdct_16x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+ DCTELEM workspace[DCTSIZE2];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* cK represents sqrt(2) * cos(K*pi/32). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]);
+ tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]);
+
+ tmp10 = tmp0 + tmp7;
+ tmp14 = tmp0 - tmp7;
+ tmp11 = tmp1 + tmp6;
+ tmp15 = tmp1 - tmp6;
+ tmp12 = tmp2 + tmp5;
+ tmp16 = tmp2 - tmp5;
+ tmp13 = tmp3 + tmp4;
+ tmp17 = tmp3 - tmp4;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]);
+ tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]);
+ tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+ MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */
+ CONST_BITS-PASS1_BITS);
+
+ tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */
+ MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */
+ + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */
+ - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */
+ MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */
+ MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */
+ MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */
+ tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */
+ tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */
+ MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */
+ tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */
+ MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */
+ MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */
+ tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+ - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */
+ tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+ + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */
+ tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+ + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == DCTSIZE * 2)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/16)**2 = 1/2**2.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2];
+ tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1];
+ tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0];
+
+ tmp10 = tmp0 + tmp7;
+ tmp14 = tmp0 - tmp7;
+ tmp11 = tmp1 + tmp6;
+ tmp15 = tmp1 - tmp6;
+ tmp12 = tmp2 + tmp5;
+ tmp16 = tmp2 - tmp5;
+ tmp13 = tmp3 + tmp4;
+ tmp17 = tmp3 - tmp4;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3];
+ tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2];
+ tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1];
+ tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+2);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+ MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */
+ CONST_BITS+PASS1_BITS+2);
+
+ tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */
+ MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */
+ + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+10 */
+ CONST_BITS+PASS1_BITS+2);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */
+ - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */
+ CONST_BITS+PASS1_BITS+2);
+
+ /* Odd part */
+
+ tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */
+ MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */
+ MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */
+ MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */
+ tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */
+ tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */
+ MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */
+ tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */
+ MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */
+ MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */
+ tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+ - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */
+ tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+ + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */
+ tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+ + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+2);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+2);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+2);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+2);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 16x8 sample block.
+ *
+ * 16-point FDCT in pass 1 (rows), 8-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_16x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+ INT32 z1;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32). */
+
+ dataptr = data;
+ ctr = 0;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[15]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[14]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[13]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[12]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[11]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[10]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[9]);
+ tmp7 = GETJSAMPLE(elemptr[7]) + GETJSAMPLE(elemptr[8]);
+
+ tmp10 = tmp0 + tmp7;
+ tmp14 = tmp0 - tmp7;
+ tmp11 = tmp1 + tmp6;
+ tmp15 = tmp1 - tmp6;
+ tmp12 = tmp2 + tmp5;
+ tmp16 = tmp2 - tmp5;
+ tmp13 = tmp3 + tmp4;
+ tmp17 = tmp3 - tmp4;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[15]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[14]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[13]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[12]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[11]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[10]);
+ tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[9]);
+ tmp7 = GETJSAMPLE(elemptr[7]) - GETJSAMPLE(elemptr[8]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 + tmp13 - 16 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+ MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */
+ CONST_BITS-PASS1_BITS);
+
+ tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */
+ MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */
+ + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */
+ - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */
+ MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */
+ MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */
+ MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */
+ tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */
+ tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */
+ MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */
+ tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */
+ MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */
+ MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */
+ tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+ - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */
+ tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+ + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */
+ tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+ + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by 8/16 = 1/2.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+ tmp10 = tmp0 + tmp3;
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) DESCALE(tmp10 + tmp11, PASS1_BITS+1);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp10 - tmp11, PASS1_BITS+1);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865),
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065),
+ CONST_BITS+PASS1_BITS+1);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0 + tmp10 + tmp12,
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1 + tmp11 + tmp13,
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2 + tmp11 + tmp12,
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp3 + tmp10 + tmp13,
+ CONST_BITS+PASS1_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 14x7 sample block.
+ *
+ * 14-point FDCT in pass 1 (rows), 7-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_14x7 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 z1, z2, z3;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Zero bottom row of output coefficient block. */
+ MEMZERO(&data[DCTSIZE*7], SIZEOF(DCTELEM) * DCTSIZE);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 7; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[13]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[12]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[11]);
+ tmp13 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[10]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[9]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[8]);
+ tmp6 = GETJSAMPLE(elemptr[6]) + GETJSAMPLE(elemptr[7]);
+
+ tmp10 = tmp0 + tmp6;
+ tmp14 = tmp0 - tmp6;
+ tmp11 = tmp1 + tmp5;
+ tmp15 = tmp1 - tmp5;
+ tmp12 = tmp2 + tmp4;
+ tmp16 = tmp2 - tmp4;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[13]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[12]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[11]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[10]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[9]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[8]);
+ tmp6 = GETJSAMPLE(elemptr[6]) - GETJSAMPLE(elemptr[7]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 + tmp13 - 14 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp13 += tmp13;
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.274162392)) + /* c4 */
+ MULTIPLY(tmp11 - tmp13, FIX(0.314692123)) - /* c12 */
+ MULTIPLY(tmp12 - tmp13, FIX(0.881747734)), /* c8 */
+ CONST_BITS-PASS1_BITS);
+
+ tmp10 = MULTIPLY(tmp14 + tmp15, FIX(1.105676686)); /* c6 */
+
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.273079590)) /* c2-c6 */
+ + MULTIPLY(tmp16, FIX(0.613604268)), /* c10 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.719280954)) /* c6+c10 */
+ - MULTIPLY(tmp16, FIX(1.378756276)), /* c2 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp1 + tmp2;
+ tmp11 = tmp5 - tmp4;
+ dataptr[7] = (DCTELEM) ((tmp0 - tmp10 + tmp3 - tmp11 - tmp6) << PASS1_BITS);
+ tmp3 <<= CONST_BITS;
+ tmp10 = MULTIPLY(tmp10, - FIX(0.158341681)); /* -c13 */
+ tmp11 = MULTIPLY(tmp11, FIX(1.405321284)); /* c1 */
+ tmp10 += tmp11 - tmp3;
+ tmp11 = MULTIPLY(tmp0 + tmp2, FIX(1.197448846)) + /* c5 */
+ MULTIPLY(tmp4 + tmp6, FIX(0.752406978)); /* c9 */
+ dataptr[5] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(2.373959773)) /* c3+c5-c13 */
+ + MULTIPLY(tmp4, FIX(1.119999435)), /* c1+c11-c9 */
+ CONST_BITS-PASS1_BITS);
+ tmp12 = MULTIPLY(tmp0 + tmp1, FIX(1.334852607)) + /* c3 */
+ MULTIPLY(tmp5 - tmp6, FIX(0.467085129)); /* c11 */
+ dataptr[3] = (DCTELEM)
+ DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.424103948)) /* c3-c9-c13 */
+ - MULTIPLY(tmp5, FIX(3.069855259)), /* c1+c5+c11 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[1] = (DCTELEM)
+ DESCALE(tmp11 + tmp12 + tmp3 + tmp6 -
+ MULTIPLY(tmp0 + tmp6, FIX(1.126980169)), /* c3+c5-c1 */
+ CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/14)*(8/7) = 32/49, which we
+ * partially fold into the constant multipliers and final shifting:
+ * 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14) * 64/49.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*6];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*5];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*4];
+ tmp3 = dataptr[DCTSIZE*3];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*6];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*5];
+ tmp12 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*4];
+
+ z1 = tmp0 + tmp2;
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(z1 + tmp1 + tmp3, FIX(1.306122449)), /* 64/49 */
+ CONST_BITS+PASS1_BITS+1);
+ tmp3 += tmp3;
+ z1 -= tmp3;
+ z1 -= tmp3;
+ z1 = MULTIPLY(z1, FIX(0.461784020)); /* (c2+c6-c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp2, FIX(1.202428084)); /* (c2+c4-c6)/2 */
+ z3 = MULTIPLY(tmp1 - tmp2, FIX(0.411026446)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS+PASS1_BITS+1);
+ z1 -= z2;
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(1.151670509)); /* c4 */
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.923568041)), /* c2+c6-c4 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS+PASS1_BITS+1);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(1.221765677)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.222383464)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.800824523)); /* -c1 */
+ tmp1 += tmp2;
+ tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.801442310)); /* c5 */
+ tmp0 += tmp3;
+ tmp2 += tmp3 + MULTIPLY(tmp12, FIX(2.443531355)); /* c3+c1-c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp0, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp1, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp2, CONST_BITS+PASS1_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 12x6 sample block.
+ *
+ * 12-point FDCT in pass 1 (rows), 6-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_12x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Zero 2 bottom rows of output coefficient block. */
+ MEMZERO(&data[DCTSIZE*6], SIZEOF(DCTELEM) * DCTSIZE * 2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[11]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[10]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[9]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[8]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[7]);
+ tmp5 = GETJSAMPLE(elemptr[5]) + GETJSAMPLE(elemptr[6]);
+
+ tmp10 = tmp0 + tmp5;
+ tmp13 = tmp0 - tmp5;
+ tmp11 = tmp1 + tmp4;
+ tmp14 = tmp1 - tmp4;
+ tmp12 = tmp2 + tmp3;
+ tmp15 = tmp2 - tmp3;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[11]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[10]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[9]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[8]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[7]);
+ tmp5 = GETJSAMPLE(elemptr[5]) - GETJSAMPLE(elemptr[6]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 - 12 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[6] = (DCTELEM) ((tmp13 - tmp14 - tmp15) << PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.224744871)), /* c4 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp14 - tmp15 + MULTIPLY(tmp13 + tmp15, FIX(1.366025404)), /* c2 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp1 + tmp4, FIX_0_541196100); /* c9 */
+ tmp14 = tmp10 + MULTIPLY(tmp1, FIX_0_765366865); /* c3-c9 */
+ tmp15 = tmp10 - MULTIPLY(tmp4, FIX_1_847759065); /* c3+c9 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.121971054)); /* c5 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.860918669)); /* c7 */
+ tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.580774953)) /* c5+c7-c1 */
+ + MULTIPLY(tmp5, FIX(0.184591911)); /* c11 */
+ tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.184591911)); /* -c11 */
+ tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.339493912)) /* c1+c5-c11 */
+ + MULTIPLY(tmp5, FIX(0.860918669)); /* c7 */
+ tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.725788011)) /* c1+c11-c7 */
+ - MULTIPLY(tmp5, FIX(1.121971054)); /* c5 */
+ tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.306562965)) /* c3 */
+ - MULTIPLY(tmp2 + tmp5, FIX_0_541196100); /* c9 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp11, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/12)*(8/6) = 8/9, which we
+ * partially fold into the constant multipliers and final shifting:
+ * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+ tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+ CONST_BITS+PASS1_BITS+1);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 10x5 sample block.
+ *
+ * 10-point FDCT in pass 1 (rows), 5-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_10x5 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Zero 3 bottom rows of output coefficient block. */
+ MEMZERO(&data[DCTSIZE*5], SIZEOF(DCTELEM) * DCTSIZE * 3);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 5; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[9]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[8]);
+ tmp12 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[7]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[6]);
+ tmp4 = GETJSAMPLE(elemptr[4]) + GETJSAMPLE(elemptr[5]);
+
+ tmp10 = tmp0 + tmp4;
+ tmp13 = tmp0 - tmp4;
+ tmp11 = tmp1 + tmp3;
+ tmp14 = tmp1 - tmp3;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[9]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[8]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[7]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[6]);
+ tmp4 = GETJSAMPLE(elemptr[4]) - GETJSAMPLE(elemptr[5]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 + tmp12 - 10 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp12 += tmp12;
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.144122806)) - /* c4 */
+ MULTIPLY(tmp11 - tmp12, FIX(0.437016024)), /* c8 */
+ CONST_BITS-PASS1_BITS);
+ tmp10 = MULTIPLY(tmp13 + tmp14, FIX(0.831253876)); /* c6 */
+ dataptr[2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.513743148)), /* c2-c6 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.176250899)), /* c2+c6 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp0 + tmp4;
+ tmp11 = tmp1 - tmp3;
+ dataptr[5] = (DCTELEM) ((tmp10 - tmp11 - tmp2) << PASS1_BITS);
+ tmp2 <<= CONST_BITS;
+ dataptr[1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.396802247)) + /* c1 */
+ MULTIPLY(tmp1, FIX(1.260073511)) + tmp2 + /* c3 */
+ MULTIPLY(tmp3, FIX(0.642039522)) + /* c7 */
+ MULTIPLY(tmp4, FIX(0.221231742)), /* c9 */
+ CONST_BITS-PASS1_BITS);
+ tmp12 = MULTIPLY(tmp0 - tmp4, FIX(0.951056516)) - /* (c3+c7)/2 */
+ MULTIPLY(tmp1 + tmp3, FIX(0.587785252)); /* (c1-c9)/2 */
+ tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.309016994)) + /* (c3-c7)/2 */
+ (tmp11 << (CONST_BITS - 1)) - tmp2;
+ dataptr[3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS-PASS1_BITS);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/10)*(8/5) = 32/25, which we
+ * fold into the constant multipliers:
+ * 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10) * 32/25.
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*3];
+ tmp2 = dataptr[DCTSIZE*2];
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*4];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp2, FIX(1.28)), /* 32/25 */
+ CONST_BITS+PASS1_BITS);
+ tmp11 = MULTIPLY(tmp11, FIX(1.011928851)); /* (c2+c4)/2 */
+ tmp10 -= tmp2 << 2;
+ tmp10 = MULTIPLY(tmp10, FIX(0.452548340)); /* (c2-c4)/2 */
+ dataptr[DCTSIZE*2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp1, FIX(1.064004961)); /* c3 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.657591230)), /* c1-c3 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.785601151)), /* c1+c3 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on an 8x4 sample block.
+ *
+ * 8-point FDCT in pass 1 (rows), 4-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_8x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Zero 4 bottom rows of output coefficient block. */
+ MEMZERO(&data[DCTSIZE*4], SIZEOF(DCTELEM) * DCTSIZE * 4);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We must also scale the output by 8/4 = 2, which we add here. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+ tmp10 = tmp0 + tmp3;
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << (PASS1_BITS+1));
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-2);
+ dataptr[2] = (DCTELEM) RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865),
+ CONST_BITS-PASS1_BITS-1);
+ dataptr[6] = (DCTELEM) RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065),
+ CONST_BITS-PASS1_BITS-1);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-2);
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS-1);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS-1);
+ dataptr[5] = (DCTELEM)
+ RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS-1);
+ dataptr[7] = (DCTELEM)
+ RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS-1);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * 4-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ */
+
+ dataptr = data;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3] + (ONE << (PASS1_BITS-1));
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x3 sample block.
+ *
+ * 6-point FDCT in pass 1 (rows), 3-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x3 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ INT32 tmp10, tmp11, tmp12;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 3; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+ tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */
+ CONST_BITS-PASS1_BITS-1);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+ CONST_BITS-PASS1_BITS-1);
+
+ /* Odd part */
+
+ tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */
+ CONST_BITS-PASS1_BITS-1);
+
+ dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << (PASS1_BITS+1)));
+ dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << (PASS1_BITS+1));
+ dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << (PASS1_BITS+1)));
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially
+ * fold into the constant multipliers (other part was done in pass 1):
+ * 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*2];
+ tmp1 = dataptr[DCTSIZE*1];
+
+ tmp2 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(1.257078722)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2, FIX(2.177324216)), /* c1 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x2 sample block.
+ *
+ * 4-point FDCT in pass 1 (rows), 2-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+ INT32 tmp10, tmp11;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We must also scale the output by (8/4)*(8/2) = 2**3, which we add here. */
+ /* 4-point FDCT kernel, */
+ /* cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT]. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 2; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+3));
+ dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+3));
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-4);
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS-3);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS-3);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = dataptr[DCTSIZE*0] + (ONE << (PASS1_BITS-1));
+ tmp1 = dataptr[DCTSIZE*1];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp0 + tmp1, PASS1_BITS);
+
+ /* Odd part */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) RIGHT_SHIFT(tmp0 - tmp1, PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x1 sample block.
+ *
+ * 2-point FDCT in pass 1 (rows), 1-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x1 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+ JSAMPROW elemptr;
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ elemptr = sample_data[0] + start_col;
+
+ tmp0 = GETJSAMPLE(elemptr[0]);
+ tmp1 = GETJSAMPLE(elemptr[1]);
+
+ /* We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/2)*(8/1) = 2**5.
+ */
+
+ /* Even part */
+ /* Apply unsigned->signed conversion */
+ data[0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5);
+
+ /* Odd part */
+ data[1] = (DCTELEM) ((tmp0 - tmp1) << 5);
+}
+
+
+/*
+ * Perform the forward DCT on an 8x16 sample block.
+ *
+ * 8-point FDCT in pass 1 (rows), 16-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_8x16 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17;
+ INT32 z1;
+ DCTELEM workspace[DCTSIZE2];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) + GETJSAMPLE(elemptr[4]);
+
+ tmp10 = tmp0 + tmp3;
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[7]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[6]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[5]);
+ tmp3 = GETJSAMPLE(elemptr[3]) - GETJSAMPLE(elemptr[4]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) ((tmp10 + tmp11 - 8 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[4] = (DCTELEM) ((tmp10 - tmp11) << PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ dataptr[2] = (DCTELEM) DESCALE(z1 + MULTIPLY(tmp12, FIX_0_765366865),
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 - MULTIPLY(tmp13, FIX_1_847759065),
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0 + tmp10 + tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1 + tmp11 + tmp13, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2 + tmp11 + tmp12, CONST_BITS-PASS1_BITS);
+ dataptr[7] = (DCTELEM) DESCALE(tmp3 + tmp10 + tmp13, CONST_BITS-PASS1_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == DCTSIZE * 2)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by 8/16 = 1/2.
+ * 16-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = DCTSIZE-1; ctr >= 0; ctr--) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*3];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*2];
+ tmp6 = dataptr[DCTSIZE*6] + wsptr[DCTSIZE*1];
+ tmp7 = dataptr[DCTSIZE*7] + wsptr[DCTSIZE*0];
+
+ tmp10 = tmp0 + tmp7;
+ tmp14 = tmp0 - tmp7;
+ tmp11 = tmp1 + tmp6;
+ tmp15 = tmp1 - tmp6;
+ tmp12 = tmp2 + tmp5;
+ tmp16 = tmp2 - tmp5;
+ tmp13 = tmp3 + tmp4;
+ tmp17 = tmp3 - tmp4;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*4];
+ tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*3];
+ tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*2];
+ tmp6 = dataptr[DCTSIZE*6] - wsptr[DCTSIZE*1];
+ tmp7 = dataptr[DCTSIZE*7] - wsptr[DCTSIZE*0];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 + tmp12 + tmp13, PASS1_BITS+1);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(1.306562965)) + /* c4[16] = c2[8] */
+ MULTIPLY(tmp11 - tmp12, FIX_0_541196100), /* c12[16] = c6[8] */
+ CONST_BITS+PASS1_BITS+1);
+
+ tmp10 = MULTIPLY(tmp17 - tmp15, FIX(0.275899379)) + /* c14[16] = c7[8] */
+ MULTIPLY(tmp14 - tmp16, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp15, FIX(1.451774982)) /* c6+c14 */
+ + MULTIPLY(tmp16, FIX(2.172734804)), /* c2+c10 */
+ CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(0.211164243)) /* c2-c6 */
+ - MULTIPLY(tmp17, FIX(1.061594338)), /* c10+c14 */
+ CONST_BITS+PASS1_BITS+1);
+
+ /* Odd part */
+
+ tmp11 = MULTIPLY(tmp0 + tmp1, FIX(1.353318001)) + /* c3 */
+ MULTIPLY(tmp6 - tmp7, FIX(0.410524528)); /* c13 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(1.247225013)) + /* c5 */
+ MULTIPLY(tmp5 + tmp7, FIX(0.666655658)); /* c11 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(1.093201867)) + /* c7 */
+ MULTIPLY(tmp4 - tmp7, FIX(0.897167586)); /* c9 */
+ tmp14 = MULTIPLY(tmp1 + tmp2, FIX(0.138617169)) + /* c15 */
+ MULTIPLY(tmp6 - tmp5, FIX(1.407403738)); /* c1 */
+ tmp15 = MULTIPLY(tmp1 + tmp3, - FIX(0.666655658)) + /* -c11 */
+ MULTIPLY(tmp4 + tmp6, - FIX(1.247225013)); /* -c5 */
+ tmp16 = MULTIPLY(tmp2 + tmp3, - FIX(1.353318001)) + /* -c3 */
+ MULTIPLY(tmp5 - tmp4, FIX(0.410524528)); /* c13 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(tmp0, FIX(2.286341144)) + /* c7+c5+c3-c1 */
+ MULTIPLY(tmp7, FIX(0.779653625)); /* c15+c13-c11+c9 */
+ tmp11 += tmp14 + tmp15 + MULTIPLY(tmp1, FIX(0.071888074)) /* c9-c3-c15+c11 */
+ - MULTIPLY(tmp6, FIX(1.663905119)); /* c7+c13+c1-c5 */
+ tmp12 += tmp14 + tmp16 - MULTIPLY(tmp2, FIX(1.125726048)) /* c7+c5+c15-c3 */
+ + MULTIPLY(tmp5, FIX(1.227391138)); /* c9-c11+c1-c13 */
+ tmp13 += tmp15 + tmp16 + MULTIPLY(tmp3, FIX(1.065388962)) /* c15+c3+c11-c7 */
+ + MULTIPLY(tmp4, FIX(2.167985692)); /* c1+c13+c5-c9 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS+1);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS+1);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 7x14 sample block.
+ *
+ * 7-point FDCT in pass 1 (rows), 14-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_7x14 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 z1, z2, z3;
+ DCTELEM workspace[8*6];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 7-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/14). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[6]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[5]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[4]);
+ tmp3 = GETJSAMPLE(elemptr[3]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[6]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[5]);
+ tmp12 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[4]);
+
+ z1 = tmp0 + tmp2;
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((z1 + tmp1 + tmp3 - 7 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp3 += tmp3;
+ z1 -= tmp3;
+ z1 -= tmp3;
+ z1 = MULTIPLY(z1, FIX(0.353553391)); /* (c2+c6-c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp2, FIX(0.920609002)); /* (c2+c4-c6)/2 */
+ z3 = MULTIPLY(tmp1 - tmp2, FIX(0.314692123)); /* c6 */
+ dataptr[2] = (DCTELEM) DESCALE(z1 + z2 + z3, CONST_BITS-PASS1_BITS);
+ z1 -= z2;
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(0.881747734)); /* c4 */
+ dataptr[4] = (DCTELEM)
+ DESCALE(z2 + z3 - MULTIPLY(tmp1 - tmp3, FIX(0.707106781)), /* c2+c6-c4 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[6] = (DCTELEM) DESCALE(z1 + z2, CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp1 = MULTIPLY(tmp10 + tmp11, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(tmp10 - tmp11, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(tmp11 + tmp12, - FIX(1.378756276)); /* -c1 */
+ tmp1 += tmp2;
+ tmp3 = MULTIPLY(tmp10 + tmp12, FIX(0.613604268)); /* c5 */
+ tmp0 += tmp3;
+ tmp2 += tmp3 + MULTIPLY(tmp12, FIX(1.870828693)); /* c3+c1-c5 */
+
+ dataptr[1] = (DCTELEM) DESCALE(tmp0, CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM) DESCALE(tmp1, CONST_BITS-PASS1_BITS);
+ dataptr[5] = (DCTELEM) DESCALE(tmp2, CONST_BITS-PASS1_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 14)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/7)*(8/14) = 32/49, which we
+ * fold into the constant multipliers:
+ * 14-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/28) * 32/49.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*3];
+ tmp13 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*2];
+ tmp4 = dataptr[DCTSIZE*4] + wsptr[DCTSIZE*1];
+ tmp5 = dataptr[DCTSIZE*5] + wsptr[DCTSIZE*0];
+ tmp6 = dataptr[DCTSIZE*6] + dataptr[DCTSIZE*7];
+
+ tmp10 = tmp0 + tmp6;
+ tmp14 = tmp0 - tmp6;
+ tmp11 = tmp1 + tmp5;
+ tmp15 = tmp1 - tmp5;
+ tmp12 = tmp2 + tmp4;
+ tmp16 = tmp2 - tmp4;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*3];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*2];
+ tmp4 = dataptr[DCTSIZE*4] - wsptr[DCTSIZE*1];
+ tmp5 = dataptr[DCTSIZE*5] - wsptr[DCTSIZE*0];
+ tmp6 = dataptr[DCTSIZE*6] - dataptr[DCTSIZE*7];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12 + tmp13,
+ FIX(0.653061224)), /* 32/49 */
+ CONST_BITS+PASS1_BITS);
+ tmp13 += tmp13;
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp13, FIX(0.832106052)) + /* c4 */
+ MULTIPLY(tmp11 - tmp13, FIX(0.205513223)) - /* c12 */
+ MULTIPLY(tmp12 - tmp13, FIX(0.575835255)), /* c8 */
+ CONST_BITS+PASS1_BITS);
+
+ tmp10 = MULTIPLY(tmp14 + tmp15, FIX(0.722074570)); /* c6 */
+
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp14, FIX(0.178337691)) /* c2-c6 */
+ + MULTIPLY(tmp16, FIX(0.400721155)), /* c10 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp15, FIX(1.122795725)) /* c6+c10 */
+ - MULTIPLY(tmp16, FIX(0.900412262)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp1 + tmp2;
+ tmp11 = tmp5 - tmp4;
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp10 + tmp3 - tmp11 - tmp6,
+ FIX(0.653061224)), /* 32/49 */
+ CONST_BITS+PASS1_BITS);
+ tmp3 = MULTIPLY(tmp3 , FIX(0.653061224)); /* 32/49 */
+ tmp10 = MULTIPLY(tmp10, - FIX(0.103406812)); /* -c13 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.917760839)); /* c1 */
+ tmp10 += tmp11 - tmp3;
+ tmp11 = MULTIPLY(tmp0 + tmp2, FIX(0.782007410)) + /* c5 */
+ MULTIPLY(tmp4 + tmp6, FIX(0.491367823)); /* c9 */
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + tmp11 - MULTIPLY(tmp2, FIX(1.550341076)) /* c3+c5-c13 */
+ + MULTIPLY(tmp4, FIX(0.731428202)), /* c1+c11-c9 */
+ CONST_BITS+PASS1_BITS);
+ tmp12 = MULTIPLY(tmp0 + tmp1, FIX(0.871740478)) + /* c3 */
+ MULTIPLY(tmp5 - tmp6, FIX(0.305035186)); /* c11 */
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(tmp10 + tmp12 - MULTIPLY(tmp1, FIX(0.276965844)) /* c3-c9-c13 */
+ - MULTIPLY(tmp5, FIX(2.004803435)), /* c1+c5+c11 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp11 + tmp12 + tmp3
+ - MULTIPLY(tmp0, FIX(0.735987049)) /* c3+c5-c1 */
+ - MULTIPLY(tmp6, FIX(0.082925825)), /* c9-c11-c13 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 6x12 sample block.
+ *
+ * 6-point FDCT in pass 1 (rows), 12-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_6x12 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ DCTELEM workspace[8*4];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[5]);
+ tmp11 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) + GETJSAMPLE(elemptr[3]);
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[5]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[4]);
+ tmp2 = GETJSAMPLE(elemptr[2]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp11 - 6 * CENTERJSAMPLE) << PASS1_BITS);
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(1.224744871)), /* c2 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(0.707106781)), /* c4 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = DESCALE(MULTIPLY(tmp0 + tmp2, FIX(0.366025404)), /* c5 */
+ CONST_BITS-PASS1_BITS);
+
+ dataptr[1] = (DCTELEM) (tmp10 + ((tmp0 + tmp1) << PASS1_BITS));
+ dataptr[3] = (DCTELEM) ((tmp0 - tmp1 - tmp2) << PASS1_BITS);
+ dataptr[5] = (DCTELEM) (tmp10 + ((tmp2 - tmp1) << PASS1_BITS));
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 12)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/6)*(8/12) = 8/9, which we
+ * fold into the constant multipliers:
+ * 12-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/24) * 8/9.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*2];
+ tmp2 = dataptr[DCTSIZE*2] + wsptr[DCTSIZE*1];
+ tmp3 = dataptr[DCTSIZE*3] + wsptr[DCTSIZE*0];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*7];
+ tmp5 = dataptr[DCTSIZE*5] + dataptr[DCTSIZE*6];
+
+ tmp10 = tmp0 + tmp5;
+ tmp13 = tmp0 - tmp5;
+ tmp11 = tmp1 + tmp4;
+ tmp14 = tmp1 - tmp4;
+ tmp12 = tmp2 + tmp3;
+ tmp15 = tmp2 - tmp3;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*2];
+ tmp2 = dataptr[DCTSIZE*2] - wsptr[DCTSIZE*1];
+ tmp3 = dataptr[DCTSIZE*3] - wsptr[DCTSIZE*0];
+ tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*7];
+ tmp5 = dataptr[DCTSIZE*5] - dataptr[DCTSIZE*6];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(0.888888889)), /* 8/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp13 - tmp14 - tmp15, FIX(0.888888889)), /* 8/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.088662108)), /* c4 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp14 - tmp15, FIX(0.888888889)) + /* 8/9 */
+ MULTIPLY(tmp13 + tmp15, FIX(1.214244803)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp1 + tmp4, FIX(0.481063200)); /* c9 */
+ tmp14 = tmp10 + MULTIPLY(tmp1, FIX(0.680326102)); /* c3-c9 */
+ tmp15 = tmp10 - MULTIPLY(tmp4, FIX(1.642452502)); /* c3+c9 */
+ tmp12 = MULTIPLY(tmp0 + tmp2, FIX(0.997307603)); /* c5 */
+ tmp13 = MULTIPLY(tmp0 + tmp3, FIX(0.765261039)); /* c7 */
+ tmp10 = tmp12 + tmp13 + tmp14 - MULTIPLY(tmp0, FIX(0.516244403)) /* c5+c7-c1 */
+ + MULTIPLY(tmp5, FIX(0.164081699)); /* c11 */
+ tmp11 = MULTIPLY(tmp2 + tmp3, - FIX(0.164081699)); /* -c11 */
+ tmp12 += tmp11 - tmp15 - MULTIPLY(tmp2, FIX(2.079550144)) /* c1+c5-c11 */
+ + MULTIPLY(tmp5, FIX(0.765261039)); /* c7 */
+ tmp13 += tmp11 - tmp14 + MULTIPLY(tmp3, FIX(0.645144899)) /* c1+c11-c7 */
+ - MULTIPLY(tmp5, FIX(0.997307603)); /* c5 */
+ tmp11 = tmp15 + MULTIPLY(tmp0 - tmp3, FIX(1.161389302)) /* c3 */
+ - MULTIPLY(tmp2 + tmp5, FIX(0.481063200)); /* c9 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM) DESCALE(tmp10, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp11, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM) DESCALE(tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp13, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 5x10 sample block.
+ *
+ * 5-point FDCT in pass 1 (rows), 10-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_5x10 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4;
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ DCTELEM workspace[8*2];
+ DCTELEM *dataptr;
+ DCTELEM *wsptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* 5-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/10). */
+
+ dataptr = data;
+ ctr = 0;
+ for (;;) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[4]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[3]);
+ tmp2 = GETJSAMPLE(elemptr[2]);
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+
+ tmp0 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[4]);
+ tmp1 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[3]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp10 + tmp2 - 5 * CENTERJSAMPLE) << PASS1_BITS);
+ tmp11 = MULTIPLY(tmp11, FIX(0.790569415)); /* (c2+c4)/2 */
+ tmp10 -= tmp2 << 2;
+ tmp10 = MULTIPLY(tmp10, FIX(0.353553391)); /* (c2-c4)/2 */
+ dataptr[2] = (DCTELEM) DESCALE(tmp11 + tmp10, CONST_BITS-PASS1_BITS);
+ dataptr[4] = (DCTELEM) DESCALE(tmp11 - tmp10, CONST_BITS-PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp1, FIX(0.831253876)); /* c3 */
+
+ dataptr[1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0, FIX(0.513743148)), /* c1-c3 */
+ CONST_BITS-PASS1_BITS);
+ dataptr[3] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp1, FIX(2.176250899)), /* c1+c3 */
+ CONST_BITS-PASS1_BITS);
+
+ ctr++;
+
+ if (ctr != DCTSIZE) {
+ if (ctr == 10)
+ break; /* Done. */
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ } else
+ dataptr = workspace; /* switch pointer to extended workspace */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/5)*(8/10) = 32/25, which we
+ * fold into the constant multipliers:
+ * 10-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/20) * 32/25.
+ */
+
+ dataptr = data;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + wsptr[DCTSIZE*1];
+ tmp1 = dataptr[DCTSIZE*1] + wsptr[DCTSIZE*0];
+ tmp12 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*7];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*6];
+ tmp4 = dataptr[DCTSIZE*4] + dataptr[DCTSIZE*5];
+
+ tmp10 = tmp0 + tmp4;
+ tmp13 = tmp0 - tmp4;
+ tmp11 = tmp1 + tmp3;
+ tmp14 = tmp1 - tmp3;
+
+ tmp0 = dataptr[DCTSIZE*0] - wsptr[DCTSIZE*1];
+ tmp1 = dataptr[DCTSIZE*1] - wsptr[DCTSIZE*0];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*7];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*6];
+ tmp4 = dataptr[DCTSIZE*4] - dataptr[DCTSIZE*5];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11 + tmp12, FIX(1.28)), /* 32/25 */
+ CONST_BITS+PASS1_BITS);
+ tmp12 += tmp12;
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp12, FIX(1.464477191)) - /* c4 */
+ MULTIPLY(tmp11 - tmp12, FIX(0.559380511)), /* c8 */
+ CONST_BITS+PASS1_BITS);
+ tmp10 = MULTIPLY(tmp13 + tmp14, FIX(1.064004961)); /* c6 */
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp13, FIX(0.657591230)), /* c2-c6 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ DESCALE(tmp10 - MULTIPLY(tmp14, FIX(2.785601151)), /* c2+c6 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = tmp0 + tmp4;
+ tmp11 = tmp1 - tmp3;
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp2, FIX(1.28)), /* 32/25 */
+ CONST_BITS+PASS1_BITS);
+ tmp2 = MULTIPLY(tmp2, FIX(1.28)); /* 32/25 */
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0, FIX(1.787906876)) + /* c1 */
+ MULTIPLY(tmp1, FIX(1.612894094)) + tmp2 + /* c3 */
+ MULTIPLY(tmp3, FIX(0.821810588)) + /* c7 */
+ MULTIPLY(tmp4, FIX(0.283176630)), /* c9 */
+ CONST_BITS+PASS1_BITS);
+ tmp12 = MULTIPLY(tmp0 - tmp4, FIX(1.217352341)) - /* (c3+c7)/2 */
+ MULTIPLY(tmp1 + tmp3, FIX(0.752365123)); /* (c1-c9)/2 */
+ tmp13 = MULTIPLY(tmp10 + tmp11, FIX(0.395541753)) + /* (c3-c7)/2 */
+ MULTIPLY(tmp11, FIX(0.64)) - tmp2; /* 16/25 */
+ dataptr[DCTSIZE*3] = (DCTELEM) DESCALE(tmp12 + tmp13, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*7] = (DCTELEM) DESCALE(tmp12 - tmp13, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ wsptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 4x8 sample block.
+ *
+ * 4-point FDCT in pass 1 (rows), 8-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_4x8 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We must also scale the output by 8/4 = 2, which we add here. */
+ /* 4-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[3]);
+ tmp1 = GETJSAMPLE(elemptr[1]) + GETJSAMPLE(elemptr[2]);
+
+ tmp10 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[3]);
+ tmp11 = GETJSAMPLE(elemptr[1]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 4 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ dataptr[2] = (DCTELEM) ((tmp0 - tmp1) << (PASS1_BITS+1));
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-2);
+
+ dataptr[1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS-1);
+ dataptr[3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS-1);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ /* Even part per LL&M figure 1 --- note that published figure is faulty;
+ * rotator "sqrt(2)*c1" should be "sqrt(2)*c6".
+ */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4];
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = tmp0 + tmp3 + (ONE << (PASS1_BITS-1));
+ tmp12 = tmp0 - tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp13 = tmp1 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5];
+ tmp3 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) RIGHT_SHIFT(tmp10 + tmp11, PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM) RIGHT_SHIFT(tmp10 - tmp11, PASS1_BITS);
+
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_0_541196100);
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ RIGHT_SHIFT(z1 + MULTIPLY(tmp12, FIX_0_765366865), CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*6] = (DCTELEM)
+ RIGHT_SHIFT(z1 - MULTIPLY(tmp13, FIX_1_847759065), CONST_BITS+PASS1_BITS);
+
+ /* Odd part per figure 8 --- note paper omits factor of sqrt(2).
+ * 8-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ * i0..i3 in the paper are tmp0..tmp3 here.
+ */
+
+ tmp10 = tmp0 + tmp3;
+ tmp11 = tmp1 + tmp2;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp1 + tmp3;
+ z1 = MULTIPLY(tmp12 + tmp13, FIX_1_175875602); /* c3 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS+PASS1_BITS-1);
+
+ tmp0 = MULTIPLY(tmp0, FIX_1_501321110); /* c1+c3-c5-c7 */
+ tmp1 = MULTIPLY(tmp1, FIX_3_072711026); /* c1+c3+c5-c7 */
+ tmp2 = MULTIPLY(tmp2, FIX_2_053119869); /* c1+c3-c5+c7 */
+ tmp3 = MULTIPLY(tmp3, FIX_0_298631336); /* -c1+c3+c5-c7 */
+ tmp10 = MULTIPLY(tmp10, - FIX_0_899976223); /* c7-c3 */
+ tmp11 = MULTIPLY(tmp11, - FIX_2_562915447); /* -c1-c3 */
+ tmp12 = MULTIPLY(tmp12, - FIX_0_390180644); /* c5-c3 */
+ tmp13 = MULTIPLY(tmp13, - FIX_1_961570560); /* -c3-c5 */
+
+ tmp12 += z1;
+ tmp13 += z1;
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + tmp10 + tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp1 + tmp11 + tmp13, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ RIGHT_SHIFT(tmp2 + tmp11 + tmp12, CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*7] = (DCTELEM)
+ RIGHT_SHIFT(tmp3 + tmp10 + tmp13, CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 3x6 sample block.
+ *
+ * 3-point FDCT in pass 1 (rows), 6-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_3x6 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1, tmp2;
+ INT32 tmp10, tmp11, tmp12;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+ /* We scale the results further by 2 as part of output adaption */
+ /* scaling for different DCT size. */
+ /* 3-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/6). */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 6; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]) + GETJSAMPLE(elemptr[2]);
+ tmp1 = GETJSAMPLE(elemptr[1]);
+
+ tmp2 = GETJSAMPLE(elemptr[0]) - GETJSAMPLE(elemptr[2]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM)
+ ((tmp0 + tmp1 - 3 * CENTERJSAMPLE) << (PASS1_BITS+1));
+ dataptr[2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp1, FIX(0.707106781)), /* c2 */
+ CONST_BITS-PASS1_BITS-1);
+
+ /* Odd part */
+
+ dataptr[1] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp2, FIX(1.224744871)), /* c1 */
+ CONST_BITS-PASS1_BITS-1);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We remove the PASS1_BITS scaling, but leave the results scaled up
+ * by an overall factor of 8.
+ * We must also scale the output by (8/6)*(8/3) = 32/9, which we partially
+ * fold into the constant multipliers (other part was done in pass 1):
+ * 6-point FDCT kernel, cK represents sqrt(2) * cos(K*pi/12) * 16/9.
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 3; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*5];
+ tmp11 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*3];
+
+ tmp10 = tmp0 + tmp2;
+ tmp12 = tmp0 - tmp2;
+
+ tmp0 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*5];
+ tmp1 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*4];
+ tmp2 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*3];
+
+ dataptr[DCTSIZE*0] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 + tmp11, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*2] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp12, FIX(2.177324216)), /* c2 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*4] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp10 - tmp11 - tmp11, FIX(1.257078722)), /* c4 */
+ CONST_BITS+PASS1_BITS);
+
+ /* Odd part */
+
+ tmp10 = MULTIPLY(tmp0 + tmp2, FIX(0.650711829)); /* c5 */
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp0 + tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ DESCALE(MULTIPLY(tmp0 - tmp1 - tmp2, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+ dataptr[DCTSIZE*5] = (DCTELEM)
+ DESCALE(tmp10 + MULTIPLY(tmp2 - tmp1, FIX(1.777777778)), /* 16/9 */
+ CONST_BITS+PASS1_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 2x4 sample block.
+ *
+ * 2-point FDCT in pass 1 (rows), 4-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_2x4 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+ INT32 tmp10, tmp11;
+ DCTELEM *dataptr;
+ JSAMPROW elemptr;
+ int ctr;
+ SHIFT_TEMPS
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ /* Pass 1: process rows. */
+ /* Note results are scaled up by sqrt(8) compared to a true DCT. */
+ /* We must also scale the output by (8/2)*(8/4) = 2**3, which we add here. */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 4; ctr++) {
+ elemptr = sample_data[ctr] + start_col;
+
+ /* Even part */
+
+ tmp0 = GETJSAMPLE(elemptr[0]);
+ tmp1 = GETJSAMPLE(elemptr[1]);
+
+ /* Apply unsigned->signed conversion */
+ dataptr[0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 3);
+
+ /* Odd part */
+
+ dataptr[1] = (DCTELEM) ((tmp0 - tmp1) << 3);
+
+ dataptr += DCTSIZE; /* advance pointer to next row */
+ }
+
+ /* Pass 2: process columns.
+ * We leave the results scaled up by an overall factor of 8.
+ * 4-point FDCT kernel,
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point FDCT].
+ */
+
+ dataptr = data;
+ for (ctr = 0; ctr < 2; ctr++) {
+ /* Even part */
+
+ tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*3];
+ tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*2];
+
+ tmp10 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*3];
+ tmp11 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*2];
+
+ dataptr[DCTSIZE*0] = (DCTELEM) (tmp0 + tmp1);
+ dataptr[DCTSIZE*2] = (DCTELEM) (tmp0 - tmp1);
+
+ /* Odd part */
+
+ tmp0 = MULTIPLY(tmp10 + tmp11, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-1);
+
+ dataptr[DCTSIZE*1] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 + MULTIPLY(tmp10, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS);
+ dataptr[DCTSIZE*3] = (DCTELEM)
+ RIGHT_SHIFT(tmp0 - MULTIPLY(tmp11, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS);
+
+ dataptr++; /* advance pointer to next column */
+ }
+}
+
+
+/*
+ * Perform the forward DCT on a 1x2 sample block.
+ *
+ * 1-point FDCT in pass 1 (rows), 2-point in pass 2 (columns).
+ */
+
+GLOBAL(void)
+jpeg_fdct_1x2 (DCTELEM * data, JSAMPARRAY sample_data, JDIMENSION start_col)
+{
+ INT32 tmp0, tmp1;
+
+ /* Pre-zero output coefficient block. */
+ MEMZERO(data, SIZEOF(DCTELEM) * DCTSIZE2);
+
+ tmp0 = GETJSAMPLE(sample_data[0][start_col]);
+ tmp1 = GETJSAMPLE(sample_data[1][start_col]);
+
+ /* We leave the results scaled up by an overall factor of 8.
+ * We must also scale the output by (8/1)*(8/2) = 2**5.
+ */
+
+ /* Even part */
+ /* Apply unsigned->signed conversion */
+ data[DCTSIZE*0] = (DCTELEM) ((tmp0 + tmp1 - 2 * CENTERJSAMPLE) << 5);
+
+ /* Odd part */
+ data[DCTSIZE*1] = (DCTELEM) ((tmp0 - tmp1) << 5);
+}
+
+#endif /* DCT_SCALING_SUPPORTED */
+#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/jpg/jidctflt.c b/jpg/jidctflt.c
new file mode 100644
index 0000000..23ae9d3
--- /dev/null
+++ b/jpg/jidctflt.c
@@ -0,0 +1,235 @@
+/*
+ * jidctflt.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * Modified 2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a floating-point implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * This implementation should be more accurate than either of the integer
+ * IDCT implementations. However, it may not give the same results on all
+ * machines because of differences in roundoff behavior. Speed will depend
+ * on the hardware's floating point capacity.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with a fixed-point
+ * implementation, accuracy is lost due to imprecise representation of the
+ * scaled quantization values. However, that problem does not arise if
+ * we use floating point arithmetic.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_FLOAT_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce a float result.
+ */
+
+#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
+ FAST_FLOAT z5, z10, z11, z12, z13;
+ JCOEFPTR inptr;
+ FLOAT_MULT_TYPE * quantptr;
+ FAST_FLOAT * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = cinfo->sample_range_limit;
+ int ctr;
+ FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
+
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
+
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
+
+ z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+ tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */
+ tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 - tmp5;
+
+ wsptr[DCTSIZE*0] = tmp0 + tmp7;
+ wsptr[DCTSIZE*7] = tmp0 - tmp7;
+ wsptr[DCTSIZE*1] = tmp1 + tmp6;
+ wsptr[DCTSIZE*6] = tmp1 - tmp6;
+ wsptr[DCTSIZE*2] = tmp2 + tmp5;
+ wsptr[DCTSIZE*5] = tmp2 - tmp5;
+ wsptr[DCTSIZE*3] = tmp3 + tmp4;
+ wsptr[DCTSIZE*4] = tmp3 - tmp4;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * And testing floats for zero is relatively expensive, so we don't bother.
+ */
+
+ /* Even part */
+
+ /* Apply signed->unsigned and prepare float->int conversion */
+ z5 = wsptr[0] + ((FAST_FLOAT) CENTERJSAMPLE + (FAST_FLOAT) 0.5);
+ tmp10 = z5 + wsptr[4];
+ tmp11 = z5 - wsptr[4];
+
+ tmp13 = wsptr[2] + wsptr[6];
+ tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z13 = wsptr[5] + wsptr[3];
+ z10 = wsptr[5] - wsptr[3];
+ z11 = wsptr[1] + wsptr[7];
+ z12 = wsptr[1] - wsptr[7];
+
+ tmp7 = z11 + z13;
+ tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
+
+ z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
+ tmp10 = z5 - z12 * ((FAST_FLOAT) 1.082392200); /* 2*(c2-c6) */
+ tmp12 = z5 - z10 * ((FAST_FLOAT) 2.613125930); /* 2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7;
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 - tmp5;
+
+ /* Final output stage: float->int conversion and range-limit */
+
+ outptr[0] = range_limit[((int) (tmp0 + tmp7)) & RANGE_MASK];
+ outptr[7] = range_limit[((int) (tmp0 - tmp7)) & RANGE_MASK];
+ outptr[1] = range_limit[((int) (tmp1 + tmp6)) & RANGE_MASK];
+ outptr[6] = range_limit[((int) (tmp1 - tmp6)) & RANGE_MASK];
+ outptr[2] = range_limit[((int) (tmp2 + tmp5)) & RANGE_MASK];
+ outptr[5] = range_limit[((int) (tmp2 - tmp5)) & RANGE_MASK];
+ outptr[3] = range_limit[((int) (tmp3 + tmp4)) & RANGE_MASK];
+ outptr[4] = range_limit[((int) (tmp3 - tmp4)) & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#endif /* DCT_FLOAT_SUPPORTED */
diff --git a/jpg/jidctfst.c b/jpg/jidctfst.c
new file mode 100644
index 0000000..dba4216
--- /dev/null
+++ b/jpg/jidctfst.c
@@ -0,0 +1,368 @@
+/*
+ * jidctfst.c
+ *
+ * Copyright (C) 1994-1998, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a fast, not so accurate integer implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on Arai, Agui, and Nakajima's algorithm for
+ * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
+ * Japanese, but the algorithm is described in the Pennebaker & Mitchell
+ * JPEG textbook (see REFERENCES section in file README). The following code
+ * is based directly on figure 4-8 in P&M.
+ * While an 8-point DCT cannot be done in less than 11 multiplies, it is
+ * possible to arrange the computation so that many of the multiplies are
+ * simple scalings of the final outputs. These multiplies can then be
+ * folded into the multiplications or divisions by the JPEG quantization
+ * table entries. The AA&N method leaves only 5 multiplies and 29 adds
+ * to be done in the DCT itself.
+ * The primary disadvantage of this method is that with fixed-point math,
+ * accuracy is lost due to imprecise representation of the scaled
+ * quantization values. The smaller the quantization table entry, the less
+ * precise the scaled value, so this implementation does worse with high-
+ * quality-setting files than with low-quality ones.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_IFAST_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */
+#endif
+
+
+/* Scaling decisions are generally the same as in the LL&M algorithm;
+ * see jidctint.c for more details. However, we choose to descale
+ * (right shift) multiplication products as soon as they are formed,
+ * rather than carrying additional fractional bits into subsequent additions.
+ * This compromises accuracy slightly, but it lets us save a few shifts.
+ * More importantly, 16-bit arithmetic is then adequate (for 8-bit samples)
+ * everywhere except in the multiplications proper; this saves a good deal
+ * of work on 16-bit-int machines.
+ *
+ * The dequantized coefficients are not integers because the AA&N scaling
+ * factors have been incorporated. We represent them scaled up by PASS1_BITS,
+ * so that the first and second IDCT rounds have the same input scaling.
+ * For 8-bit JSAMPLEs, we choose IFAST_SCALE_BITS = PASS1_BITS so as to
+ * avoid a descaling shift; this compromises accuracy rather drastically
+ * for small quantization table entries, but it saves a lot of shifts.
+ * For 12-bit JSAMPLEs, there's no hope of using 16x16 multiplies anyway,
+ * so we use a much larger scaling factor to preserve accuracy.
+ *
+ * A final compromise is to represent the multiplicative constants to only
+ * 8 fractional bits, rather than 13. This saves some shifting work on some
+ * machines, and may also reduce the cost of multiplication (since there
+ * are fewer one-bits in the constants).
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 8
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 8
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 8
+#define FIX_1_082392200 ((INT32) 277) /* FIX(1.082392200) */
+#define FIX_1_414213562 ((INT32) 362) /* FIX(1.414213562) */
+#define FIX_1_847759065 ((INT32) 473) /* FIX(1.847759065) */
+#define FIX_2_613125930 ((INT32) 669) /* FIX(2.613125930) */
+#else
+#define FIX_1_082392200 FIX(1.082392200)
+#define FIX_1_414213562 FIX(1.414213562)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_2_613125930 FIX(2.613125930)
+#endif
+
+
+/* We can gain a little more speed, with a further compromise in accuracy,
+ * by omitting the addition in a descaling shift. This yields an incorrectly
+ * rounded result half the time...
+ */
+
+#ifndef USE_ACCURATE_ROUNDING
+#undef DESCALE
+#define DESCALE(x,n) RIGHT_SHIFT(x, n)
+#endif
+
+
+/* Multiply a DCTELEM variable by an INT32 constant, and immediately
+ * descale to yield a DCTELEM result.
+ */
+
+#define MULTIPLY(var,const) ((DCTELEM) DESCALE((var) * (const), CONST_BITS))
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce a DCTELEM result. For 8-bit data a 16x16->16
+ * multiplication will do. For 12-bit data, the multiplier table is
+ * declared INT32, so a 32-bit multiply will be used.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define DEQUANTIZE(coef,quantval) (((IFAST_MULT_TYPE) (coef)) * (quantval))
+#else
+#define DEQUANTIZE(coef,quantval) \
+ DESCALE((coef)*(quantval), IFAST_SCALE_BITS-PASS1_BITS)
+#endif
+
+
+/* Like DESCALE, but applies to a DCTELEM and produces an int.
+ * We assume that int right shift is unsigned if INT32 right shift is.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define ISHIFT_TEMPS DCTELEM ishift_temp;
+#if BITS_IN_JSAMPLE == 8
+#define DCTELEMBITS 16 /* DCTELEM may be 16 or 32 bits */
+#else
+#define DCTELEMBITS 32 /* DCTELEM must be 32 bits */
+#endif
+#define IRIGHT_SHIFT(x,shft) \
+ ((ishift_temp = (x)) < 0 ? \
+ (ishift_temp >> (shft)) | ((~((DCTELEM) 0)) << (DCTELEMBITS-(shft))) : \
+ (ishift_temp >> (shft)))
+#else
+#define ISHIFT_TEMPS
+#define IRIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+#ifdef USE_ACCURATE_ROUNDING
+#define IDESCALE(x,n) ((int) IRIGHT_SHIFT((x) + (1 << ((n)-1)), n))
+#else
+#define IDESCALE(x,n) ((int) IRIGHT_SHIFT(x, n))
+#endif
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_ifast (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ DCTELEM tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ DCTELEM tmp10, tmp11, tmp12, tmp13;
+ DCTELEM z5, z10, z11, z12, z13;
+ JCOEFPTR inptr;
+ IFAST_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[DCTSIZE2]; /* buffers data between passes */
+ SHIFT_TEMPS /* for DESCALE */
+ ISHIFT_TEMPS /* for IDESCALE */
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (IFAST_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ int dcval = (int) DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
+
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
+
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ wsptr[DCTSIZE*0] = (int) (tmp0 + tmp7);
+ wsptr[DCTSIZE*7] = (int) (tmp0 - tmp7);
+ wsptr[DCTSIZE*1] = (int) (tmp1 + tmp6);
+ wsptr[DCTSIZE*6] = (int) (tmp1 - tmp6);
+ wsptr[DCTSIZE*2] = (int) (tmp2 + tmp5);
+ wsptr[DCTSIZE*5] = (int) (tmp2 - tmp5);
+ wsptr[DCTSIZE*4] = (int) (tmp3 + tmp4);
+ wsptr[DCTSIZE*3] = (int) (tmp3 - tmp4);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * On machines with very fast multiplication, it's possible that the
+ * test takes more time than it's worth. In that case this section
+ * may be commented out.
+ */
+
+#ifndef NO_ZERO_ROW_TEST
+ if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
+ wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
+ /* AC terms all zero */
+ JSAMPLE dcval = range_limit[IDESCALE(wsptr[0], PASS1_BITS+3)
+ & RANGE_MASK];
+
+ outptr[0] = dcval;
+ outptr[1] = dcval;
+ outptr[2] = dcval;
+ outptr[3] = dcval;
+ outptr[4] = dcval;
+ outptr[5] = dcval;
+ outptr[6] = dcval;
+ outptr[7] = dcval;
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+#endif
+
+ /* Even part */
+
+ tmp10 = ((DCTELEM) wsptr[0] + (DCTELEM) wsptr[4]);
+ tmp11 = ((DCTELEM) wsptr[0] - (DCTELEM) wsptr[4]);
+
+ tmp13 = ((DCTELEM) wsptr[2] + (DCTELEM) wsptr[6]);
+ tmp12 = MULTIPLY((DCTELEM) wsptr[2] - (DCTELEM) wsptr[6], FIX_1_414213562)
+ - tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z13 = (DCTELEM) wsptr[5] + (DCTELEM) wsptr[3];
+ z10 = (DCTELEM) wsptr[5] - (DCTELEM) wsptr[3];
+ z11 = (DCTELEM) wsptr[1] + (DCTELEM) wsptr[7];
+ z12 = (DCTELEM) wsptr[1] - (DCTELEM) wsptr[7];
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, - FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ /* Final output stage: scale down by a factor of 8 and range-limit */
+
+ outptr[0] = range_limit[IDESCALE(tmp0 + tmp7, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[IDESCALE(tmp0 - tmp7, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[IDESCALE(tmp1 + tmp6, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[IDESCALE(tmp1 - tmp6, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[IDESCALE(tmp2 + tmp5, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[IDESCALE(tmp2 - tmp5, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[IDESCALE(tmp3 + tmp4, PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[IDESCALE(tmp3 - tmp4, PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#endif /* DCT_IFAST_SUPPORTED */
diff --git a/jpg/jidctint.c b/jpg/jidctint.c
new file mode 100644
index 0000000..dcdf7ce
--- /dev/null
+++ b/jpg/jidctint.c
@@ -0,0 +1,5137 @@
+/*
+ * jidctint.c
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modification developed 2002-2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a slow-but-accurate integer implementation of the
+ * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
+ * must also perform dequantization of the input coefficients.
+ *
+ * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
+ * on each row (or vice versa, but it's more convenient to emit a row at
+ * a time). Direct algorithms are also available, but they are much more
+ * complex and seem not to be any faster when reduced to code.
+ *
+ * This implementation is based on an algorithm described in
+ * C. Loeffler, A. Ligtenberg and G. Moschytz, "Practical Fast 1-D DCT
+ * Algorithms with 11 Multiplications", Proc. Int'l. Conf. on Acoustics,
+ * Speech, and Signal Processing 1989 (ICASSP '89), pp. 988-991.
+ * The primary algorithm described there uses 11 multiplies and 29 adds.
+ * We use their alternate method with 12 multiplies and 32 adds.
+ * The advantage of this method is that no data path contains more than one
+ * multiplication; this allows a very simple and accurate implementation in
+ * scaled fixed-point arithmetic, with a minimal number of shifts.
+ *
+ * We also provide IDCT routines with various output sample block sizes for
+ * direct resolution reduction or enlargement and for direct resolving the
+ * common 2x1 and 1x2 subsampling cases without additional resampling: NxN
+ * (N=1...16), 2NxN, and Nx2N (N=1...8) pixels for one 8x8 input DCT block.
+ *
+ * For N<8 we simply take the corresponding low-frequency coefficients of
+ * the 8x8 input DCT block and apply an NxN point IDCT on the sub-block
+ * to yield the downscaled outputs.
+ * This can be seen as direct low-pass downsampling from the DCT domain
+ * point of view rather than the usual spatial domain point of view,
+ * yielding significant computational savings and results at least
+ * as good as common bilinear (averaging) spatial downsampling.
+ *
+ * For N>8 we apply a partial NxN IDCT on the 8 input coefficients as
+ * lower frequencies and higher frequencies assumed to be zero.
+ * It turns out that the computational effort is similar to the 8x8 IDCT
+ * regarding the output size.
+ * Furthermore, the scaling and descaling is the same for all IDCT sizes.
+ *
+ * CAUTION: We rely on the FIX() macro except for the N=1,2,4,8 cases
+ * since there would be too many additional constants to pre-calculate.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jdct.h" /* Private declarations for DCT subsystem */
+
+#ifdef DCT_ISLOW_SUPPORTED
+
+
+/*
+ * This module is specialized to the case DCTSIZE = 8.
+ */
+
+#if DCTSIZE != 8
+ Sorry, this code only copes with 8x8 DCT blocks. /* deliberate syntax err */
+#endif
+
+
+/*
+ * The poop on this scaling stuff is as follows:
+ *
+ * Each 1-D IDCT step produces outputs which are a factor of sqrt(N)
+ * larger than the true IDCT outputs. The final outputs are therefore
+ * a factor of N larger than desired; since N=8 this can be cured by
+ * a simple right shift at the end of the algorithm. The advantage of
+ * this arrangement is that we save two multiplications per 1-D IDCT,
+ * because the y0 and y4 inputs need not be divided by sqrt(N).
+ *
+ * We have to do addition and subtraction of the integer inputs, which
+ * is no problem, and multiplication by fractional constants, which is
+ * a problem to do in integer arithmetic. We multiply all the constants
+ * by CONST_SCALE and convert them to integer constants (thus retaining
+ * CONST_BITS bits of precision in the constants). After doing a
+ * multiplication we have to divide the product by CONST_SCALE, with proper
+ * rounding, to produce the correct output. This division can be done
+ * cheaply as a right shift of CONST_BITS bits. We postpone shifting
+ * as long as possible so that partial sums can be added together with
+ * full fractional precision.
+ *
+ * The outputs of the first pass are scaled up by PASS1_BITS bits so that
+ * they are represented to better-than-integral precision. These outputs
+ * require BITS_IN_JSAMPLE + PASS1_BITS + 3 bits; this fits in a 16-bit word
+ * with the recommended scaling. (To scale up 12-bit sample data further, an
+ * intermediate INT32 array would be needed.)
+ *
+ * To avoid overflow of the 32-bit intermediate results in pass 2, we must
+ * have BITS_IN_JSAMPLE + CONST_BITS + PASS1_BITS <= 26. Error analysis
+ * shows that the values given below are the most effective.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#else
+#define CONST_BITS 13
+#define PASS1_BITS 1 /* lose a little precision to avoid overflow */
+#endif
+
+/* Some C compilers fail to reduce "FIX(constant)" at compile time, thus
+ * causing a lot of useless floating-point operations at run time.
+ * To get around this we use the following pre-calculated constants.
+ * If you change CONST_BITS you may want to add appropriate values.
+ * (With a reasonable C compiler, you can just rely on the FIX() macro...)
+ */
+
+#if CONST_BITS == 13
+#define FIX_0_298631336 ((INT32) 2446) /* FIX(0.298631336) */
+#define FIX_0_390180644 ((INT32) 3196) /* FIX(0.390180644) */
+#define FIX_0_541196100 ((INT32) 4433) /* FIX(0.541196100) */
+#define FIX_0_765366865 ((INT32) 6270) /* FIX(0.765366865) */
+#define FIX_0_899976223 ((INT32) 7373) /* FIX(0.899976223) */
+#define FIX_1_175875602 ((INT32) 9633) /* FIX(1.175875602) */
+#define FIX_1_501321110 ((INT32) 12299) /* FIX(1.501321110) */
+#define FIX_1_847759065 ((INT32) 15137) /* FIX(1.847759065) */
+#define FIX_1_961570560 ((INT32) 16069) /* FIX(1.961570560) */
+#define FIX_2_053119869 ((INT32) 16819) /* FIX(2.053119869) */
+#define FIX_2_562915447 ((INT32) 20995) /* FIX(2.562915447) */
+#define FIX_3_072711026 ((INT32) 25172) /* FIX(3.072711026) */
+#else
+#define FIX_0_298631336 FIX(0.298631336)
+#define FIX_0_390180644 FIX(0.390180644)
+#define FIX_0_541196100 FIX(0.541196100)
+#define FIX_0_765366865 FIX(0.765366865)
+#define FIX_0_899976223 FIX(0.899976223)
+#define FIX_1_175875602 FIX(1.175875602)
+#define FIX_1_501321110 FIX(1.501321110)
+#define FIX_1_847759065 FIX(1.847759065)
+#define FIX_1_961570560 FIX(1.961570560)
+#define FIX_2_053119869 FIX(2.053119869)
+#define FIX_2_562915447 FIX(2.562915447)
+#define FIX_3_072711026 FIX(3.072711026)
+#endif
+
+
+/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result.
+ * For 8-bit samples with the recommended scaling, all the variable
+ * and constant values involved are no more than 16 bits wide, so a
+ * 16x16->32 bit multiply can be used instead of a full 32x32 multiply.
+ * For 12-bit samples, a full 32-bit multiplication will be needed.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define MULTIPLY(var,const) MULTIPLY16C16(var,const)
+#else
+#define MULTIPLY(var,const) ((var) * (const))
+#endif
+
+
+/* Dequantize a coefficient by multiplying it by the multiplier-table
+ * entry; produce an int result. In this module, both inputs and result
+ * are 16 bits or less, so either int or short multiply will work.
+ */
+
+#define DEQUANTIZE(coef,quantval) (((ISLOW_MULT_TYPE) (coef)) * (quantval))
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients.
+ */
+
+GLOBAL(void)
+jpeg_idct_islow (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[DCTSIZE2]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 <<= CONST_BITS;
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ tmp0 = z2 + z3;
+ tmp1 = z2 - z3;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < DCTSIZE; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+ /* Rows of zeroes can be exploited in the same way as we did with columns.
+ * However, the column calculation has created many nonzero AC terms, so
+ * the simplification applies less often (typically 5% to 10% of the time).
+ * On machines with very fast multiplication, it's possible that the
+ * test takes more time than it's worth. In that case this section
+ * may be commented out.
+ */
+
+#ifndef NO_ZERO_ROW_TEST
+ if (wsptr[1] == 0 && wsptr[2] == 0 && wsptr[3] == 0 && wsptr[4] == 0 &&
+ wsptr[5] == 0 && wsptr[6] == 0 && wsptr[7] == 0) {
+ /* AC terms all zero */
+ JSAMPLE dcval = range_limit[(int) DESCALE((INT32) wsptr[0], PASS1_BITS+3)
+ & RANGE_MASK];
+
+ outptr[0] = dcval;
+ outptr[1] = dcval;
+ outptr[2] = dcval;
+ outptr[3] = dcval;
+ outptr[4] = dcval;
+ outptr[5] = dcval;
+ outptr[6] = dcval;
+ outptr[7] = dcval;
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ continue;
+ }
+#endif
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ /* Add fudge factor here for final descale. */
+ z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 = (INT32) wsptr[4];
+
+ tmp0 = (z2 + z3) << CONST_BITS;
+ tmp1 = (z2 - z3) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = (INT32) wsptr[7];
+ tmp1 = (INT32) wsptr[5];
+ tmp2 = (INT32) wsptr[3];
+ tmp3 = (INT32) wsptr[1];
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+#ifdef IDCT_SCALING_SUPPORTED
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 7x7 output block.
+ *
+ * Optimized algorithm with 12 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/14).
+ */
+
+GLOBAL(void)
+jpeg_idct_7x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[7*7]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp13 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp13 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp13 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */
+ tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+ tmp0 = z1 + z3;
+ z2 -= tmp0;
+ tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */
+ tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */
+ tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */
+ tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */
+ tmp1 += tmp2;
+ z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */
+ tmp0 += z2;
+ tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */
+
+ /* Final output stage */
+
+ wsptr[7*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[7*6] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[7*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[7*5] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[7*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[7*4] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[7*3] = (int) RIGHT_SHIFT(tmp13, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 7 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp13 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp13 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[4];
+ z3 = (INT32) wsptr[6];
+
+ tmp10 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */
+ tmp11 = tmp10 + tmp12 + tmp13 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+ tmp0 = z1 + z3;
+ z2 -= tmp0;
+ tmp0 = MULTIPLY(tmp0, FIX(1.274162392)) + tmp13; /* c2 */
+ tmp10 += tmp0 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */
+ tmp12 += tmp0 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */
+ tmp13 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp2 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp0 = tmp1 - tmp2;
+ tmp1 += tmp2;
+ tmp2 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */
+ tmp1 += tmp2;
+ z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */
+ tmp0 += z2;
+ tmp2 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 7; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 6x6 output block.
+ *
+ * Optimized algorithm with 3 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/12).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[6*6]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */
+ tmp1 = tmp0 + tmp10;
+ tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS);
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */
+ tmp10 = tmp1 + tmp0;
+ tmp12 = tmp1 - tmp0;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+ tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+ tmp1 = (z1 - z2 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[6*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[6*1] = (int) (tmp11 + tmp1);
+ wsptr[6*4] = (int) (tmp11 - tmp1);
+ wsptr[6*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[6*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 6 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+ tmp2 = (INT32) wsptr[4];
+ tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */
+ tmp1 = tmp0 + tmp10;
+ tmp11 = tmp0 - tmp10 - tmp10;
+ tmp10 = (INT32) wsptr[2];
+ tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */
+ tmp10 = tmp1 + tmp0;
+ tmp12 = tmp1 - tmp0;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+ tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+ tmp1 = (z1 - z2 - z3) << CONST_BITS;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 6; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 5x5 output block.
+ *
+ * Optimized algorithm with 5 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/10).
+ */
+
+GLOBAL(void)
+jpeg_idct_5x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[5*5]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp12 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp12 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */
+ z3 = tmp12 + z2;
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z1;
+ tmp12 -= z2 << 2;
+
+ /* Odd part */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */
+ tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */
+ tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */
+
+ /* Final output stage */
+
+ wsptr[5*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[5*4] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[5*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[5*3] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[5*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 5 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp12 <<= CONST_BITS;
+ tmp0 = (INT32) wsptr[2];
+ tmp1 = (INT32) wsptr[4];
+ z1 = MULTIPLY(tmp0 + tmp1, FIX(0.790569415)); /* (c2+c4)/2 */
+ z2 = MULTIPLY(tmp0 - tmp1, FIX(0.353553391)); /* (c2-c4)/2 */
+ z3 = tmp12 + z2;
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z1;
+ tmp12 -= z2 << 2;
+
+ /* Odd part */
+
+ z2 = (INT32) wsptr[1];
+ z3 = (INT32) wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */
+ tmp0 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */
+ tmp1 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 5; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 4x4 output block.
+ *
+ * Optimized algorithm with 3 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+ */
+
+GLOBAL(void)
+jpeg_idct_4x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[4*4]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+
+ tmp10 = (tmp0 + tmp2) << PASS1_BITS;
+ tmp12 = (tmp0 - tmp2) << PASS1_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS);
+ tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Final output stage */
+
+ wsptr[4*0] = (int) (tmp10 + tmp0);
+ wsptr[4*3] = (int) (tmp10 - tmp0);
+ wsptr[4*1] = (int) (tmp12 + tmp2);
+ wsptr[4*2] = (int) (tmp12 - tmp2);
+ }
+
+ /* Pass 2: process 4 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp2 = (INT32) wsptr[2];
+
+ tmp10 = (tmp0 + tmp2) << CONST_BITS;
+ tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = (INT32) wsptr[1];
+ z3 = (INT32) wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+ tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 4; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 3x3 output block.
+ *
+ * Optimized algorithm with 2 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/6).
+ */
+
+GLOBAL(void)
+jpeg_idct_3x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[3*3]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+ tmp10 = tmp0 + tmp12;
+ tmp2 = tmp0 - tmp12 - tmp12;
+
+ /* Odd part */
+
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+ /* Final output stage */
+
+ wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[3*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[3*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 3 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 3; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+ tmp2 = (INT32) wsptr[2];
+ tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+ tmp10 = tmp0 + tmp12;
+ tmp2 = tmp0 - tmp12 - tmp12;
+
+ /* Odd part */
+
+ tmp12 = (INT32) wsptr[1];
+ tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 3; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 2x2 output block.
+ *
+ * Multiplication-less algorithm.
+ */
+
+GLOBAL(void)
+jpeg_idct_2x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input. */
+
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+
+ /* Column 0 */
+ tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ /* Add fudge factor here for final descale. */
+ tmp4 += ONE << 2;
+
+ tmp0 = tmp4 + tmp5;
+ tmp2 = tmp4 - tmp5;
+
+ /* Column 1 */
+ tmp4 = DEQUANTIZE(coef_block[DCTSIZE*0+1], quantptr[DCTSIZE*0+1]);
+ tmp5 = DEQUANTIZE(coef_block[DCTSIZE*1+1], quantptr[DCTSIZE*1+1]);
+
+ tmp1 = tmp4 + tmp5;
+ tmp3 = tmp4 - tmp5;
+
+ /* Pass 2: process 2 rows, store into output array. */
+
+ /* Row 0 */
+ outptr = output_buf[0] + output_col;
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp0 + tmp1, 3) & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp0 - tmp1, 3) & RANGE_MASK];
+
+ /* Row 1 */
+ outptr = output_buf[1] + output_col;
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp2 + tmp3, 3) & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2 - tmp3, 3) & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 1x1 output block.
+ *
+ * We hardly need an inverse DCT routine for this: just take the
+ * average pixel value, which is one-eighth of the DC coefficient.
+ */
+
+GLOBAL(void)
+jpeg_idct_1x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ int dcval;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* 1x1 is trivial: just take the DC coefficient divided by 8. */
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ dcval = DEQUANTIZE(coef_block[0], quantptr[0]);
+ dcval = (int) DESCALE((INT32) dcval, 3);
+
+ output_buf[0][output_col] = range_limit[dcval & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 9x9 output block.
+ *
+ * Optimized algorithm with 10 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/18).
+ */
+
+GLOBAL(void)
+jpeg_idct_9x9 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*9]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */
+ tmp1 = tmp0 + tmp3;
+ tmp2 = tmp0 - tmp3 - tmp3;
+
+ tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */
+ tmp11 = tmp2 + tmp0;
+ tmp14 = tmp2 - tmp0 - tmp0;
+
+ tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */
+ tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */
+ tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */
+
+ tmp10 = tmp1 + tmp0 - tmp3;
+ tmp12 = tmp1 - tmp0 + tmp2;
+ tmp13 = tmp1 - tmp2 + tmp3;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */
+
+ tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */
+ tmp0 = tmp2 + tmp3 - z2;
+ tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */
+ tmp2 += z2 - tmp1;
+ tmp3 += z2 + tmp1;
+ tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp11 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp13 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp13 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp14, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 9 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 9; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[4];
+ z3 = (INT32) wsptr[6];
+
+ tmp3 = MULTIPLY(z3, FIX(0.707106781)); /* c6 */
+ tmp1 = tmp0 + tmp3;
+ tmp2 = tmp0 - tmp3 - tmp3;
+
+ tmp0 = MULTIPLY(z1 - z2, FIX(0.707106781)); /* c6 */
+ tmp11 = tmp2 + tmp0;
+ tmp14 = tmp2 - tmp0 - tmp0;
+
+ tmp0 = MULTIPLY(z1 + z2, FIX(1.328926049)); /* c2 */
+ tmp2 = MULTIPLY(z1, FIX(1.083350441)); /* c4 */
+ tmp3 = MULTIPLY(z2, FIX(0.245575608)); /* c8 */
+
+ tmp10 = tmp1 + tmp0 - tmp3;
+ tmp12 = tmp1 - tmp0 + tmp2;
+ tmp13 = tmp1 - tmp2 + tmp3;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ z2 = MULTIPLY(z2, - FIX(1.224744871)); /* -c3 */
+
+ tmp2 = MULTIPLY(z1 + z3, FIX(0.909038955)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(0.483689525)); /* c7 */
+ tmp0 = tmp2 + tmp3 - z2;
+ tmp1 = MULTIPLY(z3 - z4, FIX(1.392728481)); /* c1 */
+ tmp2 += z2 - tmp1;
+ tmp3 += z2 + tmp1;
+ tmp1 = MULTIPLY(z1 - z3 - z4, FIX(1.224744871)); /* c3 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 10x10 output block.
+ *
+ * Optimized algorithm with 12 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/20).
+ */
+
+GLOBAL(void)
+jpeg_idct_10x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+ INT32 z1, z2, z3, z4, z5;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*10]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */
+ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z2;
+
+ tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */
+ CONST_BITS-PASS1_BITS);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */
+ tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+ tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+ tmp20 = tmp10 + tmp12;
+ tmp24 = tmp10 - tmp12;
+ tmp21 = tmp11 + tmp13;
+ tmp23 = tmp11 - tmp13;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z2 + z4;
+ tmp13 = z2 - z4;
+
+ tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */
+ z5 = z3 << CONST_BITS;
+
+ z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */
+ z4 = z5 + tmp12;
+
+ tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+ tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */
+ z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+ tmp12 = (z1 - tmp13 - z3) << PASS1_BITS;
+
+ tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) (tmp22 + tmp12);
+ wsptr[8*7] = (int) (tmp22 - tmp12);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 10 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 10; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 <<= CONST_BITS;
+ z4 = (INT32) wsptr[4];
+ z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */
+ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z2;
+
+ tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */
+ tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+ tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+ tmp20 = tmp10 + tmp12;
+ tmp24 = tmp10 - tmp12;
+ tmp21 = tmp11 + tmp13;
+ tmp23 = tmp11 - tmp13;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z3 <<= CONST_BITS;
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z2 + z4;
+ tmp13 = z2 - z4;
+
+ tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */
+ z4 = z3 + tmp12;
+
+ tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+ tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */
+ z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+ tmp12 = ((z1 - tmp13) << CONST_BITS) - z3;
+
+ tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 11x11 output block.
+ *
+ * Optimized algorithm with 24 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/22).
+ */
+
+GLOBAL(void)
+jpeg_idct_11x11 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*11]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp10 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp10 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */
+ tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */
+ z4 = z1 + z3;
+ tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */
+ z4 -= z2;
+ tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */
+ tmp21 = tmp20 + tmp23 + tmp25 -
+ MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */
+ tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */
+ tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */
+ tmp24 += tmp25;
+ tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */
+ tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */
+ MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */
+ tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z1 + z2;
+ tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */
+ tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */
+ tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */
+ z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */
+ tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */
+ tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */
+ z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */
+ tmp11 += z1;
+ tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */
+ tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */
+ MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */
+ MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 11 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 11; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp10 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[4];
+ z3 = (INT32) wsptr[6];
+
+ tmp20 = MULTIPLY(z2 - z3, FIX(2.546640132)); /* c2+c4 */
+ tmp23 = MULTIPLY(z2 - z1, FIX(0.430815045)); /* c2-c6 */
+ z4 = z1 + z3;
+ tmp24 = MULTIPLY(z4, - FIX(1.155664402)); /* -(c2-c10) */
+ z4 -= z2;
+ tmp25 = tmp10 + MULTIPLY(z4, FIX(1.356927976)); /* c2 */
+ tmp21 = tmp20 + tmp23 + tmp25 -
+ MULTIPLY(z2, FIX(1.821790775)); /* c2+c4+c10-c6 */
+ tmp20 += tmp25 + MULTIPLY(z3, FIX(2.115825087)); /* c4+c6 */
+ tmp23 += tmp25 - MULTIPLY(z1, FIX(1.513598477)); /* c6+c8 */
+ tmp24 += tmp25;
+ tmp22 = tmp24 - MULTIPLY(z3, FIX(0.788749120)); /* c8+c10 */
+ tmp24 += MULTIPLY(z2, FIX(1.944413522)) - /* c2+c8 */
+ MULTIPLY(z1, FIX(1.390975730)); /* c4+c10 */
+ tmp25 = tmp10 - MULTIPLY(z4, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z1 + z2;
+ tmp14 = MULTIPLY(tmp11 + z3 + z4, FIX(0.398430003)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.887983902)); /* c3-c9 */
+ tmp12 = MULTIPLY(z1 + z3, FIX(0.670361295)); /* c5-c9 */
+ tmp13 = tmp14 + MULTIPLY(z1 + z4, FIX(0.366151574)); /* c7-c9 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(z1, FIX(0.923107866)); /* c7+c5+c3-c1-2*c9 */
+ z1 = tmp14 - MULTIPLY(z2 + z3, FIX(1.163011579)); /* c7+c9 */
+ tmp11 += z1 + MULTIPLY(z2, FIX(2.073276588)); /* c1+c7+3*c9-c3 */
+ tmp12 += z1 - MULTIPLY(z3, FIX(1.192193623)); /* c3+c5-c7-c9 */
+ z1 = MULTIPLY(z2 + z4, - FIX(1.798248910)); /* -(c1+c9) */
+ tmp11 += z1;
+ tmp13 += z1 + MULTIPLY(z4, FIX(2.102458632)); /* c1+c5+c9-c7 */
+ tmp14 += MULTIPLY(z2, - FIX(1.467221301)) + /* -(c5+c9) */
+ MULTIPLY(z3, FIX(1.001388905)) - /* c1-c9 */
+ MULTIPLY(z4, FIX(1.684843907)); /* c3+c9 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 12x12 output block.
+ *
+ * Optimized algorithm with 15 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/24).
+ */
+
+GLOBAL(void)
+jpeg_idct_12x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*12]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+ z1 <<= CONST_BITS;
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+ z2 <<= CONST_BITS;
+
+ tmp12 = z1 - z2;
+
+ tmp21 = z3 + tmp12;
+ tmp24 = z3 - tmp12;
+
+ tmp12 = z4 + z2;
+
+ tmp20 = tmp10 + tmp12;
+ tmp25 = tmp10 - tmp12;
+
+ tmp12 = z4 - z1 - z2;
+
+ tmp22 = tmp11 + tmp12;
+ tmp23 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */
+ tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */
+
+ tmp10 = z1 + z3;
+ tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */
+ tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */
+ tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */
+ tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */
+ tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+ tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+ tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */
+ MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */
+
+ z1 -= z4;
+ z2 -= z3;
+ z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */
+ tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */
+ tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 12 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 12; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 <<= CONST_BITS;
+
+ z4 = (INT32) wsptr[4];
+ z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ z1 = (INT32) wsptr[2];
+ z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+ z1 <<= CONST_BITS;
+ z2 = (INT32) wsptr[6];
+ z2 <<= CONST_BITS;
+
+ tmp12 = z1 - z2;
+
+ tmp21 = z3 + tmp12;
+ tmp24 = z3 - tmp12;
+
+ tmp12 = z4 + z2;
+
+ tmp20 = tmp10 + tmp12;
+ tmp25 = tmp10 - tmp12;
+
+ tmp12 = z4 - z1 - z2;
+
+ tmp22 = tmp11 + tmp12;
+ tmp23 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */
+ tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */
+
+ tmp10 = z1 + z3;
+ tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */
+ tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */
+ tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */
+ tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */
+ tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+ tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+ tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */
+ MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */
+
+ z1 -= z4;
+ z2 -= z3;
+ z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */
+ tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */
+ tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 13x13 output block.
+ *
+ * Optimized algorithm with 29 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/26).
+ */
+
+GLOBAL(void)
+jpeg_idct_13x13 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*13]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z1 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */
+
+ tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */
+ tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */
+
+ tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */
+
+ tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */
+ tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */
+
+ tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */
+
+ tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */
+ tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */
+
+ tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */
+ tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */
+ tmp15 = z1 + z4;
+ tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */
+ tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */
+ tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */
+ tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */
+ tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */
+ tmp11 += tmp14;
+ tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */
+ tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */
+ tmp12 += tmp14;
+ tmp13 += tmp14;
+ tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */
+ tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */
+ MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */
+ z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */
+ tmp14 += z1;
+ tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */
+ MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 13 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 13; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z1 <<= CONST_BITS;
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[4];
+ z4 = (INT32) wsptr[6];
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ tmp12 = MULTIPLY(tmp10, FIX(1.155388986)); /* (c4+c6)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.096834934)) + z1; /* (c4-c6)/2 */
+
+ tmp20 = MULTIPLY(z2, FIX(1.373119086)) + tmp12 + tmp13; /* c2 */
+ tmp22 = MULTIPLY(z2, FIX(0.501487041)) - tmp12 + tmp13; /* c10 */
+
+ tmp12 = MULTIPLY(tmp10, FIX(0.316450131)); /* (c8-c12)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.486914739)) + z1; /* (c8+c12)/2 */
+
+ tmp21 = MULTIPLY(z2, FIX(1.058554052)) - tmp12 + tmp13; /* c6 */
+ tmp25 = MULTIPLY(z2, - FIX(1.252223920)) + tmp12 + tmp13; /* c4 */
+
+ tmp12 = MULTIPLY(tmp10, FIX(0.435816023)); /* (c2-c10)/2 */
+ tmp13 = MULTIPLY(tmp11, FIX(0.937303064)) - z1; /* (c2+c10)/2 */
+
+ tmp23 = MULTIPLY(z2, - FIX(0.170464608)) - tmp12 - tmp13; /* c12 */
+ tmp24 = MULTIPLY(z2, - FIX(0.803364869)) + tmp12 - tmp13; /* c8 */
+
+ tmp26 = MULTIPLY(tmp11 - z2, FIX(1.414213562)) + z1; /* c0 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.322312651)); /* c3 */
+ tmp12 = MULTIPLY(z1 + z3, FIX(1.163874945)); /* c5 */
+ tmp15 = z1 + z4;
+ tmp13 = MULTIPLY(tmp15, FIX(0.937797057)); /* c7 */
+ tmp10 = tmp11 + tmp12 + tmp13 -
+ MULTIPLY(z1, FIX(2.020082300)); /* c7+c5+c3-c1 */
+ tmp14 = MULTIPLY(z2 + z3, - FIX(0.338443458)); /* -c11 */
+ tmp11 += tmp14 + MULTIPLY(z2, FIX(0.837223564)); /* c5+c9+c11-c3 */
+ tmp12 += tmp14 - MULTIPLY(z3, FIX(1.572116027)); /* c1+c5-c9-c11 */
+ tmp14 = MULTIPLY(z2 + z4, - FIX(1.163874945)); /* -c5 */
+ tmp11 += tmp14;
+ tmp13 += tmp14 + MULTIPLY(z4, FIX(2.205608352)); /* c3+c5+c9-c7 */
+ tmp14 = MULTIPLY(z3 + z4, - FIX(0.657217813)); /* -c9 */
+ tmp12 += tmp14;
+ tmp13 += tmp14;
+ tmp15 = MULTIPLY(tmp15, FIX(0.338443458)); /* c11 */
+ tmp14 = tmp15 + MULTIPLY(z1, FIX(0.318774355)) - /* c9-c11 */
+ MULTIPLY(z2, FIX(0.466105296)); /* c1-c7 */
+ z1 = MULTIPLY(z3 - z2, FIX(0.937797057)); /* c7 */
+ tmp14 += z1;
+ tmp15 += z1 + MULTIPLY(z3, FIX(0.384515595)) - /* c3-c7 */
+ MULTIPLY(z4, FIX(1.742345811)); /* c1+c11 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 14x14 output block.
+ *
+ * Optimized algorithm with 20 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/28).
+ */
+
+GLOBAL(void)
+jpeg_idct_14x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*14]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z1 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */
+ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */
+ z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */
+
+ tmp10 = z1 + z2;
+ tmp11 = z1 + z3;
+ tmp12 = z1 - z4;
+
+ tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */
+ CONST_BITS-PASS1_BITS);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */
+
+ tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+ tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+ tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */
+ MULTIPLY(z2, FIX(1.378756276)); /* c2 */
+
+ tmp20 = tmp10 + tmp13;
+ tmp26 = tmp10 - tmp13;
+ tmp21 = tmp11 + tmp14;
+ tmp25 = tmp11 - tmp14;
+ tmp22 = tmp12 + tmp15;
+ tmp24 = tmp12 - tmp15;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp13 = z4 << CONST_BITS;
+
+ tmp14 = z1 + z3;
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */
+ tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */
+ tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+ tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */
+ tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */
+ z1 -= z2;
+ tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */
+ tmp16 += tmp15;
+ z1 += z4;
+ z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */
+ tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */
+ tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */
+ z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */
+ tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+ tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */
+
+ tmp13 = (z1 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) (tmp23 + tmp13);
+ wsptr[8*10] = (int) (tmp23 - tmp13);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 14 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 14; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z1 <<= CONST_BITS;
+ z4 = (INT32) wsptr[4];
+ z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */
+ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */
+ z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */
+
+ tmp10 = z1 + z2;
+ tmp11 = z1 + z3;
+ tmp12 = z1 - z4;
+
+ tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[6];
+
+ z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */
+
+ tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+ tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+ tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */
+ MULTIPLY(z2, FIX(1.378756276)); /* c2 */
+
+ tmp20 = tmp10 + tmp13;
+ tmp26 = tmp10 - tmp13;
+ tmp21 = tmp11 + tmp14;
+ tmp25 = tmp11 - tmp14;
+ tmp22 = tmp12 + tmp15;
+ tmp24 = tmp12 - tmp15;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+ z4 <<= CONST_BITS;
+
+ tmp14 = z1 + z3;
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */
+ tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */
+ tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+ tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */
+ tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */
+ z1 -= z2;
+ tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */
+ tmp16 += tmp15;
+ tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */
+ tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */
+ tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */
+ tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */
+ tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+ tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */
+
+ tmp13 = ((z1 - z3) << CONST_BITS) + z4;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 15x15 output block.
+ *
+ * Optimized algorithm with 22 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/30).
+ */
+
+GLOBAL(void)
+jpeg_idct_15x15 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*15]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z1 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */
+ tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */
+
+ tmp12 = z1 - tmp10;
+ tmp13 = z1 + tmp11;
+ z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */
+
+ z4 = z2 - z3;
+ z3 += z2;
+ tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */
+ z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */
+
+ tmp20 = tmp13 + tmp10 + tmp11;
+ tmp23 = tmp12 - tmp10 + tmp11 + z2;
+
+ tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */
+
+ tmp25 = tmp13 - tmp10 - tmp11;
+ tmp26 = tmp12 + tmp10 - tmp11 - z2;
+
+ tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */
+
+ tmp21 = tmp12 + tmp10 + tmp11;
+ tmp24 = tmp13 - tmp10 + tmp11;
+ tmp11 += tmp11;
+ tmp22 = z1 + tmp11; /* c10 = c6-c12 */
+ tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp13 = z2 - z4;
+ tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */
+ tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */
+ tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */
+
+ tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */
+ tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */
+ z2 = z1 - z4;
+ tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */
+
+ tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */
+ tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */
+ tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */
+ z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */
+ tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */
+ tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*14] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*13] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp27, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 15 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 15; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z1 <<= CONST_BITS;
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[4];
+ z4 = (INT32) wsptr[6];
+
+ tmp10 = MULTIPLY(z4, FIX(0.437016024)); /* c12 */
+ tmp11 = MULTIPLY(z4, FIX(1.144122806)); /* c6 */
+
+ tmp12 = z1 - tmp10;
+ tmp13 = z1 + tmp11;
+ z1 -= (tmp11 - tmp10) << 1; /* c0 = (c6-c12)*2 */
+
+ z4 = z2 - z3;
+ z3 += z2;
+ tmp10 = MULTIPLY(z3, FIX(1.337628990)); /* (c2+c4)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.045680613)); /* (c2-c4)/2 */
+ z2 = MULTIPLY(z2, FIX(1.439773946)); /* c4+c14 */
+
+ tmp20 = tmp13 + tmp10 + tmp11;
+ tmp23 = tmp12 - tmp10 + tmp11 + z2;
+
+ tmp10 = MULTIPLY(z3, FIX(0.547059574)); /* (c8+c14)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.399234004)); /* (c8-c14)/2 */
+
+ tmp25 = tmp13 - tmp10 - tmp11;
+ tmp26 = tmp12 + tmp10 - tmp11 - z2;
+
+ tmp10 = MULTIPLY(z3, FIX(0.790569415)); /* (c6+c12)/2 */
+ tmp11 = MULTIPLY(z4, FIX(0.353553391)); /* (c6-c12)/2 */
+
+ tmp21 = tmp12 + tmp10 + tmp11;
+ tmp24 = tmp13 - tmp10 + tmp11;
+ tmp11 += tmp11;
+ tmp22 = z1 + tmp11; /* c10 = c6-c12 */
+ tmp27 = z1 - tmp11 - tmp11; /* c0 = (c6-c12)*2 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z4 = (INT32) wsptr[5];
+ z3 = MULTIPLY(z4, FIX(1.224744871)); /* c5 */
+ z4 = (INT32) wsptr[7];
+
+ tmp13 = z2 - z4;
+ tmp15 = MULTIPLY(z1 + tmp13, FIX(0.831253876)); /* c9 */
+ tmp11 = tmp15 + MULTIPLY(z1, FIX(0.513743148)); /* c3-c9 */
+ tmp14 = tmp15 - MULTIPLY(tmp13, FIX(2.176250899)); /* c3+c9 */
+
+ tmp13 = MULTIPLY(z2, - FIX(0.831253876)); /* -c9 */
+ tmp15 = MULTIPLY(z2, - FIX(1.344997024)); /* -c3 */
+ z2 = z1 - z4;
+ tmp12 = z3 + MULTIPLY(z2, FIX(1.406466353)); /* c1 */
+
+ tmp10 = tmp12 + MULTIPLY(z4, FIX(2.457431844)) - tmp15; /* c1+c7 */
+ tmp16 = tmp12 - MULTIPLY(z1, FIX(1.112434820)) + tmp13; /* c1-c13 */
+ tmp12 = MULTIPLY(z2, FIX(1.224744871)) - z3; /* c5 */
+ z2 = MULTIPLY(z1 + z4, FIX(0.575212477)); /* c11 */
+ tmp13 += z2 + MULTIPLY(z1, FIX(0.475753014)) - z3; /* c7-c11 */
+ tmp15 += z2 - MULTIPLY(z4, FIX(0.869244010)) + z3; /* c11+c13 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 16x16 output block.
+ *
+ * Optimized algorithm with 28 multiplications in the 1-D kernel.
+ * cK represents sqrt(2) * cos(K*pi/32).
+ */
+
+GLOBAL(void)
+jpeg_idct_16x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*16]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += 1 << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
+ tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+ z3 = z1 - z2;
+ z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */
+ z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */
+ tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */
+ tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+ tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+ tmp20 = tmp10 + tmp0;
+ tmp27 = tmp10 - tmp0;
+ tmp21 = tmp12 + tmp1;
+ tmp26 = tmp12 - tmp1;
+ tmp22 = tmp13 + tmp2;
+ tmp25 = tmp13 - tmp2;
+ tmp23 = tmp11 + tmp3;
+ tmp24 = tmp11 - tmp3;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z1 + z3;
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */
+ tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */
+ tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */
+ tmp13 = tmp10 + tmp11 + tmp12 -
+ MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */
+ z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */
+ tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */
+ tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */
+ z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */
+ tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */
+ tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */
+ z2 += z4;
+ z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */
+ tmp1 += z1;
+ tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */
+ z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */
+ tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */
+ tmp12 += z2;
+ z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+ tmp2 += z2;
+ tmp3 += z2;
+ z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */
+ tmp10 += z2;
+ tmp11 += z2;
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 16 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 16; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[4];
+ tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
+ tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[6];
+ z3 = z1 - z2;
+ z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */
+ z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */
+ tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */
+ tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+ tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+ tmp20 = tmp10 + tmp0;
+ tmp27 = tmp10 - tmp0;
+ tmp21 = tmp12 + tmp1;
+ tmp26 = tmp12 - tmp1;
+ tmp22 = tmp13 + tmp2;
+ tmp25 = tmp13 - tmp2;
+ tmp23 = tmp11 + tmp3;
+ tmp24 = tmp11 - tmp3;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z1 + z3;
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */
+ tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */
+ tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */
+ tmp13 = tmp10 + tmp11 + tmp12 -
+ MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */
+ z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */
+ tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */
+ tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */
+ z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */
+ tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */
+ tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */
+ z2 += z4;
+ z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */
+ tmp1 += z1;
+ tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */
+ z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */
+ tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */
+ tmp12 += z2;
+ z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+ tmp2 += z2;
+ tmp3 += z2;
+ z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */
+ tmp10 += z2;
+ tmp11 += z2;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 16x8 output block.
+ *
+ * 8-point IDCT in pass 1 (columns), 16-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_16x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*8]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = DCTSIZE; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[DCTSIZE*0] = dcval;
+ wsptr[DCTSIZE*1] = dcval;
+ wsptr[DCTSIZE*2] = dcval;
+ wsptr[DCTSIZE*3] = dcval;
+ wsptr[DCTSIZE*4] = dcval;
+ wsptr[DCTSIZE*5] = dcval;
+ wsptr[DCTSIZE*6] = dcval;
+ wsptr[DCTSIZE*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 <<= CONST_BITS;
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ tmp0 = z2 + z3;
+ tmp1 = z2 - z3;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ wsptr[DCTSIZE*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[DCTSIZE*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process 8 rows from work array, store into output array.
+ * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[4];
+ tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
+ tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[6];
+ z3 = z1 - z2;
+ z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */
+ z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */
+ tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */
+ tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+ tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+ tmp20 = tmp10 + tmp0;
+ tmp27 = tmp10 - tmp0;
+ tmp21 = tmp12 + tmp1;
+ tmp26 = tmp12 - tmp1;
+ tmp22 = tmp13 + tmp2;
+ tmp25 = tmp13 - tmp2;
+ tmp23 = tmp11 + tmp3;
+ tmp24 = tmp11 - tmp3;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z1 + z3;
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */
+ tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */
+ tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */
+ tmp13 = tmp10 + tmp11 + tmp12 -
+ MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */
+ z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */
+ tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */
+ tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */
+ z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */
+ tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */
+ tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */
+ z2 += z4;
+ z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */
+ tmp1 += z1;
+ tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */
+ z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */
+ tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */
+ tmp12 += z2;
+ z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+ tmp2 += z2;
+ tmp3 += z2;
+ z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */
+ tmp10 += z2;
+ tmp11 += z2;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[15] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[14] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp27 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp27 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 14x7 output block.
+ *
+ * 7-point IDCT in pass 1 (columns), 14-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_14x7 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*7]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp23 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp23 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp23 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */
+ tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */
+ tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+ tmp10 = z1 + z3;
+ z2 -= tmp10;
+ tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */
+ tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */
+ tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */
+ tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+
+ tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp10 = tmp11 - tmp12;
+ tmp11 += tmp12;
+ tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */
+ tmp11 += tmp12;
+ z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */
+ tmp10 += z2;
+ tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 7 rows from work array, store into output array.
+ * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z1 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z1 <<= CONST_BITS;
+ z4 = (INT32) wsptr[4];
+ z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */
+ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */
+ z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */
+
+ tmp10 = z1 + z2;
+ tmp11 = z1 + z3;
+ tmp12 = z1 - z4;
+
+ tmp23 = z1 - ((z2 + z3 - z4) << 1); /* c0 = (c4+c12-c8)*2 */
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[6];
+
+ z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */
+
+ tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+ tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+ tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */
+ MULTIPLY(z2, FIX(1.378756276)); /* c2 */
+
+ tmp20 = tmp10 + tmp13;
+ tmp26 = tmp10 - tmp13;
+ tmp21 = tmp11 + tmp14;
+ tmp25 = tmp11 - tmp14;
+ tmp22 = tmp12 + tmp15;
+ tmp24 = tmp12 - tmp15;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+ z4 <<= CONST_BITS;
+
+ tmp14 = z1 + z3;
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */
+ tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */
+ tmp10 = tmp11 + tmp12 + z4 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+ tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */
+ tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */
+ z1 -= z2;
+ tmp15 = MULTIPLY(z1, FIX(0.467085129)) - z4; /* c11 */
+ tmp16 += tmp15;
+ tmp13 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - z4; /* -c13 */
+ tmp11 += tmp13 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */
+ tmp12 += tmp13 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */
+ tmp13 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */
+ tmp14 += tmp13 + z4 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+ tmp15 += tmp13 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */
+
+ tmp13 = ((z1 - z3) << CONST_BITS) + z4;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[13] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[12] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp26 + tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp26 - tmp16,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 12x6 output block.
+ *
+ * 6-point IDCT in pass 1 (columns), 12-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_12x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*6]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp10 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp10 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */
+ tmp11 = tmp10 + tmp20;
+ tmp21 = RIGHT_SHIFT(tmp10 - tmp20 - tmp20, CONST_BITS-PASS1_BITS);
+ tmp20 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */
+ tmp20 = tmp11 + tmp10;
+ tmp22 = tmp11 - tmp10;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp10 = tmp11 + ((z1 + z2) << CONST_BITS);
+ tmp12 = tmp11 + ((z3 - z2) << CONST_BITS);
+ tmp11 = (z1 - z2 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) (tmp21 + tmp11);
+ wsptr[8*4] = (int) (tmp21 - tmp11);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 6 rows from work array, store into output array.
+ * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 <<= CONST_BITS;
+
+ z4 = (INT32) wsptr[4];
+ z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ z1 = (INT32) wsptr[2];
+ z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+ z1 <<= CONST_BITS;
+ z2 = (INT32) wsptr[6];
+ z2 <<= CONST_BITS;
+
+ tmp12 = z1 - z2;
+
+ tmp21 = z3 + tmp12;
+ tmp24 = z3 - tmp12;
+
+ tmp12 = z4 + z2;
+
+ tmp20 = tmp10 + tmp12;
+ tmp25 = tmp10 - tmp12;
+
+ tmp12 = z4 - z1 - z2;
+
+ tmp22 = tmp11 + tmp12;
+ tmp23 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */
+ tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */
+
+ tmp10 = z1 + z3;
+ tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */
+ tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */
+ tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */
+ tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */
+ tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+ tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+ tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */
+ MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */
+
+ z1 -= z4;
+ z2 -= z3;
+ z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */
+ tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */
+ tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[11] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[10] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp25 + tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp25 - tmp15,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 10x5 output block.
+ *
+ * 5-point IDCT in pass 1 (columns), 10-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_10x5 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*5]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp12 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp12 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp13 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp14 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */
+ z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */
+ z3 = tmp12 + z2;
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z1;
+ tmp12 -= z2 << 2;
+
+ /* Odd part */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */
+ tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */
+ tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp10 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp10 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp11 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp11 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp12, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 5 rows from work array, store into output array.
+ * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ z3 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 <<= CONST_BITS;
+ z4 = (INT32) wsptr[4];
+ z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */
+ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z2;
+
+ tmp22 = z3 - ((z1 - z2) << 1); /* c0 = (c4-c8)*2 */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */
+ tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+ tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+ tmp20 = tmp10 + tmp12;
+ tmp24 = tmp10 - tmp12;
+ tmp21 = tmp11 + tmp13;
+ tmp23 = tmp11 - tmp13;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ z3 <<= CONST_BITS;
+ z4 = (INT32) wsptr[7];
+
+ tmp11 = z2 + z4;
+ tmp13 = z2 - z4;
+
+ tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */
+ z4 = z3 + tmp12;
+
+ tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+ tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */
+ z4 = z3 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+ tmp12 = ((z1 - tmp13) << CONST_BITS) - z3;
+
+ tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[9] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[8] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp23 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp24 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp24 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 8; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 8x4 output block.
+ *
+ * 4-point IDCT in pass 1 (columns), 8-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_8x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*4]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 4-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+
+ tmp10 = (tmp0 + tmp2) << PASS1_BITS;
+ tmp12 = (tmp0 - tmp2) << PASS1_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp0 = RIGHT_SHIFT(z1 + MULTIPLY(z2, FIX_0_765366865), /* c2-c6 */
+ CONST_BITS-PASS1_BITS);
+ tmp2 = RIGHT_SHIFT(z1 - MULTIPLY(z3, FIX_1_847759065), /* c2+c6 */
+ CONST_BITS-PASS1_BITS);
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) (tmp10 + tmp0);
+ wsptr[8*3] = (int) (tmp10 - tmp0);
+ wsptr[8*1] = (int) (tmp12 + tmp2);
+ wsptr[8*2] = (int) (tmp12 - tmp2);
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ /* Add fudge factor here for final descale. */
+ z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 = (INT32) wsptr[4];
+
+ tmp0 = (z2 + z3) << CONST_BITS;
+ tmp1 = (z2 - z3) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = (INT32) wsptr[7];
+ tmp1 = (INT32) wsptr[5];
+ tmp2 = (INT32) wsptr[3];
+ tmp3 = (INT32) wsptr[1];
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 6x3 output block.
+ *
+ * 3-point IDCT in pass 1 (columns), 6-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x3 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[6*3]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+ tmp10 = tmp0 + tmp12;
+ tmp2 = tmp0 - tmp12 - tmp12;
+
+ /* Odd part */
+
+ tmp12 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+ /* Final output stage */
+
+ wsptr[6*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[6*2] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[6*1] = (int) RIGHT_SHIFT(tmp2, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 3 rows from work array, store into output array.
+ * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 3; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+ tmp2 = (INT32) wsptr[4];
+ tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */
+ tmp1 = tmp0 + tmp10;
+ tmp11 = tmp0 - tmp10 - tmp10;
+ tmp10 = (INT32) wsptr[2];
+ tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */
+ tmp10 = tmp1 + tmp0;
+ tmp12 = tmp1 - tmp0;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+ tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+ tmp1 = (z1 - z2 - z3) << CONST_BITS;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 6; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 4x2 output block.
+ *
+ * 2-point IDCT in pass 1 (columns), 4-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_4x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ INT32 * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ INT32 workspace[4*2]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+
+ /* Odd part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ /* Final output stage */
+
+ wsptr[4*0] = tmp10 + tmp0;
+ wsptr[4*1] = tmp10 - tmp0;
+ }
+
+ /* Pass 2: process 2 rows from work array, store into output array.
+ * 4-point IDCT kernel,
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 2; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = wsptr[0] + (ONE << 2);
+ tmp2 = wsptr[2];
+
+ tmp10 = (tmp0 + tmp2) << CONST_BITS;
+ tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = wsptr[1];
+ z3 = wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+ tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 4; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 2x1 output block.
+ *
+ * 1-point IDCT in pass 1 (columns), 2-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_2x1 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp10;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* Pass 1: empty. */
+
+ /* Pass 2: process 1 row from input, store into output array. */
+
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ outptr = output_buf[0] + output_col;
+
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(coef_block[0], quantptr[0]);
+ /* Add fudge factor here for final descale. */
+ tmp10 += ONE << 2;
+
+ /* Odd part */
+
+ tmp0 = DEQUANTIZE(coef_block[1], quantptr[1]);
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, 3) & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, 3) & RANGE_MASK];
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 8x16 output block.
+ *
+ * 16-point IDCT in pass 1 (columns), 8-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_8x16 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3, tmp10, tmp11, tmp12, tmp13;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[8*16]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 16-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/32).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp1 = MULTIPLY(z1, FIX(1.306562965)); /* c4[16] = c2[8] */
+ tmp2 = MULTIPLY(z1, FIX_0_541196100); /* c12[16] = c6[8] */
+
+ tmp10 = tmp0 + tmp1;
+ tmp11 = tmp0 - tmp1;
+ tmp12 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+ z3 = z1 - z2;
+ z4 = MULTIPLY(z3, FIX(0.275899379)); /* c14[16] = c7[8] */
+ z3 = MULTIPLY(z3, FIX(1.387039845)); /* c2[16] = c1[8] */
+
+ tmp0 = z3 + MULTIPLY(z2, FIX_2_562915447); /* (c6+c2)[16] = (c3+c1)[8] */
+ tmp1 = z4 + MULTIPLY(z1, FIX_0_899976223); /* (c6-c14)[16] = (c3-c7)[8] */
+ tmp2 = z3 - MULTIPLY(z1, FIX(0.601344887)); /* (c2-c10)[16] = (c1-c5)[8] */
+ tmp3 = z4 - MULTIPLY(z2, FIX(0.509795579)); /* (c10-c14)[16] = (c5-c7)[8] */
+
+ tmp20 = tmp10 + tmp0;
+ tmp27 = tmp10 - tmp0;
+ tmp21 = tmp12 + tmp1;
+ tmp26 = tmp12 - tmp1;
+ tmp22 = tmp13 + tmp2;
+ tmp25 = tmp13 - tmp2;
+ tmp23 = tmp11 + tmp3;
+ tmp24 = tmp11 - tmp3;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z1 + z3;
+
+ tmp1 = MULTIPLY(z1 + z2, FIX(1.353318001)); /* c3 */
+ tmp2 = MULTIPLY(tmp11, FIX(1.247225013)); /* c5 */
+ tmp3 = MULTIPLY(z1 + z4, FIX(1.093201867)); /* c7 */
+ tmp10 = MULTIPLY(z1 - z4, FIX(0.897167586)); /* c9 */
+ tmp11 = MULTIPLY(tmp11, FIX(0.666655658)); /* c11 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.410524528)); /* c13 */
+ tmp0 = tmp1 + tmp2 + tmp3 -
+ MULTIPLY(z1, FIX(2.286341144)); /* c7+c5+c3-c1 */
+ tmp13 = tmp10 + tmp11 + tmp12 -
+ MULTIPLY(z1, FIX(1.835730603)); /* c9+c11+c13-c15 */
+ z1 = MULTIPLY(z2 + z3, FIX(0.138617169)); /* c15 */
+ tmp1 += z1 + MULTIPLY(z2, FIX(0.071888074)); /* c9+c11-c3-c15 */
+ tmp2 += z1 - MULTIPLY(z3, FIX(1.125726048)); /* c5+c7+c15-c3 */
+ z1 = MULTIPLY(z3 - z2, FIX(1.407403738)); /* c1 */
+ tmp11 += z1 - MULTIPLY(z3, FIX(0.766367282)); /* c1+c11-c9-c13 */
+ tmp12 += z1 + MULTIPLY(z2, FIX(1.971951411)); /* c1+c5+c13-c7 */
+ z2 += z4;
+ z1 = MULTIPLY(z2, - FIX(0.666655658)); /* -c11 */
+ tmp1 += z1;
+ tmp3 += z1 + MULTIPLY(z4, FIX(1.065388962)); /* c3+c11+c15-c7 */
+ z2 = MULTIPLY(z2, - FIX(1.247225013)); /* -c5 */
+ tmp10 += z2 + MULTIPLY(z4, FIX(3.141271809)); /* c1+c5+c9-c13 */
+ tmp12 += z2;
+ z2 = MULTIPLY(z3 + z4, - FIX(1.353318001)); /* -c3 */
+ tmp2 += z2;
+ tmp3 += z2;
+ z2 = MULTIPLY(z4 - z3, FIX(0.410524528)); /* c13 */
+ tmp10 += z2;
+ tmp11 += z2;
+
+ /* Final output stage */
+
+ wsptr[8*0] = (int) RIGHT_SHIFT(tmp20 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*15] = (int) RIGHT_SHIFT(tmp20 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[8*1] = (int) RIGHT_SHIFT(tmp21 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*14] = (int) RIGHT_SHIFT(tmp21 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[8*2] = (int) RIGHT_SHIFT(tmp22 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*13] = (int) RIGHT_SHIFT(tmp22 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[8*3] = (int) RIGHT_SHIFT(tmp23 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*12] = (int) RIGHT_SHIFT(tmp23 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[8*4] = (int) RIGHT_SHIFT(tmp24 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*11] = (int) RIGHT_SHIFT(tmp24 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[8*5] = (int) RIGHT_SHIFT(tmp25 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*10] = (int) RIGHT_SHIFT(tmp25 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[8*6] = (int) RIGHT_SHIFT(tmp26 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*9] = (int) RIGHT_SHIFT(tmp26 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[8*7] = (int) RIGHT_SHIFT(tmp27 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[8*8] = (int) RIGHT_SHIFT(tmp27 - tmp13, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process rows from work array, store into output array. */
+ /* Note that we must descale the results by a factor of 8 == 2**3, */
+ /* and also undo the PASS1_BITS scaling. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 16; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = (INT32) wsptr[2];
+ z3 = (INT32) wsptr[6];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ /* Add fudge factor here for final descale. */
+ z2 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ z3 = (INT32) wsptr[4];
+
+ tmp0 = (z2 + z3) << CONST_BITS;
+ tmp1 = (z2 - z3) << CONST_BITS;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = (INT32) wsptr[7];
+ tmp1 = (INT32) wsptr[5];
+ tmp2 = (INT32) wsptr[3];
+ tmp3 = (INT32) wsptr[1];
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[7] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp3,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp1,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp13 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp13 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += DCTSIZE; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 7x14 output block.
+ *
+ * 14-point IDCT in pass 1 (columns), 7-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_7x14 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[7*14]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 14-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/28).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 7; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z1 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z1 += ONE << (CONST_BITS-PASS1_BITS-1);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 = MULTIPLY(z4, FIX(1.274162392)); /* c4 */
+ z3 = MULTIPLY(z4, FIX(0.314692123)); /* c12 */
+ z4 = MULTIPLY(z4, FIX(0.881747734)); /* c8 */
+
+ tmp10 = z1 + z2;
+ tmp11 = z1 + z3;
+ tmp12 = z1 - z4;
+
+ tmp23 = RIGHT_SHIFT(z1 - ((z2 + z3 - z4) << 1), /* c0 = (c4+c12-c8)*2 */
+ CONST_BITS-PASS1_BITS);
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z3 = MULTIPLY(z1 + z2, FIX(1.105676686)); /* c6 */
+
+ tmp13 = z3 + MULTIPLY(z1, FIX(0.273079590)); /* c2-c6 */
+ tmp14 = z3 - MULTIPLY(z2, FIX(1.719280954)); /* c6+c10 */
+ tmp15 = MULTIPLY(z1, FIX(0.613604268)) - /* c10 */
+ MULTIPLY(z2, FIX(1.378756276)); /* c2 */
+
+ tmp20 = tmp10 + tmp13;
+ tmp26 = tmp10 - tmp13;
+ tmp21 = tmp11 + tmp14;
+ tmp25 = tmp11 - tmp14;
+ tmp22 = tmp12 + tmp15;
+ tmp24 = tmp12 - tmp15;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp13 = z4 << CONST_BITS;
+
+ tmp14 = z1 + z3;
+ tmp11 = MULTIPLY(z1 + z2, FIX(1.334852607)); /* c3 */
+ tmp12 = MULTIPLY(tmp14, FIX(1.197448846)); /* c5 */
+ tmp10 = tmp11 + tmp12 + tmp13 - MULTIPLY(z1, FIX(1.126980169)); /* c3+c5-c1 */
+ tmp14 = MULTIPLY(tmp14, FIX(0.752406978)); /* c9 */
+ tmp16 = tmp14 - MULTIPLY(z1, FIX(1.061150426)); /* c9+c11-c13 */
+ z1 -= z2;
+ tmp15 = MULTIPLY(z1, FIX(0.467085129)) - tmp13; /* c11 */
+ tmp16 += tmp15;
+ z1 += z4;
+ z4 = MULTIPLY(z2 + z3, - FIX(0.158341681)) - tmp13; /* -c13 */
+ tmp11 += z4 - MULTIPLY(z2, FIX(0.424103948)); /* c3-c9-c13 */
+ tmp12 += z4 - MULTIPLY(z3, FIX(2.373959773)); /* c3+c5-c13 */
+ z4 = MULTIPLY(z3 - z2, FIX(1.405321284)); /* c1 */
+ tmp14 += z4 + tmp13 - MULTIPLY(z3, FIX(1.6906431334)); /* c1+c9-c11 */
+ tmp15 += z4 + MULTIPLY(z2, FIX(0.674957567)); /* c1+c11-c5 */
+
+ tmp13 = (z1 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[7*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[7*13] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[7*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[7*12] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[7*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[7*11] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[7*3] = (int) (tmp23 + tmp13);
+ wsptr[7*10] = (int) (tmp23 - tmp13);
+ wsptr[7*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[7*9] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[7*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[7*8] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[7*6] = (int) RIGHT_SHIFT(tmp26 + tmp16, CONST_BITS-PASS1_BITS);
+ wsptr[7*7] = (int) RIGHT_SHIFT(tmp26 - tmp16, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 14 rows from work array, store into output array.
+ * 7-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/14).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 14; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp23 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp23 <<= CONST_BITS;
+
+ z1 = (INT32) wsptr[2];
+ z2 = (INT32) wsptr[4];
+ z3 = (INT32) wsptr[6];
+
+ tmp20 = MULTIPLY(z2 - z3, FIX(0.881747734)); /* c4 */
+ tmp22 = MULTIPLY(z1 - z2, FIX(0.314692123)); /* c6 */
+ tmp21 = tmp20 + tmp22 + tmp23 - MULTIPLY(z2, FIX(1.841218003)); /* c2+c4-c6 */
+ tmp10 = z1 + z3;
+ z2 -= tmp10;
+ tmp10 = MULTIPLY(tmp10, FIX(1.274162392)) + tmp23; /* c2 */
+ tmp20 += tmp10 - MULTIPLY(z3, FIX(0.077722536)); /* c2-c4-c6 */
+ tmp22 += tmp10 - MULTIPLY(z1, FIX(2.470602249)); /* c2+c4+c6 */
+ tmp23 += MULTIPLY(z2, FIX(1.414213562)); /* c0 */
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+
+ tmp11 = MULTIPLY(z1 + z2, FIX(0.935414347)); /* (c3+c1-c5)/2 */
+ tmp12 = MULTIPLY(z1 - z2, FIX(0.170262339)); /* (c3+c5-c1)/2 */
+ tmp10 = tmp11 - tmp12;
+ tmp11 += tmp12;
+ tmp12 = MULTIPLY(z2 + z3, - FIX(1.378756276)); /* -c1 */
+ tmp11 += tmp12;
+ z2 = MULTIPLY(z1 + z3, FIX(0.613604268)); /* c5 */
+ tmp10 += z2;
+ tmp12 += z2 + MULTIPLY(z3, FIX(1.870828693)); /* c3+c1-c5 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[6] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp23,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 7; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 6x12 output block.
+ *
+ * 12-point IDCT in pass 1 (columns), 6-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_6x12 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14, tmp15;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24, tmp25;
+ INT32 z1, z2, z3, z4;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[6*12]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 12-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/24).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z4 = MULTIPLY(z4, FIX(1.224744871)); /* c4 */
+
+ tmp10 = z3 + z4;
+ tmp11 = z3 - z4;
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z4 = MULTIPLY(z1, FIX(1.366025404)); /* c2 */
+ z1 <<= CONST_BITS;
+ z2 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+ z2 <<= CONST_BITS;
+
+ tmp12 = z1 - z2;
+
+ tmp21 = z3 + tmp12;
+ tmp24 = z3 - tmp12;
+
+ tmp12 = z4 + z2;
+
+ tmp20 = tmp10 + tmp12;
+ tmp25 = tmp10 - tmp12;
+
+ tmp12 = z4 - z1 - z2;
+
+ tmp22 = tmp11 + tmp12;
+ tmp23 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = MULTIPLY(z2, FIX(1.306562965)); /* c3 */
+ tmp14 = MULTIPLY(z2, - FIX_0_541196100); /* -c9 */
+
+ tmp10 = z1 + z3;
+ tmp15 = MULTIPLY(tmp10 + z4, FIX(0.860918669)); /* c7 */
+ tmp12 = tmp15 + MULTIPLY(tmp10, FIX(0.261052384)); /* c5-c7 */
+ tmp10 = tmp12 + tmp11 + MULTIPLY(z1, FIX(0.280143716)); /* c1-c5 */
+ tmp13 = MULTIPLY(z3 + z4, - FIX(1.045510580)); /* -(c7+c11) */
+ tmp12 += tmp13 + tmp14 - MULTIPLY(z3, FIX(1.478575242)); /* c1+c5-c7-c11 */
+ tmp13 += tmp15 - tmp11 + MULTIPLY(z4, FIX(1.586706681)); /* c1+c11 */
+ tmp15 += tmp14 - MULTIPLY(z1, FIX(0.676326758)) - /* c7-c11 */
+ MULTIPLY(z4, FIX(1.982889723)); /* c5+c7 */
+
+ z1 -= z4;
+ z2 -= z3;
+ z3 = MULTIPLY(z1 + z2, FIX_0_541196100); /* c9 */
+ tmp11 = z3 + MULTIPLY(z1, FIX_0_765366865); /* c3-c9 */
+ tmp14 = z3 - MULTIPLY(z2, FIX_1_847759065); /* c3+c9 */
+
+ /* Final output stage */
+
+ wsptr[6*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[6*11] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[6*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[6*10] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[6*2] = (int) RIGHT_SHIFT(tmp22 + tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[6*9] = (int) RIGHT_SHIFT(tmp22 - tmp12, CONST_BITS-PASS1_BITS);
+ wsptr[6*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[6*8] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[6*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[6*7] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[6*5] = (int) RIGHT_SHIFT(tmp25 + tmp15, CONST_BITS-PASS1_BITS);
+ wsptr[6*6] = (int) RIGHT_SHIFT(tmp25 - tmp15, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 12 rows from work array, store into output array.
+ * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 12; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp10 <<= CONST_BITS;
+ tmp12 = (INT32) wsptr[4];
+ tmp20 = MULTIPLY(tmp12, FIX(0.707106781)); /* c4 */
+ tmp11 = tmp10 + tmp20;
+ tmp21 = tmp10 - tmp20 - tmp20;
+ tmp20 = (INT32) wsptr[2];
+ tmp10 = MULTIPLY(tmp20, FIX(1.224744871)); /* c2 */
+ tmp20 = tmp11 + tmp10;
+ tmp22 = tmp11 - tmp10;
+
+ /* Odd part */
+
+ z1 = (INT32) wsptr[1];
+ z2 = (INT32) wsptr[3];
+ z3 = (INT32) wsptr[5];
+ tmp11 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp10 = tmp11 + ((z1 + z2) << CONST_BITS);
+ tmp12 = tmp11 + ((z3 - z2) << CONST_BITS);
+ tmp11 = (z1 - z2 - z3) << CONST_BITS;
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp20 + tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[5] = range_limit[(int) RIGHT_SHIFT(tmp20 - tmp10,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp21 + tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp21 - tmp11,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp22 + tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp22 - tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 6; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 5x10 output block.
+ *
+ * 10-point IDCT in pass 1 (columns), 5-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_5x10 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp10, tmp11, tmp12, tmp13, tmp14;
+ INT32 tmp20, tmp21, tmp22, tmp23, tmp24;
+ INT32 z1, z2, z3, z4, z5;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[5*10]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 10-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/20).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 5; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ z3 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z3 += ONE << (CONST_BITS-PASS1_BITS-1);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z1 = MULTIPLY(z4, FIX(1.144122806)); /* c4 */
+ z2 = MULTIPLY(z4, FIX(0.437016024)); /* c8 */
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z2;
+
+ tmp22 = RIGHT_SHIFT(z3 - ((z1 - z2) << 1), /* c0 = (c4-c8)*2 */
+ CONST_BITS-PASS1_BITS);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c6 */
+ tmp12 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c2-c6 */
+ tmp13 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c2+c6 */
+
+ tmp20 = tmp10 + tmp12;
+ tmp24 = tmp10 - tmp12;
+ tmp21 = tmp11 + tmp13;
+ tmp23 = tmp11 - tmp13;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ z4 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+
+ tmp11 = z2 + z4;
+ tmp13 = z2 - z4;
+
+ tmp12 = MULTIPLY(tmp13, FIX(0.309016994)); /* (c3-c7)/2 */
+ z5 = z3 << CONST_BITS;
+
+ z2 = MULTIPLY(tmp11, FIX(0.951056516)); /* (c3+c7)/2 */
+ z4 = z5 + tmp12;
+
+ tmp10 = MULTIPLY(z1, FIX(1.396802247)) + z2 + z4; /* c1 */
+ tmp14 = MULTIPLY(z1, FIX(0.221231742)) - z2 + z4; /* c9 */
+
+ z2 = MULTIPLY(tmp11, FIX(0.587785252)); /* (c1-c9)/2 */
+ z4 = z5 - tmp12 - (tmp13 << (CONST_BITS - 1));
+
+ tmp12 = (z1 - tmp13 - z3) << PASS1_BITS;
+
+ tmp11 = MULTIPLY(z1, FIX(1.260073511)) - z2 - z4; /* c3 */
+ tmp13 = MULTIPLY(z1, FIX(0.642039522)) - z2 + z4; /* c7 */
+
+ /* Final output stage */
+
+ wsptr[5*0] = (int) RIGHT_SHIFT(tmp20 + tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[5*9] = (int) RIGHT_SHIFT(tmp20 - tmp10, CONST_BITS-PASS1_BITS);
+ wsptr[5*1] = (int) RIGHT_SHIFT(tmp21 + tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[5*8] = (int) RIGHT_SHIFT(tmp21 - tmp11, CONST_BITS-PASS1_BITS);
+ wsptr[5*2] = (int) (tmp22 + tmp12);
+ wsptr[5*7] = (int) (tmp22 - tmp12);
+ wsptr[5*3] = (int) RIGHT_SHIFT(tmp23 + tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[5*6] = (int) RIGHT_SHIFT(tmp23 - tmp13, CONST_BITS-PASS1_BITS);
+ wsptr[5*4] = (int) RIGHT_SHIFT(tmp24 + tmp14, CONST_BITS-PASS1_BITS);
+ wsptr[5*5] = (int) RIGHT_SHIFT(tmp24 - tmp14, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 10 rows from work array, store into output array.
+ * 5-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/10).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 10; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp12 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp12 <<= CONST_BITS;
+ tmp13 = (INT32) wsptr[2];
+ tmp14 = (INT32) wsptr[4];
+ z1 = MULTIPLY(tmp13 + tmp14, FIX(0.790569415)); /* (c2+c4)/2 */
+ z2 = MULTIPLY(tmp13 - tmp14, FIX(0.353553391)); /* (c2-c4)/2 */
+ z3 = tmp12 + z2;
+ tmp10 = z3 + z1;
+ tmp11 = z3 - z1;
+ tmp12 -= z2 << 2;
+
+ /* Odd part */
+
+ z2 = (INT32) wsptr[1];
+ z3 = (INT32) wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX(0.831253876)); /* c3 */
+ tmp13 = z1 + MULTIPLY(z2, FIX(0.513743148)); /* c1-c3 */
+ tmp14 = z1 - MULTIPLY(z3, FIX(2.176250899)); /* c1+c3 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[4] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp13,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp11 + tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp11 - tmp14,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 5; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 4x8 output block.
+ *
+ * 8-point IDCT in pass 1 (columns), 4-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_4x8 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp3;
+ INT32 tmp10, tmp11, tmp12, tmp13;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[4*8]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array. */
+ /* Note results are scaled up by sqrt(8) compared to a true IDCT; */
+ /* furthermore, we scale the results by 2**PASS1_BITS. */
+
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 4; ctr > 0; ctr--) {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit this
+ * by short-circuiting the IDCT calculation for any column in which all
+ * the AC terms are zero. In that case each output is equal to the
+ * DC coefficient (with scale factor as needed).
+ * With typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
+ inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
+ inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
+ inptr[DCTSIZE*7] == 0) {
+ /* AC terms all zero */
+ int dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]) << PASS1_BITS;
+
+ wsptr[4*0] = dcval;
+ wsptr[4*1] = dcval;
+ wsptr[4*2] = dcval;
+ wsptr[4*3] = dcval;
+ wsptr[4*4] = dcval;
+ wsptr[4*5] = dcval;
+ wsptr[4*6] = dcval;
+ wsptr[4*7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
+
+ /* Even part: reverse the even part of the forward DCT. */
+ /* The rotator is sqrt(2)*c(-6). */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);
+ tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ z2 <<= CONST_BITS;
+ z3 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ z2 += ONE << (CONST_BITS-PASS1_BITS-1);
+
+ tmp0 = z2 + z3;
+ tmp1 = z2 - z3;
+
+ tmp10 = tmp0 + tmp2;
+ tmp13 = tmp0 - tmp2;
+ tmp11 = tmp1 + tmp3;
+ tmp12 = tmp1 - tmp3;
+
+ /* Odd part per figure 8; the matrix is unitary and hence its
+ * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively.
+ */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
+ tmp1 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ tmp3 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ z2 = tmp0 + tmp2;
+ z3 = tmp1 + tmp3;
+
+ z1 = MULTIPLY(z2 + z3, FIX_1_175875602); /* sqrt(2) * c3 */
+ z2 = MULTIPLY(z2, - FIX_1_961570560); /* sqrt(2) * (-c3-c5) */
+ z3 = MULTIPLY(z3, - FIX_0_390180644); /* sqrt(2) * (c5-c3) */
+ z2 += z1;
+ z3 += z1;
+
+ z1 = MULTIPLY(tmp0 + tmp3, - FIX_0_899976223); /* sqrt(2) * (c7-c3) */
+ tmp0 = MULTIPLY(tmp0, FIX_0_298631336); /* sqrt(2) * (-c1+c3+c5-c7) */
+ tmp3 = MULTIPLY(tmp3, FIX_1_501321110); /* sqrt(2) * ( c1+c3-c5-c7) */
+ tmp0 += z1 + z2;
+ tmp3 += z1 + z3;
+
+ z1 = MULTIPLY(tmp1 + tmp2, - FIX_2_562915447); /* sqrt(2) * (-c1-c3) */
+ tmp1 = MULTIPLY(tmp1, FIX_2_053119869); /* sqrt(2) * ( c1+c3-c5+c7) */
+ tmp2 = MULTIPLY(tmp2, FIX_3_072711026); /* sqrt(2) * ( c1+c3+c5-c7) */
+ tmp1 += z1 + z3;
+ tmp2 += z1 + z2;
+
+ /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */
+
+ wsptr[4*0] = (int) RIGHT_SHIFT(tmp10 + tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[4*7] = (int) RIGHT_SHIFT(tmp10 - tmp3, CONST_BITS-PASS1_BITS);
+ wsptr[4*1] = (int) RIGHT_SHIFT(tmp11 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[4*6] = (int) RIGHT_SHIFT(tmp11 - tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[4*2] = (int) RIGHT_SHIFT(tmp12 + tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[4*5] = (int) RIGHT_SHIFT(tmp12 - tmp1, CONST_BITS-PASS1_BITS);
+ wsptr[4*3] = (int) RIGHT_SHIFT(tmp13 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[4*4] = (int) RIGHT_SHIFT(tmp13 - tmp0, CONST_BITS-PASS1_BITS);
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
+
+ /* Pass 2: process 8 rows from work array, store into output array.
+ * 4-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/16).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 8; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp2 = (INT32) wsptr[2];
+
+ tmp10 = (tmp0 + tmp2) << CONST_BITS;
+ tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = (INT32) wsptr[1];
+ z3 = (INT32) wsptr[3];
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+ tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[3] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp12 + tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp12 - tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 4; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a reduced-size 3x6 output block.
+ *
+ * 6-point IDCT in pass 1 (columns), 3-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_3x6 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp1, tmp2, tmp10, tmp11, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ int * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ int workspace[3*6]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 6-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/12).
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 3; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp0 <<= CONST_BITS;
+ /* Add fudge factor here for final descale. */
+ tmp0 += ONE << (CONST_BITS-PASS1_BITS-1);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
+ tmp10 = MULTIPLY(tmp2, FIX(0.707106781)); /* c4 */
+ tmp1 = tmp0 + tmp10;
+ tmp11 = RIGHT_SHIFT(tmp0 - tmp10 - tmp10, CONST_BITS-PASS1_BITS);
+ tmp10 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+ tmp0 = MULTIPLY(tmp10, FIX(1.224744871)); /* c2 */
+ tmp10 = tmp1 + tmp0;
+ tmp12 = tmp1 - tmp0;
+
+ /* Odd part */
+
+ z1 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z2 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
+ tmp1 = MULTIPLY(z1 + z3, FIX(0.366025404)); /* c5 */
+ tmp0 = tmp1 + ((z1 + z2) << CONST_BITS);
+ tmp2 = tmp1 + ((z3 - z2) << CONST_BITS);
+ tmp1 = (z1 - z2 - z3) << PASS1_BITS;
+
+ /* Final output stage */
+
+ wsptr[3*0] = (int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[3*5] = (int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS-PASS1_BITS);
+ wsptr[3*1] = (int) (tmp11 + tmp1);
+ wsptr[3*4] = (int) (tmp11 - tmp1);
+ wsptr[3*2] = (int) RIGHT_SHIFT(tmp12 + tmp2, CONST_BITS-PASS1_BITS);
+ wsptr[3*3] = (int) RIGHT_SHIFT(tmp12 - tmp2, CONST_BITS-PASS1_BITS);
+ }
+
+ /* Pass 2: process 6 rows from work array, store into output array.
+ * 3-point IDCT kernel, cK represents sqrt(2) * cos(K*pi/6).
+ */
+ wsptr = workspace;
+ for (ctr = 0; ctr < 6; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp0 = (INT32) wsptr[0] + (ONE << (PASS1_BITS+2));
+ tmp0 <<= CONST_BITS;
+ tmp2 = (INT32) wsptr[2];
+ tmp12 = MULTIPLY(tmp2, FIX(0.707106781)); /* c2 */
+ tmp10 = tmp0 + tmp12;
+ tmp2 = tmp0 - tmp12 - tmp12;
+
+ /* Odd part */
+
+ tmp12 = (INT32) wsptr[1];
+ tmp0 = MULTIPLY(tmp12, FIX(1.224744871)); /* c1 */
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[2] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp2,
+ CONST_BITS+PASS1_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 3; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 2x4 output block.
+ *
+ * 4-point IDCT in pass 1 (columns), 2-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_2x4 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp2, tmp10, tmp12;
+ INT32 z1, z2, z3;
+ JCOEFPTR inptr;
+ ISLOW_MULT_TYPE * quantptr;
+ INT32 * wsptr;
+ JSAMPROW outptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ int ctr;
+ INT32 workspace[2*4]; /* buffers data between passes */
+ SHIFT_TEMPS
+
+ /* Pass 1: process columns from input, store into work array.
+ * 4-point IDCT kernel,
+ * cK represents sqrt(2) * cos(K*pi/16) [refers to 8-point IDCT].
+ */
+ inptr = coef_block;
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+ wsptr = workspace;
+ for (ctr = 0; ctr < 2; ctr++, inptr++, quantptr++, wsptr++) {
+ /* Even part */
+
+ tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ tmp2 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
+
+ tmp10 = (tmp0 + tmp2) << CONST_BITS;
+ tmp12 = (tmp0 - tmp2) << CONST_BITS;
+
+ /* Odd part */
+ /* Same rotation as in the even part of the 8x8 LL&M IDCT */
+
+ z2 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
+ z3 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
+
+ z1 = MULTIPLY(z2 + z3, FIX_0_541196100); /* c6 */
+ tmp0 = z1 + MULTIPLY(z2, FIX_0_765366865); /* c2-c6 */
+ tmp2 = z1 - MULTIPLY(z3, FIX_1_847759065); /* c2+c6 */
+
+ /* Final output stage */
+
+ wsptr[2*0] = tmp10 + tmp0;
+ wsptr[2*3] = tmp10 - tmp0;
+ wsptr[2*1] = tmp12 + tmp2;
+ wsptr[2*2] = tmp12 - tmp2;
+ }
+
+ /* Pass 2: process 4 rows from work array, store into output array. */
+
+ wsptr = workspace;
+ for (ctr = 0; ctr < 4; ctr++) {
+ outptr = output_buf[ctr] + output_col;
+
+ /* Even part */
+
+ /* Add fudge factor here for final descale. */
+ tmp10 = wsptr[0] + (ONE << (CONST_BITS+2));
+
+ /* Odd part */
+
+ tmp0 = wsptr[1];
+
+ /* Final output stage */
+
+ outptr[0] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, CONST_BITS+3)
+ & RANGE_MASK];
+ outptr[1] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, CONST_BITS+3)
+ & RANGE_MASK];
+
+ wsptr += 2; /* advance pointer to next row */
+ }
+}
+
+
+/*
+ * Perform dequantization and inverse DCT on one block of coefficients,
+ * producing a 1x2 output block.
+ *
+ * 2-point IDCT in pass 1 (columns), 1-point in pass 2 (rows).
+ */
+
+GLOBAL(void)
+jpeg_idct_1x2 (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col)
+{
+ INT32 tmp0, tmp10;
+ ISLOW_MULT_TYPE * quantptr;
+ JSAMPLE *range_limit = IDCT_range_limit(cinfo);
+ SHIFT_TEMPS
+
+ /* Process 1 column from input, store into output array. */
+
+ quantptr = (ISLOW_MULT_TYPE *) compptr->dct_table;
+
+ /* Even part */
+
+ tmp10 = DEQUANTIZE(coef_block[DCTSIZE*0], quantptr[DCTSIZE*0]);
+ /* Add fudge factor here for final descale. */
+ tmp10 += ONE << 2;
+
+ /* Odd part */
+
+ tmp0 = DEQUANTIZE(coef_block[DCTSIZE*1], quantptr[DCTSIZE*1]);
+
+ /* Final output stage */
+
+ output_buf[0][output_col] = range_limit[(int) RIGHT_SHIFT(tmp10 + tmp0, 3)
+ & RANGE_MASK];
+ output_buf[1][output_col] = range_limit[(int) RIGHT_SHIFT(tmp10 - tmp0, 3)
+ & RANGE_MASK];
+}
+
+#endif /* IDCT_SCALING_SUPPORTED */
+#endif /* DCT_ISLOW_SUPPORTED */
diff --git a/jpg/jinclude.h b/jpg/jinclude.h
new file mode 100644
index 0000000..0a4f151
--- /dev/null
+++ b/jpg/jinclude.h
@@ -0,0 +1,91 @@
+/*
+ * jinclude.h
+ *
+ * Copyright (C) 1991-1994, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file exists to provide a single place to fix any problems with
+ * including the wrong system include files. (Common problems are taken
+ * care of by the standard jconfig symbols, but on really weird systems
+ * you may have to edit this file.)
+ *
+ * NOTE: this file is NOT intended to be included by applications using the
+ * JPEG library. Most applications need only include jpeglib.h.
+ */
+
+
+/* Include auto-config file to find out which system include files we need. */
+
+#include "jconfig.h" /* auto configuration options */
+#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */
+
+/*
+ * We need the NULL macro and size_t typedef.
+ * On an ANSI-conforming system it is sufficient to include <stddef.h>.
+ * Otherwise, we get them from <stdlib.h> or <stdio.h>; we may have to
+ * pull in <sys/types.h> as well.
+ * Note that the core JPEG library does not require <stdio.h>;
+ * only the default error handler and data source/destination modules do.
+ * But we must pull it in because of the references to FILE in jpeglib.h.
+ * You can remove those references if you want to compile without <stdio.h>.
+ */
+
+#ifdef HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef NEED_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+
+/*
+ * We need memory copying and zeroing functions, plus strncpy().
+ * ANSI and System V implementations declare these in <string.h>.
+ * BSD doesn't have the mem() functions, but it does have bcopy()/bzero().
+ * Some systems may declare memset and memcpy in <memory.h>.
+ *
+ * NOTE: we assume the size parameters to these functions are of type size_t.
+ * Change the casts in these macros if not!
+ */
+
+#ifdef NEED_BSD_STRINGS
+
+#include <strings.h>
+#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size))
+#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size))
+
+#else /* not BSD, assume ANSI/SysV string lib */
+
+#include <string.h>
+#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size))
+#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size))
+
+#endif
+
+/*
+ * In ANSI C, and indeed any rational implementation, size_t is also the
+ * type returned by sizeof(). However, it seems there are some irrational
+ * implementations out there, in which sizeof() returns an int even though
+ * size_t is defined as long or unsigned long. To ensure consistent results
+ * we always use this SIZEOF() macro in place of using sizeof() directly.
+ */
+
+#define SIZEOF(object) ((size_t) sizeof(object))
+
+/*
+ * The modules that use fread() and fwrite() always invoke them through
+ * these macros. On some systems you may need to twiddle the argument casts.
+ * CAUTION: argument order is different from underlying functions!
+ */
+
+#define JFREAD(file,buf,sizeofbuf) \
+ ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
+#define JFWRITE(file,buf,sizeofbuf) \
+ ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file)))
diff --git a/jpg/jmemansi.c b/jpg/jmemansi.c
new file mode 100644
index 0000000..2d93e49
--- /dev/null
+++ b/jpg/jmemansi.c
@@ -0,0 +1,167 @@
+/*
+ * jmemansi.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a simple generic implementation of the system-
+ * dependent portion of the JPEG memory manager. This implementation
+ * assumes that you have the ANSI-standard library routine tmpfile().
+ * Also, the problem of determining the amount of memory available
+ * is shoved onto the user.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
+#define SEEK_SET 0 /* if not, assume 0 is correct */
+#endif
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
+#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed. You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFREAD(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFWRITE(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ fclose(info->temp_file);
+ /* Since this implementation uses tmpfile() to create the file,
+ * no explicit file deletion is needed.
+ */
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ *
+ * This version uses tmpfile(), which constructs a suitable file name
+ * behind the scenes. We don't have to use info->temp_name[] at all;
+ * indeed, we can't even find out the actual name of the temp file.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ if ((info->temp_file = tmpfile()) == NULL)
+ ERREXITS(cinfo, JERR_TFILE_CREATE, "");
+ info->read_backing_store = read_backing_store;
+ info->write_backing_store = write_backing_store;
+ info->close_backing_store = close_backing_store;
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/jpg/jmemdos.c b/jpg/jmemdos.c
new file mode 100644
index 0000000..60b45c6
--- /dev/null
+++ b/jpg/jmemdos.c
@@ -0,0 +1,638 @@
+/*
+ * jmemdos.c
+ *
+ * Copyright (C) 1992-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides an MS-DOS-compatible implementation of the system-
+ * dependent portion of the JPEG memory manager. Temporary data can be
+ * stored in extended or expanded memory as well as in regular DOS files.
+ *
+ * If you use this file, you must be sure that NEED_FAR_POINTERS is defined
+ * if you compile in a small-data memory model; it should NOT be defined if
+ * you use a large-data memory model. This file is not recommended if you
+ * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
+ * Also, this code will NOT work if struct fields are aligned on greater than
+ * 2-byte boundaries.
+ *
+ * Based on code contributed by Ge' Weijers.
+ */
+
+/*
+ * If you have both extended and expanded memory, you may want to change the
+ * order in which they are tried in jopen_backing_store. On a 286 machine
+ * expanded memory is usually faster, since extended memory access involves
+ * an expensive protected-mode-and-back switch. On 386 and better, extended
+ * memory is usually faster. As distributed, the code tries extended memory
+ * first (what? not everyone has a 386? :-).
+ *
+ * You can disable use of extended/expanded memory entirely by altering these
+ * definitions or overriding them from the Makefile (eg, -DEMS_SUPPORTED=0).
+ */
+
+#ifndef XMS_SUPPORTED
+#define XMS_SUPPORTED 1
+#endif
+#ifndef EMS_SUPPORTED
+#define EMS_SUPPORTED 1
+#endif
+
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare these */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+extern char * getenv JPP((const char * name));
+#endif
+
+#ifdef NEED_FAR_POINTERS
+
+#ifdef __TURBOC__
+/* These definitions work for Borland C (Turbo C) */
+#include <alloc.h> /* need farmalloc(), farfree() */
+#define far_malloc(x) farmalloc(x)
+#define far_free(x) farfree(x)
+#else
+/* These definitions work for Microsoft C and compatible compilers */
+#include <malloc.h> /* need _fmalloc(), _ffree() */
+#define far_malloc(x) _fmalloc(x)
+#define far_free(x) _ffree(x)
+#endif
+
+#else /* not NEED_FAR_POINTERS */
+
+#define far_malloc(x) malloc(x)
+#define far_free(x) free(x)
+
+#endif /* NEED_FAR_POINTERS */
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#else
+#define READ_BINARY "rb"
+#endif
+
+#ifndef USE_MSDOS_MEMMGR /* make sure user got configuration right */
+ You forgot to define USE_MSDOS_MEMMGR in jconfig.h. /* deliberate syntax error */
+#endif
+
+#if MAX_ALLOC_CHUNK >= 65535L /* make sure jconfig.h got this right */
+ MAX_ALLOC_CHUNK should be less than 64K. /* deliberate syntax error */
+#endif
+
+
+/*
+ * Declarations for assembly-language support routines (see jmemdosa.asm).
+ *
+ * The functions are declared "far" as are all their pointer arguments;
+ * this ensures the assembly source code will work regardless of the
+ * compiler memory model. We assume "short" is 16 bits, "long" is 32.
+ */
+
+typedef void far * XMSDRIVER; /* actually a pointer to code */
+typedef struct { /* registers for calling XMS driver */
+ unsigned short ax, dx, bx;
+ void far * ds_si;
+ } XMScontext;
+typedef struct { /* registers for calling EMS driver */
+ unsigned short ax, dx, bx;
+ void far * ds_si;
+ } EMScontext;
+
+extern short far jdos_open JPP((short far * handle, char far * filename));
+extern short far jdos_close JPP((short handle));
+extern short far jdos_seek JPP((short handle, long offset));
+extern short far jdos_read JPP((short handle, void far * buffer,
+ unsigned short count));
+extern short far jdos_write JPP((short handle, void far * buffer,
+ unsigned short count));
+extern void far jxms_getdriver JPP((XMSDRIVER far *));
+extern void far jxms_calldriver JPP((XMSDRIVER, XMScontext far *));
+extern short far jems_available JPP((void));
+extern void far jems_calldriver JPP((EMScontext far *));
+
+
+/*
+ * Selection of a file name for a temporary file.
+ * This is highly system-dependent, and you may want to customize it.
+ */
+
+static int next_file_num; /* to distinguish among several temp files */
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+ const char * env;
+ char * ptr;
+ FILE * tfile;
+
+ /* Keep generating file names till we find one that's not in use */
+ for (;;) {
+ /* Get temp directory name from environment TMP or TEMP variable;
+ * if none, use "."
+ */
+ if ((env = (const char *) getenv("TMP")) == NULL)
+ if ((env = (const char *) getenv("TEMP")) == NULL)
+ env = ".";
+ if (*env == '\0') /* null string means "." */
+ env = ".";
+ ptr = fname; /* copy name to fname */
+ while (*env != '\0')
+ *ptr++ = *env++;
+ if (ptr[-1] != '\\' && ptr[-1] != '/')
+ *ptr++ = '\\'; /* append backslash if not in env variable */
+ /* Append a suitable file name */
+ next_file_num++; /* advance counter */
+ sprintf(ptr, "JPG%03d.TMP", next_file_num);
+ /* Probe to see if file name is already in use */
+ if ((tfile = fopen(fname, READ_BINARY)) == NULL)
+ break;
+ fclose(tfile); /* oops, it's there; close tfile & try again */
+ }
+}
+
+
+/*
+ * Near-memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are allocated in far memory, if possible
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) far_malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ far_free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
+#define DEFAULT_MAX_MEM 300000L /* for total usage about 450K */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed. You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+/*
+ * For MS-DOS we support three types of backing storage:
+ * 1. Conventional DOS files. We access these by direct DOS calls rather
+ * than via the stdio package. This provides a bit better performance,
+ * but the real reason is that the buffers to be read or written are FAR.
+ * The stdio library for small-data memory models can't cope with that.
+ * 2. Extended memory, accessed per the XMS V2.0 specification.
+ * 3. Expanded memory, accessed per the LIM/EMS 4.0 specification.
+ * You'll need copies of those specs to make sense of the related code.
+ * The specs are available by Internet FTP from the SIMTEL archives
+ * (oak.oakland.edu and its various mirror sites). See files
+ * pub/msdos/microsoft/xms20.arc and pub/msdos/info/limems41.zip.
+ */
+
+
+/*
+ * Access methods for a DOS file.
+ */
+
+
+METHODDEF(void)
+read_file_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (jdos_seek(info->handle.file_handle, file_offset))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
+ if (byte_count > 65535L) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+ if (jdos_read(info->handle.file_handle, buffer_address,
+ (unsigned short) byte_count))
+ ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_file_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (jdos_seek(info->handle.file_handle, file_offset))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ /* Since MAX_ALLOC_CHUNK is less than 64K, byte_count will be too. */
+ if (byte_count > 65535L) /* safety check */
+ ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+ if (jdos_write(info->handle.file_handle, buffer_address,
+ (unsigned short) byte_count))
+ ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_file_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ jdos_close(info->handle.file_handle); /* close the file */
+ remove(info->temp_name); /* delete the file */
+/* If your system doesn't have remove(), try unlink() instead.
+ * remove() is the ANSI-standard name for this function, but
+ * unlink() was more common in pre-ANSI systems.
+ */
+ TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
+}
+
+
+LOCAL(boolean)
+open_file_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ short handle;
+
+ select_file_name(info->temp_name);
+ if (jdos_open((short far *) & handle, (char far *) info->temp_name)) {
+ /* might as well exit since jpeg_open_backing_store will fail anyway */
+ ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+ return FALSE;
+ }
+ info->handle.file_handle = handle;
+ info->read_backing_store = read_file_store;
+ info->write_backing_store = write_file_store;
+ info->close_backing_store = close_file_store;
+ TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
+ return TRUE; /* succeeded */
+}
+
+
+/*
+ * Access methods for extended memory.
+ */
+
+#if XMS_SUPPORTED
+
+static XMSDRIVER xms_driver; /* saved address of XMS driver */
+
+typedef union { /* either long offset or real-mode pointer */
+ long offset;
+ void far * ptr;
+ } XMSPTR;
+
+typedef struct { /* XMS move specification structure */
+ long length;
+ XMSH src_handle;
+ XMSPTR src;
+ XMSH dst_handle;
+ XMSPTR dst;
+ } XMSspec;
+
+#define ODD(X) (((X) & 1L) != 0)
+
+
+METHODDEF(void)
+read_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ XMScontext ctx;
+ XMSspec spec;
+ char endbuffer[2];
+
+ /* The XMS driver can't cope with an odd length, so handle the last byte
+ * specially if byte_count is odd. We don't expect this to be common.
+ */
+
+ spec.length = byte_count & (~ 1L);
+ spec.src_handle = info->handle.xms_handle;
+ spec.src.offset = file_offset;
+ spec.dst_handle = 0;
+ spec.dst.ptr = buffer_address;
+
+ ctx.ds_si = (void far *) & spec;
+ ctx.ax = 0x0b00; /* EMB move */
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ if (ctx.ax != 1)
+ ERREXIT(cinfo, JERR_XMS_READ);
+
+ if (ODD(byte_count)) {
+ read_xms_store(cinfo, info, (void FAR *) endbuffer,
+ file_offset + byte_count - 1L, 2L);
+ ((char FAR *) buffer_address)[byte_count - 1L] = endbuffer[0];
+ }
+}
+
+
+METHODDEF(void)
+write_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ XMScontext ctx;
+ XMSspec spec;
+ char endbuffer[2];
+
+ /* The XMS driver can't cope with an odd length, so handle the last byte
+ * specially if byte_count is odd. We don't expect this to be common.
+ */
+
+ spec.length = byte_count & (~ 1L);
+ spec.src_handle = 0;
+ spec.src.ptr = buffer_address;
+ spec.dst_handle = info->handle.xms_handle;
+ spec.dst.offset = file_offset;
+
+ ctx.ds_si = (void far *) & spec;
+ ctx.ax = 0x0b00; /* EMB move */
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ if (ctx.ax != 1)
+ ERREXIT(cinfo, JERR_XMS_WRITE);
+
+ if (ODD(byte_count)) {
+ read_xms_store(cinfo, info, (void FAR *) endbuffer,
+ file_offset + byte_count - 1L, 2L);
+ endbuffer[0] = ((char FAR *) buffer_address)[byte_count - 1L];
+ write_xms_store(cinfo, info, (void FAR *) endbuffer,
+ file_offset + byte_count - 1L, 2L);
+ }
+}
+
+
+METHODDEF(void)
+close_xms_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ XMScontext ctx;
+
+ ctx.dx = info->handle.xms_handle;
+ ctx.ax = 0x0a00;
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ TRACEMS1(cinfo, 1, JTRC_XMS_CLOSE, info->handle.xms_handle);
+ /* we ignore any error return from the driver */
+}
+
+
+LOCAL(boolean)
+open_xms_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ XMScontext ctx;
+
+ /* Get address of XMS driver */
+ jxms_getdriver((XMSDRIVER far *) & xms_driver);
+ if (xms_driver == NULL)
+ return FALSE; /* no driver to be had */
+
+ /* Get version number, must be >= 2.00 */
+ ctx.ax = 0x0000;
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ if (ctx.ax < (unsigned short) 0x0200)
+ return FALSE;
+
+ /* Try to get space (expressed in kilobytes) */
+ ctx.dx = (unsigned short) ((total_bytes_needed + 1023L) >> 10);
+ ctx.ax = 0x0900;
+ jxms_calldriver(xms_driver, (XMScontext far *) & ctx);
+ if (ctx.ax != 1)
+ return FALSE;
+
+ /* Succeeded, save the handle and away we go */
+ info->handle.xms_handle = ctx.dx;
+ info->read_backing_store = read_xms_store;
+ info->write_backing_store = write_xms_store;
+ info->close_backing_store = close_xms_store;
+ TRACEMS1(cinfo, 1, JTRC_XMS_OPEN, ctx.dx);
+ return TRUE; /* succeeded */
+}
+
+#endif /* XMS_SUPPORTED */
+
+
+/*
+ * Access methods for expanded memory.
+ */
+
+#if EMS_SUPPORTED
+
+/* The EMS move specification structure requires word and long fields aligned
+ * at odd byte boundaries. Some compilers will align struct fields at even
+ * byte boundaries. While it's usually possible to force byte alignment,
+ * that causes an overall performance penalty and may pose problems in merging
+ * JPEG into a larger application. Instead we accept some rather dirty code
+ * here. Note this code would fail if the hardware did not allow odd-byte
+ * word & long accesses, but all 80x86 CPUs do.
+ */
+
+typedef void far * EMSPTR;
+
+typedef union { /* EMS move specification structure */
+ long length; /* It's easy to access first 4 bytes */
+ char bytes[18]; /* Misaligned fields in here! */
+ } EMSspec;
+
+/* Macros for accessing misaligned fields */
+#define FIELD_AT(spec,offset,type) (*((type *) &(spec.bytes[offset])))
+#define SRC_TYPE(spec) FIELD_AT(spec,4,char)
+#define SRC_HANDLE(spec) FIELD_AT(spec,5,EMSH)
+#define SRC_OFFSET(spec) FIELD_AT(spec,7,unsigned short)
+#define SRC_PAGE(spec) FIELD_AT(spec,9,unsigned short)
+#define SRC_PTR(spec) FIELD_AT(spec,7,EMSPTR)
+#define DST_TYPE(spec) FIELD_AT(spec,11,char)
+#define DST_HANDLE(spec) FIELD_AT(spec,12,EMSH)
+#define DST_OFFSET(spec) FIELD_AT(spec,14,unsigned short)
+#define DST_PAGE(spec) FIELD_AT(spec,16,unsigned short)
+#define DST_PTR(spec) FIELD_AT(spec,14,EMSPTR)
+
+#define EMSPAGESIZE 16384L /* gospel, see the EMS specs */
+
+#define HIBYTE(W) (((W) >> 8) & 0xFF)
+#define LOBYTE(W) ((W) & 0xFF)
+
+
+METHODDEF(void)
+read_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ EMScontext ctx;
+ EMSspec spec;
+
+ spec.length = byte_count;
+ SRC_TYPE(spec) = 1;
+ SRC_HANDLE(spec) = info->handle.ems_handle;
+ SRC_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE);
+ SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
+ DST_TYPE(spec) = 0;
+ DST_HANDLE(spec) = 0;
+ DST_PTR(spec) = buffer_address;
+
+ ctx.ds_si = (void far *) & spec;
+ ctx.ax = 0x5700; /* move memory region */
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0)
+ ERREXIT(cinfo, JERR_EMS_READ);
+}
+
+
+METHODDEF(void)
+write_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ EMScontext ctx;
+ EMSspec spec;
+
+ spec.length = byte_count;
+ SRC_TYPE(spec) = 0;
+ SRC_HANDLE(spec) = 0;
+ SRC_PTR(spec) = buffer_address;
+ DST_TYPE(spec) = 1;
+ DST_HANDLE(spec) = info->handle.ems_handle;
+ DST_PAGE(spec) = (unsigned short) (file_offset / EMSPAGESIZE);
+ DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
+
+ ctx.ds_si = (void far *) & spec;
+ ctx.ax = 0x5700; /* move memory region */
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0)
+ ERREXIT(cinfo, JERR_EMS_WRITE);
+}
+
+
+METHODDEF(void)
+close_ems_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ EMScontext ctx;
+
+ ctx.ax = 0x4500;
+ ctx.dx = info->handle.ems_handle;
+ jems_calldriver((EMScontext far *) & ctx);
+ TRACEMS1(cinfo, 1, JTRC_EMS_CLOSE, info->handle.ems_handle);
+ /* we ignore any error return from the driver */
+}
+
+
+LOCAL(boolean)
+open_ems_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ EMScontext ctx;
+
+ /* Is EMS driver there? */
+ if (! jems_available())
+ return FALSE;
+
+ /* Get status, make sure EMS is OK */
+ ctx.ax = 0x4000;
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0)
+ return FALSE;
+
+ /* Get version, must be >= 4.0 */
+ ctx.ax = 0x4600;
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0 || LOBYTE(ctx.ax) < 0x40)
+ return FALSE;
+
+ /* Try to allocate requested space */
+ ctx.ax = 0x4300;
+ ctx.bx = (unsigned short) ((total_bytes_needed + EMSPAGESIZE-1L) / EMSPAGESIZE);
+ jems_calldriver((EMScontext far *) & ctx);
+ if (HIBYTE(ctx.ax) != 0)
+ return FALSE;
+
+ /* Succeeded, save the handle and away we go */
+ info->handle.ems_handle = ctx.dx;
+ info->read_backing_store = read_ems_store;
+ info->write_backing_store = write_ems_store;
+ info->close_backing_store = close_ems_store;
+ TRACEMS1(cinfo, 1, JTRC_EMS_OPEN, ctx.dx);
+ return TRUE; /* succeeded */
+}
+
+#endif /* EMS_SUPPORTED */
+
+
+/*
+ * Initial opening of a backing-store object.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ /* Try extended memory, then expanded memory, then regular file. */
+#if XMS_SUPPORTED
+ if (open_xms_store(cinfo, info, total_bytes_needed))
+ return;
+#endif
+#if EMS_SUPPORTED
+ if (open_ems_store(cinfo, info, total_bytes_needed))
+ return;
+#endif
+ if (open_file_store(cinfo, info, total_bytes_needed))
+ return;
+ ERREXITS(cinfo, JERR_TFILE_CREATE, "");
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ next_file_num = 0; /* initialize temp file name generator */
+ return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* Microsoft C, at least in v6.00A, will not successfully reclaim freed
+ * blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
+ */
+#ifdef NEED_FHEAPMIN
+ _fheapmin();
+#endif
+}
diff --git a/jpg/jmemdosa.asm b/jpg/jmemdosa.asm
new file mode 100644
index 0000000..ecd4372
--- /dev/null
+++ b/jpg/jmemdosa.asm
@@ -0,0 +1,379 @@
+;
+; jmemdosa.asm
+;
+; Copyright (C) 1992, Thomas G. Lane.
+; This file is part of the Independent JPEG Group's software.
+; For conditions of distribution and use, see the accompanying README file.
+;
+; This file contains low-level interface routines to support the MS-DOS
+; backing store manager (jmemdos.c). Routines are provided to access disk
+; files through direct DOS calls, and to access XMS and EMS drivers.
+;
+; This file should assemble with Microsoft's MASM or any compatible
+; assembler (including Borland's Turbo Assembler). If you haven't got
+; a compatible assembler, better fall back to jmemansi.c or jmemname.c.
+;
+; To minimize dependence on the C compiler's register usage conventions,
+; we save and restore all 8086 registers, even though most compilers only
+; require SI,DI,DS to be preserved. Also, we use only 16-bit-wide return
+; values, which everybody returns in AX.
+;
+; Based on code contributed by Ge' Weijers.
+;
+
+JMEMDOSA_TXT segment byte public 'CODE'
+
+ assume cs:JMEMDOSA_TXT
+
+ public _jdos_open
+ public _jdos_close
+ public _jdos_seek
+ public _jdos_read
+ public _jdos_write
+ public _jxms_getdriver
+ public _jxms_calldriver
+ public _jems_available
+ public _jems_calldriver
+
+;
+; short far jdos_open (short far * handle, char far * filename)
+;
+; Create and open a temporary file
+;
+_jdos_open proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov cx,0 ; normal file attributes
+ lds dx,dword ptr [bp+10] ; get filename pointer
+ mov ah,3ch ; create file
+ int 21h
+ jc open_err ; if failed, return error code
+ lds bx,dword ptr [bp+6] ; get handle pointer
+ mov word ptr [bx],ax ; save the handle
+ xor ax,ax ; return zero for OK
+open_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_open endp
+
+
+;
+; short far jdos_close (short handle)
+;
+; Close the file handle
+;
+_jdos_close proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov bx,word ptr [bp+6] ; file handle
+ mov ah,3eh ; close file
+ int 21h
+ jc close_err ; if failed, return error code
+ xor ax,ax ; return zero for OK
+close_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_close endp
+
+
+;
+; short far jdos_seek (short handle, long offset)
+;
+; Set file position
+;
+_jdos_seek proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov bx,word ptr [bp+6] ; file handle
+ mov dx,word ptr [bp+8] ; LS offset
+ mov cx,word ptr [bp+10] ; MS offset
+ mov ax,4200h ; absolute seek
+ int 21h
+ jc seek_err ; if failed, return error code
+ xor ax,ax ; return zero for OK
+seek_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_seek endp
+
+
+;
+; short far jdos_read (short handle, void far * buffer, unsigned short count)
+;
+; Read from file
+;
+_jdos_read proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov bx,word ptr [bp+6] ; file handle
+ lds dx,dword ptr [bp+8] ; buffer address
+ mov cx,word ptr [bp+12] ; number of bytes
+ mov ah,3fh ; read file
+ int 21h
+ jc read_err ; if failed, return error code
+ cmp ax,word ptr [bp+12] ; make sure all bytes were read
+ je read_ok
+ mov ax,1 ; else return 1 for not OK
+ jmp short read_err
+read_ok: xor ax,ax ; return zero for OK
+read_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_read endp
+
+
+;
+; short far jdos_write (short handle, void far * buffer, unsigned short count)
+;
+; Write to file
+;
+_jdos_write proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov bx,word ptr [bp+6] ; file handle
+ lds dx,dword ptr [bp+8] ; buffer address
+ mov cx,word ptr [bp+12] ; number of bytes
+ mov ah,40h ; write file
+ int 21h
+ jc write_err ; if failed, return error code
+ cmp ax,word ptr [bp+12] ; make sure all bytes written
+ je write_ok
+ mov ax,1 ; else return 1 for not OK
+ jmp short write_err
+write_ok: xor ax,ax ; return zero for OK
+write_err: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jdos_write endp
+
+
+;
+; void far jxms_getdriver (XMSDRIVER far *)
+;
+; Get the address of the XMS driver, or NULL if not available
+;
+_jxms_getdriver proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov ax,4300h ; call multiplex interrupt with
+ int 2fh ; a magic cookie, hex 4300
+ cmp al,80h ; AL should contain hex 80
+ je xmsavail
+ xor dx,dx ; no XMS driver available
+ xor ax,ax ; return a nil pointer
+ jmp short xmsavail_done
+xmsavail: mov ax,4310h ; fetch driver address with
+ int 2fh ; another magic cookie
+ mov dx,es ; copy address to dx:ax
+ mov ax,bx
+xmsavail_done: les bx,dword ptr [bp+6] ; get pointer to return value
+ mov word ptr es:[bx],ax
+ mov word ptr es:[bx+2],dx
+ pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jxms_getdriver endp
+
+
+;
+; void far jxms_calldriver (XMSDRIVER, XMScontext far *)
+;
+; The XMScontext structure contains values for the AX,DX,BX,SI,DS registers.
+; These are loaded, the XMS call is performed, and the new values of the
+; AX,DX,BX registers are written back to the context structure.
+;
+_jxms_calldriver proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ les bx,dword ptr [bp+10] ; get XMScontext pointer
+ mov ax,word ptr es:[bx] ; load registers
+ mov dx,word ptr es:[bx+2]
+ mov si,word ptr es:[bx+6]
+ mov ds,word ptr es:[bx+8]
+ mov bx,word ptr es:[bx+4]
+ call dword ptr [bp+6] ; call the driver
+ mov cx,bx ; save returned BX for a sec
+ les bx,dword ptr [bp+10] ; get XMScontext pointer
+ mov word ptr es:[bx],ax ; put back ax,dx,bx
+ mov word ptr es:[bx+2],dx
+ mov word ptr es:[bx+4],cx
+ pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jxms_calldriver endp
+
+
+;
+; short far jems_available (void)
+;
+; Have we got an EMS driver? (this comes straight from the EMS 4.0 specs)
+;
+_jems_available proc far
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ mov ax,3567h ; get interrupt vector 67h
+ int 21h
+ push cs
+ pop ds
+ mov di,000ah ; check offs 10 in returned seg
+ lea si,ASCII_device_name ; against literal string
+ mov cx,8
+ cld
+ repe cmpsb
+ jne no_ems
+ mov ax,1 ; match, it's there
+ jmp short avail_done
+no_ems: xor ax,ax ; it's not there
+avail_done: pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ ret
+
+ASCII_device_name db "EMMXXXX0"
+
+_jems_available endp
+
+
+;
+; void far jems_calldriver (EMScontext far *)
+;
+; The EMScontext structure contains values for the AX,DX,BX,SI,DS registers.
+; These are loaded, the EMS trap is performed, and the new values of the
+; AX,DX,BX registers are written back to the context structure.
+;
+_jems_calldriver proc far
+ push bp ; linkage
+ mov bp,sp
+ push si ; save all registers for safety
+ push di
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ les bx,dword ptr [bp+6] ; get EMScontext pointer
+ mov ax,word ptr es:[bx] ; load registers
+ mov dx,word ptr es:[bx+2]
+ mov si,word ptr es:[bx+6]
+ mov ds,word ptr es:[bx+8]
+ mov bx,word ptr es:[bx+4]
+ int 67h ; call the EMS driver
+ mov cx,bx ; save returned BX for a sec
+ les bx,dword ptr [bp+6] ; get EMScontext pointer
+ mov word ptr es:[bx],ax ; put back ax,dx,bx
+ mov word ptr es:[bx+2],dx
+ mov word ptr es:[bx+4],cx
+ pop ds ; restore registers and exit
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop di
+ pop si
+ pop bp
+ ret
+_jems_calldriver endp
+
+JMEMDOSA_TXT ends
+
+ end
diff --git a/jpg/jmemmac.c b/jpg/jmemmac.c
new file mode 100644
index 0000000..106f9be
--- /dev/null
+++ b/jpg/jmemmac.c
@@ -0,0 +1,289 @@
+/*
+ * jmemmac.c
+ *
+ * Copyright (C) 1992-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * jmemmac.c provides an Apple Macintosh implementation of the system-
+ * dependent portion of the JPEG memory manager.
+ *
+ * If you use jmemmac.c, then you must define USE_MAC_MEMMGR in the
+ * JPEG_INTERNALS part of jconfig.h.
+ *
+ * jmemmac.c uses the Macintosh toolbox routines NewPtr and DisposePtr
+ * instead of malloc and free. It accurately determines the amount of
+ * memory available by using CompactMem. Notice that if left to its
+ * own devices, this code can chew up all available space in the
+ * application's zone, with the exception of the rather small "slop"
+ * factor computed in jpeg_mem_available(). The application can ensure
+ * that more space is left over by reducing max_memory_to_use.
+ *
+ * Large images are swapped to disk using temporary files and System 7.0+'s
+ * temporary folder functionality.
+ *
+ * Note that jmemmac.c depends on two features of MacOS that were first
+ * introduced in System 7: FindFolder and the FSSpec-based calls.
+ * If your application uses jmemmac.c and is run under System 6 or earlier,
+ * and the jpeg library decides it needs a temporary file, it will abort,
+ * printing error messages about requiring System 7. (If no temporary files
+ * are created, it will run fine.)
+ *
+ * If you want to use jmemmac.c in an application that might be used with
+ * System 6 or earlier, then you should remove dependencies on FindFolder
+ * and the FSSpec calls. You will need to replace FindFolder with some
+ * other mechanism for finding a place to put temporary files, and you
+ * should replace the FSSpec calls with their HFS equivalents:
+ *
+ * FSpDelete -> HDelete
+ * FSpGetFInfo -> HGetFInfo
+ * FSpCreate -> HCreate
+ * FSpOpenDF -> HOpen *** Note: not HOpenDF ***
+ * FSMakeFSSpec -> (fill in spec by hand.)
+ *
+ * (Use HOpen instead of HOpenDF. HOpen is just a glue-interface to PBHOpen,
+ * which is on all HFS macs. HOpenDF is a System 7 addition which avoids the
+ * ages-old problem of names starting with a period.)
+ *
+ * Contributed by Sam Bushell (jsam@iagu.on.net) and
+ * Dan Gildor (gyld@in-touch.com).
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef USE_MAC_MEMMGR /* make sure user got configuration right */
+ You forgot to define USE_MAC_MEMMGR in jconfig.h. /* deliberate syntax error */
+#endif
+
+#include <Memory.h> /* we use the MacOS memory manager */
+#include <Files.h> /* we use the MacOS File stuff */
+#include <Folders.h> /* we use the MacOS HFS stuff */
+#include <Script.h> /* for smSystemScript */
+#include <Gestalt.h> /* we use Gestalt to test for specific functionality */
+
+#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
+#define TEMP_FILE_NAME "JPG%03d.TMP"
+#endif
+
+static int next_file_num; /* to distinguish among several temp files */
+
+
+/*
+ * Memory allocation and freeing are controlled by the MacOS library
+ * routines NewPtr() and DisposePtr(), which allocate fixed-address
+ * storage. Unfortunately, the IJG library isn't smart enough to cope
+ * with relocatable storage.
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) NewPtr(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ DisposePtr((Ptr) object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: we include FAR keywords in the routine declarations simply for
+ * consistency with the rest of the IJG code; FAR should expand to empty
+ * on rational architectures like the Mac.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) NewPtr(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ DisposePtr((Ptr) object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ */
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ long limit = cinfo->mem->max_memory_to_use - already_allocated;
+ long slop, mem;
+
+ /* Don't ask for more than what application has told us we may use */
+ if (max_bytes_needed > limit && limit > 0)
+ max_bytes_needed = limit;
+ /* Find whether there's a big enough free block in the heap.
+ * CompactMem tries to create a contiguous block of the requested size,
+ * and then returns the size of the largest free block (which could be
+ * much more or much less than we asked for).
+ * We add some slop to ensure we don't use up all available memory.
+ */
+ slop = max_bytes_needed / 16 + 32768L;
+ mem = CompactMem(max_bytes_needed + slop) - slop;
+ if (mem < 0)
+ mem = 0; /* sigh, couldn't even get the slop */
+ /* Don't take more than the application says we can have */
+ if (mem > limit && limit > 0)
+ mem = limit;
+ return mem;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed. You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ long bytes = byte_count;
+ long retVal;
+
+ if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+
+ retVal = FSRead ( info->temp_file, &bytes,
+ (unsigned char *) buffer_address );
+ if ( retVal != noErr || bytes != byte_count )
+ ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ long bytes = byte_count;
+ long retVal;
+
+ if ( SetFPos ( info->temp_file, fsFromStart, file_offset ) != noErr )
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+
+ retVal = FSWrite ( info->temp_file, &bytes,
+ (unsigned char *) buffer_address );
+ if ( retVal != noErr || bytes != byte_count )
+ ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ FSClose ( info->temp_file );
+ FSpDelete ( &(info->tempSpec) );
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ *
+ * This version uses FindFolder to find the Temporary Items folder,
+ * and puts the temporary file in there.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ short tmpRef, vRefNum;
+ long dirID;
+ FInfo finderInfo;
+ FSSpec theSpec;
+ Str255 fName;
+ OSErr osErr;
+ long gestaltResponse = 0;
+
+ /* Check that FSSpec calls are available. */
+ osErr = Gestalt( gestaltFSAttr, &gestaltResponse );
+ if ( ( osErr != noErr )
+ || !( gestaltResponse & (1<<gestaltHasFSSpecCalls) ) )
+ ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required");
+ /* TO DO: add a proper error message to jerror.h. */
+
+ /* Check that FindFolder is available. */
+ osErr = Gestalt( gestaltFindFolderAttr, &gestaltResponse );
+ if ( ( osErr != noErr )
+ || !( gestaltResponse & (1<<gestaltFindFolderPresent) ) )
+ ERREXITS(cinfo, JERR_TFILE_CREATE, "- System 7.0 or later required.");
+ /* TO DO: add a proper error message to jerror.h. */
+
+ osErr = FindFolder ( kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
+ &vRefNum, &dirID );
+ if ( osErr != noErr )
+ ERREXITS(cinfo, JERR_TFILE_CREATE, "- temporary items folder unavailable");
+ /* TO DO: Try putting the temp files somewhere else. */
+
+ /* Keep generating file names till we find one that's not in use */
+ for (;;) {
+ next_file_num++; /* advance counter */
+
+ sprintf(info->temp_name, TEMP_FILE_NAME, next_file_num);
+ strcpy ( (Ptr)fName+1, info->temp_name );
+ *fName = strlen (info->temp_name);
+ osErr = FSMakeFSSpec ( vRefNum, dirID, fName, &theSpec );
+
+ if ( (osErr = FSpGetFInfo ( &theSpec, &finderInfo ) ) != noErr )
+ break;
+ }
+
+ osErr = FSpCreate ( &theSpec, '????', '????', smSystemScript );
+ if ( osErr != noErr )
+ ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+
+ osErr = FSpOpenDF ( &theSpec, fsRdWrPerm, &(info->temp_file) );
+ if ( osErr != noErr )
+ ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+
+ info->tempSpec = theSpec;
+
+ info->read_backing_store = read_backing_store;
+ info->write_backing_store = write_backing_store;
+ info->close_backing_store = close_backing_store;
+ TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ next_file_num = 0;
+
+ /* max_memory_to_use will be initialized to FreeMem()'s result;
+ * the calling application might later reduce it, for example
+ * to leave room to invoke multiple JPEG objects.
+ * Note that FreeMem returns the total number of free bytes;
+ * it may not be possible to allocate a single block of this size.
+ */
+ return FreeMem();
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/jpg/jmemmgr.c b/jpg/jmemmgr.c
new file mode 100644
index 0000000..f0e83fb
--- /dev/null
+++ b/jpg/jmemmgr.c
@@ -0,0 +1,1119 @@
+/*
+ * jmemmgr.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains the JPEG system-independent memory management
+ * routines. This code is usable across a wide variety of machines; most
+ * of the system dependencies have been isolated in a separate file.
+ * The major functions provided here are:
+ * * pool-based allocation and freeing of memory;
+ * * policy decisions about how to divide available memory among the
+ * virtual arrays;
+ * * control logic for swapping virtual arrays between main memory and
+ * backing storage.
+ * The separate system-dependent file provides the actual backing-storage
+ * access code, and it contains the policy decision about how much total
+ * main memory to use.
+ * This file is system-dependent in the sense that some of its functions
+ * are unnecessary in some systems. For example, if there is enough virtual
+ * memory so that backing storage will never be used, much of the virtual
+ * array control logic could be removed. (Of course, if you have that much
+ * memory then you shouldn't care about a little bit of unused code...)
+ */
+
+#define JPEG_INTERNALS
+#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef NO_GETENV
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare getenv() */
+extern char * getenv JPP((const char * name));
+#endif
+#endif
+
+
+/*
+ * Some important notes:
+ * The allocation routines provided here must never return NULL.
+ * They should exit to error_exit if unsuccessful.
+ *
+ * It's not a good idea to try to merge the sarray and barray routines,
+ * even though they are textually almost the same, because samples are
+ * usually stored as bytes while coefficients are shorts or ints. Thus,
+ * in machines where byte pointers have a different representation from
+ * word pointers, the resulting machine code could not be the same.
+ */
+
+
+/*
+ * Many machines require storage alignment: longs must start on 4-byte
+ * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
+ * always returns pointers that are multiples of the worst-case alignment
+ * requirement, and we had better do so too.
+ * There isn't any really portable way to determine the worst-case alignment
+ * requirement. This module assumes that the alignment requirement is
+ * multiples of sizeof(ALIGN_TYPE).
+ * By default, we define ALIGN_TYPE as double. This is necessary on some
+ * workstations (where doubles really do need 8-byte alignment) and will work
+ * fine on nearly everything. If your machine has lesser alignment needs,
+ * you can save a few bytes by making ALIGN_TYPE smaller.
+ * The only place I know of where this will NOT work is certain Macintosh
+ * 680x0 compilers that define double as a 10-byte IEEE extended float.
+ * Doing 10-byte alignment is counterproductive because longwords won't be
+ * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have
+ * such a compiler.
+ */
+
+#ifndef ALIGN_TYPE /* so can override from jconfig.h */
+#define ALIGN_TYPE double
+#endif
+
+
+/*
+ * We allocate objects from "pools", where each pool is gotten with a single
+ * request to jpeg_get_small() or jpeg_get_large(). There is no per-object
+ * overhead within a pool, except for alignment padding. Each pool has a
+ * header with a link to the next pool of the same class.
+ * Small and large pool headers are identical except that the latter's
+ * link pointer must be FAR on 80x86 machines.
+ * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
+ * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
+ * of the alignment requirement of ALIGN_TYPE.
+ */
+
+typedef union small_pool_struct * small_pool_ptr;
+
+typedef union small_pool_struct {
+ struct {
+ small_pool_ptr next; /* next in list of pools */
+ size_t bytes_used; /* how many bytes already used within pool */
+ size_t bytes_left; /* bytes still available in this pool */
+ } hdr;
+ ALIGN_TYPE dummy; /* included in union to ensure alignment */
+} small_pool_hdr;
+
+typedef union large_pool_struct FAR * large_pool_ptr;
+
+typedef union large_pool_struct {
+ struct {
+ large_pool_ptr next; /* next in list of pools */
+ size_t bytes_used; /* how many bytes already used within pool */
+ size_t bytes_left; /* bytes still available in this pool */
+ } hdr;
+ ALIGN_TYPE dummy; /* included in union to ensure alignment */
+} large_pool_hdr;
+
+
+/*
+ * Here is the full definition of a memory manager object.
+ */
+
+typedef struct {
+ struct jpeg_memory_mgr pub; /* public fields */
+
+ /* Each pool identifier (lifetime class) names a linked list of pools. */
+ small_pool_ptr small_list[JPOOL_NUMPOOLS];
+ large_pool_ptr large_list[JPOOL_NUMPOOLS];
+
+ /* Since we only have one lifetime class of virtual arrays, only one
+ * linked list is necessary (for each datatype). Note that the virtual
+ * array control blocks being linked together are actually stored somewhere
+ * in the small-pool list.
+ */
+ jvirt_sarray_ptr virt_sarray_list;
+ jvirt_barray_ptr virt_barray_list;
+
+ /* This counts total space obtained from jpeg_get_small/large */
+ long total_space_allocated;
+
+ /* alloc_sarray and alloc_barray set this value for use by virtual
+ * array routines.
+ */
+ JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */
+} my_memory_mgr;
+
+typedef my_memory_mgr * my_mem_ptr;
+
+
+/*
+ * The control blocks for virtual arrays.
+ * Note that these blocks are allocated in the "small" pool area.
+ * System-dependent info for the associated backing store (if any) is hidden
+ * inside the backing_store_info struct.
+ */
+
+struct jvirt_sarray_control {
+ JSAMPARRAY mem_buffer; /* => the in-memory buffer */
+ JDIMENSION rows_in_array; /* total virtual array height */
+ JDIMENSION samplesperrow; /* width of array (and of memory buffer) */
+ JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */
+ JDIMENSION rows_in_mem; /* height of memory buffer */
+ JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
+ JDIMENSION cur_start_row; /* first logical row # in the buffer */
+ JDIMENSION first_undef_row; /* row # of first uninitialized row */
+ boolean pre_zero; /* pre-zero mode requested? */
+ boolean dirty; /* do current buffer contents need written? */
+ boolean b_s_open; /* is backing-store data valid? */
+ jvirt_sarray_ptr next; /* link to next virtual sarray control block */
+ backing_store_info b_s_info; /* System-dependent control info */
+};
+
+struct jvirt_barray_control {
+ JBLOCKARRAY mem_buffer; /* => the in-memory buffer */
+ JDIMENSION rows_in_array; /* total virtual array height */
+ JDIMENSION blocksperrow; /* width of array (and of memory buffer) */
+ JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */
+ JDIMENSION rows_in_mem; /* height of memory buffer */
+ JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */
+ JDIMENSION cur_start_row; /* first logical row # in the buffer */
+ JDIMENSION first_undef_row; /* row # of first uninitialized row */
+ boolean pre_zero; /* pre-zero mode requested? */
+ boolean dirty; /* do current buffer contents need written? */
+ boolean b_s_open; /* is backing-store data valid? */
+ jvirt_barray_ptr next; /* link to next virtual barray control block */
+ backing_store_info b_s_info; /* System-dependent control info */
+};
+
+
+#ifdef MEM_STATS /* optional extra stuff for statistics */
+
+LOCAL(void)
+print_mem_stats (j_common_ptr cinfo, int pool_id)
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr shdr_ptr;
+ large_pool_ptr lhdr_ptr;
+
+ /* Since this is only a debugging stub, we can cheat a little by using
+ * fprintf directly rather than going through the trace message code.
+ * This is helpful because message parm array can't handle longs.
+ */
+ fprintf(stderr, "Freeing pool %d, total space = %ld\n",
+ pool_id, mem->total_space_allocated);
+
+ for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL;
+ lhdr_ptr = lhdr_ptr->hdr.next) {
+ fprintf(stderr, " Large chunk used %ld\n",
+ (long) lhdr_ptr->hdr.bytes_used);
+ }
+
+ for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL;
+ shdr_ptr = shdr_ptr->hdr.next) {
+ fprintf(stderr, " Small chunk used %ld free %ld\n",
+ (long) shdr_ptr->hdr.bytes_used,
+ (long) shdr_ptr->hdr.bytes_left);
+ }
+}
+
+#endif /* MEM_STATS */
+
+
+LOCAL(void)
+out_of_memory (j_common_ptr cinfo, int which)
+/* Report an out-of-memory error and stop execution */
+/* If we compiled MEM_STATS support, report alloc requests before dying */
+{
+#ifdef MEM_STATS
+ cinfo->err->trace_level = 2; /* force self_destruct to report stats */
+#endif
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);
+}
+
+
+/*
+ * Allocation of "small" objects.
+ *
+ * For these, we use pooled storage. When a new pool must be created,
+ * we try to get enough space for the current request plus a "slop" factor,
+ * where the slop will be the amount of leftover space in the new pool.
+ * The speed vs. space tradeoff is largely determined by the slop values.
+ * A different slop value is provided for each pool class (lifetime),
+ * and we also distinguish the first pool of a class from later ones.
+ * NOTE: the values given work fairly well on both 16- and 32-bit-int
+ * machines, but may be too small if longs are 64 bits or more.
+ */
+
+static const size_t first_pool_slop[JPOOL_NUMPOOLS] =
+{
+ 1600, /* first PERMANENT pool */
+ 16000 /* first IMAGE pool */
+};
+
+static const size_t extra_pool_slop[JPOOL_NUMPOOLS] =
+{
+ 0, /* additional PERMANENT pools */
+ 5000 /* additional IMAGE pools */
+};
+
+#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */
+
+
+METHODDEF(void *)
+alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
+/* Allocate a "small" object */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr hdr_ptr, prev_hdr_ptr;
+ char * data_ptr;
+ size_t odd_bytes, min_request, slop;
+
+ /* Check for unsatisfiable request (do now to ensure no overflow below) */
+ if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr)))
+ out_of_memory(cinfo, 1); /* request exceeds malloc's ability */
+
+ /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
+ odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
+ if (odd_bytes > 0)
+ sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
+
+ /* See if space is available in any existing pool */
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+ prev_hdr_ptr = NULL;
+ hdr_ptr = mem->small_list[pool_id];
+ while (hdr_ptr != NULL) {
+ if (hdr_ptr->hdr.bytes_left >= sizeofobject)
+ break; /* found pool with enough space */
+ prev_hdr_ptr = hdr_ptr;
+ hdr_ptr = hdr_ptr->hdr.next;
+ }
+
+ /* Time to make a new pool? */
+ if (hdr_ptr == NULL) {
+ /* min_request is what we need now, slop is what will be leftover */
+ min_request = sizeofobject + SIZEOF(small_pool_hdr);
+ if (prev_hdr_ptr == NULL) /* first pool in class? */
+ slop = first_pool_slop[pool_id];
+ else
+ slop = extra_pool_slop[pool_id];
+ /* Don't ask for more than MAX_ALLOC_CHUNK */
+ if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request))
+ slop = (size_t) (MAX_ALLOC_CHUNK-min_request);
+ /* Try to get space, if fail reduce slop and try again */
+ for (;;) {
+ hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop);
+ if (hdr_ptr != NULL)
+ break;
+ slop /= 2;
+ if (slop < MIN_SLOP) /* give up when it gets real small */
+ out_of_memory(cinfo, 2); /* jpeg_get_small failed */
+ }
+ mem->total_space_allocated += min_request + slop;
+ /* Success, initialize the new pool header and add to end of list */
+ hdr_ptr->hdr.next = NULL;
+ hdr_ptr->hdr.bytes_used = 0;
+ hdr_ptr->hdr.bytes_left = sizeofobject + slop;
+ if (prev_hdr_ptr == NULL) /* first pool in class? */
+ mem->small_list[pool_id] = hdr_ptr;
+ else
+ prev_hdr_ptr->hdr.next = hdr_ptr;
+ }
+
+ /* OK, allocate the object from the current pool */
+ data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */
+ data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */
+ hdr_ptr->hdr.bytes_used += sizeofobject;
+ hdr_ptr->hdr.bytes_left -= sizeofobject;
+
+ return (void *) data_ptr;
+}
+
+
+/*
+ * Allocation of "large" objects.
+ *
+ * The external semantics of these are the same as "small" objects,
+ * except that FAR pointers are used on 80x86. However the pool
+ * management heuristics are quite different. We assume that each
+ * request is large enough that it may as well be passed directly to
+ * jpeg_get_large; the pool management just links everything together
+ * so that we can free it all on demand.
+ * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
+ * structures. The routines that create these structures (see below)
+ * deliberately bunch rows together to ensure a large request size.
+ */
+
+METHODDEF(void FAR *)
+alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject)
+/* Allocate a "large" object */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ large_pool_ptr hdr_ptr;
+ size_t odd_bytes;
+
+ /* Check for unsatisfiable request (do now to ensure no overflow below) */
+ if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)))
+ out_of_memory(cinfo, 3); /* request exceeds malloc's ability */
+
+ /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */
+ odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE);
+ if (odd_bytes > 0)
+ sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes;
+
+ /* Always make a new pool */
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject +
+ SIZEOF(large_pool_hdr));
+ if (hdr_ptr == NULL)
+ out_of_memory(cinfo, 4); /* jpeg_get_large failed */
+ mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr);
+
+ /* Success, initialize the new pool header and add to list */
+ hdr_ptr->hdr.next = mem->large_list[pool_id];
+ /* We maintain space counts in each pool header for statistical purposes,
+ * even though they are not needed for allocation.
+ */
+ hdr_ptr->hdr.bytes_used = sizeofobject;
+ hdr_ptr->hdr.bytes_left = 0;
+ mem->large_list[pool_id] = hdr_ptr;
+
+ return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */
+}
+
+
+/*
+ * Creation of 2-D sample arrays.
+ * The pointers are in near heap, the samples themselves in FAR heap.
+ *
+ * To minimize allocation overhead and to allow I/O of large contiguous
+ * blocks, we allocate the sample rows in groups of as many rows as possible
+ * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
+ * NB: the virtual array control routines, later in this file, know about
+ * this chunking of rows. The rowsperchunk value is left in the mem manager
+ * object so that it can be saved away if this sarray is the workspace for
+ * a virtual array.
+ */
+
+METHODDEF(JSAMPARRAY)
+alloc_sarray (j_common_ptr cinfo, int pool_id,
+ JDIMENSION samplesperrow, JDIMENSION numrows)
+/* Allocate a 2-D sample array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ JSAMPARRAY result;
+ JSAMPROW workspace;
+ JDIMENSION rowsperchunk, currow, i;
+ long ltemp;
+
+ /* Calculate max # of rows allowed in one allocation chunk */
+ ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
+ ((long) samplesperrow * SIZEOF(JSAMPLE));
+ if (ltemp <= 0)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+ if (ltemp < (long) numrows)
+ rowsperchunk = (JDIMENSION) ltemp;
+ else
+ rowsperchunk = numrows;
+ mem->last_rowsperchunk = rowsperchunk;
+
+ /* Get space for row pointers (small object) */
+ result = (JSAMPARRAY) alloc_small(cinfo, pool_id,
+ (size_t) (numrows * SIZEOF(JSAMPROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace = (JSAMPROW) alloc_large(cinfo, pool_id,
+ (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow
+ * SIZEOF(JSAMPLE)));
+ for (i = rowsperchunk; i > 0; i--) {
+ result[currow++] = workspace;
+ workspace += samplesperrow;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * Creation of 2-D coefficient-block arrays.
+ * This is essentially the same as the code for sample arrays, above.
+ */
+
+METHODDEF(JBLOCKARRAY)
+alloc_barray (j_common_ptr cinfo, int pool_id,
+ JDIMENSION blocksperrow, JDIMENSION numrows)
+/* Allocate a 2-D coefficient-block array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ JBLOCKARRAY result;
+ JBLOCKROW workspace;
+ JDIMENSION rowsperchunk, currow, i;
+ long ltemp;
+
+ /* Calculate max # of rows allowed in one allocation chunk */
+ ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) /
+ ((long) blocksperrow * SIZEOF(JBLOCK));
+ if (ltemp <= 0)
+ ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
+ if (ltemp < (long) numrows)
+ rowsperchunk = (JDIMENSION) ltemp;
+ else
+ rowsperchunk = numrows;
+ mem->last_rowsperchunk = rowsperchunk;
+
+ /* Get space for row pointers (small object) */
+ result = (JBLOCKARRAY) alloc_small(cinfo, pool_id,
+ (size_t) (numrows * SIZEOF(JBLOCKROW)));
+
+ /* Get the rows themselves (large objects) */
+ currow = 0;
+ while (currow < numrows) {
+ rowsperchunk = MIN(rowsperchunk, numrows - currow);
+ workspace = (JBLOCKROW) alloc_large(cinfo, pool_id,
+ (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow
+ * SIZEOF(JBLOCK)));
+ for (i = rowsperchunk; i > 0; i--) {
+ result[currow++] = workspace;
+ workspace += blocksperrow;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * About virtual array management:
+ *
+ * The above "normal" array routines are only used to allocate strip buffers
+ * (as wide as the image, but just a few rows high). Full-image-sized buffers
+ * are handled as "virtual" arrays. The array is still accessed a strip at a
+ * time, but the memory manager must save the whole array for repeated
+ * accesses. The intended implementation is that there is a strip buffer in
+ * memory (as high as is possible given the desired memory limit), plus a
+ * backing file that holds the rest of the array.
+ *
+ * The request_virt_array routines are told the total size of the image and
+ * the maximum number of rows that will be accessed at once. The in-memory
+ * buffer must be at least as large as the maxaccess value.
+ *
+ * The request routines create control blocks but not the in-memory buffers.
+ * That is postponed until realize_virt_arrays is called. At that time the
+ * total amount of space needed is known (approximately, anyway), so free
+ * memory can be divided up fairly.
+ *
+ * The access_virt_array routines are responsible for making a specific strip
+ * area accessible (after reading or writing the backing file, if necessary).
+ * Note that the access routines are told whether the caller intends to modify
+ * the accessed strip; during a read-only pass this saves having to rewrite
+ * data to disk. The access routines are also responsible for pre-zeroing
+ * any newly accessed rows, if pre-zeroing was requested.
+ *
+ * In current usage, the access requests are usually for nonoverlapping
+ * strips; that is, successive access start_row numbers differ by exactly
+ * num_rows = maxaccess. This means we can get good performance with simple
+ * buffer dump/reload logic, by making the in-memory buffer be a multiple
+ * of the access height; then there will never be accesses across bufferload
+ * boundaries. The code will still work with overlapping access requests,
+ * but it doesn't handle bufferload overlaps very efficiently.
+ */
+
+
+METHODDEF(jvirt_sarray_ptr)
+request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
+ JDIMENSION samplesperrow, JDIMENSION numrows,
+ JDIMENSION maxaccess)
+/* Request a virtual 2-D sample array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ jvirt_sarray_ptr result;
+
+ /* Only IMAGE-lifetime virtual arrays are currently supported */
+ if (pool_id != JPOOL_IMAGE)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ /* get control block */
+ result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id,
+ SIZEOF(struct jvirt_sarray_control));
+
+ result->mem_buffer = NULL; /* marks array not yet realized */
+ result->rows_in_array = numrows;
+ result->samplesperrow = samplesperrow;
+ result->maxaccess = maxaccess;
+ result->pre_zero = pre_zero;
+ result->b_s_open = FALSE; /* no associated backing-store object */
+ result->next = mem->virt_sarray_list; /* add to list of virtual arrays */
+ mem->virt_sarray_list = result;
+
+ return result;
+}
+
+
+METHODDEF(jvirt_barray_ptr)
+request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero,
+ JDIMENSION blocksperrow, JDIMENSION numrows,
+ JDIMENSION maxaccess)
+/* Request a virtual 2-D coefficient-block array */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ jvirt_barray_ptr result;
+
+ /* Only IMAGE-lifetime virtual arrays are currently supported */
+ if (pool_id != JPOOL_IMAGE)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+ /* get control block */
+ result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id,
+ SIZEOF(struct jvirt_barray_control));
+
+ result->mem_buffer = NULL; /* marks array not yet realized */
+ result->rows_in_array = numrows;
+ result->blocksperrow = blocksperrow;
+ result->maxaccess = maxaccess;
+ result->pre_zero = pre_zero;
+ result->b_s_open = FALSE; /* no associated backing-store object */
+ result->next = mem->virt_barray_list; /* add to list of virtual arrays */
+ mem->virt_barray_list = result;
+
+ return result;
+}
+
+
+METHODDEF(void)
+realize_virt_arrays (j_common_ptr cinfo)
+/* Allocate the in-memory buffers for any unrealized virtual arrays */
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ long space_per_minheight, maximum_space, avail_mem;
+ long minheights, max_minheights;
+ jvirt_sarray_ptr sptr;
+ jvirt_barray_ptr bptr;
+
+ /* Compute the minimum space needed (maxaccess rows in each buffer)
+ * and the maximum space needed (full image height in each buffer).
+ * These may be of use to the system-dependent jpeg_mem_available routine.
+ */
+ space_per_minheight = 0;
+ maximum_space = 0;
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->mem_buffer == NULL) { /* if not realized yet */
+ space_per_minheight += (long) sptr->maxaccess *
+ (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
+ maximum_space += (long) sptr->rows_in_array *
+ (long) sptr->samplesperrow * SIZEOF(JSAMPLE);
+ }
+ }
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->mem_buffer == NULL) { /* if not realized yet */
+ space_per_minheight += (long) bptr->maxaccess *
+ (long) bptr->blocksperrow * SIZEOF(JBLOCK);
+ maximum_space += (long) bptr->rows_in_array *
+ (long) bptr->blocksperrow * SIZEOF(JBLOCK);
+ }
+ }
+
+ if (space_per_minheight <= 0)
+ return; /* no unrealized arrays, no work */
+
+ /* Determine amount of memory to actually use; this is system-dependent. */
+ avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
+ mem->total_space_allocated);
+
+ /* If the maximum space needed is available, make all the buffers full
+ * height; otherwise parcel it out with the same number of minheights
+ * in each buffer.
+ */
+ if (avail_mem >= maximum_space)
+ max_minheights = 1000000000L;
+ else {
+ max_minheights = avail_mem / space_per_minheight;
+ /* If there doesn't seem to be enough space, try to get the minimum
+ * anyway. This allows a "stub" implementation of jpeg_mem_available().
+ */
+ if (max_minheights <= 0)
+ max_minheights = 1;
+ }
+
+ /* Allocate the in-memory buffers and initialize backing store as needed. */
+
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->mem_buffer == NULL) { /* if not realized yet */
+ minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L;
+ if (minheights <= max_minheights) {
+ /* This buffer fits in memory */
+ sptr->rows_in_mem = sptr->rows_in_array;
+ } else {
+ /* It doesn't fit in memory, create backing store. */
+ sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess);
+ jpeg_open_backing_store(cinfo, & sptr->b_s_info,
+ (long) sptr->rows_in_array *
+ (long) sptr->samplesperrow *
+ (long) SIZEOF(JSAMPLE));
+ sptr->b_s_open = TRUE;
+ }
+ sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE,
+ sptr->samplesperrow, sptr->rows_in_mem);
+ sptr->rowsperchunk = mem->last_rowsperchunk;
+ sptr->cur_start_row = 0;
+ sptr->first_undef_row = 0;
+ sptr->dirty = FALSE;
+ }
+ }
+
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->mem_buffer == NULL) { /* if not realized yet */
+ minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L;
+ if (minheights <= max_minheights) {
+ /* This buffer fits in memory */
+ bptr->rows_in_mem = bptr->rows_in_array;
+ } else {
+ /* It doesn't fit in memory, create backing store. */
+ bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess);
+ jpeg_open_backing_store(cinfo, & bptr->b_s_info,
+ (long) bptr->rows_in_array *
+ (long) bptr->blocksperrow *
+ (long) SIZEOF(JBLOCK));
+ bptr->b_s_open = TRUE;
+ }
+ bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE,
+ bptr->blocksperrow, bptr->rows_in_mem);
+ bptr->rowsperchunk = mem->last_rowsperchunk;
+ bptr->cur_start_row = 0;
+ bptr->first_undef_row = 0;
+ bptr->dirty = FALSE;
+ }
+ }
+}
+
+
+LOCAL(void)
+do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing)
+/* Do backing store read or write of a virtual sample array */
+{
+ long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+
+ bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE);
+ file_offset = ptr->cur_start_row * bytesperrow;
+ /* Loop to read or write each allocation chunk in mem_buffer */
+ for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
+ /* One chunk, but check for short chunk at end of buffer */
+ rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
+ /* Transfer no more than is currently defined */
+ thisrow = (long) ptr->cur_start_row + i;
+ rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
+ /* Transfer no more than fits in file */
+ rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
+ if (rows <= 0) /* this chunk might be past end of file! */
+ break;
+ byte_count = rows * bytesperrow;
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ file_offset += byte_count;
+ }
+}
+
+
+LOCAL(void)
+do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing)
+/* Do backing store read or write of a virtual coefficient-block array */
+{
+ long bytesperrow, file_offset, byte_count, rows, thisrow, i;
+
+ bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK);
+ file_offset = ptr->cur_start_row * bytesperrow;
+ /* Loop to read or write each allocation chunk in mem_buffer */
+ for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) {
+ /* One chunk, but check for short chunk at end of buffer */
+ rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i);
+ /* Transfer no more than is currently defined */
+ thisrow = (long) ptr->cur_start_row + i;
+ rows = MIN(rows, (long) ptr->first_undef_row - thisrow);
+ /* Transfer no more than fits in file */
+ rows = MIN(rows, (long) ptr->rows_in_array - thisrow);
+ if (rows <= 0) /* this chunk might be past end of file! */
+ break;
+ byte_count = rows * bytesperrow;
+ if (writing)
+ (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ else
+ (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info,
+ (void FAR *) ptr->mem_buffer[i],
+ file_offset, byte_count);
+ file_offset += byte_count;
+ }
+}
+
+
+METHODDEF(JSAMPARRAY)
+access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr,
+ JDIMENSION start_row, JDIMENSION num_rows,
+ boolean writable)
+/* Access the part of a virtual sample array starting at start_row */
+/* and extending for num_rows rows. writable is true if */
+/* caller intends to modify the accessed area. */
+{
+ JDIMENSION end_row = start_row + num_rows;
+ JDIMENSION undef_row;
+
+ /* debugging check */
+ if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
+ ptr->mem_buffer == NULL)
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+ /* Make the desired part of the virtual array accessible */
+ if (start_row < ptr->cur_start_row ||
+ end_row > ptr->cur_start_row+ptr->rows_in_mem) {
+ if (! ptr->b_s_open)
+ ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+ /* Flush old buffer contents if necessary */
+ if (ptr->dirty) {
+ do_sarray_io(cinfo, ptr, TRUE);
+ ptr->dirty = FALSE;
+ }
+ /* Decide what part of virtual array to access.
+ * Algorithm: if target address > current window, assume forward scan,
+ * load starting at target address. If target address < current window,
+ * assume backward scan, load so that target area is top of window.
+ * Note that when switching from forward write to forward read, will have
+ * start_row = 0, so the limiting case applies and we load from 0 anyway.
+ */
+ if (start_row > ptr->cur_start_row) {
+ ptr->cur_start_row = start_row;
+ } else {
+ /* use long arithmetic here to avoid overflow & unsigned problems */
+ long ltemp;
+
+ ltemp = (long) end_row - (long) ptr->rows_in_mem;
+ if (ltemp < 0)
+ ltemp = 0; /* don't fall off front end of file */
+ ptr->cur_start_row = (JDIMENSION) ltemp;
+ }
+ /* Read in the selected part of the array.
+ * During the initial write pass, we will do no actual read
+ * because the selected part is all undefined.
+ */
+ do_sarray_io(cinfo, ptr, FALSE);
+ }
+ /* Ensure the accessed part of the array is defined; prezero if needed.
+ * To improve locality of access, we only prezero the part of the array
+ * that the caller is about to access, not the entire in-memory array.
+ */
+ if (ptr->first_undef_row < end_row) {
+ if (ptr->first_undef_row < start_row) {
+ if (writable) /* writer skipped over a section of array */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ undef_row = start_row; /* but reader is allowed to read ahead */
+ } else {
+ undef_row = ptr->first_undef_row;
+ }
+ if (writable)
+ ptr->first_undef_row = end_row;
+ if (ptr->pre_zero) {
+ size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE);
+ undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
+ end_row -= ptr->cur_start_row;
+ while (undef_row < end_row) {
+ FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
+ undef_row++;
+ }
+ } else {
+ if (! writable) /* reader looking at undefined data */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ }
+ }
+ /* Flag the buffer dirty if caller will write in it */
+ if (writable)
+ ptr->dirty = TRUE;
+ /* Return address of proper part of the buffer */
+ return ptr->mem_buffer + (start_row - ptr->cur_start_row);
+}
+
+
+METHODDEF(JBLOCKARRAY)
+access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr,
+ JDIMENSION start_row, JDIMENSION num_rows,
+ boolean writable)
+/* Access the part of a virtual block array starting at start_row */
+/* and extending for num_rows rows. writable is true if */
+/* caller intends to modify the accessed area. */
+{
+ JDIMENSION end_row = start_row + num_rows;
+ JDIMENSION undef_row;
+
+ /* debugging check */
+ if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess ||
+ ptr->mem_buffer == NULL)
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+
+ /* Make the desired part of the virtual array accessible */
+ if (start_row < ptr->cur_start_row ||
+ end_row > ptr->cur_start_row+ptr->rows_in_mem) {
+ if (! ptr->b_s_open)
+ ERREXIT(cinfo, JERR_VIRTUAL_BUG);
+ /* Flush old buffer contents if necessary */
+ if (ptr->dirty) {
+ do_barray_io(cinfo, ptr, TRUE);
+ ptr->dirty = FALSE;
+ }
+ /* Decide what part of virtual array to access.
+ * Algorithm: if target address > current window, assume forward scan,
+ * load starting at target address. If target address < current window,
+ * assume backward scan, load so that target area is top of window.
+ * Note that when switching from forward write to forward read, will have
+ * start_row = 0, so the limiting case applies and we load from 0 anyway.
+ */
+ if (start_row > ptr->cur_start_row) {
+ ptr->cur_start_row = start_row;
+ } else {
+ /* use long arithmetic here to avoid overflow & unsigned problems */
+ long ltemp;
+
+ ltemp = (long) end_row - (long) ptr->rows_in_mem;
+ if (ltemp < 0)
+ ltemp = 0; /* don't fall off front end of file */
+ ptr->cur_start_row = (JDIMENSION) ltemp;
+ }
+ /* Read in the selected part of the array.
+ * During the initial write pass, we will do no actual read
+ * because the selected part is all undefined.
+ */
+ do_barray_io(cinfo, ptr, FALSE);
+ }
+ /* Ensure the accessed part of the array is defined; prezero if needed.
+ * To improve locality of access, we only prezero the part of the array
+ * that the caller is about to access, not the entire in-memory array.
+ */
+ if (ptr->first_undef_row < end_row) {
+ if (ptr->first_undef_row < start_row) {
+ if (writable) /* writer skipped over a section of array */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ undef_row = start_row; /* but reader is allowed to read ahead */
+ } else {
+ undef_row = ptr->first_undef_row;
+ }
+ if (writable)
+ ptr->first_undef_row = end_row;
+ if (ptr->pre_zero) {
+ size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK);
+ undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */
+ end_row -= ptr->cur_start_row;
+ while (undef_row < end_row) {
+ FMEMZERO((void FAR *) ptr->mem_buffer[undef_row], bytesperrow);
+ undef_row++;
+ }
+ } else {
+ if (! writable) /* reader looking at undefined data */
+ ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
+ }
+ }
+ /* Flag the buffer dirty if caller will write in it */
+ if (writable)
+ ptr->dirty = TRUE;
+ /* Return address of proper part of the buffer */
+ return ptr->mem_buffer + (start_row - ptr->cur_start_row);
+}
+
+
+/*
+ * Release all objects belonging to a specified pool.
+ */
+
+METHODDEF(void)
+free_pool (j_common_ptr cinfo, int pool_id)
+{
+ my_mem_ptr mem = (my_mem_ptr) cinfo->mem;
+ small_pool_ptr shdr_ptr;
+ large_pool_ptr lhdr_ptr;
+ size_t space_freed;
+
+ if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS)
+ ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */
+
+#ifdef MEM_STATS
+ if (cinfo->err->trace_level > 1)
+ print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */
+#endif
+
+ /* If freeing IMAGE pool, close any virtual arrays first */
+ if (pool_id == JPOOL_IMAGE) {
+ jvirt_sarray_ptr sptr;
+ jvirt_barray_ptr bptr;
+
+ for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) {
+ if (sptr->b_s_open) { /* there may be no backing store */
+ sptr->b_s_open = FALSE; /* prevent recursive close if error */
+ (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info);
+ }
+ }
+ mem->virt_sarray_list = NULL;
+ for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) {
+ if (bptr->b_s_open) { /* there may be no backing store */
+ bptr->b_s_open = FALSE; /* prevent recursive close if error */
+ (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info);
+ }
+ }
+ mem->virt_barray_list = NULL;
+ }
+
+ /* Release large objects */
+ lhdr_ptr = mem->large_list[pool_id];
+ mem->large_list[pool_id] = NULL;
+
+ while (lhdr_ptr != NULL) {
+ large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next;
+ space_freed = lhdr_ptr->hdr.bytes_used +
+ lhdr_ptr->hdr.bytes_left +
+ SIZEOF(large_pool_hdr);
+ jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed);
+ mem->total_space_allocated -= space_freed;
+ lhdr_ptr = next_lhdr_ptr;
+ }
+
+ /* Release small objects */
+ shdr_ptr = mem->small_list[pool_id];
+ mem->small_list[pool_id] = NULL;
+
+ while (shdr_ptr != NULL) {
+ small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next;
+ space_freed = shdr_ptr->hdr.bytes_used +
+ shdr_ptr->hdr.bytes_left +
+ SIZEOF(small_pool_hdr);
+ jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed);
+ mem->total_space_allocated -= space_freed;
+ shdr_ptr = next_shdr_ptr;
+ }
+}
+
+
+/*
+ * Close up shop entirely.
+ * Note that this cannot be called unless cinfo->mem is non-NULL.
+ */
+
+METHODDEF(void)
+self_destruct (j_common_ptr cinfo)
+{
+ int pool;
+
+ /* Close all backing store, release all memory.
+ * Releasing pools in reverse order might help avoid fragmentation
+ * with some (brain-damaged) malloc libraries.
+ */
+ for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
+ free_pool(cinfo, pool);
+ }
+
+ /* Release the memory manager control block too. */
+ jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr));
+ cinfo->mem = NULL; /* ensures I will be called only once */
+
+ jpeg_mem_term(cinfo); /* system-dependent cleanup */
+}
+
+
+/*
+ * Memory manager initialization.
+ * When this is called, only the error manager pointer is valid in cinfo!
+ */
+
+GLOBAL(void)
+jinit_memory_mgr (j_common_ptr cinfo)
+{
+ my_mem_ptr mem;
+ long max_to_use;
+ int pool;
+ size_t test_mac;
+
+ cinfo->mem = NULL; /* for safety if init fails */
+
+ /* Check for configuration errors.
+ * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
+ * doesn't reflect any real hardware alignment requirement.
+ * The test is a little tricky: for X>0, X and X-1 have no one-bits
+ * in common if and only if X is a power of 2, ie has only one one-bit.
+ * Some compilers may give an "unreachable code" warning here; ignore it.
+ */
+ if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0)
+ ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);
+ /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be
+ * a multiple of SIZEOF(ALIGN_TYPE).
+ * Again, an "unreachable code" warning may be ignored here.
+ * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK.
+ */
+ test_mac = (size_t) MAX_ALLOC_CHUNK;
+ if ((long) test_mac != MAX_ALLOC_CHUNK ||
+ (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0)
+ ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
+
+ max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */
+
+ /* Attempt to allocate memory manager's control block */
+ mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr));
+
+ if (mem == NULL) {
+ jpeg_mem_term(cinfo); /* system-dependent cleanup */
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
+ }
+
+ /* OK, fill in the method pointers */
+ mem->pub.alloc_small = alloc_small;
+ mem->pub.alloc_large = alloc_large;
+ mem->pub.alloc_sarray = alloc_sarray;
+ mem->pub.alloc_barray = alloc_barray;
+ mem->pub.request_virt_sarray = request_virt_sarray;
+ mem->pub.request_virt_barray = request_virt_barray;
+ mem->pub.realize_virt_arrays = realize_virt_arrays;
+ mem->pub.access_virt_sarray = access_virt_sarray;
+ mem->pub.access_virt_barray = access_virt_barray;
+ mem->pub.free_pool = free_pool;
+ mem->pub.self_destruct = self_destruct;
+
+ /* Make MAX_ALLOC_CHUNK accessible to other modules */
+ mem->pub.max_alloc_chunk = MAX_ALLOC_CHUNK;
+
+ /* Initialize working state */
+ mem->pub.max_memory_to_use = max_to_use;
+
+ for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) {
+ mem->small_list[pool] = NULL;
+ mem->large_list[pool] = NULL;
+ }
+ mem->virt_sarray_list = NULL;
+ mem->virt_barray_list = NULL;
+
+ mem->total_space_allocated = SIZEOF(my_memory_mgr);
+
+ /* Declare ourselves open for business */
+ cinfo->mem = & mem->pub;
+
+ /* Check for an environment variable JPEGMEM; if found, override the
+ * default max_memory setting from jpeg_mem_init. Note that the
+ * surrounding application may again override this value.
+ * If your system doesn't support getenv(), define NO_GETENV to disable
+ * this feature.
+ */
+#ifndef NO_GETENV
+ { char * memenv;
+
+ if ((memenv = getenv("JPEGMEM")) != NULL) {
+ char ch = 'x';
+
+ if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) {
+ if (ch == 'm' || ch == 'M')
+ max_to_use *= 1000L;
+ mem->pub.max_memory_to_use = max_to_use * 1000L;
+ }
+ }
+ }
+#endif
+
+}
diff --git a/jpg/jmemname.c b/jpg/jmemname.c
new file mode 100644
index 0000000..ed96dee
--- /dev/null
+++ b/jpg/jmemname.c
@@ -0,0 +1,276 @@
+/*
+ * jmemname.c
+ *
+ * Copyright (C) 1992-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a generic implementation of the system-dependent
+ * portion of the JPEG memory manager. This implementation assumes that
+ * you must explicitly construct a name for each temp file.
+ * Also, the problem of determining the amount of memory available
+ * is shoved onto the user.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+#ifndef SEEK_SET /* pre-ANSI systems may not define this; */
+#define SEEK_SET 0 /* if not, assume 0 is correct */
+#endif
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#define RW_BINARY "w+"
+#else
+#ifdef VMS /* VMS is very nonstandard */
+#define READ_BINARY "rb", "ctx=stm"
+#define RW_BINARY "w+b", "ctx=stm"
+#else /* standard ANSI-compliant case */
+#define READ_BINARY "rb"
+#define RW_BINARY "w+b"
+#endif
+#endif
+
+
+/*
+ * Selection of a file name for a temporary file.
+ * This is system-dependent!
+ *
+ * The code as given is suitable for most Unix systems, and it is easily
+ * modified for most non-Unix systems. Some notes:
+ * 1. The temp file is created in the directory named by TEMP_DIRECTORY.
+ * The default value is /usr/tmp, which is the conventional place for
+ * creating large temp files on Unix. On other systems you'll probably
+ * want to change the file location. You can do this by editing the
+ * #define, or (preferred) by defining TEMP_DIRECTORY in jconfig.h.
+ *
+ * 2. If you need to change the file name as well as its location,
+ * you can override the TEMP_FILE_NAME macro. (Note that this is
+ * actually a printf format string; it must contain %s and %d.)
+ * Few people should need to do this.
+ *
+ * 3. mktemp() is used to ensure that multiple processes running
+ * simultaneously won't select the same file names. If your system
+ * doesn't have mktemp(), define NO_MKTEMP to do it the hard way.
+ * (If you don't have <errno.h>, also define NO_ERRNO_H.)
+ *
+ * 4. You probably want to define NEED_SIGNAL_CATCHER so that cjpeg.c/djpeg.c
+ * will cause the temp files to be removed if you stop the program early.
+ */
+
+#ifndef TEMP_DIRECTORY /* can override from jconfig.h or Makefile */
+#define TEMP_DIRECTORY "/usr/tmp/" /* recommended setting for Unix */
+#endif
+
+static int next_file_num; /* to distinguish among several temp files */
+
+#ifdef NO_MKTEMP
+
+#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
+#define TEMP_FILE_NAME "%sJPG%03d.TMP"
+#endif
+
+#ifndef NO_ERRNO_H
+#include <errno.h> /* to define ENOENT */
+#endif
+
+/* ANSI C specifies that errno is a macro, but on older systems it's more
+ * likely to be a plain int variable. And not all versions of errno.h
+ * bother to declare it, so we have to in order to be most portable. Thus:
+ */
+#ifndef errno
+extern int errno;
+#endif
+
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+ FILE * tfile;
+
+ /* Keep generating file names till we find one that's not in use */
+ for (;;) {
+ next_file_num++; /* advance counter */
+ sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
+ if ((tfile = fopen(fname, READ_BINARY)) == NULL) {
+ /* fopen could have failed for a reason other than the file not
+ * being there; for example, file there but unreadable.
+ * If <errno.h> isn't available, then we cannot test the cause.
+ */
+#ifdef ENOENT
+ if (errno != ENOENT)
+ continue;
+#endif
+ break;
+ }
+ fclose(tfile); /* oops, it's there; close tfile & try again */
+ }
+}
+
+#else /* ! NO_MKTEMP */
+
+/* Note that mktemp() requires the initial filename to end in six X's */
+#ifndef TEMP_FILE_NAME /* can override from jconfig.h or Makefile */
+#define TEMP_FILE_NAME "%sJPG%dXXXXXX"
+#endif
+
+LOCAL(void)
+select_file_name (char * fname)
+{
+ next_file_num++; /* advance counter */
+ sprintf(fname, TEMP_FILE_NAME, TEMP_DIRECTORY, next_file_num);
+ mktemp(fname); /* make sure file name is unique */
+ /* mktemp replaces the trailing XXXXXX with a unique string of characters */
+}
+
+#endif /* NO_MKTEMP */
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * It's impossible to do this in a portable way; our current solution is
+ * to make the user tell us (with a default value set at compile time).
+ * If you can actually get the available space, it's a good idea to subtract
+ * a slop factor of 5% or so.
+ */
+
+#ifndef DEFAULT_MAX_MEM /* so can override from makefile */
+#define DEFAULT_MAX_MEM 1000000L /* default: one megabyte */
+#endif
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return cinfo->mem->max_memory_to_use - already_allocated;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Backing store objects are only used when the value returned by
+ * jpeg_mem_available is less than the total space needed. You can dispense
+ * with these routines if you have plenty of virtual memory; see jmemnobs.c.
+ */
+
+
+METHODDEF(void)
+read_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFREAD(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_READ);
+}
+
+
+METHODDEF(void)
+write_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count)
+{
+ if (fseek(info->temp_file, file_offset, SEEK_SET))
+ ERREXIT(cinfo, JERR_TFILE_SEEK);
+ if (JFWRITE(info->temp_file, buffer_address, byte_count)
+ != (size_t) byte_count)
+ ERREXIT(cinfo, JERR_TFILE_WRITE);
+}
+
+
+METHODDEF(void)
+close_backing_store (j_common_ptr cinfo, backing_store_ptr info)
+{
+ fclose(info->temp_file); /* close the file */
+ unlink(info->temp_name); /* delete the file */
+/* If your system doesn't have unlink(), use remove() instead.
+ * remove() is the ANSI-standard name for this function, but if
+ * your system was ANSI you'd be using jmemansi.c, right?
+ */
+ TRACEMSS(cinfo, 1, JTRC_TFILE_CLOSE, info->temp_name);
+}
+
+
+/*
+ * Initial opening of a backing-store object.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ select_file_name(info->temp_name);
+ if ((info->temp_file = fopen(info->temp_name, RW_BINARY)) == NULL)
+ ERREXITS(cinfo, JERR_TFILE_CREATE, info->temp_name);
+ info->read_backing_store = read_backing_store;
+ info->write_backing_store = write_backing_store;
+ info->close_backing_store = close_backing_store;
+ TRACEMSS(cinfo, 1, JTRC_TFILE_OPEN, info->temp_name);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ next_file_num = 0; /* initialize temp file name generator */
+ return DEFAULT_MAX_MEM; /* default for max_memory_to_use */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/jpg/jmemnobs.c b/jpg/jmemnobs.c
new file mode 100644
index 0000000..eb8c337
--- /dev/null
+++ b/jpg/jmemnobs.c
@@ -0,0 +1,109 @@
+/*
+ * jmemnobs.c
+ *
+ * Copyright (C) 1992-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides a really simple implementation of the system-
+ * dependent portion of the JPEG memory manager. This implementation
+ * assumes that no backing-store files are needed: all required space
+ * can be obtained from malloc().
+ * This is very portable in the sense that it'll compile on almost anything,
+ * but you'd better have lots of main memory (or virtual memory) if you want
+ * to process big images.
+ * Note that the max_memory_to_use option is ignored by this implementation.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "jmemsys.h" /* import the system-dependent declarations */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc(),free() */
+extern void * malloc JPP((size_t size));
+extern void free JPP((void *ptr));
+#endif
+
+
+/*
+ * Memory allocation and freeing are controlled by the regular library
+ * routines malloc() and free().
+ */
+
+GLOBAL(void *)
+jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * "Large" objects are treated the same as "small" ones.
+ * NB: although we include FAR keywords in the routine declarations,
+ * this file won't actually work in 80x86 small/medium model; at least,
+ * you probably won't be able to process useful-size images in only 64KB.
+ */
+
+GLOBAL(void FAR *)
+jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
+{
+ return (void FAR *) malloc(sizeofobject);
+}
+
+GLOBAL(void)
+jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
+{
+ free(object);
+}
+
+
+/*
+ * This routine computes the total memory space available for allocation.
+ * Here we always say, "we got all you want bud!"
+ */
+
+GLOBAL(long)
+jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
+ long max_bytes_needed, long already_allocated)
+{
+ return max_bytes_needed;
+}
+
+
+/*
+ * Backing store (temporary file) management.
+ * Since jpeg_mem_available always promised the moon,
+ * this should never be called and we can just error out.
+ */
+
+GLOBAL(void)
+jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
+ long total_bytes_needed)
+{
+ ERREXIT(cinfo, JERR_NO_BACKING_STORE);
+}
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required. Here, there isn't any.
+ */
+
+GLOBAL(long)
+jpeg_mem_init (j_common_ptr cinfo)
+{
+ return 0; /* just set max_memory_to_use to 0 */
+}
+
+GLOBAL(void)
+jpeg_mem_term (j_common_ptr cinfo)
+{
+ /* no work */
+}
diff --git a/jpg/jmemsys.h b/jpg/jmemsys.h
new file mode 100644
index 0000000..6c3c6d3
--- /dev/null
+++ b/jpg/jmemsys.h
@@ -0,0 +1,198 @@
+/*
+ * jmemsys.h
+ *
+ * Copyright (C) 1992-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This include file defines the interface between the system-independent
+ * and system-dependent portions of the JPEG memory manager. No other
+ * modules need include it. (The system-independent portion is jmemmgr.c;
+ * there are several different versions of the system-dependent portion.)
+ *
+ * This file works as-is for the system-dependent memory managers supplied
+ * in the IJG distribution. You may need to modify it if you write a
+ * custom memory manager. If system-dependent changes are needed in
+ * this file, the best method is to #ifdef them based on a configuration
+ * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR
+ * and USE_MAC_MEMMGR.
+ */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_get_small jGetSmall
+#define jpeg_free_small jFreeSmall
+#define jpeg_get_large jGetLarge
+#define jpeg_free_large jFreeLarge
+#define jpeg_mem_available jMemAvail
+#define jpeg_open_backing_store jOpenBackStore
+#define jpeg_mem_init jMemInit
+#define jpeg_mem_term jMemTerm
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/*
+ * These two functions are used to allocate and release small chunks of
+ * memory. (Typically the total amount requested through jpeg_get_small is
+ * no more than 20K or so; this will be requested in chunks of a few K each.)
+ * Behavior should be the same as for the standard library functions malloc
+ * and free; in particular, jpeg_get_small must return NULL on failure.
+ * On most systems, these ARE malloc and free. jpeg_free_small is passed the
+ * size of the object being freed, just in case it's needed.
+ * On an 80x86 machine using small-data memory model, these manage near heap.
+ */
+
+EXTERN(void *) jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject));
+EXTERN(void) jpeg_free_small JPP((j_common_ptr cinfo, void * object,
+ size_t sizeofobject));
+
+/*
+ * These two functions are used to allocate and release large chunks of
+ * memory (up to the total free space designated by jpeg_mem_available).
+ * The interface is the same as above, except that on an 80x86 machine,
+ * far pointers are used. On most other machines these are identical to
+ * the jpeg_get/free_small routines; but we keep them separate anyway,
+ * in case a different allocation strategy is desirable for large chunks.
+ */
+
+EXTERN(void FAR *) jpeg_get_large JPP((j_common_ptr cinfo,
+ size_t sizeofobject));
+EXTERN(void) jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object,
+ size_t sizeofobject));
+
+/*
+ * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may
+ * be requested in a single call to jpeg_get_large (and jpeg_get_small for that
+ * matter, but that case should never come into play). This macro is needed
+ * to model the 64Kb-segment-size limit of far addressing on 80x86 machines.
+ * On those machines, we expect that jconfig.h will provide a proper value.
+ * On machines with 32-bit flat address spaces, any large constant may be used.
+ *
+ * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type
+ * size_t and will be a multiple of sizeof(align_type).
+ */
+
+#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */
+#define MAX_ALLOC_CHUNK 1000000000L
+#endif
+
+/*
+ * This routine computes the total space still available for allocation by
+ * jpeg_get_large. If more space than this is needed, backing store will be
+ * used. NOTE: any memory already allocated must not be counted.
+ *
+ * There is a minimum space requirement, corresponding to the minimum
+ * feasible buffer sizes; jmemmgr.c will request that much space even if
+ * jpeg_mem_available returns zero. The maximum space needed, enough to hold
+ * all working storage in memory, is also passed in case it is useful.
+ * Finally, the total space already allocated is passed. If no better
+ * method is available, cinfo->mem->max_memory_to_use - already_allocated
+ * is often a suitable calculation.
+ *
+ * It is OK for jpeg_mem_available to underestimate the space available
+ * (that'll just lead to more backing-store access than is really necessary).
+ * However, an overestimate will lead to failure. Hence it's wise to subtract
+ * a slop factor from the true available space. 5% should be enough.
+ *
+ * On machines with lots of virtual memory, any large constant may be returned.
+ * Conversely, zero may be returned to always use the minimum amount of memory.
+ */
+
+EXTERN(long) jpeg_mem_available JPP((j_common_ptr cinfo,
+ long min_bytes_needed,
+ long max_bytes_needed,
+ long already_allocated));
+
+
+/*
+ * This structure holds whatever state is needed to access a single
+ * backing-store object. The read/write/close method pointers are called
+ * by jmemmgr.c to manipulate the backing-store object; all other fields
+ * are private to the system-dependent backing store routines.
+ */
+
+#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */
+
+
+#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */
+
+typedef unsigned short XMSH; /* type of extended-memory handles */
+typedef unsigned short EMSH; /* type of expanded-memory handles */
+
+typedef union {
+ short file_handle; /* DOS file handle if it's a temp file */
+ XMSH xms_handle; /* handle if it's a chunk of XMS */
+ EMSH ems_handle; /* handle if it's a chunk of EMS */
+} handle_union;
+
+#endif /* USE_MSDOS_MEMMGR */
+
+#ifdef USE_MAC_MEMMGR /* Mac-specific junk */
+#include <Files.h>
+#endif /* USE_MAC_MEMMGR */
+
+
+typedef struct backing_store_struct * backing_store_ptr;
+
+typedef struct backing_store_struct {
+ /* Methods for reading/writing/closing this backing-store object */
+ JMETHOD(void, read_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count));
+ JMETHOD(void, write_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info,
+ void FAR * buffer_address,
+ long file_offset, long byte_count));
+ JMETHOD(void, close_backing_store, (j_common_ptr cinfo,
+ backing_store_ptr info));
+
+ /* Private fields for system-dependent backing-store management */
+#ifdef USE_MSDOS_MEMMGR
+ /* For the MS-DOS manager (jmemdos.c), we need: */
+ handle_union handle; /* reference to backing-store storage object */
+ char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
+#else
+#ifdef USE_MAC_MEMMGR
+ /* For the Mac manager (jmemmac.c), we need: */
+ short temp_file; /* file reference number to temp file */
+ FSSpec tempSpec; /* the FSSpec for the temp file */
+ char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */
+#else
+ /* For a typical implementation with temp files, we need: */
+ FILE * temp_file; /* stdio reference to temp file */
+ char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */
+#endif
+#endif
+} backing_store_info;
+
+
+/*
+ * Initial opening of a backing-store object. This must fill in the
+ * read/write/close pointers in the object. The read/write routines
+ * may take an error exit if the specified maximum file size is exceeded.
+ * (If jpeg_mem_available always returns a large value, this routine can
+ * just take an error exit.)
+ */
+
+EXTERN(void) jpeg_open_backing_store JPP((j_common_ptr cinfo,
+ backing_store_ptr info,
+ long total_bytes_needed));
+
+
+/*
+ * These routines take care of any system-dependent initialization and
+ * cleanup required. jpeg_mem_init will be called before anything is
+ * allocated (and, therefore, nothing in cinfo is of use except the error
+ * manager pointer). It should return a suitable default value for
+ * max_memory_to_use; this may subsequently be overridden by the surrounding
+ * application. (Note that max_memory_to_use is only important if
+ * jpeg_mem_available chooses to consult it ... no one else will.)
+ * jpeg_mem_term may assume that all requested memory has been freed and that
+ * all opened backing-store objects have been closed.
+ */
+
+EXTERN(long) jpeg_mem_init JPP((j_common_ptr cinfo));
+EXTERN(void) jpeg_mem_term JPP((j_common_ptr cinfo));
diff --git a/jpg/jmorecfg.h b/jpg/jmorecfg.h
new file mode 100644
index 0000000..6c085c3
--- /dev/null
+++ b/jpg/jmorecfg.h
@@ -0,0 +1,369 @@
+/*
+ * jmorecfg.h
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 1997-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains additional configuration options that customize the
+ * JPEG software for special applications or support machine-dependent
+ * optimizations. Most users will not need to touch this file.
+ */
+
+
+/*
+ * Define BITS_IN_JSAMPLE as either
+ * 8 for 8-bit sample values (the usual setting)
+ * 12 for 12-bit sample values
+ * Only 8 and 12 are legal data precisions for lossy JPEG according to the
+ * JPEG standard, and the IJG code does not support anything else!
+ * We do not support run-time selection of data precision, sorry.
+ */
+
+#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
+
+
+/*
+ * Maximum number of components (color channels) allowed in JPEG image.
+ * To meet the letter of the JPEG spec, set this to 255. However, darn
+ * few applications need more than 4 channels (maybe 5 for CMYK + alpha
+ * mask). We recommend 10 as a reasonable compromise; use 4 if you are
+ * really short on memory. (Each allowed component costs a hundred or so
+ * bytes of storage, whether actually used in an image or not.)
+ */
+
+#define MAX_COMPONENTS 10 /* maximum number of image components */
+
+
+/*
+ * Basic data types.
+ * You may need to change these if you have a machine with unusual data
+ * type sizes; for example, "char" not 8 bits, "short" not 16 bits,
+ * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits,
+ * but it had better be at least 16.
+ */
+
+/* Representation of a single sample (pixel element value).
+ * We frequently allocate large arrays of these, so it's important to keep
+ * them small. But if you have memory to burn and access to char or short
+ * arrays is very slow on your hardware, you might want to change these.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+/* JSAMPLE should be the smallest type that will hold the values 0..255.
+ * You can use a signed char by having GETJSAMPLE mask it with 0xFF.
+ */
+
+#ifdef HAVE_UNSIGNED_CHAR
+
+typedef unsigned char JSAMPLE;
+#define GETJSAMPLE(value) ((int) (value))
+
+#else /* not HAVE_UNSIGNED_CHAR */
+
+typedef char JSAMPLE;
+#ifdef CHAR_IS_UNSIGNED
+#define GETJSAMPLE(value) ((int) (value))
+#else
+#define GETJSAMPLE(value) ((int) (value) & 0xFF)
+#endif /* CHAR_IS_UNSIGNED */
+
+#endif /* HAVE_UNSIGNED_CHAR */
+
+#define MAXJSAMPLE 255
+#define CENTERJSAMPLE 128
+
+#endif /* BITS_IN_JSAMPLE == 8 */
+
+
+#if BITS_IN_JSAMPLE == 12
+/* JSAMPLE should be the smallest type that will hold the values 0..4095.
+ * On nearly all machines "short" will do nicely.
+ */
+
+typedef short JSAMPLE;
+#define GETJSAMPLE(value) ((int) (value))
+
+#define MAXJSAMPLE 4095
+#define CENTERJSAMPLE 2048
+
+#endif /* BITS_IN_JSAMPLE == 12 */
+
+
+/* Representation of a DCT frequency coefficient.
+ * This should be a signed value of at least 16 bits; "short" is usually OK.
+ * Again, we allocate large arrays of these, but you can change to int
+ * if you have memory to burn and "short" is really slow.
+ */
+
+typedef short JCOEF;
+
+
+/* Compressed datastreams are represented as arrays of JOCTET.
+ * These must be EXACTLY 8 bits wide, at least once they are written to
+ * external storage. Note that when using the stdio data source/destination
+ * managers, this is also the data type passed to fread/fwrite.
+ */
+
+#ifdef HAVE_UNSIGNED_CHAR
+
+typedef unsigned char JOCTET;
+#define GETJOCTET(value) (value)
+
+#else /* not HAVE_UNSIGNED_CHAR */
+
+typedef char JOCTET;
+#ifdef CHAR_IS_UNSIGNED
+#define GETJOCTET(value) (value)
+#else
+#define GETJOCTET(value) ((value) & 0xFF)
+#endif /* CHAR_IS_UNSIGNED */
+
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+/* These typedefs are used for various table entries and so forth.
+ * They must be at least as wide as specified; but making them too big
+ * won't cost a huge amount of memory, so we don't provide special
+ * extraction code like we did for JSAMPLE. (In other words, these
+ * typedefs live at a different point on the speed/space tradeoff curve.)
+ */
+
+/* UINT8 must hold at least the values 0..255. */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char UINT8;
+#else /* not HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char UINT8;
+#else /* not CHAR_IS_UNSIGNED */
+typedef short UINT8;
+#endif /* CHAR_IS_UNSIGNED */
+#endif /* HAVE_UNSIGNED_CHAR */
+
+/* UINT16 must hold at least the values 0..65535. */
+
+#ifdef HAVE_UNSIGNED_SHORT
+typedef unsigned short UINT16;
+#else /* not HAVE_UNSIGNED_SHORT */
+typedef unsigned int UINT16;
+#endif /* HAVE_UNSIGNED_SHORT */
+
+/* INT16 must hold at least the values -32768..32767. */
+
+#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */
+typedef short INT16;
+#endif
+
+/* INT32 must hold at least signed 32-bit values. */
+
+#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */
+#ifndef _BASETSD_H_ /* Microsoft defines it in basetsd.h */
+#ifndef _BASETSD_H /* MinGW is slightly different */
+#ifndef QGLOBAL_H /* Qt defines it in qglobal.h */
+typedef long INT32;
+#endif
+#endif
+#endif
+#endif
+
+/* Datatype used for image dimensions. The JPEG standard only supports
+ * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore
+ * "unsigned int" is sufficient on all machines. However, if you need to
+ * handle larger images and you don't mind deviating from the spec, you
+ * can change this datatype.
+ */
+
+typedef unsigned int JDIMENSION;
+
+#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */
+
+
+/* These macros are used in all function definitions and extern declarations.
+ * You could modify them if you need to change function linkage conventions;
+ * in particular, you'll need to do that to make the library a Windows DLL.
+ * Another application is to make all functions global for use with debuggers
+ * or code profilers that require it.
+ */
+
+/* a function called through method pointers: */
+#define METHODDEF(type) static type
+/* a function used only in its module: */
+#define LOCAL(type) static type
+/* a function referenced thru EXTERNs: */
+#define GLOBAL(type) type
+/* a reference to a GLOBAL function: */
+#define EXTERN(type) extern type
+
+
+/* This macro is used to declare a "method", that is, a function pointer.
+ * We want to supply prototype parameters if the compiler can cope.
+ * Note that the arglist parameter must be parenthesized!
+ * Again, you can customize this if you need special linkage keywords.
+ */
+
+#ifdef HAVE_PROTOTYPES
+#define JMETHOD(type,methodname,arglist) type (*methodname) arglist
+#else
+#define JMETHOD(type,methodname,arglist) type (*methodname) ()
+#endif
+
+
+/* Here is the pseudo-keyword for declaring pointers that must be "far"
+ * on 80x86 machines. Most of the specialized coding for 80x86 is handled
+ * by just saying "FAR *" where such a pointer is needed. In a few places
+ * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol.
+ */
+
+#ifndef FAR
+#ifdef NEED_FAR_POINTERS
+#define FAR far
+#else
+#define FAR
+#endif
+#endif
+
+
+/*
+ * On a few systems, type boolean and/or its values FALSE, TRUE may appear
+ * in standard header files. Or you may have conflicts with application-
+ * specific header files that you want to include together with these files.
+ * Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
+ */
+
+#ifndef HAVE_BOOLEAN
+typedef int boolean;
+#endif
+#ifndef FALSE /* in case these macros already exist */
+#define FALSE 0 /* values of boolean */
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+/*
+ * The remaining options affect code selection within the JPEG library,
+ * but they don't need to be visible to most applications using the library.
+ * To minimize application namespace pollution, the symbols won't be
+ * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined.
+ */
+
+#ifdef JPEG_INTERNALS
+#define JPEG_INTERNAL_OPTIONS
+#endif
+
+#ifdef JPEG_INTERNAL_OPTIONS
+
+
+/*
+ * These defines indicate whether to include various optional functions.
+ * Undefining some of these symbols will produce a smaller but less capable
+ * library. Note that you can leave certain source files out of the
+ * compilation/linking process if you've #undef'd the corresponding symbols.
+ * (You may HAVE to do that if your compiler doesn't like null source files.)
+ */
+
+/* Capability options common to encoder and decoder: */
+
+#define DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */
+#define DCT_IFAST_SUPPORTED /* faster, less accurate integer method */
+#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */
+
+/* Encoder capability options: */
+
+#define C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
+#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
+#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
+#define DCT_SCALING_SUPPORTED /* Input rescaling via DCT? (Requires DCT_ISLOW)*/
+#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */
+/* Note: if you selected 12-bit data precision, it is dangerous to turn off
+ * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit
+ * precision, so jchuff.c normally uses entropy optimization to compute
+ * usable tables for higher precision. If you don't want to do optimization,
+ * you'll have to supply different default Huffman tables.
+ * The exact same statements apply for progressive JPEG: the default tables
+ * don't work for progressive mode. (This may get fixed, however.)
+ */
+#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */
+
+/* Decoder capability options: */
+
+#define D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */
+#define D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */
+#define D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/
+#define IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */
+#define SAVE_MARKERS_SUPPORTED /* jpeg_save_markers() needed? */
+#define BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */
+#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */
+#define UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */
+#define QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */
+#define QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */
+
+/* more capability options later, no doubt */
+
+
+/*
+ * Ordering of RGB data in scanlines passed to or from the application.
+ * If your application wants to deal with data in the order B,G,R, just
+ * change these macros. You can also deal with formats such as R,G,B,X
+ * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing
+ * the offsets will also change the order in which colormap data is organized.
+ * RESTRICTIONS:
+ * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats.
+ * 2. The color quantizer modules will not behave desirably if RGB_PIXELSIZE
+ * is not 3 (they don't understand about dummy color components!). So you
+ * can't use color quantization if you change that value.
+ */
+
+#define RGB_RED 0 /* Offset of Red in an RGB scanline element */
+#define RGB_GREEN 1 /* Offset of Green */
+#define RGB_BLUE 2 /* Offset of Blue */
+#define RGB_PIXELSIZE 3 /* JSAMPLEs per RGB scanline element */
+
+
+/* Definitions for speed-related optimizations. */
+
+
+/* If your compiler supports inline functions, define INLINE
+ * as the inline keyword; otherwise define it as empty.
+ */
+
+#ifndef INLINE
+#ifdef __GNUC__ /* for instance, GNU C knows about inline */
+#define INLINE __inline__
+#endif
+#ifndef INLINE
+#define INLINE /* default is to define it as empty */
+#endif
+#endif
+
+
+/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying
+ * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER
+ * as short on such a machine. MULTIPLIER must be at least 16 bits wide.
+ */
+
+#ifndef MULTIPLIER
+#define MULTIPLIER int /* type for fastest integer multiply */
+#endif
+
+
+/* FAST_FLOAT should be either float or double, whichever is done faster
+ * by your compiler. (Note that this type is only used in the floating point
+ * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.)
+ * Typically, float is faster in ANSI C compilers, while double is faster in
+ * pre-ANSI compilers (because they insist on converting to double anyway).
+ * The code below therefore chooses float if we have ANSI-style prototypes.
+ */
+
+#ifndef FAST_FLOAT
+#ifdef HAVE_PROTOTYPES
+#define FAST_FLOAT float
+#else
+#define FAST_FLOAT double
+#endif
+#endif
+
+#endif /* JPEG_INTERNAL_OPTIONS */
diff --git a/jpg/jpegint.h b/jpg/jpegint.h
new file mode 100644
index 0000000..c0d5c14
--- /dev/null
+++ b/jpg/jpegint.h
@@ -0,0 +1,426 @@
+/*
+ * jpegint.h
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 1997-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file provides common declarations for the various JPEG modules.
+ * These declarations are considered internal to the JPEG library; most
+ * applications using the library shouldn't need to include this file.
+ */
+
+
+/* Declarations for both compression & decompression */
+
+typedef enum { /* Operating modes for buffer controllers */
+ JBUF_PASS_THRU, /* Plain stripwise operation */
+ /* Remaining modes require a full-image buffer to have been created */
+ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */
+ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */
+ JBUF_SAVE_AND_PASS /* Run both subobjects, save output */
+} J_BUF_MODE;
+
+/* Values of global_state field (jdapi.c has some dependencies on ordering!) */
+#define CSTATE_START 100 /* after create_compress */
+#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */
+#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */
+#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */
+#define DSTATE_START 200 /* after create_decompress */
+#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */
+#define DSTATE_READY 202 /* found SOS, ready for start_decompress */
+#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/
+#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */
+#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */
+#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */
+#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */
+#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */
+#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */
+#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */
+
+
+/* Declarations for compression modules */
+
+/* Master control module */
+struct jpeg_comp_master {
+ JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, pass_startup, (j_compress_ptr cinfo));
+ JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean call_pass_startup; /* True if pass_startup must be called */
+ boolean is_last_pass; /* True during last pass */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_c_main_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, process_data, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail));
+};
+
+/* Compression preprocessing (downsampling input buffer control) */
+struct jpeg_c_prep_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, pre_process_data, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf,
+ JDIMENSION *in_row_ctr,
+ JDIMENSION in_rows_avail,
+ JSAMPIMAGE output_buf,
+ JDIMENSION *out_row_group_ctr,
+ JDIMENSION out_row_groups_avail));
+};
+
+/* Coefficient buffer control */
+struct jpeg_c_coef_controller {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(boolean, compress_data, (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf));
+};
+
+/* Colorspace conversion */
+struct jpeg_color_converter {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, color_convert, (j_compress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
+ JDIMENSION output_row, int num_rows));
+};
+
+/* Downsampling */
+struct jpeg_downsampler {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ JMETHOD(void, downsample, (j_compress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION in_row_index,
+ JSAMPIMAGE output_buf,
+ JDIMENSION out_row_group_index));
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+};
+
+/* Forward DCT (also controls coefficient quantization) */
+typedef JMETHOD(void, forward_DCT_ptr,
+ (j_compress_ptr cinfo, jpeg_component_info * compptr,
+ JSAMPARRAY sample_data, JBLOCKROW coef_blocks,
+ JDIMENSION start_row, JDIMENSION start_col,
+ JDIMENSION num_blocks));
+
+struct jpeg_forward_dct {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo));
+ /* It is useful to allow each component to have a separate FDCT method. */
+ forward_DCT_ptr forward_DCT[MAX_COMPONENTS];
+};
+
+/* Entropy encoding */
+struct jpeg_entropy_encoder {
+ JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics));
+ JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data));
+ JMETHOD(void, finish_pass, (j_compress_ptr cinfo));
+};
+
+/* Marker writing */
+struct jpeg_marker_writer {
+ JMETHOD(void, write_file_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_frame_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_scan_header, (j_compress_ptr cinfo));
+ JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo));
+ JMETHOD(void, write_tables_only, (j_compress_ptr cinfo));
+ /* These routines are exported to allow insertion of extra markers */
+ /* Probably only COM and APPn markers should be written this way */
+ JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker,
+ unsigned int datalen));
+ JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val));
+};
+
+
+/* Declarations for decompression modules */
+
+/* Master control module */
+struct jpeg_decomp_master {
+ JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */
+};
+
+/* Input control module */
+struct jpeg_input_controller {
+ JMETHOD(int, consume_input, (j_decompress_ptr cinfo));
+ JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo));
+ JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo));
+
+ /* State variables made visible to other modules */
+ boolean has_multiple_scans; /* True if file has multiple scans */
+ boolean eoi_reached; /* True when EOI has been consumed */
+};
+
+/* Main buffer control (downsampled-data buffer) */
+struct jpeg_d_main_controller {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, process_data, (j_decompress_ptr cinfo,
+ JSAMPARRAY output_buf, JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+};
+
+/* Coefficient buffer control */
+struct jpeg_d_coef_controller {
+ JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo));
+ JMETHOD(int, consume_data, (j_decompress_ptr cinfo));
+ JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo));
+ JMETHOD(int, decompress_data, (j_decompress_ptr cinfo,
+ JSAMPIMAGE output_buf));
+ /* Pointer to array of coefficient virtual arrays, or NULL if none */
+ jvirt_barray_ptr *coef_arrays;
+};
+
+/* Decompression postprocessing (color quantization buffer control) */
+struct jpeg_d_post_controller {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode));
+ JMETHOD(void, post_process_data, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+};
+
+/* Marker reading & parsing */
+struct jpeg_marker_reader {
+ JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo));
+ /* Read markers until SOS or EOI.
+ * Returns same codes as are defined for jpeg_consume_input:
+ * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
+ */
+ JMETHOD(int, read_markers, (j_decompress_ptr cinfo));
+ /* Read a restart marker --- exported for use by entropy decoder only */
+ jpeg_marker_parser_method read_restart_marker;
+
+ /* State of marker reader --- nominally internal, but applications
+ * supplying COM or APPn handlers might like to know the state.
+ */
+ boolean saw_SOI; /* found SOI? */
+ boolean saw_SOF; /* found SOF? */
+ int next_restart_num; /* next restart number expected (0-7) */
+ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */
+};
+
+/* Entropy decoding */
+struct jpeg_entropy_decoder {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo,
+ JBLOCKROW *MCU_data));
+};
+
+/* Inverse DCT (also performs dequantization) */
+typedef JMETHOD(void, inverse_DCT_method_ptr,
+ (j_decompress_ptr cinfo, jpeg_component_info * compptr,
+ JCOEFPTR coef_block,
+ JSAMPARRAY output_buf, JDIMENSION output_col));
+
+struct jpeg_inverse_dct {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ /* It is useful to allow each component to have a separate IDCT method. */
+ inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS];
+};
+
+/* Upsampling (note that upsampler must also call color converter) */
+struct jpeg_upsampler {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, upsample, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf,
+ JDIMENSION *in_row_group_ctr,
+ JDIMENSION in_row_groups_avail,
+ JSAMPARRAY output_buf,
+ JDIMENSION *out_row_ctr,
+ JDIMENSION out_rows_avail));
+
+ boolean need_context_rows; /* TRUE if need rows above & below */
+};
+
+/* Colorspace conversion */
+struct jpeg_color_deconverter {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, color_convert, (j_decompress_ptr cinfo,
+ JSAMPIMAGE input_buf, JDIMENSION input_row,
+ JSAMPARRAY output_buf, int num_rows));
+};
+
+/* Color quantization or color precision reduction */
+struct jpeg_color_quantizer {
+ JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan));
+ JMETHOD(void, color_quantize, (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf,
+ int num_rows));
+ JMETHOD(void, finish_pass, (j_decompress_ptr cinfo));
+ JMETHOD(void, new_color_map, (j_decompress_ptr cinfo));
+};
+
+
+/* Miscellaneous useful macros */
+
+#undef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#undef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+
+
+/* We assume that right shift corresponds to signed division by 2 with
+ * rounding towards minus infinity. This is correct for typical "arithmetic
+ * shift" instructions that shift in copies of the sign bit. But some
+ * C compilers implement >> with an unsigned shift. For these machines you
+ * must define RIGHT_SHIFT_IS_UNSIGNED.
+ * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity.
+ * It is only applied with constant shift counts. SHIFT_TEMPS must be
+ * included in the variables of any routine using RIGHT_SHIFT.
+ */
+
+#ifdef RIGHT_SHIFT_IS_UNSIGNED
+#define SHIFT_TEMPS INT32 shift_temp;
+#define RIGHT_SHIFT(x,shft) \
+ ((shift_temp = (x)) < 0 ? \
+ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \
+ (shift_temp >> (shft)))
+#else
+#define SHIFT_TEMPS
+#define RIGHT_SHIFT(x,shft) ((x) >> (shft))
+#endif
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jinit_compress_master jICompress
+#define jinit_c_master_control jICMaster
+#define jinit_c_main_controller jICMainC
+#define jinit_c_prep_controller jICPrepC
+#define jinit_c_coef_controller jICCoefC
+#define jinit_color_converter jICColor
+#define jinit_downsampler jIDownsampler
+#define jinit_forward_dct jIFDCT
+#define jinit_huff_encoder jIHEncoder
+#define jinit_arith_encoder jIAEncoder
+#define jinit_marker_writer jIMWriter
+#define jinit_master_decompress jIDMaster
+#define jinit_d_main_controller jIDMainC
+#define jinit_d_coef_controller jIDCoefC
+#define jinit_d_post_controller jIDPostC
+#define jinit_input_controller jIInCtlr
+#define jinit_marker_reader jIMReader
+#define jinit_huff_decoder jIHDecoder
+#define jinit_arith_decoder jIADecoder
+#define jinit_inverse_dct jIIDCT
+#define jinit_upsampler jIUpsampler
+#define jinit_color_deconverter jIDColor
+#define jinit_1pass_quantizer jI1Quant
+#define jinit_2pass_quantizer jI2Quant
+#define jinit_merged_upsampler jIMUpsampler
+#define jinit_memory_mgr jIMemMgr
+#define jdiv_round_up jDivRound
+#define jround_up jRound
+#define jzero_far jZeroFar
+#define jcopy_sample_rows jCopySamples
+#define jcopy_block_row jCopyBlocks
+#define jpeg_zigzag_order jZIGTable
+#define jpeg_natural_order jZAGTable
+#define jpeg_natural_order7 jZAG7Table
+#define jpeg_natural_order6 jZAG6Table
+#define jpeg_natural_order5 jZAG5Table
+#define jpeg_natural_order4 jZAG4Table
+#define jpeg_natural_order3 jZAG3Table
+#define jpeg_natural_order2 jZAG2Table
+#define jpeg_aritab jAriTab
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
+ * and coefficient-block arrays. This won't work on 80x86 because the arrays
+ * are FAR and we're assuming a small-pointer memory model. However, some
+ * DOS compilers provide far-pointer versions of memcpy() and memset() even
+ * in the small-model libraries. These will be used if USE_FMEM is defined.
+ * Otherwise, the routines in jutils.c do it the hard way.
+ */
+
+#ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */
+#define FMEMZERO(target,size) MEMZERO(target,size)
+#else /* 80x86 case */
+#ifdef USE_FMEM
+#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size))
+#else
+EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero));
+#define FMEMZERO(target,size) jzero_far(target, size)
+#endif
+#endif
+
+
+/* Compression module initialization routines */
+EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo,
+ boolean transcode_only));
+EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_arith_encoder JPP((j_compress_ptr cinfo));
+EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo));
+/* Decompression module initialization routines */
+EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo,
+ boolean need_full_buffer));
+EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_arith_decoder JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo));
+EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo));
+/* Memory manager initialization */
+EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo));
+
+/* Utility routines in jutils.c */
+EXTERN(long) jdiv_round_up JPP((long a, long b));
+EXTERN(long) jround_up JPP((long a, long b));
+EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row,
+ JSAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols));
+EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row,
+ JDIMENSION num_blocks));
+/* Constant tables in jutils.c */
+#if 0 /* This table is not actually needed in v6a */
+extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */
+#endif
+extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */
+extern const int jpeg_natural_order7[]; /* zz to natural order for 7x7 block */
+extern const int jpeg_natural_order6[]; /* zz to natural order for 6x6 block */
+extern const int jpeg_natural_order5[]; /* zz to natural order for 5x5 block */
+extern const int jpeg_natural_order4[]; /* zz to natural order for 4x4 block */
+extern const int jpeg_natural_order3[]; /* zz to natural order for 3x3 block */
+extern const int jpeg_natural_order2[]; /* zz to natural order for 2x2 block */
+
+/* Arithmetic coding probability estimation tables in jaricom.c */
+extern const INT32 jpeg_aritab[];
+
+/* Suppress undefined-structure complaints if necessary. */
+
+#ifdef INCOMPLETE_TYPES_BROKEN
+#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */
+struct jvirt_sarray_control { long dummy; };
+struct jvirt_barray_control { long dummy; };
+#endif
+#endif /* INCOMPLETE_TYPES_BROKEN */
diff --git a/jpg/jpeglib.h b/jpg/jpeglib.h
new file mode 100644
index 0000000..1327cff
--- /dev/null
+++ b/jpg/jpeglib.h
@@ -0,0 +1,1160 @@
+/*
+ * jpeglib.h
+ *
+ * Copyright (C) 1991-1998, Thomas G. Lane.
+ * Modified 2002-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file defines the application interface for the JPEG library.
+ * Most applications using the library need only include this file,
+ * and perhaps jerror.h if they want to know the exact error codes.
+ */
+
+#ifndef JPEGLIB_H
+#define JPEGLIB_H
+
+/*
+ * First we include the configuration files that record how this
+ * installation of the JPEG library is set up. jconfig.h can be
+ * generated automatically for many systems. jmorecfg.h contains
+ * manual configuration options that most people need not worry about.
+ */
+
+#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */
+#include "jconfig.h" /* widely used configuration options */
+#endif
+#include "jmorecfg.h" /* seldom changed options */
+
+
+#ifdef __cplusplus
+#ifndef DONT_USE_EXTERN_C
+extern "C" {
+#endif
+#endif
+
+/* Version IDs for the JPEG library.
+ * Might be useful for tests like "#if JPEG_LIB_VERSION >= 80".
+ */
+
+#define JPEG_LIB_VERSION 80 /* Compatibility version 8.0 */
+#define JPEG_LIB_VERSION_MAJOR 8
+#define JPEG_LIB_VERSION_MINOR 4
+
+
+/* Various constants determining the sizes of things.
+ * All of these are specified by the JPEG standard, so don't change them
+ * if you want to be compatible.
+ */
+
+#define DCTSIZE 8 /* The basic DCT block is 8x8 coefficients */
+#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */
+#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */
+#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */
+#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */
+#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */
+#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */
+/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard;
+ * the PostScript DCT filter can emit files with many more than 10 blocks/MCU.
+ * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU
+ * to handle it. We even let you do this from the jconfig.h file. However,
+ * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe
+ * sometimes emits noncompliant files doesn't mean you should too.
+ */
+#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */
+#ifndef D_MAX_BLOCKS_IN_MCU
+#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */
+#endif
+
+
+/* Data structures for images (arrays of samples and of DCT coefficients).
+ * On 80x86 machines, the image arrays are too big for near pointers,
+ * but the pointer arrays can fit in near memory.
+ */
+
+typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */
+typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */
+typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */
+
+typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */
+typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */
+typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */
+typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */
+
+typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */
+
+
+/* Types for JPEG compression parameters and working tables. */
+
+
+/* DCT coefficient quantization tables. */
+
+typedef struct {
+ /* This array gives the coefficient quantizers in natural array order
+ * (not the zigzag order in which they are stored in a JPEG DQT marker).
+ * CAUTION: IJG versions prior to v6a kept this array in zigzag order.
+ */
+ UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */
+ /* This field is used only during compression. It's initialized FALSE when
+ * the table is created, and set TRUE when it's been output to the file.
+ * You could suppress output of a table by setting this to TRUE.
+ * (See jpeg_suppress_tables for an example.)
+ */
+ boolean sent_table; /* TRUE when table has been output */
+} JQUANT_TBL;
+
+
+/* Huffman coding tables. */
+
+typedef struct {
+ /* These two fields directly represent the contents of a JPEG DHT marker */
+ UINT8 bits[17]; /* bits[k] = # of symbols with codes of */
+ /* length k bits; bits[0] is unused */
+ UINT8 huffval[256]; /* The symbols, in order of incr code length */
+ /* This field is used only during compression. It's initialized FALSE when
+ * the table is created, and set TRUE when it's been output to the file.
+ * You could suppress output of a table by setting this to TRUE.
+ * (See jpeg_suppress_tables for an example.)
+ */
+ boolean sent_table; /* TRUE when table has been output */
+} JHUFF_TBL;
+
+
+/* Basic info about one component (color channel). */
+
+typedef struct {
+ /* These values are fixed over the whole image. */
+ /* For compression, they must be supplied by parameter setup; */
+ /* for decompression, they are read from the SOF marker. */
+ int component_id; /* identifier for this component (0..255) */
+ int component_index; /* its index in SOF or cinfo->comp_info[] */
+ int h_samp_factor; /* horizontal sampling factor (1..4) */
+ int v_samp_factor; /* vertical sampling factor (1..4) */
+ int quant_tbl_no; /* quantization table selector (0..3) */
+ /* These values may vary between scans. */
+ /* For compression, they must be supplied by parameter setup; */
+ /* for decompression, they are read from the SOS marker. */
+ /* The decompressor output side may not use these variables. */
+ int dc_tbl_no; /* DC entropy table selector (0..3) */
+ int ac_tbl_no; /* AC entropy table selector (0..3) */
+
+ /* Remaining fields should be treated as private by applications. */
+
+ /* These values are computed during compression or decompression startup: */
+ /* Component's size in DCT blocks.
+ * Any dummy blocks added to complete an MCU are not counted; therefore
+ * these values do not depend on whether a scan is interleaved or not.
+ */
+ JDIMENSION width_in_blocks;
+ JDIMENSION height_in_blocks;
+ /* Size of a DCT block in samples,
+ * reflecting any scaling we choose to apply during the DCT step.
+ * Values from 1 to 16 are supported.
+ * Note that different components may receive different DCT scalings.
+ */
+ int DCT_h_scaled_size;
+ int DCT_v_scaled_size;
+ /* The downsampled dimensions are the component's actual, unpadded number
+ * of samples at the main buffer (preprocessing/compression interface);
+ * DCT scaling is included, so
+ * downsampled_width = ceil(image_width * Hi/Hmax * DCT_h_scaled_size/DCTSIZE)
+ * and similarly for height.
+ */
+ JDIMENSION downsampled_width; /* actual width in samples */
+ JDIMENSION downsampled_height; /* actual height in samples */
+ /* This flag is used only for decompression. In cases where some of the
+ * components will be ignored (eg grayscale output from YCbCr image),
+ * we can skip most computations for the unused components.
+ */
+ boolean component_needed; /* do we need the value of this component? */
+
+ /* These values are computed before starting a scan of the component. */
+ /* The decompressor output side may not use these variables. */
+ int MCU_width; /* number of blocks per MCU, horizontally */
+ int MCU_height; /* number of blocks per MCU, vertically */
+ int MCU_blocks; /* MCU_width * MCU_height */
+ int MCU_sample_width; /* MCU width in samples: MCU_width * DCT_h_scaled_size */
+ int last_col_width; /* # of non-dummy blocks across in last MCU */
+ int last_row_height; /* # of non-dummy blocks down in last MCU */
+
+ /* Saved quantization table for component; NULL if none yet saved.
+ * See jdinput.c comments about the need for this information.
+ * This field is currently used only for decompression.
+ */
+ JQUANT_TBL * quant_table;
+
+ /* Private per-component storage for DCT or IDCT subsystem. */
+ void * dct_table;
+} jpeg_component_info;
+
+
+/* The script for encoding a multiple-scan file is an array of these: */
+
+typedef struct {
+ int comps_in_scan; /* number of components encoded in this scan */
+ int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */
+ int Ss, Se; /* progressive JPEG spectral selection parms */
+ int Ah, Al; /* progressive JPEG successive approx. parms */
+} jpeg_scan_info;
+
+/* The decompressor can save APPn and COM markers in a list of these: */
+
+typedef struct jpeg_marker_struct FAR * jpeg_saved_marker_ptr;
+
+struct jpeg_marker_struct {
+ jpeg_saved_marker_ptr next; /* next in list, or NULL */
+ UINT8 marker; /* marker code: JPEG_COM, or JPEG_APP0+n */
+ unsigned int original_length; /* # bytes of data in the file */
+ unsigned int data_length; /* # bytes of data saved at data[] */
+ JOCTET FAR * data; /* the data contained in the marker */
+ /* the marker length word is not counted in data_length or original_length */
+};
+
+/* Known color spaces. */
+
+typedef enum {
+ JCS_UNKNOWN, /* error/unspecified */
+ JCS_GRAYSCALE, /* monochrome */
+ JCS_RGB, /* red/green/blue */
+ JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */
+ JCS_CMYK, /* C/M/Y/K */
+ JCS_YCCK /* Y/Cb/Cr/K */
+} J_COLOR_SPACE;
+
+/* DCT/IDCT algorithm options. */
+
+typedef enum {
+ JDCT_ISLOW, /* slow but accurate integer algorithm */
+ JDCT_IFAST, /* faster, less accurate integer method */
+ JDCT_FLOAT /* floating-point: accurate, fast on fast HW */
+} J_DCT_METHOD;
+
+#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */
+#define JDCT_DEFAULT JDCT_ISLOW
+#endif
+#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */
+#define JDCT_FASTEST JDCT_IFAST
+#endif
+
+/* Dithering options for decompression. */
+
+typedef enum {
+ JDITHER_NONE, /* no dithering */
+ JDITHER_ORDERED, /* simple ordered dither */
+ JDITHER_FS /* Floyd-Steinberg error diffusion dither */
+} J_DITHER_MODE;
+
+
+/* Common fields between JPEG compression and decompression master structs. */
+
+#define jpeg_common_fields \
+ struct jpeg_error_mgr * err; /* Error handler module */\
+ struct jpeg_memory_mgr * mem; /* Memory manager module */\
+ struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\
+ void * client_data; /* Available for use by application */\
+ boolean is_decompressor; /* So common code can tell which is which */\
+ int global_state /* For checking call sequence validity */
+
+/* Routines that are to be used by both halves of the library are declared
+ * to receive a pointer to this structure. There are no actual instances of
+ * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct.
+ */
+struct jpeg_common_struct {
+ jpeg_common_fields; /* Fields common to both master struct types */
+ /* Additional fields follow in an actual jpeg_compress_struct or
+ * jpeg_decompress_struct. All three structs must agree on these
+ * initial fields! (This would be a lot cleaner in C++.)
+ */
+};
+
+typedef struct jpeg_common_struct * j_common_ptr;
+typedef struct jpeg_compress_struct * j_compress_ptr;
+typedef struct jpeg_decompress_struct * j_decompress_ptr;
+
+
+/* Master record for a compression instance */
+
+struct jpeg_compress_struct {
+ jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */
+
+ /* Destination for compressed data */
+ struct jpeg_destination_mgr * dest;
+
+ /* Description of source image --- these fields must be filled in by
+ * outer application before starting compression. in_color_space must
+ * be correct before you can even call jpeg_set_defaults().
+ */
+
+ JDIMENSION image_width; /* input image width */
+ JDIMENSION image_height; /* input image height */
+ int input_components; /* # of color components in input image */
+ J_COLOR_SPACE in_color_space; /* colorspace of input image */
+
+ double input_gamma; /* image gamma of input image */
+
+ /* Compression parameters --- these fields must be set before calling
+ * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to
+ * initialize everything to reasonable defaults, then changing anything
+ * the application specifically wants to change. That way you won't get
+ * burnt when new parameters are added. Also note that there are several
+ * helper routines to simplify changing parameters.
+ */
+
+ unsigned int scale_num, scale_denom; /* fraction by which to scale image */
+
+ JDIMENSION jpeg_width; /* scaled JPEG image width */
+ JDIMENSION jpeg_height; /* scaled JPEG image height */
+ /* Dimensions of actual JPEG image that will be written to file,
+ * derived from input dimensions by scaling factors above.
+ * These fields are computed by jpeg_start_compress().
+ * You can also use jpeg_calc_jpeg_dimensions() to determine these values
+ * in advance of calling jpeg_start_compress().
+ */
+
+ int data_precision; /* bits of precision in image data */
+
+ int num_components; /* # of color components in JPEG image */
+ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
+
+ jpeg_component_info * comp_info;
+ /* comp_info[i] describes component that appears i'th in SOF */
+
+ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
+ int q_scale_factor[NUM_QUANT_TBLS];
+ /* ptrs to coefficient quantization tables, or NULL if not defined,
+ * and corresponding scale factors (percentage, initialized 100).
+ */
+
+ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ /* ptrs to Huffman coding tables, or NULL if not defined */
+
+ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+ int num_scans; /* # of entries in scan_info array */
+ const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */
+ /* The default value of scan_info is NULL, which causes a single-scan
+ * sequential JPEG file to be emitted. To create a multi-scan file,
+ * set num_scans and scan_info to point to an array of scan definitions.
+ */
+
+ boolean raw_data_in; /* TRUE=caller supplies downsampled data */
+ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
+ boolean optimize_coding; /* TRUE=optimize entropy encoding parms */
+ boolean CCIR601_sampling; /* TRUE=first samples are cosited */
+ boolean do_fancy_downsampling; /* TRUE=apply fancy downsampling */
+ int smoothing_factor; /* 1..100, or 0 for no input smoothing */
+ J_DCT_METHOD dct_method; /* DCT algorithm selector */
+
+ /* The restart interval can be specified in absolute MCUs by setting
+ * restart_interval, or in MCU rows by setting restart_in_rows
+ * (in which case the correct restart_interval will be figured
+ * for each scan).
+ */
+ unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */
+ int restart_in_rows; /* if > 0, MCU rows per restart interval */
+
+ /* Parameters controlling emission of special markers. */
+
+ boolean write_JFIF_header; /* should a JFIF marker be written? */
+ UINT8 JFIF_major_version; /* What to write for the JFIF version number */
+ UINT8 JFIF_minor_version;
+ /* These three values are not used by the JPEG code, merely copied */
+ /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */
+ /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */
+ /* ratio is defined by X_density/Y_density even when density_unit=0. */
+ UINT8 density_unit; /* JFIF code for pixel size units */
+ UINT16 X_density; /* Horizontal pixel density */
+ UINT16 Y_density; /* Vertical pixel density */
+ boolean write_Adobe_marker; /* should an Adobe marker be written? */
+
+ /* State variable: index of next scanline to be written to
+ * jpeg_write_scanlines(). Application may use this to control its
+ * processing loop, e.g., "while (next_scanline < image_height)".
+ */
+
+ JDIMENSION next_scanline; /* 0 .. image_height-1 */
+
+ /* Remaining fields are known throughout compressor, but generally
+ * should not be touched by a surrounding application.
+ */
+
+ /*
+ * These fields are computed during compression startup
+ */
+ boolean progressive_mode; /* TRUE if scan script uses progressive mode */
+ int max_h_samp_factor; /* largest h_samp_factor */
+ int max_v_samp_factor; /* largest v_samp_factor */
+
+ int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */
+ int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */
+
+ JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */
+ /* The coefficient controller receives data in units of MCU rows as defined
+ * for fully interleaved scans (whether the JPEG file is interleaved or not).
+ * There are v_samp_factor * DCTSIZE sample rows of each component in an
+ * "iMCU" (interleaved MCU) row.
+ */
+
+ /*
+ * These fields are valid during any one scan.
+ * They describe the components and MCUs actually appearing in the scan.
+ */
+ int comps_in_scan; /* # of JPEG components in this scan */
+ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
+ /* *cur_comp_info[i] describes component that appears i'th in SOS */
+
+ JDIMENSION MCUs_per_row; /* # of MCUs across the image */
+ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
+
+ int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int MCU_membership[C_MAX_BLOCKS_IN_MCU];
+ /* MCU_membership[i] is index in cur_comp_info of component owning */
+ /* i'th block in an MCU */
+
+ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+
+ int block_size; /* the basic DCT block size: 1..16 */
+ const int * natural_order; /* natural-order position array */
+ int lim_Se; /* min( Se, DCTSIZE2-1 ) */
+
+ /*
+ * Links to compression subobjects (methods and private variables of modules)
+ */
+ struct jpeg_comp_master * master;
+ struct jpeg_c_main_controller * main;
+ struct jpeg_c_prep_controller * prep;
+ struct jpeg_c_coef_controller * coef;
+ struct jpeg_marker_writer * marker;
+ struct jpeg_color_converter * cconvert;
+ struct jpeg_downsampler * downsample;
+ struct jpeg_forward_dct * fdct;
+ struct jpeg_entropy_encoder * entropy;
+ jpeg_scan_info * script_space; /* workspace for jpeg_simple_progression */
+ int script_space_size;
+};
+
+
+/* Master record for a decompression instance */
+
+struct jpeg_decompress_struct {
+ jpeg_common_fields; /* Fields shared with jpeg_compress_struct */
+
+ /* Source of compressed data */
+ struct jpeg_source_mgr * src;
+
+ /* Basic description of image --- filled in by jpeg_read_header(). */
+ /* Application may inspect these values to decide how to process image. */
+
+ JDIMENSION image_width; /* nominal image width (from SOF marker) */
+ JDIMENSION image_height; /* nominal image height */
+ int num_components; /* # of color components in JPEG image */
+ J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */
+
+ /* Decompression processing parameters --- these fields must be set before
+ * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes
+ * them to default values.
+ */
+
+ J_COLOR_SPACE out_color_space; /* colorspace for output */
+
+ unsigned int scale_num, scale_denom; /* fraction by which to scale image */
+
+ double output_gamma; /* image gamma wanted in output */
+
+ boolean buffered_image; /* TRUE=multiple output passes */
+ boolean raw_data_out; /* TRUE=downsampled data wanted */
+
+ J_DCT_METHOD dct_method; /* IDCT algorithm selector */
+ boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */
+ boolean do_block_smoothing; /* TRUE=apply interblock smoothing */
+
+ boolean quantize_colors; /* TRUE=colormapped output wanted */
+ /* the following are ignored if not quantize_colors: */
+ J_DITHER_MODE dither_mode; /* type of color dithering to use */
+ boolean two_pass_quantize; /* TRUE=use two-pass color quantization */
+ int desired_number_of_colors; /* max # colors to use in created colormap */
+ /* these are significant only in buffered-image mode: */
+ boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */
+ boolean enable_external_quant;/* enable future use of external colormap */
+ boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */
+
+ /* Description of actual output image that will be returned to application.
+ * These fields are computed by jpeg_start_decompress().
+ * You can also use jpeg_calc_output_dimensions() to determine these values
+ * in advance of calling jpeg_start_decompress().
+ */
+
+ JDIMENSION output_width; /* scaled image width */
+ JDIMENSION output_height; /* scaled image height */
+ int out_color_components; /* # of color components in out_color_space */
+ int output_components; /* # of color components returned */
+ /* output_components is 1 (a colormap index) when quantizing colors;
+ * otherwise it equals out_color_components.
+ */
+ int rec_outbuf_height; /* min recommended height of scanline buffer */
+ /* If the buffer passed to jpeg_read_scanlines() is less than this many rows
+ * high, space and time will be wasted due to unnecessary data copying.
+ * Usually rec_outbuf_height will be 1 or 2, at most 4.
+ */
+
+ /* When quantizing colors, the output colormap is described by these fields.
+ * The application can supply a colormap by setting colormap non-NULL before
+ * calling jpeg_start_decompress; otherwise a colormap is created during
+ * jpeg_start_decompress or jpeg_start_output.
+ * The map has out_color_components rows and actual_number_of_colors columns.
+ */
+ int actual_number_of_colors; /* number of entries in use */
+ JSAMPARRAY colormap; /* The color map as a 2-D pixel array */
+
+ /* State variables: these variables indicate the progress of decompression.
+ * The application may examine these but must not modify them.
+ */
+
+ /* Row index of next scanline to be read from jpeg_read_scanlines().
+ * Application may use this to control its processing loop, e.g.,
+ * "while (output_scanline < output_height)".
+ */
+ JDIMENSION output_scanline; /* 0 .. output_height-1 */
+
+ /* Current input scan number and number of iMCU rows completed in scan.
+ * These indicate the progress of the decompressor input side.
+ */
+ int input_scan_number; /* Number of SOS markers seen so far */
+ JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */
+
+ /* The "output scan number" is the notional scan being displayed by the
+ * output side. The decompressor will not allow output scan/row number
+ * to get ahead of input scan/row, but it can fall arbitrarily far behind.
+ */
+ int output_scan_number; /* Nominal scan number being displayed */
+ JDIMENSION output_iMCU_row; /* Number of iMCU rows read */
+
+ /* Current progression status. coef_bits[c][i] indicates the precision
+ * with which component c's DCT coefficient i (in zigzag order) is known.
+ * It is -1 when no data has yet been received, otherwise it is the point
+ * transform (shift) value for the most recent scan of the coefficient
+ * (thus, 0 at completion of the progression).
+ * This pointer is NULL when reading a non-progressive file.
+ */
+ int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */
+
+ /* Internal JPEG parameters --- the application usually need not look at
+ * these fields. Note that the decompressor output side may not use
+ * any parameters that can change between scans.
+ */
+
+ /* Quantization and Huffman tables are carried forward across input
+ * datastreams when processing abbreviated JPEG datastreams.
+ */
+
+ JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS];
+ /* ptrs to coefficient quantization tables, or NULL if not defined */
+
+ JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS];
+ /* ptrs to Huffman coding tables, or NULL if not defined */
+
+ /* These parameters are never carried across datastreams, since they
+ * are given in SOF/SOS markers or defined to be reset by SOI.
+ */
+
+ int data_precision; /* bits of precision in image data */
+
+ jpeg_component_info * comp_info;
+ /* comp_info[i] describes component that appears i'th in SOF */
+
+ boolean is_baseline; /* TRUE if Baseline SOF0 encountered */
+ boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */
+ boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */
+
+ UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */
+ UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */
+ UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */
+
+ unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */
+
+ /* These fields record data obtained from optional markers recognized by
+ * the JPEG library.
+ */
+ boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */
+ /* Data copied from JFIF marker; only valid if saw_JFIF_marker is TRUE: */
+ UINT8 JFIF_major_version; /* JFIF version number */
+ UINT8 JFIF_minor_version;
+ UINT8 density_unit; /* JFIF code for pixel size units */
+ UINT16 X_density; /* Horizontal pixel density */
+ UINT16 Y_density; /* Vertical pixel density */
+ boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */
+ UINT8 Adobe_transform; /* Color transform code from Adobe marker */
+
+ boolean CCIR601_sampling; /* TRUE=first samples are cosited */
+
+ /* Aside from the specific data retained from APPn markers known to the
+ * library, the uninterpreted contents of any or all APPn and COM markers
+ * can be saved in a list for examination by the application.
+ */
+ jpeg_saved_marker_ptr marker_list; /* Head of list of saved markers */
+
+ /* Remaining fields are known throughout decompressor, but generally
+ * should not be touched by a surrounding application.
+ */
+
+ /*
+ * These fields are computed during decompression startup
+ */
+ int max_h_samp_factor; /* largest h_samp_factor */
+ int max_v_samp_factor; /* largest v_samp_factor */
+
+ int min_DCT_h_scaled_size; /* smallest DCT_h_scaled_size of any component */
+ int min_DCT_v_scaled_size; /* smallest DCT_v_scaled_size of any component */
+
+ JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */
+ /* The coefficient controller's input and output progress is measured in
+ * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows
+ * in fully interleaved JPEG scans, but are used whether the scan is
+ * interleaved or not. We define an iMCU row as v_samp_factor DCT block
+ * rows of each component. Therefore, the IDCT output contains
+ * v_samp_factor*DCT_v_scaled_size sample rows of a component per iMCU row.
+ */
+
+ JSAMPLE * sample_range_limit; /* table for fast range-limiting */
+
+ /*
+ * These fields are valid during any one scan.
+ * They describe the components and MCUs actually appearing in the scan.
+ * Note that the decompressor output side must not use these fields.
+ */
+ int comps_in_scan; /* # of JPEG components in this scan */
+ jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN];
+ /* *cur_comp_info[i] describes component that appears i'th in SOS */
+
+ JDIMENSION MCUs_per_row; /* # of MCUs across the image */
+ JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */
+
+ int blocks_in_MCU; /* # of DCT blocks per MCU */
+ int MCU_membership[D_MAX_BLOCKS_IN_MCU];
+ /* MCU_membership[i] is index in cur_comp_info of component owning */
+ /* i'th block in an MCU */
+
+ int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */
+
+ /* These fields are derived from Se of first SOS marker.
+ */
+ int block_size; /* the basic DCT block size: 1..16 */
+ const int * natural_order; /* natural-order position array for entropy decode */
+ int lim_Se; /* min( Se, DCTSIZE2-1 ) for entropy decode */
+
+ /* This field is shared between entropy decoder and marker parser.
+ * It is either zero or the code of a JPEG marker that has been
+ * read from the data source, but has not yet been processed.
+ */
+ int unread_marker;
+
+ /*
+ * Links to decompression subobjects (methods, private variables of modules)
+ */
+ struct jpeg_decomp_master * master;
+ struct jpeg_d_main_controller * main;
+ struct jpeg_d_coef_controller * coef;
+ struct jpeg_d_post_controller * post;
+ struct jpeg_input_controller * inputctl;
+ struct jpeg_marker_reader * marker;
+ struct jpeg_entropy_decoder * entropy;
+ struct jpeg_inverse_dct * idct;
+ struct jpeg_upsampler * upsample;
+ struct jpeg_color_deconverter * cconvert;
+ struct jpeg_color_quantizer * cquantize;
+};
+
+
+/* "Object" declarations for JPEG modules that may be supplied or called
+ * directly by the surrounding application.
+ * As with all objects in the JPEG library, these structs only define the
+ * publicly visible methods and state variables of a module. Additional
+ * private fields may exist after the public ones.
+ */
+
+
+/* Error handler object */
+
+struct jpeg_error_mgr {
+ /* Error exit handler: does not return to caller */
+ JMETHOD(void, error_exit, (j_common_ptr cinfo));
+ /* Conditionally emit a trace or warning message */
+ JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level));
+ /* Routine that actually outputs a trace or error message */
+ JMETHOD(void, output_message, (j_common_ptr cinfo));
+ /* Format a message string for the most recent JPEG error or message */
+ JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer));
+#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */
+ /* Reset error state variables at start of a new image */
+ JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo));
+
+ /* The message ID code and any parameters are saved here.
+ * A message can have one string parameter or up to 8 int parameters.
+ */
+ int msg_code;
+#define JMSG_STR_PARM_MAX 80
+ union {
+ int i[8];
+ char s[JMSG_STR_PARM_MAX];
+ } msg_parm;
+
+ /* Standard state variables for error facility */
+
+ int trace_level; /* max msg_level that will be displayed */
+
+ /* For recoverable corrupt-data errors, we emit a warning message,
+ * but keep going unless emit_message chooses to abort. emit_message
+ * should count warnings in num_warnings. The surrounding application
+ * can check for bad data by seeing if num_warnings is nonzero at the
+ * end of processing.
+ */
+ long num_warnings; /* number of corrupt-data warnings */
+
+ /* These fields point to the table(s) of error message strings.
+ * An application can change the table pointer to switch to a different
+ * message list (typically, to change the language in which errors are
+ * reported). Some applications may wish to add additional error codes
+ * that will be handled by the JPEG library error mechanism; the second
+ * table pointer is used for this purpose.
+ *
+ * First table includes all errors generated by JPEG library itself.
+ * Error code 0 is reserved for a "no such error string" message.
+ */
+ const char * const * jpeg_message_table; /* Library errors */
+ int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */
+ /* Second table can be added by application (see cjpeg/djpeg for example).
+ * It contains strings numbered first_addon_message..last_addon_message.
+ */
+ const char * const * addon_message_table; /* Non-library errors */
+ int first_addon_message; /* code for first string in addon table */
+ int last_addon_message; /* code for last string in addon table */
+};
+
+
+/* Progress monitor object */
+
+struct jpeg_progress_mgr {
+ JMETHOD(void, progress_monitor, (j_common_ptr cinfo));
+
+ long pass_counter; /* work units completed in this pass */
+ long pass_limit; /* total number of work units in this pass */
+ int completed_passes; /* passes completed so far */
+ int total_passes; /* total number of passes expected */
+};
+
+
+/* Data destination object for compression */
+
+struct jpeg_destination_mgr {
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+
+ JMETHOD(void, init_destination, (j_compress_ptr cinfo));
+ JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo));
+ JMETHOD(void, term_destination, (j_compress_ptr cinfo));
+};
+
+
+/* Data source object for decompression */
+
+struct jpeg_source_mgr {
+ const JOCTET * next_input_byte; /* => next byte to read from buffer */
+ size_t bytes_in_buffer; /* # of bytes remaining in buffer */
+
+ JMETHOD(void, init_source, (j_decompress_ptr cinfo));
+ JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));
+ JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));
+ JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired));
+ JMETHOD(void, term_source, (j_decompress_ptr cinfo));
+};
+
+
+/* Memory manager object.
+ * Allocates "small" objects (a few K total), "large" objects (tens of K),
+ * and "really big" objects (virtual arrays with backing store if needed).
+ * The memory manager does not allow individual objects to be freed; rather,
+ * each created object is assigned to a pool, and whole pools can be freed
+ * at once. This is faster and more convenient than remembering exactly what
+ * to free, especially where malloc()/free() are not too speedy.
+ * NB: alloc routines never return NULL. They exit to error_exit if not
+ * successful.
+ */
+
+#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */
+#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */
+#define JPOOL_NUMPOOLS 2
+
+typedef struct jvirt_sarray_control * jvirt_sarray_ptr;
+typedef struct jvirt_barray_control * jvirt_barray_ptr;
+
+
+struct jpeg_memory_mgr {
+ /* Method pointers */
+ JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id,
+ size_t sizeofobject));
+ JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id,
+ size_t sizeofobject));
+ JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id,
+ JDIMENSION samplesperrow,
+ JDIMENSION numrows));
+ JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id,
+ JDIMENSION blocksperrow,
+ JDIMENSION numrows));
+ JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo,
+ int pool_id,
+ boolean pre_zero,
+ JDIMENSION samplesperrow,
+ JDIMENSION numrows,
+ JDIMENSION maxaccess));
+ JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo,
+ int pool_id,
+ boolean pre_zero,
+ JDIMENSION blocksperrow,
+ JDIMENSION numrows,
+ JDIMENSION maxaccess));
+ JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo));
+ JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo,
+ jvirt_sarray_ptr ptr,
+ JDIMENSION start_row,
+ JDIMENSION num_rows,
+ boolean writable));
+ JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo,
+ jvirt_barray_ptr ptr,
+ JDIMENSION start_row,
+ JDIMENSION num_rows,
+ boolean writable));
+ JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id));
+ JMETHOD(void, self_destruct, (j_common_ptr cinfo));
+
+ /* Limit on memory allocation for this JPEG object. (Note that this is
+ * merely advisory, not a guaranteed maximum; it only affects the space
+ * used for virtual-array buffers.) May be changed by outer application
+ * after creating the JPEG object.
+ */
+ long max_memory_to_use;
+
+ /* Maximum allocation request accepted by alloc_large. */
+ long max_alloc_chunk;
+};
+
+
+/* Routine signature for application-supplied marker processing methods.
+ * Need not pass marker code since it is stored in cinfo->unread_marker.
+ */
+typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo));
+
+
+/* Declarations for routines called by application.
+ * The JPP macro hides prototype parameters from compilers that can't cope.
+ * Note JPP requires double parentheses.
+ */
+
+#ifdef HAVE_PROTOTYPES
+#define JPP(arglist) arglist
+#else
+#define JPP(arglist) ()
+#endif
+
+
+/* Short forms of external names for systems with brain-damaged linkers.
+ * We shorten external names to be unique in the first six letters, which
+ * is good enough for all known systems.
+ * (If your compiler itself needs names to be unique in less than 15
+ * characters, you are out of luck. Get a better compiler.)
+ */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jpeg_std_error jStdError
+#define jpeg_CreateCompress jCreaCompress
+#define jpeg_CreateDecompress jCreaDecompress
+#define jpeg_destroy_compress jDestCompress
+#define jpeg_destroy_decompress jDestDecompress
+#define jpeg_stdio_dest jStdDest
+#define jpeg_stdio_src jStdSrc
+#define jpeg_mem_dest jMemDest
+#define jpeg_mem_src jMemSrc
+#define jpeg_set_defaults jSetDefaults
+#define jpeg_set_colorspace jSetColorspace
+#define jpeg_default_colorspace jDefColorspace
+#define jpeg_set_quality jSetQuality
+#define jpeg_set_linear_quality jSetLQuality
+#define jpeg_default_qtables jDefQTables
+#define jpeg_add_quant_table jAddQuantTable
+#define jpeg_quality_scaling jQualityScaling
+#define jpeg_simple_progression jSimProgress
+#define jpeg_suppress_tables jSuppressTables
+#define jpeg_alloc_quant_table jAlcQTable
+#define jpeg_alloc_huff_table jAlcHTable
+#define jpeg_start_compress jStrtCompress
+#define jpeg_write_scanlines jWrtScanlines
+#define jpeg_finish_compress jFinCompress
+#define jpeg_calc_jpeg_dimensions jCjpegDimensions
+#define jpeg_write_raw_data jWrtRawData
+#define jpeg_write_marker jWrtMarker
+#define jpeg_write_m_header jWrtMHeader
+#define jpeg_write_m_byte jWrtMByte
+#define jpeg_write_tables jWrtTables
+#define jpeg_read_header jReadHeader
+#define jpeg_start_decompress jStrtDecompress
+#define jpeg_read_scanlines jReadScanlines
+#define jpeg_finish_decompress jFinDecompress
+#define jpeg_read_raw_data jReadRawData
+#define jpeg_has_multiple_scans jHasMultScn
+#define jpeg_start_output jStrtOutput
+#define jpeg_finish_output jFinOutput
+#define jpeg_input_complete jInComplete
+#define jpeg_new_colormap jNewCMap
+#define jpeg_consume_input jConsumeInput
+#define jpeg_core_output_dimensions jCoreDimensions
+#define jpeg_calc_output_dimensions jCalcDimensions
+#define jpeg_save_markers jSaveMarkers
+#define jpeg_set_marker_processor jSetMarker
+#define jpeg_read_coefficients jReadCoefs
+#define jpeg_write_coefficients jWrtCoefs
+#define jpeg_copy_critical_parameters jCopyCrit
+#define jpeg_abort_compress jAbrtCompress
+#define jpeg_abort_decompress jAbrtDecompress
+#define jpeg_abort jAbort
+#define jpeg_destroy jDestroy
+#define jpeg_resync_to_restart jResyncRestart
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/* Default error-management setup */
+EXTERN(struct jpeg_error_mgr *) jpeg_std_error
+ JPP((struct jpeg_error_mgr * err));
+
+/* Initialization of JPEG compression objects.
+ * jpeg_create_compress() and jpeg_create_decompress() are the exported
+ * names that applications should call. These expand to calls on
+ * jpeg_CreateCompress and jpeg_CreateDecompress with additional information
+ * passed for version mismatch checking.
+ * NB: you must set up the error-manager BEFORE calling jpeg_create_xxx.
+ */
+#define jpeg_create_compress(cinfo) \
+ jpeg_CreateCompress((cinfo), JPEG_LIB_VERSION, \
+ (size_t) sizeof(struct jpeg_compress_struct))
+#define jpeg_create_decompress(cinfo) \
+ jpeg_CreateDecompress((cinfo), JPEG_LIB_VERSION, \
+ (size_t) sizeof(struct jpeg_decompress_struct))
+EXTERN(void) jpeg_CreateCompress JPP((j_compress_ptr cinfo,
+ int version, size_t structsize));
+EXTERN(void) jpeg_CreateDecompress JPP((j_decompress_ptr cinfo,
+ int version, size_t structsize));
+/* Destruction of JPEG compression objects */
+EXTERN(void) jpeg_destroy_compress JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_destroy_decompress JPP((j_decompress_ptr cinfo));
+
+/* Standard data source and destination managers: stdio streams. */
+/* Caller is responsible for opening the file before and closing after. */
+EXTERN(void) jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile));
+EXTERN(void) jpeg_stdio_src JPP((j_decompress_ptr cinfo, FILE * infile));
+
+/* Data source and destination managers: memory buffers. */
+EXTERN(void) jpeg_mem_dest JPP((j_compress_ptr cinfo,
+ unsigned char ** outbuffer,
+ unsigned long * outsize));
+EXTERN(void) jpeg_mem_src JPP((j_decompress_ptr cinfo,
+ unsigned char * inbuffer,
+ unsigned long insize));
+
+/* Default parameter setup for compression */
+EXTERN(void) jpeg_set_defaults JPP((j_compress_ptr cinfo));
+/* Compression parameter setup aids */
+EXTERN(void) jpeg_set_colorspace JPP((j_compress_ptr cinfo,
+ J_COLOR_SPACE colorspace));
+EXTERN(void) jpeg_default_colorspace JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_set_quality JPP((j_compress_ptr cinfo, int quality,
+ boolean force_baseline));
+EXTERN(void) jpeg_set_linear_quality JPP((j_compress_ptr cinfo,
+ int scale_factor,
+ boolean force_baseline));
+EXTERN(void) jpeg_default_qtables JPP((j_compress_ptr cinfo,
+ boolean force_baseline));
+EXTERN(void) jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl,
+ const unsigned int *basic_table,
+ int scale_factor,
+ boolean force_baseline));
+EXTERN(int) jpeg_quality_scaling JPP((int quality));
+EXTERN(void) jpeg_simple_progression JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_suppress_tables JPP((j_compress_ptr cinfo,
+ boolean suppress));
+EXTERN(JQUANT_TBL *) jpeg_alloc_quant_table JPP((j_common_ptr cinfo));
+EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table JPP((j_common_ptr cinfo));
+
+/* Main entry points for compression */
+EXTERN(void) jpeg_start_compress JPP((j_compress_ptr cinfo,
+ boolean write_all_tables));
+EXTERN(JDIMENSION) jpeg_write_scanlines JPP((j_compress_ptr cinfo,
+ JSAMPARRAY scanlines,
+ JDIMENSION num_lines));
+EXTERN(void) jpeg_finish_compress JPP((j_compress_ptr cinfo));
+
+/* Precalculate JPEG dimensions for current compression parameters. */
+EXTERN(void) jpeg_calc_jpeg_dimensions JPP((j_compress_ptr cinfo));
+
+/* Replaces jpeg_write_scanlines when writing raw downsampled data. */
+EXTERN(JDIMENSION) jpeg_write_raw_data JPP((j_compress_ptr cinfo,
+ JSAMPIMAGE data,
+ JDIMENSION num_lines));
+
+/* Write a special marker. See libjpeg.txt concerning safe usage. */
+EXTERN(void) jpeg_write_marker
+ JPP((j_compress_ptr cinfo, int marker,
+ const JOCTET * dataptr, unsigned int datalen));
+/* Same, but piecemeal. */
+EXTERN(void) jpeg_write_m_header
+ JPP((j_compress_ptr cinfo, int marker, unsigned int datalen));
+EXTERN(void) jpeg_write_m_byte
+ JPP((j_compress_ptr cinfo, int val));
+
+/* Alternate compression function: just write an abbreviated table file */
+EXTERN(void) jpeg_write_tables JPP((j_compress_ptr cinfo));
+
+/* Decompression startup: read start of JPEG datastream to see what's there */
+EXTERN(int) jpeg_read_header JPP((j_decompress_ptr cinfo,
+ boolean require_image));
+/* Return value is one of: */
+#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */
+#define JPEG_HEADER_OK 1 /* Found valid image datastream */
+#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */
+/* If you pass require_image = TRUE (normal case), you need not check for
+ * a TABLES_ONLY return code; an abbreviated file will cause an error exit.
+ * JPEG_SUSPENDED is only possible if you use a data source module that can
+ * give a suspension return (the stdio source module doesn't).
+ */
+
+/* Main entry points for decompression */
+EXTERN(boolean) jpeg_start_decompress JPP((j_decompress_ptr cinfo));
+EXTERN(JDIMENSION) jpeg_read_scanlines JPP((j_decompress_ptr cinfo,
+ JSAMPARRAY scanlines,
+ JDIMENSION max_lines));
+EXTERN(boolean) jpeg_finish_decompress JPP((j_decompress_ptr cinfo));
+
+/* Replaces jpeg_read_scanlines when reading raw downsampled data. */
+EXTERN(JDIMENSION) jpeg_read_raw_data JPP((j_decompress_ptr cinfo,
+ JSAMPIMAGE data,
+ JDIMENSION max_lines));
+
+/* Additional entry points for buffered-image mode. */
+EXTERN(boolean) jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo));
+EXTERN(boolean) jpeg_start_output JPP((j_decompress_ptr cinfo,
+ int scan_number));
+EXTERN(boolean) jpeg_finish_output JPP((j_decompress_ptr cinfo));
+EXTERN(boolean) jpeg_input_complete JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_new_colormap JPP((j_decompress_ptr cinfo));
+EXTERN(int) jpeg_consume_input JPP((j_decompress_ptr cinfo));
+/* Return value is one of: */
+/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */
+#define JPEG_REACHED_SOS 1 /* Reached start of new scan */
+#define JPEG_REACHED_EOI 2 /* Reached end of image */
+#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */
+#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */
+
+/* Precalculate output dimensions for current decompression parameters. */
+EXTERN(void) jpeg_core_output_dimensions JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo));
+
+/* Control saving of COM and APPn markers into marker_list. */
+EXTERN(void) jpeg_save_markers
+ JPP((j_decompress_ptr cinfo, int marker_code,
+ unsigned int length_limit));
+
+/* Install a special processing method for COM or APPn markers. */
+EXTERN(void) jpeg_set_marker_processor
+ JPP((j_decompress_ptr cinfo, int marker_code,
+ jpeg_marker_parser_method routine));
+
+/* Read or write raw DCT coefficients --- useful for lossless transcoding. */
+EXTERN(jvirt_barray_ptr *) jpeg_read_coefficients JPP((j_decompress_ptr cinfo));
+EXTERN(void) jpeg_write_coefficients JPP((j_compress_ptr cinfo,
+ jvirt_barray_ptr * coef_arrays));
+EXTERN(void) jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo,
+ j_compress_ptr dstinfo));
+
+/* If you choose to abort compression or decompression before completing
+ * jpeg_finish_(de)compress, then you need to clean up to release memory,
+ * temporary files, etc. You can just call jpeg_destroy_(de)compress
+ * if you're done with the JPEG object, but if you want to clean it up and
+ * reuse it, call this:
+ */
+EXTERN(void) jpeg_abort_compress JPP((j_compress_ptr cinfo));
+EXTERN(void) jpeg_abort_decompress JPP((j_decompress_ptr cinfo));
+
+/* Generic versions of jpeg_abort and jpeg_destroy that work on either
+ * flavor of JPEG object. These may be more convenient in some places.
+ */
+EXTERN(void) jpeg_abort JPP((j_common_ptr cinfo));
+EXTERN(void) jpeg_destroy JPP((j_common_ptr cinfo));
+
+/* Default restart-marker-resync procedure for use by data source modules */
+EXTERN(boolean) jpeg_resync_to_restart JPP((j_decompress_ptr cinfo,
+ int desired));
+
+
+/* These marker codes are exported since applications and data source modules
+ * are likely to want to use them.
+ */
+
+#define JPEG_RST0 0xD0 /* RST0 marker code */
+#define JPEG_EOI 0xD9 /* EOI marker code */
+#define JPEG_APP0 0xE0 /* APP0 marker code */
+#define JPEG_COM 0xFE /* COM marker code */
+
+
+/* If we have a brain-damaged compiler that emits warnings (or worse, errors)
+ * for structure definitions that are never filled in, keep it quiet by
+ * supplying dummy definitions for the various substructures.
+ */
+
+#ifdef INCOMPLETE_TYPES_BROKEN
+#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */
+struct jvirt_sarray_control { long dummy; };
+struct jvirt_barray_control { long dummy; };
+struct jpeg_comp_master { long dummy; };
+struct jpeg_c_main_controller { long dummy; };
+struct jpeg_c_prep_controller { long dummy; };
+struct jpeg_c_coef_controller { long dummy; };
+struct jpeg_marker_writer { long dummy; };
+struct jpeg_color_converter { long dummy; };
+struct jpeg_downsampler { long dummy; };
+struct jpeg_forward_dct { long dummy; };
+struct jpeg_entropy_encoder { long dummy; };
+struct jpeg_decomp_master { long dummy; };
+struct jpeg_d_main_controller { long dummy; };
+struct jpeg_d_coef_controller { long dummy; };
+struct jpeg_d_post_controller { long dummy; };
+struct jpeg_input_controller { long dummy; };
+struct jpeg_marker_reader { long dummy; };
+struct jpeg_entropy_decoder { long dummy; };
+struct jpeg_inverse_dct { long dummy; };
+struct jpeg_upsampler { long dummy; };
+struct jpeg_color_deconverter { long dummy; };
+struct jpeg_color_quantizer { long dummy; };
+#endif /* JPEG_INTERNALS */
+#endif /* INCOMPLETE_TYPES_BROKEN */
+
+
+/*
+ * The JPEG library modules define JPEG_INTERNALS before including this file.
+ * The internal structure declarations are read only when that is true.
+ * Applications using the library should not include jpegint.h, but may wish
+ * to include jerror.h.
+ */
+
+#ifdef JPEG_INTERNALS
+#include "jpegint.h" /* fetch private declarations */
+#include "jerror.h" /* fetch error codes too */
+#endif
+
+#ifdef __cplusplus
+#ifndef DONT_USE_EXTERN_C
+}
+#endif
+#endif
+
+#endif /* JPEGLIB_H */
diff --git a/jpg/jpegsr8d.zip b/jpg/jpegsr8d.zip
new file mode 100644
index 0000000..9a12a90
--- /dev/null
+++ b/jpg/jpegsr8d.zip
Binary files differ
diff --git a/jpg/jpegtran.1 b/jpg/jpegtran.1
new file mode 100644
index 0000000..0ad1bbc
--- /dev/null
+++ b/jpg/jpegtran.1
@@ -0,0 +1,285 @@
+.TH JPEGTRAN 1 "28 December 2009"
+.SH NAME
+jpegtran \- lossless transformation of JPEG files
+.SH SYNOPSIS
+.B jpegtran
+[
+.I options
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B jpegtran
+performs various useful transformations of JPEG files.
+It can translate the coded representation from one variant of JPEG to another,
+for example from baseline JPEG to progressive JPEG or vice versa. It can also
+perform some rearrangements of the image data, for example turning an image
+from landscape to portrait format by rotation.
+.PP
+.B jpegtran
+works by rearranging the compressed data (DCT coefficients), without
+ever fully decoding the image. Therefore, its transformations are lossless:
+there is no image degradation at all, which would not be true if you used
+.B djpeg
+followed by
+.B cjpeg
+to accomplish the same conversion. But by the same token,
+.B jpegtran
+cannot perform lossy operations such as changing the image quality.
+.PP
+.B jpegtran
+reads the named JPEG/JFIF file, or the standard input if no file is
+named, and produces a JPEG/JFIF file on the standard output.
+.SH OPTIONS
+All switch names may be abbreviated; for example,
+.B \-optimize
+may be written
+.B \-opt
+or
+.BR \-o .
+Upper and lower case are equivalent.
+British spellings are also accepted (e.g.,
+.BR \-optimise ),
+though for brevity these are not mentioned below.
+.PP
+To specify the coded JPEG representation used in the output file,
+.B jpegtran
+accepts a subset of the switches recognized by
+.BR cjpeg :
+.TP
+.B \-optimize
+Perform optimization of entropy encoding parameters.
+.TP
+.B \-progressive
+Create progressive JPEG file.
+.TP
+.BI \-restart " N"
+Emit a JPEG restart marker every N MCU rows, or every N MCU blocks if "B" is
+attached to the number.
+.TP
+.B \-arithmetic
+Use arithmetic coding.
+.TP
+.BI \-scans " file"
+Use the scan script given in the specified text file.
+.PP
+See
+.BR cjpeg (1)
+for more details about these switches.
+If you specify none of these switches, you get a plain baseline-JPEG output
+file. The quality setting and so forth are determined by the input file.
+.PP
+The image can be losslessly transformed by giving one of these switches:
+.TP
+.B \-flip horizontal
+Mirror image horizontally (left-right).
+.TP
+.B \-flip vertical
+Mirror image vertically (top-bottom).
+.TP
+.B \-rotate 90
+Rotate image 90 degrees clockwise.
+.TP
+.B \-rotate 180
+Rotate image 180 degrees.
+.TP
+.B \-rotate 270
+Rotate image 270 degrees clockwise (or 90 ccw).
+.TP
+.B \-transpose
+Transpose image (across UL-to-LR axis).
+.TP
+.B \-transverse
+Transverse transpose (across UR-to-LL axis).
+.IP
+The transpose transformation has no restrictions regarding image dimensions.
+The other transformations operate rather oddly if the image dimensions are not
+a multiple of the iMCU size (usually 8 or 16 pixels), because they can only
+transform complete blocks of DCT coefficient data in the desired way.
+.IP
+.BR jpegtran 's
+default behavior when transforming an odd-size image is designed
+to preserve exact reversibility and mathematical consistency of the
+transformation set. As stated, transpose is able to flip the entire image
+area. Horizontal mirroring leaves any partial iMCU column at the right edge
+untouched, but is able to flip all rows of the image. Similarly, vertical
+mirroring leaves any partial iMCU row at the bottom edge untouched, but is
+able to flip all columns. The other transforms can be built up as sequences
+of transpose and flip operations; for consistency, their actions on edge
+pixels are defined to be the same as the end result of the corresponding
+transpose-and-flip sequence.
+.IP
+For practical use, you may prefer to discard any untransformable edge pixels
+rather than having a strange-looking strip along the right and/or bottom edges
+of a transformed image. To do this, add the
+.B \-trim
+switch:
+.TP
+.B \-trim
+Drop non-transformable edge blocks.
+.IP
+Obviously, a transformation with
+.B \-trim
+is not reversible, so strictly speaking
+.B jpegtran
+with this switch is not lossless. Also, the expected mathematical
+equivalences between the transformations no longer hold. For example,
+.B \-rot 270 -trim
+trims only the bottom edge, but
+.B \-rot 90 -trim
+followed by
+.B \-rot 180 -trim
+trims both edges.
+.IP
+If you are only interested in perfect transformation, add the
+.B \-perfect
+switch:
+.TP
+.B \-perfect
+Fails with an error if the transformation is not perfect.
+.IP
+For example you may want to do
+.IP
+.B (jpegtran \-rot 90 -perfect
+.I foo.jpg
+.B || djpeg
+.I foo.jpg
+.B | pnmflip \-r90 | cjpeg)
+.IP
+to do a perfect rotation if available or an approximated one if not.
+.PP
+We also offer a lossless-crop option, which discards data outside a given
+image region but losslessly preserves what is inside. Like the rotate and
+flip transforms, lossless crop is restricted by the current JPEG format: the
+upper left corner of the selected region must fall on an iMCU boundary. If
+this does not hold for the given crop parameters, we silently move the upper
+left corner up and/or left to make it so, simultaneously increasing the region
+dimensions to keep the lower right crop corner unchanged. (Thus, the output
+image covers at least the requested region, but may cover more.)
+
+The image can be losslessly cropped by giving the switch:
+.TP
+.B \-crop WxH+X+Y
+Crop to a rectangular subarea of width W, height H starting at point X,Y.
+.PP
+Other not-strictly-lossless transformation switches are:
+.TP
+.B \-grayscale
+Force grayscale output.
+.IP
+This option discards the chrominance channels if the input image is YCbCr
+(ie, a standard color JPEG), resulting in a grayscale JPEG file. The
+luminance channel is preserved exactly, so this is a better method of reducing
+to grayscale than decompression, conversion, and recompression. This switch
+is particularly handy for fixing a monochrome picture that was mistakenly
+encoded as a color JPEG. (In such a case, the space savings from getting rid
+of the near-empty chroma channels won't be large; but the decoding time for
+a grayscale JPEG is substantially less than that for a color JPEG.)
+.TP
+.BI \-scale " M/N"
+Scale the output image by a factor M/N.
+.IP
+Currently supported scale factors are M/N with all M from 1 to 16, where N is
+the source DCT size, which is 8 for baseline JPEG. If the /N part is omitted,
+then M specifies the DCT scaled size to be applied on the given input. For
+baseline JPEG this is equivalent to M/8 scaling, since the source DCT size
+for baseline JPEG is 8.
+.B Caution:
+An implementation of the JPEG SmartScale extension is required for this
+feature. SmartScale enabled JPEG is not yet widely implemented, so many
+decoders will be unable to view a SmartScale extended JPEG file at all.
+.PP
+.B jpegtran
+also recognizes these switches that control what to do with "extra" markers,
+such as comment blocks:
+.TP
+.B \-copy none
+Copy no extra markers from source file. This setting suppresses all
+comments and other excess baggage present in the source file.
+.TP
+.B \-copy comments
+Copy only comment markers. This setting copies comments from the source file,
+but discards any other inessential (for image display) data.
+.TP
+.B \-copy all
+Copy all extra markers. This setting preserves miscellaneous markers
+found in the source file, such as JFIF thumbnails, Exif data, and Photoshop
+settings. In some files these extra markers can be sizable.
+.IP
+The default behavior is
+.BR "\-copy comments" .
+(Note: in IJG releases v6 and v6a,
+.B jpegtran
+always did the equivalent of
+.BR "\-copy none" .)
+.PP
+Additional switches recognized by jpegtran are:
+.TP
+.BI \-maxmemory " N"
+Set limit for amount of memory to use in processing large images. Value is
+in thousands of bytes, or millions of bytes if "M" is attached to the
+number. For example,
+.B \-max 4m
+selects 4000000 bytes. If more space is needed, temporary files will be used.
+.TP
+.BI \-outfile " name"
+Send output image to the named file, not to standard output.
+.TP
+.B \-verbose
+Enable debug printout. More
+.BR \-v 's
+give more output. Also, version information is printed at startup.
+.TP
+.B \-debug
+Same as
+.BR \-verbose .
+.SH EXAMPLES
+.LP
+This example converts a baseline JPEG file to progressive form:
+.IP
+.B jpegtran \-progressive
+.I foo.jpg
+.B >
+.I fooprog.jpg
+.PP
+This example rotates an image 90 degrees clockwise, discarding any
+unrotatable edge pixels:
+.IP
+.B jpegtran \-rot 90 -trim
+.I foo.jpg
+.B >
+.I foo90.jpg
+.SH ENVIRONMENT
+.TP
+.B JPEGMEM
+If this environment variable is set, its value is the default memory limit.
+The value is specified as described for the
+.B \-maxmemory
+switch.
+.B JPEGMEM
+overrides the default value specified when the program was compiled, and
+itself is overridden by an explicit
+.BR \-maxmemory .
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR djpeg (1),
+.BR rdjpgcom (1),
+.BR wrjpgcom (1)
+.br
+Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34, no. 4), pp. 30-44.
+.SH AUTHOR
+Independent JPEG Group
+.SH BUGS
+The transform options can't transform odd-size images perfectly. Use
+.B \-trim
+or
+.B \-perfect
+if you don't like the results.
+.PP
+The entire image is read into memory and then written out again, even in
+cases where this isn't really necessary. Expect swapping on large images,
+especially when using the more complex transform options.
diff --git a/jpg/jpegtran.c b/jpg/jpegtran.c
new file mode 100644
index 0000000..e539e91
--- /dev/null
+++ b/jpg/jpegtran.c
@@ -0,0 +1,560 @@
+/*
+ * jpegtran.c
+ *
+ * Copyright (C) 1995-2011, Thomas G. Lane, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a command-line user interface for JPEG transcoding.
+ * It is very similar to cjpeg.c, and partly to djpeg.c, but provides
+ * lossless transcoding between different JPEG file formats. It also
+ * provides some lossless and sort-of-lossless transformations of JPEG data.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include "transupp.h" /* Support routines for jpegtran */
+#include "jversion.h" /* for version message */
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+
+/*
+ * Argument-parsing code.
+ * The switch parser is designed to be useful with DOS-style command line
+ * syntax, ie, intermixed switches and file names, where only the switches
+ * to the left of a given file name affect processing of that file.
+ * The main program in this file doesn't actually use this capability...
+ */
+
+
+static const char * progname; /* program name for error messages */
+static char * outfilename; /* for -outfile switch */
+static char * scaleoption; /* -scale switch */
+static JCOPY_OPTION copyoption; /* -copy switch */
+static jpeg_transform_info transformoption; /* image transformation options */
+
+
+LOCAL(void)
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "inputfile outputfile\n");
+#else
+ fprintf(stderr, "[inputfile]\n");
+#endif
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -copy none Copy no extra markers from source file\n");
+ fprintf(stderr, " -copy comments Copy only comment markers (default)\n");
+ fprintf(stderr, " -copy all Copy all extra markers\n");
+#ifdef ENTROPY_OPT_SUPPORTED
+ fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n");
+#endif
+#ifdef C_PROGRESSIVE_SUPPORTED
+ fprintf(stderr, " -progressive Create progressive JPEG file\n");
+#endif
+ fprintf(stderr, "Switches for modifying the image:\n");
+#if TRANSFORMS_SUPPORTED
+ fprintf(stderr, " -crop WxH+X+Y Crop to a rectangular subarea\n");
+ fprintf(stderr, " -grayscale Reduce to grayscale (omit color data)\n");
+ fprintf(stderr, " -flip [horizontal|vertical] Mirror image (left-right or top-bottom)\n");
+ fprintf(stderr, " -perfect Fail if there is non-transformable edge blocks\n");
+ fprintf(stderr, " -rotate [90|180|270] Rotate image (degrees clockwise)\n");
+#endif
+ fprintf(stderr, " -scale M/N Scale output image by fraction M/N, eg, 1/8\n");
+#if TRANSFORMS_SUPPORTED
+ fprintf(stderr, " -transpose Transpose image\n");
+ fprintf(stderr, " -transverse Transverse transpose image\n");
+ fprintf(stderr, " -trim Drop non-transformable edge blocks\n");
+#endif
+ fprintf(stderr, "Switches for advanced users:\n");
+#ifdef C_ARITH_CODING_SUPPORTED
+ fprintf(stderr, " -arithmetic Use arithmetic coding\n");
+#endif
+ fprintf(stderr, " -restart N Set restart interval in rows, or in blocks with B\n");
+ fprintf(stderr, " -maxmemory N Maximum memory to use (in kbytes)\n");
+ fprintf(stderr, " -outfile name Specify name for output file\n");
+ fprintf(stderr, " -verbose or -debug Emit debug output\n");
+ fprintf(stderr, "Switches for wizards:\n");
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ fprintf(stderr, " -scans file Create multi-scan JPEG per script file\n");
+#endif
+ exit(EXIT_FAILURE);
+}
+
+
+LOCAL(void)
+select_transform (JXFORM_CODE transform)
+/* Silly little routine to detect multiple transform options,
+ * which we can't handle.
+ */
+{
+#if TRANSFORMS_SUPPORTED
+ if (transformoption.transform == JXFORM_NONE ||
+ transformoption.transform == transform) {
+ transformoption.transform = transform;
+ } else {
+ fprintf(stderr, "%s: can only do one image transformation at a time\n",
+ progname);
+ usage();
+ }
+#else
+ fprintf(stderr, "%s: sorry, image transformation was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+}
+
+
+LOCAL(int)
+parse_switches (j_compress_ptr cinfo, int argc, char **argv,
+ int last_file_arg_seen, boolean for_real)
+/* Parse optional switches.
+ * Returns argv[] index of first file-name argument (== argc if none).
+ * Any file names with indexes <= last_file_arg_seen are ignored;
+ * they have presumably been processed in a previous iteration.
+ * (Pass 0 for last_file_arg_seen on the first or only iteration.)
+ * for_real is FALSE on the first (dummy) pass; we may skip any expensive
+ * processing.
+ */
+{
+ int argn;
+ char * arg;
+ boolean simple_progressive;
+ char * scansarg = NULL; /* saves -scans parm if any */
+
+ /* Set up default JPEG parameters. */
+ simple_progressive = FALSE;
+ outfilename = NULL;
+ scaleoption = NULL;
+ copyoption = JCOPYOPT_DEFAULT;
+ transformoption.transform = JXFORM_NONE;
+ transformoption.perfect = FALSE;
+ transformoption.trim = FALSE;
+ transformoption.force_grayscale = FALSE;
+ transformoption.crop = FALSE;
+ cinfo->err->trace_level = 0;
+
+ /* Scan command line options, adjust parameters */
+
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (*arg != '-') {
+ /* Not a switch, must be a file name argument */
+ if (argn <= last_file_arg_seen) {
+ outfilename = NULL; /* -outfile applies to just one input file */
+ continue; /* ignore this name if previously processed */
+ }
+ break; /* else done parsing switches */
+ }
+ arg++; /* advance past switch marker character */
+
+ if (keymatch(arg, "arithmetic", 1)) {
+ /* Use arithmetic coding. */
+#ifdef C_ARITH_CODING_SUPPORTED
+ cinfo->arith_code = TRUE;
+#else
+ fprintf(stderr, "%s: sorry, arithmetic coding not supported\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "copy", 2)) {
+ /* Select which extra markers to copy. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "none", 1)) {
+ copyoption = JCOPYOPT_NONE;
+ } else if (keymatch(argv[argn], "comments", 1)) {
+ copyoption = JCOPYOPT_COMMENTS;
+ } else if (keymatch(argv[argn], "all", 1)) {
+ copyoption = JCOPYOPT_ALL;
+ } else
+ usage();
+
+ } else if (keymatch(arg, "crop", 2)) {
+ /* Perform lossless cropping. */
+#if TRANSFORMS_SUPPORTED
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (! jtransform_parse_crop_spec(&transformoption, argv[argn])) {
+ fprintf(stderr, "%s: bogus -crop argument '%s'\n",
+ progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+#else
+ select_transform(JXFORM_NONE); /* force an error */
+#endif
+
+ } else if (keymatch(arg, "debug", 1) || keymatch(arg, "verbose", 1)) {
+ /* Enable debug printouts. */
+ /* On first -d, print version identification */
+ static boolean printed_version = FALSE;
+
+ if (! printed_version) {
+ fprintf(stderr, "Independent JPEG Group's JPEGTRAN, version %s\n%s\n",
+ JVERSION, JCOPYRIGHT);
+ printed_version = TRUE;
+ }
+ cinfo->err->trace_level++;
+
+ } else if (keymatch(arg, "flip", 1)) {
+ /* Mirror left-right or top-bottom. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "horizontal", 1))
+ select_transform(JXFORM_FLIP_H);
+ else if (keymatch(argv[argn], "vertical", 1))
+ select_transform(JXFORM_FLIP_V);
+ else
+ usage();
+
+ } else if (keymatch(arg, "grayscale", 1) || keymatch(arg, "greyscale",1)) {
+ /* Force to grayscale. */
+#if TRANSFORMS_SUPPORTED
+ transformoption.force_grayscale = TRUE;
+#else
+ select_transform(JXFORM_NONE); /* force an error */
+#endif
+
+ } else if (keymatch(arg, "maxmemory", 3)) {
+ /* Maximum memory in Kb (or Mb with 'm'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (ch == 'm' || ch == 'M')
+ lval *= 1000L;
+ cinfo->mem->max_memory_to_use = lval * 1000L;
+
+ } else if (keymatch(arg, "optimize", 1) || keymatch(arg, "optimise", 1)) {
+ /* Enable entropy parm optimization. */
+#ifdef ENTROPY_OPT_SUPPORTED
+ cinfo->optimize_coding = TRUE;
+#else
+ fprintf(stderr, "%s: sorry, entropy optimization was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "outfile", 4)) {
+ /* Set output file name. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ outfilename = argv[argn]; /* save it away for later use */
+
+ } else if (keymatch(arg, "perfect", 2)) {
+ /* Fail if there is any partial edge MCUs that the transform can't
+ * handle. */
+ transformoption.perfect = TRUE;
+
+ } else if (keymatch(arg, "progressive", 2)) {
+ /* Select simple progressive mode. */
+#ifdef C_PROGRESSIVE_SUPPORTED
+ simple_progressive = TRUE;
+ /* We must postpone execution until num_components is known. */
+#else
+ fprintf(stderr, "%s: sorry, progressive output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "restart", 1)) {
+ /* Restart interval in MCU rows (or in MCUs with 'b'). */
+ long lval;
+ char ch = 'x';
+
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (sscanf(argv[argn], "%ld%c", &lval, &ch) < 1)
+ usage();
+ if (lval < 0 || lval > 65535L)
+ usage();
+ if (ch == 'b' || ch == 'B') {
+ cinfo->restart_interval = (unsigned int) lval;
+ cinfo->restart_in_rows = 0; /* else prior '-restart n' overrides me */
+ } else {
+ cinfo->restart_in_rows = (int) lval;
+ /* restart_interval will be computed during startup */
+ }
+
+ } else if (keymatch(arg, "rotate", 2)) {
+ /* Rotate 90, 180, or 270 degrees (measured clockwise). */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ if (keymatch(argv[argn], "90", 2))
+ select_transform(JXFORM_ROT_90);
+ else if (keymatch(argv[argn], "180", 3))
+ select_transform(JXFORM_ROT_180);
+ else if (keymatch(argv[argn], "270", 3))
+ select_transform(JXFORM_ROT_270);
+ else
+ usage();
+
+ } else if (keymatch(arg, "scale", 4)) {
+ /* Scale the output image by a fraction M/N. */
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ scaleoption = argv[argn];
+ /* We must postpone processing until decompression startup. */
+
+ } else if (keymatch(arg, "scans", 1)) {
+ /* Set scan script. */
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (++argn >= argc) /* advance to next argument */
+ usage();
+ scansarg = argv[argn];
+ /* We must postpone reading the file in case -progressive appears. */
+#else
+ fprintf(stderr, "%s: sorry, multi-scan output was not compiled\n",
+ progname);
+ exit(EXIT_FAILURE);
+#endif
+
+ } else if (keymatch(arg, "transpose", 1)) {
+ /* Transpose (across UL-to-LR axis). */
+ select_transform(JXFORM_TRANSPOSE);
+
+ } else if (keymatch(arg, "transverse", 6)) {
+ /* Transverse transpose (across UR-to-LL axis). */
+ select_transform(JXFORM_TRANSVERSE);
+
+ } else if (keymatch(arg, "trim", 3)) {
+ /* Trim off any partial edge MCUs that the transform can't handle. */
+ transformoption.trim = TRUE;
+
+ } else {
+ usage(); /* bogus switch */
+ }
+ }
+
+ /* Post-switch-scanning cleanup */
+
+ if (for_real) {
+
+#ifdef C_PROGRESSIVE_SUPPORTED
+ if (simple_progressive) /* process -progressive; -scans can override */
+ jpeg_simple_progression(cinfo);
+#endif
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+ if (scansarg != NULL) /* process -scans if it was present */
+ if (! read_scan_script(cinfo, scansarg))
+ usage();
+#endif
+ }
+
+ return argn; /* return index of next arg (file name) */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ struct jpeg_decompress_struct srcinfo;
+ struct jpeg_compress_struct dstinfo;
+ struct jpeg_error_mgr jsrcerr, jdsterr;
+#ifdef PROGRESS_REPORT
+ struct cdjpeg_progress_mgr progress;
+#endif
+ jvirt_barray_ptr * src_coef_arrays;
+ jvirt_barray_ptr * dst_coef_arrays;
+ int file_index;
+ /* We assume all-in-memory processing and can therefore use only a
+ * single file pointer for sequential input and output operation.
+ */
+ FILE * fp;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "jpegtran"; /* in case C library doesn't provide it */
+
+ /* Initialize the JPEG decompression object with default error handling. */
+ srcinfo.err = jpeg_std_error(&jsrcerr);
+ jpeg_create_decompress(&srcinfo);
+ /* Initialize the JPEG compression object with default error handling. */
+ dstinfo.err = jpeg_std_error(&jdsterr);
+ jpeg_create_compress(&dstinfo);
+
+ /* Now safe to enable signal catcher.
+ * Note: we assume only the decompression object will have virtual arrays.
+ */
+#ifdef NEED_SIGNAL_CATCHER
+ enable_signal_catcher((j_common_ptr) &srcinfo);
+#endif
+
+ /* Scan command line to find file names.
+ * It is convenient to use just one switch-parsing routine, but the switch
+ * values read here are mostly ignored; we will rescan the switches after
+ * opening the input file. Also note that most of the switches affect the
+ * destination JPEG object, so we parse into that and then copy over what
+ * needs to affects the source too.
+ */
+
+ file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE);
+ jsrcerr.trace_level = jdsterr.trace_level;
+ srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use;
+
+#ifdef TWO_FILE_COMMANDLINE
+ /* Must have either -outfile switch or explicit output file name */
+ if (outfilename == NULL) {
+ if (file_index != argc-2) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ outfilename = argv[file_index+1];
+ } else {
+ if (file_index != argc-1) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ }
+#else
+ /* Unix style: expect zero or one file name */
+ if (file_index < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+#endif /* TWO_FILE_COMMANDLINE */
+
+ /* Open the input file. */
+ if (file_index < argc) {
+ if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+ fp = read_stdin();
+ }
+
+#ifdef PROGRESS_REPORT
+ start_progress_monitor((j_common_ptr) &dstinfo, &progress);
+#endif
+
+ /* Specify data source for decompression */
+ jpeg_stdio_src(&srcinfo, fp);
+
+ /* Enable saving of extra markers that we want to copy */
+ jcopy_markers_setup(&srcinfo, copyoption);
+
+ /* Read file header */
+ (void) jpeg_read_header(&srcinfo, TRUE);
+
+ /* Adjust default decompression parameters */
+ if (scaleoption != NULL)
+ if (sscanf(scaleoption, "%d/%d",
+ &srcinfo.scale_num, &srcinfo.scale_denom) < 1)
+ usage();
+
+ /* Any space needed by a transform option must be requested before
+ * jpeg_read_coefficients so that memory allocation will be done right.
+ */
+#if TRANSFORMS_SUPPORTED
+ /* Fail right away if -perfect is given and transformation is not perfect.
+ */
+ if (!jtransform_request_workspace(&srcinfo, &transformoption)) {
+ fprintf(stderr, "%s: transformation is not perfect\n", progname);
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ /* Read source file as DCT coefficients */
+ src_coef_arrays = jpeg_read_coefficients(&srcinfo);
+
+ /* Initialize destination compression parameters from source values */
+ jpeg_copy_critical_parameters(&srcinfo, &dstinfo);
+
+ /* Adjust destination parameters if required by transform options;
+ * also find out which set of coefficient arrays will hold the output.
+ */
+#if TRANSFORMS_SUPPORTED
+ dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo,
+ src_coef_arrays,
+ &transformoption);
+#else
+ dst_coef_arrays = src_coef_arrays;
+#endif
+
+ /* Close input file, if we opened it.
+ * Note: we assume that jpeg_read_coefficients consumed all input
+ * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will
+ * only consume more while (! cinfo->inputctl->eoi_reached).
+ * We cannot call jpeg_finish_decompress here since we still need the
+ * virtual arrays allocated from the source object for processing.
+ */
+ if (fp != stdin)
+ fclose(fp);
+
+ /* Open the output file. */
+ if (outfilename != NULL) {
+ if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default output file is stdout */
+ fp = write_stdout();
+ }
+
+ /* Adjust default compression parameters by re-parsing the options */
+ file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE);
+
+ /* Specify data destination for compression */
+ jpeg_stdio_dest(&dstinfo, fp);
+
+ /* Start compressor (note no image data is actually written here) */
+ jpeg_write_coefficients(&dstinfo, dst_coef_arrays);
+
+ /* Copy to the output file any extra markers that we want to preserve */
+ jcopy_markers_execute(&srcinfo, &dstinfo, copyoption);
+
+ /* Execute image transformation, if any */
+#if TRANSFORMS_SUPPORTED
+ jtransform_execute_transformation(&srcinfo, &dstinfo,
+ src_coef_arrays,
+ &transformoption);
+#endif
+
+ /* Finish compression and release memory */
+ jpeg_finish_compress(&dstinfo);
+ jpeg_destroy_compress(&dstinfo);
+ (void) jpeg_finish_decompress(&srcinfo);
+ jpeg_destroy_decompress(&srcinfo);
+
+ /* Close output file, if we opened it */
+ if (fp != stdout)
+ fclose(fp);
+
+#ifdef PROGRESS_REPORT
+ end_progress_monitor((j_common_ptr) &dstinfo);
+#endif
+
+ /* All done. */
+ exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/jpg/jquant1.c b/jpg/jquant1.c
new file mode 100644
index 0000000..9d11f70
--- /dev/null
+++ b/jpg/jquant1.c
@@ -0,0 +1,857 @@
+/*
+ * jquant1.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 1-pass color quantization (color mapping) routines.
+ * These routines provide mapping to a fixed color map using equally spaced
+ * color values. Optional Floyd-Steinberg or ordered dithering is available.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef QUANT_1PASS_SUPPORTED
+
+
+/*
+ * The main purpose of 1-pass quantization is to provide a fast, if not very
+ * high quality, colormapped output capability. A 2-pass quantizer usually
+ * gives better visual quality; however, for quantized grayscale output this
+ * quantizer is perfectly adequate. Dithering is highly recommended with this
+ * quantizer, though you can turn it off if you really want to.
+ *
+ * In 1-pass quantization the colormap must be chosen in advance of seeing the
+ * image. We use a map consisting of all combinations of Ncolors[i] color
+ * values for the i'th component. The Ncolors[] values are chosen so that
+ * their product, the total number of colors, is no more than that requested.
+ * (In most cases, the product will be somewhat less.)
+ *
+ * Since the colormap is orthogonal, the representative value for each color
+ * component can be determined without considering the other components;
+ * then these indexes can be combined into a colormap index by a standard
+ * N-dimensional-array-subscript calculation. Most of the arithmetic involved
+ * can be precalculated and stored in the lookup table colorindex[].
+ * colorindex[i][j] maps pixel value j in component i to the nearest
+ * representative value (grid plane) for that component; this index is
+ * multiplied by the array stride for component i, so that the
+ * index of the colormap entry closest to a given pixel value is just
+ * sum( colorindex[component-number][pixel-component-value] )
+ * Aside from being fast, this scheme allows for variable spacing between
+ * representative values with no additional lookup cost.
+ *
+ * If gamma correction has been applied in color conversion, it might be wise
+ * to adjust the color grid spacing so that the representative colors are
+ * equidistant in linear space. At this writing, gamma correction is not
+ * implemented by jdcolor, so nothing is done here.
+ */
+
+
+/* Declarations for ordered dithering.
+ *
+ * We use a standard 16x16 ordered dither array. The basic concept of ordered
+ * dithering is described in many references, for instance Dale Schumacher's
+ * chapter II.2 of Graphics Gems II (James Arvo, ed. Academic Press, 1991).
+ * In place of Schumacher's comparisons against a "threshold" value, we add a
+ * "dither" value to the input pixel and then round the result to the nearest
+ * output value. The dither value is equivalent to (0.5 - threshold) times
+ * the distance between output values. For ordered dithering, we assume that
+ * the output colors are equally spaced; if not, results will probably be
+ * worse, since the dither may be too much or too little at a given point.
+ *
+ * The normal calculation would be to form pixel value + dither, range-limit
+ * this to 0..MAXJSAMPLE, and then index into the colorindex table as usual.
+ * We can skip the separate range-limiting step by extending the colorindex
+ * table in both directions.
+ */
+
+#define ODITHER_SIZE 16 /* dimension of dither matrix */
+/* NB: if ODITHER_SIZE is not a power of 2, ODITHER_MASK uses will break */
+#define ODITHER_CELLS (ODITHER_SIZE*ODITHER_SIZE) /* # cells in matrix */
+#define ODITHER_MASK (ODITHER_SIZE-1) /* mask for wrapping around counters */
+
+typedef int ODITHER_MATRIX[ODITHER_SIZE][ODITHER_SIZE];
+typedef int (*ODITHER_MATRIX_PTR)[ODITHER_SIZE];
+
+static const UINT8 base_dither_matrix[ODITHER_SIZE][ODITHER_SIZE] = {
+ /* Bayer's order-4 dither array. Generated by the code given in
+ * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I.
+ * The values in this array must range from 0 to ODITHER_CELLS-1.
+ */
+ { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
+ { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
+ { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
+ { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
+ { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
+ { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
+ { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
+ { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
+ { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
+ { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
+ { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
+ { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
+ { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
+ { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
+ { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
+ { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
+};
+
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count. The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ * ... (here) 7/16
+ * 3/16 5/16 1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed. We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column. (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array is indexed [component#][position].
+ * We provide (#columns + 2) entries per component; the extra entry at each
+ * end saves us from special-casing the first and last pixels.
+ *
+ * Note: on a wide image, we might not have enough room in a PC's near data
+ * segment to hold the error array; so it is allocated with alloc_large.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef INT16 FSERROR; /* 16 bits should be enough */
+typedef int LOCFSERROR; /* use 'int' for calculation temps */
+#else
+typedef INT32 FSERROR; /* may need more than 16 bits */
+typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */
+#endif
+
+typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
+
+
+/* Private subobject */
+
+#define MAX_Q_COMPS 4 /* max components I can handle */
+
+typedef struct {
+ struct jpeg_color_quantizer pub; /* public fields */
+
+ /* Initially allocated colormap is saved here */
+ JSAMPARRAY sv_colormap; /* The color map as a 2-D pixel array */
+ int sv_actual; /* number of entries in use */
+
+ JSAMPARRAY colorindex; /* Precomputed mapping for speed */
+ /* colorindex[i][j] = index of color closest to pixel value j in component i,
+ * premultiplied as described above. Since colormap indexes must fit into
+ * JSAMPLEs, the entries of this array will too.
+ */
+ boolean is_padded; /* is the colorindex padded for odither? */
+
+ int Ncolors[MAX_Q_COMPS]; /* # of values alloced to each component */
+
+ /* Variables for ordered dithering */
+ int row_index; /* cur row's vertical index in dither matrix */
+ ODITHER_MATRIX_PTR odither[MAX_Q_COMPS]; /* one dither array per component */
+
+ /* Variables for Floyd-Steinberg dithering */
+ FSERRPTR fserrors[MAX_Q_COMPS]; /* accumulated errors */
+ boolean on_odd_row; /* flag to remember which row we are on */
+} my_cquantizer;
+
+typedef my_cquantizer * my_cquantize_ptr;
+
+
+/*
+ * Policy-making subroutines for create_colormap and create_colorindex.
+ * These routines determine the colormap to be used. The rest of the module
+ * only assumes that the colormap is orthogonal.
+ *
+ * * select_ncolors decides how to divvy up the available colors
+ * among the components.
+ * * output_value defines the set of representative values for a component.
+ * * largest_input_value defines the mapping from input values to
+ * representative values for a component.
+ * Note that the latter two routines may impose different policies for
+ * different components, though this is not currently done.
+ */
+
+
+LOCAL(int)
+select_ncolors (j_decompress_ptr cinfo, int Ncolors[])
+/* Determine allocation of desired colors to components, */
+/* and fill in Ncolors[] array to indicate choice. */
+/* Return value is total number of colors (product of Ncolors[] values). */
+{
+ int nc = cinfo->out_color_components; /* number of color components */
+ int max_colors = cinfo->desired_number_of_colors;
+ int total_colors, iroot, i, j;
+ boolean changed;
+ long temp;
+ static const int RGB_order[3] = { RGB_GREEN, RGB_RED, RGB_BLUE };
+
+ /* We can allocate at least the nc'th root of max_colors per component. */
+ /* Compute floor(nc'th root of max_colors). */
+ iroot = 1;
+ do {
+ iroot++;
+ temp = iroot; /* set temp = iroot ** nc */
+ for (i = 1; i < nc; i++)
+ temp *= iroot;
+ } while (temp <= (long) max_colors); /* repeat till iroot exceeds root */
+ iroot--; /* now iroot = floor(root) */
+
+ /* Must have at least 2 color values per component */
+ if (iroot < 2)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, (int) temp);
+
+ /* Initialize to iroot color values for each component */
+ total_colors = 1;
+ for (i = 0; i < nc; i++) {
+ Ncolors[i] = iroot;
+ total_colors *= iroot;
+ }
+ /* We may be able to increment the count for one or more components without
+ * exceeding max_colors, though we know not all can be incremented.
+ * Sometimes, the first component can be incremented more than once!
+ * (Example: for 16 colors, we start at 2*2*2, go to 3*2*2, then 4*2*2.)
+ * In RGB colorspace, try to increment G first, then R, then B.
+ */
+ do {
+ changed = FALSE;
+ for (i = 0; i < nc; i++) {
+ j = (cinfo->out_color_space == JCS_RGB ? RGB_order[i] : i);
+ /* calculate new total_colors if Ncolors[j] is incremented */
+ temp = total_colors / Ncolors[j];
+ temp *= Ncolors[j]+1; /* done in long arith to avoid oflo */
+ if (temp > (long) max_colors)
+ break; /* won't fit, done with this pass */
+ Ncolors[j]++; /* OK, apply the increment */
+ total_colors = (int) temp;
+ changed = TRUE;
+ }
+ } while (changed);
+
+ return total_colors;
+}
+
+
+LOCAL(int)
+output_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
+/* Return j'th output value, where j will range from 0 to maxj */
+/* The output values must fall in 0..MAXJSAMPLE in increasing order */
+{
+ /* We always provide values 0 and MAXJSAMPLE for each component;
+ * any additional values are equally spaced between these limits.
+ * (Forcing the upper and lower values to the limits ensures that
+ * dithering can't produce a color outside the selected gamut.)
+ */
+ return (int) (((INT32) j * MAXJSAMPLE + maxj/2) / maxj);
+}
+
+
+LOCAL(int)
+largest_input_value (j_decompress_ptr cinfo, int ci, int j, int maxj)
+/* Return largest input value that should map to j'th output value */
+/* Must have largest(j=0) >= 0, and largest(j=maxj) >= MAXJSAMPLE */
+{
+ /* Breakpoints are halfway between values returned by output_value */
+ return (int) (((INT32) (2*j + 1) * MAXJSAMPLE + maxj) / (2*maxj));
+}
+
+
+/*
+ * Create the colormap.
+ */
+
+LOCAL(void)
+create_colormap (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPARRAY colormap; /* Created colormap */
+ int total_colors; /* Number of distinct output colors */
+ int i,j,k, nci, blksize, blkdist, ptr, val;
+
+ /* Select number of colors for each component */
+ total_colors = select_ncolors(cinfo, cquantize->Ncolors);
+
+ /* Report selected color counts */
+ if (cinfo->out_color_components == 3)
+ TRACEMS4(cinfo, 1, JTRC_QUANT_3_NCOLORS,
+ total_colors, cquantize->Ncolors[0],
+ cquantize->Ncolors[1], cquantize->Ncolors[2]);
+ else
+ TRACEMS1(cinfo, 1, JTRC_QUANT_NCOLORS, total_colors);
+
+ /* Allocate and fill in the colormap. */
+ /* The colors are ordered in the map in standard row-major order, */
+ /* i.e. rightmost (highest-indexed) color changes most rapidly. */
+
+ colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) total_colors, (JDIMENSION) cinfo->out_color_components);
+
+ /* blksize is number of adjacent repeated entries for a component */
+ /* blkdist is distance between groups of identical entries for a component */
+ blkdist = total_colors;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ /* fill in colormap entries for i'th color component */
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ blksize = blkdist / nci;
+ for (j = 0; j < nci; j++) {
+ /* Compute j'th output value (out of nci) for component */
+ val = output_value(cinfo, i, j, nci-1);
+ /* Fill in all colormap entries that have this value of this component */
+ for (ptr = j * blksize; ptr < total_colors; ptr += blkdist) {
+ /* fill in blksize entries beginning at ptr */
+ for (k = 0; k < blksize; k++)
+ colormap[i][ptr+k] = (JSAMPLE) val;
+ }
+ }
+ blkdist = blksize; /* blksize of this color is blkdist of next */
+ }
+
+ /* Save the colormap in private storage,
+ * where it will survive color quantization mode changes.
+ */
+ cquantize->sv_colormap = colormap;
+ cquantize->sv_actual = total_colors;
+}
+
+
+/*
+ * Create the color index table.
+ */
+
+LOCAL(void)
+create_colorindex (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPROW indexptr;
+ int i,j,k, nci, blksize, val, pad;
+
+ /* For ordered dither, we pad the color index tables by MAXJSAMPLE in
+ * each direction (input index values can be -MAXJSAMPLE .. 2*MAXJSAMPLE).
+ * This is not necessary in the other dithering modes. However, we
+ * flag whether it was done in case user changes dithering mode.
+ */
+ if (cinfo->dither_mode == JDITHER_ORDERED) {
+ pad = MAXJSAMPLE*2;
+ cquantize->is_padded = TRUE;
+ } else {
+ pad = 0;
+ cquantize->is_padded = FALSE;
+ }
+
+ cquantize->colorindex = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (MAXJSAMPLE+1 + pad),
+ (JDIMENSION) cinfo->out_color_components);
+
+ /* blksize is number of adjacent repeated entries for a component */
+ blksize = cquantize->sv_actual;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ /* fill in colorindex entries for i'th color component */
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ blksize = blksize / nci;
+
+ /* adjust colorindex pointers to provide padding at negative indexes. */
+ if (pad)
+ cquantize->colorindex[i] += MAXJSAMPLE;
+
+ /* in loop, val = index of current output value, */
+ /* and k = largest j that maps to current val */
+ indexptr = cquantize->colorindex[i];
+ val = 0;
+ k = largest_input_value(cinfo, i, 0, nci-1);
+ for (j = 0; j <= MAXJSAMPLE; j++) {
+ while (j > k) /* advance val if past boundary */
+ k = largest_input_value(cinfo, i, ++val, nci-1);
+ /* premultiply so that no multiplication needed in main processing */
+ indexptr[j] = (JSAMPLE) (val * blksize);
+ }
+ /* Pad at both ends if necessary */
+ if (pad)
+ for (j = 1; j <= MAXJSAMPLE; j++) {
+ indexptr[-j] = indexptr[0];
+ indexptr[MAXJSAMPLE+j] = indexptr[MAXJSAMPLE];
+ }
+ }
+}
+
+
+/*
+ * Create an ordered-dither array for a component having ncolors
+ * distinct output values.
+ */
+
+LOCAL(ODITHER_MATRIX_PTR)
+make_odither_array (j_decompress_ptr cinfo, int ncolors)
+{
+ ODITHER_MATRIX_PTR odither;
+ int j,k;
+ INT32 num,den;
+
+ odither = (ODITHER_MATRIX_PTR)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(ODITHER_MATRIX));
+ /* The inter-value distance for this color is MAXJSAMPLE/(ncolors-1).
+ * Hence the dither value for the matrix cell with fill order f
+ * (f=0..N-1) should be (N-1-2*f)/(2*N) * MAXJSAMPLE/(ncolors-1).
+ * On 16-bit-int machine, be careful to avoid overflow.
+ */
+ den = 2 * ODITHER_CELLS * ((INT32) (ncolors - 1));
+ for (j = 0; j < ODITHER_SIZE; j++) {
+ for (k = 0; k < ODITHER_SIZE; k++) {
+ num = ((INT32) (ODITHER_CELLS-1 - 2*((int)base_dither_matrix[j][k])))
+ * MAXJSAMPLE;
+ /* Ensure round towards zero despite C's lack of consistency
+ * about rounding negative values in integer division...
+ */
+ odither[j][k] = (int) (num<0 ? -((-num)/den) : num/den);
+ }
+ }
+ return odither;
+}
+
+
+/*
+ * Create the ordered-dither tables.
+ * Components having the same number of representative colors may
+ * share a dither table.
+ */
+
+LOCAL(void)
+create_odither_tables (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ ODITHER_MATRIX_PTR odither;
+ int i, j, nci;
+
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ nci = cquantize->Ncolors[i]; /* # of distinct values for this color */
+ odither = NULL; /* search for matching prior component */
+ for (j = 0; j < i; j++) {
+ if (nci == cquantize->Ncolors[j]) {
+ odither = cquantize->odither[j];
+ break;
+ }
+ }
+ if (odither == NULL) /* need a new table? */
+ odither = make_odither_array(cinfo, nci);
+ cquantize->odither[i] = odither;
+ }
+}
+
+
+/*
+ * Map some rows of pixels to the output colormapped representation.
+ */
+
+METHODDEF(void)
+color_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ JSAMPARRAY colorindex = cquantize->colorindex;
+ register int pixcode, ci;
+ register JSAMPROW ptrin, ptrout;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ register int nc = cinfo->out_color_components;
+
+ for (row = 0; row < num_rows; row++) {
+ ptrin = input_buf[row];
+ ptrout = output_buf[row];
+ for (col = width; col > 0; col--) {
+ pixcode = 0;
+ for (ci = 0; ci < nc; ci++) {
+ pixcode += GETJSAMPLE(colorindex[ci][GETJSAMPLE(*ptrin++)]);
+ }
+ *ptrout++ = (JSAMPLE) pixcode;
+ }
+ }
+}
+
+
+METHODDEF(void)
+color_quantize3 (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* Fast path for out_color_components==3, no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register int pixcode;
+ register JSAMPROW ptrin, ptrout;
+ JSAMPROW colorindex0 = cquantize->colorindex[0];
+ JSAMPROW colorindex1 = cquantize->colorindex[1];
+ JSAMPROW colorindex2 = cquantize->colorindex[2];
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ ptrin = input_buf[row];
+ ptrout = output_buf[row];
+ for (col = width; col > 0; col--) {
+ pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptrin++)]);
+ pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptrin++)]);
+ pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptrin++)]);
+ *ptrout++ = (JSAMPLE) pixcode;
+ }
+ }
+}
+
+
+METHODDEF(void)
+quantize_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, with ordered dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex_ci;
+ int * dither; /* points to active row of dither matrix */
+ int row_index, col_index; /* current indexes into dither matrix */
+ int nc = cinfo->out_color_components;
+ int ci;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ /* Initialize output values to 0 so can process components separately */
+ FMEMZERO((void FAR *) output_buf[row],
+ (size_t) (width * SIZEOF(JSAMPLE)));
+ row_index = cquantize->row_index;
+ for (ci = 0; ci < nc; ci++) {
+ input_ptr = input_buf[row] + ci;
+ output_ptr = output_buf[row];
+ colorindex_ci = cquantize->colorindex[ci];
+ dither = cquantize->odither[ci][row_index];
+ col_index = 0;
+
+ for (col = width; col > 0; col--) {
+ /* Form pixel value + dither, range-limit to 0..MAXJSAMPLE,
+ * select output value, accumulate into output code for this pixel.
+ * Range-limiting need not be done explicitly, as we have extended
+ * the colorindex table to produce the right answers for out-of-range
+ * inputs. The maximum dither is +- MAXJSAMPLE; this sets the
+ * required amount of padding.
+ */
+ *output_ptr += colorindex_ci[GETJSAMPLE(*input_ptr)+dither[col_index]];
+ input_ptr += nc;
+ output_ptr++;
+ col_index = (col_index + 1) & ODITHER_MASK;
+ }
+ }
+ /* Advance row index for next row */
+ row_index = (row_index + 1) & ODITHER_MASK;
+ cquantize->row_index = row_index;
+ }
+}
+
+
+METHODDEF(void)
+quantize3_ord_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* Fast path for out_color_components==3, with ordered dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register int pixcode;
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex0 = cquantize->colorindex[0];
+ JSAMPROW colorindex1 = cquantize->colorindex[1];
+ JSAMPROW colorindex2 = cquantize->colorindex[2];
+ int * dither0; /* points to active row of dither matrix */
+ int * dither1;
+ int * dither2;
+ int row_index, col_index; /* current indexes into dither matrix */
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ row_index = cquantize->row_index;
+ input_ptr = input_buf[row];
+ output_ptr = output_buf[row];
+ dither0 = cquantize->odither[0][row_index];
+ dither1 = cquantize->odither[1][row_index];
+ dither2 = cquantize->odither[2][row_index];
+ col_index = 0;
+
+ for (col = width; col > 0; col--) {
+ pixcode = GETJSAMPLE(colorindex0[GETJSAMPLE(*input_ptr++) +
+ dither0[col_index]]);
+ pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*input_ptr++) +
+ dither1[col_index]]);
+ pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*input_ptr++) +
+ dither2[col_index]]);
+ *output_ptr++ = (JSAMPLE) pixcode;
+ col_index = (col_index + 1) & ODITHER_MASK;
+ }
+ row_index = (row_index + 1) & ODITHER_MASK;
+ cquantize->row_index = row_index;
+ }
+}
+
+
+METHODDEF(void)
+quantize_fs_dither (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+/* General case, with Floyd-Steinberg dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register LOCFSERROR cur; /* current error or pixel value */
+ LOCFSERROR belowerr; /* error for pixel below cur */
+ LOCFSERROR bpreverr; /* error for below/prev col */
+ LOCFSERROR bnexterr; /* error for below/next col */
+ LOCFSERROR delta;
+ register FSERRPTR errorptr; /* => fserrors[] at column before current */
+ register JSAMPROW input_ptr;
+ register JSAMPROW output_ptr;
+ JSAMPROW colorindex_ci;
+ JSAMPROW colormap_ci;
+ int pixcode;
+ int nc = cinfo->out_color_components;
+ int dir; /* 1 for left-to-right, -1 for right-to-left */
+ int dirnc; /* dir * nc */
+ int ci;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ JSAMPLE *range_limit = cinfo->sample_range_limit;
+ SHIFT_TEMPS
+
+ for (row = 0; row < num_rows; row++) {
+ /* Initialize output values to 0 so can process components separately */
+ FMEMZERO((void FAR *) output_buf[row],
+ (size_t) (width * SIZEOF(JSAMPLE)));
+ for (ci = 0; ci < nc; ci++) {
+ input_ptr = input_buf[row] + ci;
+ output_ptr = output_buf[row];
+ if (cquantize->on_odd_row) {
+ /* work right to left in this row */
+ input_ptr += (width-1) * nc; /* so point to rightmost pixel */
+ output_ptr += width-1;
+ dir = -1;
+ dirnc = -nc;
+ errorptr = cquantize->fserrors[ci] + (width+1); /* => entry after last column */
+ } else {
+ /* work left to right in this row */
+ dir = 1;
+ dirnc = nc;
+ errorptr = cquantize->fserrors[ci]; /* => entry before first column */
+ }
+ colorindex_ci = cquantize->colorindex[ci];
+ colormap_ci = cquantize->sv_colormap[ci];
+ /* Preset error values: no error propagated to first pixel from left */
+ cur = 0;
+ /* and no error propagated to row below yet */
+ belowerr = bpreverr = 0;
+
+ for (col = width; col > 0; col--) {
+ /* cur holds the error propagated from the previous pixel on the
+ * current line. Add the error propagated from the previous line
+ * to form the complete error correction term for this pixel, and
+ * round the error term (which is expressed * 16) to an integer.
+ * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+ * for either sign of the error value.
+ * Note: errorptr points to *previous* column's array entry.
+ */
+ cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);
+ /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+ * The maximum error is +- MAXJSAMPLE; this sets the required size
+ * of the range_limit array.
+ */
+ cur += GETJSAMPLE(*input_ptr);
+ cur = GETJSAMPLE(range_limit[cur]);
+ /* Select output value, accumulate into output code for this pixel */
+ pixcode = GETJSAMPLE(colorindex_ci[cur]);
+ *output_ptr += (JSAMPLE) pixcode;
+ /* Compute actual representation error at this pixel */
+ /* Note: we can do this even though we don't have the final */
+ /* pixel code, because the colormap is orthogonal. */
+ cur -= GETJSAMPLE(colormap_ci[pixcode]);
+ /* Compute error fractions to be propagated to adjacent pixels.
+ * Add these into the running sums, and simultaneously shift the
+ * next-line error sums left by 1 column.
+ */
+ bnexterr = cur;
+ delta = cur * 2;
+ cur += delta; /* form error * 3 */
+ errorptr[0] = (FSERROR) (bpreverr + cur);
+ cur += delta; /* form error * 5 */
+ bpreverr = belowerr + cur;
+ belowerr = bnexterr;
+ cur += delta; /* form error * 7 */
+ /* At this point cur contains the 7/16 error value to be propagated
+ * to the next pixel on the current line, and all the errors for the
+ * next line have been shifted over. We are therefore ready to move on.
+ */
+ input_ptr += dirnc; /* advance input ptr to next column */
+ output_ptr += dir; /* advance output ptr to next column */
+ errorptr += dir; /* advance errorptr to current column */
+ }
+ /* Post-loop cleanup: we must unload the final error value into the
+ * final fserrors[] entry. Note we need not unload belowerr because
+ * it is for the dummy column before or after the actual array.
+ */
+ errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */
+ }
+ cquantize->on_odd_row = (cquantize->on_odd_row ? FALSE : TRUE);
+ }
+}
+
+
+/*
+ * Allocate workspace for Floyd-Steinberg errors.
+ */
+
+LOCAL(void)
+alloc_fs_workspace (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ size_t arraysize;
+ int i;
+
+ arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
+ for (i = 0; i < cinfo->out_color_components; i++) {
+ cquantize->fserrors[i] = (FSERRPTR)
+ (*cinfo->mem->alloc_large)((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+ }
+}
+
+
+/*
+ * Initialize for one-pass color quantization.
+ */
+
+METHODDEF(void)
+start_pass_1_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ size_t arraysize;
+ int i;
+
+ /* Install my colormap. */
+ cinfo->colormap = cquantize->sv_colormap;
+ cinfo->actual_number_of_colors = cquantize->sv_actual;
+
+ /* Initialize for desired dithering mode. */
+ switch (cinfo->dither_mode) {
+ case JDITHER_NONE:
+ if (cinfo->out_color_components == 3)
+ cquantize->pub.color_quantize = color_quantize3;
+ else
+ cquantize->pub.color_quantize = color_quantize;
+ break;
+ case JDITHER_ORDERED:
+ if (cinfo->out_color_components == 3)
+ cquantize->pub.color_quantize = quantize3_ord_dither;
+ else
+ cquantize->pub.color_quantize = quantize_ord_dither;
+ cquantize->row_index = 0; /* initialize state for ordered dither */
+ /* If user changed to ordered dither from another mode,
+ * we must recreate the color index table with padding.
+ * This will cost extra space, but probably isn't very likely.
+ */
+ if (! cquantize->is_padded)
+ create_colorindex(cinfo);
+ /* Create ordered-dither tables if we didn't already. */
+ if (cquantize->odither[0] == NULL)
+ create_odither_tables(cinfo);
+ break;
+ case JDITHER_FS:
+ cquantize->pub.color_quantize = quantize_fs_dither;
+ cquantize->on_odd_row = FALSE; /* initialize state for F-S dither */
+ /* Allocate Floyd-Steinberg workspace if didn't already. */
+ if (cquantize->fserrors[0] == NULL)
+ alloc_fs_workspace(cinfo);
+ /* Initialize the propagated errors to zero. */
+ arraysize = (size_t) ((cinfo->output_width + 2) * SIZEOF(FSERROR));
+ for (i = 0; i < cinfo->out_color_components; i++)
+ FMEMZERO((void FAR *) cquantize->fserrors[i], arraysize);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_NOT_COMPILED);
+ break;
+ }
+}
+
+
+/*
+ * Finish up at the end of the pass.
+ */
+
+METHODDEF(void)
+finish_pass_1_quant (j_decompress_ptr cinfo)
+{
+ /* no work in 1-pass case */
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ * Shouldn't get to this module!
+ */
+
+METHODDEF(void)
+new_color_map_1_quant (j_decompress_ptr cinfo)
+{
+ ERREXIT(cinfo, JERR_MODE_CHANGE);
+}
+
+
+/*
+ * Module initialization routine for 1-pass color quantization.
+ */
+
+GLOBAL(void)
+jinit_1pass_quantizer (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize;
+
+ cquantize = (my_cquantize_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_cquantizer));
+ cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+ cquantize->pub.start_pass = start_pass_1_quant;
+ cquantize->pub.finish_pass = finish_pass_1_quant;
+ cquantize->pub.new_color_map = new_color_map_1_quant;
+ cquantize->fserrors[0] = NULL; /* Flag FS workspace not allocated */
+ cquantize->odither[0] = NULL; /* Also flag odither arrays not allocated */
+
+ /* Make sure my internal arrays won't overflow */
+ if (cinfo->out_color_components > MAX_Q_COMPS)
+ ERREXIT1(cinfo, JERR_QUANT_COMPONENTS, MAX_Q_COMPS);
+ /* Make sure colormap indexes can be represented by JSAMPLEs */
+ if (cinfo->desired_number_of_colors > (MAXJSAMPLE+1))
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXJSAMPLE+1);
+
+ /* Create the colormap and color index table. */
+ create_colormap(cinfo);
+ create_colorindex(cinfo);
+
+ /* Allocate Floyd-Steinberg workspace now if requested.
+ * We do this now since it is FAR storage and may affect the memory
+ * manager's space calculations. If the user changes to FS dither
+ * mode in a later pass, we will allocate the space then, and will
+ * possibly overrun the max_memory_to_use setting.
+ */
+ if (cinfo->dither_mode == JDITHER_FS)
+ alloc_fs_workspace(cinfo);
+}
+
+#endif /* QUANT_1PASS_SUPPORTED */
diff --git a/jpg/jquant2.c b/jpg/jquant2.c
new file mode 100644
index 0000000..38fc2af
--- /dev/null
+++ b/jpg/jquant2.c
@@ -0,0 +1,1311 @@
+/*
+ * jquant2.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains 2-pass color quantization (color mapping) routines.
+ * These routines provide selection of a custom color map for an image,
+ * followed by mapping of the image to that color map, with optional
+ * Floyd-Steinberg dithering.
+ * It is also possible to use just the second pass to map to an arbitrary
+ * externally-given color map.
+ *
+ * Note: ordered dithering is not supported, since there isn't any fast
+ * way to compute intercolor distances; it's unclear that ordered dither's
+ * fundamental assumptions even hold with an irregularly spaced color map.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+#ifdef QUANT_2PASS_SUPPORTED
+
+
+/*
+ * This module implements the well-known Heckbert paradigm for color
+ * quantization. Most of the ideas used here can be traced back to
+ * Heckbert's seminal paper
+ * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display",
+ * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304.
+ *
+ * In the first pass over the image, we accumulate a histogram showing the
+ * usage count of each possible color. To keep the histogram to a reasonable
+ * size, we reduce the precision of the input; typical practice is to retain
+ * 5 or 6 bits per color, so that 8 or 4 different input values are counted
+ * in the same histogram cell.
+ *
+ * Next, the color-selection step begins with a box representing the whole
+ * color space, and repeatedly splits the "largest" remaining box until we
+ * have as many boxes as desired colors. Then the mean color in each
+ * remaining box becomes one of the possible output colors.
+ *
+ * The second pass over the image maps each input pixel to the closest output
+ * color (optionally after applying a Floyd-Steinberg dithering correction).
+ * This mapping is logically trivial, but making it go fast enough requires
+ * considerable care.
+ *
+ * Heckbert-style quantizers vary a good deal in their policies for choosing
+ * the "largest" box and deciding where to cut it. The particular policies
+ * used here have proved out well in experimental comparisons, but better ones
+ * may yet be found.
+ *
+ * In earlier versions of the IJG code, this module quantized in YCbCr color
+ * space, processing the raw upsampled data without a color conversion step.
+ * This allowed the color conversion math to be done only once per colormap
+ * entry, not once per pixel. However, that optimization precluded other
+ * useful optimizations (such as merging color conversion with upsampling)
+ * and it also interfered with desired capabilities such as quantizing to an
+ * externally-supplied colormap. We have therefore abandoned that approach.
+ * The present code works in the post-conversion color space, typically RGB.
+ *
+ * To improve the visual quality of the results, we actually work in scaled
+ * RGB space, giving G distances more weight than R, and R in turn more than
+ * B. To do everything in integer math, we must use integer scale factors.
+ * The 2/3/1 scale factors used here correspond loosely to the relative
+ * weights of the colors in the NTSC grayscale equation.
+ * If you want to use this code to quantize a non-RGB color space, you'll
+ * probably need to change these scale factors.
+ */
+
+#define R_SCALE 2 /* scale R distances by this much */
+#define G_SCALE 3 /* scale G distances by this much */
+#define B_SCALE 1 /* and B by this much */
+
+/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined
+ * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B
+ * and B,G,R orders. If you define some other weird order in jmorecfg.h,
+ * you'll get compile errors until you extend this logic. In that case
+ * you'll probably want to tweak the histogram sizes too.
+ */
+
+#if RGB_RED == 0
+#define C0_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 0
+#define C0_SCALE B_SCALE
+#endif
+#if RGB_GREEN == 1
+#define C1_SCALE G_SCALE
+#endif
+#if RGB_RED == 2
+#define C2_SCALE R_SCALE
+#endif
+#if RGB_BLUE == 2
+#define C2_SCALE B_SCALE
+#endif
+
+
+/*
+ * First we have the histogram data structure and routines for creating it.
+ *
+ * The number of bits of precision can be adjusted by changing these symbols.
+ * We recommend keeping 6 bits for G and 5 each for R and B.
+ * If you have plenty of memory and cycles, 6 bits all around gives marginally
+ * better results; if you are short of memory, 5 bits all around will save
+ * some space but degrade the results.
+ * To maintain a fully accurate histogram, we'd need to allocate a "long"
+ * (preferably unsigned long) for each cell. In practice this is overkill;
+ * we can get by with 16 bits per cell. Few of the cell counts will overflow,
+ * and clamping those that do overflow to the maximum value will give close-
+ * enough results. This reduces the recommended histogram size from 256Kb
+ * to 128Kb, which is a useful savings on PC-class machines.
+ * (In the second pass the histogram space is re-used for pixel mapping data;
+ * in that capacity, each cell must be able to store zero to the number of
+ * desired colors. 16 bits/cell is plenty for that too.)
+ * Since the JPEG code is intended to run in small memory model on 80x86
+ * machines, we can't just allocate the histogram in one chunk. Instead
+ * of a true 3-D array, we use a row of pointers to 2-D arrays. Each
+ * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and
+ * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that
+ * on 80x86 machines, the pointer row is in near memory but the actual
+ * arrays are in far memory (same arrangement as we use for image arrays).
+ */
+
+#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */
+
+/* These will do the right thing for either R,G,B or B,G,R color order,
+ * but you may not like the results for other color orders.
+ */
+#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */
+#define HIST_C1_BITS 6 /* bits of precision in G histogram */
+#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */
+
+/* Number of elements along histogram axes. */
+#define HIST_C0_ELEMS (1<<HIST_C0_BITS)
+#define HIST_C1_ELEMS (1<<HIST_C1_BITS)
+#define HIST_C2_ELEMS (1<<HIST_C2_BITS)
+
+/* These are the amounts to shift an input value to get a histogram index. */
+#define C0_SHIFT (BITS_IN_JSAMPLE-HIST_C0_BITS)
+#define C1_SHIFT (BITS_IN_JSAMPLE-HIST_C1_BITS)
+#define C2_SHIFT (BITS_IN_JSAMPLE-HIST_C2_BITS)
+
+
+typedef UINT16 histcell; /* histogram cell; prefer an unsigned type */
+
+typedef histcell FAR * histptr; /* for pointers to histogram cells */
+
+typedef histcell hist1d[HIST_C2_ELEMS]; /* typedefs for the array */
+typedef hist1d FAR * hist2d; /* type for the 2nd-level pointers */
+typedef hist2d * hist3d; /* type for top-level pointer */
+
+
+/* Declarations for Floyd-Steinberg dithering.
+ *
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count. The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
+ * ... (here) 7/16
+ * 3/16 5/16 1/16
+ * We work left-to-right on even rows, right-to-left on odd rows.
+ *
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed. We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column. (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array has (#columns + 2) entries; the extra entry at
+ * each end saves us from special-casing the first and last pixels.
+ * Each entry is three values long, one value for each color component.
+ *
+ * Note: on a wide image, we might not have enough room in a PC's near data
+ * segment to hold the error array; so it is allocated with alloc_large.
+ */
+
+#if BITS_IN_JSAMPLE == 8
+typedef INT16 FSERROR; /* 16 bits should be enough */
+typedef int LOCFSERROR; /* use 'int' for calculation temps */
+#else
+typedef INT32 FSERROR; /* may need more than 16 bits */
+typedef INT32 LOCFSERROR; /* be sure calculation temps are big enough */
+#endif
+
+typedef FSERROR FAR *FSERRPTR; /* pointer to error array (in FAR storage!) */
+
+
+/* Private subobject */
+
+typedef struct {
+ struct jpeg_color_quantizer pub; /* public fields */
+
+ /* Space for the eventually created colormap is stashed here */
+ JSAMPARRAY sv_colormap; /* colormap allocated at init time */
+ int desired; /* desired # of colors = size of colormap */
+
+ /* Variables for accumulating image statistics */
+ hist3d histogram; /* pointer to the histogram */
+
+ boolean needs_zeroed; /* TRUE if next pass must zero histogram */
+
+ /* Variables for Floyd-Steinberg dithering */
+ FSERRPTR fserrors; /* accumulated errors */
+ boolean on_odd_row; /* flag to remember which row we are on */
+ int * error_limiter; /* table for clamping the applied error */
+} my_cquantizer;
+
+typedef my_cquantizer * my_cquantize_ptr;
+
+
+/*
+ * Prescan some rows of pixels.
+ * In this module the prescan simply updates the histogram, which has been
+ * initialized to zeroes by start_pass.
+ * An output_buf parameter is required by the method signature, but no data
+ * is actually output (in fact the buffer controller is probably passing a
+ * NULL pointer).
+ */
+
+METHODDEF(void)
+prescan_quantize (j_decompress_ptr cinfo, JSAMPARRAY input_buf,
+ JSAMPARRAY output_buf, int num_rows)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ register JSAMPROW ptr;
+ register histptr histp;
+ register hist3d histogram = cquantize->histogram;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ ptr = input_buf[row];
+ for (col = width; col > 0; col--) {
+ /* get pixel value and index into the histogram */
+ histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT]
+ [GETJSAMPLE(ptr[1]) >> C1_SHIFT]
+ [GETJSAMPLE(ptr[2]) >> C2_SHIFT];
+ /* increment, check for overflow and undo increment if so. */
+ if (++(*histp) <= 0)
+ (*histp)--;
+ ptr += 3;
+ }
+ }
+}
+
+
+/*
+ * Next we have the really interesting routines: selection of a colormap
+ * given the completed histogram.
+ * These routines work with a list of "boxes", each representing a rectangular
+ * subset of the input color space (to histogram precision).
+ */
+
+typedef struct {
+ /* The bounds of the box (inclusive); expressed as histogram indexes */
+ int c0min, c0max;
+ int c1min, c1max;
+ int c2min, c2max;
+ /* The volume (actually 2-norm) of the box */
+ INT32 volume;
+ /* The number of nonzero histogram cells within this box */
+ long colorcount;
+} box;
+
+typedef box * boxptr;
+
+
+LOCAL(boxptr)
+find_biggest_color_pop (boxptr boxlist, int numboxes)
+/* Find the splittable box with the largest color population */
+/* Returns NULL if no splittable boxes remain */
+{
+ register boxptr boxp;
+ register int i;
+ register long maxc = 0;
+ boxptr which = NULL;
+
+ for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+ if (boxp->colorcount > maxc && boxp->volume > 0) {
+ which = boxp;
+ maxc = boxp->colorcount;
+ }
+ }
+ return which;
+}
+
+
+LOCAL(boxptr)
+find_biggest_volume (boxptr boxlist, int numboxes)
+/* Find the splittable box with the largest (scaled) volume */
+/* Returns NULL if no splittable boxes remain */
+{
+ register boxptr boxp;
+ register int i;
+ register INT32 maxv = 0;
+ boxptr which = NULL;
+
+ for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
+ if (boxp->volume > maxv) {
+ which = boxp;
+ maxv = boxp->volume;
+ }
+ }
+ return which;
+}
+
+
+LOCAL(void)
+update_box (j_decompress_ptr cinfo, boxptr boxp)
+/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
+/* and recompute its volume and population */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ histptr histp;
+ int c0,c1,c2;
+ int c0min,c0max,c1min,c1max,c2min,c2max;
+ INT32 dist0,dist1,dist2;
+ long ccount;
+
+ c0min = boxp->c0min; c0max = boxp->c0max;
+ c1min = boxp->c1min; c1max = boxp->c1max;
+ c2min = boxp->c2min; c2max = boxp->c2max;
+
+ if (c0max > c0min)
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c0min = c0min = c0;
+ goto have_c0min;
+ }
+ }
+ have_c0min:
+ if (c0max > c0min)
+ for (c0 = c0max; c0 >= c0min; c0--)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c0max = c0max = c0;
+ goto have_c0max;
+ }
+ }
+ have_c0max:
+ if (c1max > c1min)
+ for (c1 = c1min; c1 <= c1max; c1++)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c1min = c1min = c1;
+ goto have_c1min;
+ }
+ }
+ have_c1min:
+ if (c1max > c1min)
+ for (c1 = c1max; c1 >= c1min; c1--)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++)
+ if (*histp++ != 0) {
+ boxp->c1max = c1max = c1;
+ goto have_c1max;
+ }
+ }
+ have_c1max:
+ if (c2max > c2min)
+ for (c2 = c2min; c2 <= c2max; c2++)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1min][c2];
+ for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
+ if (*histp != 0) {
+ boxp->c2min = c2min = c2;
+ goto have_c2min;
+ }
+ }
+ have_c2min:
+ if (c2max > c2min)
+ for (c2 = c2max; c2 >= c2min; c2--)
+ for (c0 = c0min; c0 <= c0max; c0++) {
+ histp = & histogram[c0][c1min][c2];
+ for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS)
+ if (*histp != 0) {
+ boxp->c2max = c2max = c2;
+ goto have_c2max;
+ }
+ }
+ have_c2max:
+
+ /* Update box volume.
+ * We use 2-norm rather than real volume here; this biases the method
+ * against making long narrow boxes, and it has the side benefit that
+ * a box is splittable iff norm > 0.
+ * Since the differences are expressed in histogram-cell units,
+ * we have to shift back to JSAMPLE units to get consistent distances;
+ * after which, we scale according to the selected distance scale factors.
+ */
+ dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE;
+ dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE;
+ dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE;
+ boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2;
+
+ /* Now scan remaining volume of box and compute population */
+ ccount = 0;
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++, histp++)
+ if (*histp != 0) {
+ ccount++;
+ }
+ }
+ boxp->colorcount = ccount;
+}
+
+
+LOCAL(int)
+median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes,
+ int desired_colors)
+/* Repeatedly select and split the largest box until we have enough boxes */
+{
+ int n,lb;
+ int c0,c1,c2,cmax;
+ register boxptr b1,b2;
+
+ while (numboxes < desired_colors) {
+ /* Select box to split.
+ * Current algorithm: by population for first half, then by volume.
+ */
+ if (numboxes*2 <= desired_colors) {
+ b1 = find_biggest_color_pop(boxlist, numboxes);
+ } else {
+ b1 = find_biggest_volume(boxlist, numboxes);
+ }
+ if (b1 == NULL) /* no splittable boxes left! */
+ break;
+ b2 = &boxlist[numboxes]; /* where new box will go */
+ /* Copy the color bounds to the new box. */
+ b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max;
+ b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min;
+ /* Choose which axis to split the box on.
+ * Current algorithm: longest scaled axis.
+ * See notes in update_box about scaling distances.
+ */
+ c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE;
+ c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE;
+ c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE;
+ /* We want to break any ties in favor of green, then red, blue last.
+ * This code does the right thing for R,G,B or B,G,R color orders only.
+ */
+#if RGB_RED == 0
+ cmax = c1; n = 1;
+ if (c0 > cmax) { cmax = c0; n = 0; }
+ if (c2 > cmax) { n = 2; }
+#else
+ cmax = c1; n = 1;
+ if (c2 > cmax) { cmax = c2; n = 2; }
+ if (c0 > cmax) { n = 0; }
+#endif
+ /* Choose split point along selected axis, and update box bounds.
+ * Current algorithm: split at halfway point.
+ * (Since the box has been shrunk to minimum volume,
+ * any split will produce two nonempty subboxes.)
+ * Note that lb value is max for lower box, so must be < old max.
+ */
+ switch (n) {
+ case 0:
+ lb = (b1->c0max + b1->c0min) / 2;
+ b1->c0max = lb;
+ b2->c0min = lb+1;
+ break;
+ case 1:
+ lb = (b1->c1max + b1->c1min) / 2;
+ b1->c1max = lb;
+ b2->c1min = lb+1;
+ break;
+ case 2:
+ lb = (b1->c2max + b1->c2min) / 2;
+ b1->c2max = lb;
+ b2->c2min = lb+1;
+ break;
+ }
+ /* Update stats for boxes */
+ update_box(cinfo, b1);
+ update_box(cinfo, b2);
+ numboxes++;
+ }
+ return numboxes;
+}
+
+
+LOCAL(void)
+compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor)
+/* Compute representative color for a box, put it in colormap[icolor] */
+{
+ /* Current algorithm: mean weighted by pixels (not colors) */
+ /* Note it is important to get the rounding correct! */
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ histptr histp;
+ int c0,c1,c2;
+ int c0min,c0max,c1min,c1max,c2min,c2max;
+ long count;
+ long total = 0;
+ long c0total = 0;
+ long c1total = 0;
+ long c2total = 0;
+
+ c0min = boxp->c0min; c0max = boxp->c0max;
+ c1min = boxp->c1min; c1max = boxp->c1max;
+ c2min = boxp->c2min; c2max = boxp->c2max;
+
+ for (c0 = c0min; c0 <= c0max; c0++)
+ for (c1 = c1min; c1 <= c1max; c1++) {
+ histp = & histogram[c0][c1][c2min];
+ for (c2 = c2min; c2 <= c2max; c2++) {
+ if ((count = *histp++) != 0) {
+ total += count;
+ c0total += ((c0 << C0_SHIFT) + ((1<<C0_SHIFT)>>1)) * count;
+ c1total += ((c1 << C1_SHIFT) + ((1<<C1_SHIFT)>>1)) * count;
+ c2total += ((c2 << C2_SHIFT) + ((1<<C2_SHIFT)>>1)) * count;
+ }
+ }
+ }
+
+ cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total);
+ cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total);
+ cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total);
+}
+
+
+LOCAL(void)
+select_colors (j_decompress_ptr cinfo, int desired_colors)
+/* Master routine for color selection */
+{
+ boxptr boxlist;
+ int numboxes;
+ int i;
+
+ /* Allocate workspace for box list */
+ boxlist = (boxptr) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, desired_colors * SIZEOF(box));
+ /* Initialize one box containing whole space */
+ numboxes = 1;
+ boxlist[0].c0min = 0;
+ boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT;
+ boxlist[0].c1min = 0;
+ boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT;
+ boxlist[0].c2min = 0;
+ boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT;
+ /* Shrink it to actually-used volume and set its statistics */
+ update_box(cinfo, & boxlist[0]);
+ /* Perform median-cut to produce final box list */
+ numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors);
+ /* Compute the representative color for each box, fill colormap */
+ for (i = 0; i < numboxes; i++)
+ compute_color(cinfo, & boxlist[i], i);
+ cinfo->actual_number_of_colors = numboxes;
+ TRACEMS1(cinfo, 1, JTRC_QUANT_SELECTED, numboxes);
+}
+
+
+/*
+ * These routines are concerned with the time-critical task of mapping input
+ * colors to the nearest color in the selected colormap.
+ *
+ * We re-use the histogram space as an "inverse color map", essentially a
+ * cache for the results of nearest-color searches. All colors within a
+ * histogram cell will be mapped to the same colormap entry, namely the one
+ * closest to the cell's center. This may not be quite the closest entry to
+ * the actual input color, but it's almost as good. A zero in the cache
+ * indicates we haven't found the nearest color for that cell yet; the array
+ * is cleared to zeroes before starting the mapping pass. When we find the
+ * nearest color for a cell, its colormap index plus one is recorded in the
+ * cache for future use. The pass2 scanning routines call fill_inverse_cmap
+ * when they need to use an unfilled entry in the cache.
+ *
+ * Our method of efficiently finding nearest colors is based on the "locally
+ * sorted search" idea described by Heckbert and on the incremental distance
+ * calculation described by Spencer W. Thomas in chapter III.1 of Graphics
+ * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that
+ * the distances from a given colormap entry to each cell of the histogram can
+ * be computed quickly using an incremental method: the differences between
+ * distances to adjacent cells themselves differ by a constant. This allows a
+ * fairly fast implementation of the "brute force" approach of computing the
+ * distance from every colormap entry to every histogram cell. Unfortunately,
+ * it needs a work array to hold the best-distance-so-far for each histogram
+ * cell (because the inner loop has to be over cells, not colormap entries).
+ * The work array elements have to be INT32s, so the work array would need
+ * 256Kb at our recommended precision. This is not feasible in DOS machines.
+ *
+ * To get around these problems, we apply Thomas' method to compute the
+ * nearest colors for only the cells within a small subbox of the histogram.
+ * The work array need be only as big as the subbox, so the memory usage
+ * problem is solved. Furthermore, we need not fill subboxes that are never
+ * referenced in pass2; many images use only part of the color gamut, so a
+ * fair amount of work is saved. An additional advantage of this
+ * approach is that we can apply Heckbert's locality criterion to quickly
+ * eliminate colormap entries that are far away from the subbox; typically
+ * three-fourths of the colormap entries are rejected by Heckbert's criterion,
+ * and we need not compute their distances to individual cells in the subbox.
+ * The speed of this approach is heavily influenced by the subbox size: too
+ * small means too much overhead, too big loses because Heckbert's criterion
+ * can't eliminate as many colormap entries. Empirically the best subbox
+ * size seems to be about 1/512th of the histogram (1/8th in each direction).
+ *
+ * Thomas' article also describes a refined method which is asymptotically
+ * faster than the brute-force method, but it is also far more complex and
+ * cannot efficiently be applied to small subboxes. It is therefore not
+ * useful for programs intended to be portable to DOS machines. On machines
+ * with plenty of memory, filling the whole histogram in one shot with Thomas'
+ * refined method might be faster than the present code --- but then again,
+ * it might not be any faster, and it's certainly more complicated.
+ */
+
+
+/* log2(histogram cells in update box) for each axis; this can be adjusted */
+#define BOX_C0_LOG (HIST_C0_BITS-3)
+#define BOX_C1_LOG (HIST_C1_BITS-3)
+#define BOX_C2_LOG (HIST_C2_BITS-3)
+
+#define BOX_C0_ELEMS (1<<BOX_C0_LOG) /* # of hist cells in update box */
+#define BOX_C1_ELEMS (1<<BOX_C1_LOG)
+#define BOX_C2_ELEMS (1<<BOX_C2_LOG)
+
+#define BOX_C0_SHIFT (C0_SHIFT + BOX_C0_LOG)
+#define BOX_C1_SHIFT (C1_SHIFT + BOX_C1_LOG)
+#define BOX_C2_SHIFT (C2_SHIFT + BOX_C2_LOG)
+
+
+/*
+ * The next three routines implement inverse colormap filling. They could
+ * all be folded into one big routine, but splitting them up this way saves
+ * some stack space (the mindist[] and bestdist[] arrays need not coexist)
+ * and may allow some compilers to produce better code by registerizing more
+ * inner-loop variables.
+ */
+
+LOCAL(int)
+find_nearby_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
+ JSAMPLE colorlist[])
+/* Locate the colormap entries close enough to an update box to be candidates
+ * for the nearest entry to some cell(s) in the update box. The update box
+ * is specified by the center coordinates of its first cell. The number of
+ * candidate colormap entries is returned, and their colormap indexes are
+ * placed in colorlist[].
+ * This routine uses Heckbert's "locally sorted search" criterion to select
+ * the colors that need further consideration.
+ */
+{
+ int numcolors = cinfo->actual_number_of_colors;
+ int maxc0, maxc1, maxc2;
+ int centerc0, centerc1, centerc2;
+ int i, x, ncolors;
+ INT32 minmaxdist, min_dist, max_dist, tdist;
+ INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */
+
+ /* Compute true coordinates of update box's upper corner and center.
+ * Actually we compute the coordinates of the center of the upper-corner
+ * histogram cell, which are the upper bounds of the volume we care about.
+ * Note that since ">>" rounds down, the "center" values may be closer to
+ * min than to max; hence comparisons to them must be "<=", not "<".
+ */
+ maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT));
+ centerc0 = (minc0 + maxc0) >> 1;
+ maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT));
+ centerc1 = (minc1 + maxc1) >> 1;
+ maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT));
+ centerc2 = (minc2 + maxc2) >> 1;
+
+ /* For each color in colormap, find:
+ * 1. its minimum squared-distance to any point in the update box
+ * (zero if color is within update box);
+ * 2. its maximum squared-distance to any point in the update box.
+ * Both of these can be found by considering only the corners of the box.
+ * We save the minimum distance for each color in mindist[];
+ * only the smallest maximum distance is of interest.
+ */
+ minmaxdist = 0x7FFFFFFFL;
+
+ for (i = 0; i < numcolors; i++) {
+ /* We compute the squared-c0-distance term, then add in the other two. */
+ x = GETJSAMPLE(cinfo->colormap[0][i]);
+ if (x < minc0) {
+ tdist = (x - minc0) * C0_SCALE;
+ min_dist = tdist*tdist;
+ tdist = (x - maxc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else if (x > maxc0) {
+ tdist = (x - maxc0) * C0_SCALE;
+ min_dist = tdist*tdist;
+ tdist = (x - minc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ min_dist = 0;
+ if (x <= centerc0) {
+ tdist = (x - maxc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ } else {
+ tdist = (x - minc0) * C0_SCALE;
+ max_dist = tdist*tdist;
+ }
+ }
+
+ x = GETJSAMPLE(cinfo->colormap[1][i]);
+ if (x < minc1) {
+ tdist = (x - minc1) * C1_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - maxc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else if (x > maxc1) {
+ tdist = (x - maxc1) * C1_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - minc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ if (x <= centerc1) {
+ tdist = (x - maxc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ tdist = (x - minc1) * C1_SCALE;
+ max_dist += tdist*tdist;
+ }
+ }
+
+ x = GETJSAMPLE(cinfo->colormap[2][i]);
+ if (x < minc2) {
+ tdist = (x - minc2) * C2_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - maxc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else if (x > maxc2) {
+ tdist = (x - maxc2) * C2_SCALE;
+ min_dist += tdist*tdist;
+ tdist = (x - minc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ /* within cell range so no contribution to min_dist */
+ if (x <= centerc2) {
+ tdist = (x - maxc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ } else {
+ tdist = (x - minc2) * C2_SCALE;
+ max_dist += tdist*tdist;
+ }
+ }
+
+ mindist[i] = min_dist; /* save away the results */
+ if (max_dist < minmaxdist)
+ minmaxdist = max_dist;
+ }
+
+ /* Now we know that no cell in the update box is more than minmaxdist
+ * away from some colormap entry. Therefore, only colors that are
+ * within minmaxdist of some part of the box need be considered.
+ */
+ ncolors = 0;
+ for (i = 0; i < numcolors; i++) {
+ if (mindist[i] <= minmaxdist)
+ colorlist[ncolors++] = (JSAMPLE) i;
+ }
+ return ncolors;
+}
+
+
+LOCAL(void)
+find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2,
+ int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[])
+/* Find the closest colormap entry for each cell in the update box,
+ * given the list of candidate colors prepared by find_nearby_colors.
+ * Return the indexes of the closest entries in the bestcolor[] array.
+ * This routine uses Thomas' incremental distance calculation method to
+ * find the distance from a colormap entry to successive cells in the box.
+ */
+{
+ int ic0, ic1, ic2;
+ int i, icolor;
+ register INT32 * bptr; /* pointer into bestdist[] array */
+ JSAMPLE * cptr; /* pointer into bestcolor[] array */
+ INT32 dist0, dist1; /* initial distance values */
+ register INT32 dist2; /* current distance in inner loop */
+ INT32 xx0, xx1; /* distance increments */
+ register INT32 xx2;
+ INT32 inc0, inc1, inc2; /* initial values for increments */
+ /* This array holds the distance to the nearest-so-far color for each cell */
+ INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+ /* Initialize best-distance for each cell of the update box */
+ bptr = bestdist;
+ for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--)
+ *bptr++ = 0x7FFFFFFFL;
+
+ /* For each color selected by find_nearby_colors,
+ * compute its distance to the center of each cell in the box.
+ * If that's less than best-so-far, update best distance and color number.
+ */
+
+ /* Nominal steps between cell centers ("x" in Thomas article) */
+#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE)
+#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE)
+#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE)
+
+ for (i = 0; i < numcolors; i++) {
+ icolor = GETJSAMPLE(colorlist[i]);
+ /* Compute (square of) distance from minc0/c1/c2 to this color */
+ inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE;
+ dist0 = inc0*inc0;
+ inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE;
+ dist0 += inc1*inc1;
+ inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE;
+ dist0 += inc2*inc2;
+ /* Form the initial difference increments */
+ inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0;
+ inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1;
+ inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2;
+ /* Now loop over all cells in box, updating distance per Thomas method */
+ bptr = bestdist;
+ cptr = bestcolor;
+ xx0 = inc0;
+ for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) {
+ dist1 = dist0;
+ xx1 = inc1;
+ for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) {
+ dist2 = dist1;
+ xx2 = inc2;
+ for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) {
+ if (dist2 < *bptr) {
+ *bptr = dist2;
+ *cptr = (JSAMPLE) icolor;
+ }
+ dist2 += xx2;
+ xx2 += 2 * STEP_C2 * STEP_C2;
+ bptr++;
+ cptr++;
+ }
+ dist1 += xx1;
+ xx1 += 2 * STEP_C1 * STEP_C1;
+ }
+ dist0 += xx0;
+ xx0 += 2 * STEP_C0 * STEP_C0;
+ }
+ }
+}
+
+
+LOCAL(void)
+fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2)
+/* Fill the inverse-colormap entries in the update box that contains */
+/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */
+/* we can fill as many others as we wish.) */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ int minc0, minc1, minc2; /* lower left corner of update box */
+ int ic0, ic1, ic2;
+ register JSAMPLE * cptr; /* pointer into bestcolor[] array */
+ register histptr cachep; /* pointer into main cache array */
+ /* This array lists the candidate colormap indexes. */
+ JSAMPLE colorlist[MAXNUMCOLORS];
+ int numcolors; /* number of candidate colors */
+ /* This array holds the actually closest colormap index for each cell. */
+ JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS];
+
+ /* Convert cell coordinates to update box ID */
+ c0 >>= BOX_C0_LOG;
+ c1 >>= BOX_C1_LOG;
+ c2 >>= BOX_C2_LOG;
+
+ /* Compute true coordinates of update box's origin corner.
+ * Actually we compute the coordinates of the center of the corner
+ * histogram cell, which are the lower bounds of the volume we care about.
+ */
+ minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1);
+ minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1);
+ minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1);
+
+ /* Determine which colormap entries are close enough to be candidates
+ * for the nearest entry to some cell in the update box.
+ */
+ numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist);
+
+ /* Determine the actually nearest colors. */
+ find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist,
+ bestcolor);
+
+ /* Save the best color numbers (plus 1) in the main cache array */
+ c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */
+ c1 <<= BOX_C1_LOG;
+ c2 <<= BOX_C2_LOG;
+ cptr = bestcolor;
+ for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) {
+ for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) {
+ cachep = & histogram[c0+ic0][c1+ic1][c2];
+ for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) {
+ *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1);
+ }
+ }
+ }
+}
+
+
+/*
+ * Map some rows of pixels to the output colormapped representation.
+ */
+
+METHODDEF(void)
+pass2_no_dither (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+/* This version performs no dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ register JSAMPROW inptr, outptr;
+ register histptr cachep;
+ register int c0, c1, c2;
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+
+ for (row = 0; row < num_rows; row++) {
+ inptr = input_buf[row];
+ outptr = output_buf[row];
+ for (col = width; col > 0; col--) {
+ /* get pixel value and index into the cache */
+ c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT;
+ c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT;
+ c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT;
+ cachep = & histogram[c0][c1][c2];
+ /* If we have not seen this color before, find nearest colormap entry */
+ /* and update the cache */
+ if (*cachep == 0)
+ fill_inverse_cmap(cinfo, c0,c1,c2);
+ /* Now emit the colormap index for this cell */
+ *outptr++ = (JSAMPLE) (*cachep - 1);
+ }
+ }
+}
+
+
+METHODDEF(void)
+pass2_fs_dither (j_decompress_ptr cinfo,
+ JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)
+/* This version performs Floyd-Steinberg dithering */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */
+ LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */
+ LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */
+ register FSERRPTR errorptr; /* => fserrors[] at column before current */
+ JSAMPROW inptr; /* => current input pixel */
+ JSAMPROW outptr; /* => current output pixel */
+ histptr cachep;
+ int dir; /* +1 or -1 depending on direction */
+ int dir3; /* 3*dir, for advancing inptr & errorptr */
+ int row;
+ JDIMENSION col;
+ JDIMENSION width = cinfo->output_width;
+ JSAMPLE *range_limit = cinfo->sample_range_limit;
+ int *error_limit = cquantize->error_limiter;
+ JSAMPROW colormap0 = cinfo->colormap[0];
+ JSAMPROW colormap1 = cinfo->colormap[1];
+ JSAMPROW colormap2 = cinfo->colormap[2];
+ SHIFT_TEMPS
+
+ for (row = 0; row < num_rows; row++) {
+ inptr = input_buf[row];
+ outptr = output_buf[row];
+ if (cquantize->on_odd_row) {
+ /* work right to left in this row */
+ inptr += (width-1) * 3; /* so point to rightmost pixel */
+ outptr += width-1;
+ dir = -1;
+ dir3 = -3;
+ errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */
+ cquantize->on_odd_row = FALSE; /* flip for next time */
+ } else {
+ /* work left to right in this row */
+ dir = 1;
+ dir3 = 3;
+ errorptr = cquantize->fserrors; /* => entry before first real column */
+ cquantize->on_odd_row = TRUE; /* flip for next time */
+ }
+ /* Preset error values: no error propagated to first pixel from left */
+ cur0 = cur1 = cur2 = 0;
+ /* and no error propagated to row below yet */
+ belowerr0 = belowerr1 = belowerr2 = 0;
+ bpreverr0 = bpreverr1 = bpreverr2 = 0;
+
+ for (col = width; col > 0; col--) {
+ /* curN holds the error propagated from the previous pixel on the
+ * current line. Add the error propagated from the previous line
+ * to form the complete error correction term for this pixel, and
+ * round the error term (which is expressed * 16) to an integer.
+ * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
+ * for either sign of the error value.
+ * Note: errorptr points to *previous* column's array entry.
+ */
+ cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4);
+ cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4);
+ cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4);
+ /* Limit the error using transfer function set by init_error_limit.
+ * See comments with init_error_limit for rationale.
+ */
+ cur0 = error_limit[cur0];
+ cur1 = error_limit[cur1];
+ cur2 = error_limit[cur2];
+ /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+ * The maximum error is +- MAXJSAMPLE (or less with error limiting);
+ * this sets the required size of the range_limit array.
+ */
+ cur0 += GETJSAMPLE(inptr[0]);
+ cur1 += GETJSAMPLE(inptr[1]);
+ cur2 += GETJSAMPLE(inptr[2]);
+ cur0 = GETJSAMPLE(range_limit[cur0]);
+ cur1 = GETJSAMPLE(range_limit[cur1]);
+ cur2 = GETJSAMPLE(range_limit[cur2]);
+ /* Index into the cache with adjusted pixel value */
+ cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT];
+ /* If we have not seen this color before, find nearest colormap */
+ /* entry and update the cache */
+ if (*cachep == 0)
+ fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT);
+ /* Now emit the colormap index for this cell */
+ { register int pixcode = *cachep - 1;
+ *outptr = (JSAMPLE) pixcode;
+ /* Compute representation error for this pixel */
+ cur0 -= GETJSAMPLE(colormap0[pixcode]);
+ cur1 -= GETJSAMPLE(colormap1[pixcode]);
+ cur2 -= GETJSAMPLE(colormap2[pixcode]);
+ }
+ /* Compute error fractions to be propagated to adjacent pixels.
+ * Add these into the running sums, and simultaneously shift the
+ * next-line error sums left by 1 column.
+ */
+ { register LOCFSERROR bnexterr, delta;
+
+ bnexterr = cur0; /* Process component 0 */
+ delta = cur0 * 2;
+ cur0 += delta; /* form error * 3 */
+ errorptr[0] = (FSERROR) (bpreverr0 + cur0);
+ cur0 += delta; /* form error * 5 */
+ bpreverr0 = belowerr0 + cur0;
+ belowerr0 = bnexterr;
+ cur0 += delta; /* form error * 7 */
+ bnexterr = cur1; /* Process component 1 */
+ delta = cur1 * 2;
+ cur1 += delta; /* form error * 3 */
+ errorptr[1] = (FSERROR) (bpreverr1 + cur1);
+ cur1 += delta; /* form error * 5 */
+ bpreverr1 = belowerr1 + cur1;
+ belowerr1 = bnexterr;
+ cur1 += delta; /* form error * 7 */
+ bnexterr = cur2; /* Process component 2 */
+ delta = cur2 * 2;
+ cur2 += delta; /* form error * 3 */
+ errorptr[2] = (FSERROR) (bpreverr2 + cur2);
+ cur2 += delta; /* form error * 5 */
+ bpreverr2 = belowerr2 + cur2;
+ belowerr2 = bnexterr;
+ cur2 += delta; /* form error * 7 */
+ }
+ /* At this point curN contains the 7/16 error value to be propagated
+ * to the next pixel on the current line, and all the errors for the
+ * next line have been shifted over. We are therefore ready to move on.
+ */
+ inptr += dir3; /* Advance pixel pointers to next column */
+ outptr += dir;
+ errorptr += dir3; /* advance errorptr to current column */
+ }
+ /* Post-loop cleanup: we must unload the final error values into the
+ * final fserrors[] entry. Note we need not unload belowerrN because
+ * it is for the dummy column before or after the actual array.
+ */
+ errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */
+ errorptr[1] = (FSERROR) bpreverr1;
+ errorptr[2] = (FSERROR) bpreverr2;
+ }
+}
+
+
+/*
+ * Initialize the error-limiting transfer function (lookup table).
+ * The raw F-S error computation can potentially compute error values of up to
+ * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
+ * much less, otherwise obviously wrong pixels will be created. (Typical
+ * effects include weird fringes at color-area boundaries, isolated bright
+ * pixels in a dark area, etc.) The standard advice for avoiding this problem
+ * is to ensure that the "corners" of the color cube are allocated as output
+ * colors; then repeated errors in the same direction cannot cause cascading
+ * error buildup. However, that only prevents the error from getting
+ * completely out of hand; Aaron Giles reports that error limiting improves
+ * the results even with corner colors allocated.
+ * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
+ * well, but the smoother transfer function used below is even better. Thanks
+ * to Aaron Giles for this idea.
+ */
+
+LOCAL(void)
+init_error_limit (j_decompress_ptr cinfo)
+/* Allocate and fill in the error_limiter table */
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ int * table;
+ int in, out;
+
+ table = (int *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, (MAXJSAMPLE*2+1) * SIZEOF(int));
+ table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */
+ cquantize->error_limiter = table;
+
+#define STEPSIZE ((MAXJSAMPLE+1)/16)
+ /* Map errors 1:1 up to +- MAXJSAMPLE/16 */
+ out = 0;
+ for (in = 0; in < STEPSIZE; in++, out++) {
+ table[in] = out; table[-in] = -out;
+ }
+ /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */
+ for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) {
+ table[in] = out; table[-in] = -out;
+ }
+ /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */
+ for (; in <= MAXJSAMPLE; in++) {
+ table[in] = out; table[-in] = -out;
+ }
+#undef STEPSIZE
+}
+
+
+/*
+ * Finish up at the end of each pass.
+ */
+
+METHODDEF(void)
+finish_pass1 (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+ /* Select the representative colors and fill in cinfo->colormap */
+ cinfo->colormap = cquantize->sv_colormap;
+ select_colors(cinfo, cquantize->desired);
+ /* Force next pass to zero the color index table */
+ cquantize->needs_zeroed = TRUE;
+}
+
+
+METHODDEF(void)
+finish_pass2 (j_decompress_ptr cinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * Initialize for each processing pass.
+ */
+
+METHODDEF(void)
+start_pass_2_quant (j_decompress_ptr cinfo, boolean is_pre_scan)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+ hist3d histogram = cquantize->histogram;
+ int i;
+
+ /* Only F-S dithering or no dithering is supported. */
+ /* If user asks for ordered dither, give him F-S. */
+ if (cinfo->dither_mode != JDITHER_NONE)
+ cinfo->dither_mode = JDITHER_FS;
+
+ if (is_pre_scan) {
+ /* Set up method pointers */
+ cquantize->pub.color_quantize = prescan_quantize;
+ cquantize->pub.finish_pass = finish_pass1;
+ cquantize->needs_zeroed = TRUE; /* Always zero histogram */
+ } else {
+ /* Set up method pointers */
+ if (cinfo->dither_mode == JDITHER_FS)
+ cquantize->pub.color_quantize = pass2_fs_dither;
+ else
+ cquantize->pub.color_quantize = pass2_no_dither;
+ cquantize->pub.finish_pass = finish_pass2;
+
+ /* Make sure color count is acceptable */
+ i = cinfo->actual_number_of_colors;
+ if (i < 1)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 1);
+ if (i > MAXNUMCOLORS)
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+
+ if (cinfo->dither_mode == JDITHER_FS) {
+ size_t arraysize = (size_t) ((cinfo->output_width + 2) *
+ (3 * SIZEOF(FSERROR)));
+ /* Allocate Floyd-Steinberg workspace if we didn't already. */
+ if (cquantize->fserrors == NULL)
+ cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, arraysize);
+ /* Initialize the propagated errors to zero. */
+ FMEMZERO((void FAR *) cquantize->fserrors, arraysize);
+ /* Make the error-limit table if we didn't already. */
+ if (cquantize->error_limiter == NULL)
+ init_error_limit(cinfo);
+ cquantize->on_odd_row = FALSE;
+ }
+
+ }
+ /* Zero the histogram or inverse color map, if necessary */
+ if (cquantize->needs_zeroed) {
+ for (i = 0; i < HIST_C0_ELEMS; i++) {
+ FMEMZERO((void FAR *) histogram[i],
+ HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+ }
+ cquantize->needs_zeroed = FALSE;
+ }
+}
+
+
+/*
+ * Switch to a new external colormap between output passes.
+ */
+
+METHODDEF(void)
+new_color_map_2_quant (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize;
+
+ /* Reset the inverse color map */
+ cquantize->needs_zeroed = TRUE;
+}
+
+
+/*
+ * Module initialization routine for 2-pass color quantization.
+ */
+
+GLOBAL(void)
+jinit_2pass_quantizer (j_decompress_ptr cinfo)
+{
+ my_cquantize_ptr cquantize;
+ int i;
+
+ cquantize = (my_cquantize_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(my_cquantizer));
+ cinfo->cquantize = (struct jpeg_color_quantizer *) cquantize;
+ cquantize->pub.start_pass = start_pass_2_quant;
+ cquantize->pub.new_color_map = new_color_map_2_quant;
+ cquantize->fserrors = NULL; /* flag optional arrays not allocated */
+ cquantize->error_limiter = NULL;
+
+ /* Make sure jdmaster didn't give me a case I can't handle */
+ if (cinfo->out_color_components != 3)
+ ERREXIT(cinfo, JERR_NOTIMPL);
+
+ /* Allocate the histogram/inverse colormap storage */
+ cquantize->histogram = (hist3d) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, HIST_C0_ELEMS * SIZEOF(hist2d));
+ for (i = 0; i < HIST_C0_ELEMS; i++) {
+ cquantize->histogram[i] = (hist2d) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ HIST_C1_ELEMS*HIST_C2_ELEMS * SIZEOF(histcell));
+ }
+ cquantize->needs_zeroed = TRUE; /* histogram is garbage now */
+
+ /* Allocate storage for the completed colormap, if required.
+ * We do this now since it is FAR storage and may affect
+ * the memory manager's space calculations.
+ */
+ if (cinfo->enable_2pass_quant) {
+ /* Make sure color count is acceptable */
+ int desired = cinfo->desired_number_of_colors;
+ /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
+ if (desired < 8)
+ ERREXIT1(cinfo, JERR_QUANT_FEW_COLORS, 8);
+ /* Make sure colormap indexes can be represented by JSAMPLEs */
+ if (desired > MAXNUMCOLORS)
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, MAXNUMCOLORS);
+ cquantize->sv_colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo,JPOOL_IMAGE, (JDIMENSION) desired, (JDIMENSION) 3);
+ cquantize->desired = desired;
+ } else
+ cquantize->sv_colormap = NULL;
+
+ /* Only F-S dithering or no dithering is supported. */
+ /* If user asks for ordered dither, give him F-S. */
+ if (cinfo->dither_mode != JDITHER_NONE)
+ cinfo->dither_mode = JDITHER_FS;
+
+ /* Allocate Floyd-Steinberg workspace if necessary.
+ * This isn't really needed until pass 2, but again it is FAR storage.
+ * Although we will cope with a later change in dither_mode,
+ * we do not promise to honor max_memory_to_use if dither_mode changes.
+ */
+ if (cinfo->dither_mode == JDITHER_FS) {
+ cquantize->fserrors = (FSERRPTR) (*cinfo->mem->alloc_large)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) ((cinfo->output_width + 2) * (3 * SIZEOF(FSERROR))));
+ /* Might as well create the error-limiting table too. */
+ init_error_limit(cinfo);
+ }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/jpg/jutils.c b/jpg/jutils.c
new file mode 100644
index 0000000..5b16b6d
--- /dev/null
+++ b/jpg/jutils.c
@@ -0,0 +1,227 @@
+/*
+ * jutils.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2009-2011 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains tables and miscellaneous utility routines needed
+ * for both compression and decompression.
+ * Note we prefix all global names with "j" to minimize conflicts with
+ * a surrounding application.
+ */
+
+#define JPEG_INTERNALS
+#include "jinclude.h"
+#include "jpeglib.h"
+
+
+/*
+ * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element
+ * of a DCT block read in natural order (left to right, top to bottom).
+ */
+
+#if 0 /* This table is not actually needed in v6a */
+
+const int jpeg_zigzag_order[DCTSIZE2] = {
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63
+};
+
+#endif
+
+/*
+ * jpeg_natural_order[i] is the natural-order position of the i'th element
+ * of zigzag order.
+ *
+ * When reading corrupted data, the Huffman decoders could attempt
+ * to reference an entry beyond the end of this array (if the decoded
+ * zero run length reaches past the end of the block). To prevent
+ * wild stores without adding an inner-loop test, we put some extra
+ * "63"s after the real entries. This will cause the extra coefficient
+ * to be stored in location 63 of the block, not somewhere random.
+ * The worst case would be a run-length of 15, which means we need 16
+ * fake entries.
+ */
+
+const int jpeg_natural_order[DCTSIZE2+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order7[7*7+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 14, 21, 28, 35,
+ 42, 49, 50, 43, 36, 29, 22, 30,
+ 37, 44, 51, 52, 45, 38, 46, 53,
+ 54,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order6[6*6+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 41, 34, 27,
+ 20, 13, 21, 28, 35, 42, 43, 36,
+ 29, 37, 44, 45,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order5[5*5+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 12,
+ 19, 26, 33, 34, 27, 20, 28, 35,
+ 36,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order4[4*4+16] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 25, 18, 11, 19, 26, 27,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order3[3*3+16] = {
+ 0, 1, 8, 16, 9, 2, 10, 17,
+ 18,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+const int jpeg_natural_order2[2*2+16] = {
+ 0, 1, 8, 9,
+ 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */
+ 63, 63, 63, 63, 63, 63, 63, 63
+};
+
+
+/*
+ * Arithmetic utilities
+ */
+
+GLOBAL(long)
+jdiv_round_up (long a, long b)
+/* Compute a/b rounded up to next integer, ie, ceil(a/b) */
+/* Assumes a >= 0, b > 0 */
+{
+ return (a + b - 1L) / b;
+}
+
+
+GLOBAL(long)
+jround_up (long a, long b)
+/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */
+/* Assumes a >= 0, b > 0 */
+{
+ a += b - 1L;
+ return a - (a % b);
+}
+
+
+/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays
+ * and coefficient-block arrays. This won't work on 80x86 because the arrays
+ * are FAR and we're assuming a small-pointer memory model. However, some
+ * DOS compilers provide far-pointer versions of memcpy() and memset() even
+ * in the small-model libraries. These will be used if USE_FMEM is defined.
+ * Otherwise, the routines below do it the hard way. (The performance cost
+ * is not all that great, because these routines aren't very heavily used.)
+ */
+
+#ifndef NEED_FAR_POINTERS /* normal case, same as regular macro */
+#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size)
+#else /* 80x86 case, define if we can */
+#ifdef USE_FMEM
+#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size))
+#else
+/* This function is for use by the FMEMZERO macro defined in jpegint.h.
+ * Do not call this function directly, use the FMEMZERO macro instead.
+ */
+GLOBAL(void)
+jzero_far (void FAR * target, size_t bytestozero)
+/* Zero out a chunk of FAR memory. */
+/* This might be sample-array data, block-array data, or alloc_large data. */
+{
+ register char FAR * ptr = (char FAR *) target;
+ register size_t count;
+
+ for (count = bytestozero; count > 0; count--) {
+ *ptr++ = 0;
+ }
+}
+#endif
+#endif
+
+
+GLOBAL(void)
+jcopy_sample_rows (JSAMPARRAY input_array, int source_row,
+ JSAMPARRAY output_array, int dest_row,
+ int num_rows, JDIMENSION num_cols)
+/* Copy some rows of samples from one place to another.
+ * num_rows rows are copied from input_array[source_row++]
+ * to output_array[dest_row++]; these areas may overlap for duplication.
+ * The source and destination arrays must be at least as wide as num_cols.
+ */
+{
+ register JSAMPROW inptr, outptr;
+#ifdef FMEMCOPY
+ register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE));
+#else
+ register JDIMENSION count;
+#endif
+ register int row;
+
+ input_array += source_row;
+ output_array += dest_row;
+
+ for (row = num_rows; row > 0; row--) {
+ inptr = *input_array++;
+ outptr = *output_array++;
+#ifdef FMEMCOPY
+ FMEMCOPY(outptr, inptr, count);
+#else
+ for (count = num_cols; count > 0; count--)
+ *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */
+#endif
+ }
+}
+
+
+GLOBAL(void)
+jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row,
+ JDIMENSION num_blocks)
+/* Copy a row of coefficient blocks from one place to another. */
+{
+#ifdef FMEMCOPY
+ FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF)));
+#else
+ register JCOEFPTR inptr, outptr;
+ register long count;
+
+ inptr = (JCOEFPTR) input_row;
+ outptr = (JCOEFPTR) output_row;
+ for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) {
+ *outptr++ = *inptr++;
+ }
+#endif
+}
diff --git a/jpg/jversion.h b/jpg/jversion.h
new file mode 100644
index 0000000..5d49151
--- /dev/null
+++ b/jpg/jversion.h
@@ -0,0 +1,14 @@
+/*
+ * jversion.h
+ *
+ * Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains software version identification.
+ */
+
+
+#define JVERSION "8d 15-Jan-2012"
+
+#define JCOPYRIGHT "Copyright (C) 2012, Thomas G. Lane, Guido Vollbeding"
diff --git a/jpg/libjpeg.map b/jpg/libjpeg.map
new file mode 100644
index 0000000..ac77dca
--- /dev/null
+++ b/jpg/libjpeg.map
@@ -0,0 +1,4 @@
+LIBJPEG_8.0 {
+ global:
+ *;
+};
diff --git a/jpg/libjpeg.txt b/jpg/libjpeg.txt
new file mode 100644
index 0000000..9702669
--- /dev/null
+++ b/jpg/libjpeg.txt
@@ -0,0 +1,3085 @@
+USING THE IJG JPEG LIBRARY
+
+Copyright (C) 1994-2011, Thomas G. Lane, Guido Vollbeding.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file describes how to use the IJG JPEG library within an application
+program. Read it if you want to write a program that uses the library.
+
+The file example.c provides heavily commented skeleton code for calling the
+JPEG library. Also see jpeglib.h (the include file to be used by application
+programs) for full details about data structures and function parameter lists.
+The library source code, of course, is the ultimate reference.
+
+Note that there have been *major* changes from the application interface
+presented by IJG version 4 and earlier versions. The old design had several
+inherent limitations, and it had accumulated a lot of cruft as we added
+features while trying to minimize application-interface changes. We have
+sacrificed backward compatibility in the version 5 rewrite, but we think the
+improvements justify this.
+
+
+TABLE OF CONTENTS
+-----------------
+
+Overview:
+ Functions provided by the library
+ Outline of typical usage
+Basic library usage:
+ Data formats
+ Compression details
+ Decompression details
+ Mechanics of usage: include files, linking, etc
+Advanced features:
+ Compression parameter selection
+ Decompression parameter selection
+ Special color spaces
+ Error handling
+ Compressed data handling (source and destination managers)
+ I/O suspension
+ Progressive JPEG support
+ Buffered-image mode
+ Abbreviated datastreams and multiple images
+ Special markers
+ Raw (downsampled) image data
+ Really raw data: DCT coefficients
+ Progress monitoring
+ Memory management
+ Memory usage
+ Library compile-time options
+ Portability considerations
+ Notes for MS-DOS implementors
+
+You should read at least the overview and basic usage sections before trying
+to program with the library. The sections on advanced features can be read
+if and when you need them.
+
+
+OVERVIEW
+========
+
+Functions provided by the library
+---------------------------------
+
+The IJG JPEG library provides C code to read and write JPEG-compressed image
+files. The surrounding application program receives or supplies image data a
+scanline at a time, using a straightforward uncompressed image format. All
+details of color conversion and other preprocessing/postprocessing can be
+handled by the library.
+
+The library includes a substantial amount of code that is not covered by the
+JPEG standard but is necessary for typical applications of JPEG. These
+functions preprocess the image before JPEG compression or postprocess it after
+decompression. They include colorspace conversion, downsampling/upsampling,
+and color quantization. The application indirectly selects use of this code
+by specifying the format in which it wishes to supply or receive image data.
+For example, if colormapped output is requested, then the decompression
+library automatically invokes color quantization.
+
+A wide range of quality vs. speed tradeoffs are possible in JPEG processing,
+and even more so in decompression postprocessing. The decompression library
+provides multiple implementations that cover most of the useful tradeoffs,
+ranging from very-high-quality down to fast-preview operation. On the
+compression side we have generally not provided low-quality choices, since
+compression is normally less time-critical. It should be understood that the
+low-quality modes may not meet the JPEG standard's accuracy requirements;
+nonetheless, they are useful for viewers.
+
+A word about functions *not* provided by the library. We handle a subset of
+the ISO JPEG standard; most baseline, extended-sequential, and progressive
+JPEG processes are supported. (Our subset includes all features now in common
+use.) Unsupported ISO options include:
+ * Hierarchical storage
+ * Lossless JPEG
+ * DNL marker
+ * Nonintegral subsampling ratios
+We support both 8- and 12-bit data precision, but this is a compile-time
+choice rather than a run-time choice; hence it is difficult to use both
+precisions in a single application.
+
+By itself, the library handles only interchange JPEG datastreams --- in
+particular the widely used JFIF file format. The library can be used by
+surrounding code to process interchange or abbreviated JPEG datastreams that
+are embedded in more complex file formats. (For example, this library is
+used by the free LIBTIFF library to support JPEG compression in TIFF.)
+
+
+Outline of typical usage
+------------------------
+
+The rough outline of a JPEG compression operation is:
+
+ Allocate and initialize a JPEG compression object
+ Specify the destination for the compressed data (eg, a file)
+ Set parameters for compression, including image size & colorspace
+ jpeg_start_compress(...);
+ while (scan lines remain to be written)
+ jpeg_write_scanlines(...);
+ jpeg_finish_compress(...);
+ Release the JPEG compression object
+
+A JPEG compression object holds parameters and working state for the JPEG
+library. We make creation/destruction of the object separate from starting
+or finishing compression of an image; the same object can be re-used for a
+series of image compression operations. This makes it easy to re-use the
+same parameter settings for a sequence of images. Re-use of a JPEG object
+also has important implications for processing abbreviated JPEG datastreams,
+as discussed later.
+
+The image data to be compressed is supplied to jpeg_write_scanlines() from
+in-memory buffers. If the application is doing file-to-file compression,
+reading image data from the source file is the application's responsibility.
+The library emits compressed data by calling a "data destination manager",
+which typically will write the data into a file; but the application can
+provide its own destination manager to do something else.
+
+Similarly, the rough outline of a JPEG decompression operation is:
+
+ Allocate and initialize a JPEG decompression object
+ Specify the source of the compressed data (eg, a file)
+ Call jpeg_read_header() to obtain image info
+ Set parameters for decompression
+ jpeg_start_decompress(...);
+ while (scan lines remain to be read)
+ jpeg_read_scanlines(...);
+ jpeg_finish_decompress(...);
+ Release the JPEG decompression object
+
+This is comparable to the compression outline except that reading the
+datastream header is a separate step. This is helpful because information
+about the image's size, colorspace, etc is available when the application
+selects decompression parameters. For example, the application can choose an
+output scaling ratio that will fit the image into the available screen size.
+
+The decompression library obtains compressed data by calling a data source
+manager, which typically will read the data from a file; but other behaviors
+can be obtained with a custom source manager. Decompressed data is delivered
+into in-memory buffers passed to jpeg_read_scanlines().
+
+It is possible to abort an incomplete compression or decompression operation
+by calling jpeg_abort(); or, if you do not need to retain the JPEG object,
+simply release it by calling jpeg_destroy().
+
+JPEG compression and decompression objects are two separate struct types.
+However, they share some common fields, and certain routines such as
+jpeg_destroy() can work on either type of object.
+
+The JPEG library has no static variables: all state is in the compression
+or decompression object. Therefore it is possible to process multiple
+compression and decompression operations concurrently, using multiple JPEG
+objects.
+
+Both compression and decompression can be done in an incremental memory-to-
+memory fashion, if suitable source/destination managers are used. See the
+section on "I/O suspension" for more details.
+
+
+BASIC LIBRARY USAGE
+===================
+
+Data formats
+------------
+
+Before diving into procedural details, it is helpful to understand the
+image data format that the JPEG library expects or returns.
+
+The standard input image format is a rectangular array of pixels, with each
+pixel having the same number of "component" or "sample" values (color
+channels). You must specify how many components there are and the colorspace
+interpretation of the components. Most applications will use RGB data
+(three components per pixel) or grayscale data (one component per pixel).
+PLEASE NOTE THAT RGB DATA IS THREE SAMPLES PER PIXEL, GRAYSCALE ONLY ONE.
+A remarkable number of people manage to miss this, only to find that their
+programs don't work with grayscale JPEG files.
+
+There is no provision for colormapped input. JPEG files are always full-color
+or full grayscale (or sometimes another colorspace such as CMYK). You can
+feed in a colormapped image by expanding it to full-color format. However
+JPEG often doesn't work very well with source data that has been colormapped,
+because of dithering noise. This is discussed in more detail in the JPEG FAQ
+and the other references mentioned in the README file.
+
+Pixels are stored by scanlines, with each scanline running from left to
+right. The component values for each pixel are adjacent in the row; for
+example, R,G,B,R,G,B,R,G,B,... for 24-bit RGB color. Each scanline is an
+array of data type JSAMPLE --- which is typically "unsigned char", unless
+you've changed jmorecfg.h. (You can also change the RGB pixel layout, say
+to B,G,R order, by modifying jmorecfg.h. But see the restrictions listed in
+that file before doing so.)
+
+A 2-D array of pixels is formed by making a list of pointers to the starts of
+scanlines; so the scanlines need not be physically adjacent in memory. Even
+if you process just one scanline at a time, you must make a one-element
+pointer array to conform to this structure. Pointers to JSAMPLE rows are of
+type JSAMPROW, and the pointer to the pointer array is of type JSAMPARRAY.
+
+The library accepts or supplies one or more complete scanlines per call.
+It is not possible to process part of a row at a time. Scanlines are always
+processed top-to-bottom. You can process an entire image in one call if you
+have it all in memory, but usually it's simplest to process one scanline at
+a time.
+
+For best results, source data values should have the precision specified by
+BITS_IN_JSAMPLE (normally 8 bits). For instance, if you choose to compress
+data that's only 6 bits/channel, you should left-justify each value in a
+byte before passing it to the compressor. If you need to compress data
+that has more than 8 bits/channel, compile with BITS_IN_JSAMPLE = 12.
+(See "Library compile-time options", later.)
+
+
+The data format returned by the decompressor is the same in all details,
+except that colormapped output is supported. (Again, a JPEG file is never
+colormapped. But you can ask the decompressor to perform on-the-fly color
+quantization to deliver colormapped output.) If you request colormapped
+output then the returned data array contains a single JSAMPLE per pixel;
+its value is an index into a color map. The color map is represented as
+a 2-D JSAMPARRAY in which each row holds the values of one color component,
+that is, colormap[i][j] is the value of the i'th color component for pixel
+value (map index) j. Note that since the colormap indexes are stored in
+JSAMPLEs, the maximum number of colors is limited by the size of JSAMPLE
+(ie, at most 256 colors for an 8-bit JPEG library).
+
+
+Compression details
+-------------------
+
+Here we revisit the JPEG compression outline given in the overview.
+
+1. Allocate and initialize a JPEG compression object.
+
+A JPEG compression object is a "struct jpeg_compress_struct". (It also has
+a bunch of subsidiary structures which are allocated via malloc(), but the
+application doesn't control those directly.) This struct can be just a local
+variable in the calling routine, if a single routine is going to execute the
+whole JPEG compression sequence. Otherwise it can be static or allocated
+from malloc().
+
+You will also need a structure representing a JPEG error handler. The part
+of this that the library cares about is a "struct jpeg_error_mgr". If you
+are providing your own error handler, you'll typically want to embed the
+jpeg_error_mgr struct in a larger structure; this is discussed later under
+"Error handling". For now we'll assume you are just using the default error
+handler. The default error handler will print JPEG error/warning messages
+on stderr, and it will call exit() if a fatal error occurs.
+
+You must initialize the error handler structure, store a pointer to it into
+the JPEG object's "err" field, and then call jpeg_create_compress() to
+initialize the rest of the JPEG object.
+
+Typical code for this step, if you are using the default error handler, is
+
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ ...
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+
+jpeg_create_compress allocates a small amount of memory, so it could fail
+if you are out of memory. In that case it will exit via the error handler;
+that's why the error handler must be initialized first.
+
+
+2. Specify the destination for the compressed data (eg, a file).
+
+As previously mentioned, the JPEG library delivers compressed data to a
+"data destination" module. The library includes one data destination
+module which knows how to write to a stdio stream. You can use your own
+destination module if you want to do something else, as discussed later.
+
+If you use the standard destination module, you must open the target stdio
+stream beforehand. Typical code for this step looks like:
+
+ FILE * outfile;
+ ...
+ if ((outfile = fopen(filename, "wb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ exit(1);
+ }
+ jpeg_stdio_dest(&cinfo, outfile);
+
+where the last line invokes the standard destination module.
+
+WARNING: it is critical that the binary compressed data be delivered to the
+output file unchanged. On non-Unix systems the stdio library may perform
+newline translation or otherwise corrupt binary data. To suppress this
+behavior, you may need to use a "b" option to fopen (as shown above), or use
+setmode() or another routine to put the stdio stream in binary mode. See
+cjpeg.c and djpeg.c for code that has been found to work on many systems.
+
+You can select the data destination after setting other parameters (step 3),
+if that's more convenient. You may not change the destination between
+calling jpeg_start_compress() and jpeg_finish_compress().
+
+
+3. Set parameters for compression, including image size & colorspace.
+
+You must supply information about the source image by setting the following
+fields in the JPEG object (cinfo structure):
+
+ image_width Width of image, in pixels
+ image_height Height of image, in pixels
+ input_components Number of color channels (samples per pixel)
+ in_color_space Color space of source image
+
+The image dimensions are, hopefully, obvious. JPEG supports image dimensions
+of 1 to 64K pixels in either direction. The input color space is typically
+RGB or grayscale, and input_components is 3 or 1 accordingly. (See "Special
+color spaces", later, for more info.) The in_color_space field must be
+assigned one of the J_COLOR_SPACE enum constants, typically JCS_RGB or
+JCS_GRAYSCALE.
+
+JPEG has a large number of compression parameters that determine how the
+image is encoded. Most applications don't need or want to know about all
+these parameters. You can set all the parameters to reasonable defaults by
+calling jpeg_set_defaults(); then, if there are particular values you want
+to change, you can do so after that. The "Compression parameter selection"
+section tells about all the parameters.
+
+You must set in_color_space correctly before calling jpeg_set_defaults(),
+because the defaults depend on the source image colorspace. However the
+other three source image parameters need not be valid until you call
+jpeg_start_compress(). There's no harm in calling jpeg_set_defaults() more
+than once, if that happens to be convenient.
+
+Typical code for a 24-bit RGB source image is
+
+ cinfo.image_width = Width; /* image width and height, in pixels */
+ cinfo.image_height = Height;
+ cinfo.input_components = 3; /* # of color components per pixel */
+ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
+
+ jpeg_set_defaults(&cinfo);
+ /* Make optional parameter settings here */
+
+
+4. jpeg_start_compress(...);
+
+After you have established the data destination and set all the necessary
+source image info and other parameters, call jpeg_start_compress() to begin
+a compression cycle. This will initialize internal state, allocate working
+storage, and emit the first few bytes of the JPEG datastream header.
+
+Typical code:
+
+ jpeg_start_compress(&cinfo, TRUE);
+
+The "TRUE" parameter ensures that a complete JPEG interchange datastream
+will be written. This is appropriate in most cases. If you think you might
+want to use an abbreviated datastream, read the section on abbreviated
+datastreams, below.
+
+Once you have called jpeg_start_compress(), you may not alter any JPEG
+parameters or other fields of the JPEG object until you have completed
+the compression cycle.
+
+
+5. while (scan lines remain to be written)
+ jpeg_write_scanlines(...);
+
+Now write all the required image data by calling jpeg_write_scanlines()
+one or more times. You can pass one or more scanlines in each call, up
+to the total image height. In most applications it is convenient to pass
+just one or a few scanlines at a time. The expected format for the passed
+data is discussed under "Data formats", above.
+
+Image data should be written in top-to-bottom scanline order. The JPEG spec
+contains some weasel wording about how top and bottom are application-defined
+terms (a curious interpretation of the English language...) but if you want
+your files to be compatible with everyone else's, you WILL use top-to-bottom
+order. If the source data must be read in bottom-to-top order, you can use
+the JPEG library's virtual array mechanism to invert the data efficiently.
+Examples of this can be found in the sample application cjpeg.
+
+The library maintains a count of the number of scanlines written so far
+in the next_scanline field of the JPEG object. Usually you can just use
+this variable as the loop counter, so that the loop test looks like
+"while (cinfo.next_scanline < cinfo.image_height)".
+
+Code for this step depends heavily on the way that you store the source data.
+example.c shows the following code for the case of a full-size 2-D source
+array containing 3-byte RGB pixels:
+
+ JSAMPROW row_pointer[1]; /* pointer to a single row */
+ int row_stride; /* physical row width in buffer */
+
+ row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
+
+ while (cinfo.next_scanline < cinfo.image_height) {
+ row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
+ jpeg_write_scanlines(&cinfo, row_pointer, 1);
+ }
+
+jpeg_write_scanlines() returns the number of scanlines actually written.
+This will normally be equal to the number passed in, so you can usually
+ignore the return value. It is different in just two cases:
+ * If you try to write more scanlines than the declared image height,
+ the additional scanlines are ignored.
+ * If you use a suspending data destination manager, output buffer overrun
+ will cause the compressor to return before accepting all the passed lines.
+ This feature is discussed under "I/O suspension", below. The normal
+ stdio destination manager will NOT cause this to happen.
+In any case, the return value is the same as the change in the value of
+next_scanline.
+
+
+6. jpeg_finish_compress(...);
+
+After all the image data has been written, call jpeg_finish_compress() to
+complete the compression cycle. This step is ESSENTIAL to ensure that the
+last bufferload of data is written to the data destination.
+jpeg_finish_compress() also releases working memory associated with the JPEG
+object.
+
+Typical code:
+
+ jpeg_finish_compress(&cinfo);
+
+If using the stdio destination manager, don't forget to close the output
+stdio stream (if necessary) afterwards.
+
+If you have requested a multi-pass operating mode, such as Huffman code
+optimization, jpeg_finish_compress() will perform the additional passes using
+data buffered by the first pass. In this case jpeg_finish_compress() may take
+quite a while to complete. With the default compression parameters, this will
+not happen.
+
+It is an error to call jpeg_finish_compress() before writing the necessary
+total number of scanlines. If you wish to abort compression, call
+jpeg_abort() as discussed below.
+
+After completing a compression cycle, you may dispose of the JPEG object
+as discussed next, or you may use it to compress another image. In that case
+return to step 2, 3, or 4 as appropriate. If you do not change the
+destination manager, the new datastream will be written to the same target.
+If you do not change any JPEG parameters, the new datastream will be written
+with the same parameters as before. Note that you can change the input image
+dimensions freely between cycles, but if you change the input colorspace, you
+should call jpeg_set_defaults() to adjust for the new colorspace; and then
+you'll need to repeat all of step 3.
+
+
+7. Release the JPEG compression object.
+
+When you are done with a JPEG compression object, destroy it by calling
+jpeg_destroy_compress(). This will free all subsidiary memory (regardless of
+the previous state of the object). Or you can call jpeg_destroy(), which
+works for either compression or decompression objects --- this may be more
+convenient if you are sharing code between compression and decompression
+cases. (Actually, these routines are equivalent except for the declared type
+of the passed pointer. To avoid gripes from ANSI C compilers, jpeg_destroy()
+should be passed a j_common_ptr.)
+
+If you allocated the jpeg_compress_struct structure from malloc(), freeing
+it is your responsibility --- jpeg_destroy() won't. Ditto for the error
+handler structure.
+
+Typical code:
+
+ jpeg_destroy_compress(&cinfo);
+
+
+8. Aborting.
+
+If you decide to abort a compression cycle before finishing, you can clean up
+in either of two ways:
+
+* If you don't need the JPEG object any more, just call
+ jpeg_destroy_compress() or jpeg_destroy() to release memory. This is
+ legitimate at any point after calling jpeg_create_compress() --- in fact,
+ it's safe even if jpeg_create_compress() fails.
+
+* If you want to re-use the JPEG object, call jpeg_abort_compress(), or call
+ jpeg_abort() which works on both compression and decompression objects.
+ This will return the object to an idle state, releasing any working memory.
+ jpeg_abort() is allowed at any time after successful object creation.
+
+Note that cleaning up the data destination, if required, is your
+responsibility; neither of these routines will call term_destination().
+(See "Compressed data handling", below, for more about that.)
+
+jpeg_destroy() and jpeg_abort() are the only safe calls to make on a JPEG
+object that has reported an error by calling error_exit (see "Error handling"
+for more info). The internal state of such an object is likely to be out of
+whack. Either of these two routines will return the object to a known state.
+
+
+Decompression details
+---------------------
+
+Here we revisit the JPEG decompression outline given in the overview.
+
+1. Allocate and initialize a JPEG decompression object.
+
+This is just like initialization for compression, as discussed above,
+except that the object is a "struct jpeg_decompress_struct" and you
+call jpeg_create_decompress(). Error handling is exactly the same.
+
+Typical code:
+
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ ...
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+
+(Both here and in the IJG code, we usually use variable name "cinfo" for
+both compression and decompression objects.)
+
+
+2. Specify the source of the compressed data (eg, a file).
+
+As previously mentioned, the JPEG library reads compressed data from a "data
+source" module. The library includes one data source module which knows how
+to read from a stdio stream. You can use your own source module if you want
+to do something else, as discussed later.
+
+If you use the standard source module, you must open the source stdio stream
+beforehand. Typical code for this step looks like:
+
+ FILE * infile;
+ ...
+ if ((infile = fopen(filename, "rb")) == NULL) {
+ fprintf(stderr, "can't open %s\n", filename);
+ exit(1);
+ }
+ jpeg_stdio_src(&cinfo, infile);
+
+where the last line invokes the standard source module.
+
+WARNING: it is critical that the binary compressed data be read unchanged.
+On non-Unix systems the stdio library may perform newline translation or
+otherwise corrupt binary data. To suppress this behavior, you may need to use
+a "b" option to fopen (as shown above), or use setmode() or another routine to
+put the stdio stream in binary mode. See cjpeg.c and djpeg.c for code that
+has been found to work on many systems.
+
+You may not change the data source between calling jpeg_read_header() and
+jpeg_finish_decompress(). If you wish to read a series of JPEG images from
+a single source file, you should repeat the jpeg_read_header() to
+jpeg_finish_decompress() sequence without reinitializing either the JPEG
+object or the data source module; this prevents buffered input data from
+being discarded.
+
+
+3. Call jpeg_read_header() to obtain image info.
+
+Typical code for this step is just
+
+ jpeg_read_header(&cinfo, TRUE);
+
+This will read the source datastream header markers, up to the beginning
+of the compressed data proper. On return, the image dimensions and other
+info have been stored in the JPEG object. The application may wish to
+consult this information before selecting decompression parameters.
+
+More complex code is necessary if
+ * A suspending data source is used --- in that case jpeg_read_header()
+ may return before it has read all the header data. See "I/O suspension",
+ below. The normal stdio source manager will NOT cause this to happen.
+ * Abbreviated JPEG files are to be processed --- see the section on
+ abbreviated datastreams. Standard applications that deal only in
+ interchange JPEG files need not be concerned with this case either.
+
+It is permissible to stop at this point if you just wanted to find out the
+image dimensions and other header info for a JPEG file. In that case,
+call jpeg_destroy() when you are done with the JPEG object, or call
+jpeg_abort() to return it to an idle state before selecting a new data
+source and reading another header.
+
+
+4. Set parameters for decompression.
+
+jpeg_read_header() sets appropriate default decompression parameters based on
+the properties of the image (in particular, its colorspace). However, you
+may well want to alter these defaults before beginning the decompression.
+For example, the default is to produce full color output from a color file.
+If you want colormapped output you must ask for it. Other options allow the
+returned image to be scaled and allow various speed/quality tradeoffs to be
+selected. "Decompression parameter selection", below, gives details.
+
+If the defaults are appropriate, nothing need be done at this step.
+
+Note that all default values are set by each call to jpeg_read_header().
+If you reuse a decompression object, you cannot expect your parameter
+settings to be preserved across cycles, as you can for compression.
+You must set desired parameter values each time.
+
+
+5. jpeg_start_decompress(...);
+
+Once the parameter values are satisfactory, call jpeg_start_decompress() to
+begin decompression. This will initialize internal state, allocate working
+memory, and prepare for returning data.
+
+Typical code is just
+
+ jpeg_start_decompress(&cinfo);
+
+If you have requested a multi-pass operating mode, such as 2-pass color
+quantization, jpeg_start_decompress() will do everything needed before data
+output can begin. In this case jpeg_start_decompress() may take quite a while
+to complete. With a single-scan (non progressive) JPEG file and default
+decompression parameters, this will not happen; jpeg_start_decompress() will
+return quickly.
+
+After this call, the final output image dimensions, including any requested
+scaling, are available in the JPEG object; so is the selected colormap, if
+colormapped output has been requested. Useful fields include
+
+ output_width image width and height, as scaled
+ output_height
+ out_color_components # of color components in out_color_space
+ output_components # of color components returned per pixel
+ colormap the selected colormap, if any
+ actual_number_of_colors number of entries in colormap
+
+output_components is 1 (a colormap index) when quantizing colors; otherwise it
+equals out_color_components. It is the number of JSAMPLE values that will be
+emitted per pixel in the output arrays.
+
+Typically you will need to allocate data buffers to hold the incoming image.
+You will need output_width * output_components JSAMPLEs per scanline in your
+output buffer, and a total of output_height scanlines will be returned.
+
+Note: if you are using the JPEG library's internal memory manager to allocate
+data buffers (as djpeg does), then the manager's protocol requires that you
+request large buffers *before* calling jpeg_start_decompress(). This is a
+little tricky since the output_XXX fields are not normally valid then. You
+can make them valid by calling jpeg_calc_output_dimensions() after setting the
+relevant parameters (scaling, output color space, and quantization flag).
+
+
+6. while (scan lines remain to be read)
+ jpeg_read_scanlines(...);
+
+Now you can read the decompressed image data by calling jpeg_read_scanlines()
+one or more times. At each call, you pass in the maximum number of scanlines
+to be read (ie, the height of your working buffer); jpeg_read_scanlines()
+will return up to that many lines. The return value is the number of lines
+actually read. The format of the returned data is discussed under "Data
+formats", above. Don't forget that grayscale and color JPEGs will return
+different data formats!
+
+Image data is returned in top-to-bottom scanline order. If you must write
+out the image in bottom-to-top order, you can use the JPEG library's virtual
+array mechanism to invert the data efficiently. Examples of this can be
+found in the sample application djpeg.
+
+The library maintains a count of the number of scanlines returned so far
+in the output_scanline field of the JPEG object. Usually you can just use
+this variable as the loop counter, so that the loop test looks like
+"while (cinfo.output_scanline < cinfo.output_height)". (Note that the test
+should NOT be against image_height, unless you never use scaling. The
+image_height field is the height of the original unscaled image.)
+The return value always equals the change in the value of output_scanline.
+
+If you don't use a suspending data source, it is safe to assume that
+jpeg_read_scanlines() reads at least one scanline per call, until the
+bottom of the image has been reached.
+
+If you use a buffer larger than one scanline, it is NOT safe to assume that
+jpeg_read_scanlines() fills it. (The current implementation returns only a
+few scanlines per call, no matter how large a buffer you pass.) So you must
+always provide a loop that calls jpeg_read_scanlines() repeatedly until the
+whole image has been read.
+
+
+7. jpeg_finish_decompress(...);
+
+After all the image data has been read, call jpeg_finish_decompress() to
+complete the decompression cycle. This causes working memory associated
+with the JPEG object to be released.
+
+Typical code:
+
+ jpeg_finish_decompress(&cinfo);
+
+If using the stdio source manager, don't forget to close the source stdio
+stream if necessary.
+
+It is an error to call jpeg_finish_decompress() before reading the correct
+total number of scanlines. If you wish to abort decompression, call
+jpeg_abort() as discussed below.
+
+After completing a decompression cycle, you may dispose of the JPEG object as
+discussed next, or you may use it to decompress another image. In that case
+return to step 2 or 3 as appropriate. If you do not change the source
+manager, the next image will be read from the same source.
+
+
+8. Release the JPEG decompression object.
+
+When you are done with a JPEG decompression object, destroy it by calling
+jpeg_destroy_decompress() or jpeg_destroy(). The previous discussion of
+destroying compression objects applies here too.
+
+Typical code:
+
+ jpeg_destroy_decompress(&cinfo);
+
+
+9. Aborting.
+
+You can abort a decompression cycle by calling jpeg_destroy_decompress() or
+jpeg_destroy() if you don't need the JPEG object any more, or
+jpeg_abort_decompress() or jpeg_abort() if you want to reuse the object.
+The previous discussion of aborting compression cycles applies here too.
+
+
+Mechanics of usage: include files, linking, etc
+-----------------------------------------------
+
+Applications using the JPEG library should include the header file jpeglib.h
+to obtain declarations of data types and routines. Before including
+jpeglib.h, include system headers that define at least the typedefs FILE and
+size_t. On ANSI-conforming systems, including <stdio.h> is sufficient; on
+older Unix systems, you may need <sys/types.h> to define size_t.
+
+If the application needs to refer to individual JPEG library error codes, also
+include jerror.h to define those symbols.
+
+jpeglib.h indirectly includes the files jconfig.h and jmorecfg.h. If you are
+installing the JPEG header files in a system directory, you will want to
+install all four files: jpeglib.h, jerror.h, jconfig.h, jmorecfg.h.
+
+The most convenient way to include the JPEG code into your executable program
+is to prepare a library file ("libjpeg.a", or a corresponding name on non-Unix
+machines) and reference it at your link step. If you use only half of the
+library (only compression or only decompression), only that much code will be
+included from the library, unless your linker is hopelessly brain-damaged.
+The supplied makefiles build libjpeg.a automatically (see install.txt).
+
+While you can build the JPEG library as a shared library if the whim strikes
+you, we don't really recommend it. The trouble with shared libraries is that
+at some point you'll probably try to substitute a new version of the library
+without recompiling the calling applications. That generally doesn't work
+because the parameter struct declarations usually change with each new
+version. In other words, the library's API is *not* guaranteed binary
+compatible across versions; we only try to ensure source-code compatibility.
+(In hindsight, it might have been smarter to hide the parameter structs from
+applications and introduce a ton of access functions instead. Too late now,
+however.)
+
+On some systems your application may need to set up a signal handler to ensure
+that temporary files are deleted if the program is interrupted. This is most
+critical if you are on MS-DOS and use the jmemdos.c memory manager back end;
+it will try to grab extended memory for temp files, and that space will NOT be
+freed automatically. See cjpeg.c or djpeg.c for an example signal handler.
+
+It may be worth pointing out that the core JPEG library does not actually
+require the stdio library: only the default source/destination managers and
+error handler need it. You can use the library in a stdio-less environment
+if you replace those modules and use jmemnobs.c (or another memory manager of
+your own devising). More info about the minimum system library requirements
+may be found in jinclude.h.
+
+
+ADVANCED FEATURES
+=================
+
+Compression parameter selection
+-------------------------------
+
+This section describes all the optional parameters you can set for JPEG
+compression, as well as the "helper" routines provided to assist in this
+task. Proper setting of some parameters requires detailed understanding
+of the JPEG standard; if you don't know what a parameter is for, it's best
+not to mess with it! See REFERENCES in the README file for pointers to
+more info about JPEG.
+
+It's a good idea to call jpeg_set_defaults() first, even if you plan to set
+all the parameters; that way your code is more likely to work with future JPEG
+libraries that have additional parameters. For the same reason, we recommend
+you use a helper routine where one is provided, in preference to twiddling
+cinfo fields directly.
+
+The helper routines are:
+
+jpeg_set_defaults (j_compress_ptr cinfo)
+ This routine sets all JPEG parameters to reasonable defaults, using
+ only the input image's color space (field in_color_space, which must
+ already be set in cinfo). Many applications will only need to use
+ this routine and perhaps jpeg_set_quality().
+
+jpeg_set_colorspace (j_compress_ptr cinfo, J_COLOR_SPACE colorspace)
+ Sets the JPEG file's colorspace (field jpeg_color_space) as specified,
+ and sets other color-space-dependent parameters appropriately. See
+ "Special color spaces", below, before using this. A large number of
+ parameters, including all per-component parameters, are set by this
+ routine; if you want to twiddle individual parameters you should call
+ jpeg_set_colorspace() before rather than after.
+
+jpeg_default_colorspace (j_compress_ptr cinfo)
+ Selects an appropriate JPEG colorspace based on cinfo->in_color_space,
+ and calls jpeg_set_colorspace(). This is actually a subroutine of
+ jpeg_set_defaults(). It's broken out in case you want to change
+ just the colorspace-dependent JPEG parameters.
+
+jpeg_set_quality (j_compress_ptr cinfo, int quality, boolean force_baseline)
+ Constructs JPEG quantization tables appropriate for the indicated
+ quality setting. The quality value is expressed on the 0..100 scale
+ recommended by IJG (cjpeg's "-quality" switch uses this routine).
+ Note that the exact mapping from quality values to tables may change
+ in future IJG releases as more is learned about DCT quantization.
+ If the force_baseline parameter is TRUE, then the quantization table
+ entries are constrained to the range 1..255 for full JPEG baseline
+ compatibility. In the current implementation, this only makes a
+ difference for quality settings below 25, and it effectively prevents
+ very small/low quality files from being generated. The IJG decoder
+ is capable of reading the non-baseline files generated at low quality
+ settings when force_baseline is FALSE, but other decoders may not be.
+
+jpeg_set_linear_quality (j_compress_ptr cinfo, int scale_factor,
+ boolean force_baseline)
+ Same as jpeg_set_quality() except that the generated tables are the
+ sample tables given in the JPEC spec section K.1, multiplied by the
+ specified scale factor (which is expressed as a percentage; thus
+ scale_factor = 100 reproduces the spec's tables). Note that larger
+ scale factors give lower quality. This entry point is useful for
+ conforming to the Adobe PostScript DCT conventions, but we do not
+ recommend linear scaling as a user-visible quality scale otherwise.
+ force_baseline again constrains the computed table entries to 1..255.
+
+int jpeg_quality_scaling (int quality)
+ Converts a value on the IJG-recommended quality scale to a linear
+ scaling percentage. Note that this routine may change or go away
+ in future releases --- IJG may choose to adopt a scaling method that
+ can't be expressed as a simple scalar multiplier, in which case the
+ premise of this routine collapses. Caveat user.
+
+jpeg_default_qtables (j_compress_ptr cinfo, boolean force_baseline)
+ Set default quantization tables with linear q_scale_factor[] values
+ (see below).
+
+jpeg_add_quant_table (j_compress_ptr cinfo, int which_tbl,
+ const unsigned int *basic_table,
+ int scale_factor, boolean force_baseline)
+ Allows an arbitrary quantization table to be created. which_tbl
+ indicates which table slot to fill. basic_table points to an array
+ of 64 unsigned ints given in normal array order. These values are
+ multiplied by scale_factor/100 and then clamped to the range 1..65535
+ (or to 1..255 if force_baseline is TRUE).
+ CAUTION: prior to library version 6a, jpeg_add_quant_table expected
+ the basic table to be given in JPEG zigzag order. If you need to
+ write code that works with either older or newer versions of this
+ routine, you must check the library version number. Something like
+ "#if JPEG_LIB_VERSION >= 61" is the right test.
+
+jpeg_simple_progression (j_compress_ptr cinfo)
+ Generates a default scan script for writing a progressive-JPEG file.
+ This is the recommended method of creating a progressive file,
+ unless you want to make a custom scan sequence. You must ensure that
+ the JPEG color space is set correctly before calling this routine.
+
+
+Compression parameters (cinfo fields) include:
+
+int block_size
+ Set DCT block size. All N from 1 to 16 are possible.
+ Default is 8 (baseline format).
+ Larger values produce higher compression,
+ smaller values produce higher quality.
+ An exact DCT stage is possible with 1 or 2.
+ With the default quality of 75 and default Luminance qtable
+ the DCT+Quantization stage is lossless for value 1.
+ Note that values other than 8 require a SmartScale capable decoder,
+ introduced with IJG JPEG 8. Setting the block_size parameter for
+ compression works with version 8c and later.
+
+J_DCT_METHOD dct_method
+ Selects the algorithm used for the DCT step. Choices are:
+ JDCT_ISLOW: slow but accurate integer algorithm
+ JDCT_IFAST: faster, less accurate integer method
+ JDCT_FLOAT: floating-point method
+ JDCT_DEFAULT: default method (normally JDCT_ISLOW)
+ JDCT_FASTEST: fastest method (normally JDCT_IFAST)
+ The FLOAT method is very slightly more accurate than the ISLOW method,
+ but may give different results on different machines due to varying
+ roundoff behavior. The integer methods should give the same results
+ on all machines. On machines with sufficiently fast FP hardware, the
+ floating-point method may also be the fastest. The IFAST method is
+ considerably less accurate than the other two; its use is not
+ recommended if high quality is a concern. JDCT_DEFAULT and
+ JDCT_FASTEST are macros configurable by each installation.
+
+unsigned int scale_num, scale_denom
+ Scale the image by the fraction scale_num/scale_denom. Default is
+ 1/1, or no scaling. Currently, the supported scaling ratios are
+ M/N with all N from 1 to 16, where M is the destination DCT size,
+ which is 8 by default (see block_size parameter above).
+ (The library design allows for arbitrary scaling ratios but this
+ is not likely to be implemented any time soon.)
+
+J_COLOR_SPACE jpeg_color_space
+int num_components
+ The JPEG color space and corresponding number of components; see
+ "Special color spaces", below, for more info. We recommend using
+ jpeg_set_color_space() if you want to change these.
+
+boolean optimize_coding
+ TRUE causes the compressor to compute optimal Huffman coding tables
+ for the image. This requires an extra pass over the data and
+ therefore costs a good deal of space and time. The default is
+ FALSE, which tells the compressor to use the supplied or default
+ Huffman tables. In most cases optimal tables save only a few percent
+ of file size compared to the default tables. Note that when this is
+ TRUE, you need not supply Huffman tables at all, and any you do
+ supply will be overwritten.
+
+unsigned int restart_interval
+int restart_in_rows
+ To emit restart markers in the JPEG file, set one of these nonzero.
+ Set restart_interval to specify the exact interval in MCU blocks.
+ Set restart_in_rows to specify the interval in MCU rows. (If
+ restart_in_rows is not 0, then restart_interval is set after the
+ image width in MCUs is computed.) Defaults are zero (no restarts).
+ One restart marker per MCU row is often a good choice.
+ NOTE: the overhead of restart markers is higher in grayscale JPEG
+ files than in color files, and MUCH higher in progressive JPEGs.
+ If you use restarts, you may want to use larger intervals in those
+ cases.
+
+const jpeg_scan_info * scan_info
+int num_scans
+ By default, scan_info is NULL; this causes the compressor to write a
+ single-scan sequential JPEG file. If not NULL, scan_info points to
+ an array of scan definition records of length num_scans. The
+ compressor will then write a JPEG file having one scan for each scan
+ definition record. This is used to generate noninterleaved or
+ progressive JPEG files. The library checks that the scan array
+ defines a valid JPEG scan sequence. (jpeg_simple_progression creates
+ a suitable scan definition array for progressive JPEG.) This is
+ discussed further under "Progressive JPEG support".
+
+boolean do_fancy_downsampling
+ If TRUE, use direct DCT scaling with DCT size > 8 for downsampling
+ of chroma components.
+ If FALSE, use only DCT size <= 8 and simple separate downsampling.
+ Default is TRUE.
+ For better image stability in multiple generation compression cycles
+ it is preferable that this value matches the corresponding
+ do_fancy_upsampling value in decompression.
+
+int smoothing_factor
+ If non-zero, the input image is smoothed; the value should be 1 for
+ minimal smoothing to 100 for maximum smoothing. Consult jcsample.c
+ for details of the smoothing algorithm. The default is zero.
+
+boolean write_JFIF_header
+ If TRUE, a JFIF APP0 marker is emitted. jpeg_set_defaults() and
+ jpeg_set_colorspace() set this TRUE if a JFIF-legal JPEG color space
+ (ie, YCbCr or grayscale) is selected, otherwise FALSE.
+
+UINT8 JFIF_major_version
+UINT8 JFIF_minor_version
+ The version number to be written into the JFIF marker.
+ jpeg_set_defaults() initializes the version to 1.01 (major=minor=1).
+ You should set it to 1.02 (major=1, minor=2) if you plan to write
+ any JFIF 1.02 extension markers.
+
+UINT8 density_unit
+UINT16 X_density
+UINT16 Y_density
+ The resolution information to be written into the JFIF marker;
+ not used otherwise. density_unit may be 0 for unknown,
+ 1 for dots/inch, or 2 for dots/cm. The default values are 0,1,1
+ indicating square pixels of unknown size.
+
+boolean write_Adobe_marker
+ If TRUE, an Adobe APP14 marker is emitted. jpeg_set_defaults() and
+ jpeg_set_colorspace() set this TRUE if JPEG color space RGB, CMYK,
+ or YCCK is selected, otherwise FALSE. It is generally a bad idea
+ to set both write_JFIF_header and write_Adobe_marker. In fact,
+ you probably shouldn't change the default settings at all --- the
+ default behavior ensures that the JPEG file's color space can be
+ recognized by the decoder.
+
+JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]
+ Pointers to coefficient quantization tables, one per table slot,
+ or NULL if no table is defined for a slot. Usually these should
+ be set via one of the above helper routines; jpeg_add_quant_table()
+ is general enough to define any quantization table. The other
+ routines will set up table slot 0 for luminance quality and table
+ slot 1 for chrominance.
+
+int q_scale_factor[NUM_QUANT_TBLS]
+ Linear quantization scaling factors (percentage, initialized 100)
+ for use with jpeg_default_qtables().
+ See rdswitch.c and cjpeg.c for an example of usage.
+ Note that the q_scale_factor[] fields are the "linear" scales, so you
+ have to convert from user-defined ratings via jpeg_quality_scaling().
+ Here is an example code which corresponds to cjpeg -quality 90,70:
+
+ jpeg_set_defaults(cinfo);
+
+ /* Set luminance quality 90. */
+ cinfo->q_scale_factor[0] = jpeg_quality_scaling(90);
+ /* Set chrominance quality 70. */
+ cinfo->q_scale_factor[1] = jpeg_quality_scaling(70);
+
+ jpeg_default_qtables(cinfo, force_baseline);
+
+ CAUTION: You must also set 1x1 subsampling for efficient separate
+ color quality selection, since the default value used by library
+ is 2x2:
+
+ cinfo->comp_info[0].v_samp_factor = 1;
+ cinfo->comp_info[0].h_samp_factor = 1;
+
+JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]
+JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]
+ Pointers to Huffman coding tables, one per table slot, or NULL if
+ no table is defined for a slot. Slots 0 and 1 are filled with the
+ JPEG sample tables by jpeg_set_defaults(). If you need to allocate
+ more table structures, jpeg_alloc_huff_table() may be used.
+ Note that optimal Huffman tables can be computed for an image
+ by setting optimize_coding, as discussed above; there's seldom
+ any need to mess with providing your own Huffman tables.
+
+
+The actual dimensions of the JPEG image that will be written to the file are
+given by the following fields. These are computed from the input image
+dimensions and the compression parameters by jpeg_start_compress(). You can
+also call jpeg_calc_jpeg_dimensions() to obtain the values that will result
+from the current parameter settings. This can be useful if you are trying
+to pick a scaling ratio that will get close to a desired target size.
+
+JDIMENSION jpeg_width Actual dimensions of output image.
+JDIMENSION jpeg_height
+
+
+Per-component parameters are stored in the struct cinfo.comp_info[i] for
+component number i. Note that components here refer to components of the
+JPEG color space, *not* the source image color space. A suitably large
+comp_info[] array is allocated by jpeg_set_defaults(); if you choose not
+to use that routine, it's up to you to allocate the array.
+
+int component_id
+ The one-byte identifier code to be recorded in the JPEG file for
+ this component. For the standard color spaces, we recommend you
+ leave the default values alone.
+
+int h_samp_factor
+int v_samp_factor
+ Horizontal and vertical sampling factors for the component; must
+ be 1..4 according to the JPEG standard. Note that larger sampling
+ factors indicate a higher-resolution component; many people find
+ this behavior quite unintuitive. The default values are 2,2 for
+ luminance components and 1,1 for chrominance components, except
+ for grayscale where 1,1 is used.
+
+int quant_tbl_no
+ Quantization table number for component. The default value is
+ 0 for luminance components and 1 for chrominance components.
+
+int dc_tbl_no
+int ac_tbl_no
+ DC and AC entropy coding table numbers. The default values are
+ 0 for luminance components and 1 for chrominance components.
+
+int component_index
+ Must equal the component's index in comp_info[]. (Beginning in
+ release v6, the compressor library will fill this in automatically;
+ you don't have to.)
+
+
+Decompression parameter selection
+---------------------------------
+
+Decompression parameter selection is somewhat simpler than compression
+parameter selection, since all of the JPEG internal parameters are
+recorded in the source file and need not be supplied by the application.
+(Unless you are working with abbreviated files, in which case see
+"Abbreviated datastreams", below.) Decompression parameters control
+the postprocessing done on the image to deliver it in a format suitable
+for the application's use. Many of the parameters control speed/quality
+tradeoffs, in which faster decompression may be obtained at the price of
+a poorer-quality image. The defaults select the highest quality (slowest)
+processing.
+
+The following fields in the JPEG object are set by jpeg_read_header() and
+may be useful to the application in choosing decompression parameters:
+
+JDIMENSION image_width Width and height of image
+JDIMENSION image_height
+int num_components Number of color components
+J_COLOR_SPACE jpeg_color_space Colorspace of image
+boolean saw_JFIF_marker TRUE if a JFIF APP0 marker was seen
+ UINT8 JFIF_major_version Version information from JFIF marker
+ UINT8 JFIF_minor_version
+ UINT8 density_unit Resolution data from JFIF marker
+ UINT16 X_density
+ UINT16 Y_density
+boolean saw_Adobe_marker TRUE if an Adobe APP14 marker was seen
+ UINT8 Adobe_transform Color transform code from Adobe marker
+
+The JPEG color space, unfortunately, is something of a guess since the JPEG
+standard proper does not provide a way to record it. In practice most files
+adhere to the JFIF or Adobe conventions, and the decoder will recognize these
+correctly. See "Special color spaces", below, for more info.
+
+
+The decompression parameters that determine the basic properties of the
+returned image are:
+
+J_COLOR_SPACE out_color_space
+ Output color space. jpeg_read_header() sets an appropriate default
+ based on jpeg_color_space; typically it will be RGB or grayscale.
+ The application can change this field to request output in a different
+ colorspace. For example, set it to JCS_GRAYSCALE to get grayscale
+ output from a color file. (This is useful for previewing: grayscale
+ output is faster than full color since the color components need not
+ be processed.) Note that not all possible color space transforms are
+ currently implemented; you may need to extend jdcolor.c if you want an
+ unusual conversion.
+
+unsigned int scale_num, scale_denom
+ Scale the image by the fraction scale_num/scale_denom. Currently,
+ the supported scaling ratios are M/N with all M from 1 to 16, where
+ N is the source DCT size, which is 8 for baseline JPEG. (The library
+ design allows for arbitrary scaling ratios but this is not likely
+ to be implemented any time soon.) The values are initialized by
+ jpeg_read_header() with the source DCT size. For baseline JPEG
+ this is 8/8. If you change only the scale_num value while leaving
+ the other unchanged, then this specifies the DCT scaled size to be
+ applied on the given input. For baseline JPEG this is equivalent
+ to M/8 scaling, since the source DCT size for baseline JPEG is 8.
+ Smaller scaling ratios permit significantly faster decoding since
+ fewer pixels need be processed and a simpler IDCT method can be used.
+
+boolean quantize_colors
+ If set TRUE, colormapped output will be delivered. Default is FALSE,
+ meaning that full-color output will be delivered.
+
+The next three parameters are relevant only if quantize_colors is TRUE.
+
+int desired_number_of_colors
+ Maximum number of colors to use in generating a library-supplied color
+ map (the actual number of colors is returned in a different field).
+ Default 256. Ignored when the application supplies its own color map.
+
+boolean two_pass_quantize
+ If TRUE, an extra pass over the image is made to select a custom color
+ map for the image. This usually looks a lot better than the one-size-
+ fits-all colormap that is used otherwise. Default is TRUE. Ignored
+ when the application supplies its own color map.
+
+J_DITHER_MODE dither_mode
+ Selects color dithering method. Supported values are:
+ JDITHER_NONE no dithering: fast, very low quality
+ JDITHER_ORDERED ordered dither: moderate speed and quality
+ JDITHER_FS Floyd-Steinberg dither: slow, high quality
+ Default is JDITHER_FS. (At present, ordered dither is implemented
+ only in the single-pass, standard-colormap case. If you ask for
+ ordered dither when two_pass_quantize is TRUE or when you supply
+ an external color map, you'll get F-S dithering.)
+
+When quantize_colors is TRUE, the target color map is described by the next
+two fields. colormap is set to NULL by jpeg_read_header(). The application
+can supply a color map by setting colormap non-NULL and setting
+actual_number_of_colors to the map size. Otherwise, jpeg_start_decompress()
+selects a suitable color map and sets these two fields itself.
+[Implementation restriction: at present, an externally supplied colormap is
+only accepted for 3-component output color spaces.]
+
+JSAMPARRAY colormap
+ The color map, represented as a 2-D pixel array of out_color_components
+ rows and actual_number_of_colors columns. Ignored if not quantizing.
+ CAUTION: if the JPEG library creates its own colormap, the storage
+ pointed to by this field is released by jpeg_finish_decompress().
+ Copy the colormap somewhere else first, if you want to save it.
+
+int actual_number_of_colors
+ The number of colors in the color map.
+
+Additional decompression parameters that the application may set include:
+
+J_DCT_METHOD dct_method
+ Selects the algorithm used for the DCT step. Choices are the same
+ as described above for compression.
+
+boolean do_fancy_upsampling
+ If TRUE, use direct DCT scaling with DCT size > 8 for upsampling
+ of chroma components.
+ If FALSE, use only DCT size <= 8 and simple separate upsampling.
+ Default is TRUE.
+ For better image stability in multiple generation compression cycles
+ it is preferable that this value matches the corresponding
+ do_fancy_downsampling value in compression.
+
+boolean do_block_smoothing
+ If TRUE, interblock smoothing is applied in early stages of decoding
+ progressive JPEG files; if FALSE, not. Default is TRUE. Early
+ progression stages look "fuzzy" with smoothing, "blocky" without.
+ In any case, block smoothing ceases to be applied after the first few
+ AC coefficients are known to full accuracy, so it is relevant only
+ when using buffered-image mode for progressive images.
+
+boolean enable_1pass_quant
+boolean enable_external_quant
+boolean enable_2pass_quant
+ These are significant only in buffered-image mode, which is
+ described in its own section below.
+
+
+The output image dimensions are given by the following fields. These are
+computed from the source image dimensions and the decompression parameters
+by jpeg_start_decompress(). You can also call jpeg_calc_output_dimensions()
+to obtain the values that will result from the current parameter settings.
+This can be useful if you are trying to pick a scaling ratio that will get
+close to a desired target size. It's also important if you are using the
+JPEG library's memory manager to allocate output buffer space, because you
+are supposed to request such buffers *before* jpeg_start_decompress().
+
+JDIMENSION output_width Actual dimensions of output image.
+JDIMENSION output_height
+int out_color_components Number of color components in out_color_space.
+int output_components Number of color components returned.
+int rec_outbuf_height Recommended height of scanline buffer.
+
+When quantizing colors, output_components is 1, indicating a single color map
+index per pixel. Otherwise it equals out_color_components. The output arrays
+are required to be output_width * output_components JSAMPLEs wide.
+
+rec_outbuf_height is the recommended minimum height (in scanlines) of the
+buffer passed to jpeg_read_scanlines(). If the buffer is smaller, the
+library will still work, but time will be wasted due to unnecessary data
+copying. In high-quality modes, rec_outbuf_height is always 1, but some
+faster, lower-quality modes set it to larger values (typically 2 to 4).
+If you are going to ask for a high-speed processing mode, you may as well
+go to the trouble of honoring rec_outbuf_height so as to avoid data copying.
+(An output buffer larger than rec_outbuf_height lines is OK, but won't
+provide any material speed improvement over that height.)
+
+
+Special color spaces
+--------------------
+
+The JPEG standard itself is "color blind" and doesn't specify any particular
+color space. It is customary to convert color data to a luminance/chrominance
+color space before compressing, since this permits greater compression. The
+existing de-facto JPEG file format standards specify YCbCr or grayscale data
+(JFIF), or grayscale, RGB, YCbCr, CMYK, or YCCK (Adobe). For special
+applications such as multispectral images, other color spaces can be used,
+but it must be understood that such files will be unportable.
+
+The JPEG library can handle the most common colorspace conversions (namely
+RGB <=> YCbCr and CMYK <=> YCCK). It can also deal with data of an unknown
+color space, passing it through without conversion. If you deal extensively
+with an unusual color space, you can easily extend the library to understand
+additional color spaces and perform appropriate conversions.
+
+For compression, the source data's color space is specified by field
+in_color_space. This is transformed to the JPEG file's color space given
+by jpeg_color_space. jpeg_set_defaults() chooses a reasonable JPEG color
+space depending on in_color_space, but you can override this by calling
+jpeg_set_colorspace(). Of course you must select a supported transformation.
+jccolor.c currently supports the following transformations:
+ RGB => YCbCr
+ RGB => GRAYSCALE
+ YCbCr => GRAYSCALE
+ CMYK => YCCK
+plus the null transforms: GRAYSCALE => GRAYSCALE, RGB => RGB,
+YCbCr => YCbCr, CMYK => CMYK, YCCK => YCCK, and UNKNOWN => UNKNOWN.
+
+The de-facto file format standards (JFIF and Adobe) specify APPn markers that
+indicate the color space of the JPEG file. It is important to ensure that
+these are written correctly, or omitted if the JPEG file's color space is not
+one of the ones supported by the de-facto standards. jpeg_set_colorspace()
+will set the compression parameters to include or omit the APPn markers
+properly, so long as it is told the truth about the JPEG color space.
+For example, if you are writing some random 3-component color space without
+conversion, don't try to fake out the library by setting in_color_space and
+jpeg_color_space to JCS_YCbCr; use JCS_UNKNOWN. You may want to write an
+APPn marker of your own devising to identify the colorspace --- see "Special
+markers", below.
+
+When told that the color space is UNKNOWN, the library will default to using
+luminance-quality compression parameters for all color components. You may
+well want to change these parameters. See the source code for
+jpeg_set_colorspace(), in jcparam.c, for details.
+
+For decompression, the JPEG file's color space is given in jpeg_color_space,
+and this is transformed to the output color space out_color_space.
+jpeg_read_header's setting of jpeg_color_space can be relied on if the file
+conforms to JFIF or Adobe conventions, but otherwise it is no better than a
+guess. If you know the JPEG file's color space for certain, you can override
+jpeg_read_header's guess by setting jpeg_color_space. jpeg_read_header also
+selects a default output color space based on (its guess of) jpeg_color_space;
+set out_color_space to override this. Again, you must select a supported
+transformation. jdcolor.c currently supports
+ YCbCr => RGB
+ YCbCr => GRAYSCALE
+ RGB => GRAYSCALE
+ GRAYSCALE => RGB
+ YCCK => CMYK
+as well as the null transforms. (Since GRAYSCALE=>RGB is provided, an
+application can force grayscale JPEGs to look like color JPEGs if it only
+wants to handle one case.)
+
+The two-pass color quantizer, jquant2.c, is specialized to handle RGB data
+(it weights distances appropriately for RGB colors). You'll need to modify
+the code if you want to use it for non-RGB output color spaces. Note that
+jquant2.c is used to map to an application-supplied colormap as well as for
+the normal two-pass colormap selection process.
+
+CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK JPEG
+files: 0 represents 100% ink coverage, rather than 0% ink as you'd expect.
+This is arguably a bug in Photoshop, but if you need to work with Photoshop
+CMYK files, you will have to deal with it in your application. We cannot
+"fix" this in the library by inverting the data during the CMYK<=>YCCK
+transform, because that would break other applications, notably Ghostscript.
+Photoshop versions prior to 3.0 write EPS files containing JPEG-encoded CMYK
+data in the same inverted-YCCK representation used in bare JPEG files, but
+the surrounding PostScript code performs an inversion using the PS image
+operator. I am told that Photoshop 3.0 will write uninverted YCCK in
+EPS/JPEG files, and will omit the PS-level inversion. (But the data
+polarity used in bare JPEG files will not change in 3.0.) In either case,
+the JPEG library must not invert the data itself, or else Ghostscript would
+read these EPS files incorrectly.
+
+
+Error handling
+--------------
+
+When the default error handler is used, any error detected inside the JPEG
+routines will cause a message to be printed on stderr, followed by exit().
+You can supply your own error handling routines to override this behavior
+and to control the treatment of nonfatal warnings and trace/debug messages.
+The file example.c illustrates the most common case, which is to have the
+application regain control after an error rather than exiting.
+
+The JPEG library never writes any message directly; it always goes through
+the error handling routines. Three classes of messages are recognized:
+ * Fatal errors: the library cannot continue.
+ * Warnings: the library can continue, but the data is corrupt, and a
+ damaged output image is likely to result.
+ * Trace/informational messages. These come with a trace level indicating
+ the importance of the message; you can control the verbosity of the
+ program by adjusting the maximum trace level that will be displayed.
+
+You may, if you wish, simply replace the entire JPEG error handling module
+(jerror.c) with your own code. However, you can avoid code duplication by
+only replacing some of the routines depending on the behavior you need.
+This is accomplished by calling jpeg_std_error() as usual, but then overriding
+some of the method pointers in the jpeg_error_mgr struct, as illustrated by
+example.c.
+
+All of the error handling routines will receive a pointer to the JPEG object
+(a j_common_ptr which points to either a jpeg_compress_struct or a
+jpeg_decompress_struct; if you need to tell which, test the is_decompressor
+field). This struct includes a pointer to the error manager struct in its
+"err" field. Frequently, custom error handler routines will need to access
+additional data which is not known to the JPEG library or the standard error
+handler. The most convenient way to do this is to embed either the JPEG
+object or the jpeg_error_mgr struct in a larger structure that contains
+additional fields; then casting the passed pointer provides access to the
+additional fields. Again, see example.c for one way to do it. (Beginning
+with IJG version 6b, there is also a void pointer "client_data" in each
+JPEG object, which the application can also use to find related data.
+The library does not touch client_data at all.)
+
+The individual methods that you might wish to override are:
+
+error_exit (j_common_ptr cinfo)
+ Receives control for a fatal error. Information sufficient to
+ generate the error message has been stored in cinfo->err; call
+ output_message to display it. Control must NOT return to the caller;
+ generally this routine will exit() or longjmp() somewhere.
+ Typically you would override this routine to get rid of the exit()
+ default behavior. Note that if you continue processing, you should
+ clean up the JPEG object with jpeg_abort() or jpeg_destroy().
+
+output_message (j_common_ptr cinfo)
+ Actual output of any JPEG message. Override this to send messages
+ somewhere other than stderr. Note that this method does not know
+ how to generate a message, only where to send it.
+
+format_message (j_common_ptr cinfo, char * buffer)
+ Constructs a readable error message string based on the error info
+ stored in cinfo->err. This method is called by output_message. Few
+ applications should need to override this method. One possible
+ reason for doing so is to implement dynamic switching of error message
+ language.
+
+emit_message (j_common_ptr cinfo, int msg_level)
+ Decide whether or not to emit a warning or trace message; if so,
+ calls output_message. The main reason for overriding this method
+ would be to abort on warnings. msg_level is -1 for warnings,
+ 0 and up for trace messages.
+
+Only error_exit() and emit_message() are called from the rest of the JPEG
+library; the other two are internal to the error handler.
+
+The actual message texts are stored in an array of strings which is pointed to
+by the field err->jpeg_message_table. The messages are numbered from 0 to
+err->last_jpeg_message, and it is these code numbers that are used in the
+JPEG library code. You could replace the message texts (for instance, with
+messages in French or German) by changing the message table pointer. See
+jerror.h for the default texts. CAUTION: this table will almost certainly
+change or grow from one library version to the next.
+
+It may be useful for an application to add its own message texts that are
+handled by the same mechanism. The error handler supports a second "add-on"
+message table for this purpose. To define an addon table, set the pointer
+err->addon_message_table and the message numbers err->first_addon_message and
+err->last_addon_message. If you number the addon messages beginning at 1000
+or so, you won't have to worry about conflicts with the library's built-in
+messages. See the sample applications cjpeg/djpeg for an example of using
+addon messages (the addon messages are defined in cderror.h).
+
+Actual invocation of the error handler is done via macros defined in jerror.h:
+ ERREXITn(...) for fatal errors
+ WARNMSn(...) for corrupt-data warnings
+ TRACEMSn(...) for trace and informational messages.
+These macros store the message code and any additional parameters into the
+error handler struct, then invoke the error_exit() or emit_message() method.
+The variants of each macro are for varying numbers of additional parameters.
+The additional parameters are inserted into the generated message using
+standard printf() format codes.
+
+See jerror.h and jerror.c for further details.
+
+
+Compressed data handling (source and destination managers)
+----------------------------------------------------------
+
+The JPEG compression library sends its compressed data to a "destination
+manager" module. The default destination manager just writes the data to a
+memory buffer or to a stdio stream, but you can provide your own manager to
+do something else. Similarly, the decompression library calls a "source
+manager" to obtain the compressed data; you can provide your own source
+manager if you want the data to come from somewhere other than a memory
+buffer or a stdio stream.
+
+In both cases, compressed data is processed a bufferload at a time: the
+destination or source manager provides a work buffer, and the library invokes
+the manager only when the buffer is filled or emptied. (You could define a
+one-character buffer to force the manager to be invoked for each byte, but
+that would be rather inefficient.) The buffer's size and location are
+controlled by the manager, not by the library. For example, the memory
+source manager just makes the buffer pointer and length point to the original
+data in memory. In this case the buffer-reload procedure will be invoked
+only if the decompressor ran off the end of the datastream, which would
+indicate an erroneous datastream.
+
+The work buffer is defined as an array of datatype JOCTET, which is generally
+"char" or "unsigned char". On a machine where char is not exactly 8 bits
+wide, you must define JOCTET as a wider data type and then modify the data
+source and destination modules to transcribe the work arrays into 8-bit units
+on external storage.
+
+A data destination manager struct contains a pointer and count defining the
+next byte to write in the work buffer and the remaining free space:
+
+ JOCTET * next_output_byte; /* => next byte to write in buffer */
+ size_t free_in_buffer; /* # of byte spaces remaining in buffer */
+
+The library increments the pointer and decrements the count until the buffer
+is filled. The manager's empty_output_buffer method must reset the pointer
+and count. The manager is expected to remember the buffer's starting address
+and total size in private fields not visible to the library.
+
+A data destination manager provides three methods:
+
+init_destination (j_compress_ptr cinfo)
+ Initialize destination. This is called by jpeg_start_compress()
+ before any data is actually written. It must initialize
+ next_output_byte and free_in_buffer. free_in_buffer must be
+ initialized to a positive value.
+
+empty_output_buffer (j_compress_ptr cinfo)
+ This is called whenever the buffer has filled (free_in_buffer
+ reaches zero). In typical applications, it should write out the
+ *entire* buffer (use the saved start address and buffer length;
+ ignore the current state of next_output_byte and free_in_buffer).
+ Then reset the pointer & count to the start of the buffer, and
+ return TRUE indicating that the buffer has been dumped.
+ free_in_buffer must be set to a positive value when TRUE is
+ returned. A FALSE return should only be used when I/O suspension is
+ desired (this operating mode is discussed in the next section).
+
+term_destination (j_compress_ptr cinfo)
+ Terminate destination --- called by jpeg_finish_compress() after all
+ data has been written. In most applications, this must flush any
+ data remaining in the buffer. Use either next_output_byte or
+ free_in_buffer to determine how much data is in the buffer.
+
+term_destination() is NOT called by jpeg_abort() or jpeg_destroy(). If you
+want the destination manager to be cleaned up during an abort, you must do it
+yourself.
+
+You will also need code to create a jpeg_destination_mgr struct, fill in its
+method pointers, and insert a pointer to the struct into the "dest" field of
+the JPEG compression object. This can be done in-line in your setup code if
+you like, but it's probably cleaner to provide a separate routine similar to
+the jpeg_stdio_dest() or jpeg_mem_dest() routines of the supplied destination
+managers.
+
+Decompression source managers follow a parallel design, but with some
+additional frammishes. The source manager struct contains a pointer and count
+defining the next byte to read from the work buffer and the number of bytes
+remaining:
+
+ const JOCTET * next_input_byte; /* => next byte to read from buffer */
+ size_t bytes_in_buffer; /* # of bytes remaining in buffer */
+
+The library increments the pointer and decrements the count until the buffer
+is emptied. The manager's fill_input_buffer method must reset the pointer and
+count. In most applications, the manager must remember the buffer's starting
+address and total size in private fields not visible to the library.
+
+A data source manager provides five methods:
+
+init_source (j_decompress_ptr cinfo)
+ Initialize source. This is called by jpeg_read_header() before any
+ data is actually read. Unlike init_destination(), it may leave
+ bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
+ will occur immediately).
+
+fill_input_buffer (j_decompress_ptr cinfo)
+ This is called whenever bytes_in_buffer has reached zero and more
+ data is wanted. In typical applications, it should read fresh data
+ into the buffer (ignoring the current state of next_input_byte and
+ bytes_in_buffer), reset the pointer & count to the start of the
+ buffer, and return TRUE indicating that the buffer has been reloaded.
+ It is not necessary to fill the buffer entirely, only to obtain at
+ least one more byte. bytes_in_buffer MUST be set to a positive value
+ if TRUE is returned. A FALSE return should only be used when I/O
+ suspension is desired (this mode is discussed in the next section).
+
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+ Skip num_bytes worth of data. The buffer pointer and count should
+ be advanced over num_bytes input bytes, refilling the buffer as
+ needed. This is used to skip over a potentially large amount of
+ uninteresting data (such as an APPn marker). In some applications
+ it may be possible to optimize away the reading of the skipped data,
+ but it's not clear that being smart is worth much trouble; large
+ skips are uncommon. bytes_in_buffer may be zero on return.
+ A zero or negative skip count should be treated as a no-op.
+
+resync_to_restart (j_decompress_ptr cinfo, int desired)
+ This routine is called only when the decompressor has failed to find
+ a restart (RSTn) marker where one is expected. Its mission is to
+ find a suitable point for resuming decompression. For most
+ applications, we recommend that you just use the default resync
+ procedure, jpeg_resync_to_restart(). However, if you are able to back
+ up in the input data stream, or if you have a-priori knowledge about
+ the likely location of restart markers, you may be able to do better.
+ Read the read_restart_marker() and jpeg_resync_to_restart() routines
+ in jdmarker.c if you think you'd like to implement your own resync
+ procedure.
+
+term_source (j_decompress_ptr cinfo)
+ Terminate source --- called by jpeg_finish_decompress() after all
+ data has been read. Often a no-op.
+
+For both fill_input_buffer() and skip_input_data(), there is no such thing
+as an EOF return. If the end of the file has been reached, the routine has
+a choice of exiting via ERREXIT() or inserting fake data into the buffer.
+In most cases, generating a warning message and inserting a fake EOI marker
+is the best course of action --- this will allow the decompressor to output
+however much of the image is there. In pathological cases, the decompressor
+may swallow the EOI and again demand data ... just keep feeding it fake EOIs.
+jdatasrc.c illustrates the recommended error recovery behavior.
+
+term_source() is NOT called by jpeg_abort() or jpeg_destroy(). If you want
+the source manager to be cleaned up during an abort, you must do it yourself.
+
+You will also need code to create a jpeg_source_mgr struct, fill in its method
+pointers, and insert a pointer to the struct into the "src" field of the JPEG
+decompression object. This can be done in-line in your setup code if you
+like, but it's probably cleaner to provide a separate routine similar to the
+jpeg_stdio_src() or jpeg_mem_src() routines of the supplied source managers.
+
+For more information, consult the memory and stdio source and destination
+managers in jdatasrc.c and jdatadst.c.
+
+
+I/O suspension
+--------------
+
+Some applications need to use the JPEG library as an incremental memory-to-
+memory filter: when the compressed data buffer is filled or emptied, they want
+control to return to the outer loop, rather than expecting that the buffer can
+be emptied or reloaded within the data source/destination manager subroutine.
+The library supports this need by providing an "I/O suspension" mode, which we
+describe in this section.
+
+The I/O suspension mode is not a panacea: nothing is guaranteed about the
+maximum amount of time spent in any one call to the library, so it will not
+eliminate response-time problems in single-threaded applications. If you
+need guaranteed response time, we suggest you "bite the bullet" and implement
+a real multi-tasking capability.
+
+To use I/O suspension, cooperation is needed between the calling application
+and the data source or destination manager; you will always need a custom
+source/destination manager. (Please read the previous section if you haven't
+already.) The basic idea is that the empty_output_buffer() or
+fill_input_buffer() routine is a no-op, merely returning FALSE to indicate
+that it has done nothing. Upon seeing this, the JPEG library suspends
+operation and returns to its caller. The surrounding application is
+responsible for emptying or refilling the work buffer before calling the
+JPEG library again.
+
+Compression suspension:
+
+For compression suspension, use an empty_output_buffer() routine that returns
+FALSE; typically it will not do anything else. This will cause the
+compressor to return to the caller of jpeg_write_scanlines(), with the return
+value indicating that not all the supplied scanlines have been accepted.
+The application must make more room in the output buffer, adjust the output
+buffer pointer/count appropriately, and then call jpeg_write_scanlines()
+again, pointing to the first unconsumed scanline.
+
+When forced to suspend, the compressor will backtrack to a convenient stopping
+point (usually the start of the current MCU); it will regenerate some output
+data when restarted. Therefore, although empty_output_buffer() is only
+called when the buffer is filled, you should NOT write out the entire buffer
+after a suspension. Write only the data up to the current position of
+next_output_byte/free_in_buffer. The data beyond that point will be
+regenerated after resumption.
+
+Because of the backtracking behavior, a good-size output buffer is essential
+for efficiency; you don't want the compressor to suspend often. (In fact, an
+overly small buffer could lead to infinite looping, if a single MCU required
+more data than would fit in the buffer.) We recommend a buffer of at least
+several Kbytes. You may want to insert explicit code to ensure that you don't
+call jpeg_write_scanlines() unless there is a reasonable amount of space in
+the output buffer; in other words, flush the buffer before trying to compress
+more data.
+
+The compressor does not allow suspension while it is trying to write JPEG
+markers at the beginning and end of the file. This means that:
+ * At the beginning of a compression operation, there must be enough free
+ space in the output buffer to hold the header markers (typically 600 or
+ so bytes). The recommended buffer size is bigger than this anyway, so
+ this is not a problem as long as you start with an empty buffer. However,
+ this restriction might catch you if you insert large special markers, such
+ as a JFIF thumbnail image, without flushing the buffer afterwards.
+ * When you call jpeg_finish_compress(), there must be enough space in the
+ output buffer to emit any buffered data and the final EOI marker. In the
+ current implementation, half a dozen bytes should suffice for this, but
+ for safety's sake we recommend ensuring that at least 100 bytes are free
+ before calling jpeg_finish_compress().
+
+A more significant restriction is that jpeg_finish_compress() cannot suspend.
+This means you cannot use suspension with multi-pass operating modes, namely
+Huffman code optimization and multiple-scan output. Those modes write the
+whole file during jpeg_finish_compress(), which will certainly result in
+buffer overrun. (Note that this restriction applies only to compression,
+not decompression. The decompressor supports input suspension in all of its
+operating modes.)
+
+Decompression suspension:
+
+For decompression suspension, use a fill_input_buffer() routine that simply
+returns FALSE (except perhaps during error recovery, as discussed below).
+This will cause the decompressor to return to its caller with an indication
+that suspension has occurred. This can happen at four places:
+ * jpeg_read_header(): will return JPEG_SUSPENDED.
+ * jpeg_start_decompress(): will return FALSE, rather than its usual TRUE.
+ * jpeg_read_scanlines(): will return the number of scanlines already
+ completed (possibly 0).
+ * jpeg_finish_decompress(): will return FALSE, rather than its usual TRUE.
+The surrounding application must recognize these cases, load more data into
+the input buffer, and repeat the call. In the case of jpeg_read_scanlines(),
+increment the passed pointers past any scanlines successfully read.
+
+Just as with compression, the decompressor will typically backtrack to a
+convenient restart point before suspending. When fill_input_buffer() is
+called, next_input_byte/bytes_in_buffer point to the current restart point,
+which is where the decompressor will backtrack to if FALSE is returned.
+The data beyond that position must NOT be discarded if you suspend; it needs
+to be re-read upon resumption. In most implementations, you'll need to shift
+this data down to the start of your work buffer and then load more data after
+it. Again, this behavior means that a several-Kbyte work buffer is essential
+for decent performance; furthermore, you should load a reasonable amount of
+new data before resuming decompression. (If you loaded, say, only one new
+byte each time around, you could waste a LOT of cycles.)
+
+The skip_input_data() source manager routine requires special care in a
+suspension scenario. This routine is NOT granted the ability to suspend the
+decompressor; it can decrement bytes_in_buffer to zero, but no more. If the
+requested skip distance exceeds the amount of data currently in the input
+buffer, then skip_input_data() must set bytes_in_buffer to zero and record the
+additional skip distance somewhere else. The decompressor will immediately
+call fill_input_buffer(), which should return FALSE, which will cause a
+suspension return. The surrounding application must then arrange to discard
+the recorded number of bytes before it resumes loading the input buffer.
+(Yes, this design is rather baroque, but it avoids complexity in the far more
+common case where a non-suspending source manager is used.)
+
+If the input data has been exhausted, we recommend that you emit a warning
+and insert dummy EOI markers just as a non-suspending data source manager
+would do. This can be handled either in the surrounding application logic or
+within fill_input_buffer(); the latter is probably more efficient. If
+fill_input_buffer() knows that no more data is available, it can set the
+pointer/count to point to a dummy EOI marker and then return TRUE just as
+though it had read more data in a non-suspending situation.
+
+The decompressor does not attempt to suspend within standard JPEG markers;
+instead it will backtrack to the start of the marker and reprocess the whole
+marker next time. Hence the input buffer must be large enough to hold the
+longest standard marker in the file. Standard JPEG markers should normally
+not exceed a few hundred bytes each (DHT tables are typically the longest).
+We recommend at least a 2K buffer for performance reasons, which is much
+larger than any correct marker is likely to be. For robustness against
+damaged marker length counts, you may wish to insert a test in your
+application for the case that the input buffer is completely full and yet
+the decoder has suspended without consuming any data --- otherwise, if this
+situation did occur, it would lead to an endless loop. (The library can't
+provide this test since it has no idea whether "the buffer is full", or
+even whether there is a fixed-size input buffer.)
+
+The input buffer would need to be 64K to allow for arbitrary COM or APPn
+markers, but these are handled specially: they are either saved into allocated
+memory, or skipped over by calling skip_input_data(). In the former case,
+suspension is handled correctly, and in the latter case, the problem of
+buffer overrun is placed on skip_input_data's shoulders, as explained above.
+Note that if you provide your own marker handling routine for large markers,
+you should consider how to deal with buffer overflow.
+
+Multiple-buffer management:
+
+In some applications it is desirable to store the compressed data in a linked
+list of buffer areas, so as to avoid data copying. This can be handled by
+having empty_output_buffer() or fill_input_buffer() set the pointer and count
+to reference the next available buffer; FALSE is returned only if no more
+buffers are available. Although seemingly straightforward, there is a
+pitfall in this approach: the backtrack that occurs when FALSE is returned
+could back up into an earlier buffer. For example, when fill_input_buffer()
+is called, the current pointer & count indicate the backtrack restart point.
+Since fill_input_buffer() will set the pointer and count to refer to a new
+buffer, the restart position must be saved somewhere else. Suppose a second
+call to fill_input_buffer() occurs in the same library call, and no
+additional input data is available, so fill_input_buffer must return FALSE.
+If the JPEG library has not moved the pointer/count forward in the current
+buffer, then *the correct restart point is the saved position in the prior
+buffer*. Prior buffers may be discarded only after the library establishes
+a restart point within a later buffer. Similar remarks apply for output into
+a chain of buffers.
+
+The library will never attempt to backtrack over a skip_input_data() call,
+so any skipped data can be permanently discarded. You still have to deal
+with the case of skipping not-yet-received data, however.
+
+It's much simpler to use only a single buffer; when fill_input_buffer() is
+called, move any unconsumed data (beyond the current pointer/count) down to
+the beginning of this buffer and then load new data into the remaining buffer
+space. This approach requires a little more data copying but is far easier
+to get right.
+
+
+Progressive JPEG support
+------------------------
+
+Progressive JPEG rearranges the stored data into a series of scans of
+increasing quality. In situations where a JPEG file is transmitted across a
+slow communications link, a decoder can generate a low-quality image very
+quickly from the first scan, then gradually improve the displayed quality as
+more scans are received. The final image after all scans are complete is
+identical to that of a regular (sequential) JPEG file of the same quality
+setting. Progressive JPEG files are often slightly smaller than equivalent
+sequential JPEG files, but the possibility of incremental display is the main
+reason for using progressive JPEG.
+
+The IJG encoder library generates progressive JPEG files when given a
+suitable "scan script" defining how to divide the data into scans.
+Creation of progressive JPEG files is otherwise transparent to the encoder.
+Progressive JPEG files can also be read transparently by the decoder library.
+If the decoding application simply uses the library as defined above, it
+will receive a final decoded image without any indication that the file was
+progressive. Of course, this approach does not allow incremental display.
+To perform incremental display, an application needs to use the decoder
+library's "buffered-image" mode, in which it receives a decoded image
+multiple times.
+
+Each displayed scan requires about as much work to decode as a full JPEG
+image of the same size, so the decoder must be fairly fast in relation to the
+data transmission rate in order to make incremental display useful. However,
+it is possible to skip displaying the image and simply add the incoming bits
+to the decoder's coefficient buffer. This is fast because only Huffman
+decoding need be done, not IDCT, upsampling, colorspace conversion, etc.
+The IJG decoder library allows the application to switch dynamically between
+displaying the image and simply absorbing the incoming bits. A properly
+coded application can automatically adapt the number of display passes to
+suit the time available as the image is received. Also, a final
+higher-quality display cycle can be performed from the buffered data after
+the end of the file is reached.
+
+Progressive compression:
+
+To create a progressive JPEG file (or a multiple-scan sequential JPEG file),
+set the scan_info cinfo field to point to an array of scan descriptors, and
+perform compression as usual. Instead of constructing your own scan list,
+you can call the jpeg_simple_progression() helper routine to create a
+recommended progression sequence; this method should be used by all
+applications that don't want to get involved in the nitty-gritty of
+progressive scan sequence design. (If you want to provide user control of
+scan sequences, you may wish to borrow the scan script reading code found
+in rdswitch.c, so that you can read scan script files just like cjpeg's.)
+When scan_info is not NULL, the compression library will store DCT'd data
+into a buffer array as jpeg_write_scanlines() is called, and will emit all
+the requested scans during jpeg_finish_compress(). This implies that
+multiple-scan output cannot be created with a suspending data destination
+manager, since jpeg_finish_compress() does not support suspension. We
+should also note that the compressor currently forces Huffman optimization
+mode when creating a progressive JPEG file, because the default Huffman
+tables are unsuitable for progressive files.
+
+Progressive decompression:
+
+When buffered-image mode is not used, the decoder library will read all of
+a multi-scan file during jpeg_start_decompress(), so that it can provide a
+final decoded image. (Here "multi-scan" means either progressive or
+multi-scan sequential.) This makes multi-scan files transparent to the
+decoding application. However, existing applications that used suspending
+input with version 5 of the IJG library will need to be modified to check
+for a suspension return from jpeg_start_decompress().
+
+To perform incremental display, an application must use the library's
+buffered-image mode. This is described in the next section.
+
+
+Buffered-image mode
+-------------------
+
+In buffered-image mode, the library stores the partially decoded image in a
+coefficient buffer, from which it can be read out as many times as desired.
+This mode is typically used for incremental display of progressive JPEG files,
+but it can be used with any JPEG file. Each scan of a progressive JPEG file
+adds more data (more detail) to the buffered image. The application can
+display in lockstep with the source file (one display pass per input scan),
+or it can allow input processing to outrun display processing. By making
+input and display processing run independently, it is possible for the
+application to adapt progressive display to a wide range of data transmission
+rates.
+
+The basic control flow for buffered-image decoding is
+
+ jpeg_create_decompress()
+ set data source
+ jpeg_read_header()
+ set overall decompression parameters
+ cinfo.buffered_image = TRUE; /* select buffered-image mode */
+ jpeg_start_decompress()
+ for (each output pass) {
+ adjust output decompression parameters if required
+ jpeg_start_output() /* start a new output pass */
+ for (all scanlines in image) {
+ jpeg_read_scanlines()
+ display scanlines
+ }
+ jpeg_finish_output() /* terminate output pass */
+ }
+ jpeg_finish_decompress()
+ jpeg_destroy_decompress()
+
+This differs from ordinary unbuffered decoding in that there is an additional
+level of looping. The application can choose how many output passes to make
+and how to display each pass.
+
+The simplest approach to displaying progressive images is to do one display
+pass for each scan appearing in the input file. In this case the outer loop
+condition is typically
+ while (! jpeg_input_complete(&cinfo))
+and the start-output call should read
+ jpeg_start_output(&cinfo, cinfo.input_scan_number);
+The second parameter to jpeg_start_output() indicates which scan of the input
+file is to be displayed; the scans are numbered starting at 1 for this
+purpose. (You can use a loop counter starting at 1 if you like, but using
+the library's input scan counter is easier.) The library automatically reads
+data as necessary to complete each requested scan, and jpeg_finish_output()
+advances to the next scan or end-of-image marker (hence input_scan_number
+will be incremented by the time control arrives back at jpeg_start_output()).
+With this technique, data is read from the input file only as needed, and
+input and output processing run in lockstep.
+
+After reading the final scan and reaching the end of the input file, the
+buffered image remains available; it can be read additional times by
+repeating the jpeg_start_output()/jpeg_read_scanlines()/jpeg_finish_output()
+sequence. For example, a useful technique is to use fast one-pass color
+quantization for display passes made while the image is arriving, followed by
+a final display pass using two-pass quantization for highest quality. This
+is done by changing the library parameters before the final output pass.
+Changing parameters between passes is discussed in detail below.
+
+In general the last scan of a progressive file cannot be recognized as such
+until after it is read, so a post-input display pass is the best approach if
+you want special processing in the final pass.
+
+When done with the image, be sure to call jpeg_finish_decompress() to release
+the buffered image (or just use jpeg_destroy_decompress()).
+
+If input data arrives faster than it can be displayed, the application can
+cause the library to decode input data in advance of what's needed to produce
+output. This is done by calling the routine jpeg_consume_input().
+The return value is one of the following:
+ JPEG_REACHED_SOS: reached an SOS marker (the start of a new scan)
+ JPEG_REACHED_EOI: reached the EOI marker (end of image)
+ JPEG_ROW_COMPLETED: completed reading one MCU row of compressed data
+ JPEG_SCAN_COMPLETED: completed reading last MCU row of current scan
+ JPEG_SUSPENDED: suspended before completing any of the above
+(JPEG_SUSPENDED can occur only if a suspending data source is used.) This
+routine can be called at any time after initializing the JPEG object. It
+reads some additional data and returns when one of the indicated significant
+events occurs. (If called after the EOI marker is reached, it will
+immediately return JPEG_REACHED_EOI without attempting to read more data.)
+
+The library's output processing will automatically call jpeg_consume_input()
+whenever the output processing overtakes the input; thus, simple lockstep
+display requires no direct calls to jpeg_consume_input(). But by adding
+calls to jpeg_consume_input(), you can absorb data in advance of what is
+being displayed. This has two benefits:
+ * You can limit buildup of unprocessed data in your input buffer.
+ * You can eliminate extra display passes by paying attention to the
+ state of the library's input processing.
+
+The first of these benefits only requires interspersing calls to
+jpeg_consume_input() with your display operations and any other processing
+you may be doing. To avoid wasting cycles due to backtracking, it's best to
+call jpeg_consume_input() only after a hundred or so new bytes have arrived.
+This is discussed further under "I/O suspension", above. (Note: the JPEG
+library currently is not thread-safe. You must not call jpeg_consume_input()
+from one thread of control if a different library routine is working on the
+same JPEG object in another thread.)
+
+When input arrives fast enough that more than one new scan is available
+before you start a new output pass, you may as well skip the output pass
+corresponding to the completed scan. This occurs for free if you pass
+cinfo.input_scan_number as the target scan number to jpeg_start_output().
+The input_scan_number field is simply the index of the scan currently being
+consumed by the input processor. You can ensure that this is up-to-date by
+emptying the input buffer just before calling jpeg_start_output(): call
+jpeg_consume_input() repeatedly until it returns JPEG_SUSPENDED or
+JPEG_REACHED_EOI.
+
+The target scan number passed to jpeg_start_output() is saved in the
+cinfo.output_scan_number field. The library's output processing calls
+jpeg_consume_input() whenever the current input scan number and row within
+that scan is less than or equal to the current output scan number and row.
+Thus, input processing can "get ahead" of the output processing but is not
+allowed to "fall behind". You can achieve several different effects by
+manipulating this interlock rule. For example, if you pass a target scan
+number greater than the current input scan number, the output processor will
+wait until that scan starts to arrive before producing any output. (To avoid
+an infinite loop, the target scan number is automatically reset to the last
+scan number when the end of image is reached. Thus, if you specify a large
+target scan number, the library will just absorb the entire input file and
+then perform an output pass. This is effectively the same as what
+jpeg_start_decompress() does when you don't select buffered-image mode.)
+When you pass a target scan number equal to the current input scan number,
+the image is displayed no faster than the current input scan arrives. The
+final possibility is to pass a target scan number less than the current input
+scan number; this disables the input/output interlock and causes the output
+processor to simply display whatever it finds in the image buffer, without
+waiting for input. (However, the library will not accept a target scan
+number less than one, so you can't avoid waiting for the first scan.)
+
+When data is arriving faster than the output display processing can advance
+through the image, jpeg_consume_input() will store data into the buffered
+image beyond the point at which the output processing is reading data out
+again. If the input arrives fast enough, it may "wrap around" the buffer to
+the point where the input is more than one whole scan ahead of the output.
+If the output processing simply proceeds through its display pass without
+paying attention to the input, the effect seen on-screen is that the lower
+part of the image is one or more scans better in quality than the upper part.
+Then, when the next output scan is started, you have a choice of what target
+scan number to use. The recommended choice is to use the current input scan
+number at that time, which implies that you've skipped the output scans
+corresponding to the input scans that were completed while you processed the
+previous output scan. In this way, the decoder automatically adapts its
+speed to the arriving data, by skipping output scans as necessary to keep up
+with the arriving data.
+
+When using this strategy, you'll want to be sure that you perform a final
+output pass after receiving all the data; otherwise your last display may not
+be full quality across the whole screen. So the right outer loop logic is
+something like this:
+ do {
+ absorb any waiting input by calling jpeg_consume_input()
+ final_pass = jpeg_input_complete(&cinfo);
+ adjust output decompression parameters if required
+ jpeg_start_output(&cinfo, cinfo.input_scan_number);
+ ...
+ jpeg_finish_output()
+ } while (! final_pass);
+rather than quitting as soon as jpeg_input_complete() returns TRUE. This
+arrangement makes it simple to use higher-quality decoding parameters
+for the final pass. But if you don't want to use special parameters for
+the final pass, the right loop logic is like this:
+ for (;;) {
+ absorb any waiting input by calling jpeg_consume_input()
+ jpeg_start_output(&cinfo, cinfo.input_scan_number);
+ ...
+ jpeg_finish_output()
+ if (jpeg_input_complete(&cinfo) &&
+ cinfo.input_scan_number == cinfo.output_scan_number)
+ break;
+ }
+In this case you don't need to know in advance whether an output pass is to
+be the last one, so it's not necessary to have reached EOF before starting
+the final output pass; rather, what you want to test is whether the output
+pass was performed in sync with the final input scan. This form of the loop
+will avoid an extra output pass whenever the decoder is able (or nearly able)
+to keep up with the incoming data.
+
+When the data transmission speed is high, you might begin a display pass,
+then find that much or all of the file has arrived before you can complete
+the pass. (You can detect this by noting the JPEG_REACHED_EOI return code
+from jpeg_consume_input(), or equivalently by testing jpeg_input_complete().)
+In this situation you may wish to abort the current display pass and start a
+new one using the newly arrived information. To do so, just call
+jpeg_finish_output() and then start a new pass with jpeg_start_output().
+
+A variant strategy is to abort and restart display if more than one complete
+scan arrives during an output pass; this can be detected by noting
+JPEG_REACHED_SOS returns and/or examining cinfo.input_scan_number. This
+idea should be employed with caution, however, since the display process
+might never get to the bottom of the image before being aborted, resulting
+in the lower part of the screen being several passes worse than the upper.
+In most cases it's probably best to abort an output pass only if the whole
+file has arrived and you want to begin the final output pass immediately.
+
+When receiving data across a communication link, we recommend always using
+the current input scan number for the output target scan number; if a
+higher-quality final pass is to be done, it should be started (aborting any
+incomplete output pass) as soon as the end of file is received. However,
+many other strategies are possible. For example, the application can examine
+the parameters of the current input scan and decide whether to display it or
+not. If the scan contains only chroma data, one might choose not to use it
+as the target scan, expecting that the scan will be small and will arrive
+quickly. To skip to the next scan, call jpeg_consume_input() until it
+returns JPEG_REACHED_SOS or JPEG_REACHED_EOI. Or just use the next higher
+number as the target scan for jpeg_start_output(); but that method doesn't
+let you inspect the next scan's parameters before deciding to display it.
+
+
+In buffered-image mode, jpeg_start_decompress() never performs input and
+thus never suspends. An application that uses input suspension with
+buffered-image mode must be prepared for suspension returns from these
+routines:
+* jpeg_start_output() performs input only if you request 2-pass quantization
+ and the target scan isn't fully read yet. (This is discussed below.)
+* jpeg_read_scanlines(), as always, returns the number of scanlines that it
+ was able to produce before suspending.
+* jpeg_finish_output() will read any markers following the target scan,
+ up to the end of the file or the SOS marker that begins another scan.
+ (But it reads no input if jpeg_consume_input() has already reached the
+ end of the file or a SOS marker beyond the target output scan.)
+* jpeg_finish_decompress() will read until the end of file, and thus can
+ suspend if the end hasn't already been reached (as can be tested by
+ calling jpeg_input_complete()).
+jpeg_start_output(), jpeg_finish_output(), and jpeg_finish_decompress()
+all return TRUE if they completed their tasks, FALSE if they had to suspend.
+In the event of a FALSE return, the application must load more input data
+and repeat the call. Applications that use non-suspending data sources need
+not check the return values of these three routines.
+
+
+It is possible to change decoding parameters between output passes in the
+buffered-image mode. The decoder library currently supports only very
+limited changes of parameters. ONLY THE FOLLOWING parameter changes are
+allowed after jpeg_start_decompress() is called:
+* dct_method can be changed before each call to jpeg_start_output().
+ For example, one could use a fast DCT method for early scans, changing
+ to a higher quality method for the final scan.
+* dither_mode can be changed before each call to jpeg_start_output();
+ of course this has no impact if not using color quantization. Typically
+ one would use ordered dither for initial passes, then switch to
+ Floyd-Steinberg dither for the final pass. Caution: changing dither mode
+ can cause more memory to be allocated by the library. Although the amount
+ of memory involved is not large (a scanline or so), it may cause the
+ initial max_memory_to_use specification to be exceeded, which in the worst
+ case would result in an out-of-memory failure.
+* do_block_smoothing can be changed before each call to jpeg_start_output().
+ This setting is relevant only when decoding a progressive JPEG image.
+ During the first DC-only scan, block smoothing provides a very "fuzzy" look
+ instead of the very "blocky" look seen without it; which is better seems a
+ matter of personal taste. But block smoothing is nearly always a win
+ during later stages, especially when decoding a successive-approximation
+ image: smoothing helps to hide the slight blockiness that otherwise shows
+ up on smooth gradients until the lowest coefficient bits are sent.
+* Color quantization mode can be changed under the rules described below.
+ You *cannot* change between full-color and quantized output (because that
+ would alter the required I/O buffer sizes), but you can change which
+ quantization method is used.
+
+When generating color-quantized output, changing quantization method is a
+very useful way of switching between high-speed and high-quality display.
+The library allows you to change among its three quantization methods:
+1. Single-pass quantization to a fixed color cube.
+ Selected by cinfo.two_pass_quantize = FALSE and cinfo.colormap = NULL.
+2. Single-pass quantization to an application-supplied colormap.
+ Selected by setting cinfo.colormap to point to the colormap (the value of
+ two_pass_quantize is ignored); also set cinfo.actual_number_of_colors.
+3. Two-pass quantization to a colormap chosen specifically for the image.
+ Selected by cinfo.two_pass_quantize = TRUE and cinfo.colormap = NULL.
+ (This is the default setting selected by jpeg_read_header, but it is
+ probably NOT what you want for the first pass of progressive display!)
+These methods offer successively better quality and lesser speed. However,
+only the first method is available for quantizing in non-RGB color spaces.
+
+IMPORTANT: because the different quantizer methods have very different
+working-storage requirements, the library requires you to indicate which
+one(s) you intend to use before you call jpeg_start_decompress(). (If we did
+not require this, the max_memory_to_use setting would be a complete fiction.)
+You do this by setting one or more of these three cinfo fields to TRUE:
+ enable_1pass_quant Fixed color cube colormap
+ enable_external_quant Externally-supplied colormap
+ enable_2pass_quant Two-pass custom colormap
+All three are initialized FALSE by jpeg_read_header(). But
+jpeg_start_decompress() automatically sets TRUE the one selected by the
+current two_pass_quantize and colormap settings, so you only need to set the
+enable flags for any other quantization methods you plan to change to later.
+
+After setting the enable flags correctly at jpeg_start_decompress() time, you
+can change to any enabled quantization method by setting two_pass_quantize
+and colormap properly just before calling jpeg_start_output(). The following
+special rules apply:
+1. You must explicitly set cinfo.colormap to NULL when switching to 1-pass
+ or 2-pass mode from a different mode, or when you want the 2-pass
+ quantizer to be re-run to generate a new colormap.
+2. To switch to an external colormap, or to change to a different external
+ colormap than was used on the prior pass, you must call
+ jpeg_new_colormap() after setting cinfo.colormap.
+NOTE: if you want to use the same colormap as was used in the prior pass,
+you should not do either of these things. This will save some nontrivial
+switchover costs.
+(These requirements exist because cinfo.colormap will always be non-NULL
+after completing a prior output pass, since both the 1-pass and 2-pass
+quantizers set it to point to their output colormaps. Thus you have to
+do one of these two things to notify the library that something has changed.
+Yup, it's a bit klugy, but it's necessary to do it this way for backwards
+compatibility.)
+
+Note that in buffered-image mode, the library generates any requested colormap
+during jpeg_start_output(), not during jpeg_start_decompress().
+
+When using two-pass quantization, jpeg_start_output() makes a pass over the
+buffered image to determine the optimum color map; it therefore may take a
+significant amount of time, whereas ordinarily it does little work. The
+progress monitor hook is called during this pass, if defined. It is also
+important to realize that if the specified target scan number is greater than
+or equal to the current input scan number, jpeg_start_output() will attempt
+to consume input as it makes this pass. If you use a suspending data source,
+you need to check for a FALSE return from jpeg_start_output() under these
+conditions. The combination of 2-pass quantization and a not-yet-fully-read
+target scan is the only case in which jpeg_start_output() will consume input.
+
+
+Application authors who support buffered-image mode may be tempted to use it
+for all JPEG images, even single-scan ones. This will work, but it is
+inefficient: there is no need to create an image-sized coefficient buffer for
+single-scan images. Requesting buffered-image mode for such an image wastes
+memory. Worse, it can cost time on large images, since the buffered data has
+to be swapped out or written to a temporary file. If you are concerned about
+maximum performance on baseline JPEG files, you should use buffered-image
+mode only when the incoming file actually has multiple scans. This can be
+tested by calling jpeg_has_multiple_scans(), which will return a correct
+result at any time after jpeg_read_header() completes.
+
+It is also worth noting that when you use jpeg_consume_input() to let input
+processing get ahead of output processing, the resulting pattern of access to
+the coefficient buffer is quite nonsequential. It's best to use the memory
+manager jmemnobs.c if you can (ie, if you have enough real or virtual main
+memory). If not, at least make sure that max_memory_to_use is set as high as
+possible. If the JPEG memory manager has to use a temporary file, you will
+probably see a lot of disk traffic and poor performance. (This could be
+improved with additional work on the memory manager, but we haven't gotten
+around to it yet.)
+
+In some applications it may be convenient to use jpeg_consume_input() for all
+input processing, including reading the initial markers; that is, you may
+wish to call jpeg_consume_input() instead of jpeg_read_header() during
+startup. This works, but note that you must check for JPEG_REACHED_SOS and
+JPEG_REACHED_EOI return codes as the equivalent of jpeg_read_header's codes.
+Once the first SOS marker has been reached, you must call
+jpeg_start_decompress() before jpeg_consume_input() will consume more input;
+it'll just keep returning JPEG_REACHED_SOS until you do. If you read a
+tables-only file this way, jpeg_consume_input() will return JPEG_REACHED_EOI
+without ever returning JPEG_REACHED_SOS; be sure to check for this case.
+If this happens, the decompressor will not read any more input until you call
+jpeg_abort() to reset it. It is OK to call jpeg_consume_input() even when not
+using buffered-image mode, but in that case it's basically a no-op after the
+initial markers have been read: it will just return JPEG_SUSPENDED.
+
+
+Abbreviated datastreams and multiple images
+-------------------------------------------
+
+A JPEG compression or decompression object can be reused to process multiple
+images. This saves a small amount of time per image by eliminating the
+"create" and "destroy" operations, but that isn't the real purpose of the
+feature. Rather, reuse of an object provides support for abbreviated JPEG
+datastreams. Object reuse can also simplify processing a series of images in
+a single input or output file. This section explains these features.
+
+A JPEG file normally contains several hundred bytes worth of quantization
+and Huffman tables. In a situation where many images will be stored or
+transmitted with identical tables, this may represent an annoying overhead.
+The JPEG standard therefore permits tables to be omitted. The standard
+defines three classes of JPEG datastreams:
+ * "Interchange" datastreams contain an image and all tables needed to decode
+ the image. These are the usual kind of JPEG file.
+ * "Abbreviated image" datastreams contain an image, but are missing some or
+ all of the tables needed to decode that image.
+ * "Abbreviated table specification" (henceforth "tables-only") datastreams
+ contain only table specifications.
+To decode an abbreviated image, it is necessary to load the missing table(s)
+into the decoder beforehand. This can be accomplished by reading a separate
+tables-only file. A variant scheme uses a series of images in which the first
+image is an interchange (complete) datastream, while subsequent ones are
+abbreviated and rely on the tables loaded by the first image. It is assumed
+that once the decoder has read a table, it will remember that table until a
+new definition for the same table number is encountered.
+
+It is the application designer's responsibility to figure out how to associate
+the correct tables with an abbreviated image. While abbreviated datastreams
+can be useful in a closed environment, their use is strongly discouraged in
+any situation where data exchange with other applications might be needed.
+Caveat designer.
+
+The JPEG library provides support for reading and writing any combination of
+tables-only datastreams and abbreviated images. In both compression and
+decompression objects, a quantization or Huffman table will be retained for
+the lifetime of the object, unless it is overwritten by a new table definition.
+
+
+To create abbreviated image datastreams, it is only necessary to tell the
+compressor not to emit some or all of the tables it is using. Each
+quantization and Huffman table struct contains a boolean field "sent_table",
+which normally is initialized to FALSE. For each table used by the image, the
+header-writing process emits the table and sets sent_table = TRUE unless it is
+already TRUE. (In normal usage, this prevents outputting the same table
+definition multiple times, as would otherwise occur because the chroma
+components typically share tables.) Thus, setting this field to TRUE before
+calling jpeg_start_compress() will prevent the table from being written at
+all.
+
+If you want to create a "pure" abbreviated image file containing no tables,
+just call "jpeg_suppress_tables(&cinfo, TRUE)" after constructing all the
+tables. If you want to emit some but not all tables, you'll need to set the
+individual sent_table fields directly.
+
+To create an abbreviated image, you must also call jpeg_start_compress()
+with a second parameter of FALSE, not TRUE. Otherwise jpeg_start_compress()
+will force all the sent_table fields to FALSE. (This is a safety feature to
+prevent abbreviated images from being created accidentally.)
+
+To create a tables-only file, perform the same parameter setup that you
+normally would, but instead of calling jpeg_start_compress() and so on, call
+jpeg_write_tables(&cinfo). This will write an abbreviated datastream
+containing only SOI, DQT and/or DHT markers, and EOI. All the quantization
+and Huffman tables that are currently defined in the compression object will
+be emitted unless their sent_tables flag is already TRUE, and then all the
+sent_tables flags will be set TRUE.
+
+A sure-fire way to create matching tables-only and abbreviated image files
+is to proceed as follows:
+
+ create JPEG compression object
+ set JPEG parameters
+ set destination to tables-only file
+ jpeg_write_tables(&cinfo);
+ set destination to image file
+ jpeg_start_compress(&cinfo, FALSE);
+ write data...
+ jpeg_finish_compress(&cinfo);
+
+Since the JPEG parameters are not altered between writing the table file and
+the abbreviated image file, the same tables are sure to be used. Of course,
+you can repeat the jpeg_start_compress() ... jpeg_finish_compress() sequence
+many times to produce many abbreviated image files matching the table file.
+
+You cannot suppress output of the computed Huffman tables when Huffman
+optimization is selected. (If you could, there'd be no way to decode the
+image...) Generally, you don't want to set optimize_coding = TRUE when
+you are trying to produce abbreviated files.
+
+In some cases you might want to compress an image using tables which are
+not stored in the application, but are defined in an interchange or
+tables-only file readable by the application. This can be done by setting up
+a JPEG decompression object to read the specification file, then copying the
+tables into your compression object. See jpeg_copy_critical_parameters()
+for an example of copying quantization tables.
+
+
+To read abbreviated image files, you simply need to load the proper tables
+into the decompression object before trying to read the abbreviated image.
+If the proper tables are stored in the application program, you can just
+allocate the table structs and fill in their contents directly. For example,
+to load a fixed quantization table into table slot "n":
+
+ if (cinfo.quant_tbl_ptrs[n] == NULL)
+ cinfo.quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) &cinfo);
+ quant_ptr = cinfo.quant_tbl_ptrs[n]; /* quant_ptr is JQUANT_TBL* */
+ for (i = 0; i < 64; i++) {
+ /* Qtable[] is desired quantization table, in natural array order */
+ quant_ptr->quantval[i] = Qtable[i];
+ }
+
+Code to load a fixed Huffman table is typically (for AC table "n"):
+
+ if (cinfo.ac_huff_tbl_ptrs[n] == NULL)
+ cinfo.ac_huff_tbl_ptrs[n] = jpeg_alloc_huff_table((j_common_ptr) &cinfo);
+ huff_ptr = cinfo.ac_huff_tbl_ptrs[n]; /* huff_ptr is JHUFF_TBL* */
+ for (i = 1; i <= 16; i++) {
+ /* counts[i] is number of Huffman codes of length i bits, i=1..16 */
+ huff_ptr->bits[i] = counts[i];
+ }
+ for (i = 0; i < 256; i++) {
+ /* symbols[] is the list of Huffman symbols, in code-length order */
+ huff_ptr->huffval[i] = symbols[i];
+ }
+
+(Note that trying to set cinfo.quant_tbl_ptrs[n] to point directly at a
+constant JQUANT_TBL object is not safe. If the incoming file happened to
+contain a quantization table definition, your master table would get
+overwritten! Instead allocate a working table copy and copy the master table
+into it, as illustrated above. Ditto for Huffman tables, of course.)
+
+You might want to read the tables from a tables-only file, rather than
+hard-wiring them into your application. The jpeg_read_header() call is
+sufficient to read a tables-only file. You must pass a second parameter of
+FALSE to indicate that you do not require an image to be present. Thus, the
+typical scenario is
+
+ create JPEG decompression object
+ set source to tables-only file
+ jpeg_read_header(&cinfo, FALSE);
+ set source to abbreviated image file
+ jpeg_read_header(&cinfo, TRUE);
+ set decompression parameters
+ jpeg_start_decompress(&cinfo);
+ read data...
+ jpeg_finish_decompress(&cinfo);
+
+In some cases, you may want to read a file without knowing whether it contains
+an image or just tables. In that case, pass FALSE and check the return value
+from jpeg_read_header(): it will be JPEG_HEADER_OK if an image was found,
+JPEG_HEADER_TABLES_ONLY if only tables were found. (A third return value,
+JPEG_SUSPENDED, is possible when using a suspending data source manager.)
+Note that jpeg_read_header() will not complain if you read an abbreviated
+image for which you haven't loaded the missing tables; the missing-table check
+occurs later, in jpeg_start_decompress().
+
+
+It is possible to read a series of images from a single source file by
+repeating the jpeg_read_header() ... jpeg_finish_decompress() sequence,
+without releasing/recreating the JPEG object or the data source module.
+(If you did reinitialize, any partial bufferload left in the data source
+buffer at the end of one image would be discarded, causing you to lose the
+start of the next image.) When you use this method, stored tables are
+automatically carried forward, so some of the images can be abbreviated images
+that depend on tables from earlier images.
+
+If you intend to write a series of images into a single destination file,
+you might want to make a specialized data destination module that doesn't
+flush the output buffer at term_destination() time. This would speed things
+up by some trifling amount. Of course, you'd need to remember to flush the
+buffer after the last image. You can make the later images be abbreviated
+ones by passing FALSE to jpeg_start_compress().
+
+
+Special markers
+---------------
+
+Some applications may need to insert or extract special data in the JPEG
+datastream. The JPEG standard provides marker types "COM" (comment) and
+"APP0" through "APP15" (application) to hold application-specific data.
+Unfortunately, the use of these markers is not specified by the standard.
+COM markers are fairly widely used to hold user-supplied text. The JFIF file
+format spec uses APP0 markers with specified initial strings to hold certain
+data. Adobe applications use APP14 markers beginning with the string "Adobe"
+for miscellaneous data. Other APPn markers are rarely seen, but might
+contain almost anything.
+
+If you wish to store user-supplied text, we recommend you use COM markers
+and place readable 7-bit ASCII text in them. Newline conventions are not
+standardized --- expect to find LF (Unix style), CR/LF (DOS style), or CR
+(Mac style). A robust COM reader should be able to cope with random binary
+garbage, including nulls, since some applications generate COM markers
+containing non-ASCII junk. (But yours should not be one of them.)
+
+For program-supplied data, use an APPn marker, and be sure to begin it with an
+identifying string so that you can tell whether the marker is actually yours.
+It's probably best to avoid using APP0 or APP14 for any private markers.
+(NOTE: the upcoming SPIFF standard will use APP8 markers; we recommend you
+not use APP8 markers for any private purposes, either.)
+
+Keep in mind that at most 65533 bytes can be put into one marker, but you
+can have as many markers as you like.
+
+By default, the IJG compression library will write a JFIF APP0 marker if the
+selected JPEG colorspace is grayscale or YCbCr, or an Adobe APP14 marker if
+the selected colorspace is RGB, CMYK, or YCCK. You can disable this, but
+we don't recommend it. The decompression library will recognize JFIF and
+Adobe markers and will set the JPEG colorspace properly when one is found.
+
+
+You can write special markers immediately following the datastream header by
+calling jpeg_write_marker() after jpeg_start_compress() and before the first
+call to jpeg_write_scanlines(). When you do this, the markers appear after
+the SOI and the JFIF APP0 and Adobe APP14 markers (if written), but before
+all else. Specify the marker type parameter as "JPEG_COM" for COM or
+"JPEG_APP0 + n" for APPn. (Actually, jpeg_write_marker will let you write
+any marker type, but we don't recommend writing any other kinds of marker.)
+For example, to write a user comment string pointed to by comment_text:
+ jpeg_write_marker(cinfo, JPEG_COM, comment_text, strlen(comment_text));
+
+If it's not convenient to store all the marker data in memory at once,
+you can instead call jpeg_write_m_header() followed by multiple calls to
+jpeg_write_m_byte(). If you do it this way, it's your responsibility to
+call jpeg_write_m_byte() exactly the number of times given in the length
+parameter to jpeg_write_m_header(). (This method lets you empty the
+output buffer partway through a marker, which might be important when
+using a suspending data destination module. In any case, if you are using
+a suspending destination, you should flush its buffer after inserting
+any special markers. See "I/O suspension".)
+
+Or, if you prefer to synthesize the marker byte sequence yourself,
+you can just cram it straight into the data destination module.
+
+If you are writing JFIF 1.02 extension markers (thumbnail images), don't
+forget to set cinfo.JFIF_minor_version = 2 so that the encoder will write the
+correct JFIF version number in the JFIF header marker. The library's default
+is to write version 1.01, but that's wrong if you insert any 1.02 extension
+markers. (We could probably get away with just defaulting to 1.02, but there
+used to be broken decoders that would complain about unknown minor version
+numbers. To reduce compatibility risks it's safest not to write 1.02 unless
+you are actually using 1.02 extensions.)
+
+
+When reading, two methods of handling special markers are available:
+1. You can ask the library to save the contents of COM and/or APPn markers
+into memory, and then examine them at your leisure afterwards.
+2. You can supply your own routine to process COM and/or APPn markers
+on-the-fly as they are read.
+The first method is simpler to use, especially if you are using a suspending
+data source; writing a marker processor that copes with input suspension is
+not easy (consider what happens if the marker is longer than your available
+input buffer). However, the second method conserves memory since the marker
+data need not be kept around after it's been processed.
+
+For either method, you'd normally set up marker handling after creating a
+decompression object and before calling jpeg_read_header(), because the
+markers of interest will typically be near the head of the file and so will
+be scanned by jpeg_read_header. Once you've established a marker handling
+method, it will be used for the life of that decompression object
+(potentially many datastreams), unless you change it. Marker handling is
+determined separately for COM markers and for each APPn marker code.
+
+
+To save the contents of special markers in memory, call
+ jpeg_save_markers(cinfo, marker_code, length_limit)
+where marker_code is the marker type to save, JPEG_COM or JPEG_APP0+n.
+(To arrange to save all the special marker types, you need to call this
+routine 17 times, for COM and APP0-APP15.) If the incoming marker is longer
+than length_limit data bytes, only length_limit bytes will be saved; this
+parameter allows you to avoid chewing up memory when you only need to see the
+first few bytes of a potentially large marker. If you want to save all the
+data, set length_limit to 0xFFFF; that is enough since marker lengths are only
+16 bits. As a special case, setting length_limit to 0 prevents that marker
+type from being saved at all. (That is the default behavior, in fact.)
+
+After jpeg_read_header() completes, you can examine the special markers by
+following the cinfo->marker_list pointer chain. All the special markers in
+the file appear in this list, in order of their occurrence in the file (but
+omitting any markers of types you didn't ask for). Both the original data
+length and the saved data length are recorded for each list entry; the latter
+will not exceed length_limit for the particular marker type. Note that these
+lengths exclude the marker length word, whereas the stored representation
+within the JPEG file includes it. (Hence the maximum data length is really
+only 65533.)
+
+It is possible that additional special markers appear in the file beyond the
+SOS marker at which jpeg_read_header stops; if so, the marker list will be
+extended during reading of the rest of the file. This is not expected to be
+common, however. If you are short on memory you may want to reset the length
+limit to zero for all marker types after finishing jpeg_read_header, to
+ensure that the max_memory_to_use setting cannot be exceeded due to addition
+of later markers.
+
+The marker list remains stored until you call jpeg_finish_decompress or
+jpeg_abort, at which point the memory is freed and the list is set to empty.
+(jpeg_destroy also releases the storage, of course.)
+
+Note that the library is internally interested in APP0 and APP14 markers;
+if you try to set a small nonzero length limit on these types, the library
+will silently force the length up to the minimum it wants. (But you can set
+a zero length limit to prevent them from being saved at all.) Also, in a
+16-bit environment, the maximum length limit may be constrained to less than
+65533 by malloc() limitations. It is therefore best not to assume that the
+effective length limit is exactly what you set it to be.
+
+
+If you want to supply your own marker-reading routine, you do it by calling
+jpeg_set_marker_processor(). A marker processor routine must have the
+signature
+ boolean jpeg_marker_parser_method (j_decompress_ptr cinfo)
+Although the marker code is not explicitly passed, the routine can find it
+in cinfo->unread_marker. At the time of call, the marker proper has been
+read from the data source module. The processor routine is responsible for
+reading the marker length word and the remaining parameter bytes, if any.
+Return TRUE to indicate success. (FALSE should be returned only if you are
+using a suspending data source and it tells you to suspend. See the standard
+marker processors in jdmarker.c for appropriate coding methods if you need to
+use a suspending data source.)
+
+If you override the default APP0 or APP14 processors, it is up to you to
+recognize JFIF and Adobe markers if you want colorspace recognition to occur
+properly. We recommend copying and extending the default processors if you
+want to do that. (A better idea is to save these marker types for later
+examination by calling jpeg_save_markers(); that method doesn't interfere
+with the library's own processing of these markers.)
+
+jpeg_set_marker_processor() and jpeg_save_markers() are mutually exclusive
+--- if you call one it overrides any previous call to the other, for the
+particular marker type specified.
+
+A simple example of an external COM processor can be found in djpeg.c.
+Also, see jpegtran.c for an example of using jpeg_save_markers.
+
+
+Raw (downsampled) image data
+----------------------------
+
+Some applications need to supply already-downsampled image data to the JPEG
+compressor, or to receive raw downsampled data from the decompressor. The
+library supports this requirement by allowing the application to write or
+read raw data, bypassing the normal preprocessing or postprocessing steps.
+The interface is different from the standard one and is somewhat harder to
+use. If your interest is merely in bypassing color conversion, we recommend
+that you use the standard interface and simply set jpeg_color_space =
+in_color_space (or jpeg_color_space = out_color_space for decompression).
+The mechanism described in this section is necessary only to supply or
+receive downsampled image data, in which not all components have the same
+dimensions.
+
+
+To compress raw data, you must supply the data in the colorspace to be used
+in the JPEG file (please read the earlier section on Special color spaces)
+and downsampled to the sampling factors specified in the JPEG parameters.
+You must supply the data in the format used internally by the JPEG library,
+namely a JSAMPIMAGE array. This is an array of pointers to two-dimensional
+arrays, each of type JSAMPARRAY. Each 2-D array holds the values for one
+color component. This structure is necessary since the components are of
+different sizes. If the image dimensions are not a multiple of the MCU size,
+you must also pad the data correctly (usually, this is done by replicating
+the last column and/or row). The data must be padded to a multiple of a DCT
+block in each component: that is, each downsampled row must contain a
+multiple of 8 valid samples, and there must be a multiple of 8 sample rows
+for each component. (For applications such as conversion of digital TV
+images, the standard image size is usually a multiple of the DCT block size,
+so that no padding need actually be done.)
+
+The procedure for compression of raw data is basically the same as normal
+compression, except that you call jpeg_write_raw_data() in place of
+jpeg_write_scanlines(). Before calling jpeg_start_compress(), you must do
+the following:
+ * Set cinfo->raw_data_in to TRUE. (It is set FALSE by jpeg_set_defaults().)
+ This notifies the library that you will be supplying raw data.
+ Furthermore, set cinfo->do_fancy_downsampling to FALSE if you want to use
+ real downsampled data. (It is set TRUE by jpeg_set_defaults().)
+ * Ensure jpeg_color_space is correct --- an explicit jpeg_set_colorspace()
+ call is a good idea. Note that since color conversion is bypassed,
+ in_color_space is ignored, except that jpeg_set_defaults() uses it to
+ choose the default jpeg_color_space setting.
+ * Ensure the sampling factors, cinfo->comp_info[i].h_samp_factor and
+ cinfo->comp_info[i].v_samp_factor, are correct. Since these indicate the
+ dimensions of the data you are supplying, it's wise to set them
+ explicitly, rather than assuming the library's defaults are what you want.
+
+To pass raw data to the library, call jpeg_write_raw_data() in place of
+jpeg_write_scanlines(). The two routines work similarly except that
+jpeg_write_raw_data takes a JSAMPIMAGE data array rather than JSAMPARRAY.
+The scanlines count passed to and returned from jpeg_write_raw_data is
+measured in terms of the component with the largest v_samp_factor.
+
+jpeg_write_raw_data() processes one MCU row per call, which is to say
+v_samp_factor*DCTSIZE sample rows of each component. The passed num_lines
+value must be at least max_v_samp_factor*DCTSIZE, and the return value will
+be exactly that amount (or possibly some multiple of that amount, in future
+library versions). This is true even on the last call at the bottom of the
+image; don't forget to pad your data as necessary.
+
+The required dimensions of the supplied data can be computed for each
+component as
+ cinfo->comp_info[i].width_in_blocks*DCTSIZE samples per row
+ cinfo->comp_info[i].height_in_blocks*DCTSIZE rows in image
+after jpeg_start_compress() has initialized those fields. If the valid data
+is smaller than this, it must be padded appropriately. For some sampling
+factors and image sizes, additional dummy DCT blocks are inserted to make
+the image a multiple of the MCU dimensions. The library creates such dummy
+blocks itself; it does not read them from your supplied data. Therefore you
+need never pad by more than DCTSIZE samples. An example may help here.
+Assume 2h2v downsampling of YCbCr data, that is
+ cinfo->comp_info[0].h_samp_factor = 2 for Y
+ cinfo->comp_info[0].v_samp_factor = 2
+ cinfo->comp_info[1].h_samp_factor = 1 for Cb
+ cinfo->comp_info[1].v_samp_factor = 1
+ cinfo->comp_info[2].h_samp_factor = 1 for Cr
+ cinfo->comp_info[2].v_samp_factor = 1
+and suppose that the nominal image dimensions (cinfo->image_width and
+cinfo->image_height) are 101x101 pixels. Then jpeg_start_compress() will
+compute downsampled_width = 101 and width_in_blocks = 13 for Y,
+downsampled_width = 51 and width_in_blocks = 7 for Cb and Cr (and the same
+for the height fields). You must pad the Y data to at least 13*8 = 104
+columns and rows, the Cb/Cr data to at least 7*8 = 56 columns and rows. The
+MCU height is max_v_samp_factor = 2 DCT rows so you must pass at least 16
+scanlines on each call to jpeg_write_raw_data(), which is to say 16 actual
+sample rows of Y and 8 each of Cb and Cr. A total of 7 MCU rows are needed,
+so you must pass a total of 7*16 = 112 "scanlines". The last DCT block row
+of Y data is dummy, so it doesn't matter what you pass for it in the data
+arrays, but the scanlines count must total up to 112 so that all of the Cb
+and Cr data gets passed.
+
+Output suspension is supported with raw-data compression: if the data
+destination module suspends, jpeg_write_raw_data() will return 0.
+In this case the same data rows must be passed again on the next call.
+
+
+Decompression with raw data output implies bypassing all postprocessing.
+You must deal with the color space and sampling factors present in the
+incoming file. If your application only handles, say, 2h1v YCbCr data,
+you must check for and fail on other color spaces or other sampling factors.
+The library will not convert to a different color space for you.
+
+To obtain raw data output, set cinfo->raw_data_out = TRUE before
+jpeg_start_decompress() (it is set FALSE by jpeg_read_header()). Be sure to
+verify that the color space and sampling factors are ones you can handle.
+Furthermore, set cinfo->do_fancy_upsampling = FALSE if you want to get real
+downsampled data (it is set TRUE by jpeg_read_header()).
+Then call jpeg_read_raw_data() in place of jpeg_read_scanlines(). The
+decompression process is otherwise the same as usual.
+
+jpeg_read_raw_data() returns one MCU row per call, and thus you must pass a
+buffer of at least max_v_samp_factor*DCTSIZE scanlines (scanline counting is
+the same as for raw-data compression). The buffer you pass must be large
+enough to hold the actual data plus padding to DCT-block boundaries. As with
+compression, any entirely dummy DCT blocks are not processed so you need not
+allocate space for them, but the total scanline count includes them. The
+above example of computing buffer dimensions for raw-data compression is
+equally valid for decompression.
+
+Input suspension is supported with raw-data decompression: if the data source
+module suspends, jpeg_read_raw_data() will return 0. You can also use
+buffered-image mode to read raw data in multiple passes.
+
+
+Really raw data: DCT coefficients
+---------------------------------
+
+It is possible to read or write the contents of a JPEG file as raw DCT
+coefficients. This facility is mainly intended for use in lossless
+transcoding between different JPEG file formats. Other possible applications
+include lossless cropping of a JPEG image, lossless reassembly of a
+multi-strip or multi-tile TIFF/JPEG file into a single JPEG datastream, etc.
+
+To read the contents of a JPEG file as DCT coefficients, open the file and do
+jpeg_read_header() as usual. But instead of calling jpeg_start_decompress()
+and jpeg_read_scanlines(), call jpeg_read_coefficients(). This will read the
+entire image into a set of virtual coefficient-block arrays, one array per
+component. The return value is a pointer to an array of virtual-array
+descriptors. Each virtual array can be accessed directly using the JPEG
+memory manager's access_virt_barray method (see Memory management, below,
+and also read structure.txt's discussion of virtual array handling). Or,
+for simple transcoding to a different JPEG file format, the array list can
+just be handed directly to jpeg_write_coefficients().
+
+Each block in the block arrays contains quantized coefficient values in
+normal array order (not JPEG zigzag order). The block arrays contain only
+DCT blocks containing real data; any entirely-dummy blocks added to fill out
+interleaved MCUs at the right or bottom edges of the image are discarded
+during reading and are not stored in the block arrays. (The size of each
+block array can be determined from the width_in_blocks and height_in_blocks
+fields of the component's comp_info entry.) This is also the data format
+expected by jpeg_write_coefficients().
+
+When you are done using the virtual arrays, call jpeg_finish_decompress()
+to release the array storage and return the decompression object to an idle
+state; or just call jpeg_destroy() if you don't need to reuse the object.
+
+If you use a suspending data source, jpeg_read_coefficients() will return
+NULL if it is forced to suspend; a non-NULL return value indicates successful
+completion. You need not test for a NULL return value when using a
+non-suspending data source.
+
+It is also possible to call jpeg_read_coefficients() to obtain access to the
+decoder's coefficient arrays during a normal decode cycle in buffered-image
+mode. This frammish might be useful for progressively displaying an incoming
+image and then re-encoding it without loss. To do this, decode in buffered-
+image mode as discussed previously, then call jpeg_read_coefficients() after
+the last jpeg_finish_output() call. The arrays will be available for your use
+until you call jpeg_finish_decompress().
+
+
+To write the contents of a JPEG file as DCT coefficients, you must provide
+the DCT coefficients stored in virtual block arrays. You can either pass
+block arrays read from an input JPEG file by jpeg_read_coefficients(), or
+allocate virtual arrays from the JPEG compression object and fill them
+yourself. In either case, jpeg_write_coefficients() is substituted for
+jpeg_start_compress() and jpeg_write_scanlines(). Thus the sequence is
+ * Create compression object
+ * Set all compression parameters as necessary
+ * Request virtual arrays if needed
+ * jpeg_write_coefficients()
+ * jpeg_finish_compress()
+ * Destroy or re-use compression object
+jpeg_write_coefficients() is passed a pointer to an array of virtual block
+array descriptors; the number of arrays is equal to cinfo.num_components.
+
+The virtual arrays need only have been requested, not realized, before
+jpeg_write_coefficients() is called. A side-effect of
+jpeg_write_coefficients() is to realize any virtual arrays that have been
+requested from the compression object's memory manager. Thus, when obtaining
+the virtual arrays from the compression object, you should fill the arrays
+after calling jpeg_write_coefficients(). The data is actually written out
+when you call jpeg_finish_compress(); jpeg_write_coefficients() only writes
+the file header.
+
+When writing raw DCT coefficients, it is crucial that the JPEG quantization
+tables and sampling factors match the way the data was encoded, or the
+resulting file will be invalid. For transcoding from an existing JPEG file,
+we recommend using jpeg_copy_critical_parameters(). This routine initializes
+all the compression parameters to default values (like jpeg_set_defaults()),
+then copies the critical information from a source decompression object.
+The decompression object should have just been used to read the entire
+JPEG input file --- that is, it should be awaiting jpeg_finish_decompress().
+
+jpeg_write_coefficients() marks all tables stored in the compression object
+as needing to be written to the output file (thus, it acts like
+jpeg_start_compress(cinfo, TRUE)). This is for safety's sake, to avoid
+emitting abbreviated JPEG files by accident. If you really want to emit an
+abbreviated JPEG file, call jpeg_suppress_tables(), or set the tables'
+individual sent_table flags, between calling jpeg_write_coefficients() and
+jpeg_finish_compress().
+
+
+Progress monitoring
+-------------------
+
+Some applications may need to regain control from the JPEG library every so
+often. The typical use of this feature is to produce a percent-done bar or
+other progress display. (For a simple example, see cjpeg.c or djpeg.c.)
+Although you do get control back frequently during the data-transferring pass
+(the jpeg_read_scanlines or jpeg_write_scanlines loop), any additional passes
+will occur inside jpeg_finish_compress or jpeg_start_decompress; those
+routines may take a long time to execute, and you don't get control back
+until they are done.
+
+You can define a progress-monitor routine which will be called periodically
+by the library. No guarantees are made about how often this call will occur,
+so we don't recommend you use it for mouse tracking or anything like that.
+At present, a call will occur once per MCU row, scanline, or sample row
+group, whichever unit is convenient for the current processing mode; so the
+wider the image, the longer the time between calls. During the data
+transferring pass, only one call occurs per call of jpeg_read_scanlines or
+jpeg_write_scanlines, so don't pass a large number of scanlines at once if
+you want fine resolution in the progress count. (If you really need to use
+the callback mechanism for time-critical tasks like mouse tracking, you could
+insert additional calls inside some of the library's inner loops.)
+
+To establish a progress-monitor callback, create a struct jpeg_progress_mgr,
+fill in its progress_monitor field with a pointer to your callback routine,
+and set cinfo->progress to point to the struct. The callback will be called
+whenever cinfo->progress is non-NULL. (This pointer is set to NULL by
+jpeg_create_compress or jpeg_create_decompress; the library will not change
+it thereafter. So if you allocate dynamic storage for the progress struct,
+make sure it will live as long as the JPEG object does. Allocating from the
+JPEG memory manager with lifetime JPOOL_PERMANENT will work nicely.) You
+can use the same callback routine for both compression and decompression.
+
+The jpeg_progress_mgr struct contains four fields which are set by the library:
+ long pass_counter; /* work units completed in this pass */
+ long pass_limit; /* total number of work units in this pass */
+ int completed_passes; /* passes completed so far */
+ int total_passes; /* total number of passes expected */
+During any one pass, pass_counter increases from 0 up to (not including)
+pass_limit; the step size is usually but not necessarily 1. The pass_limit
+value may change from one pass to another. The expected total number of
+passes is in total_passes, and the number of passes already completed is in
+completed_passes. Thus the fraction of work completed may be estimated as
+ completed_passes + (pass_counter/pass_limit)
+ --------------------------------------------
+ total_passes
+ignoring the fact that the passes may not be equal amounts of work.
+
+When decompressing, pass_limit can even change within a pass, because it
+depends on the number of scans in the JPEG file, which isn't always known in
+advance. The computed fraction-of-work-done may jump suddenly (if the library
+discovers it has overestimated the number of scans) or even decrease (in the
+opposite case). It is not wise to put great faith in the work estimate.
+
+When using the decompressor's buffered-image mode, the progress monitor work
+estimate is likely to be completely unhelpful, because the library has no way
+to know how many output passes will be demanded of it. Currently, the library
+sets total_passes based on the assumption that there will be one more output
+pass if the input file end hasn't yet been read (jpeg_input_complete() isn't
+TRUE), but no more output passes if the file end has been reached when the
+output pass is started. This means that total_passes will rise as additional
+output passes are requested. If you have a way of determining the input file
+size, estimating progress based on the fraction of the file that's been read
+will probably be more useful than using the library's value.
+
+
+Memory management
+-----------------
+
+This section covers some key facts about the JPEG library's built-in memory
+manager. For more info, please read structure.txt's section about the memory
+manager, and consult the source code if necessary.
+
+All memory and temporary file allocation within the library is done via the
+memory manager. If necessary, you can replace the "back end" of the memory
+manager to control allocation yourself (for example, if you don't want the
+library to use malloc() and free() for some reason).
+
+Some data is allocated "permanently" and will not be freed until the JPEG
+object is destroyed. Most data is allocated "per image" and is freed by
+jpeg_finish_compress, jpeg_finish_decompress, or jpeg_abort. You can call the
+memory manager yourself to allocate structures that will automatically be
+freed at these times. Typical code for this is
+ ptr = (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, size);
+Use JPOOL_PERMANENT to get storage that lasts as long as the JPEG object.
+Use alloc_large instead of alloc_small for anything bigger than a few Kbytes.
+There are also alloc_sarray and alloc_barray routines that automatically
+build 2-D sample or block arrays.
+
+The library's minimum space requirements to process an image depend on the
+image's width, but not on its height, because the library ordinarily works
+with "strip" buffers that are as wide as the image but just a few rows high.
+Some operating modes (eg, two-pass color quantization) require full-image
+buffers. Such buffers are treated as "virtual arrays": only the current strip
+need be in memory, and the rest can be swapped out to a temporary file.
+
+If you use the simplest memory manager back end (jmemnobs.c), then no
+temporary files are used; virtual arrays are simply malloc()'d. Images bigger
+than memory can be processed only if your system supports virtual memory.
+The other memory manager back ends support temporary files of various flavors
+and thus work in machines without virtual memory. They may also be useful on
+Unix machines if you need to process images that exceed available swap space.
+
+When using temporary files, the library will make the in-memory buffers for
+its virtual arrays just big enough to stay within a "maximum memory" setting.
+Your application can set this limit by setting cinfo->mem->max_memory_to_use
+after creating the JPEG object. (Of course, there is still a minimum size for
+the buffers, so the max-memory setting is effective only if it is bigger than
+the minimum space needed.) If you allocate any large structures yourself, you
+must allocate them before jpeg_start_compress() or jpeg_start_decompress() in
+order to have them counted against the max memory limit. Also keep in mind
+that space allocated with alloc_small() is ignored, on the assumption that
+it's too small to be worth worrying about; so a reasonable safety margin
+should be left when setting max_memory_to_use.
+
+If you use the jmemname.c or jmemdos.c memory manager back end, it is
+important to clean up the JPEG object properly to ensure that the temporary
+files get deleted. (This is especially crucial with jmemdos.c, where the
+"temporary files" may be extended-memory segments; if they are not freed,
+DOS will require a reboot to recover the memory.) Thus, with these memory
+managers, it's a good idea to provide a signal handler that will trap any
+early exit from your program. The handler should call either jpeg_abort()
+or jpeg_destroy() for any active JPEG objects. A handler is not needed with
+jmemnobs.c, and shouldn't be necessary with jmemansi.c or jmemmac.c either,
+since the C library is supposed to take care of deleting files made with
+tmpfile().
+
+
+Memory usage
+------------
+
+Working memory requirements while performing compression or decompression
+depend on image dimensions, image characteristics (such as colorspace and
+JPEG process), and operating mode (application-selected options).
+
+As of v6b, the decompressor requires:
+ 1. About 24K in more-or-less-fixed-size data. This varies a bit depending
+ on operating mode and image characteristics (particularly color vs.
+ grayscale), but it doesn't depend on image dimensions.
+ 2. Strip buffers (of size proportional to the image width) for IDCT and
+ upsampling results. The worst case for commonly used sampling factors
+ is about 34 bytes * width in pixels for a color image. A grayscale image
+ only needs about 8 bytes per pixel column.
+ 3. A full-image DCT coefficient buffer is needed to decode a multi-scan JPEG
+ file (including progressive JPEGs), or whenever you select buffered-image
+ mode. This takes 2 bytes/coefficient. At typical 2x2 sampling, that's
+ 3 bytes per pixel for a color image. Worst case (1x1 sampling) requires
+ 6 bytes/pixel. For grayscale, figure 2 bytes/pixel.
+ 4. To perform 2-pass color quantization, the decompressor also needs a
+ 128K color lookup table and a full-image pixel buffer (3 bytes/pixel).
+This does not count any memory allocated by the application, such as a
+buffer to hold the final output image.
+
+The above figures are valid for 8-bit JPEG data precision and a machine with
+32-bit ints. For 12-bit JPEG data, double the size of the strip buffers and
+quantization pixel buffer. The "fixed-size" data will be somewhat smaller
+with 16-bit ints, larger with 64-bit ints. Also, CMYK or other unusual
+color spaces will require different amounts of space.
+
+The full-image coefficient and pixel buffers, if needed at all, do not
+have to be fully RAM resident; you can have the library use temporary
+files instead when the total memory usage would exceed a limit you set.
+(But if your OS supports virtual memory, it's probably better to just use
+jmemnobs and let the OS do the swapping.)
+
+The compressor's memory requirements are similar, except that it has no need
+for color quantization. Also, it needs a full-image DCT coefficient buffer
+if Huffman-table optimization is asked for, even if progressive mode is not
+requested.
+
+If you need more detailed information about memory usage in a particular
+situation, you can enable the MEM_STATS code in jmemmgr.c.
+
+
+Library compile-time options
+----------------------------
+
+A number of compile-time options are available by modifying jmorecfg.h.
+
+The JPEG standard provides for both the baseline 8-bit DCT process and
+a 12-bit DCT process. The IJG code supports 12-bit JPEG if you define
+BITS_IN_JSAMPLE as 12 rather than 8. Note that this causes JSAMPLE to be
+larger than a char, so it affects the surrounding application's image data.
+The sample applications cjpeg and djpeg can support 12-bit mode only for PPM
+and GIF file formats; you must disable the other file formats to compile a
+12-bit cjpeg or djpeg. (install.txt has more information about that.)
+At present, a 12-bit library can handle *only* 12-bit images, not both
+precisions. (If you need to include both 8- and 12-bit libraries in a single
+application, you could probably do it by defining NEED_SHORT_EXTERNAL_NAMES
+for just one of the copies. You'd have to access the 8-bit and 12-bit copies
+from separate application source files. This is untested ... if you try it,
+we'd like to hear whether it works!)
+
+Note that a 12-bit library always compresses in Huffman optimization mode,
+in order to generate valid Huffman tables. This is necessary because our
+default Huffman tables only cover 8-bit data. If you need to output 12-bit
+files in one pass, you'll have to supply suitable default Huffman tables.
+You may also want to supply your own DCT quantization tables; the existing
+quality-scaling code has been developed for 8-bit use, and probably doesn't
+generate especially good tables for 12-bit.
+
+The maximum number of components (color channels) in the image is determined
+by MAX_COMPONENTS. The JPEG standard allows up to 255 components, but we
+expect that few applications will need more than four or so.
+
+On machines with unusual data type sizes, you may be able to improve
+performance or reduce memory space by tweaking the various typedefs in
+jmorecfg.h. In particular, on some RISC CPUs, access to arrays of "short"s
+is quite slow; consider trading memory for speed by making JCOEF, INT16, and
+UINT16 be "int" or "unsigned int". UINT8 is also a candidate to become int.
+You probably don't want to make JSAMPLE be int unless you have lots of memory
+to burn.
+
+You can reduce the size of the library by compiling out various optional
+functions. To do this, undefine xxx_SUPPORTED symbols as necessary.
+
+You can also save a few K by not having text error messages in the library;
+the standard error message table occupies about 5Kb. This is particularly
+reasonable for embedded applications where there's no good way to display
+a message anyway. To do this, remove the creation of the message table
+(jpeg_std_message_table[]) from jerror.c, and alter format_message to do
+something reasonable without it. You could output the numeric value of the
+message code number, for example. If you do this, you can also save a couple
+more K by modifying the TRACEMSn() macros in jerror.h to expand to nothing;
+you don't need trace capability anyway, right?
+
+
+Portability considerations
+--------------------------
+
+The JPEG library has been written to be extremely portable; the sample
+applications cjpeg and djpeg are slightly less so. This section summarizes
+the design goals in this area. (If you encounter any bugs that cause the
+library to be less portable than is claimed here, we'd appreciate hearing
+about them.)
+
+The code works fine on ANSI C, C++, and pre-ANSI C compilers, using any of
+the popular system include file setups, and some not-so-popular ones too.
+See install.txt for configuration procedures.
+
+The code is not dependent on the exact sizes of the C data types. As
+distributed, we make the assumptions that
+ char is at least 8 bits wide
+ short is at least 16 bits wide
+ int is at least 16 bits wide
+ long is at least 32 bits wide
+(These are the minimum requirements of the ANSI C standard.) Wider types will
+work fine, although memory may be used inefficiently if char is much larger
+than 8 bits or short is much bigger than 16 bits. The code should work
+equally well with 16- or 32-bit ints.
+
+In a system where these assumptions are not met, you may be able to make the
+code work by modifying the typedefs in jmorecfg.h. However, you will probably
+have difficulty if int is less than 16 bits wide, since references to plain
+int abound in the code.
+
+char can be either signed or unsigned, although the code runs faster if an
+unsigned char type is available. If char is wider than 8 bits, you will need
+to redefine JOCTET and/or provide custom data source/destination managers so
+that JOCTET represents exactly 8 bits of data on external storage.
+
+The JPEG library proper does not assume ASCII representation of characters.
+But some of the image file I/O modules in cjpeg/djpeg do have ASCII
+dependencies in file-header manipulation; so does cjpeg's select_file_type()
+routine.
+
+The JPEG library does not rely heavily on the C library. In particular, C
+stdio is used only by the data source/destination modules and the error
+handler, all of which are application-replaceable. (cjpeg/djpeg are more
+heavily dependent on stdio.) malloc and free are called only from the memory
+manager "back end" module, so you can use a different memory allocator by
+replacing that one file.
+
+The code generally assumes that C names must be unique in the first 15
+characters. However, global function names can be made unique in the
+first 6 characters by defining NEED_SHORT_EXTERNAL_NAMES.
+
+More info about porting the code may be gleaned by reading jconfig.txt,
+jmorecfg.h, and jinclude.h.
+
+
+Notes for MS-DOS implementors
+-----------------------------
+
+The IJG code is designed to work efficiently in 80x86 "small" or "medium"
+memory models (i.e., data pointers are 16 bits unless explicitly declared
+"far"; code pointers can be either size). You may be able to use small
+model to compile cjpeg or djpeg by itself, but you will probably have to use
+medium model for any larger application. This won't make much difference in
+performance. You *will* take a noticeable performance hit if you use a
+large-data memory model (perhaps 10%-25%), and you should avoid "huge" model
+if at all possible.
+
+The JPEG library typically needs 2Kb-3Kb of stack space. It will also
+malloc about 20K-30K of near heap space while executing (and lots of far
+heap, but that doesn't count in this calculation). This figure will vary
+depending on selected operating mode, and to a lesser extent on image size.
+There is also about 5Kb-6Kb of constant data which will be allocated in the
+near data segment (about 4Kb of this is the error message table).
+Thus you have perhaps 20K available for other modules' static data and near
+heap space before you need to go to a larger memory model. The C library's
+static data will account for several K of this, but that still leaves a good
+deal for your needs. (If you are tight on space, you could reduce the sizes
+of the I/O buffers allocated by jdatasrc.c and jdatadst.c, say from 4K to
+1K. Another possibility is to move the error message table to far memory;
+this should be doable with only localized hacking on jerror.c.)
+
+About 2K of the near heap space is "permanent" memory that will not be
+released until you destroy the JPEG object. This is only an issue if you
+save a JPEG object between compression or decompression operations.
+
+Far data space may also be a tight resource when you are dealing with large
+images. The most memory-intensive case is decompression with two-pass color
+quantization, or single-pass quantization to an externally supplied color
+map. This requires a 128Kb color lookup table plus strip buffers amounting
+to about 40 bytes per column for typical sampling ratios (eg, about 25600
+bytes for a 640-pixel-wide image). You may not be able to process wide
+images if you have large data structures of your own.
+
+Of course, all of these concerns vanish if you use a 32-bit flat-memory-model
+compiler, such as DJGPP or Watcom C. We highly recommend flat model if you
+can use it; the JPEG library is significantly faster in flat model.
diff --git a/jpg/ltmain.sh b/jpg/ltmain.sh
new file mode 100644
index 0000000..63ae69d
--- /dev/null
+++ b/jpg/ltmain.sh
@@ -0,0 +1,9655 @@
+
+# libtool (GNU libtool) 2.4.2
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+# --config show all configuration variables
+# --debug enable verbose shell tracing
+# -n, --dry-run display commands without modifying any files
+# --features display basic configuration information and exit
+# --mode=MODE use operation mode MODE
+# --preserve-dup-deps don't remove duplicate dependency libraries
+# --quiet, --silent don't print informational messages
+# --no-quiet, --no-silent
+# print informational messages (default)
+# --no-warn don't display warning messages
+# --tag=TAG use configuration variables from tag TAG
+# -v, --verbose print more informational messages than default
+# --no-verbose don't print the extra informational messages
+# --version print version information
+# -h, --help, --help-all print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+# clean remove files from the build directory
+# compile compile a source file into a libtool object
+# execute automatically set library path, then run a program
+# finish complete the installation of libtool libraries
+# install install libraries or executables
+# link create a library or an executable
+# uninstall remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE. When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+# host-triplet: $host
+# shell: $SHELL
+# compiler: $LTCC
+# compiler flags: $LTCFLAGS
+# linker: $LD (gnu? $with_gnu_ld)
+# $progname: (GNU libtool) 2.4.2
+# automake: $automake_version
+# autoconf: $autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+# General help using GNU software: <http://www.gnu.org/gethelp/>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.4.2
+TIMESTAMP=""
+package_revision=1.3337
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test \"\${$lt_var+set}\" = set; then
+ save_$lt_var=\$$lt_var
+ $lt_var=C
+ export $lt_var
+ lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+ lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+ fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" $lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+} # func_dirname may be replaced by extended shell implementation
+
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+} # func_basename may be replaced by extended shell implementation
+
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+ func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+} # func_dirname_and_basename may be replaced by extended shell implementation
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+} # func_stripname may be replaced by extended shell implementation
+
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+ s@/\./@/@g
+ t dotsl
+ s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+# value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+ # Start from root dir and reassemble the path.
+ func_normal_abspath_result=
+ func_normal_abspath_tpath=$1
+ func_normal_abspath_altnamespace=
+ case $func_normal_abspath_tpath in
+ "")
+ # Empty path, that just means $cwd.
+ func_stripname '' '/' "`pwd`"
+ func_normal_abspath_result=$func_stripname_result
+ return
+ ;;
+ # The next three entries are used to spot a run of precisely
+ # two leading slashes without using negated character classes;
+ # we take advantage of case's first-match behaviour.
+ ///*)
+ # Unusual form of absolute path, do nothing.
+ ;;
+ //*)
+ # Not necessarily an ordinary path; POSIX reserves leading '//'
+ # and for example Cygwin uses it to access remote file shares
+ # over CIFS/SMB, so we conserve a leading double slash if found.
+ func_normal_abspath_altnamespace=/
+ ;;
+ /*)
+ # Absolute path, do nothing.
+ ;;
+ *)
+ # Relative path, prepend $cwd.
+ func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+ ;;
+ esac
+ # Cancel out all the simple stuff to save iterations. We also want
+ # the path to end with a slash for ease of parsing, so make sure
+ # there is one (and only one) here.
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+ while :; do
+ # Processed it all yet?
+ if test "$func_normal_abspath_tpath" = / ; then
+ # If we ascended to the root using ".." the result may be empty now.
+ if test -z "$func_normal_abspath_result" ; then
+ func_normal_abspath_result=/
+ fi
+ break
+ fi
+ func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$pathcar"`
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$pathcdr"`
+ # Figure out what to do with it
+ case $func_normal_abspath_tcomponent in
+ "")
+ # Trailing empty path component, ignore it.
+ ;;
+ ..)
+ # Parent dir; strip last assembled component from result.
+ func_dirname "$func_normal_abspath_result"
+ func_normal_abspath_result=$func_dirname_result
+ ;;
+ *)
+ # Actual path component, append it.
+ func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+ ;;
+ esac
+ done
+ # Restore leading double-slash if one was found on entry.
+ func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+# value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+ func_relative_path_result=
+ func_normal_abspath "$1"
+ func_relative_path_tlibdir=$func_normal_abspath_result
+ func_normal_abspath "$2"
+ func_relative_path_tbindir=$func_normal_abspath_result
+
+ # Ascend the tree starting from libdir
+ while :; do
+ # check if we have found a prefix of bindir
+ case $func_relative_path_tbindir in
+ $func_relative_path_tlibdir)
+ # found an exact match
+ func_relative_path_tcancelled=
+ break
+ ;;
+ $func_relative_path_tlibdir*)
+ # found a matching prefix
+ func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+ func_relative_path_tcancelled=$func_stripname_result
+ if test -z "$func_relative_path_result"; then
+ func_relative_path_result=.
+ fi
+ break
+ ;;
+ *)
+ func_dirname $func_relative_path_tlibdir
+ func_relative_path_tlibdir=${func_dirname_result}
+ if test "x$func_relative_path_tlibdir" = x ; then
+ # Have to descend all the way to the root!
+ func_relative_path_result=../$func_relative_path_result
+ func_relative_path_tcancelled=$func_relative_path_tbindir
+ break
+ fi
+ func_relative_path_result=../$func_relative_path_result
+ ;;
+ esac
+ done
+
+ # Now calculate path; take care to avoid doubling-up slashes.
+ func_stripname '' '/' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ func_stripname '/' '/' "$func_relative_path_tcancelled"
+ if test "x$func_stripname_result" != x ; then
+ func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+ fi
+
+ # Normalisation. If bindir is libdir, return empty string,
+ # else relative path ending with a slash; either way, target
+ # file name can be directly appended.
+ if test ! -z "$func_relative_path_result"; then
+ func_stripname './' '' "$func_relative_path_result/"
+ func_relative_path_result=$func_stripname_result
+ fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+ [\\/]*|[A-Za-z]:\\*) ;;
+ *[\\/]*)
+ progdir=$func_dirname_result
+ progdir=`cd "$progdir" && pwd`
+ progpath="$progdir/$progname"
+ ;;
+ *)
+ save_IFS="$IFS"
+ IFS=${PATH_SEPARATOR-:}
+ for progdir in $PATH; do
+ IFS="$save_IFS"
+ test -x "$progdir/$progname" && break
+ done
+ IFS="$save_IFS"
+ test -n "$progdir" || progdir=`pwd`
+ progpath="$progdir/$progname"
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+
+# Sed substitution that converts a w32 file name or path
+# which contains forward slashes, into one that contains
+# (escaped) backslashes. A very naive implementation.
+lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same. If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'. `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+ s/$bs4/&\\
+/g
+ s/^$bs2$dollar/$bs&/
+ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+ s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+ $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+ $opt_verbose && func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+ $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+ $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+
+ # bash bug again:
+ :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ func_error ${1+"$@"}
+ func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information." ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+ $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+ my_directory_path="$1"
+ my_dir_list=
+
+ if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+ # Protect directory names starting with `-'
+ case $my_directory_path in
+ -*) my_directory_path="./$my_directory_path" ;;
+ esac
+
+ # While some portion of DIR does not yet exist...
+ while test ! -d "$my_directory_path"; do
+ # ...make a list in topmost first order. Use a colon delimited
+ # list incase some portion of path contains whitespace.
+ my_dir_list="$my_directory_path:$my_dir_list"
+
+ # If the last portion added has no slash in it, the list is done
+ case $my_directory_path in */*) ;; *) break ;; esac
+
+ # ...otherwise throw away the child directory and loop
+ my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+ done
+ my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+ save_mkdir_p_IFS="$IFS"; IFS=':'
+ for my_dir in $my_dir_list; do
+ IFS="$save_mkdir_p_IFS"
+ # mkdir can fail with a `File exist' error if two processes
+ # try to create one of the directories concurrently. Don't
+ # stop in that case!
+ $MKDIR "$my_dir" 2>/dev/null || :
+ done
+ IFS="$save_mkdir_p_IFS"
+
+ # Bail out if we (or some other process) failed to create a directory.
+ test -d "$my_directory_path" || \
+ func_fatal_error "Failed to create \`$1'"
+ fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+ my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+ if test "$opt_dry_run" = ":"; then
+ # Return a directory name, but don't create it in dry-run mode
+ my_tmpdir="${my_template}-$$"
+ else
+
+ # If mktemp works, use that first and foremost
+ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$my_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+ save_mktempdir_umask=`umask`
+ umask 0077
+ $MKDIR "$my_tmpdir"
+ umask $save_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$my_tmpdir" || \
+ func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+ fi
+
+ $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+ case $1 in
+ *[\\\`\"\$]*)
+ func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+ *)
+ func_quote_for_eval_unquoted_result="$1" ;;
+ esac
+
+ case $func_quote_for_eval_unquoted_result in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and and variable
+ # expansion for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+ ;;
+ *)
+ func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+ esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+ case $1 in
+ *[\\\`\"]*)
+ my_arg=`$ECHO "$1" | $SED \
+ -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+ *)
+ my_arg="$1" ;;
+ esac
+
+ case $my_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting and command substitution for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ my_arg="\"$my_arg\""
+ ;;
+ esac
+
+ func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$my_cmd"
+ my_status=$?
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it. Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$lt_user_locale
+ $my_cmd"
+ my_status=$?
+ eval "$lt_safe_locale"
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result. All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+ case $1 in
+ [0-9]* | *[!a-zA-Z0-9_]*)
+ func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+ ;;
+ * )
+ func_tr_sh_result=$1
+ ;;
+ esac
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $opt_debug
+
+ $SED -n '/(C)/!b go
+ :more
+ /\./!{
+ N
+ s/\n# / /
+ b more
+ }
+ :go
+ /^# '$PROGRAM' (GNU /,/# warranty; / {
+ s/^# //
+ s/^# *$//
+ s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+ p
+ }' < "$progpath"
+ exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+ $opt_debug
+
+ $SED -n '/^# Usage:/,/^# *.*--help/ {
+ s/^# //
+ s/^# *$//
+ s/\$progname/'$progname'/
+ p
+ }' < "$progpath"
+ echo
+ $ECHO "run \`$progname --help | more' for full usage"
+ exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+ $opt_debug
+
+ $SED -n '/^# Usage:/,/# Report bugs to/ {
+ :print
+ s/^# //
+ s/^# *$//
+ s*\$progname*'$progname'*
+ s*\$host*'"$host"'*
+ s*\$SHELL*'"$SHELL"'*
+ s*\$LTCC*'"$LTCC"'*
+ s*\$LTCFLAGS*'"$LTCFLAGS"'*
+ s*\$LD*'"$LD"'*
+ s/\$with_gnu_ld/'"$with_gnu_ld"'/
+ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
+ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
+ p
+ d
+ }
+ /^# .* home page:/b print
+ /^# General help using/b print
+ ' < "$progpath"
+ ret=$?
+ if test -z "$1"; then
+ exit $ret
+ fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+ $opt_debug
+
+ func_error "missing argument for $1."
+ exit_cmd=exit
+}
+
+
+# func_split_short_opt shortopt
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+func_split_short_opt ()
+{
+ my_sed_short_opt='1s/^\(..\).*$/\1/;q'
+ my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+
+ func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
+ func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
+} # func_split_short_opt may be replaced by extended shell implementation
+
+
+# func_split_long_opt longopt
+# Set func_split_long_opt_name and func_split_long_opt_arg shell
+# variables after splitting LONGOPT at the `=' sign.
+func_split_long_opt ()
+{
+ my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
+ my_sed_long_arg='1s/^--[^=]*=//'
+
+ func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
+ func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
+} # func_split_long_opt may be replaced by extended shell implementation
+
+exit_cmd=:
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+nonopt=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "${1}=\$${1}\${2}"
+} # func_append may be replaced by extended shell implementation
+
+# func_append_quoted var value
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+func_append_quoted ()
+{
+ func_quote_for_eval "${2}"
+ eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
+} # func_append_quoted may be replaced by extended shell implementation
+
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "${@}"`
+} # func_arith may be replaced by extended shell implementation
+
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
+} # func_len may be replaced by extended shell implementation
+
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+} # func_lo2o may be replaced by extended shell implementation
+
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+} # func_xform may be replaced by extended shell implementation
+
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+ func_error ${1+"$@"}
+ func_error "See the $PACKAGE documentation for more information."
+ func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+ re_begincf='^# ### BEGIN LIBTOOL'
+ re_endcf='^# ### END LIBTOOL'
+
+ # Default configuration.
+ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+ done
+
+ exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+ echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+
+ exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+ # Global variable:
+ tagname="$1"
+
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
+
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
+ *)
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+ fi
+
+ exit $EXIT_MISMATCH
+ fi
+}
+
+
+# Shorthand for --mode=foo, only valid as the first argument
+case $1 in
+clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+esac
+
+
+
+# Option defaults:
+opt_debug=:
+opt_dry_run=false
+opt_config=false
+opt_preserve_dup_deps=false
+opt_features=false
+opt_finish=false
+opt_help=false
+opt_help_all=false
+opt_silent=:
+opt_warning=:
+opt_verbose=:
+opt_silent=false
+opt_verbose=false
+
+
+# Parse options once, thoroughly. This comes as soon as possible in the
+# script to make things like `--version' happen as quickly as we can.
+{
+ # this just eases exit handling
+ while test $# -gt 0; do
+ opt="$1"
+ shift
+ case $opt in
+ --debug|-x) opt_debug='set -x'
+ func_echo "enabling shell trace mode"
+ $opt_debug
+ ;;
+ --dry-run|--dryrun|-n)
+ opt_dry_run=:
+ ;;
+ --config)
+ opt_config=:
+func_config
+ ;;
+ --dlopen|-dlopen)
+ optarg="$1"
+ opt_dlopen="${opt_dlopen+$opt_dlopen
+}$optarg"
+ shift
+ ;;
+ --preserve-dup-deps)
+ opt_preserve_dup_deps=:
+ ;;
+ --features)
+ opt_features=:
+func_features
+ ;;
+ --finish)
+ opt_finish=:
+set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ --help)
+ opt_help=:
+ ;;
+ --help-all)
+ opt_help_all=:
+opt_help=': help-all'
+ ;;
+ --mode)
+ test $# = 0 && func_missing_arg $opt && break
+ optarg="$1"
+ opt_mode="$optarg"
+case $optarg in
+ # Valid mode arguments:
+ clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $opt"
+ exit_cmd=exit
+ break
+ ;;
+esac
+ shift
+ ;;
+ --no-silent|--no-quiet)
+ opt_silent=false
+func_append preserve_args " $opt"
+ ;;
+ --no-warning|--no-warn)
+ opt_warning=false
+func_append preserve_args " $opt"
+ ;;
+ --no-verbose)
+ opt_verbose=false
+func_append preserve_args " $opt"
+ ;;
+ --silent|--quiet)
+ opt_silent=:
+func_append preserve_args " $opt"
+ opt_verbose=false
+ ;;
+ --verbose|-v)
+ opt_verbose=:
+func_append preserve_args " $opt"
+opt_silent=false
+ ;;
+ --tag)
+ test $# = 0 && func_missing_arg $opt && break
+ optarg="$1"
+ opt_tag="$optarg"
+func_append preserve_args " $opt $optarg"
+func_enable_tag "$optarg"
+ shift
+ ;;
+
+ -\?|-h) func_usage ;;
+ --help) func_help ;;
+ --version) func_version ;;
+
+ # Separate optargs to long options:
+ --*=*)
+ func_split_long_opt "$opt"
+ set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate non-argument short options:
+ -\?*|-h*|-n*|-v*)
+ func_split_short_opt "$opt"
+ set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ --) break ;;
+ -*) func_fatal_help "unrecognized option \`$opt'" ;;
+ *) set dummy "$opt" ${1+"$@"}; shift; break ;;
+ esac
+ done
+
+ # Validate options:
+
+ # save first non-option argument
+ if test "$#" -gt 0; then
+ nonopt="$opt"
+ shift
+ fi
+
+ # preserve --debug
+ test "$opt_debug" = : || func_append preserve_args " --debug"
+
+ case $host in
+ *cygwin* | *mingw* | *pw32* | *cegcc*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+ ;;
+ esac
+
+ $opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+
+ if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ func_fatal_configuration "not configured to build any kind of library"
+ fi
+
+ # Darwin sucks
+ eval std_shrext=\"$shrext_cmds\"
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
+ func_error "unrecognized option \`-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$progname --help --mode=$opt_mode' for more information."
+ }
+
+
+ # Bail if the options were screwed
+ $exit_cmd $EXIT_FAILURE
+}
+
+
+
+
+## ----------- ##
+## Main. ##
+## ----------- ##
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+ test -f "$1" &&
+ $SED -e 4q "$1" 2>/dev/null \
+ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs. To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway. Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+ lalib_p=no
+ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+ for lalib_p_l in 1 2 3 4
+ do
+ read lalib_p_line
+ case "$lalib_p_line" in
+ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+ esac
+ done
+ exec 0<&5 5<&-
+ fi
+ test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+ func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+ func_ltwrapper_exec_suffix=
+ case $1 in
+ *.exe) ;;
+ *) func_ltwrapper_exec_suffix=.exe ;;
+ esac
+ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+ func_dirname_and_basename "$1" "" "."
+ func_stripname '' '.exe' "$func_basename_result"
+ func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+ $opt_debug
+ save_ifs=$IFS; IFS='~'
+ for cmd in $1; do
+ IFS=$save_ifs
+ eval cmd=\"$cmd\"
+ func_show_eval "$cmd" "${2-:}"
+ done
+ IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)! Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+ $opt_debug
+ case $1 in
+ */* | *\\*) . "$1" ;;
+ *) . "./$1" ;;
+ esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot. Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+ func_resolve_sysroot_result=$1
+ case $func_resolve_sysroot_result in
+ =*)
+ func_stripname '=' '' "$func_resolve_sysroot_result"
+ func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+ ;;
+ esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+ case "$lt_sysroot:$1" in
+ ?*:"$lt_sysroot"*)
+ func_stripname "$lt_sysroot" '' "$1"
+ func_replace_sysroot_result="=$func_stripname_result"
+ ;;
+ *)
+ # Including no sysroot.
+ func_replace_sysroot_result=$1
+ ;;
+ esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ $opt_debug
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case "$@ " in
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ func_echo "unable to infer tagged configuration"
+ func_fatal_error "specify a tag with \`--tag'"
+# else
+# func_verbose "using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+ write_libobj=${1}
+ if test "$build_libtool_libs" = yes; then
+ write_lobj=\'${2}\'
+ else
+ write_lobj=none
+ fi
+
+ if test "$build_old_libs" = yes; then
+ write_oldobj=\'${3}\'
+ else
+ write_oldobj=none
+ fi
+
+ $opt_dry_run || {
+ cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+ $MV "${write_libobj}T" "${write_libobj}"
+ }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+ $opt_debug
+ func_convert_core_file_wine_to_w32_result="$1"
+ if test -n "$1"; then
+ # Unfortunately, winepath does not exit with a non-zero error code, so we
+ # are forced to check the contents of stdout. On the other hand, if the
+ # command is not found, the shell will set an exit code of 127 and print
+ # *an error message* to stdout. So we must check for both error code of
+ # zero AND non-empty stdout, which explains the odd construction:
+ func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+ if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+ func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+ $SED -e "$lt_sed_naive_backslashify"`
+ else
+ func_convert_core_file_wine_to_w32_result=
+ fi
+ fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+ $opt_debug
+ # unfortunately, winepath doesn't convert paths, only file names
+ func_convert_core_path_wine_to_w32_result=""
+ if test -n "$1"; then
+ oldIFS=$IFS
+ IFS=:
+ for func_convert_core_path_wine_to_w32_f in $1; do
+ IFS=$oldIFS
+ func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+ if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+ if test -z "$func_convert_core_path_wine_to_w32_result"; then
+ func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+ else
+ func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+ fi
+ fi
+ done
+ IFS=$oldIFS
+ fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+ $opt_debug
+ if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+ func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+ if test "$?" -ne 0; then
+ # on failure, ensure result is empty
+ func_cygpath_result=
+ fi
+ else
+ func_cygpath_result=
+ func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+ fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format. Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+ $opt_debug
+ # awkward: cmd appends spaces to result
+ func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+ $opt_debug
+ if test -z "$2" && test -n "$1" ; then
+ func_error "Could not determine host file name corresponding to"
+ func_error " \`$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback:
+ func_to_host_file_result="$1"
+ fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+ $opt_debug
+ if test -z "$4" && test -n "$3"; then
+ func_error "Could not determine the host path corresponding to"
+ func_error " \`$3'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback. This is a deliberately simplistic "conversion" and
+ # should not be "improved". See libtool.info.
+ if test "x$1" != "x$2"; then
+ lt_replace_pathsep_chars="s|$1|$2|g"
+ func_to_host_path_result=`echo "$3" |
+ $SED -e "$lt_replace_pathsep_chars"`
+ else
+ func_to_host_path_result="$3"
+ fi
+ fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+ $opt_debug
+ case $4 in
+ $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+ ;;
+ esac
+ case $4 in
+ $2 ) func_append func_to_host_path_result "$3"
+ ;;
+ esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via `$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+ $opt_debug
+ $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result. If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+ $opt_debug
+ case ,$2, in
+ *,"$to_tool_file_cmd",*)
+ func_to_tool_file_result=$1
+ ;;
+ *)
+ $to_tool_file_cmd "$1"
+ func_to_tool_file_result=$func_to_host_file_result
+ ;;
+ esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+ func_to_host_file_result="$1"
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+ # LT_CYGPATH in this case.
+ func_to_host_file_result=`cygpath -m "$1"`
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format. Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ func_convert_core_file_wine_to_w32 "$1"
+ func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_msys_to_w32_result"
+ func_to_host_file_result="$func_cygpath_result"
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set. Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+ func_convert_core_file_wine_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+ func_to_host_file_result="$func_cygpath_result"
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format. If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+# file name conversion function : func_convert_file_X_to_Y ()
+# path conversion function : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same. If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+ $opt_debug
+ if test -z "$to_host_path_cmd"; then
+ func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+ to_host_path_cmd="func_convert_path_${func_stripname_result}"
+ fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+ $opt_debug
+ func_init_to_host_path_cmd
+ $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+ func_to_host_path_result="$1"
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from ARG. MSYS
+ # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+ # and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format. Requires a wine environment and
+# a working winepath. Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+ func_to_host_path_result="$func_cygpath_result"
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set. Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from
+ # ARG. msys behavior is inconsistent here, cygpath turns them
+ # into '.;' and ';.', and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+ func_to_host_path_result="$func_cygpath_result"
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+ $opt_debug
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+ pie_flag=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ test -n "$libobj" && \
+ func_fatal_error "you cannot specify \`-o' more than once"
+ arg_mode=target
+ continue
+ ;;
+
+ -pie | -fpie | -fPIE)
+ func_append pie_flag " $arg"
+ continue
+ ;;
+
+ -shared | -static | -prefer-pic | -prefer-non-pic)
+ func_append later " $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+ func_append_quoted lastarg "$arg"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$lastarg"
+ lastarg=$func_stripname_result
+
+ # Add the arguments to base_compile.
+ func_append base_compile " $lastarg"
+ continue
+ ;;
+
+ *)
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ func_append_quoted base_compile "$lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ func_fatal_error "you must specify an argument for -Xcompile"
+ ;;
+ target)
+ func_fatal_error "you must specify a target with \`-o'"
+ ;;
+ *)
+ # Get the name of the library object.
+ test -z "$libobj" && {
+ func_basename "$srcfile"
+ libobj="$func_basename_result"
+ }
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ case $libobj in
+ *.[cCFSifmso] | \
+ *.ada | *.adb | *.ads | *.asm | \
+ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+ func_xform "$libobj"
+ libobj=$func_xform_result
+ ;;
+ esac
+
+ case $libobj in
+ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+ *)
+ func_fatal_error "cannot determine name of library object from \`$libobj'"
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ continue
+ ;;
+
+ -static)
+ build_libtool_libs=no
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ func_quote_for_eval "$libobj"
+ test "X$libobj" != "X$func_quote_for_eval_result" \
+ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && func_warning "libobj name \`$libobj' may not contain shell special characters."
+ func_dirname_and_basename "$obj" "/" ""
+ objname="$func_basename_result"
+ xdir="$func_dirname_result"
+ lobj=${xdir}$objdir/$objname
+
+ test -z "$base_compile" && \
+ func_fatal_help "you must specify a compilation command"
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2* | cegcc*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+ func_append removelist " $output_obj"
+ $ECHO "$srcfile" > "$lockfile"
+ fi
+
+ $opt_dry_run || $RM $removelist
+ func_append removelist " $lockfile"
+ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+ func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+ srcfile=$func_to_tool_file_result
+ func_quote_for_eval "$srcfile"
+ qsrcfile=$func_quote_for_eval_result
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ func_mkdir_p "$xdir$objdir"
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ func_append command " -o $lobj"
+ fi
+
+ func_show_eval_locale "$command" \
+ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ func_show_eval '$MV "$output_obj" "$lobj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+
+ # Allow error messages only from the first compilation.
+ if test "$suppress_opt" = yes; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile$pie_flag"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ func_append command " -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ func_append command "$suppress_output"
+ func_show_eval_locale "$command" \
+ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ func_show_eval '$MV "$output_obj" "$obj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+ fi
+
+ $opt_dry_run || {
+ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ removelist=$lockfile
+ $RM "$lockfile"
+ fi
+ }
+
+ exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+ test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+ # We need to display help for each of the modes.
+ case $opt_mode in
+ "")
+ # Generic help is extracted from the usage comments
+ # at the start of this file.
+ func_help
+ ;;
+
+ clean)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ compile)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -no-suppress do not suppress compiler output for multiple passes
+ -prefer-pic try to build PIC objects only
+ -prefer-non-pic try to build non-PIC objects only
+ -shared do not build a \`.o' file suitable for static linking
+ -static only build a \`.o' file suitable for static linking
+ -Wc,FLAG pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+ execute)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+ finish)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+ install)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+ -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+ link)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -bindir BINDIR specify path to binaries directory (for systems where
+ libraries must be found in the PATH setting at runtime)
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -shared only do dynamic linking of libtool libraries
+ -shrext SUFFIX override the standard shared library file extension
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+ -weak LIBNAME declare that the target provides the LIBNAME interface
+ -Wc,FLAG
+ -Xcompiler FLAG pass linker-specific FLAG directly to the compiler
+ -Wl,FLAG
+ -Xlinker FLAG pass linker-specific FLAG directly to the linker
+ -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+ uninstall)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ *)
+ func_fatal_help "invalid operation mode \`$opt_mode'"
+ ;;
+ esac
+
+ echo
+ $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+ if test "$opt_help" = :; then
+ func_mode_help
+ else
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ func_mode_help
+ done
+ } | sed -n '1p; 2,$s/^Usage:/ or: /p'
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ echo
+ func_mode_help
+ done
+ } |
+ sed '1d
+ /^When reporting/,/^Report/{
+ H
+ d
+ }
+ $x
+ /information about other modes/d
+ /more detailed .*MODE/d
+ s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+ fi
+ exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+ $opt_debug
+ # The first argument is the command name.
+ cmd="$nonopt"
+ test -z "$cmd" && \
+ func_fatal_help "you must specify a COMMAND"
+
+ # Handle -dlopen flags immediately.
+ for file in $opt_dlopen; do
+ test -f "$file" \
+ || func_fatal_help "\`$file' is not a file"
+
+ dir=
+ case $file in
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+ func_source "$file"
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && \
+ func_warning "\`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+
+ if test -f "$dir/$objdir/$dlname"; then
+ func_append dir "/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ ;;
+
+ *)
+ func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -* | *.la | *.lo ) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if func_ltwrapper_script_p "$file"; then
+ func_source "$file"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ elif func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ func_source "$func_ltwrapper_scriptname_result"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ func_append_quoted args "$file"
+ done
+
+ if test "X$opt_dry_run" = Xfalse; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ else
+ $lt_unset $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ echo "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+ $opt_debug
+ libs=
+ libdirs=
+ admincmds=
+
+ for opt in "$nonopt" ${1+"$@"}
+ do
+ if test -d "$opt"; then
+ func_append libdirs " $opt"
+
+ elif test -f "$opt"; then
+ if func_lalib_unsafe_p "$opt"; then
+ func_append libs " $opt"
+ else
+ func_warning "\`$opt' is not a valid libtool archive"
+ fi
+
+ else
+ func_fatal_error "invalid argument \`$opt'"
+ fi
+ done
+
+ if test -n "$libs"; then
+ if test -n "$lt_sysroot"; then
+ sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+ sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+ else
+ sysroot_cmd=
+ fi
+
+ # Remove sysroot references
+ if $opt_dry_run; then
+ for lib in $libs; do
+ echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+ done
+ else
+ tmpdir=`func_mktempdir`
+ for lib in $libs; do
+ sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+ > $tmpdir/tmp-la
+ mv -f $tmpdir/tmp-la $lib
+ done
+ ${RM}r "$tmpdir"
+ fi
+ fi
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $opt_dry_run || eval "$cmds" || func_append admincmds "
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ $opt_silent && exit $EXIT_SUCCESS
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $ECHO " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $ECHO " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $ECHO " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ echo
+
+ echo "See any operating system documentation about shared libraries for"
+ case $host in
+ solaris2.[6789]|solaris2.1[0-9])
+ echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+ echo "pages."
+ ;;
+ *)
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ ;;
+ esac
+ echo "----------------------------------------------------------------------"
+ fi
+ exit $EXIT_SUCCESS
+}
+
+test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+ $opt_debug
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ case $nonopt in *shtool*) :;; *) false;; esac; then
+ # Aesthetically quote it.
+ func_quote_for_eval "$nonopt"
+ install_prog="$func_quote_for_eval_result "
+ arg=$1
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ func_quote_for_eval "$arg"
+ func_append install_prog "$func_quote_for_eval_result"
+ install_shared_prog=$install_prog
+ case " $install_prog " in
+ *[\\\ /]cp\ *) install_cp=: ;;
+ *) install_cp=false ;;
+ esac
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ no_mode=:
+ for arg
+ do
+ arg2=
+ if test -n "$dest"; then
+ func_append files " $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f)
+ if $install_cp; then :; else
+ prev=$arg
+ fi
+ ;;
+ -g | -m | -o)
+ prev=$arg
+ ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ if test "x$prev" = x-m && test -n "$install_override_mode"; then
+ arg2=$install_override_mode
+ no_mode=false
+ fi
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ func_quote_for_eval "$arg"
+ func_append install_prog " $func_quote_for_eval_result"
+ if test -n "$arg2"; then
+ func_quote_for_eval "$arg2"
+ fi
+ func_append install_shared_prog " $func_quote_for_eval_result"
+ done
+
+ test -z "$install_prog" && \
+ func_fatal_help "you must specify an install program"
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prev' option requires an argument"
+
+ if test -n "$install_override_mode" && $no_mode; then
+ if $install_cp; then :; else
+ func_quote_for_eval "$install_override_mode"
+ func_append install_shared_prog " -m $func_quote_for_eval_result"
+ fi
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ func_fatal_help "no file or destination specified"
+ else
+ func_fatal_help "you must specify a destination"
+ fi
+ fi
+
+ # Strip any trailing slash from the destination.
+ func_stripname '' '/' "$dest"
+ dest=$func_stripname_result
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ func_dirname_and_basename "$dest" "" "."
+ destdir="$func_dirname_result"
+ destname="$func_basename_result"
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files; shift
+ test "$#" -gt 1 && \
+ func_fatal_help "\`$dest' is not a directory"
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ func_fatal_help "\`$destdir' must be an absolute directory name"
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ func_append staticlibs " $file"
+ ;;
+
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$file' is not a valid libtool archive"
+
+ library_names=
+ old_library=
+ relink_command=
+ func_source "$file"
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append current_libdirs " $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append future_libdirs " $libdir" ;;
+ esac
+ fi
+
+ func_dirname "$file" "/" ""
+ dir="$func_dirname_result"
+ func_append dir "$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ test "$inst_prefix_dir" = "$destdir" && \
+ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ func_warning "relinking \`$file'"
+ func_show_eval "$relink_command" \
+ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names; shift
+ if test -n "$1"; then
+ realname="$1"
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+ 'exit $?'
+ tstripme="$stripme"
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $realname in
+ *.dll.a)
+ tstripme=""
+ ;;
+ esac
+ ;;
+ esac
+ if test -n "$tstripme" && test -n "$striplib"; then
+ func_show_eval "$striplib $destdir/$realname" 'exit $?'
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try `ln -sf' first, because the `ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ test "$linkname" != "$realname" \
+ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ func_execute_cmds "$postinstall_cmds" 'exit $?'
+ fi
+
+ # Install the pseudo-library for information purposes.
+ func_basename "$file"
+ name="$func_basename_result"
+ instname="$dir/$name"i
+ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ func_lo2o "$destfile"
+ staticdest=$func_lo2o_result
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ func_fatal_help "cannot copy a libtool object to \`$destfile'"
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ test -n "$destfile" && \
+ func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ func_lo2o "$file"
+ staticobj=$func_lo2o_result
+ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin* | *mingw*)
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ wrapper=$func_ltwrapper_scriptname_result
+ else
+ func_stripname '' '.exe' "$file"
+ wrapper=$func_stripname_result
+ fi
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if func_ltwrapper_script_p "$wrapper"; then
+ notinst_deplibs=
+ relink_command=
+
+ func_source "$wrapper"
+
+ # Check the variables that should have been set.
+ test -z "$generated_by_libtool_version" && \
+ func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ func_source "$lib"
+ fi
+ libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ func_warning "\`$lib' has not been installed in \`$libdir'"
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ func_source "$wrapper"
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ $opt_dry_run || {
+ if test "$finalize" = yes; then
+ tmpdir=`func_mktempdir`
+ func_basename "$file$stripped_ext"
+ file="$func_basename_result"
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $opt_silent || {
+ func_quote_for_expand "$relink_command"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ if eval "$relink_command"; then :
+ else
+ func_error "error: relink \`$file' with the above command before installing it"
+ $opt_dry_run || ${RM}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ func_warning "cannot relink \`$file'"
+ fi
+ }
+ else
+ # Install the binary that we compiled earlier.
+ file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ func_stripname '' '.exe' "$destfile"
+ destfile=$func_stripname_result
+ ;;
+ esac
+ ;;
+ esac
+ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+ $opt_dry_run || if test -n "$outputname"; then
+ ${RM}r "$tmpdir"
+ fi
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ func_basename "$file"
+ name="$func_basename_result"
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+
+ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+ fi
+
+ # Do each command in the postinstall commands.
+ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+ done
+
+ test -n "$future_libdirs" && \
+ func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ $opt_dry_run && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$opt_mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+ $opt_debug
+ my_outputname="$1"
+ my_originator="$2"
+ my_pic_p="${3-no}"
+ my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+ my_dlsyms=
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ my_dlsyms="${my_outputname}S.c"
+ else
+ func_error "not configured to extract global symbols from dlpreopened files"
+ fi
+ fi
+
+ if test -n "$my_dlsyms"; then
+ case $my_dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${my_outputname}.nm"
+
+ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+ # Parse the name list into a source file.
+ func_verbose "creating $output_objdir/$my_dlsyms"
+
+ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ func_verbose "generating symbol list for \`$output'"
+
+ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ for progfile in $progfiles; do
+ func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+ func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+ $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $opt_dry_run || {
+ eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $opt_dry_run || {
+ eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$outputname.exp"
+ $opt_dry_run || {
+ $RM $export_symbols
+ eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ else
+ $opt_dry_run || {
+ eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ fi
+ fi
+
+ for dlprefile in $dlprefiles; do
+ func_verbose "extracting global C symbols from \`$dlprefile'"
+ func_basename "$dlprefile"
+ name="$func_basename_result"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ # if an import library, we need to obtain dlname
+ if func_win32_import_lib_p "$dlprefile"; then
+ func_tr_sh "$dlprefile"
+ eval "curr_lafile=\$libfile_$func_tr_sh_result"
+ dlprefile_dlbasename=""
+ if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+ # Use subshell, to avoid clobbering current variable values
+ dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+ if test -n "$dlprefile_dlname" ; then
+ func_basename "$dlprefile_dlname"
+ dlprefile_dlbasename="$func_basename_result"
+ else
+ # no lafile. user explicitly requested -dlpreopen <import library>.
+ $sharedlib_from_linklib_cmd "$dlprefile"
+ dlprefile_dlbasename=$sharedlib_from_linklib_result
+ fi
+ fi
+ $opt_dry_run || {
+ if test -n "$dlprefile_dlbasename" ; then
+ eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+ else
+ func_warning "Could not compute DLL name from $name"
+ eval '$ECHO ": $name " >> "$nlist"'
+ fi
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+ $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+ }
+ else # not an import lib
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ fi
+ ;;
+ *)
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ ;;
+ esac
+ done
+
+ $opt_dry_run || {
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if $GREP -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ $GREP -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+ fi
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols. */
+typedef struct {
+ const char *name;
+ void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+ { \"$my_originator\", (void *) 0 },"
+
+ case $need_lib_prefix in
+ no)
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ *)
+ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ esac
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ } # !$opt_dry_run
+
+ pic_flag_for_symtable=
+ case "$compile_command " in
+ *" -static "*) ;;
+ *)
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+ *-*-hpux*)
+ pic_flag_for_symtable=" $pic_flag" ;;
+ *)
+ if test "X$my_pic_p" != Xno; then
+ pic_flag_for_symtable=" $pic_flag"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ symtab_cflags=
+ for arg in $LTCFLAGS; do
+ case $arg in
+ -pie | -fpie | -fPIE) ;;
+ *) func_append symtab_cflags " $arg" ;;
+ esac
+ done
+
+ # Now compile the dynamic symbol file.
+ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+ # Clean up the generated files.
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+ # Transform the symbol file into the correct name.
+ symfileobj="$output_objdir/${my_outputname}S.$objext"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ if test -f "$output_objdir/$my_outputname.def"; then
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ else
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ fi
+ ;;
+ *)
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ ;;
+ esac
+ ;;
+ *)
+ func_fatal_error "unknown suffix for \`$my_dlsyms'"
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+ fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+ $opt_debug
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+ $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+ $SED -n -e '
+ 1,100{
+ / I /{
+ s,.*,import,
+ p
+ q
+ }
+ }'`
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+ $opt_debug
+ sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+ $opt_debug
+ match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+ $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+ $SED '/^Contents of section '"$match_literal"':/{
+ # Place marker at beginning of archive member dllname section
+ s/.*/====MARK====/
+ p
+ d
+ }
+ # These lines can sometimes be longer than 43 characters, but
+ # are always uninteresting
+ /:[ ]*file format pe[i]\{,1\}-/d
+ /^In archive [^:]*:/d
+ # Ensure marker is printed
+ /^====MARK====/p
+ # Remove all lines with less than 43 characters
+ /^.\{43\}/!d
+ # From remaining lines, remove first 43 characters
+ s/^.\{43\}//' |
+ $SED -n '
+ # Join marker and all lines until next marker into a single line
+ /^====MARK====/ b para
+ H
+ $ b para
+ b
+ :para
+ x
+ s/\n//g
+ # Remove the marker
+ s/^====MARK====//
+ # Remove trailing dots and whitespace
+ s/[\. \t]*$//
+ # Print
+ /./p' |
+ # we now have a list, one entry per line, of the stringified
+ # contents of the appropriate section of all members of the
+ # archive which possess that section. Heuristic: eliminate
+ # all those which have a first or second character that is
+ # a '.' (that is, objdump's representation of an unprintable
+ # character.) This should work for all archives with less than
+ # 0x302f exports -- but will fail for DLLs whose name actually
+ # begins with a literal '.' or a single character followed by
+ # a '.'.
+ #
+ # Of those that remain, print the first one.
+ $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+ $opt_debug
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+ test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+ $opt_debug
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+ test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+ $opt_debug
+ if func_cygming_gnu_implib_p "$1" ; then
+ # binutils import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+ elif func_cygming_ms_implib_p "$1" ; then
+ # ms-generated import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+ else
+ # unknown
+ sharedlib_from_linklib_result=""
+ fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ $opt_debug
+ f_ex_an_ar_dir="$1"; shift
+ f_ex_an_ar_oldlib="$1"
+ if test "$lock_old_archive_extraction" = yes; then
+ lockfile=$f_ex_an_ar_oldlib.lock
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ fi
+ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+ 'stat=$?; rm -f "$lockfile"; exit $stat'
+ if test "$lock_old_archive_extraction" = yes; then
+ $opt_dry_run || rm -f "$lockfile"
+ fi
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+ fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ $opt_debug
+ my_gentop="$1"; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=""
+ my_xlib=""
+ my_xabs=""
+ my_xdir=""
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ func_basename "$my_xlib"
+ my_xlib="$func_basename_result"
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ func_arith $extracted_serial + 1
+ extracted_serial=$func_arith_result
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir="$my_gentop/$my_xlib_u"
+
+ func_mkdir_p "$my_xdir"
+
+ case $host in
+ *-darwin*)
+ func_verbose "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ $opt_dry_run || {
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ darwin_base_archive=`basename "$darwin_archive"`
+ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches ; do
+ func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ cd "$darwin_curdir"
+ $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ done # $darwin_arches
+ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd $darwin_orig_dir
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ } # !$opt_dry_run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+ done
+
+ func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable. Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take. If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory. This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+ func_emit_wrapper_arg1=${1-no}
+
+ $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='$macro_version'
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$ECHO are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ file=\"\$0\""
+
+ qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+ ECHO=\"$qECHO\"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=\$0
+ shift
+ for lt_opt
+ do
+ case \"\$lt_opt\" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+ test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+ lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+ cat \"\$lt_dump_D/\$lt_dump_F\"
+ exit 0
+ ;;
+ --lt-*)
+ \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n \"\$lt_option_debug\"; then
+ echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+ lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2* | *-cegcc*)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $ECHO "\
+ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case \" \$* \" in
+ *\\ --lt-*)
+ for lt_wr_arg
+ do
+ case \$lt_wr_arg in
+ --lt-*) ;;
+ *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core \${1+\"\$@\"}
+}
+
+ # Parse options
+ func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $ECHO "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" ||
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $MKDIR \"\$progdir\"
+ else
+ $RM \"\$progdir/\$file\"
+ fi"
+
+ $ECHO "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $ECHO \"\$relink_command_output\" >&2
+ $RM \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $RM \"\$progdir/\$program\";
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $RM \"\$progdir/\$file\"
+ fi"
+ else
+ $ECHO "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $ECHO "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # fixup the dll searchpath if we need to.
+ #
+ # Fix the DLL searchpath if we need to. Do this before prepending
+ # to shlibpath, because on Windows, both are PATH and uninstalled
+ # libraries must come first.
+ if test -n "$dllsearchpath"; then
+ $ECHO "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $ECHO "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ $ECHO "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+ func_exec_program \${1+\"\$@\"}
+ fi
+ else
+ # The program doesn't exist.
+ \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+ \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+ cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+*/
+EOF
+ cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+# include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+# define _INTPTR_T_DEFINED
+# define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+ cat <<EOF
+volatile const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ func_to_host_path "$temp_rpath"
+ cat <<EOF
+const char * LIB_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * LIB_PATH_VALUE = "";
+EOF
+ fi
+
+ if test -n "$dllsearchpath"; then
+ func_to_host_path "$dllsearchpath:"
+ cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE = "";
+EOF
+ fi
+
+ if test "$fast_install" = yes; then
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+ else
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+ fi
+
+
+ cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int newargc;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *actual_cwrapper_name;
+ char *target_name;
+ char *lt_argv_zero;
+ intptr_t rval = 127;
+
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ newargz = XMALLOC (char *, argc + 1);
+
+ /* very simple arg parsing; don't want to rely on getopt
+ * also, copy all non cwrapper options to newargz, except
+ * argz[0], which is handled differently
+ */
+ newargc=0;
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], dumpscript_opt) == 0)
+ {
+EOF
+ case "$host" in
+ *mingw* | *cygwin* )
+ # make stdout use "unix" line endings
+ echo " setmode(1,_O_BINARY);"
+ ;;
+ esac
+
+ cat <<"EOF"
+ lt_dump_script (stdout);
+ return 0;
+ }
+ if (strcmp (argv[i], debug_opt) == 0)
+ {
+ lt_debug = 1;
+ continue;
+ }
+ if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+ {
+ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+ namespace, but it is not one of the ones we know about and
+ have already dealt with, above (inluding dump-script), then
+ report an error. Otherwise, targets might begin to believe
+ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+ namespace. The first time any user complains about this, we'll
+ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+ or a configure.ac-settable value.
+ */
+ lt_fatal (__FILE__, __LINE__,
+ "unrecognized %s option: '%s'",
+ ltwrapper_option_prefix, argv[i]);
+ }
+ /* otherwise ... */
+ newargz[++newargc] = xstrdup (argv[i]);
+ }
+ newargz[++newargc] = NULL;
+
+EOF
+ cat <<EOF
+ /* The GNU banner must be the first non-error debug message */
+ lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+ cat <<"EOF"
+ lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
+ lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (before symlink chase) at: %s\n",
+ tmp_pathspec);
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (after symlink chase) at: %s\n",
+ actual_cwrapper_path);
+ XFREE (tmp_pathspec);
+
+ actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+ strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+ /* wrapper name transforms */
+ strendzap (actual_cwrapper_name, ".exe");
+ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+ XFREE (actual_cwrapper_name);
+ actual_cwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ /* target_name transforms -- use actual target program name; might have lt- prefix */
+ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+ strendzap (target_name, ".exe");
+ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+ XFREE (target_name);
+ target_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) libtool target name: %s\n",
+ target_name);
+EOF
+
+ cat <<EOF
+ newargz[0] =
+ XMALLOC (char, (strlen (actual_cwrapper_path) +
+ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+ strcpy (newargz[0], actual_cwrapper_path);
+ strcat (newargz[0], "$objdir");
+ strcat (newargz[0], "/");
+EOF
+
+ cat <<"EOF"
+ /* stop here, and copy so we don't have to do this twice */
+ tmp_pathspec = xstrdup (newargz[0]);
+
+ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+ strcat (newargz[0], actual_cwrapper_name);
+
+ /* DO want the lt- prefix here if it exists, so use target_name */
+ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+ XFREE (tmp_pathspec);
+ tmp_pathspec = NULL;
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p;
+ while ((p = strchr (newargz[0], '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE (target_name);
+ XFREE (actual_cwrapper_path);
+ XFREE (actual_cwrapper_name);
+
+ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
+ /* Update the DLL searchpath. EXE_PATH_VALUE ($dllsearchpath) must
+ be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+ because on Windows, both *_VARNAMEs are PATH but uninstalled
+ libraries must come first. */
+ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+ lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+ nonnull (lt_argv_zero));
+ for (i = 0; i < newargc; i++)
+ {
+ lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+ i, nonnull (newargz[i]));
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ /* execv doesn't actually work on mingw as expected on unix */
+ newargz = prepare_spawn (newargz);
+ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ if (rval == -1)
+ {
+ /* failed to start process */
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) failed to launch target \"%s\": %s\n",
+ lt_argv_zero, nonnull (strerror (errno)));
+ return 127;
+ }
+ return rval;
+EOF
+ ;;
+ *)
+ cat <<"EOF"
+ execv (lt_argv_zero, newargz);
+ return rval; /* =127, but avoids unused variable warning */
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void *p = (void *) malloc (num);
+ if (!p)
+ lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+ string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable (const char *path)
+{
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0)
+ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return 1;
+ else
+ return 0;
+}
+
+int
+make_executable (const char *path)
+{
+ int rval = 0;
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+ }
+ return rval;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+ int has_slash = 0;
+ const char *p;
+ const char *p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ int tmp_len;
+ char *concat_name;
+
+ lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+ nonempty (wrapper));
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char *path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char *q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR (*q))
+ break;
+ p_len = q - p;
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name =
+ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name =
+ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup (pathspec);
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ char *tmp_pathspec = xstrdup (pathspec);
+ char *p;
+ int has_symlinks = 0;
+ while (strlen (tmp_pathspec) && !has_symlinks)
+ {
+ lt_debugprintf (__FILE__, __LINE__,
+ "checking path component for symlinks: %s\n",
+ tmp_pathspec);
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK (s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ p--;
+ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "error accessing file \"%s\": %s",
+ tmp_pathspec, nonnull (strerror (errno)));
+ }
+ }
+ XFREE (tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup (pathspec);
+ }
+
+ tmp_pathspec = realpath (pathspec, buf);
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert (str != NULL);
+ assert (pat != NULL);
+
+ len = strlen (str);
+ patlen = strlen (pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp (str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+ if (lt_debug)
+ {
+ (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+ va_start (args, fmt);
+ (void) vfprintf (stderr, fmt, args);
+ va_end (args);
+ }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+ int line, const char *mode,
+ const char *message, va_list ap)
+{
+ fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+ va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+ return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+ return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_setenv) setting '%s' to '%s'\n",
+ nonnull (name), nonnull (value));
+ {
+#ifdef HAVE_SETENV
+ /* always make a copy, for consistency with !HAVE_SETENV */
+ char *str = xstrdup (value);
+ setenv (name, str, 1);
+#else
+ int len = strlen (name) + 1 + strlen (value) + 1;
+ char *str = XMALLOC (char, len);
+ sprintf (str, "%s=%s", name, value);
+ if (putenv (str) != EXIT_SUCCESS)
+ {
+ XFREE (str);
+ }
+#endif
+ }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+ char *new_value;
+ if (orig_value && *orig_value)
+ {
+ int orig_value_len = strlen (orig_value);
+ int add_len = strlen (add);
+ new_value = XMALLOC (char, add_len + orig_value_len + 1);
+ if (to_end)
+ {
+ strcpy (new_value, orig_value);
+ strcpy (new_value + orig_value_len, add);
+ }
+ else
+ {
+ strcpy (new_value, add);
+ strcpy (new_value + add_len, orig_value);
+ }
+ }
+ else
+ {
+ new_value = xstrdup (add);
+ }
+ return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ /* some systems can't cope with a ':'-terminated path #' */
+ int len = strlen (new_value);
+ while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ {
+ new_value[len-1] = '\0';
+ }
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+EOF
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+ Note that spawn() does not by itself call the command interpreter
+ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&v);
+ v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+ }) ? "cmd.exe" : "command.com").
+ Instead it simply concatenates the arguments, separated by ' ', and calls
+ CreateProcess(). We must quote the arguments since Win32 CreateProcess()
+ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+ special way:
+ - Space and tab are interpreted as delimiters. They are not treated as
+ delimiters if they are surrounded by double quotes: "...".
+ - Unescaped double quotes are removed from the input. Their only effect is
+ that within double quotes, space and tab are treated like normal
+ characters.
+ - Backslashes not followed by double quotes are not special.
+ - But 2*n+1 backslashes followed by a double quote become
+ n backslashes followed by a double quote (n >= 0):
+ \" -> "
+ \\\" -> \"
+ \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+ size_t argc;
+ char **new_argv;
+ size_t i;
+
+ /* Count number of arguments. */
+ for (argc = 0; argv[argc] != NULL; argc++)
+ ;
+
+ /* Allocate new argument vector. */
+ new_argv = XMALLOC (char *, argc + 1);
+
+ /* Put quoted arguments into the new argument vector. */
+ for (i = 0; i < argc; i++)
+ {
+ const char *string = argv[i];
+
+ if (string[0] == '\0')
+ new_argv[i] = xstrdup ("\"\"");
+ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+ {
+ int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+ size_t length;
+ unsigned int backslashes;
+ const char *s;
+ char *quoted_string;
+ char *p;
+
+ length = 0;
+ backslashes = 0;
+ if (quote_around)
+ length++;
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ length += backslashes + 1;
+ length++;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ length += backslashes + 1;
+
+ quoted_string = XMALLOC (char, length + 1);
+
+ p = quoted_string;
+ backslashes = 0;
+ if (quote_around)
+ *p++ = '"';
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ {
+ unsigned int j;
+ for (j = backslashes + 1; j > 0; j--)
+ *p++ = '\\';
+ }
+ *p++ = c;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ {
+ unsigned int j;
+ for (j = backslashes; j > 0; j--)
+ *p++ = '\\';
+ *p++ = '"';
+ }
+ *p = '\0';
+
+ new_argv[i] = quoted_string;
+ }
+ else
+ new_argv[i] = (char *) string;
+ }
+ new_argv[argc] = NULL;
+
+ return new_argv;
+}
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+ func_emit_wrapper yes |
+ $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/ fputs ("\1", f);/p
+g
+D'
+ cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+ $opt_debug
+ case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+ *import*) : ;;
+ *) false ;;
+ esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+ $opt_debug
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args=$nonopt
+ base_compile="$nonopt $@"
+ compile_command=$nonopt
+ finalize_command=$nonopt
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+ new_inherited_linker_flags=
+
+ avoid_version=no
+ bindir=
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+ weak_libs=
+ single_module="${wl}-single_module"
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ break
+ ;;
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ func_warning "complete static linking is impossible in this configuration"
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ func_quote_for_eval "$arg"
+ qarg=$func_quote_for_eval_unquoted_result
+ func_append libtool_args " $func_quote_for_eval_result"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ func_append compile_command " @OUTPUT@"
+ func_append finalize_command " @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ bindir)
+ bindir="$arg"
+ prev=
+ continue
+ ;;
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ func_append compile_command " @SYMFILE@"
+ func_append finalize_command " @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ func_append dlfiles " $arg"
+ else
+ func_append dlprefiles " $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ test -f "$arg" \
+ || func_fatal_error "symbol file \`$arg' does not exist"
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ framework)
+ case $host in
+ *-*-darwin*)
+ case "$deplibs " in
+ *" $qarg.ltframework "*) ;;
+ *) func_append deplibs " $qarg.ltframework" # this is fixed later
+ ;;
+ esac
+ ;;
+ esac
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat "$save_arg"`
+ do
+# func_append moreargs " $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ done
+ else
+ func_fatal_error "link input file \`$arg' does not exist"
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) func_append rpath " $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) func_append xrpath " $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ weak)
+ func_append weak_libs " $arg"
+ prev=
+ continue
+ ;;
+ xcclinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xcompiler)
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xlinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $wl$qarg"
+ prev=
+ func_append compile_command " $wl$qarg"
+ func_append finalize_command " $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ # See comment for -static flag below, for more details.
+ func_append compile_command " $link_static_flag"
+ func_append finalize_command " $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -bindir)
+ prev=bindir
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ func_fatal_error "more than one -exported-symbols argument is not allowed"
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework)
+ prev=framework
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ func_stripname "-L" '' "$arg"
+ if test -z "$func_stripname_result"; then
+ if test "$#" -gt 0; then
+ func_fatal_error "require no space between \`-L' and \`$1'"
+ else
+ func_fatal_error "need path for \`-L' option"
+ fi
+ fi
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ test -z "$absdir" && \
+ func_fatal_error "cannot determine absolute directory name of \`$dir'"
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "* | *" $arg "*)
+ # Will only happen for absolute or sysroot arguments
+ ;;
+ *)
+ # Preserve sysroot, but never include relative directories
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+ *) func_append deplibs " -L$dir" ;;
+ esac
+ func_append lib_search_path " $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ ::) dllsearchpath=$dir;;
+ *) func_append dllsearchpath ":$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ func_append deplibs " System.ltframework"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test "X$arg" = "X-lc" && continue
+ ;;
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ func_append deplibs " $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ # Darwin uses the -arch flag to determine output architecture.
+ -model|-arch|-isysroot|--sysroot)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) func_append new_inherited_linker_flags " $arg" ;;
+ esac
+ continue
+ ;;
+
+ -multi_module)
+ single_module="${wl}-multi_module"
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ func_warning "\`-no-install' is ignored for $host"
+ func_warning "assuming \`-no-fast-install' instead"
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ func_stripname '-R' '' "$arg"
+ dir=$func_stripname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ =*)
+ func_stripname '=' '' "$dir"
+ dir=$lt_sysroot$func_stripname_result
+ ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ continue
+ ;;
+
+ -shared)
+ # The effects of -shared are defined in a previous loop.
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -weak)
+ prev=weak
+ continue
+ ;;
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ func_append arg " $func_quote_for_eval_result"
+ func_append compiler_flags " $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Wl,*)
+ func_stripname '-Wl,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ func_append arg " $wl$func_quote_for_eval_result"
+ func_append compiler_flags " $wl$func_quote_for_eval_result"
+ func_append linker_flags " $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # -msg_* for osf cc
+ -msg_*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ # Flags to be passed through unchanged, with rationale:
+ # -64, -mips[0-9] enable 64-bit mode for the SGI compiler
+ # -r[0-9][0-9]* specify processor for the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+ # +DA*, +DD* enable 64-bit mode for the HP compiler
+ # -q* compiler args for the IBM compiler
+ # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+ # -F/path path to uninstalled frameworks, gcc on darwin
+ # -p, -pg, --coverage, -fprofile-* profiling flags for GCC
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ # --sysroot=* for sysroot support
+ # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+ -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ func_append compiler_flags " $arg"
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ *.$objext)
+ # A standard object.
+ func_append objs " $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ func_append deplibs " $arg"
+ func_append old_deplibs " $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ func_resolve_sysroot "$arg"
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ func_append dlfiles " $func_resolve_sysroot_result"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ func_append dlprefiles " $func_resolve_sysroot_result"
+ prev=
+ else
+ func_append deplibs " $func_resolve_sysroot_result"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+ done # argument parsing loop
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prevarg' option requires an argument"
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ func_basename "$output"
+ outputname="$func_basename_result"
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ func_dirname "$output" "/" ""
+ output_objdir="$func_dirname_result$objdir"
+ func_to_tool_file "$output_objdir/"
+ tool_output_objdir=$func_to_tool_file_result
+ # Create the object directory.
+ func_mkdir_p "$output_objdir"
+
+ # Determine the type of output
+ case $output in
+ "")
+ func_fatal_help "you must specify an output file"
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if $opt_preserve_dup_deps ; then
+ case "$libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append libs " $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if $opt_duplicate_compiler_generated_deps; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+ esac
+ func_append pre_post_deps " $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+
+ case $linkmode in
+ lib)
+ passes="conv dlpreopen link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+
+ for pass in $passes; do
+ # The preopen pass in lib mode reverses $deplibs; put it back here
+ # so that -L comes before libs that need it for instance...
+ if test "$linkmode,$pass" = "lib,link"; then
+ ## FIXME: Find the place where the list is rebuilt in the wrong
+ ## order, and fix it there properly
+ tmp_deplibs=
+ for deplib in $deplibs; do
+ tmp_deplibs="$deplib $tmp_deplibs"
+ done
+ deplibs="$tmp_deplibs"
+ fi
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+ esac
+ fi
+ if test "$linkmode,$pass" = "lib,dlpreopen"; then
+ # Collect and forward deplibs of preopened libtool libs
+ for lib in $dlprefiles; do
+ # Ignore non-libtool-libs
+ dependency_libs=
+ func_resolve_sysroot "$lib"
+ case $lib in
+ *.la) func_source "$func_resolve_sysroot_result" ;;
+ esac
+
+ # Collect preopened libtool deplibs, except any this library
+ # has declared as weak libs
+ for deplib in $dependency_libs; do
+ func_basename "$deplib"
+ deplib_base=$func_basename_result
+ case " $weak_libs " in
+ *" $deplib_base "*) ;;
+ *) func_append deplibs " $deplib" ;;
+ esac
+ done
+ done
+ libs="$dlprefiles"
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append compiler_flags " $deplib"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ func_warning "\`-l' is ignored for archives/objects"
+ continue
+ fi
+ func_stripname '-l' '' "$deplib"
+ name=$func_stripname_result
+ if test "$linkmode" = lib; then
+ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+ else
+ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+ fi
+ for searchdir in $searchdirs; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if func_lalib_p "$lib"; then
+ library_names=
+ old_library=
+ func_source "$lib"
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ *.ltframework)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ *)
+ func_warning "\`-L' is ignored for archives/objects"
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ func_stripname '-R' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ lib=$func_resolve_sysroot_result
+ ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ # Linking convenience modules into shared libraries is allowed,
+ # but linking other static libraries is non-portable.
+ case " $dlpreconveniencelibs " in
+ *" $deplib "*) ;;
+ *)
+ valid_a_lib=no
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=yes
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=yes
+ ;;
+ esac
+ if test "$valid_a_lib" != yes; then
+ echo
+ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because the file extensions .$libext of this argument makes me believe"
+ echo "*** that it is just a static archive that I should not use here."
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ ;;
+ esac
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ func_append newdlprefiles " $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append newdlfiles " $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+ fi
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$lib" \
+ || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ inherited_linker_flags=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ func_source "$lib"
+
+ # Convert "-framework foo" to "foo.ltframework"
+ if test -n "$inherited_linker_flags"; then
+ tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+ case " $new_inherited_linker_flags " in
+ *" $tmp_inherited_linker_flag "*) ;;
+ *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+ esac
+ done
+ fi
+ dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && func_append dlfiles " $dlopen"
+ test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ func_append convenience " $ladir/$objdir/$old_library"
+ func_append old_convenience " $ladir/$objdir/$old_library"
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ func_fatal_error "\`$lib' is not a convenience library"
+ fi
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_preserve_dup_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ if test -n "$old_library" &&
+ { test "$prefer_static_libs" = yes ||
+ test "$prefer_static_libs,$installed" = "built,no"; }; then
+ linklib=$old_library
+ else
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ fi
+ if test -z "$linklib"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+ fi
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ func_append dlprefiles " $lib $dependency_libs"
+ else
+ func_append newdlfiles " $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ func_warning "cannot determine absolute directory name of \`$ladir'"
+ func_warning "passing it literally to the linker, although it might fail"
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ func_basename "$lib"
+ laname="$func_basename_result"
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ func_warning "library \`$lib' was moved."
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$lt_sysroot$libdir"
+ absdir="$lt_sysroot$libdir"
+ fi
+ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir="$ladir"
+ absdir="$abs_ladir"
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ fi
+ fi # $installed = yes
+ func_stripname 'lib' '.la' "$laname"
+ name=$func_stripname_result
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir" && test "$linkmode" = prog; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+ fi
+ case "$host" in
+ # special handling for platforms with PE-DLLs.
+ *cygwin* | *mingw* | *cegcc* )
+ # Linker will automatically link against shared library if both
+ # static and shared are present. Therefore, ensure we extract
+ # symbols from the import library if a shared library is present
+ # (otherwise, the dlopen module name will be incorrect). We do
+ # this by putting the import library name into $newdlprefiles.
+ # We recover the dlopen module name by 'saving' the la file
+ # name in a special purpose variable, and (later) extracting the
+ # dlname from the la file.
+ if test -n "$dlname"; then
+ func_tr_sh "$dir/$linklib"
+ eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+ func_append newdlprefiles " $dir/$linklib"
+ else
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ fi
+ ;;
+ * )
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ func_append newdlprefiles " $dir/$dlname"
+ else
+ func_append newdlprefiles " $dir/$linklib"
+ fi
+ ;;
+ esac
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ func_append newlib_search_path " $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if $opt_preserve_dup_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { { test "$prefer_static_libs" = no ||
+ test "$prefer_static_libs,$installed" = "built,yes"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath:" in
+ *"$absdir:"*) ;;
+ *) func_append temp_rpath "$absdir:" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test "$use_static_libs" = built && test "$installed" = yes; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ case $host in
+ *cygwin* | *mingw* | *cegcc*)
+ # No point in relinking DLLs because paths are not encoded
+ func_append notinst_deplibs " $lib"
+ need_relink=no
+ ;;
+ *)
+ if test "$installed" = no; then
+ func_append notinst_deplibs " $lib"
+ need_relink=yes
+ fi
+ ;;
+ esac
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some
+ # systems (darwin). Don't bleat about dlopened modules though!
+ dlopenmodule=""
+ for dlpremoduletest in $dlprefiles; do
+ if test "X$dlpremoduletest" = "X$lib"; then
+ dlopenmodule="$dlpremoduletest"
+ break
+ fi
+ done
+ if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+ echo
+ if test "$linkmode" = prog; then
+ $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $ECHO "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw* | *cegcc*)
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ func_basename "$soroot"
+ soname="$func_basename_result"
+ func_stripname 'lib' '.dll' "$soname"
+ newlib=libimp-$func_stripname_result.a
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ func_verbose "extracting exported symbol list from \`$soname'"
+ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ func_verbose "generating import library for \`$soname'"
+ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$opt_mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a (non-dlopened) module then we can not
+ # link against it, someone is ignoring the earlier warnings
+ if /usr/bin/file -L $add 2> /dev/null |
+ $GREP ": [^:]* bundle" >/dev/null ; then
+ if test "X$dlopenmodule" != "X$lib"; then
+ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ echo
+ echo "*** And there doesn't seem to be a static archive available"
+ echo "*** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ elif test -n "$old_library"; then
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$absdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ func_fatal_configuration "unsupported hardcode properties"
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) func_append compile_shlibpath "$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes &&
+ test "$hardcode_minus_L" != yes &&
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$opt_mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ echo
+ $ECHO "*** Warning: This system can not link to static lib archive $lib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ echo "*** But as you try to build a module library, libtool will still create "
+ echo "*** a static module, that should work as long as the dlopening application"
+ echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) func_stripname '-R' '' "$libdir"
+ temp_xrpath=$func_stripname_result
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) func_append xrpath " $temp_xrpath";;
+ esac;;
+ *) func_append temp_deplibs " $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ func_append newlib_search_path " $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result";;
+ *) func_resolve_sysroot "$deplib" ;;
+ esac
+ if $opt_preserve_dup_deps ; then
+ case "$tmp_libs " in
+ *" $func_resolve_sysroot_result "*)
+ func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+ esac
+ fi
+ func_append tmp_libs " $func_resolve_sysroot_result"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ path=
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ deplib=$func_resolve_sysroot_result
+ func_dirname "$deplib" "" "."
+ dir=$func_dirname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ func_warning "cannot determine absolute directory name of \`$dir'"
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if $GREP "^installed=no" $deplib > /dev/null; then
+ case $host in
+ *-*-darwin*)
+ depdepl=
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$absdir/$objdir/$depdepl" ; then
+ depdepl="$absdir/$objdir/$depdepl"
+ darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -z "$darwin_install_name"; then
+ darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ fi
+ func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+ func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+ path=
+ fi
+ fi
+ ;;
+ *)
+ path="-L$absdir/$objdir"
+ ;;
+ esac
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ test "$absdir" != "$libdir" && \
+ func_warning "\`$deplib' seems to be moved"
+
+ path="-L$absdir"
+ fi
+ ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test "$pass" = link; then
+ if test "$linkmode" = "prog"; then
+ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ fi
+ fi
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) func_append lib_search_path " $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ func_append tmp_libs " $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ fi
+ if test "$linkmode" = prog || test "$linkmode" = lib; then
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for archives"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for archives" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for archives"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for archives"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for archives"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for archives"
+
+ test -n "$export_symbols$export_symbols_regex" && \
+ func_warning "\`-export-symbols' is ignored for archives"
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ func_append objs "$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ func_stripname 'lib' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ test "$module" = no && \
+ func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ func_stripname '' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ func_stripname '' '.la' "$outputname"
+ libname=$func_stripname_result
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+ $ECHO "*** objects $objs is not portable!"
+ func_append libobjs " $objs"
+ fi
+ fi
+
+ test "$dlself" != no && \
+ func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+ set dummy $rpath
+ shift
+ test "$#" -gt 1 && \
+ func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+ install_libdir="$1"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for convenience libraries"
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ shift
+ IFS="$save_ifs"
+
+ test -n "$7" && \
+ func_fatal_help "too many parameters to \`-version-info'"
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$1"
+ number_minor="$2"
+ number_revision="$3"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ # correct linux to gnu/linux during the next big refactor
+ darwin|linux|osf|windows|none)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|qnx|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_minor"
+ lt_irix_increment=no
+ ;;
+ esac
+ ;;
+ no)
+ current="$1"
+ revision="$2"
+ age="$3"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "CURRENT \`$current' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "REVISION \`$revision' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "AGE \`$age' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ func_error "AGE \`$age' is greater than the current interface number \`$current'"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ func_arith $current + 1
+ minor_current=$func_arith_result
+ xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ irix | nonstopux)
+ if test "X$lt_irix_increment" = "Xno"; then
+ func_arith $current - $age
+ else
+ func_arith $current - $age + 1
+ fi
+ major=$func_arith_result
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ func_arith $revision - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux) # correct to gnu/linux during the next big refactor
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ func_arith $current - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ func_append verstring ":${current}.0"
+ ;;
+
+ qnx)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+
+ *)
+ func_fatal_configuration "unknown library version type \`$version_type'"
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ func_warning "undefined symbols not allowed in $host shared libraries"
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+
+ fi
+
+ func_generate_dlsyms "$libname" "$libname" "yes"
+ func_append libobjs " $symfileobj"
+ test "X$libobjs" = "X " && libobjs=
+
+ if test "$opt_mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$ECHO "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext | *.gcno)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if test "X$precious_files_regex" != "X"; then
+ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ func_append removelist " $p"
+ ;;
+ *) ;;
+ esac
+ done
+ test -n "$removelist" && \
+ func_show_eval "${RM}r \$removelist"
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ func_append oldlibs " $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+ # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+ # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ func_replace_sysroot "$libdir"
+ func_append temp_xrpath " -R$func_replace_sysroot_result"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) func_append dlfiles " $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) func_append dlprefiles " $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ func_append deplibs " System.ltframework"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ func_append deplibs " -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $opt_dry_run || $RM conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which I believe you do not have"
+ echo "*** because a test_compile did reveal that the linker did not use it for"
+ echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because a test_compile did reveal that the linker did not use this one"
+ echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method; shift
+ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ if test -n "$file_magic_glob"; then
+ libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+ else
+ libnameglob=$libname
+ fi
+ test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ if test "$want_nocaseglob" = yes; then
+ shopt -s nocaseglob
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ $nocaseglob
+ else
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ fi
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null |
+ $GREP " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+ $SED -e 10q |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+ $EGREP "$match_pattern_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+ done
+ fi
+ case $tmp_deplibs in
+ *[!\ \ ]*)
+ echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ ;;
+ esac
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library with the System framework
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ echo
+ echo "*** Since this library must not contain undefined symbols,"
+ echo "*** because either the platform does not support them or"
+ echo "*** it was explicitly requested with -no-undefined,"
+ echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ case $host in
+ *-*-darwin*)
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ deplibs="$new_libs"
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ # Remove ${wl} instances when linking with ld.
+ # FIXME: should test the right _cmds variable.
+ case $archive_cmds in
+ *\$LD\ *) wl= ;;
+ esac
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ func_replace_sysroot "$libdir"
+ libdir=$func_replace_sysroot_result
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append dep_rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ linknames=
+ for link
+ do
+ func_append linknames " $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ test "X$libobjs" = "X " && libobjs=
+
+ delfiles=
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+ export_symbols="$output_objdir/$libname.uexp"
+ func_append delfiles " $export_symbols"
+ fi
+
+ orig_export_symbols=
+ case $host_os in
+ cygwin* | mingw* | cegcc*)
+ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+ # exporting using user supplied symfile
+ if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+ # and it's NOT already a .def file. Must figure out
+ # which of the given symbols are data symbols and tag
+ # them as such. So, trigger use of export_symbols_cmds.
+ # export_symbols gets reassigned inside the "prepare
+ # the list of exported symbols" if statement, so the
+ # include_expsyms logic still works.
+ orig_export_symbols="$export_symbols"
+ export_symbols=
+ always_export_symbols=yes
+ fi
+ fi
+ ;;
+ esac
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd1 in $cmds; do
+ IFS="$save_ifs"
+ # Take the normal branch if the nm_file_list_spec branch
+ # doesn't work or if tool conversion is not needed.
+ case $nm_file_list_spec~$to_tool_file_cmd in
+ *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+ try_normal_branch=yes
+ eval cmd=\"$cmd1\"
+ func_len " $cmd"
+ len=$func_len_result
+ ;;
+ *)
+ try_normal_branch=no
+ ;;
+ esac
+ if test "$try_normal_branch" = yes \
+ && { test "$len" -lt "$max_cmd_len" \
+ || test "$max_cmd_len" -le -1; }
+ then
+ func_show_eval "$cmd" 'exit $?'
+ skipped_export=false
+ elif test -n "$nm_file_list_spec"; then
+ func_basename "$output"
+ output_la=$func_basename_result
+ save_libobjs=$libobjs
+ save_output=$output
+ output=${output_objdir}/${output_la}.nm
+ func_to_tool_file "$output"
+ libobjs=$nm_file_list_spec$func_to_tool_file_result
+ func_append delfiles " $output"
+ func_verbose "creating $NM input file list: $output"
+ for obj in $save_libobjs; do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > "$output"
+ eval cmd=\"$cmd1\"
+ func_show_eval "$cmd" 'exit $?'
+ output=$save_output
+ libobjs=$save_libobjs
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ func_verbose "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ func_append tmp_deplibs " $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec" &&
+ test "$compiler_needs_object" = yes &&
+ test -z "$libobjs"; then
+ # extract the archives, so we have objects to list.
+ # TODO: could optimize this to just extract one archive.
+ whole_archive_flag_spec=
+ fi
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ else
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ func_append linker_flags " $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$opt_mode" = relink; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" &&
+ func_len " $test_cmds" &&
+ len=$func_len_result &&
+ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise
+ # or, if using GNU ld and skipped_export is not :, use a linker
+ # script.
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ func_basename "$output"
+ output_la=$func_basename_result
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ last_robj=
+ k=1
+
+ if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+ output=${output_objdir}/${output_la}.lnkscript
+ func_verbose "creating GNU ld script: $output"
+ echo 'INPUT (' > $output
+ for obj in $save_libobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ echo ')' >> $output
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$func_to_tool_file_result
+ elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+ output=${output_objdir}/${output_la}.lnk
+ func_verbose "creating linker input file list: $output"
+ : > $output
+ set x $save_libobjs
+ shift
+ firstobj=
+ if test "$compiler_needs_object" = yes; then
+ firstobj="$1 "
+ shift
+ fi
+ for obj
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+ else
+ if test -n "$save_libobjs"; then
+ func_verbose "creating reloadable object files..."
+ output=$output_objdir/$output_la-${k}.$objext
+ eval test_cmds=\"$reload_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ if test "X$objlist" = X ||
+ test "$len" -lt "$max_cmd_len"; then
+ func_append objlist " $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ reload_objs=$objlist
+ eval concat_cmds=\"$reload_cmds\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-${k}.$objext
+ func_arith $k + 1
+ k=$func_arith_result
+ output=$output_objdir/$output_la-${k}.$objext
+ objlist=" $obj"
+ func_len " $last_robj"
+ func_arith $len0 + $func_len_result
+ len=$func_arith_result
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+ fi
+ func_append delfiles " $output"
+
+ else
+ output=
+ fi
+
+ if ${skipped_export-false}; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ fi
+
+ test -n "$save_libobjs" &&
+ func_verbose "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$opt_mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+
+ if ${skipped_export-false}; then
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+ fi
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+ fi
+
+ if test -n "$delfiles"; then
+ # Append the command to remove temporary files to $cmds.
+ eval cmds=\"\$cmds~\$RM $delfiles\"
+ fi
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$opt_mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$opt_mode" = relink; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for objects"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for objects" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for objects"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for objects"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for objects"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for objects"
+
+ case $output in
+ *.lo)
+ test -n "$objs$old_deplibs" && \
+ func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+ libobj=$output
+ func_lo2o "$libobj"
+ obj=$func_lo2o_result
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $opt_dry_run || $RM $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec and hope we can get by with
+ # turning comma into space..
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+ reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ else
+ gentop="$output_objdir/${obj}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # If we're not building shared, we need to use non_pic_objs
+ test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+ fi
+
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result.exe;;
+ esac
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for programs"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for programs"
+
+ test "$preload" = yes \
+ && test "$dlopen_support" = unknown \
+ && test "$dlopen_self" = unknown \
+ && test "$dlopen_self_static" = unknown && \
+ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ case $host in
+ *-*-darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ # But is supposedly fixed on 10.4 or later (yay!).
+ if test "$tagname" = CXX ; then
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[0123])
+ func_append compile_command " ${wl}-bind_at_load"
+ func_append finalize_command " ${wl}-bind_at_load"
+ ;;
+ esac
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ compile_deplibs="$new_libs"
+
+
+ func_append compile_command " $compile_deplibs"
+ func_append finalize_command " $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ ::) dllsearchpath=$libdir;;
+ *) func_append dllsearchpath ":$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ fi
+
+ func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+ # template prelinking step
+ if test -n "$prelink_cmds"; then
+ func_execute_cmds "$prelink_cmds" 'exit $?'
+ fi
+
+ wrappers_required=yes
+ case $host in
+ *cegcc* | *mingw32ce*)
+ # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+ wrappers_required=no
+ ;;
+ *cygwin* | *mingw* )
+ if test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ *)
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ esac
+ if test "$wrappers_required" = no; then
+ # Replace the output file specification.
+ compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ exit_status=0
+ func_show_eval "$link_command" 'exit_status=$?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Delete the generated files.
+ if test -f "$output_objdir/${outputname}S.${objext}"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+ fi
+
+ exit $exit_status
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $opt_dry_run || $RM $output
+ # Link the executable and exit
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "\`$output' will be relinked during installation"
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output_objdir/$outputname"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Now create the wrapper script.
+ func_verbose "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if not in dry run mode.
+ $opt_dry_run || {
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ func_stripname '' '.exe' "$outputname"
+ outputname=$func_stripname_result ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ func_dirname_and_basename "$output" "" "."
+ output_name=$func_basename_result
+ output_path=$func_dirname_result
+ cwrappersource="$output_path/$objdir/lt-$output_name.c"
+ cwrapper="$output_path/$output_name.exe"
+ $RM $cwrappersource $cwrapper
+ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_cwrapperexe_src > $cwrappersource
+
+ # The wrapper executable is built using the $host compiler,
+ # because it contains $host paths and files. If cross-
+ # compiling, it, like the target executable, must be
+ # executed on the $host or under an emulation environment.
+ $opt_dry_run || {
+ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+ $STRIP $cwrapper
+ }
+
+ # Now, create the wrapper script for func_source use:
+ func_ltwrapper_scriptname $cwrapper
+ $RM $func_ltwrapper_scriptname_result
+ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+ $opt_dry_run || {
+ # note: this script will not be executed, so do not chmod.
+ if test "x$build" = "x$host" ; then
+ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+ else
+ func_emit_wrapper no > $func_ltwrapper_scriptname_result
+ fi
+ }
+ ;;
+ * )
+ $RM $output
+ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_wrapper no > $output
+ chmod +x $output
+ ;;
+ esac
+ }
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ if test "$preload" = yes && test -f "$symfileobj"; then
+ func_append oldobjs " $symfileobj"
+ fi
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $addlibs
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ func_basename "$obj"
+ $ECHO "$func_basename_result"
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ echo "copying selected object files to avoid basename conflicts..."
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+ func_mkdir_p "$gentop"
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ func_basename "$obj"
+ objbase="$func_basename_result"
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ func_arith $counter + 1
+ counter=$func_arith_result
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ func_append oldobjs " $gentop/$newobj"
+ ;;
+ *) func_append oldobjs " $obj" ;;
+ esac
+ done
+ fi
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+ eval cmds=\"$old_archive_cmds\"
+
+ func_len " $cmds"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ elif test -n "$archiver_list_spec"; then
+ func_verbose "using command file archive linking..."
+ for obj in $oldobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > $output_objdir/$libname.libcmd
+ func_to_tool_file "$output_objdir/$libname.libcmd"
+ oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ func_verbose "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ oldobjs=
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ eval test_cmds=\"$old_archive_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+ for obj in $save_oldobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ func_append objlist " $obj"
+ if test "$len" -lt "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ len=$len0
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ func_execute_cmds "$cmds" 'exit $?'
+ done
+
+ test -n "$generated" && \
+ func_show_eval "${RM}r$generated"
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ func_verbose "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+
+ # Only create the output if not a dry run.
+ $opt_dry_run || {
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ func_basename "$deplib"
+ name="$func_basename_result"
+ func_resolve_sysroot "$deplib"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ -L*)
+ func_stripname -L '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -L$func_replace_sysroot_result"
+ ;;
+ -R*)
+ func_stripname -R '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -R$func_replace_sysroot_result"
+ ;;
+ *) func_append newdependency_libs " $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+
+ for lib in $dlfiles; do
+ case $lib in
+ *.la)
+ func_basename "$lib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ *) func_append newdlfiles " $lib" ;;
+ esac
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ *.la)
+ # Only pass preopened files to the pseudo-archive (for
+ # eventual linking with the app. that links it) if we
+ # didn't already link the preopened objects directly into
+ # the library:
+ func_basename "$lib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ esac
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlfiles " $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlprefiles " $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $RM $output
+ # place dlname in correct position for cygwin
+ # In fact, it would be nice if we could use this code for all target
+ # systems that can't hard-code library paths into their executables
+ # and that have no shared library path variable independent of PATH,
+ # but it turns out we can't easily determine that from inspecting
+ # libtool variables, so we have to hard-code the OSs to which it
+ # applies here; at the moment, that means platforms that use the PE
+ # object format with DLL files. See the long comment at the top of
+ # tests/bindir.at for full details.
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+ # If a -bindir argument was supplied, place the dll there.
+ if test "x$bindir" != x ;
+ then
+ func_relative_path "$install_libdir" "$bindir"
+ tdlname=$func_relative_path_result$dlname
+ else
+ # Otherwise fall back on heuristic.
+ tdlname=../bin/$dlname
+ fi
+ ;;
+ esac
+ $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $ECHO >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ }
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+}
+
+{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
+ func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+ $opt_debug
+ RM="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) func_append RM " $arg"; rmforce=yes ;;
+ -*) func_append RM " $arg" ;;
+ *) func_append files " $arg" ;;
+ esac
+ done
+
+ test -z "$RM" && \
+ func_fatal_help "you must specify an RM program"
+
+ rmdirs=
+
+ for file in $files; do
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ if test "X$dir" = X.; then
+ odir="$objdir"
+ else
+ odir="$dir/$objdir"
+ fi
+ func_basename "$file"
+ name="$func_basename_result"
+ test "$opt_mode" = uninstall && odir="$dir"
+
+ # Remember odir for removal later, being careful to avoid duplicates
+ if test "$opt_mode" = clean; then
+ case " $rmdirs " in
+ *" $odir "*) ;;
+ *) func_append rmdirs " $odir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if { test -L "$file"; } >/dev/null 2>&1 ||
+ { test -h "$file"; } >/dev/null 2>&1 ||
+ test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if func_lalib_p "$file"; then
+ func_source $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ func_append rmfiles " $odir/$n"
+ done
+ test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+ case "$opt_mode" in
+ clean)
+ case " $library_names " in
+ *" $dlname "*) ;;
+ *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+ esac
+ test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if func_lalib_p "$file"; then
+
+ # Read the .lo file
+ func_source $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" &&
+ test "$pic_object" != none; then
+ func_append rmfiles " $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" &&
+ test "$non_pic_object" != none; then
+ func_append rmfiles " $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$opt_mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ func_stripname '' '.exe' "$name"
+ noexename=$func_stripname_result
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ func_append rmfiles " $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if func_ltwrapper_p "$file"; then
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ relink_command=
+ func_source $func_ltwrapper_scriptname_result
+ func_append rmfiles " $func_ltwrapper_scriptname_result"
+ else
+ relink_command=
+ func_source $dir/$noexename
+ fi
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ func_append rmfiles " $odir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ func_append rmfiles " $odir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ func_show_eval "$RM $rmfiles" 'exit_status=1'
+ done
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ func_show_eval "rmdir $dir >/dev/null 2>&1"
+ fi
+ done
+
+ exit $exit_status
+}
+
+{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
+ func_mode_uninstall ${1+"$@"}
+
+test -z "$opt_mode" && {
+ help="$generic_help"
+ func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+ func_fatal_help "invalid operation mode \`$opt_mode'"
+
+if test -n "$exec_cmd"; then
+ eval exec "$exec_cmd"
+ exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/jpg/makcjpeg.st b/jpg/makcjpeg.st
new file mode 100644
index 0000000..628f533
--- /dev/null
+++ b/jpg/makcjpeg.st
@@ -0,0 +1,36 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle, B. Setzepfandt, and Guido Vollbeding.
+;
+; To use this file, rename it to cjpeg.prj.
+; If you are using Turbo C, change filenames beginning with "pc..." to "tc..."
+; Read installation instructions before trying to make the program!
+;
+;
+; * * * Output file * * *
+cjpeg.ttp
+;
+; * * * COMPILER OPTIONS * * *
+.C[-P] ; absolute calls
+.C[-M] ; and no string merging, folks
+.C[-w-cln] ; no "constant is long" warnings
+.C[-w-par] ; no "parameter xxxx unused"
+.C[-w-rch] ; no "unreachable code"
+.C[-wsig] ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * *
+pcstart.o
+cjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h)
+cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdswitch.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdppm.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdgif.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdtarga.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdbmp.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdrle.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+libjpeg.lib ; built by libjpeg.prj
+pcfltlib.lib ; floating point library
+; the float library can be omitted if you've turned off DCT_FLOAT_SUPPORTED
+pcstdlib.lib ; standard library
+pcextlib.lib ; extended library
diff --git a/jpg/makdjpeg.st b/jpg/makdjpeg.st
new file mode 100644
index 0000000..4b61404
--- /dev/null
+++ b/jpg/makdjpeg.st
@@ -0,0 +1,36 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle, B. Setzepfandt, and Guido Vollbeding.
+;
+; To use this file, rename it to djpeg.prj.
+; If you are using Turbo C, change filenames beginning with "pc..." to "tc..."
+; Read installation instructions before trying to make the program!
+;
+;
+; * * * Output file * * *
+djpeg.ttp
+;
+; * * * COMPILER OPTIONS * * *
+.C[-P] ; absolute calls
+.C[-M] ; and no string merging, folks
+.C[-w-cln] ; no "constant is long" warnings
+.C[-w-par] ; no "parameter xxxx unused"
+.C[-w-rch] ; no "unreachable code"
+.C[-wsig] ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * *
+pcstart.o
+djpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,jversion.h)
+cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdcolmap.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrppm.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrgif.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrtarga.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrbmp.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+wrrle.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+libjpeg.lib ; built by libjpeg.prj
+pcfltlib.lib ; floating point library
+; the float library can be omitted if you've turned off DCT_FLOAT_SUPPORTED
+pcstdlib.lib ; standard library
+pcextlib.lib ; extended library
diff --git a/jpg/makeadsw.vc6 b/jpg/makeadsw.vc6
new file mode 100644
index 0000000..b44838f
--- /dev/null
+++ b/jpg/makeadsw.vc6
@@ -0,0 +1,77 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELSCHT WERDEN!
+
+###############################################################################
+
+Project: "cjpeg"=".\cjpeg.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "djpeg"=".\djpeg.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "jpegtran"=".\jpegtran.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "rdjpgcom"=".\rdjpgcom.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "wrjpgcom"=".\wrjpgcom.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/jpg/makeasln.v10 b/jpg/makeasln.v10
new file mode 100644
index 0000000..ab96a9f
--- /dev/null
+++ b/jpg/makeasln.v10
@@ -0,0 +1,33 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cjpeg", "cjpeg.vcxproj", "{2E7FAAD9-2F58-4BDE-81F2-1D6D3FB8BF57}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "djpeg", "djpeg.vcxproj", "{11043137-B453-4DFA-9010-4D2B9DC1545C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpegtran", "jpegtran.vcxproj", "{025BAC50-51B5-4FFE-BC47-3F920BB4047E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rdjpgcom", "rdjpgcom.vcxproj", "{C81513DB-78DC-46BC-BC98-82E745203976}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wrjpgcom", "wrjpgcom.vcxproj", "{B57065D4-DDDA-4668-BAF5-2D49270C973C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2E7FAAD9-2F58-4BDE-81F2-1D6D3FB8BF57}.Release|Win32.ActiveCfg = Release|Win32
+ {2E7FAAD9-2F58-4BDE-81F2-1D6D3FB8BF57}.Release|Win32.Build.0 = Release|Win32
+ {11043137-B453-4DFA-9010-4D2B9DC1545C}.Release|Win32.ActiveCfg = Release|Win32
+ {11043137-B453-4DFA-9010-4D2B9DC1545C}.Release|Win32.Build.0 = Release|Win32
+ {025BAC50-51B5-4FFE-BC47-3F920BB4047E}.Release|Win32.ActiveCfg = Release|Win32
+ {025BAC50-51B5-4FFE-BC47-3F920BB4047E}.Release|Win32.Build.0 = Release|Win32
+ {C81513DB-78DC-46BC-BC98-82E745203976}.Release|Win32.ActiveCfg = Release|Win32
+ {C81513DB-78DC-46BC-BC98-82E745203976}.Release|Win32.Build.0 = Release|Win32
+ {B57065D4-DDDA-4668-BAF5-2D49270C973C}.Release|Win32.ActiveCfg = Release|Win32
+ {B57065D4-DDDA-4668-BAF5-2D49270C973C}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/jpg/makecdep.vc6 b/jpg/makecdep.vc6
new file mode 100644
index 0000000..32443db
--- /dev/null
+++ b/jpg/makecdep.vc6
@@ -0,0 +1,82 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von cjpeg.mak
+
+.\cdjpeg.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\cjpeg.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+ ".\jversion.h"\
+
+
+.\rdbmp.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\rdgif.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\rdppm.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\rdrle.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\rdswitch.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\rdtarga.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
diff --git a/jpg/makecdsp.vc6 b/jpg/makecdsp.vc6
new file mode 100644
index 0000000..2cc2f8a
--- /dev/null
+++ b/jpg/makecdsp.vc6
@@ -0,0 +1,130 @@
+# Microsoft Developer Studio Project File - Name="cjpeg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=cjpeg - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "cjpeg.mak".
+!MESSAGE
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "cjpeg.mak" CFG="cjpeg - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "cjpeg - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\cjpeg\Release"
+# PROP BASE Intermediate_Dir ".\cjpeg\Release"
+# PROP BASE Target_Dir ".\cjpeg"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\cjpeg\Release"
+# PROP Intermediate_Dir ".\cjpeg\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\cjpeg"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "cjpeg - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\cdjpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\cjpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdbmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdgif.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdppm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdrle.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdswitch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdtarga.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\cderror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cdjpeg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmorecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpeglib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jversion.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/jpg/makecfil.v10 b/jpg/makecfil.v10
new file mode 100644
index 0000000..d16cb2c
--- /dev/null
+++ b/jpg/makecfil.v10
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="cderror.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="cdjpeg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jerror.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jinclude.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jmorecfg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jpeglib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jversion.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="cdjpeg.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="cjpeg.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdbmp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdgif.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdppm.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdrle.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdswitch.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdtarga.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makecmak.vc6 b/jpg/makecmak.vc6
new file mode 100644
index 0000000..74a230e
--- /dev/null
+++ b/jpg/makecmak.vc6
@@ -0,0 +1,159 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on cjpeg.dsp
+!IF "$(CFG)" == ""
+CFG=cjpeg - Win32
+!MESSAGE Keine Konfiguration angegeben. cjpeg - Win32 wird als Standard verwendet.
+!ENDIF
+
+!IF "$(CFG)" != "cjpeg - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "cjpeg.mak" CFG="cjpeg - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "cjpeg - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\cjpeg\Release
+INTDIR=.\cjpeg\Release
+# Begin Custom Macros
+OutDir=.\cjpeg\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\cjpeg.exe"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\cdjpeg.obj"
+ -@erase "$(INTDIR)\cjpeg.obj"
+ -@erase "$(INTDIR)\rdbmp.obj"
+ -@erase "$(INTDIR)\rdgif.obj"
+ -@erase "$(INTDIR)\rdppm.obj"
+ -@erase "$(INTDIR)\rdrle.obj"
+ -@erase "$(INTDIR)\rdswitch.obj"
+ -@erase "$(INTDIR)\rdtarga.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\cjpeg.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\cjpeg.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\cjpeg.pdb" /machine:I386 /out:"$(OUTDIR)\cjpeg.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\cdjpeg.obj" \
+ "$(INTDIR)\cjpeg.obj" \
+ "$(INTDIR)\rdbmp.obj" \
+ "$(INTDIR)\rdgif.obj" \
+ "$(INTDIR)\rdppm.obj" \
+ "$(INTDIR)\rdrle.obj" \
+ "$(INTDIR)\rdswitch.obj" \
+ "$(INTDIR)\rdtarga.obj"
+
+"$(OUTDIR)\cjpeg.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\cjpeg.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("cjpeg.dep")
+!INCLUDE "cjpeg.dep"
+!ELSE
+!MESSAGE Warning: cannot find "cjpeg.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "cjpeg - Win32"
+SOURCE=.\cdjpeg.c
+
+"$(INTDIR)\cdjpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\cjpeg.c
+
+"$(INTDIR)\cjpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdbmp.c
+
+"$(INTDIR)\rdbmp.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdgif.c
+
+"$(INTDIR)\rdgif.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdppm.c
+
+"$(INTDIR)\rdppm.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdrle.c
+
+"$(INTDIR)\rdrle.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdswitch.c
+
+"$(INTDIR)\rdswitch.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdtarga.c
+
+"$(INTDIR)\rdtarga.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/jpg/makecvcx.v10 b/jpg/makecvcx.v10
new file mode 100644
index 0000000..ed1ceef
--- /dev/null
+++ b/jpg/makecvcx.v10
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{2E7FAAD9-2F58-4BDE-81F2-1D6D3FB8BF57}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>cjpeg</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectName)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectName)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>Full</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>false</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <OmitFramePointers>true</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>Release\jpeg.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="cderror.h" />
+ <ClInclude Include="cdjpeg.h" />
+ <ClInclude Include="jconfig.h" />
+ <ClInclude Include="jerror.h" />
+ <ClInclude Include="jinclude.h" />
+ <ClInclude Include="jmorecfg.h" />
+ <ClInclude Include="jpeglib.h" />
+ <ClInclude Include="jversion.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="cdjpeg.c" />
+ <ClCompile Include="cjpeg.c" />
+ <ClCompile Include="rdbmp.c" />
+ <ClCompile Include="rdgif.c" />
+ <ClCompile Include="rdppm.c" />
+ <ClCompile Include="rdrle.c" />
+ <ClCompile Include="rdswitch.c" />
+ <ClCompile Include="rdtarga.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makeddep.vc6 b/jpg/makeddep.vc6
new file mode 100644
index 0000000..4d2b3ad
--- /dev/null
+++ b/jpg/makeddep.vc6
@@ -0,0 +1,82 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von djpeg.mak
+
+.\cdjpeg.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\djpeg.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+ ".\jversion.h"\
+
+
+.\rdcolmap.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\wrbmp.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\wrgif.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\wrppm.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\wrrle.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\wrtarga.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
diff --git a/jpg/makeddsp.vc6 b/jpg/makeddsp.vc6
new file mode 100644
index 0000000..252f8c7
--- /dev/null
+++ b/jpg/makeddsp.vc6
@@ -0,0 +1,130 @@
+# Microsoft Developer Studio Project File - Name="djpeg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=djpeg - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "djpeg.mak".
+!MESSAGE
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "djpeg.mak" CFG="djpeg - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "djpeg - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\djpeg\Release"
+# PROP BASE Intermediate_Dir ".\djpeg\Release"
+# PROP BASE Target_Dir ".\djpeg"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\djpeg\Release"
+# PROP Intermediate_Dir ".\djpeg\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\djpeg"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "djpeg - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\cdjpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\djpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdcolmap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrbmp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrgif.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrppm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrrle.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\wrtarga.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\cderror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cdjpeg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmorecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpeglib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jversion.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/jpg/makedfil.v10 b/jpg/makedfil.v10
new file mode 100644
index 0000000..92f321c
--- /dev/null
+++ b/jpg/makedfil.v10
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="cderror.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="cdjpeg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jerror.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jinclude.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jmorecfg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jpeglib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jversion.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="cdjpeg.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="djpeg.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdcolmap.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wrbmp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wrgif.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wrppm.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wrrle.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wrtarga.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makedmak.vc6 b/jpg/makedmak.vc6
new file mode 100644
index 0000000..5d7e778
--- /dev/null
+++ b/jpg/makedmak.vc6
@@ -0,0 +1,159 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on djpeg.dsp
+!IF "$(CFG)" == ""
+CFG=djpeg - Win32
+!MESSAGE Keine Konfiguration angegeben. djpeg - Win32 wird als Standard verwendet.
+!ENDIF
+
+!IF "$(CFG)" != "djpeg - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "djpeg.mak" CFG="djpeg - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "djpeg - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\djpeg\Release
+INTDIR=.\djpeg\Release
+# Begin Custom Macros
+OutDir=.\djpeg\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\djpeg.exe"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\cdjpeg.obj"
+ -@erase "$(INTDIR)\djpeg.obj"
+ -@erase "$(INTDIR)\rdcolmap.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\wrbmp.obj"
+ -@erase "$(INTDIR)\wrgif.obj"
+ -@erase "$(INTDIR)\wrppm.obj"
+ -@erase "$(INTDIR)\wrrle.obj"
+ -@erase "$(INTDIR)\wrtarga.obj"
+ -@erase "$(OUTDIR)\djpeg.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\djpeg.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\djpeg.pdb" /machine:I386 /out:"$(OUTDIR)\djpeg.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\cdjpeg.obj" \
+ "$(INTDIR)\djpeg.obj" \
+ "$(INTDIR)\rdcolmap.obj" \
+ "$(INTDIR)\wrbmp.obj" \
+ "$(INTDIR)\wrgif.obj" \
+ "$(INTDIR)\wrppm.obj" \
+ "$(INTDIR)\wrrle.obj" \
+ "$(INTDIR)\wrtarga.obj"
+
+"$(OUTDIR)\djpeg.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\djpeg.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("djpeg.dep")
+!INCLUDE "djpeg.dep"
+!ELSE
+!MESSAGE Warning: cannot find "djpeg.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "djpeg - Win32"
+SOURCE=.\cdjpeg.c
+
+"$(INTDIR)\cdjpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\djpeg.c
+
+"$(INTDIR)\djpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdcolmap.c
+
+"$(INTDIR)\rdcolmap.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrbmp.c
+
+"$(INTDIR)\wrbmp.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrgif.c
+
+"$(INTDIR)\wrgif.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrppm.c
+
+"$(INTDIR)\wrppm.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrrle.c
+
+"$(INTDIR)\wrrle.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\wrtarga.c
+
+"$(INTDIR)\wrtarga.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/jpg/makedvcx.v10 b/jpg/makedvcx.v10
new file mode 100644
index 0000000..d3e4cbf
--- /dev/null
+++ b/jpg/makedvcx.v10
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{11043137-B453-4DFA-9010-4D2B9DC1545C}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>djpeg</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectName)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectName)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>Full</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>false</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <OmitFramePointers>true</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>Release\jpeg.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="cderror.h" />
+ <ClInclude Include="cdjpeg.h" />
+ <ClInclude Include="jconfig.h" />
+ <ClInclude Include="jerror.h" />
+ <ClInclude Include="jinclude.h" />
+ <ClInclude Include="jmorecfg.h" />
+ <ClInclude Include="jpeglib.h" />
+ <ClInclude Include="jversion.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="cdjpeg.c" />
+ <ClCompile Include="djpeg.c" />
+ <ClCompile Include="rdcolmap.c" />
+ <ClCompile Include="wrbmp.c" />
+ <ClCompile Include="wrgif.c" />
+ <ClCompile Include="wrppm.c" />
+ <ClCompile Include="wrrle.c" />
+ <ClCompile Include="wrtarga.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makefile.ansi b/jpg/makefile.ansi
new file mode 100644
index 0000000..7d0499f
--- /dev/null
+++ b/jpg/makefile.ansi
@@ -0,0 +1,221 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Unix-like systems with ANSI-capable compilers.
+# If you have a non-ANSI compiler, makefile.unix is a better starting point.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= cc
+
+# You may need to adjust these cc options:
+CFLAGS= -O
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+LDFLAGS=
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS=
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# file deletion command
+RM= rm -f
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+ jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+ jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+ jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+ jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+ jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+ jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+libjpeg.a: $(LIBOBJECTS)
+ $(RM) libjpeg.a
+ $(AR) libjpeg.a $(LIBOBJECTS)
+ $(AR2) libjpeg.a
+
+cjpeg: $(COBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.txt
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.txt.
+ exit 1
+
+clean:
+ $(RM) *.o cjpeg djpeg jpegtran libjpeg.a rdjpgcom wrjpgcom
+ $(RM) core testout*
+
+test: cjpeg djpeg jpegtran
+ $(RM) testout*
+ ./djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ ./jpegtran -outfile testoutt.jpg testprog.jpg
+ cmp testimg.ppm testout.ppm
+ cmp testimg.bmp testout.bmp
+ cmp testimg.jpg testout.jpg
+ cmp testimg.ppm testoutp.ppm
+ cmp testimgp.jpg testoutp.jpg
+ cmp testorig.jpg testoutt.jpg
+
+
+jaricom.o: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.o: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.o: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/jpg/makefile.bcc b/jpg/makefile.bcc
new file mode 100644
index 0000000..d89e09b
--- /dev/null
+++ b/jpg/makefile.bcc
@@ -0,0 +1,292 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Borland C on MS-DOS or OS/2.
+# It works with Borland C++ for DOS, revision 3.0 or later,
+# and has been tested with Borland C++ for OS/2.
+# Watch out for optimization bugs in the OS/2 compilers --- see notes below!
+# Thanks to Tom Wright and Ge' Weijers (original DOS) and
+# Ken Porter (OS/2) for this file.
+
+# Read installation instructions before saying "make" !!
+
+# Are we under DOS or OS/2?
+!if !$d(DOS) && !$d(OS2)
+!if $d(__OS2__)
+OS2=1
+!else
+DOS=1
+!endif
+!endif
+
+# The name of your C compiler:
+CC= bcc
+
+# You may need to adjust these cc options:
+!if $d(DOS)
+CFLAGS= -O2 -mm -w-par -w-stu -w-ccc -w-rch
+!else
+CFLAGS= -O1 -w-par -w-stu -w-ccc -w-rch
+!endif
+# -O2 enables full code optimization (for pre-3.0 Borland C++, use -O -G -Z).
+# -O2 is buggy in Borland OS/2 C++ revision 2.0, so use -O1 there for now.
+# If you have Borland OS/2 C++ revision 1.0, use -O or no optimization at all.
+# -mm selects medium memory model (near data, far code pointers; DOS only!)
+# -w-par suppresses warnings about unused function parameters
+# -w-stu suppresses warnings about incomplete structures
+# -w-ccc suppresses warnings about compile-time-constant conditions
+# -w-rch suppresses warnings about unreachable code
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+!if $d(DOS)
+LDFLAGS= -mm
+# memory model option here must match CFLAGS!
+!else
+LDFLAGS=
+# -lai full-screen app
+# -lc case-significant link
+!endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file.
+# For DOS, we recommend jmemdos.c and jmemdosa.asm.
+# For OS/2, we recommend jmemnobs.c (flat memory!)
+# SYSDEPMEMLIB must list the same files with "+" signs for the librarian.
+!if $d(DOS)
+SYSDEPMEM= jmemdos.obj jmemdosa.obj
+SYSDEPMEMLIB= +jmemdos.obj +jmemdosa.obj
+!else
+SYSDEPMEM= jmemnobs.obj
+SYSDEPMEMLIB= +jmemnobs.obj
+!endif
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj \
+ jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj \
+ jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj \
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj \
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj \
+ jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj \
+ jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj \
+ jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS)
+ - del libjpeg.lib
+ tlib libjpeg.lib /E /C @&&|
++jcapimin.obj +jcapistd.obj +jcarith.obj +jctrans.obj +jcparam.obj &
++jdatadst.obj +jcinit.obj +jcmaster.obj +jcmarker.obj +jcmainct.obj &
++jcprepct.obj +jccoefct.obj +jccolor.obj +jcsample.obj +jchuff.obj &
++jcdctmgr.obj +jfdctfst.obj +jfdctflt.obj +jfdctint.obj +jdapimin.obj &
++jdapistd.obj +jdarith.obj +jdtrans.obj +jdatasrc.obj +jdmaster.obj &
++jdinput.obj +jdmarker.obj +jdhuff.obj +jdmainct.obj +jdcoefct.obj &
++jdpostct.obj +jddctmgr.obj +jidctfst.obj +jidctflt.obj +jidctint.obj &
++jdsample.obj +jdcolor.obj +jquant1.obj +jquant2.obj +jdmerge.obj &
++jaricom.obj +jcomapi.obj +jutils.obj +jerror.obj +jmemmgr.obj &
+$(SYSDEPMEMLIB)
+|
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) -ecjpeg.exe $(COBJECTS) libjpeg.lib
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) -edjpeg.exe $(DOBJECTS) libjpeg.lib
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) -ejpegtran.exe $(TROBJECTS) libjpeg.lib
+
+rdjpgcom.exe: rdjpgcom.c
+!if $d(DOS)
+ $(CC) -ms -O rdjpgcom.c
+!else
+ $(CC) $(CFLAGS) rdjpgcom.c
+!endif
+
+# On DOS, wrjpgcom needs large model so it can malloc a 64K chunk
+wrjpgcom.exe: wrjpgcom.c
+!if $d(DOS)
+ $(CC) -ml -O wrjpgcom.c
+!else
+ $(CC) $(CFLAGS) wrjpgcom.c
+!endif
+
+# This "{}" syntax allows Borland Make to "batch" source files.
+# In this way, each run of the compiler can build many modules.
+.c.obj:
+ $(CC) $(CFLAGS) -c{ $<}
+
+jconfig.h: jconfig.txt
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.txt.
+ exit 1
+
+clean:
+ - del *.obj
+ - del libjpeg.lib
+ - del cjpeg.exe
+ - del djpeg.exe
+ - del jpegtran.exe
+ - del rdjpgcom.exe
+ - del wrjpgcom.exe
+ - del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe
+ - del testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+!if $d(DOS)
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.bmp testout.bmp
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+!else
+ echo n > n.tmp
+ comp testimg.ppm testout.ppm < n.tmp
+ comp testimg.bmp testout.bmp < n.tmp
+ comp testimg.jpg testout.jpg < n.tmp
+ comp testimg.ppm testoutp.ppm < n.tmp
+ comp testimgp.jpg testoutp.jpg < n.tmp
+ comp testorig.jpg testoutt.jpg < n.tmp
+ del n.tmp
+!endif
+
+
+jaricom.obj: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+jmemdosa.obj: jmemdosa.asm
+ tasm /mx jmemdosa.asm
diff --git a/jpg/makefile.dj b/jpg/makefile.dj
new file mode 100644
index 0000000..37b6ee7
--- /dev/null
+++ b/jpg/makefile.dj
@@ -0,0 +1,227 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for DJGPP (Delorie's GNU C port on MS-DOS), v2.0 or later.
+# Thanks to Frank J. Donahoe for this version.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= gcc
+
+# You may need to adjust these cc options:
+CFLAGS= -O2 -Wall -I.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+LDFLAGS= -s
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS=
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For DJGPP this is usually jmemnobs.o, but you could
+# use jmemname.o if you want to use named temp files instead of swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# file deletion command
+RM= del
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+ jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+ jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+ jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+ jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+ jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+ jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: libjpeg.a cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.a: $(LIBOBJECTS)
+ $(RM) libjpeg.a
+ $(AR) libjpeg.a $(LIBOBJECTS)
+ $(AR2) libjpeg.a
+
+cjpeg.exe: $(COBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o cjpeg.exe $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg.exe: $(DOBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o djpeg.exe $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran.exe: $(TROBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o jpegtran.exe $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom.exe: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom.exe rdjpgcom.o $(LDLIBS)
+
+wrjpgcom.exe: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom.exe wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.txt
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.txt.
+ exit 1
+
+clean:
+ $(RM) *.o
+ $(RM) cjpeg.exe
+ $(RM) djpeg.exe
+ $(RM) jpegtran.exe
+ $(RM) rdjpgcom.exe
+ $(RM) wrjpgcom.exe
+ $(RM) libjpeg.a
+ $(RM) testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe
+ $(RM) testout*.*
+ ./djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ ./jpegtran -outfile testoutt.jpg testprog.jpg
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.bmp testout.bmp
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+
+
+jaricom.o: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.o: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.o: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/jpg/makefile.manx b/jpg/makefile.manx
new file mode 100644
index 0000000..471f408
--- /dev/null
+++ b/jpg/makefile.manx
@@ -0,0 +1,221 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Amiga systems using Manx Aztec C ver 5.x.
+# Thanks to D.J. James (djjames@cup.portal.com) for this version.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= cc
+
+# You may need to adjust these cc options:
+# Uncomment for generic 68000 code (will work on any Amiga)
+ARCHFLAGS= -sn
+
+# Uncomment for 68020/68030 code (faster, but won't run on 68000 CPU)
+#ARCHFLAGS= -c2
+
+CFLAGS= -MC -MD $(ARCHFLAGS) -spfam -r4
+
+# Link-time cc options:
+LDFLAGS= -g
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS= -lml -lcl
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Amiga we recommend jmemname.o.
+SYSDEPMEM= jmemname.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= ln
+# file deletion command
+RM= delete quiet
+# library (.lib) file creation command
+AR= lb
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+ jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+ jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+ jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+ jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+ jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+ jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: libjpeg.lib cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+libjpeg.lib: $(LIBOBJECTS)
+ -$(RM) libjpeg.lib
+ $(AR) libjpeg.lib $(LIBOBJECTS)
+
+cjpeg: $(COBJECTS) libjpeg.lib
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.lib $(LDLIBS)
+
+djpeg: $(DOBJECTS) libjpeg.lib
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.lib $(LDLIBS)
+
+jpegtran: $(TROBJECTS) libjpeg.lib
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.lib $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.txt
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.txt.
+ exit 1
+
+clean:
+ -$(RM) *.o cjpeg djpeg jpegtran libjpeg.lib rdjpgcom wrjpgcom
+ -$(RM) core testout*.*
+
+test: cjpeg djpeg jpegtran
+ -$(RM) testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+ cmp testimg.ppm testout.ppm
+ cmp testimg.bmp testout.bmp
+ cmp testimg.jpg testout.jpg
+ cmp testimg.ppm testoutp.ppm
+ cmp testimgp.jpg testoutp.jpg
+ cmp testorig.jpg testoutt.jpg
+
+
+jaricom.o: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.o: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.o: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/jpg/makefile.mc6 b/jpg/makefile.mc6
new file mode 100644
index 0000000..1ee83be
--- /dev/null
+++ b/jpg/makefile.mc6
@@ -0,0 +1,256 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Microsoft C for MS-DOS, version 6.00A and up.
+# Use NMAKE, not Microsoft's brain-damaged MAKE.
+# Thanks to Alan Wright and Chris Turner of Olivetti Research Ltd.
+
+# Read installation instructions before saying "nmake" !!
+
+# You may need to adjust these compiler options:
+CFLAGS = -AM -Oecigt -Gs -W3
+# -AM medium memory model (or use -AS for small model, if you remove features)
+# -Oecigt -Gs maximum safe optimisation (-Ol has bugs in MSC 6.00A)
+# -W3 warning level 3
+# You might also want to add -G2 if you have an 80286, etc.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Jan-Herman Buining suggests the following switches for MS C 8.0 and a 486:
+# CFLAGS = /AM /f- /FPi87 /G3 /Gs /Gy /Ob1 /Oc /Oe /Og /Oi /Ol /On /Oo /Ot \
+# /OV4 /W3
+# except for jquant1.c, which must be compiled with /Oo- to avoid a compiler
+# crash.
+
+# Ingar Steinsland suggests the following switches when building
+# a 16-bit Windows DLL:
+# CFLAGS = -ALw -Gsw -Zpe -W3 -O2 -Zi -Zd
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For DOS, we recommend jmemdos.c and jmemdosa.asm.
+# (But not for Windows; see install.txt if you use this makefile for Windows.)
+SYSDEPMEM= jmemdos.obj jmemdosa.obj
+# SYSDEPMEMLIB must list the same files with "+" signs for the librarian.
+SYSDEPMEMLIB= +jmemdos.obj +jmemdosa.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj \
+ jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj \
+ jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj \
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj \
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj \
+ jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj \
+ jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj \
+ jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+
+# need linker response file because file list > 128 chars
+RFILE = libjpeg.ans
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS) $(RFILE)
+ del libjpeg.lib
+ lib @$(RFILE)
+
+# linker response file for building libjpeg.lib
+$(RFILE) : makefile
+ del $(RFILE)
+ echo libjpeg.lib >$(RFILE)
+# silly want-to-create-it prompt:
+ echo y >>$(RFILE)
+ echo +jcapimin.obj +jcapistd.obj +jcarith.obj +jctrans.obj & >>$(RFILE)
+ echo +jcparam.obj +jdatadst.obj +jcinit.obj +jcmaster.obj & >>$(RFILE)
+ echo +jcmarker.obj +jcmainct.obj +jcprepct.obj & >>$(RFILE)
+ echo +jccoefct.obj +jccolor.obj +jcsample.obj +jchuff.obj & >>$(RFILE)
+ echo +jcdctmgr.obj +jfdctfst.obj +jfdctflt.obj & >>$(RFILE)
+ echo +jfdctint.obj +jdapimin.obj +jdapistd.obj & >>$(RFILE)
+ echo +jdarith.obj +jdtrans.obj +jdatasrc.obj +jdmaster.obj & >>$(RFILE)
+ echo +jdinput.obj +jdmarker.obj +jdhuff.obj +jdmainct.obj & >>$(RFILE)
+ echo +jdcoefct.obj +jdpostct.obj +jddctmgr.obj & >>$(RFILE)
+ echo +jidctfst.obj +jidctflt.obj +jidctint.obj & >>$(RFILE)
+ echo +jdsample.obj +jdcolor.obj +jquant1.obj & >>$(RFILE)
+ echo +jquant2.obj +jdmerge.obj +jaricom.obj +jcomapi.obj & >>$(RFILE)
+ echo +jutils.obj +jerror.obj +jmemmgr.obj & >>$(RFILE)
+ echo $(SYSDEPMEMLIB) ; >>$(RFILE)
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+ echo $(COBJECTS) >cjpeg.lst
+ link /STACK:4096 /EXEPACK @cjpeg.lst, cjpeg.exe, , libjpeg.lib, ;
+ del cjpeg.lst
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+ echo $(DOBJECTS) >djpeg.lst
+ link /STACK:4096 /EXEPACK @djpeg.lst, djpeg.exe, , libjpeg.lib, ;
+ del djpeg.lst
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+ link /STACK:4096 /EXEPACK $(TROBJECTS), jpegtran.exe, , libjpeg.lib, ;
+
+rdjpgcom.exe: rdjpgcom.c
+ $(CC) -AS -O -W3 rdjpgcom.c
+
+# wrjpgcom needs large model so it can malloc a 64K chunk
+wrjpgcom.exe: wrjpgcom.c
+ $(CC) -AL -O -W3 wrjpgcom.c
+
+jconfig.h: jconfig.txt
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.txt.
+ exit 1
+
+clean:
+ del *.obj
+ del libjpeg.lib
+ del cjpeg.exe
+ del djpeg.exe
+ del jpegtran.exe
+ del rdjpgcom.exe
+ del wrjpgcom.exe
+ del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe
+ del testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.bmp testout.bmp
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+
+
+jaricom.obj: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+jmemdosa.obj : jmemdosa.asm
+ masm /mx $*;
diff --git a/jpg/makefile.mms b/jpg/makefile.mms
new file mode 100644
index 0000000..6019dfa
--- /dev/null
+++ b/jpg/makefile.mms
@@ -0,0 +1,225 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for use with MMS on Digital VMS systems.
+# Thanks to Rick Dyson (dyson@iowasp.physics.uiowa.edu)
+# and Tim Bell (tbell@netcom.com) for their help.
+
+# Read installation instructions before saying "MMS" !!
+
+# You may need to adjust these cc options:
+CFLAGS= $(CFLAGS) /NoDebug /Optimize
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via /Define switches here.
+.ifdef ALPHA
+OPT=
+.else
+OPT= ,Sys$Disk:[]MAKVMS.OPT/Option
+.endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj \
+ jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj \
+ jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj \
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj \
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj \
+ jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj \
+ jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj \
+ jdmerge.obj
+# These objectfiles are included in libjpeg.olb
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+# objectfile lists with commas --- what a crock
+COBJLIST= cjpeg.obj,rdppm.obj,rdgif.obj,rdtarga.obj,rdrle.obj,rdbmp.obj,\
+ rdswitch.obj,cdjpeg.obj
+DOBJLIST= djpeg.obj,wrppm.obj,wrgif.obj,wrtarga.obj,wrrle.obj,wrbmp.obj,\
+ rdcolmap.obj,cdjpeg.obj
+TROBJLIST= jpegtran.obj,rdswitch.obj,cdjpeg.obj,transupp.obj
+LIBOBJLIST= jaricom.obj,jcapimin.obj,jcapistd.obj,jcarith.obj,jctrans.obj,\
+ jcparam.obj,jdatadst.obj,jcinit.obj,jcmaster.obj,jcmarker.obj,\
+ jcmainct.obj,jcprepct.obj,jccoefct.obj,jccolor.obj,jcsample.obj,\
+ jchuff.obj,jcdctmgr.obj,jfdctfst.obj,jfdctflt.obj,jfdctint.obj,\
+ jdapimin.obj,jdapistd.obj,jdarith.obj,jdtrans.obj,jdatasrc.obj,\
+ jdmaster.obj,jdinput.obj,jdmarker.obj,jdhuff.obj,jdmainct.obj,\
+ jdcoefct.obj,jdpostct.obj,jddctmgr.obj,jidctfst.obj,jidctflt.obj,\
+ jidctint.obj,jdsample.obj,jdcolor.obj,jquant1.obj,jquant2.obj,\
+ jdmerge.obj,jcomapi.obj,jutils.obj,jerror.obj,jmemmgr.obj,$(SYSDEPMEM)
+
+
+.first
+ @- Define /NoLog Sys Sys$Library
+
+ALL : libjpeg.olb cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+ @ Continue
+
+libjpeg.olb : $(LIBOBJECTS)
+ Library /Create libjpeg.olb $(LIBOBJLIST)
+
+cjpeg.exe : $(COBJECTS) libjpeg.olb
+ $(LINK) $(LFLAGS) /Executable = cjpeg.exe $(COBJLIST),libjpeg.olb/Library$(OPT)
+
+djpeg.exe : $(DOBJECTS) libjpeg.olb
+ $(LINK) $(LFLAGS) /Executable = djpeg.exe $(DOBJLIST),libjpeg.olb/Library$(OPT)
+
+jpegtran.exe : $(TROBJECTS) libjpeg.olb
+ $(LINK) $(LFLAGS) /Executable = jpegtran.exe $(TROBJLIST),libjpeg.olb/Library$(OPT)
+
+rdjpgcom.exe : rdjpgcom.obj
+ $(LINK) $(LFLAGS) /Executable = rdjpgcom.exe rdjpgcom.obj$(OPT)
+
+wrjpgcom.exe : wrjpgcom.obj
+ $(LINK) $(LFLAGS) /Executable = wrjpgcom.exe wrjpgcom.obj$(OPT)
+
+jconfig.h : jconfig.vms
+ @- Copy jconfig.vms jconfig.h
+
+clean :
+ @- Set Protection = Owner:RWED *.*;-1
+ @- Set Protection = Owner:RWED *.OBJ
+ - Purge /NoLog /NoConfirm *.*
+ - Delete /NoLog /NoConfirm *.OBJ;
+
+test : cjpeg.exe djpeg.exe jpegtran.exe
+ mcr sys$disk:[]djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ mcr sys$disk:[]djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ mcr sys$disk:[]cjpeg -dct int -outfile testout.jpg testimg.ppm
+ mcr sys$disk:[]djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ mcr sys$disk:[]cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ mcr sys$disk:[]jpegtran -outfile testoutt.jpg testprog.jpg
+ - Backup /Compare/Log testimg.ppm testout.ppm
+ - Backup /Compare/Log testimg.bmp testout.bmp
+ - Backup /Compare/Log testimg.jpg testout.jpg
+ - Backup /Compare/Log testimg.ppm testoutp.ppm
+ - Backup /Compare/Log testimgp.jpg testoutp.jpg
+ - Backup /Compare/Log testorig.jpg testoutt.jpg
+
+
+jaricom.obj : jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj : jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj : jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj : jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj : jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj : jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj : jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj : jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj : jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj : jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj : jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj : jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj : jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj : jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj : jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj : jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj : jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj : jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj : jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj : jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj : jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj : jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj : jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj : jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj : jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj : jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj : jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj : jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj : jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj : jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj : jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj : jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj : jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj : jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj : jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj : jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj : jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj : jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj : jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj : jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj : jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj : jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj : jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj : jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj : jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj : jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj : jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj : jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj : jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj : jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj : cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj : djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj : jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj : rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj : wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj : cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj : rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj : rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj : transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj : rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj : wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj : rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj : wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj : rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj : wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj : rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj : wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj : rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj : wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/jpg/makefile.sas b/jpg/makefile.sas
new file mode 100644
index 0000000..252f8fb
--- /dev/null
+++ b/jpg/makefile.sas
@@ -0,0 +1,259 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Amiga systems using SAS C 6.0 and up.
+# Thanks to Ed Hanway, Mark Rinfret, and Jim Zepeda.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= sc
+
+# You may need to adjust these cc options:
+# Uncomment the following lines for generic 680x0 version
+ARCHFLAGS= cpu=any
+SUFFIX=
+
+# Uncomment the following lines for 68030-only version
+#ARCHFLAGS= cpu=68030
+#SUFFIX=.030
+
+CFLAGS= nostackcheck data=near parms=register optimize $(ARCHFLAGS) \
+ ignore=104 ignore=304 ignore=306
+# ignore=104 disables warnings for mismatched const qualifiers
+# ignore=304 disables warnings for variables being optimized out
+# ignore=306 disables warnings for the inlining of functions
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via define switches here.
+
+# Link-time cc options:
+LDFLAGS= SC SD ND BATCH
+
+# To link any special libraries, add the necessary commands here.
+LDLIBS= LIB:scm.lib LIB:sc.lib
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Amiga we recommend jmemname.o.
+SYSDEPMEM= jmemname.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= slink
+# file deletion command
+RM= delete quiet
+# library (.lib) file creation command
+AR= oml
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+ jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+ jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+ jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+ jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+ jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+ jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: libjpeg.lib cjpeg$(SUFFIX) djpeg$(SUFFIX) jpegtran$(SUFFIX) rdjpgcom$(SUFFIX) wrjpgcom$(SUFFIX)
+
+# note: do several AR steps to avoid command line length limitations
+
+libjpeg.lib: $(LIBOBJECTS)
+ -$(RM) libjpeg.lib
+ $(AR) libjpeg.lib r $(CLIBOBJECTS)
+ $(AR) libjpeg.lib r $(DLIBOBJECTS)
+ $(AR) libjpeg.lib r $(COMOBJECTS)
+
+cjpeg$(SUFFIX): $(COBJECTS) libjpeg.lib
+ $(LN) <WITH <
+$(LDFLAGS)
+TO cjpeg$(SUFFIX)
+FROM LIB:c.o $(COBJECTS)
+LIB libjpeg.lib $(LDLIBS)
+<
+
+djpeg$(SUFFIX): $(DOBJECTS) libjpeg.lib
+ $(LN) <WITH <
+$(LDFLAGS)
+TO djpeg$(SUFFIX)
+FROM LIB:c.o $(DOBJECTS)
+LIB libjpeg.lib $(LDLIBS)
+<
+
+jpegtran$(SUFFIX): $(TROBJECTS) libjpeg.lib
+ $(LN) <WITH <
+$(LDFLAGS)
+TO jpegtran$(SUFFIX)
+FROM LIB:c.o $(TROBJECTS)
+LIB libjpeg.lib $(LDLIBS)
+<
+
+rdjpgcom$(SUFFIX): rdjpgcom.o
+ $(LN) <WITH <
+$(LDFLAGS)
+TO rdjpgcom$(SUFFIX)
+FROM LIB:c.o rdjpgcom.o
+LIB $(LDLIBS)
+<
+
+wrjpgcom$(SUFFIX): wrjpgcom.o
+ $(LN) <WITH <
+$(LDFLAGS)
+TO wrjpgcom$(SUFFIX)
+FROM LIB:c.o wrjpgcom.o
+LIB $(LDLIBS)
+<
+
+jconfig.h: jconfig.txt
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.txt.
+ exit 1
+
+clean:
+ -$(RM) *.o cjpeg djpeg jpegtran cjpeg.030 djpeg.030 jpegtran.030
+ -$(RM) rdjpgcom wrjpgcom rdjpgcom.030 wrjpgcom.030
+ -$(RM) libjpeg.lib core testout*.*
+
+test: cjpeg djpeg jpegtran
+ -$(RM) testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+ cmp testimg.ppm testout.ppm
+ cmp testimg.bmp testout.bmp
+ cmp testimg.jpg testout.jpg
+ cmp testimg.ppm testoutp.ppm
+ cmp testimgp.jpg testoutp.jpg
+ cmp testorig.jpg testoutt.jpg
+
+
+jaricom.o: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.o: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.o: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/jpg/makefile.unix b/jpg/makefile.unix
new file mode 100644
index 0000000..eaadfc1
--- /dev/null
+++ b/jpg/makefile.unix
@@ -0,0 +1,235 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Unix-like systems with non-ANSI compilers.
+# If you have an ANSI compiler, makefile.ansi is a better starting point.
+
+# Read installation instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= cc
+
+# You may need to adjust these cc options:
+CFLAGS= -O
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+# However, any special defines for ansi2knr.c may be included here:
+ANSI2KNRFLAGS=
+
+# Link-time cc options:
+LDFLAGS=
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS=
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For Unix this is usually jmemnobs.o, but you may want
+# to use jmemansi.o or jmemname.o if you have limited swap space.
+SYSDEPMEM= jmemnobs.o
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# file deletion command
+RM= rm -f
+# file rename command
+MV= mv
+# library (.a) file creation command
+AR= ar rc
+# second step in .a creation (use "touch" if not needed)
+AR2= ranlib
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.o jcomapi.o jutils.o jerror.o jmemmgr.o $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.o jcapistd.o jcarith.o jctrans.o jcparam.o \
+ jdatadst.o jcinit.o jcmaster.o jcmarker.o jcmainct.o jcprepct.o \
+ jccoefct.o jccolor.o jcsample.o jchuff.o jcdctmgr.o jfdctfst.o \
+ jfdctflt.o jfdctint.o
+# decompression library object files
+DLIBOBJECTS= jdapimin.o jdapistd.o jdarith.o jdtrans.o jdatasrc.o \
+ jdmaster.o jdinput.o jdmarker.o jdhuff.o jdmainct.o \
+ jdcoefct.o jdpostct.o jddctmgr.o jidctfst.o jidctflt.o \
+ jidctint.o jdsample.o jdcolor.o jquant1.o jquant2.o jdmerge.o
+# These objectfiles are included in libjpeg.a
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.o rdppm.o rdgif.o rdtarga.o rdrle.o rdbmp.o rdswitch.o \
+ cdjpeg.o
+DOBJECTS= djpeg.o wrppm.o wrgif.o wrtarga.o wrrle.o wrbmp.o rdcolmap.o \
+ cdjpeg.o
+TROBJECTS= jpegtran.o rdswitch.o cdjpeg.o transupp.o
+
+
+all: ansi2knr libjpeg.a cjpeg djpeg jpegtran rdjpgcom wrjpgcom
+
+# This rule causes ansi2knr to be invoked.
+.c.o:
+ ./ansi2knr $*.c T$*.c
+ $(CC) $(CFLAGS) -c T$*.c
+ $(RM) T$*.c $*.o
+ $(MV) T$*.o $*.o
+
+ansi2knr: ansi2knr.c
+ $(CC) $(CFLAGS) $(ANSI2KNRFLAGS) -o ansi2knr ansi2knr.c
+
+libjpeg.a: ansi2knr $(LIBOBJECTS)
+ $(RM) libjpeg.a
+ $(AR) libjpeg.a $(LIBOBJECTS)
+ $(AR2) libjpeg.a
+
+cjpeg: ansi2knr $(COBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o cjpeg $(COBJECTS) libjpeg.a $(LDLIBS)
+
+djpeg: ansi2knr $(DOBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o djpeg $(DOBJECTS) libjpeg.a $(LDLIBS)
+
+jpegtran: ansi2knr $(TROBJECTS) libjpeg.a
+ $(LN) $(LDFLAGS) -o jpegtran $(TROBJECTS) libjpeg.a $(LDLIBS)
+
+rdjpgcom: rdjpgcom.o
+ $(LN) $(LDFLAGS) -o rdjpgcom rdjpgcom.o $(LDLIBS)
+
+wrjpgcom: wrjpgcom.o
+ $(LN) $(LDFLAGS) -o wrjpgcom wrjpgcom.o $(LDLIBS)
+
+jconfig.h: jconfig.txt
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.txt.
+ exit 1
+
+clean:
+ $(RM) *.o cjpeg djpeg jpegtran libjpeg.a rdjpgcom wrjpgcom
+ $(RM) ansi2knr core testout*
+
+test: cjpeg djpeg jpegtran
+ $(RM) testout*
+ ./djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ ./djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ ./cjpeg -dct int -outfile testout.jpg testimg.ppm
+ ./djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ ./cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ ./jpegtran -outfile testoutt.jpg testprog.jpg
+ cmp testimg.ppm testout.ppm
+ cmp testimg.bmp testout.bmp
+ cmp testimg.jpg testout.jpg
+ cmp testimg.ppm testoutp.ppm
+ cmp testimgp.jpg testoutp.jpg
+ cmp testorig.jpg testoutt.jpg
+
+
+jaricom.o: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.o: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.o: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.o: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.o: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.o: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.o: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.o: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.o: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.o: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.o: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.o: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.o: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.o: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.o: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.o: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.o: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.o: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.o: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.o: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.o: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.o: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.o: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.o: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.o: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.o: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.o: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.o: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.o: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.o: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.o: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.o: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.o: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.o: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.o: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.o: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.o: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.o: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.o: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.o: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.o: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.o: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.o: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.o: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.o: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.o: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.o: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.o: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.o: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.o: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.o: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.o: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.o: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.o: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.o: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.o: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.o: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.o: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.o: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.o: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.o: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.o: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.o: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.o: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.o: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.o: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.o: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.o: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.o: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/jpg/makefile.vc b/jpg/makefile.vc
new file mode 100644
index 0000000..d4df9d4
--- /dev/null
+++ b/jpg/makefile.vc
@@ -0,0 +1,273 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Microsoft Visual C++ on Windows NT (and 95?).
+# It builds the IJG library as a statically linkable library (.LIB),
+# and builds the sample applications as console-mode apps.
+# Thanks to Xingong Chang, Raymond Everly and others.
+
+# Read installation instructions before saying "nmake" !!
+# To build an optimized library without debug info, say "nmake nodebug=1".
+
+# Pull in standard variable definitions
+!include <win32.mak>
+
+# You may want to adjust these compiler options:
+CFLAGS= $(cflags) $(cdebug) $(cvars) -I.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time options:
+LDFLAGS= $(ldebug) $(conlflags)
+
+# To link any special libraries, add the necessary commands here.
+LDLIBS= $(conlibs)
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. For NT we suggest jmemnobs.obj, which expects the OS to
+# provide adequate virtual memory.
+SYSDEPMEM= jmemnobs.obj
+
+# miscellaneous OS-dependent stuff
+# file deletion command
+RM= del
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c \
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c \
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c \
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c \
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c \
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c \
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c \
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c \
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h \
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 \
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt \
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc \
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 \
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 \
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 \
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 \
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 \
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 \
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 \
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st \
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas \
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat \
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas \
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm \
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg \
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) \
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj \
+ jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj \
+ jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj \
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj \
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj \
+ jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj \
+ jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj \
+ jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj \
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj \
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+
+# Template command for compiling .c to .obj
+.c.obj:
+ $(cc) $(CFLAGS) $*.c
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS)
+ $(RM) libjpeg.lib
+ lib -out:libjpeg.lib $(LIBOBJECTS)
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+ $(link) $(LDFLAGS) -out:cjpeg.exe $(COBJECTS) libjpeg.lib $(LDLIBS)
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+ $(link) $(LDFLAGS) -out:djpeg.exe $(DOBJECTS) libjpeg.lib $(LDLIBS)
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+ $(link) $(LDFLAGS) -out:jpegtran.exe $(TROBJECTS) libjpeg.lib $(LDLIBS)
+
+rdjpgcom.exe: rdjpgcom.obj
+ $(link) $(LDFLAGS) -out:rdjpgcom.exe rdjpgcom.obj $(LDLIBS)
+
+wrjpgcom.exe: wrjpgcom.obj
+ $(link) $(LDFLAGS) -out:wrjpgcom.exe wrjpgcom.obj $(LDLIBS)
+
+
+clean:
+ $(RM) *.obj *.exe libjpeg.lib
+ $(RM) testout*
+
+setup-vc6:
+ ren jconfig.vc jconfig.h
+ ren makejdsw.vc6 jpeg.dsw
+ ren makeadsw.vc6 apps.dsw
+ ren makejmak.vc6 jpeg.mak
+ ren makejdep.vc6 jpeg.dep
+ ren makejdsp.vc6 jpeg.dsp
+ ren makecmak.vc6 cjpeg.mak
+ ren makecdep.vc6 cjpeg.dep
+ ren makecdsp.vc6 cjpeg.dsp
+ ren makedmak.vc6 djpeg.mak
+ ren makeddep.vc6 djpeg.dep
+ ren makeddsp.vc6 djpeg.dsp
+ ren maketmak.vc6 jpegtran.mak
+ ren maketdep.vc6 jpegtran.dep
+ ren maketdsp.vc6 jpegtran.dsp
+ ren makermak.vc6 rdjpgcom.mak
+ ren makerdep.vc6 rdjpgcom.dep
+ ren makerdsp.vc6 rdjpgcom.dsp
+ ren makewmak.vc6 wrjpgcom.mak
+ ren makewdep.vc6 wrjpgcom.dep
+ ren makewdsp.vc6 wrjpgcom.dsp
+
+setup-v10:
+ ren jconfig.vc jconfig.h
+ ren makejsln.v10 jpeg.sln
+ ren makeasln.v10 apps.sln
+ ren makejvcx.v10 jpeg.vcxproj
+ ren makejfil.v10 jpeg.vcxproj.filters
+ ren makecvcx.v10 cjpeg.vcxproj
+ ren makecfil.v10 cjpeg.vcxproj.filters
+ ren makedvcx.v10 djpeg.vcxproj
+ ren makedfil.v10 djpeg.vcxproj.filters
+ ren maketvcx.v10 jpegtran.vcxproj
+ ren maketfil.v10 jpegtran.vcxproj.filters
+ ren makervcx.v10 rdjpgcom.vcxproj
+ ren makerfil.v10 rdjpgcom.vcxproj.filters
+ ren makewvcx.v10 wrjpgcom.vcxproj
+ ren makewfil.v10 wrjpgcom.vcxproj.filters
+
+test:
+ IF EXIST testout* $(RM) testout*
+ .\djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ .\djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ .\cjpeg -dct int -outfile testout.jpg testimg.ppm
+ .\djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ .\cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ .\jpegtran -outfile testoutt.jpg testprog.jpg
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.bmp testout.bmp
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+
+test-build:
+ IF EXIST testout* $(RM) testout*
+ .\djpeg\Release\djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ .\djpeg\Release\djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ .\cjpeg\Release\cjpeg -dct int -outfile testout.jpg testimg.ppm
+ .\djpeg\Release\djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ .\cjpeg\Release\cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ .\jpegtran\Release\jpegtran -outfile testoutt.jpg testprog.jpg
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.bmp testout.bmp
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+
+
+jaricom.obj: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/jpg/makefile.vms b/jpg/makefile.vms
new file mode 100644
index 0000000..a07d070
--- /dev/null
+++ b/jpg/makefile.vms
@@ -0,0 +1,142 @@
+$! Makefile for Independent JPEG Group's software
+$!
+$! This is a command procedure for Digital VMS systems that do not have MMS.
+$! It builds the JPEG software by brute force, recompiling everything whether
+$! or not it is necessary. It then runs the basic self-test.
+$! Thanks to Rick Dyson (dyson@iowasp.physics.uiowa.edu)
+$! and Tim Bell (tbell@netcom.com) for their help.
+$!
+$! Read installation instructions before running this!!
+$!
+$ If F$Mode () .eqs. "INTERACTIVE"
+$ Then
+$ VERIFY = F$Verify (0)
+$ Else
+$ VERIFY = F$Verify (1)
+$ EndIf
+$ On Control_Y Then GoTo End
+$ On Error Then GoTo End
+$
+$ If F$GetSyi ("HW_MODEL") .gt. 1023
+$ Then
+$ OPT = ""
+$ Else
+$ OPT = ",Sys$Disk:[]makvms.opt/Option"
+$ EndIf
+$
+$ DoCompile := CC /NoDebug /Optimize /NoList
+$!
+$ DoCompile jaricom.c
+$ DoCompile jcapimin.c
+$ DoCompile jcapistd.c
+$ DoCompile jcarith.c
+$ DoCompile jctrans.c
+$ DoCompile jcparam.c
+$ DoCompile jdatadst.c
+$ DoCompile jcinit.c
+$ DoCompile jcmaster.c
+$ DoCompile jcmarker.c
+$ DoCompile jcmainct.c
+$ DoCompile jcprepct.c
+$ DoCompile jccoefct.c
+$ DoCompile jccolor.c
+$ DoCompile jcsample.c
+$ DoCompile jchuff.c
+$ DoCompile jcdctmgr.c
+$ DoCompile jfdctfst.c
+$ DoCompile jfdctflt.c
+$ DoCompile jfdctint.c
+$ DoCompile jdapimin.c
+$ DoCompile jdapistd.c
+$ DoCompile jdarith.c
+$ DoCompile jdtrans.c
+$ DoCompile jdatasrc.c
+$ DoCompile jdmaster.c
+$ DoCompile jdinput.c
+$ DoCompile jdmarker.c
+$ DoCompile jdhuff.c
+$ DoCompile jdmainct.c
+$ DoCompile jdcoefct.c
+$ DoCompile jdpostct.c
+$ DoCompile jddctmgr.c
+$ DoCompile jidctfst.c
+$ DoCompile jidctflt.c
+$ DoCompile jidctint.c
+$ DoCompile jdsample.c
+$ DoCompile jdcolor.c
+$ DoCompile jquant1.c
+$ DoCompile jquant2.c
+$ DoCompile jdmerge.c
+$ DoCompile jcomapi.c
+$ DoCompile jutils.c
+$ DoCompile jerror.c
+$ DoCompile jmemmgr.c
+$ DoCompile jmemnobs.c
+$!
+$ Library /Create libjpeg.olb jaricom.obj,jcapimin.obj,jcapistd.obj, -
+ jcarith.obj,jctrans.obj,jcparam.obj,jdatadst.obj,jcinit.obj, -
+ jcmaster.obj,jcmarker.obj,jcmainct.obj,jcprepct.obj,jccoefct.obj, -
+ jccolor.obj,jcsample.obj,jchuff.obj,jcdctmgr.obj,jfdctfst.obj, -
+ jfdctflt.obj,jfdctint.obj,jdapimin.obj,jdapistd.obj,jdarith.obj, -
+ jdtrans.obj,jdatasrc.obj,jdmaster.obj,jdinput.obj,jdmarker.obj, -
+ jdhuff.obj,jdmainct.obj,jdcoefct.obj,jdpostct.obj,jddctmgr.obj, -
+ jidctfst.obj,jidctflt.obj,jidctint.obj,jdsample.obj,jdcolor.obj, -
+ jquant1.obj,jquant2.obj,jdmerge.obj,jcomapi.obj,jutils.obj, -
+ jerror.obj,jmemmgr.obj,jmemnobs.obj
+$!
+$ DoCompile cjpeg.c
+$ DoCompile rdppm.c
+$ DoCompile rdgif.c
+$ DoCompile rdtarga.c
+$ DoCompile rdrle.c
+$ DoCompile rdbmp.c
+$ DoCompile rdswitch.c
+$ DoCompile cdjpeg.c
+$!
+$ Link /NoMap /Executable = cjpeg.exe cjpeg.obj,rdppm.obj,rdgif.obj, -
+ rdtarga.obj,rdrle.obj,rdbmp.obj,rdswitch.obj,cdjpeg.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile djpeg.c
+$ DoCompile wrppm.c
+$ DoCompile wrgif.c
+$ DoCompile wrtarga.c
+$ DoCompile wrrle.c
+$ DoCompile wrbmp.c
+$ DoCompile rdcolmap.c
+$ DoCompile cdjpeg.c
+$!
+$ Link /NoMap /Executable = djpeg.exe djpeg.obj,wrppm.obj,wrgif.obj, -
+ wrtarga.obj,wrrle.obj,wrbmp.obj,rdcolmap.obj,cdjpeg.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile jpegtran.c
+$ DoCompile rdswitch.c
+$ DoCompile cdjpeg.c
+$ DoCompile transupp.c
+$!
+$ Link /NoMap /Executable = jpegtran.exe jpegtran.obj,rdswitch.obj, -
+ cdjpeg.obj,transupp.obj,libjpeg.olb/Library'OPT'
+$!
+$ DoCompile rdjpgcom.c
+$ Link /NoMap /Executable = rdjpgcom.exe rdjpgcom.obj'OPT'
+$!
+$ DoCompile wrjpgcom.c
+$ Link /NoMap /Executable = wrjpgcom.exe wrjpgcom.obj'OPT'
+$!
+$! Run the self-test
+$!
+$ mcr sys$disk:[]djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+$ mcr sys$disk:[]djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+$ mcr sys$disk:[]cjpeg -dct int -outfile testout.jpg testimg.ppm
+$ mcr sys$disk:[]djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+$ mcr sys$disk:[]cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+$ mcr sys$disk:[]jpegtran -outfile testoutt.jpg testprog.jpg
+$ Backup /Compare/Log testimg.ppm testout.ppm
+$ Backup /Compare/Log testimg.bmp testout.bmp
+$ Backup /Compare/Log testimg.jpg testout.jpg
+$ Backup /Compare/Log testimg.ppm testoutp.ppm
+$ Backup /Compare/Log testimgp.jpg testoutp.jpg
+$ Backup /Compare/Log testorig.jpg testoutt.jpg
+$!
+$End:
+$ If Verify Then Set Verify
+$ Exit
diff --git a/jpg/makefile.wat b/jpg/makefile.wat
new file mode 100644
index 0000000..a3e652b
--- /dev/null
+++ b/jpg/makefile.wat
@@ -0,0 +1,240 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is suitable for Watcom C/C++ 10.0 on MS-DOS (using
+# dos4g extender), OS/2, and Windows NT console mode.
+# Thanks to Janos Haide, jhaide@btrvtech.com.
+
+# Read installation instructions before saying "wmake" !!
+
+# Uncomment line for desired system
+SYSTEM=DOS
+#SYSTEM=OS2
+#SYSTEM=NT
+
+# The name of your C compiler:
+CC= wcl386
+
+# You may need to adjust these cc options:
+CFLAGS= -4r -ort -wx -zq -bt=$(SYSTEM)
+# Caution: avoid -ol or -ox; these generate bad code with 10.0 or 10.0a.
+# Generally, we recommend defining any configuration symbols in jconfig.h,
+# NOT via -D switches here.
+
+# Link-time cc options:
+!ifeq SYSTEM DOS
+LDFLAGS= -zq -l=dos4g
+!else ifeq SYSTEM OS2
+LDFLAGS= -zq -l=os2v2
+!else ifeq SYSTEM NT
+LDFLAGS= -zq -l=nt
+!endif
+
+# Put here the object file name for the correct system-dependent memory
+# manager file. jmemnobs should work fine for dos4g or OS/2 environment.
+SYSDEPMEM= jmemnobs.obj
+
+# End of configurable options.
+
+
+# source files: JPEG library proper
+LIBSOURCES= jaricom.c jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c &
+ jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c &
+ jcomapi.c jcparam.c jcprepct.c jcsample.c jctrans.c jdapimin.c &
+ jdapistd.c jdarith.c jdatadst.c jdatasrc.c jdcoefct.c jdcolor.c &
+ jddctmgr.c jdhuff.c jdinput.c jdmainct.c jdmarker.c jdmaster.c &
+ jdmerge.c jdpostct.c jdsample.c jdtrans.c jerror.c jfdctflt.c &
+ jfdctfst.c jfdctint.c jidctflt.c jidctfst.c jidctint.c jquant1.c &
+ jquant2.c jutils.c jmemmgr.c
+# memmgr back ends: compile only one of these into a working library
+SYSDEPSOURCES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemmac.c
+# source files: cjpeg/djpeg/jpegtran applications, also rdjpgcom/wrjpgcom
+APPSOURCES= cjpeg.c djpeg.c jpegtran.c rdjpgcom.c wrjpgcom.c cdjpeg.c &
+ rdcolmap.c rdswitch.c transupp.c rdppm.c wrppm.c rdgif.c wrgif.c &
+ rdtarga.c wrtarga.c rdbmp.c wrbmp.c rdrle.c wrrle.c
+SOURCES= $(LIBSOURCES) $(SYSDEPSOURCES) $(APPSOURCES)
+# files included by source files
+INCLUDES= jdct.h jerror.h jinclude.h jmemsys.h jmorecfg.h jpegint.h &
+ jpeglib.h jversion.h cdjpeg.h cderror.h transupp.h
+# documentation, test, and support files
+DOCS= README install.txt usage.txt cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 &
+ wrjpgcom.1 wizard.txt example.c libjpeg.txt structure.txt &
+ coderules.txt filelist.txt change.log
+MKFILES= configure Makefile.in makefile.ansi makefile.unix makefile.bcc &
+ makefile.mc6 makefile.dj makefile.wat makefile.vc makejdsw.vc6 &
+ makeadsw.vc6 makejdep.vc6 makejdsp.vc6 makejmak.vc6 makecdep.vc6 &
+ makecdsp.vc6 makecmak.vc6 makeddep.vc6 makeddsp.vc6 makedmak.vc6 &
+ maketdep.vc6 maketdsp.vc6 maketmak.vc6 makerdep.vc6 makerdsp.vc6 &
+ makermak.vc6 makewdep.vc6 makewdsp.vc6 makewmak.vc6 makejsln.v10 &
+ makeasln.v10 makejvcx.v10 makejfil.v10 makecvcx.v10 makecfil.v10 &
+ makedvcx.v10 makedfil.v10 maketvcx.v10 maketfil.v10 makervcx.v10 &
+ makerfil.v10 makewvcx.v10 makewfil.v10 makeproj.mac makcjpeg.st &
+ makdjpeg.st makljpeg.st maktjpeg.st makefile.manx makefile.sas &
+ makefile.mms makefile.vms makvms.opt
+CONFIGFILES= jconfig.cfg jconfig.bcc jconfig.mc6 jconfig.dj jconfig.wat &
+ jconfig.vc jconfig.mac jconfig.st jconfig.manx jconfig.sas &
+ jconfig.vms
+CONFIGUREFILES= config.guess config.sub install-sh ltmain.sh depcomp missing
+OTHERFILES= jconfig.txt ckconfig.c ansi2knr.c ansi2knr.1 jmemdosa.asm &
+ libjpeg.map
+TESTFILES= testorig.jpg testimg.ppm testimg.bmp testimg.jpg testprog.jpg &
+ testimgp.jpg
+DISTFILES= $(DOCS) $(MKFILES) $(CONFIGFILES) $(SOURCES) $(INCLUDES) &
+ $(CONFIGUREFILES) $(OTHERFILES) $(TESTFILES)
+# library object files common to compression and decompression
+COMOBJECTS= jaricom.obj jcomapi.obj jutils.obj jerror.obj jmemmgr.obj $(SYSDEPMEM)
+# compression library object files
+CLIBOBJECTS= jcapimin.obj jcapistd.obj jcarith.obj jctrans.obj jcparam.obj &
+ jdatadst.obj jcinit.obj jcmaster.obj jcmarker.obj jcmainct.obj &
+ jcprepct.obj jccoefct.obj jccolor.obj jcsample.obj jchuff.obj &
+ jcdctmgr.obj jfdctfst.obj jfdctflt.obj jfdctint.obj
+# decompression library object files
+DLIBOBJECTS= jdapimin.obj jdapistd.obj jdarith.obj jdtrans.obj jdatasrc.obj &
+ jdmaster.obj jdinput.obj jdmarker.obj jdhuff.obj jdmainct.obj &
+ jdcoefct.obj jdpostct.obj jddctmgr.obj jidctfst.obj jidctflt.obj &
+ jidctint.obj jdsample.obj jdcolor.obj jquant1.obj jquant2.obj &
+ jdmerge.obj
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+# object files for sample applications (excluding library files)
+COBJECTS= cjpeg.obj rdppm.obj rdgif.obj rdtarga.obj rdrle.obj rdbmp.obj &
+ rdswitch.obj cdjpeg.obj
+DOBJECTS= djpeg.obj wrppm.obj wrgif.obj wrtarga.obj wrrle.obj wrbmp.obj &
+ rdcolmap.obj cdjpeg.obj
+TROBJECTS= jpegtran.obj rdswitch.obj cdjpeg.obj transupp.obj
+
+
+all: libjpeg.lib cjpeg.exe djpeg.exe jpegtran.exe rdjpgcom.exe wrjpgcom.exe
+
+libjpeg.lib: $(LIBOBJECTS)
+ - del libjpeg.lib
+ * wlib -n libjpeg.lib $(LIBOBJECTS)
+
+cjpeg.exe: $(COBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) $(COBJECTS) libjpeg.lib
+
+djpeg.exe: $(DOBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) $(DOBJECTS) libjpeg.lib
+
+jpegtran.exe: $(TROBJECTS) libjpeg.lib
+ $(CC) $(LDFLAGS) $(TROBJECTS) libjpeg.lib
+
+rdjpgcom.exe: rdjpgcom.c
+ $(CC) $(CFLAGS) $(LDFLAGS) rdjpgcom.c
+
+wrjpgcom.exe: wrjpgcom.c
+ $(CC) $(CFLAGS) $(LDFLAGS) wrjpgcom.c
+
+.c.obj:
+ $(CC) $(CFLAGS) -c $<
+
+jconfig.h: jconfig.txt
+ echo You must prepare a system-dependent jconfig.h file.
+ echo Please read the installation directions in install.txt.
+ exit 1
+
+clean: .SYMBOLIC
+ - del *.obj
+ - del libjpeg.lib
+ - del cjpeg.exe
+ - del djpeg.exe
+ - del jpegtran.exe
+ - del rdjpgcom.exe
+ - del wrjpgcom.exe
+ - del testout*.*
+
+test: cjpeg.exe djpeg.exe jpegtran.exe .SYMBOLIC
+ - del testout*.*
+ djpeg -dct int -ppm -outfile testout.ppm testorig.jpg
+ djpeg -dct int -bmp -colors 256 -outfile testout.bmp testorig.jpg
+ cjpeg -dct int -outfile testout.jpg testimg.ppm
+ djpeg -dct int -ppm -outfile testoutp.ppm testprog.jpg
+ cjpeg -dct int -progressive -opt -outfile testoutp.jpg testimg.ppm
+ jpegtran -outfile testoutt.jpg testprog.jpg
+!ifeq SYSTEM DOS
+ fc /b testimg.ppm testout.ppm
+ fc /b testimg.bmp testout.bmp
+ fc /b testimg.jpg testout.jpg
+ fc /b testimg.ppm testoutp.ppm
+ fc /b testimgp.jpg testoutp.jpg
+ fc /b testorig.jpg testoutt.jpg
+!else
+ echo n > n.tmp
+ comp testimg.ppm testout.ppm < n.tmp
+ comp testimg.bmp testout.bmp < n.tmp
+ comp testimg.jpg testout.jpg < n.tmp
+ comp testimg.ppm testoutp.ppm < n.tmp
+ comp testimgp.jpg testoutp.jpg < n.tmp
+ comp testorig.jpg testoutt.jpg < n.tmp
+ del n.tmp
+!endif
+
+
+jaricom.obj: jaricom.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapimin.obj: jcapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcapistd.obj: jcapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcarith.obj: jcarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccoefct.obj: jccoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jccolor.obj: jccolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcdctmgr.obj: jcdctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jchuff.obj: jchuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcinit.obj: jcinit.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmainct.obj: jcmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmarker.obj: jcmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcmaster.obj: jcmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcomapi.obj: jcomapi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcparam.obj: jcparam.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcprepct.obj: jcprepct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jcsample.obj: jcsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jctrans.obj: jctrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapimin.obj: jdapimin.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdapistd.obj: jdapistd.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdarith.obj: jdarith.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdatadst.obj: jdatadst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdatasrc.obj: jdatasrc.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h
+jdcoefct.obj: jdcoefct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdcolor.obj: jdcolor.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jddctmgr.obj: jddctmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jdhuff.obj: jdhuff.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdinput.obj: jdinput.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmainct.obj: jdmainct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmarker.obj: jdmarker.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmaster.obj: jdmaster.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdmerge.obj: jdmerge.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdpostct.obj: jdpostct.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdsample.obj: jdsample.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jdtrans.obj: jdtrans.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jerror.obj: jerror.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jversion.h jerror.h
+jfdctflt.obj: jfdctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctfst.obj: jfdctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jfdctint.obj: jfdctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctflt.obj: jidctflt.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctfst.obj: jidctfst.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jidctint.obj: jidctint.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jdct.h
+jquant1.obj: jquant1.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jquant2.obj: jquant2.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jutils.obj: jutils.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h
+jmemmgr.obj: jmemmgr.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemansi.obj: jmemansi.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemname.obj: jmemname.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemnobs.obj: jmemnobs.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemdos.obj: jmemdos.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+jmemmac.obj: jmemmac.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h jmemsys.h
+cjpeg.obj: cjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+djpeg.obj: djpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h jversion.h
+jpegtran.obj: jpegtran.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h transupp.h jversion.h
+rdjpgcom.obj: rdjpgcom.c jinclude.h jconfig.h
+wrjpgcom.obj: wrjpgcom.c jinclude.h jconfig.h
+cdjpeg.obj: cdjpeg.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdcolmap.obj: rdcolmap.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdswitch.obj: rdswitch.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+transupp.obj: transupp.c jinclude.h jconfig.h jpeglib.h jmorecfg.h jpegint.h jerror.h transupp.h
+rdppm.obj: rdppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrppm.obj: wrppm.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdgif.obj: rdgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrgif.obj: wrgif.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdtarga.obj: rdtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrtarga.obj: wrtarga.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdbmp.obj: rdbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrbmp.obj: wrbmp.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+rdrle.obj: rdrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
+wrrle.obj: wrrle.c cdjpeg.h jinclude.h jconfig.h jpeglib.h jmorecfg.h jerror.h cderror.h
diff --git a/jpg/makejdep.vc6 b/jpg/makejdep.vc6
new file mode 100644
index 0000000..d373edf
--- /dev/null
+++ b/jpg/makejdep.vc6
@@ -0,0 +1,423 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von jpeg.mak
+
+.\jaricom.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcapimin.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcapistd.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcarith.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jccoefct.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jccolor.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcdctmgr.c : \
+ ".\jconfig.h"\
+ ".\jdct.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jchuff.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcinit.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcmainct.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcmarker.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcmaster.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcomapi.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcparam.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcprepct.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jcsample.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jctrans.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdapimin.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdapistd.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdarith.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdatadst.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\jdatasrc.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\jdcoefct.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdcolor.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jddctmgr.c : \
+ ".\jconfig.h"\
+ ".\jdct.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdhuff.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdinput.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdmainct.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdmarker.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdmaster.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdmerge.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdpostct.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdsample.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jdtrans.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jerror.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+ ".\jversion.h"\
+
+
+.\jfdctflt.c : \
+ ".\jconfig.h"\
+ ".\jdct.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jfdctfst.c : \
+ ".\jconfig.h"\
+ ".\jdct.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jfdctint.c : \
+ ".\jconfig.h"\
+ ".\jdct.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jidctflt.c : \
+ ".\jconfig.h"\
+ ".\jdct.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jidctfst.c : \
+ ".\jconfig.h"\
+ ".\jdct.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jidctint.c : \
+ ".\jconfig.h"\
+ ".\jdct.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jmemmgr.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmemsys.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jmemnobs.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmemsys.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jquant1.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jquant2.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
+
+.\jutils.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+
diff --git a/jpg/makejdsp.vc6 b/jpg/makejdsp.vc6
new file mode 100644
index 0000000..2576fc2
--- /dev/null
+++ b/jpg/makejdsp.vc6
@@ -0,0 +1,285 @@
+# Microsoft Developer Studio Project File - Name="jpeg" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=jpeg - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "jpeg.mak".
+!MESSAGE
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "jpeg.mak" CFG="jpeg - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "jpeg - Win32" (basierend auf "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD BASE RSC /l 0x407
+# ADD RSC /l 0x407
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+# Begin Target
+
+# Name "jpeg - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\jaricom.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcapimin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcapistd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcarith.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jccoefct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jccolor.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcdctmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jchuff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcinit.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcmainct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcmarker.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcmaster.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcomapi.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcparam.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcprepct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jcsample.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jctrans.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdapimin.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdapistd.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdarith.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdatadst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdatasrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdcoefct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdcolor.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jddctmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdhuff.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdinput.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdmainct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdmarker.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdmaster.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdmerge.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdpostct.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdsample.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdtrans.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jfdctflt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jfdctfst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jfdctint.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jidctflt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jidctfst.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jidctint.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmemmgr.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmemnobs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jquant1.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jquant2.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jutils.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jdct.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmemsys.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmorecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpegint.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpeglib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jversion.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/jpg/makejdsw.vc6 b/jpg/makejdsw.vc6
new file mode 100644
index 0000000..8913f62
--- /dev/null
+++ b/jpg/makejdsw.vc6
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELSCHT WERDEN!
+
+###############################################################################
+
+Project: "jpeg"=".\jpeg.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/jpg/makejfil.v10 b/jpg/makejfil.v10
new file mode 100644
index 0000000..5accea2
--- /dev/null
+++ b/jpg/makejfil.v10
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="jconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jdct.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jerror.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jinclude.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jmemsys.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jmorecfg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jpegint.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jpeglib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jversion.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="jaricom.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcapimin.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcapistd.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcarith.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jccoefct.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jccolor.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcdctmgr.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jchuff.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcinit.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcmainct.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcmarker.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcmaster.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcomapi.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcparam.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcprepct.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jcsample.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jctrans.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdapimin.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdapistd.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdarith.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdatadst.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdatasrc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdcoefct.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdcolor.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jddctmgr.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdhuff.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdinput.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdmainct.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdmarker.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdmaster.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdmerge.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdpostct.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdsample.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jdtrans.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jerror.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jfdctflt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jfdctfst.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jfdctint.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jidctflt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jidctfst.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jidctint.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jmemmgr.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jmemnobs.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jquant1.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jquant2.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jutils.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makejmak.vc6 b/jpg/makejmak.vc6
new file mode 100644
index 0000000..88a4eb3
--- /dev/null
+++ b/jpg/makejmak.vc6
@@ -0,0 +1,425 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on jpeg.dsp
+!IF "$(CFG)" == ""
+CFG=jpeg - Win32
+!MESSAGE Keine Konfiguration angegeben. jpeg - Win32 wird als Standard verwendet.
+!ENDIF
+
+!IF "$(CFG)" != "jpeg - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "jpeg.mak" CFG="jpeg - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "jpeg - Win32" (basierend auf "Win32 (x86) Static Library")
+!MESSAGE
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\jpeg.lib"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\jaricom.obj"
+ -@erase "$(INTDIR)\jcapimin.obj"
+ -@erase "$(INTDIR)\jcapistd.obj"
+ -@erase "$(INTDIR)\jcarith.obj"
+ -@erase "$(INTDIR)\jccoefct.obj"
+ -@erase "$(INTDIR)\jccolor.obj"
+ -@erase "$(INTDIR)\jcdctmgr.obj"
+ -@erase "$(INTDIR)\jchuff.obj"
+ -@erase "$(INTDIR)\jcinit.obj"
+ -@erase "$(INTDIR)\jcmainct.obj"
+ -@erase "$(INTDIR)\jcmarker.obj"
+ -@erase "$(INTDIR)\jcmaster.obj"
+ -@erase "$(INTDIR)\jcomapi.obj"
+ -@erase "$(INTDIR)\jcparam.obj"
+ -@erase "$(INTDIR)\jcprepct.obj"
+ -@erase "$(INTDIR)\jcsample.obj"
+ -@erase "$(INTDIR)\jctrans.obj"
+ -@erase "$(INTDIR)\jdapimin.obj"
+ -@erase "$(INTDIR)\jdapistd.obj"
+ -@erase "$(INTDIR)\jdarith.obj"
+ -@erase "$(INTDIR)\jdatadst.obj"
+ -@erase "$(INTDIR)\jdatasrc.obj"
+ -@erase "$(INTDIR)\jdcoefct.obj"
+ -@erase "$(INTDIR)\jdcolor.obj"
+ -@erase "$(INTDIR)\jddctmgr.obj"
+ -@erase "$(INTDIR)\jdhuff.obj"
+ -@erase "$(INTDIR)\jdinput.obj"
+ -@erase "$(INTDIR)\jdmainct.obj"
+ -@erase "$(INTDIR)\jdmarker.obj"
+ -@erase "$(INTDIR)\jdmaster.obj"
+ -@erase "$(INTDIR)\jdmerge.obj"
+ -@erase "$(INTDIR)\jdpostct.obj"
+ -@erase "$(INTDIR)\jdsample.obj"
+ -@erase "$(INTDIR)\jdtrans.obj"
+ -@erase "$(INTDIR)\jerror.obj"
+ -@erase "$(INTDIR)\jfdctflt.obj"
+ -@erase "$(INTDIR)\jfdctfst.obj"
+ -@erase "$(INTDIR)\jfdctint.obj"
+ -@erase "$(INTDIR)\jidctflt.obj"
+ -@erase "$(INTDIR)\jidctfst.obj"
+ -@erase "$(INTDIR)\jidctint.obj"
+ -@erase "$(INTDIR)\jmemmgr.obj"
+ -@erase "$(INTDIR)\jmemnobs.obj"
+ -@erase "$(INTDIR)\jquant1.obj"
+ -@erase "$(INTDIR)\jquant2.obj"
+ -@erase "$(INTDIR)\jutils.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\jpeg.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"$(INTDIR)\jpeg.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+RSC=rc.exe
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\jpeg.bsc"
+BSC32_SBRS= \
+
+LIB32=link.exe -lib
+LIB32_FLAGS=/nologo /out:"$(OUTDIR)\jpeg.lib"
+LIB32_OBJS= \
+ "$(INTDIR)\jaricom.obj" \
+ "$(INTDIR)\jcapimin.obj" \
+ "$(INTDIR)\jcapistd.obj" \
+ "$(INTDIR)\jcarith.obj" \
+ "$(INTDIR)\jccoefct.obj" \
+ "$(INTDIR)\jccolor.obj" \
+ "$(INTDIR)\jcdctmgr.obj" \
+ "$(INTDIR)\jchuff.obj" \
+ "$(INTDIR)\jcinit.obj" \
+ "$(INTDIR)\jcmainct.obj" \
+ "$(INTDIR)\jcmarker.obj" \
+ "$(INTDIR)\jcmaster.obj" \
+ "$(INTDIR)\jcomapi.obj" \
+ "$(INTDIR)\jcparam.obj" \
+ "$(INTDIR)\jcprepct.obj" \
+ "$(INTDIR)\jcsample.obj" \
+ "$(INTDIR)\jctrans.obj" \
+ "$(INTDIR)\jdapimin.obj" \
+ "$(INTDIR)\jdapistd.obj" \
+ "$(INTDIR)\jdarith.obj" \
+ "$(INTDIR)\jdatadst.obj" \
+ "$(INTDIR)\jdatasrc.obj" \
+ "$(INTDIR)\jdcoefct.obj" \
+ "$(INTDIR)\jdcolor.obj" \
+ "$(INTDIR)\jddctmgr.obj" \
+ "$(INTDIR)\jdhuff.obj" \
+ "$(INTDIR)\jdinput.obj" \
+ "$(INTDIR)\jdmainct.obj" \
+ "$(INTDIR)\jdmarker.obj" \
+ "$(INTDIR)\jdmaster.obj" \
+ "$(INTDIR)\jdmerge.obj" \
+ "$(INTDIR)\jdpostct.obj" \
+ "$(INTDIR)\jdsample.obj" \
+ "$(INTDIR)\jdtrans.obj" \
+ "$(INTDIR)\jerror.obj" \
+ "$(INTDIR)\jfdctflt.obj" \
+ "$(INTDIR)\jfdctfst.obj" \
+ "$(INTDIR)\jfdctint.obj" \
+ "$(INTDIR)\jidctflt.obj" \
+ "$(INTDIR)\jidctfst.obj" \
+ "$(INTDIR)\jidctint.obj" \
+ "$(INTDIR)\jmemmgr.obj" \
+ "$(INTDIR)\jmemnobs.obj" \
+ "$(INTDIR)\jquant1.obj" \
+ "$(INTDIR)\jquant2.obj" \
+ "$(INTDIR)\jutils.obj"
+
+"$(OUTDIR)\jpeg.lib" : "$(OUTDIR)" $(DEF_FILE) $(LIB32_OBJS)
+ $(LIB32) @<<
+ $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS)
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("jpeg.dep")
+!INCLUDE "jpeg.dep"
+!ELSE
+!MESSAGE Warning: cannot find "jpeg.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "jpeg - Win32"
+SOURCE=.\jaricom.c
+
+"$(INTDIR)\jaricom.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcapimin.c
+
+"$(INTDIR)\jcapimin.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcapistd.c
+
+"$(INTDIR)\jcapistd.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcarith.c
+
+"$(INTDIR)\jcarith.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jccoefct.c
+
+"$(INTDIR)\jccoefct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jccolor.c
+
+"$(INTDIR)\jccolor.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcdctmgr.c
+
+"$(INTDIR)\jcdctmgr.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jchuff.c
+
+"$(INTDIR)\jchuff.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcinit.c
+
+"$(INTDIR)\jcinit.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcmainct.c
+
+"$(INTDIR)\jcmainct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcmarker.c
+
+"$(INTDIR)\jcmarker.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcmaster.c
+
+"$(INTDIR)\jcmaster.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcomapi.c
+
+"$(INTDIR)\jcomapi.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcparam.c
+
+"$(INTDIR)\jcparam.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcprepct.c
+
+"$(INTDIR)\jcprepct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jcsample.c
+
+"$(INTDIR)\jcsample.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jctrans.c
+
+"$(INTDIR)\jctrans.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdapimin.c
+
+"$(INTDIR)\jdapimin.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdapistd.c
+
+"$(INTDIR)\jdapistd.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdarith.c
+
+"$(INTDIR)\jdarith.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdatadst.c
+
+"$(INTDIR)\jdatadst.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdatasrc.c
+
+"$(INTDIR)\jdatasrc.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdcoefct.c
+
+"$(INTDIR)\jdcoefct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdcolor.c
+
+"$(INTDIR)\jdcolor.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jddctmgr.c
+
+"$(INTDIR)\jddctmgr.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdhuff.c
+
+"$(INTDIR)\jdhuff.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdinput.c
+
+"$(INTDIR)\jdinput.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdmainct.c
+
+"$(INTDIR)\jdmainct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdmarker.c
+
+"$(INTDIR)\jdmarker.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdmaster.c
+
+"$(INTDIR)\jdmaster.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdmerge.c
+
+"$(INTDIR)\jdmerge.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdpostct.c
+
+"$(INTDIR)\jdpostct.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdsample.c
+
+"$(INTDIR)\jdsample.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jdtrans.c
+
+"$(INTDIR)\jdtrans.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jerror.c
+
+"$(INTDIR)\jerror.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jfdctflt.c
+
+"$(INTDIR)\jfdctflt.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jfdctfst.c
+
+"$(INTDIR)\jfdctfst.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jfdctint.c
+
+"$(INTDIR)\jfdctint.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jidctflt.c
+
+"$(INTDIR)\jidctflt.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jidctfst.c
+
+"$(INTDIR)\jidctfst.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jidctint.c
+
+"$(INTDIR)\jidctint.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jmemmgr.c
+
+"$(INTDIR)\jmemmgr.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jmemnobs.c
+
+"$(INTDIR)\jmemnobs.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jquant1.c
+
+"$(INTDIR)\jquant1.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jquant2.c
+
+"$(INTDIR)\jquant2.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jutils.c
+
+"$(INTDIR)\jutils.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/jpg/makejsln.v10 b/jpg/makejsln.v10
new file mode 100644
index 0000000..292de1f
--- /dev/null
+++ b/jpg/makejsln.v10
@@ -0,0 +1,17 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg", "jpeg.vcxproj", "{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.ActiveCfg = Release|Win32
+ {019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/jpg/makejvcx.v10 b/jpg/makejvcx.v10
new file mode 100644
index 0000000..c7a898e
--- /dev/null
+++ b/jpg/makejvcx.v10
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="jconfig.h" />
+ <ClInclude Include="jdct.h" />
+ <ClInclude Include="jerror.h" />
+ <ClInclude Include="jinclude.h" />
+ <ClInclude Include="jmemsys.h" />
+ <ClInclude Include="jmorecfg.h" />
+ <ClInclude Include="jpegint.h" />
+ <ClInclude Include="jpeglib.h" />
+ <ClInclude Include="jversion.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="jaricom.c" />
+ <ClCompile Include="jcapimin.c" />
+ <ClCompile Include="jcapistd.c" />
+ <ClCompile Include="jcarith.c" />
+ <ClCompile Include="jccoefct.c" />
+ <ClCompile Include="jccolor.c" />
+ <ClCompile Include="jcdctmgr.c" />
+ <ClCompile Include="jchuff.c" />
+ <ClCompile Include="jcinit.c" />
+ <ClCompile Include="jcmainct.c" />
+ <ClCompile Include="jcmarker.c" />
+ <ClCompile Include="jcmaster.c" />
+ <ClCompile Include="jcomapi.c" />
+ <ClCompile Include="jcparam.c" />
+ <ClCompile Include="jcprepct.c" />
+ <ClCompile Include="jcsample.c" />
+ <ClCompile Include="jctrans.c" />
+ <ClCompile Include="jdapimin.c" />
+ <ClCompile Include="jdapistd.c" />
+ <ClCompile Include="jdarith.c" />
+ <ClCompile Include="jdatadst.c" />
+ <ClCompile Include="jdatasrc.c" />
+ <ClCompile Include="jdcoefct.c" />
+ <ClCompile Include="jdcolor.c" />
+ <ClCompile Include="jddctmgr.c" />
+ <ClCompile Include="jdhuff.c" />
+ <ClCompile Include="jdinput.c" />
+ <ClCompile Include="jdmainct.c" />
+ <ClCompile Include="jdmarker.c" />
+ <ClCompile Include="jdmaster.c" />
+ <ClCompile Include="jdmerge.c" />
+ <ClCompile Include="jdpostct.c" />
+ <ClCompile Include="jdsample.c" />
+ <ClCompile Include="jdtrans.c" />
+ <ClCompile Include="jerror.c" />
+ <ClCompile Include="jfdctflt.c" />
+ <ClCompile Include="jfdctfst.c" />
+ <ClCompile Include="jfdctint.c" />
+ <ClCompile Include="jidctflt.c" />
+ <ClCompile Include="jidctfst.c" />
+ <ClCompile Include="jidctint.c" />
+ <ClCompile Include="jmemmgr.c" />
+ <ClCompile Include="jmemnobs.c" />
+ <ClCompile Include="jquant1.c" />
+ <ClCompile Include="jquant2.c">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Disabled</Optimization>
+ <BufferSecurityCheck Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</BufferSecurityCheck>
+ </ClCompile>
+ <ClCompile Include="jutils.c" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{019DBD2A-273D-4BA4-BF86-B5EFE2ED76B1}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>jpeg</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>Full</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>false</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <OmitFramePointers>true</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makeproj.mac b/jpg/makeproj.mac
new file mode 100644
index 0000000..e5b5102
--- /dev/null
+++ b/jpg/makeproj.mac
@@ -0,0 +1,213 @@
+--
+-- makeproj.mac
+--
+-- This AppleScript builds Code Warrior PRO Release 2 project files for the
+-- libjpeg library as well as the test programs 'cjpeg', 'djpeg', 'jpegtran'.
+-- (We'd distribute real project files, except they're not text
+-- and would create maintenance headaches.)
+--
+-- The script then compiles and links the library and the test programs.
+-- NOTE: if you haven't already created a 'jconfig.h' file, the script
+-- automatically copies 'jconfig.mac' to 'jconfig.h'.
+--
+-- To use this script, you must have AppleScript 1.1 or later installed
+-- and a suitable AppleScript editor like Script Editor or Script Debugger
+-- (http://www.latenightsw.com). Open this file with your AppleScript
+-- editor and execute the "run" command to build the projects.
+--
+-- Thanks to Dan Sears and Don Agro for this script.
+-- Questions about this script can be addressed to dogpark@interlog.com
+--
+
+on run
+
+ choose folder with prompt ">>> Select IJG source folder <<<"
+ set ijg_folder to result
+
+ choose folder with prompt ">>> Select MetroWerks folder <<<"
+ set cw_folder to result
+
+ -- if jconfig.h doesn't already exist, copy jconfig.mac
+
+ tell application "Finder"
+ if not (exists file "jconfig.h" of ijg_folder) then
+ duplicate {file "jconfig.mac" of folder ijg_folder}
+ select file "jconfig.mac copy" of folder ijg_folder
+ set name of selection to "jconfig.h"
+ end if
+ end tell
+
+ tell application "CodeWarrior IDE 2.1"
+ with timeout of 10000 seconds
+
+ -- create libjpeg project
+
+ activate
+ Create Project (ijg_folder as string) & "libjpeg.proj"
+ Set Preferences of panel "Target Settings" to {Target Name:"libjpeg"}
+ Set Preferences of panel "PPC Project" to {File Name:"libjpeg"}
+ Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"}
+ Set Preferences of panel "PPC Project" to {Project Type:library}
+ Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true}
+ Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true}
+ Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC}
+ Set Preferences of panel "PPC Linker" to {Generate SYM File:false}
+
+ Add Files (ijg_folder as string) & "jaricom.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcapimin.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcapistd.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcarith.c" To Segment 1
+ Add Files (ijg_folder as string) & "jctrans.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcparam.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdatadst.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcinit.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcmaster.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcmarker.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcmainct.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcprepct.c" To Segment 1
+ Add Files (ijg_folder as string) & "jccoefct.c" To Segment 1
+ Add Files (ijg_folder as string) & "jccolor.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcsample.c" To Segment 1
+ Add Files (ijg_folder as string) & "jchuff.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcdctmgr.c" To Segment 1
+ Add Files (ijg_folder as string) & "jfdctfst.c" To Segment 1
+ Add Files (ijg_folder as string) & "jfdctflt.c" To Segment 1
+ Add Files (ijg_folder as string) & "jfdctint.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdapimin.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdapistd.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdarith.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdtrans.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdatasrc.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdmaster.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdinput.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdmarker.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdhuff.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdmainct.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdcoefct.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdpostct.c" To Segment 1
+ Add Files (ijg_folder as string) & "jddctmgr.c" To Segment 1
+ Add Files (ijg_folder as string) & "jidctfst.c" To Segment 1
+ Add Files (ijg_folder as string) & "jidctflt.c" To Segment 1
+ Add Files (ijg_folder as string) & "jidctint.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdsample.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdcolor.c" To Segment 1
+ Add Files (ijg_folder as string) & "jquant1.c" To Segment 1
+ Add Files (ijg_folder as string) & "jquant2.c" To Segment 1
+ Add Files (ijg_folder as string) & "jdmerge.c" To Segment 1
+ Add Files (ijg_folder as string) & "jcomapi.c" To Segment 1
+ Add Files (ijg_folder as string) & "jutils.c" To Segment 1
+ Add Files (ijg_folder as string) & "jerror.c" To Segment 1
+ Add Files (ijg_folder as string) & "jmemmgr.c" To Segment 1
+ Add Files (ijg_folder as string) & "jmemmac.c" To Segment 1
+
+ -- compile and link the library
+
+ Make Project
+ Close Project
+
+ -- create cjpeg project
+
+ activate
+ Create Project (ijg_folder as string) & "cjpeg.proj"
+ Set Preferences of panel "Target Settings" to {Target Name:"cjpeg"}
+ Set Preferences of panel "PPC Project" to {File Name:"cjpeg"}
+ Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"}
+ Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true}
+ Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true}
+ Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC}
+ Set Preferences of panel "PPC Linker" to {Generate SYM File:false}
+
+ Add Files (ijg_folder as string) & "cjpeg.c" To Segment 1
+ Add Files (ijg_folder as string) & "rdppm.c" To Segment 1
+ Add Files (ijg_folder as string) & "rdgif.c" To Segment 1
+ Add Files (ijg_folder as string) & "rdtarga.c" To Segment 1
+ Add Files (ijg_folder as string) & "rdrle.c" To Segment 1
+ Add Files (ijg_folder as string) & "rdbmp.c" To Segment 1
+ Add Files (ijg_folder as string) & "rdswitch.c" To Segment 1
+ Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1
+
+ Add Files (ijg_folder as string) & "libjpeg" To Segment 2
+
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3
+
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4
+
+ -- compile and link cjpeg
+
+ Make Project
+ Close Project
+
+ -- create djpeg project
+
+ activate
+ Create Project (ijg_folder as string) & "djpeg.proj"
+ Set Preferences of panel "Target Settings" to {Target Name:"djpeg"}
+ Set Preferences of panel "PPC Project" to {File Name:"djpeg"}
+ Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"}
+ Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true}
+ Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true}
+ Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC}
+ Set Preferences of panel "PPC Linker" to {Generate SYM File:false}
+
+ Add Files (ijg_folder as string) & "djpeg.c" To Segment 1
+ Add Files (ijg_folder as string) & "wrppm.c" To Segment 1
+ Add Files (ijg_folder as string) & "wrgif.c" To Segment 1
+ Add Files (ijg_folder as string) & "wrtarga.c" To Segment 1
+ Add Files (ijg_folder as string) & "wrrle.c" To Segment 1
+ Add Files (ijg_folder as string) & "wrbmp.c" To Segment 1
+ Add Files (ijg_folder as string) & "rdcolmap.c" To Segment 1
+ Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1
+
+ Add Files (ijg_folder as string) & "libjpeg" To Segment 2
+
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3
+
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4
+
+ -- compile and link djpeg
+
+ Make Project
+ Close Project
+
+ -- create jpegtran project
+
+ activate
+ Create Project (ijg_folder as string) & "jpegtran.proj"
+ Set Preferences of panel "Target Settings" to {Target Name:"jpegtran"}
+ Set Preferences of panel "PPC Project" to {File Name:"jpegtran"}
+ Set Preferences of panel "Target Settings" to {Linker:"MacOS PPC Linker"}
+ Set Preferences of panel "C/C++ Compiler" to {ANSI Strict:true}
+ Set Preferences of panel "C/C++ Compiler" to {Enums Always Ints:true}
+ Set Preferences of panel "PPC Codegen" to {Struct Alignment:PowerPC}
+ Set Preferences of panel "PPC Linker" to {Generate SYM File:false}
+
+ Add Files (ijg_folder as string) & "jpegtran.c" To Segment 1
+ Add Files (ijg_folder as string) & "rdswitch.c" To Segment 1
+ Add Files (ijg_folder as string) & "cdjpeg.c" To Segment 1
+ Add Files (ijg_folder as string) & "transupp.c" To Segment 1
+
+ Add Files (ijg_folder as string) & "libjpeg" To Segment 2
+
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL C.PPC.Lib" To Segment 3
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:Metrowerks Standard Library:MSL C:Bin:MSL SIOUX.PPC.Lib" To Segment 3
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:Runtime:Runtime PPC:MSL RuntimePPC.Lib" To Segment 3
+
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:InterfaceLib" To Segment 4
+ Add Files (cw_folder as string) & "Metrowerks CodeWarrior:MacOS Support:Libraries:MacOS Common:MathLib" To Segment 4
+
+ -- compile and link jpegtran
+
+ Make Project
+ Close Project
+
+ quit
+
+ end timeout
+ end tell
+end run
diff --git a/jpg/makerdep.vc6 b/jpg/makerdep.vc6
new file mode 100644
index 0000000..d2dac9d
--- /dev/null
+++ b/jpg/makerdep.vc6
@@ -0,0 +1,6 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von rdjpgcom.mak
+
+.\rdjpgcom.c : \
+ ".\jconfig.h"\
+ ".\jinclude.h"\
+
diff --git a/jpg/makerdsp.vc6 b/jpg/makerdsp.vc6
new file mode 100644
index 0000000..6efb442
--- /dev/null
+++ b/jpg/makerdsp.vc6
@@ -0,0 +1,78 @@
+# Microsoft Developer Studio Project File - Name="rdjpgcom" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=rdjpgcom - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "rdjpgcom.mak".
+!MESSAGE
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "rdjpgcom.mak" CFG="rdjpgcom - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "rdjpgcom - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\rdjpgcom\Release"
+# PROP BASE Intermediate_Dir ".\rdjpgcom\Release"
+# PROP BASE Target_Dir ".\rdjpgcom"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\rdjpgcom\Release"
+# PROP Intermediate_Dir ".\rdjpgcom\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\rdjpgcom"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "rdjpgcom - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\rdjpgcom.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/jpg/makerfil.v10 b/jpg/makerfil.v10
new file mode 100644
index 0000000..4660d49
--- /dev/null
+++ b/jpg/makerfil.v10
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="jconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jinclude.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="rdjpgcom.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makermak.vc6 b/jpg/makermak.vc6
new file mode 100644
index 0000000..b54ea7d
--- /dev/null
+++ b/jpg/makermak.vc6
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on rdjpgcom.dsp
+!IF "$(CFG)" == ""
+CFG=rdjpgcom - Win32
+!MESSAGE Keine Konfiguration angegeben. rdjpgcom - Win32 wird als Standard verwendet.
+!ENDIF
+
+!IF "$(CFG)" != "rdjpgcom - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "rdjpgcom.mak" CFG="rdjpgcom - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "rdjpgcom - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\rdjpgcom\Release
+INTDIR=.\rdjpgcom\Release
+# Begin Custom Macros
+OutDir=.\rdjpgcom\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\rdjpgcom.exe"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\rdjpgcom.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\rdjpgcom.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\rdjpgcom.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\rdjpgcom.pdb" /machine:I386 /out:"$(OUTDIR)\rdjpgcom.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\rdjpgcom.obj"
+
+"$(OUTDIR)\rdjpgcom.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\rdjpgcom.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("rdjpgcom.dep")
+!INCLUDE "rdjpgcom.dep"
+!ELSE
+!MESSAGE Warning: cannot find "rdjpgcom.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "rdjpgcom - Win32"
+SOURCE=.\rdjpgcom.c
+
+"$(INTDIR)\rdjpgcom.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/jpg/makervcx.v10 b/jpg/makervcx.v10
new file mode 100644
index 0000000..f34017f
--- /dev/null
+++ b/jpg/makervcx.v10
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{C81513DB-78DC-46BC-BC98-82E745203976}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>rdjpgcom</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectName)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectName)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>Full</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>false</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <OmitFramePointers>true</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="jconfig.h" />
+ <ClInclude Include="jinclude.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="rdjpgcom.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/maketdep.vc6 b/jpg/maketdep.vc6
new file mode 100644
index 0000000..acebae9
--- /dev/null
+++ b/jpg/maketdep.vc6
@@ -0,0 +1,43 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von jpegtran.mak
+
+.\cdjpeg.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\jpegtran.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+ ".\jversion.h"\
+ ".\transupp.h"\
+
+
+.\rdswitch.c : \
+ ".\cderror.h"\
+ ".\cdjpeg.h"\
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpeglib.h"\
+
+
+.\transupp.c : \
+ ".\jconfig.h"\
+ ".\jerror.h"\
+ ".\jinclude.h"\
+ ".\jmorecfg.h"\
+ ".\jpegint.h"\
+ ".\jpeglib.h"\
+ ".\transupp.h"\
+
diff --git a/jpg/maketdsp.vc6 b/jpg/maketdsp.vc6
new file mode 100644
index 0000000..42e7312
--- /dev/null
+++ b/jpg/maketdsp.vc6
@@ -0,0 +1,122 @@
+# Microsoft Developer Studio Project File - Name="jpegtran" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=jpegtran - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "jpegtran.mak".
+!MESSAGE
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "jpegtran.mak" CFG="jpegtran - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "jpegtran - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\jpegtran\Release"
+# PROP BASE Intermediate_Dir ".\jpegtran\Release"
+# PROP BASE Target_Dir ".\jpegtran"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\jpegtran\Release"
+# PROP Intermediate_Dir ".\jpegtran\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\jpegtran"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "jpegtran - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\cdjpeg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpegtran.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\rdswitch.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\transupp.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\cderror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\cdjpeg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jerror.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jmorecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpegint.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jpeglib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jversion.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\transupp.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/jpg/maketfil.v10 b/jpg/maketfil.v10
new file mode 100644
index 0000000..e772792
--- /dev/null
+++ b/jpg/maketfil.v10
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="cderror.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="cdjpeg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jerror.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jinclude.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jmorecfg.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jpegint.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jpeglib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jversion.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="transupp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="cdjpeg.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="jpegtran.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdswitch.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="transupp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/maketmak.vc6 b/jpg/maketmak.vc6
new file mode 100644
index 0000000..4ef27fd
--- /dev/null
+++ b/jpg/maketmak.vc6
@@ -0,0 +1,131 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on jpegtran.dsp
+!IF "$(CFG)" == ""
+CFG=jpegtran - Win32
+!MESSAGE Keine Konfiguration angegeben. jpegtran - Win32 wird als Standard verwendet.
+!ENDIF
+
+!IF "$(CFG)" != "jpegtran - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "jpegtran.mak" CFG="jpegtran - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "jpegtran - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\jpegtran\Release
+INTDIR=.\jpegtran\Release
+# Begin Custom Macros
+OutDir=.\jpegtran\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\jpegtran.exe"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\cdjpeg.obj"
+ -@erase "$(INTDIR)\jpegtran.obj"
+ -@erase "$(INTDIR)\rdswitch.obj"
+ -@erase "$(INTDIR)\transupp.obj"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(OUTDIR)\jpegtran.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\jpegtran.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\jpegtran.pdb" /machine:I386 /out:"$(OUTDIR)\jpegtran.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\cdjpeg.obj" \
+ "$(INTDIR)\jpegtran.obj" \
+ "$(INTDIR)\rdswitch.obj" \
+ "$(INTDIR)\transupp.obj"
+
+"$(OUTDIR)\jpegtran.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\jpegtran.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("jpegtran.dep")
+!INCLUDE "jpegtran.dep"
+!ELSE
+!MESSAGE Warning: cannot find "jpegtran.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "jpegtran - Win32"
+SOURCE=.\cdjpeg.c
+
+"$(INTDIR)\cdjpeg.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\jpegtran.c
+
+"$(INTDIR)\jpegtran.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\rdswitch.c
+
+"$(INTDIR)\rdswitch.obj" : $(SOURCE) "$(INTDIR)"
+
+
+SOURCE=.\transupp.c
+
+"$(INTDIR)\transupp.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/jpg/maketvcx.v10 b/jpg/maketvcx.v10
new file mode 100644
index 0000000..b8e7203
--- /dev/null
+++ b/jpg/maketvcx.v10
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{025BAC50-51B5-4FFE-BC47-3F920BB4047E}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>jpegtran</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectName)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectName)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>Full</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>false</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <OmitFramePointers>true</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>Release\jpeg.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="cderror.h" />
+ <ClInclude Include="cdjpeg.h" />
+ <ClInclude Include="jconfig.h" />
+ <ClInclude Include="jerror.h" />
+ <ClInclude Include="jinclude.h" />
+ <ClInclude Include="jmorecfg.h" />
+ <ClInclude Include="jpegint.h" />
+ <ClInclude Include="jpeglib.h" />
+ <ClInclude Include="jversion.h" />
+ <ClInclude Include="transupp.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="cdjpeg.c" />
+ <ClCompile Include="jpegtran.c" />
+ <ClCompile Include="rdswitch.c" />
+ <ClCompile Include="transupp.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makewdep.vc6 b/jpg/makewdep.vc6
new file mode 100644
index 0000000..358146f
--- /dev/null
+++ b/jpg/makewdep.vc6
@@ -0,0 +1,6 @@
+# Microsoft Developer Studio erstellte Abhngigkeitsdatei, einbezogen von wrjpgcom.mak
+
+.\wrjpgcom.c : \
+ ".\jconfig.h"\
+ ".\jinclude.h"\
+
diff --git a/jpg/makewdsp.vc6 b/jpg/makewdsp.vc6
new file mode 100644
index 0000000..b572e8a
--- /dev/null
+++ b/jpg/makewdsp.vc6
@@ -0,0 +1,78 @@
+# Microsoft Developer Studio Project File - Name="wrjpgcom" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** NICHT BEARBEITEN **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=wrjpgcom - Win32
+!MESSAGE Dies ist kein gltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
+!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und fhren Sie den Befehl
+!MESSAGE
+!MESSAGE NMAKE /f "wrjpgcom.mak".
+!MESSAGE
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "wrjpgcom.mak" CFG="wrjpgcom - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "wrjpgcom - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\wrjpgcom\Release"
+# PROP BASE Intermediate_Dir ".\wrjpgcom\Release"
+# PROP BASE Target_Dir ".\wrjpgcom"
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\wrjpgcom\Release"
+# PROP Intermediate_Dir ".\wrjpgcom\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ".\wrjpgcom"
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c
+# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# Begin Target
+
+# Name "wrjpgcom - Win32"
+# Begin Group "Quellcodedateien"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\wrjpgcom.c
+# End Source File
+# End Group
+# Begin Group "Header-Dateien"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# Begin Source File
+
+SOURCE=.\jconfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\jinclude.h
+# End Source File
+# End Group
+# Begin Group "Ressourcendateien"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/jpg/makewfil.v10 b/jpg/makewfil.v10
new file mode 100644
index 0000000..370fa14
--- /dev/null
+++ b/jpg/makewfil.v10
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="jconfig.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="jinclude.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="wrjpgcom.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makewmak.vc6 b/jpg/makewmak.vc6
new file mode 100644
index 0000000..27c73f3
--- /dev/null
+++ b/jpg/makewmak.vc6
@@ -0,0 +1,110 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on wrjpgcom.dsp
+!IF "$(CFG)" == ""
+CFG=wrjpgcom - Win32
+!MESSAGE Keine Konfiguration angegeben. wrjpgcom - Win32 wird als Standard verwendet.
+!ENDIF
+
+!IF "$(CFG)" != "wrjpgcom - Win32"
+!MESSAGE Ungltige Konfiguration "$(CFG)" angegeben.
+!MESSAGE Sie knnen beim Ausfhren von NMAKE eine Konfiguration angeben
+!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
+!MESSAGE
+!MESSAGE NMAKE /f "wrjpgcom.mak" CFG="wrjpgcom - Win32"
+!MESSAGE
+!MESSAGE Fr die Konfiguration stehen zur Auswahl:
+!MESSAGE
+!MESSAGE "wrjpgcom - Win32" (basierend auf "Win32 (x86) Console Application")
+!MESSAGE
+!ERROR Eine ungltige Konfiguration wurde angegeben.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+RSC=rc.exe
+OUTDIR=.\wrjpgcom\Release
+INTDIR=.\wrjpgcom\Release
+# Begin Custom Macros
+OutDir=.\wrjpgcom\Release
+# End Custom Macros
+
+ALL : "$(OUTDIR)\wrjpgcom.exe"
+
+
+CLEAN :
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\wrjpgcom.obj"
+ -@erase "$(OUTDIR)\wrjpgcom.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\wrjpgcom.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=Release\jpeg.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /pdb:"$(OUTDIR)\wrjpgcom.pdb" /machine:I386 /out:"$(OUTDIR)\wrjpgcom.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\wrjpgcom.obj"
+
+"$(OUTDIR)\wrjpgcom.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+CPP_PROJ=/nologo /G6 /MT /W3 /GX /Ox /Oa /Ob2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"$(INTDIR)\wrjpgcom.pch" /YX /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("wrjpgcom.dep")
+!INCLUDE "wrjpgcom.dep"
+!ELSE
+!MESSAGE Warning: cannot find "wrjpgcom.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "wrjpgcom - Win32"
+SOURCE=.\wrjpgcom.c
+
+"$(INTDIR)\wrjpgcom.obj" : $(SOURCE) "$(INTDIR)"
+
+
+
+!ENDIF
+
diff --git a/jpg/makewvcx.v10 b/jpg/makewvcx.v10
new file mode 100644
index 0000000..b7ce0b4
--- /dev/null
+++ b/jpg/makewvcx.v10
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B57065D4-DDDA-4668-BAF5-2D49270C973C}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>wrjpgcom</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(ProjectName)\$(Configuration)\</OutDir>
+ <IntDir>$(ProjectName)\$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>Full</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>false</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+ <OmitFramePointers>true</OmitFramePointers>
+ <EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
+ <DisableSpecificWarnings>4996</DisableSpecificWarnings>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="jconfig.h" />
+ <ClInclude Include="jinclude.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="wrjpgcom.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/jpg/makljpeg.st b/jpg/makljpeg.st
new file mode 100644
index 0000000..cc1ba01
--- /dev/null
+++ b/jpg/makljpeg.st
@@ -0,0 +1,68 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle, B. Setzepfandt, and Guido Vollbeding.
+;
+; To use this file, rename it to libjpeg.prj.
+; Read installation instructions before trying to make the program!
+;
+;
+; * * * Output file * * *
+libjpeg.lib
+;
+; * * * COMPILER OPTIONS * * *
+.C[-P] ; absolute calls
+.C[-M] ; and no string merging, folks
+.C[-w-cln] ; no "constant is long" warnings
+.C[-w-par] ; no "parameter xxxx unused"
+.C[-w-rch] ; no "unreachable code"
+.C[-wsig] ; warn if significant digits may be lost
+.L[-J] ; link new Obj-format (so we get a library)
+=
+; * * * * List of modules * * * *
+jaricom.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcapimin.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcapistd.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcarith.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jccoefct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jccolor.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcdctmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jchuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcinit.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmainct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmarker.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcmaster.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcomapi.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcparam.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcprepct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jcsample.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jctrans.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdapimin.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdapistd.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdarith.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdatadst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h)
+jdatasrc.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h)
+jdcoefct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdcolor.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jddctmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jdhuff.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdinput.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmainct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmarker.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmaster.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdmerge.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdpostct.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdsample.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jdtrans.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jerror.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jversion.h,jerror.h)
+jfdctflt.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jfdctfst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jfdctint.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctflt.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctfst.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jidctint.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jdct.h)
+jquant1.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jquant2.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jutils.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h)
+jmemmgr.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jmemsys.h)
+jmemansi.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,jmemsys.h)
diff --git a/jpg/maktjpeg.st b/jpg/maktjpeg.st
new file mode 100644
index 0000000..43f078a
--- /dev/null
+++ b/jpg/maktjpeg.st
@@ -0,0 +1,30 @@
+; Project file for Independent JPEG Group's software
+;
+; This project file is for Atari ST/STE/TT systems using Pure C or Turbo C.
+; Thanks to Frank Moehle, B. Setzepfandt, and Guido Vollbeding.
+;
+; To use this file, rename it to jpegtran.prj.
+; If you are using Turbo C, change filenames beginning with "pc..." to "tc..."
+; Read installation instructions before trying to make the program!
+;
+;
+; * * * Output file * * *
+jpegtran.ttp
+;
+; * * * COMPILER OPTIONS * * *
+.C[-P] ; absolute calls
+.C[-M] ; and no string merging, folks
+.C[-w-cln] ; no "constant is long" warnings
+.C[-w-par] ; no "parameter xxxx unused"
+.C[-w-rch] ; no "unreachable code"
+.C[-wsig] ; warn if significant digits may be lost
+=
+; * * * * List of modules * * * *
+pcstart.o
+jpegtran.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h,transupp.h,jversion.h)
+cdjpeg.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+rdswitch.c (cdjpeg.h,jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jerror.h,cderror.h)
+transupp.c (jinclude.h,jconfig.h,jpeglib.h,jmorecfg.h,jpegint.h,jerror.h,transupp.h)
+libjpeg.lib ; built by libjpeg.prj
+pcstdlib.lib ; standard library
+pcextlib.lib ; extended library
diff --git a/jpg/makvms.opt b/jpg/makvms.opt
new file mode 100644
index 0000000..675e8fe
--- /dev/null
+++ b/jpg/makvms.opt
@@ -0,0 +1,4 @@
+! A pointer to the VAX/VMS C Run-Time Shareable Library.
+! This file is needed by makefile.mms and makefile.vms,
+! but only for the older VAX C compiler. DEC C does not need it.
+Sys$Library:VAXCRTL.EXE /Share
diff --git a/jpg/missing b/jpg/missing
new file mode 100644
index 0000000..28055d2
--- /dev/null
+++ b/jpg/missing
@@ -0,0 +1,376 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ autom4te touch the output file, or create a stub one
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# normalize program name to check for.
+program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program). This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+ lex*|yacc*)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar*)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case $f in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te*)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison*|yacc*)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f y.tab.h; then
+ echo >y.tab.h
+ fi
+ if test ! -f y.tab.c; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex*|flex*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if test $# -ne 1; then
+ eval LASTARG="\${$#}"
+ case $LASTARG in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if test -f "$SRCFILE"; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if test ! -f lex.yy.c; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit $?
+ fi
+ ;;
+
+ makeinfo*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n "$sed_output"`
+ test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '
+ /^@setfilename/{
+ s/.* \([^ ]*\) *$/\1/
+ p
+ q
+ }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ # If the file does not exist, the user really needs makeinfo;
+ # let's fail without touching anything.
+ test -f $file || exit 1
+ touch $file
+ ;;
+
+ tar*)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case $firstarg in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case $firstarg in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/jpg/rdbmp.c b/jpg/rdbmp.c
new file mode 100644
index 0000000..fd773d4
--- /dev/null
+++ b/jpg/rdbmp.c
@@ -0,0 +1,480 @@
+/*
+ * rdbmp.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * Modified 2009-2010 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Microsoft "BMP"
+ * format (MS Windows 3.x, OS/2 1.x, and OS/2 2.x flavors).
+ * Currently, only 8-bit and 24-bit images are supported, not 1-bit or
+ * 4-bit (feeding such low-depth images into JPEG would be silly anyway).
+ * Also, we don't support RLE-compressed files.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed BMP format).
+ *
+ * This code contributed by James Arthur Boucher.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef BMP_SUPPORTED
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x) ((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x) ((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x) ((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/* Private version of data source object */
+
+typedef struct _bmp_source_struct * bmp_source_ptr;
+
+typedef struct _bmp_source_struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ j_compress_ptr cinfo; /* back link saves passing separate parm */
+
+ JSAMPARRAY colormap; /* BMP colormap (converted to my format) */
+
+ jvirt_sarray_ptr whole_image; /* Needed to reverse row order */
+ JDIMENSION source_row; /* Current source row number */
+ JDIMENSION row_width; /* Physical width of scanlines in file */
+
+ int bits_per_pixel; /* remembers 8- or 24-bit format */
+} bmp_source_struct;
+
+
+LOCAL(int)
+read_byte (bmp_source_ptr sinfo)
+/* Read next byte from BMP file */
+{
+ register FILE *infile = sinfo->pub.input_file;
+ register int c;
+
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
+ return c;
+}
+
+
+LOCAL(void)
+read_colormap (bmp_source_ptr sinfo, int cmaplen, int mapentrysize)
+/* Read the colormap from a BMP file */
+{
+ int i;
+
+ switch (mapentrysize) {
+ case 3:
+ /* BGR format (occurs in OS/2 files) */
+ for (i = 0; i < cmaplen; i++) {
+ sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+ }
+ break;
+ case 4:
+ /* BGR0 format (occurs in MS Windows files) */
+ for (i = 0; i < cmaplen; i++) {
+ sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+ (void) read_byte(sinfo);
+ }
+ break;
+ default:
+ ERREXIT(sinfo->cinfo, JERR_BMP_BADCMAP);
+ break;
+ }
+}
+
+
+/*
+ * Read one row of pixels.
+ * The image has been read into the whole_image array, but is otherwise
+ * unprocessed. We must read it out in top-to-bottom row order, and if
+ * it is an 8-bit image, we must expand colormapped pixels to 24bit format.
+ */
+
+METHODDEF(JDIMENSION)
+get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit colormap indexes */
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ register JSAMPARRAY colormap = source->colormap;
+ JSAMPARRAY image_ptr;
+ register int t;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+
+ /* Fetch next row from virtual array */
+ source->source_row--;
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source->source_row, (JDIMENSION) 1, FALSE);
+
+ /* Expand the colormap indexes to real data */
+ inptr = image_ptr[0];
+ outptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ t = GETJSAMPLE(*inptr++);
+ *outptr++ = colormap[0][t]; /* can omit GETJSAMPLE() safely */
+ *outptr++ = colormap[1][t];
+ *outptr++ = colormap[2][t];
+ }
+
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 24-bit pixels */
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+
+ /* Fetch next row from virtual array */
+ source->source_row--;
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source->source_row, (JDIMENSION) 1, FALSE);
+
+ /* Transfer data. Note source values are in BGR order
+ * (even though Microsoft's own documents say the opposite).
+ */
+ inptr = image_ptr[0];
+ outptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[1] = *inptr++;
+ outptr[0] = *inptr++;
+ outptr += 3;
+ }
+
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_32bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 32-bit pixels */
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+
+ /* Fetch next row from virtual array */
+ source->source_row--;
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source->source_row, (JDIMENSION) 1, FALSE);
+ /* Transfer data. Note source values are in BGR order
+ * (even though Microsoft's own documents say the opposite).
+ */
+ inptr = image_ptr[0];
+ outptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[1] = *inptr++;
+ outptr[0] = *inptr++;
+ inptr++; /* skip the 4th byte (Alpha channel) */
+ outptr += 3;
+ }
+
+ return 1;
+}
+
+
+/*
+ * This method loads the image into whole_image during the first call on
+ * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
+ * get_8bit_row, get_24bit_row, or get_32bit_row on subsequent calls.
+ */
+
+METHODDEF(JDIMENSION)
+preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ register FILE *infile = source->pub.input_file;
+ register int c;
+ register JSAMPROW out_ptr;
+ JSAMPARRAY image_ptr;
+ JDIMENSION row, col;
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+ /* Read the data into a virtual array in input-file row order. */
+ for (row = 0; row < cinfo->image_height; row++) {
+ if (progress != NULL) {
+ progress->pub.pass_counter = (long) row;
+ progress->pub.pass_limit = (long) cinfo->image_height;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ row, (JDIMENSION) 1, TRUE);
+ out_ptr = image_ptr[0];
+ for (col = source->row_width; col > 0; col--) {
+ /* inline copy of read_byte() for speed */
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ *out_ptr++ = (JSAMPLE) c;
+ }
+ }
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+
+ /* Set up to read from the virtual array in top-to-bottom order */
+ switch (source->bits_per_pixel) {
+ case 8:
+ source->pub.get_pixel_rows = get_8bit_row;
+ break;
+ case 24:
+ source->pub.get_pixel_rows = get_24bit_row;
+ break;
+ case 32:
+ source->pub.get_pixel_rows = get_32bit_row;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+ }
+ source->source_row = cinfo->image_height;
+
+ /* And read the first row */
+ return (*source->pub.get_pixel_rows) (cinfo, sinfo);
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ bmp_source_ptr source = (bmp_source_ptr) sinfo;
+ U_CHAR bmpfileheader[14];
+ U_CHAR bmpinfoheader[64];
+#define GET_2B(array,offset) ((unsigned int) UCH(array[offset]) + \
+ (((unsigned int) UCH(array[offset+1])) << 8))
+#define GET_4B(array,offset) ((INT32) UCH(array[offset]) + \
+ (((INT32) UCH(array[offset+1])) << 8) + \
+ (((INT32) UCH(array[offset+2])) << 16) + \
+ (((INT32) UCH(array[offset+3])) << 24))
+ INT32 bfOffBits;
+ INT32 headerSize;
+ INT32 biWidth;
+ INT32 biHeight;
+ unsigned int biPlanes;
+ INT32 biCompression;
+ INT32 biXPelsPerMeter,biYPelsPerMeter;
+ INT32 biClrUsed = 0;
+ int mapentrysize = 0; /* 0 indicates no colormap */
+ INT32 bPad;
+ JDIMENSION row_width;
+
+ /* Read and verify the bitmap file header */
+ if (! ReadOK(source->pub.input_file, bmpfileheader, 14))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ if (GET_2B(bmpfileheader,0) != 0x4D42) /* 'BM' */
+ ERREXIT(cinfo, JERR_BMP_NOT);
+ bfOffBits = (INT32) GET_4B(bmpfileheader,10);
+ /* We ignore the remaining fileheader fields */
+
+ /* The infoheader might be 12 bytes (OS/2 1.x), 40 bytes (Windows),
+ * or 64 bytes (OS/2 2.x). Check the first 4 bytes to find out which.
+ */
+ if (! ReadOK(source->pub.input_file, bmpinfoheader, 4))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ headerSize = (INT32) GET_4B(bmpinfoheader,0);
+ if (headerSize < 12 || headerSize > 64)
+ ERREXIT(cinfo, JERR_BMP_BADHEADER);
+ if (! ReadOK(source->pub.input_file, bmpinfoheader+4, headerSize-4))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+
+ switch ((int) headerSize) {
+ case 12:
+ /* Decode OS/2 1.x header (Microsoft calls this a BITMAPCOREHEADER) */
+ biWidth = (INT32) GET_2B(bmpinfoheader,4);
+ biHeight = (INT32) GET_2B(bmpinfoheader,6);
+ biPlanes = GET_2B(bmpinfoheader,8);
+ source->bits_per_pixel = (int) GET_2B(bmpinfoheader,10);
+
+ switch (source->bits_per_pixel) {
+ case 8: /* colormapped image */
+ mapentrysize = 3; /* OS/2 uses RGBTRIPLE colormap */
+ TRACEMS2(cinfo, 1, JTRC_BMP_OS2_MAPPED, (int) biWidth, (int) biHeight);
+ break;
+ case 24: /* RGB image */
+ TRACEMS2(cinfo, 1, JTRC_BMP_OS2, (int) biWidth, (int) biHeight);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+ break;
+ }
+ break;
+ case 40:
+ case 64:
+ /* Decode Windows 3.x header (Microsoft calls this a BITMAPINFOHEADER) */
+ /* or OS/2 2.x header, which has additional fields that we ignore */
+ biWidth = GET_4B(bmpinfoheader,4);
+ biHeight = GET_4B(bmpinfoheader,8);
+ biPlanes = GET_2B(bmpinfoheader,12);
+ source->bits_per_pixel = (int) GET_2B(bmpinfoheader,14);
+ biCompression = GET_4B(bmpinfoheader,16);
+ biXPelsPerMeter = GET_4B(bmpinfoheader,24);
+ biYPelsPerMeter = GET_4B(bmpinfoheader,28);
+ biClrUsed = GET_4B(bmpinfoheader,32);
+ /* biSizeImage, biClrImportant fields are ignored */
+
+ switch (source->bits_per_pixel) {
+ case 8: /* colormapped image */
+ mapentrysize = 4; /* Windows uses RGBQUAD colormap */
+ TRACEMS2(cinfo, 1, JTRC_BMP_MAPPED, (int) biWidth, (int) biHeight);
+ break;
+ case 24: /* RGB image */
+ TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
+ break;
+ case 32: /* RGB image + Alpha channel */
+ TRACEMS2(cinfo, 1, JTRC_BMP, (int) biWidth, (int) biHeight);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADDEPTH);
+ break;
+ }
+ if (biCompression != 0)
+ ERREXIT(cinfo, JERR_BMP_COMPRESSED);
+
+ if (biXPelsPerMeter > 0 && biYPelsPerMeter > 0) {
+ /* Set JFIF density parameters from the BMP data */
+ cinfo->X_density = (UINT16) (biXPelsPerMeter/100); /* 100 cm per meter */
+ cinfo->Y_density = (UINT16) (biYPelsPerMeter/100);
+ cinfo->density_unit = 2; /* dots/cm */
+ }
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BMP_BADHEADER);
+ return;
+ }
+
+ if (biWidth <= 0 || biHeight <= 0)
+ ERREXIT(cinfo, JERR_BMP_EMPTY);
+ if (biPlanes != 1)
+ ERREXIT(cinfo, JERR_BMP_BADPLANES);
+
+ /* Compute distance to bitmap data --- will adjust for colormap below */
+ bPad = bfOffBits - (headerSize + 14);
+
+ /* Read the colormap, if any */
+ if (mapentrysize > 0) {
+ if (biClrUsed <= 0)
+ biClrUsed = 256; /* assume it's 256 */
+ else if (biClrUsed > 256)
+ ERREXIT(cinfo, JERR_BMP_BADCMAP);
+ /* Allocate space to store the colormap */
+ source->colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) biClrUsed, (JDIMENSION) 3);
+ /* and read it from the file */
+ read_colormap(source, (int) biClrUsed, mapentrysize);
+ /* account for size of colormap */
+ bPad -= biClrUsed * mapentrysize;
+ }
+
+ /* Skip any remaining pad bytes */
+ if (bPad < 0) /* incorrect bfOffBits value? */
+ ERREXIT(cinfo, JERR_BMP_BADHEADER);
+ while (--bPad >= 0) {
+ (void) read_byte(source);
+ }
+
+ /* Compute row width in file, including padding to 4-byte boundary */
+ if (source->bits_per_pixel == 24)
+ row_width = (JDIMENSION) (biWidth * 3);
+ else if (source->bits_per_pixel == 32)
+ row_width = (JDIMENSION) (biWidth * 4);
+ else
+ row_width = (JDIMENSION) biWidth;
+ while ((row_width & 3) != 0) row_width++;
+ source->row_width = row_width;
+
+ /* Allocate space for inversion array, prepare for preload pass */
+ source->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ row_width, (JDIMENSION) biHeight, (JDIMENSION) 1);
+ source->pub.get_pixel_rows = preload_image;
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+
+ /* Allocate one-row buffer for returned data */
+ source->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (biWidth * 3), (JDIMENSION) 1);
+ source->pub.buffer_height = 1;
+
+ cinfo->in_color_space = JCS_RGB;
+ cinfo->input_components = 3;
+ cinfo->data_precision = 8;
+ cinfo->image_width = (JDIMENSION) biWidth;
+ cinfo->image_height = (JDIMENSION) biHeight;
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_bmp (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for BMP format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_bmp (j_compress_ptr cinfo)
+{
+ bmp_source_ptr source;
+
+ /* Create module interface object */
+ source = (bmp_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(bmp_source_struct));
+ source->cinfo = cinfo; /* make back link for subroutines */
+ /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+ source->pub.start_input = start_input_bmp;
+ source->pub.finish_input = finish_input_bmp;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* BMP_SUPPORTED */
diff --git a/jpg/rdcolmap.c b/jpg/rdcolmap.c
new file mode 100644
index 0000000..42b3437
--- /dev/null
+++ b/jpg/rdcolmap.c
@@ -0,0 +1,253 @@
+/*
+ * rdcolmap.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file implements djpeg's "-map file" switch. It reads a source image
+ * and constructs a colormap to be supplied to the JPEG decompressor.
+ *
+ * Currently, these file formats are supported for the map file:
+ * GIF: the contents of the GIF's global colormap are used.
+ * PPM (either text or raw flavor): the entire file is read and
+ * each unique pixel value is entered in the map.
+ * Note that reading a large PPM file will be horrendously slow.
+ * Typically, a PPM-format map file should contain just one pixel
+ * of each desired color. Such a file can be extracted from an
+ * ordinary image PPM file with ppmtomap(1).
+ *
+ * Rescaling a PPM that has a maxval unequal to MAXJSAMPLE is not
+ * currently implemented.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef QUANT_2PASS_SUPPORTED /* otherwise can't quantize to supplied map */
+
+/* Portions of this code are based on the PBMPLUS library, which is:
+**
+** Copyright (C) 1988 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+*/
+
+
+/*
+ * Add a (potentially) new color to the color map.
+ */
+
+LOCAL(void)
+add_map_entry (j_decompress_ptr cinfo, int R, int G, int B)
+{
+ JSAMPROW colormap0 = cinfo->colormap[0];
+ JSAMPROW colormap1 = cinfo->colormap[1];
+ JSAMPROW colormap2 = cinfo->colormap[2];
+ int ncolors = cinfo->actual_number_of_colors;
+ int index;
+
+ /* Check for duplicate color. */
+ for (index = 0; index < ncolors; index++) {
+ if (GETJSAMPLE(colormap0[index]) == R &&
+ GETJSAMPLE(colormap1[index]) == G &&
+ GETJSAMPLE(colormap2[index]) == B)
+ return; /* color is already in map */
+ }
+
+ /* Check for map overflow. */
+ if (ncolors >= (MAXJSAMPLE+1))
+ ERREXIT1(cinfo, JERR_QUANT_MANY_COLORS, (MAXJSAMPLE+1));
+
+ /* OK, add color to map. */
+ colormap0[ncolors] = (JSAMPLE) R;
+ colormap1[ncolors] = (JSAMPLE) G;
+ colormap2[ncolors] = (JSAMPLE) B;
+ cinfo->actual_number_of_colors++;
+}
+
+
+/*
+ * Extract color map from a GIF file.
+ */
+
+LOCAL(void)
+read_gif_map (j_decompress_ptr cinfo, FILE * infile)
+{
+ int header[13];
+ int i, colormaplen;
+ int R, G, B;
+
+ /* Initial 'G' has already been read by read_color_map */
+ /* Read the rest of the GIF header and logical screen descriptor */
+ for (i = 1; i < 13; i++) {
+ if ((header[i] = getc(infile)) == EOF)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ }
+
+ /* Verify GIF Header */
+ if (header[1] != 'I' || header[2] != 'F')
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ /* There must be a global color map. */
+ if ((header[10] & 0x80) == 0)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ /* OK, fetch it. */
+ colormaplen = 2 << (header[10] & 0x07);
+
+ for (i = 0; i < colormaplen; i++) {
+ R = getc(infile);
+ G = getc(infile);
+ B = getc(infile);
+ if (R == EOF || G == EOF || B == EOF)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ add_map_entry(cinfo,
+ R << (BITS_IN_JSAMPLE-8),
+ G << (BITS_IN_JSAMPLE-8),
+ B << (BITS_IN_JSAMPLE-8));
+ }
+}
+
+
+/* Support routines for reading PPM */
+
+
+LOCAL(int)
+pbm_getc (FILE * infile)
+/* Read next char, skipping over any comments */
+/* A comment/newline sequence is returned as a newline */
+{
+ register int ch;
+
+ ch = getc(infile);
+ if (ch == '#') {
+ do {
+ ch = getc(infile);
+ } while (ch != '\n' && ch != EOF);
+ }
+ return ch;
+}
+
+
+LOCAL(unsigned int)
+read_pbm_integer (j_decompress_ptr cinfo, FILE * infile)
+/* Read an unsigned decimal integer from the PPM file */
+/* Swallows one trailing character after the integer */
+/* Note that on a 16-bit-int machine, only values up to 64k can be read. */
+/* This should not be a problem in practice. */
+{
+ register int ch;
+ register unsigned int val;
+
+ /* Skip any leading whitespace */
+ do {
+ ch = pbm_getc(infile);
+ if (ch == EOF)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
+
+ if (ch < '0' || ch > '9')
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ val = ch - '0';
+ while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
+ val *= 10;
+ val += ch - '0';
+ }
+ return val;
+}
+
+
+/*
+ * Extract color map from a PPM file.
+ */
+
+LOCAL(void)
+read_ppm_map (j_decompress_ptr cinfo, FILE * infile)
+{
+ int c;
+ unsigned int w, h, maxval, row, col;
+ int R, G, B;
+
+ /* Initial 'P' has already been read by read_color_map */
+ c = getc(infile); /* save format discriminator for a sec */
+
+ /* while we fetch the remaining header info */
+ w = read_pbm_integer(cinfo, infile);
+ h = read_pbm_integer(cinfo, infile);
+ maxval = read_pbm_integer(cinfo, infile);
+
+ if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ /* For now, we don't support rescaling from an unusual maxval. */
+ if (maxval != (unsigned int) MAXJSAMPLE)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+
+ switch (c) {
+ case '3': /* it's a text-format PPM file */
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ R = read_pbm_integer(cinfo, infile);
+ G = read_pbm_integer(cinfo, infile);
+ B = read_pbm_integer(cinfo, infile);
+ add_map_entry(cinfo, R, G, B);
+ }
+ }
+ break;
+
+ case '6': /* it's a raw-format PPM file */
+ for (row = 0; row < h; row++) {
+ for (col = 0; col < w; col++) {
+ R = getc(infile);
+ G = getc(infile);
+ B = getc(infile);
+ if (R == EOF || G == EOF || B == EOF)
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ add_map_entry(cinfo, R, G, B);
+ }
+ }
+ break;
+
+ default:
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ break;
+ }
+}
+
+
+/*
+ * Main entry point from djpeg.c.
+ * Input: opened input file (from file name argument on command line).
+ * Output: colormap and actual_number_of_colors fields are set in cinfo.
+ */
+
+GLOBAL(void)
+read_color_map (j_decompress_ptr cinfo, FILE * infile)
+{
+ /* Allocate space for a color map of maximum supported size. */
+ cinfo->colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3);
+ cinfo->actual_number_of_colors = 0; /* initialize map to empty */
+
+ /* Read first byte to determine file format */
+ switch (getc(infile)) {
+ case 'G':
+ read_gif_map(cinfo, infile);
+ break;
+ case 'P':
+ read_ppm_map(cinfo, infile);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_BAD_CMAP_FILE);
+ break;
+ }
+}
+
+#endif /* QUANT_2PASS_SUPPORTED */
diff --git a/jpg/rdgif.c b/jpg/rdgif.c
new file mode 100644
index 0000000..b27c167
--- /dev/null
+++ b/jpg/rdgif.c
@@ -0,0 +1,38 @@
+/*
+ * rdgif.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in GIF format.
+ *
+ *****************************************************************************
+ * NOTE: to avoid entanglements with Unisys' patent on LZW compression, *
+ * the ability to read GIF files has been removed from the IJG distribution. *
+ * Sorry about that. *
+ *****************************************************************************
+ *
+ * We are required to state that
+ * "The Graphics Interchange Format(c) is the Copyright property of
+ * CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ * CompuServe Incorporated."
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef GIF_SUPPORTED
+
+/*
+ * The module selection routine for GIF format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_gif (j_compress_ptr cinfo)
+{
+ fprintf(stderr, "GIF input is unsupported for legal reasons. Sorry.\n");
+ exit(EXIT_FAILURE);
+ return NULL; /* keep compiler happy */
+}
+
+#endif /* GIF_SUPPORTED */
diff --git a/jpg/rdjpgcom.1 b/jpg/rdjpgcom.1
new file mode 100644
index 0000000..97611df
--- /dev/null
+++ b/jpg/rdjpgcom.1
@@ -0,0 +1,63 @@
+.TH RDJPGCOM 1 "02 April 2009"
+.SH NAME
+rdjpgcom \- display text comments from a JPEG file
+.SH SYNOPSIS
+.B rdjpgcom
+[
+.B \-raw
+]
+[
+.B \-verbose
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B rdjpgcom
+reads the named JPEG/JFIF file, or the standard input if no file is named,
+and prints any text comments found in the file on the standard output.
+.PP
+The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
+Although the standard doesn't actually define what COM blocks are for, they
+are widely used to hold user-supplied text strings. This lets you add
+annotations, titles, index terms, etc to your JPEG files, and later retrieve
+them as text. COM blocks do not interfere with the image stored in the JPEG
+file. The maximum size of a COM block is 64K, but you can have as many of
+them as you like in one JPEG file.
+.SH OPTIONS
+.TP
+.B \-raw
+Normally
+.B rdjpgcom
+escapes non-printable characters in comments, for security reasons.
+This option avoids that.
+.PP
+.B \-verbose
+Causes
+.B rdjpgcom
+to also display the JPEG image dimensions.
+.PP
+Switch names may be abbreviated, and are not case sensitive.
+.SH HINTS
+.B rdjpgcom
+does not depend on the IJG JPEG library. Its source code is intended as an
+illustration of the minimum amount of code required to parse a JPEG file
+header correctly.
+.PP
+In
+.B \-verbose
+mode,
+.B rdjpgcom
+will also attempt to print the contents of any "APP12" markers as text.
+Some digital cameras produce APP12 markers containing useful textual
+information. If you like, you can modify the source code to print
+other APPn marker types as well.
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR djpeg (1),
+.BR jpegtran (1),
+.BR wrjpgcom (1)
+.SH AUTHOR
+Independent JPEG Group
diff --git a/jpg/rdjpgcom.c b/jpg/rdjpgcom.c
new file mode 100644
index 0000000..3719154
--- /dev/null
+++ b/jpg/rdjpgcom.c
@@ -0,0 +1,515 @@
+/*
+ * rdjpgcom.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * Modified 2009 by Bill Allombert, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a very simple stand-alone application that displays
+ * the text in COM (comment) markers in a JFIF file.
+ * This may be useful as an example of the minimum logic needed to parse
+ * JPEG markers.
+ */
+
+#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */
+#include "jinclude.h" /* get auto-config symbols, <stdio.h> */
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h> /* Bill Allombert: use locale for isprint */
+#endif
+#include <ctype.h> /* to declare isupper(), tolower() */
+#ifdef USE_SETMODE
+#include <fcntl.h> /* to declare setmode()'s parameter macros */
+/* If you have setmode() but not <io.h>, just delete this line: */
+#include <io.h> /* to declare setmode() */
+#endif
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#else
+#ifdef VMS /* VMS is very nonstandard */
+#define READ_BINARY "rb", "ctx=stm"
+#else /* standard ANSI-compliant case */
+#define READ_BINARY "rb"
+#endif
+#endif
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+#ifdef VMS
+#define EXIT_SUCCESS 1 /* VMS is very nonstandard */
+#else
+#define EXIT_SUCCESS 0
+#endif
+#endif
+
+
+/*
+ * These macros are used to read the input file.
+ * To reuse this code in another application, you might need to change these.
+ */
+
+static FILE * infile; /* input JPEG file */
+
+/* Return next input byte, or EOF if no more */
+#define NEXTBYTE() getc(infile)
+
+
+/* Error exit handler */
+#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
+
+
+/* Read one byte, testing for EOF */
+static int
+read_1_byte (void)
+{
+ int c;
+
+ c = NEXTBYTE();
+ if (c == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ return c;
+}
+
+/* Read 2 bytes, convert to unsigned int */
+/* All 2-byte quantities in JPEG markers are MSB first */
+static unsigned int
+read_2_bytes (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ if (c1 == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ c2 = NEXTBYTE();
+ if (c2 == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ return (((unsigned int) c1) << 8) + ((unsigned int) c2);
+}
+
+
+/*
+ * JPEG markers consist of one or more 0xFF bytes, followed by a marker
+ * code byte (which is not an FF). Here are the marker codes of interest
+ * in this program. (See jdmarker.c for a more complete list.)
+ */
+
+#define M_SOF0 0xC0 /* Start Of Frame N */
+#define M_SOF1 0xC1 /* N indicates which compression process */
+#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
+#define M_SOF3 0xC3
+#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
+#define M_SOF6 0xC6
+#define M_SOF7 0xC7
+#define M_SOF9 0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
+#define M_EOI 0xD9 /* End Of Image (end of datastream) */
+#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
+#define M_APP0 0xE0 /* Application-specific marker, type N */
+#define M_APP12 0xEC /* (we don't bother to list all 16 APPn's) */
+#define M_COM 0xFE /* COMment */
+
+
+/*
+ * Find the next JPEG marker and return its marker code.
+ * We expect at least one FF byte, possibly more if the compressor used FFs
+ * to pad the file.
+ * There could also be non-FF garbage between markers. The treatment of such
+ * garbage is unspecified; we choose to skip over it but emit a warning msg.
+ * NB: this routine must not be used after seeing SOS marker, since it will
+ * not deal correctly with FF/00 sequences in the compressed image data...
+ */
+
+static int
+next_marker (void)
+{
+ int c;
+ int discarded_bytes = 0;
+
+ /* Find 0xFF byte; count and skip any non-FFs. */
+ c = read_1_byte();
+ while (c != 0xFF) {
+ discarded_bytes++;
+ c = read_1_byte();
+ }
+ /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs
+ * are legal as pad bytes, so don't count them in discarded_bytes.
+ */
+ do {
+ c = read_1_byte();
+ } while (c == 0xFF);
+
+ if (discarded_bytes != 0) {
+ fprintf(stderr, "Warning: garbage data found in JPEG file\n");
+ }
+
+ return c;
+}
+
+
+/*
+ * Read the initial marker, which should be SOI.
+ * For a JFIF file, the first two bytes of the file should be literally
+ * 0xFF M_SOI. To be more general, we could use next_marker, but if the
+ * input file weren't actually JPEG at all, next_marker might read the whole
+ * file and then return a misleading error message...
+ */
+
+static int
+first_marker (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ c2 = NEXTBYTE();
+ if (c1 != 0xFF || c2 != M_SOI)
+ ERREXIT("Not a JPEG file");
+ return c2;
+}
+
+
+/*
+ * Most types of marker are followed by a variable-length parameter segment.
+ * This routine skips over the parameters for any marker we don't otherwise
+ * want to process.
+ * Note that we MUST skip the parameter segment explicitly in order not to
+ * be fooled by 0xFF bytes that might appear within the parameter segment;
+ * such bytes do NOT introduce new markers.
+ */
+
+static void
+skip_variable (void)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ unsigned int length;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2)
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+ /* Skip over the remaining bytes */
+ while (length > 0) {
+ (void) read_1_byte();
+ length--;
+ }
+}
+
+
+/*
+ * Process a COM marker.
+ * We want to print out the marker contents as legible text;
+ * we must guard against non-text junk and varying newline representations.
+ */
+
+static void
+process_COM (int raw)
+{
+ unsigned int length;
+ int ch;
+ int lastch = 0;
+
+ /* Bill Allombert: set locale properly for isprint */
+#ifdef HAVE_LOCALE_H
+ setlocale(LC_CTYPE, "");
+#endif
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2)
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+
+ while (length > 0) {
+ ch = read_1_byte();
+ if (raw) {
+ putc(ch, stdout);
+ /* Emit the character in a readable form.
+ * Nonprintables are converted to \nnn form,
+ * while \ is converted to \\.
+ * Newlines in CR, CR/LF, or LF form will be printed as one newline.
+ */
+ } else if (ch == '\r') {
+ printf("\n");
+ } else if (ch == '\n') {
+ if (lastch != '\r')
+ printf("\n");
+ } else if (ch == '\\') {
+ printf("\\\\");
+ } else if (isprint(ch)) {
+ putc(ch, stdout);
+ } else {
+ printf("\\%03o", ch);
+ }
+ lastch = ch;
+ length--;
+ }
+ printf("\n");
+
+ /* Bill Allombert: revert to C locale */
+#ifdef HAVE_LOCALE_H
+ setlocale(LC_CTYPE, "C");
+#endif
+}
+
+
+/*
+ * Process a SOFn marker.
+ * This code is only needed if you want to know the image dimensions...
+ */
+
+static void
+process_SOFn (int marker)
+{
+ unsigned int length;
+ unsigned int image_height, image_width;
+ int data_precision, num_components;
+ const char * process;
+ int ci;
+
+ length = read_2_bytes(); /* usual parameter length count */
+
+ data_precision = read_1_byte();
+ image_height = read_2_bytes();
+ image_width = read_2_bytes();
+ num_components = read_1_byte();
+
+ switch (marker) {
+ case M_SOF0: process = "Baseline"; break;
+ case M_SOF1: process = "Extended sequential"; break;
+ case M_SOF2: process = "Progressive"; break;
+ case M_SOF3: process = "Lossless"; break;
+ case M_SOF5: process = "Differential sequential"; break;
+ case M_SOF6: process = "Differential progressive"; break;
+ case M_SOF7: process = "Differential lossless"; break;
+ case M_SOF9: process = "Extended sequential, arithmetic coding"; break;
+ case M_SOF10: process = "Progressive, arithmetic coding"; break;
+ case M_SOF11: process = "Lossless, arithmetic coding"; break;
+ case M_SOF13: process = "Differential sequential, arithmetic coding"; break;
+ case M_SOF14: process = "Differential progressive, arithmetic coding"; break;
+ case M_SOF15: process = "Differential lossless, arithmetic coding"; break;
+ default: process = "Unknown"; break;
+ }
+
+ printf("JPEG image is %uw * %uh, %d color components, %d bits per sample\n",
+ image_width, image_height, num_components, data_precision);
+ printf("JPEG process: %s\n", process);
+
+ if (length != (unsigned int) (8 + num_components * 3))
+ ERREXIT("Bogus SOF marker length");
+
+ for (ci = 0; ci < num_components; ci++) {
+ (void) read_1_byte(); /* Component ID code */
+ (void) read_1_byte(); /* H, V sampling factors */
+ (void) read_1_byte(); /* Quantization table number */
+ }
+}
+
+
+/*
+ * Parse the marker stream until SOS or EOI is seen;
+ * display any COM markers.
+ * While the companion program wrjpgcom will always insert COM markers before
+ * SOFn, other implementations might not, so we scan to SOS before stopping.
+ * If we were only interested in the image dimensions, we would stop at SOFn.
+ * (Conversely, if we only cared about COM markers, there would be no need
+ * for special code to handle SOFn; we could treat it like other markers.)
+ */
+
+static int
+scan_JPEG_header (int verbose, int raw)
+{
+ int marker;
+
+ /* Expect SOI at start of file */
+ if (first_marker() != M_SOI)
+ ERREXIT("Expected SOI marker first");
+
+ /* Scan miscellaneous markers until we reach SOS. */
+ for (;;) {
+ marker = next_marker();
+ switch (marker) {
+ /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
+ * treated as SOFn. C4 in particular is actually DHT.
+ */
+ case M_SOF0: /* Baseline */
+ case M_SOF1: /* Extended sequential, Huffman */
+ case M_SOF2: /* Progressive, Huffman */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_SOF9: /* Extended sequential, arithmetic */
+ case M_SOF10: /* Progressive, arithmetic */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ if (verbose)
+ process_SOFn(marker);
+ else
+ skip_variable();
+ break;
+
+ case M_SOS: /* stop before hitting compressed data */
+ return marker;
+
+ case M_EOI: /* in case it's a tables-only JPEG stream */
+ return marker;
+
+ case M_COM:
+ process_COM(raw);
+ break;
+
+ case M_APP12:
+ /* Some digital camera makers put useful textual information into
+ * APP12 markers, so we print those out too when in -verbose mode.
+ */
+ if (verbose) {
+ printf("APP12 contains:\n");
+ process_COM(raw);
+ } else
+ skip_variable();
+ break;
+
+ default: /* Anything else just gets skipped */
+ skip_variable(); /* we assume it has a parameter count... */
+ break;
+ }
+ } /* end loop */
+}
+
+
+/* Command line parsing code */
+
+static const char * progname; /* program name for error messages */
+
+
+static void
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "rdjpgcom displays any textual comments in a JPEG file.\n");
+
+ fprintf(stderr, "Usage: %s [switches] [inputfile]\n", progname);
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -raw Display non-printable characters in comments (unsafe)\n");
+ fprintf(stderr, " -verbose Also display dimensions of JPEG image\n");
+
+ exit(EXIT_FAILURE);
+}
+
+
+static int
+keymatch (char * arg, const char * keyword, int minchars)
+/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
+/* keyword is the constant keyword (must be lower case already), */
+/* minchars is length of minimum legal abbreviation. */
+{
+ register int ca, ck;
+ register int nmatched = 0;
+
+ while ((ca = *arg++) != '\0') {
+ if ((ck = *keyword++) == '\0')
+ return 0; /* arg longer than keyword, no good */
+ if (isupper(ca)) /* force arg to lcase (assume ck is already) */
+ ca = tolower(ca);
+ if (ca != ck)
+ return 0; /* no good */
+ nmatched++; /* count matched characters */
+ }
+ /* reached end of argument; fail if it's too short for unique abbrev */
+ if (nmatched < minchars)
+ return 0;
+ return 1; /* A-OK */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ int argn;
+ char * arg;
+ int verbose = 0, raw = 0;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "rdjpgcom"; /* in case C library doesn't provide it */
+
+ /* Parse switches, if any */
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (arg[0] != '-')
+ break; /* not switch, must be file name */
+ arg++; /* advance over '-' */
+ if (keymatch(arg, "verbose", 1)) {
+ verbose++;
+ } else if (keymatch(arg, "raw", 1)) {
+ raw = 1;
+ } else
+ usage();
+ }
+
+ /* Open the input file. */
+ /* Unix style: expect zero or one file name */
+ if (argn < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+ if (argn < argc) {
+ if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open stdin\n", progname);
+ exit(EXIT_FAILURE);
+ }
+#else
+ infile = stdin;
+#endif
+ }
+
+ /* Scan the JPEG headers. */
+ (void) scan_JPEG_header(verbose, raw);
+
+ /* All done. */
+ exit(EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/jpg/rdppm.c b/jpg/rdppm.c
new file mode 100644
index 0000000..a757022
--- /dev/null
+++ b/jpg/rdppm.c
@@ -0,0 +1,459 @@
+/*
+ * rdppm.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * Modified 2009 by Bill Allombert, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in PPM/PGM format.
+ * The extended 2-byte-per-sample raw PPM/PGM formats are supported.
+ * The PBMPLUS library is NOT required to compile this software
+ * (but it is highly useful as a set of PPM image manipulation programs).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed PPM format).
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef PPM_SUPPORTED
+
+
+/* Portions of this code are based on the PBMPLUS library, which is:
+**
+** Copyright (C) 1988 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation. This software is provided "as is" without express or
+** implied warranty.
+*/
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x) ((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x) ((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x) ((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/*
+ * On most systems, reading individual bytes with getc() is drastically less
+ * efficient than buffering a row at a time with fread(). On PCs, we must
+ * allocate the buffer in near data space, because we are assuming small-data
+ * memory model, wherein fread() can't reach far memory. If you need to
+ * process very wide images on a PC, you might have to compile in large-memory
+ * model, or else replace fread() with a getc() loop --- which will be much
+ * slower.
+ */
+
+
+/* Private version of data source object */
+
+typedef struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ U_CHAR *iobuffer; /* non-FAR pointer to I/O buffer */
+ JSAMPROW pixrow; /* FAR pointer to same */
+ size_t buffer_width; /* width of I/O buffer */
+ JSAMPLE *rescale; /* => maxval-remapping array, or NULL */
+} ppm_source_struct;
+
+typedef ppm_source_struct * ppm_source_ptr;
+
+
+LOCAL(int)
+pbm_getc (FILE * infile)
+/* Read next char, skipping over any comments */
+/* A comment/newline sequence is returned as a newline */
+{
+ register int ch;
+
+ ch = getc(infile);
+ if (ch == '#') {
+ do {
+ ch = getc(infile);
+ } while (ch != '\n' && ch != EOF);
+ }
+ return ch;
+}
+
+
+LOCAL(unsigned int)
+read_pbm_integer (j_compress_ptr cinfo, FILE * infile)
+/* Read an unsigned decimal integer from the PPM file */
+/* Swallows one trailing character after the integer */
+/* Note that on a 16-bit-int machine, only values up to 64k can be read. */
+/* This should not be a problem in practice. */
+{
+ register int ch;
+ register unsigned int val;
+
+ /* Skip any leading whitespace */
+ do {
+ ch = pbm_getc(infile);
+ if (ch == EOF)
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
+
+ if (ch < '0' || ch > '9')
+ ERREXIT(cinfo, JERR_PPM_NONNUMERIC);
+
+ val = ch - '0';
+ while ((ch = pbm_getc(infile)) >= '0' && ch <= '9') {
+ val *= 10;
+ val += ch - '0';
+ }
+ return val;
+}
+
+
+/*
+ * Read one row of pixels.
+ *
+ * We provide several different versions depending on input file format.
+ * In all cases, input is scaled to the size of JSAMPLE.
+ *
+ * A really fast path is provided for reading byte/sample raw files with
+ * maxval = MAXJSAMPLE, which is the normal case for 8-bit data.
+ */
+
+
+METHODDEF(JDIMENSION)
+get_text_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PGM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ FILE * infile = source->pub.input_file;
+ register JSAMPROW ptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_text_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading text-format PPM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ FILE * infile = source->pub.input_file;
+ register JSAMPROW ptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+ *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+ *ptr++ = rescale[read_pbm_integer(cinfo, infile)];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_scaled_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PGM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR * bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ *ptr++ = rescale[UCH(*bufferptr++)];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_scaled_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format PPM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR * bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ *ptr++ = rescale[UCH(*bufferptr++)];
+ *ptr++ = rescale[UCH(*bufferptr++)];
+ *ptr++ = rescale[UCH(*bufferptr++)];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_raw_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-byte-format files with maxval = MAXJSAMPLE.
+ * In this case we just read right into the JSAMPLE buffer!
+ * Note that same code works for PPM and PGM files.
+ */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_word_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PGM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR * bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ register int temp;
+ temp = UCH(*bufferptr++) << 8;
+ temp |= UCH(*bufferptr++);
+ *ptr++ = rescale[temp];
+ }
+ return 1;
+}
+
+
+METHODDEF(JDIMENSION)
+get_word_rgb_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading raw-word-format PPM files with any maxval */
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register U_CHAR * bufferptr;
+ register JSAMPLE *rescale = source->rescale;
+ JDIMENSION col;
+
+ if (! ReadOK(source->pub.input_file, source->iobuffer, source->buffer_width))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+ ptr = source->pub.buffer[0];
+ bufferptr = source->iobuffer;
+ for (col = cinfo->image_width; col > 0; col--) {
+ register int temp;
+ temp = UCH(*bufferptr++) << 8;
+ temp |= UCH(*bufferptr++);
+ *ptr++ = rescale[temp];
+ temp = UCH(*bufferptr++) << 8;
+ temp |= UCH(*bufferptr++);
+ *ptr++ = rescale[temp];
+ temp = UCH(*bufferptr++) << 8;
+ temp |= UCH(*bufferptr++);
+ *ptr++ = rescale[temp];
+ }
+ return 1;
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ ppm_source_ptr source = (ppm_source_ptr) sinfo;
+ int c;
+ unsigned int w, h, maxval;
+ boolean need_iobuffer, use_raw_buffer, need_rescale;
+
+ if (getc(source->pub.input_file) != 'P')
+ ERREXIT(cinfo, JERR_PPM_NOT);
+
+ c = getc(source->pub.input_file); /* subformat discriminator character */
+
+ /* detect unsupported variants (ie, PBM) before trying to read header */
+ switch (c) {
+ case '2': /* it's a text-format PGM file */
+ case '3': /* it's a text-format PPM file */
+ case '5': /* it's a raw-format PGM file */
+ case '6': /* it's a raw-format PPM file */
+ break;
+ default:
+ ERREXIT(cinfo, JERR_PPM_NOT);
+ break;
+ }
+
+ /* fetch the remaining header info */
+ w = read_pbm_integer(cinfo, source->pub.input_file);
+ h = read_pbm_integer(cinfo, source->pub.input_file);
+ maxval = read_pbm_integer(cinfo, source->pub.input_file);
+
+ if (w <= 0 || h <= 0 || maxval <= 0) /* error check */
+ ERREXIT(cinfo, JERR_PPM_NOT);
+
+ cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */
+ cinfo->image_width = (JDIMENSION) w;
+ cinfo->image_height = (JDIMENSION) h;
+
+ /* initialize flags to most common settings */
+ need_iobuffer = TRUE; /* do we need an I/O buffer? */
+ use_raw_buffer = FALSE; /* do we map input buffer onto I/O buffer? */
+ need_rescale = TRUE; /* do we need a rescale array? */
+
+ switch (c) {
+ case '2': /* it's a text-format PGM file */
+ cinfo->input_components = 1;
+ cinfo->in_color_space = JCS_GRAYSCALE;
+ TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h);
+ source->pub.get_pixel_rows = get_text_gray_row;
+ need_iobuffer = FALSE;
+ break;
+
+ case '3': /* it's a text-format PPM file */
+ cinfo->input_components = 3;
+ cinfo->in_color_space = JCS_RGB;
+ TRACEMS2(cinfo, 1, JTRC_PPM_TEXT, w, h);
+ source->pub.get_pixel_rows = get_text_rgb_row;
+ need_iobuffer = FALSE;
+ break;
+
+ case '5': /* it's a raw-format PGM file */
+ cinfo->input_components = 1;
+ cinfo->in_color_space = JCS_GRAYSCALE;
+ TRACEMS2(cinfo, 1, JTRC_PGM, w, h);
+ if (maxval > 255) {
+ source->pub.get_pixel_rows = get_word_gray_row;
+ } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
+ source->pub.get_pixel_rows = get_raw_row;
+ use_raw_buffer = TRUE;
+ need_rescale = FALSE;
+ } else {
+ source->pub.get_pixel_rows = get_scaled_gray_row;
+ }
+ break;
+
+ case '6': /* it's a raw-format PPM file */
+ cinfo->input_components = 3;
+ cinfo->in_color_space = JCS_RGB;
+ TRACEMS2(cinfo, 1, JTRC_PPM, w, h);
+ if (maxval > 255) {
+ source->pub.get_pixel_rows = get_word_rgb_row;
+ } else if (maxval == MAXJSAMPLE && SIZEOF(JSAMPLE) == SIZEOF(U_CHAR)) {
+ source->pub.get_pixel_rows = get_raw_row;
+ use_raw_buffer = TRUE;
+ need_rescale = FALSE;
+ } else {
+ source->pub.get_pixel_rows = get_scaled_rgb_row;
+ }
+ break;
+ }
+
+ /* Allocate space for I/O buffer: 1 or 3 bytes or words/pixel. */
+ if (need_iobuffer) {
+ source->buffer_width = (size_t) w * cinfo->input_components *
+ ((maxval<=255) ? SIZEOF(U_CHAR) : (2*SIZEOF(U_CHAR)));
+ source->iobuffer = (U_CHAR *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ source->buffer_width);
+ }
+
+ /* Create compressor input buffer. */
+ if (use_raw_buffer) {
+ /* For unscaled raw-input case, we can just map it onto the I/O buffer. */
+ /* Synthesize a JSAMPARRAY pointer structure */
+ /* Cast here implies near->far pointer conversion on PCs */
+ source->pixrow = (JSAMPROW) source->iobuffer;
+ source->pub.buffer = & source->pixrow;
+ source->pub.buffer_height = 1;
+ } else {
+ /* Need to translate anyway, so make a separate sample buffer. */
+ source->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) w * cinfo->input_components, (JDIMENSION) 1);
+ source->pub.buffer_height = 1;
+ }
+
+ /* Compute the rescaling array if required. */
+ if (need_rescale) {
+ INT32 val, half_maxval;
+
+ /* On 16-bit-int machines we have to be careful of maxval = 65535 */
+ source->rescale = (JSAMPLE *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) (((long) maxval + 1L) * SIZEOF(JSAMPLE)));
+ half_maxval = maxval / 2;
+ for (val = 0; val <= (INT32) maxval; val++) {
+ /* The multiplication here must be done in 32 bits to avoid overflow */
+ source->rescale[val] = (JSAMPLE) ((val*MAXJSAMPLE + half_maxval)/maxval);
+ }
+ }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_ppm (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for PPM format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_ppm (j_compress_ptr cinfo)
+{
+ ppm_source_ptr source;
+
+ /* Create module interface object */
+ source = (ppm_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(ppm_source_struct));
+ /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+ source->pub.start_input = start_input_ppm;
+ source->pub.finish_input = finish_input_ppm;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* PPM_SUPPORTED */
diff --git a/jpg/rdrle.c b/jpg/rdrle.c
new file mode 100644
index 0000000..542bc37
--- /dev/null
+++ b/jpg/rdrle.c
@@ -0,0 +1,387 @@
+/*
+ * rdrle.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Utah RLE format.
+ * The Utah Raster Toolkit library is required (version 3.1 or later).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed RLE format).
+ *
+ * Based on code contributed by Mike Lijewski,
+ * with updates from Robert Hutchinson.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef RLE_SUPPORTED
+
+/* rle.h is provided by the Utah Raster Toolkit. */
+
+#include <rle.h>
+
+/*
+ * We assume that JSAMPLE has the same representation as rle_pixel,
+ * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+/*
+ * We support the following types of RLE files:
+ *
+ * GRAYSCALE - 8 bits, no colormap
+ * MAPPEDGRAY - 8 bits, 1 channel colomap
+ * PSEUDOCOLOR - 8 bits, 3 channel colormap
+ * TRUECOLOR - 24 bits, 3 channel colormap
+ * DIRECTCOLOR - 24 bits, no colormap
+ *
+ * For now, we ignore any alpha channel in the image.
+ */
+
+typedef enum
+ { GRAYSCALE, MAPPEDGRAY, PSEUDOCOLOR, TRUECOLOR, DIRECTCOLOR } rle_kind;
+
+
+/*
+ * Since RLE stores scanlines bottom-to-top, we have to invert the image
+ * to conform to JPEG's top-to-bottom order. To do this, we read the
+ * incoming image into a virtual array on the first get_pixel_rows call,
+ * then fetch the required row from the virtual array on subsequent calls.
+ */
+
+typedef struct _rle_source_struct * rle_source_ptr;
+
+typedef struct _rle_source_struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ rle_kind visual; /* actual type of input file */
+ jvirt_sarray_ptr image; /* virtual array to hold the image */
+ JDIMENSION row; /* current row # in the virtual array */
+ rle_hdr header; /* Input file information */
+ rle_pixel** rle_row; /* holds a row returned by rle_getrow() */
+
+} rle_source_struct;
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ rle_source_ptr source = (rle_source_ptr) sinfo;
+ JDIMENSION width, height;
+#ifdef PROGRESS_REPORT
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+ /* Use RLE library routine to get the header info */
+ source->header = *rle_hdr_init(NULL);
+ source->header.rle_file = source->pub.input_file;
+ switch (rle_get_setup(&(source->header))) {
+ case RLE_SUCCESS:
+ /* A-OK */
+ break;
+ case RLE_NOT_RLE:
+ ERREXIT(cinfo, JERR_RLE_NOT);
+ break;
+ case RLE_NO_SPACE:
+ ERREXIT(cinfo, JERR_RLE_MEM);
+ break;
+ case RLE_EMPTY:
+ ERREXIT(cinfo, JERR_RLE_EMPTY);
+ break;
+ case RLE_EOF:
+ ERREXIT(cinfo, JERR_RLE_EOF);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_RLE_BADERROR);
+ break;
+ }
+
+ /* Figure out what we have, set private vars and return values accordingly */
+
+ width = source->header.xmax - source->header.xmin + 1;
+ height = source->header.ymax - source->header.ymin + 1;
+ source->header.xmin = 0; /* realign horizontally */
+ source->header.xmax = width-1;
+
+ cinfo->image_width = width;
+ cinfo->image_height = height;
+ cinfo->data_precision = 8; /* we can only handle 8 bit data */
+
+ if (source->header.ncolors == 1 && source->header.ncmap == 0) {
+ source->visual = GRAYSCALE;
+ TRACEMS2(cinfo, 1, JTRC_RLE_GRAY, width, height);
+ } else if (source->header.ncolors == 1 && source->header.ncmap == 1) {
+ source->visual = MAPPEDGRAY;
+ TRACEMS3(cinfo, 1, JTRC_RLE_MAPGRAY, width, height,
+ 1 << source->header.cmaplen);
+ } else if (source->header.ncolors == 1 && source->header.ncmap == 3) {
+ source->visual = PSEUDOCOLOR;
+ TRACEMS3(cinfo, 1, JTRC_RLE_MAPPED, width, height,
+ 1 << source->header.cmaplen);
+ } else if (source->header.ncolors == 3 && source->header.ncmap == 3) {
+ source->visual = TRUECOLOR;
+ TRACEMS3(cinfo, 1, JTRC_RLE_FULLMAP, width, height,
+ 1 << source->header.cmaplen);
+ } else if (source->header.ncolors == 3 && source->header.ncmap == 0) {
+ source->visual = DIRECTCOLOR;
+ TRACEMS2(cinfo, 1, JTRC_RLE, width, height);
+ } else
+ ERREXIT(cinfo, JERR_RLE_UNSUPPORTED);
+
+ if (source->visual == GRAYSCALE || source->visual == MAPPEDGRAY) {
+ cinfo->in_color_space = JCS_GRAYSCALE;
+ cinfo->input_components = 1;
+ } else {
+ cinfo->in_color_space = JCS_RGB;
+ cinfo->input_components = 3;
+ }
+
+ /*
+ * A place to hold each scanline while it's converted.
+ * (GRAYSCALE scanlines don't need converting)
+ */
+ if (source->visual != GRAYSCALE) {
+ source->rle_row = (rle_pixel**) (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) width, (JDIMENSION) cinfo->input_components);
+ }
+
+ /* request a virtual array to hold the image */
+ source->image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) (width * source->header.ncolors),
+ (JDIMENSION) height, (JDIMENSION) 1);
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ /* count file input as separate pass */
+ progress->total_extra_passes++;
+ }
+#endif
+
+ source->pub.buffer_height = 1;
+}
+
+
+/*
+ * Read one row of pixels.
+ * Called only after load_image has read the image into the virtual array.
+ * Used for GRAYSCALE, MAPPEDGRAY, TRUECOLOR, and DIRECTCOLOR images.
+ */
+
+METHODDEF(JDIMENSION)
+get_rle_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ rle_source_ptr source = (rle_source_ptr) sinfo;
+
+ source->row--;
+ source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
+
+ return 1;
+}
+
+/*
+ * Read one row of pixels.
+ * Called only after load_image has read the image into the virtual array.
+ * Used for PSEUDOCOLOR images.
+ */
+
+METHODDEF(JDIMENSION)
+get_pseudocolor_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ rle_source_ptr source = (rle_source_ptr) sinfo;
+ JSAMPROW src_row, dest_row;
+ JDIMENSION col;
+ rle_map *colormap;
+ int val;
+
+ colormap = source->header.cmap;
+ dest_row = source->pub.buffer[0];
+ source->row--;
+ src_row = * (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, source->row, (JDIMENSION) 1, FALSE);
+
+ for (col = cinfo->image_width; col > 0; col--) {
+ val = GETJSAMPLE(*src_row++);
+ *dest_row++ = (JSAMPLE) (colormap[val ] >> 8);
+ *dest_row++ = (JSAMPLE) (colormap[val + 256] >> 8);
+ *dest_row++ = (JSAMPLE) (colormap[val + 512] >> 8);
+ }
+
+ return 1;
+}
+
+
+/*
+ * Load the image into a virtual array. We have to do this because RLE
+ * files start at the lower left while the JPEG standard has them starting
+ * in the upper left. This is called the first time we want to get a row
+ * of input. What we do is load the RLE data into the array and then call
+ * the appropriate routine to read one row from the array. Before returning,
+ * we set source->pub.get_pixel_rows so that subsequent calls go straight to
+ * the appropriate row-reading routine.
+ */
+
+METHODDEF(JDIMENSION)
+load_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ rle_source_ptr source = (rle_source_ptr) sinfo;
+ JDIMENSION row, col;
+ JSAMPROW scanline, red_ptr, green_ptr, blue_ptr;
+ rle_pixel **rle_row;
+ rle_map *colormap;
+ char channel;
+#ifdef PROGRESS_REPORT
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+ colormap = source->header.cmap;
+ rle_row = source->rle_row;
+
+ /* Read the RLE data into our virtual array.
+ * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
+ * and (b) we are not on a machine where FAR pointers differ from regular.
+ */
+ RLE_CLR_BIT(source->header, RLE_ALPHA); /* don't read the alpha channel */
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_limit = cinfo->image_height;
+ progress->pub.pass_counter = 0;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+
+ switch (source->visual) {
+
+ case GRAYSCALE:
+ case PSEUDOCOLOR:
+ for (row = 0; row < cinfo->image_height; row++) {
+ rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+ rle_getrow(&source->header, rle_row);
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ break;
+
+ case MAPPEDGRAY:
+ case TRUECOLOR:
+ for (row = 0; row < cinfo->image_height; row++) {
+ scanline = * (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+ rle_row = source->rle_row;
+ rle_getrow(&source->header, rle_row);
+
+ for (col = 0; col < cinfo->image_width; col++) {
+ for (channel = 0; channel < source->header.ncolors; channel++) {
+ *scanline++ = (JSAMPLE)
+ (colormap[GETJSAMPLE(rle_row[channel][col]) + 256 * channel] >> 8);
+ }
+ }
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ break;
+
+ case DIRECTCOLOR:
+ for (row = 0; row < cinfo->image_height; row++) {
+ scanline = * (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->image, row, (JDIMENSION) 1, TRUE);
+ rle_getrow(&source->header, rle_row);
+
+ red_ptr = rle_row[0];
+ green_ptr = rle_row[1];
+ blue_ptr = rle_row[2];
+
+ for (col = cinfo->image_width; col > 0; col--) {
+ *scanline++ = *red_ptr++;
+ *scanline++ = *green_ptr++;
+ *scanline++ = *blue_ptr++;
+ }
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ }
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+#endif
+
+ /* Set up to call proper row-extraction routine in future */
+ if (source->visual == PSEUDOCOLOR) {
+ source->pub.buffer = source->rle_row;
+ source->pub.get_pixel_rows = get_pseudocolor_row;
+ } else {
+ source->pub.get_pixel_rows = get_rle_row;
+ }
+ source->row = cinfo->image_height;
+
+ /* And fetch the topmost (bottommost) row */
+ return (*source->pub.get_pixel_rows) (cinfo, sinfo);
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_rle (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for RLE format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_rle (j_compress_ptr cinfo)
+{
+ rle_source_ptr source;
+
+ /* Create module interface object */
+ source = (rle_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(rle_source_struct));
+ /* Fill in method ptrs */
+ source->pub.start_input = start_input_rle;
+ source->pub.finish_input = finish_input_rle;
+ source->pub.get_pixel_rows = load_image;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* RLE_SUPPORTED */
diff --git a/jpg/rdswitch.c b/jpg/rdswitch.c
new file mode 100644
index 0000000..7a839af
--- /dev/null
+++ b/jpg/rdswitch.c
@@ -0,0 +1,365 @@
+/*
+ * rdswitch.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to process some of cjpeg's more complicated
+ * command-line switches. Switches processed here are:
+ * -qtables file Read quantization tables from text file
+ * -scans file Read scan script from text file
+ * -quality N[,N,...] Set quality ratings
+ * -qslots N[,N,...] Set component quantization table selectors
+ * -sample HxV[,HxV,...] Set component sampling factors
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+#include <ctype.h> /* to declare isdigit(), isspace() */
+
+
+LOCAL(int)
+text_getc (FILE * file)
+/* Read next char, skipping over any comments (# to end of line) */
+/* A comment/newline sequence is returned as a newline */
+{
+ register int ch;
+
+ ch = getc(file);
+ if (ch == '#') {
+ do {
+ ch = getc(file);
+ } while (ch != '\n' && ch != EOF);
+ }
+ return ch;
+}
+
+
+LOCAL(boolean)
+read_text_integer (FILE * file, long * result, int * termchar)
+/* Read an unsigned decimal integer from a file, store it in result */
+/* Reads one trailing character after the integer; returns it in termchar */
+{
+ register int ch;
+ register long val;
+
+ /* Skip any leading whitespace, detect EOF */
+ do {
+ ch = text_getc(file);
+ if (ch == EOF) {
+ *termchar = ch;
+ return FALSE;
+ }
+ } while (isspace(ch));
+
+ if (! isdigit(ch)) {
+ *termchar = ch;
+ return FALSE;
+ }
+
+ val = ch - '0';
+ while ((ch = text_getc(file)) != EOF) {
+ if (! isdigit(ch))
+ break;
+ val *= 10;
+ val += ch - '0';
+ }
+ *result = val;
+ *termchar = ch;
+ return TRUE;
+}
+
+
+GLOBAL(boolean)
+read_quant_tables (j_compress_ptr cinfo, char * filename, boolean force_baseline)
+/* Read a set of quantization tables from the specified file.
+ * The file is plain ASCII text: decimal numbers with whitespace between.
+ * Comments preceded by '#' may be included in the file.
+ * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
+ * The tables are implicitly numbered 0,1,etc.
+ * NOTE: does not affect the qslots mapping, which will default to selecting
+ * table 0 for luminance (or primary) components, 1 for chrominance components.
+ * You must use -qslots if you want a different component->table mapping.
+ */
+{
+ FILE * fp;
+ int tblno, i, termchar;
+ long val;
+ unsigned int table[DCTSIZE2];
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ fprintf(stderr, "Can't open table file %s\n", filename);
+ return FALSE;
+ }
+ tblno = 0;
+
+ while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
+ if (tblno >= NUM_QUANT_TBLS) {
+ fprintf(stderr, "Too many tables in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+ table[0] = (unsigned int) val;
+ for (i = 1; i < DCTSIZE2; i++) {
+ if (! read_text_integer(fp, &val, &termchar)) {
+ fprintf(stderr, "Invalid table data in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+ table[i] = (unsigned int) val;
+ }
+ jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
+ force_baseline);
+ tblno++;
+ }
+
+ if (termchar != EOF) {
+ fprintf(stderr, "Non-numeric data in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+
+ fclose(fp);
+ return TRUE;
+}
+
+
+#ifdef C_MULTISCAN_FILES_SUPPORTED
+
+LOCAL(boolean)
+read_scan_integer (FILE * file, long * result, int * termchar)
+/* Variant of read_text_integer that always looks for a non-space termchar;
+ * this simplifies parsing of punctuation in scan scripts.
+ */
+{
+ register int ch;
+
+ if (! read_text_integer(file, result, termchar))
+ return FALSE;
+ ch = *termchar;
+ while (ch != EOF && isspace(ch))
+ ch = text_getc(file);
+ if (isdigit(ch)) { /* oops, put it back */
+ if (ungetc(ch, file) == EOF)
+ return FALSE;
+ ch = ' ';
+ } else {
+ /* Any separators other than ';' and ':' are ignored;
+ * this allows user to insert commas, etc, if desired.
+ */
+ if (ch != EOF && ch != ';' && ch != ':')
+ ch = ' ';
+ }
+ *termchar = ch;
+ return TRUE;
+}
+
+
+GLOBAL(boolean)
+read_scan_script (j_compress_ptr cinfo, char * filename)
+/* Read a scan script from the specified text file.
+ * Each entry in the file defines one scan to be emitted.
+ * Entries are separated by semicolons ';'.
+ * An entry contains one to four component indexes,
+ * optionally followed by a colon ':' and four progressive-JPEG parameters.
+ * The component indexes denote which component(s) are to be transmitted
+ * in the current scan. The first component has index 0.
+ * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
+ * The file is free format text: any whitespace may appear between numbers
+ * and the ':' and ';' punctuation marks. Also, other punctuation (such
+ * as commas or dashes) can be placed between numbers if desired.
+ * Comments preceded by '#' may be included in the file.
+ * Note: we do very little validity checking here;
+ * jcmaster.c will validate the script parameters.
+ */
+{
+ FILE * fp;
+ int scanno, ncomps, termchar;
+ long val;
+ jpeg_scan_info * scanptr;
+#define MAX_SCANS 100 /* quite arbitrary limit */
+ jpeg_scan_info scans[MAX_SCANS];
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ fprintf(stderr, "Can't open scan definition file %s\n", filename);
+ return FALSE;
+ }
+ scanptr = scans;
+ scanno = 0;
+
+ while (read_scan_integer(fp, &val, &termchar)) {
+ if (scanno >= MAX_SCANS) {
+ fprintf(stderr, "Too many scans defined in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+ scanptr->component_index[0] = (int) val;
+ ncomps = 1;
+ while (termchar == ' ') {
+ if (ncomps >= MAX_COMPS_IN_SCAN) {
+ fprintf(stderr, "Too many components in one scan in file %s\n",
+ filename);
+ fclose(fp);
+ return FALSE;
+ }
+ if (! read_scan_integer(fp, &val, &termchar))
+ goto bogus;
+ scanptr->component_index[ncomps] = (int) val;
+ ncomps++;
+ }
+ scanptr->comps_in_scan = ncomps;
+ if (termchar == ':') {
+ if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+ goto bogus;
+ scanptr->Ss = (int) val;
+ if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+ goto bogus;
+ scanptr->Se = (int) val;
+ if (! read_scan_integer(fp, &val, &termchar) || termchar != ' ')
+ goto bogus;
+ scanptr->Ah = (int) val;
+ if (! read_scan_integer(fp, &val, &termchar))
+ goto bogus;
+ scanptr->Al = (int) val;
+ } else {
+ /* set non-progressive parameters */
+ scanptr->Ss = 0;
+ scanptr->Se = DCTSIZE2-1;
+ scanptr->Ah = 0;
+ scanptr->Al = 0;
+ }
+ if (termchar != ';' && termchar != EOF) {
+bogus:
+ fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+ scanptr++, scanno++;
+ }
+
+ if (termchar != EOF) {
+ fprintf(stderr, "Non-numeric data in file %s\n", filename);
+ fclose(fp);
+ return FALSE;
+ }
+
+ if (scanno > 0) {
+ /* Stash completed scan list in cinfo structure.
+ * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
+ * but if you want to compress multiple images you'd want JPOOL_PERMANENT.
+ */
+ scanptr = (jpeg_scan_info *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ scanno * SIZEOF(jpeg_scan_info));
+ MEMCOPY(scanptr, scans, scanno * SIZEOF(jpeg_scan_info));
+ cinfo->scan_info = scanptr;
+ cinfo->num_scans = scanno;
+ }
+
+ fclose(fp);
+ return TRUE;
+}
+
+#endif /* C_MULTISCAN_FILES_SUPPORTED */
+
+
+GLOBAL(boolean)
+set_quality_ratings (j_compress_ptr cinfo, char *arg, boolean force_baseline)
+/* Process a quality-ratings parameter string, of the form
+ * N[,N,...]
+ * If there are more q-table slots than parameters, the last value is replicated.
+ */
+{
+ int val = 75; /* default value */
+ int tblno;
+ char ch;
+
+ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+ if (*arg) {
+ ch = ','; /* if not set by sscanf, will be ',' */
+ if (sscanf(arg, "%d%c", &val, &ch) < 1)
+ return FALSE;
+ if (ch != ',') /* syntax check */
+ return FALSE;
+ /* Convert user 0-100 rating to percentage scaling */
+ cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
+ while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+ ;
+ } else {
+ /* reached end of parameter, set remaining factors to last value */
+ cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
+ }
+ }
+ jpeg_default_qtables(cinfo, force_baseline);
+ return TRUE;
+}
+
+
+GLOBAL(boolean)
+set_quant_slots (j_compress_ptr cinfo, char *arg)
+/* Process a quantization-table-selectors parameter string, of the form
+ * N[,N,...]
+ * If there are more components than parameters, the last value is replicated.
+ */
+{
+ int val = 0; /* default table # */
+ int ci;
+ char ch;
+
+ for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+ if (*arg) {
+ ch = ','; /* if not set by sscanf, will be ',' */
+ if (sscanf(arg, "%d%c", &val, &ch) < 1)
+ return FALSE;
+ if (ch != ',') /* syntax check */
+ return FALSE;
+ if (val < 0 || val >= NUM_QUANT_TBLS) {
+ fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
+ NUM_QUANT_TBLS-1);
+ return FALSE;
+ }
+ cinfo->comp_info[ci].quant_tbl_no = val;
+ while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+ ;
+ } else {
+ /* reached end of parameter, set remaining components to last table */
+ cinfo->comp_info[ci].quant_tbl_no = val;
+ }
+ }
+ return TRUE;
+}
+
+
+GLOBAL(boolean)
+set_sample_factors (j_compress_ptr cinfo, char *arg)
+/* Process a sample-factors parameter string, of the form
+ * HxV[,HxV,...]
+ * If there are more components than parameters, "1x1" is assumed for the rest.
+ */
+{
+ int ci, val1, val2;
+ char ch1, ch2;
+
+ for (ci = 0; ci < MAX_COMPONENTS; ci++) {
+ if (*arg) {
+ ch2 = ','; /* if not set by sscanf, will be ',' */
+ if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
+ return FALSE;
+ if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
+ return FALSE;
+ if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
+ fprintf(stderr, "JPEG sampling factors must be 1..4\n");
+ return FALSE;
+ }
+ cinfo->comp_info[ci].h_samp_factor = val1;
+ cinfo->comp_info[ci].v_samp_factor = val2;
+ while (*arg && *arg++ != ',') /* advance to next segment of arg string */
+ ;
+ } else {
+ /* reached end of parameter, set remaining components to 1x1 sampling */
+ cinfo->comp_info[ci].h_samp_factor = 1;
+ cinfo->comp_info[ci].v_samp_factor = 1;
+ }
+ }
+ return TRUE;
+}
diff --git a/jpg/rdtarga.c b/jpg/rdtarga.c
new file mode 100644
index 0000000..4c2cd26
--- /dev/null
+++ b/jpg/rdtarga.c
@@ -0,0 +1,500 @@
+/*
+ * rdtarga.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to read input images in Targa format.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume input from
+ * an ordinary stdio stream. They further assume that reading begins
+ * at the start of the file; start_input may need work if the
+ * user interface has already read some data (e.g., to determine that
+ * the file is indeed Targa format).
+ *
+ * Based on code contributed by Lee Daniel Crocker.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef TARGA_SUPPORTED
+
+
+/* Macros to deal with unsigned chars as efficiently as compiler allows */
+
+#ifdef HAVE_UNSIGNED_CHAR
+typedef unsigned char U_CHAR;
+#define UCH(x) ((int) (x))
+#else /* !HAVE_UNSIGNED_CHAR */
+#ifdef CHAR_IS_UNSIGNED
+typedef char U_CHAR;
+#define UCH(x) ((int) (x))
+#else
+typedef char U_CHAR;
+#define UCH(x) ((int) (x) & 0xFF)
+#endif
+#endif /* HAVE_UNSIGNED_CHAR */
+
+
+#define ReadOK(file,buffer,len) (JFREAD(file,buffer,len) == ((size_t) (len)))
+
+
+/* Private version of data source object */
+
+typedef struct _tga_source_struct * tga_source_ptr;
+
+typedef struct _tga_source_struct {
+ struct cjpeg_source_struct pub; /* public fields */
+
+ j_compress_ptr cinfo; /* back link saves passing separate parm */
+
+ JSAMPARRAY colormap; /* Targa colormap (converted to my format) */
+
+ jvirt_sarray_ptr whole_image; /* Needed if funny input row order */
+ JDIMENSION current_row; /* Current logical row number to read */
+
+ /* Pointer to routine to extract next Targa pixel from input file */
+ JMETHOD(void, read_pixel, (tga_source_ptr sinfo));
+
+ /* Result of read_pixel is delivered here: */
+ U_CHAR tga_pixel[4];
+
+ int pixel_size; /* Bytes per Targa pixel (1 to 4) */
+
+ /* State info for reading RLE-coded pixels; both counts must be init to 0 */
+ int block_count; /* # of pixels remaining in RLE block */
+ int dup_pixel_count; /* # of times to duplicate previous pixel */
+
+ /* This saves the correct pixel-row-expansion method for preload_image */
+ JMETHOD(JDIMENSION, get_pixel_rows, (j_compress_ptr cinfo,
+ cjpeg_source_ptr sinfo));
+} tga_source_struct;
+
+
+/* For expanding 5-bit pixel values to 8-bit with best rounding */
+
+static const UINT8 c5to8bits[32] = {
+ 0, 8, 16, 25, 33, 41, 49, 58,
+ 66, 74, 82, 90, 99, 107, 115, 123,
+ 132, 140, 148, 156, 165, 173, 181, 189,
+ 197, 206, 214, 222, 230, 239, 247, 255
+};
+
+
+
+LOCAL(int)
+read_byte (tga_source_ptr sinfo)
+/* Read next byte from Targa file */
+{
+ register FILE *infile = sinfo->pub.input_file;
+ register int c;
+
+ if ((c = getc(infile)) == EOF)
+ ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
+ return c;
+}
+
+
+LOCAL(void)
+read_colormap (tga_source_ptr sinfo, int cmaplen, int mapentrysize)
+/* Read the colormap from a Targa file */
+{
+ int i;
+
+ /* Presently only handles 24-bit BGR format */
+ if (mapentrysize != 24)
+ ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP);
+
+ for (i = 0; i < cmaplen; i++) {
+ sinfo->colormap[2][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[1][i] = (JSAMPLE) read_byte(sinfo);
+ sinfo->colormap[0][i] = (JSAMPLE) read_byte(sinfo);
+ }
+}
+
+
+/*
+ * read_pixel methods: get a single pixel from Targa file into tga_pixel[]
+ */
+
+METHODDEF(void)
+read_non_rle_pixel (tga_source_ptr sinfo)
+/* Read one Targa pixel from the input file; no RLE expansion */
+{
+ register FILE *infile = sinfo->pub.input_file;
+ register int i;
+
+ for (i = 0; i < sinfo->pixel_size; i++) {
+ sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
+ }
+}
+
+
+METHODDEF(void)
+read_rle_pixel (tga_source_ptr sinfo)
+/* Read one Targa pixel from the input file, expanding RLE data as needed */
+{
+ register FILE *infile = sinfo->pub.input_file;
+ register int i;
+
+ /* Duplicate previously read pixel? */
+ if (sinfo->dup_pixel_count > 0) {
+ sinfo->dup_pixel_count--;
+ return;
+ }
+
+ /* Time to read RLE block header? */
+ if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */
+ i = read_byte(sinfo);
+ if (i & 0x80) { /* Start of duplicate-pixel block? */
+ sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */
+ sinfo->block_count = 0; /* then read new block header */
+ } else {
+ sinfo->block_count = i & 0x7F; /* number of pixels after this one */
+ }
+ }
+
+ /* Read next pixel */
+ for (i = 0; i < sinfo->pixel_size; i++) {
+ sinfo->tga_pixel[i] = (U_CHAR) getc(infile);
+ }
+}
+
+
+/*
+ * Read one row of pixels.
+ *
+ * We provide several different versions depending on input file format.
+ */
+
+
+METHODDEF(JDIMENSION)
+get_8bit_gray_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit grayscale pixels */
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+ *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
+ }
+ return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_8bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 8-bit colormap indexes */
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ register int t;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+ register JSAMPARRAY colormap = source->colormap;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+ t = UCH(source->tga_pixel[0]);
+ *ptr++ = colormap[0][t];
+ *ptr++ = colormap[1][t];
+ *ptr++ = colormap[2][t];
+ }
+ return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_16bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 16-bit pixels */
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ register int t;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+ t = UCH(source->tga_pixel[0]);
+ t += UCH(source->tga_pixel[1]) << 8;
+ /* We expand 5 bit data to 8 bit sample width.
+ * The format of the 16-bit (LSB first) input word is
+ * xRRRRRGGGGGBBBBB
+ */
+ ptr[2] = (JSAMPLE) c5to8bits[t & 0x1F];
+ t >>= 5;
+ ptr[1] = (JSAMPLE) c5to8bits[t & 0x1F];
+ t >>= 5;
+ ptr[0] = (JSAMPLE) c5to8bits[t & 0x1F];
+ ptr += 3;
+ }
+ return 1;
+}
+
+METHODDEF(JDIMENSION)
+get_24bit_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+/* This version is for reading 24-bit pixels */
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = source->pub.buffer[0];
+ for (col = cinfo->image_width; col > 0; col--) {
+ (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
+ *ptr++ = (JSAMPLE) UCH(source->tga_pixel[2]); /* change BGR to RGB order */
+ *ptr++ = (JSAMPLE) UCH(source->tga_pixel[1]);
+ *ptr++ = (JSAMPLE) UCH(source->tga_pixel[0]);
+ }
+ return 1;
+}
+
+/*
+ * Targa also defines a 32-bit pixel format with order B,G,R,A.
+ * We presently ignore the attribute byte, so the code for reading
+ * these pixels is identical to the 24-bit routine above.
+ * This works because the actual pixel length is only known to read_pixel.
+ */
+
+#define get_32bit_row get_24bit_row
+
+
+/*
+ * This method is for re-reading the input data in standard top-down
+ * row order. The entire image has already been read into whole_image
+ * with proper conversion of pixel format, but it's in a funny row order.
+ */
+
+METHODDEF(JDIMENSION)
+get_memory_row (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ JDIMENSION source_row;
+
+ /* Compute row of source that maps to current_row of normal order */
+ /* For now, assume image is bottom-up and not interlaced. */
+ /* NEEDS WORK to support interlaced images! */
+ source_row = cinfo->image_height - source->current_row - 1;
+
+ /* Fetch that row from virtual array */
+ source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image,
+ source_row, (JDIMENSION) 1, FALSE);
+
+ source->current_row++;
+ return 1;
+}
+
+
+/*
+ * This method loads the image into whole_image during the first call on
+ * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
+ * get_memory_row on subsequent calls.
+ */
+
+METHODDEF(JDIMENSION)
+preload_image (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ JDIMENSION row;
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+ /* Read the data into a virtual array in input-file row order. */
+ for (row = 0; row < cinfo->image_height; row++) {
+ if (progress != NULL) {
+ progress->pub.pass_counter = (long) row;
+ progress->pub.pass_limit = (long) cinfo->image_height;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+ source->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, source->whole_image, row, (JDIMENSION) 1, TRUE);
+ (*source->get_pixel_rows) (cinfo, sinfo);
+ }
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+
+ /* Set up to read from the virtual array in unscrambled order */
+ source->pub.get_pixel_rows = get_memory_row;
+ source->current_row = 0;
+ /* And read the first row */
+ return get_memory_row(cinfo, sinfo);
+}
+
+
+/*
+ * Read the file header; return image size and component count.
+ */
+
+METHODDEF(void)
+start_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ tga_source_ptr source = (tga_source_ptr) sinfo;
+ U_CHAR targaheader[18];
+ int idlen, cmaptype, subtype, flags, interlace_type, components;
+ unsigned int width, height, maplen;
+ boolean is_bottom_up;
+
+#define GET_2B(offset) ((unsigned int) UCH(targaheader[offset]) + \
+ (((unsigned int) UCH(targaheader[offset+1])) << 8))
+
+ if (! ReadOK(source->pub.input_file, targaheader, 18))
+ ERREXIT(cinfo, JERR_INPUT_EOF);
+
+ /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */
+ if (targaheader[16] == 15)
+ targaheader[16] = 16;
+
+ idlen = UCH(targaheader[0]);
+ cmaptype = UCH(targaheader[1]);
+ subtype = UCH(targaheader[2]);
+ maplen = GET_2B(5);
+ width = GET_2B(12);
+ height = GET_2B(14);
+ source->pixel_size = UCH(targaheader[16]) >> 3;
+ flags = UCH(targaheader[17]); /* Image Descriptor byte */
+
+ is_bottom_up = ((flags & 0x20) == 0); /* bit 5 set => top-down */
+ interlace_type = flags >> 6; /* bits 6/7 are interlace code */
+
+ if (cmaptype > 1 || /* cmaptype must be 0 or 1 */
+ source->pixel_size < 1 || source->pixel_size > 4 ||
+ (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */
+ interlace_type != 0) /* currently don't allow interlaced image */
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+
+ if (subtype > 8) {
+ /* It's an RLE-coded file */
+ source->read_pixel = read_rle_pixel;
+ source->block_count = source->dup_pixel_count = 0;
+ subtype -= 8;
+ } else {
+ /* Non-RLE file */
+ source->read_pixel = read_non_rle_pixel;
+ }
+
+ /* Now should have subtype 1, 2, or 3 */
+ components = 3; /* until proven different */
+ cinfo->in_color_space = JCS_RGB;
+
+ switch (subtype) {
+ case 1: /* Colormapped image */
+ if (source->pixel_size == 1 && cmaptype == 1)
+ source->get_pixel_rows = get_8bit_row;
+ else
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height);
+ break;
+ case 2: /* RGB image */
+ switch (source->pixel_size) {
+ case 2:
+ source->get_pixel_rows = get_16bit_row;
+ break;
+ case 3:
+ source->get_pixel_rows = get_24bit_row;
+ break;
+ case 4:
+ source->get_pixel_rows = get_32bit_row;
+ break;
+ default:
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ break;
+ }
+ TRACEMS2(cinfo, 1, JTRC_TGA, width, height);
+ break;
+ case 3: /* Grayscale image */
+ components = 1;
+ cinfo->in_color_space = JCS_GRAYSCALE;
+ if (source->pixel_size == 1)
+ source->get_pixel_rows = get_8bit_gray_row;
+ else
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ break;
+ }
+
+ if (is_bottom_up) {
+ /* Create a virtual array to buffer the upside-down image. */
+ source->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) width * components, (JDIMENSION) height, (JDIMENSION) 1);
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+ /* source->pub.buffer will point to the virtual array. */
+ source->pub.buffer_height = 1; /* in case anyone looks at it */
+ source->pub.get_pixel_rows = preload_image;
+ } else {
+ /* Don't need a virtual array, but do need a one-row input buffer. */
+ source->whole_image = NULL;
+ source->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (JDIMENSION) width * components, (JDIMENSION) 1);
+ source->pub.buffer_height = 1;
+ source->pub.get_pixel_rows = source->get_pixel_rows;
+ }
+
+ while (idlen--) /* Throw away ID field */
+ (void) read_byte(source);
+
+ if (maplen > 0) {
+ if (maplen > 256 || GET_2B(3) != 0)
+ ERREXIT(cinfo, JERR_TGA_BADCMAP);
+ /* Allocate space to store the colormap */
+ source->colormap = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, (JDIMENSION) maplen, (JDIMENSION) 3);
+ /* and read it from the file */
+ read_colormap(source, (int) maplen, UCH(targaheader[7]));
+ } else {
+ if (cmaptype) /* but you promised a cmap! */
+ ERREXIT(cinfo, JERR_TGA_BADPARMS);
+ source->colormap = NULL;
+ }
+
+ cinfo->input_components = components;
+ cinfo->data_precision = 8;
+ cinfo->image_width = width;
+ cinfo->image_height = height;
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_input_tga (j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
+{
+ /* no work */
+}
+
+
+/*
+ * The module selection routine for Targa format input.
+ */
+
+GLOBAL(cjpeg_source_ptr)
+jinit_read_targa (j_compress_ptr cinfo)
+{
+ tga_source_ptr source;
+
+ /* Create module interface object */
+ source = (tga_source_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(tga_source_struct));
+ source->cinfo = cinfo; /* make back link for subroutines */
+ /* Fill in method ptrs, except get_pixel_rows which start_input sets */
+ source->pub.start_input = start_input_tga;
+ source->pub.finish_input = finish_input_tga;
+
+ return (cjpeg_source_ptr) source;
+}
+
+#endif /* TARGA_SUPPORTED */
diff --git a/jpg/readme.dos b/jpg/readme.dos
new file mode 100644
index 0000000..3267876
--- /dev/null
+++ b/jpg/readme.dos
@@ -0,0 +1,15 @@
+This archive contains a DOS-friendly version of the Independent JPEG Group's
+source code. It differs from the normal distribution in that:
+
+1. The archive format is zip rather than tar+gzip. You should be able to
+unpack it with PKUNZIP (2.04g or later) or Info-Zip's unzip or 7-Zip.
+
+2. Newlines have been converted from Unix (LF) to DOS (CR/LF) style in all
+text files, but not in the binary files (test*.*).
+
+3. Object files have been included for jmemdosa.asm. See jdosaobj.txt.
+
+Please see the main README file for the primary documentation.
+
+If you'd rather have a non-DOSified archive, see the ARCHIVE LOCATIONS section
+of README.
diff --git a/jpg/structure.txt b/jpg/structure.txt
new file mode 100644
index 0000000..44e48ca
--- /dev/null
+++ b/jpg/structure.txt
@@ -0,0 +1,941 @@
+IJG JPEG LIBRARY: SYSTEM ARCHITECTURE
+
+Copyright (C) 1991-2012, Thomas G. Lane, Guido Vollbeding.
+This file is part of the Independent JPEG Group's software.
+For conditions of distribution and use, see the accompanying README file.
+
+
+This file provides an overview of the architecture of the IJG JPEG software;
+that is, the functions of the various modules in the system and the interfaces
+between modules. For more precise details about any data structure or calling
+convention, see the include files and comments in the source code.
+
+We assume that the reader is already somewhat familiar with the JPEG standard.
+The README file includes references for learning about JPEG. The file
+libjpeg.txt describes the library from the viewpoint of an application
+programmer using the library; it's best to read that file before this one.
+Also, the file coderules.txt describes the coding style conventions we use.
+
+In this document, JPEG-specific terminology follows the JPEG standard:
+ A "component" means a color channel, e.g., Red or Luminance.
+ A "sample" is a single component value (i.e., one number in the image data).
+ A "coefficient" is a frequency coefficient (a DCT transform output number).
+ A "block" is an array of samples or coefficients.
+ An "MCU" (minimum coded unit) is an interleaved set of blocks of size
+ determined by the sampling factors, or a single block in a
+ noninterleaved scan.
+We do not use the terms "pixel" and "sample" interchangeably. When we say
+pixel, we mean an element of the full-size image, while a sample is an element
+of the downsampled image. Thus the number of samples may vary across
+components while the number of pixels does not. (This terminology is not used
+rigorously throughout the code, but it is used in places where confusion would
+otherwise result.)
+
+
+*** System features ***
+
+The IJG distribution contains two parts:
+ * A subroutine library for JPEG compression and decompression.
+ * cjpeg/djpeg, two sample applications that use the library to transform
+ JFIF JPEG files to and from several other image formats.
+cjpeg/djpeg are of no great intellectual complexity: they merely add a simple
+command-line user interface and I/O routines for several uncompressed image
+formats. This document concentrates on the library itself.
+
+We desire the library to be capable of supporting all JPEG baseline, extended
+sequential, and progressive DCT processes. The library does not support the
+hierarchical or lossless processes defined in the standard.
+
+Within these limits, any set of compression parameters allowed by the JPEG
+spec should be readable for decompression. (We can be more restrictive about
+what formats we can generate.) Although the system design allows for all
+parameter values, some uncommon settings are not yet implemented and may
+never be; nonintegral sampling ratios are the prime example. Furthermore,
+we treat 8-bit vs. 12-bit data precision as a compile-time switch, not a
+run-time option, because most machines can store 8-bit pixels much more
+compactly than 12-bit.
+
+By itself, the library handles only interchange JPEG datastreams --- in
+particular the widely used JFIF file format. The library can be used by
+surrounding code to process interchange or abbreviated JPEG datastreams that
+are embedded in more complex file formats. (For example, libtiff uses this
+library to implement JPEG compression within the TIFF file format.)
+
+The library includes a substantial amount of code that is not covered by the
+JPEG standard but is necessary for typical applications of JPEG. These
+functions preprocess the image before JPEG compression or postprocess it after
+decompression. They include colorspace conversion, downsampling/upsampling,
+and color quantization. This code can be omitted if not needed.
+
+A wide range of quality vs. speed tradeoffs are possible in JPEG processing,
+and even more so in decompression postprocessing. The decompression library
+provides multiple implementations that cover most of the useful tradeoffs,
+ranging from very-high-quality down to fast-preview operation. On the
+compression side we have generally not provided low-quality choices, since
+compression is normally less time-critical. It should be understood that the
+low-quality modes may not meet the JPEG standard's accuracy requirements;
+nonetheless, they are useful for viewers.
+
+
+*** Portability issues ***
+
+Portability is an essential requirement for the library. The key portability
+issues that show up at the level of system architecture are:
+
+1. Memory usage. We want the code to be able to run on PC-class machines
+with limited memory. Images should therefore be processed sequentially (in
+strips), to avoid holding the whole image in memory at once. Where a
+full-image buffer is necessary, we should be able to use either virtual memory
+or temporary files.
+
+2. Near/far pointer distinction. To run efficiently on 80x86 machines, the
+code should distinguish "small" objects (kept in near data space) from
+"large" ones (kept in far data space). This is an annoying restriction, but
+fortunately it does not impact code quality for less brain-damaged machines,
+and the source code clutter turns out to be minimal with sufficient use of
+pointer typedefs.
+
+3. Data precision. We assume that "char" is at least 8 bits, "short" and
+"int" at least 16, "long" at least 32. The code will work fine with larger
+data sizes, although memory may be used inefficiently in some cases. However,
+the JPEG compressed datastream must ultimately appear on external storage as a
+sequence of 8-bit bytes if it is to conform to the standard. This may pose a
+problem on machines where char is wider than 8 bits. The library represents
+compressed data as an array of values of typedef JOCTET. If no data type
+exactly 8 bits wide is available, custom data source and data destination
+modules must be written to unpack and pack the chosen JOCTET datatype into
+8-bit external representation.
+
+
+*** System overview ***
+
+The compressor and decompressor are each divided into two main sections:
+the JPEG compressor or decompressor proper, and the preprocessing or
+postprocessing functions. The interface between these two sections is the
+image data that the official JPEG spec regards as its input or output: this
+data is in the colorspace to be used for compression, and it is downsampled
+to the sampling factors to be used. The preprocessing and postprocessing
+steps are responsible for converting a normal image representation to or from
+this form. (Those few applications that want to deal with YCbCr downsampled
+data can skip the preprocessing or postprocessing step.)
+
+Looking more closely, the compressor library contains the following main
+elements:
+
+ Preprocessing:
+ * Color space conversion (e.g., RGB to YCbCr).
+ * Edge expansion and downsampling. Optionally, this step can do simple
+ smoothing --- this is often helpful for low-quality source data.
+ JPEG proper:
+ * MCU assembly, DCT, quantization.
+ * Entropy coding (sequential or progressive, Huffman or arithmetic).
+
+In addition to these modules we need overall control, marker generation,
+and support code (memory management & error handling). There is also a
+module responsible for physically writing the output data --- typically
+this is just an interface to fwrite(), but some applications may need to
+do something else with the data.
+
+The decompressor library contains the following main elements:
+
+ JPEG proper:
+ * Entropy decoding (sequential or progressive, Huffman or arithmetic).
+ * Dequantization, inverse DCT, MCU disassembly.
+ Postprocessing:
+ * Upsampling. Optionally, this step may be able to do more general
+ rescaling of the image.
+ * Color space conversion (e.g., YCbCr to RGB). This step may also
+ provide gamma adjustment [ currently it does not ].
+ * Optional color quantization (e.g., reduction to 256 colors).
+ * Optional color precision reduction (e.g., 24-bit to 15-bit color).
+ [This feature is not currently implemented.]
+
+We also need overall control, marker parsing, and a data source module.
+The support code (memory management & error handling) can be shared with
+the compression half of the library.
+
+There may be several implementations of each of these elements, particularly
+in the decompressor, where a wide range of speed/quality tradeoffs is very
+useful. It must be understood that some of the best speedups involve
+merging adjacent steps in the pipeline. For example, upsampling, color space
+conversion, and color quantization might all be done at once when using a
+low-quality ordered-dither technique. The system architecture is designed to
+allow such merging where appropriate.
+
+
+Note: it is convenient to regard edge expansion (padding to block boundaries)
+as a preprocessing/postprocessing function, even though the JPEG spec includes
+it in compression/decompression. We do this because downsampling/upsampling
+can be simplified a little if they work on padded data: it's not necessary to
+have special cases at the right and bottom edges. Therefore the interface
+buffer is always an integral number of blocks wide and high, and we expect
+compression preprocessing to pad the source data properly. Padding will occur
+only to the next block (N-sample) boundary. In an interleaved-scan situation,
+additional dummy blocks may be used to fill out MCUs, but the MCU assembly and
+disassembly logic will create or discard these blocks internally. (This is
+advantageous for speed reasons, since we avoid DCTing the dummy blocks.
+It also permits a small reduction in file size, because the compressor can
+choose dummy block contents so as to minimize their size in compressed form.
+Finally, it makes the interface buffer specification independent of whether
+the file is actually interleaved or not.) Applications that wish to deal
+directly with the downsampled data must provide similar buffering and padding
+for odd-sized images.
+
+
+*** Poor man's object-oriented programming ***
+
+It should be clear by now that we have a lot of quasi-independent processing
+steps, many of which have several possible behaviors. To avoid cluttering the
+code with lots of switch statements, we use a simple form of object-style
+programming to separate out the different possibilities.
+
+For example, two different color quantization algorithms could be implemented
+as two separate modules that present the same external interface; at runtime,
+the calling code will access the proper module indirectly through an "object".
+
+We can get the limited features we need while staying within portable C.
+The basic tool is a function pointer. An "object" is just a struct
+containing one or more function pointer fields, each of which corresponds to
+a method name in real object-oriented languages. During initialization we
+fill in the function pointers with references to whichever module we have
+determined we need to use in this run. Then invocation of the module is done
+by indirecting through a function pointer; on most machines this is no more
+expensive than a switch statement, which would be the only other way of
+making the required run-time choice. The really significant benefit, of
+course, is keeping the source code clean and well structured.
+
+We can also arrange to have private storage that varies between different
+implementations of the same kind of object. We do this by making all the
+module-specific object structs be separately allocated entities, which will
+be accessed via pointers in the master compression or decompression struct.
+The "public" fields or methods for a given kind of object are specified by
+a commonly known struct. But a module's initialization code can allocate
+a larger struct that contains the common struct as its first member, plus
+additional private fields. With appropriate pointer casting, the module's
+internal functions can access these private fields. (For a simple example,
+see jdatadst.c, which implements the external interface specified by struct
+jpeg_destination_mgr, but adds extra fields.)
+
+(Of course this would all be a lot easier if we were using C++, but we are
+not yet prepared to assume that everyone has a C++ compiler.)
+
+An important benefit of this scheme is that it is easy to provide multiple
+versions of any method, each tuned to a particular case. While a lot of
+precalculation might be done to select an optimal implementation of a method,
+the cost per invocation is constant. For example, the upsampling step might
+have a "generic" method, plus one or more "hardwired" methods for the most
+popular sampling factors; the hardwired methods would be faster because they'd
+use straight-line code instead of for-loops. The cost to determine which
+method to use is paid only once, at startup, and the selection criteria are
+hidden from the callers of the method.
+
+This plan differs a little bit from usual object-oriented structures, in that
+only one instance of each object class will exist during execution. The
+reason for having the class structure is that on different runs we may create
+different instances (choose to execute different modules). You can think of
+the term "method" as denoting the common interface presented by a particular
+set of interchangeable functions, and "object" as denoting a group of related
+methods, or the total shared interface behavior of a group of modules.
+
+
+*** Overall control structure ***
+
+We previously mentioned the need for overall control logic in the compression
+and decompression libraries. In IJG implementations prior to v5, overall
+control was mostly provided by "pipeline control" modules, which proved to be
+large, unwieldy, and hard to understand. To improve the situation, the
+control logic has been subdivided into multiple modules. The control modules
+consist of:
+
+1. Master control for module selection and initialization. This has two
+responsibilities:
+
+ 1A. Startup initialization at the beginning of image processing.
+ The individual processing modules to be used in this run are selected
+ and given initialization calls.
+
+ 1B. Per-pass control. This determines how many passes will be performed
+ and calls each active processing module to configure itself
+ appropriately at the beginning of each pass. End-of-pass processing,
+ where necessary, is also invoked from the master control module.
+
+ Method selection is partially distributed, in that a particular processing
+ module may contain several possible implementations of a particular method,
+ which it will select among when given its initialization call. The master
+ control code need only be concerned with decisions that affect more than
+ one module.
+
+2. Data buffering control. A separate control module exists for each
+ inter-processing-step data buffer. This module is responsible for
+ invoking the processing steps that write or read that data buffer.
+
+Each buffer controller sees the world as follows:
+
+input data => processing step A => buffer => processing step B => output data
+ | | |
+ ------------------ controller ------------------
+
+The controller knows the dataflow requirements of steps A and B: how much data
+they want to accept in one chunk and how much they output in one chunk. Its
+function is to manage its buffer and call A and B at the proper times.
+
+A data buffer control module may itself be viewed as a processing step by a
+higher-level control module; thus the control modules form a binary tree with
+elementary processing steps at the leaves of the tree.
+
+The control modules are objects. A considerable amount of flexibility can
+be had by replacing implementations of a control module. For example:
+* Merging of adjacent steps in the pipeline is done by replacing a control
+ module and its pair of processing-step modules with a single processing-
+ step module. (Hence the possible merges are determined by the tree of
+ control modules.)
+* In some processing modes, a given interstep buffer need only be a "strip"
+ buffer large enough to accommodate the desired data chunk sizes. In other
+ modes, a full-image buffer is needed and several passes are required.
+ The control module determines which kind of buffer is used and manipulates
+ virtual array buffers as needed. One or both processing steps may be
+ unaware of the multi-pass behavior.
+
+In theory, we might be able to make all of the data buffer controllers
+interchangeable and provide just one set of implementations for all. In
+practice, each one contains considerable special-case processing for its
+particular job. The buffer controller concept should be regarded as an
+overall system structuring principle, not as a complete description of the
+task performed by any one controller.
+
+
+*** Compression object structure ***
+
+Here is a sketch of the logical structure of the JPEG compression library:
+
+ |-- Colorspace conversion
+ |-- Preprocessing controller --|
+ | |-- Downsampling
+Main controller --|
+ | |-- Forward DCT, quantize
+ |-- Coefficient controller --|
+ |-- Entropy encoding
+
+This sketch also describes the flow of control (subroutine calls) during
+typical image data processing. Each of the components shown in the diagram is
+an "object" which may have several different implementations available. One
+or more source code files contain the actual implementation(s) of each object.
+
+The objects shown above are:
+
+* Main controller: buffer controller for the subsampled-data buffer, which
+ holds the preprocessed input data. This controller invokes preprocessing to
+ fill the subsampled-data buffer, and JPEG compression to empty it. There is
+ usually no need for a full-image buffer here; a strip buffer is adequate.
+
+* Preprocessing controller: buffer controller for the downsampling input data
+ buffer, which lies between colorspace conversion and downsampling. Note
+ that a unified conversion/downsampling module would probably replace this
+ controller entirely.
+
+* Colorspace conversion: converts application image data into the desired
+ JPEG color space; also changes the data from pixel-interleaved layout to
+ separate component planes. Processes one pixel row at a time.
+
+* Downsampling: performs reduction of chroma components as required.
+ Optionally may perform pixel-level smoothing as well. Processes a "row
+ group" at a time, where a row group is defined as Vmax pixel rows of each
+ component before downsampling, and Vk sample rows afterwards (remember Vk
+ differs across components). Some downsampling or smoothing algorithms may
+ require context rows above and below the current row group; the
+ preprocessing controller is responsible for supplying these rows via proper
+ buffering. The downsampler is responsible for edge expansion at the right
+ edge (i.e., extending each sample row to a multiple of N samples); but the
+ preprocessing controller is responsible for vertical edge expansion (i.e.,
+ duplicating the bottom sample row as needed to make a multiple of N rows).
+
+* Coefficient controller: buffer controller for the DCT-coefficient data.
+ This controller handles MCU assembly, including insertion of dummy DCT
+ blocks when needed at the right or bottom edge. When performing
+ Huffman-code optimization or emitting a multiscan JPEG file, this
+ controller is responsible for buffering the full image. The equivalent of
+ one fully interleaved MCU row of subsampled data is processed per call,
+ even when the JPEG file is noninterleaved.
+
+* Forward DCT and quantization: Perform DCT, quantize, and emit coefficients.
+ Works on one or more DCT blocks at a time. (Note: the coefficients are now
+ emitted in normal array order, which the entropy encoder is expected to
+ convert to zigzag order as necessary. Prior versions of the IJG code did
+ the conversion to zigzag order within the quantization step.)
+
+* Entropy encoding: Perform Huffman or arithmetic entropy coding and emit the
+ coded data to the data destination module. Works on one MCU per call.
+ For progressive JPEG, the same DCT blocks are fed to the entropy coder
+ during each pass, and the coder must emit the appropriate subset of
+ coefficients.
+
+In addition to the above objects, the compression library includes these
+objects:
+
+* Master control: determines the number of passes required, controls overall
+ and per-pass initialization of the other modules.
+
+* Marker writing: generates JPEG markers (except for RSTn, which is emitted
+ by the entropy encoder when needed).
+
+* Data destination manager: writes the output JPEG datastream to its final
+ destination (e.g., a file). The destination manager supplied with the
+ library knows how to write to a stdio stream or to a memory buffer;
+ for other behaviors, the surrounding application may provide its own
+ destination manager.
+
+* Memory manager: allocates and releases memory, controls virtual arrays
+ (with backing store management, where required).
+
+* Error handler: performs formatting and output of error and trace messages;
+ determines handling of nonfatal errors. The surrounding application may
+ override some or all of this object's methods to change error handling.
+
+* Progress monitor: supports output of "percent-done" progress reports.
+ This object represents an optional callback to the surrounding application:
+ if wanted, it must be supplied by the application.
+
+The error handler, destination manager, and progress monitor objects are
+defined as separate objects in order to simplify application-specific
+customization of the JPEG library. A surrounding application may override
+individual methods or supply its own all-new implementation of one of these
+objects. The object interfaces for these objects are therefore treated as
+part of the application interface of the library, whereas the other objects
+are internal to the library.
+
+The error handler and memory manager are shared by JPEG compression and
+decompression; the progress monitor, if used, may be shared as well.
+
+
+*** Decompression object structure ***
+
+Here is a sketch of the logical structure of the JPEG decompression library:
+
+ |-- Entropy decoding
+ |-- Coefficient controller --|
+ | |-- Dequantize, Inverse DCT
+Main controller --|
+ | |-- Upsampling
+ |-- Postprocessing controller --| |-- Colorspace conversion
+ |-- Color quantization
+ |-- Color precision reduction
+
+As before, this diagram also represents typical control flow. The objects
+shown are:
+
+* Main controller: buffer controller for the subsampled-data buffer, which
+ holds the output of JPEG decompression proper. This controller's primary
+ task is to feed the postprocessing procedure. Some upsampling algorithms
+ may require context rows above and below the current row group; when this
+ is true, the main controller is responsible for managing its buffer so as
+ to make context rows available. In the current design, the main buffer is
+ always a strip buffer; a full-image buffer is never required.
+
+* Coefficient controller: buffer controller for the DCT-coefficient data.
+ This controller handles MCU disassembly, including deletion of any dummy
+ DCT blocks at the right or bottom edge. When reading a multiscan JPEG
+ file, this controller is responsible for buffering the full image.
+ (Buffering DCT coefficients, rather than samples, is necessary to support
+ progressive JPEG.) The equivalent of one fully interleaved MCU row of
+ subsampled data is processed per call, even when the source JPEG file is
+ noninterleaved.
+
+* Entropy decoding: Read coded data from the data source module and perform
+ Huffman or arithmetic entropy decoding. Works on one MCU per call.
+ For progressive JPEG decoding, the coefficient controller supplies the prior
+ coefficients of each MCU (initially all zeroes), which the entropy decoder
+ modifies in each scan.
+
+* Dequantization and inverse DCT: like it says. Note that the coefficients
+ buffered by the coefficient controller have NOT been dequantized; we
+ merge dequantization and inverse DCT into a single step for speed reasons.
+ When scaled-down output is asked for, simplified DCT algorithms may be used
+ that need fewer coefficients and emit fewer samples per DCT block, not the
+ full 8x8. Works on one DCT block at a time.
+
+* Postprocessing controller: buffer controller for the color quantization
+ input buffer, when quantization is in use. (Without quantization, this
+ controller just calls the upsampler.) For two-pass quantization, this
+ controller is responsible for buffering the full-image data.
+
+* Upsampling: restores chroma components to full size. (May support more
+ general output rescaling, too. Note that if undersized DCT outputs have
+ been emitted by the DCT module, this module must adjust so that properly
+ sized outputs are created.) Works on one row group at a time. This module
+ also calls the color conversion module, so its top level is effectively a
+ buffer controller for the upsampling->color conversion buffer. However, in
+ all but the highest-quality operating modes, upsampling and color
+ conversion are likely to be merged into a single step.
+
+* Colorspace conversion: convert from JPEG color space to output color space,
+ and change data layout from separate component planes to pixel-interleaved.
+ Works on one pixel row at a time.
+
+* Color quantization: reduce the data to colormapped form, using either an
+ externally specified colormap or an internally generated one. This module
+ is not used for full-color output. Works on one pixel row at a time; may
+ require two passes to generate a color map. Note that the output will
+ always be a single component representing colormap indexes. In the current
+ design, the output values are JSAMPLEs, so an 8-bit compilation cannot
+ quantize to more than 256 colors. This is unlikely to be a problem in
+ practice.
+
+* Color reduction: this module handles color precision reduction, e.g.,
+ generating 15-bit color (5 bits/primary) from JPEG's 24-bit output.
+ Not quite clear yet how this should be handled... should we merge it with
+ colorspace conversion???
+
+Note that some high-speed operating modes might condense the entire
+postprocessing sequence to a single module (upsample, color convert, and
+quantize in one step).
+
+In addition to the above objects, the decompression library includes these
+objects:
+
+* Master control: determines the number of passes required, controls overall
+ and per-pass initialization of the other modules. This is subdivided into
+ input and output control: jdinput.c controls only input-side processing,
+ while jdmaster.c handles overall initialization and output-side control.
+
+* Marker reading: decodes JPEG markers (except for RSTn).
+
+* Data source manager: supplies the input JPEG datastream. The source
+ manager supplied with the library knows how to read from a stdio stream
+ or from a memory buffer; for other behaviors, the surrounding application
+ may provide its own source manager.
+
+* Memory manager: same as for compression library.
+
+* Error handler: same as for compression library.
+
+* Progress monitor: same as for compression library.
+
+As with compression, the data source manager, error handler, and progress
+monitor are candidates for replacement by a surrounding application.
+
+
+*** Decompression input and output separation ***
+
+To support efficient incremental display of progressive JPEG files, the
+decompressor is divided into two sections that can run independently:
+
+1. Data input includes marker parsing, entropy decoding, and input into the
+ coefficient controller's DCT coefficient buffer. Note that this
+ processing is relatively cheap and fast.
+
+2. Data output reads from the DCT coefficient buffer and performs the IDCT
+ and all postprocessing steps.
+
+For a progressive JPEG file, the data input processing is allowed to get
+arbitrarily far ahead of the data output processing. (This occurs only
+if the application calls jpeg_consume_input(); otherwise input and output
+run in lockstep, since the input section is called only when the output
+section needs more data.) In this way the application can avoid making
+extra display passes when data is arriving faster than the display pass
+can run. Furthermore, it is possible to abort an output pass without
+losing anything, since the coefficient buffer is read-only as far as the
+output section is concerned. See libjpeg.txt for more detail.
+
+A full-image coefficient array is only created if the JPEG file has multiple
+scans (or if the application specifies buffered-image mode anyway). When
+reading a single-scan file, the coefficient controller normally creates only
+a one-MCU buffer, so input and output processing must run in lockstep in this
+case. jpeg_consume_input() is effectively a no-op in this situation.
+
+The main impact of dividing the decompressor in this fashion is that we must
+be very careful with shared variables in the cinfo data structure. Each
+variable that can change during the course of decompression must be
+classified as belonging to data input or data output, and each section must
+look only at its own variables. For example, the data output section may not
+depend on any of the variables that describe the current scan in the JPEG
+file, because these may change as the data input section advances into a new
+scan.
+
+The progress monitor is (somewhat arbitrarily) defined to treat input of the
+file as one pass when buffered-image mode is not used, and to ignore data
+input work completely when buffered-image mode is used. Note that the
+library has no reliable way to predict the number of passes when dealing
+with a progressive JPEG file, nor can it predict the number of output passes
+in buffered-image mode. So the work estimate is inherently bogus anyway.
+
+No comparable division is currently made in the compression library, because
+there isn't any real need for it.
+
+
+*** Data formats ***
+
+Arrays of pixel sample values use the following data structure:
+
+ typedef something JSAMPLE; a pixel component value, 0..MAXJSAMPLE
+ typedef JSAMPLE *JSAMPROW; ptr to a row of samples
+ typedef JSAMPROW *JSAMPARRAY; ptr to a list of rows
+ typedef JSAMPARRAY *JSAMPIMAGE; ptr to a list of color-component arrays
+
+The basic element type JSAMPLE will typically be one of unsigned char,
+(signed) char, or short. Short will be used if samples wider than 8 bits are
+to be supported (this is a compile-time option). Otherwise, unsigned char is
+used if possible. If the compiler only supports signed chars, then it is
+necessary to mask off the value when reading. Thus, all reads of JSAMPLE
+values must be coded as "GETJSAMPLE(value)", where the macro will be defined
+as "((value) & 0xFF)" on signed-char machines and "((int) (value))" elsewhere.
+
+With these conventions, JSAMPLE values can be assumed to be >= 0. This helps
+simplify correct rounding during downsampling, etc. The JPEG standard's
+specification that sample values run from -128..127 is accommodated by
+subtracting 128 from the sample value in the DCT step. Similarly, during
+decompression the output of the IDCT step will be immediately shifted back to
+0..255. (NB: different values are required when 12-bit samples are in use.
+The code is written in terms of MAXJSAMPLE and CENTERJSAMPLE, which will be
+defined as 255 and 128 respectively in an 8-bit implementation, and as 4095
+and 2048 in a 12-bit implementation.)
+
+We use a pointer per row, rather than a two-dimensional JSAMPLE array. This
+choice costs only a small amount of memory and has several benefits:
+* Code using the data structure doesn't need to know the allocated width of
+ the rows. This simplifies edge expansion/compression, since we can work
+ in an array that's wider than the logical picture width.
+* Indexing doesn't require multiplication; this is a performance win on many
+ machines.
+* Arrays with more than 64K total elements can be supported even on machines
+ where malloc() cannot allocate chunks larger than 64K.
+* The rows forming a component array may be allocated at different times
+ without extra copying. This trick allows some speedups in smoothing steps
+ that need access to the previous and next rows.
+
+Note that each color component is stored in a separate array; we don't use the
+traditional layout in which the components of a pixel are stored together.
+This simplifies coding of modules that work on each component independently,
+because they don't need to know how many components there are. Furthermore,
+we can read or write each component to a temporary file independently, which
+is helpful when dealing with noninterleaved JPEG files.
+
+In general, a specific sample value is accessed by code such as
+ GETJSAMPLE(image[colorcomponent][row][col])
+where col is measured from the image left edge, but row is measured from the
+first sample row currently in memory. Either of the first two indexings can
+be precomputed by copying the relevant pointer.
+
+
+Since most image-processing applications prefer to work on images in which
+the components of a pixel are stored together, the data passed to or from the
+surrounding application uses the traditional convention: a single pixel is
+represented by N consecutive JSAMPLE values, and an image row is an array of
+(# of color components)*(image width) JSAMPLEs. One or more rows of data can
+be represented by a pointer of type JSAMPARRAY in this scheme. This scheme is
+converted to component-wise storage inside the JPEG library. (Applications
+that want to skip JPEG preprocessing or postprocessing will have to contend
+with component-wise storage.)
+
+
+Arrays of DCT-coefficient values use the following data structure:
+
+ typedef short JCOEF; a 16-bit signed integer
+ typedef JCOEF JBLOCK[DCTSIZE2]; an 8x8 block of coefficients
+ typedef JBLOCK *JBLOCKROW; ptr to one horizontal row of 8x8 blocks
+ typedef JBLOCKROW *JBLOCKARRAY; ptr to a list of such rows
+ typedef JBLOCKARRAY *JBLOCKIMAGE; ptr to a list of color component arrays
+
+The underlying type is at least a 16-bit signed integer; while "short" is big
+enough on all machines of interest, on some machines it is preferable to use
+"int" for speed reasons, despite the storage cost. Coefficients are grouped
+into 8x8 blocks (but we always use #defines DCTSIZE and DCTSIZE2 rather than
+"8" and "64").
+
+The contents of a coefficient block may be in either "natural" or zigzagged
+order, and may be true values or divided by the quantization coefficients,
+depending on where the block is in the processing pipeline. In the current
+library, coefficient blocks are kept in natural order everywhere; the entropy
+codecs zigzag or dezigzag the data as it is written or read. The blocks
+contain quantized coefficients everywhere outside the DCT/IDCT subsystems.
+(This latter decision may need to be revisited to support variable
+quantization a la JPEG Part 3.)
+
+Notice that the allocation unit is now a row of 8x8 coefficient blocks,
+corresponding to N rows of samples. Otherwise the structure is much the same
+as for samples, and for the same reasons.
+
+On machines where malloc() can't handle a request bigger than 64Kb, this data
+structure limits us to rows of less than 512 JBLOCKs, or a picture width of
+4000+ pixels. This seems an acceptable restriction.
+
+
+On 80x86 machines, the bottom-level pointer types (JSAMPROW and JBLOCKROW)
+must be declared as "far" pointers, but the upper levels can be "near"
+(implying that the pointer lists are allocated in the DS segment).
+We use a #define symbol FAR, which expands to the "far" keyword when
+compiling on 80x86 machines and to nothing elsewhere.
+
+
+*** Suspendable processing ***
+
+In some applications it is desirable to use the JPEG library as an
+incremental, memory-to-memory filter. In this situation the data source or
+destination may be a limited-size buffer, and we can't rely on being able to
+empty or refill the buffer at arbitrary times. Instead the application would
+like to have control return from the library at buffer overflow/underrun, and
+then resume compression or decompression at a later time.
+
+This scenario is supported for simple cases. (For anything more complex, we
+recommend that the application "bite the bullet" and develop real multitasking
+capability.) The libjpeg.txt file goes into more detail about the usage and
+limitations of this capability; here we address the implications for library
+structure.
+
+The essence of the problem is that the entropy codec (coder or decoder) must
+be prepared to stop at arbitrary times. In turn, the controllers that call
+the entropy codec must be able to stop before having produced or consumed all
+the data that they normally would handle in one call. That part is reasonably
+straightforward: we make the controller call interfaces include "progress
+counters" which indicate the number of data chunks successfully processed, and
+we require callers to test the counter rather than just assume all of the data
+was processed.
+
+Rather than trying to restart at an arbitrary point, the current Huffman
+codecs are designed to restart at the beginning of the current MCU after a
+suspension due to buffer overflow/underrun. At the start of each call, the
+codec's internal state is loaded from permanent storage (in the JPEG object
+structures) into local variables. On successful completion of the MCU, the
+permanent state is updated. (This copying is not very expensive, and may even
+lead to *improved* performance if the local variables can be registerized.)
+If a suspension occurs, the codec simply returns without updating the state,
+thus effectively reverting to the start of the MCU. Note that this implies
+leaving some data unprocessed in the source/destination buffer (ie, the
+compressed partial MCU). The data source/destination module interfaces are
+specified so as to make this possible. This also implies that the data buffer
+must be large enough to hold a worst-case compressed MCU; a couple thousand
+bytes should be enough.
+
+In a successive-approximation AC refinement scan, the progressive Huffman
+decoder has to be able to undo assignments of newly nonzero coefficients if it
+suspends before the MCU is complete, since decoding requires distinguishing
+previously-zero and previously-nonzero coefficients. This is a bit tedious
+but probably won't have much effect on performance. Other variants of Huffman
+decoding need not worry about this, since they will just store the same values
+again if forced to repeat the MCU.
+
+This approach would probably not work for an arithmetic codec, since its
+modifiable state is quite large and couldn't be copied cheaply. Instead it
+would have to suspend and resume exactly at the point of the buffer end.
+
+The JPEG marker reader is designed to cope with suspension at an arbitrary
+point. It does so by backing up to the start of the marker parameter segment,
+so the data buffer must be big enough to hold the largest marker of interest.
+Again, a couple KB should be adequate. (A special "skip" convention is used
+to bypass COM and APPn markers, so these can be larger than the buffer size
+without causing problems; otherwise a 64K buffer would be needed in the worst
+case.)
+
+The JPEG marker writer currently does *not* cope with suspension.
+We feel that this is not necessary; it is much easier simply to require
+the application to ensure there is enough buffer space before starting. (An
+empty 2K buffer is more than sufficient for the header markers; and ensuring
+there are a dozen or two bytes available before calling jpeg_finish_compress()
+will suffice for the trailer.) This would not work for writing multi-scan
+JPEG files, but we simply do not intend to support that capability with
+suspension.
+
+
+*** Memory manager services ***
+
+The JPEG library's memory manager controls allocation and deallocation of
+memory, and it manages large "virtual" data arrays on machines where the
+operating system does not provide virtual memory. Note that the same
+memory manager serves both compression and decompression operations.
+
+In all cases, allocated objects are tied to a particular compression or
+decompression master record, and they will be released when that master
+record is destroyed.
+
+The memory manager does not provide explicit deallocation of objects.
+Instead, objects are created in "pools" of free storage, and a whole pool
+can be freed at once. This approach helps prevent storage-leak bugs, and
+it speeds up operations whenever malloc/free are slow (as they often are).
+The pools can be regarded as lifetime identifiers for objects. Two
+pools/lifetimes are defined:
+ * JPOOL_PERMANENT lasts until master record is destroyed
+ * JPOOL_IMAGE lasts until done with image (JPEG datastream)
+Permanent lifetime is used for parameters and tables that should be carried
+across from one datastream to another; this includes all application-visible
+parameters. Image lifetime is used for everything else. (A third lifetime,
+JPOOL_PASS = one processing pass, was originally planned. However it was
+dropped as not being worthwhile. The actual usage patterns are such that the
+peak memory usage would be about the same anyway; and having per-pass storage
+substantially complicates the virtual memory allocation rules --- see below.)
+
+The memory manager deals with three kinds of object:
+1. "Small" objects. Typically these require no more than 10K-20K total.
+2. "Large" objects. These may require tens to hundreds of K depending on
+ image size. Semantically they behave the same as small objects, but we
+ distinguish them for two reasons:
+ * On MS-DOS machines, large objects are referenced by FAR pointers,
+ small objects by NEAR pointers.
+ * Pool allocation heuristics may differ for large and small objects.
+ Note that individual "large" objects cannot exceed the size allowed by
+ type size_t, which may be 64K or less on some machines.
+3. "Virtual" objects. These are large 2-D arrays of JSAMPLEs or JBLOCKs
+ (typically large enough for the entire image being processed). The
+ memory manager provides stripwise access to these arrays. On machines
+ without virtual memory, the rest of the array may be swapped out to a
+ temporary file.
+
+(Note: JSAMPARRAY and JBLOCKARRAY data structures are a combination of large
+objects for the data proper and small objects for the row pointers. For
+convenience and speed, the memory manager provides single routines to create
+these structures. Similarly, virtual arrays include a small control block
+and a JSAMPARRAY or JBLOCKARRAY working buffer, all created with one call.)
+
+In the present implementation, virtual arrays are only permitted to have image
+lifespan. (Permanent lifespan would not be reasonable, and pass lifespan is
+not very useful since a virtual array's raison d'etre is to store data for
+multiple passes through the image.) We also expect that only "small" objects
+will be given permanent lifespan, though this restriction is not required by
+the memory manager.
+
+In a non-virtual-memory machine, some performance benefit can be gained by
+making the in-memory buffers for virtual arrays be as large as possible.
+(For small images, the buffers might fit entirely in memory, so blind
+swapping would be very wasteful.) The memory manager will adjust the height
+of the buffers to fit within a prespecified maximum memory usage. In order
+to do this in a reasonably optimal fashion, the manager needs to allocate all
+of the virtual arrays at once. Therefore, there isn't a one-step allocation
+routine for virtual arrays; instead, there is a "request" routine that simply
+allocates the control block, and a "realize" routine (called just once) that
+determines space allocation and creates all of the actual buffers. The
+realize routine must allow for space occupied by non-virtual large objects.
+(We don't bother to factor in the space needed for small objects, on the
+grounds that it isn't worth the trouble.)
+
+To support all this, we establish the following protocol for doing business
+with the memory manager:
+ 1. Modules must request virtual arrays (which may have only image lifespan)
+ during the initial setup phase, i.e., in their jinit_xxx routines.
+ 2. All "large" objects (including JSAMPARRAYs and JBLOCKARRAYs) must also be
+ allocated during initial setup.
+ 3. realize_virt_arrays will be called at the completion of initial setup.
+ The above conventions ensure that sufficient information is available
+ for it to choose a good size for virtual array buffers.
+Small objects of any lifespan may be allocated at any time. We expect that
+the total space used for small objects will be small enough to be negligible
+in the realize_virt_arrays computation.
+
+In a virtual-memory machine, we simply pretend that the available space is
+infinite, thus causing realize_virt_arrays to decide that it can allocate all
+the virtual arrays as full-size in-memory buffers. The overhead of the
+virtual-array access protocol is very small when no swapping occurs.
+
+A virtual array can be specified to be "pre-zeroed"; when this flag is set,
+never-yet-written sections of the array are set to zero before being made
+available to the caller. If this flag is not set, never-written sections
+of the array contain garbage. (This feature exists primarily because the
+equivalent logic would otherwise be needed in jdcoefct.c for progressive
+JPEG mode; we may as well make it available for possible other uses.)
+
+The first write pass on a virtual array is required to occur in top-to-bottom
+order; read passes, as well as any write passes after the first one, may
+access the array in any order. This restriction exists partly to simplify
+the virtual array control logic, and partly because some file systems may not
+support seeking beyond the current end-of-file in a temporary file. The main
+implication of this restriction is that rearrangement of rows (such as
+converting top-to-bottom data order to bottom-to-top) must be handled while
+reading data out of the virtual array, not while putting it in.
+
+
+*** Memory manager internal structure ***
+
+To isolate system dependencies as much as possible, we have broken the
+memory manager into two parts. There is a reasonably system-independent
+"front end" (jmemmgr.c) and a "back end" that contains only the code
+likely to change across systems. All of the memory management methods
+outlined above are implemented by the front end. The back end provides
+the following routines for use by the front end (none of these routines
+are known to the rest of the JPEG code):
+
+jpeg_mem_init, jpeg_mem_term system-dependent initialization/shutdown
+
+jpeg_get_small, jpeg_free_small interface to malloc and free library routines
+ (or their equivalents)
+
+jpeg_get_large, jpeg_free_large interface to FAR malloc/free in MSDOS machines;
+ else usually the same as
+ jpeg_get_small/jpeg_free_small
+
+jpeg_mem_available estimate available memory
+
+jpeg_open_backing_store create a backing-store object
+
+read_backing_store, manipulate a backing-store object
+write_backing_store,
+close_backing_store
+
+On some systems there will be more than one type of backing-store object
+(specifically, in MS-DOS a backing store file might be an area of extended
+memory as well as a disk file). jpeg_open_backing_store is responsible for
+choosing how to implement a given object. The read/write/close routines
+are method pointers in the structure that describes a given object; this
+lets them be different for different object types.
+
+It may be necessary to ensure that backing store objects are explicitly
+released upon abnormal program termination. For example, MS-DOS won't free
+extended memory by itself. To support this, we will expect the main program
+or surrounding application to arrange to call self_destruct (typically via
+jpeg_destroy) upon abnormal termination. This may require a SIGINT signal
+handler or equivalent. We don't want to have the back end module install its
+own signal handler, because that would pre-empt the surrounding application's
+ability to control signal handling.
+
+The IJG distribution includes several memory manager back end implementations.
+Usually the same back end should be suitable for all applications on a given
+system, but it is possible for an application to supply its own back end at
+need.
+
+
+*** Implications of DNL marker ***
+
+Some JPEG files may use a DNL marker to postpone definition of the image
+height (this would be useful for a fax-like scanner's output, for instance).
+In these files the SOF marker claims the image height is 0, and you only
+find out the true image height at the end of the first scan.
+
+We could read these files as follows:
+1. Upon seeing zero image height, replace it by 65535 (the maximum allowed).
+2. When the DNL is found, update the image height in the global image
+ descriptor.
+This implies that control modules must avoid making copies of the image
+height, and must re-test for termination after each MCU row. This would
+be easy enough to do.
+
+In cases where image-size data structures are allocated, this approach will
+result in very inefficient use of virtual memory or much-larger-than-necessary
+temporary files. This seems acceptable for something that probably won't be a
+mainstream usage. People might have to forgo use of memory-hogging options
+(such as two-pass color quantization or noninterleaved JPEG files) if they
+want efficient conversion of such files. (One could improve efficiency by
+demanding a user-supplied upper bound for the height, less than 65536; in most
+cases it could be much less.)
+
+The standard also permits the SOF marker to overestimate the image height,
+with a DNL to give the true, smaller height at the end of the first scan.
+This would solve the space problems if the overestimate wasn't too great.
+However, it implies that you don't even know whether DNL will be used.
+
+This leads to a couple of very serious objections:
+1. Testing for a DNL marker must occur in the inner loop of the decompressor's
+ Huffman decoder; this implies a speed penalty whether the feature is used
+ or not.
+2. There is no way to hide the last-minute change in image height from an
+ application using the decoder. Thus *every* application using the IJG
+ library would suffer a complexity penalty whether it cared about DNL or
+ not.
+We currently do not support DNL because of these problems.
+
+A different approach is to insist that DNL-using files be preprocessed by a
+separate program that reads ahead to the DNL, then goes back and fixes the SOF
+marker. This is a much simpler solution and is probably far more efficient.
+Even if one wants piped input, buffering the first scan of the JPEG file needs
+a lot smaller temp file than is implied by the maximum-height method. For
+this approach we'd simply treat DNL as a no-op in the decompressor (at most,
+check that it matches the SOF image height).
+
+We will not worry about making the compressor capable of outputting DNL.
+Something similar to the first scheme above could be applied if anyone ever
+wants to make that work.
diff --git a/jpg/testimg.bmp b/jpg/testimg.bmp
new file mode 100644
index 0000000..012223e
--- /dev/null
+++ b/jpg/testimg.bmp
Binary files differ
diff --git a/jpg/testimg.jpg b/jpg/testimg.jpg
new file mode 100644
index 0000000..a026e48
--- /dev/null
+++ b/jpg/testimg.jpg
Binary files differ
diff --git a/jpg/testimg.ppm b/jpg/testimg.ppm
new file mode 100644
index 0000000..bd78ef8
--- /dev/null
+++ b/jpg/testimg.ppm
@@ -0,0 +1,4 @@
+P6
+227 149
+255
+0/-0/-10.21/51.51.62/72.83/83/83/:3-:3-:3-:3-:3-:2/91.91.80-80-91.91.:2/80-80-80-80-80-80-80-80-6.+6.+6.+5-*5-*4,)4,)4,)4,)4,)4,)4,)4,)4,)4,)4,).+$/,%/,%0-&1.'2/(30)30)63,63,74-85.85.96/:70:70A;/B<0D>2F@2IA4JB5KC6KD4MD5MD5MD3NB2OC3OC3PD4QE5T>1Y?2b@4nB5}E6G8G9E7F9F9E8F;F>F?G@G@CNCLCLDKDIBF>B<A;A9@9?;@>@?@?<=;@.@.@.?-?-@-?-?-@,A.A-B,A*A)@*A*?/?/?/>,>,<+<+<+?+?+=*=*=*>+?+@,?:>7=4?1B3D3D3D4?/@2E8H;H9mB2T8*D3#:659549547326216005//50-72/72/72/61-61-50,50,50,.0-.0-.0-//-//-0/-2.-3--5,-4+,4*+4(*7(+=.1E69L<?n@B|HJMNNOVZclns|}|pz`aTLuRCjSKcOG_MH\TR`fdo|}{|jhgUXWERO>UPdUPdUPd0/-0/-10.10.40-51.62/72.83/83/83/:3-:3-:3-:3-:3-91.91.80-80-80-80-91.91.80-80-80-80-80-80-80-80-6.+6.+5-*5-*5-*4,)4,)4,)5-*5-*5-*5-*5-*5-*5-*5-*/,%0-&0-&1.'2/(30)41*41*63,63,74-74-85.96/:70:70@:.A;/C=1E?3H@3IA4JB5JC3LC4LC4KB3MA1MA1NB2OC3PD4P>0U?1^A3jC4xD6D4D5B3B3@2@4B7C:E<F=G>AKAICIDHDGBD@D>C;A9@9?<??@@@@<=8@.@.?-?-?-?,?-@-@,@-A-A+A*@+@*A*?/?/>.>.>,=+<+<+>->*>*=*=*>+?,@-@8>5>3?1A3D4D3C4A2B6E8I;G:kA3S9*D4$<66;55:4493382271161.61.72/72/72/61-61-50,50,50,.0-.0-.0-//-//-0/-2.-2.-3--5,-4*+4(*5)+<-0C47I:=h<;vDCJILJST`hk{r{|ylv[\QHsQBkOFaOFaNI_RN_[Yfnot~ojk[]\JVUCXQaXQaXQa/.,/.,0/-10.40-40-51.51.72.72.72.92,92,92,92,92,91.80-7/,7/,7/,7/,80-91.80-80-80-80-80-80-80-80-6.+5-*5-*5-*4,)4,)4,)4,)5-*5-*5-*5-*5-*5-*5-*5-*1.'1.'2/(30)30)41*41*52+63,63,63,74-85.96/96/:70?9-@:.B<0D>2G?4H@3H@3H@3I@1I@1I@1K?1K?/L@0MA1NB2MA1QA2YB2dC2qC3|C2A2@0<+:+;,>0@4C8F=G>?E@FBGCFDFCEAD?D;@:?:@=@@@A=@;>7@-@-@-?,?,?->,?,?-@-@,A+A,@*A*@)?/>.>.>.=+=+=+<+=,=,<+=)>*>*?+@,B7?5>3>2A4C5D5C4D6F9I=I=F;gA4P:,B6&=77=77<66:4493383072/72/62/62/62/52-52-41,41,41,,1-,1-.0-.0-//-//-0/-2.-5//4..5,-4*+4*+9-/>24C79_83l?:|E@IBNKZ^ftnw~zsdmUUNEtO?lMBbPEcQHcMH^NK\[[estx|xzlghXZ[KVTEZT`ZT`ZT`.-+/.,/.,0/-10.40-40-40-51.61-61-61-81+81+81+81+50-50-4/,4/,4/,4/,50-50-61.61.61.61.61.61.61.61.3.+3.+3.+2-*2-*2-*1,)1,)4/,4/,4/,4/,4/,4/,4/,4/,30+30+30+41,41,52-52-52-52-52-63.74/850850961961>8,?9-@:.B<0E=2E=2F>1F>1G=1G>/F=.I=/I=/J>0L@0L@0JD4NE4TD4^D3hE2sB1~A/>-9'9'9)<-@3E8I<J>@CACCEDECDAC@C>A;@:?:>=@A?B=A7>5@,@,@,?->,>,?,>-?-?,@-@,@+@*@)@(>.>.>.=-=-=-<*<*=+=+<*<*=+=,>->-B6?5?2@2B4C6B5B5F:H>K@J@|F:aA4K;.?9+@86@86?75>64:5294183073062/62/62/32.32-21,21,21,-2.-2.-2./1./1.00.00.10.5106005//5,-4+,6,-:01>45W6-b<3qA7}D9H@RQ_iis|zu~my^gRQMDyM?rN@dPEgQFfLC^GBVNLZ^^fjnquzvx}vzvwzokoa`bUWYKTUG]V^]V^]V^.-+.-+.-+/.,0/-10.3/,40-3/,4/+4/+4/+4/+6/)6/)6/)4/,4/,3.+3.+3.+3.+4/,4/,50-50-50-50-50-50-50-50-3.+3.+2-*2-*2-*1,)1,)1,)4/,4/,4/,4/,4/,4/,4/,4/,41,41,41,41,41,52-52-52-52-52-63.63.74/850961961<5+=6,?8.@9/B:/C;0C;0C;.D:.D:.D:.G;-H<.I=/J>0K?1GH6KH7PG6XG5aF3jD1uB/|?,;):';(=,B2G7K<M>DBDCDBEBC@@@>>:>:=9<;>?>B>C:A5?0@-?,?,?,>+>+>-?-?,?-?,?+?*?+?*>)?.?.>->->-=,=,=,=,=,=,=,<,=->.>.B4A4@1@3B5C7A8@7B;G?KCJ@uE;Y>3C9-78*@86@86?75>64=53:5294173062/43/43/32.23.12-12,12,,2.-2.-2.-2./1./1.00.00.3205105104..2,,4+,7./901P5*Y9,e>/n@1tB7|KGYcg~pxxs{js]eTTOGLAyPAjPAhMAeJA`GBYHEXKKWMPU^bc`fbcha`f\Z`TWZOUYKWYL`WZ`WZ`WZ,,,,,,---.-+/.,0/-10.3/,2.+2.+3.*3.*3.*3.*3.*3.*3.+3.+2-*1,)1,)2-*3.+3.+3.+3.+3.+3.+3.+3.+3.+3.+2-*2-*2-*2-*1,)1,)1,)0+(3.+3.+3.+3.+3.+3.+3.+3.+41,41,41,41,41,41,41,41,41,52-52-63.74/850850850;4*<5+=6,>7-@7.A8/A9.A9.C9/C9-C9-F:.G;/H<.J>0K?1FI8GH6MH5TG6[F3dC0lA.t?-{<*;);*=,A1F5J:M=E@FAFAE@C?@>==9<:<9;;=?=B=D8A2>,@,@,?+>->->,>,>.>-?,?,>,?+>*>)?)>->->->-=,=,=,<+=,<+<+<+<+=.>/?0C2A2@2A5B9C:@:@9@9H@NGNEoG=R@4?;039-A75A75@64>63<4194083/74/63.43.34/23.13.02-02-02--3/-3/-3/.3/.3/02/02/11/11/32032040/2.-1-,4..5//H4)M5)X8+a<,f>2nGBzYblu{|u|mubi[[SLLBQAnN?jI=cH>`HB^FCX@BO<?HBGJFLJJQJJQIIQFKQGOUISYMaXSaXSaXS++++++,,,---/.,/.,0/-0/-1-*1-*1-*2-)2-)2-)2-)2-)2-*2-*1,)1,)1,)1,)2-*2-*1,)1,)1,)1,)1,)1,)1,)1,)2-*2-*2-*1,)1,)1,)0+(0+(3.+3.+3.+3.+3.+3.+3.+3.+41,41,41,30+30+30+30+30+41,41,52-63.74/74/850850:3+;4,<5-=6.?6-?6-?6-?6-B8.B8.C9/E9-G;/H<0J>2K?3DG6EF6KE5PD4VC2^C2e@.m>,v=,|;):);*=.B2F7I:D<F>G>F>E>C?@><>9:9:;<@<B;D6A/=)@-@-@-?,?,>.=->->,?.?-?,>,>*?*>)>->->-=,=,=,<-<-<-<-<,<,=-=0=0>1D2C1A3B6C:A<B=B=EAPJXPZOqSIVI@BD97A6A83@72?61=60<4194083/63.43.43.34.13.13.02-.3-.3--3/-3/-3/.3/.3/.3/02/02/00.11/22021/0/-/.,2.-3/.?0)C1'K3'T8,Z<2dGCw]hs|szkqedVSJCN>kK<gG;cG=`FB]DBX?AP;?H:BE?HGDMHGQIGQHJRGNVKRZOaYNaYNaYN++++++,,,,,,---/.,0/-0/-/.,1-*1-*1-*2-)2-)2-)2-)1-,0,+0,+/+*/+*0,+0,+1-,/+*/+*/+*/+*/+*/+*/+*/+*1-,1-,1-,0,+0,+/+*/+*/+*1-,1-,1-,1-,1-,1-,1-,1-,3/,3/,3/,3/,3/,3/,3/,3/,40-40-51.62/62/73084184192,:3-;4,<5->5.>5.>5.>5,B8/B8/C9/E8/G:1I<3J=4K?3EC6FB6IC5NB4TA3\@2b>0h=-q<.w9*}8)7*:,=/B2D5E9F;G<H=H>F@C?@@:9:9=;A;D:E4A-?(A-A-@.@.?.>-?->/>.@.?.?->+?*>)>+>->->-=,=.=-=-=-</<.<.<.<.=0>1?2D2C1B4B6C;C>C>D?PJ[Te\f]s_TYUJFNC>KA@70@72>71=6094.83-63,63.43.34.34.13.13..3-.3-.3--3/-3/-3/.3/.3/.3/.3/02/.0-00.22022000.0/-0/-10.8,,;,)B1*K7.S<4^IHtbnzʂyrwikXVGDI<gG<fD<aC>^C@[ABV>DP>EMGQSKWUQ^WU`XS_UR^TT^SV`UaZHaZHaZH,-/,-/------------.-+.-+/.,/.,1-*0,)0,)0,)/+(0+'/+*/+*/+*/+*/+*/+*/+*0,+/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*0,+0,+1-,1-,2.-1-,1-,1-,1-,1-,1-,1-,1-,0,)1-*2.+3/,3/,3/,3/,3/,3/,3/,3/,3/,40-51.62/73081+92,:3-;4.=4/>5.>5.>5.?4.?5,@6-C6.D7.F90G:1H;2F?5H@5J@6N@5R>3W<1\:0a7+k9.t8-|8+9,;/=0?1?2@3B5D8E:G=F>D?B>?=A?D?E>C8C1B.B,A.@-?,?,=-=->.?.<,=,=+>-=,=+=*>*<+<+<+<,<,<,;-;-=/</</=0?1@4A5B6F3E4F7H>F@C>DAKGXRf]qfth|rfik^S_SCSHQJBLE=D=5<8/95,74-63,33+43.34.23-13.02--2,,1+,1+-2.-2.-2.-2.-2.-2./1./1.02/02/11/11/11/11/11/11/5*2;/3A32C4/J;6]OOymyӐ݂tzjn_bYZPHmHBdA>]>>X?AVBHVLU^U`bbqnn}xv|pulyoguh_k_T`Ta[Eb\Fc]G,-/,-/,-/,-/---------.-+/.,.-+.-+0,)/+(/+(/+(/+(.*).*).*).*)/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*/+*0,+0,+0,+1-,1-,1-,1-,1-,1-,1-,1-,1-,1-,0,)0,)1-*2.+3/,3/,2.+2.+2.+2.+2.+2.+3/,40-51.62/80-91.:2/;30=4/>50>50=4-?4.?4.?4.B5-C6.E80G:2H;3H>5J=5L=6O>6Q=4V;2Z90_7/h8.p7.y6-8-9.;1<1>1@3A5B5E8E:F<E=C=C?D@F@F>F8C2B/C-B0A/@.?-?->->.>.=,=.=-=,=+>-=,>,=+=+<,<,<,;-;-<-</=/=1=1>4@6A7B8H7F7G:I@HBFAJFTMdZre~op~|mlteYgZJZOPLAKI=EC7@>2=:1:7.44*11)23+23-12,/1,/1,.0+.0+.0-/1./1./1./1./1./1./1./1.02/11/11/11/11/11/11/11/5*:9-9<15?53H?:^VTxszΐׄxpykten__yXZsSUjRWjU]j\gmguvrv}vypsfteXfW_YA`ZBb\D,-/,-/,-/,-/,-/---------.-+.-+.-+-,*/+(.*'.*'.*'.*+.*+.*+.*+-)*-)*-)*-)*/+,/+,/+,/+,/+,/+,/+,/+,.*+.*+/+,/+,/+,0,-0,-0,-0,-0,-0,-1-.1-.1-.1-.1-.0,+0,+1-,2.-2.-2.-2.-1-,1-,1-,1-,1-,2.-3/.40/51080-91.:2/;30=31=31=4/=4/?40?4.?4.A4.C60D7/F91G:2H;5J;6K<7N=6P;6S:5V72[60c60k6.t5,}7/9/:0<0<1@3@4@3A3C6C8D:C<F>G@HBH?E:C3B0B.B/A.@->->->->-?0<-=-=,=.>-=,=+=+<*<,<,;+;+<-;,;-<0<0<2>3?4A8C:D;K<H;H>JDIFKGSM_Vrgqz{wrocqbVdWPQCMN@HI;DD8@@4::055+/0(01)01+/0*/0+./*./*//-//-//-//-//-//-//-//-//-//-00.00.00.00.00.00.00.00.6*>6+;8.6;63HE>_^Yyz|Î˄}{||yq~o|n}oy|{j{iXiW\V<^X>`Z@-.0-.0-.0-.0-.0-.0......---.-+-,*-,*,+).*'.*'.*',*++)*+)*+)*+)**()*()*(),*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+-+,-+,-+,-+,.,-.,-.,-.,-/-./-./-./+*0,+1-,1-,1-,1-,0,+0,+0,+0,+0,+0,+1-,2.-3/.40/91/:20;31<42=31=31=31=31>3/>3/>3/@3-A4.C60D71E82G83H94I:5L:6M:6N94Q83T50^72e60o6/x8/90:/;1=1?4?4?2@1A2C5D7D:F<G>IAH>F:C4B0B.A.A.?->,>,=.=.=.<,<.=.=-<.=-=-<,;);+;+;+;,;,;-:,;/<1<1>5@7C:E<F=M>I<H>ICLGPL\Tj^oyzym{lam_UYHQUDKO@EI:@D6;=057,13(01)/0*/.).-).-).-+/.,0/-/.,/.,/.,/.,/.,/.,/.,/.,0/-0/-0/-0/-0/-0/-0/-0/-8*A6):3-1961HJ=bfX{y}~k|iUfSXT7ZV9^Z=+/2+/2-.0-.0-.0-.0-.0...------.-+-,*-,*,+),+),+),*+,*+,*++)*+)**()*()*(),*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*+,*++)*+)*+)*,*+-+,-+,.,-.,-/-./-./-./+*0,+0,+0,+0,+0,+/+*.*)/+*/+*/+*/+*0,+1-,3/.40/91/:20;31<42=32=32<20<20=20=2.=2.?1.@2/A4.B5/C60D63C84D95G96G96H94K84N51V72_60h70r7/}:1<1=2>2?7?5?5?3A3C5D6E8E;F=G>F=D8B5@0@/A-A-?,>+<,<,=-=/<.<-=-<.<-<,<,<,;+:*:*:*:+:+:,:.;0<1=4?6B9D;G@HALAH?HAKGOLWQf]whw|}tqlte\eRV_LMVCEL<?F6<@27;-68-01)00(.-(/+(/+(/+*2,,3--1-,1-,1-,1-,1-,1-,1-,1-,0/-0/-0/-0/-0/-0/-0/-0/-9*?5)73*-66*GL6_iPxn{xgzdQcMTS5VU7XW9,03,03,03,03./1./1./1///..........-+.-+.-+-,*-,*-+,-+,-+,,*++)**()*()*()+)*+)*+)*+)*+)*+)*+)*+)*,*+,*++)*+)*+)**()*()*(),*+,*+,*+-+,.,-.,-/-./-./+*/+*0,+0,+/+*/+*.*)-)(0,+0,+/+*0,+1-,2.-3/.40/:12:12;23<42=32<21<21;1/=20<1/<1->0-?1.@2/A30A30?61@72@93A96A96B94E74G51O61W6/a6/j8/u9.</=0>0>7>5?5@4B4C4C4D4B5C8E:E;C7@4?1?2A,?-=,=,<+<+<.<.;-</<.;-;,<,;-<-:*:*9):):+9+:+9-<1<3?5A8C<F?JBJEJAG@HCNJVR_Yper{~~zuszjcqZ]iSR^JHT@BK:>E5:@29<134,22*1.)/+(/*'0**3*+4+,1++1++1++1++1++1++1++0,+1-,1-,1-,1-,1-,1-,1-,/.,;(;5(23+(56$CL-\hDt`wƤШɯʰ˯ɪ{wrdx]MaHQQ5QQ5RR6,03,03,03,03./1./1./1./1/////////0/-/.,/.,.-+.-+/-..,-.,--+,,*++)*+)**()+)*+)*+)*+)*+)*+)*+)*+)*+)*+)*+)**()*()*())'()'(+)*+)*,*+-+,.,-.,-/-./-./+*/+*/+*/+*/+*.*)-)(,('0,+0,+0,+0,+1-,2.-40/40/:12;23;23<34=32<21<21;10<1/<1/<1/=/,>0->0-?1.@2/;60;62;83<94=:5=:5?82A60F5.O4-W5+b6+n8,x:-<,<.:6<5=5@4A4B3B2@0?1@4B7B9@6?5=2?2@-?->,<+;*;,;-;-;,<.;-<-;.;-;,;,9)9)9)9*9*9+~8,}9,=1=4@7B9E>HCKFMHIAGAJFSO\Xh`{ny~w{nixacr[ZhQP]IIUACL;>D6<?467/44,30+0+(1)'1()3)*5+,2)*2)*2)*2)*2)*0**0**0**1++1++0,+0,+0,+0,+0,+0,+;&57(/4-%46?I$Ue8pTk}ɓҔҰҮѭ̥{{tqk_sWJ^CMM1LL0KK/,03,03,03,03./1./1./1./10000000000/-0/-0/-/.,/.,0.//-./-..,--+,,*++)*+)*+)*+)*+)*+)*+)*+)*+)*+)*+)*+)*+)**()*())'()'((&'*()+)*,*+,*+-+,.,-/-./-./+*/+*/+*/+*.*)-)(,(',('1-,1-,1-,1-,2.-3/.40/510;23;23<34<34=34<21;10;10<1/<1/;0.=/.=/,>0-?1.?1.96/:729839839:4:94;83>71A2+I2*S2)^4(j6)s8*|:*~;+84:5=4@3B3A1@/>-<-=0@4A7@7>4=4=3@-?,=+<*;*;,;,<-;.<.;-;,:-;-;,;,9)9)9(9*9*8*~8,}9,>2?5@7C<G?IDMGOIICHDMJUTa^ngs||yql{dgv__nWXeQP\HIRAAG9=@579.66.41,1,)1)'2()3)*4*+2)*2)*2)*2)*2)*2)*2)*0**1++1++1++0,+0,+0,+0,+0,+:&27(+4."47=HRb1l~Jbr|~{ƅ΅ɢɟȞ×~~vumldZnRG[?IL/GJ-DG*/0*/0*/0*01+01+01+21,21,32-63.63.63.52-50,4/+4/+8.,7/,6.+5-+4,*2-*1++0,-0,-.,/--/-,1,+0*+/)*.()./(0/(//(//(//(//)-.)-.*+/+,-,*-,(.-).-)-.(./)./)--/--/---.../-.0/-2.+3.+2-)4,)5.(7.)8/(;0*;1(<2)<5+=4+>5.>5.>5.=4-<3.<1-=2.<1-<1/;0.=/.>0/>0/?11H-&C1';5)2:++=-(=.-;.45-?-+H()R%(X((Z.+Z8.[A2\G6wC-{B.C1A3?1;0:/8+;->.B1D0D0B.?,<*6383:2<1@1B0|A/|A/C2A1>1=0;/:.9-9-v:/|@5u=0n9)s@/s@/t<+{@0{<-?4D9H?LANBQCRCHKTRd]ue{lwsz|yk{awhea]\zV[sS]mR[cLVTEPH=J;6G53B,/=&,:#+:#-9#/8".#/-#-,$-,&*+))+-(.1'/2'/4'06&14'14'13'32(32(30(3.)-0,-0,)//'=>0WZErx\gspqrrs{{z{~}|zvroi{e[jWLZIKO@CG8>B3/0*01+01+01+12,12,21,32-43.63.74/74/63.61-50,50,7/,7/,6.+6.,5-+2-*1++0,+0,-/-./-0--/-,1+*/)*.()-/(//(//(//(//)-/)-.*+.*+/+*-,*.-).-)/.*./)./)./)..0....../-./.,/.,1-*3.+3.*5.(6/)8/(90);0*<2)=3*>5,>5,>5.>5.>5.=4-<3,=2.=2.<1-;0.;0.;0.=/.>0/?10F/'D0)A3*=4+96-85.83-<1-?-+D*)K)(P*'U.)[4-_:1c?3s@+xA-A0?2?4;3:1;19.<->.A0B1B/A/@/93:3;2=1?0@0@/?/A1>0=0;/;.:-:,:,w9.x<1s9-n9)r?.s>.q9*u:,}=1@5E:H?K@MBPCQCDJQRd]vfp}w~w}oxag\`VZU}XWyXWpSPbJKVECI;@A998340-0,+/+,.)--(,*,+)+***,+),-(,/)-2(03(03(02(02(10)1/*1-*1,+3,+32-12./0,)--%9:,TWBox[iolnpppw{xwy||{xuqnh{eYjWL[HGK<@D5:>/12,12,12,12,23-23-43.43.54/74/85085085083/72.61-80-80-7/,6.,6.,3.+2,,1-,1-./-.0.1..0--/,+0+*/*).1'//(//(//)-/)-/)-.*+.*+0,+0,+/.*/.*/.*0/*/0*/0*/////////0./0/-1-,1-*2-)4/+70*90+:1*<1+=3*>4+?5,?6-?6-@7.@70?6/>5.=4->3/=2.<1-;0.;0.;0.;0.<1/=20C2*E0+H/+L,-N+/M*.J*/E+.A-,@.*@/(C/(M/'Y0*d1-j30i;+o;-w;0=4<4;594:4;2=2>2@1A2A3B5C6=2=1>1>0>/=.=.=.<.;.:-9,;,;+~=+z=*}=3z<1v:/u;-x@1x@1v<.v;-?3B6F=H?JAKANCPDDHQQc^ugnt~}{ak[eXaV`W`W]QtVMiPC[E=RA6F9/<2*5-&1+%.)$-(1&*1&*1&*1&*1&*1(-2).1+//*0-+0,+0+,0),1(-1&.1&.14.24.0.*'**"66*PUAmv[~ik~hjnn~mqx|zwvtuwyy}}ywspmh{eYkUL[HEG:=?28:-23-23-34.34.34.45/54/54/650961961:72:72:51940940:2/91.91.80-7/-4/,4/,3/.3/.3/01/01/00.1..0--/,,.2).2).2).0*.0*,0*,0*,/+*1-,1-*0/+0/+10+10+10+10+11111100010.10.2.+2.+3.*91.92,;2+<3,>4+@6-@6-A7.A8/A8/B90A8/A81@70>5.?4.=2.=2.<1-;0.;0.<1/=20=20?5,E2.O-.W(0]#/\"0W#/L'.C/.:3-55);5)E1(U.'c+*l*+e;/j;1s=3}<6;8;9;7:6>9?9B9C9B9B9A9@7B/B/@.@.>-<,:+9+8*8*9*9)<)z=(w?(t@(=3{7,x8,z</v;-w=/{A5{?4B7D:G=I@I@LBNFPHOLYSf[sbg}mzv{|~zmmiiegdefgce]~_Zw[PhPI_J@Q?8D60:/-5**/(),%7$(7$(5%(4%(1&*1(+/+,.,-*+-(,-'--%-/%-/$./$./$./1(+1+-0+(.+$88,PUAiqYve{hyf{in}mykzmrsq}o}p}s~t~v}w|x}zzwuqnjg{bWkRK]GGE9?=1:8,45/45/45/560560560761761872:72;83<94<94=84<73<73<41<41;30;3083072/61.61.5106216213122011/00.//-.4+.4+.4+.4+.2,.2,,2,,2,,3/,3/,3/,10,21,21,32-32-22222032032032.51.61-61-;4.<5-=4-@6-A7.B8/E8/E8/C:1C:1E;2D:1C90B71@5/@5/>3/>3/=2.=2.=20=20>31>31>7/C41O/2Y*2_%3`#2Y%1N+1B3077-39+68*?5)N1)]-)e+)c;3h<3r=7z=:<<<=;;;:;9>8A:C;C<B<@9?8E/D/C.@-=,<,9+9+6)7)9);)~=)w?(sA(qB(6/|/'8/?4w5)s5*}A6}C7E9G<I>J?K@LDOGSJycL~hSoYu]}biu|~|~|}{yn}lylwkwmtjogl~dbqZ[hTSZHIK=B@4=6,8/&5+":&(8%'6&'2&&0(&-)(++)).*'+*&,*&,*'+*'+,)*,**,**,-#$2*(50,85,BC5UZFfpWn}^tcqbtexiwkshsiwmzmxlwkvlyq{u{w|wxuzwwtqomhd{_WkPJ^CFB9>:195,560560671671782782872872983<94=:5>;6>;6?:6>95>95?74?74>63=52;62:5294194184184195484373243132021/6-.6-.6-.6-.6-.4..4/,4/,40-40-40-52-32-32-43.43.431431542540841850940:5/=60?6/@7.B8/C9/F90G:1H;2F<3F<3F<3F<3E;2C90B71A60@5/@51>50=4/=4/>42?53?53=82A64I35Q16V.6U-5R/5J22A62::08<.9;-?9)H6*P4)U3)]2+c4.k62t76}77897978}75{:6|=8{?7@9@:@;?;|E0}D0C0A/=.;-:-9,8+9+:+<+{>+x?+uA+tB+2,2,LEXQA8|90F;J>yH:zJ<{M@|NA~NBPEUJYN_uNgwRtzX{^|bis|z||x~tyqvponpp}pxmskk~bgu\_iQWZGPM<H@3B6*>0%:,+7,*5+)1,(-,'+.').((/().(+-*,,*/+*3)*6',7&,9&,2)$<3,E>4JF:QR@]bLgqVizXm]j\j]pbqeodoerhukrhqitlxrzvyvyvvtwturokjfc|^UlOJ^BHA9@91;4,671782782782893893983:94:94=:5>;6?<7?<7@;7@;7@;7B:7B:7A96@85=84=84<73<73<74<74<74;74:6395284173080.80.80.80.80.80.61.61.61-52-52-52-63.63.54/54/540540651952:72=84=82@93?80A8/C90D:0E;1H;2I=1I=1H>4H>4H>4G=4F<3D:1B8/A60B71@70@72?61?61@72@72A83=84@85B86D97E:8G96G96E:4C90B90B:/B:-D;,F:*H;*H;*].&b0)n3/x7398;;<<>;A>A<?6}=4~;3;5=8>:~C3B3A2?2=1<0;/;/;.|=.{=.|>/|>/|>/}>/}>/.*;8kf~yZTC<LAN@tJ:qM=pQ?qR@tSB{VD[J_OUOeUz~[y_raofrkxovz~~}yyvrrrrt|svpspligeby\\lQU_GMP;ED0A<)>3-<3,92*41(01).1(+1'+0)/0*2/*6,*:*+@'+D%+G$+H#+A7+LC4WP@[XE`bLgmQiwVj{Wl[gWfWj^nananbrfrkohniqnwsyvxuutssutspnlicb{[TmMH`@MD=E<5@707827828938938939:4:94:94;:5>;6?<7@=8@=8A<8A<8A<8A<8A<8A<8@;7?:6>95>95=84>95>95>95>95=84<73:51940:0.:0.:0.91.91.91.91.72.61-61-63.63.63.74/74/74/540651961;83<94?:4@;5B;3A8/B90C9/E;1H<0I=1J>2K=2K>5K>5J=4J=4F<3E;2C90B8/B92B92A81@72@72@93A:4A:4?74>95=<7>?7?@8@@6D@5J=4J70N5.Q6-Q6+O8*M:+I<)H=)l3(r6,~;3@:DAHDJGLHQJMDD;;28-7-91;4?7?7=6<5=5=4|>3y?3vA3uA3uA3y?3}=3:38373%$<;{zhcG@K@wI:mN<gR=dU>fW@jX@r\E}aLeQj{O{{Uw\l`^_R\M[O^muxx΅~}xurruuus{sxrqlphiadtW]gLVX@LJ3GB.L40H3.D3,?2*:1(70&40'40'81):/+?-+C++H(+M%-O$-Q#-PE1[P:d^FgfJilOnuTm{Wl~VkZgVgVm]papbrdvhrlokmipmwtyxwwtustutsqokicb{[TmMGa>SJCKB;F=69:49:49:49:49:4:;5=<7=<7=<7?<7@=8@=8A>9C>:D?;D?;E@<E@<E@<D?;D?9C>8C>8D=7B;5B;5B;5B;5B;5B;5A:4A:4A83A83A83@72@72>71>71>71<71<71;60:5/85085074/74/761961961:72<71=82A:2B;1C:1E;1F<2J>2K?3L@2N@3N@3M@7M@7L?6K>5I<3F<2E;2E;2B90A81A81?80?80?82@93@93<5/LE?IB:E<5OB:K:2J3+\>6Z5-`5.`4+^/'\0%b8,g@1gB2I;G;I?LAF>>7=6D;NDQEVHYKPB@5:0=49;9:675496@:{@8o?3oC6lB4m?2u:27435-3(1EEbaEDWUyvVOF<WGlS=f\CedFgfHgbEm_DyeLnVdKp]phW]8K(D&H+L<WG\Xenr|zف}ֆ؉wwxxxyyxmm~itagY{YMtLBpE<r;>d02b22\31L)'D'#I2,J70F5.E2,E0+H0.I-,I)*O+-V24VK/`W:f_BgdEkoLu}Xu]oWjWlXn]q`sbubudveqksmsoqosrwxzzyzxyqrmjjghdazZTnKIc@TKBSJAPG>9:49:49:49:4:;5;<6>=8?>9>=8@=8A>9A>9B?:D?;D?;D?;FA;E@:E@:E@:D?9D?9E>8E>8E>8E>6E>6D=5C<4D;4D;4C:3B92B92B92B92A81A81@91@93>71<71;60;60:5/85.74-74-96196/96/;60<8/>:1A:0C:1C;0E;1G=1J>0L@2M?2NA1NA1N@5N@5M?6J=4I<3H;2E;1E;2C:1B90A81@91@91@91?;2?;2C:3G81I0,V..j68u99{;;ECD?H@I?G>JANHPLMKE3C2B4B6>36-7+<0C5@.@.E3F6E5H9N@KRGN@F9=8:?<A:r@5k?2uK=NC@:,-(08FK\JIMM>=>?_\XQ@5UDvbJa]@Z_?ekIonOshJ{fKkP]V][SZ<N'EDH!K(N.N9RF[M^O]O]S`akclgnkpnrstvuww{zwzuxotircn^k\i`nRaJWGQDKFIk79FS2-L0,F2+I6/J91I;2M>7SD=]P.dY9ga?ifCnrMz[zbt^r]o]o^q^ubwcwcwcrmwrzvyw~}z|qqljhc`yYTnKJdAWQEVPDUOC8938938939:4;<6<=7?>9@?:@?:B?:C@;C@;C@;D?;D?;D?;FA;FA;FA;E@:E@:G@:G@8F?7IB:HA9H?8G>5F=4E<3E<3D;2D:1D:1D:1C:1D;2D;4D;4C<4?80?80<71;60:5/:5/94.94.96/96/96/;7.<8/@9/A:0C;0E;1F<0I=/K?1M@0M@0NA1M@0N@5M?4L>3K=2I<3H;2E;1D:0C:1C:1A:0A:2?;2@<3@<3A=4SE<P40g35AGJWS`[f^cB>I?MAOBRJSRNSENE2B0@0?1:-7*8+=/E4>+7$:%>+@/B2C5/89BDLKRNRLLB>}:1u;/q9,s5*2-47<GEWLaFC41:921MKb]J?\JzdLebCbfEpqOysS~iLiNrZW`NZ@Q3I-H-N*M&H-M,K.J2L1K.K.L1O=Z?[B]FaJcMfQhSkPhOiLgKiKjLoOsQuh_|ZtUkYldrR[r-0]''X1,T<2N@5?<-7:)<C1GP=[N,aW4e_=heBstRd~hwdxgsercrctcwfzgze~xzynmg~b^wYTmMKfCXUFXUFYVG7827828939:4;<6=>8@?:A@;BA<DA<DA<DA<DA<E@<E@<E@<GB<GB<GB<FA;FA;HA9HA9HA9LC:KB9JA8I@7H>4G=3F<2E;1D:0D:0E;1E;1D;2E<3E<3E<3@91?80?80<71;60:5/:5/:5/96/96-;7.;7.=9.@9/C;0D<1F<0F=.J>0L?/M@0M@0O?/O?/O>4O>4N=3K=2J<1G:1G:1D:0D;2D;2B;1B;1@<3A=4A>5A>5Q9/X+&:?P`OeOfPcGO20:/?.C3F=FG>H2BH6F5B3@3?1>1B4D6G5B/<);&<(:(5&3$7<8>7>6=<BJMTSZT@76+.%62HKNX@Q0E:4-(7464D@\UWKXFtX@rgIysS|qQhJdKoY~kGVAP9J8I=N@Q:N5H@S:M4K3K0J-I-L1S1T1T3W3W6Z9\;^<a@f=f<e<g<i?mBpEsLuNuRvPqRn`xdvWb|15h0/U3*L:,BA/:C.5G/5L2VH+_T6i`CokN||`rv}qzq|s|szozm}msxsqh|c]tWSlLLgDVWEWXFYZH671671782893:;5<=7?>9@?:BA<DA<DA<DA<DA<FA=FA=FA=FC<GB<GB<HC=HC=JC;JC;JC9LC:KB9KA7J@6H>4G=1H<0G;/E;/E;/E;/E;1E;1D<1D;2D;2@9/@91@91?82<71;60;60:5/;7.;7.;7.<8-?8.A;/C;0D</G=1I=/K?/M@0M@/P@0O?/O?/O>4N=3N=3J<1I;0G;/F90D:0D<1D;2B;1@<1A=2A>5B?6C@7_4-t42KSYiH_:Q2C#+/)9(;&=)@3A=:?0;D4B3?2>2?5C7G;J<>/?-=+:)9':*;-</EBCB=?6:7<AFLNRPD>LDTLTNKJ>C3>.<5+7.0+9482@9[PUDxO9~dIlPbF]FeTqdsj<I9D8A<DCHHKJLIMLSDM:I5H1G-F0J5P7V7X7X8Z:[<_>b?eAiBkBmAm@o@o@qAqBn=hEmJpGhMiZrbsYc@D]($M-"PC2PR=CO76H.WH1eYCujT{gy~þþyvh{e\sWTmONiHTYBUZCW\E560560671782893:;5=<7>=8@?:B?:C@;DA<EB=FA=GB>GB>GD=GD=HC=ID>IE<KD<KD<MD;LC:KC8LB8KA5L@4K?3J>0I=/G>/G>/F<0F<0E;/E;1D<1C:1B90A:2@91@91?82<71;60;60;7.;7.;7,<8-?8.A;/D</F<0H?0J>0K?/M@0NA0P@0O?/O@-P>2N>1M<2L;1I;0H:/F90C9/C;0B<0B;1@<1A=2A?3B@4C@7t50FEY_Ub@Q5F0;*+1%9#;!: =&=.902-:,:-9-6,91A9E;E:?2@0<,6'6)=0D9G=9*@4D=A@<?7<05-.63H@TJNE=70..0273$</,"7/2,6/g\m^XC\CW?R=\LjafbUTAI>D<@?>C>JBRMZWPREL;G6F2D/B1G6L:T:T:T:W=\?aBeDi<e>h?jAm@n?o>m=mFn:a>dInJlMmSoXnp_jILt:6\6-O9+OD2SN:`PArdW|p̿m~k^u[VoQSlNU_DV`EWaF560560560560671893:94;:5=<7@=8A>9C@;DA<GB>HC?HC?GD=HE>ID>ID>JF=LE=MF<NE<ME:MC9MC7OC7NB6MA3MA3N@3JA2JA2I@1H>2G=1F<0D<1D<1C:1B;1A:2@91?82?82<71<71<8/<8-<8->7-@:.B:/D</F<0H?0K?/M@0NA0NA0P@0O@-O@-O=1O=1M=0L;1I;0G9.E9-C9/B:/A;/A:0?;0?=1@>2B@4@@4+)JKSV=B/6.3./0)1 9!=!== =#;#6"6-8/5.3,71@:B<@6B7A5</8+:0B:C=@;@(?+5))$ #")'/-2((.)2*4*4*1*0+.+6#5&2$6,6.>7`UqeSWCN:XGe[a_PTBIDK@D@?B<B8B9IAPLKP@K9H7H5H3E7G=K9R9R7R7U7X9]<a=g@k@nBqDtCuCuCvBuFgAaEeJlJkUt^z\vi~o~nw]aCAh6/hB7vTHwf_}vŽ˻tqexb[tWXqS\iK\iK[hJ560560560560560671872983<;6?<7@=8B?:DA<GB>HC?ID@HE>HE>ID>JE?JF=MF>MF<OF=NF;OE;ND8PD8PD6PD6QC6QC6OC5MD5KB3JA2H>2G=1E=2D<1C:1C:1A:2A:2@93?82<71<71<8-<8-<8-?8.@:.B:/D</F<0I@1K?/M@0NA0P@0PA.O@-O@-O=1O=1M=0L;1H:/G9.E9-C9/A9.@:.@9/?;0?=1@>2??3@@467]_Z[78,,/,,#0#8$B(G*G'F$F$C!? 81;29250:6B>D=>7<3<2</<1F<KDE>72:<$:*.($&''%%(,)2*5*3(2'/&-%=(2>05)7/?7C9qdm]YFVEi\lfSS@H?L<B:=<:@9>46,4.44BH8G2F3H5I7G<JBN>Y=X:W6W5Y5\6_7e;k:m;o<r<r=t>t>vEbNkTqIf?\Rqff^wbvkys{rvfeZVTN~ĻþĪyvi|f`w[\uWbqRapQ`oP201312423653875984984983;:5<<4==5??5AA7CC9EE9EE9HH@HH>HH<HI9KJ6LK6MM5MM5LK7IG8EE;HGELIPKIWFCVA=TQF4NC1JA0KB1MD5LB6F>3B90E<5C:5@85?74@86?67>56:44F85E76B87@78>:;<:=<<>==????A@<DA:HB6JA2M@-P?+O?(CB0F?/K:2O62Q35Q28N5;F:<??=-=3)A1.J4/G-,?#5B&GP3`SJ<7)7':'9%;&@);$='?+?+:)6&4%2$8'8':(>,B0D2D0B/?,>*<*=-C4F7>03&6+8,:-=/=.</905//,--.,0,4,9)=)>(9%44 9%8&6&@4QEIAMIUUVXJP9A4?9DCHCFAA?;=3=/?/@0Q@QCLCC=??@E>G8CGMENEQESAR=S>XCbGiBh<f;g=kDsIyK}MyNwRtTqQkQl[xdY?lMxX{Ypyca}sŹʻ|zt|qpzo~synv}k0./1/0320542653762873872:94;;3==5??5AA7CC9DD8EE9HH@HH>HH<JH9KJ6LK6MM5NM8KJ6KI<KJEQORWU`ZWhVTjQNiSI@ND;H?6F=6G>7H?8F=6C:5C<6A:4?74?74@85>95=84;63>3/=4/>42<74=98<;9=<:>=;@?;C@9G@6J@4L@0O@-P?+P>(=B,?A,E=0H92K63J46F35A57>=;8=69?5?A4C=-J9)^B4sRCK=;-2#6&:'8$9%?(;%=(@,@-=,9*6(5(;+:*9);+?.B/B/@.?.:(<+E6H9?18+7+5+7,:.;/=/;/8/4/0----+/+4)8(;'=&:'7"8%=*;*5&;/G<G?JFPOPQGK;@:A?GDGDCB?>8;1;-<->.F5M?NEGC?@>B>F>HDJCLDPFTBS=S>XBaFhCi?i@lBpGvJzL|IxHtKpRs]z`{XwMqCkAlCjJg^ppugNIv̲Ų}/.,0/-10.21/43/540762761:94::2<<4>>4@@6BB8CC9DD8IF=IG;JH;KJ8MJ7NL7NL7OL9KI:NKBTSQ_^dihxmmlkihcYd[QZQGPJ@IH>FG>CC=A@:<A;;?:7<73<73=82>:1>:1=90:3-94.;60=82=:3>;4?<5?<3C?4F@4I?3L@2O?0P?-Q>-P>*3@&7?'<=+A;-B8/A62>42;31=85B:7H94O2.[+)o-.:=EJ9+2$1"9'<)7$8$<&;&=)A-A/>.<-:-:.>0<.9+:+<+>->-=,?-9(>/L=H:6*2&;05*6+8,:.;/9.7/2,/-.+.+0)2'6&8$:#7$5#8'>-=.7)8.A7<5?8EAKIIJCC?A@CDCC?B;=4:.9*;*<+9)E8NEIE?@<AAIFPAG@ICOGTEU@U>X@_DfCiDmFpIwK{L|K{CvGwJtNtZ|aUvCdHkRv=\H`z}~\F;rճξ/.,/.,0/-10,21-32.54/650872991;;3==3??5AA7BB8CC9IE<JF;KG;OI9PK8QL8QL8OL;LJ=SPK^]bmlzzz~|urke^}YSoRMdMEZG@PB<HD?F@;?<87;62;7.<8-=9-<8,880991;;1><0?=1@<0?<-A;+F?/H?.K?/M@/O?/P?/Q>/P=.<@)=?*?>,?<-?;0=:3;:5:94<94D95N43[*-o&--83C7H7)7&9(?-?,9&9#;&:&<)>,@/>/<0=/=0@5=2:,8*9+:,:,:*;,;-B4E9?31'2(:13+4*7,8-8.7,3,1,0,.+.)0(1&4$6 8/04$;,</9.<2C;6/70;5E@MILGC?;8A9@8>4</:+8*:+<-4&?3HBHEAB@DELLU?E?GBKHUHWBW?W@\BbCfFmIsMyO|L{Jy@tL~Q}JrLoUwUuLjEcKf>Vet͑]=2aP@wlѥº10,10,0/+0/+10,21,43.54/77/880991;;1==3??5AA7BB8KD:LF:OG:QJ:RK9SL9RM:QK=OKBVTUfdowxÎƏ{wrlid_[~UPnNJaJGXEBM?=B;7696196-86*86)581692891;;/><-?<+C<)D<'I>*J?+L?,M@/M@0M?2M?4L>3M?4K?3F<2B90=909:25<44>57<5>:1H3.\0/{48;D9E2A<+<+@.A/@-<'<'>*8%:'<+=.;/;.<0<1A6>3:/7,7,8+8+8+7+A5C88.1&3)7-6-2+3)5+6,5,4-2*/*/,.*/)0'1#4!67//2"5)9-:0?6E=F>@9<5@9KDNGF<;1=1<0</;,9*:+=-?29-=4@:C?BDDHIOOV>C>EBJJTJYFXCYB]@_BdFjJsOxOzLyIxGwRQ}IqImStVtNiD^F]YkKFd2)jc͖ɿ˾Ⱦȿ84163.52-30+30+41,52-63,85.96/:70<90>;2@=4B?6B?6KC8ME:PF:SJ9TK:UL;SL<RL@QLHZW^kj|~Θڙޙޓ֋̆~xvmlfe]ZwVTiMKXDAH><=;:6;8396/267465672880<:-A<)D>(G?(I?&J?)IA,JA0IA4IA6HA9G@:R9<N8;I68A57:65384.93+;12?517+=3'X:0{D=GC>?46<*=+?-?->,>*?+@-8%9(:+:+9,9.:0;2>7;4818.8.9/8.6,7-C9?50&,#7/<44,1*1*2)3*3+2+/*.(.*-)/)2&3$5"7 75#3#2$2&5)7,;3?8YRRJHAD;F<J?G;?3;(;(;*:):(:+>0A3A6<5<6A?EEGIJMMQAD?ECIJTN[JZF\F]A]BaEiJpNwOzMxKxR{R{OvOtVw]{SoD^UjQddt`cKLkeώ<94;8385052-41*41*52+63,74-85.96/;8/=:1?<3A>5B?6KA7MC7RF8UI9WK;WK;UL=SJASJK[Xcnlǚޞ졩홛敘ߔ֐̈zzrqfd|XWiPN\IGRFCJDBG=?K==G;:?;:8<92A;-D=*F@*F@(GA)GB.ED2CC7BC=AC@>BAG9HH<JG?LGDODGN@JL;II:ID?KA<@2F=.bH9QBK<@2;-=+>,>,?+@,@-?-=*8'8)9*9,8-8.91;3;4:3818192:2706/<3>5912*3*;2<35,0(1)1*1+0+/)-(,(-).)0)2(5%6#7!8 8%8%5%4%4(6+7.7/NGXPZQRIH>E9B5?1<&<&<(;'9(;*>0@4D;?9@:FCIHHGIHJMCFADDIKSQZN]L]J`D^DaFfIlNuOxOxNyYzWvVuYx]{ZuQkI`WkUgN\^kKZSaSaQ_jfɂ~窧@=6=:3:7074-52+52+52+63,74-74-96/;8/=:1?<3@=4A>5M@7OC7RF8WJ:XK:YL<WK=TICSJM^Xfpm͜磬Ꝡ㙛ؕΒĉyyji`]|XUpSOhPLcMJeKG^FBS@=H?;<?:4B<0A>-C@-CB.BC3AE7>E=<EB;EF9DF:D]@JcHTjR]oXdt\fp]dj`ac`[W]LDgI>UEYFL7A+A+@,A-A-A-A.A/=+7&7(8)8+8-6-7/8/;2736161729494816/A:8/3*7/=5=58/6-0'0'0(/).)-)+(+(-)/)1)4)5'8&8$8#8$9%7$6&7)8,7+4*3+NGd\`YOFB9<2:/?&>&=&;%9&9*;/>3C9A9E?KHLIGDFEJIFGCDDHMSRZR\N^OaG^GbGdIiNrRvRyRy[u\x`}_|UpMgPgYn[mbsL]SdM_RgI_E]d`tqښA>5@=4?<3=:1;8/96-74+63*52)52)63*74-:70=:3@=6B?8J@6OC7RF8VI9WJ9XK;ZL?[NHTIMXR`gd|}̗瞩꟡ܙҍurhe]ZXR~YP{YQxVOpOG_E?M?:@?;8@@6>>2@B5@F:>E=:C>9CB<GI?MP:YvKh[udunx|zq|`n]eX[XUWMM?A,:";#<(>*?,@.@.?-=,;,6'5(6*7-7-8/91818495:685616183:3C<=670@7[Rlc]T@71'2)1*/)*&'%(&*(-)0*2)1%0#1"5$:(=&=&=)<*;,9+8,6-@871GAc^XQB<@93.<#<$<&<&:(:)<.=2>4C;PJXTOJ@;@:KEFEFEJKPTQWNVKVL\RdOfKeJfMnRsRvPt[wZuZu[w]xZsWnVictVg\mYlDXBXMeIbnhhcˎ赲C?4B>3A=2?;0=90;7.:6-95,73*73*73*83-:5/=82@;5B=7I?5LB6QE7UH8VI8YI9YK>ZMEUKLXP_ebyzɔ䚧䘘،ɀ~uqieb^cVbU]TWOtNHdFCTBAIAAA;=8@C<DG@BD??A@BCGMNSWW_Vlgyw}q_wXkTaOUFD=49(:$<#8%7%8&:(8'9(7(5&3%4(7-;0<3=5;5;5>9<7<7=9A=C=B<A;@:A9@78/1'6+I>\Q?46,+#)#,)./,-((0.4/7/6,4)2&3%5&='<'<(;(:(7)6(4(8/5-<6PJSOLHA?/,=%>&='<'9(8(9,:/>4B:OFWPQKD=B<KDIFIFMLSRTVPVNVOZVfUhSiRkRmSqStRsNoTv\|^{[vUoQgReUfQbZhZjM^RcWiI\ha\W{٩EA5EA6C?4A=2?;0=9.<8-;7.84+84+73*83-:5/=82?:4A<6G>5JB7ND8RF6TG6WG7YI:YKBWKKXP[b^wsuޗ뙗Ղxtqml`i]dY^VVQyNKhEDV@@J76;?=>HBBKABN?BYFJmX_}fnt}}wpcRpE^I\EP9<3,7(;%; <*<*;);*<,<-<-<.6*8.<1>5@8>7<3:273403/93A;E?A<<5<44,4*7-2', 6*H<I>@64--)+*+,+,*,))/+3,5.4+2(2'2':&;'<(;);*:,8+8,4+;4:5<7ONXYEE02=(<(<(:'9)8*7*7,>2A6JAUKRIH>E:H@IDHCLGSPSSPQMQNWXdZh[pZrUoQlPnRpFmOvZ}[{VqSkVk[mYhYh`m`k\fenfmT[cY}NDlfØ߹IE9HD8FB6D@4B>2@<1?;0>:/:6-95,95,94.:5/<71>93@;5E>6HA7LD7QE5RE4UF3WG7WI<XMIXNW_Zppp֔횪엖䌋ق{zxlpfh__ZYWQQwGGc@?Q<6DF9BS>C_@EmDJOU]fjreklf]TyFg8U0H>PBM:<7/@.B*<!5$5$5$6&7(8);-</@6@5@6?6<5:16.4,/(-'.(3-:4;4814-5,+")7,B4?04%.F7I<H?<9,,"%&)/2-./-2.3,2*0(/'/)8*9+;-=->/?0@3@36*KBJE50FFZ\HK?B=-;+:*:*:*9,9+8,<0>2F9OBPDH<C7D7F?F?JCPKROMLKMKPX`[haqauWoOgMgPkJuOySwRqSm[pcuixguaobmelgljjjhc_dVeH:_TͫLI:KH9JG8HD8FB6D@4B>3A=2=9.<8/;7.;60;60<71>93?:4B?8EA8JD8NE4PE1TE0VG4XH9ZMEVMR[Whkl~В噧铕⊌لӅ{umjdd_aX[QQsNHbUFY_CRlBLEOLVU][d]fJuNxPuLnFc?Y5J+?5EAMFK><>6H8J6B)>-=-<->/?2B4D7E:E9B7>5:26-5,3+2*1*4-6090807/6.5,/&5+6)2#1"9)>-<+=-D7KAD?56)-)-.26755301,/,/,0-/-80:1:1<0<0=0?0>17+WL`X;6;:OQEHOT=2:/8,8,:-;.;-:.:-<.B3H9I:D6@2>0E<E<I@PIRMNKKKLOZ`^hfrhx]qOgMeQjPzQxQpSm\qhxjwepfr_k_kkrsulhf\l^ujXVI8kXJ{tQK=PJ<OI;MG9KE9IC7GA5G@6B;1A:2@91?82?82?82A:4B:7@?:EB;IE9MF6PE1RF0UF1WG7YLCUKLZTbii|ɓޗ먫횞蕙⑕ޒډ|rxnulphhj_x`xWjO_OZR\R[OVHP:P=QAPCLCI?B9:45IJHH@A7693B8E8@1E6E6F7E8G8G:H<G;>3;18/4*3*4+4,5-9/<2=4<3905-5,6-.$;.<.1".8$=);&:'9+:1=9@@;?27+1,.+,+)+(/.4488:;5564736/7-5*5(5&5'PEmcHA42CC>BUYB;=6706-9/<1=1=.9)<+@.B0B0?.=,<+C8D9H=PGSLOIOJOP_caiitm|duUjRgWoSxUtWp_poyy~msXaam`maos{숊ɂ|wjyhhpYMO:^WGqgݿSM=RL<QK=OI;MG9KE9JD8IB8E>4D=5B;3A:4@93A:4A96B:7@A;CC;IE:NG7QF2RF.UF/WH5XJ=RHFXR\jh}ƒږ奦띤蛢晞⒚ۊ҅ʂ‚ymczWiP]KWGP?H9A;6<5B6H7J5G1D.@/UGG?;76488:;9866=.<.;.;,8+6*3)1&5*3*3(2)3*5,6.7/>3<2;18/7.6,4*3)3&3%4%6&=)>*9$2;(5%3'60;<=@7=27-1..--0.449:;=;>.4/3011/1*2(1%3$2#>/j_TL95@@:=RUJEB=935.8.;0<0=-<*?-@.?-;(;(<)=*>2>2D8LBPFNFMGNLbcbfhqo{hxYmUj[pXs\tbqkt퉇yy_dhrl|cskw餟z\pWFR<UVFtg^ܾUO?TN>RL<PJ<NH:LF:KE9JC9G@6F?7D=5B;5A:4A:4B:7C;8@A<DD<IG;MG7OG2RF.VG0WH3VH;RGCWRYjh~~Œؖ㡞뢪룫좪롩蘡䖡ᔟݓِѐǒmc{WjM\BN;E6>4:B*D)H)N+O(L%H%D&WBF8;5>>BH>F5>08F8E7D7A3=08,3)0%0&1(2(3*5,5,4,4,C8=27-7-:/9/5+1'7*0"0!9&9%5 9#E.:&:)7+3.//055;;BIMGJDD@@>>9:28.4'/(/*.-.0+2*5)7(0!/eY]TA<ED;=NRPMFC:65/8.:/</<+>,A/B0=)8%9&;)>,8+8+>1G<K@IAICJG`a^bdllxixZkTiZo^tcugqqr݅锍ꋇruq{x`sXg֫TnSAS;PTCkaWݿXO@XO@WN?VM>TK<SJ;RI:QH9MD5LC4KB3I@1H?0H?0H?0H?0FC<GE9JG8NI6RJ5UJ4UJ4VK9XNDULMXTbii{~Ƒڗ妢ꧨ뫨ﲧ珣֢˴bnEP:G5B4>8>=@D@HB;D;BCG99B@D@/-HIHKAG;D8A:?<><;<9A=>9C=LCK@>27+;-9,8-7-3,0,/-1134A19)1 1"8(;*6%22454 3"3%3(3).(2+6+8*8(7&7%6'3'2,3101+2*2+4-6+1*/+,.-4.8,7(5#.3 XHZL<2OG5/IFQRLKDB<8807,9+;+;):'9%:&<)=+=+=,9.;.=1?1?1@1@2A4k_qed[mirocbjituk|ivdm_hafgjnkqk|w}Yj[wZpaz]sMIZ6LR6snX˷YPAXO@XO@VM>UL=TK<SJ;RI:NE6MD5LC4KB3JA2JA2JA2JA2FC<GE9JG8OH6RJ5UJ4VK5VK9XNDUMKYUcii{}ԓߠퟧ梦榣誢瞧垞ҬºrUbCM;D7?6=8==?AADA:C8?@D;;C@A=41OPDF>D:B7?7;89:8;7F?<5<4G>LAC7;,9+7*7+7-4-2.3/5366?0<-6)4&6%6%4"4:":":#;&<*;,8,5*3.5-7-8*6&4"4!3"2$1(/+.,,-,1-3.4*,,-0.2.3*5'7'9'@,*E5?1F>WPC?BAWVRRKJC>=59.9+8(;);(:';'>+?-@/>-9.;0=0=1?0?1B3C6i\mdb[kfolbakluvpo|ir^fY^adqn|vyux~RdUrXnXn[tLN_;QZ;us\úZQBYPAYPAWN?VM>UL=TK<TK<QH9PG8OF7MD5MD5MD5MD5MD5GD;JF;MG9PI7SK6VK5VK5VK9WMCVNL\Vbkiy{͏ؙ䘙障蜤✢៙㞗䐝㖛ݠҮ¼rZqCQAJ>C<?;=<?=A>C>C;C7=?AA@D?=896WWBC=B:A7<586696;6HA:35+A5K>H:=/8)7)7+8,7.606387;;5)6*6*6*5(7):*?,556 7"9)8+4(0&=;>8=5</9)8$7"7#7%2&.&-'-*.-////*)/+4.5,3&5#9&>*B/1 TE<0A;C?JITSVVSSOMIEC;<28+6&7&7%7$:'<*>-=,=,:.;/<.=/=.?0B4E7\Og]aYlgpoabfgkoP`^khqem`edgqqzwvsnuJ]MjUm񜡟PcVoEOd=Va?ww]\PB\PB[OAZN@YM?YM?XL>XL>UI;TH:SG9RF8RF8RF8RF8RF8JF=KG<OI;RK9TL7WL6WL6WL:VL@UMJ\V`jh~yyĎДҔՕۖ㘛ꘞ욢훣뜥昢ߖؓՓՓג֐ց~reTzDa:K@HBCC?C?AA?C=F;F?F:>>@FCA<71>:[WAB?C=@:=8997=8A:E;9/2(</E7E6>/9(8)8+:,:/8083;7=:3+3,5,4-6-7.:.>/9(<)>->.=/=2>6>7?>?<?7=1:*9%;$<%<(8'2#1%2(4,2,0*3*5*7+7)7'8%<(>*<(=,^PF<3/.-?BUXvurojg^YPIA75(.8'9&8&:)=,=->,<-<.<.=/<-;->0B3E9MA`Wa[pltr`a]a^dFVYegpgodljpstxvssenCXEbRk뒘N\Ql?Ri?ZhDy|_\PB\PB[OA[OAZN@YM?YM?YM?WK=VJ<UI;UI;TH:UI;UI;UI;LH=OI=QI<TK:WL8XM7YM7XM;UK?UKI\U]hexut|~ĎƐ͒ԒܓᕚޕܒԌ̇ƃÁ}z|vqh[Kv>c7U8IAEFAIAIAFCAG;J9JDI>A@?JE?83,D<TPDCAC>@>?>=@<E;H<=27,5'9*=-=-<+<);*;,<-;/8/708395:764223142502+1)2'9-<0905/52<;DC5766615,5&6"9#;#>'9&5$5'9,;0:/8-?1;-8'7&:'<)=';&>-:*>2B:.+::142673;7C>JEQISHTHUG?0>.<,<->.@.?/?.=0=.<.<.<,=.A3D6LAbZc]nlrr`c`e`gixozlt`h^fkqw{{|pq^h@W>]Oh懍XaXuE\vIgwPfŻ㾺޺޼[OA[OA[OAZN@ZN@YM?YM?YM?XL>XL>WK=VJ<VJ<WK=WK=XL>PI?QI>SK>UL;XM9YM7YM7XM;WK=ULGYSWc_nmktt|~ȍώԏՍӐӋʂ{u|ovgpckn~eyZvMo?c2V0L6G@CGBLBMCIGCJ<N8NFHCCA>ID<45*I@LFCA>=:;;;?=E=H<I;7*7*8(9(9'9&:(;(;)=,<-;.8.6.6/5.24.1+0/237694521/,316342/3/55?=G,2.22/3,5(8';&>(9$8$8&:,?1A5B5A6I8B1<*:&<)?*<)9&;*6)0'B<1/>A.2'-3-4.71928.5*2&1#E5A2=.:+9):+:,:,</=.>/=.<+=,?/A4SGg^d_kinochjqoxp}t~mwcjdlqzw|sukpXfAY:[Kf}lojXoZx`rū٫ӦѥԩԮֱںZN>ZN>ZN>ZN>YM=YM=YM=YM=XL<XL<WK;WK;WK;XL<XL<YM=RJ?TJ@UL=XL<YN:ZN8ZN8ZM:YM?VKEXOP^Xbd_sifqpyy|~ĈˉΉ̈ȃ{~uxorjmegacacX^O\H\=V1K/D7B>@E@JBKCHGBL<N8PDDEDA=IB:/7,PFB<=8641051>8E;F9E68(:*:*:'8%:&:':&9&:);*9+7+5+3+4-)-)/,3.4071828587;8<9?9A9D6G6H5J)1,2024/7-9*<+=,7&9*</>2?4>4?6?6N<H7B1=,:':'9(9)3%9/@8D>0/-.38384-6.80:1;1;0:.:/L?F:?29*7)7*8*8*<->/?0=/<+<+<,>0KAc[c^kioshnrzveroyr{jslvvu}ioflRbA[6YFat{~zf{fhu˭շˮŨґēș˝ˡΧҮٻǾ[N>ZM=ZM=ZM=ZM=ZM=YL<YL<ZM=YL<YL<XK;XK;YL<ZM=ZM=TJ@TJ>XL>YN<ZM:ZN8ZN8ZM:[O?WMDWMKZSZ^Xfb]sjfspvwxx|{~Ljʉɂ}~zzuvqvoslogldPHJEFFEO@L7D3@8><=A=E?GBDHAK=M:OBAGDA<H=;.</VK>583.,)&.*:3C9D6@0:(<)<):';(=(;'8%6"7%8)7*5(3(3)3*03587<38,2&-'-)1,3'0%/'6+=(A:2".&0+10/1,4+5)6*6+90>5>7:4615061L?K<F7>/6(3%6)9-5*6-C<7421 89352(3)4)5)5+5*5+7+YNRFH;@4</;0=1=1:-</=0=.<,:*:*;-<2YQb]ppvyltrzr}yziqeop|t}nt`jNa@^3WA^nt~i}ghq̭ܽٻԴ̩ß~~ÏÑŗɟΪҵºνȷZM=ZM=ZM=ZM=ZM=ZM=ZM=ZM=XK;XK;XK;YL<YL<ZM=ZM=ZM=YMAYM?ZM=[N=[N;\O<\P:\O<ZM=YMAWLHXNOXQX]Ub`Yka\pifokspvq{u}ÊˊɈŠ~zrrulz^G9C7A:C@?=89:<BC<<=<>=@ABICMAN>NA<@9?6?3=/=0E8MD61;61.2.C<?36'?.6#:'<);'9%:&:':&:'9(7(3$."/%7.=57230.-)(%&#%"'"'$* )!,%7'<;43)7"."+*---+(-)416254645512-.+,++<491:1TK"+#F>.&/(<7E@:7/,.*41:7?3;.5)3&5*:.;08.bWZOD86,:/9-3)6,1%2&2&4'7':,<.=/:.C;\Wppsvv~yq|{xu}s{r~q}lxisbmI\=\8[:Vek}~i|d}cju|vxqwo|rtwuy§̹־ʻZM<ZM<ZM<ZM<ZM<ZM<ZM<ZM<XK:XK:XK:YL;YL;ZM<ZM<ZM<ZL?ZL?ZM=]M=]N;^O<^O<\O<]P?[OA[NFYNJZPQ\SX_U^_Wbb\xibngqjvpyƊŏÐ~tnquiY;.7)6)>1B6?6?8A==;:<:@<D?IAI@K?H>7=4<1</:,;+B5JAG@A=6341@9C8:+6%8%;(=*=*;(;(:(:&9(5&2%2%5*8.80912&0%.#,$+%+',+-,)-%+#.&5$951 0 .-92<*1(,.002*.9>6;3:06-2.314364/:572DADA/+2."41?<E@=83-2,6091<-9*5'4&8+;0<29/cYXN@83+:1;27.:14+4*4*5*6(6(7(6);0B9YTllqtw~|v|yv~uso}iweqanI]<\9\=Ydhysu`t\w]ckppmp_l_f\g^j_qeyi}lrtz}ƷǿҺŷ\L<\L<\L<\L<\L<\L<\L<\L<ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<\L?\L=\L=]M=]N;^O<^O<^O<_RA^QA\PD[NFZOK[PN]QS]ST_RlcXvh]jbsk}w}}ÙvotviU925-5)>/E5G7C8?9=<9>9A:E>GAH@E@B<4908-:*9(:*?3F<D>9665:7C=OEI<4%9&:'<)=+>,=*:)9)8'2#/#4*=3?6912+7&6&3#/"-"+%,&+(++(+'-(5%8523(5.;4?8C;D<E5>+61</9-8+5,3-1.1011.<964;9ljBA.-.,97?<A=<67.6+6+5*8&6%6%8);.<1<2;1aWTM<30(;3?6;3>6=8<7=4<2;/:.7*6);/@8TMgeorz~{{zxwsl}ftbn]kG^:Z9\AZ_cgk^eOhOlRtX{\}^x\qX`yO_P`UeYm`ug{jmptvyyz~ǹ˸̴[K;[K;[K;[K;[K;[K;[K;[K;ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<]K=]K=]L<^M=^M;^O<^O<^O<`P@^Q@]P@\NC\NE[NF\OI]PJ`NdcSmfX{g^ohzu|{yxucOyAF@@A=F;J;J;F9B:@?;A:D<G@HAFAA?<?6<19+;*:)9*?0D:<721:9A?D?TLVH;+9)6&8%;)=,=,9*8)3&2&3'9/>7>850-&:)8)5(2'/'.',(,*+*(,)1+7';";="A8G(6/;P\`lP\<I9G)8)8,90:1701*(&#2-641/BArpTU==FF=:<9:5807-7*4&1#7#6"8&;,</9.:/<4XQMG70/*<7A:;5=5<9=9?9?8?5<0;.9-9,<3OGc_no|~xyzxtl}dt_nXhE\6V7ZC\YZmRWxIXv@\yCdzIl}PtVwXrXoWlZl^obuh{loqrqruvvvwz|z|ȷ˶[K;[K;[K;[K;[K;[K;[K;[K;ZJ:ZJ:ZJ:[K;[K;\L<\L<\L<^K=^K<]L<^M=^M;_N<^O<^O<^O<^N>^N>^N?^N?_OB`PC`OEbM\cPdcUodZlevr~wv~‰ЁwkXuFf=MDPJNJHG>G<G<D>BB>C>G@HCIDDB=?9A5=/:+;*:)9*<.?6FB<;ABAA:8JBXLL>@08(3#8(<-:*7)8+0%3)8/;4:3500++'4,4-2.314345586;/4.60=2C.F*G,L1T<H3?@M_llzWfCS>P3D2A3>5<89733*/$2*-(61XT\ZXV@AHHB@<7706-8-9+7'3!:%9$;(=-;-6)8.>5NGEA501->9?:8171/011427392:/9.:.6*7-IB_Ynl}v}x~zxsj{dt_nUeF]6V7ZF_TRvaBJo<Us?[vCdzIn~QtVyZy_waygvhyl|oprpmrrttrrtw{xxüƪZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8[L9[L9\M:\M:\M:^K<^K<^K<_L=^M;_N<^O<^O<]N;]N;^O<_P=_P=aP@bQAbQAeKTdN[aPc`Usgarpxv|rv݂̋rbsOb>R-H:QCTDK@AA>DAEBEFAF@EBFDEEAC:?4@3;-8(9(:)9(:-;3IE??;>682/A:ZPg[QCA34'6)9+8+6+8,0&5-;4:440/,-+-,4;3;3<2=1>0=0?0@1A2D5K5O0P-Q1X:d7BO\an`nXfQbEX8J@S:G2;/23-9-=+>(9/2(JBkcLGPM<9;9LJ@<7/7-</<+:'9&>(;%=)?-9)4':1C=HAC?722.;7:62.2-)++,.-3/61:1<1>26)4)B:XRjh|}v}y{xqh{bt^oSeI`9X9[I_QNmZ:Em8ZvCa|InSvY|]bgll{m|o}p~onllqqrronptvtwï̾ŽӫZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8[L9[L9\M:\M:\M:`J<`J<^K<_L=^M;_N<_N<^O<^O<_P;_P;aP<aP<aP<aP<bP<fLOdMUaO]_Vkgbsryx}tvΆ}owbjOX>H$H0Q;U<M<GAEEDBCCEBCADABDBC>A6>1?19+7':)=*=,>1>7=:79/3/03294NElaj[QC</:-:.7*6+8/4,7/93621/.,1/320E/E-D*B%@"=::'A+G/M0R+R)V1b=nHS`miuVeKZL]CU1DAR7C,3)(0$9&A&D'=.;,ZM\SG>D>61;7UQF@918-:,9(:&;%B)<&<&=*8(3(=4MFGCEB96307341/+2-)/*/--0/4/7/;1>2:,4(;2NHb^yzz}}xn~dw^p[lN`Ha8W7YH]JGcS1Al6ZtDf~NuZcfjnsttr}p}nmlknpoolknpsrwƱοŷҤZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8ZK8[L9[L9\M:\M:\M:`J<`J<^K<_L=^M=_N<_N<^O<`Q>aR=bQ=bQ=bR;bP:aO9`N8jNMgNRbQ[cWkjfuv}}y{˃{|qsgjTXAG#M.T7W9P>NEMEH?BBDAC@AA?C?B9?4=0?19+8(=,A.B1C7D=6457,002880+5-UKzn^RD7=0<06,6+90708271401/105387=>>>==<=:@$I&N$Q%U0e=sgralXeR_Q`M]?R1B:J4?-0-(5'>&C%E"7&9(WH<0A87/3/C@XSHA916*6&5$6"9#B*<%:%<*7&3'A7SLIEGE:82.411-.)4.'-',)+*)-(1*5,9->13(7.HB\Xwu~xl|`sZlXiHZE^4S3RCXE@\L*?j4Uo?d|Lw\hlptx{xt|mzi}ghhkmmlj}ilostx«ǶȻӞ]K7]K7]K7]K7]K7]K7]K7]K7^L8^L8^L8^L8^L8^L8^L8^L8\J>]K?]M@\L=ZM=ZO=\Q?^SA_T@_R?^Q@aQAcRBdQCdNAcM@pKEjKIfOUgZknlv|}̃{~uml]fRN[DQ>LANCQ>K:G<F:B;?;;<:?7>4;/8+:$C0=,6(?5D=;56183716-7)9(=';"774PLXOD98(?.C3;-4+GD.14;4?+9@Q(9&+*-*-"#$()(("+1 )&1.<$5Yn+@`j^iYcT[PTHI@;:1A2F2D.;$57#;)=+8183EC;9234544CAKFKED;:04+4*3+2*?19,.#',"7/C:G=PFE;801*/-01/3.4141201/00.1+4+8-=/2#?0>3`Wtqwe}[wXuSoJgDc7Y9]>[]kC=PI/F`;Xw<eKu[zcze|hlol~k~j}g}feee}p~onk~geegjpszĤŧz]K7]K7]K7]K7]K7]K7]K7]K7^L8^L8^L8^L8^L8^L8^L8^L8\J<^L>^N?^N?[N>ZO=\Q?^SA_TB]QA]P@_OB`NBbPFcOFcOFkLGjMOgS\h_rnow~~̢wx|xuhjYZgN\FRHUJVER?J;E9A:>::=:?7>4</;,>+?-9(:,A6<47/<7404-4*4(7&:&;%;"52A;MDI>>/8(8);.<2JF/15<6A.<?P'8$'%(),+,*+'(((*,$'%(%,:D'4CAT#6lublZcW]OSBC;8>68,E4H6?,1)()-':6TRHG5445<=WUGBGAB99/4+6,7/5.?5:15.3+4.83?9E=JBA86/1*0-1103.3141201/00.1+4+8->03$=.=2^Uvsue|[vWtQoIhAa8Z=_F`Q\{?7NH.Ga>Yx=eKsYxawbzf|i}j|i|i|h{e{d}c}cd{l}n}l}i}e}cccfkpu|zdoqR]_]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8]L8^K<_N>aP@`P@]P?[O?[O?[RC[QE[QE\OF\OG_PKcQOfTRhTUiTQiVXi]kmisvz͉ٟ֗ʪ}烅~tve`kS\GQFQHREQ@K=G6=7:99<7@7A4?0=-@-=+;*B4I?;20)926/5.7,7*7(7$:%<'3/4.A9OCH:6%3#@2>5HD134;6@4@ES3A),"&#&03--''%%12(*7:+1)13?R^=KYiafV\OTMREI:;74?96,?2C5>18-3),%' % 0*FC::,,44AB^]>:C;A9=39/=4@8@9A>=;>=A??>;9?=IDA;=45,2+2-3112/2040201/0/.0+4+8-?14%9*;0[Rzw~rcyZtTqMmFg=_:^BbQg?Fn<1OK2KcA[z?hLrZu^t_wc{gzgyfyfycxbyb{a|b}byj{j{h{e{az^|^`hnstwvypngVb`COM4@>^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^L6`N:aP<`Q>]P?ZN>YPAXPEXOH[RM_UTcWYeX_iYcl\fm]hlbclemolrtx~τߊ狇ޝ٬ɳy{߁yvnrbgU\LUFPBM>G;D5;7:97=7A6B4B1?.;,=/>0G:RGH?6.1)9181;0<0;-6%6&9'402-=4OCK=;,8*B67.>:/0164<8BNZKW>C38$&/1,,22+*0.::37-29BENYcLY?AADCF>C9=8988:58391:2A:NHVSNNAB82:5KGNLQRYZRQYX51>6C9@7?5A9C<A;<B7=8?>C:?58=?LJ93704+3,5.302101040201.0/.0+3+8-@26'6'9.WM}y{ocwXqNmFh?c8\=`IdYh25d<0SQ8TgG`}EjPsYt\u^wbyeyfwdvawav`x`z`{a|byhzg|fzbz_z]|]~_emrsustii_RaZDSL8G@^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;^M;_K2_M5aO9_P;\O>ZN@XPEXQKYQO^X\g`hnfsshysg{sg}tfnnzorrwv|y~׃刋쒍뛌ߞƞtkmqvj{illklfi]`QWEM;B5=596898>7A7C5C0A-8+@3;.;1RH]SNC;2907,9/>1=16*4'7(2-60=5E9F9C3A2?20&620/-1-47?OYZd[_OS.103--EE66,,-.>@2537ch=C*2-4();=AE7:378;89..43<9HESS`chndk[eB<E@^[igopjjKK=;4.>7E<C;?5<4937/0=,9+6-8*5+38<JK3/4.4+4+5.404/3//4/2/1-0..0+3+7-?29*3$8-NE}y}wl|atUmHg>b8_4\@aMcWap/+\A0XX>]lMbIlSt\u_v_xcyexbu`u`u_v_w_z`{a|byd{f|dz`y^yZ{Z}\_gmpst{nrffvi[k^RbU_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<_N<`L1aM2`N6^O:[N>YOE[RMZTT_Zahbprmzu{tyrzpyoovpyt}wz~Ճዋ唏㗊ҙ~yl[X>H?PIVRVURRJM=C387<9;;9=8A8C4B0@-9.A65+.$J?h\eZVI=26)4):0;05,3)6+/+61;2:/?0F7C39+1&3-31-.*.17EJS[_d\a9<9<+.JK89//55()(+YZ?B9=7: %))=>BE49,217/5(,37KNaehncl_k_m_nNIOJ]ZVTMMGH3231A<KDPHKAA8:3502+,;+:(7%4'4/:=CIL1.3,4,5,4-4-5/4//4/2.1-0../+3+7-=0;-1#7,D;yvyqhx`sTlCc7^3_3\DcM^JMb6+TE0W[@^kMc~KkTt[w_x`{dzcv`s]s\s\t]v^w_{a|bybzb|b{_x[xYzY{Z~]eimsus|mvunmfwe_P=_P=_P=_P=_P=_P=_P=_P=^O<^O<^O<^O<^O<^O<^O<^O<cP2cO4aO7^O<[OA[RK^UV_Zakgvso}z~|}w{u{tpzs}w{~DŽ͋ӓԘ͠«ǮŦlmJ?/A2@4A9GBMLHK?A;?:=;;=:A:A5?1=.;2?84,1'J>cWh[fYPB?25)7,:05,2+6.0,4/7/8.>1C4?04'4*1)2/..-.1468?COTY^FKRW47FJ8<BE7:.015IK8;8:#%<>89;>=A6<-4)219<DLS^eksis`lYhXhXkgaZVWT@?104441C@JDRKSLJA?7938171)8/>/>)7-:9CAHAB1/4-5,5,4-3,5/50.4.2.1-0../+3+7-:.>02$7,<3tqrj}bt]pRjBb6`5a8_KfN[z;6Y?.LH/TZ@]cIbzJjTr[v^yc{dxas\pYpYqZqZt\u]y_z`x_y^z^y\xWvUwV{X~]dhlormxgrlk}ecu]_O?_O?_O?_O?_O?_O?_O?_O?^N>^N>^N>^N>^N>^N>^N>^N>eQ6cR8aP<]P@ZPG\TR_Zab^otryx~~yxwvxwt}w}Ƃƅȸп¡ϼDzkS\FG5=0H=VQVTNO?A=?<<<;=:=5;18.82<5:3>5PDYM]PgXdWM@:-8.913-2,50402-5-<3C7C4:-3%5*-&0+.,2144.,00EIY]W\puDJHN=C[aou>C~mqQT>@02<>EI9>7==F6@-8>J\hmwitdl]g^kap]nWh_YOKJG740.54/.95D?JDJA@86/5-7194$0/<1=*6/:>E>C443.5.6-5,3*3,4/5/.4.2.1-0...+2+6-9-@21$6,7/pokcx]pZnPiAd7a8d=bPiQW^2'RG3DH/PV<X\C_vHiRq[v_zb|dx_rZnUnUnUoVrXt\u]y_v[x[y[wXvUvSwTyVzX~_cd~f{fr_kV`uVZoPRgH\L<^N>`P@`P@_O?_O?_O?aQAbRB_O?]M=]M=aQAcSCbRB`P@eS;aP<_O?^QH[QOZSZeapsqxxz|~}xyrsnoqwv{̋ȖäŲͭЩУѠѡ̚Ɣզg_FzgteG?QMbaIL>A799;997561949550B;=5I?XKPAeVdVYKG;:/6-6/5/3//-2,70=4<08)5(8*/$/(.)0-204051408<JNY]OS7?6>X`~~owgoipfj\_Y[^`RYCK8B7A1>+9/>=IS_`kgpepbobp`o[lTOFA853110/.2186D=B:?7<4908183845=4;3;4<5;49331/3,6-7.5+3+2,1,2./503/2.1///,3,7.@49,7+/&<5XW~he|]rRhHeAe9b5`JlRd==K. >>&?I.IO5]]EWlAcxMqZxby`t\rXqWlSmRnSoVrXt\u]u]tVtWvXwWvUvUuTtS{[{\z\uZnUc}MXrCSj>AW1?U/<R,[K;^N>`P@`P@`P@_O?`P@aQAbRB`P@_O?`P@bRBcSCbRB`P@fVF_QD\OF_TRcZ_f`nmkwvwy{}}x|qtlolnoqsu|}ىԘШƹƵϩףܞߞޝܞ٠ҜʖѼ~dċw}mVJ`YqnZZJL>@<>>@:;5634=:73?86.>3L@I;^Op`aSH<5)0&5-4-/)4395<7<38.5)5(5*6.4-1+0+0,2,4.5.9;>AIMW[\d\d]e`kR]MXQ[_gjqfl[`RU07+5+5-9&5/'67DP\[dclemepdo[hP^FB<9646353202/62>9>7<2:1918295969;7:7:797957313,4,7-7.6,2+1*0,1.0503/2.1///,3,6.=2>28-2*82Z[w{a{^vWqOkFf=b:c=cLhJVw<8F5#7=#9C(DH/UP<Tf>`rJnXw_v]tZpVnTkOkPlQmRoVrZs[s[tVuWuWuUtTrQqPqQnPlNhLbFXu?Nh8F]/@W+@W-@W-AX.YL<[N>^QA^QA^QA^QA_RB`SCaTD`SC_RB`SCaTDaTD`SC^QAbUM^QK[QPcYakesqmvuy{y{y~w}nseibfjnrv}zᇃᖔߩټظۤϠĘkpp`RG]Umius^_HL@D@D=@7:36>;;6A:707.?3=/G8j\j[\MB62(4+6-1*44A>GC=62)1'2'0%3*1).)/)2,7/=4A7-,43CEVX^bYaS]P[FQHSNY\fmvmtY_AG*2,41<1>*9&66EJXISOYW__fdkaiQ[BJ956375<8<9855160:3;290908183:6:8;9:999988884403+6,8-8,6,3)/)/,0.151302.1//0,3,6.9/D99/4.0,`bnu_zWsPmLlDf8_9_GfReDJi=4K@,7@%8@(ED/LE2N^9YkEg|Qr[tZqUmRkMiKhKiLkPmToUpXqZuWuWtUrTpRmMkKjLdGaE\~AUt;Li3E_/AX*>U'B\/E_2Ic6WJ:ZM=\O?^QA]P@^QA_RBaTD`SC`SC`SCaTDaTD`SC_RB]P@YNR[PVbXcjcsqmvuxzz|w|symrbi]caglrv|ȋ攑褡淴޿ܨҧßvqsecWi`rmut[[KNCG?D;?8=:8;8D?C;:0;/7)2#J;bRk]SG9.3)5+4+33ML[XKF803*4+2(-&,%,%,'0)6-<0?20(4,:6CBFHEKGPLVQ]VbXd[ggpmuY_=C.2-4-4*4%2(6<KS_?IBIGMQV[`X]GM5<5173;8?>@?<;857292:1908071738687<9;9:7;8:8845.4+7,8-8,7*3)/)/)/+252312/1//0,3,6.8.G<903.-*fjyjr`{TqKkFj=c3[<^PhXeDBbE7WP=DH1@D-JH3JB/IW4Sc?btLmUpXoRkNiKgIgIhKjMkPmToWpYtVsUqSnQjLgIeHdG`D]AWy=Rq8Mi6Lf6Ne7Pe:Lf6Oi9Sm=UH8WJ:[N>\O?]P@]P@_RBaTD_RB`SCaTDaTD`SC_RB_RB_RBTLY`Xgnf{tpxtxwxzy{syjq`g\b`fkqv|~Ε䞞譭齼߳سѴůy}qwkskngoi扄~sredVYLNCE>A95:7B=E?<3=3B51%1"I;YKN@=/8*6*3'34UUkh]XE>;3;2804-1,1+0)/'0$/$0#9,4'3):5CAEGBG@HDOOZVaVa^igoYaDI885526183;9CHSVa6?4;7;AFKOIM;@056195;8;9;9:77370;2;1;2:282736465<8;8;8:9;7956/4,8-9,9-7*3)0'/)0+453322010/1,3,6.7.D:7/1-21jprzhr]vPmCf<d7c6^Db[mW[uF>_L;_ZFQP;KI4PI6MB0DR1M[8[kFf|NmSmPlMhHfGgHgIiLjOlSnVoXtVqUnPjLfIcFaF_DZ@X|?St;Pn8Pj:Tk=XmB[pEUp=Vq>Wr?RE5UH8XK;ZM=[N>\O?^QA`SC`SCaTDaTDaTD`SC`SCbUEdWG]Ulje|yu}yzywyvxswlqcj[c]ehpw}ǁІՙܡ௲廿Źxzuwvqulg~mfoib[a[smzu{|yrpccSTHHB=>:<6A;:1D:TJ>26):,=.?/A3C5?18*23LM_]XSD?;48170929292929/9.9+8))3"@2I>E>;:7;9@8AHTUaYb^g`iU[CI?:?;AAGJMRQYT]V^4:/5037:=A:?48/2619595411/20404.<4=4=3;293734333:898888987754/4+7-9,9-7*2(0&0(0*454332111/1,3,5.90<3700-AAnukucoSkIf;c1`3b<dMg]iIFeH:YN<\WCXQ>RJ7QF4MB0AL.GU4Sc>`rHgMjMjKhGeFfGfHgJiNkRlUmVqSoQjNgKcH`E_F_G\E[~DWxAVr?Uo?YpB]rG_tKYtAYtAXs@NB2QE5UI9WK;XL<ZN>\P@^RBaUEbVFbVFaUE_SCaUEfZJj^Nkgup|x{ywxvwptjoah^f_gempx~͉؏ܙϠ֪۴ߺ߾̼ƻŴqqstpqogevhenj`Ye_[Tg`tn{v{wwshf[ZQKGB=6C=;4G=\R;0<07+6(>.D3C2A1A08:>@DCC@=8917/7/:393:3;3>5A5E6G8.;%K8L==30+108>BJKVU`Ze]eYaLR?D4+8/<7@@DFEJBI?F5;26368<7914-2.44095640.,*/,2.2-=5=4>4<3:58565555757575656422.1*7.:-:+8*3(1&1(1*555342111/1,3,5.;24+;420UVpxcn[gKbEf7b+]1b@hKeRYd8/ZI7SN:UN;[P>VI8M@0MA1=H*CN.K[6Xj@ayGfHhIgFeDcBcEeHgLhOiRjTnPlNhLdJbH_F_H`H_H_H]~I]yH]wH`wKcxOdyP[vA[vAZu@MA1PD4SG7VJ:WK;YM=[O?]QAcWGdXHdXHbVFaUEcWGj^NpdTvqyuxvtsrrsulpbgZa^femltu}ƁЍڕ⚤ȟͦԬٰ۱ڲڵ۳ֲѮ˫Ī¦{|ydbgidhbY\g[[xeauXRe]OHVOaYjcvp}zwuljZUPJD>MGB9F>WO,"2'5'=0E6>-2!8%F4DF9;3262;6<7<6<6;4825.4+5+8+<.>/U;I/=';+=2;56537KRLVOYS]WaU\LSCG5)8-816455584:288<6;9=<?6:,0)..44.94860.,*/-405.;4=4=4=4;49676563615052435310-/(7.9-:+8*4&1&1(2*655342211/1,3,5.=4/&>853cepy\hR_HaGh:e*]/a@hE]AFQ-!UJ8PN9OH5\O>YH8L<-NB2:D)?J*GU2Rd:]sBcEfGeDcBa@aCcFeJfMgPhRlPkOfLcIaG_H_H`I\G]H]~I`|Ka{Ld{Of{Rg|S]xC^yD_zEAC8CE:IF=OH@RGAWI@]M>`O=aQ:aS9`T>_VGaZTfaeljwrowozt~wzurohfa`^^bahgqo|xυڏ㗐흖٣ڥܦݧݦۥڦ٥֣ҢС͞ɗymrvghlc_`e[ZlYUtUPULVKRGZNZP\Smd|t~xyyyabPQEEYV611(5(7&6%8%9':+<.?18+=/?1;-5'4&:.?590907.7+7);)@+C,;3?7D<F>C;<42*,$>5G>QHXO[RYPPGE<<!<$:(4,--'0%2$6(@'@'B&B%B$B!A!A:"<'>)<*6.648;;94:5<4;5:593736225445464717.6,6)9*:(:&9&8%8%7#7#414/4.3.4,5)6(8*:.7/96>BlyasRlGdIj5Y5];e=cPjLVT)":1 9<)EF4RL>PH;BC39E15K4FGHJ#MQ,U\:\jGcuOf}QeNcHbBa>c@eDjIlNmQjIiFgFfFfHfIcIcGdJdIc~Gc~GdFfFe~Dc|BX}8[;^><?4?A6FC<JE?OF?TG>[K>^M;`O;`Q:^S?^WGa\Vhcinlyrqtnvptppmgfaa]^\\edkjtr}{φَ蘒웗Ҝӝ֞ם֝՜ҝўќ͜ʛǙēwtmtkdkf]`e[YiZSoWMzVJVIUK\RYRXRf_qjvowuufdTSYU2+/%7)7&7%8%9&:*;-=/8,9,:,:,9+9+8+8,;1908.8,8*:(;&;%4-80=5@8A9?7<4915->6H@OGQINFC;7/89"8)4,./*3(7(:+B*B)A&A$@ >=<89$;);-9297;;;94:5;6;5:593736225365464717.5,6)9*:(:&9&9%8%7#7#4-3-4,4*4*5(6)7*</5,52TYes[pGbKh@d:`1[7aImJb8?O,&=7'3:(:=,C@1F@0@?-;C.:H1@CKP'\b<eoLhvRezSd~QdLaFa@a>c@eDiHkMlPlIjGhGfFfHfIdJdHeKdIcHdHeGeGfEd}C\<_?bB69.:<1??7E@:KB=OE<VH=[K<^O<\O<\TA_WLc^[helol}sqsmqkjgc`\[ZZ\]\_hjnowxʁ҆؋ܐⓒΓΓЕДѓГϒΕ͓ǓĔz{rdpt_fiZ]c\Vc\ReYKqWHTFZQ_Y[YXWcblipkwq|ymh`Z4+2&8):':%9%9&:):+:,9-5)5'8*>/>/6(/":.7-7,8,9+:)9&8#4*6,8.:0=3@6A7B8;1@6E;F<H>G=@68.6!7&7,3/03,5*9*<'='=%=#;!:87766#8*;1<6=9;;:86:5;6;5:585736226475565616/5,5(9)9)9'8%8%7$7$7$4+4)4*5(6(7&7'8)=12+98lt]nPi=[Jl5\=e4[<`Tq?Oa#(H1+79+-8'18&:;)B=*A<(@>)@B*?GY`4s~Tfwbi~Ub|MaI`C`?a>c@hEjJkMlPnKkHhGgGgIhKfKfJeKeJcHeGfHfGeFcDbBeEhH06*58-;<4A>9G@:KB;RE<VJ<XL<YN<YRB^WOc_`igrompppmjg`^WWTUWY\_adkoqt{|̂Ոيیڍۏ͎̏Ύ΍юЍύ΍ʎƎxxq[i}WbmWYa]T\`Q\^IhYF}SCULZYW[V\bekkplys}v{u~{ka<29);(:'<&;%:&:'9)9*9.6*4'8)>.?.8(/!6)5)4(6)9+<+=*;(9/9/9/9/:0;1<2=3E;E;B8=3=3A7A7=34#6)5.31/5+6(7)<&9&;&;'<&<%<$:#:!7"7%7-95>:?9:8786:5;6;59585655427376665726/5,5(8*8(9&8&7$7$6#6#6'7(8'9(9(:(:':+;/3.IKo{VjDa=_Ci/[7`=cLlOe0=G >3--3'+8'2=,=B.B@+C;$G="MA'R_*q}Mp|mjW_{J]~E_Ca@b?fCkHlLmQmSoLlIiHhHhJiLhMiMfLdJdGeHfHhIfEeDfFiIlL-3'17-7:3<;6B=9G?<MD=QG=SI=SK>UOCZUQa_dhgukklljgbaXVPPQQXY`cfjorux|Ѓֆ׉؊׌،̋ˊ͉ЉшъӉЌϋȍ}xvpScQ\qUT`^RVcOTbH_]DvUBLBRRPWPY\dejljwqvlph~v{~ka?28(;(='='=';':'8(8)8/7.8,9+;+;*:)7(9+7+8,7+7*8*<,>-=0<0<0;/:.8,7+5*@5@5=28.8.;1:06,.$0)2.23/8-9+;+>-?.?0@/@/A.?-?->)9)8*70:6=9=775386:5;6:79585655438485676746/6,5*9*9*9(9&9&8&7$7$9%:&<'=(=(=(>*=.8-;8^eaqPi;\Ai6a/].WIjYq>NX'-?+,730*1)-9-5@/:B+<<"B;VG(iV6vPlwo[aK^F`BcBeBjGoLpPoSoUoLlKiHgGiJiLiNhNfJeIdHfIgIhHgGfFgIiKlN*2%.4*470894<;7B=:HA;KD<NH<NH<OKBUTR_^ffewggfgba[YQQNORS[^eilosxx}փ؆ن׈ՉԇȆȅ˅΄Ѕԅԇҍӌˍ{vrnN\NTqTPa_PWgMReI\`EsXCOCTRSXPZYc`ghjqq{rrh}tsjxm\Q:-5#<'>(>(=(;(;)9)8*3+6-:.:,:)9';)=,>.@2A4=17*4&8)<,:,:,;-;-;-9+6)5(6*;/>2>3?4>37,.#)%-*02290;/>/?0A0@1@2@0=/:-9,8*7/</;0:2:6;68554286:5:6:78777675449496976746/6-6*7+8)8)9'8'8%8%8%:$<%>&?'A(A*@,=.71IKgrOdHf7]Am/_1^1XOjWfh39@*,?994443524925>-2<#29ECl`8}RuΗȕ}vbeQ_F`Bc@gDoJrOrRqUpVoLlKhGfFhIiLiNiOgKfJeIfIhIjJiGgEhJkMnP(0#*2'/4-350664<87@<9C>8IE<HE<KHCQQQ[[eabvab~`a_]ZXTTTT\]gipsty{~ہބ݃؃օ҆ӃDŽȃ˂̓ӄՆ؈ՍՋʋ|uqlirOVNQpUNc`OYgMVfI]dEo]ETF[TXYSZYa\daekn|rsjxoYP[QD85':):'<(='=*<*:*8*7+/'2)8,;,<*;(;(<);*C4K=G:</4&5';,9)9)9)9)8)8)7)7)7);.?2?3@4A5;/3'..12495>3>0>0@/?.</</907.5,2+2)/1;3<5;59475565758697:6:7877767465:5:7:8774726-6+8*8*9(9(9(8&8&8&:";">$?%A(@*>-;1:6U\_oGc>b8c6g0c4\CbMaBIL44:97<<>948>58<7379+3="8DS[,PoȈˎ̒Í}{ggQ^E^@c@iDoJsPsSqUoUnMkJgGeEgHhKiNiNfLdIdIgHiJjIiFhEiKlNoQ&.!(0%-2+130333756:97>;6GD=DD<GFAOOQZZd_`t^_{\]|`^\ZYX\\ggqrz|}܁ゅ䃆ㄅႄہՁ҃ЄȃɄ̃΅Ն׈؋؍ҌƋxsntjfgSPuRLjWIe`MafO\gI`cFn`FxR?[MZSRRUZV\X``itkofqhD;A91%4&C29%:&;'=);+:,8,7,,#/%6)<,@->*<'8$5#B2OAN@B47)7)>/;+:*8(6'6'6(8*8+;.;/9-5*7,;1<29/7:8=:A8B4A.>,;,:/;19385857483645496;9<69453386;986979899896967465:5:7:7985827/7+8+9+:*;*:*:*:(9(: : =$?%@(@+=.81<?[hQhHh7]<j,]7i;XYpLUX00?<5<E@99;B3:G08F21?9+<E(DW*at=_|̌ɋĉzygfPZ|@]?a>hCoJrOrRpTnToMkIgFeFfGhKiNiNfKeJdGeHgHhGhGfDjLmOpR(0!'/"(-&+-*.0/333775:94==5?@8DE?JLKQQYVWiZ\s]^|YW[Y^]eennwxڄ䊌솇䂂܀ԂӃҀāǃɄΆ҈Ջ֌ҊNJ~xwpxkeec^XpZMm[Mi\Kf^Kd_IcaHfbGl`FlR;UA^OaYYXPTQ[XbkcYRD<707/;/</;+9(:(:(:)8)7,5,4,/'2)8,>/@/@-=*9'9)0"VJJ?.#=1</8*;*:)9(8'6&6&5&4&7);.>2<07,7->4E;AF8?3:4?2>-;,:2=7@5;687899:98665==<<:<8977767575979899::9;9<9<8<6;5:7:9::9;5907,7+9):):):):);*;)9!>%;#5:$E3@60.^eVgHc;\0X/[5c<j\mEOo33G6.9C8:E==9:B+3P-4N00D7'CJ)Wo=}_v~ˌ~~nfRXvBY{?]>c?iDnImLlNkQjRjHfDcBcDfGhKgLdJgMhNgKfHeEfEjImJpSrUtW*0")/#).'+-(-/.222553782;<4>@5BC;HJGOPTSUaXYm[[s\Z^]dakjus}Їዋ퍌텄 ڀ~ҀσυƆȇˉ΋ьЍΎɊ{x{stknkd^e\SbaLb`Ke^Kh]Ii\Ij^Hk_Gm_EraG{]C[F[LWPQSPXS`WQKF>9505/908,8*8&8&8&8)7)5,3,2,1'4)9+=-A/@-=*9(9)<.QEH<4(:-:,5&=+=+;*;*:)8)7)6(7*8,7,3)1'1(7.=4BH7>07/:0;.;1<6?6<3632:8EBJFEA?<:9:89796858598988788999:9;9<8=7<5:596888:8:5917-8*:*:*;*;*<+<+<+9"?);$5;'</:2<=]iOd@[6Y5[:`=f@gEJ>>];2@>/3A05?4E=:X;?T-0X51ZI7bjEu[p||}yr`YuESq?\{B_>b>iCmFlKkMhMhQhFeDcBcDgHiLhNgMiOiMiKgGgGfGjImLnQoRrU-1"-1#,/&,.).0-11/34/45-9;0<>1@B5EH?KMLQRWUTbXWi\Yx^]fcpmzxύᐏ퐎釃~|}ȁ}DžĈƊʌˌˌnj|v{pujpod`i_Ue\MXeK]bKa_Jh[HmZIp[Hq\Go]EtcItZ?V=WDYMTSNTIU@<<984616/6.6+7(6&8&8&8'6)5,3,1,5(6(9)<+@-@-=+8(5'J=E:A5</6(;+7&:):):):*8)7)5(3'8-6,3*3*2+6/:3=6;?4:070:2<3>7@=C7;AANKZUZURLB>62727474748596;8::7788898;9<8<7<7<38475777:7:48/7,8+:+;+<+<+<+<+<+9$@*9$7$;+2%40OTZiH`8U6V>]FfHfEat?9e?6QA2@C04?.29)>5,O61K*#W:,j\B_t{yv|m\uKHa7Nh9[xB_}?c?hBlEjGhJgLeMeCdCcBeFhIjNkOjNkOkOiMhJgHiHlIpMsVtWvY25$13&02'01+12-23.34.46+9;-;>-?B1DF9IJBNNNRQWTR]XVd\Zoda~nlzwČؑ唑쓏펋扅ڂ{|}Ë}{vzm~sfmoa`k^Vi[NgZJVdJZbJa_JjZJpYIsYJtZIs]FqY?tU9T;ZF\PRNEG:A3/4151505.4+6)8)7$8$8&9'6)5*3,2,8+7)7(:*=->/;-8+3)TK;38.A64'<->-7&8'9(:)8)7)6(3'5*3)2)4,:3>7?9>847596;5;2:397=<@UVc`njidVQA<613/71717182859697::78898;9<8<8<8<8<48686787;7<49/8.9,;,;+<+<+<+;*;*:'@,8&9';-+"54_gSdE];U<XG_OdP_KZcPAVI8JE2CF1AF0<?*<7#>1B2SE*okHfttqt}l\K_:BV1Lc7Yq?_{@d@iAkDiFgIdJbLcBcBdCgHjMkOmQnRjPjNjLiJgGiGmKqMuYvZx\78(78*66,56056156167/68+;>-=@+@C.DG4IK=NNFQPNSQTVUSYY[a_lkius}Ȍ֕㔐䐍ދӄƁ}|{~zxsznzrfjm_\j[Tk[NjZKjYI^bK_aKe^Kk[KpZLtZKw\Kz[G{WAS=U?XFSFF?76012-3/5/4.2*2'5(9(7$9$:$:'8)7*5,3,>-:)6%8';+=.;.6,80\T=54+A53$:(@-9):*:+:,;-:-8-7-3*1)1+71;7>:;77477;<<?69156:BFNOxwqna[KC832.73?<939382727275767868798;8<8<8>7=7=69797:::=:=7;2;/9*;*<*<)=)<(<(<(:(=*9':*9-0)AAgrL^E[BYF[N^T]VWSQSU@LN9JG4JE1FD-AA'>C#@G%MU.^g<xTfmnrzudRcC?O2BS3Oa;Vl=b{Be@iCjEiFeFbH`IeBdCgFiJkNlPnRoSjPkOjMiKiIkInKrOuYvZw[?>,?=.==1==5=<7;<6;=2;=/?B-@D+CG,GI1KM8NOASPITQLYXDZ[M_^Zgepqo{yƏӏՍъǃ~zzw{uzw|y|~~y|tzrvkqrffm`Zl[QlZNl[KmZKmZIg^Mi]Mi]Mj]Mn]Ms^My^M[I`OWGN@I=@56.0)0*515/4/4-2)3'6&;(9$;$<$<':)9*7,5,A.;(6#5#:)=.;/6->7ZTHA90@36&4 >)7'7'7'7(7)7*7,8-<3:293<7>:=9854196<9::8:>@ORccqpheUP=82+5.;7<::9<3:2:4837365556869697;8<8>7=7=6<8:8;8:;:>:>7<2</9);*;);(<(;':&:&<):(<):*7*?8TXdpK\H]I\L[RXWV\R^OAP9FN9NI5K>+>467>O#Jh4gTt\cdfltxpn}\Q`C=J09F,BO3O_;Xi=czDgBkDkDhFeF`G`GfCiFjKlMlOkOmQlRmQmQmPlLkJmJrOuQy]y]x\CB0DB3DB6EB9CC;CC;BB8AD3CG0EH-GJ-JM0OO7RQ?TREURI[\:\\@\]Kaa_ihvrq{z~È{ystpqmolrntqwrwrtoskxrilmb^l_Vj\OlZLn[Lo\Kq\Kq\KrZNq[Nn\Nl_Ol`PqaQy_N[K_SOEA8:25-1(1(5*706/4-3*4(5(6%9#;"<$>$>'<';*9,8,D/<(5!4!9(<.9/5-83NISMB9B5@.2?(;,9+8*6)7+9.;1;3D=A<?;>;=;;:8877939584;:JJ\[dcca=9824.81B=E@=;42;3;3928484667777696;6;8<8>7=7=6<686989;9>9>6<1<.8););(;';&;%:'9&?-7%=,:)3'QKkm\fN^I\HWJUSS]RfQjP=S<CL7JB/L7$F5FH!Tq;cTxoof~YXcd|YXeGGT89E-8A,:C.?I0JX7Wh>g{FhClEkDiGcFaG^GiFlImNnOlOjNkOkQpTpSpRoPoNqNvRwUz^z^y]GD3HE6HF9HE<GG?GG?FF:FG5GI1HK.JM.LO0QQ7SR=VSDWSG[\4Z\7[[C\\Rcbhmkuszx~{||zwsomjkfgbhdlflhlhleuibij`^g]Th\NjZJl[Io\Ks^Ms^Ms\LzWQvYQp\Ql`PkbQpcR{aP\OULD>613/5/5+7*8)6/4-3,4*6*7'7%7 <">">$?'>'<*:,9,E/='33 8';.9/5./*?;YTI@D7I75D,F7D5A3?2?3B7F<G?B;>9;77464657799>7:473<:IHML=;(%-(5/@9C=A;=8>;?>:2:292849596999:7:6;7<8<8>7=6<7<595878:8<7<4<0:-8(:(;';&:':&:&9%?,4">,:*1&\Xy|T_TbI[DRGOSPbSlS{rSC[C?H3B7%O6"_K0prJiǀyt{qu]oHy}JXy|O\d5:D)3=$4>&<E2=D2:B+EP2Ve<g{HiDlEmEiGdGaG^GkHnKoPoPlOiMjNjPsWsVsUrSrQuRwU{YtXsWqUSJ;SJ;SJ;SJ;SJ;SJ;SJ;SJ;VM>WN?XO@YPAZQB\SD]TE]TEcZKbYJbXNcXRg\Zmacsfmwjs|n{~p}ss~p}wjtobli\fcb]a`[a^W_\U_[R^ZOa[ObZMe\Kg\Ji\Ii]Gk\El]Fm]Dm]D_gOkiTqZH{M@RIWLTIWHN:G2?*;(:.7223,17.7.7.8.8.7-6+6+7+7+7+7+8+8+8+8+=.=.8(2!2!;*>/:,6+6-:2B8I>G9;,1!OGIAE=E;H?G@C><:54678:9:7772:3>5KAE;=07)5&8)>.A2;/<2>5=8;97967687>7>7<8:9997:5:35.6/818497989:9:;>9;99<<A=C;B6@3;+=+>,<*;(:'9&8%F2>//%-(IKkolqWZOPTQVOYP[P]R^V`XMb!:O3JOf xIhrtpakN\lEWdHS\GHN@=C9;<,AB4=?2:=2<B6:C2AN4Rc?\tBgHpKoIlGjIjKgJlUmToUlPkLkHlHmFpJoIpJrNsPvUyYzZ{jo^dSWN?WN?WN?WN?WN?WN?WN?WN?XO@YPAYPA[RC\SD]TE^UF_VGd[JcZIcYMcYOf[Uj_]nbdpcjrentgpvirvirsfom`ggZacW[\\T\YRYVOWTKXTIXTI\VJ^VIb[Ic[Hf[Gh[Hi]Gj^Fm^Gm^G]eNmhTt]MRFVMVMQHQEH9C2>,:)9,7042226-7.8.8.7-8-7,7+7+7+7+8+8+8+8+9+>/=.9(2 3 :)=.;,:-4*3+;0E:PBRCQAE@@;<6;5>7=89633696879687797=9?:C9?2:,6'5&8)=-@1A4A4@7=8976756686<6<7:89879795:392:3:3;6:8:899999;:=<=?=@;?6<2;-;+<,=+<);(:&8&7%z;)8)5*;5QPce]aMMNLSOYP\R^S^U_V^VSg*Sg(^r3zOlzn`jFau@Sf9IY5FP7?H59?358/;<,AB4=?2:=2;A5:C2@M3Rc?]uCgHqLpJmHkJkLhKmTnToSmQkLjHlHmHpJnJpLsOuTxXxXxZm\bQYH]TE]TE]TE]TE]TE]TE]TE]TE[RC\SD]TE^UF_VG`WHaXIaXIe]He]Jd[Jd[Le[Qf[Uh]Yh\\i]]j^`k_ak__i]]f[YbWU`USYVMWTKTQHRNCQMBSOCWQCXRB^WG^WEaYFc[Fg\Hi^Hk`Jk`J^cOmhUy_PXN[TVQHEE>@7>3<-9*8+9.:/;17-7-7-8.8-7,8,7+7+7+7+8+8+8+9+9+@1>.9(2 3:&=,=.?07+2(3(<0F9M?QB87432052:7>;=<;<8<5:27245697<8=8;-9+6'4%5%8(<+=.D7C6B8=7966455675:6:69797795:3:3:3;4<6<6;8:999889:;<@>A=>7:17+7(;,=+=*<(;(9&8%7$u8%y6%9,E=ROVTOOHHLHSLZO^SbUaW_V]UgxB{UnzzYYp:?R$AS)AQ-?L0:C.6<.690581:;+@A3=?29<1;A59B1@M3Qb>_wEiJsNrLoJmLmNkNpVqUoSnPlKkIlHmIpJpJpLuSxXy[uWqU_NVEOx>aXIaXIaXIaXIaXIaXIaXIaXI_VG`WH`WHaXIbYJcZKd[Ld[Le]Ff^Gf^Ig_Lg^Of\Pf\Rf\Sh]Wh]Wh^Uh^Ug]Se[QdZNdZN]YNZVKVRFRNBPL@PM>RO@UO?WQAYTA[VC^WDaZGd]Jf`JgaKadSleUt]O[Qb\YXDD9:;8:6808-8):*@.C17*7*8+8+8+8*8*8)8)8)8)8)8)9)9)9)A2>.9'4 28"=)@.>/9+6*4*7+;.</>02614023488;<=?;?6<38/505477764307(6'6&7&7&9':):*A3A4A7?8:78576676:6:68768694:4;492:2:4;7:8989789<:@<B?A;;26+5'7(;*<)<)<(:&8$7#6%z@,v5#6'E;OHMILGPLPHVLZO_RbTaVaW`W~]ztsYN`8/A->3B%:F.=F3;A3:=2;<4<=79:*?@2<>19<1:@49B1?L2Pa=`xFjKtOsMqLoNoPmPpTqUpRoPmLlJnJoKqMrNtSyX|]w[mSdJ[LS|DNw?cZKcZKcZKcZKcZKcZKcZKcZKcZKcZKd[Ld[Le\Mf]Nf]Nf]Nf_Eg`Fh`IiaLiaNi`Oh_Ng^OjaRi`Qi`Qh_Nh`Mh`Mh`KiaLb_P^[LYVGTQBPM>NK<NK:NK:PM<RO>TQ>VS@YVC\YF^[H^]I`aSf^QmWJ[Rhcb`LM@C:<7974709+>)D+H-7)7)8*9+9+9*9*8)8)8)8)9)9)9)9)9)A2>.:(7"57 >&B-<*;*:,8-8.:.<0>25<3:2736464646155:39385:8:662/,(9(:(:(:(:(:(9&7&:+<-?3?7=8:68687566666748493:3;3:2;2=5=9=:><=;==A<B<A:<37-5(7(;);)<)=(;(9&8%7$6#}C/s4"y4$G:RGNFNEWNULXL[N\N^R`UaWbYd|j]kJDS42@&$2-:&0;*5=.9?3<?6=>6:;3::29:*>?1;=08;09?38A0>K1Pa=ayGkLuPtNrMqPqRoRrSrSrQpOmKmIpLrOtQvSxY{^z_qVdJY?]NVGQzBe\Me\Me\Me\Me\Me\Me\Me\Me\Mf]Nf]Nf]Ng^Og^Oh_Ph_Pg`Fh`IiaJjbMjbMjbOjbOjbOjbOiaNh`Kh`Ih`IhaGibHjcGe`Mb]J^XHXRBSM=MJ9KH7IH6KJ8LK9LM;NO=PQ?QTASVESVEYYM]WKcQEzXNhaeaUUOR=C8>6762:.@+E*I*7(7(8)9*9*9*9*8)8)9)9)9)9)9)9):)@4=/<+:$76<#B*C.@/;,7*2(4+:2@81<2<5=8>:>;>:=9<485:8<;>;<861--'<+=,>*>*=)<(:'8%6%7);.=3<5;7;8;77575758494;4;4=4>5?7A:A;A>A?????B:@8<38-5(5'8(<*;*<)<(:&9'7%6$5#y<)r3!}:*OAYLRGOEVJZN[M[M[O\Q^T`Ya[s}Xy`r|ZU`B9F,/;'0;+1;03=44;35<4:?8?B9?A6<<277+89)>?1:</7:/8>27@/=J0O`<ayGkLuPuOsNqPrSpSrOrPqOoMnJpLsOuRyX{Z|]x]qWgO]EV@`PYISzCg^Og^Og^Og^Og^Og^Og^Og^Og^Og^Og^Oh_Ph_Ph_Ph_Pi`QjbOjbOjbOjbOiaNiaNiaNiaNiaLh`Kh`Ih`IhaGhaEhaEhaEf_Le^Kb[H\WDWR?PM:LI6IH6GH6GH8GJ9GK:HL;IM>HO?HO?PPDVRGYOChREYMULRLXWGJ<B7954:1@-D*D$6'7(8):*:*:*:*:*9)9)9):):):):):)?3</=,<)9 6: B)C-A/=/6)/%/'6.=60;5>:A?CBCAC@A>?1256::<;;7734.3+>+>+>+?,>+>(<';'7$7'8+8.8.92<7?;85858494:4;4=4>4A7C9C<B;A=?<=;<9>3:/8+6(7'8):);(=)=*<):'9&7&6%~5$v4$x5%B2UEXKQCPDZLZM[N]O\Q\R\U[V\W`hCX_=JS4>G,6?*2=-4>35?74=88>:=B<CF?EG<CC7@>/;9*78(=>0:</7:/8>26?.=J0N_;`xFkLuPuOsNrQrSpSqMrNqMpLoKrNuRyX`~az]qUfL_G[E\HbRYISzCh_Ph_Ph_Ph_Ph_Ph_Ph_Ph_Pg^Oh_Ph_Ph_Ph_Ph_Pi`Qi`QmcWlbVjaRi`Qh_Pg^Og^Mh_NiaNiaLiaLiaJh`IhaGhaGhaGh`Kg_Je_Ib[H\WCUR?PM:ML:EF4DG6DH7BI9BI9BJ;BJ;BJ;JJ@QQERPAUN<bM:qF6I>YSQOCE8:55:3>/>)<$8'8'9(;*;*;*;*;*:):):):):):):):)=2:.<,>+9#59@':$<)?0;18.7/<5A;;B>FBGCE@?;7501.0,51:5<6:29.9,9,>+>+?,@-@-A+>*=*<(:(7(5)4*80?8D>:5:5;4;4<4=4?4@5C9D:C;A9?:;685739-7*5'6':)<*:)9&=*=+=*<)~:'|7'{6&{6&y1#8*G8REPBK?SE_SXKZN\R]T\V[VYTXSV^7EM(6@8A&>G2<D53=2-7/1737>7@E>GJ?GI;BC1?>);;#78(=>09;.69.8>26?.<I/N_;`xFjKuPtNsNrQrSpSqJqLpLoKoLrOwV{\edx^jP]EYC^HeOcUZLSzEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qj_Yj_Yj`Wj`Wj`Vj`Vj`TjaRjaPjaPjbOjbOjbOjbMjbMjbMg_Jg_Jf^Ie_Ib]I\WCSP=ML:HI7EH7AE6>E5>F7?G8=H8<G7HJ=HL>AE4HK6YS;_F0K9j]f`SSDE@@?==5=0>/3$5&6'7(7(8);,=.<-<-<-<-;,;,;,;,3,7.;-;)8"78:"B-<+7)4*6/<7C?HCBGDHCC:661808.5+:/9.8.8-9,:+<+>-=*=*>+?,@-A.B-@-<*:(7(6)6+8-;1=4:4<6?6@7A7A6@4@5G=E;A6;26.3-1,1+;-:,:+:*:);)<+=+~:'|9(|9({:({:(z9'x6&w4$z, A4NCMAL>REVHRG\R\RUMTLZUXSWR`^R[0IQ(AK&BK,>H/7@-2=-4>34;3HPEX^RW[LLO<DF.AA'==!:;+>?1;=0:=29?34=,;H.Pa=bzHlMuPsMqLpOrSqTpJqKrLrNsPvU{\bfx^iO_G]G`JfOhRdU[LTyEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qj^^j_]j_]j_[j_Yj`Wj`Vj`Vj`TjaRjaRjaRjaRjaRjaRjaRj_Kh`Kg_Jg_Jd]J^YEUR?ON<IJ8EH7AE6>E5?E7>F7>F7=E6BF8>E5=F1DN5HK0PB'yS<ubdX_YUTFG>>@=>982:+<-=.<.;-:,9+9+:,:,:,:,:,:,:,:,?9A:A7=/6#2235#7(;0A8E?IDJFJGBCEDC@;59/>1A1?.@1@0>0?/?-?.A.B.;*;*<+=,?+?+?,>+@.=-:,9*8+8-:0:190;2>5A7C7D7D9E8B6A4=1:08-5.5,5.=,=,;,;+:*;*<,=,~;*|;)y:)y:)x9(w8'u6't5&1)C9NCK?J>PDTIRGSJWQUOUR\XWTSO\XT]0Zc8_j@[eBIT66C)4@*<G6MXGYbQ_fTW\FJN5BE*?@!<=9:*=>0:</9<1:@45>-;H.Pa=c{IlMuPtNqLqPrSqTqKpLpJqMtQxW|_c{aoUcJ]FaJeNeNcLdU[LTyEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`Qj^`j^`j^^j_]j_[j_Yj`Wj`Vj`Vj`Tj`Tj`Tj`Tj`Vj`Vj`VlaMk`LiaLiaNf_La\I[VCTQ@ML:HI9DG6AE6AE6?E7>D6=C5=F57@-?H3EM5AA%QA']Eu`WHbZebRSEFFHBD799+:,:,:,:,8+6)6)8+7+7+7+7+8,8,7,3/5/5-3(0"01 4$A2C7G?KFLGJFFBC?CCDA@:;1=/C1F4G3E3E2C2B0B0B/{B.xD.8*9+:);*<+<+=,<*?.=-;+9*8+9-:/;/7.90;0>3?3@4@3A4:,:,9+7+7+7,8.91=-<,<+;,:+;+<+<,};+z;*z;,w9*v8)u7(t6's5&91F<MBJ?H<ODSHQINGSOSOVS]XYUZTf_wS~\`lxPJX46D#=J.MZ@eqYeoW\fMNW<DJ.?D&=@!:=89);<.8:-9<1;A56?.<I/Pa=c{ImNvQtNrMqPrSpSsMpLnLpOuV{\}`|boUfM\E\EdMhQeN_GcUZLSxEi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QjaRjaRjaRjaRjaRjaRjaRjaRk_ak__k__k`^k`\kaXkaWkaWkaUkaUkaUkaWkaWkaWkaXkaXncQmbPjbOjbOhaNe^L_ZGYVERO>MK<GH8DF8CE7AE6@D5>B3;I27C-EJ3IG0K<%mN9dO`NA5SLc_^^RUJMDH>C;/9-7+7+9-:/;0;0>4>4>4>4?5?5?5?5?=B>D>F=G<I>N@PDSJOGLGIEFCC?A=@<FDC??7<1>.D2H3J6G4F3D3C1B0zA.wC.uB/8+9+9+:,:,;-;+;+:+:)8)8*9,<-=/>09/8.9/:.:.:,9+8*7)7*7(6*7+8-9/;0=.<-;,9*:+~9*}:*};-|:,z;,y;,w9,s8*q6(q7)q7)B8G=K?H<I<ODUJTLPLSPQORO\X_Xh^znkfuVYh=CR)?O(P`<crQetS\iKNY;CL/?E)>B'=A&;>#78(:;-79,9<1;A57@/<I/O`<ayGlMvQuOsNrQrSpSqMoKoMsRz]|az^u[bJ^G[D_HgMjPfL`FbTY~KRwDi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QjaRjaRjaRjaRjaRjaRjaRjaRk`^k`^k`\k`ZkaXkaWkaUkbSkbSkbSkbSkaUkaWkaWkaXkaXocSnbRmaQkbQkbQhaOd]M`ZJVSBRO>MK<IG8EF6DE5BC3@A19K1>H/JH1Q?+e>-ZL`S>64+@9XUigdeRUINKQJ@F<@6>4@6D:G=G>JAJAJBJBKCJCKDKDRTSTTPSMSLSLTNUNLHHFEBB@B@B@EBEBJHD@>7>2A2C1F3I6F3D3C3@0@1}?0y@/x@19.9.:.:.;/;-;-;-9*9*9+9,:+;-<.=/;/:/9-:.9,8*8*8*8)8)8(8)9*:,:-;-;-:,9+~9*}8)}7+|8+{9+z8*y9-x:-t9+q5*o5)q7+r:-G;H<I=I;K=RFWMWOQMTQRPVQ`YbWh[whivKZi>JY.AR&IZ0Wi?dvLj|TXjDL\8?M,:D)<D,>C-=@-:=*89):;-68+8;0<B67@/;H.L]9^vDiJtOtNsNrQsTqTmJmLpPxY|_z`rXiQYC\E`IeKgMgKfJdHcSY{IRtBi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QkbSkbSkbSkbSkbSkbSkbSkbSla[lbYlbYlbXlcTlcRldQldQldQldQlcRlcTlbVlbXlbXlbYocSnbRmaQlcTlcTkbSg`Pd]M]WGYSCSM=MJ9KH7HE6DB3B@16J.>H-NC-b=-D:VPMJ++:9=;TPpnwvehY^]cVOOHG@C<D=G@GAGAHCIDIDIEJFJFKGKGGJGIGHGGHDHDGDEBBAAB@CBBBBB@A>A=JIB@<6>3@3A2B0D3A2@2>1=1<2<1=1}=1:3;3;1;1<1<1=/=/=/</=-;,;,9+9+8):/9.9/;/;.=.=/>.9)9*:*;+;,;+;,;+:,9+7)~6*{5){5)z6)z6+x6*x8,w9.s7,o5)o5)r:-u=0L>K>J<M=QCVHXMWNMIRQTR[We\y_PcXFb]IBP,?M)?O(K\2_qGk~QcyKVk@M_7@R,6E&7D*=F1=D4:=27:19:*:;-68+8;0<B67@/9F,IZ6Zr@eFrMsMrMrQsTqTlKoOsUx\z_s[iQ`JXB^GdMgMfJeIgGhHaQXzHQsAi`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QkbSkbSkbSkbSkbSkbSkbSkbSlbXlbVlcTlcRldQldOldMldMldMldMldOldQlcRlcTlbVlbXocUmaSkbSlcTmdUlcTi`Qf_Ob[K^WGWQARL<OI9LF6IC3F@02K+>G*SA+{E9NLEH5<19@E?@JIb`rpopbeZ^RJLDD=B;D=E>C<?9C=B=C>C?C?D@EAEA?D@DDFFHIHJIIIFHACADAEACAA@>>:=8EG=<73;4@4?1>0A1=/<0;1928193:4;4:4:4<3<3<3}=3}=3|<0{=0{=0{=.{<-z;,y:+z8*z8*:0:.:-:.:.;.<.=-9):):*;*;+;,<+}<*8,8,~6*}5)|4(z4(z4*y5*u3'v6,v8-r6+n4(n5*s:/v@4PBN?N=R@VFXIUJRINIRPSO\VfZl\LML7BL3@O.KZ9WgC`rJezOdzLVl=G]/AV+7I#0A!5C*=F5<D98=7796:;+;<.68+9<1=C77@/7D*FW3Um;a}BoJqKrMrQtUrUnNqQuWv\sYjR`J[E^G`IbKeKfJhHfEeD`PWyGPr@i`Qi`Qi`Qi`Qi`Qi`Qi`Qi`QkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcRldQldOldMleKleIleIleKldMldOlcRlcTlbVlbVnbTmaSkbSkbSmdUlcTjaRh_Pd]M`YIZSCUN>QJ:MG7IC3GA13M*>G*[B.PGVV7?'3BN:C9>;:HG][gf[]ILJDF@C=C>GBGBB>=9C?B?C@DADBECECFD>C?DBEEGGGFFBC=AAD>C;A<>>>A?D@FA@C7830:4?4>1=/?2;.9.8061717384:5:3:3:3~;3|<3|<2{=2{=2u9.v;-w<.w<.x=-x=-y;,y;,{;1};/~8,7*6)5'6(5&7(8(:);)<+<,~=+{<*8,7+~6*|4(|4({2)y3)y5*t1(u5+v8-r6+n4)n5*t;0xB6TEQ@P>UBYHYISGNGSNRPPKVObUeZHFK4;K0IX;[jKgxVewQYnCSi;Me5I`28M"-B*;2@):E7;B;8<;7;<<=-<=/79,9<1=C77@/6C)DU1Rj8_{@mHpJqLrQtUrUqQtVuYsYmSdN\HZDdNaJ`HcIfJiIeDa>`PWyGPr@i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTo\Nq_QtdUrdWnbTj`Th`ShbTgaSebQa^K[VBVQ;TN6NH.GA'RD)N=#cI2iVzmng[WPQBE@E@GBFDGEIGIGIBEBEBDEEDBC;D:H;F7H9H:G?EBBD?F=EBDBDBDDEDEEDEDEDDAC@B?@>?=?=?=@>E??8:280:0>4@3?2A4|@5}?4<3:3837372<-<-<-;,;-:,:,:,9-9-9-~:/~:/~:/~:/~:/~80~80}90}90}90}90|90|90|90|90z:0y9/y9/x8.w9.w9.w8/w8/v7.t8.s7-r6,q5+p6+l2'q7,m4)l3(o6+m4)q8-H=ULTLQKPJNJNLNMPLSMUK\NdOkaFTW8JX5N_;gT`zMWpFTkARg@O`<IX7DQ39C*5=&49%7:)=>0CA4B@4@<12:/2:/4:.5;-9=.<?.>A,>D*T^<bqHqTtVtUrSsSrQv^ggqYcK_G_G^F`HbJdLfNeMcK`H^F_OTvDKm;i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTsaSr`RrbUqcVrfZpfZmeZjdXgdUkhYmjYlgThcOd^H[U=RL4PJ0F?%P@)kP;WGNBD=C?VTSRPQNOLMLKKHJHRTFG<<;:A@E?B9>4E9F9G=G>GDCEAE?GCDCDCDDEDEFDFDFDEAC@B?A>A=A=@=A>FAB<=6:090;/=0=0A4|@5}?4<3:3917172<-<-;,;,;-:,:,:,9-9-9-~:/~:/~:/~:/~:/}90}90}90}90}90}90|90|90|90z:0z:0y9/y9/x:/w9.w9.w8/w8/t8.s7-r6,r6,p6+p6+k1&q7,m4)l3(o6+l3(p7,~H<SKTJQJPJPLOMPNROOGSH[K{ePsiPhkLdrOgxT\uKXoEPf?Ka:K_:K\:GV7CP4<F-8@)6;'7:)<=/?@2@>2><03;03;05;/6<09=/<?.>A,>D*Q[9^mDmPpRrSqRsSsRxa|exakT`I]F]F\E`IaJcLeNdMbK`I^G]MRtBIk9i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTtbTo_Pm]Pm_ToeYog\keYhbVfbVpl`{xi~{jzgzuapiVf`JPV<DF.A?(MB.S@/U8(^6*m=3p7.x71:3@9HBOHWP\R[WROFEA?CBFCD@?:A9C:E>G@GCFFEFDGCDCDCDCDDEECECECDBE@D?C>C=C=B=B=F@E=C:>5:/8-9,<-A2~@3}?2=1:1918180<-;,;,;,:,:,:,:.9-9-9-~:/~:/~:/~:/~:/}90}90}90}90|90{8/{8/{8/{;1{;1z:0y;0x:/x:/x:/x:/t8.t8.s7-s7-r6,q5+o5*o5*k1&o6+m4)k2'n5*i3'm7+}G;QIPIQJQLRMRNTPUPVO[P^OtbNoiQnrWjwYfwWPf@K_:EY6BV3EV6GV7FU8ER8?I1<D-9>*7;*:<.<>0<=/:;-5<45<46<26<09=/<>0=@-=C)MV7Zi@h|KlNpOqRuStSzcw`nWcL\E\E\EZC_HaJbKdMcLaJ_H]F[}KPr@Gi7i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTtdWqaTm_Rk_SkaWlcZle[jf]jf]wuiy|rygZfNLV>AI2CF1ED0D?,I=-TD5M:+O8*R6*T7)X8+];/a?3eA5KASLUQNKEDABCCEF?>@=B>D@EAFDEDEDCDCDDDDDDDEDEBGCFBE?E>E>D=D=E=E=C<E?E>@8;/8,9+;.@2@1~?0=/;/:/9/90;,;,;-:,:,:,9+9-9-9-~:/~:/~:/~:/~:/~:/}90|90|90{8/{8/{8/y9/x8.{;1y;0y;0y;0x:/x:/v:/v:/s7-s7-s7-r6,p6+o5*o5*n4)j1&o6+l3(h2&k5)h2&l6*|F:OGPHQIRMSNUPWPYQ]RaUy_PiZGd_IciOZgKN]@EU8AQ4=M0<K.?M3CQ7FR:GS;BK6>G2:A/7>,9=,9=.8<-7;,6=66=66;46<29<1;=/<?,<A*JS4Ve>dxGjLpOsTwUwT{dr[eN\EZC\E\EZC_H`IaJbKaJ`I^G]FY{INp>Ef7i`Qi`Qi`QjaRjaRkbSkbSkbSjaRjaRjaRjaRjaRjaRjaRjaRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTseXugZsg[mcYjaXle]snhzwp~wv~i`hSLSADK9AJ7>G4>G4BI7GN<FJ9CF5?@0=;,<:+<9*<9*U5(lD8PHPLHIEIDIAE>B?@AAC@EAEAEAEADFDFDFDDEDEDEDEAFBFAF>E=F=F=F=G>@9B;D=B9>3:-;.=/?0?/~?0=/<-:-:-:.;-;-:,:,:,9+9-9-9-~:/~:/~:/~:/}:1}:1}:1|90|90|90{8/y9/x8.x8.v8-y;0y;0x:/v:/v:/u9.u9.u9.s7/r6.q6.p5-o4,n3+m4+m4+j1(o6-j4*h2(j4*g1'k5+zF;MGNHPJSLUOWPZPZQ{YMv\OkZJ]UBYXDY^HOYA>L3;G18D.5A+5A+8D.=I3AM7EN;BK8?H5<E29B/7@/7>.5<,4;+5;75<56;56;48;2:</;>-;@)GP1Ra:buGiKqPuVyWxUzcnW`IZ}C[~D^G^G]F`IaJbKbKaJ`I_H^GW{KLp@Bf6haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTmaUndXpf\lcZkd\rmg|ľtfcTPQAEI8=F38E18G45F35F44E36D58D6;E:?G<@H=<6(L</b@7EAOOW[OVBIDJDFDFEBEBE@D?C?DFDFDFDFDCDCDCECEAFAF@F=F<F<G=G==8@9B:C9A7>0=/=.>/?/>.=-<-;,;,;-:,:,:,:,9+9-9-~8,~:/~:/~:/~:/}:1}:1}:1}:1z:1z:1y90y90x8/v7.v7.v7.u9/u9/u9/s9.s9.s9.r8-r8-q6.q6.p5-o4,n3+m4+l3*l3*h2(l6,i3)f2'h4)e1&i5*xD9KEMFPJTLVOXNYO|\Os\Nk[L_XFUTBPS@JQ?@I64@,3<+2;*09(09(2;*5>-9B1<E4?H7=H7<G6:E48C25A-3?+1=)3973954954937:19;0;>-;@*CL/O^7_rDiMrSwXyWvUs\fOZ}CX{A\E]F]F^G`I`I`I`I`I_H^G]FVzLJn@Ae7haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcTiaVjbWkdZmf^upjҺzym__YIKL:>F19E1<K8;J79G68D68@57<57947836A3>>2J91`94HH\__dVZOSMOLKJJHEFBDAA?DFDFDFCECEBBCBCBDCD@E?F?F<F<G=H=>8?:B9C:C8A4<-9)>->.>-=,=,<,;,<-:,:,:,9+9-9-~8,}9.~:/~:/~:/}:1}:1}:1}:1}:1y:1y:1x90x90w8/t8.s7-s7-s9.s9.r8-r8-q8-p7,p7,p7,p5-o6-n5,n5,m4+l3*i3)i3)g1'k7,h4)e1&h4)d0%f4)uC8JELHPJTLWNYOx[Mp]Nj^N]WGPQAKN=CJ:9B12:+08)36-17-06,/5+/5)17+2:-4<-9D4;F6=H7<I7:G56C/3@,1>*0640641622716929;0:<.:?)?H+KY5]pChLsTwYwWrQiT^IUx@WzB[~F[~F[~F]H_J_J_J_J^I^I]H]HUvKJk@@a6haQhaQhaQibRibRjcSjcSjcSibRibRibRibRibRibRibRibRkbSkbSkbSkbSkbSkbSkbSkbSlcTlcTlcTlcTlcTlcTlcTlcToh^ng_lh_tqjũsbaZGML7CH2AI4AH6BF7BD7C@9D<9C98C772?5;@9@93H/+c76QRgimm[\YWUSQNKKGFBB@ACGDFDFBEBEADBBBBDCCBC?C>E>E>F<G=@;@9@9C9D:B5;-5&=-=.>-=,=,<,<*=+:,:,:.9-9-~8,}9.}9.~:/~:/}:1}:1}:1}:1}:1{;2w;1w;1v:0u9/t8.s9.r8-q7,r8-q8-p7,p7,n8,m7+m7+m7+o6-o6-n5,m4+j4*j4*i3)h4)f2'k7,h4)c1&e3(b0%e3(uC8JGNIQJTMXOzZMq[Mh\LXUDHK:=D4=E69A208+/7*5=056157257247005.06,08-19,6A3:E5=J9>K9;J77F12A,0?*.42.420511605818:/:<.:?+<E*IW4[nAgMrUvZuWoPbMX{CSv>WzB[~FY|DY|D\G_J_J^I^I^I]H]H]HSsJHh?>^5icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUfc\gd]vsnȷɴicbFGG-EG/DF0GD3IC5H;3F42G34M797@;;@:@;8G85cGFkjŔ譩ҋtn]XSNNNIKEICGFHHKCF:>>@FIDG:;@@@@A@B>C>B<B;B;A<@9?8A7B8@4;.8*>.>/?.>-=,<+=*=*9-9-9-~8,~8,|8-|8-|8-}9.|90|90|90z:1z:1z:1z:1x=5w<4v;3u:2t91r7/p7.p7.o6-m7-m7-m7-m7-l8-l8-l8-i2+m6/p92o81k4-g2*g2*h3+e0(i7.d2)^,#`0&_/%b2(p@6LJOKQJQJ}YMv_QfYIRO>CF5=F58C35@02=/3;04:04:077577566446135016/05..6+.9+2=/6C29H5:I68G42D./A+,20,2.-2..3-36/780:</:?+6>&DR1YkChRu[w_rWjN\}HXyDTu@Tu@WxCZ{F[|GZ{F^JbNbN^J\}H_K`L^JTrNFd@:X4icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUmdUed_onjͱcgkJMP1II/EC,HA/J>2L93M85Q99;;9BA?MHE\RQyjg̳ǿ괪̃|c\VTPSFM=DEEEEGHIKEG<><>@C>???@@A@B>B=A<A;@:@;?8A:C9A6;/9+=.>/>.>-=,<+=,<,9-9-9-~8,}9.|8-|8-|8-|90|90|90z:1z:1{;2{;2{;2v=4u<3t;2s:1r90p7.m7-m7-m7-l8-l8-l8-l8-j8-j8-j8-l5.n70n91n91l7/i4,g2*e3*c1(e3*_/%^.$b2(^.$`0&n?5IEQLWRWOrVKdRDQJ:>?/:A16A14A02>02<14<15;17:388677577557446116005./7,.8-1<.4A07E49H58G44E22D.062.40.3--2,14-45-8:-9=,7?'DQ3YkEhSv`wbpYfNZzHWwETtBTtBVvDYyGYyGYyG[{I_M_M\|J[{I^~L^~L\|JTmOF_A9R4icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUmdUmdUneVneVneVddby{xشĝj`hCRW7DG,EC.KD4MC9N?8L=8C:;SJKi`axv画ecACBINVVRLIDABAFEEFCDBD=?>>??@?A@A=B=A<?:@:A:D<D<B7<29.=0=0>/>.=-<+=,=,9-9-9-}9.}9.|8-|8-{8/}:1}:1{;2{;2{;2{;2{;2{;2t;2s:1p:0o9/n8.m7-k7,k7,l8-l8-j8-j8-j8-j8-i9-i9-n91m80m80m80m80i7.f4+c1(c3)a1']-#_0&c4*\-#_0&sD:OKUPXQqSK^J?OC7?<-37(2:+/<+0<.2=/4<15;17:37:388688668557257227016/08-.8-0;-2?.6C27E48G48G48G46=53:2/4-,1*.1(13(57*6:)6>'DQ5[lHkZyfwflX^KWwEUuCRr@Rr@TtBVvDWwEWwEXxF[{I]}K[{I[{I]}K\|JXxFPfOAW@3I2icSicSicSicSicSicSicSicSicSicSicSicSicSicSicSicSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUneVneVneVneVofWgkl۲™}cdnKLS4EI0HJ5KI:GE9D@7QEEk__莎bd>CPITMOJF@FBMJJI??>>>??>@?A?B?B?C?>8?:C=E?E>B9=5;2<1=0=1=0=-~<,=-=-~:/~:/~:/}9.}9.|8-{8/{8/~;2|<3|<3{;2{;2z;4z;4z;4p:0o9/o9/m9.l8-k7,j6+h6+i7,i7,h8,h8,h8,h8,h8,h8,o:4j81h6/i70j81j81e4-a0)e4-b1*].&a2*b3+Y*"_3*zNE~]XvWRiNGWC:J<3@:.:;-8<.08)/:,1<.2=/5=25;169078079468368349338138119.19..9+/:,1<.2?.5B18E4:I6;J7;C87?428.-3)-0%/1&24'48)4<'ER8_pPrd}nwifXT}EUrBTqASp@Sp@TqAUrBVsCVsCWtD[xH]zJ\yI^{K_|L\yIVsCK\J<M;.?-gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUmdUneVneVofWofWpgXmruҭ|bX_@GL5DL7DK;AG9>D8f\Z|z즤ifK=QDYN[QQHD=A<D@@=?>@?B>C?C?C?C?>9@<D@E@D<@9>5<4<3=2=1=0=/~<.=/</~:/~:/~:/}9.}9.{8/{8/{8/~;2|<3|<3{;2z;4y:3y:3y:3m80m80l7/l7/k6.h6-h6-h6-h8.h8.h8.h8.g8.g8.g8.g8.k92h6/f4-g5.i70h70e4-b1*b3+b3+_0(_0(]1(V*!b6-SJn[U`OHN?8A7.=6,;9-9;.7=12:-3;.4</6<06<07:167/56.49249238139/39/2:/19.19,.9+.9+/:,0;+2?.6C29F5;H7=E6:B35;-06(/3%/1$13&15&29'GS;dtWwm~rqg\QIq?Qn>Qn>Qn>Qn>Qn>Qn>Sp@Sp@WtD[xH]zJ]zJ_|L_|LZwGQn>ESF6D7(6)gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVneVofWpgXpgXpgXinrz׹ĥregOMP;EL:EM>EODGSG~zqƽߑ}fSK:UFWKF;@8KEC>C?B?C@C>D>D>C=@<C=E?D?A;=8;5<4<3=4=3=2=1~<0=1=/~:/~:/~:/}9.|90{8/{8/{8/|<3{;2{;2y:3y:3x92w81w81m80l7/j8/j8/i7.i7.g7-g7-g7-g7-f7-f7-f7-f7-f7-d8-i70h6/g5.f5.g6/h70g6/e6.a2*e6.^2)\0'`4+a5,i=4|PGQJBE>6:6-85,99/8:/47,36+4:.5;/5;/69.69.68-57,46+19,19,19,19,19,19,19,19,08+.9+.9+/:*0;+3>.6A17B2<E4:C28?/5<,37)24'13%04%07%HT>gw]umvnf_RwKAh;Mj:Nk;Pm=Pm=Nk;Nk;Ol<Qn>VsCZwG]zJ^{K_|L_|LVsCLi9=H@/:2#.&gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVneVofWpgXqhYqhYcjpmtzƯ}vn[ZWFOQCQWKYcZbmeq[WDSCQBMAJAG@E?E@E@E>D=C<C<C?D@EAC==9;5;5<6<5<6=5=4<3~<0=1<1~:/~:/~:/}9.|90{8/{8/y90{;2{;2z:1x92w81v70v70u6/k90j8/j8/j8/j8/h8.h8.h8.g7-f7-f7-f7-d8-d8-d8-d8-h6/h70i81i81h70i81j;3l=5g80k<4b6-a5,oC:xLCtI@uJA:=647036/7:18;247.14+25,58-58-57,46+46+46+46+46)/7(08)08)08)08)08)08+08+19,08+08+/7*08+19,3;.4</9B/:C0;B0:A19=.68*24&/3$29'IU?eu[mghbWyTInE>e9Jg9Li;Nk=Nk=Li;Li;Mj<Ol>UrDYvH[xJ]zL^{M\yKQn@Eb47@;+4/!*%gdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSgdSkbSkbSkbSlcTlcTmdUmdUmdUmdUmdUneVofWpgXpgXqhYriZhowmt|ʹƯsce]P[YM_bYovo|Ȱ}gO=Q@RDC8IAH@F@F@E=D<C;C;D@E@E@A=;77493<6<5<6=5=4<3~;2<3=1~:/~:/~:/}9.|90{8/{8/y90z:1z:1y90w81v70u6/u6/t5.k90k90j8/j8/j8/i9/i9/h8.f7-f7-f7-d8-d8-d8-d8-d8-f5.i81l;4k:3j92j92m>6qB:n?7pD;g;2g;2SJaXTKpE<6=52913:27<5492/5+25,9<345-35*24)13(13(35(46)57*,7',7'-8(-8(-8(-8(-8(/7(19*08)08+/7*/7*/7*08+08+7@+9B-=D2=D2=A29;-35'/3$3:*JVBcr[f}a\wVLnICgA=c:He7Kh:Nk=Nk=Kh:Jg9Li;Nk=TqCWtFZwI[xJ]zLZwINk=A^05;9*0.!'%heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVhdYkd\kd\md]meZmfVg`MjeOnlWnl]ff^eeeqqyֵymvW\fK`lTq~lЪa\D=MEKBC:A7D:H>JAI>G>J2K4L5K4H2F2E3E5D5C6@4>3;29/7/6-~:1~:1}90|8/{7.z7.y6-x5,w7-w7-x8.x8.v8-u7,s5*q3(h91h91h91g80h70g6/g6/g6/f5.h6/i70j81i70h6/f4-g2,k1-k4/n70m80k9.j:.i>.iB1dC2gJ8aJ8raOyn\|jqOL;4:04:04:039/39/39/28.28.17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4.05//4./4..3-.3-/4./4.05/0;32=55A77C98D86B64@22?.3@.DQ=WeN\jSSaHHV=DR8FT:Ic>Ke@Ke@Ke>Je<Je<Lg>OjAUpGYtK\vO]wR]wTWpPHaC8Q3).2&+/$)-heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVhdYkd\kd\md]meZmfVjcPlgQmkVlj[gg_lll~~ЯvkrSYaI_kUto}uJ@K@J<K>J>D9=2?6D;H3J7M9J7G5C4D6F7C7C8A7>5<4:19181}:2}:2|91z:1y90x8/w7.v7.u6-v7.t8.t8.t8.r6,p4*o3)i81i81i81h70h70h70g6/g6/e3,e3,g5.h6/j81j81j81k92k60l71m80l:1k;/l>1j@0iD2hG6kP=gR?ufSvdsrML:4:039/39/39/28.28.28.17-17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4.05//4..3-.3-.3-.3-/4.05/-80/:21=34@66B66B66B45B16C1CP<P]IR`IIW>AO6BP7FT:Ic@Jd?Ke@Ke>Ic<Hc:Id;Je<SnEXrK\vQ]wT[tTTmOC\>3L/).2',0$)-heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVhdYkd\kd\md]meZmfVmhTmhRmkVjk[jkcvxwۿʫyuy^kpZt{iٞL=Q@K;>1G9XMTJ?6D6H9J=I=B7?5A7E=A9A9@:>8~>5<4<4;4x<2x<2w;1w;1v:0u9/t:/t:/s9.r9.r9.r9.q8-n8,l6*k5)j81j81j81j81i70i70i70h6/g5.g5.g5.g6/h70i81k:3k:3l;4k:3i:0j;1k?2lB4iD2fE2fI7lVAjYEviVl{mEF439/28.28.28.17-17-17-06,17-17-17-06,06,/5+/5+/5+/4./4./4./4./4./4./4./4./4./4..3--2,-2,.3-/4./4.*5-+6.-9//;12>24@46B47D38E3?L:ER>CQ:;I28F->L3ES:H`>Jb@LdBKc?Ia=G`9F_8G`9RkDXpL]uS^vVZqTPgK=T8,C)).2',0%*.heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVjcYkd\kd\md]meZmfVniUljSlkVlm]pqiؼǫ}ſınQ>P=XHL?D7G<>4D;H?F>?9;6=8A>?;@<@<}@;z?9y@9x?8v?8v=4v=4v=4u<3s=3r<2r<2q;1o;0o;0o;0l:/k9.j8-j8-i7,n72n72m61l71l71k60i70i70l:3j92h70g6/f7/f7/h91h91j?6f>4e=1f>2hC3iE5gF3cG2cJ6hV@k\GskVnzor_9>*28.28.17-17-17-06,06,06,17-17-17-06,06,/5+/5+/5+.3-.3-.3-.3-.3-.3-.3-.3-.3-.3--2,-2,-2,-2,.3-.3-)4,)4,*6,+7-.:01=14@25A36C2:G5<I58E12@)2@)8F/?M4DX<G\=K`ALa@K`?I_;H^:H^:SiEZoN`uV`tXZnSNbI9M4(;%',/%*-$),heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVjcYkd\kd\md]meZmfVlgSkiRnmXop`svmؿʱ½ÝcPK8L:O@M>=7A;D?C?<;989:====>>@?|A=xA<sB=rC=pC=s>6s>6s>6r=5p>5p>5p>5n>4n>4m=3l<2j;1j;1i:0i:0i:0p62p62p62o51m61m61k60i70l;4k:3h91e90e90e90e:1f;2dB6cA5cC4dD5fG5eH6cH3_I2^L6eV?jbKrmWnr[`L3;&28.28.17-17-17-06,06,06,17-17-17-06,06,/5+/5+/5+.3-.3-.3-.3-.3-.3-.3-.3--2,-2,,1+,1+,1+,1+-2,-2,,6.+5-*4,*4++5,.8-0:/2=/2=-5@06A05A-1=)1=)5A+9E/=O5AS9FY=I\@J]?J]=K^>L_?TgG\oQcvZbtZYkSK]G6G4$5"&+.$),"'*heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTheVjcYkd\lc\md]meZlfVlgSljSlnXorasvmθͺƶø̧lXZGVCM;A8B<D>D??>;;99:;<<>??=}@=wB<pC=mE=lF=q?8q?8q?8q?8p?8o>7o>7n?7o@8n?7m>6i=4h<3h<3h<3i=4r73q62q62p62o51m61l71j81h70g80e90e:1d<2f>4f@5gA6]C4aG8cL:dM;cM8`K6]K3]M4]Q9`Y?miPss[mt|eFO:2>(39/28.28.28.17-17-17-06,17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,-2,,1++0*+0*+0*+0*,1+-2,,6.,6.*4,*4+*4++5*-7,.9+-8*0;+4?/5@/4?.3>-3?+4@,7F/;J3@P6DT:GW<JZ?M]@O_BUeJ^nSdtZbqZXgRIXE4B1$2!&+.$),"'*heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheTjdVjcYkd\lc\md]meZlfVljUllTkmWjn]lrhy}оλvaP:^HI>H=H>G@F@C@=:97<;=;>;A<wB:sD<nF<lH<q?8q?8q?8q?8p?8p?8p?8p?8qB:pA9n?7j>5i=4j>5j>5k?6s63r73q62p62n72l71j81i81d8/d90c;1d>3d@4cA5cA5bB5VG4^O<gVBhWCbS<^O8[O5\R7]V<]Y>mmSsw^zjcmU2>(5C,4:039/39/39/28.28.28.17-17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,,1+,1++0**/)*/)+0*,1+,1++5-+5-*4,*4,+5,+5,,6+-7,,7)/:,2=/6A17B27B25@/4?.2?+5B.:G3>L5AO6ES:JX?M[BTbI]kTcqZ_lXUbPERA2>0#/#(..&,,$**heVheVheVheVheVheVheVheVheVheVheVheVheVheVheVheVjdTjdVjcYkd\lc\md]lfZlfVomXmmUimVgkZembr{x׭sYSAQ?N>O?OBJ@C:<4<7>8?6@7{B7tD6qE8nG8s>:s>:s>:q>:q>:q>:q>:p?:sB=rA<p?:m>8l=7l=7m>8n?9r73r73q73n72m82j81i81f:1f;2d>3d@4bB5`C5]A3\@2[?1QI4[S>f^Gg_H`Y?ZS9ZS7\W:ZV;WW;knSrx^u}eUaI%37E.4:04:04:039/39/39/28.28.17-17-17-06,06,/5+/5+/5+-2,-2,-2,-2,-2,-2,-2,-2,,1++0*+0**/)*/)+0*+0*,1+)3+)3+*4,+5-+5,,6--7.-7,,6+.8-2=/6A39D69D67B46A1/<*2?-5B09F2<J3@N7FT=JXAR`I[iRanZ\iWQ^MBN@/;/!-!+1/(.,&,*heVheVheVheVheVheVheVheVifWifWifWifWifWifWifWifWkeUkeWkdZle]md]ne^mg[mgWqoZkmUkoXkr`jrgozvecIO7T=YFQ?I:L?;0=0=0=/x=/t?/rC3sE5s<9s<9t=:s>:u@<u@<t?;q>:s@<r?;q@;q@;p?:o>9o>9o>9n72n72n93m;4l;4j;3g<3d<2c?3^>1dG9cG9T=-O8(M8'D/TR;PN7KI0MK2]Y>ieJeaDVU7XX<]`CosXzfcmT=I1,:#1?(5;15;14:04:04:039/39/39/39/39/39/28.17-17-17-06,16016005/05//4./4./4./4.,1+,1+,1+,1+,1+,1++0*+0*.5.-4--4-,3,-4--4-.5-.5-+2*-4,08-5=29A6=E:?G<AI>7B25@03>-1<+2>*9E/BN8IU?O[EVbN]hWYdTLWI<F;/90)3*)/-(.,'-+heVheVheVheVheVheVheVheVifWifWifWifWifWifWifWifWkeUkeWkdZmd]md]mf^mg[khWonYjlTjoXkr`jtiq|x߲uZ[AZBYCUAQ>F5F4D4D2}B0yB.s@-o?+v?:t=8u>9v?:t?9q<6r=7sA:q?8q?8q?8o>7o>7n=6n=6n=6l;4m<5m>6k?6j?6h@6eA5cA5dG9[A2^G7\I8N=+F7$G8%A4!IM4GK2DG,BE*MM1[[?abC`aBYY=dgJsw\sy_X`H8D,/;%6D-7=36<26<26<25;15;15;15;15;15;15;14:04:039/39/39/27127127116016016005/05/.3-.3--2,-2,,1+,1++0*+0**1**1*)0))0))0)*1*+2+,3,.5--4,.5-07/4;39@8?F>BIA:G69F56C13@.2?+5B.;I2?M6KXDR_KXeSVcRKWI<H<0<2*6,+1-*0,)/+heVheVheVheVheVheVheVheVifWifWifWifWifWifWifWifWkeUkeWlcZmd]md]mf^mg[khWmlWimTjoXktaiuiq}yjYAQ;[D]GR=F2w=)t=)t@+vC.xE2s>8p;5q<6vA;sA:p>7r@9xG@n=6n=6n=6m>6l=5l=5l=5l=5g?5h@6gA6gC7eC7cC6`C5^D5aL;UB1ZI7`S@RG3C;&E=(GA+>G,BH.@F*<@%?B%LO2_`AijKaaEnqTvz_gmSHP84<%4=(=F18>48>48>48>47=37=37=36<28>48>47=37=37=36<26<26<25:449349349338238238227105/05//4..3--2,,1++0*+0*(/((/((/((/((/()0)*1*+2+070.5.+2++2+.5.5<5<C<AHA?L;>K:<I78E34A-2?+3A*5C,DQ=KXDQ^LQ^MHTF<H<2>4-9/-3/-3/,2.gdUgdUheVheVheVheVifWifWifWifWifWifWifWifWifWifWleUldWlcZmd]md]mf^mg[khWmlWimThpXht`hthm|wڻּҽzyS<tJ2uH1wI2{M6~O;zK7o@.e8%{LBsD:qB8sD:qB8g;0d8-h<1j>3i?3i?3i?3f>2f>2f>2f>2aA4`C5`C5_C5^D5[D4ZE4VE3XI6OB/\T?oiSc^HMK4IG0LJ3;E*?H->G*<B&<A#FI,VY:deFmmQxx\tw\[_F@D-6;%8@+<D/9?59?59?58>48>47=37=37=39?58>48>48>48>48>48>48>47<67<67<66;56;56;55:45:438238216005//4.-2,,1+,1++0,+0,*/+*/++0,,1--2.-2.051.3/+0,+0,-2.2738=9<A=?L;@M<@M;=J88E13@,1?(0>'<I5BO;HUCIVEDPB;G;2>4.:0.5..5.-4-gdUgdUgdUheVheVifWifWifWifWifWifWifWifWifWifWifWleUldWlcZmd]md]mf^mg[khWkmWjnUiqYgs_drejytܽչѷѾӾϴu`yVBlI5mH6rM;uP>mF7iB3gB2jE5nI9oJ:pK;oK;eA1eA1cB1cB1cB1cB1cB1bC1\G6\G6\G6ZG6YH6WH5TG4RG3PH3MH2fdM~~fprZVX@IM4HL3;E*<F+?H+AG+AF(DG*MN/TU6xw[{z^nnTUU=AC-?A,>A.;>+9?59?59?58>48>47=37=37=38>48>48>48>48>48>48>48>49>89>89>88=78=78=77<67<66;55:449338227105//4./4.-2.-2.,1-+0,+0,,1--2.-2.,1-,1-,1-,1-.21043376598:H7=L9@O<@O:<K67F/4C,2A*6E.:I4@O<BP??M>8F91?2,9/.5.-4-,3,fcTfcTgdUheVheVifWjgXjgXifWifWifWifWifWifWifWifWleUldWlcZmd]md]mf^mg[khWkmWioUiqYgs_bpcgxrڻѵ˴˺ӿһurd|]I}^JrVAaE0W;&Y=(Z?*X=(`E0`E0_F0_F0`G1`G1^H1^H1[L9ZM:ZM:XM9XM9UM8RL6QL6NL5QQ9ikS|glrXSY?DM2>G,:G+<F+?H+DJ.EJ,DG*HI*ML.yx\tsWfdKTR;LJ5KJ6FE3<=+:@69?59?59?58>48>48>48>47=37=38>48>48>48>49?59?5:?9:?9:?9:?99>89>89>88=78=78=77<66;55:4493382382/40.3/-2.,1-+0,+0,+0,+0,+/.,0/-10.21/32/32/32.210A.5F3;M7>P:=O7:L47I/6H.3E-6H0:L6<M::K95F6/?2*:--4,-4,,3+fcTfcTgdUheVheVifWjgXjgXifWifWifWifWifWifWifWifWleUldWlcZmd]md]mf^mg[jiWjlVhnThrYfs_aqdhysչ̳ŰĴ˴xt^GdP8aM5\H0\J2\J2\J2]K3\L3]M4]M4]M4WO:WO:VP:VP:TO9QO8PN7NN6MO7PT;`fLfoTU^CEO4AK0:G+=J.?I.CL/HN2HM/FI,OP1YX:qmRjfKa]D[V@YT@TQ>MJ9EB1;A7;A7;A7;A7:@6:@6:@69?58>48>48>49?59?5:@6:@6:@6;@:;@:;@::?9:?99>89>89>8:?9:?99>89>88=78=77<67<6495273162/40-2.,1-+0,+/.,0/,0/-10.21.21.23-12,01):'/@-6H2;M5=O7<N4:L2:L25G-7I1:L6<M::K96G70@3+;..5--4,,3+fcTfcTgdUheVheVifWjgXjgXifWifWifWifWifWifWifWifWleUldWlcZmd]md]mf^kg[jiWikUhnThrYgt`brej{uҶȯſļŸtaP6RB(XH.XH.[M2[M2\N3\N3[P4[P4\Q5\Q5TO9TO9TO9QO8PN7NN6KM5IM4JN5LR8S\AOY>?I.9F*?L0=J.AN2DN3HQ4LR6IN0JM0ZY;miLhdIc]C_YA_ZD`[GZUBQN=LI8=C9=C9=C9<B8<B8<B8;A7;A79?59?59?5:@6:@6;A7;A7;A7;@:;@:;@::?9:?99>89>89>8;@:;@:;@:;@::?9:?9:?9:?99>:8=95:6384162/40.3/.21.21.21-10-12,01,01-12-12$5"*<&3E/9K3<N6;M3;M3;M38J09K3;M7<M:<M;7H81B2,<//6..5--4,ZgM[hN\hP_iQakSckTfkWhkXfgUhgUheVheVjdVldWldYmeZjgVkhYkg[kg^kg^jf]hfZgeVfiVfkUenYbo^dqhsҿͼ̿·ƍnTO2UN1RL,SJ+WN/UO/UN1TO1SO2QP4QP4PP6QM2PO3QO6PP6MO7KO6HM6EM5HQ6FO4AJ-?F'@G&EK)GM)FL(ST2RS3MN.JK,TT8bbHccIZZB[YB\ZC][B][B[Z>XW9UT6SR3KE/JD.FA-D?,A>/@>1??3>@5<=5;>59?59A67B48C57C57D3:B79A69A68@58@59A69A6:B7:B7:B79A6:B7;C8<D9=E:>F;7B:7C97A66A16?.4<-39-270.5./51-7/-9+-<%.B3J7O7Z 8Y$8W+:U2:R8;P==O?>O=:L6@R8EX:EZ;DY:>U93J0(>'.5-,3++2*ZgM[hN\hP_iQakSckTglXhkXghVihVifWifWkeWmeXmeZnf[khWkhYkg[kg^jf]jf]hfZgeVgjWglVfoZerajwnz̹˾NjlRM0TM0QK+SJ+WN/UO/UN1TO1SO2QP4QP4PP6QM2PO3PN5PP6MO7KO6HM6EM5HQ6EN3BK.AH)BI(GM+JP,KQ-NR/PT1VZ9^aBaaE[[?VV<UU=VV>VV>XV=YW>XW;XW9WV8VU7QK5OI3LG3ID1DA2B@3??3>@5<=5;>59?59A67B48C57C57D3:B79A69A68@58@59A69A6:B7:B7:B7:B7:B7;C8<D9=E:>F;<G?<H><F;;F6<E4:B39?38=67>76<83=51=/3B+9M*BY-Ia1Nq7Mn9Ji=Fa>AY?<Q>:L<:K9=O9DV<K^@LaBLaBF]A:Q7/E.-4,+2*)0(ZgM[hN\hP`jRakSdlUglXilYijXkjXkhYkhYlfXmgYnf[og\khWkhYkg[jf]jf]ie\hfZhfWgjWejTdmXgtco|s˸öƉjPK.RK.QJ-SJ+VM.UO/UN1UP2TP3QP4QP4OO3QM2ON2PN5OO5MO7KO6IN7FN6HQ6FO4CL/EL-FM,KQ/OU1SY5QY0W_8jpLy]qvVY^@LO4MO7QQ9QQ9QQ9SQ8TR9UT8WV:ZV;XR<VP:RM9NI6HE6DB5AA5?A6<=5;>5:@69A67B47B47C57D3:B7:B79A69A69A69A6:B7:B7:B7:B7:B7:B7;C8<D9>F;>F;>IA>J@?I>>I9?H7>F7>D8=B;>E>;A=6@85A39H1BV3Pg;ZrB]F\}HVuIMhEBZ@9N;5G74E3<N8EW=NaCRgHShILcG@W=4J3180/6.-4,YgM[hN\hP^jRblTemVhmYjmZklZklZlj[liZnhZnhZog\ph]liXkhYjfZjf]ie\ie\hfZhfWehUbgQajUerao|s~Ѿ˸ƳþķǺNJmPJ0SL0SL/UL-VM.UO/VO2UP2TP3QP4PO3NN2PL1NM1OM4NN4LN6KO6JO8HP8JS8GP5GP3KR3MT3PV4V\8]c?fsGtUislnuTZaBRV;LN6NN6MM5NL5OM6TP7WS:YU<ZT>XR<TO;QL9KH9GE8CC7@B7=>6<?6:@69A67B47B46B46C2;C8:B79A69A69A69A6:B7;C8;C8:B7:B7;C8;C8=E:>F;?G<<G?<H>>H=>I9?H7>F7>D8=B;=D=;A=6@85A39H1DX5Ri=]uEY|BXyDRqEIdA<T:2G4.@0->,6H2@R8L_AQfGShIMdH@W=4J329107/-4,YgMZhN\hP^jRblTemVgoZjo[lo\lm[mk\mj[nhZnhZoi]ph]liXkhYjfZie\ie\ie\ig[igXfiVchRajUerao|s{ѿɶıþ˾Ÿ̌oRL2UN2TM0WN1VM.UO/WP3VQ3UQ4QP2ON2MM1PL1NM1NL3MM3LN6LP7KP9JR:LU:IR7JS6QX9SZ9U[9]c?gmIasxpr|Z\bFLP7KM7LK6KI4NI5PK7TM:VP:WQ;VP:SN:QL9LI:IG:EE9CE:=>6<?6:@69A67B47B46B46C2;C8;C8:B79A69A6:B7;C8;C8;C8;C8;C8;C8<D9=E:>F;?G<<G?<H>=G<=H8>G6=E6=C7=B;:A:9?;5?75A39H1BV3Ne9Wo?Sv<St?NmAE`=8P6-B/*<,+<*1C-<N4H[=OdERgHLcG@W=3I2.5-+2*'.& \ No newline at end of file
diff --git a/jpg/testimgp.jpg b/jpg/testimgp.jpg
new file mode 100644
index 0000000..ca6acad
--- /dev/null
+++ b/jpg/testimgp.jpg
Binary files differ
diff --git a/jpg/testorig.jpg b/jpg/testorig.jpg
new file mode 100644
index 0000000..9816a0c
--- /dev/null
+++ b/jpg/testorig.jpg
Binary files differ
diff --git a/jpg/testprog.jpg b/jpg/testprog.jpg
new file mode 100644
index 0000000..920fee2
--- /dev/null
+++ b/jpg/testprog.jpg
Binary files differ
diff --git a/jpg/transupp.c b/jpg/transupp.c
new file mode 100644
index 0000000..016f383
--- /dev/null
+++ b/jpg/transupp.c
@@ -0,0 +1,1597 @@
+/*
+ * transupp.c
+ *
+ * Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains image transformation routines and other utility code
+ * used by the jpegtran sample application. These are NOT part of the core
+ * JPEG library. But we keep these routines separate from jpegtran.c to
+ * ease the task of maintaining jpegtran-like programs that have other user
+ * interfaces.
+ */
+
+/* Although this file really shouldn't have access to the library internals,
+ * it's helpful to let it call jround_up() and jcopy_block_row().
+ */
+#define JPEG_INTERNALS
+
+#include "jinclude.h"
+#include "jpeglib.h"
+#include "transupp.h" /* My own external interface */
+#include <ctype.h> /* to declare isdigit() */
+
+
+#if TRANSFORMS_SUPPORTED
+
+/*
+ * Lossless image transformation routines. These routines work on DCT
+ * coefficient arrays and thus do not require any lossy decompression
+ * or recompression of the image.
+ * Thanks to Guido Vollbeding for the initial design and code of this feature,
+ * and to Ben Jackson for introducing the cropping feature.
+ *
+ * Horizontal flipping is done in-place, using a single top-to-bottom
+ * pass through the virtual source array. It will thus be much the
+ * fastest option for images larger than main memory.
+ *
+ * The other routines require a set of destination virtual arrays, so they
+ * need twice as much memory as jpegtran normally does. The destination
+ * arrays are always written in normal scan order (top to bottom) because
+ * the virtual array manager expects this. The source arrays will be scanned
+ * in the corresponding order, which means multiple passes through the source
+ * arrays for most of the transforms. That could result in much thrashing
+ * if the image is larger than main memory.
+ *
+ * If cropping or trimming is involved, the destination arrays may be smaller
+ * than the source arrays. Note it is not possible to do horizontal flip
+ * in-place when a nonzero Y crop offset is specified, since we'd have to move
+ * data from one block row to another but the virtual array manager doesn't
+ * guarantee we can touch more than one row at a time. So in that case,
+ * we have to use a separate destination array.
+ *
+ * Some notes about the operating environment of the individual transform
+ * routines:
+ * 1. Both the source and destination virtual arrays are allocated from the
+ * source JPEG object, and therefore should be manipulated by calling the
+ * source's memory manager.
+ * 2. The destination's component count should be used. It may be smaller
+ * than the source's when forcing to grayscale.
+ * 3. Likewise the destination's sampling factors should be used. When
+ * forcing to grayscale the destination's sampling factors will be all 1,
+ * and we may as well take that as the effective iMCU size.
+ * 4. When "trim" is in effect, the destination's dimensions will be the
+ * trimmed values but the source's will be untrimmed.
+ * 5. When "crop" is in effect, the destination's dimensions will be the
+ * cropped values but the source's will be uncropped. Each transform
+ * routine is responsible for picking up source data starting at the
+ * correct X and Y offset for the crop region. (The X and Y offsets
+ * passed to the transform routines are measured in iMCU blocks of the
+ * destination.)
+ * 6. All the routines assume that the source and destination buffers are
+ * padded out to a full iMCU boundary. This is true, although for the
+ * source buffer it is an undocumented property of jdcoefct.c.
+ */
+
+
+LOCAL(void)
+do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays,
+ jvirt_barray_ptr *dst_coef_arrays)
+/* Crop. This is only used when no rotate/flip is requested with the crop. */
+{
+ JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
+ int ci, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ jpeg_component_info *compptr;
+
+ /* We simply have to copy the right amount of data (the destination's
+ * image size) starting at the given X and Y offsets in the source.
+ */
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ dst_blk_y + y_crop_blocks,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
+ dst_buffer[offset_y],
+ compptr->width_in_blocks);
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays)
+/* Horizontal flip; done in-place, so no separate dest array is required.
+ * NB: this only works when y_crop_offset is zero.
+ */
+{
+ JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
+ int ci, k, offset_y;
+ JBLOCKARRAY buffer;
+ JCOEFPTR ptr1, ptr2;
+ JCOEF temp1, temp2;
+ jpeg_component_info *compptr;
+
+ /* Horizontal mirroring of DCT blocks is accomplished by swapping
+ * pairs of blocks in-place. Within a DCT block, we perform horizontal
+ * mirroring by changing the signs of odd-numbered columns.
+ * Partial iMCUs at the right edge are left untouched.
+ */
+ MCU_cols = srcinfo->output_width /
+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ for (blk_y = 0; blk_y < compptr->height_in_blocks;
+ blk_y += compptr->v_samp_factor) {
+ buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ /* Do the mirroring */
+ for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
+ ptr1 = buffer[offset_y][blk_x];
+ ptr2 = buffer[offset_y][comp_width - blk_x - 1];
+ /* this unrolled loop doesn't need to know which row it's on... */
+ for (k = 0; k < DCTSIZE2; k += 2) {
+ temp1 = *ptr1; /* swap even column */
+ temp2 = *ptr2;
+ *ptr1++ = temp2;
+ *ptr2++ = temp1;
+ temp1 = *ptr1; /* swap odd column with sign change */
+ temp2 = *ptr2;
+ *ptr1++ = -temp2;
+ *ptr2++ = -temp1;
+ }
+ }
+ if (x_crop_blocks > 0) {
+ /* Now left-justify the portion of the data to be kept.
+ * We can't use a single jcopy_block_row() call because that routine
+ * depends on memcpy(), whose behavior is unspecified for overlapping
+ * source and destination areas. Sigh.
+ */
+ for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
+ jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
+ buffer[offset_y] + blk_x,
+ (JDIMENSION) 1);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays,
+ jvirt_barray_ptr *dst_coef_arrays)
+/* Horizontal flip in general cropping case */
+{
+ JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+ JDIMENSION x_crop_blocks, y_crop_blocks;
+ int ci, k, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JBLOCKROW src_row_ptr, dst_row_ptr;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ /* Here we must output into a separate array because we can't touch
+ * different rows of a single virtual array simultaneously. Otherwise,
+ * this is essentially the same as the routine above.
+ */
+ MCU_cols = srcinfo->output_width /
+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ dst_blk_y + y_crop_blocks,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ dst_row_ptr = dst_buffer[offset_y];
+ src_row_ptr = src_buffer[offset_y];
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+ if (x_crop_blocks + dst_blk_x < comp_width) {
+ /* Do the mirrorable blocks */
+ dst_ptr = dst_row_ptr[dst_blk_x];
+ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
+ /* this unrolled loop doesn't need to know which row it's on... */
+ for (k = 0; k < DCTSIZE2; k += 2) {
+ *dst_ptr++ = *src_ptr++; /* copy even column */
+ *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */
+ }
+ } else {
+ /* Copy last partial block(s) verbatim */
+ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
+ dst_row_ptr + dst_blk_x,
+ (JDIMENSION) 1);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays,
+ jvirt_barray_ptr *dst_coef_arrays)
+/* Vertical flip */
+{
+ JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+ JDIMENSION x_crop_blocks, y_crop_blocks;
+ int ci, i, j, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JBLOCKROW src_row_ptr, dst_row_ptr;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ /* We output into a separate array because we can't touch different
+ * rows of the source virtual array simultaneously. Otherwise, this
+ * is a pretty straightforward analog of horizontal flip.
+ * Within a DCT block, vertical mirroring is done by changing the signs
+ * of odd-numbered rows.
+ * Partial iMCUs at the bottom edge are copied verbatim.
+ */
+ MCU_rows = srcinfo->output_height /
+ (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_height = MCU_rows * compptr->v_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ if (y_crop_blocks + dst_blk_y < comp_height) {
+ /* Row is within the mirrorable area. */
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ comp_height - y_crop_blocks - dst_blk_y -
+ (JDIMENSION) compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ } else {
+ /* Bottom-edge blocks will be copied verbatim. */
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ dst_blk_y + y_crop_blocks,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ }
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ if (y_crop_blocks + dst_blk_y < comp_height) {
+ /* Row is within the mirrorable area. */
+ dst_row_ptr = dst_buffer[offset_y];
+ src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
+ src_row_ptr += x_crop_blocks;
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x++) {
+ dst_ptr = dst_row_ptr[dst_blk_x];
+ src_ptr = src_row_ptr[dst_blk_x];
+ for (i = 0; i < DCTSIZE; i += 2) {
+ /* copy even row */
+ for (j = 0; j < DCTSIZE; j++)
+ *dst_ptr++ = *src_ptr++;
+ /* copy odd row with sign change */
+ for (j = 0; j < DCTSIZE; j++)
+ *dst_ptr++ = - *src_ptr++;
+ }
+ }
+ } else {
+ /* Just copy row verbatim. */
+ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
+ dst_buffer[offset_y],
+ compptr->width_in_blocks);
+ }
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays,
+ jvirt_barray_ptr *dst_coef_arrays)
+/* Transpose source into destination */
+{
+ JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
+ int ci, i, j, offset_x, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ /* Transposing pixels within a block just requires transposing the
+ * DCT coefficients.
+ * Partial iMCUs at the edges require no special treatment; we simply
+ * process all the available DCT blocks for every component.
+ */
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x += compptr->h_samp_factor) {
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ dst_blk_x + x_crop_blocks,
+ (JDIMENSION) compptr->h_samp_factor, FALSE);
+ for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+ src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
+ for (i = 0; i < DCTSIZE; i++)
+ for (j = 0; j < DCTSIZE; j++)
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ }
+ }
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays,
+ jvirt_barray_ptr *dst_coef_arrays)
+/* 90 degree rotation is equivalent to
+ * 1. Transposing the image;
+ * 2. Horizontal mirroring.
+ * These two steps are merged into a single processing routine.
+ */
+{
+ JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
+ JDIMENSION x_crop_blocks, y_crop_blocks;
+ int ci, i, j, offset_x, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ /* Because of the horizontal mirror step, we can't process partial iMCUs
+ * at the (output) right edge properly. They just get transposed and
+ * not mirrored.
+ */
+ MCU_cols = srcinfo->output_height /
+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x += compptr->h_samp_factor) {
+ if (x_crop_blocks + dst_blk_x < comp_width) {
+ /* Block is within the mirrorable area. */
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ comp_width - x_crop_blocks - dst_blk_x -
+ (JDIMENSION) compptr->h_samp_factor,
+ (JDIMENSION) compptr->h_samp_factor, FALSE);
+ } else {
+ /* Edge blocks are transposed but not mirrored. */
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ dst_blk_x + x_crop_blocks,
+ (JDIMENSION) compptr->h_samp_factor, FALSE);
+ }
+ for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+ if (x_crop_blocks + dst_blk_x < comp_width) {
+ /* Block is within the mirrorable area. */
+ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
+ [dst_blk_y + offset_y + y_crop_blocks];
+ for (i = 0; i < DCTSIZE; i++) {
+ for (j = 0; j < DCTSIZE; j++)
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ i++;
+ for (j = 0; j < DCTSIZE; j++)
+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+ }
+ } else {
+ /* Edge blocks are transposed but not mirrored. */
+ src_ptr = src_buffer[offset_x]
+ [dst_blk_y + offset_y + y_crop_blocks];
+ for (i = 0; i < DCTSIZE; i++)
+ for (j = 0; j < DCTSIZE; j++)
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays,
+ jvirt_barray_ptr *dst_coef_arrays)
+/* 270 degree rotation is equivalent to
+ * 1. Horizontal mirroring;
+ * 2. Transposing the image.
+ * These two steps are merged into a single processing routine.
+ */
+{
+ JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
+ JDIMENSION x_crop_blocks, y_crop_blocks;
+ int ci, i, j, offset_x, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ /* Because of the horizontal mirror step, we can't process partial iMCUs
+ * at the (output) bottom edge properly. They just get transposed and
+ * not mirrored.
+ */
+ MCU_rows = srcinfo->output_width /
+ (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_height = MCU_rows * compptr->v_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x += compptr->h_samp_factor) {
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ dst_blk_x + x_crop_blocks,
+ (JDIMENSION) compptr->h_samp_factor, FALSE);
+ for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+ if (y_crop_blocks + dst_blk_y < comp_height) {
+ /* Block is within the mirrorable area. */
+ src_ptr = src_buffer[offset_x]
+ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
+ for (i = 0; i < DCTSIZE; i++) {
+ for (j = 0; j < DCTSIZE; j++) {
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ j++;
+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+ }
+ }
+ } else {
+ /* Edge blocks are transposed but not mirrored. */
+ src_ptr = src_buffer[offset_x]
+ [dst_blk_y + offset_y + y_crop_blocks];
+ for (i = 0; i < DCTSIZE; i++)
+ for (j = 0; j < DCTSIZE; j++)
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays,
+ jvirt_barray_ptr *dst_coef_arrays)
+/* 180 degree rotation is equivalent to
+ * 1. Vertical mirroring;
+ * 2. Horizontal mirroring.
+ * These two steps are merged into a single processing routine.
+ */
+{
+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
+ JDIMENSION x_crop_blocks, y_crop_blocks;
+ int ci, i, j, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JBLOCKROW src_row_ptr, dst_row_ptr;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ MCU_cols = srcinfo->output_width /
+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
+ MCU_rows = srcinfo->output_height /
+ (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ comp_height = MCU_rows * compptr->v_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ if (y_crop_blocks + dst_blk_y < comp_height) {
+ /* Row is within the vertically mirrorable area. */
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ comp_height - y_crop_blocks - dst_blk_y -
+ (JDIMENSION) compptr->v_samp_factor,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ } else {
+ /* Bottom-edge rows are only mirrored horizontally. */
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ dst_blk_y + y_crop_blocks,
+ (JDIMENSION) compptr->v_samp_factor, FALSE);
+ }
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ dst_row_ptr = dst_buffer[offset_y];
+ if (y_crop_blocks + dst_blk_y < comp_height) {
+ /* Row is within the mirrorable area. */
+ src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+ dst_ptr = dst_row_ptr[dst_blk_x];
+ if (x_crop_blocks + dst_blk_x < comp_width) {
+ /* Process the blocks that can be mirrored both ways. */
+ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
+ for (i = 0; i < DCTSIZE; i += 2) {
+ /* For even row, negate every odd column. */
+ for (j = 0; j < DCTSIZE; j += 2) {
+ *dst_ptr++ = *src_ptr++;
+ *dst_ptr++ = - *src_ptr++;
+ }
+ /* For odd row, negate every even column. */
+ for (j = 0; j < DCTSIZE; j += 2) {
+ *dst_ptr++ = - *src_ptr++;
+ *dst_ptr++ = *src_ptr++;
+ }
+ }
+ } else {
+ /* Any remaining right-edge blocks are only mirrored vertically. */
+ src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
+ for (i = 0; i < DCTSIZE; i += 2) {
+ for (j = 0; j < DCTSIZE; j++)
+ *dst_ptr++ = *src_ptr++;
+ for (j = 0; j < DCTSIZE; j++)
+ *dst_ptr++ = - *src_ptr++;
+ }
+ }
+ }
+ } else {
+ /* Remaining rows are just mirrored horizontally. */
+ src_row_ptr = src_buffer[offset_y];
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
+ if (x_crop_blocks + dst_blk_x < comp_width) {
+ /* Process the blocks that can be mirrored. */
+ dst_ptr = dst_row_ptr[dst_blk_x];
+ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
+ for (i = 0; i < DCTSIZE2; i += 2) {
+ *dst_ptr++ = *src_ptr++;
+ *dst_ptr++ = - *src_ptr++;
+ }
+ } else {
+ /* Any remaining right-edge blocks are only copied. */
+ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
+ dst_row_ptr + dst_blk_x,
+ (JDIMENSION) 1);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+LOCAL(void)
+do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
+ jvirt_barray_ptr *src_coef_arrays,
+ jvirt_barray_ptr *dst_coef_arrays)
+/* Transverse transpose is equivalent to
+ * 1. 180 degree rotation;
+ * 2. Transposition;
+ * or
+ * 1. Horizontal mirroring;
+ * 2. Transposition;
+ * 3. Horizontal mirroring.
+ * These steps are merged into a single processing routine.
+ */
+{
+ JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
+ JDIMENSION x_crop_blocks, y_crop_blocks;
+ int ci, i, j, offset_x, offset_y;
+ JBLOCKARRAY src_buffer, dst_buffer;
+ JCOEFPTR src_ptr, dst_ptr;
+ jpeg_component_info *compptr;
+
+ MCU_cols = srcinfo->output_height /
+ (dstinfo->max_h_samp_factor * dstinfo->min_DCT_h_scaled_size);
+ MCU_rows = srcinfo->output_width /
+ (dstinfo->max_v_samp_factor * dstinfo->min_DCT_v_scaled_size);
+
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ comp_width = MCU_cols * compptr->h_samp_factor;
+ comp_height = MCU_rows * compptr->v_samp_factor;
+ x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
+ y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
+ for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
+ dst_blk_y += compptr->v_samp_factor) {
+ dst_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y,
+ (JDIMENSION) compptr->v_samp_factor, TRUE);
+ for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
+ for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
+ dst_blk_x += compptr->h_samp_factor) {
+ if (x_crop_blocks + dst_blk_x < comp_width) {
+ /* Block is within the mirrorable area. */
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ comp_width - x_crop_blocks - dst_blk_x -
+ (JDIMENSION) compptr->h_samp_factor,
+ (JDIMENSION) compptr->h_samp_factor, FALSE);
+ } else {
+ src_buffer = (*srcinfo->mem->access_virt_barray)
+ ((j_common_ptr) srcinfo, src_coef_arrays[ci],
+ dst_blk_x + x_crop_blocks,
+ (JDIMENSION) compptr->h_samp_factor, FALSE);
+ }
+ for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
+ dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
+ if (y_crop_blocks + dst_blk_y < comp_height) {
+ if (x_crop_blocks + dst_blk_x < comp_width) {
+ /* Block is within the mirrorable area. */
+ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
+ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
+ for (i = 0; i < DCTSIZE; i++) {
+ for (j = 0; j < DCTSIZE; j++) {
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ j++;
+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+ }
+ i++;
+ for (j = 0; j < DCTSIZE; j++) {
+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+ j++;
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ }
+ }
+ } else {
+ /* Right-edge blocks are mirrored in y only */
+ src_ptr = src_buffer[offset_x]
+ [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
+ for (i = 0; i < DCTSIZE; i++) {
+ for (j = 0; j < DCTSIZE; j++) {
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ j++;
+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+ }
+ }
+ }
+ } else {
+ if (x_crop_blocks + dst_blk_x < comp_width) {
+ /* Bottom-edge blocks are mirrored in x only */
+ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
+ [dst_blk_y + offset_y + y_crop_blocks];
+ for (i = 0; i < DCTSIZE; i++) {
+ for (j = 0; j < DCTSIZE; j++)
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ i++;
+ for (j = 0; j < DCTSIZE; j++)
+ dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j];
+ }
+ } else {
+ /* At lower right corner, just transpose, no mirroring */
+ src_ptr = src_buffer[offset_x]
+ [dst_blk_y + offset_y + y_crop_blocks];
+ for (i = 0; i < DCTSIZE; i++)
+ for (j = 0; j < DCTSIZE; j++)
+ dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
+ * Returns TRUE if valid integer found, FALSE if not.
+ * *strptr is advanced over the digit string, and *result is set to its value.
+ */
+
+LOCAL(boolean)
+jt_read_integer (const char ** strptr, JDIMENSION * result)
+{
+ const char * ptr = *strptr;
+ JDIMENSION val = 0;
+
+ for (; isdigit(*ptr); ptr++) {
+ val = val * 10 + (JDIMENSION) (*ptr - '0');
+ }
+ *result = val;
+ if (ptr == *strptr)
+ return FALSE; /* oops, no digits */
+ *strptr = ptr;
+ return TRUE;
+}
+
+
+/* Parse a crop specification (written in X11 geometry style).
+ * The routine returns TRUE if the spec string is valid, FALSE if not.
+ *
+ * The crop spec string should have the format
+ * <width>[f]x<height>[f]{+-}<xoffset>{+-}<yoffset>
+ * where width, height, xoffset, and yoffset are unsigned integers.
+ * Each of the elements can be omitted to indicate a default value.
+ * (A weakness of this style is that it is not possible to omit xoffset
+ * while specifying yoffset, since they look alike.)
+ *
+ * This code is loosely based on XParseGeometry from the X11 distribution.
+ */
+
+GLOBAL(boolean)
+jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec)
+{
+ info->crop = FALSE;
+ info->crop_width_set = JCROP_UNSET;
+ info->crop_height_set = JCROP_UNSET;
+ info->crop_xoffset_set = JCROP_UNSET;
+ info->crop_yoffset_set = JCROP_UNSET;
+
+ if (isdigit(*spec)) {
+ /* fetch width */
+ if (! jt_read_integer(&spec, &info->crop_width))
+ return FALSE;
+ if (*spec == 'f' || *spec == 'F') {
+ spec++;
+ info->crop_width_set = JCROP_FORCE;
+ } else
+ info->crop_width_set = JCROP_POS;
+ }
+ if (*spec == 'x' || *spec == 'X') {
+ /* fetch height */
+ spec++;
+ if (! jt_read_integer(&spec, &info->crop_height))
+ return FALSE;
+ if (*spec == 'f' || *spec == 'F') {
+ spec++;
+ info->crop_height_set = JCROP_FORCE;
+ } else
+ info->crop_height_set = JCROP_POS;
+ }
+ if (*spec == '+' || *spec == '-') {
+ /* fetch xoffset */
+ info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
+ spec++;
+ if (! jt_read_integer(&spec, &info->crop_xoffset))
+ return FALSE;
+ }
+ if (*spec == '+' || *spec == '-') {
+ /* fetch yoffset */
+ info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
+ spec++;
+ if (! jt_read_integer(&spec, &info->crop_yoffset))
+ return FALSE;
+ }
+ /* We had better have gotten to the end of the string. */
+ if (*spec != '\0')
+ return FALSE;
+ info->crop = TRUE;
+ return TRUE;
+}
+
+
+/* Trim off any partial iMCUs on the indicated destination edge */
+
+LOCAL(void)
+trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width)
+{
+ JDIMENSION MCU_cols;
+
+ MCU_cols = info->output_width / info->iMCU_sample_width;
+ if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
+ full_width / info->iMCU_sample_width)
+ info->output_width = MCU_cols * info->iMCU_sample_width;
+}
+
+LOCAL(void)
+trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height)
+{
+ JDIMENSION MCU_rows;
+
+ MCU_rows = info->output_height / info->iMCU_sample_height;
+ if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
+ full_height / info->iMCU_sample_height)
+ info->output_height = MCU_rows * info->iMCU_sample_height;
+}
+
+
+/* Request any required workspace.
+ *
+ * This routine figures out the size that the output image will be
+ * (which implies that all the transform parameters must be set before
+ * it is called).
+ *
+ * We allocate the workspace virtual arrays from the source decompression
+ * object, so that all the arrays (both the original data and the workspace)
+ * will be taken into account while making memory management decisions.
+ * Hence, this routine must be called after jpeg_read_header (which reads
+ * the image dimensions) and before jpeg_read_coefficients (which realizes
+ * the source's virtual arrays).
+ *
+ * This function returns FALSE right away if -perfect is given
+ * and transformation is not perfect. Otherwise returns TRUE.
+ */
+
+GLOBAL(boolean)
+jtransform_request_workspace (j_decompress_ptr srcinfo,
+ jpeg_transform_info *info)
+{
+ jvirt_barray_ptr *coef_arrays;
+ boolean need_workspace, transpose_it;
+ jpeg_component_info *compptr;
+ JDIMENSION xoffset, yoffset;
+ JDIMENSION width_in_iMCUs, height_in_iMCUs;
+ JDIMENSION width_in_blocks, height_in_blocks;
+ int ci, h_samp_factor, v_samp_factor;
+
+ /* Determine number of components in output image */
+ if (info->force_grayscale &&
+ srcinfo->jpeg_color_space == JCS_YCbCr &&
+ srcinfo->num_components == 3)
+ /* We'll only process the first component */
+ info->num_components = 1;
+ else
+ /* Process all the components */
+ info->num_components = srcinfo->num_components;
+
+ /* Compute output image dimensions and related values. */
+ jpeg_core_output_dimensions(srcinfo);
+
+ /* Return right away if -perfect is given and transformation is not perfect.
+ */
+ if (info->perfect) {
+ if (info->num_components == 1) {
+ if (!jtransform_perfect_transform(srcinfo->output_width,
+ srcinfo->output_height,
+ srcinfo->min_DCT_h_scaled_size,
+ srcinfo->min_DCT_v_scaled_size,
+ info->transform))
+ return FALSE;
+ } else {
+ if (!jtransform_perfect_transform(srcinfo->output_width,
+ srcinfo->output_height,
+ srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size,
+ srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size,
+ info->transform))
+ return FALSE;
+ }
+ }
+
+ /* If there is only one output component, force the iMCU size to be 1;
+ * else use the source iMCU size. (This allows us to do the right thing
+ * when reducing color to grayscale, and also provides a handy way of
+ * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
+ */
+ switch (info->transform) {
+ case JXFORM_TRANSPOSE:
+ case JXFORM_TRANSVERSE:
+ case JXFORM_ROT_90:
+ case JXFORM_ROT_270:
+ info->output_width = srcinfo->output_height;
+ info->output_height = srcinfo->output_width;
+ if (info->num_components == 1) {
+ info->iMCU_sample_width = srcinfo->min_DCT_v_scaled_size;
+ info->iMCU_sample_height = srcinfo->min_DCT_h_scaled_size;
+ } else {
+ info->iMCU_sample_width =
+ srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
+ info->iMCU_sample_height =
+ srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
+ }
+ break;
+ default:
+ info->output_width = srcinfo->output_width;
+ info->output_height = srcinfo->output_height;
+ if (info->num_components == 1) {
+ info->iMCU_sample_width = srcinfo->min_DCT_h_scaled_size;
+ info->iMCU_sample_height = srcinfo->min_DCT_v_scaled_size;
+ } else {
+ info->iMCU_sample_width =
+ srcinfo->max_h_samp_factor * srcinfo->min_DCT_h_scaled_size;
+ info->iMCU_sample_height =
+ srcinfo->max_v_samp_factor * srcinfo->min_DCT_v_scaled_size;
+ }
+ break;
+ }
+
+ /* If cropping has been requested, compute the crop area's position and
+ * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
+ */
+ if (info->crop) {
+ /* Insert default values for unset crop parameters */
+ if (info->crop_xoffset_set == JCROP_UNSET)
+ info->crop_xoffset = 0; /* default to +0 */
+ if (info->crop_yoffset_set == JCROP_UNSET)
+ info->crop_yoffset = 0; /* default to +0 */
+ if (info->crop_xoffset >= info->output_width ||
+ info->crop_yoffset >= info->output_height)
+ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+ if (info->crop_width_set == JCROP_UNSET)
+ info->crop_width = info->output_width - info->crop_xoffset;
+ if (info->crop_height_set == JCROP_UNSET)
+ info->crop_height = info->output_height - info->crop_yoffset;
+ /* Ensure parameters are valid */
+ if (info->crop_width <= 0 || info->crop_width > info->output_width ||
+ info->crop_height <= 0 || info->crop_height > info->output_height ||
+ info->crop_xoffset > info->output_width - info->crop_width ||
+ info->crop_yoffset > info->output_height - info->crop_height)
+ ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
+ /* Convert negative crop offsets into regular offsets */
+ if (info->crop_xoffset_set == JCROP_NEG)
+ xoffset = info->output_width - info->crop_width - info->crop_xoffset;
+ else
+ xoffset = info->crop_xoffset;
+ if (info->crop_yoffset_set == JCROP_NEG)
+ yoffset = info->output_height - info->crop_height - info->crop_yoffset;
+ else
+ yoffset = info->crop_yoffset;
+ /* Now adjust so that upper left corner falls at an iMCU boundary */
+ if (info->crop_width_set == JCROP_FORCE)
+ info->output_width = info->crop_width;
+ else
+ info->output_width =
+ info->crop_width + (xoffset % info->iMCU_sample_width);
+ if (info->crop_height_set == JCROP_FORCE)
+ info->output_height = info->crop_height;
+ else
+ info->output_height =
+ info->crop_height + (yoffset % info->iMCU_sample_height);
+ /* Save x/y offsets measured in iMCUs */
+ info->x_crop_offset = xoffset / info->iMCU_sample_width;
+ info->y_crop_offset = yoffset / info->iMCU_sample_height;
+ } else {
+ info->x_crop_offset = 0;
+ info->y_crop_offset = 0;
+ }
+
+ /* Figure out whether we need workspace arrays,
+ * and if so whether they are transposed relative to the source.
+ */
+ need_workspace = FALSE;
+ transpose_it = FALSE;
+ switch (info->transform) {
+ case JXFORM_NONE:
+ if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
+ need_workspace = TRUE;
+ /* No workspace needed if neither cropping nor transforming */
+ break;
+ case JXFORM_FLIP_H:
+ if (info->trim)
+ trim_right_edge(info, srcinfo->output_width);
+ if (info->y_crop_offset != 0)
+ need_workspace = TRUE;
+ /* do_flip_h_no_crop doesn't need a workspace array */
+ break;
+ case JXFORM_FLIP_V:
+ if (info->trim)
+ trim_bottom_edge(info, srcinfo->output_height);
+ /* Need workspace arrays having same dimensions as source image. */
+ need_workspace = TRUE;
+ break;
+ case JXFORM_TRANSPOSE:
+ /* transpose does NOT have to trim anything */
+ /* Need workspace arrays having transposed dimensions. */
+ need_workspace = TRUE;
+ transpose_it = TRUE;
+ break;
+ case JXFORM_TRANSVERSE:
+ if (info->trim) {
+ trim_right_edge(info, srcinfo->output_height);
+ trim_bottom_edge(info, srcinfo->output_width);
+ }
+ /* Need workspace arrays having transposed dimensions. */
+ need_workspace = TRUE;
+ transpose_it = TRUE;
+ break;
+ case JXFORM_ROT_90:
+ if (info->trim)
+ trim_right_edge(info, srcinfo->output_height);
+ /* Need workspace arrays having transposed dimensions. */
+ need_workspace = TRUE;
+ transpose_it = TRUE;
+ break;
+ case JXFORM_ROT_180:
+ if (info->trim) {
+ trim_right_edge(info, srcinfo->output_width);
+ trim_bottom_edge(info, srcinfo->output_height);
+ }
+ /* Need workspace arrays having same dimensions as source image. */
+ need_workspace = TRUE;
+ break;
+ case JXFORM_ROT_270:
+ if (info->trim)
+ trim_bottom_edge(info, srcinfo->output_width);
+ /* Need workspace arrays having transposed dimensions. */
+ need_workspace = TRUE;
+ transpose_it = TRUE;
+ break;
+ }
+
+ /* Allocate workspace if needed.
+ * Note that we allocate arrays padded out to the next iMCU boundary,
+ * so that transform routines need not worry about missing edge blocks.
+ */
+ if (need_workspace) {
+ coef_arrays = (jvirt_barray_ptr *)
+ (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE,
+ SIZEOF(jvirt_barray_ptr) * info->num_components);
+ width_in_iMCUs = (JDIMENSION)
+ jdiv_round_up((long) info->output_width,
+ (long) info->iMCU_sample_width);
+ height_in_iMCUs = (JDIMENSION)
+ jdiv_round_up((long) info->output_height,
+ (long) info->iMCU_sample_height);
+ for (ci = 0; ci < info->num_components; ci++) {
+ compptr = srcinfo->comp_info + ci;
+ if (info->num_components == 1) {
+ /* we're going to force samp factors to 1x1 in this case */
+ h_samp_factor = v_samp_factor = 1;
+ } else if (transpose_it) {
+ h_samp_factor = compptr->v_samp_factor;
+ v_samp_factor = compptr->h_samp_factor;
+ } else {
+ h_samp_factor = compptr->h_samp_factor;
+ v_samp_factor = compptr->v_samp_factor;
+ }
+ width_in_blocks = width_in_iMCUs * h_samp_factor;
+ height_in_blocks = height_in_iMCUs * v_samp_factor;
+ coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
+ ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE,
+ width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor);
+ }
+ info->workspace_coef_arrays = coef_arrays;
+ } else
+ info->workspace_coef_arrays = NULL;
+
+ return TRUE;
+}
+
+
+/* Transpose destination image parameters */
+
+LOCAL(void)
+transpose_critical_parameters (j_compress_ptr dstinfo)
+{
+ int tblno, i, j, ci, itemp;
+ jpeg_component_info *compptr;
+ JQUANT_TBL *qtblptr;
+ JDIMENSION jtemp;
+ UINT16 qtemp;
+
+ /* Transpose image dimensions */
+ jtemp = dstinfo->image_width;
+ dstinfo->image_width = dstinfo->image_height;
+ dstinfo->image_height = jtemp;
+ itemp = dstinfo->min_DCT_h_scaled_size;
+ dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
+ dstinfo->min_DCT_v_scaled_size = itemp;
+
+ /* Transpose sampling factors */
+ for (ci = 0; ci < dstinfo->num_components; ci++) {
+ compptr = dstinfo->comp_info + ci;
+ itemp = compptr->h_samp_factor;
+ compptr->h_samp_factor = compptr->v_samp_factor;
+ compptr->v_samp_factor = itemp;
+ }
+
+ /* Transpose quantization tables */
+ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
+ qtblptr = dstinfo->quant_tbl_ptrs[tblno];
+ if (qtblptr != NULL) {
+ for (i = 0; i < DCTSIZE; i++) {
+ for (j = 0; j < i; j++) {
+ qtemp = qtblptr->quantval[i*DCTSIZE+j];
+ qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i];
+ qtblptr->quantval[j*DCTSIZE+i] = qtemp;
+ }
+ }
+ }
+ }
+}
+
+
+/* Adjust Exif image parameters.
+ *
+ * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
+ */
+
+LOCAL(void)
+adjust_exif_parameters (JOCTET FAR * data, unsigned int length,
+ JDIMENSION new_width, JDIMENSION new_height)
+{
+ boolean is_motorola; /* Flag for byte order */
+ unsigned int number_of_tags, tagnum;
+ unsigned int firstoffset, offset;
+ JDIMENSION new_value;
+
+ if (length < 12) return; /* Length of an IFD entry */
+
+ /* Discover byte order */
+ if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49)
+ is_motorola = FALSE;
+ else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D)
+ is_motorola = TRUE;
+ else
+ return;
+
+ /* Check Tag Mark */
+ if (is_motorola) {
+ if (GETJOCTET(data[2]) != 0) return;
+ if (GETJOCTET(data[3]) != 0x2A) return;
+ } else {
+ if (GETJOCTET(data[3]) != 0) return;
+ if (GETJOCTET(data[2]) != 0x2A) return;
+ }
+
+ /* Get first IFD offset (offset to IFD0) */
+ if (is_motorola) {
+ if (GETJOCTET(data[4]) != 0) return;
+ if (GETJOCTET(data[5]) != 0) return;
+ firstoffset = GETJOCTET(data[6]);
+ firstoffset <<= 8;
+ firstoffset += GETJOCTET(data[7]);
+ } else {
+ if (GETJOCTET(data[7]) != 0) return;
+ if (GETJOCTET(data[6]) != 0) return;
+ firstoffset = GETJOCTET(data[5]);
+ firstoffset <<= 8;
+ firstoffset += GETJOCTET(data[4]);
+ }
+ if (firstoffset > length - 2) return; /* check end of data segment */
+
+ /* Get the number of directory entries contained in this IFD */
+ if (is_motorola) {
+ number_of_tags = GETJOCTET(data[firstoffset]);
+ number_of_tags <<= 8;
+ number_of_tags += GETJOCTET(data[firstoffset+1]);
+ } else {
+ number_of_tags = GETJOCTET(data[firstoffset+1]);
+ number_of_tags <<= 8;
+ number_of_tags += GETJOCTET(data[firstoffset]);
+ }
+ if (number_of_tags == 0) return;
+ firstoffset += 2;
+
+ /* Search for ExifSubIFD offset Tag in IFD0 */
+ for (;;) {
+ if (firstoffset > length - 12) return; /* check end of data segment */
+ /* Get Tag number */
+ if (is_motorola) {
+ tagnum = GETJOCTET(data[firstoffset]);
+ tagnum <<= 8;
+ tagnum += GETJOCTET(data[firstoffset+1]);
+ } else {
+ tagnum = GETJOCTET(data[firstoffset+1]);
+ tagnum <<= 8;
+ tagnum += GETJOCTET(data[firstoffset]);
+ }
+ if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
+ if (--number_of_tags == 0) return;
+ firstoffset += 12;
+ }
+
+ /* Get the ExifSubIFD offset */
+ if (is_motorola) {
+ if (GETJOCTET(data[firstoffset+8]) != 0) return;
+ if (GETJOCTET(data[firstoffset+9]) != 0) return;
+ offset = GETJOCTET(data[firstoffset+10]);
+ offset <<= 8;
+ offset += GETJOCTET(data[firstoffset+11]);
+ } else {
+ if (GETJOCTET(data[firstoffset+11]) != 0) return;
+ if (GETJOCTET(data[firstoffset+10]) != 0) return;
+ offset = GETJOCTET(data[firstoffset+9]);
+ offset <<= 8;
+ offset += GETJOCTET(data[firstoffset+8]);
+ }
+ if (offset > length - 2) return; /* check end of data segment */
+
+ /* Get the number of directory entries contained in this SubIFD */
+ if (is_motorola) {
+ number_of_tags = GETJOCTET(data[offset]);
+ number_of_tags <<= 8;
+ number_of_tags += GETJOCTET(data[offset+1]);
+ } else {
+ number_of_tags = GETJOCTET(data[offset+1]);
+ number_of_tags <<= 8;
+ number_of_tags += GETJOCTET(data[offset]);
+ }
+ if (number_of_tags < 2) return;
+ offset += 2;
+
+ /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
+ do {
+ if (offset > length - 12) return; /* check end of data segment */
+ /* Get Tag number */
+ if (is_motorola) {
+ tagnum = GETJOCTET(data[offset]);
+ tagnum <<= 8;
+ tagnum += GETJOCTET(data[offset+1]);
+ } else {
+ tagnum = GETJOCTET(data[offset+1]);
+ tagnum <<= 8;
+ tagnum += GETJOCTET(data[offset]);
+ }
+ if (tagnum == 0xA002 || tagnum == 0xA003) {
+ if (tagnum == 0xA002)
+ new_value = new_width; /* ExifImageWidth Tag */
+ else
+ new_value = new_height; /* ExifImageHeight Tag */
+ if (is_motorola) {
+ data[offset+2] = 0; /* Format = unsigned long (4 octets) */
+ data[offset+3] = 4;
+ data[offset+4] = 0; /* Number Of Components = 1 */
+ data[offset+5] = 0;
+ data[offset+6] = 0;
+ data[offset+7] = 1;
+ data[offset+8] = 0;
+ data[offset+9] = 0;
+ data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF);
+ data[offset+11] = (JOCTET)(new_value & 0xFF);
+ } else {
+ data[offset+2] = 4; /* Format = unsigned long (4 octets) */
+ data[offset+3] = 0;
+ data[offset+4] = 1; /* Number Of Components = 1 */
+ data[offset+5] = 0;
+ data[offset+6] = 0;
+ data[offset+7] = 0;
+ data[offset+8] = (JOCTET)(new_value & 0xFF);
+ data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF);
+ data[offset+10] = 0;
+ data[offset+11] = 0;
+ }
+ }
+ offset += 12;
+ } while (--number_of_tags);
+}
+
+
+/* Adjust output image parameters as needed.
+ *
+ * This must be called after jpeg_copy_critical_parameters()
+ * and before jpeg_write_coefficients().
+ *
+ * The return value is the set of virtual coefficient arrays to be written
+ * (either the ones allocated by jtransform_request_workspace, or the
+ * original source data arrays). The caller will need to pass this value
+ * to jpeg_write_coefficients().
+ */
+
+GLOBAL(jvirt_barray_ptr *)
+jtransform_adjust_parameters (j_decompress_ptr srcinfo,
+ j_compress_ptr dstinfo,
+ jvirt_barray_ptr *src_coef_arrays,
+ jpeg_transform_info *info)
+{
+ /* If force-to-grayscale is requested, adjust destination parameters */
+ if (info->force_grayscale) {
+ /* First, ensure we have YCbCr or grayscale data, and that the source's
+ * Y channel is full resolution. (No reasonable person would make Y
+ * be less than full resolution, so actually coping with that case
+ * isn't worth extra code space. But we check it to avoid crashing.)
+ */
+ if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
+ dstinfo->num_components == 3) ||
+ (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
+ dstinfo->num_components == 1)) &&
+ srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
+ srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
+ /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
+ * properly. Among other things, it sets the target h_samp_factor &
+ * v_samp_factor to 1, which typically won't match the source.
+ * We have to preserve the source's quantization table number, however.
+ */
+ int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
+ jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
+ dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
+ } else {
+ /* Sorry, can't do it */
+ ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
+ }
+ } else if (info->num_components == 1) {
+ /* For a single-component source, we force the destination sampling factors
+ * to 1x1, with or without force_grayscale. This is useful because some
+ * decoders choke on grayscale images with other sampling factors.
+ */
+ dstinfo->comp_info[0].h_samp_factor = 1;
+ dstinfo->comp_info[0].v_samp_factor = 1;
+ }
+
+ /* Correct the destination's image dimensions as necessary
+ * for rotate/flip, resize, and crop operations.
+ */
+ dstinfo->jpeg_width = info->output_width;
+ dstinfo->jpeg_height = info->output_height;
+
+ /* Transpose destination image parameters */
+ switch (info->transform) {
+ case JXFORM_TRANSPOSE:
+ case JXFORM_TRANSVERSE:
+ case JXFORM_ROT_90:
+ case JXFORM_ROT_270:
+ transpose_critical_parameters(dstinfo);
+ break;
+ default:
+ break;
+ }
+
+ /* Adjust Exif properties */
+ if (srcinfo->marker_list != NULL &&
+ srcinfo->marker_list->marker == JPEG_APP0+1 &&
+ srcinfo->marker_list->data_length >= 6 &&
+ GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 &&
+ GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 &&
+ GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 &&
+ GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 &&
+ GETJOCTET(srcinfo->marker_list->data[4]) == 0 &&
+ GETJOCTET(srcinfo->marker_list->data[5]) == 0) {
+ /* Suppress output of JFIF marker */
+ dstinfo->write_JFIF_header = FALSE;
+ /* Adjust Exif image parameters */
+ if (dstinfo->jpeg_width != srcinfo->image_width ||
+ dstinfo->jpeg_height != srcinfo->image_height)
+ /* Align data segment to start of TIFF structure for parsing */
+ adjust_exif_parameters(srcinfo->marker_list->data + 6,
+ srcinfo->marker_list->data_length - 6,
+ dstinfo->jpeg_width, dstinfo->jpeg_height);
+ }
+
+ /* Return the appropriate output data set */
+ if (info->workspace_coef_arrays != NULL)
+ return info->workspace_coef_arrays;
+ return src_coef_arrays;
+}
+
+
+/* Execute the actual transformation, if any.
+ *
+ * This must be called *after* jpeg_write_coefficients, because it depends
+ * on jpeg_write_coefficients to have computed subsidiary values such as
+ * the per-component width and height fields in the destination object.
+ *
+ * Note that some transformations will modify the source data arrays!
+ */
+
+GLOBAL(void)
+jtransform_execute_transform (j_decompress_ptr srcinfo,
+ j_compress_ptr dstinfo,
+ jvirt_barray_ptr *src_coef_arrays,
+ jpeg_transform_info *info)
+{
+ jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
+
+ /* Note: conditions tested here should match those in switch statement
+ * in jtransform_request_workspace()
+ */
+ switch (info->transform) {
+ case JXFORM_NONE:
+ if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
+ do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ break;
+ case JXFORM_FLIP_H:
+ if (info->y_crop_offset != 0)
+ do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ else
+ do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
+ src_coef_arrays);
+ break;
+ case JXFORM_FLIP_V:
+ do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ break;
+ case JXFORM_TRANSPOSE:
+ do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ break;
+ case JXFORM_TRANSVERSE:
+ do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ break;
+ case JXFORM_ROT_90:
+ do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ break;
+ case JXFORM_ROT_180:
+ do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ break;
+ case JXFORM_ROT_270:
+ do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
+ src_coef_arrays, dst_coef_arrays);
+ break;
+ }
+}
+
+/* jtransform_perfect_transform
+ *
+ * Determine whether lossless transformation is perfectly
+ * possible for a specified image and transformation.
+ *
+ * Inputs:
+ * image_width, image_height: source image dimensions.
+ * MCU_width, MCU_height: pixel dimensions of MCU.
+ * transform: transformation identifier.
+ * Parameter sources from initialized jpeg_struct
+ * (after reading source header):
+ * image_width = cinfo.image_width
+ * image_height = cinfo.image_height
+ * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
+ * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
+ * Result:
+ * TRUE = perfect transformation possible
+ * FALSE = perfect transformation not possible
+ * (may use custom action then)
+ */
+
+GLOBAL(boolean)
+jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
+ int MCU_width, int MCU_height,
+ JXFORM_CODE transform)
+{
+ boolean result = TRUE; /* initialize TRUE */
+
+ switch (transform) {
+ case JXFORM_FLIP_H:
+ case JXFORM_ROT_270:
+ if (image_width % (JDIMENSION) MCU_width)
+ result = FALSE;
+ break;
+ case JXFORM_FLIP_V:
+ case JXFORM_ROT_90:
+ if (image_height % (JDIMENSION) MCU_height)
+ result = FALSE;
+ break;
+ case JXFORM_TRANSVERSE:
+ case JXFORM_ROT_180:
+ if (image_width % (JDIMENSION) MCU_width)
+ result = FALSE;
+ if (image_height % (JDIMENSION) MCU_height)
+ result = FALSE;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+#endif /* TRANSFORMS_SUPPORTED */
+
+
+/* Setup decompression object to save desired markers in memory.
+ * This must be called before jpeg_read_header() to have the desired effect.
+ */
+
+GLOBAL(void)
+jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option)
+{
+#ifdef SAVE_MARKERS_SUPPORTED
+ int m;
+
+ /* Save comments except under NONE option */
+ if (option != JCOPYOPT_NONE) {
+ jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
+ }
+ /* Save all types of APPn markers iff ALL option */
+ if (option == JCOPYOPT_ALL) {
+ for (m = 0; m < 16; m++)
+ jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
+ }
+#endif /* SAVE_MARKERS_SUPPORTED */
+}
+
+/* Copy markers saved in the given source object to the destination object.
+ * This should be called just after jpeg_start_compress() or
+ * jpeg_write_coefficients().
+ * Note that those routines will have written the SOI, and also the
+ * JFIF APP0 or Adobe APP14 markers if selected.
+ */
+
+GLOBAL(void)
+jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JCOPY_OPTION option)
+{
+ jpeg_saved_marker_ptr marker;
+
+ /* In the current implementation, we don't actually need to examine the
+ * option flag here; we just copy everything that got saved.
+ * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
+ * if the encoder library already wrote one.
+ */
+ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (dstinfo->write_JFIF_header &&
+ marker->marker == JPEG_APP0 &&
+ marker->data_length >= 5 &&
+ GETJOCTET(marker->data[0]) == 0x4A &&
+ GETJOCTET(marker->data[1]) == 0x46 &&
+ GETJOCTET(marker->data[2]) == 0x49 &&
+ GETJOCTET(marker->data[3]) == 0x46 &&
+ GETJOCTET(marker->data[4]) == 0)
+ continue; /* reject duplicate JFIF */
+ if (dstinfo->write_Adobe_marker &&
+ marker->marker == JPEG_APP0+14 &&
+ marker->data_length >= 5 &&
+ GETJOCTET(marker->data[0]) == 0x41 &&
+ GETJOCTET(marker->data[1]) == 0x64 &&
+ GETJOCTET(marker->data[2]) == 0x6F &&
+ GETJOCTET(marker->data[3]) == 0x62 &&
+ GETJOCTET(marker->data[4]) == 0x65)
+ continue; /* reject duplicate Adobe */
+#ifdef NEED_FAR_POINTERS
+ /* We could use jpeg_write_marker if the data weren't FAR... */
+ {
+ unsigned int i;
+ jpeg_write_m_header(dstinfo, marker->marker, marker->data_length);
+ for (i = 0; i < marker->data_length; i++)
+ jpeg_write_m_byte(dstinfo, marker->data[i]);
+ }
+#else
+ jpeg_write_marker(dstinfo, marker->marker,
+ marker->data, marker->data_length);
+#endif
+ }
+}
diff --git a/jpg/transupp.h b/jpg/transupp.h
new file mode 100644
index 0000000..9aa0af3
--- /dev/null
+++ b/jpg/transupp.h
@@ -0,0 +1,213 @@
+/*
+ * transupp.h
+ *
+ * Copyright (C) 1997-2011, Thomas G. Lane, Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains declarations for image transformation routines and
+ * other utility code used by the jpegtran sample application. These are
+ * NOT part of the core JPEG library. But we keep these routines separate
+ * from jpegtran.c to ease the task of maintaining jpegtran-like programs
+ * that have other user interfaces.
+ *
+ * NOTE: all the routines declared here have very specific requirements
+ * about when they are to be executed during the reading and writing of the
+ * source and destination files. See the comments in transupp.c, or see
+ * jpegtran.c for an example of correct usage.
+ */
+
+/* If you happen not to want the image transform support, disable it here */
+#ifndef TRANSFORMS_SUPPORTED
+#define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */
+#endif
+
+/*
+ * Although rotating and flipping data expressed as DCT coefficients is not
+ * hard, there is an asymmetry in the JPEG format specification for images
+ * whose dimensions aren't multiples of the iMCU size. The right and bottom
+ * image edges are padded out to the next iMCU boundary with junk data; but
+ * no padding is possible at the top and left edges. If we were to flip
+ * the whole image including the pad data, then pad garbage would become
+ * visible at the top and/or left, and real pixels would disappear into the
+ * pad margins --- perhaps permanently, since encoders & decoders may not
+ * bother to preserve DCT blocks that appear to be completely outside the
+ * nominal image area. So, we have to exclude any partial iMCUs from the
+ * basic transformation.
+ *
+ * Transpose is the only transformation that can handle partial iMCUs at the
+ * right and bottom edges completely cleanly. flip_h can flip partial iMCUs
+ * at the bottom, but leaves any partial iMCUs at the right edge untouched.
+ * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched.
+ * The other transforms are defined as combinations of these basic transforms
+ * and process edge blocks in a way that preserves the equivalence.
+ *
+ * The "trim" option causes untransformable partial iMCUs to be dropped;
+ * this is not strictly lossless, but it usually gives the best-looking
+ * result for odd-size images. Note that when this option is active,
+ * the expected mathematical equivalences between the transforms may not hold.
+ * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim
+ * followed by -rot 180 -trim trims both edges.)
+ *
+ * We also offer a lossless-crop option, which discards data outside a given
+ * image region but losslessly preserves what is inside. Like the rotate and
+ * flip transforms, lossless crop is restricted by the JPEG format: the upper
+ * left corner of the selected region must fall on an iMCU boundary. If this
+ * does not hold for the given crop parameters, we silently move the upper left
+ * corner up and/or left to make it so, simultaneously increasing the region
+ * dimensions to keep the lower right crop corner unchanged. (Thus, the
+ * output image covers at least the requested region, but may cover more.)
+ * The adjustment of the region dimensions may be optionally disabled.
+ *
+ * We also provide a lossless-resize option, which is kind of a lossless-crop
+ * operation in the DCT coefficient block domain - it discards higher-order
+ * coefficients and losslessly preserves lower-order coefficients of a
+ * sub-block.
+ *
+ * Rotate/flip transform, resize, and crop can be requested together in a
+ * single invocation. The crop is applied last --- that is, the crop region
+ * is specified in terms of the destination image after transform/resize.
+ *
+ * We also offer a "force to grayscale" option, which simply discards the
+ * chrominance channels of a YCbCr image. This is lossless in the sense that
+ * the luminance channel is preserved exactly. It's not the same kind of
+ * thing as the rotate/flip transformations, but it's convenient to handle it
+ * as part of this package, mainly because the transformation routines have to
+ * be aware of the option to know how many components to work on.
+ */
+
+
+/* Short forms of external names for systems with brain-damaged linkers. */
+
+#ifdef NEED_SHORT_EXTERNAL_NAMES
+#define jtransform_parse_crop_spec jTrParCrop
+#define jtransform_request_workspace jTrRequest
+#define jtransform_adjust_parameters jTrAdjust
+#define jtransform_execute_transform jTrExec
+#define jtransform_perfect_transform jTrPerfect
+#define jcopy_markers_setup jCMrkSetup
+#define jcopy_markers_execute jCMrkExec
+#endif /* NEED_SHORT_EXTERNAL_NAMES */
+
+
+/*
+ * Codes for supported types of image transformations.
+ */
+
+typedef enum {
+ JXFORM_NONE, /* no transformation */
+ JXFORM_FLIP_H, /* horizontal flip */
+ JXFORM_FLIP_V, /* vertical flip */
+ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */
+ JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */
+ JXFORM_ROT_90, /* 90-degree clockwise rotation */
+ JXFORM_ROT_180, /* 180-degree rotation */
+ JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */
+} JXFORM_CODE;
+
+/*
+ * Codes for crop parameters, which can individually be unspecified,
+ * positive or negative for xoffset or yoffset,
+ * positive or forced for width or height.
+ */
+
+typedef enum {
+ JCROP_UNSET,
+ JCROP_POS,
+ JCROP_NEG,
+ JCROP_FORCE
+} JCROP_CODE;
+
+/*
+ * Transform parameters struct.
+ * NB: application must not change any elements of this struct after
+ * calling jtransform_request_workspace.
+ */
+
+typedef struct {
+ /* Options: set by caller */
+ JXFORM_CODE transform; /* image transform operator */
+ boolean perfect; /* if TRUE, fail if partial MCUs are requested */
+ boolean trim; /* if TRUE, trim partial MCUs as needed */
+ boolean force_grayscale; /* if TRUE, convert color image to grayscale */
+ boolean crop; /* if TRUE, crop source image */
+
+ /* Crop parameters: application need not set these unless crop is TRUE.
+ * These can be filled in by jtransform_parse_crop_spec().
+ */
+ JDIMENSION crop_width; /* Width of selected region */
+ JCROP_CODE crop_width_set; /* (forced disables adjustment) */
+ JDIMENSION crop_height; /* Height of selected region */
+ JCROP_CODE crop_height_set; /* (forced disables adjustment) */
+ JDIMENSION crop_xoffset; /* X offset of selected region */
+ JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */
+ JDIMENSION crop_yoffset; /* Y offset of selected region */
+ JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */
+
+ /* Internal workspace: caller should not touch these */
+ int num_components; /* # of components in workspace */
+ jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */
+ JDIMENSION output_width; /* cropped destination dimensions */
+ JDIMENSION output_height;
+ JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */
+ JDIMENSION y_crop_offset;
+ int iMCU_sample_width; /* destination iMCU size */
+ int iMCU_sample_height;
+} jpeg_transform_info;
+
+
+#if TRANSFORMS_SUPPORTED
+
+/* Parse a crop specification (written in X11 geometry style) */
+EXTERN(boolean) jtransform_parse_crop_spec
+ JPP((jpeg_transform_info *info, const char *spec));
+/* Request any required workspace */
+EXTERN(boolean) jtransform_request_workspace
+ JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info));
+/* Adjust output image parameters */
+EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters
+ JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ jvirt_barray_ptr *src_coef_arrays,
+ jpeg_transform_info *info));
+/* Execute the actual transformation, if any */
+EXTERN(void) jtransform_execute_transform
+ JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ jvirt_barray_ptr *src_coef_arrays,
+ jpeg_transform_info *info));
+/* Determine whether lossless transformation is perfectly
+ * possible for a specified image and transformation.
+ */
+EXTERN(boolean) jtransform_perfect_transform
+ JPP((JDIMENSION image_width, JDIMENSION image_height,
+ int MCU_width, int MCU_height,
+ JXFORM_CODE transform));
+
+/* jtransform_execute_transform used to be called
+ * jtransform_execute_transformation, but some compilers complain about
+ * routine names that long. This macro is here to avoid breaking any
+ * old source code that uses the original name...
+ */
+#define jtransform_execute_transformation jtransform_execute_transform
+
+#endif /* TRANSFORMS_SUPPORTED */
+
+
+/*
+ * Support for copying optional markers from source to destination file.
+ */
+
+typedef enum {
+ JCOPYOPT_NONE, /* copy no optional markers */
+ JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */
+ JCOPYOPT_ALL /* copy all optional markers */
+} JCOPY_OPTION;
+
+#define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */
+
+/* Setup decompression object to save desired markers in memory */
+EXTERN(void) jcopy_markers_setup
+ JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option));
+/* Copy markers saved in the given source object to the destination object */
+EXTERN(void) jcopy_markers_execute
+ JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
+ JCOPY_OPTION option));
diff --git a/jpg/usage.txt b/jpg/usage.txt
new file mode 100644
index 0000000..de9def7
--- /dev/null
+++ b/jpg/usage.txt
@@ -0,0 +1,637 @@
+USAGE instructions for the Independent JPEG Group's JPEG software
+=================================================================
+
+This file describes usage of the JPEG conversion programs cjpeg and djpeg,
+as well as the utility programs jpegtran, rdjpgcom and wrjpgcom. (See
+the other documentation files if you wish to use the JPEG library within
+your own programs.)
+
+If you are on a Unix machine you may prefer to read the Unix-style manual
+pages in files cjpeg.1, djpeg.1, jpegtran.1, rdjpgcom.1, wrjpgcom.1.
+
+
+INTRODUCTION
+
+These programs implement JPEG image encoding, decoding, and transcoding.
+JPEG (pronounced "jay-peg") is a standardized compression method for
+full-color and gray-scale images.
+
+
+GENERAL USAGE
+
+We provide two programs, cjpeg to compress an image file into JPEG format,
+and djpeg to decompress a JPEG file back into a conventional image format.
+
+On Unix-like systems, you say:
+ cjpeg [switches] [imagefile] >jpegfile
+or
+ djpeg [switches] [jpegfile] >imagefile
+The programs read the specified input file, or standard input if none is
+named. They always write to standard output (with trace/error messages to
+standard error). These conventions are handy for piping images between
+programs.
+
+On most non-Unix systems, you say:
+ cjpeg [switches] imagefile jpegfile
+or
+ djpeg [switches] jpegfile imagefile
+i.e., both the input and output files are named on the command line. This
+style is a little more foolproof, and it loses no functionality if you don't
+have pipes. (You can get this style on Unix too, if you prefer, by defining
+TWO_FILE_COMMANDLINE when you compile the programs; see install.txt.)
+
+You can also say:
+ cjpeg [switches] -outfile jpegfile imagefile
+or
+ djpeg [switches] -outfile imagefile jpegfile
+This syntax works on all systems, so it is useful for scripts.
+
+The currently supported image file formats are: PPM (PBMPLUS color format),
+PGM (PBMPLUS gray-scale format), BMP, Targa, and RLE (Utah Raster Toolkit
+format). (RLE is supported only if the URT library is available.)
+cjpeg recognizes the input image format automatically, with the exception
+of some Targa-format files. You have to tell djpeg which format to generate.
+
+JPEG files are in the defacto standard JFIF file format. There are other,
+less widely used JPEG-based file formats, but we don't support them.
+
+All switch names may be abbreviated; for example, -grayscale may be written
+-gray or -gr. Most of the "basic" switches can be abbreviated to as little as
+one letter. Upper and lower case are equivalent (-BMP is the same as -bmp).
+British spellings are also accepted (e.g., -greyscale), though for brevity
+these are not mentioned below.
+
+
+CJPEG DETAILS
+
+The basic command line switches for cjpeg are:
+
+ -quality N[,...] Scale quantization tables to adjust image quality.
+ Quality is 0 (worst) to 100 (best); default is 75.
+ (See below for more info.)
+
+ -grayscale Create monochrome JPEG file from color input.
+ Be sure to use this switch when compressing a grayscale
+ BMP file, because cjpeg isn't bright enough to notice
+ whether a BMP file uses only shades of gray. By
+ saying -grayscale, you'll get a smaller JPEG file that
+ takes less time to process.
+
+ -rgb Create RGB JPEG file.
+ Using this switch suppresses the conversion from RGB
+ colorspace input to the default YCbCr JPEG colorspace.
+ Use this switch in combination with the -block N
+ switch (see below) for lossless JPEG coding.
+
+ -optimize Perform optimization of entropy encoding parameters.
+ Without this, default encoding parameters are used.
+ -optimize usually makes the JPEG file a little smaller,
+ but cjpeg runs somewhat slower and needs much more
+ memory. Image quality and speed of decompression are
+ unaffected by -optimize.
+
+ -progressive Create progressive JPEG file (see below).
+
+ -scale M/N Scale the output image by a factor M/N. Currently
+ supported scale factors are M/N with all N from 1 to
+ 16, where M is the destination DCT size, which is 8 by
+ default (see -block N switch below).
+
+ -targa Input file is Targa format. Targa files that contain
+ an "identification" field will not be automatically
+ recognized by cjpeg; for such files you must specify
+ -targa to make cjpeg treat the input as Targa format.
+ For most Targa files, you won't need this switch.
+
+The -quality switch lets you trade off compressed file size against quality of
+the reconstructed image: the higher the quality setting, the larger the JPEG
+file, and the closer the output image will be to the original input. Normally
+you want to use the lowest quality setting (smallest file) that decompresses
+into something visually indistinguishable from the original image. For this
+purpose the quality setting should be between 50 and 95; the default of 75 is
+often about right. If you see defects at -quality 75, then go up 5 or 10
+counts at a time until you are happy with the output image. (The optimal
+setting will vary from one image to another.)
+
+-quality 100 will generate a quantization table of all 1's, minimizing loss
+in the quantization step (but there is still information loss in subsampling,
+as well as roundoff error). This setting is mainly of interest for
+experimental purposes. Quality values above about 95 are NOT recommended for
+normal use; the compressed file size goes up dramatically for hardly any gain
+in output image quality.
+
+In the other direction, quality values below 50 will produce very small files
+of low image quality. Settings around 5 to 10 might be useful in preparing an
+index of a large image library, for example. Try -quality 2 (or so) for some
+amusing Cubist effects. (Note: quality values below about 25 generate 2-byte
+quantization tables, which are considered optional in the JPEG standard.
+cjpeg emits a warning message when you give such a quality value, because some
+other JPEG programs may be unable to decode the resulting file. Use -baseline
+if you need to ensure compatibility at low quality values.)
+
+The -quality option has been extended in IJG version 7 for support of separate
+quality settings for luminance and chrominance (or in general, for every
+provided quantization table slot). This feature is useful for high-quality
+applications which cannot accept the damage of color data by coarse
+subsampling settings. You can now easily reduce the color data amount more
+smoothly with finer control without separate subsampling. The resulting file
+is fully compliant with standard JPEG decoders.
+Note that the -quality ratings refer to the quantization table slots, and that
+the last value is replicated if there are more q-table slots than parameters.
+The default q-table slots are 0 for luminance and 1 for chrominance with
+default tables as given in the JPEG standard. This is compatible with the old
+behaviour in case that only one parameter is given, which is then used for
+both luminance and chrominance (slots 0 and 1). More or custom quantization
+tables can be set with -qtables and assigned to components with -qslots
+parameter (see the "wizard" switches below).
+CAUTION: You must explicitly add -sample 1x1 for efficient separate color
+quality selection, since the default value used by library is 2x2!
+
+The -progressive switch creates a "progressive JPEG" file. In this type of
+JPEG file, the data is stored in multiple scans of increasing quality. If the
+file is being transmitted over a slow communications link, the decoder can use
+the first scan to display a low-quality image very quickly, and can then
+improve the display with each subsequent scan. The final image is exactly
+equivalent to a standard JPEG file of the same quality setting, and the total
+file size is about the same --- often a little smaller.
+
+Switches for advanced users:
+
+ -arithmetic Use arithmetic coding. CAUTION: arithmetic coded JPEG
+ is not yet widely implemented, so many decoders will
+ be unable to view an arithmetic coded JPEG file at
+ all.
+
+ -block N Set DCT block size. All N from 1 to 16 are possible.
+ Default is 8 (baseline format).
+ Larger values produce higher compression,
+ smaller values produce higher quality
+ (exact DCT stage possible with 1 or 2; with the
+ default quality of 75 and default Luminance qtable
+ the DCT+Quantization stage is lossless for N=1).
+ CAUTION: An implementation of the JPEG SmartScale
+ extension is required for this feature. SmartScale
+ enabled JPEG is not yet widely implemented, so many
+ decoders will be unable to view a SmartScale extended
+ JPEG file at all.
+
+ -dct int Use integer DCT method (default).
+ -dct fast Use fast integer DCT (less accurate).
+ -dct float Use floating-point DCT method.
+ The float method is very slightly more accurate than
+ the int method, but is much slower unless your machine
+ has very fast floating-point hardware. Also note that
+ results of the floating-point method may vary slightly
+ across machines, while the integer methods should give
+ the same results everywhere. The fast integer method
+ is much less accurate than the other two.
+
+ -nosmooth Don't use high-quality downsampling.
+
+ -restart N Emit a JPEG restart marker every N MCU rows, or every
+ N MCU blocks if "B" is attached to the number.
+ -restart 0 (the default) means no restart markers.
+
+ -smooth N Smooth the input image to eliminate dithering noise.
+ N, ranging from 1 to 100, indicates the strength of
+ smoothing. 0 (the default) means no smoothing.
+
+ -maxmemory N Set limit for amount of memory to use in processing
+ large images. Value is in thousands of bytes, or
+ millions of bytes if "M" is attached to the number.
+ For example, -max 4m selects 4000000 bytes. If more
+ space is needed, temporary files will be used.
+
+ -verbose Enable debug printout. More -v's give more printout.
+ or -debug Also, version information is printed at startup.
+
+The -restart option inserts extra markers that allow a JPEG decoder to
+resynchronize after a transmission error. Without restart markers, any damage
+to a compressed file will usually ruin the image from the point of the error
+to the end of the image; with restart markers, the damage is usually confined
+to the portion of the image up to the next restart marker. Of course, the
+restart markers occupy extra space. We recommend -restart 1 for images that
+will be transmitted across unreliable networks such as Usenet.
+
+The -smooth option filters the input to eliminate fine-scale noise. This is
+often useful when converting dithered images to JPEG: a moderate smoothing
+factor of 10 to 50 gets rid of dithering patterns in the input file, resulting
+in a smaller JPEG file and a better-looking image. Too large a smoothing
+factor will visibly blur the image, however.
+
+Switches for wizards:
+
+ -baseline Force baseline-compatible quantization tables to be
+ generated. This clamps quantization values to 8 bits
+ even at low quality settings. (This switch is poorly
+ named, since it does not ensure that the output is
+ actually baseline JPEG. For example, you can use
+ -baseline and -progressive together.)
+
+ -qtables file Use the quantization tables given in the specified
+ text file.
+
+ -qslots N[,...] Select which quantization table to use for each color
+ component.
+
+ -sample HxV[,...] Set JPEG sampling factors for each color component.
+
+ -scans file Use the scan script given in the specified text file.
+
+The "wizard" switches are intended for experimentation with JPEG. If you
+don't know what you are doing, DON'T USE THEM. These switches are documented
+further in the file wizard.txt.
+
+
+DJPEG DETAILS
+
+The basic command line switches for djpeg are:
+
+ -colors N Reduce image to at most N colors. This reduces the
+ or -quantize N number of colors used in the output image, so that it
+ can be displayed on a colormapped display or stored in
+ a colormapped file format. For example, if you have
+ an 8-bit display, you'd need to reduce to 256 or fewer
+ colors. (-colors is the recommended name, -quantize
+ is provided only for backwards compatibility.)
+
+ -fast Select recommended processing options for fast, low
+ quality output. (The default options are chosen for
+ highest quality output.) Currently, this is equivalent
+ to "-dct fast -nosmooth -onepass -dither ordered".
+
+ -grayscale Force gray-scale output even if JPEG file is color.
+ Useful for viewing on monochrome displays; also,
+ djpeg runs noticeably faster in this mode.
+
+ -scale M/N Scale the output image by a factor M/N. Currently
+ supported scale factors are M/N with all M from 1 to
+ 16, where N is the source DCT size, which is 8 for
+ baseline JPEG. If the /N part is omitted, then M
+ specifies the DCT scaled size to be applied on the
+ given input. For baseline JPEG this is equivalent to
+ M/8 scaling, since the source DCT size for baseline
+ JPEG is 8. Scaling is handy if the image is larger
+ than your screen; also, djpeg runs much faster when
+ scaling down the output.
+
+ -bmp Select BMP output format (Windows flavor). 8-bit
+ colormapped format is emitted if -colors or -grayscale
+ is specified, or if the JPEG file is gray-scale;
+ otherwise, 24-bit full-color format is emitted.
+
+ -gif Select GIF output format. Since GIF does not support
+ more than 256 colors, -colors 256 is assumed (unless
+ you specify a smaller number of colors). If you
+ specify -fast, the default number of colors is 216.
+
+ -os2 Select BMP output format (OS/2 1.x flavor). 8-bit
+ colormapped format is emitted if -colors or -grayscale
+ is specified, or if the JPEG file is gray-scale;
+ otherwise, 24-bit full-color format is emitted.
+
+ -pnm Select PBMPLUS (PPM/PGM) output format (this is the
+ default format). PGM is emitted if the JPEG file is
+ gray-scale or if -grayscale is specified; otherwise
+ PPM is emitted.
+
+ -rle Select RLE output format. (Requires URT library.)
+
+ -targa Select Targa output format. Gray-scale format is
+ emitted if the JPEG file is gray-scale or if
+ -grayscale is specified; otherwise, colormapped format
+ is emitted if -colors is specified; otherwise, 24-bit
+ full-color format is emitted.
+
+Switches for advanced users:
+
+ -dct int Use integer DCT method (default).
+ -dct fast Use fast integer DCT (less accurate).
+ -dct float Use floating-point DCT method.
+ The float method is very slightly more accurate than
+ the int method, but is much slower unless your machine
+ has very fast floating-point hardware. Also note that
+ results of the floating-point method may vary slightly
+ across machines, while the integer methods should give
+ the same results everywhere. The fast integer method
+ is much less accurate than the other two.
+
+ -dither fs Use Floyd-Steinberg dithering in color quantization.
+ -dither ordered Use ordered dithering in color quantization.
+ -dither none Do not use dithering in color quantization.
+ By default, Floyd-Steinberg dithering is applied when
+ quantizing colors; this is slow but usually produces
+ the best results. Ordered dither is a compromise
+ between speed and quality; no dithering is fast but
+ usually looks awful. Note that these switches have
+ no effect unless color quantization is being done.
+ Ordered dither is only available in -onepass mode.
+
+ -map FILE Quantize to the colors used in the specified image
+ file. This is useful for producing multiple files
+ with identical color maps, or for forcing a predefined
+ set of colors to be used. The FILE must be a GIF
+ or PPM file. This option overrides -colors and
+ -onepass.
+
+ -nosmooth Don't use high-quality upsampling.
+
+ -onepass Use one-pass instead of two-pass color quantization.
+ The one-pass method is faster and needs less memory,
+ but it produces a lower-quality image. -onepass is
+ ignored unless you also say -colors N. Also,
+ the one-pass method is always used for gray-scale
+ output (the two-pass method is no improvement then).
+
+ -maxmemory N Set limit for amount of memory to use in processing
+ large images. Value is in thousands of bytes, or
+ millions of bytes if "M" is attached to the number.
+ For example, -max 4m selects 4000000 bytes. If more
+ space is needed, temporary files will be used.
+
+ -verbose Enable debug printout. More -v's give more printout.
+ or -debug Also, version information is printed at startup.
+
+
+HINTS FOR CJPEG
+
+Color GIF files are not the ideal input for JPEG; JPEG is really intended for
+compressing full-color (24-bit) images. In particular, don't try to convert
+cartoons, line drawings, and other images that have only a few distinct
+colors. GIF works great on these, JPEG does not. If you want to convert a
+GIF to JPEG, you should experiment with cjpeg's -quality and -smooth options
+to get a satisfactory conversion. -smooth 10 or so is often helpful.
+
+Avoid running an image through a series of JPEG compression/decompression
+cycles. Image quality loss will accumulate; after ten or so cycles the image
+may be noticeably worse than it was after one cycle. It's best to use a
+lossless format while manipulating an image, then convert to JPEG format when
+you are ready to file the image away.
+
+The -optimize option to cjpeg is worth using when you are making a "final"
+version for posting or archiving. It's also a win when you are using low
+quality settings to make very small JPEG files; the percentage improvement
+is often a lot more than it is on larger files. (At present, -optimize
+mode is always selected when generating progressive JPEG files.)
+
+GIF input files are no longer supported, to avoid the Unisys LZW patent.
+(Conversion of GIF files to JPEG is usually a bad idea anyway.)
+
+
+HINTS FOR DJPEG
+
+To get a quick preview of an image, use the -grayscale and/or -scale switches.
+"-grayscale -scale 1/8" is the fastest case.
+
+Several options are available that trade off image quality to gain speed.
+"-fast" turns on the recommended settings.
+
+"-dct fast" and/or "-nosmooth" gain speed at a small sacrifice in quality.
+When producing a color-quantized image, "-onepass -dither ordered" is fast but
+much lower quality than the default behavior. "-dither none" may give
+acceptable results in two-pass mode, but is seldom tolerable in one-pass mode.
+
+If you are fortunate enough to have very fast floating point hardware,
+"-dct float" may be even faster than "-dct fast". But on most machines
+"-dct float" is slower than "-dct int"; in this case it is not worth using,
+because its theoretical accuracy advantage is too small to be significant
+in practice.
+
+Two-pass color quantization requires a good deal of memory; on MS-DOS machines
+it may run out of memory even with -maxmemory 0. In that case you can still
+decompress, with some loss of image quality, by specifying -onepass for
+one-pass quantization.
+
+To avoid the Unisys LZW patent, djpeg produces uncompressed GIF files. These
+are larger than they should be, but are readable by standard GIF decoders.
+
+
+HINTS FOR BOTH PROGRAMS
+
+If more space is needed than will fit in the available main memory (as
+determined by -maxmemory), temporary files will be used. (MS-DOS versions
+will try to get extended or expanded memory first.) The temporary files are
+often rather large: in typical cases they occupy three bytes per pixel, for
+example 3*800*600 = 1.44Mb for an 800x600 image. If you don't have enough
+free disk space, leave out -progressive and -optimize (for cjpeg) or specify
+-onepass (for djpeg).
+
+On MS-DOS, the temporary files are created in the directory named by the TMP
+or TEMP environment variable, or in the current directory if neither of those
+exist. Amiga implementations put the temp files in the directory named by
+JPEGTMP:, so be sure to assign JPEGTMP: to a disk partition with adequate free
+space.
+
+The default memory usage limit (-maxmemory) is set when the software is
+compiled. If you get an "insufficient memory" error, try specifying a smaller
+-maxmemory value, even -maxmemory 0 to use the absolute minimum space. You
+may want to recompile with a smaller default value if this happens often.
+
+On machines that have "environment" variables, you can define the environment
+variable JPEGMEM to set the default memory limit. The value is specified as
+described for the -maxmemory switch. JPEGMEM overrides the default value
+specified when the program was compiled, and itself is overridden by an
+explicit -maxmemory switch.
+
+On MS-DOS machines, -maxmemory is the amount of main (conventional) memory to
+use. (Extended or expanded memory is also used if available.) Most
+DOS-specific versions of this software do their own memory space estimation
+and do not need you to specify -maxmemory.
+
+
+JPEGTRAN
+
+jpegtran performs various useful transformations of JPEG files.
+It can translate the coded representation from one variant of JPEG to another,
+for example from baseline JPEG to progressive JPEG or vice versa. It can also
+perform some rearrangements of the image data, for example turning an image
+from landscape to portrait format by rotation.
+
+jpegtran works by rearranging the compressed data (DCT coefficients), without
+ever fully decoding the image. Therefore, its transformations are lossless:
+there is no image degradation at all, which would not be true if you used
+djpeg followed by cjpeg to accomplish the same conversion. But by the same
+token, jpegtran cannot perform lossy operations such as changing the image
+quality.
+
+jpegtran uses a command line syntax similar to cjpeg or djpeg.
+On Unix-like systems, you say:
+ jpegtran [switches] [inputfile] >outputfile
+On most non-Unix systems, you say:
+ jpegtran [switches] inputfile outputfile
+where both the input and output files are JPEG files.
+
+To specify the coded JPEG representation used in the output file,
+jpegtran accepts a subset of the switches recognized by cjpeg:
+ -optimize Perform optimization of entropy encoding parameters.
+ -progressive Create progressive JPEG file.
+ -arithmetic Use arithmetic coding.
+ -restart N Emit a JPEG restart marker every N MCU rows, or every
+ N MCU blocks if "B" is attached to the number.
+ -scans file Use the scan script given in the specified text file.
+See the previous discussion of cjpeg for more details about these switches.
+If you specify none of these switches, you get a plain baseline-JPEG output
+file. The quality setting and so forth are determined by the input file.
+
+The image can be losslessly transformed by giving one of these switches:
+ -flip horizontal Mirror image horizontally (left-right).
+ -flip vertical Mirror image vertically (top-bottom).
+ -rotate 90 Rotate image 90 degrees clockwise.
+ -rotate 180 Rotate image 180 degrees.
+ -rotate 270 Rotate image 270 degrees clockwise (or 90 ccw).
+ -transpose Transpose image (across UL-to-LR axis).
+ -transverse Transverse transpose (across UR-to-LL axis).
+
+The transpose transformation has no restrictions regarding image dimensions.
+The other transformations operate rather oddly if the image dimensions are not
+a multiple of the iMCU size (usually 8 or 16 pixels), because they can only
+transform complete blocks of DCT coefficient data in the desired way.
+
+jpegtran's default behavior when transforming an odd-size image is designed
+to preserve exact reversibility and mathematical consistency of the
+transformation set. As stated, transpose is able to flip the entire image
+area. Horizontal mirroring leaves any partial iMCU column at the right edge
+untouched, but is able to flip all rows of the image. Similarly, vertical
+mirroring leaves any partial iMCU row at the bottom edge untouched, but is
+able to flip all columns. The other transforms can be built up as sequences
+of transpose and flip operations; for consistency, their actions on edge
+pixels are defined to be the same as the end result of the corresponding
+transpose-and-flip sequence.
+
+For practical use, you may prefer to discard any untransformable edge pixels
+rather than having a strange-looking strip along the right and/or bottom edges
+of a transformed image. To do this, add the -trim switch:
+ -trim Drop non-transformable edge blocks.
+Obviously, a transformation with -trim is not reversible, so strictly speaking
+jpegtran with this switch is not lossless. Also, the expected mathematical
+equivalences between the transformations no longer hold. For example,
+"-rot 270 -trim" trims only the bottom edge, but "-rot 90 -trim" followed by
+"-rot 180 -trim" trims both edges.
+
+If you are only interested in perfect transformation, add the -perfect switch:
+ -perfect Fails with an error if the transformation is not
+ perfect.
+For example you may want to do
+ jpegtran -rot 90 -perfect foo.jpg || djpeg foo.jpg | pnmflip -r90 | cjpeg
+to do a perfect rotation if available or an approximated one if not.
+
+We also offer a lossless-crop option, which discards data outside a given
+image region but losslessly preserves what is inside. Like the rotate and
+flip transforms, lossless crop is restricted by the current JPEG format: the
+upper left corner of the selected region must fall on an iMCU boundary. If
+this does not hold for the given crop parameters, we silently move the upper
+left corner up and/or left to make it so, simultaneously increasing the region
+dimensions to keep the lower right crop corner unchanged. (Thus, the output
+image covers at least the requested region, but may cover more.)
+
+The image can be losslessly cropped by giving the switch:
+ -crop WxH+X+Y Crop to a rectangular subarea of width W, height H
+ starting at point X,Y.
+
+Other not-strictly-lossless transformation switches are:
+
+ -grayscale Force grayscale output.
+This option discards the chrominance channels if the input image is YCbCr
+(ie, a standard color JPEG), resulting in a grayscale JPEG file. The
+luminance channel is preserved exactly, so this is a better method of reducing
+to grayscale than decompression, conversion, and recompression. This switch
+is particularly handy for fixing a monochrome picture that was mistakenly
+encoded as a color JPEG. (In such a case, the space savings from getting rid
+of the near-empty chroma channels won't be large; but the decoding time for
+a grayscale JPEG is substantially less than that for a color JPEG.)
+
+ -scale M/N Scale the output image by a factor M/N.
+Currently supported scale factors are M/N with all M from 1 to 16, where N is
+the source DCT size, which is 8 for baseline JPEG. If the /N part is omitted,
+then M specifies the DCT scaled size to be applied on the given input. For
+baseline JPEG this is equivalent to M/8 scaling, since the source DCT size
+for baseline JPEG is 8. CAUTION: An implementation of the JPEG SmartScale
+extension is required for this feature. SmartScale enabled JPEG is not yet
+widely implemented, so many decoders will be unable to view a SmartScale
+extended JPEG file at all.
+
+jpegtran also recognizes these switches that control what to do with "extra"
+markers, such as comment blocks:
+ -copy none Copy no extra markers from source file. This setting
+ suppresses all comments and other excess baggage
+ present in the source file.
+ -copy comments Copy only comment markers. This setting copies
+ comments from the source file, but discards
+ any other inessential (for image display) data.
+ -copy all Copy all extra markers. This setting preserves
+ miscellaneous markers found in the source file, such
+ as JFIF thumbnails, Exif data, and Photoshop settings.
+ In some files these extra markers can be sizable.
+The default behavior is -copy comments. (Note: in IJG releases v6 and v6a,
+jpegtran always did the equivalent of -copy none.)
+
+Additional switches recognized by jpegtran are:
+ -outfile filename
+ -maxmemory N
+ -verbose
+ -debug
+These work the same as in cjpeg or djpeg.
+
+
+THE COMMENT UTILITIES
+
+The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
+Although the standard doesn't actually define what COM blocks are for, they
+are widely used to hold user-supplied text strings. This lets you add
+annotations, titles, index terms, etc to your JPEG files, and later retrieve
+them as text. COM blocks do not interfere with the image stored in the JPEG
+file. The maximum size of a COM block is 64K, but you can have as many of
+them as you like in one JPEG file.
+
+We provide two utility programs to display COM block contents and add COM
+blocks to a JPEG file.
+
+rdjpgcom searches a JPEG file and prints the contents of any COM blocks on
+standard output. The command line syntax is
+ rdjpgcom [-raw] [-verbose] [inputfilename]
+The switch "-raw" (or just "-r") causes rdjpgcom to also output non-printable
+characters in comments, which are normally escaped for security reasons.
+The switch "-verbose" (or just "-v") causes rdjpgcom to also display the JPEG
+image dimensions. If you omit the input file name from the command line,
+the JPEG file is read from standard input. (This may not work on some
+operating systems, if binary data can't be read from stdin.)
+
+wrjpgcom adds a COM block, containing text you provide, to a JPEG file.
+Ordinarily, the COM block is added after any existing COM blocks, but you
+can delete the old COM blocks if you wish. wrjpgcom produces a new JPEG
+file; it does not modify the input file. DO NOT try to overwrite the input
+file by directing wrjpgcom's output back into it; on most systems this will
+just destroy your file.
+
+The command line syntax for wrjpgcom is similar to cjpeg's. On Unix-like
+systems, it is
+ wrjpgcom [switches] [inputfilename]
+The output file is written to standard output. The input file comes from
+the named file, or from standard input if no input file is named.
+
+On most non-Unix systems, the syntax is
+ wrjpgcom [switches] inputfilename outputfilename
+where both input and output file names must be given explicitly.
+
+wrjpgcom understands three switches:
+ -replace Delete any existing COM blocks from the file.
+ -comment "Comment text" Supply new COM text on command line.
+ -cfile name Read text for new COM block from named file.
+(Switch names can be abbreviated.) If you have only one line of comment text
+to add, you can provide it on the command line with -comment. The comment
+text must be surrounded with quotes so that it is treated as a single
+argument. Longer comments can be read from a text file.
+
+If you give neither -comment nor -cfile, then wrjpgcom will read the comment
+text from standard input. (In this case an input image file name MUST be
+supplied, so that the source JPEG file comes from somewhere else.) You can
+enter multiple lines, up to 64KB worth. Type an end-of-file indicator
+(usually control-D or control-Z) to terminate the comment text entry.
+
+wrjpgcom will not add a COM block if the provided comment string is empty.
+Therefore -replace -comment "" can be used to delete all COM blocks from a
+file.
+
+These utility programs do not depend on the IJG JPEG library. In
+particular, the source code for rdjpgcom is intended as an illustration of
+the minimum amount of code required to parse a JPEG file header correctly.
diff --git a/jpg/wizard.txt b/jpg/wizard.txt
new file mode 100644
index 0000000..54170b2
--- /dev/null
+++ b/jpg/wizard.txt
@@ -0,0 +1,211 @@
+Advanced usage instructions for the Independent JPEG Group's JPEG software
+==========================================================================
+
+This file describes cjpeg's "switches for wizards".
+
+The "wizard" switches are intended for experimentation with JPEG by persons
+who are reasonably knowledgeable about the JPEG standard. If you don't know
+what you are doing, DON'T USE THESE SWITCHES. You'll likely produce files
+with worse image quality and/or poorer compression than you'd get from the
+default settings. Furthermore, these switches must be used with caution
+when making files intended for general use, because not all JPEG decoders
+will support unusual JPEG parameter settings.
+
+
+Quantization Table Adjustment
+-----------------------------
+
+Ordinarily, cjpeg starts with a default set of tables (the same ones given
+as examples in the JPEG standard) and scales them up or down according to
+the -quality setting. The details of the scaling algorithm can be found in
+jcparam.c. At very low quality settings, some quantization table entries
+can get scaled up to values exceeding 255. Although 2-byte quantization
+values are supported by the IJG software, this feature is not in baseline
+JPEG and is not supported by all implementations. If you need to ensure
+wide compatibility of low-quality files, you can constrain the scaled
+quantization values to no more than 255 by giving the -baseline switch.
+Note that use of -baseline will result in poorer quality for the same file
+size, since more bits than necessary are expended on higher AC coefficients.
+
+You can substitute a different set of quantization values by using the
+-qtables switch:
+
+ -qtables file Use the quantization tables given in the named file.
+
+The specified file should be a text file containing decimal quantization
+values. The file should contain one to four tables, each of 64 elements.
+The tables are implicitly numbered 0,1,etc. in order of appearance. Table
+entries appear in normal array order (NOT in the zigzag order in which they
+will be stored in the JPEG file).
+
+Quantization table files are free format, in that arbitrary whitespace can
+appear between numbers. Also, comments can be included: a comment starts
+with '#' and extends to the end of the line. Here is an example file that
+duplicates the default quantization tables:
+
+ # Quantization tables given in JPEG spec, section K.1
+
+ # This is table 0 (the luminance table):
+ 16 11 10 16 24 40 51 61
+ 12 12 14 19 26 58 60 55
+ 14 13 16 24 40 57 69 56
+ 14 17 22 29 51 87 80 62
+ 18 22 37 56 68 109 103 77
+ 24 35 55 64 81 104 113 92
+ 49 64 78 87 103 121 120 101
+ 72 92 95 98 112 100 103 99
+
+ # This is table 1 (the chrominance table):
+ 17 18 24 47 99 99 99 99
+ 18 21 26 66 99 99 99 99
+ 24 26 56 99 99 99 99 99
+ 47 66 99 99 99 99 99 99
+ 99 99 99 99 99 99 99 99
+ 99 99 99 99 99 99 99 99
+ 99 99 99 99 99 99 99 99
+ 99 99 99 99 99 99 99 99
+
+If the -qtables switch is used without -quality, then the specified tables
+are used exactly as-is. If both -qtables and -quality are used, then the
+tables taken from the file are scaled in the same fashion that the default
+tables would be scaled for that quality setting. If -baseline appears, then
+the quantization values are constrained to the range 1-255.
+
+By default, cjpeg will use quantization table 0 for luminance components and
+table 1 for chrominance components. To override this choice, use the -qslots
+switch:
+
+ -qslots N[,...] Select which quantization table to use for
+ each color component.
+
+The -qslots switch specifies a quantization table number for each color
+component, in the order in which the components appear in the JPEG SOF marker.
+For example, to create a separate table for each of Y,Cb,Cr, you could
+provide a -qtables file that defines three quantization tables and say
+"-qslots 0,1,2". If -qslots gives fewer table numbers than there are color
+components, then the last table number is repeated as necessary.
+
+
+Sampling Factor Adjustment
+--------------------------
+
+By default, cjpeg uses 2:1 horizontal and vertical downsampling when
+compressing YCbCr data, and no downsampling for all other color spaces.
+You can override this default with the -sample switch:
+
+ -sample HxV[,...] Set JPEG sampling factors for each color
+ component.
+
+The -sample switch specifies the JPEG sampling factors for each color
+component, in the order in which they appear in the JPEG SOF marker.
+If you specify fewer HxV pairs than there are components, the remaining
+components are set to 1x1 sampling. For example, the default YCbCr setting
+is equivalent to "-sample 2x2,1x1,1x1", which can be abbreviated to
+"-sample 2x2".
+
+There are still some JPEG decoders in existence that support only 2x1
+sampling (also called 4:2:2 sampling). Compatibility with such decoders can
+be achieved by specifying "-sample 2x1". This is not recommended unless
+really necessary, since it increases file size and encoding/decoding time
+with very little quality gain.
+
+
+Multiple Scan / Progression Control
+-----------------------------------
+
+By default, cjpeg emits a single-scan sequential JPEG file. The
+-progressive switch generates a progressive JPEG file using a default series
+of progression parameters. You can create multiple-scan sequential JPEG
+files or progressive JPEG files with custom progression parameters by using
+the -scans switch:
+
+ -scans file Use the scan sequence given in the named file.
+
+The specified file should be a text file containing a "scan script".
+The script specifies the contents and ordering of the scans to be emitted.
+Each entry in the script defines one scan. A scan definition specifies
+the components to be included in the scan, and for progressive JPEG it also
+specifies the progression parameters Ss,Se,Ah,Al for the scan. Scan
+definitions are separated by semicolons (';'). A semicolon after the last
+scan definition is optional.
+
+Each scan definition contains one to four component indexes, optionally
+followed by a colon (':') and the four progressive-JPEG parameters. The
+component indexes denote which color component(s) are to be transmitted in
+the scan. Components are numbered in the order in which they appear in the
+JPEG SOF marker, with the first component being numbered 0. (Note that these
+indexes are not the "component ID" codes assigned to the components, just
+positional indexes.)
+
+The progression parameters for each scan are:
+ Ss Zigzag index of first coefficient included in scan
+ Se Zigzag index of last coefficient included in scan
+ Ah Zero for first scan of a coefficient, else Al of prior scan
+ Al Successive approximation low bit position for scan
+If the progression parameters are omitted, the values 0,63,0,0 are used,
+producing a sequential JPEG file. cjpeg automatically determines whether
+the script represents a progressive or sequential file, by observing whether
+Ss and Se values other than 0 and 63 appear. (The -progressive switch is
+not needed to specify this; in fact, it is ignored when -scans appears.)
+The scan script must meet the JPEG restrictions on progression sequences.
+(cjpeg checks that the spec's requirements are obeyed.)
+
+Scan script files are free format, in that arbitrary whitespace can appear
+between numbers and around punctuation. Also, comments can be included: a
+comment starts with '#' and extends to the end of the line. For additional
+legibility, commas or dashes can be placed between values. (Actually, any
+single punctuation character other than ':' or ';' can be inserted.) For
+example, the following two scan definitions are equivalent:
+ 0 1 2: 0 63 0 0;
+ 0,1,2 : 0-63, 0,0 ;
+
+Here is an example of a scan script that generates a partially interleaved
+sequential JPEG file:
+
+ 0; # Y only in first scan
+ 1 2; # Cb and Cr in second scan
+
+Here is an example of a progressive scan script using only spectral selection
+(no successive approximation):
+
+ # Interleaved DC scan for Y,Cb,Cr:
+ 0,1,2: 0-0, 0, 0 ;
+ # AC scans:
+ 0: 1-2, 0, 0 ; # First two Y AC coefficients
+ 0: 3-5, 0, 0 ; # Three more
+ 1: 1-63, 0, 0 ; # All AC coefficients for Cb
+ 2: 1-63, 0, 0 ; # All AC coefficients for Cr
+ 0: 6-9, 0, 0 ; # More Y coefficients
+ 0: 10-63, 0, 0 ; # Remaining Y coefficients
+
+Here is an example of a successive-approximation script. This is equivalent
+to the default script used by "cjpeg -progressive" for YCbCr images:
+
+ # Initial DC scan for Y,Cb,Cr (lowest bit not sent)
+ 0,1,2: 0-0, 0, 1 ;
+ # First AC scan: send first 5 Y AC coefficients, minus 2 lowest bits:
+ 0: 1-5, 0, 2 ;
+ # Send all Cr,Cb AC coefficients, minus lowest bit:
+ # (chroma data is usually too small to be worth subdividing further;
+ # but note we send Cr first since eye is least sensitive to Cb)
+ 2: 1-63, 0, 1 ;
+ 1: 1-63, 0, 1 ;
+ # Send remaining Y AC coefficients, minus 2 lowest bits:
+ 0: 6-63, 0, 2 ;
+ # Send next-to-lowest bit of all Y AC coefficients:
+ 0: 1-63, 2, 1 ;
+ # At this point we've sent all but the lowest bit of all coefficients.
+ # Send lowest bit of DC coefficients
+ 0,1,2: 0-0, 1, 0 ;
+ # Send lowest bit of AC coefficients
+ 2: 1-63, 1, 0 ;
+ 1: 1-63, 1, 0 ;
+ # Y AC lowest bit scan is last; it's usually the largest scan
+ 0: 1-63, 1, 0 ;
+
+It may be worth pointing out that this script is tuned for quality settings
+of around 50 to 75. For lower quality settings, you'd probably want to use
+a script with fewer stages of successive approximation (otherwise the
+initial scans will be really bad). For higher quality settings, you might
+want to use more stages of successive approximation (so that the initial
+scans are not too large).
diff --git a/jpg/wrbmp.c b/jpg/wrbmp.c
new file mode 100644
index 0000000..3283b0f
--- /dev/null
+++ b/jpg/wrbmp.c
@@ -0,0 +1,442 @@
+/*
+ * wrbmp.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in Microsoft "BMP"
+ * format (MS Windows 3.x and OS/2 1.x flavors).
+ * Either 8-bit colormapped or 24-bit full-color format can be written.
+ * No compression is supported.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ *
+ * This code contributed by James Arthur Boucher.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef BMP_SUPPORTED
+
+
+/*
+ * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
+ * This is not yet implemented.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+/*
+ * Since BMP stores scanlines bottom-to-top, we have to invert the image
+ * from JPEG's top-to-bottom order. To do this, we save the outgoing data
+ * in a virtual array during put_pixel_row calls, then actually emit the
+ * BMP file during finish_output. The virtual array contains one JSAMPLE per
+ * pixel if the output is grayscale or colormapped, three if it is full color.
+ */
+
+/* Private version of data destination object */
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ boolean is_os2; /* saves the OS2 format request flag */
+
+ jvirt_sarray_ptr whole_image; /* needed to reverse row order */
+ JDIMENSION data_width; /* JSAMPLEs per row */
+ JDIMENSION row_width; /* physical width of one row in the BMP file */
+ int pad_bytes; /* number of padding bytes needed per row */
+ JDIMENSION cur_output_row; /* next row# to write to virtual array */
+} bmp_dest_struct;
+
+typedef bmp_dest_struct * bmp_dest_ptr;
+
+
+/* Forward declarations */
+LOCAL(void) write_colormap
+ JPP((j_decompress_ptr cinfo, bmp_dest_ptr dest,
+ int map_colors, int map_entry_size));
+
+
+/*
+ * Write some pixel data.
+ * In this module rows_supplied will always be 1.
+ */
+
+METHODDEF(void)
+put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+/* This version is for writing 24-bit pixels */
+{
+ bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ int pad;
+
+ /* Access next row in virtual array */
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image,
+ dest->cur_output_row, (JDIMENSION) 1, TRUE);
+ dest->cur_output_row++;
+
+ /* Transfer data. Note destination values must be in BGR order
+ * (even though Microsoft's own documents say the opposite).
+ */
+ inptr = dest->pub.buffer[0];
+ outptr = image_ptr[0];
+ for (col = cinfo->output_width; col > 0; col--) {
+ outptr[2] = *inptr++; /* can omit GETJSAMPLE() safely */
+ outptr[1] = *inptr++;
+ outptr[0] = *inptr++;
+ outptr += 3;
+ }
+
+ /* Zero out the pad bytes. */
+ pad = dest->pad_bytes;
+ while (--pad >= 0)
+ *outptr++ = 0;
+}
+
+METHODDEF(void)
+put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+/* This version is for grayscale OR quantized color output */
+{
+ bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW inptr, outptr;
+ register JDIMENSION col;
+ int pad;
+
+ /* Access next row in virtual array */
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image,
+ dest->cur_output_row, (JDIMENSION) 1, TRUE);
+ dest->cur_output_row++;
+
+ /* Transfer data. */
+ inptr = dest->pub.buffer[0];
+ outptr = image_ptr[0];
+ for (col = cinfo->output_width; col > 0; col--) {
+ *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
+ }
+
+ /* Zero out the pad bytes. */
+ pad = dest->pad_bytes;
+ while (--pad >= 0)
+ *outptr++ = 0;
+}
+
+
+/*
+ * Startup: normally writes the file header.
+ * In this module we may as well postpone everything until finish_output.
+ */
+
+METHODDEF(void)
+start_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ /* no work here */
+}
+
+
+/*
+ * Finish up at the end of the file.
+ *
+ * Here is where we really output the BMP file.
+ *
+ * First, routines to write the Windows and OS/2 variants of the file header.
+ */
+
+LOCAL(void)
+write_bmp_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
+/* Write a Windows-style BMP file header, including colormap if needed */
+{
+ char bmpfileheader[14];
+ char bmpinfoheader[40];
+#define PUT_2B(array,offset,value) \
+ (array[offset] = (char) ((value) & 0xFF), \
+ array[offset+1] = (char) (((value) >> 8) & 0xFF))
+#define PUT_4B(array,offset,value) \
+ (array[offset] = (char) ((value) & 0xFF), \
+ array[offset+1] = (char) (((value) >> 8) & 0xFF), \
+ array[offset+2] = (char) (((value) >> 16) & 0xFF), \
+ array[offset+3] = (char) (((value) >> 24) & 0xFF))
+ INT32 headersize, bfSize;
+ int bits_per_pixel, cmap_entries;
+
+ /* Compute colormap size and total file size */
+ if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->quantize_colors) {
+ /* Colormapped RGB */
+ bits_per_pixel = 8;
+ cmap_entries = 256;
+ } else {
+ /* Unquantized, full color RGB */
+ bits_per_pixel = 24;
+ cmap_entries = 0;
+ }
+ } else {
+ /* Grayscale output. We need to fake a 256-entry colormap. */
+ bits_per_pixel = 8;
+ cmap_entries = 256;
+ }
+ /* File size */
+ headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
+ bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
+
+ /* Set unused fields of header to 0 */
+ MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
+ MEMZERO(bmpinfoheader, SIZEOF(bmpinfoheader));
+
+ /* Fill the file header */
+ bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
+ bmpfileheader[1] = 0x4D;
+ PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
+ /* we leave bfReserved1 & bfReserved2 = 0 */
+ PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
+
+ /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
+ PUT_2B(bmpinfoheader, 0, 40); /* biSize */
+ PUT_4B(bmpinfoheader, 4, cinfo->output_width); /* biWidth */
+ PUT_4B(bmpinfoheader, 8, cinfo->output_height); /* biHeight */
+ PUT_2B(bmpinfoheader, 12, 1); /* biPlanes - must be 1 */
+ PUT_2B(bmpinfoheader, 14, bits_per_pixel); /* biBitCount */
+ /* we leave biCompression = 0, for none */
+ /* we leave biSizeImage = 0; this is correct for uncompressed data */
+ if (cinfo->density_unit == 2) { /* if have density in dots/cm, then */
+ PUT_4B(bmpinfoheader, 24, (INT32) (cinfo->X_density*100)); /* XPels/M */
+ PUT_4B(bmpinfoheader, 28, (INT32) (cinfo->Y_density*100)); /* XPels/M */
+ }
+ PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */
+ /* we leave biClrImportant = 0 */
+
+ if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t) 40)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+
+ if (cmap_entries > 0)
+ write_colormap(cinfo, dest, cmap_entries, 4);
+}
+
+
+LOCAL(void)
+write_os2_header (j_decompress_ptr cinfo, bmp_dest_ptr dest)
+/* Write an OS2-style BMP file header, including colormap if needed */
+{
+ char bmpfileheader[14];
+ char bmpcoreheader[12];
+ INT32 headersize, bfSize;
+ int bits_per_pixel, cmap_entries;
+
+ /* Compute colormap size and total file size */
+ if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->quantize_colors) {
+ /* Colormapped RGB */
+ bits_per_pixel = 8;
+ cmap_entries = 256;
+ } else {
+ /* Unquantized, full color RGB */
+ bits_per_pixel = 24;
+ cmap_entries = 0;
+ }
+ } else {
+ /* Grayscale output. We need to fake a 256-entry colormap. */
+ bits_per_pixel = 8;
+ cmap_entries = 256;
+ }
+ /* File size */
+ headersize = 14 + 12 + cmap_entries * 3; /* Header and colormap */
+ bfSize = headersize + (INT32) dest->row_width * (INT32) cinfo->output_height;
+
+ /* Set unused fields of header to 0 */
+ MEMZERO(bmpfileheader, SIZEOF(bmpfileheader));
+ MEMZERO(bmpcoreheader, SIZEOF(bmpcoreheader));
+
+ /* Fill the file header */
+ bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */
+ bmpfileheader[1] = 0x4D;
+ PUT_4B(bmpfileheader, 2, bfSize); /* bfSize */
+ /* we leave bfReserved1 & bfReserved2 = 0 */
+ PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */
+
+ /* Fill the info header (Microsoft calls this a BITMAPCOREHEADER) */
+ PUT_2B(bmpcoreheader, 0, 12); /* bcSize */
+ PUT_2B(bmpcoreheader, 4, cinfo->output_width); /* bcWidth */
+ PUT_2B(bmpcoreheader, 6, cinfo->output_height); /* bcHeight */
+ PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */
+ PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */
+
+ if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t) 14)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+ if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t) 12)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+
+ if (cmap_entries > 0)
+ write_colormap(cinfo, dest, cmap_entries, 3);
+}
+
+
+/*
+ * Write the colormap.
+ * Windows uses BGR0 map entries; OS/2 uses BGR entries.
+ */
+
+LOCAL(void)
+write_colormap (j_decompress_ptr cinfo, bmp_dest_ptr dest,
+ int map_colors, int map_entry_size)
+{
+ JSAMPARRAY colormap = cinfo->colormap;
+ int num_colors = cinfo->actual_number_of_colors;
+ FILE * outfile = dest->pub.output_file;
+ int i;
+
+ if (colormap != NULL) {
+ if (cinfo->out_color_components == 3) {
+ /* Normal case with RGB colormap */
+ for (i = 0; i < num_colors; i++) {
+ putc(GETJSAMPLE(colormap[2][i]), outfile);
+ putc(GETJSAMPLE(colormap[1][i]), outfile);
+ putc(GETJSAMPLE(colormap[0][i]), outfile);
+ if (map_entry_size == 4)
+ putc(0, outfile);
+ }
+ } else {
+ /* Grayscale colormap (only happens with grayscale quantization) */
+ for (i = 0; i < num_colors; i++) {
+ putc(GETJSAMPLE(colormap[0][i]), outfile);
+ putc(GETJSAMPLE(colormap[0][i]), outfile);
+ putc(GETJSAMPLE(colormap[0][i]), outfile);
+ if (map_entry_size == 4)
+ putc(0, outfile);
+ }
+ }
+ } else {
+ /* If no colormap, must be grayscale data. Generate a linear "map". */
+ for (i = 0; i < 256; i++) {
+ putc(i, outfile);
+ putc(i, outfile);
+ putc(i, outfile);
+ if (map_entry_size == 4)
+ putc(0, outfile);
+ }
+ }
+ /* Pad colormap with zeros to ensure specified number of colormap entries */
+ if (i > map_colors)
+ ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, i);
+ for (; i < map_colors; i++) {
+ putc(0, outfile);
+ putc(0, outfile);
+ putc(0, outfile);
+ if (map_entry_size == 4)
+ putc(0, outfile);
+ }
+}
+
+
+METHODDEF(void)
+finish_output_bmp (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
+ register FILE * outfile = dest->pub.output_file;
+ JSAMPARRAY image_ptr;
+ register JSAMPROW data_ptr;
+ JDIMENSION row;
+ register JDIMENSION col;
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+
+ /* Write the header and colormap */
+ if (dest->is_os2)
+ write_os2_header(cinfo, dest);
+ else
+ write_bmp_header(cinfo, dest);
+
+ /* Write the file body from our virtual array */
+ for (row = cinfo->output_height; row > 0; row--) {
+ if (progress != NULL) {
+ progress->pub.pass_counter = (long) (cinfo->output_height - row);
+ progress->pub.pass_limit = (long) cinfo->output_height;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+ image_ptr = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
+ data_ptr = image_ptr[0];
+ for (col = dest->row_width; col > 0; col--) {
+ putc(GETJSAMPLE(*data_ptr), outfile);
+ data_ptr++;
+ }
+ }
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+
+ /* Make sure we wrote the output file OK */
+ fflush(outfile);
+ if (ferror(outfile))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for BMP format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_bmp (j_decompress_ptr cinfo, boolean is_os2)
+{
+ bmp_dest_ptr dest;
+ JDIMENSION row_width;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (bmp_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(bmp_dest_struct));
+ dest->pub.start_output = start_output_bmp;
+ dest->pub.finish_output = finish_output_bmp;
+ dest->is_os2 = is_os2;
+
+ if (cinfo->out_color_space == JCS_GRAYSCALE) {
+ dest->pub.put_pixel_rows = put_gray_rows;
+ } else if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->quantize_colors)
+ dest->pub.put_pixel_rows = put_gray_rows;
+ else
+ dest->pub.put_pixel_rows = put_pixel_rows;
+ } else {
+ ERREXIT(cinfo, JERR_BMP_COLORSPACE);
+ }
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ /* Determine width of rows in the BMP file (padded to 4-byte boundary). */
+ row_width = cinfo->output_width * cinfo->output_components;
+ dest->data_width = row_width;
+ while ((row_width & 3) != 0) row_width++;
+ dest->row_width = row_width;
+ dest->pad_bytes = (int) (row_width - dest->data_width);
+
+ /* Allocate space for inversion array, prepare for write pass */
+ dest->whole_image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ row_width, cinfo->output_height, (JDIMENSION) 1);
+ dest->cur_output_row = 0;
+ if (cinfo->progress != NULL) {
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+ progress->total_extra_passes++; /* count file input as separate pass */
+ }
+
+ /* Create decompressor output buffer. */
+ dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
+ dest->pub.buffer_height = 1;
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* BMP_SUPPORTED */
diff --git a/jpg/wrgif.c b/jpg/wrgif.c
new file mode 100644
index 0000000..5fe8328
--- /dev/null
+++ b/jpg/wrgif.c
@@ -0,0 +1,399 @@
+/*
+ * wrgif.c
+ *
+ * Copyright (C) 1991-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in GIF format.
+ *
+ **************************************************************************
+ * NOTE: to avoid entanglements with Unisys' patent on LZW compression, *
+ * this code has been modified to output "uncompressed GIF" files. *
+ * There is no trace of the LZW algorithm in this file. *
+ **************************************************************************
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ */
+
+/*
+ * This code is loosely based on ppmtogif from the PBMPLUS distribution
+ * of Feb. 1991. That file contains the following copyright notice:
+ * Based on GIFENCODE by David Rowley <mgardi@watdscu.waterloo.edu>.
+ * Lempel-Ziv compression based on "compress" by Spencer W. Thomas et al.
+ * Copyright (C) 1989 by Jef Poskanzer.
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. This software is provided "as is" without express or
+ * implied warranty.
+ *
+ * We are also required to state that
+ * "The Graphics Interchange Format(c) is the Copyright property of
+ * CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ * CompuServe Incorporated."
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef GIF_SUPPORTED
+
+
+/* Private version of data destination object */
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ j_decompress_ptr cinfo; /* back link saves passing separate parm */
+
+ /* State for packing variable-width codes into a bitstream */
+ int n_bits; /* current number of bits/code */
+ int maxcode; /* maximum code, given n_bits */
+ INT32 cur_accum; /* holds bits not yet output */
+ int cur_bits; /* # of bits in cur_accum */
+
+ /* State for GIF code assignment */
+ int ClearCode; /* clear code (doesn't change) */
+ int EOFCode; /* EOF code (ditto) */
+ int code_counter; /* counts output symbols */
+
+ /* GIF data packet construction buffer */
+ int bytesinpkt; /* # of bytes in current packet */
+ char packetbuf[256]; /* workspace for accumulating packet */
+
+} gif_dest_struct;
+
+typedef gif_dest_struct * gif_dest_ptr;
+
+/* Largest value that will fit in N bits */
+#define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
+
+
+/*
+ * Routines to package finished data bytes into GIF data blocks.
+ * A data block consists of a count byte (1..255) and that many data bytes.
+ */
+
+LOCAL(void)
+flush_packet (gif_dest_ptr dinfo)
+/* flush any accumulated data */
+{
+ if (dinfo->bytesinpkt > 0) { /* never write zero-length packet */
+ dinfo->packetbuf[0] = (char) dinfo->bytesinpkt++;
+ if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt)
+ != (size_t) dinfo->bytesinpkt)
+ ERREXIT(dinfo->cinfo, JERR_FILE_WRITE);
+ dinfo->bytesinpkt = 0;
+ }
+}
+
+
+/* Add a character to current packet; flush to disk if necessary */
+#define CHAR_OUT(dinfo,c) \
+ { (dinfo)->packetbuf[++(dinfo)->bytesinpkt] = (char) (c); \
+ if ((dinfo)->bytesinpkt >= 255) \
+ flush_packet(dinfo); \
+ }
+
+
+/* Routine to convert variable-width codes into a byte stream */
+
+LOCAL(void)
+output (gif_dest_ptr dinfo, int code)
+/* Emit a code of n_bits bits */
+/* Uses cur_accum and cur_bits to reblock into 8-bit bytes */
+{
+ dinfo->cur_accum |= ((INT32) code) << dinfo->cur_bits;
+ dinfo->cur_bits += dinfo->n_bits;
+
+ while (dinfo->cur_bits >= 8) {
+ CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
+ dinfo->cur_accum >>= 8;
+ dinfo->cur_bits -= 8;
+ }
+}
+
+
+/* The pseudo-compression algorithm.
+ *
+ * In this module we simply output each pixel value as a separate symbol;
+ * thus, no compression occurs. In fact, there is expansion of one bit per
+ * pixel, because we use a symbol width one bit wider than the pixel width.
+ *
+ * GIF ordinarily uses variable-width symbols, and the decoder will expect
+ * to ratchet up the symbol width after a fixed number of symbols.
+ * To simplify the logic and keep the expansion penalty down, we emit a
+ * GIF Clear code to reset the decoder just before the width would ratchet up.
+ * Thus, all the symbols in the output file will have the same bit width.
+ * Note that emitting the Clear codes at the right times is a mere matter of
+ * counting output symbols and is in no way dependent on the LZW patent.
+ *
+ * With a small basic pixel width (low color count), Clear codes will be
+ * needed very frequently, causing the file to expand even more. So this
+ * simplistic approach wouldn't work too well on bilevel images, for example.
+ * But for output of JPEG conversions the pixel width will usually be 8 bits
+ * (129 to 256 colors), so the overhead added by Clear symbols is only about
+ * one symbol in every 256.
+ */
+
+LOCAL(void)
+compress_init (gif_dest_ptr dinfo, int i_bits)
+/* Initialize pseudo-compressor */
+{
+ /* init all the state variables */
+ dinfo->n_bits = i_bits;
+ dinfo->maxcode = MAXCODE(dinfo->n_bits);
+ dinfo->ClearCode = (1 << (i_bits - 1));
+ dinfo->EOFCode = dinfo->ClearCode + 1;
+ dinfo->code_counter = dinfo->ClearCode + 2;
+ /* init output buffering vars */
+ dinfo->bytesinpkt = 0;
+ dinfo->cur_accum = 0;
+ dinfo->cur_bits = 0;
+ /* GIF specifies an initial Clear code */
+ output(dinfo, dinfo->ClearCode);
+}
+
+
+LOCAL(void)
+compress_pixel (gif_dest_ptr dinfo, int c)
+/* Accept and "compress" one pixel value.
+ * The given value must be less than n_bits wide.
+ */
+{
+ /* Output the given pixel value as a symbol. */
+ output(dinfo, c);
+ /* Issue Clear codes often enough to keep the reader from ratcheting up
+ * its symbol size.
+ */
+ if (dinfo->code_counter < dinfo->maxcode) {
+ dinfo->code_counter++;
+ } else {
+ output(dinfo, dinfo->ClearCode);
+ dinfo->code_counter = dinfo->ClearCode + 2; /* reset the counter */
+ }
+}
+
+
+LOCAL(void)
+compress_term (gif_dest_ptr dinfo)
+/* Clean up at end */
+{
+ /* Send an EOF code */
+ output(dinfo, dinfo->EOFCode);
+ /* Flush the bit-packing buffer */
+ if (dinfo->cur_bits > 0) {
+ CHAR_OUT(dinfo, dinfo->cur_accum & 0xFF);
+ }
+ /* Flush the packet buffer */
+ flush_packet(dinfo);
+}
+
+
+/* GIF header construction */
+
+
+LOCAL(void)
+put_word (gif_dest_ptr dinfo, unsigned int w)
+/* Emit a 16-bit word, LSB first */
+{
+ putc(w & 0xFF, dinfo->pub.output_file);
+ putc((w >> 8) & 0xFF, dinfo->pub.output_file);
+}
+
+
+LOCAL(void)
+put_3bytes (gif_dest_ptr dinfo, int val)
+/* Emit 3 copies of same byte value --- handy subr for colormap construction */
+{
+ putc(val, dinfo->pub.output_file);
+ putc(val, dinfo->pub.output_file);
+ putc(val, dinfo->pub.output_file);
+}
+
+
+LOCAL(void)
+emit_header (gif_dest_ptr dinfo, int num_colors, JSAMPARRAY colormap)
+/* Output the GIF file header, including color map */
+/* If colormap==NULL, synthesize a gray-scale colormap */
+{
+ int BitsPerPixel, ColorMapSize, InitCodeSize, FlagByte;
+ int cshift = dinfo->cinfo->data_precision - 8;
+ int i;
+
+ if (num_colors > 256)
+ ERREXIT1(dinfo->cinfo, JERR_TOO_MANY_COLORS, num_colors);
+ /* Compute bits/pixel and related values */
+ BitsPerPixel = 1;
+ while (num_colors > (1 << BitsPerPixel))
+ BitsPerPixel++;
+ ColorMapSize = 1 << BitsPerPixel;
+ if (BitsPerPixel <= 1)
+ InitCodeSize = 2;
+ else
+ InitCodeSize = BitsPerPixel;
+ /*
+ * Write the GIF header.
+ * Note that we generate a plain GIF87 header for maximum compatibility.
+ */
+ putc('G', dinfo->pub.output_file);
+ putc('I', dinfo->pub.output_file);
+ putc('F', dinfo->pub.output_file);
+ putc('8', dinfo->pub.output_file);
+ putc('7', dinfo->pub.output_file);
+ putc('a', dinfo->pub.output_file);
+ /* Write the Logical Screen Descriptor */
+ put_word(dinfo, (unsigned int) dinfo->cinfo->output_width);
+ put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
+ FlagByte = 0x80; /* Yes, there is a global color table */
+ FlagByte |= (BitsPerPixel-1) << 4; /* color resolution */
+ FlagByte |= (BitsPerPixel-1); /* size of global color table */
+ putc(FlagByte, dinfo->pub.output_file);
+ putc(0, dinfo->pub.output_file); /* Background color index */
+ putc(0, dinfo->pub.output_file); /* Reserved (aspect ratio in GIF89) */
+ /* Write the Global Color Map */
+ /* If the color map is more than 8 bits precision, */
+ /* we reduce it to 8 bits by shifting */
+ for (i=0; i < ColorMapSize; i++) {
+ if (i < num_colors) {
+ if (colormap != NULL) {
+ if (dinfo->cinfo->out_color_space == JCS_RGB) {
+ /* Normal case: RGB color map */
+ putc(GETJSAMPLE(colormap[0][i]) >> cshift, dinfo->pub.output_file);
+ putc(GETJSAMPLE(colormap[1][i]) >> cshift, dinfo->pub.output_file);
+ putc(GETJSAMPLE(colormap[2][i]) >> cshift, dinfo->pub.output_file);
+ } else {
+ /* Grayscale "color map": possible if quantizing grayscale image */
+ put_3bytes(dinfo, GETJSAMPLE(colormap[0][i]) >> cshift);
+ }
+ } else {
+ /* Create a gray-scale map of num_colors values, range 0..255 */
+ put_3bytes(dinfo, (i * 255 + (num_colors-1)/2) / (num_colors-1));
+ }
+ } else {
+ /* fill out the map to a power of 2 */
+ put_3bytes(dinfo, 0);
+ }
+ }
+ /* Write image separator and Image Descriptor */
+ putc(',', dinfo->pub.output_file); /* separator */
+ put_word(dinfo, 0); /* left/top offset */
+ put_word(dinfo, 0);
+ put_word(dinfo, (unsigned int) dinfo->cinfo->output_width); /* image size */
+ put_word(dinfo, (unsigned int) dinfo->cinfo->output_height);
+ /* flag byte: not interlaced, no local color map */
+ putc(0x00, dinfo->pub.output_file);
+ /* Write Initial Code Size byte */
+ putc(InitCodeSize, dinfo->pub.output_file);
+
+ /* Initialize for "compression" of image data */
+ compress_init(dinfo, InitCodeSize+1);
+}
+
+
+/*
+ * Startup: write the file header.
+ */
+
+METHODDEF(void)
+start_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ gif_dest_ptr dest = (gif_dest_ptr) dinfo;
+
+ if (cinfo->quantize_colors)
+ emit_header(dest, cinfo->actual_number_of_colors, cinfo->colormap);
+ else
+ emit_header(dest, 256, (JSAMPARRAY) NULL);
+}
+
+
+/*
+ * Write some pixel data.
+ * In this module rows_supplied will always be 1.
+ */
+
+METHODDEF(void)
+put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ gif_dest_ptr dest = (gif_dest_ptr) dinfo;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ for (col = cinfo->output_width; col > 0; col--) {
+ compress_pixel(dest, GETJSAMPLE(*ptr++));
+ }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_output_gif (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ gif_dest_ptr dest = (gif_dest_ptr) dinfo;
+
+ /* Flush "compression" mechanism */
+ compress_term(dest);
+ /* Write a zero-length data block to end the series */
+ putc(0, dest->pub.output_file);
+ /* Write the GIF terminator mark */
+ putc(';', dest->pub.output_file);
+ /* Make sure we wrote the output file OK */
+ fflush(dest->pub.output_file);
+ if (ferror(dest->pub.output_file))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for GIF format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_gif (j_decompress_ptr cinfo)
+{
+ gif_dest_ptr dest;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (gif_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(gif_dest_struct));
+ dest->cinfo = cinfo; /* make back link for subroutines */
+ dest->pub.start_output = start_output_gif;
+ dest->pub.put_pixel_rows = put_pixel_rows;
+ dest->pub.finish_output = finish_output_gif;
+
+ if (cinfo->out_color_space != JCS_GRAYSCALE &&
+ cinfo->out_color_space != JCS_RGB)
+ ERREXIT(cinfo, JERR_GIF_COLORSPACE);
+
+ /* Force quantization if color or if > 8 bits input */
+ if (cinfo->out_color_space != JCS_GRAYSCALE || cinfo->data_precision > 8) {
+ /* Force quantization to at most 256 colors */
+ cinfo->quantize_colors = TRUE;
+ if (cinfo->desired_number_of_colors > 256)
+ cinfo->desired_number_of_colors = 256;
+ }
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ if (cinfo->output_components != 1) /* safety check: just one component? */
+ ERREXIT(cinfo, JERR_GIF_BUG);
+
+ /* Create decompressor output buffer. */
+ dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, cinfo->output_width, (JDIMENSION) 1);
+ dest->pub.buffer_height = 1;
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* GIF_SUPPORTED */
diff --git a/jpg/wrjpgcom.1 b/jpg/wrjpgcom.1
new file mode 100644
index 0000000..d419a99
--- /dev/null
+++ b/jpg/wrjpgcom.1
@@ -0,0 +1,103 @@
+.TH WRJPGCOM 1 "15 June 1995"
+.SH NAME
+wrjpgcom \- insert text comments into a JPEG file
+.SH SYNOPSIS
+.B wrjpgcom
+[
+.B \-replace
+]
+[
+.BI \-comment " text"
+]
+[
+.BI \-cfile " name"
+]
+[
+.I filename
+]
+.LP
+.SH DESCRIPTION
+.LP
+.B wrjpgcom
+reads the named JPEG/JFIF file, or the standard input if no file is named,
+and generates a new JPEG/JFIF file on standard output. A comment block is
+added to the file.
+.PP
+The JPEG standard allows "comment" (COM) blocks to occur within a JPEG file.
+Although the standard doesn't actually define what COM blocks are for, they
+are widely used to hold user-supplied text strings. This lets you add
+annotations, titles, index terms, etc to your JPEG files, and later retrieve
+them as text. COM blocks do not interfere with the image stored in the JPEG
+file. The maximum size of a COM block is 64K, but you can have as many of
+them as you like in one JPEG file.
+.PP
+.B wrjpgcom
+adds a COM block, containing text you provide, to a JPEG file.
+Ordinarily, the COM block is added after any existing COM blocks; but you
+can delete the old COM blocks if you wish.
+.SH OPTIONS
+Switch names may be abbreviated, and are not case sensitive.
+.TP
+.B \-replace
+Delete any existing COM blocks from the file.
+.TP
+.BI \-comment " text"
+Supply text for new COM block on command line.
+.TP
+.BI \-cfile " name"
+Read text for new COM block from named file.
+.PP
+If you have only one line of comment text to add, you can provide it on the
+command line with
+.BR \-comment .
+The comment text must be surrounded with quotes so that it is treated as a
+single argument. Longer comments can be read from a text file.
+.PP
+If you give neither
+.B \-comment
+nor
+.BR \-cfile ,
+then
+.B wrjpgcom
+will read the comment text from standard input. (In this case an input image
+file name MUST be supplied, so that the source JPEG file comes from somewhere
+else.) You can enter multiple lines, up to 64KB worth. Type an end-of-file
+indicator (usually control-D) to terminate the comment text entry.
+.PP
+.B wrjpgcom
+will not add a COM block if the provided comment string is empty. Therefore
+\fB\-replace \-comment ""\fR can be used to delete all COM blocks from a file.
+.SH EXAMPLES
+.LP
+Add a short comment to in.jpg, producing out.jpg:
+.IP
+.B wrjpgcom \-c
+\fI"View of my back yard" in.jpg
+.B >
+.I out.jpg
+.PP
+Attach a long comment previously stored in comment.txt:
+.IP
+.B wrjpgcom
+.I in.jpg
+.B <
+.I comment.txt
+.B >
+.I out.jpg
+.PP
+or equivalently
+.IP
+.B wrjpgcom
+.B -cfile
+.I comment.txt
+.B <
+.I in.jpg
+.B >
+.I out.jpg
+.SH SEE ALSO
+.BR cjpeg (1),
+.BR djpeg (1),
+.BR jpegtran (1),
+.BR rdjpgcom (1)
+.SH AUTHOR
+Independent JPEG Group
diff --git a/jpg/wrjpgcom.c b/jpg/wrjpgcom.c
new file mode 100644
index 0000000..8c04b05
--- /dev/null
+++ b/jpg/wrjpgcom.c
@@ -0,0 +1,583 @@
+/*
+ * wrjpgcom.c
+ *
+ * Copyright (C) 1994-1997, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains a very simple stand-alone application that inserts
+ * user-supplied text as a COM (comment) marker in a JFIF file.
+ * This may be useful as an example of the minimum logic needed to parse
+ * JPEG markers.
+ */
+
+#define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */
+#include "jinclude.h" /* get auto-config symbols, <stdio.h> */
+
+#ifndef HAVE_STDLIB_H /* <stdlib.h> should declare malloc() */
+extern void * malloc ();
+#endif
+#include <ctype.h> /* to declare isupper(), tolower() */
+#ifdef USE_SETMODE
+#include <fcntl.h> /* to declare setmode()'s parameter macros */
+/* If you have setmode() but not <io.h>, just delete this line: */
+#include <io.h> /* to declare setmode() */
+#endif
+
+#ifdef USE_CCOMMAND /* command-line reader for Macintosh */
+#ifdef __MWERKS__
+#include <SIOUX.h> /* Metrowerks needs this */
+#include <console.h> /* ... and this */
+#endif
+#ifdef THINK_C
+#include <console.h> /* Think declares it here */
+#endif
+#endif
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#define WRITE_BINARY "w"
+#else
+#ifdef VMS /* VMS is very nonstandard */
+#define READ_BINARY "rb", "ctx=stm"
+#define WRITE_BINARY "wb", "ctx=stm"
+#else /* standard ANSI-compliant case */
+#define READ_BINARY "rb"
+#define WRITE_BINARY "wb"
+#endif
+#endif
+
+#ifndef EXIT_FAILURE /* define exit() codes if not provided */
+#define EXIT_FAILURE 1
+#endif
+#ifndef EXIT_SUCCESS
+#ifdef VMS
+#define EXIT_SUCCESS 1 /* VMS is very nonstandard */
+#else
+#define EXIT_SUCCESS 0
+#endif
+#endif
+
+/* Reduce this value if your malloc() can't allocate blocks up to 64K.
+ * On DOS, compiling in large model is usually a better solution.
+ */
+
+#ifndef MAX_COM_LENGTH
+#define MAX_COM_LENGTH 65000L /* must be <= 65533 in any case */
+#endif
+
+
+/*
+ * These macros are used to read the input file and write the output file.
+ * To reuse this code in another application, you might need to change these.
+ */
+
+static FILE * infile; /* input JPEG file */
+
+/* Return next input byte, or EOF if no more */
+#define NEXTBYTE() getc(infile)
+
+static FILE * outfile; /* output JPEG file */
+
+/* Emit an output byte */
+#define PUTBYTE(x) putc((x), outfile)
+
+
+/* Error exit handler */
+#define ERREXIT(msg) (fprintf(stderr, "%s\n", msg), exit(EXIT_FAILURE))
+
+
+/* Read one byte, testing for EOF */
+static int
+read_1_byte (void)
+{
+ int c;
+
+ c = NEXTBYTE();
+ if (c == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ return c;
+}
+
+/* Read 2 bytes, convert to unsigned int */
+/* All 2-byte quantities in JPEG markers are MSB first */
+static unsigned int
+read_2_bytes (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ if (c1 == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ c2 = NEXTBYTE();
+ if (c2 == EOF)
+ ERREXIT("Premature EOF in JPEG file");
+ return (((unsigned int) c1) << 8) + ((unsigned int) c2);
+}
+
+
+/* Routines to write data to output file */
+
+static void
+write_1_byte (int c)
+{
+ PUTBYTE(c);
+}
+
+static void
+write_2_bytes (unsigned int val)
+{
+ PUTBYTE((val >> 8) & 0xFF);
+ PUTBYTE(val & 0xFF);
+}
+
+static void
+write_marker (int marker)
+{
+ PUTBYTE(0xFF);
+ PUTBYTE(marker);
+}
+
+static void
+copy_rest_of_file (void)
+{
+ int c;
+
+ while ((c = NEXTBYTE()) != EOF)
+ PUTBYTE(c);
+}
+
+
+/*
+ * JPEG markers consist of one or more 0xFF bytes, followed by a marker
+ * code byte (which is not an FF). Here are the marker codes of interest
+ * in this program. (See jdmarker.c for a more complete list.)
+ */
+
+#define M_SOF0 0xC0 /* Start Of Frame N */
+#define M_SOF1 0xC1 /* N indicates which compression process */
+#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
+#define M_SOF3 0xC3
+#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
+#define M_SOF6 0xC6
+#define M_SOF7 0xC7
+#define M_SOF9 0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
+#define M_EOI 0xD9 /* End Of Image (end of datastream) */
+#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
+#define M_COM 0xFE /* COMment */
+
+
+/*
+ * Find the next JPEG marker and return its marker code.
+ * We expect at least one FF byte, possibly more if the compressor used FFs
+ * to pad the file. (Padding FFs will NOT be replicated in the output file.)
+ * There could also be non-FF garbage between markers. The treatment of such
+ * garbage is unspecified; we choose to skip over it but emit a warning msg.
+ * NB: this routine must not be used after seeing SOS marker, since it will
+ * not deal correctly with FF/00 sequences in the compressed image data...
+ */
+
+static int
+next_marker (void)
+{
+ int c;
+ int discarded_bytes = 0;
+
+ /* Find 0xFF byte; count and skip any non-FFs. */
+ c = read_1_byte();
+ while (c != 0xFF) {
+ discarded_bytes++;
+ c = read_1_byte();
+ }
+ /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs
+ * are legal as pad bytes, so don't count them in discarded_bytes.
+ */
+ do {
+ c = read_1_byte();
+ } while (c == 0xFF);
+
+ if (discarded_bytes != 0) {
+ fprintf(stderr, "Warning: garbage data found in JPEG file\n");
+ }
+
+ return c;
+}
+
+
+/*
+ * Read the initial marker, which should be SOI.
+ * For a JFIF file, the first two bytes of the file should be literally
+ * 0xFF M_SOI. To be more general, we could use next_marker, but if the
+ * input file weren't actually JPEG at all, next_marker might read the whole
+ * file and then return a misleading error message...
+ */
+
+static int
+first_marker (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ c2 = NEXTBYTE();
+ if (c1 != 0xFF || c2 != M_SOI)
+ ERREXIT("Not a JPEG file");
+ return c2;
+}
+
+
+/*
+ * Most types of marker are followed by a variable-length parameter segment.
+ * This routine skips over the parameters for any marker we don't otherwise
+ * want to process.
+ * Note that we MUST skip the parameter segment explicitly in order not to
+ * be fooled by 0xFF bytes that might appear within the parameter segment;
+ * such bytes do NOT introduce new markers.
+ */
+
+static void
+copy_variable (void)
+/* Copy an unknown or uninteresting variable-length marker */
+{
+ unsigned int length;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ write_2_bytes(length);
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2)
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+ /* Skip over the remaining bytes */
+ while (length > 0) {
+ write_1_byte(read_1_byte());
+ length--;
+ }
+}
+
+static void
+skip_variable (void)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ unsigned int length;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2)
+ ERREXIT("Erroneous JPEG marker length");
+ length -= 2;
+ /* Skip over the remaining bytes */
+ while (length > 0) {
+ (void) read_1_byte();
+ length--;
+ }
+}
+
+
+/*
+ * Parse the marker stream until SOFn or EOI is seen;
+ * copy data to output, but discard COM markers unless keep_COM is true.
+ */
+
+static int
+scan_JPEG_header (int keep_COM)
+{
+ int marker;
+
+ /* Expect SOI at start of file */
+ if (first_marker() != M_SOI)
+ ERREXIT("Expected SOI marker first");
+ write_marker(M_SOI);
+
+ /* Scan miscellaneous markers until we reach SOFn. */
+ for (;;) {
+ marker = next_marker();
+ switch (marker) {
+ /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
+ * treated as SOFn. C4 in particular is actually DHT.
+ */
+ case M_SOF0: /* Baseline */
+ case M_SOF1: /* Extended sequential, Huffman */
+ case M_SOF2: /* Progressive, Huffman */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_SOF9: /* Extended sequential, arithmetic */
+ case M_SOF10: /* Progressive, arithmetic */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ return marker;
+
+ case M_SOS: /* should not see compressed data before SOF */
+ ERREXIT("SOS without prior SOFn");
+ break;
+
+ case M_EOI: /* in case it's a tables-only JPEG stream */
+ return marker;
+
+ case M_COM: /* Existing COM: conditionally discard */
+ if (keep_COM) {
+ write_marker(marker);
+ copy_variable();
+ } else {
+ skip_variable();
+ }
+ break;
+
+ default: /* Anything else just gets copied */
+ write_marker(marker);
+ copy_variable(); /* we assume it has a parameter count... */
+ break;
+ }
+ } /* end loop */
+}
+
+
+/* Command line parsing code */
+
+static const char * progname; /* program name for error messages */
+
+
+static void
+usage (void)
+/* complain about bad command line */
+{
+ fprintf(stderr, "wrjpgcom inserts a textual comment in a JPEG file.\n");
+ fprintf(stderr, "You can add to or replace any existing comment(s).\n");
+
+ fprintf(stderr, "Usage: %s [switches] ", progname);
+#ifdef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "inputfile outputfile\n");
+#else
+ fprintf(stderr, "[inputfile]\n");
+#endif
+
+ fprintf(stderr, "Switches (names may be abbreviated):\n");
+ fprintf(stderr, " -replace Delete any existing comments\n");
+ fprintf(stderr, " -comment \"text\" Insert comment with given text\n");
+ fprintf(stderr, " -cfile name Read comment from named file\n");
+ fprintf(stderr, "Notice that you must put quotes around the comment text\n");
+ fprintf(stderr, "when you use -comment.\n");
+ fprintf(stderr, "If you do not give either -comment or -cfile on the command line,\n");
+ fprintf(stderr, "then the comment text is read from standard input.\n");
+ fprintf(stderr, "It can be multiple lines, up to %u characters total.\n",
+ (unsigned int) MAX_COM_LENGTH);
+#ifndef TWO_FILE_COMMANDLINE
+ fprintf(stderr, "You must specify an input JPEG file name when supplying\n");
+ fprintf(stderr, "comment text from standard input.\n");
+#endif
+
+ exit(EXIT_FAILURE);
+}
+
+
+static int
+keymatch (char * arg, const char * keyword, int minchars)
+/* Case-insensitive matching of (possibly abbreviated) keyword switches. */
+/* keyword is the constant keyword (must be lower case already), */
+/* minchars is length of minimum legal abbreviation. */
+{
+ register int ca, ck;
+ register int nmatched = 0;
+
+ while ((ca = *arg++) != '\0') {
+ if ((ck = *keyword++) == '\0')
+ return 0; /* arg longer than keyword, no good */
+ if (isupper(ca)) /* force arg to lcase (assume ck is already) */
+ ca = tolower(ca);
+ if (ca != ck)
+ return 0; /* no good */
+ nmatched++; /* count matched characters */
+ }
+ /* reached end of argument; fail if it's too short for unique abbrev */
+ if (nmatched < minchars)
+ return 0;
+ return 1; /* A-OK */
+}
+
+
+/*
+ * The main program.
+ */
+
+int
+main (int argc, char **argv)
+{
+ int argn;
+ char * arg;
+ int keep_COM = 1;
+ char * comment_arg = NULL;
+ FILE * comment_file = NULL;
+ unsigned int comment_length = 0;
+ int marker;
+
+ /* On Mac, fetch a command line. */
+#ifdef USE_CCOMMAND
+ argc = ccommand(&argv);
+#endif
+
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "wrjpgcom"; /* in case C library doesn't provide it */
+
+ /* Parse switches, if any */
+ for (argn = 1; argn < argc; argn++) {
+ arg = argv[argn];
+ if (arg[0] != '-')
+ break; /* not switch, must be file name */
+ arg++; /* advance over '-' */
+ if (keymatch(arg, "replace", 1)) {
+ keep_COM = 0;
+ } else if (keymatch(arg, "cfile", 2)) {
+ if (++argn >= argc) usage();
+ if ((comment_file = fopen(argv[argn], "r")) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+ } else if (keymatch(arg, "comment", 1)) {
+ if (++argn >= argc) usage();
+ comment_arg = argv[argn];
+ /* If the comment text starts with '"', then we are probably running
+ * under MS-DOG and must parse out the quoted string ourselves. Sigh.
+ */
+ if (comment_arg[0] == '"') {
+ comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
+ if (comment_arg == NULL)
+ ERREXIT("Insufficient memory");
+ strcpy(comment_arg, argv[argn]+1);
+ for (;;) {
+ comment_length = (unsigned int) strlen(comment_arg);
+ if (comment_length > 0 && comment_arg[comment_length-1] == '"') {
+ comment_arg[comment_length-1] = '\0'; /* zap terminating quote */
+ break;
+ }
+ if (++argn >= argc)
+ ERREXIT("Missing ending quote mark");
+ strcat(comment_arg, " ");
+ strcat(comment_arg, argv[argn]);
+ }
+ }
+ comment_length = (unsigned int) strlen(comment_arg);
+ } else
+ usage();
+ }
+
+ /* Cannot use both -comment and -cfile. */
+ if (comment_arg != NULL && comment_file != NULL)
+ usage();
+ /* If there is neither -comment nor -cfile, we will read the comment text
+ * from stdin; in this case there MUST be an input JPEG file name.
+ */
+ if (comment_arg == NULL && comment_file == NULL && argn >= argc)
+ usage();
+
+ /* Open the input file. */
+ if (argn < argc) {
+ if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ /* default input file is stdin */
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open stdin\n", progname);
+ exit(EXIT_FAILURE);
+ }
+#else
+ infile = stdin;
+#endif
+ }
+
+ /* Open the output file. */
+#ifdef TWO_FILE_COMMANDLINE
+ /* Must have explicit output file name */
+ if (argn != argc-2) {
+ fprintf(stderr, "%s: must name one input and one output file\n",
+ progname);
+ usage();
+ }
+ if ((outfile = fopen(argv[argn+1], WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open %s\n", progname, argv[argn+1]);
+ exit(EXIT_FAILURE);
+ }
+#else
+ /* Unix style: expect zero or one file name */
+ if (argn < argc-1) {
+ fprintf(stderr, "%s: only one input file\n", progname);
+ usage();
+ }
+ /* default output file is stdout */
+#ifdef USE_SETMODE /* need to hack file mode? */
+ setmode(fileno(stdout), O_BINARY);
+#endif
+#ifdef USE_FDOPEN /* need to re-open in binary mode? */
+ if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
+ fprintf(stderr, "%s: can't open stdout\n", progname);
+ exit(EXIT_FAILURE);
+ }
+#else
+ outfile = stdout;
+#endif
+#endif /* TWO_FILE_COMMANDLINE */
+
+ /* Collect comment text from comment_file or stdin, if necessary */
+ if (comment_arg == NULL) {
+ FILE * src_file;
+ int c;
+
+ comment_arg = (char *) malloc((size_t) MAX_COM_LENGTH);
+ if (comment_arg == NULL)
+ ERREXIT("Insufficient memory");
+ comment_length = 0;
+ src_file = (comment_file != NULL ? comment_file : stdin);
+ while ((c = getc(src_file)) != EOF) {
+ if (comment_length >= (unsigned int) MAX_COM_LENGTH) {
+ fprintf(stderr, "Comment text may not exceed %u bytes\n",
+ (unsigned int) MAX_COM_LENGTH);
+ exit(EXIT_FAILURE);
+ }
+ comment_arg[comment_length++] = (char) c;
+ }
+ if (comment_file != NULL)
+ fclose(comment_file);
+ }
+
+ /* Copy JPEG headers until SOFn marker;
+ * we will insert the new comment marker just before SOFn.
+ * This (a) causes the new comment to appear after, rather than before,
+ * existing comments; and (b) ensures that comments come after any JFIF
+ * or JFXX markers, as required by the JFIF specification.
+ */
+ marker = scan_JPEG_header(keep_COM);
+ /* Insert the new COM marker, but only if nonempty text has been supplied */
+ if (comment_length > 0) {
+ write_marker(M_COM);
+ write_2_bytes(comment_length + 2);
+ while (comment_length > 0) {
+ write_1_byte(*comment_arg++);
+ comment_length--;
+ }
+ }
+ /* Duplicate the remainder of the source file.
+ * Note that any COM markers occuring after SOF will not be touched.
+ */
+ write_marker(marker);
+ copy_rest_of_file();
+
+ /* All done. */
+ exit(EXIT_SUCCESS);
+ return 0; /* suppress no-return-value warnings */
+}
diff --git a/jpg/wrppm.c b/jpg/wrppm.c
new file mode 100644
index 0000000..68e0c85
--- /dev/null
+++ b/jpg/wrppm.c
@@ -0,0 +1,269 @@
+/*
+ * wrppm.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * Modified 2009 by Guido Vollbeding.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in PPM/PGM format.
+ * The extended 2-byte-per-sample raw PPM/PGM formats are supported.
+ * The PBMPLUS library is NOT required to compile this software
+ * (but it is highly useful as a set of PPM image manipulation programs).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef PPM_SUPPORTED
+
+
+/*
+ * For 12-bit JPEG data, we either downscale the values to 8 bits
+ * (to write standard byte-per-sample PPM/PGM files), or output
+ * nonstandard word-per-sample PPM/PGM files. Downscaling is done
+ * if PPM_NORAWWORD is defined (this can be done in the Makefile
+ * or in jconfig.h).
+ * (When the core library supports data precision reduction, a cleaner
+ * implementation will be to ask for that instead.)
+ */
+
+#if BITS_IN_JSAMPLE == 8
+#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) (v)
+#define BYTESPERSAMPLE 1
+#define PPM_MAXVAL 255
+#else
+#ifdef PPM_NORAWWORD
+#define PUTPPMSAMPLE(ptr,v) *ptr++ = (char) ((v) >> (BITS_IN_JSAMPLE-8))
+#define BYTESPERSAMPLE 1
+#define PPM_MAXVAL 255
+#else
+/* The word-per-sample format always puts the MSB first. */
+#define PUTPPMSAMPLE(ptr,v) \
+ { register int val_ = v; \
+ *ptr++ = (char) ((val_ >> 8) & 0xFF); \
+ *ptr++ = (char) (val_ & 0xFF); \
+ }
+#define BYTESPERSAMPLE 2
+#define PPM_MAXVAL ((1<<BITS_IN_JSAMPLE)-1)
+#endif
+#endif
+
+
+/*
+ * When JSAMPLE is the same size as char, we can just fwrite() the
+ * decompressed data to the PPM or PGM file. On PCs, in order to make this
+ * work the output buffer must be allocated in near data space, because we are
+ * assuming small-data memory model wherein fwrite() can't reach far memory.
+ * If you need to process very wide images on a PC, you might have to compile
+ * in large-memory model, or else replace fwrite() with a putc() loop ---
+ * which will be much slower.
+ */
+
+
+/* Private version of data destination object */
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ /* Usually these two pointers point to the same place: */
+ char *iobuffer; /* fwrite's I/O buffer */
+ JSAMPROW pixrow; /* decompressor output buffer */
+ size_t buffer_width; /* width of I/O buffer */
+ JDIMENSION samples_per_row; /* JSAMPLEs per output row */
+} ppm_dest_struct;
+
+typedef ppm_dest_struct * ppm_dest_ptr;
+
+
+/*
+ * Write some pixel data.
+ * In this module rows_supplied will always be 1.
+ *
+ * put_pixel_rows handles the "normal" 8-bit case where the decompressor
+ * output buffer is physically the same as the fwrite buffer.
+ */
+
+METHODDEF(void)
+put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * This code is used when we have to copy the data and apply a pixel
+ * format translation. Typically this only happens in 12-bit mode.
+ */
+
+METHODDEF(void)
+copy_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+ register char * bufferptr;
+ register JSAMPROW ptr;
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ bufferptr = dest->iobuffer;
+ for (col = dest->samples_per_row; col > 0; col--) {
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(*ptr++));
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Write some pixel data when color quantization is in effect.
+ * We have to demap the color index values to straight data.
+ */
+
+METHODDEF(void)
+put_demapped_rgb (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+ register char * bufferptr;
+ register int pixval;
+ register JSAMPROW ptr;
+ register JSAMPROW color_map0 = cinfo->colormap[0];
+ register JSAMPROW color_map1 = cinfo->colormap[1];
+ register JSAMPROW color_map2 = cinfo->colormap[2];
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ bufferptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ pixval = GETJSAMPLE(*ptr++);
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map0[pixval]));
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map1[pixval]));
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map2[pixval]));
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+METHODDEF(void)
+put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+ register char * bufferptr;
+ register JSAMPROW ptr;
+ register JSAMPROW color_map = cinfo->colormap[0];
+ register JDIMENSION col;
+
+ ptr = dest->pub.buffer[0];
+ bufferptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ PUTPPMSAMPLE(bufferptr, GETJSAMPLE(color_map[GETJSAMPLE(*ptr++)]));
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Startup: write the file header.
+ */
+
+METHODDEF(void)
+start_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ ppm_dest_ptr dest = (ppm_dest_ptr) dinfo;
+
+ /* Emit file header */
+ switch (cinfo->out_color_space) {
+ case JCS_GRAYSCALE:
+ /* emit header for raw PGM format */
+ fprintf(dest->pub.output_file, "P5\n%ld %ld\n%d\n",
+ (long) cinfo->output_width, (long) cinfo->output_height,
+ PPM_MAXVAL);
+ break;
+ case JCS_RGB:
+ /* emit header for raw PPM format */
+ fprintf(dest->pub.output_file, "P6\n%ld %ld\n%d\n",
+ (long) cinfo->output_width, (long) cinfo->output_height,
+ PPM_MAXVAL);
+ break;
+ default:
+ ERREXIT(cinfo, JERR_PPM_COLORSPACE);
+ }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_output_ppm (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ /* Make sure we wrote the output file OK */
+ fflush(dinfo->output_file);
+ if (ferror(dinfo->output_file))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for PPM format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_ppm (j_decompress_ptr cinfo)
+{
+ ppm_dest_ptr dest;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (ppm_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(ppm_dest_struct));
+ dest->pub.start_output = start_output_ppm;
+ dest->pub.finish_output = finish_output_ppm;
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ /* Create physical I/O buffer. Note we make this near on a PC. */
+ dest->samples_per_row = cinfo->output_width * cinfo->out_color_components;
+ dest->buffer_width = dest->samples_per_row * (BYTESPERSAMPLE * SIZEOF(char));
+ dest->iobuffer = (char *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width);
+
+ if (cinfo->quantize_colors || BITS_IN_JSAMPLE != 8 ||
+ SIZEOF(JSAMPLE) != SIZEOF(char)) {
+ /* When quantizing, we need an output buffer for colormap indexes
+ * that's separate from the physical I/O buffer. We also need a
+ * separate buffer if pixel format translation must take place.
+ */
+ dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->output_width * cinfo->output_components, (JDIMENSION) 1);
+ dest->pub.buffer_height = 1;
+ if (! cinfo->quantize_colors)
+ dest->pub.put_pixel_rows = copy_pixel_rows;
+ else if (cinfo->out_color_space == JCS_GRAYSCALE)
+ dest->pub.put_pixel_rows = put_demapped_gray;
+ else
+ dest->pub.put_pixel_rows = put_demapped_rgb;
+ } else {
+ /* We will fwrite() directly from decompressor output buffer. */
+ /* Synthesize a JSAMPARRAY pointer structure */
+ /* Cast here implies near->far pointer conversion on PCs */
+ dest->pixrow = (JSAMPROW) dest->iobuffer;
+ dest->pub.buffer = & dest->pixrow;
+ dest->pub.buffer_height = 1;
+ dest->pub.put_pixel_rows = put_pixel_rows;
+ }
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* PPM_SUPPORTED */
diff --git a/jpg/wrrle.c b/jpg/wrrle.c
new file mode 100644
index 0000000..a4e7337
--- /dev/null
+++ b/jpg/wrrle.c
@@ -0,0 +1,305 @@
+/*
+ * wrrle.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in RLE format.
+ * The Utah Raster Toolkit library is required (version 3.1 or later).
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ *
+ * Based on code contributed by Mike Lijewski,
+ * with updates from Robert Hutchinson.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef RLE_SUPPORTED
+
+/* rle.h is provided by the Utah Raster Toolkit. */
+
+#include <rle.h>
+
+/*
+ * We assume that JSAMPLE has the same representation as rle_pixel,
+ * to wit, "unsigned char". Hence we can't cope with 12- or 16-bit samples.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+
+/*
+ * Since RLE stores scanlines bottom-to-top, we have to invert the image
+ * from JPEG's top-to-bottom order. To do this, we save the outgoing data
+ * in a virtual array during put_pixel_row calls, then actually emit the
+ * RLE file during finish_output.
+ */
+
+
+/*
+ * For now, if we emit an RLE color map then it is always 256 entries long,
+ * though not all of the entries need be used.
+ */
+
+#define CMAPBITS 8
+#define CMAPLENGTH (1<<(CMAPBITS))
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ jvirt_sarray_ptr image; /* virtual array to store the output image */
+ rle_map *colormap; /* RLE-style color map, or NULL if none */
+ rle_pixel **rle_row; /* To pass rows to rle_putrow() */
+
+} rle_dest_struct;
+
+typedef rle_dest_struct * rle_dest_ptr;
+
+/* Forward declarations */
+METHODDEF(void) rle_put_pixel_rows
+ JPP((j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied));
+
+
+/*
+ * Write the file header.
+ *
+ * In this module it's easier to wait till finish_output to write anything.
+ */
+
+METHODDEF(void)
+start_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ rle_dest_ptr dest = (rle_dest_ptr) dinfo;
+ size_t cmapsize;
+ int i, ci;
+#ifdef PROGRESS_REPORT
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+ /*
+ * Make sure the image can be stored in RLE format.
+ *
+ * - RLE stores image dimensions as *signed* 16 bit integers. JPEG
+ * uses unsigned, so we have to check the width.
+ *
+ * - Colorspace is expected to be grayscale or RGB.
+ *
+ * - The number of channels (components) is expected to be 1 (grayscale/
+ * pseudocolor) or 3 (truecolor/directcolor).
+ * (could be 2 or 4 if using an alpha channel, but we aren't)
+ */
+
+ if (cinfo->output_width > 32767 || cinfo->output_height > 32767)
+ ERREXIT2(cinfo, JERR_RLE_DIMENSIONS, cinfo->output_width,
+ cinfo->output_height);
+
+ if (cinfo->out_color_space != JCS_GRAYSCALE &&
+ cinfo->out_color_space != JCS_RGB)
+ ERREXIT(cinfo, JERR_RLE_COLORSPACE);
+
+ if (cinfo->output_components != 1 && cinfo->output_components != 3)
+ ERREXIT1(cinfo, JERR_RLE_TOOMANYCHANNELS, cinfo->num_components);
+
+ /* Convert colormap, if any, to RLE format. */
+
+ dest->colormap = NULL;
+
+ if (cinfo->quantize_colors) {
+ /* Allocate storage for RLE-style cmap, zero any extra entries */
+ cmapsize = cinfo->out_color_components * CMAPLENGTH * SIZEOF(rle_map);
+ dest->colormap = (rle_map *) (*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, cmapsize);
+ MEMZERO(dest->colormap, cmapsize);
+
+ /* Save away data in RLE format --- note 8-bit left shift! */
+ /* Shifting would need adjustment for JSAMPLEs wider than 8 bits. */
+ for (ci = 0; ci < cinfo->out_color_components; ci++) {
+ for (i = 0; i < cinfo->actual_number_of_colors; i++) {
+ dest->colormap[ci * CMAPLENGTH + i] =
+ GETJSAMPLE(cinfo->colormap[ci][i]) << 8;
+ }
+ }
+ }
+
+ /* Set the output buffer to the first row */
+ dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->image, (JDIMENSION) 0, (JDIMENSION) 1, TRUE);
+ dest->pub.buffer_height = 1;
+
+ dest->pub.put_pixel_rows = rle_put_pixel_rows;
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->total_extra_passes++; /* count file writing as separate pass */
+ }
+#endif
+}
+
+
+/*
+ * Write some pixel data.
+ *
+ * This routine just saves the data away in a virtual array.
+ */
+
+METHODDEF(void)
+rle_put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ rle_dest_ptr dest = (rle_dest_ptr) dinfo;
+
+ if (cinfo->output_scanline < cinfo->output_height) {
+ dest->pub.buffer = (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->image,
+ cinfo->output_scanline, (JDIMENSION) 1, TRUE);
+ }
+}
+
+/*
+ * Finish up at the end of the file.
+ *
+ * Here is where we really output the RLE file.
+ */
+
+METHODDEF(void)
+finish_output_rle (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ rle_dest_ptr dest = (rle_dest_ptr) dinfo;
+ rle_hdr header; /* Output file information */
+ rle_pixel **rle_row, *red, *green, *blue;
+ JSAMPROW output_row;
+ char cmapcomment[80];
+ int row, col;
+ int ci;
+#ifdef PROGRESS_REPORT
+ cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
+#endif
+
+ /* Initialize the header info */
+ header = *rle_hdr_init(NULL);
+ header.rle_file = dest->pub.output_file;
+ header.xmin = 0;
+ header.xmax = cinfo->output_width - 1;
+ header.ymin = 0;
+ header.ymax = cinfo->output_height - 1;
+ header.alpha = 0;
+ header.ncolors = cinfo->output_components;
+ for (ci = 0; ci < cinfo->output_components; ci++) {
+ RLE_SET_BIT(header, ci);
+ }
+ if (cinfo->quantize_colors) {
+ header.ncmap = cinfo->out_color_components;
+ header.cmaplen = CMAPBITS;
+ header.cmap = dest->colormap;
+ /* Add a comment to the output image with the true colormap length. */
+ sprintf(cmapcomment, "color_map_length=%d", cinfo->actual_number_of_colors);
+ rle_putcom(cmapcomment, &header);
+ }
+
+ /* Emit the RLE header and color map (if any) */
+ rle_put_setup(&header);
+
+ /* Now output the RLE data from our virtual array.
+ * We assume here that (a) rle_pixel is represented the same as JSAMPLE,
+ * and (b) we are not on a machine where FAR pointers differ from regular.
+ */
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_limit = cinfo->output_height;
+ progress->pub.pass_counter = 0;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+
+ if (cinfo->output_components == 1) {
+ for (row = cinfo->output_height-1; row >= 0; row--) {
+ rle_row = (rle_pixel **) (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->image,
+ (JDIMENSION) row, (JDIMENSION) 1, FALSE);
+ rle_putrow(rle_row, (int) cinfo->output_width, &header);
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ } else {
+ for (row = cinfo->output_height-1; row >= 0; row--) {
+ rle_row = (rle_pixel **) dest->rle_row;
+ output_row = * (*cinfo->mem->access_virt_sarray)
+ ((j_common_ptr) cinfo, dest->image,
+ (JDIMENSION) row, (JDIMENSION) 1, FALSE);
+ red = rle_row[0];
+ green = rle_row[1];
+ blue = rle_row[2];
+ for (col = cinfo->output_width; col > 0; col--) {
+ *red++ = GETJSAMPLE(*output_row++);
+ *green++ = GETJSAMPLE(*output_row++);
+ *blue++ = GETJSAMPLE(*output_row++);
+ }
+ rle_putrow(rle_row, (int) cinfo->output_width, &header);
+#ifdef PROGRESS_REPORT
+ if (progress != NULL) {
+ progress->pub.pass_counter++;
+ (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
+ }
+#endif
+ }
+ }
+
+#ifdef PROGRESS_REPORT
+ if (progress != NULL)
+ progress->completed_extra_passes++;
+#endif
+
+ /* Emit file trailer */
+ rle_puteof(&header);
+ fflush(dest->pub.output_file);
+ if (ferror(dest->pub.output_file))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for RLE format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_rle (j_decompress_ptr cinfo)
+{
+ rle_dest_ptr dest;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (rle_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(rle_dest_struct));
+ dest->pub.start_output = start_output_rle;
+ dest->pub.finish_output = finish_output_rle;
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ /* Allocate a work array for output to the RLE library. */
+ dest->rle_row = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ cinfo->output_width, (JDIMENSION) cinfo->output_components);
+
+ /* Allocate a virtual array to hold the image. */
+ dest->image = (*cinfo->mem->request_virt_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
+ (JDIMENSION) (cinfo->output_width * cinfo->output_components),
+ cinfo->output_height, (JDIMENSION) 1);
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* RLE_SUPPORTED */
diff --git a/jpg/wrtarga.c b/jpg/wrtarga.c
new file mode 100644
index 0000000..cf104d2
--- /dev/null
+++ b/jpg/wrtarga.c
@@ -0,0 +1,253 @@
+/*
+ * wrtarga.c
+ *
+ * Copyright (C) 1991-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains routines to write output images in Targa format.
+ *
+ * These routines may need modification for non-Unix environments or
+ * specialized applications. As they stand, they assume output to
+ * an ordinary stdio stream.
+ *
+ * Based on code contributed by Lee Daniel Crocker.
+ */
+
+#include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
+
+#ifdef TARGA_SUPPORTED
+
+
+/*
+ * To support 12-bit JPEG data, we'd have to scale output down to 8 bits.
+ * This is not yet implemented.
+ */
+
+#if BITS_IN_JSAMPLE != 8
+ Sorry, this code only copes with 8-bit JSAMPLEs. /* deliberate syntax err */
+#endif
+
+/*
+ * The output buffer needs to be writable by fwrite(). On PCs, we must
+ * allocate the buffer in near data space, because we are assuming small-data
+ * memory model, wherein fwrite() can't reach far memory. If you need to
+ * process very wide images on a PC, you might have to compile in large-memory
+ * model, or else replace fwrite() with a putc() loop --- which will be much
+ * slower.
+ */
+
+
+/* Private version of data destination object */
+
+typedef struct {
+ struct djpeg_dest_struct pub; /* public fields */
+
+ char *iobuffer; /* physical I/O buffer */
+ JDIMENSION buffer_width; /* width of one row */
+} tga_dest_struct;
+
+typedef tga_dest_struct * tga_dest_ptr;
+
+
+LOCAL(void)
+write_header (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors)
+/* Create and write a Targa header */
+{
+ char targaheader[18];
+
+ /* Set unused fields of header to 0 */
+ MEMZERO(targaheader, SIZEOF(targaheader));
+
+ if (num_colors > 0) {
+ targaheader[1] = 1; /* color map type 1 */
+ targaheader[5] = (char) (num_colors & 0xFF);
+ targaheader[6] = (char) (num_colors >> 8);
+ targaheader[7] = 24; /* 24 bits per cmap entry */
+ }
+
+ targaheader[12] = (char) (cinfo->output_width & 0xFF);
+ targaheader[13] = (char) (cinfo->output_width >> 8);
+ targaheader[14] = (char) (cinfo->output_height & 0xFF);
+ targaheader[15] = (char) (cinfo->output_height >> 8);
+ targaheader[17] = 0x20; /* Top-down, non-interlaced */
+
+ if (cinfo->out_color_space == JCS_GRAYSCALE) {
+ targaheader[2] = 3; /* image type = uncompressed gray-scale */
+ targaheader[16] = 8; /* bits per pixel */
+ } else { /* must be RGB */
+ if (num_colors > 0) {
+ targaheader[2] = 1; /* image type = colormapped RGB */
+ targaheader[16] = 8;
+ } else {
+ targaheader[2] = 2; /* image type = uncompressed RGB */
+ targaheader[16] = 24;
+ }
+ }
+
+ if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t) 18)
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * Write some pixel data.
+ * In this module rows_supplied will always be 1.
+ */
+
+METHODDEF(void)
+put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+/* used for unquantized full-color output */
+{
+ tga_dest_ptr dest = (tga_dest_ptr) dinfo;
+ register JSAMPROW inptr;
+ register char * outptr;
+ register JDIMENSION col;
+
+ inptr = dest->pub.buffer[0];
+ outptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ outptr[0] = (char) GETJSAMPLE(inptr[2]); /* RGB to BGR order */
+ outptr[1] = (char) GETJSAMPLE(inptr[1]);
+ outptr[2] = (char) GETJSAMPLE(inptr[0]);
+ inptr += 3, outptr += 3;
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+METHODDEF(void)
+put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+/* used for grayscale OR quantized color output */
+{
+ tga_dest_ptr dest = (tga_dest_ptr) dinfo;
+ register JSAMPROW inptr;
+ register char * outptr;
+ register JDIMENSION col;
+
+ inptr = dest->pub.buffer[0];
+ outptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ *outptr++ = (char) GETJSAMPLE(*inptr++);
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Write some demapped pixel data when color quantization is in effect.
+ * For Targa, this is only applied to grayscale data.
+ */
+
+METHODDEF(void)
+put_demapped_gray (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
+ JDIMENSION rows_supplied)
+{
+ tga_dest_ptr dest = (tga_dest_ptr) dinfo;
+ register JSAMPROW inptr;
+ register char * outptr;
+ register JSAMPROW color_map0 = cinfo->colormap[0];
+ register JDIMENSION col;
+
+ inptr = dest->pub.buffer[0];
+ outptr = dest->iobuffer;
+ for (col = cinfo->output_width; col > 0; col--) {
+ *outptr++ = (char) GETJSAMPLE(color_map0[GETJSAMPLE(*inptr++)]);
+ }
+ (void) JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width);
+}
+
+
+/*
+ * Startup: write the file header.
+ */
+
+METHODDEF(void)
+start_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ tga_dest_ptr dest = (tga_dest_ptr) dinfo;
+ int num_colors, i;
+ FILE *outfile;
+
+ if (cinfo->out_color_space == JCS_GRAYSCALE) {
+ /* Targa doesn't have a mapped grayscale format, so we will */
+ /* demap quantized gray output. Never emit a colormap. */
+ write_header(cinfo, dinfo, 0);
+ if (cinfo->quantize_colors)
+ dest->pub.put_pixel_rows = put_demapped_gray;
+ else
+ dest->pub.put_pixel_rows = put_gray_rows;
+ } else if (cinfo->out_color_space == JCS_RGB) {
+ if (cinfo->quantize_colors) {
+ /* We only support 8-bit colormap indexes, so only 256 colors */
+ num_colors = cinfo->actual_number_of_colors;
+ if (num_colors > 256)
+ ERREXIT1(cinfo, JERR_TOO_MANY_COLORS, num_colors);
+ write_header(cinfo, dinfo, num_colors);
+ /* Write the colormap. Note Targa uses BGR byte order */
+ outfile = dest->pub.output_file;
+ for (i = 0; i < num_colors; i++) {
+ putc(GETJSAMPLE(cinfo->colormap[2][i]), outfile);
+ putc(GETJSAMPLE(cinfo->colormap[1][i]), outfile);
+ putc(GETJSAMPLE(cinfo->colormap[0][i]), outfile);
+ }
+ dest->pub.put_pixel_rows = put_gray_rows;
+ } else {
+ write_header(cinfo, dinfo, 0);
+ dest->pub.put_pixel_rows = put_pixel_rows;
+ }
+ } else {
+ ERREXIT(cinfo, JERR_TGA_COLORSPACE);
+ }
+}
+
+
+/*
+ * Finish up at the end of the file.
+ */
+
+METHODDEF(void)
+finish_output_tga (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
+{
+ /* Make sure we wrote the output file OK */
+ fflush(dinfo->output_file);
+ if (ferror(dinfo->output_file))
+ ERREXIT(cinfo, JERR_FILE_WRITE);
+}
+
+
+/*
+ * The module selection routine for Targa format output.
+ */
+
+GLOBAL(djpeg_dest_ptr)
+jinit_write_targa (j_decompress_ptr cinfo)
+{
+ tga_dest_ptr dest;
+
+ /* Create module interface object, fill in method pointers */
+ dest = (tga_dest_ptr)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ SIZEOF(tga_dest_struct));
+ dest->pub.start_output = start_output_tga;
+ dest->pub.finish_output = finish_output_tga;
+
+ /* Calculate output image dimensions so we can allocate space */
+ jpeg_calc_output_dimensions(cinfo);
+
+ /* Create I/O buffer. Note we make this near on a PC. */
+ dest->buffer_width = cinfo->output_width * cinfo->output_components;
+ dest->iobuffer = (char *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
+ (size_t) (dest->buffer_width * SIZEOF(char)));
+
+ /* Create decompressor output buffer. */
+ dest->pub.buffer = (*cinfo->mem->alloc_sarray)
+ ((j_common_ptr) cinfo, JPOOL_IMAGE, dest->buffer_width, (JDIMENSION) 1);
+ dest->pub.buffer_height = 1;
+
+ return (djpeg_dest_ptr) dest;
+}
+
+#endif /* TARGA_SUPPORTED */
diff --git a/lib/Readme.txt b/lib/Readme.txt
new file mode 100644
index 0000000..79e1dde
--- /dev/null
+++ b/lib/Readme.txt
@@ -0,0 +1 @@
+The libraries may be installed here.
diff --git a/lib/afiles b/lib/afiles
new file mode 100644
index 0000000..c519e4e
--- /dev/null
+++ b/lib/afiles
@@ -0,0 +1,2 @@
+Readme.txt
+afiles
diff --git a/link/Jamfile b/link/Jamfile
new file mode 100644
index 0000000..4d4dc24
--- /dev/null
+++ b/link/Jamfile
@@ -0,0 +1,36 @@
+
+# JAM style makefile for collink and friends
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCPROFFLAG) ; # Profile flags
+#PREF_LINKFLAGS += $(LINKPROFFLAG) ; # Profile flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Link debugging flags
+
+#Products
+Executables = collink ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+
+HDRS = ../h ../icc ../rspl ../plot ../numlib $(TIFFINC) ;
+LINKLIBS = $(TIFFLIB) $(JPEGLIB) ../icc/libicc ../plot/libplot ../numlib/libnum $(LibWin) ;
+
+# K only reprocessor
+#Main icc2ko : icc2ko.c ;
+
+# Monochrome transfer curve plotter
+Main monoplot : monoplot.c ;
+
+HDRS += ../cgats ../xicc ../spectro ../gamut ;
+LINKLIBS = ../xicc/libxicc ../xicc/libxcolorants ../gamut/libgamut.c
+ ../gamut/libgammap ../rspl/librspl ../cgats/libcgats
+ ../plot/libvrml $(LINKLIBS) ;
+
+# ICC linker
+Main collink : collink.c ;
+
+# Device path L curve plotter
+Main pathplot : pathplot.c ;
+
diff --git a/link/License.txt b/link/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/link/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/link/Makefile.am b/link/Makefile.am
new file mode 100644
index 0000000..37a3ac9
--- /dev/null
+++ b/link/Makefile.am
@@ -0,0 +1,11 @@
+include $(top_srcdir)/Makefile.shared
+
+LDADD = ../spectro/libinsttypes.la ../xicc/libxicc.la \
+ ../xicc/libxutils.la ../gamut/libgamut.la \
+ ../gamut/libgammap.la ../plot/libplot.la ../plot/libvrml.la \
+ ../rspl/librspl.la $(ICC_LIBS) ../cgats/libcgats.la \
+ ../numlib/libargyllnum.la ../libargyll.la $(X_LIBS) $(TIFF_LIBS)
+
+bin_PROGRAMS = collink pathplot
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/link/Readme.txt b/link/Readme.txt
new file mode 100644
index 0000000..9e8dacc
--- /dev/null
+++ b/link/Readme.txt
@@ -0,0 +1,6 @@
+This direcory holds the top level icc link code.
+
+collink.exe takes two device ICC profiles, and links
+ then together in a simple fashion, producing
+ a device link ICC profile.
+
diff --git a/link/afiles b/link/afiles
new file mode 100644
index 0000000..7c73bd7
--- /dev/null
+++ b/link/afiles
@@ -0,0 +1,7 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+collink.c
+monoplot.c
+pathplot.c
diff --git a/link/collink.c b/link/collink.c
new file mode 100644
index 0000000..6c40efd
--- /dev/null
+++ b/link/collink.c
@@ -0,0 +1,3298 @@
+
+/*
+ * collink
+ *
+ * Link two device profiles to create a Device Link Profile
+ *
+ * Author: Graeme W. Gill
+ * Date: 25/11/00
+ * Version: 2.10
+ *
+ * Copyright 2000 - 2005 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.
+ */
+
+/* TTBD:
+ *
+ * Device curve resolution should be taken from the device profiles,
+ * rather than depending on the quality settings (scRGB compression curves)
+ *
+ * Abstract link support intent doesn't work properly for anything
+ * other than absolute. This should really be fixed.
+ */
+
+/* NOTES:
+
+ Normally the device side per channel curves are copied from
+ the source profiles to the link profile on the assumption that
+ the raw linearisation they do is good, and should be maintained
+ for best overall transform accuracy. Since the intermediate
+ link is done in an Lab like space, then this linearisation
+ will even out quantisation error introduced by the Lut
+ in perceptual space. In the case of a Matrix profile with a native
+ XYZ PCS, these assumptions break, since the device curves
+ would generally be linearising the device to Y, not a perceptual
+ space. For this reason we add a Y to L* type curve to the input
+ linearisation curves. For XYZ CLUT based profiles, we just have
+ to hope that the profile has been created well, and that the
+ input curves distribute the indexes reasonably perceptually
+ evenly. For an output (XYZ) Matrix profile, we also
+ use an L* style mixing space.
+
+ In general the per channel curves should be:
+
+ No curve, or
+
+ An optimized curve, or
+
+ The source profile per channel curve plus
+ a Y to L* curve it's a Matrix profile.
+
+
+ Colorspace representations are a bit of a mess. It's hard to know what space
+ color is in at any point, and difficult to transform to match
+ some other element. Putting the different colorspace support within
+ the profile transforms is neat, but may not be flexible enough, since the
+ needed information to do a transform (white point, viewing conditions)
+ might be a bit too closely bound into the profile. An alternative might be
+ to expand the colorspace definition from a tag to include all the
+ other needed information, and create a general colorspace adapter
+ to transform from one to the other, or to limit connections
+ to a cannonical spaces such as XYZ.
+ One big cause of confusion for user and implimentor is how to
+ handle the conflicting intents. What does it mean to link
+ a relative source to absolute abstract to CAM destination ???
+
+ A non-absolute abstract profile is poorly defined (just like
+ the device profiles) if it doesn't define the viewing conditions
+ within which the transform is defined.
+
+ Having separated creating a gamut surface for a raster out
+ (for better modularity), it then creates problems in applying
+ an abstact transform. The abstract transform can't really be
+ applied to a gamut surface, it really needs to be applied
+ to the image data before gamut surface extraction. This is yet
+ another avenue for user & implementor confusion, with regard
+ to intents, even without allowing the user to set the intent
+ of the abstract profile.
+
+ */
+
+#undef USE_MERGE_CLUT_OPT /* [Undef] When using inverse A2B table, merge the output luts */
+ /* with the clut for faster operation, and clipping in */
+ /* Jab space. Turned off because it affects the accuracy too much, */
+ /* and xicc handles Jab clip without this now. */
+
+#define USE_CAM_CLIP_OPT /* [Define] Clip out of gamut in CAM space rather than XYZ or L*a*b* */
+#define ENKHACK /* [Define] Enable K hack code */
+#undef WARN_CLUT_CLIPPING /* [Undef] Print warning if setting clut clips */
+
+#undef DEBUG /* Report values of each sample transformed */
+#undef DEBUGC /* ie "if (tt)" */ /* Debug condition */
+#undef DEBUG_ONE /* test a single value out. Look for DBGNO to set value. */
+#undef NEUTKDEBUG /* print info about neutral L -> K mapping */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xicc.h"
+#include "gamut.h"
+#include "gammap.h"
+// ~~~99
+#include "vrml.h"
+
+void usage(char *diag, ...) {
+ int i;
+ fprintf(stderr,"Link ICC profiles, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: collink [options] srcprofile dstprofile linkedprofile\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -A manufacturer Manufacturer description string\n");
+ fprintf(stderr," -M model Model description string\n");
+ fprintf(stderr," -D description Profile Description string (Default \"inoutfile\")\n");
+ fprintf(stderr," -C copyright Copyright string\n");
+ fprintf(stderr," -V Verify existing profile, rather than link\n");
+ fprintf(stderr," -q lmhu Quality - Low, Medium (def), High, Ultra\n");
+// fprintf(stderr," -q fmsu Speed - Fast, Medium (def), Slow, Ultra Slow\n");
+ fprintf(stderr," -r res Override clut res. set by -q\n");
+ fprintf(stderr," -n Don't preserve device linearization curves in result\n");
+ fprintf(stderr," -f Special :- Force neutral colors to be K only output\n");
+ fprintf(stderr," -fk Special :- Force K only neutral colors to be K only output\n");
+ fprintf(stderr," -F Special :- Force all colors to be K only output\n");
+ fprintf(stderr," -fcmy Special :- Force 100%% C,M or Y only to stay pure \n");
+ fprintf(stderr," -p absprof Include abstract profile in link\n");
+ fprintf(stderr," -s Simple Mode (default)\n");
+ fprintf(stderr," -g [src.gam] Gamut Mapping Mode [optional source image gamut]\n");
+ fprintf(stderr," -G [src.gam] Gamut Mapping Mode using inverse outprofile A2B\n");
+ fprintf(stderr," Simple Mode Options:\n");
+ fprintf(stderr," -i in_intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute colorimetric\n");
+ fprintf(stderr," -o out_intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute colorimetric\n");
+ fprintf(stderr," Gamut Mapping Mode Options:\n");
+ fprintf(stderr," -i intent set linking intent from the following choice:\n");
+ for (i = 0; ; i++) {
+ icxGMappingIntent gmi;
+ if (xicc_enum_gmapintent(&gmi, i, NULL) == icxIllegalGMIntent)
+ break;
+
+ fprintf(stderr," %s\n",gmi.desc);
+ }
+ fprintf(stderr," -w [J,a,b] Use forced whitepoint hack [optional target point]\n");
+// fprintf(stderr," -W J,a,b Forced whitepoint adjustment by delta Jab\n");
+ fprintf(stderr," -c viewcond set source viewing conditions for %s,\n",icxcam_description(cam_default));
+ fprintf(stderr," either an enumerated choice, or a parameter\n");
+ fprintf(stderr," -d viewcond set destination viewing conditions for %s,\n",icxcam_description(cam_default));
+ fprintf(stderr," either an enumerated choice, or parameter:value changes\n");
+ for (i = 0; ; i++) {
+ icxViewCond vc;
+ if (xicc_enum_viewcond(NULL, &vc, i, NULL, 1, NULL) == -999)
+ break;
+
+ fprintf(stderr," %s\n",vc.desc);
+ }
+ fprintf(stderr," s:surround n = auto, a = average, m = dim, d = dark,\n");
+ fprintf(stderr," c = transparency (default average)\n");
+ fprintf(stderr," w:X:Y:Z Adapted white point as XYZ (default media white)\n");
+ fprintf(stderr," w:x:y Adapted white point as x, y\n");
+ fprintf(stderr," a:adaptation Adaptation luminance in cd.m^2 (default 50.0)\n");
+ fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
+ fprintf(stderr," l:scenewhite Scene white in cd.m^2 if surround = auto (default 250)\n");
+ fprintf(stderr," f:flare Flare light %% of image luminance (default 1)\n");
+ fprintf(stderr," f:X:Y:Z Flare color as XYZ (default media white)\n");
+ fprintf(stderr," f:x:y Flare color as x, y\n");
+ fprintf(stderr," -t tlimit set source total ink limit, 0 - 400%% (estimate by default)\n");
+ fprintf(stderr," -T klimit set source black ink limit, 0 - 100%% (estimate by default)\n");
+ fprintf(stderr," Inverse outprofile A2B Options:\n");
+ fprintf(stderr," -k tezhxr CMYK Black generation\n");
+ fprintf(stderr," t = transfer K from source to destination, e = retain K of destination B2A table\n");
+ fprintf(stderr," z = zero K, h = 0.5 K, x = maximum K, r = ramp K (default)\n");
+ fprintf(stderr," -k p stle stpo enpo enle shape\n");
+ fprintf(stderr," p = black target generation curve parameters\n");
+ fprintf(stderr," -k q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2\n");
+ fprintf(stderr," q = transfer source K to dual curve limits\n");
+ fprintf(stderr," -K parameters Same as -k, but target is K locus rather than K value itself\n");
+ fprintf(stderr," -l tlimit set destination total ink limit, 0 - 400%% (estimate by default)\n");
+ fprintf(stderr," -L klimit set destination black ink limit, 0 - 100%% (estimate by default)\n");
+ fprintf(stderr," -P Create gamut gammap.wrl diagostic\n");
+ exit(1);
+}
+
+/* ------------------------------------------- */
+/* structures to support icc calbacks */
+
+/* Information needed from a profile */
+struct _profinfo {
+ /* Setup parameters */
+ icRenderingIntent intent; /* Selected ICC rendering intent */
+ icxViewCond vc; /* Viewing Condition for CAM */
+ int inking; /* k inking algorithm, 0 = input, 1 = min, */
+ /* 2 = 0.5, 3 = max, 4 = ramp, 5 = curve, 6 = dual curve */
+ /* 7 = outpupt profile K value */
+ int locus; /* 0 = K target value, 1 = K locus value */
+ icxInk ink; /* Ink parameters */
+
+ /* Operational parameters */
+ icc *c;
+ icmHeader *h;
+ xicc *x;
+ icxLuBase *luo; /* Base XLookup type object */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ icColorSpaceSignature csp; /* Colorspace */
+ int chan; /* Channels */
+ int nocurve; /* NZ to not use device curve in per channel curve */
+ int lcurve; /* 1 to apply a Y like to L* curve for XYZ Matrix profiles */
+ /* 2 to apply a Y to L* curve for XYZ space */
+ double wp[3]; /* Lab/Jab white point for profile used by wphack & xyzscale */
+ icxLuBase *b2aluo; /* B2A lookup for inking == 7 */
+}; typedef struct _profinfo profinfo;
+
+/* Structure that holds all the color lookup information */
+struct _clink {
+ /* Overall options */
+ int verb;
+ int gamdiag; /* nz, create gammap.wrl diagnostic */
+ int total, count, last; /* Progress count information */
+ int mode; /* 0 = simple mode, 1 = mapping mode, 2 = mapping mode with inverse A2B */
+ int quality; /* 0 = low, 1 = medium, 2 = high, 3 = ultra */
+ int clutres; /* 0 = quality default, !0 = override, then actual during link */
+ int src_kbp; /* nz = Use K only black point as src gamut black point */
+ int dst_kbp; /* nz = Use K only black point as dst gamut black point */
+ int dst_cmymap; /* masks C = 1, M = 2, Y = 4 to force 100% cusp map */
+
+ icColorSpaceSignature pcsor; /* PCS to use between in & out profiles */
+
+ int nhack; /* 0 = off, 1 = hack to map input neutrals to output K only, */
+ /* 2 = map 000K to output K only, 3 = all to K */
+ int cmyhack; /* CMY 100% colorant map though hack, 1 = C, 2 = M, 4 = Y */
+ rspl *pcs2k; /* PCS L to K' lookup for nhack */
+ int wphack; /* 0 = off, 1 = hack to map input wp to output wp, 2 = to hwp[] */
+ double hwp[3]; /* hack destination white point in PCS space */
+ int wphacked; /* Operation flag, set nz if white point was translated */
+ int rel_oride; /* Relative override flag */
+
+ icmFile *abs_fp; /* Abstract profile transform */
+ icRenderingIntent abs_intent;
+ icc *abs_icc;
+ xicc *abs_xicc;
+ icxLuBase *abs_luo; /* NULL if none */
+
+ /* (We current assume that xyzscale can't be used with gmi) */
+ double xyzscale; /* < 1.0 if Y is to be scaled in destination XYZ space */
+ double swxyz[3]; /* Source white point in XYZ */
+
+ icxGMappingIntent gmi;
+ gammap *map; /* Gamut mapping */
+ gammap *Kmap; /* Gamut mapping K in to K out nhack == 2 and K in to K out */
+
+
+ /* Per profile setup information */
+ profinfo in;
+ profinfo out;
+
+}; typedef struct _clink clink;
+
+
+/* ------------------------------------------- */
+//#define YSCALE 1.0
+#define YSCALE (2.0/1.3)
+
+/* Extra non-linearity applied to BtoA XYZ PCS */
+/* This distributes the LUT indexes more evenly in */
+/* perceptual space, greatly improving the B2A accuracy of XYZ LUT */
+/* Since typically XYZ doesn't use the full range of 0-2.0 allowed */
+/* for in the encoding, we scale the cLUT index values to use the 0-1.3 range */
+
+/* (For these functions the encoded XYZ 0.0 - 2.0 range is 0.0 - 1.0 ??) */
+
+/* Y to L* */
+static void y2l_curve(double *out, double *in, int isXYZ) {
+ int i;
+ double val;
+ double isc = 1.0, osc = 1.0;
+
+ /* Scale from 0.0 .. 1.999969 to 0.0 .. 1.0 and back */
+ /* + range adjustment */
+ if (isXYZ) {
+ isc = 32768.0/65535.0 * YSCALE;
+ osc = 65535.0/32768.0;
+ }
+
+ for (i = 0; i < 3; i++) {
+ val = in[i] * isc;
+ if (val > 0.008856451586)
+ val = 1.16 * pow(val,1.0/3.0) - 0.16;
+ else
+ val = 9.032962896 * val;
+ if (val > 1.0)
+ val = 1.0;
+ out[i] = val * osc;
+ }
+}
+
+/* L* to Y */
+static void l2y_curve(double *out, double *in, int isXYZ) {
+ int i;
+ double val;
+ double isc = 1.0, osc = 1.0;
+
+ /* Scale from 0.0 .. 1.999969 to 0.0 .. 1.0 and back */
+ /* + range adjustment */
+ if (isXYZ) {
+ isc = 32768.0/65535.0;
+ osc = 65535.0/32768.0 / YSCALE;
+ }
+
+ /* Use an L* like curve, scaled to the maximum XYZ value */
+ for (i = 0; i < 3; i++) {
+ val = in[i] * isc;
+ if (val > 0.08)
+ val = pow((val + 0.16)/1.16, 3.0);
+ else
+ val = val/9.032962896;
+ out[i] = val * osc;
+ }
+}
+
+/* ------------------------------------------- */
+/* Functions called back in setting up the transform table */
+
+#ifdef DEBUGC
+
+static int tt = 0;
+
+#endif /* DEBUGC */
+
+/* Input table, DevIn -> DevIn' */
+void devi_devip(void *cntx, double *out, double *in) {
+ int rv = 0;
+ clink *p = (clink *)cntx;
+
+#ifdef DEBUGC
+ if (in[0] == 1.0 && in[1] == 1.0 && in[2] == 1.0 && in[3])
+ tt = 1;
+#endif
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("DevIn->DevIn' got %f %f %f %f\n",in[0], in[1], in[2], in[3]); fflush(stdout);
+#endif
+
+ if (p->in.nocurve) { /* Don't use profile per channel curves */
+ int i;
+ for (i = 0; i < p->in.chan; i++)
+ out[i] = in[i];
+ } else { /* Use input profile per channel curves */
+ switch(p->in.alg) {
+ case icmMonoFwdType: {
+ icxLuMono *lu = (icxLuMono *)p->in.luo; /* Safe to coerce */
+ rv |= lu->fwd_curve(lu, out, in);
+ break;
+ }
+ case icmMatrixFwdType: {
+ icxLuMatrix *lu = (icxLuMatrix *)p->in.luo; /* Safe to coerce */
+ rv |= lu->fwd_curve(lu, out, in);
+ break;
+ }
+ case icmLutType: {
+ icxLuLut *lu = (icxLuLut *)p->in.luo; /* Safe to coerce */
+ /* Since not PCS, in_abs and matrix cannot be valid, */
+ /* so input curve on own is ok to use. */
+ rv |= lu->input(lu, out, in);
+ break;
+ }
+ default:
+ error("Unexpected algorithm type %d in devi_devip()",p->in.alg);
+ }
+ if (rv >= 2)
+ error("icc lookup failed: %d, %s",p->in.c->errc,p->in.c->err);
+ }
+
+ if (p->in.lcurve) { /* Apply Y to L* */
+//printf("~1 y2l_curve got %f %f %f, isXYZ %d\n",in[0],in[1],in[2],p->in.lcurve == 2);
+ y2l_curve(out, out, p->in.lcurve == 2);
+ }
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("DevIn->DevIn' ret %f %f %f %f\n",out[0], out[1], out[2], in[3]); fflush(stdout);
+#endif
+}
+
+
+/* - - - - - - - - - - - - */
+/* clut, DevIn' -> DevOut' */
+void devip_devop(void *cntx, double *out, double *in) {
+ double win[MAX_CHAN]; /* working input values */
+ double pcsv[MAX_CHAN]; /* PCS intermediate value, pre-gamut map */
+ double pcsvm[MAX_CHAN]; /* PCS intermediate value, post-gamut map */
+ double locus[MAX_CHAN]; /* Auxiliary locus values */
+ int wptrig = 0; /* White point hack triggered */
+ double konlyness = 0.0; /* Degree of K onlyness */
+ int ntrig = 0; /* K only output hack triggered */
+ int cmytrig = 0; /* CMY output hack triggered */
+ int i, rv = 0;
+ clink *p = (clink *)cntx;
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("DevIn'->DevOut' got %f %f %f %f\n",in[0], in[1], in[2], in[3]); fflush(stdout);
+#endif
+
+#ifdef ENKHACK
+ /* Handle neutral recognition/output K only hack */
+ /* (see discussion at top of file for generalization of this idea) */
+ if (p->nhack == 1 || p->nhack == 2) {
+ double thr = (0.5)/(p->clutres-1.0); /* Match threshold */
+
+ if (p->nhack == 1) {
+ /* We want to see if the input colors are equal (Or a=b= 0.0 ??) */
+ /* li.nhack should have set p->in.nocurve, so we should be getting raw */
+ /* input space device values here. It also made sure that there are at */
+ /* least 3 input channels. */
+
+ if (fabs(in[0] - in[1]) < thr
+ && fabs(in[1] - in[2]) < thr
+ && fabs(in[2] - in[0]) < thr)
+ ntrig = 1; /* K only output triggered flag */
+
+ } else if (p->nhack == 2) {
+ double maxcmy; /* Comute a degree of source "K onlyness" */
+ double maxcmyk;
+
+ maxcmy = in[0]; /* Compute minimum of CMY */
+ if (in[1] > maxcmy)
+ maxcmy = in[1];
+ if (in[2] > maxcmy)
+ maxcmy = in[2];
+
+ maxcmyk = maxcmy; /* Compute minimum of all inks */
+ if (in[3] > maxcmyk)
+ maxcmyk = in[3];
+
+//printf("~1 maxcmy = %f, maxcmyk = %f, in[3] = %f\n",maxcmy,maxcmyk,in[3]);
+ if (in[3] <= 0.0 || maxcmy > in[3]) {
+ konlyness = 0.0;
+ } else {
+ konlyness = (in[3] - maxcmy)/in[3];
+ }
+
+ /* As we approach no colorant, blend towards no Konlyness */
+ if (maxcmyk < 0.2)
+ konlyness *= maxcmyk/0.2;
+
+ /* We want to see if the input colors are exactly K only. */
+ if (in[0] < thr
+ && in[1] < thr
+ && in[2] < thr)
+ ntrig = 1; /* K only output triggered flag */
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("konlyness set to %f\n",konlyness);
+#endif
+
+ }
+ }
+ /* Handle 100% CMY hack */
+ if (p->cmyhack != 0) {
+ double thr = (0.5)/(p->clutres-1.0); /* Match threshold */
+
+ if (p->cmyhack & 1) {
+ if (in[0] > (1.0 - thr)
+ && in[1] < thr
+ && in[2] < thr
+ && (p->in.chan < 4 || in[3] < thr))
+ cmytrig |= 1;
+ }
+ if (p->cmyhack & 2) {
+ if (in[0] < thr
+ && in[1] > (1.0 - thr)
+ && in[2] < thr
+ && (p->in.chan < 4 || in[3] < thr))
+ cmytrig |= 2;
+ }
+ if (p->cmyhack & 4) {
+ if (in[0] < thr
+ && in[1] < thr
+ && in[2] > (1.0 - thr)
+ && (p->in.chan < 4 || in[3] < thr))
+ cmytrig |= 4;
+ }
+ }
+#endif /* ENKHACK */
+
+ if (p->in.lcurve) { /* Apply L* to Y */
+ l2y_curve(win, in, p->in.lcurve == 2);
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("win[] set to L* value %f %f %f %f\n",win[0], win[1], win[2], win[3]); fflush(stdout);
+#endif
+
+ } else {
+ for (i = 0; i < p->in.chan; i++)
+ win[i] = in[i];
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("win[] set to in[] value %f %f %f %f\n",win[0], win[1], win[2], win[3]); fflush(stdout);
+#endif
+ }
+
+ /* Do DevIn' -> PCS */
+ switch(p->in.alg) {
+ case icmMonoFwdType: {
+ icxLuMono *lu = (icxLuMono *)p->in.luo; /* Safe to coerce */
+
+ if (p->in.nocurve) { /* No explicit curve, so do implicit here */
+ rv |= lu->fwd_curve(lu, pcsv, win);
+ rv |= lu->fwd_map(lu, pcsv, pcsv);
+ } else {
+ rv |= lu->fwd_map(lu, pcsv, win);
+ }
+ rv |= lu->fwd_abs(lu, pcsv, pcsv);
+ break;
+ }
+ case icmMatrixFwdType: {
+ icxLuMatrix *lu = (icxLuMatrix *)p->in.luo; /* Safe to coerce */
+
+ if (p->in.nocurve) { /* No explicit curve, so do implicit here */
+ rv |= lu->fwd_curve(lu, pcsv, win);
+ rv |= lu->fwd_matrix(lu, pcsv, pcsv);
+ } else {
+ rv |= lu->fwd_matrix(lu, pcsv, win);
+ }
+ rv |= lu->fwd_abs(lu, pcsv, pcsv);
+ break;
+ }
+ case icmLutType: {
+ icxLuLut *lu = (icxLuLut *)p->in.luo; /* Safe to coerce */
+ if (p->in.nocurve) { /* No explicit curve, so we've got Dev */
+ /* Since not PCS, in_abs and matrix cannot be valid, */
+ /* so input curve on own is ok to use. */
+ rv |= lu->input(lu, pcsv, win); /* Dev -> Dev' */
+ rv |= lu->clut(lu, pcsv, pcsv); /* Dev' -> PCS' */
+ } else { /* We've got Dev' */
+ rv |= lu->clut(lu, pcsv, win); /* Dev' -> PCS' */
+ }
+ /* We've got the input profile PCS' at this point. */
+
+ /* If we're transfering the K value from the input profile to the */
+ /* output, copy it into locus[], which will be given to the inverse */
+ /* lookup function, else the inverse lookup will generate a K using */
+ /* the curve parameters. */
+//printf("~1 out.inking = %d\n",p->out.inking);
+ if (p->out.inking == 0 || p->out.inking == 6) {
+ if (p->out.locus) {
+ /* Converts PCS' to K locus proportion */
+ lu->clut_locus(lu, locus, pcsv, win); /* Compute possible locus values */
+//printf("~1 looked up locus value\n");
+ } else {
+ for (i = 0; i < p->in.chan; i++) /* Target is K input value */
+ locus[i] = win[i];
+ /* Convert K' to K value ready for aux target */
+ if (!p->in.nocurve) { /* we have an input curve, so convert Dev' -> Dev */
+ lu->inv_input(lu, locus, locus);
+ }
+//printf("~1 copied win to locus\n");
+ }
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("Got possible K %s of %f %f %f %f\n",p->out.locus ? "locus" : "value", locus[0],locus[1],locus[2],locus[3]);
+#endif
+ }
+ rv |= lu->output(lu, pcsv, pcsv); /* PCS' -> */
+ rv |= lu->out_abs(lu, pcsv, pcsv); /* PCS */
+ break;
+ }
+ default:
+ error("Unexpected algorithm type %d in devip of devip_devop()",p->in.alg);
+ }
+
+ /* At this point, the PCS is:
+ *
+ * If not gamut mapped:
+ * Lab in the intent selected for the source profile
+ * If gamut mapped:
+ * either
+ * Absolute Lab
+ * or
+ * Jab derived from absolute XYZ via the in/out viewing conditions
+ *
+ * and locus[] contains any auxiliar target values if the
+ * auxiliary is not being created by a rule applied to the PCS.
+ */
+
+ /*
+ * The order to do this intermediate processing is hard to figure out,
+ * as is the interaction between such elements. How should the
+ * abstract profile be properly handled ?
+ * what should we do if the wphack is on and Y scaling is on ?
+ */
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("PCS before map %f %f %f\n",pcsv[0], pcsv[1], pcsv[2]); fflush(stdout);
+#endif
+
+ if (p->wphack) {
+ int e;
+ double dd = 0.0;
+ for (e = 0; e < 3; e++) { /* Does this match the input white point ? */
+ double tt;
+ tt = pcsv[e] - p->in.wp[e];
+ dd += tt * tt;
+ }
+ dd = sqrt(dd);
+
+ if (dd < 1.0) { /* Triggered withing 1 delta E */
+ p->wphacked++;
+ wptrig = 1;
+ if (p->wphack == 2) {
+ for (e = 0; e < 3; e++) /* Map input white to given white */
+ pcsv[e] = p->hwp[e];
+ } else {
+ for (e = 0; e < 3; e++) /* Map input white to output white */
+ pcsv[e] = p->out.wp[e];
+ }
+
+#ifndef DEBUG
+ if (p->verb)
+#endif
+ {
+ printf("White point hack mapped %f %f %f to %f %f %f, hit withing %f\n",
+ p->in.wp[0],p->in.wp[1],p->in.wp[2],pcsv[0], pcsv[1], pcsv[2],dd);
+ fflush(stdout);
+ }
+ }
+ }
+
+ /* Do luminence scaling if requested */
+ if (wptrig == 0 && p->xyzscale < 1.0) {
+ double xyz[3];
+
+//printf("~1 got xyzscale = %f\n",p->xyzscale);
+//printf("PCS %f %f %f\n",pcsv[0], pcsv[1], pcsv[2]);
+
+ /* Convert our PCS to XYZ */
+ if (p->pcsor == icxSigJabData) {
+ /* We're being bad in delving inside the xluo, but we'll fix it latter */
+ p->out.luo->cam->cam_to_XYZ(p->out.luo->cam, xyz, pcsv);
+ } else
+ error("Internal :- not setup to handle Y scaling and non-Jab PCS");
+
+//printf("XYZ %f %f %f\n",xyz[0], xyz[1], xyz[2]);
+ /* Scale it */
+ xyz[0] *= p->xyzscale;
+ xyz[1] *= p->xyzscale;
+ xyz[2] *= p->xyzscale;
+
+//printf("scaled XYZ %f %f %f\n",xyz[0], xyz[1], xyz[2]);
+ /* Convert back to PCS */
+ if (p->pcsor == icxSigJabData) {
+ /* We're being bad in delving inside the xluo, but we'll fix it latter */
+ p->out.luo->cam->XYZ_to_cam(p->out.luo->cam, pcsv, xyz);
+ } else
+ error("Internal :- not setup to handle Y scaling and non-Jab PCS");
+
+//printf("scaled PCS %f %f %f\n",pcsv[0], pcsv[1], pcsv[2]);
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("PCS after Y scale %f %f %f\n",pcsv[0], pcsv[1], pcsv[2]); fflush(stdout);
+#endif
+ }
+
+
+ /* Do gamut mapping */
+ if (wptrig == 0 && p->mode > 0 && p->gmi.usemap) {
+ /* We've used pcsor to ensure PCS space is appropriate */
+
+ /* Doing XXXK -> XXXK */
+ if (p->nhack == 2) {
+ /* Ideally we would create a 4D PCSK -> PCSK gamut mapping */
+ /* to smoothly and accurately cope with the changing source */
+ /* and destination gamuts acording to their degree of "K onlyness". */
+ /* In practice we're going to simply interpolated between */
+ /* two extremes: unrestricted gamut and K only black gamut. */
+ double map0[3], map1[3];
+
+ /* Compute blend of normal gamut map and Konly to Konly gamut map */
+ {
+ p->map->domap(p->map, map0, pcsv);
+ p->Kmap->domap(p->Kmap, map1, pcsv);
+ icmBlend3(pcsvm, map0, map1, konlyness);
+ }
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("PCS after map0 %f %f %f map1 %f %f %f\n", map0[0], map0[1], map0[2], map1[0], map1[1], map1[2]);
+#endif
+
+ /* Normal gamut mapping */
+ } else {
+ {
+ p->map->domap(p->map, pcsvm, pcsv);
+ }
+ }
+
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("PCS after map %f %f %f\n",pcsvm[0], pcsvm[1], pcsvm[2]); fflush(stdout);
+#endif
+ } else {
+ pcsvm[0] = pcsv[0];
+ pcsvm[1] = pcsv[1];
+ pcsvm[2] = pcsv[2];
+ }
+
+ /* Gamut mapped PCS value is now in pcsvm[] */
+
+ /* Abstract profile transform, PCS -> PCS */
+ /* pcsor -> abstract -> pcsor conversion */
+ /* We're applying any abstract profile after gamut mapping, */
+ /* on the assumption is is primarily being used to "correct" the */
+ /* output device. Ideally the gamut mapping should take the change */
+ /* the abstract profile has on the output device into account, but */
+ /* currently we're not doing this.. */
+ if (wptrig == 0 && p->abs_luo != NULL) {
+ /* Abstract profile is either absolute or relative. */
+ /* We need to convert the current PCS into something compatible. */
+ /* This is more ugly than it really should be, so we're ignoring it. */
+ /* We should really run the source through the abstract profile before */
+ /* creating the gamut mapping, to be able to use abstract with gamut */
+ /* mapping properly. */
+ p->abs_luo->lookup(p->abs_luo, pcsvm, pcsvm);
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("PCS after abstract %f %f %f\n",pcsvm[0], pcsvm[1], pcsvm[2]); fflush(stdout);
+#endif
+ }
+
+ /* If we're using the existing B2A inking to determine K, */
+ /* lookup the output profiles K value for this PCS */
+ if (p->mode >= 2 && p->out.inking == 7) {
+ double tdevv[MAX_CHAN];
+
+//printf("~1 dealing with out.inking = %d\n",p->out.inking);
+ if (p->out.alg != icmLutType || p->out.c->header->colorSpace != icSigCmykData)
+ error ("Attempting to use non-CMYK output profile to determine K inking");
+
+ /* Lookup PCS in B2A of output profile to get target K value */
+//printf("~1 looking up pcs %f %f %f in B2A\n", pcsvm[0], pcsvm[1], pcsvm[2]);
+ p->out.b2aluo->lookup(p->out.b2aluo, tdevv, pcsvm);
+//printf("~1 resulting dev %f %f %f %f\n", tdevv[0], tdevv[1], tdevv[2], tdevv[3]);
+
+ if (p->out.locus) {
+ double tpcsv[MAX_CHAN];
+ icxLuLut *lu = (icxLuLut *)p->out.luo; /* Safe to coerce */
+
+ /* Convert PCS to PCS' ready for locus lookup */
+ lu->in_abs(lu, tpcsv, pcsvm);
+ lu->matrix(lu, tpcsv, tpcsv);
+ lu->input(lu, tpcsv, tpcsv);
+ lu->clut_locus(lu, locus, tpcsv, tdevv); /* Compute locus values */
+ } else {
+ for (i = 0; i < p->out.chan; i++) /* Target is K value */
+ locus[i] = tdevv[i];
+ }
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("Got possible K %s of %f %f %f %f\n",p->out.locus ? "locus" : "value", locus[0],locus[1],locus[2],locus[3]);
+#endif
+ }
+
+ /* Do PCS -> DevOut' */
+ if (p->nhack == 3 /* All to K only */
+ || ntrig /* Neutral or K only to K only hack has triggered */
+ || cmytrig) { /* 100% CMY rough hack has triggered */
+
+ if (p->nhack == 3 || ntrig) { /* Neutral to K only hack has triggered */
+ co pp;
+ pp.p[0] = pcsvm[0]; /* Input L value */
+ p->pcs2k->interp(p->pcs2k, &pp); /* L -> K' */
+ if (pp.v[0] < 0.0) /* rspl might have extrapolated */
+ pp.v[0] = 0.0;
+ else if (pp.v[0] > 1.0)
+ pp.v[0] = 1.0;
+ out[0] = out[1] = out[2] = 0.0; /* We know output is CMYK' */
+ out[3] = pp.v[0];
+
+#ifndef DEBUG
+ if (p->verb)
+#endif
+ if (ntrig) {
+ printf("Neutral hack mapped %s to 0 0 0 %f\n", icmPdv(p->in.chan,win), out[3]);
+ fflush(stdout);
+ }
+ } else if (cmytrig) { /* 100% CMY rough hack has triggered */
+ if (cmytrig & 1) {
+ out[0] = 1.0;
+ out[1] = out[2] = out[3] = 0.0;
+ }
+ if (cmytrig & 2) {
+ out[1] = 1.0;
+ out[0] = out[2] = out[3] = 0.0;
+ }
+ if (cmytrig & 4) {
+ out[2] = 1.0;
+ out[0] = out[1] = out[3] = 0.0;
+ }
+
+#ifndef DEBUG
+ if (p->verb)
+#endif
+ if (cmytrig != 0) {
+ if (p->in.chan == 4)
+ printf("CMY hack mapped %s to %s\n",icmPdv(p->in.chan, win), icmPdv(p->out.chan, out));
+ fflush(stdout);
+ }
+ }
+ } else { /* Neutral to K hack has NOT triggered */
+ switch(p->out.alg) {
+ case icmMonoBwdType: {
+ icxLuMono *lu = (icxLuMono *)p->out.luo; /* Safe to coerce */
+
+ rv |= lu->bwd_abs(lu, pcsvm, pcsvm);
+ rv |= lu->bwd_map(lu, out, pcsvm);
+ if (p->out.nocurve) { /* No explicit curve, so do implicit here */
+ rv |= lu->bwd_curve(lu, out, out);
+ }
+ break;
+ }
+ case icmMatrixBwdType: {
+ icxLuMatrix *lu = (icxLuMatrix *)p->out.luo; /* Safe to coerce */
+
+ rv |= lu->bwd_abs(lu, pcsvm, pcsvm);
+ rv |= lu->bwd_matrix(lu, out, pcsvm);
+ if (p->out.nocurve) { /* No explicit curve, so do implicit here */
+ rv |= lu->bwd_curve(lu, out, out);
+ }
+ break;
+ }
+ case icmLutType: {
+ icxLuLut *lu = (icxLuLut *)p->out.luo; /* Safe to coerce */
+
+ if (p->mode < 2) { /* Using B2A table */
+ rv |= lu->in_abs(lu, pcsvm, pcsvm);
+ rv |= lu->matrix(lu, pcsvm, pcsvm);
+ rv |= lu->input(lu, pcsvm, pcsvm);
+ rv |= lu->clut(lu, out, pcsvm);
+ if (p->out.nocurve) { /* No explicit curve, so do implicit here */
+ rv |= lu->output(lu, out, out);
+ }
+
+ } else { /* Use inverse A2B table */
+ int i;
+#ifdef USE_MERGE_CLUT_OPT
+ /* Because we have used the ICX_MERGE_CLUT flag, we don't need */
+ /* to call inv_out_abs() and inv_output() */
+#else
+ rv |= lu->inv_out_abs(lu, pcsvm, pcsvm);
+ rv |= lu->inv_output(lu, pcsvm, pcsvm);
+#endif
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("Calling inv_clut with K aux targets %f %f %f %f and pcsvm %f %f %f %f\n",
+ locus[0],locus[1],locus[2],locus[3],pcsvm[0],pcsvm[1],pcsvm[2],pcsvm[3]);
+#endif
+
+ /* locus[] contains possible K target or locus value, */
+ /* so copy it to out[] so that inv_clut will use it. */
+ for (i = 0; i < p->out.chan; i++)
+ out[i] = locus[i];
+
+ rv |= lu->inv_clut(lu, out, pcsvm);
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("Got result %f %f %f %f\n", out[0],out[1],out[2],out[3]);
+#endif
+
+
+ if (p->out.nocurve) { /* No explicit curve, so do implicit here */
+ rv |= lu->inv_input(lu, out, out);
+ }
+ }
+ break;
+ }
+
+ default:
+ error("Unexpected algorithm type %d in devop of devip_devop()",p->out.alg);
+ }
+ if (rv >= 2)
+ error("icc lookup failed: %d, %s",p->in.c->errc,p->in.c->err);
+ }
+
+ if (p->out.lcurve) /* Apply Y to L* */
+ y2l_curve(out, out, p->out.lcurve == 2);
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("DevIn'->DevOut' ret %f %f %f %f\n\n",out[0], out[1], out[2], out[3]); fflush(stdout);
+#endif
+
+
+ if (p->verb) { /* Output percent intervals */
+ int pc;
+ p->count++;
+ pc = (int)(p->count * 100.0/p->total + 0.5);
+ if (pc != p->last) {
+ printf("%c%2d%%",cr_char,pc); fflush(stdout);
+ p->last = pc;
+ }
+ }
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Output table, DevOut' -> DevOut */
+void devop_devo(void *cntx, double *out, double *in) {
+ int rv = 0;
+ clink *p = (clink *)cntx;
+ int i;
+
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("DevOut'->DevOut got %f %f %f %f\n",in[0], in[1], in[2], in[4]); fflush(stdout);
+#endif
+
+ for (i = 0; i < p->out.chan; i++)
+ out[i] = in[i];
+
+ if (p->out.lcurve) /* Apply L* to Y */
+ l2y_curve(out, out, p->out.lcurve == 2);
+
+ if (p->out.nocurve == 0) { /* Using per channel curves */
+
+ switch(p->out.alg) {
+ case icmMonoBwdType: {
+ icxLuMono *lu = (icxLuMono *)p->out.luo; /* Safe to coerce */
+ rv |= lu->bwd_curve(lu, out, out);
+ break;
+ }
+ case icmMatrixBwdType: {
+ icxLuMatrix *lu = (icxLuMatrix *)p->out.luo; /* Safe to coerce */
+ rv |= lu->bwd_curve(lu, out, out);
+ break;
+ }
+ case icmLutType: {
+ if (p->mode < 2) { /* Using B2A table */
+ icxLuLut *lu = (icxLuLut *)p->out.luo; /* Safe to coerce */
+ rv |= lu->output(lu, out, out);
+ /* Since not PCS, out_abs is never used */
+ break;
+ } else { /* Use inverse A2B table */
+ icxLuLut *lu = (icxLuLut *)p->out.luo; /* Safe to coerce */
+ rv |= lu->inv_input(lu, out, out);
+ /* Since not PCS, inv_matrix and inv_in_abs is never used */
+ break;
+ }
+ }
+ default:
+ error("Unexpected algorithm type in devop_devo()");
+ }
+ if (rv >= 2)
+ error("icc lookup failed: %d, %s",p->in.c->errc,p->in.c->err);
+ }
+#ifdef DEBUG
+#ifdef DEBUGC
+ DEBUGC
+#endif
+ printf("DevOut'->DevOut ret %f %f %f %f\n",out[0], out[1], out[2], out[3]); fflush(stdout);
+#endif
+#ifdef DEBUGC
+ tt = 0;
+#endif
+}
+
+/* ------------------------------------------- */
+/* Fixup L -> K only lookup table white and black values, */
+/* to compensate for inexact rspl fitting */
+
+/* Context for fixup */
+typedef struct {
+ double kmax;
+ double kmin;
+} pcs2k_ctx;
+
+/* Function to pass to rspl to re-set output values, */
+/* to make them relative to the white and black points */
+static void
+fix_pcs2k_white(
+ void *pp, /* relativectx structure */
+ double *out, /* output value */
+ double *in /* input value */
+) {
+ double f;
+ pcs2k_ctx *p = (pcs2k_ctx *)pp;
+
+ /* Scale so that kmin->hmax becomes 0 to 1 */
+ f = (out[0] - p->kmin)/(p->kmax - p->kmin);
+
+ out[0] = f;
+}
+
+/* ------------------------------------------- */
+/* powell() callback to set XYZ scaling factor */
+
+static double xyzoptfunc(void *cntx, double *v) {
+ clink *p = (clink *)cntx;
+ double swxyz[3], jab[3], dev[MAX_CHAN];
+ double rv;
+ int rc = 0;
+
+ rv = 2.0 - v[0]; /* Make Y as large as possible */
+
+ /* If we wanted to use this function to maximise the brightness */
+ /* we would not limit the scale to 1.0 */
+ if (v[0] > 1.0) {
+ rv += 1000.0;
+ return rv;
+ }
+ if (v[0] < 0.0) {
+ rv += 100.0;
+ return rv;
+ }
+ swxyz[0] = v[0] * p->swxyz[0];
+ swxyz[1] = v[0] * p->swxyz[1];
+ swxyz[2] = v[0] * p->swxyz[2];
+
+//printf("~1 scaled white XYZ = %f %f %f\n", swxyz[0], swxyz[1], swxyz[2]);
+
+ if (p->pcsor == icxSigJabData) {
+ /* We're being bad in delving inside the xluo, but we'll fix it latter */
+ p->out.luo->cam->XYZ_to_cam(p->out.luo->cam, jab, swxyz);
+ } else
+ error("Internal :- not setup to handle Y scaling and non-Jab PCS");
+
+//printf("~1 scaled white Jab = %f %f %f\n", jab[0], jab[1], jab[2]);
+
+ /* Run the target PCS backwards through the output space to see if it clips */
+ switch(p->out.alg) {
+ case icmMonoBwdType: {
+ icxLuMono *lu = (icxLuMono *)p->out.luo; /* Safe to coerce */
+
+ rc = lu->bwd_lookup(p->out.luo, dev, jab);
+ break;
+ }
+ case icmMatrixBwdType: {
+ icxLuMatrix *lu = (icxLuMatrix *)p->out.luo; /* Safe to coerce */
+
+ rc = lu->bwd_lookup(p->out.luo, dev, jab);
+ break;
+ }
+ case icmLutType: {
+ icxLuLut *lu = (icxLuLut *)p->out.luo; /* Safe to coerce */
+
+ if (p->mode < 2) /* Using B2A table */
+ rc = lu->lookup(p->out.luo, dev, jab);
+ else /* Use inverse A2B table */
+ rc = lu->inv_lookup(p->out.luo, dev, jab);
+ break;
+ }
+ default:
+ error("Unexpected algorithm type %d in devop of devip_devop()",p->out.alg);
+ }
+//printf("~1 device = %f %f %f, rc = %d\n", dev[0], dev[1], dev[2], rc);
+ if (rc != 0)
+ rv += 500.0;
+
+//printf("~1 xyzoptfunc rv %f from xyzscale %f\n\n",rv,v[0]);
+ return rv;
+}
+
+/* ------------------------------------------- */
+
+int
+main(int argc, char *argv[]) {
+ int fa, nfa, mfa; /* argument we're looking at */
+ char in_name[MAXNAMEL+1];
+ char sgam_name[MAXNAMEL+1] = "\000"; /* Source gamut name */
+ char abs_name[MAXNAMEL+1] = "\000"; /* Abstract profile name */
+ char out_name[MAXNAMEL+1];
+ char link_name[MAXNAMEL+1];
+ int verify = 0; /* Do verify pass */
+ int outinkset = 0; /* The user specfied an output inking */
+ int intentset = 0; /* The user specified an intent */
+ int vcset = 0; /* Viewing conditions were set by user */
+ int modeset = 0; /* The gamut mapping mode was set by the user */
+ int rv = 0;
+ icxViewCond ivc, ovc; /* Viewing Condition Overrides for in and out profiles */
+ int ivc_e = -1, ovc_e = -1; /* Enumerated viewing condition */
+ clink li; /* Linking information structure */
+ int isJab = 0; /* (Derived from li.mode & li.gmi) NZ if Jab link space */
+ int in_curve_res = 0; /* Input profile A2B input curve resolution (if known) */
+ int out_curve_res = 0; /* Output profile B2A output curve resolution (if known) */
+ profxinf xpi; /* Extra profile information */
+ int i;
+
+ error_program = argv[0];
+ check_if_not_interactive();
+ memset((void *)&xpi, 0, sizeof(profxinf)); /* Init extra profile info to defaults */
+ memset((void *)&li, 0, sizeof(clink));
+
+ /* Set defaults */
+ li.verb = 0;
+ li.count = 0;
+ li.last = -1;
+ li.mode = 0; /* Default simple link mode */
+ li.quality = 1; /* Medium quality */
+ li.clutres = 0; /* No resolution override */
+ li.nhack = 0;
+ li.cmyhack = 0; /* Mask for 100% purity through mapping of CMY */
+ li.pcs2k = NULL;
+ li.wphack = 0;
+ li.wphacked = 0;
+ li.abs_luo = NULL; /* No abstract */
+ li.xyzscale = 1.0; /* No XYZ scaling */
+ li.hwp[0] = li.hwp[1] = li.hwp[2] = 0.0;
+ li.map = NULL;
+ li.Kmap = NULL;
+ li.in.intent = icmDefaultIntent; /* Default */
+ li.in.ink.tlimit = -1.0; /* Default no total limit */
+ li.in.ink.klimit = -1.0; /* Default no black limit */
+ li.in.inking = 4; /* Inking algorithm default = ramp */
+ li.in.locus = 0; /* Default K value target */
+ li.in.nocurve = 0; /* Preserve device linearisation curve */
+ li.in.lcurve = 0; /* Don't apply a Y to L* curve after device curve */
+ li.out.intent = icmDefaultIntent; /* Default */
+ li.out.ink.tlimit = -1.0; /* Default no total limit */
+ li.out.ink.klimit = -1.0; /* Default no black limit */
+ li.out.ink.KonlyLmin = 0; /* Use normal black Lmin for locus */
+ li.out.ink.c.Ksmth = ICXINKDEFSMTH; /* default curve smoothing */
+ li.out.ink.c.Kskew = ICXINKDEFSKEW; /* default curve skew */
+ li.out.ink.x.Ksmth = ICXINKDEFSMTH;
+ li.out.ink.x.Kskew = ICXINKDEFSKEW;
+ li.out.inking = 4; /* Default ramp K */
+ li.out.locus = 0; /* Default K value target */
+ li.out.nocurve = 0; /* Preserve device linearisation curve */
+ li.out.lcurve = 0; /* Don't apply an L* to Y curve before device curve */
+ li.out.b2aluo = NULL; /* B2A lookup for inking == 7 */
+
+ xicc_enum_gmapintent(&li.gmi, icxDefaultGMIntent, NULL); /* Set default overall intent */
+
+ /* Init VC overrides so that we know when the've been set */
+ ivc.Ev = -1;
+ ivc.Wxyz[0] = -1.0; ivc.Wxyz[1] = -1.0; ivc.Wxyz[2] = -1.0;
+ ivc.La = -1.0;
+ ivc.Yb = -1.0;
+ ivc.Lv = -1.0;
+ ivc.Yf = -1.0;
+ ivc.Fxyz[0] = -1.0; ivc.Fxyz[1] = -1.0; ivc.Fxyz[2] = -1.0;
+
+ ovc.Ev = -1;
+ ovc.Wxyz[0] = -1.0; ovc.Wxyz[1] = -1.0; ovc.Wxyz[2] = -1.0;
+ ovc.La = -1.0;
+ ovc.Yb = -1.0;
+ ovc.Lv = -1.0;
+ ovc.Yf = -1.0;
+ ovc.Fxyz[0] = -1.0; ovc.Fxyz[1] = -1.0; ovc.Fxyz[2] = -1.0;
+
+ if (argc < 4)
+ usage("Too few arguments, got %d expect at least 3",argc-1);
+
+ /* Process the arguments */
+ mfa = 3; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Requested usage");
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v') {
+ li.verb = 1;
+ }
+
+ /* Manufacturer description string */
+ else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to manufacturer description flag -A");
+ xpi.deviceMfgDesc = na;
+ }
+
+ /* Model description string */
+ else if (argv[fa][1] == 'M') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to model description flag -M");
+ xpi.modelDesc = na;
+ }
+
+ /* Profile Description */
+ else if (argv[fa][1] == 'D') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to profile description flag -D");
+ xpi.profDesc = na;
+ }
+
+ /* Copyright string */
+ else if (argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to copyright flag -C");
+ xpi.copyright = na;
+ }
+
+ /* Verify rather than link */
+ else if (argv[fa][1] == 'V')
+ verify = 1;
+
+ /* Disable profile per channel curve use in device link output */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ li.in.nocurve = 1;
+ li.out.nocurve = 1;
+ }
+
+ /* Hack to force input neutrals to K only output */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+
+ if (argv[fa][1] == 'f') {
+ if (na != NULL) { /* XXXK -> XXXK hack */
+ int j;
+ fa = nfa;
+ for (j = 0; ; j++) {
+ if (na[j] == '\000')
+ break;
+ if (na[j] == 'k' || na[j] == 'K')
+ li.nhack = 2;
+ else if (na[j] == 'c' || na[j] == 'C')
+ li.cmyhack |= 0x1;
+ else if (na[j] == 'm' || na[j] == 'M')
+ li.cmyhack |= 0x2;
+ else if (na[j] == 'y' || na[j] == 'Y')
+ li.cmyhack |= 0x4;
+ else
+ usage("Unexpected argument '%c' to -f flag",na[j]);
+ }
+
+ } else { /* Neutral -> 000K hack */
+ li.nhack = 1;
+ li.in.nocurve = 1; /* Disable input curve to preserve input equality */
+ }
+ } else {
+ li.nhack = 3; /* All -> 000K Hack */
+ }
+ }
+
+ /* Quality */
+ else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') {
+ fa = nfa;
+ if (na == NULL) usage("Quality flag (-q) needs an argument");
+ switch (na[0]) {
+ case 'f': /* fast */
+ case 'l':
+ case 'L':
+ li.quality = 0;
+ break;
+ case 'm': /* medium */
+ case 'M':
+ li.quality = 1;
+ break;
+ case 's': /* slow */
+ case 'h':
+ case 'H':
+ li.quality = 2;
+ break;
+ case 'u': /* ultra slow */
+ case 'U':
+ li.quality = 3;
+ break;
+ default:
+ usage("Unrecognised quality flag (-q) argument '%c'",na[0]);
+// usage("Unrecognised speed flag (-q) argument '%c'",na[0]);
+ }
+ }
+
+ /* CLUT resolution override */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ int rr;
+ fa = nfa;
+ if (na == NULL) usage("Resolution flag (-r) needs an argument");
+ rr = atoi(na);
+ if (rr < 1 || rr > 255) usage("Resolution flag (-r) argument out of range (%d)",rr);
+ li.clutres = rr;
+ }
+
+ /* Abstract profile */
+ else if (argv[fa][1] == 'p') {
+ if (na == NULL) usage("Expected abstract profile filename after -a");
+ fa = nfa;
+ strncpy(abs_name,na,MAXNAMEL); abs_name[MAXNAMEL] = '\000';
+ }
+
+ /* Simple mode */
+ else if (argv[fa][1] == 's') {
+ li.mode = 0;
+ modeset = 1;
+ }
+
+ /* Maping mode */
+ else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') {
+ li.mode = 1;
+ if (argv[fa][1] == 'G') {
+ li.mode = 2;
+ }
+
+ if (na != NULL) { /* Found an optional source gamut */
+ fa = nfa;
+ strncpy(sgam_name,na,MAXNAMEL); sgam_name[MAXNAMEL] = '\000';
+ }
+ modeset = 1;
+ }
+
+ /* White point hack */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ li.wphack = 1;
+ if (na != NULL) { // To a particular white point
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf ",&li.hwp[0], &li.hwp[1], &li.hwp[2]) == 3) {
+ li.wphack = 2;
+ } else
+ usage("Couldn't parse hack white point (-w) value '%s'",na);
+ }
+ }
+ /* Input profile Intent or Mapping mode intent */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage("Input intent flag (-i) needs an argument");
+ /* Record it for simple mode */
+ switch (na[0]) {
+ case 'p':
+ case 'P':
+ li.in.intent = icPerceptual;
+ break;
+ case 'r':
+ case 'R':
+ li.in.intent = icRelativeColorimetric;
+ break;
+ case 's':
+ case 'S':
+ li.in.intent = icSaturation;
+ break;
+ case 'a':
+ case 'A':
+ li.in.intent = icAbsoluteColorimetric;
+ break;
+ default:
+ li.in.intent = icMaxEnumIntent; /* Detect error later */
+ }
+ /* Record it for gamut mapping mode */
+ if (xicc_enum_gmapintent(&li.gmi, icxNoGMIntent, na) == -999)
+ usage("Input intent (-i) argument '%s' isn't recognised",na);
+ intentset = 1;
+ }
+
+ /* Output profile Intent */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage("Output intent flag (-o) needs an argument");
+ switch (na[0]) {
+ case 'p':
+ case 'P':
+ li.out.intent = icPerceptual;
+ break;
+ case 'r':
+ case 'R':
+ li.out.intent = icRelativeColorimetric;
+ break;
+ case 's':
+ case 'S':
+ li.out.intent = icSaturation;
+ break;
+ case 'a':
+ case 'A':
+ li.out.intent = icAbsoluteColorimetric;
+ break;
+ default:
+ usage("Output intent (-o) argument '%s' not recognised",na);
+ }
+ }
+
+ /* Viewing conditions */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C'
+ || argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ icxViewCond *vc;
+
+ if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ vc = &ivc;
+ } else {
+ vc = &ovc;
+ }
+
+ fa = nfa;
+ if (na == NULL) usage("Viewing conditions flag (-[cd]) needs an argument");
+#ifdef NEVER
+ if (na[0] >= '0' && na[0] <= '9') {
+ if (vc == &ivc)
+ ivc_e = atoi(na);
+ else
+ ovc_e = atoi(na);
+ } else
+#endif
+ if (na[1] != ':') {
+ /* Enumerated condition index */
+ if (vc == &ivc) {
+ if ((ivc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
+ usage("Unrecognised viewing condition enumeration '%s'",na);
+ } else {
+ if ((ovc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
+ usage("Unrecognised viewing condition enumeration '%s'",na);
+ }
+ } else if (na[0] == 's' || na[0] == 'S') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-[cd]s) missing ':'");
+ if (na[2] == 'n' || na[2] == 'N') {
+ vc->Ev = vc_none; /* Automatic */
+ } else if (na[2] == 'a' || na[2] == 'A') {
+ vc->Ev = vc_average;
+ } else if (na[2] == 'm' || na[2] == 'M') {
+ vc->Ev = vc_dim;
+ } else if (na[2] == 'd' || na[2] == 'D') {
+ vc->Ev = vc_dark;
+ } else if (na[2] == 'c' || na[2] == 'C') {
+ vc->Ev = vc_cut_sheet;
+ } else
+ usage("Viewing condition (-[cd]) unrecognised surround '%c'",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) {
+ vc->Wxyz[0] = x; vc->Wxyz[1] = y; vc->Wxyz[2] = z;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc->Wxyz[0] = x; vc->Wxyz[1] = y;
+ } else
+ usage("Viewing condition (-[cd]w) unrecognised white point '%s'",na+1);
+ } else if (na[0] == 'a' || na[0] == 'A') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-[cd]a) missing ':'");
+ vc->La = atof(na+2);
+ } else if (na[0] == 'b' || na[0] == 'B') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-[cd]b) missing ':'");
+ vc->Yb = atof(na+2)/100.0;
+ } else if (na[0] == 'l' || na[0] == 'L') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-[cd]l) missing ':'");
+ vc->Lv = atof(na+2);
+ } else if (na[0] == 'f' || na[0] == 'F') {
+ 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;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc->Fxyz[0] = x; vc->Fxyz[1] = y;
+ } else if (sscanf(na+1,":%lf",&x) == 1) {
+ vc->Yf = x/100.0;
+ } else
+ usage("Viewing condition (-[cd]f) unrecognised flare '%s'",na+1);
+ } else
+ usage("Viewing condition (-[cd]) unrecognised sub flag '%c'",na[0]);
+ vcset = 1; /* Viewing conditions were set by user */
+ }
+
+ /* Inking rule */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ fa = nfa;
+ if (na == NULL) usage("Inking rule flag (-k) needs an argument");
+ if (argv[fa][1] == 'k')
+ li.out.locus = 0; /* Use K value target */
+ else
+ li.out.locus = 1; /* Use K locus target */
+ switch (na[0]) {
+ case 't':
+ case 'T':
+ li.out.inking = 0; /* Use input K value for output */
+ break;
+ case 'e':
+ case 'E':
+ li.out.inking = 7; /* Use output K value as guide */
+ break;
+ case 'z':
+ case 'Z':
+ li.out.inking = 1; /* Use minimum k */
+ break;
+ case 'h':
+ case 'H':
+ li.out.inking = 2; /* Use half k */
+ break;
+ case 'x':
+ case 'X':
+ li.out.inking = 3; /* Use maximum k */
+ break;
+ case 'r':
+ case 'R':
+ li.out.inking = 4; /* Use ramp k */
+ break;
+ case 'p':
+ case 'P':
+ case 'q':
+ case 'Q':
+ li.out.inking = 5; /* Use curve parameter */
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kp) expects more parameters");
+ li.out.ink.c.Kstle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kp) expects more parameters");
+ li.out.ink.c.Kstpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kp) expects more parameters");
+ li.out.ink.c.Kenpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kp) expects more parameters");
+ li.out.ink.c.Kenle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kp) expects more parameters");
+ li.out.ink.c.Kshap = atof(argv[fa]);
+
+ if (na[0] == 'q' || na[0] == 'Q') {
+ li.out.inking = 6; /* Use transfer to dual curve parameter */
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kq) expects more parameters");
+ li.out.ink.x.Kstle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kq) expects more parameters");
+ li.out.ink.x.Kstpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kq) expects more parameters");
+ li.out.ink.x.Kenpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kq) expects more parameters");
+ li.out.ink.x.Kenle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kq) expects more parameters");
+ li.out.ink.x.Kshap = atof(argv[fa]);
+
+ }
+ break;
+ default:
+ usage("Inking rule (-k) unknown sub flag '%c'",na[0]);
+ }
+ outinkset = 1; /* The user set an inking */
+ }
+ /* Input ink limits */
+ else if (argv[fa][1] == 't') {
+ int tlimit;
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -t");
+ tlimit = atoi(na);
+ if (tlimit >= 0)
+ li.in.ink.tlimit = tlimit/100.0;
+ else
+ li.in.ink.tlimit = -1.0;
+ }
+ else if (argv[fa][1] == 'T') {
+ int klimit;
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -T");
+ klimit = atoi(na);
+ if (klimit >= 0)
+ li.in.ink.klimit = klimit/100.0;
+ else
+ li.in.ink.klimit = -1.0;
+ }
+ /* Output ink limits */
+ else if (argv[fa][1] == 'l') {
+ int tlimit;
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -l");
+ tlimit = atoi(na);
+ if (tlimit >= 0)
+ li.out.ink.tlimit = tlimit/100.0;
+ else
+ li.out.ink.tlimit = -1.0;
+ if (li.mode < 2) /* Set minimum link mode */
+ li.mode = 2;
+ }
+ else if (argv[fa][1] == 'L') {
+ int klimit;
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -L");
+ klimit = atoi(na);
+ if (klimit >= 0)
+ li.out.ink.klimit = klimit/100.0;
+ else
+ li.out.ink.klimit = -1.0;
+ if (li.mode < 2) /* Set minimum link mode */
+ li.mode = 2;
+ }
+
+ /* Gammut mapping diagnostic plots */
+ else if (argv[fa][1] == 'P')
+ li.gamdiag = 1;
+
+ else
+ usage("Unknown flag '%c'",argv[fa][1]);
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing input profile");
+ strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing output profile");
+ strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing result profile");
+ strncpy(link_name,argv[fa++],MAXNAMEL); link_name[MAXNAMEL] = '\000';
+
+ if (xpi.profDesc == NULL)
+ xpi.profDesc = link_name; /* Default description */
+
+ if (li.verb)
+ printf("Got options\n");
+
+ /* - - - - - - - - - - - - - - - - - - - */
+#ifndef ENKHACK /* Enable K hack code */
+ warning("!!!!!! linkl/collink.c ENKHACK not enabled !!!!!!");
+#endif
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* Sanity checking/defaulting of options */
+
+ /* Deal with options that need link mode -g */
+ if (li.mode < 1
+ && (li.in.intent == icMaxEnumIntent /* User set a smart linking intent */
+ || vcset /* Viewing conditions were set by user */
+ || li.wphack)) {
+ if (modeset) {
+ if (li.in.intent == icMaxEnumIntent)
+ warning("Complex intent can't work with -s linking mode");
+ else if (vcset)
+ warning("Viewing conditions are ignored with -s linking mode");
+ else if (li.wphack)
+ warning("White point hack is ignored with -s linking mode");
+ } else {
+ if (li.verb) {
+ if (li.in.intent == icMaxEnumIntent)
+ printf("Setting -g to enable Gamut Mapping mode intent\n");
+ else if (vcset)
+ printf("Setting -g to enable viewing conditions\n");
+ else if (li.wphack)
+ printf("Setting -g to enable white point hack\n");
+ }
+ li.mode = 1;
+ }
+ }
+
+ /* Deal with options that need link mode -G */
+ if (li.mode < 2
+ && (outinkset /* The user set a K inking rule */
+ || li.out.ink.tlimit >= 0.0 /* The user set an output total limit */
+ || li.out.ink.klimit >= 0.0)) { /* The user set an output black limit */
+ if (modeset) {
+ if (outinkset)
+ warning("Black inking can't work with -s or -g linking mode");
+ else if (li.out.ink.tlimit >= 0.0 || li.out.ink.klimit >= 0.0)
+ warning("Ink limiting can't work with -s linking mode");
+ } else {
+ if (li.verb) {
+ if (outinkset)
+ printf("Setting -G to enable black inking\n");
+ else if (li.out.ink.tlimit >= 0.0 || li.out.ink.klimit >= 0.0)
+ printf("Setting -G to enable ink limiting\n");
+ }
+ li.mode = 2;
+ }
+ }
+
+ /* Deal with options that complement -f -F */
+ if (li.nhack || li.cmyhack) {
+
+ /* Ideally we need to set K inking and map to K only black point, which require -G mode */
+ if (li.mode < 2) {
+ if (li.nhack == 1) { /* All neutrals to K only */
+ if (modeset) {
+ warning("-f will give best result with -G mode");
+ } else {
+ if (li.verb)
+ printf("Setting -G mode to complement -f option\n");
+ li.mode = 2;
+ }
+ } else if (li.nhack == 2) { /* K only in to K only out */
+ if (modeset) {
+ warning("For better results use -G mode with -fk option");
+ } else {
+ if (li.verb)
+ printf("Setting -G mode to complement -fk option\n");
+ li.mode = 2;
+ }
+ } else if (li.nhack == 3) { /* All to K only out */
+ if (modeset) {
+ warning("For better results use -G mode with -F option");
+ } else {
+ if (li.verb)
+ printf("Setting -G mode to complement -F option\n");
+ li.mode = 2;
+ }
+ }
+ if (li.cmyhack != 0) { /* Map pure 100% CMY to pure CMY */
+ if (modeset) {
+ warning("For better results use -G mode with -fcmy options");
+ } else {
+ if (li.verb)
+ printf("Setting -G mode to complement -fcmy options\n");
+ li.mode = 2;
+ }
+ }
+ }
+
+ /* Ideally we should use an appropriate K inking */
+ if (li.mode >= 2) { /* Gammut mapping mode */
+ if (li.nhack == 1 && li.out.inking != 3) { /* All neutrals to K only */
+ if (outinkset) {
+ warning("For better results use -kx with -f option");
+ } else {
+ if (li.verb)
+ printf("Setting -kx to complement -f option\n");
+ li.out.inking = 3; /* Use maximum K */
+ }
+ } else if (li.nhack == 2 && li.out.inking != 0) { /* K only in to K only out */
+ if (outinkset) {
+ warning("For better results use -kt with -fk option");
+ } else {
+ if (li.verb)
+ printf("Setting -kt to complement -fk option\n");
+ li.out.inking = 0; /* Use input K value for output */
+ }
+ } else if (li.nhack == 3 && li.out.inking != 3) { /* All colors to K only */
+ if (modeset) {
+ warning("For better results use -kx with -F option");
+ } else {
+ if (li.verb)
+ printf("Setting -kx to complement -f option\n");
+ li.out.inking = 3; /* Use maximum K */
+ }
+ }
+ }
+
+ /* Ideally we should use an appropriate gamut mapping */
+ if (li.mode >= 1) { /* Gammut mapping mode */
+
+ if (li.gmi.usemap == 0 || li.gmi.greymf < 1.0 /* Not mapping black point */
+ || li.gmi.glumbcpf < 1.0 || li.gmi.glumbexf < 1.0) {
+ if (li.nhack == 1) { /* All neutrals to K only */
+ if (intentset) {
+ warning("For better results use an intent that maps black point with -f option");
+ } else {
+ if (li.verb)
+ printf("Setting -ip intent to complement -f option\n");
+ if (xicc_enum_gmapintent(&li.gmi, icxNoGMIntent, "p") == -999)
+ usage("Internal, intent 'p' isn't recognised");
+ li.dst_kbp = 1; /* Map to K only black point */
+ li.out.ink.KonlyLmin = 1; /* Use K only black Lmin for locus */
+ }
+ } else if (li.nhack == 3) { /* All to K only out */
+ if (intentset) {
+ warning("For better results use an intent that maps black point with -F option");
+ } else {
+ if (li.verb)
+ printf("Setting -ip intent to complement -F option\n");
+ if (xicc_enum_gmapintent(&li.gmi, icxNoGMIntent, "p") == -999)
+ usage("Internal, intent 'p' isn't recognised");
+ li.dst_kbp = 1; /* Map to K only black point */
+ li.out.ink.KonlyLmin = 1; /* Use K only black Lmin for locus */
+ }
+ }
+
+ /* Got an appropriate intent, so set mapping to K only black point */
+ } else if (li.nhack == 1 || li.nhack == 3) {
+ li.dst_kbp = 1; /* Map to K only black point */
+ li.out.ink.KonlyLmin = 1; /* Use K only black Lmin for locus */
+ }
+ if (li.cmyhack != 0) { /* Map pure 100% CMY to pure CMY */
+ if (intentset) {
+ if (strcmp(li.gmi.as, "s") != 0)
+ warning("For better results use -is with -fcmy options");
+ } else {
+ if (li.verb)
+ printf("Setting -is intent to complement -fcmy options\n");
+ if (xicc_enum_gmapintent(&li.gmi, icxNoGMIntent, "s") == -999)
+ usage("Internal, intent 's' isn't recognised");
+ li.dst_cmymap = li.cmyhack;
+ }
+ }
+ }
+ }
+
+ if (li.mode == 0) {
+ if (li.in.intent == icMaxEnumIntent)
+ usage("Input intent (-i) argument isn't recognised for simple mapping mode");
+ }
+
+ if (li.wphack && (li.gmi.usecas & 0x100) != 0)
+ usage("Can't use 'white point hack' and Luminence scaling intent together");
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* Open up the input device profile for reading, and read header etc. */
+ if ((li.in.c = read_embedded_icc(in_name)) == NULL)
+ error ("Can't open file '%s'",in_name);
+ li.in.h = li.in.c->header;
+
+ /* Check that it is a suitable device input icc */
+ if (li.in.h->deviceClass != icSigInputClass
+ && li.in.h->deviceClass != icSigDisplayClass
+ && li.in.h->deviceClass != icSigOutputClass
+ && li.in.h->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
+ error("Input profile '%s' isn't a device profile",in_name);
+
+ /* Wrap with an expanded icc */
+ if ((li.in.x = new_xicc(li.in.c)) == NULL)
+ error ("Creation of input profile xicc failed");
+
+ /* Set the default ink limits if not set on command line */
+ icxDefaultLimits(li.in.x, &li.in.ink.tlimit, li.in.ink.tlimit, &li.in.ink.klimit, li.in.ink.klimit);
+
+ if (li.verb) {
+ if (li.in.ink.tlimit >= 0.0)
+ printf("Input total ink limit assumed is %3.0f%%\n",100.0 * li.in.ink.tlimit);
+ if (li.in.ink.klimit >= 0.0)
+ printf("Input black ink limit assumed is %3.0f%%\n",100.0 * li.in.ink.klimit);
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* Open up the abstract profile if requested */
+ if (abs_name[0] != '\000') {
+ if ((li.abs_fp = new_icmFileStd_name(abs_name,"r")) == NULL)
+ error ("Can't open abstract profile file '%s'",abs_name);
+
+ if ((li.abs_icc = new_icc()) == NULL)
+ error ("Creation of Abstract profile ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = li.abs_icc->read(li.abs_icc,li.abs_fp,0)) != 0)
+ error ("%d, %s",rv,li.abs_icc->err);
+
+ if (li.abs_icc->header->deviceClass != icSigAbstractClass)
+ error("Abstract profile isn't an abstract profile");
+
+ /* Take intended abstract intent from profile itself */
+ if ((li.abs_intent = li.abs_icc->header->renderingIntent) != icAbsoluteColorimetric)
+ li.abs_intent = icRelativeColorimetric;
+
+ /* Wrap with an expanded icc */
+ if ((li.abs_xicc = new_xicc(li.abs_icc)) == NULL)
+ error ("Creation of abstract profile xicc failed");
+ }
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* Open up the output device output profile for reading, and read header etc. */
+ if ((li.out.c = read_embedded_icc(out_name)) == NULL)
+ error ("Can't open file '%s'",out_name);
+ li.out.h = li.out.c->header;
+
+ if (li.out.h->deviceClass != icSigInputClass
+ && li.out.h->deviceClass != icSigDisplayClass
+ && li.out.h->deviceClass != icSigOutputClass
+ && li.out.h->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
+ error("Output profile isn't a device profile");
+
+ /* Wrap with an expanded icc */
+ if ((li.out.x = new_xicc(li.out.c)) == NULL)
+ error ("Creation of output profile xicc failed");
+
+ /* Set the default ink limits if not set on command line */
+ icxDefaultLimits(li.out.x, &li.out.ink.tlimit, li.out.ink.tlimit, &li.out.ink.klimit, li.out.ink.klimit);
+
+ if (li.verb) {
+ if (li.out.ink.tlimit >= 0.0)
+ printf("Output total ink limit assumed is %3.0f%%\n",100.0 * li.out.ink.tlimit);
+ if (li.out.ink.klimit >= 0.0)
+ printf("Output black ink limit assumed is %3.0f%%\n",100.0 * li.out.ink.klimit);
+ }
+
+ /* deal with output black generation. */
+ /* Ink limits will have been set in option parsing */
+
+ switch (li.out.inking) {
+ case 0: /* Use input profile K level or locus */
+ /* Sanity check */
+ if (li.in.h->colorSpace != li.out.h->colorSpace)
+ error("Can't transfer black ink in & out unless the same colorspaces");
+ li.out.ink.k_rule = li.out.locus ? icxKlocus : icxKvalue; /* Given as aux parameter in PCS -> Device */
+ break;
+ case 7: /* Use output profile K level or locus */
+ li.out.ink.k_rule = li.out.locus ? icxKlocus : icxKvalue; /* Given as aux parameter in PCS -> Device */
+ break;
+ case 1: /* Minimum K */
+ li.out.ink.k_rule = li.out.locus ? icxKluma5 : icxKluma5k;
+ li.out.ink.c.Kstle = 0.0;
+ li.out.ink.c.Kstpo = 0.0;
+ li.out.ink.c.Kenpo = 1.0;
+ li.out.ink.c.Kenle = 0.0;
+ li.out.ink.c.Kshap = 1.0;
+ break;
+ case 2: /* 0.5 K */
+ li.out.ink.k_rule = li.out.locus ? icxKluma5 : icxKluma5k;
+ li.out.ink.c.Kstle = 0.5;
+ li.out.ink.c.Kstpo = 0.0;
+ li.out.ink.c.Kenpo = 1.0;
+ li.out.ink.c.Kenle = 0.5;
+ li.out.ink.c.Kshap = 1.0;
+ break;
+ case 3: /* Maximum K */
+ li.out.ink.k_rule = li.out.locus ? icxKluma5 : icxKluma5k;
+ li.out.ink.c.Kstle = 1.0;
+ li.out.ink.c.Kstpo = 0.0;
+ li.out.ink.c.Kenpo = 1.0;
+ li.out.ink.c.Kenle = 1.0;
+ li.out.ink.c.Kshap = 1.0;
+ break;
+ case 4: /* Ramp K */
+ li.out.ink.k_rule = li.out.locus ? icxKluma5 : icxKluma5k;
+ li.out.ink.c.Kstle = 0.0;
+ li.out.ink.c.Kstpo = 0.0;
+ li.out.ink.c.Kenpo = 1.0;
+ li.out.ink.c.Kenle = 1.0;
+ li.out.ink.c.Kshap = 1.0;
+ break;
+ case 5: /* Curve */
+ li.out.ink.k_rule = li.out.locus ? icxKluma5 : icxKluma5k;
+ break; /* Other params already set by options */
+ case 6: /* Use input profile K locus + dual curve limits */
+ /* Sanity check */
+ if (li.in.h->colorSpace != li.out.h->colorSpace)
+ error("Can't transfer black ink in & out unless the same colorspaces");
+ li.out.ink.k_rule = li.out.locus ? icxKl5l : icxKl5lk; /* Aux param in PCS -> Device */
+ break; /* Other params already set by options */
+ }
+
+ for (i = 0; i < 2; i++) {
+ xicc *x;
+ icxViewCond *v, *vc;
+ int es;
+
+ if (i == 0) {
+ v = &ivc; /* Override parameters */
+ vc = &li.in.vc; /* Target parameters */
+ es = ivc_e;
+ x = li.in.x; /* xicc */
+ } else {
+ v = &ovc; /* Override parameters */
+ vc = &li.out.vc; /* Target parameters */
+ es = ovc_e;
+ x = li.out.x; /* xicc */
+ }
+
+ /* Set the default viewing conditions */
+ xicc_enum_viewcond(x, vc, -1, NULL, 0, NULL);
+
+ /* Override the default viewing conditions. */
+ /* (?? Could move this code into xicc_enum_viewcond() as an option ??) */
+ /* First any enumerated selection */
+ if (es != -1) {
+ if (xicc_enum_viewcond(x, vc, es, NULL, 0, NULL) == -999)
+ error ("%d, %s",x->errc, x->err);
+ }
+ /* Then any individual paramaters */
+ if (v->Ev >= 0)
+ vc->Ev = v->Ev;
+ if (v->Wxyz[0] >= 0.0 && v->Wxyz[1] > 0.0 && v->Wxyz[2] >= 0.0) {
+ /* Normalise XYZ to current media white */
+ vc->Wxyz[0] = v->Wxyz[0]/v->Wxyz[1] * vc->Wxyz[1];
+ vc->Wxyz[2] = v->Wxyz[2]/v->Wxyz[1] * vc->Wxyz[1];
+ }
+ if (v->Wxyz[0] >= 0.0 && v->Wxyz[1] >= 0.0 && v->Wxyz[2] < 0.0) {
+ /* Convert Yxy to XYZ */
+ double x = v->Wxyz[0];
+ double y = v->Wxyz[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
+ double z = 1.0 - x - y;
+ vc->Wxyz[0] = x/y * vc->Wxyz[1];
+ vc->Wxyz[2] = z/y * vc->Wxyz[1];
+ }
+ if (v->La >= 0.0)
+ vc->La = v->La;
+ if (v->Yb >= 0.0)
+ vc->Yb = v->Yb;
+ if (v->Lv >= 0.0)
+ 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) {
+ /* 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];
+ }
+ if (v->Fxyz[0] >= 0.0 && v->Fxyz[1] >= 0.0 && v->Fxyz[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 z = 1.0 - x - y;
+ vc->Fxyz[0] = x/y * vc->Fxyz[1];
+ vc->Fxyz[2] = z/y * vc->Fxyz[1];
+ }
+ }
+
+ if (li.verb)
+ printf("Configured options\n");
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* Setup the profile color lookup information */
+ {
+ icmLuAlgType oalg; /* Native output algorithm */
+ icColorSpaceSignature natpcs; /* Underlying native output PCS */
+ int flb = 0, fl = 0; /* luobj flags */
+
+ li.pcsor = icSigLabData; /* Default use Lab as PCS */
+
+ /* If we are using the gamut map mode, then setup */
+ /* the intents and pcsor appropriately. */
+ if (li.mode > 0) {
+
+ if ((li.gmi.usecas & 0xff) != 0) {
+ li.pcsor = icxSigJabData; /* Use CAM as PCS */
+ isJab = 1;
+
+ if ((li.gmi.usecas & 0xff) == 0x2) { /* Absolute Appearance space */
+ double mxw;
+
+ li.in.intent = li.out.intent = li.abs_intent = icxAbsAppearance;
+
+ /* Make absolute common white point average between the two */
+ li.in.vc.Wxyz[0] = 0.5 * (li.in.vc.Wxyz[0] + li.out.vc.Wxyz[0]);
+ li.in.vc.Wxyz[1] = 0.5 * (li.in.vc.Wxyz[1] + li.out.vc.Wxyz[1]);
+ li.in.vc.Wxyz[2] = 0.5 * (li.in.vc.Wxyz[2] + li.out.vc.Wxyz[2]);
+
+ /* And scale it Y to be equal to 1.0 */
+ mxw = 1.0/li.in.vc.Wxyz[1];
+ li.in.vc.Wxyz[0] *= mxw;
+ li.in.vc.Wxyz[1] *= mxw;
+ li.in.vc.Wxyz[2] *= mxw;
+
+ /* Set the output vc to be the same as the input */
+ li.out.vc = li.in.vc; /* Structure copy */
+ } else {
+ /* Not Abs Appearance space */
+ li.in.intent = li.out.intent = li.abs_intent = icxAppearance;
+ }
+ } else {
+ /* Not Appearance space */
+ li.in.intent = li.out.intent = li.abs_intent = icAbsoluteColorimetric;
+ }
+ }
+
+ if (li.verb)
+ printf("Loading input A2B table\n");
+
+ /* default flags for all xicc luobj's */
+ flb = ICX_CLIP_NEAREST;
+ if (li.verb)
+ flb |= ICX_VERBOSE;
+
+ /* Get an input profile xicc conversion object */
+ fl = flb;
+#ifdef USE_MERGE_CLUT_OPT
+ fl |= ICX_MERGE_CLUT;
+#endif
+
+#ifdef NEVER
+ printf("~1 input space flags = 0x%x\n",fl);
+ printf("~1 input space intent = %s\n",icx2str(icmRenderingIntent,li.in.intent));
+ printf("~1 input space pcs = %s\n",icx2str(icmColorSpaceSignature,li.pcsor));
+ printf("~1 input space viewing conditions =\n"); xicc_dump_viewcond(&li.in.vc);
+ printf("~1 input space inking =\n"); xicc_dump_inking(&li.in.ink);
+#endif
+ if ((li.in.luo = li.in.x->get_luobj(li.in.x, fl, icmFwd, li.in.intent,
+ li.pcsor, icmLuOrdNorm, &li.in.vc, &li.in.ink)) == NULL) {
+ error("get xlookup object failed: %d, %s",li.in.x->errc,li.in.x->err);
+ }
+
+ /* Get details of overall conversion */
+ li.in.luo->spaces(li.in.luo, &li.in.csp, &li.in.chan, NULL, NULL, &li.in.alg,
+ NULL, NULL, NULL);
+
+ /* Get the input profile A2B input curve resolution */
+ /* (This is pretty rough - this should work for non LUT types as well!!) */
+ {
+ if (li.in.alg== icmLutType) {
+ icmLut *lut;
+ icxLuLut *luluo = (icxLuLut *)li.in.luo; /* Safe to coerce */
+ luluo->get_info(luluo, &lut, NULL, NULL, NULL); /* Get some details */
+ in_curve_res = lut->inputEnt;
+ }
+ }
+
+ /* Grab the white point in case the wphack or xyzscale needs it */
+ li.in.luo->efv_wh_bk_points(li.in.luo, li.in.wp, NULL, NULL);
+
+ /* Get native PCS space */
+ li.in.luo->lutspaces(li.in.luo, NULL, NULL, &natpcs, NULL, NULL);
+
+ if (li.in.nocurve == 0 && natpcs == icSigXYZData
+ && (li.in.alg == icmMatrixFwdType || li.in.alg == icmMatrixBwdType
+ || li.in.csp == icSigXYZData)) {
+ li.in.lcurve = 1; /* Use Y to L* and L* to Y for input */
+ if (li.in.csp == icSigXYZData) {
+ li.in.lcurve = 2; /* Use real Y to L* and L* to Y for input */
+ li.in.nocurve = 1; /* Don't trust the curve that comes with it */
+ }
+ if (li.verb)
+ printf("Using Y to L* and L* to Y curves for input\n");
+ }
+
+ /* Setup any abstract profile to match the chosen PCS */
+ /* We aren't checking whether the input/abstract/output profile */
+ /* intents really make any sense. It's assumed at the moment */
+ /* that the user knows what they're doing! */
+ if (abs_name[0] != '\000') {
+
+ if ((li.abs_luo = li.abs_xicc->get_luobj(li.abs_xicc, flb, icmFwd, li.abs_intent,
+ li.pcsor, icmLuOrdNorm, &li.out.vc, NULL)) == NULL)
+ error ("%d, %s",li.abs_icc->errc, li.abs_icc->err);
+ }
+
+ // Figure out whether the output profile is a Lut profile or not */
+ {
+ icmLuBase *plu;
+
+ /* Get temporary icm lookup object */
+ /* (Use Fwd just in case profile is missing B2A !!!!) */
+ if ((plu = li.out.c->get_luobj(li.out.c, icmFwd, icmDefaultIntent, icmSigDefaultData,
+ icmLuOrdNorm)) == NULL) {
+ error("get icm lookup object failed: on '%s' %d, %s",out_name,li.out.c->errc,li.out.c->err);
+ }
+
+ /* Check what the algorithm is */
+ plu->spaces(plu, NULL, NULL, NULL, NULL, &oalg, NULL, NULL, NULL, NULL);
+
+ /* release the icm lookup */
+ plu->del(plu);
+
+ }
+
+ if (oalg != icmLutType || li.mode < 2) { /* Using B2A table or inv. mono/matrix */
+ if (li.verb)
+ printf("Loading output B2A table\n");
+
+ if ((li.out.luo = li.out.x->get_luobj(li.out.x, flb, icmBwd, li.out.intent,
+ li.pcsor, icmLuOrdNorm, &li.out.vc, &li.out.ink)) == NULL) {
+ error("get xlookup object failed: %d, %s",li.out.x->errc,li.out.x->err);
+ }
+ /* Get details of overall conversion */
+ li.out.luo->spaces(li.out.luo, NULL, NULL, NULL, &li.out.chan, &li.out.alg,
+ NULL, NULL, NULL);
+
+ /* Get the output profile B2A output curve resolution */
+ /* (This is pretty rough - this should work for non LUT types as well!!) */
+ {
+ if (li.out.alg== icmLutType) {
+ icmLut *lut;
+ icxLuLut *luluo = (icxLuLut *)li.out.luo; /* Safe to coerce */
+ luluo->get_info(luluo, &lut, NULL, NULL, NULL); /* Get some details */
+ out_curve_res = lut->outputEnt;
+ }
+ }
+
+ /* Grab the white point in case the wphack or xyzscale needs it */
+ li.out.luo->efv_wh_bk_points(li.out.luo, li.out.wp, NULL, NULL);
+
+ /* Get native PCS space */
+ li.out.luo->lutspaces(li.out.luo, &natpcs, NULL, NULL, NULL, NULL);
+
+ } else { /* Using inverse A2B Lut for output conversion */
+
+ fl = flb;
+#ifdef USE_MERGE_CLUT_OPT
+ fl |= ICX_MERGE_CLUT;
+#endif
+#ifdef USE_CAM_CLIP_OPT
+ fl |= ICX_CAM_CLIP;
+#endif
+ if (li.verb)
+ printf("Loading output inverse A2B table\n");
+
+#ifdef NEVER
+ printf("~1 output space flags = 0x%x\n",fl);
+ printf("~1 output space intent = %s\n",icx2str(icmRenderingIntent,li.out.intent));
+ printf("~1 output space pcs = %s\n",icx2str(icmColorSpaceSignature,li.pcsor));
+ printf("~1 output space viewing conditions =\n"); xicc_dump_viewcond(&li.out.vc);
+ printf("~1 output space inking =\n"); xicc_dump_inking(&li.out.ink);
+#endif
+
+ if ((li.out.luo = li.out.x->get_luobj(li.out.x, fl, icmFwd,
+ li.out.intent, li.pcsor, icmLuOrdNorm, &li.out.vc,
+ &li.out.ink)) == NULL) {
+ error("get xlookup object failed: %d, %s",li.out.x->errc,li.out.x->err);
+ }
+
+ /* Get details of overall conversion */
+ li.out.luo->spaces(li.out.luo, &li.out.csp, &li.out.chan, NULL, NULL, &li.out.alg,
+ NULL, NULL, NULL);
+
+ /* Get the output profile A2B input curve resolution */
+ /* (This is pretty rough - this should work for non LUT types as well!!) */
+ {
+ if (li.out.alg== icmLutType) {
+ icmLut *lut;
+ icxLuLut *luluo = (icxLuLut *)li.out.luo; /* Safe to coerce */
+ luluo->get_info(luluo, &lut, NULL, NULL, NULL); /* Get some details */
+ out_curve_res = lut->inputEnt;
+ }
+ }
+
+ /* Grab the white point in case the wphack or xyzscale needs it */
+ li.out.luo->efv_wh_bk_points(li.out.luo, li.out.wp, NULL, NULL);
+
+ /* Get native PCS space */
+ li.out.luo->lutspaces(li.out.luo, NULL, NULL, &natpcs, NULL, NULL);
+
+ /* If we need a B2A lookup to get the existing K */
+ if (li.out.inking == 7) {
+ if ((li.out.b2aluo = li.out.x->get_luobj(li.out.x, flb, icmBwd,
+ li.out.intent, li.pcsor, icmLuOrdNorm, &li.out.vc, NULL)) == NULL) {
+ error("get B2A xlookup object failed: %d, %s",li.out.x->errc,li.out.x->err);
+ }
+ }
+ }
+
+ /* If we need an PCS->K' mapping for the neutral axis to K hack. */
+ /* What we do is lookup the L for K values from 0 to 1, */
+ /* and then invert this to create an L to K lookup. */
+ /* If the gamut mapping is set to map to the K only black point, */
+ /* it should all work well... */
+ if (li.nhack) {
+ icxLuBase *luo; /* Base XLookup type object */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ co ips[256]; /* Initialisation points */
+ datai glow; /* Grid low scale */
+ datai ghigh; /* Grid high scale */
+ datao vlow; /* Data value low normalize */
+ datao vhigh; /* Data value high normalize */
+ double Lmax, Lmin; /* Max and Min L values that result */
+ int grres;
+ double avgdev[MXDO];
+
+ if (li.out.h->colorSpace != icSigCmykData)
+ error("Neutral Axis K only requested with non CMYK output profile");
+
+ if (li.in.chan < 3)
+ error("Neutral Axis K only requested with input profile with less than 3 channels");
+
+ if (li.nhack == 2 && li.in.h->colorSpace != icSigCmykData)
+ error("Neutral Axis 000K only requested with input profile that is not CMYK");
+
+ if ((li.pcs2k = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ error("Failed to create an rspl object");
+ }
+
+ /* Get a device to PCS lookup object to use to lookup K->PCS */
+ if ((luo = li.out.x->get_luobj(li.out.x, flb,
+ icmFwd, li.out.intent, li.pcsor, icmLuOrdNorm, &li.out.vc,
+ NULL)) == NULL) {
+ error("get xlookup object failed: %d, %s",li.out.x->errc,li.out.x->err);
+ }
+ /* Get details of overall conversion */
+ luo->spaces(luo, NULL, NULL, NULL, NULL, &alg, NULL, NULL, NULL);
+ if (alg != icmLutType)
+ error ("Unexpected algorithm type for CMYK output profile");
+
+ /* Setup the initialisation points */
+ Lmax = -100.0;
+ Lmin = 1000.0;
+ for (i = 0; i < 256; i++) {
+ icxLuLut *lu = (icxLuLut *)luo; /* Safe to coerce */
+ double in[4], pcsv[4];
+ in[0] = in[1] = in[2] = 0.0;
+ in[3] = i/(255.0);
+
+ /* Want to do dev' -> PCS conversion to match the */
+ /* normal inverse PCS-> dev' used in devip_devop() */
+ if (li.out.nocurve) { /* No explicit curve, so do implicit here */
+ /* Since not PCS, in_abs and matrix cannot be valid, */
+ /* so input curve on own is ok to use. */
+ lu->input(lu, pcsv, in);
+ lu->clut(lu, pcsv, pcsv);
+ } else {
+ lu->clut(lu, pcsv, in);
+ }
+ lu->output(lu, pcsv, pcsv);
+ lu->out_abs(lu, pcsv, pcsv);
+
+ /* We force the rspl to be a forward conversion by swapping K and PCS */
+ ips[i].p[0] = pcsv[0]; /* PCS as input */
+ ips[i].v[0] = in[3]; /* K as output */
+#ifdef NEUTKDEBUG
+ printf("L %f -> K' %f\n",pcsv[0], in[3]);
+#endif /* NEUTKDEBUG */
+
+ if (pcsv[0] > Lmax) /* Track min and max L values */
+ Lmax = pcsv[0];
+ if (pcsv[0] < Lmin)
+ Lmin = pcsv[0];
+ }
+
+ glow[0] = 0.0;
+ ghigh[0] = 100.0;
+ vlow[0] = 0.0;
+ vhigh[0] = 1.0;
+ grres = 256;
+ avgdev[0] = 0.005;
+
+ li.pcs2k->fit_rspl(li.pcs2k, 0, ips, 256, glow, ghigh, &grres, vlow, vhigh, 1.0, avgdev, NULL);
+
+ /* Fixup the white and black points for neutral axis to K hack. */
+ /* This is to make sure that they exactly match the fwd mapping */
+ /* after the rspl is fitted. */
+ {
+ pcs2k_ctx cx; /* White point fixup context */
+ co pp; /* Lookup the min and max K values */
+
+ pp.p[0] = Lmax;
+ li.pcs2k->interp(li.pcs2k, &pp);
+ cx.kmin = pp.v[0]; /* Ideally would be 0 */
+ pp.p[0] = Lmin;
+ li.pcs2k->interp(li.pcs2k, &pp);
+ cx.kmax = pp.v[0]; /* Ideally would be 1 */
+
+#ifdef NEUTKDEBUG
+ printf("Before fix: Lmax %f, Lmin %f, Kmin %f, Kmax %f\n",Lmax, Lmin, cx.kmin, cx.kmax);
+#endif /* NEUTKDEBUG */
+
+ li.pcs2k->re_set_rspl(li.pcs2k, 0, (void *)&cx, fix_pcs2k_white);
+#ifdef NEUTKDEBUG
+ pp.p[0] = Lmax;
+ li.pcs2k->interp(li.pcs2k, &pp);
+ cx.kmin = pp.v[0]; /* Ideally would be 0 */
+ pp.p[0] = Lmin;
+ li.pcs2k->interp(li.pcs2k, &pp);
+ cx.kmax = pp.v[0]; /* Ideally would be 1 */
+ printf("After fix: Lmax %f, Lmin %f, Kmin %f, Kmax %f\n",Lmax, Lmin, cx.kmin, cx.kmax);
+#endif /* NEUTKDEBUG */
+ }
+
+ } /* end if neutral axis to K hack */
+
+ if (li.cmyhack != 0) {
+ if (li.in.h->colorSpace != icSigCmyData
+ && li.in.h->colorSpace != icSigCmykData)
+ error("100% CMY mapping requested with non CMY or CMYK input profile");
+
+ if (li.out.h->colorSpace != icSigCmyData
+ && li.out.h->colorSpace != icSigCmykData)
+ error("100% CMY mapping requested with non CMY or CMYK output profile");
+ }
+
+ if (li.out.nocurve == 0 && natpcs == icSigXYZData
+ && (li.out.alg == icmMatrixFwdType || li.out.alg == icmMatrixBwdType
+ || li.out.csp == icSigXYZData)) {
+ li.out.lcurve = 1; /* Use Y to L* and L* to Y for output */
+ if (li.out.csp == icSigXYZData) {
+ li.out.lcurve = 2; /* Use real Y to L* and L* to Y for output */
+ li.out.nocurve = 1; /* Don't trust the curve that comes with it */
+ }
+ if (li.verb)
+ printf("Using Y to L* and L* to Y curves for output\n");
+ }
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* Setup the gamut mapping */
+// ~~~~ need to account for possible abstract profile after source !!!!
+// ~~~~ also need to fix tiffgamut to allow for abstract profile !!!!
+
+ if (li.verb)
+ printf("Gamut mapping mode is '%s'\n",li.mode == 0 ? "Simple" : li.mode == 1 ? "Mapping" : "Mapping inverse A2B");
+ if (li.verb && li.mode > 0)
+ printf("Gamut mapping intent is '%s'\n",li.gmi.desc);
+
+ /* In gamut mapping mode, the PCS used will always be absolute */
+ /* intent from the input and output profiles, and either */
+ /* lab or Jab space, with the given in/out viewing conditions */
+ /* for the latter. The xluo->get_gamut work in the set li.pcsor */
+ /* for each xluo. */
+ if (li.mode > 0 && li.gmi.usemap) {
+ gamut *csgam, *igam, *ogam;
+ double sgres; /* Source gamut surface feature resolution */
+ double dgres; /* Destination gamut surface feature resolution */
+ int mapres; /* Mapping rspl resolution */
+
+ if (li.verb)
+ printf("Creating Gamut Mapping\n");
+
+ /* Gamut mapping will extend given grid res to encompas */
+ /* source gamut by a margin. */
+ if (li.quality == 3) { /* Ultra High */
+ sgres = 7.0;
+ dgres = 7.0;
+ mapres = 41;
+ } else if (li.quality == 2) { /* High */
+ sgres = 8.0;
+ dgres = 8.0;
+ mapres = 33;
+ } else if (li.quality == 1) { /* Medium */
+ sgres = 10.0;
+ dgres = 10.0;
+ mapres = 25;
+ } else { /* Low quality */
+ sgres = 12.0;
+ dgres = 12.0;
+ mapres = 17;
+ }
+
+ /* Creat the source colorspace gamut surface */
+ if (li.verb)
+ printf(" Finding Source Colorspace Gamut with res %f\n",sgres);
+
+ /* Creat the source image gamut surface in the selected li.pcsor space */
+ if ((csgam = li.in.luo->get_gamut(li.in.luo, sgres)) == NULL)
+ error ("%d, %s",li.in.x->errc, li.in.x->err);
+
+ /* Grab a given source image gamut. */
+ if (sgam_name[0] != '\000') { /* Optional source gamut - ie. from an images */
+
+ if (li.verb)
+ printf(" Loading Image Source Gamut '%s'\n",sgam_name);
+
+ igam = new_gamut(sgres, isJab, 0); /* isJab will be overriden by gamut file */
+
+ if (igam->read_gam(igam, sgam_name))
+ error("Reading source gamut '%s' failed",sgam_name);
+
+ if (igam->getisjab(igam) != isJab) {
+ /* Should really convert to/from Jab here! */
+ warning("Image gamut is wrong colorspace for link (Lab != Jab)");
+
+ /* This will actually error in the gamut mapping code */
+ /* Note that we're not checking relative/absolute colorspace here. */
+ /* At the moment it's up to the user to get this right. */
+ }
+
+ } else {
+ igam = NULL; /* NULL signals no source image gamut */
+ }
+
+ /* Creat the destination gamut surface */
+ if (li.verb)
+ printf(" Finding Destination Gamut with res %f\n",dgres);
+
+ if ((ogam = li.out.luo->get_gamut(li.out.luo, dgres)) == NULL)
+ error ("%d, %s",li.out.x->errc, li.out.x->err);
+
+ if (li.verb)
+ printf(" Creating Gamut match\n");
+
+ li.map = new_gammap(li.verb, csgam, igam, ogam, &li.gmi,
+ li.src_kbp, li.dst_kbp, li.cmyhack, li.rel_oride,
+ mapres, NULL, NULL, li.gamdiag ? "gammap.wrl" : NULL
+ );
+ if (li.map == NULL)
+ error ("Failed to make gamut map transform");
+
+ if (li.nhack == 2) {
+ if (li.verb)
+ printf(" Creating K only black to K only black Gamut match\n");
+
+ li.Kmap = new_gammap(li.verb, csgam, igam, ogam, &li.gmi,
+ 1, 1, li.cmyhack, li.rel_oride,
+ mapres, NULL, NULL, li.gamdiag ? "gammap.wrl" : NULL
+ );
+ if (li.Kmap == NULL)
+ error ("Failed to make K only gamut map transform");
+ }
+
+ ogam->del(ogam);
+ if (igam != NULL)
+ igam->del(igam);
+ csgam->del(csgam);
+ }
+
+ /* If we've got a request for Absolute Appearance mode with scaling */
+ /* to avoid clipping the source white point, compute the needed XYZ scaling factor. */
+ /* We assume that the white point hack can't be used at the same time. */
+ if (li.mode > 0 && li.wphack == 0 && (li.gmi.usecas & 0x100) != 0) {
+ double xyzscale[1], sa[1];
+
+ /* We already have the source space white point in li.in.wp[] */
+
+ /* Convert it to destination XYZ */
+ if (li.pcsor == icxSigJabData) {
+ /* We're being bad in delving inside the xluo, but we'll fix it latter */
+ li.out.luo->cam->cam_to_XYZ(li.out.luo->cam, li.swxyz, li.in.wp);
+ } else
+ error("Internal :- not setup to handle Y scaling and non-Jab PCS");
+
+//printf("~1 Source white Jab = %f %f %f\n", li.in.wp[0], li.in.wp[1], li.in.wp[2]);
+//printf("~1 Source white XYZ = %f %f %f\n", li.swxyz[0], li.swxyz[1], li.swxyz[2]);
+
+ /* Compute the bigest scale factor less than or equal to 1.0, */
+ /* that doesn't clip the li.swxyz[] on the destination gamut */
+ sa[0] = 0.1;
+ xyzscale[0] = 0.5;
+ if (powell(NULL, 1, xyzscale, sa, 1e-6, 2000, xyzoptfunc, (void *)&li, NULL, NULL) != 0) {
+ warning("set_icxLuLut: XYZ scale powell failed to converge - set scale to 1.0");
+ } else {
+ li.xyzscale = xyzscale[0];
+ if (li.verb)
+ printf("Set XYZ scale factor to %f\n",li.xyzscale);
+ }
+ }
+
+ /* Create the link profile */
+ if (verify == 0) {
+ icmFile *wr_fp;
+ icc *wr_icc;
+
+ if (li.verb)
+ printf("Creating link profile\n");
+
+ /* Open up the link file for writing */
+ if ((wr_fp = new_icmFileStd_name(link_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",link_name);
+
+ if ((wr_icc = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icc->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigLinkClass; /* We are creating a link ! */
+ wh->colorSpace = li.in.h->colorSpace; /* Input profile device space */
+ wh->pcs = li.out.h->colorSpace; /* Output profile device space */
+ if (li.mode > 0) {
+ wh->renderingIntent = li.gmi.icci; /* Closest ICC intent */
+ } else {
+ wh->renderingIntent = li.out.intent; /* Output intent chosen */
+ }
+
+ /* Values that should be set before writing */
+ if (xpi.manufacturer != 0L)
+ wh->manufacturer = xpi.manufacturer;
+ else
+ wh->manufacturer = icmSigUnknownType;
+
+ if (xpi.model != 0L)
+ wh->model = xpi.model;
+ else
+ wh->model = icmSigUnknownType;
+
+ /* Values that may be set before writing */
+ if (xpi.creator != 0L)
+ wh->creator = xpi.creator;
+
+ wh->attributes.l = 0;
+ wh->flags = 0;
+#ifdef NT
+ wh->platform = icSigMicrosoft;
+#endif
+#ifdef __APPLE__
+ wh->platform = icSigMacintosh;
+#endif
+#if defined(UNIX) && !defined(__APPLE__)
+ wh->platform = icmSig_nix;
+#endif
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst, dstm[200]; /* description */
+
+ if (xpi.profDesc != NULL)
+ dst = xpi.profDesc;
+ else {
+ dst = "Device Link profile - See ProfileSequenceDescTag for more information";
+ dst = dstm;
+ }
+
+ if ((wo = (icmTextDescription *)wr_icc->add_tag(
+ wr_icc, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt;
+
+ if (xpi.copyright != NULL)
+ crt = xpi.copyright;
+ else
+ crt = "Copyright, the creator of this profile";
+
+ if ((wo = (icmText *)wr_icc->add_tag(
+ wr_icc, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* Device Manufacturers Description Tag: */
+ if (xpi.deviceMfgDesc != NULL) {
+ icmTextDescription *wo;
+ char *dst = xpi.deviceMfgDesc;
+
+ if ((wo = (icmTextDescription *)wr_icc->add_tag(
+ wr_icc, icSigDeviceMfgDescTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Model Description Tag: */
+ if (xpi.modelDesc != NULL) {
+ icmTextDescription *wo;
+ char *dst = xpi.modelDesc;
+
+ if ((wo = (icmTextDescription *)wr_icc->add_tag(
+ wr_icc, icSigDeviceModelDescTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* ProfileSequenceDescTag: */
+ {
+ unsigned int i;
+ icmProfileSequenceDesc *wo;
+ if ((wo = (icmProfileSequenceDesc *)wr_icc->add_tag(
+ wr_icc, icSigProfileSequenceDescTag, icSigProfileSequenceDescType)) == NULL)
+ return 1;
+
+ wo->count = 2; /* Number of descriptions in sequence */
+ if (wo->allocate((icmBase *)wo) != 0) /* Allocate space for all the DescStructures */
+ error("allocate failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ /* Fill in each description structure in sequence */
+
+ /* For each profile in the chain */
+ for (i = 0; i < wo->count; i++) {
+ icc *iccs = NULL;
+ icmHeader *sh = NULL;
+ icmSignature *tsig;
+ icmTextDescription *ddesc;
+ icmTextDescription *mdesc;
+
+ if (i == 0) {
+ iccs = li.in.c; /* Input profile */
+ sh = li.in.h; /* Input profile header */
+ } else if (i == (wo->count-1)) {
+ iccs = li.out.c; /* Output profile */
+ sh = li.out.h; /* Output profile header */
+ } else {
+ error("Abstract profiles in link not implemented yet!");
+ }
+
+ /* Try and read the technology tag */
+ if ((tsig = (icmSignature *)iccs->read_tag(iccs, icSigTechnologyTag)) != NULL) {
+ if (tsig->ttype != icSigSignatureType) /* oops */
+ tsig = NULL;
+ }
+
+ /* Try and read the Device Manufacturers Description Tag */
+ if ((ddesc = (icmTextDescription *)iccs->read_tag(
+ iccs, icSigDeviceMfgDescTag)) != NULL) {
+ if (ddesc->ttype != icSigTextDescriptionType) /* oops */
+ ddesc = NULL;
+ }
+
+ /* Try and read the Model Manufacturers Description Tag */
+ if ((mdesc = (icmTextDescription *)iccs->read_tag(
+ iccs, icSigDeviceModelDescTag)) != NULL) {
+ if (mdesc->ttype != icSigTextDescriptionType) /* oops */
+ mdesc = NULL;
+ }
+
+ /* Header information */
+ wo->data[i].deviceMfg = sh->manufacturer;
+ wo->data[i].deviceModel = sh->model;
+ wo->data[i].attributes = sh->attributes;
+
+ /* Technology signature */
+ if (tsig != NULL)
+ wo->data[i].technology = tsig->sig;
+
+ if (ddesc != NULL) {
+ wo->data[i].device.size = ddesc->size;
+ if (wo->data[i].allocate(&wo->data[i]) != 0) /* Allocate space */
+ error("allocate failed: %d, %s",wr_icc->errc,wr_icc->err);
+ strcpy(wo->data[i].device.desc, ddesc->desc);
+
+ wo->data[i].device.ucLangCode = ddesc->ucLangCode;
+ wo->data[i].device.ucSize = ddesc->ucSize;
+ if (wo->data[i].allocate(&wo->data[i]) != 0) /* Allocate space */
+ error("allocate failed: %d, %s",wr_icc->errc,wr_icc->err);
+ memmove(wo->data[i].device.ucDesc, ddesc->ucDesc, 2 * ddesc->ucSize);
+
+ wo->data[i].device.scCode = ddesc->scCode;
+ wo->data[i].device.scSize = ddesc->scSize;
+ strcpy((char *)wo->data[i].device.scDesc, (char *)ddesc->scDesc);
+ }
+
+ /* model Text description */
+ if (mdesc != NULL) {
+ wo->data[i].model.size = mdesc->size;
+ if (wo->data[i].allocate(&wo->data[i])!= 0) /* Allocate space */
+ error("allocate failed: %d, %s",wr_icc->errc,wr_icc->err);
+ strcpy(wo->data[i].model.desc, mdesc->desc);
+
+ wo->data[i].model.ucLangCode = mdesc->ucLangCode;
+ wo->data[i].model.ucSize = mdesc->ucSize;
+ if (wo->data[i].allocate(&wo->data[i]) != 0) /* Allocate space */
+ error("allocate failed: %d, %s",wr_icc->errc,wr_icc->err);
+ memmove(wo->data[i].model.ucDesc, mdesc->ucDesc, 2 * mdesc->ucSize);
+
+ wo->data[i].model.scCode = mdesc->scCode;
+ wo->data[i].model.scSize = mdesc->scSize;
+ strcpy((char *)wo->data[i].model.scDesc, (char *)mdesc->scDesc);
+ }
+ }
+ }
+ /* ColorantTable: */
+ {
+ int i;
+ unsigned int j;
+ int repclip = 0;
+
+ /* For the first and last profile in the chain */
+ /* (Note that we're assuming that the link output PCS is always Lab) */
+ for (i = 0; i < 2; i++) {
+ icc *iccs;
+ icmHeader *sh;
+ icmColorantTable *ro;
+ icmColorantTable *wo;
+ icTagSignature cts;
+
+ if (i == 0) {
+ iccs = li.in.c; /* Input profile */
+ sh = li.in.h; /* Input profile header */
+ cts = icSigColorantTableTag;
+ } else {
+ iccs = li.out.c; /* Output profile */
+ sh = li.out.h; /* Output profile header */
+ cts = icSigColorantTableOutTag;
+ }
+
+ /* Try and read the input ColorantTable */
+ if ((ro = (icmColorantTable *)iccs->read_tag(
+ iccs, icSigColorantTableTag)) != NULL) {
+
+ /* Create a ColorantTable in the output device link */
+ if ((wo = (icmColorantTable *)wr_icc->add_tag(
+ wr_icc, cts, icSigColorantTableType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ /* Copy everything across */
+ wo->count = ro->count;
+ if (wo->allocate((icmBase *)wo) != 0)
+ error("allocate failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ for (j = 0; j < wo->count; j++) {
+ strcpy(wo->data[j].name, ro->data[j].name);
+ if (sh->pcs != icSigLabData) {
+ icmXYZ2Lab(&icmD50, wo->data[j].pcsCoords, ro->data[j].pcsCoords);
+ /* For device links the colorant table must be Lab PCS, */
+ /* but embarassingly, XYZ profiles can have colorant values */
+ /* not representable in the Lab PCS range. */
+ if (icmClipLab(wo->data[j].pcsCoords, wo->data[j].pcsCoords)) {
+ if (repclip)
+ warning("Colorant Tag Lab value was clipped");
+ repclip = 1;
+ }
+ } else {
+ icmAry2Ary(wo->data[j].pcsCoords, ro->data[j].pcsCoords);
+ }
+ }
+
+ } else { /* Do this the hard way */
+ icmLuBase *luo;
+ unsigned int count;
+ double dv[MAX_CHAN];
+ double cvals[MAX_CHAN][3];
+ inkmask imask;
+
+ /* Get a lookup to read colorant values */
+ if ((luo = iccs->get_luobj(iccs, icmFwd, icRelativeColorimetric,
+ icSigLabData, icmLuOrdNorm)) == NULL)
+ goto skip_coloranttable;
+
+ count = icmCSSig2nchan(sh->colorSpace);
+ for (j = 0; j < count; j++)
+ dv[j] = 0.0;
+
+ /* Lookup the colorant Lab values the recommended ICC way */
+ for (j = 0; j < count; j++) {
+ dv[j] = 1.0;
+ luo->lookup(luo, cvals[j], dv);
+ /* For device links the colorant table must be Lab PCS, */
+ /* but embarassingly, XYZ profiles can have colorant values */
+ /* not representable in the Lab PCS range. */
+ if (icmClipLab(cvals[j], cvals[j])) {
+ if (repclip)
+ warning("Colorant Tag Lab value was clipped");
+ repclip = 1;
+ }
+ dv[j] = 0.0;
+ }
+ luo->del(luo);
+
+ /* Lookup colorant names */
+ if ((imask = icx_icc_cv_to_colorant_comb(sh->colorSpace, iccs->header->deviceClass, cvals)) == 0)
+ goto skip_coloranttable;
+
+ /* Create a ColorantTable in the output device link */
+ if ((wo = (icmColorantTable *)wr_icc->add_tag(
+ wr_icc, cts, icSigColorantTableType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->count = count;
+ if (wo->allocate((icmBase *)wo) != 0)
+ error("allocate failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ for (j = 0; j < count; j++) {
+ inkmask iimask; /* Individual ink mask */
+ char *name;
+
+ iimask = icx_index2ink(imask, j);
+ name = icx_ink2string(iimask);
+ if (strlen(name) > 31)
+ error("Internal: colorant name exceeds 31 characters");
+ strcpy(wo->data[j].name, name);
+ wo->data[j].pcsCoords[0] = cvals[j][0];
+ wo->data[j].pcsCoords[1] = cvals[j][1];
+ wo->data[j].pcsCoords[2] = cvals[j][2];
+ }
+ }
+ /* Jump to here if we can't figure out what to put in ColorantTag */
+ skip_coloranttable:;
+ }
+ }
+ /* 16 bit input device -> output device lut: */
+ {
+ int inputEnt, outputEnt, clutPoints;
+ icmLut *wo;
+
+ /* Setup the cLUT resolutions */
+ if (li.quality >= 3)
+ inputEnt = 4096;
+ else if (li.quality == 2)
+ inputEnt = 2048;
+ else
+ inputEnt = 256;
+
+ /* Make sure that we have at least the number of input entries as the */
+ /* input profile. */
+ if (in_curve_res > inputEnt)
+ inputEnt = in_curve_res;
+
+ /* See discussion in imdi/imdi_gen.c for ideal numbers */
+ switch (li.in.chan) {
+ case 0:
+ error ("Illegal number of input chanels");
+ case 1:
+ if (li.quality >= 3)
+ clutPoints = 255;
+ else if (li.quality == 2)
+ clutPoints = 255;
+ else
+ clutPoints = 255;
+ break;
+
+ case 2:
+ if (li.quality >= 2)
+ clutPoints = 255;
+ else
+ clutPoints = 86;
+ break;
+ case 3:
+ if (li.quality >= 3)
+ clutPoints = 52;
+ else if (li.quality == 2)
+ clutPoints = 33;
+ else if (li.quality == 1)
+ clutPoints = 17;
+ else
+ clutPoints = 9;
+ break;
+ case 4:
+ if (li.quality >= 3)
+ clutPoints = 33;
+ else if (li.quality == 2)
+ clutPoints = 18;
+ else if (li.quality == 1)
+ clutPoints = 9;
+ else
+ clutPoints = 6;
+ break;
+ case 5:
+ if (li.quality >= 3)
+ clutPoints = 18;
+ else if (li.quality == 2)
+ clutPoints = 16;
+ else
+ clutPoints = 9;
+ break;
+ case 6:
+ if (li.quality >= 3)
+ clutPoints = 12;
+ else if (li.quality == 2)
+ clutPoints = 9;
+ else
+ clutPoints = 6;
+ break;
+ case 7:
+ if (li.quality >= 3)
+ clutPoints = 8;
+ else if (li.quality == 2)
+ clutPoints = 7;
+ else
+ clutPoints = 6;
+ break;
+ case 8:
+ if (li.quality >= 3)
+ clutPoints = 7;
+ else if (li.quality == 2)
+ clutPoints = 6;
+ else
+ clutPoints = 5;
+ break;
+ default: /* > 8 chan */
+ clutPoints = 3;
+ break;
+ }
+
+ if (li.clutres > 0) /* clut resolution override */
+ clutPoints = li.clutres;
+ li.clutres = clutPoints; /* Actual resolution */
+
+ if (li.quality >= 3)
+ outputEnt = 4096;
+ else if (li.quality == 2)
+ outputEnt = 2048;
+ else
+ outputEnt = 256;
+
+ /* Make sure that we have at least the number of input entries as the */
+ /* output profile. */
+ if (out_curve_res > outputEnt)
+ outputEnt = out_curve_res;
+
+
+ /* Link Lut = AToB0 */
+ if ((wo = (icmLut *)wr_icc->add_tag(
+ wr_icc, icSigAToB0Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->inputChan = li.in.chan;
+ wo->outputChan = li.out.chan;
+
+ /* Setup the tables resolutions */
+ wo->inputEnt = inputEnt;
+ wo->clutPoints = clutPoints;
+ wo->outputEnt = outputEnt;
+
+ if (wo->allocate((icmBase *)wo) != 0) /* Allocate space */
+ error("allocate failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ /* Special case if input profile is Lut with matrix */
+ /* (Does this do anything since input is not XYZ ?) */
+ if (li.in.alg == icmLutType && li.in.nocurve == 0) {
+ icxLuLut *lu = (icxLuLut *)li.in.luo;
+ lu->get_matrix(lu, wo->e); /* Copy it across */
+ }
+
+
+
+ if (li.verb)
+ printf("Filling in Lut table\n");
+#ifdef DEBUG_ONE
+#define DBGNO 1 /* Up to 10 */
+
+#ifndef NEVER
+ /* Test a single given rgb/cmyk -> cmyk value */
+ {
+ double in[10][MAX_CHAN];
+ double out[MAX_CHAN];
+ in[0][0] = 1.0;
+ in[0][1] = 1.0;
+ in[0][2] = 1.0;
+ in[0][3] = 0.0;
+
+ in[1][0] = 1.0;
+ in[1][1] = 1.0;
+ in[1][2] = 1.0;
+ in[1][3] = 0.0;
+
+ for (i = 0; i < DBGNO; i++) {
+ printf("Input %f %f %f %f\n",in[i][0], in[i][1], in[i][2], in[i][3]);
+ devi_devip((void *)&li, out, in[i]);
+ devip_devop((void *)&li, out, out);
+ devop_devo((void *)&li, out, out);
+ printf("Output %f %f %f %f\n\n",out[0], out[1], out[2], out[3]);
+ }
+ }
+#endif /* NEVER */
+
+#else /* !DEBUG_ONE */
+ /* Use helper function to do the hard work. */
+ if (li.verb) {
+ unsigned int ui;
+ int itotal;
+ for (itotal = 1, ui = 0; ui < li.in.chan; ui++, itotal *= clutPoints)
+ ;
+ li.total = itotal;
+ /* Allow for extra lookups due to ICM_CLUT_SET_APXLS */
+ for (itotal = 1, ui = 0; ui < li.in.chan; ui++, itotal *= (clutPoints-1))
+ ;
+ li.total += itotal;
+ li.count = 0;
+ printf(" 0%%"); fflush(stdout);
+ }
+ if (icmSetMultiLutTables(
+ 1,
+ &wo,
+ ICM_CLUT_SET_APXLS, /* Use aproximate least squares */
+ &li, /* Context */
+ li.in.h->colorSpace, /* Input color space */
+ li.out.h->colorSpace, /* Output color space */
+ devi_devip, /* Input transfer tables devi->devi' */
+ NULL, NULL, /* Use default input colorspace range */
+ devip_devop, /* devi' -> devo' transfer function */
+ NULL, NULL, /* Default output colorspace range */
+ devop_devo /* Output transfer tables, devo'->devo */
+ ) != 0) {
+ error("Setting 16 bit Lut failed: %d, %s",wr_icc->errc,wr_icc->err);
+ }
+ if (li.verb) {
+ printf("\n");
+ }
+#ifdef WARN_CLUT_CLIPPING
+ if (wr_icc->warnc)
+ warning("Values clipped in setting device link LUT");
+#endif /* WARN_CLUT_CLIPPING */
+
+#endif /* !DEBUG_ONE */
+
+ }
+
+ if (li.verb && li.wphack && li.wphacked == 0)
+ printf("Warning :- white point hack didn't trigger!\n");
+ if (li.verb && li.wphack && li.wphacked > 1)
+ printf("Warning :- white point hack trigger more than once! (%d)\n",li.wphacked);
+
+ if (li.verb)
+ printf("Writing out file\n");
+
+ /* Write the file out */
+ if ((rv = wr_icc->write(wr_icc,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icc->err);
+
+ wr_icc->del(wr_icc);
+ wr_fp->del(wr_fp);
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* Verify the given link, assuming all the options are the same */
+ } else {
+ icmFile *rd_fp;
+ icc *rd_icc;
+ icmLuBase *luo;
+
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int inn, outn; /* Number of components */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+
+ /* Lookup parameters */
+ icmLookupFunc func = icmFwd; /* Default */
+ icRenderingIntent intent = icmDefaultIntent; /* Default */
+ icmLookupOrder order = icmLuOrdNorm; /* Default */
+
+ int gc[MAX_CHAN]; /* Grid counter */
+ int vres = 8; //~~9
+ double imin[MAX_CHAN], imax[MAX_CHAN]; /* Range of input values */
+ double omin[MAX_CHAN], omax[MAX_CHAN]; /* Range of output values */
+ double in[MAX_CHAN]; /* Input value */
+ double ref[MAX_CHAN]; /* Reference output value */
+ double out[MAX_CHAN]; /* Output value */
+ double aerr, perr; /* Average, Peak error */
+ double nerr;
+ int count, total;
+ int pc, lastpc;
+ double pin[MAX_CHAN], pref[MAX_CHAN], pout[MAX_CHAN]; /* Peak error values */
+
+ if (li.verb)
+ printf("Setting up to verify the link\n");
+
+ /* Open up the link file for reading */
+ if ((rd_fp = new_icmFileStd_name(link_name,"r")) == NULL)
+ error ("Verify: Can't open file '%s'",link_name);
+
+ if ((rd_icc = new_icc()) == NULL)
+ error ("Verify: Creation of ICC object failed");
+
+ if ((rv = rd_icc->read(rd_icc,rd_fp,0)) != 0)
+ error ("%d, %s",rv,rd_icc->err);
+
+ /* Check that the profile is appropriate */
+ if (rd_icc->header->deviceClass != icSigLinkClass)
+ error("Profile isn't a device link profile");
+
+ /* Get a conversion object */
+ if ((luo = rd_icc->get_luobj(rd_icc, func, intent, icmSigDefaultData, order)) == NULL)
+ error ("%d, %s",rd_icc->errc, rd_icc->err);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ luo->spaces(luo, &ins, &inn, &outs, &outn, &alg, NULL, NULL, NULL, NULL);
+
+ if (alg != icmLutType)
+ error ("DeviceLink profile doesn't have Lut !");
+
+ /* Get the icm value ranges */
+ luo->get_ranges(luo, imin, imax, omin, omax);
+
+ /* Init the grid counter */
+ for (i = 0; i < inn; i++)
+ gc[i] = 0;
+
+ for (total = 1, i = 0; i < inn; i++, total *= vres)
+ ;
+
+ count = 0;
+ lastpc = 0;
+ nerr = aerr = perr = 0.0;
+ for(i = 0; i < inn; ) {
+ int j;
+ double err;
+
+ /* Create and scale input */
+ for (j = 0; j < inn; j++) {
+ in[j] = gc[j]/(vres-1.0);
+ in[j] = in[j] * (imax[j] - imin[j]) + imin[j];
+ }
+
+// printf("Input %f %f %f %f\n",in[0], in[1], in[2], in[3]);
+
+ /* Create the reference output value */
+ devi_devip((void *)&li, ref, in);
+ devip_devop((void *)&li, ref, ref);
+ devop_devo((void *)&li, ref, ref);
+
+ /* Lookup the icm output value */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icc->errc,rd_icc->err);
+
+// printf("Output %f %f %f %f\n",out[0], out[1], out[2], out[3]);
+// printf("Ref %f %f %f %f\n",ref[0], ref[1], ref[2], ref[3]);
+// printf("\n");
+
+ /* Unscale output and compare the results */
+ for (err = 0.0, j = 0; j < outn; j++) {
+ double o,r;
+ o = (out[j] - omin[j])/(omax[j] - omin[j]);
+ r = (ref[j] - omin[j])/(omax[j] - omin[j]);
+ err += (o - r) * (o - r);
+ }
+ err = sqrt(err);
+
+ aerr += err;
+ nerr++;
+ if (err > perr) {
+ perr = err;
+ for (j = 0; j < outn; j++) {
+ pin[j] = in[j];
+ pref[j] = ref[j];
+ pout[j] = out[j];
+ }
+ }
+
+ count++;
+ pc = (int)(count * 100.0/total + 0.5);
+ if (pc != lastpc) {
+ printf("%c%2d%%",cr_char,pc); fflush(stdout);
+ lastpc = pc;
+ }
+
+ /* Increment the grid counter */
+ for (i = 0; i < inn; i++) {
+ if (++gc[i] < vres)
+ break; /* No carry */
+ gc[i] = 0; /* Reset digit */
+ }
+ }
+
+ if (li.verb)
+ printf("Finished verfication\n");
+
+ printf("Average error = %f%%, peak error = %f%%\n",aerr * 100.0/nerr, perr * 100.0);
+ printf("Input %f %f %f %f\n",pin[0], pin[1], pin[2], pin[3]);
+ printf("Output %f %f %f %f\n",pout[0], pout[1], pout[2], pout[3]);
+ printf("Ref %f %f %f %f\n",pref[0], pref[1], pref[2], pref[3]);
+
+ luo->del(luo);
+ rd_icc->del(rd_icc);
+ rd_fp->del(rd_fp);
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ /* Cleanup source profiles and exit */
+
+ if (li.pcs2k != NULL) /* Free up PCS->K lookup for neutral hack */
+ li.pcs2k->del(li.pcs2k);
+
+ if (li.map != NULL)
+ li.map->del(li.map);
+ if (li.Kmap != NULL)
+ li.Kmap->del(li.Kmap);
+
+ if (li.abs_luo != NULL) { /* Free up abstract transform */
+ li.abs_luo->del(li.abs_luo);
+ li.abs_xicc->del(li.abs_xicc);
+ li.abs_icc->del(li.abs_icc);
+ li.abs_fp->del(li.abs_fp);
+ }
+
+ li.in.luo->del(li.in.luo);
+ li.in.x->del(li.in.x);
+ li.in.c->del(li.in.c);
+
+ if (li.out.b2aluo != NULL)
+ li.out.b2aluo->del(li.out.b2aluo);
+ li.out.luo->del(li.out.luo);
+ li.out.x->del(li.out.x);
+ li.out.c->del(li.out.c);
+
+ return 0;
+}
+
+
+
+
+
+
+
diff --git a/link/monoplot.c b/link/monoplot.c
new file mode 100644
index 0000000..781342b
--- /dev/null
+++ b/link/monoplot.c
@@ -0,0 +1,231 @@
+
+/*
+ * Argyll Color Management System
+ *
+ * Plot the monochrome axis transfer curve of a given link.
+ *
+ * Author: Graeme W. Gill
+ * Date: 01/26/8
+ * Version: 2.00
+ *
+ * Copyright 2001 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "icc.h"
+#include "plot.h"
+
+#define PRES 100
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+/* ---------------------------------------- */
+
+void usage(void) {
+ fprintf(stderr,"Plot monochrome axis of ICC link file, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"PCS->DEV ->link-> DEV->PCS\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: monoplot inprof linkprof outprof\n");
+ fprintf(stderr," -v verbose\n");
+ exit(1);
+}
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa, nfa; /* argument we're looking at */
+ int verb = 0;
+ char in_name[100];
+ char link_name[100];
+ char out_name[100];
+ icmFile *in_fp, *link_fp, *out_fp;
+ icc *in_icco, *link_icco, *out_icco;
+ icmLuBase *in_lu, *link_lu, *out_lu;
+ int rv = 0;
+
+ if (argc < 4)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ else if (argv[fa][1] == '?')
+ usage();
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(link_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(out_name,argv[fa++]);
+
+ /* Open up the files for reading */
+ if ((in_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((in_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ if ((rv = in_icco->read(in_icco,in_fp,0)) != 0)
+ error ("Read: %d, %s",rv,in_icco->err);
+
+
+ if ((link_fp = new_icmFileStd_name(link_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",link_name);
+
+ if ((link_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ if ((rv = link_icco->read(link_icco,link_fp,0)) != 0)
+ error ("Read: %d, %s",rv,link_icco->err);
+
+
+ if ((out_fp = new_icmFileStd_name(out_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",out_name);
+
+ if ((out_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ if ((rv = out_icco->read(out_icco,out_fp,0)) != 0)
+ error ("Read: %d, %s",rv,out_icco->err);
+
+
+ /* Get a PCS to Device conversion object */
+ if ((in_lu = in_icco->get_luobj(in_icco, icmBwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((in_lu = in_icco->get_luobj(in_icco, icmBwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",in_icco->errc, in_icco->err);
+ }
+
+ /* Get a Device to Device conversion object */
+ if ((link_lu = link_icco->get_luobj(link_icco, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",link_icco->errc, link_icco->err);
+
+ /* Get a Device to PCS conversion object */
+ if ((out_lu = out_icco->get_luobj(out_icco, icmFwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((out_lu = out_icco->get_luobj(out_icco, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",out_icco->errc, out_icco->err);
+ }
+
+ {
+ double xx[100], yy[PRES];
+ int i;
+ double tt[10];
+
+ for (i = 0; i < PRES; i++) {
+
+ tt[0] = 100.0 * i/(PRES-1.0);
+ tt[1] = tt[2] = 0.0;
+
+ xx[i] = tt[0];
+
+ if (verb)
+ printf(" %f %f %f -> ",tt[0],tt[1],tt[2]);
+
+ /* PCS to input device space */
+ if ((rv = in_lu->lookup(in_lu, tt, tt)) > 1)
+ error ("%d, %s",in_icco->errc,in_icco->err);
+
+
+ /* input device space to output device space */
+ if ((rv = link_lu->lookup(link_lu, tt, tt)) > 1)
+ error ("%d, %s",link_icco->errc,link_icco->err);
+
+ /* output device space to PCS */
+ if ((rv = out_lu->lookup(out_lu, tt, tt)) > 1)
+ error ("%d, %s",out_icco->errc,out_icco->err);
+
+ yy[i] = tt[0];
+
+ if (verb)
+ printf("%f %f %f\n",tt[0],tt[1],tt[2]);
+ }
+
+ if (do_plot(xx,yy,NULL,NULL,PRES) < 0)
+ error("do_plot returned -1!\n");
+
+ }
+
+ /* Done with lookup objects */
+ in_lu->del(in_lu);
+ link_lu->del(link_lu);
+ out_lu->del(out_lu);
+
+ in_icco->del(in_icco);
+ in_fp->del(in_fp);
+ link_icco->del(link_icco);
+ link_fp->del(link_fp);
+ out_icco->del(out_icco);
+ out_fp->del(out_fp);
+
+ return 0;
+}
+
+/* ------------------------------------------------ */
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"monoplot: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"monoplot: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/link/pathplot.c b/link/pathplot.c
new file mode 100644
index 0000000..fc12943
--- /dev/null
+++ b/link/pathplot.c
@@ -0,0 +1,281 @@
+
+/*
+ * Argyll Color Management System
+ *
+ * Plot the L in vs. L out for a path through the
+ * input device space, for a given link.
+ *
+ * We are assuming RGB device input space !!!!
+ *
+ * Author: Graeme W. Gill
+ * Date: 2002/1/28
+ * Version: 1.00
+ *
+ * Copyright 2002 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xicc.h"
+#include "plot.h"
+
+#define PRES 100
+
+static double start[13][4] = {
+ { 0.0, 0.0, 0.0, 0.0},
+ { 0.0, 0.0, 0.0, 0.0},
+ { 0.0, 0.0, 0.0, 0.0},
+ { 0.0, 0.0, 0.0, 0.0},
+ { 0.0, 0.0, 0.0, 0.0},
+ { 0.0, 0.0, 0.0, 0.0},
+
+ { 0.0, 0.0, 0.0, 0.0},
+
+ { 1.0, 0.0, 0.0, 0.0},
+ { 0.0, 1.0, 0.0, 0.0},
+ { 0.0, 0.0, 1.0, 0.0},
+ { 0.0, 1.0, 1.0, 0.0},
+ { 1.0, 0.0, 1.0, 0.0},
+ { 1.0, 1.0, 0.0, 0.0}
+};
+
+static double end[13][4] = {
+ { 1.0, 0.0, 0.0, 0.0},
+ { 0.0, 1.0, 0.0, 0.0},
+ { 0.0, 0.0, 1.0, 0.0},
+ { 0.0, 1.0, 1.0, 0.0},
+ { 1.0, 0.0, 1.0, 0.0},
+ { 1.0, 1.0, 0.0, 0.0},
+
+ { 1.0, 1.0, 1.0, 0.0},
+
+ { 1.0, 1.0, 1.0, 0.0},
+ { 1.0, 1.0, 1.0, 0.0},
+ { 1.0, 1.0, 1.0, 0.0},
+ { 1.0, 1.0, 1.0, 0.0},
+ { 1.0, 1.0, 1.0, 0.0},
+ { 1.0, 1.0, 1.0, 0.0}
+};
+
+static char *name[13] = {
+ "Black - Red", "Black - Green", "Black - Blue",
+ "Black - Cyan", "Black - Magenta", "Black - Yellow",
+ "Grey",
+ "Red - White", "Green - White", "Blue - White",
+ "Cyan - White", "Magenta - White", "Yellow - White",
+ };
+
+#define USE_JAB /* Assume CRT in (2), print out (0) */
+
+/* ---------------------------------------- */
+
+void usage(void) {
+ fprintf(stderr,"Plot device space path L in/out curve from an ICC link file, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: pathplot inprof linkprof outprof\n");
+ fprintf(stderr," -v verbose\n");
+ exit(1);
+}
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa, nfa; /* argument we're looking at */
+ int verb = 0;
+ char in_name[100];
+ char link_name[100];
+ char out_name[100];
+ icmFile *in_fp, *link_fp, *out_fp;
+ icc *in_icco, *link_icco, *out_icco;
+ xicc *in_xicco, *out_xicco;
+ icmLuBase *link_lu;
+ icxLuBase *in_lu, *out_lu;
+ icColorSpaceSignature pcsor; /* PCS to use */
+ icxViewCond ivc[1], ovc[1];
+ int rv = 0;
+
+ error_program = argv[0];
+
+ if (argc < 4)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ else if (argv[fa][1] == '?')
+ usage();
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(link_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(out_name,argv[fa++]);
+
+ /* Open up the files for reading */
+ if ((in_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((in_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ if ((rv = in_icco->read(in_icco,in_fp,0)) != 0)
+ error ("Read: %d, %s",rv,in_icco->err);
+
+ if ((in_xicco = new_xicc(in_icco)) == NULL)
+ error ("Creation of input profile xicc failed");
+
+
+ if ((link_fp = new_icmFileStd_name(link_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",link_name);
+
+ if ((link_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ if ((rv = link_icco->read(link_icco,link_fp,0)) != 0)
+ error ("Read: %d, %s",rv,link_icco->err);
+
+
+ if ((out_fp = new_icmFileStd_name(out_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",out_name);
+
+ if ((out_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ if ((rv = out_icco->read(out_icco,out_fp,0)) != 0)
+ error ("Read: %d, %s",rv,out_icco->err);
+
+ if ((out_xicco = new_xicc(out_icco)) == NULL)
+ error ("Creation of output profile xicc failed");
+
+
+#ifdef USE_JAB
+ pcsor = icxSigJabData; /* Use CIECAM as PCS */
+
+ if (xicc_enum_viewcond(in_xicco, ivc, -2, "mt", 0, NULL) == -999) /* Set input at monitor in typical */
+ error ("%d, %s",in_xicco->errc, in_xicco->err);
+
+ if (xicc_enum_viewcond(out_xicco, ovc, -2, "pp", 0, NULL) == -999) /* Set output at practical reflection print */
+ error ("%d, %s",out_xicco->errc, out_xicco->err);
+
+#else
+ pcsor = icSigLabData; /* Default use Lab as PCS */
+#endif /* !USE_JAB */
+
+ /* Device to PCS conversion object */
+ if ((in_lu = in_xicco->get_luobj(in_xicco, ICX_CLIP_NEAREST, icmFwd, icAbsoluteColorimetric, pcsor, icmLuOrdNorm, ivc, NULL)) == NULL) {
+ if ((in_lu = in_xicco->get_luobj(in_xicco, ICX_CLIP_NEAREST, icmBwd, icmDefaultIntent, pcsor, icmLuOrdNorm, ivc, NULL)) == NULL)
+ error ("%d, %s",in_xicco->errc, in_xicco->err);
+ }
+
+ /* Get a Device to Device conversion object */
+ if ((link_lu = link_icco->get_luobj(link_icco, icmFwd, icmDefaultIntent, pcsor, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",link_icco->errc, link_icco->err);
+
+ /* Get a Device to PCS conversion object */
+ if ((out_lu = out_xicco->get_luobj(out_xicco, ICX_CLIP_NEAREST, icmFwd, icAbsoluteColorimetric, pcsor, icmLuOrdNorm, ovc, NULL)) == NULL) {
+ if ((out_lu = out_xicco->get_luobj(out_xicco, ICX_CLIP_NEAREST, icmFwd, icmDefaultIntent, pcsor, icmLuOrdNorm, ovc, NULL)) == NULL)
+ error ("%d, %s",out_xicco->errc, out_xicco->err);
+ }
+
+ {
+ double xx[PRES], yy[PRES];
+ int k, i, j;
+ double tt[10], tt2[10];
+
+ for (k = 0; k < 13; k++) {
+ printf("Doing %s\n",name[k]);
+
+ for (i = 0; i < PRES; i++) {
+ double frac = i/(PRES-1.0);
+
+ for (j = 0; j < 4; j++)
+ tt[j] = (end[k][j] - start[k][j]) * frac + start[k][j];
+
+ if (verb)
+ printf(" %f %f %f -> ",tt[0],tt[1],tt[2]);
+
+ /* input device space to PCS */
+ if ((rv = in_lu->lookup(in_lu, tt2, tt)) > 1)
+ error ("%d, %s",in_icco->errc,in_icco->err);
+
+ xx[i] = tt2[0]; /* L value */
+
+ /* input device space to output device space */
+ if ((rv = link_lu->lookup(link_lu, tt, tt)) > 1)
+ error ("%d, %s",link_icco->errc,link_icco->err);
+
+ /* output device space to PCS */
+ if ((rv = out_lu->lookup(out_lu, tt, tt)) > 1)
+ error ("%d, %s",out_icco->errc,out_icco->err);
+
+ yy[i] = tt[0]; /* L value */
+
+ if (verb)
+ printf("%f %f %f\n",tt[0],tt[1],tt[2]);
+ }
+
+ if (do_plot(xx,yy,NULL,NULL,PRES) < 0)
+ error("do_plot returned -1!\n");
+ }
+
+ }
+
+ /* Done with lookup objects */
+ in_lu->del(in_lu);
+ link_lu->del(link_lu);
+ out_lu->del(out_lu);
+
+ in_icco->del(in_icco);
+ in_fp->del(in_fp);
+ link_icco->del(link_icco);
+ link_fp->del(link_fp);
+ out_icco->del(out_icco);
+ out_fp->del(out_fp);
+
+ return 0;
+}
+
diff --git a/log.txt b/log.txt
new file mode 100644
index 0000000..13f6bad
--- /dev/null
+++ b/log.txt
@@ -0,0 +1,3581 @@
+
+Argyll CMS change log
+=====================
+
+Version 1.5.1 (8th March 2013)
+-------------
+
+* Fix spectro/instlib.ksh and standalone instlib build.
+
+* Turned off debug plot on using FWA.
+
+* Changed link $(LINKFLAGS) location in link command line
+ Jambase to get latest gcc working.
+
+* Fixed new bug in matrix display profile creation that causes an
+ inacurate relative white point. This causes Photoshop to barf on
+ the profiles.
+
+* Added -m option to printcal.
+
+* Fix bug in webwin that causes crash.
+
+
+Version 1.5.0 (1st March 2013)
+-------------
+
+* Made SpectroScanT respond to enter key when reading
+ transparent samples.
+
+* Added signal handlers to dispwin to restore VideoLUT
+ in case of interrupt.
+
+* Added support for an FWA simulated instrument illuminant
+ separate to the illuminant used to compute XYZ values.
+ This (and the provision of appropriate illuminants and illuminant
+ aliases) allows simulation of ISO 13655:2009 M0, M1 and M2
+ measurements using any spectrometer that can take non-UV filtered
+ measurements. An optional argumen to the -f flag is used to select
+ this.
+
+* Increased stability of i1d3 refresh display measurements
+ by increasing integration time, and tweaking crossover
+ from frequency to period measurement.
+ Fixed bug that sometimes resulted in zero dark readings
+ due to round up of integration time that then exceeded
+ the valid maximum.
+
+* Added spotread interactive function 'f' to read out the
+ calibrate display refresh rate for instruments that have a refresh display
+ mode, as well as an 'F' function that measures the refresh rate for instruments
+ that support a refresh rate measurement function (colorimeters & spectrometers).
+
+* Added refresh rate measurement function to the i1pro
+ and ColorMunki Spectro's. Also added a set refresh rate
+ function, so that a refresh rate calibration can
+ be carried over between sessions, or set manually.
+
+* Bumped icclib to 2.15.
+ Change icc->read_tag() to only succeed if the tag type is
+ known, since the standard expectation of a non NULL
+ return type is that it is of a known type. Added new
+ method icc->read_tag_any() which will return a
+ icmSigUnknownType if the tag type is unknown.
+
+* The Display Type selection option -y in dispcal, dispread,
+ chartread, spotread & ccxxmake now lists installed
+ CCSS and CCMX files as a selction. The -X options
+ is no longer used to select installed CCSS files.
+ To make this work, the CCMX and CCSS files now have extra
+ fields to indicate the refresh mode, an optional list of
+ default UI selection characters, and (for CCMX files)
+ the base display type they apply over (CB-n). ccxxmake now
+ only allows Base Calibration display types to be selected.
+ The installer (oeminst) checks for the refresh mode
+ and base ID before installing CCMX and CCSS's.
+
+* Tweaked B2A least squares aproximation code to reduce
+ artefacts when used on badly behaved CMYK profiles.
+
+* Fixed targen so that use of -v1 (verify) doesn't cause it to fail
+ if ofps stats pass fails.
+
+* Tweaked CIECAM02 to imrove behaviour for extreme blue
+ colors, so that the hue doesn't swing too far towards the
+ cyan. This helps in the clipping behaviour from colorspaces
+ such as ProPhotoRGB.
+
+* Added some post table setting filtering to the B2A table
+ creation for out of gamut colors.
+
+* Made the input profile cLUT extra neutral axis extrapolation
+ points the default for colprof -u and non -u profiles. Fixed serious
+ bug in colprof -u :- the white point was being set incorrectly.
+ Changed -u algorithm to work similarly to -U scale :- it
+ sets the scale automatically. Relative colorimetric is therefore
+ hue matched to the white reference patch,
+ Removed colprof -un, as it seems unnecessary.
+ Added coloprof -uc, which clips cLUT colors over Y = 1
+ to white.
+ Modified matrix profile creation to match cLUT in terms
+ of how these options work.
+
+* Add verbose report if dispcal/dispread -Ibw is used.
+
+* Fixed bug in CRI computation - the TCS09 sample was incorrect.
+ (Thanks to Gabriele Guarnieri for noticing this).
+
+* The spyd2en, spyd4en and i1d3ccss tools have been combined into
+ and replaced by a single oeminst tool.
+
+* Fix problem with dispwin/dispcal/dispread -dweb and the latest
+ Safari browser.
+
+* Added optional fourth parameter to dispwin, dispcal, dispread, ccxxmake
+ -P option, that allows setting different horizontal and vertical
+ scalings of the test window.
+
+* Changed to a single ArgyllCMS.inf file for MSWin USB driver
+ installation. This eases instalation of more than a single
+ type of isntrument.
+ Tested on MS Windows 8 and updated installation instructions.
+
+* Added scanin support for ColorCheckerPassort
+ (Thanks to Ben Goren)
+
+* Enable the ColorHug by default, although it
+ isn't advertised as supported, since it doesn't
+ yet work reliably on OS X.
+
+* Updated OS X code to compile on 10.6 and 10.7
+ (64 bit compatible API used when compiling
+ on those platforms, including Cocoa for the test
+ patch window).
+
+* Added support for Quato Silver Haze 3 OEM i1d3
+
+* No longer using libusb for USB access, using native USB access instead.
+ MSWin uses the libusb-win32 kernel driver.
+ (This resolves the long standing issue of ArgyllCMS using
+ a custom version of libusb.)
+
+* Moved the usb setup files from libusb1 to
+ a new directory, usb.
+
+* Added support for X-Rite ColorMunki Smile colorimeter.
+
+* Changed udev file usb/55-Argyll.rules to eliminate
+ the test for /lib/udev/udev-acl as a condition of using
+ ACL_MANAGE, since I'm informed that it is deprecated
+ in recent distribution releases.
+
+* Deprecated -V flag (adaptive mode) in dispcal, dispread and ccxxmake,
+ since this is now the default. Flag will be ignored with a warning.
+ Added -ZA flag instead, to select non-adaptive integration time mode.
+
+* spotread -d flag is deprecated, and is now a synonym for the -e
+ flag, since it defaults to adaptive mode. Added -ZA flag instead, to
+ select non-adaptive integration time mode. Also addes -Zr and -ZR flags
+ to allow testing of the refresh mode overrides.
+
+* Migrated ArgyllCMS specific application runtime files (such as instrument
+ blobs, calibration state & calibration files) to an "ArgyllCMS"
+ subdirectory rather than the generic "color" directory.
+ On OS X also moved data files to below the "Application Support" sub
+ directory. The old locations will be used as a fallback.
+
+* Fix potential array bounds violation in icc/icc.c for malformed
+ cLUT profiles with zero input channels. Bump to icclib to V2.14
+
+* Fixed bug in cgats/pars.c that caused a parsing failure
+ with the ARM compiler.
+
+* Modified colprof so that a -rr smoothing parameter is now
+ passed to the shaper fitting of shaper/matrix.
+
+* Reduced regularisation weight of order 0 & 1 curve shape parameters
+ for matrix and cLUT based profiles, as well as converting it to
+ be a two pass matrix then matrix+curves approach, making for a more
+ reliable and better fit for some devices. This may improve matrix input profiles.
+
+* Added partial i1pro Rev E (i1pro2) support.
+ Uses RevE measurement mode, and does wavelength calibration.
+ Uses RevE (internal) stray light reduction, and black level temperature
+ compensation. The only Rev E feature not currently supported is U.V.
+ measurement, which would improve the accuracy of FWA compensation.
+ Rev E driver can be disabled and the legacy driver
+ mode used by setting the ARGYLL_DISABLE_I1PRO2_DRIVER environment variable.
+
+* Changed ColorMunki adaptive mode to avoid high gain mode,
+ so as to give more consistent and longer integration
+ times for low levels. Added black level temperature compensation.
+
+* Changed i1pro adaptive mode to avoid high gain mode,
+ so as to give more consistent and longer integration
+ times for low light levels.
+
+* Added automatic adjustment of patch reading delay
+ for i1d3, so that a more conservative (longer) default value (200 msec)
+ can be used without impacting i1d3 speed.
+ Also added environment variable ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS
+ that can set a different minimum update delay.
+
+* Fixed a bug introduced in V1.3.6 that stops the dtp41 from being initialised properly.
+
+* Added warning message to colprof if an additive device (ie. RGB)
+ has an ink limit set that will affect the white point.
+
+* Modified printtarg so as to output CMY colorspace charts in CMYK PS, EPS & TIFF
+ files by default rather than Device N, and to add an option (-o) to select
+ CMY as inverted RGB, or CMY Device N as an option
+
+* Add explicity icoms error message when there are no instruments to be found.
+
+* Updated ColorHug PCI VID & PID
+
+* Change ColorHug driver to not do Raw mode post scale if
+ firmware is >= 1.1.5
+
+* Fixed regression with Spectrolino not taking filter options.
+
+* Added doco for QPcard_201, and ref. files for QPcar_202
+
+* Modify numlib/numsup so that error() is marked noreturn,
+ to shut up bogus compiler warnings.
+
+* Fix problem in libusb1 for MSWIN libusb0 devices not
+ being able to be opened with more than one instance of
+ usb open (This bug is not relevant to ArgyllCMS, but is to libinst use).
+
+* For Spyder, emit a warning rather than error if the feature bits
+ are missing for calibration tables.
+
+* Added an introduction to color management document.
+
+* Change libjpg to libjpeg in Jamtop & jpg/Jamfile
+ so it picks up system libraries, and fix system library link flag.
+
+* Fix bug in profile B2A table construction that
+ sometimes created reversals in black clipping behaviour.
+
+* For i1d3, make transition to longer re-measure integration
+ time smooth and progressive. Changed debugging so that reading
+ details are printed if debug >= 6
+
+* Fix bug in gamut/gammap.c - freeing not allocated memory
+ if no nearpoint mapping was being done.
+
+* Update icclib to address robustness against malformed profiles.
+
+* Various API changes to the instlib to make it more
+ self contained and flexible:
+
+ The ipatch structure has been changed to remove the unused/unsupported
+ Lab[] value, and merge the XYZ[] and aXYZ[] values.
+ There is a new type indicator "mtype" to track what sort of
+ measurement it is, and (implicitly) what units the measurement is in.
+
+ Spectral readings have always been clamped to be +ve in past
+ release of Argyll, but this has now been removed, because
+ it has a detrimetal effect on dark XYZ readings, limiting the
+ minimum reading possible. By default now, read_sample allows
+ possibly -ve XYZ values (which will aid the accuracy
+ of averaged dark readings) and has an option flag to
+ clamp XYZ values to be +ve for compatibility with previous behaviour.
+
+ To avoid enumerating USB devices multiple times, the list of
+ available instruments now uses an icompaths object, and a
+ particular icompath is handed to new_inst().
+
+ An error, debug and verbose logging object 'a1log' (declared
+ in numlib/numsup.h) is now used to control and capture
+ informational output. This is handed to new_icompaths()
+ as well as new_inst(); Existing error(), warning() and
+ verbose() function calls now funnel into the default
+ global a1log object 'g_log'.
+
+ instlib user interaction is now funnelled through a callback
+ function (uicallback) rather than interacting with stdout and
+ command line input itself. The implementation of the callback
+ function and the default calibration setup handler for Argyll
+ command line applications is now in a separate library instappsup.c.
+
+ There is now an asynchronous callback for indicating events
+ such as the instrument switch being pressed, or the
+ instrument measurement configuration being changed (ie.
+ sensor position, ambient filter). Only some instruments
+ will use this. This is called from a thread.
+
+ inst_capability and inst_mode are now one and the same: inst_mode.
+ The IMODETST macro should be used for testing a capability or mode,
+ but because a specific mode is represented by a combinations of
+ bits, this test is not definitive, and should also be verified with
+ the check_mode() function to be sure it is valid, and won't be
+ rejected by set_mode();
+
+ inst_emis_disptype, inst_emis_disptypem, inst_ccmx and inst_ccss
+ have moved to cap2 as inst2_disptype, inst2_disptypem, inst2_ccmx
+ and inst2_ccss respectively.
+
+ The capabilities2() method has been removed, and capabilities() now
+ returns inst_mode capability, inst2_capability and new placeholder
+ inst3_capability flags.
+
+ All the inst2_cal_* enumerations have been replaced by the new
+ get_n_a_cals() call, which gives fuller information about what
+ calibrations are needed and available for the current measurement mode.
+
+ needs_calibration() now retuns a mask of calibrations needed.
+ calibrate() now can be given one of three pseudo-calibrations,
+ and returns a mask of remaining calibrations.
+
+ The inst_mode_emis_disp and inst_mode_emis_proj modes have been removed
+ and replaced with a general emissive mode, with a "tele" modifier
+ to indicate projector mode (there are also corresponding changes in
+ the calibration types and conditions, replacing "disp" and "proj" with
+ "emis"). Adaptive measurement mode used as default
+ for emmissive measurement. inst_mode_emis_spot and inst_mode_emis_tele can
+ be used as replacements, with the inst_mode_emis_nonadaptive
+ option used to get the non-adaptive display measurement mode
+ previously triggered by inst_mode_emis_disp/proj in those instances
+ where it is wanted and the device supports it. (i1pro, colormunki spectro.)
+
+ By default display refresh synchronized calibration and measurement
+ is selected in tandem with the display type selector
+ (indicated in inst_disptypesel). Where supported, this refresh
+ mode can now be overridden using the inst_mode_emis_refresh_ovd and
+ inst_mode_emis_norefresh_ovd modes.
+
+ Changed get_status(inst_stat_sensmode) to a new
+ function meas_config(), and changed the values returned to be the
+ valid measurement modes or calibration conditions for the current
+ instrument physical configuration.
+ This allows the application to be sensitive to what measurement
+ modes are available with things like the Colormunki sensor position,
+ and the i1d3 ambient adapter position.
+
+ A new function get_ref_rate() has been added to make the measured
+ display refresh rate available.
+
+ get_opt_details(inst_optdet_disptypesel) has been replaced by get_disptypesel();
+
+ Commbined set_opt_mode() and get_status() into get_set_opt(),
+ and combined inst_opt_mode and inst_status_type into inst_opt_type;
+
+ col_cal_spec_set() now only sets the CCSS, not the observer.
+ The observer can be set by a call to get_set_opt(inst_opt_set_ccss_obs);
+
+
+
+Version 1.4.0 (20th April 2012)
+-------------
+
+* Modified spectro/ccxxmake so that a colorimeter can be used
+ as a reference to make ccmx files if two .ti3 files are used.
+ Added ref/ccxx.ti1 as convenient way of creating ccmx .ti3 files.
+
+* Added dither/screening support for 8 bit output of
+ render, and then made it available in target/printtarg -D switch.
+
+* Added JPEG file support to imdi/cctiff, xicc/tiffgamut and xicc/extracticc.
+ ICC profiles embedded in JPEG files can now be used anywhere a TIFF
+ file with embedded ICC profile can be used as a source of an ICC profile.
+ This makes it more convenient to color correct photographs.
+
+* Fixed memory leaks in usbio.c, xdg_bds.c & conv.c
+
+* Fixed double memory free bug in icc/icc.c when
+ iccdump'ing a profile that has a duplicate tag.
+
+* Changed license of xicc/ccmx.[ch] to GPL2+.
+
+* Removed dispcal -K option, since it is not
+ needed with more graceful handling of no
+ VideoLUT access.
+
+* Made display calibration and profile making
+ deal with displays without hardware calibration
+ support (VideoLUT support) more graceful.
+ Added tutorial section covering this.
+
+* Added option to dispwin/dispcal/dispread/ccxxmake to
+ redirect the test patches to a web browser via
+ a local web server. This augments Argyll's long standing
+ local and remote display capability.
+
+* Fixed bug in spectro/i1d3.c which results in NAN if a
+ low level readings drops to zero at a particular time.
+ Improved refresh rate calibration accuracy. Fixed bugs
+ in adaptive measurement logic that caused a channel to
+ be pre-measured when it shouldn't. This seems to noticeably
+ improve repeatability on refresh displays.
+
+* Fixed bug in ucmm/jcnf where it was failing to locate
+ the correct profile for a display.
+
+* Fix bugs in ColorMunki Transmissive measurement mode
+ calibration.
+
+Version 1.3.7 (26 March 2012)
+-------------
+
+* Fix regression in Spyder support - ccmx files were not
+ being handled (bug introduced in 1.3.6).
+
+* Fix packaging problem - Spyder4 MSWin .inf file was missing.
+
+* Change dispwin so that it will install a profile when
+ there is no access to the display VideoLUT if the profile
+ has no vcgt.
+
+Version 1.3.6 (19th March 2012)
+-------------
+
+* Experimental ColorHug support is compiled in, but is disabled
+ unless the environment variable "ENABLE_COLORHUG" is set.
+ (The ColorHug currently doesn't seem to work reliably
+ accross all platforms Argyll supports).
+
+* Modified spectro/hidio.c for OS X so that it only
+ attaches run loop when an hid call is made,
+ to make the SW more GUI friendly.
+
+* Fixed bug in Spyder 2 driver, where aborting a reading
+ (ie. in interactive dispcal), leaves hardware out of sync
+ with driver, leading to a bad next reading.
+
+* Reworked i1disp driver slightly to improve repeatability
+ when in CRT mode.
+
+* Added a -V option to spotread to allow tracking
+ reading consistency.
+
+* Tweaked i1d3 integration times, and added refresh
+ period calibration to the refresh display mode.
+ Refresh display measurement times are double
+ non-refresh displays.
+
+* Added Spyder4 support. Note the need for sptd4en.
+ Speeded up Spyder on brighter colors. Hopefully
+ this doesn't affect accuracy.
+
+* Changed ccxxmake to create default .ccss with just
+ RGBW, and not to weight W. This may give better
+ matching. Made corresponding change to CCMX, giving
+ the white patch 1/4 weighting of sum of all other patches.
+
+* Changed display selection (-y flag) to be instrument
+ specific. This is to support the Spyder4 and ColorHug.
+
+* Improved i1d3 period measurement logic to improve
+ measurement speed and accuracy for dark colors.
+
+* Removed Linux serial port filtering code for USB serial
+ ports, since it may interfere with other devices.
+
+* Fixed OS X and Linux profile installation so that if you run
+ dispwin -I as root (ie. sudo), the profile is still installed
+ as the underlying user, not to the root user location.
+
+* Fixed bug in black point finding code in xicc/xicc.c that
+ affected xicclu.
+
+* Fixed txt2ti3 to cope with inputs that don't have any device values.
+ This is useful for dealing with input chart reference values.
+
+* Fixed applycal so that it applies calibration to both A2B and B2A tables,
+ to preserve softproofing.
+
+* Changed ICC unknown manufracturer and model Tags to value 0, rather than "????".
+
+* Fixed timeout in SpectroScanT reference transmission measurement.
+
+* Switched ucmm over to using spectro/xdg_bds code,
+ to solve problem with multiple paths in
+ XDG_*_DIRS. Changed xdg_bds and aglob code to
+ an "MIT" license, consistent with all the ucmm code.
+
+* Made DTRP94 driver ignore with a warning any
+ NEEDS_OFFSET_DRIFT_CAL_ERR after a full reset.
+ It seems that occasionally a few instruments do this,
+ and X-Rite don't appear to be prepared to treat this
+ as an instrument fault.
+
+* Added support for Datacolor SpyderCheckr (Thanks to Jos Pereira).
+
+* Improved the ability of spyd2en to cope with slightly
+ different setup.exe formats.
+
+* Made sure that dispcal and dispread now error if
+ reading of ccmx or ccss files fail.
+
+* Add support for NEC SpectraSensor Pro version of the i1d3.
+
+* Add smoothing control flag to printcal.
+
+* Fix bug in ccxxmake with regard to -I and -T options.
+
+* Fix bug in ccxxmake that stops the test patch from being scaled
+ properly using -P
+
+* Supress TIFF open message errors better when attempting to
+ open an ICC profile embedded within a TIFF file.
+
+Version 1.3.5 (24th October 2011)
+-------------
+
+* Add support for the OEM version of the i1d3.
+
+* Fix bug in dispread where spectral instrument readings weren't being
+ normalized to the display white Y when they were supposed to be.
+
+* Kill i1ProfileTray.exe process if unable to open i1d3 on MSWin.
+
+* Tweak gamut mapping to improve dark area mapping, non-monotonic
+ profile inversion, and contrast preservation to small gamut.
+
+* Fix bug that stopped ccxxmake being able to make ccmx's.
+ (Unable to use colorimeter due to "instrument doesn't support spectral or CCSS"
+ error).
+
+* Fix bug (crash) that affects ColorMunki design/photo display measurement.
+ This also stops it restoring a calibration (-N flag).
+
+* Fix DTP20 chart printing - TID was sometimes incomplete.
+ This shows up on a 4x6 chart.
+
+* Changed DTP20 chart to use a much smaller and ligher row label
+ to try and avoid mis-reads.
+
+Version 1.3.4 (31 August 2011)
+-------------
+
+* Fix gamut code to ignore setting primary/secondary cusps that
+ are unlikely to be true. This avoids buggy gamut mapping
+ behaviour for gamuts that are very small and odd shaped.
+ Tweak saturation intent very slightly to improved hue consistency.
+
+* Changed Linux USB code to avoid doing a set_configuration
+ if possible, since the USB driver does this by default.
+ This then avoids triggering a bug in the Spyder2, which
+ allows it to work on Linux version without the reset_ep fix,
+ and may also allow the Spyder to work better with USB hubs.
+
+* Added support for the X-Rite i1 Display Pro and ColorMunki Display
+ colorimeters. As part of this, added support for CCSS calibration
+ files for the instruments and added CCSS support to ccxxmake (renamed from ccmxmake).
+ Provide new tool i1d3ccss to translating and installing CCSS files as well as
+ the manufacturers calibration files for these instruments.
+ Added non-default observer support for these instruments too.
+
+* Fix all colorimeters so that the ccmx matrix is used only
+ for non-Ambient measurements.
+
+* Change printtarg for DTP20 to allow for variable patch size.
+ Note that patch length must me 6.5, 7, 10, 12.5 or 13 mm.
+
+* Changed dummy display matrix table to have channels rotated
+ rather than R & G swapped, to make it more obvious.
+
+* Added option to colprof to allow setting the default profile
+ rendering intent.
+
+* Fix bug in spectro/average.c - field match check index was wrong variable.
+
+* Fix bug in xicc/xlut.c that caused bad reverse lookup
+ values at some clipped grid points.
+
+* Increase number of re-seeding retries in target/ofps.c,
+ and fix bug that caused failure to finish rather than
+ error.
+
+* Enhanced spectro/fakeread so that it will process a .ti3
+ file that has been renamed to .ti1.
+
+* Fix bug in matrix input profile white point selection,
+ + add in slight neutral bias code used in clut profiles.
+
+* New profcheck -I wasn't working - fix option parsing.
+
+Version 1.3.3 (12th May 2011)
+-------------
+
+* Added -I relative colorimetric intent flags to spectro/fakeread
+ and profile/profcheck, for special use.
+
+* Fixed compiler dependant bug in Eye-One pro and (posibly) Munki
+ high res. spectral wavelength calculation.
+
+* Add support for install variables DESTDIR and PREFIX
+ in Jamtop. These can be set on the command line using "jam -s"
+
+* Add ref/linear.cal to distribution.
+
+* Added targen -N parameter to allow adjustment of neutral axis
+ patch density emphasis. The default effect has also been
+ increased. Note this is only effective when perceptual distributions
+ are created, or the defaul OFPS with a high level of Adaptation is
+ used. This will be most effective when a pre-conditioning profile
+ is used. This may reduce the number of patches needed for a given
+ quality profile, or increase the quality for a given number of
+ patches. This should improve the result without needing to add
+ explicit grey test patches.
+
+* Added spectro/instlib.ksh script to assemble all the files needed
+ for a standalone instrument library. Changed licence to GPLv2 for
+ the files included in the instlib.zip file that is thus created.
+ Can be built using the included Makefile, once libusb-1.0A has
+ been built.
+
+* Fix Jambase so that recent MingW compilers don't need extra .dll's
+
+* Change Linux serial code to test ports using O_NONBLOCK
+
+* Modify xspect & illumread to improve realism of UV spectrum estimation.
+
+* Fixed profile/txt2ti3 so that a sample name that looks like an integer
+ is treated as text. (Fixes problem with latest ProfileMaker file).
+
+* Added LCh option to spotread.
+
+* Fixed numerical issue in scanin/scanrd.c, where large input rasters
+ would cause fitting to fail.
+
+* Modified colprof input chart white patch detection to slightly
+ favour patches that are close to D50 neutral.
+
+* Scaled XYZ PCS A2B profile deviation to improve default
+ smoothness.
+
+* Change Make cLUT input -u black & white point extrapolation
+ to use gamma curve + one order shaper, and increase these
+ extra points weights.
+
+* Change black point search weighting to give a*b* error less
+ weight, so that devices narow gamuts due to strange inks
+ get a better chance at a reasonable black point.
+
+* Added -Z option to colprof, to allow setting ICC attribute flags.
+
+* Attempted to (yet again) fix the shortcoming of cam02 blue behaviour.
+ This may well improve the purity and color of blue gamut mapping.
+ Also fixed problem with inversion not matching the forward conversion,
+ resulting in gamut mapped cLUT tables white points not
+ being exact, and resulted in non perfect device values for white.
+
+* Add code to temporarily disable X-Rite's new Daemon drivers on
+ OS X, for ColorMunki and EyeOne. The Argyll utilities either need
+ to be run as root, or the X-Rite Daeomon .plist's need to
+ be changed to run as the user.
+
+* Added -R flag to colprof, which restricts the values of the white, black
+ and primaryies to have Y <= 1 and +ve, respectively. This can aid
+ compatibility with other programs.
+
+* Fixed typo in spectro/inst.h that prevented flash measurement mode from
+ working.
+
+* Replaced spectro/average with a new version that is more
+ general. Merging and Averaging are are now separate operations.
+
+* Fixed bug in printcal - it wasn't dealing with spectral only files.
+
+* Added extra verbose output to printcal in which it
+ computes an ideal power-like value to apply to the test chart values
+ in targen. Modified targen to use power-like function, to avoid
+ issues with small values with real power curve.
+
+* Reduced printcal data point smoothing slightly, to improve
+ accuracy.
+
+* Fix bug in profile/printcal where the white point device
+ value wasn't beeing computed as the average of all the
+ white patches. Tightened up definition of white patch
+ to avoid targen -p type test charts slipping non-white
+ patches into white average. Made sort of device value consistent.
+
+* Modify the way that XYZ cLUT B2A tables are indexed, so that
+ the white point is at the top corner of the grid. This should
+ make better use of the cLUT, as well as improving the accuracy
+ of the inverse white mapping. [Should solve Photoshop CS4/CS5
+ complaining that XYZ LUT profiles are 'defective'.]
+
+* Added option in xicc/xicclu to plot an arbitrary slice.
+
+* Expand the number of i1 Display OEM devices that can be used.
+
+* Added some patches to help compile on FreeBSD.
+ (Thanks to Simon Walton)
+
+* Added offset parameter to spectro/synthcal, to allow generation of
+ inverted ramps.
+
+* Added another intent, "pa", Perceptual Appearance, which is the
+ same as perceptual except that the grey axes are not forced into
+ alignment, allowing the appearance parameters to have full affect,
+ including altering the chromatic mapping.
+
+* txt2ti3 wasn't creating an iRGB colorspace file for output device
+ RGB files. This can cause warnings and failurs when mixed with
+ other iRGB tool sequences. Also fixed fakeread grey fudge to recognise
+ both RGB and iRGB.
+
+* Added pathological case fix for target/ofps where the ink
+ limit == di-2. For CMYK this needs slightly more than
+ 32 bits of mask. Fix forces limit to be slightly less than
+ di-2.
+
+* targen was failing to proceed when fixed points happened
+ to be numerically just over the total ink limit, and ofps
+ then got stumped in adding them. Now clip them before
+ ofps tries to add them.
+
+* Added more navigation options for chartread patch by patch mode.
+
+* Fixed bug in "chartread -r -H" that caused resume of i1Pro high res
+ to fail with "The resumed spectral type seems to have changed"
+ due to a floating point mismatch.
+
+* Modified profcheck so that it prints patch location if it is
+ present in the .ti3 file.
+
+* Made doubly sure that DTP94 has offset drift compensation on.
+
+* Changed dispcal and dispread -K option to -J. Added -K option to dispcal as
+ an alternate way of profiling a calibrated display, and also added a -K
+ option to dispcal. These options may be useful for displays that
+ don't have VideoLUTs or that (very strangely) have VideoLUTs with lower
+ precision entries than the frame buffer.
+
+* Increased ColorMunki emissive auto scaling target "over" margine
+ from 5% to 10% to allow more room for instrument drift.
+
+* Add more runtime debugging output in dispsup code (dispcal, dispread etc.)
+
+* Fix bug in winusb + i1Display, where dark CRT measurements timeout.
+
+Version 1.3.2 (4th November 2010)
+-------------
+
+* Turn off debugging that was accidentally left on in FWA code.
+ Add gcc 3.3 PPC optimizer bug workaround to FWA code in xicc/xspect.c
+
+* Change shaper/matrix profile back to using power curve as 0th
+ order shape. Improve it with input & output offsets and
+ straight segment at zero. Make cLUT input -u black & white
+ point extrapolation use pure shaper curves with special tweaks.
+
+* Increase dispcal native white target weighting from 10 to 50
+ to encourage white to be device 1.0,1.0,1.0 more strongly.
+
+Version 1.3.1 (26th October 2010)
+-------------
+
+* Tightened up scanin -ca option parsing to reduce chances of false
+ trigger.
+
+* Added synthetic device white/black point for input cLUT profiles
+ where the -u flag is being used. Particularly for Lab PCS, this can
+ improve the reasonableness of the extrapolation along the neutral
+ axis. Added -un flag option to disable this.
+
+* Changed shaper/matrix profiles so that they use pure shaper curves
+ rather than base gamma + shapers, as this seems to be a better fit
+ for real device behaviour.
+
+* Fixed MSWIN Vista/Win7 problem where having Task Manager running
+ would stop display test window updating. Also fixed plot library to
+ avid the same problem.
+
+* Added -i (input) option to profile/txt2ti3, as well as making
+ device value scaling be guessed from the data range.
+
+* Fixed problem in MSWin .inf files not copying libusb .dll to system
+ directories.
+
+* Swapped dispwin -E and -D flags, to make -D debug consistent
+ throughout tools.
+
+* Changed the ARGYLL_NOT_INTERACTIVE mode so that all return and line
+ feed characters are ignored, so that they can be used freely to
+ flush stdin without triggering anything.
+
+* Added ref/ECI2002.ti1, so ECI2002 test values can be printed using
+ printtarg.
+
+* Added -L option to chartread, to save both XYZ and Lab values.
+
+* Fixed endless loop problem with chartread -r -p on fully read chart.
+
+* Increase display patch color change to instrument measurement
+ settling time from 60 to 200 msec, to allow for very slow
+ MVA and PVA LCD displays.
+
+* Fixed problem in Jambase that stops MSWin MingW compiling.
+
+* Added -S option to chartread, that suppresses wrong strip and unexpected value warnings.
+
+* Fix dispcal and spotread so that color temperature takes into account any non-standard
+ observer (ie. the color temperature is the closest point on the spectrum locus
+ as determined by the chosen observers interpretation of the Plancian or
+ daylight spectrum.)
+
+* Fix bug in libusb1 triggered on systems that support bulk continuation (Linux)
+
+* Added 1964_10c observer to spectro/dispcal, to better allow comparison to
+ the default numbers.
+
+* Added recognition for Huey built into Lenovo W series Laptops.
+
+* Fixed chartread/dispsup/spotread etc. so that -N isn't fatal if the instrument
+ doesn't support it.
+
+* Fixed dispcal to disable black & white drift tracking during interactive adjustment.
+
+* Added -s option to ccmxmake to allow the number of test patches to be set.
+
+
+Version 1.3.0 (8th September 2010)
+-------------
+
+* Added option to dispread to save non-normalised to Y=100 values.
+ Fixed colprof to normalise display spectral values that haven't been normalised.
+ Fixed profcheck to normalise display spectral values that haven't been normalised.
+ Fixed verify to scale white point reference to be larger than largest Y value
+ being compared.
+
+* Added option to dispcal and dispread that attempts to counteract instrument
+ black drift and display white drift (-I option). This may help with
+ instruments that haven't properly acclimatised to the measurement location,
+ and LCD displays that also take some time to stabilise.
+
+* Added option to dispcal to allow specifying a non 1931 2 degree observer
+ if a spectrometer is being used.
+
+* Added new utility spectro/ccmxmake, which makes Colorimeter Correction
+ Matrices for a particular Colorimeter/Display combination, using a
+ Spectrometer as a reference. The resulting .ccmx file can then be used
+ with spotread/dispcal/dispread (-X option) to improve the accuracy of
+ the colorimeter on that particular display.
+
+* Fixed bug in spotread's handling of emsissive measurements.
+ If the XYZ was computed from spectral, it was using a D50 white
+ instead of no white reference.
+
+* Fixed bug in i1pro normal resolution wavelength calibration,
+ introduced in V1.2.0.
+
+* Fixed bug in the way illumread displays available instruments.
+
+* Changed libusb V1.0 name to libusb-1.0A, so as not to clash
+ with any official but different libubs V1.0 installation.
+ [This may necessitate re-installing device drivers on MSWin.]
+
+* Added support for HP DreamColor version of the i1 display.
+
+* Fix problem with ARGYLL_NOT_INTERACTIVE - reading from instruments
+ was not actually possible, because polling for input was disabled.
+
+* Adjust ColorMunki dark threshold to reduce misread reports.
+ Add inconsitent data to debug output.
+ Fix bug in adaptive mode - the integration time was sometimes
+ too short.
+ Set adapative emissive target at 95% to allow a little more
+ margin to saturation.
+
+* Fix some minor compiler warnings.
+
+* Added direction indicators to xy values in dispcal interactive
+ monitor adjustments.
+
+Version 1.2.1 (9 August 2010)
+-------------
+
+* Fix problem with ColorMunki reporting erroneous inconsistent
+ measurement errors. This shows up on display calibration.
+
+* Fix bug in CIECAM02 viewing condition settings :- the enumerated
+ conditions after "mt" are displaced by 1. (ie. "mt" is really "pc",
+ "mb" is "mt", "md" is "mb" etc.) Added option -c:sn for auto
+ surround from the Lv parameter (-c:l).
+
+* Add option to illumread to average several readings.
+
+Version 1.2.0 (30 July 2010)
+-------------
+
+* Added EV calculation to spotread -a
+
+* Updates included libtiff to V3.9.4
+
+* Modified colprof -p to allow different abstract profiles to be applied
+ for each intent.
+
+* Added -I option (imitation) to printcal, so that an existing devices
+ response can be set as a target.
+
+* Fixed scale by 100 bug in spec2cie -f spectral output values.
+
+* Fixed memory allocation bug in spectro/fakeread.c.
+ (Also fix memory allocation leak in xicc/mpp.c)
+
+* Fixed bug in target/targen where .mpp pre-conditioning profiles
+ ink limits wern't being handled properly.
+
+* Reduced i1pro high res mode from 750 to 740 nm because of
+ unreliable sensor values.
+
+* Added support for filter in chartread.
+
+* Re-worked gamut mapping to improve perceptual intent saturation
+ levels, as well as improve highlight and shadow contrast.
+ Added fine tuning to improve both smoothness and the precision
+ with which the source is mapped to the destination.
+
+* Fixed bug in installing profile on MSWin Vista/Win 7 in system scope.
+
+* Fixed bug in xsp_Tdensity() table values.
+
+* Enable -C option in dispcal.
+
+* Increase target/ofps.c vertex intersection retries from 10 to 40
+ to give it a better chance of working with difficult profiles.
+
+* Fixed printcal -D problem.
+
+* Fixed average spectral output problems.
+
+* Changed i1pro & Munki driver to save instrument calibration
+ file in $XDG_CACHE_HOME/color/ (or the XDG fallback)
+ rather than in the directory that the executable
+ exists in. Also changed spyd2en to save the PLD pattern
+ in the $XDG_DATA_HOME or $XDG_DATA_DIRS.
+
+* Fixed bug in plot that shows up on XP+, where the window
+ isn't dismissed by the first keystroke, but only after it
+ has been moved or resized.
+
+* Added illumread, which allows measuring an illuminant and
+ estimating its UV content, for better accuracy with
+ FWA compensation.
+
+* Use a modified/forked version of libusb V1.0, that supports Win2K
+ (libusb0.sys) back end by default. Supports 64 but MSWin
+ using a combination of WinUSB.sys and ptlibusb0.sys.
+ [ The HCFR does not work on Win 64 bit though, due to its
+ buggy USB implementation. ]
+
+ NOTE that the included version of Libusb V1 has been carefully
+ tested with all supported instruments on all supported platforms,
+ and includes many bug fixes needed for correct functioning.
+ While bug fixes have been fed upstream, not all have been
+ adopted. In particular there is a nasty race condition
+ that has not, and may never be fixed upstream, as well as
+ missing critical functionality (clearep()).
+
+* Changed CMYK black point to be neutral, rather than the darkest
+ point in the same direction and K only. This may wreck
+ K only to black point matching, but it will stop printers
+ with funny colored K ink from messing up the black point.
+
+* Make Lacie Blue Eye colorimeter appear as an i1display.
+
+* Improved i1pro matching to Original Manufacturers Driver
+ (see doc/i1proDriver.html).
+
+* Improved i1pro/ColorMunki patch recognition for beter uniformity.
+
+* Fixed bug in ColorMunki driver scan mode calibration
+ when instrument is more sensitive than usual.
+
+* Fix usage of dispread, -V option was missing.
+
+* Fix plot bug in printcal
+
+Version 1.1.1 (21 February 2010)
+-------------
+
+* Altered xpsect FWA code to reduce overshoot artefacts due to filetering.
+
+* Updated ref/CMP_Digital_Target-3.cht as it seems that the reference
+ chart has columns labeled "2A - 2D" rather than the "AA - AD" that
+ is actually printed on the chart...
+
+* Changed dispcal and dispread so that a request for projector
+ mode falls back to display mode if the instrument doesn't
+ support a projector mode.
+
+* Changed printcal so that it will create .AMP file with more
+ than 4 channels.
+ Also fixed up plotting to plot up to 10 channels.
+
+* Renamed the following tools:
+
+ cb2cgats -> cb2ti3
+ kodak2cgats -> kodak2ti3
+ logo2cgats -> txt2ti3
+ splitcgats -> splitti3
+ mpprof -> mppprof
+
+* Modified scanin so that it ignores any alpha channels
+ in the input .tif file.
+
+* Change spotread so that it takes spectral readings by
+ default so that FWA comensation readings can be used.
+
+* Changed link/collink to apply Y to L* curve if the input or output
+ space is XYZ. Fixed the Y to L* scaling to make sure it only
+ apples to XYZ space, and that the L* non-linearisation still
+ applies to Y like device spaces.
+
+* Fixed colprof so that the per channel input curves for
+ XYZ PCS B2A tables are actually scaled correctly.
+
+* Re-organized imdi/cctiff to allow for the possibility of
+ the Y to L* linearization being applied to actual XYZ input
+ spaces, not just Y like device spaces.
+
+* Modifed target/targen to cope better with case where adding
+ nodes fails to determine vertex positions a lot of the time, causing
+ extreme slowdown. Re-shuffle node order and retry now.
+ Also change appoach of adding fixed nodes to temporarily
+ skip fixed nodes that fail to add due to vertex positioning
+ failures. Also removed special node as this doesn't seem to
+ be required for reasonable positioning, and caused problems
+ in at least one case (media fixed node could never be added).
+
+* Modified libusb/55-Argyll.rules for better compatibility
+ with systems that have ACL installed but no ConsoleKit.
+ Also set ID_VENDOR and ID_MODEL using usb-db
+
+* Added matrix only/linear algorithm option to
+ profile/colprof, for raw camera profiling.
+
+* Fixed bug in input matrix profiles introduced by the XYZ cLUT
+ display matrix profile change, where the correct white and
+ black point wern't being written.
+
+* Changed tiffgamut to use one pass gamut hull finding,
+ since this seems to be more reliable on the odd shaped
+ image gamuts, as well as use a convex hull surface that
+ more closely wraps the raster colors.
+
+* Added standards references to the viewing condition pre-set
+ descriptions, and also added a preset for the ISO Critical
+ print viewing lighting level.
+
+* Fixed bug in profile/colprof -u, this wasn't being
+ applied properly to matrix profiles.
+
+* Fixed several build bugs in imdi code related to 64 bits.
+ The 64 bit code was sometimes being compiled on non-native 64
+ bit architectures, and not being compiled on native 64 bit
+ architectures. The table setup code was not handling 64 bit
+ setup correctly on 32 bit architectures.
+
+* Tried to improve dispcal -E (verify) behavior
+ by switching to native response for base measurement used
+ to establish black aim point. Probably would be better to
+ store all aim info in .cal file, and verify against that
+ rather than altering verification target by the current response...
+
+* Added documentation for specplot.
+
+* Added -M option to printtarg, for the case where the TIFF
+ file is to include the margin.
+
+* Fixed bug in ucmm/ucmm.c where wrong malloc length
+ causes crash when installing/unintstalling profiles
+ with long filenames.
+
+* Modified black curve to make sure that smoothed
+ curve meets target level at boundaries, and to
+ reduce smoothing filter width.
+
+Version 1.1.0 (17th January 2010)
+-------------
+
+* Added some warnings to colprof for strange combinations
+ of -s -S and -t -T and -g.
+
+* Fixed problem in perceptual gamut mapping that resulting in
+ less deep blacks than desirable. Also tweaked gamut mapping
+ to try and maintain luminance gradation near black
+ for chromatic colors.
+
+* Simplified the Linux instalation instructions, particularly
+ with regard to USB and serial permissions. Permissions use groups now,
+ or ACL if it is available.
+
+* Added working MSWindows 64 bit libusb drivers, which will work
+ on Vista 64 and MSWindows 7 64 bit. Because of
+ Microsofts driver signing requirements though, they won't be
+ usable unless a driver code signing workaround is used.
+
+* Fixed viewgam so that the number of gamuts that can be
+ viewed is unlimited. Also added error when computing intersecting
+ volume if the two gamuts are incompatible.
+
+* Added -O option to scanin and colprof, to allow overriding the
+ default output filename/location.
+
+* There was a regression in the black inking fixes, the K target
+ was corresponding to the pre-1D Lut values, this is now fixed.
+
+* Fixed another glitch in rspl/rev.c when computing black solution -
+ the auxiliary target was not always the closest one possible.
+ This fix may also help smoothness near black.
+
+Version 1.1.0 RC4 (6th January 2010)
+-----------------
+
+* Fixed bug in xicclu -pz that caused maximum rather than minimum ink. Also
+ fixed tolerance glitch in rspl/rev.c that was causing non-exact black
+ values to be returned.
+
+* Changed printtarg so that the TIFF output has the paper margin subtracted
+ from it. This is so that the resulting TIFF can be placed on that sized paper
+ without clipping or scaling. Set the margin to zero to get a TIFF that
+ exactly fits into the specified paper size.
+
+* Fixed bug in colprof -aX which caused crash when there are calibration
+ curves.
+
+* Fixed bug in printcal, changed first -n option to -d to distinguish it
+ from second -n parameter.
+
+Version 1.1.0 RC3 (4th January 2010)
+-----------------
+
+* Fixed bug in Linux profile uninstall (dispwin -U)
+ (Typo in path causes uninstall to fail).
+
+* Changed MSWindows athread implementation to kill a thread
+ that hasn't terminated on thread object deletion. This
+ isn't nice, but avoids the problem of the i1pro switch handler
+ thread exiting after 600 seconds and then accessing
+ a free'd structure when dispread -K is used.
+
+* Change colprof XYZ B2A table scaling to make better
+ use of the cLUT table grid resolution.
+
+* Fixed bugs in black generation rule to do with white->black point
+ calculations, scale and input/output curve handling. Changed
+ xicclu -g to better correspond with -k p parameters.
+ Changed xlut CMYK black locus handling to pick largest K value
+ when there are multiple K locus segments and the desired K
+ doesn't fall on any segment, to give better K continuity.
+ Added "skew" adjustment to K generation rule to make
+ the curve it better fit typical device behaviour.
+ Updated tutorial to reflect these changes.
+ Note that the -kp parameter values will have to
+ be re-established for a particular device using V1.1.0 RC3.
+ (This may improve the "bumpy black" problem ?)
+
+* Changed profile/colprof to generate matrix tags for Display XYZ PCS cLUT profiles,
+ to improve compatibility with other CMMs.
+ By default (-ax) the matrix tags will be a dummy transform that swaps red and green
+ so that it is obvious if the matrix is being used instead of the cLUT, and so it does
+ not increase profiling time. Using -aX will create real matrix tags.
+
+* Removed deprecated imdi/cctiff -o option, and added per profile -o option to set the
+ tag search order so as to be able to test profiles that have both matrix and
+ cLUT tags.
+
+* Removed general cLUT clip warnings, and added a specific RGB display/output
+ device warning if a primary can't be encoded in L*a*b* PCS.
+
+* Fixed bug in i1pro driver - the linearization factors were being swapped
+ between low and high gain. This improves the absolute luminance calibration,
+ and may have subtle effects on the accuracy of other readings.
+
+* Added -V option to dispcal and dispread to allow using the
+ adaptive mode of the i1pro for display measurement.
+ This may give better low level readings ?
+
+* Improved targen so that it doesn't slow down as badly
+ when a very large number of fixed points are used together
+ with full spread points.
+
+* Improved profile/logo2cgats so that it errors
+ on a wrong spectral field type.
+
+* Change spectro/dispcal to default to -f 1.0 (assume
+ black is all output offset) to make it work in more
+ sympathy to a typical display response. This may give
+ better fit and lessen the chance of color tints
+ due to a poor fit.
+
+* Increased profile/printcal curve smoothing to reduce
+ the effect of noise.
+
+* Changed chartread strip reading mode to allow navigating about the
+ strips, saving a partially read chart, and resuming a partially
+ read chart (chartread -r).
+ Also added a "next unread patch" key to the patch by patch mode.
+ Chartread won't exeit automaticcaly now, once all the patches have
+ been read (in case any patches need to be re-read), so the 'd'
+ key must be hit to finish.
+ Removed chartread -a option (it always saves the patch locations now).
+ Added a -I option to allow re-using .ti2 files on a chart printed
+ with different calibration curves.
+
+* Modified xicc/cam02 to clip the blue to avoid
+ crazy behaviour outside the spectrum locus.
+ Removed previous attempt at spectrum locus clipping.
+
+* Fixed bug in Spyder 3 driver that can cause readings
+ to be scaled by a factor of 16. (This depends on
+ when the Spyder was manufactured.)
+
+* Fixed bug in adding CIE illuminant C to spectral support.
+
+* Change printtarg last row padding to be media color
+ for both random and non-random layout.
+
+Version 1.1.0 RC2 (7th December 2009)
+-----------------
+
+* Re-worked gamut mapping to improve saturation levels
+ within the bulk of the gamut, as well as improve
+ hue preservation.
+
+* Changed "la" intent (luminance matched appearance) to have
+ zero luminance matching enhancement "knee", to make
+ it more appropriate for assessing transformations
+ in light of their estimated appearance.
+
+* Added CIE C type illuminant spectrum support.
+
+* Modified DTP20 driver to double check for an offline
+ read chart in case it is running old firmware.
+
+* Added device power value for targen to allow
+ calibrating devices that have extreme non linearity.
+
+* Fixed bug in targen when full spread patches were
+ mixed with other test patch types.
+
+* Updated yajl library to latest version.
+
+* Improved X11 XRandR CRTC detection
+
+* Added verbosity level to profcheck to match invprofcheck.
+
+* Clarified licensing of various files (GPLv2+ files, reference
+ files and documentation).
+
+Version 1.1.0 RC1 (6 November 2009)
+-----------------
+
+* Added flash measurement support to i1pro and Munki, + corresponding
+ option in spotread.
+
+* Added new link/collink flags -fcmy that force pure 100% C, M and/or Y
+ colorant input values to be pure output values. Gamut mapping
+ is adjusted sympathetically with these options too.
+
+* Fixed link/collink so that the -f, fk and -F options used
+ to force K only output also trigger gammut mapping
+ to the K only destination range. Also made these
+ options set black generation and intent in a sympathetic
+ way by default. The result is that there now should be
+ no discontinuity between the K only mapped colors and
+ others in the gamut, and the source gamut should be
+ mapped to be within the range of the K only black device.
+
+* Modified and improved gamut mapping to fix perceptual uniformity,
+ and also greatly improves smoothness and preservation of
+ source detail.. Re-tuned gamut mapping parameters.
+ Added support for K only black gamut mapping from source
+ and/or destination.
+
+* Fixed most CIECAM02 usages so as to clip values against
+ the spectrum locus before converting to Jab. This
+ may help avoid poor CIECAM behaviour for imaginary color values.
+
+* Fixed bug in rspl/inv.c that was causing innacurate
+ inverse lookups in some corner cases. This may have been
+ afecting black generation accuracy and general B2A table
+ and device link accuracy.
+
+* Added support for Spyder3Express (ie. disable ambient capability
+ if it's an Express).
+
+* Added workalike sRGB and Adobe1998 ICC profiles to /ref
+ Note that the sRGB profile has slightly higher accuracy
+ (better matching of matrix to white point) than the
+ original H.P./Microsoft profile.
+ Also provided lab2lab profile to use with collink.
+
+* Add support for the ColorMunki Create colorimeter.
+
+* Fixed xicc/xicc.x and xicc/xlut.c to be more robust in
+ computing a CMYK black point. Fixed bug in K limit handling.
+
+* Changed xicc/xfit to use higher order delta E metric, so that
+ maximum errors do not blow out. This seems to make the
+ output curves a much better fit, and reduces the error
+ when higher rspl smoothing factors are used. Curve stiffness
+ has been increased to improve smoothness ant match higher order error
+ values.
+
+* Added support for the Christophe Mtairie's Digital Target-3 chart with 570
+ patches. (Thanks to Nikolay Pokhilchenko & Ben Goren).
+
+* Changed the rspl/rev "> colprof: Error - rev: bwd vertex 0 is not prime or secondary"
+ error to a warning. This seems to be triggered by odd data sets (ie. monochrome).
+
+* Created a new tool extractttag to extract text tags from an ICC
+ profile. This can be used to extract the original target data
+ (ie. .ti3 file) and/or CAL curves from an ICC profile.
+
+* Fixed all the ink limit calculations to work in post-calibrated
+ final device values when per-channel calibration is being used,
+ and the calibration curves are embedded in the .ti3 file or ICC profile.
+
+* Added printer calibration capability:
+ Added printcal utility to create and verify printer calibrations.
+ Added calibration file support to printtarg.
+ Added calibration file support to cctiff.
+ New utility "applycal" to apply calibration to ICC profiles.
+ Modified targen etc. to distiguish between real RGB and fake
+ printer RGB.
+
+* Changed targen ofps point distribution to maintain
+ any initial gamut surface points during itterative
+ refinement, and to distribute them independently in
+ the sub-dimension they lie in. Changed adaptive operation
+ to be the default, and to use a much more sophisticated error
+ estimation model in determining the points locations.
+
+* Fixed problem with reliably detecting backward read strips
+ using the i1pro & Munki, by making target/printtarg optimize the
+ random patch layout to maximize the difference between
+ patches read from each direction. (This problem was more
+ prevalent with large charts with lots of strips.)
+
+* Added support for the LaserSoft DCPro scanner/camera
+ target chart.
+
+* Changed profile/logo2cats.c spectral scaling heuristic threshold
+ from 2 to 10 to allow more margin.
+
+* Fixed bug in spectro/dispwin.c for 256 byte EDID's (thanks to Omari Stephens).
+
+* Fixed bug in scanin/scanrd.c that caused crash due to diagnositic
+ output when a gross chart recognition mismatch occures.
+
+* Added warnings to colprof, collink and tweak if any values
+ get clipped when setting the cLUTs.
+
+* Fix bug in xicc/xfit.c where too little memory was being allocated.
+
+* Fix dispwin/dispcal problem on X11 with compositing WMs displaying
+ transparent test window.
+
+* Fix spectro/dispcal to fall back if Jacobian inversion fails.
+
+* Reduce default reverse cache memory limits to avoid thrashing.
+
+* Changed all code with my copyright to the
+ GNU AFFERO GENERAL PUBLIC LICENSE Version 3.
+ This may be of significance to anyone using
+ this code to provide a service over the Internet.
+
+* Modified spyder 2 & 3 driver to change how adaptive works.
+ Now increases the integration time to try and get
+ a minimum transition count. This speeds Spyder 2
+ readings (at some cost to accuracy), while helping
+ make the Spyder 3 a bit more useful on dark displays
+ (at the cost of a long read time). Also added workaround
+ to the Spyder 3 not having a reset command - drain
+ any pending read data on startup, so that it doesn't
+ corrupt calibration or initial readings.
+
+* Fix USB instruments so that a comms failure doesn't try
+ and re-establish communications. Fix i1pro & Munki so
+ that they don't return a comms error on a short measurement.
+
+* For the ColorMunki on OS X, kill the manufacturers daemon process that
+ has it open, when Argyll wants to open it. (daemon will automatically
+ restart).
+
+* Changed spectro/dispsup.c to show test window without
+ black background to position instrument, and
+ then re-create the test window with black backgroud.
+
+* Fixed memory allocation bug in i1pro & Munki drivers
+ when sensor gets saturated during display measurement.
+
+* Tweaked Jambase to work with Microsoft VC++8 and 9
+ when the Platform SDK February 2003 is used.
+
+* Removed need for DDK to access HID devices on MSWindows.
+ This simplifies compiling with Microsoft VC++ and
+ means that a MingW compile can use HID.
+
+* Enhanced plot library to aid debugging target/ofps.
+
+* Added a -M "command" option to dispcal and dispread, that
+ allows an external command to supply display readings.
+ This could be used to interface to an instrument not directly
+ supported by Argyll.
+
+* Fix spectrum -> XYZ conversion scale factor for absolute readings.
+ It was in error by 100/(10.685 * 6.83) = 1.37. This affected display
+ and emission readings for the i1pro.
+
+* Modified printtarg to allow creating of a ColorMunki chart.
+ By default the rows are as wide as the instrument, but -h will
+ double the row density.
+
+* Added -p for projector mode to spotread, dispcal and dispread.
+
+* Change dispread, dispcal & dispwin to use -P to position test window,
+ so that -p can be used for projector mode.
+
+* Added ColorMunki spectrometer driver.
+
+* Changed most code that reports progress on optimization
+ to aproximate percentage rather than ".....".
+
+* Added interactive option to spotread to allow saving specrums
+ to a CGATS ".sp" spectral file, suitable for use as an illuminant.
+
+* Added Spyder3 colorimeter driver.
+
+* Modified libusb/linux.c to make sure that a single large
+ request is broken down into overlapping 16K reads, so that
+ the i1pro rev A/B doesn't time out on SuSE Linux.
+
+* Fix bug in spectro/ntio.c involving error() and warning()
+ declarations. This causes crashes on machines with no serial ports.
+
+* Added another challenge/response key for DTP22.
+
+* Fix bug in gamut creation that caused internal error if
+ .gam points matches fake initial gamut tetrahedron.
+
+* Fix two problems in spectro/i1pro_imp.c:
+ The way that calibration files were detected as invalid
+ was insufficiently sesitive to the parameters being
+ changed in the driver. This meant reading and partially
+ re-using some parameters when the previous calibratin
+ should really have been ignored.
+
+ 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
+ display measurement exposures.
+
+* Fix bug in link/collink -ke where the K value was being
+ distorted by not taking into account the B2A per channel output curves.
+
+* Fix bug in spectro/hidio.c that can cause a crash (bus error) on OS X
+ for any program that accesses the instruments.
+
+* Make cgats lib easier to use from C++ (Thanks to Alastair M. Robinson).
+
+* Fix ICC spec. compliance issue with minimum
+ description tag length in Profile Sequence Description
+ tag type.
+
+* Fix bug in spectro/dispwin that prevented DPMS being
+ re-enabled if the process is killed.
+
+* Fix bug in xicc/tiffgamut.c that prevented it working for
+ Lab TIFF input. Fixed issues with doing image specific gamut mapping
+ in collink.
+
+* Make sure CGATS file identifiers are always a minimum of 7 characters.
+
+* Add 'targ' tag to hold chart data in profiles.
+
+* Fix problem where rev would fail on systems with lots
+ of RAM, due to running out of Virtual Memory space.
+ This happens mostly on OS X, because its malloc
+ routine use a lot more VM for small allocations
+ than the actual memory consumed.
+
+* Fixed problem with Spyder 2 driver, where errors or user
+ terminating/aborting measurements leaves the instrument
+ in a hung or corrupted state. Fix by making sure that
+ a measurement is always completed before returning.
+
+* Added Color Rendering Ra Index to measurements returned
+ from spotread for ambient or with the -T flag.
+
+* Add an option to tweak/refine to improve matching for
+ white point relative test chart data (Relative Colorimetric
+ intent matching).
+
+* Fix a memory leak in gamut.c, plus a few other 1-off minor leaks
+ elsewhere. (Thanks to Jordi Nodal for pointing these out.)
+
+* Add -U scale option to colprof so that input profiles can be created
+ that have a media white that is whiter than PCS white.
+
+* Fixed bug introduced in V1.0.0 in matrix input profiles where white point
+ was being normalized rather than being left absolute.
+ Also changed Lut based display profiles so that the white
+ point is forced to have a Y value of 1.0, to bring it into
+ line with matrix profiles. (This may worsen the verification
+ match to the original data though.)
+
+* Change rev cache RAM allocation to make sure
+ ARGYLL_REV_CACHE_MULT scaled value can't exceed VM size.
+
+* Added -A option to displcal, so that the neutral axis to
+ black point blend rate can be altered, and changed default to 4.0
+ to improve the off axis visual appearance with some LCD displays.
+
+* Made verify and refine a bit more robust in the face
+ of different format .ti3 files, partucularly those created
+ by logo2cgats.
+
+* Added a -O parameter to tiffgamut, to allow the resulting gamut
+ file to be located somewhere other that the directory the last .tiff
+ file is in.
+
+Version 1.0.4 bug fix release (30th June 2009)
+-----------------------------
+
+* Modify icc/icclib to protect against integer overflow exploits,
+ and fixes to minor bugs.
+ Bump icclib version to 2.11 to reflect this.
+
+* Fix bug in spectro/hidio.c that can cause a crash (bus error) on OS X
+ for any program that accesses the instruments.
+
+* Fix bug in xicc/xfit.c where too little memory was being allocated.
+
+
+Version 1.0.3 bug fix release (3rd September 2008)
+-----------------------------
+
+* Modified tiffgamut so that it processes an arbitrary number
+ of raster files. Also added a filter option, that filters out
+ little used colors from the raster gamut.
+
+* Changed gamut mapping to fix problem in which the gamut
+ mapping for profiles didn't match that in collink by
+ fixeing out of gamut mapping to make extended source
+ gamut of B2A table more sensible without afecting
+ primary gamut hull fidelity. Tweaked the gamut mapping
+ to de-emphasise luminence matching slightly, resulting
+ in more saturated but darker primaries for the typical
+ RGB->CMYK gamut mapping.
+
+* Fixed problem with i1display in which it would
+ time out for some particular inputs (low level dynamic
+ input ?)
+
+* Fixed MSWindows screensaver reset to work on
+ Vista by adding fake mouse move event.
+
+* Changes rspl/rev to have a "fast setup" mode
+ that trades a faster setup time for slower
+ reverse lookups. This is to improve the
+ responsiveness of xicclu.
+
+* Fixed bug in dispcal when using -a with -t
+
+* Added -L option to printtarg to suppress the i1pro target holder
+ clip margin.
+
+* Fix yet another PPC GCC optimizer bug in spectro/dispread.c
+
+* Modifed rspl/rev cache allocation to make sure
+ that it is somewhat less than the maximum virtual
+ memory that a process can allocate. On some systems
+ with lots of RAM, it is possible to have malloc() fail
+ due to this.
+
+* Added support for i1 Monitor instrument,
+ which is an i1pro without reflective capability.
+
+Version 1.0.2 bug fix release 19th August 2008
+-----------------------------
+
+* Fixed two typo bugs in colprof (xicc/xfit.c) to do with output
+ per curve optimization - the symptoms were gcc based compiles
+ taking a long time to create the A2B tables.
+
+* Added workaround to strange i1pro Rev A upgrade/Rev B quirk,
+ that causes extra time to be taken for reads.
+
+* Added some extra verbose output when creating profiles (rspl/rev)
+ to show the system RAM detected and the limit imposed on
+ each rev cache. Also changed code to prevent failure when
+ there is not enough memory to allocate a single cell
+ to search, and to fix memory limit setting for systems that
+ may have 4 Gbytes or more of memory.
+
+* Added new option to collink -fk, that forces 000K input
+ to K only output.
+
+* Fix dispwin.c so that -K option (calibrate instrument)
+ doesn't fail when it thinks two dispwin's are being requested.
+
+* Change spectro/hidio.c so that HidD_GetAttributes() fail is ignored.
+
+* Fixed bug in dispcal which causes a numerical fault if a Yxy white point
+ is specified and ambient correction is used.
+
+* Changed colprof -bn to be the same effect as -B (ie. a minimal resolution
+ B2A table).
+
+* Fixed dispwin -R "Effective LUT entry depth" report to work without -v.
+
+* Modified MSWindows display enumeration to not ignore displays
+ that have EnumDisplayDevices() fail, but ignore displays
+ with a name \\.\\DISPLAYV*. This us to get it working under VMWARE.
+
+* Added device target value quantization option to
+ target/printtarg, as well as making it default for TIFF output files.
+
+* Fixed a bad memory leak in render/render.c, that was
+ affecting target/printtarg. Probably improved the
+ anti-aliased rendering speed too.
+
+* Fix typo in spectro/dispwin.c that sometimes causes a crash
+ when the system has XRandR 1.2.
+
+* Fix latent bug in xicc/xfit.c that could affect
+ profiles that are not white point corrected (ie. colorof -u inputdevice).
+
+* Fixed problem with an i1pro that has had it's
+ EEProm reset after a firmware upgrade - a previous
+ calibration EEPRom integration time of 0.0 is increased
+ to the minimum integration time to prevent divide by zero etc.
+
+* Added Argyll version number to the i1pro calibration file,
+ to try and make sure that old files are invalidated with
+ each potentialy incompatible update.
+
+* Fix LUT entry depth reporting bug, and add yet another
+ workaround for the GCC/PPC optimizer bug.
+
+Version 1.0.1 bug fix release (14th July 2008)
+-----------------------------
+
+* Changed XRandR code to index the _ICC_PROFILE property
+ such than inactive displays are ignored.
+
+* Fixed problem in rspl/rev.c where the memory consuption
+ was sometimes exceeding the maximum RAM limit.
+
+* Changed XRandR code to fall back to other extensions
+ if it fails simple VideoLUT access tests.
+* Add environment variable "ARGYLL_IGNORE_XRANDR1_2" to
+ cause XRandR 1.2 to be ignored on X11 systems
+ that have buggy XRandR 1.2 implementation.
+
+* Fixed problem with locating displays on MSWindows with
+ some particular configurations.
+
+* Fixed bug introduced into cam02.c that ignored
+ enumerated viewing condition.
+
+* Changed udev USB matches to lower case, since
+ apparently udev does a text match rather than matching
+ the integers...
+
+* Fixed malloc size bug in profile/logo2cgats.c
+ (thanks to Steven Greaves).
+
+* Fix dispwin so that the lack of an EDID_DATA atome is
+ not a fatal error.
+
+* Fixed jcnf so that the temporary file is in the same directory
+ as the file it will be renamed to.
+
+* Added debug option to dispwin/ucmm to help with diagnosis of
+ locating displays.
+
+Version 1.0.0 changes (1st July 2008)
+---------------------
+
+* Changed input device profile creation to create B2A table
+ by default. This can be disabled with the -b option.
+
+* Changed scanin to pass spectral information from reference file
+ to .ti3 file, and also changed coloprof to honour observer and
+ illuminant options for input profile creation.
+
+* Added check to using libusb to check that it has
+ been patched to work properly with Argyll supported instruments.
+
+* Remove termination character setting from ntio.c and unixio.c
+ to work around problem with Prolific 2302 USB<->Serial converted.
+
+* Fixed bug in MingW build that caused a run time
+ "(null) DLL cannot be found" error, for any
+ program that linked to the libusb library.
+
+* Modified profile/logo2cgats to output the sample name,
+ to make it more useful. Added -n flag to spectro/spec2cie
+ to optionaly suppress spectral output. Documented spec2cie-p
+ (plot spectrum) flag.
+
+* Modified gamut/nearsmth.c to change optimization search
+ from 3D to 2D to improve speed.
+
+* Added experimental "Daemon" mode to dispwin, so that it
+ monitors an X11 server and keeps each screen up to date
+ with the corresponding profile and calibration using XRandR 1.2.
+
+* Tweaked dispcal to try and improve behaviour and resulting
+ smoothness of curves. Added black brightness option -B.
+ Added extra report to -R to show VideoLUT entry bits of significance.
+
+* The i1pro fixed integration time of 2.0 seconds for display
+ calibration turns out to be too long for some very bright
+ displays. To cope, an alternat 1.0 second integration
+ time is calibrated, and switched to if the display
+ is bright enough.
+
+* Changed distribution archives so that they have a top
+ level directory. Changed OS X and Linux to gzip'd tar
+ archives rather than .zip, so as to preserve the
+ UNIX style permissions better.
+
+* Modified rspl/rev.c to add improved nearest acceleration
+ lookup grid structure, to tackle performance issues.
+ Changed aceleration grids to only hold fwd cells that
+ are within the ink limit. Changes sub-simplex handling
+ to make common face sub-simplexes shared between cells.
+ Fixed bug in ink limit bug that was causing many sub-simplexes
+ to be treated as if they straddled the ink boundary, slowing
+ down inversions with ink limits applied. Changed reverse
+ memory size accounting from cells to bytes, for more
+ accurate containtment of memory usage below the swap
+ threshold. Made default memory limit automatically adapt
+ to available system RAM. Increased default reverse
+ acceleration grid resolution to be twice the forward grid
+ resolution, for much improved speed. Added another performance
+ tuning environment variable ARGYLL_REV_ACC_GRID_RES_MULT to
+ allow altering the reverse acceleration grid resolution.
+
+* Fixed cctiff so that it will copy a tiff file
+ with no color transformation. This allows embedding
+ an ICC profile in the output. Note that the TIFF file
+ will have been modified, the format may have changed,
+ and tags may be lost (ie., this is not the same as
+ an "in place" embedding).
+
+* Added a simple utility "extracticc" to extract
+ embedded ICC profiles from TIF files.
+
+* Modify tiffgamut, cctiff colprof and collink so that a TIFF file
+ with an embedded profile may be used to supply ICC profiles.
+ Also added an option to cctiff of embedding a profile in the
+ destination raster file.
+
+* Added a micro cmm to Linux port, to supord recording
+ the installed display profile to monitor association
+ in the file system. dispwin uses this for installing
+ display profiles, as well as setting a display
+ to the currently installed profile.
+
+* Changed dispwin operation on OS X to be able
+ to set the display calibration in a semi-persistent
+ way that is similar to the behaviour on other systems.
+
+* Fixed imdi/cctiff and link/collink so that they
+ no longer rely on a Matrix profile device space
+ being roughtly perceptualy linear - instead
+ use the per channel curves and convert them
+ to an L* type space for indexing the CLUT grid,
+ and also make a Matrix output space L* like
+ for interpolation.
+
+* Changed colprof to extract the source gamuts
+ for the perceptual and saturation gamut
+ mapping from the perceptual and saturation
+ A2B tables of the source profile (if they exist).
+ This makes for a better match of the gamut
+ mapping to that particular source profile
+ when subsequently linked with a CMM that
+ chooses the same intent table for source
+ and destination profiles. Changed iccgamut, tiffgamut
+ and xicclu to correspond - make Jab appearance space
+ selection orthogonal to intent table used.
+
+* Checked and adjsted ambient calibration (Lux etc.).
+ The Eye-One pro, Huey etc. now give reasonable readings.
+
+* Changed dispcal to make handling of input and/or
+ output black offset consistent across all calibration
+ curve selections, as well as make it selectable/blendable.
+ Added some other standard video calibration curves.
+ Added a viewing conditions transform based on CIECAM02
+ to adjust for the effect of ambient light on display
+ visual contrast, plus option of measuring the ambient
+ light with the instrument.
+
+* Made cam02 set_view() argument order consistent.
+
+* Added battery status report to spotread and chartread
+ for DTP20.
+
+* Enhanced dispwin to take care of installing
+ and uninstalling profiles for a chosen display.
+ Also allow setting the display calibration to the
+ appropriate installed profile.
+
+* Changed colprof so that the .ti3 data is
+ included in a 'DevD' and 'CIED' text tag in the profile.
+
+* Added X11 RandR 1.2 support, and use this in
+ preference to Xinerama and XF86VidMode extensions.
+ Support the _ICC_PROFILE atom in the Xrandr output
+ object, as well as the usual RootWindow properties.
+
+* Added TIFF file output support to target/printtarg,
+ as well as an identification string on each page.
+
+* Enhance argyll/render to support text (using Hershey fonts),
+ solid and dotted lines, improve speed, plus add
+ anti-aliased output. This is in order to make
+ it usable with printtarg.
+
+* Completely re-wrote the Jambase & Jamfiles to make
+ a build system thaht works from the top and within
+ sub-directories, as well as cleaning up the Jamfiles
+ and improving the build system capabilities.
+ This solves the circular dependency issues,
+ makes a full build faster and cleaner,
+ and makes it easier to ensure that a full
+ build has consistent build flags and completes
+ sucessfuly. The system TIFF library will
+ now be used if available. Argyll project setup
+ is now in "Jamtop" in the project root directory.
+
+* Added ability to dispwin to display test patches
+ from a CGATS file, so that it can be used for manual
+ patch measurement.
+
+* Improved ability of cctiff to cope with input
+ files that have extra planes.
+
+* Changed tiffgamut to accept Lab encoded TIFF files without
+ using an ICC profile, as well as accepting a colorspace
+ ICC profile.
+
+* Removed limititation that VideoLUTs have exactly 256 entries.
+
+* Fixed problem with accuracy of dispcal -o profiles.
+ [There were two issues, one being that the fitting was
+ weighting smoothness to the detrement of accuracy,
+ and the other being that there are unconstrained
+ parameters that allow the model curves not to
+ go through 1,1]
+
+* Fixed problem with Linux PolicyKit/Hal permission
+ files not enabling serial ports and Huey.
+
+* Fixed and verified that the major Linux/X11 screensavers
+ (X11 saver, xscreensaver, gnome & kde screensavers) and DPMS
+ are disabled properly, and now we avoid doing an exec()
+ every 60 seconds!
+
+* Modified libusb to address Linux intr/bulk polling
+ and reliability issues.
+
+* Improved install documentation in the light of current
+ Linux distributions, and MSWindows versions.
+
+* Renamed "profile" to "colprof", and "icclink" to "collink"
+ to avoid clashes that have arisen with other executable names.
+
+* Fixed bug in scanin/scanrd.c that sometimes caused
+ a double free crash on Linux. (Thanks to Guy K. Kloss)
+
+* Modified dispwin to open a device context to a particular
+ MSWindows display differently, for better compatibility with
+ MS Vista.
+
+* Changed dispwin to allow several of the commands
+ to operate in one call. Clearing the LUT,
+ setting the X11 ICC_PROFILE, loading the profile or
+ X11 ICC_PROFILE can now be done with one
+ invokation of dispwin.
+
+* Fixed bug in dispcal that affected black level
+ adjustment and calibration. Symptom was a black
+ level not quite as low as it should be.
+ [Thanks to Hal V. Engel for noticing this]
+
+* Made sure that display profiles have the luminance tag
+ value set, so that it's possible to recover the
+ actual instrument reading.
+
+* Fixed dispcal and dispread -dfake so that
+ they will take notice of a -kcal file.
+
+[Beta 8 Snapshot 2008/1/15]
+
+* Added -S and -L options to spectro/dispwin for Unix/X11
+ systems, to allow setting and using the _ICC_PROFILE
+ root window property to store the displays profile
+ and calibration.
+
+* Changed MSWindows and OS X dispwin/dispcal/dispread test
+ window to be title and borderless, and also have
+ an option (-B) to mask the whole screen behind the
+ test window with black.
+
+* Added a "create intersection gamut" method
+ to the gamut class, and also added a companion
+ -i/-I flag to viewgam to print out the intersecting
+ volume of the first two gamuts, and oprionaly
+ save the intersecting gamut. Improved robustness of
+ the gamut "radial" point test methods slightly.
+
+* Fixed spotread so that it doesn't display any
+ color information when reading the Huey ambient
+ sensor, and added an option (-T) to show
+ color temperature for each reading.
+
+* Added gamut volume report (with -v) to tiffgamut.
+
+* Changed spectro/spyd2setup.h to only set the
+ loaded flag after sucessfuly loaded a firmware file.
+
+* Changed numlib/numsup.c error, warning and verbose
+ functions into function pointers so that they
+ can be overridden by callers of library functions
+ that make use of them (lprof).
+
+* Switched icc and cgats library from
+ the "BSD like" license to the "MIT" license.
+
+* Added better DTP22 support to driver and
+ printtarg.c (thanks to Nigel Rowe)
+
+* Fixed spectro/ntio.c to cope gracefully with systems
+ that don't have any serial ports.
+
+* Renamed spectro/printread to spectro/chartread.
+
+* Fixed problem in spectro/usbio.c where on
+ some systems usb_detach_kernel_driver_np() needs
+ to be called before usb_set_configuration().
+
+* Added option to dispread (-C) to allow a shell callout
+ with each color being tested, to allow relaying the
+ test patch value to a remote display via a script.
+
+* Removed spectro/filmread.c and target/filmtarg.c
+ until their licensing compatibility with GPLv3 is
+ figured out.
+
+* Added -W parameter to instrument using programs,
+ that allows overriding the default serial flow
+ control protocol. This may allow working around
+ problems caused by flow control not working
+ on certain systems.
+
+* Added quick ICC profile creation to dispcal,
+ so that single operation calibration & profile
+ is now possible.
+
+* Fixed some bugs in cctiff handling of Lab PCS and/or
+ -p operation.
+
+* Added a new test chart type to render/timage, for
+ testing profile B2A tables.
+
+* Added -V option to spectro/dispwin, that verifies
+ the currently loaded calibration.
+
+* Added (yet another!) variation of the spectral
+ field names to support colorport output,
+ to profile/logo2cgats.
+
+* Fixed problem with dispcal -u (and possibly
+ other cases, ie. profile) where an out of range
+ VideoLUT calibration value can wrap around
+ rather than saturating.
+
+* Improved black point setting in dispcal,
+ so that it doesn't get lighter if the white point
+ is reset during the run. Also changed the white
+ point cliping to use the device model, rather than
+ relying in the cube clipping code, which was not
+ so accurate.
+
+* Modified profout per channel curve algorithm
+ to be encapsulated in an independent module (xicc/xfit.c),
+ and to create input curves that adjust the curve shape and
+ clut grid locations independently of each other.
+ This has similar performance to the old code in many
+ cases, but reduces fit errors for certain types
+ of device characteristics.
+
+[Beta 7 Snapshot 2007/10/15]
+
+* Fixed minor bug in icc.c - was double freeing while
+ a V4 profile was being rejected.
+ Also changed SYMETRICAL_DEFAULT_LAB_RANGE
+ B2A input curve tweak for 16 bit -
+ the range can be almost -128 to 128 and still
+ remain symetrical.
+
+* Improved robustness of dispcal in zeroing in
+ on the neutral patches. Got Jacobian matrix
+ refinement going, added device value clipping,
+ and made it revert back to the best ever
+ value as a worst case result. Tested all the colorimeters
+ on every platform, fixed bugs with spyder on
+ different platforms (USB bugs ?).
+
+* Tweaked spyder driver to improve repeatability
+ for low light conditions - made integration
+ time adaptive.
+
+* Added Huey colorimeter support, including driving
+ it through the HID drivers on MSWindows and OS X.
+
+* Added Spyder 2 Colorimeter support, including the
+ firware transfer utility spyd2en, to allow the
+ end user to get their instrument workings.
+
+* Fixed a problem in dispwin/dispcal/dispread not keeping
+ the Gnome screensaver at bay.
+
+* Fixed very minor error in profile that caused a crash
+ if -taw was used without a -s.
+
+* Hopefully fixed the last lingering issues with the
+ gamut function "split plane" problem. Improved
+ the split plane choice criteria too, reducing
+ the structure size and (presumably)
+ improving interogation speed slightly.
+ (Visualizing things always helps a lot!)
+
+[Beta 6 Snapshot 2007/9/15]
+
+* Fixed bugs in dispcal target curve - the curves
+ didn't seem to be as neutral as they should be.
+
+* Changed HCFR setup to assume no special 2mm apatures
+ on its sensors, since this is the default hardware configuration.
+
+* Added support for more scan targets. The list is now:
+ IT8.7/2, ColorCheckerDC, ColorCheckerSG,
+ Eye-One Pro Scan Target 1.4 and HutchColor HCT.
+
+* Fixed bug in printread -xl :- XYZ wasn't being scaled to 100
+ (thanks to Duane Ruck for pointing this out).
+
+* Fixed bug that affected printread handling a chart with
+ the patch location identifier that has patch location
+ before strip location. This was affecting reading the
+ Eye-One Pro Scan Target 1.4 chart.
+
+* Added a -a flag to printread, to cause the patch locations
+ to be saved to the output, so that a chart read can be used
+ to create a scan/input CIE reference file.
+
+* Added good/bad beeps to printread for the Eye-One Pro,
+ to speed up chart reading.
+
+* Added a -B flag to print read, to disable bi-directional
+ strip recognition if the reference patch values are not to
+ be relied upon.
+
+* Modified i1pro patch recognition to make it more
+ sensitive to differences in just some wavelength bands
+ - this fixes Eye-One Scan Target 1.4 patch recognition,
+ and generally helps robustness for all charts.
+
+* Supressed "There is at least one patch with an very unexpected response!"
+ warning in printread unless the expected values were created using
+ a specific device model such as an ICC or MPP profile in targen.
+
+[Beta5a Snapshot 2007/9/10]
+
+* Fixed bug that had crept into profile/profout.c
+ that wreckes the contents of the gamut lut.
+
+* Added a manual chart recognition fiducial marks to
+ print charts that are intended to be scanned in (printtar -s),
+ so that manual chart recognition can be used on these too.
+
+[Beta5 Snapshot 2007/8/28]
+
+* Fixed serious bug in dispcal & dispread on Linux -
+ screensaver suppression using fork() was causing
+ programs to execute twice at the same time.
+
+* Changed spectro/dispcal.c calibration algorithm
+ to be faster, more precise, and more robust.
+ Improved handling of "native white" mode
+ to better hit the target 1.0 RGB values.
+ This should contain the worst case errors better.
+
+* Changed printtarg to pad i1 test chart last row,
+ since the printread logic can't cope otherwise.
+
+* Added a manual chart recognition option (-F) to scanin,
+ that makes use of fiducial marks defined in the .cht file.
+
+* Added a -G gamma option to scanin/scanin to allow
+ some flexibility in the face of extreme device behaviour.
+
+* (Hopefully) fixed DTP02Q thanks to feedback from Udo Lembke.
+
+* Changed all of my code and other GPL code that allows upgrading,
+ to the GPL Version 3 license. Corrected "licence" to "license"
+ in many (but probably not all) places.
+
+* Modified DTP51 driver to ignore a "bad command"
+ error to the GI command (allow for old firmware ?)
+
+* Modifed dtp20 on-line reading to be more forgiving
+ of unexpected status after a strip read.
+
+* Added some fudge scale factors for i1pro emission
+ and ambient modes. I'm not sure at the moment where the
+ real scale factors come from, so I've roughly matched
+ the scale to what the GM driver returns.
+ Also add fudge factor for i1display2 ambient mode.
+
+* Fixed some bugs that had crept into DTP20
+ offline chart reading (not reading, heap corruption on free).
+
+* Added diagnostic for DTP20 offline chart reading
+ to hint at what strip hasn't been read.
+
+* Changed printtarg to optimise contrast between
+ test patches and spacers.
+
+* Added "aproximate least squares" setting mode
+ to icc set_lut and rspl set_rspl to improve average
+ accuract when setting interpolation arrays from
+ a function (ie. when inverting A2B).
+
+* Added a "display with normalized brightness" to spot
+ read to make it easier to verify spot readings
+ for a display profile.
+
+* Fixed "r" and "rl" intents so that the white points
+ are linearly mapped, as is the normal expectation with
+ relative colorimetric intents.
+
+[Beta4 Snapshot 2007/5/16]
+
+* Fixed icclib to handle unknown tag types now,
+ as well as cope more gracefully with ProfileMaker4
+ profiles that have an illegal flag value in their
+ data tagtype flag field.
+
+* Modified gamut mapping to improve coherence of mapping
+ outside the source gamut when used to create B2A table.
+
+* Created first cut of VRML debug plot library in plot/vrml.c,
+ and switched gamut/gammap.c to use it. Other diagnostics
+ could be switched to use it too (ie gamut/gamut.c).
+
+* Modified ciecam02 to improve handling of imaginary colors,
+ and coherence in those regions.
+
+* Added a delay between setting a screen color (spectro/dispwin.c)
+ and starting to read the patch with a display instrument.
+
+* Fixed issue on OS X with locating displays - IO dictionary
+ string handling.
+
+* Made the dispcal/dispread calibration a bit friendlier if the
+ instrument doesn't actually support calibration.
+
+* Added profile comment options to link/icclink.
+
+* Fixed bugs in xicc/xicc.c and xicc/xlut.c that were affecting
+ how black generation was controlled by the input luminence
+ value for a -kp option. This affected profile/profile the
+ most, but could also have changed how link/icclink -G
+ generates black as well. The black generation should now
+ match quite closelgy between the B2A tables generated
+ by profile/profile, and the black generation generated
+ by link/icclink -G.
+
+* Added "patch by patch" mode to print read, that allows
+ reading media where strip recognition is unreliable.
+
+* Added patch consistency tolerance modifier to
+ printread and the i1pro driver.
+
+[Beta3 Snapshot 2007/4/10]
+
+* Modified i1pro driver to do scan measurements with
+ single USB read, to avoid read latency issues.
+
+* Added display/emission distinction for i1pro,
+ to speed up display measurement, while still allowing general
+ ambient measurements to be adaptive. Added display mode
+ to spotread.
+
+* Added workaround to the i1pro rev D crashing on
+ close under Linux. It's reset rather than closed.
+
+* Modified libusb-win32 to fix problem with i1pro rev D
+ crashing on a get_configuration.
+
+* Reworked scan patch recognition to work for reflective
+ or emissive scans, and to be more tolerant of noisy media.
+
+* Added support for emission scans to i1pro and printreaf.
+
+* Fixed ref/*.sp files, as well as adding back in D50*.sp
+ variations that seem to have gone missing.
+
+* Change i1pro trigger/read logic to ensure that
+ process scheduling latency doesn't cause the read to
+ be late, causing read failure. Add trigger/read timing diagnostics.
+
+* Fix i1pro switch thread cleanup to avoid memory access fault.
+
+* Tweak xicc/xspect.c FWA to have better estimation accuracy
+ with a range of paper stocks, as verified by xicc/spectest2.c
+ and xicc/spectest.c
+
+* Fixed spotread to display FWA corrected spectra correctly,
+ as well as fix some bugs with the reference spectra.
+
+[Beta2 Snapshot 2007/3/29]
+
+* Fixed gcc 3.3 optimiser problems on OS X which were
+ causing crashes in spotread -S and i1pro high res.
+
+* Modified spec2cie to look for specific device values to
+ identify white, since some devices fool looking for maximum Y.
+
+* Fix triggering to make FWA spotreads work.
+
+* Fix bug in Spectrolino calibration with filter messages
+ work properly.
+
+* Fix bugs with DTP41 and DTP51 triggering.
+
+* Change how rows per strip are stored in .ti2 file,
+ to remove base 62 limit.
+
+* Increase scope of target/printtarg scale options,
+ and add extra scale for spacers.
+
+* Changed Linux serial port location to look
+ for /dev/ttyUSB* as well as /dev/ttyS*,
+ and only offer them if they can be opened.
+
+* Fix i1pro driver so that it does not return
+ spectral data unless asked.
+
+[Beta1 Snapshot 2007/3/22]
+
+* Finished i1pro driver by adding highres spectral mode
+ (+ matching changes in dispcal, dispread, printread, spotread),
+ and making the calibrations non-volatile so that
+ they can be retained between utility starts.
+
+* Changed the default observer backto the 1931 2 degree
+ observer in various programs (profile etc.), so there
+ is less surprise at the discrepancy between the
+ default instrument values and the values when
+ spectral data is used.
+
+* Changed profile/logo2cgats so that it uses a heuristic to
+ determine if the spectral data needs scaling by 1.0 or
+ 100.0, since it seems the type of file cannot be relied upon
+ as an indicator.
+
+* Fixed link/icclink to record a more accurate summary of
+ overall intent in the header.
+
+* Re-worked tweak/refine.c slightly, to try and improve how
+ it copes with out of gamut points. Added automatic
+ extra weight (5) for lightest patch.
+
+* Added new black generation feature to link/icclink. It can
+ now take the output inking from that of the output profile
+ B2A table, just like revfix.
+
+* Fix bug in link/icclink - the changeover to using K target rather than
+ locus had a bug in it. It was still partially defaulting to locus rather
+ than K value target (some C library has a global called locus ?)
+
+* Made it so Eye-One pro can recognise strips when read in either direction.
+
+* Re-worked instrument calibration and measurement triggering
+ to support instrument operated buttons.
+
+* Added support for DTP20 spectrometer.
+
+* Added support for Eye-One Pro spectrometer.
+
+* Fixed bug in profile where RGB space profiles didn't handle FWA correctly.
+
+* Fixed some bugs in cctiff that were causing inacurate results.
+
+* Added support for the DTP22/Digital Swatchbook.
+
+* Changed serial port driven instruments type to be automatically
+ recognized, eliminating the need for the -i option on
+ all the instrument using utilities (dispcal, dispread, printread, spotread).
+
+* Reworked gamut hull triangulation, hopefully making it more
+ robust against any numerical issues.
+
+* Fix bug in printtarg that caused green spacers instead of white ones.
+
+* Added -c flag to spectro/dispwin. This clears a display
+ calibration.
+
+* Added support for Eye-One Display 1 and 2 colorimeters.
+
+* Added extra configuration for DTP92 to cope with
+ a firmware bug for certain early DTP92Q instruments.
+
+* Fixed bug in logo2cgats - X-Rite ColorPort spectral data
+ is already scaled to 100, so only do this for Gretag files.
+
+* Added the -m flag to scanin/scanin, to allow it to
+ return true mean values, rather than robust mean values
+ (but see latter bugfix).
+
+* Fixed a bug in profile/profout.c that caused some matrix shaper
+ profile to generate colorant XYZ values slightly less than
+ 0.0, due to numerical inacuracy, triggering an assert.
+
+* Added a new option to spectro/spot read to allow use of
+ the Spectrolino with filters fitted.
+
+* Added error handler to spectro/dispwin.c, so that there
+ is not a fatal error triggered in just listing the
+ screens on an X11 system running TwinView or MergedFB.
+
+* Fixed problem with USB/DTP94 that caused instrument
+ coms to fail after doing calibration.
+
+* Fix bug in render/timage.c that caused central wedge to be
+ corrupted.
+
+
+Version 0.60 changes (July 17 2006)
+--------------------
+
+* Changed both gamut mapping intents, and enumerated
+ viewing conditions to be symbolic mnemonics, so that
+ the options don't change as intents and viewing conditions
+ are added, deleted or re-ordered. Selection of
+ intents or viewinging conditions using a numerical
+ enumerator is no longer supported, to help
+ catch problems caused by changes to the list
+ with this releas.
+
+* Fixed bug in profile/profile.c when creation XYZ PCS
+ LUT profiles - the gamut tag was being created with the
+ wrong color space, and often this would cause an
+ internal fault in gamut surface creation.
+
+* Changed profile/profile so that if a source
+ gamut/profile is supplied for display LUT type
+ profile creation, an ICC V2.4.0 profile is created
+ with all 3 intent tables, rather than the single
+ colorimetric intent that is default for ICC V2.2.0 and
+ earlier. Fixed icc/icc.c to properly support the
+ possibility of a full set of intent Luts in
+ display and input profiles. (Profile does
+ not yet support intents for input profiles.)
+
+* Added new intent to link/icclink and profile/profile.c,
+ that does an absolute colorimetric link, but
+ will scale the brightness down if needed to
+ avoid clipping the source white point. This
+ is useful in soft-proofing situatations.
+
+* Went through with both gcc -Wall, and Vc++ -w3
+ and reduced the number of waring messages.
+ Fixed some very minor bugs along the way.
+
+* Made additional changes to spectro/dispcal.c, to
+ improve behaviour when adjusting controls with and
+ without targets. When adjusting without a white target,
+ the control hints now help you adjust to be on
+ the chosen black body or daylight locus.
+
+* Changed profile smoothing factors that are different
+ for the L* a* and b* channels.
+
+* Made profile/profile.c label the profile with the platform
+ it was created on.
+
+* Improved the device model used by dispcal, including
+ optimising the model, so that it zero's in on
+ calibration faster, and handles the black point
+ more accurately. Added a variable -k option to
+ dispcal.
+
+* Added display controls addjustment mode to dispcal,
+ and altered the target gamma curve to better take the
+ black point into account.
+
+* Added report option to dispcal, to measure and report on
+ the current display behaviour.
+
+* Added verification mode to dispcal (-E), to
+ allow checking how well a display meets its calibration
+ targets.
+
+* Added -N option to dispcal, dispread and spotread to
+ allow instrument calibration to be bypassed. This makes
+ repeatedly operating some instruments (ie. Spectrolino)
+ more convenient in emission mode.
+
+* Added a "load video LUT" mode to dispwin, so it can now
+ be used to initialse the displays from either ICC profiles,
+ or Argyll .cal files. Can be used on all platforms (but
+ particularly MSWindows and X11) in startup scripts.
+
+* Fixed bug in X11 disable screensaver, and disabled
+ the cursor over the test window.
+
+* Added proper multiscreen support on all platforms
+ (Even X11 Xinerama!).
+
+* Fixed bug in dispcal that was causing the achievable
+ brightness calculation to misbehave.
+
+* Added -u "update" option to dispcal, to speed up
+ maintenance of display calibration.
+
+* Added separate options in dispcal for a daylight or
+ black body color temperature target.
+
+* Added "plot spectra" option to spotread.
+
+* Added support for the X-Rite DTP94 (AKA OPTIX) to spotread, dispcal,
+ dispread. Added -y option to allow specifying whether a CRT or LCD
+ is being read.
+
+* Streamlined instalation (particularly on Unix and OSX),
+ so that tifflib and libusb don't need special handling.
+ Changes to Jambase to accomodate this.
+
+* Added support for USB connected instruments using libusb.
+
+* Added support in profile/logo2cgats for converting from
+ X-Rite ColorPort format.
+
+* Added extra facilities to imdi to suppport arbitrary
+ colorant order, arbitrary pixel padding, reduced
+ runtime code size and improved cross platform
+ compatibility.
+
+* Added warnings in all the instrument driver
+ code, that instrument companies are not to be
+ expected to support anything involving these drivers.
+
+* Completed new version of cctiff, that deals with an
+ arbitrary sequence of profiles, as well as supporting
+ L*a*B* encoded TIFF I/O.
+
+* Added alternate sort algorithm to imdi/cgen.c, for
+ 16 bit input support, speeding up higher dimensional
+ input conversions.
+
+* Changed icc/iccdump so that the -t parameter can
+ be specified multiple times.
+
+* Added extra PCS curve for BtoA table of XYZ LUT
+ profiles :- this greatly improves the accuracy
+ of the BtoA lookup of XYZ LUT profiles.
+
+* Added greytiff utlity to binary distribution,
+ and also added option to convert using CIECAM02
+ space, for lighter chromatic colors.
+
+* Added ColorantTable tag to profiles created by
+ profile/profile.
+
+* Added a new option to dispcal and dispread, to allow
+ the test window to be positioned and sized. This
+ allows some people to cope with multiple displays
+ better, and may give some flexibility in applying
+ these utilities to projectors etc.
+
+* Added three stage overal conversions to icc/icclib.c,
+ for monochrome, matrix and lut conversion classes.
+ This is to make it convenient to split up every conversion
+ into input per component, core intercomponent conversion,
+ and per component output, to match the capabilities
+ of imdi.
+
+* Modifed xicc/xicclu, xicc/revfix.c, profile/profile.c
+ and link/icclink.c, to default the -k black generation
+ to setting black level targets, instead of locus targets.
+ In pratcice it seems easier to create smooth black curves
+ this way, especially when meshing with the black behaviour
+ forced by ink limits and L target levels.
+ Backward compatibility with the previous controls is provided
+ via the -K flag. Default black generation has generally
+ been switched to -kr. xicc/xicclu has had the -kq option
+ added, so that the behaviour of icclink -kq can be
+ explored. Some bugs in -kq may have been fixed.
+
+* Added full verbosity levels to icc/icclu and xicc/icclu,
+ so that -v0 can be used to capture batch output that
+ is ready for further batch processing.
+
+* Enabled proper gamut tag creation in profiles.
+
+* Fixed numerical issue in xicc/xicc.c:icxdCIE94sq(),
+ that was causing profile to fail when optimising
+ matrix and curves.
+
+* Bumped up the default profile smoothing factors,
+ as the resulting gamut boundaries were noticably
+ bumpy. Default profile -r is 0.5%, and internal
+ factors within rspl/scat.c have also been increased.
+ This seems to be favouring smoothness over accuracy
+ somewhat, but is still on the shallow part of the
+ "knee", where further increasing smoothness would
+ start to strongly decrease fit.
+
+* Fixed problem in profile (xicc/xlut.c) in locating
+ the black point. Doing one search is not robust
+ given the behaviour of many profiles, so
+ several searches are now used to avoid local
+ minima. The same fix is applied to xicc/mpp.c
+ (Thanks to Gerhard Fuernkranz for discovering
+ the problem.)
+
+* Fixed target/targen, link/icclink, xicc/iccgamut,
+ xicc/fakeCMY, xicc/revfx, xicc/xfbview and xicc/xicclu
+ to have estimated default ink limit values. Added input
+ profile ink limit options to link/icclink.
+
+* Added a function to icc/icc.c to estimate the
+ total link limit and per channel limits of
+ an ICC profile. This is to workaround the lack
+ of a standard tag in the ICC profiles.
+ A function built on top of this in xicc/xicc.c
+ (icxDefaultLimits()) established default total
+ and black ink limits for a profile.
+
+* Modified gammap.c & nearsmth.c to increase
+ the control over gamut mapping, and add new features.
+ The controll weightings within gammap.c are now
+ tables rather than #defines, and can be segmented
+ by color, to fine tune particular areas. Only
+ yellow uses this feature, to keep the gamut mapping
+ universal. Two aditional features have been added,
+ cusp mapping, that applies a degree of rotation to
+ areas surounding source primary/secondary colorant
+ cusps to partially align them with the destination
+ cusps. The radius of influence of this mapping is
+ settable. Another factor called "elevation" has been
+ added, that simulates the effect of inflating the
+ source gamut, allowing more complience in the
+ mapping of the control vectors.
+ Just perceptual and saturation tables are present.
+ In nearsmth, expansion of the gamut is finessed a little
+ by termporarily reversing the direction of the mapping
+ when expansion is present. There are lots of
+ other changes in nearsmth.c aimed at improving the robustness
+ and behaviour of the nearsmooth function.
+ The gammap tuning factors are aimed at providing good saturation
+ while maintaining smoothness at the gamut surface.
+
+* Added code to the gamut hull finding, to locate and
+ store the primary and secondary colorant "cusps" in
+ the gamut file, as well as adding options to
+ the various vrml utilities to mark the cusps.
+ The cusps can be used within the new gamut mapping
+ to align or partially align the colorants
+ of the source to the destination.
+
+* Modified gamut boundary code to improve detail and acuracy
+ of the gamut hulls. The smoothness of the destination
+ hull affects the smoothness of the resulting gamut
+ mapping to some degree.
+
+* Changed gamut mapping so that "full" neutral axis alignment
+ no longer aligns the black point a*b* to the destination.
+ The L/J range is mapped as if the black points are
+ fully aligned, so the contrast ratio is not compromised.
+ This approach seems to give a better subjective neutral result.
+ (There appears to be no such thing as black point hue adaptation.)
+
+* Modified enumerated viewing conditions list to tweak
+ ambient values slihtly, and introduce "monitor in bright
+ work environment".
+
+* Added new option to spectro/fakeread to allow manipulation
+ of the black point of the fake readings, to allow creation
+ of test profiles with different black points.
+
+* Added another numerical problem workaround to
+ xicc/cam02.c, to deal with Jab->XYZ issues when J == 0
+
+* Created utility render/itest to generate RGB test images
+ for checking gamut mapping behaviour.
+
+* Created new sub project "render", for a simple 2d raster rendering
+ system. This is intended for use in generating test images, as
+ well as rendering measurment test charts directly to rasters,
+ rather than just postscript.
+
+* Added a -m option to target/printtarg, so that the paper margins
+ can be increased from the default.
+
+* Added documentation for the .ti3 and .cal file formats.
+
+* Fixed bug in spectro/unixio.c, which caused long strips read
+ on the DTP41 on OSX or Linux to fail when spectral readings
+ were enabled. The canonical input buffer size was being exceeded.
+ Switched to non-canonical input mode. (Also seemed to fix
+ problem with Xon/Xoff flow control on OSX.)
+
+* Added flow control to serio I/O, to make instrument
+ communications more robust. Hardware handshaking
+ seems to be the most reliable (but see above).
+
+* Converted icc/fbtest into profile/invprofcheck,
+ and added some more features to make it comparible to
+ profile/profcheck.
+
+* Added VRML L*a*b* axis labels to gamut/viewgam, profile/*profcheck.
+
+* Increased gamut mapping RSPL smoothness, to compensate for
+ RSPL changes in V0.53. Smooths out bumps in saturation mapping
+ somewhat better, and should eliminate the "non-monotonic" warning
+ message.
+
+Version 0.53 changes (16 December 2005)
+--------------------
+
+* Fixed serious bug in target/ofps.c, that made
+ the default distribution of points very non-optimal.
+
+* Added CIEDE2000 Delta E function to icc/icc.c, and
+ also added this as an option to profile/profcheck,
+ profile/mppcheck and profile/verify.
+
+* Added new utilities rspl/smtmpp.c and profile/splitcgats.c
+ to allow testing and verification of profile optimised smoothness
+ factors with more realistic device data. Use splitcgats in
+ combination with profcheck and the hidden "-rs" flag in
+ profile to cross validate the optimised smoothness factors.
+
+* Added new "-r" parameter to profile/profile to allow
+ the profile smoothness factor to be adjusted to suite
+ the uncertaintly of the device and instrument readings.
+
+* Created more in depth simulation of device behaviour to
+ verify profiling operation (rspl/smtnd.c). Running this
+ indicated that no single smoothness factor will suite
+ all combinations of dimension, number of sample points
+ and sample point uncertainty. Create a interpolation table
+ lookup to provide an "optimised" smoothness factor,
+ determined from the simulations. Used new profile/splitcgats
+ to cross validate
+
+* Fixed serious bug in rspl/scat.c - new smoothness tracking
+ factors were seriously wrong. Figured out correct approach
+ and fixed it. Will affect various components including
+ profile, icclink and refine.
+
+* Added support for hexagonal layout of charts on XY instruments.
+ Supports aprox 14% more patches on the same sized chart.
+ Changed default patch size for Spectrolino to 7mm, since
+ this fits more patches on a page while remaining more
+ reliable than the 6mm patches used in charts such as the
+ ECI2002. (Changes to target/printtarg and spectro/printread)
+
+* Added extra check code for argument handling in link/icclink.c
+ - we now switch to appropriate linking mode if options that
+ require it are selected.
+
+* Added better algorithm for weakly tending rspl's to
+ a particular mapping. Added weak default function
+ API to scattered fit, and now make use of this
+ in tweak/refine. This should eliminate an "overshoot"
+ issue that was present with the simple grid of weak
+ mapping points previously used (Thanks to Gerhard Fuernkranz
+ for pointing out the problem.) Affects tweak/refine.
+ tweak/refine has also been afected by problems with RSPL
+ scattered data fit functionality - see above.
+
+* Modified spectro/dispcal.c to more acurately compute clip
+ of target white with device gamut, and also use matrix to
+ compute aprox. inverse more quickly and acurately, to
+ give faster and more accurate convergence. Needs some
+ more testing, may not work well on real monitors ?
+
+* Started adding support for ICC V4 Lab encoding into icc.c
+
+Version 0.52 changes (3 November 2005)
+--------------------
+
+* Added a display calibration utility, dispcal,
+ to create appropriate display lookup curves.
+ Modified dispread and profile to carry the display
+ curves through to the vcgt tag in the profile.
+ Not extensively tested yet.
+
+* Added spectro/spec2cie.c from Gerhard Fuernkranz.
+
+* Changed clut profile input and output curve optimisation
+ code to use conjgrad() instead of powell(). Aim was to
+ speed up profiling, but speed seems to be about even.
+ Added "optimise all" step since conjgrad() makes this
+ feasible, getting slightly better fit.
+
+* Modified the rspl code to support non-equal grid resolutions.
+ This was to support display calibration, but may come in handy
+ for support of V4 profiles. Noticed that the smoothness tracking
+ with different resolutions and dimensions wasn't working very well.
+ Improved the test code (c1, t2d, t3d) to help reveal this, and
+ fixed the problem. Now operates faster, more accurately, more
+ smooth output with a better fit to the input points. Should
+ improve the quality of forward profiles somewhat.
+ The fitting error is more noticably improved from -ql through -qu.
+ Gamut mapping seems to be a little smoother.
+
+* Completed the tweak/refine tool, useful for improving the accuracy
+ of proofing systems. Changes were made to profile, icclink and
+ revfix to support simple use of abstract correction profiles created
+ using refine.
+
+* Added option to printread, to allow CIE data to be saved
+ as D50 L*a*b*, for more flexibility for other purposes.
+
+* Fixed minor bug in DTP51 reading, where the guide setting
+ was wrong for strips with less than the 6 passes.
+ Also added fix code for DTP51 "off by one" patch
+ problem - the error should be corrected automatically.
+
+* Fixed problem in reverse lookup of per channel curves,
+ that affected performance of profile and icclink -G.
+ This problem became evident when CAM was switched to CIECAM02.
+ Note this problem seems only significant when CIECAM02 is used,
+ ie. when the -c and -d flags are used to specify viewing conditions.
+
+* Added support for alternate test patch indexing, to
+ better support non Argyll test charts (ie. ECI2002)
+
+* Renamed printspot to spotread, and expanded the range
+ of instrument modes supported.
+
+* Added emmisive measurement mode support to printspot.
+
+* Added independent Gretag Spectrlino/SpectroScan
+ interface library to cleanup some minor problems,
+ and add some more features (such as a fake transmission
+ measurement mode using a light table, etc.)
+
+* Added extra option to targen that allows creating test
+ points targetted at a specified portion of the devices
+ colorspace.
+
+* Fixed problem with imid & cctiff, where a profile that returns
+ device values > 1.0 causes pixel value wraparound.
+
+* Added an extra option to printtarg to scale the size of the test
+ patches. This can be used to allow for coarse screening, poor
+ registration, and packing more test patches onto a page.
+
+* Added extra support in fakeread to allow monochrome test charts to
+ be faked using RGB/CMYK profiles.
+
+* Added extra options to printtarg, to allow greyscale test charts to
+ be represented in a number of different postscript color representations.
+
+* Fixed bug in targen when > 4 colorants are used, and -v is turned on.
+ Diagnostic fails for > 4 colorants. (Thanks to Andrej Javorsek).
+
+* Fixed bugs in matrix/shaper profiling :- -ve offsets in shaper don't
+ make any sense, so removed them; weighting of parameter values was
+ faulty, so suppression of unsconstrained bumps in curves wasn't always
+ effective. This change may improve matrix/shaper profile quality slightly.
+
+Version 0.51 changes (11 March 2005)
+--------------------
+
+* Added new option to xicc/xicclu to allow plotting of the neutral
+ axis to examine black generation behaviour.
+
+* scanin has problems with new correlation code. Revert to
+ old code until problems are figured out.
+
+* Added support for a black channel ink limit
+ in nearly all utilities that currently support
+ a total ink limit.
+
+* Created cam02plot to explore discontinuities in
+ CIECAM02 conversions. To support this, the usage
+ of Helmholtz-Kohlraush effect is now a runtime flag.
+
+* A few changes in icc/ moving towards V4 support
+
+* Modify Jamfiles to support a more restricted "install" of
+ executables and other files to bin/
+
+Version 0.5 changes (7 November 2004)
+-------------------
+
+* Got the GUI and serial coms dependent parts running
+ under Mac OSX. Changes to Jambase and Jamfiles to make this work.
+
+* Modified Jambase to allow for Mac OSX Carbon GUI applications
+ needing a minimal resource fork to run properly.
+
+* Added incremental rspl scattered point suport, to allow
+ for us in an error driven targen point generation routine.
+
+* Added "EXTRAFIT" option to rspl, that allows for better fitting
+ to scattered data points that have a high error after normal
+ fitting. May improve profile accuracy when large test charts are used.
+
+* Add a special purpose "-f" and "-F" option to icclink, that causes
+ K only or all output for RGB/CMY in to CMYK out devices for neutral
+ (R=G=B) input.
+
+* Switched around gamut mapping high level controls into
+ a simple "Perceptual" and "Saturation" set of pre-canned
+ surface point weighting values. This allows more detail
+ in setting the two different styles. A saturation enhancement
+ control has also been made available, although this may need
+ a little more work to be fully effective.
+
+* Switched over to CIECAM02 for better blue gamut mappings.
+ Fix CIECAM02 so that it is robust given arbitrary Jab input values.
+
+* Fixed bug in gretag spectroscan print chart reader - it wasn't
+ recalibrating every 50 readings.
+
+* Added support in spectro/fakeread.c for a "separation" device
+ link profile to preceed the real device profile. This allows
+ simulating the response of a device that used an explicit
+ separation in its rendering pipeline.
+
+* Creating a hack CMY to CMYK separation creation support tool
+ called xicc/fakeCMY.c This creates a dummy CMY->PCS .ti3 file
+ from a CMYK device profile, that can then be turned into a CMY
+ device profile that can then be linked with the CMYK device profile
+ to create a CMY->CMYK device link separation profile. This program
+ will be redundant when profile/sepgen is completed.
+
+* Add support for the Spectrocam illuminant spectrum (Xenon Lamp),
+ even though this instrument is not supported directly. This
+ allows the FWA to be used on spectral readings from this instrument.
+ (Thanks to Gerhard Fuernkranz for providing this information).
+
+* Add method to gamut object to compute a gamuts volume,
+ and report the total volume in xicc/iccgamut if verbose
+ is set.
+
+* Modified scanin to work with scan of Gretag ColorCheckerDC.
+ Needed to modify edge detection filter to reduce noise,
+ modify edge matching code to support a wider range of
+ scales, change matching logic to ignore target edges
+ with no matching reference edge, stop using crossings
+ as part of edge matching.
+
+* Added new entries to test chart recognition template, to
+ allow scanin to determine correct rotation, even when the
+ chart has no asymetric elements. This works similarly
+ to the strip reading code, in checking correlation
+ between expected and measured color values.
+ Printtarg has also been modified to support
+ this new scan recognition template entries.
+
+* Fixed up Gretag Spectroscan operation so that
+ emission readings (for displays) etc. modes are
+ correctly set and calibrated.
+
+* Added new facility to cgats library, to allow for a
+ wildcard table keyword, as well as a variable "CGATS.XX"
+ table keyword.
+
+* Switched to CIE94 delta E for shaper/matrix profile
+ model fitting.
+
+* Introduce new flag ICX_CAM_CLIP to xicc, to allow full
+ accuracy lookups within gamut, and clipping in CAM Jab space
+ for out of gamut values. Turned this flag on in profile/profile,
+ to improve clipping behaviour of colorimetric B2A table, and
+ in link/icclink, to do the same for absolute and appearance
+ indents.
+
+* fix argument '-t' processing error in profile/profile.c
+
+* gamut/gammap.c: Change over to better vector alignment code.
+
+* Improved some of the black point handling precision in icclink
+ to reduce some innacuracies noticed by Gerhard Fuernkranz.
+
+* Modified Absolute Appearance intent to use
+ a common white point between the input and
+ output profiles, as well as scaling it to
+ Y = 1.0, to try and prevent Jab values
+ exceeding J = 100.0
+
+* Improved profile/logo2cgats to cope with the latest
+ formats of data files from Gretag. They seems to
+ have moved over to including the device values in
+ the readings file, just like Argyll :-).
+
+* Changed rspl/rev.c so that instead of failing
+ when it runs out of room to cache all the cells
+ being searched in a query, it proceeds with the
+ search in chunks. This allows the memory usage to
+ be curtailed, without risking the reverse lookup
+ being aborted. There will be a slight performance
+ loss if this happens though.
+
+* Fixed imdi/cctiff when linking profiles,
+ to not use explicit per channel curves when
+ the PCS is XYZ. This was causing excessive
+ quantization, because XYZ is a non-perceptual
+ space. (Same problem noticed in link/icclink some
+ time ago!)
+
+* Fixed old bug in target/ppoint.c,
+ that caused a crash under Linux in targen.
+ (Thanks to Greg Sullivan for bringing this to my attention.)
+
+* Improved robustness of cam97s3 some more,
+ some cases encountered in b2a table creation
+ triggered problems with out of range values.
+
+* Added grid range override for gamut creation,
+ to assist uniform handling of gamut compression
+ in b2a table creation.
+
+* Added perceptual and saturation gamut mapping
+ support to the profile creator (profile.c,
+ profout.c). This takes an input profile as a parameter,
+ to determine the necessary gamut mapping.
+
+* Added new function to icclib to allow setting
+ of up to 3 Lut tags simultaniously.
+ This is to allow the multiple intent B2A table
+ values to be set while getting the best possible speed
+ of inverse A2B lookup.
+
+* Added two new functions (fwd_relpcs_outpcs,
+ bwd_outpcs_relpcs) to xicclu, to allow
+ converting between native relative PCS and the
+ appearance space configured in the space conversion.
+ This is to allow converting to/from source/destination
+ CAM Jab space for gamut mapping during profile creation.
+
+* 2003/12/9 Unstable release
+
+* Started HTML documentation in the doc directory.
+ This is work in progress, and is not yet complete.
+ See doc/Index.html
+
+* Changed per channel curve algorithm in xicc/profout.c,
+ xicc/mpp.c and xicc/xmatrix.c, to improve accuracy
+ of profile, and markedly reduce "wiggles" in certain
+ cases, as well as improving the accuracy of the
+ profile compared to the "true" underlying device
+ characteristic. Changed how the white point is preserved
+ once again, this time by simply adjusting the order 0
+ a*b* curve harmonic to map 0.0 to 0.0. Tuned curve
+ weighting. Checked that the rspl scatterd data smoothing
+ default is still an approproate compromise.
+
+* Added support for a TI3 file as reference for
+ profile/fakeread, to improve reference set generation.
+
+* Fixed a bug that was causing the A2B output curve
+ ranges to be excessive (160%, rather than the intended
+ 110%). Altered profile/profile.c to remove the code that disables
+ the use of A2B output curves when a high quality B2A is needed,
+ now that there is a way of ensuring that the a*b* curves go
+ through 0.0.
+
+* Tweaked xicc/mpp.c to improve accuracy with
+ a very small number of points, by improving the
+ sophistication of its estimation of ink 100% overlap
+ values in the "anchor points" (which become defaults
+ if measured values are missing), as well as strengthening
+ the weight given to minimising the transfer curve and
+ ink interaction "shape" values.
+
+* Added comment support in icclink, similar
+ to that in profile.
+
+* Added support for MPP profile in profile/fakeread,
+ to permit a simple way of creating an ICC profile
+ from an MPP profile for <= 4 colorants. Spectral
+ values can be generated using an MPP profile.
+ This provides a path to creating a useful
+ profile when very few measurements are available.
+
+* Changed -n flag in profile/profile.c to allow
+ disabling input (-ni) and/or output (-no) clut lut
+ curves. This allows testing of the effects of
+ per channel curves.
+
+* Added -r flag to link/icclink.c to allow
+ overriding the device link clut resolution.
+
+* Add some filtering to the K locus curve
+ generation in profile, icclink etc., to smooth
+ out mixing behaviour. Transition to ink limiting
+ isn't smoothed at the moment.
+ This may improve problems with banded colorization,
+ but only if high resolution, reverse AtoB linking
+ is being performed.
+
+* Correct Gamut boundary table support has been added
+ to profile/profout.c, but isn't enabled or debugged yet.
+
+* Add spectral lookup support to mpplu.c utility.
+
+* Fix bug in spectro/dispread.c - we hadn't
+ updated it for the latest .ti1 format.
+
+* Added a special "simple" mpp model mode
+ to profile/mpprof.c and xicc/mpp.c,
+ to support a more simple Neugenbauer
+ like model for possible proofing standards use.
+
+* Added support in diagnostic plot for up to 6 curves,
+ with do_plot6() function.
+
+* Disable USE_MERGE_CLUT_OPT from icclink, since
+ it compromises accuracy, without a noticable
+ improvement in speed.
+
+* Added simple link support into cctiff
+ for convenience, and to serve as an
+ example of how to link and convert pixel data
+ in one step.
+
+* 2003/4/23 Unstable release
+
+* Modify gamut/gamut.c to #undefine ADD_EXTRA. This
+ code doesn't seem to add much, and seems to go
+ crazy with some profiles, using endless amounts
+ of memory.
+
+* Changed rev.c allocation code to make sure
+ doubles get allocated on their natural boundaries.
+ This may fix problems with some processors (MIPS).
+ (Thanks to Daniel Borenstein for pointing out the issue.).
+
+* Changed Absolute intent to clip in CIECAM97 space,
+ for improved out of gamut color handling.
+ (link/icclink.c, xicc/xicc.h, xicc/xicc.c, xicc/xlut.x xicc/xicclu.x).
+ CIECAM97 is tricked into an absolute mode
+ by forcing a D50 adapted white point for both source
+ and destination profiles. The other appearance
+ parameters still have an effect.
+
+* Hopefully removed the last problems involving
+ the confusion about whether RGB device values ranges
+ are 0-100 or 0-255. Argyll should now be consistent
+ in using 0-100 for all its CGATS data files.
+ [Changes mainly to scanin/scanin.c, plus warning
+ code in profile/profout.c and profile/profin.c]
+
+* Added support in targen for using an mpp model
+ to set test point distribution.
+
+* MPP profile format and creation now complete.
+ Using much more complicated derivative minimisation
+ equations to get adequate speed out of it.
+ Overall accuracy of the profiles hasn't yet been
+ established.
+
+* 2003/2/8 Unstable release
+
+* Added a slight refinement to the CIECAM97 model -
+ rather than using linear interpolation for computing
+ the eccentricity factor, use a spline blend
+ to smooth out the slight "kink" at the
+ knot points.
+
+* Updates mpp.c - work in progress.
+
+* 2002/12/25 Unstable release
+
+* Completed Gretag Macbeth Spectroscan support
+ for print profiling. Most changess in spectro/printread.c,
+ spectro/gretag.[ch] and spectro/spm.[ch].
+
+* Tuned gamut mapping to improve perceptual. Fixed
+ gamut/gammap.c so that separate luminance, chrominance
+ and hue weighting works properly. Added variable chrominance
+ weighting so that blues will be mapped with high L weight,
+ while yellows will map to closest. This exploits the
+ extra blue lightness added by allowing for the
+ Helmholtz-Kohlraush effect in conversion to CIECAM97 Jab
+ colorspace. Tweaked xicc/xicc.c gamut mapping control
+ parameters to improve perceptual and saturation
+ gamut mapping. Made extra gamut mapping surface point code
+ in gamut/gamut.c more robust so that it can be turned
+ on by default (since disabled again).
+
+* Added Helmholtz-Kohlraush effect modeling
+ in xicc/cam97s3, using the equation from
+ Bradford-Hunt 96C, as detailed in Mark Fairchilds
+ "Color Appearance Models". CIECAM97 was derived
+ from Bradford-Hunt 96S Simple model.
+ It turns out that this effect is crucuial in
+ gamut mapping CRT blues onto printing blues,
+ and making sure that they take into account
+ the subjective lightness of the highly saturated
+ CRT blue.
+
+* Added more elaborate "thru Black" controll to
+ link/icclink.c, allowing a CMYK to CMYK with a partial
+ through black. This is implemented using two
+ "upper" and "lower" limit black generation curves.
+
+* Added hack program profile/logo3 to
+ allow for a smaller number of test
+ sheets read on the Spectrolino.
+
+* Added new test point generation module
+ target/ifarp.c, an "Incremental Far Point"
+ generation algorithm, intended for N dimention
+ test chart generation. This is none too quick, but
+ seems to generate reasonably well distributed
+ test points at a steady rate. Any reasonable
+ algorithm in N dimensions needs to create test
+ points starting with some in gamut "seed" point,
+ as the valid gamut space becomes smaller and smaller
+ as N increases.
+
+* 2002/12/2 Unstable release
+
+* Increased imdi code to handle at least
+ 8 channels in and out.
+ Added tables to generate all
+ possible dimension combinations
+ in and out from 3 to 8.
+ Added -q and -s flags to itest to
+ increase testing speed.
+
+* Added full 16 bit processing support
+ to the imdi code. This also allows
+ the handling of > 4 channel input conversions.
+ Configured generation of 8 bit to 16 bit
+ conversion kernels. The per channel output
+ table value is 16 bits, useful for final device
+ linearisation without the penalty of 16 bit
+ precision thruout.
+ Cleaned up the cgen code to more gracefully
+ handle the differences between sort and simplex
+ table code, as well as better handle 64 bit
+ capability properly.
+
+* Changes imdi_gen to, by default generate
+ all the imdi kernel code in a single
+ file, reducing clutter. The -i flag
+ invokes the previous behaviour.
+
+* Added -w flag to icclink, which enables
+ a white point matching hack during linking.
+ If set, the white points are forced to match
+ regardless of the intent or gamut mapping.
+
+* Modified rspl to separate out the functions
+ that are limited in the maximum input
+ dimensions, and those that aren't,
+ so that some rspl functionality can
+ be used with larger numbers of colors.
+ This translates through to increased number
+ of colors support in some of xicc.
+
+* Fixed memory leak in imdi/imdi_tab.c
+ (thanks to Krzysztof Spera)
+
+* Merged back basic changes to support compiling
+ under Mac OSX. GUI and serial port dependent
+ code isn't finished though.
+
+* Made allowance in CGATS and icc
+ library for compiling without support
+ of the usual system file and memory
+ allocation calls, to increase flexibility
+ when using these libraries in non
+ standard environments.
+
+* Changed CGATS library to support
+ alternate allocator and/or file I/O,
+ for broader system compatibiliy.
+ Added error return codes for all methods,
+ to eliminate any calls to error().
+ Added new method error() to avoid having to
+ check every method for a return code.
+
+* Finished first cut at the model printer profile
+ object (xicc/mpp.[ch], profile/mpprof.c),
+ that supports profiling N color printing devices.
+ Note that ink modeling is not supported at the moment,
+ but there is enough support for optimised seprations.
+
+* Added -u flag to profile/profile,
+ that forces input Lut based profiles
+ to be stored as an absolute profile.
+ This is non-standard, but very useful for
+ avoiding Lab range clipping when using
+ a image as a colorimiter.
+
+* Added hack program profile/logo4 to
+ convert four separate spectral files read
+ using the logo software, to a single
+ argyll .ti3 file. This won't be needed
+ once Argyll can run the SpectroScan
+ directly.
+
+* Added numerical library support for
+ a Sobol sub-random multi-dimentional
+ sequence generator, to support an
+ alternate means of creating greater than
+ 4 dimentional test chart values, plus
+ first cut point support using it in
+ target/qrand.c (This doesn't seem useful in
+ practice though.)
+
+* Added -s option to iccdump to enable
+ searching and dumping embedded profiles.
+
+* Fix bug in profile white point adjustment
+ (xlut.c). The actual white point didn't
+ match the specified white point to the degree
+ of accuracy desired. There may also have been
+ issues with clipping values in Lab PCS.
+
+* Added option to spectral to CIE module to
+ compensate for the presense of FWA (Fluorescent
+ Whitener Additive) in paper. This improves the
+ accuracy of the CIE color values when a media
+ measured under one illuminant is going to be
+ viewer under a different illuminant. This works
+ if you are using a spectral measurment instrument.
+ (See poster in proceedings of the IS&T/SID
+ 11th Color Imaging Conference, November 2003 page 248).
+
+* Added shaper/matrix input profile support.
+ (profile/profin.c, xicc/xmatrix.c)
+ This may be more accurate for scanner profiles,
+ given the poor coverage of test points provided
+ by an IT8 chart (but doesn't appear to be in practice).
+
+* Added support in scanin.c and scanrd.c for
+ processing 16 bit TIFFs, allowing for higher
+ precision scans (useful when using the image to
+ measure color).
+
+* Added support in scanin.c and scanrd.c for
+ using a scan of a print test chart, plus a
+ profile for the scanner, to be able to measure
+ color for printer calibration. This
+ new mode handles multi-page test charts.
+
+* Added support in printtarg, for producing a scan
+ recognition template (.cht) for each page.
+
+* Added patch optimisation module to target/printtarg,
+ to arrange patches to maximise their contrast for
+ strip reading instruments.
+
+* Removed the color directory, since it's functionality
+ has been taken over by the xcolorants library,
+ and the (yet to be completed) MPP profile library.
+
+* Added DTP41T (tranmission) support in target/printtarg.c
+ and spectro/printread.c etc.
+
+* Made changes to target/targen.c, target/printtarg.c
+ and spectro/printread.c to be able to generate
+ and then read >4 color test charts, to be able to
+ characterise 6 to 8 color devices.
+
+* Added support in xicc/xspect.c for measuring
+ StatusT and Visual density from a spectral
+ reading, as well as an aproximate XYZ to
+ density conversion, to support spectrometer
+ patch spacer contrast determination.
+ Also added an XYZ to sRGB conversion
+ function to support RGB previews of N color
+ devices, as well as scanner recognition template files.
+
+* Expanded xicc/xcolorants.c to incorporate
+ an approximate device model for arbitrary
+ colorant combinations. This is used to
+ be able to approximate expected density readings,
+ as well as preview colors and scanner recognition templates.
+
+* Create a new test point creation module,
+ target/simplat.c, to create higher dimentional,
+ regular simplex latice test pointsi (this seems
+ rather slow and has difficulty arriving at the
+ desired number of test points.)
+
+
+Fourth snapshot changes: (25 March 2002)
+------------------------
+
+* Removed gamut/iccgamut, and renamed
+ xicc/xiccgamut to xicc/iccgamut.
+
+* Modified tiffgamut to be able to emit CIECAM97 style
+ colorspace gamuts, so that it can be used to
+ generate appropriate gamut files as input to
+ icclink. Moved it to the xicc subdirectory,
+ as it depends on xicc, just like xiccgamut.
+
+* Fixed up icclink.c, gammap.c and nearsmth.c to
+ more correctly handle gammut mapping for a particular
+ image gamut, rather than a source colorspace.
+
+* Added text description option to profile utility.
+
+* Made significant modifications to the perceptual
+ gamut mapping. Turned gammap into an object, rather
+ than merely returning a rspl to allow for a separate
+ L mapping step. Added #define to control this.
+ Made the source to destination surface point a weighted
+ optimisation algorithm for more control over the absolute
+ vs. relative error introduced, and setup some initial
+ weighting values. This is intended to combat the
+ tendency of the "smallest absolute error" mapping
+ to map many to one in the most saturated regions,
+ leading to a loss of detail. The weighting scheme
+ could probably use some more fine tuning, or even
+ some alteration to make it vary with respect to (say)
+ the absolute L value, or the absolute C value.
+
+* Added first cut at a model based forward profile
+ creation (profile/mpprof.c). This is intended for
+ profiling 6 or more color devices, and using as
+ the profile driving optimised separations.
+
+* Added xcolorants resource to allow specifying and defining
+ device colorant combinations. This is needed as a foundation
+ to profiling 6 or more color printing devices.
+
+* Tweaked targen to concentrate test patch points
+ at regions of higher curvature. This should improve profiling
+ efficiency slightly.
+
+* Fix bug in xlut.c where creating a gamut cleared
+ any ink limit set on a rspl. This caused the ink limit
+ to be ignored in any icclink that used gamut mapping.
+
+* Modified printtarg.c to try and get more reliable
+ DTP41 operation. Switch to black and white patch
+ spacers by default. It's difficult to know what the
+ instrument really requires to reliably pick up
+ the test spacers.
+
+* Fixed bug in gamut where it was still hanging on to
+ vertex points that disapear below the log convex hull.
+ This has no consequences.
+
+* Added option in icclink to allow specifying an explicit source
+ gamut for the gamut mapping. This allows tailoring the gamut
+ compression to be optimised for a particular image.
+
+* Added profile checking utility, that checks measured device points
+ against an icc profile.
+
+* Fixed probem with linking when any of the profiles native PCS is XYX.
+ The device linearisation curve should not be preserved if the
+ native device profile PCS is XYZ.
+
+* Fixed bug in xmatrix.c & xmono.c when finding the gamuts of
+ matrix and mono transforms when a Bwd transform is used.
+ Showed up in icclink when the output profile was a matrix
+ of monochrome transform.
+
+* Fixed bug in icclib when PCS overide is used with a
+ Bwd transform. Similar problem to above for matrix & mono
+ profiles, but at the icclib level.
+
+* Added function in icclink.c to allow the generation of
+ a device linearisation curve for XYZ profiles. This was
+ expected to improve the result when linking to XYZ profiles,
+ but currently seems to make things worse. This feature is
+ therefore off by default. :-( (This should be changed
+ to work the same as the current xlut.c profile code!)
+
+* Added preliminary support in printtarg for the SpectroScan
+ spectrodensitometer. Also added preliminary support for
+ scanner recognisable test charts.
+
+* Added option to icclink to turn off the use of linearisation
+ curves in the output link, since this sometimes seems to
+ make the accuracy worse given profiles with odd device
+ linearisation curves.
+
+* Added custom page size support to printtarg.
+
+* Modified icc library defines to use INR32 rather than INT32
+ definition, to avoid clashes with system typdefs etc.
+
+* Added CIE94 delta E support to profchek utility, changed
+ peak reading to be peak delta E rather than peak individual
+ L, a or b, and made the same change in the check code
+ in profout.c
+
+* Added utility to do reflective spot readings using appropriate
+ instrument (printspot). DTP41 supported.
+
+* Fixed bug in profile.c that meant that the spectral mode
+ was ignored unless an observer was specified (ie. it wasn't
+ defaulting to 1978_2).
+
+* Modified targen.c so that when a previous profile is used
+ to pre-condition test points, the neutral axis has a higher
+ density of points, in line with the higher sensitivity the
+ CIE94 delta E formula has in this region. This should improve
+ the tolerance of the resulting profile in the important
+ neutral gray area.
+
+* Fixed bug in printread.c that is triggered when more than
+ 26 strips are being read.
+
+* Modified targen.c so that the 4 dimentional auxiliary chanel
+ weighting (ie. K chanel in CMYK) is 150% of the Lab spacing,
+ rather than being 50% of it, when ICC profile pre-conditioning
+ is being used. This seems to improve both the worst case, and
+ average error of the resulting profile for at least some devices.
+
+* Switched to (now working) xlut2.c code, for creating clut
+ based profiles. This version creates both input and output
+ 1D luts by optimising the accuracy of the profile for a linear clut.
+ The result seems to be more accurate profiles, since the underlying
+ device characteristic is better modeled. It also seems to aleviate
+ some of the issues when linking and preserving the device 1D luts
+ in the linked profile.
+
+* Added verification function to icclink.c, to check the
+ accuracy of a link profile.
+
+* Fixed numsup.c 2d array malloc/free to be more efficient
+ by allocating the main array as a single block.
+
+* Fixed bugs in handling XYZ lut based profiles.
+
+* Fixed bug in setting white and black points for input
+ profiles.
+
+* Added support for selecting algorithm type for all
+ types of profiles - input, display and output.
+ (XYZ lut doesn't seem to work properly yet though!)
+
+* Merged Raph Levien's cleanups to icc.c, to quiet gcc
+ warnings.
+
+* Improved new xlut2.c to handle pathalogical input data
+ from gridded charts. The order of the curves is now
+ adjusted so that it is not greater than what can
+ be supported by the data. Also changed shaper curve
+ parameter action to be more progressive, and tied
+ the parameters into the optimisation goal so that
+ parameters that have no effect are minimised, resulting
+ in less "ringing". Fixed bug in shaper curve transform
+ that was clipping parameters, resulting in gross errors
+ before the white point was exactly fixed on.
+
+* Added new features to profcheck: Sorting feature to
+ indicate support for a particular device->pcs value,
+ + VRML output of errors between profile and datapoints.
+
+* Modified scanin/scanrd to allow for Grey and CMYK .tiff
+ files, as well as just outputing a CGATS data file,
+ rather than only performing the data collection needed
+ for and RGB scan calibration. This is useful for capturing
+ the patch values from a test chart only available as a
+ TIFF file. Removed automatic extention stuff.
+
+* Added black wedge generation to targen, and extra checking
+ to elminate redundant test patches.
+
+* Added EPS output support to printtarg.
+
+* Added a couple of options to cctiff to aid diagnostics.
+
+
+Third snapshot changes: (17 July 2001)
+----------------------
+
+* Changed targen to allow full spread test points to take account
+ of the others sorts of test points.
+
+* Changed icclib to use the Bradford chromatic adaption for
+ white point shifting in profile creation and absolute profiles
+ lookup. This creates some minor incompatiblity with profiles
+ produced with earlier versions, but is likely to be more
+ compatible with other CMMs.
+
+* Added support in icclib for abstract file accesor type (icmFile), and included
+ implementations for standard file and memory image.
+
+* Added support in icclib for abstract memory allocator, and included
+ implementation for standard alloc/free.
+
+* 25/2/2001 Changed targen to use ICC profile for perceptual even
+ point generation. Includes support for Gray and RGB as well as CMYK
+ perceptual support.
+
+* Film profiling using the Spectroscan-T care of Niel Okamoto.
+
+* Print charts suitable for the Xrite DTP41 are
+ now supported, and print chart reading using the DTP41
+ is now supported.
+
+* Added DTP92 support and Lut and matrix profile support for
+ display profiles.
+
+* Added spectral reading support to the DTP41 readings.
+
+* Added support in profile for using spectral data with choice
+ of observers and builtin or loadable illuminant spectra.
+
+* Modified the gammap code to precicely match the white and black
+ points. Solves "background color" problems in linking RGB and CMYK etc.
+
+* Changed K generation curve parameters to be easier to control.
+ Have two breakpoints and curve shape along the luminance axis.
+
+* Added more sophisticated auxiliary chanel locus finder in rspl/rev.c,
+ to be able to detect profile anomolies (not made use of in current code).
+
+* Added underlying support for optimised separations into
+ 4 to 8 separations in rspl/opt.[ch] . This is intended to be
+ used internally as an option for driving a CMYK device, and
+ also explicitly to support 6 or more color devices. Not tested
+ or made use of just yet.
+
+* Added development area for Java GUI development. The intention
+ is to use Java as a sophisticated scripting front end, to
+ make the command line commands more palatable.
+
+Second snapshot changes: (30 November 2000)
+------------------------
+
+ Neil Okamoto has contributed support for generating
+ RGB TIFF targets suitable for film recorder output,
+ as well as Gretag Spectrolino support for reading them
+ in again.
+
+ The target patch generation now uses ICC profile to
+ pre-condition the test points. This now works for
+ RGB and Grey targets.
+
+ Finished port to Linux.
+ Cleaned up build automation somewhat.
+
+ Added RGB output device profile generation support.
+ Added RGB scanner device profile generation support.
+
+ Added a couple of spectrometer conversion utilities for
+ raw data files from other CMSs.
+
+ Added gamut boundary mapping and visualization tools (VRML)
+
+ Added CIECAM97s Color Appearance Model (CAM) colorspace support.
+
+ Added experimental gamut mapping code.
+
+ Enhanced linker to use CAM and gamut mapping.
+
+ Numerous bug fixes and enhancement.
+
+First snapshot (28 October 2000)
+--------------
diff --git a/m4/libtool.m4 b/m4/libtool.m4
new file mode 100644
index 0000000..02b4bbe
--- /dev/null
+++ b/m4/libtool.m4
@@ -0,0 +1,7991 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable. If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins. After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script. The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ _LT_PROG_REPLACE_SHELLFNS
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Go], [_LT_LANG(GO)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_GO. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC], [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+ fi
+fi
+if test -z "$GOC"; then
+ AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+ [LT_LANG(GO)],
+ [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS="$save_LDFLAGS"
+ ])
+
+ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+ [lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+ echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+ $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+ [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ m4_if([$1], [CXX],
+[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+ lt_aix_libpath_sed='[
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }]'
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi],[])
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+ fi
+ ])
+ aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+case "$ECHO" in
+ printf*) AC_MSG_RESULT([printf]) ;;
+ print*) AC_MSG_RESULT([print -r]) ;;
+ *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test "X`printf %s $ECHO`" = "X$ECHO" \
+ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[ --with-sysroot[=DIR] Search for dependent libraries within DIR
+ (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted. We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+ if test "$GCC" = yes; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ AC_MSG_RESULT([${with_sysroot}])
+ AC_MSG_ERROR([The sysroot must be an absolute path.])
+ ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD="${LD-ld}_sol2"
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+ [lt_cv_ar_at_file=no
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+ [echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([lt_ar_try])
+ if test "$ac_status" -eq 0; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ AC_TRY_EVAL([lt_ar_try])
+ if test "$ac_status" -ne 0; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+ ])
+ ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+ [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+ [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+ [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+ test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='${libname}.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec="$LIB"
+ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[23]].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+ [lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [lt_cv_shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+ ])
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+ [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+ [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test "$GCC" != yes; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+ [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+ [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+ AC_SUBST([DUMPBIN])
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh
+ # decide which to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+ [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+ [lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+ MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+ esac
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT@&t@_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data. */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT@&t@_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+ [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd* | netbsdelf*-gnu)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+ if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Intel*\ [[CF]]*Compiler*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ *Portland\ Group*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global defined
+ # symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ case $cc_basename in
+ cl*)
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ m4_if($1, [], [
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ _LT_LINKER_OPTION([if $CC understands -b],
+ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+ [lt_cv_irix_exported_symbol],
+ [save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE(
+ [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+ [C++], [[int foo (void) { return 0; }]],
+ [Fortran 77], [[
+ subroutine foo
+ end]],
+ [Fortran], [[
+ subroutine foo
+ end]])])],
+ [lt_cv_irix_exported_symbol=yes],
+ [lt_cv_irix_exported_symbol=no])
+ LDFLAGS="$save_LDFLAGS"])
+ if test "$lt_cv_irix_exported_symbol" = yes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ fi
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+ [$RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ ])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+ [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report which library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_CFLAGS=$CFLAGS
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ CFLAGS=$CXXFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $GXX,$cc_basename in
+ ,cl* | no,cl*)
+ # Native MSVC
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # g++
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd2.*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+ '"$_LT_TAGVAR(reload_cmds, $1)"
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)="$GXX"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case ${prev}${p} in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ fi
+
+ # Expand the sysroot to ease extracting the directories later.
+ if test -z "$prev"; then
+ case $p in
+ -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+ -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+ -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+ esac
+ fi
+ case $p in
+ =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+ esac
+ if test "$pre_test_object_deps_done" = no; then
+ case ${prev} in
+ -L | -R)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ prev=
+ ;;
+
+ *.lto.$objext) ;; # Ignore GCC LTO objects
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+ _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${F77-"f77"}
+ CFLAGS=$FFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$G77"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+ CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+ _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${FC-"f95"}
+ CFLAGS=$FCFLAGS
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,b/c, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+ _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac])
+
+ _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+ func_basename_result="${1##*/}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+ func_split_long_opt_name=${1%%=*}
+ func_split_long_opt_arg=${1#*=}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+ func_split_short_opt_arg=${1#??}
+ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac])
+
+ _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo])
+
+ _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))])
+
+ _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+ _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+ func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+ eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+ # Save a `func_append' function call where possible by direct use of '+='
+ sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+else
+ # Save a `func_append' function call even when '+=' is not available
+ sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+ AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+ [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+ [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4
new file mode 100644
index 0000000..5d9acd8
--- /dev/null
+++ b/m4/ltoptions.m4
@@ -0,0 +1,384 @@
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for lt_pkg in $withval; do
+ IFS="$lt_save_ifs"
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4
new file mode 100644
index 0000000..9000a05
--- /dev/null
+++ b/m4/ltsugar.m4
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/m4/ltversion.m4 b/m4/ltversion.m4
new file mode 100644
index 0000000..07a8602
--- /dev/null
+++ b/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4
new file mode 100644
index 0000000..c573da9
--- /dev/null
+++ b/m4/lt~obsolete.m4
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/makeall.bat b/makeall.bat
new file mode 100644
index 0000000..fe99e59
--- /dev/null
+++ b/makeall.bat
@@ -0,0 +1,5 @@
+echo Simple batch file to invoke Jam from the top
+jam -q -fJambase -j%NUMBER_OF_PROCESSORS%
+rem If you have trouble with the parallel build, try the
+rem version with only one thread.
+rem jam -q -fJambase
diff --git a/makeall.sh b/makeall.sh
new file mode 100644
index 0000000..eb4ac7d
--- /dev/null
+++ b/makeall.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+echo "Script to invoke Jam from the top"
+
+if [ X$OS != "XWindows_NT" ] ; then
+ # Fixup issues with the .zip format
+ chmod +x *.sh
+fi
+
+# Make sure that some environment variable are visible to Jam:
+export OSTYPE MACHTYPE HOSTTYPE
+
+jam -q -fJambase -j${NUMBER_OF_PROCESSORS:-2}
diff --git a/makeinstall.sh b/makeinstall.sh
new file mode 100644
index 0000000..be2b03d
--- /dev/null
+++ b/makeinstall.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+echo "Script to invoke Jam from the top and install"
+echo "binaries in the ./bin directory and samples into the ref ./directory"
+
+if [ X$OS != "XWindows_NT" ] ; then
+ # Fixup issues with the .zip format
+ chmod +x *.sh
+fi
+jam -q -fJambase -j${NUMBER_OF_PROCESSORS:-2} install
diff --git a/makepackagebin.sh b/makepackagebin.sh
new file mode 100644
index 0000000..64a1d12
--- /dev/null
+++ b/makepackagebin.sh
@@ -0,0 +1,173 @@
+#!/bin/sh
+echo "Script to invoke Jam and then package the binary release."
+
+# Typical environment variables:
+# (NOTE some systems don't export these ENV vars. by default !!!)
+#
+# Platform $OSTYPE $MACHTYPE $HOSTTYPE
+#
+# Win2K [CMD.EXE] (none) (none) (none)
+#
+# Cygwin Win2K [bash] cygwin i686-pc-cygwin i686
+#
+# OS X PPC 10.3 [zsh] darwin7.0 powerpc (none)
+#
+# OS X i386 10.4 [bash] darwin8.0 i386-apple-darwin8.0 i386
+#
+# OS X i386 10.5 [bash] darwin9.0 i386-apple-darwin9.0 i386
+#
+# OS X i386 10.6 [bash] darwin10.0 x86_64-apple-darwin10.0 x86_64
+#
+# OS X i386 10.7 [bash] darwin11 x86_64-apple-darwin11 x86_64
+#
+# Linux RH 4.0 [bash] linux-gnu i686-redhat-linux-gnu i686
+#
+# Linux Fedora 7.1 [bash] linux-gnu i386-redhat-linux-gnu i386
+# Linux Ubuntu ??7 linux-gnu i486-pc-linux-gnu i686
+#
+# Linux Fedora 7.1 64 bit [bash] linux-gnu x86_64-redhat-linux-gnu x86_64
+# Ubuntu 12.10 64 bit [bash] linux-gnu x86_64-pc-linux-gnu x86_64
+#
+# FreeBSD 9.1 64 bit [bash] freebsd9.1 amd64-portbld-freebsd9.1 amd64
+#
+
+# Set the environment string VERSION from the #define, ie 1.0.0
+VERSION=`grep ARGYLL_VERSION_STR h/aconfig.h | sed 's/#define ARGYLL_VERSION_STR //' | sed 's/"//g'`
+
+echo "About to make Argyll binary distribution"
+
+TOPDIR=Argyll_V$VERSION
+
+if [ X$OS != "XWindows_NT" ] ; then
+ # Fixup issues with the .zip format
+ chmod +x *.sh
+fi
+
+# Make sure that some environment variable are visible to Jam:
+export OSTYPE MACHTYPE HOSTTYPE
+
+# .sp come from profile, .cht from scanin and .ti3 from spectro
+rm -f bin/*.exe bin/*.dll
+rm -f ref/*.sp ref/*.cht ref/*.ti2
+
+# Make sure it's built and installed
+if ! jam -q -fJambase -j${NUMBER_OF_PROCESSORS:-2} -sBUILTIN_TIFF=true -sBUILTIN_JPEG=true install ; then
+ echo "Build failed!"
+ exit 1
+fi
+
+# Maybe we could get Jam to do the following ?
+
+if [ X$OS = "XWindows_NT" ] ; then
+ echo "We're on MSWindows!"
+ # Hack cross comile
+ if [ X$COMPILER = "XMINGW64" ] ; then
+ echo "We're cross compiling to MSWin 64 bit !"
+ PACKAGE=Argyll_V${VERSION}_win64_exe.zip
+ USBDIRS="usb"
+ USBBINFILES="binfiles.msw"
+ unset USETAR
+ else
+ # ~~ should detect native 64 bit here ~~
+ echo "We're on MSWin 32 bit !"
+ PACKAGE=Argyll_V${VERSION}_win32_exe.zip
+ USBDIRS="usb"
+ USBBINFILES="binfiles.msw"
+ unset USETAR
+ fi
+else if [ X$OSTYPE = "Xdarwin7.0" ] ; then
+ echo "We're on OSX 10.3 PPC!"
+ PACKAGE=Argyll_V${VERSION}_osx10.3_ppc_bin.tgz
+ USBDIRS="usb"
+ USBBINFILES="binfiles.osx"
+ USETAR=true
+else if [ X$OSTYPE = "Xdarwin8.0" ] ; then
+ if [ X$MACHTYPE = "Xi386-apple-darwin8.0" ] ; then
+ echo "We're on OSX 10.4 i386!"
+ PACKAGE=Argyll_V${VERSION}_osx10.4_i86_bin.tgz
+ else if [ X$MACHTYPE = "Xpowerpc-apple-darwin8.0" ] ; then
+ echo "We're on OSX 10.4 PPC!"
+ PACKAGE=Argyll_V${VERSION}_osx10.4_ppc_bin.tgz
+ fi
+ fi
+ USBDIRS="usb"
+ USBBINFILES="binfiles.osx"
+ USETAR=true
+else if [ X$OSTYPE = "Xdarwin10.0" \
+ -o X$OSTYPE = "Xdarwin11" ] ; then
+ if [ X$HOSTTYPE = "Xx86_64" ] ; then
+ echo "We're on OSX 10.6 x86_64!"
+ PACKAGE=Argyll_V${VERSION}_osx10.6_x86_64_bin.tgz
+ fi
+ USBDIRS="usb"
+ USBBINFILES="binfiles.osx"
+ USETAR=true
+else if [ X$OSTYPE = "Xlinux-gnu" ] ; then
+ if [[ "$MACHTYPE" =~ x86_64-.*-linux-gnu ]] ; then
+ echo "We're on Linux x86_64!"
+ PACKAGE=Argyll_V${VERSION}_linux_x86_64_bin.tgz
+ else if [[ "$MACHTYPE" =~ i.86-.*-linux-gnu ]] ; then
+ echo "We're on Linux x86!"
+ PACKAGE=Argyll_V${VERSION}_linux_x86_bin.tgz
+ fi
+ fi
+ USBDIRS="usb"
+ USBBINFILES="binfiles.lx"
+ USETAR=true
+fi
+fi
+fi
+fi
+fi
+
+if [ X$PACKAGE = "X" ] ; then
+ echo "Unknown host - build failed!"
+ exit 1
+fi
+
+echo "Making GNU Argyll binary distribution $PACKAGE for Version $VERSION"
+
+rm -rf $TOPDIR
+mkdir $TOPDIR
+
+# Collect the names of all the files that we're going to package
+unset topfiles; for i in `cat binfiles`; do topfiles="$topfiles ${i}"; done
+unset docfiles; for i in `cat doc/afiles`; do docfiles="$docfiles doc/${i}"; done
+unset usbfiles;
+for j in ${USBDIRS}; do
+ if [ ${j} ]; then
+ for i in `cat ${j}/${USBBINFILES}`; do usbfiles="$usbfiles ${j}/${i}"; done
+ fi
+done
+
+allfiles="${topfiles} bin/* ref/* ${docfiles} ${usbfiles}"
+
+# Copy all the files to the package top directory
+for i in ${allfiles}; do
+ path=${i%/*} # extract path without filename
+ file=${i##*/} # extract filename
+ if [ $path = $i ] ; then
+ path=
+ fi
+ if [ X$path != "X" ] ; then
+ mkdir -p $TOPDIR/${path}
+ fi
+ cp $i $TOPDIR/$i
+done
+
+# Create the package
+rm -f $PACKAGE
+if [ X$USETAR = "Xtrue" ] ; then
+ tar -czvf $PACKAGE $TOPDIR
+ # tar -xzf to extract
+ # tar -tzf to list
+else
+ zip -9 -r $PACKAGE $TOPDIR
+ # unzip to extract
+ # unzip -l to list
+fi
+rm -rf $TOPDIR
+echo "Done GNU Argyll binary distribution $PACKAGE"
+
+exit 0
+
diff --git a/missing b/missing
new file mode 100644
index 0000000..cdea514
--- /dev/null
+++ b/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2012-06-26.16; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'automa4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/notes.txt b/notes.txt
new file mode 100644
index 0000000..c15e076
--- /dev/null
+++ b/notes.txt
@@ -0,0 +1,118 @@
+Misc technical notes
+--------------------
+
+
+Things I'd like to standardise
+------------------------------
+
+ICC:
+ Tag for TAC. Should include all combination of colorant
+ summs limits. Should be min and max ?
+ Option for LUT for abitrary limit (similar to gamut LUT).
+
+ Tag for 3D gamut Hull using triangles.
+
+ Standard rendering intent encodings, to be used as basis
+ of extra per color component attribute. Backward compatible
+ with current ICC rendering intents ?
+ Use "schemes" too, to allow for future changes.
+
+ Spectral sub-tag for spectrum encoding.
+
+ New named color using spectral.
+
+ New colorant tag using spectral.
+
+Other:
+ Add rendering intent plane support to TIFF etc.
+
+
+ICC profile locations in various operating systems.
+---------------------------------------------------
+
+Someone emailed me about a standard Linux location for ICC profiles,
+and I decided to research this a little more than has been done in
+the past, so though others might be interested in the results.
+
+> I was wondering if you are aware of any standard location in the Linux
+> filesystem to put ICC profiles?
+
+There was some discussion about this on the OpenICC mailing list a while
+back:
+
+Stefan Klein wrote:
+> Marti Maria, developer of littlecms (www.littlecms.com), suggested
+> /usr/share/color/icc and ~/.color/icc as intuitive paths. We decided to
+> go along with this.
+
+Kai-Uwe Behrmann wrote:
+> I followed the suggestions of using
+> /usr/share/color for global configuration data and
+> /usr/share/color/icc for global ICC profiles
+> ~/.color and ~/.color/icc as user pendant.
+
+Googling for "common Linux ICC profile directory" brings up other references.
+
+For instance Scribus puts its profiles in
+
+ /usr/local/share/Scribus/profiles
+
+
+SUN has been implementing CMM's on its Solaris system
+for a long while (using Kodaks KCMS), and have already
+established other conventions in its part of the the Unix world:
+> 1. The current directory
+> 2. Directories listed by the KCMS_PROFILES environment variable, which is a
+> colon-separated list of directories
+> 3. /etc/openwin/devdata/profiles
+> 4. /usr/openwin/etc/devdata/profiles
+as well as having extensive support for ICC profiles in Java, on multiple
+platforms (again using KCMS and the native platform CMM's it seems).
+
+
+SGI has a CMM called Coloratura on their IRIX Unix system, and uses
+yet another convention:
+> The Coloratura CMS searches for a file sequentially in the directories specified
+> by the environment variable CMS_DEFAULT_PATH, which is a colon-separated list of
+> pathnames similar to that used in the environment variable MANPATH.
+> The value of CMS_DEFAULT_PATH defined in cms.h is
+> /var/cms/profiles/local:/var/cms/profiles:.,
+> which allows you to place profiles you prefer in /var/cms/profiles/local,
+> and generic profiles, which might have the same names, in
+> /var/cms/profiles or your working directory.
+
+
+Apple in OSX (another Unix based system) chooses
+
+ /Library/ColorSync/Profile
+ /System/Library/Colorsync/Profiles
+ /Network/Library/ColorSync/Profiles
+ ~/Library/ColorSync/Profiles
+
+and individual drivers store relevant profiles in their application
+resources: eg.
+
+ /Library/Image Capture/Devices/EPSON SScanner.app/Contents/Resources/
+and
+ /Library/Printers/Canon/BJPrinter/PMs/BJC8200PM.plugin/Contents/Resources/
+and
+ /Library/Printers/hp/Profiles
+and many other places.
+
+Microsoft Windows chooses:
+
+\WINDOWS\SYSTEM\COLOR
+\WINNT\SYSTEM32\COLOR
+\WINNT\SYSTEM32\SPOOL\DRIVERS\COLOR
+
+depending on the operating system version.
+Photoshop on MSWindows seems to use its own location:
+
+\Program Files\Common Files\Adobe\Color\Profiles
+
+Note that Apple ColorSync, Microsoft ICM2.0 and KCMS as implemented
+by SUN are all existing CMM's with detailed technical documentation
+available via the web (as examples of how it has been done, and the variety
+of facilities a CMM may make available.)
+
+
diff --git a/numlib/Jamfile b/numlib/Jamfile
new file mode 100644
index 0000000..dd90e22
--- /dev/null
+++ b/numlib/Jamfile
@@ -0,0 +1,28 @@
+
+# Jamfile for the numlib and other general utilities
+
+# Optization state and configuration. Overridden by parent-Jamfiles
+
+PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+#PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ;
+#PREF_CCFLAGS = $(CCPROFFLAG) ; # Profile flags
+#PREF_LINKFLAGS = $(LINKPROFFLAG) ; # Profile flags
+
+# Products
+Libraries = libnum ;
+Headers = numlib.h ;
+
+#Install
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+# Numeric library
+Library libnum.lib : numsup.c dnsq.c powell.c dhsx.c ludecomp.c svd.c zbrent.c rand.c sobol.c aatree.c ;
+
+# Link all utilities with libnum
+LINKLIBS = libnum ;
+
+# All test programs are made from a single source file
+MainsFromSources dnsqtest.c tpowell.c tdhsx.c LUtest.c svdtest.c zbrenttest.c soboltest.c ;
+
diff --git a/numlib/LUtest.c b/numlib/LUtest.c
new file mode 100644
index 0000000..feb2277
--- /dev/null
+++ b/numlib/LUtest.c
@@ -0,0 +1,113 @@
+
+/* Test the LU decomposition code */
+/*
+ * Copyright 1999 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.
+ */
+
+#include "numlib.h"
+
+int test(int n, double **a, double *b);
+
+int main() {
+ double **a;
+ double *b;
+ int n = 4;
+ int rv;
+
+ a = dmatrix(0, n-1, 0, n-1);
+ b = dvector(0, n-1);
+
+ a[0][0] = 1.0;
+ a[0][1] = 2.0;
+ a[0][2] = 3.1415926;
+ a[0][3] = 5.1415926;
+
+ a[1][0] = 3.0;
+ a[1][1] = 2.0;
+ a[1][2] = 4.0;
+ a[1][3] = -0.1;
+
+ a[2][0] = -1.0;
+ a[2][1] = 0.5;
+ a[2][2] = 1.0;
+ a[2][3] = 1.5;
+
+ a[3][0] = 11.0;
+ a[3][1] = 9.0;
+ a[3][2] = 15.0;
+ a[3][3] = 0.9;
+
+ b[0] = 6.0;
+ b[1] = 4.0;
+ b[2] = 4.5;
+ b[3] = -10.0;
+
+ if ((rv = test(n, a, b)) != 0) {
+ if (rv == 1)
+ printf("LU test failed due to singularity\n");
+ else {
+ printf("LU test failed to verify\n");
+ printf("Got solution %f %f %f %f\n",b[0],b[1],b[2],b[3]);
+ }
+ } else {
+ printf("Got verified solution %f %f %f %f\n",b[0],b[1],b[2],b[3]);
+ }
+ return 0;
+}
+
+
+int
+test(
+int n, /* Dimensionality */
+double **a, /* A[][] input matrix, returns LU decimposition of A */
+double *b /* B[] input array, returns solution X[] */
+) {
+ int i, j;
+ double rip; /* Row interchange parity */
+ int *pivx;
+ int rv = 0;
+
+ double **sa; /* save input matrix values */
+ double *sb; /* save input vector values */
+
+ pivx = ivector(0, n-1);
+ sa = dmatrix(0, n-1, 0, n-1);
+ sb = dvector(0, n-1);
+
+ /* Copy input matrix and vector values */
+ for (i = 0; i < n; i++) {
+ sb[i] = b[i];
+ for (j = 0; j < n; j++)
+ sa[i][j] = a[i][j];
+ }
+
+ if (lu_decomp(a, n, pivx, &rip)) {
+ free_dvector(sb, 0, n-1);
+ free_dmatrix(sa, 0, n-1, 0, n-1);
+ free_ivector(pivx, 0, n-1);
+ return 1;
+ }
+
+ lu_backsub(a, n, pivx, b);
+
+ /* Check that the solution is correct */
+ for (i = 0; i < n; i++) {
+ double sum, temp;
+ sum = 0.0;
+ for (j = 0; j < n; j++)
+ sum += sa[i][j] * b[j];
+//printf("~~ check %d = %f, against %f\n",i,sum,sb[i]);
+ temp = fabs(sum - sb[i]);
+ if (temp > 1e-6)
+ rv = 2;
+ }
+ free_dvector(sb, 0, n-1);
+ free_dmatrix(sa, 0, n-1, 0, n-1);
+ free_ivector(pivx, 0, n-1);
+ return rv;
+}
+
diff --git a/numlib/License.txt b/numlib/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/numlib/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/numlib/Makefile.am b/numlib/Makefile.am
new file mode 100644
index 0000000..da95596
--- /dev/null
+++ b/numlib/Makefile.am
@@ -0,0 +1,15 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libargyllnum.la
+privatelibdir = $(pkglibdir)
+
+libargyllnum_la_SOURCES = numlib.h numsup.c numsup.h dnsq.c dnsq.h \
+ powell.c powell.h dhsx.c dhsx.h ludecomp.c ludecomp.h svd.c \
+ svd.h zbrent.c zbrent.h rand.c rand.h sobol.c sobol.h aatree.c
+
+LDADD = ./libargyllnum.la
+
+check_PROGRAMS = dnsqtest tpowell tdhsx LUtest svdtest zbrenttest \
+ soboltest
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/numlib/Readme.txt b/numlib/Readme.txt
new file mode 100644
index 0000000..8cc0173
--- /dev/null
+++ b/numlib/Readme.txt
@@ -0,0 +1,14 @@
+Collection of numerical routines used by various other
+(mainly color) code.
+
+Included are:
+
+numsup Error handling, vector/array allocation, macros
+dnsq Non-linear equation solver
+powell Powell and Conjugate Gradient multi dimentional minimiser
+ludecomp LU decomposition matrix solver
+svd Singular Value decomposition matrix solver
+zbrent 1 dimentional brent root search
+rand Random number generators
+sobolo Sobol sub-random vector sequence generator
+
diff --git a/numlib/aatree.c b/numlib/aatree.c
new file mode 100644
index 0000000..2f38b1d
--- /dev/null
+++ b/numlib/aatree.c
@@ -0,0 +1,432 @@
+
+/*
+ Andersson binary balanced tree library
+
+ > Created (Julienne Walker): September 10, 2005
+ > Corrections (James Bucanek): April 10, 2006
+ 1) Typo in jsw_aerase:
+ up != 0 should be top != 0
+ 2) Bug in jsw_aerase:
+ skew ( path[top] ) should be skew ( up )
+ split ( path[top] ) should be split ( up )
+ 3) Bug in skew and split macros:
+ Condition should test for nil
+ 4) Bug in jsw_aerase:
+ Search for successor should save the path
+ > Fixed duplicate handling (Graeme W. Gill): August 16, 2009
+*/
+
+#include "aatree.h"
+
+#ifdef __cplusplus
+#include <cstdlib>
+
+using std::malloc;
+using std::free;
+using std::size_t;
+#else
+#include <stdlib.h>
+#endif
+
+#ifndef HEIGHT_LIMIT
+#define HEIGHT_LIMIT 64 /* Tallest allowable tree */
+#endif
+
+typedef struct aat_anode {
+ int level; /* Horizontal level for balance */
+ void *data; /* User-defined content */
+ struct aat_anode *link[2]; /* Left (0) and right (1) links */
+} aat_anode_t;
+
+struct aat_atree {
+ aat_anode_t *root; /* Top of the tree */
+ aat_anode_t *nil; /* End of tree sentinel */
+ cmp_f cmp; /* Compare two items */
+ size_t size; /* Number of items (user-defined) */
+};
+
+struct aat_atrav {
+ aat_atree_t *tree; /* Paired tree */
+ aat_anode_t *it; /* Current node */
+ aat_anode_t *path[HEIGHT_LIMIT]; /* Traversal path */
+ size_t top; /* Top of stack */
+};
+
+/* Remove left horizontal links */
+#define skew(t) do { \
+ if ( t->link[0]->level == t->level && t->level != 0 ) { \
+ aat_anode_t *save = t->link[0]; \
+ t->link[0] = save->link[1]; \
+ save->link[1] = t; \
+ t = save; \
+ } \
+} while(0)
+
+/* Remove consecutive horizontal links */
+#define split(t) do { \
+ if ( t->link[1]->link[1]->level == t->level && t->level != 0 ) { \
+ aat_anode_t *save = t->link[1]; \
+ t->link[1] = save->link[0]; \
+ save->link[0] = t; \
+ t = save; \
+ ++t->level; \
+ } \
+} while(0)
+
+/* Version of cmp that ensure there are no duplicates */
+/* Set res to comparison result */
+#define AAT_CMP( res, tree, p1, p2) \
+{ \
+ if ((res = tree->cmp ( p1, p2 )) == 0) { \
+ if (p1 < p2) \
+ res = -1; \
+ else if (p1 > p2) \
+ res = 1; \
+ } \
+}
+
+/* Create a new node that points to our data */
+/* Return tree-nil if malloc failed. */
+static aat_anode_t *new_node ( aat_atree_t *tree, void *data )
+{
+ aat_anode_t *rn = (aat_anode_t *)malloc ( sizeof *rn );
+
+ if ( rn == NULL )
+ return tree->nil;
+
+ rn->level = 1;
+ rn->data = data;
+ rn->link[0] = rn->link[1] = tree->nil;
+
+ return rn;
+}
+
+/* Create a new empty tree */
+aat_atree_t *aat_anew ( cmp_f cmp )
+{
+ aat_atree_t *rt = (aat_atree_t *)malloc ( sizeof *rt );
+
+ if ( rt == NULL )
+ return NULL;
+
+ /* Initialize sentinel */
+ rt->nil = (aat_anode_t *)malloc ( sizeof *rt->nil );
+ if ( rt->nil == NULL ) {
+ free ( rt );
+ return NULL;
+ }
+
+ rt->nil->data = NULL; /* Simplifies some ops */
+ rt->nil->level = 0;
+ rt->nil->link[0] = rt->nil->link[1] = rt->nil;
+
+ /* Initialize tree */
+ rt->root = rt->nil;
+ rt->cmp = cmp;
+ rt->size = 0;
+
+ return rt;
+}
+
+/* Delete the whole tree (but not the data) */
+void aat_adelete ( aat_atree_t *tree )
+{
+ aat_anode_t *it = tree->root;
+ aat_anode_t *save;
+
+ /* Destruction by rotation */
+ while ( it != tree->nil ) {
+ if ( it->link[0] == tree->nil ) {
+ /* Remove node */
+ save = it->link[1];
+ free ( it );
+ }
+ else {
+ /* Rotate right */
+ save = it->link[0];
+ it->link[0] = save->link[1];
+ save->link[1] = it;
+ }
+
+ it = save;
+ }
+
+ /* Finalize destruction */
+ free ( tree->nil );
+ free ( tree );
+}
+
+/* Locate a entry based on the data's value */
+void *aat_afind ( aat_atree_t *tree, void *data )
+{
+ aat_anode_t *it = tree->root;
+
+ while ( it != tree->nil ) {
+ int cmp;
+ AAT_CMP(cmp, tree, it->data, data);
+
+ if ( cmp == 0 )
+ break;
+
+ it = it->link[cmp < 0];
+ }
+
+ /* nil->data == NULL */
+ return it->data;
+}
+
+/* Insert an entry based on the data's value. */
+/* Take a copy of the pointer to the entry. */
+/* Return 0 if malloc failed */
+int aat_ainsert ( aat_atree_t *tree, void *data )
+{
+ if ( tree->root == tree->nil ) {
+ /* Empty tree case */
+ tree->root = new_node ( tree, data );
+ if ( tree->root == tree->nil )
+ return 0;
+ }
+ else {
+ aat_anode_t *it = tree->root;
+ aat_anode_t *path[HEIGHT_LIMIT];
+ int top = 0, dir;
+
+ /* Find a spot and save the path */
+ for ( ; ; ) {
+ int cmp;
+
+ path[top++] = it;
+ AAT_CMP(cmp, tree, it->data, data);
+ dir = cmp < 0;
+
+ if ( it->link[dir] == tree->nil )
+ break;
+
+ it = it->link[dir];
+ }
+
+ /* Create a new item */
+ it->link[dir] = new_node ( tree, data );
+ if ( it->link[dir] == tree->nil )
+ return 0;
+
+ /* Walk back and rebalance */
+ while ( --top >= 0 ) {
+ /* Which child? */
+ if ( top != 0 )
+ dir = path[top - 1]->link[1] == path[top];
+
+ skew ( path[top] );
+ split ( path[top] );
+
+ /* Fix the parent */
+ if ( top != 0 )
+ path[top - 1]->link[dir] = path[top];
+ else
+ tree->root = path[top];
+ }
+ }
+
+ ++tree->size;
+
+ return 1;
+}
+
+/* Delete an given entry by locating it by */
+/* its value, then removing it from the tree. */
+/* The item itself isn't deleted. */
+/* Return 0 if the item wasn't found */
+int aat_aerase ( aat_atree_t *tree, void *data )
+{
+ if ( tree->root == tree->nil )
+ return 0;
+ else {
+ aat_anode_t *it = tree->root;
+ aat_anode_t *path[HEIGHT_LIMIT];
+ int top = 0, dir, cmp;
+
+ /* Find node to remove and save path */
+ for ( ; ; ) {
+ path[top++] = it;
+
+ if ( it == tree->nil )
+ return 0;
+
+ AAT_CMP(cmp, tree, it->data, data);
+ if ( cmp == 0 )
+ break;
+
+ dir = cmp < 0;
+ it = it->link[dir];
+ }
+
+ /* Remove the found node */
+ if ( it->link[0] == tree->nil
+ || it->link[1] == tree->nil )
+ {
+ /* Single child case */
+ int dir2 = it->link[0] == tree->nil;
+
+ /* Unlink the item */
+ if ( --top != 0 )
+ path[top - 1]->link[dir] = it->link[dir2];
+ else
+ tree->root = it->link[1];
+
+ free ( it );
+ }
+ else {
+ /* Two child case */
+ aat_anode_t *heir = it->link[1];
+ aat_anode_t *prev = it;
+
+ while ( heir->link[0] != tree->nil ) {
+ path[top++] = prev = heir;
+ heir = heir->link[0];
+ }
+
+ /*
+ Order is important!
+ (free item, replace item, free heir)
+ */
+ it->data = heir->data;
+ prev->link[prev == it] = heir->link[1];
+ free ( heir );
+ }
+
+ /* Walk back up and rebalance */
+ while ( --top >= 0 ) {
+ aat_anode_t *up = path[top];
+
+ if ( top != 0 )
+ dir = path[top - 1]->link[1] == up;
+
+ /* Rebalance (aka. black magic) */
+ if ( up->link[0]->level < up->level - 1
+ || up->link[1]->level < up->level - 1 )
+ {
+ if ( up->link[1]->level > --up->level )
+ up->link[1]->level = up->level;
+
+ /* Order is important! */
+ skew ( up );
+ skew ( up->link[1] );
+ skew ( up->link[1]->link[1] );
+ split ( up );
+ split ( up->link[1] );
+ }
+
+ /* Fix the parent */
+ if ( top != 0 )
+ path[top - 1]->link[dir] = up;
+ else
+ tree->root = up;
+ }
+ }
+
+ --tree->size;
+
+ return 1;
+}
+
+/* Return the current number of items */
+size_t aat_asize ( aat_atree_t *tree )
+{
+ return tree->size;
+}
+
+/* Return a traversal object */
+aat_atrav_t *aat_atnew ( void )
+{
+ return malloc ( sizeof ( aat_atrav_t ) );
+}
+
+/* Destroy a traversal object */
+void aat_atdelete ( aat_atrav_t *trav )
+{
+ free ( trav );
+}
+
+/*
+ First step in traversal,
+ handles min and max
+*/
+static void *start ( aat_atrav_t *trav,
+ aat_atree_t *tree, int dir )
+{
+ trav->tree = tree;
+ trav->it = tree->root;
+ trav->top = 0;
+
+ /* Build a path to work with */
+ if ( trav->it != tree->nil ) {
+ while ( trav->it->link[dir] != tree->nil ) {
+ trav->path[trav->top++] = trav->it;
+ trav->it = trav->it->link[dir];
+ }
+ }
+
+ /* Could be nil, but nil->data == NULL */
+ return trav->it->data;
+}
+
+/*
+ Subsequent traversal steps,
+ handles ascending and descending
+*/
+static void *move ( aat_atrav_t *trav, int dir )
+{
+ aat_anode_t *nil = trav->tree->nil;
+
+ if ( trav->it->link[dir] != nil ) {
+ /* Continue down this branch */
+ trav->path[trav->top++] = trav->it;
+ trav->it = trav->it->link[dir];
+
+ while ( trav->it->link[!dir] != nil ) {
+ trav->path[trav->top++] = trav->it;
+ trav->it = trav->it->link[!dir];
+ }
+ }
+ else {
+ /* Move to the next branch */
+ aat_anode_t *last;
+
+ do {
+ if ( trav->top == 0 ) {
+ trav->it = nil;
+ break;
+ }
+
+ last = trav->it;
+ trav->it = trav->path[--trav->top];
+ } while ( last == trav->it->link[dir] );
+ }
+
+ /* Could be nil, but nil->data == NULL */
+ return trav->it->data;
+}
+
+/* Return first item */
+void *aat_atfirst ( aat_atrav_t *trav, aat_atree_t *tree )
+{
+ return start ( trav, tree, 0 ); /* Min value */
+}
+
+/* Return last item */
+void *aat_atlast ( aat_atrav_t *trav, aat_atree_t *tree )
+{
+ return start ( trav, tree, 1 ); /* Max value */
+}
+
+/* Move to next */
+void *aat_atnext ( aat_atrav_t *trav )
+{
+ return move ( trav, 1 ); /* Toward larger items */
+}
+
+/* Move to previous */
+void *aat_atprev ( aat_atrav_t *trav )
+{
+ return move ( trav, 0 ); /* Toward smaller items */
+}
diff --git a/numlib/aatree.h b/numlib/aatree.h
new file mode 100644
index 0000000..2a6df84
--- /dev/null
+++ b/numlib/aatree.h
@@ -0,0 +1,58 @@
+#ifndef AATREE_H
+#define AATREE_H
+
+/*
+ Andersson binary balanced tree library
+
+ > Created (Julienne Walker): September 10, 2005
+
+ This code is in the public domain. Anyone may
+ use it or change it in any way that they see
+ fit. The author assumes no responsibility for
+ damages incurred through use of the original
+ code or any variations thereof.
+
+ It is requested, but not required, that due
+ credit is given to the original author and
+ anyone who has modified the code through
+ a header comment, such as this one.
+*/
+
+#ifdef __cplusplus
+#include <cstddef>
+
+using std::size_t;
+
+extern "C" {
+#else
+#include <stddef.h>
+#endif
+
+/* Opaque types */
+typedef struct aat_atree aat_atree_t;
+typedef struct aat_atrav aat_atrav_t;
+
+/* User-defined item handling */
+typedef int (*cmp_f) ( const void *p1, const void *p2 );
+
+/* Andersson tree functions */
+aat_atree_t *aat_anew ( cmp_f cmp );
+void aat_adelete ( aat_atree_t *tree );
+void *aat_afind ( aat_atree_t *tree, void *data );
+int aat_ainsert ( aat_atree_t *tree, void *data );
+int aat_aerase ( aat_atree_t *tree, void *data );
+size_t aat_asize ( aat_atree_t *tree );
+
+/* Traversal functions */
+aat_atrav_t *aat_atnew ( void );
+void aat_atdelete ( aat_atrav_t *trav );
+void *aat_atfirst ( aat_atrav_t *trav, aat_atree_t *tree );
+void *aat_atlast ( aat_atrav_t *trav, aat_atree_t *tree );
+void *aat_atnext ( aat_atrav_t *trav );
+void *aat_atprev ( aat_atrav_t *trav );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* AATREE */
diff --git a/numlib/afiles b/numlib/afiles
new file mode 100644
index 0000000..dff62ef
--- /dev/null
+++ b/numlib/afiles
@@ -0,0 +1,32 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+dnsq.c
+dnsq.h
+dnsqtest.c
+numlib.h
+numsup.c
+numsup.h
+powell.h
+powell.c
+tpowell.c
+dhsx.h
+dhsx.c
+tdhsx.c
+rand.c
+rand.h
+ludecomp.h
+ludecomp.c
+LUtest.c
+svd.h
+svd.c
+svdtest.c
+zbrent.c
+zbrent.h
+zbrenttest.c
+sobol.c
+sobol.h
+soboltest.c
+aatree.h
+aatree.c
diff --git a/numlib/dhsx.c b/numlib/dhsx.c
new file mode 100644
index 0000000..180d15c
--- /dev/null
+++ b/numlib/dhsx.c
@@ -0,0 +1,302 @@
+
+/* This is better for stocastic optimisation, where the function */
+/* being evaluated may have a random component, or is not smooth. */
+
+/*
+ * Copyright 1999 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.
+ */
+
+/* A general purpose downhill simplex multivariate optimser, */
+/* based on the Nelder and Mead algorithm. */
+/* Code is an original expression of the algorithms decsribed in */
+/* "Numerical Recipes in C", by W.H.Press, B.P.Flannery, */
+/* S.A.Teukolsky & W.T.Vetterling. */
+
+#include "numsup.h"
+
+#undef DEBUG
+
+static void simplexinit(int di, double *cp, double *r,double **p);
+static double trypoint(int di,double *cp, double **p, double *y, int hix, double hpfac,
+ double (*funk)(void *fdata, double *tp), void *fdata, double *tryp);
+
+#ifdef NEVER /* Experimental */
+
+#define ALPHA 0.7 /* Extrapolate hight point through oposite face factor */
+#define GAMMA 1.4 /* Aditional extrapolation if ALPHA is good */
+#define BETA 0.4 /* One dimensional contraction factor */
+#define NONEXP 2 /* non expanding passes */
+
+#else /* Standard tuning values */
+
+#define ALPHA 1.0 /* Extrapolate hight point through oposite face factor */
+#define GAMMA 2.0 /* Aditional extrapolation if ALPHA is good */
+#define BETA 0.5 /* One dimensional contraction factor */
+#define NONEXP 2 /* non expanding passes */
+
+#endif
+
+
+/* Down hill simplex function */
+/* return 0 on sucess, 1 on failure due to excessive itterations */
+/* Result will be in cp */
+/* Arrays start at 0 */
+int dhsx(
+double *rv, /* If not NULL, return the residual error */
+int di, /* Dimentionality */
+double *cp, /* Initial starting point */
+double *s, /* Size of initial search area */
+double ftol, /* Finishing tollerance of error change */
+double atol, /* Absolute return value tollerance */
+int maxit, /* Maximum iterations allowed */
+double (*funk)(void *fdata, double *tp), /* Error function to evaluate */
+void *fdata /* Data needed by function */
+) {
+ int i, j;
+ int lox, hix, nhix; /* Lowest point index, highest point, next highest point */
+ int nsp = di+1; /* Number of simplex verticy points */
+ int nit; /* Number of iterations */
+ double tryy, ysave;
+ double tol;
+ double **p; /* Simplex array */
+ double *y; /* values of func at verticies */
+ double *tryp; /* Temporary used by trypoint() */
+
+ /* Allocate array arrays */
+ y = dvector(0, di); /* Value of function at verticies */
+ tryp = dvector(0, di-1);
+ p = dmatrix(0, di+1, 0, di); /* Vertex array of dimentions */
+
+ /* Init the search simplex */
+ simplexinit(di, cp, s, p);
+
+ /* Compute current center point position */
+ for (j = 0; j < di; j++) { /* For all dimensions */
+ double sum;
+ for (i = 0, sum = 0.0; i < nsp; i++) /* For all verticies */
+ sum += p[i][j];
+ cp[j] = sum;
+ }
+
+ /* Compute initial y (function) values at verticies */
+ for (i = 0; i < nsp; i++) /* For all verticies */
+ y[i] = (*funk)(fdata,p[i]); /* Compute error function */
+
+ /* Untill we find a solution or give up */
+ for (nit = 0; nit < maxit; nit++) {
+ /* Find highest, next highest and lowest vertex */
+
+ lox = nhix = hix = 0;
+ for (i = 0; i < nsp; i++) {
+ if (y[i] < y[lox])
+ lox = i;
+ if (y[i] > y[hix]) {
+ nhix = hix;
+ hix = i;
+ } else if (y[i] > y[nhix]) {
+ nhix = i;
+ }
+ }
+
+ tol = y[hix] - y[lox];
+
+#ifdef DEBUG /* 2D */
+ printf("Current vs = %f,%f %f,%f %f,%f\n",
+ p[0].c[0],p[0].c[1],p[1].c[0],p[1].c[1],p[2].c[0],p[2].c[1]);
+ printf("Current errs = %e %e %e\n",y[0],y[1],y[2]);
+ printf("Current sxs = %d %d %d\n",sy[0]->no,sy[1]->no,sy[2]->no);
+ printf("Current y[hix] = %e\n",y[hix]);
+#endif /* DEBUG */
+
+ if (tol < ftol && y[lox] < atol) { /* Found an adequate solution */
+ /* (allow 10 x range for disambiguator) */
+ /* set cp[] to best point, and return error value of that point */
+ tryy = 1.0/(di+1);
+ for (j = 0; j < di; j++) /* For all dimensions */
+ cp[j] *= tryy; /* Set cp to center point of simplex */
+#ifdef DEBUG
+ printf("C point = %f,%f\n",cp[0],cp[1]);
+#endif
+ tryy = (*funk)(fdata,cp); /* Compute error function */
+
+ if (tryy > y[lox]) { /* Center point is not the best */
+ tryy = y[lox];
+ for (j = 0; j < di; j++)
+ cp[j] = p[lox][j];
+ }
+ free_dmatrix(p, 0, di+1, 0, di);
+ free_dvector(tryp, 0, di-1);
+ free_dvector(y, 0, di);
+printf("~1 itterations = %d\n",nit);
+ if (rv != NULL)
+ *rv = tryy;
+ return 0;
+ }
+
+ if (nit > NONEXP) { /* Only try expanding after a couple of iterations */
+ /* Try moving the high point through the oposite face by ALPHA */
+#ifdef DEBUG
+ printf("dhsx: try moving high point %d through oposite face",hix);
+#endif
+ tryy = trypoint(di, cp, p, y, hix, -ALPHA, funk, fdata, tryp);
+ }
+
+ if (nit > NONEXP && tryy <= y[lox]) {
+#ifdef DEBUG
+ verbose(4,"dhsx: moving high through oposite face worked");
+#endif
+ /* Gave good result, so continue on in that direction */
+ tryy=trypoint(di,cp,p,y,hix,GAMMA,funk,fdata,tryp);
+
+
+ } else if (nit <= NONEXP || tryy >= y[nhix]) {
+
+ /* else if ALPHA move made things worse, do a one dimensional */
+ /* contraction by a factor BETA */
+#ifdef DEBUG
+ verbose(4,"dhsx: else try moving contracting point %d, y[ini] = %f",hix,y[hix]);
+#endif
+ ysave = y[hix];
+ tryy = trypoint(di, cp, p, y, hix, BETA, funk, fdata, tryp);
+
+ if (tryy >= ysave) {
+#ifdef DEBUG
+ verbose(4,"dhsx: contracting didn't work, try contracting other points to low");
+#endif
+ /* That still didn't help us, so move all the */
+ /* other points towards the high point */
+ for (i = 0; i < nsp; i++) { /* For all verts except low */
+ if (i != lox) {
+ for (j = 0; j < di; j++) { /* For all dimensions */
+ cp[j] = 0.5 * (p[i][j] + p[lox][j]);
+ p[i][j] = cp[j];
+ }
+ /* Compute function value for new point */
+ y[i] = (*funk)(fdata,p[i]); /* Compute error function */
+ }
+ }
+ /* Re-compute current center point value */
+ for (j = 0; j < di; j++) {
+ double sum;
+ for (i = 0,sum = 0.0;i<nsp;i++)
+ sum += p[i][j];
+ cp[j] = sum;
+ }
+ } else {
+#ifdef DEBUG
+ verbose(4,"dhsx: contracting point %d worked, tryy = %e, ysave = %e",hix,tryy,ysave);
+#endif
+ }
+ }
+ }
+ free_dmatrix(p, 0, di+1, 0, di);
+ free_dvector(tryp, 0, di-1);
+ free_dvector(y, 0, di);
+ if (rv != NULL)
+ *rv = tryy;
+ return 1; /* Failed */
+}
+
+/* Try moving the high point through the opposite face */
+/* by a factor of fac, and replaces the high point if */
+/* that proves to be better. */
+static double trypoint(
+int di, /* Dimentionality */
+double *cp, /* nsp * center coord/Returned coordinate */
+double **p, /* Starting/Current simplex (modified by dhsx) */
+double *y, /* values of func at verticies */
+int hix, /* Index of high point we are moving */
+double hpfac, /* factor to move high point */
+double (*funk)(void *fdata, double tp[]), /* Error function to evaluate */
+void *fdata, /* Data needed by function */
+double *tryp /* temporary array of size di-1 */
+) {
+ int j;
+ double tt, tryy;
+
+ /* Compute trial high point */
+ tt = (1.0 - hpfac)/di;
+ for (j = 0; j < di; j++)
+ tryp[j] = cp[j] * tt - p[hix][j] * (tt - hpfac);
+
+ /* Evaluate trial point */
+ tryy = (*funk)(fdata, tryp); /* Compute error function */
+
+ /* If new high point pos. is better */
+ if (tryy < y[hix]) {
+#ifdef DEBUG
+ printf("Try gave improved %e from sx %d",tryy,lsxp->last_fwd->no);
+#endif
+ y[hix] = tryy; /* Replace func val of hi with trial */
+
+ for (j = 0; j < di; j++) {
+ cp[j] += tryp[j] - p[hix][j]; /* Recompute cp */
+ p[hix][j] = tryp[j]; /* Replace co-ords of hi with trial */
+ }
+ } else {
+#ifdef DEBUG
+ verbose(4,"Try gave worse %e from sx %d",tryy,
+ lsxp->last_fwd == NULL ? -999 : lsxp->last_fwd->no);
+#endif
+ }
+ return tryy; /* Function value of trial point */
+}
+
+
+/* Make up an initial simplex for dhsx routine */
+static void
+simplexinit(
+int di, /* Dimentionality */
+double *cp, /* Initial solution values */
+double *s, /* initial radius for each dimention */
+double **p /* Simplex to initialize */
+) {
+ double bb;
+ double hh = 0.5; /* Constant */
+ double rr = sqrt(3.0)/2.0; /* Constant */
+ int i,j;
+ for (i = 0; i <= di; i++) { /* For each vertex */
+ /* The bounding points form a equalateral simplex */
+ /* whose vertexes are on a spehere about the data */
+ /* point center. The coordinate sequence is: */
+ /* B = sphere radius */
+ /* H = 0.5 */
+ /* R = sqrt(3)/2 */
+ /* 0 0 0 +B */
+ /* 0 0 0 -B */
+
+ /* 0 0 0 +B */
+ /* 0 0 +RB -HB */
+ /* 0 0 -RB -HB */
+
+ /* 0 0 0 +B */
+ /* 0 0 +RB -HB */
+ /* 0 +RRb -HRB -HB */
+ /* 0 -RRb -HRB -HB */
+
+ /* 0 0 0 +B */
+ /* 0 0 +RB -HB */
+ /* 0 +RRb -HRB -HB */
+ /* +RRRb -HRRb -HRB -HB */
+ /* -RRRb -HRRb -HRB -HB */
+
+ /* etc. */
+ bb = 1.0; /* Initial unscaled radius */
+ for (j = 0; j < di; j++) { /* For each coordinate in vertex */
+ if (j > i)
+ p[i][j] = cp[j] + s[j] * 0.0; /* If beyond last */
+ else if (j == i) /* If last non-zero */
+ p[i][j] = cp[j] + s[j] * bb;
+ else if (i == di && j == (di-1)) /* If last of last */
+ p[i][j] = cp[j] + s[j] * -1.0 * bb;
+ else /* If before last */
+ p[i][j] = cp[j] + s[j] * -hh * bb;
+ bb *= rr;
+ }
+ }
+}
+
diff --git a/numlib/dhsx.h b/numlib/dhsx.h
new file mode 100644
index 0000000..828b8b2
--- /dev/null
+++ b/numlib/dhsx.h
@@ -0,0 +1,42 @@
+#ifndef DHSX_H
+#define DHSX_H
+
+/* A general purpose downhill simplex multivariate optimser, */
+/* as described in */
+/* "Numerical Recipes in C", by W.H.Press, B.P.Flannery, */
+/* S.A.Teukolsky & W.T.Vetterling. */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Down hill simplex function */
+/* return err on sucess, -1.0 on failure */
+/* Result will be in cp */
+/* Arrays start at 0 */
+
+/* Standard interface for optimizer function */
+/* return 0 on sucess, 1 on failure due to excessive itterations */
+/* Result will be in cp */
+/* Arrays start at 0 */
+int dhsx(
+double *rv, /* If not NULL, return the residual error */
+int di, /* Dimentionality */
+double cp[], /* Initial starting point */
+double s[], /* Size of initial search area */
+double ftol, /* Tollerance of error change to stop on */
+double atol, /* Absolute return value tollerance */
+int maxit, /* Maximum iterations allowed */
+double (*funk)(void *fdata, double tp[]), /* Error function to evaluate */
+void *fdata /* Data needed by function */
+);
+
+double dhsx_funk( /* Return function value */
+ void *fdata, /* Opaque data pointer */
+ double tp[]); /* Multivriate input value */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* DHSX_H */
diff --git a/numlib/dnsq.c b/numlib/dnsq.c
new file mode 100644
index 0000000..75f00a8
--- /dev/null
+++ b/numlib/dnsq.c
@@ -0,0 +1,1675 @@
+
+/* Concatenated dnsq code */
+
+/*
+ * This concatenation, translation to C and modifications,
+ * Copyright 1998 Graeme 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.
+ */
+
+#include "numsup.h"
+#include "dnsq.h" /* Public interface definitions */
+
+#undef DEBUG
+
+typedef long int bool;
+#ifndef TRUE
+# define FALSE (0)
+# define TRUE (!FALSE)
+#endif
+
+#ifndef min
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a,b) ((a) >= (b) ? (a) : (b))
+#endif
+#ifndef fabs
+#define fabs(x) ((x) >= 0.0 ? (x) : -(x))
+#endif
+
+/* Forward difference jacobian approximation */
+static int dfdjc1(
+ void *fdata,
+ int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
+ int n, double *x, double * fvec, double *fjac,
+ int ldfjac, int ml, int mu,
+ double epsfcn, double *wa1, double *wa2);
+
+/* QR factorization */
+static int dqrfac(int m, int n, double *a, int lda,
+ bool pivot, int *ipvt, double *sigma,
+ double *acnorm, double *wa);
+
+/* Use QR decomposition to form the orthogonal matrix */
+static int dqform(int m, int n, double *q, int ldq, double *wa);
+
+/* QR decomposition update */
+static int d1updt(int m, int n, double *s,
+ double *u, double *v, double *w);
+
+/* Jacobian rotation, called by QR update */
+static int d1mpyq(int m, int n, double *a, int lda,
+ double *v, double *w);
+
+/* Compute norm of a vector */
+static double denorm(int n, double *x);
+
+/* Line search */
+static int ddoglg(int n, double *r, double *diag, double *qtb,
+ double delta, double *x, double *wa1, double *wa2);
+
+/***************************************************************/
+
+/*
+ * A simplified interface to dnsq().
+ */
+
+int dnsqe(
+ void *fdata, /* Opaque pointer to pass to fcn() and jac() */
+ int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
+ /* Pointer to function we are solving */
+ int (*jac)(void *fdata, int n, double *x, double *fvec, double **fjac),
+ /* Optional function to compute jacobian, NULL if not used */
+ int n, /* Number of functions and variables */
+ double x[], /* Initial solution estimate, RETURNs final solution */
+ double ss, /* Initial search area */
+ double fvec[], /* Array that will be RETURNed with thefunction values at the solution */
+ double dtol, /* Desired delta tollerance of the solution */
+ double atol, /* Desired absolute tollerance of the solution */
+ int maxfev, /* Maximum number of function calls. set to 0 for automatic */
+ int nprint /* Turn on debugging printouts from func() every nprint itterations */
+) {
+ int info = 0; /* Return status */
+
+ int nfev, njev;
+ int i,j, index, ml, lr, mu;
+ double epsfcn = ss * ss; /* Jacobian estimate step */
+ double factor = ss; /* Initial step size */
+ double maxstep = 0.0; /* Subsequent step size (not working ??) */
+
+ if (maxfev <= 0) {
+ maxfev = (n + 1) * 100;
+ if (jac == NULL)
+ maxfev <<= 1;
+ }
+ ml = n - 1; /* number of subdiagonals within the band of the Jacobian matrix. */
+ mu = n - 1; /* number of superdiagonals within the band of the Jacobian matrix. */
+
+ lr = n * (n + 1) / 2;
+ index = n * 6 + lr;
+
+ /* Call dnsq. */
+ info = dnsq(fdata, fcn, jac, NULL, 0,
+ n, &x[0], &fvec[0], dtol, atol,
+ maxfev, ml, mu, epsfcn, NULL, factor, maxstep, nprint,
+ &nfev, &njev);
+
+ if (info == 5)
+ info = 4;
+ if (info == 0)
+ warning("dnsqe: invalid input parameter.");
+ return info;
+} /* dnsqe */
+
+
+
+/***************************************************************/
+/*
+ * Library: SLATEC
+ * Category: F2A
+ * Type: Double precision (SNSQE-S, DNSQE-D)
+ * Keywords easy-to-use, nonlinear square system,
+ * powell hybrid method, zeros
+ * Author: Hiebert, K. L. (SNLA)
+ * Translated to C by f2c and Graeme W. Gill
+ *
+ * 1. Purpose.
+ *
+ * The purpose of DNSQ is to find a zero of a system of N nonlinear
+ * functions in N variables by a modification of the Powell
+ * hybrid method. The user must provide a subroutine which
+ * calculates the functions. The user has the option of either to
+ * provide a subroutine which calculates the Jacobian or to let the
+ * code calculate it by a forward-difference approximation.
+ * This code is the combination of the MINPACK codes (Argonne)
+ * HYBRD and HYBRDJ.
+ *
+ * 2. Subroutine and Type Statements.
+ *
+ * SUBROUTINE DNSQ(FCN,JAC,N,X,FVEC,FJAC,LDFJAC,XTOL,MAXFEV,
+ * ML,MU,EPSFCN,DIAG,MODE,FACTOR,NPRINT,INFO,NFEV,
+ * NJEV,R,LR,QTF,WA1,WA2,WA3,WA4)
+ * INTEGER N,MAXFEV,ML,MU,MODE,NPRINT,INFO,NFEV,LDFJAC,NJEV,LR
+ * DOUBLE PRECISION XTOL,EPSFCN,FACTOR
+ * DOUBLE PRECISION
+ * X(N),FVEC(N),DIAG(N),FJAC(LDFJAC,N),R(LR),QTF(N),
+ * WA1(N),WA2(N),WA3(N),WA4(N)
+ * EXTERNAL FCN,JAC
+ *
+ * 3. Parameters.
+ *
+ * Parameters designated as input parameters must be specified on
+ * entry to DNSQ and are not changed on exit, while parameters
+ * designated as output parameters need not be specified on entry
+ * and are set to appropriate values on exit from DNSQ.
+ *
+ * fcn() is the name of the user-supplied subroutine which calculates
+ * the functions. fcn() must be declared in an external statement
+ * in the user calling program, and should be written as follows.
+ *
+ * int fcn(
+ * void *fdata,
+ * int n,
+ * double *x,
+ * double *fvec,
+ * int iflag);
+ * {
+ * calculate the functions at x and
+ * return this vector in fvec.
+ * print out vector if iflag == 0
+ * return 0 (or < 0 to abort)
+ * }
+ * The value 0 should be returned fcn() unless the
+ * user wants to terminate execution of DNSQ. In this case
+ * return a negative integer.
+ *
+ * jac() is the name of the user-supplied subroutine which calculates
+ * the Jacobian. If jac!=NULL, then jac() must be declared in an
+ * external statement in the user calling program, and should be
+ * written as follows.
+ *
+ * int jac(
+ * void *fdata,
+ * int n,
+ * double *x,
+ * double *fvec,
+ * double **fjac,
+ * {
+ * Calculate the Jacobian at x and return this
+ * matrix in fjac. fvec contains the function
+ * values at x and should not be altered.
+ * return 0 (or < 0 to abort)
+ * }
+ * The value 0 should be returned jac() unless the
+ * user wants to terminate execution of DNSQ. In this case
+ * return a negative integer.
+ *
+ * If jac == NULL, then the code will approximate the
+ * Jacobian by forward-differencing.
+ *
+ * double **sjac;
+ * sjac is an optional n by n matrix that can hold an initial
+ * jacobian matrix that will be used in preference to calling the jac()
+ * function, or to using forward differencing. If the array is provided,
+ * it will also contain the last jacobian matrix used before exiting.
+ * If this array is not used, it should be set to NULL.
+ *
+ * int startsjac;
+ * styatsjac is a flag, that when set to non-zero, will cause the
+ * sjac[] array to be used as the initial jacobian matrix, in preference
+ * to calling the jac() function, or to using forward differencing.
+ *
+ * n is a positive integer input variable set to the number of
+ * functions and variables.
+ *
+ * x is an array of length n. On input x must contain an initial
+ * estimate of the solution vector. On output x contains the
+ * final estimate of the solution vector.
+ *
+ * fvec is an output array of length n which contains the functions
+ * evaluated at the output x.
+ *
+ * fjac is an output N by N array which contains the orthogonal
+ * matrix Q produced by the QR factorization of the final
+ * approximate Jacobian.
+ *
+ * ldfjac is a positive integer input variable not less than n
+ * which specifies the leading dimension of the array fjac.
+ *
+ * dtol is a nonnegative input variable. Termination occurs when
+ * the relative error between two consecutive iterates is at most
+ * dtol. Therefore, dtol measures the relative error desired in
+ * the approximate solution. Section 4 contains more details
+ * about dtol.
+ *
+ * tol is a nonnegative input variable. Termination occurs when
+ * the value of all the function values falls below this threshold.
+ * Termination occurs when either the dtol or tol condition is met.
+ *
+ * maxfev is a positive integer input variable. Termination occurs
+ * when the number of calls to fcn is at least maxfev by the end
+ * of an iteration.
+ *
+ * ml is a nonnegative integer input variable which specifies the
+ * number of subdiagonals within the band of the Jacobian matrix.
+ * If the Jacobian is not banded or jac!=null, set ml to at
+ * least n - 1.
+ *
+ * mu is a nonnegative integer input variable which specifies the
+ * number of superdiagonals within the band of the Jacobian
+ * matrix. If the Jacobian is not banded or jac!=null, set mu to at
+ * least n - 1.
+ *
+ * epsfcn is an input variable used in determining a suitable step
+ * for the forward-difference approximation. This approximation
+ * assumes that the relative errors in the functions are of the
+ * order of epsfcn. If epsfcn is less than the machine
+ * precision, it is assumed that the relative errors in the
+ * functions are of the order of the machine precision. If
+ * jac!=null, then epsfcn can be ignored (treat it as a dummy
+ * argument).
+ *
+ * diag is an array of length n. If MODE = 1 (see below), diag is
+ * internally set. If mode = 2, diag must contain positive
+ * entries that serve as implicit (multiplicative) scale factors
+ * for the variables.
+ *
+ * mode is an integer input variable. If mode = 1, the variables
+ * will be scaled internally. If mode = 2, the scaling is
+ * specified by the input diag. Other values of mode are
+ * equivalent to mode = 1.
+ *
+ * factor is a positive input variable used in determining the
+ * initial step bound. This bound is set to the product of
+ * factor and the Euclidean norm of diag*x if nonzero, or else to
+ * factor itself. In most cases factor should lie in the
+ * interval (.1,100.). 100. is a generally recommended value.
+ *
+ * nprint is an integer input variable that enables controlled
+ * printing of iterates if it is positive. In this case, fcn is
+ * called with iflag = 0 at the beginning of the first iteration
+ * and every nprint iterations thereafter and immediately prior
+ * to return, with x and fvec available for printing. Appropriate
+ * print statements must be added to fcn(see example). If nprint
+ * is not positive, no special calls of fcn with iflag = 0 are
+ * made.
+ *
+ * info is an integer output variable. If the user has terminated
+ * execution, info is set to the (negative) value of iflag. See
+ * description of fcn and jac. Otherwise, INFO is set as follows.
+ *
+ * INFO = 0 Improper input parameters.
+ *
+ * INFO = 1 Relative error between two consecutive iterates is
+ * at most XTOL. Normal sucessful return value.
+ *
+ * INFO = 2 Number of calls to FCN has reached or exceeded
+ * MAXFEV.
+ *
+ * INFO = 3 XTOL is too small. No further improvement in the
+ * approximate solution X is possible.
+ *
+ * INFO = 4 Iteration is not making good progress, as measured
+ * by the improvement from the last five Jacobian
+ * evaluations.
+ *
+ * INFO = 5 Iteration is not making good progress, as measured
+ * by the improvement from the last ten iterations.
+ * Return value if no zero can be found from this starting
+ * point.
+ *
+ * Sections 4 and 5 contain more details about INFO.
+ *
+ * nfev is an integer output variable set to the number of calls to
+ * fcn.
+ *
+ * njev is an integer output variable set to the number of calls to
+ * jac. (If jac==null, then njev is set to zero.)
+ *
+ * 4. Successful completion.
+ *
+ * The accuracy of DNSQ is controlled by the convergence parameter
+ * XTOL. This parameter is used in a test which makes a comparison
+ * between the approximation X and a solution XSOL. DNSQ
+ * terminates when the test is satisfied. If the convergence
+ * parameter is less than the machine precision (as defined by the
+ * function D1MACH(4)), then DNSQ only attempts to satisfy the test
+ * defined by the machine precision. Further progress is not
+ * usually possible.
+ *
+ * The test assumes that the functions are reasonably well behaved,
+ * and, if the Jacobian is supplied by the user, that the functions
+ * and the Jacobian are coded consistently. If these conditions
+ * are not satisfied, then DNSQ may incorrectly indicate
+ * convergence. The coding of the Jacobian can be checked by the
+ * subroutine DCKDER. If the Jacobian is coded correctly or JAC==NULL,
+ * then the validity of the answer can be checked, for example, by
+ * rerunning DNSQ with a tighter tolerance.
+ *
+ * Convergence Test. If DENORM(Z) denotes the Euclidean norm of a
+ * vector Z and D is the diagonal matrix whose entries are
+ * defined by the array DIAG, then this test attempts to
+ * guarantee that
+ *
+ * DENORM(D*(X-XSOL)) .LE. XTOL*DENORM(D*XSOL).
+ *
+ * If this condition is satisfied with XTOL = 10**(-K), then the
+ * larger components of D*X have K significant decimal digits and
+ * INFO is set to 1. There is a danger that the smaller
+ * components of D*X may have large relative errors, but the fast
+ * rate of convergence of DNSQ usually avoids this possibility.
+ *
+ * Unless high precision solutions are required, the recommended
+ * value for XTOL is the square root of the machine precision.
+ *
+ *
+ * 5. Unsuccessful Completion.
+ *
+ * Unsuccessful termination of DNSQ can be due to improper input
+ * parameters, arithmetic interrupts, an excessive number of
+ * function evaluations, or lack of good progress.
+ *
+ * Improper Input Parameters. INFO is set to 0 if
+ * N .LE. 0, or LDFJAC .LT. N, or
+ * XTOL .LT. 0.E0, or MAXFEV .LE. 0, or ML .LT. 0, or MU .LT. 0,
+ * or FACTOR .LE. 0.E0, or LR .LT. (N*(N+1))/2.
+ *
+ * Arithmetic Interrupts. If these interrupts occur in the FCN
+ * subroutine during an early stage of the computation, they may
+ * be caused by an unacceptable choice of X by DNSQ. In this
+ * case, it may be possible to remedy the situation by rerunning
+ * DNSQ with a smaller value of FACTOR.
+ *
+ * Excessive Number of Function Evaluations. A reasonable value
+ * for MAXFEV is 100*(N+1) for JAC!=NULL and 200*(N+1) for JAC==NULL.
+ *
+ * If the number of calls to FCN reaches MAXFEV, then this
+ * indicates that the routine is converging very slowly as
+ * measured by the progress of FVEC, and INFO is set to 2. This
+ *
+ * situation should be unusual because, as indicated below, lack
+ * of good progress is usually diagnosed earlier by DNSQ,
+ * causing termination with info = 4 or INFO = 5.
+ *
+ * Lack of Good Progress. DNSQ searches for a zero of the system
+ *
+ * by minimizing the sum of the squares of the functions. In so
+ * doing, it can become trapped in a region where the minimum
+ * does not correspond to a zero of the system and, in this
+ * situation, the iteration eventually fails to make good
+ * progress. In particular, this will happen if the system does
+ * not have a zero. If the system has a zero, rerunning DNSQ
+ * from a different starting point may be helpful.
+ *
+ *
+ * 6. Characteristics of The Algorithm.
+ *
+ * DNSQ is a modification of the Powell Hybrid method. Two of its
+ * main characteristics involve the choice of the correction as a
+ * convex combination of the Newton and scaled gradient directions,
+ * and the updating of the Jacobian by the rank-1 method of
+ * Broyden. The choice of the correction guarantees (under
+ * reasonable conditions) global convergence for starting points
+ * far from the solution and a fast rate of convergence. The
+ * Jacobian is calculated at the starting point by either the
+ * user-supplied subroutine or a forward-difference approximation,
+ * but it is not recalculated until the rank-1 method fails to
+ * produce satisfactory progress.
+ *
+ * Timing. The time required by DNSQ to solve a given problem
+ * depends on N, the behavior of the functions, the accuracy
+ * requested, and the starting point. The number of arithmetic
+ * operations needed by DNSQ is about 11.5*(N**2) to process
+ * each evaluation of the functions (call to FCN) and 1.3*(N**3)
+ * to process each evaluation of the Jacobian (call to JAC,
+ * if JAC!=NULL). Unless FCN and JAC can be evaluated quickly,
+ * the timing of DNSQ will be strongly influenced by the time
+ * spent in FCN and JAC.
+ *
+ * Storage. DNSQ requires (3*N**2 + 17*N)/2 single precision
+ * storage locations, in addition to the storage required by the
+ * program. There are no internally declared storage arrays.
+ *
+ * References: M. J. D. Powell, A hybrid method for nonlinear equa-
+ * tions. In Numerical Methods for Nonlinear Algebraic
+ * Equations, P. Rabinowitz, Editor. Gordon and Breach,
+ * 1988.
+ *
+ * Routines called: D1MPYQ, D1UPDT, DDOGLG, DENORM, DFDJC1, DQFORM, DQRFAC
+ *
+ * Revision history: (YYMMDD)
+ * 800301 DATE WRITTEN
+ * 890531 Changed all specific intrinsics to generic. (WRB)
+ * 890831 Modified array declarations. (WRB)
+ * 890831 REVISION DATE from Version 3.2
+ * 891214 Prologue converted to Version 4.0 format. (BAB)
+ * 900315 CALLs to XERROR changed to CALLs to XERMSG. (THJ)
+ * 920501 Reformatted the REFERENCES section. (WRB)
+ * 960510 Translated to C and features added. (GWG)
+ */
+
+/* Returns status. 0 = OK. */
+int dnsq(
+ void *fdata, /* Opaque data pointer, passed to called functions */
+ int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
+ /* Pointer to function we are solving */
+ int (*jac)(void *fdata, int n, double *x, double *fvec, double **fjac),
+ /* Optional function to compute jacobian, NULL if not used */
+ double **sjac, /* Optional initial jacobian matrix/last jacobian matrix. NULL if not used.*/
+ int startsjac, /* Set to non-zero to use sjac as the initial jacobian */
+ int n, /* Number of functions and variables */
+ double x[], /* Initial solution estimate, RETURNs final solution */
+ double fvec[], /* Array that will be RETURNed with thefunction values at the solution */
+ double dtol, /* Desired delta tollerance of the solution */
+ double atol, /* Desired tollerance of the root (stops on dtol or tol) */
+ int maxfev, /* Set excessive Number of Function Evaluations */
+ int ml, /* number of subdiagonals within the band of the Jacobian matrix. */
+ int mu, /* number of superdiagonals within the band of the Jacobian matrix. */
+ double epsfcn, /* determines suitable step for forward-difference approximation */
+ double diag[], /* Optional scaling factors, use NULL for internal scaling */
+ double factor, /* Determines the initial step bound */
+ double maxstep, /* Determines the maximum subsequent step bound (0.0 for none) */
+ /* maxstep is NOT WORKING !!! ??? */
+ int nprint, /* Turn on debugging printouts from func() every nprint itterations */
+ int *nfev, /* RETURNs the number of calls to fcn() */
+ int *njev /* RETURNs the number of calls to jac() */
+) {
+ int info = 0; /* Return status - invalid argument */
+ int smode = 0; /* Scaling mode, 1 = internal */
+
+ /* Internal working arrays */
+ double *fjac = NULL; /* n by n array which contains the orthogonal matrix Q */
+ /* produced by the QR factorization of the final approximate Jacobian. */
+ int ldfjac = n; /* stride of 2d array */
+ double **jjac = NULL; /* NR style pointers to fjac */
+
+ double *r = NULL; /* Array of length (n*(n+1))/2 which contains the upper */
+ /* triangular matrix produced by the QR factorization of the */
+ /* final approximate Jacobian, stored rowwise. */
+ double *qtf = NULL; /* Array of length n which contains the vector (q transpose)*fvec. */
+
+ double *wa1 = NULL; /* Four working arrays length n */
+ double *wa2 = NULL;
+ double *wa3 = NULL;
+ double *wa4 = NULL;
+
+ int iwa[1]; /* Pivot swap array (only one element used) */
+
+ /* Local variables */
+ bool jeval;
+ int iter;
+ int i, j, k, l, iflag;
+ int qrflag; /* Set when a valid Q is in fjac[], and R is in r[] */
+ int ncsuc;
+ int nslow1, nslow2, ncfail;
+ double temp;
+ double delta = 0.0;
+ double ratio, fnorm, pnorm;
+ double xnorm = 0.0;
+ double fnorm1;
+ double actred, prered;
+ double sum;
+
+ /* Allocate out working arrays */
+ if (diag == NULL) { /* Internal scaling */
+ smode = 1;
+ diag = dvector(0,n-1);
+ }
+ fjac = dvector(0,(n * n)-1);
+ jjac = convert_dmatrix(fjac,0,n-1,0,ldfjac-1);
+ r = dvector(0,((n * (n+1))/2)-1);
+ qtf = dvector(0,n-1);
+ wa1 = dvector(0,n-1);
+ wa2 = dvector(0,n-1);
+ wa3 = dvector(0,n-1);
+ wa4 = dvector(0,n-1);
+
+ qrflag = 0;
+ iflag = 0;
+ *nfev = 0;
+ *njev = 0;
+
+ /* Check the input parameters for errors. */
+ if (n <= 0 || dtol < 0.0 || maxfev <= 0
+ || ml < 0 || mu < 0 || factor <= 0.0 || maxstep < 0.0
+ || (sjac == NULL && startsjac != 0)) {
+ goto func_exit;
+ }
+ if (!smode) { /* Check the scaling array we were given */
+ for (j = 0; j < n; ++j) {
+ if (diag[j] <= 0.0) {
+ goto func_exit;
+ }
+ }
+ }
+
+ /* Evaluate the function at the starting point */
+ /* and calculate its norm. */
+ *nfev = 1;
+ if ((iflag = (*fcn)(fdata, n, &x[0], &fvec[0], 1)) < 0)
+ goto func_exit;
+ fnorm = denorm(n, &fvec[0]);
+
+ /* Initialize iteration counter and monitors. */
+
+ iter = 1;
+ ncsuc = 0;
+ ncfail = 0;
+ nslow1 = 0;
+ nslow2 = 0;
+
+ /* Beginning of the outer loop. */
+ for (;;) {
+ jeval = TRUE;
+
+ /* initialize the jacobian matrix. */
+ if (startsjac) { /* User provided array */
+ for (j = 0; j < n; j++) {
+ for (i = 0; i < n; i++)
+ fjac[j * ldfjac + i] = sjac[j][i];
+ }
+ } else if (jac == NULL) { /* Code approximates the jacobian */
+ int ti;
+ iflag = dfdjc1(fdata, fcn, n, &x[0], &fvec[0], &fjac[0], ldfjac,
+ ml, mu, epsfcn, &wa1[0], &wa2[0]);
+ ti = ml + mu + 1;
+ *nfev += min(ti,n);
+ } else { /* User supplies jacobian function */
+ iflag = (*jac)(fdata, n, &x[0], &fvec[0], jjac);
+ ++(*njev);
+ }
+#ifdef DEBUG
+printf("DNSQ: Jacobian initialized\n");
+#endif
+
+ if (iflag < 0)
+ goto func_exit;
+
+ /* Compute the qr factorization of the jacobian. */
+ dqrfac(n, n, &fjac[0], ldfjac, FALSE, iwa, &wa1[0], &wa2[0], &wa3[0]);
+
+ /* On the first iteration and if internal scaling mode set, scale */
+ /* according to the norms of the columns of the initial jacobian. */
+ /* (wa2[] will contain norms) */
+ /* Do this on subsequent itterations too, if a maxstep is set. */
+ if (iter == 1 || maxstep > 0.0) {
+ if (smode) {
+ for (j = 0; j < n; ++j) {
+ diag[j] = wa2[j];
+ if (wa2[j] == 0.0) {
+ diag[j] = 1.0;
+ }
+ }
+ }
+
+ /* On the first iteration, calculate the norm of the scaled */
+ /* x[], and initialize the step bound delta. */
+ for (j = 0; j < n; ++j)
+ wa3[j] = diag[j] * x[j];
+
+ xnorm = denorm(n, &wa3[0]);
+ if (iter == 1) {
+ delta = factor * xnorm;
+ if (delta == 0.0)
+ delta = factor;
+#ifdef DEBUG
+ printf("Initial Delta = %f\n",delta);
+#endif /* DEBUG */
+ } else {
+ delta = maxstep * xnorm;
+ if (delta == 0.0)
+ delta = maxstep;
+#ifdef DEBUG
+ printf("Subsequent Delta = %f\n",delta);
+#endif /* DEBUG */
+ }
+ }
+
+ /* Form (q transpose)*fvec and store in qtf. */
+ for (i = 0; i < n; ++i)
+ qtf[i] = fvec[i];
+
+ for (j = 0; j < n; ++j) {
+ if (fjac[j + j * ldfjac] != 0.0) {
+ sum = 0.0;
+ for (i = j; i < n; ++i)
+ sum += fjac[i + j * ldfjac] * qtf[i];
+ temp = -sum / fjac[j + j * ldfjac];
+
+ for (i = j; i < n; ++i)
+ qtf[i] += fjac[i + j * ldfjac] * temp;
+ }
+ }
+
+ /* Copy the triangular factor of the qr factorization into r. */
+ for (j = 0; j < n; ++j) {
+ l = j;
+ if (j >= 1) {
+ for (i = 0; i < j; ++i) {
+ r[l] = fjac[i + j * ldfjac];
+ l += (n-1) - i;
+ }
+ }
+ r[l] = wa1[j];
+ }
+
+ /* Accumulate the orthogonal factor Q in fjac. */
+ dqform(n, n, &fjac[0], ldfjac, &wa1[0]);
+
+ qrflag = 1;
+
+ /* Rescale if necessary. */
+ if (smode) {
+ for (j = 0; j < n; ++j) {
+ diag[j] = max(diag[j],wa2[j]);
+ }
+ }
+
+ /* Beginning of the inner loop. */
+ for (;;) {
+ /* If requested, call fcn to enable printing of iterates. */
+ if (nprint > 0) {
+ if ((iter - 1) % nprint == 0)
+ if ((iflag = (*fcn)(fdata, n, &x[0], &fvec[0], 0)) < 0)
+ goto func_exit;
+ }
+
+#ifdef DEBUG
+ /* If the user supplied an array, and there is a valid Q in */
+ /* fjac[], and R is in r[], recover the most recent Jacobian */
+ /* matrix by multiplying Q by R */
+ if (qrflag && sjac) {
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < n; ++j) {
+ double temp = 0.0;
+ l = j;
+ for (k = 0; k <= j; ++k) {
+ temp += fjac[k * ldfjac + i] * r[l];
+ l += (n-1-k);
+ }
+ sjac[j][i] = temp;
+ }
+ }
+ printf("Current Jacobian = \n");
+ for (j = 0; j < n; ++j) {
+ for (i = 0; i < n; ++i) {
+ printf("%f ",sjac[j][i]);
+ }
+ printf("\n");
+ }
+ }
+#endif /* DEBUG */
+
+ /* Determine the direction p. */
+ ddoglg(n, &r[0], &diag[0], &qtf[0], delta, &wa1[0], &wa2[0], &wa3[0]);
+
+ /* Store the direction p and x + p. calculate the norm of p. */
+ /* (wa1[] is X[] output array from ddoglg()) */
+ for (j = 0; j < n; ++j) {
+ wa1[j] = -wa1[j];
+ wa2[j] = x[j] + wa1[j];
+ wa3[j] = diag[j] * wa1[j];
+ }
+ pnorm = denorm(n, &wa3[0]);
+
+ /* On the first iteration, adjust the initial step bound. */
+ /* Do this on subsequent itterations too, if maxstep is set. */
+ if (iter == 1 || maxstep > 0.0) {
+ delta = min(delta,pnorm);
+#ifdef DEBUG
+ if (iter == 1)
+ printf("First itter Delta = %f\n",delta);
+ else
+ printf("Subsequent itter Delta = %f\n",delta);
+#endif /* DEBUG */
+ }
+
+ /* Evaluate the function at x + p and calculate its norm. */
+ ++(*nfev);
+ if ((iflag = (*fcn)(fdata, n, &wa2[0], &wa4[0], 1)) < 0)
+ goto func_exit;
+ fnorm1 = denorm(n, &wa4[0]);
+
+ /* Compute the scaled actual reduction. */
+ actred = -1.0; /* Assume norm is made worse */
+ if (fnorm1 < fnorm) { /* There was a reduction in the norm */
+ double td;
+ td = fnorm1 / fnorm;
+ actred = 1.0 - td * td;
+ }
+
+ /* Compute the scaled predicted reduction. */
+ l = 0;
+ for (i = 0; i < n; ++i) {
+ sum = 0.0;
+ for (j = i; j < n; ++j) {
+ sum += r[l] * wa1[j];
+ ++l;
+ }
+ wa3[i] = qtf[i] + sum;
+ }
+
+ temp = denorm(n, &wa3[0]);
+ prered = 0.0;
+ if (temp < fnorm) {
+ double td;
+ td = temp / fnorm;
+ prered = 1.0 - td * td;
+ }
+
+ /* Compute the ratio of the actual to the predicted reduction. */
+ ratio = 0.0; /* Assume no improvement */
+ if (prered > 0.0)
+ ratio = actred / prered;
+#ifdef DEBUG
+printf("DNSQ: actual/predicted ratio = %f\n",ratio);
+#endif /* DEBUG */
+
+ /* Update the step bound. */
+ if (ratio < 0.1) {
+ ncsuc = 0;
+ ++ncfail; /* Forces jacobian recalc when ncfail == 2 */
+ delta = 0.5 * delta;
+#ifdef DEBUG
+printf("ratio < 0.1 bad, Delta = %f, ncfail = %d\n",delta,ncfail);
+#endif /* DEBUG */
+ } else {
+ ncfail = 0; /* Pospone jacobian recalc */
+ ++ncsuc;
+ if (ratio >= 0.5 || ncsuc > 1) {
+ delta = max(delta, pnorm / 0.5);
+#ifdef DEBUG
+printf("ratio > 0.1 good, Delta = %f, ncsuc = %d\n",delta,ncsuc);
+#endif /* DEBUG */
+ }
+ if (fabs(ratio - 1.0) <= 0.1) {
+ delta = 2.0 * pnorm;
+#ifdef DEBUG
+printf("abs(ratio -1.0) <= 0.1 Delta = %f\n",delta);
+#endif /* DEBUG */
+ }
+ }
+
+ /* Test for progressing iteration. */
+ if (ratio > 0.0001) {
+#ifdef DEBUG
+printf("Successful itter\n");
+#endif /* DEBUG */
+ /* Successful iteration. update x, fvec, and their norms. */
+ for (j = 0; j < n; ++j) {
+ x[j] = wa2[j];
+ wa2[j] = diag[j] * x[j];
+ fvec[j] = wa4[j];
+ }
+ xnorm = denorm(n, &wa2[0]);
+ fnorm = fnorm1;
+ ++iter;
+ }
+
+#ifdef DEBUG
+printf("DNSQ: actual = %f\n",actred);
+#endif /* DEBUG */
+ /* Determine the progress of the iteration. */
+ ++nslow1;
+ if (fabs(actred) >= 0.001)
+ nslow1 = 0;
+ if (jeval)
+ ++nslow2;
+ if (fabs(actred) >= 0.1)
+ nslow2 = 0;
+
+ /* Test for convergence. */
+ if (delta <= dtol * xnorm || fnorm == 0.0) {
+#ifdef DEBUG
+printf("DNSQ: delta %f <= dtol * xnorm %f || fnorm == %f\n",delta,dtol * xnorm,fnorm);
+#endif /* DEBUG */
+ info = 1;
+ goto func_exit;
+ }
+ /* Test for root meeting tolerance (GWG) */
+ for (j = 0; j < n; ++j) {
+ if (fabs(fvec[j]) > atol)
+ break;
+ }
+ if (j >= n) { /* All were below tollerance */
+#ifdef DEBUG
+printf("DNSQ: fvecs are all <= atol %f\n",atol);
+#endif /* DEBUG */
+ info = 1;
+ goto func_exit;
+ }
+
+ /* Tests for termination and stringent tolerances. */
+ if (*nfev >= maxfev)
+ info = 2;
+ if (0.1 * max(0.1 * delta, pnorm) <= M_DIVER * xnorm)
+ info = 3;
+ if (nslow2 == 5)
+ info = 4;
+ if (nslow1 == 10)
+ info = 5;
+ if (info != 0)
+ goto func_exit;
+
+ /* Criterion for recalculating jacobian */
+ if (ncfail == 2) {
+ break; /* Break out of inner loop */
+ }
+
+ /* Calculate the rank one modification to the jacobian */
+ /* and update qtf if necessary. */
+ for (j = 0; j < n; ++j) {
+ sum = 0.0;
+ for (i = 0; i < n; ++i) {
+ sum += fjac[i + j * ldfjac] * wa4[i];
+ }
+ wa2[j] = (sum - wa3[j]) / pnorm;
+ wa1[j] = diag[j] * (diag[j] * wa1[j] / pnorm);
+ if (ratio >= 1e-4) {
+ qtf[j] = sum;
+ }
+ }
+
+ /* Compute the qr factorization of the updated jacobian. */
+ d1updt(n, n, &r[0], &wa1[0], &wa2[0], &wa3[0]);
+ d1mpyq(n, n, &fjac[0], ldfjac, &wa2[0], &wa3[0]);
+ d1mpyq(1, n, &qtf[0], 1, &wa2[0], &wa3[0]);
+
+ jeval = FALSE;
+ } /* End of the inner loop. */
+ } /* End of the outer loop. */
+
+
+ /* Termination, either normal or user imposed. */
+func_exit:
+
+ /* If the user supplied an array, and there is a valid Q in */
+ /* fjac[], and R is in r[], recover the most recent Jacobian */
+ /* matrix by multiplying Q by R */
+ if (qrflag && sjac) {
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < n; ++j) {
+ double temp = 0.0;
+ l = j;
+ for (k = 0; k <= j; ++k) {
+ temp += fjac[k * ldfjac + i] * r[l];
+ l += (n-1-k);
+ }
+ sjac[j][i] = temp;
+ }
+ }
+ }
+
+ /* Free our working arrays */
+ if (smode)
+ free_dvector(diag,0,n-1);
+ free_dvector(fjac,0,(n * n)-1);
+ free_convert_dmatrix(jjac,0,n-1,0,ldfjac-1);
+ free_dvector(r,0,((n * (n+1))/2)-1);
+ free_dvector(qtf,0,n-1);
+ free_dvector(wa1,0,n-1);
+ free_dvector(wa2,0,n-1);
+ free_dvector(wa3,0,n-1);
+ free_dvector(wa4,0,n-1);
+
+
+ if (iflag < 0)
+ info = iflag;
+ if (nprint > 0)
+ (*fcn)(fdata, n, &x[0], &fvec[0], 0);
+#ifdef DEBUG
+ if (info < 0)
+ printf("dnsq: Execution terminated because user set iflag negative\n");
+ if (info == 0)
+ printf("dnsq: Invalid input parameter\n");
+ if (info == 2)
+ printf("dnsq: Too many function evaluations\n");
+ if (info == 3)
+ printf("dnsq: dtol too small. no further improvement possible\n");
+ if (info > 4)
+ printf("dnsq: Iteration not making good progress\n");
+#endif /* DEBUG */
+ return info;
+} /* dnsq */
+
+/***************************************************************/
+/***************************************************************/
+
+/*
+ * Given an M by N matrix A, this subroutine computes A*Q where
+ * Q is the product of 2*(N - 1) transformations
+ *
+ * GV(N-1)*...*GV(1)*GW(1)*...*GW(N-1)
+ *
+ * and GV(I), GW(I) are Givens rotations in the (I,N) plane which
+ * eliminate elements in the I-th and N-th planes, respectively.
+ * Q itself is not given, rather the information to recover the
+ * GV, GW rotations is supplied.
+ *
+ */
+
+static int d1mpyq(
+ int m, /* Number of rows of A */
+ int n, /* Number of columns of A */
+ double *a, /* M by N array */
+ int lda, /* stride for a[][] */
+ double *v, /* Input array */
+ double *w) /* Input array */
+{
+ /* Local variables */
+ int i, j;
+ int nm1 = n - 1;
+ double temp;
+ double cos_ = 0.0, sin_ = 0.0;
+
+ /* Apply the first set of givens rotations to a. */
+ if (nm1 >= 1) {
+ for (j = n-2; j >= 0; --j) {
+ if (fabs(v[j]) > 1.0)
+ cos_ = 1.0 / v[j];
+ if (fabs(v[j]) > 1.0) { /* Computing 2nd power */
+ sin_ = sqrt(1.0 - cos_ * cos_);
+ }
+ if (fabs(v[j]) <= 1.0) {
+ sin_ = v[j];
+ }
+ if (fabs(v[j]) <= 1.0) { /* Computing 2nd power */
+ cos_ = sqrt(1.0 - sin_ * sin_);
+ }
+ for (i = 0; i < m; ++i) {
+ temp = cos_ * a[i + j * lda] - sin_ * a[i + nm1 * lda];
+ a[i + nm1 * lda] = sin_ * a[i + j * lda] + cos_ * a[i + nm1 * lda];
+ a[i + j * lda] = temp;
+ }
+ }
+
+ /* Apply the second set of givens rotations to a. */
+ for (j = 0; j < nm1; ++j) {
+ if (fabs(w[j]) > 1.0)
+ cos_ = 1.0 / w[j];
+ if (fabs(w[j]) > 1.0) { /* Computing 2nd power */
+ sin_ = sqrt(1.0 - cos_ * cos_);
+ }
+ if (fabs(w[j]) <= 1.0)
+ sin_ = w[j];
+ if (fabs(w[j]) <= 1.0) { /* Computing 2nd power */
+ cos_ = sqrt(1.0 - sin_ * sin_);
+ }
+ for (i = 0; i < m; ++i) {
+ temp = cos_ * a[i + j * lda] + sin_ * a[i + nm1 * lda];
+ a[i + nm1 * lda] = -sin_ * a[i + j * lda] + cos_ * a[i + nm1 * lda];
+ a[i + j * lda] = temp;
+ }
+ }
+ }
+ return 0;
+}
+
+/***************************************************************/
+/***************************************************************/
+
+/*
+ * Given an M by N lower trapezoidal matrix S, an M-vector U,
+ * and an N-vector V, the problem is to determine an
+ * orthogonal matrix Q such that
+ *
+ * t
+ * (S + U*V )*Q
+ *
+ * is again lower trapezoidal.
+ *
+ * This subroutine determines Q as the product of 2*(N - 1)
+ * transformations
+ *
+ * GV(N-1)*...*GV(1)*GW(1)*...*GW(N-1)
+ *
+ * where GV(I), GW(I) are Givens rotations in the (I,N) plane
+ * which eliminate elements in the I-th and N-th planes,
+ * respectively. Q itself is not accumulated, rather the
+ * information to recover the GV, GW rotations is returned.
+ *
+ */
+
+static int d1updt(
+ int m, /* Number of rows of S */
+ int n, /* Number of columns of S */
+ double *s, /* Array of length (n*(2*m-n+1))/2 containing the lower trapezoid matrix */
+ double *u, /* U vector lenghth m */
+ double *v, /* V vector length n */
+ double *w) /* Output array W length m */
+{
+ int i, j, l;
+ int jj;
+ int nm1 = n - 1;
+ int nmj;
+ double temp;
+ double giant, cotan;
+ double tan_;
+ double cos_, sin_, tau;
+
+ /* Giant is the largest magnitude. */
+ giant = M_LARGE;
+
+ /* Initialize the diagonal element pointer. */
+ jj = n * ((m << 1) - n + 1) / 2 - (m - n) - 1;
+
+ /* Move the nontrivial part of the last column of s into w. */
+ l = jj;
+ for (i = nm1; i < m; ++i) {
+ w[i] = s[l];
+ ++l;
+ }
+
+ /* Rotate the vector v into a multiple of the n-th unit vector */
+ /* in such a way that a spike is introduced into w. */
+ if (nm1 >= 1) {
+ for (nmj = 1; nmj <= nm1; ++nmj) {
+ j = n - nmj - 1;
+ jj -= m - j;
+ w[j] = 0.0;
+ if (v[j] == 0.0)
+ continue;
+
+ /* Determine a givens rotation which eliminates the */
+ /* j-th element of v. */
+ if (fabs(v[nm1]) < fabs(v[j])) {
+ cotan = v[nm1] / v[j];
+ sin_ = 0.5 / sqrt(0.25 + 0.25 * (cotan * cotan));
+ cos_ = sin_ * cotan;
+ tau = 1.0;
+ if (fabs(cos_) * giant > 1.0) {
+ tau = 1.0 / cos_;
+ }
+ } else {
+ tan_ = v[j] / v[nm1];
+ cos_ = 0.5 / sqrt(0.25 + 0.25 * (tan_ * tan_));
+ sin_ = cos_ * tan_;
+ tau = sin_;
+ }
+
+ /* Apply the transformation to v and store the information */
+ /* necessary to recover the givens rotation. */
+ v[nm1] = sin_ * v[j] + cos_ * v[nm1];
+ v[j] = tau;
+
+ /* Apply the transformation to s and extend the spike in w. */
+ l = jj;
+ for (i = j; i < m; ++i) {
+ temp = cos_ * s[l] - sin_ * w[i];
+ w[i] = sin_ * s[l] + cos_ * w[i];
+ s[l] = temp;
+ ++l;
+ }
+ }
+ }
+
+ /* Add the spike from the rank 1 update to w. */
+ for (i = 0; i < m; ++i)
+ w[i] += v[nm1] * u[i];
+
+ /* Eliminate the spike. */
+ if (nm1 >= 1) {
+ for (j = 0; j < nm1; ++j) {
+ if (w[j] != 0.0) {
+ /* Determine a givens rotation which eliminates the */
+ /* j-th element of the spike. */
+ if (fabs(s[jj]) < fabs(w[j])) {
+ cotan = s[jj] / w[j];
+ sin_ = 0.5 / sqrt(0.25 + 0.25 * (cotan * cotan));
+ cos_ = sin_ * cotan;
+ tau = 1.0;
+ if (fabs(cos_) * giant > 1.0) {
+ tau = 1.0 / cos_;
+ }
+ } else {
+ tan_ = w[j] / s[jj];
+ cos_ = 0.5 / sqrt(0.25 + 0.25 * (tan_ * tan_));
+ sin_ = cos_ * tan_;
+ tau = sin_;
+ }
+
+ /* Apply the transformation to s and reduce the spike in w. */
+ l = jj;
+ for (i = j; i < m; ++i) {
+ temp = cos_ * s[l] + sin_ * w[i];
+ w[i] = -sin_ * s[l] + cos_ * w[i];
+ s[l] = temp;
+ ++l;
+ }
+
+ /* Store the information necessary to recover the givens rotation. */
+ w[j] = tau;
+ }
+ jj += m - j;
+ }
+ }
+
+ /* Move w back into the last column of the output s. */
+ l = jj;
+ for (i = nm1; i < m; ++i) {
+ s[l] = w[i];
+ ++l;
+ }
+ return 0;
+}
+
+/***************************************************************/
+/***************************************************************/
+
+/*
+ * Given an M by N matrix A, an N by N nonsingular diagonal
+ * matrix D, an M-vector B, and a positive number DELTA, the
+ * problem is to determine the convex combination X of the
+ * Gauss-Newton and scaled gradient directions that minimizes
+ * (A*X - B) in the least squares sense, subject to the
+ * restriction that the Euclidean norm of D*X be at most DELTA.
+ *
+ * This subroutine completes the solution of the problem
+ * if it is provided with the necessary information from the
+ * QR factorization of A. That is, if A = Q*R, where Q has
+ * orthogonal columns and R is an upper triangular matrix,
+ * then DDOGLG expects the full upper triangle of R and
+ * the first N components of (Q transpose)*B.
+ *
+ */
+
+static int ddoglg(
+ int n, /* Order of r[] */
+ double r[], /* Array of length (n*(n+!))/2 containing upper triangular matrix */
+ double diag[], /* Array of length n containing the diagonal elements of the matrix d[] */
+ double qtb[], /* Array of length n containing first n elements of vector (Q transpose)*B */
+ double delta, /* Upper bound on the Euclidean norm of D*X */
+ double x[], /* output array of length N containing the desired direction */
+ double wa1[], /* Working arrays length n */
+ double wa2[])
+{
+ int i, j, k, l;
+ int jj;
+ int jp1;
+ int nm1 = n-1;
+ double temp;
+ double alpha, gnorm, qnorm;
+ double epsmch;
+ double sgnorm;
+ double sum;
+
+ /* Epsmch is the machine precision. */
+ epsmch = M_DIVER;
+
+ /* First, calculate the gauss-newton direction. */
+ jj = n * (n + 1) / 2;
+ for (k = 0; k < n; ++k) {
+ j = nm1 - k;
+ jp1 = j + 1;
+ jj -= (k+1);
+ l = jj + 1;
+ sum = 0.0;
+ if (n >= (jp1+1)) {
+ for (i = jp1; i < n; ++i) {
+ sum += r[l] * x[i];
+ ++l;
+ }
+ }
+
+ temp = r[jj];
+ if (temp == 0.0) {
+ l = j;
+ for (i = 0; i <= j; ++i) { /* Computing MAX */
+ double dt;
+ dt = fabs(r[l]);
+ temp = max(temp,dt);
+ l += nm1 - i;
+ }
+ temp = epsmch * temp;
+ if (temp == 0.0) {
+ temp = epsmch;
+ }
+ }
+ x[j] = (qtb[j] - sum) / temp;
+ }
+
+
+ /* Test whether the gauss-newton direction is acceptable. */
+ for (j = 0; j < n; ++j) {
+ wa1[j] = 0.0;
+ wa2[j] = diag[j] * x[j];
+ }
+ qnorm = denorm(n, &wa2[0]);
+ if (qnorm <= delta) {
+ return 0; /* Done - use this direction */
+ }
+
+ /* The gauss-newton direction is not acceptable. */
+ /* Next, calculate the scaled gradient direction. */
+ l = 0;
+ for (j = 0; j < n; ++j) {
+ temp = qtb[j];
+ for (i = j; i < n; ++i) {
+ wa1[i] += r[l] * temp;
+ ++l;
+ }
+ wa1[j] /= diag[j];
+ }
+
+ /* Calculate the norm of the scaled gradient and test for */
+ /* The special case in which the scaled gradient is zero. */
+ gnorm = denorm(n, &wa1[0]);
+ sgnorm = 0.0;
+ alpha = delta / qnorm;
+ if (gnorm != 0.0) {
+ /* Calculate the point along the scaled gradient */
+ /* at which the quadratic is minimized. */
+ for (j = 0; j < n; ++j)
+ wa1[j] = wa1[j] / gnorm / diag[j];
+ l = 0;
+ for (j = 0; j < n; ++j) {
+ sum = 0.0;
+ for (i = j; i < n; ++i) {
+ sum += r[l] * wa1[i];
+ ++l;
+ }
+ wa2[j] = sum;
+ }
+ temp = denorm(n, &wa2[0]);
+ sgnorm = gnorm / temp / temp;
+
+ /* Test whether the scaled gradient direction is acceptable. */
+ alpha = 0.0;
+ if (sgnorm < delta) {
+ double d0,d1,d2,d3,d4,
+ /* The scaled gradient direction is not acceptable. */
+ /* Finally, calculate the point along the dogleg */
+ /* at which the quadratic is minimized. */
+ bnorm = denorm(n, &qtb[0]);
+ d0 = bnorm / gnorm * (bnorm / qnorm) * (sgnorm / delta);
+ d1 = sgnorm / delta;
+ d2 = d0 - delta / qnorm;
+ d3 = delta / qnorm;
+ d4 = sgnorm / delta;
+ d0 = d0 - delta / qnorm * (d1 * d1)
+ + sqrt(d2 * d2 + (1.0 - d3 * d3) * (1.0 - d4 * d4));
+ d1 = sgnorm / delta;
+ alpha = delta / qnorm * (1.0 - d1 * d1) / d0;
+ }
+ }
+
+ /* Form appropriate convex combination of the gauss-newton */
+ /* direction and the scaled gradient direction. */
+ temp = (1.0 - alpha) * min(sgnorm,delta);
+ for (j = 0; j < n; ++j)
+ x[j] = temp * wa1[j] + alpha * x[j];
+
+ return 0;
+} /* ddoglg */
+
+
+/***************************************************************/
+/***************************************************************/
+
+/*
+ * Given an N-vector X, this function calculates the
+ * Euclidean norm of X.
+ *
+ * The Euclidean norm is computed by accumulating the sum of
+ * squares in three different sums. The sums of squares for the
+ * small and large components are scaled so that no overflows
+ * occur. Non-destructive underflows are permitted. Underflows
+ * and overflows do not occur in the computation of the unscaled
+ * sum of squares for the intermediate components.
+ * The definitions of small, intermediate and large components
+ * depend on two constants, RDWARF and RGIANT. The main
+ * restrictions on these constants are that RDWARF**2 not
+ * underflow and RGIANT**2 not overflow. The constants
+ * given here are suitable for every known computer.
+ *
+ */
+
+static double denorm(
+ int n, /* Size of x[] */
+ double x[]) /* Input vector */
+{
+ if (n < 8) { /* Make it simple and fast */
+ double ss = 0.0;
+ switch (n) {
+ case 8:
+ ss += x[7] * x[7];
+ case 7:
+ ss += x[6] * x[6];
+ case 6:
+ ss += x[5] * x[5];
+ case 5:
+ ss += x[4] * x[4];
+ case 4:
+ ss += x[3] * x[3];
+ case 3:
+ ss += x[2] * x[2];
+ case 2:
+ ss += x[1] * x[1];
+ case 1:
+ ss += x[0] * x[0];
+ }
+ return sqrt(ss);
+ } else {
+ /* Initialized data */
+ static double rdwarf = 3.834e-20;
+ static double rgiant = 1.304e19;
+
+ /* Local variables */
+ static double xabs, x1max, x3max;
+ static int i;
+ static double s1, s2, s3, agiant, floatn;
+ double ret_val, td;
+
+ s1 = 0.0; /* Large component */
+ s2 = 0.0; /* Intermedate component */
+ s3 = 0.0; /* Small component */
+ x1max = 0.0;
+ x3max = 0.0;
+ floatn = (double) (n + 1);
+ agiant = rgiant / floatn;
+ for (i = 0; i < n; i++) {
+ xabs = (td = x[i], fabs(td));
+
+ /* Sum for intermediate components. */
+ if (xabs > rdwarf && xabs < agiant) {
+ td = xabs; /* Computing 2nd power */
+ s2 += td * td;
+
+ /* Sum for small components. */
+ } else if (xabs <= rdwarf) {
+ if (xabs <= x3max) {
+ if (xabs != 0.0) { /* Computing 2nd power */
+ td = xabs / x3max;
+ s3 += td * td;
+ }
+ } else { /* Computing 2nd power */
+ td = x3max / xabs;
+ s3 = 1.0 + s3 * (td * td);
+ x3max = xabs;
+ }
+
+ /* Sum for large components. */
+ } else {
+ if (xabs <= x1max) { /* Computing 2nd power */
+ td = xabs / x1max;
+ s1 += td * td;
+ } else { /* Computing 2nd power */
+ td = x1max / xabs;
+ s1 = 1.0 + s1 * (td * td);
+ x1max = xabs;
+ }
+ }
+ }
+
+ /* Calculation of norm. */
+ if (s1 != 0.0) { /* Large is present */
+ ret_val = x1max * sqrt(s1 + s2 / x1max / x1max);
+ } else { /* Medium and small are present */
+ if (s2 == 0.0) {
+ ret_val = x3max * sqrt(s3); /* Small only */
+ } else {
+ if (s2 >= x3max) { /* Medium larger than small */
+ ret_val = sqrt(s2 * (1.0 + x3max / s2 * (x3max * s3)));
+ } else { /* Small large than medium */
+ ret_val = sqrt(x3max * (s2 / x3max + x3max * s3));
+ }
+ }
+ }
+ return ret_val;
+ }
+}
+
+/***************************************************************/
+/***************************************************************/
+
+/*
+ * This subroutine computes a forward-difference approximation
+ * to the N by N Jacobian matrix associated with a specified
+ * problem of N functions in N variables. If the Jacobian has
+ * a banded form, then function evaluations are saved by only
+ * approximating the nonzero terms.
+ *
+ */
+
+static int dfdjc1( /* Return < 0 if fcn() aborts */
+ void *fdata, /* Opaque data pointer to pass to fcn() */
+ int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
+ /* Pointer to function we are solving */
+ int n, /* Number of functions and variables */
+ double x[], /* Input array size n */
+ double fvec[], /* array of length n which must contain the functions evaluated at x[] */
+ double fjac[], /* output n by n array containing approximation to the Jacobian matrix at x[] */
+ int ldfjac, /* stride of fjac[] */
+ int ml, /* Number of subdiagonals within the band of the Jacobian matrix */
+ int mu, /* Number of superdiagonals within the band of the Jacobian matrix */
+ double epsfcn, /* Step length for the forward-difference approximation */
+ double *wa1, /* Working arrays of length n */
+ double *wa2)
+{
+ /* Local variables */
+ int iflag = 0;
+ double temp;
+ int msum;
+ double h;
+ int i, j, k;
+ double eps;
+ int nm1 = n-1;
+
+ /* M_DIVER is the machine precision. */
+ eps = sqrt((max(epsfcn,M_DIVER)));
+ msum = ml + mu + 1;
+ if (msum >= n) {
+ /* Computation of dense approximate jacobian. */
+ for (j = 0; j < n; ++j) {
+ temp = x[j];
+ h = eps * fabs(temp);
+ if (h == 0.0)
+ h = eps;
+ x[j] = temp + h;
+ if ((iflag = (*fcn)(fdata,n, &x[0], &wa1[0], 1)) < 0)
+ break;
+ x[j] = temp;
+ for (i = 0; i < n; ++i)
+ fjac[i + j * ldfjac] = (wa1[i] - fvec[i]) / h;
+ }
+ } else {
+ /* Computation of banded approximate jacobian. */
+ for (k = 0; k < msum; ++k) {
+ for (j = k; msum < 0 ? j >= nm1 : j <= nm1; j += msum) {
+ wa2[j] = x[j];
+ h = eps * fabs(wa2[j]);
+ if (h == 0.0)
+ h = eps;
+ x[j] = wa2[j] + h;
+ }
+ if ((iflag = (*fcn)(fdata, n, &x[0], &wa1[0], 1)) < 0)
+ break;
+ for (j = k; msum < 0 ? j >= nm1 : j <= nm1; j += msum) {
+ x[j] = wa2[j];
+ h = eps * fabs(wa2[j]);
+ if (h == 0.0)
+ h = eps;
+ for (i = 0; i < n; ++i) {
+ fjac[i + j * ldfjac] = 0.0;
+ if (i >= j - mu && i <= j + ml)
+ fjac[i + j * ldfjac] = (wa1[i] - fvec[i]) / h;
+ }
+ }
+ }
+ }
+ return iflag;
+} /* dfdjc1_ */
+
+/***************************************************************/
+/***************************************************************/
+
+/*
+ * This subroutine proceeds from the computed QR factorization of
+ * an M by N matrix A to accumulate the M by M orthogonal matrix
+ * Q from its factored form.
+ *
+ */
+
+static int dqform(
+ int m, /* No of rows of A and the order of Q. */
+ int n, /* No of columns of A. */
+ double *q, /* m by m array */
+ int ldq, /* stride of q[][] */
+ double *wa) /* Working aray length m */
+{
+ int i, j, k, l, minmn;
+ double sum;
+
+ /* Zero out upper triangle of q in the first min(m,n) columns. */
+ minmn = min(m,n);
+ if (minmn >= 2) {
+ for (j = 1; j < minmn; ++j) {
+ for (i = 0; i < j; ++i)
+ q[i + j * ldq] = 0.0;
+ }
+ }
+
+ /* Initialize remaining columns to those of the identity matrix. */
+ if (m > n) {
+ for (j = n; j < m; ++j) {
+ for (i = 0; i < m; ++i) {
+ q[i + j * ldq] = 0.0;
+ }
+ q[j + j * ldq] = 1.0;
+ }
+ }
+
+ /* Accumulate q from its factored form. */
+ for (l = 0; l < minmn; ++l) {
+ k = minmn - l - 1;
+ for (i = k; i < m; ++i) {
+ wa[i] = q[i + k * ldq];
+ q[i + k * ldq] = 0.0;
+ }
+ q[k + k * ldq] = 1.0;
+ if (wa[k] != 0.0) {
+ for (j = k; j < m; ++j) {
+ double temp;
+ sum = 0.0;
+ for (i = k; i < m; ++i)
+ sum += q[i + j * ldq] * wa[i];
+ temp = sum / wa[k];
+ for (i = k; i < m; ++i)
+ q[i + j * ldq] -= temp * wa[i];
+ }
+ }
+ }
+ return 0;
+} /* dqform_ */
+
+/***************************************************************/
+/***************************************************************/
+
+/*
+ * This subroutine uses Householder transformations with column
+ * pivoting (optional) to compute a QR factorization of the
+ * M by N matrix A. That is, DQRFAC determines an orthogonal
+ * matrix Q, a permutation matrix P, and an upper trapezoidal
+ * matrix R with diagonal elements of nonincreasing magnitude,
+ * such that A*P = Q*R. The Householder transformation for
+ * column K, K = 1,2,...,MIN(M,N), is of the form
+ *
+ * T
+ * I - (1/U(K))*U*U
+ *
+ * where U has zeros in the first K-1 positions. The form of
+ * this transformation and the method of pivoting first
+ * appeared in the corresponding LINPACK subroutine.
+ *
+ */
+
+static int dqrfac(
+ int m, /* Number of rows of a[] */
+ int n, /* Number of columns of a[] */
+ double *a, /* m by n array */
+ int lda, /* stride of a[][] */
+ bool pivot, /* TRUE to enforce column pivoting */
+ int *ipvt, /* Pivot output array, size n */
+ double *sigma, /* Output diagonal elements of R, length n */
+ double *acnorm, /* Output norms of A, length n */
+ double *wa) /* Working array size n */
+{
+ /* Local variables */
+ int kmax;
+ int i, j, k, minmn;
+ double ajnorm;
+ int jp1;
+ double sum;
+
+ /* Compute the initial column norms and initialize several arrays. */
+ for (j = 0; j < n; ++j) {
+ acnorm[j] = denorm(m, &a[j * lda]);
+ sigma[j] = acnorm[j];
+ wa[j] = sigma[j];
+ if (pivot)
+ ipvt[j] = j;
+ }
+
+ /* Reduce a to r with householder transformations. */
+ minmn = min(m,n);
+ for (j = 0; j < minmn; ++j) {
+ if (pivot) {
+ /* Bring the column of largest norm into the pivot position. */
+ kmax = j;
+ for (k = j; k < n; ++k) {
+ if (sigma[k] > sigma[kmax]) {
+ kmax = k;
+ }
+ }
+ if (kmax != j) {
+ for (i = 0; i < m; ++i) {
+ double temp;
+ temp = a[i + j * lda];
+ a[i + j * lda] = a[i + kmax * lda];
+ a[i + kmax * lda] = temp;
+ }
+ sigma[kmax] = sigma[j];
+ wa[kmax] = wa[j];
+ k = ipvt[j];
+ ipvt[j] = ipvt[kmax];
+ ipvt[kmax] = k;
+ }
+ }
+
+ /* Compute the householder transformation to reduce the */
+ /* j-th column of a to a multiple of the j-th unit vector. */
+ ajnorm = denorm(m - j, &a[j + j * lda]);
+ if (ajnorm != 0.0) {
+ if (a[j + j * lda] < 0.0)
+ ajnorm = -ajnorm;
+ for (i = j; i < m; ++i)
+ a[i + j * lda] /= ajnorm;
+ a[j + j * lda] += 1.0;
+
+ /* Apply the transformation to the remaining columns */
+ /* and update the norms. */
+ jp1 = j + 1;
+ if (n > jp1) {
+ for (k = jp1; k < n; ++k) {
+ double temp;
+ sum = 0.0;
+ for (i = j; i < m; ++i)
+ sum += a[i + j * lda] * a[i + k * lda];
+ temp = sum / a[j + j * lda];
+ for (i = j; i < m; ++i)
+ a[i + k * lda] -= temp * a[i + j * lda];
+ if (pivot && sigma[k] != 0.0) {
+ temp = a[j + k * lda] / sigma[k];
+ temp = 1.0 - temp * temp;
+ sigma[k] *= sqrt((max(0.0,temp)));
+ temp = sigma[k] / wa[k];
+ if (0.05 * (temp * temp) <= M_DIVER) {
+ sigma[k] = denorm(m - jp1, &a[jp1 + k * lda]);
+ wa[k] = sigma[k];
+ }
+ }
+ }
+ }
+ }
+ sigma[j] = -ajnorm;
+ }
+ return 0;
+} /* dqrfac_ */
+
+/***************************************************************/
+/***************************************************************/
+
diff --git a/numlib/dnsq.h b/numlib/dnsq.h
new file mode 100644
index 0000000..e06e562
--- /dev/null
+++ b/numlib/dnsq.h
@@ -0,0 +1,120 @@
+#ifndef DNSQ_H
+#define DNSQ_H
+
+/* dnsq non-linear equation solver public interface definition */
+/*
+ * This concatenation Copyright 1998 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.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*
+
+ return values from dnsq() and dnsqe():
+
+ 0 Improper input parameters.
+
+ 1 Relative error between two consecutive iterates is at
+ most XTOL. Normal sucess return value.
+
+ 2 Number of calls to FCN has reached or exceeded MAXFEV.
+
+ 3 XTOL is too small. No further improvement in the
+ approximate solution X is possible.
+
+ 4 Iteration is not making good progress, as measured by
+ the improvement from the last five Jacobian evaluations.
+
+ 5 Iteration is not making good progress, as measured
+ by the improvement from the last ten iterations.
+ Return value if no zero can be found from this starting
+ point.
+ */
+
+/* dnsq function */
+int dnsq(
+ void *fdata, /* Opaque data pointer, passed to called functions */
+ int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
+ /* Pointer to function we are solving */
+ int (*jac)(void *fdata, int n, double *x, double *fvec, double **fjac),
+ /* Optional function to compute jacobian, NULL if not used */
+ double **sjac, /* Optional initial jacobian matrix/last jacobian matrix. NULL if not used.*/
+ int startsjac, /* Set to non-zero to use sjac as the initial jacobian */
+ int n, /* Number of functions and variables */
+ double x[], /* Initial solution estimate, RETURNs final solution */
+ double fvec[], /* Array that will be RETURNed with thefunction values at the solution */
+ double dtol, /* Desired tollerance of the solution */
+ double tol, /* Desired tollerance of root */
+ int maxfev, /* Set excessive Number of Function Evaluations */
+ int ml, /* number of subdiagonals within the band of the Jacobian matrix. */
+ int mu, /* number of superdiagonals within the band of the Jacobian matrix. */
+ double epsfcn, /* determines suitable step for forward-difference approximation */
+ double diag[], /* Optional scaling factors, use NULL for internal scaling */
+ double factor, /* Determines the initial step bound */
+ double maxstep, /* Determines the maximum subsequent step bound (0.0 for none) */
+ int nprint, /* Turn on debugging printouts from func() every nprint itterations */
+ int *nfev, /* RETURNs the number of calls to fcn() */
+ int *njev /* RETURNs the number of calls to jac() */
+);
+
+/* User supplied functions */
+
+/* calculate the functions at x[] */
+int dnsq_fcn( /* Return < 0 on abort */
+ void *fdata, /* Opaque data pointer */
+ int n, /* Dimenstionality */
+ double *x, /* Multivariate input values */
+ double *fvec, /* Multivariate output values */
+ int iflag /* Flag set to 0 to trigger debug output */
+);
+
+/* Calculate Jacobian at x[] */
+int dnsq_jac( /* Return < 0 on abort */
+ void *fdata, /* Opaque data pointer */
+ int n, /* Dimensionality */
+ double *x, /* Point to caluculate Jacobian at (do not alter) */
+ double *fvec, /* Function values at x (do not alter) */
+ double **fjac /* Return n by n Jacobian in this array */
+);
+
+#define M_LARGE 1.79e+308
+#define M_DIVER 2.22e-15
+
+/* Simplified dnsq() */
+int dnsqe(
+ void *fdata, /* Opaque pointer to pass to fcn() and jac() */
+ int (*fcn)(void *fdata, int n, double *x, double *fvec, int iflag),
+ /* Pointer to function we are solving */
+ int (*jac)(void *fdata, int n, double *x, double *fvec, double **fjac),
+ /* Optional function to compute jacobian, NULL if not used */
+ int n, /* Number of functions and variables */
+ double x[], /* Initial solution estimate, RETURNs final solution */
+ double ss, /* Initial search area */
+ double fvec[], /* Array that will be RETURNed with thefunction values at the solution */
+ double dtol, /* Desired tollerance of the solution */
+ double tol, /* Desired tollerance of root */
+ int maxfev, /* Maximum number of function calls. set to 0 for automatic */
+ int nprint /* Turn on debugging printouts from func() every nprint itterations */
+);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* DNSQ_H */
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/dnsqtest.c b/numlib/dnsqtest.c
new file mode 100644
index 0000000..3f02819
--- /dev/null
+++ b/numlib/dnsqtest.c
@@ -0,0 +1,192 @@
+
+/*
+ * Copyright 1999 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.
+ */
+
+/* Example use of dnsqe() */
+/* */
+/* The problem is to determine the values of X(1), X(2), ..., X(9), */
+/* which solve the system of tridiagonal equations */
+/* */
+/* (3-2*X(1))*X(1) -2*X(2) = -1 */
+/* -X(I-1) + (3-2*X(I))*X(I) -2*X(I+1) = -1, I=2-8 */
+/* -X(8) + (3-2*X(9))*X(9) = -1 */
+/* */
+/* Final approximate solution: */
+/* */
+/* -0.5706545E+00 */
+/* -0.6816283E+00 */
+/* -0.7017325E+00 */
+/* -0.7042129E+00 */
+/* -0.7013690E+00 */
+/* -0.6918656E+00 */
+/* -0.6657920E+00 */
+/* -0.5960342E+00 */
+/* -0.4164121E+00 */
+
+#include "numlib.h"
+
+/* Compute norm of a vector */
+static double denorm(int n, double *x);
+
+int fcn(void *fdata, int n, double *x, double *fvec, int iflag);
+
+double expect[9] = {
+ -0.5706545E+00,
+ -0.6816283E+00,
+ -0.7017325E+00,
+ -0.7042129E+00,
+ -0.7013690E+00,
+ -0.6918656E+00,
+ -0.6657920E+00,
+ -0.5960342E+00,
+ -0.4164121E+00 };
+
+int main(void)
+{
+ int n = 9 /* 9 */; /* Problem vector size */
+ double x[9]; /* Function input values */
+ double fvec[9]; /* Function output values */
+ double ss; /* Search area */
+ int info, j;
+ double fnorm;
+ int nprint = 0; /* Itteration debugging print = off */
+ double tol;
+
+ error_program = "dnsqtest"; /* Set global error reporting string */
+
+ /* Driver for dnsqe example. */
+ /* Not supplying Jacobian, use approximation */
+
+ /* The following starting values provide a rough solution. */
+ for (j = 1; j <= 9; ++j) {
+ x[j - 1] = -1.f;
+ }
+ ss = 0.1;
+
+ nprint = 0;
+
+ /* Set tol to the square root of the machine precision. */
+ /* Unless high precision solutions are required, */
+ /* this is the recommended setting. */
+
+ tol = sqrt(M_DIVER);
+
+ info = dnsqe(NULL, fcn, NULL, n, x, ss, fvec, tol, tol, 0, nprint);
+ fnorm = denorm(n, fvec);
+ fprintf(stdout,"Final L2 norm of the residuals = %e\n",fnorm);
+ fprintf(stdout,"Exit return value = %d (1 = sucess)\n",info);
+ fprintf(stdout,"Final approximate solution:\n");
+ for (j = 0; j < n; j++) {
+ fprintf(stdout,"x[%d] = %f, expect %f\n",j,x[j], expect[j]);
+ }
+
+ return 0;
+} /* main() */
+
+/* Function being solved */
+int fcn(void *fdata, int n, double *x, double *fvec, int iflag)
+{
+ double temp, temp1, temp2;
+ int k;
+
+ /* Function Body */
+ for (k = 0; k < n; ++k) {
+ temp = (3.0 - 2.0 * x[k]) * x[k];
+ temp1 = 0.0;
+ if (k != 0) {
+ temp1 = x[k-1];
+ }
+ temp2 = 0.0;
+ if (k != ((n)-1))
+ temp2 = x[k+1];
+ fvec[k] = temp - temp1 - 2.0 * temp2 + 1.0;
+ if (iflag == 0)
+ printf("x[%d] = %f, fvec[%d] + %f\n",k,x[k],k,fvec[k]);
+
+#ifdef DEBUG
+printf("~~ x[%d] = %f, fvec[%d] + %f\n",k,x[k],k,fvec[k]);
+#endif /* DEBUG */
+ }
+ /* Return < 0 to abort */
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - */
+
+static double denorm(
+ int n, /* Size of x[] */
+ double x[]) /* Input vector */
+{
+ /* Initialized data */
+ static double rdwarf = 3.834e-20;
+ static double rgiant = 1.304e19;
+
+ /* Local variables */
+ static double xabs, x1max, x3max;
+ static int i;
+ static double s1, s2, s3, agiant, floatn;
+ double ret_val, td;
+
+ s1 = 0.0; /* Large component */
+ s2 = 0.0; /* Intermedate component */
+ s3 = 0.0; /* Small component */
+ x1max = 0.0;
+ x3max = 0.0;
+ floatn = (double) (n + 1);
+ agiant = rgiant / floatn;
+ for (i = 0; i < n; i++) {
+ xabs = (td = x[i], fabs(td));
+
+ /* Sum for intermediate components. */
+ if (xabs > rdwarf && xabs < agiant) {
+ td = xabs; /* Computing 2nd power */
+ s2 += td * td;
+
+ /* Sum for small components. */
+ } else if (xabs <= rdwarf) {
+ if (xabs <= x3max) {
+ if (xabs != 0.0) { /* Computing 2nd power */
+ td = xabs / x3max;
+ s3 += td * td;
+ }
+ } else { /* Computing 2nd power */
+ td = x3max / xabs;
+ s3 = 1.0 + s3 * (td * td);
+ x3max = xabs;
+ }
+
+ /* Sum for large components. */
+ } else {
+ if (xabs <= x1max) { /* Computing 2nd power */
+ td = xabs / x1max;
+ s1 += td * td;
+ } else { /* Computing 2nd power */
+ td = x1max / xabs;
+ s1 = 1.0 + s1 * (td * td);
+ x1max = xabs;
+ }
+ }
+ }
+
+ /* Calculation of norm. */
+ if (s1 != 0.0) { /* Large is present */
+ ret_val = x1max * sqrt(s1 + s2 / x1max / x1max);
+ } else { /* Medium and small are present */
+ if (s2 == 0.0) {
+ ret_val = x3max * sqrt(s3); /* Small only */
+ } else {
+ if (s2 >= x3max) { /* Medium larger than small */
+ ret_val = sqrt(s2 * (1.0 + x3max / s2 * (x3max * s3)));
+ } else { /* Small large than medium */
+ ret_val = sqrt(x3max * (s2 / x3max + x3max * s3));
+ }
+ }
+ }
+ return ret_val;
+}
+
diff --git a/numlib/ludecomp.c b/numlib/ludecomp.c
new file mode 100644
index 0000000..72e014a
--- /dev/null
+++ b/numlib/ludecomp.c
@@ -0,0 +1,500 @@
+/***************************************************/
+/* Linear Simultaeous equation solver */
+/***************************************************/
+
+/* General simultaneous equation solver. */
+/* Code was inspired by the algorithm decsribed in section 2.3 */
+/* of "Numerical Recipes in C", by W.H.Press, B.P.Flannery, */
+/* S.A.Teukolsky & W.T.Vetterling. */
+
+/*
+ * Copyright 2000 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.
+ */
+
+#include "numsup.h"
+#include "ludecomp.h"
+
+#undef DO_POLISH
+#undef DO_CHECK
+
+/* Solve the simultaneous linear equations A.X = B */
+/* Return 1 if the matrix is singular, 0 if OK */
+int
+solve_se(
+double **a, /* A[][] input matrix, returns LU decomposition of A */
+double *b, /* B[] input array, returns solution X[] */
+int n /* Dimensionality */
+) {
+ double rip; /* Row interchange parity */
+ int *pivx, PIVX[10];
+#if defined(DO_POLISH) || defined(DO_CHECK)
+ double **sa; /* save input matrix values */
+ double *sb; /* save input vector values */
+ int i, j;
+#endif
+
+ if (n <= 10)
+ pivx = PIVX;
+ else
+ pivx = ivector(0, n-1);
+
+#if defined(DO_POLISH) || defined(DO_CHECK)
+ sa = dmatrix(0, n-1, 0, n-1);
+ sb = dvector(0, n-1);
+
+ /* Copy input matrix and vector values */
+ for (i = 0; i < n; i++) {
+ sb[i] = b[i];
+ for (j = 0; j < n; j++)
+ sa[i][j] = a[i][j];
+ }
+#endif
+
+ if (lu_decomp(a, n, pivx, &rip)) {
+#if defined(DO_POLISH) || defined(DO_CHECK)
+ free_dvector(sb, 0, n-1);
+ free_dmatrix(sa, 0, n-1, 0, n-1);
+#endif
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 1;
+ }
+
+ lu_backsub(a, n, pivx, b);
+
+#ifdef DO_POLISH
+ lu_polish(sa, a, n, sb, b, pivx); /* Improve the solution */
+#endif
+
+#ifdef DO_CHECK
+ /* Check that the solution is correct */
+ for (i = 0; i < n; i++) {
+ double sum, temp;
+ sum = 0.0;
+ for (j = 0; j < n; j++)
+ sum += sa[i][j] * b[j];
+ temp = fabs(sum - sb[i]);
+ if (temp > 1e-6) {
+ free_dvector(sb, 0, n-1);
+ free_dmatrix(sa, 0, n-1, 0, n-1);
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 2;
+ }
+ }
+#endif
+#if defined(DO_POLISH) || defined(DO_CHECK)
+ free_dvector(sb, 0, n-1);
+ free_dmatrix(sa, 0, n-1, 0, n-1);
+#endif
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 0;
+}
+
+/* Solve the simultaneous linear equations A.X = B, with polishing */
+/* Return 1 if the matrix is singular, 0 if OK */
+int
+polished_solve_se(
+double **a, /* A[][] input matrix, returns LU decomposition of A */
+double *b, /* B[] input array, returns solution X[] */
+int n /* Dimensionality */
+) {
+ double rip; /* Row interchange parity */
+ int *pivx, PIVX[10];
+ double **sa; /* save input matrix values */
+ double *sb; /* save input vector values */
+ int i, j;
+
+ if (n <= 10)
+ pivx = PIVX;
+ else
+ pivx = ivector(0, n-1);
+
+ sa = dmatrix(0, n-1, 0, n-1);
+ sb = dvector(0, n-1);
+
+ /* Copy source input matrix and vector values */
+ for (i = 0; i < n; i++) {
+ sb[i] = b[i];
+ for (j = 0; j < n; j++)
+ sa[i][j] = a[i][j];
+ }
+
+ if (lu_decomp(a, n, pivx, &rip)) {
+ free_dvector(sb, 0, n-1);
+ free_dmatrix(sa, 0, n-1, 0, n-1);
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 1;
+ }
+
+ lu_backsub(a, n, pivx, b);
+
+ lu_polish(sa, a, n, sb, b, pivx); /* Improve the solution */
+
+#ifdef DO_CHECK
+ /* Check that the solution is correct */
+ for (i = 0; i < n; i++) {
+ double sum, temp;
+ sum = 0.0;
+ for (j = 0; j < n; j++)
+ sum += sa[i][j] * b[j];
+ temp = fabs(sum - sb[i]);
+ if (temp > 1e-6) {
+ free_dvector(sb, 0, n-1);
+ free_dmatrix(sa, 0, n-1, 0, n-1);
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 2;
+ }
+ }
+#endif
+ free_dvector(sb, 0, n-1);
+ free_dmatrix(sa, 0, n-1, 0, n-1);
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 0;
+}
+
+/* Decompose the square matrix A[][] into lower and upper triangles */
+/* Return 1 if the matrix is singular. */
+int
+lu_decomp(
+double **a, /* A input array, output upper and lower triangles. */
+int n, /* Dimensionality */
+int *pivx, /* Return pivoting row permutations record */
+double *rip /* Row interchange parity, +/- 1.0, used for determinant */
+) {
+ int i, j;
+ double *rscale, RSCALE[10]; /* Implicit scaling of each row */
+
+ if (n <= 10)
+ rscale = RSCALE;
+ else
+ rscale = dvector(0, n-1);
+
+ /* For each row */
+ for (i = 0; i < n; i++) {
+ double big;
+ /* For each column in row */
+ for (big = 0.0, j=0; j < n; j++) {
+ double temp;
+ temp = fabs(a[i][j]);
+ if (temp > big)
+ big = temp;
+ }
+ if (fabs(big) <= DBL_MIN) {
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 1; /* singular matrix */
+ }
+ rscale[i] = 1.0/big; /* Save the scaling */
+ }
+
+ /* For each column (Crout's method) */
+ for (*rip = 1.0, j = 0; j < n; j++) {
+ double big;
+ int k, bigi = 0;
+
+ /* For each row */
+ for (i = 0; i < j; i++) {
+ double sum;
+ sum = a[i][j];
+ for (k = 0; k < i; k++)
+ sum -= a[i][k] * a[k][j];
+ a[i][j] = sum;
+ }
+
+ /* Find largest pivot element */
+ for (big = 0.0, i = j; i < n; i++) {
+ double sum, temp;
+
+ sum = a[i][j];
+ for (k = 0; k < j; k++)
+ sum -= a[i][k] * a[k][j];
+ a[i][j] = sum;
+
+ temp = rscale[i] * fabs(sum); /* Figure of merit */
+ if (temp >= big) {
+ big = temp; /* Best so far */
+ bigi = i; /* Remember index */
+ }
+ }
+
+ /* If we need to interchange rows */
+ if (j != bigi) {
+ { /* Take advantage of matrix storage to swap pointers to rows */
+ double *temp;
+ temp = a[bigi];
+ a[bigi] = a[j];
+ a[j] = temp;
+ }
+ *rip = -(*rip); /* Another row interchange */
+ rscale[bigi] = rscale[j]; /* Interchange scale factor */
+ }
+
+ pivx[j] = bigi; /* Record pivot */
+ if (fabs(a[j][j]) <= DBL_MIN) {
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 1; /* Pivot element is zero, so matrix is singular */
+ }
+
+ /* Divide by the pivot element */
+ if (j != (n-1)) {
+ double temp;
+ temp = 1.0/a[j][j];
+ for (i = j+1; i < n; i++)
+ a[i][j] *= temp;
+ }
+ }
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 0;
+}
+
+/* Solve a set of simultaneous equations from the */
+/* LU decomposition, by back substitution. */
+void
+lu_backsub(
+double **a, /* A[][] LU decomposed matrix */
+int n, /* Dimensionality */
+int *pivx, /* Pivoting row permutations record */
+double *b /* Input B[] vecor, return X[] */
+) {
+ int i, j;
+ int nvi; /* When >= 0, indicates non-vanishing B[] index */
+
+ /* Forward substitution, undo pivoting on the fly */
+ for (nvi = -1, i = 0; i < n; i++) {
+ int px;
+ double sum;
+
+ px = pivx[i];
+ sum = b[px];
+ b[px] = b[i];
+ if (nvi >= 0) {
+ for (j = nvi; j < i; j++)
+ sum -= a[i][j] * b[j];
+ } else {
+ if (sum != 0.0)
+ nvi = i; /* Found non-vanishing element */
+ }
+ b[i] = sum;
+ }
+
+ /* Back substitution */
+ for (i = (n-1); i >= 0; i--) {
+ double sum;
+ sum = b[i];
+ for (j = i+1; j < n; j++)
+ sum -= a[i][j] * b[j];
+ b[i] = sum/a[i][i];
+ }
+}
+
+
+/* Improve a solution of equations */
+void
+lu_polish(
+double **a, /* Original A[][] matrix */
+double **lua, /* LU decomposition of A[][] */
+int n, /* Dimensionality */
+double *b, /* B[] vector of equation */
+double *x, /* X[] solution to be polished */
+int *pivx /* Pivoting row permutations record */
+) {
+ int i, j;
+ double *r, R[10]; /* Residuals */
+
+ if (n <= 10)
+ r = R;
+ else
+ r = dvector(0, n-1);
+
+ /* Accumulate the residual error */
+ for (i = 0; i < n; i++) {
+ double sum;
+ sum = -b[i];
+ for (j = 0; j < n; j++)
+ sum += a[i][j] * x[j];
+ r[i] = sum;
+ }
+
+ /* Solve for the error */
+ lu_backsub(lua, n, pivx, r);
+
+ /* Subtract error from the old solution */
+ for (i = 0; i < n; i++)
+ x[i] -= r[i];
+
+ if (r != R)
+ free_dvector(r, 0, n-1);
+}
+
+
+/* Invert a matrix A using lu decomposition */
+/* Return 1 if the matrix is singular, 0 if OK */
+int
+lu_invert(
+double **a, /* A[][] input matrix, returns inversion of A */
+int n /* Dimensionality */
+) {
+ int i, j;
+ double rip; /* Row interchange parity */
+ int *pivx, PIVX[10];
+ double **y;
+
+ if (n <= 10)
+ pivx = PIVX;
+ else
+ pivx = ivector(0, n-1);
+
+ if (lu_decomp(a, n, pivx, &rip)) {
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 1;
+ }
+
+ /* Copy lu decomp. to y[][] */
+ y = dmatrix(0, n-1, 0, n-1);
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++) {
+ y[i][j] = a[i][j];
+ }
+ }
+
+ /* Find inverse by columns */
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++)
+ a[i][j] = 0.0;
+ a[i][i] = 1.0;
+ lu_backsub(y, n, pivx, a[i]);
+ }
+
+ /* Clean up */
+ free_dmatrix(y, 0, n-1, 0, n-1);
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+
+ return 0;
+}
+
+#ifdef NEVER /* It's not clear that this is correct */
+int
+lu_polished_invert(
+double **a, /* A[][] input matrix, returns inversion of A */
+int n /* Dimensionality */
+) {
+ int i, j, k;
+ double **aa; /* saved a */
+ double **t1, **t2;
+
+ aa = dmatrix(0, n-1, 0, n-1);
+ t1 = dmatrix(0, n-1, 0, n-1);
+ t2 = dmatrix(0, n-1, 0, n-1);
+
+ /* Copy a to aa */
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++)
+ aa[i][j] = a[i][j];
+ }
+
+ /* Invert a */
+ if ((i = lu_invert(a, n)) != 0) {
+ free_dmatrix(aa, 0, n-1, 0, n-1);
+ free_dmatrix(t1, 0, n-1, 0, n-1);
+ free_dmatrix(t2, 0, n-1, 0, n-1);
+ return i;
+ }
+
+ for (k = 0; k < 10; k++) {
+ matrix_mult(t1, n, n, aa, n, n, a, n, n);
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++) {
+ t2[i][j] = a[i][j];
+ if (i == j)
+ t1[i][j] = 2.0 - t1[i][j];
+ else
+ t1[i][j] = 0.0 - t1[i][j];
+ }
+ }
+ matrix_mult(a, n, n, t2, n, n, t1, n, n);
+ }
+
+ free_dmatrix(aa, 0, n-1, 0, n-1);
+ free_dmatrix(t1, 0, n-1, 0, n-1);
+ free_dmatrix(t2, 0, n-1, 0, n-1);
+ return 0;
+}
+#endif
+
+/* Pseudo-Invert matrix A using lu decomposition */
+/* Return 1 if the matrix is singular, 0 if OK */
+int
+lu_psinvert(
+double **out, /* Output[0..N-1][0..M-1] */
+double **in, /* Input[0..M-1][0..N-1] input matrix */
+int m, /* Rows */
+int n /* Columns */
+) {
+ int rv = 0;
+ double **tr; /* Transpose */
+ double **sq; /* Square matrix */
+
+ tr = dmatrix(0, n-1, 0, m-1);
+ matrix_trans(tr, in, m, n);
+
+ /* Use left inverse */
+ if (m > n) {
+ sq = dmatrix(0, n-1, 0, n-1);
+
+ /* Multiply transpose by input */
+ if ((rv = matrix_mult(sq, n, n, tr, n, m, in, m, n)) == 0) {
+
+ /* Invert the square matrix */
+ if ((rv = lu_invert(sq, n)) == 0) {
+
+ /* Multiply inverted square by transpose */
+ rv = matrix_mult(out, n, m, sq, n, n, tr, n, m);
+ }
+ }
+ free_dmatrix(sq, 0, n-1, 0, n-1);
+
+ /* Use right inverse */
+ } else {
+ sq = dmatrix(0, m-1, 0, m-1);
+
+ /* Multiply input by transpose */
+ if ((rv = matrix_mult(sq, m, m, in, m, n, tr, n, m)) == 0) {
+
+ /* Invert the square matrix */
+ if ((rv = lu_invert(sq, m)) == 0) {
+
+ /* Multiply transpose by inverted square */
+ rv = matrix_mult(out, n, m, tr, n, m, sq, m, m);
+ }
+ }
+ free_dmatrix(sq, 0, m-1, 0, m-1);
+ }
+
+ free_dmatrix(tr, 0, n-1, 0, m-1);
+
+ return rv;
+}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/ludecomp.h b/numlib/ludecomp.h
new file mode 100644
index 0000000..cdb4382
--- /dev/null
+++ b/numlib/ludecomp.h
@@ -0,0 +1,93 @@
+
+#ifndef LUDECOMP_H
+#define LUDECOMP_H
+
+/*
+ * Copyright 2000 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.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* NOTE:- lu decomp rearanges the rows of the matrix */
+/* by swapping pointers rather than exchanging data, */
+/* so the matrix must be addressed by the **pointer */
+/* if it is re-used after an ludecomp!!! */
+
+/* Solve the simultaneous linear equations A.X = B */
+/* Return 1 if the matrix is singular, 0 if OK */
+int
+solve_se(
+double **a, /* A[][] input matrix, returns LU decimposition of A */
+double *b, /* B[] input array, returns solution X[] */
+int n /* Dimensionality */
+);
+
+/* Solve the simultaneous linear equations A.X = B, with polishing */
+/* Return 1 if the matrix is singular, 0 if OK */
+int
+polished_solve_se(
+double **a, /* A[][] input matrix, returns LU decimposition of A */
+double *b, /* B[] input array, returns solution X[] */
+int n /* Dimensionality */
+);
+
+/* Decompose the square matrix A[][] into lower and upper triangles */
+/* Return 1 if the matrix is singular. */
+int
+lu_decomp(
+double **a, /* A input array, output upper and lower triangles. */
+int n, /* Dimensionality */
+int *pivx, /* Return pivoting row permutations record */
+double *rip /* Row interchange parity, +/- 1.0, used for determinant */
+);
+
+/* Solve a set of simultaneous equations from the */
+/* LU decomposition, by back substitution. */
+void
+lu_backsub(
+double **a, /* A[][] LU decomposed matrix */
+int n, /* Dimensionality */
+int *pivx, /* Pivoting row permutations record */
+double *b /* Input B[] vecor, return X[] */
+);
+
+/* Polish a solution for equations */
+void
+lu_polish(
+double **a, /* Original A[][] matrix */
+double **lua, /* LU decomposition of A[][] */
+int n, /* Dimensionality */
+double *b, /* B[] vector of equation */
+double *x, /* X[] solution to be polished */
+int *pivx /* Pivoting row permutations record */
+);
+
+/* Invert a matrix A using lu decomposition */
+/* Return 1 if the matrix is singular, 0 if OK */
+int
+lu_invert(
+double **a, /* A[][] input matrix, returns inversion of A */
+int n /* Dimensionality */
+);
+
+/* Pseudo-Invert matrix A using lu decomposition */
+/* Return 1 if the matrix is singular, 0 if OK */
+int
+lu_psinvert(
+double **out, /* Output[0..N-1][0..M-1] */
+double **in, /* Input[0..M-1][0..N-1] input matrix */
+int m, /* Rows */
+int n /* Columns */
+);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* LUDECOMP_H */
diff --git a/numlib/numlib.h b/numlib/numlib.h
new file mode 100644
index 0000000..aa34b2d
--- /dev/null
+++ b/numlib/numlib.h
@@ -0,0 +1,18 @@
+
+#ifndef NUMLIB_H
+#define NUMLIB_H
+
+/* Numerical routine library interface declarations */
+
+#include "numsup.h" /* Support routines, macros */
+#include "dnsq.h" /* Non-linear equation solver */
+#include "powell.h" /* Powell multi dimentional minimiser */
+#include "dhsx.h" /* Downhill simplex multi dimentional minimiser */
+#include "ludecomp.h" /* LU decomposition matrix solver */
+#include "svd.h" /* Singular Value decomposition matrix solver */
+#include "zbrent.h" /* 1 dimentional brent root search */
+#include "rand.h" /* Random number generators */
+#include "sobol.h" /* Sub-random vector generators */
+#include "aatree.h" /* Anderson balanced binary tree */
+
+#endif /* NUMLIB_H */
diff --git a/numlib/numsup.c b/numlib/numsup.c
new file mode 100644
index 0000000..7648a62
--- /dev/null
+++ b/numlib/numsup.c
@@ -0,0 +1,1539 @@
+
+/* General Numerical routines support functions, */
+/* and common Argyll support functions. */
+/* (Perhaps these should be moved out of numlib at some stange ?) */
+
+/*
+ * Copyright 1997 - 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+#if defined (NT)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/param.h>
+#include <pthread.h>
+#endif
+
+#include "numsup.h"
+
+/*
+ * TODO: Should probably break all the non-numlib stuff out into
+ * a separate library, so that it can be ommitted.
+ * Or enhance it so that numerical callers of error()
+ * can get a callback on out of memory etc. ???
+ *
+ */
+
+/* Globals */
+
+char *exe_path = "\000"; /* Directory executable resides in ('/' dir separator) */
+//char *error_program = "Unknown"; /* Name to report as responsible for an error */
+
+static int g_log_init = 0; /* Initialised ? */
+extern a1log default_log;
+extern a1log *g_log;
+
+/* Should Vector/Matrix Support functions return NULL on error, */
+/* or call error() ? */
+int ret_null_on_malloc_fail = 0; /* Call error() */
+
+/******************************************************************/
+/* Executable path routine. Sets default error_program too. */
+/******************************************************************/
+
+/* Pass in argv[0] from main() */
+/* Sets the error_program name too */
+void set_exe_path(char *argv0) {
+ int i;
+
+ g_log->tag = argv0;
+ i = strlen(argv0);
+ if ((exe_path = malloc(i + 5)) == NULL) {
+ a1loge(g_log, 1, "set_exe_path: malloc %d bytes failed",i+5);
+ return;
+ }
+ strcpy(exe_path, argv0);
+
+#ifdef NT /* CMD.EXE doesn't give us the full path in argv[0] :-( */
+ /* so we need to fix this */
+ {
+ HMODULE mh;
+ char *tpath = NULL;
+ int pl;
+
+ /* Add an .exe extension if it is missing */
+ if (i < 4 || _stricmp(exe_path +i -4, ".exe") != 0)
+ strcat(exe_path, ".exe");
+
+ if ((mh = GetModuleHandle(exe_path)) == NULL) {
+ a1loge(g_log, 1, "set_exe_path: GetModuleHandle '%s' failed with%d",
+ exe_path,GetLastError());
+ exe_path[0] = '\000';
+ return;
+ }
+
+ /* Retry until we don't truncate the returned path */
+ for (pl = 100; ; pl *= 2) {
+ if (tpath != NULL)
+ free(tpath);
+ if ((tpath = malloc(pl)) == NULL) {
+ a1loge(g_log, 1, "set_exe_path: malloc %d bytes failed",pl);
+ exe_path[0] = '\000';
+ return;
+ }
+ if ((i = GetModuleFileName(mh, tpath, pl)) == 0) {
+ a1loge(g_log, 1, "set_exe_path: GetModuleFileName '%s' failed with%d",
+ tpath,GetLastError());
+ exe_path[0] = '\000';
+ return;
+ }
+ if (i < pl) /* There was enough space */
+ break;
+ }
+ free(exe_path);
+ exe_path = tpath;
+
+ /* Convert from MSWindows to UNIX file separator convention */
+ for (i = 0; ;i++) {
+ if (exe_path[i] == '\000')
+ break;
+ if (exe_path[i] == '\\')
+ exe_path[i] = '/';
+ }
+ }
+#else /* Neither does UNIX */
+
+ if (*exe_path != '/') { /* Not already absolute */
+ char *p, *cp;
+ if (strchr(exe_path, '/') != 0) { /* relative path */
+ cp = ".:"; /* Fake a relative PATH */
+ } else {
+ cp = getenv("PATH");
+ }
+ if (cp != NULL) {
+ int found = 0;
+ while((p = strchr(cp,':')) != NULL
+ || *cp != '\000') {
+ char b1[PATH_MAX], b2[PATH_MAX];
+ int ll;
+ if (p == NULL)
+ ll = strlen(cp);
+ else
+ ll = p - cp;
+ if ((ll + 1 + strlen(exe_path) + 1) > PATH_MAX) {
+ a1loge(g_log, 1, "set_exe_path: Search path exceeds PATH_MAX");
+ exe_path[0] = '\000';
+ return;
+ }
+ strncpy(b1, cp, ll); /* Element of path to search */
+ b1[ll] = '\000';
+ strcat(b1, "/");
+ strcat(b1, exe_path); /* Construct path */
+ if (realpath(b1, b2)) {
+ if (access(b2, 0) == 0) { /* See if exe exits */
+ found = 1;
+ free(exe_path);
+ if ((exe_path = malloc(strlen(b2)+1)) == NULL) {
+ a1loge(g_log, 1, "set_exe_path: malloc %d bytes failed",strlen(b2)+1);
+ exe_path[0] = '\000';
+ return;
+ }
+ strcpy(exe_path, b2);
+ break;
+ }
+ }
+ if (p == NULL)
+ break;
+ cp = p + 1;
+ }
+ if (found == 0)
+ exe_path[0] = '\000';
+ }
+ }
+#endif
+ /* strip the executable path to the base */
+ for (i = strlen(exe_path)-1; i >= 0; i--) {
+ if (exe_path[i] == '/') {
+ char *tpath;
+ if ((tpath = malloc(strlen(exe_path + i))) == NULL) {
+ a1loge(g_log, 1, "set_exe_path: malloc %d bytes failed",strlen(exe_path + i));
+ exe_path[0] = '\000';
+ return;
+ }
+ strcpy(tpath, exe_path + i + 1);
+ g_log->tag = tpath; /* Set g_log->tag to base name */
+ exe_path[i+1] = '\000'; /* (The malloc never gets free'd) */
+ break;
+ }
+ }
+ /* strip off any .exe from the g_log->tag to be more readable */
+ i = strlen(g_log->tag);
+ if (i >= 4
+ && g_log->tag[i-4] == '.'
+ && (g_log->tag[i-3] == 'e' || g_log->tag[i-3] == 'E')
+ && (g_log->tag[i-2] == 'x' || g_log->tag[i-2] == 'X')
+ && (g_log->tag[i-1] == 'e' || g_log->tag[i-1] == 'E'))
+ g_log->tag[i-4] = '\000';
+
+// a1logd(g_log, 1, "exe_path = '%s'\n",exe_path);
+// a1logd(g_log, 1, "g_log->tag = '%s'\n",g_log->tag);
+}
+
+/******************************************************************/
+/* Check "ARGYLL_NOT_INTERACTIVE" environment variable. */
+/******************************************************************/
+
+/* Check if the "ARGYLL_NOT_INTERACTIVE" environment variable is */
+/* set, and set cr_char to '\n' if it is. */
+
+int not_interactive = 0;
+char cr_char = '\r';
+
+void check_if_not_interactive() {
+ char *ev;
+
+ if ((ev = getenv("ARGYLL_NOT_INTERACTIVE")) != NULL) {
+ not_interactive = 1;
+ cr_char = '\n';
+ } else {
+ not_interactive = 0;
+ cr_char = '\r';
+ }
+}
+
+/******************************************************************/
+/* Default verbose/debug/error loger */
+/* It's values can be overridden to redirect these messages. */
+/******************************************************************/
+
+#ifdef NT
+# define A1LOG_LOCK(log) \
+ if (g_log_init == 0) { \
+ InitializeCriticalSection(&log->lock); \
+ g_log_init = 1; \
+ } \
+ EnterCriticalSection(&log->lock)
+# define A1LOG_UNLOCK(log) LeaveCriticalSection(&log->lock)
+#endif
+#ifdef UNIX
+# define A1LOG_LOCK(log) \
+ if (g_log_init == 0) { \
+ pthread_mutex_init(&log->lock, NULL); \
+ g_log_init = 1; \
+ } \
+ pthread_mutex_lock(&log->lock)
+# define A1LOG_UNLOCK(log) pthread_mutex_unlock(&log->lock)
+#endif
+
+
+/* Default verbose logging function - print to stdtout */
+static void a1_default_v_log(void *cntx, a1log *p, char *fmt, va_list args) {
+ vfprintf(stdout, fmt, args);
+ fflush(stdout);
+}
+
+/* Default debug & error logging function - print to stderr */
+static void a1_default_de_log(void *cntx, a1log *p, char *fmt, va_list args) {
+ vfprintf(stderr, fmt, args);
+ fflush(stderr);
+}
+
+#define a1_default_d_log a1_default_de_log
+#define a1_default_e_log a1_default_de_log
+
+
+/* Global log */
+a1log default_log = {
+ 1, /* Refcount of 1 because this is not allocated or free'd */
+ "argyll", /* Default tag */
+ 0, /* Vebose off */
+ 0, /* Debug off */
+ NULL, /* Context */
+ &a1_default_v_log, /* Default verbose to stdout */
+ &a1_default_d_log, /* Default debug to stderr */
+ &a1_default_e_log, /* Default error to stderr */
+ 0, /* error code 0 */
+ { '\000' } /* No error message */
+};
+a1log *g_log = &default_log;
+
+/* If log NULL, allocate a new log and return it, */
+/* otherwise increment reference count and return existing log, */
+/* exit() if malloc fails. */
+a1log *new_a1log(
+ a1log *log, /* Existing log to reference, NULL if none */
+ int verb, /* Verbose level to set */
+ int debug, /* Debug level to set */
+ void *cntx, /* Function context value */
+ /* Vebose log function to call - stdout if NULL */
+ void (*logv)(void *cntx, a1log *p, char *fmt, va_list args),
+ /* Debug log function to call - stderr if NULL */
+ void (*logd)(void *cntx, a1log *p, char *fmt, va_list args),
+ /* Warning/error Log function to call - stderr if NULL */
+ void (*loge)(void *cntx, a1log *p, char *fmt, va_list args)
+) {
+ if (log != NULL) {
+ log->refc++;
+ return log;
+ }
+ if ((log = (a1log *)calloc(sizeof(a1log), 1)) == NULL) {
+ a1loge(g_log, 1, "new_a1log: malloc of a1log failed, calling exit(1)\n");
+ exit(1);
+ }
+ log->verb = verb;
+ log->debug = debug;
+
+ log->cntx = cntx;
+ if (logv != NULL)
+ log->logv = logv;
+ else
+ log->logv = a1_default_v_log;
+
+ if (logd != NULL)
+ log->logd = logd;
+ else
+ log->logd = a1_default_d_log;
+
+ if (loge != NULL)
+ log->loge = loge;
+ else
+ log->loge = a1_default_e_log;
+
+ log->errc = 0;
+ log->errm[0] = '\000';
+
+ return log;
+}
+
+/* Same as above but set default functions */
+a1log *new_a1log_d(a1log *log) {
+ return new_a1log(log, 0, 0, NULL, NULL, NULL, NULL);
+}
+
+/* Decrement reference count and free log. */
+/* Returns NULL */
+a1log *del_a1log(a1log *log) {
+ if (log != NULL) {
+ if (--log->refc <= 0) {
+#ifdef NT
+ DeleteCriticalSection(&log->lock);
+#endif
+#ifdef UNIX
+ pthread_mutex_destroy(&log->lock);
+#endif
+ free(log);
+ }
+ }
+ return NULL;
+}
+
+/* Set the tag. Note that the tage string is NOT copied, just referenced */
+void a1log_tag(a1log *log, char *tag) {
+ log->tag = tag;
+}
+
+/* Log a verbose message if level >= verb */
+void a1logv(a1log *log, int level, char *fmt, ...) {
+ if (log != NULL) {
+ if (log->verb >= level) {
+ va_list args;
+
+ A1LOG_LOCK(log);
+ va_start(args, fmt);
+ log->logv(log->cntx, log, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ }
+ }
+}
+
+/* Log a debug message if level >= debug */
+void a1logd(a1log *log, int level, char *fmt, ...) {
+ if (log != NULL) {
+ if (log->debug >= level) {
+ va_list args;
+
+ A1LOG_LOCK(log);
+ va_start(args, fmt);
+ log->loge(log->cntx, log, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ }
+ }
+}
+
+/* log a warning message to the verbose, debug and error output, */
+void a1logw(a1log *log, char *fmt, ...) {
+ if (log != NULL) {
+ va_list args;
+
+ /* log to all the outputs, but only log once */
+ A1LOG_LOCK(log);
+ va_start(args, fmt);
+ log->loge(log->cntx, log, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ if (log->logd != log->loge) {
+ A1LOG_LOCK(log);
+ va_start(args, fmt);
+ log->logd(log->cntx, log, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ }
+ if (log->logv != log->loge && log->logv != log->logd) {
+ A1LOG_LOCK(log);
+ va_start(args, fmt);
+ log->logv(log->cntx, log, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ }
+ }
+}
+
+/* log an error message to the verbose, debug and error output, */
+/* and latch the error if it is the first. */
+/* ecode = system, icoms or instrument error */
+void a1loge(a1log *log, int ecode, char *fmt, ...) {
+ if (log != NULL) {
+ va_list args;
+
+ if (log->errc == 0) {
+ A1LOG_LOCK(log);
+ log->errc = ecode;
+ va_start(args, fmt);
+ vsnprintf(log->errm, A1_LOG_BUFSIZE, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ }
+ va_start(args, fmt);
+ /* log to all the outputs, but only log once */
+ A1LOG_LOCK(log);
+ va_start(args, fmt);
+ log->loge(log->cntx, log, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ if (log->logd != log->loge) {
+ A1LOG_LOCK(log);
+ va_start(args, fmt);
+ log->logd(log->cntx, log, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ }
+ if (log->logv != log->loge && log->logv != log->logd) {
+ A1LOG_LOCK(log);
+ va_start(args, fmt);
+ log->logv(log->cntx, log, fmt, args);
+ va_end(args);
+ A1LOG_UNLOCK(log);
+ }
+ }
+}
+
+/* Unlatch an error message. */
+/* This just resets errc and errm */
+void a1logue(a1log *log) {
+ if (log != NULL) {
+ log->errc = 0;
+ log->errm[0] = '\000';
+ }
+}
+
+/******************************************************************/
+/* Default verbose/warning/error output routines */
+/* These fall through to, and can be re-director using the */
+/* above log class. */
+/******************************************************************/
+
+/* Some utilities to allow us to format output to log functions */
+/* (Caller aquires lock) */
+static void g_logv(char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ g_log->logv(g_log->cntx, g_log, fmt, args);
+ va_end(args);
+}
+
+static void g_loge(char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ g_log->loge(g_log->cntx, g_log, fmt, args);
+ va_end(args);
+}
+
+void
+verbose(int level, char *fmt, ...) {
+ if (level >= g_log->verb) {
+ va_list args;
+
+ A1LOG_LOCK(g_log);
+ g_logv("%s: ",g_log->tag);
+ va_start(args, fmt);
+ g_log->logv(g_log->cntx, g_log, fmt, args);
+ va_end(args);
+ g_logv("\n");
+ A1LOG_UNLOCK(g_log);
+ }
+}
+
+void
+warning(char *fmt, ...) {
+ va_list args;
+
+ A1LOG_LOCK(g_log);
+ g_loge("%s: Warning - ",g_log->tag);
+ va_start(args, fmt);
+ g_log->loge(g_log->cntx, g_log, fmt, args);
+ va_end(args);
+ g_loge("\n");
+ A1LOG_UNLOCK(g_log);
+}
+
+ATTRIBUTE_NORETURN void
+error(char *fmt, ...) {
+ va_list args;
+
+ A1LOG_LOCK(g_log);
+ g_loge("%s: Error - ",g_log->tag);
+ va_start(args, fmt);
+ g_log->loge(g_log->cntx, g_log, fmt, args);
+ va_end(args);
+ g_loge("\n");
+ A1LOG_UNLOCK(g_log);
+
+ exit(1);
+}
+
+
+/******************************************************************/
+/* Numerical Recipes Vector/Matrix Support functions */
+/******************************************************************/
+/* Note the z suffix versions return zero'd vectors/matricies */
+
+/* Double Vector malloc/free */
+double *dvector(
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ double *v;
+
+ if ((v = (double *) malloc((nh-nl+1) * sizeof(double))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dvector()");
+ }
+ return v-nl;
+}
+
+double *dvectorz(
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ double *v;
+
+ if ((v = (double *) calloc(nh-nl+1, sizeof(double))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dvector()");
+ }
+ return v-nl;
+}
+
+void free_dvector(
+double *v,
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ if (v == NULL)
+ return;
+
+ free((char *) (v+nl));
+}
+
+/* --------------------- */
+/* 2D Double vector malloc/free */
+double **dmatrix(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i;
+ int rows, cols;
+ double **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if ((m = (double **) malloc((rows + 1) * sizeof(double *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dmatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (double *) malloc(rows * cols * sizeof(double))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dmatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1; i <= nrh; i++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + cols;
+
+ return m;
+}
+
+double **dmatrixz(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i;
+ int rows, cols;
+ double **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if ((m = (double **) malloc((rows + 1) * sizeof(double *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dmatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (double *) calloc(rows * cols, sizeof(double))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dmatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1; i <= nrh; i++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + cols;
+
+ return m;
+}
+
+void free_dmatrix(
+double **m,
+int nrl,
+int nrh,
+int ncl,
+int nch
+) {
+ if (m == NULL)
+ return;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ free((char *)(m[nrl-1]));
+ free((char *)(m+nrl-1));
+}
+
+/* --------------------- */
+/* 2D diagonal half matrix vector malloc/free */
+/* A half matrix must have equal rows and columns, */
+/* and the column address must always be >= than the row. */
+double **dhmatrix(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i, j;
+ int rows, cols;
+ double **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if (rows != cols) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("dhmatrix() given unequal rows and columns");
+ }
+
+ if ((m = (double **) malloc((rows + 1) * sizeof(double *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dhmatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (double *) malloc((rows * rows + rows)/2 * sizeof(double))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dhmatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1, j = 1; i <= nrh; i++, j++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + j; /* Start with 1 entry and increment */
+
+ return m;
+}
+
+double **dhmatrixz(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i, j;
+ int rows, cols;
+ double **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if (rows != cols) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("dhmatrix() given unequal rows and columns");
+ }
+
+ if ((m = (double **) malloc((rows + 1) * sizeof(double *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dhmatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (double *) calloc((rows * rows + rows)/2, sizeof(double))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dhmatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1, j = 1; i <= nrh; i++, j++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + j; /* Start with 1 entry and increment */
+
+ return m;
+}
+
+void free_dhmatrix(
+double **m,
+int nrl,
+int nrh,
+int ncl,
+int nch
+) {
+ if (m == NULL)
+ return;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ free((char *)(m[nrl-1]));
+ free((char *)(m+nrl-1));
+}
+
+/* --------------------- */
+/* 2D vector copy */
+void copy_dmatrix(
+double **dst,
+double **src,
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i, j;
+ for (j = nrl; j <= nrh; j++)
+ for (i = ncl; i <= nch; i++)
+ dst[j][i] = src[j][i];
+}
+
+/* Copy a matrix to a 3x3 standard C array */
+void copy_dmatrix_to3x3(
+double dst[3][3],
+double **src,
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i, j;
+ if ((nrh - nrl) > 2)
+ nrh = nrl + 2;
+ if ((nch - ncl) > 2)
+ nch = ncl + 2;
+ for (j = nrl; j <= nrh; j++)
+ for (i = ncl; i <= nch; i++)
+ dst[j][i] = src[j][i];
+}
+
+/* -------------------------------------------------------------- */
+/* Convert standard C type 2D array into an indirect referenced array */
+double **convert_dmatrix(
+double *a, /* base address of normal C array, ie &a[0][0] */
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i, j, nrow = nrh-nrl+1, ncol = nch-ncl+1;
+ double **m;
+
+ /* Allocate pointers to rows */
+ if ((m = (double **) malloc(nrow * sizeof(double*))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in convert_dmatrix()");
+ }
+
+ m -= nrl;
+
+ m[nrl] = a - ncl;
+ for(i=1, j = nrl+1; i < nrow; i++, j++)
+ m[j] = m[j-1] + ncol;
+ /* return pointer to array of pointers */
+ return m;
+}
+
+/* Free the indirect array reference (but not array) */
+void free_convert_dmatrix(
+double **m,
+int nrl,
+int nrh,
+int ncl,
+int nch
+) {
+ if (m == NULL)
+ return;
+
+ free((char*) (m+nrl));
+}
+
+/* -------------------------- */
+/* Float vector malloc/free */
+float *fvector(
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ float *v;
+
+ if ((v = (float *) malloc((nh-nl+1) * sizeof(float))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in fvector()");
+ }
+ return v-nl;
+}
+
+float *fvectorz(
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ float *v;
+
+ if ((v = (float *) calloc(nh-nl+1, sizeof(float))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in fvector()");
+ }
+ return v-nl;
+}
+
+void free_fvector(
+float *v,
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ if (v == NULL)
+ return;
+
+ free((char *) (v+nl));
+}
+
+/* --------------------- */
+/* 2D Float matrix malloc/free */
+float **fmatrix(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i;
+ int rows, cols;
+ float **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if ((m = (float **) malloc((rows + 1) * sizeof(float *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dmatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (float *) malloc(rows * cols * sizeof(float))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dmatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1; i <= nrh; i++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + cols;
+
+ return m;
+}
+
+float **fmatrixz(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i;
+ int rows, cols;
+ float **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if ((m = (float **) malloc((rows + 1) * sizeof(float *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dmatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (float *) calloc(rows * cols, sizeof(float))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in dmatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1; i <= nrh; i++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + cols;
+
+ return m;
+}
+
+void free_fmatrix(
+float **m,
+int nrl,
+int nrh,
+int ncl,
+int nch
+) {
+ if (m == NULL)
+ return;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ free((char *)(m[nrl-1]));
+ free((char *)(m+nrl-1));
+}
+
+/* ------------------ */
+/* Integer vector malloc/free */
+int *ivector(
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ int *v;
+
+ if ((v = (int *) malloc((nh-nl+1) * sizeof(int))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in ivector()");
+ }
+ return v-nl;
+}
+
+int *ivectorz(
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ int *v;
+
+ if ((v = (int *) calloc(nh-nl+1, sizeof(int))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in ivector()");
+ }
+ return v-nl;
+}
+
+void free_ivector(
+int *v,
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ if (v == NULL)
+ return;
+
+ free((char *) (v+nl));
+}
+
+
+/* ------------------------------ */
+/* 2D integer matrix malloc/free */
+
+int **imatrix(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i;
+ int rows, cols;
+ int **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if ((m = (int **) malloc((rows + 1) * sizeof(int *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in imatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (int *) malloc(rows * cols * sizeof(int))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in imatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1; i <= nrh; i++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + cols;
+
+ return m;
+}
+
+int **imatrixz(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i;
+ int rows, cols;
+ int **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if ((m = (int **) malloc((rows + 1) * sizeof(int *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in imatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (int *) calloc(rows * cols, sizeof(int))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in imatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1; i <= nrh; i++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + cols;
+
+ return m;
+}
+
+void free_imatrix(
+int **m,
+int nrl,
+int nrh,
+int ncl,
+int nch
+) {
+ if (m == NULL)
+ return;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ free((char *)(m[nrl-1]));
+ free((char *)(m+nrl-1));
+}
+
+/* ------------------ */
+/* Short vector malloc/free */
+short *svector(
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ short *v;
+
+ if ((v = (short *) malloc((nh-nl+1) * sizeof(short))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in svector()");
+ }
+ return v-nl;
+}
+
+short *svectorz(
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ short *v;
+
+ if ((v = (short *) calloc(nh-nl+1, sizeof(short))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in svector()");
+ }
+ return v-nl;
+}
+
+void free_svector(
+short *v,
+int nl, /* Lowest index */
+int nh /* Highest index */
+) {
+ if (v == NULL)
+ return;
+
+ free((char *) (v+nl));
+}
+
+
+/* ------------------------------ */
+/* 2D short vector malloc/free */
+
+short **smatrix(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i;
+ int rows, cols;
+ short **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if ((m = (short **) malloc((rows + 1) * sizeof(short *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in smatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (short *) malloc(rows * cols * sizeof(short))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in smatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1; i <= nrh; i++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + cols;
+
+ return m;
+}
+
+short **smatrixz(
+int nrl, /* Row low index */
+int nrh, /* Row high index */
+int ncl, /* Col low index */
+int nch /* Col high index */
+) {
+ int i;
+ int rows, cols;
+ short **m;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ rows = nrh - nrl + 1;
+ cols = nch - ncl + 1;
+
+ if ((m = (short **) malloc((rows + 1) * sizeof(short *))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in smatrix(), pointers");
+ }
+ m -= nrl; /* Offset to nrl */
+ m += 1; /* Make nrl-1 pointer to main allocation, in case rows get swaped */
+
+ if ((m[nrl-1] = (short *) calloc(rows * cols, sizeof(short))) == NULL) {
+ if (ret_null_on_malloc_fail)
+ return NULL;
+ else
+ error("Malloc failure in smatrix(), array");
+ }
+
+ m[nrl] = m[nrl-1] - ncl; /* Set first row address, offset to ncl */
+ for(i = nrl+1; i <= nrh; i++) /* Set subsequent row addresses */
+ m[i] = m[i-1] + cols;
+
+ return m;
+}
+
+void free_smatrix(
+short **m,
+int nrl,
+int nrh,
+int ncl,
+int nch
+) {
+ if (m == NULL)
+ return;
+
+ if (nrh < nrl) /* Prevent failure for 0 dimension */
+ nrh = nrl;
+ if (nch < ncl)
+ nch = ncl;
+
+ free((char *)(m[nrl-1]));
+ free((char *)(m+nrl-1));
+}
+
+/***************************/
+/* Basic matrix operations */
+/***************************/
+
+/* Transpose a 0 base matrix */
+void matrix_trans(double **d, double **s, int nr, int nc) {
+ int i, j;
+
+ for (i = 0; i < nr; i++) {
+ for (j = 0; j < nc; j++) {
+ d[j][i] = s[i][j];
+ }
+ }
+}
+
+/* Multiply two 0 based matricies */
+/* Return nz on matching error */
+int matrix_mult(
+ double **d, int nr, int nc,
+ double **s1, int nr1, int nc1,
+ double **s2, int nr2, int nc2
+) {
+ int i, j, k;
+
+ /* s1 and s2 must mesh */
+ if (nc1 != nr2)
+ return 1;
+
+ /* Output rows = s1 rows */
+ if (nr != nr1)
+ return 2;
+
+ /* Output colums = s2 columns */
+ if (nc != nc2)
+ return 2;
+
+ for (i = 0; i < nr1; i++) {
+ for (j = 0; j < nc2; j++) {
+ d[i][j] = 0.0;
+ for (k = 0; k < nc1; k++) {
+ d[i][j] += s1[i][k] * s2[k][j];
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Diagnostic - print to g_log debug */
+void matrix_print(char *c, double **a, int nr, int nc) {
+ int i, j;
+ a1logd(g_log, 0, "%s, %d x %d\n",c,nr,nc);
+
+ for (j = 0; j < nr; j++) {
+ a1logd(g_log, 0, " ");
+ for (i = 0; i < nc; i++) {
+ a1logd(g_log, 0, " %.2f",a[j][i]);
+ }
+ a1logd(g_log, 0, "\n");
+ }
+}
+
+
+/*******************************************/
+/* Platform independent IEE754 conversions */
+/*******************************************/
+
+/* Cast a native double to an IEEE754 encoded single precision value, */
+/* in a platform independent fashion. (ie. This works even */
+/* on the rare platforms that don't use IEEE 754 floating */
+/* point for their C implementation) */
+ORD32 doubletoIEEE754(double d) {
+ ORD32 sn = 0, ep = 0, ma;
+ ORD32 id;
+
+ /* Convert double to IEEE754 single precision. */
+ /* This would be easy if we're running on an IEEE754 architecture, */
+ /* but isn't generally portable, so we use ugly code: */
+
+ if (d < 0.0) {
+ sn = 1;
+ d = -d;
+ }
+ if (d != 0.0) {
+ int ee;
+ ee = (int)floor(log(d)/log(2.0));
+ if (ee < -126) /* Allow for denormalized */
+ ee = -126;
+ d *= pow(0.5, (double)(ee - 23));
+ ee += 127;
+ if (ee < 1) /* Too small */
+ ee = 0; /* Zero or denormalised */
+ else if (ee > 254) { /* Too large */
+ ee = 255; /* Infinity */
+ d = 0.0;
+ }
+ ep = ee;
+ } else {
+ ep = 0; /* Zero */
+ }
+ ma = ((ORD32)d) & ((1 << 23)-1);
+ id = (sn << 31) | (ep << 23) | ma;
+
+ return id;
+}
+
+/* Cast a an IEEE754 encoded single precision value to a native double, */
+/* in a platform independent fashion. (ie. This works even */
+/* on the rare platforms that don't use IEEE 754 floating */
+/* point for their C implementation) */
+double IEEE754todouble(ORD32 ip) {
+ double op;
+ ORD32 sn = 0, ep = 0, ma;
+
+ sn = (ip >> 31) & 0x1;
+ ep = (ip >> 23) & 0xff;
+ ma = ip & 0x7fffff;
+
+ if (ep == 0) { /* Zero or denormalised */
+ op = (double)ma/(double)(1 << 23);
+ op *= pow(2.0, (-126.0));
+ } else {
+ op = (double)(ma | (1 << 23))/(double)(1 << 23);
+ op *= pow(2.0, (((int)ep)-127.0));
+ }
+ if (sn)
+ op = -op;
+ return op;
+}
+
+/* Cast a native double to an IEEE754 encoded double precision value, */
+/* in a platform independent fashion. (ie. This works even */
+/* on the rare platforms that don't use IEEE 754 floating */
+/* point for their C implementation) */
+ORD64 doubletoIEEE754_64(double d) {
+ ORD32 sn = 0, ep = 0;
+ ORD64 ma, id;
+
+ /* Convert double to IEEE754 double precision. */
+ /* This would be easy if we know we're running on an IEEE754 architecture, */
+ /* but isn't generally portable, so we use ugly code: */
+
+ if (d < 0.0) {
+ sn = 1;
+ d = -d;
+ }
+ if (d != 0.0) {
+ int ee;
+ ee = (int)floor(log(d)/log(2.0));
+ if (ee < -1022) /* Allow for denormalized */
+ ee = -1022;
+ d *= pow(0.5, (double)(ee - 52));
+ ee += 1023; /* Exponent bias */
+ if (ee < 1) /* Too small */
+ ee = 0; /* Zero or denormalised */
+ else if (ee > 2046) { /* Too large */
+ ee = 2047; /* Infinity */
+ d = 0.0;
+ }
+ ep = ee;
+ } else {
+ ep = 0; /* Zero */
+ }
+ ma = ((ORD64)d) & (((ORD64)1 << 52)-1);
+ id = ((ORD64)sn << 63) | ((ORD64)ep << 52) | ma;
+
+ return id;
+}
+
+/* Cast a an IEEE754 encode double precision value to a native double, */
+/* in a platform independent fashion. (ie. This works even */
+/* on the rare platforms that don't use IEEE 754 floating */
+/* point for their C implementation) */
+double IEEE754_64todouble(ORD64 ip) {
+ double op;
+ ORD32 sn = 0, ep = 0;
+ INR64 ma;
+
+ sn = (ip >> 63) & 0x1;
+ ep = (ip >> 52) & 0x7ff;
+ ma = ip & (((INR64)1 << 52)-1);
+
+ if (ep == 0) { /* Zero or denormalised */
+ op = (double)ma/(double)((INR64)1 << 52);
+ op *= pow(2.0, -1022.0);
+ } else {
+ op = (double)(ma | ((INR64)1 << 52))/(double)((INR64)1 << 52);
+ op *= pow(2.0, (((int)ep)-1023.0));
+ }
+ if (sn)
+ op = -op;
+ return op;
+}
+
+/* Return a string representation of a 32 bit ctime. */
+/* A static buffer is used. There is no \n at the end */
+char *ctime_32(const INR32 *timer) {
+ char *rv;
+#if defined(_MSC_VER) && __MSVCRT_VERSION__ >= 0x0601
+ rv = _ctime32((const __time32_t *)timer);
+#else
+ time_t timerv = (time_t) *timer; /* May case to 64 bit */
+ rv = ctime(&timerv);
+#endif
+
+ if (rv != NULL)
+ rv[strlen(rv)-1] = '\000';
+
+ return rv;
+}
+
+/* Return a string representation of a 64 bit ctime. */
+/* A static buffer is used. There is no \n at the end */
+char *ctime_64(const INR64 *timer) {
+ char *rv;
+#if defined(_MSC_VER) && __MSVCRT_VERSION__ >= 0x0601
+ rv = _ctime64((const __time64_t *)timer);
+#else
+ time_t timerv;
+
+ if (sizeof(time_t) == 4 && *timer > 0x7fffffff)
+ return NULL;
+ timerv = (time_t) *timer; /* May truncate to 32 bits */
+ rv = ctime(&timerv);
+#endif
+
+ if (rv != NULL)
+ rv[strlen(rv)-1] = '\000';
+
+ return rv;
+}
diff --git a/numlib/numsup.h b/numlib/numsup.h
new file mode 100644
index 0000000..7db7676
--- /dev/null
+++ b/numlib/numsup.h
@@ -0,0 +1,380 @@
+#ifndef NUMSUP_H
+
+/* Numerical routine general support declarations */
+
+/*
+ * Copyright 2000-2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+#include <math.h>
+
+#ifdef NT
+#include <basetsd.h> /* So jpg header doesn't define INT32 */
+# if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
+# undef _WIN32_WINNT
+# define _WIN32_WINNT 0x0501
+# endif
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#endif
+#ifdef UNIX
+# include <pthread.h>
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* =========================================================== */
+/* Should this go in spectro/conv.h ?? */
+/* =========================================================== */
+/* Platform specific primitive defines. */
+/* This really needs checking for each different platform. */
+/* Using C99 and MSC covers a lot of cases, */
+/* and the fallback default is pretty reliable with modern compilers and machines. */
+/* (duplicated in icc.h) */
+
+#if (__STDC_VERSION__ >= 199901L) /* C99 */
+
+#include <stdint.h>
+
+#define INR8 int8_t /* 8 bit signed */
+#define INR16 int16_t /* 16 bit signed */
+#define INR32 int32_t /* 32 bit signed */
+#define INR64 int64_t /* 64 bit signed - not used in icclib */
+#define ORD8 uint8_t /* 8 bit unsigned */
+#define ORD16 uint16_t /* 16 bit unsigned */
+#define ORD32 uint32_t /* 32 bit unsigned */
+#define ORD64 uint64_t /* 64 bit unsigned - not used in icclib */
+
+#define PNTR intptr_t
+
+/* printf format precision specifier */
+#define PF64PREC "ll"
+
+/* Constant precision specifier */
+#define CF64PREC "LL"
+
+#ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+#endif
+
+#else /* !__STDC_VERSION__ */
+#ifdef _MSC_VER
+
+#define INR8 __int8 /* 8 bit signed */
+#define INR16 __int16 /* 16 bit signed */
+#define INR32 __int32 /* 32 bit signed */
+#define INR64 __int64 /* 64 bit signed - not used in icclib */
+#define ORD8 unsigned __int8 /* 8 bit unsigned */
+#define ORD16 unsigned __int16 /* 16 bit unsigned */
+#define ORD32 unsigned __int32 /* 32 bit unsigned */
+#define ORD64 unsigned __int64 /* 64 bit unsigned - not used in icclib */
+
+#define PNTR UINT_PTR
+
+#define vsnprintf _vsnprintf
+
+/* printf format precision specifier */
+#define PF64PREC "I64"
+
+/* Constant precision specifier */
+#define CF64PREC "LL"
+
+#ifndef ATTRIBUTE_NORETURN
+# define ATTRIBUTE_NORETURN __declspec(noreturn)
+#endif
+
+#else /* !_MSC_VER */
+
+/* The following works on a lot of modern systems, including */
+/* LP64 model 64 bit modes */
+
+#define INR8 signed char /* 8 bit signed */
+#define INR16 signed short /* 16 bit signed */
+#define INR32 signed int /* 32 bit signed */
+#define ORD8 unsigned char /* 8 bit unsigned */
+#define ORD16 unsigned short /* 16 bit unsigned */
+#define ORD32 unsigned int /* 32 bit unsigned */
+
+#ifdef __GNUC__
+#define INR64 long long /* 64 bit signed - not used in icclib */
+#define ORD64 unsigned long long /* 64 bit unsigned - not used in icclib */
+
+/* printf format precision specifier */
+#define PF64PREC "ll"
+
+/* Constant precision specifier */
+#define CF64PREC "LL"
+
+#ifndef ATTRIBUTE_NORETURN
+#define ATTRIBUTE_NORETURN __attribute__((noreturn))
+#endif
+
+#endif /* __GNUC__ */
+/* =========================================================== */
+
+#define PNTR unsigned long
+
+#endif /* !_MSC_VER */
+#endif /* !__STDC_VERSION__ */
+/* Some default math limits and constants */
+#ifndef DBL_EPSILON
+#define DBL_EPSILON 2.2204460492503131e-016 /* 1.0+DBL_EPSILON != 1.0 */
+#endif
+#ifndef DBL_MIN
+#define DBL_MIN 2.2250738585072014e-308 /* IEEE 64 bit min value */
+#endif
+#ifndef DBL_MAX
+#define DBL_MAX 1.7976931348623158e+308 /* IEEE 64 bit max value */
+#endif
+#ifndef DBL_PI
+#define DBL_PI 3.1415926535897932384626433832795
+#endif
+
+/* =========================================================== */
+/* General verbose, debug, warning and error logging object and functions */
+
+/*
+
+ Verbose is simply informational for the end user during normal
+ operation, typically on stdout or in a text information log.
+ This will be logged to the verbose log stream. Level:
+
+ 0 = Off
+ 1 = Brief progress and informational messages
+ 2 = Much more verbose information
+ 3+ = Very verbose detail
+
+ Debug output is for the developer, to trace what has happened so
+ as to help diagnose a fault. This will be logged to the debug log stream.
+ Level:
+
+ 0 = Off
+ 1 = Brief debug info and any internal errors that may be significant
+ if something subsequently fails.
+ 1-5 = Application internals at increasing level of detail
+ 2-6 = Driver level.(overlaps app & coms)
+ 6-7 = high level communications
+ 8-9 = low level communications.
+
+ Warning is a serious internal fault that is going to be ignored at the
+ point it is noticed, but may explain any unexpected behaviour.
+ It will be reported to the vebose, debug and error log streams.
+
+ An error is something that is regarded as fatal at the point it
+ is noticed. It will be reported to the vebose, debug and error log
+ streams. The error code and error message will be latched within the
+ log object if it is the first error logged. It can (theoretically) be
+ treated as a warning at a higher calling level by calling
+ a1logue (unlatch error) to reset the error code and message.
+
+ */
+
+#define A1_LOG_BUFSIZE 500
+
+
+struct _a1log {
+ int refc; /* Reference count */
+ char *tag; /* Optional tag name */
+ int verb; /* Current verbosity level (public) */
+ int debug; /* Current debug level (public) */
+
+ void *cntx; /* Context to provide to log functions */
+ void (*logv)(void *cntx, struct _a1log *p, char *fmt, va_list args);
+ /* Implementation of log verbose */
+ void (*logd)(void *cntx, struct _a1log *p, char *fmt, va_list args);
+ /* Implementation of log debug */
+ void (*loge)(void *cntx, struct _a1log *p, char *fmt, va_list args);
+ /* Implementation of log warning/error */
+
+ int errc; /* error code */
+ char errm[A1_LOG_BUFSIZE]; /* error message (public) */
+
+#ifdef NT
+ CRITICAL_SECTION lock;
+#endif
+#ifdef UNIX
+ pthread_mutex_t lock;
+#endif
+}; typedef struct _a1log a1log;
+
+
+
+/* If log NULL, allocate a new log and return it, */
+/* otherwise increment reference count and return existing log, */
+/* exit() if malloc fails. */
+a1log *new_a1log(
+ a1log *log, /* Existing log to reference, NULL if none */
+ int verb, /* Verbose level to set */
+ int debug, /* Debug level to set */
+ void *cntx, /* Function context value */
+ /* Debug log function to call - stdout if NULL */
+ void (*logv)(void *cntx, a1log *p, char *fmt, va_list args),
+ /* Debug log function to call - stderr if NULL */
+ void (*logd)(void *cntx, a1log *p, char *fmt, va_list args),
+ /* Warning/error Log function to call - stderr if NULL */
+ void (*loge)(void *cntx, a1log *p, char *fmt, va_list args)
+);
+
+/* Same as above but set default functions */
+a1log *new_a1log_d(a1log *log);
+
+/* Decrement reference count and free log. */
+/* Returns NULL */
+a1log *del_a1log(a1log *log);
+
+/* Set the tag. Note that the tage string is NOT copied, just referenced */
+void a1log_tag(a1log *log, char *tag);
+
+/* Log a verbose message if level >= verb */
+void a1logv(a1log *log, int level, char *fmt, ...);
+
+/* Log a debug message if level >= debug */
+void a1logd(a1log *log, int level, char *fmt, ...);
+
+/* log a warning message to the error output */
+void a1logw(a1log *log, char *fmt, ...);
+
+/* log an error message, */
+/* ecode = system, icoms or instrument error */
+void a1loge(a1log *log, int ecode, char *fmt, ...);
+
+/* Unlatch an error message. */
+/* This resets errc and errm */
+void a1logue(a1log *log);
+
+/* =========================================================== */
+/* Globals used to hold certain information */
+extern char *exe_path; /* Path leading to executable, not including exe name itself. */
+ /* Always uses '/' separator */
+ /* Malloce'd - won't be freed on exit (intended leak) */
+
+extern a1log *g_log; /* Default log */
+
+/* These legacy functions that now call through to the default log */
+#define error_program g_log->tag
+extern void set_exe_path(char *arg0);
+
+extern void ATTRIBUTE_NORETURN error(char *fmt, ...);
+extern void warning(char *fmt, ...);
+extern void verbose(int level, char *fmt, ...);
+
+extern int ret_null_on_malloc_fail;
+
+extern void check_if_not_interactive();
+extern int not_interactive;
+extern char cr_char;
+
+/* =========================================================== */
+
+/* Numerical recipes vector/matrix support functions */
+/* Note that the index arguments are the inclusive low and high values */
+
+/* Double */
+double *dvector(int nl,int nh);
+double *dvectorz(int nl,int nh);
+void free_dvector(double *v,int nl,int nh);
+
+double **dmatrix(int nrl, int nrh, int ncl, int nch);
+double **dmatrixz(int nrl, int nrh, int ncl, int nch);
+void free_dmatrix(double **m, int nrl, int nrh, int ncl, int nch);
+
+double **dhmatrix(int nrl, int nrh, int ncl, int nch);
+double **dhmatrixz(int nrl, int nrh, int ncl, int nch);
+void free_dhmatrix(double **m, int nrl, int nrh, int ncl, int nch);
+
+void copy_dmatrix(double **dst, double **src, int nrl, int nrh, int ncl, int nch);
+void copy_dmatrix_to3x3(double dst[3][3], double **src, int nrl, int nrh, int ncl, int nch);
+
+double **convert_dmatrix(double *a,int nrl,int nrh,int ncl,int nch);
+void free_convert_dmatrix(double **m,int nrl,int nrh,int ncl,int nch);
+
+
+/* Float */
+float *fvector(int nl,int nh);
+float *fvectorz(int nl,int nh);
+void free_fvector(float *v,int nl,int nh);
+
+float **fmatrix(int nrl, int nrh, int ncl, int nch);
+float **fmatrixz(int nrl, int nrh, int ncl, int nch);
+void free_fmatrix(float **m, int nrl, int nrh, int ncl, int nch);
+
+
+/* Int */
+int *ivector(int nl,int nh);
+int *ivectorz(int nl,int nh);
+void free_ivector(int *v,int nl,int nh);
+
+int **imatrix(int nrl,int nrh,int ncl,int nch);
+int **imatrixz(int nrl,int nrh,int ncl,int nch);
+void free_imatrix(int **m,int nrl,int nrh,int ncl,int nch);
+
+
+/* Short */
+short *svector(int nl, int nh);
+short *svectorz(int nl, int nh);
+void free_svector(short *v, int nl, int nh);
+
+short **smatrix(int nrl,int nrh,int ncl,int nch);
+short **smatrixz(int nrl,int nrh,int ncl,int nch);
+void free_smatrix(short **m,int nrl,int nrh,int ncl,int nch);
+
+/* ----------------------------------------------------------- */
+/* Basic matrix operations */
+
+/* Transpose a 0 base matrix */
+void matrix_trans(double **d, double **s, int nr, int nc);
+
+/* Matrix multiply 0 based matricies */
+int matrix_mult(
+ double **d, int nr, int nc,
+ double **s1, int nr1, int nc1,
+ double **s2, int nr2, int nc2
+);
+
+/* Diagnostic */
+void matrix_print(char *c, double **a, int nr, int nc);
+
+/* =========================================================== */
+
+/* Cast a native double to an IEEE754 encoded single precision value, */
+/* in a platform independent fashion. */
+ORD32 doubletoIEEE754(double d);
+
+/* Cast an IEEE754 encoded single precision value to a native double, */
+/* in a platform independent fashion. */
+double IEEE754todouble(ORD32 ip);
+
+
+/* Cast a native double to an IEEE754 encoded double precision value, */
+/* in a platform independent fashion. */
+ORD64 doubletoIEEE754_64(double d);
+
+/* Cast an IEEE754 encoded double precision value to a native double, */
+/* in a platform independent fashion. */
+double IEEE754_64todouble(ORD64 ip);
+
+/* Return a string representation of a 32 bit ctime. */
+/* A static buffer is used. There is no \n at the end */
+char *ctime_32(const INR32 *timer);
+
+/* Return a string representation of a 64 bit ctime. */
+/* A static buffer is used. There is no \n at the end */
+char *ctime_64(const INR64 *timer);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define NUMSUP_H
+#endif /* NUMSUP_H */
diff --git a/numlib/powell.c b/numlib/powell.c
new file mode 100644
index 0000000..5d2adac
--- /dev/null
+++ b/numlib/powell.c
@@ -0,0 +1,691 @@
+
+/* Multi-dimentional minizer using Powell or Conjugate Gradient methods */
+/* This is good for smoother, well behaved functions. */
+
+/* Code is an original expression of the algorithms decsribed in */
+/* "Numerical Recipes in C", by W.H.Press, B.P.Flannery, */
+/* S.A.Teukolsky & W.T.Vetterling. */
+
+/*
+ * Copyright 2000, 2006 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.
+ */
+
+/* TTBD:
+ Fix error handling to return status (malloc, excessive itters)
+ Create to "safe" library ?
+ Make standalone - ie remove numsup ?
+ */
+
+/*
+
+ Idea for improving progress accounting:
+
+ count number of itterations already done (pitter)
+ estimate number yet needed (fitter)
+ progress = pitter/(pitter + fitter)
+
+ Number yet needed estimated by progress of retval delta
+ againsth threshold target.
+
+ ie fitters = (lastdel - curdel)/(curdel - stopth)
+
+*/
+
+/* Note that all arrays are indexed from 0 */
+
+#include "numsup.h"
+#include "powell.h"
+
+#undef SLOPE_SANITY_CHECK /* exermental */
+#undef ABSTOL /* Make tollerance absolute */
+#undef DEBUG /* Some debugging printfs (not comprehensive) */
+
+#ifdef DEBUG
+#undef DBG
+#define DBG(xxx) printf xxx ;
+#else
+#undef DBG
+#define DBG(xxx)
+#endif
+
+static double linmin(double p[], double xi[], int n, double ftol,
+ double (*func)(void *fdata, double tp[]), void *fdata);
+
+/* Standard interface for powell function */
+/* return 0 on sucess, 1 on failure due to excessive itterions */
+/* Result will be in cp */
+int powell(
+double *rv, /* If not NULL, return the residual error */
+int di, /* Dimentionality */
+double cp[], /* Initial starting point */
+double s[], /* Size of initial search area */
+#ifdef ABSTOL
+double ftol, /* Absolute tollerance of error change to stop on */
+#else
+double ftol, /* Relative tollerance of error change to stop on */
+#endif
+int maxit, /* Maximum iterations allowed */
+double (*func)(void *fdata, double tp[]), /* Error function to evaluate */
+void *fdata, /* Opaque data needed by function */
+void (*prog)(void *pdata, int perc), /* Optional progress percentage callback */
+void *pdata /* Opaque data needed by prog() */
+) {
+ int i;
+ double **dmtx; /* Direction vector */
+ double *spt; /* Sarting point before exploring all the directions */
+ double *xpt; /* Extrapolated point */
+ double *svec; /* Search vector */
+ int iter;
+ double retv; /* Returned function value at p */
+ double stopth; /* Current stop threshold */
+ double startdel = -1.0; /* Initial change in function value */
+ double curdel; /* Current change in function value */
+ int pc = 0; /* Percentage complete */
+
+ dmtx = dmatrixz(0, di-1, 0, di-1); /* Zero filled */
+ spt = dvector(0,di-1);
+ xpt = dvector(0,di-1);
+ svec = dvector(0,di-1);
+
+ /* Create initial direction matrix by */
+ /* placing search start on diagonal */
+ for (i = 0; i < di; i++)
+ dmtx[i][i] = s[i];
+
+ /* Save the starting point */
+ for (i = 0; i < di; i++)
+ spt[i] = cp[i];
+
+ if (prog != NULL) /* Report initial progress */
+ prog(pdata, pc);
+
+ /* Initial function evaluation */
+ retv = (*func)(fdata, cp);
+
+//printf("~1 ### initial retv = %f\n",retv);
+ /* Itterate untill we converge on a solution, or give up. */
+ for (iter = 1; iter < maxit; iter++) {
+ int j;
+ double lretv; /* Last function return value */
+ int ibig = 0; /* Index of biggest delta */
+ double del = 0.0; /* Biggest function value decrease */
+ double pretv; /* Previous function return value */
+
+ pretv = retv; /* Save return value at top of itteration */
+
+ /* Loop over all directions in the set */
+ for (i = 0; i < di; i++) {
+
+ DBG(("Looping over direction %d\n",i))
+
+ for (j = 0; j < di; j++) /* Extract this direction to make search vector */
+ svec[j] = dmtx[j][i];
+
+//printf("~1 ### chosen dir = %f %f\n", svec[0],svec[1]);
+ /* Minimize in that direction */
+ lretv = retv;
+ retv = linmin(cp, svec, di, ftol, func, fdata);
+
+ /* Record bigest function decrease, and dimension it occured on */
+ if (fabs(lretv - retv) > del) {
+ del = fabs(lretv - retv);
+ ibig = i;
+ }
+ }
+
+//printf("~1 ### biggest change was dir %d by %f\n", ibig, del);
+
+#ifdef ABSTOL
+ stopth = ftol; /* Absolute tollerance */
+#else
+ stopth = ftol * 0.5 * (fabs(pretv) + fabs(retv) + DBL_EPSILON);
+#endif
+ curdel = fabs(pretv - retv);
+ if (startdel < 0.0) {
+ startdel = curdel;
+ } else {
+ int tt;
+ tt = (int)(100.0 * pow((log(curdel) - log(startdel))/(log(stopth) - log(startdel)), 4.0) + 0.5);
+ if (tt > pc && tt < 100) {
+ pc = tt;
+ if (prog != NULL) /* Report initial progress */
+ prog(pdata, pc);
+ }
+
+ }
+ /* If we have had at least one change of direction and */
+ /* reached a suitable tollerance, then finish */
+ if (iter > 1 && curdel <= stopth) {
+//printf("~1 ### stopping on itter %d because curdel %f <= stopth %f\n",iter, curdel,stopth);
+ DBG(("Reached stop tollerance because curdel %f <= stopth %f\n",curdel,stopth))
+ break;
+ }
+ DBG(("Not stopping because curdel %f > stopth %f\n",curdel,stopth))
+
+//printf("~1 ### recomputing direction\n");
+ for (i = 0; i < di; i++) {
+ svec[i] = cp[i] - spt[i]; /* Average direction moved after minimization round */
+ xpt[i] = cp[i] + svec[i]; /* Extrapolated point after round of minimization */
+ spt[i] = cp[i]; /* New start point for next round */
+ }
+//printf("~1 ### new dir = %f %f\n", svec[0],svec[1]);
+
+ /* Function value at extrapolated point */
+ lretv = (*func)(fdata, xpt);
+
+ if (lretv < pretv) { /* If extrapolation is an improvement */
+ double t, t1, t2;
+
+//printf("~1 ### extrap is improvement\n");
+ t1 = pretv - retv - del;
+ t2 = pretv - lretv;
+ t = 2.0 * (pretv -2.0 * retv + lretv) * t1 * t1 - del * t2 * t2;
+ if (t < 0.0) {
+//printf("~1 ### move to min in new direction\n");
+ /* Move to the minimum of the new direction */
+ retv = linmin(cp, svec, di, ftol, func, fdata);
+
+ for (i = 0; i < di; i++) { /* Save the new direction */
+ dmtx[i][ibig] = svec[i]; /* by replacing best previous */
+ }
+ }
+ }
+ }
+
+//printf("~1 iters = %d\n",iter);
+ /* Free up all the temporary vectors and matrix */
+ free_dvector(svec,0,di-1);
+ free_dvector(xpt,0,di-1);
+ free_dvector(spt,0,di-1);
+ free_dmatrix(dmtx, 0, di-1, 0, di-1);
+
+ if (prog != NULL) /* Report final progress */
+ prog(pdata, 100);
+
+ if (rv != NULL)
+ *rv = retv;
+
+ if (iter < maxit)
+ return 0;
+
+ DBG(("powell: returning 1 due to excessive itterations\n"))
+ return 1; /* Failed due to execessive itterations */
+}
+
+/* -------------------------------------- */
+/* Conjugate Gradient optimiser */
+/* return 0 on sucess, 1 on failure due to excessive itterions */
+/* Result will be in cp */
+/* Note that we could use gradient in line minimiser, */
+/* but haven't bothered yet. */
+int conjgrad(
+double *rv, /* If not NULL, return the residual error */
+int di, /* Dimentionality */
+double cp[], /* Initial starting point */
+double s[], /* Size of initial search area */
+#ifdef ABSTOL
+double ftol, /* Absolute tollerance of error change to stop on */
+#else
+double ftol, /* Relative tollerance of error change to stop on */
+#endif
+int maxit, /* Maximum iterations allowed */
+double (*func)(void *fdata, double tp[]), /* Error function to evaluate */
+double (*dfunc)(void *fdata, double dp[], double tp[]), /* Gradient function to evaluate */
+void *fdata, /* Opaque data needed by function */
+void (*prog)(void *pdata, int perc), /* Optional progress percentage callback */
+void *pdata /* Opaque data needed by prog() */
+) {
+ int i, iter;
+ double *svec; /* Search vector */
+ double *gvec; /* G direction vector */
+ double *hvec; /* H direction vector */
+ double retv; /* Returned function value at p */
+ double stopth; /* Current stop threshold */
+ double startdel = -1.0; /* Initial change in function value */
+ double curdel; /* Current change in function value */
+ double svec_sca; /* initial svec scale factor */
+ int pc = 0; /* Percentage complete */
+
+ svec = dvector(0,di-1);
+ gvec = dvector(0,di-1);
+ hvec = dvector(0,di-1);
+
+ if (prog != NULL) /* Report initial progress */
+ prog(pdata, pc);
+
+ /* Initial function evaluation */
+ retv = (*dfunc)(fdata, svec, cp);
+
+ /* svec[] seems to be large after this. */
+ /* Rescale it to conform to maximum of s[] */
+ for (svec_sca = 0.0, i = 0; i < di; i++) {
+ if (fabs(svec[i]) > svec_sca)
+ svec_sca = fabs(svec[i]);
+ }
+ /* set scale so largest <= 1 */
+ if (svec_sca < 1e-12)
+ svec_sca = 1.0;
+ else
+ svec_sca = 1.0/svec_sca;
+
+//printf("~1 ### initial dir = %f %f\n", svec[0],svec[1]);
+//printf("~1 ### initial retv = %f\n",retv);
+ /* Initial vector setup */
+ for (i = 0; i < di; i++) {
+ gvec[i] = hvec[i] = -svec[i]; /* Inverse gradient */
+ svec[i] = s[i] * -svec[i] * svec_sca; /* Scale the search vector */
+ }
+//printf("~1 ### svec = %f %f\n", svec[0],svec[1]);
+
+ /* Itterate untill we converge on a solution, or give up. */
+ for (iter = 1; iter < maxit; iter++) {
+ double gamden, gamnum, gam;
+ double pretv; /* Previous function return value */
+
+ DBG(("conjrad: about to do linmin\n"))
+ pretv = retv;
+ retv = linmin(cp, svec, di, ftol, func, fdata);
+
+#ifdef ABSTOL
+ stopth = ftol; /* Absolute tollerance */
+#else
+ stopth = ftol * 0.5 * (fabs(pretv) + fabs(retv) + DBL_EPSILON); // Old code
+#endif
+ curdel = fabs(pretv - retv);
+//printf("~1 ### this retv = %f, pretv = %f, curdel = %f\n",retv,pretv,curdel);
+ if (startdel < 0.0) {
+ startdel = curdel;
+ } else {
+ int tt;
+ tt = (int)(100.0 * pow((log(curdel) - log(startdel))/(log(stopth) - log(startdel)), 4.0) + 0.5);
+ if (tt > pc && tt < 100) {
+ pc = tt;
+ if (prog != NULL) /* Report initial progress */
+ prog(pdata, pc);
+ }
+ }
+
+ /* If we have had at least one change of direction and */
+ /* reached a suitable tollerance, then finish */
+ if (iter > 1 && curdel <= stopth) {
+//printf("~1 ### stopping on itter %d because curdel %f <= stopth %f\n",iter, curdel,stopth);
+ break;
+ }
+//printf("~1 ### Not stopping on itter %d because curdel %f > stopth %f\n",iter, curdel,stopth);
+
+ DBG(("conjrad: recomputing direction\n"))
+//printf("~1 ### recomputing direction\n");
+ (*dfunc)(fdata, svec, cp); /* (Don't use retv as it wrecks stop test) */
+
+//printf("~1 ### pderiv = %f %f\n", svec[0],svec[1]);
+ /* Compute gamma */
+ for (gamnum = gamden = 0.0, i = 0; i < di; i++) {
+ gamnum += svec[i] * (gvec[i] + svec[i]);
+ gamden += gvec[i] * gvec[i];
+ }
+
+//printf("~1 ### gamnum = %f, gamden = %f\n", gamnum,gamden);
+ if (gamden == 0.0) { /* Gradient is exactly zero */
+ DBG(("conjrad: gradient is exactly zero\n"))
+ break;
+ }
+
+ gam = gamnum/gamden;
+ DBG(("conjrad: gamma = %f = %f/%f\n",gam,gamnum,gamden))
+//printf("~1 ### gvec[] = %f %f, gamma = %f, hvec = %f %f\n", gvec[0],gvec[1],gam,hvec[0],hvec[1]);
+
+ /* Adjust seach direction */
+ for (i = 0; i < di; i++) {
+ gvec[i] = -svec[i];
+ svec[i] = hvec[i] = gvec[i] + gam * hvec[i];
+ }
+
+ /* svec[] seems to be large after this. */
+ /* Rescale it to conform to maximum of s[] */
+ for (svec_sca = 0.0, i = 0; i < di; i++) {
+ if (fabs(svec[i]) > svec_sca)
+ svec_sca = fabs(svec[i]);
+ }
+ /* set scale so largest <= 1 */
+ if (svec_sca < 1e-12)
+ svec_sca = 1.0;
+ else
+ svec_sca = 1.0/svec_sca;
+ for (i = 0; i < di; i++)
+ svec[i] = svec[i] * s[i] * svec_sca;
+//printf("~1 ### svec = %f %f\n", svec[0],svec[1]);
+
+ }
+ /* Free up all the temporary vectors and matrix */
+ free_dvector(hvec,0,di-1);
+ free_dvector(gvec,0,di-1);
+ free_dvector(svec,0,di-1);
+
+ if (prog != NULL) /* Report final progress */
+ prog(pdata, 100);
+
+ if (rv != NULL)
+ *rv = retv;
+
+//printf("~1 ### done\n");
+
+ if (iter < maxit)
+ return 0;
+
+ return 1; /* Failed due to execessive itterations */
+}
+
+/*------------------------------*/
+#define POWELL_GOLD 1.618034
+#define POWELL_CGOLD 0.3819660
+#define POWELL_MAXIT 100
+
+/* Line bracketing and minimisation routine. */
+/* Return value at minimum. */
+static double linmin(
+double cp[], /* Start point, and returned value */
+double xi[], /* Search vector */
+int di, /* Dimensionality */
+#ifdef ABSTOL
+double ftol, /* Absolute tolerance to stop on */
+#else
+double ftol, /* Relative tolerance to stop on */
+#endif
+double (*func)(void *fdata, double tp[]), /* Error function to evaluate */
+void *fdata) /* Opaque data for func() */
+{
+ int i;
+ double ax, xx, bx; /* Search vector multipliers */
+ double af, xf, bf; /* Function values at those points */
+ double *xt, XT[10]; /* Trial point */
+
+ if (di <= 10)
+ xt = XT;
+ else
+ xt = dvector(0, di-1); /* Vector for trial point */
+
+ /* -------------------------- */
+ /* First bracket the solution */
+
+ DBG(("linmin: Bracketing solution\n"))
+
+ /* The line is measured as startpoint + offset * search vector. */
+ /* (Search isn't symetric, but it seems to depend on cp being */
+ /* best current solution ?) */
+ ax = 0.0;
+ for (i = 0; i < di; i++)
+ xt[i] = cp[i] + ax * xi[i];
+ af = (*func)(fdata, xt);
+
+ /* xx being vector offset 0.618 */
+ xx = 1.0/POWELL_GOLD;
+ for (i = 0; i < di; i++)
+ xt[i] = cp[i] + xx * xi[i];
+ xf = (*func)(fdata, xt);
+
+ DBG(("linmin: Initial points a:%f:%f -> b:%f:%f\n",ax,af,xx,xf))
+
+ /* Fix it so that we are decreasing from point a -> x */
+ if (xf > af) {
+ double tt;
+ tt = ax; ax = xx; xx = tt;
+ tt = af; af = xf; xf = tt;
+ }
+ DBG(("linmin: Ordered Initial points a:%f:%f -> b:%f:%f\n",ax,af,xx,xf))
+
+ bx = xx + POWELL_GOLD * (xx-ax); /* Guess b beyond a -> x */
+ for (i = 0; i < di; i++)
+ xt[i] = cp[i] + bx * xi[i];
+ bf = (*func)(fdata, xt);
+
+ DBG(("linmin: Initial bracket a:%f:%f x:%f:%f b:%f:%f\n",ax,af,xx,xf,bx,bf))
+
+#ifdef SLOPE_SANITY_CHECK
+ /* If we're not seeing a slope indicitive of progress */
+ /* of order ftol, give up straight away */
+ if (2000.0 * fabs(xf - bf) <= ftol * (fabs(xf) + fabs(bf))
+ && 2000.0 * fabs(af - xf) <= ftol * (fabs(af) + fabs(xf))) {
+ DBG(("linmin: giving up because slope is too shallow\n"))
+ if (xt != XT)
+ free_dvector(xt,0,di-1);
+
+ if (bf < xf) {
+ xf = bf;
+ xx = bx;
+ }
+
+ /* Compute solution vector */
+ for (i = 0; i < di; i++)
+ cp[i] += xx * xi[i];
+ return xf;
+ }
+#endif /* SLOPE_SANITY_CHECK */
+
+ /* While not bracketed */
+ while (xf > bf) {
+ double ulim, ux, uf;
+ double tt, r, q;
+
+// DBG(("linmin: Not bracketed a:%f:%f x:%f%f b:%f:%f\n",ax,af,xx,xf,bx,bf))
+ DBG(("linmin: Not bracketed because xf %f > bf %f\n",xf, bf))
+ DBG((" ax = %f, xx = %f, bx = %f\n",ax,xx,bx))
+
+ /* Compute ux by parabolic interpolation from a, x & b */
+ q = (xx - bx) * (xf - af);
+ r = (xx - ax) * (xf - bf);
+ tt = q - r;
+ if (tt >= 0.0 && tt < 1e-20) /* If +ve too small */
+ tt = 1e-20;
+ else if (tt <= 0.0 && tt > -1e-20) /* If -ve too small */
+ tt = -1e-20;
+ ux = xx - ((xx - bx) * q - (xx - ax) * r) / (2.0 * tt);
+ ulim = xx + 100.0 * (bx - xx); /* Extrapolation limit */
+
+//printf("~1 ux = %f, ulim = %f\n",ux,ulim);
+ if ((xx - ux) * (ux - bx) > 0.0) { /* u is between x and b */
+
+ for (i = 0; i < di; i++) /* Evaluate u */
+ xt[i] = cp[i] + ux * xi[i];
+ uf = (*func)(fdata, xt);
+
+//printf("~1 u is between x and b, uf = %f\n",uf);
+
+ if (uf < bf) { /* Minimum is between x and b */
+//printf("~1 min is between x and b\n");
+ ax = xx; af = xf;
+ xx = ux; xf = uf;
+ break;
+ } else if (uf > xf) { /* Minimum is between a and u */
+//printf("~1 min is between a and u\n");
+ bx = ux; bf = uf;
+ break;
+ }
+
+ /* Parabolic fit didn't work, look further out in direction of b */
+ ux = bx + POWELL_GOLD * (bx-xx);
+//printf("~1 parabolic fit didn't work,look further in direction of b (%f)\n",ux);
+
+ } else if ((bx - ux) * (ux - ulim) > 0.0) { /* u is between b and limit */
+ for (i = 0; i < di; i++) /* Evaluate u */
+ xt[i] = cp[i] + ux * xi[i];
+ uf = (*func)(fdata, xt);
+
+//printf("~1 u is between b and limit uf = %f\n",uf);
+ if (uf > bf) { /* Minimum is between x and u */
+//printf("~1 min is between x and uf\n");
+ ax = xx; af = xf;
+ xx = bx; xf = bf;
+ bx = ux; bf = uf;
+ break;
+ }
+ xx = bx; xf = bf; /* Continue looking */
+ bx = ux; bf = uf;
+ ux = bx + POWELL_GOLD * (bx - xx); /* Test beyond b */
+//printf("~1 continue looking beyond b (%f)\n",ux);
+
+ } else if ((ux - ulim) * (ulim - bx) >= 0.0) { /* u is beyond limit */
+ ux = ulim;
+//printf("~1 use limit\n");
+ } else { /* u is to left side of x ? */
+ ux = bx + POWELL_GOLD * (bx-xx);
+//printf("~1 look gold beyond b (%f)\n",ux);
+ }
+ /* Evaluate u, and move into place at b */
+ for (i = 0; i < di; i++)
+ xt[i] = cp[i] + ux * xi[i];
+ uf = (*func)(fdata, xt);
+//printf("~1 lookup ux %f value uf = %f\n",ux,uf);
+ ax = xx; af = xf;
+ xx = bx; xf = bf;
+ bx = ux; bf = uf;
+//printf("~1 move along to the right (a<-x, x<-b, b-<u)\n");
+ }
+ DBG(("linmin: Got bracket a:%f:%f x:%f:%f b:%f:%f\n",ax,af,xx,xf,bx,bf))
+ /* Got bracketed minimum between a -> x -> b */
+//printf("~1 got bracketed minimum at %f (%f), %f (%f), %f (%f)\n",ax,af,xx,xf,bx,bf);
+
+ /* --------------------------------------- */
+ /* Now use brent minimiser bewteen a and b */
+ {
+ /* a and b bracket solution */
+ /* x is best function value so far */
+ /* w is second best function value so far */
+ /* v is previous second best, or third best */
+ /* u is most recently tested point */
+ double wx, vx, ux; /* Search vector multipliers */
+ double wf, vf = 0.0, uf; /* Function values at those points */
+ int iter;
+ double de = 0.0; /* Distance moved on previous step */
+ double e = 0.0; /* Distance moved on 2nd previous step */
+
+ /* Make sure a and b are in ascending order */
+ if (ax > bx) {
+ double tt;
+ tt = ax; ax = bx; bx = tt;
+ tt = af; af = bf; bf = tt;
+ }
+
+ wx = vx = xx; /* Initial values of other center points */
+ wf = xf = xf;
+
+ for (iter = 1; iter <= POWELL_MAXIT; iter++) {
+ double mx = 0.5 * (ax + bx); /* m is center of bracket values */
+#ifdef ABSTOL
+ double tol1 = ftol; /* Absolute tollerance */
+#else
+ double tol1 = ftol * fabs(xx) + 1e-10;
+#endif
+ double tol2 = 2.0 * tol1;
+
+ DBG(("linmin: Got bracket a:%f:%f x:%f:%f b:%f:%f\n",ax,af,xx,xf,bx,bf))
+
+ /* See if we're done */
+//printf("~1 linmin check %f <= %f\n",fabs(xx - mx), tol2 - 0.5 * (bx - ax));
+ if (fabs(xx - mx) <= (tol2 - 0.5 * (bx - ax))) {
+ DBG(("linmin: We're done because %f <= %f\n",fabs(xx - mx), tol2 - 0.5 * (bx - ax)))
+ break;
+ }
+
+ if (fabs(e) > tol1) { /* Do a trial parabolic fit */
+ double te, p, q, r;
+ r = (xx-wx) * (xf-vf);
+ q = (xx-vx) * (xf-wf);
+ p = (xx-vx) * q - (xx-wx) * r;
+ q = 2.0 * (q - r);
+ if (q > 0.0)
+ p = -p;
+ else
+ q = -q;
+ te = e; /* Save previous e value */
+ e = de; /* Previous steps distance moved */
+
+ DBG(("linmin: Trial parabolic fit\n" ))
+
+ if (fabs(p) >= fabs(0.5 * q * te) || p <= q * (ax-xx) || p >= q * (bx-xx)) {
+ /* Give up on the parabolic fit, and use the golden section search */
+ e = ((xx >= mx) ? ax-xx : bx-xx); /* Override previous distance moved */
+ de = POWELL_CGOLD * e;
+ DBG(("linmin: Moving to golden section search\n" ))
+ } else { /* Use parabolic fit */
+ de = p/q; /* Change in xb */
+ ux = xx + de; /* Trial point according to parabolic fit */
+ if ((ux - ax) < tol2 || (bx - ux) < tol2) {
+ if ((mx - xx) > 0.0) /* Don't use parabolic, use tol1 */
+ de = tol1; /* tol1 is +ve */
+ else
+ de = -tol1;
+ }
+ DBG(("linmin: Using parabolic fit\n" ))
+ }
+ } else { /* Keep using the golden section search */
+ e = ((xx >= mx) ? ax-xx : bx-xx); /* Override previous distance moved */
+ de = POWELL_CGOLD * e;
+ DBG(("linmin: Continuing golden section search\n" ))
+ }
+
+ if (fabs(de) >= tol1) { /* If de moves as much as tol1 would */
+ ux = xx + de; /* use it */
+ DBG(("linmin: ux = %f = xx %f + de %f\n",ux,xx,de))
+ } else { /* else move by tol1 in direction de */
+ if (de > 0.0) {
+ ux = xx + tol1;
+ DBG(("linmin: ux = %f = xx %f + tol1 %f\n",ux,xx,tol1))
+ } else {
+ ux = xx - tol1;
+ DBG(("linmin: ux = %f = xx %f - tol1 %f\n",ux,xx,tol1))
+ }
+ }
+
+ /* Evaluate function */
+ for (i = 0; i < di; i++)
+ xt[i] = cp[i] + ux * xi[i];
+ uf = (*func)(fdata, xt);
+
+ if (uf <= xf) { /* Found new best solution */
+ if (ux >= xx) {
+ ax = xx; af = xf; /* New lower bracket */
+ } else {
+ bx = xx; bf = xf; /* New upper bracket */
+ }
+ vx = wx; vf = wf; /* New previous 2nd best solution */
+ wx = xx; wf = xf; /* New 2nd best solution from previous best */
+ xx = ux; xf = uf; /* New best solution from latest */
+ DBG(("linmin: found new best solution\n"))
+ } else { /* Found a worse solution */
+ if (ux < xx) {
+ ax = ux; af = uf; /* New lower bracket */
+ } else {
+ bx = ux; bf = uf; /* New upper bracket */
+ }
+ if (uf <= wf || wx == xx) { /* New 2nd best solution, or equal best */
+ vx = wx; vf = wf; /* New previous 2nd best solution */
+ wx = ux; wf = uf; /* New 2nd best from latest */
+ } else if (uf <= vf || vx == xx || vx == wx) { /* New 3rd best, or equal 1st & 2nd */
+ vx = ux; vf = uf; /* New previous 2nd best from latest */
+ }
+ DBG(("linmin: found new worse solution\n"))
+ }
+ }
+ /* !!! should do something if iter > POWELL_MAXIT !!!! */
+ /* Solution is at xx, xf */
+
+ /* Compute solution vector */
+ for (i = 0; i < di; i++)
+ cp[i] += xx * xi[i];
+ }
+
+ if (xt != XT)
+ free_dvector(xt,0,di-1);
+//printf("~~~ line minimizer returning %e\n",xf);
+ return xf;
+}
+
+#undef POWELL_GOLD
+#undef POWELL_CGOLD
+#undef POWELL_MAXIT
+
+/**************************************************/
diff --git a/numlib/powell.h b/numlib/powell.h
new file mode 100644
index 0000000..a1db8b6
--- /dev/null
+++ b/numlib/powell.h
@@ -0,0 +1,74 @@
+#ifndef POWELL_H
+#define POWELL_H
+
+/* Powell and Conjugate Gradient multivariate minimiser */
+
+/*
+ * Copyright 2000 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.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Standard interface for powell function */
+/* return 0 on sucess, 1 on failure due to excessive itterations */
+/* Result will be in cp */
+/* Arrays start at 0 */
+int powell(
+double *rv, /* If not NULL, return the residual error */
+int di, /* Dimentionality */
+double cp[], /* Initial starting point */
+double s[], /* Size of initial search area */
+double ftol, /* Tollerance of error change to stop on */
+int maxit, /* Maximum iterations allowed */
+double (*funk)(void *fdata, double tp[]), /* Error function to evaluate */
+void *fdata, /* Opaque data needed by func() */
+void (*prog)(void *pdata, int perc), /* Optional progress percentage callback */
+void *pdata /* Opaque data needed by prog() */
+);
+
+/* Conjugate Gradient optimiser */
+/* return 0 on sucess, 1 on failure due to excessive itterations */
+/* Result will be in cp */
+int conjgrad(
+double *rv, /* If not NULL, return the residual error */
+int di, /* Dimentionality */
+double cp[], /* Initial starting point */
+double s[], /* Size of initial search area */
+double ftol, /* Tollerance of error change to stop on */
+int maxit, /* Maximum iterations allowed */
+double (*func)(void *fdata, double tp[]), /* Error function to evaluate */
+double (*dfunc)(void *fdata, double dp[], double tp[]), /* Gradient function to evaluate */
+void *fdata, /* Opaque data needed by function */
+void (*prog)(void *pdata, int perc), /* Optional progress percentage callback */
+void *pdata /* Opaque data needed by prog() */
+);
+
+/* Example user function declarations */
+double powell_funk( /* Return function value */
+ void *fdata, /* Opaque data pointer */
+ double tp[]); /* Multivriate input value */
+
+/* Line in multi-dimensional space minimiser */
+double brentnd( /* vector multiplier return value */
+double ax, /* Minimum of multiplier range */
+double bx, /* Starting point multiplier of search */
+double cx, /* Maximum of multiplier range */
+double ftol, /* Tollerance to stop search */
+double *xmin, /* Return value of multiplier at minimum */
+int n, /* Dimensionality */
+double (*func)(void *fdata, double tp[]), /* Error function to evaluate */
+void *fdata, /* Opaque data */
+double pcom[], /* Base vector point */
+double xicom[]); /* Vector that will be multiplied and added to pcom[] */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* POWELL_H */
diff --git a/numlib/rand.c b/numlib/rand.c
new file mode 100644
index 0000000..436de52
--- /dev/null
+++ b/numlib/rand.c
@@ -0,0 +1,108 @@
+/* Integer and floating point random number generator routines */
+/*
+ * Copyright 2000 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.
+ */
+
+#include "numsup.h"
+#include "rand.h"
+
+/* 32 bit pseudo random sequencer based on XOR feedback */
+/* generates number between 1 and 4294967295 */
+#define PSRAND32(S) (((S) & 0x80000000) ? (((S) << 1) ^ 0xa398655d) : ((S) << 1))
+
+/* 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 */
+/* Use Knuth shuffle to improve PSRAND32 sequence */
+unsigned int
+rand32( /* Return 32 bit random number */
+unsigned int seed /* Optional seed. Non-zero re-initialized with that seed */
+) {
+#define TSIZE 2843 /* Prime */
+ static unsigned int last, ran = 0x12345678; /* Default seed */
+ static unsigned int pvs[TSIZE];
+ static int pvs_inited = 0;
+ int i;
+
+ if (seed != 0)
+ {
+ pvs_inited = 0;
+ ran = seed;;
+ }
+
+ /* Init random storage locations */
+ if (pvs_inited == 0)
+ {
+ for (i = 0; i < TSIZE; i++)
+ pvs[i] = ran = PSRAND32(ran);
+ last = ran;
+ pvs_inited = 1;
+ }
+ i = last % TSIZE; /* New location */
+ last = pvs[i]; /* Value generated */
+ pvs[i] = ran = PSRAND32(ran); /* New value */
+
+ return last-1;
+}
+
+/* return a random number between 0.0 and 1.0 */
+/* based on rand32 */
+double ranno(void) {
+ return rand32(0) / 4294967295.0;
+}
+
+/* Return a random double in the range min to max */
+double
+d_rand(double min, double max) {
+ double tt;
+ tt = ranno();
+ return min + (max - min) * tt;
+}
+
+/* Return a random integer in the range min to max inclusive */
+int
+i_rand(int min, int max) {
+ double tt;
+ tt = ranno();
+ return min + (int)floor(0.5 + ((double)(max - min)) * tt);
+}
+
+
+/* Return a random floating point number with a gausian/normal */
+/* distribution, centered about 0.0, with standard deviation 1.0 */
+/* This uses the Box-Muller transformation */
+double norm_rand(void) {
+ static int r2 = 0; /* Can use 2nd number generated */
+ static double nr2;
+
+ if (r2 == 0) {
+ double v1, v2, t1, t2, r1;
+ do {
+ v1 = d_rand(-1.0, 1.0);
+ v2 = d_rand(-1.0, 1.0);
+ t1 = v1 * v1 + v2 * v2;
+ } while (t1 == 0.0 || t1 >= 1.0);
+ t2 = sqrt(-2.0 * log(t1)/t1);
+ nr2 = v2 * t2; /* One for next time */
+ r2 = 1;
+ r1 = v1 * t2;
+ return r1;
+ } else {
+ r2 = 0;
+ return nr2;
+ }
+}
+
+
+
+
+
+
+
diff --git a/numlib/rand.h b/numlib/rand.h
new file mode 100644
index 0000000..46f79f2
--- /dev/null
+++ b/numlib/rand.h
@@ -0,0 +1,36 @@
+#ifndef RAND_H
+#define RAND_H
+
+/*
+ * Copyright 1998 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.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Return a random number between 0 and 4294967294 */
+unsigned int
+rand32( /* Return 32 bit random number */
+unsigned int seed); /* Optional seed. Non-zero re-initialized with that seed */
+
+/* Return a random integer in the range min to max inclusive */
+int i_rand(int min, int max);
+
+/* Return a random double in the range min to max inclusive */
+double d_rand(double min, double max);
+
+/* Return a random floating point number with a gausian/normal */
+/* distribution, centered about 0.0, with standard deviation 1.0 */
+/* and an average deviation of 0.564 */
+double norm_rand(void);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* RAND_H */
diff --git a/numlib/sobol.c b/numlib/sobol.c
new file mode 100644
index 0000000..40a2c38
--- /dev/null
+++ b/numlib/sobol.c
@@ -0,0 +1,211 @@
+
+/***************************************************/
+/* Sobol sub-random vector sequence generator */
+/***************************************************/
+
+/* Code is an expression of the algorithm decsribed in */
+/* the SSOBOL.F fortran source file, with additional */
+/* guidance from "Numerical Recipes in C", by W.H.Press, B.P.Flannery, */
+/* S.A.Teukolsky & W.T.Vetterling. */
+
+/*
+ * Copyright 2002 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.
+ */
+
+#include "numsup.h"
+#include "sobol.h"
+
+/*
+ * The array poly gives successive primitive
+ * polynomials coded in binary, e.g.
+ 45 = 100101
+ * has bits 5, 2, and 0 set (counting from the
+ * right) and therefore represents
+ X**5 + X**2 + X**0
+
+ * These polynomials are in the order used by
+ * sobol in ussr comput. maths. math. phys. 16 (1977),
+ * 236-242.
+ */
+
+static int sobol_poly[SOBOL_MAXDIM] = {
+ 1, 3, 7, 11, 13, 19, 25, 37, 59, 47,
+ 61, 55, 41, 67, 97, 91, 109, 103, 115, 131,
+ 193, 137, 145, 143, 241, 157, 185, 167, 229, 171,
+ 213, 191, 253, 203, 211, 239, 247, 285, 369, 299
+};
+
+/*
+ * The initialization of the array vinit is from
+ * Sobol and Levitan, the production of points uniformly
+ * distributed in a multidimensional cube (in Russian),
+ * preprint ipm akad. nauk sssr, no. 40, moscow 1976.
+ * For a polynomial of degree m, m initial
+ * values are needed : these are the values given here.
+ * subsequent values are calculated during initialisation.
+ */
+
+static int vinit[8][SOBOL_MAXDIM] = {
+ {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ },
+ {
+ 0, 0, 1, 3, 1, 3, 1, 3, 3, 1,
+ 3, 1, 3, 1, 3, 1, 1, 3, 1, 3,
+ 1, 3, 1, 3, 3, 1, 3, 1, 3, 1,
+ 3, 1, 1, 3, 1, 3, 1, 3, 1, 3
+ },
+ {
+ 0, 0, 0, 7, 5, 1, 3, 3, 7, 5,
+ 5, 7, 7, 1, 3, 3, 7, 5, 1, 1,
+ 5, 3, 3, 1, 7, 5, 1, 3, 3, 7,
+ 5, 1, 1, 5, 7, 7, 5, 1, 3, 3
+ },
+ {
+ 0, 0, 0, 0, 0, 1, 7, 9, 13, 11,
+ 1, 3, 7, 9, 5, 13, 13, 11, 3, 15,
+ 5, 3, 15, 7, 9, 13, 9, 1, 11, 7,
+ 5, 15, 1, 15, 11, 5, 3, 1, 7, 9
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 9, 3, 27,
+ 15, 29, 21, 23, 19, 11, 25, 7, 13, 17,
+ 1, 25, 29, 3, 31, 11, 5, 23, 27, 19,
+ 21, 5, 1, 17, 13, 7, 15, 9, 31, 9
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 37, 33, 7, 5, 11, 39, 63,
+ 27, 17, 15, 23, 29, 3, 21, 13, 31, 25,
+ 9, 49, 33, 19, 29, 11, 19, 27, 15, 25
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,
+ 33, 115, 41, 79, 17, 29, 119, 75, 73, 105,
+ 7, 59, 65, 21, 3, 113, 61, 89, 45, 107
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 7, 23, 39
+ }
+};
+
+/* Get the next sobol vector */
+/* return nz if we've run out */
+static int next_sobol(sobol *s, double * v)
+{
+ int i, p;
+ unsigned int c;
+
+ s->count++;
+
+ /* Find the position of the right-hand zero in count */
+ for (c = s->count, p = 0; (c & 1) == 0; p++, c >>= 1)
+ ;
+
+ if(p > SOBOL_MAXBIT)
+ return 1; /* Run out */
+
+ for (i = 0; i < s->dim; i++) {
+ s->lastq[i] ^= s->dir[p][i];
+ v[i] = s->lastq[i] * s->recipd;
+ }
+
+ return 0;
+}
+
+/* Free up the object */
+static void del_sobol(sobol *s) {
+ if (s != NULL)
+ free(s);
+}
+
+/* reset the count */
+static void reset_sobol(sobol *s) {
+ int i;
+
+ /* Set up first vector and values */
+ s->count = 0;
+ for (i = 0; i < s->dim; i++)
+ s->lastq[i] = 0;
+}
+
+/* Return NULL on error */
+sobol *new_sobol(int dim) {
+ sobol *s = NULL;
+ int i, j, p;
+
+ if (dim < 1 || dim > SOBOL_MAXDIM) {
+ return NULL;
+ }
+
+ if ((s = (sobol *)malloc(sizeof(sobol))) == NULL) {
+ return NULL;
+ }
+
+ s->dim = dim;
+ s->next = next_sobol;
+ s->reset = reset_sobol;
+ s->del = del_sobol;
+
+ /* Initialize the direction table */
+ for (i = 0; i < dim; i++) {
+
+ if (i == 0) {
+ for (j = 0; j < SOBOL_MAXBIT; j++)
+ s->dir[j][i] = 1;
+ } else {
+ int m; /* Degree */
+ int pm; /* Polinomial mask */
+
+ /* Find degree of polynomial from binary encoding */
+ for (m = 0, pm = sobol_poly[i] >> 1; pm != 0; m++, pm >>= 1)
+ ;
+
+ /* The leading elements of row i come from vinit[][] */
+ for (j = 0; j < m; j++) {
+ s->dir[j][i] = vinit[j][i];
+ }
+
+ /* Calculate remaining elements of row i as explained */
+ /* in bratley and fox, section 2 */
+ pm = sobol_poly[i];
+ for (j = m; j < SOBOL_MAXBIT; j++) {
+ int k;
+ int newv = s->dir[j-m][i];
+ for (k = 0; k < m; k++) {
+ if (pm & (1 << (m-k-1))) {
+ newv ^= s->dir[j-k-1][i] << (k+1);
+ }
+ }
+ s->dir[j][i] = newv;
+ }
+ }
+ }
+ /* Multiply columns of v by appropriate power of 2 */
+ for (p = 2, j = SOBOL_MAXBIT-2; j >= 0; j--, p <<= 1) {
+ for (i = 0; i < dim; i++)
+ s->dir[j][i] *= p;
+ }
+
+ /* recipd is 1/(common denominator of the elements in v) */
+ s->recipd = 1.0/(1 << SOBOL_MAXBIT);
+
+ /* Set up first vector and values */
+ s->count = 0;
+ for (i = 0; i < dim; i++)
+ s->lastq[i] = 0;
+
+ return s;
+}
+
diff --git a/numlib/sobol.h b/numlib/sobol.h
new file mode 100644
index 0000000..08ac5c0
--- /dev/null
+++ b/numlib/sobol.h
@@ -0,0 +1,52 @@
+#ifndef SOBOL_H
+#define SOBOL_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define SOBOL_MAXBIT 30
+#define SOBOL_MAXDIM 40
+
+/* Object definition */
+struct _sobol {
+ /* Private: */
+ int dim; /* dimension we're set for */
+ unsigned int count;
+ double recipd;
+ int lastq[SOBOL_MAXDIM];
+ int dir[SOBOL_MAXBIT][SOBOL_MAXDIM];
+
+ /* Public: */
+ /* Methods */
+
+ /* Get the next sobol vector, return nz if we've run out */
+ /* Values are between 0.0 and 1.0 */
+ int (*next)(struct _sobol *s, double *v);
+
+ /* Rest to the begining of the sequence */
+ void (*reset)(struct _sobol *s);
+
+ /* We're done with the object */
+ void (*del)(struct _sobol *s);
+
+}; typedef struct _sobol sobol;
+
+/* Return NULL on error */
+sobol *new_sobol(int dim);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* SOBOL_H */
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/soboltest.c b/numlib/soboltest.c
new file mode 100644
index 0000000..32c26ee
--- /dev/null
+++ b/numlib/soboltest.c
@@ -0,0 +1,127 @@
+
+/* Test the sobol sub-random vector sequencer */
+
+#include <stdlib.h>
+#include "numlib.h"
+
+/* Reference vectors */
+/* First 10 of dimension 40 */
+static double refv[10][40] = {
+ {
+ 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000,
+ 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000,
+ 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000,
+ 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000, 0.5000
+ }, {
+ 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.2500, 0.7500,
+ 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.7500, 0.2500, 0.7500, 0.2500,
+ 0.7500, 0.2500, 0.7500, 0.2500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500,
+ 0.2500, 0.7500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500
+ }, {
+ 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.7500, 0.2500,
+ 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.2500, 0.7500, 0.2500, 0.7500,
+ 0.2500, 0.7500, 0.2500, 0.7500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500,
+ 0.7500, 0.2500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500, 0.2500, 0.7500
+ }, {
+ 0.3750, 0.3750, 0.6250, 0.1250, 0.8750, 0.8750, 0.1250, 0.6250, 0.1250, 0.8750,
+ 0.3750, 0.6250, 0.1250, 0.3750, 0.6250, 0.1250, 0.6250, 0.3750, 0.3750, 0.8750,
+ 0.8750, 0.6250, 0.1250, 0.8750, 0.1250, 0.8750, 0.8750, 0.1250, 0.6250, 0.6250,
+ 0.3750, 0.3750, 0.3750, 0.3750, 0.6250, 0.1250, 0.8750, 0.8750, 0.1250, 0.6250
+ }, {
+ 0.8750, 0.8750, 0.1250, 0.6250, 0.3750, 0.3750, 0.6250, 0.1250, 0.6250, 0.3750,
+ 0.8750, 0.1250, 0.6250, 0.8750, 0.1250, 0.6250, 0.1250, 0.8750, 0.8750, 0.3750,
+ 0.3750, 0.1250, 0.6250, 0.3750, 0.6250, 0.3750, 0.3750, 0.6250, 0.1250, 0.1250,
+ 0.8750, 0.8750, 0.8750, 0.8750, 0.1250, 0.6250, 0.3750, 0.3750, 0.6250, 0.1250
+ }, {
+ 0.6250, 0.1250, 0.3750, 0.3750, 0.1250, 0.6250, 0.8750, 0.8750, 0.3750, 0.1250,
+ 0.1250, 0.3750, 0.3750, 0.6250, 0.8750, 0.8750, 0.3750, 0.1250, 0.6250, 0.6250,
+ 0.1250, 0.8750, 0.8750, 0.6250, 0.3750, 0.1250, 0.6250, 0.8750, 0.8750, 0.3750,
+ 0.1250, 0.6250, 0.6250, 0.1250, 0.3750, 0.3750, 0.1250, 0.6250, 0.8750, 0.8750
+ }, {
+ 0.1250, 0.6250, 0.8750, 0.8750, 0.6250, 0.1250, 0.3750, 0.3750, 0.8750, 0.6250,
+ 0.6250, 0.8750, 0.8750, 0.1250, 0.3750, 0.3750, 0.8750, 0.6250, 0.1250, 0.1250,
+ 0.6250, 0.3750, 0.3750, 0.1250, 0.8750, 0.6250, 0.1250, 0.3750, 0.3750, 0.8750,
+ 0.6250, 0.1250, 0.1250, 0.6250, 0.8750, 0.8750, 0.6250, 0.1250, 0.3750, 0.3750
+ }, {
+ 0.1875, 0.3125, 0.3125, 0.6875, 0.5625, 0.1875, 0.0625, 0.9375, 0.1875, 0.0625,
+ 0.6875, 0.8125, 0.5625, 0.6875, 0.1875, 0.6875, 0.1875, 0.0625, 0.0625, 0.8125,
+ 0.9375, 0.3125, 0.5625, 0.3125, 0.4375, 0.4375, 0.6875, 0.4375, 0.8125, 0.5625,
+ 0.9375, 0.8125, 0.1875, 0.3125, 0.3125, 0.6875, 0.5625, 0.1875, 0.0625, 0.9375
+ }, {
+ 0.6875, 0.8125, 0.8125, 0.1875, 0.0625, 0.6875, 0.5625, 0.4375, 0.6875, 0.5625,
+ 0.1875, 0.3125, 0.0625, 0.1875, 0.6875, 0.1875, 0.6875, 0.5625, 0.5625, 0.3125,
+ 0.4375, 0.8125, 0.0625, 0.8125, 0.9375, 0.9375, 0.1875, 0.9375, 0.3125, 0.0625,
+ 0.4375, 0.3125, 0.6875, 0.8125, 0.8125, 0.1875, 0.0625, 0.6875, 0.5625, 0.4375
+ }, {
+ 0.9375, 0.0625, 0.5625, 0.9375, 0.3125, 0.4375, 0.8125, 0.6875, 0.4375, 0.8125,
+ 0.9375, 0.0625, 0.8125, 0.4375, 0.4375, 0.4375, 0.9375, 0.3125, 0.8125, 0.5625,
+ 0.1875, 0.0625, 0.3125, 0.0625, 0.1875, 0.6875, 0.9375, 0.6875, 0.5625, 0.3125,
+ 0.6875, 0.0625, 0.9375, 0.0625, 0.5625, 0.9375, 0.3125, 0.4375, 0.8125, 0.6875
+ }
+};
+
+int main() {
+ sobol *s;
+ int i;
+ double vec[40];
+ int fail = 0;
+
+ printf("Starting sobol test\n");
+
+ if ((s = new_sobol(40)) == NULL) {
+ printf("new_sobol failed\n");
+ exit(1);
+ }
+
+ for (i = 0; i < 10; i++) {
+ int j;
+ if (s->next(s, vec)) {
+ printf("Next failed\n");
+ exit(1);
+ }
+ printf("Vector %d = ",i);
+ for (j = 0; j < 40; j++) {
+ printf("%f ",vec[j]);
+ }
+ printf("\n");
+
+ for (j = 0; j < 40; j++) {
+ if (refv[i][j] != vec[j]) {
+ printf("Warning: failed at vector %d, dim %d (%f != %f)\n",i,j,refv[i][j],vec[j]);
+ fail = 1;
+ }
+ }
+ }
+
+ s->del(s);
+ if (fail) {
+ printf("Sobol test FAILED\n");
+ return 1;
+ } else {
+ printf("Sobol test done OK\n");
+ return 0;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/svd.c b/numlib/svd.c
new file mode 100644
index 0000000..fdb8edd
--- /dev/null
+++ b/numlib/svd.c
@@ -0,0 +1,611 @@
+
+/*
+ * Singular Value Decomposition,
+ * from the Burton S. Garbow's EISPACK FORTRAN code,
+ * based on the algorithm of Golub and Reinsch in
+ * "Handbook of Automatic Computation",
+ * with some guidance from R. B Davie's newmat09.
+ *
+ * Copyright 2000 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.
+ */
+
+#include "numsup.h"
+#include "svd.h"
+
+#ifndef NEVER
+/* Compute the pythagorian distance sqrt(a^2 + b^2) */
+/* taking care of under or overflow. */
+double pythag(
+double a,
+double b) {
+ double aba, abb;
+
+ aba = fabs(a);
+ abb = fabs(b);
+
+ if (aba > abb) {
+ double boa;
+ boa = abb/aba;
+ return aba * sqrt(1.0 + boa * boa);
+ } else {
+ double aob;
+ if (abb == 0.0)
+ return 0.0;
+ aob = aba/abb;
+ return abb * sqrt(1.0 + aob * aob);
+ }
+}
+#else /* Quicker, but less robust */
+#define pythag(a, b) sqrt((a) * (a) + (b) * (b))
+#endif
+
+#define MAXITS 30
+
+/* Compute Singular Value Decomposition of A = U.W.Vt */
+/* Return status value: */
+/* 0 - no error */
+/* 1 - Too many itterations */
+int svdecomp(
+double **a, /* A[0..m-1][0..n-1], return U[][] */
+double *w, /* return W[0..n-1] */
+double **v, /* return V[0..n-1][0..n-1] (not transpose!) */
+int m, /* Number of equations */
+int n /* Number of unknowns */
+) {
+ double eps = DBL_EPSILON; /* 1.0 + eps = 1.0 */
+ double tol = DBL_MIN/eps; /* Minumum +ve value/eps */
+ double *rv1, RV1[10];
+ double anm;
+ int i, j, k;
+ int its;
+
+ if (n <= 10)
+ rv1 = RV1; /* Allocate fast off stack */
+ else
+ rv1 = dvector(0, n-1);
+
+ /* Housholder reduction of A to bidiagonal form */
+ anm = 0.0;
+ rv1[0] = 0.0; /* Will always == 0.0 */
+ for (i = 0; i < n; i++) { /* For each element in the diagonal of A */
+ int ip1 = i + 1;
+
+ /* Deal with lower column at i */
+ w[i] = 0.0;
+ if (i < m) { /* If it makes sense to go from row i .. m-1 */
+ double ss, ff = 0.0;
+
+ for (ss = 0.0, k = m-1; k >= i; k--) { /* Sum of squares of column */
+ ff = a[k][i];
+ ss += ff * ff;
+ } /* Note ff = A[i][i] */
+ if (ss >= tol) {
+ double gg, hh;
+ gg = sqrt(ss);
+ w[i] = gg = ff < 0.0 ? gg : -gg; /* gg has -sign of ff */
+ hh = ff * gg - ss;
+ a[i][i] = ff - gg;
+
+ /* For all lower columns to the right of this one */
+ for (j = ip1; j < n; j++) { /* Column j */
+ double tt;
+ for (ss = 0.0, k = i; k < m; k++)
+ ss += a[k][j] * a[k][i]; /* Sum of products of i and j columns */
+ tt = ss / hh;
+ for (k = i; k < m; k++)
+ a[k][j] += tt * a[k][i]; /* Add sumprod/hh to column j */
+ }
+ }
+ }
+
+ /* Deal with upper super row at i */
+ if (ip1 < n) { /* If it makes sense to go from column i+1 .. n-1 */
+ rv1[ip1] = 0.0;
+ if (i < m) { /* If it makes sense to process row i */
+ double ss, ff = 0.0;
+ for (ss = 0.0, k = n-1; k >= ip1; k--) { /* Sum of squares of row */
+ ff = a[i][k];
+ ss += ff * ff;
+ } /* Note ff = A[i][ip1] */
+ if (ss >= tol) {
+ double gg, hh;
+ gg = sqrt(ss);
+ rv1[ip1] = gg = ff < 0.0 ? gg : -gg; /* gg has -sign of ff */
+ hh = ff * gg - ss;
+ a[i][ip1] = (ff - gg);
+
+ /* For all upper rows below this one */
+ for (j = ip1; j < m; j++) {
+ double tt;
+ for (ss = 0.0, k = ip1; k < n; k++) /* Sum of products of i and j rows */
+ ss += a[j][k] * a[i][k];
+ tt = ss / hh;
+ for (k = ip1; k < n; k++)
+ a[j][k] += tt * a[i][k]; /* Add sumprod/hh to row j */
+ }
+ }
+ }
+ }
+ {
+ double tt;
+ tt = fabs(w[i]) + fabs(rv1[i]);
+ if (tt > anm)
+ anm = tt;
+ }
+ }
+
+ /* Accumulation of right hand transformations */
+ for (i = n-1; i >= 0; i--) {
+ int ip1 = i + 1;
+ if (ip1 < n) {
+ double gg;
+ gg = rv1[ip1];
+ if (gg != 0.0) {
+ gg = 1.0 / gg;
+ for (j = ip1; j < n; j++)
+ v[j][i] = (a[i][j] / a[i][ip1]) * gg; /* Double division to avoid underflow */
+ for (j = ip1; j < n; j++) {
+ double ss;
+ for (ss = 0.0, k = ip1; k < n; k++)
+ ss += a[i][k] * v[k][j];
+ for (k = ip1; k < n; k++)
+ v[k][j] += ss * v[k][i];
+ }
+ }
+ for (j = ip1; j < n; j++)
+ v[i][j] = v[j][i] = 0.0;
+ }
+ v[i][i] = 1.0;
+ }
+ /* Accumulation of left hand transformations */
+ for (i = n < m ? n-1 : m-1; i >= 0; i--) {
+ int ip1 = i + 1;
+ double gg = w[i];
+ if (ip1 < n)
+ for (j = ip1; j < n; j++)
+ a[i][j] = 0.0;
+ if (gg == 0.0) {
+ for (j = i; j < m; j++)
+ a[j][i] = 0.0;
+ } else {
+ gg = 1.0 / gg;
+ if (ip1 < n) {
+ for (j = ip1; j < n; j++) {
+ double ss, ff;
+ for (ss = 0.0, k = ip1; k < m; k++)
+ ss += a[k][i] * a[k][j];
+ ff = (ss / a[i][i]) * gg; /* Double division to avoid underflow */
+ for (k = i; k < m; k++)
+ a[k][j] += ff * a[k][i];
+ }
+ }
+ for (j = i; j < m; j++)
+ a[j][i] *= gg;
+ }
+ a[i][i] += 1.0;
+ }
+
+ eps *= anm;
+
+ /* Fully diagonalize bidiagonal result, by */
+ /* successive QR rotations. */
+ for (k = (n-1); k >= 0; k--) { /* For all the singular values */
+ for (its = 0;; its++) {
+ int flag;
+ int lm1 = 0;
+ int ll;
+ double zz;
+
+ /* Test for splitting */
+ for (flag = 1, ll = k; ll >= 0; ll--) {
+ lm1 = ll - 1;
+ if (fabs(rv1[ll]) <= eps) { /* Note always stops at 0 because rv1[0] = 0.0 */
+ flag = 0;
+ break;
+ }
+ if (fabs(w[lm1]) <= eps)
+ break;
+ }
+ if (flag != 0) {
+ double cc = 0.0;
+ double ss = 1.0;
+ for (i = ll; i <= k; i++) {
+ double ff, gg, hh;
+ gg = rv1[i];
+ rv1[i] = cc * gg;
+ ff = ss * gg;
+ if (fabs(ff) <= eps)
+ break; /* Found acceptable solution */
+ gg = w[i];
+ w[i] = hh = pythag(ff, gg);
+ hh = 1.0 / hh;
+ cc = gg * hh;
+ ss = -ff * hh;
+
+ /* Apply rotation */
+ for (j = 0; j < m; j++) {
+ double y1, z1;
+ y1 = a[j][lm1];
+ z1 = a[j][i];
+ a[j][lm1] = y1 * cc + z1 * ss;
+ a[j][i] = z1 * cc - y1 * ss;
+ }
+ }
+ }
+ zz = w[k];
+ if (k == ll) { /* Convergence */
+ if (zz < 0.0) {
+ w[k] = -zz; /* Make singular value non-negative */
+ for (j = 0; j < n; j++)
+ v[j][k] = (-v[j][k]);
+ }
+ break;
+ }
+ if (its == MAXITS) {
+/* fprintf(stderr,"No convergence in %d SVDCMP iterations",MAXITS); */
+ if (rv1 != RV1)
+ free_dvector(rv1, 0, n-1);
+ return 1;
+ }
+ {
+ double ff, gg, hh, cc, ss, xx, yy;
+ int km1;
+
+ km1 = k - 1;
+ xx = w[ll];
+ yy = w[km1];
+ gg = rv1[km1];
+ hh = rv1[k];
+ ff = ((yy - zz) * (yy + zz) + (gg - hh) * (gg + hh)) / (2.0 * hh * yy);
+ gg = pythag(ff, 1.0);
+ gg = ff < 0.0 ? -gg : gg;
+ ff = ((xx - zz) * (xx + zz) + hh * ((yy / (ff + gg)) - hh)) / xx;
+ cc = ss = 1.0;
+
+ for (j = ll; j <= km1; j++) {
+ double f2, g2, y2, h2, z2;
+ int jp1 = j + 1;
+ g2 = rv1[jp1];
+ y2 = w[jp1];
+ h2 = ss * g2;
+ g2 = cc * g2;
+ rv1[j] = z2 = pythag(ff, h2);
+ cc = ff / z2;
+ ss = h2 / z2;
+ f2 = xx * cc + g2 * ss;
+ g2 = g2 * cc - xx * ss;
+ h2 = y2 * ss;
+ y2 = y2 * cc;
+
+ /* Apply rotation */
+ for (i = 0; i < n; i++) {
+ double x1, z1;
+ x1 = v[i][j];
+ z1 = v[i][jp1];
+ v[i][j] = x1 * cc + z1 * ss;
+ v[i][jp1] = z1 * cc - x1 * ss;
+ }
+ w[j] = z2 = pythag(f2, h2);
+ if (z2 != 0.0) { /* Rotation can be arbitrary */
+ z2 = 1.0 / z2;
+ cc = f2 * z2;
+ ss = h2 * z2;
+ }
+ ff = (cc * g2) + (ss * y2);
+ xx = (cc * y2) - (ss * g2);
+
+ /* Apply rotation */
+ for (i = 0; i < m; i++) {
+ double y1, z1;
+ y1 = a[i][j];
+ z1 = a[i][jp1];
+ a[i][j] = y1 * cc + z1 * ss;
+ a[i][jp1] = z1 * cc - y1 * ss;
+ }
+ }
+ rv1[ll] = 0.0;
+ rv1[k] = ff;
+ w[k] = xx;
+ }
+ }
+ }
+ if (rv1 != RV1)
+ free_dvector(rv1, 0, n-1);
+
+ return 0;
+}
+
+/* --------------------------- */
+/* Threshold the singular values W[] */
+void svdthresh(
+double w[], /* Singular values */
+int n /* Number of unknowns */
+) {
+ int i;
+ double maxw;
+
+ /* Threshold the w[] values */
+ for (maxw = 0.0, i = 0; i < n; i++) {
+ if (w[i] > maxw)
+ maxw = w[i];
+ }
+ maxw *= 1.0e-12;
+ for (i = 0; i < n; i++) {
+ if (w[i] < maxw)
+ w[i] = 0.0;
+ }
+}
+
+/* --------------------------- */
+/* Threshold the singular values W[] to give */
+/* a specific degree of freedom. */
+void svdsetthresh(
+double w[], /* Singular values */
+int n, /* Number of unknowns */
+int dof /* Expected degree of freedom */
+) {
+ int i, j;
+
+ /* Set the dof smallest elements to zero */
+ /* (This algorithm is simple but not quick) */
+ for (j = 0; j < dof;) {
+ int k;
+ double minv = 1e38;
+ for (k = j = i = 0; i < n; i++) {
+ if (w[i] == 0.0) {
+ j++;
+ continue;
+ }
+ if (w[i] < minv) {
+ minv = w[i];
+ k = i;
+ }
+ }
+ if (j < dof) /* Zero next smallest */
+ w[k] = 0.0;
+ }
+}
+
+/* --------------------------- */
+/* Use output of svdcmp() to solve overspecified and/or */
+/* singular equation A.x = b */
+int svdbacksub(
+double **u, /* U[0..m-1][0..n-1] U, W, V SVD decomposition of A[][] */
+double *w, /* W[0..n-1] */
+double **v, /* V[0..n-1][0..n-1] (not transpose!) */
+double b[], /* B[0..m-1] Right hand side of equation */
+double x[], /* X[0..n-1] Return solution. (May be the same as b[]) */
+int m, /* Number of equations */
+int n /* Number of unknowns */
+) {
+ int i, j;
+ double *tmp, TMP[10]; /* Intermediate value of B . U-1 . W-1 */
+
+ if (n <= 10)
+ tmp = TMP;
+ else
+ tmp = dvector(0, n-1);
+
+ /* A . X = B == U . W . Vt . X = B */
+ /* and U, W, and Vt are trivialy invertable */
+
+ /* Compute B . U-1 . W-1 */
+ for (j = 0; j < n; j++) {
+ if (w[j]) {
+ double s;
+ for (s = 0.0, i = 0; i < m; i++)
+ s += b[i] * u[i][j];
+ s /= w[j];
+ tmp[j] = s;
+ } else {
+ tmp[j] = 0.0;
+ }
+ }
+ /* Compute T. V-1 */
+ for (j = 0; j < n; j++) {
+ double s;
+ for (s = 0.0, i = 0; i < n; i++)
+ s += v[j][i] * tmp[i];
+ x[j] = s;
+ }
+ if (tmp != TMP)
+ free_dvector(tmp, 0, n-1);
+ return 0;
+}
+
+
+/* --------------------------- */
+/* Solve the equation A.x = b using SVD */
+/* (The w[] values are thresholded for best accuracy) */
+/* Return non-zero if no solution found */
+int svdsolve(
+double **a, /* A[0..m-1][0..n-1] input A[][], will return U[][] */
+double b[], /* B[0..m-1] Right hand side of equation, return solution */
+int m, /* Number of equations */
+int n /* Number of unknowns */
+) {
+ int i;
+ double *w, W[8];
+ double **v, *VP[8], V[8][8];
+ double maxw;
+
+ if (n <= 8) {
+ w = W;
+ VP[0] = V[0]; VP[1] = V[1]; VP[2] = V[2]; VP[3] = V[3];
+ VP[4] = V[4]; VP[5] = V[5]; VP[6] = V[6]; VP[7] = V[7];
+ v = VP;
+ } else {
+ w = dvector(0, n-1);
+ v = dmatrix(0, n-1, 0, n-1);
+ }
+
+ /* Singular value decompose */
+ if (svdecomp(a, w, v, m, n)) {
+ if (w != W) {
+ free_dvector(w, 0, n-1);
+ free_dmatrix(v, 0, n-1, 0, n-1);
+ }
+ return 1;
+ }
+
+ /* Threshold the w[] values */
+ for (maxw = 0.0, i = 0; i < n; i++) {
+ if (w[i] > maxw)
+ maxw = w[i];
+ }
+ maxw *= 1.0e-12;
+ for (i = 0; i < n; i++) {
+ if (w[i] < maxw)
+ w[i] = 0.0;
+ }
+
+ /* Back substitute to solve the equation */
+ svdbacksub(a, w, v, b, b, m, n);
+
+ if (w != W) {
+ free_dvector(w, 0, n-1);
+ free_dmatrix(v, 0, n-1, 0, n-1);
+ }
+ return 0;
+}
+
+
+/* --------------------------- */
+/* Solve the equation A.x = b using SVD */
+/* The top s out of n singular values will be used */
+/* Return non-zero if no solution found */
+int svdsolve_s(
+double **a, /* A[0..m-1][0..n-1] input A[][], will return U[][] */
+double b[], /* B[0..m-1] Right hand side of equation, return solution */
+int m, /* Number of equations */
+int n, /* Number of unknowns */
+int s /* Number of singular values */
+) {
+ int i, j;
+ double *w, W[8];
+ int *sw, SW[8];
+ double **v, *VP[8], V[8][8];
+ double maxw;
+
+ if (n <= 8) {
+ w = W;
+ sw = SW;
+ VP[0] = V[0]; VP[1] = V[1]; VP[2] = V[2]; VP[3] = V[3];
+ VP[4] = V[4]; VP[5] = V[5]; VP[6] = V[6]; VP[7] = V[7];
+ v = VP;
+ } else {
+ w = dvector(0, n-1);
+ sw = ivector(0, n-1);
+ v = dmatrix(0, n-1, 0, n-1);
+ }
+
+ /* Singular value decompose */
+ if (svdecomp(a, w, v, m, n)) {
+ if (w != W) {
+ free_dvector(w, 0, n-1);
+ free_dmatrix(v, 0, n-1, 0, n-1);
+ }
+ return 1;
+ }
+
+ /* Create sorted index of w[] */
+ for (maxw = 0.0, i = 0; i < n; i++) {
+ sw[i] = i;
+ if (w[i] > maxw)
+ maxw = w[i];
+ }
+ maxw *= 1.0e-12;
+
+ /* Really dumb exchange sort.. */
+ for (i = 0; i < (n-1); i++) {
+ for (j = i+1; j < n; j++) {
+ if (w[sw[i]] > w[sw[j]]) {
+ int tt = sw[i];
+ sw[i] = sw[j];
+ sw[j] = tt;
+ }
+ }
+ }
+
+ /* Set the (n - s) smallest values to zero */
+ s = n - s;
+ if (s < 0)
+ s = 0;
+ if (s > n)
+ s = n;
+ for (i = 0; i < s; i++)
+ w[sw[i]] = 0.0;
+
+ /* And threshold them too */
+ for (maxw = 0.0, i = 0; i < n; i++) {
+ if (w[i] < maxw)
+ w[i] = 0.0;
+ }
+
+ /* Back substitute to solve the equation */
+ svdbacksub(a, w, v, b, b, m, n);
+
+ if (w != W) {
+ free_dvector(w, 0, n-1);
+ free_ivector(sw, 0, n-1);
+ free_dmatrix(v, 0, n-1, 0, n-1);
+ }
+ return 0;
+}
+
+
+/* --------------------------- */
+/* Solve the equation A.x = b using Direct calculation, LU or SVD as appropriate */
+/* Return non-zero if no solution found */
+
+#include "ludecomp.h"
+
+int gen_solve_se(
+double **a, /* A[0..m-1][0..n-1] input A[][], will return U[][] */
+double b[], /* B[0..m-1] Right hand side of equation, return solution */
+int m, /* Number of equations */
+int n /* Number of unknowns */
+) {
+ if (n == m) {
+ if (n == 1) { /* So simple, solve it directly */
+ double tt = a[0][0];
+ if (fabs(tt) <= DBL_MIN)
+ return 1;
+ b[0] = b[0]/tt;
+ return 0;
+ } else {
+ return solve_se(a, b, n);
+ }
+ } else {
+ return svdsolve(a, b, m, n);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/svd.h b/numlib/svd.h
new file mode 100644
index 0000000..59b080d
--- /dev/null
+++ b/numlib/svd.h
@@ -0,0 +1,90 @@
+#ifndef SVD_H
+#define SVD_H
+
+/*
+ * Copyright 2000 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.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Compute Singular Value Decomposition of A = U.W.Vt */
+/* Return status value: */
+/* 0 - no error */
+/* 1 - m < n error */
+int svdecomp(
+double **a, /* A[0..m-1][0..n-1], return U[][] */
+double *w, /* return W[0..n-1] */
+double **v, /* return V[0..n-1][0..n-1] (not transpose!) */
+int m, /* Number of equations */
+int n /* Number of unknowns */
+);
+
+/* Threshold the singular values W[] */
+void svdthresh(
+double w[], /* Singular values */
+int n /* Number of unknowns */
+);
+
+/* Threshold the singular values W[] to give a specific dof */
+void svdsetthresh(
+double w[], /* Singular values */
+int n, /* Number of unknowns */
+int dof /* Expected degree of freedom */
+);
+
+/* Use output of svdcmp() to solve overspecified and/or */
+/* singular equation A.x = b */
+int svdbacksub(
+double **u, /* U[0..m-1][0..n-1] U, W, V SVD decomposition of A[][] */
+double *w, /* W[0..n-1] */
+double **v, /* V[0..n-1][0..n-1] (not transpose!) */
+double b[], /* B[0..m-1] Right hand side of equation */
+double x[], /* X[0..n-1] Return solution. (May be the same as b[]) */
+int m, /* Number of equations */
+int n /* Number of unknowns */
+);
+
+/* Solve the equation A.x = b using SVD */
+/* (The w[] values are thresholded for best accuracy) */
+/* Return non-zero if no solution found */
+/* !!! Note that A[][] will be changed !!! */
+int svdsolve(
+double **a, /* A[0..m-1][0..n-1] input A[][], will return U[][] */
+double b[], /* B[0..m-1] Right hand side of equation, return solution */
+int m, /* Number of equations */
+int n /* Number of unknowns */
+);
+
+/* Solve the equation A.x = b using SVD */
+/* The top s out of n singular values will be used */
+/* Return non-zero if no solution found */
+/* !!! Note that A[][] will be changed !!! */
+int svdsolve_s(
+double **a, /* A[0..m-1][0..n-1] input A[][], will return U[][] */
+double b[], /* B[0..m-1] Right hand side of equation, return solution */
+int m, /* Number of equations */
+int n, /* Number of unknowns */
+int s /* Number of unknowns */
+);
+
+/* Solve the equation A.x = b using Direct calculation, LU or SVD as appropriate */
+/* Return non-zero if no solution found */
+/* !!! Note that A[][] will be changed !!! */
+int gen_solve_se(
+double **a, /* A[0..m-1][0..n-1] input A[][], will return U[][] */
+double b[], /* B[0..m-1] Right hand side of equation, return solution */
+int m, /* Number of equations */
+int n /* Number of unknowns */
+);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* SVD_H */
diff --git a/numlib/svdtest.c b/numlib/svdtest.c
new file mode 100644
index 0000000..100120d
--- /dev/null
+++ b/numlib/svdtest.c
@@ -0,0 +1,214 @@
+
+/* SVD test */
+/* Verify that the SVD solver does what it is supposed to. */
+/*
+ * Copyright 2000 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.
+ */
+
+/* We assume two device dependent variables, and one objective function value */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+
+#include "numlib.h"
+
+int main(void) {
+ int its;
+ int i,j,x;
+ double **a; /* A[0..M-1][0..N-1] input */
+ double **u; /* U[0..M-1][0..N-1] output */
+ double *w; /* W[0..N-1] output */
+ double **v; /* V[0..N-1][0..N-1] output */
+ double **a2; /* A[0..M-1][0..N-1] check on a */
+ double **t; /* A[0..M-1][0..N-1] temp */
+ int m,n;
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ printf("Test SVD\n");
+
+ for (its = 400; its > 0; its--) {
+ int bad;
+ int bad0;
+
+ m = i_rand(1,30); /* Number of equations */
+ n = i_rand(1,30); /* Number of unknowns */
+
+ a = dmatrix(0,m-1, 0,n-1);
+ t = dmatrix(0,m-1, 0,n-1);
+ a2 = dmatrix(0,m-1, 0,n-1);
+ u = dmatrix(0,m-1, 0,n-1);
+ w = dvector(0,n-1);
+ v = dmatrix(0,n-1, 0,n-1);
+
+ printf("Testing %d by %d\n",m,n);
+
+ /* Create A matrix */
+ for (j = 0; j < m; j++)
+ for (i = 0; i < n; i++)
+ a[j][i] = d_rand(-10.0, 10.0);
+
+ /* Setup u */
+ for (j = 0; j < m; j++)
+ for (i = 0; i < n; i++)
+ u[j][i] = a[j][i];
+
+ /* decompose A into U, W and V */
+ svdecomp(u, w, v, m, n);
+
+ /* Check results by computing a2 = U.W.Vt */
+ for (j = 0; j < m; j++) { /* U.W */
+ for (i = 0; i < n; i++) {
+ t[j][i] = 0.0;
+ for (x = 0; x < n; x++) {
+ if (x == i)
+ t[j][i] += u[j][x] * w[x];
+ }
+ }
+ }
+ for (j = 0; j < m; j++) { /* .Vt */
+ for (i = 0; i < n; i++) {
+ a2[j][i] = 0.0;
+ for (x = 0; x < n; x++) {
+ a2[j][i] += t[j][x] * v[i][x];
+ }
+ }
+ }
+
+ /* Now check */
+ bad = 0;
+ for (j = 0; j < m; j++)
+ for (i = 0; i < n; i++) {
+ double tt;
+ tt = a2[j][i] - a[j][i];
+ tt = fabs(tt);
+ if (tt > 0.0000001) {
+ bad = 1;
+ }
+ }
+ if (bad)
+ printf("A == U.W.Vt Check failed!\n");
+
+
+ /* Check that U and Ut are inverses */
+ bad = bad0 = 0;
+ for (j = 0; j < n; j++) {
+ for (i = 0; i < n; i++) {
+ double t2, tt = 0.0;
+ for (x = 0; x < m; x++) {
+ tt += u[x][j] * u[x][i];
+ }
+ t2 = tt;
+ if (i == j)
+ tt -= 1.0;
+ tt = fabs(tt);
+ if (tt > 0.0000001) {
+ if (i == j && fabs(t2) < 0.0000001)
+ bad0++; /* Unexpected zero diagonal */
+ else {
+ bad = 1;
+ printf("Possible U error at %d %d = %f \n",j,i,tt);
+ }
+ }
+ }
+ }
+ /* Expect n-m diagnals to be 0 instead of 1 if m < n */
+ if (bad || (m >= n && bad0) || (m < n && bad0 != n-m))
+ printf("U,Ut == 1 Check failed!\n");
+
+ /* Check that V and Vt are inverses */
+ bad = 0;
+ for (j = 0; j < n; j++) {
+ for (i = 0; i < n; i++) {
+ double tt = 0.0;
+ for (x = 0; x < n; x++) {
+ tt += v[j][x] * v[i][x];
+ }
+ if (i == j)
+ tt -= 1.0;
+ tt = fabs(tt);
+ if (tt > 0.0000001) {
+ bad = 1;
+ printf("V Error at %d %d = %f \n",j,i,tt);
+ }
+ }
+ if (bad)
+ printf("V,Vt == 1 Check failed!\n");
+ }
+
+#ifdef NEVER
+ printf("A = %f %f %f\n %f %f %f\n %f %f %f\n\n",
+ a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[1][2], a[2][0], a[2][1], a[2][2]);
+
+ printf("u = %f %f %f\n %f %f %f\n %f %f %f\n\n",
+ u[0][0], u[0][1], u[0][2], u[1][0], u[1][1], u[1][2], u[2][0], u[2][1], u[2][2]);
+
+ printf("w = %f %f %f\n\n", w[0],w[1],w[2]);
+
+ printf("V = %f %f %f\n %f %f %f\n %f %f %f\n\n",
+ v[0][0], v[0][1], v[0][2], v[1][0], v[1][1], v[1][2], v[2][0], v[2][1], v[2][2]);;
+
+ printf("A2 = %f %f %f\n %f %f %f\n %f %f %f\n\n",
+ a2[0][0], a2[0][1], a2[0][2], a2[1][0], a2[1][1],
+ a2[1][2], a2[2][0], a2[2][1], a2[2][2]);
+#endif
+
+ free_dmatrix(a, 0,m-1, 0,n-1);
+ free_dmatrix(t, 0,m-1, 0,n-1);
+ free_dmatrix(a2, 0,m-1, 0,n-1);
+ free_dmatrix(u, 0,m-1, 0,n-1);
+ free_dvector(w, 0,n-1);
+ free_dmatrix(v, 0,n-1, 0,n-1);
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/tdhsx.c b/numlib/tdhsx.c
new file mode 100644
index 0000000..d1738c4
--- /dev/null
+++ b/numlib/tdhsx.c
@@ -0,0 +1,117 @@
+
+/*
+ * Code to test the downhill simplex minimiser
+ *
+ * Copyright 1999 - 2005 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.
+ */
+
+#include <stdio.h>
+#include "numlib.h"
+
+/* Final approximate solution: */
+
+double expect[9] = {
+ -0.5706545E+00,
+ -0.6816283E+00,
+ -0.7017325E+00,
+ -0.7042129E+00,
+ -0.7013690E+00,
+ -0.6918656E+00,
+ -0.6657920E+00,
+ -0.5960342E+00,
+ -0.4164121E+00 };
+
+double fcn( /* Return function value */
+ void *fdata, /* Opaque data pointer */
+ double tp[]); /* Multivriate input value */
+
+#define N 9
+
+int main(void)
+{
+ double cp[N]; /* Function input values */
+ double s[N]; /* Search area */
+ double err;
+ int j;
+ int nprint = 0; /* Itteration debugging print = off */
+ int rv;
+
+ error_program = "tdhsx"; /* Set global error reporting string */
+
+ /* The following starting values provide a rough solution. */
+ for (j = 0; j < N; j++) {
+ cp[j] = -1.f;
+ s[j] = 0.9;
+ }
+
+ nprint = 0;
+
+ /* Set tol to the square root of the machine precision. */
+ /* Unless high precision solutions are required, */
+ /* this is the recommended setting. */
+
+ rv = dhsx(
+ &err, /* return residual */
+ N, /* Dimentionality */
+ cp, /* Initial starting point */
+ s, /* Size of initial search area */
+ 0.0000001, /* Tollerance of error change to stop on */
+ 1e6, /* Absolute error to stop on */
+// 10.0, /* Tollerance of error change to stop on */
+// 0.0001, /* Absolute error to stop on */
+ 1000, /* Maximum iterations allowed */
+ fcn, /* Error function to evaluate */
+ NULL); /* Opaque data needed by function */
+
+
+ fprintf(stdout,"Return code %d, residual err = %f:\n",rv, err);
+ for (j = 0; j < N; j++) {
+ fprintf(stdout,"cp[%d] = %e, expect %e\n",j,cp[j],expect[j]);
+ }
+
+ return 0;
+} /* main() */
+
+/* Function being minimized */
+double fcn( /* Return function value */
+void *fdata, /* Opaque data pointer */
+double tp[] /* Multivriate input value */
+) {
+ double err, tt;
+ double temp, temp1, temp2;
+ int k;
+
+ /* Function Body */
+ err = 0.0;
+ for (k = 0; k < N; ++k) {
+ temp = (3.0 - 2.0 * tp[k]) * tp[k];
+ temp1 = 0.0;
+ if (k != 0) {
+ temp1 = tp[k-1];
+ }
+ temp2 = 0.0;
+ if (k != ((N)-1))
+ temp2 = tp[k+1];
+ tt = temp - temp1 - 2.0 * temp2 + 1.0;
+ err += tt * tt;
+ }
+ err = sqrt(err);
+// printf("Returning %16.14f\n",err);
+ return err;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/tpowell.c b/numlib/tpowell.c
new file mode 100644
index 0000000..f7b0aad
--- /dev/null
+++ b/numlib/tpowell.c
@@ -0,0 +1,123 @@
+/* Code to test the powell minimiser */
+/*
+ * Copyright 1999 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.
+ */
+
+#include <stdio.h>
+#include "numlib.h"
+
+/* Final approximate solution: */
+
+double expect[9] = {
+ -0.5706545E+00,
+ -0.6816283E+00,
+ -0.7017325E+00,
+ -0.7042129E+00,
+ -0.7013690E+00,
+ -0.6918656E+00,
+ -0.6657920E+00,
+ -0.5960342E+00,
+ -0.4164121E+00 };
+
+double fcn( /* Return function value */
+ void *fdata, /* Opaque data pointer */
+ double tp[]); /* Multivriate input value */
+
+#define N 9
+
+static void progress(void *pdata, int perc) {
+ printf("%c% 3d%%",cr_char,perc);
+ if (perc == 100)
+ printf("\n");
+ fflush(stdout);
+}
+
+int main(void)
+{
+ double cp[N]; /* Function input values */
+ double s[N]; /* Search area */
+ double err;
+ int j;
+ int nprint = 0; /* Itteration debugging print = off */
+ int rc;
+
+ error_program = "tpowell"; /* Set global error reporting string */
+ check_if_not_interactive();
+
+ /* The following starting values provide a rough solution. */
+ for (j = 0; j < N; j++) {
+ cp[j] = -1.f;
+ s[j] = 0.9;
+ }
+
+ nprint = 0;
+
+ /* Set tol to the square root of the machine precision. */
+ /* Unless high precision solutions are required, */
+ /* this is the recommended setting. */
+
+ rc = powell(
+ &err,
+ N, /* Dimentionality */
+ cp, /* Initial starting point */
+ s, /* Size of initial search area */
+ 0.00000001, /* Tollerance of error change to stop on */
+ 1000, /* Maximum iterations allowed */
+ fcn, /* Error function to evaluate */
+ NULL, /* Opaque data needed by function */
+ progress, /* Progress callback */
+ NULL /* Context for callback */
+ );
+
+
+ fprintf(stdout,"Status = %d, final approximate solution err = %f:\n",rc,err);
+ for (j = 0; j < N; j++) {
+ fprintf(stdout,"cp[%d] = %e, expect %e\n",j,cp[j],expect[j]);
+ }
+
+ return 0;
+} /* main() */
+
+/* Function being minimized */
+double fcn( /* Return function value */
+void *fdata, /* Opaque data pointer */
+double tp[] /* Multivriate input value */
+) {
+ double err, tt;
+ double temp, temp1, temp2;
+ int k;
+
+ /* Function Body */
+ err = 0.0;
+ for (k = 0; k < N; ++k) {
+ temp = (3.0 - 2.0 * tp[k]) * tp[k];
+ temp1 = 0.0;
+ if (k != 0) {
+ temp1 = tp[k-1];
+ }
+ temp2 = 0.0;
+ if (k != ((N)-1))
+ temp2 = tp[k+1];
+ tt = temp - temp1 - 2.0 * temp2 + 1.0;
+ err += tt * tt;
+ }
+ err = sqrt(err);
+//printf("Returning %16.14f\n",err);
+ return err;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/zbrent.c b/numlib/zbrent.c
new file mode 100644
index 0000000..a811818
--- /dev/null
+++ b/numlib/zbrent.c
@@ -0,0 +1,182 @@
+
+/* 1 dimentional root finding code */
+/* inspired by the Van Wijngaarden-Dekker-Brent */
+/* method algorithm presented in */
+/* "Numerical Recipes in C", by W.H.Press, */
+/* B.P.Flannery, S.A.Teukolsky & W.T.Vetterling. */
+
+/*
+ * Copyright 2000 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.
+ */
+
+#include "numsup.h"
+#include "zbrent.h"
+
+#undef DEBUG
+
+#define ZBRACK_MAXTRY 40 /* Maximum tries to bracket */
+#define ZBRACK_GOLD 1.618034 /* Golden ratio */
+
+/* Bracket search function */
+/* return 0 on sucess */
+/* -1 on no range */
+/* -2 on too many itterations */
+int zbrac(
+double *x1p, /* Input and output bracket values */
+double *x2p, /* Min and Max */
+double (*func)(void *fdata, double tp), /* function to evaluate */
+void *fdata /* Opaque data pointer */
+) {
+ int i;
+ double x1, x2; /* Bracket under consideration */
+ double f1, f2; /* Function values at points x1 and x2 */
+
+ x1 = *x1p;
+ x2 = *x2p;
+ if (x1 == x2) /* Nowhere to go */
+ return -1;
+
+ f1 = (*func)(fdata, x1); /* Initial function values */
+ f2 = (*func)(fdata, x2);
+
+ for (i = 0; i < ZBRACK_MAXTRY; i++) {
+ if ((f1 * f2) < 0.0) {
+ *x1p = x1;
+ *x2p = x2;
+ return 0; /* If signs are opposite, we're done */
+ }
+ if (fabs(f2) > fabs(f1)) { /* Move smaller in direction away from larger */
+ x1 += ZBRACK_GOLD * (x1 - x2);
+ f1 = (*func)(fdata, x1);
+ } else {
+ x2 += ZBRACK_GOLD * (x2 - x1);
+ f2 = (*func)(fdata, x2);
+ }
+ }
+ return -2;
+}
+
+#undef ZBRACK_GOLD
+#undef ZBRACK_MAXTRY
+
+
+#define ZBRENT_MAXIT 100
+
+/* Root finder */
+/* return 0 on sucess */
+/* -1 on root not bracketed */
+/* -2 on too many itterations */
+int zbrent(
+double *rv, /* Return value */
+double ax, /* Bracket to search */
+double bx, /* (Min, Max) */
+double tol, /* Desired tollerance */
+double (*func)(void *fdata, double tp), /* function to evaluate */
+void *fdata /* Opaque data pointer */
+) {
+ int i;
+ double cx; /* Trial points, bx = best current */
+ double af ,bf, cf; /* Function values at those points */
+
+ af = (*func)(fdata, ax);
+ bf = (*func)(fdata, bx);
+
+ /* Sanity check bracketing */
+ if (af * bf > 0.0)
+ return -1; /* No good */
+
+ cx = bx; /* Force bisection for first itter */
+ cf = bf;
+ for (i = 0; i < ZBRENT_MAXIT; i++) {
+ double xdel; /* Bisection delta to bx */
+ double del = 1e80; /* Delta to be applied to bx */
+ double pdel = 1e80; /* Last del from interpolation step */
+ double tol1; /* Minimum reasonable change in bx */
+
+ /* Make bx and cx straddle root */
+ if (bf * cf > 0.0) { /* bx and cx don't straddle root */
+ cx = ax; /* ax must, so make cx = ax */
+ cf = af;
+ pdel = del = bx - ax;
+ }
+
+ /* Make bx be point closest to solution */
+ if (fabs(cf) < fabs(bf)) {
+ ax = bx; /* swap bx & cx, and make ax == new cx */
+ af = bf;
+ bx = cx;
+ bf = cf;
+ cx = ax;
+ cf = af;
+ }
+ tol1 = (0.5 * tol) + (2.0 * DBL_EPSILON * fabs(bx)); /* Minimum tollerable bx move */
+ xdel = 0.5 * (cx - bx); /* Delta to bx for bisection move */
+
+ if (bf == 0.0 || fabs(xdel) <= tol1) { /* If exact soln, or last was min move */
+ *rv = bx;
+ return 0;
+ }
+ if (fabs(pdel) >= tol1 && fabs(af) > fabs(bf)) { /* Try inv. quadratic interpolation */
+ double P, Q;
+
+ if (ax == cx) { /* Only have 2 points, use extrapolation */
+ double R;
+ R = bf / cf;
+ P = (cx - bx) * R;
+ Q = R - 1.0;
+ } else { /* Brent's interpolation of 3 points */
+ double R, S, T;
+ R = bf / cf;
+ S = bf / af;
+ T = af / cf;
+ P = S * ((T * (R - T) * (cx - bx)) - ((1.0 - R) * (bx - ax)));
+ Q = (T - 1.0) * (R - 1.0) * (S - 1.0);
+ }
+ if (P < 0.0) /* Keep sign of P/Q with abs(P) */
+ Q = -Q;
+ P = fabs(P);
+ {
+ double min1, min2;
+ min1 = (3.0 * xdel * Q) - (tol1 * fabs(Q));
+ min2 = fabs(pdel * Q);
+ if (min2 < min1)
+ min1 = min2;
+
+ if ((2.0 * P) < min1) { /* Interpolation looks OK */
+ pdel = del; /* Remember last delta */
+ del = P / Q; /* Next delta */
+ } else {
+ pdel = del = xdel; /* Use bisection */
+ }
+ }
+ } else {
+ pdel = del = xdel; /* Use bisection */
+ }
+ ax = bx; /* a keeps previous best point */
+ af = bf;
+ if (fabs(del) > tol1) /* Delta looks reasonable */
+ bx += del;
+ else
+ bx += (xdel > 0.0 ? tol1 : -tol1); /* Do minimum move in direction of bisection */
+ bf = (*func)(fdata, bx);
+ }
+ return -2; /* Too many iterations */
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/numlib/zbrent.h b/numlib/zbrent.h
new file mode 100644
index 0000000..2f8aac4
--- /dev/null
+++ b/numlib/zbrent.h
@@ -0,0 +1,44 @@
+#ifndef ROOT_H
+#define ROOT_H
+
+/*
+ * Copyright 2000 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.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* 1 dimentional root finding code */
+
+/* Bracket search function */
+/* return 0 on sucess */
+/* -1 on no range */
+/* -2 on too many itterations */
+int zbrac(
+double *x1, /* Input and output bracket values */
+double *x2,
+double (*func)(void *fdata, double tp), /* function to evaluate */
+void *fdata); /* Opaque data pointer */
+
+/* Root finder */
+/* return 0 on sucess */
+/* -1 on root not bracketed */
+/* -2 on too many itterations */
+int zbrent(
+double *rv, /* Return value */
+double x1, /* Bracket to search */
+double x2, /* (Min, Max) */
+double tol, /* Desired tollerance */
+double (*func)(void *fdata, double tp), /* function to evaluate */
+void *fdata); /* Opaque data pointer */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* ROOT_H */
diff --git a/numlib/zbrenttest.c b/numlib/zbrenttest.c
new file mode 100644
index 0000000..d7b44d3
--- /dev/null
+++ b/numlib/zbrenttest.c
@@ -0,0 +1,56 @@
+/* Do a test of the brent 1d root finder */
+
+/*
+ * Copyright 2000 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.
+ */
+
+/* Solves (3 - 2*X) * X = -1 */
+
+#include "numlib.h"
+
+int its = 0;
+double fcn(void *fdata, double tp);
+
+/* Expected solution */
+double expect = -2.80776403408306e-01;
+
+int main(void)
+{
+ int rv;
+ double x1, x2, soln;
+
+ /* Attempt bracket the solution */
+ x1 = -0.1;
+ x2 = 0.1;
+ rv = zbrac(&x1, &x2, fcn, NULL);
+ if (rv != 0) {
+ error("zbrack failed with rv = %d\n",rv);
+ }
+ printf("Got bracket %f, %f in %d itterations\n",x1,x2,its);
+
+ /* Solve the equation */
+ its = 0;
+ rv = zbrent(&soln, x1, x2, 1e-6, fcn, NULL);
+ if (rv != 0) {
+ error("xbrent failed with rv = %d\n",rv);
+ }
+
+ printf("Solution = %f, expected = %f in %d itterations\n",soln, expect, its);
+ return 0;
+
+} /* main() */
+
+/* Function being solved */
+double fcn(void *fdata, double tp)
+{
+ double temp;
+ its++;
+ temp = ((3.0 - 2.0 * tp) * tp) + 1.0;
+/* printf("~~ %f returns %f\n",tp,temp); */
+ return temp;
+}
+
diff --git a/plot/Imakefile b/plot/Imakefile
new file mode 100644
index 0000000..316b296
--- /dev/null
+++ b/plot/Imakefile
@@ -0,0 +1,6 @@
+ INCLUDES = -I$(TOP)
+ DEPLIBS = $(DEPXLIB)
+LOCAL_LIBRARIES = $(XLIB)
+ SYS_LIBRARIES = -lm
+
+SimpleProgramTarget(plot)
diff --git a/plot/Jamfile b/plot/Jamfile
new file mode 100644
index 0000000..47bc09e
--- /dev/null
+++ b/plot/Jamfile
@@ -0,0 +1,27 @@
+
+# Jamfile for plot library and test program
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ;
+
+# Compile .c as .m
+if $(OS) = MACOSX {
+ ObjectCcFlags plot : -ObjC ;
+ ObjectCcFlags plot_plot : -ObjC ;
+}
+
+# PLOT library
+Library libplot : plot.c : : : ../h ../numlib ../spectro ;
+if $(UNIX) && $(OS) != MACOSX {
+ ObjectHdrs plot : $(LibWinH) ;
+}
+
+# Individual stand alone test of plot library
+MainVariant plot : plot.c : : STANDALONE_TEST : ../h ../numlib ../spectro : : ../spectro/libconv.lib ../numlib/libnum.lib ;
+
+# VRML plot library
+Library libvrml : vrml.c : : : ../h ../icc ../cgats ../numlib ../gamut ;
+
+#MainsFromSources t.c ;
+
diff --git a/plot/License.txt b/plot/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/plot/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/plot/Makefile.am b/plot/Makefile.am
new file mode 100644
index 0000000..eabcb91
--- /dev/null
+++ b/plot/Makefile.am
@@ -0,0 +1,12 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libplot.la libvrml.la
+privatelibdir = $(pkglibdir)
+
+libplot_la_SOURCES = plot.h plot.c
+libplot_la_LIBADD = $(X_LIBS)
+
+libvrml_la_SOURCES = vrml.h vrml.c
+libvrml_la_LIBADD = $(ICC_LIBS) ../numlib/libargyllnum.la
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/plot/Readme.txt b/plot/Readme.txt
new file mode 100644
index 0000000..df5a0c0
--- /dev/null
+++ b/plot/Readme.txt
@@ -0,0 +1,2 @@
+A simple Windows NT/X11 2d graph plot library,
+to quickly display graphs and points for debug purposes.
diff --git a/plot/afiles b/plot/afiles
new file mode 100644
index 0000000..0fbf8c6
--- /dev/null
+++ b/plot/afiles
@@ -0,0 +1,14 @@
+Readme.txt
+License.txt
+Jamfile
+Imakefile
+afiles
+plot.c
+plot.h
+vrml.c
+vrml.h
+osx/Readme.txt
+osx/Jamfile
+osx/helloc.c
+osx/acoccoa.h
+osx/hellom.m
diff --git a/plot/osx/Jamfile b/plot/osx/Jamfile
new file mode 100644
index 0000000..933d56d
--- /dev/null
+++ b/plot/osx/Jamfile
@@ -0,0 +1,21 @@
+
+# Jamfile for OS X window code development
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += -x objective-c ;
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ;
+
+# Hello world
+#Main hello : hello.m ;
+
+# Hello world window in C
+Main helloc : helloc.c ;
+
+# Hello world window in Objective-C
+ObjectCcFlags hellom : -ObjC ;
+Main hellom : hellom.m ;
+
+#GuiBin tt ;
+#Main tt : tt.m ;
+
diff --git a/plot/osx/Readme.txt b/plot/osx/Readme.txt
new file mode 100644
index 0000000..44b083b
--- /dev/null
+++ b/plot/osx/Readme.txt
@@ -0,0 +1 @@
+Develop Cocoa based simple window code.
diff --git a/plot/osx/acoccoa.h b/plot/osx/acoccoa.h
new file mode 100644
index 0000000..ba88cd4
--- /dev/null
+++ b/plot/osx/acoccoa.h
@@ -0,0 +1,402 @@
+
+#ifndef ACOCCOA_H
+
+/* OS X Coccoa support code for Argyll. */
+/* In some places we really prefer not to have OS X code */
+/* in separate .m files, so we'll do it all from C. */
+
+#include <Carbon/Carbon.h>
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+# include <objc/runtime.h>
+# include <objc/message.h>
+#else
+# include <objc/objc-runtime.h>
+
+/* Objective-C runtime compatibility functions for < 10.5 */
+
+/* Create a class definition, but don't register it */
+Class CreateClassDefinition(const char *name, const char *superclassName) {
+ struct objc_class *meta_class;
+ struct objc_class *super_class;
+ struct objc_class *new_class;
+ struct objc_class *root_class;
+
+ // Ensure that the superclass exists and that someone
+ // hasn't already implemented a class with the same name
+ //
+ super_class = (struct objc_class *)objc_lookUpClass(superclassName);
+ if (super_class == nil) {
+ printf("failed to lookup '%s'\n",superclassName);
+ return Nil;
+ }
+
+ if (objc_lookUpClass(name) != nil) {
+ return Nil;
+ }
+
+ // Find the root class
+ root_class = super_class;
+ while(root_class->super_class != nil)
+ root_class = root_class->super_class;
+
+ // Allocate space for the class and its metaclass
+ if ((new_class = calloc(2, sizeof(struct objc_class))) == NULL) {
+ return Nil;
+ }
+ meta_class = &new_class[1];
+
+ // setup class
+ new_class->isa = meta_class;
+ new_class->info = CLS_CLASS;
+ meta_class->info = CLS_META;
+
+ // Create a copy of the class name.
+ // For efficiency, we have the metaclass and the class itself
+ // to share this copy of the name, but this is not a requirement
+ // imposed by the runtime.
+ if ((new_class->name = strdup(name)) == NULL) {
+ free(new_class);
+ }
+ meta_class->name = new_class->name;
+
+ // Allocate empty method lists.
+ // We can add methods later.
+ if ((new_class->methodLists = calloc( 1, sizeof(struct objc_method_list *))) == NULL) {
+ free((void *)new_class->name);
+ free(new_class);
+ return Nil;
+ }
+ *new_class->methodLists = (struct objc_method_list *) -1;
+ if ((meta_class->methodLists = calloc(1, sizeof(struct objc_method_list *))) == NULL) {
+ free(new_class->methodLists);
+ free((void *)new_class->name);
+ free(new_class);
+ return Nil;
+ }
+ *meta_class->methodLists = (struct objc_method_list *) -1;
+
+ // Connect the class definition to the class hierarchy:
+ // Connect the class to the superclass.
+ // Connect the metaclass to the metaclass of the superclass.
+ // Connect the metaclass of the metaclass to the metaclass of the root class.
+ new_class->super_class = super_class;
+ meta_class->super_class = super_class->isa;
+ meta_class->isa = (void *)root_class->isa;
+
+ // Set the sizes of the class and the metaclass.
+ new_class->instance_size = super_class->instance_size;
+ meta_class->instance_size = meta_class->super_class->instance_size;
+
+ return new_class;
+}
+
+/* Add an array of methods. Null terminated by name array */
+/* We assume that the class is being created, and that there are */
+/* no existing methods. */
+BOOL registerDynamicMethods(Class cls, const char *mnames[], IMP mimps[], const char *mtypes[]) {
+ int i, nmeth;
+ struct objc_method_list *methodList;
+
+ /* Count the number of methods */
+ for (nmeth = 0; mnames[nmeth] != NULL && mnames[nmeth][0] != '\000'; nmeth++)
+ ;
+
+ /* Allocate an array */
+ methodList = malloc(sizeof(struct objc_method_list) + (nmeth-1) * sizeof(struct objc_method));
+
+ methodList->method_count = nmeth;
+ for (i = 0; i < nmeth; i++) {
+ // Get or register the selector for the method name
+ SEL methodSEL = SELUID(mnames[i]);
+
+ // Registering the method seems to register the selector
+ if (ISSELECTOR(methodSEL) == NO) {
+ methodSEL = sel_registerName(mnames[i]);
+ }
+
+ // Fill out the method list
+ methodList->method_list[i].method_name = methodSEL;
+ methodList->method_list[i].method_imp = mimps[i];
+ methodList->method_list[i].method_types = strdup(mtypes[i]);
+ }
+
+ // Register our methods
+ class_addMethods((Class)cls, methodList);
+
+ return YES;
+}
+
+/* Add an array of instance variables. Null terminated by name array */
+/* We assume that the class is being created, and that there are */
+/* no existing methods. */
+BOOL registerDynamicVariables(Class cls, const char *names[], size_t sizes[], const char *types[]) {
+ int i, nvar = 1;
+ int vsize;
+ struct objc_ivar *ivarp;
+
+ /* Count the number of variables */
+ for (nvar = 0; names[nvar] != NULL && names[nvar][0] != '\000'; nvar++)
+ ;
+
+ vsize = sizeof(struct objc_ivar_list) + (nvar - 1) * sizeof(struct objc_ivar);
+ cls->ivars = calloc(vsize, 1);
+ cls->ivars->ivar_count = nvar;
+
+ for (i = 0; i < nvar; i++) {
+ int abytes;
+ ivarp = &cls->ivars->ivar_list[i];
+
+ /* Set the variable information */
+ ivarp->ivar_name = strdup(names[i]);
+ ivarp->ivar_type = strdup(types[i]);
+
+ /* Align the offset for this variable to it's size, limiting to 64 bits */
+ if ((abytes = sizes[i]) > 8)
+ abytes = 8;
+ cls->instance_size = (cls->instance_size + abytes-1) & ~(abytes-1);
+ ivarp->ivar_offset = (int)cls->instance_size;
+ cls->instance_size += sizes[i];
+ }
+
+ return YES;
+}
+
+#endif /* __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 */
+
+extern id NSApp;
+
+/* Create a class */
+BOOL registerClass(
+const char *name, /* Name of class being created */
+const char *supername, /* Name of superclass */
+const char *methnames[], /* List of method names, empty string terminated */
+IMP methimps[], /* Method implementations */
+const char *methsigs[], /* Method signatures */
+const char *varnames[], /* List of variable names, empty string terminated */
+size_t varsizes[], /* Variable size in bytes */
+const char *varsigs[] /* Variable signatures */
+) {
+ int i;
+ Class nclass;
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+ nclass = objc_allocateClassPair((Class)objc_getClass(supername), name, 0);
+ if (nclass == Nil) {
+ return NO;
+ }
+
+ for (i = 0; methnames[i] != NULL && methnames[i][0] != '\000'; i++) {
+ class_addMethod(nclass, sel_getUid(methnames[i]), methimps[i], methsigs[i]);
+ }
+
+ // Should check return value is YES
+ for (i = 0; varnames[i] != NULL && varnames[i][0] != '\000'; i++) {
+ int asize;
+ while( (1 << asize) < varsizes[i] && asize < 8)
+ asize++;
+ class_addIvar(nclass, varnames[i], varsizes[i], asize, varsigs[i]);
+ }
+
+ // Must be called after adding instance variable
+ objc_registerClassPair(nclass);
+#else
+ /* Use compat.h functions to do the dirty work */
+ // Should check the return value!
+ if ((nclass = CreateClassDefinition(name, supername)) == Nil) {
+ return NO;
+ }
+
+ registerDynamicMethods(nclass, methnames, methimps, methsigs);
+
+ registerDynamicVariables(nclass, varnames, varsizes, varsigs);
+
+ // Register the class with the runtime.
+ objc_addClass(nclass);
+#endif
+ return YES;
+}
+
+/* ------------------------------------------------ */
+/* One of the primary disadvantages of coding Coccoa in C */
+/* is the lack of compatible .h files. We have to make our own.. */
+
+/* ------------------------------------------------ */
+
+/* Foundation stuff */
+
+#ifndef __OBJC__
+
+#if !defined(FSTATIC_INLINE)
+# if defined (__GNUC__) && (__GNUC__ == 4)
+# define FSTATIC_INLINE static __inline__ __attribute__((always_inline))
+# else
+# define FSTATIC_INLINE static __inline__
+# endif
+#endif
+
+#ifdef __LP64__
+typedef double NSFloat;
+#else
+typedef float NSFloat;
+#endif
+
+typedef struct _NSPoint {
+ NSFloat x;
+ NSFloat y;
+} NSPoint;
+
+FSTATIC_INLINE NSPoint NSMakePoint(NSFloat x, NSFloat y) {
+ NSPoint r;
+ r.x = x;
+ r.y = y;
+ return r;
+}
+
+typedef struct _NSSize {
+ NSFloat width;
+ NSFloat height;
+} NSSize;
+
+FSTATIC_INLINE NSSize NSMakeSize(NSFloat w, NSFloat h) {
+ NSSize r;
+ r.width = w;
+ r.height = h;
+ return r;
+}
+
+
+typedef struct _NSRect {
+ NSPoint origin;
+ NSSize size;
+} NSRect;
+
+FSTATIC_INLINE NSRect NSMakeRect(NSFloat x, NSFloat y, NSFloat w, NSFloat h) {
+ NSRect r;
+ r.origin.x = x;
+ r.origin.y = y;
+ r.size.width = w;
+ r.size.height = h;
+ return r;
+}
+
+#endif /* !__OBJC__ */
+
+/* ------------------------------------------------ */
+/* Constats for NSString class */
+
+/* 10.4 and latter */
+typedef enum {
+ NSStringDrawingUsesLineFragmentOrigin = (1 << 0),
+ NSStringDrawingUsesFontLeading = (1 << 1),
+ NSStringDrawingDisableScreenFontSubstitution = (1 << 2),
+ NSStringDrawingUsesDeviceMetrics = (1 << 3),
+ NSStringDrawingOneShot = (1 << 4),
+ NSStringDrawingTruncatesLastVisibleLine = (1 << 5)
+} NSStringDrawingOptions;
+
+/* ------------------------------------------------ */
+/* Constats for NSApplication class */
+
+typedef enum {
+ NSApplicationPresentationDefault = 0,
+ NSApplicationPresentationAutoHideDock = (1 << 0),
+ NSApplicationPresentationHideDock = (1 << 1),
+ NSApplicationPresentationAutoHideMenuBar = (1 << 2),
+ NSApplicationPresentationHideMenuBar = (1 << 3),
+ NSApplicationPresentationDisableAppleMenu = (1 << 4),
+ NSApplicationPresentationDisableProcessSwitching = (1 << 5),
+ NSApplicationPresentationDisableForceQuit = (1 << 6),
+ NSApplicationPresentationDisableSessionTermination = (1 << 7),
+ NSApplicationPresentationDisableHideApplication = (1 << 8),
+ NSApplicationPresentationDisableMenuBarTransparency = (1 << 9),
+ NSApplicationPresentationFullScreen = (1 << 10),
+ NSApplicationPresentationAutoHideToolbar = (1 << 11)
+} NSApplicationPresentationOptions;
+
+typedef enum {
+ NSTerminateCancel = 0,
+ NSTerminateNow = 1,
+ NSTerminateLater = 2
+} NSApplicationTerminateReply;
+
+/* ------------------------------------------------ */
+/* Constats for NSWindow class */
+
+enum {
+ NSBorderlessWindowMask = 0,
+ NSTitledWindowMask = 1 << 0,
+ NSClosableWindowMask = 1 << 1,
+ NSMiniaturizableWindowMask = 1 << 2,
+ NSResizableWindowMask = 1 << 3,
+ NSTexturedBackgroundWindowMask = 1 << 8
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
+ ,NSUnscaledWindowMask = 1 << 11,
+ NSUnifiedTitleAndToolbarWindowMask = 1 << 12
+#endif
+};
+
+/* types of window backing store */
+typedef enum {
+ NSBackingStoreRetained = 0,
+ NSBackingStoreNonretained = 1,
+ NSBackingStoreBuffered = 2
+} NSBackingStoreType;
+
+
+/* ------------------------------------------------ */
+/* Convenience functions */
+
+/* Transform process to interact with descktop */
+void transProcess() {
+ OSStatus stat;
+ ProcessSerialNumber psn = { 0, 0 };
+
+ if (GetCurrentProcess(&psn) != noErr) {
+ /* Transform the process so that the desktop interacts with it properly. */
+ /* We don't need resources or a bundle if we do this. */
+ if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn,
+ kProcessTransformToForegroundApplication)) != noErr)
+ fprintf(stderr,"TransformProcess failed with code %d\n",stat);
+ }
+}
+
+/* Send a message to the object */
+#define sendMsg(oid, msg, ...) objc_msgSend(oid, sel_getUid(msg), ##__VA_ARGS__)
+
+/* alloc and init a new object */
+id newObject(const char *cname) {
+ id rv;
+ rv = objc_msgSend(objc_getClass(cname), sel_getUid("alloc"));
+ rv = objc_msgSend(rv, sel_getUid("init"));
+ return rv;
+}
+/* release an object */
+void delObject(id oid) {
+ objc_msgSend(oid, sel_getUid("release"));
+}
+
+/* dealloc super */
+void delObjectSuper(id oid) {
+ struct objc_super ss;
+ ss.receiver = oid;
+#ifdef __OBJC__
+ ss.super_class = sendMsg(oid, "superclass");
+#else
+ ss.class = (Class)sendMsg(oid, "superclass");
+#endif
+ objc_msgSendSuper(&ss, sel_getUid("dealloc"));
+}
+
+/* Create an NSString from a C string */
+id newNSString(const char *cstr) {
+ id str;
+
+ str = objc_msgSend(objc_getClass("NSString"), sel_getUid("alloc"));
+ str = objc_msgSend(str, sel_getUid("initWithUTF8String:"), cstr);
+
+ return str;
+}
+
+#define ACOCCOA_H
+#endif /* ACOCCOA_H */
diff --git a/plot/osx/helloc.c b/plot/osx/helloc.c
new file mode 100644
index 0000000..9150989
--- /dev/null
+++ b/plot/osx/helloc.c
@@ -0,0 +1,313 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __OBJC__
+# include <Foundation/Foundation.h>
+# include <AppKit/AppKit.h>
+#endif
+
+#include "acocoa.h" /* Argyll Cocoa support functions and defines */
+
+/*
+- (void) someMethod:...
+{
+ va_list va;
+
+ va_start(va, _cmd);
+
+ // process all args with va_arg
+
+ va_end(va);
+}
+ */
+
+/* Our static instance variables for AppDelegate */
+typedef struct {
+ id window; /* NSWindow */
+ id view; /* NSView */
+} cntx_t;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+void MyView_setCntx(id self, SEL _cmd, void *val) {
+ object_setInstanceVariable(self, "cntx", val);
+}
+
+void MyView_drawRect(id self, SEL _cmd, NSRect rect) {
+ double w = rect.size.width, h = rect.size.height;
+
+ id aPath = sendClassMsg("NSBezierPath", "bezierPath");
+ sendMsg(aPath, "setLineWidth:", 2.0);
+ sendMsg(aPath, "moveToPoint:", NSMakePoint(0.0, 0.0));
+ sendMsg(aPath, "lineToPoint:", NSMakePoint(0.9 * w, 0.9 * h));
+ sendMsg(aPath, "appendBezierPathWithRect:", NSMakeRect(0.5 * w, 0.5 * h,
+ 0.7 * w, 0.6 * h));
+ sendMsg(aPath, "stroke");
+
+ {
+ id att = newObject("NSDictionary");
+ id str = newNSString("String");
+ sendMsg(str, "drawAtPoint:withAttributes:", NSMakePoint(0.1 * w, 0.1 * h), att);
+ }
+}
+
+/* Clean up */
+void MyView_dealloc(id self, SEL _cmd) {
+ delObjectSuper(self);
+}
+
+// Create our custom NSView */
+void createMyView() {
+ method_info minfo[] = {
+ { "setCntx:", (IMP)MyView_setCntx, "v@:^v" },
+ { "drawRect:", (IMP)MyView_drawRect, "v@:@" },
+ { "dealloc", (IMP)MyView_dealloc, "v@:" },
+ { "" }
+ };
+
+ variable_info vinfo[] = {
+ { "cntx", sizeof(void *), "^v" },
+ { "" }
+ };
+
+ registerClass("MyView", "NSView", minfo, vinfo);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+void MyWin_setCntx(id self, SEL _cmd, void *val) {
+ object_setInstanceVariable(self, "cntx", val);
+}
+
+void MyWin_keyDown(id self, SEL _cmd, id event) {
+ int etype;
+ id nresp;
+ id str;
+ const char *cstr;
+
+ etype = (int)sendMsg(event, "type");
+ str = sendMsg(event, "characters");
+ cstr = cNSString(str);
+ printf("Got Window KeyDown type %d, chars '%s'\n",etype, cstr);
+
+ if (cstr[0] == ' ')
+ sendMsg(NSApp, "terminate:", self);
+}
+
+/* Clean up */
+void MyWin_dealloc(id self, SEL _cmd) {
+ delObjectSuper(self);
+}
+
+// Create our custom NSWin */
+void createMyWin() {
+ method_info minfo[] = {
+ { "setCntx:", (IMP)MyWin_setCntx, "v@:^v", },
+ { "keyDown:", (IMP)MyWin_keyDown, "v@:@", },
+ { "dealloc", (IMP)MyWin_dealloc, "v@:" },
+ { "" }
+ };
+
+ variable_info vinfo[] = {
+ { "cntx", sizeof(void *), "^v" },
+ { "" }
+ };
+
+ registerClass("MyWin", "NSWindow", minfo, vinfo);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Create all the bits */
+void AppDel_willFinishLaunching(id self, SEL _cmd, id notification) {
+ cntx_t *cx;
+ id label; /* NSTextField */
+
+ cx = calloc(1, sizeof(cntx_t));
+
+ // Set cntx to to allocated structure
+ object_setInstanceVariable(self, "cntx", (void *)cx);
+
+ /* Create Window */
+ cx->window = sendClassMsg("MyWin", "alloc");
+ cx->window = sendMsg(cx->window,
+ "initWithContentRect:styleMask:backing:defer:",
+ NSMakeRect(300, 300, 200, 100),
+ NSTitledWindowMask
+ | NSClosableWindowMask
+ | NSMiniaturizableWindowMask
+ | NSResizableWindowMask,
+ NSBackingStoreBuffered,
+ YES);
+
+ /* Make the background white */
+ sendMsg(cx->window, "setBackgroundColor:", sendClassMsg("NSColor","whiteColor"));
+
+ /* Add title */
+ sendMsg(cx->window, "setTitle:", newNSString("Hello World"));
+
+#ifdef NEVER
+ /* Create Label */
+ label = sendClassMsg("NSTextField", "alloc");
+ label = sendMsg(label, "initWithFrame:", NSMakeRect(30, 30, 80, 30));
+
+ sendMsg(label, "setSelectable:", NO);
+ sendMsg(label, "setBezeled:", NO);
+ sendMsg(label, "setDrawsBackground:", NO);
+ sendMsg(label, "setStringValue:", newNSString("Hello World"));
+
+ /* Hmm. How does this work ? */
+ cx->view = sendMsg(cx->window, "contentView");
+ sendMsg(cx->view, "addSubview:", label);
+#else
+ /* Use our custom view to draw contents */
+ cx->view = newObject("MyView");
+
+ sendMsg(cx->view, "setCntx:", (void *)cx);
+ sendMsg(cx->window, "setContentView:", cx->view);
+
+// sendMsg(cx->window, "setInitialFirstResponder:", cx->view);
+#endif
+
+ // Window methods:
+
+ // sendEvent: gets messages.
+
+ // Set above the screen saver
+ // [aWindow setLevel:NSScreenSaverWindowLevel + 1];
+
+ // setCollectionBehavior: NSWindowCollectionBehaviorIgnoresCycle
+ // NSWindowCollectionBehaviorFullScreenPrimary
+ // NSWindowCollectionBehaviorStationary
+ // NSWindowCollectionBehaviorIgnoresCycle
+
+ // center
+ // mouseDownCanMoveWindow
+ // setMovable:
+ // setContentMinSize: and setContentMaxSize:
+ //
+ // NSRect frame = [myWindow frame];
+ // if (frame.size.width <= MIN_WIDTH_WITH_ADDITIONS)
+ // frame.size.width = MIN_WIDTH_WITH_ADDITIONS;
+ // frame.size.height += ADDITIONS_HEIGHT;
+ // frame.origin.y -= ADDITIONS_HEIGHT;
+ // [myWindow setFrame:frame display:YES animate:YES];
+ // objc_msgSend(label, "release"));
+ //
+ // setExcludedFromWindowsMenu:YES
+ //
+ // setBackgroundColor: and setAlphaValue:
+
+ // WindowImage object:
+ // setDepthLimit:
+
+ // Setting cursor:
+ // NSTrackingArea class, along with the cursorUpdate: method of the NSResponder class
+
+}
+
+/* Map the window */
+void AppDel_didFinishLaunching(id self, SEL _cmd, id notification) {
+ cntx_t *cx;
+
+ object_getInstanceVariable(self, "cntx", (void **)&cx);
+ sendMsg(cx->window, "makeKeyAndOrderFront:", self);
+
+#ifdef NEVER /* Test terminate */
+ sleep(5);
+ sendMsg(NSApp, "terminate:", self);
+#endif
+}
+
+/* Should the application terminate ? */
+NSApplicationTerminateReply AppDel_shouldTerminate(id self, SEL _cmd, id notification) {
+ return NSTerminateNow;
+}
+
+/* Clean up */
+void AppDel_dealloc(id self, SEL _cmd) {
+ cntx_t *cx;
+
+ object_getInstanceVariable(self, "cntx", (void **)&cx);
+ delObject(cx->window);
+ delObjectSuper(self);
+}
+
+// Create the delegate class that implements our window
+void createAppDelClass() {
+ method_info minfo[] = {
+ { "applicationWillFinishLaunching:", (IMP)AppDel_willFinishLaunching, "v@:@" },
+ { "applicationDidFinishLaunching:", (IMP)AppDel_didFinishLaunching, "v@:@" },
+ { "applicationShouldTerminate:", (IMP)AppDel_shouldTerminate, "i@:@" },
+ { "dealloc", (IMP)AppDel_dealloc, "v@:" },
+ { "" }
+ };
+
+ variable_info vinfo[] = {
+ { "cntx", sizeof(void *), "^v" },
+ { "" }
+ };
+
+ registerClass("AppDelegate", "NSObject", minfo, vinfo);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+int main(int argc, char** argv) {
+ id pool;
+ id appDelObj;
+
+ /* Transform process so that it interacts with desktop properly */
+ transProcess();
+
+ /* Create an autorelease pool */
+ pool = newObject("NSAutoreleasePool");
+
+ // Create all the classes we override
+ createAppDelClass();
+ createMyWin();
+ createMyView();
+
+ // Get our shared NSApplication and start it
+ sendClassMsg("NSApplication", "sharedApplication");
+
+ if (NSApp == NULL) {
+ fprintf(stderr,"Failed to initialized NSApplication... terminating...\n");
+ return -1;
+ }
+
+ /* Set a delegate to create the window */
+ appDelObj = newObject("AppDelegate");
+ sendMsg(NSApp, "setDelegate:", appDelObj);
+
+// if running on 10.7:
+// sendMsg(NSApp, "disableRelaunchOnLogin"));
+
+ /* Call the run loop */
+ sendMsg(NSApp, "run");
+
+ // detachDrawingThread:toTarget:withObject:
+
+ /* To terminate:
+ sendMsg(NSApp, "terminate:", self);
+ */
+
+ /* We're done with the pool */
+ delObject(pool);
+
+ return EXIT_SUCCESS;
+}
+
+#ifdef NEVER
+
+- (void)drawRect:(NSRect)rect
+{
+ NSRect r = NSMakeRect(10, 10, 50, 60);
+ NSBezierPath *bp = [NSBezierPath bezierPathWithRect:r];
+ NSColor *color = [NSColor blueColor];
+ [color set];
+ [bp fill];
+}
+
+#endif
diff --git a/plot/osx/hellom.m b/plot/osx/hellom.m
new file mode 100644
index 0000000..b306878
--- /dev/null
+++ b/plot/osx/hellom.m
@@ -0,0 +1,181 @@
+
+#include <Foundation/Foundation.h>
+#include <AppKit/AppKit.h>
+
+#include <objc/objc-runtime.h> /* For diagnostics */
+
+typedef struct {
+ id window; /* NSWindow */
+ id view; /* NSTextField */
+} cntx_t;
+
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+@interface MyView : NSView {
+ void *cntx;
+}
+- (void)setCntx:(void *)cntx;
+@end
+
+@implementation MyView
+
+- (void)setCntx:(void *)val {
+ cntx = val;
+}
+
+- (void)drawRect:(NSRect)rect {
+// NSGraphicsContext* aContext = [NSGraphicsContext currentContext];
+
+ [[NSColor redColor] setStroke];
+
+ NSBezierPath* aPath = [NSBezierPath bezierPath];
+ [aPath setLineWidth:2.0];
+ [aPath moveToPoint:NSMakePoint(0.0, 0.0)];
+ [aPath lineToPoint:NSMakePoint(100.0, 100.0)];
+ [aPath appendBezierPathWithRect:NSMakeRect(20.0, 160.0, 80.0, 50.0)];
+
+ [aPath stroke];
+
+ NSDictionary *att = [NSDictionary new];
+
+ [ @"String" drawAtPoint: NSMakePoint(10.0, 10.0) withAttributes: att ];
+
+/*
+
+[@"Hello" drawInRect:r withAttributes:[NSDictionary
+dictionaryWithObjectsAndKeys:
+[NSColor redColor], NSForegroundColorAttributeName,
+[NSFont systemFontOfSize:24], NSFontAttributeName,
+nil]];
+
+*/
+}
+
+@end
+
+/* To trigger an update:
+
+Send a setNeedsDisplayInRect: or setNeedsDisplay: message to the
+view. Sending either of these messages marks part or all of the view as invalid
+
+ */
+
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+@interface MyWin : NSWindow {
+ void *cntx;
+}
+- (void)setCntx:(void *)cntx;
+@end
+
+@implementation MyWin
+
+- (void)setCntx:(void *)val {
+ cntx = val;
+}
+
+- (void)keyDown:(NSEvent *)event {
+ printf("Got Window KeyDown type %d char %s\n",[event type],
+ [[event characters] cStringUsingEncoding:NSASCIIStringEncoding]);
+}
+
+- (BOOL)windowShouldClose:(id)sender {
+ printf("Got Window windowShouldClose\n");
+ [NSApp terminate: nil];
+ return YES;
+}
+
+@end
+
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+@interface AppDelegate : NSObject {
+ void *cntx;
+}
+@end
+
+@implementation AppDelegate
+- (void) applicationWillFinishLaunching: (NSNotification *)not {
+ cntx_t *cx;
+
+ cx = calloc(1, sizeof(cntx_t));
+
+ cntx = (void *)cx;
+
+ /* Create Window */
+ cx->window = [[MyWin alloc] initWithContentRect: NSMakeRect(300, 300, 200, 100)
+ styleMask: (NSTitledWindowMask |
+ NSClosableWindowMask |
+ NSMiniaturizableWindowMask |
+ NSResizableWindowMask)
+ backing: NSBackingStoreBuffered
+ defer: YES];
+ [cx->window setTitle: @"Hello World"];
+
+#ifdef NEVER
+ /* Create Label */
+ cx->label = [[NSTextField alloc] initWithFrame: NSMakeRect(30, 30, 80, 30)];
+ [cx->label setSelectable: NO];
+ [cx->label setBezeled: NO];
+ [cx->label setDrawsBackground: NO];
+ [cx->label setStringValue: @"Hello World"];
+
+ [[cx->window contentView] addSubview: cx->label];
+
+ [cx->label release];
+
+#else
+ cx->view = [MyView new];
+ [cx->view setCntx:(void *)cx];
+ [cx->window setContentView: cx->view];
+#endif
+ // [window setContentView:customView]
+}
+
+- (void) applicationDidFinishLaunching: (NSNotification *) not {
+ cntx_t *cx = (cntx_t *)cntx;
+ [cx->window makeKeyAndOrderFront: self];
+}
+
+- (void) dealloc {
+ cntx_t *cx = (cntx_t *)cntx;
+ [cx->window release];
+ [super dealloc];
+}
+@end
+
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+int main (int argc, const char **argv)
+{
+ NSAutoreleasePool *pool;
+ id appDelObj;
+
+ if (NSApp == nil) {
+ OSStatus stat;
+ ProcessSerialNumber psn = { 0, 0 };
+
+ if (GetCurrentProcess(&psn) == noErr) {
+ /* Transform the process so that the desktop interacts with it properly. */
+ /* We don't need resources or a bundle if we do this. */
+ if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn,
+ kProcessTransformToForegroundApplication)) != noErr)
+ fprintf(stderr,"TransformProcess failed with code %d\n",stat);
+ }
+
+ pool = [NSAutoreleasePool new];
+
+ [NSApplication sharedApplication];
+ appDelObj = [AppDelegate new];
+ [NSApp setDelegate: appDelObj];
+
+ // Run the event loop until done
+ [NSApp run];
+
+ [pool release];
+ }
+
+ // To terminate:
+ // [NSApp terminate: nil];
+}
+
+
diff --git a/plot/plot.c b/plot/plot.c
new file mode 100644
index 0000000..c5ca910
--- /dev/null
+++ b/plot/plot.c
@@ -0,0 +1,2511 @@
+
+/*
+ * Copyright 1998 - 2004 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.
+ */
+
+/* This is a simple 2d graph plotter that runs on MSWindows/OSX/X11 */
+/* The code is in three sections, one for each GUI environment. */
+/* (Perhaps common code could be consolidated ?) */
+
+
+/*
+ * TTBD:
+ *
+ * Allow for a window title for each plot.
+ *
+ * Put all state information in plot_info (window handles etc.)
+ * Create thread to handle events, so it updates correctly.
+ * (Will have to lock plot info updates or ping pong them);
+ * Have call to destroy window.
+ * (Could then move to having multiple instances of plot).
+ *
+ * OS X Cocoa code doesn't get window focus. No idea why.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#include <math.h>
+#include "numlib.h"
+#include "plot.h"
+
+#undef DODEBUG /* Print error messages & progress reports */
+//#define STANDALONE_TEST /* Defined by build script */
+
+#define NTICK 10
+#define LTHICK 1.2 /* Plot line thickness */
+#define ILTHICK ((int)(LTHICK+0.5)) /* Integer line thickness */
+//#define ILTHICK 2
+#undef CROSSES /* Mark input points with crosses */
+
+#define DEFWWIDTH 500
+#define DEFWHEIGHT 500
+
+/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */
+/* Brown = Y7, Orange = Y8, Grey = Y9, Magenta = Y10 */
+
+double nicenum(double x, int round);
+
+#define MXGPHS 10 /* Number of graphs with common X axis */
+
+/* Colors of the graphs */
+static int gcolors[MXGPHS][3] = {
+ { 0, 0, 0}, /* Black */
+ { 210, 30, 0}, /* Red */
+ { 0, 200, 90}, /* Green */
+ { 0, 10, 255}, /* Blue */
+ { 200, 200, 0}, /* Yellow */
+ { 220, 0, 255}, /* Purple */
+ { 136, 86, 68}, /* Brown */
+ { 248, 95, 0}, /* Orange */
+ { 160, 160, 160}, /* Grey */
+ { 220, 30, 220} /* Magenta */
+};
+
+/* Information defining plot */
+/* There is one global instance of this. */
+struct _plot_info {
+ void *cx; /* Other Context */
+
+ int dowait; /* Wait for user key if > 0, wait for n secs if < 0 */
+ double ratio; /* Aspect ratio of window, X/Y */
+
+ /* Plot point information */
+ double mnx, mxx, mny, mxy; /* Extrema of values to be plotted */
+ int graph; /* NZ if graph, Z if vectors */
+ int revx; /* reversed X axis */
+
+ double *x1, *x2;
+ double *yy[MXGPHS]; /* y1 - y10 */
+ char **ntext;
+ int n;
+
+ double *x7, *y7;
+ plot_col *mcols;
+ char **mtext;
+ int m;
+
+ double *x8, *y8, *x9, *y9;
+ plot_col *ocols;
+ int o;
+
+ /* Plot instance information */
+ int sx,sy; /* Screen offset */
+ int sw,sh; /* Screen width and height */
+ double scx, scy; /* Scale from input values to screen pixels */
+
+ }; typedef struct _plot_info plot_info;
+
+/* Global to transfer info to window callback */
+static plot_info pd;
+
+/* Declaration of superset */
+static int do_plot_imp(
+ double xmin, double xmax, double ymin, double ymax, /* Bounding box */
+ double ratio, /* Aspect ratio of window, X/Y */
+ int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
+ double *x1, double *x2,
+ double *yy[MXGPHS], char **ntext,
+ int n,
+ double *x7, double *y7, plot_col *mcols, char **mtext,
+ int m,
+ double *x8, double *y8, double *x9, double*y9, plot_col *ocols,
+ int o
+);
+
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+
+/* Public routines */
+/* Plot up to 3 graphs. Wait for key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int
+do_plot(
+double *x,
+double *y1, /* Up to 3 graphs */
+double *y2,
+double *y3,
+int n) {
+ int i, j;
+ double xmin, xmax, ymin, ymax;
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+ yy[2] = y3;
+
+ /* Determine min and max dimensions of plot */
+ xmin = ymin = 1e6;
+ xmax = ymax = -1e6;
+
+ for (i = 0; i < n; i++) {
+ if (xmin > x[i])
+ xmin = x[i];
+ if (xmax < x[i])
+ xmax = x[i];
+
+ for (j = 0; j < MXGPHS; j++) {
+ if (yy[j] != NULL) {
+ if (ymin > yy[j][i])
+ ymin = yy[j][i];
+ if (ymax < yy[j][i])
+ ymax = yy[j][i];
+ }
+ }
+ }
+
+ /* Work out scale factors */
+ if ((xmax - xmin) == 0.0)
+ xmax += 0.5, xmin -= 0.5;
+ if ((ymax - ymin) == 0.0)
+ ymax += 0.5, ymin -= 0.5;
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1,
+ x, NULL, yy, NULL, n,
+ NULL, NULL, NULL, NULL, 0,
+ NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+/* Public routines */
+/* Plot up to 3 graphs + crosses. Wait for key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int
+do_plot_p(
+double *x,
+double *y1, /* Up to 3 graphs */
+double *y2,
+double *y3,
+int n,
+double *x4, double *y4, /* And crosses */
+int m) {
+ int i, j;
+ double xmin, xmax, ymin, ymax;
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+ yy[2] = y3;
+
+ /* Determine min and max dimensions of plot */
+ xmin = ymin = 1e6;
+ xmax = ymax = -1e6;
+
+ for (i = 0; i < n; i++) {
+ if (xmin > x[i])
+ xmin = x[i];
+ if (xmax < x[i])
+ xmax = x[i];
+
+ for (j = 0; j < MXGPHS; j++) {
+ if (yy[j] != NULL) {
+ if (ymin > yy[j][i])
+ ymin = yy[j][i];
+ if (ymax < yy[j][i])
+ ymax = yy[j][i];
+ }
+ }
+ }
+
+ for (i = 0; i < m; i++) {
+ if (x4 != NULL) {
+ if (xmin > x4[i])
+ xmin = x4[i];
+ if (xmax < x4[i])
+ xmax = x4[i];
+ }
+ if (y4 != NULL) {
+ if (ymin > y4[i])
+ ymin = y4[i];
+ if (ymax < y4[i])
+ ymax = y4[i];
+ }
+ }
+
+ /* Work out scale factors */
+ if ((xmax - xmin) == 0.0)
+ xmax += 0.5, xmin -= 0.5;
+ if ((ymax - ymin) == 0.0)
+ ymax += 0.5, ymin -= 0.5;
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1,
+ x, NULL, yy, NULL, n,
+ x4, y4, NULL, NULL, m ,
+ NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+/* Plot up to 3 graphs with specified window size. */
+/* if dowait > 0, wait for user key */
+/* if dowait < 0, wait for no seconds */
+/* If xmax > xmin, use as x scale, else auto. */
+/* If ymax > ymin, use as y scale, else auto. */
+/* ratio is window X / Y */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int
+do_plot_x(
+double *x,
+double *y1,
+double *y2,
+double *y3,
+int n,
+int dowait,
+double pxmin,
+double pxmax,
+double pymin,
+double pymax,
+double ratio
+) {
+ int i, j;
+ double xmin, xmax, ymin, ymax;
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+ yy[2] = y3;
+
+ /* Determine min and max dimensions of plot */
+ xmin = ymin = 1e6;
+ xmax = ymax = -1e6;
+
+ for (i = 0; i < n; i++) {
+ if (xmin > x[i])
+ xmin = x[i];
+ if (xmax < x[i])
+ xmax = x[i];
+
+ for (j = 0; j < MXGPHS; j++) {
+ if (yy[j] != NULL) {
+ if (ymin > yy[j][i])
+ ymin = yy[j][i];
+ if (ymax < yy[j][i])
+ ymax = yy[j][i];
+ }
+ }
+ }
+
+ /* Work out scale factors */
+ if ((xmax - xmin) == 0.0)
+ xmax += 0.5, xmin -= 0.5;
+ if ((ymax - ymin) == 0.0)
+ ymax += 0.5, ymin -= 0.5;
+
+ if (pxmax > pxmin) {
+ xmax = pxmax;
+ xmin = pxmin;
+ }
+ if (pymax > pymin) {
+ ymax = pymax;
+ ymin = pymin;
+ }
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, ratio, dowait,
+ x, NULL, yy, NULL, n,
+ NULL, NULL, NULL, NULL, 0,
+ NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+/* Public routines */
+/* Plot up to 6 graphs. Wait for a key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int
+do_plot6(
+double *x, /* X coord */
+double *y1, /* Black */
+double *y2, /* Red */
+double *y3, /* Green */
+double *y4, /* Blue */
+double *y5, /* Yellow */
+double *y6, /* Purple */
+int n) { /* Number of values */
+ int i, j;
+ double xmin, xmax, ymin, ymax;
+ int nn = abs(n);
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+ yy[2] = y3;
+ yy[3] = y4;
+ yy[4] = y5;
+ yy[5] = y6;
+
+ /* Determine min and max dimensions of plot */
+ xmin = ymin = 1e6;
+ xmax = ymax = -1e6;
+
+ for (i = 0; i < n; i++) {
+ if (xmin > x[i])
+ xmin = x[i];
+ if (xmax < x[i])
+ xmax = x[i];
+
+ for (j = 0; j < MXGPHS; j++) {
+ if (yy[j] != NULL) {
+ if (ymin > yy[j][i])
+ ymin = yy[j][i];
+ if (ymax < yy[j][i])
+ ymax = yy[j][i];
+ }
+ }
+ }
+
+ /* Work out scale factors */
+ if ((xmax - xmin) == 0.0)
+ xmax += 0.5, xmin -= 0.5;
+ if ((ymax - ymin) == 0.0)
+ ymax += 0.5, ymin -= 0.5;
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1,
+ x, NULL, yy, NULL, n,
+ NULL, NULL, NULL, NULL, n ,
+ NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+/* Public routines */
+/* Plot up to 6 graphs + optional crosses. Wait for a key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int
+do_plot6p(
+double *x, /* X coord */
+double *y1, /* Black */
+double *y2, /* Red */
+double *y3, /* Green */
+double *y4, /* Blue */
+double *y5, /* Yellow */
+double *y6, /* Purple */
+int n, /* Number of values */
+double *xp, double *yp, /* And crosses */
+int m) {
+ int i, j;
+ double xmin, xmax, ymin, ymax;
+ int nn = abs(n);
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+ yy[2] = y3;
+ yy[3] = y4;
+ yy[4] = y5;
+ yy[5] = y6;
+
+ /* Determine min and max dimensions of plot */
+ xmin = ymin = 1e6;
+ xmax = ymax = -1e6;
+
+ for (i = 0; i < n; i++) {
+ if (xmin > x[i])
+ xmin = x[i];
+ if (xmax < x[i])
+ xmax = x[i];
+
+ for (j = 0; j < MXGPHS; j++) {
+ if (yy[j] != NULL) {
+ if (ymin > yy[j][i])
+ ymin = yy[j][i];
+ if (ymax < yy[j][i])
+ ymax = yy[j][i];
+ }
+ }
+ }
+
+ for (i = 0; i < m; i++) {
+ if (xp != NULL) {
+ if (xmin > xp[i])
+ xmin = xp[i];
+ if (xmax < xp[i])
+ xmax = xp[i];
+ }
+ if (yp != NULL) {
+ if (ymin > yp[i])
+ ymin = yp[i];
+ if (ymax < yp[i])
+ ymax = yp[i];
+ }
+ }
+
+ /* Work out scale factors */
+ if ((xmax - xmin) == 0.0)
+ xmax += 0.5, xmin -= 0.5;
+ if ((ymax - ymin) == 0.0)
+ ymax += 0.5, ymin -= 0.5;
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1,
+ x, NULL, yy, NULL, n,
+ xp, yp, NULL, NULL, m,
+ NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+/* Public routines */
+/* Plot up to 10 graphs. Wait for a key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int
+do_plot10(
+double *x, /* X coord */
+double *y1, /* Black */
+double *y2, /* Red */
+double *y3, /* Green */
+double *y4, /* Blue */
+double *y5, /* Yellow */
+double *y6, /* Purple */
+double *y7, /* Brown */
+double *y8, /* Orange */
+double *y9, /* Grey */
+double *y10,/* White */
+int n, /* Number of values */
+int zero /* Flag - make sure zero is in y range */
+) {
+ int i, j;
+ double xmin, xmax, ymin, ymax;
+ int nn = abs(n);
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+ yy[2] = y3;
+ yy[3] = y4;
+ yy[4] = y5;
+ yy[5] = y6;
+ yy[6] = y7;
+ yy[7] = y8;
+ yy[8] = y9;
+ yy[9] = y10;
+
+ /* Determine min and max dimensions of plot */
+ xmin = ymin = 1e6;
+ xmax = ymax = -1e6;
+
+ for (i = 0; i < n; i++) {
+ if (xmin > x[i])
+ xmin = x[i];
+ if (xmax < x[i])
+ xmax = x[i];
+
+ for (j = 0; j < MXGPHS; j++) {
+ if (yy[j] != NULL) {
+ if (ymin > yy[j][i])
+ ymin = yy[j][i];
+ if (ymax < yy[j][i])
+ ymax = yy[j][i];
+ }
+ }
+ }
+
+ if (zero && ymin > 0.0)
+ ymin = 0.0;
+
+ /* Work out scale factors */
+ if ((xmax - xmin) == 0.0)
+ xmax += 0.5, xmin -= 0.5;
+ if ((ymax - ymin) == 0.0)
+ ymax += 0.5, ymin -= 0.5;
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1,
+ x, NULL, yy, NULL, n,
+ NULL, NULL, NULL, NULL, n ,
+ NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+/* Public routines */
+/* Plot up to 10 graphs + optional crosses. Wait for a key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int
+do_plot10p(
+double *x, /* X coord */
+double *y1, /* Black */
+double *y2, /* Red */
+double *y3, /* Green */
+double *y4, /* Blue */
+double *y5, /* Yellow */
+double *y6, /* Purple */
+double *y7, /* Brown */
+double *y8, /* Orange */
+double *y9, /* Grey */
+double *y10,/* White */
+int n, /* Number of values */
+double *xp, double *yp, /* And crosses */
+int m) {
+ int i, j;
+ double xmin, xmax, ymin, ymax;
+ int nn = abs(n);
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+ yy[2] = y3;
+ yy[3] = y4;
+ yy[4] = y5;
+ yy[5] = y6;
+ yy[6] = y7;
+ yy[7] = y8;
+ yy[9] = y9;
+ yy[5] = y10;
+
+ /* Determine min and max dimensions of plot */
+ xmin = ymin = 1e6;
+ xmax = ymax = -1e6;
+
+ for (i = 0; i < n; i++) {
+ if (xmin > x[i])
+ xmin = x[i];
+ if (xmax < x[i])
+ xmax = x[i];
+
+ for (j = 0; j < MXGPHS; j++) {
+ if (yy[j] != NULL) {
+ if (ymin > yy[j][i])
+ ymin = yy[j][i];
+ if (ymax < yy[j][i])
+ ymax = yy[j][i];
+ }
+ }
+ }
+
+ for (i = 0; i < m; i++) {
+ if (xp != NULL) {
+ if (xmin > xp[i])
+ xmin = xp[i];
+ if (xmax < xp[i])
+ xmax = xp[i];
+ }
+ if (yp != NULL) {
+ if (ymin > yp[i])
+ ymin = yp[i];
+ if (ymax < yp[i])
+ ymax = yp[i];
+ }
+ }
+
+ /* Work out scale factors */
+ if ((xmax - xmin) == 0.0)
+ xmax += 0.5, xmin -= 0.5;
+ if ((ymax - ymin) == 0.0)
+ ymax += 0.5, ymin -= 0.5;
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1,
+ x, NULL, yy, NULL, n,
+ xp, yp, NULL, NULL, m,
+ NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+
+/* Plot a bunch of vectors + optional crosses */
+/* return 0 on success, -1 on error */
+int do_plot_vec(
+double xmin,
+double xmax,
+double ymin,
+double ymax,
+double *x1, /* vector start */
+double *y1,
+double *x2, /* vector end */
+double *y2,
+int n, /* Number of vectors */
+int dowait,
+double *x3, /* extra point */
+double *y3,
+plot_col *mcols, /* point colors */
+char **mtext, /* notation */
+int m /* Number of points */
+) {
+ int j;
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, dowait,
+ x1, x2, yy, NULL, n,
+ x3, y3, mcols, mtext, m,
+ NULL, NULL, NULL, NULL, NULL, 0);
+}
+
+/* Plot a bunch of vectors + optional crosses + optional vectors*/
+/* return 0 on success, -1 on error */
+int do_plot_vec2(
+double xmin,
+double xmax,
+double ymin,
+double ymax,
+double *x1, /* n vector start */
+double *y1,
+double *x2, /* vector end and diagonal cross */
+double *y2,
+char **ntext, /* text annotation at cross */
+int n, /* Number of vectors */
+int dowait,
+double *x3, /* m extra point */
+double *y3,
+plot_col *mcols,/* point colors */
+char **mtext, /* text annotation */
+int m, /* Number of points */
+double *x4, /* o vector start */
+double *y4,
+double *x5, /* o vector end */
+double *y5,
+plot_col *ocols,/* Vector colors */
+int o /* Number of vectors */
+) {
+ int j;
+ double *yy[MXGPHS];
+
+ for (j = 0; j < MXGPHS; j++)
+ yy[j] = NULL;
+
+ yy[0] = y1;
+ yy[1] = y2;
+
+ return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, dowait,
+ x1, x2, yy, ntext, n,
+ x3, y3, mcols, mtext, m,
+ x4, y4, x5, y5, ocols, o);
+}
+/* ********************************** NT version ********************** */
+#ifdef NT
+
+#include <windows.h>
+
+#ifdef DODEBUG
+# define debugf(xx) printf xx
+#else
+# define debugf(xx)
+#endif
+
+double plot_ratio = 1.0;
+HANDLE plot_th; /* Thread */
+char plot_AppName[] = "PlotWin";
+HWND plot_hwnd = NULL; /* Open only one window per session */
+int plot_signal = 0; /* Signal a key or quit */
+
+static LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);
+
+/* Thread to handle message processing, so that there is no delay */
+/* when the main thread is doing other things. */
+DWORD WINAPI plot_message_thread(LPVOID lpParameter) {
+ MSG msg;
+ WNDCLASS wc;
+ ATOM arv;
+ HWND _hwnd;
+
+ // Fill in window class structure with parameters that describe the
+ // main window.
+
+ wc.style = CS_HREDRAW | CS_VREDRAW; // Class style(s).
+ wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for windows of this class.
+ wc.cbClsExtra = 0; // No per-class extra data.
+ wc.cbWndExtra = 0; // No per-window extra data.
+ wc.hInstance = NULL; // Application that owns the class.
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_CROSS);
+ wc.hbrBackground = GetStockObject(WHITE_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = plot_AppName;
+
+ arv = RegisterClass(&wc);
+
+ if (!arv) {
+ debugf(("RegisterClass failed, lasterr = %d\n",GetLastError()));
+ return -1;
+ }
+
+ _hwnd = CreateWindow(
+ plot_AppName,
+ "2D Diagnostic Graph Plot",
+ WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ (int)(DEFWWIDTH * plot_ratio + 0.5),
+ DEFWHEIGHT,
+ NULL,
+ NULL,
+ NULL, // hInstance,
+ NULL);
+
+ if (!_hwnd) {
+ debugf(("CreateWindow failed, lasterr = %d\n",GetLastError()));
+ return -1;
+ }
+
+ ShowWindow(_hwnd, SW_SHOW);
+
+ plot_hwnd = _hwnd;
+
+ /* Now process messages until we're done */
+ for (;;) {
+ if (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ if (plot_signal == 99)
+ break;
+ }
+ }
+
+ if (UnregisterClass(plot_AppName, NULL) == 0) {
+ debugf(("UnregisterClass failed, lasterr = %d\n",GetLastError()));
+ }
+
+ plot_hwnd = NULL; /* Signal it's been deleted */
+
+ return 0;
+}
+
+/* Superset implementation function: */
+/* return 0 on success, -1 on error */
+/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */
+/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */
+/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */
+/* with annotation ntext at the cross, */
+/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */
+/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */
+/* n = number of points/vectors. -ve for reversed X axis */
+/* m = number of extra points (x2,y3 or x7,y7) */
+static int do_plot_imp(
+ double xmin, double xmax, double ymin, double ymax, /* Bounding box */
+ double ratio, /* Aspect ratio of window, X/Y */
+ int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
+ double *x1, double *x2,
+ double *yy[MXGPHS], char **ntext,
+ int n,
+ double *x7, double *y7, plot_col *mcols, char **mtext,
+ int m,
+ double *x8, double *y8, double *x9, double*y9, plot_col *ocols,
+ int o
+) {
+ pd.dowait = 10 * dowait;
+ pd.ratio = ratio;
+ {
+ int j;
+ double xr,yr;
+
+ pd.mnx = xmin;
+ pd.mny = ymin;
+ pd.mxx = xmax;
+ pd.mxy = ymax;
+
+ /* Allow some extra around plot */
+ xr = pd.mxx - pd.mnx;
+ yr = pd.mxy - pd.mny;
+ if (xr < 1e-6)
+ xr = 1e-6;
+ if (yr < 1e-6)
+ yr = 1e-6;
+ pd.mnx -= xr/10.0;
+ pd.mxx += xr/10.0;
+ pd.mny -= yr/10.0;
+ pd.mxy += yr/10.0;
+
+ /* Transfer raw point info */
+ if (x2 == NULL)
+ pd.graph = 1; /* 6 graphs + points */
+ else
+ pd.graph = 0;
+ pd.x1 = x1;
+ pd.x2 = x2;
+ for (j = 0; j < MXGPHS; j++)
+ pd.yy[j] = yy[j];
+ pd.ntext = ntext;
+ pd.n = abs(n);
+
+ if (n < 0) {
+ double tt;
+ tt = pd.mxx;
+ pd.mxx = pd.mnx;
+ pd.mnx = tt;
+ pd.revx = 1;
+ } else {
+ pd.revx = 0;
+ }
+ pd.x7 = x7;
+ pd.y7 = y7;
+ pd.mcols = mcols;
+ pd.mtext = mtext;
+ pd.m = abs(m);
+
+ pd.x8 = x8;
+ pd.y8 = y8;
+ pd.x9 = x9;
+ pd.y9 = y9;
+ pd.ocols = ocols;
+ pd.o = abs(o);
+ }
+
+ /* ------------------------------------------- */
+ /* Setup windows stuff */
+ {
+
+ /* It would be nice to reduce number of globals. */
+
+ /* We don't clean up properly either - ie. don't delete thread etc. */
+
+ /* Create thread that creats window and processes window messages */
+ if (plot_hwnd == NULL) {
+
+ plot_ratio = ratio;
+
+ plot_th = CreateThread(NULL, 0, plot_message_thread, NULL, 0, NULL);
+ if (plot_th == NULL) {
+ debugf(("new_athread failed\n"));
+ return -1;
+ }
+ while (plot_hwnd == NULL)
+ Sleep(50);
+ }
+
+ plot_signal = 0;
+
+ SetForegroundWindow(plot_hwnd);
+
+ /* Force a repaint with the new data */
+ if (!InvalidateRgn(plot_hwnd,NULL,TRUE)) {
+ debugf(("InvalidateRgn failed, lasterr = %d\n",GetLastError()));
+ return -1;
+ }
+
+ if (dowait > 0) { /* Wait for a space key */
+ while(plot_signal == 0 && plot_hwnd != NULL)
+ Sleep(50);
+ plot_signal = 0;
+ } else if (dowait < 0) {
+ Sleep(-dowait * 1000);
+ }
+ }
+ return 0;
+}
+
+void DoPlot(HDC hdc, plot_info *pd);
+
+static LRESULT CALLBACK MainWndProc(
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+) {
+ HDC hdc;
+ PAINTSTRUCT ps;
+ RECT rect;
+
+ debugf(("Handling message type 0x%x\n",message));
+ // Could use Set/GetWindowLong() to pass window class info instead of global pd (beware NULL)
+ switch(message) {
+ case WM_PAINT:
+ debugf(("It's a paint message\n"));
+ hdc = BeginPaint(hwnd, &ps);
+ GetClientRect(hwnd, &rect);
+
+ /* Setup the plot info structure for this drawing */
+ pd.sx = rect.left;
+ pd.sy = rect.top;
+ pd.sw = 1 + rect.right - rect.left;
+ pd.sh = 1 + rect.bottom - rect.top;
+ pd.scx = (pd.sw - 10)/(pd.mxx - pd.mnx);
+ pd.scy = (pd.sh - 10)/(pd.mxy - pd.mny);
+
+ DoPlot(hdc, &pd);
+
+ EndPaint(hwnd, &ps);
+
+ return 0;
+
+ case WM_CHAR:
+ debugf(("It's a char message, wParam = 0x%x\n",wParam));
+ switch(wParam) {
+ case ' ': /* Space */
+ debugf(("It's a SPACE, so signal it\n"));
+ plot_signal = 1;
+ return 0;
+ }
+
+ case WM_CLOSE:
+ debugf(("It's a close message\n"));
+ DestroyWindow(hwnd);
+ return 0;
+
+ case WM_DESTROY:
+ debugf(("It's a destroy message\n"));
+ plot_signal = 99;
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ debugf(("It's a message not handled here\n"));
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+void
+xtick(HDC hdc, plot_info *pdp, double x, char *lab)
+ {
+ int xx,yy;
+ RECT rct;
+// GrLine(10 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 - 5,
+// 10 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 + 5, 1);
+// GrTextXY(5 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 - 10, lab, 1, 0);
+
+ xx = 10 + (int)((x - pdp->mnx) * pdp->scx + 0.5);
+ yy = pdp->sh - 10;
+
+ MoveToEx(hdc,xx, yy, NULL);
+ LineTo( hdc,xx, 0);
+ rct.right =
+ rct.left = xx;
+ rct.top =
+ rct.bottom = yy;
+ DrawText(hdc, lab, -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
+ }
+
+void
+ytick(HDC hdc, plot_info *pdp, double y, char *lab)
+ {
+ int xx,yy;
+ RECT rct;
+// GrLine(5, 10 + (int)((y - pdp->mny) * pdp->scy + 0.5),
+// 15, 10 + (int)((y - pdp->mny) * pdp->scy + 0.5), 1);
+// GrTextXY(5, pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5), lab, 1, 0);
+
+ xx = 5;
+ yy = pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5);
+ MoveToEx(hdc,xx, yy,NULL);
+ LineTo( hdc,pdp->sw, yy);
+ rct.right =
+ rct.left = xx;
+ rct.top =
+ rct.bottom = yy;
+ DrawText(hdc, lab, -1, &rct, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_NOCLIP);
+ }
+
+void
+loose_label(HDC hdc, plot_info *pdp, double min, double max, void (*pfunc)(HDC hdc, plot_info *pdp, double, char *)
+) {
+ char str[6], temp[20];
+ int nfrac;
+ double d;
+ double graphmin, graphmax;
+ double range,x;
+
+ range = nicenum(min-max,0);
+ d = nicenum(range/(NTICK-1),1);
+ graphmin = floor(min/d) * d;
+ graphmax = ceil(max/d) * d;
+ nfrac = (int)MAX(-floor(log10(d)),0);
+ sprintf(str,"%%.%df", nfrac);
+ for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
+ sprintf(temp,str,x);
+ pfunc(hdc,pdp,x,temp);
+ }
+}
+
+void
+DoPlot(
+HDC hdc,
+plot_info *pdp
+) {
+ int i, j;
+ int lx,ly; /* Last x,y */
+ HPEN pen;
+
+ pen = CreatePen(PS_DOT,0,RGB(200,200,200));
+
+ SaveDC(hdc);
+ SelectObject(hdc,pen);
+
+ /* Plot horizontal axis */
+ if (pdp->revx)
+ loose_label(hdc, pdp, pdp->mxx, pdp->mnx, xtick);
+ else
+ loose_label(hdc, pdp, pdp->mnx, pdp->mxx, xtick);
+
+ /* Plot vertical axis */
+ loose_label(hdc, pdp, pdp->mny, pdp->mxy, ytick);
+
+ RestoreDC(hdc,-1);
+ DeleteObject(pen);
+
+ if (pdp->graph) { /* Up to MXGPHS graphs + crosses */
+ int gcolors[MXGPHS][3] = {
+ { 0, 0, 0}, /* Black */
+ { 210, 30, 0}, /* Red */
+ { 0, 200, 90}, /* Green */
+ { 0, 10, 255}, /* Blue */
+ { 200, 200, 0}, /* Yellow */
+ { 220, 0, 255}, /* Purple */
+ { 136, 86, 68}, /* Brown */
+ { 248, 95, 0}, /* Orange */
+ { 160, 160, 160}, /* Grey */
+ { 220, 220, 220} /* White */
+ };
+ for (j = MXGPHS-1; j >= 0; j--) {
+ double *yp = pdp->yy[j];
+
+ if (yp == NULL)
+ continue;
+
+ pen = CreatePen(PS_SOLID,ILTHICK,RGB(gcolors[j][0],gcolors[j][1],gcolors[j][2]));
+ SelectObject(hdc,pen);
+
+ lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5);
+
+ for (i = 0; i < pdp->n; i++) {
+ int cx,cy;
+ cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5);
+
+ MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL);
+ LineTo(hdc, 10 + cx, pdp->sh - 10 - cy);
+#ifdef CROSSES
+ MoveToEx(hdc, 10 + cx - 5, pdp->sh - 10 - cy - 5, NULL);
+ LineTo(hdc, 10 + cx + 5, pdp->sh - 10 - cy + 5);
+ GrLine(10 + cx + 5, pdp->sh - 10 - cy - 5);
+ LineTo(hdc, 10 + cx - 5, pdp->sh - 10 - cy + 5);
+#endif
+ lx = cx;
+ ly = cy;
+ }
+ DeleteObject(pen);
+ }
+
+ } else { /* Vectors with cross */
+
+ pen = CreatePen(PS_SOLID,ILTHICK,RGB(0,0,0));
+ SelectObject(hdc,pen);
+
+ if (pdp->ntext != NULL) {
+ HFONT fon;
+
+ fon = CreateFont(12, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
+ FF_DONTCARE, NULL);
+
+ if (fon == NULL)
+ fprintf(stderr,"plot: CreateFont returned NULL\n");
+ else {
+ SelectObject(hdc,fon);
+ DeleteObject(fon);
+ }
+ }
+
+ for (i = 0; i < pdp->n; i++) {
+ int cx,cy;
+
+ lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5);
+
+ cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5);
+
+ MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL);
+ LineTo(hdc, 10 + cx, pdp->sh - 10 - cy);
+
+ MoveToEx(hdc, 10 + cx - 5, pdp->sh - 10 - cy - 5, NULL);
+ LineTo(hdc, 10 + cx + 5, pdp->sh - 10 - cy + 5);
+ MoveToEx(hdc, 10 + cx + 5, pdp->sh - 10 - cy - 5, NULL);
+ LineTo(hdc, 10 + cx - 5, pdp->sh - 10 - cy + 5);
+
+ if (pdp->ntext != NULL) {
+ RECT rct;
+ rct.right =
+ rct.left = 10 + cx + 10;
+ rct.top =
+ rct.bottom = pdp->sh - 10 - cy + 10;
+ DrawText(hdc, pdp->ntext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
+ }
+ }
+ DeleteObject(pen);
+ }
+
+ /* Extra points */
+ if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) {
+ pen = CreatePen(PS_SOLID,ILTHICK,RGB(210,150,0));
+ SelectObject(hdc,pen);
+
+ if (pdp->mtext != NULL) {
+ HFONT fon;
+
+
+ fon = CreateFont(12, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
+ FF_DONTCARE, NULL);
+
+ if (fon == NULL)
+ fprintf(stderr,"plot: CreateFont returned NULL\n");
+ else {
+ SelectObject(hdc,fon);
+ DeleteObject(fon);
+ }
+ }
+
+ for (i = 0; i < pdp->m; i++) {
+ lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5);
+
+ if (pdp->mcols != NULL) {
+ int rgb[3];
+
+ for (j = 0; j < 3; j++)
+ rgb[j] = (int)(pdp->mcols[i].rgb[j] * 255.0 + 0.5);
+
+ DeleteObject(pen);
+ pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2]));
+ SelectObject(hdc,pen);
+
+ if (pdp->mtext != NULL)
+ SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2]));
+ }
+ MoveToEx(hdc, 10 + lx - 5, pdp->sh - 10 - ly, NULL);
+ LineTo(hdc, 10 + lx + 5, pdp->sh - 10 - ly);
+ MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly - 5, NULL);
+ LineTo(hdc, 10 + lx, pdp->sh - 10 - ly + 5);
+
+ if (pdp->mtext != NULL) {
+ RECT rct;
+ rct.right =
+ rct.left = 10 + lx + 10;
+ rct.top =
+ rct.bottom = pdp->sh - 10 - ly - 10;
+ DrawText(hdc, pdp->mtext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
+ }
+ }
+ DeleteObject(pen);
+ }
+ /* Extra vectors */
+ if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) {
+ pen = CreatePen(PS_SOLID,ILTHICK,RGB(150,255,255));
+ SelectObject(hdc,pen);
+
+ for (i = 0; i < pdp->o; i++) {
+ int cx,cy;
+
+ lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5);
+
+ cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5);
+
+ if (pdp->ocols != NULL) {
+ int rgb[3];
+
+ for (j = 0; j < 3; j++)
+ rgb[j] = (int)(pdp->ocols[i].rgb[j] * 255.0 + 0.5);
+
+ DeleteObject(pen);
+ pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2]));
+ SelectObject(hdc,pen);
+
+ if (pdp->mtext != NULL)
+ SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2]));
+ }
+ MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL);
+ LineTo(hdc, 10 + cx, pdp->sh - 10 - cy);
+ }
+ DeleteObject(pen);
+ }
+
+// while(!kbhit());
+ }
+
+#else /* !NT */
+
+/* ************************** APPLE OSX Cocoa version ****************** */
+#ifdef __APPLE__
+
+#include <Foundation/Foundation.h>
+#include <AppKit/AppKit.h>
+
+#ifndef CGFLOAT_DEFINED
+#ifdef __LP64__
+typedef double CGFloat;
+#else
+typedef float CGFloat;
+#endif /* defined(__LP64__) */
+#endif
+
+#ifdef DODEBUG
+# define debugf(xx) printf xx
+#else
+# define debugf(xx)
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+@class PLWin;
+@class PLView;
+
+/* Our static instance variables */
+typedef struct {
+ PLWin *window; /* NSWindow */
+ PLView *view; /* NSTextField */
+ volatile int plot_signal; /* Signal a key or quit */
+} cntx_t;
+
+/* Global plot instanc */
+
+cntx_t *plot_cx = NULL;
+
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+@interface PLView : NSView {
+ cntx_t *cntx;
+}
+- (void)setCntx:(cntx_t *)cntx;
+@end
+
+@implementation PLView
+
+- (void)setCntx:(cntx_t *)val {
+ cntx = val;
+}
+
+/* This function does the work */
+static void DoPlot(NSRect *rect, plot_info *pdp);
+
+- (void)drawRect:(NSRect)rect {
+
+ /* Use global plot data struct for now */
+ DoPlot(&rect, &pd);
+}
+
+@end
+
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+@interface PLWin : NSWindow {
+ cntx_t *cntx;
+}
+- (void)setCntx:(cntx_t *)cntx;
+@end
+
+@implementation PLWin
+
+- (void)setCntx:(cntx_t *)val {
+ cntx = val;
+}
+
+- (BOOL)canBecomeMainWindow {
+ return YES;
+}
+
+- (void)keyDown:(NSEvent *)event {
+ const char *chars;
+
+ chars = [[event characters] UTF8String];
+// printf("Got Window KeyDown type %d char %s\n",(int)[event type], chars);
+
+ if (chars[0] == ' ') {
+// printf("Set plot_signal = 1\n");
+ plot_cx->plot_signal = 1;
+ }
+}
+
+- (BOOL)windowShouldClose:(id)sender {
+// printf("Got Window windowShouldClose\n");
+
+ [NSApp terminate: nil];
+ return YES;
+}
+
+@end
+
+/* Create our window */
+static void create_my_win(cntx_t *cx) {
+ NSRect wRect;
+
+ /* Create Window */
+ wRect.origin.x = 100;
+ wRect.origin.y = 100;
+ wRect.size.width = (int)(DEFWWIDTH*pd.ratio+0.5);
+ wRect.size.height = DEFWHEIGHT;
+
+ cx->window = [[PLWin alloc] initWithContentRect: wRect
+ styleMask: (NSTitledWindowMask |
+ NSClosableWindowMask |
+ NSMiniaturizableWindowMask |
+ NSResizableWindowMask)
+ backing: NSBackingStoreBuffered
+ defer: YES
+ screen: nil]; /* Main screen */
+
+ [cx->window setBackgroundColor: [NSColor whiteColor]];
+
+ [cx->window setLevel: NSMainMenuWindowLevel]; // ~~99
+
+ [cx->window setTitle: @"PlotWin"];
+
+ /* Use our view for the whole window to draw plot */
+ cx->view = [PLView new];
+ [cx->view setCntx:(void *)cx];
+ [cx->window setContentView: cx->view];
+
+ [cx->window makeKeyAndOrderFront: nil];
+
+// [cx->window makeMainWindow];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/*
+ Cocoa NSApp is pretty horrible - it will only get user events
+ if created and run in the main thread. So the only way we could
+ decouble the windows from the application would be to intercept
+ main() and create a secondary thread to run the appication while
+ leaving main() in reserve for creating an NSApp and windows.
+
+ Instead we poll events for a while and then go back to the main application.
+ */
+
+/* Superset implementation function: */
+/* return 0 on success, -1 on error */
+/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */
+/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */
+/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */
+/* with annotation ntext at the cross, */
+/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */
+/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */
+/* n = number of points/vectors. -ve for reversed X axis */
+/* m = number of extra points (x2,y3 or x7,y7) */
+static int do_plot_imp(
+ double xmin, double xmax, double ymin, double ymax, /* Bounding box */
+ double ratio, /* Aspect ratio of window, X/Y */
+ int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
+ double *x1, double *x2,
+ double *yy[MXGPHS], char **ntext,
+ int n,
+ double *x7, double *y7, plot_col *mcols, char **mtext,
+ int m,
+ double *x8, double *y8, double *x9, double*y9, plot_col *ocols,
+ int o
+) {
+ /* Put information in global pd */
+ {
+ int j;
+ double xr,yr;
+
+ pd.dowait = dowait;
+ pd.ratio = ratio;
+
+ pd.mnx = xmin;
+ pd.mny = ymin;
+ pd.mxx = xmax;
+ pd.mxy = ymax;
+
+ /* Allow some extra arround plot */
+ xr = pd.mxx - pd.mnx;
+ yr = pd.mxy - pd.mny;
+ if (xr < 1e-6)
+ xr = 1e-6;
+ if (yr < 1e-6)
+ yr = 1e-6;
+ pd.mnx -= xr/10.0;
+ pd.mxx += xr/10.0;
+ pd.mny -= yr/10.0;
+ pd.mxy += yr/10.0;
+
+ /* Transfer raw point info */
+ if (x2 == NULL)
+ pd.graph = 1; /* 6 graphs + points */
+ else
+ pd.graph = 0;
+ pd.x1 = x1;
+ pd.x2 = x2;
+ for (j = 0; j < MXGPHS; j++)
+ pd.yy[j] = yy[j];
+ pd.ntext = ntext;
+ pd.n = abs(n);
+
+ if (n < 0) {
+ double tt;
+ tt = pd.mxx;
+ pd.mxx = pd.mnx;
+ pd.mnx = tt;
+ pd.revx = 1;
+ } else {
+ pd.revx = 0;
+ }
+ pd.x7 = x7;
+ pd.y7 = y7;
+ pd.mcols = mcols;
+ pd.mtext = mtext;
+ pd.m = abs(m);
+
+ pd.x8 = x8;
+ pd.y8 = y8;
+ pd.x9 = x9;
+ pd.y9 = y9;
+ pd.ocols = ocols;
+ pd.o = abs(o);
+ }
+
+ /* If needed, create the indow */
+ if (plot_cx == NULL) {
+
+ /* If there is no NSApp */
+ /* (This should go in a common library) */
+ /* Note that we don't actually clean this up on exit - */
+ /* possibly we can't. */
+ if (NSApp == nil) {
+ static NSAutoreleasePool *pool = nil;
+ ProcessSerialNumber psn = { 0, 0 };
+
+ /* Transform the process so that the desktop interacts with it properly. */
+ /* We don't need resources or a bundle if we do this. */
+ if (GetCurrentProcess(&psn) == noErr) {
+ OSStatus stat;
+ if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn,
+ kProcessTransformToForegroundApplication)) != noErr) {
+// fprintf(stderr,"TransformProcess failed with code %d\n",stat);
+ } else {
+// fprintf(stderr,"TransformProcess suceeded\n");
+ }
+ }
+
+
+ pool = [NSAutoreleasePool new];
+ [NSApplication sharedApplication]; /* Creates NSApp */
+ [NSApp finishLaunching];
+
+ /* We seem to need this, because otherwise we don't get focus automatically */
+ [NSApp activateIgnoringOtherApps: YES];
+ }
+
+ if ((plot_cx = (cntx_t *)calloc(sizeof(cntx_t), 1)) == NULL)
+ error("new_dispwin: Malloc failed (cntx_t)\n");
+
+ create_my_win(plot_cx);
+
+ } else { /* Trigger an update */
+ [plot_cx->view setNeedsDisplay: YES ];
+ }
+
+ /* Wait until the events are done */
+ {
+ NSEvent *event;
+ double tot;
+ NSDate *to;
+ /* We're creating and draining a pool here to ensure that all the */
+ /* auto release objects get drained when we're finished (?) */
+ NSAutoreleasePool *tpool = [NSAutoreleasePool new];
+
+ if (dowait > 0) { /* Wait for a space key */
+ tot = 24.0 * 60.0 * 60.0;
+ } else if (dowait < 0) {
+ tot = (double)-dowait;
+ } else {
+ tot = 0.1;
+ }
+ to = [NSDate dateWithTimeIntervalSinceNow:tot]; /* autorelease ? */
+ plot_cx->plot_signal = 0;
+ for (;plot_cx->plot_signal == 0;) {
+ /* Hmm. Assume event is autorelease */
+ if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:to inMode:NSDefaultRunLoopMode dequeue:YES]) != nil) {
+ [NSApp sendEvent:event];
+ } else {
+ break;
+ }
+ }
+ [tpool release];
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Cleanup code (not called) */
+
+static void cleanup() {
+ [plot_cx->window release]; /* Take down the plot window */
+ free(plot_cx);
+ plot_cx = NULL;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Utility to draw text in Cocoa with centering */
+/* Size is points */
+/* Flags 0x1 == horizontal center */
+/* Flags 0x2 == vertical center */
+static void ADrawText(NSColor *col, float size, float x, float y, int flags, char *text) {
+ NSFont* font = [NSFont systemFontOfSize:size];
+ NSDictionary *att = [NSDictionary dictionaryWithObjectsAndKeys:
+ font, NSFontAttributeName,
+ col, NSForegroundColorAttributeName,
+ nil];
+ NSString *str = [[NSString alloc] initWithUTF8String: text];
+
+ if (flags != 0x0) {
+ NSSize size;
+
+ /* Figure out how big it will be */
+ size = [str sizeWithAttributes: att ];
+ if (flags & 0x1) {
+ double w = fabs(size.width);
+ x -= 0.5 * w;
+ }
+ if (flags & 0x2) {
+ double h = fabs(size.height);
+ y -= 0.5 * h;
+ }
+ }
+
+ [str drawAtPoint: NSMakePoint(x, y) withAttributes: att];
+ [str release]; /* Others are autorelease */
+}
+
+/* Draw a line */
+/* We re-use the same path so that we can set the dash style */
+static void ADrawLine(NSBezierPath *path, float xs, float ys, float xe, float ye) {
+ [path removeAllPoints ];
+ [path moveToPoint:NSMakePoint(xs, ys)];
+ [path lineToPoint:NSMakePoint(xe, ye)];
+ [path stroke];
+}
+
+/* Draw X axis grid lines */
+void
+xtick(
+plot_info *pdp,
+NSBezierPath *path,
+NSColor *lcol,
+NSColor *tcol,
+double x, char *lab
+) {
+ float xx, yy;
+
+ xx = 20.0 + (x - pdp->mnx) * pdp->scx;
+ yy = 20.0;
+
+ [lcol setStroke]; /* There is a bug in 10.4 which resets this after each stroke */
+ ADrawLine(path, xx, yy, xx, (float)pdp->sh);
+ ADrawText(tcol, 10.0, xx, 5.0, 0x1, lab);
+}
+
+/* Draw Y axis grid lines */
+void
+ytick(
+plot_info *pdp,
+NSBezierPath *path,
+NSColor *lcol,
+NSColor *tcol,
+double y, char *lab
+) {
+ float xx, yy;
+
+ xx = 20.0;
+ yy = 20.0 + (y - pdp->mny) * pdp->scy;
+
+ [lcol setStroke]; /* There is a bug in 10.4 which resets this after each stroke */
+ ADrawLine(path, xx, yy, (float)pdp->sw, yy);
+ ADrawText(tcol, 10.0, 3.0, yy, 0x2, lab);
+}
+
+void
+loose_label(
+plot_info *pdp,
+NSBezierPath *path,
+NSColor *lcol,
+NSColor *tcol,
+double min, double max,
+void (*pfunc)(plot_info *pdp, NSBezierPath *path, NSColor *lcol, NSColor *tcol, double, char *)
+) {
+ char str[6], temp[20];
+ int nfrac;
+ double d;
+ double graphmin, graphmax;
+ double range,x;
+
+ range = nicenum(min-max,0);
+ d = nicenum(range/(NTICK-1),1);
+ graphmin = floor(min/d) * d;
+ graphmax = ceil(max/d) * d;
+ nfrac = (int)MAX(-floor(log10(d)),0);
+ sprintf(str,"%%.%df", nfrac);
+ for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
+ sprintf(temp,str,x);
+ pfunc(pdp, path, lcol, tcol, x, temp);
+ }
+}
+
+/* Called from within view to plot overall graph */
+static void DoPlot(NSRect *rect, plot_info *pdp) {
+ int i, j;
+ int lx,ly; /* Last x,y */
+ CGFloat dash_list[2] = {7.0, 2.0};
+ /* Note path and tcol are autorelease */
+ NSBezierPath *path = [NSBezierPath bezierPath]; /* Path to use */
+ NSColor *lcol = nil;
+ NSColor *tcol = nil;
+
+ /* Setup the plot info structure for this drawing */
+ /* Note port rect is raster like, pdp/Quartz2D is Postscript like */
+ pdp->sx = rect->origin.x;
+ pdp->sy = rect->origin.y;
+ pdp->sw = rect->size.width;
+ pdp->sh = rect->size.height;
+ pdp->scx = (pdp->sw - 20)/(pdp->mxx - pdp->mnx);
+ pdp->scy = (pdp->sh - 20)/(pdp->mxy - pdp->mny);
+
+ /* Plot the axis lines */
+ [path setLineWidth:1.0];
+ [path setLineDash: dash_list count: 2 phase: 0.0 ]; /* Set dashed lines for axes */
+
+ /* Make sure text is black */
+ tcol = [NSColor colorWithCalibratedRed: 0.0
+ green: 0.0
+ blue: 0.0
+ alpha: 1.0];
+
+ lcol = [NSColor colorWithCalibratedRed:0.7 green: 0.7 blue:0.7 alpha: 1.0]; /* Grey */
+
+ /* Plot horizontal axis */
+ if (pdp->revx)
+ loose_label(pdp, path, lcol, tcol, pdp->mxx, pdp->mnx, xtick);
+ else
+ loose_label(pdp, path, lcol, tcol, pdp->mnx, pdp->mxx, xtick);
+
+ /* Plot vertical axis */
+ loose_label(pdp, path, lcol, tcol, pdp->mny, pdp->mxy, ytick);
+
+ /* Set to non-dashed line */
+ [path setLineWidth: LTHICK];
+ [path setLineDash: NULL count: 0 phase: 0.0 ];
+
+ if (pdp->graph) { /* Up to 6 graphs */
+ int gcolors[MXGPHS][3] = {
+ { 0, 0, 0}, /* Black */
+ { 210, 30, 0}, /* Red */
+ { 0, 200, 90}, /* Green */
+ { 0, 10, 255}, /* Blue */
+ { 200, 200, 0}, /* Yellow */
+ { 220, 0, 255}, /* Purple */
+ { 136, 86, 68}, /* Brown */
+ { 248, 95, 0}, /* Orange */
+ { 160, 160, 160}, /* Grey */
+ { 220, 220, 220} /* White */
+ };
+ for (j = MXGPHS-1; j >= 0; j--) {
+ double *yp = pdp->yy[j];
+
+ if (yp == NULL)
+ continue;
+ [[NSColor colorWithCalibratedRed: gcolors[j][0]/255.0
+ green: gcolors[j][1]/255.0
+ blue: gcolors[j][2]/255.0
+ alpha: 1.0] setStroke];
+
+ lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5);
+
+ for (i = 0; i < pdp->n; i++) {
+ int cx,cy;
+ cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5);
+
+ ADrawLine(path, 20.0 + lx, 20.0 + ly, 20 + cx, 20.0 + cy);
+#ifdef CROSSES
+ ADrawLine(path, 20.0 + cx - 5, 20.0 - cy - 5, 20.0 + cx + 5, 20.0 + cy + 5);
+ ADrawLine(path, 20.0 + cx + 5, 20.0 - cy - 5, 20.0 + cx - 5, 20.0 + cy + 5);
+#endif
+ lx = cx;
+ ly = cy;
+ }
+ }
+
+ } else { /* Vectors */
+ [[NSColor colorWithCalibratedRed: 0.0
+ green: 0.0
+ blue: 0.0
+ alpha: 1.0] setStroke];
+ if (pdp->ntext != NULL) {
+ tcol = [NSColor colorWithCalibratedRed: 0.0
+ green: 0.0
+ blue: 0.0
+ alpha: 1.0];
+ }
+ for (i = 0; i < pdp->n; i++) {
+ int cx,cy;
+
+ lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5);
+
+ cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5);
+
+ ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy);
+
+ ADrawLine(path, 20.0 + cx - 5, 20.0 + cy - 5, 20.0 + cx + 5, 20.0 + cy + 5);
+ ADrawLine(path, 20.0 + cx + 5, 20.0 + cy - 5, 20.0 + cx - 5, 20.0 + cy + 5);
+
+ if (pdp->ntext != NULL)
+ ADrawText(tcol, 9.0, 20.0 + cx + 9, 20.0 + cy - 7, 0x1, pdp->ntext[i]);
+ }
+ }
+
+ /* Extra points */
+ if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) {
+ [[NSColor colorWithCalibratedRed: 0.82 /* Orange ? */
+ green: 0.59
+ blue: 0.0
+ alpha: 1.0] setStroke];
+
+ for (i = 0; i < pdp->m; i++) {
+
+ if (pdp->mcols != NULL) {
+ [[NSColor colorWithCalibratedRed: pdp->mcols[i].rgb[0]
+ green: pdp->mcols[i].rgb[1]
+ blue: pdp->mcols[i].rgb[2]
+ alpha: 1.0] setStroke];
+
+ if (pdp->mtext != NULL) {
+ tcol = [NSColor colorWithCalibratedRed: pdp->mcols[i].rgb[0]
+ green: pdp->mcols[i].rgb[1]
+ blue: pdp->mcols[i].rgb[2]
+ alpha: 1.0];
+ }
+ }
+ lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5);
+
+ ADrawLine(path, 20.0 + lx - 5, 20.0 + ly, 20.0 + lx + 5, 20.0 + ly);
+ ADrawLine(path, 20.0 + lx, 20.0 + ly - 5, 20.0 + lx, 20.0 + ly + 5);
+
+ if (pdp->mtext != NULL) {
+ ADrawText(tcol, 9.0, 20.0 + lx + 9, 20.0 + ly + 7, 0x1, pdp->mtext[i]);
+ }
+ }
+ }
+
+ /* Extra vectors */
+ if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) {
+ [[NSColor colorWithCalibratedRed: 0.5 /* Light blue */
+ green: 0.9
+ blue: 0.9
+ alpha: 1.0] setStroke];
+
+ for (i = 0; i < pdp->o; i++) {
+ int cx,cy;
+
+ if (pdp->ocols != NULL) {
+ [[NSColor colorWithCalibratedRed: pdp->ocols[i].rgb[0]
+ green: pdp->ocols[i].rgb[1]
+ blue: pdp->ocols[i].rgb[2]
+ alpha: 1.0] setStroke];
+ if (pdp->mtext != NULL) {
+ tcol = [NSColor colorWithCalibratedRed: pdp->ocols[i].rgb[0]
+ green: pdp->ocols[i].rgb[1]
+ blue: pdp->ocols[i].rgb[2]
+ alpha: 1.0];
+ }
+ }
+ lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5);
+
+ cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5);
+
+ ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy);
+ }
+ }
+}
+
+#else /* Assume UNIX + X11 */
+/* ********************************** X11 version ********************** */
+
+/* !!!! There is a problem if the user closes the window - an X11 error results */
+/* This seems to happen before a DestroyNotify !. How to fix ??? !!!! */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#ifdef DODEBUG
+# define debugf(xx) printf xx
+#else
+# define debugf(xx)
+#endif
+
+void DoPlot(Display *mydisplay, Window mywindow, GC mygc, plot_info *pdp);
+
+/* Superset implementation function: */
+/* return 0 on success, -1 on error */
+/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */
+/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */
+/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */
+/* with annotation ntext at the cross, */
+/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */
+/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */
+/* n = number of points/vectors. -ve for reversed X axis */
+/* m = number of extra points (x2,y3 or x7,y7) */
+static int do_plot_imp(
+ double xmin, double xmax, double ymin, double ymax, /* Bounding box */
+ double ratio, /* Aspect ratio of window, X/Y */
+ int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
+ double *x1, double *x2,
+ double *yy[MXGPHS], char **ntext,
+ int n,
+ double *x7, double *y7, plot_col *mcols, char **mtext,
+ int m,
+ double *x8, double *y8, double *x9, double*y9, plot_col *ocols,
+ int o
+) {
+ {
+ int j;
+ double xr,yr;
+
+ pd.dowait = dowait;
+ pd.ratio = ratio;
+
+ pd.mnx = xmin;
+ pd.mny = ymin;
+ pd.mxx = xmax;
+ pd.mxy = ymax;
+
+ /* Allow some extra arround plot */
+ xr = pd.mxx - pd.mnx;
+ yr = pd.mxy - pd.mny;
+ if (xr < 1e-6)
+ xr = 1e-6;
+ if (yr < 1e-6)
+ yr = 1e-6;
+ pd.mnx -= xr/10.0;
+ pd.mxx += xr/10.0;
+ pd.mny -= yr/10.0;
+ pd.mxy += yr/10.0;
+
+ /* Transfer raw point info */
+ if (x2 == NULL)
+ pd.graph = 1; /* 6 graphs + points */
+ else
+ pd.graph = 0;
+ pd.x1 = x1;
+ pd.x2 = x2;
+ for (j = 0; j < MXGPHS; j++)
+ pd.yy[j] = yy[j];
+ pd.ntext = ntext;
+ pd.n = abs(n);
+
+ if (n < 0) {
+ double tt;
+ tt = pd.mxx;
+ pd.mxx = pd.mnx;
+ pd.mnx = tt;
+ pd.revx = 1;
+ } else {
+ pd.revx = 0;
+ }
+ pd.x7 = x7;
+ pd.y7 = y7;
+ pd.mcols = mcols;
+ pd.mtext = mtext;
+ pd.m = abs(m);
+
+ pd.x8 = x8;
+ pd.y8 = y8;
+ pd.x9 = x9;
+ pd.y9 = y9;
+ pd.ocols = ocols;
+ pd.o = abs(o);
+ }
+
+ {
+ /* stuff for X windows */
+ char plot[] = {"plot"};
+ static Display *mydisplay = NULL;
+ static Window mywindow = -1;
+ int dorefresh = 1;
+ GC mygc;
+ XEvent myevent;
+ XSizeHints myhint;
+ XWindowAttributes mywattributes;
+ int myscreen;
+ unsigned long myforeground,mybackground;
+ int done;
+
+ /* open the display */
+ if (mydisplay == NULL) {
+ mydisplay = XOpenDisplay("");
+ if(!mydisplay)
+ error("Unable to open display");
+ dorefresh = 0;
+ }
+ myscreen = DefaultScreen(mydisplay);
+ mybackground = WhitePixel(mydisplay,myscreen);
+ myforeground = BlackPixel(mydisplay,myscreen);
+
+ myhint.x = 100;
+ myhint.y = 100;
+ myhint.width = (int)(DEFWWIDTH * ratio + 0.5);
+ myhint.height = DEFWHEIGHT;
+ myhint.flags = PPosition | USSize;
+
+ debugf(("Opened display OK\n"));
+
+ if (mywindow == -1) {
+ debugf(("Opening window\n"));
+ mywindow = XCreateSimpleWindow(mydisplay,
+ DefaultRootWindow(mydisplay),
+ myhint.x,myhint.y,myhint.width,myhint.height,
+ 5, myforeground,mybackground);
+ XSetStandardProperties(mydisplay,mywindow,plot,plot,None,
+ NULL,0, &myhint);
+ }
+
+ mygc = XCreateGC(mydisplay,mywindow,0,0);
+ XSetBackground(mydisplay,mygc,mybackground);
+ XSetForeground(mydisplay,mygc,myforeground);
+
+ XSelectInput(mydisplay,mywindow,
+ KeyPressMask | ExposureMask | StructureNotifyMask);
+
+ if (dorefresh) {
+ XExposeEvent ev;
+
+ ev.type = Expose;
+ ev.display = mydisplay;
+ ev.send_event = True;
+ ev.window = mywindow;
+ ev.x = 0;
+ ev.y = 0;
+ ev.width = myhint.width;
+ ev.height = myhint.height;
+ ev.count = 0;
+
+ XClearWindow(mydisplay, mywindow);
+ XSendEvent(mydisplay, mywindow, False, ExposureMask, (XEvent *)&ev);
+
+ } else {
+ XMapRaised(mydisplay,mywindow);
+ debugf(("Raised window\n"));
+ }
+
+ /* Main event loop */
+ debugf(("About to enter main loop\n"));
+ done = 0;
+ while(done == 0) {
+ XNextEvent(mydisplay,&myevent);
+ switch(myevent.type) {
+ case Expose:
+ if(myevent.xexpose.count == 0) { /* Repare the exposed region */
+ XGetWindowAttributes(mydisplay, mywindow, & mywattributes);
+ /* Setup the plot info structure for this drawing */
+ pd.sx = mywattributes.x;
+ pd.sy = mywattributes.y;
+ pd.sw = mywattributes.width;
+ pd.sh = mywattributes.height;
+ pd.scx = (pd.sw - 10)/(pd.mxx - pd.mnx);
+ pd.scy = (pd.sh - 10)/(pd.mxy - pd.mny);
+
+ DoPlot(mydisplay,mywindow, mygc, &pd);
+
+ if (pd.dowait <= 0) { /* Don't wait */
+ if (pd.dowait < 0)
+ sleep(-pd.dowait);
+ debugf(("Not waiting, so set done=1\n"));
+ done = 1;
+ }
+ }
+ break;
+ case MappingNotify:
+ XRefreshKeyboardMapping(&myevent.xmapping);
+ break;
+ case KeyPress:
+ debugf(("Got a button press\n"));
+ done = 1;
+ break;
+ }
+ }
+ debugf(("About to close display\n"));
+ XFreeGC(mydisplay,mygc);
+// XDestroyWindow(mydisplay,mywindow);
+// XCloseDisplay(mydisplay);
+ debugf(("finished\n"));
+ }
+ return 0;
+}
+
+/* Draw X axis grid lines */
+void
+xtick(
+Display *mydisplay,
+Window mywindow,
+GC mygc,
+plot_info *pdp,
+double x, char *lab
+) {
+ int xx,yy;
+
+ xx = 10 + (int)((x - pdp->mnx) * pdp->scx + 0.5);
+ yy = pdp->sh - 10;
+
+ XDrawLine(mydisplay, mywindow, mygc, xx, yy, xx, 0);
+ XDrawImageString(mydisplay, mywindow, mygc, xx-6, yy, lab, strlen(lab));
+}
+
+/* Draw Y axis grid lines */
+void
+ytick(
+Display *mydisplay,
+Window mywindow,
+GC mygc,
+plot_info *pdp,
+double y, char *lab
+) {
+ int xx,yy;
+
+ xx = 5;
+ yy = pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5);
+
+ XDrawLine(mydisplay, mywindow, mygc, xx, yy, pdp->sw, yy);
+ XDrawImageString(mydisplay, mywindow, mygc, xx, yy+4, lab, strlen(lab));
+}
+
+void
+loose_label(
+Display *mydisplay,
+Window mywindow,
+GC mygc,
+plot_info *pdp,
+double min, double max,
+void (*pfunc)(Display *mydisplay, Window mywindow, GC mygc, plot_info *pdp, double, char *)
+) {
+ char str[6], temp[20];
+ int nfrac;
+ double d;
+ double graphmin, graphmax;
+ double range,x;
+
+ range = nicenum(min-max,0);
+ d = nicenum(range/(NTICK-1),1);
+ graphmin = floor(min/d) * d;
+ graphmax = ceil(max/d) * d;
+ nfrac = (int)MAX(-floor(log10(d)),0);
+ sprintf(str,"%%.%df", nfrac);
+ for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
+ sprintf(temp,str,x);
+ pfunc(mydisplay, mywindow, mygc, pdp, x, temp);
+ }
+}
+
+void
+DoPlot(
+Display *mydisplay,
+Window mywindow,
+GC mygc,
+plot_info *pdp
+) {
+ int i, j;
+ int lx,ly; /* Last x,y */
+ char dash_list[2] = {5, 1};
+ Colormap mycmap;
+ XColor col;
+
+ mycmap = DefaultColormap(mydisplay, 0);
+ col.red = col.green = col.blue = 150 * 256;
+ XAllocColor(mydisplay, mycmap, &col);
+ XSetForeground(mydisplay,mygc, col.pixel);
+
+ /* Set dashed lines for axes */
+ XSetLineAttributes(mydisplay, mygc, 1, LineOnOffDash, CapButt, JoinBevel);
+ XSetDashes(mydisplay, mygc, 0, dash_list, 2);
+ // ~~ doesn't seem to work. Why ?
+
+ /* Plot horizontal axis */
+ if (pdp->revx)
+ loose_label(mydisplay, mywindow, mygc, pdp, pdp->mxx, pdp->mnx, xtick);
+ else
+ loose_label(mydisplay, mywindow, mygc, pdp, pdp->mnx, pdp->mxx, xtick);
+
+ /* Plot vertical axis */
+ loose_label(mydisplay, mywindow, mygc, pdp, pdp->mny, pdp->mxy, ytick);
+
+ if (pdp->graph) { /* Up to 10 graphs */
+ for (j = MXGPHS-1; j >= 0; j--) {
+ double *yp = pdp->yy[j];
+
+ if (yp == NULL)
+ continue;
+
+ col.red = gcolors[j][0] * 256;
+ col.green = gcolors[j][1] * 256;
+ col.blue = gcolors[j][2] * 256;
+ XAllocColor(mydisplay, mycmap, &col);
+ XSetForeground(mydisplay,mygc, col.pixel);
+ XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
+
+ lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5);
+
+ for (i = 0; i < pdp->n; i++) {
+ int cx,cy;
+ cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5);
+
+ XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy);
+#ifdef CROSSES
+
+ XDrawLine(mydisplay, mywindow, mygc, 10 + cx - 5, pdp->sh - 10 - cy - 5, 10 + cx + 5, pdp->sh - 10 - cy + 5);
+ XDrawLine(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy - 5, 10 + cx - 5, pdp->sh - 10 - cy + 5);
+#endif
+ lx = cx;
+ ly = cy;
+ }
+ }
+
+ } else { /* Vectors */
+
+ col.red = col.green = col.blue = 0 * 256;
+ XAllocColor(mydisplay, mycmap, &col);
+ XSetForeground(mydisplay,mygc, col.pixel);
+ XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
+
+ for (i = 0; i < pdp->n; i++) {
+ int cx,cy;
+
+ lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5);
+
+ cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5);
+
+ XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy);
+
+ XDrawLine(mydisplay, mywindow, mygc, 10 + cx - 5, pdp->sh - 10 - cy - 5, 10 + cx + 5, pdp->sh - 10 - cy + 5);
+ XDrawLine(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy - 5, 10 + cx - 5, pdp->sh - 10 - cy + 5);
+
+ if (pdp->ntext != NULL)
+ XDrawImageString(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy + 7,
+ pdp->ntext[i], strlen(pdp->ntext[i]));
+ }
+ }
+
+ /* Extra points */
+ if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) {
+ col.red = 210 * 256; col.green = 150 * 256; col.blue = 0 * 256;
+ XAllocColor(mydisplay, mycmap, &col);
+ XSetForeground(mydisplay,mygc, col.pixel);
+ XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
+
+ for (i = 0; i < pdp->m; i++) {
+ lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5);
+
+ if (pdp->mcols != NULL) {
+ col.red = (int)(pdp->mcols[i].rgb[0] * 65535.0 + 0.5);
+ col.green = (int)(pdp->mcols[i].rgb[1] * 65535.0 + 0.5);
+ col.blue = (int)(pdp->mcols[i].rgb[2] * 65535.0 + 0.5);
+
+ XAllocColor(mydisplay, mycmap, &col);
+ XSetForeground(mydisplay,mygc, col.pixel);
+
+ }
+ XDrawLine(mydisplay, mywindow, mygc, 10 + lx - 5, pdp->sh - 10 - ly,
+ 10 + lx + 5, pdp->sh - 10 - ly);
+ XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly - 5,
+ 10 + lx, pdp->sh - 10 - ly + 5);
+
+ if (pdp->mtext != NULL)
+ XDrawImageString(mydisplay, mywindow, mygc, 10 + lx + 5, pdp->sh - 10 - ly - 7,
+ pdp->mtext[i], strlen(pdp->mtext[i]));
+ }
+ }
+
+ /* Extra vectors */
+ if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) {
+ col.red = 150 * 256; col.green = 255 * 256; col.blue = 255 * 256;
+ XAllocColor(mydisplay, mycmap, &col);
+ XSetForeground(mydisplay,mygc, col.pixel);
+ XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
+
+ for (i = 0; i < pdp->o; i++) {
+ int cx,cy;
+
+ lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5);
+ ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5);
+
+ cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5);
+ cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5);
+
+ if (pdp->ocols != NULL) {
+ col.red = (int)(pdp->ocols[i].rgb[0] * 65535.0 + 0.5);
+ col.green = (int)(pdp->ocols[i].rgb[1] * 65535.0 + 0.5);
+ col.blue = (int)(pdp->ocols[i].rgb[2] * 65535.0 + 0.5);
+
+ XAllocColor(mydisplay, mycmap, &col);
+ XSetForeground(mydisplay,mygc, col.pixel);
+
+ }
+
+ XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy);
+ }
+ }
+}
+
+#endif /* UNIX + X11 */
+#endif /* !NT */
+/***********************************************************************/
+
+
+/* Nice graph labeling functions */
+
+#define expt(a,n) pow(a,(double)(n))
+
+double nicenum(double x, int round) {
+ int ex;
+ double f;
+ double nf;
+// printf("nocenum called with %f and %d\n",x,round);
+ if (x < 0.0)
+ x = -x;
+ ex = (int)floor(log10(x));
+// printf("ex = %d\n",ex);
+ f = x/expt(10.0,ex);
+// printf("f = %f\n",f);
+ if (round) {
+ if (f < 1.5) nf = 1.0;
+ else if (f < 3.0) nf = 2.0;
+ else if (f < 7.0) nf = 5.0;
+ else nf = 10.0;
+ } else {
+ if (f < 1.0) nf = 1.0;
+ else if (f < 2.0) nf = 2.0;
+ else if (f < 5.0) nf = 5.0;
+ else nf = 10.0;
+ }
+// printf("nf = %f\n",nf);
+// printf("about to return %f\n",(nf * expt(10.0, ex)));
+ return (nf * expt(10.0, ex));
+}
+
+/* ---------------------------------------------------------------- */
+#ifdef STANDALONE_TEST
+/* test code */
+
+// ~~99
+#define TEST_NON_CONSOLE /* Version that works from command line and GUI */
+// May have to add link flag -Wl,-subsystem,windows
+// since MingW is stupid about noticing WinMain or pragma
+
+//#include <windows.h>
+//#include <stdio.h>
+#include <fcntl.h>
+//#include <io.h>
+
+
+#ifdef NEVER
+/* Append debugging string to log.txt */
+static void dprintf(char *fmt, ...) {
+ FILE *fp = NULL;
+ if ((fp = fopen("log.txt", "a+")) != NULL) {
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(fp, fmt, args);
+ fflush(fp);
+ fclose(fp);
+ va_end(args);
+ }
+}
+#endif // NEVER
+
+#ifdef NEVER /* Other non-working enable console output code */
+{
+ /* This clever code have been found at:
+ Adding Console I/O to a Win32 GUI App
+ Windows Developer Journal, December 1997
+ http://dslweb.nwnexus.com/~ast/dload/guicon.htm
+ Andrew Tucker's Home Page */
+
+ /* This is not so clever, since it doesn't work... */
+
+ // redirect unbuffered STDOUT to the console
+ long lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
+ int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+ FILE *fp = _fdopen(hConHandle, "w");
+ *stdout = *fp;
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ // redirect unbuffered STDIN to the console
+ lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
+ hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+ fp = _fdopen( hConHandle, "r" );
+ *stdin = *fp;
+ setvbuf(stdin, NULL, _IONBF, 0);
+
+ // redirect unbuffered STDERR to the console
+ lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
+ hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
+ fp = _fdopen( hConHandle, "w" );
+ *stderr = *fp;
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+
+}
+#endif // NEVER
+
+#ifdef NEVER
+// ~~~~~~~~~~~~~
+// AllocConsole();
+ {
+ ULONG pbi[6];
+ ULONG ulSize = 0;
+ LONG (WINAPI *NtQueryInformationProcess)(HANDLE ProcessHandle,
+ ULONG ProcessInformationClass,
+ PVOID ProcessInformation,
+ ULONG ProcessInformationLength,
+ PULONG ReturnLength);
+
+ BOOL (WINAPI *AttachConsole)(DWORD dwProcessId);
+
+ *(FARPROC *)&NtQueryInformationProcess =
+ GetProcAddress(LoadLibraryA("NTDLL.DLL"), "NtQueryInformationProcess");
+ if(NtQueryInformationProcess) {
+printf("~1 found NtQueryInformationProcess\n"); fflush(stdout);
+ if(NtQueryInformationProcess(GetCurrentProcess(), 0,
+ &pbi, sizeof(pbi), &ulSize) >= 0 && ulSize == sizeof(pbi)) {
+printf("~1 NtQueryInformationProcess suceeded\n"); fflush(stdout);
+
+ *(FARPROC *)&AttachConsole =
+ GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole");
+
+ if (AttachConsole) {
+printf("~1 found AttachConsole\n"); fflush(stdout);
+ AttachConsole(pbi[5]);
+printf("~1 about to freopen CONNOUT\n"); fflush(stdout);
+ freopen("CONOUT$","wb",stdout);
+ } else {
+printf("~1 failed to find AttachConsole\n"); fflush(stdout);
+ }
+ }
+ }
+ // AttachConsole(ID ATTACH_PARENT_CONSOLE); // Should work on XP ??
+
+ /* i mean OpenConsoleW - you are as picky as i am - its
+ ordinal=519 and it is exported by name; the header(s)
+ do not include it, which tells me there's got to be a
+ reason for that.
+ */
+ }
+// ~~~~~~~~~~~~~
+#endif // NEVER
+
+#if defined(TEST_NON_CONSOLE) && defined(NT)
+# pragma comment( linker, "/subsystem:windows" )
+
+APIENTRY WinMain(
+ HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPSTR lpCmdLine,
+ int nCmdShow
+) {
+ { /* Only works on >= XP though */
+ BOOL (WINAPI *AttachConsole)(DWORD dwProcessId);
+
+ *(FARPROC *)&AttachConsole =
+ GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole");
+
+ if (AttachConsole != NULL && AttachConsole(((DWORD)-1)))
+ {
+ if (_fileno(stdout) < 0)
+ freopen("CONOUT$","wb",stdout);
+ if (_fileno(stderr) < 0)
+ freopen("CONOUT$","wb",stderr);
+ if (_fileno(stdin) < 0)
+ freopen("CONIN$","rb",stdin);
+#ifdef __cplusplus
+ // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
+ std::ios::sync_with_stdio();
+#endif
+ }
+ }
+
+ return main(__argc, __argv);
+}
+#endif /* TEST_NON_CONSOLE && NT */
+
+int main(int argc, char *argv[]) {
+ double x[10] = {0.0, 0.5, 0.7, 1.0};
+ double y1[10] = {0.0, 0.5, 0.7, 1.0};
+ double y2[10] = {0.9, 0.8, 1.4, 1.2};
+ double y3[10] = {0.1, 0.8, 0.7, -0.1};
+
+ double Bx1[10] = {0.0, 0.5, 0.9, 0.5};
+ double By1[10] = {0.0, 0.3, 1.2, 0.2};
+ double Bx2[10] = {0.1, 0.8, 0.1, 0.2};
+ double By2[10] = {0.1, 1.8, 2.0, 0.5};
+
+ double Bx3[10] = {0.8, 0.4, 1.3, 0.5, 0.23};
+ double By3[10] = {0.5, 1.3, 0.4, 0.7, 0.77};
+
+ plot_col mcols[5] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 },
+ { 0.6, 0.6, 0.6 },
+ { 1.0, 1.0, 0.0 } };
+
+ char *ntext[5] = { "A", "B", "C", "D" };
+ char *mtext[5] = { "10", "20", "30", "40", "50" };
+
+ printf("Doing first plot\n");
+ if (do_plot(x,y1,y2,y3,4) < 0)
+ printf("Error - do_plot returned -1!\n");
+
+ /* Try a second plot */
+ printf("Doing second plot\n");
+ x[2] = 0.55;
+ if (do_plot(x,y2,y3,y1,3) < 0)
+ printf("Error - do_plot returned -1!\n");
+
+ /* Try vectors */
+ printf("Doing vector plot\n");
+ if (do_plot_vec(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, 4, 1, Bx3, By3, NULL, NULL, 5))
+ printf("Error - do_plot_vec returned -1!\n");
+
+ printf("Doing vector plot with colors and notation\n");
+ if (do_plot_vec(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, 4, 1, Bx3, By3, mcols, mtext, 5))
+ printf("Error - do_plot_vec returned -1!\n");
+
+ printf("Doing vector plot with colors and notation + extra vectors\n");
+ if (do_plot_vec2(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, ntext, 4, 1, Bx3, By3, mcols, mtext, 5,
+ x,y1,y2,y3,mcols,4))
+ printf("Error - do_plot_vec returned -1!\n");
+
+ printf("We're done\n");
+ return 0;
+}
+
+#endif /* STANDALONE_TEST */
+/* ---------------------------------------------------------------- */
+
diff --git a/plot/plot.h b/plot/plot.h
new file mode 100644
index 0000000..89bf16b
--- /dev/null
+++ b/plot/plot.h
@@ -0,0 +1,94 @@
+
+#ifndef PLOT_H
+
+/*
+ * Simple diagnostic 2d plot function
+ *
+ * Copyright 1998 - 2004 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.
+ */
+
+/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */
+/* Brown = Y7, Orange = Y8, Grey = Y9, White = Y10 */
+
+/* A plot color */
+typedef struct {
+ float rgb[3];
+} plot_col;
+
+/* Plot up to 3 X/Y Graphs. return when the user closes the window */
+/* return 0 on success, -1 on error */
+int do_plot(double *x, double *y1, double *y2, double *y3, int n);
+
+/* Plot up to 3 graphs. */
+/* if dowait > 0, wait for user key */
+/* if dowait < 0, wait for no seconds */
+/* If xmax > xmin, use as x scale, else auto. */
+/* If ymax > ymin, use as y scale, else auto. */
+/* ratio is window X / Y */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int do_plot_x(double *x, double *y1, double *y2, double *y3, int n,
+int dowait, double pxmin, double pxmax, double pymin, double pymax, double ratio);
+
+/* Plot up to 3 graphs + crosses. Wait for key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int do_plot_p(double *x, double *y1, double *y2, double *y3, int n,
+ double *x4, double *y4, int m);
+
+/* Public routines */
+/* Plot up to 6 graphs */
+/* return 0 on success, -1 on error */
+/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */
+int do_plot6(double *x, double *y1, double *y2, double *y3, double *y4, double *y5, double *y6, int n);
+
+/* Plot up to 6 graphs + optional crosses. Wait for a key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int do_plot6p(double *x, double *y1, double *y2, double *y3, double *y4, double *y5, double *y6,
+ int n, double *x7, double *y7, int m);
+
+/* Public routines */
+/* Plot up to 10 graphs */
+/* return 0 on success, -1 on error */
+/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */
+/* Brown = Y7, Orange = Y8, Grey = Y9, White = Y10 */
+/* if dozero flag, make sure y range covers zero */
+int do_plot10(double *x, double *y1, double *y2, double *y3, double *y4, double *y5, double *y6,
+ double *y7, double *y8, double *y9, double *y10,
+ int n, int dozero);
+
+/* Plot up to 10 graphs + optional crosses. Wait for a key */
+/* return 0 on success, -1 on error */
+/* If n is -ve, reverse the X axis */
+int do_plot10p(double *x, double *y1, double *y2, double *y3, double *y4, double *y5, double *y6,
+ double *y7, double *y8, double *y9, double *y10,
+ int n, double *xp, double *yp, int m);
+
+/* Plot a bunch of vectors + points + optional colored points & notation */
+/* return 0 on success, -1 on error */
+/* Vectors are x1, y1 to x2, y2 with 'X' at x2, y3, */
+/* Colored annotated Crosss at x3, y3. */
+int do_plot_vec(double xmin, double xmax, double ymin, double ymax,
+ double *x1, double *y1, double *x2, double *y2, int n,
+ int dowait,
+ double *x3, double *y3, plot_col *mcols, char **mtext, int m);
+
+/* Plot a bunch of vectors + points + optional colored points & notation */
+/* + optional colored vectors */
+/* return 0 on success, -1 on error */
+/* Vectors are x1, y1 to x2, y2 with annotated 'X' at x2, y3, */
+/* Colored annotated Crosss at x3, y3. */
+/* Colored vector from x4, y4 to x5, y5 */
+int do_plot_vec2(double xmin, double xmax, double ymin, double ymax,
+ double *x1, double *y1, double *x2, double *y2, char **ntext, int n,
+ int dowait,
+ double *x3, double *y3, plot_col *mcols, char **mtext, int m,
+ double *x4, double *y4, double *x5, double *y5, plot_col *ocols, int o);
+
+#define PLOT_H
+#endif /* PLOT_H */
diff --git a/plot/vrml.c b/plot/vrml.c
new file mode 100644
index 0000000..5b195c2
--- /dev/null
+++ b/plot/vrml.c
@@ -0,0 +1,928 @@
+
+/*
+ * Simple diagnostic VRML function library for debugging
+ *
+ * Copyright 2005 - 2007 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include "numlib.h"
+#include "icc.h"
+#include "gamut.h"
+#include "vrml.h"
+
+#define MAKE_SOLID
+
+/* Add a shere at the given location. */
+/* if col[] is NULL, use natural color. */
+/* Need to do this before or after start_line_set()/dd_vertex()/make_lines() ! */
+static void add_marker(vrml *s, double pos[3], double col[3], double rad) {
+ double rgb[3];
+
+ if (rad <= 0.0)
+ rad = 1.0;
+
+ if (col == NULL) {
+ if (s->isxyz)
+ s->XYZ2RGB(s, rgb, pos);
+ else
+ s->Lab2RGB(s, rgb, pos);
+ } else {
+ rgb[0] = col[0];
+ rgb[1] = col[1];
+ rgb[2] = col[2];
+ }
+
+ fprintf(s->fp," # Shere\n");
+ fprintf(s->fp," Transform { translation %f %f %f\n", s->scale * pos[1], s->scale * pos[2], s->scale * pos[0] - s->off);
+ fprintf(s->fp," children [\n");
+ fprintf(s->fp," Shape{\n");
+ fprintf(s->fp," geometry Sphere { radius %f}\n", s->scale * rad);
+ fprintf(s->fp," appearance Appearance { material Material ");
+ fprintf(s->fp,"{ diffuseColor %f %f %f} }\n", rgb[0], rgb[1], rgb[2]);
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+}
+
+/* Add a cone marker to the plot. col == NULL for natural color */
+/* Need to do this before or after start_line_set()/dd_vertex()/make_lines() ! */
+static void add_cone(vrml *s, double pp0[3], double pp1[3], double col[3], double rad) {
+ double rgb[3];
+ double p0[3], p1[3];
+
+ icmScale3(p0, pp0, s->scale);
+ icmScale3(p1, pp1, s->scale);
+
+//printf("~1 cone %f %f %f -> %f %f %f rad %f\n", p0[0], p0[1], p0[2], p1[0], p1[1], p1[2], rad);
+
+ if (rad <= 0.0)
+ rad = 1.0;
+
+ if (col == NULL) {
+ icmAdd3(rgb, p1, p0);
+ icmScale3(rgb, rgb, 0.5); /* Compute half way value */
+ if (s->isxyz)
+ s->XYZ2RGB(s, rgb, rgb);
+ else
+ s->Lab2RGB(s, rgb, rgb);
+ } else {
+ rgb[0] = col[0];
+ rgb[1] = col[1];
+ rgb[2] = col[2];
+ }
+
+ p0[0] -= s->off;
+ p1[0] -= s->off;
+
+ {
+ double base[3] = { 0.0, 0.0, 1.0 }; /* Default orientation of cone is b axis */
+ double len;
+ double loc[3];
+ double vec[3];
+ double axis[3]; /* Axis to rotate around */
+ double rot; /* In radians */
+ int j;
+
+//printf("~1 edge vert %d to %d\n",tp->v[0]->n, tp->v[1]->n);
+//printf("~1 edge %f %f %f to %f %f %f\n",
+//tp->v[0]->ch[0], tp->v[0]->ch[1], tp->v[0]->ch[2],
+//tp->v[1]->ch[0], tp->v[1]->ch[1], tp->v[1]->ch[2]);
+
+ icmAdd3(loc, p1, p0);
+ icmScale3(loc, loc, 0.5); /* Compute half way value */
+ icmSub3(vec, p1, p0);
+ len = icmNorm3(vec);
+//printf("~1 loc = %f %f %f\n", loc[0], loc[1], loc[2]);
+//printf("~1 vec = %f %f %f\n", vec[0], vec[1], vec[2]);
+//printf("~1 len = %f\n", len);
+
+ if (len < 0.1)
+ len = 0.1;
+
+ icmNormalize3(base, base, 1.0);
+ icmNormalize3(vec, vec, 1.0);
+ icmCross3(axis, base, vec);
+ rot = icmDot3(base, vec);
+//printf("~1 base = %f %f %f\n", base[0], base[1], base[2]);
+//printf("~1 vec = %f %f %f\n", vec[0], vec[1], vec[2]);
+//printf("~1 axis = %f %f %f, rot = %f\n",axis[0],axis[1],axis[2],rot);
+ if (icmNorm3sq(axis) < 1e-10) { /* 0 or 180 degrees */
+ double base2[3];
+ int mxi = 0;
+//printf("~1 computing a different axis\n");
+ base2[0] = vec[1]; /* Comute vector in a different direction */
+ base2[1] = vec[2];
+ base2[2] = vec[0];
+ for (j = 1; j < 3; j++) {
+ if (fabs(base2[j]) > fabs(base2[mxi]))
+ mxi = j;
+ }
+ base2[mxi] = -base2[mxi];
+
+ icmCross3(axis, base2, vec);
+ if (icmNorm3sq(axis) < 1e-10) { /* 0 or 180 degrees */
+ error("VRML rotate axis still too small");
+ }
+ if (rot < 0.0)
+ rot = 3.1415926;
+ else
+ rot = 0.0;
+ } else {
+ rot = acos(rot);
+//printf("~1 rotation %f\n",rot);
+ }
+
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," # Cone\n");
+ fprintf(s->fp," Transform {\n");
+ fprintf(s->fp," rotation %f %f %f %f\n",axis[1], axis[2], axis[0], rot);
+ fprintf(s->fp," translation %f %f %f\n",loc[1], loc[2], loc[0]);
+ fprintf(s->fp," children [\n");
+ fprintf(s->fp," Shape { \n");
+ fprintf(s->fp," geometry Cone { bottomRadius %f height %f }\n",s->scale * rad,len);
+ fprintf(s->fp," appearance Appearance { material Material { diffuseColor %f %f %f } }\n",rgb[0],rgb[1],rgb[2]);
+ fprintf(s->fp," } \n");
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+ }
+}
+
+/* Add a text marker to the plot. col == NULL for natural color */
+/* (Need to do this before or after start_line_set()/dd_vertex()/make_lines() !) */
+static void add_text(vrml *s, char *text, double p[3], double col[3], double size) {
+ double rgb[3];
+
+ if (size <= 0.0)
+ size = 1.0;
+
+ if (col == NULL) {
+ if (s->isxyz)
+ s->XYZ2RGB(s, rgb, p);
+ else
+ s->Lab2RGB(s, rgb, p);
+ } else {
+ rgb[0] = col[0];
+ rgb[1] = col[1];
+ rgb[2] = col[2];
+ }
+ fprintf(s->fp," # Text\n");
+ fprintf(s->fp," Transform { translation %f %f %f\n", s->scale * p[1], s->scale * p[2], s->scale * p[0] - s->off);
+ fprintf(s->fp," children [\n");
+ fprintf(s->fp," Shape{\n");
+ fprintf(s->fp," geometry Text { string [\"%s\"]\n",text);
+ fprintf(s->fp," fontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n",
+ s->scale * size);
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," appearance Appearance { material Material ");
+ fprintf(s->fp,"{ diffuseColor %f %f %f} }\n", rgb[0], rgb[1], rgb[2]);
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+}
+
+/* Start building up verticies that will be converted to lines */
+/* Set can be from 0 - 9 */
+static void start_line_set(vrml *s, int set) {
+ if (set < 0 || set > 9)
+ error("vrml start_line_set set %d out of range",set);
+ s->set[set].npoints = 0;
+}
+
+/* Add a verticy with color */
+static void add_col_vertex_l(vrml *s, int set, double pos[3], double col[3], int last) {
+
+ if (set < 0 || set > 9)
+ error("vrml start_line_set set %d out of range",set);
+
+ if (s->set[set].npoints >= s->set[set].paloc) {
+ s->set[set].paloc = (s->set[set].paloc + 10) * 2;
+ if (s->set[set].pary == NULL)
+ s->set[set].pary = malloc(s->set[set].paloc * 6 * (sizeof(double) + sizeof(int)));
+ else
+ s->set[set].pary = realloc(s->set[set].pary, s->set[set].paloc * 6 * (sizeof(double) + sizeof(int)));
+
+ if (s->set[set].pary == NULL)
+ error("VRML malloc failed at count %d\n",s->set[set].paloc);
+ }
+ s->set[set].pary[s->set[set].npoints].pp[0] = pos[0];
+ s->set[set].pary[s->set[set].npoints].pp[1] = pos[1];
+ s->set[set].pary[s->set[set].npoints].pp[2] = pos[2];
+ s->set[set].pary[s->set[set].npoints].cc[0] = col[0];
+ s->set[set].pary[s->set[set].npoints].cc[1] = col[1];
+ s->set[set].pary[s->set[set].npoints].cc[2] = col[2];
+ s->set[set].pary[s->set[set].npoints].last = last;
+ s->set[set].npoints++;
+}
+
+/* Add a verticy with color */
+static void add_col_vertex(vrml *s, int set, double pos[3], double col[3]) {
+
+ add_col_vertex_l(s, set, pos, col, 0);
+}
+
+/* Add a color verticy */
+static void add_vertex(vrml *s, int set, double pos[3]) {
+ double col[3] = { -1.0, -1.0, -1.0 };
+
+ add_col_vertex_l(s, set, pos, col, 0);
+}
+
+/* Turn the last added vertex into the last vertex of the line */
+static void make_last_vertex(vrml *s, int set) {
+
+ if (set < 0 || set > 9)
+ error("vrml start_line_set set %d out of range",set);
+
+ if (s->set[set].npoints <= 0)
+ warning("vrml plot: tried to set last point with no points added!\n");
+ else
+ s->set[set].pary[s->set[set].npoints-1].last = 1;
+}
+
+/* Convert the verticies to lines, ppset verticies per line (or .last flag) */
+static void make_lines(vrml *s, int set, int ppset) {
+ int i, j;
+
+ if (set < 0 || set > 9)
+ error("vrml start_line_set set %d out of range",set);
+
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," # Lines\n");
+ fprintf(s->fp," Shape {\n");
+ fprintf(s->fp," geometry IndexedLineSet { \n");
+ fprintf(s->fp," coord Coordinate { \n");
+ fprintf(s->fp," point [\n");
+
+ for (i = 0; i < s->set[set].npoints; i++) {
+ fprintf(s->fp," %f %f %f,\n",
+ s->scale * s->set[set].pary[i].pp[1],
+ s->scale * s->set[set].pary[i].pp[2],
+ s->scale * s->set[set].pary[i].pp[0] - s->off);
+ }
+
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," coordIndex [\n");
+
+ for (i = 0; i < s->set[set].npoints;) {
+ fprintf(s->fp," ");
+ for (j = 0; i < s->set[set].npoints && j < ppset; j++) {
+ fprintf(s->fp,"%d, ", i++);
+ if (s->set[set].pary[i-1].last != 0)
+ break;
+ }
+ fprintf(s->fp,"-1,\n");
+ }
+ fprintf(s->fp," ]\n");
+
+ /* Color */
+ fprintf(s->fp," colorPerVertex TRUE\n");
+ fprintf(s->fp," color Color {\n");
+ fprintf(s->fp," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < s->set[set].npoints; i++) {
+ double rgb[3], Lab[3];
+
+ if (s->set[set].pary[i].cc[0] < 0.0) {
+ Lab[0] = s->set[set].pary[i].pp[0];
+ Lab[1] = s->set[set].pary[i].pp[1];
+ Lab[2] = s->set[set].pary[i].pp[2];
+ if (s->isxyz)
+ s->XYZ2RGB(s, rgb, Lab);
+ else
+ s->Lab2RGB(s, rgb, Lab);
+ fprintf(s->fp," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ } else {
+ fprintf(s->fp," %f %f %f,\n", s->set[set].pary[i].cc[0], s->set[set].pary[i].cc[1], s->set[set].pary[i].cc[2]);
+ }
+ }
+ fprintf(s->fp," ] \n");
+ fprintf(s->fp," }\n");
+ /* End color */
+
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," } # end shape\n");
+}
+
+/* Convert the verticies to triangles */
+static void make_triangles_imp(
+vrml *s,
+int set,
+double trans, /* Transparency level */
+int ixcol, /* NZ for using index color */
+double cc[3] /* Surface color, cc == NULL or cc[0] < 0.0 for natural color */
+) {
+ int i, nverts, ix;
+ int v[3];
+
+ if (set < 0 || set > 9)
+ error("vrml start_line_set set %d out of range",set);
+
+ fprintf(s->fp," # Triangles\n");
+ fprintf(s->fp," Transform {\n");
+ fprintf(s->fp," translation 0 0 0\n");
+ fprintf(s->fp," children [\n");
+ fprintf(s->fp," Shape { \n");
+ fprintf(s->fp," geometry IndexedFaceSet {\n");
+// fprintf(s->fp," ccw FALSE\n");
+ fprintf(s->fp," convex TRUE\n");
+#ifdef MAKE_SOLID
+ fprintf(s->fp," solid FALSE\n"); /* If we want them visible from both sides */
+#endif
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," coord Coordinate { \n");
+ fprintf(s->fp," point [ # Verticy coordinates\n");
+
+ /* Spit out the point values, in order. */
+ /* Note that a->x, b->y, L->z */
+ for (i = 0; i < s->set[set].npoints; i++) {
+ fprintf(s->fp," %f %f %f,\n",
+ s->scale * s->set[set].pary[i].pp[1],
+ s->scale * s->set[set].pary[i].pp[2],
+ s->scale * s->set[set].pary[i].pp[0] - s->off);
+ }
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," coordIndex [ # Indexes of poligon Verticies \n");
+
+ for (i = 0; i < s->ntris; i++) {
+ if (s->tary[i].set == set)
+ fprintf(s->fp," %d, %d, %d, -1\n", s->tary[i].ix[0], s->tary[i].ix[1], s->tary[i].ix[2]);
+ }
+
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," colorPerVertex TRUE\n");
+ fprintf(s->fp," color Color {\n");
+ fprintf(s->fp," color [ # RGB colors of each vertex\n");
+
+ /* Spit out the colors for each vertex */
+ for (i = 0; i < s->set[set].npoints; i++) {
+ double out[3];
+ double rgb[3];
+
+ if (ixcol) {
+ fprintf(s->fp," %f %f %f,\n",s->set[set].pary[i].cc[0], s->set[set].pary[i].cc[1], s->set[set].pary[i].cc[2]);
+ } else {
+ if (cc == NULL || cc[0] < 0.0) {
+ if (s->isxyz)
+ s->XYZ2RGB(s, rgb, s->set[set].pary[i].pp);
+ else
+ s->Lab2RGB(s, rgb, s->set[set].pary[i].pp);
+ fprintf(s->fp," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ } else {
+ fprintf(s->fp," %f %f %f,\n", cc[0], cc[1], cc[2]);
+ }
+ }
+ }
+ fprintf(s->fp," ] \n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," appearance Appearance { \n");
+ fprintf(s->fp," material Material {\n");
+ fprintf(s->fp," transparency %f\n",trans);
+ fprintf(s->fp," ambientIntensity 0.3\n");
+ fprintf(s->fp," shininess 0.5\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," } # end Shape\n");
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+}
+
+/* Convert the verticies to triangles with vertex color */
+static void make_triangles_vc(
+vrml *s,
+int set,
+double trans /* Transparency level */
+) {
+ make_triangles_imp(s, set, trans, 1, NULL);
+}
+
+/* Convert the verticies to triangles with color */
+static void make_triangles(
+vrml *s,
+int set,
+double trans, /* Transparency level */
+double cc[3] /* Surface color, cc == NULL or cc[0] < 0.0 for natural color */
+) {
+ make_triangles_imp(s, set, trans, 0, cc);
+}
+
+/* Add a triangle */
+static void add_triangle(vrml *s, int set, int ix[3]) {
+
+ if (set < 0 || set > 9)
+ error("vrml start_line_set set %d out of range",set);
+
+ if (s->ntris >= s->taloc) {
+ s->taloc = (s->taloc + 10) * 2;
+ if (s->tary == NULL)
+ s->tary = malloc(s->taloc * 4 * sizeof(int));
+ else
+ s->tary = realloc(s->tary, s->taloc * 4 * sizeof(int));
+
+ if (s->tary == NULL)
+ error("VRML malloc failed at count %d\n",s->taloc);
+ }
+ s->tary[s->ntris].set = set;
+ s->tary[s->ntris].ix[0] = ix[0];
+ s->tary[s->ntris].ix[1] = ix[1];
+ s->tary[s->ntris].ix[2] = ix[2];
+ s->ntris++;
+}
+
+/* Create a gamut surface solid or wireframe from the given gamut. */
+/* Use the given transparency level. */
+/* Display in natural colors if c[0] < 0.0, */
+/* or the given color otherwise */
+static void make_gamut_surface_2(
+vrml *s,
+gamut *g,
+double trans, /* Transparency level */
+int wire, /* Z for solid, NZ for wireframe */
+double cc[3] /* Surface color, cc[0] < 0.0 for natural color */
+) {
+ int i, nverts, ix;
+ int v[3];
+
+ nverts = g->nverts(g);
+
+ if (nverts == 0)
+ return;
+
+ fprintf(s->fp," # Gamut surface\n");
+ fprintf(s->fp," Transform {\n");
+ fprintf(s->fp," translation 0 0 0\n");
+ fprintf(s->fp," children [\n");
+ fprintf(s->fp," Shape { \n");
+ if (wire) {
+ fprintf(s->fp," geometry IndexedLineSet {\n");
+ } else {
+ fprintf(s->fp," geometry IndexedFaceSet {\n");
+// fprintf(s->fp," ccw FALSE\n");
+ fprintf(s->fp," convex TRUE\n");
+#ifdef MAKE_SOLID
+ fprintf(s->fp," solid FALSE\n"); /* If we want them visible from both sides */
+#endif
+ }
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," coord Coordinate { \n");
+ fprintf(s->fp," point [ # Verticy coordinates\n");
+
+ /* Spit out the point values, in order. */
+ /* Note that a->x, b->y, L->z */
+ for (ix = i = 0; ix >= 0 && i < nverts; i++) {
+ double out[3];
+
+ ix = g->getvert(g, NULL, out, ix);
+ fprintf(s->fp," %f %f %f,\n",s->scale * out[1], s->scale * out[2], s->scale * out[0] - s->off);
+ }
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," coordIndex [ # Indexes of poligon Verticies \n");
+
+ g->startnexttri(g);
+ while (g->getnexttri(g, v) == 0) {
+ if (wire) {
+ if (v[0] < v[1]) /* Only output 1 wire of two on an edge */
+ fprintf(s->fp," %d, %d, -1\n", v[0], v[1]);
+ if (v[1] < v[2])
+ fprintf(s->fp," %d, %d, -1\n", v[1], v[2]);
+ if (v[2] < v[0])
+ fprintf(s->fp," %d, %d, -1\n", v[2], v[0]);
+ } else {
+ fprintf(s->fp," %d, %d, %d, -1\n", v[0], v[1], v[2]);
+ }
+ }
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," colorPerVertex TRUE\n");
+ fprintf(s->fp," color Color {\n");
+ fprintf(s->fp," color [ # RGB colors of each vertex\n");
+
+ /* Spit out the colors for each vertex */
+ for (ix = i = 0; ix >= 0 && i < nverts; i++) {
+ double out[3];
+ double rgb[3];
+
+ ix = g->getvert(g, NULL, out, ix);
+
+ if (cc == NULL || cc[0] < 0.0) {
+ if (s->isxyz)
+ s->XYZ2RGB(s, rgb, out);
+ else
+ s->Lab2RGB(s, rgb, out);
+ fprintf(s->fp," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ } else {
+ fprintf(s->fp," %f %f %f,\n", cc[0], cc[1], cc[2]);
+ }
+ }
+ fprintf(s->fp," ] \n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," appearance Appearance { \n");
+ fprintf(s->fp," material Material {\n");
+ fprintf(s->fp," transparency %f\n",trans);
+ fprintf(s->fp," ambientIntensity 0.3\n");
+ fprintf(s->fp," shininess 0.5\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," } # end Shape\n");
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+}
+
+/* Create a gamut surface from the given gamut. */
+/* Use the given transparency level. */
+/* Display in natural colors if c[0] < 0.0, */
+/* or the given color otherwise */
+static void make_gamut_surface(
+vrml *s,
+gamut *g,
+double trans, /* Transparency level */
+double cc[3] /* Surface color, cc[0] < 0.0 for natural color */
+) {
+ s->make_gamut_surface_2(s, g, trans, 0, cc);
+}
+
+/* Add cusp markers from a gamut surface */
+/* Use the given transparency level. */
+/* Display in natural colors if c[0] < 0.0, */
+/* or the given color otherwise */
+static void add_cusps(
+vrml *s,
+gamut *g,
+double trans, /* Transparency level */
+double cc[3] /* Surface color, cc[0] < 0.0 for natural color, NULL for default */
+) {
+ double cusps[6][3];
+ double ccolors[6][3] = {
+ { 1.0, 0.1, 0.1 }, /* Red */
+ { 1.0, 1.0, 0.1 }, /* Yellow */
+ { 0.1, 1.0, 0.1 }, /* Green */
+ { 0.1, 1.0, 1.0 }, /* Cyan */
+ { 0.1, 0.1, 1.0 }, /* Blue */
+ { 1.0, 0.1, 1.0 } /* Magenta */
+ };
+ double rgb[3];
+ double *cv = NULL;
+ int i;
+ int v[3];
+
+ if (g->getcusps(g, cusps) != 0)
+ return;
+
+ fprintf(s->fp," # Cusps\n");
+ for (i = 0; i < 6; i++) {
+ if (cc == NULL) {
+ cv = ccolors[i];
+ } else if (cc[0] < 0.0) {
+ if (s->isxyz)
+ s->XYZ2RGB(s, rgb, cusps[i]);
+ else
+ s->Lab2RGB(s, rgb, cusps[i]);
+ cv = rgb;
+ } else {
+ cv = cc;
+ }
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," Transform {\n");
+ fprintf(s->fp," translation %f %f %f\n",s->scale * cusps[i][1], s->scale * cusps[i][2], s->scale * cusps[i][0] - s->off);
+ fprintf(s->fp," children [\n");
+ fprintf(s->fp," Shape { \n");
+ fprintf(s->fp," geometry Sphere { radius 2.0 }\n");
+ fprintf(s->fp," appearance Appearance { \n");
+ fprintf(s->fp," material Material {\n");
+ fprintf(s->fp," transparency %f\n",trans);
+ fprintf(s->fp," ambientIntensity 0.3\n");
+ fprintf(s->fp," shininess 0.5\n");
+ fprintf(s->fp," diffuseColor %f %f %f\n", cv[0],cv[1],cv[2]);
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," } \n");
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+ }
+}
+
+/* Clear verticies and triangles */
+static void clear(vrml *s) {
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ if (s->set[i].pary != NULL)
+ free(s->set[i].pary);
+ s->set[i].pary = NULL;
+ s->set[i].npoints = s->set[i].paloc = 0;
+ }
+ if (s->tary != NULL)
+ free(s->tary);
+ s->tary = NULL;
+ s->ntris = s->taloc = 0;
+}
+
+/* Helper :- convert a Lab value to RGB for display purposes */
+static void Lab2RGB(vrml *s, double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+ double R, G, B;
+
+ /* Scale so that black is visible */
+ L = L * (100 - 40.0)/100.0 + 40.0;
+
+ /* First convert to XYZ using D50 white point */
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ x *= 0.9642; /* Multiply by white point, D50 */
+ y *= 1.0;
+ z *= 0.8249;
+
+ /* Now convert to sRGB values */
+ R = x * 3.2410 + y * -1.5374 + z * -0.4986;
+ G = x * -0.9692 + y * 1.8760 + z * 0.0416;
+ B = x * 0.0556 + y * -0.2040 + z * 1.0570;
+
+ if (R < 0.0)
+ R = 0.0;
+ else if (R > 1.0)
+ R = 1.0;
+
+ if (G < 0.0)
+ G = 0.0;
+ else if (G > 1.0)
+ G = 1.0;
+
+ if (B < 0.0)
+ B = 0.0;
+ else if (B > 1.0)
+ B = 1.0;
+
+ R = pow(R, 1.0/2.2);
+ G = pow(G, 1.0/2.2);
+ B = pow(B, 1.0/2.2);
+
+ /* For a black background: */
+// R = R * 0.85 + 0.15;
+// G = G * 0.85 + 0.15;
+// B = B * 0.85 + 0.15;
+
+ /* For a white background: */
+ R = R * 0.70 + 0.05;
+ G = G * 0.70 + 0.05;
+ B = B * 0.70 + 0.05;
+
+ out[0] = R;
+ out[1] = G;
+ out[2] = B;
+}
+
+/* Helper :- convert an XYZ value to RGB for display purposes */
+static void XYZ2RGB(vrml *s, double *out, double *in) {
+ double x = in[0], y = in[1], z = in[2];
+ double R, G, B;
+
+ /* Now convert to sRGB values */
+ R = x * 3.2410 + y * -1.5374 + z * -0.4986;
+ G = x * -0.9692 + y * 1.8760 + z * 0.0416;
+ B = x * 0.0556 + y * -0.2040 + z * 1.0570;
+
+ if (R < 0.0)
+ R = 0.0;
+ else if (R > 1.0)
+ R = 1.0;
+
+ if (G < 0.0)
+ G = 0.0;
+ else if (G > 1.0)
+ G = 1.0;
+
+ if (B < 0.0)
+ B = 0.0;
+ else if (B > 1.0)
+ B = 1.0;
+
+ R = pow(R, 1.0/2.2);
+ G = pow(G, 1.0/2.2);
+ B = pow(B, 1.0/2.2);
+
+ /* For a black background: */
+// R = R * 0.85 + 0.15;
+// G = G * 0.85 + 0.15;
+// B = B * 0.85 + 0.15;
+
+ /* For a white background: */
+ R = R * 0.70 + 0.05;
+ G = G * 0.70 + 0.05;
+ B = B * 0.70 + 0.05;
+
+ out[0] = R;
+ out[1] = G;
+ out[2] = B;
+}
+
+static void del_vrml(vrml *s);
+
+/* Constructor */
+vrml *new_vrml(
+char *name,
+int doaxes,
+int isxyz
+) {
+ vrml *s;
+
+ int i, j;
+
+ if ((s = (vrml *)calloc(1, sizeof(vrml))) == NULL) {
+ warning("Malloc of vrml plot object failed");
+ return NULL;
+ }
+
+ s->del = del_vrml;
+ s->add_marker = add_marker;
+ s->add_cone = add_cone;
+ s->add_text = add_text;
+ s->start_line_set = start_line_set;
+ s->add_vertex = add_vertex;
+ s->add_col_vertex = add_col_vertex;
+ s->make_last_vertex = make_last_vertex;
+ s->add_triangle = add_triangle;
+ s->make_lines = make_lines;
+ s->make_triangles = make_triangles;
+ s->make_triangles_vc = make_triangles_vc;
+ s->make_gamut_surface = make_gamut_surface;
+ s->make_gamut_surface_2 = make_gamut_surface_2;
+ s->add_cusps = add_cusps;
+ s->clear = clear;
+ s->Lab2RGB = Lab2RGB;
+ s->XYZ2RGB = XYZ2RGB;
+
+ s->isxyz = isxyz;
+
+ if (s->isxyz) {
+ s->scale = 100.0;
+ s->off = 50.0;
+ } else {
+ s->scale = 1.0;
+ s->off = 50.0;
+ }
+
+ if ((s->fp = fopen(name,"w")) == NULL) {
+ warning("Opening of vrml plot file '%s' for write failed",name);
+ free(s);
+ return NULL;
+ }
+
+ fprintf(s->fp,"#VRML V2.0 utf8\n");
+ fprintf(s->fp,"\n");
+ fprintf(s->fp,"# Created by the Argyll CMS\n");
+ fprintf(s->fp,"Transform {\n");
+ fprintf(s->fp," children [\n");
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," NavigationInfo {\n");
+ fprintf(s->fp," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(s->fp," } # We'll add our own light\n");
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," DirectionalLight {\n");
+ fprintf(s->fp," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(s->fp," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," Viewpoint {\n");
+ fprintf(s->fp," position 0 0 340 # Position we view from\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp,"\n");
+ if (doaxes != 0) {
+ /* Axes definition */
+ struct {
+ char *label;
+ double x, y, z; /* == a,b,L or Y,Z,X */
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[2][6] = {
+ { /* Box coords are center and size: */
+ { "L", 0, 0, 50, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { "+a", 50, 0, 0, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { "-b", 0, -50, 0, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { "-a", -50, 0, 0, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { "+b", 0, 50, 0, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ { NULL },
+ }, {
+ { "X", 0, 0, 50, 2, 2, 100, .7, .7, .7 }, /* X axis */
+ { "Y", 50, 0, 0, 100, 2, 2, 1, 0, 0 }, /* Y (red) axis */
+ { "Z", 0, 50, 0, 2, 100, 2, 0, 0, 1 }, /* Z (blue) axis */
+ { NULL },
+ }
+ };
+
+ if (s->isxyz) {
+ j = 1;
+ fprintf(s->fp," # XYZ axes as boxes:\n");
+ } else {
+ j = 0;
+ fprintf(s->fp," # Lab axes as boxes:\n");
+ }
+ for (i = 0; ; i++) {
+ double toff[3] = { -3.0, -2.0, 0 };
+
+ if (axes[j][i].label == NULL)
+ break;
+
+ fprintf(s->fp," Transform { translation %f %f %f\n", axes[j][i].x, axes[j][i].y, axes[j][i].z - s->off);
+ fprintf(s->fp," children [\n");
+ fprintf(s->fp," Shape {\n");
+ fprintf(s->fp," geometry Box { size %f %f %f }\n",
+ axes[j][i].wx, axes[j][i].wy, axes[j][i].wz);
+ fprintf(s->fp," appearance Appearance {");
+ fprintf(s->fp," material Material { diffuseColor %f %f %f }\n", axes[j][i].r, axes[0][i].g, axes[0][i].b);
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," }\n");
+ fprintf(s->fp," ]\n");
+ fprintf(s->fp," }\n");
+
+ if (fabs(axes[j][i].x) > fabs(axes[j][i].y) && fabs(axes[j][i].x) > fabs(axes[j][i].z)) {
+ if (axes[j][i].x > 0.0)
+ toff[0] += axes[j][i].x + 0.5 * axes[j][i].wx + 5.0;
+ else
+ toff[0] += axes[j][i].x - 0.5 * axes[j][i].wx - 5.0;
+ } else if (fabs(axes[j][i].y) > fabs(axes[j][i].x) && fabs(axes[j][i].y) > fabs(axes[j][i].z)) {
+ if (axes[j][i].y > 0.0)
+ toff[1] += axes[j][i].y + 0.5 * axes[j][i].wy + 5.0;
+ else
+ toff[1] += axes[j][i].y - 0.5 * axes[j][i].wy - 5.0;
+ } else {
+ if (axes[j][i].z > 0.0)
+ toff[2] += axes[j][i].z + 0.5 * axes[j][i].wz + 5.0;
+ else
+ toff[2] += axes[j][i].z - 0.5 * axes[j][i].wz - 5.0;
+ }
+
+ fprintf(s->fp,"Transform { translation %f %f %f\n", toff[0], toff[1], toff[2] - s->off);
+ fprintf(s->fp,"\tchildren [\n");
+ fprintf(s->fp,"\t\tShape {\n");
+ fprintf(s->fp,"\t\t\tgeometry Text { string [\"%s\"]\n",axes[j][i].label);
+ fprintf(s->fp,"\t\t\t\tfontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n",
+ 10.0);
+ fprintf(s->fp,"\t\t\t\t}\n");
+ fprintf(s->fp,"\t\t\tappearance Appearance { material Material ");
+ fprintf(s->fp,"{ diffuseColor %f %f %f} }\n", axes[j][i].r, axes[j][i].g, axes[j][i].b);
+ fprintf(s->fp,"\t\t}\n");
+ fprintf(s->fp,"\t]\n");
+ fprintf(s->fp,"}\n");
+ }
+ fprintf(s->fp,"\n");
+ }
+
+ return s;
+}
+
+/* Finish writing the file and free ourselves */
+static void del_vrml(vrml *s) {
+ int i;
+
+ fprintf(s->fp,"\n");
+ fprintf(s->fp," ] # end of children for world\n");
+ fprintf(s->fp,"}\n");
+
+ fflush(s->fp);
+ if (fclose(s->fp) != 0)
+ error("VRML: Error closing VRML file\n");
+
+ for (i = 0; i < 10; i++) {
+ if (s->set[i].pary)
+ free(s->set[i].pary);
+ }
+ if (s->tary)
+ free(s->tary);
+ free(s);
+}
+
diff --git a/plot/vrml.h b/plot/vrml.h
new file mode 100644
index 0000000..e3991c5
--- /dev/null
+++ b/plot/vrml.h
@@ -0,0 +1,113 @@
+
+#ifndef VRML_H
+
+/*
+ * Simple diagnostic VRML function library for debugging
+ *
+ * Copyright 2005 - 2007 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.
+ */
+
+struct _vrml {
+
+/* Private: */
+ FILE *fp;
+
+ int isxyz; /* nz if XYZ plot, (range 0..1) */
+ double scale; /* Scale factor to use (applied before off) */
+ double off; /* Gamut L center, usually 50, to put 50 at center of view */
+
+ /* Expandable point arrays */
+ struct {
+ int npoints;
+ int paloc;
+ struct {
+ double pp[3]; /* Vertex position */
+ double cc[3]; /* Vertex color */
+ int last; /* Last vertex of line flag */
+ } *pary;
+ } set[10]; /* Ten sets */
+
+ /* Expandable triangle vertex index */
+ int ntris;
+ int taloc;
+ struct { int set; int ix[3]; } *tary;
+
+/* Public: */
+
+ /* Methods */
+
+ /* Finish writing the file and free ourselves */
+ void (*del)(struct _vrml *s);
+
+ /* Add a spherical marker point to the plot. col == NULL for natural color */
+ /* (Need to do this before or after start_line_set()/dd_vertex()/make_lines() !) */
+ void (*add_marker)(struct _vrml *s, double pos[3], double col[3], double rad);
+
+ /* Add a cone marker to the plot. col == NULL for natural color */
+ /* (Need to do this before or after start_line_set()/dd_vertex()/make_lines() !) */
+ void (*add_cone)(struct _vrml *s, double p0[3], double p1[3], double col[3], double rad);
+
+ /* Add a text marker to the plot. col == NULL for natural color */
+ /* (Need to do this before or after start_line_set()/dd_vertex()/make_lines() !) */
+ void (*add_text)(struct _vrml *s, char *text, double p[3], double col[3], double size);
+
+
+ /* Start building up verticies that will be converted to lines */
+ /* Set can be from 0 - 9 */
+ void (*start_line_set)(struct _vrml *s, int set);
+
+ /* Add a verticy (color automatic from Lab position) */
+ void (*add_vertex)(struct _vrml *s, int set, double pos[3]);
+
+ /* Add a verticy with color */
+ void (*add_col_vertex)(struct _vrml *s, int set, double pos[3], double col[3]);
+
+ /* Turn the last added vertex into the last vertex of the line */
+ void (*make_last_vertex)(struct _vrml *s, int set);
+
+ /* Convert the verticies to lines, ppset verticies per line (or using .last flag) */
+ /* Use large ppset for just .last flag */
+ void (*make_lines)(struct _vrml *s, int set, int ppset);
+
+ /* Add a triangles vertexes defined by vertex index */
+ void (*add_triangle)(struct _vrml *s, int set, int ix[3]);
+
+ /* Convert the triangle vertexes to triangles with overall color */
+ void (*make_triangles)(struct _vrml *s, int set, double trans, double col[3]);
+
+ /* Convert the triangle vertexes to triangles using vertex colors */
+ void (*make_triangles_vc)(struct _vrml *s, int set, double trans);
+
+ /* Clear verticies and triangles */
+ void (*clear)(struct _vrml *s);
+
+ /* Helper :- convert a Lab value to RGB */
+ void (*Lab2RGB)(struct _vrml *s, double *out, double *in);
+
+ /* Helper :- convert a XYZ value to RGB */
+ void (*XYZ2RGB)(struct _vrml *s, double *out, double *in);
+
+#ifdef GAMUT_H /* If gamut.h is #included ahead of us */
+ /* Create a solid gamut surface from the given gamut */
+ /* trans is trasparency, cc is surface color, cc[0] < 0.0 for natural */
+ void (*make_gamut_surface)(struct _vrml *s, gamut *g, double trans, double cc[3]);
+
+ /* Create a solid or wireframe gamut surface from the given gamut */
+ /* trans is trasparency, cc is surface color, cc[0] < 0.0 for natural */
+ void (*make_gamut_surface_2)(struct _vrml *s, gamut *g, double trans, int wire, double cc[3]);
+
+ /* Add cusp markers from the gamut surface */
+ void (*add_cusps)(struct _vrml *s, gamut *g, double trans, double cc[3]);
+#endif /* GAMUT_H */
+
+}; typedef struct _vrml vrml;
+
+/* Constructor. */
+vrml *new_vrml(char *name, int doaxes, int isxyz);
+
+#define VRML_H
+#endif /* VRML_H */
diff --git a/profile/3dap5k.sp b/profile/3dap5k.sp
new file mode 100644
index 0000000..cfbc67d
--- /dev/null
+++ b/profile/3dap5k.sp
@@ -0,0 +1,103 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for 3DAP viewing booth at D50 - Foam reflector, extendedto 355nm by estimate of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Tue Apr 9 17:15:32 2002"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "355.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "3945.000"
+
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+NUMBER_OF_FIELDS 80
+BEGIN_DATA_FORMAT
+SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 44.97 103.94 164.9 200.88 269.8301111 310.0680556 414.1321667 586.6544444 1066.693611 1133.624333 1031.633944 972.29 1043.722333 1360.529389 2417.268111 3132.216667 2818.478056 2192.068111 1957.285667 2012.437833 2086.816 2149.097611 2205.945556 2264.570111 2339.1085 2399.303778 2451.353278 2494.1235 2516.631 2534.502167 2543.351444 2565.551778 2603.578944 2647.086278 2702.404611 3045.447667 3626.533111 3944.484778 3524.838667 3082.760333 2947.282889 2987.046333 3115.224611 3264.204778 3254.242611 3106.393611 3101.613167 3069.166278 3050.570056 3084.844278 3103.531722 3083.711278 3053.589722 3031.742722 2965.037333 2901.627444 2814.946667 2731.505611 2628.440667 2523.334611 2418.187556 2309.318778 2191.377056 2074.207278 1952.003389 1830.847556 1709.364111 1586.339889 1466.436333 1359.227167 1251.518111 1158.713556 1056.849167 982.2127778 900.2322778 833.9932222 763.601 692.7145556 643.0055556
+END_DATA
diff --git a/profile/CIE_C.sp b/profile/CIE_C.sp
new file mode 100644
index 0000000..8b771fe
--- /dev/null
+++ b/profile/CIE_C.sp
@@ -0,0 +1,118 @@
+SPECT
+
+DESCRIPTOR "Argyll CIE illuminant C spectral power"
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Thu Dec 02 23:05:57 2009"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "93"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "320.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "780.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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 93
+BEGIN_DATA_FORMAT
+SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+0.01 0.20 0.40 1.55 2.70 4.85 7.00 9.95 12.90 17.20 21.40 27.50 33.00 39.92 47.40 55.17 63.30 71.81 80.60 89.53 98.10 105.80 112.40 117.75 121.50 123.45 124.00 123.60 123.10 123.30 123.80 124.09 123.90 122.92 120.70 116.90 112.10 106.98 102.30 98.81 96.90 96.78 98.00 99.94 102.10 103.95 105.20 105.67 105.30 104.11 102.30 100.15 97.80 95.43 93.20 91.22 89.70 88.83 88.40 88.19 88.10 88.06 88.00 87.86 87.80 87.99 88.20 88.20 87.90 87.22 86.30 85.30 84.00 82.21 80.20 78.24 76.30 74.36 72.40 70.40 68.30 66.30 64.40 62.80 61.50 60.20 59.20 58.50 58.10 58.00 58.20 58.50 59.10
+END_DATA
diff --git a/profile/D50_0.0.sp b/profile/D50_0.0.sp
new file mode 100644
index 0000000..8904fca
--- /dev/null
+++ b/profile/D50_0.0.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 0% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 25.0 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_0.1.sp b/profile/D50_0.1.sp
new file mode 100644
index 0000000..ad747fb
--- /dev/null
+++ b/profile/D50_0.1.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 0% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.45 5.44 11.95 23.75 39.45 47.62 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_0.3.sp b/profile/D50_0.3.sp
new file mode 100644
index 0000000..1a64a27
--- /dev/null
+++ b/profile/D50_0.3.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 30% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.01 0.31 0.62 1.47 2.33 3.38 4.43 4.91 5.39 5.84 6.3 6.74 7.18 7.64 8.09 7.72 9.06 11.96 17.32 28.5 42.41 49.21 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_0.5.sp b/profile/D50_0.5.sp
new file mode 100644
index 0000000..367d0d3
--- /dev/null
+++ b/profile/D50_0.5.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 50% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.01 0.52 1.03 2.46 3.89 5.63 7.38 8.18 8.98 9.74 10.51 11.24 11.97 12.73 13.48 12.86 13.47 16.31 20.91 31.67 44.38 50.26 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_0.7.sp b/profile/D50_0.7.sp
new file mode 100644
index 0000000..2e0b2e8
--- /dev/null
+++ b/profile/D50_0.7.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 70% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.01 0.72 1.44 3.44 5.45 7.88 10.33 11.45 12.57 13.64 14.71 15.74 16.76 17.82 18.87 18 17.88 20.66 24.49 34.84 46.35 51.32 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_1.0.sp b/profile/D50_1.0.sp
new file mode 100644
index 0000000..d74e76a
--- /dev/null
+++ b/profile/D50_1.0.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, Standard U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.020000 1.0300 2.0500 4.9100 7.7800 11.260 14.750 16.350 17.950 19.480 21.010 22.480 23.940 25.450 26.960 25.720 24.490 27.180 29.870 39.590 49.310 52.910 56.510 58.270 60.030 58.930 57.820 66.320 74.820 81.040 87.250 88.930 90.610 90.990 91.370 93.240 95.110 93.540 91.960 93.840 95.720 96.170 96.610 96.870 97.130 99.610 102.10 101.43 100.75 101.54 102.32 101.16 100.00 98.870 97.740 98.330 98.920 96.210 93.500 95.590 97.690 98.480 99.270 99.160 99.040 97.380 95.720 97.290 98.860 97.260 95.670 96.930 98.190 100.60 103.00 101.07 99.130 93.260 87.380 89.490 91.600 92.250 92.890 84.870 76.850 81.680 86.510 89.550 92.580 85.400 78.230 67.960 57.690 70.310 82.920 80.600 78.270 78.910 79.550 76.480 73.400 68.660 63.920 67.350 70.780 72.610 74.440
+END_DATA
diff --git a/profile/D50_1.2.sp b/profile/D50_1.2.sp
new file mode 100644
index 0000000..180d650
--- /dev/null
+++ b/profile/D50_1.2.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 120% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.02 1.24 2.46 5.89 9.34 13.51 17.7 19.62 21.54 23.38 25.21 26.98 28.73 30.54 32.35 30.86 28.9 31.53 33.45 42.76 51.28 53.97 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_1.5.sp b/profile/D50_1.5.sp
new file mode 100644
index 0000000..786e292
--- /dev/null
+++ b/profile/D50_1.5.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 150% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.03 1.55 3.08 7.37 11.67 16.89 22.13 24.53 26.93 29.22 31.52 33.72 35.91 38.18 40.44 38.58 35.51 38.05 38.83 47.51 54.24 55.56 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_1.7.sp b/profile/D50_1.7.sp
new file mode 100644
index 0000000..ba8dc6b
--- /dev/null
+++ b/profile/D50_1.7.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 170% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.03 1.75 3.49 8.35 13.23 19.14 25.08 27.8 30.52 33.12 35.72 38.22 40.7 43.27 45.83 43.72 39.92 42.4 42.42 50.68 56.21 56.61 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_2.0.sp b/profile/D50_2.0.sp
new file mode 100644
index 0000000..efa0214
--- /dev/null
+++ b/profile/D50_2.0.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 200% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.04 2.06 4.1 9.82 15.56 22.52 29.5 32.7 35.9 38.96 42.02 44.96 47.88 50.9 53.92 51.44 46.53 48.92 47.79 55.43 59.17 58.2 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_2.5.sp b/profile/D50_2.5.sp
new file mode 100644
index 0000000..8057f14
--- /dev/null
+++ b/profile/D50_2.5.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 250% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.05 2.58 5.13 12.28 19.45 28.15 36.88 40.88 44.88 48.7 52.53 56.2 59.85 63.63 67.4 64.3 57.55 59.8 56.75 63.34 64.1 60.85 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/D50_3.0.sp b/profile/D50_3.0.sp
new file mode 100644
index 0000000..e68d891
--- /dev/null
+++ b/profile/D50_3.0.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 300% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.06 3.09 6.15 14.73 23.34 33.78 44.25 49.05 53.85 58.44 63.03 67.44 71.82 76.35 80.88 77.16 68.57 70.67 65.71 71.26 69.03 63.49 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/profile/GTIPlus.sp b/profile/GTIPlus.sp
new file mode 100644
index 0000000..4c4c164
--- /dev/null
+++ b/profile/GTIPlus.sp
@@ -0,0 +1,64 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for GTI D50 viewer - extended to 350nm with high estimation of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Thu May 20 15:12:32 2004"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "340.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "50.000"
+
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_380"
+KEYWORD "SPEC_390"
+KEYWORD "SPEC_400"
+KEYWORD "SPEC_410"
+KEYWORD "SPEC_420"
+KEYWORD "SPEC_430"
+KEYWORD "SPEC_440"
+KEYWORD "SPEC_450"
+KEYWORD "SPEC_460"
+KEYWORD "SPEC_470"
+KEYWORD "SPEC_480"
+KEYWORD "SPEC_490"
+KEYWORD "SPEC_500"
+KEYWORD "SPEC_510"
+KEYWORD "SPEC_520"
+KEYWORD "SPEC_530"
+KEYWORD "SPEC_540"
+KEYWORD "SPEC_550"
+KEYWORD "SPEC_560"
+KEYWORD "SPEC_570"
+KEYWORD "SPEC_580"
+KEYWORD "SPEC_590"
+KEYWORD "SPEC_600"
+KEYWORD "SPEC_610"
+KEYWORD "SPEC_620"
+KEYWORD "SPEC_630"
+KEYWORD "SPEC_640"
+KEYWORD "SPEC_650"
+KEYWORD "SPEC_660"
+KEYWORD "SPEC_670"
+KEYWORD "SPEC_680"
+KEYWORD "SPEC_690"
+KEYWORD "SPEC_700"
+KEYWORD "SPEC_710"
+KEYWORD "SPEC_720"
+KEYWORD "SPEC_730"
+NUMBER_OF_FIELDS 40
+BEGIN_DATA_FORMAT
+SPEC_340 SPEC_350 SPEC_360 SPEC_370 SPEC_380 SPEC_390 SPEC_400 SPEC_410 SPEC_420 SPEC_430 SPEC_440 SPEC_450 SPEC_460 SPEC_470 SPEC_480 SPEC_490 SPEC_500 SPEC_510 SPEC_520 SPEC_530 SPEC_540 SPEC_550 SPEC_560 SPEC_570 SPEC_580 SPEC_590 SPEC_600 SPEC_610 SPEC_620 SPEC_630 SPEC_640 SPEC_650 SPEC_660 SPEC_670 SPEC_680 SPEC_690 SPEC_700 SPEC_710 SPEC_720 SPEC_730
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+5.0 7.0 7.0 6.0 3.257189 6.165859 19.269892 21.802994 16.533678 39.975159 57.056049 30.274649 30.155033 32.977394 35.03986 36.617123 37.617252 38.191128 38.476234 39.155827 51.626312 62.044827 42.804649 43.08567 48.201847 44.268539 43.22028 43.416119 42.784763 41.291107 39.292709 36.579609 33.26786 29.675453 26.125034 22.980124 19.86338 16.922205 13.994864 11.727232
+END_DATA
+
diff --git a/profile/Jamfile b/profile/Jamfile
new file mode 100644
index 0000000..780f9a5
--- /dev/null
+++ b/profile/Jamfile
@@ -0,0 +1,104 @@
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ;
+
+#Products
+Libraries = libprof ;
+Executables = cb2ti3 kodak2ti3 txt2ti3 splitti3 mppcheck mppprof
+ profcheck invprofcheck verify 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 ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+InstallFile $(DESTDIR)$(PREFIX)/$(REFSUBDIR) : $(Samples) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+HDRS = ../h ../icc ../cgats ../rspl
+ ../numlib ../gamut ../xicc ../spectro
+ ../target ../plot ;
+
+# PROF library
+Library libprof : profin.c profout.c ;
+
+
+LINKLIBS = ../rspl/librspl ../icc/libicc ../cgats/libcgats ../numlib/libnum ../plot/libplot
+ ../plot/libvrml ;
+
+# Simple profile generator
+Main simpprof : simpprof.c ;
+
+#Kodak raw profile data to Argyll CGATS format converter
+Main kodak2ti3 : kodak2ti3.c ;
+
+#Colorblind raw profile data to Argyll CGATS format converter
+Main cb2ti3 : cb2ti3.c ;
+
+# the gcc linker is retarded, and can't link to things it's gone past, hence 2 x libxicc...
+LINKLIBS = ../xicc/libxicc ../spectro/libinsttypes ../xicc/libxicc ../gamut/libgamut $(LINKLIBS) ;
+
+#Gretag/Logo raw CMYK profile data to Argyll CGATS format converter
+Main txt2ti3 : txt2ti3.c ;
+
+#Split a .ti3 into two pieces randomly
+Main splitti3 : splitti3.c ;
+
+# Profile checker
+Main profcheck : profcheck.c ;
+
+# Reverse Profile checker
+Main invprofcheck : invprofcheck.c ;
+
+# Model Printer Profile generator
+Main mppprof : mppprof.c ;
+
+# Model Printer Profile checker
+Main mppcheck : mppcheck.c ;
+
+LINKLIBS = ../plot/libvrml $(LINKLIBS) ;
+
+# Verifyer
+Main verify : verify.c ;
+
+LINKLIBS = libprof ../gamut/libgammap $(LINKLIBS) $(TIFFLIB) $(JPEGLIB) ;
+
+# Full profile generator
+Main colprof : colprof.c : : : $(TIFFINC) $(JPEGINC) ;
+
+# Print calibration
+Main printcal : printcal.c : : : $(TIFFINC) $(JPEGINC) ;
+
+# Applying calibration
+Main applycal : applycal.c ;
+
+# Optimised Separation Generator
+#Main sepgen : sepgen.c ;
+
+# Test code
+if $(HOME) = "d:\\usr\\graeme" && $(PWD) = "/src/argyll/profile" {
+ Main specinpprof : specinpprof.c ;
+}
+
+# Development code
+if [ GLOB . : retargti3.c ] {
+ Main retargti3 : retargti3.c ;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/profile/License.txt b/profile/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/profile/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/profile/Makefile.am b/profile/Makefile.am
new file mode 100644
index 0000000..4b60046
--- /dev/null
+++ b/profile/Makefile.am
@@ -0,0 +1,27 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libprof.la
+privatelibdir = $(pkglibdir)
+
+libprof_la_SOURCES = prof.h profin.c profout.c
+libprof_la_LIBADD = ../gamut/libgammap.la $(ICC_LIBS) \
+ ../gamut/libgamut.la ../xicc/libxicc.la \
+ ../numlib/libargyllnum.la ../spectro/libinsttypes.la \
+ ../xicc/libxutils.la ../libargyll.la
+
+LDADD = ./libprof.la ../xicc/libxutils.la ../spectro/libinst.la \
+ ../xicc/libxicc.la ../spectro/libinsttypes.la \
+ ../gamut/libgamut.la ../gamut/libgammap.la ../plot/libvrml.la \
+ ../plot/libplot.la ../rspl/librspl.la \
+ ../numlib/libargyllnum.la $(ICC_LIBS) ../cgats/libcgats.la \
+ ../libargyll.la $(TIFF_LIBS) ../spectro/libconv.la
+
+bin_PROGRAMS = simpprof kodak2ti3 cb2ti3 txt2ti3 splitti3 \
+ profcheck invprofcheck mppprof mppcheck verify colprof printcal \
+ applycal
+
+refdir = $(datadir)/color/argyll/ref
+
+ref_DATA = $(wildcard *.sp)
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/profile/Office.sp b/profile/Office.sp
new file mode 100644
index 0000000..290d310
--- /dev/null
+++ b/profile/Office.sp
@@ -0,0 +1,103 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for Typical Office lighting (Ref), extended to 355nm by estimate of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Wed Sep 12 15:12:32 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "380.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000"
+
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+NUMBER_OF_FIELDS 80
+BEGIN_DATA_FORMAT
+SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 3.0 5.0 6.0 8.0 9.4368 10.6036 13.842 20.7332 34.842 32.098 26.2668 24.5324 24.5532 33.8892 67.0204 82.9432 65.6956 48.8256 39.5772 38.0888 37.9392 37.624 37.78 37.4864 37.5828 37.4708 37.6088 37.4588 37.4644 37.622 38.0968 39.4056 41.7988 45.5484 50.8436 69.6052 106.3616 130.678 114.7876 97.5064 99.306 107.0748 117.8096 127.0744 126.3964 116.4272 111.9564 106.0416 99.828 93.2196 85.5196 77.282 69.6072 62.604 55.1144 48.3624 42.4144 37.872 33.3228 29.2668 25.792 23.0656 19.8412 17.7056 15.4692 13.7852 12.314 10.8312 9.4588 8.542 7.4892 6.912 5.8156 5.7536 5.3348 5.1076 4.636 4.0384 4.1468
+END_DATA
diff --git a/profile/Readme.txt b/profile/Readme.txt
new file mode 100644
index 0000000..5fc569a
--- /dev/null
+++ b/profile/Readme.txt
@@ -0,0 +1,3 @@
+
+This directory has the source code ICC profile creation.
+
diff --git a/profile/Trulux.sp b/profile/Trulux.sp
new file mode 100644
index 0000000..fc5bb0f
--- /dev/null
+++ b/profile/Trulux.sp
@@ -0,0 +1,103 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for Trulux D50 viewer - Foam reflector, extended to 355nm with estimation of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Fri Oct 5 15:12:32 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "380.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000"
+
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+NUMBER_OF_FIELDS 80
+BEGIN_DATA_FORMAT
+SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 0.685175 1.37035 2.255525 3.0407 4.11105 4.09644 5.01837 7.36485 11.98614 11.19519 7.11198 3.33963 6.44973 21.99549 67.47228 93.88269 79.77081 64.85577 57.85737 65.37378 75.29142 82.82394 87.81939 90.44277 92.28321 93.10557 93.11004 92.17122 89.96841 87.65004 84.8304 82.13712 77.75847 74.04651 74.87289 91.45155 123.67365 139.4193 115.8867 87.2391 79.06761 81.88944 91.58172 101.15043 102.11544 94.71408 93.87819 94.00419 95.28195 97.80723 99.53307 99.40416 98.43141 97.50237 95.58378 93.41358 91.00236 88.69698 85.72017 83.18451 80.22261 77.45886 73.79589 70.02708 66.29484 62.08128 57.95706 53.89545 49.70493 45.99504 42.19815 38.68413 35.16609 32.78418 30.1482 27.3201 24.13857 21.88494 20.10168
+END_DATA
diff --git a/profile/TruluxPlus.sp b/profile/TruluxPlus.sp
new file mode 100644
index 0000000..0fd9c39
--- /dev/null
+++ b/profile/TruluxPlus.sp
@@ -0,0 +1,103 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for Trulux D50 viewer - Foam reflector, extended to 355nm with larger estimation of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Fri Oct 5 15:12:32 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "355.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000"
+
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+NUMBER_OF_FIELDS 80
+BEGIN_DATA_FORMAT
+SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+10.0 10.0 10.0 10.0 10.0407 6.11105 5.09644 5.01837 7.36485 11.98614 11.19519 7.11198 3.33963 6.44973 21.99549 67.47228 93.88269 79.77081 64.85577 57.85737 65.37378 75.29142 82.82394 87.81939 90.44277 92.28321 93.10557 93.11004 92.17122 89.96841 87.65004 84.8304 82.13712 77.75847 74.04651 74.87289 91.45155 123.67365 139.4193 115.8867 87.2391 79.06761 81.88944 91.58172 101.15043 102.11544 94.71408 93.87819 94.00419 95.28195 97.80723 99.53307 99.40416 98.43141 97.50237 95.58378 93.41358 91.00236 88.69698 85.72017 83.18451 80.22261 77.45886 73.79589 70.02708 66.29484 62.08128 57.95706 53.89545 49.70493 45.99504 42.19815 38.68413 35.16609 32.78418 30.1482 27.3201 24.13857 21.88494 20.10168
+END_DATA
diff --git a/profile/afiles b/profile/afiles
new file mode 100644
index 0000000..986bf70
--- /dev/null
+++ b/profile/afiles
@@ -0,0 +1,40 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+printcal.c
+prof.h
+profin.c
+profout.c
+colprof.c
+profcheck.c
+invprofcheck.c
+verify.c
+applycal.c
+mppprof.c
+mppcheck.c
+simpprof.c
+kodak2ti3.c
+cb2ti3.c
+txt2ti3.c
+splitti3.c
+3dap5k.sp
+GTIPlus.sp
+Office.sp
+Trulux.sp
+TruluxPlus.sp
+example.sp
+example121.sp
+CIE_C.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
diff --git a/profile/applycal.c b/profile/applycal.c
new file mode 100644
index 0000000..ff9a76d
--- /dev/null
+++ b/profile/applycal.c
@@ -0,0 +1,693 @@
+
+/*
+ * ArgyllCMS.
+ * Apply a device calibration to an ICC profile.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2009/8/31
+ * Version: 1.00
+ *
+ * Copyright 2009 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/* TTBD:
+ *
+ * Would be good if remove restores shared curves, rather than
+ * leaving duplicates.
+ *
+ * Could stash the whole cal file in a text tag.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "cgats.h"
+#include "numlib.h"
+#include "rspl.h"
+#include "xicc.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#undef DBG
+#define DBG(xxx) printf xxx ;
+#else
+#undef DBG
+#define DBG(xxx)
+#endif
+
+void usage(char *diag, ...) {
+ int i;
+ fprintf(stderr,"Apply device calibration to an ICC profile, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: %s [-options] [calfile.cal] inprof%s [outprof%s]\n","applycal",ICC_FILE_EXT,ICC_FILE_EXT);
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -a Apply or re-apply calibration (default)\n");
+ fprintf(stderr," -u Remove calibration\n");
+ fprintf(stderr," -c Check calibration\n");
+ fprintf(stderr," calfile.cal Calibration file to apply\n");
+ fprintf(stderr," inprof%s ICC profile to read\n",ICC_FILE_EXT);
+ fprintf(stderr," outprof%s modified ICC profile to write\n",ICC_FILE_EXT);
+ exit(2);
+}
+
+/* A primary signature and its backup */
+struct _tagsigpair {
+ icTagSignature prim;
+ icTagSignature back;
+ int chan;
+ int dir; /* 0 = none or out, 1 = in */
+}; typedef struct _tagsigpair tagsigpair;
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char cal_name[MAXNAMEL+1];
+ char in_name[MAXNAMEL+1];
+ char out_name[MAXNAMEL+1];
+ xcal *cal = NULL; /* Calibration to apply */
+ icmFile *rd_fp = NULL, *wr_fp = NULL;
+ icc *icco;
+ int apply = 1;
+ int remove = 0;
+ int check = 0;
+ int verb = 0;
+ int found = -1;
+ int rv;
+
+ if (argc < 3)
+ usage("Too few arguments");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ else if (argv[fa][1] == 'a' || argv[fa][1] == 'A') {
+ apply = 1;
+ remove = 0;
+ check = 0;
+ }
+
+ else if (argv[fa][1] == 'u' || argv[fa][1] == 'U') {
+ apply = 0;
+ remove = 1;
+ check = 0;
+ }
+
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ apply = 0;
+ remove = 0;
+ check = 1;
+ }
+
+ else
+ usage("Unknown option '%s'",argv[fa][1]);
+
+ } else
+ break;
+ }
+
+ if (apply) {
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing calibration filename");
+ strncpy(cal_name,argv[fa++],MAXNAMEL); cal_name[MAXNAMEL] = '\000';
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing input profile filename");
+ strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ if (apply || remove) {
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing output profile name");
+ strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
+ }
+ if (fa < argc) usage("Extra argument '%s'",argv[fa]);
+
+ DBG(("apply %d, remove %d, check %d, calfile '%s', infile '%s', outfile '%s'\n",apply,remove,check,cal_name,in_name,out_name));
+
+ if (apply) {
+ /* Open up the calibration file */
+ if ((cal = new_xcal()) == NULL)
+ error("new_xcal failed");
+ if ((cal->read(cal, cal_name)) != 0)
+ error("%s",cal->err);
+ }
+
+ /* Open up the profile for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Can't open file '%s'",in_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = icco->read(icco,rd_fp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ /* Read every tag */
+ if (icco->read_all_tags(icco) != 0) {
+ error("Unable to read all tags: %d, %s",icco->errc,icco->err);
+ }
+
+ rd_fp->del(rd_fp);
+
+ /* ======================================= */
+ {
+ tagsigpair sigs[] = { /* Signatures to modify and their backups */
+ { icSigProfileDescriptionTag, icmMakeTag('A','R','0','T'), 0, 0 },
+ { icSigAToB0Tag, icmMakeTag('A','R','1','0'), 0, 1 },
+ { icSigAToB1Tag, icmMakeTag('A','R','2','0'), 0, 1 },
+ { icSigAToB2Tag, icmMakeTag('A','R','3','0'), 0, 1 },
+ { icSigBToA0Tag, icmMakeTag('A','R','4','0'), 0, 0 },
+ { icSigBToA1Tag, icmMakeTag('A','R','5','0'), 0, 0 },
+ { icSigBToA2Tag, icmMakeTag('A','R','6','0'), 0, 0 },
+ { icSigRedTRCTag, icmMakeTag('A','R','7','0'), 0, 0 },
+ { icSigGreenTRCTag, icmMakeTag('A','R','7','1'), 1, 0 },
+ { icSigBlueTRCTag, icmMakeTag('A','R','7','2'), 2, 0 },
+ { icSigGrayTRCTag, icmMakeTag('A','R','8','0'), 0, 0 },
+ { 0, 0, 0 }
+ };
+ tagsigpair linksigs[] = { /* Signatures to modify */
+ { icSigProfileDescriptionTag, icmMakeTag('A','R','0','T'), 0 },
+ { icSigAToB0Tag, icmMakeTag('A','R','9','1'), 1 },
+ { icSigAToB0Tag, icmMakeTag('A','R','9','0'), 0 },
+ { 0, 0, 0 }
+ };
+ tagsigpair *ssigp, *sigp;
+ int ntags = 0; /* Number of tags done */
+ icmBase *dtags[50]; /* Address of tags done */
+ int inp = 0; /* NZ for input calibration */
+ unsigned int i, j;
+
+ if (icco->header->deviceClass == icSigInputClass && cal->devclass != icSigInputClass) {
+ warning("Non-input calibration being applied to an input profile");
+ }
+
+ if (check) {
+ DBG(("Checking...\n"));
+
+ for (sigp = linksigs; sigp->prim != 0; sigp++) {
+ icmBase *primt;
+
+ if (sigp->prim != icSigProfileDescriptionTag)
+ continue;
+
+ if ((primt = icco->read_tag(icco, sigp->prim)) == NULL)
+ error("Can't find icSigProfileDescriptionTag in profile");
+
+ /* See if we have a backup */
+ if (icco->read_tag(icco, sigp->back) != NULL)
+ found = 1;
+ else
+ found = 0;
+ }
+ DBG(("found = %d\n",found));
+ if (found < 0)
+ error("Internal, didn't look for ProfileDescriptionTag");
+
+ if (verb) {
+ if (found)
+ printf("Profile has had calibration applied\n");
+ else
+ printf("Profile has NOT had calibration applied\n");
+ }
+ } else if (apply) {
+ DBG(("Applying...\n"));
+
+ if (icco->header->deviceClass == icSigInputClass
+ || icco->header->deviceClass == icSigDisplayClass
+ || icco->header->deviceClass == icSigOutputClass) {
+
+ DBG(("Input, display or output profile\n"));
+
+ /* Check colorspace is compatible */
+ if (cal->colspace != icco->header->colorSpace)
+ error("Calibration space %s doesn't match profile %s",
+ icm2str(icmColorSpaceSignature, cal->colspace),
+ icm2str(icmColorSpaceSignature, icco->header->colorSpace));
+
+ ssigp = sigs;
+ /* Note the cal direction */
+ if (cal->devclass == icSigInputClass)
+ inp = 1;
+ else
+ inp = 0;
+
+ } else if (icco->header->deviceClass == icSigLinkClass) {
+ DBG(("Device link profile\n"));
+
+ /* Check colorspace is compatible */
+ if (cal->colspace != icco->header->pcs)
+ error("Calibration space %s doesn't match profile %s",
+ icm2str(icmColorSpaceSignature, cal->colspace),
+ icm2str(icmColorSpaceSignature, icco->header->pcs));
+ ssigp = linksigs;
+ /* Noe the cal direction */
+ if (cal->devclass == icSigInputClass)
+ inp = 1;
+ else
+ inp = 0;
+ } else {
+ error("Can't apply calibration to profile of class %s",
+ icm2str(icmProfileClassSignature, icco->header->deviceClass));
+ }
+ DBG(("input calibration = %d\n",inp));
+
+ /* First pass is to duplicate any linked TRCTags */
+ for (sigp = ssigp; sigp->prim != 0; sigp++) { /* Process each tag */
+ icmBase *primt;
+
+ DBG(("looking for tag '%s'\n",icm2str(icmTagSignature, sigp->prim)));
+ if ((primt = icco->read_tag(icco, sigp->prim)) == NULL) {
+ if (sigp->prim == icSigProfileDescriptionTag)
+ error("Can't find icSigProfileDescriptionTag in profile");
+ continue; /* Don't have this tag */
+ }
+
+ /* XXXXTRCTag */
+ if (primt->ttype == icSigCurveType) {
+ icmCurve *wo, *ro = (icmCurve *)primt;
+
+ /* See if we have a backup */
+ if ((wo = (icmCurve *)icco->read_tag(icco, sigp->back)) == NULL) {
+
+ /* If tag is shared, we need to separated it */
+ if (ro->refcount > 1) {
+ DBG(("tag is shared, so separate it\n"));
+ if ((wo = (icmCurve *)icco->add_tag(
+ icco, sigp->back, icSigCurveType)) == NULL)
+ error("Failed to create tag '%s'\n", icm2str(icmTagSignature, sigp->back));
+ wo->flag = ro->flag;
+ wo->size = ro->size;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) /* Copy the curve */
+ wo->data[i] = ro->data[i];
+
+ if (icco->delete_tag(icco, sigp->prim))
+ error("Failed to delete tag '%s'",icm2str(icmTagSignature, sigp->prim));
+ if (icco->rename_tag(icco, sigp->back, sigp->prim))
+ error("Failed to rename tag '%s' to '%s'",
+ icm2str(icmTagSignature, sigp->back),
+ icm2str(icmTagSignature, sigp->prim));
+ }
+ } else {
+ if (ro->refcount > 1)
+ error("Found tag %s has backup, but is shared",icm2str(icmTagSignature,sigp->prim));
+ }
+ }
+ }
+ /* Second pass we create backups and calibrated curves */
+ for (sigp = ssigp; sigp->prim != 0; sigp++) { /* Process each tag */
+ icmBase *primt;
+
+ DBG(("looking for tag '%s'\n",icm2str(icmTagSignature, sigp->prim)));
+ if ((primt = icco->read_tag(icco, sigp->prim)) == NULL) {
+ if (sigp->prim == icSigProfileDescriptionTag)
+ error("Can't find icSigProfileDescriptionTag in profile");
+ continue; /* Don't have this tag */
+ }
+
+ /* icSigProfileDescriptionTag type */
+ if (primt->ttype == icSigTextDescriptionType) {
+ icmTextDescription *wo, *ro = (icmTextDescription *)primt;
+ char *extra = NULL;
+
+ /* See if we've done this tag before due to links */
+ for (i = 0; i < ntags; i++) {
+ if (dtags[i] == primt)
+ break; /* Yes */
+ }
+ if (i < ntags) {
+ DBG(("Found this tag before (link)\n"));
+ continue; /* Skip tag */
+ }
+ if (ntags >= 50) /* Impossible */
+ error("Internal, run out of previuos tags space");
+ dtags[ntags++] = primt; /* Remember this one */
+
+ DBG(("ProfileDescriptionTag\n"));
+ DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSignature, sigp->back)));
+
+ /* See if we have a backup */
+ if ((wo = (icmTextDescription *)icco->read_tag(icco, sigp->back)) == NULL) {
+ DBG(("No backup, creating one\n"));
+ /* No, so create one */
+ if ((wo = (icmTextDescription *)icco->add_tag(
+ icco, sigp->back, icSigTextDescriptionType)) == NULL)
+ error("Failed to create tag '%s'\n", icm2str(icmTagSignature, sigp->back));
+
+ wo->size = ro->size;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ strcpy(wo->desc, ro->desc); /* Copy the string in */
+ /* Hmm. what should we do with Unicode and script ? */
+ }
+
+ if (cal->xpi.profDesc != NULL)
+ extra = cal->xpi.profDesc;
+ else
+ extra = cal_name;
+
+ ro->size = strlen(ro->desc) + 3 + strlen(extra) + 3;
+ ro->allocate((icmBase *)ro); /* Allocate space */
+ strcpy(ro->desc, wo->desc);
+ strcat(ro->desc, " [ ");
+ strcat(ro->desc, extra);
+ strcat(ro->desc, " ]");
+
+ DBG(("Set tag contents to '%s'\n",ro->desc));
+
+ /* icSigAToBXTag or icSigBToAXTag */
+ } else if (primt->ttype == icSigLut8Type
+ || primt->ttype == icSigLut16Type) {
+ icmLut *ro = (icmLut *)primt; /* Modified Lut */
+
+ /* See if we've done this tag before due to links */
+ for (i = 0; i < ntags; i++) {
+ if (dtags[i] == primt)
+ break; /* Yes */
+ }
+ if (i < ntags) {
+ DBG(("Found this tag before (link)\n"));
+ continue; /* Skip tag */
+ }
+ if (ntags >= 50) /* Impossible */
+ error("Internal, run out of previous tags space");
+ dtags[ntags++] = primt; /* Remember this one */
+
+ DBG(("Lut8 or Lut16\n"));
+
+ if (sigp->dir) {
+ /* Apply calibration to the input table */
+ for (j = 0; j < ro->inputChan; j++) {
+ icTagSignature bsig = sigp->back;
+ icmCurve *wo; /* Backup of original */
+
+ /* Create a tag per channel */
+ bsig += j;
+
+ DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSignature, bsig)));
+
+ /* See if we have a backup */
+ if ((wo = (icmCurve *)icco->read_tag(icco, bsig)) == NULL) {
+ DBG(("No backup, creating one\n"));
+ /* No, so create one */
+ if ((wo = (icmCurve *)icco->add_tag(
+ icco, bsig, icSigCurveType)) == NULL)
+ error("Failed to create tag '%s'\n", icm2str(icmTagSignature, bsig));
+ wo->flag = icmCurveSpec; /* Specified version */
+ wo->size = ro->inputEnt;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) /* Copy the curve */
+ wo->data[i] = ro->inputTable[j * ro->inputEnt + i];
+ }
+
+ /* Create new input curve from inv cal + orginal curve */
+ for (i = 0; i < ro->inputEnt; i++) {
+ double val;
+ val = i/(ro->inputEnt-1.0);
+ if (inp)
+ val = cal->interp_ch(cal, j, val); /* Do calibration */
+ else
+ val = cal->inv_interp_ch(cal, j, val); /* Undo calibration */
+ wo->lookup_fwd(wo, &val, &val); /* Original curve */
+ ro->inputTable[j * ro->inputEnt + i] = val;
+ }
+ DBG(("Created calibrated input curve\n"));
+ }
+ } else {
+ /* Apply calibration to the output table */
+ for (j = 0; j < ro->outputChan; j++) {
+ icTagSignature bsig = sigp->back;
+ icmCurve *wo; /* Backup of original */
+
+ /* Create a tag per channel */
+ bsig += j;
+
+ DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSignature, bsig)));
+ /* See if we have a backup */
+ if ((wo = (icmCurve *)icco->read_tag(icco, bsig)) == NULL) {
+ DBG(("No backup, creating one\n"));
+ /* No, so create one */
+ if ((wo = (icmCurve *)icco->add_tag(
+ icco, bsig, icSigCurveType)) == NULL)
+ error("Failed to create tag '%s'\n", icm2str(icmTagSignature, bsig));
+
+ wo->flag = icmCurveSpec; /* Specified version */
+ wo->size = ro->outputEnt;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) /* Copy the curve */
+ wo->data[i] = ro->outputTable[j * ro->outputEnt + i];
+ }
+
+ /* Create new output curve from original + cal */
+ for (i = 0; i < ro->outputEnt; i++) {
+ double val;
+ val = i/(ro->outputEnt-1.0);
+ wo->lookup_fwd(wo, &val, &val); /* Original curve */
+ if (inp)
+ val = cal->interp_ch(cal, j, val); /* Undo calibration */
+ else
+ val = cal->interp_ch(cal, j, val); /* Do calibration */
+ ro->outputTable[j * ro->outputEnt + i] = val;
+ }
+ DBG(("Created calibrated output curve\n"));
+ }
+ }
+
+ /* XXXXTRCTag */
+ } else if (primt->ttype == icSigCurveType) {
+ icmCurve *wo, *ro = (icmCurve *)primt;
+
+ DBG(("CurveType\n"));
+
+ DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSignature, sigp->back)));
+
+ /* See if we have a backup */
+ if ((wo = (icmCurve *)icco->read_tag(icco, sigp->back)) == NULL) {
+
+ DBG(("No backup, creating one\n"));
+ /* No, so create one */
+ if ((wo = (icmCurve *)icco->add_tag(
+ icco, sigp->back, icSigCurveType)) == NULL)
+ error("Failed to create tag '%s'\n", icm2str(icmTagSignature, sigp->back));
+
+ wo->flag = ro->flag;
+ wo->size = ro->size;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ for (i = 0; i < wo->size; i++) /* Copy the curve */
+ wo->data[i] = ro->data[i];
+
+ /* Change type & size of ro if necessary */
+ if (ro->flag != icmCurveSpec || wo->size < 256) {
+ ro->flag = icmCurveSpec;
+ ro->size = 256;
+ ro->allocate((icmBase *)wo); /* Allocate space */
+ }
+ }
+
+ /* Create new forward direction curve from cal + orginal curve */
+ j = sigp->chan;
+ for (i = 0; i < ro->size; i++) {
+ double val;
+ val = i/(ro->size-1.0);
+//printf("~1 Input val %f", val);
+ if (inp)
+ val = cal->interp_ch(cal, j, val); /* Input calibration */
+ else
+ val = cal->inv_interp_ch(cal, j, val); /* Inverse output calibration */
+//printf(", after inv curve %f", val);
+ wo->lookup_fwd(wo, &val, &val); /* Original curve */
+//printf(", after orig %f\n", val);
+ ro->data[i] = val;
+ }
+ DBG(("Created calibrated %s curve for chan %d\n",inp ? "input" : "output",j));
+ } else {
+ error("Tag %s is type %s we don't know how to handle",
+ icm2str(icmTagSignature, sigp->prim),
+ icm2str(icmTypeSignature, primt->ttype));
+ }
+ }
+
+ } else if (remove) {
+ int k;
+ DBG(("Removing...\n"));
+ for (k = 0; k < 2; k++) {
+ if (k == 0)
+ ssigp = sigs;
+ else if (k == 1)
+ ssigp = linksigs;
+
+ for (sigp = ssigp; sigp->prim != 0; sigp++) { /* Process each tag */
+ icmBase *backt, *primt;
+
+ DBG(("Looking for baclup tag '%s'\n",icm2str(icmTagSignature, sigp->back)));
+ if ((backt = icco->read_tag(icco, sigp->back)) == NULL)
+ continue; /* Don't have this backup tag */
+
+ DBG(("Looking for primary tag '%s'\n",icm2str(icmTagSignature, sigp->prim)));
+ if ((primt = icco->read_tag(icco, sigp->prim)) == NULL) {
+ error("Can't find primary tag %s for backup %s",
+ icm2str(icmTagSignature, sigp->prim),
+ icm2str(icmTagSignature, sigp->back));
+ }
+
+ /* icSigProfileDescriptionTag type */
+ if (primt->ttype == icSigTextDescriptionType) {
+ icmTextDescription *wo, *ro = (icmTextDescription *)primt;
+
+ DBG(("ProfileDescriptionTag\n"));
+
+ wo = (icmTextDescription *)backt;
+
+ /* Restore primary table */
+ ro->size = wo->size;
+ ro->allocate((icmBase *)ro); /* Reallocate space */
+ strcpy(ro->desc, wo->desc); /* Restore description */
+
+ /* delete backup */
+ if (icco->delete_tag(icco, sigp->back))
+ error("Failed to delete tag '%s'",icm2str(icmTagSignature, sigp->prim));
+ DBG(("Restored primary and deleted backup\n"));
+
+ /* icSigAToBXTag or icSigBToAXTag */
+ } else if (primt->ttype == icSigLut8Type
+ || primt->ttype == icSigLut16Type) {
+ icmLut *ro = (icmLut *)primt; /* Modified Lut */
+
+ if (sigp->dir) {
+ /* Restore the input table */
+ for (j = 0; j < ro->inputChan; j++) {
+ icTagSignature bsig = sigp->back;
+ icmCurve *wo; /* Backup of original */
+
+ /* Create a tag per channel */
+ bsig += j;
+
+ DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSignature, bsig)));
+
+ /* See if we have a backup */
+ if ((wo = (icmCurve *)icco->read_tag(icco, bsig)) == NULL)
+ error("Can't find original table data in tag %s",
+ icm2str(icmTagSignature, sigp->back));
+
+ /* Restore primary table */
+ for (i = 0; i < wo->size; i++) /* Copy the curve */
+ ro->inputTable[j * ro->inputEnt + i] = wo->data[i];
+
+ /* delete backup */
+ if (icco->delete_tag(icco, bsig))
+ error("Failed to delete tag '%s'",icm2str(icmTagSignature, bsig));
+ DBG(("Restored primary and deleted backup\n"));
+ }
+ } else {
+ /* Restore the output table */
+ for (j = 0; j < ro->outputChan; j++) {
+ icTagSignature bsig = sigp->back;
+ icmCurve *wo; /* Backup of original */
+
+ /* Create a tag per channel */
+ bsig += j;
+
+ DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSignature, bsig)));
+
+ /* See if we have a backup */
+ if ((wo = (icmCurve *)icco->read_tag(icco, bsig)) == NULL)
+ error("Can't find original table data in tag %s",
+ icm2str(icmTagSignature, sigp->back));
+
+ /* Restore primary table */
+ for (i = 0; i < wo->size; i++) /* Copy the curve */
+ ro->outputTable[j * ro->outputEnt + i] = wo->data[i];
+
+ /* delete backup */
+ if (icco->delete_tag(icco, bsig))
+ error("Failed to delete tag '%s'",icm2str(icmTagSignature, bsig));
+ DBG(("Restored primary and deleted backup\n"));
+ }
+ }
+
+ /* XXXXTRCTag */
+ } else if (primt->ttype == icSigCurveType) {
+ icmCurve *wo, *ro = (icmCurve *)primt;
+
+ DBG(("CurveType\n"));
+ DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSignature, sigp->back)));
+
+ /* See if we have a backup */
+ wo = (icmCurve *)backt;
+
+ /* Restore primary table */
+ ro->flag = wo->flag;
+ ro->size = wo->size;
+ ro->allocate((icmBase *)ro); /* Allocate space */
+ for (i = 0; i < wo->size; i++) /* Copy the curve */
+ ro->data[i] = wo->data[i];
+
+ /* delete backup */
+ if (icco->delete_tag(icco, sigp->back))
+ error("Failed to delete tag '%s'",icm2str(icmTagSignature, sigp->back));
+ DBG(("Restored primary and deleted backup\n"));
+
+ } else {
+ error("Tag %s is type %s we don't know how to handle",
+ icm2str(icmTagSignature, sigp->prim),
+ icm2str(icmTypeSignature, primt->ttype));
+ }
+ }
+ }
+ }
+ }
+ /* ======================================= */
+
+ if (apply || remove) {
+ /* Open up the other profile for writing */
+ if ((wr_fp = new_icmFileStd_name(out_name,"w")) == NULL)
+ error ("Can't open file '%s'",out_name);
+
+ if ((rv = icco->write(icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,icco->err);
+ wr_fp->del(wr_fp);
+ }
+
+ if (cal != NULL)
+ cal->del(cal);
+ icco->del(icco);
+
+ if (found == 1)
+ return 1;
+ return 0;
+}
+
diff --git a/profile/cb2ti3.c b/profile/cb2ti3.c
new file mode 100644
index 0000000..4fc7866
--- /dev/null
+++ b/profile/cb2ti3.c
@@ -0,0 +1,244 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Read in the device data from Colorblind device files,
+ * and convert it into a .ti3 CGATs format suitable for
+ * the Argyll CMM.
+ *
+ * Derived from kodak2cgats.c
+ * Author: Graeme W. Gill
+ * Date: 16/11/00
+ *
+ * Copyright 2000, 2010, Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+#define VERSION "1.0"
+
+/* TTBD
+ */
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include <stdarg.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+
+void
+usage(void) {
+ fprintf(stderr,"Convert Colorblind raw device profile data to Argyll data, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: cb2ti3 [-v] [-l limit] infile outfile\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -l limit Set inklimit in .ti3 file\n");
+ fprintf(stderr," infile Base name for input.CMY and input.nCIE file\n");
+ fprintf(stderr," outfile Base name for output.ti3 file\n");
+ exit(1);
+ }
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ static char tarname[200] = { 0 }; /* Input .CMY file */
+ static char inname[200] = { 0 }; /* Input .nCIE file */
+ static char outname[200] = { 0 }; /* Output cgats .ti3 file base name */
+ cgats *cmy; /* Input RGB reference file */
+ int f_id1, f_c, f_m, f_y; /* Field indexes */
+ cgats *ncie; /* Inpit CIE readings file */
+ int f_id2, f_xx, f_yy, f_zz; /* Field indexes */
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ int npat = 0; /* Number of patches */
+
+ error_program = "cb2ti3";
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++)
+ {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') /* Look for any flags */
+ {
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else
+ {
+ if ((fa+1) < argc)
+ {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+
+ strcpy(inname,argv[fa]);
+ strcpy(tarname,argv[fa++]);
+ strcat(inname,".CMY");
+ strcat(tarname,".nCIE");
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(outname, argv[fa++]);
+ strcat(outname,".ti3");
+
+ /* Open up the Input CMY reference file */
+ cmy = new_cgats(); /* Create a CGATS structure */
+ cmy->add_other(cmy, "CBTA"); /* Colorblind Target file */
+ if (cmy->read_name(cmy, inname))
+ error ("Read: Can't open file '%s'",inname);
+ if (cmy->ntables == 0 || cmy->t[0].tt != tt_other || cmy->t[0].oi != 0)
+ error ("Input file isn't a 'CBTA' format file");
+ if (cmy->ntables != 1)
+ fprintf(stderr,"Input file '%s' doesn't contain exactly one table",inname);
+
+ if ((npat = cmy->t[0].nsets) <= 0)
+ error("No patches");
+
+ if ((f_id1 = cmy->find_field(cmy, 0, "SAMPLE_ID")) < 0)
+ error("Input file doesn't contain field SAMPLE_ID");
+ if (cmy->t[0].ftype[f_id1] != nqcs_t)
+ error("Field SAMPLE_ID is wrong type");
+
+ if ((f_c = cmy->find_field(cmy, 0, "C")) < 0)
+ error("Input file doesn't contain field C");
+ if (cmy->t[0].ftype[f_c] != r_t)
+ error("Field C is wrong type");
+
+ if ((f_m = cmy->find_field(cmy, 0, "M")) < 0)
+ error("Input file doesn't contain field M");
+ if (cmy->t[0].ftype[f_m] != r_t)
+ error("Field M is wrong type");
+
+ if ((f_y = cmy->find_field(cmy, 0, "Y")) < 0)
+ error("Input file doesn't contain field Y");
+ if (cmy->t[0].ftype[f_y] != r_t)
+ error("Field Y is wrong type");
+
+ /* Open up the input nCIE device data file */
+ ncie = new_cgats(); /* Create a CGATS structure */
+ ncie->add_other(ncie, "CBPR"); /* Colorblind Printer Response file */
+ if (ncie->read_name(ncie, tarname))
+ error ("Read: Can't open file '%s'",tarname);
+ if (ncie->ntables == 0 || ncie->t[0].tt != tt_other || ncie->t[0].oi != 0)
+ error ("Input file isn't a 'CBTA' format file");
+ if (ncie->ntables != 1)
+ fprintf(stderr,"Input file '%s' doesn't contain exactly one table",tarname);
+
+ if (npat != ncie->t[0].nsets)
+ error("Number of patches doesn't match");
+
+ if ((f_id2 = ncie->find_field(ncie, 0, "SAMPLE_ID")) < 0)
+ error("Input file doesn't contain field SAMPLE_ID");
+ if (ncie->t[0].ftype[f_id2] != nqcs_t)
+ error("Field SAMPLE_ID is wrong type");
+
+ if ((f_xx = ncie->find_field(ncie, 0, "XYZ_X")) < 0)
+ error("Input file doesn't contain field XYZ_X");
+ if (ncie->t[0].ftype[f_xx] != r_t)
+ error("Field XYZ_X is wrong type");
+
+ if ((f_yy = ncie->find_field(ncie, 0, "XYZ_Y")) < 0)
+ error("Input file doesn't contain field XYZ_Y");
+ if (ncie->t[0].ftype[f_yy] != r_t)
+ error("Field XYZ_Y is wrong type");
+
+ if ((f_zz = ncie->find_field(ncie, 0, "XYZ_Z")) < 0)
+ error("Input file doesn't contain field XYZ_Z");
+ if (ncie->t[0].ftype[f_zz] != r_t)
+ error("Field XYZ_Z is wrong type");
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll target", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL); /* What sort of device this is */
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+
+ ocg->add_field(ocg, 0, "RGB_R", r_t);
+ ocg->add_field(ocg, 0, "RGB_G", r_t);
+ ocg->add_field(ocg, 0, "RGB_B", r_t);
+ ocg->add_kword(ocg, 0, "COLOR_REP","RGB_XYZ", NULL);
+ ocg->add_field(ocg, 0, "XYZ_X", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Y", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Z", r_t);
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < npat; i++) {
+ char id[100];
+ double rgb[3];
+ double xyz[3];
+
+ if (strcmp(((char *)cmy->t[0].fdata[i][f_id1]),
+ ((char *)ncie->t[0].fdata[i][f_id2])) != 0) {
+ error("Patch label mismatch, patch %d, '%s' != '%s'\n",
+ i, ((char *)cmy->t[0].fdata[i][f_id1]),
+ ((char *)ncie->t[0].fdata[i][f_id2]));
+ }
+
+ rgb[0] = 100.0 - *((double *)cmy->t[0].fdata[i][f_c]); /* Convert to RGB */
+ rgb[1] = 100.0 - *((double *)cmy->t[0].fdata[i][f_m]);
+ rgb[2] = 100.0 - *((double *)cmy->t[0].fdata[i][f_y]);
+
+ xyz[0] = *((double *)ncie->t[0].fdata[i][f_xx]);
+ xyz[1] = *((double *)ncie->t[0].fdata[i][f_yy]);
+ xyz[2] = *((double *)ncie->t[0].fdata[i][f_zz]);
+
+ sprintf(id, "%d", i+1);
+ ocg->add_set(ocg, 0, id, rgb[0], rgb[1], rgb[2],
+ xyz[0], xyz[1], xyz[2]);
+ }
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ ncie->del(ncie); /* Clean up */
+ cmy->del(cmy);
+ ocg->del(ocg);
+
+ return 0;
+}
+
+
+
diff --git a/profile/colprof.c b/profile/colprof.c
new file mode 100644
index 0000000..99e02cf
--- /dev/null
+++ b/profile/colprof.c
@@ -0,0 +1,1116 @@
+/*
+ * Argyll Color Correction System
+ * Color Device profile generator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 15/2/97
+ *
+ * Copyright 1996-2011 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.
+ */
+
+/*
+ * This program takes in the scattered test chart
+ * points, and interpolates them into a gridded
+ * forward ICC device profile, as well as creating
+ * backward conversions based on the forward grid.
+ *
+ * Preview profiles are not currently generated.
+ *
+ * The gamut cLUT should be implemented with xicc/rspl
+ */
+
+/*
+ * TTBD:
+ * Should allow ICC Device attributes to be set.
+ *
+ * Add Argyll private tag to record ink limit etc. to automate link parameters.
+ * Estimate ink limit from B2A tables if no private tag ?
+ * Add used option for black relative
+ * Add used option for separate high res reverse tables
+ * Fix 400% assumptions for > 4 color devices ?
+ *
+ * Should allow creating profiles from .MPP directly for <= 4 dev channels.
+ * Should allow creating profiles from existing ICC profiles (deprecate revfix ?)
+ *
+ * Should allow creating profiles >4 channels by providing .MPP for input,
+ * dev link .icm for psudo-dev to device & .ti3 for Pseudo-dev to PCS.
+ * Note gamut should come from psudo-dev to PCS.
+ */
+
+#undef DEBUG
+#undef DO_TIME /* Time the operation */
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "prof.h"
+
+#define DEFAVGDEV 0.5 /* Default average deviation percentage */
+ /* This equates to a uniform added error of +/- 1% */
+
+/*
+
+ Flags used:
+
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ upper . .. . ... .. .... .
+ lower .... .. . .. ......... .
+
+*/
+
+void usage(char *diag, ...) {
+ int i;
+ fprintf(stderr,"Create ICC profile, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: %s [-options] inoutfile\n",error_program);
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -A manufacturer Manufacturer description string\n");
+ fprintf(stderr," -M model Model description string\n");
+ fprintf(stderr," -D description Profile Description string (Default \"inoutfile\")\n");
+ fprintf(stderr," -C copyright Copyright string\n");
+ fprintf(stderr," -Z tmnb Attributes: Transparency, Matte, Negative, BlackAndWhite\n");
+ fprintf(stderr," -Z prsa Default intent: Perceptual, Rel. Colorimetric, Saturation, Abs. Colorimetric\n");
+
+ fprintf(stderr," -q lmhu Quality - Low, Medium (def), High, Ultra\n");
+// 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");
+ fprintf(stderr," -nc Don't put the input .ti3 data in the profile\n");
+ fprintf(stderr," -k zhxr Black value target: z = zero K,\n");
+ fprintf(stderr," h = 0.5 K, x = max K, r = ramp K (def.)\n");
+ fprintf(stderr," -k p stle stpo enpo enle shape\n");
+ fprintf(stderr," stle: K level at White 0.0 - 1.0\n");
+ fprintf(stderr," stpo: start point of transition Wh 0.0 - Bk 1.0\n");
+ fprintf(stderr," enpo: End point of transition Wh 0.0 - Bk 1.0\n");
+ fprintf(stderr," enle: K level at Black 0.0 - 1.0\n");
+ fprintf(stderr," shape: 1.0 = straight, 0.0-1.0 concave, 1.0-2.0 convex\n");
+ fprintf(stderr," -K parameters Same as -k, but target is K locus rather than K value itself\n");
+ fprintf(stderr," -l tlimit override total ink limit, 0 - 400%% (default from .ti3)\n");
+ fprintf(stderr," -L klimit override black ink limit, 0 - 100%% (default from .ti3)\n");
+ fprintf(stderr," -a lxXgsmGS Algorithm type override\n");
+ fprintf(stderr," l = Lab cLUT (def.), x = XYZ cLUT, X = display XYZ cLUT + matrix\n");
+ fprintf(stderr," g = gamma+matrix, s = shaper+matrix, m = matrix only,\n");
+ fprintf(stderr," G = single gamma+matrix, S = single shaper+matrix\n");
+// Development - not supported
+// fprintf(stderr," -I ver Set ICC profile version > 2.2.0\n");
+// fprintf(stderr," ver = 4, Enable ICC V4 creation\n");
+ fprintf(stderr," -u If input profile, auto scale WP to allow extrapolation\n");
+ 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," -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");
+ 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," -r avgdev Average deviation of device+instrument readings as a percentage (default %4.2f%%)\n",DEFAVGDEV);
+/* Research options: */
+/* fprintf(stderr," -r sSMOOTH RSPL or shaper suplimental optimised smoothing factor\n"); */
+/* fprintf(stderr," -r rSMOOTH RSPL or shaper raw underlying smoothing factor\n"); */
+ fprintf(stderr," -s src%s Apply gamut mapping to output profile perceptual B2A table for given source space\n",ICC_FILE_EXT);
+ fprintf(stderr," -S src%s Apply gamut mapping to output profile perceptual and saturation B2A table\n",ICC_FILE_EXT);
+ fprintf(stderr," -nP Use colormetric source gamut to make output profile perceptual table\n");
+ fprintf(stderr," -nS Use colormetric source gamut to make output profile saturation table\n");
+ fprintf(stderr," -g src.gam Use source image gamut as well for output profile gamut mapping\n");
+ fprintf(stderr," -p absprof,... Incorporate abstract profile(s) into output tables\n");
+ fprintf(stderr," -t intent Override gamut mapping intent for output profile perceptual table:\n");
+ fprintf(stderr," -T intent Override gamut mapping intent for output profile saturation table:\n");
+ for (i = 0; ; i++) {
+ icxGMappingIntent gmi;
+ if (xicc_enum_gmapintent(&gmi, i, NULL) == icxIllegalGMIntent)
+ break;
+ fprintf(stderr," %s\n",gmi.desc);
+ }
+ fprintf(stderr," -c viewcond set input viewing conditions for output profile %s gamut mapping,\n",icxcam_description(cam_default));
+ fprintf(stderr," either an enumerated choice, or a parameter\n");
+ fprintf(stderr," -d viewcond set output viewing conditions for output profile %s gamut mapping\n",icxcam_description(cam_default));
+ fprintf(stderr," either an enumerated choice, or a parameter\n");
+ fprintf(stderr," Also sets out of gamut clipping CAM space.\n");
+ fprintf(stderr," either an enumerated choice, or a series of parameters:value changes\n");
+ for (i = 0; ; i++) {
+ icxViewCond vc;
+ if (xicc_enum_viewcond(NULL, &vc, i, NULL, 1, NULL) == -999)
+ break;
+
+ fprintf(stderr," %s\n",vc.desc);
+ }
+ fprintf(stderr," -P Create gamut gammap_p.wrl and gammap_s.wrl diagostics\n");
+ fprintf(stderr," -O outputfile Override the default output filename.\n");
+ fprintf(stderr," inoutfile Base name for input.ti3/output%s file\n",ICC_FILE_EXT);
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa,mfa; /* current argument we're looking at */
+#ifdef DO_TIME /* Time the operation */
+ clock_t stime, ttime; /* Start and total times */
+#endif
+ int verb = 0;
+ int iquality = 1; /* A2B quality */
+ int oquality = -1; /* B2A quality same as A2B */
+ int verify = 0;
+ int noisluts = 0; /* No input shaper luts */
+ int noipluts = 0; /* No input position luts */
+ int nooluts = 0; /* No output shaper luts */
+ int nocied = 0; /* No .ti3 CIE data in profile */
+ int noptop = 0; /* Use colormetric source gamut to make perceptual table */
+ int nostos = 0; /* Use colormetric source gamut to make saturation table */
+ int gamdiag = 0; /* Make gamut mapping diagnostic wrl plots */
+ 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 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 */
+ int inking = 3; /* Default K target ramp K */
+ int locus = 0; /* Default K value target */
+ double Kstle = 0.0, Kstpo = 0.0, Kenle = 0.0, Kenpo = 0.0, Kshap = 0.0;
+ int tlimit = -1; /* Total ink limit as a % */
+ int klimit = -1; /* Black ink limit as a % */
+ int fwacomp = 0; /* FWA compensation */
+ double avgdev = DEFAVGDEV/100.0; /* Average measurement deviation */
+ double smooth = 1.0; /* RSPL Smoothness factor (relative, for verification) */
+ int spec = 0; /* Use spectral data flag */
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ xspect cust_tillum; /* Custom target/simulated illumination spectrum */
+ icxIllumeType illum = icxIT_D50; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxObserverType observ = icxOT_CIE_1931_2; /* The classic observer */
+ char ipname[MAXNAMEL+1] = ""; /* Input icc profile - enables gamut map */
+ char sgname[MAXNAMEL+1] = ""; /* Image source gamut name */
+ char absstring[3 * MAXNAMEL +1]; /* Storage for absnames */
+ char *absnames[3] = { NULL, NULL, NULL }; /* Abstract profile name */
+ int sepsat = 0; /* Create separate saturation B2A table */
+ icxViewCond ivc_p; /* Input Viewing Parameters for CAM */
+ icxViewCond ovc_p; /* Output Viewing Parameters for CAM (enables CAM clip) */
+ int ivc_e = -1, ovc_e = -1; /* Enumerated viewing condition */
+ icxGMappingIntent pgmi; /* default Perceptual gamut mapping intent */
+ int pgmi_set = 0; /* Set by user option */
+ icxGMappingIntent sgmi; /* default Saturation gamut mapping intent */
+ int sgmi_set = 0; /* Set by user option */
+ char baname[MAXNAMEL+1] = ""; /* Input & Output base name */
+ char inname[MAXNAMEL+1] = ""; /* Input cgats file base name */
+ char outname[MAXNAMEL+1] = ""; /* Output cgats file base name */
+ cgats *icg; /* input cgats structure */
+ int ti; /* Temporary CGATs index */
+ prof_atype ptype = prof_default; /* Default for each type of device */
+ int mtxtoo = 0; /* NZ if matrix tags should be created for Display XYZ cLUT */
+ icmICCVersion iccver = icmVersionDefault; /* ICC profile version to create */
+ profxinf xpi; /* Extra profile information */
+
+
+#ifdef DO_TIME /* Time the operation */
+ stime = clock();
+#endif /* DO_TIME */
+ error_program = argv[0];
+ check_if_not_interactive();
+ memset((void *)&xpi, 0, sizeof(profxinf)); /* Init extra profile info to defaults */
+ xpi.default_ri = icMaxEnumIntent; /* Default default */
+
+ /* Init VC overrides so that we know when the've been set */
+ ivc_p.Ev = -1;
+ ivc_p.Wxyz[0] = -1.0; ivc_p.Wxyz[1] = -1.0; ivc_p.Wxyz[2] = -1.0;
+ ivc_p.La = -1.0;
+ 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;
+
+ ovc_p.Ev = -1;
+ ovc_p.Wxyz[0] = -1.0; ovc_p.Wxyz[1] = -1.0; ovc_p.Wxyz[2] = -1.0;
+ ovc_p.La = -1.0;
+ 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;
+
+ xicc_enum_gmapintent(&pgmi, icxPerceptualGMIntent, NULL);
+ xicc_enum_gmapintent(&sgmi, icxSaturationGMIntent, NULL);
+
+ if (argc <= 1)
+ usage("Too few arguments, got %d expect at least %d",argc-1,1);
+
+ /* Process the arguments */
+ mfa = 1; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ /* Manufacturer description string */
+ else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to manufacturer description flag -A");
+ xpi.deviceMfgDesc = na;
+ }
+
+ /* Model description string */
+ else if (argv[fa][1] == 'M') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to model description flag -M");
+ xpi.modelDesc = na;
+ }
+
+ /* Profile Description */
+ else if (argv[fa][1] == 'D') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to profile description flag -D");
+ xpi.profDesc = na;
+ }
+
+ /* Copyright string */
+ else if (argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to copyright flag -C");
+ xpi.copyright = na;
+ }
+
+ /* Attribute bits */
+ else if (argv[fa][1] == 'Z') {
+ int i, j;
+
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to attribute flag -Z");
+ for (j = i = 0; j == 0; i++) {
+
+ switch(na[i]) {
+
+ /* Attribute */
+ case 't':
+ case 'T':
+ xpi.transparency = 1;
+ break;
+ case 'm':
+ case 'M':
+ xpi.matte = 1;
+ break;
+ case 'n':
+ case 'N':
+ xpi.negative = 1;
+ break;
+ case 'b':
+ case 'B':
+ xpi.blackandwhite = 1;
+ break;
+
+ /* Default intent */
+ case 'p':
+ case 'P':
+ xpi.default_ri = icPerceptual;
+ break;
+ case 'r':
+ case 'R':
+ xpi.default_ri = icRelativeColorimetric;
+ break;
+ case 's':
+ case 'S':
+ xpi.default_ri = icSaturation;
+ break;
+ case 'a':
+ case 'A':
+ xpi.default_ri = icAbsoluteColorimetric;
+ break;
+ default:
+ j = 1;
+ break;
+ }
+ }
+ if (na[i-1] != '\000') usage("Unknown argument '%c' to attribute flag -Z",na[i-1]);
+ }
+
+ /* Quality */
+ else if (argv[fa][1] == 'q' || 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");
+ switch (na[0]) {
+ case 'f': /* Fast */
+ case 'l':
+ case 'L':
+ iquality = 0;
+ break;
+ case 'm': /* Medium */
+ case 'M':
+ iquality = 1;
+ break;
+ case 's': /* Slow */
+ case 'h':
+ case 'H':
+ iquality = 2;
+ break;
+ case 'u': /* Ultra Slow */
+ case 'U':
+ iquality = 3;
+ break;
+ default:
+ usage("Unknown argument '%c' to quality flag -q",na[0]);
+// usage("Unknown argument '%c' to speed flag -q",na[0]);
+ }
+ }
+ else if (argv[fa][1] == 'b') {
+ if (na != NULL) { /* Got a B2A quaiity */
+ fa = nfa;
+ switch (na[0]) {
+ case 'f': /* Fast */
+ case 'l':
+ case 'L':
+ oquality = 0;
+ break;
+ case 'm': /* Medium */
+ case 'M':
+ oquality = 1;
+ break;
+ case 's': /* Slow */
+ case 'h':
+ case 'H':
+ oquality = 2;
+ break;
+ case 'u': /* Ultra Slow */
+ case 'U':
+ oquality = 3;
+ break;
+ case 'n': /* No B2A for input device */
+ case 'N':
+ oquality = -2;
+ doinb2a = 0;
+ break;
+ default:
+ usage("Unknown argument '%c' to quality flag -q",na[0]);
+ }
+ } else
+ oquality = 0;
+ }
+
+ else if (argv[fa][1] == 'B') {
+ oquality = -2;
+ 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') {
+ fa = nfa;
+ if (na == NULL) { /* Backwards compatible */
+ nooluts = 1;
+ } else {
+ if (na[0] == 'i')
+ noisluts = 1;
+ else if (na[0] == 'p')
+ noipluts = 1;
+ else if (na[0] == 'o')
+ nooluts = 1;
+ else if (na[0] == 'c')
+ nocied = 1;
+ else if (na[0] == 'P')
+ noptop = 1;
+ else if (na[0] == 'S')
+ nostos = 1;
+ else
+ usage("Unknown argument '%c' to flag -n",na[0]);
+ }
+ }
+
+ else if (argv[fa][1] == 'u') {
+ autowpsc = 1;
+ clipovwp = 0;
+ if (argv[fa][2] == 'c') {
+ autowpsc = 0;
+ clipovwp = 1;
+ } else if (argv[fa][2] != '\000') {
+ usage("Unknown flag '%c' after -u",argv[fa][2]);
+ }
+ }
+ else if (argv[fa][1] == 'U') {
+ 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)
+ usage("Argument '%s' to flag -U out of range",na);
+ }
+ /* Clip primaries */
+ else if (argv[fa][1] == 'R') {
+ clipprims = 1;
+ }
+
+ /* Inking rule */
+ 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')
+ locus = 0; /* Use K value target */
+ else
+ locus = 1; /* Use K locus target */
+ switch (na[0]) {
+ case 'z':
+ case 'Z':
+ inking = 0; /* Use minimum k */
+ break;
+ case 'h':
+ case 'H':
+ inking = 1; /* Use 0.5 k */
+ break;
+ case 'x':
+ case 'X':
+ inking = 2; /* Use maximum K */
+ break;
+ case 'r':
+ case 'R':
+ inking = 3; /* Use ramping K */
+ break;
+ case 'p':
+ case 'P':
+ inking = 4; /* Use parameter curve */
+ ++fa;
+ if (fa >= argc) usage("Too few arguments to inking flag -kp");
+ Kstle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage("Too few arguments to inking flag -kp");
+ Kstpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Too few arguments to inking flag -kp");
+ Kenpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage("Too few arguments to inking flag -kp");
+ Kenle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Too few arguments to inking flag -kp");
+ Kshap = atof(argv[fa]);
+ break;
+ default:
+ usage("Unknown inking rule (-k) argument '%c'",na[0]);
+ }
+ }
+
+ /* Total Ink Limit */
+ else if (argv[fa][1] == 'l') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to total ink limit flag -l");
+ tlimit = atoi(na);
+ }
+
+ /* Black Ink Limit */
+ else if (argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to black ink limit flag -L");
+ klimit = atoi(na);
+ }
+
+ /* Algorithm type */
+ else if (argv[fa][1] == 'a' || argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to algorithm flag -a");
+ switch (na[0]) {
+ case 'l':
+ case 'L':
+ ptype = prof_clutLab;
+ break;
+ case 'X':
+ mtxtoo = 1;
+ /* Fall though */
+ case 'x':
+ ptype = prof_clutXYZ;
+ break;
+ case 'g':
+ ptype = prof_gammat;
+ break;
+ case 'G':
+ ptype = prof_gam1mat;
+ break;
+ case 's':
+ ptype = prof_shamat;
+ break;
+ case 'S':
+ ptype = prof_sha1mat;
+ break;
+ case 'm':
+ ptype = prof_matonly;
+ break;
+ default:
+ usage("Unknown argument '%c' to algorithm flag -a",na[0] );
+ }
+ }
+ /* Profile version */
+ else if (argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to version flag -I");
+ switch (na[0]) {
+ case '4':
+ iccver = icmVersion4_1;
+ break;
+ default:
+ usage("Unknown argument '%c' to version flag -I",na[0] );
+ }
+ }
+
+ /* FWA compensation */
+ else if (argv[fa][1] == 'f') {
+ fwacomp = 1;
+
+ if (na != NULL) { /* Argument is present - target/simulated instr. illum. */
+ fa = nfa;
+ if (strcmp(na, "A") == 0
+ || strcmp(na, "M0") == 0) {
+ spec = 1;
+ tillum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ tillum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0
+ || strcmp(na, "M1") == 0) {
+ spec = 1;
+ tillum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0
+ || strcmp(na, "M2") == 0) {
+ spec = 1;
+ tillum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ tillum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ tillum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ tillum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ tillum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ tillum = icxIT_custom;
+ if (read_xspect(&cust_tillum, na) != 0)
+ usage("Failed to read custom target illuminant spectrum in file '%s'",na);
+ }
+ }
+ }
+
+ /* Spectral Illuminant type */
+ else if (argv[fa][1] == 'i') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to illuminant flag -i");
+ if (strcmp(na, "A") == 0) {
+ spec = 1;
+ illum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ illum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0) {
+ spec = 1;
+ illum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0) {
+ spec = 1;
+ illum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ illum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ illum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ illum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ illum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ illum = icxIT_custom;
+ if (read_xspect(&cust_illum, na) != 0)
+ usage("Failed to read custom illuminant spectrum in file '%s'",na);
+ }
+ }
+
+ /* Spectral Observer type */
+ else if (argv[fa][1] == 'o') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to observer flag -o");
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ spec = 1;
+ observ = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ spec = 1;
+ observ = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ spec = 1;
+ observ = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ spec = 1;
+ observ = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ spec = 1;
+ observ = icxOT_Shaw_Fairchild_2;
+ } else
+ usage("Unrecognised argument '%s' to observer flag -o",na);
+ }
+
+
+ /* Average Deviation percentage */
+ else if (argv[fa][1] == 'r') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to average deviation flag -r");
+ if (na[0] == 's') { /* (relative, for verification) */
+ smooth = atof(na+1);
+ if (smooth < 0.0)
+ usage("Optimised smoothing factor argument to '-rs' must be over 0.0");
+ } else if (na[0] == 'r') { /* (absolute, for testing) */
+ smooth = atof(na+1);
+ if (smooth < 0.0)
+ usage("Raw smoothing factor argument to '-rr' must be over 0.0");
+ smooth = -smooth; /* Signal raw factor */
+ } else {
+ avgdev = 0.01 * atof(na);
+ if (avgdev < 0.0 || avgdev > 1.0)
+ usage("Average Deviation argument must be between 0.0 and 100.0");
+ }
+ }
+
+ /* Percetual Source Gamut and Perceptual/Saturation Gamut Maping mode enable */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ if (argv[fa][1] == 'S')
+ sepsat = 1;
+ if (na == NULL)
+ usage("Unrecognised argument to source gamut flag -%c",argv[fa][1]);
+
+ fa = nfa;
+ strncpy(ipname,na,MAXNAMEL); ipname[MAXNAMEL] = '\000';
+ }
+
+ /* Source image gamut */
+ else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') {
+ if (na == NULL)
+ usage("Unrecognised argument to source image gamut flag -g",argv[fa][1]);
+ fa = nfa;
+ strncpy(sgname,na,MAXNAMEL); sgname[MAXNAMEL] = '\000';
+ }
+
+ /* Abstract profile */
+ else if (argv[fa][1] == 'p') {
+ char *f1 = NULL, *f2 = NULL;
+ if (na == NULL) usage("Expected abstract profile filename after -p");
+ fa = nfa;
+ strncpy(absstring,na,MAXNAMEL*3); absstring[MAXNAMEL*3] = '\000';
+ if ((f1 = strchr(absstring, ',')) == NULL) { /* Only one profile */
+ absnames[2] = absnames[1] = absnames[0] = absstring; /* Duplicate */
+ } else { /* At least one comma */
+ *f1++ = '\000';
+ if ((f2 = strchr(f1, ',')) != NULL) /* Two commas */
+ *f2++ = '\000';
+ if (*absstring != '\000')
+ absnames[0] = absstring;
+ if (*f1 != '\000')
+ absnames[1] = f1;
+ if (f2 != NULL && *f2 != '\000')
+ absnames[2] = f2;
+ }
+ }
+
+ /* Perceptual Mapping intent override */
+ else if (argv[fa][1] == 't') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to perceptul intent override flag -t");
+ if (xicc_enum_gmapintent(&pgmi, icxNoGMIntent, na) == icxIllegalGMIntent)
+ usage("Unrecognised intent '%s' to perceptual override flag -t",na);
+ pgmi_set = 1;
+ }
+
+ /* Saturation Mapping intent override */
+ else if (argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to saturation intent override flag -T");
+ if (xicc_enum_gmapintent(&sgmi, icxNoGMIntent, na) == icxIllegalGMIntent)
+ usage("Unrecognised intent '%s' to saturation override flag -T",na);
+ sgmi_set = 1;
+ }
+
+ /* Viewing conditions */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'd') {
+ icxViewCond *vc;
+
+ if (argv[fa][1] == 'c') {
+ vc = &ivc_p;
+ } else {
+ vc = &ovc_p;
+ }
+
+ fa = nfa;
+ if (na == NULL) usage("Viewing conditions flag (-c) needs an argument");
+ if (na[1] != ':') {
+ if (vc == &ivc_p) {
+ if ((ivc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
+ usage("Urecognised Enumerated Viewing conditions '%s'",na);
+ } else {
+ if ((ovc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
+ usage("Urecognised Enumerated Viewing conditions '%s'",na);
+ }
+ } else if (na[0] == 's' || na[0] == 'S') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-cs) missing ':'");
+ if (na[2] == 'n' || na[2] == 'N') {
+ vc->Ev = vc_none; /* Automatic */
+ } else if (na[2] == 'a' || na[2] == 'A') {
+ vc->Ev = vc_average;
+ } else if (na[2] == 'm' || na[2] == 'M') {
+ vc->Ev = vc_dim;
+ } else if (na[2] == 'd' || na[2] == 'D') {
+ vc->Ev = vc_dark;
+ } else if (na[2] == 'c' || na[2] == 'C') {
+ vc->Ev = vc_cut_sheet;
+ } else
+ usage("Viewing condition (-c) unrecognised surround '%c'",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) {
+ vc->Wxyz[0] = x; vc->Wxyz[1] = y; vc->Wxyz[2] = z;
+ } 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);
+ } else if (na[0] == 'a' || na[0] == 'A') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-ca) missing ':'");
+ vc->La = atof(na+2);
+ } else if (na[0] == 'b' || na[0] == 'B') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-cb) missing ':'");
+ vc->Yb = atof(na+2)/100.0;
+ } else if (na[0] == 'l' || na[0] == 'L') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-[cd]l) missing ':'");
+ vc->Lv = atof(na+2);
+ } else if (na[0] == 'f' || na[0] == 'F') {
+ 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;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc->Fxyz[0] = x; vc->Fxyz[1] = y;
+ } else if (sscanf(na+1,":%lf",&x) == 1) {
+ vc->Yf = x/100.0;
+ } else
+ usage("Viewing condition (-cf) unrecognised flare '%s'",na+1);
+ } else
+ usage("Viewing condition (-c) unrecognised sub flag '%c'",na[0]);
+ }
+
+ /* Gammut mapping diagnostic plots */
+ else if (argv[fa][1] == 'P')
+ gamdiag = 1;
+
+ /* Output file name */
+ else if (argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage("Output filename override (-O) needs an argument");
+ strncpy(outname,na,MAXNAMEL); outname[MAXNAMEL] = '\000';
+ }
+
+ else
+ usage("Unknown flag '%c'",argv[fa][1]);
+ } else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing input .ti3 and output ICC basename");
+ strncpy(baname,argv[fa++],MAXNAMEL-4); baname[MAXNAMEL-4] = '\000';
+ if (xpi.profDesc == NULL)
+ xpi.profDesc = baname; /* Default description */
+ strcpy(inname,baname);
+ strcat(inname,".ti3");
+ if (outname[0] == '\000') { /* If not overridden */
+ strcpy(outname,baname);
+ strcat(outname,ICC_FILE_EXT);
+ }
+
+ /* Issue some errors & warnings for strange combinations */
+ if (fwacomp && spec == 0)
+ error("FWA compensation only works when viewer and/or illuminant selected");
+
+ if (pgmi_set && ipname[0] == '\000')
+ warning("-t perceptual intent override only works if -s srcprof or -S srcprof is used");
+
+ if (sgmi_set && ipname[0] == '\000')
+ warning("-T saturation intent override only works if -S srcprof is used");
+
+ if (sgmi_set && sepsat == 0) { /* Won't do much otherwise */
+ if (verb)
+ printf("Saturation intent override was set, so adding saturation intent table\n");
+ sepsat = 1;
+ }
+
+ if (gamdiag && ipname[0] == '\000')
+ warning("no gamut mapping called for, so -P will produce nothing");
+
+ if (sgname[0] != '\000' && ipname[0] == '\000')
+ warning("-g srcgam will do nothing without -s srcprof or -S srcprof");
+
+ if (oquality == -1) { /* B2A tables will be used */
+ oquality = iquality;
+ }
+
+ /* Open and look at the .ti3 profile patches file */
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI3"); /* our special input type is Calibration Target Information 3 */
+ icg->add_other(icg, "CAL"); /* our special device Calibration state */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI3 format file");
+ if (icg->ntables < 1)
+ error ("Input file doesn't contain at least one table");
+
+ /* See if CIE is actually available - some sources of .TI3 don't provide it */
+ if (!spec
+ && icg->find_field(icg, 0, "LAB_L") < 0
+ && icg->find_field(icg, 0, "XYZ_X") < 0) {
+
+ if (icg->find_kword(icg, 0, "SPECTRAL_BANDS") < 0)
+ error("Neither CIE nor spectral data found in file '%s'",inname);
+
+ /* Switch to using spectral information */
+ if (verb)
+ printf("No CIE data found, switching to spectral with standard observer & D50\n");
+ spec = 1;
+ illum = icxIT_D50;
+ observ = icxOT_CIE_1931_2;
+ }
+
+ /* If we requested spectral, check that it is available */
+ if (spec) {
+ if (icg->find_kword(icg, 0, "SPECTRAL_BANDS") < 0)
+ error ("Requested spectral interpretation when data not available");
+ }
+
+ /* 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");
+
+ if (strcmp(icg->t[0].kdata[ti],"OUTPUT") == 0) {
+ icxInk ink; /* Ink parameters */
+
+ if ((ti = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0) {
+ int imax;
+ imax = atoi(icg->t[0].kdata[ti]);
+ if (imax > 0 && imax <= 400.0) {
+ if (tlimit > 0 && tlimit <= 400.0) { /* User has specified limit as option */
+ if (imax < tlimit) {
+ warning("Ink limit greater than original chart! (%d%% > %d%%)",tlimit,imax);
+ }
+ } else {
+ if (imax > 80.0)
+ tlimit = (int)imax - 10; /* Rule of thumb - 10% below chart maximum */
+ else
+ tlimit = (int)imax;
+ }
+ }
+ }
+
+ /* (Note that this isn't set by any of the Argyll tools currently, */
+ /* but can be set manually.) */
+ if ((ti = icg->find_kword(icg, 0, "BLACK_INK_LIMIT")) >= 0) {
+ int kmax;
+ kmax = atoi(icg->t[0].kdata[ti]);
+ if (kmax > 0 && kmax <= 100.0) {
+ if (klimit > 0 && klimit <= 100.0) { /* User has specified limit as option */
+ if (kmax < klimit) {
+ warning("Black ink limit greater than original chart! (%d%% > %d%%)",klimit,kmax);
+ }
+ } else {
+ klimit = (int)kmax;
+ }
+ }
+ }
+
+ if (tlimit >= 0 && tlimit < 400.0) {
+ if (verb)
+ printf("Total ink limit being used is %d%%\n",tlimit);
+ ink.tlimit = tlimit/100.0; /* Set a total ink limit */
+ } else {
+ if (verb)
+ printf("No total ink limit being used\n");
+ ink.tlimit = -1.0; /* Don't use a limit */
+ }
+
+ if (klimit >= 0 && klimit < 100.0) {
+ if (verb)
+ printf("Black ink limit being used is %d%%\n",klimit);
+ ink.klimit = klimit/100.0; /* Set a black ink limit */
+ } else {
+ if (verb)
+ printf("No black ink limit being used\n");
+ ink.klimit = -1.0; /* Don't use a limit */
+ }
+
+ ink.KonlyLmin = 0; /* Use normal black Lmin for locus */
+ ink.c.Ksmth = ICXINKDEFSMTH; /* default black curve smoothing */
+ ink.c.Kskew = ICXINKDEFSKEW; /* default black curve skew */
+ ink.x.Ksmth = ICXINKDEFSMTH;
+ ink.x.Kskew = ICXINKDEFSKEW;
+
+ if (inking == 0) { /* Use minimum */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = 0.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 0.0;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 1) { /* Use 0.5 */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = 0.5;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 0.5;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 2) { /* Use maximum */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = 1.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 1.0;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 3) { /* Use ramp */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = 0.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 1.0;
+ ink.c.Kshap = 1.0;
+ } else { /* Use specified curve */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = Kstle;
+ ink.c.Kstpo = Kstpo;
+ ink.c.Kenpo = Kenpo;
+ ink.c.Kenle = Kenle;
+ ink.c.Kshap = Kshap;
+ }
+
+ if (ptype == prof_default)
+ ptype = prof_clutLab;
+ else if (ptype != prof_clutLab && ptype != prof_clutXYZ) {
+ error ("Output profile can only be a cLUT algorithm");
+ }
+
+ if (autowpsc)
+ error ("Input auto WP scale mode isn't applicable to an output device");
+ if (clipovwp)
+ error ("Input cLUT clipping above WP mode isn't applicable to an output device");
+
+ make_output_icc(ptype, 0, iccver, verb, iquality, oquality,
+ noisluts, noipluts, nooluts, nocied, noptop, nostos,
+ gamdiag, verify, clipprims, &ink, inname, outname, icg,
+ spec, tillum, &cust_tillum, illum, &cust_illum, observ, fwacomp,
+ smooth, avgdev,
+ ipname[0] != '\000' ? ipname : NULL,
+ sgname[0] != '\000' ? sgname : NULL,
+ absnames,
+ sepsat, &ivc_p, &ovc_p, ivc_e, ovc_e,
+ &pgmi, &sgmi, &xpi);
+
+ } else if (strcmp(icg->t[0].kdata[ti],"INPUT") == 0) {
+
+ if (ptype == prof_default)
+ ptype = prof_clutLab; /* For best possible quality */
+
+ if (clipovwp && ptype != prof_clutLab && ptype != prof_clutXYZ)
+ error ("Input cLUT clipping above WP mode isn't applicable to a matrix profile");
+
+ make_input_icc(ptype, iccver, verb, iquality, oquality, noisluts, noipluts, nooluts, nocied,
+ verify, autowpsc, clipovwp, iwpscale, doinb2a, doinextrap, clipprims,
+ inname, outname, icg, spec, illum, &cust_illum, observ,
+ smooth, avgdev, &xpi);
+
+ } else if (strcmp(icg->t[0].kdata[ti],"DISPLAY") == 0) {
+
+ if (autowpsc)
+ error ("Input auto WP scale mode isn't applicable to an output device");
+ if (clipovwp)
+ error ("Input cLUT clipping above WP mode isn't applicable to an output device");
+
+ if (fwacomp)
+ error ("FWA compensation isn't applicable to a display device");
+
+ if (ptype == prof_default)
+ ptype = prof_clutLab; /* ?? or should it default to prof_shamat ?? */
+
+ /* 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,
+ spec, icxIT_none, NULL, illum, &cust_illum, observ, 0,
+ smooth, avgdev,
+ ipname[0] != '\000' ? ipname : NULL,
+ sgname[0] != '\000' ? sgname : NULL,
+ absnames,
+ sepsat, &ivc_p, &ovc_p, ivc_e, ovc_e,
+ &pgmi, &sgmi, &xpi);
+
+ } else
+ error ("Input file keyword DEVICE_CLASS has unknown value");
+
+ icg->del(icg); /* Clean up */
+
+#ifdef DO_TIME /* Time the operation */
+ ttime = clock() - stime;
+ printf("Exectution time = %f seconds\n",(double)ttime/(double)CLOCKS_PER_SEC);
+#endif /* DO_TIME */
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/profile/example.sp b/profile/example.sp
new file mode 100644
index 0000000..08d836e
--- /dev/null
+++ b/profile/example.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll Example Spectral power/reflectance information (D50)"
+ORIGINATOR "Argyll CMS"
+CREATED "Fri Jul 06 17:49:57 2001"
+# If you want the FWA compensation to work properly, you need to specify your
+# light source down to 300nm
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.020000 1.0300 2.0500 4.9100 7.7800 11.260 14.750 16.350 17.950 19.480 21.010 22.480 23.940 25.450 26.960 25.720 24.490 27.180 29.870 39.590 49.310 52.910 56.510 58.270 60.030 58.930 57.820 66.320 74.820 81.040 87.250 88.930 90.610 90.990 91.370 93.240 95.110 93.540 91.960 93.840 95.720 96.170 96.610 96.870 97.130 99.610 102.10 101.43 100.75 101.54 102.32 101.16 100.00 98.870 97.740 98.330 98.920 96.210 93.500 95.590 97.690 98.480 99.270 99.160 99.040 97.380 95.720 97.290 98.860 97.260 95.670 96.930 98.190 100.60 103.00 101.07 99.130 93.260 87.380 89.490 91.600 92.250 92.890 84.870 76.850 81.680 86.510 89.550 92.580 85.400 78.230 67.960 57.690 70.310 82.920 80.600 78.270 78.910 79.550 76.480 73.400 68.660 63.920 67.350 70.780 72.610 74.440
+END_DATA
diff --git a/profile/example121.sp b/profile/example121.sp
new file mode 100644
index 0000000..d139c38
--- /dev/null
+++ b/profile/example121.sp
@@ -0,0 +1,147 @@
+SPECT
+
+DESCRIPTOR "Argyll Example Spectral power/reflectance information with 121 bands from an i1 pro (Fluorescent lamp)"
+ORIGINATOR "Argyll CMS"
+CREATED "Wed Sep 12 16:45:26 2007"
+# If you want the FWA compensation to work properly, you need to specify your
+# light source down to 300nm
+
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "121"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "350"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100"
+
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_353"
+KEYWORD "SPEC_357"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_363"
+KEYWORD "SPEC_367"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_373"
+KEYWORD "SPEC_377"
+KEYWORD "SPEC_380"
+KEYWORD "SPEC_383"
+KEYWORD "SPEC_387"
+KEYWORD "SPEC_390"
+KEYWORD "SPEC_393"
+KEYWORD "SPEC_397"
+KEYWORD "SPEC_400"
+KEYWORD "SPEC_403"
+KEYWORD "SPEC_407"
+KEYWORD "SPEC_410"
+KEYWORD "SPEC_413"
+KEYWORD "SPEC_417"
+KEYWORD "SPEC_420"
+KEYWORD "SPEC_423"
+KEYWORD "SPEC_427"
+KEYWORD "SPEC_430"
+KEYWORD "SPEC_433"
+KEYWORD "SPEC_437"
+KEYWORD "SPEC_440"
+KEYWORD "SPEC_443"
+KEYWORD "SPEC_447"
+KEYWORD "SPEC_450"
+KEYWORD "SPEC_453"
+KEYWORD "SPEC_457"
+KEYWORD "SPEC_460"
+KEYWORD "SPEC_463"
+KEYWORD "SPEC_467"
+KEYWORD "SPEC_470"
+KEYWORD "SPEC_473"
+KEYWORD "SPEC_477"
+KEYWORD "SPEC_480"
+KEYWORD "SPEC_483"
+KEYWORD "SPEC_487"
+KEYWORD "SPEC_490"
+KEYWORD "SPEC_493"
+KEYWORD "SPEC_497"
+KEYWORD "SPEC_500"
+KEYWORD "SPEC_503"
+KEYWORD "SPEC_507"
+KEYWORD "SPEC_510"
+KEYWORD "SPEC_513"
+KEYWORD "SPEC_517"
+KEYWORD "SPEC_520"
+KEYWORD "SPEC_523"
+KEYWORD "SPEC_527"
+KEYWORD "SPEC_530"
+KEYWORD "SPEC_533"
+KEYWORD "SPEC_537"
+KEYWORD "SPEC_540"
+KEYWORD "SPEC_543"
+KEYWORD "SPEC_547"
+KEYWORD "SPEC_550"
+KEYWORD "SPEC_553"
+KEYWORD "SPEC_557"
+KEYWORD "SPEC_560"
+KEYWORD "SPEC_563"
+KEYWORD "SPEC_567"
+KEYWORD "SPEC_570"
+KEYWORD "SPEC_573"
+KEYWORD "SPEC_577"
+KEYWORD "SPEC_580"
+KEYWORD "SPEC_583"
+KEYWORD "SPEC_587"
+KEYWORD "SPEC_590"
+KEYWORD "SPEC_593"
+KEYWORD "SPEC_597"
+KEYWORD "SPEC_600"
+KEYWORD "SPEC_603"
+KEYWORD "SPEC_607"
+KEYWORD "SPEC_610"
+KEYWORD "SPEC_613"
+KEYWORD "SPEC_617"
+KEYWORD "SPEC_620"
+KEYWORD "SPEC_623"
+KEYWORD "SPEC_627"
+KEYWORD "SPEC_630"
+KEYWORD "SPEC_633"
+KEYWORD "SPEC_637"
+KEYWORD "SPEC_640"
+KEYWORD "SPEC_643"
+KEYWORD "SPEC_647"
+KEYWORD "SPEC_650"
+KEYWORD "SPEC_653"
+KEYWORD "SPEC_657"
+KEYWORD "SPEC_660"
+KEYWORD "SPEC_663"
+KEYWORD "SPEC_667"
+KEYWORD "SPEC_670"
+KEYWORD "SPEC_673"
+KEYWORD "SPEC_677"
+KEYWORD "SPEC_680"
+KEYWORD "SPEC_683"
+KEYWORD "SPEC_687"
+KEYWORD "SPEC_690"
+KEYWORD "SPEC_693"
+KEYWORD "SPEC_697"
+KEYWORD "SPEC_700"
+KEYWORD "SPEC_703"
+KEYWORD "SPEC_707"
+KEYWORD "SPEC_710"
+KEYWORD "SPEC_713"
+KEYWORD "SPEC_717"
+KEYWORD "SPEC_720"
+KEYWORD "SPEC_723"
+KEYWORD "SPEC_727"
+KEYWORD "SPEC_730"
+KEYWORD "SPEC_733"
+KEYWORD "SPEC_737"
+KEYWORD "SPEC_740"
+KEYWORD "SPEC_743"
+KEYWORD "SPEC_747"
+KEYWORD "SPEC_750"
+NUMBER_OF_FIELDS 121
+BEGIN_DATA_FORMAT
+SPEC_350 SPEC_353 SPEC_357 SPEC_360 SPEC_363 SPEC_367 SPEC_370 SPEC_373 SPEC_377 SPEC_380 SPEC_383 SPEC_387 SPEC_390 SPEC_393 SPEC_397 SPEC_400 SPEC_403 SPEC_407 SPEC_410 SPEC_413 SPEC_417 SPEC_420 SPEC_423 SPEC_427 SPEC_430 SPEC_433 SPEC_437 SPEC_440 SPEC_443 SPEC_447 SPEC_450 SPEC_453 SPEC_457 SPEC_460 SPEC_463 SPEC_467 SPEC_470 SPEC_473 SPEC_477 SPEC_480 SPEC_483 SPEC_487 SPEC_490 SPEC_493 SPEC_497 SPEC_500 SPEC_503 SPEC_507 SPEC_510 SPEC_513 SPEC_517 SPEC_520 SPEC_523 SPEC_527 SPEC_530 SPEC_533 SPEC_537 SPEC_540 SPEC_543 SPEC_547 SPEC_550 SPEC_553 SPEC_557 SPEC_560 SPEC_563 SPEC_567 SPEC_570 SPEC_573 SPEC_577 SPEC_580 SPEC_583 SPEC_587 SPEC_590 SPEC_593 SPEC_597 SPEC_600 SPEC_603 SPEC_607 SPEC_610 SPEC_613 SPEC_617 SPEC_620 SPEC_623 SPEC_627 SPEC_630 SPEC_633 SPEC_637 SPEC_640 SPEC_643 SPEC_647 SPEC_650 SPEC_653 SPEC_657 SPEC_660 SPEC_663 SPEC_667 SPEC_670 SPEC_673 SPEC_677 SPEC_680 SPEC_683 SPEC_687 SPEC_690 SPEC_693 SPEC_697 SPEC_700 SPEC_703 SPEC_707 SPEC_710 SPEC_713 SPEC_717 SPEC_720 SPEC_723 SPEC_727 SPEC_730 SPEC_733 SPEC_737 SPEC_740 SPEC_743 SPEC_747 SPEC_750
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+-0.041690 0.24392 4.3572 5.4017 6.5222 7.0710 8.6925 12.563 16.482 18.309 17.829 17.021 16.072 16.687 87.378 282.88 411.34 306.20 188.94 221.27 286.97 368.32 461.52 591.86 962.15 2078.2 2435.7 1583.7 985.14 1000.3 1013.1 1010.9 994.64 967.45 926.07 875.50 826.62 776.65 728.56 729.41 894.38 1230.5 1346.3 1108.1 831.25 636.32 518.37 473.21 477.58 492.45 491.10 457.30 399.25 348.62 326.58 367.02 707.07 1919.0 3813.6 4662.9 3291.3 1432.5 513.04 229.68 141.83 108.25 90.996 144.02 387.80 680.40 822.45 858.52 763.41 621.14 498.90 391.19 345.59 749.61 2255.0 3078.6 1993.9 866.06 750.13 785.14 718.71 498.72 228.97 128.41 127.71 158.54 217.06 231.70 191.86 166.43 164.48 146.81 124.29 112.00 109.04 115.61 129.27 146.74 143.18 117.28 87.783 80.151 141.77 286.25 374.19 308.51 156.95 59.626 32.257 32.390 32.801 33.930 35.539 37.845 36.214 31.438 23.866
+END_DATA
diff --git a/profile/invprofcheck.c b/profile/invprofcheck.c
new file mode 100644
index 0000000..0965096
--- /dev/null
+++ b/profile/invprofcheck.c
@@ -0,0 +1,733 @@
+
+/*
+ * Argyll Color Correction System
+ * Inverse profile checker.
+ *
+ * Author: Graeme W. Gill
+ * Date: 1999/11/29
+ *
+ * Copyright 1999 - 2005 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.
+ */
+
+/*
+ * This program takes checks the round trip errors of
+ * the colorimetric forward and inverse profile direction
+ * of an ICC profile.
+ * (Was called icc/fbtest.c)
+ */
+
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xicc.h"
+
+/* Resolution of the sampling modes */
+#define TRES 11
+#define HTRES 27
+#define UHTRES 61
+
+/* ------------------------------------------------------- */
+/* Macros for an di or fdi dimensional counter */
+/* Declare the counter name nn, dimensions di, & count */
+
+#define DCOUNT(nn, di, start, reset, count) \
+ int nn[MAX_CHAN]; /* counter value */ \
+ int nn##_di = (di); /* Number of dimensions */ \
+ int nn##_stt = (start); /* start count value */ \
+ int nn##_rst = (reset); /* reset on carry value */ \
+ int nn##_res = (count); /* last count +1 */ \
+ int nn##_e /* dimension index */
+
+/* Set the counter value to 0 */
+#define DC_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
+ nn[nn##_e] = nn##_stt; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define DC_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < nn##_res) \
+ break; /* No carry */ \
+ nn[nn##_e] = nn##_rst; \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define DC_DONE(nn) \
+ (nn##_e >= nn##_di)
+
+/* ---------------------------------------- */
+
+void usage(void) {
+ fprintf(stderr,"Check fwd to bwd relative transfer of an ICC file, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: invprofcheck [-] profile.icm\n");
+ fprintf(stderr," -v [level] verbosity level (default 1), 2 to print each DE\n");
+ fprintf(stderr," -l limit set total ink limit (estimate by default)\n");
+ fprintf(stderr," -L klimit set black channel ink limit (estimate by default)\n");
+ fprintf(stderr," -h high res test (%d)\n",HTRES);
+ fprintf(stderr," -u Ultra high res test (%d)\n",UHTRES);
+ fprintf(stderr," -R res Specific grid resolution\n");
+ fprintf(stderr," -c Show CIE94 delta E values\n");
+ fprintf(stderr," -k Show CIEDE2000 delta E values\n");
+ fprintf(stderr," -w create VRML visualisation (profile.wrl)\n");
+ fprintf(stderr," -x Use VRML axes\n");
+ fprintf(stderr," -e Color vectors acording to delta E\n");
+ fprintf(stderr," profile.icm Profile to check\n");
+ exit(1);
+}
+
+FILE *start_vrml(char *name, int doaxes);
+void start_line_set(FILE *wrl);
+void add_vertex(FILE *wrl, double pp[3]);
+void make_lines(FILE *wrl, int ppset);
+void make_de_lines(FILE *wrl);
+void end_vrml(FILE *wrl);
+
+#if defined(__IBMC__) && defined(_M_IX86)
+void bug_workaround(int *co) { }; /* Workaround optimiser bug */
+#endif
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int cie94 = 0;
+ int cie2k = 0;
+ int dovrml = 0;
+ int doaxes = 0;
+ int dodecol = 0;
+ char in_name[MAXNAMEL+1];
+ char out_name[MAXNAMEL+1], *xl; /* VRML name */
+ icmFile *rd_fp;
+ icc *icco;
+ int rv = 0;
+ int tres = TRES;
+ double tlimit = -1.0;
+ double klimit = -1.0;
+ FILE *wrl = NULL;
+
+ error_program = "invprofcheck";
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ if (na != NULL && isdigit(na[0])) {
+ verb = atoi(na);
+ }
+ }
+
+ /* Resolution */
+ else if (argv[fa][1] == 'h' || argv[fa][1] == 'H') {
+ tres = HTRES;
+
+ }
+ /* Resolution */
+ else if (argv[fa][1] == 'u' || argv[fa][1] == 'U') {
+ tres = UHTRES;
+ }
+
+ /* Resolution */
+ else if (argv[fa][1] == 'R') {
+ int res;
+ fa = nfa;
+ if (na == NULL) usage();
+ res = atoi(na);
+ if (res < 2 || res > 500)
+ usage();
+ tres = res;
+ }
+
+ else if (argv[fa][1] == 'l') {
+ int limit;
+ fa = nfa;
+ if (na == NULL) usage();
+ limit = atoi(na);
+ if (limit < 1)
+ limit = 1;
+ tlimit = limit/100.0;
+ }
+
+ else if (argv[fa][1] == 'L') {
+ int limit;
+ fa = nfa;
+ if (na == NULL) usage();
+ limit = atoi(na);
+ if (limit < 1)
+ limit = 1;
+ klimit = limit/100.0;
+ }
+
+ /* VRML */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W')
+ dovrml = 1;
+
+ /* Axes */
+ else if (argv[fa][1] == 'x' || argv[fa][1] == 'X')
+ doaxes = 1;
+
+ /* Delta E coloring */
+ else if (argv[fa][1] == 'e' || argv[fa][1] == 'E')
+ dodecol = 1;
+
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ cie94 = 1;
+ cie2k = 0;
+ }
+
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ cie94 = 0;
+ cie2k = 1;
+ }
+
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+
+ strncpy(out_name,in_name,MAXNAMEL-4); out_name[MAXNAMEL-4] = '\000';
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".wrl");
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = icco->read(icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,icco->err);
+
+ /* Check the forward lookup against the bwd function */
+ {
+ xcal *cal = NULL; /* Device calibration curves */
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces of fwd */
+ int inn, outn; /* Channels of fwd conversion */
+ int kch; /* Black channel, -1 if not known/applicable */
+ icmLuBase *luo1, *luo2;
+ double merr = 0.0; /* Max */
+ double aerr = 0.0; /* Avg */
+ double rerr = 0.0; /* RMS */
+ double nsamps = 0.0;
+
+ /* Get a Device to PCS conversion object */
+ if ((luo1 = icco->get_luobj(icco, icmFwd, icRelativeColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((luo1 = icco->get_luobj(icco, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",icco->errc, icco->err);
+ }
+ /* Get details of conversion */
+ luo1->spaces(luo1, &ins, &inn, &outs, &outn, NULL, NULL, NULL, NULL, NULL);
+
+ /* Get a PCS to Device conversion object */
+ if ((luo2 = icco->get_luobj(icco, icmBwd, icRelativeColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((luo2 = icco->get_luobj(icco, icmBwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",icco->errc, icco->err);
+ }
+
+ if (dovrml) {
+ wrl = start_vrml(out_name, doaxes);
+ start_line_set(wrl);
+ }
+
+ /* Grab any device calibration curves */
+ cal = xiccReadCalTag(icco);
+
+ kch = icxGuessBlackChan(icco);
+
+ /* Set the default ink limits if not set by user */
+ if (tlimit < 0.0 || klimit < 0.0) {
+ double max[MAX_CHAN], total;
+
+ total = icco->get_tac(icco, max, cal != NULL ? xiccCalCallback : NULL, (void *)cal);
+
+ if (tlimit < 0.0)
+ tlimit = total;
+
+ if (klimit < 0.0 && kch >= 0)
+ klimit = max[kch];
+ }
+
+ if (verb) {
+ printf("Grid resolution is %d\n",tres);
+ if (tlimit >= 0.0)
+ printf("Input total ink limit assumed is %3.1f%%\n",100.0 * tlimit);
+ if (klimit >= 0.0)
+ printf("Input black ink limit assumed is %3.1f%%\n",100.0 * klimit);
+ }
+
+ {
+ double dev[MAX_CHAN], cdev[MAX_CHAN], pcsin[3], devout[MAX_CHAN], pcsout[3];
+ DCOUNT(co, inn, 0, 0, tres); /* Multi-D counter */
+
+ /* Go through the chosen device grid */
+ DC_INIT(co)
+ for (; !DC_DONE(co);) {
+ int n, rv1, rv2;
+ double sum;
+ double de;
+
+ /* Check the (possibly calibrated) device values */
+ /* end reject any over the limits. */
+ for (sum = 0, n = 0; n < inn; n++) {
+ cdev[n] = dev[n] = co[n]/(tres-1.0);
+ sum += cdev[n];
+ }
+ if (cal != NULL) {
+ cal->interp(cal, cdev, dev);
+ for (sum = 0, n = 0; n < inn; n++)
+ sum += cdev[n];
+ }
+
+ if ((tlimit > 0.0 && sum > tlimit)
+ || (klimit > 0.0 && kch >= 0 && cdev[kch] > klimit)) {
+ DC_INC(co);
+ continue;
+ }
+
+ /* Generate the in-gamut PCS test point */
+ /* by converting device to pcsin */
+ if ((rv1 = luo1->lookup(luo1, pcsin, dev)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ /* Now do the check */
+ /* PCS -> Device */
+ if ((rv2 = luo2->lookup(luo2, devout, pcsin)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ /* Device to PCS */
+ if ((rv2 = luo1->lookup(luo1, pcsout, devout)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ /* Delta E */
+ if (dovrml) {
+ add_vertex(wrl, pcsin);
+ add_vertex(wrl, pcsout);
+ }
+
+ /* Check the result */
+ if (cie2k)
+ de = icmCIE2K(pcsout, pcsin);
+ else if (cie94)
+ de = icmCIE94(pcsout, pcsin);
+ else
+ de = icmLabDE(pcsout, pcsin);
+
+ aerr += de;
+ rerr += de * de;
+ if (de > merr)
+ merr = de;
+ nsamps++;
+
+ if (verb > 1) {
+ printf("[%f] %f %f %f -> ",de, pcsin[0], pcsin[1], pcsin[2]);
+ for (n = 0; n < inn; n++)
+ printf("%f ",devout[n]);
+ printf("-> %f %f %f\n",pcsout[0], pcsout[1], pcsout[2]);
+ }
+
+ DC_INC(co);
+ }
+ }
+ if (dovrml) {
+ if (dodecol)
+ make_de_lines(wrl);
+ else
+ make_lines(wrl, 2);
+ end_vrml(wrl);
+ }
+
+ printf("Profile check complete, errors%s: max. = %f, avg. = %f, RMS = %f\n",
+ cie2k ? "(CIEDE2000)" : cie94 ? " (CIE94)" : "", merr, aerr/nsamps, sqrt(rerr/nsamps));
+
+ /* Done with lookup object */
+ luo1->del(luo1);
+ luo2->del(luo2);
+ }
+
+ icco->del(icco);
+ rd_fp->del(rd_fp);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------ */
+/* Some simple functions to do basix VRML work */
+/* !!! Should change to plot/vrml lib !!! */
+
+#define GAMUT_LCENT 50.0
+static int npoints = 0;
+static int paloc = 0;
+static struct { double pp[3]; } *pary;
+
+static void Lab2RGB(double *out, double *in);
+static void DE2RGB(double *out, double in);
+
+FILE *start_vrml(char *name, int doaxes) {
+ FILE *wrl;
+
+ /* Define the axis boxes */
+ struct {
+ double x, y, z; /* Box center */
+ double wx, wy, wz; /* Box size */
+ double r, g, b; /* Box color */
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+
+ /* Define the labels */
+ struct {
+ double x, y, z;
+ double size;
+ char *string;
+ double r, g, b;
+ } labels[6] = {
+ { -2, 2, -GAMUT_LCENT + 100 + 10, 10, "+L*", .7, .7, .7 }, /* Top of L axis */
+ { -2, 2, -GAMUT_LCENT - 10, 10, "0", .7, .7, .7 }, /* Bottom of L axis */
+ { 100 + 5, -3, 0-GAMUT_LCENT, 10, "+a*", 1, 0, 0 }, /* +a (red) axis */
+ { -5, -100 - 10, 0-GAMUT_LCENT, 10, "-b*", 0, 0, 1 }, /* -b (blue) axis */
+ { -100 - 15, -3, 0-GAMUT_LCENT, 10, "-a*", 0, 0, 1 }, /* -a (green) axis */
+ { -5, 100 + 5, 0-GAMUT_LCENT, 10, "+b*", 1, 1, 0 }, /* +b (yellow) axis */
+ };
+
+ if ((wrl = fopen(name,"w")) == NULL)
+ error("Error opening VRML file '%s'\n",name);
+
+ npoints = 0;
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ int n;
+ fprintf(wrl," # Lab axes as boxes:\n");
+ for (n = 0; n < 5; n++) {
+ fprintf(wrl," Transform { translation %f %f %f\n", axes[n].x, axes[n].y, axes[n].z);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape{\n");
+ fprintf(wrl," geometry Box { size %f %f %f }\n",
+ axes[n].wx, axes[n].wy, axes[n].wz);
+ fprintf(wrl," appearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[n].r, axes[n].g, axes[n].b);
+ fprintf(wrl," }\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+ fprintf(wrl," # Axes identification:\n");
+ for (n = 0; n < 6; n++) {
+ fprintf(wrl," Transform { translation %f %f %f\n", labels[n].x, labels[n].y, labels[n].z);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape{\n");
+ fprintf(wrl," geometry Text { string [\"%s\"]\n",labels[n].string);
+ fprintf(wrl," fontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n",
+ labels[n].size);
+ fprintf(wrl," }\n");
+ fprintf(wrl," appearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", labels[n].r, labels[n].g, labels[n].b);
+ fprintf(wrl," }\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+ fprintf(wrl,"\n");
+ }
+
+ return wrl;
+}
+
+void
+start_line_set(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+}
+
+void add_vertex(FILE *wrl, double pp[3]) {
+
+ fprintf(wrl,"%f %f %f,\n",pp[1], pp[2], pp[0]-GAMUT_LCENT);
+
+ if (paloc < (npoints+1)) {
+ paloc = (paloc + 10) * 2;
+ if (pary == NULL)
+ pary = malloc(paloc * 3 * sizeof(double));
+ else
+ pary = realloc(pary, paloc * 3 * sizeof(double));
+
+ if (pary == NULL)
+ error ("Malloc failed");
+ }
+ pary[npoints].pp[0] = pp[0];
+ pary[npoints].pp[1] = pp[1];
+ pary[npoints].pp[2] = pp[2];
+ npoints++;
+}
+
+
+void make_lines(FILE *wrl, int ppset) {
+ int i, j;
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (i = 0; i < npoints;) {
+ for (j = 0; j < ppset; j++, i++) {
+ fprintf(wrl,"%d, ", i);
+ }
+ fprintf(wrl,"-1,\n");
+ }
+ fprintf(wrl," ]\n");
+
+ /* Color */
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < npoints; i++) {
+ double rgb[3], Lab[3];
+ Lab[0] = pary[i].pp[0];
+ Lab[1] = pary[i].pp[1];
+ Lab[2] = pary[i].pp[2];
+ Lab2RGB(rgb, Lab);
+ fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ /* End color */
+
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+}
+
+/* Assume 2 ppset, and make line color prop to length */
+void make_de_lines(FILE *wrl) {
+ int i, j;
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (i = 0; i < npoints;) {
+ for (j = 0; j < 2; j++, i++) {
+ fprintf(wrl,"%d, ", i);
+ }
+ fprintf(wrl,"-1,\n");
+ }
+ fprintf(wrl," ]\n");
+
+ /* Color */
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < npoints; i++) {
+ double rgb[3], ss;
+ for (ss = 0.0, j = 0; j < 3; j++) {
+ double tt = (pary[i & ~1].pp[j] - pary[i | 1].pp[j]);
+ ss += tt * tt;
+ }
+ ss = sqrt(ss);
+ DE2RGB(rgb, ss);
+ fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ /* End color */
+
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+}
+
+void end_vrml(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0)
+ error("Error closing VRML file\n");
+}
+
+
+/* Convert a gamut Lab value to an RGB value for display purposes */
+static void
+Lab2RGB(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+ double R, G, B;
+
+ /* Scale so that black is visible */
+ L = L * (100 - 40.0)/100.0 + 40.0;
+
+ /* First convert to XYZ using D50 white point */
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ x *= 0.9642; /* Multiply by white point, D50 */
+ y *= 1.0;
+ z *= 0.8249;
+
+ /* Now convert to sRGB values */
+ R = x * 3.2410 + y * -1.5374 + z * -0.4986;
+ G = x * -0.9692 + y * 1.8760 + z * 0.0416;
+ B = x * 0.0556 + y * -0.2040 + z * 1.0570;
+
+ if (R < 0.0)
+ R = 0.0;
+ else if (R > 1.0)
+ R = 1.0;
+
+ if (G < 0.0)
+ G = 0.0;
+ else if (G > 1.0)
+ G = 1.0;
+
+ if (B < 0.0)
+ B = 0.0;
+ else if (B > 1.0)
+ B = 1.0;
+
+ R = pow(R, 1.0/2.2);
+ G = pow(G, 1.0/2.2);
+ B = pow(B, 1.0/2.2);
+
+ out[0] = R;
+ out[1] = G;
+ out[2] = B;
+}
+
+/* Convert a delta E value into a signal color: */
+static void
+DE2RGB(double *out, double in) {
+ struct {
+ double de;
+ double r, g, b;
+ } range[6] = {
+ { 10.0, 1, 1, 0 }, /* yellow */
+ { 4.0, 1, 0, 0 }, /* red */
+ { 2.0, 1, 0, 1 }, /* magenta */
+ { 1.0, 0, 0, 1 }, /* blue */
+ { 0.5, 0, 1, 1 }, /* cyan */
+ { 0.0, 0, 1, 0 } /* green */
+ };
+ int i;
+ double bl;
+
+//printf("~1 input de = %f\n",in);
+
+ /* Locate the range we're in */
+ if (in > range[0].de) {
+ out[0] = range[0].r;
+ out[1] = range[0].g;
+ out[2] = range[0].b;
+//printf("~1 too big\n");
+ } else {
+ for (i = 0; i < 5; i++) {
+ if (in <= range[i].de && in >= range[i+1].de)
+ break;
+ }
+ bl = (in - range[i+1].de)/(range[i].de - range[i+1].de);
+//printf("~1 located at ix %d, bl = %f\n",i,bl);
+ out[0] = bl * range[i].r + (1.0 - bl) * range[i+1].r;
+ out[1] = bl * range[i].g + (1.0 - bl) * range[i+1].g;
+ out[2] = bl * range[i].b + (1.0 - bl) * range[i+1].b;
+ }
+//printf("~1 returning rgb %f %f %f\n",out[0],out[1],out[2]);
+}
+
+
diff --git a/profile/kodak2ti3.c b/profile/kodak2ti3.c
new file mode 100644
index 0000000..53278e1
--- /dev/null
+++ b/profile/kodak2ti3.c
@@ -0,0 +1,1273 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Read in the raw data from a Kodak print profile,
+ * and convert it into a .ti3 CGATs format suitable for
+ * the Argyll CMM.
+ *
+ * Derived from spectro.c
+ * Author: Graeme W. Gill
+ * Date: 4/9/00
+ *
+ * Copyright 2000, 2010, 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.
+ */
+
+/* TTBD
+ */
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "icc.h"
+#include <stdarg.h>
+
+void
+usage(void) {
+ fprintf(stderr,"Convert Kodak raw printer profile data to Argyll print data, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: kodak2ti3 [-v] [-l limit] infile outfile\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -l limit set ink limit, 0 - 400%%\n");
+ fprintf(stderr," -r filename Use an alternate 928 patch reference file\n");
+ fprintf(stderr," infile Base name for input.pat file\n");
+ fprintf(stderr," outfile Base name for output.ti3 file\n");
+ exit(1);
+ }
+
+#define NPAT 928
+
+FILE *open_928(char *filename);
+int next_928(FILE *fp, int i, double *CMYK);
+void close_928(FILE *fp);
+
+FILE *open_pat(char *filename);
+int next_pat(FILE *fp, double *Lab);
+void close_pat(FILE *fp);
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ int limit = -1;
+ static char tarname[200] = { 0 }; /* optional 928 patch reference file */
+ static char inname[200] = { 0 }; /* Input .pat file base name */
+ static char outname[200] = { 0 }; /* Output cgats .ti3 file base name */
+ FILE *d928_fp = NULL;
+ FILE *pat_fp;
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+
+ error_program = "kodak2ti3";
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++)
+ {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') /* Look for any flags */
+ {
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else
+ {
+ if ((fa+1) < argc)
+ {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage();
+ limit = atoi(na);
+ if (limit < 1)
+ limit = 1;
+ }
+
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'r') {
+ fa = nfa;
+ if (na == NULL) usage();
+ strcpy(tarname, na);
+ }
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+
+ strcpy(inname,argv[fa++]);
+ strcat(inname,".pat");
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(outname, argv[fa++]);
+ strcat(outname,".ti3");
+
+ /* Open up the Test chart reference file if we were given one */
+ if (tarname[0] != '\000') {
+ if (verb)
+ printf("Using alternate reference file '%s'\n",tarname);
+ if ((d928_fp = open_928(tarname)) == NULL)
+ error ("Read: Can't open file '%s'",tarname);
+ }
+
+ if ((pat_fp = open_pat(inname)) == NULL)
+ error ("Read: Can't open file '%s'",inname);
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll target", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL); /* What sort of device this is */
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+
+ if (limit > 0) {
+ char buf[100];
+ sprintf(buf, "%d", limit);
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT", buf, NULL);
+ }
+
+ ocg->add_field(ocg, 0, "CMYK_C", r_t);
+ ocg->add_field(ocg, 0, "CMYK_M", r_t);
+ ocg->add_field(ocg, 0, "CMYK_Y", r_t);
+ ocg->add_field(ocg, 0, "CMYK_K", r_t);
+ ocg->add_kword(ocg, 0, "COLOR_REP","CMYK_LAB", NULL);
+ ocg->add_field(ocg, 0, "LAB_L", r_t);
+ ocg->add_field(ocg, 0, "LAB_A", r_t);
+ ocg->add_field(ocg, 0, "LAB_B", r_t);
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < NPAT; i++) {
+ char id[100];
+ double cmykv[4];
+ double labv[3];
+
+ if (next_928(d928_fp, i, cmykv) != 0)
+ error("Error reading reference information from '%s' file",tarname);
+
+ if (next_pat(pat_fp, labv) != 0)
+ error("Error reading Kodak .pat file");
+
+ sprintf(id, "%d", i+1);
+ ocg->add_set(ocg, 0, id, 100.0 * cmykv[0], 100.0 * cmykv[1],
+ 100.0 * cmykv[2], 100.0 * cmykv[3],
+ labv[0], labv[1], labv[2]);
+ }
+
+ {
+ double wp[3]; /* Paper white XYZ */
+ double D50wp[3] /* D50 white point Kodak uses */
+ = { 0.9642, 1.0000, 0.8249 };
+ double tt[3];
+ int li;
+
+ /* Get offset of Lab values in cgats file */
+ if ((li = ocg->find_field(ocg, 0, "LAB_L")) < 0)
+ error("Internal - cgats doesn't field LAB_L");
+
+ /* Get last line of pat file - this is the paper white in XYZ */
+ if (next_pat(pat_fp, wp) != 0)
+ error("Error reading Kodak .pat file");
+
+//printf("~1 white point is XYZ %f %f %f\n",wp[0],wp[1],wp[2]);
+
+ /* Run through all the data points, and adjust them back to the absolute */
+ /* white point. */
+
+ for (i = 0; i < NPAT; i++) {
+ double in[3], out[3];
+
+ tt[0] = *((double *)ocg->t[0].fdata[i][li+0]);
+ tt[1] = *((double *)ocg->t[0].fdata[i][li+1]);
+ tt[2] = *((double *)ocg->t[0].fdata[i][li+2]);
+
+ icmLab2XYZ(&icmD50, in, tt);
+
+ /* Undo Kodak's D50->paper white point adjustment */
+ out[0] = in[0] * (D50wp[1] * wp[0])/(D50wp[0] * wp[1]);
+ out[1] = in[1]; /* Y remains unchanged */
+ out[2] = in[2] * (D50wp[1] * wp[2])/(D50wp[2] * wp[1]);
+
+ icmXYZ2Lab(&icmD50, tt, out);
+
+ *((double *)ocg->t[0].fdata[i][li+0]) = tt[0];
+ *((double *)ocg->t[0].fdata[i][li+1]) = tt[1];
+ *((double *)ocg->t[0].fdata[i][li+2]) = tt[2];
+ }
+
+
+ }
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ ocg->del(ocg); /* Clean up */
+
+ if (d928_fp != NULL)
+ close_928(d928_fp);
+ close_pat(pat_fp);
+
+ return 0;
+}
+/* ------------------------------------------------ */
+/* Library to read in a Kodak .pat file */
+
+/* Open the file, return NULL on error */
+FILE *open_pat(char *filename) {
+ FILE *fp;
+ char buf[200];
+
+ if ((fp = fopen(filename,"r")) == NULL)
+ return NULL;
+
+ /* First line should be "KCMSPATCHFILE 2 1" */
+ if (fgets(buf, 200, fp) == NULL)
+ return NULL;
+ if (strncmp(buf, "KCMSPATCHFILE 2 1", strlen("KCMSPATCHFILE 2 1")) != 0) {
+ fclose(fp);
+ return NULL;
+ }
+
+ /* Second line should be "928" */
+ if (fgets(buf, 200, fp) == NULL)
+ return NULL;
+ if (strncmp(buf, "928", strlen("928")) != 0) {
+ fclose(fp);
+ return NULL;
+ }
+
+ return fp;
+}
+
+/* return non-zero on error */
+int next_pat(FILE *fp, double *Lab) {
+ char buf[200];
+
+ if (fgets(buf, 200, fp) == NULL)
+ return 1;
+
+ if (sscanf(buf, "%lf, %lf, %lf", &Lab[0], &Lab[1], &Lab[2]) != 3)
+ return 1;
+
+ return 0;
+}
+
+void close_pat(FILE *fp) {
+ fclose(fp);
+}
+
+/* ------------------------------------------------ */
+/* Library to read in a Kodak CMYK_Large_Target_928 file */
+
+/* default reference values */
+double refvs[NPAT][4] = {
+ { 0.00, 0.00, 0.00, 0.00 },
+ { 0.00, 0.00, 0.00, 0.00 },
+ { 0.00, 0.40, 1.00, 0.60 },
+ { 0.20, 1.00, 0.40, 0.60 },
+ { 0.00, 0.20, 0.70, 0.20 },
+ { 0.00, 1.00, 0.20, 0.20 },
+ { 0.40, 0.20, 0.00, 0.40 },
+ { 0.00, 0.00, 0.30, 0.00 },
+ { 0.00, 1.00, 0.20, 0.40 },
+ { 0.00, 0.70, 0.70, 0.20 },
+ { 0.10, 1.00, 1.00, 0.20 },
+ { 0.70, 0.70, 0.70, 0.40 },
+ { 1.00, 0.00, 0.00, 0.60 },
+ { 0.00, 0.00, 0.00, 0.40 },
+ { 0.03, 0.00, 0.00, 0.00 },
+ { 0.70, 0.20, 0.70, 0.00 },
+ { 0.20, 1.00, 0.10, 0.20 },
+ { 0.40, 0.00, 0.70, 0.00 },
+ { 0.00, 0.10, 0.40, 0.20 },
+ { 0.00, 0.00, 0.00, 0.40 },
+ { 0.40, 0.40, 0.00, 0.60 },
+ { 0.70, 0.10, 0.40, 0.20 },
+ { 0.00, 0.10, 0.20, 0.00 },
+ { 0.10, 0.40, 0.10, 0.00 },
+ { 0.70, 1.00, 0.40, 0.00 },
+ { 0.10, 0.40, 0.70, 0.20 },
+ { 0.70, 0.70, 0.20, 0.20 },
+ { 1.00, 0.40, 0.40, 0.00 },
+ { 1.00, 0.00, 0.70, 0.40 },
+ { 1.00, 0.20, 1.00, 0.40 },
+ { 0.10, 0.00, 0.10, 0.20 },
+ { 0.70, 0.40, 0.40, 0.60 },
+ { 0.10, 1.00, 0.00, 0.20 },
+ { 0.20, 0.10, 0.00, 0.20 },
+ { 0.20, 0.00, 1.00, 0.40 },
+ { 0.00, 1.00, 1.00, 0.70 },
+ { 0.00, 0.70, 1.00, 0.40 },
+ { 0.70, 0.00, 0.40, 0.80 },
+ { 0.20, 0.00, 0.70, 0.40 },
+ { 0.20, 0.00, 0.10, 0.20 },
+ { 0.40, 1.00, 1.00, 0.00 },
+ { 0.90, 0.00, 0.00, 0.00 },
+ { 0.20, 0.00, 1.00, 0.60 },
+ { 0.00, 0.70, 0.20, 0.40 },
+ { 0.40, 0.40, 0.40, 0.60 },
+ { 0.10, 0.20, 0.40, 0.00 },
+ { 0.20, 0.40, 0.20, 0.00 },
+ { 0.00, 0.00, 0.20, 0.00 },
+ { 0.00, 0.00, 0.70, 0.80 },
+ { 1.00, 0.85, 0.85, 0.60 },
+ { 0.00, 0.00, 0.40, 0.00 },
+ { 0.00, 0.40, 0.40, 0.00 },
+ { 0.20, 0.10, 0.20, 0.20 },
+ { 1.00, 0.40, 0.20, 0.40 },
+ { 0.10, 0.06, 0.06, 0.40 },
+ { 0.40, 0.40, 0.70, 0.40 },
+ { 0.70, 1.00, 0.70, 0.60 },
+ { 1.00, 1.00, 0.70, 0.00 },
+ { 0.00, 0.40, 0.70, 0.60 },
+ { 0.40, 0.40, 0.00, 0.20 },
+ { 0.20, 0.40, 0.00, 0.60 },
+ { 0.20, 1.00, 0.40, 0.00 },
+ { 0.40, 0.40, 1.00, 0.80 },
+ { 1.00, 0.00, 0.40, 0.20 },
+ { 1.00, 1.00, 1.00, 0.60 },
+ { 0.20, 0.20, 0.40, 0.00 },
+ { 0.40, 0.70, 0.70, 0.80 },
+ { 0.70, 0.70, 1.00, 0.80 },
+ { 0.00, 1.00, 0.40, 0.60 },
+ { 0.20, 0.00, 0.40, 0.40 },
+ { 0.10, 0.40, 0.10, 0.20 },
+ { 0.70, 0.10, 0.70, 0.00 },
+ { 0.40, 0.70, 0.00, 0.00 },
+ { 0.20, 0.12, 0.12, 0.40 },
+ { 1.00, 0.70, 0.20, 0.00 },
+ { 1.00, 0.40, 0.70, 0.00 },
+ { 0.70, 0.00, 0.70, 0.00 },
+ { 0.70, 0.40, 0.70, 0.40 },
+ { 0.40, 0.40, 0.40, 0.00 },
+ { 0.70, 0.40, 0.20, 0.00 },
+ { 0.70, 0.00, 1.00, 0.00 },
+ { 1.00, 0.40, 0.20, 0.20 },
+ { 0.60, 0.45, 0.45, 0.20 },
+ { 1.00, 0.70, 0.00, 0.60 },
+ { 1.00, 0.00, 0.40, 0.80 },
+ { 0.70, 1.00, 0.10, 0.00 },
+ { 0.40, 0.00, 0.40, 0.20 },
+ { 1.00, 1.00, 0.20, 0.60 },
+ { 1.00, 0.00, 1.00, 0.40 },
+ { 0.40, 0.70, 0.40, 0.60 },
+ { 0.20, 0.40, 0.70, 0.60 },
+ { 0.70, 0.70, 0.40, 0.00 },
+ { 0.00, 1.00, 0.70, 0.80 },
+ { 0.00, 0.00, 1.00, 0.80 },
+ { 1.00, 0.40, 0.00, 0.40 },
+ { 0.20, 0.10, 0.40, 0.00 },
+ { 0.00, 0.40, 0.40, 0.80 },
+ { 0.10, 0.40, 0.20, 0.20 },
+ { 0.00, 0.70, 1.00, 0.20 },
+ { 0.00, 0.10, 0.70, 0.20 },
+ { 0.20, 0.70, 1.00, 0.40 },
+ { 0.10, 0.20, 0.00, 0.20 },
+ { 1.00, 0.00, 0.00, 0.40 },
+ { 0.10, 0.00, 0.10, 0.00 },
+ { 0.10, 0.40, 1.00, 0.00 },
+ { 0.40, 0.27, 0.27, 0.00 },
+ { 0.70, 0.70, 1.00, 0.00 },
+ { 0.10, 0.20, 0.10, 0.20 },
+ { 0.00, 0.70, 0.40, 0.00 },
+ { 0.40, 1.00, 1.00, 0.20 },
+ { 0.00, 0.20, 0.40, 0.00 },
+ { 0.20, 0.10, 1.00, 0.00 },
+ { 0.40, 0.20, 0.00, 0.60 },
+ { 0.20, 0.20, 0.40, 0.40 },
+ { 0.40, 0.40, 0.40, 0.20 },
+ { 0.00, 0.20, 1.00, 0.20 },
+ { 0.70, 0.40, 0.40, 0.00 },
+ { 0.40, 0.40, 0.20, 0.00 },
+ { 0.00, 1.00, 0.40, 0.40 },
+ { 0.00, 0.70, 1.00, 0.60 },
+ { 0.40, 0.00, 1.00, 0.40 },
+ { 1.00, 0.00, 1.00, 0.80 },
+ { 1.00, 0.70, 1.00, 0.60 },
+ { 0.00, 1.00, 0.10, 0.20 },
+ { 0.40, 0.40, 1.00, 0.40 },
+ { 0.70, 0.00, 1.00, 0.40 },
+ { 0.70, 0.40, 0.00, 0.20 },
+ { 0.20, 1.00, 0.40, 0.40 },
+ { 0.00, 0.90, 0.00, 0.00 },
+ { 0.40, 0.10, 0.00, 0.20 },
+ { 0.20, 0.20, 0.20, 0.00 },
+ { 0.00, 1.00, 1.00, 0.20 },
+ { 0.40, 0.00, 0.20, 0.40 },
+ { 0.70, 0.00, 1.00, 0.80 },
+ { 0.10, 0.20, 0.00, 0.00 },
+ { 0.70, 0.20, 0.00, 0.20 },
+ { 0.20, 0.40, 0.20, 0.20 },
+ { 1.00, 0.00, 0.10, 0.20 },
+ { 0.00, 0.20, 0.00, 0.00 },
+ { 0.00, 0.00, 1.00, 0.40 },
+ { 0.20, 0.00, 1.00, 0.00 },
+ { 0.70, 0.40, 0.00, 0.60 },
+ { 0.20, 0.00, 0.70, 0.60 },
+ { 0.10, 0.70, 0.20, 0.20 },
+ { 0.00, 0.70, 0.40, 0.80 },
+ { 0.40, 0.70, 0.10, 0.20 },
+ { 1.00, 0.40, 1.00, 0.40 },
+ { 0.40, 0.00, 0.00, 0.00 },
+ { 0.20, 0.40, 0.40, 0.60 },
+ { 0.00, 1.00, 0.00, 0.70 },
+ { 0.00, 1.00, 0.70, 0.40 },
+ { 1.00, 1.00, 0.40, 0.40 },
+ { 0.00, 0.20, 1.00, 0.40 },
+ { 0.70, 0.70, 0.20, 0.40 },
+ { 0.70, 0.00, 0.00, 0.80 },
+ { 0.00, 0.25, 0.00, 0.00 },
+ { 0.20, 0.40, 0.40, 0.40 },
+ { 0.00, 0.40, 0.00, 0.00 },
+ { 0.40, 0.70, 0.10, 0.00 },
+ { 0.40, 0.00, 0.20, 0.20 },
+ { 0.70, 0.00, 1.00, 0.20 },
+ { 0.70, 0.10, 0.20, 0.20 },
+ { 0.20, 0.00, 0.70, 0.00 },
+ { 1.00, 0.00, 0.00, 1.00 },
+ { 0.00, 0.10, 1.00, 0.20 },
+ { 0.70, 0.40, 1.00, 0.80 },
+ { 0.20, 0.00, 0.20, 0.00 },
+ { 0.00, 0.20, 0.20, 0.00 },
+ { 0.70, 0.10, 0.00, 0.00 },
+ { 0.00, 0.70, 0.20, 0.20 },
+ { 0.10, 1.00, 0.10, 0.20 },
+ { 0.00, 0.10, 0.00, 0.20 },
+ { 0.70, 0.20, 0.70, 0.40 },
+ { 0.10, 0.70, 0.70, 0.00 },
+ { 0.40, 0.70, 1.00, 0.60 },
+ { 0.70, 0.70, 0.20, 0.00 },
+ { 0.20, 1.00, 0.00, 0.60 },
+ { 0.00, 0.00, 0.00, 0.60 },
+ { 0.20, 1.00, 0.00, 0.00 },
+ { 0.20, 0.20, 0.00, 0.00 },
+ { 0.00, 0.15, 0.00, 0.00 },
+ { 1.00, 0.20, 0.10, 0.20 },
+ { 0.10, 0.10, 0.00, 0.20 },
+ { 0.20, 0.40, 0.00, 0.20 },
+ { 1.00, 0.40, 1.00, 0.20 },
+ { 1.00, 1.00, 0.20, 0.20 },
+ { 1.00, 0.70, 0.70, 0.00 },
+ { 0.40, 1.00, 0.40, 0.00 },
+ { 0.10, 0.00, 0.70, 0.20 },
+ { 0.00, 1.00, 0.20, 0.60 },
+ { 0.00, 0.20, 0.70, 0.40 },
+ { 0.00, 0.00, 0.00, 0.80 },
+ { 0.20, 0.00, 0.00, 0.40 },
+ { 1.00, 1.00, 0.20, 0.00 },
+ { 0.70, 1.00, 0.40, 0.80 },
+ { 0.00, 0.00, 1.00, 0.20 },
+ { 0.40, 1.00, 0.70, 0.20 },
+ { 1.00, 1.00, 0.40, 0.80 },
+ { 0.20, 0.20, 0.40, 0.60 },
+ { 0.70, 0.10, 0.20, 0.00 },
+ { 0.70, 1.00, 0.20, 0.40 },
+ { 0.40, 0.20, 0.40, 0.00 },
+ { 0.40, 0.70, 1.00, 0.00 },
+ { 0.10, 0.20, 0.20, 0.20 },
+ { 0.10, 0.00, 0.70, 0.00 },
+ { 0.70, 0.00, 0.70, 0.40 },
+ { 1.00, 0.00, 0.20, 0.40 },
+ { 0.00, 0.40, 1.00, 0.20 },
+ { 0.40, 0.40, 0.40, 0.40 },
+ { 0.00, 0.40, 0.40, 0.60 },
+ { 0.00, 1.00, 0.20, 0.00 },
+ { 0.40, 0.70, 1.00, 0.40 },
+ { 0.10, 0.40, 1.00, 0.20 },
+ { 0.70, 0.40, 0.70, 0.00 },
+ { 0.20, 0.20, 1.00, 0.60 },
+ { 0.10, 0.70, 0.20, 0.00 },
+ { 0.20, 1.00, 0.70, 0.40 },
+ { 0.70, 1.00, 1.00, 0.00 },
+ { 1.00, 0.70, 0.20, 0.40 },
+ { 0.00, 0.20, 0.10, 0.20 },
+ { 0.20, 0.70, 1.00, 0.20 },
+ { 0.00, 0.70, 0.70, 0.00 },
+ { 0.70, 1.00, 1.00, 0.20 },
+ { 1.00, 1.00, 1.00, 0.00 },
+ { 0.70, 1.00, 0.00, 0.60 },
+ { 0.20, 0.40, 0.40, 0.00 },
+ { 0.40, 0.40, 1.00, 0.00 },
+ { 0.00, 0.70, 0.20, 0.60 },
+ { 0.25, 0.00, 0.00, 0.00 },
+ { 0.40, 0.40, 0.00, 0.00 },
+ { 0.70, 0.20, 1.00, 0.40 },
+ { 1.00, 1.00, 0.00, 0.20 },
+ { 0.00, 0.10, 0.70, 0.00 },
+ { 0.70, 0.40, 0.00, 0.00 },
+ { 0.20, 0.40, 0.00, 0.00 },
+ { 0.70, 0.00, 0.70, 0.80 },
+ { 0.20, 1.00, 0.00, 0.20 },
+ { 0.40, 0.10, 0.20, 0.00 },
+ { 0.20, 1.00, 0.20, 0.40 },
+ { 0.40, 0.00, 1.00, 0.60 },
+ { 0.40, 0.40, 0.00, 0.80 },
+ { 0.40, 0.20, 0.70, 0.60 },
+ { 0.40, 0.27, 0.27, 0.40 },
+ { 0.40, 0.20, 0.10, 0.20 },
+ { 0.40, 0.70, 0.40, 0.20 },
+ { 1.00, 0.00, 1.00, 0.00 },
+ { 0.00, 0.40, 0.20, 0.40 },
+ { 1.00, 0.70, 0.40, 0.80 },
+ { 1.00, 0.85, 0.85, 1.00 },
+ { 0.20, 0.10, 0.10, 0.00 },
+ { 0.10, 0.10, 0.10, 0.20 },
+ { 0.20, 0.70, 0.00, 0.60 },
+ { 0.00, 0.40, 0.70, 0.00 },
+ { 0.20, 0.00, 0.20, 0.60 },
+ { 0.40, 0.00, 0.40, 0.00 },
+ { 0.50, 0.00, 0.00, 0.00 },
+ { 0.40, 0.40, 0.40, 0.80 },
+ { 0.70, 0.20, 0.20, 0.40 },
+ { 0.40, 0.20, 0.40, 0.40 },
+ { 0.00, 0.40, 0.40, 0.20 },
+ { 0.40, 0.20, 1.00, 0.00 },
+ { 1.00, 1.00, 0.00, 0.20 },
+ { 1.00, 1.00, 0.00, 0.00 },
+ { 0.40, 0.20, 0.40, 0.60 },
+ { 0.20, 0.40, 0.10, 0.20 },
+ { 0.00, 0.00, 1.00, 0.00 },
+ { 0.70, 0.10, 1.00, 0.20 },
+ { 0.10, 0.20, 1.00, 0.20 },
+ { 0.20, 0.00, 0.10, 0.00 },
+ { 0.70, 1.00, 0.40, 0.20 },
+ { 0.00, 1.00, 1.00, 0.80 },
+ { 1.00, 0.20, 0.00, 0.20 },
+ { 0.00, 0.10, 0.10, 0.00 },
+ { 0.40, 0.00, 0.20, 0.00 },
+ { 0.20, 0.20, 0.00, 0.60 },
+ { 1.00, 0.00, 0.40, 0.00 },
+ { 0.20, 0.20, 0.70, 0.40 },
+ { 0.10, 1.00, 0.40, 0.00 },
+ { 0.40, 0.70, 0.40, 0.00 },
+ { 1.00, 0.20, 0.00, 0.40 },
+ { 0.20, 0.12, 0.12, 0.10 },
+ { 0.00, 0.00, 0.25, 0.00 },
+ { 0.40, 0.00, 1.00, 0.20 },
+ { 0.70, 0.70, 0.00, 0.40 },
+ { 1.00, 0.20, 0.10, 0.00 },
+ { 0.00, 1.00, 0.10, 0.00 },
+ { 0.70, 1.00, 0.20, 0.60 },
+ { 0.00, 0.20, 0.40, 0.40 },
+ { 0.40, 0.40, 0.70, 0.00 },
+ { 1.00, 1.00, 0.00, 0.00 },
+ { 0.00, 0.20, 0.40, 0.20 },
+ { 0.70, 0.00, 0.20, 0.40 },
+ { 0.40, 0.20, 1.00, 0.40 },
+ { 0.40, 0.10, 0.70, 0.00 },
+ { 0.00, 0.00, 0.40, 0.40 },
+ { 0.20, 1.00, 0.20, 0.20 },
+ { 0.00, 0.40, 1.00, 0.40 },
+ { 0.20, 0.40, 1.00, 0.20 },
+ { 0.20, 1.00, 1.00, 0.60 },
+ { 0.00, 0.20, 1.00, 0.00 },
+ { 1.00, 0.00, 1.00, 1.00 },
+ { 0.40, 1.00, 0.00, 0.00 },
+ { 0.70, 0.70, 0.00, 0.60 },
+ { 0.40, 0.10, 0.40, 0.20 },
+ { 1.00, 0.00, 0.20, 0.00 },
+ { 0.40, 0.20, 0.20, 0.20 },
+ { 0.70, 0.20, 1.00, 0.60 },
+ { 0.20, 0.40, 1.00, 0.60 },
+ { 0.40, 0.00, 0.40, 0.40 },
+ { 0.70, 0.20, 0.40, 0.40 },
+ { 0.70, 0.00, 0.10, 0.20 },
+ { 0.20, 0.40, 0.70, 0.20 },
+ { 0.00, 1.00, 0.40, 0.20 },
+ { 1.00, 1.00, 0.00, 0.40 },
+ { 0.40, 1.00, 0.00, 0.20 },
+ { 1.00, 0.40, 1.00, 0.00 },
+ { 0.40, 0.00, 0.40, 0.60 },
+ { 0.10, 0.06, 0.06, 0.80 },
+ { 1.00, 1.00, 0.00, 1.00 },
+ { 0.70, 0.20, 1.00, 0.00 },
+ { 1.00, 0.40, 0.00, 0.00 },
+ { 0.40, 0.00, 0.00, 0.80 },
+ { 0.40, 0.40, 1.00, 0.20 },
+ { 0.20, 0.70, 0.00, 0.40 },
+ { 1.00, 1.00, 0.40, 0.60 },
+ { 0.00, 0.30, 0.00, 0.00 },
+ { 0.00, 0.20, 0.70, 0.60 },
+ { 1.00, 0.40, 0.70, 0.40 },
+ { 0.20, 0.70, 0.00, 0.00 },
+ { 0.40, 0.40, 0.70, 0.60 },
+ { 0.20, 0.20, 0.20, 0.00 },
+ { 0.10, 0.06, 0.06, 0.20 },
+ { 0.00, 1.00, 1.00, 0.40 },
+ { 1.00, 0.20, 0.20, 0.60 },
+ { 1.00, 0.10, 0.00, 0.20 },
+ { 0.40, 0.20, 0.20, 0.00 },
+ { 0.00, 1.00, 1.00, 1.00 },
+ { 0.20, 0.20, 0.40, 0.00 },
+ { 1.00, 0.10, 0.10, 0.00 },
+ { 0.00, 0.00, 0.00, 0.07 },
+ { 0.20, 0.70, 0.10, 0.20 },
+ { 0.40, 0.70, 0.00, 0.60 },
+ { 0.40, 0.00, 1.00, 0.80 },
+ { 0.20, 0.70, 0.70, 0.00 },
+ { 1.00, 0.40, 0.20, 0.00 },
+ { 1.00, 1.00, 1.00, 0.00 },
+ { 0.00, 0.40, 0.00, 0.80 },
+ { 0.40, 1.00, 0.70, 0.80 },
+ { 1.00, 0.10, 0.20, 0.00 },
+ { 0.10, 0.00, 0.40, 0.00 },
+ { 0.00, 0.00, 0.00, 0.80 },
+ { 0.00, 0.20, 0.00, 0.00 },
+ { 0.00, 0.00, 0.00, 0.50 },
+ { 1.00, 1.00, 0.70, 0.00 },
+ { 1.00, 0.40, 0.40, 0.40 },
+ { 0.00, 0.00, 0.20, 0.20 },
+ { 0.70, 0.40, 1.00, 0.60 },
+ { 0.20, 0.20, 0.70, 0.20 },
+ { 0.20, 0.70, 0.20, 0.20 },
+ { 0.40, 1.00, 0.40, 0.80 },
+ { 0.70, 0.70, 1.00, 0.40 },
+ { 0.40, 0.00, 0.70, 0.60 },
+ { 1.00, 0.40, 0.40, 0.00 },
+ { 0.40, 1.00, 0.70, 0.40 },
+ { 1.00, 1.00, 1.00, 1.00 },
+ { 0.40, 1.00, 0.10, 0.00 },
+ { 0.00, 0.20, 0.10, 0.00 },
+ { 0.40, 1.00, 1.00, 0.40 },
+ { 1.00, 0.20, 0.00, 0.60 },
+ { 0.70, 1.00, 0.20, 0.00 },
+ { 1.00, 0.70, 0.00, 0.40 },
+ { 1.00, 0.00, 0.00, 0.20 },
+ { 0.40, 1.00, 0.20, 0.20 },
+ { 0.00, 0.00, 0.00, 0.90 },
+ { 1.00, 0.70, 0.00, 0.00 },
+ { 0.10, 1.00, 0.20, 0.20 },
+ { 0.20, 0.00, 0.20, 0.20 },
+ { 1.00, 1.00, 0.00, 0.40 },
+ { 0.40, 0.10, 0.00, 0.00 },
+ { 0.40, 1.00, 0.40, 0.60 },
+ { 0.40, 0.70, 0.20, 0.20 },
+ { 0.00, 0.00, 0.10, 0.00 },
+ { 0.00, 0.00, 0.50, 0.00 },
+ { 0.20, 0.70, 0.20, 0.00 },
+ { 0.00, 1.00, 0.40, 0.80 },
+ { 0.20, 1.00, 1.00, 0.20 },
+ { 0.20, 0.20, 0.70, 0.60 },
+ { 0.40, 0.40, 1.00, 0.00 },
+ { 0.00, 0.00, 0.00, 0.30 },
+ { 0.00, 0.40, 0.00, 0.20 },
+ { 0.20, 0.12, 0.12, 0.80 },
+ { 0.00, 0.10, 0.00, 0.00 },
+ { 0.00, 0.10, 0.00, 0.00 },
+ { 0.20, 0.70, 1.00, 0.00 },
+ { 0.00, 0.70, 0.00, 0.00 },
+ { 0.60, 0.45, 0.45, 0.80 },
+ { 0.40, 0.20, 1.00, 0.60 },
+ { 1.00, 0.85, 0.85, 0.00 },
+ { 1.00, 0.70, 0.70, 0.80 },
+ { 0.70, 0.00, 0.00, 0.20 },
+ { 0.70, 0.00, 0.00, 0.40 },
+ { 0.00, 0.00, 1.00, 1.00 },
+ { 0.00, 0.10, 0.20, 0.20 },
+ { 0.40, 0.40, 0.70, 0.80 },
+ { 0.10, 0.10, 0.10, 0.00 },
+ { 1.00, 0.00, 0.10, 0.00 },
+ { 0.10, 1.00, 0.00, 0.00 },
+ { 0.70, 0.70, 0.10, 0.00 },
+ { 0.00, 0.00, 0.40, 0.20 },
+ { 1.00, 1.00, 0.70, 0.20 },
+ { 0.10, 1.00, 0.20, 0.00 },
+ { 0.20, 0.70, 0.70, 0.60 },
+ { 0.00, 0.00, 0.60, 0.00 },
+ { 1.00, 0.00, 0.00, 0.00 },
+ { 0.40, 0.10, 0.10, 0.00 },
+ { 0.00, 1.00, 0.70, 0.20 },
+ { 0.10, 0.00, 0.00, 0.00 },
+ { 0.70, 0.00, 1.00, 0.60 },
+ { 0.70, 0.40, 0.40, 0.20 },
+ { 0.70, 0.20, 0.20, 0.00 },
+ { 1.00, 0.20, 0.70, 0.60 },
+ { 0.10, 0.00, 1.00, 0.20 },
+ { 0.00, 0.00, 0.70, 0.00 },
+ { 1.00, 0.20, 1.00, 0.60 },
+ { 0.70, 1.00, 0.70, 0.00 },
+ { 0.80, 0.00, 0.00, 0.00 },
+ { 0.00, 0.00, 0.80, 0.00 },
+ { 0.70, 0.40, 0.10, 0.00 },
+ { 1.00, 0.20, 0.20, 0.20 },
+ { 0.40, 0.20, 0.00, 0.00 },
+ { 1.00, 0.00, 0.00, 0.00 },
+ { 0.70, 0.40, 1.00, 0.00 },
+ { 0.10, 0.20, 0.10, 0.00 },
+ { 0.70, 0.40, 0.70, 0.60 },
+ { 0.40, 0.70, 0.70, 0.20 },
+ { 0.70, 0.10, 0.00, 0.20 },
+ { 1.00, 1.00, 0.70, 0.60 },
+ { 0.20, 1.00, 0.10, 0.00 },
+ { 1.00, 0.00, 1.00, 0.40 },
+ { 1.00, 0.10, 0.40, 0.20 },
+ { 0.00, 0.40, 0.40, 0.40 },
+ { 1.00, 0.00, 1.00, 0.20 },
+ { 0.00, 1.00, 0.00, 0.60 },
+ { 0.10, 0.10, 0.40, 0.20 },
+ { 0.00, 0.20, 0.20, 0.20 },
+ { 0.00, 0.70, 0.00, 0.80 },
+ { 0.40, 0.20, 0.70, 0.20 },
+ { 0.20, 0.40, 0.40, 0.00 },
+ { 0.70, 0.40, 1.00, 0.20 },
+ { 0.70, 0.40, 0.00, 0.80 },
+ { 0.70, 0.20, 0.20, 0.60 },
+ { 1.00, 0.70, 0.20, 0.60 },
+ { 1.00, 0.40, 1.00, 0.00 },
+ { 1.00, 0.70, 0.20, 0.00 },
+ { 0.00, 0.03, 0.00, 0.00 },
+ { 0.40, 0.00, 0.00, 0.00 },
+ { 0.00, 1.00, 1.00, 0.60 },
+ { 0.20, 0.00, 0.00, 0.60 },
+ { 0.70, 0.70, 0.00, 0.80 },
+ { 0.10, 0.06, 0.06, 0.10 },
+ { 0.40, 0.40, 0.40, 0.00 },
+ { 0.00, 0.20, 0.00, 0.20 },
+ { 0.00, 1.00, 1.00, 0.00 },
+ { 0.00, 0.40, 0.10, 0.00 },
+ { 1.00, 0.20, 0.70, 0.20 },
+ { 0.20, 0.70, 0.70, 0.20 },
+ { 0.70, 0.00, 0.20, 0.20 },
+ { 0.70, 1.00, 0.00, 0.00 },
+ { 0.40, 1.00, 1.00, 0.60 },
+ { 1.00, 0.20, 0.70, 0.00 },
+ { 0.20, 0.10, 0.40, 0.20 },
+ { 0.70, 1.00, 1.00, 0.40 },
+ { 1.00, 0.20, 0.70, 0.00 },
+ { 0.40, 0.27, 0.27, 0.10 },
+ { 0.10, 0.10, 0.20, 0.20 },
+ { 1.00, 0.70, 1.00, 0.80 },
+ { 0.00, 0.20, 0.40, 0.60 },
+ { 0.20, 0.40, 0.40, 0.20 },
+ { 0.70, 0.70, 0.70, 0.00 },
+ { 0.20, 0.20, 0.00, 0.20 },
+ { 0.70, 0.00, 0.10, 0.00 },
+ { 0.40, 0.20, 0.00, 0.20 },
+ { 0.10, 0.10, 0.20, 0.00 },
+ { 0.00, 0.40, 0.40, 0.00 },
+ { 0.40, 1.00, 0.00, 0.80 },
+ { 0.00, 0.00, 1.00, 0.20 },
+ { 0.70, 0.20, 0.20, 0.20 },
+ { 1.00, 0.10, 1.00, 0.20 },
+ { 0.00, 0.40, 1.00, 0.80 },
+ { 0.00, 0.00, 0.00, 0.20 },
+ { 0.70, 0.70, 0.00, 0.20 },
+ { 0.70, 0.40, 0.20, 0.40 },
+ { 0.20, 0.20, 0.10, 0.20 },
+ { 0.00, 1.00, 1.00, 0.20 },
+ { 0.20, 0.10, 0.70, 0.00 },
+ { 1.00, 0.10, 0.00, 0.00 },
+ { 0.00, 0.40, 0.70, 0.20 },
+ { 0.20, 0.10, 1.00, 0.20 },
+ { 1.00, 0.00, 0.70, 0.60 },
+ { 0.40, 0.70, 1.00, 0.80 },
+ { 0.00, 0.70, 1.00, 0.80 },
+ { 0.20, 1.00, 0.20, 0.60 },
+ { 0.00, 0.70, 0.70, 0.80 },
+ { 0.70, 0.40, 0.40, 0.00 },
+ { 0.70, 0.70, 0.70, 0.00 },
+ { 0.40, 1.00, 0.40, 0.40 },
+ { 0.00, 0.00, 0.03, 0.00 },
+ { 0.20, 0.12, 0.12, 0.20 },
+ { 0.70, 0.20, 1.00, 0.20 },
+ { 0.00, 0.00, 0.20, 0.00 },
+ { 0.70, 0.70, 0.40, 0.80 },
+ { 0.00, 0.00, 0.70, 0.00 },
+ { 0.40, 0.00, 0.40, 0.80 },
+ { 0.10, 0.20, 0.40, 0.20 },
+ { 1.00, 0.70, 0.40, 0.20 },
+ { 0.70, 0.20, 0.40, 0.20 },
+ { 0.70, 1.00, 0.20, 0.00 },
+ { 0.80, 0.65, 0.65, 0.00 },
+ { 0.40, 0.70, 1.00, 0.20 },
+ { 0.20, 1.00, 0.70, 0.20 },
+ { 0.10, 0.40, 0.00, 0.20 },
+ { 1.00, 1.00, 0.00, 0.80 },
+ { 0.70, 0.20, 1.00, 0.00 },
+ { 0.00, 0.10, 0.40, 0.00 },
+ { 1.00, 0.70, 1.00, 0.00 },
+ { 0.70, 0.40, 0.10, 0.20 },
+ { 0.70, 0.20, 0.10, 0.00 },
+ { 0.40, 1.00, 1.00, 0.00 },
+ { 0.40, 0.40, 0.10, 0.20 },
+ { 0.80, 0.65, 0.65, 1.00 },
+ { 0.20, 0.00, 0.20, 0.40 },
+ { 0.70, 0.00, 0.70, 0.20 },
+ { 0.70, 1.00, 0.40, 0.40 },
+ { 1.00, 0.10, 0.70, 0.00 },
+ { 0.40, 0.70, 0.00, 0.80 },
+ { 0.70, 0.40, 0.40, 0.80 },
+ { 0.70, 0.70, 0.00, 0.00 },
+ { 0.40, 0.20, 0.40, 0.20 },
+ { 0.20, 0.00, 1.00, 0.20 },
+ { 0.00, 0.00, 0.00, 1.00 },
+ { 0.70, 0.20, 0.00, 0.60 },
+ { 0.40, 1.00, 0.10, 0.20 },
+ { 0.20, 1.00, 0.00, 0.40 },
+ { 0.20, 0.20, 0.70, 0.00 },
+ { 1.00, 0.00, 1.00, 0.70 },
+ { 0.00, 0.20, 0.20, 0.00 },
+ { 0.40, 0.40, 0.00, 0.40 },
+ { 1.00, 0.00, 0.00, 0.70 },
+ { 1.00, 0.85, 0.85, 0.80 },
+ { 0.10, 0.40, 0.40, 0.00 },
+ { 0.40, 0.70, 0.70, 0.40 },
+ { 0.40, 0.27, 0.27, 0.60 },
+ { 0.10, 0.10, 0.70, 0.00 },
+ { 0.10, 0.20, 0.70, 0.00 },
+ { 0.20, 0.70, 0.40, 0.20 },
+ { 0.00, 0.40, 0.70, 0.80 },
+ { 0.00, 0.40, 0.20, 0.20 },
+ { 0.70, 0.00, 0.00, 0.00 },
+ { 0.70, 0.40, 0.00, 0.40 },
+ { 1.00, 0.70, 0.00, 0.80 },
+ { 0.40, 0.00, 0.40, 0.70 },
+ { 0.40, 0.40, 0.00, 0.00 },
+ { 0.00, 0.00, 0.40, 0.80 },
+ { 0.00, 0.70, 0.70, 0.40 },
+ { 0.40, 0.00, 0.00, 0.40 },
+ { 0.10, 0.40, 0.40, 0.20 },
+ { 0.60, 0.45, 0.45, 0.00 },
+ { 0.10, 1.00, 0.40, 0.20 },
+ { 0.40, 0.00, 0.40, 0.40 },
+ { 0.10, 0.20, 0.70, 0.20 },
+ { 0.20, 0.00, 0.00, 0.00 },
+ { 0.00, 0.00, 0.00, 0.03 },
+ { 0.70, 0.20, 0.00, 0.00 },
+ { 1.00, 1.00, 0.40, 0.00 },
+ { 0.20, 1.00, 1.00, 0.40 },
+ { 0.20, 0.20, 0.70, 0.00 },
+ { 0.00, 0.00, 0.00, 0.70 },
+ { 1.00, 0.00, 1.00, 0.20 },
+ { 1.00, 0.70, 0.00, 0.20 },
+ { 1.00, 0.40, 0.00, 0.00 },
+ { 1.00, 0.40, 0.70, 0.20 },
+ { 0.70, 0.70, 0.70, 0.80 },
+ { 0.70, 0.70, 0.70, 0.60 },
+ { 0.00, 0.40, 1.00, 0.00 },
+ { 0.60, 0.45, 0.45, 0.60 },
+ { 0.10, 1.00, 0.70, 0.00 },
+ { 0.40, 0.00, 0.70, 0.80 },
+ { 0.20, 0.70, 0.20, 0.60 },
+ { 0.20, 0.70, 0.20, 0.40 },
+ { 0.00, 0.40, 1.00, 0.00 },
+ { 0.20, 0.70, 0.40, 0.60 },
+ { 1.00, 0.40, 0.10, 0.20 },
+ { 0.20, 0.20, 0.00, 0.00 },
+ { 0.00, 0.10, 0.10, 0.20 },
+ { 0.40, 0.00, 0.40, 0.00 },
+ { 0.70, 0.40, 0.20, 0.20 },
+ { 0.70, 0.70, 0.20, 0.60 },
+ { 1.00, 0.00, 0.70, 0.80 },
+ { 0.20, 0.00, 0.00, 0.00 },
+ { 1.00, 0.40, 0.00, 0.60 },
+ { 0.00, 0.00, 0.10, 0.00 },
+ { 0.40, 1.00, 0.70, 0.60 },
+ { 0.40, 0.20, 0.20, 0.40 },
+ { 0.20, 0.70, 1.00, 0.00 },
+ { 1.00, 0.20, 0.20, 0.40 },
+ { 1.00, 1.00, 0.40, 0.20 },
+ { 0.20, 0.20, 1.00, 0.20 },
+ { 0.20, 0.70, 0.40, 0.00 },
+ { 1.00, 0.00, 0.40, 0.00 },
+ { 0.00, 0.20, 1.00, 0.60 },
+ { 1.00, 0.40, 0.40, 0.60 },
+ { 1.00, 0.10, 1.00, 0.00 },
+ { 0.70, 0.10, 0.10, 0.20 },
+ { 0.10, 0.40, 0.70, 0.00 },
+ { 0.00, 1.00, 0.70, 0.00 },
+ { 0.00, 0.70, 0.00, 0.20 },
+ { 1.00, 0.00, 0.20, 0.60 },
+ { 0.10, 0.70, 0.40, 0.20 },
+ { 0.40, 0.00, 1.00, 0.00 },
+ { 0.10, 0.70, 0.10, 0.00 },
+ { 0.40, 0.40, 0.70, 0.00 },
+ { 0.10, 0.00, 0.00, 0.00 },
+ { 0.00, 0.70, 0.10, 0.20 },
+ { 0.70, 0.20, 0.40, 0.00 },
+ { 0.70, 0.10, 0.70, 0.20 },
+ { 1.00, 1.00, 0.20, 0.40 },
+ { 0.70, 0.00, 0.40, 0.20 },
+ { 0.40, 0.40, 0.20, 0.60 },
+ { 1.00, 0.70, 0.10, 0.20 },
+ { 0.00, 1.00, 0.00, 0.20 },
+ { 0.40, 0.70, 0.20, 0.60 },
+ { 0.40, 0.10, 1.00, 0.20 },
+ { 0.40, 1.00, 0.40, 0.00 },
+ { 0.00, 1.00, 0.00, 0.20 },
+ { 0.00, 0.00, 0.40, 0.60 },
+ { 0.40, 0.20, 0.40, 0.00 },
+ { 0.20, 0.20, 0.00, 0.40 },
+ { 0.70, 0.20, 0.70, 0.20 },
+ { 0.20, 0.70, 0.70, 0.00 },
+ { 0.40, 1.00, 0.70, 0.00 },
+ { 0.40, 0.20, 0.70, 0.40 },
+ { 0.10, 0.06, 0.06, 0.60 },
+ { 0.00, 0.40, 0.10, 0.20 },
+ { 0.20, 0.00, 0.40, 0.20 },
+ { 0.20, 0.40, 0.70, 0.00 },
+ { 0.00, 0.40, 0.00, 0.00 },
+ { 0.40, 1.00, 0.00, 0.40 },
+ { 0.00, 0.00, 0.15, 0.00 },
+ { 1.00, 0.10, 0.20, 0.20 },
+ { 0.40, 1.00, 0.00, 0.60 },
+ { 1.00, 1.00, 0.40, 0.00 },
+ { 0.70, 1.00, 0.70, 0.00 },
+ { 0.80, 0.65, 0.65, 0.80 },
+ { 0.70, 0.20, 0.00, 0.40 },
+ { 0.00, 0.40, 0.40, 0.70 },
+ { 0.40, 1.00, 0.20, 0.00 },
+ { 1.00, 0.00, 0.70, 0.00 },
+ { 0.70, 1.00, 1.00, 0.00 },
+ { 0.10, 0.00, 0.20, 0.00 },
+ { 0.70, 0.40, 0.40, 0.40 },
+ { 0.20, 0.20, 0.10, 0.00 },
+ { 0.00, 0.40, 0.00, 0.60 },
+ { 0.40, 0.70, 0.40, 0.40 },
+ { 0.10, 0.40, 0.20, 0.00 },
+ { 0.20, 0.20, 0.20, 0.60 },
+ { 0.20, 0.20, 0.40, 0.20 },
+ { 0.00, 0.20, 0.20, 0.60 },
+ { 0.20, 0.70, 0.00, 0.20 },
+ { 0.00, 1.00, 0.00, 0.00 },
+ { 0.70, 0.20, 0.70, 0.00 },
+ { 0.70, 0.10, 0.10, 0.00 },
+ { 0.00, 0.70, 0.70, 0.60 },
+ { 0.00, 0.40, 0.40, 0.40 },
+ { 0.20, 0.40, 1.00, 0.00 },
+ { 0.00, 0.70, 0.10, 0.00 },
+ { 1.00, 0.70, 0.70, 0.40 },
+ { 0.10, 1.00, 0.10, 0.00 },
+ { 0.00, 0.70, 0.40, 0.60 },
+ { 1.00, 0.70, 0.40, 0.40 },
+ { 0.70, 1.00, 0.00, 0.20 },
+ { 0.70, 0.70, 0.40, 0.60 },
+ { 1.00, 0.00, 0.40, 0.60 },
+ { 0.40, 1.00, 0.00, 0.00 },
+ { 0.20, 0.12, 0.12, 1.00 },
+ { 0.00, 0.00, 0.00, 0.60 },
+ { 0.20, 0.10, 0.10, 0.20 },
+ { 0.40, 0.40, 0.20, 0.20 },
+ { 0.00, 0.50, 0.00, 0.00 },
+ { 0.70, 1.00, 0.70, 0.20 },
+ { 0.60, 0.45, 0.45, 1.00 },
+ { 1.00, 0.70, 0.40, 0.60 },
+ { 0.40, 0.70, 0.70, 0.60 },
+ { 0.20, 0.20, 0.20, 0.40 },
+ { 1.00, 0.20, 0.40, 0.40 },
+ { 0.80, 0.65, 0.65, 0.40 },
+ { 0.00, 0.70, 0.70, 0.00 },
+ { 0.00, 0.00, 0.00, 0.25 },
+ { 0.20, 1.00, 1.00, 0.00 },
+ { 0.10, 0.06, 0.06, 0.00 },
+ { 0.20, 0.70, 0.20, 0.00 },
+ { 0.20, 0.10, 0.70, 0.20 },
+ { 1.00, 0.70, 0.10, 0.00 },
+ { 0.70, 1.00, 1.00, 0.60 },
+ { 0.10, 1.00, 0.70, 0.20 },
+ { 0.20, 0.20, 1.00, 0.00 },
+ { 0.70, 0.10, 0.40, 0.00 },
+ { 0.40, 0.00, 0.70, 0.20 },
+ { 0.00, 0.20, 0.00, 0.40 },
+ { 1.00, 1.00, 0.00, 0.60 },
+ { 0.10, 0.70, 0.00, 0.00 },
+ { 0.00, 1.00, 0.40, 0.00 },
+ { 0.70, 0.70, 0.70, 0.20 },
+ { 0.00, 0.10, 1.00, 0.00 },
+ { 1.00, 1.00, 0.10, 0.20 },
+ { 0.00, 0.00, 0.70, 0.20 },
+ { 0.00, 0.40, 0.70, 0.40 },
+ { 0.70, 0.20, 0.20, 0.00 },
+ { 0.40, 0.20, 0.70, 0.00 },
+ { 0.40, 0.10, 0.70, 0.20 },
+ { 0.00, 0.40, 0.20, 0.60 },
+ { 0.20, 0.40, 0.10, 0.00 },
+ { 0.40, 0.70, 0.40, 0.80 },
+ { 0.00, 0.00, 1.00, 0.60 },
+ { 0.10, 0.10, 0.70, 0.20 },
+ { 0.10, 0.10, 1.00, 0.20 },
+ { 0.70, 1.00, 0.70, 0.40 },
+ { 0.10, 0.00, 0.20, 0.20 },
+ { 0.05, 0.03, 0.03, 0.00 },
+ { 0.70, 1.00, 0.10, 0.20 },
+ { 1.00, 0.70, 0.70, 0.20 },
+ { 1.00, 0.20, 1.00, 0.20 },
+ { 0.20, 0.20, 1.00, 0.40 },
+ { 0.00, 0.00, 0.00, 0.20 },
+ { 1.00, 0.40, 0.70, 0.80 },
+ { 1.00, 0.40, 1.00, 0.60 },
+ { 0.40, 0.20, 0.20, 0.60 },
+ { 0.40, 0.40, 0.70, 0.20 },
+ { 0.60, 0.45, 0.45, 0.40 },
+ { 0.40, 1.00, 0.40, 0.20 },
+ { 1.00, 0.00, 0.20, 0.20 },
+ { 0.40, 0.20, 0.10, 0.00 },
+ { 0.70, 0.70, 0.00, 0.00 },
+ { 1.00, 0.00, 0.00, 0.80 },
+ { 0.20, 0.40, 0.20, 0.00 },
+ { 0.20, 0.40, 0.20, 0.40 },
+ { 0.40, 0.40, 0.00, 0.70 },
+ { 0.10, 0.70, 1.00, 0.00 },
+ { 0.00, 0.70, 0.00, 0.40 },
+ { 1.00, 0.00, 0.00, 0.20 },
+ { 0.40, 0.70, 0.20, 0.40 },
+ { 0.00, 0.00, 0.90, 0.00 },
+ { 0.00, 0.40, 0.20, 0.00 },
+ { 1.00, 0.10, 0.40, 0.00 },
+ { 0.70, 0.00, 0.40, 0.60 },
+ { 0.70, 0.40, 0.20, 0.60 },
+ { 0.00, 0.80, 0.00, 0.00 },
+ { 1.00, 0.70, 0.40, 0.00 },
+ { 0.40, 1.00, 0.20, 0.60 },
+ { 1.00, 0.70, 0.20, 0.20 },
+ { 0.00, 0.20, 0.70, 0.00 },
+ { 0.40, 0.00, 0.40, 0.20 },
+ { 0.70, 0.40, 0.70, 0.00 },
+ { 0.10, 0.10, 0.40, 0.00 },
+ { 0.70, 1.00, 1.00, 0.80 },
+ { 0.10, 0.10, 1.00, 0.00 },
+ { 0.40, 0.40, 0.10, 0.00 },
+ { 0.00, 0.00, 1.00, 0.70 },
+ { 0.70, 0.20, 0.70, 0.60 },
+ { 1.00, 0.10, 0.10, 0.20 },
+ { 0.00, 0.70, 0.00, 0.00 },
+ { 0.00, 0.70, 0.40, 0.20 },
+ { 0.40, 1.00, 1.00, 0.80 },
+ { 0.70, 1.00, 0.20, 0.20 },
+ { 0.20, 1.00, 0.70, 0.00 },
+ { 0.00, 0.20, 0.20, 0.40 },
+ { 0.00, 1.00, 0.00, 0.00 },
+ { 0.40, 0.40, 1.00, 0.60 },
+ { 0.70, 1.00, 0.00, 0.80 },
+ { 0.20, 0.00, 0.20, 0.00 },
+ { 1.00, 0.70, 1.00, 0.40 },
+ { 0.00, 0.00, 0.00, 0.10 },
+ { 0.70, 0.00, 0.20, 0.00 },
+ { 0.70, 1.00, 0.40, 0.60 },
+ { 0.40, 0.00, 0.20, 0.60 },
+ { 0.70, 0.10, 1.00, 0.00 },
+ { 0.70, 0.70, 0.20, 0.00 },
+ { 1.00, 0.40, 0.10, 0.00 },
+ { 0.10, 0.70, 0.10, 0.20 },
+ { 1.00, 0.70, 0.70, 0.60 },
+ { 0.00, 0.07, 0.00, 0.00 },
+ { 0.70, 1.00, 0.00, 0.40 },
+ { 1.00, 0.40, 0.00, 0.80 },
+ { 0.10, 0.06, 0.06, 1.00 },
+ { 1.00, 0.00, 1.00, 0.00 },
+ { 1.00, 0.40, 0.70, 0.60 },
+ { 0.70, 0.20, 0.10, 0.20 },
+ { 0.00, 1.00, 1.00, 0.00 },
+ { 0.40, 0.10, 0.10, 0.20 },
+ { 1.00, 0.00, 0.70, 0.20 },
+ { 1.00, 0.20, 0.20, 0.00 },
+ { 1.00, 0.40, 0.00, 0.20 },
+ { 0.20, 1.00, 0.70, 0.60 },
+ { 0.70, 0.00, 0.00, 0.00 },
+ { 0.10, 0.40, 0.00, 0.00 },
+ { 0.20, 0.00, 0.00, 0.20 },
+ { 0.07, 0.00, 0.00, 0.00 },
+ { 0.70, 0.20, 0.40, 0.60 },
+ { 0.00, 0.70, 0.00, 0.60 },
+ { 0.30, 0.00, 0.00, 0.00 },
+ { 0.40, 0.27, 0.27, 0.20 },
+ { 0.00, 0.40, 0.40, 0.20 },
+ { 0.20, 1.00, 0.70, 0.00 },
+ { 1.00, 0.20, 0.70, 0.40 },
+ { 0.70, 1.00, 0.70, 0.80 },
+ { 1.00, 1.00, 1.00, 0.40 },
+ { 1.00, 0.00, 0.40, 0.40 },
+ { 0.10, 0.00, 0.40, 0.20 },
+ { 0.40, 0.10, 1.00, 0.00 },
+ { 1.00, 0.00, 1.00, 0.60 },
+ { 0.00, 0.00, 0.70, 0.60 },
+ { 1.00, 0.40, 1.00, 0.80 },
+ { 0.70, 0.70, 1.00, 0.60 },
+ { 0.20, 0.00, 0.40, 0.00 },
+ { 0.40, 0.00, 0.10, 0.20 },
+ { 0.70, 0.00, 0.00, 0.60 },
+ { 0.00, 0.60, 0.00, 0.00 },
+ { 0.10, 0.70, 0.70, 0.20 },
+ { 1.00, 0.20, 1.00, 0.00 },
+ { 0.00, 0.00, 1.00, 0.00 },
+ { 0.20, 1.00, 0.20, 0.00 },
+ { 0.40, 0.40, 0.00, 0.20 },
+ { 0.40, 0.10, 0.20, 0.20 },
+ { 0.20, 0.12, 0.12, 0.00 },
+ { 0.20, 0.70, 1.00, 0.60 },
+ { 0.40, 0.70, 0.00, 0.40 },
+ { 0.00, 0.00, 0.40, 0.00 },
+ { 0.40, 0.00, 0.10, 0.00 },
+ { 0.00, 1.00, 0.40, 0.00 },
+ { 0.70, 0.70, 0.40, 0.20 },
+ { 0.20, 0.00, 0.70, 0.20 },
+ { 0.10, 1.00, 1.00, 0.00 },
+ { 0.70, 0.00, 0.70, 0.00 },
+ { 0.10, 0.70, 1.00, 0.20 },
+ { 0.00, 1.00, 1.00, 0.40 },
+ { 1.00, 0.70, 1.00, 0.20 },
+ { 0.20, 0.70, 0.40, 0.40 },
+ { 0.70, 0.70, 1.00, 0.00 },
+ { 0.40, 0.27, 0.27, 0.80 },
+ { 0.40, 0.00, 0.00, 0.60 },
+ { 0.10, 0.20, 1.00, 0.00 },
+ { 0.00, 0.00, 0.00, 0.15 },
+ { 1.00, 1.00, 1.00, 0.20 },
+ { 1.00, 0.40, 0.40, 0.20 },
+ { 0.00, 1.00, 0.00, 0.40 },
+ { 0.70, 0.40, 0.70, 0.80 },
+ { 0.40, 0.70, 0.70, 0.00 },
+ { 0.20, 0.40, 0.00, 0.40 },
+ { 0.70, 0.40, 1.00, 0.40 },
+ { 0.40, 1.00, 0.20, 0.40 },
+ { 0.40, 0.00, 1.00, 0.00 },
+ { 0.40, 0.20, 0.20, 0.00 },
+ { 0.10, 0.20, 0.20, 0.00 },
+ { 0.20, 0.70, 0.40, 0.00 },
+ { 1.00, 0.40, 0.40, 0.80 },
+ { 0.40, 0.00, 0.00, 0.20 },
+ { 0.60, 0.00, 0.00, 0.00 },
+ { 1.00, 0.40, 0.20, 0.60 },
+ { 0.40, 0.20, 1.00, 0.20 },
+ { 0.70, 0.00, 0.70, 0.60 },
+ { 0.40, 0.70, 0.20, 0.00 },
+ { 0.70, 0.00, 0.40, 0.40 },
+ { 0.20, 0.20, 0.20, 0.20 },
+ { 1.00, 0.20, 0.00, 0.00 },
+ { 0.40, 0.70, 0.00, 0.20 },
+ { 0.70, 0.40, 0.70, 0.20 },
+ { 0.70, 0.70, 0.40, 0.40 },
+ { 0.00, 0.00, 0.20, 0.40 },
+ { 0.40, 0.27, 0.27, 1.00 },
+ { 0.40, 0.40, 0.20, 0.40 },
+ { 0.00, 0.40, 0.00, 0.40 },
+ { 0.10, 0.00, 1.00, 0.00 },
+ { 0.10, 0.70, 0.40, 0.00 },
+ { 1.00, 1.00, 0.10, 0.00 },
+ { 0.20, 0.70, 0.70, 0.40 },
+ { 0.20, 0.10, 0.00, 0.00 },
+ { 0.70, 0.70, 1.00, 0.20 },
+ { 0.00, 0.70, 0.40, 0.40 },
+ { 1.00, 0.20, 0.40, 0.60 },
+ { 1.00, 1.00, 0.00, 0.70 },
+ { 0.00, 0.00, 0.70, 0.40 },
+ { 0.10, 0.10, 0.00, 0.00 },
+ { 0.10, 0.00, 0.00, 0.20 },
+ { 0.70, 0.00, 0.40, 0.00 },
+ { 0.00, 1.00, 0.70, 0.60 },
+ { 0.40, 0.00, 0.70, 0.40 },
+ { 0.20, 0.12, 0.12, 0.60 },
+ { 0.40, 0.40, 0.20, 0.00 },
+ { 0.80, 0.65, 0.65, 0.60 },
+ { 1.00, 1.00, 1.00, 0.80 },
+ { 0.20, 0.00, 0.40, 0.60 },
+ { 0.20, 1.00, 0.40, 0.20 },
+ { 0.15, 0.00, 0.00, 0.00 },
+ { 1.00, 1.00, 0.70, 0.40 },
+ { 0.20, 0.10, 0.20, 0.00 },
+ { 0.10, 0.70, 0.00, 0.20 },
+ { 0.00, 1.00, 0.00, 0.80 },
+ { 0.00, 0.00, 0.20, 0.60 },
+ { 0.70, 0.00, 0.20, 0.60 },
+ { 0.20, 0.40, 0.70, 0.40 },
+ { 0.00, 0.70, 0.20, 0.00 },
+ { 0.20, 0.40, 0.20, 0.60 },
+ { 0.00, 0.00, 0.10, 0.20 },
+ { 0.70, 0.70, 0.10, 0.20 },
+ { 1.00, 1.00, 0.70, 0.80 },
+ { 0.40, 0.40, 0.00, 0.40 },
+ { 0.40, 0.70, 0.40, 0.00 },
+ { 0.00, 0.00, 0.07, 0.00 },
+ { 1.00, 0.20, 0.40, 0.20 },
+ { 1.00, 0.20, 0.40, 0.00 },
+ { 0.20, 0.70, 0.10, 0.00 },
+ { 0.00, 0.70, 1.00, 0.00 },
+ { 1.00, 0.10, 0.70, 0.20 },
+ { 0.00, 0.20, 0.00, 0.60 },
+ { 1.00, 0.70, 1.00, 0.00 },
+ { 0.00, 1.00, 0.00, 1.00 },
+ { 0.20, 0.40, 1.00, 0.40 },
+ { 1.00, 0.70, 0.70, 0.00 },
+ { 0.40, 0.10, 0.40, 0.00 }
+};
+
+/* Open the file, return NULL on error */
+FILE *open_928(char *filename) {
+ FILE *fp;
+
+ if ((fp = fopen(filename,"r")) == NULL)
+ return NULL;
+
+ return fp;
+}
+
+/* return non-zero on error */
+int next_928(FILE *fp, int i, double *cmyk) {
+ char buf[200];
+ double w;
+
+ if (fp != NULL) { /* We're reading from a file */
+
+ if (fgets(buf, 200, fp) == NULL)
+ return 1;
+
+ if (sscanf(buf, " %lf %lf %lf %lf %lf", &cmyk[0], &cmyk[1], &cmyk[2], &cmyk[3], &w) != 5)
+ return 1;
+
+ } else { /* Fetch it from our array */
+ cmyk[0] = refvs[i][0];
+ cmyk[1] = refvs[i][1];
+ cmyk[2] = refvs[i][2];
+ cmyk[3] = refvs[i][3];
+ }
+
+ return 0;
+}
+
+void close_928(FILE *fp) {
+ fclose(fp);
+}
+
+
+
diff --git a/profile/mppcheck.c b/profile/mppcheck.c
new file mode 100644
index 0000000..2efe878
--- /dev/null
+++ b/profile/mppcheck.c
@@ -0,0 +1,588 @@
+
+/*
+ * Argyll Color Correction System
+ * Color Printer Device Model Profile checker.
+ * Check an mpp profile against a .ti3 file.
+ *
+ * Author: Graeme W. Gill
+ * Date: 19/3/2003
+ *
+ * Copyright 2003 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.
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "prof.h"
+#include "sort.h"
+
+void
+usage(void) {
+ fprintf(stderr,"Check Model Printer Profile, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: %s [-v] [-c] [-s] [-y] values.ti3 profile.mpp\n",error_program);
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -c Show CIE94 delta E values\n");
+ fprintf(stderr," -k Show CIEDE2000 delta E values\n");
+ fprintf(stderr," -s Check spectral model too\n");
+ fprintf(stderr," -y Detail each value\n");
+ fprintf(stderr," values.ti3 Test values to check against\n");
+ fprintf(stderr," profile.mpp Profile to check\n");
+ exit(1);
+ }
+
+int main(int argc, char *argv[])
+{
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ int cie94 = 0; /* Display CIE94 delta E */
+ int cie2k = 0; /* Display CIEDE2000 delta E */
+ int verify = 0;
+ int ospec = 0; /* Output spectral model flag */
+ static char ti3name[200] = { 0 }; /* Input cgats file base name */
+ static char mppname[200] = { 0 }; /* Profile file base name */
+
+ int i, j;
+ int ti; /* Temporary index */
+ cgats *icg; /* input cgats structure */
+ int devmask; /* ICX ink mask of device space */
+ int devchan; /* Number of chanels in device space */
+ int isLab = 0; /* Flag indicating whether PCS is XYZ or Lab */
+ int isDisplay = 0; /* Flag indicating that this is a display device, not output */
+ double limit = -1.0; /* Ink limit */
+ instType itype = instUnknown; /* Spectral instrument type */
+ int spec_n = 0; /* Number of spectral bands, 0 if not valid */
+ double spec_wl_short = 0.0; /* First reading wavelength in nm (shortest) */
+ double spec_wl_long = 0.0; /* Last reading wavelength in nm (longest) */
+ double norm = 0.0; /* Normalising scale value */
+ int nodp; /* Number of test patches */
+ mppcol *cols; /* Test patches */
+ mpp *p; /* Model Printer Profile */
+
+ double merr = 0.0;
+ double aerr = 0.0;
+ double nsamps = 0.0;
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+ error_program = argv[0];
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ cie94 = 1;
+ cie2k = 0;
+ }
+
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ cie94 = 0;
+ cie2k = 1;
+ }
+
+ /* Verify model against input points */
+ else if (argv[fa][1] == 'y' || argv[fa][1] == 'Y')
+ verify = 1;
+
+ /* Check spectral model */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S')
+ ospec = 1;
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(ti3name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(mppname,argv[fa++]);
+
+ /* Open and look at the .ti3 profile patches file */
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI3"); /* our special input type is Calibration Target Information 3 */
+
+ if (icg->read_name(icg, ti3name))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI3 format file");
+ if (icg->ntables != 1)
+ error ("Input file doesn't contain exactly one table");
+
+ /* If we requested spectral, check that it is available */
+ if (ospec) {
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0) {
+ if (ospec) {
+ error ("No spectral data, so no spectral model output");
+ ospec = 0; /* Can't output spectral model */
+ }
+ } else {
+ spec_n = atoi(icg->t[0].kdata[ti]);
+ if (spec_n > MPP_MXBANDS) {
+ error ("MPP can't cope with %d spectral components", spec_n);
+ ospec = 0; /* Can't output spectral model */
+ /* Alternative would be to downsample the spectrum to fit */
+ }
+ }
+ }
+
+ /* 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");
+
+ if (strcmp(icg->t[0].kdata[ti],"OUTPUT") == 0) {
+ isDisplay = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"DISPLAY") == 0) {
+ isDisplay = 1;
+ } else {
+ error ("Input file must be for an output device");
+ }
+
+ /* Deal with color representation of input */
+ {
+ char *buf;
+ char *inc, *outc;
+
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error("Input file doesn't contain keyword COLOR_REPS");
+
+ if ((buf = strdup(icg->t[0].kdata[ti])) == NULL)
+ error("Malloc failed - color rep");
+
+ /* Split COLOR_REP into device and PCS space */
+ inc = buf;
+ if ((outc = strchr(buf, '_')) == NULL)
+ error("COLOR_REP '%s' invalid", icg->t[0].kdata[ti]);
+ *outc++ = '\000';
+
+ if (strcmp(outc, "XYZ") == 0)
+ isLab = 0;
+ else if (strcmp(outc, "LAB") == 0)
+ isLab = 1;
+ else
+ error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", icg->t[0].kdata[ti]);
+
+ devmask = icx_char2inkmask(inc);
+ devchan = icx_noofinks(devmask);
+
+ if (devchan == 0)
+ error("COLOR_REP '%s' invalid (No matching devmask)", icg->t[0].kdata[ti]);
+
+ if ((nodp = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ free(buf);
+ }
+
+ /* Deal with ink limit */
+ if ((ti = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0) {
+ double imax;
+ imax = atof(icg->t[0].kdata[ti]);
+ if (imax > 1e-4 && imax <= (ICX_MXINKS * 100.0)) {
+ if (limit > 1e-4 && limit <= (ICX_MXINKS * 100.0)) {
+ /* User has specified limit as option */
+ if (imax < limit) {
+ warning("Ink limit greater than original chart! (%f > %f)",limit,imax);
+ }
+ } else {
+ if (imax > 80.0)
+ limit = imax - 10.0; /* Rule of thumb - 10% below chart maximum */
+ else
+ limit = imax;
+ }
+ }
+ }
+
+ if (limit > 1e-4 && limit <= (ICX_MXINKS * 100.0)) {
+ if (verb)
+ printf("Total ink limit being used is %f\n",limit);
+ limit = limit/100.0; /* Set a total ink limit */
+ } else {
+ if (verb)
+ printf("No total ink limit being used\n");
+ limit = 0.0; /* Don't use a limit */
+ }
+
+ if (ospec && !isDisplay) {
+
+ /* Deal with instrument type */
+ if ((ti = icg->find_kword(icg, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Can't find target instrument needed for FWA compensation");
+
+ if ((itype = inst_enum(icg->t[0].kdata[ti])) == instUnknown)
+ error ("Unrecognised target instrument '%s'", icg->t[0].kdata[ti]);
+ }
+
+ if (verb)
+ printf("Device has %d colorants, key = '%s', %s\n", devchan, icx_inkmask2char(devmask, 1),
+ devmask & ICX_ADDITIVE ? "Additive" : "Subtractive");
+
+ if ((cols = new_mppcols(nodp, devchan, spec_n)) == NULL)
+ error("Malloc failed! - cols (%d colors x %d bytes",nodp,sizeof(mppcol));
+
+ /* Read in all the patch values */
+ {
+ int chix[ICX_MXINKS];
+ char *bident;
+ int ii, Xi, Yi, Zi;
+ xspect sp;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+
+ bident = icx_inkmask2char(devmask, 0);
+
+ /* Find the device value fields */
+ for (j = 0; j < devchan; j++) {
+ int ii, imask;
+ char fname[100];
+
+ imask = icx_index2ink(devmask, j);
+ sprintf(fname,"%s_%s",bident,icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (icg->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+
+ chix[j] = ii;
+ }
+
+ if (isLab) { /* Expect Lab */
+ if (verb)
+ printf("Using the instruments Lab values\n");
+ if ((Xi = icg->find_field(icg, 0, "LAB_L")) < 0)
+ error("Input file doesn't contain field LAB_L");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error("Field LAB_L is wrong type");
+ if ((Yi = icg->find_field(icg, 0, "LAB_A")) < 0)
+ error("Input file doesn't contain field LAB_A");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error("Field LAB_A is wrong type");
+ if ((Zi = icg->find_field(icg, 0, "LAB_B")) < 0)
+ error("Input file doesn't contain field LAB_B");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error("Field LAB_B is wrong type");
+
+ } else { /* Expect XYZ */
+ if (verb)
+ printf("Using the instruments XYZ values\n");
+ if ((Xi = icg->find_field(icg, 0, "XYZ_X")) < 0)
+ error("Input file doesn't contain field XYZ_X");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error("Field XYZ_X is wrong type");
+ if ((Yi = icg->find_field(icg, 0, "XYZ_Y")) < 0)
+ error("Input file doesn't contain field XYZ_Y");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error("Field XYZ_Y is wrong type");
+ if ((Zi = icg->find_field(icg, 0, "XYZ_Z")) < 0)
+ error("Input file doesn't contain field XYZ_Z");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error("Field XYZ_Z is wrong type");
+ }
+
+ /* If we need the spectral information, find the fields */
+ if (ospec) {
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ sp.spec_n = atoi(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ sp.spec_wl_short = atof(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ sp.spec_wl_long = atof(icg->t[0].kdata[ii]);
+ sp.norm = 100.0;
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = icg->find_field(icg, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",buf);
+ }
+
+ /* Record spectral parameters */
+ spec_n = sp.spec_n;
+ spec_wl_short = sp.spec_wl_short;
+ spec_wl_long = sp.spec_wl_long;
+ norm = sp.norm;
+ } else {
+ spec_n = 0; /* Not using spectral in model */
+ }
+
+ /* Load up all the patch values */
+ for (i = 0; i < nodp; i++) {
+
+ /* read in device values */
+ for (j = 0; j < devchan; j++)
+ cols[i].nv[j] = *((double *)icg->t[0].fdata[i][chix[j]])/100.0;
+
+ /* Read the spectral values for this patch */
+ if (ospec) {
+
+ /* norm takes care of 100 scale */
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+ if (ospec)
+ cols[i].band[3+j] = sp.spec[j];
+ }
+ }
+
+ /* Use the instrument CIE values */
+ if (isLab) {
+ cols[i].band[0] = *((double *)icg->t[0].fdata[i][Xi]);
+ cols[i].band[1] = *((double *)icg->t[0].fdata[i][Yi]);
+ cols[i].band[2] = *((double *)icg->t[0].fdata[i][Zi]);
+ icmLab2XYZ(&icmD50, cols[i].band, cols[i].band);
+ } else {
+ cols[i].band[0] = *((double *)icg->t[0].fdata[i][Xi])/100.0;
+ cols[i].band[1] = *((double *)icg->t[0].fdata[i][Yi])/100.0;
+ cols[i].band[2] = *((double *)icg->t[0].fdata[i][Zi])/100.0;
+ }
+ }
+
+ free(bident);
+
+ } /* End of reading in CGATs file */
+
+ /* Done with inputs to mpp->create() */
+ icg->del(icg);
+
+ merr = 0.0;
+ aerr = 0.0;
+ nsamps = 0.0;
+
+ if ((p = new_mpp()) == NULL)
+ error("Failed to create an mpp");
+
+ if (p->read_mpp(p, mppname))
+ error("Read error : %s",p->err);
+
+ /* Set just PCS and use XYZ model */
+ p->set_ilob(p, icxIT_default, NULL, icxOT_default, NULL, icSigLabData, 0);
+
+ for (i = 0; i < nodp; i++) {
+ double out[3], ref[3];
+ double mxd;
+
+ /* Lookup the profile PCS value for this data point */
+ p->lookup(p, out, cols[i].nv);
+
+ /* Convert our cols data to Lab */
+ icmXYZ2Lab(&icmD50, ref, cols[i].band);
+
+ if (verify && verb) {
+ printf("[%f] ", cie2k ? icmCIE2K(ref, out) :
+ cie94 ? icmCIE94(ref, out) : icmLabDE(ref, out));
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> %5.1f %5.1f %5.1f should be %5.1f %5.1f %5.1f\n",
+ out[0],out[1],out[2], ref[0],ref[1],ref[2]);
+ }
+
+ /* Check the result */
+ mxd = cie2k ? icmCIE2K(ref, out) : cie94 ? icmCIE94(ref, out) : icmLabDE(ref, out);
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += mxd;
+ nsamps++;
+ }
+ printf("Read profile %s check complete, avg err = %f, max err = %f\n",
+ cie2k ? "CIEDE2000" : cie94 ? "CIE94" : "Lab", aerr/nsamps, merr); fflush(stdout);
+
+ if (ospec) {
+ merr = 0.0;
+ aerr = 0.0;
+ nsamps = 0.0;
+
+ for (i = 0; i < nodp; i++) {
+ xspect out;
+ double avd, mxd;
+
+ /* Lookup the profile spectral value for this data point */
+ p->lookup_spec(p, &out, cols[i].nv);
+
+ if (spec_n != out.spec_n)
+ error("Mismatch between original spectral and returned");
+
+ avd = mxd = 0.0;
+ for (j = 0; j < spec_n; j++) {
+ double ded;
+ ded = fabs(out.spec[j]/out.norm - cols[i].band[3+j]/norm);
+ avd += ded;
+ if (ded > mxd)
+ mxd = ded;
+ }
+ avd /= (double)spec_n;
+
+ if (verify && verb) {
+ printf("[%f %f] ", avd, mxd);
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> ");
+ for (j = 0; j < spec_n; j++)
+ printf("%2.0f ", out.spec[j]);
+
+ printf("should be ");
+ for (j = 0; j < spec_n; j++)
+ printf("%2.0f ", cols[i].band[3+j]);
+ printf("\n");
+ }
+
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += avd;
+ nsamps++;
+ }
+ printf("profile spectral check complete, avg err = %f%%, max err = %f%%\n",
+ aerr * 100.0/nsamps, merr * 100.0); fflush(stdout);
+
+ /* Check spectrally derived Lab values */
+ {
+ xsp2cie *sc;
+ xspect sp;
+
+ if ((sc = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
+ error("Failed to create xsp2cie object");
+
+ /* Set standard D50 viewer & illum. */
+ p->set_ilob(p, icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, 0);
+
+ merr = 0.0;
+ aerr = 0.0;
+ nsamps = 0.0;
+
+ for (i = 0; i < nodp; i++) {
+ double out[3], ref[3];
+ double mxd;
+
+ /* Lookup the profile PCS value for this data point */
+ p->lookup(p, out, cols[i].nv);
+
+ /* Convert our cols ref data to Lab */
+ sp.spec_n = spec_n;
+ sp.spec_wl_short = spec_wl_short;
+ sp.spec_wl_long = spec_wl_long;
+ sp.norm = norm;
+ for (j = 0; j < spec_n; j++)
+ sp.spec[j] = cols[i].band[3+j];
+ sc->convert(sc, ref, &sp);
+
+ if (verify && verb) {
+ printf("[%f] ", cie2k ? icmCIE2K(ref, out) :
+ cie94 ? icmCIE94(ref, out) : icmLabDE(ref, out));
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> %5.1f %5.1f %5.1f should be %5.1f %5.1f %5.1f\n",
+ out[0],out[1],out[2], ref[0],ref[1],ref[2]);
+ }
+
+ /* Check the result */
+ mxd = cie2k ? icmCIE2K(ref, out) : cie94 ? icmCIE94(ref, out) : icmLabDE(ref, out);
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += mxd;
+ nsamps++;
+ }
+ printf("Read profile spectral %s check complete, avg err = %f, max err = %f\n",
+ cie2k ? "CIEDE2000" : cie94 ? "CIE94" : "Lab", aerr/nsamps, merr);
+ fflush(stdout);
+
+ sc->del(sc);
+ }
+ }
+
+ p->del(p);
+
+ /* Clean up */
+ del_mppcols(cols, nodp, devchan, spec_n);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/profile/mppprof.c b/profile/mppprof.c
new file mode 100644
index 0000000..0c3593f
--- /dev/null
+++ b/profile/mppprof.c
@@ -0,0 +1,961 @@
+
+/*
+ * Argyll Color Correction System
+ * Color Printer Device Model Profile generator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/2/2002
+ *
+ * Copyright 2003 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.
+ */
+
+/*
+ * This program takes in the scattered test chart
+ * points, and creates a model based forward printer profile
+ * (Device -> CIE + spectral), based on Neugenbauer equations.
+ * It is designed to handle an arbitrary number of colorants,
+ * and in the future, (optionaly) create an aproximate ink overlap/mixing model
+ * to allow synthesis of a forward model for a hyperthetical
+ * similar printing process with aditional inks.
+ *
+ * This code is based on profile.c, sprof.c and xlut.c
+ *
+ */
+
+/*
+ * TTBD:
+ *
+ * Add ink order and overlay modeling stuff back in, with
+ * new ink overlay model (see mpprof0.c).
+ *
+ * Add options to set extra information in xpi structure.
+ *
+ * Rather than computing XYZ based versios of the print model
+ * and ink mixing models, should compute spectrally sharpened
+ * equivalents to XYZ ??
+ *
+ * Fixup error handling in make_output_mpp()
+ *
+ */
+
+#undef DEBUG
+
+#undef DOQUAD /* Minimise error^4 */
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "cgats.h"
+#include "numlib.h"
+#include "xicc.h"
+#include "prof.h"
+#include "../h/sort.h"
+
+void
+usage(void) {
+ fprintf(stderr,"Create Model Printer Profile, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: %s [options] outfile\n",error_program);
+ fprintf(stderr," -v [level] Verbose mode\n");
+ fprintf(stderr," -q [lmhus] Quality - Low, Medium (def), High, Ultra, Simple\n");
+// fprintf(stderr," -q [vfmsu] Speed - Very Fast, Medium (def), Slow, Ultra Slow\n");
+ fprintf(stderr," -l limit override default ink limit, 1 - n00%%\n");
+ fprintf(stderr," -s Generate spectral model too\n");
+ fprintf(stderr," -m Generate ink mixing model\n");
+ fprintf(stderr," -y [level] Verify profile, 2 = read/write verify\n");
+ fprintf(stderr," -L Output Lab values\n");
+ fprintf(stderr," outfile Base name for input.ti3/output.mpp file\n");
+ exit(1);
+ }
+
+/* Worker function */
+static int make_output_mpp(int verb, int quality, int verify, char *inname, char *outname,
+int dolab, double ilimit, int ospec, int omix, profxinf *xpi);
+
+int main(int argc, char *argv[])
+{
+ int fa,nfa,mfa; /* current argument we're looking at */
+ int verb = 0;
+ int iquality = 1; /* Forward quality, default medium */
+ int dolab = 0;
+ int verify = 0; /* Verify each point */
+ double limit = -1.0; /* Ink limit */
+ int ospec = 0; /* Output spectral model flag */
+ int omix = 0; /* Output mixing model flag */
+ static char inname[200] = { 0 }; /* Input cgats file base name */
+ static char outname[200] = { 0 }; /* Output cgats file base name */
+ profxinf xpi; /* Extra profile information */
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+ error_program = argv[0];
+ check_if_not_interactive();
+ memset((void *)&xpi, 0, sizeof(profxinf)); /* Init extra profile info to defaults */
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ mfa = 1; /* Expect out filename */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ fa = nfa;
+ if (na == NULL) {
+ verb = 1;
+ } else {
+ verb = atoi(na);
+ }
+ }
+
+ /* Ink Limit */
+ else if (argv[fa][1] == 'l') {
+ fa = nfa;
+ if (na == NULL) usage();
+ limit = atof(na);
+ }
+
+ /* Verify model against input points */
+ else if (argv[fa][1] == 'y' || argv[fa][1] == 'Y') {
+ fa = nfa;
+ if (na == NULL) {
+ verify = 1;
+ } else {
+ verify = atoi(na);
+ }
+ }
+
+ /* Quality */
+ else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'v': /* Very fast */
+ case 'V':
+ iquality = 99;
+ break;
+ case 'f': /* fast */
+ case 'l':
+ case 'L':
+ iquality = 0;
+ break;
+ case 'm': /* medium */
+ case 'M':
+ iquality = 1;
+ break;
+ case 's': /* slow */
+ case 'h':
+ case 'H':
+ iquality = 2;
+ break;
+ case 'u': /* ultra slow */
+ case 'U':
+ iquality = 3;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Output spectral model */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S')
+ ospec = 1;
+
+ /* Output mixing model */
+ else if (argv[fa][1] == 'm' || argv[fa][1] == 'M')
+ omix = 1;
+
+ /* Output Lab values rather than XYZ */
+ else if (argv[fa][1] == 'L')
+ dolab = 1;
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(inname,argv[fa]);
+ strcat(inname,".ti3");
+ strcpy(outname,argv[fa]);
+ strcat(outname,".mpp");
+
+ if (make_output_mpp(verb, iquality, verify, inname, outname,
+ dolab, limit, ospec, omix, &xpi) != 0) {
+ error ("making mpp failed");
+ }
+
+ return 0;
+}
+
+/* ===================================== */
+/* Make a DeviceN model printing profile */
+/* return nz on error */
+static int
+make_output_mpp(
+ int verb, /* Vebosity level, 0 = none, 1 = summary, 2 = detail */
+ int quality, /* quality, 0..3 */
+ int verify, /* verify result flag */
+ char *inname, /* Input .ti3 file name */
+ char *outname, /* Output .mpp file name */
+ int dolab, /* NZ if Lab output */
+ double limit, /* Ink limit, -1.0 == default */
+ int ospec, /* Output spectral model */
+ int omix, /* Output ink mixing model */
+ profxinf *xpi /* Optional Profile creation extra data */
+) {
+ int i, j;
+ int ti; /* Temporary index */
+ cgats *icg; /* input cgats structure */
+ int devmask; /* ICX ink mask of device space */
+ int devchan; /* Number of chanels in device space */
+ int isLab = 0; /* Flag indicating whether PCS is XYZ or Lab */
+ int isDisplay = 0; /* Flag indicating that this is a display device, not output */
+ int isdnormed = 0; /* Has display data been normalised to 100 ? */
+ instType itype = instUnknown; /* Spectral instrument type */
+ int spec_n = 0; /* Number of spectral bands, 0 if not valid */
+ double spec_wl_short = 0.0; /* First reading wavelength in nm (shortest) */
+ double spec_wl_long = 0.0; /* Last reading wavelength in nm (longest) */
+ double norm = 0.0; /* Normalising scale value */
+ int nodp; /* Number of test patches */
+ mppcol *cols; /* Test patches */
+ mpp *p; /* Model Printer Profile */
+
+ /* Open and look at the .ti3 profile patches file */
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI3"); /* our special input type is Calibration Target Information 3 */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI3 format file");
+ if (icg->ntables < 1)
+ error ("Input file doesn't contain at least one table");
+
+ /* If we requested spectral, check that it is available */
+ if (ospec) {
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0) {
+ if (ospec) {
+ error ("No spectral data, so no spectral model output");
+ ospec = 0; /* Can't output spectral model */
+ }
+ } else {
+ spec_n = atoi(icg->t[0].kdata[ti]);
+ if (spec_n > MPP_MXBANDS) {
+ error ("MPP can't cope with %d spectral components", spec_n);
+ ospec = 0; /* Can't output spectral model */
+ /* Alternative would be to downsample the spectrum to fit */
+ }
+ }
+ }
+
+ /* 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");
+
+ if (strcmp(icg->t[0].kdata[ti],"OUTPUT") == 0) {
+ isDisplay = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"DISPLAY") == 0) {
+ isDisplay = 1;
+ } else {
+ error ("Input file must be for an output device");
+ }
+
+ /* See if the display CIE data has been normalised to Y = 100 */
+ if ((ti = icg->find_kword(icg, 0, "NORMALIZED_TO_Y_100")) < 0
+ || strcmp(icg->t[0].kdata[ti],"NO") == 0) {
+ isdnormed = 0;
+ } else {
+ isdnormed = 1;
+ }
+
+ /* Deal with color representation of input */
+ {
+ char *buf;
+ char *inc, *outc;
+
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error("Input file doesn't contain keyword COLOR_REPS");
+
+ if ((buf = strdup(icg->t[0].kdata[ti])) == NULL)
+ error("Malloc failed - color rep");
+
+ /* Split COLOR_REP into device and PCS space */
+ inc = buf;
+ if ((outc = strchr(buf, '_')) == NULL)
+ error("COLOR_REP '%s' invalid", icg->t[0].kdata[ti]);
+ *outc++ = '\000';
+
+ if (strcmp(outc, "XYZ") == 0)
+ isLab = 0;
+ else if (strcmp(outc, "LAB") == 0)
+ isLab = 1;
+ else
+ error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", icg->t[0].kdata[ti]);
+
+ devmask = icx_char2inkmask(inc);
+ devchan = icx_noofinks(devmask);
+
+ if (devchan == 0)
+ error("COLOR_REP '%s' invalid (No matching devmask)", icg->t[0].kdata[ti]);
+
+ if ((nodp = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ free(buf);
+ }
+
+ /* Deal with ink limit */
+ if ((ti = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0) {
+ double imax;
+ imax = atof(icg->t[0].kdata[ti]);
+ if (imax > 1e-4 && imax <= (ICX_MXINKS * 100.0)) {
+ if (limit > 1e-4 && limit <= (ICX_MXINKS * 100.0)) {
+ /* User has specified limit as option */
+ if (imax < limit) {
+ warning("Ink limit greater than original chart! (%f > %f)",limit,imax);
+ }
+ } else {
+#ifdef NEVER /* Don't need rule of thumb in MPP's ?? */
+ if (imax > 80.0)
+ limit = imax - 10.0; /* Rule of thumb - 10% below chart maximum */
+ else
+#endif /* NEVER */
+ limit = imax;
+ }
+ }
+ }
+
+ if (limit > 1e-4 && limit <= (ICX_MXINKS * 100.0)) {
+ if (verb)
+ printf("Total ink limit being used is %f\n",limit);
+ limit = limit/100.0; /* Set a total ink limit */
+ } else {
+ if (verb)
+ printf("No total ink limit being used\n");
+ limit = 0.0; /* Don't use a limit */
+ }
+
+ if (ospec && !isDisplay) {
+
+ /* Deal with instrument type */
+ if ((ti = icg->find_kword(icg, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Can't find target instrument needed for FWA compensation");
+
+ if ((itype = inst_enum(icg->t[0].kdata[ti])) == instUnknown)
+ error ("Unrecognised target instrument '%s'", icg->t[0].kdata[ti]);
+ }
+
+ if (verb)
+ printf("Device has %d colorants, key = '%s', %s\n", devchan, icx_inkmask2char(devmask, 1),
+ devmask & ICX_ADDITIVE ? "Additive" : "Subtractive");
+
+ if ((cols = new_mppcols(nodp, devchan, spec_n)) == NULL)
+ error("Malloc failed! - cols (%d colors x %d bytes",nodp,sizeof(mppcol));
+
+ /* Read in all the patch values from the CGATS file */
+ {
+ int chix[ICX_MXINKS];
+ char *bident;
+ int ii, Xi, Yi, Zi;
+ xspect sp;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+
+ bident = icx_inkmask2char(devmask, 0);
+
+ /* Find the device value fields */
+ for (j = 0; j < devchan; j++) {
+ int ii, imask;
+ char fname[100];
+
+ imask = icx_index2ink(devmask, j);
+ sprintf(fname,"%s_%s",bident,icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (icg->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+
+ chix[j] = ii;
+ }
+
+ if (isLab) { /* Expect Lab */
+ if (verb)
+ printf("Using the instruments Lab values\n");
+ if ((Xi = icg->find_field(icg, 0, "LAB_L")) < 0)
+ error("Input file doesn't contain field LAB_L");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error("Field LAB_L is wrong type");
+ if ((Yi = icg->find_field(icg, 0, "LAB_A")) < 0)
+ error("Input file doesn't contain field LAB_A");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error("Field LAB_A is wrong type");
+ if ((Zi = icg->find_field(icg, 0, "LAB_B")) < 0)
+ error("Input file doesn't contain field LAB_B");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error("Field LAB_B is wrong type");
+
+ } else { /* Expect XYZ */
+ if (verb)
+ printf("Using the instruments XYZ values\n");
+ if ((Xi = icg->find_field(icg, 0, "XYZ_X")) < 0)
+ error("Input file doesn't contain field XYZ_X");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error("Field XYZ_X is wrong type");
+ if ((Yi = icg->find_field(icg, 0, "XYZ_Y")) < 0)
+ error("Input file doesn't contain field XYZ_Y");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error("Field XYZ_Y is wrong type");
+ if ((Zi = icg->find_field(icg, 0, "XYZ_Z")) < 0)
+ error("Input file doesn't contain field XYZ_Z");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error("Field XYZ_Z is wrong type");
+ }
+
+ /* If we need the spectral information, find the fields */
+ if (ospec) {
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ sp.spec_n = atoi(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ sp.spec_wl_short = atof(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ sp.spec_wl_long = atof(icg->t[0].kdata[ii]);
+ sp.norm = 1.0; /* MPP uses norm of 1.0 */
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = icg->find_field(icg, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",buf);
+ }
+ }
+
+ if (ospec) { /* Record spectral parameters */
+ spec_n = sp.spec_n;
+ spec_wl_short = sp.spec_wl_short;
+ spec_wl_long = sp.spec_wl_long;
+ norm = sp.norm;
+ } else {
+ spec_n = 0; /* Not using spectral in model */
+ }
+
+ /* Load up all the patch values */
+ for (i = 0; i < nodp; i++) {
+
+ /* read in device values */
+ for (j = 0; j < devchan; j++)
+ cols[i].nv[j] = *((double *)icg->t[0].fdata[i][chix[j]])/100.0;
+
+ /* Read the spectral values for this patch */
+ if (ospec) {
+
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+ if (ospec) {
+ if (!isDisplay || isdnormed)
+ cols[i].band[3+j] = sp.spec[j]/100.0; /* Convert to 1.0 norm */
+ else
+ cols[i].band[3+j] = sp.spec[j]; /* Absolute */
+ }
+ }
+ }
+
+ /* Use the instrument CIE values */
+ if (isLab) {
+ cols[i].band[0] = *((double *)icg->t[0].fdata[i][Xi]);
+ cols[i].band[1] = *((double *)icg->t[0].fdata[i][Yi]);
+ cols[i].band[2] = *((double *)icg->t[0].fdata[i][Zi]);
+ icmLab2XYZ(&icmD50, cols[i].band, cols[i].band);
+ } else {
+ cols[i].band[0] = *((double *)icg->t[0].fdata[i][Xi]);
+ cols[i].band[1] = *((double *)icg->t[0].fdata[i][Yi]);
+ cols[i].band[2] = *((double *)icg->t[0].fdata[i][Zi]);
+
+ /* Convert % to 1.0 scale */
+ if (!isDisplay || isdnormed) {
+ cols[i].band[0] /= 100.0;
+ cols[i].band[1] /= 100.0;
+ cols[i].band[2] /= 100.0;
+ }
+ }
+ }
+
+ free(bident);
+
+ /* Normalize display values to Y = 1.0 for display */
+ if (isDisplay && !isdnormed) {
+
+ /* XYZ not already normed */
+ if (isdnormed == 0) {
+ double scale = -1e6;
+
+ /* Locate max Y */
+ for (i = 0; i < nodp; i++) {
+ if (cols[i].band[1] > scale)
+ scale = cols[i].band[1];
+ }
+
+ scale = 1.0/scale;
+
+ for (i = 0; i < nodp; i++) {
+ cols[i].band[0] *= scale;
+ cols[i].band[1] *= scale;
+ cols[i].band[2] *= scale;
+ }
+
+ /* Keep spectral consistent, but won't necessarily */
+ /* give Y = 1.0 for a non 1931_2 observer. */
+ if (ospec) {
+ for (i = 0; i < nodp; i++) {
+ for (j = 0; j < sp.spec_n; j++) {
+ cols[i].band[3+j] *= scale;
+ }
+ }
+ }
+ }
+ }
+ } /* End of reading in CGATs file */
+
+ /* Create the mpp */
+ if ((p = new_mpp()) == NULL)
+ return 1;
+
+ /* Create from scattered data */
+ if (p->create(p, verb, quality, isDisplay, limit, devmask, spec_n, spec_wl_short, spec_wl_long,
+ norm, itype, nodp, cols) != 0) {
+ return 1;
+ }
+
+ /* Done with inputs to mpp->create() */
+ icg->del(icg);
+
+ /* Estimate the ink mixing model */
+ if (omix) {
+ printf("The ink mixing model isn't implimented here yet\n");
+ }
+
+ /* create and write the cgats profile */
+ if (p->write_mpp(p, outname, dolab))
+ error("Write error : %s",p->err);
+
+ /* Check the forward profile accuracy against the data points */
+ if (verb || verify) {
+ double merr = 0.0;
+ double aerr = 0.0;
+ double nsamps = 0.0;
+
+ /* Set just PCS and use XYZ model */
+ p->set_ilob(p, icxIT_default, NULL, icxOT_default, NULL, icSigLabData, 0);
+
+ for (i = 0; i < nodp; i++) {
+ double out[3], ref[3];
+ double mxd;
+
+ /* Lookup the profile PCS value for this data point */
+ p->lookup(p, out, cols[i].nv);
+
+ /* Convert our cols data to Lab */
+ icmXYZ2Lab(&icmD50, ref, cols[i].band);
+
+ if ((verify && verb) || verb >= 2) {
+ printf("[%f] ", icmLabDE(ref, out));
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> %5.1f %5.1f %5.1f should be %5.1f %5.1f %5.1f\n",
+ out[0],out[1],out[2], ref[0],ref[1],ref[2]);
+ }
+
+ /* Check the result */
+ mxd = icmLabDE(ref, out);
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += mxd;
+ nsamps++;
+ }
+ printf("Profile Lab check complete, peak err = %f, avg err = %f\n",
+ merr, aerr/nsamps);
+
+ if (ospec) {
+ double maxsp = -1e6;
+ merr = 0.0;
+ aerr = 0.0;
+ nsamps = 0.0;
+
+ for (i = 0; i < nodp; i++) {
+ xspect out;
+ double avd, mxd;
+
+ /* Lookup the profile spectral value for this data point */
+ p->lookup_spec(p, &out, cols[i].nv);
+
+ if (spec_n != out.spec_n)
+ error("Mismatch between original spectral and returned");
+
+ avd = mxd = 0.0;
+ for (j = 0; j < spec_n; j++) {
+ double ded;
+ if (out.spec[j] > maxsp)
+ maxsp = out.spec[j];
+ if (cols[i].band[3+j] > maxsp)
+ maxsp = out.spec[j];
+ ded = fabs(out.spec[j] - cols[i].band[3+j]);
+ avd += ded;
+ if (ded > mxd)
+ mxd = ded;
+ }
+ avd /= (double)spec_n;
+
+ if ((verify && verb) || verb >= 2) {
+ printf("[%f %f] ", avd, mxd);
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> ");
+#ifdef NEVER
+ for (j = 0; j < spec_n; j++)
+ printf("%2.0f ", out.spec[j]);
+ printf("should be ");
+ for (j = 0; j < spec_n; j++)
+ printf("%2.0f ", cols[i].band[3+j]);
+#else
+ for (j = 0; j < spec_n; j++)
+ printf("%f ", out.spec[j]);
+ printf("should be ");
+ for (j = 0; j < spec_n; j++)
+ printf("%f ", cols[i].band[3+j]);
+#endif
+ printf("\n");
+ }
+
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += avd;
+ nsamps++;
+ }
+ printf("profile spectral check complete, avg err = %f%%, max err = %f%%\n",
+ aerr * 100.0/nsamps * 1.0/maxsp, merr * 100.0/maxsp);
+
+ /* Check spectrally derived Lab values */
+ {
+ xsp2cie *sc;
+ xspect sp;
+
+ if (isDisplay) {
+ if ((sc = new_xsp2cie(icxIT_none, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
+ error("Failed to create xsp2cie object");
+
+ p->set_ilob(p, icxIT_none, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, 0);
+ } else {
+ /* Set standard D50 viewer & illum. */
+ if ((sc = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
+ error("Failed to create xsp2cie object");
+
+ p->set_ilob(p, icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, 0);
+ }
+
+ merr = 0.0;
+ aerr = 0.0;
+ nsamps = 0.0;
+
+ for (i = 0; i < nodp; i++) {
+ double out[3], ref[3];
+ double mxd;
+
+ /* Lookup the profile PCS value for this data point */
+ p->lookup(p, out, cols[i].nv);
+
+ /* Convert our cols ref data to Lab */
+ sp.spec_n = spec_n;
+ sp.spec_wl_short = spec_wl_short;
+ sp.spec_wl_long = spec_wl_long;
+ sp.norm = norm;
+ for (j = 0; j < spec_n; j++)
+ sp.spec[j] = cols[i].band[3+j];
+ sc->convert(sc, ref, &sp);
+
+ if ((verify && verb) || verb >= 2) {
+ printf("[%f] ", icmLabDE(ref, out));
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> %5.1f %5.1f %5.1f should be %5.1f %5.1f %5.1f\n",
+ out[0],out[1],out[2], ref[0],ref[1],ref[2]);
+ }
+
+ /* Check the result */
+ mxd = icmLabDE(ref, out);
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += mxd;
+ nsamps++;
+ }
+ printf("Profile spectral Lab check complete, avg err = %f, max err = %f\n",
+ aerr/nsamps, merr);
+
+ sc->del(sc);
+ }
+ }
+ }
+
+
+ /* Test again by reading and loading the profile */
+ if (verify >= 2) {
+ mpp *p2; /* Second test profile */
+ double merr = 0.0;
+ double aerr = 0.0;
+ double nsamps = 0.0;
+
+ printf("\n");
+ if ((p2 = new_mpp()) == NULL)
+ error("Failed to create an mpp");
+
+ if (p2->read_mpp(p2, outname))
+ error("Read error : %s",p2->err);
+
+ {
+ /* Set just PCS and use XYZ model */
+ p2->set_ilob(p2, icxIT_default, NULL, icxOT_default, NULL, icSigLabData, 0);
+
+ for (i = 0; i < nodp; i++) {
+ double out[3], ref[3];
+ double mxd;
+
+ /* Lookup the profile PCS value for this data point */
+ p2->lookup(p2, out, cols[i].nv);
+
+ /* Convert our cols data to Lab */
+ icmXYZ2Lab(&icmD50, ref, cols[i].band);
+
+ if (verify && verb) {
+ printf("[%f] ", icmLabDE(ref, out));
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> %5.1f %5.1f %5.1f should be %5.1f %5.1f %5.1f\n",
+ out[0],out[1],out[2], ref[0],ref[1],ref[2]);
+ }
+
+ /* Check the result */
+ mxd = icmLabDE(ref, out);
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += mxd;
+ nsamps++;
+ }
+ printf("Read profile Lab check complete, avg err = %f, max err = %f\n",
+ aerr/nsamps, merr); fflush(stdout);
+
+ if (ospec) {
+ double maxsp = -1e6;
+ merr = 0.0;
+ aerr = 0.0;
+ nsamps = 0.0;
+
+ for (i = 0; i < nodp; i++) {
+ xspect out;
+ double avd, mxd;
+
+ /* Lookup the profile spectral value for this data point */
+ p2->lookup_spec(p2, &out, cols[i].nv);
+
+ if (spec_n != out.spec_n)
+ error("Mismatch between original spectral and returned");
+
+ avd = mxd = 0.0;
+ for (j = 0; j < spec_n; j++) {
+ double ded;
+ if (out.spec[j] > maxsp)
+ maxsp = out.spec[j];
+ if (cols[i].band[3+j] > maxsp)
+ maxsp = out.spec[j];
+ ded = fabs(out.spec[j] - cols[i].band[3+j]);
+ avd += ded;
+ if (ded > mxd)
+ mxd = ded;
+ }
+ avd /= (double)spec_n;
+
+ if (verify && verb) {
+ printf("[%f %f] ", avd, mxd);
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> ");
+#ifdef NEVER
+ for (j = 0; j < spec_n; j++)
+ printf("%2.0f ", out.spec[j]);
+ printf("should be ");
+ for (j = 0; j < spec_n; j++)
+ printf("%2.0f ", cols[i].band[3+j]);
+#else
+ for (j = 0; j < spec_n; j++)
+ printf("%f ", out.spec[j]);
+ printf("should be ");
+ for (j = 0; j < spec_n; j++)
+ printf("%f ", cols[i].band[3+j]);
+#endif
+ printf("\n");
+ }
+
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += avd;
+ nsamps++;
+ }
+ printf("profile spectral check complete, avg err = %f, max err = %f\n",
+ aerr * 100.0/nsamps * 1.0/maxsp, merr * 100.0/maxsp); fflush(stdout);
+
+ /* Check spectrally derived Lab values */
+ {
+ xsp2cie *sc;
+ xspect sp;
+
+
+ if (isDisplay) {
+ /* Set emissive viewer. */
+ if ((sc = new_xsp2cie(icxIT_none, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
+ error("Failed to create xsp2cie object");
+ /* (mpp will ignore illuminant for display anyway ??) */
+ p2->set_ilob(p2, icxIT_none, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, 0);
+ } else {
+ /* Set standard D50 viewer & illum. */
+ if ((sc = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
+ error("Failed to create xsp2cie object");
+ p2->set_ilob(p2, icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, 0);
+ }
+
+ merr = 0.0;
+ aerr = 0.0;
+ nsamps = 0.0;
+
+ for (i = 0; i < nodp; i++) {
+ double out[3], ref[3];
+ double mxd;
+
+ /* Lookup the profile PCS value for this data point */
+ p2->lookup(p2, out, cols[i].nv);
+
+ /* Convert our cols ref data to Lab */
+ sp.spec_n = spec_n;
+ sp.spec_wl_short = spec_wl_short;
+ sp.spec_wl_long = spec_wl_long;
+ sp.norm = norm;
+ for (j = 0; j < spec_n; j++)
+ sp.spec[j] = cols[i].band[3+j];
+ sc->convert(sc, ref, &sp);
+
+ if (verify && verb) {
+ printf("[%f] ", icmLabDE(ref, out));
+ for (j = 0; j < devchan; j++)
+ printf("%6.4f ", cols[i].nv[j]);
+ printf("-> %5.1f %5.1f %5.1f should be %5.1f %5.1f %5.1f\n",
+ out[0],out[1],out[2], ref[0],ref[1],ref[2]);
+ }
+
+ /* Check the result */
+ mxd = icmLabDE(ref, out);
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += mxd;
+ nsamps++;
+ }
+ printf("Read profile spectral Lab check complete, avg err = %f, max err = %f\n",
+ aerr/nsamps, merr); fflush(stdout);
+
+ sc->del(sc);
+ }
+ }
+ }
+
+ if (p2->write_mpp(p2, "xxxx.mpp", dolab))
+ error("Write error : %s",p2->err);
+
+ p2->del(p2);
+ }
+
+ /* Clean up */
+ del_mppcols(cols, nodp, devchan, spec_n);
+
+ p->del(p);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/profile/printcal.c b/profile/printcal.c
new file mode 100644
index 0000000..f9107eb
--- /dev/null
+++ b/profile/printcal.c
@@ -0,0 +1,2320 @@
+
+
+
+/*
+ * Argyll Color Correction System
+ * Print Device calibration curve generator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/3/3
+ *
+ * Copyright 1996-2008 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.
+ */
+
+/*
+ * This program takes in the colorent wedge test chart
+ * points, and creates a set of per channel correction curves.
+ */
+
+/*
+ * TTBD:
+ * Allow auto max threshold to be scaled on command line ?
+ * ie. -m# set % to go below the default optimal maximum.
+ */
+
+
+/*
+ Additive spaces are handled by inverting the device values internally.
+ (Such a space should probably have ICX_INVERTED set as well, indicating
+ that the underlying device is actually subtractive.)
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "cgats.h"
+#include "numlib.h"
+#include "sort.h"
+#include "rspl.h"
+#include "xicc.h"
+#include "plot.h"
+
+
+#define RSPLFLAGS (0 /* | RSPL_2PASSSMTH | RSPL_EXTRAFIT2 */)
+
+#define RSPLSMOOTH 2.0 /* RSPL Smoothness factor use on measured device points */
+
+#define TCURVESMOOTH 1.0 /* RSPL smoothness factor for target aim points */
+
+#define GRES 256 /* Rspl grid resolution */
+#define SLOPE_NORM 70.0 /* Normalized delta E for below thresholds */
+#define MIN_SLOPE_A 8.0 /* Criteria for Auto max, DE/dDev at max */
+#define MIN_SLOPE_O 3.0 /* Criteria for Auto max, min DE/dDev below max */
+
+#define CAL_RES 256 /* Resolution saved to .cal file */
+
+#define PRES 256 /* Plotting resolution */
+
+void usage(char *diag, ...) {
+ int i;
+ fprintf(stderr,"Create printer calibration, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: %s [-options] [prevcal] inoutfile\n",error_program);
+ fprintf(stderr," -v verbosity Verbose mode\n");
+ fprintf(stderr," -p Plot graphs.\n");
+ fprintf(stderr," -i Initial calibration, set targets, create .cal\n");
+ fprintf(stderr," -r Re-calibrate against previous .cal and create new .cal\n");
+ fprintf(stderr," -e Verify against previous .cal\n");
+ fprintf(stderr," -I Create imitation target from .ti3 and null calibration\n");
+ fprintf(stderr," -d Go through the motions but don't write any files\n");
+ fprintf(stderr," -s smoothing Extra curve smoothing (default 1.0)\n");
+ fprintf(stderr," -A manufacturer Set the manufacturer description string\n");
+ fprintf(stderr," -M model Set the model description string\n");
+ fprintf(stderr," -D description Set the profile Description string\n");
+ fprintf(stderr," -C copyright Set the copyright string\n");
+ fprintf(stderr," -x# percent Set initial maximum device %% target (override auto)\n");
+ fprintf(stderr," -m# percent Set initial dev target to %% of auto maximum\n");
+ fprintf(stderr," -n# deltaE Set initial white minimum deltaE target\n");
+ fprintf(stderr," -t# percent Set initial 50%% transfer curve percentage target\n");
+ fprintf(stderr," # = c, r, 0 First channel\n");
+ fprintf(stderr," m, g, 1 Second channel\n");
+ fprintf(stderr," y, b, 2 Third channel\n");
+ fprintf(stderr," k, 3 Fourth channel, etc.\n");
+ fprintf(stderr," -a Create an Adobe Photoshop .AMP file as well as a .cal\n");
+ fprintf(stderr," prevcal Base name of previous .cal file for recal or verify.\n");
+ fprintf(stderr," inoutname Base name of input .ti3 file, output .cal file\n");
+ exit(1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+typedef struct {
+ double loc; /* Location up the curve 0.0 - 1.0 */
+ double val[MAX_CHAN]; /* Value at that location 0.0 - 1.0 */
+} trans_point;
+
+/* Class to hold a print calibration target */
+struct _pcaltarg {
+ inkmask devmask; /* ICX ink mask of device space */
+
+ /* Note that with all of these, a value < 0.0 */
+ /* indicates no value set. */
+ int devmaxset; /* Flag - nz if the devmax is set */
+ double devmax[MAX_CHAN]; /* Device value maximum 0.0 - 1.0 */
+
+ int ademaxset; /* Flag - nz if the ademax is set */
+ double ademax[MAX_CHAN]; /* abs DE maximum for each channel */
+
+ int ademinset; /* Flag - nz if the ademin is set */
+ double ademin[MAX_CHAN]; /* abs DE minimum for each channel */
+
+ int no_tpoints; /* Number of transfer curve points */
+ trans_point *tpoints; /* Array of transfer curve points */
+
+ char err[500]; /* Error message from diagnostics */
+
+ /* Methods */
+ void (*del)(struct _pcaltarg *p);
+
+ /* Save/restore to a CGATS file */
+ int (*write)(struct _pcaltarg *p, cgats *cg, int tab); /* return nz on error */
+ int (*read)(struct _pcaltarg *p, cgats *cg, int tab); /* return nz on error */
+
+ /* Set values in the target */
+ void (*update_devmax)(struct _pcaltarg *p, int chan, double val);
+ void (*update_ademax)(struct _pcaltarg *p, int chan, double val);
+ void (*update_ademin)(struct _pcaltarg *p, int chan, double val);
+ void (*update_tcurve)(struct _pcaltarg *p, int chan, double loc, double val);
+
+ /* Reurn nz if the target has been set */
+ int (*is_set)(struct _pcaltarg *p);
+
+ /* Update settings or from one from another */
+ void (*update)(struct _pcaltarg *p, struct _pcaltarg *s);
+
+}; typedef struct _pcaltarg pcaltarg;
+
+static void pcaltarg_del(pcaltarg *p) {
+ if (p != NULL) {
+ free(p);
+ }
+}
+
+/* Write the cal target to a givent cgats table */
+static int pcaltarg_write(pcaltarg *p, cgats *cg, int tab) {
+ int i, j;
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ char *ident = icx_inkmask2char(p->devmask, 1);
+ char *bident = icx_inkmask2char(p->devmask, 0);
+ int devchan = icx_noofinks(p->devmask);
+ int nsetel = 0;
+ cgats_set_elem *setel; /* Array of set value elements */
+ char buf[100];
+
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+
+ /* Setup output cgats file */
+ cg->add_table(cg, tt_other, 0); /* Add a table for Calibration TarGet values */
+ cg->add_kword(cg, tab, "DESCRIPTOR", "Argyll Calibration Target Definition File",NULL);
+ cg->add_kword(cg, tab, "ORIGINATOR", "Argyll printcal", NULL);
+ cg->add_kword(cg, tab, "CREATED",atm, NULL);
+ cg->add_kword(cg, tab, "COLOR_REP", ident, NULL);
+
+ /* Setup the table, which holds all the model parameters. */
+ /* There is always a parameter per X Y Z or spectral band */
+ cg->add_field(cg, tab, "PARAMTYPE", nqcs_t);
+ nsetel++;
+ sprintf(buf, "%s_I",bident);
+ cg->add_field(cg, tab, buf, r_t);
+ nsetel++;
+ for (i = 0; i < devchan; i++) {
+ inkmask imask = icx_index2ink(p->devmask, i);
+ sprintf(buf, "%s_%s",bident,icx_ink2char(imask));
+ cg->add_field(cg, tab, buf, r_t);
+ nsetel++;
+ }
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL) {
+ free(ident);
+ free(bident);
+ sprintf(p->err,"ctg_write: malloc of setel failed");
+ return 1;
+ }
+
+ /* Write out the values */
+ if (p->devmaxset) {
+ /* This is informational only */
+ setel[0].c = "DEVMAX_USED";
+ setel[1].d = 0.0; /* Not used */
+
+ if (p->devmask & ICX_ADDITIVE) {
+ for (i = 0; i < devchan; i++)
+ setel[2+i].d = 1.0 - p->devmax[i];
+ } else {
+ for (i = 0; i < devchan; i++)
+ setel[2+i].d = p->devmax[i];
+ }
+ cg->add_setarr(cg, tab, setel);
+ }
+ if (p->ademaxset) {
+ setel[0].c = "DELMAX_AIM";
+ setel[1].d = 0.0; /* Not used */
+
+ for (i = 0; i < devchan; i++)
+ setel[2+i].d = p->ademax[i];
+ cg->add_setarr(cg, tab, setel);
+ }
+ if (p->ademinset) {
+ setel[0].c = "DELMIN_AIM";
+ setel[1].d = 0.0; /* Not used */
+
+ for (i = 0; i < devchan; i++)
+ setel[2+i].d = p->ademin[i];
+ cg->add_setarr(cg, tab, setel);
+ }
+ for (j = 0; j < p->no_tpoints; j++) {
+ setel[0].c = "TRANS_PNT";
+ setel[1].d = p->tpoints[j].loc;
+
+ for (i = 0; i < devchan; i++)
+ setel[2+i].d = p->tpoints[j].val[i];
+ cg->add_setarr(cg, tab, setel);
+ }
+ free(setel);
+ free(ident);
+ free(bident);
+
+ return 0;
+}
+
+/* Read the cal target from a given cgats table */
+static int pcaltarg_read(pcaltarg *p, cgats *cg, int tab) {
+ char *bident;
+ int devchan;
+ int i, j, ix;
+ int ti; /* Temporary CGATs index */
+ int spi[2+MAX_CHAN]; /* CGATS indexes for each field */
+ char buf[100];
+
+ if ((ti = cg->find_kword(cg, tab, "COLOR_REP")) < 0) {
+ sprintf(p->err, "ctg_read: Can't fint COLOR_REP");
+ return 1;
+ }
+
+ if ((p->devmask = icx_char2inkmask(cg->t[tab].kdata[ti]) ) == 0) {
+ sprintf(p->err, "ctg_read: unrecognized COLOR_REP '%s'",cg->t[tab].kdata[ti]);
+ return 1;
+ }
+ devchan = icx_noofinks(p->devmask);
+ bident = icx_inkmask2char(p->devmask, 0);
+
+ /* Figure out the indexes of all the fields */
+ if ((spi[0] = cg->find_field(cg, tab, "PARAMTYPE")) < 0) {
+ sprintf(p->err, "ctg_read: Can't find field PARAMTYPE");
+ free(bident);
+ return 1;
+ }
+ sprintf(buf, "%s_I",bident);
+ if ((spi[1] = cg->find_field(cg, tab, buf)) < 0) {
+ sprintf(p->err, "ctg_read: Can't find field %s",buf);
+ free(bident);
+ return 1;
+ }
+ for (i = 0; i < devchan; i++) {
+ inkmask imask = icx_index2ink(p->devmask, i);
+ sprintf(buf, "%s_%s",bident,icx_ink2char(imask));
+ if ((spi[2+i] = cg->find_field(cg, tab, buf)) < 0) {
+ sprintf(p->err, "ctg_read: Can't find field %s",buf);
+ free(bident);
+ return 1;
+ }
+ }
+
+ /* Go through all the entries in the table, putting them in the right place */
+ for (ix = 0; ix < cg->t[tab].nsets; ix++) {
+
+ if (strcmp((char *)cg->t[tab].fdata[ix][spi[0]], "DELMAX_AIM") == 0) {
+ for (i = 0; i < devchan; i++)
+ p->ademax[i] = *((double *)cg->t[tab].fdata[ix][spi[2+i]]);
+ p->ademaxset = 1;
+
+ } else if (strcmp((char *)cg->t[tab].fdata[ix][spi[0]], "DELMIN_AIM") == 0) {
+ for (i = 0; i < devchan; i++)
+ p->ademin[i] = *((double *)cg->t[tab].fdata[ix][spi[2+i]]);
+ p->ademinset = 1;
+
+ } else if (strcmp((char *)cg->t[tab].fdata[ix][spi[0]], "TRANS_PNT") == 0) {
+ if ((p->tpoints = (trans_point *)realloc(p->tpoints, sizeof(trans_point)
+ * (p->no_tpoints+1))) == NULL)
+ error("Realloc of tpoints");
+ p->tpoints[p->no_tpoints].loc = *((double *)cg->t[tab].fdata[ix][spi[1]]);
+ for (i = 0; i < devchan; i++)
+ p->tpoints[p->no_tpoints].val[i] = *((double *)cg->t[tab].fdata[ix][spi[2+i]]);
+ p->no_tpoints++;
+ }
+ }
+ free(bident);
+
+ return 0;
+}
+
+/* Update an individual setting. Use chan < 0 to set all to default */
+void pcaltarg_update_devmax(struct _pcaltarg *p, int chan, double val) {
+ int i;
+ if (p->devmaxset == 0) {
+ for (i = 0; i < MAX_CHAN; i++)
+ p->devmax[i] = -1.0;
+ p->devmaxset = 1;
+ }
+ if (chan >= 0)
+ p->devmax[chan] = val;
+}
+void pcaltarg_update_ademax(struct _pcaltarg *p, int chan, double val) {
+ int i;
+ if (p->ademaxset == 0) {
+ for (i = 0; i < MAX_CHAN; i++)
+ p->ademax[i] = -1.0;
+ p->ademaxset = 1;
+ }
+ if (chan >= 0)
+ p->ademax[chan] = val;
+}
+void pcaltarg_update_ademin(struct _pcaltarg *p, int chan, double val) {
+ int i;
+ if (p->ademinset == 0) {
+ for (i = 0; i < MAX_CHAN; i++)
+ p->ademin[i] = -1.0;
+ p->ademinset = 1;
+ }
+ if (chan >= 0)
+ p->ademin[chan] = val;
+}
+void pcaltarg_update_tcurve(struct _pcaltarg *p, int chan, double loc, double val) {
+ int i, j;
+
+ /* See if a transfer curve point already exists */
+ for (j = 0; j < p->no_tpoints; j++) {
+ if (p->tpoints[j].loc == loc)
+ break;
+ }
+ /* If not, allocate a new one */
+ if (j >= p->no_tpoints) {
+ p->no_tpoints++;
+ if ((p->tpoints = (trans_point *)realloc(p->tpoints, sizeof(trans_point) * p->no_tpoints)) == NULL)
+ error("Realloc of tpoints");
+ p->tpoints[j].loc = loc;
+ for (i = 0; i < MAX_CHAN; i++)
+ p->tpoints[j].val[i] = -1.0;
+ }
+ p->tpoints[j].val[chan] = val;
+
+ if (p->no_tpoints > 0) {
+ /* Sort the transfer points into loc order */
+#define HEAP_COMPARE(A,B) ((A).loc < (B).loc)
+ HEAPSORT(trans_point, p->tpoints, p->no_tpoints);
+#undef HEAP_COMPARE
+ }
+}
+
+/* Reurn nz if the target has been set */
+static int pcaltarg_is_set(pcaltarg *p) {
+ if (p->devmaxset != 0
+ || p->ademaxset != 0
+ || p->ademinset != 0
+ || p->no_tpoints > 0)
+ return 1;
+ return 0;
+}
+
+/* Update one from another */
+static void pcaltarg_update(pcaltarg *p, pcaltarg *s) {
+ int i, j, k;
+
+ if (s->devmaxset) {
+ if (p->devmaxset == 0) {
+ for (i = 0; i < MAX_CHAN; i++)
+ p->devmax[i] = -1.0;
+ p->devmaxset = 1;
+ }
+ for (i = 0; i < MAX_CHAN; i++) {
+ if (s->devmax[i] >= 0.0)
+ p->devmax[i] = s->devmax[i];
+ }
+ }
+
+ if (s->ademaxset) {
+ if (p->ademaxset == 0) {
+ for (i = 0; i < MAX_CHAN; i++)
+ p->ademax[i] = -1.0;
+ p->ademaxset = 1;
+ }
+ for (i = 0; i < MAX_CHAN; i++) {
+ if (s->ademax[i] >= 0.0)
+ p->ademax[i] = s->ademax[i];
+ }
+ }
+
+ if (s->ademinset) {
+ if (p->ademinset == 0) {
+ for (i = 0; i < MAX_CHAN; i++)
+ p->ademin[i] = -1.0;
+ p->ademinset = 1;
+ }
+ for (i = 0; i < MAX_CHAN; i++) {
+ if (s->ademin[i] >= 0.0)
+ p->ademin[i] = s->ademin[i];
+ }
+ }
+
+ /* For each source transfer curve point */
+ for (k = 0; k < s->no_tpoints; k++) {
+
+ /* See if a transfer curve point already exists */
+ for (j = 0; j < p->no_tpoints; j++) {
+ if (p->tpoints[j].loc == s->tpoints[k].loc)
+ break;
+ }
+ /* If not, allocate a new one */
+ if (j >= p->no_tpoints) {
+ p->no_tpoints++;
+ if ((p->tpoints = (trans_point *)realloc(p->tpoints, sizeof(trans_point) * p->no_tpoints)) == NULL)
+ error("Realloc of tpoints");
+ p->tpoints[j].loc = s->tpoints[k].loc;
+ for (i = 0; i < MAX_CHAN; i++)
+ p->tpoints[j].val[i] = -1.0;
+ }
+ for (i = 0; i < MAX_CHAN; i++) {
+ if (s->tpoints[k].val[i] >= 0.0)
+ p->tpoints[j].val[i] = s->tpoints[k].val[i];
+ }
+ }
+ if (s->no_tpoints > 0) {
+ /* Sort the transfer points into loc order */
+#define HEAP_COMPARE(A,B) ((A).loc < (B).loc)
+ HEAPSORT(trans_point, p->tpoints, p->no_tpoints);
+#undef HEAP_COMPARE
+ }
+}
+
+/* Create a new, empty pcaltarget */
+/* Return NULL on error */
+pcaltarg *new_pcaltarg() {
+ pcaltarg *p;
+
+ if ((p = (pcaltarg *)calloc(1, sizeof(pcaltarg))) == NULL) {
+ return NULL;
+ }
+
+ /* Set method pointers */
+ p->del = pcaltarg_del;
+ p->write = pcaltarg_write;
+ p->read = pcaltarg_read;
+ p->update_devmax = pcaltarg_update_devmax;
+ p->update_ademax = pcaltarg_update_ademax;
+ p->update_ademin = pcaltarg_update_ademin;
+ p->update_tcurve = pcaltarg_update_tcurve;
+ p->is_set = pcaltarg_is_set;
+ p->update = pcaltarg_update;
+
+ return p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* A wedge sample value */
+typedef struct {
+ double inv; /* Input value (cal table) */
+ double dev; /* Device value */
+ double XYZ[3]; /* XYZ value */
+ double Lab[3]; /* Lab value */
+ double del; /* Absolute delta (to white) */
+} wval;
+
+#define MAX_INVSOLN 10 /* Rspl maximum reverse solutions */
+
+/* rspl setting functions */
+static void rsplset1(void *cbntx, double *out, double *in) {
+ co *dpoints = (co *)cbntx;
+ int ix;
+
+ ix = *((int*)&in[-0-1]); /* Get grid index being looked up */
+ out[0] = dpoints[ix].v[0];
+}
+
+/* Do an inverse lookup of an rspl. Return -1.0 on error. */
+/* dir is value to favour if there are multiple solutions. */
+static double rspl_ilookup(rspl *r, double dir, double in) {
+ int nsoln; /* Number of solutions found */
+ co pp[MAX_INVSOLN]; /* Room for all the solutions found */
+ int k; /* Chosen solution */
+
+ pp[0].v[0] = in;
+
+ nsoln = r->rev_interp (
+ r, /* this */
+ RSPL_NEARCLIP, /* Clip to nearest (faster than vector) */
+ MAX_INVSOLN, /* Maximum number of solutions allowed for */
+ NULL, /* No auxiliary input targets */
+ NULL, /* Clip vector direction and length */
+ pp); /* Input and output values */
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln == 1) { /* Exactly one solution */
+ k = 0;
+ } else if (nsoln == 0) { /* Zero solutions. This is unexpected. */
+ return -1.0;
+ } else { /* Multiple solutions */
+ double bdist = 1e300;
+ int bsoln = 0;
+// warning("Multiple solutions for curve %d for DE %f",j,pp[0].v[0]);
+ for (k = 0; k < nsoln; k++) {
+ double tt;
+ tt = pp[k].p[0] - dir;
+ tt *= tt;
+ if (tt < bdist) { /* Better solution */
+ bdist = tt;
+ bsoln = k;
+ }
+ }
+ k = bsoln;
+ }
+ return pp[k].p[0];
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa,mfa; /* current argument we're looking at */
+ int verb = 0;
+ int doplot = 0;
+ int initial = 0; /* Do initial creation of cal target and calibration */
+ int recal = 0; /* Do recalibrate/use cal target. */
+ int verify = 0; /* Do verification */
+ int imitate = 0; /* Do target directly from input */
+ int dowrite = 1; /* Write to files */
+ int doamp = 0; /* Write Adobe Photoshop .AMP file */
+ profxinf xpi; /* Extra profile/calibration information */
+ pcaltarg *upct = NULL; /* User settings of print calibration target */
+ pcaltarg *pct = NULL; /* Settings of print calibration target */
+ double smooth = RSPLSMOOTH; /* RSPL Smoothness factor */
+ double xsmooth = 1.0; /* Smoothing multiplier */
+ double ver_maxde = 2.0; /* Verify maximum Delta E (1.0 for smooth == 1.0) */
+ int spec = 0; /* Use spectral data flag */
+ icxIllumeType illum = icxIT_D50; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxObserverType observ = icxOT_CIE_1931_2; /* The classic observer */
+
+ char baname[MAXNAMEL+1] = ""; /* Input & Output base name */
+ char inname[MAXNAMEL+1] = ""; /* new .ti3 input file name */
+ char calname[MAXNAMEL+1] = ""; /* previous .cal input file name */
+ char outname[MAXNAMEL+1] = ""; /* new .cal output file name */
+ char ampname[MAXNAMEL+1] = ""; /* new .amp output file name */
+ double maxscale[MAX_CHAN]; /* Scale auto device maximum to % */
+ cgats *icg = NULL; /* .ti3 input cgats structure */
+ int ti; /* Temporary CGATs index */
+ inkmask devmask; /* ICX ink mask of device space */
+ int devchan; /* Number of chanels in device space */
+ int isLab = 0; /* Flag indicating whether PCS is XYZ or Lab */
+ int n_pvals[MAX_CHAN]; /* Number of measurement values */
+ wval *pvals[MAX_CHAN]; /* Patch measurement values */
+ wval white; /* Average white value */
+ int n_white = 0; /* Number of values to average */
+ icmXYZNumber wht; /* White value */
+ rspl *raw[MAX_CHAN]; /* Raw Lab values fitted to rspl */
+ rspl *ade[MAX_CHAN]; /* Absolute delta E */
+ rspl *rde[MAX_CHAN]; /* Relative delta E */
+ rspl *pcade[MAX_CHAN]; /* Previous calibrated absolute delta E */
+ double mxade[MAX_CHAN]; /* Maximum ade value */
+ double idpow[MAX_CHAN] = { -1.0 }; /* Ideal power-like of targen values */
+ int n_cvals; /* Number of calibration curve values */
+ wval *cvals[MAX_CHAN]; /* Calibration curve tables */
+ rspl *tcurves[MAX_CHAN]; /* Tweak target curves */
+
+ int i, j;
+
+ /* Init pointers to NULL */
+ for (j = 0; j < MAX_CHAN; j++) {
+ maxscale[j] = -1.0;
+ pvals[j] = NULL;
+ raw[j] = NULL;
+ ade[j] = NULL;
+ rde[j] = NULL;
+ pcade[j] = NULL;
+ cvals[j] = NULL;
+ tcurves[j] = NULL;
+ }
+
+ error_program = argv[0];
+ memset((void *)&xpi, 0, sizeof(profxinf)); /* Init extra profile info to defaults */
+ if ((upct = new_pcaltarg()) == NULL || (pct = new_pcaltarg()) == NULL)
+ error("new_caltarg failed");
+
+ if (argc < 3)
+ usage("Too few arguments, got %d expect at least %d",argc-1,2);
+
+#ifdef NEVER
+ {
+ double src, dst, pp;
+
+ src = 0.5;
+ dst = 0.25;
+ pp = icx_powlike_needed(src, dst);
+ printf("%f -> %f needs %f, check %f\n",src,dst,pp,icx_powlike(src,pp));
+
+ src = 0.25;
+ dst = 0.5;
+ pp = icx_powlike_needed(src, dst);
+ printf("%f -> %f needs %f, check %f\n",src,dst,pp,icx_powlike(src,pp));
+
+ src = 0.5;
+ dst = 0.707106;
+ pp = icx_powlike_needed(src, dst);
+ printf("%f -> %f needs %f, check %f\n",src,dst,pp,icx_powlike(src,pp));
+
+ src = 0.5;
+ dst = 0.5;
+ pp = icx_powlike_needed(src, dst);
+ printf("%f -> %f needs %f, check %f\n",src,dst,pp,icx_powlike(src,pp));
+ }
+#endif // NEVER
+
+ /* Process the arguments */
+ mfa = 2; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ else if (argv[fa][1] == 'v') {
+ if (na != NULL) {
+ fa = nfa;
+ verb = atoi(na);
+ } else
+ verb = 1;
+ }
+
+ else if (argv[fa][1] == 'p') {
+ if (na != NULL) {
+ fa = nfa;
+ doplot = atoi(na);
+ } else
+ doplot = 1; /* Plot various graphs */
+ }
+
+ else if (argv[fa][1] == 'i') {
+ initial = 1; /* Initial calibration */
+ recal = 0;
+ verify = 0;
+ imitate = 0;
+ }
+
+ else if (argv[fa][1] == 'r') {
+ initial = 0;
+ recal = 1; /* Recalibrate */
+ verify = 0;
+ imitate = 0;
+ }
+
+ else if (argv[fa][1] == 'e') {
+ initial = 0;
+ recal = 0;
+ verify = 1; /* Verify */
+ imitate = 0;
+ }
+
+ else if (argv[fa][1] == 'I') {
+ initial = 0;
+ recal = 0;
+ verify = 0;
+ imitate = 1; /* Imitation target */
+ }
+
+ else if (argv[fa][1] == 'd')
+ dowrite = 0; /* Don't write to files */
+
+ else if (argv[fa][1] == 'a')
+ doamp = 1; /* write AMP file */
+
+ /* Smoothing modfider */
+ else if (argv[fa][1] == 's') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to smoothing flag -s");
+ xsmooth = atof(na);
+ }
+
+ /* Manufacturer description string */
+ else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to manufacturer description flag -A");
+ xpi.deviceMfgDesc = na;
+ }
+
+ /* Model description string */
+ else if (argv[fa][1] == 'M') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to model description flag -M");
+ xpi.modelDesc = na;
+ }
+
+ /* Profile Description */
+ else if (argv[fa][1] == 'D') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to profile description flag -D");
+ xpi.profDesc = na;
+ }
+
+ /* Copyright string */
+ else if (argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to copyright flag -C");
+ xpi.copyright = na;
+ }
+
+ /* Per channel target modifiers */
+ else if (argv[fa][1] == 'x'
+ || argv[fa][1] == 'm'
+ || argv[fa][1] == 'n'
+ || argv[fa][1] == 't') {
+ char fch = argv[fa][1];
+ int chan = -1;
+ double val = -1.0;
+ fa = nfa;
+ if (na == NULL)
+ usage("Expect channel flag after flag -%c",argv[fa][1]);
+ switch (na[0]) {
+ case 'c': case 'r': case '0':
+ chan = 0;
+ break;
+ case 'm': case 'g': case '1':
+ chan = 1;
+ break;
+ case 'y': case 'b': case '2':
+ chan = 2;
+ break;
+ case 'k': case '3':
+ chan = 3;
+ break;
+ case '4':
+ chan = 4;
+ break;
+ case '5':
+ chan = 5;
+ break;
+ case '6':
+ chan = 6;
+ break;
+ case '7':
+ chan = 7;
+ break;
+ case '8':
+ chan = 8;
+ break;
+ case '9':
+ chan = 9;
+ break;
+ case 'A':
+ chan = 10;
+ break;
+ case 'B':
+ chan = 11;
+ break;
+ case 'C':
+ chan = 12;
+ break;
+ case 'D':
+ chan = 13;
+ break;
+ case 'E':
+ chan = 14;
+ break;
+ case 'F':
+ chan = 15;
+ break;
+ default:
+ usage("Unknown channel flag '%s' after flag -%c",argv[fa][2],argv[fa][1]);
+ }
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Expect argument after flag -%c%c",fch,na[0]);
+ val = atof(argv[fa]);
+
+ if (fch == 'x') {
+ if (val < 0.0 || val > 100.0)
+ usage("Argument to -%c%c %f from '%s' is out of range",fch,na[0],val,argv[fa]);
+ val /= 100.0;
+ upct->update_devmax(upct, chan, val);
+
+ } else if (fch == 'm') {
+ if (val < 0.0 || val > 100.0)
+ usage("Argument to -%c%c %f from '%s' is out of range",fch,na[0],val,argv[fa]);
+ val /= 100.0;
+ maxscale[chan] = val;
+
+ } else if (fch == 'n') {
+ upct->update_ademin(upct, chan, val);
+
+ } else if (fch == 't') {
+ if (val < 0.0 || val > 100.0)
+ usage("Argument to -%c%c %f from '%s' is out of range",fch,na[0],val,argv[fa]);
+ val /= 100.0;
+ upct->update_tcurve(upct, chan, 0.5, val);
+ }
+ }
+ else
+ usage("Unknown flag '%c'",argv[fa][1]);
+ } else
+ break;
+ }
+
+ smooth *= xsmooth;
+
+ if (!( (initial && !recal && !verify && !imitate)
+ || (!initial && recal && !verify && !imitate)
+ || (!initial && !recal && verify && !imitate)
+ || (!initial && !recal && !verify && imitate)))
+ error("One of -i, -r -e or -I must be set");
+
+ /* Get the file name arguments */
+ if (verify || recal) {
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing prevoius .cal basename");
+ strncpy(calname,argv[fa++],MAXNAMEL-4); calname[MAXNAMEL-4] = '\000';
+ strcat(calname,".cal");
+ }
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing .ti3 and new .cal basename");
+ strncpy(baname,argv[fa++],MAXNAMEL-4); baname[MAXNAMEL-4] = '\000';
+ strcpy(inname,baname); /* new .ti3 file */
+ strcat(inname,".ti3");
+ strcpy(outname,baname); /* New .cal file */
+ strcat(outname,".cal");
+ strcpy(ampname,baname); /* New .amp file */
+ strcat(ampname,".amp");
+
+ if (fa < argc) usage("Too many arguments ('%s')",argv[fa]);
+
+ /* Open and look at the .ti3 profile patches file */
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI3"); /* our special input type is Calibration Target Information 3 */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI3 format file");
+ if (icg->ntables < 1)
+ error ("Input file doesn't contain at least one table");
+
+ /* See if CIE is actually available - some sources of .TI3 don't provide it */
+ if (!spec
+ && icg->find_field(icg, 0, "LAB_L") < 0
+ && icg->find_field(icg, 0, "XYZ_X") < 0) {
+
+ if (icg->find_kword(icg, 0, "SPECTRAL_BANDS") < 0)
+ error ("Neither CIE nor spectral data found in file '%s'",inname);
+
+ /* Switch to using spectral information */
+ if (verb)
+ printf("No CIE data found, switching to spectral with standard observer & D50\n");
+ spec = 1;
+ illum = icxIT_D50;
+ observ = icxOT_CIE_1931_2;
+ }
+
+ /* If we requested spectral, check that it is available */
+ if (spec) {
+ if (icg->find_kword(icg, 0, "SPECTRAL_BANDS") < 0)
+ error ("Requested spectral interpretation when data not available");
+ }
+
+ /* Get colorspace information from input CGATS file */
+ {
+ char *buf;
+ char *inc, *outc;
+
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error("Input file doesn't contain keyword COLOR_REPS");
+
+ if ((buf = strdup(icg->t[0].kdata[ti])) == NULL)
+ error("Malloc failed - color rep");
+
+ /* Split COLOR_REP into device and PCS space */
+ inc = buf;
+ if ((outc = strchr(buf, '_')) == NULL)
+ error("COLOR_REP '%s' invalid", icg->t[0].kdata[ti]);
+ *outc++ = '\000';
+
+ if (strcmp(outc, "XYZ") == 0)
+ isLab = 0;
+ else if (strcmp(outc, "LAB") == 0)
+ isLab = 1;
+ else
+ error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", icg->t[0].kdata[ti]);
+
+ devmask = icx_char2inkmask(inc);
+ devchan = icx_noofinks(devmask);
+
+ if (devchan == 0)
+ error("COLOR_REP '%s' invalid (No matching devmask)", icg->t[0].kdata[ti]);
+
+ if ((devmask & ICX_ADDITIVE) && !(devmask & ICX_INVERTED))
+ warning("COLOR_REP '%s' is probably not suitable for print calibration!", icg->t[0].kdata[ti]);
+
+ free(buf);
+ }
+
+ if (verify || recal || imitate) {
+ if (upct->is_set(upct)) {
+ warning("Command line calibration target paramers ignored on re-calibrate, verify and imitate!");
+ }
+ }
+
+ /* For recalibrate or verify, load the previous calibration file */
+ if (verify || recal) {
+ cgats *tcg; /* Previous .cal file */
+
+ tcg = new_cgats(); /* Create a CGATS structure */
+ tcg->add_other(tcg, "CAL"); /* our special input type is Calibration Target */
+
+ if (tcg->read_name(tcg, calname))
+ error("No cal target '%s' found for re-calibrate (%s)\n",calname,tcg->err);
+
+ /* Check that this is an output cal file */
+ if ((ti = tcg->find_kword(tcg, 0, "DEVICE_CLASS")) < 0)
+ error ("Calibration file '%s'doesn't contain keyword DEVICE_CLASS",calname);
+ if (strcmp(tcg->t[0].kdata[ti],"OUTPUT") != 0)
+ error ("Calibration file '%s' doesn't has DEVICE_CLASS that is not OUTPUT",calname);
+
+ if (pct->read(pct, tcg, 1) != 0)
+ error("Reading cal target '%s' failed",calname);
+
+ if (pct->devmask != devmask)
+ error("Target '%s' colorspace '%s' doesn't match '%s' colorspace '%s'",
+ calname,icx_inkmask2char(pct->devmask, 1),inname,icx_inkmask2char(devmask, 1));
+
+ /* Load the previous expected absolute DE response */
+ /* It will be in the third table with other type "CAL" */
+ if (tcg->ntables >= 3 && tcg->t[2].tt == tt_other && tcg->t[0].oi == 0) {
+ int ti;
+ char *bident;
+ int spi[1+MAX_CHAN]; /* CGATS indexes for each field */
+ char buf[100];
+
+ bident = icx_inkmask2char(pct->devmask, 0);
+
+ if (tcg->t[2].nsets <= 0)
+ error ("No Calibration Expected DE Response in '%s'",calname);
+
+ /* Figure out the indexes of all the fields */
+ sprintf(buf, "%s_I_DE",bident);
+ if ((spi[0] = tcg->find_field(tcg, 2, buf)) < 0)
+ error("Can't find field %s in '%s'",buf,calname);
+
+ for (i = 0; i < devchan; i++) {
+ inkmask imask = icx_index2ink(pct->devmask, i);
+ sprintf(buf, "%s_%s_DE",bident,icx_ink2char(imask));
+ if ((spi[1+i] = tcg->find_field(tcg, 2, buf)) < 0)
+ error("Can't find field %s in '%s'",buf,calname);
+ }
+
+ /* Read in each channels values and put them in a rspl */
+ for (j = 0; j < devchan; j++) {
+ datai low,high;
+ int gres[MXDI];
+ co *dpoints;
+
+ low[0] = 0.0;
+ high[0] = 1.0;
+ gres[0] = tcg->t[2].nsets;
+
+ if ((pcade[j] = new_rspl(RSPL_NOFLAGS,1, 1)) == NULL)
+ error("new_rspl() failed");
+
+ if ((dpoints = malloc(sizeof(co) * gres[0])) == NULL)
+ error("malloc dpoints[%d] failed",gres[0]);
+
+ /* Copy the points to our array */
+ if (devmask & ICX_ADDITIVE) {
+ for (i = 0; i < gres[0]; i++) {
+ dpoints[i].p[0] = 1.0 - i/(double)(gres[0]-1);
+ dpoints[i].v[0] = *((double *)tcg->t[2].fdata[gres[0]-1-i][spi[1+j]]);
+ }
+ } else {
+ for (i = 0; i < gres[0]; i++) {
+ dpoints[i].p[0] = i/(double)(gres[0]-1);
+ dpoints[i].v[0] = *((double *)tcg->t[2].fdata[i][spi[1+j]]);
+ }
+ }
+
+ pcade[j]->set_rspl(pcade[j],
+ 0,
+ (void *)dpoints, /* Read points */
+ rsplset1, /* Setting function */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL /* Default data scale */
+ );
+ free(dpoints);
+ }
+ free(bident);
+ }
+ tcg->del(tcg);
+
+ } else { /* Must be an initial or Imitation calibration */
+
+ pct->devmask = devmask;
+
+ /* Set the cal target from any user supplied parameters */
+ pct->update(pct, upct);
+
+ /* No previous absolute de reference */
+ for (j = 0; j < devchan; j++)
+ pcade[j] = NULL;
+ }
+
+ /* Common processing: */
+
+ /* Read in the patch data */
+ {
+ char buf[100];
+ char *pcsfname[2][3] = { { "XYZ_X", "XYZ_Y", "XYZ_Z" },
+ { "LAB_L", "LAB_A", "LAB_B" } };
+ int dvi[MAX_CHAN]; /* CGATS indexes for each device field */
+ int pcsix[3]; /* XYZ/Lab chanel indexes */
+ xsp2cie *sp2cie = NULL; /* Spectral conversion object */
+ xspect sp;
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ char *bident = icx_inkmask2char(devmask, 0);
+
+ /* Figure out the indexes of all the device fields */
+ for (j = 0; j < devchan; j++) {
+ inkmask imask = icx_index2ink(devmask, j);
+ sprintf(buf, "%s_%s",bident,icx_ink2char(imask));
+ if ((dvi[j] = icg->find_field(icg, 0, buf)) < 0)
+ error("Can't find field %s in '%s'",buf,inname);
+#ifdef DEBUG
+ printf("devn chan %d field %s = %d\n",j,buf,dvi[j]);
+#endif
+ }
+ free(bident);
+
+ if (spec) {
+ int ii;
+ char buf[100];
+
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ sp.spec_n = atoi(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ sp.spec_wl_short = atof(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ sp.spec_wl_long = atof(icg->t[0].kdata[ii]);
+ sp.norm = 100.0;
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = icg->find_field(icg, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",buf);
+ }
+
+ /* Create a spectral conversion object to XYZ */
+ if ((sp2cie = new_xsp2cie(illum, &cust_illum, observ, NULL, icSigXYZData, icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+
+ /* To add FWA comp. would have to locate/create spectral white here, */
+ /* then set the FWA comp. on. */
+ /* See profout.c */
+
+ } else {
+ /* Figure out the indexes of the PCS fields */
+ for (j = 0; j < 3; j++) {
+ if ((i = icg->find_field(icg, 0, pcsfname[isLab][j])) >= 0) {
+ if (icg->t[0].ftype[i] != r_t)
+ error ("Field %s is wrong type",pcsfname[isLab][j]);
+ pcsix[j] = i;
+#ifdef DEBUG
+ printf("PCS chan %d field %s = %d\n",j,pcsfname[isLab][j],pcsix[j]);
+#endif
+ } else {
+ error ("Failed to find field %s",pcsfname[isLab][j]);
+ }
+ }
+ }
+
+ n_cvals = 0;
+ for (j = 0; j < devchan; j++) {
+ pvals[j] = NULL;
+ n_pvals[j] = 0;
+ cvals[j] = NULL;
+ }
+
+ /* Read all the test patches in */
+ for (i = 0; i < icg->t[0].nsets; i++) {
+ double maxv = -1.0;
+ int maxch;
+
+#ifdef DEBUG
+ printf("Reading patch %d\n",i);
+#endif
+
+ /* Locate the maximum device value of any channel */
+ for (j = 0; j < devchan; j++) {
+ double val = *((double *)icg->t[0].fdata[i][dvi[j]]) / 100.0;
+ if (devmask & ICX_ADDITIVE)
+ val = 1.0 - val;
+ if (val > maxv) {
+ maxv = val;
+ maxch = j;
+ }
+ }
+#ifdef DEBUG
+ printf("max %f at chan %d\n",maxv,maxch);
+#endif
+ /* Treat white specially, and take it out of the list */
+ if (maxv < 1e-6) {
+ double wxyz[3];
+ if (n_white == 0) {
+ white.dev = 0.0;
+ for (j = 0; j < 3; j++)
+ white.XYZ[j] = 0.0;
+ }
+ if (spec) {
+ /* Read and convert the spectral value */
+ for (j = 0; j < sp.spec_n; j++)
+ sp.spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+
+ sp2cie->convert(sp2cie, wxyz, &sp);
+
+ } else {
+ /* Read the CIE value */
+ for (j = 0; j < 3; j++)
+ wxyz[j] = *((double *)icg->t[0].fdata[i][pcsix[j]]);
+
+ /* And convert to XYZ 0..1 */
+ if (isLab) {
+ icmLab2XYZ(&icmD50, wxyz, wxyz);
+ } else {
+ for (j = 0; j < 3; j++)
+ wxyz[j] /= 100.0;
+ }
+ }
+
+ white.dev += maxv;
+ for (j = 0; j < 3; j++)
+ white.XYZ[j] += wxyz[j];
+ n_white++;
+#ifdef DEBUG
+ printf(" white: dev %f,XYZ %f %f %f\n",
+ white.dev,white.XYZ[0]/n_white, white.XYZ[1]/n_white, white.XYZ[2]/n_white);
+#endif
+ } else {
+ wval *vp;
+ /* Check that all the non-max value channels are zero */
+ for (j = 0; j < devchan; j++) {
+ double val = *((double *)icg->t[0].fdata[i][dvi[j]]) / 100.0;
+ if (devmask & ICX_ADDITIVE)
+ val = 1.0 - val;
+ if (j == maxch)
+ continue;
+ if (val > 0.001)
+ break;
+ }
+ if (j < devchan) {
+#ifdef DEBUG
+ printf("Skipping patch\n");
+#endif
+ continue; /* Ignore this patch */
+ }
+
+ if ((pvals[maxch] = (wval *)realloc(pvals[maxch],
+ sizeof(wval) * (n_pvals[maxch]+1))) == NULL)
+ error("Realloc of pvals failed");
+ vp = &pvals[maxch][n_pvals[maxch]];
+ vp->dev = maxv;
+
+ if (spec) {
+ /* Read and convert the spectral value */
+ for (j = 0; j < sp.spec_n; j++)
+ sp.spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+
+ sp2cie->convert(sp2cie, vp->XYZ, &sp);
+
+ } else {
+ /* Read the CIE value */
+ for (j = 0; j < 3; j++)
+ vp->XYZ[j] = *((double *)icg->t[0].fdata[i][pcsix[j]]);
+
+ /* And convert to XYZ 0..1 */
+ if (isLab) {
+ icmLab2XYZ(&icmD50, vp->XYZ, vp->XYZ);
+ } else {
+ for (j = 0; j < 3; j++)
+ vp->XYZ[j] /= 100.0;
+ }
+ }
+ /* Temporary D50 Lab */
+ icmXYZ2Lab(&icmD50, vp->Lab, vp->XYZ);
+#ifdef DEBUG
+ printf(" patch %d: dev %f,XYZ %f %f %f, D50 Lab %f %f %f\n",
+ n_pvals[maxch], vp->dev,vp->XYZ[0], vp->XYZ[1], vp->XYZ[2],
+ vp->Lab[0], vp->Lab[1], vp->Lab[2]);
+#endif
+ n_pvals[maxch]++;
+ }
+ }
+
+ /* Average the white */
+ if (n_white == 0)
+ error("Can't find even one white patch in '%s'",inname);
+#ifdef DEBUG
+ printf("% white patches\n",n_white);
+#endif
+ for (j = 0; j < 3; j++) {
+ white.dev /= (double)n_white;
+ white.XYZ[j] /= (double)n_white;
+ }
+ icmAry2XYZ(wht, white.XYZ);
+ icmXYZ2Lab(&icmD50, white.Lab, white.XYZ);
+
+ /* Convert the Lab white reference to absolute */
+ wht.X /= wht.Y;
+ wht.Z /= wht.Y;
+ wht.Y /= wht.Y;
+
+ if (verb) {
+ icmXYZ2Lab(&icmD50, white.Lab, white.XYZ);
+ printf("Average white = XYZ %f %f %f, D50 Lab %f %f %f\n",
+ white.XYZ[0], white.XYZ[1], white.XYZ[2], white.Lab[0], white.Lab[1], white.Lab[2]);
+ }
+
+ for (j = 0; j < devchan; j++) {
+ wval *wp;
+
+ /* Add averaged white back into each channel */
+ if ((pvals[j] = (wval *)realloc(pvals[j],
+ sizeof(wval) * (n_pvals[j]+1))) == NULL)
+ error("Realloc (%d) of pvals failed",n_pvals[j]+1);
+ wp = &pvals[j][n_pvals[j]];
+ wp->dev = white.dev;
+ wp->XYZ[0] = white.XYZ[0];
+ wp->XYZ[1] = white.XYZ[1];
+ wp->XYZ[2] = white.XYZ[2];
+ n_pvals[j]++;
+
+ /* Convert all the XYZ values to Lab paper relative */
+ for (i = 0; i < n_pvals[j]; i++) {
+ wp = &pvals[j][i];
+ icmXYZ2Lab(&wht, wp->Lab, wp->XYZ);
+ }
+
+ /* Sort the channel acording to device value */
+ /* For a consistent result for identical device values, */
+ /* secondary sort by inverse CIE value */
+//#define HEAP_COMPARE(A,B) ((A).dev < (B).dev)
+#define HEAP_COMPARE(A,B) ((A).dev != (B).dev ? ((A).dev < (B).dev) : ((A).Lab[0] > (B).Lab[0]))
+ HEAPSORT(wval, pvals[j], n_pvals[j]);
+#undef HEAP_COMPARE
+
+ /* Check the maximum value looks OK */
+ if (n_pvals[j] < 5)
+ warning("Channel %d has only %d test patches",n_pvals[j]);
+ if (pvals[j][n_pvals[j]-1].dev < 0.99)
+ warning("Channel %d has max test patch value of %f",pvals[j][n_pvals[j]-1]);
+
+ if (verb > 1) {
+ printf("Chan %d has %d raw values:\n",j,n_pvals[j]);
+ for (i = 0; i < n_pvals[j]; i++) {
+ wp = &pvals[j][i];
+ printf(" %d: dev %f,XYZ %f %f %f, Lab %f %f %f\n",
+ i,wp->dev,wp->XYZ[0], wp->XYZ[1], wp->XYZ[2],
+ wp->Lab[0], wp->Lab[1], wp->Lab[2]);
+ }
+ }
+ }
+
+ if (sp2cie != NULL)
+ sp2cie->del(sp2cie);
+ }
+ icg->del(icg); /* Clean up */
+
+ /* Interpolate Lab using rspl */
+ for (j = 0; j < devchan; j++) {
+ datai low,high;
+ datao olow,ohigh;
+ int gres[MXDI];
+ double avgdev[MXDO];
+ cow *dpoints;
+
+ low[0] = 0.0;
+ high[0] = 1.0;
+ gres[0] = GRES;
+ olow[0] = 0.0;
+ ohigh[0] = 100.0;
+ olow[1] = olow[2] = -128.0;
+ ohigh[1] = ohigh[2] = 128.0;
+ avgdev[0] = 0.0025;
+ avgdev[1] = 0.005;
+ avgdev[2] = 0.005;
+
+ if ((raw[j] = new_rspl(RSPL_NOFLAGS,1, 3)) == NULL)
+ error("new_rspl() failed");
+
+ if ((dpoints = (cow *)malloc(sizeof(cow) * n_pvals[j])) == NULL)
+ error("malloc dpoints[%d] failed",n_pvals[j]);
+
+ for (i = 0; i < n_pvals[j]; i++) {
+ dpoints[i].p[0] = pvals[j][i].dev;
+ dpoints[i].v[0] = pvals[j][i].Lab[0];
+ dpoints[i].v[1] = pvals[j][i].Lab[1];
+ dpoints[i].v[2] = pvals[j][i].Lab[2];
+ if (i == 0)
+ dpoints[i].w = (double)n_white;
+ else
+ dpoints[i].w = 1.0;
+ }
+
+ raw[j]->fit_rspl_w(raw[j],
+ RSPLFLAGS,
+ dpoints, /* Test points */
+ n_pvals[j], /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ olow, ohigh, /* Default data scale */
+ smooth, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+
+
+ if (verb > 1) {
+ }
+
+ free(dpoints);
+ }
+
+ /* Plot the raw curves */
+ if (doplot > 1) {
+ double xx[PRES];
+ double yy[3][PRES];
+
+ for (j = 0; j < devchan; j++) {
+ printf("Chan %d raw L*a*b*:\n",j);
+ for (i = 0; i < PRES; i++) {
+ co tp; /* Test point */
+ xx[i] = i/(double)(PRES-1);
+ tp.p[0] = xx[i];
+ raw[j]->interp(raw[j], &tp);
+ yy[0][i] = tp.v[0];
+ yy[1][i] = tp.v[1];
+ yy[2][i] = tp.v[2];
+ }
+ do_plot(xx, yy[0], yy[1], yy[2], PRES);
+ }
+ }
+
+ /* Create a RSPL of absolute deltaE and relative deltaE '94 */
+ for (j = 0; j < devchan; j++) {
+ datai low,high;
+ int gres[MXDI];
+ double avgdev[MXDO];
+ co *dpoints_a;
+ co *dpoints_r;
+ double wh[3], prev[3], tot;
+
+ low[0] = 0.0;
+ high[0] = 1.0;
+ gres[0] = GRES;
+ avgdev[0] = 0.0;
+
+ if ((ade[j] = new_rspl(RSPL_NOFLAGS,1, 1)) == NULL)
+ error("new_rspl() failed");
+ if (imitate) {
+ if ((pcade[j] = new_rspl(RSPL_NOFLAGS,1, 1)) == NULL)
+ error("new_rspl() failed");
+ }
+ if ((rde[j] = new_rspl(RSPL_NOFLAGS,1, 1)) == NULL)
+ error("new_rspl() failed");
+
+ if ((dpoints_a = malloc(sizeof(co) * GRES)) == NULL)
+ error("malloc dpoints[%d] failed",GRES);
+ if ((dpoints_r = malloc(sizeof(co) * GRES)) == NULL)
+ error("malloc dpoints[%d] failed",GRES);
+
+//printf("~1 Chan %d:\n",j);
+ for (i = 0; i < GRES; i++) {
+ co tp; /* Test point */
+
+ tp.p[0] = i/(double)(GRES-1);
+ raw[j]->interp(raw[j], &tp);
+
+ dpoints_a[i].p[0] = tp.p[0];
+ dpoints_r[i].p[0] = tp.p[0];
+ if (i == 0) {
+//printf("~1 wht = %f %f %f\n",tp.v[0],tp.v[1],tp.v[2]);
+ tot = 0.0;
+ prev[0] = wh[0] = tp.v[0];
+ prev[1] = wh[1] = tp.v[1];
+ prev[2] = wh[2] = tp.v[2];
+ dpoints_a[i].v[0] = 0.0;
+ dpoints_r[i].v[0] = 0.0;
+ } else {
+//printf("~1 samp %d = %f %f %f\n",i,tp.v[0],tp.v[1],tp.v[2]);
+ /* Use Euclidean for large DE: (CIE94 stuffs up here) */
+ dpoints_a[i].v[0] = icmLabDE(tp.v, wh);
+ /* And CIE94 for small: */
+ tot += icmCIE94(tp.v, prev);
+ prev[0] = tp.v[0];
+ prev[1] = tp.v[1];
+ prev[2] = tp.v[2];
+ dpoints_r[i].v[0] = tot;
+ }
+//printf("~1 %d: dev %f, ade %f, rde %f\n",i,tp.p[0],dpoints_a[i].v[0],dpoints_r[i].v[0]);
+ }
+
+ ade[j]->set_rspl(ade[j],
+ 0,
+ (void *)dpoints_a, /* Test points */
+ rsplset1, /* Setting function */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL /* Default data scale */
+ );
+ if (imitate) {
+ pcade[j]->set_rspl(pcade[j],
+ 0,
+ (void *)dpoints_a, /* Test points */
+ rsplset1, /* Setting function */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL /* Default data scale */
+ );
+ }
+ rde[j]->set_rspl(rde[j],
+ 0,
+ (void *)dpoints_r, /* Test points */
+ rsplset1, /* Setting function */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL /* Default data scale */
+ );
+ free(dpoints_a);
+ free(dpoints_r);
+ }
+
+ if (initial) {
+ /* Establish the ademax values */
+ pct->update_devmax(pct, -1, -1.0); /* Make sure there is a value for each */
+ pct->update_ademax(pct, -1, -1.0);
+ pct->update_ademin(pct, -1, -1.0);
+ for (j = 0; j < devchan; j++) {
+ co tp; /* Test point */
+
+ if (pct->devmax[j] < 0.0) { /* Auto */
+ double maxd, maxde, maxix;
+ /* Locate the point of maximum aDE */
+ for (maxde = -1.0, i = 0; i < GRES; i++) {
+
+ tp.p[0] = i/(GRES-1.0);
+ ade[j]->interp(ade[j], &tp);
+ if (tp.v[0] > maxde) {
+ maxd = tp.p[0];
+ maxde = tp.v[0];
+ maxix = i;
+ }
+ }
+ pct->devmax[j] = maxd;
+ pct->ademax[j] = maxde; /* Temporary */
+//printf("Chan %d, dev %f, max de = %f\n", j, maxd, maxde);
+
+ if (maxd < 0.2) {
+ warning("Chan %d, max DE point %f is below < 0.2 - ignored\n", j, maxd);
+ maxix = GRES-1;
+ }
+ /* Then locate the point below that where the slope */
+ /* becomes reasonable. */
+ for (i = maxix; i >= 40; i--) {
+ double aslope, minslope = 1e6;
+ double naslope, nminslope;
+ int k;
+
+ /* Compute the minimum over a span of 20/GRES */
+ for (k = 0; k < 40; k++) {
+ double dp, dv, slope;
+
+ tp.p[0] = (i-k)/(GRES-1.0);
+ dp = tp.p[0];
+ ade[j]->interp(ade[j], &tp);
+ dv = tp.v[0];
+
+ tp.p[0] = (i-k-1)/(GRES-1.0);
+ ade[j]->interp(ade[j], &tp);
+ slope = (dv - tp.v[0])/(dp - (i-k-1)/(GRES-1.0));
+ if (k == 0)
+ aslope = slope;
+//printf(" Chan %d, dev %f, dv = %f, slope = %f\n", j, (i-k)/(GRES-1.0),dv - tp.v[0],slope);
+ if (slope < minslope)
+ minslope = slope;
+ }
+//printf("Chan %d, dev %f, aslope = %f, min slope = %f\n", j, i/(GRES-1.0),aslope,minslope);
+ /* Normalize the slopes */
+ naslope = aslope * SLOPE_NORM/pct->ademax[j];
+ nminslope = minslope * SLOPE_NORM/pct->ademax[j];
+//printf("Chan %d, dev %f, norm aslope = %f, min slope = %f\n", j, i/(GRES-1.0),naslope,nminslope);
+
+ if (naslope > MIN_SLOPE_A && nminslope >= MIN_SLOPE_O)
+ break;
+ }
+ pct->devmax[j] = i/(GRES-1.0);
+
+ /* Scale auto max device value */
+ if (maxscale[j] >= 0.0)
+ pct->devmax[j] *= maxscale[j];
+
+ /* Manually set initial dev max */
+ } else {
+ if (maxscale[j] >= 0.0)
+ warning("Chan %d, scale %.1f%% of auto max ignored since max override used\n", j, maxscale[j] * 100.0);
+ }
+
+ /* Lookup devmax to set ademax */
+ tp.p[0] = pct->devmax[j];
+ ade[j]->interp(ade[j], &tp);
+ pct->ademax[j] = tp.v[0];
+
+
+ /* Establish a default ademin value */
+ if (pct->ademin[j] < 0.0)
+ pct->ademin[j] = 0.0;
+ }
+
+ } else if (recal) {
+
+ /* Since the plot markers use devmax, look it up */
+ for (j = 0; j < devchan; j++) {
+ if ((pct->devmax[j] = rspl_ilookup(ade[j], 0.5, pct->ademax[j])) < 0.0)
+ error("Unexpected failure to invert curve %d for ADE %f",j,pct->ademax[j]);
+ }
+ }
+
+ /* Find the maximum aDE value for each curve */
+ for (j = 0; j < devchan; j++) {
+ co tp; /* Test point */
+ mxade[j] = -1e6;
+ for (i = 0; i < PRES; i++) {
+ tp.p[0] = i/(double)(PRES-1);
+ ade[j]->interp(ade[j], &tp);
+ if (tp.v[0] > mxade[j])
+ mxade[j] = tp.v[0];
+ }
+ }
+
+ if (initial || recal) {
+ /* Compute an ideal power-like value for test target */
+ for (j = 0; j < devchan; j++) {
+ double hdv; /* Half device value */
+ double hdvrde; /* Half device rDE value */
+ double thdvrde; /* Target half device rDE value */
+ double thdv; /* Target half device value */
+ double fdvrde; /* Full device rDE value */
+ co tp; /* Test point */
+
+ /* full rDE */
+ tp.p[0] = pct->devmax[j];
+ rde[j]->interp(rde[j], &tp);
+ fdvrde = tp.v[0];
+
+ /* Half device value of maximum */
+ hdv = pct->devmax[j] * 0.5;
+
+ /* rDE value half the device value */
+ tp.p[0] = hdv;
+ rde[j]->interp(rde[j], &tp);
+ hdvrde = tp.v[0];
+
+ /* rDE value we'd like at half the device value */
+ thdvrde = 0.5 * fdvrde;
+
+ /* Device value to get the rDE value we'd like at half */
+ if ((thdv = rspl_ilookup(rde[j], 0.5, thdvrde)) < 0.0)
+ error("Unexpected failure to invert curve %d for ADE %f",j,thdvrde);
+
+//printf("hdv %f, hdvrde %f, thdvrde %f, fdvrde %f, thdv %f\n",hdv,hdvrde,thdvrde, fdvrde,thdv);
+
+ /* Power like value needed to get rDE value we'd like at hald device */
+ idpow[j] = icx_powlike_needed(hdv, thdv);
+
+ }
+ }
+
+ if (verb > 1) {
+ printf("Abs DE values:\n");
+ for (i = 0; i < PRES; i++) {
+ co tp; /* Test point */
+ tp.p[0]= i/(double)(PRES-1);
+
+ printf(" dev %f, aDE",tp.p[0]);
+ for (j = 0; j < 6 && j < devchan; j++) {
+ ade[j]->interp(ade[j], &tp);
+ printf(" %f",tp.v[0]);
+ }
+ printf("\n");
+ }
+ printf("Rel DE values:\n");
+ for (i = 0; i < PRES; i++) {
+ co tp; /* Test point */
+ tp.p[0]= i/(double)(PRES-1);
+
+ printf(" dev %f, rdev",tp.p[0]);
+ for (j = 0; j < 6 && j < devchan; j++) {
+ rde[j]->interp(rde[j], &tp);
+ printf(" %f",tp.v[0]);
+ }
+ printf("\n");
+ }
+ }
+
+ if (initial || recal) {
+ if (verb && pct->is_set(pct)) {
+ for (j = 0; j < devchan; j++) {
+ printf("Chan %d Dev max %f, aDE Max %f, aDE Min %f\n",j,pct->devmax[j],pct->ademax[j],pct->ademin[j]);
+ }
+ }
+
+ if (verb) {
+ double avgpow = 0.0;
+ for (j = 0; j < devchan; j++) {
+ printf("Chan %d ideal targen power = %f\n",j,idpow[j]);
+ avgpow += idpow[j];
+ }
+ avgpow /= (double)devchan;
+ printf("Average ideal targen power = %f\n",avgpow);
+ }
+ }
+
+ /* Plot both the delta E curves, and markers */
+ if (doplot) {
+ co tp; /* Test point */
+ double xx[PRES];
+ double yy[10][PRES];
+ double cx[10], cy[10];
+ int nmark;
+
+ printf("Absolute DE plot:\n");
+
+ for (i = 0; i < PRES; i++) {
+ xx[i] = i/(double)(PRES-1);
+
+ for (j = 0; j < 10 && j < devchan; j++) {
+ tp.p[0] = xx[i];
+ ade[j]->interp(ade[j], &tp);
+ yy[j][i] = tp.v[0];
+ }
+ }
+ nmark = 0;
+ if (pct->is_set(pct)) {
+ /* Add markers for deMax */
+ for (j = 0; j < 10 && j < devchan; j++) {
+ cx[j] = pct->devmax[j];
+ cy[j] = pct->ademax[j];
+ nmark++;
+ }
+ }
+ do_plot10p(xx, devchan > 3 ? yy[3] : NULL,
+ devchan > 1 ? yy[1] : NULL,
+ devchan > 4 ? yy[4] : NULL,
+ devchan > 0 ? yy[0] : NULL,
+ devchan > 2 ? yy[2] : NULL,
+ devchan > 5 ? yy[5] : NULL,
+ devchan > 6 ? yy[6] : NULL,
+ devchan > 7 ? yy[7] : NULL,
+ devchan > 8 ? yy[8] : NULL,
+ devchan > 9 ? yy[9] : NULL,
+ PRES,
+ cx, cy, verify ? 0 : nmark);
+
+ printf("Relative DE plot:\n");
+
+ for (i = 0; i < PRES; i++) {
+ xx[i] = i/(double)(PRES-1.0);
+
+ for (j = 0; j < 10 && j < devchan; j++) {
+ tp.p[0] = xx[i];
+ rde[j]->interp(rde[j], &tp);
+ yy[j][i] = tp.v[0];
+ }
+ }
+ nmark = 0;
+ if (pct->is_set(pct)) {
+ /* Add markers for deMax */
+ for (j = 0; j < 10 && j < devchan; j++) {
+ cx[j] = pct->devmax[j];
+ tp.p[0] = cx[j];
+ rde[j]->interp(rde[j], &tp);
+ cy[j] = tp.v[0];
+ nmark++;
+ }
+ }
+ do_plot10p(xx, devchan > 3 ? yy[3] : NULL,
+ devchan > 1 ? yy[1] : NULL,
+ devchan > 4 ? yy[4] : NULL,
+ devchan > 0 ? yy[0] : NULL,
+ devchan > 2 ? yy[2] : NULL,
+ devchan > 5 ? yy[5] : NULL,
+ devchan > 6 ? yy[6] : NULL,
+ devchan > 7 ? yy[7] : NULL,
+ devchan > 8 ? yy[8] : NULL,
+ devchan > 9 ? yy[9] : NULL,
+ PRES,
+ cx, cy, verify ? 0 : nmark);
+
+ if (idpow[0] > 0.0) {
+ printf("Relative DE plot with ideal targen power applied:\n");
+
+ for (i = 0; i < PRES; i++) {
+ xx[i] = i/(double)(PRES-1.0);
+
+ for (j = 0; j < 10 && j < devchan; j++) {
+ tp.p[0] = icx_powlike(xx[i],idpow[j]);
+ rde[j]->interp(rde[j], &tp);
+ yy[j][i] = tp.v[0];
+ }
+ }
+ nmark = 0;
+ if (pct->is_set(pct)) {
+ /* Add markers for deMax */
+ for (j = 0; j < 10 && j < devchan; j++) {
+ cx[j] = pct->devmax[j];
+ tp.p[0] = icx_powlike(cx[j],idpow[j]);
+ rde[j]->interp(rde[j], &tp);
+ cy[j] = tp.v[0];
+ nmark++;
+ }
+ }
+ do_plot10p(xx, devchan > 3 ? yy[3] : NULL,
+ devchan > 1 ? yy[1] : NULL,
+ devchan > 4 ? yy[4] : NULL,
+ devchan > 0 ? yy[0] : NULL,
+ devchan > 2 ? yy[2] : NULL,
+ devchan > 5 ? yy[5] : NULL,
+ devchan > 6 ? yy[6] : NULL,
+ devchan > 7 ? yy[7] : NULL,
+ devchan > 8 ? yy[8] : NULL,
+ devchan > 9 ? yy[9] : NULL,
+ PRES,
+ cx, cy, verify ? 0 : nmark);
+ }
+ }
+
+ /* Compare the previous expected aDE against the current one */
+ if (verify) {
+ co tp; /* Test point */
+ double avg[MAX_CHAN];
+ double max[MAX_CHAN];
+ double rms[MAX_CHAN];
+ int verified = 1;
+
+ /* Verify each channel */
+ for (j = 0; j < devchan; j++) {
+ co tp;
+
+ avg[j] = 0.0;
+ max[j] = -1.0;
+ rms[j] = 0.0;
+
+ /* Sample it at GRES */
+ for (i = 0; i < GRES; i++) {
+ double iv, targ, val, tt;
+
+ iv = i/(GRES-1.0);
+
+ /* Lookup the ade that we expect */
+ tp.p[0] = iv;
+ pcade[j]->interp(pcade[j], &tp);
+ targ = tp.v[0];
+
+ /* Lookup the ade that we have */
+ tp.p[0] = iv;
+ ade[j]->interp(ade[j], &tp);
+ val = tp.v[0];
+
+ /* Compute the stats */
+ tt = fabs(targ - val);
+ avg[j] += tt;
+ rms[j] += tt * tt;
+ if (tt > max[j])
+ max[j] = tt;
+//printf("~1 chan %d, ix %d, iv %f, targ %f, actual %f, err %f\n",j,i,iv,targ,val,tt);
+ }
+ avg[j] /= (double)GRES;
+ rms[j] /= (double)GRES;
+ rms[j] = sqrt(rms[j]);
+ if (max[j] > ver_maxde)
+ verified = 0;
+ }
+ if (verb) {
+ for (j = 0; j < devchan; j++) {
+ printf("Verify results:\n");
+ printf("Channel %d has DE avg %.1f, rms %.1f, max %.1f\n",j,avg[j],rms[j],max[j]);
+ }
+ if (verified)
+ printf("Verified OK\n");
+ else
+ printf("Verification FAILED\n");
+ }
+
+ /* Plot the verification curves */
+ if (doplot) {
+ double xx[PRES];
+ double yy[10][PRES];
+
+ printf("Verification match plot:\n");
+
+ for (j = 0; j < 6 && j < devchan; j++) {
+ co tp; /* Test point */
+ double max;
+
+ /* Establish the scale */
+ tp.p[0] = 1.0;
+ pcade[j]->interp(pcade[j], &tp);
+ max = tp.v[0];
+
+ for (i = 0; i < PRES; i++) {
+ xx[i] = i/(double)(PRES-1);
+
+ /* Convert ade target to device */
+ tp.v[0] = max * xx[i];
+ if ((tp.p[0] = rspl_ilookup(pcade[j], 1.0, tp.v[0])) < 0.0)
+ error("Unexpected failure to invert curve %d for pcADE %f",j,tp.v[0]);
+ /* Convert device to actual ade */
+ ade[j]->interp(ade[j], &tp);
+ if (fabs(max) > 0.1)
+ yy[j][i] = tp.v[0]/max;
+ else
+ yy[j][i] = 0.0;
+ }
+ }
+ do_plot10(xx, devchan > 3 ? yy[3] : NULL,
+ devchan > 1 ? yy[1] : NULL,
+ devchan > 4 ? yy[4] : NULL,
+ devchan > 0 ? yy[0] : NULL,
+ devchan > 2 ? yy[2] : NULL,
+ devchan > 5 ? yy[5] : NULL,
+ devchan > 6 ? yy[6] : NULL,
+ devchan > 7 ? yy[7] : NULL,
+ devchan > 8 ? yy[8] : NULL,
+ devchan > 9 ? yy[9] : NULL,
+ PRES, 0);
+ if (!verified)
+ exit(1);
+ }
+ } else if (initial) {
+
+ /* Convert any transfer curve target points into a smooth curve */
+ if (pct->no_tpoints > 0) {
+ int gres[MXDI] = { GRES };
+ co *pnts;
+
+ if ((pnts = (co *)calloc(pct->no_tpoints + 2, sizeof(co))) == NULL)
+ error ("Malloc of rspl points failed");
+
+ for (j = 0; j < devchan; j++) {
+ int npts;
+ int gotmin, gotmax;
+
+ /* Count the number of valid points */
+ for (npts = i = 0; i < pct->no_tpoints; i++) {
+ if (pct->tpoints[i].val[j] >= 0.0)
+ npts++;
+ }
+ if (npts == 0)
+ continue; /* No target curve for this channel */
+
+ if ((tcurves[j] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL)
+ error("new_rspl(1,1) failed");
+
+ gotmin = gotmax = 0;
+ for (npts = i = 0; i < pct->no_tpoints; i++) {
+ if (pct->tpoints[i].val[j] < 0.0)
+ continue;
+
+ pnts[npts].p[0] = pct->tpoints[i].loc;
+ pnts[npts].v[0] = pct->tpoints[i].val[j];
+ if (pnts[npts].p[0] < 0.0)
+ pnts[npts].p[0] = 0.0;
+ else if (pnts[npts].p[0] > 1.0)
+ pnts[npts].p[0] = 1.0;
+ if (pnts[npts].v[0] < 0.0)
+ pnts[npts].v[0] = 0.0;
+ else if (pnts[npts].v[0] > 1.0)
+ pnts[npts].v[0] = 1.0;
+
+ if (pnts[npts].p[0] <= 0.05)
+ gotmin = 1;
+ if (pnts[npts].p[0] >= 0.95)
+ gotmax = 1;
+ npts++;
+ }
+ /* Add default anchors if there are none supplied */
+ if (gotmin == 0) {
+ pnts[npts].p[0] = 0.0;
+ pnts[npts++].v[0] = 0.0;
+ }
+ if (gotmax == 0) {
+ pnts[npts].p[0] = 1.0;
+ pnts[npts++].v[0] = 1.0;
+ }
+
+ /* Fit the curve to the given points */
+ tcurves[j]->fit_rspl(tcurves[j], RSPLFLAGS, pnts, npts,
+ NULL, NULL, gres, NULL, NULL, TCURVESMOOTH, NULL, NULL);
+ }
+ free(pnts);
+
+ /* Plot the target curves */
+ if (doplot) {
+ double xx[PRES];
+ double yy[10][PRES];
+
+ printf("Target curves plot:\n");
+
+ for (i = 0; i < (PRES-1); i++) {
+ co tp; /* Test point */
+ double pp = i/(PRES-1.0);
+
+ xx[i] = pp;
+ for (j = 0; j < 10 && j < devchan; j++) {
+ if (tcurves[j] != NULL) {
+ tp.p[0] = pp;
+ tcurves[j]->interp(tcurves[j], &tp);
+ yy[j][i] = tp.v[0];
+ } else
+ yy[j][i] = pp;
+ }
+ }
+ do_plot10(xx, devchan > 3 ? yy[3] : NULL,
+ devchan > 1 ? yy[1] : NULL,
+ devchan > 4 ? yy[4] : NULL,
+ devchan > 0 ? yy[0] : NULL,
+ devchan > 2 ? yy[2] : NULL,
+ devchan > 5 ? yy[5] : NULL,
+ devchan > 6 ? yy[6] : NULL,
+ devchan > 7 ? yy[7] : NULL,
+ devchan > 8 ? yy[8] : NULL,
+ devchan > 9 ? yy[9] : NULL,
+ PRES, 0);
+ }
+ }
+
+ /* Do inverse lookup to create relative linearization curves */
+ n_cvals = CAL_RES;
+ for (j = 0; j < devchan; j++) {
+ co tp;
+ double rdemin, rdemax; /* Relative DE min and max targets */
+
+ /* Convert absolute de aims to relative */
+ if ((rdemax = rspl_ilookup(ade[j], 0.0, pct->ademax[j])) < 0.0)
+ error("Unexpected failure to invert curve %d for DE %f",j,pct->ademax[j]);
+
+ tp.p[0] = rdemax;
+ rde[j]->interp(rde[j], &tp);
+ rdemax = tp.v[0];
+
+ if ((rdemin = rspl_ilookup(ade[j], 1.0, pct->ademin[j])) < 0.0)
+ error("Unexpected failure to invert curve %d for DE %f",j,pct->ademax[j]);
+
+ tp.p[0] = rdemin;
+ rde[j]->interp(rde[j], &tp);
+ rdemin = tp.v[0];
+
+ if (verb > 0)
+ printf("Chan %d: rDE Max = %f, rDE Min = %f\n",j,rdemax,rdemin);
+
+ if ((cvals[j] = (wval *)malloc(sizeof(wval) * n_cvals)) == NULL)
+ error("Malloc of %d cvals failed",n_cvals);
+
+ /* Convert relative delta E aim to device value */
+ for (i = 0; i < n_cvals; i++) {
+ double x = i/(n_cvals-1.0);
+ double inv;
+
+ cvals[j][i].inv = x;
+
+ /* Apply any aim tweak curve */
+ if (tcurves[j] != NULL) {
+ tp.p[0] = x;
+ tcurves[j]->interp(tcurves[j], &tp);
+ x = tp.v[0];
+ }
+
+ inv = x * (rdemax - rdemin) + rdemin;
+
+ if ((cvals[j][i].dev = rspl_ilookup(rde[j], 0.5, inv)) < 0.0)
+ error("Unexpected failure to invert curve %d for DE %f",j,inv);
+//printf("~1 chan %d, step %d, inv %f, detarg %f, got dev %f\n",j,i,x,pp[0].v[0],pp[k].p[0]);
+ }
+ }
+
+ } else if (recal || imitate) {
+
+ n_cvals = CAL_RES;
+ for (j = 0; j < devchan; j++) {
+ co tp;
+
+ if ((cvals[j] = (wval *)malloc(sizeof(wval) * n_cvals)) == NULL)
+ error("Malloc of %d cvals failed",n_cvals);
+
+ /* Lookup the expected ade for each input device value, and */
+ /* then translate it into the required output device value */
+ for (i = 0; i < n_cvals; i++) {
+ double x = i/(n_cvals-1.0);
+
+ cvals[j][i].inv = tp.p[0] = x;
+ pcade[j]->interp(pcade[j], &tp);
+
+ if ((cvals[j][i].dev = rspl_ilookup(ade[j], 0.5, tp.v[0])) < 0.0)
+ error("Unexpected failure to invert curve %d for DE %f",j,tp.v[0]);
+//printf("~1 chan %d, ix %d, inv %f, pcade %f, iade %f\n",j,i,x,tp.v[0],cvals[j][i].dev);
+ }
+ }
+ }
+
+ if (initial || recal || imitate) {
+
+ if (verb > 1) {
+ printf("Calibration curve values:\n");
+ for (i = 0; i < n_cvals; i++) {
+ printf(" inv %f, dev",cvals[0][i].inv);
+ for (j = 0; j < devchan; j++) {
+ printf(" %f",cvals[j][i].dev);
+ }
+ printf("\n");
+ }
+ }
+
+ /* Plot the calibration curves */
+ if (doplot) {
+ double xx[PRES];
+ double yy[10][PRES];
+
+ printf("Calibration curve plot:\n");
+
+ for (i = 0; i < n_cvals; i++) {
+ xx[i] = cvals[0][i].inv;
+ for (j = 0; j < 10 && j < devchan; j++) {
+ yy[j][i] = cvals[j][i].dev;
+ }
+ }
+ do_plot10(xx, devchan > 3 ? yy[3] : NULL, /* Black */
+ devchan > 1 ? yy[1] : NULL, /* Red */
+ devchan > 4 ? yy[4] : NULL, /* Green */
+ devchan > 0 ? yy[0] : NULL, /* Blue */
+ devchan > 2 ? yy[2] : NULL, /* Yellow */
+ devchan > 5 ? yy[5] : NULL, /* Purple */
+ devchan > 6 ? yy[6] : NULL, /* Brown */
+ devchan > 7 ? yy[7] : NULL, /* Orange */
+ devchan > 8 ? yy[8] : NULL, /* Grey */
+ devchan > 9 ? yy[9] : NULL, /* White */
+ PRES, 0);
+ }
+
+ /* Write out an Argyll .CAL file */
+ if (dowrite) {
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ char *ident = icx_inkmask2char(devmask, 1);
+ char *bident = icx_inkmask2char(devmask, 0);
+ cgats_set_elem *setel; /* Array of set value elements */
+ int nsetel = 0;
+ int ncps; /* Number of curve parameters */
+ double *cps[3]; /* Arrays of curve parameters */
+ char *bp = NULL, buf[100]; /* Buffer to sprintf into */
+ co tp;
+
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CAL"); /* our special type is Calibration file */
+
+ ocg->add_table(ocg, tt_other, 0); /* Add a table for RAMDAC values */
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Device Calibration Curves",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll printcal", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);
+ ocg->add_kword(ocg, 0, "COLOR_REP", ident, NULL);
+
+ if (xpi.deviceMfgDesc != NULL)
+ ocg->add_kword(ocg, 0, "MANUFACTURER", xpi.deviceMfgDesc, NULL);
+ if (xpi.modelDesc != NULL)
+ ocg->add_kword(ocg, 0, "MODEL", xpi.modelDesc, NULL);
+ if (xpi.profDesc != NULL)
+ ocg->add_kword(ocg, 0, "DESCRIPTION", xpi.profDesc, NULL);
+ if (xpi.copyright != NULL)
+ ocg->add_kword(ocg, 0, "COPYRIGHT", xpi.copyright, NULL);
+
+ /* Setup the table which holds the translation from calibrated */
+ /* device value "I" to the raw device channel value */
+ sprintf(buf, "%s_I",bident);
+ ocg->add_field(ocg, 0, buf, r_t);
+ nsetel++;
+ for (j = 0; j < devchan; j++) {
+ inkmask imask = icx_index2ink(devmask, j);
+ sprintf(buf, "%s_%s",bident,icx_ink2char(imask));
+ ocg->add_field(ocg, 0, buf, r_t);
+ nsetel++;
+ }
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL)
+ error("Malloc failed!");
+
+ /* Write the per channel device to device loolup curve values */
+ if (devmask & ICX_ADDITIVE) {
+ for (i = n_cvals-1; i >= 0; i--) {
+
+ setel[0].d = 1.0 - cvals[0][i].inv;
+ for (j = 0; j < devchan; j++)
+ setel[1+j].d = 1.0 - cvals[j][i].dev;
+ ocg->add_setarr(ocg, 0, setel);
+ }
+ } else {
+ for (i = 0; i < n_cvals; i++) {
+
+ setel[0].d = cvals[0][i].inv;
+ for (j = 0; j < devchan; j++)
+ setel[1+j].d = cvals[j][i].dev;
+ ocg->add_setarr(ocg, 0, setel);
+ }
+ }
+
+ free(setel);
+
+ /* Write the calibration target information to a second table */
+ if (pct->write(pct, ocg, 1) != 0)
+ error("Writing cal target info to cal file '%s'",outname);
+
+ /* Add a third table which is the expected absolute DE response */
+ /* of the calibrated device. */
+ ocg->add_table(ocg, tt_other, 0); /* Add a table for RAMDAC values */
+ ocg->add_kword(ocg, 2, "DESCRIPTOR", "Argyll Output Calibration Expected DE Response",NULL);
+ ocg->add_kword(ocg, 2, "ORIGINATOR", "Argyll printcal", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 2, "CREATED",atm, NULL);
+
+ ocg->add_kword(ocg, 2, "DEVICE_CLASS","OUTPUT", NULL);
+ ocg->add_kword(ocg, 2, "COLOR_REP", ident, NULL);
+
+ /* Setup the table which holds the translation from calibrated */
+ /* device value "I" to the expected absolute deltaE value for */
+ /* each colorant. */
+ sprintf(buf, "%s_I_DE",bident);
+ ocg->add_field(ocg, 2, buf, r_t);
+ nsetel++;
+ for (j = 0; j < devchan; j++) {
+ inkmask imask = icx_index2ink(devmask, j);
+ sprintf(buf, "%s_%s_DE",bident,icx_ink2char(imask));
+ ocg->add_field(ocg, 2, buf, r_t);
+ nsetel++;
+ }
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL)
+ error("Malloc failed!");
+
+ for (i = 0; i < n_cvals; i++) {
+ int ix = i;
+
+ /* Calibrated device value */
+ if (devmask & ICX_ADDITIVE) {
+ ix = n_cvals -1 - i;
+ setel[0].d = 1.0 - cvals[0][ix].inv;
+ } else
+ setel[0].d = cvals[0][ix].inv;
+
+ for (j = 0; j < devchan; j++) {
+ tp.p[0] = cvals[j][ix].dev; /* Raw device value */
+ ade[j]->interp(ade[j], &tp); /* Corresponding ade value */
+ setel[1+j].d = tp.v[0];
+ }
+ ocg->add_setarr(ocg, 2, setel);
+ }
+
+ free(setel);
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error to file '%s': %s",outname,ocg->err);
+
+ if (verb)
+ printf("Written calibration file '%s'\n",outname);
+
+ ocg->del(ocg); /* Clean up */
+ free(ident);
+ free(bident);
+ }
+
+ /*
+ The structure of *.AMP is very simple.
+
+ It has 5 tables that have
+ 256 entries that are 8-bit (byte), even for 16 bit mode.
+
+ The first table 0000..00FFh is the CMYK channel.
+ The second table 0100..01FFh is the C channel.
+ The third table 0200..02FFh is the M channel.
+ The fourth table 0300..03FFh is the Y channel.
+ The fifth table 0300..03FFh is the K channel.
+
+ Table position nn00h is the black end and table position nnFFh
+ is the white end.
+
+ */
+
+ /* Write an Adobe map format (.AMP) file */
+ /* (It's not clear if more than 4 channels is allowed) */
+ if (dowrite && doamp) {
+ FILE *fp;
+ cgatsFile *p;
+ char nmode[50] = { '\000' };
+
+ strcpy(nmode, "w");
+#if defined(O_BINARY) || defined(_O_BINARY)
+ strcat(nmode, "b");
+#endif
+ if ((fp = fopen(ampname, nmode)) == NULL)
+ error("Couldn't open '%s' for writing",ampname);
+
+ /* CMYK table is unity */
+ for (i = 0; i < 256; i++) {
+ if (putc(i,fp) == EOF)
+ error("Error writing to fle '%s'",ampname);
+ }
+ for (j = 0; j < devchan; j++) {
+ for (i = 0; i < 256; i++) {
+ int x;
+ if (devmask & ICX_ADDITIVE)
+ x = (int)(cvals[j][i].dev * 255.0 + 0.5); /* ??? */
+ else
+ x = 255 - (int)(cvals[j][255 - i].dev * 255.0 + 0.5);
+ if (putc(x,fp) == EOF)
+ error("Error writing to fle '%s'",ampname);
+//printf("~1 chan %d, inv %d, dev %d\n",j,i,x);
+ }
+ }
+ /* Extra 1:1 table */
+ for (i = 0; i < 256; i++) {
+ if (putc(i,fp) == EOF)
+ error("Error writing to fle '%s'",ampname);
+ }
+
+ if (fclose(fp) != 0)
+ error("Closing '%s' failed",ampname);
+
+ if (verb)
+ printf("Written calibration curves to '%s'\n",ampname);
+ }
+ }
+
+ /* Free up various possible allocations */
+ for (j = 0; j < devchan; j++) {
+ if (pvals[j] != NULL)
+ free(pvals[j]);
+ if (raw[j] != NULL)
+ raw[j]->del(raw[j]);
+ if (ade[j] != NULL)
+ ade[j]->del(ade[j]);
+ if (rde[j] != NULL)
+ rde[j]->del(rde[j]);
+ if (pcade[j] != NULL)
+ pcade[j]->del(pcade[j]);
+ if (cvals[j] != NULL)
+ free(cvals[j]);
+ if (tcurves[j] != NULL)
+ tcurves[j]->del(tcurves[j]);
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/profile/prof.h b/profile/prof.h
new file mode 100644
index 0000000..074bb73
--- /dev/null
+++ b/profile/prof.h
@@ -0,0 +1,109 @@
+#ifndef PROF_H
+#define PROF_H
+/*
+ * ICC Profile creation library.
+ *
+ * Author: Graeme W. Gill
+ * Date: 11/10/00
+ * Version: 1.00
+ *
+ * Copyright 2000 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.
+ */
+
+/*
+ * This library provide high level routines to create device ICC
+ * profiles from argyll cgats patch test data.
+ */
+
+
+/* Profile algorithm type */
+typedef enum {
+ prof_default = 0, /* Default for type of device */
+ prof_clutLab = 1, /* Lab clut. */
+ prof_clutXYZ = 2, /* XYZ clut. */
+ prof_gammat = 3, /* XYZ gamut + matrix */
+ prof_shamat = 4, /* XYZ shaper + matrix */
+ prof_gam1mat = 5, /* XYZ shared TRC gamut + matrix */
+ prof_sha1mat = 6, /* XYZ shared TRC shaper + matrix */
+ prof_matonly = 7 /* XYZ matrix, linear */
+} prof_atype;
+
+/* Output or Display device */
+void make_output_icc(
+ prof_atype ptype, /* Profile output type */
+ int mtxtoo, /* NZ if matrix tags should be created for Display XYZ cLUT */
+ icmICCVersion iccver, /* ICC profile version to create */
+ int verb, /* Vebosity level, 0 = none */
+ int iquality, /* A2B table quality, 0..2 */
+ int oquality, /* B2A table quality, 0..2 */
+ int noiluts, /* nz to supress creation of input (Device) shaper luts */
+ int noisluts, /* nz to supress creation of input sub-grid (Device) shaper luts */
+ int nooluts, /* nz to supress creation of output (PCS) shaper luts */
+ int nocied, /* nz to supress inclusion of .ti3 data in profile */
+ int noptop, /* nz to use colorimetic source gamut to make perceptual table */
+ int nostos, /* nz to use colorimetic source gamut to make perceptual table */
+ int gamdiag, /* Make gamut mapping diagnostic wrl plots */
+ int verify, /* nz to print verification */
+ int clipprims, /* Clip white, black and primaries */
+ icxInk *ink, /* Ink limit/black generation setup */
+ char *in_name, /* input .ti3 file name */
+ char *file_name, /* output icc name */
+ cgats *icg, /* input cgats structure */
+ int spec, /* Use spectral data flag */
+ icxIllumeType tillum, /* Target/simulated instrument illuminant */
+ xspect *cust_tillum, /* Possible custom target/simulated instrument illumination */
+ icxIllumeType illum, /* Spectral illuminant */
+ xspect *cust_illum, /* Possible custom illumination */
+ icxObserverType observ, /* Spectral observer */
+ 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 */
+ 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 */
+ /* may be duplicated, NULL if none */
+ int sepsat, /* Create separate Saturation B2A */
+ icxViewCond *ivc_p, /* Input Viewing Parameters for CIECAM97s */
+ icxViewCond *ovc_p, /* Output Viewing Parameters for CIECAM97s (enables CAM clip) */
+ int ivc_e, /* Input Enumerated viewing condition */
+ int ovc_e, /* Output Enumerated viewing condition */
+ icxGMappingIntent *pgmi,/* Perceptual gamut mapping intent */
+ icxGMappingIntent *sgmi,/* Saturation gamut mapping intent */
+ profxinf *pi /* Optional Profile creation extra data */
+);
+
+/* Input device */
+void make_input_icc(
+ prof_atype ptype, /* Profile algorithm type */
+ icmICCVersion iccver, /* ICC profile version to create */
+ int verb,
+ int iquality, /* A2B table quality, 0..3 */
+ int oquality, /* B2A table quality, 0..3 */
+ int noisluts, /* nz to supress creation of input (Device) shaper luts */
+ int noipluts, /* nz to supress creation of input (Device) position luts */
+ int nooluts, /* nz to supress creation of output (PCS) shaper luts */
+ int nocied, /* nz to supress inclusion of .ti3 data in profile */
+ int verify,
+ int autowpsc, /* nz for Auto scale the WP to prevent clipping above WP patch */
+ int clipovwp, /* nz for Clip cLUT values above WP */
+ double wpscale, /* >= 0.0 for media white point scale factor */
+ int dob2a, /* nz to create a B2A table as well */
+ int extrap, /* nz to create extra cLUT interpolation points */
+ int clipprims, /* Clip white, black and primaries */
+ char *in_name, /* input .ti3 file name */
+ char *file_name, /* output icc name */
+ cgats *icg, /* input cgats structure */
+ int spec, /* Use spectral data flag */
+ icxIllumeType illum, /* Spectral illuminant */
+ xspect *cust_illum, /* Possible custom illumination */
+ icxObserverType observ, /* Spectral observer */
+ double smooth, /* RSPL smoothing factor, -ve if raw */
+ double avgdev, /* reading Average Deviation as a proportion of the input range */
+ profxinf *xpi /* Optional Profile creation extra data */
+);
+
+#endif /* PROF_H */
diff --git a/profile/profcheck.c b/profile/profcheck.c
new file mode 100644
index 0000000..ca9b0b2
--- /dev/null
+++ b/profile/profcheck.c
@@ -0,0 +1,1349 @@
+
+/*
+ * Argyll Color Correction System
+ * Color Device profile checker.
+ *
+ * Author: Graeme W. Gill
+ * Date: 15/7/2001
+ *
+ * Copyright 2001 - 2005 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.
+ */
+
+/*
+ * This program takes in the .ti3 scattered test chart
+ * points, and checks them against an ICC profile.
+ * forward ICC device profile.
+ */
+
+/*
+ * TTBD:
+ * Switch to generic colorant read code rather than Grey/RGB/CMYK,
+ * and allow checking ICC profiles > 4 colors
+ */
+
+#undef DEBUG
+
+#define IMP_MONO /* Turn on development code */
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "insttypes.h"
+#include "sort.h"
+
+void
+usage(void) {
+ fprintf(stderr,"Check accuracy of ICC profile, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: profcheck [-options] data.ti3 iccprofile.icm\n");
+ fprintf(stderr," -v [level] Verbosity level (default 1), 2 to print each DE\n");
+ fprintf(stderr," -c Show CIE94 delta E values\n");
+ fprintf(stderr," -k Show CIEDE2000 delta E values\n");
+ fprintf(stderr," -w create VRML visualisation (iccprofile.wrl)\n");
+ fprintf(stderr," -x Use VRML axes\n");
+ fprintf(stderr," -m Make VRML lines a minimum of 0.5\n");
+ fprintf(stderr," -e Color vectors acording to delta E\n");
+ fprintf(stderr," -d devval1,deval2,devvalN\n");
+ fprintf(stderr," Specify a device value to sort against\n");
+ fprintf(stderr," -p Sort device value by PCS (Lab) target\n");
+ 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");
+ 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," -I intent r = relative colorimetric, a = absolute (default)\n");
+ fprintf(stderr," data.ti3 Test data file\n");
+ fprintf(stderr," iccprofile.icm Profile to check against\n");
+ exit(1);
+ }
+
+FILE *start_vrml(char *name, int doaxes);
+void start_line_set(FILE *wrl);
+void add_vertex(FILE *wrl, double pp[3]);
+void make_lines(FILE *wrl, int ppset);
+void make_de_lines(FILE *wrl);
+void end_vrml(FILE *wrl);
+
+/* Patch value type */
+typedef struct {
+ char sid[50]; /* sample id */
+ char slo[50]; /* sample location, "" if not known */
+ double p[MAX_CHAN]; /* Device value */
+ double v[3]; /* CIE value */
+ double dp; /* Delta from target value */
+ double dv; /* Delta from CIE value */
+} pval;
+
+int main(int argc, char *argv[])
+{
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ int cie94 = 0;
+ int cie2k = 0;
+ int dovrml = 0;
+ int dominl = 0;
+ int doaxes = 0;
+ int dodecol = 0;
+ char ti3name[MAXNAMEL+1] = { 0 }; /* Input cgats file base name */
+ cgats *icg; /* input cgats structure */
+ char iccname[MAXNAMEL+1] = { 0 }; /* Input icc file base name */
+ icmFile *rd_fp;
+ icRenderingIntent intent = icAbsoluteColorimetric;
+ icc *rd_icco;
+ icmLuBase *luo;
+ char out_name[MAXNAMEL+1], *xl; /* VRML name */
+ FILE *wrl = NULL;
+
+ int fwacomp = 0; /* FWA compensation */
+ int isdisp = 0; /* nz if this is a display device, 0 if output */
+ int isdnormed = 0; /* Has display data been normalised to 100 ? */
+ int spec = 0; /* Use spectral data flag */
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */
+ icxIllumeType illum = icxIT_D50; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxObserverType observ = icxOT_CIE_1931_2;
+
+ int ddevv = 0; /* Do device value sort */
+ double devval[MAX_CHAN]; /* device value to sort on */
+ int sortbypcs = 0; /* Sort by PCS */
+
+ int npat; /* Number of patches */
+ pval *tpat; /* Patch input values */
+ int i, j, rv = 0;
+ icColorSpaceSignature devspace = 0; /* The device colorspace */
+ int isAdditive = 0; /* 0 if subtractive, 1 if additive colorspace */
+ int isLab = 0; /* 0 if input is XYZ, 1 if input is Lab */
+ int devchan = 0; /* Number of device chanels */
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ error_program = "profcheck";
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v') {
+ verb = 1;
+ if (na != NULL && isdigit(na[0])) {
+ verb = atoi(na);
+ }
+ }
+
+ /* VRML */
+ else if (argv[fa][1] == 'w')
+ dovrml = 1;
+
+ /* Minimum line length */
+ else if (argv[fa][1] == 'm')
+ dominl = 1;
+
+ /* Axes */
+ else if (argv[fa][1] == 'x')
+ doaxes = 1;
+
+ /* Delta E coloring */
+ else if (argv[fa][1] == 'e')
+ dodecol = 1;
+
+ else if (argv[fa][1] == 'c') {
+ cie94 = 1;
+ cie2k = 0;
+ }
+
+ else if (argv[fa][1] == 'k') {
+ cie94 = 0;
+ cie2k = 1;
+ }
+
+ /* Device sort value */
+ else if (argv[fa][1] == 'd') {
+ char *tp, buf[200];
+ int ndv;
+ fa = nfa;
+ if (na == NULL) usage();
+
+ ddevv = 1;
+ strcpy(buf, na);
+
+ /* Replace ',' with '\000' */
+ for (ndv = 1,tp = buf; *tp != '\000'; tp++) {
+ if (*tp == ',') {
+ *tp = '\000';
+ ndv++;
+ }
+ }
+ if (ndv >= MAX_CHAN)
+ ndv = MAX_CHAN;
+
+ for (tp = buf, i = 0; i < ndv; i++, tp += strlen(tp) + 1) {
+ devval[i] = atof(tp);
+ }
+ }
+
+ else if (argv[fa][1] == 'p')
+ sortbypcs = 1;
+
+ /* FWA compensation */
+ else if (argv[fa][1] == 'f') {
+ fwacomp = 1;
+
+ if (na != NULL) { /* Argument is present - target/simulated instr. illum. */
+ fa = nfa;
+ if (strcmp(na, "A") == 0
+ || strcmp(na, "M0") == 0) {
+ spec = 1;
+ tillum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ tillum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0
+ || strcmp(na, "M1") == 0) {
+ spec = 1;
+ tillum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0
+ || strcmp(na, "M2") == 0) {
+ spec = 1;
+ tillum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ tillum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ tillum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ tillum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ tillum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ tillum = icxIT_custom;
+ if (read_xspect(&cust_tillum, na) != 0)
+ usage();
+ }
+ }
+ }
+ /* Spectral Illuminant type */
+ else if (argv[fa][1] == 'i') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "A") == 0) {
+ spec = 1;
+ illum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ illum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0) {
+ spec = 1;
+ illum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0) {
+ spec = 1;
+ illum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ illum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ illum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ illum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ illum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ illum = icxIT_custom;
+ if (read_xspect(&cust_illum, na) != 0)
+ usage();
+ }
+ }
+
+ /* Spectral Observer type */
+ else if (argv[fa][1] == 'o') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ spec = 1;
+ observ = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ spec = 1;
+ observ = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ spec = 1;
+ observ = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ spec = 1;
+ observ = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ spec = 1;
+ observ = icxOT_Shaw_Fairchild_2;
+ } else
+ usage();
+ }
+
+ /* Intent (only applies to ICC profile) */
+ else if (argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'r':
+ intent = icRelativeColorimetric;
+ break;
+ case 'a':
+ intent = icAbsoluteColorimetric;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ /* Get the file name arguments */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(ti3name,argv[fa++],MAXNAMEL); ti3name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(iccname,argv[fa++],MAXNAMEL); iccname[MAXNAMEL] = '\000';
+
+ strncpy(out_name,iccname,MAXNAMEL-4); out_name[MAXNAMEL-4] = '\000';
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".wrl");
+
+ if (fwacomp && spec == 0)
+ error ("FWA compensation only works when viewer and/or illuminant selected");
+
+ /* Open and look at the .ti3 profile patches file */
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI3"); /* our special input type is Calibration Target Information 3 */
+
+ if (icg->read_name(icg, ti3name))
+ error("CGATS file read error on '%s': %s",ti3name,icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file '%s' isn't a CTI3 format file",ti3name);
+ if (icg->ntables < 1)
+ error ("Input file '%s' doesn't contain at least one table",ti3name);
+
+ /* See if CIE is actually available - some sources of .TI3 don't provide it */
+ if (!spec
+ && icg->find_field(icg, 0, "LAB_L") < 0
+ && icg->find_field(icg, 0, "XYZ_X") < 0) {
+
+ if (icg->find_kword(icg, 0, "SPECTRAL_BANDS") < 0)
+ error ("Neither CIE nor spectral data found in file '%s'",ti3name);
+
+ /* Switch to using spectral information */
+ if (verb)
+ printf("No CIE data found, switching to spectral with standard observer & D50\n");
+ spec = 1;
+ illum = icxIT_D50;
+ observ = icxOT_CIE_1931_2;
+ }
+
+ /* Figure out what sort of device it is */
+ {
+ int ti;
+
+ if ((ti = icg->find_kword(icg, 0, "DEVICE_CLASS")) < 0)
+ error ("Input file '%s' doesn't contain keyword DEVICE_CLASS",ti3name);
+
+ if (strcmp(icg->t[0].kdata[ti],"DISPLAY") == 0) {
+ isdisp = 1;
+ }
+
+ /* See if the CIE data has been normalised to Y = 100 */
+ if ((ti = icg->find_kword(icg, 0, "NORMALIZED_TO_Y_100")) < 0
+ || strcmp(icg->t[0].kdata[ti],"NO") == 0) {
+ isdnormed = 0;
+ } else {
+ isdnormed = 1;
+ }
+ }
+
+ /* Figure out what sort of device colorspace it is */
+ {
+ int ti;
+
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error("Input file '%s' doesn't contain keyword COLOR_REPS",ti3name);
+
+ if (strcmp(icg->t[0].kdata[ti],"CMYK_XYZ") == 0) {
+ devspace = icSigCmykData;
+ devchan = 4;
+ isLab = 0;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"CMYK_LAB") == 0) {
+ devspace = icSigCmykData;
+ devchan = 4;
+ isLab = 1;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"CMY_XYZ") == 0) {
+ devspace = icSigCmyData;
+ devchan = 3;
+ isLab = 0;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"CMY_LAB") == 0) {
+ devspace = icSigCmyData;
+ devchan = 3;
+ isLab = 1;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"RGB_XYZ") == 0) {
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 0;
+ isAdditive = 1;
+ } else if (strcmp(icg->t[0].kdata[ti],"RGB_LAB") == 0) {
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 1;
+ isAdditive = 1;
+ } else if (strcmp(icg->t[0].kdata[ti],"iRGB_XYZ") == 0) {
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 0;
+ isAdditive = 1;
+ } else if (strcmp(icg->t[0].kdata[ti],"iRGB_LAB") == 0) {
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 1;
+ isAdditive = 1;
+ /* Scanner .ti3 files: */
+ } else if (strcmp(icg->t[0].kdata[ti],"XYZ_RGB") == 0) {
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 0;
+ isAdditive = 1;
+ } else if (strcmp(icg->t[0].kdata[ti],"LAB_RGB") == 0) {
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 1;
+ isAdditive = 1;
+#ifdef IMP_MONO
+ } else if (strcmp(icg->t[0].kdata[ti],"K_XYZ") == 0) {
+ devspace = icSigGrayData;
+ devchan = 1;
+ isLab = 0;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"K_LAB") == 0) {
+ devspace = icSigGrayData;
+ devchan = 1;
+ isLab = 1;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"W_XYZ") == 0) {
+ devspace = icSigGrayData;
+ devchan = 1;
+ isLab = 0;
+ isAdditive = 1;
+ } else if (strcmp(icg->t[0].kdata[ti],"W_LAB") == 0) {
+ devspace = icSigGrayData;
+ devchan = 1;
+ isLab = 1;
+ isAdditive = 1;
+#endif /* IMP_MONO */
+
+ } else
+ error("Device input file '%s' has unhandled color representation '%s'",
+ ti3name, icg->t[0].kdata[ti]);
+ }
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error("Input file '%s' has no sets of data",ti3name);
+
+ if (verb) {
+ fprintf(verbo,"No of test patches = %d\n",npat);
+ }
+
+ /* Allocate arrays to hold test patch input and output values */
+ if ((tpat = (pval *)malloc(sizeof(pval) * npat)) == NULL)
+ error("Malloc failed - tpat[]");
+
+ /* Read in the CGATs fields */
+ {
+ int sidx; /* Sample ID index */
+ int sloc; /* Sample location indexi (if any) */
+ int ti, ci, mi, yi, ki;
+ int Xi, Yi, Zi;
+
+ if ((sidx = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_ID",ti3name);
+ if (icg->t[0].ftype[sidx] != nqcs_t)
+ error("Input file '%s' field SAMPLE_ID is wrong type",ti3name);
+
+ if ((sloc = icg->find_field(icg, 0, "SAMPLE_LOC")) >= 0) {
+ if (icg->t[0].ftype[sloc] != cs_t)
+ error("Input file '%s' field SAMPLE_LOC is wrong type",ti3name);
+ }
+
+ if (devspace == icSigGrayData) {
+ if (isAdditive) {
+ if ((ci = icg->find_field(icg, 0, "GRAY_W")) < 0)
+ error("Input file doesn't contain field GRAY_W");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field GRAY_W is wrong type - corrupted file ?");
+ } else {
+ if ((ci = icg->find_field(icg, 0, "GRAY_K")) < 0)
+ error("Input file doesn't contain field GRAY_K");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field GRAY_K is wrong type - corrupted file ?");
+ }
+ mi = yi = ki = ci;
+
+ } else if (devspace == icSigRgbData) {
+ if ((ci = icg->find_field(icg, 0, "RGB_R")) < 0)
+ error("Input file '%s' doesn't contain field RGB_R",ti3name);
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Input file '%s' field RGB_R is wrong type",ti3name);
+ if ((mi = icg->find_field(icg, 0, "RGB_G")) < 0)
+ error("Input file '%s' doesn't contain field RGB_G",ti3name);
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Input file '%s' field RGB_G is wrong type",ti3name);
+ if ((yi = icg->find_field(icg, 0, "RGB_B")) < 0)
+ error("Input file '%s' doesn't contain field RGB_B",ti3name);
+ if (icg->t[0].ftype[yi] != r_t)
+ error("Input file '%s' field RGB_B is wrong type",ti3name);
+ ki = yi;
+
+ } else if (devspace == icSigCmyData) {
+
+ if ((ci = icg->find_field(icg, 0, "CMY_C")) < 0)
+ error("Input file '%s' doesn't contain field CMY_C",ti3name);
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Input file '%s' field CMY_C is wrong type",ti3name);
+ if ((mi = icg->find_field(icg, 0, "CMY_M")) < 0)
+ error("Input file '%s' doesn't contain field CMY_M",ti3name);
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Input file '%s' field CMY_M is wrong type",ti3name);
+ if ((yi = icg->find_field(icg, 0, "CMY_Y")) < 0)
+ error("Input file '%s' doesn't contain field CMY_Y",ti3name);
+ ki = yi;
+ } else { /* Assume CMYK */
+
+ if ((ci = icg->find_field(icg, 0, "CMYK_C")) < 0)
+ error("Input file '%s' doesn't contain field CMYK_C",ti3name);
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Input file '%s' field CMYK_C is wrong type",ti3name);
+ if ((mi = icg->find_field(icg, 0, "CMYK_M")) < 0)
+ error("Input file '%s' doesn't contain field CMYK_M",ti3name);
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Input file '%s' field CMYK_M is wrong type",ti3name);
+ if ((yi = icg->find_field(icg, 0, "CMYK_Y")) < 0)
+ error("Input file '%s' doesn't contain field CMYK_Y",ti3name);
+ if (icg->t[0].ftype[yi] != r_t)
+ error("Input file '%s' field CMYK_Y is wrong type",ti3name);
+ if ((ki = icg->find_field(icg, 0, "CMYK_K")) < 0)
+ error("Input file '%s' doesn't contain field CMYK_K",ti3name);
+ if (icg->t[0].ftype[ki] != r_t)
+ error("Input file '%s' field CMYK_K is wrong type",ti3name);
+ }
+
+ if (spec == 0) { /* Using instrument tristimulous value */
+
+ if (isLab) { /* Expect Lab */
+ if ((Xi = icg->find_field(icg, 0, "LAB_L")) < 0)
+ error("Input file '%s' doesn't contain field LAB_L",ti3name);
+ if (icg->t[0].ftype[Xi] != r_t)
+ error("Input file '%s' field LAB_L is wrong type",ti3name);
+ if ((Yi = icg->find_field(icg, 0, "LAB_A")) < 0)
+ error("Input '%s' file doesn't contain field LAB_A",ti3name);
+ if (icg->t[0].ftype[Yi] != r_t)
+ error("Input file '%s' field LAB_A is wrong type",ti3name);
+ if ((Zi = icg->find_field(icg, 0, "LAB_B")) < 0)
+ error("Input file '%s' doesn't contain field LAB_B",ti3name);
+ if (icg->t[0].ftype[Zi] != r_t)
+ error("Input file '%s' field LAB_B is wrong type",ti3name);
+
+ } else { /* Expect XYZ */
+ if ((Xi = icg->find_field(icg, 0, "XYZ_X")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_X",ti3name);
+ if (icg->t[0].ftype[Xi] != r_t)
+ error("Input file '%s' field XYZ_X is wrong type",ti3name);
+ if ((Yi = icg->find_field(icg, 0, "XYZ_Y")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Y",ti3name);
+ if (icg->t[0].ftype[Yi] != r_t)
+ error("Input file '%s' field XYZ_Y is wrong type",ti3name);
+ if ((Zi = icg->find_field(icg, 0, "XYZ_Z")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Z",ti3name);
+ if (icg->t[0].ftype[Zi] != r_t)
+ error("Input file '%s' field XYZ_Z is wrong type",ti3name);
+ }
+
+ for (i = 0; i < npat; i++) {
+ strcpy(tpat[i].sid, (char *)icg->t[0].fdata[i][sidx]);
+ if (sloc >= 0)
+ strcpy(tpat[i].slo, (char *)icg->t[0].fdata[i][sloc]);
+ else
+ strcpy(tpat[i].slo, "");
+ tpat[i].p[0] = *((double *)icg->t[0].fdata[i][ci]) / 100.0;
+ tpat[i].p[1] = *((double *)icg->t[0].fdata[i][mi]) / 100.0;
+ tpat[i].p[2] = *((double *)icg->t[0].fdata[i][yi]) / 100.0;
+ tpat[i].p[3] = *((double *)icg->t[0].fdata[i][ki]) / 100.0;
+ if (tpat[i].p[0] > 1.0
+ || tpat[i].p[1] > 1.0
+ || tpat[i].p[2] > 1.0
+ || tpat[i].p[3] > 1.0) {
+ error("Input file '%s' device value field value exceeds 100.0 !",ti3name);
+ }
+ tpat[i].v[0] = *((double *)icg->t[0].fdata[i][Xi]);
+ tpat[i].v[1] = *((double *)icg->t[0].fdata[i][Yi]);
+ tpat[i].v[2] = *((double *)icg->t[0].fdata[i][Zi]);
+ if (!isLab && (!isdisp || isdnormed != 0)) {
+ tpat[i].v[0] /= 100.0; /* Normalise XYZ to range 0.0 - 1.0 */
+ tpat[i].v[1] /= 100.0;
+ tpat[i].v[2] /= 100.0;
+ }
+ if (!isLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
+ icmXYZ2Lab(&icmD50, tpat[i].v, tpat[i].v);
+ }
+ }
+
+ } else { /* Using spectral data */
+ int ii;
+ xspect sp;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xsp2cie *sp2cie; /* Spectral conversion object */
+
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_BANDS",ti3name);
+ sp.spec_n = atoi(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_START_NM",ti3name);
+ sp.spec_wl_short = atof(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file '%s; doesn't contain keyword SPECTRAL_END_NM",ti3name);
+ sp.spec_wl_long = atof(icg->t[0].kdata[ii]);
+ if (!isdisp || isdnormed != 0)
+ sp.norm = 100.0;
+ else
+ sp.norm = 1.0;
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = icg->find_field(icg, 0, buf)) < 0)
+ error("Input file '%s' doesn't contain field %s",ti3name,buf);
+ }
+
+ if (isdisp) {
+ illum = icxIT_none; /* Displays are assumed to be self luminous */
+ }
+
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie(illum, illum == icxIT_none ? NULL : &cust_illum,
+ observ, NULL, icSigLabData, icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+
+ if (fwacomp) {
+ double nw = 0.0; /* Number of media white patches */
+ xspect mwsp; /* Medium spectrum */
+ instType itype; /* Spectral instrument type */
+ xspect insp; /* Instrument illuminant */
+
+ mwsp = sp; /* Struct copy */
+
+ if ((ti = icg->find_kword(icg, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Input file '%s' can't find target instrument needed for FWA compensation",ti3name);
+
+ if ((itype = inst_enum(icg->t[0].kdata[ti])) == instUnknown)
+ error ("Input file '%s' unrecognised target instrument '%s'",ti3name, icg->t[0].kdata[ti]);
+
+ if (inst_illuminant(&insp, itype) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+
+ /* Find the media white spectral reflectance */
+ for (j = 0; j < mwsp.spec_n; j++)
+ mwsp.spec[j] = 0.0;
+
+ /* Compute the mean of all the media white patches */
+ for (i = 0; i < npat; i++) {
+ int use = 0;
+
+ if (devspace == icSigGrayData) {
+ if (isAdditive) {
+ if (*((double *)icg->t[0].fdata[i][ci]) > (100.0 - 0.1))
+ use = 1;
+ } else {
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1)
+ use = 1;
+ }
+ } else if (devspace == icSigRgbData) {
+ if (*((double *)icg->t[0].fdata[i][ci]) > (100.0 - 0.1)
+ && *((double *)icg->t[0].fdata[i][mi]) > (100.0 - 0.1)
+ && *((double *)icg->t[0].fdata[i][yi]) > (100.0 - 0.1))
+ use = 1;
+ } else if (devspace == icSigCmyData) {
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1
+ && *((double *)icg->t[0].fdata[i][mi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][yi]) < 0.1)
+ use = 1;
+ } else { /* Assume CMYK */
+
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1
+ && *((double *)icg->t[0].fdata[i][mi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][yi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][ki]) < 0.1) {
+ use = 1;
+ }
+ }
+
+ if (use) {
+ /* Read the spectral values for this patch */
+ for (j = 0; j < mwsp.spec_n; j++) {
+ mwsp.spec[j] += *((double *)icg->t[0].fdata[i][spi[j]]);
+ }
+ nw++;
+ }
+ }
+ if (nw == 0.0) {
+ warning("Input file '%s' can't find a media white patch to init FWA",ti3name);
+
+ /* Track the maximum reflectance for any band to determine white. */
+ /* This might give bogus results if there is no white patch... */
+ for (i = 0; i < npat; i++) {
+ for (j = 0; j < mwsp.spec_n; j++) {
+ double rv = *((double *)icg->t[0].fdata[i][spi[j]]);
+ if (rv > mwsp.spec[j])
+ mwsp.spec[j] = rv;
+ }
+ }
+ nw++;
+ }
+
+ for (j = 0; j < mwsp.spec_n; j++)
+ mwsp.spec[j] /= nw; /* Compute average */
+
+ /* If we are setting a specific simulated instrument illuminant */
+ if (tillum != icxIT_none) {
+ tillump = &cust_tillum;
+ if (tillum != icxIT_custom) {
+ if (standardIlluminant(tillump, tillum, 0.0)) {
+ error("simulated inst. illum. not recognised");
+ }
+ }
+ }
+
+ if (sp2cie->set_fwa(sp2cie, &insp, tillump, &mwsp))
+ error ("Set FWA on sp2cie failed");
+
+ if (verb) {
+ double FWAc;
+ sp2cie->get_fwa_info(sp2cie, &FWAc);
+ fprintf(verbo,"FWA content = %f\n",FWAc);
+ }
+
+ }
+
+ for (i = 0; i < npat; i++) {
+ strcpy(tpat[i].sid, (char *)icg->t[0].fdata[i][sidx]);
+ if (sloc >= 0)
+ strcpy(tpat[i].slo, (char *)icg->t[0].fdata[i][sloc]);
+ else
+ strcpy(tpat[i].slo, "");
+ tpat[i].p[0] = *((double *)icg->t[0].fdata[i][ci]) / 100.0;
+ tpat[i].p[1] = *((double *)icg->t[0].fdata[i][mi]) / 100.0;
+ tpat[i].p[2] = *((double *)icg->t[0].fdata[i][yi]) / 100.0;
+ tpat[i].p[3] = *((double *)icg->t[0].fdata[i][ki]) / 100.0;
+ if (tpat[i].p[0] > 1.0
+ || tpat[i].p[1] > 1.0
+ || tpat[i].p[2] > 1.0
+ || tpat[i].p[3] > 1.0) {
+ error("Input file '%s' device value field value exceeds 100.0 !",ti3name);
+ }
+
+ /* Read the spectral values for this patch */
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+ }
+
+ /* Convert it to CIE space */
+ sp2cie->convert(sp2cie, tpat[i].v, &sp);
+ }
+
+ sp2cie->del(sp2cie); /* Done with this */
+ }
+ /* Normalize display values to Y = 1.0 if needed */
+ /* (re-norm spec derived, since observer may be different) */
+ if (isdisp && (isdnormed == 0 || spec != 0)) {
+ double scale = -1e6;
+ double bxyz[3];
+
+ /* Locate max Y */
+ for (i = 0; i < npat; i++) {
+ icmLab2XYZ(&icmD50, bxyz, tpat[i].v);
+ if (bxyz[1] > scale)
+ scale = bxyz[1];
+ }
+
+ scale = 1.0/scale;
+
+ /* Scale max Y to 1.0 */
+ for (i = 0; i < npat; i++) {
+ icmLab2XYZ(&icmD50, tpat[i].v, tpat[i].v);
+ tpat[i].v[0] *= scale;
+ tpat[i].v[1] *= scale;
+ tpat[i].v[2] *= scale;
+ icmXYZ2Lab(&icmD50, tpat[i].v, tpat[i].v);
+ }
+ }
+
+ icg->del(icg); /* Clean up */
+ } /* End of reading in CGATs file */
+
+ /* - - - - - - - - - - */
+ /* Check the forward profile accuracy against the data points */
+ {
+ double merr = 0.0; /* Max */
+ double aerr = 0.0; /* Avg */
+ double rerr = 0.0; /* RMS */
+ double nsamps = 0.0;
+ int inn, outn; /* Chanells for input and output spaces */
+
+ if (dovrml) {
+ wrl = start_vrml(out_name, doaxes);
+ start_line_set(wrl);
+ }
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(iccname,"r")) == NULL)
+ error("Write: Can't open file '%s'",iccname);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error("Read: %d, %s",rv,rd_icco->err);
+
+ /* Get the Fwd table, absolute with Lab override */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, intent,
+ icSigLabData, icmLuOrdNorm)) == NULL) {
+ error("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ luo->spaces(luo, NULL, &inn, NULL, &outn, NULL, NULL, NULL, NULL, NULL);
+
+ for (i = 0; i < npat; i++) {
+ double out[3];
+ double mxd;
+
+ /* Lookup the patch value in the profile */
+ if (luo->lookup(luo, out, tpat[i].p) > 1)
+ error("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (verb > 1) {
+ printf("[%f] %s%s%s: %s -> %f %f %f should be %f %f %f\n",
+ cie2k ? icmCIE2K(tpat[i].v, out) :
+ cie94 ? icmCIE94(tpat[i].v, out) : icmLabDE(tpat[i].v, out),
+ tpat[i].sid,
+ tpat[i].slo[0] != '\000' ? " @ " : "",
+ tpat[i].slo,
+ icmPdv(devchan, tpat[i].p),
+ out[0],out[1],out[2],
+ tpat[i].v[0],tpat[i].v[1],tpat[i].v[2]);
+ }
+ if (dovrml) {
+ if (dominl && icmLabDE(tpat[i].v, out) < 0.5) {
+ double cent[3], vec[3], vlen;
+ double p1[3], p2[3];
+
+ /* Compute center */
+ icmAdd3(cent, tpat[i].v, out);
+ icmScale3(cent, cent, 0.5);
+ if ((vlen = icmLabDE(tpat[i].v, out)) < 1e-6) {
+ vec[0] = 0.25; vec[1] = 0.0; vec[2] = 0.0;
+ } else {
+ icmSub3(vec, tpat[i].v, out);
+ icmScale3(vec, vec, 0.25/vlen);
+ }
+ icmSub3(p1, cent, vec);
+ icmAdd3(p2, cent, vec);
+ add_vertex(wrl, p1);
+ add_vertex(wrl, p2);
+ } else {
+ add_vertex(wrl, tpat[i].v);
+ add_vertex(wrl, out);
+ }
+ }
+
+ /* Check the result */
+ if (cie2k)
+ mxd = icmCIE2K(tpat[i].v, out);
+ else if (cie94)
+ mxd = icmCIE94(tpat[i].v, out);
+ else
+ mxd = icmLabDE(tpat[i].v, out);
+
+ aerr += mxd;
+ rerr += mxd * mxd;
+
+ nsamps++;
+ if (mxd > merr)
+ merr = mxd;
+
+ }
+ if (dovrml) {
+ if (dodecol)
+ make_de_lines(wrl);
+ else
+ make_lines(wrl, 2);
+ end_vrml(wrl);
+ }
+ printf("Profile check complete, errors%s: max. = %f, avg. = %f, RMS = %f\n",
+ cie2k ? "(CIEDE2000)" : cie94 ? " (CIE94)" : "", merr, aerr/nsamps, sqrt(rerr/nsamps));
+
+ /* ------------------------------- */
+ /* If we want sort by target value */
+ if (ddevv) {
+ double cieval[3];
+
+ /* Lookup the CIE value of the target */
+ if (luo->lookup(luo, cieval, devval) > 1)
+ error("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Compute deltas to target value. */
+ for (i = 0; i < npat; i++) {
+ if (cie2k)
+ tpat[i].dv = icmCIE2K(tpat[i].v, cieval);
+ else if (cie94)
+ tpat[i].dv = icmCIE94(tpat[i].v, cieval);
+ else
+ tpat[i].dv = icmLabDE(tpat[i].v, cieval);
+
+ tpat[i].dp = 0.0;
+ for (j = 0; j < inn; j++) {
+ double tt;
+ tt = tpat[i].p[j] - devval[j];
+ tpat[i].dp += tt * tt;
+ }
+ tpat[i].dp = sqrt(tpat[i].dp);
+ }
+
+ if (sortbypcs) {
+ /* Sort by pcs delta */
+#define HEAP_COMPARE(A,B) (A.dv < B.dv)
+ HEAPSORT(pval, tpat, npat);
+#undef HEAP_COMPARE
+ } else {
+ /* Sort by device delta */
+#define HEAP_COMPARE(A,B) (A.dp < B.dp)
+ HEAPSORT(pval, tpat, npat);
+#undef HEAP_COMPARE
+ }
+
+ printf("Target point:\n");
+ if (devspace == icSigCmykData) {
+ printf("%f %f %f %f -> %f %f %f\n",
+ devval[0],devval[1],devval[2],devval[3],
+ cieval[0],cieval[1],cieval[2]);
+ } else { /* Assume RGB/CMY */
+ printf("%f %f %f -> %f %f %f\n",
+ devval[0],devval[1],devval[2],
+ cieval[0],cieval[1],cieval[2]);
+ }
+ printf("\n");
+
+ for (i = 0; i < npat; i++) {
+ if (devspace == icSigCmykData) {
+ printf("%s: %f %f %f %f [%f] -> %f %f %f [%f]\n",
+ tpat[i].sid,
+ tpat[i].p[0],tpat[i].p[1],tpat[i].p[2],tpat[i].p[3],
+ tpat[i].dp,
+ tpat[i].v[0],tpat[i].v[1],tpat[i].v[2],
+ tpat[i].dv);
+ } else { /* Assume RGB/CMY */
+ printf("%s: %f %f %f [%f] -> %f %f %f [%f]\n",
+ tpat[i].sid,
+ tpat[i].p[0],tpat[i].p[1],tpat[i].p[2],
+ tpat[i].dp,
+ tpat[i].v[0],tpat[i].v[1],tpat[i].v[2],
+ tpat[i].dv);
+ }
+ }
+ }
+
+ /* Done with lookup object */
+ luo->del(luo);
+
+ /* Close the file */
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------ */
+/* Some simple functions to do basix VRML work */
+/* !!! Should change to plot/vrml lib !!! */
+
+#define GAMUT_LCENT 50.0
+static int npoints = 0;
+static int paloc = 0;
+static struct { double pp[3]; } *pary;
+
+static void Lab2RGB(double *out, double *in);
+static void DE2RGB(double *out, double in);
+
+FILE *start_vrml(char *name, int doaxes) {
+ FILE *wrl;
+
+ /* Define the axis boxes */
+ struct {
+ double x, y, z; /* Box center */
+ double wx, wy, wz; /* Box size */
+ double r, g, b; /* Box color */
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+
+ /* Define the labels */
+ struct {
+ double x, y, z;
+ double size;
+ char *string;
+ double r, g, b;
+ } labels[6] = {
+ { -2, 2, -GAMUT_LCENT + 100 + 10, 10, "+L*", .7, .7, .7 }, /* Top of L axis */
+ { -2, 2, -GAMUT_LCENT - 10, 10, "0", .7, .7, .7 }, /* Bottom of L axis */
+ { 100 + 5, -3, 0-GAMUT_LCENT, 10, "+a*", 1, 0, 0 }, /* +a (red) axis */
+ { -5, -100 - 10, 0-GAMUT_LCENT, 10, "-b*", 0, 0, 1 }, /* -b (blue) axis */
+ { -100 - 15, -3, 0-GAMUT_LCENT, 10, "-a*", 0, 0, 1 }, /* -a (green) axis */
+ { -5, 100 + 5, 0-GAMUT_LCENT, 10, "+b*", 1, 1, 0 }, /* +b (yellow) axis */
+ };
+
+ if ((wrl = fopen(name,"w")) == NULL)
+ error("Error opening VRML file '%s'\n",name);
+
+ npoints = 0;
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ int n;
+ fprintf(wrl," # Lab axes as boxes:\n");
+ for (n = 0; n < 5; n++) {
+ fprintf(wrl," Transform { translation %f %f %f\n", axes[n].x, axes[n].y, axes[n].z);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape{\n");
+ fprintf(wrl," geometry Box { size %f %f %f }\n",
+ axes[n].wx, axes[n].wy, axes[n].wz);
+ fprintf(wrl," appearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[n].r, axes[n].g, axes[n].b);
+ fprintf(wrl," }\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+ fprintf(wrl," # Axes identification:\n");
+ for (n = 0; n < 6; n++) {
+ fprintf(wrl," Transform { translation %f %f %f\n", labels[n].x, labels[n].y, labels[n].z);
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape{\n");
+ fprintf(wrl," geometry Text { string [\"%s\"]\n",labels[n].string);
+ fprintf(wrl," fontStyle FontStyle { family \"SANS\" style \"BOLD\" size %f }\n",
+ labels[n].size);
+ fprintf(wrl," }\n");
+ fprintf(wrl," appearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", labels[n].r, labels[n].g, labels[n].b);
+ fprintf(wrl," }\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ }
+ fprintf(wrl,"\n");
+ }
+
+ return wrl;
+}
+
+void
+start_line_set(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+}
+
+void add_vertex(FILE *wrl, double pp[3]) {
+
+ fprintf(wrl,"%f %f %f,\n",pp[1], pp[2], pp[0]-GAMUT_LCENT);
+
+ if (paloc < (npoints+1)) {
+ paloc = (paloc + 10) * 2;
+ if (pary == NULL)
+ pary = malloc(paloc * 3 * sizeof(double));
+ else
+ pary = realloc(pary, paloc * 3 * sizeof(double));
+
+ if (pary == NULL)
+ error ("Malloc failed");
+ }
+ pary[npoints].pp[0] = pp[0];
+ pary[npoints].pp[1] = pp[1];
+ pary[npoints].pp[2] = pp[2];
+ npoints++;
+}
+
+
+void make_lines(FILE *wrl, int ppset) {
+ int i, j;
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (i = 0; i < npoints;) {
+ for (j = 0; j < ppset; j++, i++) {
+ fprintf(wrl,"%d, ", i);
+ }
+ fprintf(wrl,"-1,\n");
+ }
+ fprintf(wrl," ]\n");
+
+ /* Color */
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < npoints; i++) {
+ double rgb[3], Lab[3];
+ Lab[0] = pary[i].pp[0];
+ Lab[1] = pary[i].pp[1];
+ Lab[2] = pary[i].pp[2];
+ Lab2RGB(rgb, Lab);
+ fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ /* End color */
+
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+}
+
+/* Assume 2 ppset, and make line color prop to length */
+void make_de_lines(FILE *wrl) {
+ int i, j;
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (i = 0; i < npoints;) {
+ for (j = 0; j < 2; j++, i++) {
+ fprintf(wrl,"%d, ", i);
+ }
+ fprintf(wrl,"-1,\n");
+ }
+ fprintf(wrl," ]\n");
+
+ /* Color */
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < npoints; i++) {
+ double rgb[3], ss;
+ for (ss = 0.0, j = 0; j < 3; j++) {
+ double tt = (pary[i & ~1].pp[j] - pary[i | 1].pp[j]);
+ ss += tt * tt;
+ }
+ ss = sqrt(ss);
+ DE2RGB(rgb, ss);
+ fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ /* End color */
+
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+}
+
+void end_vrml(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0)
+ error("Error closing VRML file\n");
+}
+
+
+/* Convert a gamut Lab value to an RGB value for display purposes */
+static void
+Lab2RGB(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+ double R, G, B;
+
+ /* Scale so that black is visible */
+ L = L * (100 - 40.0)/100.0 + 40.0;
+
+ /* First convert to XYZ using D50 white point */
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ x *= 0.9642; /* Multiply by white point, D50 */
+ y *= 1.0;
+ z *= 0.8249;
+
+ /* Now convert to sRGB values */
+ R = x * 3.2410 + y * -1.5374 + z * -0.4986;
+ G = x * -0.9692 + y * 1.8760 + z * 0.0416;
+ B = x * 0.0556 + y * -0.2040 + z * 1.0570;
+
+ if (R < 0.0)
+ R = 0.0;
+ else if (R > 1.0)
+ R = 1.0;
+
+ if (G < 0.0)
+ G = 0.0;
+ else if (G > 1.0)
+ G = 1.0;
+
+ if (B < 0.0)
+ B = 0.0;
+ else if (B > 1.0)
+ B = 1.0;
+
+ R = pow(R, 1.0/2.2);
+ G = pow(G, 1.0/2.2);
+ B = pow(B, 1.0/2.2);
+
+ out[0] = R;
+ out[1] = G;
+ out[2] = B;
+}
+
+/* Convert a delta E value into a signal color: */
+static void
+DE2RGB(double *out, double in) {
+ struct {
+ double de;
+ double r, g, b;
+ } range[6] = {
+ { 10.0, 1, 1, 0 }, /* yellow */
+ { 4.0, 1, 0, 0 }, /* red */
+ { 2.0, 1, 0, 1 }, /* magenta */
+ { 1.0, 0, 0, 1 }, /* blue */
+ { 0.5, 0, 1, 1 }, /* cyan */
+ { 0.0, 0, 1, 0 } /* green */
+ };
+ int i;
+ double bl;
+
+ /* Locate the range we're in */
+ if (in > range[0].de) {
+ out[0] = range[0].r;
+ out[1] = range[0].g;
+ out[2] = range[0].b;
+ } else {
+ for (i = 0; i < 5; i++) {
+ if (in <= range[i].de && in >= range[i+1].de)
+ break;
+ }
+ bl = (in - range[i+1].de)/(range[i].de - range[i+1].de);
+ out[0] = bl * range[i].r + (1.0 - bl) * range[i+1].r;
+ out[1] = bl * range[i].g + (1.0 - bl) * range[i+1].g;
+ out[2] = bl * range[i].b + (1.0 - bl) * range[i+1].b;
+ }
+}
+
+
+
diff --git a/profile/profin.c b/profile/profin.c
new file mode 100644
index 0000000..2f74ec2
--- /dev/null
+++ b/profile/profin.c
@@ -0,0 +1,1310 @@
+
+/*
+ * Argyll Color Correction System
+ * Input device profile creator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 11/10/00
+ *
+ * Copyright 2000 - 2011 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.
+ */
+
+/*
+ * This program takes in the scattered test chart
+ * points, and interpolates them into a gridded
+ * forward ICC device profile.
+ * It also creates (at the moment) a limited backward
+ * profile based on the forward grid.
+ *
+ */
+
+/*
+ * TTBD:
+ * Need to make this more of a library:
+ * ** By default limit matrix primaries to have +ve XYZ
+ * Add flag to override this.
+ * Fix error handling
+ * fix verbose output
+ * hand icc object back rather than writing file ?
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include "counters.h"
+#include "numlib.h"
+#include "icc.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "rspl.h"
+#include "prof.h"
+
+#define DOB2A /* Create B2A table as well (not implemented) */
+#define NO_B2A_PCS_CURVES /* PCS curves seem to make B2A less accurate. Why ? */
+#define USE_CAM_CLIP_OPT /* Clip out of gamut in CAM space rather than XYZ or L*a*b* */
+#undef USE_EXTRA_FITTING /* Turn on data point error compensation */
+#define USE_2ASS_SMOOTHING /* Turn on Gaussian smoothing */
+#undef WARN_CLUT_CLIPPING /* Print warning if setting clut clips */
+#define EXTRAP_MAXPNTS 10 /* Maximum number of extra extrapolated points per direction */
+#define EXTRAP_WEIGHT 1.0 /* Extra extrapolated point weighting */
+
+/*
+ Basic algorithm outline:
+
+ Scanner:
+
+ Figure out the input curves to give
+ the flattest grid.
+
+ Figure out the grid values.
+
+ Use them to generate the A2B table.
+
+ Do all the calculations in Lab space,
+ but represent the profile in XYZ space, so that
+ the white/black point normalisation doesn't cause
+ the clut values to be clipped.
+
+ This leads to a poorer accuracy as an XYZ profile,
+ but can then be compensated for using the ICX_MERGE_CLUT flag
+ together with a PCS override.
+
+ Note we're hard coded as RGB device space, so we're not coping
+ with grey scale or CMY.
+*/
+
+#ifdef DEBUG
+#undef DBG
+#define DBG(xxx) printf xxx ;
+#else
+#undef DBG
+#define DBG(xxx)
+#endif
+
+/* ---------------------------------------- */
+#ifdef DOB2A
+
+/* structure to support output icc B2A Lut initialisation calbacks */
+/* Note that we don't cope with a LUT matrix - assume it's unity. */
+
+typedef struct {
+ int verb;
+ int total, count, last; /* Progress count information */
+ int noPCScurves; /* Flag set if we don't want PCS curves */
+ icColorSpaceSignature pcsspace; /* The PCS colorspace */
+ icColorSpaceSignature devspace; /* The device colorspace */
+ icxLuLut *x; /* A2B icxLuLut we are inverting in std PCS */
+
+ double swxyz[3]; /* Source white point in XYZ */
+
+ int wantLab; /* 0 if want is XYZ PCS, 1 want is Lab PCS */
+} in_b2a_callback;
+
+
+/* --------------------------------------------------------- */
+
+/* Extra non-linearity applied to BtoA XYZ PCS */
+/* This distributes the LUT indexes more evenly in */
+/* perceptual space, greatly improving the B2A accuracy of XYZ LUT */
+static void xyzcurve(double *out, double *in) {
+ int i;
+ double sc = 65535.0/32768.0;
+
+ /* Use an L* like curve, scaled to the maximum XYZ valu */
+ out[0] = in[0]/sc;
+ out[1] = in[1]/sc;
+ out[2] = in[2]/sc;
+ for (i = 0; i < 3; i++) {
+ if (out[i] > 0.08)
+ out[i] = pow((out[i] + 0.16)/1.16, 3.0);
+ else
+ out[i] = out[i]/9.032962896;
+ }
+ out[0] = out[0] * sc;
+ out[1] = out[1] * sc;
+ out[2] = out[2] * sc;
+}
+
+static void invxyzcurve(double *out, double *in) {
+ int i;
+ double sc = 65535.0/32768.0;
+
+ out[0] = in[0]/sc;
+ out[1] = in[1]/sc;
+ out[2] = in[2]/sc;
+ for (i = 0; i < 3; i++) {
+ if (out[i] > 0.008856451586)
+ out[i] = 1.16 * pow(out[i],1.0/3.0) - 0.16;
+ else
+ out[i] = 9.032962896 * out[i];
+ }
+ out[0] = out[0] * sc;
+ out[1] = out[1] * sc;
+ out[2] = out[2] * sc;
+}
+
+/* --------------------------------------------------------- */
+/* NOTE :- the assumption that each stage of the BtoA is a mirror */
+/* of the AtoB makes for inflexibility. */
+/* Perhaps it would be better to remove this asumption from the */
+/* in_b2a_clut processing ? */
+/* To do this we then need inv_in_b2a_input(), and */
+/* inv_in_b2a_output(), and we need to clearly distinguish between */
+/* AtoB PCS' & DEV', and BtoA PCS' & DEV', since they are not */
+/* necessarily the same... */
+
+
+/* B2A Input table is the inverse of the AtoB output table */
+/* Input PCS output PCS'' */
+void in_b2a_input(void *cntx, double out[3], double in[3]) {
+ in_b2a_callback *p = (in_b2a_callback *)cntx;
+
+ DBG(("out_b2a_input got PCS %f %f %f\n",in[0],in[1],in[2]))
+
+ /* PCS to PCS' */
+ if (p->noPCScurves) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ } else {
+ if (p->x->inv_output(p->x, out, in) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+ }
+ /* PCS' to PCS'' */
+ if (p->pcsspace == icSigXYZData) /* Apply XYZ non-linearity curve */
+ invxyzcurve(out, out);
+
+ DBG(("in_b2a_input returning PCS'' %f %f %f\n",out[0],out[1],out[2]))
+}
+
+/* clut - multitable */
+/* Input PCS' output Dev' */
+/* We're applying any abstract profile after gamut mapping, */
+/* on the assumption is is primarily being used to "correct" the */
+/* output device. Ideally the gamut mapping should take the change */
+/* the abstract profile has on the output device into account, but */
+/* currently we're not doing this.. */
+void in_b2a_clut(void *cntx, double *out, double in[3]) {
+ in_b2a_callback *p = (in_b2a_callback *)cntx;
+ double in1[3];
+
+ in1[0] = in[0]; /* in[] may be aliased with out[] */
+ in1[1] = in[1]; /* so take a copy. */
+ in1[2] = in[2];
+
+ DBG(("in_b2a_clut got PCS' %f %f %f\n",in[0],in[1],in[2]))
+
+ if (p->pcsspace == icSigXYZData) /* Undo effects of extra XYZ non-linearity curve */
+ xyzcurve(in1, in1);
+
+ if (p->noPCScurves) { /* We were given PCS or have converted to PCS */
+
+ /* PCS to PCS' */
+ if (p->x->inv_output(p->x, in1, in1) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+
+ DBG(("convert to PCS' got %f %f %f\n",in1[0],in1[1],in1[2]))
+ }
+
+ /* Invert AtoB clut (PCS' to Dev') Colorimetric */
+ /* to producte the colorimetric tables output. */
+ if (p->x->inv_clut(p->x, out, in1) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+
+ DBG(("convert PCS' to DEV' got %f %f %f %f\n",out[0],out[1],out[2],out[3]))
+ DBG(("in_b2a_clut returning DEV' %f %f %f\n",out[0],out[1],out[2]))
+
+ if (p->verb) { /* Output percent intervals */
+ int pc;
+ p->count++;
+ pc = (int)(p->count * 100.0/p->total + 0.5);
+ if (pc != p->last) {
+ printf("%c%2d%%",cr_char,pc); fflush(stdout);
+ p->last = pc;
+ }
+ }
+}
+
+/* Output table is the inverse of the AtoB input table */
+/* Input Dev' output Dev */
+void in_b2a_output(void *cntx, double out[4], double in[4]) {
+ in_b2a_callback *p = (in_b2a_callback *)cntx;
+
+ DBG(("in_b2a_output got DEV' %f %f %f\n",in[0],in[1],in[2]))
+
+ if (p->x->inv_input(p->x, out, in) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+
+ DBG(("in_b2a_output returning DEV %f %f %f\n",out[0],out[1],out[2]))
+}
+
+#endif /* DOB2A */
+/* ---------------------------------------- */
+
+/* Make an input device profile, where we create an A2B lut */
+/* directly from the scattered input data. */
+void
+make_input_icc(
+ prof_atype ptype, /* Profile algorithm type */
+ icmICCVersion iccver, /* ICC profile version to create */
+ int verb,
+ int iquality, /* A2B table quality, 0..3 */
+ int oquality, /* B2A table quality, 0..3 */
+ int noisluts, /* nz to supress creation of input (Device) shaper luts */
+ int noipluts, /* nz to supress creation of input (Device) position luts */
+ int nooluts, /* nz to supress creation of output (PCS) shaper luts */
+ int nocied, /* nz to supress inclusion of .ti3 data in profile */
+ int verify,
+ int autowpsc, /* nz for Auto scale the WP to prevent clipping above WP patch */
+ int clipovwp, /* nz for Clip cLUT values above WP */
+ double wpscale, /* >= 0.0 for media white point scale factor */
+ int dob2a, /* nz to create a B2A table as well */
+ int extrap, /* nz to create extra cLUT interpolation points */
+ int clipprims, /* Clip white, black and primaries */
+ char *in_name, /* input .ti3 file name */
+ char *file_name, /* output icc name */
+ cgats *icg, /* input cgats structure */
+ int spec, /* Use spectral data flag */
+ icxIllumeType illum, /* Spectral illuminant */
+ xspect *cust_illum, /* Possible custom illumination */
+ icxObserverType observ, /* Spectral observer */
+ double smooth, /* RSPL smoothing factor, -ve if raw */
+ double avgdev, /* reading Average Deviation as a proportion of the input range */
+ profxinf *xpi /* Optional Profile creation extra data */
+) {
+ icmFile *wr_fp;
+ icc *wr_icco;
+ int npat; /* Number of patches */
+ int npxpat = 0; /* Number of possible extrap extrapolation patches */
+ int nxpat = 0; /* Number of extrap extrapolation patches */
+ cow *tpat; /* Patch input values */
+ int i, rv = 0;
+ int isLab = 0; /* 0 if input is XYZ, 1 if input is Lab */
+ int wantLab = 0; /* 0 if want is XYZ, 1 want is Lab. */
+ /* Values will be wantLab after reading */
+ int isLut = 0; /* 0 if shaper+ matrix, 1 if lut type */
+ int isShTRC = 0; /* 0 if separate gamma/shaper TRC, 1 if shared */
+
+ if (ptype == prof_clutLab) { /* Lab lut */
+ wantLab = 1;
+ isLut = 1;
+ } else if (ptype == prof_clutXYZ) { /* XYZ lut */
+ wantLab = 0;
+ isLut = 1;
+ } else {
+ wantLab = 0; /* gamma/shaper + matrix profile must be XYZ */
+ isLut = 0;
+ extrap = 0;
+
+ if (ptype == prof_gam1mat
+ || ptype == prof_sha1mat
+ || ptype == prof_matonly) {
+ isShTRC = 1; /* Single curve */
+ }
+ }
+
+ /* Open up the file for writing */
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigInputClass;
+ wh->colorSpace = icSigRgbData; /* It's an RGB profile */
+ if (wantLab)
+ wh->pcs = icSigLabData;
+ else
+ wh->pcs = icSigXYZData;
+
+ if (xpi->default_ri != icMaxEnumIntent)
+ wh->renderingIntent = xpi->default_ri;
+ else
+ wh->renderingIntent = icRelativeColorimetric;
+
+ /* Values that should be set before writing */
+ if (xpi != NULL && xpi->manufacturer != 0L)
+ wh->manufacturer = xpi->manufacturer;
+ else
+ wh->manufacturer = icmSigUnknownType;
+
+ if (xpi != NULL && xpi->model != 0L)
+ wh->model = xpi->model;
+ else
+ wh->model = icmSigUnknownType;
+
+ /* Values that may be set before writing */
+ if (xpi != NULL && xpi->creator != 0L)
+ wh->creator = xpi->creator;
+#ifdef NT
+ wh->platform = icSigMicrosoft;
+#endif
+#ifdef __APPLE__
+ wh->platform = icSigMacintosh;
+#endif
+#if defined(UNIX) && !defined(__APPLE__)
+ wh->platform = icmSig_nix;
+#endif
+
+ if (xpi != NULL && xpi->transparency)
+ wh->attributes.l |= icTransparency;
+ if (xpi != NULL && xpi->matte)
+ wh->attributes.l |= icMatte;
+ if (xpi != NULL && xpi->negative)
+ wh->attributes.l |= icNegative;
+ if (xpi != NULL && xpi->blackandwhite)
+ wh->attributes.l |= icBlackAndWhite;
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst; /* description */
+
+ if (xpi != NULL && xpi->profDesc != NULL)
+ dst = xpi->profDesc;
+ else {
+ dst = "This is a Lut style RGB - XYZ Input Profile";
+ }
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt;
+
+ if (xpi != NULL && xpi->copyright != NULL)
+ crt = xpi->copyright;
+ else
+ crt = "Copyright, the creator of this profile";
+
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* Device Manufacturers Description Tag: */
+ if (xpi != NULL && xpi->deviceMfgDesc != NULL) {
+ icmTextDescription *wo;
+ char *dst = xpi->deviceMfgDesc;
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigDeviceMfgDescTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Model Description Tag: */
+ if (xpi != NULL && xpi->modelDesc != NULL) {
+ icmTextDescription *wo;
+ char *dst = xpi->modelDesc;
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigDeviceModelDescTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.9642; /* Set a default value - D50 */
+ wo->data[0].Y = 1.0000;
+ wo->data[0].Z = 0.8249;
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.00; /* Set default perfect black */
+ wo->data[0].Y = 0.00;
+ wo->data[0].Z = 0.00;
+ }
+
+ if (isLut == 0) { /* shaper + matrix type */
+
+ /* Red, Green and Blue Colorant Tags: */
+ {
+ icmXYZArray *wor, *wog, *wob;
+ if ((wor = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigRedColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wog = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigGreenColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigBlueColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wor->size = wog->size = wob->size = 1;
+ wor->allocate((icmBase *)wor); /* Allocate space */
+ wog->allocate((icmBase *)wog);
+ wob->allocate((icmBase *)wob);
+
+ /* Setup some sane dummy values */
+ /* icxMatrix will override these later */
+ 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;
+ }
+
+ /* Red, Green and Blue Tone Reproduction Curve Tags: */
+ {
+ icmCurve *wor, *wog, *wob;
+ if ((wor = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigRedTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ if (isShTRC) { /* Make all TRCs shared */
+ if ((wog = (icmCurve *)wr_icco->link_tag(
+ wr_icco, icSigGreenTRCTag, icSigRedTRCTag)) == NULL)
+ error("link_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmCurve *)wr_icco->link_tag(
+ wr_icco, icSigBlueTRCTag, icSigRedTRCTag)) == NULL)
+ error("link_tag failed: %d, %s",rv,wr_icco->err);
+
+ } else { /* Else individual */
+ if ((wog = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigGreenTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigBlueTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ }
+
+ if (ptype == prof_shamat || ptype == prof_sha1mat) { /* Shaper */
+ wor->flag = wog->flag = wob->flag = icmCurveSpec;
+ wor->size = wog->size = wob->size = 256; /* Number of entries */
+ } else { /* Gamma */
+ wor->flag = wog->flag = wob->flag = icmCurveGamma;
+ wor->size = wog->size = wob->size = 1; /* Must be 1 for gamma */
+ }
+ wor->allocate((icmBase *)wor); /* Allocate space */
+ wog->allocate((icmBase *)wog);
+ wob->allocate((icmBase *)wob);
+
+ /* icxMatrix will set curve values */
+ }
+
+ } else { /* Lut type profile */
+
+ /* 16 bit dev -> pcs lut: */
+ {
+ icmLut *wo;
+
+ /* Only A2B0, no intent */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigAToB0Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ if (iquality >= 3) {
+ wo->clutPoints = 45;
+ wo->inputEnt = 2048;
+ wo->outputEnt = 2048;
+ } else if (iquality == 2) {
+ wo->clutPoints = 33;
+ wo->inputEnt = 2048;
+ wo->outputEnt = 2048;
+ } else if (iquality == 1) {
+ wo->clutPoints = 17;
+ wo->inputEnt = 1024;
+ wo->outputEnt = 1024;
+ } else {
+ wo->clutPoints = 9;
+ wo->inputEnt = 512;
+ wo->outputEnt = 512;
+ }
+
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* icxLuLut will set tables values */
+ }
+
+#ifdef DOB2A
+ /* 16 bit pcs -> dev lut: */
+ if (dob2a) {
+ icmLut *wo;
+
+ /* Only B2A0, no intent */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigBToA0Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ if (oquality >= 3) {
+ wo->clutPoints = 45;
+ wo->inputEnt = 2048;
+ wo->outputEnt = 2048;
+ } else if (oquality == 2) {
+ wo->clutPoints = 33;
+ wo->inputEnt = 2048;
+ wo->outputEnt = 2048;
+ } else if (oquality == 1) {
+ wo->clutPoints = 17;
+ wo->inputEnt = 1024;
+ wo->outputEnt = 1024;
+ } else if (oquality >= 0) {
+ wo->clutPoints = 9;
+ wo->inputEnt = 512;
+ wo->outputEnt = 512;
+ } else { /* Special, Extremely low quality */
+ wo->clutPoints = 3;
+ wo->inputEnt = 64;
+ wo->outputEnt = 64;
+ }
+
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* We set the tables below */
+ }
+#endif /* DOB2A */
+
+ }
+
+ /* Sample data use to create profile: */
+ if (nocied == 0) {
+ icmText *wo;
+ char *crt;
+ FILE *fp;
+
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icmMakeTag('t','a','r','g'), icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(in_name, "rb")) == NULL)
+#else
+ if ((fp = fopen(in_name, "r")) == NULL)
+#endif
+ error("Unable to open input file '%s' for reading",in_name);
+
+ if (fseek(fp, 0, SEEK_END))
+ error("Unable to seek to end of file '%s'",in_name);
+ wo->size = ftell(fp) + 1; /* Size needed + null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ if (fseek(fp, 0, SEEK_SET))
+ error("Unable to seek to end of file '%s'",in_name);
+
+ if (fread(wo->data, 1, wo->size-1, fp) != wo->size-1)
+ error("Failed to read file '%s'",in_name);
+ wo->data[wo->size-1] = '\000';
+ fclose(fp);
+
+ /* Duplicate for compatibility */
+ if (wr_icco->link_tag(
+ wr_icco, icmMakeTag('D','e','v','D'), icmMakeTag('t','a','r','g')) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ if (wr_icco->link_tag(
+ wr_icco, icmMakeTag('C','I','E','D'), icmMakeTag('t','a','r','g')) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ if (verb) {
+ fprintf(verbo,"No of test patches = %d\n",npat);
+ }
+
+ if (extrap) {
+ npxpat = 4 * EXTRAP_MAXPNTS; /* Allow for up to 20 extra patches */
+ }
+
+ /* Allocate arrays to hold test patch input and output values */
+ if ((tpat = (cow *)malloc(sizeof(cow) * (npat + npxpat))) == NULL)
+ error("Malloc failed - tpat[]");
+
+ /* Read in the CGATs fields */
+ {
+ int ti;
+ int Xi, Yi, Zi;
+ int ri, gi, bi;
+
+ /* Check that we handle the color space */
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error ("Input file doesn't contain keyword COLOR_REPS");
+ if (strcmp(icg->t[0].kdata[ti],"LAB_RGB") == 0) {
+ isLab = 1;
+ } else {
+ if (strcmp(icg->t[0].kdata[ti],"XYZ_RGB") == 0) {
+ isLab = 0;
+ } else {
+ error ("Input device input file has unhandled color representation");
+ }
+ }
+
+ if ((ri = icg->find_field(icg, 0, "RGB_R")) < 0)
+ error ("Input file doesn't contain field RGB_R");
+ if (icg->t[0].ftype[ri] != r_t)
+ error ("Field CMYK_C is wrong type - corrupted file ?");
+ if ((gi = icg->find_field(icg, 0, "RGB_G")) < 0)
+ error ("Input file doesn't contain field RGB_G");
+ if (icg->t[0].ftype[gi] != r_t)
+ error ("Field CMYK_M is wrong type - corrupted file ?");
+ if ((bi = icg->find_field(icg, 0, "RGB_B")) < 0)
+ error ("Input file doesn't contain field RGB_B");
+ if (icg->t[0].ftype[bi] != r_t)
+ error ("Field CMYK_Y is wrong type - corrupted file ?");
+
+ if (spec == 0) { /* Using instrument tristimulous value */
+
+ if (isLab) {
+ if ((Xi = icg->find_field(icg, 0, "LAB_L")) < 0)
+ error ("Input file doesn't contain field LAB_L");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error ("Field LAB_L is wrong type - corrupted file ?");
+ if ((Yi = icg->find_field(icg, 0, "LAB_A")) < 0)
+ error ("Input file doesn't contain field LAB_A");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error ("Field LAB_A is wrong type - corrupted file ?");
+ if ((Zi = icg->find_field(icg, 0, "LAB_B")) < 0)
+ error ("Input file doesn't contain field LAB_B");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error ("Field LAB_B is wrong type - corrupted file ?");
+ } else {
+ if ((Xi = icg->find_field(icg, 0, "XYZ_X")) < 0)
+ error ("Input file doesn't contain field XYZ_X");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error ("Field XYZ_X is wrong type - corrupted file ?");
+ if ((Yi = icg->find_field(icg, 0, "XYZ_Y")) < 0)
+ error ("Input file doesn't contain field XYZ_Y");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error ("Field XYZ_Y is wrong type - corrupted file ?");
+ if ((Zi = icg->find_field(icg, 0, "XYZ_Z")) < 0)
+ error ("Input file doesn't contain field XYZ_Z");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error ("Field XYZ_Z is wrong type - corrupted file ?");
+ }
+
+ for (i = 0; i < npat; i++) {
+ tpat[i].w = 1.0;
+ tpat[i].p[0] = *((double *)icg->t[0].fdata[i][ri]) / 100.0;
+ tpat[i].p[1] = *((double *)icg->t[0].fdata[i][gi]) / 100.0;
+ tpat[i].p[2] = *((double *)icg->t[0].fdata[i][bi]) / 100.0;
+ if (tpat[i].p[0] > 1.0
+ || tpat[i].p[1] > 1.0
+ || tpat[i].p[2] > 1.0) {
+ error("At %d device values %f %f %f field exceeds 100.0!",i,100.0 * tpat[i].p[0],100.0 * tpat[i].p[1],100.0 * tpat[i].p[2]);
+ }
+ tpat[i].v[0] = *((double *)icg->t[0].fdata[i][Xi]);
+ tpat[i].v[1] = *((double *)icg->t[0].fdata[i][Yi]);
+ tpat[i].v[2] = *((double *)icg->t[0].fdata[i][Zi]);
+ if (!isLab) {
+ tpat[i].v[0] /= 100.0; /* Normalise XYZ to range 0.0 - 1.0 */
+ tpat[i].v[1] /= 100.0;
+ tpat[i].v[2] /= 100.0;
+ }
+ if (!isLab && wantLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
+ icmXYZ2Lab(&icmD50, tpat[i].v, tpat[i].v);
+ } else if (isLab && !wantLab) {
+ icmLab2XYZ(&icmD50, tpat[i].v, tpat[i].v);
+ }
+ }
+
+ } else { /* Using spectral data */
+ int j, ii;
+ xspect sp;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xsp2cie *sp2cie; /* Spectral conversion object */
+
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ sp.spec_n = atoi(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ sp.spec_wl_short = atof(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ sp.spec_wl_long = atof(icg->t[0].kdata[ii]);
+ sp.norm = 100.0;
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = icg->find_field(icg, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",buf);
+ }
+
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie(illum, cust_illum, observ, NULL,
+ wantLab ? icSigLabData : icSigXYZData, icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+
+ for (i = 0; i < npat; i++) {
+ tpat[i].w = 1.0;
+ tpat[i].p[0] = *((double *)icg->t[0].fdata[i][ri]) / 100.0;
+ tpat[i].p[1] = *((double *)icg->t[0].fdata[i][gi]) / 100.0;
+ tpat[i].p[2] = *((double *)icg->t[0].fdata[i][bi]) / 100.0;
+ if (tpat[i].p[0] > 1.0
+ || tpat[i].p[1] > 1.0
+ || tpat[i].p[2] > 1.0) {
+ error("Device value field exceeds 100.0!");
+ }
+
+ /* Read the spectral values for this patch */
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+ }
+
+ /* Convert it to CIE space */
+ sp2cie->convert(sp2cie, tpat[i].v, &sp);
+ }
+
+ sp2cie->del(sp2cie); /* Done with this */
+
+ }
+ } /* End of reading in CGATs file */
+
+ if (isLut == 0) { /* Gamma/Shaper + matrix profile */
+ xicc *wr_xicc; /* extention object */
+ icxLuBase *xluo; /* Forward ixcLu */
+ int flags = 0;
+
+ /* Wrap with an expanded icc */
+ if ((wr_xicc = new_xicc(wr_icco)) == NULL)
+ error("Creation of xicc failed");
+
+ if (verb)
+ flags |= ICX_VERBOSE;
+
+ if (ptype == prof_matonly)
+ flags |= ICX_NO_IN_SHP_LUTS; /* Make it linear */
+
+ if (clipprims)
+ flags |= ICX_CLIP_WB | ICX_CLIP_PRIMS;
+
+ flags |= ICX_SET_BLACK; /* Compute & use black */
+ flags |= ICX_SET_WHITE; /* Compute & use white */
+ if (autowpsc)
+ flags |= ICX_SET_WHITE_US; /* Compute & use white without scaling to L */
+
+ flags |= ICX_WRITE_WBL; /* Matrix: write white/black/luminence */
+
+ /* Setup Device -> XYZ conversion (Fwd) object from scattered data. */
+ if ((xluo = wr_xicc->set_luobj(
+// wr_xicc, icmFwd, icRelativeColorimetric,
+ wr_xicc, icmFwd, icmDefaultIntent,
+ icmLuOrdNorm,
+ flags, /* Flags */
+ npat, npat, tpat, NULL, 0.0, wpscale, smooth, avgdev,
+ NULL, NULL, NULL, iquality)) == NULL)
+ error("%d, %s",wr_xicc->errc, wr_xicc->err);
+
+ /* Free up xicc stuff */
+ xluo->del(xluo);
+ wr_xicc->del(wr_xicc);
+
+ } else { /* cLUT based profile */
+ int flags = 0;
+ icxMatrixModel *mm = NULL;
+
+ xicc *wr_xicc; /* extention object */
+ icxLuBase *AtoB; /* AtoB ixcLu */
+
+ if (extrap) {
+ cow *mpat;
+ int nmpat;
+ int j;
+
+ if (verb) printf("Creating extrapolation black and white points:\n");
+
+ if ((mpat = (cow *)malloc(sizeof(cow) * npat)) == NULL)
+ error("Malloc failed - mpat[]");
+
+ /* Weight points from full set to build matrix model */
+ /* to extrapolate the neutral axis */
+ for (nmpat = j = 0; j < npat; j++) {
+ double mnp, mxp;
+ int k;
+
+ icmCpy3(mpat[nmpat].p, tpat[j].p);
+ icmCpy3(mpat[nmpat].v, tpat[j].v);
+
+ /* Locate largest/smallest RGB value */
+ mxp = -1e6, mnp = 1e6;
+ for (k = 0; k < 3; k++) {
+ if (tpat[j].p[k] > mxp)
+ mxp = tpat[j].p[k];
+ if (tpat[j].p[k] < mnp)
+ mnp = tpat[j].p[k];
+ }
+ mxp -= mnp; /* Spread; 0 for R=G=B */
+
+ mpat[nmpat].w = pow(1.1 - mxp, 2.0);
+//printf("~1 added value %d: %f %f %f -> %f %f %f wt %f\n",j, mpat[nmpat].p[0], mpat[nmpat].p[1], mpat[nmpat].p[2], mpat[nmpat].v[0], mpat[nmpat].v[1], mpat[nmpat].v[2],mpat[nmpat].w);
+ nmpat++;
+ }
+
+ /* Create gamma/matrix model to extrapolate with. */
+ /* (Use ofset & gain, gamma curve as 0th order with 1 harmonic, */
+ /* and smooth it.) */
+ if ((mm = new_MatrixModel(verb, nmpat, mpat, wantLab,
+ /* quality */ -1, /* isLinear */ ptype == prof_matonly,
+ /* isGamma */ 0, /* isShTRC */ 0,
+ /* shape0gam */ 1, /* clipbw */ 0, /* clipprims */ 0,
+// /* smooth */ 1.0, /* scale */ 0.7)) == NULL) {
+ /* smooth */ 1.0, /* scale */ 1.0)) == NULL) {
+ error("Creating extrapolation matrix model failed - memory ?");
+ }
+
+#ifdef NEVER /* Plot Lab of model */
+{
+ #define XRES 100
+ double xx[XRES];
+ double y0[XRES];
+ double y1[XRES];
+ double y2[XRES];
+
+ /* Display the result fit */
+ for (i = 0; i < XRES; i++) {
+ double rgb[3], lab[3];
+ xx[i] = rgb[0] = rgb[1] = rgb[2] = i/(double)(XRES-1);
+ mm->lookup(mm, lab, rgb);
+ if (wantLab)
+ icmLab2XYZ(&icmD50,lab,lab);
+ y0[i] = lab[0];
+ y1[i] = lab[1];
+ y2[i] = lab[2];
+ }
+ do_plot(xx,y0,y1,y2,XRES);
+}
+#endif /* DEBUG_PLOT */
+ }
+
+ if (extrap) {
+ int ii, wix = 0, j;
+ int pcsy; /* Effective PCS L or Y chanel index */
+ double wpy = -1e60;
+ double dwhite[MXDI]; /* Device white */
+ double mxdw;
+ double avgdist; /* Average distance between points */
+
+ /* Figure out the device white point. */
+ /* Note that this is duplicating code in xicc/xmatrix.c */
+ /* and xfit.c */
+
+ if (wantLab)
+ pcsy = 0; /* L or Lab */
+ else
+ pcsy = 1; /* Y of XYZ */
+
+ for (i = 0; i < npat; i++) {
+ double labv[3], yv;
+
+ /* Create D50 Lab to allow some chromatic sensitivity */
+ /* in picking the white point */
+ if (wantLab)
+ icmCpy3(labv, tpat[i].v);
+ else
+ icmXYZ2Lab(&icmD50, labv, tpat[i].v);
+
+ /* Tilt things towards D50 neutral white patches */
+ yv = labv[0] - 0.3 * sqrt(labv[1] * labv[1] + labv[2] * labv[2]);
+ if (yv > wpy) {
+ for (j = 0; j < 3; j++)
+ dwhite[j] = tpat[i].p[j];
+ wpy = yv;
+ wix = i;
+ }
+ }
+
+ /* Fix extrapolation matrix to be perfect at white point */
+ mm->force(mm, tpat[wix].v, tpat[wix].p);
+
+ /* Scale the white point to make one dev value 1.0 */
+ mxdw = -1;
+ for (j = 0; j < 3; j++) {
+ if (dwhite[j] > mxdw)
+ mxdw = dwhite[j];
+ }
+ for (j = 0; j < 3; j++) {
+ dwhite[j] /= mxdw;
+ }
+
+ avgdist = pow(1.0/(double)npat, 1.0/3.0);
+ if (avgdist < 0.001)
+ avgdist = 0.001;
+ else if (avgdist > 0.3)
+ avgdist = 0.3;
+//printf("~1 avgdist = %f\n",avgdist);
+
+ /* For points with white point device ratio, */
+ /* and points with R=G=B ratio, create extrapolation points. */
+ for (ii = 0; ii < 2; ii++) {
+
+ if (ii > 1)
+ dwhite[0] = dwhite[1] = dwhite[2] = 1.0;
+
+ /* Create a series of black and white patch */
+ for (i = 0; i < 2; i++) {
+ int cix; /* Closest point index */
+ int eix; /* End point index */
+ double cde = 1e60; /* Closest point distance */
+ double tt;
+ double corr[3], cwt; /* Correction */
+
+ eix = npat + nxpat;
+
+ icmScale3(tpat[eix].p, dwhite, (double)i);
+
+ /* Locate closest point */
+ for (j = 0; j < npat; j++) {
+ double mnp, mxp;
+ int k;
+
+ /* Locate largest/smallest RGB value */
+ mxp = -1e6, mnp = 1e6;
+ for (k = 0; k < 3; k++) {
+ if (tpat[j].p[k] > mxp)
+ mxp = tpat[j].p[k];
+ if (tpat[j].p[k] < mnp)
+ mnp = tpat[j].p[k];
+ }
+ mxp -= mnp; /* Spread; 0 for R=G=B */
+
+ tt = icmNorm33(tpat[eix].p, tpat[j].p);
+ tt += mxp;
+
+ if (tt < cde) {
+ cde = tt;
+ cix = j;
+ }
+ }
+
+//printf("~1 closest %d: de %f, %f %f %f -> %f %f %f\n",cix, cde, tpat[cix].p[0], tpat[cix].p[1], tpat[cix].p[2], tpat[cix].v[0], tpat[cix].v[1], tpat[cix].v[2]);
+
+//{
+//double val[3];
+//mm->lookup(mm, val, tpat[cix].p);
+//printf("~1 closest gam/matrix -> %f %f %f\n",val[0],val[1],val[2]);
+//}
+
+ /* Lookup matrix value for our new point */
+ mm->lookup(mm, tpat[eix].v, tpat[eix].p);
+//printf("~1 got value %d: %f %f %f -> %f %f %f\n",i, tpat[eix].p[0], tpat[eix].p[1], tpat[eix].p[2], tpat[eix].v[0], tpat[eix].v[1], tpat[eix].v[2]);
+ /* Weight the extra point so that it doesn't overpower the */
+ /* nearest real point to it too much. */
+ tt = cde;
+ if (tt > avgdist) /* Distance at which sythetic point has 100% weight */
+ tt = avgdist;
+ tpat[eix].w = 0.5 * EXTRAP_WEIGHT * tt/avgdist;
+//printf("~1 weight %f\n",tpat[eix].w);
+ if (verb)
+ printf("Added synthetic point @ %f %f %f, val %f %f %f, weight %f\n",tpat[eix].p[0], tpat[eix].p[1], tpat[eix].p[2], tpat[eix].v[0], tpat[eix].v[1], tpat[eix].v[2],tpat[eix].w);
+ nxpat++;
+
+ /* If there is a lot of space, add a second intemediate point */
+//printf("~1 cde = %f, avgdist = %f\n",cde,avgdist);
+ if (cde >= (0.5 * avgdist)) {
+ int nxps; /* Number of extra points including end point */
+ nxps = 1 + (int)(cde/(0.5 * avgdist));
+ if (nxps > EXTRAP_MAXPNTS)
+ nxps = EXTRAP_MAXPNTS;
+
+//printf("~1 nxps = %d\n",nxps);
+ for (j = 1; j < nxps; j++) {
+ double bl, ipos;
+
+ bl = j/(nxps + 1.0);
+
+ ipos = (1.0 - bl) * tpat[eix].p[0]
+ + bl * (tpat[cix].p[0] + tpat[cix].p[1] + tpat[cix].p[1])/3.0;
+ icmScale3(tpat[npat + nxpat].p, dwhite, ipos);
+
+ /* Lookup matrix value for our new point */
+ mm->lookup(mm, tpat[npat + nxpat].v, tpat[npat + nxpat].p);
+
+ /* Weight the extra point so that it doesn't overpower the */
+ /* nearest real point to it too much. */
+ cde = icmNorm33(tpat[cix].p, tpat[npat + nxpat].p);
+
+ if (cde > avgdist) /* Distance at which sythetic point has 100% weight */
+ cde = avgdist;
+ tpat[npat + nxpat].w = 0.5 * EXTRAP_WEIGHT * cde/avgdist;
+ if (verb)
+ printf("Added synthetic point @ %f %f %f, val %f %f %f, weight %f\n",tpat[npat + nxpat].p[0], tpat[npat + nxpat].p[1], tpat[npat + nxpat].p[2], tpat[npat + nxpat].v[0], tpat[npat + nxpat].v[1], tpat[npat + nxpat].v[2],tpat[npat + nxpat].w);
+ nxpat++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Wrap with an expanded icc */
+ if ((wr_xicc = new_xicc(wr_icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ flags |= ICX_CLIP_NEAREST; /* This will avoid clip caused rev setup */
+
+ if (noisluts)
+ flags |= ICX_NO_IN_SHP_LUTS;
+
+ if (noipluts)
+ flags |= ICX_NO_IN_POS_LUTS;
+
+ if (nooluts)
+ flags |= ICX_NO_OUT_LUTS;
+
+ if (verb)
+ flags |= ICX_VERBOSE;
+
+ if (clipprims)
+ flags |= ICX_CLIP_WB;
+
+ flags |= ICX_SET_BLACK; /* Compute & use black */
+ flags |= ICX_SET_WHITE; /* Compute & use white */
+ if (clipovwp)
+ flags |= ICX_SET_WHITE_C; /* Compute & use white and clip cLUT over D50 */
+ else if (autowpsc)
+ flags |= ICX_SET_WHITE_US; /* Compute & use white without scaling to L */
+
+ /* Setup RGB -> Lab conversion object from scattered data. */
+ /* Note that we've layered it on a native XYZ icc profile. */
+ /* (The skeleton model is not used - it doesn't seem to help) */
+ if ((AtoB = wr_xicc->set_luobj(
+ wr_xicc, icmFwd, icmDefaultIntent,
+ icmLuOrdNorm,
+#ifdef USE_EXTRA_FITTING
+ ICX_EXTRA_FIT |
+#endif
+#ifdef USE_2PASSSMTH
+ ICX_2PASSSMTH |
+#endif
+ flags, /* Flags */
+ npat + nxpat, npat, tpat, NULL, 0.0, wpscale, smooth, avgdev,
+ NULL, NULL, NULL, iquality)) == NULL)
+ error ("%d, %s",wr_xicc->errc, wr_xicc->err);
+
+ if (mm != NULL)
+ mm->del(mm);
+
+ /* Free up xicc stuff */
+ AtoB->del(AtoB);
+
+#ifdef DOB2A
+ if (dob2a) {
+ icmLut *wo;
+
+ in_b2a_callback cx;
+
+ if (verb)
+ printf("Setting up B to A table lookup\n");
+
+ /* Get a suitable forward conversion object to invert. */
+ /* By creating a separate one to the one created using scattered data, */
+ /* we ge the chance to set ICX_CAM_CLIP. It is always set to Lab 'PCS' */
+ {
+ int flags = 0;
+
+ if (verb)
+ flags |= ICX_VERBOSE;
+
+ flags |= ICX_CLIP_NEAREST; /* Not vector clip */
+#ifdef USE_CAM_CLIP_OPT
+ flags |= ICX_CAM_CLIP; /* Clip in CAM Jab space rather than Lab */
+#else
+ warning("!!!! USE_CAM_CLIP_OPT in profout.c is off !!!!");
+#endif
+ if ((AtoB = wr_xicc->get_luobj(wr_xicc, flags, icmFwd,
+ icmDefaultIntent,
+ wantLab ? icSigLabData : icSigXYZData,
+ icmLuOrdNorm, NULL, NULL)) == NULL)
+ error ("%d, %s",wr_xicc->errc, wr_xicc->err);
+ }
+
+ /* setup context ready for B2A table setting */
+ cx.verb = verb;
+ cx.pcsspace = wantLab ? icSigLabData : icSigXYZData;
+ cx.wantLab = wantLab; /* Copy PCS flag over */
+#ifdef NO_B2A_PCS_CURVES
+ cx.noPCScurves = 1; /* Don't use PCS curves */
+#else
+ cx.noPCScurves = 0;
+#endif
+ cx.devspace = icSigRgbData;
+ cx.x = (icxLuLut *)AtoB; /* A2B icxLuLut created from scattered data */
+
+ if ((wo = (icmLut *)wr_icco->read_tag(
+ wr_icco, icSigBToA0Tag)) == NULL)
+ error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ /* We now setup an exact inverse, colorimetric style */
+ /* Use helper function to do the hard work. */
+
+ if (cx.verb) {
+ unsigned int ui;
+ int extra;
+ cx.count = 0;
+ cx.last = -1;
+ for (cx.total = 1, ui = 0; ui < wo->inputChan; ui++, cx.total *= wo->clutPoints)
+ ;
+ /* Add in cell center points */
+ for (extra = 1, ui = 0; ui < wo->inputChan; ui++, extra *= (wo->clutPoints-1))
+ ;
+ cx.total += extra;
+ printf("Creating B to A tables\n");
+ printf(" 0%%"); fflush(stdout);
+ }
+
+ if (icmSetMultiLutTables(
+ 1,
+ &wo,
+ ICM_CLUT_SET_APXLS, /* Use least squared aprox. */
+ &cx, /* Context */
+ cx.pcsspace, /* Input color space */
+ icSigRgbData, /* Output color space */
+ in_b2a_input, /* Input transform PCS->PCS' */
+ 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 */
+ error("Setting 16 bit PCS->Device Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+ if (cx.verb) {
+ printf("\n");
+ }
+#ifdef WARN_CLUT_CLIPPING
+ if (wr_icco->warnc)
+ warning("Values clipped in setting LUT");
+#endif /* WARN_CLUT_CLIPPING */
+
+ if (verb)
+ printf("Done B to A table\n");
+ AtoB->del(AtoB);
+ }
+#endif /* DOB2A */
+ wr_xicc->del(wr_xicc);
+
+ }
+
+ /* Write the file (including all tags) out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icco->err);
+
+ /* Close the file */
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+
+ /* Check the profile accuracy against the data points */
+ if (verb || verify) {
+ icmFile *rd_fp;
+ icc *rd_icco;
+ icmLuBase *luo;
+ double merr = 0.0;
+ double aerr = 0.0;
+ double nsamps = 0.0;
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error ("Write: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Write: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* ~~ should use an xluobj with merge output ~~~ */
+ /* Get the A2B table */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd,
+ icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ for (i = 0; i < npat; i++) {
+ double out[3], ref[3];
+ double mxd;
+
+ if (luo->lookup(luo, out, tpat[i].p) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Our tpat data might be in XYZ, so generate an Lab ref value */
+ if (!wantLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
+ icmXYZ2Lab(&icmD50, ref, tpat[i].v);
+
+ } else {
+ ref[0] = tpat[i].v[0];
+ ref[1] = tpat[i].v[1];
+ ref[2] = tpat[i].v[2];
+ }
+
+ if (verb && verify) {
+ printf("[%f] %f %f %f -> %f %f %f should be %f %f %f\n",
+ icmLabDE(ref, out),
+ tpat[i].p[0],tpat[i].p[1],tpat[i].p[2],
+ out[0],out[1],out[2],
+ ref[0],ref[1],ref[2]);
+ }
+
+ /* Check the result */
+ mxd = icmLabDE(ref, out);
+ if (mxd > merr)
+ merr = mxd;
+
+ aerr += mxd;
+ nsamps++;
+ }
+ printf("Profile check complete, peak err = %f, avg err = %f\n",merr,aerr/nsamps);
+
+ /* Done with lookup object */
+ luo->del(luo);
+
+ /* Close the file */
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+ }
+
+ free(tpat);
+}
+
+
diff --git a/profile/profout.c b/profile/profout.c
new file mode 100644
index 0000000..d89ae4e
--- /dev/null
+++ b/profile/profout.c
@@ -0,0 +1,2963 @@
+
+/*
+ * Argyll Color Correction System
+ * Output device profile creator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 11/10/00
+ *
+ * Copyright 2000-2011 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.
+ */
+
+/*
+ * This program takes in the scattered test chart
+ * points, and interpolates them into a gridded
+ * forward ICC device profile for an output or display device,
+ * using a clut based profle.
+ * It also creates backward tables based on the forward grid.
+ *
+ * Preview profiles are not currently generated.
+ *
+ * The gamut clut should be implemented with xicc/rspl
+ */
+
+/*
+ * TTBD:
+ *
+ * For flexibility, it might be nice to allow the user to override the
+ * default intent for all 3 output tables, allowing fully custom usage.
+ * ie. Would be nice to offer various relative colorimetric intents,
+ * so that more image friendly versions could be chosen.
+ * (Need to break dependence between intents CAM to do this with full flexibility).
+ *
+ * Need to make this more of a library:
+ * Fix error handling
+ * fix verbose output
+ * hand icc object back rather than writing file ?
+ */
+
+/*
+ Outline of code flow:
+
+ profout:
+ Create ICC profile and all the tags. Table tags are initialy not set.
+
+ Read in the CGTATS data and convert spectral to PCS if needed.
+
+ Wrap the icc in an xicc, and then create an xicc lookup object
+ 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
+ from PCS to device, then use (icc) icmSetMultiLutTables() which will
+ call back the out_b2a_input(), out_b2a_clut() and out_b2a_output()
+ functions.
+ */
+
+#undef DEBUG /* Print B2A processing information */
+#undef DEBUG_ONE /* Test a particular value rather than process whole grid */
+
+#define verbo stdout
+
+#undef IMP_MONO /* [Undef] Turn on development code */
+
+#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 */
+//#undef USE_EXTRA_FITTING /* [Undef] Turn on data point error compensation in A2B */
+//#undef USE_2PASSSMTH /* [Undef] Turn on Gaussian smoothing in A2B */
+#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 */
+#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 */
+
+#include <stdio.h>
+#include "numlib.h"
+#include "icc.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "counters.h"
+#include "rspl.h"
+#include "insttypes.h"
+#include "prof.h"
+#include "gamut.h"
+#include "gammap.h"
+
+#ifndef MAX_CAL_ENT
+#define MAX_CAL_ENT 4096
+#endif
+
+/*
+ Basic algorithm outline:
+
+ Printer:
+ Figure out the input curves to give
+ the flattest grid.
+
+ Figure out the grid values.
+
+ Use them to generate all the A2B tables.
+
+ Use the inverse rspl code to compute
+ all the B2A profiles.
+
+*/
+
+/*
+ Notes:
+
+ The shared gamma/shaper support is for silly applications
+ like which can't handle display profiles that have per
+ chanel gamma's, per chanel curves or clut based display profiles.
+
+*/
+
+/* NOTE:-
+ It's interesting that the white and black points recorded in the tags,
+ generally won't quite match the white and black points returned by
+ looking up the profile in absolute mode.
+
+ For a Matrix profile, in the case of the white point this is
+ because we're not using the ICC 16 bit quantized value to
+ create the relative transform matrix, and in the case of
+ the black point, it can never be a perfect match because the black
+ point returned by a profile lookup will be the quantized black
+ point of the matrix, transformed by the rel->abs matrix, which
+ generally won't be equal to an ICC quantized value.
+ It might help the latter case if we were at least able to convert
+ the profile quantized black point into the absolute black point
+ via the rel->abs transform, and then quantize it.
+
+ Of course all of this will be worse in the Lut type profile,
+ due to the white and black points being stored in a different
+ quantized space (XYZ vs. Lab) than the Lut grid point values!
+ */
+
+
+#ifdef DEBUG
+#undef DBG
+#define DBG(xxx) printf xxx ;
+#else
+#undef DBG
+#define DBG(xxx)
+#endif
+
+/* ---------------------------------------- */
+
+/* structure to support output icc B2A Lut initialisation calbacks. */
+/* Note that we don't cope with a LUT matrix - assume it's unity. */
+
+typedef struct {
+ int verb;
+ int total, count, last; /* Progress count information */
+ int noPCScurves; /* Flag set if we don't want PCS curves */
+ int filter; /* Filter clipped values */
+ double filter_thr; /* Clip DE threshold */
+ double filter_ratio; /* Clip DE to radius factor */
+ double filter_maxrad; /* Clip maximum filter radius */
+ icColorSpaceSignature pcsspace; /* The PCS colorspace */
+ icColorSpaceSignature devspace; /* The device colorspace */
+ icxLuLut *x; /* A2B icxLuLut we are inverting in std PCS */
+
+ int ntables; /* Number of tables being set. 1 = colorimetric */
+ /* 2 = colorimetric + saturation, 3 = all intents */
+ int ochan; /* Number of output channels for B2A */
+ gammap *pmap; /* Perceptual CAM to CAM Gamut mapping, NULL if no mapping */
+ gammap *smap; /* Saturation CAM to CAM Gamut mapping, NULL if no mapping */
+ icxLuBase *ixp; /* Source profile perceptual PCS to CAM conversion */
+ icxLuBase *ox; /* Destination profile CAM to std PCS conversion */
+ /* (This is NOT used for the colorimetric B2A table creation!) */
+
+ /* Abstract transform for each table. These may be */
+ /* duplicates. */
+ icRenderingIntent abs_intent[3]; /* Desired abstract profile rendering intent */
+ icxLuBase *abs_luo[3]; /* abstract profile transform in PCS, NULL if none */
+
+ double xyzscale[2]; /* < 1.0 if XYZ is to be scaled in destination space */
+ /* for perceptual [0], and saturation [1] */
+ 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 */
+} out_b2a_callback;
+
+/* Utility to handle abstract profile application to PCS. */
+/* PCS in creating output table is always XYZ or Lab relative colorimetric, */
+/* and abstract profile is absolute or relative, and will be */
+/* XYZ if absolute, and PCS if relative. */
+static void do_abstract(out_b2a_callback *p, int tn, double out[3], double in[3]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+
+ if (p->abs_intent[tn] == icAbsoluteColorimetric) {
+ if (p->pcsspace == icSigLabData) {
+ icmLab2XYZ(&icmD50, out, out);
+ }
+ p->x->plu->XYZ_Rel2Abs(p->x->plu, out, out);
+ }
+
+ p->abs_luo[tn]->lookup(p->abs_luo[tn], out, out);
+
+ if (p->abs_intent[tn] == icAbsoluteColorimetric) {
+ p->x->plu->XYZ_Abs2Rel(p->x->plu, out, out);
+ if (p->pcsspace == icSigLabData) {
+ icmXYZ2Lab(&icmD50, out, out);
+ }
+ }
+}
+
+/* --------------------------------------------------------- */
+
+/* Extra non-linearity applied to BtoA XYZ PCS. */
+/* This distributes the LUT indexes more evenly in */
+/* perceptual space, greatly improving the B2A accuracy of XYZ LUT */
+/* To better use the full range of the grid, and also to make sure */
+/* that the white point gets mapped accurately, scale the XYZ to put */
+/* the D50 white at the top corner of the grid. */
+
+/* Y to L* */
+static void y2l_curve(double *out, double *in) {
+ int i;
+ double sc = 65535.0/32768.0; /* Scale from 0.0 .. 1.999969 to 0.0 .. 1.0 and back */
+ double val;
+
+ for (i = 0; i < 3; i++) {
+ val = in[i];
+ val /= icmD50_ary3[i]; /* Put white at top of grid and scale */
+ if (val > 0.008856451586)
+ val = 1.16 * pow(val,1.0/3.0) - 0.16;
+ else
+ val = 9.032962896 * val;
+ if (val > 1.0)
+ val = 1.0;
+ val *= sc; /* Unscale */
+ out[i] = val;
+ }
+}
+
+/* L* to Y */
+static void l2y_curve(double *out, double *in) {
+ int i;
+ double sc = 65535.0/32768.0; /* Scale from 0.0 .. 1.999969 to 0.0 .. 1.0 and back */
+ double val;
+
+ /* Use an L* like curve, scaled to the maximum XYZ value */
+ for (i = 0; i < 3; i++) {
+ val = in[i];
+ val /= sc; /* Scale */
+ if (val > 0.08)
+ val = pow((val + 0.16)/1.16, 3.0);
+ else
+ val = val/9.032962896;
+ val *= icmD50_ary3[i]; /* Unscale and put white at top of grid */
+ out[i] = val;
+ }
+}
+
+/* --------------------------------------------------------- */
+
+/* sRGB device gamma encoded value to linear value 0.0 .. 1.0 */
+static double gdv2dv(double iv) {
+ double ov;
+
+ if (iv < 0.04045)
+ ov = iv/12.92;
+ else
+ ov = pow((iv + 0.055)/1.055, 2.4);
+ return ov;
+}
+
+
+/* --------------------------------------------------------- */
+/* NOTE :- the assumption that each stage of the BtoA is a mirror */
+/* of the AtoB makes for inflexibility. */
+/* Perhaps it would be better to remove this asumption from the */
+/* out_b2a_clut processing ? */
+/* To do this we then need inv_out_b2a_input(), and */
+/* inv_out_b2a_output(), and we need to clearly distinguish between */
+/* AtoB PCS' & DEV', and BtoA PCS' & DEV', since they are not */
+/* necessarily the same... */
+
+
+/* B2A Input table is the inverse of the AtoB output table */
+/* Input PCS output PCS'' */
+void out_b2a_input(void *cntx, double out[3], double in[3]) {
+ out_b2a_callback *p = (out_b2a_callback *)cntx;
+
+ DBG(("out_b2a_input got PCS %f %f %f\n",in[0],in[1],in[2]))
+
+ /* PCS to PCS' */
+ if (p->noPCScurves) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ } else {
+ if (p->x->inv_output(p->x, out, in) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+ }
+ /* PCS' to PCS'' */
+ if (p->pcsspace == icSigXYZData) /* Apply XYZ non-linearity curve */
+ y2l_curve(out, out);
+
+ DBG(("out_b2a_input returning PCS'' %f %f %f\n",out[0],out[1],out[2]))
+}
+
+/* clut - multitable */
+/* Input PCS' output Dev' */
+/* We're applying any abstract profile after gamut mapping, */
+/* on the assumption is is primarily being used to "correct" the */
+/* output device. Ideally the gamut mapping should take the change */
+/* the abstract profile has on the output device into account, but */
+/* currently we're not doing this.. */
+/* If ICM_CLUT_SET_FILTER is being used, then */
+/* we need to set a filter radius value at out[-1-table] */
+void out_b2a_clut(void *cntx, double *out, double in[3]) {
+ out_b2a_callback *p = (out_b2a_callback *)cntx;
+ double inn[3], in1[3];
+ double cdist = 0.0; /* Clipping DE */
+ int tn;
+
+ DBG(("\nout_b2a_clut got PCS'' %f %f %f\n",in[0],in[1],in[2]))
+
+ in1[0] = in[0]; /* in[] may be aliased with out[] */
+ in1[1] = in[1]; /* so take a copy. */
+ in1[2] = in[2]; /* (If we were using "index-under", we should copy it too) */
+
+ DBG(("out_b2a_clut got PCS' %f %f %f\n",in[0],in[1],in[2]))
+
+ if (p->pcsspace == icSigXYZData) /* Undo effects of extra XYZ non-linearity curve */
+ l2y_curve(in1, in1);
+
+ inn[0] = in1[0]; /* Copy of PCS' for 2nd and 3rd tables */
+ inn[1] = in1[1];
+ inn[2] = in1[2];
+
+ if (p->abs_luo[0] != NULL) { /* Abstract profile to apply to first table only. */
+
+ if (!p->noPCScurves) { /* Convert from PCS' to PCS so we can apply abstract */
+ if (p->x->output(p->x, in1, in1) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+ }
+ do_abstract(p, 0, in1, in1); /* Abstract profile to apply to first table */
+ DBG(("through abstract prof PCS %f %f %f\n",in1[0],in1[1],in1[2]))
+ /* We now have PCS */
+ }
+
+ if (p->noPCScurves || p->abs_luo[0] != NULL) { /* We were given PCS or have converted to PCS */
+
+ /* PCS to PCS' */
+ if (p->x->inv_output(p->x, in1, in1) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+
+ DBG(("noPCScurves = %d, abs_luo[0] = 0x%x\n",p->noPCScurves,p->abs_luo[0]))
+ DBG(("convert PCS to PCS' got %f %f %f\n",in1[0],in1[1],in1[2]))
+ }
+
+ /* Invert AtoB clut (PCS' to Dev') Colorimetric */
+ /* to producte the colorimetric tables output. */
+ /* (Note that any aux target if we were using one, would be in Dev space) */
+ if (p->x->inv_clut_aux(p->x, out, NULL, NULL, NULL, &cdist, in1) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+ if (p->filter) {
+ cdist -= p->filter_thr;
+ if (cdist < 0.0)
+ cdist = 0.0;
+ cdist *= p->filter_ratio;
+ if (cdist > p->filter_maxrad)
+ cdist = p->filter_maxrad;
+ out[-1-0] = cdist;
+ }
+
+ DBG(("convert PCS' to DEV' got %s\n",icmPdv(p->ochan, out)))
+
+#ifdef COMPARE_INV_CLUT /* Compare the inversion result with the fwd lookup */
+ {
+ double chk[3];
+
+ if (p->x->clut(p->x, chk, out) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+
+ DBG(("check DEV' to PCS' got %f %f %f\n",chk[0],chk[1],chk[2]))
+ }
+#endif
+ if (p->ntables > 1) { /* Do first part once for both intents */
+ double *tnout = out; /* This tables output values */
+
+ DBG(("\n"))
+
+ /* Starting with original input inn[] PCS' (no abstract profile applied to other tables) */
+ in1[0] = inn[0];
+ in1[1] = inn[1];
+ in1[2] = inn[2];
+
+ if (!p->noPCScurves) { /* Convert from PCS' to PCS */
+ if (p->x->output(p->x, in1, in1) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+ }
+ DBG(("convert PCS' to PCS got %f %f %f\n",in1[0],in1[1],in1[2]))
+
+ /* Convert from PCS to CAM/Gamut mapping space */
+ p->ixp->fwd_relpcs_outpcs(p->ixp, p->pcsspace, in1, in1);
+
+ DBG(("convert PCS to CAM got %f %f %f\n",in1[0],in1[1],in1[2]))
+
+ /* Apply gamut mapping in CAM space for remaining tables */
+ /* and create the output values */
+ for (tn = 1; tn < p->ntables; tn++) {
+ double in2[3];
+
+ tnout += p->ochan; /* next table/intent */
+ in2[0] = in1[0]; /* Copy in1[] so it can be used for both tables */
+ in2[1] = in1[1];
+ in2[2] = in1[2];
+
+ /* Do luminence scaling if requested */
+ if (p->xyzscale[tn-1] < 1.0) {
+ double xyz[3];
+
+ DBG(("got xyzscale = %f\n",p->xyzscale[tn-1]))
+ DBG(("PCS %f %f %f\n",in2[0], in2[1], in2[2]))
+ /* Convert our CAM to XYZ */
+ /* We're being bad in delving inside the xluo, but we'll fix it latter */
+ p->ox->cam->cam_to_XYZ(p->ox->cam, xyz, in2);
+
+ DBG(("XYZ %f %f %f\n",xyz[0], xyz[1], xyz[2]))
+ /* Scale it */
+ xyz[0] *= p->xyzscale[tn-1];
+ xyz[1] *= p->xyzscale[tn-1];
+ xyz[2] *= p->xyzscale[tn-1];
+
+ DBG(("scaled XYZ %f %f %f\n",xyz[0], xyz[1], xyz[2]))
+ /* Convert back to CAM */
+ /* We're being bad in delving inside the xluo, but we'll fix it latter */
+ p->ox->cam->XYZ_to_cam(p->ox->cam, in2, xyz);
+
+ DBG(("scaled PCS %f %f %f\n",in2[0], in2[1], in2[2]))
+ }
+
+ if (tn == 1) {
+ DBG(("percep gamut map in %f %f %f\n",in2[0],in2[1],in2[2]))
+ p->pmap->domap(p->pmap, in2, in2); /* Perceptual mapping */
+ DBG(("percep gamut map out %f %f %f\n",in2[0],in2[1],in2[2]))
+ } else {
+ DBG(("sat gamut map in %f %f %f\n",in2[0],in2[1],in2[2]))
+ p->smap->domap(p->smap, in2, in2); /* Saturation mapping */
+ DBG(("sat gamut map got %f %f %f\n",in2[0],in2[1],in2[2]))
+ }
+
+ /* Convert from Gamut maping/CAM space to PCS */
+ p->ox->bwd_outpcs_relpcs(p->ox, p->pcsspace, in2, in2);
+ DBG(("convert CAM to PCS got %f %f %f\n",in2[0],in2[1],in2[2]))
+
+ if (p->abs_luo[tn] != NULL) /* Abstract profile to other tables after gamut map */
+ do_abstract(p, tn, in2, in2);
+
+ /* Convert from PCS to PCS' */
+ if (p->x->inv_output(p->x, in2, in2) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+ DBG(("convert PCS to PCS' got %f %f %f\n",in2[0],in2[1],in2[2]))
+
+ /* Invert AtoB clut (PCS' to Dev') */
+ /* to producte the perceptual or saturation tables output. */
+ /* (Note that any aux target if we were using one, would be in Dev space) */
+ if (p->x->inv_clut_aux(p->x, tnout, NULL, NULL, NULL, &cdist, in2) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+ if (p->filter) {
+ cdist -= p->filter_thr;
+ if (cdist < 0.0)
+ cdist = 0.0;
+ cdist *= p->filter_ratio;
+ if (cdist > p->filter_maxrad)
+ cdist = p->filter_maxrad;
+ out[-1-tn] = cdist;
+ }
+ DBG(("convert PCS' to DEV' got %s\n",icmPdv(p->ochan, tnout)))
+ }
+ }
+
+ DBG(("out_b2a_clut returning DEV' %s\n",icmPdv(p->ochan, out)))
+
+ if (p->verb) { /* Output percent intervals */
+ int pc;
+ p->count++;
+ pc = (int)(p->count * 100.0/p->total + 0.5);
+ if (pc != p->last) {
+ printf("%c%2d%%",cr_char,pc); fflush(stdout);
+ p->last = pc;
+ }
+ }
+}
+
+/* Output table is the inverse of the AtoB input table */
+/* Input Dev' output Dev */
+void out_b2a_output(void *cntx, double out[4], double in[4]) {
+ out_b2a_callback *p = (out_b2a_callback *)cntx;
+
+ DBG(("out_b2a_output got DEV' %s\n",icmPdv(p->ochan,in)))
+
+ if (p->x->inv_input(p->x, out, in) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+
+ DBG(("out_b2a_output returning DEV %s\n",icmPdv(p->ochan,out)))
+}
+
+/* --------------------------------------------------------- */
+
+/* PCS' -> distance to gamut boundary */
+static void PCSp_bdist(void *cntx, double out[1], double in[3]) {
+ out_b2a_callback *p = (out_b2a_callback *)cntx;
+ double pcs[3]; /* PCS value of input */
+ double nrad; /* normalised radial value of point */
+ double np[3]; /* Nearest point */
+ double gdist; /* Out of gamut distance */
+
+//printf("~1 bdist got PCS %f %f %f\n",in[0],in[1],in[2]);
+ /* Do PCS' -> PCS */
+ if (p->x->inv_output(p->x, pcs, in) > 1)
+ error("%d, %s",p->x->pp->errc,p->x->pp->err);
+
+ /* If PCS is XYZ, convert to Lab */
+ if (p->wantLab == 0) {
+ icmXYZ2Lab(&icmD50, pcs, pcs);
+//printf("~1 bdist converted to Lab %f %f %f\n",pcs[0],pcs[1],pcs[2]);
+ }
+
+ /* Check if this point is in or out of gamut */
+ nrad = p->gam->nradial(p->gam, np, pcs);
+
+//printf("~1 nrad = %f\n",nrad);
+
+ /* Radial rather than nearest distance seems the best overall. */
+
+ gdist = icmNorm33(np, pcs);
+ if (nrad <= 1.0)
+ gdist = -gdist; /* -ve delta E if within gamut */
+
+//printf("~1 gdist %f\n",gdist);
+
+ /* Distance in PCS space will be roughly -128 -> 128 */
+ /* Clip to range -20 - +20, then scale to 0.0 - 1.0 */
+ if (gdist < -20.0)
+ gdist = -20.0;
+ else if (gdist > 20.0)
+ gdist = 20.0;
+
+ out[0] = (gdist + 20.0)/40.0;
+//printf("~1 bdist returning %f\n",out[0]);
+
+ if (p->verb) { /* Output percent intervals */
+ int pc;
+ p->count++;
+ pc = (int)(p->count * 100.0/p->total + 0.5);
+ if (pc != p->last) {
+ printf("%c%2d%%",cr_char,pc); fflush(stdout);
+ p->last = pc;
+ }
+ }
+}
+
+/* The output table for a Gamut lut is usually a special function, returning */
+/* a value of 0 for all inputs <= 0.5, and then outputing between */
+/* 0.0 and 1.0 for the input range 0.5 to 1.0. This is so a graduated */
+/* "gamut boundary distance" number from the multi-d lut can be */
+/* translated into the ICC "0.0 if in gamut, > 0.0 if not" number. */
+static void gamut_output(void *cntx, double out[1], double in[1]) {
+ double iv, ov;
+ iv = in[0];
+ if (iv <= 0.5)
+ ov = 0.0;
+ else
+ ov = (iv - 0.5) * 2.0;
+ out[0] = ov;
+}
+
+/* -------------------------------------------------------------- */
+/* powell() callback to set XYZ white scaling factor for */
+/* Absolute Appearance mode with scaling intent */
+
+static double xyzoptfunc(void *cntx, double *v) {
+ out_b2a_callback *p = (out_b2a_callback *)cntx;
+ double swxyz[3], jab[3], dev[MAX_CHAN];
+ double rv;
+ int rc;
+
+ rv = 2.0 - v[0]; /* Make Y as large as possible */
+
+ /* If we wanted to use this function to maximise the brightness */
+ /* we would not limit the scale to 1.0 */
+ if (v[0] > 1.0) {
+ rv += 1000.0;
+ return rv;
+ }
+ if (v[0] < 0.0) {
+ rv += 100.0;
+ return rv;
+ }
+ swxyz[0] = v[0] * p->swxyz[0];
+ swxyz[1] = v[0] * p->swxyz[1];
+ swxyz[2] = v[0] * p->swxyz[2];
+
+//printf("~1 scaled white XYZ = %f %f %f\n", swxyz[0], swxyz[1], swxyz[2]);
+
+ /* We're being bad in delving inside the xluo, but we'll fix it latter */
+ p->ox->cam->XYZ_to_cam(p->ox->cam, jab, swxyz);
+
+//printf("~1 scaled white Jab = %f %f %f\n", jab[0], jab[1], jab[2]);
+
+ /* Run the target PCS backwards through the output space to see if it clips */
+ rc = p->ox->inv_lookup(p->ox, dev, jab);
+//printf("~1 device = %f %f %f, rc = %d\n", dev[0], dev[1], dev[2],rc);
+ if (rc != 0)
+ rv += 500.0;
+
+//printf("~1 xyzoptfunc rv %f from xyzscale %f\n\n",rv,v[0]);
+ return rv;
+}
+
+/* -------------------------------------------------------------- */
+/* Make an output device profile, where a forward mapping is from */
+/* RGB/CMYK to XYZ/Lab space */
+void
+make_output_icc(
+ prof_atype ptype, /* Profile algorithm type */
+ int mtxtoo, /* NZ if matrix tags should be created for Display XYZ cLUT */
+ icmICCVersion iccver, /* ICC profile version to create */
+ int verb, /* Vebosity level, 0 = none */
+ int iquality, /* A2B table quality, 0..3 */
+ int oquality, /* B2A table quality, 0..3 */
+ int noisluts, /* nz to supress creation of input (Device) shaper luts */
+ int noipluts, /* nz to supress creation of input (Device) position luts */
+ int nooluts, /* nz to supress creation of output (PCS) shaper luts */
+ int nocied, /* nz to supress inclusion of .ti3 data in profile */
+ int noptop, /* nz to use colorimetic source gamut to make perceptual table */
+ int nostos, /* nz to use colorimetic source gamut to make saturation table */
+ int gamdiag, /* Make gamut mapping diagnostic wrl plots */
+ int verify, /* nz to print verification */
+ int clipprims, /* Clip white, black and primaries */
+ icxInk *oink, /* Ink limit/black generation setup (NULL if n/a) */
+ char *in_name, /* input .ti3 file name */
+ char *file_name, /* output icc name */
+ cgats *icg, /* input cgats structure */
+ int spec, /* Use spectral data flag */
+ icxIllumeType tillum, /* Target/simulated instrument illuminant */
+ xspect *cust_tillum, /* Possible custom target/simulated instrument illumination */
+ icxIllumeType illum, /* Spectral illuminant */
+ xspect *cust_illum, /* Possible custom illumination */
+ icxObserverType observ, /* Spectral observer */
+ 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 */
+ 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 */
+ int sepsat, /* Create separate Saturation B2A */
+ icxViewCond *ivc_p, /* Input Viewing Parameters for CAM */
+ icxViewCond *ovc_p, /* Output Viewing Parameters for CAM */
+ int ivc_e, /* Input Enumerated viewing condition */
+ int ovc_e, /* Output Enumerated viewing condition */
+ icxGMappingIntent *pgmi,/* Perceptual gamut mapping intent */
+ icxGMappingIntent *sgmi,/* Saturation gamut mapping intent */
+ profxinf *xpi /* Optional Profile creation extra data */
+) {
+ int isdisp; /* nz if this is a display device, 0 if output */
+ double dispLuminance = 0.0; /* Display luminance. 0 if not known */
+ int isdnormed = 0; /* Has display data been normalised to 100 ? */
+ int allintents; /* nz if all intents should possibly be created */
+ icmFile *wr_fp;
+ icc *wr_icco;
+ int npat; /* Number of patches */
+ cow *tpat; /* Patch input values */
+ int i, j, rv = 0;
+ icColorSpaceSignature devspace = icmSigDefaultData; /* The device colorspace */
+ inkmask imask = 0; /* Device inkmask */
+ int isAdditive = 0; /* 0 if subtractive, 1 if additive colorspace */
+ int isLab = 0; /* 0 if input is XYZ, 1 if input is Lab */
+ int wantLab = 0; /* 0 if want XYZ, 1 want Lab */
+ int isLut = 0; /* 0 if shaper+ matrix, 1 if lut type */
+ int isShTRC = 0; /* 0 if separate gamma/shaper TRC, 1 if shared */
+ int devchan = 0; /* Number of device chanels */
+ int a2binres = 0; /* A2B input (device) table resolution */
+ int a2bres = 0; /* A2B clut resolution */
+ int a2boutres = 0; /* A2B output (PCS) table resolution */
+ int b2ainres = 0; /* B2A input (PCS) table resolution */
+ int b2ares = 0; /* B2A clut resolution */
+ int b2aoutres = 0; /* B2A output (device) table resolution */
+ xcal *cal = NULL; /* Calibration if present, NULL if none */
+ icxInk iink; /* Source profile ink limit values */
+
+ memset((void *)&iink, 0, sizeof(icxInk));
+ iink.tlimit = -1.0; /* default to unknown */
+ iink.klimit = -1.0;
+
+ if (ptype == prof_clutLab) { /* Lab lut */
+ wantLab = 1;
+ isLut = 1;
+ } else if (ptype == prof_clutXYZ) { /* XYZ lut */
+ wantLab = 0;
+ isLut = 1;
+ } else {
+ wantLab = 0; /* gamma/shaper + matrix profile must be XYZ */
+ isLut = 0;
+
+ if (ptype == prof_gam1mat
+ || ptype == prof_sha1mat
+ || ptype == prof_matonly) {
+ isShTRC = 1; /* Single curve */
+ }
+ }
+
+ {
+ int ti;
+
+ if ((ti = icg->find_kword(icg, 0, "DEVICE_CLASS")) < 0)
+ error ("Input file doesn't contain keyword DEVICE_CLASS");
+
+ if (strcmp(icg->t[0].kdata[ti],"DISPLAY") == 0) {
+ isdisp = 1;
+ if (isLut && ipname != NULL)
+ allintents = 1;
+ else
+ allintents = 0; /* Only the default intent */
+ } else {
+ isdisp = 0;
+ allintents = 1;
+ }
+ }
+
+ /* See if display luminance data is present */
+ if (isdisp) {
+ 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)
+ dispLuminance = 0.0;
+ }
+
+ /* See if the CIE data has been normalised to Y = 100 */
+ if ((ti = icg->find_kword(icg, 0, "NORMALIZED_TO_Y_100")) < 0
+ || strcmp(icg->t[0].kdata[ti],"NO") == 0) {
+ isdnormed = 0;
+ } else {
+ isdnormed = 1;
+ }
+ }
+
+ /* Figure out what sort of device colorspace it is */
+ {
+ int ti;
+
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error("Input file doesn't contain keyword COLOR_REPS");
+
+ if (strcmp(icg->t[0].kdata[ti],"CMYK_XYZ") == 0) {
+ imask = ICX_CMYK;
+ devspace = icSigCmykData;
+ devchan = 4;
+ isLab = 0;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"CMYK_LAB") == 0) {
+ imask = ICX_CMYK;
+ devspace = icSigCmykData;
+ devchan = 4;
+ isLab = 1;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"CMY_XYZ") == 0) {
+ imask = ICX_CMY;
+ devspace = icSigCmyData;
+ devchan = 3;
+ isLab = 0;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"CMY_LAB") == 0) {
+ imask = ICX_CMY;
+ devspace = icSigCmyData;
+ devchan = 3;
+ isLab = 1;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"RGB_XYZ") == 0) {
+ imask = ICX_RGB;
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 0;
+ isAdditive = 1;
+ } else if (strcmp(icg->t[0].kdata[ti],"RGB_LAB") == 0) {
+ imask = ICX_RGB;
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 1;
+ isAdditive = 1;
+ } else if ( strcmp(icg->t[0].kdata[ti],"iRGB_XYZ") == 0) {
+ imask = ICX_IRGB;
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 0;
+ isAdditive = 1;
+ } else if (strcmp(icg->t[0].kdata[ti],"iRGB_LAB") == 0) {
+ imask = ICX_IRGB;
+ devspace = icSigRgbData;
+ devchan = 3;
+ isLab = 1;
+ isAdditive = 1;
+#ifdef IMP_MONO
+ } else if (strcmp(icg->t[0].kdata[ti],"K_XYZ") == 0) {
+ imask = ICX_K;
+ devspace = icSigGrayData;
+ devchan = 1;
+ isLab = 0;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"K_LAB") == 0) {
+ imask = ICX_K;
+ devspace = icSigGrayData;
+ devchan = 1;
+ isLab = 1;
+ isAdditive = 0;
+ } else if (strcmp(icg->t[0].kdata[ti],"W_XYZ") == 0) {
+ imask = ICX_W;
+ devspace = icSigGrayData;
+ devchan = 1;
+ isLab = 0;
+ isAdditive = 1;
+ } else if (strcmp(icg->t[0].kdata[ti],"W_LAB") == 0) {
+ imask = ICX_W;
+ devspace = icSigGrayData;
+ devchan = 1;
+ isLab = 1;
+ isAdditive = 1;
+#endif /* IMP_MONO */
+ } else
+ error("Output device input file has unhandled color representation '%s'",
+ icg->t[0].kdata[ti]);
+ /* Figure out some suitable table sizes */
+ if (devchan >= 4) { /* devchan == 4 or greater */
+ if (iquality >= 3) {
+ a2binres = 2048;
+ a2bres = 23;
+ a2boutres = 2048;
+ } else if (iquality == 2) {
+ a2binres = 2048;
+ a2bres = 17;
+ a2boutres = 2048;
+ } else if (iquality == 1) {
+ a2binres = 1024;
+ a2bres = 9;
+ a2boutres = 1024;
+ } else {
+ a2binres = 512;
+ a2bres = 5;
+ a2boutres = 512;
+ }
+ } else if (devchan >= 2) { /* devchan == 2 or 3 */
+ if (iquality >= 3) {
+ a2binres = 2048;
+ a2bres = 45;
+ a2boutres = 2048;
+ } else if (iquality == 2) {
+ a2binres = 2048;
+ a2bres = 33;
+ a2boutres = 2048;
+ } else if (iquality == 1) {
+ a2binres = 1024;
+ a2bres = 17;
+ a2boutres = 1024;
+ } else {
+ a2binres = 512;
+ a2bres = 9;
+ a2boutres = 512;
+ }
+ } else { /* devchan == 1 */
+ if (iquality >= 3) {
+ a2binres = 256;
+ a2bres = 2048;
+ a2boutres = 256;
+ } else if (iquality == 2) {
+ a2binres = 256;
+ a2bres = 1024;
+ a2boutres = 256;
+ } else if (iquality == 1) {
+ a2binres = 256;
+ a2bres = 512;
+ a2boutres = 256;
+ } else {
+ a2binres = 256;
+ a2bres = 256;
+ a2boutres = 256;
+ }
+ }
+
+ if (devchan >= 2) {
+ if (oquality >= 3) { /* Ultra High */
+ b2ainres = 2048;
+ b2ares = 45;
+ b2aoutres = 2048;
+ } else if (oquality == 2) {
+ b2ainres = 2048;
+ b2ares = 33; /* High */
+ b2aoutres = 2048;
+ } else if (oquality == 1) {
+ b2ainres = 1024;
+ b2ares = 17; /* Medium */
+ b2aoutres = 1024;
+ } else if (oquality >= 0) {
+ b2ainres = 512;
+ b2ares = 9; /* Low */
+ b2aoutres = 512;
+ } else { /* Special, Extremely low quality */
+ b2ainres = 64;
+ b2ares = 3;
+ b2aoutres = 64;
+ }
+ } else { /* devchan == 1 */
+ if (oquality >= 3) { /* Ultra High */
+ b2ainres = 256;
+ b2ares = 3;
+ b2aoutres = 4096;
+ } else if (oquality == 2) {
+ b2ainres = 256;
+ b2ares = 3; /* High */
+ b2aoutres = 2048;
+ } else if (oquality == 1) {
+ b2ainres = 256;
+ b2ares = 3; /* Medium */
+ b2aoutres = 1024;
+ } else if (oquality >= 0) {
+ b2ainres = 256;
+ b2ares = 3; /* Low */
+ b2aoutres = 512;
+ } else { /* Special, Extremely low quality */
+ b2ainres = 64;
+ b2ares = 3;
+ b2aoutres = 64;
+ }
+ }
+
+ }
+
+ /* See if there is a calibration in the .ti3, and read it if there is */
+ {
+ int oi, tab;
+
+ if ((oi = icg->get_oi(icg, "CAL")) < 0)
+ error("Expect CAL type to be registered");
+
+ for (tab = 0; tab < icg->ntables; tab++) {
+ if (icg->t[tab].tt == tt_other && icg->t[tab].oi == oi) {
+ break;
+ }
+ }
+ if (tab < icg->ntables) {
+
+ if ((cal = new_xcal()) == NULL) {
+ error("new_xcal failed");
+ }
+ if (cal->read_cgats(cal, icg, tab, in_name) != 0) {
+ error("%s",cal->err);
+ }
+
+ if (cal->devmask != imask)
+ error("Calibrate colorspace %s doesn't match .ti3 %s",
+ icx_inkmask2char(cal->devmask, 1),
+ icx_inkmask2char(imask, 1));
+
+ if ((isdisp && cal->devclass != icSigDisplayClass)
+ || (!isdisp && cal->devclass != icSigOutputClass))
+ error("Calibration class %s doesn't match .ti3 %s",
+ icm2str(icmProfileClassSignature,cal->devclass),
+ isdisp ? "Display" : "Output");
+ }
+ }
+
+ /* Open up the file for writing */
+ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL)
+ error("Write: Can't open file '%s'",file_name);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ if (isdisp)
+ wh->deviceClass = icSigDisplayClass;
+ else
+ wh->deviceClass = icSigOutputClass;
+ wh->colorSpace = devspace; /* Device space it is */
+ if (wantLab)
+ wh->pcs = icSigLabData;
+ else
+ wh->pcs = icSigXYZData; /* Must be XYZ for matrix based profile */
+
+ if (xpi->default_ri != icMaxEnumIntent)
+ wh->renderingIntent = xpi->default_ri;
+ else
+ wh->renderingIntent = icRelativeColorimetric;
+
+ /* Values that should be set before writing */
+ if (xpi != NULL && xpi->manufacturer != 0L)
+ wh->manufacturer = xpi->manufacturer;
+ else
+ wh->manufacturer = icmSigUnknownType;
+
+ if (xpi != NULL && xpi->model != 0L)
+ wh->model = xpi->model;
+ else
+ wh->model = icmSigUnknownType;
+
+ /* Values that may be set before writing */
+ if (xpi != NULL && xpi->creator != 0L)
+ wh->creator = xpi->creator;
+
+#ifdef NT
+ wh->platform = icSigMicrosoft;
+#endif
+#ifdef __APPLE__
+ wh->platform = icSigMacintosh;
+#endif
+#if defined(UNIX) && !defined(__APPLE__)
+ wh->platform = icmSig_nix;
+#endif
+
+ if (xpi != NULL && xpi->transparency)
+ wh->attributes.l |= icTransparency;
+ if (xpi != NULL && xpi->matte)
+ wh->attributes.l |= icMatte;
+ if (xpi != NULL && xpi->negative)
+ wh->attributes.l |= icNegative;
+ if (xpi != NULL && xpi->blackandwhite)
+ wh->attributes.l |= icBlackAndWhite;
+ }
+
+ /* mtxtoo only applies to Display cLUT profiles */
+ if (!isLut
+ || wr_icco->header->deviceClass != icSigDisplayClass
+ || wr_icco->header->pcs != icSigXYZData) {
+ mtxtoo = 0;
+ }
+
+ /* Set the version of ICC profile we want */
+ if (isdisp && allintents) {
+ if (iccver < icmVersion2_4) {
+ iccver = icmVersion2_4; /* Need 2.4.0 for Display intents */
+ if (verb)
+ fprintf(verbo,"Bumped ICC version to 2.4.0 to accomodate multiple Display intents\n");
+ }
+ }
+ if (wr_icco->set_version(wr_icco, iccver) != 0)
+ error("set_version failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst, dstm[200]; /* description */
+
+ if (xpi != NULL && xpi->profDesc != NULL)
+ dst = xpi->profDesc;
+ else {
+ sprintf(dstm, "This is a Lut style %s - %s Output Profile",
+ devspace == icSigCmykData ? "CMYK" :
+ devspace == icSigCmyData ? "CMY" : "RGB",
+ wantLab ? "Lab" : "XYZ");
+ dst = dstm;
+ }
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt;
+
+ if (xpi != NULL && xpi->copyright != NULL)
+ crt = xpi->copyright;
+ else
+ crt = "Copyright, the creator of this profile";
+
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* Device Manufacturers Description Tag: */
+ if (xpi != NULL && xpi->deviceMfgDesc != NULL) {
+ icmTextDescription *wo;
+ char *dst = xpi->deviceMfgDesc;
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigDeviceMfgDescTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Model Description Tag: */
+ if (xpi != NULL && xpi->modelDesc != NULL) {
+ icmTextDescription *wo;
+ char *dst = xpi->modelDesc;
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigDeviceModelDescTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Display Luminance tag */
+ if (isdisp && dispLuminance > 0.0) {
+ {
+ icmXYZArray *wo;;
+
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigLuminanceTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.0; /* Set a default value */
+ wo->data[0].Y = dispLuminance; /* Set a default value */
+ wo->data[0].Z = 0.0; /* Set a default value */
+ }
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0] = icmD50; /* Set a default value - D50 */
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0] = icmBlack; /* Set a default value - absolute black */
+ }
+
+ /* Colorant Table Tag: */
+ {
+ unsigned int i;
+ icmColorantTable *wo;
+ if ((wo = (icmColorantTable *)wr_icco->add_tag(
+ wr_icco, icSigColorantTableTag, icSigColorantTableType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->count = icmCSSig2nchan(devspace);
+ if (wo->count != (unsigned long)icx_noofinks(imask))
+ error("Interna: device colorspace and inkmask conflict!");
+
+ wo->allocate((icmBase *)wo); /* Allocate ColorantTable structures */
+
+ for (i = 0; i < wo->count; i++) {
+ inkmask iimask; /* Individual ink mask */
+ char *name;
+
+ iimask = icx_index2ink(imask, i);
+ name = icx_ink2string(iimask);
+ if (strlen(name) > 31)
+ error("Internal: colorant name exceeds 31 characters");
+ strcpy(wo->data[i].name, name);
+ }
+ /* Fill in the colorant PCS values when we've got something to lookup */
+ }
+
+ /* vcgt tag */
+ if (verb & isdisp && cal != NULL && cal->noramdac) { /* We've been given vcgt information */
+ fprintf(verbo,"Not writing calibration to 'vcgt' because there is no VideoLUT access\n");
+ }
+ if (isdisp && cal != NULL && !cal->noramdac) { /* We've been given vcgt information */
+ int j, i;
+ int ncal = 256; /* This is safe with other s/w */
+ icmVideoCardGamma *wo;
+ wo = (icmVideoCardGamma *)wr_icco->add_tag(wr_icco,
+ icSigVideoCardGammaTag, icSigVideoCardGammaType);
+ if (wo == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->tagType = icmVideoCardGammaTableType;
+ wo->u.table.channels = 3; /* rgb */
+ wo->u.table.entryCount = ncal; /* full lut */
+ wo->u.table.entrySize = 2; /* 16 bits */
+ wo->allocate((icmBase*)wo);
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < ncal; i++) {
+ double cc, vv = i/(ncal - 1.0);
+ cc = cal->interp_ch(cal, j, vv);
+ if (cc < 0.0)
+ cc = 0.0;
+ else if (cc > 1.0)
+ cc = 1.0;
+ ((unsigned short*)wo->u.table.data)[ncal * j + i] = (int)(cc * 65535.0 + 0.5);
+ }
+ }
+ }
+
+ if (isLut) { /* Lut type profile */
+
+ /* Up to and including ICC Version 2.3, Display LUT profiles were assumed */
+ /* to have AtoB0 with no interpretation of the intent, which */
+ /* implies Relative Colorimetric. */
+
+ /* 16 bit dev -> pcs lut: (A2B) */
+ {
+ icmLut *wo;
+
+ if (!allintents) { /* Only A2B0, no intent */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigAToB0Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ } else {
+ /* Intent 1 = relative colorimetric */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigAToB1Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ wo->inputChan = devchan;
+ wo->outputChan = 3;
+ wo->clutPoints = a2bres;
+ wo->inputEnt = a2binres;
+ wo->outputEnt = a2boutres;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* icxLuLut will set tables values */
+ }
+
+ if (allintents) { /* All the intents may be needed */
+
+ /* 16 bit dev -> pcs lut - link intent 0 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB0Tag, icSigAToB1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ /* 16 dev -> pcs bit lut - link intent 2 to intent 1 */
+ {
+ icmLut *wo;
+ /* Intent 2 = saturation */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigAToB2Tag, icSigAToB1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ }
+
+ /* 16 bit pcs -> dev lut: (B2A) */
+ {
+ icmLut *wo;
+
+ if (!allintents) { /* Only B2A0, no intent */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigBToA0Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ } else {
+
+ /* Intent 1 = relative colorimetric */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigBToA1Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ wo->inputChan = 3;
+ wo->outputChan = devchan;
+ wo->clutPoints = b2ares;
+ wo->inputEnt = b2ainres;
+ wo->outputEnt = b2aoutres;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ }
+
+ if (allintents) { /* All the intents may be needed */
+
+ if (ipname == NULL) { /* No gamut mapping */
+ icmLut *wo;
+
+ /* link intent 0 = perceptual to intent 1 = colorimetric */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA0Tag, icSigBToA1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ /* Intent 2 = saturation */
+ /* link intent 2 = saturation to intent 1 = colorimetric */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA2Tag, icSigBToA1Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ } else { /* We have gamut mapping */
+ icmLut *wo;
+
+ /* Intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigBToA0Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = devchan;
+ wo->inputEnt = b2ainres;
+ wo->clutPoints = b2ares;
+ wo->outputEnt = b2aoutres;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ if (sepsat == 0) { /* No separate gamut mapping for saturation */
+ /* link intent 2 = saturation to intent 0 = perceptual */
+ if ((wo = (icmLut *)wr_icco->link_tag(
+ wr_icco, icSigBToA2Tag, icSigBToA0Tag)) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ } else {
+ /* Intent 2 = saturation */
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigBToA2Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = devchan;
+ wo->inputEnt = b2ainres;
+ wo->clutPoints = b2ares;
+ wo->outputEnt = b2aoutres;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ }
+ }
+
+ /* 16 bit pcs -> gamut lut: */
+ {
+ icmLut *wo;
+
+ if ((wo = (icmLut *)wr_icco->add_tag(
+ wr_icco, icSigGamutTag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 1;
+ wo->inputEnt = 256;
+ wo->clutPoints = b2ares;
+ wo->outputEnt = 256;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ }
+ }
+ }
+
+ /* shaper + matrix type tags */
+ if (!isLut
+ || ( wr_icco->header->deviceClass == icSigDisplayClass
+ && wr_icco->header->pcs == icSigXYZData)) {
+
+ /* Red, Green and Blue Colorant Tags: */
+ {
+ icmXYZArray *wor, *wog, *wob;
+ if ((wor = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigRedColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wog = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigGreenColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigBlueColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wor->size = wog->size = wob->size = 1;
+ wor->allocate((icmBase *)wor); /* Allocate space */
+ 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;
+
+ /* Setup deliberately wrong dummy values (channels rotated). */
+ /* icxMatrix may override 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;
+ }
+
+ /* Red, Green and Blue Tone Reproduction Curve Tags: */
+ {
+ icmCurve *wor, *wog, *wob;
+ if ((wor = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigRedTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ if (isShTRC) { /* Make all TRCs shared */
+ if ((wog = (icmCurve *)wr_icco->link_tag(
+ wr_icco, icSigGreenTRCTag, icSigRedTRCTag)) == NULL)
+ error("link_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmCurve *)wr_icco->link_tag(
+ wr_icco, icSigBlueTRCTag, icSigRedTRCTag)) == NULL)
+ error("link_tag failed: %d, %s",rv,wr_icco->err);
+
+ } else { /* Else individual */
+ if ((wog = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigGreenTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigBlueTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ }
+
+ /* Shaper */
+ if (ptype == prof_shamat || ptype == prof_sha1mat || ptype == prof_clutXYZ) {
+ wor->flag = wog->flag = wob->flag = icmCurveSpec;
+ wor->size = wog->size = wob->size = 256; /* Number of entries */
+ } else { /* Gamma */
+ wor->flag = wog->flag = wob->flag = icmCurveGamma;
+ wor->size = wog->size = wob->size = 1; /* Must be 1 for gamma */
+ }
+ wor->allocate((icmBase *)wor); /* Allocate space */
+ wog->allocate((icmBase *)wog);
+ wob->allocate((icmBase *)wob);
+
+ /* Setup a default sRGB like curve. */
+ /* icxMatrix will may override curve values later */
+ for (i = 0; i < wor->size; i++) {
+ wor->data[i] =
+ wog->data[i] =
+ wob->data[i] = gdv2dv(i/(wor->size-1.0));
+ }
+
+ }
+ }
+ /* .ti3 Sample data use to create profile, plus any calibration curves: */
+ if (nocied == 0) {
+ icmText *wo;
+ char *crt;
+ FILE *fp;
+
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icmMakeTag('t','a','r','g'), icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(in_name, "rb")) == NULL)
+#else
+ if ((fp = fopen(in_name, "r")) == NULL)
+#endif
+ error("Unable to open input file '%s' for reading",in_name);
+
+ if (fseek(fp, 0, SEEK_END))
+ error("Unable to seek to end of file '%s'",in_name);
+ wo->size = ftell(fp) + 1; /* Size needed + null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ if (fseek(fp, 0, SEEK_SET))
+ error("Unable to seek to end of file '%s'",in_name);
+
+ if (fread(wo->data, 1, wo->size-1, fp) != wo->size-1)
+ error("Failed to read file '%s'",in_name);
+ wo->data[wo->size-1] = '\000';
+ fclose(fp);
+
+ /* Duplicate for compatibility */
+ if (wr_icco->link_tag(
+ wr_icco, icmMakeTag('D','e','v','D'), icmMakeTag('t','a','r','g')) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ if (wr_icco->link_tag(
+ wr_icco, icmMakeTag('C','I','E','D'), icmMakeTag('t','a','r','g')) == NULL)
+ error("link_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error("No sets of data");
+
+ if (verb)
+ fprintf(verbo,"No of test patches = %d\n",npat);
+
+ /* Allocate arrays to hold test patch input and output values */
+ if ((tpat = (cow *)malloc(sizeof(cow) * npat)) == NULL)
+ error("Malloc failed - tpat[]");
+
+ /* Read in the CGATs fields */
+ {
+ int ti, ii, ci, mi, yi, ki;
+ int Xi, Yi, Zi;
+
+ /* Read the ink limit */
+ if (oink != NULL && (ii = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0) {
+ double ilimit = -1;
+ ilimit = atof(icg->t[0].kdata[ii]);
+ if (ilimit > 1e-4 && ilimit <= 400.0 && oink->tlimit < 0.0) {
+ oink->tlimit = ilimit/100.0; /* Set requested ink limit */
+ }
+ }
+
+ /* A sanity check */
+ if (isAdditive && oink != NULL && oink->tlimit > 0 && oink->tlimit < (double)devchan) {
+ warning("\n!!!!!!! Additive space has ink limit of %.0f%% set !!!!!!!\n"
+ ">> You probably don't want to do this, as it will limit the white point <<",oink->tlimit * 100.0);
+ }
+
+ /* Should targen/.ti3 file allow for BLACK_INK_LIMIT ?? */
+
+ /* A problem here is that if the .ti3 is corrupted, then */
+ /* often this results in the field type being "wrong", */
+ /* rather than a more inteligable message. */
+
+ if (devspace == icSigGrayData) {
+
+ if (isAdditive) {
+ if ((ci = icg->find_field(icg, 0, "GRAY_W")) < 0)
+ error("Input file doesn't contain field GRAY_W");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field GRAY_W is wrong type - corrupted file ?");
+ } else {
+ if ((ci = icg->find_field(icg, 0, "GRAY_K")) < 0)
+ error("Input file doesn't contain field GRAY_K");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field GRAY_K is wrong type - corrupted file ?");
+ }
+ mi = yi = ki = ci;
+
+ } else if (devspace == icSigRgbData) {
+
+ if ((ci = icg->find_field(icg, 0, "RGB_R")) < 0)
+ error("Input file doesn't contain field RGB_R");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field RGB_R is wrong type - corrupted file ?");
+ if ((mi = icg->find_field(icg, 0, "RGB_G")) < 0)
+ error("Input file doesn't contain field RGB_G");
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Field RGB_G is wrong type - corrupted file ?");
+ if ((yi = icg->find_field(icg, 0, "RGB_B")) < 0)
+ error("Input file doesn't contain field RGB_B");
+ if (icg->t[0].ftype[yi] != r_t)
+ error("Field RGB_B is wrong type - corrupted file ?");
+ ki = yi;
+
+ } else if (devspace == icSigCmyData) {
+
+ if ((ci = icg->find_field(icg, 0, "CMY_C")) < 0)
+ error("Input file doesn't contain field CMY_C");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field CMY_C is wrong type - corrupted file ?");
+ if ((mi = icg->find_field(icg, 0, "CMY_M")) < 0)
+ error("Input file doesn't contain field CMY_M");
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Field CMY_M is wrong type - corrupted file ?");
+ if ((yi = icg->find_field(icg, 0, "CMY_Y")) < 0)
+ error("Input file doesn't contain field CMY_Y");
+ if (icg->t[0].ftype[yi] != r_t)
+ error("Field CMY_Y is wrong type - corrupted file ?");
+ ki = yi;
+
+ } else { /* Assume CMYK */
+
+ if ((ci = icg->find_field(icg, 0, "CMYK_C")) < 0)
+ error("Input file doesn't contain field CMYK_C");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field CMYK_C is wrong type - corrupted file ?",icg->t[0].ftype[ci],r_t);
+ if ((mi = icg->find_field(icg, 0, "CMYK_M")) < 0)
+ error("Input file doesn't contain field CMYK_M");
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Field CMYK_M is wrong type - corrupted file ?");
+ if ((yi = icg->find_field(icg, 0, "CMYK_Y")) < 0)
+ error("Input file doesn't contain field CMYK_Y");
+ if (icg->t[0].ftype[yi] != r_t)
+ error("Field CMYK_Y is wrong type - corrupted file ?");
+ if ((ki = icg->find_field(icg, 0, "CMYK_K")) < 0)
+ error("Input file doesn't contain field CMYK_K");
+ if (icg->t[0].ftype[ki] != r_t)
+ error("Field CMYK_K is wrong type - corrupted file ?");
+ }
+
+ if (spec == 0) { /* Using instrument tristimulous value */
+
+ if (isLab) { /* Expect Lab */
+ if ((Xi = icg->find_field(icg, 0, "LAB_L")) < 0)
+ error("Input file doesn't contain field LAB_L");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error("Field LAB_L is wrong type - corrupted file ?");
+ if ((Yi = icg->find_field(icg, 0, "LAB_A")) < 0)
+ error("Input file doesn't contain field LAB_A");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error("Field LAB_A is wrong type - corrupted file ?");
+ if ((Zi = icg->find_field(icg, 0, "LAB_B")) < 0)
+ error("Input file doesn't contain field LAB_B");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error("Field LAB_B is wrong type - corrupted file ?");
+
+ } else { /* Expect XYZ */
+ if ((Xi = icg->find_field(icg, 0, "XYZ_X")) < 0)
+ error("Input file doesn't contain field XYZ_X");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error("Field XYZ_X is wrong type - corrupted file ?");
+ if ((Yi = icg->find_field(icg, 0, "XYZ_Y")) < 0)
+ error("Input file doesn't contain field XYZ_Y");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error("Field XYZ_Y is wrong type - corrupted file ?");
+ if ((Zi = icg->find_field(icg, 0, "XYZ_Z")) < 0)
+ error("Input file doesn't contain field XYZ_Z");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error("Field XYZ_Z is wrong type - corrupted file ?");
+ }
+
+ for (i = 0; i < npat; i++) {
+ tpat[i].w = 1.0;
+ tpat[i].p[0] = *((double *)icg->t[0].fdata[i][ci]) / 100.0;
+ tpat[i].p[1] = *((double *)icg->t[0].fdata[i][mi]) / 100.0;
+ tpat[i].p[2] = *((double *)icg->t[0].fdata[i][yi]) / 100.0;
+ tpat[i].p[3] = *((double *)icg->t[0].fdata[i][ki]) / 100.0;
+ if (tpat[i].p[0] > 1.0
+ || tpat[i].p[1] > 1.0
+ || tpat[i].p[2] > 1.0
+ || tpat[i].p[3] > 1.0) {
+ double bgst = 0.0;
+ int j, bj = 0;
+ for (j = 0; j < 4; j++) {
+ if (tpat[i].p[j] > bgst) {
+ bgst = tpat[i].p[j];
+ bj = j;
+ }
+ }
+ error("Device value field value exceeds 100.0 (%d:%d:%f) !",i,bj,bgst * 100.0);
+ }
+ tpat[i].v[0] = *((double *)icg->t[0].fdata[i][Xi]);
+ tpat[i].v[1] = *((double *)icg->t[0].fdata[i][Yi]);
+ tpat[i].v[2] = *((double *)icg->t[0].fdata[i][Zi]);
+ if (!isLab && (!isdisp || isdnormed != 0)) {
+ tpat[i].v[0] /= 100.0; /* Normalise XYZ to range 0.0 - 1.0 */
+ tpat[i].v[1] /= 100.0;
+ tpat[i].v[2] /= 100.0;
+ }
+ if (!isLab && wantLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
+ icmXYZ2Lab(&icmD50, tpat[i].v, tpat[i].v);
+ } else if (isLab && !wantLab) {
+ icmLab2XYZ(&icmD50, tpat[i].v, tpat[i].v);
+ }
+ }
+
+ } else { /* Using spectral data */
+ int ii;
+ xspect sp;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xsp2cie *sp2cie; /* Spectral conversion object */
+
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ sp.spec_n = atoi(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ sp.spec_wl_short = atof(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ sp.spec_wl_long = atof(icg->t[0].kdata[ii]);
+ if (!isdisp || isdnormed != 0)
+ sp.norm = 100.0;
+ else
+ sp.norm = 1.0;
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = icg->find_field(icg, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",buf);
+ }
+
+ if (isdisp) {
+ illum = icxIT_none; /* Displays are assumed to be self luminous */
+ cust_illum = NULL;
+ }
+
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie(illum, cust_illum, observ, NULL,
+ wantLab ? icSigLabData : icSigXYZData, icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+
+ /* If Fluorescent Whitening Agent compensation is enabled */
+ if (!isdisp && fwacomp) {
+ double nw = 0.0; /* Number of media white patches */
+ xspect mwsp; /* Medium spectrum */
+ instType itype; /* Spectral instrument type */
+ xspect insp; /* Instrument illuminant */
+ xspect tinsp, *tinspp = NULL; /* Target/simulated instrument illuminant */
+
+ mwsp = sp; /* Struct copy */
+
+ if ((ti = icg->find_kword(icg, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Can't find target instrument needed for FWA compensation");
+
+ if ((itype = inst_enum(icg->t[0].kdata[ti])) == instUnknown)
+ error ("Unrecognised target instrument '%s'", icg->t[0].kdata[ti]);
+
+ if (inst_illuminant(&insp, itype) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+
+ /* Find the media white spectral reflectance */
+ for (j = 0; j < mwsp.spec_n; j++)
+ mwsp.spec[j] = 0.0;
+
+ /* Compute the mean of all the media white patches */
+ for (i = 0; i < npat; i++) {
+ int use = 0;
+
+ if (devspace == icSigGrayData) {
+ if (isAdditive) {
+ if (*((double *)icg->t[0].fdata[i][ci]) > (100.0 - 0.1))
+ use = 1;
+ } else {
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1)
+ use = 1;
+ }
+ } else if (devspace == icSigRgbData) {
+ if (*((double *)icg->t[0].fdata[i][ci]) > (100.0 - 0.1)
+ && *((double *)icg->t[0].fdata[i][mi]) > (100.0 - 0.1)
+ && *((double *)icg->t[0].fdata[i][yi]) > (100.0 - 0.1))
+ use = 1;
+ } else if (devspace == icSigCmyData) {
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1
+ && *((double *)icg->t[0].fdata[i][mi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][yi]) < 0.1)
+ use = 1;
+ } else { /* Assume CMYK */
+
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1
+ && *((double *)icg->t[0].fdata[i][mi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][yi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][ki]) < 0.1) {
+ use = 1;
+ }
+ }
+
+ if (use) {
+ /* Read the spectral values for this patch */
+ for (j = 0; j < mwsp.spec_n; j++) {
+ mwsp.spec[j] += *((double *)icg->t[0].fdata[i][spi[j]]);
+ }
+ nw++;
+ }
+ }
+
+ if (nw == 0.0) {
+ warning("Can't find a media white patch to init FWA");
+
+ /* Track the maximum reflectance for any band to determine white. */
+ /* This might give bogus results if there is no white patch... */
+ for (i = 0; i < npat; i++) {
+ for (j = 0; j < mwsp.spec_n; j++) {
+ double rv = *((double *)icg->t[0].fdata[i][spi[j]]);
+ if (rv > mwsp.spec[j])
+ mwsp.spec[j] = rv;
+ }
+ }
+ nw++;
+ }
+ for (j = 0; j < mwsp.spec_n; j++) {
+ mwsp.spec[j] /= nw; /* Compute average */
+ }
+
+ /* If the simulated instrument illumination is */
+ /* not the observer/final illuminant */
+ if (tillum != icxIT_none) {
+ if (tillum == icxIT_custom)
+ tinspp = cust_tillum;
+ else {
+ tinspp = &tinsp;
+ if (standardIlluminant(tinspp, tillum, 0.0)) {
+ error("simulated inst. illum. not recognised");
+ }
+ }
+ }
+
+ /* (Note that sp and mwsp.norm is set to 100.0) */
+ if (sp2cie->set_fwa(sp2cie, &insp, tinspp, &mwsp))
+ error ("Set FWA on sp2cie failed");
+
+ if (verb) {
+ double FWAc;
+ sp2cie->get_fwa_info(sp2cie, &FWAc);
+ fprintf(verbo,"FWA content = %f\n",FWAc);
+ }
+ }
+
+ for (i = 0; i < npat; i++) {
+
+ tpat[i].w = 1.0;
+ tpat[i].p[0] = *((double *)icg->t[0].fdata[i][ci]) / 100.0;
+ tpat[i].p[1] = *((double *)icg->t[0].fdata[i][mi]) / 100.0;
+ tpat[i].p[2] = *((double *)icg->t[0].fdata[i][yi]) / 100.0;
+ tpat[i].p[3] = *((double *)icg->t[0].fdata[i][ki]) / 100.0;
+
+ if (tpat[i].p[0] > 1.0
+ || tpat[i].p[1] > 1.0
+ || tpat[i].p[2] > 1.0
+ || tpat[i].p[3] > 1.0) {
+ error("Device value field value exceeds 100.0 !");
+ }
+
+ /* Read the spectral values for this patch */
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+ }
+
+ /* Convert it to CIE space */
+ sp2cie->convert(sp2cie, tpat[i].v, &sp);
+
+ }
+
+ sp2cie->del(sp2cie); /* Done with this */
+
+ }
+
+ /* Normalize display values to Y = 1.0 if needed */
+ /* (re-norm spec derived, since observer may be different) */
+ if (isdisp && (isdnormed == 0 || spec != 0)) {
+ double scale = -1e6;
+
+ if (wantLab) {
+ double bxyz[3];
+
+ /* Locate max Y */
+ for (i = 0; i < npat; i++) {
+ icmLab2XYZ(&icmD50, bxyz, tpat[i].v);
+ if (bxyz[1] > scale)
+ scale = bxyz[1];
+ }
+
+ scale = 1.0/scale;
+
+ /* Scale max Y to 1.0 */
+ for (i = 0; i < npat; i++) {
+ icmLab2XYZ(&icmD50, tpat[i].v, tpat[i].v);
+ tpat[i].v[0] *= scale;
+ tpat[i].v[1] *= scale;
+ tpat[i].v[2] *= scale;
+ icmXYZ2Lab(&icmD50, tpat[i].v, tpat[i].v);
+ }
+ } else {
+
+ /* Locate max Y */
+ for (i = 0; i < npat; i++) {
+ if (tpat[i].v[1] > scale)
+ scale = tpat[i].v[1];
+ }
+
+ scale = 1.0/scale;
+
+ for (i = 0; i < npat; i++) {
+ tpat[i].v[0] *= scale;
+ tpat[i].v[1] *= scale;
+ tpat[i].v[2] *= scale;
+ }
+ }
+ }
+ } /* End of reading in CGATs file */
+
+ if (isLut) {
+ xicc *wr_xicc; /* extention object */
+ icxLuBase *AtoB; /* AtoB ixcLu */
+
+ /* Create A2B clut */
+ {
+ int flags = 0;
+
+ /* Wrap with an expanded icc */
+ if ((wr_xicc = new_xicc(wr_icco)) == NULL)
+ error("Creation of xicc failed");
+
+ flags |= ICX_CLIP_NEAREST; /* This will avoid clip caused rev setup */
+
+ if (noisluts)
+ flags |= ICX_NO_IN_SHP_LUTS;
+
+ if (noipluts)
+ flags |= ICX_NO_IN_POS_LUTS;
+
+ if (nooluts)
+ flags |= ICX_NO_OUT_LUTS;
+
+ if (clipprims)
+ flags |= ICX_CLIP_WB;
+
+ if (verb)
+ flags |= ICX_VERBOSE;
+
+ flags |= ICX_SET_WHITE | ICX_SET_BLACK; /* Compute & use white & black */
+
+ /* Setup Device -> PCS conversion (Fwd) object from scattered data. */
+ if ((AtoB = wr_xicc->set_luobj(
+ wr_xicc, icmFwd, !allintents ? icmDefaultIntent : icRelativeColorimetric,
+ icmLuOrdNorm,
+#ifdef USE_EXTRA_FITTING
+ ICX_EXTRA_FIT |
+#endif
+#ifdef USE_2PASSSMTH
+ ICX_2PASSSMTH |
+#endif
+ flags,
+ npat, npat, tpat, NULL, dispLuminance, -1.0, smooth, avgdev,
+ NULL, oink, cal, iquality)) == NULL)
+ error("%d, %s",wr_xicc->errc, wr_xicc->err);
+
+ AtoB->del(AtoB); /* Done with lookup */
+ }
+
+ /* Create B2A clut */
+ {
+ icc *src_icco = NULL;
+ xicc *src_xicc = NULL; /* Source profile */
+ icxViewCond ivc; /* Input Viewing Condition for CAM */
+ icxViewCond ovc; /* Output Viewing Condition for CAM */
+ icmFile *abs_fp[3] = { NULL, NULL, NULL }; /* Abstract profile transform: */
+ icc *abs_icc[3] = { NULL, NULL, NULL };
+ xicc *abs_xicc[3] = { NULL, NULL, NULL };
+ icmLut *wo[3];
+
+ out_b2a_callback cx;
+
+ if (verb)
+ printf("Setting up B to A table lookup\n");
+
+#ifdef FILTER_B2ACLIP
+ cx.filter = 1;
+ cx.filter_thr = FILTER_THR_DE;
+ cx.filter_ratio = FILTER_MAX_RAD/FILTER_MAX_DE;
+ cx.filter_maxrad = FILTER_MAX_RAD;
+#else
+ cx.filter = 0;
+ cx.filter_thr = 100.0;
+ cx.filter_ratio = 0.0;
+ cx.filter_maxrad = 0.0;
+#endif
+
+ if (ipname != NULL) { /* There is a source profile to determine gamut mapping */
+
+ /* Open up the profile for reading */
+ if ((src_icco = read_embedded_icc(ipname)) == NULL)
+ error ("Can't open file '%s'",ipname);
+
+ /* Wrap with an expanded icc */
+ if ((src_xicc = new_xicc(src_icco)) == NULL)
+ error ("Creation of src_xicc failed");
+ }
+
+ /* Figure out the final src & dst viewing conditions */
+ for (i = 0; i < 2; i++) {
+ xicc *x;
+ icxViewCond *v, *vc;
+ int es;
+
+ if (i == 0) { /* Input */
+ v = ivc_p; /* Override parameters */
+ es = ivc_e;
+ vc = &ivc; /* Target parameters */
+ if (src_xicc == NULL)
+ continue; /* Source viewing conditions won't be used */
+ x = src_xicc;
+ } else { /* Output */
+ v = ovc_p; /* Override parameters */
+ es = ovc_e;
+ vc = &ovc; /* Target parameters */
+ x = wr_xicc;
+ }
+
+ /* Set the default */
+ xicc_enum_viewcond(x, vc, -1, NULL, 0, NULL);
+
+ /* Override the viewing conditions */
+ if (es >= 0)
+ if (xicc_enum_viewcond(x, vc, es, NULL, 0, NULL) == -2)
+ error ("%d, %s",x->errc, x->err);
+ if (v->Ev >= 0)
+ vc->Ev = v->Ev;
+ if (v->Wxyz[0] >= 0.0 && v->Wxyz[1] > 0.0 && v->Wxyz[2] >= 0.0) {
+ /* Normalise XYZ to current media white */
+ vc->Wxyz[0] = v->Wxyz[0]/v->Wxyz[1] * vc->Wxyz[1];
+ vc->Wxyz[2] = v->Wxyz[2]/v->Wxyz[1] * vc->Wxyz[1];
+ }
+ if (v->Wxyz[0] >= 0.0 && v->Wxyz[1] >= 0.0 && v->Wxyz[2] < 0.0) {
+ /* Convert Yxy to XYZ */
+ double x = v->Wxyz[0];
+ double y = v->Wxyz[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
+ double z = 1.0 - x - y;
+ vc->Wxyz[0] = x/y * vc->Wxyz[1];
+ vc->Wxyz[2] = z/y * vc->Wxyz[1];
+ }
+ if (v->La >= 0.0)
+ vc->La = v->La;
+ if (v->Yb >= 0.0)
+ vc->Yb = v->Yb;
+ if (v->Lv >= 0.0)
+ 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) {
+ /* 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];
+ }
+ if (v->Fxyz[0] >= 0.0 && v->Fxyz[1] >= 0.0 && v->Fxyz[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 z = 1.0 - x - y;
+ vc->Fxyz[0] = x/y * vc->Fxyz[1];
+ vc->Fxyz[2] = z/y * vc->Fxyz[1];
+ }
+ }
+
+ /* Get a suitable forward conversion object to invert. */
+ /* By creating a separate one to the one created using scattered data, */
+ /* we get the chance to set ICX_CAM_CLIP. */
+ {
+ int flags = 0;
+
+ if (verb)
+ flags |= ICX_VERBOSE;
+
+ flags |= ICX_CLIP_NEAREST; /* Not vector clip */
+#ifdef USE_CAM_CLIP_OPT
+ flags |= ICX_CAM_CLIP; /* Clip in CAM Jab space rather than Lab */
+#else
+ warning("!!!! USE_CAM_CLIP_OPT in profout.c is off !!!!");
+#endif
+
+ if ((AtoB = wr_xicc->get_luobj(wr_xicc, flags, icmFwd,
+ !allintents ? icmDefaultIntent : icRelativeColorimetric,
+ wantLab ? icSigLabData : icSigXYZData,
+ icmLuOrdNorm, &ovc, oink)) == NULL)
+ error ("%d, %s",wr_xicc->errc, wr_xicc->err);
+ }
+
+ /* setup context ready for B2A table setting */
+ cx.verb = verb;
+ cx.pcsspace = wantLab ? icSigLabData : icSigXYZData;
+#ifdef NO_B2A_PCS_CURVES
+ cx.noPCScurves = 1; /* Don't use PCS curves */
+#else
+ cx.noPCScurves = 0;
+#endif
+ cx.devspace = devspace;
+ cx.x = (icxLuLut *)AtoB; /* A2B icxLuLut created from scattered data */
+
+ cx.ixp = NULL; /* Perceptual PCS to CAM conversion */
+ cx.ox = NULL; /* CAM to PCS conversion */
+ cx.pmap = NULL; /* perceptual gamut map */
+ cx.smap = NULL; /* Saturation gamut map */
+
+ cx.abs_luo[0] = cx.abs_luo[1] = cx.abs_luo[2] = NULL;
+ cx.xyzscale[0] = 1.0;
+ cx.xyzscale[1] = 1.0;
+ cx.gam = NULL;
+ cx.wantLab = wantLab; /* Copy PCS flag over */
+
+ /* Determine the number of tables */
+ cx.ntables = 1;
+ if (src_xicc) { /* Creating separate perceptual and Saturation tables */
+ cx.ntables = 2;
+ if (sepsat)
+ cx.ntables = 3;
+ }
+
+ /* Open up the abstract profile if supplied, and setup luo */
+ for (i = 0; i < cx.ntables; i++) {
+ if (absname[i] != NULL && cx.abs_luo[i] == NULL) {
+
+ if ((abs_fp[i] = new_icmFileStd_name(absname[i],"r")) == NULL)
+ error ("Can't open abstract profile file '%s'",absname[i]);
+
+ if ((abs_icc[i] = new_icc()) == NULL)
+ error ("Creation of Abstract profile ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = abs_icc[i]->read(abs_icc[i],abs_fp[i],0)) != 0)
+ error ("%d, %s",rv,abs_icc[i]->err);
+
+ if (abs_icc[i]->header->deviceClass != icSigAbstractClass)
+ error("Abstract profile isn't an abstract profile");
+
+ /* Take intended abstract intent from profile itself */
+ if ((cx.abs_intent[i] = abs_icc[i]->header->renderingIntent) != icAbsoluteColorimetric)
+ cx.abs_intent[i] = icRelativeColorimetric;
+
+ /* Wrap with an expanded icc */
+ if ((abs_xicc[i] = new_xicc(abs_icc[i])) == NULL)
+ error ("Creation of abstract profile xicc failed");
+
+ /* The abstract profile intent is assumed to determine how it gets applied. */
+ /* Make abstract PCS XYZ if icAbsoluteColorimetric is needed. */
+ if ((cx.abs_luo[i] = abs_xicc[i]->get_luobj(abs_xicc[i], ICX_CLIP_NEAREST, icmFwd,
+ cx.abs_intent[i],
+ (cx.pcsspace == icSigLabData && cx.abs_intent[i] == icRelativeColorimetric)
+ ? icSigLabData : icSigXYZData,
+ icmLuOrdNorm, NULL, NULL)) == NULL)
+ error ("%d, %s",abs_icc[i]->errc, abs_icc[i]->err);
+
+ /* If the same abstract profile is used in the other tables, */
+ /* duplicate the transform pointer */
+ for (j = i; j < cx.ntables; j++) {
+ if (absname[i] == absname[j]) {
+ cx.abs_intent[j] = cx.abs_intent[i];
+ cx.abs_luo[j] = cx.abs_luo[i];
+ if (verb)
+ printf("Applying %s abstract profile '%s' to %s table\n",
+ i == 0 ? "first" : i == 1 ? "second" : "third",
+ absname[i],
+ j == 0 ? "colorimetric" : j == 1 ? "perceptual" : "saturation");
+ }
+ }
+ }
+ }
+
+ if (!allintents) { /* Only B2A0, no intent */
+ if ((wo[0] = (icmLut *)wr_icco->read_tag(
+ wr_icco, icSigBToA0Tag)) == NULL)
+ error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ } else { /* All 3 intent tables */
+ /* Intent 1 = relative colorimetric */
+ if ((wo[0] = (icmLut *)wr_icco->read_tag(
+ wr_icco, icSigBToA1Tag)) == NULL)
+ error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ if (src_xicc) { /* Creating separate perceptual and Saturation tables */
+ icRenderingIntent intentp; /* Gamut mapping space perceptual selection */
+ icRenderingIntent intents; /* Gamut mapping space saturation selection */
+ icRenderingIntent intento; /* Gamut mapping space output selection */
+ gamut *csgamp; /* Incoming colorspace perceptual gamut */
+ gamut *csgams; /* Incoming colorspace saturation gamut */
+ gamut *igam = NULL; /* Incoming image gamut */
+ gamut *ogam; /* Destination colorspace gamut */
+ double gres; /* Gamut surface feature resolution */
+ int mapres; /* Mapping rspl resolution */
+
+ if (verb)
+ printf("Creating Gamut Mapping\n");
+
+ /* Gamut mapping will extend given grid res to encompas */
+ /* source gamut by a margin. */
+ if (oquality == 3) { /* Ultra High */
+ gres = 8.0;
+ mapres = 41;
+ } else if (oquality == 2) { /* High */
+ gres = 8.0;
+ mapres = 33;
+ } else if (oquality == 1) { /* Medium */
+ gres = 10.0;
+ mapres = 25;
+ } else if (oquality == 0) { /* Low quality */
+ gres = 12.0;
+ mapres = 17;
+ } else { /* Extremely low */
+ gres = 14.0;
+ mapres = 9;
+ }
+
+ /* We could lift this restriction by allowing for separate */
+ /* 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) {
+ intentp = noptop ? icxAppearance : icxPerceptualAppearance;
+ }
+ 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) {
+ intents = nostos ? icxAppearance : icxSaturationAppearance;
+ }
+ }
+ /* Default output gamut mapping space is absolute colorimetric */
+ intento = icAbsoluteColorimetric;
+
+ /* But override this for apperance space gamut mapping */
+ if ((pgmi->usecas & 0xff) != 0x0) {
+ intento = icxAppearance;
+ }
+
+ if ((pgmi->usecas & 0xff) == 0x2) {
+ double mxw;
+ intentp = intents = intento = icxAbsAppearance;
+
+ /* Make absolute common white point average between the two */
+ ivc.Wxyz[0] = 0.5 * (ivc.Wxyz[0] + ovc.Wxyz[0]);
+ ivc.Wxyz[1] = 0.5 * (ivc.Wxyz[1] + ovc.Wxyz[1]);
+ ivc.Wxyz[2] = 0.5 * (ivc.Wxyz[2] + ovc.Wxyz[2]);
+
+ /* And scale it's Y to be equal to 1.0 */
+ mxw = 1.0/ivc.Wxyz[1];
+ ivc.Wxyz[0] *= mxw;
+ ivc.Wxyz[1] *= mxw;
+ ivc.Wxyz[2] *= mxw;
+
+ /* set output view conditions the same as the input */
+ ovc = ivc; /* Structure copy */
+ }
+
+ /* Unlike icclink, we've not provided a way for the user */
+ /* to set the source profile ink limit, so estimate it */
+ /* from the profile */
+ icxDefaultLimits(src_xicc, &iink.tlimit, iink.tlimit,
+ &iink.klimit, iink.klimit);
+
+ /* Get lookup object simply for fwd_relpcs_outpcs() */
+ /* and perceptual input gamut shell creation. */
+ /* Note that the intent=Appearance will trigger Jab CAM, */
+ /* overriding icSigLabData.. */
+#ifdef NEVER
+ printf("~1 input space flags = 0x%x\n",ICX_CLIP_NEAREST);
+ printf("~1 input space intent = %s\n",icx2str(icmRenderingIntent,intentp));
+ printf("~1 input space pcs = %s\n",icx2str(icmColorSpaceSignature,icSigLabData));
+ printf("~1 input space viewing conditions =\n"); xicc_dump_viewcond(&ivc);
+ printf("~1 input space inking =\n"); xicc_dump_inking(&iink);
+#endif
+ if ((cx.ixp = src_xicc->get_luobj(src_xicc,ICX_CLIP_NEAREST
+ , icmFwd, intentp, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL)
+ error ("%d, %s",src_xicc->errc, src_xicc->err);
+
+ /* Create the source colorspace gamut surface */
+ if (verb)
+ printf(" Finding Source Colorspace Perceptual Gamut\n");
+
+ if ((csgamp = cx.ixp->get_gamut(cx.ixp, gres)) == NULL)
+ error ("%d, %s",src_xicc->errc, src_xicc->err);
+
+ if (sepsat) {
+ icxLuBase *ixs = NULL; /* Source profile saturation lookup for gamut */
+ /* Get lookup object for saturation input gamut shell creation */
+ /* Note that the intent=Appearance will trigger Jab CAM, */
+ /* overriding icSigLabData.. */
+ if ((ixs = src_xicc->get_luobj(src_xicc, ICX_CLIP_NEAREST
+ , icmFwd, intents, icSigLabData, icmLuOrdNorm, &ivc, &iink)) == NULL)
+ error ("%d, %s",src_xicc->errc, src_xicc->err);
+
+ if (verb)
+ printf(" Finding Source Colorspace Saturation Gamut\n");
+
+ if ((csgams = ixs->get_gamut(ixs, gres)) == NULL)
+ error ("%d, %s",src_xicc->errc, src_xicc->err);
+ ixs->del(ixs);
+ }
+
+ /* Read image source gamut if provided */
+ if (sgname != NULL) { /* Optional source gamut - ie. from an images */
+ int isJab = 0;
+
+ if ((pgmi->usecas & 0xff) != 0)
+ isJab = 1;
+
+ if (verb)
+ printf(" Loading Image Source Gamut '%s'\n",sgname);
+
+ igam = new_gamut(gres, 0, 0);
+
+ if (igam->read_gam(igam, sgname))
+ error("Reading source gamut '%s' failed",sgname);
+
+ if (igam->getisjab(igam) != isJab) {
+ /* Should really convert to/from Jab here! */
+ warning("Image gamut is wrong colorspace for gamut mapping (Lab != Jab)");
+ /* This will actually error in the gamut mapping code */
+ /* Note that we're not checking relative/absolute colorspace here. */
+ /* At the moment it's up to the user to get this right. */
+ }
+ }
+
+ /* Get lookup object for bwd_outpcs_relpcs(), */
+ /* and output gamut shell creation */
+ /* Note that the intent=Appearance will trigger Jab CAM, */
+ /* overriding icSigLabData.. */
+ if ((cx.ox = wr_xicc->get_luobj(wr_xicc, ICX_CLIP_NEAREST
+ , icmFwd, intento,
+ icSigLabData, icmLuOrdNorm, &ovc, oink)) == NULL)
+ error ("%d, %s",wr_xicc->errc, wr_xicc->err);
+
+ /* Creat the destination gamut surface */
+ if (verb)
+ printf(" Finding Destination Gamut\n");
+
+ if ((ogam = cx.ox->get_gamut(cx.ox, gres)) == NULL)
+ error ("%d, %s",wr_xicc->errc, wr_xicc->err);
+
+ if (verb)
+ printf(" Creating Gamut match\n");
+
+ /* The real range of Lab 0..100,-128..128,1-28..128 cube */
+ /* when mapped to CAM is ridiculously large (ie. */
+ /* 0..100, -288..265, -112..533), so we don't attempt to */
+ /* set a gamut mapping grid range based on this. Instead */
+ /* rely on the gamut map code to set a reasonable grid range */
+ /* around the source gamut, and to cope reasonably with */
+ /* values outside the grid range. */
+
+ /* setup perceptual gamut mapping */
+ cx.pmap = new_gammap(verb, csgamp, igam, ogam, pgmi, 0, 0, 0, 0, mapres,
+ NULL, NULL, gamdiag ? "gammap_p.wrl" : NULL
+ );
+ if (cx.pmap == NULL)
+ error ("Failed to make perceptual gamut map transform");
+
+ /* Intent 0 = perceptual */
+ if ((wo[1] = (icmLut *)wr_icco->read_tag(
+ wr_icco, icSigBToA0Tag)) == NULL)
+ error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ if (sepsat) {
+ /* setup saturation gamut mapping */
+ cx.smap = new_gammap(verb, csgams, igam, ogam, sgmi, 0, 0, 0, 0, mapres,
+ NULL, NULL, gamdiag ? "gammap_s.wrl" : NULL
+ );
+ if (cx.smap == NULL)
+ error ("Failed to make saturation gamut map transform");
+
+ /* Intent 2 = saturation */
+ if ((wo[2] = (icmLut *)wr_icco->read_tag(
+ wr_icco, icSigBToA2Tag)) == NULL)
+ error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+ }
+ csgamp->del(csgamp);
+ csgamp = NULL;
+ if (sepsat) {
+ csgams->del(csgams);
+ csgams = NULL;
+ }
+ if (igam != NULL) {
+ igam->del(igam);
+ igam = NULL;
+ }
+ ogam->del(ogam);
+ ogam = NULL;
+ }
+ }
+ cx.ochan = wo[0]->outputChan;
+
+ /* If we've got a request for Absolute Appearance mode with scaling */
+ /* to avoid clipping the source white point, compute the needed XYZ scaling factor. */
+ if (src_xicc != NULL && allintents
+ && ((pgmi->usecas & 0x100) || (sgmi->usecas & 0x100))) {
+ double swcam[3];
+ double xyzscale[1], sa[1];
+
+ /* Grab the source white point in CAM space */
+ cx.ixp->efv_wh_bk_points(cx.ixp, swcam, NULL, NULL);
+
+ /* Convert it to destination XYZ */
+ /* We're being bad in delving inside the xluo, but we'll fix it latter */
+ cx.ox->cam->cam_to_XYZ(cx.ox->cam, cx.swxyz, swcam);
+
+//printf("~1 Source white Jab = %f %f %f\n", swcam[0], swcam[1], swcam[2]);
+//printf("~1 Source white XYZ = %f %f %f\n", cx.swxyz[0], cx.swxyz[1], cx.swxyz[2]);
+
+ /* Compute the bigest scale factor less than or equal to 1.0, */
+ /* that doesn't clip the cx.swxyz[] on the destination gamut */
+ sa[0] = 0.1;
+ xyzscale[0] = 0.5;
+ if (powell(NULL, 1, xyzscale, sa, 1e-6, 2000,
+ xyzoptfunc, (void *)&cx, NULL, NULL) != 0) {
+ warning("make_output_icc: XYZ scale powell failed to converge - set scale to 1.0");
+ } else {
+ if (pgmi->usecas & 0x100) {
+ cx.xyzscale[0] = xyzscale[0];
+ if (cx.verb) printf("Set Perceptual XYZ scale factor to %f\n",xyzscale[0]);
+ }
+ if (sgmi->usecas & 0x100) {
+ cx.xyzscale[1] = xyzscale[0];
+ if (cx.verb) printf("Set Saturation XYZ scale factor to %f\n",xyzscale[0]);
+ }
+ }
+ }
+
+// ====================================================================
+#ifdef NEVER
+// ~~99
+ /* DEVELOPMENT CODE - not complete */
+ /* Setup optimised B2A per channel curves */
+ {
+ xfit *xf; /* Curve fitting class instance */
+ int xfflags = 0; /* xfit flags */
+ double in_min[MXDI]; /* Input value scaling minimum */
+ double in_max[MXDI]; /* Input value scaling maximum */
+ double out_min[MXDO]; /* Output value scaling minimum */
+ double out_max[MXDO]; /* Output value scaling maximum */
+ int iluord, oluord;
+ int iord[MXDI]; /* Input curve orders */
+ int oord[MXDO]; /* Output curve orders */
+ int nodp; /* Number of inverse data points */
+ co *points; /* List of inverse points as PCS->dev */
+
+ optcomb tcomb = oc_imo; /* Create all by default */
+
+ if ((xf = new_xfit()) == NULL) {
+ error("profout: Creation of xfit object failed");
+ }
+
+ /* Setup for optimising run */
+ if (nooluts) /* Use option flags - swap sense for B2A */
+ tcomb &= ~oc_i;
+
+ if (noiluts)
+ tcomb &= ~oc_o;
+
+ if (verb)
+ xfflags |= XFIT_VERB;
+
+ xfflags |= XFIT_OUT_DEV; /* Outpupt is device */
+ /* (Switch to XFIT_OUT_LU latter ?) */
+ if (cx.pcsspace == icSigLabData)
+ xfflags |= XFIT_IN_ZERO; /* Adjust a & b to zero */
+
+~~~~~~~~~~~~~~~~~~~
+ /* Set the curve order for input (PCS) */
+ if (oquality >= 3) { /* Ultra high */
+ iluord = 25;
+ nodp = 2000;
+ } else if (oquality == 2) { /* High */
+ iluord = 20;
+ nodp = 1000;
+ } else if (oquality == 1) { /* Medium */
+ iluord = 17;
+ nodp = 750;
+ } else { /* Low */
+ iluord = 10;
+ nodp = 500;
+ }
+ for (e = 0; e < p->inputChan; e++) {
+ iord[e] = iluord;
+ in_min[e] = p->inmin[e];
+ in_max[e] = p->inmax[e];
+
+ /* Hack to prevent a convex L curve pushing */
+ /* the clut L values above the maximum value */
+ /* that can be represented, causing clipping. */
+ /* Do this by making sure that the L curve pivots */
+ /* through 100.0 to 100.0 */
+ if (e == 0 && cx.pcsspace == icSigLabData) {
+ if (in_min[e] < 0.0001 && in_max[e] > 100.0) {
+ in_max[e] = 100.0;
+ }
+ }
+ }
+
+ /* Set curve order for output (Device) */
+ if (oquality >= 3) { /* Ultra high */
+ oluord = 25;
+ } else if (oquality == 2) { /* High */
+ oluord = 20;
+ } else if (oquality == 1) { /* Medium */
+ oluord = 17;
+ } else { /* Low */
+ oluord = 10;
+ }
+ for (f = 0; f < p->outputChan; f++) {
+ oord[f] = oluord;
+ out_min[f] = p->outmin[f];
+ out_max[f] = p->outmax[f];
+
+ }
+
+ /* Create the sample points */
+ ~~~~~~~~~~~
+ malloc
+
+ for (i = 0; i < nodp;) {
+ generate random pcs value
+
+ if not within gamut
+ continue;
+
+ lookup through overall conversion
+ i++;
+ }
+
+ /* Fit input and output curves to our data points */
+ if (xf->fit(xf, xfflags, p->inputChan, p->outputChan, nodp, points,
+ in_min, in_max, out_min, out_max, iord, oord, tcomb, NULL) != 0) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"xfit fitting failed");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Set the xicc input curve rspl */
+ for (e = 0; e < p->inputChan; e++) {
+ curvectx cx;
+
+ cx.xf = xf;
+ cx.oix = -1;
+ cx.iix = e;
+
+ if ((p->inputTable[e] = new_rspl(1, 1)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of input table rspl failed");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ p->inputTable[e]->set_rspl(p->inputTable[e], RSPL_NOFLAGS,
+ (void *)&cx, set_linfunc,
+ &p->ninmin[e], &p->ninmax[e],
+ &p->lut->inputEnt,
+ &p->ninmin[e], &p->ninmax[e]);
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Set the xicc output curve rspl */
+
+ /* Allow for a bigger than normal input and output range, to */
+ /* give some leaway in accounting for approximate white point shifted */
+ /* profile creation. */
+ for (f = 0; f < p->outputChan; f++) {
+ double min[1], max[1], exval;
+ int entries;
+ curvectx cx;
+
+ cx.xf = xf;
+ cx.iix = -1;
+ cx.oix = f;
+
+ /* Expand in and out range by 1.05 */
+ exval = (p->noutmax[f] - p->noutmin[f]);
+ min[0] = p->noutmin[f] - exval * 0.05 * 0.5;
+ max[0] = p->noutmax[f] + exval * 0.05 * 0.5;
+ entries = (int)(1.05 * (double)p->lut->outputEnt + 0.5);
+
+ if ((p->outputTable[f] = new_rspl(1, 1)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of output table rspl failed");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ p->outputTable[f]->set_rspl(p->outputTable[f], RSPL_NOFLAGS,
+ (void *)&cx, set_linfunc,
+ min, max, &entries, min, max);
+
+ }
+
+ xf->del(xf);
+ }
+#endif /* NEVER (Setup optimised B2A per channel curves) */
+// ====================================================================
+
+ /* We now setup an exact inverse, colorimetric style, plus gamut mapping */
+ /* for perceptual and saturation intents */
+ /* Use helper function to do the hard work. */
+
+ if (cx.verb) {
+ unsigned int ui;
+ int extra;
+ cx.count = 0;
+ cx.last = -1;
+ for (cx.total = 1, ui = 0; ui < wo[0]->inputChan; ui++, cx.total *= wo[0]->clutPoints)
+ ;
+ /* Add in cell center points */
+ for (extra = 1, ui = 0; ui < wo[0]->inputChan; ui++, extra *= (wo[0]->clutPoints-1))
+ ;
+ cx.total += extra;
+ printf("Creating B to A tables\n");
+ printf(" 0%%"); fflush(stdout);
+ }
+
+#ifdef DEBUG_ONE
+#define DBGNO 1 /* Up to 10 */
+
+ /* Test a single given PCS (Rel D50 Lab) -> cmyk value */
+ {
+ double in[10][MAX_CHAN];
+ double out[MAX_CHAN];
+ in[0][0] = 100.0; /* White point */
+ in[0][1] = 0.001;
+ in[0][2] = 0.001;
+
+ for (i = 0; i < DBGNO; i++) {
+ printf("Input %s\n",icmPdv(3,in[i]));
+ out_b2a_input((void *)&cx, out, in[i]);
+ printf("Input' %s\n",icmPdv(3,out));
+ out_b2a_clut((void *)&cx, out, out);
+ printf("Output' %s\n\n",icmPdv(4,out));
+ out_b2a_output((void *)&cx, out, out);
+ printf("Output %s\n\n",icmPdv(4,out));
+ }
+ }
+#else /* !DEBUG_ONE */
+
+#ifndef USE_LEASTSQUARES_APROX
+ fprintf(stderr,"!!!!! profile/profout: USE_LEASTSQUARES_APROX undef !!!!!\n");
+#endif
+ if (icmSetMultiLutTables(
+ cx.ntables,
+ wo,
+#ifdef USE_LEASTSQUARES_APROX
+ ICM_CLUT_SET_APXLS |
+#endif
+#ifdef FILTER_B2ACLIP
+ 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 */
+ error("Setting 16 bit PCS->Device Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+ if (cx.verb) {
+ printf("\n");
+ }
+
+#ifdef WARN_CLUT_CLIPPING /* Print warning if setting clut clips */
+ /* Ignore clipping of the input table, because this happens */
+ /* anyway due to Lab symetry adjustment. */
+ if (wr_icco->warnc != 0 && wr_icco->warnc != 1) {
+ warning("Values clipped in setting B2A LUT!");
+ }
+#endif /* WARN_CLUT_CLIPPING */
+#endif /* !DEBUG_ONE */
+
+ /* Free up abstract transform */
+ for (i = 0; i < cx.ntables; i++) {
+ if (cx.abs_luo[i] != NULL) {
+ for (j = cx.ntables-1; j >= i; j--) { /* Free all duplicates */
+ if (cx.abs_luo[j] == cx.abs_luo[i]) {
+ cx.abs_luo[j]->del(cx.abs_luo[j]);
+ abs_xicc[j]->del(abs_xicc[j]);
+ abs_icc[j]->del(abs_icc[j]);
+ abs_fp[j]->del(abs_fp[j]);
+ cx.abs_luo[j] = NULL;
+ }
+ }
+ }
+ }
+
+ if (cx.pmap != NULL)
+ cx.pmap->del(cx.pmap), cx.pmap = NULL;
+ if (cx.smap != NULL)
+ cx.smap->del(cx.smap), cx.smap = NULL;
+ if (cx.ixp != NULL)
+ cx.ixp->del(cx.ixp), cx.ixp = NULL;
+ if (cx.ox != NULL)
+ cx.ox->del(cx.ox), cx.ox = NULL;
+
+ if (src_xicc != NULL)
+ src_xicc->del(src_xicc), src_xicc = NULL;
+ if (src_icco != NULL)
+ src_icco->del(src_icco), src_icco = NULL;
+
+ if (verb)
+ printf("Done B to A tables\n");
+ }
+
+ /* Set the ColorantTable PCS values */
+ {
+ unsigned int i;
+ icmColorantTable *wo;
+ double dv[MAX_CHAN];
+
+ if ((wo = (icmColorantTable *)wr_icco->read_tag(
+ wr_icco, icSigColorantTableTag)) == NULL)
+ error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ for (i = 0; i < wo->count; i++)
+ dv[i] = 0.0;
+
+ /* Lookup the colorant PCS values the recommended ICC way */
+ for (i = 0; i < wo->count; i++) {
+ dv[i] = 1.0;
+ AtoB->lookup(AtoB, wo->data[i].pcsCoords, dv);
+ dv[i] = 0.0;
+ }
+ }
+
+#ifndef DISABLE_GAMUT_TAG
+ /* Create Gamut clut for output type */
+ /* This is not mandated for V2.4.0 Display profiles, but add it anyway */
+ if (allintents) {
+ icmLut *wo;
+ out_b2a_callback cx;
+ double gres = 0.0;
+
+ cx.verb = verb;
+ cx.pcsspace = wantLab ? icSigLabData : icSigXYZData;
+ cx.devspace = devspace;
+ cx.x = (icxLuLut *)AtoB; /* A2B icxLuLut */
+
+ if (verb)
+ printf("Creating gamut boundary table\n");
+
+ /* Need to switch AtoB to be override Lab PCS */
+ /* Do this the dirty way, by delving into xicclu and icclu. Alternatively */
+ /* we could create an xlut set method, delete AtoB and recreate it, */
+ /* or fix get_gamut to independently override convert to icmSigLabData */
+ /* ~~~~~~~~999 should fix this !!! */
+ cx.x->outs = icSigLabData;
+ cx.x->pcs = icSigLabData;
+ cx.x->plu->e_outSpace = icSigLabData;
+ cx.x->plu->e_pcs = icSigLabData;
+ cx.wantLab = wantLab; /* Copy PCS flag over */
+
+ if (oquality == 3) { /* Ultra High */
+ gres = 8.0;
+ } else if (oquality == 2) { /* High */
+ gres = 9.0;
+ } else if (oquality == 1) { /* Medium */
+ gres = 10.0;
+ } else if (oquality == 0) { /* Low quality */
+ gres = 12.0;
+ } else { /* Extremely low */
+ gres = 15.0;
+ }
+
+ /* Creat a gamut surface */
+ if ((cx.gam = AtoB->get_gamut(AtoB, gres)) == NULL)
+ error("Get_gamut failed: %d, %s",AtoB->pp->errc,AtoB->pp->err);
+
+ if ((wo = (icmLut *)wr_icco->read_tag(
+ wr_icco, icSigGamutTag)) == NULL)
+ error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ if (cx.verb) {
+ unsigned int ui;
+ cx.count = 0;
+ cx.last = -1;
+ for (cx.total = 1, ui = 0; ui < wo->inputChan; ui++, cx.total *= wo->clutPoints)
+ ;
+ printf(" 0%%"); fflush(stdout);
+ }
+#ifndef DEBUG_ONE /* Skip this when debugging */
+ if (wo->set_tables(wo,
+ ICM_CLUT_SET_EXACT,
+ &cx, /* Context */
+ cx.pcsspace, /* Input color space */
+ icSigGrayData, /* Output color space */
+ out_b2a_input, /* Input transform PCS->PCS' */
+ 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 */
+ error("Setting 16 bit PCS->Device Gamut Lut failed: %d, %s",wr_icco->errc,wr_icco->err);
+#endif /* !DEBUG_ONE */
+ if (cx.verb) {
+ printf("\n");
+ }
+#ifdef WARN_CLUT_CLIPPING /* Print warning if setting clut clips */
+ if (wr_icco->warnc)
+ warning("Values clipped in setting Gamut LUT");
+#endif /* WARN_CLUT_CLIPPING */
+
+ cx.gam->del(cx.gam); /* Done with gamut object */
+ cx.gam = NULL;
+
+ if (verb)
+ printf("Done gamut boundary table\n");
+ }
+#endif /* !DISABLE_GAMUT_TAG */
+
+ /* Free up xicc stuff */
+ AtoB->del(AtoB); /* Done with device to PCS lookup */
+ wr_xicc->del(wr_xicc);
+
+ }
+ /* Gamma/Shaper + matrix profile */
+ /* or XYZ cLUT with matrix as well. */
+ if (!isLut || mtxtoo) {
+ xicc *wr_xicc; /* extention object */
+ icxLuBase *xluo; /* Forward ixcLu */
+ int flags = 0;
+
+ /* Wrap with an expanded icc */
+ if ((wr_xicc = new_xicc(wr_icco)) == NULL)
+ error("Creation of xicc failed");
+
+ if (verb)
+ flags |= ICX_VERBOSE;
+
+ if (ptype == prof_matonly)
+ flags |= ICX_NO_IN_SHP_LUTS; /* Make it linear */
+
+ if (clipprims)
+ flags |= ICX_CLIP_WB | ICX_CLIP_PRIMS;
+
+ flags |= ICX_SET_WHITE | ICX_SET_BLACK; /* Compute & use white & black */
+
+ if (!mtxtoo) /* Write matrix white/black/Luminance if no cLUT */
+ flags |= ICX_WRITE_WBL;
+
+ /* Setup Device -> XYZ conversion (Fwd) object from scattered data. */
+ if ((xluo = wr_xicc->set_luobj(
+ wr_xicc, icmFwd, isdisp ? icmDefaultIntent : icRelativeColorimetric,
+ icmLuOrdRev,
+ flags, /* Compute white & black */
+ npat, npat, tpat, NULL, dispLuminance, -1.0, smooth, avgdev,
+ NULL, oink, cal, iquality)) == NULL)
+ error("%d, %s",wr_xicc->errc, wr_xicc->err);
+
+ /* Free up xicc stuff */
+ xluo->del(xluo);
+
+ /* Set the ColorantTable PCS values */
+ if (!mtxtoo) {
+ unsigned int i;
+ icmColorantTable *wo;
+ double dv[MAX_CHAN];
+
+ /* Get lookup object simply for fwd_relpcs_outpcs() */
+ if ((xluo = wr_xicc->get_luobj(wr_xicc, ICX_CLIP_NEAREST, icmFwd,
+ icRelativeColorimetric, icmSigDefaultData,
+ icmLuOrdNorm, NULL, NULL)) == NULL)
+ error ("%d, %s",wr_xicc->errc, wr_xicc->err);
+
+ if ((wo = (icmColorantTable *)wr_icco->read_tag(
+ wr_icco, icSigColorantTableTag)) == NULL)
+ error("read_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ for (i = 0; i < wo->count; i++)
+ dv[i] = 0.0;
+
+ /* Lookup the colorant PCS values the recommended ICC way */
+ for (i = 0; i < wo->count; i++) {
+ dv[i] = 1.0;
+ xluo->lookup(xluo, wo->data[i].pcsCoords, dv);
+ /* Matrix profile can produce -ve values not representable by 16 bit XYZ */
+ icmClipXYZ(wo->data[i].pcsCoords,wo->data[i].pcsCoords);
+ dv[i] = 0.0;
+ }
+ xluo->del(xluo);
+ }
+
+ wr_xicc->del(wr_xicc);
+ }
+
+ /* We're done with any cal now */
+ if (cal != NULL)
+ cal->del(cal);
+
+ /* Write the file (including all tags) out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0) {
+ error("Write file: %d, %s",rv,wr_icco->err);
+ }
+
+ /* Close the file */
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+
+ /* Check the forward profile accuracy against the data points */
+ if (verb || verify) {
+ icmFile *rd_fp;
+ icc *rd_icco;
+ icmLuBase *luo;
+ double merr = 0.0;
+ double rerr = 0.0;
+ double aerr = 0.0;
+ double nsamps = 0.0;
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL)
+ error("Write: Can't open file '%s'",file_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error("Write: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error("Read: %d, %s",rv,rd_icco->err);
+
+ /* Get the Fwd table */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric,
+ icSigLabData, icmLuOrdNorm)) == NULL) {
+ error("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ for (i = 0; i < npat; i++) {
+ double out[3], ref[3];
+ double mxd;
+
+ /* Lookup the profiles PCS for out test patch point */
+ if (luo->lookup(luo, out, tpat[i].p) > 1)
+ error("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Our tpat data might be in XYZ, so generate an Lab ref value */
+ if (!wantLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
+ icmXYZ2Lab(&icmD50, ref, tpat[i].v);
+
+ } else {
+ ref[0] = tpat[i].v[0];
+ ref[1] = tpat[i].v[1];
+ ref[2] = tpat[i].v[2];
+ }
+
+ if (verify && verb) {
+ if (devspace == icSigCmykData) {
+ printf("[%f] %f %f %f %f -> %f %f %f should be %f %f %f\n",
+ icmLabDE(ref, out),
+ tpat[i].p[0],tpat[i].p[1],tpat[i].p[2],tpat[i].p[3],
+ out[0],out[1],out[2],
+ ref[0],ref[1],ref[2]);
+ } else {
+ printf("[%f] %f %f %f -> %f %f %f should be %f %f %f\n",
+ icmLabDE(ref, out),
+ tpat[i].p[0],tpat[i].p[1],tpat[i].p[2],
+ out[0],out[1],out[2],
+ ref[0],ref[1],ref[2]);
+ }
+ }
+
+ /* Check the result */
+ mxd = icmLabDE(ref, out);
+ if (mxd > merr)
+ merr = mxd;
+
+ rerr += mxd * mxd;
+ aerr += mxd;
+ nsamps++;
+ }
+ rerr = sqrt(rerr/nsamps);
+ aerr /= nsamps;
+ printf("Profile check complete, peak err = %f, avg err = %f, RMS = %f\n",merr,aerr,rerr);
+
+ /* Done with lookup object */
+ luo->del(luo);
+
+ /* Close the file */
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+ }
+
+ free(tpat);
+}
+
diff --git a/profile/simpprof.c b/profile/simpprof.c
new file mode 100644
index 0000000..61128ff
--- /dev/null
+++ b/profile/simpprof.c
@@ -0,0 +1,433 @@
+
+/*
+ * Argyll Color Correction System
+ * Simple CMYK profile generator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 9/11/96
+ *
+ * Copyright 1996, 2002 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.
+ */
+
+/* This program generates a simple mathematical profile for a CMYK device. */
+/* It is intended for use in bootstrapping the test chart generation. */
+
+#define VERSION "1.1"
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include "../cgats/cgats.h"
+#include "../numlib/numlib.h"
+#include "icc.h"
+
+/* A color structure */
+/* This holds the test patch results */
+typedef struct {
+ double c,m,y,k;
+ double bc[8]; /* Gamma corrected blend coefficients of cmyk */
+ double Lab[3];
+ double err; /* Delta E squared */
+} col;
+
+/* Structure to hold data for optimization function */
+struct _edatas {
+ col *cols; /* Pointer to table of patch results */
+ int npat; /* Number of patches */
+ int xyzi; /* current xyz index */
+ double gam[4]; /* Gamma values */
+ double k[3][8]; /* Primary combination values */
+ }; typedef struct _edatas edatas;
+
+/* Definition of the power optimization function handed to powell() */
+/* This function is for optimising the gamma function */
+double efunc1(void *edata, double p[]) {
+ edatas *ed = (edatas *)edata;
+ double rv;
+ col *cp;
+ for (rv = 0.0, cp = &ed->cols[ed->npat-1]; cp >= &ed->cols[0]; cp--) {
+ double cc,mm,yy,kk;
+ double nc,nm,ny,nk;
+ double XYZ[3], Lab[3];
+ int j;
+
+ /* Apply gamma correction to each input */
+ for (j = 0; j < 4; j++) {
+ if (p[j] < 0.2)
+ p[j] = 0.2;
+ else if (p[j] > 5.0)
+ p[j] = 5.0;
+ }
+ cc = pow(cp->c, p[0]);
+ nc = 1.0 - cc;
+ mm = pow(cp->m, p[1]);
+ nm = 1.0 - mm;
+ yy = pow(cp->y, p[2]);
+ ny = 1.0 - yy;
+ kk = pow(cp->k, p[3]);
+ nk = 1.0 - kk;
+
+ /* Then interpolate between all combinations of primaries. */
+ /* plus one that stands for all that are close to black */
+ for (j = 0; j < 3; j++) {
+ XYZ[j] = nc * nm * ny * nk * ed->k[j][0]
+ + nc * nm * yy * nk * ed->k[j][1]
+ + nc * mm * ny * nk * ed->k[j][2]
+ + nc * mm * yy * nk * ed->k[j][3]
+ + cc * nm * ny * nk * ed->k[j][4]
+ + cc * nm * yy * nk * ed->k[j][5]
+ + cc * mm * ny * nk * ed->k[j][6]
+ + (cc * mm * yy * nk + kk) * ed->k[j][7];
+ }
+ icmXYZ2Lab(&icmD50, Lab, XYZ);
+ rv += cp->err = icmLabDEsq(Lab, cp->Lab);
+ }
+printf("Efunc1 returning %f\n",rv);
+ return rv;
+}
+
+/* Definition of the primary coefficient optimization function handed to powell() */
+/* This function is for optimising the primary values */
+double efunc2(void *edata, double p[]) {
+ edatas *ed = (edatas *)edata;
+ int j, os = ed->xyzi;
+ double tt, rv;
+ col *cp;
+
+ rv = 0.0;
+
+ for (j = 0; j < 8; j++) {
+ if (p[j] < 0.0) { /* Protect against silly values */
+ p[j] = 0.0;
+ rv += 1000.0;
+ }
+ else if (p[j] > 1.5) {
+ p[j] = 1.5;
+ rv += 1000.0;
+ }
+ ed->k[os][j] = p[j]; /* Load into current */
+ }
+
+ /* Compute error */
+ for (cp = &ed->cols[ed->npat-1]; cp >= &ed->cols[0]; cp--) {
+ double XYZ[3], Lab[3];
+
+ for (os = 0; os < 3; os++) {
+
+ /* Interpolate between all combinations of primaries. */
+ for (tt = 0.0, j = 0; j < 8; j++)
+ tt += cp->bc[j] * ed->k[os][j];
+ XYZ[os] = tt;
+ }
+ icmXYZ2Lab(&icmD50, Lab, XYZ);
+ rv += cp->err = icmLabDEsq(Lab, cp->Lab);
+ }
+printf("Efunc2 returning %f\n",rv);
+ return rv;
+}
+
+/* Calculate blend coefficients */
+void calc_bc(edatas *ed) {
+ int j;
+ col *cp;
+ for (cp = &ed->cols[ed->npat-1]; cp >= &ed->cols[0]; cp--) {
+ double cc,mm,yy,kk;
+ double nc,nm,ny,nk;
+
+ /* Apply gamma correction to each input, and calculate complement */
+ for (j = 0; j < 4; j++) {
+ if (ed->gam[j] < 0.2)
+ ed->gam[j] = 0.2;
+ else if (ed->gam[j] > 5.0)
+ ed->gam[j] = 2.0;
+ }
+ cc = pow(cp->c, ed->gam[0]);
+ nc = 1.0 - cc;
+ mm = pow(cp->m, ed->gam[1]);
+ nm = 1.0 - mm;
+ yy = pow(cp->y, ed->gam[2]);
+ ny = 1.0 - yy;
+ kk = pow(cp->k, ed->gam[3]);
+ nk = 1.0 - kk;
+
+ /* Go through all 8 combinations */
+ cp->bc[0] = nc * nm * ny * nk;
+ cp->bc[1] = nc * nm * yy * nk;
+ cp->bc[2] = nc * mm * ny * nk;
+ cp->bc[3] = nc * mm * yy * nk;
+ cp->bc[4] = cc * nm * ny * nk;
+ cp->bc[5] = cc * nm * yy * nk;
+ cp->bc[6] = cc * mm * ny * nk;
+ cp->bc[7] = cc * mm * yy * nk + kk;
+ }
+}
+
+void usage(void);
+
+int main(int argc, char *argv[])
+{
+ int i,j,k;
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ static char inname[200] = { 0 }; /* Input cgats file base name */
+ static char outname[200] = { 0 }; /* Output cgats file base name */
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ int ti; /* Temporary index */
+ edatas ed; /* Optimising function data structure */
+ double resid[4];
+ double presid,dresid;
+ double sarea;
+
+ error_program = argv[0];
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++)
+ {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') /* Look for any flags */
+ {
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else
+ {
+ if ((fa+1) < argc)
+ {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(inname,argv[fa]);
+ strcat(inname,".ti3");
+ strcpy(outname,argv[fa]);
+ strcat(outname,".pr1");
+
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI3"); /* our special input type is Calibration Target Information 3 */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI3 format file");
+ if (icg->ntables != 1)
+ error ("Input file doesn't contain exactly one table");
+
+ if ((ed.npat = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ if (verb) {
+ printf("No of test patches = %d\n",ed.npat);
+ }
+
+ if ((ed.cols = (col *)malloc(sizeof(col) * ed.npat)) == NULL)
+ error("Malloc failed!");
+
+ /* Setup output cgats file */
+ /* This is a simple interpolation CMYK -> XYZ device profile */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "PROF1"); /* our special type is Profile type 1 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Device Profile Type 1",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll sprof", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ /* Figure out the color space */
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error ("Input file doesn't contain keyword COLOR_REPS");
+ if (strcmp(icg->t[0].kdata[ti],"CMYK_XYZ") == 0) {
+ int ci, mi, yi, ki;
+ int Xi, Yi, Zi;
+ if ((ci = icg->find_field(icg, 0, "CMYK_C")) < 0)
+ error ("Input file doesn't contain field CMYK_C");
+ if (icg->t[0].ftype[ci] != r_t)
+ error ("Field CMYK_C is wrong type");
+ if ((mi = icg->find_field(icg, 0, "CMYK_M")) < 0)
+ error ("Input file doesn't contain field CMYK_M");
+ if (icg->t[0].ftype[mi] != r_t)
+ error ("Field CMYK_M is wrong type");
+ if ((yi = icg->find_field(icg, 0, "CMYK_Y")) < 0)
+ error ("Input file doesn't contain field CMYK_Y");
+ if (icg->t[0].ftype[yi] != r_t)
+ error ("Field CMYK_Y is wrong type");
+ if ((ki = icg->find_field(icg, 0, "CMYK_K")) < 0)
+ error ("Input file doesn't contain field CMYK_K");
+ if (icg->t[0].ftype[ki] != r_t)
+ error ("Field CMYK_K is wrong type");
+ if ((Xi = icg->find_field(icg, 0, "XYZ_X")) < 0)
+ error ("Input file doesn't contain field XYZ_X");
+ if (icg->t[0].ftype[Xi] != r_t)
+ error ("Field XYZ_X is wrong type");
+ if ((Yi = icg->find_field(icg, 0, "XYZ_Y")) < 0)
+ error ("Input file doesn't contain field XYZ_Y");
+ if (icg->t[0].ftype[Yi] != r_t)
+ error ("Field XYZ_Y is wrong type");
+ if ((Zi = icg->find_field(icg, 0, "XYZ_Z")) < 0)
+ error ("Input file doesn't contain field XYZ_Z");
+ if (icg->t[0].ftype[Zi] != r_t)
+ error ("Field XYZ_Z is wrong type");
+ for (i = 0; i < ed.npat; i++) {
+ double XYZ[3];
+ ed.cols[i].c = *((double *)icg->t[0].fdata[i][ci]) / 100.0;
+ ed.cols[i].m = *((double *)icg->t[0].fdata[i][mi]) / 100.0;
+ ed.cols[i].y = *((double *)icg->t[0].fdata[i][yi]) / 100.0;
+ ed.cols[i].k = *((double *)icg->t[0].fdata[i][ki]) / 100.0;
+ XYZ[0] = *((double *)icg->t[0].fdata[i][Xi]) / 100.0;
+ XYZ[1] = *((double *)icg->t[0].fdata[i][Yi]) / 100.0;
+ XYZ[2] = *((double *)icg->t[0].fdata[i][Zi]) / 100.0;
+ icmXYZ2Lab(&icmD50, ed.cols[i].Lab, XYZ);
+ }
+
+ /* Initialise the model */
+ ed.gam[0] = 1.0; /* First four are CMYK gamma values */
+ ed.gam[1] = 1.0;
+ ed.gam[2] = 1.0;
+ ed.gam[3] = 1.0;
+
+ /* Initialise interpolation end points for each combination of primary, */
+ /* with all combinations close to black being represented by param[7]. */
+ ed.k[0][0] = .82; ed.k[1][0] = .83; ed.k[2][0] = .75; /* White */
+ ed.k[0][1] = .66; ed.k[1][1] = .72; ed.k[2][1] = .05; /* Y */
+ ed.k[0][2] = .27; ed.k[1][2] = .12; ed.k[2][2] = .06; /* M */
+ ed.k[0][3] = .27; ed.k[1][3] = .12; ed.k[2][3] = .00; /* MY */
+ ed.k[0][4] = .09; ed.k[1][4] = .13; ed.k[2][4] = .44; /* C */
+ ed.k[0][5] = .03; ed.k[1][5] = .10; ed.k[2][5] = .04; /* C Y */
+ ed.k[0][6] = .02; ed.k[1][6] = .01; ed.k[2][6] = .05; /* CM */
+ ed.k[0][7] = .01; ed.k[1][7] = .01; ed.k[2][7] = .01; /* Black */
+
+ sarea = 0.3;
+ presid = dresid = 100.0;
+ for (k=0; /* dresid > 0.0001 && */ k < 40; k++) { /* Untill we're done */
+ double sresid;
+ double sr[8];
+ double p[8];
+
+ /* Adjust the gamma */
+ for (i = 0; i < 4; i++)
+ sr[i] = 0.1; /* Device space search radius */
+ if (powell(&resid[3], 4, &ed.gam[0], sr, 0.1, 1000, efunc1, (void *)&ed, NULL, NULL) != 0)
+ error ("Powell failed");
+
+ /* Adjust the primaries */
+ calc_bc(&ed); /* Calculate blend coefficients */
+ for (i = 0; i < 8; i++)
+ sr[i] = 0.2; /* Device space search radius */
+ sresid = 99.0;
+ for (j = 0; j < 3; j++) { /* For each of X, Y and Z */
+ ed.xyzi = j;
+
+ for (i = 0; i < 8; i++)
+ p[i] = ed.k[j][i];
+printf("##############\n");
+printf("XYZ = %d\n",j);
+ if (powell(&resid[j], 8, p, sr, 0.1, 1000, efunc2, (void *)&ed, NULL, NULL) != 0)
+ error ("Powell failed");
+
+ for (i = 0; i < 8; i++)
+ ed.k[j][i] = p[i];
+
+ if (sresid > resid[j])
+ sresid = resid[j];
+ }
+ dresid = presid - sresid;
+ if (dresid < 0.0)
+ dresid = 100.0;
+ presid = sresid;
+printf("~1 presid = %f, sresid = %f, dresid = %f\n",presid, sresid, dresid);
+ }
+
+ /* Fields we want */
+ ocg->add_kword(ocg, 0, "DSPACE","CMYK", NULL);
+ ocg->add_kword(ocg, 0, "DTYPE","PRINTER", NULL);
+ ocg->add_field(ocg, 0, "PARAM_ID", i_t);
+ ocg->add_field(ocg, 0, "PARAM", r_t);
+
+ /* Output model parameters */
+ for (j = 0; j < 4; j++)
+ ocg->add_set(ocg, 0, j, ed.gam[j]);
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 8; i++)
+ ocg->add_set(ocg, 0, 10 * (j + 1) + i, 100.0 * ed.k[j][i]);
+ }
+
+ if (verb) {
+ double aver = 0.0;
+ double maxer = 0.0;
+ for (i = 0; i < ed.npat; i++) {
+ double err = sqrt(ed.cols[i].err);
+ if (err > maxer)
+ maxer = err;
+ aver += err;
+ }
+ aver = aver/((double)i);
+ printf("Average fit error = %f, maximum = %f\n",aver,maxer);
+ }
+ } else if (strcmp(icg->t[0].kdata[ti],"RGB") == 0) {
+ error ("We can't handle RGB !");
+ } else if (strcmp(icg->t[0].kdata[ti],"W") == 0) {
+ error ("We can't handle Grey !");
+ } else
+ error ("Input file keyword COLOR_REPS has unknown value");
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ free(ed.cols);
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+void
+usage(void) {
+ fprintf(stderr,"Create Simple CMYK Device Profile, Version %s\n",VERSION);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: %s [-v] outfile\n",error_program);
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," outfile Base name for input.tr3/output.pr1 file\n");
+ exit(1);
+ }
+
+
diff --git a/profile/splitti3.c b/profile/splitti3.c
new file mode 100644
index 0000000..0e170c1
--- /dev/null
+++ b/profile/splitti3.c
@@ -0,0 +1,400 @@
+/*
+ * Argyll Color Correction System
+ * Split a .ti3 (or other CGATS like) file into two parts.
+ *
+ * Author: Graeme W. Gill
+ * Date: 14/12/2005
+ *
+ * Copyright 2005, 2010 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.
+ */
+
+/*
+ * This program takes in a CGATS .ti3 file, and splits it into
+ * two .ti3 files, spreading the readings between them.
+ * This is intended for use in verifying the profiler.
+ */
+
+/*
+ * TTBD:
+
+ This doesn't pass calibration table information through.
+ (ie. should copy all tables after the first.)
+
+ Write a companion "combineti3" to merge .ti3's together.
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <string.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#include <sys/types.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "insttypes.h"
+#include "sort.h"
+
+void
+usage(void) {
+ fprintf(stderr,"Split a .ti3 into two, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: splitcgats [-options] input.ti3 output1.ti3 output2.ti3\n");
+ fprintf(stderr," -v Verbose - print each patch value\n");
+ fprintf(stderr," -n no Put no sets in first file, and balance in second file.\n");
+ fprintf(stderr," -p percent Put percent%% sets in first file, and balance in second file. (def. 50%%)\n");
+ fprintf(stderr," -w Put white patches in both files.\n");
+ fprintf(stderr," -r seed Use given random seed.\n");
+ fprintf(stderr," input.ti3 File to be split up.\n");
+ fprintf(stderr," output1.ti3 First output file\n");
+ fprintf(stderr," output2.ti3 Second output file\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ int numb = -1; /* Number to put in first */
+ double prop = 0.5; /* Proportion to put in first */
+ int dow = 0; /* Put white patches in both files */
+ int seed = 0x12345678;
+ int doseed = 0;
+
+ cgats *cgf = NULL; /* cgats file data */
+ char in_name[MAXNAMEL+1]; /* Patch filename */
+
+ cgats *cg1 = NULL; /* cgats file data */
+ char out_name1[MAXNAMEL+4+1]; /* VRML name */
+ cgats *cg2 = NULL; /* cgats file data */
+ char out_name2[MAXNAMEL+4+1]; /* VRML name */
+
+ cgats_set_elem *setel; /* Array of set value elements */
+ int *flags; /* Point to destination of set */
+
+ int i, j, n;
+
+ error_program = "splitti3";
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?') {
+ usage();
+
+ } else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+
+ } else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ fa = nfa;
+ if (na == NULL) usage();
+ numb = atoi(na);
+ if (numb < 0) usage();
+
+ } else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage();
+ prop = atoi(na);
+ if (prop < 0) usage();
+ prop = prop / 100.0;
+
+ } else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ dow = 1;
+
+ } else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ seed = atoi(na);
+ doseed = 1;
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (doseed)
+ rand32(seed); /* Init seed deterministicaly */
+ else
+ rand32(time(NULL)); /* Init seed randomly */
+
+ /* Get the file name arguments */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(out_name1,argv[fa++],MAXNAMEL); out_name1[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(out_name2,argv[fa++],MAXNAMEL); out_name2[MAXNAMEL] = '\000';
+
+ if ((cgf = new_cgats()) == NULL)
+ error("Failed to create cgats object");
+ cgf->add_other(cgf, ""); /* Allow any signature file */
+
+ if (cgf->read_name(cgf, in_name))
+ error("CGATS file '%s' read error : %s",in_name,cgf->err);
+
+ if (cgf->ntables < 1)
+ error ("Input file '%s' doesn't contain at least one table",in_name);
+
+ /* Create the two output files */
+ if ((cg1 = new_cgats()) == NULL)
+ error("Failed to create cgats object");
+ if ((cg2 = new_cgats()) == NULL)
+ error("Failed to create cgats object");
+
+ /* Duplicate the type of the file */
+ if (cgf->t[0].tt == cgats_X) {
+ cg1->add_other(cg1, cgf->cgats_type);
+ cg1->add_table(cg1, tt_other, 0);
+ cg2->add_other(cg2, cgf->cgats_type);
+ cg2->add_table(cg2, tt_other, 0);
+ } else if (cgf->t[0].tt == tt_other) {
+ cg1->add_other(cg1, cgf->others[cgf->t[0].oi]);
+ cg1->add_table(cg1, tt_other, 0);
+ cg2->add_other(cg2, cgf->others[cgf->t[0].oi]);
+ cg2->add_table(cg2, tt_other, 0);
+ } else {
+ cg1->add_table(cg1, cgf->t[0].tt, 0);
+ cg2->add_table(cg1, cgf->t[0].tt, 0);
+ }
+
+ /* Duplicate all the keywords */
+ for (i = 0; i < cgf->t[0].nkwords; i++) {
+ cg1->add_kword(cg1, 0, cgf->t[0].ksym[i], cgf->t[0].kdata[i], NULL);
+ cg2->add_kword(cg2, 0, cgf->t[0].ksym[i], cgf->t[0].kdata[i], NULL);
+ }
+
+ /* Duplicate all of the fields */
+ for (i = 0; i < cgf->t[0].nfields; i++) {
+ cg1->add_field(cg1, 0, cgf->t[0].fsym[i], cgf->t[0].ftype[i]);
+ cg2->add_field(cg2, 0, cgf->t[0].fsym[i], cgf->t[0].ftype[i]);
+ }
+
+ if ((setel = (cgats_set_elem *)malloc(
+ sizeof(cgats_set_elem) * cgf->t[0].nfields)) == NULL)
+ error("Malloc failed!");
+
+ if ((flags = (int *)calloc(cgf->t[0].nsets, sizeof(int))) == NULL)
+ error("Malloc failed!");
+
+ if (numb < 0) { /* Use percentage */
+ numb = (int)(cgf->t[0].nsets * prop + 0.5);
+ }
+ if (numb > cgf->t[0].nsets)
+ numb = cgf->t[0].nsets;
+
+ if (verb)
+ printf("Putting %d sets in '%s' and %d in '%s'\n",numb,out_name1,cgf->t[0].nsets-numb,out_name2);
+
+ n = 0;
+
+ /* If dow, add white patches to both sets */
+ if (dow) {
+ int ti;
+ char *buf;
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+ char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
+ char *outc;
+ int nmask;
+ int nchan;
+ char *bident;
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ int pcsix[3]; /* PCS chanel indexes */
+ int isin = 0;
+ int isadd = 0;
+ int isLab = 0;
+
+ if ((ti = cgf->find_kword(cgf, 0, "DEVICE_CLASS")) < 0)
+ error ("Input file doesn't contain keyword DEVICE_CLASS");
+
+ if (strcmp(cgf->t[0].kdata[ti],"INPUT") == 0)
+ isin = 1;
+
+ if ((ti = cgf->find_kword(cgf, 0, "COLOR_REP")) < 0)
+ error("Input file doesn't contain keyword COLOR_REPS");
+
+ if ((buf = strdup(cgf->t[0].kdata[ti])) == NULL)
+ error("Malloc failed");
+
+ /* Split COLOR_REP into device and PCS space */
+ if ((outc = strchr(buf, '_')) == NULL)
+ error("COLOR_REP '%s' invalid", cgf->t[0].kdata[ti]);
+ *outc++ = '\000';
+
+ if (strcmp(outc, "XYZ") == 0) {
+ isLab = 0;
+ } else if (strcmp(outc, "LAB") == 0) {
+ isLab = 1;
+ } else
+ error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", cgf->t[0].kdata[ti]);
+
+ if ((nmask = icx_char2inkmask(buf)) == 0) {
+ error ("File '%s' keyword COLOR_REPS has unknown device value '%s'",in_name,buf);
+ }
+
+ if (nmask & ICX_ADDITIVE)
+ isadd = 1;
+
+ nchan = icx_noofinks(nmask);
+ bident = icx_inkmask2char(nmask, 0);
+
+ /* Find device fields */
+ for (j = 0; j < nchan; j++) {
+ int ii, imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = cgf->find_field(cgf, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (cgf->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+ chix[j] = ii;
+ }
+
+ /* Find PCS fields */
+ for (j = 0; j < 3; j++) {
+ int ii;
+
+ if ((ii = cgf->find_field(cgf, 0, isLab ? labfname[j] : xyzfname[j])) < 0)
+ error ("Input file doesn't contain field %s",isLab ? labfname[j] : xyzfname[j]);
+ if (cgf->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",isLab ? labfname[j] : xyzfname[j]);
+ pcsix[j] = ii;
+ }
+
+ if (isin) {
+ int wix = -1;
+ double wv = -1e60;
+ int pcsy = 1;
+
+ if (isLab)
+ pcsy = 0;
+
+ /* We assume that the white point is the patch with the */
+ /* highest L* or Y value. */
+ for (i = 0; i < cgf->t[0].nsets; i++) {
+ double val;
+
+ val = *((double *)cgf->t[0].fdata[i][pcsix[pcsy]]);
+ if (val > wv) {
+ wv = val;
+ wix = i;
+ }
+ }
+ if (wix > 0) {
+ n++;
+ flags[wix] = 3;
+ if (verb)
+ printf("Found input white patch index %d\n",wix);
+ }
+
+ } else {
+
+ if (isadd) {
+ for (i = 0; i < cgf->t[0].nsets; i++) {
+ for (j = 0; j < nchan; j++) {
+ if (*((double *)cgf->t[0].fdata[i][chix[j]]) < 99.99)
+ break;
+ }
+ if (j >= nchan) {
+ n++;
+ flags[i] = 3;
+ if (verb)
+ printf("Found additive white patch index %d\n",i);
+ }
+ }
+ } else {
+ for (i = 0; i < cgf->t[0].nsets; i++) {
+ for (j = 0; j < nchan; j++) {
+ if (*((double *)cgf->t[0].fdata[i][chix[j]]) > 0.01)
+ break;
+ }
+ if (j >= nchan) {
+ n++;
+ flags[i] = 3;
+ if (verb)
+ printf("Found subtractive white patch index %d\n",i);
+ }
+ }
+ }
+ }
+ free(bident);
+ }
+
+ /* Chose which of the sets go into file 1 and 2*/
+ for (;n < numb;) {
+ i = i_rand(0, cgf->t[0].nsets-1);
+ if (flags[i] == 0) {
+ flags[i] = 1;
+ n++;
+ }
+ }
+
+ /* Assume any patch not flagged goes to 2 */
+ for (i = 0; i < cgf->t[0].nsets; i++) {
+ if (flags[i] == 0)
+ flags[i] = 2;
+ }
+
+ /* Copy them approproately */
+ for (i = 0; i < cgf->t[0].nsets; i++) {
+ cgf->get_setarr(cgf, 0, i, setel);
+ if (flags[i] & 1) {
+ cg1->add_setarr(cg1, 0, setel);
+ }
+ if (flags[i] & 2) {
+ cg2->add_setarr(cg2, 0, setel);
+ }
+ }
+
+ /* Write out the files */
+ if (cg1->write_name(cg1, out_name1))
+ error("CGATS file '%s' write error : %s",out_name1,cg1->err);
+ if (cg2->write_name(cg2, out_name2))
+ error("CGATS file '%s' write error : %s",out_name2,cg2->err);
+
+
+ free(flags);
+ free(setel);
+
+ return 0;
+}
+
+
+
+
+
diff --git a/profile/txt2ti3.c b/profile/txt2ti3.c
new file mode 100644
index 0000000..9b425f3
--- /dev/null
+++ b/profile/txt2ti3.c
@@ -0,0 +1,830 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Read in the RGB/CMYK CGATS device data from Gretag/Logo/X-Rite etc.
+ * and convert it into a .ti3 CGATs format suitable for the Argyll CMS.
+ *
+ * Derived from kodak2cgats.c
+ * Author: Graeme W. Gill
+ * Date: 16/11/00
+ *
+ * Copyright 2000 - 2010, 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.
+ */
+
+/* TTBD
+
+ Need to add support for SPECTRAL_NM SPECTRAL_PCT type spectral values.
+ See /src/argyll/test/JosvanRiswick/R080505.cgt
+
+ Do we need to worry about normalising display values to Y = 100, or marking
+ them not normalised ?
+
+ Should have an option to output .ti1 files instead of .ti3.
+
+ */
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include <stdarg.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "cgats.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "numlib.h"
+
+void
+usage(char *mes) {
+ fprintf(stderr,"Convert Gretag/Logo or X-Rite ColorPport raw RGB or CMYK device profile data to Argyll CGATS data, Version %s\n",ARGYLL_VERSION_STR);
+ 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," -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");
+ fprintf(stderr," -d Set type of device as Display, not Output\n");
+ fprintf(stderr," -i Set type of device as Input, not Output\n");
+ fprintf(stderr," [devfile] Input Device CMYK target file (typically file.txt)\n");
+ fprintf(stderr," infile Input CIE, Spectral or Device & Spectral file (typically file.txt)\n");
+ fprintf(stderr," [specfile] Input Spectral file (typically file.txt)\n");
+ fprintf(stderr," outbasename Output file basename for .ti3 and .ti2\n");
+ exit(1);
+ }
+
+int main(int argc, char *argv[])
+{
+ int i, j;
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ int out2 = 0; /* Create dumy .ti2 file output */
+ int disp = 0; /* nz if this is a display device */
+ int inp = 0; /* nz if this is an input device */
+ static char devname[200] = { 0 }; /* Input CMYK/Device .txt file (may be null) */
+ static char ciename[200] = { 0 }; /* Input CIE .txt file (may be null) */
+ static char specname[200] = { 0 }; /* Input Device / Spectral .txt file */
+ static char outname[200] = { 0 }; /* Output cgats .ti3 file base name */
+ static char outname2[200] = { 0 }; /* Output cgats .ti2 file base name */
+ cgats *cmy = NULL; /* Input RGB/CMYK reference file */
+ int f_id1 = -1, f_c, f_m, f_y, f_k = 0; /* Field indexes */
+ double dev_scale = 1.0; /* Device value scaling */
+ cgats *ncie = NULL; /* Input CIE readings file (may be Dev & spectral too) */
+ int f_id2, f_cie[3]; /* Field indexes */
+ cgats *spec = NULL; /* Input spectral readings (NULL if none) */
+ double spec_scale = 1.0; /* Spectral value scaling */
+ int f_id3 = 0; /* Field indexes */
+ int spi[100]; /* CGATS indexes for each wavelength */
+ cgats *ocg; /* output cgats structure for .ti3 */
+ cgats *ocg2; /* output cgats structure for .ti2 */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ int islab = 0; /* CIE is Lab rather than XYZ */
+ int specmin = 0, specmax = 0, specnum = 0; /* Min and max spectral in nm, inclusive */
+ int npat = 0; /* Number of patches */
+ int ndchan = 0; /* Number of device channels, 0 = no device, RGB = 3, CMYK = 4 */
+ int tlimit = -1; /* Not set */
+ double mxsum = -1.0; /* Maximim sum of inks found in file */
+ int mxsumix = 0;
+
+ error_program = "txt2ti3";
+
+ if (argc <= 1)
+ usage("Too few arguments");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage(NULL);
+
+ else if (argv[fa][1] == '2')
+ out2 = 1;
+
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage("No ink limit parameter");
+ tlimit = atoi(na);
+ if (tlimit < 1)
+ tlimit = -1;
+ }
+
+ else if (argv[fa][1] == 'd') {
+ disp = 1;
+ inp = 0;
+
+ } else if (argv[fa][1] == 'i') {
+ disp = 0;
+ inp = 1;
+
+ } else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+ else
+ usage("Unknown flag");
+ } else
+ break;
+ }
+
+ /* See how many arguments remain */
+ switch (argc - fa) {
+ case 2: /* Must be a new combined device + cie/spectral */
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad dev filename");
+ strcpy(devname,argv[fa]);
+ strcpy(ciename,argv[fa++]);
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad output filename");
+ strcpy(outname, argv[fa++]);
+ if (verb) printf("Single source file, assumed dev/cie/spectral\n");
+ break;
+ case 3: /* Device + cie or spectral */
+ /* or combined cie + spectral */
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad dev filename");
+ strcpy(devname,argv[fa++]);
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad cie/spec filename");
+ strcpy(ciename,argv[fa++]);
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad output filename");
+ strcpy(outname, argv[fa++]);
+ if (verb) printf("Two source files, assumed dev + cie/spectral or dev/cie + spectral\n");
+ break;
+ case 4: /* Device, ci and spectral */
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad dev filename");
+ strcpy(devname,argv[fa++]);
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad cie filename");
+ strcpy(ciename,argv[fa++]);
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad spec filename");
+ strcpy(specname,argv[fa++]);
+ if (fa >= argc || argv[fa][0] == '-') usage("Bad output filename");
+ strcpy(outname, argv[fa++]);
+ if (verb) printf("Three source files, assumed dev + cie + spectral\n");
+ break;
+ default:
+ usage("Wrong number of filenames");
+ }
+
+ if (out2) {
+ strcpy (outname2, outname);
+ strcat(outname2,".ti2");
+ }
+
+ /* Convert basename into .ti3 */
+ strcat(outname,".ti3");
+
+ /* Open up the Input CMYK/RGB reference file (might be same as ncie/spec) */
+ cmy = new_cgats(); /* Create a CGATS structure */
+ cmy->add_other(cmy, "LGOROWLENGTH"); /* Gretag/Logo Target file */
+ cmy->add_other(cmy, "Date:"); /* Gretag/Logo Target file */
+ 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);
+ if (cmy->ntables != 1)
+ warning("Input file '%s' doesn't contain exactly one table",devname);
+
+ if ((npat = cmy->t[0].nsets) <= 0)
+ error("No patches");
+
+ if ((f_id1 = cmy->find_field(cmy, 0, "SampleName")) < 0
+ && (f_id1 = cmy->find_field(cmy, 0, "Sample_Name")) < 0
+ && (f_id1 = cmy->find_field(cmy, 0, "SAMPLE_NAME")) < 0
+ && (f_id1 = cmy->find_field(cmy, 0, "SAMPLE_ID")) < 0)
+ error("Input file '%s' doesn't contain field SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_ID",devname);
+ if (cmy->t[0].ftype[f_id1] != nqcs_t
+ && cmy->t[0].ftype[f_id1] != cs_t
+ && cmy->t[0].ftype[f_id1] != i_t)
+ error("Field SampleName (%s) from CMYK/RGB file '%s' is wrong type",cmy->t[0].fsym[f_id1],devname);
+
+ if (cmy->find_field(cmy, 0, "RGB_R") >= 0) {
+ ndchan = 3;
+ if (verb) {
+ if (inp || disp)
+ printf("Seems to be an RGB device\n");
+ else
+ printf("Seems to be a psuedo-RGB device\n");
+ }
+ } else if (cmy->find_field(cmy, 0, "CMYK_C") >= 0) {
+ ndchan = 4;
+ if (verb)
+ printf("Seems to be a CMYK device\n");
+ } else {
+ printf("No device values found - hope that's OK!\n");
+ }
+
+ if (ndchan == 3) {
+ if ((f_c = cmy->find_field(cmy, 0, "RGB_R")) < 0) {
+ error("Input file '%s' doesn't contain field RGB_R",devname);
+ }
+ if (cmy->t[0].ftype[f_c] != r_t)
+ error("Field RGB_R from file '%s' is wrong type",devname);
+
+ if ((f_m = cmy->find_field(cmy, 0, "RGB_G")) < 0)
+ error("Input file '%s' doesn't contain field RGB_G",devname);
+ if (cmy->t[0].ftype[f_m] != r_t)
+ error("Field RGB_G from file '%s' is wrong type",devname);
+
+ if ((f_y = cmy->find_field(cmy, 0, "RGB_B")) < 0)
+ error("Input file '%s' doesn't contain field RGB_B",devname);
+ if (cmy->t[0].ftype[f_y] != r_t)
+ error("Field RGB_B from file '%s' is wrong type",devname);
+
+ } else if (ndchan == 4) {
+ if ((f_c = cmy->find_field(cmy, 0, "CMYK_C")) < 0) {
+ error("Input file '%s' doesn't contain field CMYK_C",devname);
+ }
+ if (cmy->t[0].ftype[f_c] != r_t)
+ error("Field CMYK_C from file '%s' is wrong type",devname);
+
+ if ((f_m = cmy->find_field(cmy, 0, "CMYK_M")) < 0)
+ error("Input file '%s' doesn't contain field CMYK_M",devname);
+ if (cmy->t[0].ftype[f_m] != r_t)
+ error("Field CMYK_M from file '%s' is wrong type",devname);
+
+ if ((f_y = cmy->find_field(cmy, 0, "CMYK_Y")) < 0)
+ error("Input file '%s' doesn't contain field CMYK_Y",devname);
+ if (cmy->t[0].ftype[f_y] != r_t)
+ error("Field CMYK_Y from file '%s' is wrong type",devname);
+
+ if ((f_k = cmy->find_field(cmy, 0, "CMYK_K")) < 0)
+ error("Input file '%s' doesn't contain field CMYK_Y",devname);
+ if (cmy->t[0].ftype[f_k] != r_t)
+ error("Field CMYK_K from file '%s' is wrong type",devname);
+ }
+ if (verb && ndchan > 0) printf("Read device values\n");
+
+ if (cmy->find_field(cmy, 0, "XYZ_X") >= 0
+ || cmy->find_field(cmy, 0, "LAB_L") >= 0) {
+ /* We've got a new combined device+cie file as the first one. */
+ /* Shuffle it into ciename , and ciename into specname */
+
+ strcpy(specname, ciename);
+ strcpy(ciename, devname);
+
+ if (verb) printf("We've got a combined device + instrument readings file\n");
+ }
+
+ /* Open up the input nCIE or Spectral device data file */
+ ncie = new_cgats(); /* Create a CGATS structure */
+ ncie->add_other(ncie, "LGOROWLENGTH"); /* Gretag/Logo Target file */
+ ncie->add_other(ncie, "ECI2002"); /* Gretag/Logo Target file */
+ ncie->add_other(ncie, ""); /* Wildcard */
+ if (ncie->read_name(ncie, ciename))
+ error ("Read: Can't read cie file '%s'. Unknown format or corrupted file ?",ciename);
+ if (ncie->ntables != 1)
+ warning("Input file '%s' doesn't contain exactly one table",ciename);
+
+ if (npat != ncie->t[0].nsets)
+ error("Number of patches between '%s' and '%s' doesn't match",devname,ciename);
+
+ if ((f_id2 = ncie->find_field(ncie, 0, "SampleName")) < 0
+ && (f_id2 = ncie->find_field(ncie, 0, "Sample_Name")) < 0
+ && (f_id2 = ncie->find_field(ncie, 0, "SAMPLE_NAME")) < 0
+ && (f_id2 = ncie->find_field(ncie, 0, "SAMPLE_ID")) < 0)
+ error("Input file '%s' doesn't contain field SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_ID",ciename);
+ if (ncie->t[0].ftype[f_id2] != nqcs_t
+ && ncie->t[0].ftype[f_id2] != cs_t
+ && cmy->t[0].ftype[f_id2] != i_t)
+ error("Field SampleName (%s) from cie file '%s' is wrong type",ncie->t[0].fsym[f_id2],ciename);
+
+ if (ncie->find_field(ncie, 0, "XYZ_X") < 0
+ && ncie->find_field(ncie, 0, "LAB_L") < 0) {
+
+ /* Not a cie file. See if it's a spectral file */
+ if (ncie->find_field(ncie, 0, "nm500") < 0
+ && ncie->find_field(ncie, 0, "NM_500") < 0
+ && ncie->find_field(ncie, 0, "SPECTRAL_NM_500") < 0
+ && ncie->find_field(ncie, 0, "R_500") < 0
+ && ncie->find_field(ncie, 0, "SPECTRAL_500") < 0)
+ error("Input file '%s' doesn't contain field XYZ_X or spectral",ciename); /* Nope */
+
+ /* We have a spectral file only. Fix things and drop through */
+ ncie->del(ncie);
+ ncie = NULL;
+ strcpy(specname, ciename);
+ ciename[0] = '\000';
+
+ } else { /* Continue dealing with cie value file */
+ char *fields[2][3] = {
+ { "XYZ_X", "XYZ_Y", "XYZ_Z" },
+ { "LAB_L", "LAB_A", "LAB_B" }
+ };
+
+ if (ncie->find_field(ncie, 0, "nm500") >= 0
+ || ncie->find_field(ncie, 0, "NM_500") < 0
+ || ncie->find_field(ncie, 0, "SPECTRAL_NM_500") >= 0
+ || ncie->find_field(ncie, 0, "R_500") >= 0
+ || ncie->find_field(ncie, 0, "SPECTRAL_500") >= 0) {
+ if (verb) printf("Found spectral values\n");
+ /* It's got spectral data too. Make sure we read it */
+ strcpy(specname, ciename);
+ }
+
+ if (ncie->find_field(ncie, 0, "LAB_L") >= 0)
+ islab = 1;
+
+ for (i = 0; i < 3; i++) {
+
+ if ((f_cie[i] = ncie->find_field(ncie, 0, fields[islab][i])) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Y",fields[islab][i], ciename);
+
+ if (ncie->t[0].ftype[f_cie[i]] != r_t)
+ error("Field %s from file '%s' is wrong type",fields[islab][i], ciename);
+ }
+
+ if (verb) printf("Found CIE values\n");
+ }
+
+ /* Open up the input Spectral device data file */
+ if (specname[0] != '\000') {
+ char bufs[5][50];
+
+ spec = new_cgats(); /* Create a CGATS structure */
+ spec->add_other(spec, "LGOROWLENGTH"); /* Gretag/Logo Target file */
+ spec->add_other(spec, "ECI2002"); /* Gretag/Logo Target file */
+ spec->add_other(spec, ""); /* Wildcard */
+ if (spec->read_name(spec, specname))
+ error ("Read: Can't read spec file '%s'. Unknown format or corrupted file ?",specname);
+ if (spec->ntables != 1)
+ warning("Input file '%s' doesn't contain exactly one table",specname);
+
+ if (npat != spec->t[0].nsets)
+ error("Number of patches between '%s' and '%s' doesn't match",specname);
+
+ if ((f_id3 = spec->find_field(spec, 0, "SampleName")) < 0
+ && (f_id3 = spec->find_field(spec, 0, "Sample_Name")) < 0
+ && (f_id3 = spec->find_field(spec, 0, "SAMPLE_NAME")) < 0
+ && (f_id3 = spec->find_field(spec, 0, "SAMPLE_ID")) < 0)
+ error("Input file '%s' doesn't contain field SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_ID",specname);
+ if (spec->t[0].ftype[f_id3] != nqcs_t
+ && spec->t[0].ftype[f_id3] != cs_t
+ && cmy->t[0].ftype[f_id3] != i_t)
+ error("Field SampleName (%s) from spec file '%s' is wrong type",spec->t[0].fsym[f_id3],specname);
+
+ /* Find the spectral readings nm range */
+ for (specmin = 500; specmin >= 300; specmin -= 10) {
+ sprintf(bufs[0],"nm%03d", specmin);
+ sprintf(bufs[1],"NM_%03d", specmin);
+ sprintf(bufs[2],"SPECTRAL_NM_%03d", specmin);
+ sprintf(bufs[3],"R_%03d", specmin);
+ sprintf(bufs[4],"SPECTRAL_%03d", specmin);
+
+ if (spec->find_field(spec, 0, bufs[0]) < 0
+ && spec->find_field(spec, 0, bufs[1]) < 0
+ && spec->find_field(spec, 0, bufs[2]) < 0
+ && spec->find_field(spec, 0, bufs[3]) < 0
+ && spec->find_field(spec, 0, bufs[4]) < 0) /* Not found */
+ break;
+ }
+ specmin += 10;
+ for (specmax = 500; specmax <= 900; specmax += 10) {
+ sprintf(bufs[0],"nm%03d", specmax);
+ sprintf(bufs[1],"NM_%03d", specmax);
+ sprintf(bufs[2],"SPECTRAL_NM_%03d", specmax);
+ sprintf(bufs[3],"R_%03d", specmax);
+ sprintf(bufs[4],"SPECTRAL_%03d", specmax);
+
+ if (spec->find_field(spec, 0, bufs[0]) < 0
+ && spec->find_field(spec, 0, bufs[1]) < 0
+ && spec->find_field(spec, 0, bufs[2]) < 0
+ && spec->find_field(spec, 0, bufs[3]) < 0
+ && spec->find_field(spec, 0, bufs[4]) < 0) /* Not found */
+ break;
+ }
+ specmax -= 10;
+
+ if (specmin > 420 || specmax < 680) { /* Not enough range to be useful */
+ spec->del(spec);
+ spec = NULL;
+ specname[0] = '\000';
+ } else {
+
+ specnum = (specmax - specmin)/10 + 1;
+
+ if (verb)
+ printf("Found there are %d spectral values, from %d to %d nm\n",specnum,specmin,specmax);
+
+
+ /* Locate the fields for spectral values */
+ for (j = 0; j < specnum; j++) {
+ sprintf(bufs[0],"nm%03d", specmin + 10 * j);
+ sprintf(bufs[1],"NM_%03d", specmin + 10 * j);
+ sprintf(bufs[2],"SPECTRAL_NM_%03d", specmin + 10 * j);
+ sprintf(bufs[3],"R_%03d", specmin + 10 * j);
+ sprintf(bufs[4],"SPECTRAL_%03d", specmin + 10 * j);
+
+ if ((spi[j] = spec->find_field(spec, 0, bufs[0])) < 0
+ && (spi[j] = spec->find_field(spec, 0, bufs[1])) < 0
+ && (spi[j] = spec->find_field(spec, 0, bufs[2])) < 0
+ && (spi[j] = spec->find_field(spec, 0, bufs[3])) < 0
+ && (spi[j] = spec->find_field(spec, 0, bufs[4])) < 0) { /* Not found */
+
+ spec->del(spec);
+ spec = NULL;
+ specname[0] = '\000';
+ error("Failed to find spectral band %d nm in file '%s'\n",specmin + 10 * j,specname);
+ } else {
+ if (spec->t[0].ftype[spi[j]] != r_t)
+ error("Field '%s' from file '%s' is wrong type",spec->t[0].fsym[spi[j]], specname);
+ }
+
+ }
+ }
+ }
+
+ if (ciename[0] == '\000' && specname[0] == '\000')
+ error("Input file doesn't contain either CIE or spectral data");
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll target", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+ if (disp)
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL); /* What sort of device this is */
+ else if (inp)
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","INPUT", NULL); /* What sort of device this is */
+ else
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL); /* What sort of device this is */
+
+ /* Note what instrument the chart was read with */
+ /* Assume this - could try reading from file INSTRUMENTATION "SpectroScan" ?? */
+ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(instSpectrolino) , NULL);
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+ if (f_id1 >= 0)
+ ocg->add_field(ocg, 0, "SAMPLE_NAME", cs_t);
+
+ if (ndchan == 3) {
+ ocg->add_field(ocg, 0, "RGB_R", r_t);
+ ocg->add_field(ocg, 0, "RGB_G", r_t);
+ ocg->add_field(ocg, 0, "RGB_B", r_t);
+ if (inp) {
+ if (islab)
+ ocg->add_kword(ocg, 0, "COLOR_REP","LAB_RGB", NULL);
+ else
+ ocg->add_kword(ocg, 0, "COLOR_REP","XYZ_RGB", NULL);
+ } else if (disp) {
+ if (islab)
+ ocg->add_kword(ocg, 0, "COLOR_REP","RGB_LAB", NULL);
+ else
+ ocg->add_kword(ocg, 0, "COLOR_REP","RGB_XYZ", NULL);
+ } else {
+ if (islab)
+ ocg->add_kword(ocg, 0, "COLOR_REP","iRGB_LAB", NULL);
+ else
+ ocg->add_kword(ocg, 0, "COLOR_REP","iRGB_XYZ", NULL);
+ }
+ } else if (ndchan == 4) {
+ ocg->add_field(ocg, 0, "CMYK_C", r_t);
+ ocg->add_field(ocg, 0, "CMYK_M", r_t);
+ ocg->add_field(ocg, 0, "CMYK_Y", r_t);
+ ocg->add_field(ocg, 0, "CMYK_K", r_t);
+ if (inp) { /* Does this make any sense ? */
+ if (islab)
+ ocg->add_kword(ocg, 0, "COLOR_REP","LAB_CMYK", NULL);
+ else
+ ocg->add_kword(ocg, 0, "COLOR_REP","XYZ_CMYK", NULL);
+ } else {
+ if (islab)
+ ocg->add_kword(ocg, 0, "COLOR_REP","CMYK_LAB", NULL);
+ else
+ ocg->add_kword(ocg, 0, "COLOR_REP","CMYK_XYZ", NULL);
+ }
+ }
+
+ if (ncie != NULL) {
+ if (islab) {
+ ocg->add_field(ocg, 0, "LAB_L", r_t);
+ ocg->add_field(ocg, 0, "LAB_A", r_t);
+ ocg->add_field(ocg, 0, "LAB_B", r_t);
+ } else {
+ ocg->add_field(ocg, 0, "XYZ_X", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Y", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Z", r_t);
+ }
+ }
+
+ /* Guess the device data scaling */
+ if (ndchan > 0) {
+ double maxv = 0.0;
+ int f_dev[4] = { f_c, f_m, f_y, f_k };
+
+ /* Guess what scale the spectral data is set to */
+ for (i = 0; i < npat; i++) {
+ for (j = 0; j < ndchan; j++) {
+ double vv;
+ vv = *((double *)cmy->t[0].fdata[i][f_dev[j]]);
+ if (vv > maxv)
+ maxv = vv;
+ }
+ }
+ if (maxv < 10.0) {
+ dev_scale = 100.0/1.0;
+ if (verb) printf("Device max found = %f, scale by 100.0\n",maxv);
+ } else if (maxv > 160.0) {
+ dev_scale = 100.0/255.0;
+ if (verb) printf("Device max found = %f, scale by 100/255\n",maxv);
+ } else {
+ dev_scale = 100.0/100.0;
+ if (verb) printf("Device max found = %f, scale by 1.0\n",maxv);
+ }
+ }
+
+ if (spec != NULL) {
+ char buf[100];
+ double maxv = 0.0;
+ sprintf(buf,"%d", specnum);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+ sprintf(buf,"%d", specmin);
+ ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
+ sprintf(buf,"%d", specmax);
+ ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);
+
+ /* Generate fields for spectral values */
+ for (j = 0; j < specnum; j++) {
+ sprintf(buf,"SPEC_%03d", specmin + 10 * j);
+ ocg->add_field(ocg, 0, buf, r_t);
+ }
+
+ /* Guess what scale the spectral data is set to */
+ for (i = 0; i < npat; i++) {
+ for (j = 0; j < specnum; j++) {
+ double vv;
+ vv = *((double *)spec->t[0].fdata[i][spi[j]]);
+ if (vv > maxv)
+ maxv = vv;
+ }
+ }
+ if (maxv < 10.0) {
+ spec_scale = 100.0/1.0;
+ if (verb) printf("Spectral max found = %f, scale by 100.0\n",maxv);
+ } else if (maxv > 160.0) {
+ spec_scale = 100.0/255.0;
+ if (verb) printf("Spectral max found = %f, scale by 100/255\n",maxv);
+ } else {
+ spec_scale = 100.0/100.0;
+ if (verb) printf("Spectral max found = %f, scale by 1.0\n",maxv);
+ }
+ }
+
+ /* Write out the patch info to the output CGATS file */
+ {
+ cgats_set_elem *setel; /* Array of set value elements */
+
+ if ((setel = (cgats_set_elem *)malloc(
+ sizeof(cgats_set_elem) * ocg->t[0].nfields)) == NULL)
+ error("Malloc failed!");
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < npat; i++) {
+ char id[100];
+ int k = 0;
+
+ if (ncie != NULL) {
+ if (strcmp(((char *)cmy->t[0].rfdata[i][f_id1]),
+ ((char *)ncie->t[0].rfdata[i][f_id2])) != 0) {
+ error("Patch label mismatch to CIE values, patch %d, '%s' != '%s'\n",
+ i, ((char *)cmy->t[0].rfdata[i][f_id1]),
+ ((char *)ncie->t[0].rfdata[i][f_id2]));
+ }
+ }
+
+ if (spec != NULL) {
+ if (strcmp(((char *)cmy->t[0].rfdata[i][f_id1]),
+ ((char *)spec->t[0].rfdata[i][f_id3])) != 0) {
+ error("Patch label mismatch to spectral values, patch %d, '%s' != '%s'\n",
+ i, ((char *)cmy->t[0].rfdata[i][f_id1]),
+ ((char *)spec->t[0].rfdata[i][f_id3]));
+ }
+ }
+
+ /* SAMPLE ID */
+ sprintf(id, "%d", i+1);
+ setel[k++].c = id;
+
+ /* SAMPLE NAME */
+ if (f_id1 >= 0)
+ setel[k++].c = (char *)cmy->t[0].rfdata[i][f_id1];
+
+ if (ndchan == 3) {
+ setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_c]);
+ setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_m]);
+ setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_y]);
+ } else if (ndchan == 4){
+ double sum = 0.0;
+ sum += setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_c]);
+ sum += setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_m]);
+ sum += setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_y]);
+ sum += setel[k++].d = dev_scale * *((double *)cmy->t[0].fdata[i][f_k]);
+ if (sum > mxsum) {
+ mxsum = sum;
+ mxsumix = i;
+ }
+ }
+
+ if (ncie != NULL) {
+ setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[0]]);
+ setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[1]]);
+ setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[2]]);
+ }
+
+ if (spec) {
+ for (j = 0; j < specnum; j++) {
+ setel[k++].d = spec_scale * *((double *)spec->t[0].fdata[i][spi[j]]);
+ }
+ }
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+ }
+
+ if (tlimit < 0 && mxsum > 0.0) {
+ if (verb)
+ printf("No ink limit given, using maximum %f found in file at %d\n",mxsum,mxsumix+1);
+
+ tlimit = (int)(mxsum + 0.5);
+ }
+
+ if (tlimit > 0) {
+ char buf[100];
+ sprintf(buf, "%d", tlimit);
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT", buf, NULL);
+ }
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ /* Create a dummy .ti2 file (used with scanin -r) */
+ if (out2) {
+
+ /* Setup output cgats file */
+ ocg2 = new_cgats(); /* Create a CGATS structure */
+ ocg2->add_other(ocg2, "CTI2"); /* our special type is Calibration Target Information 2 */
+ ocg2->add_table(ocg2, tt_other, 0); /* Start the first table */
+
+ ocg2->add_kword(ocg2, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 2",NULL);
+ ocg2->add_kword(ocg2, 0, "ORIGINATOR", "Argyll txt2ti3", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg2->add_kword(ocg2, 0, "CREATED",atm, NULL);
+ if (disp)
+ ocg2->add_kword(ocg2, 0, "DEVICE_CLASS","DISPLAY", NULL); /* What sort of device this is */
+ else
+ ocg2->add_kword(ocg2, 0, "DEVICE_CLASS","OUTPUT", NULL); /* What sort of device this is */
+ /* Note what instrument the chart was read with */
+ /* Assume this - could try reading from file INSTRUMENTATION "SpectroScan" ?? */
+ ocg2->add_kword(ocg2, 0, "TARGET_INSTRUMENT", inst_name(instSpectrolino) , NULL);
+
+ /* Fields we want */
+ ocg2->add_field(ocg2, 0, "SAMPLE_ID", nqcs_t);
+ ocg2->add_field(ocg2, 0, "SAMPLE_LOC", nqcs_t);
+
+ /* We're missing lots of .ti2 stuff like: */
+ /* ocg->add_kword(ocg, 0, "APPROX_WHITE_POINT",icg->t[0].kdata[fi], NULL); */
+ /* ocg->add_kword(ocg, 0, "PATCH_LENGTH", buf, NULL); */
+ /* ocg->add_kword(ocg, 0, "GAP_LENGTH", buf, NULL); */
+ /* ocg->add_kword(ocg, 0, "TRAILER_LENGTH", buf, NULL); */
+ /* ocg->add_kword(ocg, 0, "STEPS_IN_PASS", buf, NULL); */
+ /* ocg->add_kword(ocg, 0, "PASSES_IN_STRIPS", pis, NULL); */
+ /* ocg->add_kword(ocg, 0, "STRIP_INDEX_PATTERN", sixpat, NULL); */
+ /* ocg->add_kword(ocg, 0, "PATCH_INDEX_PATTERN", pixpat, NULL); */
+ /* ocg->add_kword(ocg, 0, "INDEX_ORDER", ixord ? "PATCH_THEN_STRIP" : "STRIP_THEN_PATCH", NULL); */
+
+ if (tlimit > 0) {
+ char buf[100];
+ sprintf(buf, "%d", tlimit);
+ ocg2->add_kword(ocg2, 0, "TOTAL_INK_LIMIT", buf, NULL);
+ }
+
+ if (ndchan == 3) {
+ ocg2->add_field(ocg2, 0, "RGB_R", r_t);
+ ocg2->add_field(ocg2, 0, "RGB_G", r_t);
+ ocg2->add_field(ocg2, 0, "RGB_B", r_t);
+ if (inp || disp) {
+ ocg2->add_kword(ocg2, 0, "COLOR_REP","RGB", NULL);
+ } else {
+ ocg2->add_kword(ocg2, 0, "COLOR_REP","iRGB", NULL);
+ }
+ } else if (ndchan == 4) {
+ ocg2->add_field(ocg2, 0, "CMYK_C", r_t);
+ ocg2->add_field(ocg2, 0, "CMYK_M", r_t);
+ ocg2->add_field(ocg2, 0, "CMYK_Y", r_t);
+ ocg2->add_field(ocg2, 0, "CMYK_K", r_t);
+ ocg2->add_kword(ocg2, 0, "COLOR_REP","CMYK", NULL);
+ }
+
+ if (ncie != NULL) {
+ if (islab) {
+ ocg2->add_field(ocg2, 0, "LAB_L", r_t);
+ ocg2->add_field(ocg2, 0, "LAB_A", r_t);
+ ocg2->add_field(ocg2, 0, "LAB_B", r_t);
+ } else {
+ ocg2->add_field(ocg2, 0, "XYZ_X", r_t);
+ ocg2->add_field(ocg2, 0, "XYZ_Y", r_t);
+ ocg2->add_field(ocg2, 0, "XYZ_Z", r_t);
+ }
+ }
+
+ /* Write out the patch info to the output CGATS file */
+ {
+ cgats_set_elem *setel; /* Array of set value elements */
+
+ if ((setel = (cgats_set_elem *)malloc(
+ sizeof(cgats_set_elem) * (2 + (ndchan) + (ncie != NULL ? 3 : 0)))) == NULL)
+ error("Malloc failed!");
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < npat; i++) {
+ char id[100];
+ int k = 0;
+
+ if (ncie != NULL) {
+ if (strcmp(((char *)cmy->t[0].rfdata[i][f_id1]),
+ ((char *)ncie->t[0].rfdata[i][f_id2])) != 0) {
+ error("Patch label mismatch to CIE values, patch %d, '%s' != '%s'\n",
+ i, ((char *)cmy->t[0].rfdata[i][f_id1]),
+ ((char *)ncie->t[0].rfdata[i][f_id2]));
+ }
+ }
+
+ if (spec != NULL) {
+ if (strcmp(((char *)cmy->t[0].rfdata[i][f_id1]),
+ ((char *)spec->t[0].rfdata[i][f_id3])) != 0) {
+ error("Patch label mismatch to spectral values, patch %d, '%s' != '%s'\n",
+ i, ((char *)cmy->t[0].rfdata[i][f_id1]),
+ ((char *)spec->t[0].rfdata[i][f_id3]));
+ }
+ }
+
+ sprintf(id, "%d", i+1);
+ setel[k++].c = id; /* ID */
+ setel[k++].c = ((char *)cmy->t[0].rfdata[i][f_id1]); /* Location */
+
+ if (ndchan == 3) {
+ setel[k++].d = 100.0/255.0 * *((double *)cmy->t[0].fdata[i][f_c]);
+ setel[k++].d = 100.0/255.0 * *((double *)cmy->t[0].fdata[i][f_m]);
+ setel[k++].d = 100.0/255.0 * *((double *)cmy->t[0].fdata[i][f_y]);
+ } else if (ndchan == 4) {
+ setel[k++].d = *((double *)cmy->t[0].fdata[i][f_c]);
+ setel[k++].d = *((double *)cmy->t[0].fdata[i][f_m]);
+ setel[k++].d = *((double *)cmy->t[0].fdata[i][f_y]);
+ setel[k++].d = *((double *)cmy->t[0].fdata[i][f_k]);
+ }
+
+ if (ncie != NULL) {
+ setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[0]]);
+ setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[1]]);
+ setel[k++].d = *((double *)ncie->t[0].fdata[i][f_cie[2]]);
+ }
+ ocg2->add_setarr(ocg2, 0, setel);
+ }
+
+ free(setel);
+ }
+
+ if (ocg2->write_name(ocg2, outname2))
+ error("Write error : %s",ocg2->err);
+
+ }
+
+ /* Clean up */
+ cmy->del(cmy);
+ if (ncie != NULL)
+ ncie->del(ncie);
+ if (spec != NULL)
+ spec->del(spec);
+ ocg->del(ocg);
+
+ return 0;
+}
+
+
+
diff --git a/profile/verify.c b/profile/verify.c
new file mode 100644
index 0000000..849d7fc
--- /dev/null
+++ b/profile/verify.c
@@ -0,0 +1,783 @@
+/*
+ * Argyll Color Correction System
+ * Verify two sets of PCS values.
+ *
+ * Author: Graeme W. Gill
+ * Date: 7/6/2005
+ *
+ * Copyright 2005 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.
+ */
+
+/*
+ * This program takes in two CGATS files (probably but not necesserily .ti3 files) of PCS
+ * values (either XYZ, L*a*b* or spectral), matches the values, and computes
+ * overall errors. This is useful for verifying proofing systems.
+ */
+
+/*
+ * TTBD:
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <string.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "vrml.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "ccmx.h"
+#include "insttypes.h"
+#include "sort.h"
+
+void
+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," -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");
+ fprintf(stderr," -s Sort patch values by error\n");
+ fprintf(stderr," -w create VRML vector visualisation (measured.wrl)\n");
+ fprintf(stderr," -W create VRML marker visualisation (measured.wrl)\n");
+ fprintf(stderr," -x Use VRML axes\n");
+ 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");
+ 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," -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");
+ exit(1);
+ }
+
+/* Patch value type */
+typedef struct {
+ char sid[50]; /* sample id */
+ double v[3]; /* Lab value */
+ double de; /* Delta E */
+} 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 cie94 = 0;
+ int cie2k = 0;
+ int dovrml = 0;
+ int doaxes = 0;
+ int dosort = 0;
+ char ccmxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction Matrix name */
+ ccmx *cmx = NULL; /* Colorimeter Correction Matrix */
+
+ 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 */
+ pval *pat; /* patch values */
+ } cg[2]; /* Target and current patch file information */
+
+ int *match; /* Array mapping first list indexes to corresponding second */
+ int *sort; /* Array of first list indexes in sorted order */
+ int fwacomp = 0; /* FWA compensation */
+ int spec = 0; /* Use spectral data flag */
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */
+ icxIllumeType illum = icxIT_D50; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxObserverType observ = icxOT_CIE_1931_2;
+
+ icmXYZNumber labw = icmD50; /* The Lab white reference */
+
+ char out_name[MAXNAMEL+4+1]; /* VRML name */
+ vrml *wrl = NULL;
+
+ int i, j, n;
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ /* normalize */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ norm = 1;
+ if (argv[fa][1] == 'N')
+ norm = 2;
+ }
+
+ else if (argv[fa][1] == 'D')
+ usestdd50 = 1;
+
+ /* VRML */
+ else if (argv[fa][1] == 'w')
+ dovrml = 1;
+ else if (argv[fa][1] == 'W')
+ dovrml = 2;
+
+ /* Axes */
+ else if (argv[fa][1] == 'x')
+ doaxes = 1;
+
+ /* CIE94 delta E */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ cie94 = 1;
+ cie2k = 0;
+ }
+
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ cie94 = 0;
+ cie2k = 1;
+ }
+
+ /* Sort */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S')
+ dosort = 1;
+
+ /* FWA compensation */
+ else if (argv[fa][1] == 'f') {
+ fwacomp = 1;
+
+ if (na != NULL) { /* Argument is present - target/simulated instr. illum. */
+ fa = nfa;
+ if (strcmp(na, "A") == 0
+ || strcmp(na, "M0") == 0) {
+ spec = 1;
+ tillum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ tillum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0
+ || strcmp(na, "M1") == 0) {
+ spec = 1;
+ tillum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0
+ || strcmp(na, "M2") == 0) {
+ spec = 1;
+ tillum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ tillum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ tillum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ tillum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ tillum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ tillum = icxIT_custom;
+ if (read_xspect(&cust_tillum, na) != 0)
+ usage();
+ }
+ }
+ }
+
+ /* Spectral to CIE Illuminant type */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "A") == 0) {
+ spec = 1;
+ illum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ illum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0) {
+ spec = 1;
+ illum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0) {
+ spec = 1;
+ illum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ illum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ illum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ illum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ illum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ illum = icxIT_custom;
+ if (read_xspect(&cust_illum, na) != 0)
+ usage();
+ }
+ }
+
+ /* Spectral Observer type */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ spec = 1;
+ observ = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ spec = 1;
+ observ = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ spec = 1;
+ observ = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ spec = 1;
+ observ = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ spec = 1;
+ observ = icxOT_Shaw_Fairchild_2;
+ } else
+ usage();
+ }
+
+ /* Colorimeter Correction Matrix for second file */
+ else if (argv[fa][1] == 'X') {
+ fa = nfa;
+ if (na == NULL) usage();
+ strncpy(ccmxname,na,MAXNAMEL-1); ccmxname[MAXNAMEL-1] = '\000';
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+ /* Get the file name arguments */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(cg[0].name,argv[fa++],MAXNAMEL); cg[0].name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(cg[1].name,argv[fa],MAXNAMEL); cg[1].name[MAXNAMEL] = '\000';
+
+ /* Create VRML name */
+ {
+ char *xl;
+ strcpy(out_name, cg[1].name);
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".wrl");
+ }
+
+ if (fwacomp && spec == 0)
+ error ("FWA compensation only works when viewer and/or illuminant selected");
+
+ /* Colorimeter Correction Matrix */
+ if (ccmxname[0] != '\000') {
+ if ((cmx = new_ccmx()) == NULL)
+ error("new_ccmx failed\n");
+ if (cmx->read_ccmx(cmx,ccmxname))
+ error("Reading Colorimeter Correction Matrix file '%s' failed with error %d:'%s'\n",
+ 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 xix, yix, zix;
+
+ /* Open CIE target values */
+ cgf = new_cgats(); /* Create a CGATS structure */
+ cgf->add_other(cgf, ""); /* Allow any signature file */
+
+ if (cgf->read_name(cgf, cg[n].name))
+ error("CGATS file '%s' read error : %s",cg[n].name,cgf->err);
+
+ if (cgf->ntables < 1)
+ error ("Input file '%s' doesn't contain at least one table",cg[n].name);
+
+ /* Check if the file is suitable */
+ if (!spec
+ && cgf->find_field(cgf, 0, "LAB_L") < 0
+ && cgf->find_field(cgf, 0, "XYZ_X") < 0) {
+
+ if (cgf->find_kword(cgf, 0, "SPECTRAL_BANDS") < 0)
+ error ("Neither CIE nor spectral data found in file '%s'",cg[n].name);
+
+ /* Switch to using spectral information */
+ if (verb)
+ printf("No CIE data found, switching to spectral with standard observer & D50 for file '%s'\n",cg[n].name);
+ spec = 1;
+ illum = icxIT_D50;
+ observ = icxOT_CIE_1931_2;
+ }
+ if (spec && cgf->find_kword(cgf, 0, "SPECTRAL_BANDS") < 0)
+ error ("No spectral data data found in file '%s' when spectral expected",cg[n].name);
+
+ if (!spec && cgf->find_field(cgf, 0, "LAB_L") >= 0)
+ isLab = 1;
+
+ cg[n].npat = cgf->t[0].nsets; /* Number of patches */
+
+ /* Figure out what sort of device it is */
+ {
+ int ti;
+
+ cg[n].isdisp = 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;
+ 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;
+ }
+ }
+
+ /* Read all the target patches */
+ if (cg[n].npat <= 0)
+ error("No sets of data in file '%s'",cg[n].name);
+
+ if (verb && n == 0) {
+ fprintf(verbo,"No of test patches = %d\n",cg[n].npat);
+ }
+
+ /* Allocate arrays to hold test patch input and output values */
+ if ((cg[n].pat = (pval *)malloc(sizeof(pval) * cg[n].npat)) == NULL)
+ error("Malloc failed - pat[]");
+
+ /* Read in the CGATs fields */
+ if ((sidx = cgf->find_field(cgf, 0, "SAMPLE_ID")) < 0
+ && (sidx = cgf->find_field(cgf, 0, "SampleName")) < 0
+ && (sidx = cgf->find_field(cgf, 0, "Sample_Name")) < 0
+ && (sidx = cgf->find_field(cgf, 0, "SAMPLE_NAME")) < 0
+ && (sidx = cgf->find_field(cgf, 0, "SAMPLE_LOC")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_ID, SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_LOC",cg[n].name);
+ if (cgf->t[0].ftype[sidx] != nqcs_t
+ && cgf->t[0].ftype[sidx] != cs_t)
+ error("Sample ID/Name field isn't a quoted or non quoted character string");
+
+ if (spec == 0) { /* Using instrument tristimulous value */
+
+ if (isLab) { /* Expect Lab */
+ if ((xix = cgf->find_field(cgf, 0, "LAB_L")) < 0)
+ error("Input file '%s' doesn't contain field LAB_L",cg[n].name);
+ if (cgf->t[0].ftype[xix] != r_t)
+ error("Field LAB_L is wrong type");
+ if ((yix = cgf->find_field(cgf, 0, "LAB_A")) < 0)
+ error("Input file '%s' doesn't contain field LAB_A",cg[n].name);
+ if (cgf->t[0].ftype[yix] != r_t)
+ error("Field LAB_A is wrong type");
+ if ((zix = cgf->find_field(cgf, 0, "LAB_B")) < 0)
+ error("Input file '%s' doesn't contain field LAB_B",cg[n].name);
+ if (cgf->t[0].ftype[zix] != r_t)
+ error("Field LAB_B is wrong type");
+
+ } else { /* Expect XYZ */
+ if ((xix = cgf->find_field(cgf, 0, "XYZ_X")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_X",cg[n].name);
+ if (cgf->t[0].ftype[xix] != r_t)
+ error("Field XYZ_X is wrong type");
+ if ((yix = cgf->find_field(cgf, 0, "XYZ_Y")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Y",cg[n].name);
+ if (cgf->t[0].ftype[yix] != r_t)
+ error("Field XYZ_Y is wrong type");
+ if ((zix = cgf->find_field(cgf, 0, "XYZ_Z")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Z",cg[n].name);
+ if (cgf->t[0].ftype[zix] != r_t)
+ error("Field XYZ_Z is wrong type");
+ }
+
+ 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;
+ }
+ } else { /* If Lab */
+ icmLab2XYZ(&icmD50, cg[n].pat[i].v, cg[n].pat[i].v);
+ }
+ /* Apply ccmx */
+ if (n == 1 && cmx != NULL) {
+ cmx->xform(cmx, cg[n].pat[i].v, cg[n].pat[i].v);
+ }
+ }
+
+ } else { /* Using spectral data */
+ int ii;
+ xspect sp;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xsp2cie *sp2cie; /* Spectral conversion object */
+
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ sp.spec_n = atoi(cgf->t[0].kdata[ii]);
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ sp.spec_wl_short = atof(cgf->t[0].kdata[ii]);
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ sp.spec_wl_long = atof(cgf->t[0].kdata[ii]);
+ if (!cg[n].isdisp || cg[n].isdnormed != 0)
+ sp.norm = 100.0;
+ else
+ sp.norm = 1.0;
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = cgf->find_field(cgf, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",buf);
+ }
+
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie(illum, illum == icxIT_none ? NULL : &cust_illum,
+ observ, NULL, icSigXYZData, icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+
+ if (fwacomp) {
+ int ti;
+ xspect mwsp; /* Medium spectrum */
+ instType itype; /* Spectral instrument type */
+ xspect insp; /* Instrument illuminant */
+
+ mwsp = sp; /* Struct copy */
+
+ if ((ti = cgf->find_kword(cgf, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Can't find target instrument in '%s' needed for FWA compensation",cg[n].name);
+
+ if ((itype = inst_enum(cgf->t[0].kdata[ti])) == instUnknown)
+ error ("Unrecognised target instrument '%s'", cgf->t[0].kdata[ti]);
+
+ if (inst_illuminant(&insp, itype) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+
+ /* Determine a media white spectral reflectance */
+ for (j = 0; j < mwsp.spec_n; j++)
+ mwsp.spec[j] = 0.0;
+
+ /* Since we don't want to assume that there are any associated device */
+ /* values present in each file, we can't use this as means of */
+ /* determining the media color. Use an alternative approach here, */
+ /* which may give slightly different results to profile. */
+
+ /* Track the maximum reflectance for any band to determine white. */
+ /* This might silently fail, if there isn't white in the sample set. */
+ for (i = 0; i < cg[0].npat; i++) {
+ for (j = 0; j < mwsp.spec_n; j++) {
+ double rv = *((double *)cgf->t[0].fdata[i][spi[j]]);
+ if (rv > mwsp.spec[j])
+ mwsp.spec[j] = rv;
+ }
+ }
+
+ /* If we are setting a specific simulated instrument illuminant */
+ if (tillum != icxIT_none) {
+ tillump = &cust_tillum;
+ if (tillum != icxIT_custom) {
+ if (standardIlluminant(tillump, tillum, 0.0)) {
+ error("simulated inst. illum. not recognised");
+ }
+ }
+ }
+
+ if (sp2cie->set_fwa(sp2cie, &insp, tillump, &mwsp))
+ error ("Set FWA on sp2cie failed");
+
+ if (verb) {
+ double FWAc;
+ sp2cie->get_fwa_info(sp2cie, &FWAc);
+ fprintf(verbo,"FWA content = %f\n",FWAc);
+ }
+ }
+
+ for (i = 0; i < cg[0].npat; i++) {
+
+ strcpy(cg[n].pat[i].sid, (char *)cgf->t[0].fdata[i][sidx]);
+
+ /* Read the spectral values for this patch */
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)cgf->t[0].fdata[i][spi[j]]);
+ }
+
+ /* Convert it to XYZ space */
+ sp2cie->convert(sp2cie, cg[n].pat[i].v, &sp);
+
+ /* Applu ccmx */
+ if (n == 1 && cmx != NULL) {
+ cmx->xform(cmx, cg[n].pat[i].v, cg[n].pat[i].v);
+ }
+ }
+
+ sp2cie->del(sp2cie); /* Done with this */
+
+ } /* End of reading in CGATs file */
+
+
+ /* Normalise this file to white = 1.0 or D50 */
+ if (norm) {
+ double bxyz[3] = { 0.0, -100.0, 0.0 };
+
+ /* 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);
+ }
+ }
+
+ /* 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];
+ } 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];
+ }
+ }
+ }
+ cgf->del(cgf); /* Clean up */
+ }
+ if (cmx != NULL)
+ cmx->del(cmx);
+ cmx = NULL;
+
+ /* Check that the number of test patches matches */
+ if (cg[0].npat != cg[1].npat)
+ error("Number of patches between '%s' and '%s' doesn't match",cg[0].name,cg[1].name);
+
+ /* Create a list to map the second list of patches to the first */
+ if ((match = (int *)malloc(sizeof(int) * cg[0].npat)) == NULL)
+ error("Malloc failed - match[]");
+ for (i = 0; i < cg[0].npat; i++) {
+ for (j = 0; j < cg[1].npat; j++) {
+ if (strcmp(cg[0].pat[i].sid, cg[1].pat[j].sid) == 0)
+ break; /* Found it */
+ }
+ if (j < cg[1].npat) {
+ match[i] = j;
+ } else {
+ error("Failed to find matching patch to '%s'",cg[0].pat[i].sid);
+ }
+ }
+
+ /* 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];
+ }
+ }
+ labw.X *= maxy/icmD50.Y; /* Scale white uniformly */
+ labw.Y *= maxy/icmD50.Y; /* Scale white uniformly */
+ labw.Z *= maxy/icmD50.Y;
+
+ if (verb)
+ printf("L*a*b* white reference = XYZ %f %f %f\n",labw.X,labw.Y,labw.Z);
+ }
+
+ /* 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);
+ }
+ }
+
+ /* Compute the delta E's */
+ for (i = 0; i < cg[0].npat; i++) {
+ 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);
+ }
+
+ /* Create sorted list, from worst to best. */
+ if ((sort = (int *)malloc(sizeof(int) * cg[0].npat)) == NULL)
+ error("Malloc failed - sort[]");
+ for (i = 0; i < cg[0].npat; i++)
+ sort[i] = i;
+
+#define HEAP_COMPARE(A,B) (cg[0].pat[A].de > cg[0].pat[B].de)
+ HEAPSORT(int, sort, cg[0].npat);
+#undef HEAP_COMPARE
+
+ /* - - - - - - - - - - */
+ /* Figure out the report */
+ {
+ double merr = 0.0, aerr = 0.0;
+ int n90;
+ double merr90 = 0.0, aerr90 = 0.0;
+ int n10;
+ double merr10 = 0.0, aerr10 = 0.0;
+ double rad;
+
+ if (dovrml) {
+ wrl = new_vrml(out_name, doaxes, 0);
+ wrl->start_line_set(wrl, 0);
+
+ /* Fudge sphere diameter */
+ rad = 10.0/pow(cg[0].npat, 1.0/3.0);
+ }
+
+ /* Do overall results */
+ for (i = 0; i < cg[0].npat; i++) {
+ double de;
+ if (dosort)
+ j = sort[i];
+ else
+ j = i;
+
+ de = cg[0].pat[j].de;
+ aerr += de;
+
+ if (verb) {
+ printf("%s: %f %f %f <=> %f %f %f de %f\n",
+ cg[0].pat[j].sid,
+ 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);
+ }
+
+ if (de > merr)
+ merr = de;
+
+ if (dovrml) {
+ if (de > 1e-6) {
+ wrl->add_vertex(wrl, 0, cg[0].pat[j].v);
+ wrl->add_vertex(wrl, 0, cg[1].pat[j].v);
+ }
+ if (dovrml == 2) {
+ wrl->add_marker(wrl, cg[0].pat[j].v, NULL, rad);
+ wrl->add_marker(wrl, cg[1].pat[j].v, NULL, rad);
+ }
+ }
+
+ }
+ if (cg[0].npat > 0)
+ aerr /= (double)cg[0].npat;
+
+ if (dovrml) {
+ wrl->make_lines(wrl, 0, 2);
+ wrl->del(wrl);
+ wrl = NULL;
+ }
+
+ /* 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++) {
+ double de = cg[0].pat[sort[i]].de;
+ aerr90 += de;
+ if (de > merr90)
+ merr90 = de;
+ }
+ 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++) {
+ double de = cg[0].pat[sort[i]].de;
+ aerr10 += de;
+ if (de > merr10)
+ merr10 = de;
+ }
+ if (n10 > 0)
+ aerr10 /= (double)n10;
+
+ if (verb) {
+ fprintf(verbo,"No of test patches in worst 10%% are = %d\n",n10);
+ fprintf(verbo,"No of test patches in best 90%% are = %d\n",n90);
+ }
+ printf("Verify results:\n");
+ 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);
+
+ free(sort);
+ free(match);
+ free(cg[0].pat);
+ free(cg[1].pat);
+ }
+
+ return 0;
+}
+
+
diff --git a/ref/3dap5k.sp b/ref/3dap5k.sp
new file mode 100644
index 0000000..cfbc67d
--- /dev/null
+++ b/ref/3dap5k.sp
@@ -0,0 +1,103 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for 3DAP viewing booth at D50 - Foam reflector, extendedto 355nm by estimate of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Tue Apr 9 17:15:32 2002"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "355.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "3945.000"
+
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+NUMBER_OF_FIELDS 80
+BEGIN_DATA_FORMAT
+SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 44.97 103.94 164.9 200.88 269.8301111 310.0680556 414.1321667 586.6544444 1066.693611 1133.624333 1031.633944 972.29 1043.722333 1360.529389 2417.268111 3132.216667 2818.478056 2192.068111 1957.285667 2012.437833 2086.816 2149.097611 2205.945556 2264.570111 2339.1085 2399.303778 2451.353278 2494.1235 2516.631 2534.502167 2543.351444 2565.551778 2603.578944 2647.086278 2702.404611 3045.447667 3626.533111 3944.484778 3524.838667 3082.760333 2947.282889 2987.046333 3115.224611 3264.204778 3254.242611 3106.393611 3101.613167 3069.166278 3050.570056 3084.844278 3103.531722 3083.711278 3053.589722 3031.742722 2965.037333 2901.627444 2814.946667 2731.505611 2628.440667 2523.334611 2418.187556 2309.318778 2191.377056 2074.207278 1952.003389 1830.847556 1709.364111 1586.339889 1466.436333 1359.227167 1251.518111 1158.713556 1056.849167 982.2127778 900.2322778 833.9932222 763.601 692.7145556 643.0055556
+END_DATA
diff --git a/ref/CIE_C.sp b/ref/CIE_C.sp
new file mode 100644
index 0000000..8b771fe
--- /dev/null
+++ b/ref/CIE_C.sp
@@ -0,0 +1,118 @@
+SPECT
+
+DESCRIPTOR "Argyll CIE illuminant C spectral power"
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Thu Dec 02 23:05:57 2009"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "93"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "320.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "780.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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 93
+BEGIN_DATA_FORMAT
+SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+0.01 0.20 0.40 1.55 2.70 4.85 7.00 9.95 12.90 17.20 21.40 27.50 33.00 39.92 47.40 55.17 63.30 71.81 80.60 89.53 98.10 105.80 112.40 117.75 121.50 123.45 124.00 123.60 123.10 123.30 123.80 124.09 123.90 122.92 120.70 116.90 112.10 106.98 102.30 98.81 96.90 96.78 98.00 99.94 102.10 103.95 105.20 105.67 105.30 104.11 102.30 100.15 97.80 95.43 93.20 91.22 89.70 88.83 88.40 88.19 88.10 88.06 88.00 87.86 87.80 87.99 88.20 88.20 87.90 87.22 86.30 85.30 84.00 82.21 80.20 78.24 76.30 74.36 72.40 70.40 68.30 66.30 64.40 62.80 61.50 60.20 59.20 58.50 58.10 58.00 58.20 58.50 59.10
+END_DATA
diff --git a/ref/CMP_DT_003.cht b/ref/CMP_DT_003.cht
new file mode 100644
index 0000000..37411af
--- /dev/null
+++ b/ref/CMP_DT_003.cht
@@ -0,0 +1,336 @@
+
+BOXES 286
+ F _ _ 22 14 522 14 522 402 22 402
+ D ALL ALL _ _ 500 388 22 14 0 0
+ X A S 1 15 24.21052632 22.4 44.5 43.5 24.21052632 22.4
+
+BOX_SHRINK 3.0
+
+REF_ROTATION 0.0
+
+XLIST 20
+ 44.500000 1.0 1.0
+ 68.710526 1.0 1.0
+ 92.921053 1.0 1.0
+ 117.131579 1.0 1.0
+ 141.342105 1.0 1.0
+ 165.552632 1.0 1.0
+ 189.763158 1.0 1.0
+ 213.973684 1.0 1.0
+ 238.184211 1.0 1.0
+ 262.394737 1.0 1.0
+ 286.605263 1.0 1.0
+ 310.815790 1.0 1.0
+ 335.026316 1.0 1.0
+ 359.236842 1.0 1.0
+ 383.447368 1.0 1.0
+ 407.657895 1.0 1.0
+ 431.868421 1.0 1.0
+ 456.078947 1.0 1.0
+ 480.289474 1.0 1.0
+ 504.500000 1.0 1.0
+
+YLIST 16
+ 43.5000000 1.0 1.0
+ 65.9000000 1.0 1.0
+ 88.3000000 1.0 1.0
+ 110.7000000 1.0 1.0
+ 133.1000000 1.0 1.0
+ 155.5000000 1.0 1.0
+ 177.9000000 1.0 1.0
+ 200.3000000 1.0 1.0
+ 222.7000000 1.0 1.0
+ 245.1000000 1.0 1.0
+ 267.5000000 1.0 1.0
+ 289.9000000 1.0 1.0
+ 312.3000000 1.0 1.0
+ 334.7000000 1.0 1.0
+ 357.1000000 1.0 1.0
+ 379.5000000 1.0 1.0
+
+EXPECTED XYZ 285
+ A1 9.46 8.62 29.26
+ A2 75.93 84.68 17.08
+ A3 44.11 49.20 9.06
+ A4 74.02 82.54 15.47
+ A5 37.88 42.42 7.93
+ A6 70.26 78.24 13.90
+ A7 33.59 37.74 7.04
+ A8 64.25 71.82 12.27
+ A9 30.32 34.10 6.32
+ A10 57.13 63.83 11.22
+ A11 26.62 30.10 5.61
+ A12 51.96 58.23 10.31
+ A13 24.04 26.72 5.25
+ A14 47.16 52.59 9.77
+ A15 37.64 22.85 4.57
+ B1 8.18 6.87 23.20
+ B2 3.61 3.38 6.33
+ B3 20.88 23.43 4.87
+ B4 6.33 6.95 2.79
+ B5 16.96 19.17 4.20
+ B6 5.33 5.76 2.62
+ B7 13.34 14.75 3.69
+ B8 4.19 4.42 2.51
+ B9 11.50 12.44 3.41
+ B10 3.35 3.48 2.29
+ B11 9.89 10.67 3.24
+ B12 2.58 2.69 2.00
+ B13 8.23 9.01 3.11
+ B14 6.56 5.16 3.23
+ B15 24.38 14.64 3.70
+ C1 68.17 69.38 68.07
+ C2 36.78 42.46 59.62
+ C3 75.58 84.30 16.75
+ C4 75.91 84.25 23.05
+ C5 74.70 83.33 16.21
+ C6 75.40 83.27 27.19
+ C7 72.95 81.42 15.76
+ C8 76.66 83.97 33.57
+ C9 71.33 79.64 15.34
+ C10 76.21 82.14 39.39
+ C11 70.81 79.26 15.13
+ C12 78.61 84.06 47.87
+ C13 73.95 82.35 17.71
+ C14 60.78 52.94 41.53
+ C15 36.37 21.94 4.40
+ D1 7.77 6.43 21.76
+ D2 3.42 3.25 4.79
+ D3 10.85 14.71 3.95
+ D4 45.74 31.43 7.66
+ D5 64.97 58.40 40.57
+ D6 19.20 20.77 4.47
+ D7 75.67 77.88 68.77
+ D8 46.56 58.50 11.12
+ D9 63.18 64.06 65.19
+ D10 81.64 85.77 61.30
+ D11 65.37 58.65 46.40
+ D12 61.29 55.60 29.97
+ D13 39.33 30.42 13.58
+ D14 5.41 4.44 3.00
+ D15 21.48 13.05 3.51
+ E1 51.91 51.52 63.01
+ E2 33.50 39.48 59.55
+ E3 19.80 26.35 5.19
+ E4 40.01 32.11 15.48
+ E5 37.52 50.89 23.01
+ E6 12.96 19.59 4.87
+ E7 40.98 31.63 14.39
+ E8 82.08 84.89 69.04
+ E9 42.04 30.96 10.93
+ E10 22.65 16.11 3.94
+ E11 16.97 31.21 9.80
+ E12 17.85 13.86 4.54
+ E13 37.65 30.47 11.22
+ E14 59.56 52.44 35.78
+ E15 37.21 22.38 4.99
+ F1 7.29 5.92 19.97
+ F2 2.90 2.84 3.47
+ F3 23.09 24.88 26.94
+ F4 12.29 23.07 7.35
+ F5 3.78 3.96 3.02
+ F6 35.90 39.27 26.05
+ F7 31.18 36.48 44.00
+ F8 14.33 10.91 3.47
+ F9 51.06 46.54 12.01
+ F10 62.15 71.68 13.67
+ F11 45.60 30.43 40.49
+ F12 27.89 15.62 6.31
+ F13 39.47 27.31 5.08
+ F14 4.49 3.88 2.77
+ F15 19.73 12.17 3.49
+ G1 40.25 39.39 58.62
+ G2 19.66 22.70 47.78
+ G3 14.05 21.04 21.63
+ G4 25.20 38.40 38.99
+ G5 2.23 2.29 1.82
+ G6 32.34 44.38 25.97
+ G7 39.08 40.35 45.16
+ G8 21.91 25.22 7.66
+ G9 51.20 40.45 19.47
+ G10 53.69 54.84 12.82
+ G11 43.69 29.70 5.63
+ G12 14.51 14.92 41.81
+ G13 48.91 38.08 7.33
+ G14 57.75 51.93 23.98
+ G15 40.27 24.75 7.03
+ H1 6.40 5.14 17.21
+ H2 2.50 2.51 2.41
+ H3 29.45 31.10 6.27
+ H4 8.45 13.05 6.25
+ H5 86.92 89.85 72.02
+ H6 55.25 57.23 44.58
+ H7 61.04 63.45 50.22
+ H8 66.13 68.64 54.49
+ H9 72.30 74.84 59.86
+ H10 77.76 80.54 64.40
+ H11 51.45 33.36 33.30
+ H12 34.29 19.71 5.84
+ H13 58.12 53.49 9.49
+ H14 3.19 3.01 2.34
+ H15 17.14 10.82 3.44
+ I1 28.84 27.18 51.31
+ I2 26.22 30.11 55.57
+ I3 8.61 12.78 13.10
+ I4 33.19 47.31 44.96
+ I5 2.15 2.20 1.76
+ I6 49.64 51.25 39.42
+ I7 5.60 5.83 4.56
+ I8 7.15 7.43 5.74
+ I9 8.78 9.28 7.44
+ I10 10.72 11.21 8.69
+ I11 40.19 25.72 5.17
+ I12 24.06 30.11 17.13
+ I13 37.28 22.42 4.86
+ I14 55.52 50.69 14.17
+ I15 43.35 28.37 10.26
+ J1 5.89 4.70 15.90
+ J2 2.28 2.31 1.96
+ J3 27.11 24.41 4.88
+ J4 7.74 9.84 6.03
+ J5 89.34 92.52 73.92
+ J6 43.85 45.42 35.57
+ J7 4.30 4.50 3.43
+ J8 2.15 2.19 1.76
+ J9 2.09 2.14 1.72
+ J10 13.73 14.17 11.04
+ J11 48.54 31.76 20.77
+ J12 32.08 17.94 10.34
+ J13 40.10 26.64 5.08
+ J14 2.38 2.39 1.88
+ J15 14.87 9.67 3.40
+ K1 20.70 19.17 45.35
+ K2 50.77 57.51 66.01
+ K3 5.13 6.59 5.77
+ K4 39.68 52.97 51.16
+ K5 2.10 2.15 1.70
+ K6 38.94 40.21 31.90
+ K7 3.21 3.34 2.69
+ K8 2.41 2.47 1.98
+ K9 2.13 2.17 1.74
+ K10 15.60 16.15 12.73
+ K11 33.32 21.81 4.35
+ K12 27.52 31.82 32.36
+ K13 56.60 50.73 8.89
+ K14 45.02 29.35 9.98
+ K15 33.62 20.13 4.15
+ L1 5.46 4.40 14.88
+ L2 2.11 2.16 1.70
+ L3 25.77 20.56 4.52
+ L4 7.71 9.80 5.98
+ L5 84.08 86.79 69.98
+ L6 33.50 34.70 27.85
+ L7 29.61 30.66 23.86
+ L8 24.73 25.62 19.83
+ L9 21.29 22.01 17.44
+ L10 18.36 19.06 15.25
+ L11 46.52 30.74 11.47
+ L12 24.42 16.78 15.94
+ L13 52.38 41.58 7.87
+ L14 2.21 2.25 1.78
+ L15 13.22 8.72 3.42
+ M1 14.98 13.99 39.67
+ M2 11.85 13.25 28.34
+ M3 12.36 12.97 3.50
+ M4 61.64 70.63 61.46
+ M5 2.71 2.82 2.20
+ M6 19.68 32.16 26.16
+ M7 22.82 21.24 9.05
+ M8 18.52 24.40 39.35
+ M9 12.91 11.12 3.85
+ M10 30.16 32.59 40.27
+ M11 19.93 15.24 35.28
+ M12 23.31 32.50 35.69
+ M13 40.57 29.47 5.44
+ M14 48.37 32.78 13.33
+ M15 33.33 19.90 4.09
+ N1 4.94 4.06 12.92
+ N2 2.11 2.17 1.71
+ N3 24.26 17.39 4.08
+ N4 7.07 6.36 6.03
+ N5 4.99 5.20 4.01
+ N6 16.13 29.37 14.18
+ N7 26.00 22.77 21.27
+ N8 19.90 28.01 35.06
+ N9 13.59 11.19 8.53
+ N10 25.06 17.40 4.36
+ N11 45.92 30.60 7.35
+ N12 23.35 22.39 17.67
+ N13 32.06 32.06 6.36
+ N14 2.19 2.22 1.79
+ N15 11.33 7.77 3.42
+ O1 10.02 9.28 31.17
+ O2 10.76 11.90 24.53
+ O3 42.31 54.55 53.67
+ O4 19.88 26.90 37.20
+ O5 13.56 15.96 37.55
+ O6 4.92 5.13 7.76
+ O7 5.99 4.89 16.71
+ O8 86.01 88.32 70.07
+ O9 41.28 54.49 46.60
+ O10 54.51 66.41 49.82
+ O11 6.39 4.76 7.70
+ O12 7.47 7.24 24.02
+ O13 10.20 9.57 23.31
+ O14 53.00 38.17 18.52
+ O15 32.29 19.09 3.94
+ P1 4.39 3.79 10.44
+ P2 23.77 36.35 37.44
+ P3 9.32 10.17 16.69
+ P4 21.20 34.66 29.30
+ P5 13.42 11.68 33.90
+ P6 85.83 89.93 70.83
+ P7 10.92 10.20 33.11
+ P8 68.39 77.72 54.98
+ P9 74.31 69.95 50.96
+ P10 76.65 83.76 61.45
+ P11 22.36 24.83 36.36
+ P12 53.63 58.46 57.53
+ P13 5.08 4.20 5.62
+ P14 56.95 44.27 24.67
+ P15 9.35 6.75 3.46
+ Q1 8.80 8.07 28.22
+ Q2 23.52 36.04 37.29
+ Q3 20.50 35.70 11.97
+ Q4 30.51 46.22 20.80
+ Q5 20.45 35.69 11.99
+ Q6 36.10 51.62 25.45
+ Q7 20.44 35.71 12.27
+ Q8 41.63 56.54 30.57
+ Q9 21.38 36.76 13.48
+ Q10 51.17 64.25 39.66
+ Q11 23.24 38.80 15.22
+ Q12 62.32 72.88 49.66
+ Q13 26.49 42.23 17.36
+ Q14 60.98 51.36 33.35
+ Q15 29.32 17.44 3.82
+ R1 3.95 3.59 8.36
+ R2 20.13 30.86 31.56
+ R3 10.16 18.47 6.04
+ R4 4.78 6.56 3.40
+ R5 9.21 15.96 5.65
+ R6 4.38 5.64 3.17
+ R7 8.46 14.35 5.50
+ R8 3.97 4.84 3.01
+ R9 7.21 11.73 4.98
+ R10 3.21 3.65 2.53
+ R11 6.23 9.66 4.43
+ R12 2.54 2.69 2.07
+ R13 5.50 7.95 3.98
+ R14 65.19 58.07 40.38
+ R15 7.60 5.78 3.43
+ S1 8.92 8.17 28.21
+ S2 20.24 35.38 11.78
+ S3 17.56 32.25 10.31
+ S4 19.54 34.67 11.34
+ S5 17.29 31.99 10.02
+ S6 18.80 33.75 11.17
+ S7 16.23 30.73 9.38
+ S8 16.69 31.26 9.79
+ S9 14.30 27.57 7.99
+ S10 19.72 34.91 12.50
+ S11 12.91 24.49 7.31
+ S12 26.55 41.95 17.28
+ S13 11.56 21.36 6.62
+ S14 33.15 44.32 24.54
+ S15 26.38 15.91 3.70
diff --git a/ref/CMP_Digital_Target-3.cht b/ref/CMP_Digital_Target-3.cht
new file mode 100644
index 0000000..eb95ed8
--- /dev/null
+++ b/ref/CMP_Digital_Target-3.cht
@@ -0,0 +1,1210 @@
+
+BOXES 571
+ F _ _ 100 200 3100 200 3100 2100 100 2100
+ D ALL ALL _ _ 3200 200 0 0 0 0
+ X A Z 1 19 100 100 100 200 100 100
+ X 2A 2D 1 19 100 100 2700 200 100 100
+
+BOX_SHRINK 12
+
+REF_ROTATION 0.0
+
+XLIST 31
+ 100 1 1
+ 200 1 1
+ 300 1 1
+ 400 1 1
+ 500 1 1
+ 600 1 1
+ 700 1 1
+ 800 1 1
+ 900 1 1
+ 1000 1 1
+ 1100 1 1
+ 1200 1 1
+ 1300 1 1
+ 1400 1 1
+ 1500 1 1
+ 1600 1 1
+ 1700 1 1
+ 1800 1 1
+ 1900 1 1
+ 2000 1 1
+ 2100 1 1
+ 2200 1 1
+ 2300 1 1
+ 2400 1 1
+ 2500 1 1
+ 2600 1 1
+ 2700 1 1
+ 2800 1 1
+ 2900 1 1
+ 3000 1 1
+ 3100 1 1
+
+YLIST 21
+ 200 1 1
+ 300 1 1
+ 400 1 1
+ 500 1 1
+ 600 1 1
+ 700 1 1
+ 800 1 1
+ 900 1 1
+ 1000 1 1
+ 1100 1 1
+ 1200 1 1
+ 1300 1 1
+ 1400 1 1
+ 1500 1 1
+ 1500 1 1
+ 1600 1 1
+ 1700 1 1
+ 1800 1 1
+ 1900 1 1
+ 2000 1 1
+ 2100 1 1
+
+EXPECTED XYZ 570
+A1 19.991 14.120 27.886
+B1 19.926 34.054 14.005
+C1 6.2319 5.6339 19.078
+D1 32.785 35.198 16.672
+E1 38.996 22.658 25.805
+F1 16.011 17.612 14.561
+G1 39.496 24.997 12.003
+H1 7.4905 6.2468 18.358
+I1 11.987 23.286 6.5928
+J1 16.591 12.444 27.331
+K1 63.038 64.179 58.403
+L1 4.3513 3.8393 2.7750
+M1 27.386 30.873 42.527
+N1 31.789 44.281 40.439
+O1 59.453 61.985 40.335
+P1 26.783 15.713 3.5833
+Q1 3.0238 3.6843 3.0876
+R1 15.462 28.885 12.776
+S1 23.694 16.421 29.352
+T1 65.900 73.381 11.377
+U1 8.3333 15.036 13.749
+V1 72.416 77.985 33.423
+W1 16.393 25.254 38.122
+X1 2.3144 2.3581 1.9303
+Y1 27.102 23.276 16.813
+Z1 2.6994 2.8850 2.2332
+2A1 10.757 20.588 4.8216
+2B1 40.765 45.919 58.857
+2C1 22.864 16.381 33.839
+2D1 28.289 21.404 20.483
+A2 10.412 10.567 30.978
+B2 24.139 14.085 3.5857
+C2 19.473 21.752 38.376
+D2 26.280 16.991 28.035
+E2 42.573 39.671 9.6556
+F2 17.113 18.705 43.690
+G2 35.850 22.548 3.8554
+H2 13.037 10.392 26.425
+I2 14.946 28.262 8.1825
+J2 3.1780 3.3914 2.3047
+K2 35.880 35.178 26.683
+L2 36.434 22.147 28.386
+M2 17.689 17.022 15.072
+N2 36.396 23.022 13.623
+O2 19.884 26.988 39.544
+P2 10.294 7.4271 3.4839
+Q2 24.415 37.008 36.288
+R2 36.078 21.682 26.898
+S2 12.232 12.247 33.412
+T2 12.486 23.920 5.4357
+U2 38.913 47.091 40.794
+V2 8.3779 6.8387 3.7119
+W2 2.3401 2.3804 1.9157
+X2 17.501 20.678 9.7225
+Y2 60.324 56.490 9.7029
+Z2 18.340 14.257 6.9452
+2A2 39.051 50.700 6.0515
+2B2 5.3134 8.7205 3.7883
+2C2 24.040 16.842 14.641
+2D2 10.963 22.720 8.1563
+A3 3.2215 2.8069 3.1344
+B3 35.703 49.122 24.276
+C3 9.6710 9.2674 28.141
+D3 39.368 42.329 16.693
+E3 9.8448 9.8037 29.501
+F3 50.040 60.997 38.371
+G3 9.8731 9.2375 28.216
+H3 31.926 43.409 5.2962
+I3 18.889 24.530 52.235
+J3 36.271 22.167 11.952
+K3 34.281 37.060 50.573
+L3 2.4511 2.5353 2.0398
+M3 34.120 37.136 30.510
+N3 28.309 16.461 3.7229
+O3 12.851 10.508 27.052
+P3 24.532 27.910 7.4170
+Q3 29.800 23.719 40.761
+R3 11.420 17.249 4.2060
+S3 30.098 17.923 3.6411
+T3 15.102 16.455 41.548
+U3 16.816 29.880 6.2892
+V3 19.054 17.886 40.635
+W3 21.160 13.146 3.6418
+X3 56.827 44.647 36.033
+Y3 7.3224 13.350 4.3645
+Z3 34.447 20.515 11.595
+2A3 10.795 11.448 32.464
+2B3 20.617 25.691 5.5795
+2C3 11.126 10.174 28.914
+2D3 68.724 66.102 56.410
+A4 19.671 15.554 33.919
+B4 17.501 19.753 3.8498
+C4 21.509 25.734 51.674
+D4 51.958 42.451 9.1213
+E4 14.112 17.806 42.697
+F4 61.487 65.884 27.427
+G4 38.420 23.239 29.457
+H4 9.8759 9.7311 29.126
+I4 75.793 79.718 46.695
+J4 10.595 15.480 24.653
+K4 32.187 21.331 32.814
+L4 13.777 17.753 16.663
+M4 27.339 16.027 3.5603
+N4 16.922 28.995 29.336
+O4 6.3066 4.7610 6.9921
+P4 22.390 29.210 15.592
+Q4 30.657 20.369 32.268
+R4 19.152 19.807 15.592
+S4 13.948 25.671 5.2122
+T4 14.991 27.898 19.745
+U4 11.486 7.6381 12.484
+V4 10.749 11.899 3.2945
+W4 77.699 80.782 67.995
+X4 24.430 21.610 7.1800
+Y4 3.2104 3.1999 4.2513
+Z4 14.450 27.763 8.5197
+2A4 21.679 16.235 32.574
+2B4 15.737 29.267 10.078
+2C4 3.9226 4.4418 7.5674
+2D4 24.022 34.375 15.022
+A5 16.920 10.945 3.6233
+B5 32.876 32.373 51.547
+C5 23.454 37.144 7.5202
+D5 24.762 25.266 23.702
+E5 29.192 16.958 3.5359
+F5 23.640 37.186 26.447
+G5 20.387 28.842 4.7028
+H5 3.3636 4.0809 2.6833
+I5 23.272 35.820 35.198
+J5 30.642 19.573 30.103
+K5 22.753 35.416 35.064
+L5 11.209 7.8786 3.5144
+M5 17.513 29.721 30.234
+N5 2.9935 2.9559 2.2837
+O5 44.139 49.035 35.423
+P5 14.200 13.959 3.6761
+Q5 59.021 56.831 48.262
+R5 6.3401 9.2262 3.4989
+S5 45.700 49.818 40.124
+T5 9.3142 14.437 4.0636
+U5 2.3535 2.3975 1.9290
+V5 27.766 28.925 20.091
+W5 3.0887 2.9300 2.3596
+X5 8.7239 16.803 5.0276
+Y5 70.161 75.882 63.247
+Z5 11.191 11.244 16.654
+2A5 62.394 68.771 47.096
+2B5 12.640 10.459 27.333
+2C5 11.160 21.761 5.5099
+2D5 77.413 80.592 53.936
+A6 37.703 22.453 27.499
+B6 14.943 18.301 44.058
+C6 44.282 30.956 7.9185
+D6 10.440 18.144 6.5076
+E6 32.892 20.486 29.274
+F6 17.819 31.263 19.184
+G6 3.7468 3.6058 6.3752
+H6 45.907 41.132 28.818
+I6 4.4472 4.1158 9.1204
+J6 20.388 31.549 44.358
+K6 2.3970 2.4515 1.9961
+L6 14.323 24.343 14.536
+M6 2.3623 2.4293 1.9541
+N6 41.190 36.767 50.714
+O6 62.357 69.847 6.3069
+P6 10.124 10.811 31.915
+Q6 67.127 65.762 49.352
+R6 39.128 23.959 27.822
+S6 10.413 15.222 6.7952
+T6 41.195 30.074 26.292
+U6 8.4099 9.5591 6.5834
+V6 43.942 26.976 32.439
+W6 33.397 44.263 15.513
+X6 56.629 45.672 50.137
+Y6 10.198 10.583 6.9283
+Z6 42.782 29.822 40.386
+2A6 61.567 65.013 61.274
+2B6 21.335 15.115 28.916
+2C6 3.2203 3.7212 2.6005
+2D6 35.799 34.854 29.422
+A7 19.123 33.078 10.667
+B7 12.915 10.831 28.225
+C7 77.518 80.587 57.622
+D7 11.348 10.154 28.703
+E7 12.442 24.254 5.6475
+F7 15.345 13.969 34.910
+G7 52.703 61.988 5.9513
+H7 9.9056 10.888 32.881
+I7 67.471 66.483 44.705
+J7 8.8426 9.6268 8.1730
+K7 61.925 56.855 24.968
+L7 9.6349 10.726 32.427
+M7 32.435 45.157 6.1480
+N7 30.427 18.146 3.6270
+O7 16.928 17.695 11.911
+P7 56.094 48.894 4.9467
+Q7 11.934 11.778 20.573
+R7 15.285 28.434 6.3346
+S7 3.5054 4.3615 2.7830
+T7 35.099 44.589 58.771
+U7 26.155 17.005 28.079
+V7 8.9086 14.924 14.071
+W7 30.611 33.536 8.6858
+X7 79.113 81.784 66.503
+Y7 10.240 10.764 31.229
+Z7 11.976 23.218 5.4228
+2A7 9.9976 9.7574 28.929
+2B7 25.572 39.297 14.262
+2C7 66.257 69.908 5.8960
+2D7 14.893 16.603 41.626
+A8 12.100 24.359 8.4071
+B8 42.436 39.900 4.7260
+C8 20.574 15.216 20.136
+D8 12.701 25.255 8.1803
+E8 18.324 13.039 26.409
+F8 16.724 30.035 13.212
+G8 3.3200 3.1831 3.0291
+H8 20.304 33.570 24.443
+I8 2.9169 2.9009 3.0168
+J8 48.038 46.099 39.891
+K8 5.2241 8.0427 3.5985
+L8 38.619 50.368 44.407
+M8 2.3428 2.3959 1.9273
+N8 3.1956 3.3116 2.6415
+O8 10.494 10.847 8.8081
+P8 22.233 23.005 18.548
+Q8 39.317 40.778 33.056
+R8 63.147 65.480 53.862
+S8 28.252 23.514 24.400
+T8 14.520 26.909 5.4756
+U8 18.057 24.054 51.817
+V8 2.3402 2.3911 1.9209
+W8 77.838 79.255 64.883
+X8 14.232 12.342 3.5677
+Y8 31.451 43.594 39.472
+Z8 3.8429 5.0881 3.0661
+2A8 27.844 41.491 21.140
+2B8 2.4921 2.5648 2.0613
+2C8 34.635 36.777 50.964
+2D8 2.3436 2.3905 1.9440
+A9 46.811 59.109 25.406
+B9 35.695 26.905 33.928
+C9 8.0578 15.313 4.8058
+D9 70.562 68.540 46.575
+E9 10.633 11.656 33.787
+F9 54.113 43.360 23.933
+G9 7.1200 11.358 10.328
+H9 31.237 20.786 32.756
+I9 14.469 27.174 19.553
+J9 11.813 8.1727 3.4750
+K9 51.613 51.265 59.093
+L9 11.232 21.889 5.3482
+M9 2.3389 2.3932 1.9205
+N9 4.6543 4.8363 3.9004
+O9 11.973 12.444 10.082
+P9 24.548 25.410 20.720
+Q9 43.270 44.842 36.215
+R9 68.113 71.034 59.864
+S9 31.468 18.903 5.4734
+T9 3.2297 3.6435 2.9170
+U9 31.779 25.042 15.321
+V9 30.098 43.673 10.856
+W9 65.360 57.273 55.175
+X9 7.8261 15.682 5.0934
+Y9 30.151 17.603 3.5424
+Z9 14.169 10.872 25.545
+2A9 49.740 51.961 35.295
+2B9 19.293 14.167 28.533
+2C9 23.305 29.469 10.465
+2D9 22.420 16.254 30.792
+A10 7.4766 14.316 6.7672
+B10 30.693 34.185 4.8132
+C10 11.568 23.235 13.773
+D10 2.4307 2.4999 2.0171
+E10 30.140 19.949 31.751
+F10 15.810 25.353 37.521
+G10 2.4272 2.4936 1.9887
+H10 12.549 25.096 11.562
+I10 2.3402 2.3788 1.9223
+J10 13.387 24.235 23.958
+K10 25.478 22.853 4.3681
+L10 5.0366 4.2550 2.8902
+M10 2.3374 2.3915 1.9194
+N10 5.8942 6.1054 4.9143
+O10 13.462 14.013 11.428
+P10 27.055 28.014 23.007
+Q10 47.406 49.169 39.386
+R10 73.974 77.043 65.729
+S10 7.8358 8.0794 7.9176
+T10 54.395 42.563 48.165
+U10 11.113 22.841 7.7084
+V10 2.9394 3.4387 2.9247
+W10 13.284 25.973 11.867
+X10 2.4768 2.5120 2.1182
+Y10 27.102 26.481 19.829
+Z10 23.978 16.698 3.6586
+2A10 24.659 30.178 27.108
+2B10 13.618 8.1445 8.4106
+2C10 24.412 26.496 22.533
+2D10 5.2897 4.2252 10.803
+A11 15.662 9.9371 16.757
+B11 6.3528 11.756 4.1276
+C11 70.247 65.054 58.834
+D11 42.904 30.283 4.3741
+E11 33.675 37.292 27.259
+F11 7.3260 5.3398 8.4321
+G11 56.748 56.026 41.441
+H11 8.1585 8.7147 3.0001
+I11 54.512 56.195 42.466
+J11 4.9736 7.2275 6.1574
+K11 50.413 50.352 29.675
+L11 11.783 8.3671 18.993
+M11 2.4004 2.4632 1.9865
+N11 7.0502 7.2979 5.9348
+O11 15.157 15.663 12.643
+P11 30.809 31.935 26.037
+Q11 51.029 52.827 42.179
+R11 78.892 82.077 69.152
+S11 9.0391 9.3614 7.5795
+T11 54.688 46.067 27.270
+U11 7.0672 5.5203 3.1542
+V11 19.018 30.251 40.808
+W11 2.6438 2.7813 2.1741
+X11 20.294 33.254 28.954
+Y11 4.7917 4.3367 10.461
+Z11 39.678 51.335 44.730
+2A11 11.397 22.075 5.4606
+2B11 43.396 54.386 47.692
+2C11 9.0264 8.0855 4.5632
+2D11 29.263 17.239 3.6542
+A12 42.435 55.238 11.960
+B12 10.244 9.5241 28.550
+C12 25.557 39.490 11.397
+D12 9.5983 9.1448 8.3283
+E12 71.285 77.444 27.463
+F12 32.592 33.399 30.058
+G12 5.1430 4.3541 13.182
+H12 18.517 32.087 22.562
+I12 6.9977 5.1440 3.8014
+J12 69.246 76.042 17.844
+K12 10.642 7.6407 17.593
+L12 21.927 35.477 19.681
+M12 2.4287 2.4921 1.9949
+N12 7.9937 8.3172 6.7360
+O12 17.120 17.761 14.285
+P12 33.242 34.486 28.221
+Q12 55.136 57.000 45.303
+R12 84.047 87.070 71.496
+S12 46.799 45.618 34.284
+T12 6.6921 6.0185 19.773
+U12 31.583 45.365 15.646
+V12 35.975 22.808 7.0470
+W12 15.632 16.004 15.333
+X12 32.188 19.569 3.7849
+Y12 9.9981 9.6287 28.171
+Z12 14.429 27.348 6.4901
+2A12 13.822 12.446 29.936
+2B12 68.261 74.431 52.067
+2C12 2.4685 2.5621 2.0287
+2D12 28.798 30.974 45.549
+A13 14.129 10.884 26.286
+B13 21.280 29.662 4.6515
+C13 32.064 17.966 13.604
+D13 9.9611 10.733 32.277
+E13 51.845 54.927 28.181
+F13 6.3441 8.5421 15.068
+G13 68.699 71.452 46.387
+H13 10.374 10.902 29.169
+I13 26.203 23.997 4.3858
+J13 25.753 36.554 54.373
+K13 5.9068 4.9157 15.287
+L13 35.348 27.270 4.1933
+M13 2.6154 2.7053 2.1626
+N13 9.3637 9.6843 7.8391
+O13 19.359 20.106 16.147
+P13 36.624 37.957 30.671
+Q13 59.859 61.861 49.702
+R13 89.957 93.025 75.604
+S13 17.613 12.665 26.369
+T13 22.969 25.114 7.7873
+U13 13.623 8.3610 7.6135
+V13 59.661 54.433 33.140
+W13 15.045 10.609 3.4373
+X13 26.676 39.190 37.659
+Y13 16.770 18.831 3.7976
+Z13 16.243 13.004 15.620
+2A13 62.079 69.145 59.254
+2B13 9.8300 11.508 34.315
+2C13 13.378 8.4024 4.1065
+2D13 11.706 16.228 24.708
+A14 27.260 17.709 28.446
+B14 10.007 11.116 33.309
+C14 55.170 63.826 56.969
+D14 22.474 12.791 7.8220
+E14 17.833 19.340 7.6068
+F14 25.508 15.387 3.5019
+G14 28.674 42.244 25.294
+H14 20.013 14.167 27.201
+I14 2.4079 2.4331 1.9867
+J14 23.527 21.066 41.374
+K14 23.203 12.509 8.0121
+L14 48.486 42.511 43.112
+M14 8.6031 15.926 4.6200
+N14 53.107 53.884 48.977
+O14 3.9836 3.7404 6.5852
+P14 35.517 35.068 43.001
+Q14 37.782 22.314 19.042
+R14 17.467 17.105 13.104
+S14 22.370 35.508 5.9931
+T14 23.886 13.985 16.868
+U14 19.591 19.252 12.172
+V14 63.345 63.812 5.6645
+W14 12.028 10.481 3.3856
+X14 42.635 43.420 39.912
+Y14 19.856 32.192 5.1431
+Z14 15.570 17.641 12.711
+2A14 29.733 19.495 31.105
+2B14 81.209 84.285 67.959
+2C14 16.972 13.897 32.504
+2D14 20.262 27.906 7.7177
+A15 24.922 14.319 17.652
+B15 20.394 32.266 39.177
+C15 28.847 42.042 6.3345
+D15 27.579 26.553 23.681
+E15 38.874 23.290 19.357
+F15 36.703 46.352 27.027
+G15 34.061 22.803 34.531
+H15 10.113 11.921 31.879
+I15 64.423 58.008 39.281
+J15 9.4542 9.1717 6.7120
+K15 48.073 52.062 16.154
+L15 22.225 20.657 33.169
+M15 32.410 43.840 8.6168
+N15 19.932 29.141 53.896
+O15 8.2354 6.1612 3.2448
+P15 21.186 33.689 34.860
+Q15 2.8839 2.9372 2.7235
+R15 16.647 10.677 18.389
+S15 35.874 22.454 3.7685
+T15 18.024 31.495 21.231
+U15 26.027 17.635 30.172
+V15 5.7623 9.6302 3.8733
+W15 53.522 58.991 41.376
+X15 23.991 17.693 34.060
+Y15 3.5595 3.8688 2.3978
+Z15 34.055 35.265 28.241
+2A15 29.379 16.826 7.3609
+2B15 9.2107 8.5579 25.691
+2C15 25.707 18.129 3.6532
+2D15 13.875 19.568 19.948
+A16 32.441 19.582 3.7464
+B16 43.738 40.362 16.554
+C16 4.9159 8.3065 7.2559
+D16 37.197 27.832 7.4910
+E16 36.691 35.876 51.695
+F16 38.836 30.036 4.3338
+G16 17.555 13.363 28.888
+H16 75.466 77.836 67.216
+I16 16.954 15.112 7.2992
+J16 47.072 52.200 10.669
+K16 55.962 60.759 50.287
+L16 10.165 9.7715 28.705
+M16 36.859 23.500 3.8297
+N16 29.735 43.076 29.229
+O16 7.3545 6.2503 2.9745
+P16 46.114 46.965 33.568
+Q16 6.2218 6.8107 2.7776
+R16 29.663 17.214 6.8286
+S16 8.0381 10.138 16.410
+T16 31.088 18.734 3.6263
+U16 18.911 32.215 23.899
+V16 26.145 16.883 27.363
+W16 33.705 20.761 3.7986
+X16 14.361 27.487 7.1744
+Y16 29.882 22.982 39.138
+Z16 2.4233 2.4412 1.9648
+2A16 42.519 39.188 21.270
+2B16 5.2349 4.4461 13.823
+2C16 32.492 19.465 7.0806
+2D16 33.454 46.863 22.481
+A17 18.355 31.722 19.048
+B17 4.8626 4.2833 10.526
+C17 39.631 36.092 16.781
+D17 3.8471 5.8319 4.8962
+E17 43.491 44.349 22.904
+F17 35.028 21.444 3.8305
+G17 23.826 20.302 40.464
+H17 44.211 56.679 16.435
+I17 6.5115 6.2807 3.6004
+J17 35.464 48.530 31.500
+K17 31.217 18.833 4.2081
+L17 6.1796 5.0138 3.0160
+M17 21.355 33.511 36.981
+N17 31.382 17.339 13.539
+O17 20.515 20.076 24.934
+P17 32.143 19.447 3.7592
+Q17 60.501 50.532 52.708
+R17 12.657 24.420 5.6873
+S17 3.4355 3.1639 2.5372
+T17 28.192 29.771 51.322
+U17 52.660 42.651 15.019
+V17 69.823 71.393 63.731
+W17 44.995 50.413 5.2421
+X17 37.401 38.967 26.702
+Y17 8.0339 5.5483 9.9052
+Z17 10.382 21.829 11.599
+2A17 34.325 21.131 7.2263
+2B17 9.1863 9.9839 3.1512
+2C17 75.534 73.388 61.922
+2D17 19.258 14.916 29.290
+A18 74.089 78.770 59.424
+B18 42.903 30.204 40.715
+C18 8.7363 10.837 6.0872
+D18 75.509 74.636 56.066
+E18 10.413 9.8011 28.727
+F18 11.836 22.861 5.4226
+G18 26.954 18.177 29.358
+H18 16.220 29.699 13.154
+I18 2.3647 2.3980 1.9090
+J18 77.786 81.283 65.463
+K18 14.363 11.898 6.7644
+L18 60.378 57.128 5.2726
+M18 30.554 20.123 31.743
+N18 24.748 27.645 20.451
+O18 44.929 31.003 12.389
+P18 11.881 10.425 27.990
+Q18 25.737 39.690 14.823
+R18 52.300 42.856 4.6545
+S18 7.2126 14.429 7.1944
+T18 77.679 78.425 65.193
+U18 47.084 32.209 22.319
+V18 6.6683 11.848 10.189
+W18 65.207 70.970 60.729
+X18 6.2806 11.330 4.1095
+Y18 60.571 56.044 16.070
+Z18 15.673 16.045 40.153
+2A18 41.178 25.901 19.845
+2B18 13.693 16.674 24.407
+2C18 74.223 78.952 41.733
+2D18 38.135 24.817 4.1395
+A19 39.239 29.094 15.479
+B19 4.7416 7.0454 3.4644
+C19 49.395 43.657 28.522
+D19 42.332 52.372 5.7052
+E19 24.242 22.424 14.026
+F19 2.4551 2.5226 2.0256
+G19 16.677 25.667 25.825
+H19 13.124 8.8453 3.5763
+I19 28.527 37.076 34.358
+J19 22.891 16.490 6.9749
+K19 22.666 35.279 35.631
+L19 5.4212 4.5484 2.9627
+M19 11.199 21.925 5.4425
+N19 22.708 12.897 3.6335
+O19 12.507 23.738 22.498
+P19 2.3442 2.3896 1.9267
+Q19 30.303 17.749 3.5777
+R19 10.104 9.7374 28.448
+S19 13.901 26.685 6.3873
+T19 2.4391 2.4780 2.0610
+U19 45.972 49.473 57.247
+V19 4.8275 8.3485 3.9886
+W19 63.154 70.855 7.5811
+X19 14.863 14.166 8.5770
+Y19 74.340 78.986 66.286
+Z19 49.996 33.344 36.894
+2A19 10.165 11.287 33.081
+2B19 62.642 69.515 6.2139
+2C19 38.429 24.741 7.3479
+2D19 12.944 12.283 32.608
+
+A1 106.60 73.896 140.50
+B1 101.22 157.76 91.298
+C1 56.474 54.712 116.20
+D1 142.23 143.96 106.67
+E1 161.58 92.303 143.82
+F1 90.405 96.497 94.153
+G1 163.39 98.124 88.178
+H1 63.278 55.370 115.21
+I1 71.385 133.64 49.363
+J1 97.757 75.383 143.28
+K1 194.49 193.52 200.39
+L1 43.729 37.037 36.612
+M1 128.36 143.53 178.51
+N1 136.71 176.12 173.90
+O1 190.25 190.03 173.26
+P1 139.89 69.074 45.054
+Q1 34.433 40.188 37.667
+R1 87.362 153.04 89.833
+S1 124.79 84.048 151.84
+T1 201.42 206.76 79.283
+U1 59.875 104.70 93.370
+V1 205.39 208.60 159.63
+W1 91.572 136.12 167.03
+X1 30.336 29.306 28.957
+Y1 132.60 110.17 107.91
+Z1 32.956 33.215 31.185
+2A1 70.282 129.32 46.946
+2B1 159.00 173.65 202.91
+2C1 121.19 88.150 161.84
+2D1 136.59 101.50 125.83
+A2 75.414 80.525 150.43
+B2 128.64 63.027 42.872
+C2 101.62 116.40 166.26
+D2 129.62 78.772 146.55
+E2 164.20 144.75 82.589
+F2 96.904 110.83 179.21
+G2 157.24 84.071 46.359
+H2 84.439 70.424 140.26
+I2 81.661 147.44 58.864
+J2 35.433 35.856 32.072
+K2 150.66 144.08 140.58
+L2 158.35 93.379 154.74
+M2 100.38 93.492 99.897
+N2 158.93 93.968 95.921
+O2 102.60 137.21 171.09
+P2 74.932 50.703 44.902
+Q2 115.12 165.78 166.70
+R2 157.97 92.663 150.58
+S2 83.913 88.787 161.27
+T2 72.772 133.20 48.154
+U2 155.64 177.45 175.23
+V2 65.311 50.797 44.712
+W2 30.304 29.389 28.630
+X2 98.383 112.57 76.501
+Y2 196.95 176.56 81.174
+Z2 106.87 76.461 64.020
+2A2 149.29 180.57 55.756
+2B2 46.850 72.093 42.887
+2C2 126.21 86.097 104.74
+2D2 68.443 138.05 59.668
+A3 40.703 34.668 43.170
+B3 140.80 177.61 130.47
+C3 71.422 72.467 144.63
+D3 157.83 159.05 109.87
+E3 74.511 78.412 148.91
+F3 172.35 192.98 167.60
+G3 72.505 72.322 146.66
+H3 132.85 167.63 50.020
+I3 99.822 132.27 193.48
+J3 158.78 88.817 87.144
+K3 146.32 156.61 192.38
+L3 30.978 30.641 29.826
+M3 146.27 153.30 150.57
+N3 144.16 70.919 46.534
+O3 85.091 72.947 144.27
+P3 122.91 131.12 67.881
+Q3 140.27 116.77 178.48
+R3 73.020 103.31 46.082
+S3 148.58 74.828 46.145
+T3 92.676 106.61 179.17
+U3 89.067 149.36 56.522
+V3 104.27 103.98 177.68
+W3 122.27 64.970 44.965
+X3 190.80 157.08 167.65
+Y3 55.033 94.759 44.077
+Z3 157.08 85.576 87.558
+2A3 79.250 88.578 159.52
+2B3 108.15 127.71 55.172
+2C3 78.102 75.847 150.05
+2D3 202.83 194.20 199.16
+A4 105.09 86.729 157.14
+B4 99.696 102.26 43.923
+C4 107.26 130.81 190.72
+D4 178.30 141.51 75.719
+E4 86.201 111.97 176.39
+F4 192.41 193.92 143.50
+G4 161.20 95.317 155.94
+H4 74.863 77.945 149.59
+I4 207.61 208.23 184.16
+J4 70.931 101.90 131.71
+K4 147.01 94.545 162.80
+L4 81.586 103.83 104.84
+M4 141.06 69.848 45.247
+N4 90.494 151.07 150.65
+O4 55.294 41.016 63.313
+P4 111.84 140.47 103.22
+Q4 144.45 93.249 162.31
+R4 105.31 104.82 101.31
+S4 79.325 137.68 48.973
+T4 84.189 150.82 120.01
+U4 81.413 52.379 93.432
+V4 76.459 77.531 42.048
+W4 211.28 212.44 213.00
+X4 125.79 102.06 67.469
+Y4 36.736 36.340 46.306
+Z4 83.114 150.29 61.891
+2A4 117.71 90.574 160.37
+2B4 89.463 153.87 72.494
+2C4 42.498 47.832 65.570
+2D4 115.91 156.34 101.73
+A5 100.43 57.576 43.875
+B5 139.57 140.52 191.37
+C5 106.24 157.82 63.346
+D5 120.63 119.68 128.56
+E5 144.32 70.530 44.643
+F5 112.12 164.88 139.23
+G5 103.37 136.87 47.413
+H5 36.251 41.780 35.395
+I5 111.24 162.80 164.26
+J5 143.56 87.562 156.55
+K5 109.54 163.06 164.19
+L5 79.627 52.133 45.354
+M5 92.456 152.33 153.19
+N5 34.714 33.013 32.281
+O5 166.35 175.94 163.99
+P5 89.669 79.549 47.144
+Q5 191.24 182.85 188.48
+R5 51.675 70.899 41.770
+S5 170.53 177.54 173.76
+T5 63.890 93.942 45.687
+U5 30.168 29.299 28.940
+V5 133.08 133.14 122.05
+W5 36.054 32.923 33.276
+X5 61.314 111.77 45.755
+Y5 203.39 209.40 208.06
+Z5 76.353 77.670 109.77
+2A5 193.86 202.18 186.73
+2B5 84.630 73.965 145.61
+2C5 68.392 129.05 45.336
+2D5 210.46 210.49 195.89
+A6 156.79 90.614 148.03
+B6 88.481 111.82 178.46
+C6 167.90 108.82 66.983
+D6 66.578 110.85 54.360
+E6 148.31 87.735 154.80
+F6 93.611 155.13 115.73
+G6 40.190 39.280 58.763
+H6 170.89 152.59 147.19
+I6 46.469 44.545 75.326
+J6 102.48 151.18 180.03
+K6 30.872 30.164 29.516
+L6 83.294 137.00 98.315
+M6 30.722 30.150 29.446
+N6 163.74 151.67 194.83
+O6 199.83 203.65 49.970
+P6 77.512 86.873 159.07
+Q6 200.99 194.31 190.45
+R6 165.39 100.99 154.68
+S6 69.496 98.026 61.986
+T6 167.68 124.93 146.98
+U6 62.706 68.483 60.211
+V6 174.63 108.06 166.14
+W6 138.60 174.02 106.27
+X6 192.12 161.59 197.05
+Y6 71.207 70.503 63.173
+Z6 171.42 121.85 182.26
+2A6 193.77 197.98 207.14
+2B6 117.80 82.965 151.94
+2C6 36.305 39.517 34.462
+2D6 152.48 145.44 148.89
+A7 93.637 153.35 73.710
+B7 83.277 73.755 144.52
+C7 206.85 206.70 197.33
+D7 77.454 73.349 146.72
+E7 70.809 132.64 47.023
+F7 91.049 88.345 163.10
+G7 177.87 190.87 53.018
+H7 75.960 87.720 159.98
+I7 199.48 192.77 181.55
+J7 64.713 68.090 67.610
+K7 193.08 175.48 139.54
+L7 75.430 87.876 159.79
+M7 133.24 173.17 56.742
+N7 148.49 75.098 46.216
+O7 97.134 97.177 86.559
+P7 191.20 160.30 54.685
+Q7 80.068 80.251 125.32
+R7 83.368 147.19 55.358
+S7 37.747 44.719 36.907
+T7 146.52 175.26 205.50
+U7 133.97 82.941 152.98
+V7 63.182 103.22 97.125
+W7 144.22 147.07 76.384
+X7 212.78 213.19 211.89
+Y7 77.896 86.298 158.37
+Z7 71.313 133.52 47.389
+2A7 75.926 78.650 151.98
+2B7 118.08 168.98 98.781
+2C7 207.34 198.34 43.623
+2D7 92.639 108.26 179.66
+A8 69.904 137.36 58.325
+B8 167.09 144.55 49.599
+C8 111.10 78.672 121.83
+D8 74.340 141.34 56.829
+E8 104.13 74.055 141.65
+F8 90.075 154.61 90.911
+G8 36.341 33.896 36.868
+H8 101.65 159.66 134.07
+I8 34.216 33.499 37.712
+J8 174.41 165.56 173.38
+K8 46.252 66.300 42.397
+L8 152.69 184.12 182.69
+M8 30.240 29.863 28.939
+N8 35.593 35.467 34.190
+O8 71.728 71.553 70.937
+P8 115.92 116.10 114.68
+Q8 159.85 160.38 159.13
+R8 196.60 197.21 197.12
+S8 137.57 112.53 140.33
+T8 80.940 142.13 50.952
+U8 99.365 133.93 196.43
+V8 30.957 30.566 29.813
+W8 212.09 210.69 210.55
+X8 90.920 71.799 46.751
+Y8 137.72 177.30 175.40
+Z8 39.524 49.911 38.685
+2A8 130.39 176.13 127.05
+2B8 31.904 31.437 30.690
+2C8 149.77 158.18 196.00
+2D8 30.719 29.824 29.600
+A9 160.64 188.72 135.75
+B9 151.09 113.48 161.82
+C9 56.378 101.12 44.028
+D9 200.86 192.61 183.06
+E9 77.639 89.149 161.20
+F9 183.43 148.52 132.23
+G9 53.868 83.869 77.703
+H9 144.68 93.693 163.06
+I9 80.625 147.05 117.46
+J9 82.612 53.093 45.342
+K9 179.05 178.11 205.03
+L9 68.256 128.21 45.397
+M9 30.122 29.559 28.786
+N9 44.132 44.030 43.113
+O9 77.603 77.496 77.212
+P9 123.38 123.35 123.35
+Q9 167.61 168.12 167.11
+R9 202.61 204.17 205.53
+S9 152.34 81.269 59.657
+T9 36.525 39.233 37.120
+U9 147.79 112.59 105.57
+V9 128.85 175.42 85.449
+W9 202.12 182.11 203.04
+X9 58.841 111.22 46.014
+Y9 150.27 74.574 46.780
+Z9 91.373 72.814 142.15
+2A9 178.42 178.87 165.68
+2B9 110.21 82.066 150.83
+2C9 115.57 141.00 82.227
+2D9 120.44 87.308 156.62
+A10 54.278 98.104 59.100
+B10 141.49 142.92 50.130
+C10 69.545 135.98 93.417
+D10 30.772 30.009 29.471
+E10 140.52 89.479 159.03
+F10 88.149 135.62 165.23
+G10 30.508 30.075 29.389
+H10 75.794 144.13 86.030
+I10 29.881 29.286 28.915
+J10 78.427 139.08 135.09
+K10 127.69 103.24 52.122
+L10 47.518 38.484 37.887
+M10 30.202 29.466 28.978
+N10 50.671 50.438 49.901
+O10 84.087 84.218 84.130
+P10 130.92 131.27 131.19
+Q10 174.24 174.94 173.31
+R10 208.46 209.75 212.17
+S10 61.440 61.759 68.112
+T10 189.59 154.63 195.61
+U10 70.065 139.76 58.155
+V10 34.382 38.877 37.374
+W10 81.185 148.91 88.683
+X10 31.337 30.706 30.647
+Y10 132.10 124.54 122.36
+Z10 128.86 77.259 44.848
+2A10 121.07 144.71 145.24
+2B10 91.404 54.498 76.524
+2C10 122.45 129.19 129.52
+2D10 52.091 43.712 85.349
+A11 95.121 56.945 109.13
+B11 49.247 84.978 41.595
+C11 201.38 188.28 201.57
+D11 165.99 106.71 48.883
+E11 142.45 151.87 140.77
+F11 59.895 43.373 70.686
+G11 185.60 179.80 175.52
+H11 62.810 62.001 39.464
+I11 182.38 181.99 177.01
+J11 44.613 62.579 56.523
+K11 177.26 171.26 154.02
+L11 81.706 58.921 119.57
+M11 30.648 29.769 29.464
+N11 56.534 56.324 55.689
+O11 89.911 89.936 88.980
+P11 140.77 141.41 140.88
+Q11 179.84 180.21 178.58
+R11 212.60 213.84 215.53
+S11 66.493 66.184 65.558
+T11 187.32 160.61 146.99
+U11 59.842 44.929 41.517
+V11 100.71 151.70 177.40
+W11 32.433 32.983 31.555
+X11 103.41 161.56 150.03
+Y11 49.930 46.756 84.028
+Z11 157.24 187.57 185.20
+2A11 69.840 130.51 46.639
+2B11 164.73 190.77 189.92
+2C11 67.660 57.565 50.639
+2D11 146.88 73.255 46.894
+A12 149.18 183.06 84.464
+B12 72.446 71.794 146.17
+C12 111.58 163.80 82.344
+D12 67.115 62.023 67.669
+E12 202.25 206.59 144.16
+F12 142.52 142.52 149.46
+G12 52.218 46.843 96.005
+H12 95.301 157.62 128.66
+I12 58.804 42.199 45.333
+J12 201.67 207.01 112.57
+K12 76.878 56.433 113.86
+L12 110.43 164.87 121.89
+M12 31.073 30.502 29.828
+N12 60.863 60.999 60.221
+O12 97.436 97.414 96.425
+P12 146.96 147.76 147.68
+Q12 186.04 186.49 184.52
+R12 217.03 217.69 217.80
+S12 173.81 166.67 164.48
+T12 61.998 59.133 126.43
+U12 133.08 178.53 107.01
+V12 159.59 92.307 67.569
+W12 92.823 93.091 102.67
+X12 153.31 79.910 48.385
+Y12 76.169 77.765 152.48
+Z12 80.867 145.82 55.209
+2A12 88.726 84.091 155.13
+2B12 201.37 208.14 195.53
+2C12 32.004 31.705 30.813
+2D12 135.53 145.08 187.78
+A13 86.415 69.301 138.07
+B13 104.58 136.42 46.559
+C13 147.82 79.114 100.32
+D13 75.334 85.157 157.26
+E13 178.81 179.96 148.24
+F13 55.482 72.327 100.16
+G13 200.09 199.75 184.43
+H13 76.688 84.710 151.41
+I13 129.73 107.35 52.022
+J13 119.03 160.66 198.42
+K13 56.473 50.032 106.16
+L13 153.18 106.56 46.936
+M13 32.264 31.978 31.289
+N13 66.470 66.520 66.246
+O13 105.28 105.86 104.76
+P13 153.75 154.63 154.12
+Q13 192.03 192.25 191.27
+R13 221.68 221.89 221.96
+S13 104.20 75.856 145.33
+T13 121.87 124.18 72.370
+U13 91.392 55.886 72.021
+V13 193.01 176.53 161.70
+W13 97.047 61.496 44.638
+X13 124.18 171.27 172.48
+Y13 100.95 103.55 45.932
+Z13 98.719 76.722 108.03
+2A13 193.99 204.68 205.71
+2B13 77.619 94.368 167.50
+2C13 91.512 53.191 50.701
+2D13 76.609 104.98 135.45
+A14 129.84 79.131 147.61
+B14 74.731 86.884 158.53
+C14 178.45 194.65 198.02
+D14 122.80 65.789 71.805
+E14 99.529 101.15 66.691
+F14 133.73 68.160 43.803
+G14 130.31 174.28 137.87
+H14 110.49 77.413 145.63
+I14 30.999 29.764 29.587
+J14 120.14 114.13 178.99
+K14 128.29 64.544 74.117
+L14 176.70 157.34 183.40
+M14 59.777 105.00 45.141
+N14 182.00 181.11 190.30
+O14 42.651 40.749 62.042
+P14 151.32 150.31 182.91
+Q14 162.51 94.932 125.82
+R14 99.745 94.301 93.467
+S14 107.25 159.78 58.090
+T14 128.01 72.369 117.84
+U14 107.76 101.18 90.766
+V14 204.14 190.16 48.644
+W14 82.597 65.626 44.970
+X14 166.39 166.20 175.82
+Y14 100.69 152.17 51.384
+Z14 91.650 100.20 90.746
+2A14 143.62 91.243 162.04
+2B14 214.71 215.34 214.31
+2C14 101.32 87.875 161.74
+2D14 105.18 138.75 68.497
+A15 124.84 68.758 114.78
+B15 99.929 150.22 167.53
+C15 121.25 165.78 57.133
+D15 129.49 121.04 130.58
+E15 161.27 95.254 123.97
+F15 148.20 174.03 142.22
+G15 150.41 98.923 167.42
+H15 75.180 91.615 158.04
+I15 196.22 179.25 172.32
+J15 66.558 62.105 60.696
+K15 174.25 177.65 112.40
+L15 116.33 112.29 162.02
+M15 133.68 171.46 73.038
+N15 102.47 146.49 198.15
+O15 64.715 46.574 43.032
+P15 105.91 159.08 164.78
+Q15 34.379 33.754 36.003
+R15 102.62 61.271 119.89
+S15 159.62 86.224 48.021
+T15 95.611 158.57 127.45
+U15 133.03 87.140 157.87
+V15 48.894 77.368 43.484
+W15 182.54 191.20 178.40
+X15 126.00 95.308 166.74
+Y15 38.376 39.986 33.590
+Z15 148.30 148.94 147.37
+2A15 146.55 75.055 68.429
+2B15 71.706 70.645 144.63
+2C15 133.02 80.816 44.452
+2D15 82.777 113.54 117.52
+A16 147.43 75.104 45.417
+B16 162.22 145.05 108.87
+C16 43.273 69.681 61.261
+D16 154.15 106.72 65.606
+E16 149.19 148.83 193.98
+F16 157.80 111.38 47.573
+G16 100.61 79.449 149.13
+H16 206.92 207.61 211.44
+I16 97.895 82.272 66.348
+J16 172.80 178.46 82.595
+K16 183.90 191.17 190.75
+L16 75.048 76.021 151.02
+M16 159.42 88.282 47.938
+N16 133.24 176.09 150.50
+O16 59.749 48.251 40.198
+P16 171.06 168.69 161.58
+Q16 53.260 54.841 37.700
+R16 147.03 76.735 66.424
+S16 63.206 78.809 107.93
+T16 150.22 77.352 47.226
+U16 97.824 159.49 134.64
+V16 133.39 81.567 151.23
+W16 155.32 82.024 48.477
+X16 81.301 147.86 56.013
+Y16 141.53 112.75 178.08
+Z16 31.556 30.196 30.075
+2A16 166.04 149.78 129.15
+2B16 53.939 48.402 100.70
+2C16 152.96 83.435 68.500
+2D16 141.97 181.00 131.63
+A17 93.002 152.57 112.99
+B17 48.562 44.595 81.595
+C17 155.24 137.12 108.13
+D17 37.723 54.820 48.270
+E17 163.04 158.68 133.73
+F17 155.10 81.151 47.477
+G17 119.76 108.26 175.73
+H17 155.83 188.69 108.40
+I17 54.125 49.417 43.252
+J17 146.89 182.65 155.76
+K17 148.71 77.345 50.119
+L17 53.925 41.854 39.291
+M17 105.46 156.83 167.45
+N17 149.16 79.222 103.08
+O17 109.98 107.89 138.78
+P17 151.99 78.765 47.620
+Q17 195.13 169.06 200.08
+R17 73.599 136.55 49.271
+S17 37.757 33.718 34.938
+T17 132.61 142.77 197.68
+U17 181.82 145.93 103.48
+V17 204.10 203.91 210.35
+W17 175.82 179.36 52.229
+X17 155.69 156.50 143.88
+Y17 65.731 44.495 80.654
+Z17 67.930 138.21 88.916
+2A17 156.40 87.866 68.881
+2B17 68.870 68.990 41.254
+2C17 209.60 202.66 207.60
+2D17 108.97 87.062 152.98
+A18 200.70 204.40 197.90
+B18 164.93 117.44 177.68
+C18 61.227 72.827 56.013
+D18 204.51 199.19 195.95
+E18 73.692 73.322 148.06
+F18 68.313 128.24 45.392
+G18 131.14 85.288 152.52
+H18 89.609 153.68 93.128
+I18 30.179 29.676 28.922
+J18 208.65 210.69 209.48
+K18 88.863 70.346 63.498
+L18 197.92 177.16 54.602
+M18 143.55 91.470 162.00
+N18 121.99 131.52 122.44
+O18 172.04 115.00 91.328
+P18 81.187 74.923 148.64
+Q18 117.91 169.48 101.12
+R18 183.93 145.62 52.297
+S18 55.452 105.38 65.438
+T18 211.11 208.92 210.90
+U18 177.41 124.39 134.00
+V18 53.506 90.891 78.889
+W18 197.65 205.13 206.81
+X18 51.396 86.860 43.674
+Y18 193.58 175.18 113.92
+Z18 96.313 103.94 178.60
+2A18 168.53 106.08 128.73
+2B18 85.496 104.15 136.89
+2C18 208.09 210.26 179.31
+2D18 161.94 92.492 50.116
+A19 156.71 112.54 101.12
+B19 42.513 58.501 40.536
+C19 172.17 152.13 143.40
+D19 159.73 183.13 54.703
+E19 119.21 105.48 95.518
+F19 30.235 29.764 29.269
+G19 88.689 134.99 136.69
+H19 86.392 53.901 45.566
+I19 126.88 158.15 160.78
+J19 120.42 79.125 64.241
+K19 108.34 160.80 164.56
+L19 49.327 39.952 38.592
+M19 67.917 128.27 44.976
+N19 127.84 62.080 45.945
+O19 74.380 138.45 130.11
+P19 30.060 29.337 28.817
+Q19 147.97 73.539 46.480
+R19 75.153 76.608 151.15
+S19 78.339 144.41 52.936
+T19 31.312 30.556 30.767
+U19 169.32 177.98 203.35
+V19 44.471 72.376 45.634
+W19 199.02 205.39 55.979
+X19 90.125 81.954 73.039
+Y19 207.33 211.44 212.22
+Z19 182.95 126.85 175.69
+2A19 77.857 90.598 163.13
+2B19 202.16 204.23 49.052
+2C19 162.94 96.440 68.740
+2D19 83.952 84.116 160.97
+
diff --git a/ref/CMP_Digital_Target-3.cie b/ref/CMP_Digital_Target-3.cie
new file mode 100644
index 0000000..6c8ff5d
--- /dev/null
+++ b/ref/CMP_Digital_Target-3.cie
@@ -0,0 +1,591 @@
+CTI3
+
+DESCRIPTOR "Argyll Calibration Target chart information 3"
+ORIGINATOR "Argyll chartread"
+CREATED "Mon Sep 7 08:33:21 2009"
+KEYWORD "DEVICE_CLASS"
+DEVICE_CLASS "OUTPUT"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB_XYZ"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth i1 Pro"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 570
+BEGIN_DATA
+1 "A1" 106.60 73.896 140.50 19.991 14.120 27.886
+2 "B1" 101.22 157.76 91.298 19.926 34.054 14.005
+3 "C1" 56.474 54.712 116.20 6.2319 5.6339 19.078
+4 "D1" 142.23 143.96 106.67 32.785 35.198 16.672
+5 "E1" 161.58 92.303 143.82 38.996 22.658 25.805
+6 "F1" 90.405 96.497 94.153 16.011 17.612 14.561
+7 "G1" 163.39 98.124 88.178 39.496 24.997 12.003
+8 "H1" 63.278 55.370 115.21 7.4905 6.2468 18.358
+9 "I1" 71.385 133.64 49.363 11.987 23.286 6.5928
+10 "J1" 97.757 75.383 143.28 16.591 12.444 27.331
+11 "K1" 194.49 193.52 200.39 63.038 64.179 58.403
+12 "L1" 43.729 37.037 36.612 4.3513 3.8393 2.7750
+13 "M1" 128.36 143.53 178.51 27.386 30.873 42.527
+14 "N1" 136.71 176.12 173.90 31.789 44.281 40.439
+15 "O1" 190.25 190.03 173.26 59.453 61.985 40.335
+16 "P1" 139.89 69.074 45.054 26.783 15.713 3.5833
+17 "Q1" 34.433 40.188 37.667 3.0238 3.6843 3.0876
+18 "R1" 87.362 153.04 89.833 15.462 28.885 12.776
+19 "S1" 124.79 84.048 151.84 23.694 16.421 29.352
+20 "T1" 201.42 206.76 79.283 65.900 73.381 11.377
+21 "U1" 59.875 104.70 93.370 8.3333 15.036 13.749
+22 "V1" 205.39 208.60 159.63 72.416 77.985 33.423
+23 "W1" 91.572 136.12 167.03 16.393 25.254 38.122
+24 "X1" 30.336 29.306 28.957 2.3144 2.3581 1.9303
+25 "Y1" 132.60 110.17 107.91 27.102 23.276 16.813
+26 "Z1" 32.956 33.215 31.185 2.6994 2.8850 2.2332
+27 "2A1" 70.282 129.32 46.946 10.757 20.588 4.8216
+28 "2B1" 159.00 173.65 202.91 40.765 45.919 58.857
+29 "2C1" 121.19 88.150 161.84 22.864 16.381 33.839
+30 "2D1" 136.59 101.50 125.83 28.289 21.404 20.483
+31 "A2" 75.414 80.525 150.43 10.412 10.567 30.978
+32 "B2" 128.64 63.027 42.872 24.139 14.085 3.5857
+33 "C2" 101.62 116.40 166.26 19.473 21.752 38.376
+34 "D2" 129.62 78.772 146.55 26.280 16.991 28.035
+35 "E2" 164.20 144.75 82.589 42.573 39.671 9.6556
+36 "F2" 96.904 110.83 179.21 17.113 18.705 43.690
+37 "G2" 157.24 84.071 46.359 35.850 22.548 3.8554
+38 "H2" 84.439 70.424 140.26 13.037 10.392 26.425
+39 "I2" 81.661 147.44 58.864 14.946 28.262 8.1825
+40 "J2" 35.433 35.856 32.072 3.1780 3.3914 2.3047
+41 "K2" 150.66 144.08 140.58 35.880 35.178 26.683
+42 "L2" 158.35 93.379 154.74 36.434 22.147 28.386
+43 "M2" 100.38 93.492 99.897 17.689 17.022 15.072
+44 "N2" 158.93 93.968 95.921 36.396 23.022 13.623
+45 "O2" 102.60 137.21 171.09 19.884 26.988 39.544
+46 "P2" 74.932 50.703 44.902 10.294 7.4271 3.4839
+47 "Q2" 115.12 165.78 166.70 24.415 37.008 36.288
+48 "R2" 157.97 92.663 150.58 36.078 21.682 26.898
+49 "S2" 83.913 88.787 161.27 12.232 12.247 33.412
+50 "T2" 72.772 133.20 48.154 12.486 23.920 5.4357
+51 "U2" 155.64 177.45 175.23 38.913 47.091 40.794
+52 "V2" 65.311 50.797 44.712 8.3779 6.8387 3.7119
+53 "W2" 30.304 29.389 28.630 2.3401 2.3804 1.9157
+54 "X2" 98.383 112.57 76.501 17.501 20.678 9.7225
+55 "Y2" 196.95 176.56 81.174 60.324 56.490 9.7029
+56 "Z2" 106.87 76.461 64.020 18.340 14.257 6.9452
+57 "2A2" 149.29 180.57 55.756 39.051 50.700 6.0515
+58 "2B2" 46.850 72.093 42.887 5.3134 8.7205 3.7883
+59 "2C2" 126.21 86.097 104.74 24.040 16.842 14.641
+60 "2D2" 68.443 138.05 59.668 10.963 22.720 8.1563
+61 "A3" 40.703 34.668 43.170 3.2215 2.8069 3.1344
+62 "B3" 140.80 177.61 130.47 35.703 49.122 24.276
+63 "C3" 71.422 72.467 144.63 9.6710 9.2674 28.141
+64 "D3" 157.83 159.05 109.87 39.368 42.329 16.693
+65 "E3" 74.511 78.412 148.91 9.8448 9.8037 29.501
+66 "F3" 172.35 192.98 167.60 50.040 60.997 38.371
+67 "G3" 72.505 72.322 146.66 9.8731 9.2375 28.216
+68 "H3" 132.85 167.63 50.020 31.926 43.409 5.2962
+69 "I3" 99.822 132.27 193.48 18.889 24.530 52.235
+70 "J3" 158.78 88.817 87.144 36.271 22.167 11.952
+71 "K3" 146.32 156.61 192.38 34.281 37.060 50.573
+72 "L3" 30.978 30.641 29.826 2.4511 2.5353 2.0398
+73 "M3" 146.27 153.30 150.57 34.120 37.136 30.510
+74 "N3" 144.16 70.919 46.534 28.309 16.461 3.7229
+75 "O3" 85.091 72.947 144.27 12.851 10.508 27.052
+76 "P3" 122.91 131.12 67.881 24.532 27.910 7.4170
+77 "Q3" 140.27 116.77 178.48 29.800 23.719 40.761
+78 "R3" 73.020 103.31 46.082 11.420 17.249 4.2060
+79 "S3" 148.58 74.828 46.145 30.098 17.923 3.6411
+80 "T3" 92.676 106.61 179.17 15.102 16.455 41.548
+81 "U3" 89.067 149.36 56.522 16.816 29.880 6.2892
+82 "V3" 104.27 103.98 177.68 19.054 17.886 40.635
+83 "W3" 122.27 64.970 44.965 21.160 13.146 3.6418
+84 "X3" 190.80 157.08 167.65 56.827 44.647 36.033
+85 "Y3" 55.033 94.759 44.077 7.3224 13.350 4.3645
+86 "Z3" 157.08 85.576 87.558 34.447 20.515 11.595
+87 "2A3" 79.250 88.578 159.52 10.795 11.448 32.464
+88 "2B3" 108.15 127.71 55.172 20.617 25.691 5.5795
+89 "2C3" 78.102 75.847 150.05 11.126 10.174 28.914
+90 "2D3" 202.83 194.20 199.16 68.724 66.102 56.410
+91 "A4" 105.09 86.729 157.14 19.671 15.554 33.919
+92 "B4" 99.696 102.26 43.923 17.501 19.753 3.8498
+93 "C4" 107.26 130.81 190.72 21.509 25.734 51.674
+94 "D4" 178.30 141.51 75.719 51.958 42.451 9.1213
+95 "E4" 86.201 111.97 176.39 14.112 17.806 42.697
+96 "F4" 192.41 193.92 143.50 61.487 65.884 27.427
+97 "G4" 161.20 95.317 155.94 38.420 23.239 29.457
+98 "H4" 74.863 77.945 149.59 9.8759 9.7311 29.126
+99 "I4" 207.61 208.23 184.16 75.793 79.718 46.695
+100 "J4" 70.931 101.90 131.71 10.595 15.480 24.653
+101 "K4" 147.01 94.545 162.80 32.187 21.331 32.814
+102 "L4" 81.586 103.83 104.84 13.777 17.753 16.663
+103 "M4" 141.06 69.848 45.247 27.339 16.027 3.5603
+104 "N4" 90.494 151.07 150.65 16.922 28.995 29.336
+105 "O4" 55.294 41.016 63.313 6.3066 4.7610 6.9921
+106 "P4" 111.84 140.47 103.22 22.390 29.210 15.592
+107 "Q4" 144.45 93.249 162.31 30.657 20.369 32.268
+108 "R4" 105.31 104.82 101.31 19.152 19.807 15.592
+109 "S4" 79.325 137.68 48.973 13.948 25.671 5.2122
+110 "T4" 84.189 150.82 120.01 14.991 27.898 19.745
+111 "U4" 81.413 52.379 93.432 11.486 7.6381 12.484
+112 "V4" 76.459 77.531 42.048 10.749 11.899 3.2945
+113 "W4" 211.28 212.44 213.00 77.699 80.782 67.995
+114 "X4" 125.79 102.06 67.469 24.430 21.610 7.1800
+115 "Y4" 36.736 36.340 46.306 3.2104 3.1999 4.2513
+116 "Z4" 83.114 150.29 61.891 14.450 27.763 8.5197
+117 "2A4" 117.71 90.574 160.37 21.679 16.235 32.574
+118 "2B4" 89.463 153.87 72.494 15.737 29.267 10.078
+119 "2C4" 42.498 47.832 65.570 3.9226 4.4418 7.5674
+120 "2D4" 115.91 156.34 101.73 24.022 34.375 15.022
+121 "A5" 100.43 57.576 43.875 16.920 10.945 3.6233
+122 "B5" 139.57 140.52 191.37 32.876 32.373 51.547
+123 "C5" 106.24 157.82 63.346 23.454 37.144 7.5202
+124 "D5" 120.63 119.68 128.56 24.762 25.266 23.702
+125 "E5" 144.32 70.530 44.643 29.192 16.958 3.5359
+126 "F5" 112.12 164.88 139.23 23.640 37.186 26.447
+127 "G5" 103.37 136.87 47.413 20.387 28.842 4.7028
+128 "H5" 36.251 41.780 35.395 3.3636 4.0809 2.6833
+129 "I5" 111.24 162.80 164.26 23.272 35.820 35.198
+130 "J5" 143.56 87.562 156.55 30.642 19.573 30.103
+131 "K5" 109.54 163.06 164.19 22.753 35.416 35.064
+132 "L5" 79.627 52.133 45.354 11.209 7.8786 3.5144
+133 "M5" 92.456 152.33 153.19 17.513 29.721 30.234
+134 "N5" 34.714 33.013 32.281 2.9935 2.9559 2.2837
+135 "O5" 166.35 175.94 163.99 44.139 49.035 35.423
+136 "P5" 89.669 79.549 47.144 14.200 13.959 3.6761
+137 "Q5" 191.24 182.85 188.48 59.021 56.831 48.262
+138 "R5" 51.675 70.899 41.770 6.3401 9.2262 3.4989
+139 "S5" 170.53 177.54 173.76 45.700 49.818 40.124
+140 "T5" 63.890 93.942 45.687 9.3142 14.437 4.0636
+141 "U5" 30.168 29.299 28.940 2.3535 2.3975 1.9290
+142 "V5" 133.08 133.14 122.05 27.766 28.925 20.091
+143 "W5" 36.054 32.923 33.276 3.0887 2.9300 2.3596
+144 "X5" 61.314 111.77 45.755 8.7239 16.803 5.0276
+145 "Y5" 203.39 209.40 208.06 70.161 75.882 63.247
+146 "Z5" 76.353 77.670 109.77 11.191 11.244 16.654
+147 "2A5" 193.86 202.18 186.73 62.394 68.771 47.096
+148 "2B5" 84.630 73.965 145.61 12.640 10.459 27.333
+149 "2C5" 68.392 129.05 45.336 11.160 21.761 5.5099
+150 "2D5" 210.46 210.49 195.89 77.413 80.592 53.936
+151 "A6" 156.79 90.614 148.03 37.703 22.453 27.499
+152 "B6" 88.481 111.82 178.46 14.943 18.301 44.058
+153 "C6" 167.90 108.82 66.983 44.282 30.956 7.9185
+154 "D6" 66.578 110.85 54.360 10.440 18.144 6.5076
+155 "E6" 148.31 87.735 154.80 32.892 20.486 29.274
+156 "F6" 93.611 155.13 115.73 17.819 31.263 19.184
+157 "G6" 40.190 39.280 58.763 3.7468 3.6058 6.3752
+158 "H6" 170.89 152.59 147.19 45.907 41.132 28.818
+159 "I6" 46.469 44.545 75.326 4.4472 4.1158 9.1204
+160 "J6" 102.48 151.18 180.03 20.388 31.549 44.358
+161 "K6" 30.872 30.164 29.516 2.3970 2.4515 1.9961
+162 "L6" 83.294 137.00 98.315 14.323 24.343 14.536
+163 "M6" 30.722 30.150 29.446 2.3623 2.4293 1.9541
+164 "N6" 163.74 151.67 194.83 41.190 36.767 50.714
+165 "O6" 199.83 203.65 49.970 62.357 69.847 6.3069
+166 "P6" 77.512 86.873 159.07 10.124 10.811 31.915
+167 "Q6" 200.99 194.31 190.45 67.127 65.762 49.352
+168 "R6" 165.39 100.99 154.68 39.128 23.959 27.822
+169 "S6" 69.496 98.026 61.986 10.413 15.222 6.7952
+170 "T6" 167.68 124.93 146.98 41.195 30.074 26.292
+171 "U6" 62.706 68.483 60.211 8.4099 9.5591 6.5834
+172 "V6" 174.63 108.06 166.14 43.942 26.976 32.439
+173 "W6" 138.60 174.02 106.27 33.397 44.263 15.513
+174 "X6" 192.12 161.59 197.05 56.629 45.672 50.137
+175 "Y6" 71.207 70.503 63.173 10.198 10.583 6.9283
+176 "Z6" 171.42 121.85 182.26 42.782 29.822 40.386
+177 "2A6" 193.77 197.98 207.14 61.567 65.013 61.274
+178 "2B6" 117.80 82.965 151.94 21.335 15.115 28.916
+179 "2C6" 36.305 39.517 34.462 3.2203 3.7212 2.6005
+180 "2D6" 152.48 145.44 148.89 35.799 34.854 29.422
+181 "A7" 93.637 153.35 73.710 19.123 33.078 10.667
+182 "B7" 83.277 73.755 144.52 12.915 10.831 28.225
+183 "C7" 206.85 206.70 197.33 77.518 80.587 57.622
+184 "D7" 77.454 73.349 146.72 11.348 10.154 28.703
+185 "E7" 70.809 132.64 47.023 12.442 24.254 5.6475
+186 "F7" 91.049 88.345 163.10 15.345 13.969 34.910
+187 "G7" 177.87 190.87 53.018 52.703 61.988 5.9513
+188 "H7" 75.960 87.720 159.98 9.9056 10.888 32.881
+189 "I7" 199.48 192.77 181.55 67.471 66.483 44.705
+190 "J7" 64.713 68.090 67.610 8.8426 9.6268 8.1730
+191 "K7" 193.08 175.48 139.54 61.925 56.855 24.968
+192 "L7" 75.430 87.876 159.79 9.6349 10.726 32.427
+193 "M7" 133.24 173.17 56.742 32.435 45.157 6.1480
+194 "N7" 148.49 75.098 46.216 30.427 18.146 3.6270
+195 "O7" 97.134 97.177 86.559 16.928 17.695 11.911
+196 "P7" 191.20 160.30 54.685 56.094 48.894 4.9467
+197 "Q7" 80.068 80.251 125.32 11.934 11.778 20.573
+198 "R7" 83.368 147.19 55.358 15.285 28.434 6.3346
+199 "S7" 37.747 44.719 36.907 3.5054 4.3615 2.7830
+200 "T7" 146.52 175.26 205.50 35.099 44.589 58.771
+201 "U7" 133.97 82.941 152.98 26.155 17.005 28.079
+202 "V7" 63.182 103.22 97.125 8.9086 14.924 14.071
+203 "W7" 144.22 147.07 76.384 30.611 33.536 8.6858
+204 "X7" 212.78 213.19 211.89 79.113 81.784 66.503
+205 "Y7" 77.896 86.298 158.37 10.240 10.764 31.229
+206 "Z7" 71.313 133.52 47.389 11.976 23.218 5.4228
+207 "2A7" 75.926 78.650 151.98 9.9976 9.7574 28.929
+208 "2B7" 118.08 168.98 98.781 25.572 39.297 14.262
+209 "2C7" 207.34 198.34 43.623 66.257 69.908 5.8960
+210 "2D7" 92.639 108.26 179.66 14.893 16.603 41.626
+211 "A8" 69.904 137.36 58.325 12.100 24.359 8.4071
+212 "B8" 167.09 144.55 49.599 42.436 39.900 4.7260
+213 "C8" 111.10 78.672 121.83 20.574 15.216 20.136
+214 "D8" 74.340 141.34 56.829 12.701 25.255 8.1803
+215 "E8" 104.13 74.055 141.65 18.324 13.039 26.409
+216 "F8" 90.075 154.61 90.911 16.724 30.035 13.212
+217 "G8" 36.341 33.896 36.868 3.3200 3.1831 3.0291
+218 "H8" 101.65 159.66 134.07 20.304 33.570 24.443
+219 "I8" 34.216 33.499 37.712 2.9169 2.9009 3.0168
+220 "J8" 174.41 165.56 173.38 48.038 46.099 39.891
+221 "K8" 46.252 66.300 42.397 5.2241 8.0427 3.5985
+222 "L8" 152.69 184.12 182.69 38.619 50.368 44.407
+223 "M8" 30.240 29.863 28.939 2.3428 2.3959 1.9273
+224 "N8" 35.593 35.467 34.190 3.1956 3.3116 2.6415
+225 "O8" 71.728 71.553 70.937 10.494 10.847 8.8081
+226 "P8" 115.92 116.10 114.68 22.233 23.005 18.548
+227 "Q8" 159.85 160.38 159.13 39.317 40.778 33.056
+228 "R8" 196.60 197.21 197.12 63.147 65.480 53.862
+229 "S8" 137.57 112.53 140.33 28.252 23.514 24.400
+230 "T8" 80.940 142.13 50.952 14.520 26.909 5.4756
+231 "U8" 99.365 133.93 196.43 18.057 24.054 51.817
+232 "V8" 30.957 30.566 29.813 2.3402 2.3911 1.9209
+233 "W8" 212.09 210.69 210.55 77.838 79.255 64.883
+234 "X8" 90.920 71.799 46.751 14.232 12.342 3.5677
+235 "Y8" 137.72 177.30 175.40 31.451 43.594 39.472
+236 "Z8" 39.524 49.911 38.685 3.8429 5.0881 3.0661
+237 "2A8" 130.39 176.13 127.05 27.844 41.491 21.140
+238 "2B8" 31.904 31.437 30.690 2.4921 2.5648 2.0613
+239 "2C8" 149.77 158.18 196.00 34.635 36.777 50.964
+240 "2D8" 30.719 29.824 29.600 2.3436 2.3905 1.9440
+241 "A9" 160.64 188.72 135.75 46.811 59.109 25.406
+242 "B9" 151.09 113.48 161.82 35.695 26.905 33.928
+243 "C9" 56.378 101.12 44.028 8.0578 15.313 4.8058
+244 "D9" 200.86 192.61 183.06 70.562 68.540 46.575
+245 "E9" 77.639 89.149 161.20 10.633 11.656 33.787
+246 "F9" 183.43 148.52 132.23 54.113 43.360 23.933
+247 "G9" 53.868 83.869 77.703 7.1200 11.358 10.328
+248 "H9" 144.68 93.693 163.06 31.237 20.786 32.756
+249 "I9" 80.625 147.05 117.46 14.469 27.174 19.553
+250 "J9" 82.612 53.093 45.342 11.813 8.1727 3.4750
+251 "K9" 179.05 178.11 205.03 51.613 51.265 59.093
+252 "L9" 68.256 128.21 45.397 11.232 21.889 5.3482
+253 "M9" 30.122 29.559 28.786 2.3389 2.3932 1.9205
+254 "N9" 44.132 44.030 43.113 4.6543 4.8363 3.9004
+255 "O9" 77.603 77.496 77.212 11.973 12.444 10.082
+256 "P9" 123.38 123.35 123.35 24.548 25.410 20.720
+257 "Q9" 167.61 168.12 167.11 43.270 44.842 36.215
+258 "R9" 202.61 204.17 205.53 68.113 71.034 59.864
+259 "S9" 152.34 81.269 59.657 31.468 18.903 5.4734
+260 "T9" 36.525 39.233 37.120 3.2297 3.6435 2.9170
+261 "U9" 147.79 112.59 105.57 31.779 25.042 15.321
+262 "V9" 128.85 175.42 85.449 30.098 43.673 10.856
+263 "W9" 202.12 182.11 203.04 65.360 57.273 55.175
+264 "X9" 58.841 111.22 46.014 7.8261 15.682 5.0934
+265 "Y9" 150.27 74.574 46.780 30.151 17.603 3.5424
+266 "Z9" 91.373 72.814 142.15 14.169 10.872 25.545
+267 "2A9" 178.42 178.87 165.68 49.740 51.961 35.295
+268 "2B9" 110.21 82.066 150.83 19.293 14.167 28.533
+269 "2C9" 115.57 141.00 82.227 23.305 29.469 10.465
+270 "2D9" 120.44 87.308 156.62 22.420 16.254 30.792
+271 "A10" 54.278 98.104 59.100 7.4766 14.316 6.7672
+272 "B10" 141.49 142.92 50.130 30.693 34.185 4.8132
+273 "C10" 69.545 135.98 93.417 11.568 23.235 13.773
+274 "D10" 30.772 30.009 29.471 2.4307 2.4999 2.0171
+275 "E10" 140.52 89.479 159.03 30.140 19.949 31.751
+276 "F10" 88.149 135.62 165.23 15.810 25.353 37.521
+277 "G10" 30.508 30.075 29.389 2.4272 2.4936 1.9887
+278 "H10" 75.794 144.13 86.030 12.549 25.096 11.562
+279 "I10" 29.881 29.286 28.915 2.3402 2.3788 1.9223
+280 "J10" 78.427 139.08 135.09 13.387 24.235 23.958
+281 "K10" 127.69 103.24 52.122 25.478 22.853 4.3681
+282 "L10" 47.518 38.484 37.887 5.0366 4.2550 2.8902
+283 "M10" 30.202 29.466 28.978 2.3374 2.3915 1.9194
+284 "N10" 50.671 50.438 49.901 5.8942 6.1054 4.9143
+285 "O10" 84.087 84.218 84.130 13.462 14.013 11.428
+286 "P10" 130.92 131.27 131.19 27.055 28.014 23.007
+287 "Q10" 174.24 174.94 173.31 47.406 49.169 39.386
+288 "R10" 208.46 209.75 212.17 73.974 77.043 65.729
+289 "S10" 61.440 61.759 68.112 7.8358 8.0794 7.9176
+290 "T10" 189.59 154.63 195.61 54.395 42.563 48.165
+291 "U10" 70.065 139.76 58.155 11.113 22.841 7.7084
+292 "V10" 34.382 38.877 37.374 2.9394 3.4387 2.9247
+293 "W10" 81.185 148.91 88.683 13.284 25.973 11.867
+294 "X10" 31.337 30.706 30.647 2.4768 2.5120 2.1182
+295 "Y10" 132.10 124.54 122.36 27.102 26.481 19.829
+296 "Z10" 128.86 77.259 44.848 23.978 16.698 3.6586
+297 "2A10" 121.07 144.71 145.24 24.659 30.178 27.108
+298 "2B10" 91.404 54.498 76.524 13.618 8.1445 8.4106
+299 "2C10" 122.45 129.19 129.52 24.412 26.496 22.533
+300 "2D10" 52.091 43.712 85.349 5.2897 4.2252 10.803
+301 "A11" 95.121 56.945 109.13 15.662 9.9371 16.757
+302 "B11" 49.247 84.978 41.595 6.3528 11.756 4.1276
+303 "C11" 201.38 188.28 201.57 70.247 65.054 58.834
+304 "D11" 165.99 106.71 48.883 42.904 30.283 4.3741
+305 "E11" 142.45 151.87 140.77 33.675 37.292 27.259
+306 "F11" 59.895 43.373 70.686 7.3260 5.3398 8.4321
+307 "G11" 185.60 179.80 175.52 56.748 56.026 41.441
+308 "H11" 62.810 62.001 39.464 8.1585 8.7147 3.0001
+309 "I11" 182.38 181.99 177.01 54.512 56.195 42.466
+310 "J11" 44.613 62.579 56.523 4.9736 7.2275 6.1574
+311 "K11" 177.26 171.26 154.02 50.413 50.352 29.675
+312 "L11" 81.706 58.921 119.57 11.783 8.3671 18.993
+313 "M11" 30.648 29.769 29.464 2.4004 2.4632 1.9865
+314 "N11" 56.534 56.324 55.689 7.0502 7.2979 5.9348
+315 "O11" 89.911 89.936 88.980 15.157 15.663 12.643
+316 "P11" 140.77 141.41 140.88 30.809 31.935 26.037
+317 "Q11" 179.84 180.21 178.58 51.029 52.827 42.179
+318 "R11" 212.60 213.84 215.53 78.892 82.077 69.152
+319 "S11" 66.493 66.184 65.558 9.0391 9.3614 7.5795
+320 "T11" 187.32 160.61 146.99 54.688 46.067 27.270
+321 "U11" 59.842 44.929 41.517 7.0672 5.5203 3.1542
+322 "V11" 100.71 151.70 177.40 19.018 30.251 40.808
+323 "W11" 32.433 32.983 31.555 2.6438 2.7813 2.1741
+324 "X11" 103.41 161.56 150.03 20.294 33.254 28.954
+325 "Y11" 49.930 46.756 84.028 4.7917 4.3367 10.461
+326 "Z11" 157.24 187.57 185.20 39.678 51.335 44.730
+327 "2A11" 69.840 130.51 46.639 11.397 22.075 5.4606
+328 "2B11" 164.73 190.77 189.92 43.396 54.386 47.692
+329 "2C11" 67.660 57.565 50.639 9.0264 8.0855 4.5632
+330 "2D11" 146.88 73.255 46.894 29.263 17.239 3.6542
+331 "A12" 149.18 183.06 84.464 42.435 55.238 11.960
+332 "B12" 72.446 71.794 146.17 10.244 9.5241 28.550
+333 "C12" 111.58 163.80 82.344 25.557 39.490 11.397
+334 "D12" 67.115 62.023 67.669 9.5983 9.1448 8.3283
+335 "E12" 202.25 206.59 144.16 71.285 77.444 27.463
+336 "F12" 142.52 142.52 149.46 32.592 33.399 30.058
+337 "G12" 52.218 46.843 96.005 5.1430 4.3541 13.182
+338 "H12" 95.301 157.62 128.66 18.517 32.087 22.562
+339 "I12" 58.804 42.199 45.333 6.9977 5.1440 3.8014
+340 "J12" 201.67 207.01 112.57 69.246 76.042 17.844
+341 "K12" 76.878 56.433 113.86 10.642 7.6407 17.593
+342 "L12" 110.43 164.87 121.89 21.927 35.477 19.681
+343 "M12" 31.073 30.502 29.828 2.4287 2.4921 1.9949
+344 "N12" 60.863 60.999 60.221 7.9937 8.3172 6.7360
+345 "O12" 97.436 97.414 96.425 17.120 17.761 14.285
+346 "P12" 146.96 147.76 147.68 33.242 34.486 28.221
+347 "Q12" 186.04 186.49 184.52 55.136 57.000 45.303
+348 "R12" 217.03 217.69 217.80 84.047 87.070 71.496
+349 "S12" 173.81 166.67 164.48 46.799 45.618 34.284
+350 "T12" 61.998 59.133 126.43 6.6921 6.0185 19.773
+351 "U12" 133.08 178.53 107.01 31.583 45.365 15.646
+352 "V12" 159.59 92.307 67.569 35.975 22.808 7.0470
+353 "W12" 92.823 93.091 102.67 15.632 16.004 15.333
+354 "X12" 153.31 79.910 48.385 32.188 19.569 3.7849
+355 "Y12" 76.169 77.765 152.48 9.9981 9.6287 28.171
+356 "Z12" 80.867 145.82 55.209 14.429 27.348 6.4901
+357 "2A12" 88.726 84.091 155.13 13.822 12.446 29.936
+358 "2B12" 201.37 208.14 195.53 68.261 74.431 52.067
+359 "2C12" 32.004 31.705 30.813 2.4685 2.5621 2.0287
+360 "2D12" 135.53 145.08 187.78 28.798 30.974 45.549
+361 "A13" 86.415 69.301 138.07 14.129 10.884 26.286
+362 "B13" 104.58 136.42 46.559 21.280 29.662 4.6515
+363 "C13" 147.82 79.114 100.32 32.064 17.966 13.604
+364 "D13" 75.334 85.157 157.26 9.9611 10.733 32.277
+365 "E13" 178.81 179.96 148.24 51.845 54.927 28.181
+366 "F13" 55.482 72.327 100.16 6.3441 8.5421 15.068
+367 "G13" 200.09 199.75 184.43 68.699 71.452 46.387
+368 "H13" 76.688 84.710 151.41 10.374 10.902 29.169
+369 "I13" 129.73 107.35 52.022 26.203 23.997 4.3858
+370 "J13" 119.03 160.66 198.42 25.753 36.554 54.373
+371 "K13" 56.473 50.032 106.16 5.9068 4.9157 15.287
+372 "L13" 153.18 106.56 46.936 35.348 27.270 4.1933
+373 "M13" 32.264 31.978 31.289 2.6154 2.7053 2.1626
+374 "N13" 66.470 66.520 66.246 9.3637 9.6843 7.8391
+375 "O13" 105.28 105.86 104.76 19.359 20.106 16.147
+376 "P13" 153.75 154.63 154.12 36.624 37.957 30.671
+377 "Q13" 192.03 192.25 191.27 59.859 61.861 49.702
+378 "R13" 221.68 221.89 221.96 89.957 93.025 75.604
+379 "S13" 104.20 75.856 145.33 17.613 12.665 26.369
+380 "T13" 121.87 124.18 72.370 22.969 25.114 7.7873
+381 "U13" 91.392 55.886 72.021 13.623 8.3610 7.6135
+382 "V13" 193.01 176.53 161.70 59.661 54.433 33.140
+383 "W13" 97.047 61.496 44.638 15.045 10.609 3.4373
+384 "X13" 124.18 171.27 172.48 26.676 39.190 37.659
+385 "Y13" 100.95 103.55 45.932 16.770 18.831 3.7976
+386 "Z13" 98.719 76.722 108.03 16.243 13.004 15.620
+387 "2A13" 193.99 204.68 205.71 62.079 69.145 59.254
+388 "2B13" 77.619 94.368 167.50 9.8300 11.508 34.315
+389 "2C13" 91.512 53.191 50.701 13.378 8.4024 4.1065
+390 "2D13" 76.609 104.98 135.45 11.706 16.228 24.708
+391 "A14" 129.84 79.131 147.61 27.260 17.709 28.446
+392 "B14" 74.731 86.884 158.53 10.007 11.116 33.309
+393 "C14" 178.45 194.65 198.02 55.170 63.826 56.969
+394 "D14" 122.80 65.789 71.805 22.474 12.791 7.8220
+395 "E14" 99.529 101.15 66.691 17.833 19.340 7.6068
+396 "F14" 133.73 68.160 43.803 25.508 15.387 3.5019
+397 "G14" 130.31 174.28 137.87 28.674 42.244 25.294
+398 "H14" 110.49 77.413 145.63 20.013 14.167 27.201
+399 "I14" 30.999 29.764 29.587 2.4079 2.4331 1.9867
+400 "J14" 120.14 114.13 178.99 23.527 21.066 41.374
+401 "K14" 128.29 64.544 74.117 23.203 12.509 8.0121
+402 "L14" 176.70 157.34 183.40 48.486 42.511 43.112
+403 "M14" 59.777 105.00 45.141 8.6031 15.926 4.6200
+404 "N14" 182.00 181.11 190.30 53.107 53.884 48.977
+405 "O14" 42.651 40.749 62.042 3.9836 3.7404 6.5852
+406 "P14" 151.32 150.31 182.91 35.517 35.068 43.001
+407 "Q14" 162.51 94.932 125.82 37.782 22.314 19.042
+408 "R14" 99.745 94.301 93.467 17.467 17.105 13.104
+409 "S14" 107.25 159.78 58.090 22.370 35.508 5.9931
+410 "T14" 128.01 72.369 117.84 23.886 13.985 16.868
+411 "U14" 107.76 101.18 90.766 19.591 19.252 12.172
+412 "V14" 204.14 190.16 48.644 63.345 63.812 5.6645
+413 "W14" 82.597 65.626 44.970 12.028 10.481 3.3856
+414 "X14" 166.39 166.20 175.82 42.635 43.420 39.912
+415 "Y14" 100.69 152.17 51.384 19.856 32.192 5.1431
+416 "Z14" 91.650 100.20 90.746 15.570 17.641 12.711
+417 "2A14" 143.62 91.243 162.04 29.733 19.495 31.105
+418 "2B14" 214.71 215.34 214.31 81.209 84.285 67.959
+419 "2C14" 101.32 87.875 161.74 16.972 13.897 32.504
+420 "2D14" 105.18 138.75 68.497 20.262 27.906 7.7177
+421 "A15" 124.84 68.758 114.78 24.922 14.319 17.652
+422 "B15" 99.929 150.22 167.53 20.394 32.266 39.177
+423 "C15" 121.25 165.78 57.133 28.847 42.042 6.3345
+424 "D15" 129.49 121.04 130.58 27.579 26.553 23.681
+425 "E15" 161.27 95.254 123.97 38.874 23.290 19.357
+426 "F15" 148.20 174.03 142.22 36.703 46.352 27.027
+427 "G15" 150.41 98.923 167.42 34.061 22.803 34.531
+428 "H15" 75.180 91.615 158.04 10.113 11.921 31.879
+429 "I15" 196.22 179.25 172.32 64.423 58.008 39.281
+430 "J15" 66.558 62.105 60.696 9.4542 9.1717 6.7120
+431 "K15" 174.25 177.65 112.40 48.073 52.062 16.154
+432 "L15" 116.33 112.29 162.02 22.225 20.657 33.169
+433 "M15" 133.68 171.46 73.038 32.410 43.840 8.6168
+434 "N15" 102.47 146.49 198.15 19.932 29.141 53.896
+435 "O15" 64.715 46.574 43.032 8.2354 6.1612 3.2448
+436 "P15" 105.91 159.08 164.78 21.186 33.689 34.860
+437 "Q15" 34.379 33.754 36.003 2.8839 2.9372 2.7235
+438 "R15" 102.62 61.271 119.89 16.647 10.677 18.389
+439 "S15" 159.62 86.224 48.021 35.874 22.454 3.7685
+440 "T15" 95.611 158.57 127.45 18.024 31.495 21.231
+441 "U15" 133.03 87.140 157.87 26.027 17.635 30.172
+442 "V15" 48.894 77.368 43.484 5.7623 9.6302 3.8733
+443 "W15" 182.54 191.20 178.40 53.522 58.991 41.376
+444 "X15" 126.00 95.308 166.74 23.991 17.693 34.060
+445 "Y15" 38.376 39.986 33.590 3.5595 3.8688 2.3978
+446 "Z15" 148.30 148.94 147.37 34.055 35.265 28.241
+447 "2A15" 146.55 75.055 68.429 29.379 16.826 7.3609
+448 "2B15" 71.706 70.645 144.63 9.2107 8.5579 25.691
+449 "2C15" 133.02 80.816 44.452 25.707 18.129 3.6532
+450 "2D15" 82.777 113.54 117.52 13.875 19.568 19.948
+451 "A16" 147.43 75.104 45.417 32.441 19.582 3.7464
+452 "B16" 162.22 145.05 108.87 43.738 40.362 16.554
+453 "C16" 43.273 69.681 61.261 4.9159 8.3065 7.2559
+454 "D16" 154.15 106.72 65.606 37.197 27.832 7.4910
+455 "E16" 149.19 148.83 193.98 36.691 35.876 51.695
+456 "F16" 157.80 111.38 47.573 38.836 30.036 4.3338
+457 "G16" 100.61 79.449 149.13 17.555 13.363 28.888
+458 "H16" 206.92 207.61 211.44 75.466 77.836 67.216
+459 "I16" 97.895 82.272 66.348 16.954 15.112 7.2992
+460 "J16" 172.80 178.46 82.595 47.072 52.200 10.669
+461 "K16" 183.90 191.17 190.75 55.962 60.759 50.287
+462 "L16" 75.048 76.021 151.02 10.165 9.7715 28.705
+463 "M16" 159.42 88.282 47.938 36.859 23.500 3.8297
+464 "N16" 133.24 176.09 150.50 29.735 43.076 29.229
+465 "O16" 59.749 48.251 40.198 7.3545 6.2503 2.9745
+466 "P16" 171.06 168.69 161.58 46.114 46.965 33.568
+467 "Q16" 53.260 54.841 37.700 6.2218 6.8107 2.7776
+468 "R16" 147.03 76.735 66.424 29.663 17.214 6.8286
+469 "S16" 63.206 78.809 107.93 8.0381 10.138 16.410
+470 "T16" 150.22 77.352 47.226 31.088 18.734 3.6263
+471 "U16" 97.824 159.49 134.64 18.911 32.215 23.899
+472 "V16" 133.39 81.567 151.23 26.145 16.883 27.363
+473 "W16" 155.32 82.024 48.477 33.705 20.761 3.7986
+474 "X16" 81.301 147.86 56.013 14.361 27.487 7.1744
+475 "Y16" 141.53 112.75 178.08 29.882 22.982 39.138
+476 "Z16" 31.556 30.196 30.075 2.4233 2.4412 1.9648
+477 "2A16" 166.04 149.78 129.15 42.519 39.188 21.270
+478 "2B16" 53.939 48.402 100.70 5.2349 4.4461 13.823
+479 "2C16" 152.96 83.435 68.500 32.492 19.465 7.0806
+480 "2D16" 141.97 181.00 131.63 33.454 46.863 22.481
+481 "A17" 93.002 152.57 112.99 18.355 31.722 19.048
+482 "B17" 48.562 44.595 81.595 4.8626 4.2833 10.526
+483 "C17" 155.24 137.12 108.13 39.631 36.092 16.781
+484 "D17" 37.723 54.820 48.270 3.8471 5.8319 4.8962
+485 "E17" 163.04 158.68 133.73 43.491 44.349 22.904
+486 "F17" 155.10 81.151 47.477 35.028 21.444 3.8305
+487 "G17" 119.76 108.26 175.73 23.826 20.302 40.464
+488 "H17" 155.83 188.69 108.40 44.211 56.679 16.435
+489 "I17" 54.125 49.417 43.252 6.5115 6.2807 3.6004
+490 "J17" 146.89 182.65 155.76 35.464 48.530 31.500
+491 "K17" 148.71 77.345 50.119 31.217 18.833 4.2081
+492 "L17" 53.925 41.854 39.291 6.1796 5.0138 3.0160
+493 "M17" 105.46 156.83 167.45 21.355 33.511 36.981
+494 "N17" 149.16 79.222 103.08 31.382 17.339 13.539
+495 "O17" 109.98 107.89 138.78 20.515 20.076 24.934
+496 "P17" 151.99 78.765 47.620 32.143 19.447 3.7592
+497 "Q17" 195.13 169.06 200.08 60.501 50.532 52.708
+498 "R17" 73.599 136.55 49.271 12.657 24.420 5.6873
+499 "S17" 37.757 33.718 34.938 3.4355 3.1639 2.5372
+500 "T17" 132.61 142.77 197.68 28.192 29.771 51.322
+501 "U17" 181.82 145.93 103.48 52.660 42.651 15.019
+502 "V17" 204.10 203.91 210.35 69.823 71.393 63.731
+503 "W17" 175.82 179.36 52.229 44.995 50.413 5.2421
+504 "X17" 155.69 156.50 143.88 37.401 38.967 26.702
+505 "Y17" 65.731 44.495 80.654 8.0339 5.5483 9.9052
+506 "Z17" 67.930 138.21 88.916 10.382 21.829 11.599
+507 "2A17" 156.40 87.866 68.881 34.325 21.131 7.2263
+508 "2B17" 68.870 68.990 41.254 9.1863 9.9839 3.1512
+509 "2C17" 209.60 202.66 207.60 75.534 73.388 61.922
+510 "2D17" 108.97 87.062 152.98 19.258 14.916 29.290
+511 "A18" 200.70 204.40 197.90 74.089 78.770 59.424
+512 "B18" 164.93 117.44 177.68 42.903 30.204 40.715
+513 "C18" 61.227 72.827 56.013 8.7363 10.837 6.0872
+514 "D18" 204.51 199.19 195.95 75.509 74.636 56.066
+515 "E18" 73.692 73.322 148.06 10.413 9.8011 28.727
+516 "F18" 68.313 128.24 45.392 11.836 22.861 5.4226
+517 "G18" 131.14 85.288 152.52 26.954 18.177 29.358
+518 "H18" 89.609 153.68 93.128 16.220 29.699 13.154
+519 "I18" 30.179 29.676 28.922 2.3647 2.3980 1.9090
+520 "J18" 208.65 210.69 209.48 77.786 81.283 65.463
+521 "K18" 88.863 70.346 63.498 14.363 11.898 6.7644
+522 "L18" 197.92 177.16 54.602 60.378 57.128 5.2726
+523 "M18" 143.55 91.470 162.00 30.554 20.123 31.743
+524 "N18" 121.99 131.52 122.44 24.748 27.645 20.451
+525 "O18" 172.04 115.00 91.328 44.929 31.003 12.389
+526 "P18" 81.187 74.923 148.64 11.881 10.425 27.990
+527 "Q18" 117.91 169.48 101.12 25.737 39.690 14.823
+528 "R18" 183.93 145.62 52.297 52.300 42.856 4.6545
+529 "S18" 55.452 105.38 65.438 7.2126 14.429 7.1944
+530 "T18" 211.11 208.92 210.90 77.679 78.425 65.193
+531 "U18" 177.41 124.39 134.00 47.084 32.209 22.319
+532 "V18" 53.506 90.891 78.889 6.6683 11.848 10.189
+533 "W18" 197.65 205.13 206.81 65.207 70.970 60.729
+534 "X18" 51.396 86.860 43.674 6.2806 11.330 4.1095
+535 "Y18" 193.58 175.18 113.92 60.571 56.044 16.070
+536 "Z18" 96.313 103.94 178.60 15.673 16.045 40.153
+537 "2A18" 168.53 106.08 128.73 41.178 25.901 19.845
+538 "2B18" 85.496 104.15 136.89 13.693 16.674 24.407
+539 "2C18" 208.09 210.26 179.31 74.223 78.952 41.733
+540 "2D18" 161.94 92.492 50.116 38.135 24.817 4.1395
+541 "A19" 156.71 112.54 101.12 39.239 29.094 15.479
+542 "B19" 42.513 58.501 40.536 4.7416 7.0454 3.4644
+543 "C19" 172.17 152.13 143.40 49.395 43.657 28.522
+544 "D19" 159.73 183.13 54.703 42.332 52.372 5.7052
+545 "E19" 119.21 105.48 95.518 24.242 22.424 14.026
+546 "F19" 30.235 29.764 29.269 2.4551 2.5226 2.0256
+547 "G19" 88.689 134.99 136.69 16.677 25.667 25.825
+548 "H19" 86.392 53.901 45.566 13.124 8.8453 3.5763
+549 "I19" 126.88 158.15 160.78 28.527 37.076 34.358
+550 "J19" 120.42 79.125 64.241 22.891 16.490 6.9749
+551 "K19" 108.34 160.80 164.56 22.666 35.279 35.631
+552 "L19" 49.327 39.952 38.592 5.4212 4.5484 2.9627
+553 "M19" 67.917 128.27 44.976 11.199 21.925 5.4425
+554 "N19" 127.84 62.080 45.945 22.708 12.897 3.6335
+555 "O19" 74.380 138.45 130.11 12.507 23.738 22.498
+556 "P19" 30.060 29.337 28.817 2.3442 2.3896 1.9267
+557 "Q19" 147.97 73.539 46.480 30.303 17.749 3.5777
+558 "R19" 75.153 76.608 151.15 10.104 9.7374 28.448
+559 "S19" 78.339 144.41 52.936 13.901 26.685 6.3873
+560 "T19" 31.312 30.556 30.767 2.4391 2.4780 2.0610
+561 "U19" 169.32 177.98 203.35 45.972 49.473 57.247
+562 "V19" 44.471 72.376 45.634 4.8275 8.3485 3.9886
+563 "W19" 199.02 205.39 55.979 63.154 70.855 7.5811
+564 "X19" 90.125 81.954 73.039 14.863 14.166 8.5770
+565 "Y19" 207.33 211.44 212.22 74.340 78.986 66.286
+566 "Z19" 182.95 126.85 175.69 49.996 33.344 36.894
+567 "2A19" 77.857 90.598 163.13 10.165 11.287 33.081
+568 "2B19" 202.16 204.23 49.052 62.642 69.515 6.2139
+569 "2C19" 162.94 96.440 68.740 38.429 24.741 7.3479
+570 "2D19" 83.952 84.116 160.97 12.944 12.283 32.608
+END_DATA
diff --git a/ref/CMP_Digital_Target-3.ti2 b/ref/CMP_Digital_Target-3.ti2
new file mode 100644
index 0000000..e4b15e9
--- /dev/null
+++ b/ref/CMP_Digital_Target-3.ti2
@@ -0,0 +1,601 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2 for Christopher Metarie Digital Target 3"
+ORIGINATOR "Argyll printtarg"
+CREATED "Wed Sep 12 00:02:26 2007"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth i1 Pro"
+KEYWORD "ACCURATE_EXPECTED_VALUES"
+ACCURATE_EXPECTED_VALUES "true"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "30"
+KEYWORD "PASSES_IN_STRIPS2"
+PASSES_IN_STRIPS2 "19"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "A-Z, 2-9"
+KEYWORD "INDEX_ORDER"
+INDEX_ORDER "PATCH_THEN_STRIP"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 570
+BEGIN_DATA
+1 "A1" 106.60 73.896 140.50 19.991 14.120 27.886
+2 "B1" 101.22 157.76 91.298 19.926 34.054 14.005
+3 "C1" 56.474 54.712 116.20 6.2319 5.6339 19.078
+4 "D1" 142.23 143.96 106.67 32.785 35.198 16.672
+5 "E1" 161.58 92.303 143.82 38.996 22.658 25.805
+6 "F1" 90.405 96.497 94.153 16.011 17.612 14.561
+7 "G1" 163.39 98.124 88.178 39.496 24.997 12.003
+8 "H1" 63.278 55.370 115.21 7.4905 6.2468 18.358
+9 "I1" 71.385 133.64 49.363 11.987 23.286 6.5928
+10 "J1" 97.757 75.383 143.28 16.591 12.444 27.331
+11 "K1" 194.49 193.52 200.39 63.038 64.179 58.403
+12 "L1" 43.729 37.037 36.612 4.3513 3.8393 2.7750
+13 "M1" 128.36 143.53 178.51 27.386 30.873 42.527
+14 "N1" 136.71 176.12 173.90 31.789 44.281 40.439
+15 "O1" 190.25 190.03 173.26 59.453 61.985 40.335
+16 "P1" 139.89 69.074 45.054 26.783 15.713 3.5833
+17 "Q1" 34.433 40.188 37.667 3.0238 3.6843 3.0876
+18 "R1" 87.362 153.04 89.833 15.462 28.885 12.776
+19 "S1" 124.79 84.048 151.84 23.694 16.421 29.352
+20 "T1" 201.42 206.76 79.283 65.900 73.381 11.377
+21 "U1" 59.875 104.70 93.370 8.3333 15.036 13.749
+22 "V1" 205.39 208.60 159.63 72.416 77.985 33.423
+23 "W1" 91.572 136.12 167.03 16.393 25.254 38.122
+24 "X1" 30.336 29.306 28.957 2.3144 2.3581 1.9303
+25 "Y1" 132.60 110.17 107.91 27.102 23.276 16.813
+26 "Z1" 32.956 33.215 31.185 2.6994 2.8850 2.2332
+27 "2A1" 70.282 129.32 46.946 10.757 20.588 4.8216
+28 "2B1" 159.00 173.65 202.91 40.765 45.919 58.857
+29 "2C1" 121.19 88.150 161.84 22.864 16.381 33.839
+30 "2D1" 136.59 101.50 125.83 28.289 21.404 20.483
+31 "A2" 75.414 80.525 150.43 10.412 10.567 30.978
+32 "B2" 128.64 63.027 42.872 24.139 14.085 3.5857
+33 "C2" 101.62 116.40 166.26 19.473 21.752 38.376
+34 "D2" 129.62 78.772 146.55 26.280 16.991 28.035
+35 "E2" 164.20 144.75 82.589 42.573 39.671 9.6556
+36 "F2" 96.904 110.83 179.21 17.113 18.705 43.690
+37 "G2" 157.24 84.071 46.359 35.850 22.548 3.8554
+38 "H2" 84.439 70.424 140.26 13.037 10.392 26.425
+39 "I2" 81.661 147.44 58.864 14.946 28.262 8.1825
+40 "J2" 35.433 35.856 32.072 3.1780 3.3914 2.3047
+41 "K2" 150.66 144.08 140.58 35.880 35.178 26.683
+42 "L2" 158.35 93.379 154.74 36.434 22.147 28.386
+43 "M2" 100.38 93.492 99.897 17.689 17.022 15.072
+44 "N2" 158.93 93.968 95.921 36.396 23.022 13.623
+45 "O2" 102.60 137.21 171.09 19.884 26.988 39.544
+46 "P2" 74.932 50.703 44.902 10.294 7.4271 3.4839
+47 "Q2" 115.12 165.78 166.70 24.415 37.008 36.288
+48 "R2" 157.97 92.663 150.58 36.078 21.682 26.898
+49 "S2" 83.913 88.787 161.27 12.232 12.247 33.412
+50 "T2" 72.772 133.20 48.154 12.486 23.920 5.4357
+51 "U2" 155.64 177.45 175.23 38.913 47.091 40.794
+52 "V2" 65.311 50.797 44.712 8.3779 6.8387 3.7119
+53 "W2" 30.304 29.389 28.630 2.3401 2.3804 1.9157
+54 "X2" 98.383 112.57 76.501 17.501 20.678 9.7225
+55 "Y2" 196.95 176.56 81.174 60.324 56.490 9.7029
+56 "Z2" 106.87 76.461 64.020 18.340 14.257 6.9452
+57 "2A2" 149.29 180.57 55.756 39.051 50.700 6.0515
+58 "2B2" 46.850 72.093 42.887 5.3134 8.7205 3.7883
+59 "2C2" 126.21 86.097 104.74 24.040 16.842 14.641
+60 "2D2" 68.443 138.05 59.668 10.963 22.720 8.1563
+61 "A3" 40.703 34.668 43.170 3.2215 2.8069 3.1344
+62 "B3" 140.80 177.61 130.47 35.703 49.122 24.276
+63 "C3" 71.422 72.467 144.63 9.6710 9.2674 28.141
+64 "D3" 157.83 159.05 109.87 39.368 42.329 16.693
+65 "E3" 74.511 78.412 148.91 9.8448 9.8037 29.501
+66 "F3" 172.35 192.98 167.60 50.040 60.997 38.371
+67 "G3" 72.505 72.322 146.66 9.8731 9.2375 28.216
+68 "H3" 132.85 167.63 50.020 31.926 43.409 5.2962
+69 "I3" 99.822 132.27 193.48 18.889 24.530 52.235
+70 "J3" 158.78 88.817 87.144 36.271 22.167 11.952
+71 "K3" 146.32 156.61 192.38 34.281 37.060 50.573
+72 "L3" 30.978 30.641 29.826 2.4511 2.5353 2.0398
+73 "M3" 146.27 153.30 150.57 34.120 37.136 30.510
+74 "N3" 144.16 70.919 46.534 28.309 16.461 3.7229
+75 "O3" 85.091 72.947 144.27 12.851 10.508 27.052
+76 "P3" 122.91 131.12 67.881 24.532 27.910 7.4170
+77 "Q3" 140.27 116.77 178.48 29.800 23.719 40.761
+78 "R3" 73.020 103.31 46.082 11.420 17.249 4.2060
+79 "S3" 148.58 74.828 46.145 30.098 17.923 3.6411
+80 "T3" 92.676 106.61 179.17 15.102 16.455 41.548
+81 "U3" 89.067 149.36 56.522 16.816 29.880 6.2892
+82 "V3" 104.27 103.98 177.68 19.054 17.886 40.635
+83 "W3" 122.27 64.970 44.965 21.160 13.146 3.6418
+84 "X3" 190.80 157.08 167.65 56.827 44.647 36.033
+85 "Y3" 55.033 94.759 44.077 7.3224 13.350 4.3645
+86 "Z3" 157.08 85.576 87.558 34.447 20.515 11.595
+87 "2A3" 79.250 88.578 159.52 10.795 11.448 32.464
+88 "2B3" 108.15 127.71 55.172 20.617 25.691 5.5795
+89 "2C3" 78.102 75.847 150.05 11.126 10.174 28.914
+90 "2D3" 202.83 194.20 199.16 68.724 66.102 56.410
+91 "A4" 105.09 86.729 157.14 19.671 15.554 33.919
+92 "B4" 99.696 102.26 43.923 17.501 19.753 3.8498
+93 "C4" 107.26 130.81 190.72 21.509 25.734 51.674
+94 "D4" 178.30 141.51 75.719 51.958 42.451 9.1213
+95 "E4" 86.201 111.97 176.39 14.112 17.806 42.697
+96 "F4" 192.41 193.92 143.50 61.487 65.884 27.427
+97 "G4" 161.20 95.317 155.94 38.420 23.239 29.457
+98 "H4" 74.863 77.945 149.59 9.8759 9.7311 29.126
+99 "I4" 207.61 208.23 184.16 75.793 79.718 46.695
+100 "J4" 70.931 101.90 131.71 10.595 15.480 24.653
+101 "K4" 147.01 94.545 162.80 32.187 21.331 32.814
+102 "L4" 81.586 103.83 104.84 13.777 17.753 16.663
+103 "M4" 141.06 69.848 45.247 27.339 16.027 3.5603
+104 "N4" 90.494 151.07 150.65 16.922 28.995 29.336
+105 "O4" 55.294 41.016 63.313 6.3066 4.7610 6.9921
+106 "P4" 111.84 140.47 103.22 22.390 29.210 15.592
+107 "Q4" 144.45 93.249 162.31 30.657 20.369 32.268
+108 "R4" 105.31 104.82 101.31 19.152 19.807 15.592
+109 "S4" 79.325 137.68 48.973 13.948 25.671 5.2122
+110 "T4" 84.189 150.82 120.01 14.991 27.898 19.745
+111 "U4" 81.413 52.379 93.432 11.486 7.6381 12.484
+112 "V4" 76.459 77.531 42.048 10.749 11.899 3.2945
+113 "W4" 211.28 212.44 213.00 77.699 80.782 67.995
+114 "X4" 125.79 102.06 67.469 24.430 21.610 7.1800
+115 "Y4" 36.736 36.340 46.306 3.2104 3.1999 4.2513
+116 "Z4" 83.114 150.29 61.891 14.450 27.763 8.5197
+117 "2A4" 117.71 90.574 160.37 21.679 16.235 32.574
+118 "2B4" 89.463 153.87 72.494 15.737 29.267 10.078
+119 "2C4" 42.498 47.832 65.570 3.9226 4.4418 7.5674
+120 "2D4" 115.91 156.34 101.73 24.022 34.375 15.022
+121 "A5" 100.43 57.576 43.875 16.920 10.945 3.6233
+122 "B5" 139.57 140.52 191.37 32.876 32.373 51.547
+123 "C5" 106.24 157.82 63.346 23.454 37.144 7.5202
+124 "D5" 120.63 119.68 128.56 24.762 25.266 23.702
+125 "E5" 144.32 70.530 44.643 29.192 16.958 3.5359
+126 "F5" 112.12 164.88 139.23 23.640 37.186 26.447
+127 "G5" 103.37 136.87 47.413 20.387 28.842 4.7028
+128 "H5" 36.251 41.780 35.395 3.3636 4.0809 2.6833
+129 "I5" 111.24 162.80 164.26 23.272 35.820 35.198
+130 "J5" 143.56 87.562 156.55 30.642 19.573 30.103
+131 "K5" 109.54 163.06 164.19 22.753 35.416 35.064
+132 "L5" 79.627 52.133 45.354 11.209 7.8786 3.5144
+133 "M5" 92.456 152.33 153.19 17.513 29.721 30.234
+134 "N5" 34.714 33.013 32.281 2.9935 2.9559 2.2837
+135 "O5" 166.35 175.94 163.99 44.139 49.035 35.423
+136 "P5" 89.669 79.549 47.144 14.200 13.959 3.6761
+137 "Q5" 191.24 182.85 188.48 59.021 56.831 48.262
+138 "R5" 51.675 70.899 41.770 6.3401 9.2262 3.4989
+139 "S5" 170.53 177.54 173.76 45.700 49.818 40.124
+140 "T5" 63.890 93.942 45.687 9.3142 14.437 4.0636
+141 "U5" 30.168 29.299 28.940 2.3535 2.3975 1.9290
+142 "V5" 133.08 133.14 122.05 27.766 28.925 20.091
+143 "W5" 36.054 32.923 33.276 3.0887 2.9300 2.3596
+144 "X5" 61.314 111.77 45.755 8.7239 16.803 5.0276
+145 "Y5" 203.39 209.40 208.06 70.161 75.882 63.247
+146 "Z5" 76.353 77.670 109.77 11.191 11.244 16.654
+147 "2A5" 193.86 202.18 186.73 62.394 68.771 47.096
+148 "2B5" 84.630 73.965 145.61 12.640 10.459 27.333
+149 "2C5" 68.392 129.05 45.336 11.160 21.761 5.5099
+150 "2D5" 210.46 210.49 195.89 77.413 80.592 53.936
+151 "A6" 156.79 90.614 148.03 37.703 22.453 27.499
+152 "B6" 88.481 111.82 178.46 14.943 18.301 44.058
+153 "C6" 167.90 108.82 66.983 44.282 30.956 7.9185
+154 "D6" 66.578 110.85 54.360 10.440 18.144 6.5076
+155 "E6" 148.31 87.735 154.80 32.892 20.486 29.274
+156 "F6" 93.611 155.13 115.73 17.819 31.263 19.184
+157 "G6" 40.190 39.280 58.763 3.7468 3.6058 6.3752
+158 "H6" 170.89 152.59 147.19 45.907 41.132 28.818
+159 "I6" 46.469 44.545 75.326 4.4472 4.1158 9.1204
+160 "J6" 102.48 151.18 180.03 20.388 31.549 44.358
+161 "K6" 30.872 30.164 29.516 2.3970 2.4515 1.9961
+162 "L6" 83.294 137.00 98.315 14.323 24.343 14.536
+163 "M6" 30.722 30.150 29.446 2.3623 2.4293 1.9541
+164 "N6" 163.74 151.67 194.83 41.190 36.767 50.714
+165 "O6" 199.83 203.65 49.970 62.357 69.847 6.3069
+166 "P6" 77.512 86.873 159.07 10.124 10.811 31.915
+167 "Q6" 200.99 194.31 190.45 67.127 65.762 49.352
+168 "R6" 165.39 100.99 154.68 39.128 23.959 27.822
+169 "S6" 69.496 98.026 61.986 10.413 15.222 6.7952
+170 "T6" 167.68 124.93 146.98 41.195 30.074 26.292
+171 "U6" 62.706 68.483 60.211 8.4099 9.5591 6.5834
+172 "V6" 174.63 108.06 166.14 43.942 26.976 32.439
+173 "W6" 138.60 174.02 106.27 33.397 44.263 15.513
+174 "X6" 192.12 161.59 197.05 56.629 45.672 50.137
+175 "Y6" 71.207 70.503 63.173 10.198 10.583 6.9283
+176 "Z6" 171.42 121.85 182.26 42.782 29.822 40.386
+177 "2A6" 193.77 197.98 207.14 61.567 65.013 61.274
+178 "2B6" 117.80 82.965 151.94 21.335 15.115 28.916
+179 "2C6" 36.305 39.517 34.462 3.2203 3.7212 2.6005
+180 "2D6" 152.48 145.44 148.89 35.799 34.854 29.422
+181 "A7" 93.637 153.35 73.710 19.123 33.078 10.667
+182 "B7" 83.277 73.755 144.52 12.915 10.831 28.225
+183 "C7" 206.85 206.70 197.33 77.518 80.587 57.622
+184 "D7" 77.454 73.349 146.72 11.348 10.154 28.703
+185 "E7" 70.809 132.64 47.023 12.442 24.254 5.6475
+186 "F7" 91.049 88.345 163.10 15.345 13.969 34.910
+187 "G7" 177.87 190.87 53.018 52.703 61.988 5.9513
+188 "H7" 75.960 87.720 159.98 9.9056 10.888 32.881
+189 "I7" 199.48 192.77 181.55 67.471 66.483 44.705
+190 "J7" 64.713 68.090 67.610 8.8426 9.6268 8.1730
+191 "K7" 193.08 175.48 139.54 61.925 56.855 24.968
+192 "L7" 75.430 87.876 159.79 9.6349 10.726 32.427
+193 "M7" 133.24 173.17 56.742 32.435 45.157 6.1480
+194 "N7" 148.49 75.098 46.216 30.427 18.146 3.6270
+195 "O7" 97.134 97.177 86.559 16.928 17.695 11.911
+196 "P7" 191.20 160.30 54.685 56.094 48.894 4.9467
+197 "Q7" 80.068 80.251 125.32 11.934 11.778 20.573
+198 "R7" 83.368 147.19 55.358 15.285 28.434 6.3346
+199 "S7" 37.747 44.719 36.907 3.5054 4.3615 2.7830
+200 "T7" 146.52 175.26 205.50 35.099 44.589 58.771
+201 "U7" 133.97 82.941 152.98 26.155 17.005 28.079
+202 "V7" 63.182 103.22 97.125 8.9086 14.924 14.071
+203 "W7" 144.22 147.07 76.384 30.611 33.536 8.6858
+204 "X7" 212.78 213.19 211.89 79.113 81.784 66.503
+205 "Y7" 77.896 86.298 158.37 10.240 10.764 31.229
+206 "Z7" 71.313 133.52 47.389 11.976 23.218 5.4228
+207 "2A7" 75.926 78.650 151.98 9.9976 9.7574 28.929
+208 "2B7" 118.08 168.98 98.781 25.572 39.297 14.262
+209 "2C7" 207.34 198.34 43.623 66.257 69.908 5.8960
+210 "2D7" 92.639 108.26 179.66 14.893 16.603 41.626
+211 "A8" 69.904 137.36 58.325 12.100 24.359 8.4071
+212 "B8" 167.09 144.55 49.599 42.436 39.900 4.7260
+213 "C8" 111.10 78.672 121.83 20.574 15.216 20.136
+214 "D8" 74.340 141.34 56.829 12.701 25.255 8.1803
+215 "E8" 104.13 74.055 141.65 18.324 13.039 26.409
+216 "F8" 90.075 154.61 90.911 16.724 30.035 13.212
+217 "G8" 36.341 33.896 36.868 3.3200 3.1831 3.0291
+218 "H8" 101.65 159.66 134.07 20.304 33.570 24.443
+219 "I8" 34.216 33.499 37.712 2.9169 2.9009 3.0168
+220 "J8" 174.41 165.56 173.38 48.038 46.099 39.891
+221 "K8" 46.252 66.300 42.397 5.2241 8.0427 3.5985
+222 "L8" 152.69 184.12 182.69 38.619 50.368 44.407
+223 "M8" 30.240 29.863 28.939 2.3428 2.3959 1.9273
+224 "N8" 35.593 35.467 34.190 3.1956 3.3116 2.6415
+225 "O8" 71.728 71.553 70.937 10.494 10.847 8.8081
+226 "P8" 115.92 116.10 114.68 22.233 23.005 18.548
+227 "Q8" 159.85 160.38 159.13 39.317 40.778 33.056
+228 "R8" 196.60 197.21 197.12 63.147 65.480 53.862
+229 "S8" 137.57 112.53 140.33 28.252 23.514 24.400
+230 "T8" 80.940 142.13 50.952 14.520 26.909 5.4756
+231 "U8" 99.365 133.93 196.43 18.057 24.054 51.817
+232 "V8" 30.957 30.566 29.813 2.3402 2.3911 1.9209
+233 "W8" 212.09 210.69 210.55 77.838 79.255 64.883
+234 "X8" 90.920 71.799 46.751 14.232 12.342 3.5677
+235 "Y8" 137.72 177.30 175.40 31.451 43.594 39.472
+236 "Z8" 39.524 49.911 38.685 3.8429 5.0881 3.0661
+237 "2A8" 130.39 176.13 127.05 27.844 41.491 21.140
+238 "2B8" 31.904 31.437 30.690 2.4921 2.5648 2.0613
+239 "2C8" 149.77 158.18 196.00 34.635 36.777 50.964
+240 "2D8" 30.719 29.824 29.600 2.3436 2.3905 1.9440
+241 "A9" 160.64 188.72 135.75 46.811 59.109 25.406
+242 "B9" 151.09 113.48 161.82 35.695 26.905 33.928
+243 "C9" 56.378 101.12 44.028 8.0578 15.313 4.8058
+244 "D9" 200.86 192.61 183.06 70.562 68.540 46.575
+245 "E9" 77.639 89.149 161.20 10.633 11.656 33.787
+246 "F9" 183.43 148.52 132.23 54.113 43.360 23.933
+247 "G9" 53.868 83.869 77.703 7.1200 11.358 10.328
+248 "H9" 144.68 93.693 163.06 31.237 20.786 32.756
+249 "I9" 80.625 147.05 117.46 14.469 27.174 19.553
+250 "J9" 82.612 53.093 45.342 11.813 8.1727 3.4750
+251 "K9" 179.05 178.11 205.03 51.613 51.265 59.093
+252 "L9" 68.256 128.21 45.397 11.232 21.889 5.3482
+253 "M9" 30.122 29.559 28.786 2.3389 2.3932 1.9205
+254 "N9" 44.132 44.030 43.113 4.6543 4.8363 3.9004
+255 "O9" 77.603 77.496 77.212 11.973 12.444 10.082
+256 "P9" 123.38 123.35 123.35 24.548 25.410 20.720
+257 "Q9" 167.61 168.12 167.11 43.270 44.842 36.215
+258 "R9" 202.61 204.17 205.53 68.113 71.034 59.864
+259 "S9" 152.34 81.269 59.657 31.468 18.903 5.4734
+260 "T9" 36.525 39.233 37.120 3.2297 3.6435 2.9170
+261 "U9" 147.79 112.59 105.57 31.779 25.042 15.321
+262 "V9" 128.85 175.42 85.449 30.098 43.673 10.856
+263 "W9" 202.12 182.11 203.04 65.360 57.273 55.175
+264 "X9" 58.841 111.22 46.014 7.8261 15.682 5.0934
+265 "Y9" 150.27 74.574 46.780 30.151 17.603 3.5424
+266 "Z9" 91.373 72.814 142.15 14.169 10.872 25.545
+267 "2A9" 178.42 178.87 165.68 49.740 51.961 35.295
+268 "2B9" 110.21 82.066 150.83 19.293 14.167 28.533
+269 "2C9" 115.57 141.00 82.227 23.305 29.469 10.465
+270 "2D9" 120.44 87.308 156.62 22.420 16.254 30.792
+271 "A10" 54.278 98.104 59.100 7.4766 14.316 6.7672
+272 "B10" 141.49 142.92 50.130 30.693 34.185 4.8132
+273 "C10" 69.545 135.98 93.417 11.568 23.235 13.773
+274 "D10" 30.772 30.009 29.471 2.4307 2.4999 2.0171
+275 "E10" 140.52 89.479 159.03 30.140 19.949 31.751
+276 "F10" 88.149 135.62 165.23 15.810 25.353 37.521
+277 "G10" 30.508 30.075 29.389 2.4272 2.4936 1.9887
+278 "H10" 75.794 144.13 86.030 12.549 25.096 11.562
+279 "I10" 29.881 29.286 28.915 2.3402 2.3788 1.9223
+280 "J10" 78.427 139.08 135.09 13.387 24.235 23.958
+281 "K10" 127.69 103.24 52.122 25.478 22.853 4.3681
+282 "L10" 47.518 38.484 37.887 5.0366 4.2550 2.8902
+283 "M10" 30.202 29.466 28.978 2.3374 2.3915 1.9194
+284 "N10" 50.671 50.438 49.901 5.8942 6.1054 4.9143
+285 "O10" 84.087 84.218 84.130 13.462 14.013 11.428
+286 "P10" 130.92 131.27 131.19 27.055 28.014 23.007
+287 "Q10" 174.24 174.94 173.31 47.406 49.169 39.386
+288 "R10" 208.46 209.75 212.17 73.974 77.043 65.729
+289 "S10" 61.440 61.759 68.112 7.8358 8.0794 7.9176
+290 "T10" 189.59 154.63 195.61 54.395 42.563 48.165
+291 "U10" 70.065 139.76 58.155 11.113 22.841 7.7084
+292 "V10" 34.382 38.877 37.374 2.9394 3.4387 2.9247
+293 "W10" 81.185 148.91 88.683 13.284 25.973 11.867
+294 "X10" 31.337 30.706 30.647 2.4768 2.5120 2.1182
+295 "Y10" 132.10 124.54 122.36 27.102 26.481 19.829
+296 "Z10" 128.86 77.259 44.848 23.978 16.698 3.6586
+297 "2A10" 121.07 144.71 145.24 24.659 30.178 27.108
+298 "2B10" 91.404 54.498 76.524 13.618 8.1445 8.4106
+299 "2C10" 122.45 129.19 129.52 24.412 26.496 22.533
+300 "2D10" 52.091 43.712 85.349 5.2897 4.2252 10.803
+301 "A11" 95.121 56.945 109.13 15.662 9.9371 16.757
+302 "B11" 49.247 84.978 41.595 6.3528 11.756 4.1276
+303 "C11" 201.38 188.28 201.57 70.247 65.054 58.834
+304 "D11" 165.99 106.71 48.883 42.904 30.283 4.3741
+305 "E11" 142.45 151.87 140.77 33.675 37.292 27.259
+306 "F11" 59.895 43.373 70.686 7.3260 5.3398 8.4321
+307 "G11" 185.60 179.80 175.52 56.748 56.026 41.441
+308 "H11" 62.810 62.001 39.464 8.1585 8.7147 3.0001
+309 "I11" 182.38 181.99 177.01 54.512 56.195 42.466
+310 "J11" 44.613 62.579 56.523 4.9736 7.2275 6.1574
+311 "K11" 177.26 171.26 154.02 50.413 50.352 29.675
+312 "L11" 81.706 58.921 119.57 11.783 8.3671 18.993
+313 "M11" 30.648 29.769 29.464 2.4004 2.4632 1.9865
+314 "N11" 56.534 56.324 55.689 7.0502 7.2979 5.9348
+315 "O11" 89.911 89.936 88.980 15.157 15.663 12.643
+316 "P11" 140.77 141.41 140.88 30.809 31.935 26.037
+317 "Q11" 179.84 180.21 178.58 51.029 52.827 42.179
+318 "R11" 212.60 213.84 215.53 78.892 82.077 69.152
+319 "S11" 66.493 66.184 65.558 9.0391 9.3614 7.5795
+320 "T11" 187.32 160.61 146.99 54.688 46.067 27.270
+321 "U11" 59.842 44.929 41.517 7.0672 5.5203 3.1542
+322 "V11" 100.71 151.70 177.40 19.018 30.251 40.808
+323 "W11" 32.433 32.983 31.555 2.6438 2.7813 2.1741
+324 "X11" 103.41 161.56 150.03 20.294 33.254 28.954
+325 "Y11" 49.930 46.756 84.028 4.7917 4.3367 10.461
+326 "Z11" 157.24 187.57 185.20 39.678 51.335 44.730
+327 "2A11" 69.840 130.51 46.639 11.397 22.075 5.4606
+328 "2B11" 164.73 190.77 189.92 43.396 54.386 47.692
+329 "2C11" 67.660 57.565 50.639 9.0264 8.0855 4.5632
+330 "2D11" 146.88 73.255 46.894 29.263 17.239 3.6542
+331 "A12" 149.18 183.06 84.464 42.435 55.238 11.960
+332 "B12" 72.446 71.794 146.17 10.244 9.5241 28.550
+333 "C12" 111.58 163.80 82.344 25.557 39.490 11.397
+334 "D12" 67.115 62.023 67.669 9.5983 9.1448 8.3283
+335 "E12" 202.25 206.59 144.16 71.285 77.444 27.463
+336 "F12" 142.52 142.52 149.46 32.592 33.399 30.058
+337 "G12" 52.218 46.843 96.005 5.1430 4.3541 13.182
+338 "H12" 95.301 157.62 128.66 18.517 32.087 22.562
+339 "I12" 58.804 42.199 45.333 6.9977 5.1440 3.8014
+340 "J12" 201.67 207.01 112.57 69.246 76.042 17.844
+341 "K12" 76.878 56.433 113.86 10.642 7.6407 17.593
+342 "L12" 110.43 164.87 121.89 21.927 35.477 19.681
+343 "M12" 31.073 30.502 29.828 2.4287 2.4921 1.9949
+344 "N12" 60.863 60.999 60.221 7.9937 8.3172 6.7360
+345 "O12" 97.436 97.414 96.425 17.120 17.761 14.285
+346 "P12" 146.96 147.76 147.68 33.242 34.486 28.221
+347 "Q12" 186.04 186.49 184.52 55.136 57.000 45.303
+348 "R12" 217.03 217.69 217.80 84.047 87.070 71.496
+349 "S12" 173.81 166.67 164.48 46.799 45.618 34.284
+350 "T12" 61.998 59.133 126.43 6.6921 6.0185 19.773
+351 "U12" 133.08 178.53 107.01 31.583 45.365 15.646
+352 "V12" 159.59 92.307 67.569 35.975 22.808 7.0470
+353 "W12" 92.823 93.091 102.67 15.632 16.004 15.333
+354 "X12" 153.31 79.910 48.385 32.188 19.569 3.7849
+355 "Y12" 76.169 77.765 152.48 9.9981 9.6287 28.171
+356 "Z12" 80.867 145.82 55.209 14.429 27.348 6.4901
+357 "2A12" 88.726 84.091 155.13 13.822 12.446 29.936
+358 "2B12" 201.37 208.14 195.53 68.261 74.431 52.067
+359 "2C12" 32.004 31.705 30.813 2.4685 2.5621 2.0287
+360 "2D12" 135.53 145.08 187.78 28.798 30.974 45.549
+361 "A13" 86.415 69.301 138.07 14.129 10.884 26.286
+362 "B13" 104.58 136.42 46.559 21.280 29.662 4.6515
+363 "C13" 147.82 79.114 100.32 32.064 17.966 13.604
+364 "D13" 75.334 85.157 157.26 9.9611 10.733 32.277
+365 "E13" 178.81 179.96 148.24 51.845 54.927 28.181
+366 "F13" 55.482 72.327 100.16 6.3441 8.5421 15.068
+367 "G13" 200.09 199.75 184.43 68.699 71.452 46.387
+368 "H13" 76.688 84.710 151.41 10.374 10.902 29.169
+369 "I13" 129.73 107.35 52.022 26.203 23.997 4.3858
+370 "J13" 119.03 160.66 198.42 25.753 36.554 54.373
+371 "K13" 56.473 50.032 106.16 5.9068 4.9157 15.287
+372 "L13" 153.18 106.56 46.936 35.348 27.270 4.1933
+373 "M13" 32.264 31.978 31.289 2.6154 2.7053 2.1626
+374 "N13" 66.470 66.520 66.246 9.3637 9.6843 7.8391
+375 "O13" 105.28 105.86 104.76 19.359 20.106 16.147
+376 "P13" 153.75 154.63 154.12 36.624 37.957 30.671
+377 "Q13" 192.03 192.25 191.27 59.859 61.861 49.702
+378 "R13" 221.68 221.89 221.96 89.957 93.025 75.604
+379 "S13" 104.20 75.856 145.33 17.613 12.665 26.369
+380 "T13" 121.87 124.18 72.370 22.969 25.114 7.7873
+381 "U13" 91.392 55.886 72.021 13.623 8.3610 7.6135
+382 "V13" 193.01 176.53 161.70 59.661 54.433 33.140
+383 "W13" 97.047 61.496 44.638 15.045 10.609 3.4373
+384 "X13" 124.18 171.27 172.48 26.676 39.190 37.659
+385 "Y13" 100.95 103.55 45.932 16.770 18.831 3.7976
+386 "Z13" 98.719 76.722 108.03 16.243 13.004 15.620
+387 "2A13" 193.99 204.68 205.71 62.079 69.145 59.254
+388 "2B13" 77.619 94.368 167.50 9.8300 11.508 34.315
+389 "2C13" 91.512 53.191 50.701 13.378 8.4024 4.1065
+390 "2D13" 76.609 104.98 135.45 11.706 16.228 24.708
+391 "A14" 129.84 79.131 147.61 27.260 17.709 28.446
+392 "B14" 74.731 86.884 158.53 10.007 11.116 33.309
+393 "C14" 178.45 194.65 198.02 55.170 63.826 56.969
+394 "D14" 122.80 65.789 71.805 22.474 12.791 7.8220
+395 "E14" 99.529 101.15 66.691 17.833 19.340 7.6068
+396 "F14" 133.73 68.160 43.803 25.508 15.387 3.5019
+397 "G14" 130.31 174.28 137.87 28.674 42.244 25.294
+398 "H14" 110.49 77.413 145.63 20.013 14.167 27.201
+399 "I14" 30.999 29.764 29.587 2.4079 2.4331 1.9867
+400 "J14" 120.14 114.13 178.99 23.527 21.066 41.374
+401 "K14" 128.29 64.544 74.117 23.203 12.509 8.0121
+402 "L14" 176.70 157.34 183.40 48.486 42.511 43.112
+403 "M14" 59.777 105.00 45.141 8.6031 15.926 4.6200
+404 "N14" 182.00 181.11 190.30 53.107 53.884 48.977
+405 "O14" 42.651 40.749 62.042 3.9836 3.7404 6.5852
+406 "P14" 151.32 150.31 182.91 35.517 35.068 43.001
+407 "Q14" 162.51 94.932 125.82 37.782 22.314 19.042
+408 "R14" 99.745 94.301 93.467 17.467 17.105 13.104
+409 "S14" 107.25 159.78 58.090 22.370 35.508 5.9931
+410 "T14" 128.01 72.369 117.84 23.886 13.985 16.868
+411 "U14" 107.76 101.18 90.766 19.591 19.252 12.172
+412 "V14" 204.14 190.16 48.644 63.345 63.812 5.6645
+413 "W14" 82.597 65.626 44.970 12.028 10.481 3.3856
+414 "X14" 166.39 166.20 175.82 42.635 43.420 39.912
+415 "Y14" 100.69 152.17 51.384 19.856 32.192 5.1431
+416 "Z14" 91.650 100.20 90.746 15.570 17.641 12.711
+417 "2A14" 143.62 91.243 162.04 29.733 19.495 31.105
+418 "2B14" 214.71 215.34 214.31 81.209 84.285 67.959
+419 "2C14" 101.32 87.875 161.74 16.972 13.897 32.504
+420 "2D14" 105.18 138.75 68.497 20.262 27.906 7.7177
+421 "A15" 124.84 68.758 114.78 24.922 14.319 17.652
+422 "B15" 99.929 150.22 167.53 20.394 32.266 39.177
+423 "C15" 121.25 165.78 57.133 28.847 42.042 6.3345
+424 "D15" 129.49 121.04 130.58 27.579 26.553 23.681
+425 "E15" 161.27 95.254 123.97 38.874 23.290 19.357
+426 "F15" 148.20 174.03 142.22 36.703 46.352 27.027
+427 "G15" 150.41 98.923 167.42 34.061 22.803 34.531
+428 "H15" 75.180 91.615 158.04 10.113 11.921 31.879
+429 "I15" 196.22 179.25 172.32 64.423 58.008 39.281
+430 "J15" 66.558 62.105 60.696 9.4542 9.1717 6.7120
+431 "K15" 174.25 177.65 112.40 48.073 52.062 16.154
+432 "L15" 116.33 112.29 162.02 22.225 20.657 33.169
+433 "M15" 133.68 171.46 73.038 32.410 43.840 8.6168
+434 "N15" 102.47 146.49 198.15 19.932 29.141 53.896
+435 "O15" 64.715 46.574 43.032 8.2354 6.1612 3.2448
+436 "P15" 105.91 159.08 164.78 21.186 33.689 34.860
+437 "Q15" 34.379 33.754 36.003 2.8839 2.9372 2.7235
+438 "R15" 102.62 61.271 119.89 16.647 10.677 18.389
+439 "S15" 159.62 86.224 48.021 35.874 22.454 3.7685
+440 "T15" 95.611 158.57 127.45 18.024 31.495 21.231
+441 "U15" 133.03 87.140 157.87 26.027 17.635 30.172
+442 "V15" 48.894 77.368 43.484 5.7623 9.6302 3.8733
+443 "W15" 182.54 191.20 178.40 53.522 58.991 41.376
+444 "X15" 126.00 95.308 166.74 23.991 17.693 34.060
+445 "Y15" 38.376 39.986 33.590 3.5595 3.8688 2.3978
+446 "Z15" 148.30 148.94 147.37 34.055 35.265 28.241
+447 "2A15" 146.55 75.055 68.429 29.379 16.826 7.3609
+448 "2B15" 71.706 70.645 144.63 9.2107 8.5579 25.691
+449 "2C15" 133.02 80.816 44.452 25.707 18.129 3.6532
+450 "2D15" 82.777 113.54 117.52 13.875 19.568 19.948
+451 "A16" 147.43 75.104 45.417 32.441 19.582 3.7464
+452 "B16" 162.22 145.05 108.87 43.738 40.362 16.554
+453 "C16" 43.273 69.681 61.261 4.9159 8.3065 7.2559
+454 "D16" 154.15 106.72 65.606 37.197 27.832 7.4910
+455 "E16" 149.19 148.83 193.98 36.691 35.876 51.695
+456 "F16" 157.80 111.38 47.573 38.836 30.036 4.3338
+457 "G16" 100.61 79.449 149.13 17.555 13.363 28.888
+458 "H16" 206.92 207.61 211.44 75.466 77.836 67.216
+459 "I16" 97.895 82.272 66.348 16.954 15.112 7.2992
+460 "J16" 172.80 178.46 82.595 47.072 52.200 10.669
+461 "K16" 183.90 191.17 190.75 55.962 60.759 50.287
+462 "L16" 75.048 76.021 151.02 10.165 9.7715 28.705
+463 "M16" 159.42 88.282 47.938 36.859 23.500 3.8297
+464 "N16" 133.24 176.09 150.50 29.735 43.076 29.229
+465 "O16" 59.749 48.251 40.198 7.3545 6.2503 2.9745
+466 "P16" 171.06 168.69 161.58 46.114 46.965 33.568
+467 "Q16" 53.260 54.841 37.700 6.2218 6.8107 2.7776
+468 "R16" 147.03 76.735 66.424 29.663 17.214 6.8286
+469 "S16" 63.206 78.809 107.93 8.0381 10.138 16.410
+470 "T16" 150.22 77.352 47.226 31.088 18.734 3.6263
+471 "U16" 97.824 159.49 134.64 18.911 32.215 23.899
+472 "V16" 133.39 81.567 151.23 26.145 16.883 27.363
+473 "W16" 155.32 82.024 48.477 33.705 20.761 3.7986
+474 "X16" 81.301 147.86 56.013 14.361 27.487 7.1744
+475 "Y16" 141.53 112.75 178.08 29.882 22.982 39.138
+476 "Z16" 31.556 30.196 30.075 2.4233 2.4412 1.9648
+477 "2A16" 166.04 149.78 129.15 42.519 39.188 21.270
+478 "2B16" 53.939 48.402 100.70 5.2349 4.4461 13.823
+479 "2C16" 152.96 83.435 68.500 32.492 19.465 7.0806
+480 "2D16" 141.97 181.00 131.63 33.454 46.863 22.481
+481 "A17" 93.002 152.57 112.99 18.355 31.722 19.048
+482 "B17" 48.562 44.595 81.595 4.8626 4.2833 10.526
+483 "C17" 155.24 137.12 108.13 39.631 36.092 16.781
+484 "D17" 37.723 54.820 48.270 3.8471 5.8319 4.8962
+485 "E17" 163.04 158.68 133.73 43.491 44.349 22.904
+486 "F17" 155.10 81.151 47.477 35.028 21.444 3.8305
+487 "G17" 119.76 108.26 175.73 23.826 20.302 40.464
+488 "H17" 155.83 188.69 108.40 44.211 56.679 16.435
+489 "I17" 54.125 49.417 43.252 6.5115 6.2807 3.6004
+490 "J17" 146.89 182.65 155.76 35.464 48.530 31.500
+491 "K17" 148.71 77.345 50.119 31.217 18.833 4.2081
+492 "L17" 53.925 41.854 39.291 6.1796 5.0138 3.0160
+493 "M17" 105.46 156.83 167.45 21.355 33.511 36.981
+494 "N17" 149.16 79.222 103.08 31.382 17.339 13.539
+495 "O17" 109.98 107.89 138.78 20.515 20.076 24.934
+496 "P17" 151.99 78.765 47.620 32.143 19.447 3.7592
+497 "Q17" 195.13 169.06 200.08 60.501 50.532 52.708
+498 "R17" 73.599 136.55 49.271 12.657 24.420 5.6873
+499 "S17" 37.757 33.718 34.938 3.4355 3.1639 2.5372
+500 "T17" 132.61 142.77 197.68 28.192 29.771 51.322
+501 "U17" 181.82 145.93 103.48 52.660 42.651 15.019
+502 "V17" 204.10 203.91 210.35 69.823 71.393 63.731
+503 "W17" 175.82 179.36 52.229 44.995 50.413 5.2421
+504 "X17" 155.69 156.50 143.88 37.401 38.967 26.702
+505 "Y17" 65.731 44.495 80.654 8.0339 5.5483 9.9052
+506 "Z17" 67.930 138.21 88.916 10.382 21.829 11.599
+507 "2A17" 156.40 87.866 68.881 34.325 21.131 7.2263
+508 "2B17" 68.870 68.990 41.254 9.1863 9.9839 3.1512
+509 "2C17" 209.60 202.66 207.60 75.534 73.388 61.922
+510 "2D17" 108.97 87.062 152.98 19.258 14.916 29.290
+511 "A18" 200.70 204.40 197.90 74.089 78.770 59.424
+512 "B18" 164.93 117.44 177.68 42.903 30.204 40.715
+513 "C18" 61.227 72.827 56.013 8.7363 10.837 6.0872
+514 "D18" 204.51 199.19 195.95 75.509 74.636 56.066
+515 "E18" 73.692 73.322 148.06 10.413 9.8011 28.727
+516 "F18" 68.313 128.24 45.392 11.836 22.861 5.4226
+517 "G18" 131.14 85.288 152.52 26.954 18.177 29.358
+518 "H18" 89.609 153.68 93.128 16.220 29.699 13.154
+519 "I18" 30.179 29.676 28.922 2.3647 2.3980 1.9090
+520 "J18" 208.65 210.69 209.48 77.786 81.283 65.463
+521 "K18" 88.863 70.346 63.498 14.363 11.898 6.7644
+522 "L18" 197.92 177.16 54.602 60.378 57.128 5.2726
+523 "M18" 143.55 91.470 162.00 30.554 20.123 31.743
+524 "N18" 121.99 131.52 122.44 24.748 27.645 20.451
+525 "O18" 172.04 115.00 91.328 44.929 31.003 12.389
+526 "P18" 81.187 74.923 148.64 11.881 10.425 27.990
+527 "Q18" 117.91 169.48 101.12 25.737 39.690 14.823
+528 "R18" 183.93 145.62 52.297 52.300 42.856 4.6545
+529 "S18" 55.452 105.38 65.438 7.2126 14.429 7.1944
+530 "T18" 211.11 208.92 210.90 77.679 78.425 65.193
+531 "U18" 177.41 124.39 134.00 47.084 32.209 22.319
+532 "V18" 53.506 90.891 78.889 6.6683 11.848 10.189
+533 "W18" 197.65 205.13 206.81 65.207 70.970 60.729
+534 "X18" 51.396 86.860 43.674 6.2806 11.330 4.1095
+535 "Y18" 193.58 175.18 113.92 60.571 56.044 16.070
+536 "Z18" 96.313 103.94 178.60 15.673 16.045 40.153
+537 "2A18" 168.53 106.08 128.73 41.178 25.901 19.845
+538 "2B18" 85.496 104.15 136.89 13.693 16.674 24.407
+539 "2C18" 208.09 210.26 179.31 74.223 78.952 41.733
+540 "2D18" 161.94 92.492 50.116 38.135 24.817 4.1395
+541 "A19" 156.71 112.54 101.12 39.239 29.094 15.479
+542 "B19" 42.513 58.501 40.536 4.7416 7.0454 3.4644
+543 "C19" 172.17 152.13 143.40 49.395 43.657 28.522
+544 "D19" 159.73 183.13 54.703 42.332 52.372 5.7052
+545 "E19" 119.21 105.48 95.518 24.242 22.424 14.026
+546 "F19" 30.235 29.764 29.269 2.4551 2.5226 2.0256
+547 "G19" 88.689 134.99 136.69 16.677 25.667 25.825
+548 "H19" 86.392 53.901 45.566 13.124 8.8453 3.5763
+549 "I19" 126.88 158.15 160.78 28.527 37.076 34.358
+550 "J19" 120.42 79.125 64.241 22.891 16.490 6.9749
+551 "K19" 108.34 160.80 164.56 22.666 35.279 35.631
+552 "L19" 49.327 39.952 38.592 5.4212 4.5484 2.9627
+553 "M19" 67.917 128.27 44.976 11.199 21.925 5.4425
+554 "N19" 127.84 62.080 45.945 22.708 12.897 3.6335
+555 "O19" 74.380 138.45 130.11 12.507 23.738 22.498
+556 "P19" 30.060 29.337 28.817 2.3442 2.3896 1.9267
+557 "Q19" 147.97 73.539 46.480 30.303 17.749 3.5777
+558 "R19" 75.153 76.608 151.15 10.104 9.7374 28.448
+559 "S19" 78.339 144.41 52.936 13.901 26.685 6.3873
+560 "T19" 31.312 30.556 30.767 2.4391 2.4780 2.0610
+561 "U19" 169.32 177.98 203.35 45.972 49.473 57.247
+562 "V19" 44.471 72.376 45.634 4.8275 8.3485 3.9886
+563 "W19" 199.02 205.39 55.979 63.154 70.855 7.5811
+564 "X19" 90.125 81.954 73.039 14.863 14.166 8.5770
+565 "Y19" 207.33 211.44 212.22 74.340 78.986 66.286
+566 "Z19" 182.95 126.85 175.69 49.996 33.344 36.894
+567 "2A19" 77.857 90.598 163.13 10.165 11.287 33.081
+568 "2B19" 202.16 204.23 49.052 62.642 69.515 6.2139
+569 "2C19" 162.94 96.440 68.740 38.429 24.741 7.3479
+570 "2D19" 83.952 84.116 160.97 12.944 12.283 32.608
+END_DATA
diff --git a/ref/CRT.ccss b/ref/CRT.ccss
new file mode 100644
index 0000000..5b9eb80
--- /dev/null
+++ b/ref/CRT.ccss
@@ -0,0 +1,42 @@
+CCSS
+
+DESCRIPTOR "CCSS for CRT"
+ORIGINATOR "Argyll ccxxmake"
+CREATED "Wed Aug 31 22:46:24 2011"
+KEYWORD "DISPLAY"
+DISPLAY "Hitachi CM2112MET, Diamond View 1772ie"
+KEYWORD "TECHNOLOGY"
+TECHNOLOGY "CRT"
+KEYWORD "DISPLAY_TYPE_REFRESH"
+DISPLAY_TYPE_REFRESH "YES"
+KEYWORD "UI_SELECTORS"
+UI_SELECTORS "c"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "118"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "350.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "740.000000"
+
+NUMBER_OF_FIELDS 119
+BEGIN_DATA_FORMAT
+SAMPLE_ID SPEC_350 SPEC_353 SPEC_357 SPEC_360 SPEC_363 SPEC_367 SPEC_370 SPEC_373 SPEC_377 SPEC_380 SPEC_383 SPEC_387 SPEC_390 SPEC_393 SPEC_397 SPEC_400 SPEC_403 SPEC_407 SPEC_410 SPEC_413 SPEC_417 SPEC_420 SPEC_423 SPEC_427 SPEC_430 SPEC_433 SPEC_437 SPEC_440 SPEC_443 SPEC_447 SPEC_450 SPEC_453 SPEC_457 SPEC_460 SPEC_463 SPEC_467 SPEC_470 SPEC_473 SPEC_477 SPEC_480 SPEC_483 SPEC_487 SPEC_490 SPEC_493 SPEC_497 SPEC_500 SPEC_503 SPEC_507 SPEC_510 SPEC_513 SPEC_517 SPEC_520 SPEC_523 SPEC_527 SPEC_530 SPEC_533 SPEC_537 SPEC_540 SPEC_543 SPEC_547 SPEC_550 SPEC_553 SPEC_557 SPEC_560 SPEC_563 SPEC_567 SPEC_570 SPEC_573 SPEC_577 SPEC_580 SPEC_583 SPEC_587 SPEC_590 SPEC_593 SPEC_597 SPEC_600 SPEC_603 SPEC_607 SPEC_610 SPEC_613 SPEC_617 SPEC_620 SPEC_623 SPEC_627 SPEC_630 SPEC_633 SPEC_637 SPEC_640 SPEC_643 SPEC_647 SPEC_650 SPEC_653 SPEC_657 SPEC_660 SPEC_663 SPEC_667 SPEC_670 SPEC_673 SPEC_677 SPEC_680 SPEC_683 SPEC_687 SPEC_690 SPEC_693 SPEC_697 SPEC_700 SPEC_703 SPEC_707 SPEC_710 SPEC_713 SPEC_717 SPEC_720 SPEC_723 SPEC_727 SPEC_730 SPEC_733 SPEC_737 SPEC_740
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 14
+BEGIN_DATA
+1 -7.3700e-04 6.1095e-03 0.020354 0.011089 -0.014952 -0.015479 -0.020888 0.027670 -0.027287 0.010601 4.2205e-03 -0.017912 -8.1306e-03 4.5454e-03 -7.3271e-03 -4.0405e-03 0.024777 0.032952 0.064311 0.063862 0.057954 0.10684 0.13254 0.16127 0.18654 0.21677 0.25272 0.26655 0.29312 0.30823 0.31529 0.32202 0.29030 0.29707 0.30249 0.30359 0.32619 0.30877 0.27962 0.26530 0.24185 0.24539 0.29581 0.34715 0.39553 0.39491 0.32338 0.25875 0.30497 0.52190 0.55100 0.39806 0.29395 0.28863 0.33812 0.43367 0.84770 1.5588 1.4688 0.78170 0.47425 0.58771 0.86740 0.79104 0.50757 0.43964 0.40264 0.34495 0.37491 0.74227 1.7837 3.4401 4.0819 5.0589 6.5397 4.6700 1.4797 1.1370 1.8928 6.1931 15.071 18.401 27.859 48.762 44.830 17.634 4.0753 1.2994 0.59734 0.43588 0.35368 0.36829 0.40927 0.36990 0.32213 0.32840 0.42884 0.54795 0.51201 0.42537 0.76886 1.5324 1.5464 1.1802 1.6755 4.2219 12.545 22.218 18.635 6.5901 0.73773 0.34854 0.27621 0.25350 0.20876 0.14641 0.16087 0.17191
+2 -2.4493e-03 0.021567 0.054497 0.023205 0.019870 0.063323 0.044675 0.053733 0.016618 0.038352 0.020519 0.021606 0.019095 0.012931 0.031764 0.044953 0.056768 0.060961 0.064268 0.074291 0.095784 0.13581 0.16558 0.18438 0.22416 0.27177 0.31740 0.36627 0.40037 0.44618 0.49044 0.53016 0.56820 0.65256 0.75017 0.88415 1.0849 1.3594 1.7265 2.1976 2.7794 3.5345 4.4413 5.4169 6.4809 7.6474 8.8551 9.9726 10.935 11.814 12.759 13.608 14.022 14.324 14.831 15.256 15.394 15.263 14.893 14.377 13.861 13.284 12.422 11.341 10.329 9.3851 8.3414 7.2985 6.4383 5.7180 5.0684 4.4692 3.9615 3.5435 3.1881 2.7663 2.3521 2.0733 1.8620 1.7527 1.7794 1.6929 1.8051 2.2423 2.0107 1.1558 0.71531 0.55855 0.46204 0.42080 0.35185 0.30212 0.26598 0.25609 0.25139 0.25151 0.20103 0.19451 0.16380 0.16465 0.17406 0.17408 0.16916 0.17716 0.22784 0.28489 0.52887 0.79378 0.70727 0.36607 0.22348 0.19336 0.16239 0.18587 0.21809 0.25263 0.25801 0.21398
+3 -3.0028e-03 0.025209 0.078741 0.047349 -5.6730e-03 0.051147 0.023143 0.046124 0.041976 0.046679 2.4038e-03 4.4094e-03 0.028173 0.042252 0.051262 0.050293 0.048719 0.061859 0.089619 0.12025 0.14885 0.19829 0.26031 0.31910 0.40649 0.47843 0.53883 0.61313 0.66384 0.72701 0.78650 0.80945 0.86159 0.93696 1.0181 1.1684 1.3888 1.6370 1.9777 2.4423 2.9885 3.7391 4.6841 5.7011 6.8072 7.9594 9.0734 10.126 11.154 12.165 13.139 13.755 14.028 14.323 14.862 15.389 15.943 16.501 16.053 14.875 14.062 13.604 13.044 11.895 10.599 9.6142 8.5721 7.4996 6.6716 6.3370 6.7305 7.7882 7.8986 8.4440 9.5222 7.2856 3.7489 3.1147 3.6696 7.7661 16.442 19.607 28.910 49.669 45.608 18.306 4.6380 1.8015 1.0356 0.82630 0.68474 0.62193 0.65342 0.61600 0.52413 0.52215 0.57743 0.68820 0.63334 0.52266 0.92521 1.6558 1.6864 1.2909 1.7999 4.2448 12.632 22.410 18.792 6.7354 0.83797 0.40737 0.41943 0.41237 0.38109 0.34629 0.27222 0.18790
+4 -1.1368e-03 8.7317e-03 0.037091 0.033352 7.9502e-03 0.074724 0.057022 0.085936 0.11924 0.17141 0.25849 0.36967 0.52277 0.74478 0.99210 1.2880 1.6315 2.0437 2.6240 3.3827 4.3601 5.6089 7.1227 8.8386 10.712 12.541 14.150 15.523 16.465 17.120 17.401 17.146 16.568 15.822 14.933 13.909 12.909 11.922 10.874 9.8039 8.7005 7.7302 6.8910 6.0031 5.1519 4.3953 3.7315 3.1433 2.6142 2.1763 1.8225 1.5358 1.2796 1.0760 0.92209 0.80122 0.70911 0.63347 0.55076 0.47010 0.41522 0.37928 0.34798 0.30440 0.26669 0.23800 0.20130 0.16902 0.14893 0.12905 0.12879 0.14397 0.15014 0.15730 0.15974 0.13569 0.086498 0.089819 0.099452 0.14771 0.25712 0.29124 0.42187 0.69645 0.65229 0.30073 0.12243 0.077598 0.073020 0.094930 0.10403 0.093978 0.086995 0.13438 0.13641 0.13705 0.13657 0.18451 0.16483 0.15674 0.15712 0.14541 0.15869 0.13660 0.14607 0.18591 0.35565 0.51347 0.48610 0.25682 0.11789 0.11814 0.098212 0.068700 0.10601 0.077454 0.094982 0.10982
+5 -2.2226e-03 0.020571 0.041058 -2.7634e-03 -0.011584 -7.8557e-03 0.032369 0.054281 0.095994 0.17359 0.26377 0.38957 0.52887 0.74869 0.99436 1.2890 1.6141 2.0437 2.6310 3.3734 4.3548 5.5941 7.0890 8.7769 10.622 12.467 14.094 15.482 16.480 17.161 17.469 17.215 16.637 15.896 15.016 14.025 13.036 12.070 11.008 9.9281 8.8113 7.8644 7.0851 6.2536 5.4619 4.7374 3.9923 3.3645 2.8930 2.6379 2.3357 1.8892 1.5317 1.3146 1.2128 1.1996 1.5280 2.1507 1.9742 1.2177 0.86241 0.93313 1.1819 1.0672 0.73378 0.63309 0.58601 0.48253 0.48543 0.84379 1.8909 3.5855 4.2175 5.1864 6.6537 4.7764 1.5429 1.1764 1.9564 6.2869 15.197 18.555 28.051 48.956 44.959 17.704 4.1197 1.3703 0.65604 0.51775 0.42091 0.42665 0.49014 0.45893 0.42404 0.45564 0.52296 0.66426 0.61818 0.48217 0.87114 1.6147 1.6473 1.2541 1.7183 4.2347 12.613 22.356 18.787 6.6579 0.76160 0.40378 0.33627 0.29396 0.27160 0.18503 0.13327 0.13244
+6 -4.2548e-03 0.034747 0.11666 0.11900 0.081282 0.071189 0.066498 0.10725 0.13639 0.19829 0.26744 0.39534 0.54733 0.75213 1.0100 1.3181 1.6731 2.0926 2.6703 3.4246 4.4063 5.6613 7.1697 8.8888 10.782 12.632 14.268 15.652 16.640 17.309 17.640 17.420 16.895 16.233 15.460 14.597 13.800 13.112 12.445 11.854 11.356 11.155 11.233 11.341 11.551 11.963 12.526 13.047 13.489 13.868 14.454 14.959 15.079 15.163 15.479 15.756 15.755 15.537 15.088 14.503 13.947 13.350 12.484 11.379 10.335 9.3897 8.3343 7.2800 6.4208 5.7058 5.0641 4.4933 3.9964 3.5862 3.2526 2.8152 2.3621 2.1073 1.8881 1.8335 1.9753 1.9294 2.1395 2.8184 2.5520 1.4044 0.80205 0.60486 0.50602 0.47270 0.42625 0.38338 0.33918 0.36632 0.34227 0.31604 0.29442 0.31916 0.31319 0.29496 0.30266 0.30052 0.29051 0.26534 0.29669 0.40323 0.76418 1.1948 1.0572 0.54035 0.26406 0.23523 0.20553 0.23956 0.26220 0.26412 0.25833 0.25881
+7 -6.1567e-03 0.046578 0.20350 0.23369 0.096015 0.21914 0.19183 0.22443 0.28301 0.44517 0.57975 0.82101 1.1237 1.5355 2.0487 2.6132 3.2808 4.1530 5.2895 6.7583 8.7317 11.213 14.164 17.507 21.196 24.842 28.074 30.853 32.721 34.118 34.783 34.374 33.302 32.015 30.518 28.856 27.364 26.029 24.687 23.482 22.488 22.114 22.375 22.667 23.196 24.039 24.969 25.893 26.884 28.033 29.229 29.943 30.002 30.175 30.929 31.737 32.617 33.589 32.527 30.083 28.399 27.418 26.244 23.948 21.346 19.331 17.227 15.037 13.390 12.728 13.489 15.586 15.777 16.889 19.059 14.603 7.5120 6.2714 7.3827 15.597 33.037 39.408 58.173 100.00 91.893 36.932 9.4472 3.7485 2.1941 1.7503 1.5411 1.3912 1.4333 1.4455 1.3057 1.2738 1.4218 1.6386 1.5111 1.2973 2.0050 3.5094 3.6047 2.8114 3.7529 8.8795 26.089 46.025 38.563 13.882 1.8645 1.1260 0.96853 0.82897 0.82685 0.80802 0.79237 0.75046
+8 -3.0243e-003 0.021963 0.10572 0.15818 0.086760 -2.2270e-003 0.013776 0.12474 0.032279 0.057171 -6.7098e-003 0.014431 0.051666 0.015062 0.036417 0.080134 0.10473 0.10493 0.13533 0.15081 0.13670 0.17271 0.22562 0.25312 0.28423 0.34783 0.36887 0.36716 0.40319 0.40719 0.39590 0.40184 0.37547 0.35142 0.36940 0.43590 0.48253 0.46133 0.38222 0.33422 0.29552 0.34283 0.46555 0.52325 0.64655 0.64990 0.41709 0.33820 0.47861 0.78870 0.86320 0.54510 0.35908 0.36006 0.42539 0.55946 1.0962 2.0405 1.8904 0.97393 0.58505 0.69035 0.99079 0.90243 0.62042 0.56242 0.53268 0.47398 0.48895 0.88852 2.0320 3.4805 3.8943 5.3733 7.3099 5.2596 1.7975 1.5319 2.3679 6.6826 15.451 18.618 28.017 48.672 44.305 17.193 3.9595 1.3712 0.77892 0.67565 0.54782 0.53111 0.63456 0.66363 0.50958 0.43008 0.53407 0.62899 0.61791 0.54333 1.0493 2.1288 2.2176 1.7526 2.4695 6.1417 18.268 32.150 26.824 9.5492 1.2661 0.71686 0.73545 0.75076 0.70875 0.58500 0.56398 0.46740
+9 3.1411e-004 -4.3065e-003 6.7770e-003 0.029770 -3.8142e-003 -0.014539 -0.021943 0.038745 8.2185e-003 0.048000 -0.014007 5.6365e-003 0.014422 0.031985 0.058386 0.063306 0.070400 0.083127 0.11748 0.12364 0.12066 0.16501 0.20468 0.23858 0.29343 0.35767 0.37299 0.41052 0.46600 0.48584 0.52273 0.56663 0.59468 0.65937 0.73336 0.87801 1.0536 1.3333 1.7010 2.1522 2.7313 3.4798 4.3641 5.2799 6.2810 7.3831 8.4797 9.5071 10.387 11.115 11.916 12.596 12.906 13.099 13.451 13.744 13.756 13.605 13.306 12.922 12.579 12.206 11.580 10.724 9.9165 9.1298 8.1707 7.1681 6.2977 5.5549 4.8247 4.1330 3.5616 3.1257 2.7447 2.3821 2.0759 1.8075 1.5643 1.4105 1.2781 1.1490 1.0880 1.1309 0.97991 0.64160 0.48702 0.42041 0.38289 0.31928 0.25639 0.20914 0.20041 0.21606 0.18762 0.16854 0.16316 0.17769 0.18872 0.19560 0.17368 0.18057 0.19752 0.23601 0.23641 0.25333 0.38237 0.50747 0.50476 0.38217 0.31891 0.29606 0.30800 0.39872 0.45122 0.42287 0.45432 0.41564
+10 -1.8536e-003 0.014156 0.057644 0.091021 0.072453 -0.017848 0.014141 0.033066 0.10668 0.068976 8.9062e-003 0.026244 0.072843 0.089121 0.11664 0.12514 0.12049 0.16042 0.21348 0.23141 0.26155 0.32497 0.39567 0.46032 0.53433 0.64585 0.70972 0.74796 0.80912 0.83152 0.87857 0.92129 0.92994 0.98411 1.0821 1.2682 1.5380 1.7932 2.0980 2.5074 3.0341 3.8133 4.8058 5.7992 6.9220 8.0307 8.9372 9.8722 10.871 11.925 12.819 13.216 13.331 13.507 13.907 14.345 14.936 15.716 15.250 13.968 13.232 12.959 12.624 11.687 10.563 9.6919 8.7003 7.6389 6.7709 6.4534 6.8589 7.6109 7.4577 8.4433 10.028 7.6240 3.8305 3.3026 3.8924 8.0027 16.636 19.622 28.947 49.536 45.017 17.778 4.4243 1.7697 1.1065 0.95735 0.77967 0.74692 0.80900 0.80062 0.68228 0.53869 0.60105 0.72137 0.71147 0.65133 1.1745 2.2006 2.2582 1.8103 2.5112 6.3159 18.570 32.512 27.113 9.7708 1.3430 0.79796 0.73946 0.80235 0.77386 0.60207 0.58900 0.65814
+11 -2.3518e-003 0.019036 0.066658 0.065324 0.013564 -0.014231 0.039825 0.094398 0.12788 0.22194 0.24422 0.38008 0.53562 0.73002 1.0220 1.3301 1.6485 2.0579 2.6108 3.2773 4.0875 5.0758 6.2126 7.3926 8.6022 9.7173 10.549 11.207 11.612 11.802 11.828 11.534 11.020 10.466 9.8465 9.1778 8.5023 7.8793 7.1822 6.4750 5.7433 5.0971 4.5198 3.8961 3.3180 2.8334 2.3770 1.9941 1.6724 1.3745 1.1555 0.95834 0.81628 0.69057 0.60598 0.52278 0.44434 0.41813 0.37473 0.32764 0.29297 0.27283 0.26603 0.23111 0.20899 0.19898 0.17154 0.15166 0.14440 0.14026 0.14055 0.11907 0.10712 0.11742 0.11879 0.10944 0.098970 0.085629 0.076777 0.12902 0.15278 0.17169 0.22796 0.32860 0.29775 0.13847 0.093693 0.099290 0.12471 0.11584 0.076686 0.064523 0.088899 0.13892 0.12382 0.12405 0.13804 0.15727 0.19447 0.19982 0.17738 0.18354 0.18923 0.20861 0.20472 0.22623 0.34501 0.43425 0.42256 0.32025 0.30011 0.29157 0.26554 0.33820 0.35962 0.38420 0.40679 0.34604
+12 -2.5087e-003 0.019542 0.076799 0.095288 0.048747 -8.7747e-003 -7.4653e-003 0.086691 0.11530 0.23228 0.24220 0.39511 0.54453 0.77571 1.0615 1.4031 1.7598 2.1630 2.7326 3.4311 4.2793 5.3057 6.4646 7.7003 8.9625 10.104 10.993 11.675 12.068 12.270 12.291 11.975 11.423 10.846 10.250 9.6049 9.0082 8.3596 7.5963 6.8291 6.0544 5.4379 4.9414 4.4150 3.9493 3.4680 2.8101 2.2992 2.0740 2.1081 1.9803 1.4802 1.1328 0.98651 0.96255 1.0163 1.4906 2.4052 2.2114 1.2497 0.80250 0.90171 1.2120 1.0815 0.75381 0.69015 0.62034 0.54414 0.54506 0.95594 2.0957 3.5424 3.9584 5.4236 7.3729 5.3179 1.8201 1.5688 2.4000 6.6895 15.493 18.664 28.136 48.883 44.542 17.346 4.0438 1.3863 0.77278 0.67434 0.57921 0.60386 0.66246 0.66688 0.56299 0.46786 0.54442 0.67267 0.67425 0.57713 1.0971 2.0984 2.1840 1.7712 2.4472 6.1564 18.308 32.277 26.966 9.5862 1.3431 0.78754 0.70374 0.62490 0.58397 0.58770 0.51841 0.45820
+13 -4.2484e-003 0.036049 0.10475 0.088243 0.061262 0.027990 0.069014 0.10311 0.14821 0.26407 0.27443 0.40068 0.57466 0.77337 1.0602 1.3831 1.7246 2.1487 2.7195 3.4037 4.2360 5.2580 6.4319 7.6617 8.9221 10.078 10.977 11.679 12.127 12.348 12.413 12.168 11.690 11.201 10.659 10.110 9.6305 9.2796 8.9485 8.6912 8.5401 8.6174 8.9060 9.2096 9.6227 10.217 10.877 11.509 12.040 12.475 13.072 13.564 13.721 13.771 14.038 14.256 14.199 14.005 13.650 13.228 12.859 12.458 11.810 10.923 10.094 9.2892 8.3084 7.2865 6.4127 5.6551 4.9225 4.2255 3.6354 3.2150 2.8395 2.4630 2.1230 1.8468 1.6185 1.4885 1.3853 1.2624 1.2627 1.4152 1.2338 0.76973 0.56016 0.47637 0.43679 0.39196 0.30938 0.25526 0.25925 0.29926 0.26437 0.23604 0.26530 0.27826 0.30132 0.30326 0.29592 0.27409 0.26259 0.29385 0.29629 0.36051 0.57302 0.75371 0.68550 0.47208 0.38098 0.38061 0.36402 0.43526 0.46143 0.47224 0.51120 0.49274
+14 -0.015896 0.13024 0.43197 0.43696 0.30469 0.24329 0.19535 0.36553 0.40560 0.55260 0.65328 0.89291 1.2791 1.6564 2.2735 2.9397 3.6423 4.5037 5.6891 7.1097 8.8310 10.928 13.335 15.897 18.484 20.949 22.768 24.264 25.165 25.609 25.772 25.217 24.248 23.238 22.151 21.163 20.347 19.574 18.822 18.199 17.764 18.030 18.822 19.645 20.742 21.956 22.852 23.947 25.230 26.726 28.054 28.386 28.299 28.433 29.044 29.741 30.825 32.299 31.275 28.616 27.032 26.418 25.775 23.834 21.476 19.760 17.712 15.531 13.830 13.163 13.866 15.369 15.184 17.179 20.278 15.449 7.7944 6.7361 7.9107 16.200 33.618 39.687 58.337 100.00 91.067 36.065 9.0568 3.6526 2.3274 1.9834 1.7371 1.6670 1.8161 1.8205 1.5401 1.2870 1.5337 1.8243 1.6046 1.5941 2.5734 4.5848 4.7438 3.8166 5.1292 12.673 37.258 65.247 54.609 19.643 3.0214 1.9535 1.7496 1.8527 1.8025 1.4880 1.3496 1.3914
+END_DATA
diff --git a/ref/ClayRGB1998.icm b/ref/ClayRGB1998.icm
new file mode 100644
index 0000000..1eedf09
--- /dev/null
+++ b/ref/ClayRGB1998.icm
Binary files differ
diff --git a/ref/ColorChecker.cht b/ref/ColorChecker.cht
new file mode 100644
index 0000000..1da441b
--- /dev/null
+++ b/ref/ColorChecker.cht
@@ -0,0 +1,59 @@
+
+BOXES 25
+ F _ _ 10.0 9.75 321.25 9.75 321.26 217 10.0 217
+ D ALL ALL _ _ 330 228 0 0 0 0
+ Y 1 6 A D 46.0 46.0 12.0 11.5 52.5 52.5
+
+BOX_SHRINK 6.0
+
+REF_ROTATION 0.0
+
+XLIST 12
+ 12.0 1.0 1.0
+ 58.5 1.0 1.0
+ 64.5 1.0 1.0
+ 110.5 1.0 1.0
+ 117.0 1.0 1.0
+ 163.0 1.0 1.0
+ 169.5 1.0 1.0
+ 215.5 1.0 1.0
+ 221.5 1.0 1.0
+ 267.5 1.0 1.0
+ 274.0 1.0 1.0
+ 320.0 1.0 1.0
+
+YLIST 8
+ 11.5 1.0 1.0
+ 58.0 1.0 1.0
+ 64.0 1.0 1.0
+ 110.0 1.0 1.0
+ 116.5 1.0 1.0
+ 163.0 1.0 1.0
+ 169.0 1.0 1.0
+ 215.0 1.0 1.0
+
+EXPECTED XYZ 24
+ A1 11.773 10.213 4.9219
+ A2 40.174 36.201 20.217
+ A3 17.675 19.409 26.983
+ A4 11.121 13.530 5.5615
+ A5 25.551 24.404 34.847
+ A6 31.744 43.164 35.249
+ B1 40.056 30.947 4.8180
+ B2 12.544 11.700 28.648
+ B3 30.675 20.352 10.837
+ B4 8.3961 6.5047 10.849
+ B5 36.036 44.991 8.9494
+ B6 50.203 44.570 6.2773
+ C1 7.4590 6.0952 23.518
+ C2 15.439 23.986 7.7482
+ C3 22.850 13.022 4.1188
+ C4 59.637 60.332 7.3520
+ C5 30.450 20.015 22.947
+ C6 13.591 19.466 30.479
+ D1 86.776 90.361 70.642
+ D2 56.865 59.038 48.218
+ D3 34.763 36.036 29.378
+ D4 18.884 19.603 16.309
+ D5 8.4332 8.7464 7.1022
+ D6 3.0110 3.0971 2.5475
diff --git a/ref/ColorChecker.cie b/ref/ColorChecker.cie
new file mode 100644
index 0000000..8c78ff6
--- /dev/null
+++ b/ref/ColorChecker.cie
@@ -0,0 +1,39 @@
+IT8.7/2
+ORIGINATOR "Graeme Gill, ArgyllCMS from Gretag Macbeth reference"
+DESCRIPTOR "ColorChecker 24"
+CREATED "Feb 18, 2008"
+MANUFACTURER "X-Rite/Gretag Macbeth"
+
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+SAMPLE_ID LAB_L LAB_A LAB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 24
+BEGIN_DATA
+A01 37.99 13.56 14.06
+A02 65.71 18.13 17.81
+A03 49.93 -4.88 -21.93
+A04 43.14 -13.10 21.91
+A05 55.11 8.84 -25.40
+A06 70.72 -33.40 -0.20
+B01 62.66 36.07 57.10
+B02 40.02 10.41 -45.96
+B03 51.12 48.24 16.25
+B04 30.33 22.98 -21.59
+B05 72.53 -23.71 57.26
+B06 71.94 19.36 67.86
+C01 28.78 14.18 -50.30
+C02 55.26 -38.34 31.37
+C03 42.10 53.38 28.19
+C04 81.73 4.04 79.82
+C05 51.94 49.99 -14.57
+C06 51.04 -28.63 -28.64
+D01 96.54 -0.43 1.19
+D02 81.26 -0.64 -0.34
+D03 66.77 -0.73 -0.50
+D04 50.87 -0.15 -0.27
+D05 35.66 -0.42 -1.23
+D06 20.46 -0.08 -0.97
+END_DATA
+
diff --git a/ref/ColorChecker.ti2 b/ref/ColorChecker.ti2
new file mode 100644
index 0000000..6ede47a
--- /dev/null
+++ b/ref/ColorChecker.ti2
@@ -0,0 +1,54 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+# Standard Macbeth ColorChecker 6x4 chart, read patch by patch
+ORIGINATOR "Argyll printtarg"
+CREATED "Wed Apr 11 22:19:15 2007"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "86.776 90.361 70.642"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "6"
+KEYWORD "PASSES_IN_STRIPS2"
+PASSES_IN_STRIPS2 "4"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "A-Z, 2-9;A-X,2A-9Z"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 24
+BEGIN_DATA
+1 "A1" 0 0 0 11.773 10.213 4.9219
+2 "A2" 0 0 0 40.174 36.201 20.217
+3 "A3" 0 0 0 17.675 19.409 26.983
+4 "A4" 0 0 0 11.121 13.530 5.5615
+5 "A5" 0 0 0 25.551 24.404 34.847
+6 "A6" 0 0 0 31.744 43.164 35.249
+7 "B1" 0 0 0 40.056 30.947 4.8180
+8 "B2" 0 0 0 12.544 11.700 28.648
+9 "B3" 0 0 0 30.675 20.352 10.837
+10 "B4" 0 0 0 8.3961 6.5047 10.849
+11 "B5" 0 0 0 36.036 44.991 8.9494
+12 "B6" 0 0 0 50.203 44.570 6.2773
+13 "C1" 0 0 0 7.4590 6.0952 23.518
+14 "C2" 0 0 0 15.439 23.986 7.7482
+15 "C3" 0 0 0 22.850 13.022 4.1188
+16 "C4" 0 0 0 59.637 60.332 7.3520
+17 "C5" 0 0 0 30.450 20.015 22.947
+18 "C6" 0 0 0 13.591 19.466 30.479
+19 "D1" 0 0 0 86.776 90.361 70.642
+20 "D2" 0 0 0 56.865 59.038 48.218
+21 "D3" 0 0 0 34.763 36.036 29.378
+22 "D4" 0 0 0 18.884 19.603 16.309
+23 "D5" 0 0 0 8.4332 8.7464 7.1022
+24 "D6" 0 0 0 3.0110 3.0971 2.5475
+END_DATA
diff --git a/ref/ColorCheckerDC.cht b/ref/ColorCheckerDC.cht
new file mode 100644
index 0000000..ad7ea29
--- /dev/null
+++ b/ref/ColorCheckerDC.cht
@@ -0,0 +1,318 @@
+
+BOXES 241
+ F _ _ 26.09 18.7 330.2 18.7 330.2 202.4 26.09 202.4
+ D ALL ALL _ _ 355 216 0 0 0 0
+ X A T 01 12 12.675 12.75 27.5 20.0 15.175 15.25
+
+BOX_SHRINK 1.6
+
+XLIST 40
+ 27.5 1.0 1.0
+ 40.175 1.0 1.0
+ 42.675 1.0 1.0
+ 55.35 1.0 1.0
+ 57.85 1.0 1.0
+ 70.525 1.0 1.0
+ 73.025 1.0 1.0
+ 85.7 1.0 1.0
+ 88.2 1.0 1.0
+ 100.875 1.0 1.0
+ 103.375 1.0 1.0
+ 116.05 1.0 1.0
+ 118.55 1.0 1.0
+ 131.225 1.0 1.0
+ 133.725 1.0 1.0
+ 146.4 1.0 1.0
+ 148.9 1.0 1.0
+ 161.575 1.0 1.0
+ 164.075 1.0 1.0
+ 176.75 1.0 1.0
+ 179.25 1.0 1.0
+ 191.925 1.0 1.0
+ 194.425 1.0 1.0
+ 207.1 1.0 1.0
+ 209.6 1.0 1.0
+ 222.275 1.0 1.0
+ 224.775 1.0 1.0
+ 237.45 1.0 1.0
+ 239.95 1.0 1.0
+ 252.625 1.0 1.0
+ 255.125 1.0 1.0
+ 267.8 1.0 1.0
+ 270.3 1.0 1.0
+ 282.975 1.0 1.0
+ 285.475 1.0 1.0
+ 298.15 1.0 1.0
+ 300.65 1.0 1.0
+ 313.325 1.0 1.0
+ 315.825 1.0 1.0
+ 328.5 1.0 1.0
+
+YLIST 24
+ 20.0 1.0 1.0
+ 32.75 1.0 1.0
+ 35.25 1.0 1.0
+ 48.0 1.0 1.0
+ 50.5 1.0 1.0
+ 63.25 1.0 1.0
+ 65.75 1.0 1.0
+ 78.5 1.0 1.0
+ 81.0 1.0 1.0
+ 93.75 1.0 1.0
+ 96.25 1.0 1.0
+ 109.0 1.0 1.0
+ 111.5 1.0 1.0
+ 124.25 1.0 1.0
+ 126.75 1.0 1.0
+ 139.5 1.0 1.0
+ 142.0 1.0 1.0
+ 154.75 1.0 1.0
+ 157.25 1.0 1.0
+ 170.0 1.0 1.0
+ 172.5 1.0 1.0
+ 185.25 1.0 1.0
+ 187.75 1.0 1.0
+ 200.5 1.0 1.0
+
+EXPECTED XYZ 240
+A01 74.79 77.56 64.46
+A02 3.08 3.19 2.77
+A03 18.98 19.71 16.53
+A04 74.57 77.34 64.38
+A05 3.1 3.21 2.78
+A06 18.88 19.62 16.44
+A07 74.65 77.43 64.37
+A08 3.05 3.16 2.74
+A09 18.86 19.59 16.42
+A10 74.33 77.13 64.18
+A11 3.05 3.16 2.74
+A12 18.94 19.67 16.48
+B01 18.98 19.71 16.53
+B02 9.28 6.32 3.27
+B03 7.34 6.63 3.64
+B04 19.71 19.69 11.13
+B05 10.69 11.58 6.54
+B06 5.55 6.26 3.53
+B07 4.69 6.4 3.88
+B08 4.45 6.24 5.6
+B09 5.26 6.13 6.71
+B10 4.16 4.4 7.55
+B11 7.13 6.18 5.2
+B12 74.68 77.45 64.31
+C01 3.03 3.14 2.72
+C02 22.27 12.45 5.91
+C03 13.73 11.57 5.26
+C04 12.35 11.83 4.46
+C05 16.62 19.15 7.75
+C06 8.81 11.49 5.72
+C07 7.38 11.51 5.94
+C08 7.96 11.09 9.57
+C09 5.61 6.35 9.68
+C10 5.49 6.22 12.37
+C11 8.5 6.58 6.19
+C12 3.04 3.15 2.73
+D01 74.7 77.48 64.38
+D02 23.6 12.43 3.41
+D03 15.71 12.25 4.16
+D04 19.85 19.78 4.3
+D05 15.7 19.2 4.89
+D06 22.07 30.17 8.05
+D07 6.22 11.44 6.34
+D08 11.56 19.31 16.65
+D09 5.69 6.13 12.53
+D10 5.6 5.88 14.72
+D11 9.13 6.35 7.28
+D12 18.91 19.64 16.46
+E01 18.95 19.69 16.5
+E02 35.41 20.25 6.45
+E03 28.25 20.38 3.83
+E04 20.73 19.59 4.47
+E05 16.4 19.03 4.34
+E06 34.81 43.02 17.75
+E07 11.78 19.58 11.32
+E08 6.88 11.75 14.39
+E09 7.88 11.31 19.64
+E10 9.22 11.09 27.08
+E11 17.84 11.47 13.98
+E12 74.56 77.32 64.24
+F01 3.04 3.15 2.73
+F02 48.3 30.25 11.41
+F03 16.14 10.93 3.9
+F04 31.33 29.91 8.52
+F05 14.11 18.71 6.4
+F06 38.16 43.99 9.51
+F07 10.52 19.33 8.14
+F08 7.96 11.49 16.13
+F09 8.63 11.3 17.86
+F10 10.41 11.24 27.64
+F11 21.49 12.15 9.52
+F12 3.04 3.15 2.73
+G01 74.73 77.5 64.38
+G02 44.51 29.8 15.52
+G03 24.34 19.34 8.11
+G04 25.26 19.88 4.38
+G05 13.65 19.52 4.62
+G06 36.49 43.18 5.73
+G07 19.42 29.58 14.51
+G08 19.86 28.9 37.67
+G09 14.15 18.75 25.13
+G10 10.69 11.62 23.13
+G11 31.57 19.76 17.91
+G12 18.91 19.64 16.46
+H01 18.98 19.71 16.53
+H02 33.5 20.33 9.91
+H03 34.67 28.65 13.17
+H04 16.86 12.12 2.75
+H05 21.16 30.06 6.66
+H06 52.08 58.65 19.39
+H07 22.63 29.16 10.83
+H08 21.74 29.15 34.08
+H09 13.59 18.65 33.2
+H10 17.32 18.86 39.16
+H11 29.3 19.82 17.88
+H12 74.65 77.41 64.27
+I01 3.05 3.16 2.74
+I02 22.03 19.1 15.09
+I03 31.97 28.79 15.9
+I04 42.69 29.41 6.24
+I05 82.21 85.41 69.86
+I06 30.96 32.15 26.58
+I07 16.49 17.18 14.34
+I08 7.03 7.28 6.15
+I09 24.91 29.34 38.48
+I10 29.04 29.31 45.2
+I11 41.09 29.82 26.18
+I12 3.05 3.16 2.75
+J01 74.72 77.5 64.44
+J02 26.91 19.35 14.94
+J03 34.54 29.66 11.16
+J04 58.1 42.93 8.71
+J05 64.14 66.75 54.99
+J06 87.06 90.39 72.76
+J07 86.82 90.15 72.56
+J08 4.28 4.47 3.84
+J09 24.87 28.59 45.17
+J10 41.47 42.2 57.7
+J11 53.38 42.55 36.49
+J12 18.92 19.65 16.47
+K01 18.97 19.7 16.52
+K02 36.7 29.69 19.45
+K03 36.83 30.22 8.83
+K04 53.42 43.05 10.13
+K05 51.78 53.86 44.86
+K06 86.85 90.18 72.55
+K07 86.91 90.25 72.64
+K08 3.45 3.59 3.07
+K09 21.49 28.73 46.46
+K10 21.85 19.42 36.39
+K11 32.48 29.05 24.22
+K12 74.63 77.39 64.28
+L01 3.03 3.14 2.73
+L02 53.85 42.1 29.27
+L03 58.21 42.93 21.15
+L04 40.96 30.79 3.87
+L05 40.79 42.45 35.04
+L06 23.51 24.47 20.31
+L07 11.1 11.62 9.8
+L08 3.02 3.13 2.71
+L09 31.86 41.84 53.57
+L10 7.9 6.16 10.17
+L11 62.34 57.68 47.93
+L12 3.03 3.14 2.72
+M01 74.74 77.52 64.43
+M02 68.21 58.76 45.3
+M03 54.32 42.79 26.91
+M04 68.17 58.65 13.41
+M05 76.51 80.88 14.08
+M06 15.06 19.36 18.82
+M07 16.03 29.31 11.79
+M08 52.05 57.11 51.73
+M09 32.54 42.52 46.33
+M10 7.2 6.19 8.57
+M11 78.01 78.48 67.07
+M12 18.93 19.67 16.48
+N01 18.97 19.7 16.51
+N02 65.97 60.13 42.01
+N03 50.5 42.33 28.58
+N04 63.78 59.07 15.95
+N05 62.58 58.72 7.2
+N06 21.33 29.57 29.73
+N07 17.06 29.9 17.13
+N08 54.05 58.63 61.58
+N09 49.41 57.82 58.22
+N10 16.9 12.02 19.29
+N11 41.76 29.82 32.52
+N12 74.67 77.43 64.28
+O01 3.02 3.13 2.71
+O02 47.1 42.51 31.08
+O03 51.87 42.51 15.81
+O04 77.2 77.91 50.55
+O05 45.99 42.6 4.49
+O06 23.64 29.5 29.06
+O07 26.97 42.73 19.28
+O08 27.97 29.35 28.33
+O09 50.32 57.45 48.38
+O10 23.06 19.58 23.21
+O11 32.18 29.25 34.95
+O12 3.01 3.12 2.7
+P01 74.64 77.41 64.32
+P02 44.39 42.98 33.4
+P03 71.49 59.42 23.1
+P04 79.86 78.26 38.44
+P05 31.59 29.6 5.37
+P06 20.07 28.76 23.92
+P07 31.22 42.07 27.31
+P08 17.15 18.99 23.19
+P09 37.97 42.95 38.15
+P10 19.91 19.24 17.99
+P11 44.36 43.41 45.48
+P12 18.95 19.68 16.49
+Q01 18.96 19.69 16.51
+Q02 59.99 58.87 41.85
+Q03 67.98 58.85 30.96
+Q04 82.15 79.03 48.34
+Q05 33.18 29.48 5.74
+Q06 18.92 29.39 27.97
+Q07 44.1 58.65 39.14
+Q08 37.51 41.38 26.69
+Q09 40.27 42.04 17.38
+Q10 24.86 28.48 22.3
+Q11 9.43 11.28 9.5
+Q12 74.61 77.37 64.24
+R01 3.05 3.16 2.74
+R02 31.16 30.09 20.86
+R03 56.92 56.98 36.53
+R04 79.37 78.57 56.95
+R05 42.68 42.54 8.26
+R06 28.15 41.91 31.53
+R07 48.61 58.02 33.46
+R08 26.81 28.91 16.95
+R09 39.83 43.08 12.47
+R10 11.8 11.72 5.87
+R11 17.1 19.71 16.41
+R12 3.02 3.13 2.71
+S01 74.66 77.43 64.34
+S02 40.67 42.42 26.09
+S03 65.09 68.67 41.71
+S04 3.01 3.34 15.4
+S05 3.26 11.22 2.89
+S06 17.7 8.11 0.42
+S07 89.01 92.27 74.63
+S08 0.28 0.29 0.24
+S09 72.92 74.82 4.56
+S10 17.03 7.57 3.05
+S11 6.56 11.29 24.29
+S12 18.91 19.64 16.46
+T01 18.91 19.64 16.46
+T02 3.05 3.16 2.73
+T03 74.38 77.15 64.2
+T04 18.94 19.68 16.48
+T05 3.12 3.24 2.79
+T06 74.2 76.97 63.98
+T07 18.87 19.61 16.43
+T08 3.04 3.16 2.73
+T09 74.41 77.19 64.05
+T10 18.9 19.63 16.46
+T11 3.09 3.2 2.78
+T12 74.57 77.32 64.19
+
diff --git a/ref/ColorCheckerPassport.cht b/ref/ColorCheckerPassport.cht
new file mode 100644
index 0000000..758cad7
--- /dev/null
+++ b/ref/ColorCheckerPassport.cht
@@ -0,0 +1,122 @@
+BOXES 51
+ F _ _ 97.0 17.0 157.3 17.0 157.3 107.0 97.0 107.0
+ D ALL ALL _ _ 59.0 5.0 98.0 11.0 0.0 0.0
+ X SAT SAT 1 8 10.0 10.0 13.5 102.1 0.0 -12.9
+ X WBP WBP 1 5 13.4 13.4 26.4 87.0 0.0 -16.0
+ X WBL WBL 1 5 13.4 13.4 42.5 87.0 0.0 -16.0
+ X NEU NEU 1 8 10.0 10.0 58.6 102.1 0.0 -12.9
+ X A D 1 6 12.4 12.4 98.5 93.4 15.0 -15.0
+
+BOX_SHRINK 2.0
+
+REF_ROTATION 0.0
+
+XLIST 16
+ 13.5 1.0 1.0
+ 23.5 1.0 1.0
+ 26.4 1.0 1.0
+ 39.8 1.0 1.0
+ 42.5 1.0 1.0
+ 55.9 1.0 1.0
+ 58.6 1.0 1.0
+ 68.6 1.0 1.0
+ 98.5 1.0 1.0
+ 110.9 1.0 1.0
+ 113.5 1.0 1.0
+ 125.9 1.0 1.0
+ 128.5 1.0 1.0
+ 140.9 1.0 1.0
+ 143.5 1.0 1.0
+ 155.9 1.0 1.0
+
+YLIST 38
+ 11.5 1.0 1.0
+ 18.5 1.0 1.0
+ 21.6 1.0 1.0
+ 23.4 1.0 1.0
+ 24.3 1.0 1.0
+ 30.9 1.0 1.0
+ 33.5 1.0 1.0
+ 34.6 1.0 1.0
+ 36.5 1.0 1.0
+ 37.2 1.0 1.0
+ 39.2 1.0 1.0
+ 45.8 1.0 1.0
+ 47.5 1.0 1.0
+ 48.4 1.0 1.0
+ 50.2 1.0 1.0
+ 52.5 1.0 1.0
+ 55.2 1.0 1.0
+ 60.4 1.0 1.0
+ 60.7 1.0 1.0
+ 63.1 1.0 1.0
+ 63.4 1.0 1.0
+ 68.4 1.0 1.0
+ 71.1 1.0 1.0
+ 73.3 1.0 1.0
+ 75.7 1.0 1.0
+ 76.1 1.0 1.0
+ 78.4 1.0 1.0
+ 84.3 1.0 1.0
+ 86.3 1.0 1.0
+ 87.0 1.0 1.0
+ 89.0 1.0 1.0
+ 90.6 1.0 1.0
+ 93.4 1.0 1.0
+ 99.4 1.0 1.0
+ 100.4 1.0 1.0
+ 102.1 1.0 1.0
+ 105.7 1.0 1.0
+ 112.4 1.0 1.0
+
+EXPECTED XYZ
+SAT1 31.444334 19.286094 6.888559
+SAT2 56.064662 44.030373 6.427599
+SAT3 67.324242 67.447159 7.468562
+SAT4 15.570651 29.465796 11.20434
+SAT5 21.619963 29.778971 41.25516
+SAT6 17.456572 19.372800 46.61877
+SAT7 24.114288 18.910816 30.96444
+SAT8 30.360635 18.858573 16.93814
+WBP1 55.603171 57.729295 46.42132
+WBP2 57.049606 60.324512 49.89966
+WBP3 53.811668 58.177050 49.42470
+WBP4 52.378305 57.343255 49.64556
+WBP5 52.469763 58.680177 51.97625
+WBL1 59.661034 59.332741 48.55177
+WBL2 59.041480 59.368909 48.29234
+WBL3 55.920447 58.052670 47.03935
+WBL4 55.083575 58.526581 51.10275
+WBL5 53.892264 58.200472 53.59833
+NEU1 3.151107 3.263644 2.737095
+NEU2 3.610326 3.768524 3.225077
+NEU3 4.585675 4.814770 4.063276
+NEU4 5.242110 5.523981 4.582603
+NEU5 44.365128 46.364955 37.75652
+NEU6 55.836099 58.281967 47.53593
+NEU7 70.627230 73.603361 59.69403
+NEU8 88.638466 92.368156 71.51666
+A1 11.411919 10.072672 5.112897
+A2 38.118655 34.074205 18.53409
+A3 16.687521 18.224488 25.41503
+A4 11.119565 13.272712 5.165291
+A5 23.995041 23.022599 32.25695
+A6 29.864887 41.242607 33.61720
+B1 40.774497 30.980646 4.853984
+B2 12.786912 11.654674 29.31582
+B3 29.900282 19.631992 10.31426
+B4 8.854344 6.750602 10.88177
+B5 35.445183 44.094908 8.863355
+B6 49.113465 43.647237 6.214123
+C1 6.659992 5.799339 20.11315
+C2 15.407588 23.700772 7.772715
+C3 21.254733 12.710445 3.970060
+C4 58.616280 59.203678 6.871706
+C5 31.444170 20.458848 23.34756
+C6 13.290512 19.046913 29.20373
+D1 87.016740 90.636247 69.99650
+D2 57.632418 59.860806 48.52846
+D3 35.434916 36.927843 30.23039
+D4 18.558911 19.319142 15.73822
+D5 8.770657 9.165214 7.636996
+D6 3.216922 3.320339 2.732945
diff --git a/ref/ColorCheckerPassport.cie b/ref/ColorCheckerPassport.cie
new file mode 100644
index 0000000..f25c019
--- /dev/null
+++ b/ref/ColorCheckerPassport.cie
@@ -0,0 +1,64 @@
+CTI3
+DESCRIPTOR "ColorChecker Passport CIE data"
+ORIGINATOR "Ben Goren <ben@trumpetpower.com>"
+CREATED "Fri Aug 3 15:35:05 MST 2012"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 7
+BEGIN_DATA_FORMAT
+SAMPLE_LOC XYZ_X XYZ_Y XYZ_Z LAB_L LAB_A LAB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 50
+BEGIN_DATA
+SAT1 31.444334 19.286094 6.888559 51.020256 55.280672 28.133194
+SAT2 56.064662 44.030373 6.427599 72.248793 36.945117 66.729238
+SAT3 67.324242 67.447159 7.468562 85.729258 5.091307 85.588609
+SAT4 15.570651 29.465796 11.204340 61.190534 -60.437314 30.279584
+SAT5 21.619963 29.778971 41.255169 61.463043 -30.131006 -25.196180
+SAT6 17.456572 19.372800 46.618774 51.120542 -6.455450 -49.629615
+SAT7 24.114288 18.910816 30.964446 50.582702 28.026310 -29.474885
+SAT8 30.360635 18.858573 16.938149 50.521331 53.431168 -3.299773
+WBP1 55.603171 57.729295 46.421327 80.588052 -0.148185 1.410213
+WBP2 57.049606 60.324512 49.899666 82.014259 -2.717710 -0.156044
+WBP3 53.811668 58.177050 49.424708 80.837125 -5.740350 -1.647214
+WBP4 52.378305 57.343255 49.645561 80.372273 -7.424711 -2.699450
+WBP5 52.469763 58.680177 51.976257 81.115480 -10.390873 -4.020205
+WBL1 59.661034 59.332741 48.551776 81.474151 5.919789 0.449649
+WBL2 59.041480 59.368909 48.292349 81.493953 4.354460 0.782852
+WBL3 55.920447 58.052670 47.039351 80.768065 -0.134018 0.991035
+WBL4 55.083575 58.526581 51.102758 81.030672 -3.356452 -3.200486
+WBL5 53.892264 58.200472 53.598335 80.850119 -5.590938 -6.243136
+NEU1 3.151107 3.263644 2.737095 21.070257 0.072763 -0.353478
+NEU2 3.610326 3.768524 3.225077 22.890939 -0.358852 -0.826826
+NEU3 4.585675 4.814770 4.063276 26.200395 -0.743922 -0.554941
+NEU4 5.242110 5.523981 4.582603 28.178271 -1.007717 -0.143878
+NEU5 44.365128 46.364955 37.756524 73.781723 -0.983457 0.663808
+NEU6 55.836099 58.281967 47.535933 80.895303 -0.892210 0.628840
+NEU7 70.627230 73.603361 59.694037 88.734687 -0.724494 1.018307
+NEU8 88.638466 92.368156 71.516660 96.970594 -0.771975 4.070471
+A1 11.411919 10.072672 5.112897 37.972545 12.849750 13.905933
+A2 38.118655 34.074205 18.534096 65.021429 17.736538 18.105244
+A3 16.687521 18.224488 25.415039 49.767263 -4.838656 -21.688821
+A4 11.119565 13.272712 5.165291 43.171313 -11.673243 22.599880
+A5 23.995041 23.022599 32.256955 55.095608 8.054000 -23.674108
+A6 29.864887 41.242607 33.617201 70.345563 -33.879730 0.591375
+B1 40.774497 30.980646 4.853984 62.491292 36.974257 57.538878
+B2 12.786912 11.654674 29.315826 40.661930 10.745627 -43.972357
+B3 29.900282 19.631992 10.314269 51.418556 47.835790 16.229131
+B4 8.854344 6.750602 10.881778 31.232269 21.992198 -20.376399
+B5 35.445183 44.094908 8.863355 72.291888 -22.389553 57.145982
+B6 49.113465 43.647237 6.214123 71.992078 20.037754 67.243006
+C1 6.659992 5.799339 20.113152 28.900464 11.613838 -47.531575
+C2 15.407588 23.700772 7.772715 55.786947 -38.099805 32.761011
+C3 21.254733 12.710445 3.970060 42.323678 50.646029 27.808803
+C4 58.616280 59.203678 6.871706 81.403423 3.722966 80.589317
+C5 31.444170 20.458848 23.347563 52.352077 49.539466 -13.465303
+C6 13.290512 19.046913 29.203736 50.742046 -29.398805 -26.412062
+D1 87.016740 90.636247 69.996509 96.260066 -0.692605 4.206323
+D2 57.632418 59.860806 48.528468 81.762472 -0.207864 0.973581
+D3 35.434916 36.927843 30.230398 67.222860 -0.574879 0.364223
+D4 18.558911 19.319142 15.738222 51.058515 -0.355289 0.481164
+D5 8.770657 9.165214 7.636996 36.300462 -0.566396 -0.303560
+D6 3.216922 3.320339 2.732945 21.283684 0.258119 0.046995
+END_DATA
diff --git a/ref/ColorCheckerSG.cht b/ref/ColorCheckerSG.cht
new file mode 100644
index 0000000..1836f73
--- /dev/null
+++ b/ref/ColorCheckerSG.cht
@@ -0,0 +1,203 @@
+
+BOXES 141
+ F _ _ 26.09 18.7 239.15 18.7 239.15 171.9 26.09 171.9
+ D ALL ALL _ _ 263.95 185.5 0 0 0 0
+ X A N 1 10 12.675 12.75 27.5 20.0 15.175 15.25
+
+BOX_SHRINK 1.6
+
+XLIST 28
+ 27.5 1.0 1.0
+ 40.175 1.0 1.0
+ 42.675 1.0 1.0
+ 55.35 1.0 1.0
+ 57.85 1.0 1.0
+ 70.525 1.0 1.0
+ 73.025 1.0 1.0
+ 85.7 1.0 1.0
+ 88.2 1.0 1.0
+ 100.875 1.0 1.0
+ 103.375 1.0 1.0
+ 116.05 1.0 1.0
+ 118.55 1.0 1.0
+ 131.225 1.0 1.0
+ 133.725 1.0 1.0
+ 146.4 1.0 1.0
+ 148.9 1.0 1.0
+ 161.575 1.0 1.0
+ 164.075 1.0 1.0
+ 176.75 1.0 1.0
+ 179.25 1.0 1.0
+ 191.925 1.0 1.0
+ 194.425 1.0 1.0
+ 207.1 1.0 1.0
+ 209.6 1.0 1.0
+ 222.275 1.0 1.0
+ 224.775 1.0 1.0
+ 237.45 1.0 1.0
+
+YLIST 20
+ 20.0 1.0 1.0
+ 32.75 1.0 1.0
+ 35.25 1.0 1.0
+ 48.0 1.0 1.0
+ 50.5 1.0 1.0
+ 63.25 1.0 1.0
+ 65.75 1.0 1.0
+ 78.5 1.0 1.0
+ 81.0 1.0 1.0
+ 93.75 1.0 1.0
+ 96.25 1.0 1.0
+ 109.0 1.0 1.0
+ 111.5 1.0 1.0
+ 124.25 1.0 1.0
+ 126.75 1.0 1.0
+ 139.5 1.0 1.0
+ 142.0 1.0 1.0
+ 154.75 1.0 1.0
+ 157.25 1.0 1.0
+ 170.0 1.0 1.0
+
+
+EXPECTED XYZ 140
+ A1 88.25 87.51 67.62
+ A2 0.79 0.79 0.62
+ A3 18.38 18.15 14.12
+ A4 88.68 87.94 68.1
+ A5 0.82 0.81 0.66
+ A6 18.44 18.2 14.18
+ A7 88.65 87.9 67.95
+ A8 0.83 0.82 0.66
+ A9 18.12 17.89 13.95
+ A10 88.87 88.13 68.08
+ B1 18.02 17.8 13.91
+ B2 13.95 7.23 8.27
+ B3 35.63 27.85 32.84
+ B4 10.67 5.28 15.25
+ B5 14.41 15.79 39.4
+ B6 20.68 26.24 36.89
+ B7 1.45 2.35 2.56
+ B8 18.04 25.72 27.04
+ B9 3.38 3.27 1.58
+ B10 18.48 18.24 14.19
+ C1 0.83 0.81 0.66
+ C2 4.58 3.29 5.62
+ C3 14.6 11.31 24.29
+ C4 2.74 2.49 8.91
+ C5 22.92 25.79 40.25
+ C6 1.84 2.4 5.03
+ C7 26.45 26.69 42.35
+ C8 10.25 16.92 17.28
+ C9 19.05 27.21 12.27
+ C10 0.81 0.8 0.64
+ D1 88.5 87.75 67.91
+ D2 61.95 61.45 55.8
+ D3 70.83 63.53 49.33
+ D4 55.96 62.69 49.91
+ D5 71.17 64.56 44.57
+ D6 58.43 62.22 28.86
+ D7 38.57 30.13 8.72
+ D8 38.93 32.31 15.64
+ D9 9.71 17.25 8.69
+ D10 88.85 88.1 68.15
+ E1 18.14 17.91 13.97
+ E2 8.92 6.95 2.01
+ E3 39.66 29.42 2.06
+ E4 3.85 2.22 16.31
+ E5 88.54 87.8 67.91
+ E6 0.8 0.79 0.64
+ E7 57.95 50.11 24.14
+ E8 55.65 45.09 20.47
+ E9 1.8 2.87 1.55
+ E10 18.29 18.05 14.05
+ F1 0.82 0.81 0.65
+ F2 37.55 31.16 14.86
+ F3 9.34 7.46 25.35
+ F4 12.16 19.3 4.13
+ F5 54.56 53.71 42.14
+ F6 6.41 6.34 5.07
+ F7 35.94 31.61 12.54
+ F8 37.12 32.69 16.79
+ F9 17.63 26.21 16.52
+ F10 0.82 0.8 0.65
+ G1 88.12 87.38 67.64
+ G2 14.14 14.42 21.78
+ G3 27.07 16.15 6.53
+ G4 19.38 9.32 1.23
+ G5 33.43 32.97 25.94
+ G6 11.06 10.95 8.66
+ G7 16.15 13.52 3.95
+ G8 37.66 32.45 16.85
+ G9 21.4 28.64 6.94
+ G10 88.76 88.01 68.03
+ H1 18.23 18 14.03
+ H2 7.94 10.03 2.21
+ H3 5.33 3.13 7.61
+ H4 58.28 57.39 3.84
+ H5 18.06 17.83 13.93
+ H6 27.87 27.48 21.66
+ H7 40.98 36.13 18.85
+ H8 38.13 32.77 16.09
+ H9 10.91 18.91 3.26
+ H10 18.32 18.08 14.08
+ I1 0.88 0.87 0.69
+ I2 20.96 18.51 28.03
+ I3 33.58 40.91 5.29
+ I4 28.76 16.58 19.42
+ I5 8.34 8.25 6.47
+ I6 47.53 46.8 36.74
+ I7 18.56 14.28 2.54
+ I8 10.92 8.92 2.27
+ I9 17.44 28.57 5.55
+ I10 0.82 0.81 0.65
+ J1 88.45 87.71 67.89
+ J2 28.25 36.79 28.98
+ J3 46.48 40.82 3.05
+ J4 10.73 14.67 25.45
+ J5 1.95 1.94 1.63
+ J6 72.43 71.6 56.6
+ J7 39 31.84 12.66
+ J8 41.29 34.62 13.36
+ J9 34.26 30.19 5.4
+ J10 88.69 87.94 67.95
+ K1 18.29 18.06 14.09
+ K2 69.8 64.78 36.61
+ K3 65.69 71.95 50.54
+ K4 65.74 62.36 54.38
+ K5 56.64 60.89 55.78
+ K6 40.88 40.32 31.77
+ K7 14.74 14.56 11.28
+ K8 2.93 2.89 2.29
+ K9 26.26 30.23 4.54
+ K10 18.27 18.04 14.06
+ L1 0.86 0.85 0.69
+ L2 6.16 3.5 1.81
+ L3 26.34 13.44 1.4
+ L4 38.55 28.09 19.93
+ L5 39.77 29.23 14.66
+ L6 46.55 31.09 1.68
+ L7 40.32 44.89 2.28
+ L8 30.88 30.54 4.31
+ L9 34.35 43.52 4.2
+ L10 0.8 0.79 0.64
+ M1 18.19 17.97 14.01
+ M2 23.95 12.47 6.9
+ M3 4.92 2.88 3.25
+ M4 22.84 11.31 2.24
+ M5 37.86 20.94 3.23
+ M6 68.62 59.75 4.77
+ M7 62.14 60.57 3.46
+ M8 36.4 42.08 3.08
+ M9 3.85 2.98 0.82
+ M10 18.24 18.01 14.03
+ N1 88.23 87.51 67.77
+ N2 18.24 18.01 14.03
+ N3 0.9 0.89 0.72
+ N4 88.57 87.82 67.97
+ N5 18.12 17.9 13.96
+ N6 0.91 0.9 0.73
+ N7 88.71 87.96 67.97
+ N8 18.2 17.97 14
+ N9 0.84 0.83 0.67
+ N10 88.82 88.07 68.12
+
diff --git a/ref/D50_0.0.sp b/ref/D50_0.0.sp
new file mode 100644
index 0000000..8904fca
--- /dev/null
+++ b/ref/D50_0.0.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 0% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 25.0 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_0.1.sp b/ref/D50_0.1.sp
new file mode 100644
index 0000000..ad747fb
--- /dev/null
+++ b/ref/D50_0.1.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 0% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.45 5.44 11.95 23.75 39.45 47.62 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_0.3.sp b/ref/D50_0.3.sp
new file mode 100644
index 0000000..1a64a27
--- /dev/null
+++ b/ref/D50_0.3.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 30% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.01 0.31 0.62 1.47 2.33 3.38 4.43 4.91 5.39 5.84 6.3 6.74 7.18 7.64 8.09 7.72 9.06 11.96 17.32 28.5 42.41 49.21 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_0.5.sp b/ref/D50_0.5.sp
new file mode 100644
index 0000000..367d0d3
--- /dev/null
+++ b/ref/D50_0.5.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 50% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.01 0.52 1.03 2.46 3.89 5.63 7.38 8.18 8.98 9.74 10.51 11.24 11.97 12.73 13.48 12.86 13.47 16.31 20.91 31.67 44.38 50.26 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_0.7.sp b/ref/D50_0.7.sp
new file mode 100644
index 0000000..2e0b2e8
--- /dev/null
+++ b/ref/D50_0.7.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 70% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.01 0.72 1.44 3.44 5.45 7.88 10.33 11.45 12.57 13.64 14.71 15.74 16.76 17.82 18.87 18 17.88 20.66 24.49 34.84 46.35 51.32 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_1.0.sp b/ref/D50_1.0.sp
new file mode 100644
index 0000000..d74e76a
--- /dev/null
+++ b/ref/D50_1.0.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, Standard U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.020000 1.0300 2.0500 4.9100 7.7800 11.260 14.750 16.350 17.950 19.480 21.010 22.480 23.940 25.450 26.960 25.720 24.490 27.180 29.870 39.590 49.310 52.910 56.510 58.270 60.030 58.930 57.820 66.320 74.820 81.040 87.250 88.930 90.610 90.990 91.370 93.240 95.110 93.540 91.960 93.840 95.720 96.170 96.610 96.870 97.130 99.610 102.10 101.43 100.75 101.54 102.32 101.16 100.00 98.870 97.740 98.330 98.920 96.210 93.500 95.590 97.690 98.480 99.270 99.160 99.040 97.380 95.720 97.290 98.860 97.260 95.670 96.930 98.190 100.60 103.00 101.07 99.130 93.260 87.380 89.490 91.600 92.250 92.890 84.870 76.850 81.680 86.510 89.550 92.580 85.400 78.230 67.960 57.690 70.310 82.920 80.600 78.270 78.910 79.550 76.480 73.400 68.660 63.920 67.350 70.780 72.610 74.440
+END_DATA
diff --git a/ref/D50_1.2.sp b/ref/D50_1.2.sp
new file mode 100644
index 0000000..180d650
--- /dev/null
+++ b/ref/D50_1.2.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 120% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.02 1.24 2.46 5.89 9.34 13.51 17.7 19.62 21.54 23.38 25.21 26.98 28.73 30.54 32.35 30.86 28.9 31.53 33.45 42.76 51.28 53.97 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_1.5.sp b/ref/D50_1.5.sp
new file mode 100644
index 0000000..786e292
--- /dev/null
+++ b/ref/D50_1.5.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 150% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.03 1.55 3.08 7.37 11.67 16.89 22.13 24.53 26.93 29.22 31.52 33.72 35.91 38.18 40.44 38.58 35.51 38.05 38.83 47.51 54.24 55.56 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_1.7.sp b/ref/D50_1.7.sp
new file mode 100644
index 0000000..ba8dc6b
--- /dev/null
+++ b/ref/D50_1.7.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 170% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.03 1.75 3.49 8.35 13.23 19.14 25.08 27.8 30.52 33.12 35.72 38.22 40.7 43.27 45.83 43.72 39.92 42.4 42.42 50.68 56.21 56.61 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_2.0.sp b/ref/D50_2.0.sp
new file mode 100644
index 0000000..efa0214
--- /dev/null
+++ b/ref/D50_2.0.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 200% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.04 2.06 4.1 9.82 15.56 22.52 29.5 32.7 35.9 38.96 42.02 44.96 47.88 50.9 53.92 51.44 46.53 48.92 47.79 55.43 59.17 58.2 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_2.5.sp b/ref/D50_2.5.sp
new file mode 100644
index 0000000..8057f14
--- /dev/null
+++ b/ref/D50_2.5.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 250% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.05 2.58 5.13 12.28 19.45 28.15 36.88 40.88 44.88 48.7 52.53 56.2 59.85 63.63 67.4 64.3 57.55 59.8 56.75 63.34 64.1 60.85 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/D50_3.0.sp b/ref/D50_3.0.sp
new file mode 100644
index 0000000..e68d891
--- /dev/null
+++ b/ref/D50_3.0.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll D50 illimunant spectral power, 300% U.V."
+
+ORIGINATOR "Argyll CMS"
+
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.06 3.09 6.15 14.73 23.34 33.78 44.25 49.05 53.85 58.44 63.03 67.44 71.82 76.35 80.88 77.16 68.57 70.67 65.71 71.26 69.03 63.49 56.51 58.27 60.03 58.93 57.82 66.32 74.82 81.04 87.25 88.93 90.61 90.99 91.37 93.24 95.11 93.54 91.96 93.84 95.72 96.17 96.61 96.87 97.13 99.61 102.1 101.43 100.75 101.54 102.32 101.16 100.0 98.87 97.74 98.33 98.92 96.21 93.5 95.59 97.69 98.48 99.27 99.16 99.04 97.38 95.72 97.29 98.86 97.26 95.67 96.93 98.19 100.6 103.0 101.07 99.13 93.26 87.38 89.49 91.6 92.25 92.89 84.87 76.85 81.68 86.51 89.55 92.58 85.4 78.23 67.96 57.69 70.31 82.92 80.6 78.27 78.91 79.55 76.48 73.4 68.66 63.92 67.35 70.78 72.61 74.44
+END_DATA
diff --git a/ref/ECI2002.ti2 b/ref/ECI2002.ti2
new file mode 100644
index 0000000..0ab3095
--- /dev/null
+++ b/ref/ECI2002.ti2
@@ -0,0 +1,1578 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+ORIGINATOR "Argyll printtarg"
+CREATED "Mon Oct 11 11:50:06 2010"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "Xrite DTP41"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "86.886812 89.830019 77.951670"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+KEYWORD "RANDOM_START"
+RANDOM_START "1251"
+KEYWORD "PATCH_LENGTH"
+PATCH_LENGTH "7.366000"
+KEYWORD "GAP_LENGTH"
+GAP_LENGTH "2.032000"
+KEYWORD "TRAILER_LENGTH"
+TRAILER_LENGTH "18.796000"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "57"
+KEYWORD "PASSES_IN_STRIPS2"
+PASSES_IN_STRIPS2 "8,8,8,3"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "A-Z, A-Z"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+KEYWORD "INDEX_ORDER"
+INDEX_ORDER "STRIP_THEN_PATCH"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1539
+BEGIN_DATA
+1 "K18" 0.0000 0.0000 0.0000 0.0000 82.670 85.770 75.100
+2 "C42" 0.0000 10.196 0.0000 0.0000 75.440 75.210 67.360
+3 "H41" 0.0000 20.000 0.0000 0.0000 68.390 65.250 59.520
+4 "J28" 0.0000 29.804 0.0000 0.0000 61.730 55.910 51.990
+5 "P43" 0.0000 40.000 0.0000 0.0000 55.570 47.360 44.900
+6 "P52" 0.0000 54.902 0.0000 0.0000 47.430 36.190 34.970
+7 "Q3" 0.0000 70.196 0.0000 0.0000 40.640 27.330 26.760
+8 "C3" 0.0000 85.098 0.0000 0.0000 36.010 21.120 20.750
+9 "O41" 0.0000 100.00 0.0000 0.0000 32.280 16.480 15.950
+10 "R55" 10.196 0.0000 0.0000 0.0000 74.060 78.380 73.130
+11 "V5" 10.196 10.196 0.0000 0.0000 67.440 68.580 65.650
+12 "R5" 10.196 20.000 0.0000 0.0000 61.180 59.530 58.060
+13 "L34" 10.196 29.804 0.0000 0.0000 55.110 50.870 50.710
+14 "G34" 10.196 40.000 0.0000 0.0000 49.460 42.920 43.790
+15 "B38" 10.196 54.902 0.0000 0.0000 42.150 32.700 34.170
+16 "A44" 10.196 70.196 0.0000 0.0000 36.060 24.630 26.220
+17 "S11" 10.196 85.098 0.0000 0.0000 31.880 18.960 20.420
+18 "X39" 10.196 100.00 0.0000 0.0000 28.510 14.710 15.790
+19 "R40" 20.000 0.0000 0.0000 0.0000 65.080 70.510 71.060
+20 "R31" 20.000 10.196 0.0000 0.0000 59.420 61.860 63.940
+21 "S5" 20.000 20.000 0.0000 0.0000 54.000 53.760 56.770
+22 "N37" 20.000 29.804 0.0000 0.0000 48.570 45.890 49.620
+23 "X57" 20.000 40.000 0.0000 0.0000 43.490 38.650 42.860
+24 "Y52" 20.000 54.902 0.0000 0.0000 36.980 29.400 33.560
+25 "D13" 20.000 70.196 0.0000 0.0000 31.560 22.080 25.870
+26 "Q15" 20.000 85.098 0.0000 0.0000 27.790 16.870 20.230
+27 "A15" 20.000 100.00 0.0000 0.0000 24.730 12.950 15.700
+28 "W20" 29.804 0.0000 0.0000 0.0000 56.270 62.660 68.950
+29 "AA44" 29.804 10.196 0.0000 0.0000 51.330 54.930 61.980
+30 "A43" 29.804 20.000 0.0000 0.0000 46.640 47.710 55.080
+31 "C45" 29.804 29.804 0.0000 0.0000 41.990 40.770 48.310
+32 "Z39" 29.804 40.000 0.0000 0.0000 37.620 34.380 41.870
+33 "V30" 29.804 54.902 0.0000 0.0000 31.960 26.120 32.880
+34 "H33" 29.804 70.196 0.0000 0.0000 27.230 19.560 25.440
+35 "C23" 29.804 85.098 0.0000 0.0000 23.930 14.880 20.050
+36 "Y49" 29.804 100.00 0.0000 0.0000 21.240 11.340 15.730
+37 "Z50" 40.000 0.0000 0.0000 0.0000 48.240 55.380 66.850
+38 "L20" 40.000 10.196 0.0000 0.0000 43.880 48.440 60.010
+39 "K41" 40.000 20.000 0.0000 0.0000 39.840 42.020 53.330
+40 "F1" 40.000 29.804 0.0000 0.0000 35.910 35.950 46.930
+41 "S55" 40.000 40.000 0.0000 0.0000 32.220 30.360 40.840
+42 "B10" 40.000 54.902 0.0000 0.0000 27.350 23.050 32.190
+43 "N30" 40.000 70.196 0.0000 0.0000 23.270 17.220 25.020
+44 "T4" 40.000 85.098 0.0000 0.0000 20.410 13.050 19.880
+45 "I25" 40.000 100.00 0.0000 0.0000 18.080 9.9000 15.760
+46 "G17" 54.902 0.0000 0.0000 0.0000 38.030 45.930 63.790
+47 "D2" 54.902 10.196 0.0000 0.0000 34.510 40.110 57.320
+48 "B52" 54.902 20.000 0.0000 0.0000 31.280 34.770 51.060
+49 "K1" 54.902 29.804 0.0000 0.0000 28.140 29.700 44.980
+50 "O42" 54.902 40.000 0.0000 0.0000 25.220 25.070 39.230
+51 "Z36" 54.902 54.902 0.0000 0.0000 21.420 19.070 31.290
+52 "F13" 54.902 70.196 0.0000 0.0000 18.220 14.260 24.660
+53 "P32" 54.902 85.098 0.0000 0.0000 15.880 10.710 19.720
+54 "Y57" 54.902 100.00 0.0000 0.0000 13.940 7.9900 15.690
+55 "K51" 70.196 0.0000 0.0000 0.0000 29.450 37.760 60.910
+56 "T57" 70.196 10.196 0.0000 0.0000 26.690 32.940 54.840
+57 "L28" 70.196 20.000 0.0000 0.0000 24.150 28.550 48.990
+58 "Y13" 70.196 29.804 0.0000 0.0000 21.690 24.370 43.210
+59 "K47" 70.196 40.000 0.0000 0.0000 19.410 20.550 37.770
+60 "O23" 70.196 54.902 0.0000 0.0000 16.490 15.670 30.460
+61 "B18" 70.196 70.196 0.0000 0.0000 14.010 11.710 24.300
+62 "S3" 70.196 85.098 0.0000 0.0000 12.120 8.7200 19.550
+63 "A9" 70.196 100.00 0.0000 0.0000 10.540 6.3900 15.630
+64 "R7" 85.098 0.0000 0.0000 0.0000 22.360 31.030 58.510
+65 "P51" 85.098 10.196 0.0000 0.0000 20.260 27.090 52.840
+66 "G55" 85.098 20.000 0.0000 0.0000 18.350 23.520 47.310
+67 "F25" 85.098 29.804 0.0000 0.0000 16.510 20.140 41.930
+68 "X30" 85.098 40.000 0.0000 0.0000 14.790 17.020 36.840
+69 "AA48" 85.098 54.902 0.0000 0.0000 12.500 12.920 29.790
+70 "AA46" 85.098 70.196 0.0000 0.0000 10.560 9.6000 23.840
+71 "Z23" 85.098 85.098 0.0000 0.0000 9.0900 7.1100 19.350
+72 "I55" 85.098 100.00 0.0000 0.0000 7.8700 5.1700 15.670
+73 "M27" 100.00 0.0000 0.0000 0.0000 16.720 25.290 56.260
+74 "X34" 100.00 10.196 0.0000 0.0000 15.170 22.120 51.000
+75 "A3" 100.00 20.000 0.0000 0.0000 13.770 19.260 45.750
+76 "Y30" 100.00 29.804 0.0000 0.0000 12.430 16.590 40.800
+77 "X4" 100.00 40.000 0.0000 0.0000 11.160 14.070 36.080
+78 "A8" 100.00 54.902 0.0000 0.0000 9.3600 10.620 29.150
+79 "Y39" 100.00 70.196 0.0000 0.0000 7.8300 7.8300 23.340
+80 "L44" 100.00 85.098 0.0000 0.0000 6.7100 5.7800 19.130
+81 "D52" 100.00 100.00 0.0000 0.0000 5.7900 4.2100 15.750
+82 "D3" 0.0000 0.0000 10.196 0.0000 80.380 84.000 64.370
+83 "O17" 0.0000 10.196 10.196 0.0000 73.240 73.550 57.600
+84 "H11" 0.0000 20.000 10.196 0.0000 66.560 63.900 51.070
+85 "C48" 0.0000 29.804 10.196 0.0000 60.220 54.850 44.770
+86 "O25" 0.0000 40.000 10.196 0.0000 54.320 46.530 38.760
+87 "C56" 0.0000 54.902 10.196 0.0000 46.490 35.580 30.230
+88 "E57" 0.0000 70.196 10.196 0.0000 39.940 26.920 23.160
+89 "AA55" 0.0000 85.098 10.196 0.0000 35.480 20.900 18.000
+90 "Z21" 0.0000 100.00 10.196 0.0000 31.910 16.410 13.900
+91 "G7" 10.196 0.0000 10.196 0.0000 71.850 76.680 62.750
+92 "H25" 10.196 10.196 10.196 0.0000 65.560 67.260 56.410
+93 "W51" 10.196 20.000 10.196 0.0000 59.560 58.430 50.060
+94 "F6" 10.196 29.804 10.196 0.0000 53.740 50.010 43.840
+95 "R50" 10.196 40.000 10.196 0.0000 48.340 42.280 37.940
+96 "K45" 10.196 54.902 10.196 0.0000 41.320 32.260 29.640
+97 "G23" 10.196 70.196 10.196 0.0000 35.490 24.370 22.790
+98 "A55" 10.196 85.098 10.196 0.0000 31.500 18.860 17.820
+99 "D5" 10.196 100.00 10.196 0.0000 28.300 14.750 13.870
+100 "N50" 20.000 0.0000 10.196 0.0000 63.190 69.190 61.080
+101 "G47" 20.000 10.196 10.196 0.0000 57.650 60.620 54.910
+102 "T27" 20.000 20.000 10.196 0.0000 52.360 52.680 48.710
+103 "J23" 20.000 29.804 10.196 0.0000 47.190 45.010 42.630
+104 "N57" 20.000 40.000 10.196 0.0000 42.370 37.990 36.900
+105 "B21" 20.000 54.902 10.196 0.0000 36.180 28.990 28.990
+106 "E7" 20.000 70.196 10.196 0.0000 31.020 21.860 22.440
+107 "E12" 20.000 85.098 10.196 0.0000 27.440 16.800 17.600
+108 "B42" 20.000 100.00 10.196 0.0000 24.540 12.990 13.700
+109 "Q43" 29.804 0.0000 10.196 0.0000 54.560 61.520 59.050
+110 "O44" 29.804 10.196 10.196 0.0000 49.750 53.870 53.150
+111 "C52" 29.804 20.000 10.196 0.0000 45.200 46.820 47.200
+112 "V1" 29.804 29.804 10.196 0.0000 40.730 40.020 41.410
+113 "F26" 29.804 40.000 10.196 0.0000 36.560 33.770 35.950
+114 "J37" 29.804 54.902 10.196 0.0000 31.180 25.750 28.380
+115 "I38" 29.804 70.196 10.196 0.0000 26.680 19.370 22.070
+116 "F23" 29.804 85.098 10.196 0.0000 23.510 14.790 17.380
+117 "AA15" 29.804 100.00 10.196 0.0000 20.920 11.310 13.590
+118 "Y54" 40.000 0.0000 10.196 0.0000 46.600 54.310 57.010
+119 "G19" 40.000 10.196 10.196 0.0000 42.470 47.550 51.400
+120 "O47" 40.000 20.000 10.196 0.0000 38.590 41.330 45.720
+121 "U42" 40.000 29.804 10.196 0.0000 34.790 35.350 40.250
+122 "F39" 40.000 40.000 10.196 0.0000 31.230 29.850 35.070
+123 "K23" 40.000 54.902 10.196 0.0000 26.600 22.740 27.800
+124 "Z18" 40.000 70.196 10.196 0.0000 22.720 17.060 21.720
+125 "G49" 40.000 85.098 10.196 0.0000 19.950 12.940 17.190
+126 "V56" 40.000 100.00 10.196 0.0000 17.670 9.8000 13.520
+127 "L47" 54.902 0.0000 10.196 0.0000 36.470 44.940 54.360
+128 "AA56" 54.902 10.196 10.196 0.0000 33.150 39.300 49.040
+129 "N49" 54.902 20.000 10.196 0.0000 30.120 34.180 43.840
+130 "H23" 54.902 29.804 10.196 0.0000 27.160 29.250 38.710
+131 "G25" 54.902 40.000 10.196 0.0000 24.390 24.710 33.830
+132 "K4" 54.902 54.902 10.196 0.0000 20.750 18.820 27.020
+133 "N17" 54.902 70.196 10.196 0.0000 17.690 14.080 21.310
+134 "M43" 54.902 85.098 10.196 0.0000 15.470 10.610 17.020
+135 "Q42" 54.902 100.00 10.196 0.0000 13.640 7.9500 13.520
+136 "K55" 70.196 0.0000 10.196 0.0000 27.940 36.820 51.930
+137 "E45" 70.196 10.196 10.196 0.0000 25.360 32.200 46.890
+138 "J26" 70.196 20.000 10.196 0.0000 23.020 28.000 42.110
+139 "H45" 70.196 29.804 10.196 0.0000 20.770 23.990 37.280
+140 "Q41" 70.196 40.000 10.196 0.0000 18.660 20.280 32.670
+141 "C2" 70.196 54.902 10.196 0.0000 15.860 15.440 26.300
+142 "AA18" 70.196 70.196 10.196 0.0000 13.490 11.540 20.940
+143 "N2" 70.196 85.098 10.196 0.0000 11.760 8.6500 16.890
+144 "P16" 70.196 100.00 10.196 0.0000 10.320 6.4100 13.560
+145 "X52" 85.098 0.0000 10.196 0.0000 20.880 30.120 49.870
+146 "R42" 85.098 10.196 10.196 0.0000 19.000 26.420 45.220
+147 "Y2" 85.098 20.000 10.196 0.0000 17.220 22.970 40.630
+148 "H21" 85.098 29.804 10.196 0.0000 15.530 19.690 36.070
+149 "Q45" 85.098 40.000 10.196 0.0000 13.960 16.660 31.740
+150 "D22" 85.098 54.902 10.196 0.0000 11.860 12.690 25.740
+151 "C22" 85.098 70.196 10.196 0.0000 10.070 9.4700 20.670
+152 "U35" 85.098 85.098 10.196 0.0000 8.7400 7.0600 16.830
+153 "J53" 85.098 100.00 10.196 0.0000 7.6400 5.2000 13.660
+154 "L12" 100.00 0.0000 10.196 0.0000 15.280 24.400 47.930
+155 "T16" 100.00 10.196 10.196 0.0000 13.990 21.530 43.690
+156 "L23" 100.00 20.000 10.196 0.0000 12.640 18.700 39.220
+157 "C44" 100.00 29.804 10.196 0.0000 11.390 16.040 34.910
+158 "S44" 100.00 40.000 10.196 0.0000 10.230 13.600 30.870
+159 "T14" 100.00 54.902 10.196 0.0000 8.6900 10.360 25.210
+160 "S9" 100.00 70.196 10.196 0.0000 7.3700 7.7300 20.420
+161 "G24" 100.00 85.098 10.196 0.0000 6.3600 5.7600 16.780
+162 "B53" 100.00 100.00 10.196 0.0000 5.5300 4.2200 13.770
+163 "H37" 0.0000 0.0000 20.000 0.0000 78.300 82.380 54.640
+164 "R37" 0.0000 10.196 20.000 0.0000 71.360 72.100 48.880
+165 "AA22" 0.0000 20.000 20.000 0.0000 65.060 62.860 43.680
+166 "V10" 0.0000 29.804 20.000 0.0000 58.960 54.020 38.370
+167 "T22" 0.0000 40.000 20.000 0.0000 53.250 45.860 33.210
+168 "O39" 0.0000 54.902 20.000 0.0000 45.770 35.240 25.990
+169 "V49" 0.0000 70.196 20.000 0.0000 39.500 26.800 19.980
+170 "Z56" 0.0000 85.098 20.000 0.0000 35.160 20.850 15.510
+171 "B39" 0.0000 100.00 20.000 0.0000 31.650 16.380 11.930
+172 "A50" 10.196 0.0000 20.000 0.0000 69.820 75.120 53.140
+173 "M39" 10.196 10.196 20.000 0.0000 63.810 65.980 47.900
+174 "U2" 10.196 20.000 20.000 0.0000 58.190 57.500 42.860
+175 "K15" 10.196 29.804 20.000 0.0000 52.650 49.350 37.630
+176 "I1" 10.196 40.000 20.000 0.0000 47.450 41.810 32.570
+177 "C32" 10.196 54.902 20.000 0.0000 40.640 31.960 25.540
+178 "Q29" 10.196 70.196 20.000 0.0000 34.960 24.170 19.690
+179 "W19" 10.196 85.098 20.000 0.0000 31.090 18.740 15.360
+180 "P41" 10.196 100.00 20.000 0.0000 27.980 14.690 11.890
+181 "B51" 20.000 0.0000 20.000 0.0000 61.330 67.780 51.660
+182 "E37" 20.000 10.196 20.000 0.0000 56.030 59.460 46.530
+183 "B31" 20.000 20.000 20.000 0.0000 51.100 51.890 41.660
+184 "U39" 20.000 29.804 20.000 0.0000 46.130 44.410 36.510
+185 "T47" 20.000 40.000 20.000 0.0000 41.450 37.500 31.540
+186 "I29" 20.000 54.902 20.000 0.0000 35.490 28.670 24.840
+187 "Y40" 20.000 70.196 20.000 0.0000 30.520 21.670 19.280
+188 "N25" 20.000 85.098 20.000 0.0000 27.040 16.700 15.120
+189 "J11" 20.000 100.00 20.000 0.0000 24.220 12.950 11.750
+190 "S22" 29.804 0.0000 20.000 0.0000 52.750 60.170 49.770
+191 "V9" 29.804 10.196 20.000 0.0000 48.210 52.780 44.850
+192 "B45" 29.804 20.000 20.000 0.0000 43.950 46.030 40.170
+193 "I49" 29.804 29.804 20.000 0.0000 39.710 39.450 35.370
+194 "B4" 29.804 40.000 20.000 0.0000 35.720 33.350 30.730
+195 "S52" 29.804 54.902 20.000 0.0000 30.520 25.450 24.250
+196 "A36" 29.804 70.196 20.000 0.0000 26.170 19.160 18.850
+197 "A27" 29.804 85.098 20.000 0.0000 23.120 14.680 14.860
+198 "U32" 29.804 100.00 20.000 0.0000 20.640 11.290 11.640
+199 "A17" 40.000 0.0000 20.000 0.0000 44.870 53.030 47.880
+200 "K30" 40.000 10.196 20.000 0.0000 41.020 46.530 43.230
+201 "M48" 40.000 20.000 20.000 0.0000 37.380 40.550 38.740
+202 "W53" 40.000 29.804 20.000 0.0000 33.840 34.820 34.310
+203 "V54" 40.000 40.000 20.000 0.0000 30.490 29.510 30.000
+204 "M56" 40.000 54.902 20.000 0.0000 26.000 22.460 23.730
+205 "N4" 40.000 70.196 20.000 0.0000 22.210 16.840 18.480
+206 "M12" 40.000 85.098 20.000 0.0000 19.560 12.830 14.660
+207 "F18" 40.000 100.00 20.000 0.0000 17.420 9.7900 11.580
+208 "A22" 54.902 0.0000 20.000 0.0000 35.030 43.940 45.670
+209 "F46" 54.902 10.196 20.000 0.0000 31.970 38.520 41.340
+210 "G53" 54.902 20.000 20.000 0.0000 29.140 33.620 37.240
+211 "Y11" 54.902 29.804 20.000 0.0000 26.340 28.850 32.990
+212 "B49" 54.902 40.000 20.000 0.0000 23.700 24.410 28.850
+213 "Z11" 54.902 54.902 20.000 0.0000 20.220 18.600 23.080
+214 "N55" 54.902 70.196 20.000 0.0000 17.280 13.940 18.230
+215 "G38" 54.902 85.098 20.000 0.0000 15.130 10.540 14.610
+216 "K9" 54.902 100.00 20.000 0.0000 13.360 7.9400 11.670
+217 "H43" 70.196 0.0000 20.000 0.0000 26.700 36.030 43.670
+218 "H17" 70.196 10.196 20.000 0.0000 24.320 31.560 39.620
+219 "O30" 70.196 20.000 20.000 0.0000 22.190 27.590 35.870
+220 "O12" 70.196 29.804 20.000 0.0000 20.010 23.650 31.770
+221 "R46" 70.196 40.000 20.000 0.0000 17.960 19.980 27.790
+222 "AA13" 70.196 54.902 20.000 0.0000 15.350 15.250 22.490
+223 "W13" 70.196 70.196 20.000 0.0000 13.140 11.440 18.030
+224 "M7" 70.196 85.098 20.000 0.0000 11.450 8.6000 14.610
+225 "AA1" 70.196 100.00 20.000 0.0000 10.020 6.4000 11.780
+226 "V43" 85.098 0.0000 20.000 0.0000 19.660 29.370 41.960
+227 "D30" 85.098 10.196 20.000 0.0000 17.910 25.760 38.150
+228 "R53" 85.098 20.000 20.000 0.0000 16.330 22.510 34.520
+229 "D50" 85.098 29.804 20.000 0.0000 14.730 19.300 30.700
+230 "Z45" 85.098 40.000 20.000 0.0000 13.230 16.320 27.010
+231 "C20" 85.098 54.902 20.000 0.0000 11.300 12.470 22.050
+232 "F21" 85.098 70.196 20.000 0.0000 9.6700 9.3500 17.840
+233 "U45" 85.098 85.098 20.000 0.0000 8.4000 7.0000 14.550
+234 "Y10" 85.098 100.00 20.000 0.0000 7.3300 5.1800 11.820
+235 "T48" 100.00 0.0000 20.000 0.0000 14.050 23.630 40.330
+236 "D53" 100.00 10.196 20.000 0.0000 12.830 20.790 36.740
+237 "E20" 100.00 20.000 20.000 0.0000 11.670 18.130 33.170
+238 "M13" 100.00 29.804 20.000 0.0000 10.550 15.580 29.660
+239 "M40" 100.00 40.000 20.000 0.0000 9.5000 13.210 26.320
+240 "Z31" 100.00 54.902 20.000 0.0000 8.1000 10.100 21.640
+241 "L6" 100.00 70.196 20.000 0.0000 6.9000 7.5700 17.620
+242 "E16" 100.00 85.098 20.000 0.0000 5.9800 5.6700 14.470
+243 "X9" 100.00 100.00 20.000 0.0000 5.2200 4.2000 11.840
+244 "I19" 0.0000 0.0000 29.804 0.0000 76.290 80.780 45.490
+245 "U18" 0.0000 10.196 29.804 0.0000 69.640 70.770 40.820
+246 "A21" 0.0000 20.000 29.804 0.0000 63.470 61.670 36.480
+247 "E5" 0.0000 29.804 29.804 0.0000 57.610 53.040 32.110
+248 "E2" 0.0000 40.000 29.804 0.0000 52.150 45.090 27.870
+249 "X7" 0.0000 54.902 29.804 0.0000 44.940 34.710 21.850
+250 "A49" 0.0000 70.196 29.804 0.0000 38.900 26.490 16.830
+251 "T51" 0.0000 85.098 29.804 0.0000 34.770 20.740 13.120
+252 "B44" 0.0000 100.00 29.804 0.0000 31.460 16.430 10.140
+253 "Y21" 10.196 0.0000 29.804 0.0000 67.860 73.560 44.410
+254 "Y18" 10.196 10.196 29.804 0.0000 62.090 64.640 40.170
+255 "R57" 10.196 20.000 29.804 0.0000 56.730 56.440 35.980
+256 "Q4" 10.196 29.804 29.804 0.0000 51.390 48.450 31.590
+257 "O35" 10.196 40.000 29.804 0.0000 46.360 41.070 27.340
+258 "N51" 10.196 54.902 29.804 0.0000 39.850 31.530 21.510
+259 "T2" 10.196 70.196 29.804 0.0000 34.420 23.980 16.660
+260 "C28" 10.196 85.098 29.804 0.0000 30.730 18.690 13.060
+261 "D18" 10.196 100.00 29.804 0.0000 27.770 14.730 10.160
+262 "D45" 20.000 0.0000 29.804 0.0000 59.420 66.240 43.090
+263 "P26" 20.000 10.196 29.804 0.0000 54.410 58.230 39.030
+264 "M51" 20.000 20.000 29.804 0.0000 49.760 50.910 34.960
+265 "R43" 20.000 29.804 29.804 0.0000 44.940 43.580 30.610
+266 "E49" 20.000 40.000 29.804 0.0000 40.420 36.810 26.440
+267 "Q19" 20.000 54.902 29.804 0.0000 34.740 28.280 20.900
+268 "AA26" 20.000 70.196 29.804 0.0000 30.020 21.510 16.310
+269 "L50" 20.000 85.098 29.804 0.0000 26.700 16.660 12.870
+270 "L48" 20.000 100.00 29.804 0.0000 23.990 12.980 10.080
+271 "F22" 29.804 0.0000 29.804 0.0000 51.100 58.890 41.600
+272 "S31" 29.804 10.196 29.804 0.0000 46.760 51.710 37.680
+273 "AA4" 29.804 20.000 29.804 0.0000 42.790 45.230 33.780
+274 "Q50" 29.804 29.804 29.804 0.0000 38.690 38.760 29.720
+275 "I11" 29.804 40.000 29.804 0.0000 34.810 32.760 25.820
+276 "X24" 29.804 54.902 29.804 0.0000 29.830 25.090 20.450
+277 "R24" 29.804 70.196 29.804 0.0000 25.670 19.000 15.980
+278 "V15" 29.804 85.098 29.804 0.0000 22.780 14.630 12.670
+279 "M52" 29.804 100.00 29.804 0.0000 20.420 11.310 9.9900
+280 "U48" 40.000 0.0000 29.804 0.0000 43.450 52.000 40.160
+281 "O5" 40.000 10.196 29.804 0.0000 39.710 45.600 36.380
+282 "Y16" 40.000 20.000 29.804 0.0000 36.340 39.880 32.650
+283 "U57" 40.000 29.804 29.804 0.0000 32.920 34.240 28.910
+284 "I3" 40.000 40.000 29.804 0.0000 29.650 28.990 25.280
+285 "E47" 40.000 54.902 29.804 0.0000 25.340 22.140 20.070
+286 "V36" 40.000 70.196 29.804 0.0000 21.730 16.690 15.720
+287 "I54" 40.000 85.098 29.804 0.0000 19.230 12.780 12.520
+288 "O15" 40.000 100.00 29.804 0.0000 17.200 9.8200 9.9400
+289 "J51" 54.902 0.0000 29.804 0.0000 33.680 42.990 38.300
+290 "C39" 54.902 10.196 29.804 0.0000 30.740 37.650 34.740
+291 "D25" 54.902 20.000 29.804 0.0000 28.090 32.910 31.290
+292 "M36" 54.902 29.804 29.804 0.0000 25.370 28.210 27.700
+293 "H29" 54.902 40.000 29.804 0.0000 22.800 23.860 24.250
+294 "W44" 54.902 54.902 29.804 0.0000 19.570 18.300 19.520
+295 "M10" 54.902 70.196 29.804 0.0000 16.850 13.830 15.540
+296 "S7" 54.902 85.098 29.804 0.0000 14.830 10.510 12.520
+297 "T31" 54.902 100.00 29.804 0.0000 13.130 7.9500 10.040
+298 "O48" 70.196 0.0000 29.804 0.0000 25.400 35.120 36.620
+299 "W33" 70.196 10.196 29.804 0.0000 23.170 30.740 33.270
+300 "U22" 70.196 20.000 29.804 0.0000 21.120 26.850 30.070
+301 "Y24" 70.196 29.804 29.804 0.0000 19.020 22.990 26.610
+302 "U55" 70.196 40.000 29.804 0.0000 17.060 19.420 23.300
+303 "I21" 70.196 54.902 29.804 0.0000 14.730 14.970 19.020
+304 "R3" 70.196 70.196 29.804 0.0000 12.750 11.360 15.400
+305 "I16" 70.196 85.098 29.804 0.0000 11.160 8.5800 12.540
+306 "A34" 70.196 100.00 29.804 0.0000 9.7800 6.4000 10.150
+307 "B54" 85.098 0.0000 29.804 0.0000 18.470 28.540 35.270
+308 "A5" 85.098 10.196 29.804 0.0000 16.860 25.020 32.140
+309 "R14" 85.098 20.000 29.804 0.0000 15.370 21.850 29.080
+310 "C34" 85.098 29.804 29.804 0.0000 13.860 18.740 25.870
+311 "J31" 85.098 40.000 29.804 0.0000 12.450 15.870 22.800
+312 "N45" 85.098 54.902 29.804 0.0000 10.740 12.230 18.720
+313 "E41" 85.098 70.196 29.804 0.0000 9.2800 9.2700 15.250
+314 "I9" 85.098 85.098 29.804 0.0000 8.1000 6.9800 12.500
+315 "S39" 85.098 100.00 29.804 0.0000 7.0900 5.1700 10.190
+316 "P6" 100.00 0.0000 29.804 0.0000 12.990 22.890 34.020
+317 "N31" 100.00 10.196 29.804 0.0000 11.870 20.140 31.110
+318 "P4" 100.00 20.000 29.804 0.0000 10.830 17.600 28.160
+319 "T37" 100.00 29.804 29.804 0.0000 9.8200 15.150 25.230
+320 "S40" 100.00 40.000 29.804 0.0000 8.8600 12.890 22.430
+321 "K27" 100.00 54.902 29.804 0.0000 7.5900 9.9100 18.480
+322 "T26" 100.00 70.196 29.804 0.0000 6.5100 7.4800 15.080
+323 "H32" 100.00 85.098 29.804 0.0000 5.6700 5.6300 12.430
+324 "O46" 100.00 100.00 29.804 0.0000 4.9700 4.1800 10.210
+325 "P49" 0.0000 0.0000 40.000 0.0000 74.390 79.200 36.970
+326 "P5" 0.0000 10.196 40.000 0.0000 67.990 69.470 33.260
+327 "H20" 0.0000 20.000 40.000 0.0000 61.920 60.440 29.670
+328 "S24" 0.0000 29.804 40.000 0.0000 56.270 52.000 26.160
+329 "S21" 0.0000 40.000 40.000 0.0000 51.050 44.280 22.780
+330 "P44" 0.0000 54.902 40.000 0.0000 44.100 34.130 17.920
+331 "X56" 0.0000 70.196 40.000 0.0000 38.280 26.120 13.860
+332 "C4" 0.0000 85.098 40.000 0.0000 34.370 20.590 10.880
+333 "O34" 0.0000 100.00 40.000 0.0000 31.270 16.470 8.4900
+334 "E31" 10.196 0.0000 40.000 0.0000 66.000 72.030 36.270
+335 "H57" 10.196 10.196 40.000 0.0000 60.440 63.300 32.890
+336 "O20" 10.196 20.000 40.000 0.0000 55.270 55.310 29.430
+337 "B40" 10.196 29.804 40.000 0.0000 50.100 47.480 25.830
+338 "X49" 10.196 40.000 40.000 0.0000 45.250 40.270 22.370
+339 "V34" 10.196 54.902 40.000 0.0000 39.050 31.050 17.670
+340 "Q1" 10.196 70.196 40.000 0.0000 33.900 23.770 13.770
+341 "C6" 10.196 85.098 40.000 0.0000 30.390 18.640 10.880
+342 "A46" 10.196 100.00 40.000 0.0000 27.580 14.780 8.5600
+343 "Y15" 20.000 0.0000 40.000 0.0000 57.590 64.730 35.140
+344 "N53" 20.000 10.196 40.000 0.0000 52.850 56.990 32.000
+345 "AA23" 20.000 20.000 40.000 0.0000 48.380 49.850 28.590
+346 "Y35" 20.000 29.804 40.000 0.0000 43.740 42.660 25.010
+347 "C9" 20.000 40.000 40.000 0.0000 39.390 36.060 21.630
+348 "Y46" 20.000 54.902 40.000 0.0000 34.000 27.850 17.190
+349 "L22" 20.000 70.196 40.000 0.0000 29.520 21.330 13.510
+350 "C36" 20.000 85.098 40.000 0.0000 26.380 16.620 10.760
+351 "M34" 20.000 100.00 40.000 0.0000 23.800 13.020 8.5200
+352 "S4" 29.804 0.0000 40.000 0.0000 49.550 57.650 34.070
+353 "Z33" 29.804 10.196 40.000 0.0000 45.360 50.640 31.000
+354 "Q46" 29.804 20.000 40.000 0.0000 41.620 44.370 27.750
+355 "A18" 29.804 29.804 40.000 0.0000 37.650 38.000 24.370
+356 "M23" 29.804 40.000 40.000 0.0000 33.870 32.100 21.180
+357 "L43" 29.804 54.902 40.000 0.0000 29.130 24.710 16.880
+358 "T40" 29.804 70.196 40.000 0.0000 25.190 18.840 13.300
+359 "G3" 29.804 85.098 40.000 0.0000 22.450 14.590 10.630
+360 "P8" 29.804 100.00 40.000 0.0000 20.210 11.340 8.4500
+361 "K34" 40.000 0.0000 40.000 0.0000 42.140 51.000 33.060
+362 "P30" 40.000 10.196 40.000 0.0000 38.440 44.670 30.030
+363 "O45" 40.000 20.000 40.000 0.0000 35.330 39.180 26.960
+364 "R6" 40.000 29.804 40.000 0.0000 31.990 33.600 23.810
+365 "L41" 40.000 40.000 40.000 0.0000 28.770 28.400 20.790
+366 "M18" 40.000 54.902 40.000 0.0000 24.680 21.800 16.630
+367 "K32" 40.000 70.196 40.000 0.0000 21.270 16.540 13.140
+368 "S50" 40.000 85.098 40.000 0.0000 18.910 12.740 10.540
+369 "G39" 40.000 100.00 40.000 0.0000 16.990 9.8300 8.4100
+370 "G20" 54.902 0.0000 40.000 0.0000 32.390 42.020 31.550
+371 "P34" 54.902 10.196 40.000 0.0000 29.520 36.740 28.640
+372 "P50" 54.902 20.000 40.000 0.0000 27.010 32.130 25.760
+373 "H9" 54.902 29.804 40.000 0.0000 24.380 27.510 22.780
+374 "Z7" 54.902 40.000 40.000 0.0000 21.910 23.260 19.950
+375 "V32" 54.902 54.902 40.000 0.0000 18.920 17.960 16.180
+376 "S34" 54.902 70.196 40.000 0.0000 16.410 13.690 13.000
+377 "C29" 54.902 85.098 40.000 0.0000 14.520 10.470 10.540
+378 "X42" 54.902 100.00 40.000 0.0000 12.920 7.9500 8.4900
+379 "Y20" 70.196 0.0000 40.000 0.0000 24.130 34.160 30.170
+380 "A42" 70.196 10.196 40.000 0.0000 22.000 29.870 27.400
+381 "V6" 70.196 20.000 40.000 0.0000 20.030 26.030 24.680
+382 "A47" 70.196 29.804 40.000 0.0000 18.020 22.270 21.860
+383 "I57" 70.196 40.000 40.000 0.0000 16.190 18.840 19.200
+384 "C25" 70.196 54.902 40.000 0.0000 14.100 14.650 15.780
+385 "Q57" 70.196 70.196 40.000 0.0000 12.330 11.240 12.880
+386 "E25" 70.196 85.098 40.000 0.0000 10.860 8.5400 10.550
+387 "U36" 70.196 100.00 40.000 0.0000 9.5600 6.3900 8.5800
+388 "F17" 85.098 0.0000 40.000 0.0000 17.320 27.680 29.170
+389 "C8" 85.098 10.196 40.000 0.0000 15.830 24.270 26.620
+390 "F36" 85.098 20.000 40.000 0.0000 14.420 21.160 24.040
+391 "D7" 85.098 29.804 40.000 0.0000 13.000 18.150 21.410
+392 "AA27" 85.098 40.000 40.000 0.0000 11.710 15.410 18.910
+393 "T19" 85.098 54.902 40.000 0.0000 10.180 11.970 15.610
+394 "G56" 85.098 70.196 40.000 0.0000 8.8800 9.1500 12.790
+395 "Z19" 85.098 85.098 40.000 0.0000 7.8000 6.9300 10.540
+396 "J44" 85.098 100.00 40.000 0.0000 6.8600 5.1600 8.6400
+397 "E23" 100.00 0.0000 40.000 0.0000 11.990 22.160 28.290
+398 "X25" 100.00 10.196 40.000 0.0000 10.980 19.510 25.970
+399 "F4" 100.00 20.000 40.000 0.0000 10.040 17.070 23.530
+400 "V41" 100.00 29.804 40.000 0.0000 9.1100 14.730 21.100
+401 "X48" 100.00 40.000 40.000 0.0000 8.2400 12.570 18.770
+402 "W42" 100.00 54.902 40.000 0.0000 7.1100 9.7100 15.500
+403 "W9" 100.00 70.196 40.000 0.0000 6.1400 7.3700 12.690
+404 "M35" 100.00 85.098 40.000 0.0000 5.3800 5.5800 10.500
+405 "I4" 100.00 100.00 40.000 0.0000 4.7300 4.1600 8.6800
+406 "M15" 0.0000 0.0000 54.902 0.0000 71.850 76.950 25.370
+407 "L46" 0.0000 10.196 54.902 0.0000 65.680 67.470 22.770
+408 "D21" 0.0000 20.000 54.902 0.0000 59.880 58.740 20.360
+409 "AA6" 0.0000 29.804 54.902 0.0000 54.450 50.550 17.950
+410 "Z55" 0.0000 40.000 54.902 0.0000 49.460 43.080 15.630
+411 "L35" 0.0000 54.902 54.902 0.0000 42.980 33.400 12.470
+412 "O33" 0.0000 70.196 54.902 0.0000 37.560 25.750 9.8100
+413 "X31" 0.0000 85.098 54.902 0.0000 33.860 20.410 7.7800
+414 "Q8" 0.0000 100.00 54.902 0.0000 30.910 16.400 6.1200
+415 "U43" 10.196 0.0000 54.902 0.0000 63.580 69.930 24.890
+416 "C55" 10.196 10.196 54.902 0.0000 58.240 61.470 22.580
+417 "A48" 10.196 20.000 54.902 0.0000 53.250 53.660 20.240
+418 "R39" 10.196 29.804 54.902 0.0000 48.380 46.160 17.810
+419 "D49" 10.196 40.000 54.902 0.0000 43.840 39.280 15.490
+420 "J30" 10.196 54.902 54.902 0.0000 38.020 30.410 12.360
+421 "I48" 10.196 70.196 54.902 0.0000 33.160 23.390 9.7500
+422 "L31" 10.196 85.098 54.902 0.0000 29.860 18.460 7.7800
+423 "Q54" 10.196 100.00 54.902 0.0000 27.220 14.740 6.1800
+424 "I5" 20.000 0.0000 54.902 0.0000 55.290 62.740 24.130
+425 "Z30" 20.000 10.196 54.902 0.0000 50.730 55.220 22.030
+426 "W18" 20.000 20.000 54.902 0.0000 46.420 48.250 19.660
+427 "K29" 20.000 29.804 54.902 0.0000 42.090 41.390 17.270
+428 "S43" 20.000 40.000 54.902 0.0000 38.060 35.130 15.040
+429 "T6" 20.000 54.902 54.902 0.0000 33.020 27.230 12.030
+430 "F20" 20.000 70.196 54.902 0.0000 28.810 20.960 9.5300
+431 "P22" 20.000 85.098 54.902 0.0000 25.880 16.440 7.6700
+432 "F37" 20.000 100.00 54.902 0.0000 23.490 12.990 6.1500
+433 "E36" 29.804 0.0000 54.902 0.0000 47.380 55.770 23.500
+434 "J42" 29.804 10.196 54.902 0.0000 43.320 48.960 21.370
+435 "R16" 29.804 20.000 54.902 0.0000 39.750 42.870 19.180
+436 "D57" 29.804 29.804 54.902 0.0000 36.070 36.810 16.890
+437 "J17" 29.804 40.000 54.902 0.0000 32.590 31.210 14.710
+438 "A39" 29.804 54.902 54.902 0.0000 28.190 24.120 11.810
+439 "I23" 29.804 70.196 54.902 0.0000 24.530 18.480 9.3900
+440 "G31" 29.804 85.098 54.902 0.0000 22.000 14.420 7.5900
+441 "O18" 29.804 100.00 54.902 0.0000 19.930 11.320 6.1100
+442 "L19" 40.000 0.0000 54.902 0.0000 40.090 49.230 22.920
+443 "U13" 40.000 10.196 54.902 0.0000 36.510 43.100 20.740
+444 "U20" 40.000 20.000 54.902 0.0000 33.580 37.810 18.740
+445 "U26" 40.000 29.804 54.902 0.0000 30.510 32.510 16.560
+446 "AA51" 40.000 40.000 54.902 0.0000 27.550 27.560 14.450
+447 "Y3" 40.000 54.902 54.902 0.0000 23.780 21.240 11.650
+448 "E42" 40.000 70.196 54.902 0.0000 20.630 16.200 9.3100
+449 "F33" 40.000 85.098 54.902 0.0000 18.460 12.570 7.5500
+450 "U19" 40.000 100.00 54.902 0.0000 16.710 9.8100 6.1000
+451 "I45" 54.902 0.0000 54.902 0.0000 30.490 40.400 21.940
+452 "D44" 54.902 10.196 54.902 0.0000 27.770 35.360 19.870
+453 "W41" 54.902 20.000 54.902 0.0000 25.450 30.940 18.010
+454 "X14" 54.902 29.804 54.902 0.0000 23.100 26.600 16.000
+455 "S16" 54.902 40.000 54.902 0.0000 20.880 22.580 14.040
+456 "E21" 54.902 54.902 54.902 0.0000 18.070 17.450 11.410
+457 "R29" 54.902 70.196 54.902 0.0000 15.710 13.320 9.2100
+458 "D4" 54.902 85.098 54.902 0.0000 14.010 10.270 7.5500
+459 "N47" 54.902 100.00 54.902 0.0000 12.590 7.9000 6.1800
+460 "W49" 70.196 0.0000 54.902 0.0000 22.390 32.710 21.050
+461 "E50" 70.196 10.196 54.902 0.0000 20.430 28.660 19.130
+462 "P15" 70.196 20.000 54.902 0.0000 18.630 25.000 17.350
+463 "T34" 70.196 29.804 54.902 0.0000 16.890 21.490 15.480
+464 "G29" 70.196 40.000 54.902 0.0000 15.290 18.280 13.670
+465 "Q21" 70.196 54.902 54.902 0.0000 13.300 14.180 11.210
+466 "C12" 70.196 70.196 54.902 0.0000 11.600 10.850 9.1300
+467 "E44" 70.196 85.098 54.902 0.0000 10.300 8.3100 7.5600
+468 "G41" 70.196 100.00 54.902 0.0000 9.1900 6.3100 6.2600
+469 "S25" 85.098 0.0000 54.902 0.0000 15.750 26.400 20.560
+470 "N44" 85.098 10.196 54.902 0.0000 14.390 23.190 18.740
+471 "V48" 85.098 20.000 54.902 0.0000 13.140 20.250 16.990
+472 "R51" 85.098 29.804 54.902 0.0000 11.930 17.440 15.210
+473 "I47" 85.098 40.000 54.902 0.0000 10.800 14.850 13.490
+474 "I39" 85.098 54.902 54.902 0.0000 9.4100 11.510 11.140
+475 "I36" 85.098 70.196 54.902 0.0000 8.2100 8.8000 9.1400
+476 "L10" 85.098 85.098 54.902 0.0000 7.2700 6.7200 7.5900
+477 "O11" 85.098 100.00 54.902 0.0000 6.4700 5.0700 6.3100
+478 "T55" 100.00 0.0000 54.902 0.0000 10.570 21.060 20.180
+479 "Y53" 100.00 10.196 54.902 0.0000 9.6800 18.550 18.440
+480 "N16" 100.00 20.000 54.902 0.0000 8.8700 16.280 16.720
+481 "W55" 100.00 29.804 54.902 0.0000 8.0700 14.050 15.000
+482 "Q35" 100.00 40.000 54.902 0.0000 7.3200 11.980 13.370
+483 "S10" 100.00 54.902 54.902 0.0000 6.3600 9.2700 11.100
+484 "S53" 100.00 70.196 54.902 0.0000 5.5400 7.0700 9.1600
+485 "R15" 100.00 85.098 54.902 0.0000 4.8900 5.3900 7.6300
+486 "H44" 100.00 100.00 54.902 0.0000 4.3500 4.0800 6.3500
+487 "H14" 0.0000 0.0000 70.196 0.0000 69.800 74.880 16.470
+488 "B12" 0.0000 10.196 70.196 0.0000 63.780 65.610 14.710
+489 "R17" 0.0000 20.000 70.196 0.0000 58.230 57.180 13.230
+490 "T13" 0.0000 29.804 70.196 0.0000 52.990 49.220 11.670
+491 "AA21" 0.0000 40.000 70.196 0.0000 48.170 41.980 10.170
+492 "K46" 0.0000 54.902 70.196 0.0000 42.070 32.730 8.2600
+493 "S29" 0.0000 70.196 70.196 0.0000 36.970 25.400 6.6500
+494 "C40" 0.0000 85.098 70.196 0.0000 33.440 20.220 5.3500
+495 "Q6" 0.0000 100.00 70.196 0.0000 30.600 16.310 4.2700
+496 "F34" 10.196 0.0000 70.196 0.0000 61.650 68.010 16.120
+497 "I7" 10.196 10.196 70.196 0.0000 56.470 59.790 14.610
+498 "P27" 10.196 20.000 70.196 0.0000 51.630 52.160 13.150
+499 "Z2" 10.196 29.804 70.196 0.0000 47.010 44.970 11.630
+500 "AA33" 10.196 40.000 70.196 0.0000 42.730 38.390 10.180
+501 "C38" 10.196 54.902 70.196 0.0000 37.200 29.830 8.2300
+502 "J14" 10.196 70.196 70.196 0.0000 32.570 23.030 6.6000
+503 "S38" 10.196 85.098 70.196 0.0000 29.430 18.250 5.3400
+504 "E26" 10.196 100.00 70.196 0.0000 26.920 14.660 4.3100
+505 "G6" 20.000 0.0000 70.196 0.0000 53.480 60.950 15.650
+506 "E55" 20.000 10.196 70.196 0.0000 49.030 53.620 14.290
+507 "N14" 20.000 20.000 70.196 0.0000 44.850 46.800 12.780
+508 "P37" 20.000 29.804 70.196 0.0000 40.780 40.270 11.310
+509 "Z24" 20.000 40.000 70.196 0.0000 37.020 34.300 9.9300
+510 "J34" 20.000 54.902 70.196 0.0000 32.230 26.660 8.0300
+511 "W52" 20.000 70.196 70.196 0.0000 28.240 20.580 6.4300
+512 "I13" 20.000 85.098 70.196 0.0000 25.470 16.240 5.2400
+513 "V52" 20.000 100.00 70.196 0.0000 23.240 12.930 4.2800
+514 "J54" 29.804 0.0000 70.196 0.0000 45.620 54.040 15.320
+515 "D31" 29.804 10.196 70.196 0.0000 41.700 47.430 13.880
+516 "V16" 29.804 20.000 70.196 0.0000 38.240 41.500 12.520
+517 "J2" 29.804 29.804 70.196 0.0000 34.800 35.730 11.090
+518 "Z13" 29.804 40.000 70.196 0.0000 31.560 30.400 9.7100
+519 "B19" 29.804 54.902 70.196 0.0000 27.450 23.570 7.8800
+520 "G10" 29.804 70.196 70.196 0.0000 24.000 18.130 6.3400
+521 "X12" 29.804 85.098 70.196 0.0000 21.630 14.240 5.2000
+522 "U10" 29.804 100.00 70.196 0.0000 19.700 11.270 4.2700
+523 "Y14" 40.000 0.0000 70.196 0.0000 38.400 47.570 15.020
+524 "E24" 40.000 10.196 70.196 0.0000 34.980 41.670 13.500
+525 "S8" 40.000 20.000 70.196 0.0000 32.150 36.540 12.320
+526 "D36" 40.000 29.804 70.196 0.0000 29.300 31.490 10.920
+527 "P9" 40.000 40.000 70.196 0.0000 26.580 26.800 9.5400
+528 "T36" 40.000 54.902 70.196 0.0000 23.070 20.720 7.7800
+529 "C19" 40.000 70.196 70.196 0.0000 20.120 15.860 6.3000
+530 "J46" 40.000 85.098 70.196 0.0000 18.100 12.400 5.1900
+531 "Q44" 40.000 100.00 70.196 0.0000 16.480 9.7600 4.2800
+532 "J12" 54.902 0.0000 70.196 0.0000 28.990 38.930 14.450
+533 "V12" 54.902 10.196 70.196 0.0000 26.430 34.130 13.060
+534 "F7" 54.902 20.000 70.196 0.0000 24.220 29.870 11.960
+535 "R35" 54.902 29.804 70.196 0.0000 22.100 25.790 10.700
+536 "Q16" 54.902 40.000 70.196 0.0000 20.110 22.000 9.4300
+537 "D11" 54.902 54.902 70.196 0.0000 17.420 16.980 7.7000
+538 "L39" 54.902 70.196 70.196 0.0000 15.150 12.950 6.2500
+539 "Y44" 54.902 85.098 70.196 0.0000 13.580 10.050 5.2000
+540 "A4" 54.902 100.00 70.196 0.0000 12.310 7.8300 4.3500
+541 "E30" 70.196 0.0000 70.196 0.0000 21.040 31.420 13.950
+542 "O51" 70.196 10.196 70.196 0.0000 19.240 27.610 12.700
+543 "W30" 70.196 20.000 70.196 0.0000 17.560 24.110 11.650
+544 "V51" 70.196 29.804 70.196 0.0000 16.050 20.840 10.500
+545 "J39" 70.196 40.000 70.196 0.0000 14.640 17.820 9.3400
+546 "L29" 70.196 54.902 70.196 0.0000 12.690 13.760 7.6500
+547 "X1" 70.196 70.196 70.196 0.0000 11.020 10.470 6.2200
+548 "T7" 70.196 85.098 70.196 0.0000 9.8400 8.0700 5.2200
+549 "U46" 70.196 100.00 70.196 0.0000 8.8800 6.2200 4.4200
+550 "T12" 85.098 0.0000 70.196 0.0000 14.510 25.260 13.810
+551 "I6" 85.098 10.196 70.196 0.0000 13.280 22.230 12.580
+552 "S46" 85.098 20.000 70.196 0.0000 12.150 19.450 11.490
+553 "H55" 85.098 29.804 70.196 0.0000 11.100 16.810 10.370
+554 "B36" 85.098 40.000 70.196 0.0000 10.120 14.360 9.2600
+555 "E34" 85.098 54.902 70.196 0.0000 8.8000 11.100 7.6600
+556 "N1" 85.098 70.196 70.196 0.0000 7.6600 8.4500 6.3000
+557 "A12" 85.098 85.098 70.196 0.0000 6.8300 6.4900 5.2900
+558 "N5" 85.098 100.00 70.196 0.0000 6.1500 4.9800 4.4600
+559 "T25" 100.00 0.0000 70.196 0.0000 9.4400 20.050 13.750
+560 "R49" 100.00 10.196 70.196 0.0000 8.6300 17.670 12.510
+561 "K35" 100.00 20.000 70.196 0.0000 7.9400 15.540 11.370
+562 "W17" 100.00 29.804 70.196 0.0000 7.2400 13.420 10.240
+563 "M32" 100.00 40.000 70.196 0.0000 6.5800 11.440 9.1600
+564 "Z16" 100.00 54.902 70.196 0.0000 5.7500 8.8500 7.6900
+565 "O32" 100.00 70.196 70.196 0.0000 5.0400 6.7700 6.4100
+566 "E3" 100.00 85.098 70.196 0.0000 4.4900 5.2000 5.3600
+567 "H16" 100.00 100.00 70.196 0.0000 4.0200 3.9800 4.4800
+568 "J8" 0.0000 0.0000 85.098 0.0000 68.430 73.430 10.410
+569 "Q51" 0.0000 10.196 85.098 0.0000 62.490 64.260 9.2600
+570 "L51" 0.0000 20.000 85.098 0.0000 57.100 56.050 8.3900
+571 "Z26" 0.0000 29.804 85.098 0.0000 52.030 48.310 7.4600
+572 "G8" 0.0000 40.000 85.098 0.0000 47.370 41.250 6.5500
+573 "S56" 0.0000 54.902 85.098 0.0000 41.420 32.200 5.4000
+574 "AA30" 0.0000 70.196 85.098 0.0000 36.460 25.040 4.4200
+575 "E18" 0.0000 85.098 85.098 0.0000 33.070 20.020 3.6500
+576 "K48" 0.0000 100.00 85.098 0.0000 30.360 16.240 3.0200
+577 "B2" 10.196 0.0000 85.098 0.0000 60.350 66.640 10.190
+578 "T35" 10.196 10.196 85.098 0.0000 55.320 58.620 9.2000
+579 "V8" 10.196 20.000 85.098 0.0000 50.600 51.150 8.3400
+580 "T41" 10.196 29.804 85.098 0.0000 46.130 44.150 7.4400
+581 "H24" 10.196 40.000 85.098 0.0000 42.000 37.750 6.5500
+582 "C46" 10.196 54.902 85.098 0.0000 36.660 29.410 5.3900
+583 "C1" 10.196 70.196 85.098 0.0000 32.180 22.780 4.4100
+584 "D19" 10.196 85.098 85.098 0.0000 29.130 18.110 3.6700
+585 "P20" 10.196 100.00 85.098 0.0000 26.690 14.580 3.0600
+586 "U9" 20.000 0.0000 85.098 0.0000 52.310 59.720 9.9000
+587 "Y5" 20.000 10.196 85.098 0.0000 47.960 52.550 9.0200
+588 "C13" 20.000 20.000 85.098 0.0000 43.970 45.950 8.1400
+589 "Y51" 20.000 29.804 85.098 0.0000 40.050 39.610 7.2600
+590 "AA10" 20.000 40.000 85.098 0.0000 36.390 33.790 6.4300
+591 "A29" 20.000 54.902 85.098 0.0000 31.730 26.280 5.2800
+592 "AA19" 20.000 70.196 85.098 0.0000 27.830 20.300 4.3100
+593 "C53" 20.000 85.098 85.098 0.0000 25.180 16.080 3.6100
+594 "U28" 20.000 100.00 85.098 0.0000 23.040 12.880 3.0500
+595 "A13" 29.804 0.0000 85.098 0.0000 44.520 52.890 9.7300
+596 "U23" 29.804 10.196 85.098 0.0000 40.790 46.510 8.8100
+597 "U21" 29.804 20.000 85.098 0.0000 37.450 40.750 8.0000
+598 "I52" 29.804 29.804 85.098 0.0000 34.100 35.100 7.1400
+599 "M53" 29.804 40.000 85.098 0.0000 30.950 29.880 6.3100
+600 "T20" 29.804 54.902 85.098 0.0000 26.950 23.190 5.2100
+601 "G18" 29.804 70.196 85.098 0.0000 23.610 17.870 4.2800
+602 "E27" 29.804 85.098 85.098 0.0000 21.330 14.090 3.6000
+603 "M11" 29.804 100.00 85.098 0.0000 19.500 11.220 3.0500
+604 "A35" 40.000 0.0000 85.098 0.0000 37.360 46.510 9.5900
+605 "Q5" 40.000 10.196 85.098 0.0000 34.210 40.890 8.6200
+606 "N56" 40.000 20.000 85.098 0.0000 31.430 35.860 7.9100
+607 "E52" 40.000 29.804 85.098 0.0000 28.620 30.880 7.0700
+608 "D29" 40.000 40.000 85.098 0.0000 25.980 26.280 6.2400
+609 "R4" 40.000 54.902 85.098 0.0000 22.590 20.350 5.1700
+610 "J27" 40.000 70.196 85.098 0.0000 19.760 15.630 4.2800
+611 "K56" 40.000 85.098 85.098 0.0000 17.820 12.260 3.6200
+612 "D20" 40.000 100.00 85.098 0.0000 16.260 9.7000 3.0700
+613 "I14" 54.902 0.0000 85.098 0.0000 28.140 38.070 9.3200
+614 "R33" 54.902 10.196 85.098 0.0000 25.790 33.510 8.4400
+615 "I24" 54.902 20.000 85.098 0.0000 23.570 29.290 7.7800
+616 "Y29" 54.902 29.804 85.098 0.0000 21.530 25.290 7.0200
+617 "V3" 54.902 40.000 85.098 0.0000 19.630 21.590 6.2400
+618 "L26" 54.902 54.902 85.098 0.0000 17.020 16.690 5.1800
+619 "I53" 54.902 70.196 85.098 0.0000 14.810 12.750 4.2900
+620 "Z17" 54.902 85.098 85.098 0.0000 13.300 9.9200 3.6500
+621 "O10" 54.902 100.00 85.098 0.0000 12.080 7.7600 3.1300
+622 "A24" 70.196 0.0000 85.098 0.0000 20.310 30.710 9.0900
+623 "I33" 70.196 10.196 85.098 0.0000 18.650 27.080 8.3300
+624 "K49" 70.196 20.000 85.098 0.0000 16.970 23.600 7.6800
+625 "N8" 70.196 29.804 85.098 0.0000 15.540 20.420 6.9800
+626 "A10" 70.196 40.000 85.098 0.0000 14.240 17.500 6.2700
+627 "J4" 70.196 54.902 85.098 0.0000 12.330 13.510 5.2100
+628 "M29" 70.196 70.196 85.098 0.0000 10.690 10.280 4.3200
+629 "N34" 70.196 85.098 85.098 0.0000 9.5500 7.9500 3.6900
+630 "Q10" 70.196 100.00 85.098 0.0000 8.6400 6.1600 3.1800
+631 "O6" 85.098 0.0000 85.098 0.0000 13.780 24.590 9.1200
+632 "Q53" 85.098 10.196 85.098 0.0000 12.670 21.710 8.3700
+633 "AA24" 85.098 20.000 85.098 0.0000 11.550 18.950 7.7100
+634 "G43" 85.098 29.804 85.098 0.0000 10.580 16.400 7.0200
+635 "P38" 85.098 40.000 85.098 0.0000 9.6900 14.050 6.3400
+636 "D12" 85.098 54.902 85.098 0.0000 8.4200 10.860 5.3200
+637 "H2" 85.098 70.196 85.098 0.0000 7.3300 8.2700 4.4400
+638 "Q12" 85.098 85.098 85.098 0.0000 6.5500 6.3700 3.7700
+639 "E35" 85.098 100.00 85.098 0.0000 5.9100 4.9100 3.2100
+640 "U1" 100.00 0.0000 85.098 0.0000 8.6800 19.390 9.2000
+641 "F53" 100.00 10.196 85.098 0.0000 7.9800 17.120 8.4600
+642 "L25" 100.00 20.000 85.098 0.0000 7.3400 15.040 7.7500
+643 "U15" 100.00 29.804 85.098 0.0000 6.7100 13.000 7.0600
+644 "W11" 100.00 40.000 85.098 0.0000 6.1100 11.110 6.4000
+645 "X6" 100.00 54.902 85.098 0.0000 5.3500 8.6100 5.4400
+646 "L40" 100.00 70.196 85.098 0.0000 4.7100 6.5900 4.5900
+647 "M37" 100.00 85.098 85.098 0.0000 4.2100 5.0800 3.8600
+648 "S33" 100.00 100.00 85.098 0.0000 3.8000 3.9100 3.2300
+649 "A2" 0.0000 0.0000 100.00 0.0000 67.430 72.230 6.1400
+650 "H56" 0.0000 10.196 100.00 0.0000 61.540 63.120 5.4400
+651 "G2" 0.0000 20.000 100.00 0.0000 56.250 55.090 4.9800
+652 "O22" 0.0000 29.804 100.00 0.0000 51.340 47.560 4.5000
+653 "X37" 0.0000 40.000 100.00 0.0000 46.820 40.680 4.0200
+654 "M16" 0.0000 54.902 100.00 0.0000 40.930 31.740 3.3500
+655 "N24" 0.0000 70.196 100.00 0.0000 36.020 24.690 2.7900
+656 "P2" 0.0000 85.098 100.00 0.0000 32.750 19.830 2.4100
+657 "G42" 0.0000 100.00 100.00 0.0000 30.180 16.190 2.1100
+658 "B3" 10.196 0.0000 100.00 0.0000 59.400 65.500 6.0300
+659 "K14" 10.196 10.196 100.00 0.0000 54.490 57.660 5.4100
+660 "Z43" 10.196 20.000 100.00 0.0000 49.880 50.340 4.9600
+661 "Z48" 10.196 29.804 100.00 0.0000 45.510 43.480 4.4700
+662 "Q40" 10.196 40.000 100.00 0.0000 41.480 37.210 3.9800
+663 "D10" 10.196 54.902 100.00 0.0000 36.280 29.070 3.3500
+664 "B48" 10.196 70.196 100.00 0.0000 31.910 22.580 2.8200
+665 "Q20" 10.196 85.098 100.00 0.0000 28.920 17.990 2.4500
+666 "C31" 10.196 100.00 100.00 0.0000 26.500 14.500 2.1500
+667 "W14" 20.000 0.0000 100.00 0.0000 51.490 58.710 5.8500
+668 "A31" 20.000 10.196 100.00 0.0000 47.230 51.690 5.3000
+669 "C7" 20.000 20.000 100.00 0.0000 43.430 45.310 4.8600
+670 "X50" 20.000 29.804 100.00 0.0000 39.600 39.120 4.3900
+671 "A6" 20.000 40.000 100.00 0.0000 35.980 33.390 3.9300
+672 "L17" 20.000 54.902 100.00 0.0000 31.380 25.970 3.3100
+673 "U47" 20.000 70.196 100.00 0.0000 27.540 20.080 2.7900
+674 "N40" 20.000 85.098 100.00 0.0000 24.950 15.950 2.4400
+675 "S57" 20.000 100.00 100.00 0.0000 22.890 12.830 2.1600
+676 "T46" 29.804 0.0000 100.00 0.0000 43.750 51.970 5.7800
+677 "F56" 29.804 10.196 100.00 0.0000 40.230 45.810 5.2200
+678 "F15" 29.804 20.000 100.00 0.0000 37.010 40.220 4.8000
+679 "P29" 29.804 29.804 100.00 0.0000 33.680 34.640 4.3400
+680 "H40" 29.804 40.000 100.00 0.0000 30.540 29.480 3.9000
+681 "P57" 29.804 54.902 100.00 0.0000 26.590 22.880 3.3000
+682 "E39" 29.804 70.196 100.00 0.0000 23.310 17.660 2.8000
+683 "Z10" 29.804 85.098 100.00 0.0000 21.090 13.970 2.4500
+684 "Q32" 29.804 100.00 100.00 0.0000 19.320 11.170 2.1700
+685 "Q31" 40.000 0.0000 100.00 0.0000 36.650 45.670 5.7400
+686 "W47" 40.000 10.196 100.00 0.0000 33.800 40.340 5.1800
+687 "T39" 40.000 20.000 100.00 0.0000 31.030 35.390 4.7700
+688 "B24" 40.000 29.804 100.00 0.0000 28.210 30.420 4.3300
+689 "S36" 40.000 40.000 100.00 0.0000 25.560 25.850 3.8900
+690 "D23" 40.000 54.902 100.00 0.0000 22.240 20.050 3.3200
+691 "W1" 40.000 70.196 100.00 0.0000 19.480 15.450 2.8300
+692 "K52" 40.000 85.098 100.00 0.0000 17.580 12.160 2.4800
+693 "I37" 40.000 100.00 100.00 0.0000 16.060 9.6400 2.1900
+694 "G27" 54.902 0.0000 100.00 0.0000 27.620 37.430 5.6700
+695 "B9" 54.902 10.196 100.00 0.0000 25.500 33.120 5.1700
+696 "F40" 54.902 20.000 100.00 0.0000 23.220 28.890 4.7800
+697 "G16" 54.902 29.804 100.00 0.0000 21.180 24.900 4.3600
+698 "L9" 54.902 40.000 100.00 0.0000 19.320 21.260 3.9400
+699 "S37" 54.902 54.902 100.00 0.0000 16.760 16.460 3.3700
+700 "L56" 54.902 70.196 100.00 0.0000 14.590 12.610 2.8900
+701 "H47" 54.902 85.098 100.00 0.0000 13.090 9.8300 2.5300
+702 "Y56" 54.902 100.00 100.00 0.0000 11.880 7.7100 2.2400
+703 "S26" 70.196 0.0000 100.00 0.0000 19.890 30.210 5.6200
+704 "E9" 70.196 10.196 100.00 0.0000 18.370 26.750 5.2000
+705 "R11" 70.196 20.000 100.00 0.0000 16.620 23.220 4.8300
+706 "T30" 70.196 29.804 100.00 0.0000 15.220 20.080 4.4200
+707 "X40" 70.196 40.000 100.00 0.0000 13.980 17.240 4.0200
+708 "O31" 70.196 54.902 100.00 0.0000 12.100 13.330 3.4500
+709 "Y6" 70.196 70.196 100.00 0.0000 10.490 10.160 2.9600
+710 "G26" 70.196 85.098 100.00 0.0000 9.3600 7.8700 2.5900
+711 "A52" 70.196 100.00 100.00 0.0000 8.4500 6.1000 2.2800
+712 "B56" 85.098 0.0000 100.00 0.0000 13.310 24.080 5.7300
+713 "F48" 85.098 10.196 100.00 0.0000 12.310 21.330 5.3500
+714 "Y28" 85.098 20.000 100.00 0.0000 11.170 18.560 4.9800
+715 "K13" 85.098 29.804 100.00 0.0000 10.230 16.070 4.5900
+716 "U17" 85.098 40.000 100.00 0.0000 9.4000 13.810 4.2100
+717 "L55" 85.098 54.902 100.00 0.0000 8.1700 10.690 3.6300
+718 "F8" 85.098 70.196 100.00 0.0000 7.1000 8.1500 3.1100
+719 "D37" 85.098 85.098 100.00 0.0000 6.3500 6.2900 2.6800
+720 "K44" 85.098 100.00 100.00 0.0000 5.7300 4.8500 2.3000
+721 "D56" 100.00 0.0000 100.00 0.0000 8.1500 18.840 5.8600
+722 "J41" 100.00 10.196 100.00 0.0000 7.5400 16.690 5.5300
+723 "Z46" 100.00 20.000 100.00 0.0000 6.9300 14.620 5.1500
+724 "L36" 100.00 29.804 100.00 0.0000 6.3300 12.660 4.7900
+725 "M20" 100.00 40.000 100.00 0.0000 5.7800 10.860 4.4300
+726 "E1" 100.00 54.902 100.00 0.0000 5.0700 8.4400 3.8400
+727 "R1" 100.00 70.196 100.00 0.0000 4.4600 6.4700 3.2900
+728 "N48" 100.00 85.098 100.00 0.0000 4.0000 5.0000 2.7700
+729 "K6" 100.00 100.00 100.00 0.0000 3.6300 3.8400 2.3100
+730 "AA40" 0.0000 0.0000 0.0000 20.000 58.360 60.610 53.170
+731 "D43" 0.0000 10.196 0.0000 20.000 53.610 53.700 48.160
+732 "E29" 0.0000 20.000 0.0000 20.000 48.890 47.040 42.950
+733 "D54" 0.0000 40.000 0.0000 20.000 40.030 34.580 32.840
+734 "F49" 0.0000 70.196 0.0000 20.000 29.450 20.200 19.890
+735 "B5" 0.0000 100.00 0.0000 20.000 23.380 12.170 11.950
+736 "U31" 10.196 0.0000 0.0000 20.000 52.670 55.730 51.910
+737 "V38" 10.196 10.196 0.0000 20.000 48.300 49.300 47.050
+738 "P46" 10.196 20.000 0.0000 20.000 44.110 43.230 41.990
+739 "X29" 10.196 40.000 0.0000 20.000 36.000 31.630 32.080
+740 "J7" 10.196 70.196 0.0000 20.000 26.440 18.410 19.540
+741 "M31" 10.196 100.00 0.0000 20.000 20.820 10.960 11.830
+742 "P35" 20.000 0.0000 0.0000 20.000 46.630 50.470 50.570
+743 "B25" 20.000 10.196 0.0000 20.000 42.900 44.780 45.930
+744 "U25" 20.000 20.000 0.0000 20.000 39.260 39.330 41.130
+745 "N32" 20.000 40.000 0.0000 20.000 31.990 28.770 31.460
+746 "H39" 20.000 70.196 0.0000 20.000 23.430 16.720 19.310
+747 "Z22" 20.000 100.00 0.0000 20.000 18.200 9.7200 11.760
+748 "Q7" 40.000 0.0000 0.0000 20.000 34.990 40.080 47.760
+749 "L37" 40.000 10.196 0.0000 20.000 32.140 35.530 43.290
+750 "S28" 40.000 20.000 0.0000 20.000 29.450 31.220 38.810
+751 "T9" 40.000 40.000 0.0000 20.000 24.220 23.070 30.090
+752 "F16" 40.000 70.196 0.0000 20.000 17.690 13.370 18.770
+753 "M5" 40.000 100.00 0.0000 20.000 13.490 7.5300 11.800
+754 "S47" 70.196 0.0000 0.0000 20.000 21.560 27.570 43.680
+755 "M49" 70.196 10.196 0.0000 20.000 19.770 24.420 39.700
+756 "Z20" 70.196 20.000 0.0000 20.000 18.090 21.460 35.760
+757 "T23" 70.196 40.000 0.0000 20.000 14.830 15.810 27.910
+758 "H38" 70.196 70.196 0.0000 20.000 10.900 9.2900 18.290
+759 "X22" 70.196 100.00 0.0000 20.000 8.1500 5.0700 11.840
+760 "C5" 100.00 0.0000 0.0000 20.000 12.040 18.260 40.230
+761 "X23" 100.00 10.196 0.0000 20.000 11.030 16.160 36.800
+762 "F12" 100.00 20.000 0.0000 20.000 10.110 14.230 33.300
+763 "F2" 100.00 40.000 0.0000 20.000 8.3400 10.560 26.580
+764 "J38" 100.00 70.196 0.0000 20.000 6.0600 6.1100 17.550
+765 "P17" 100.00 100.00 0.0000 20.000 4.6900 3.5400 12.120
+766 "H19" 0.0000 0.0000 10.196 20.000 56.880 59.490 46.150
+767 "E33" 0.0000 10.196 10.196 20.000 52.190 52.650 41.710
+768 "P3" 0.0000 20.000 10.196 20.000 47.710 46.180 37.310
+769 "X18" 0.0000 40.000 10.196 20.000 39.230 34.050 28.660
+770 "M25" 0.0000 70.196 10.196 20.000 29.010 19.950 17.420
+771 "R52" 0.0000 100.00 10.196 20.000 23.130 12.140 10.560
+772 "Q47" 10.196 0.0000 10.196 20.000 51.250 54.670 45.100
+773 "H26" 10.196 10.196 10.196 20.000 47.100 48.480 40.930
+774 "K26" 10.196 20.000 10.196 20.000 43.060 42.530 36.640
+775 "AA42" 10.196 40.000 10.196 20.000 35.260 31.210 28.100
+776 "B6" 10.196 70.196 10.196 20.000 26.070 18.250 17.170
+777 "X33" 10.196 100.00 10.196 20.000 20.700 11.000 10.520
+778 "Q28" 20.000 0.0000 10.196 20.000 45.440 49.660 44.000
+779 "R13" 20.000 10.196 10.196 20.000 41.760 44.000 39.930
+780 "F35" 20.000 20.000 10.196 20.000 38.190 38.630 35.730
+781 "L4" 20.000 40.000 10.196 20.000 31.230 28.300 27.390
+782 "AA8" 20.000 70.196 10.196 20.000 23.050 16.570 16.940
+783 "S32" 20.000 100.00 10.196 20.000 18.110 9.7800 10.400
+784 "N6" 40.000 0.0000 10.196 20.000 34.000 39.460 41.260
+785 "J19" 40.000 10.196 10.196 20.000 31.250 34.980 37.540
+786 "T38" 40.000 20.000 10.196 20.000 28.630 30.760 33.670
+787 "X54" 40.000 40.000 10.196 20.000 23.490 22.650 26.130
+788 "W27" 40.000 70.196 10.196 20.000 17.270 13.220 16.460
+789 "V47" 40.000 100.00 10.196 20.000 13.270 7.5000 10.250
+790 "R36" 70.196 0.0000 10.196 20.000 20.640 27.060 37.720
+791 "E43" 70.196 10.196 10.196 20.000 18.930 23.970 34.350
+792 "B46" 70.196 20.000 10.196 20.000 17.350 21.100 31.070
+793 "G22" 70.196 40.000 10.196 20.000 14.290 15.580 24.370
+794 "T52" 70.196 70.196 10.196 20.000 10.520 9.1300 15.900
+795 "V17" 70.196 100.00 10.196 20.000 8.0400 5.1100 10.360
+796 "V55" 100.00 0.0000 10.196 20.000 11.150 17.780 34.660
+797 "I31" 100.00 10.196 10.196 20.000 10.300 15.850 31.840
+798 "Y27" 100.00 20.000 10.196 20.000 9.3900 13.900 28.800
+799 "C10" 100.00 40.000 10.196 20.000 7.7200 10.240 22.890
+800 "D17" 100.00 70.196 10.196 20.000 5.7400 6.0400 15.400
+801 "S2" 100.00 100.00 10.196 20.000 4.5000 3.5400 10.610
+802 "E10" 0.0000 0.0000 20.000 20.000 55.510 58.460 39.620
+803 "Z41" 0.0000 10.196 20.000 20.000 50.960 51.730 35.790
+804 "M33" 0.0000 20.000 20.000 20.000 46.740 45.520 32.240
+805 "H7" 0.0000 40.000 20.000 20.000 38.550 33.640 24.800
+806 "Z49" 0.0000 70.196 20.000 20.000 28.750 19.910 15.170
+807 "Y34" 0.0000 100.00 20.000 20.000 22.950 12.130 9.1700
+808 "F50" 10.196 0.0000 20.000 20.000 49.930 53.690 38.630
+809 "T50" 10.196 10.196 20.000 20.000 45.960 47.660 35.140
+810 "B15" 10.196 20.000 20.000 20.000 42.160 41.940 31.690
+811 "T15" 10.196 40.000 20.000 20.000 34.670 30.910 24.370
+812 "M14" 10.196 70.196 20.000 20.000 25.720 18.140 14.980
+813 "G28" 10.196 100.00 20.000 20.000 20.500 10.980 9.1400
+814 "F54" 20.000 0.0000 20.000 20.000 44.240 48.780 37.640
+815 "J57" 20.000 10.196 20.000 20.000 40.710 43.270 34.210
+816 "L45" 20.000 20.000 20.000 20.000 37.360 38.130 30.870
+817 "V19" 20.000 40.000 20.000 20.000 30.580 27.960 23.650
+818 "Y31" 20.000 70.196 20.000 20.000 22.700 16.440 14.690
+819 "D15" 20.000 100.00 20.000 20.000 17.930 9.7800 9.0200
+820 "I8" 40.000 0.0000 20.000 20.000 32.900 38.690 35.070
+821 "A30" 40.000 10.196 20.000 20.000 30.310 34.340 31.940
+822 "M46" 40.000 20.000 20.000 20.000 27.800 30.230 28.830
+823 "L14" 40.000 40.000 20.000 20.000 22.920 22.350 22.560
+824 "U16" 40.000 70.196 20.000 20.000 16.870 13.030 14.140
+825 "J9" 40.000 100.00 20.000 20.000 13.160 7.5500 8.8800
+826 "G40" 70.196 0.0000 20.000 20.000 19.890 26.630 32.070
+827 "B26" 70.196 10.196 20.000 20.000 18.280 23.600 29.330
+828 "Z34" 70.196 20.000 20.000 20.000 16.800 20.840 26.720
+829 "X2" 70.196 40.000 20.000 20.000 13.770 15.330 20.890
+830 "F52" 70.196 70.196 20.000 20.000 10.250 9.0300 13.770
+831 "C30" 70.196 100.00 20.000 20.000 7.8800 5.1400 9.0600
+832 "W6" 100.00 0.0000 20.000 20.000 10.390 17.380 29.450
+833 "I28" 100.00 10.196 20.000 20.000 9.5600 15.440 27.010
+834 "U40" 100.00 20.000 20.000 20.000 8.7700 13.580 24.530
+835 "N15" 100.00 40.000 20.000 20.000 7.2200 9.9900 19.600
+836 "T3" 100.00 70.196 20.000 20.000 5.4100 5.9200 13.300
+837 "Y4" 100.00 100.00 20.000 20.000 4.2800 3.5200 9.1000
+838 "I46" 0.0000 0.0000 40.000 20.000 52.880 56.400 27.260
+839 "D16" 0.0000 10.196 40.000 20.000 48.700 50.030 24.750
+840 "L1" 0.0000 20.000 40.000 20.000 44.640 43.970 22.250
+841 "AA38" 0.0000 40.000 40.000 20.000 37.100 32.640 17.260
+842 "U51" 0.0000 70.196 40.000 20.000 27.990 19.520 10.690
+843 "X15" 0.0000 100.00 40.000 20.000 22.690 12.240 6.6600
+844 "F44" 10.196 0.0000 40.000 20.000 47.390 51.700 26.810
+845 "L49" 10.196 10.196 40.000 20.000 43.700 45.940 24.510
+846 "G45" 10.196 20.000 40.000 20.000 40.200 40.510 22.100
+847 "D51" 10.196 40.000 40.000 20.000 33.150 29.870 16.970
+848 "B8" 10.196 70.196 40.000 20.000 25.010 17.910 10.620
+849 "Z51" 10.196 100.00 40.000 20.000 20.260 11.120 6.6900
+850 "H18" 20.000 0.0000 40.000 20.000 41.770 46.840 26.030
+851 "J52" 20.000 10.196 40.000 20.000 38.570 41.670 23.900
+852 "R48" 20.000 20.000 40.000 20.000 35.500 36.770 21.500
+853 "X47" 20.000 40.000 40.000 20.000 29.090 26.920 16.440
+854 "R22" 20.000 70.196 40.000 20.000 21.980 16.200 10.430
+855 "X3" 20.000 100.00 40.000 20.000 17.710 9.9100 6.6500
+856 "F42" 40.000 0.0000 40.000 20.000 31.120 37.440 24.580
+857 "M38" 40.000 10.196 40.000 20.000 28.550 33.110 22.510
+858 "E14" 40.000 20.000 40.000 20.000 26.350 29.270 20.340
+859 "O57" 40.000 40.000 40.000 20.000 21.530 21.410 15.830
+860 "K43" 40.000 70.196 40.000 20.000 16.100 12.750 10.160
+861 "Z29" 40.000 100.00 40.000 20.000 12.980 7.6800 6.5500
+862 "U12" 70.196 0.0000 40.000 20.000 18.220 25.500 22.460
+863 "X8" 70.196 10.196 40.000 20.000 16.710 22.500 20.530
+864 "C54" 70.196 20.000 40.000 20.000 15.280 19.750 18.590
+865 "A45" 70.196 40.000 40.000 20.000 12.400 14.380 14.520
+866 "D33" 70.196 70.196 40.000 20.000 9.6100 8.8200 9.8600
+867 "T11" 70.196 100.00 40.000 20.000 7.6300 5.2000 6.6300
+868 "R10" 100.00 0.0000 40.000 20.000 9.0700 16.580 20.850
+869 "N36" 100.00 10.196 40.000 20.000 8.3600 14.700 19.230
+870 "R23" 100.00 20.000 40.000 20.000 7.6900 12.940 17.480
+871 "E32" 100.00 40.000 40.000 20.000 6.3600 9.5600 13.950
+872 "K11" 100.00 70.196 40.000 20.000 4.8700 5.7800 9.4800
+873 "D9" 100.00 100.00 40.000 20.000 3.9100 3.4700 6.5600
+874 "P33" 0.0000 0.0000 70.196 20.000 49.570 53.360 12.660
+875 "AA2" 0.0000 10.196 70.196 20.000 45.630 47.300 11.410
+876 "A41" 0.0000 20.000 70.196 20.000 41.930 41.640 10.340
+877 "T29" 0.0000 40.000 70.196 20.000 34.960 30.980 8.0400
+878 "I26" 0.0000 70.196 70.196 20.000 26.980 19.010 5.3600
+879 "H54" 0.0000 100.00 70.196 20.000 22.180 12.160 3.5200
+880 "O49" 10.196 0.0000 70.196 20.000 44.230 48.860 12.400
+881 "B16" 10.196 10.196 70.196 20.000 40.810 43.440 11.330
+882 "E38" 10.196 20.000 70.196 20.000 37.540 38.270 10.270
+883 "I50" 10.196 40.000 70.196 20.000 31.320 28.550 8.0400
+884 "P10" 10.196 70.196 70.196 20.000 24.050 17.420 5.3200
+885 "I43" 10.196 100.00 70.196 20.000 19.800 11.070 3.5500
+886 "W57" 20.000 0.0000 70.196 20.000 38.780 44.170 12.050
+887 "W50" 20.000 10.196 70.196 20.000 35.800 39.280 11.080
+888 "AA57" 20.000 20.000 70.196 20.000 32.940 34.620 9.9900
+889 "N35" 20.000 40.000 70.196 20.000 27.400 25.720 7.8500
+890 "H15" 20.000 70.196 70.196 20.000 21.110 15.740 5.1900
+891 "F28" 20.000 100.00 70.196 20.000 17.340 9.9100 3.5300
+892 "W22" 40.000 0.0000 70.196 20.000 28.430 35.030 11.550
+893 "O29" 40.000 10.196 70.196 20.000 26.060 31.010 10.480
+894 "D55" 40.000 20.000 70.196 20.000 24.080 27.430 9.6200
+895 "F31" 40.000 40.000 70.196 20.000 20.060 20.410 7.5400
+896 "Y50" 40.000 70.196 70.196 20.000 15.440 12.420 5.1000
+897 "N20" 40.000 100.00 70.196 20.000 12.700 7.6900 3.5200
+898 "X19" 70.196 0.0000 70.196 20.000 16.050 23.620 10.700
+899 "Q48" 70.196 10.196 70.196 20.000 14.770 20.950 9.8000
+900 "M6" 70.196 20.000 70.196 20.000 13.560 18.450 9.0300
+901 "B27" 70.196 40.000 70.196 20.000 11.410 13.790 7.2800
+902 "H51" 70.196 70.196 70.196 20.000 8.8300 8.4300 4.9700
+903 "Y32" 70.196 100.00 70.196 20.000 7.2300 5.1400 3.6000
+904 "V20" 100.00 0.0000 70.196 20.000 7.3300 15.200 10.370
+905 "AA11" 100.00 10.196 70.196 20.000 6.7500 13.480 9.4800
+906 "J16" 100.00 20.000 70.196 20.000 6.2500 11.920 8.6400
+907 "P36" 100.00 40.000 70.196 20.000 5.2300 8.8200 6.9600
+908 "E6" 100.00 70.196 70.196 20.000 4.1700 5.4400 4.9700
+909 "S49" 100.00 100.00 70.196 20.000 3.4700 3.4000 3.6200
+910 "O27" 0.0000 0.0000 100.00 20.000 47.580 51.210 4.9300
+911 "V14" 0.0000 10.196 100.00 20.000 43.710 45.260 4.4100
+912 "X41" 0.0000 20.000 100.00 20.000 40.190 39.890 4.0700
+913 "M9" 0.0000 40.000 100.00 20.000 33.690 29.870 3.3200
+914 "D41" 0.0000 70.196 100.00 20.000 26.080 18.400 2.3900
+915 "Q17" 0.0000 100.00 100.00 20.000 21.830 12.070 1.8800
+916 "X35" 10.196 0.0000 100.00 20.000 42.290 46.780 4.8300
+917 "K40" 10.196 10.196 100.00 20.000 39.070 41.650 4.3700
+918 "W54" 10.196 20.000 100.00 20.000 36.010 36.770 4.0400
+919 "R12" 10.196 40.000 100.00 20.000 30.270 27.640 3.2800
+920 "Y22" 10.196 70.196 100.00 20.000 23.500 17.090 2.4000
+921 "AA17" 10.196 100.00 100.00 20.000 19.450 10.960 1.9100
+922 "I22" 20.000 0.0000 100.00 20.000 37.000 42.250 4.6800
+923 "L3" 20.000 10.196 100.00 20.000 34.220 37.660 4.2800
+924 "O54" 20.000 20.000 100.00 20.000 31.710 33.400 3.9500
+925 "K10" 20.000 40.000 100.00 20.000 26.660 25.130 3.2300
+926 "F11" 20.000 70.196 100.00 20.000 20.670 15.470 2.3800
+927 "S30" 20.000 100.00 100.00 20.000 17.060 9.8400 1.9200
+928 "B32" 40.000 0.0000 100.00 20.000 26.840 33.370 4.5700
+929 "P19" 40.000 10.196 100.00 20.000 25.020 29.910 4.1600
+930 "B28" 40.000 20.000 100.00 20.000 23.240 26.630 3.8600
+931 "D14" 40.000 40.000 100.00 20.000 19.630 20.050 3.1900
+932 "P55" 40.000 70.196 100.00 20.000 15.250 12.380 2.4100
+933 "Q25" 40.000 100.00 100.00 20.000 12.380 7.6200 1.9400
+934 "V29" 70.196 0.0000 100.00 20.000 15.020 22.560 4.4700
+935 "X36" 70.196 10.196 100.00 20.000 14.080 20.300 4.1600
+936 "C47" 70.196 20.000 100.00 20.000 12.930 17.920 3.8800
+937 "P40" 70.196 40.000 100.00 20.000 11.220 13.740 3.2600
+938 "K53" 70.196 70.196 100.00 20.000 8.6700 8.4500 2.4900
+939 "X20" 70.196 100.00 100.00 20.000 6.9400 5.0900 2.0100
+940 "H10" 100.00 0.0000 100.00 20.000 6.2800 14.140 4.6600
+941 "G33" 100.00 10.196 100.00 20.000 5.8900 12.680 4.4000
+942 "Y23" 100.00 20.000 100.00 20.000 5.4800 11.230 4.1000
+943 "X45" 100.00 40.000 100.00 20.000 4.6900 8.4700 3.5000
+944 "P24" 100.00 70.196 100.00 20.000 3.8000 5.3200 2.6800
+945 "O4" 100.00 100.00 100.00 20.000 3.2300 3.3700 2.0200
+946 "I18" 0.0000 0.0000 0.0000 40.000 35.870 37.330 32.950
+947 "Y26" 0.0000 20.000 0.0000 40.000 30.230 29.160 26.800
+948 "V25" 0.0000 40.000 0.0000 40.000 25.150 21.930 20.960
+949 "AA36" 0.0000 70.196 0.0000 40.000 18.700 13.060 12.860
+950 "U27" 0.0000 100.00 0.0000 40.000 14.740 7.8300 7.6100
+951 "D35" 20.000 0.0000 0.0000 40.000 28.670 31.130 31.220
+952 "V45" 20.000 20.000 0.0000 40.000 24.270 24.370 25.550
+953 "W35" 20.000 40.000 0.0000 40.000 20.090 18.170 19.960
+954 "O53" 20.000 70.196 0.0000 40.000 14.900 10.780 12.360
+955 "AA49" 20.000 100.00 0.0000 40.000 11.690 6.3800 7.4900
+956 "P42" 40.000 0.0000 0.0000 40.000 21.620 24.850 29.390
+957 "M1" 40.000 20.000 0.0000 40.000 18.280 19.370 23.990
+958 "K21" 40.000 40.000 0.0000 40.000 15.230 14.510 18.930
+959 "K7" 40.000 70.196 0.0000 40.000 11.320 8.6100 11.900
+960 "T24" 40.000 100.00 0.0000 40.000 8.9100 5.1000 7.5200
+961 "C16" 70.196 0.0000 0.0000 40.000 13.500 17.280 26.810
+962 "E56" 70.196 20.000 0.0000 40.000 11.420 13.450 22.040
+963 "D32" 70.196 40.000 0.0000 40.000 9.5400 10.080 17.500
+964 "L21" 70.196 70.196 0.0000 40.000 7.2400 6.1400 11.590
+965 "AA7" 70.196 100.00 0.0000 40.000 5.6800 3.6200 7.5800
+966 "M22" 100.00 0.0000 0.0000 40.000 7.6800 11.640 24.760
+967 "I2" 100.00 20.000 0.0000 40.000 6.5800 9.1700 20.590
+968 "N9" 100.00 40.000 0.0000 40.000 5.6100 7.0000 16.710
+969 "V24" 100.00 70.196 0.0000 40.000 4.3200 4.3200 11.260
+970 "Z9" 100.00 100.00 0.0000 40.000 3.4900 2.6700 7.8400
+971 "I32" 0.0000 0.0000 20.000 40.000 34.040 35.930 24.620
+972 "V40" 0.0000 20.000 20.000 40.000 28.830 28.170 20.180
+973 "V27" 0.0000 40.000 20.000 40.000 24.160 21.290 15.890
+974 "C43" 0.0000 70.196 20.000 40.000 18.230 12.870 9.8700
+975 "G21" 0.0000 100.00 20.000 40.000 14.540 7.8700 5.9600
+976 "K36" 20.000 0.0000 20.000 40.000 27.120 30.010 23.330
+977 "V23" 20.000 20.000 20.000 40.000 23.040 23.560 19.260
+978 "Z5" 20.000 40.000 20.000 40.000 19.150 17.630 15.090
+979 "Z44" 20.000 70.196 20.000 40.000 14.420 10.600 9.4800
+980 "Q27" 20.000 100.00 20.000 40.000 11.510 6.4500 5.8500
+981 "E4" 40.000 0.0000 20.000 40.000 20.240 23.890 21.670
+982 "H5" 40.000 20.000 20.000 40.000 17.200 18.700 17.940
+983 "R8" 40.000 40.000 20.000 40.000 14.380 14.040 14.320
+984 "G5" 40.000 70.196 20.000 40.000 10.790 8.4100 9.0500
+985 "R2" 40.000 100.00 20.000 40.000 8.6400 5.1000 5.7400
+986 "C49" 70.196 0.0000 20.000 40.000 12.450 16.670 19.850
+987 "W4" 70.196 20.000 20.000 40.000 10.620 13.080 16.640
+988 "U37" 70.196 40.000 20.000 40.000 8.8900 9.8000 13.270
+989 "S45" 70.196 70.196 20.000 40.000 6.8300 6.0200 8.8200
+990 "C27" 70.196 100.00 20.000 40.000 5.4700 3.6600 5.8600
+991 "L5" 100.00 0.0000 20.000 40.000 6.7400 11.210 18.420
+992 "P1" 100.00 20.000 20.000 40.000 5.8200 8.8600 15.430
+993 "O13" 100.00 40.000 20.000 40.000 4.9700 6.7300 12.540
+994 "W28" 100.00 70.196 20.000 40.000 3.9300 4.2600 8.6600
+995 "V28" 100.00 100.00 20.000 40.000 3.2600 2.7100 5.9900
+996 "M41" 0.0000 0.0000 40.000 40.000 32.280 34.540 16.750
+997 "P7" 0.0000 20.000 40.000 40.000 27.410 27.100 13.780
+998 "W3" 0.0000 40.000 40.000 40.000 23.150 20.570 10.940
+999 "W8" 0.0000 70.196 40.000 40.000 17.680 12.600 6.9200
+1000 "AA47" 0.0000 100.00 40.000 40.000 14.440 8.0200 4.3800
+1001 "M21" 20.000 0.0000 40.000 40.000 25.450 28.700 15.960
+1002 "S1" 20.000 20.000 40.000 40.000 21.770 22.640 13.300
+1003 "O2" 20.000 40.000 40.000 40.000 18.130 16.910 10.410
+1004 "Q11" 20.000 70.196 40.000 40.000 13.910 10.440 6.7100
+1005 "G46" 20.000 100.00 40.000 40.000 11.360 6.5700 4.3400
+1006 "N11" 40.000 0.0000 40.000 40.000 19.000 23.010 15.060
+1007 "K17" 40.000 20.000 40.000 40.000 16.200 18.030 12.580
+1008 "C14" 40.000 40.000 40.000 40.000 13.450 13.420 10.020
+1009 "F14" 40.000 70.196 40.000 40.000 10.260 8.2300 6.4900
+1010 "Z57" 40.000 100.00 40.000 40.000 8.4500 5.1800 4.2300
+1011 "R56" 70.196 0.0000 40.000 40.000 11.350 15.930 13.860
+1012 "M4" 70.196 20.000 40.000 40.000 9.6500 12.410 11.580
+1013 "W26" 70.196 40.000 40.000 40.000 8.0300 9.2500 9.2600
+1014 "B20" 70.196 70.196 40.000 40.000 6.4100 5.9200 6.3300
+1015 "E53" 70.196 100.00 40.000 40.000 5.2600 3.7100 4.2900
+1016 "G37" 100.00 0.0000 40.000 40.000 5.9700 10.810 13.150
+1017 "V22" 100.00 20.000 40.000 40.000 5.1800 8.5500 11.090
+1018 "I44" 100.00 40.000 40.000 40.000 4.4400 6.5300 9.0000
+1019 "L11" 100.00 70.196 40.000 40.000 3.6000 4.2200 6.2100
+1020 "T28" 100.00 100.00 40.000 40.000 3.0500 2.7500 4.3500
+1021 "Y17" 0.0000 0.0000 70.196 40.000 30.110 32.530 7.8400
+1022 "X43" 0.0000 20.000 70.196 40.000 25.640 25.540 6.4900
+1023 "G1" 0.0000 40.000 70.196 40.000 21.710 19.410 5.2000
+1024 "H34" 0.0000 70.196 70.196 40.000 17.020 12.270 3.6000
+1025 "S12" 0.0000 100.00 70.196 40.000 14.160 8.0600 2.4500
+1026 "Y37" 20.000 0.0000 70.196 40.000 23.490 26.940 7.4500
+1027 "W5" 20.000 20.000 70.196 40.000 20.010 21.120 6.2700
+1028 "P11" 20.000 40.000 70.196 40.000 16.810 15.890 5.0900
+1029 "B43" 20.000 70.196 70.196 40.000 13.190 10.030 3.4900
+1030 "K31" 20.000 100.00 70.196 40.000 11.110 6.6100 2.4300
+1031 "R20" 40.000 0.0000 70.196 40.000 17.210 21.410 7.1200
+1032 "F24" 40.000 20.000 70.196 40.000 14.550 16.640 6.0500
+1033 "Q9" 40.000 40.000 70.196 40.000 12.140 12.370 4.9300
+1034 "B11" 40.000 70.196 70.196 40.000 9.5800 7.8100 3.4200
+1035 "N3" 40.000 100.00 70.196 40.000 8.2200 5.2100 2.4000
+1036 "C21" 70.196 0.0000 70.196 40.000 9.9300 14.690 6.6700
+1037 "N18" 70.196 20.000 70.196 40.000 8.4300 11.430 5.7400
+1038 "Y7" 70.196 40.000 70.196 40.000 7.1600 8.5900 4.7900
+1039 "AA25" 70.196 70.196 70.196 40.000 5.7600 5.5200 3.3600
+1040 "J24" 70.196 100.00 70.196 40.000 4.9800 3.6900 2.4600
+1041 "L8" 100.00 0.0000 70.196 40.000 4.9200 10.010 6.6400
+1042 "J45" 100.00 20.000 70.196 40.000 4.2900 7.9400 5.6100
+1043 "AA12" 100.00 40.000 70.196 40.000 3.7200 6.0500 4.6300
+1044 "N21" 100.00 70.196 70.196 40.000 3.1500 3.9800 3.4100
+1045 "M17" 100.00 100.00 70.196 40.000 2.7800 2.7200 2.5600
+1046 "R44" 0.0000 0.0000 100.00 40.000 28.850 31.210 3.3700
+1047 "F45" 0.0000 20.000 100.00 40.000 24.550 24.460 2.8400
+1048 "S54" 0.0000 40.000 100.00 40.000 20.890 18.660 2.4100
+1049 "R26" 0.0000 70.196 100.00 40.000 16.460 11.890 1.8600
+1050 "K57" 0.0000 100.00 100.00 40.000 13.900 8.0200 1.5400
+1051 "L54" 20.000 0.0000 100.00 40.000 22.420 25.850 3.2100
+1052 "M30" 20.000 20.000 100.00 40.000 19.130 20.270 2.7800
+1053 "H49" 20.000 40.000 100.00 40.000 16.050 15.200 2.3700
+1054 "V57" 20.000 70.196 100.00 40.000 12.710 9.6900 1.8500
+1055 "J35" 20.000 100.00 100.00 40.000 10.910 6.5800 1.5400
+1056 "O14" 40.000 0.0000 100.00 40.000 16.250 20.490 3.1400
+1057 "S41" 40.000 20.000 100.00 40.000 13.770 15.900 2.7300
+1058 "U50" 40.000 40.000 100.00 40.000 11.340 11.590 2.3700
+1059 "J36" 40.000 70.196 100.00 40.000 9.1100 7.4700 1.8700
+1060 "M45" 40.000 100.00 100.00 40.000 8.0200 5.1700 1.5300
+1061 "K3" 70.196 0.0000 100.00 40.000 9.2500 13.990 3.1100
+1062 "D28" 70.196 20.000 100.00 40.000 7.8100 10.790 2.7700
+1063 "F38" 70.196 40.000 100.00 40.000 6.6300 8.0500 2.4100
+1064 "Y25" 70.196 70.196 100.00 40.000 5.4400 5.2900 1.9100
+1065 "H4" 70.196 100.00 100.00 40.000 4.8200 3.6700 1.5700
+1066 "C57" 100.00 0.0000 100.00 40.000 4.2300 9.1900 3.3200
+1067 "AA35" 100.00 20.000 100.00 40.000 3.7700 7.3600 2.9300
+1068 "X21" 100.00 40.000 100.00 40.000 3.3300 5.7000 2.5400
+1069 "S15" 100.00 70.196 100.00 40.000 2.8800 3.8500 2.0300
+1070 "P28" 100.00 100.00 100.00 40.000 2.6300 2.7000 1.6000
+1071 "P13" 0.0000 0.0000 0.0000 60.000 18.920 19.770 17.150
+1072 "A32" 0.0000 20.000 0.0000 60.000 16.340 15.770 14.120
+1073 "V42" 0.0000 40.000 0.0000 60.000 14.000 12.220 11.280
+1074 "P21" 0.0000 70.196 0.0000 60.000 10.700 7.6400 7.1400
+1075 "Y47" 0.0000 100.00 0.0000 60.000 8.5700 4.8000 4.3800
+1076 "U6" 20.000 0.0000 0.0000 60.000 15.460 16.840 16.420
+1077 "J33" 20.000 20.000 0.0000 60.000 13.250 13.290 13.530
+1078 "Q39" 20.000 40.000 0.0000 60.000 11.130 10.030 10.730
+1079 "T49" 20.000 70.196 0.0000 60.000 8.5400 6.2900 6.8500
+1080 "F27" 20.000 100.00 0.0000 60.000 7.0000 4.0600 4.3400
+1081 "B13" 40.000 0.0000 0.0000 60.000 11.910 13.740 15.620
+1082 "A40" 40.000 20.000 0.0000 60.000 10.010 10.570 12.760
+1083 "Q55" 40.000 40.000 0.0000 60.000 8.2800 7.8100 10.130
+1084 "N52" 40.000 70.196 0.0000 60.000 6.4600 4.9900 6.5800
+1085 "G35" 40.000 100.00 0.0000 60.000 5.5100 3.3800 4.3900
+1086 "K28" 70.196 0.0000 0.0000 60.000 7.7000 9.8600 14.380
+1087 "D27" 70.196 20.000 0.0000 60.000 6.4400 7.5200 11.770
+1088 "W7" 70.196 40.000 0.0000 60.000 5.3600 5.5600 9.3700
+1089 "X11" 70.196 70.196 0.0000 60.000 4.3900 3.7500 6.4300
+1090 "U56" 70.196 100.00 0.0000 60.000 3.8400 2.6400 4.4700
+1091 "M19" 100.00 0.0000 0.0000 60.000 4.5500 6.8200 13.210
+1092 "U53" 100.00 20.000 0.0000 60.000 3.9900 5.4500 11.020
+1093 "L24" 100.00 40.000 0.0000 60.000 3.5100 4.2900 9.0400
+1094 "V33" 100.00 70.196 0.0000 60.000 3.0100 3.0000 6.3500
+1095 "T1" 100.00 100.00 0.0000 60.000 2.7600 2.2300 4.6700
+1096 "Z52" 0.0000 0.0000 20.000 60.000 17.650 18.660 13.040
+1097 "A57" 0.0000 20.000 20.000 60.000 15.210 14.850 10.820
+1098 "B33" 0.0000 40.000 20.000 60.000 13.040 11.490 8.7000
+1099 "V4" 0.0000 70.196 20.000 60.000 10.150 7.3400 5.6000
+1100 "W34" 0.0000 100.00 20.000 60.000 8.3400 4.8000 3.5600
+1101 "X51" 20.000 0.0000 20.000 60.000 14.260 15.790 12.420
+1102 "AA20" 20.000 20.000 20.000 60.000 12.250 12.490 10.350
+1103 "B23" 20.000 40.000 20.000 60.000 10.350 9.4800 8.2400
+1104 "N46" 20.000 70.196 20.000 60.000 8.1000 6.0800 5.3800
+1105 "J10" 20.000 100.00 20.000 60.000 6.8100 4.0700 3.5100
+1106 "C18" 40.000 0.0000 20.000 60.000 10.760 12.700 11.610
+1107 "X26" 40.000 20.000 20.000 60.000 9.1600 9.9100 9.6500
+1108 "D1" 40.000 40.000 20.000 60.000 7.7100 7.4500 7.8000
+1109 "N29" 40.000 70.196 20.000 60.000 6.1100 4.8400 5.1200
+1110 "AA16" 40.000 100.00 20.000 60.000 5.2900 3.3500 3.4600
+1111 "M24" 70.196 0.0000 20.000 60.000 6.8300 9.0700 10.680
+1112 "V53" 70.196 20.000 20.000 60.000 5.8600 7.0900 8.9800
+1113 "O8" 70.196 40.000 20.000 60.000 4.9700 5.3400 7.2400
+1114 "J6" 70.196 70.196 20.000 60.000 4.1400 3.6600 5.0200
+1115 "N26" 70.196 100.00 20.000 60.000 3.6600 2.6300 3.5500
+1116 "K22" 100.00 0.0000 20.000 60.000 3.9700 6.3600 9.9000
+1117 "Z28" 100.00 20.000 20.000 60.000 3.5300 5.1400 8.3700
+1118 "V35" 100.00 40.000 20.000 60.000 3.1500 4.0600 6.9300
+1119 "E48" 100.00 70.196 20.000 60.000 2.7900 2.9300 5.0100
+1120 "E46" 100.00 100.00 20.000 60.000 2.5900 2.2200 3.6500
+1121 "O16" 0.0000 0.0000 40.000 60.000 16.280 17.460 8.9900
+1122 "D8" 0.0000 20.000 40.000 60.000 13.940 13.790 7.4700
+1123 "F32" 0.0000 40.000 40.000 60.000 11.950 10.650 6.0700
+1124 "T17" 0.0000 70.196 40.000 60.000 9.4900 6.9600 4.0200
+1125 "O52" 0.0000 100.00 40.000 60.000 8.1200 4.8400 2.7200
+1126 "B17" 20.000 0.0000 40.000 60.000 12.910 14.570 8.5600
+1127 "I27" 20.000 20.000 40.000 60.000 11.160 11.580 7.2100
+1128 "Y41" 20.000 40.000 40.000 60.000 9.4600 8.8000 5.7600
+1129 "Y19" 20.000 70.196 40.000 60.000 7.6000 5.8500 3.8800
+1130 "U38" 20.000 100.00 40.000 60.000 6.5900 4.1000 2.6900
+1131 "A53" 40.000 0.0000 40.000 60.000 9.6500 11.690 8.0600
+1132 "K33" 40.000 20.000 40.000 60.000 8.3300 9.2300 6.8000
+1133 "U44" 40.000 40.000 40.000 60.000 7.0700 6.9900 5.5300
+1134 "H35" 40.000 70.196 40.000 60.000 5.7300 4.6900 3.7500
+1135 "AA14" 40.000 100.00 40.000 60.000 5.0800 3.3600 2.6300
+1136 "S35" 70.196 0.0000 40.000 60.000 5.9400 8.2400 7.4200
+1137 "H8" 70.196 20.000 40.000 60.000 5.1800 6.5200 6.2800
+1138 "O1" 70.196 40.000 40.000 60.000 4.4900 5.0100 5.1400
+1139 "AA39" 70.196 70.196 40.000 60.000 3.8800 3.5800 3.6700
+1140 "AA54" 70.196 100.00 40.000 60.000 3.4600 2.6100 2.6500
+1141 "F30" 100.00 0.0000 40.000 60.000 3.4600 5.9400 7.0600
+1142 "S51" 100.00 20.000 40.000 60.000 3.1400 4.8400 6.0700
+1143 "T8" 100.00 40.000 40.000 60.000 2.8500 3.8800 5.0700
+1144 "L2" 100.00 70.196 40.000 60.000 2.5700 2.8600 3.6700
+1145 "L13" 100.00 100.00 40.000 60.000 2.4100 2.1900 2.7000
+1146 "Y43" 0.0000 0.0000 70.196 60.000 14.740 16.020 4.3100
+1147 "C41" 0.0000 20.000 70.196 60.000 12.580 12.610 3.6000
+1148 "O7" 0.0000 40.000 70.196 60.000 10.780 9.7300 2.9400
+1149 "K24" 0.0000 70.196 70.196 60.000 8.8400 6.6200 2.1600
+1150 "A51" 0.0000 100.00 70.196 60.000 7.7800 4.8100 1.6200
+1151 "P54" 20.000 0.0000 70.196 60.000 11.480 13.230 4.0400
+1152 "J15" 20.000 20.000 70.196 60.000 9.9000 10.490 3.4500
+1153 "A20" 20.000 40.000 70.196 60.000 8.5200 8.1000 2.8800
+1154 "K54" 20.000 70.196 70.196 60.000 7.0800 5.5800 2.1200
+1155 "E22" 20.000 100.00 70.196 60.000 6.3200 4.0900 1.6000
+1156 "Z37" 40.000 0.0000 70.196 60.000 8.3300 10.440 3.7900
+1157 "T21" 40.000 20.000 70.196 60.000 7.2400 8.3100 3.3000
+1158 "A28" 40.000 40.000 70.196 60.000 6.3100 6.4500 2.8100
+1159 "L27" 40.000 70.196 70.196 60.000 5.3400 4.5000 2.0900
+1160 "W29" 40.000 100.00 70.196 60.000 4.8800 3.3700 1.5800
+1161 "L30" 70.196 0.0000 70.196 60.000 4.9400 7.2800 3.5100
+1162 "J18" 70.196 20.000 70.196 60.000 4.4400 5.9200 3.1400
+1163 "F9" 70.196 40.000 70.196 60.000 4.0200 4.7200 2.7600
+1164 "P45" 70.196 70.196 70.196 60.000 3.5400 3.4200 2.0700
+1165 "D40" 70.196 100.00 70.196 60.000 3.2700 2.6000 1.6200
+1166 "J1" 100.00 0.0000 70.196 60.000 2.8100 5.3600 3.5000
+1167 "W12" 100.00 20.000 70.196 60.000 2.6300 4.4700 3.1000
+1168 "Q30" 100.00 40.000 70.196 60.000 2.4600 3.6400 2.7100
+1169 "X53" 100.00 70.196 70.196 60.000 2.3200 2.7500 2.1300
+1170 "F19" 100.00 100.00 70.196 60.000 2.2400 2.1800 1.7000
+1171 "R45" 0.0000 0.0000 100.00 60.000 14.580 15.940 2.3100
+1172 "I51" 0.0000 20.000 100.00 60.000 12.630 12.710 1.9300
+1173 "N7" 0.0000 40.000 100.00 60.000 10.990 9.9500 1.6300
+1174 "W48" 0.0000 70.196 100.00 60.000 8.9400 6.7100 1.3300
+1175 "P14" 0.0000 100.00 100.00 60.000 7.7500 4.7900 1.1900
+1176 "K8" 20.000 0.0000 100.00 60.000 11.610 13.460 2.1900
+1177 "H53" 20.000 20.000 100.00 60.000 10.060 10.730 1.9000
+1178 "T10" 20.000 40.000 100.00 60.000 8.6300 8.2800 1.6400
+1179 "T42" 20.000 70.196 100.00 60.000 7.1200 5.6500 1.3600
+1180 "F43" 20.000 100.00 100.00 60.000 6.3400 4.1200 1.2000
+1181 "X10" 40.000 0.0000 100.00 60.000 8.6200 10.880 2.1300
+1182 "U11" 40.000 20.000 100.00 60.000 7.4100 8.5900 1.8900
+1183 "N41" 40.000 40.000 100.00 60.000 6.2300 6.4500 1.6800
+1184 "O36" 40.000 70.196 100.00 60.000 5.3000 4.5300 1.4100
+1185 "Z6" 40.000 100.00 100.00 60.000 4.9100 3.4400 1.2200
+1186 "C26" 70.196 0.0000 100.00 60.000 5.1600 7.7100 2.1000
+1187 "W45" 70.196 20.000 100.00 60.000 4.4600 6.0900 1.9200
+1188 "Z8" 70.196 40.000 100.00 60.000 3.9000 4.7000 1.7400
+1189 "W23" 70.196 70.196 100.00 60.000 3.4800 3.4600 1.4500
+1190 "Q22" 70.196 100.00 100.00 60.000 3.3000 2.7100 1.2600
+1191 "C24" 100.00 0.0000 100.00 60.000 2.6900 5.4400 2.2300
+1192 "Z53" 100.00 20.000 100.00 60.000 2.5100 4.5200 2.0100
+1193 "H22" 100.00 40.000 100.00 60.000 2.3600 3.6900 1.7900
+1194 "W39" 100.00 70.196 100.00 60.000 2.2400 2.8000 1.5100
+1195 "O19" 100.00 100.00 100.00 60.000 2.2100 2.2400 1.2900
+1196 "L38" 0.0000 0.0000 0.0000 80.000 7.9300 8.2700 6.9600
+1197 "M44" 0.0000 40.000 0.0000 80.000 6.2500 5.4900 4.7900
+1198 "E13" 0.0000 70.196 0.0000 80.000 5.2700 3.9500 3.3700
+1199 "V7" 0.0000 100.00 0.0000 80.000 4.4200 2.7100 2.1800
+1200 "Y36" 40.000 0.0000 0.0000 80.000 5.3400 6.1300 6.6800
+1201 "X28" 40.000 40.000 0.0000 80.000 4.2900 4.1000 4.6400
+1202 "J21" 40.000 70.196 0.0000 80.000 3.7200 3.0200 3.3100
+1203 "F55" 40.000 100.00 0.0000 80.000 3.3100 2.2400 2.3200
+1204 "L42" 70.196 0.0000 0.0000 80.000 3.7700 4.7400 6.4100
+1205 "C15" 70.196 40.000 0.0000 80.000 3.1200 3.2300 4.4800
+1206 "B7" 70.196 70.196 0.0000 80.000 2.8100 2.4700 3.3100
+1207 "W43" 70.196 100.00 0.0000 80.000 2.5900 1.9300 2.4000
+1208 "N54" 100.00 0.0000 0.0000 80.000 2.4000 3.4600 6.0000
+1209 "D38" 100.00 40.000 0.0000 80.000 2.2300 2.5700 4.3900
+1210 "B1" 100.00 70.196 0.0000 80.000 2.1300 2.0600 3.2900
+1211 "R21" 100.00 100.00 0.0000 80.000 2.0000 1.6500 2.4400
+1212 "Z15" 0.0000 0.0000 40.000 80.000 7.3700 7.9100 4.1700
+1213 "I12" 0.0000 40.000 40.000 80.000 5.8100 5.2700 2.9500
+1214 "Z25" 0.0000 70.196 40.000 80.000 5.0300 3.9300 2.1900
+1215 "Z27" 0.0000 100.00 40.000 80.000 4.5400 3.0400 1.6100
+1216 "E11" 40.000 0.0000 40.000 80.000 4.7700 5.7300 3.9000
+1217 "G14" 40.000 40.000 40.000 80.000 3.9100 3.9200 2.8200
+1218 "G54" 40.000 70.196 40.000 80.000 3.4900 3.0100 2.1300
+1219 "F51" 40.000 100.00 40.000 80.000 3.2900 2.4500 1.6500
+1220 "Z4" 70.196 0.0000 40.000 80.000 3.2800 4.4100 3.7300
+1221 "AA5" 70.196 40.000 40.000 80.000 2.8200 3.1100 2.7300
+1222 "W38" 70.196 70.196 40.000 80.000 2.6600 2.5200 2.1400
+1223 "O56" 70.196 100.00 40.000 80.000 2.5900 2.1300 1.7100
+1224 "P39" 100.00 0.0000 40.000 80.000 2.1600 3.4200 3.6700
+1225 "J49" 100.00 40.000 40.000 80.000 2.0800 2.6000 2.8000
+1226 "V31" 100.00 70.196 40.000 80.000 2.0700 2.1800 2.2100
+1227 "F47" 100.00 100.00 40.000 80.000 2.0700 1.9000 1.7500
+1228 "D42" 0.0000 0.0000 70.196 80.000 7.0600 7.6700 2.5600
+1229 "R19" 0.0000 40.000 70.196 80.000 5.5800 5.1500 1.8900
+1230 "J32" 0.0000 70.196 70.196 80.000 4.9200 3.9400 1.5400
+1231 "I42" 0.0000 100.00 70.196 80.000 4.5200 3.1700 1.2700
+1232 "A11" 40.000 0.0000 70.196 80.000 4.4800 5.5000 2.4100
+1233 "M57" 40.000 40.000 70.196 80.000 3.7400 3.8500 1.8300
+1234 "D34" 40.000 70.196 70.196 80.000 3.4000 3.0300 1.5000
+1235 "J56" 40.000 100.00 70.196 80.000 3.2800 2.5500 1.2900
+1236 "R18" 70.196 0.0000 70.196 80.000 3.0400 4.2200 2.3300
+1237 "B14" 70.196 40.000 70.196 80.000 2.7000 3.0800 1.8300
+1238 "L7" 70.196 70.196 70.196 80.000 2.5600 2.5100 1.5000
+1239 "P56" 70.196 100.00 70.196 80.000 2.5600 2.2100 1.3100
+1240 "Y42" 100.00 0.0000 70.196 80.000 2.0000 3.3300 2.3600
+1241 "G30" 100.00 40.000 70.196 80.000 1.9700 2.5800 1.8800
+1242 "N23" 100.00 70.196 70.196 80.000 1.9900 2.1900 1.5500
+1243 "R30" 100.00 100.00 70.196 80.000 2.0100 1.9400 1.3000
+1244 "N39" 0.0000 0.0000 100.00 80.000 7.0200 7.6900 1.6400
+1245 "W40" 0.0000 40.000 100.00 80.000 5.6300 5.2600 1.3400
+1246 "L15" 0.0000 70.196 100.00 80.000 4.9500 4.0400 1.1900
+1247 "D47" 0.0000 100.00 100.00 80.000 4.4900 3.2300 1.1000
+1248 "O9" 40.000 0.0000 100.00 80.000 4.5100 5.6100 1.6000
+1249 "K2" 40.000 40.000 100.00 80.000 3.7700 3.9500 1.3300
+1250 "W25" 40.000 70.196 100.00 80.000 3.4400 3.1300 1.1900
+1251 "D39" 40.000 100.00 100.00 80.000 3.2800 2.6300 1.1300
+1252 "Q24" 70.196 0.0000 100.00 80.000 3.0600 4.3200 1.5900
+1253 "J3" 70.196 40.000 100.00 80.000 2.7200 3.1700 1.3400
+1254 "Q14" 70.196 70.196 100.00 80.000 2.5800 2.6000 1.2000
+1255 "R34" 70.196 100.00 100.00 80.000 2.5500 2.2800 1.1300
+1256 "G50" 100.00 0.0000 100.00 80.000 1.9100 3.3100 1.6000
+1257 "T43" 100.00 40.000 100.00 80.000 1.9300 2.6100 1.3900
+1258 "M50" 100.00 70.196 100.00 80.000 1.9600 2.2400 1.2300
+1259 "T18" 100.00 100.00 100.00 80.000 1.9600 1.9800 1.0600
+1260 "Q13" 0.0000 0.0000 0.0000 100.00 2.6900 2.8000 2.1600
+1261 "N33" 0.0000 40.000 0.0000 100.00 2.4700 2.3000 1.6700
+1262 "B50" 0.0000 100.00 0.0000 100.00 2.3200 1.6600 1.0100
+1263 "N43" 40.000 0.0000 0.0000 100.00 1.9700 2.2000 2.1200
+1264 "C11" 40.000 40.000 0.0000 100.00 1.9300 1.8900 1.6800
+1265 "Z35" 40.000 100.00 0.0000 100.00 1.9800 1.4700 1.0700
+1266 "K5" 100.00 0.0000 0.0000 100.00 1.2300 1.6300 2.2800
+1267 "AA52" 100.00 40.000 0.0000 100.00 1.3300 1.4900 1.8100
+1268 "S17" 100.00 100.00 0.0000 100.00 1.5800 1.3300 1.2300
+1269 "S18" 0.0000 0.0000 40.000 100.00 2.6600 2.7900 1.6200
+1270 "G52" 0.0000 40.000 40.000 100.00 2.4800 2.3600 1.3200
+1271 "O21" 0.0000 100.00 40.000 100.00 2.4000 1.8300 0.92000
+1272 "I30" 40.000 0.0000 40.000 100.00 1.9700 2.2300 1.5800
+1273 "O38" 40.000 40.000 40.000 100.00 1.9500 1.9600 1.3100
+1274 "Q18" 40.000 100.00 40.000 100.00 2.0500 1.6300 0.94000
+1275 "H28" 100.00 0.0000 40.000 100.00 1.2300 1.6600 1.6700
+1276 "O43" 100.00 40.000 40.000 100.00 1.3500 1.5600 1.3900
+1277 "A19" 100.00 100.00 40.000 100.00 1.6300 1.4600 1.0400
+1278 "S20" 0.0000 0.0000 100.00 100.00 2.5600 2.8300 0.98000
+1279 "A56" 0.0000 40.000 100.00 100.00 2.4600 2.4900 0.89000
+1280 "U5" 0.0000 100.00 100.00 100.00 2.4600 2.0800 0.85000
+1281 "AA28" 40.000 0.0000 100.00 100.00 1.9200 2.3000 0.93000
+1282 "H6" 40.000 40.000 100.00 100.00 1.9500 2.1100 0.85000
+1283 "S42" 40.000 100.00 100.00 100.00 2.1100 1.8700 0.81000
+1284 "P12" 100.00 0.0000 100.00 100.00 1.2000 1.7500 0.98000
+1285 "C35" 100.00 40.000 100.00 100.00 1.3600 1.6900 0.90000
+1286 "U3" 100.00 100.00 100.00 100.00 1.6800 1.6600 0.83000
+1287 "Y48" 100.00 0.0000 0.0000 0.0000 16.720 25.290 56.260
+1288 "J29" 98.039 0.0000 0.0000 0.0000 17.390 26.000 56.550
+1289 "A33" 94.902 0.0000 0.0000 0.0000 18.440 27.100 57.000
+1290 "V2" 90.196 0.0000 0.0000 0.0000 20.310 29.010 57.740
+1291 "A37" 85.098 0.0000 0.0000 0.0000 22.360 31.030 58.510
+1292 "N12" 80.000 0.0000 0.0000 0.0000 24.560 33.150 59.270
+1293 "J47" 74.902 0.0000 0.0000 0.0000 26.920 35.350 60.050
+1294 "O3" 70.196 0.0000 0.0000 0.0000 29.450 37.760 60.910
+1295 "N19" 60.000 0.0000 0.0000 0.0000 35.020 43.070 62.800
+1296 "H50" 50.196 0.0000 0.0000 0.0000 41.200 48.900 64.790
+1297 "D48" 40.000 0.0000 0.0000 0.0000 48.240 55.380 66.850
+1298 "K12" 29.804 0.0000 0.0000 0.0000 56.270 62.660 68.950
+1299 "H52" 25.098 0.0000 0.0000 0.0000 60.620 66.560 70.010
+1300 "H13" 20.000 0.0000 0.0000 0.0000 65.080 70.510 71.060
+1301 "Y8" 14.902 0.0000 0.0000 0.0000 69.620 74.500 72.110
+1302 "A54" 10.196 0.0000 0.0000 0.0000 74.060 78.380 73.130
+1303 "I17" 7.0588 0.0000 0.0000 0.0000 76.690 80.650 73.730
+1304 "O50" 5.0980 0.0000 0.0000 0.0000 78.370 82.090 74.120
+1305 "H30" 3.1373 0.0000 0.0000 0.0000 80.070 83.550 74.510
+1306 "Y45" 1.9608 0.0000 0.0000 0.0000 80.930 84.290 74.710
+1307 "U49" 0.0000 100.00 0.0000 0.0000 32.280 16.480 15.950
+1308 "U41" 0.0000 98.039 0.0000 0.0000 32.750 17.030 16.530
+1309 "Q56" 0.0000 94.902 0.0000 0.0000 33.460 17.900 17.440
+1310 "M3" 0.0000 90.196 0.0000 0.0000 34.690 19.430 19.040
+1311 "S27" 0.0000 85.098 0.0000 0.0000 36.010 21.120 20.750
+1312 "R27" 0.0000 80.000 0.0000 0.0000 37.400 22.980 22.580
+1313 "F41" 0.0000 74.902 0.0000 0.0000 38.840 24.970 24.520
+1314 "T44" 0.0000 70.196 0.0000 0.0000 40.640 27.330 26.760
+1315 "L18" 0.0000 60.000 0.0000 0.0000 44.970 32.940 32.000
+1316 "E17" 0.0000 50.196 0.0000 0.0000 50.010 39.680 38.140
+1317 "D6" 0.0000 40.000 0.0000 0.0000 55.570 47.360 44.900
+1318 "M47" 0.0000 29.804 0.0000 0.0000 61.730 55.910 51.990
+1319 "X27" 0.0000 25.098 0.0000 0.0000 64.990 60.480 55.690
+1320 "AA50" 0.0000 20.000 0.0000 0.0000 68.390 65.250 59.520
+1321 "Z47" 0.0000 14.902 0.0000 0.0000 71.880 70.190 63.430
+1322 "U24" 0.0000 10.196 0.0000 0.0000 75.440 75.210 67.360
+1323 "T5" 0.0000 7.0588 0.0000 0.0000 77.590 78.300 69.700
+1324 "Y55" 0.0000 5.0980 0.0000 0.0000 79.020 80.390 71.220
+1325 "L52" 0.0000 3.1373 0.0000 0.0000 80.470 82.520 72.750
+1326 "A26" 0.0000 1.9608 0.0000 0.0000 81.200 83.590 73.530
+1327 "Z40" 0.0000 0.0000 100.00 0.0000 67.430 72.230 6.1400
+1328 "A38" 0.0000 0.0000 98.039 0.0000 67.550 72.380 6.6300
+1329 "P53" 0.0000 0.0000 94.902 0.0000 67.740 72.610 7.4100
+1330 "K37" 0.0000 0.0000 90.196 0.0000 68.070 73.010 8.8300
+1331 "R54" 0.0000 0.0000 85.098 0.0000 68.430 73.430 10.410
+1332 "D24" 0.0000 0.0000 80.000 0.0000 68.840 73.870 12.190
+1333 "D26" 0.0000 0.0000 74.902 0.0000 69.260 74.310 14.170
+1334 "P47" 0.0000 0.0000 70.196 0.0000 69.800 74.880 16.470
+1335 "S13" 0.0000 0.0000 60.000 0.0000 71.090 76.210 22.050
+1336 "E15" 0.0000 0.0000 50.196 0.0000 72.640 77.690 29.020
+1337 "M2" 0.0000 0.0000 40.000 0.0000 74.390 79.200 36.970
+1338 "AA3" 0.0000 0.0000 29.804 0.0000 76.290 80.780 45.490
+1339 "R25" 0.0000 0.0000 25.098 0.0000 77.270 81.580 50.000
+1340 "Q49" 0.0000 0.0000 20.000 0.0000 78.300 82.380 54.640
+1341 "AA31" 0.0000 0.0000 14.902 0.0000 79.330 83.180 59.470
+1342 "B35" 0.0000 0.0000 10.196 0.0000 80.380 84.000 64.370
+1343 "K16" 0.0000 0.0000 7.0588 0.0000 81.040 84.510 67.460
+1344 "X17" 0.0000 0.0000 5.0980 0.0000 81.510 84.870 69.580
+1345 "AA53" 0.0000 0.0000 3.1373 0.0000 81.970 85.230 71.760
+1346 "X16" 0.0000 0.0000 1.9608 0.0000 82.200 85.410 72.860
+1347 "Z12" 0.0000 0.0000 0.0000 100.00 2.6900 2.8000 2.1600
+1348 "AA32" 0.0000 0.0000 0.0000 98.039 3.0500 3.1800 2.4900
+1349 "P25" 0.0000 0.0000 0.0000 94.902 3.6700 3.8200 3.0400
+1350 "I34" 0.0000 0.0000 0.0000 90.196 4.8400 5.0500 4.1200
+1351 "T53" 0.0000 0.0000 0.0000 85.098 6.2100 6.4700 5.3700
+1352 "R41" 0.0000 0.0000 0.0000 80.000 7.9300 8.2700 6.9600
+1353 "O55" 0.0000 0.0000 0.0000 74.902 10.010 10.450 8.8900
+1354 "Q2" 0.0000 0.0000 0.0000 70.196 12.600 13.150 11.280
+1355 "I41" 0.0000 0.0000 0.0000 60.000 18.920 19.770 17.150
+1356 "W16" 0.0000 0.0000 0.0000 50.196 26.590 27.730 24.310
+1357 "L32" 0.0000 0.0000 0.0000 40.000 35.870 37.330 32.950
+1358 "S19" 0.0000 0.0000 0.0000 29.804 46.510 48.340 42.550
+1359 "E40" 0.0000 0.0000 0.0000 25.098 52.470 54.520 47.890
+1360 "X13" 0.0000 0.0000 0.0000 20.000 58.360 60.610 53.170
+1361 "R47" 0.0000 0.0000 0.0000 14.902 64.370 66.830 58.570
+1362 "AA9" 0.0000 0.0000 0.0000 10.196 70.130 72.800 63.780
+1363 "AA37" 0.0000 0.0000 0.0000 7.0588 73.750 76.540 67.050
+1364 "I15" 0.0000 0.0000 0.0000 5.0980 76.230 79.110 69.290
+1365 "G32" 0.0000 0.0000 0.0000 3.1373 78.770 81.730 71.570
+1366 "E54" 0.0000 0.0000 0.0000 1.9608 80.050 83.060 72.740
+1367 "G48" 0.0000 0.0000 0.0000 0.0000 82.670 85.770 75.100
+1368 "C51" 100.00 85.098 85.098 0.0000 4.2100 5.0800 3.8600
+1369 "F29" 80.000 65.098 65.098 0.0000 9.2500 10.040 7.5600
+1370 "U4" 60.000 45.098 45.098 0.0000 18.590 19.740 16.510
+1371 "AA34" 40.000 27.059 27.059 0.0000 34.220 36.090 31.630
+1372 "E51" 20.000 12.157 12.157 0.0000 56.270 58.800 51.990
+1373 "J43" 10.196 5.8824 5.8824 0.0000 68.820 71.500 62.730
+1374 "N10" 5.0980 3.1373 3.1373 0.0000 75.560 78.420 68.630
+1375 "A25" 40.000 27.059 27.059 10.196 29.920 31.630 27.750
+1376 "G9" 20.000 12.157 12.157 10.196 48.460 50.700 44.880
+1377 "H42" 10.196 5.8824 5.8824 10.196 58.810 61.160 53.730
+1378 "J48" 60.000 45.098 45.098 20.000 14.020 14.930 12.540
+1379 "X5" 40.000 27.059 27.059 20.000 25.580 27.090 23.790
+1380 "Q36" 20.000 12.157 12.157 20.000 40.850 42.790 37.950
+1381 "W56" 10.196 5.8824 5.8824 20.000 49.240 51.260 45.120
+1382 "V46" 80.000 65.098 65.098 40.000 5.0200 5.3800 3.9000
+1383 "W2" 60.000 45.098 45.098 40.000 8.9700 9.5400 7.9900
+1384 "O37" 40.000 27.059 27.059 40.000 15.850 16.790 14.880
+1385 "W37" 20.000 12.157 12.157 40.000 25.140 26.400 23.570
+1386 "W10" 10.196 5.8824 5.8824 40.000 30.280 31.590 27.990
+1387 "C33" 100.00 85.098 85.098 60.000 2.2400 2.4600 1.6300
+1388 "H1" 80.000 65.098 65.098 60.000 3.1800 3.3500 2.3200
+1389 "AA41" 60.000 45.098 45.098 60.000 4.8500 5.0700 4.4500
+1390 "Y38" 40.000 27.059 27.059 60.000 8.3800 8.8100 8.0600
+1391 "F57" 20.000 12.157 12.157 60.000 13.460 14.110 12.550
+1392 "G51" 10.196 5.8824 5.8824 60.000 16.140 16.860 14.740
+1393 "K39" 100.00 85.098 85.098 80.000 1.9600 2.0600 1.2500
+1394 "X55" 80.000 65.098 65.098 80.000 2.3600 2.4500 1.6300
+1395 "W36" 60.000 45.098 45.098 80.000 3.0700 3.2100 2.4800
+1396 "V50" 40.000 27.059 27.059 80.000 4.2700 4.4900 3.7200
+1397 "K42" 20.000 12.157 12.157 80.000 5.9400 6.2300 5.2700
+1398 "H46" 10.196 5.8824 5.8824 80.000 6.8900 7.1900 6.0600
+1399 "K20" 100.00 85.098 85.098 100.00 1.6000 1.6200 0.88000
+1400 "O28" 80.000 65.098 65.098 100.00 1.6500 1.6700 1.0000
+1401 "M55" 60.000 45.098 45.098 100.00 1.7400 1.7900 1.2400
+1402 "Q33" 40.000 27.059 27.059 100.00 1.9500 2.0300 1.5400
+1403 "G11" 20.000 12.157 12.157 100.00 2.2800 2.3700 1.8500
+1404 "O24" 10.196 5.8824 5.8824 100.00 2.4700 2.5700 1.9900
+1405 "I40" 100.00 0.0000 0.0000 70.196 3.3500 4.9400 9.1000
+1406 "V26" 0.0000 100.00 0.0000 70.196 6.2200 3.6300 3.1400
+1407 "P23" 0.0000 0.0000 100.00 70.196 10.310 11.280 1.9600
+1408 "Z38" 100.00 100.00 0.0000 70.196 2.3500 1.9200 3.4300
+1409 "I20" 100.00 0.0000 100.00 70.196 2.2700 4.2800 1.9000
+1410 "V18" 0.0000 100.00 100.00 70.196 5.9200 3.9200 1.1400
+1411 "U33" 40.000 40.000 0.0000 70.196 6.0400 5.7300 7.0200
+1412 "V37" 40.000 0.0000 40.000 70.196 6.8800 8.3200 5.7100
+1413 "A23" 0.0000 40.000 40.000 70.196 8.4500 7.5800 4.3000
+1414 "U54" 3.1373 3.1373 0.0000 0.0000 77.910 80.350 72.190
+1415 "Y1" 3.1373 0.0000 3.1373 0.0000 79.370 83.010 71.210
+1416 "M8" 0.0000 3.1373 3.1373 0.0000 79.770 81.980 69.490
+1417 "J50" 3.1373 3.1373 3.1373 0.0000 77.230 79.830 68.970
+1418 "J55" 3.1373 0.0000 0.0000 3.1373 76.310 79.640 71.020
+1419 "M42" 0.0000 3.1373 0.0000 3.1373 76.690 78.660 69.370
+1420 "A14" 3.1373 3.1373 0.0000 3.1373 74.280 76.630 68.840
+1421 "Y9" 0.0000 0.0000 3.1373 3.1373 78.110 81.220 68.430
+1422 "S14" 3.1373 0.0000 3.1373 3.1373 75.660 79.130 67.910
+1423 "G15" 0.0000 3.1373 3.1373 3.1373 76.030 78.160 66.300
+1424 "H48" 3.1373 3.1373 3.1373 3.1373 73.640 76.140 65.810
+1425 "B30" 7.0588 7.0588 0.0000 0.0000 71.830 73.480 68.450
+1426 "G36" 7.0588 0.0000 7.0588 0.0000 75.070 79.390 66.280
+1427 "G44" 0.0000 7.0588 7.0588 0.0000 75.980 77.080 62.510
+1428 "Q52" 7.0588 7.0588 7.0588 0.0000 70.400 72.440 61.560
+1429 "C50" 7.0588 0.0000 0.0000 7.0588 68.550 72.090 65.870
+1430 "D46" 0.0000 7.0588 0.0000 7.0588 69.340 70.070 62.380
+1431 "M28" 7.0588 7.0588 0.0000 7.0588 64.320 65.870 61.300
+1432 "K19" 0.0000 0.0000 7.0588 7.0588 72.350 75.460 60.420
+1433 "I56" 7.0588 0.0000 7.0588 7.0588 67.150 71.010 59.410
+1434 "S23" 0.0000 7.0588 7.0588 7.0588 67.940 69.020 56.130
+1435 "I35" 7.0588 7.0588 7.0588 7.0588 63.090 64.980 55.310
+1436 "F10" 40.000 3.1373 0.0000 0.0000 46.900 53.230 64.760
+1437 "W32" 3.1373 40.000 0.0000 0.0000 53.700 46.000 44.550
+1438 "K38" 40.000 0.0000 3.1373 0.0000 47.760 55.080 63.820
+1439 "B41" 40.000 3.1373 3.1373 0.0000 46.430 52.940 61.850
+1440 "B55" 0.0000 40.000 3.1373 0.0000 55.180 47.100 42.990
+1441 "H3" 3.1373 40.000 3.1373 0.0000 53.320 45.760 42.680
+1442 "F3" 40.000 40.000 3.1373 0.0000 31.900 30.200 39.030
+1443 "N27" 3.1373 0.0000 40.000 0.0000 71.840 77.030 36.790
+1444 "U30" 0.0000 3.1373 40.000 0.0000 72.430 76.190 35.830
+1445 "T32" 3.1373 3.1373 40.000 0.0000 69.950 74.110 35.680
+1446 "A1" 40.000 3.1373 40.000 0.0000 40.970 49.010 32.140
+1447 "H12" 3.1373 40.000 40.000 0.0000 49.290 43.080 22.680
+1448 "A7" 40.000 0.0000 0.0000 3.1373 46.150 52.970 63.810
+1449 "N28" 40.000 3.1373 0.0000 3.1373 44.890 50.940 61.840
+1450 "T33" 0.0000 40.000 0.0000 3.1373 53.090 45.340 42.990
+1451 "G57" 3.1373 40.000 0.0000 3.1373 51.330 44.050 42.660
+1452 "AA29" 40.000 40.000 0.0000 3.1373 30.990 29.250 39.160
+1453 "Z54" 40.000 0.0000 3.1373 3.1373 45.700 52.680 60.950
+1454 "B57" 40.000 3.1373 3.1373 3.1373 44.460 50.670 59.100
+1455 "E19" 0.0000 40.000 3.1373 3.1373 52.730 45.090 41.180
+1456 "W24" 3.1373 40.000 3.1373 3.1373 50.980 43.830 40.890
+1457 "L16" 40.000 40.000 3.1373 3.1373 30.680 29.090 37.450
+1458 "Q38" 0.0000 0.0000 40.000 3.1373 70.950 75.570 35.460
+1459 "E28" 3.1373 0.0000 40.000 3.1373 68.550 73.520 35.290
+1460 "J25" 40.000 0.0000 40.000 3.1373 40.440 48.890 31.760
+1461 "Z42" 0.0000 3.1373 40.000 3.1373 69.110 72.730 34.390
+1462 "O40" 3.1373 3.1373 40.000 3.1373 66.780 70.770 34.250
+1463 "P48" 40.000 3.1373 40.000 3.1373 39.330 47.000 30.880
+1464 "S48" 0.0000 40.000 40.000 3.1373 48.850 42.450 21.930
+1465 "T54" 3.1373 40.000 40.000 3.1373 47.180 41.310 21.840
+1466 "V21" 40.000 40.000 40.000 3.1373 27.660 27.330 20.040
+1467 "X32" 3.1373 0.0000 0.0000 40.000 34.810 36.430 32.700
+1468 "M54" 0.0000 3.1373 0.0000 40.000 35.000 36.040 32.030
+1469 "P18" 3.1373 3.1373 0.0000 40.000 33.960 35.170 31.790
+1470 "B29" 40.000 3.1373 0.0000 40.000 21.090 23.970 28.560
+1471 "N42" 3.1373 40.000 0.0000 40.000 24.370 21.350 20.800
+1472 "H36" 0.0000 0.0000 3.1373 40.000 35.580 37.110 31.630
+1473 "Y33" 3.1373 0.0000 3.1373 40.000 34.530 36.220 31.390
+1474 "X38" 40.000 0.0000 3.1373 40.000 21.430 24.730 28.190
+1475 "W46" 0.0000 3.1373 3.1373 40.000 34.710 35.820 30.740
+1476 "Q34" 3.1373 3.1373 3.1373 40.000 33.680 34.950 30.510
+1477 "L53" 40.000 3.1373 3.1373 40.000 20.900 23.850 27.410
+1478 "Q23" 0.0000 40.000 3.1373 40.000 24.990 21.820 20.150
+1479 "N22" 3.1373 40.000 3.1373 40.000 24.220 21.240 20.010
+1480 "L57" 40.000 40.000 3.1373 40.000 15.080 14.420 18.190
+1481 "F5" 3.1373 0.0000 40.000 40.000 31.250 33.670 16.670
+1482 "J22" 0.0000 3.1373 40.000 40.000 31.520 33.360 16.290
+1483 "H27" 3.1373 3.1373 40.000 40.000 30.520 32.520 16.230
+1484 "U29" 40.000 3.1373 40.000 40.000 18.520 22.170 14.690
+1485 "U34" 3.1373 40.000 40.000 40.000 22.390 20.040 10.900
+0 "R9" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "R38" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "T45" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "G12" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Q37" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "G4" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Z32" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "S6" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "V39" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "V44" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Q26" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Z3" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "N38" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "B22" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "W21" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "B47" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "AA45" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Z1" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "R32" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "V11" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "P31" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "W31" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "N13" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "H31" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "K50" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "M26" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "J40" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "B34" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "T56" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "K25" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "W15" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "E8" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "G13" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "C17" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "U14" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Y12" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "J20" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "A16" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "B37" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "U7" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "X44" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "U8" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "AA43" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "U52" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "J13" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "J5" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "I10" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "O26" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Z14" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "V13" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "C37" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "X46" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "L33" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "R28" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+END_DATA
diff --git a/ref/ECI2002R.ti2 b/ref/ECI2002R.ti2
new file mode 100644
index 0000000..d3f2d8b
--- /dev/null
+++ b/ref/ECI2002R.ti2
@@ -0,0 +1,1517 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+# ECI2002 Random CMYK chart, 1485 patches.
+ORIGINATOR "Argyll printtarg"
+CREATED "Thu Aug 11 22:19:15 2005"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
+KEYWORD "MULTI_DIM_STEPS"
+MULTI_DIM_STEPS "2"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "96.420000 100.000000 82.490000"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "33"
+KEYWORD "PASSES_IN_STRIPS"
+PASSES_IN_STRIPS "j"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "A-Z, 2-9;A-X,2A-9Z"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1485
+BEGIN_DATA
+810 "A1" 10 20 20 20 42.793 42.608 32.296
+1369 "A2" 80 65 65 0 9.5005 10.178 7.8087
+1393 "A3" 100 85 85 80 1.9086 2.003 1.1906
+1427 "A4" 0 7 7 0 76.857 77.978 63.869
+1387 "A5" 100 85 85 60 2.2422 2.4721 1.6188
+1377 "A6" 10 6 6 10 60.778 63.216 55.806
+558 "A7" 85 100 70 0 6.1175 5.0394 4.4819
+1381 "A8" 10 6 6 20 50.129 52.184 46.198
+1394 "A9" 80 65 65 80 2.3235 2.4083 1.599
+1434 "A10" 0 7 7 7 69.874 71.047 58.514
+1388 "A11" 80 65 65 60 3.437 3.6144 2.5883
+1392 "A12" 10 6 6 60 16.236 16.953 14.978
+1382 "A13" 80 65 65 40 5.2618 5.5902 4.1157
+93 "A14" 10 20 10 0 60.498 59.465 51.051
+230 "A15" 85 40 20 0 13.639 16.589 27.468
+1430 "A16" 0 7 0 7 71.224 72.097 64.03
+1395 "A17" 60 45 45 80 3.041 3.1902 2.4497
+1376 "A18" 20 12 12 10 49.823 52.06 45.983
+1389 "A19" 60 45 45 60 5.2975 5.5898 4.7403
+1380 "A20" 20 12 12 20 41.45 43.378 38.352
+1424 "A21" 3 3 3 3 75.838 78.392 68.023
+1385 "A22" 20 12 12 40 25.493 26.703 23.726
+1378 "A23" 60 45 45 20 14.211 15.169 12.762
+1391 "A24" 20 12 12 60 13.215 13.844 12.297
+1420 "A25" 3 3 0 3 76.251 78.631 70.15
+1397 "A26" 20 12 12 80 5.8519 6.1281 5.184
+210 "A27" 55 20 20 0 29.639 34.115 38.205
+101 "A28" 20 10 10 0 58.653 61.601 55.595
+1432 "A29" 0 0 7 7 74.374 77.494 62.933
+1375 "A30" 40 27 27 10 30.415 32.13 28.372
+1384 "A31" 40 27 27 40 16.266 17.237 15.144
+1379 "A32" 40 27 27 20 25.674 27.176 23.921
+1 "A33" 0 0 0 0 83.532 86.556 75.658
+970 "B1" 100 100 0 40 3.6335 2.7779 7.9686
+1049 "B2" 0 70 100 40 16.486 12.087 1.9347
+968 "B3" 100 40 0 40 5.7755 7.1079 16.701
+336 "B4" 10 20 40 0 55.595 55.81 29.655
+479 "B5" 100 10 55 0 9.9812 18.831 18.457
+560 "B6" 100 10 70 0 8.8992 17.985 12.749
+328 "B7" 0 30 40 0 56.678 52.472 26.359
+564 "B8" 100 55 70 0 5.8864 8.9485 7.8006
+974 "B9" 0 70 20 40 18.626 13.239 10.215
+1045 "B10" 100 100 70 40 2.8294 2.7651 2.6045
+234 "B11" 85 100 20 0 7.5253 5.3012 12.047
+999 "B12" 0 70 40 40 17.721 12.765 7.0851
+1018 "B13" 100 40 40 40 4.5218 6.511 8.8453
+997 "B14" 0 20 40 40 27.374 27.152 13.911
+641 "B15" 100 10 85 0 8.1959 17.374 8.6931
+849 "B16" 10 100 40 20 20.419 11.252 6.8398
+433 "B17" 30 0 55 0 47.637 56.166 23.691
+279 "B18" 30 100 30 0 20.49 11.372 10.058
+469 "B19" 85 0 55 0 16.124 26.789 20.762
+315 "B20" 85 100 30 0 7.2433 5.2818 10.282
+1046 "B21" 0 0 100 40 28.466 31.033 3.3861
+955 "B22" 20 100 0 40 11.794 6.4646 7.5603
+1056 "B23" 40 0 100 40 16.346 20.623 3.1537
+965 "B24" 70 100 0 40 5.7639 3.7213 7.6967
+1066 "B25" 100 0 100 40 4.1162 8.961 3.2855
+422 "B26" 10 85 55 0 30.135 18.78 7.901
+887 "B27" 20 10 70 20 36.357 39.95 11.445
+458 "B28" 55 85 55 0 14.013 10.389 7.6421
+899 "B29" 70 10 70 20 14.937 21.331 10.227
+740 "B30" 10 70 0 20 26.948 18.819 20.02
+911 "B31" 0 10 100 20 43.802 45.594 4.5306
+1265 "B32" 40 100 0 100 2.0055 1.5286 1.1038
+905 "B33" 100 10 70 20 6.9562 13.709 9.7649
+1061 "C1" 70 0 100 40 9.2036 14.115 3.1614
+952 "C2" 20 20 0 40 24.491 24.553 25.45
+1063 "C3" 70 40 100 40 6.7295 8.3357 2.4606
+358 "C4" 30 70 40 0 25.322 19.034 13.417
+720 "C5" 85 100 100 0 5.6081 4.8531 2.2834
+135 "C6" 55 100 10 0 13.763 8.0611 13.747
+350 "C7" 20 85 40 0 26.724 17.011 10.976
+384 "C8" 70 55 40 0 14.077 14.733 15.901
+1027 "C9" 20 20 70 40 20.476 21.648 6.6864
+986 "C10" 70 0 20 40 12.854 17.116 20.559
+389 "C11" 85 10 40 0 16.298 24.777 26.866
+1002 "C12" 20 20 40 40 21.604 22.456 13.304
+1013 "C13" 70 40 40 40 7.9577 9.151 9.2125
+1004 "C14" 20 70 40 40 13.987 10.47 6.8252
+216 "C15" 55 100 20 0 13.4 7.9938 11.912
+728 "C16" 100 85 100 0 4.0841 5.1036 2.7965
+471 "C17" 85 20 55 0 13.49 20.624 17.26
+457 "C18" 55 70 55 0 15.752 13.406 9.2268
+435 "C19" 30 20 55 0 40.149 43.322 19.482
+421 "C20" 10 70 55 0 33.517 23.678 9.8153
+400 "C21" 100 30 40 0 9.4072 14.991 21.358
+186 "C22" 20 55 20 0 35.935 29.1 25.365
+616 "C23" 55 30 85 0 21.553 25.496 7.2393
+222 "C24" 70 55 20 0 15.6 15.466 23.084
+580 "C25" 10 30 85 0 46.288 44.489 7.4927
+1267 "C26" 100 40 0 100 1.3818 1.5205 1.8283
+935 "C27" 70 10 100 20 13.917 20.374 4.265
+1261 "C28" 0 40 0 100 2.8301 2.5695 1.9105
+918 "C29" 10 20 100 20 36.334 37.277 4.1001
+474 "C30" 85 55 55 0 9.5771 11.612 11.315
+452 "C31" 55 10 55 0 28.107 35.803 20.187
+438 "C32" 30 55 55 0 28.453 24.407 11.952
+416 "C33" 10 10 55 0 58.641 61.983 22.575
+960 "D1" 40 100 0 40 8.982 5.1483 7.5676
+1059 "D2" 40 70 100 40 9.3594 7.7211 1.9254
+958 "D3" 40 40 0 40 15.606 14.83 19.238
+372 "D4" 55 20 40 0 27.182 32.439 26.236
+370 "D5" 55 0 40 0 32.564 42.302 31.907
+362 "D6" 40 10 40 0 39.04 45.288 30.422
+364 "D7" 40 30 40 0 32.681 34.373 24.474
+366 "D8" 40 55 40 0 24.752 21.975 16.766
+984 "D9" 40 70 20 40 11.209 8.7933 9.4358
+1035 "D10" 40 100 70 40 8.2908 5.2998 2.5581
+198 "D11" 30 100 20 0 20.728 11.36 11.887
+1009 "D12" 40 70 40 40 10.342 8.24 6.5236
+1008 "D13" 40 40 40 40 13.263 13.221 9.9237
+1007 "D14" 40 20 40 40 15.983 17.734 12.478
+371 "D15" 55 10 40 0 29.797 37.094 29.054
+419 "D16" 10 40 55 0 44.092 39.582 15.619
+437 "D17" 30 40 55 0 32.767 31.468 14.757
+455 "D18" 55 40 55 0 21.173 22.9 14.519
+473 "D19" 85 40 55 0 10.975 15.009 13.636
+150 "D20" 85 55 10 0 12.293 12.909 26.065
+1048 "D21" 0 40 100 40 20.719 18.667 2.3797
+953 "D22" 20 40 0 40 20.382 18.42 20.1
+1058 "D23" 40 40 100 40 11.607 11.948 2.4183
+963 "D24" 70 40 0 40 9.8391 10.374 17.803
+1068 "D25" 100 40 100 40 3.3945 5.7942 2.5531
+418 "D26" 10 30 55 0 48.669 46.539 17.988
+436 "D27" 30 30 55 0 36.428 37.272 17.106
+454 "D28" 55 30 55 0 23.62 27.183 16.565
+76 "D29" 100 30 0 0 13.039 16.997 41.354
+738 "D30" 10 20 0 20 44.794 43.834 42.663
+1278 "D31" 0 0 100 100 2.572 2.8437 0.98565
+1263 "D32" 40 0 0 100 3.6855 4.1078 4.037
+1284 "D33" 100 0 100 100 1.2048 1.7593 0.98423
+1051 "E1" 20 0 100 40 22.537 26.074 3.287
+962 "E2" 70 20 0 40 11.811 13.835 22.408
+1053 "E3" 20 40 100 40 16.09 15.286 2.4195
+394 "E4" 85 70 40 0 9.0571 9.2955 12.883
+684 "E5" 30 100 100 0 19.136 11.158 2.267
+99 "E6" 10 100 10 0 28.387 14.824 13.952
+386 "E7" 70 85 40 0 10.927 8.6924 10.65
+348 "E8" 20 55 40 0 34.295 28.185 17.407
+1037 "E9" 70 20 70 40 8.742 11.892 6.0601
+976 "E10" 20 0 20 40 27.708 30.572 23.903
+353 "E11" 30 10 40 0 45.851 51.24 31.303
+1012 "E12" 70 20 40 40 9.5758 12.338 11.494
+1003 "E13" 20 40 40 40 17.982 16.763 10.473
+1014 "E14" 70 70 40 40 6.3807 5.873 6.3043
+180 "E15" 10 100 20 0 28.092 14.8 12.13
+1042 "E16" 100 20 70 40 4.4208 8.0398 5.8433
+989 "E17" 70 70 20 40 7.153 6.3562 9.1678
+1032 "E18" 40 20 70 40 15.006 17.115 6.3506
+979 "E19" 20 70 20 40 14.885 11.021 9.8194
+1022 "E20" 0 20 70 40 26.023 26.124 6.893
+465 "E21" 70 55 55 0 13.34 14.247 11.521
+443 "E22" 40 10 55 0 37.025 43.64 20.961
+429 "E23" 20 55 55 0 33.356 27.593 12.197
+407 "E24" 0 10 55 0 66.105 68.086 22.708
+847 "E25" 10 40 40 20 33.266 30.041 17.13
+791 "E26" 70 10 10 20 19.449 24.461 34.957
+1282 "E27" 40 40 100 100 2.0252 2.1915 0.93621
+779 "E28" 20 10 10 20 42.453 44.687 40.368
+920 "E29" 10 70 100 20 23.705 17.325 2.4843
+470 "E30" 85 10 55 0 14.757 23.58 19.012
+456 "E31" 55 55 55 0 18.248 17.687 11.697
+434 "E32" 30 10 55 0 43.729 49.397 21.567
+420 "E33" 10 55 55 0 38.378 30.8 12.538
+950 "F1" 0 100 0 40 14.72 7.8407 7.6846
+1069 "F2" 100 70 100 40 2.9619 3.9055 2.0486
+948 "F3" 0 40 0 40 25.204 21.959 20.959
+481 "F4" 100 30 55 0 8.3475 14.293 15.071
+334 "F5" 10 0 40 0 66.412 72.64 36.369
+326 "F6" 0 10 40 0 68.338 69.993 33.426
+562 "F7" 100 30 70 0 7.442 13.62 10.455
+330 "F8" 0 55 40 0 44.42 34.552 18.22
+994 "F9" 100 70 20 40 4.1074 4.3786 8.8089
+1025 "F10" 0 100 70 40 14.075 8.072 2.5768
+813 "F11" 10 100 20 20 20.591 11.076 9.279
+1019 "F12" 100 70 40 40 3.6876 4.2309 6.2137
+998 "F13" 0 40 40 40 23.042 20.474 11.041
+1017 "F14" 100 20 40 40 5.3212 8.6332 11.014
+335 "F15" 10 10 40 0 61.004 64.009 33.147
+971 "F16" 0 0 20 40 34.702 36.66 25.315
+1030 "F17" 20 100 70 40 11.115 6.6577 2.5397
+981 "F18" 40 0 20 40 20.866 24.502 22.417
+1040 "F19" 70 100 70 40 5.0452 3.8003 2.5712
+991 "F20" 100 0 20 40 7.0357 11.405 18.83
+848 "F21" 10 70 40 20 25.346 18.217 10.84
+851 "F22" 20 10 40 20 39.003 42.17 24.128
+431 "F23" 20 85 55 0 26.099 16.712 7.7591
+863 "F24" 70 10 40 20 16.884 22.769 20.63
+467 "F25" 70 85 55 0 10.306 8.4104 7.6211
+875 "F26" 0 10 70 20 46.193 47.991 11.698
+440 "F27" 30 85 55 0 22.165 14.664 7.6754
+893 "F28" 40 10 70 20 26.604 31.587 10.802
+476 "F29" 85 85 55 0 7.4139 6.8546 7.6769
+731 "F30" 0 10 0 20 54.196 54.229 48.696
+1280 "F31" 0 100 100 100 2.4602 2.0877 0.85588
+749 "F32" 40 10 0 20 32.888 36.102 43.757
+1286 "F33" 100 100 100 100 1.6821 1.6669 0.84474
+91 "G1" 10 0 10 0 72.655 77.501 63.478
+151 "G2" 85 70 10 0 10.431 9.6758 21.099
+127 "G3" 55 0 10 0 36.695 45.049 54.358
+115 "G4" 30 70 10 0 27.027 19.626 22.285
+74 "G5" 100 10 0 0 15.768 22.473 51.333
+799 "G6" 100 40 10 20 8.0418 10.464 23.122
+901 "G7" 70 40 70 20 11.548 14.047 7.522
+787 "G8" 40 40 10 20 24.018 23.121 26.467
+889 "G9" 20 40 70 20 27.785 26.194 8.1213
+769 "G10" 0 40 10 20 39.7 34.449 29.069
+92 "G11" 10 10 10 0 66.392 68.104 57.186
+152 "G12" 85 85 10 0 9.0576 7.294 17.214
+128 "G13" 55 10 10 0 33.535 39.592 49.444
+116 "G14" 30 85 10 0 23.803 15.085 17.589
+236 "G15" 100 10 20 0 13.328 21.135 37.261
+323 "G16" 100 85 30 0 5.8909 5.7585 12.626
+587 "G17" 20 10 85 0 48.263 52.997 9.1566
+214 "G18" 55 70 20 0 17.587 14.191 18.765
+623 "G19" 70 10 85 0 18.622 27.328 8.567
+178 "G20" 10 70 20 0 35.423 24.586 20.135
+164 "G21" 0 10 20 0 72.096 72.884 50.177
+224 "G22" 70 85 20 0 11.621 8.7959 15.019
+200 "G23" 40 10 20 0 41.66 47.104 43.962
+188 "G24" 20 85 20 0 27.325 17.019 15.415
+398 "G25" 100 10 40 0 11.311 19.793 26.198
+1277 "G26" 100 100 40 100 1.6231 1.463 1.0683
+815 "G27" 20 10 20 20 41.466 44.041 34.957
+1271 "G28" 0 100 40 100 2.3835 1.8323 0.95284
+827 "G29" 70 10 20 20 18.625 23.963 30.049
+233 "G30" 85 85 20 0 8.7078 7.2232 14.921
+596 "G31" 30 10 85 0 41.074 46.949 8.98
+197 "G32" 30 85 20 0 23.387 14.972 15.204
+632 "G33" 85 10 85 0 12.726 21.931 8.5728
+873 "H1" 100 100 40 20 4.0344 3.542 6.6923
+826 "H2" 70 0 20 20 20.193 26.962 32.911
+861 "H3" 40 100 40 20 13.132 7.8145 6.7117
+814 "H4" 20 0 20 20 45.011 49.644 38.435
+843 "H5" 0 100 40 20 22.911 12.431 6.8012
+87 "H6" 0 55 10 0 46.808 35.876 30.627
+139 "H7" 70 30 10 0 21.203 24.321 37.669
+123 "H8" 40 55 10 0 27.068 23.111 28.104
+103 "H9" 20 30 10 0 47.872 45.713 43.191
+159 "H10" 100 55 10 0 9.06 10.557 25.56
+734 "H11" 0 70 0 20 30.09 20.627 20.392
+924 "H12" 20 20 100 20 31.964 33.847 4.0427
+752 "H13" 40 70 0 20 17.978 13.534 19.055
+936 "H14" 70 20 100 20 12.98 18.161 3.9702
+764 "H15" 100 70 0 20 6.3548 6.3278 17.789
+176 "H16" 10 40 20 0 47.705 42.092 33.062
+228 "H17" 85 20 20 0 16.859 22.879 35.148
+212 "H18" 55 40 20 0 23.936 24.63 29.499
+192 "H19" 30 20 20 0 44.961 47.088 41.589
+321 "H20" 100 55 30 0 7.8525 10.036 18.64
+967 "H21" 100 20 0 40 6.8416 9.3463 20.683
+1064 "H22" 70 70 100 40 5.5461 5.4696 1.964
+957 "H23" 40 20 0 40 18.62 19.639 24.192
+1054 "H24" 20 70 100 40 12.884 9.8577 1.9285
+947 "H25" 0 20 0 40 30.469 29.407 26.979
+177 "H26" 10 55 20 0 41.029 32.359 25.991
+211 "H27" 55 30 20 0 26.724 29.193 33.776
+213 "H28" 55 55 20 0 20.573 18.917 23.762
+175 "H29" 10 30 20 0 53.082 49.78 38.239
+775 "H30" 10 40 10 20 35.701 31.677 28.433
+1272 "H31" 40 0 40 100 3.1261 3.5912 2.1998
+1273 "H32" 40 40 40 100 1.9912 2.0029 1.3252
+774 "H33" 10 20 10 20 43.922 43.41 37.409
+95 "I1" 10 40 10 0 48.895 42.882 38.427
+147 "I2" 85 20 10 0 17.934 23.473 41.104
+131 "I3" 55 40 10 0 24.753 25.048 34.193
+111 "I4" 30 20 10 0 45.998 47.606 47.873
+78 "I5" 100 55 0 0 9.7782 10.862 29.546
+800 "I6" 100 70 10 20 6.0042 6.2242 15.688
+900 "I7" 70 20 70 20 13.87 18.947 9.4115
+788 "I8" 40 70 10 20 17.773 13.576 16.768
+888 "I9" 20 20 70 20 33.503 35.29 10.418
+770 "I10" 0 70 10 20 29.596 20.42 17.817
+96 "I11" 10 55 10 0 41.647 32.596 29.968
+148 "I12" 85 30 10 0 16.114 20.056 36.433
+132 "I13" 55 55 10 0 21.206 19.17 27.442
+112 "I14" 30 30 10 0 41.422 40.699 42.001
+240 "I15" 100 55 20 0 8.4259 10.278 22.043
+319 "I16" 100 30 30 0 10.129 15.397 25.408
+591 "I17" 20 55 85 0 32 26.649 5.4117
+1396 "I18" 40 27 27 80 4.0894 4.3142 3.5719
+627 "I19" 70 55 85 0 12.285 13.572 5.4121
+174 "I20" 10 20 20 0 58.796 58.174 43.686
+168 "I21" 0 55 20 0 46.124 35.582 26.484
+220 "I22" 70 30 20 0 20.264 23.866 32.415
+204 "I23" 40 55 20 0 26.384 22.796 24.217
+184 "I24" 20 30 20 0 46.704 44.962 37.252
+402 "I25" 100 55 40 0 7.331 9.8658 15.652
+1275 "I26" 100 0 40 100 1.2309 1.6899 1.6818
+1270 "I27" 0 40 40 100 3.2681 3.0735 1.5546
+1269 "I28" 0 0 40 100 2.9669 3.1625 1.83
+1276 "I29" 100 40 40 100 1.4023 1.624 1.4424
+229 "I30" 85 30 20 0 15.201 19.611 31.303
+600 "I31" 30 55 85 0 27.177 23.519 5.3512
+193 "I32" 30 30 20 0 40.3 40.044 36.324
+636 "I33" 85 55 85 0 8.5285 11.006 5.5658
+944 "J1" 100 70 100 20 3.8385 5.3703 2.7357
+756 "J2" 70 20 0 20 18.512 21.78 36.238
+932 "J3" 40 70 100 20 15.288 12.495 2.4705
+744 "J4" 20 20 0 20 39.781 39.757 41.498
+914 "J5" 0 70 100 20 26.393 18.799 2.4983
+83 "J6" 0 10 10 0 73.893 74.191 58.471
+143 "J7" 70 85 10 0 11.962 8.8492 17.294
+119 "J8" 40 10 10 0 43.033 47.993 51.622
+107 "J9" 20 85 10 0 27.765 17.167 17.844
+155 "J10" 100 10 10 0 14.44 21.781 43.785
+805 "J11" 0 40 20 20 38.936 33.996 25.233
+853 "J12" 20 40 40 20 29.539 27.398 16.776
+823 "J13" 40 40 20 20 23.556 22.971 23.03
+865 "J14" 70 40 40 20 12.596 14.604 14.68
+835 "J15" 100 40 20 20 7.5128 10.212 20.015
+172 "J16" 10 0 20 0 70.716 76.081 54.653
+232 "J17" 85 70 20 0 9.9958 9.5404 18.27
+208 "J18" 55 0 20 0 35.457 44.307 46.319
+196 "J19" 30 70 20 0 26.484 19.44 19.264
+317 "J20" 100 10 30 0 12.264 20.462 31.235
+404 "J21" 100 85 40 0 5.5846 5.711 10.662
+182 "J22" 20 10 20 0 56.852 60.272 47.551
+620 "J23" 55 85 85 0 13.193 10.033 3.8012
+218 "J24" 70 10 20 0 24.73 31.961 40.398
+584 "J25" 10 85 85 0 29.365 18.455 3.8402
+173 "J26" 10 10 20 0 64.663 66.846 49.307
+215 "J27" 55 85 20 0 15.327 10.768 15.072
+209 "J28" 55 10 20 0 32.457 38.971 42.15
+179 "J29" 10 85 20 0 31.401 19.157 15.756
+803 "J30" 0 10 20 20 51.767 52.562 36.611
+1274 "J31" 40 100 40 100 2.0691 1.6856 1.0061
+821 "J32" 40 10 20 20 31.147 35.136 32.826
+776 "J33" 10 70 10 20 26.657 18.779 17.602
+1120 "K1" 100 100 20 60 2.7153 2.3352 3.7231
+1161 "K2" 70 0 70 60 5.2448 7.7346 3.9283
+1110 "K3" 40 100 20 60 5.3374 3.4243 3.4798
+1151 "K4" 20 0 70 60 11.544 13.308 4.2438
+1100 "K5" 0 100 20 60 8.2906 4.8151 3.5443
+721 "K6" 100 0 100 0 8.1076 18.912 5.7582
+63 "K7" 70 100 0 0 10.674 6.4968 15.82
+685 "K8" 40 0 100 0 36.515 45.894 5.8715
+27 "K9" 20 100 0 0 25.023 13.172 15.983
+649 "K10" 0 0 100 0 67.831 73.183 6.3566
+397 "K11" 100 0 40 0 12.306 22.492 28.548
+387 "K12" 70 100 40 0 9.5791 6.4536 8.6392
+361 "K13" 40 0 40 0 42.364 51.362 33.35
+351 "K14" 20 100 40 0 23.924 13.131 8.6622
+325 "K15" 0 0 40 0 74.951 79.955 36.787
+73 "K16" 100 0 0 0 17.316 25.666 56.941
+711 "K17" 70 100 100 0 8.1065 6.0234 2.3028
+37 "K18" 40 0 0 0 48.74 55.767 67.464
+675 "K19" 20 100 100 0 22.791 12.85 2.2624
+1367 "K20" 0 0 0 0 83.532 86.556 75.658
+1170 "K21" 100 100 70 60 2.2415 2.1937 1.767
+1111 "K22" 70 0 20 60 6.7365 8.9202 10.488
+1160 "K23" 40 100 70 60 4.9604 3.4503 1.6823
+1101 "K24" 20 0 20 60 13.925 15.376 12.153
+1150 "K25" 0 100 70 60 7.7356 4.82 1.7333
+1268 "K26" 100 100 0 100 1.586 1.3361 1.2371
+929 "K27" 40 10 100 20 25.041 30.091 4.2447
+1262 "K28" 0 100 0 100 2.3217 1.6655 1.0172
+916 "K29" 10 0 100 20 42.296 47.086 4.8745
+54 "K30" 55 100 0 0 14.16 8.1322 15.9
+614 "K31" 55 10 85 0 25.842 33.805 8.7239
+18 "K32" 10 100 0 0 28.671 14.852 16.045
+578 "K33" 10 10 85 0 55.572 59.114 9.4388
+3 "L1" 0 20 0 0 69.597 66.565 60.838
+673 "L2" 20 70 100 0 27.825 20.432 2.9018
+39 "L3" 40 20 0 0 40.572 42.615 53.944
+709 "L4" 70 70 100 0 10.2 10.073 3.0376
+75 "L5" 100 20 0 0 14.395 19.681 46.296
+1149 "L6" 0 70 70 60 8.9749 6.7909 2.3081
+1102 "L7" 20 20 20 60 12.058 12.309 10.166
+1159 "L8" 40 70 70 60 5.4431 4.5543 2.1995
+1112 "L9" 70 20 20 60 5.7816 6.99 8.7996
+1169 "L10" 100 70 70 60 2.3761 2.8104 2.2458
+327 "L11" 0 20 40 0 62.366 61.062 29.931
+349 "L12" 20 70 40 0 29.877 21.69 13.737
+363 "L13" 40 20 40 0 35.967 39.85 27.525
+385 "L14" 70 70 40 0 12.394 11.372 12.969
+399 "L15" 100 20 40 0 10.365 17.364 23.838
+1099 "L16" 0 70 20 60 10.103 7.3489 5.5678
+1152 "L17" 20 20 70 60 10.044 10.668 3.7279
+1109 "L18" 40 70 20 60 6.1706 4.8349 5.1079
+1162 "L19" 70 20 70 60 4.6655 6.2353 3.4497
+1119 "L20" 100 70 20 60 2.8528 2.9433 4.9122
+651 "L21" 0 20 100 0 56.365 55.495 5.0428
+25 "L22" 20 70 0 0 31.967 22.387 26.188
+687 "L23" 40 20 100 0 31.007 35.545 4.8234
+61 "L24" 70 70 0 0 14.307 11.92 24.622
+723 "L25" 100 20 100 0 6.9585 14.721 5.1854
+170 "L26" 0 85 20 0 35.618 21.393 16.061
+598 "L27" 30 30 85 0 34.305 35.444 7.2538
+206 "L28" 40 85 20 0 19.826 13.094 15.005
+634 "L29" 85 30 85 0 10.637 16.574 7.1922
+739 "L30" 10 40 0 20 36.361 31.929 32.553
+923 "L31" 20 10 100 20 34.532 38.16 4.3913
+1264 "L32" 40 40 0 100 3.025 2.9233 2.7653
+941 "L33" 100 10 100 20 5.8796 12.705 4.4488
+725 "M1" 100 40 100 0 5.6657 10.768 4.437
+59 "M2" 70 40 0 0 19.82 20.835 38.153
+689 "M3" 40 40 100 0 25.449 25.81 3.9199
+23 "M4" 20 40 0 0 43.988 39.086 43.242
+653 "M5" 0 40 100 0 46.826 40.833 4.0776
+401 "M6" 100 40 40 0 8.508 12.792 19.04
+383 "M7" 70 40 40 0 15.911 18.715 19.337
+365 "M8" 40 40 40 0 28.9 28.624 21.058
+347 "M9" 20 40 40 0 39.477 36.198 21.787
+329 "M10" 0 40 40 0 51.464 44.787 23.357
+1118 "M11" 100 40 20 60 3.2583 4.1229 6.8222
+1163 "M12" 70 40 70 60 4.1138 4.892 2.905
+1108 "M13" 40 40 20 60 7.7936 7.5097 7.7076
+1153 "M14" 20 40 70 60 8.5393 8.172 3.0297
+1098 "M15" 0 40 20 60 12.826 11.415 8.5245
+77 "M16" 100 40 0 0 11.697 14.469 36.691
+707 "M17" 70 40 100 0 13.879 17.302 4.1153
+41 "M18" 40 40 0 0 32.737 30.791 41.385
+671 "M19" 20 40 100 0 36.014 33.591 3.9651
+5 "M20" 0 40 0 0 56.387 48.115 45.856
+1168 "M21" 100 40 70 60 2.5594 3.7583 2.8973
+1113 "M22" 70 40 20 60 4.8984 5.29 7.0265
+1158 "M23" 40 40 70 60 6.4157 6.5513 2.9637
+1103 "M24" 20 40 20 60 10.233 9.4169 8.1469
+1148 "M25" 0 40 70 60 10.845 9.911 3.1434
+1266 "M26" 100 0 0 100 1.2487 1.6429 2.2918
+1281 "M27" 40 0 100 100 1.9438 2.3714 0.98627
+1260 "M28" 0 0 0 100 2.6842 2.7971 2.1442
+919 "M29" 10 40 100 20 30.294 27.803 3.3279
+231 "M30" 85 55 20 0 11.711 12.702 22.558
+618 "M31" 55 55 85 0 17.046 16.86 5.3492
+195 "M32" 30 55 20 0 30.939 25.813 24.749
+582 "M33" 10 55 85 0 36.867 29.737 5.4828
+7 "N1" 0 70 0 0 41.064 27.7 27.285
+669 "N2" 20 20 100 0 43.633 45.789 4.9326
+43 "N3" 40 70 0 0 23.633 17.469 25.317
+705 "N4" 70 20 100 0 16.392 23.335 4.9379
+79 "N5" 100 70 0 0 8.126 7.9858 23.641
+1147 "N6" 0 20 70 60 12.587 12.713 3.8151
+1104 "N7" 20 70 20 60 8.0904 6.0557 5.3789
+1157 "N8" 40 20 70 60 7.5476 8.6054 3.5775
+1114 "N9" 70 70 20 60 4.1371 3.6437 4.9376
+1167 "N10" 100 20 70 60 2.7694 4.6386 3.3816
+331 "N11" 0 70 40 0 38.555 26.426 14.048
+345 "N12" 20 20 40 0 48.9 50.47 29.029
+367 "N13" 40 70 40 0 21.346 16.675 13.201
+381 "N14" 70 20 40 0 20.214 26.349 24.972
+403 "N15" 100 70 40 0 6.3393 7.4821 12.814
+1097 "N16" 0 20 20 60 15.268 14.982 10.814
+1154 "N17" 20 70 70 60 7.1701 5.6409 2.2541
+1107 "N18" 40 20 20 60 9.4122 10.149 9.7345
+1164 "N19" 70 70 70 60 3.633 3.517 2.2485
+1117 "N20" 100 20 20 60 3.6367 5.1854 8.293
+655 "N21" 0 70 100 0 36.241 25.005 2.8668
+21 "N22" 20 20 0 0 54.93 54.652 57.434
+691 "N23" 40 70 100 0 19.499 15.579 2.9145
+57 "N24" 70 20 0 0 24.704 28.996 49.5
+727 "N25" 100 70 100 0 4.5299 6.5549 3.3469
+166 "N26" 0 30 20 0 59.495 54.521 39.124
+602 "N27" 30 85 85 0 21.419 14.317 3.7354
+202 "N28" 40 30 20 0 34.441 35.391 35.145
+638 "N29" 85 85 85 0 6.544 6.5053 3.8482
+767 "N30" 0 10 10 20 52.858 53.287 42.421
+1279 "N31" 0 40 100 100 2.5356 2.5301 0.93376
+785 "N32" 40 10 10 20 32.161 35.818 38.145
+1285 "N33" 100 40 100 100 1.3834 1.7214 0.9272
+1116 "O1" 100 0 20 60 4.0233 6.3135 9.7349
+1165 "O2" 70 100 70 60 3.3702 2.7166 1.7203
+1106 "O3" 40 0 20 60 10.885 12.753 11.594
+1155 "O4" 20 100 70 60 6.3144 4.1045 1.6767
+1096 "O5" 0 0 20 60 17.552 18.567 13.037
+729 "O6" 100 100 100 0 3.664 3.8734 2.2561
+55 "O7" 70 0 0 0 30.004 38.132 61.496
+693 "O8" 40 100 100 0 15.807 9.6095 2.2784
+19 "O9" 20 0 0 0 66.155 71.475 71.889
+657 "O10" 0 100 100 0 30.384 16.417 2.1357
+1166 "O11" 100 0 70 60 2.9468 5.4992 3.8083
+1115 "O12" 70 100 20 60 3.6881 2.6925 3.5312
+1156 "O13" 40 0 70 60 8.7063 10.81 4.1087
+1105 "O14" 20 100 20 60 6.8185 4.1293 3.5251
+1146 "O15" 0 0 70 60 14.463 15.773 4.3803
+405 "O16" 100 100 40 0 4.8934 4.227 8.7463
+379 "O17" 70 0 40 0 24.306 34.442 30.471
+369 "O18" 40 100 40 0 17.036 9.9095 8.4951
+343 "O19" 20 0 40 0 57.937 65.282 35.342
+333 "O20" 0 100 40 0 31.525 16.713 8.6926
+81 "O21" 100 100 0 0 5.9847 4.2869 15.899
+703 "O22" 70 0 100 0 19.672 30.335 5.7155
+45 "O23" 40 100 0 0 18.459 10.135 16.046
+667 "O24" 20 0 100 0 51.529 59.137 6.0021
+9 "O25" 0 100 0 0 32.54 16.641 16.24
+755 "O26" 70 10 0 20 20.246 24.805 40.149
+1283 "O27" 40 100 100 100 2.1248 1.9121 0.8517
+743 "O28" 20 10 0 20 43.426 45.187 46.138
+921 "O29" 10 100 100 20 19.493 11.05 1.9553
+227 "O30" 85 10 20 0 18.576 26.246 38.785
+702 "O31" 55 100 100 0 11.506 7.6255 2.2956
+191 "O32" 30 10 20 0 49.042 53.595 46.035
+666 "O33" 10 100 100 0 26.519 14.59 2.2261
+72 "P1" 85 100 0 0 8.1029 5.2979 15.827
+340 "P2" 10 70 40 0 34.272 24.137 13.968
+483 "P3" 100 55 55 0 6.5506 9.3542 11.193
+1047 "P4" 0 20 100 40 24.607 24.742 2.8903
+966 "P5" 100 0 0 40 7.8864 11.734 24.621
+1041 "P6" 100 0 70 40 4.9885 9.9939 6.791
+972 "P7" 0 20 20 40 29.603 28.971 20.875
+1043 "P8" 100 40 70 40 3.8205 6.1544 4.8109
+332 "P9" 0 85 40 0 34.717 21.033 11.097
+153 "P10" 85 100 10 0 7.7939 5.3137 13.803
+1020 "P11" 100 100 40 40 3.1018 2.7833 4.3737
+341 "P12" 10 85 40 0 30.755 19.063 11.102
+645 "P13" 100 55 85 0 5.452 8.6712 5.5797
+337 "P14" 10 30 40 0 50.294 47.764 25.922
+1016 "P15" 100 0 40 40 6.031 10.716 12.899
+975 "P16" 0 100 20 40 14.692 8.0191 6.1097
+1026 "P17" 20 0 70 40 23.972 27.505 7.9233
+985 "P18" 40 100 20 40 8.8642 5.2767 5.9276
+1036 "P19" 70 0 70 40 10.213 15.128 7.1568
+995 "P20" 100 100 20 40 3.4196 2.8206 6.1531
+839 "P21" 0 10 40 20 48.941 50.379 24.983
+413 "P22" 0 85 55 0 34.221 20.855 7.9812
+857 "P23" 40 10 40 20 28.681 33.245 22.467
+449 "P24" 40 85 55 0 18.641 12.797 7.6507
+869 "P25" 100 10 40 20 8.6715 14.974 19.269
+504 "P26" 10 100 70 0 27.004 14.761 4.3751
+1403 "P27" 20 12 12 100 2.3544 2.4509 1.8872
+540 "P28" 55 100 70 0 12.158 7.8497 4.4409
+137 "P29" 70 10 10 0 25.806 32.587 47.472
+585 "P30" 10 100 85 0 26.788 14.692 3.1709
+190 "P31" 30 0 20 0 53.459 60.877 50.898
+621 "P32" 55 100 85 0 11.844 7.745 3.2349
+226 "P33" 85 0 20 0 20.45 29.973 42.588
+388 "Q1" 85 0 40 0 17.714 28.071 29.4
+354 "Q2" 30 20 40 0 42.187 45.057 28.305
+392 "Q3" 85 40 40 0 11.752 15.464 19.015
+954 "Q4" 20 70 0 40 15.189 11.028 12.597
+1065 "Q5" 70 100 100 40 4.8713 3.7963 1.602
+990 "Q6" 70 100 20 40 5.5746 3.7845 5.993
+1029 "Q7" 20 70 70 40 13.561 10.362 3.7644
+988 "Q8" 70 40 20 40 9.1547 10.107 13.621
+346 "Q9" 20 30 40 0 44.17 43.164 25.365
+380 "Q10" 70 10 40 0 22.221 30.224 27.687
+1011 "Q11" 70 0 40 40 11.281 15.853 13.82
+355 "Q12" 30 30 40 0 38.083 38.522 24.763
+393 "Q13" 85 55 40 0 10.347 12.121 15.787
+359 "Q14" 30 85 40 0 22.653 14.886 10.796
+1015 "Q15" 70 100 40 40 5.2597 3.798 4.3099
+1044 "Q16" 100 70 70 40 3.254 4.0928 3.564
+987 "Q17" 70 20 20 40 11.085 13.59 17.234
+1034 "Q18" 40 70 70 40 9.9768 8.179 3.6375
+977 "Q19" 20 20 20 40 23.514 24.033 19.687
+1024 "Q20" 0 70 70 40 17.151 12.502 3.8006
+461 "Q21" 70 10 55 0 20.669 29.041 19.486
+447 "Q22" 40 55 55 0 24.03 21.485 11.773
+425 "Q23" 20 10 55 0 51.206 55.742 22.11
+411 "Q24" 0 55 55 0 43.461 33.955 12.825
+844 "Q25" 10 0 40 20 47.596 52.102 27.007
+637 "Q26" 85 70 85 0 7.3644 8.3584 4.5689
+129 "Q27" 55 20 10 0 30.721 34.726 44.429
+601 "Q28" 30 70 85 0 23.755 18.069 4.3796
+1398 "Q29" 10 6 6 80 7.0105 7.296 6.1388
+629 "Q30" 70 85 85 0 9.3822 8 3.8025
+130 "Q31" 55 30 10 0 27.711 29.708 39.164
+593 "Q32" 20 85 85 0 25.359 16.384 3.7822
+94 "Q33" 10 30 10 0 54.468 50.787 44.521
+36 "R1" 30 100 0 0 21.556 11.576 16.017
+376 "R2" 55 70 40 0 16.504 13.853 13.09
+374 "R3" 55 40 40 0 22.024 23.501 20.533
+1057 "R4" 40 20 100 40 13.816 15.962 2.8108
+956 "R5" 40 0 0 40 22.126 25.279 29.614
+1031 "R6" 40 0 70 40 17.712 21.988 7.536
+982 "R7" 40 20 20 40 17.794 19.295 18.567
+1033 "R8" 40 40 70 40 12.562 12.837 5.1282
+368 "R9" 40 85 40 0 19.001 12.943 10.645
+603 "R10" 30 100 85 0 19.457 11.28 3.1632
+1010 "R11" 40 100 40 40 8.5279 5.2899 4.3262
+377 "R12" 55 85 40 0 14.612 10.65 10.619
+375 "R13" 55 55 40 0 18.962 18.108 16.309
+373 "R14" 55 30 40 0 24.694 27.954 23.328
+1006 "R15" 40 0 40 40 18.948 22.947 15.201
+973 "R16" 0 40 20 40 24.664 21.767 16.297
+1028 "R17" 20 40 70 40 17.171 16.287 5.3583
+983 "R18" 40 40 20 40 14.701 14.35 14.562
+1038 "R19" 70 40 70 40 7.3528 8.9015 4.9868
+993 "R20" 100 40 20 40 5.1831 6.9074 12.774
+846 "R21" 10 20 40 20 40.547 40.963 22.243
+409 "R22" 0 30 55 0 54.926 51.085 18.191
+427 "R23" 20 30 55 0 42.488 41.9 17.571
+445 "R24" 40 30 55 0 31.051 33.066 16.879
+463 "R25" 70 30 55 0 17.193 21.865 15.919
+581 "R26" 10 40 85 0 42.195 38.09 6.6443
+105 "R27" 20 55 10 0 36.68 29.43 29.303
+617 "R28" 55 40 85 0 19.79 21.875 6.4114
+141 "R29" 70 55 10 0 16.099 15.606 26.608
+573 "R30" 0 55 85 0 41.699 32.615 5.5737
+194 "R31" 30 40 20 0 36.038 33.681 31.325
+609 "R32" 40 55 85 0 22.77 20.607 5.3262
+1401 "R33" 60 45 45 100 1.7812 1.8318 1.268
+352 "S1" 30 0 40 0 49.662 57.958 34.147
+390 "S2" 85 20 40 0 14.827 21.597 24.334
+356 "S3" 30 40 40 0 33.95 32.236 21.274
+964 "S4" 70 70 0 40 7.5493 6.3917 11.819
+1055 "S5" 20 100 100 40 10.959 6.6601 1.5403
+980 "S6" 20 100 20 40 11.707 6.6171 6.0027
+1039 "S7" 70 70 70 40 6.0395 5.8289 3.6118
+978 "S8" 20 40 20 40 19.514 17.974 15.42
+382 "S9" 70 30 40 0 18.083 22.458 22.119
+344 "S10" 20 10 40 0 53.406 57.674 32.389
+1001 "S11" 20 0 40 40 25.382 28.644 16.04
+391 "S12" 85 30 40 0 13.302 18.459 21.66
+357 "S13" 30 55 40 0 29.224 24.877 17.005
+395 "S14" 85 85 40 0 7.9931 7.0878 10.595
+1005 "S15" 20 100 40 40 11.468 6.6943 4.4176
+724 "S16" 100 30 100 0 6.3165 12.701 4.8035
+475 "S17" 85 70 55 0 8.3754 8.8787 9.2435
+453 "S18" 55 20 55 0 25.734 31.381 18.381
+439 "S19" 30 70 55 0 24.743 18.69 9.4446
+417 "S20" 10 20 55 0 53.632 54.204 20.345
+969 "S21" 100 70 0 40 4.4711 4.4108 11.353
+1062 "S22" 70 20 100 40 7.8759 11.047 2.8479
+959 "S23" 40 70 0 40 11.581 8.7901 12.166
+1052 "S24" 20 20 100 40 19.245 20.452 2.8827
+949 "S25" 0 70 0 40 18.935 13.249 13.033
+633 "S26" 85 20 85 0 11.655 19.202 7.8973
+133 "S27" 55 70 10 0 17.99 14.262 21.622
+597 "S28" 30 20 85 0 37.726 41.19 8.1607
+97 "S29" 10 70 10 0 35.88 24.704 23.163
+625 "S30" 70 30 85 0 15.417 20.507 7.1937
+134 "S31" 55 85 10 0 15.742 10.852 17.356
+589 "S32" 20 30 85 0 40.348 40.08 7.3947
+98 "S33" 10 85 10 0 31.817 19.291 18.193
+741 "T1" 10 100 0 20 20.92 11.046 11.999
+485 "T2" 100 85 55 0 5.0324 5.4618 7.6477
+338 "T3" 10 40 40 0 45.243 40.342 22.51
+1067 "T4" 100 20 100 40 3.8495 7.4907 2.9603
+946 "T5" 0 0 0 40 36.398 37.862 33.394
+1021 "T6" 0 0 70 40 30.347 32.944 8.1709
+992 "T7" 100 20 20 40 6.1477 9.1347 15.967
+1023 "T8" 0 40 70 40 21.896 19.753 5.4679
+566 "T9" 100 85 70 0 4.5612 5.2604 5.3847
+777 "T10" 10 100 10 20 20.725 11.051 10.533
+1000 "T11" 0 100 40 40 14.375 8.0539 4.4273
+647 "T12" 100 85 85 0 4.2488 5.1601 3.9195
+339 "T13" 10 55 40 0 39.423 31.475 17.861
+643 "T14" 100 30 85 0 6.846 13.168 7.2542
+996 "T15" 0 0 40 40 31.718 34.029 16.657
+415 "T16" 10 0 55 0 63.997 70.524 24.637
+261 "T17" 10 100 30 0 27.879 14.844 10.292
+451 "T18" 55 0 55 0 30.669 40.701 22.033
+297 "T19" 55 100 30 0 13.148 8 10.121
+146 "T20" 85 10 10 0 19.783 26.989 45.684
+1050 "T21" 0 100 100 40 13.872 8.1063 1.6531
+951 "T22" 20 0 0 40 29.196 31.595 31.502
+1060 "T23" 40 100 100 40 8.0648 5.252 1.5254
+961 "T24" 70 0 0 40 13.926 17.677 27.023
+1070 "T25" 100 100 100 40 2.6364 2.7274 1.6146
+577 "T26" 10 0 85 0 60.79 67.419 10.52
+522 "T27" 30 100 70 0 19.696 11.34 4.3352
+613 "T28" 55 0 85 0 28.109 38.325 9.5404
+1400 "T29" 80 65 65 100 1.6643 1.6892 1.0143
+569 "T30" 0 10 85 0 62.99 65.129 9.7311
+117 "T31" 30 100 10 0 21.029 11.408 13.717
+605 "T32" 40 10 85 0 34.556 41.383 8.8728
+80 "T33" 100 85 0 0 6.9675 5.9349 19.448
+772 "U1" 10 0 10 20 52.057 55.554 45.831
+773 "U2" 10 10 10 20 47.759 49.162 41.538
+1399 "U3" 100 85 85 100 1.6187 1.6394 0.89845
+737 "U4" 10 10 0 20 48.784 49.713 47.296
+1408 "U5" 100 100 0 70 2.3691 1.9568 3.3718
+1409 "U6" 100 0 100 70 2.199 4.0799 1.855
+1410 "U7" 0 100 100 70 5.5848 3.7343 1.077
+1411 "U8" 40 40 0 70 5.7934 5.5192 6.6041
+1412 "U9" 40 0 40 70 6.7115 8.06 5.5183
+1413 "U10" 0 40 40 70 7.6432 6.9353 3.875
+940 "U11" 100 0 100 20 6.04 13.773 4.7479
+759 "U12" 70 100 0 20 8.2981 5.199 11.988
+928 "U13" 40 0 100 20 26.943 33.718 4.5748
+747 "U14" 20 100 0 20 18.477 9.8932 11.977
+910 "U15" 0 0 100 20 47.123 51.088 4.9814
+917 "U16" 10 10 100 20 39.259 42.042 4.485
+881 "U17" 10 10 70 20 41.368 44.128 11.608
+1211 "U18" 100 100 0 80 2.0214 1.6659 2.424
+672 "U19" 20 55 100 0 31.603 26.297 3.3949
+26 "U20" 20 85 0 0 28.234 17.308 20.611
+717 "U21" 85 55 100 0 8.0848 10.71 3.7004
+1227 "U22" 100 100 40 80 2.0471 1.8756 1.7224
+510 "U23" 20 55 70 0 32.554 27.054 8.1303
+269 "U24" 20 85 30 0 26.943 16.945 13.047
+555 "U25" 85 55 70 0 9.0366 11.316 7.9158
+396 "U26" 85 100 40 0 7.0104 5.2661 8.714
+290 "U27" 55 10 30 0 31.15 38.101 34.962
+360 "U28" 30 100 40 0 20.282 11.426 8.5811
+254 "U29" 10 10 30 0 62.704 65.312 40.658
+477 "U30" 85 100 55 0 6.5143 5.1384 6.2913
+47 "U31" 55 10 0 0 34.846 40.287 57.695
+441 "U32" 30 100 55 0 20.015 11.407 6.151
+11 "U33" 10 10 0 0 68.278 69.374 66.073
+1429 "V1" 7 0 0 7 70.46 73.92 67.261
+1404 "V2" 10 6 6 100 2.5919 2.6833 2.038
+1431 "V3" 7 7 0 7 66.447 68.034 62.702
+1390 "V4" 40 27 27 60 8.7749 9.2534 8.0212
+1433 "V5" 7 0 7 7 69.32 73.145 61.541
+1386 "V6" 10 6 6 40 30.82 32.145 28.568
+1435 "V7" 7 7 7 7 65.491 67.488 57.736
+1405 "V8" 100 0 0 70 3.3139 4.757 8.8718
+1406 "V9" 0 100 0 70 5.8208 3.4664 3.0148
+1407 "V10" 0 0 100 70 9.7971 10.768 1.8949
+732 "V11" 0 20 0 20 49.803 47.82 43.811
+926 "V12" 20 70 100 20 20.873 15.756 2.4785
+750 "V13" 40 20 0 20 30.145 31.768 39.381
+938 "V14" 70 70 100 20 8.5654 8.4502 2.5669
+762 "V15" 100 20 0 20 10.566 14.545 33.543
+736 "V16" 10 0 0 20 53.253 56.303 52.493
+811 "V17" 10 40 20 20 35.05 31.312 24.766
+14 "V18" 10 40 0 0 50.032 43.488 44.395
+688 "V19" 40 30 100 0 28.329 30.701 4.3862
+1206 "V20" 70 70 0 80 2.8994 2.5411 3.343
+1245 "V21" 0 40 100 80 5.6651 5.3425 1.396
+257 "V22" 10 40 30 0 46.555 41.32 27.521
+526 "V23" 40 30 70 0 29.655 31.955 11.194
+1222 "V24" 70 70 40 80 2.7614 2.6125 2.2024
+1229 "V25" 0 40 70 80 5.6798 5.2963 1.9558
+503 "V26" 10 85 70 0 29.757 18.637 5.4744
+274 "V27" 30 30 30 0 39.358 39.499 30.446
+1239 "V28" 70 100 70 80 2.5641 2.2416 1.3396
+1225 "V29" 100 40 40 80 2.1514 2.6607 2.8621
+665 "V30" 10 85 100 0 29.156 18.326 2.5466
+31 "V31" 30 30 0 0 42.828 41.521 48.982
+1255 "V32" 70 100 100 80 2.6193 2.3714 1.1818
+1209 "V33" 100 40 0 80 2.2087 2.5172 4.2884
+1480 "W1" 40 40 3 40 15.491 14.783 18.578
+1481 "W2" 3 0 40 40 30.835 33.282 16.572
+1482 "W3" 0 3 40 40 31.096 33.009 16.254
+1483 "W4" 3 3 40 40 30.215 32.277 16.188
+1484 "W5" 40 3 40 40 18.485 22.123 14.796
+1485 "W6" 3 40 40 40 22.306 19.937 10.964
+1425 "W7" 7 7 0 0 72.916 74.562 68.933
+1426 "W8" 7 0 7 0 76.125 80.385 67.437
+1368 "W9" 100 85 85 0 4.2488 5.1601 3.9195
+1428 "W10" 7 7 7 0 71.61 73.677 62.845
+943 "W11" 100 40 100 20 4.7403 8.5831 3.5312
+757 "W12" 70 40 0 20 15.154 16.041 28.325
+931 "W13" 40 40 100 20 19.538 20.131 3.252
+745 "W14" 20 40 0 20 32.397 29.093 31.919
+913 "W15" 0 40 100 20 33.852 30.15 3.3353
+882 "W16" 10 20 70 20 38.037 38.894 10.534
+880 "W17" 10 0 70 20 44.871 49.726 12.722
+67 "W18" 85 30 0 0 17.178 20.552 42.38
+1248 "W19" 40 0 100 80 4.5413 5.658 1.6254
+30 "W20" 30 20 0 0 47.48 48.506 55.784
+713 "W21" 85 10 100 0 12.311 21.57 5.442
+310 "W22" 85 30 30 0 14.221 19.029 26.141
+1232 "W23" 40 0 70 80 4.7088 5.7638 2.5301
+273 "W24" 30 20 30 0 43.523 46.036 34.48
+551 "W25" 85 10 70 0 13.518 22.62 12.816
+1226 "W26" 100 70 40 80 2.1369 2.2414 2.227
+517 "W27" 30 30 70 0 35.091 36.183 11.185
+276 "W28" 30 55 30 0 30.089 25.385 20.636
+1241 "W29" 100 40 70 80 2.0726 2.6889 1.9514
+1210 "W30" 100 70 0 80 2.1361 2.0453 3.268
+679 "W31" 30 30 100 0 33.743 34.869 4.3993
+33 "W32" 30 55 0 0 32.472 26.538 33.225
+1257 "W33" 100 40 100 80 2.0186 2.7006 1.4305
+1418 "X1" 3 0 0 3 78.087 81.304 72.192
+1471 "X2" 3 40 0 40 24.528 21.469 20.832
+1416 "X3" 0 3 3 0 80.718 82.931 70.76
+1473 "X4" 3 0 3 40 35.081 36.717 31.93
+1474 "X5" 40 0 3 40 21.975 25.198 28.589
+1450 "X6" 0 40 0 3 54.231 46.336 44.17
+1402 "X7" 40 27 27 100 1.9928 2.0843 1.578
+1451 "X8" 3 40 0 3 52.764 45.324 43.924
+1478 "X9" 0 40 3 40 25.167 21.969 20.329
+1479 "X10" 3 40 3 40 24.43 21.434 20.192
+238 "X11" 100 30 20 0 10.953 15.845 30.175
+114 "X12" 30 55 10 0 31.677 26.184 28.689
+607 "X13" 40 30 85 0 28.89 31.247 7.2553
+726 "X14" 100 55 100 0 5.0689 8.4682 3.8849
+571 "X15" 0 30 85 0 52.284 48.719 7.5835
+797 "X16" 100 10 10 20 10.649 16.035 32.114
+885 "X17" 10 100 70 20 19.827 11.129 3.648
+10 "X18" 10 0 0 0 75.117 79.325 73.888
+296 "X19" 55 85 30 0 14.958 10.704 12.697
+38 "X20" 40 10 0 0 44.525 48.85 60.426
+259 "X21" 10 70 30 0 34.846 24.357 16.865
+496 "X22" 10 0 70 0 61.985 68.656 16.253
+701 "X23" 55 85 100 0 12.855 9.8743 2.6087
+524 "X24" 40 10 70 0 35.387 42.195 13.842
+664 "X25" 10 70 100 0 32.058 22.77 2.9035
+499 "X26" 10 30 70 0 47.31 45.407 11.733
+278 "X27" 30 85 30 0 22.93 14.868 12.814
+535 "X28" 55 30 70 0 22.277 26.128 10.97
+314 "X29" 85 85 30 0 8.3629 7.174 12.667
+661 "X30" 10 30 100 0 45.626 43.799 4.5115
+35 "X31" 30 85 0 0 24.287 15.231 20.388
+697 "X32" 55 30 100 0 20.902 24.885 4.4299
+71 "X33" 85 85 0 0 9.4362 7.3338 19.684
+1455 "2A1" 0 40 3 3 53.993 46.223 42.661
+1461 "2A2" 0 3 40 3 70.383 74.295 34.724
+1448 "2A3" 40 0 0 3 47.195 53.953 64.998
+1449 "2A4" 40 3 0 3 46.112 52.161 63.209
+1464 "2A5" 0 40 40 3 49.506 43.168 22.613
+1465 "2A6" 3 40 40 3 48.143 42.244 22.502
+1419 "2A7" 0 3 0 3 78.35 80.439 70.76
+1467 "2A8" 3 0 0 40 35.38 36.979 33.117
+1468 "2A9" 0 3 0 40 35.504 36.593 32.45
+1469 "2A10" 3 3 0 40 34.505 35.714 32.02
+945 "2A11" 100 100 100 20 3.2509 3.4049 2.0486
+754 "2A12" 70 0 0 20 22.089 28.05 44.087
+933 "2A13" 40 100 100 20 12.377 7.6664 1.9719
+742 "2A14" 20 0 0 20 47.424 51.241 51.225
+915 "2A15" 0 100 100 20 21.691 12.124 1.9921
+884 "2A16" 10 70 70 20 24.384 17.733 5.538
+833 "2A17" 100 10 20 20 9.9756 15.72 27.732
+1259 "2A18" 100 100 100 80 2.113 2.1285 1.1794
+1200 "2A19" 40 0 0 80 5.5174 6.2971 6.7766
+674 "2A20" 20 85 100 0 25.196 16.32 2.5594
+65 "2A21" 85 10 0 0 21.358 27.932 53.463
+1243 "2A22" 100 100 70 80 2.0847 2.0389 1.3911
+1216 "2A23" 40 0 40 80 4.9677 5.9205 3.9901
+512 "2A24" 20 85 70 0 25.681 16.532 5.3409
+308 "2A25" 85 10 30 0 17.37 25.474 32.287
+1224 "2A26" 100 0 40 80 2.1836 3.3985 3.6401
+521 "2A27" 30 85 70 0 21.75 14.466 5.2726
+272 "2A28" 30 10 30 0 47.416 52.397 38.143
+557 "2A29" 85 85 70 0 6.8894 6.6312 5.3769
+1208 "2A30" 100 0 0 80 2.454 3.4793 5.9636
+683 "2A31" 30 85 100 0 21.18 14.225 2.5591
+29 "2A32" 30 10 0 0 52.057 55.456 62.416
+719 "2A33" 85 85 100 0 6.2798 6.3626 2.7033
+730 "2B1" 0 0 0 20 58.945 61.186 53.819
+927 "2B2" 20 100 100 20 17.147 9.9331 1.9505
+748 "2B3" 40 0 0 20 35.871 40.917 48.425
+939 "2B4" 70 100 100 20 6.9229 5.146 2.0433
+760 "2B5" 100 0 0 20 12.282 18.294 40.046
+879 "2B6" 0 100 70 20 22.293 12.288 3.6598
+778 "2B7" 20 0 10 20 46.281 50.535 44.514
+897 "2B8" 40 100 70 20 12.747 7.7894 3.6629
+790 "2B9" 70 0 10 20 21.117 27.534 38.328
+909 "2B10" 100 100 70 20 3.5374 3.4661 3.6518
+802 "2B11" 0 0 20 20 56.601 59.66 40.624
+855 "2B12" 20 100 40 20 17.914 10.071 6.8185
+820 "2B13" 40 0 20 20 33.673 39.499 36.055
+867 "2B14" 70 100 40 20 7.6254 5.2461 6.6314
+832 "2B15" 100 0 20 20 10.812 17.701 30.133
+808 "2B16" 10 0 20 20 50.801 54.679 39.587
+809 "2B17" 10 10 20 20 46.797 48.543 36.027
+662 "2B18" 10 40 100 0 41.429 37.335 4.0161
+40 "2B19" 40 30 0 0 36.619 36.559 47.537
+1254 "2B20" 70 70 100 80 2.5715 2.5962 1.2142
+1197 "2B21" 0 40 0 80 6.4426 5.6762 4.9924
+500 "2B22" 10 40 70 0 42.89 38.711 10.283
+283 "2B23" 40 30 30 0 33.8 35.223 30.04
+1238 "2B24" 70 70 70 80 2.634 2.5979 1.5788
+1213 "2B25" 0 40 40 80 5.8329 5.3275 2.9845
+494 "2B26" 0 85 70 0 33.767 20.676 5.531
+1220 "2B27" 70 0 40 80 3.3832 4.5369 3.8556
+530 "2B28" 40 85 70 0 18.281 12.652 5.3328
+245 "2B29" 0 10 30 0 70.09 71.322 41.218
+656 "2B30" 0 85 100 0 33.072 20.292 2.4698
+1204 "2B31" 70 0 0 80 3.7611 4.7312 6.4057
+692 "2B32" 40 85 100 0 17.532 12.31 2.5727
+2 "2B33" 0 10 0 0 76.386 76.234 68.218
+942 "2C1" 100 20 100 20 5.5861 11.454 4.1569
+758 "2C2" 70 70 0 20 11.215 9.5001 18.543
+930 "2C3" 40 20 100 20 23.258 26.76 3.9332
+746 "2C4" 20 70 0 20 23.84 17.025 19.697
+912 "2C5" 0 20 100 20 40.492 40.409 4.1293
+157 "2C6" 100 30 10 0 11.881 16.348 35.184
+599 "2C7" 30 40 85 0 31.083 30.156 6.447
+121 "2C8" 40 30 10 0 35.412 35.905 40.726
+635 "2C9" 85 40 85 0 9.8396 14.293 6.4971
+85 "2C10" 0 30 10 0 60.945 55.586 45.669
+870 "2C11" 100 20 40 20 7.9757 13.201 17.586
+830 "2C12" 70 70 20 20 10.44 9.2485 14.123
+858 "2C13" 40 20 40 20 26.608 29.542 20.401
+818 "2C14" 20 70 20 20 23.192 16.881 15.065
+840 "2C15" 0 20 40 20 44.975 44.4 22.596
+883 "2C16" 10 40 70 20 31.53 28.832 8.2102
+761 "2C17" 100 10 0 20 11.442 16.401 36.797
+715 "2C18" 85 30 100 0 10.092 16.111 4.6429
+24 "2C19" 20 55 0 0 37.446 29.749 33.815
+678 "2C20" 30 20 100 0 37.103 40.577 4.8694
+69 "2C21" 85 55 0 0 12.993 13.191 30.047
+553 "2C22" 85 30 70 0 11.284 17.084 10.6
+267 "2C23" 20 55 30 0 35.127 28.689 21.218
+516 "2C24" 30 20 70 0 38.702 42.133 12.782
+312 "2C25" 85 55 30 0 11.038 12.408 18.913
+303 "2C26" 70 55 30 0 14.846 15.086 19.26
+508 "2C27" 20 30 70 0 41.217 40.898 11.519
+1218 "2C28" 40 70 40 80 3.6659 3.1681 2.2246
+544 "2C29" 70 30 70 0 16.099 21.105 10.782
+60 "2C30" 70 55 0 0 16.76 15.817 30.664
+670 "2C31" 20 30 100 0 39.738 39.469 4.4475
+1202 "2C32" 40 70 0 80 3.7763 3.0477 3.2991
+706 "2C33" 70 30 100 0 14.854 19.997 4.5073
+733 "2D1" 0 40 0 20 40.233 34.647 33.129
+925 "2D2" 20 40 100 20 26.655 25.285 3.2995
+751 "2D3" 40 40 0 20 24.262 23.011 30.235
+937 "2D4" 70 40 100 20 11.121 13.778 3.3001
+763 "2D5" 100 40 0 20 8.6134 10.69 26.448
+877 "2D6" 0 40 70 20 35.215 31.352 8.2469
+781 "2D7" 20 40 10 20 31.798 28.893 27.848
+895 "2D8" 40 40 70 20 20.565 20.969 7.8714
+793 "2D9" 70 40 10 20 14.627 15.876 24.736
+907 "2D10" 100 40 70 20 5.376 8.9832 7.2014
+242 "2D11" 100 85 20 0 6.248 5.8322 14.826
+110 "2D12" 30 10 10 0 50.445 54.511 53.557
+611 "2D13" 40 85 85 0 17.915 12.48 3.772
+722 "2D14" 100 10 100 0 7.5407 16.73 5.5048
+575 "2D15" 0 85 85 0 33.454 20.538 3.8382
+845 "2D16" 10 10 40 20 44.143 46.488 24.678
+812 "2D17" 10 70 20 20 26.183 18.591 15.339
+658 "2D18" 10 0 100 0 59.555 66.059 6.1393
+539 "2D19" 55 85 70 0 13.564 10.195 5.3184
+686 "2D20" 40 10 100 0 33.715 40.512 5.2951
+502 "2D21" 10 70 70 0 32.955 23.401 6.7685
+253 "2D22" 10 0 30 0 68.467 74.301 44.913
+53 "2D23" 55 85 0 0 16.201 10.972 20.026
+281 "2D24" 40 10 30 0 40.297 46.19 36.753
+16 "2D25" 10 70 0 0 36.4 24.93 26.624
+490 "2D26" 0 30 70 0 53.301 49.669 11.829
+285 "2D27" 40 55 30 0 25.601 22.406 20.218
+1237 "2D28" 70 40 70 80 2.7354 3.1541 1.8793
+249 "2D29" 0 55 30 0 45.291 35.118 22.117
+652 "2D30" 0 30 100 0 51.46 47.868 4.5834
+42 "2D31" 40 55 0 0 27.794 23.398 32.575
+1253 "2D32" 70 40 100 80 2.6706 3.1448 1.3783
+6 "2D33" 0 55 0 0 47.429 36.04 35.201
+639 "2E1" 85 100 85 0 5.8308 4.9409 3.2424
+109 "2E2" 30 0 10 0 55.088 61.998 59.12
+619 "2E3" 55 70 85 0 14.749 12.807 4.4093
+145 "2E4" 85 0 10 0 21.862 30.879 50.22
+583 "2E5" 10 70 85 0 32.511 23.105 4.5305
+798 "2E6" 100 20 10 20 9.8389 14.217 29.27
+902 "2E7" 70 70 70 20 9.0284 8.6722 5.2487
+786 "2E8" 40 20 10 20 29.549 31.581 34.307
+890 "2E9" 20 70 70 20 21.516 16.127 5.5174
+768 "2E10" 0 20 10 20 48.723 47.131 38.268
+872 "2E11" 100 70 40 20 5.0542 5.875 9.601
+828 "2E12" 70 20 20 20 17.147 21.19 27.273
+860 "2E13" 40 70 40 20 16.588 13.074 10.285
+816 "2E14" 20 20 20 20 38.01 38.793 31.561
+842 "2E15" 0 70 40 20 28.249 19.899 10.893
+868 "2E16" 100 0 40 20 9.4045 16.878 20.882
+831 "2E17" 70 100 20 20 7.8989 5.178 9.1518
+856 "2E18" 40 0 40 20 30.615 36.969 24.493
+819 "2E19" 20 100 20 20 18.113 9.908 9.1732
+838 "2E20" 0 0 40 20 53.014 56.721 27.364
+801 "2E21" 100 100 10 20 4.5969 3.5817 10.626
+898 "2E22" 70 0 70 20 16.054 23.845 11.028
+789 "2E23" 40 100 10 20 13.563 7.6862 10.405
+886 "2E24" 20 0 70 20 39.398 45.005 12.506
+771 "2E25" 0 100 10 20 23.23 12.237 10.633
+299 "2E26" 70 10 30 0 23.504 31.165 33.504
+1235 "2E27" 40 100 70 80 3.3405 2.6353 1.3536
+263 "2E28" 20 10 30 0 55.035 58.89 39.483
+548 "2E29" 70 85 70 0 9.7363 8.1738 5.3342
+56 "2E30" 70 10 0 0 27.178 33.283 55.276
+1251 "2E31" 40 100 100 80 3.2688 2.647 1.118
+20 "2E32" 20 10 0 0 60.381 62.688 64.424
+710 "2E33" 70 85 100 0 9.063 7.8401 2.6433
+735 "2F1" 0 100 0 20 23.313 12.186 12.03
+922 "2F2" 20 0 100 20 37.207 42.764 4.7618
+753 "2F3" 40 100 0 20 13.706 7.6698 11.934
+934 "2F4" 70 0 100 20 14.805 22.592 4.5557
+765 "2F5" 100 100 0 20 4.7688 3.5633 11.941
+874 "2F6" 0 0 70 20 50.178 54.221 12.859
+783 "2F7" 20 100 10 20 18.29 9.8994 10.499
+892 "2F8" 40 0 70 20 28.936 35.683 11.763
+795 "2F9" 70 100 10 20 8.091 5.1913 10.527
+904 "2F10" 100 0 70 20 7.4692 15.345 10.452
+807 "2F11" 0 100 20 20 23.058 12.245 9.3329
+850 "2F12" 20 0 40 20 41.953 47.187 26.39
+825 "2F13" 40 100 20 20 13.401 7.6934 9.073
+862 "2F14" 70 0 40 20 18.366 25.704 22.551
+837 "2F15" 100 100 20 20 4.4115 3.5814 9.3364
+804 "2F16" 0 20 20 20 47.421 46.184 32.872
+854 "2F17" 20 70 40 20 22.348 16.488 10.687
+822 "2F18" 40 20 20 20 28.605 31.013 29.77
+866 "2F19" 70 70 40 20 9.6063 8.8285 9.7922
+834 "2F20" 100 20 20 20 9.1624 13.858 25.265
+878 "2F21" 0 70 70 20 27.083 19.177 5.4949
+780 "2F22" 20 20 10 20 39 39.419 36.308
+896 "2F23" 40 70 70 20 15.843 12.812 5.3519
+792 "2F24" 70 20 10 20 17.857 21.566 31.645
+908 "2F25" 100 70 70 20 4.2637 5.5352 5.0322
+1231 "2F26" 0 100 70 80 4.3827 3.0922 1.2778
+289 "2F27" 55 0 30 0 33.975 43.311 38.423
+538 "2F28" 55 70 70 0 15.19 13.094 6.4213
+1212 "2F29" 0 0 40 80 7.2398 7.7736 4.0923
+1247 "2F30" 0 100 100 80 4.4779 3.2461 1.1384
+46 "2F31" 55 0 0 0 37.906 45.689 64.134
+700 "2F32" 55 70 100 0 14.382 12.584 2.9632
+1196 "2F33" 0 0 0 80 7.5688 7.8937 6.6402
+495 "2G1" 0 100 70 0 30.696 16.461 4.3649
+241 "2G2" 100 70 20 0 7.204 7.7121 18.004
+491 "2G3" 0 40 70 0 48.486 42.462 10.329
+237 "2G4" 100 20 20 0 12.139 18.465 33.814
+487 "2G5" 0 0 70 0 70.296 75.801 16.829
+162 "2G6" 100 100 10 0 5.6757 4.2905 13.782
+622 "2G7" 70 0 85 0 20.256 30.935 9.2353
+126 "2G8" 40 100 10 0 17.864 9.9327 13.659
+586 "2G9" 20 0 85 0 52.677 60.378 10.16
+90 "2G10" 0 100 10 0 32.128 16.573 14.095
+1175 "2G11" 0 100 100 60 7.7461 4.8491 1.2043
+1094 "2G12" 100 70 0 60 3.1519 3.0872 6.637
+1173 "2G13" 0 40 100 60 11.279 10.35 1.7059
+1092 "2G14" 100 20 0 60 4.2429 5.682 11.587
+1171 "2G15" 0 0 100 60 14.598 16.021 2.3931
+871 "2G16" 100 40 40 20 6.5827 9.7411 14.016
+829 "2G17" 70 40 20 20 14.093 15.634 21.374
+859 "2G18" 40 40 40 20 21.865 21.791 15.941
+817 "2G19" 20 40 20 20 31.09 28.498 24.183
+841 "2G20" 0 40 40 20 36.833 32.49 17.453
+161 "2G21" 100 85 10 0 6.6047 5.9016 16.991
+595 "2G22" 30 0 85 0 44.655 53.316 9.9579
+125 "2G23" 40 85 10 0 20.256 13.207 17.412
+631 "2G24" 85 0 85 0 13.875 24.876 9.1828
+89 "2G25" 0 85 10 0 36.074 21.585 18.626
+311 "2G26" 85 40 30 0 12.707 16.067 22.975
+1233 "2G27" 40 40 70 80 3.8288 3.958 1.903
+275 "2G28" 30 40 30 0 34.956 32.941 26.009
+552 "2G29" 85 20 70 0 12.404 19.831 11.757
+68 "2G30" 85 40 0 0 15.401 17.409 37.286
+1249 "2G31" 40 40 100 80 3.7464 3.9131 1.3253
+32 "2G32" 30 40 0 0 38.119 34.792 42.301
+714 "2G33" 85 20 100 0 11.174 18.801 5.061
+181 "2H1" 20 0 20 0 62.098 68.564 52.696
+543 "2H2" 70 20 70 0 17.657 24.48 11.96
+185 "2H3" 20 40 20 0 41.807 37.848 32.114
+547 "2H4" 70 70 70 0 10.995 10.582 6.3901
+189 "2H5" 20 100 20 0 24.389 13.068 11.973
+574 "2H6" 0 70 85 0 36.78 25.432 4.5745
+102 "2H7" 20 20 10 0 53.225 53.555 49.466
+610 "2H8" 40 70 85 0 19.945 15.86 4.4212
+138 "2H9" 70 20 10 0 23.543 28.475 42.67
+646 "2H10" 100 70 85 0 4.7922 6.658 4.6939
+1076 "2H11" 20 0 0 60 16.12 17.453 17.095
+1187 "2H12" 70 20 100 60 4.5975 6.3578 1.9865
+1078 "2H13" 20 40 0 60 11.246 10.181 10.973
+1189 "2H14" 70 70 100 60 3.5687 3.5704 1.4992
+1080 "2H15" 20 100 0 60 7.0775 4.127 4.4583
+806 "2H16" 0 70 20 20 29.112 20.241 15.526
+852 "2H17" 20 20 40 20 35.941 37.258 21.792
+824 "2H18" 40 70 20 20 17.483 13.512 14.633
+864 "2H19" 70 20 40 20 15.463 19.996 18.676
+836 "2H20" 100 70 20 20 5.6528 6.1009 13.653
+876 "2H21" 0 20 70 20 42.359 42.186 10.58
+782 "2H22" 20 70 10 20 23.594 17.029 17.321
+894 "2H23" 40 20 70 20 24.554 27.936 9.8858
+794 "2H24" 70 70 10 20 10.82 9.3917 16.304
+906 "2H25" 100 20 70 20 6.4375 12.12 9.0207
+498 "2H26" 10 20 70 0 52.093 52.845 13.265
+293 "2H27" 55 40 30 0 23.034 24.103 24.689
+534 "2H28" 55 20 70 0 24.425 30.317 12.235
+1214 "2H29" 0 70 40 80 4.9538 3.8773 2.1287
+660 "2H30" 10 20 100 0 50.036 50.783 4.986
+50 "2H31" 55 40 0 0 25.599 25.355 39.62
+696 "2H32" 55 20 100 0 23.048 29.043 4.8772
+1198 "2H33" 0 70 0 80 5.2316 3.8927 3.3515
+531 "2I1" 40 100 70 0 16.461 9.8123 4.3821
+205 "2I2" 40 70 20 0 22.514 17.107 18.902
+527 "2I3" 40 40 70 0 26.802 27.163 9.6925
+201 "2I4" 40 20 20 0 38.27 41.405 39.909
+523 "2I5" 40 0 70 0 38.624 48.002 15.263
+158 "2I6" 100 40 10 0 10.662 13.88 31.163
+626 "2I7" 70 40 85 0 14.365 17.774 6.4865
+122 "2I8" 40 40 10 0 31.718 30.304 35.442
+590 "2I9" 20 40 85 0 36.646 34.206 6.581
+86 "2I10" 0 40 10 0 54.892 47.114 39.437
+1185 "2I11" 40 100 100 60 5.0017 3.5415 1.2204
+1084 "2I12" 40 70 0 60 6.8268 5.2535 6.9461
+1183 "2I13" 40 40 100 60 6.4525 6.7027 1.7087
+1082 "2I14" 40 20 0 60 10.544 11.081 13.353
+1181 "2I15" 40 0 100 60 8.7155 10.991 2.1626
+472 "2I16" 85 30 55 0 12.234 17.741 15.442
+113 "2I17" 30 40 10 0 37.004 34.223 36.327
+615 "2I18" 55 20 85 0 23.49 29.472 7.9889
+149 "2I19" 85 40 10 0 14.438 16.952 32.008
+579 "2I20" 10 20 85 0 50.831 51.658 8.4306
+796 "2I21" 100 0 10 20 11.565 18.075 34.978
+903 "2I22" 70 100 70 20 7.2197 5.2296 3.6755
+784 "2I23" 40 0 10 20 34.823 40.299 41.81
+891 "2I24" 20 100 70 20 17.351 9.9665 3.658
+766 "2I25" 0 0 10 20 57.939 60.619 47.246
+307 "2I26" 85 0 30 0 19.008 28.996 35.395
+520 "2I27" 30 70 70 0 24.172 18.332 6.4687
+271 "2I28" 30 0 30 0 51.632 59.517 42.064
+556 "2I29" 85 70 70 0 7.8131 8.5513 6.5836
+64 "2I30" 85 0 0 0 23.365 31.716 59.171
+682 "2I31" 30 70 100 0 23.425 17.869 2.8932
+28 "2I32" 30 0 0 0 56.939 63.231 69.655
+718 "2I33" 85 70 100 0 7.0792 8.2175 3.1644
+217 "2J1" 70 0 20 0 27.125 36.402 44.283
+507 "2J2" 20 20 70 0 45.39 47.549 12.999
+221 "2J3" 70 40 20 0 18.121 20.121 28.272
+511 "2J4" 20 70 70 0 28.512 20.854 6.5761
+225 "2J5" 70 100 20 0 10.071 6.4693 12.011
+570 "2J6" 0 20 85 0 57.496 56.756 8.6102
+106 "2J7" 20 70 10 0 31.445 22.187 22.731
+606 "2J8" 40 20 85 0 31.7 36.246 8.065
+142 "2J9" 70 70 10 0 13.821 11.77 21.436
+642 "2J10" 100 20 85 0 7.5282 15.276 7.9873
+1086 "2J11" 70 0 0 60 8.0007 10.124 14.828
+1177 "2J12" 20 20 100 60 10.17 10.9 1.9567
+1088 "2J13" 70 40 0 60 5.7691 6.0384 10.009
+1179 "2J14" 20 70 100 60 7.236 5.7348 1.4263
+1090 "2J15" 70 100 0 60 3.9422 2.7307 4.5882
+1441 "2J16" 3 40 3 0 54.293 46.676 43.807
+1442 "2J17" 40 40 3 0 32.465 30.677 39.82
+1445 "2J18" 3 3 40 0 70.851 75.213 35.788
+1452 "2J19" 40 40 0 3 31.687 29.834 39.954
+1475 "2J20" 0 3 3 40 35.382 36.528 31.537
+1460 "2J21" 40 0 40 3 40.881 49.515 32.217
+1439 "2J22" 40 3 3 0 47.181 53.597 62.936
+1470 "2J23" 40 3 0 40 21.586 24.396 28.773
+1458 "2J24" 0 0 40 3 71.989 76.822 35.593
+1459 "2J25" 3 0 40 3 69.942 75.071 35.529
+17 "2J26" 10 85 0 0 32.373 19.535 21.02
+695 "2J27" 55 10 100 0 25.223 33.197 5.3016
+1207 "2J28" 70 100 0 80 2.5582 1.9132 2.3762
+659 "2J29" 10 10 100 0 54.751 58.224 5.5591
+260 "2J30" 10 85 30 0 31 19.053 13.235
+533 "2J31" 55 10 70 0 26.597 34.52 13.332
+1223 "2J32" 70 100 40 80 2.5976 2.1507 1.738
+497 "2J33" 10 10 70 0 56.943 60.473 14.751
+567 "2K1" 100 100 70 0 4.0646 4.0207 4.4248
+169 "2K2" 0 70 20 0 39.926 27.209 20.466
+563 "2K3" 100 40 70 0 6.7195 11.55 9.3203
+165 "2K4" 0 20 20 0 65.698 63.533 44.561
+559 "2K5" 100 0 70 0 9.7118 20.377 13.922
+154 "2K6" 100 0 10 0 15.883 24.856 47.995
+630 "2K7" 70 100 85 0 8.3698 6.119 3.2589
+118 "2K8" 40 0 10 0 47.027 54.654 56.844
+594 "2K9" 20 100 85 0 23.133 12.999 3.1718
+82 "2K10" 0 0 10 0 81.546 85.184 66.064
+1195 "2K11" 100 100 100 60 2.1724 2.2263 1.2824
+1074 "2K12" 0 70 0 60 10.685 7.6357 7.2649
+1193 "2K13" 100 40 100 60 2.3928 3.7472 1.7985
+1072 "2K14" 0 20 0 60 16.905 16.358 14.823
+1191 "2K15" 100 0 100 60 2.6759 5.3706 2.2135
+1456 "2K16" 3 40 3 3 52.498 45.211 42.458
+1457 "2K17" 40 40 3 3 31.539 29.824 38.593
+1462 "2K18" 3 3 40 3 68.523 72.789 34.704
+1466 "2K19" 40 40 40 3 27.973 27.724 20.342
+1476 "2K20" 3 3 3 40 34.365 35.654 31.211
+1463 "2K21" 40 3 40 3 40.141 48.066 31.487
+1454 "2K22" 40 3 3 3 45.786 52.01 61.036
+1477 "2K23" 40 3 3 40 21.485 24.371 27.892
+1383 "2K24" 60 45 45 40 9.0665 9.6529 8.1931
+1421 "2K25" 0 0 3 3 79.789 82.854 70.456
+1258 "2K26" 100 70 100 80 2.0133 2.2902 1.2531
+51 "2K27" 55 55 0 0 21.878 19.422 31.73
+681 "2K28" 30 55 100 0 26.716 23.115 3.3808
+15 "2K29" 10 55 0 0 42.403 32.903 34.48
+1242 "2K30" 100 70 70 80 2.0233 2.2352 1.5758
+294 "2K31" 55 55 30 0 19.917 18.657 19.916
+519 "2K32" 30 55 70 0 27.687 23.883 8.0068
+258 "2K33" 10 55 30 0 40.235 31.957 21.726
+244 "2L1" 0 0 30 0 77.08 81.697 45.873
+432 "2L2" 20 100 55 0 23.639 13.11 6.1943
+280 "2L3" 40 0 30 0 43.854 52.447 40.404
+468 "2L4" 70 100 55 0 9.0996 6.3346 6.2835
+316 "2L5" 100 0 30 0 13.442 23.318 34.159
+1141 "2L6" 100 0 40 60 3.6644 6.2207 7.1392
+1122 "2L7" 0 20 40 60 14.806 14.748 7.7643
+1143 "2L8" 100 40 40 60 2.9983 4.0964 5.1669
+1124 "2L9" 0 70 40 60 10.133 7.5047 4.2491
+1145 "2L10" 100 100 40 60 2.4113 2.1836 2.7443
+406 "2L11" 0 0 55 0 72.272 77.656 24.988
+270 "2L12" 20 100 30 0 24.153 13.087 10.191
+442 "2L13" 40 0 55 0 40.203 49.451 22.945
+306 "2L14" 70 100 30 0 9.7975 6.4564 10.228
+478 "2L15" 100 0 55 0 10.877 21.35 20.18
+1316 "2L16" 0 50 0 0 50.062 39.535 38.4
+1317 "2L17" 0 40 0 0 56.387 48.115 45.856
+1336 "2L18" 0 0 50 0 73.074 78.372 28.447
+1337 "2L19" 0 0 40 0 74.951 79.955 36.787
+1356 "2L20" 0 0 0 50 27.113 28.23 24.861
+1357 "2L21" 0 0 0 40 36.398 37.862 33.394
+1296 "2L22" 50 0 0 0 41.037 48.639 65.176
+1297 "2L23" 40 0 0 0 48.74 55.767 67.464
+1423 "2L24" 0 3 3 3 77.783 79.99 68.416
+1446 "2L25" 40 3 40 0 41.382 49.573 32.515
+13 "2L26" 10 30 0 0 55.886 51.656 51.481
+699 "2L27" 55 55 100 0 16.597 16.464 3.4464
+49 "2L28" 55 30 0 0 28.708 30.127 45.424
+663 "2L29" 10 55 100 0 36.425 29.327 3.4137
+256 "2L30" 10 30 30 0 51.713 48.832 31.807
+537 "2L31" 55 55 70 0 17.549 17.239 7.7907
+292 "2L32" 55 30 30 0 25.976 28.883 28.527
+501 "2L33" 10 55 70 0 37.489 30.199 8.313
+480 "2M1" 100 20 55 0 9.1693 16.548 16.803
+304 "2M2" 70 70 30 0 12.946 11.538 15.631
+444 "2M3" 40 20 55 0 34.071 38.341 19.01
+268 "2M4" 20 70 30 0 30.376 21.828 16.549
+408 "2M5" 0 20 55 0 60.429 59.474 20.497
+1140 "2M6" 70 100 40 60 3.6536 2.8129 2.798
+1129 "2M7" 20 70 40 60 8.0524 6.1717 4.0654
+1138 "2M8" 70 40 40 60 4.681 5.3026 5.3278
+1127 "2M9" 20 20 40 60 11.795 12.27 7.4165
+1136 "2M10" 70 0 40 60 6.2776 8.7036 7.5706
+318 "2M11" 100 20 30 0 11.189 17.899 28.374
+466 "2M12" 70 70 55 0 11.666 10.941 9.1914
+282 "2M13" 40 20 30 0 37.116 40.692 33.418
+430 "2M14" 20 70 55 0 29.124 21.215 9.6145
+246 "2M15" 0 20 30 0 63.958 62.225 36.837
+1335 "2M16" 0 0 60 0 71.538 76.972 21.903
+1338 "2M17" 0 0 30 0 77.08 81.697 45.873
+1071 "2M18" 0 0 0 60 18.722 19.509 17.095
+1358 "2M19" 0 0 0 30 47.08 48.926 43.146
+1295 "2M20" 60 0 0 0 34.932 42.867 63.187
+1298 "2M21" 30 0 0 0 56.939 63.231 69.655
+1315 "2M22" 0 60 0 0 44.984 32.815 32.205
+4 "2M23" 0 30 0 0 62.701 56.901 53.098
+1443 "2M24" 3 0 40 0 72.542 77.891 36.699
+1444 "2M25" 0 3 40 0 73.042 77.009 35.813
+1256 "2M26" 100 0 100 80 1.893 3.2487 1.582
+459 "2M27" 55 100 55 0 12.532 7.9279 6.2308
+677 "2M28" 30 10 100 0 40.279 46.151 5.3443
+423 "2M29" 10 100 55 0 27.329 14.831 6.2413
+1240 "2M30" 100 0 70 80 2.053 3.3808 2.4352
+378 "2M31" 55 100 40 0 12.95 8.0267 8.5395
+515 "2M32" 30 10 70 0 42.101 47.999 14.089
+342 "2M33" 10 100 40 0 27.652 14.886 8.7057
+248 "2N1" 0 40 30 0 52.528 45.525 28.318
+428 "2N2" 20 40 55 0 38.41 35.546 15.198
+284 "2N3" 40 40 30 0 29.939 29.326 25.645
+464 "2N4" 70 40 55 0 15.489 18.523 14.18
+320 "2N5" 100 40 30 0 9.1277 13.089 22.599
+1131 "2N6" 40 0 40 60 10.19 12.289 8.225
+1132 "2N7" 40 20 40 60 8.8102 9.7595 6.9608
+1133 "2N8" 40 40 40 60 7.5029 7.4316 5.702
+1134 "2N9" 40 70 40 60 6.1031 4.9339 3.8811
+1135 "2N10" 40 100 40 60 5.4052 3.6322 2.7892
+410 "2N11" 0 40 55 0 49.848 43.529 15.896
+266 "2N12" 20 40 30 0 40.719 37.127 26.715
+446 "2N13" 40 40 55 0 27.771 27.816 14.545
+302 "2N14" 70 40 30 0 17.16 19.561 23.614
+482 "2N15" 100 40 55 0 7.5448 12.159 13.409
+1334 "2N16" 0 0 70 0 70.296 75.801 16.829
+1339 "2N17" 0 0 25 0 78.242 82.636 50.981
+1354 "2N18" 0 0 0 70 12.207 12.724 11
+1359 "2N19" 0 0 0 25 52.793 54.831 48.289
+1294 "2N20" 70 0 0 0 30.004 38.132 61.496
+1299 "2N21" 25 0 0 0 61.333 67.185 70.784
+1314 "2N22" 0 70 0 0 41.064 27.7 27.285
+1319 "2N23" 0 25 0 0 65.984 61.496 56.807
+1422 "2N24" 3 0 3 3 77.603 80.974 69.8
+1453 "2N25" 40 0 3 3 46.789 53.696 62.519
+8 "2N26" 0 85 0 0 36.321 21.541 21.27
+1252 "2N27" 70 0 100 80 3.0822 4.3835 1.6602
+44 "2N28" 40 85 0 0 20.804 13.409 20.271
+650 "2N29" 0 10 100 0 61.675 63.625 5.5889
+251 "2N30" 0 85 30 0 35.13 21.185 13.353
+1236 "2N31" 70 0 70 80 3.1049 4.3664 2.4244
+287 "2N32" 40 85 30 0 19.397 12.989 12.646
+488 "2N33" 0 10 70 0 64.187 66.282 14.983
+484 "2O1" 100 70 55 0 5.6991 7.1059 9.2396
+300 "2O2" 70 20 30 0 21.43 27.247 30.357
+448 "2O3" 40 70 55 0 20.835 16.388 9.392
+264 "2O4" 20 20 30 0 50.349 51.559 35.476
+412 "2O5" 0 70 55 0 37.905 26.101 9.9968
+1130 "2O6" 20 100 40 60 6.858 4.3108 2.799
+1139 "2O7" 70 70 40 60 3.9719 3.6823 3.7647
+1128 "2O8" 20 40 40 60 10.011 9.377 5.9896
+1137 "2O9" 70 20 40 60 5.3796 6.8306 6.3741
+1126 "2O10" 20 0 40 60 13.55 15.296 8.8402
+322 "2O11" 100 70 30 0 6.7492 7.5725 15.244
+462 "2O12" 70 20 55 0 18.9 25.419 17.746
+286 "2O13" 40 70 30 0 21.943 16.881 15.824
+426 "2O14" 20 20 55 0 46.818 48.738 19.917
+250 "2O15" 0 70 30 0 39.264 26.87 17.027
+1333 "2O16" 0 0 75 0 69.765 75.294 14.738
+163 "2O17" 0 0 20 0 79.484 83.639 56.44
+1353 "2O18" 0 0 0 75 9.6965 10.11 8.6337
+1360 "2O19" 0 0 0 20 58.945 61.186 53.819
+1293 "2O20" 75 0 0 0 27.91 36.096 60.764
+1300 "2O21" 20 0 0 0 66.155 71.475 71.889
+1313 "2O22" 0 75 0 0 39.448 25.605 25.236
+1320 "2O23" 0 20 0 0 69.597 66.565 60.838
+1447 "2O24" 3 40 40 0 49.709 43.549 23.144
+1440 "2O25" 0 40 3 0 56.018 47.878 44.066
+708 "2O26" 70 55 100 0 11.905 13.313 3.5428
+22 "2O27" 20 30 0 0 49.337 46.598 50.167
+1250 "2O28" 40 70 100 80 3.5096 3.1916 1.2656
+58 "2O29" 70 30 0 0 22.184 24.711 43.62
+546 "2O30" 70 55 70 0 12.724 13.885 7.8103
+265 "2O31" 20 30 30 0 45.493 44.156 31.065
+1234 "2O32" 40 70 70 80 3.5287 3.1386 1.5764
+301 "2O33" 70 30 30 0 19.263 23.285 27.099
+252 "2P1" 0 100 30 0 31.693 16.659 10.363
+424 "2P2" 20 0 55 0 55.813 63.395 24.202
+288 "2P3" 40 100 30 0 17.259 9.8599 10.01
+460 "2P4" 70 0 55 0 22.568 32.996 21.23
+324 "2P5" 100 100 30 0 5.115 4.2399 10.227
+1121 "2P6" 0 0 40 60 17.271 18.552 9.4611
+1142 "2P7" 100 20 40 60 3.3494 5.165 6.2004
+1123 "2P8" 0 40 40 60 12.404 11.185 6.1411
+1144 "2P9" 100 70 40 60 2.6547 2.9252 3.7357
+1125 "2P10" 0 100 40 60 8.4247 5.0487 2.8149
+414 "2P11" 0 100 55 0 31.062 16.556 6.234
+262 "2P12" 20 0 30 0 59.989 66.929 43.563
+450 "2P13" 40 100 55 0 16.719 9.8527 6.1702
+298 "2P14" 70 0 30 0 25.698 35.448 36.711
+486 "2P15" 100 100 55 0 4.4375 4.1148 6.2786
+1352 "2P16" 0 0 0 80 7.5688 7.8937 6.6402
+1361 "2P17" 0 0 0 15 64.939 67.375 59.178
+1292 "2P18" 80 0 0 0 25.861 34.122 60.042
+1301 "2P19" 15 0 0 0 70.678 75.488 73.034
+1312 "2P20" 0 80 0 0 37.947 23.655 23.333
+1321 "2P21" 0 15 0 0 73.058 71.373 64.646
+1332 "2P22" 0 0 80 0 69.318 74.851 12.828
+1341 "2P23" 0 0 15 0 80.55 84.499 61.058
+1472 "2P24" 0 0 3 40 36.184 37.715 32.352
+1417 "2P25" 3 3 3 0 78.484 81.076 70.262
+1318 "2P26" 0 30 0 0 62.701 56.901 53.098
+690 "2P27" 40 55 100 0 22.27 20.208 3.3847
+1205 "2P28" 70 40 0 80 3.1799 3.3106 4.5548
+654 "2P29" 0 55 100 0 41.058 32.033 3.4188
+247 "2P30" 0 30 30 0 58.153 53.602 32.559
+528 "2P31" 40 55 70 0 23.312 21.036 7.9337
+1221 "2P32" 70 40 40 80 2.8916 3.2153 2.8407
+492 "2P33" 0 55 70 0 42.45 33.253 8.4795
+1075 "2Q1" 0 100 0 60 8.4242 4.7581 4.4183
+1194 "2Q2" 100 70 100 60 2.2826 2.8028 1.5269
+1073 "2Q3" 0 40 0 60 14.133 12.396 11.625
+1192 "2Q4" 100 20 100 60 2.5815 4.6387 2.025
+1355 "2Q5" 0 0 0 60 18.722 19.509 17.095
+648 "2Q6" 100 100 85 0 3.8434 3.9547 3.2222
+136 "2Q7" 70 0 10 0 28.399 37.168 52.105
+612 "2Q8" 40 100 85 0 16.149 9.722 3.1901
+100 "2Q9" 20 0 10 0 64.122 70.064 61.644
+576 "2Q10" 0 100 85 0 30.497 16.411 3.101
+171 "2Q11" 0 100 20 0 31.855 16.576 12.252
+565 "2Q12" 100 70 70 0 5.126 6.7822 6.4772
+167 "2Q13" 0 40 20 0 53.653 46.279 33.894
+561 "2Q14" 100 20 70 0 8.1739 15.8 11.648
+1340 "2Q15" 0 0 20 0 79.484 83.639 56.44
+1351 "2Q16" 0 0 0 85 5.8783 6.1325 5.0453
+1362 "2Q17" 0 0 0 10 71.324 73.964 64.846
+1291 "2Q18" 85 0 0 0 23.365 31.716 59.171
+1302 "2Q19" 10 0 0 0 75.117 79.325 73.888
+1311 "2Q20" 0 85 0 0 36.321 21.541 21.27
+1322 "2Q21" 0 10 0 0 76.386 76.234 68.218
+568 "2Q22" 0 0 85 0 68.847 74.374 10.815
+1342 "2Q23" 0 0 10 0 81.546 85.184 66.064
+1374 "2Q24" 5 3 3 0 76.898 79.714 69.893
+1438 "2Q25" 40 0 3 0 48.364 55.548 64.6
+704 "2Q26" 70 10 100 0 17.965 26.694 5.3452
+1203 "2Q27" 40 100 0 80 3.2852 2.2379 2.2698
+668 "2Q28" 20 10 100 0 47.476 52.192 5.4187
+62 "2Q29" 70 85 0 0 12.341 8.8945 19.81
+542 "2Q30" 70 10 70 0 19.275 27.93 13.002
+1219 "2Q31" 40 100 40 80 3.3941 2.569 1.7401
+506 "2Q32" 20 10 70 0 49.495 54.282 14.405
+305 "2Q33" 70 85 30 0 11.307 8.7763 12.758
+1176 "2R1" 20 0 100 60 11.693 13.6 2.2243
+1087 "2R2" 70 20 0 60 6.8485 7.9614 12.462
+1178 "2R3" 20 40 100 60 8.7383 8.4322 1.6864
+1089 "2R4" 70 70 0 60 4.667 3.981 6.7619
+1180 "2R5" 20 100 100 60 6.4005 4.2183 1.2148
+88 "2R6" 0 70 10 0 40.436 27.379 23.635
+588 "2R7" 20 20 85 0 44.346 46.526 8.2869
+124 "2R8" 40 70 10 0 23.071 17.287 21.894
+624 "2R9" 70 20 85 0 16.961 23.857 7.9109
+160 "2R10" 100 70 10 0 7.664 7.8564 20.701
+505 "2R11" 20 0 70 0 53.84 61.587 15.853
+219 "2R12" 70 20 20 0 22.509 27.914 36.573
+509 "2R13" 20 40 70 0 37.308 34.783 10.114
+223 "2R14" 70 70 20 0 13.409 11.668 18.565
+513 "2R15" 20 100 70 0 23.329 13.052 4.3523
+1350 "2R16" 0 0 0 90 4.4602 4.6549 3.7277
+1363 "2R17" 0 0 0 7 75.254 78.018 68.33
+1290 "2R18" 90 0 0 0 21.073 29.468 58.368
+1303 "2R19" 7 0 0 0 77.791 81.624 74.41
+1310 "2R20" 0 90 0 0 34.862 19.646 19.365
+1323 "2R21" 0 7 0 0 78.538 79.375 70.488
+1330 "2R22" 0 0 90 0 68.433 73.929 9.0439
+1343 "2R23" 0 0 7 0 82.212 85.642 69.346
+1373 "2R24" 10 6 6 0 70.016 72.69 64.029
+1415 "2R25" 3 0 3 0 80.483 84.013 72.319
+1199 "2R26" 0 100 0 80 4.3725 2.7121 2.1754
+694 "2R27" 55 0 100 0 27.395 37.577 5.7703
+52 "2R28" 55 70 0 0 18.521 14.442 24.918
+1244 "2R29" 0 0 100 80 6.9069 7.584 1.6615
+1215 "2R30" 0 100 40 80 4.3481 2.9399 1.5795
+532 "2R31" 55 0 70 0 29.025 39.214 14.527
+295 "2R32" 55 70 30 0 17.073 14.022 15.756
+1228 "2R33" 0 0 70 80 7.1318 7.7751 2.585
+1085 "2S1" 40 100 0 60 5.6385 3.4701 4.5217
+1184 "2S2" 40 70 100 60 5.472 4.6439 1.431
+1083 "2S3" 40 40 0 60 8.6745 8.2231 10.527
+1182 "2S4" 40 20 100 60 7.5389 8.7392 1.9446
+1081 "2S5" 40 0 0 60 12.481 14.256 16.248
+644 "2S6" 100 40 85 0 6.1465 11.136 6.5358
+140 "2S7" 70 40 10 0 18.977 20.519 32.887
+608 "2S8" 40 40 85 0 26.102 26.494 6.3489
+104 "2S9" 20 40 10 0 42.831 38.473 37.277
+572 "2S10" 0 40 85 0 47.559 41.579 6.6855
+207 "2S11" 40 100 20 0 17.46 9.8331 11.75
+529 "2S12" 40 70 70 0 20.353 16.119 6.5305
+203 "2S13" 40 40 20 0 30.828 29.84 30.465
+525 "2S14" 40 20 70 0 32.496 37.003 12.595
+199 "2S15" 40 0 20 0 45.428 53.565 48.478
+1289 "2S16" 95 0 0 0 19.138 27.524 57.623
+1304 "2S17" 5 0 0 0 79.535 83.122 74.775
+1309 "2S18" 0 95 0 0 33.67 18.103 17.756
+1324 "2S19" 0 5 0 0 79.986 81.472 72
+1329 "2S20" 0 0 95 0 68.131 73.555 7.6466
+1344 "2S21" 0 0 5 0 82.632 85.932 71.387
+1349 "2S22" 0 0 0 95 3.4906 3.6405 2.8571
+1364 "2S23" 0 0 0 5 77.813 80.658 70.597
+1372 "2S24" 20 12 12 0 57.127 59.628 52.649
+1437 "2S25" 3 40 0 0 54.609 46.838 45.445
+716 "2S26" 85 40 100 0 9.3486 13.878 4.257
+1201 "2S27" 40 40 0 80 4.4886 4.319 4.7764
+680 "2S28" 30 40 100 0 30.501 29.579 3.9312
+66 "2S29" 85 20 0 0 19.214 24.141 47.91
+554 "2S30" 85 40 70 0 10.365 14.666 9.5341
+1217 "2S31" 40 40 40 80 4.1433 4.1667 2.9522
+518 "2S32" 30 40 70 0 31.79 30.79 9.8645
+309 "2S33" 85 20 30 0 15.812 22.227 29.309
+1186 "2T1" 70 0 100 60 5.2037 7.8436 2.1627
+1077 "2T2" 20 20 0 60 13.375 13.41 13.73
+1188 "2T3" 70 40 100 60 4.0032 4.9322 1.7678
+1079 "2T4" 20 70 0 60 8.7529 6.4523 7.1492
+1190 "2T5" 70 100 100 60 3.3628 2.8119 1.2912
+84 "2T6" 0 20 10 0 67.502 64.907 52.292
+592 "2T7" 20 70 85 0 28.108 20.596 4.4394
+120 "2T8" 40 20 10 0 39.229 41.854 46.166
+628 "2T9" 70 70 85 0 10.587 10.344 4.467
+156 "2T10" 100 20 10 0 13.142 19.002 39.45
+541 "2T11" 70 0 70 0 21.057 31.724 14.068
+183 "2T12" 20 20 20 0 51.957 52.761 42.696
+545 "2T13" 70 40 70 0 14.902 18.186 9.7369
+187 "2T14" 20 70 20 0 30.915 22.015 19.669
+549 "2T15" 70 100 70 0 8.6643 6.2153 4.4865
+1288 "2T16" 98 0 0 0 18.031 26.399 57.207
+1305 "2T17" 3 0 0 0 81.162 84.519 75.123
+1308 "2T18" 0 98 0 0 32.984 17.216 16.835
+1325 "2T19" 0 3 0 0 81.401 83.509 73.467
+1328 "2T20" 0 0 98 0 67.951 73.331 6.8597
+1345 "2T21" 0 0 3 0 83.005 86.19 73.174
+1348 "2T22" 0 0 0 98 2.99 3.117 2.4132
+1365 "2T23" 0 0 0 3 80.153 83.071 72.668
+1371 "2T24" 40 27 27 0 35.147 37.025 32.701
+1436 "2T25" 40 3 0 0 47.607 53.841 65.458
+12 "2T26" 10 20 0 0 62.169 60.553 58.992
+698 "2T27" 55 40 100 0 19.251 21.319 3.9971
+48 "2T28" 55 20 0 0 31.849 35.245 51.635
+1246 "2T29" 0 70 100 80 4.9126 4.0355 1.2344
+255 "2T30" 10 20 30 0 57.101 56.911 36.24
+536 "2T31" 55 40 70 0 20.38 22.356 9.6853
+291 "2T32" 55 20 30 0 28.488 33.387 31.708
+1230 "2T33" 0 70 70 80 4.9638 4.0166 1.6192
+1095 "2U1" 100 100 0 60 2.7618 2.2108 4.6888
+1174 "2U2" 0 70 100 60 9.0728 6.8758 1.3976
+1093 "2U3" 100 40 0 60 3.7545 4.5005 9.551
+1172 "2U4" 0 20 100 60 12.964 13.182 1.9982
+1091 "2U5" 100 0 0 60 4.728 6.906 13.457
+640 "2U6" 100 0 85 0 8.8403 19.595 9.2829
+144 "2U7" 70 100 10 0 10.353 6.489 13.819
+604 "2U8" 40 0 85 0 37.463 46.861 9.8419
+108 "2U9" 20 100 10 0 24.631 13.078 13.805
+1331 "2U10" 0 0 85 0 68.847 74.374 10.815
+243 "2U11" 100 100 20 0 5.3982 4.2754 11.983
+493 "2U12" 0 70 70 0 37.425 25.929 6.9599
+239 "2U13" 100 40 20 0 9.8374 13.434 26.709
+489 "2U14" 0 20 70 0 58.624 57.821 13.421
+235 "2U15" 100 0 20 0 14.646 24.111 40.809
+1287 "2U16" 100 0 0 0 17.316 25.666 56.941
+1306 "2U17" 2 0 0 0 81.949 85.195 75.296
+1307 "2U18" 0 100 0 0 32.54 16.641 16.24
+1326 "2U19" 0 2 0 0 82.103 84.515 74.191
+1327 "2U20" 0 0 100 0 67.831 73.183 6.3566
+1346 "2U21" 0 0 2 0 83.181 86.312 74.008
+1347 "2U22" 0 0 0 100 2.6842 2.7971 2.1442
+1366 "2U23" 0 0 0 2 81.269 84.221 73.655
+1370 "2U24" 60 45 45 0 18.648 19.88 16.953
+1414 "2U25" 3 3 0 0 79.032 81.452 72.778
+712 "2U26" 85 0 100 0 13.275 24.297 5.716
+34 "2U27" 30 70 0 0 27.569 19.811 25.728
+676 "2U28" 30 0 100 0 43.65 52.263 5.9337
+70 "2U29" 85 70 0 0 10.922 9.7865 24.082
+550 "2U30" 85 0 70 0 14.772 25.647 13.911
+277 "2U31" 30 70 30 0 25.866 19.213 16.143
+514 "2U32" 30 0 70 0 45.856 54.52 15.521
+313 "2U33" 85 70 30 0 9.539 9.4096 15.441
+END_DATA
diff --git a/ref/FograStrip2.ti1 b/ref/FograStrip2.ti1
new file mode 100644
index 0000000..f8abae7
--- /dev/null
+++ b/ref/FograStrip2.ti1
@@ -0,0 +1,120 @@
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Manualy created for FOGRA strip #2 "
+CREATED "Wed Jun 1 15:06:24 2004"
+KEYWORD "DEFAULT_EXPECTED_VALUES"
+DEFAULT_EXPECTED_VALUES "true"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "83.77 87.26 66.79"
+KEYWORD "TOTAL_INK_LIMIT"
+TOTAL_INK_LIMIT "270.0"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 46
+BEGIN_DATA
+1 100 0 0 0 19.21 25.37 45.6
+2 70 0 0 0 28.25 35.4 51.26
+3 40 0 0 0 45.2 52.51 58.34
+4 0 100 0 0 35.66 21.75 16.18
+5 0 70 0 0 41.16 28.04 22.51
+6 0 40 0 0 54.44 44.85 37.56
+7 0 0 100 0 70.46 73.51 10.34
+8 0 0 70 0 72.54 76.67 16.6
+9 0 0 40 0 76.58 81.29 31.57
+10 20 70 70 0 26.84 20.24 9.68
+11 40 70 70 20 15.21 13.33 8.47
+12 40 100 100 20 13.26 10.8 6.56
+13 40 100 40 20 15.41 12.16 10.32
+14 40 40 100 20 17.64 18.07 7.7
+15 100 40 100 20 8.74 11.04 7.8
+16 100 40 40 20 10.64 12.84 14.75
+17 100 100 40 20 8.44 8.45 10.12
+18 0 0 0 10 69.21 72.04 55.31
+19 0 0 0 20 57.67 59.99 46.27
+20 0 0 0 40 37.79 39.2 30.25
+21 0 0 0 60 22.87 23.62 18.11
+22 0 0 0 80 12.52 12.83 9.74
+23 0 0 0 100 7.34 7.42 5.6
+24 100 100 0 0 10.64 10.02 15.7
+25 70 70 0 0 15.73 14.48 21.18
+26 40 40 0 0 31.46 29.92 34.72
+27 0 100 100 0 32.06 19.73 6.79
+28 0 70 70 0 37.86 26.24 10.23
+29 0 40 40 0 50.42 41.91 21.32
+30 100 0 100 0 11.84 18.76 9.74
+31 70 0 70 0 20.00 28.29 14.84
+32 40 0 40 0 37.71 46.37 28.51
+33 10 40 40 0 44.02 38.09 21.16
+34 0 40 100 0 46.00 37.51 8.7
+35 0 100 40 0 34.28 21.23 12.07
+36 40 100 0 0 20.58 15.09 16.73
+37 40 0 100 0 32.29 40.42 10.44
+38 100 0 40 0 15.35 22.58 24.53
+39 100 40 0 0 14.68 16.88 29.74
+40 0 0 0 0 83.77 87.26 66.79
+41 10 6 6 0 69.49 73.01 57.1
+42 20 12 12 0 53.95 56.73 46.26
+43 40 27 27 0 31.75 33.56 28.39
+44 60 45 45 0 18.83 20.03 17.45
+45 80 65 65 0 11.98 12.82 11.37
+46 100 85 85 0 8.30 8.90 8.39
+END_DATA
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Argyll targen"
+KEYWORD "DENSITY_EXTREME_VALUES"
+DENSITY_EXTREME_VALUES "8"
+CREATED "April 22, 2008"
+
+KEYWORD "INDEX"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+INDEX CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 8
+BEGIN_DATA
+0 0.0000 0.0000 0.0000 0.0000 96.420 100.00 82.490
+1 100.00 0.0000 0.0000 0.0000 12.000 18.000 48.000
+2 0.0000 100.00 0.0000 0.0000 38.000 19.000 20.000
+3 100.00 0.0000 0.0000 45.486 3.2503 4.8706 13.063
+4 0.0000 17.988 100.00 0.0000 59.720 57.803 8.0538
+5 100.00 0.0000 100.00 40.023 3.1381 4.8335 2.1311
+6 0.0000 100.00 100.00 18.089 19.420 9.9765 1.7309
+7 0.0000 31.327 0.0000 100.00 0.65916 0.54433 0.57384
+END_DATA
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Argyll targen"
+KEYWORD "DEVICE_COMBINATION_VALUES"
+DEVICE_COMBINATION_VALUES "9"
+CREATED "April 22, 2008"
+
+KEYWORD "INDEX"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+INDEX CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 9
+BEGIN_DATA
+0 0.0000 0.0000 0.0000 0.0000 96.420 100.00 82.490
+1 100.00 0.0000 0.0000 0.0000 12.000 18.000 48.000
+2 0.0000 100.00 0.0000 0.0000 38.000 19.000 20.000
+3 100.00 100.00 0.0000 0.0000 4.7293 3.4200 11.638
+4 0.0000 0.0000 100.00 0.0000 76.000 81.000 11.000
+5 100.00 0.0000 100.00 0.0000 9.4586 14.580 6.4008
+6 0.0000 100.00 100.00 0.0000 29.952 15.390 2.6670
+7 100.00 100.00 100.00 100.00 0.038661 0.027702 0.018813
+8 40.000 40.000 40.000 0.0000 19.978 17.645 12.009
+END_DATA
diff --git a/ref/FograStrip2_2.ti2 b/ref/FograStrip2_2.ti2
new file mode 100644
index 0000000..b84cb9d
--- /dev/null
+++ b/ref/FograStrip2_2.ti2
@@ -0,0 +1,75 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+ORIGINATOR "Manualy created for FOGRA strip #2 in 2 strip layout"
+CREATED "Wed Jun 1 15:06:24 2004"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "83.77 87.26 66.79"
+KEYWORD "TOTAL_INK_LIMIT"
+TOTAL_INK_LIMIT "270.0"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "23"
+KEYWORD "PASSES_IN_STRIPS"
+PASSES_IN_STRIPS "2"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 46
+BEGIN_DATA
+1 "A1" 100 0 0 0 19.21 25.37 45.6
+2 "A2" 70 0 0 0 28.25 35.4 51.26
+3 "A3" 40 0 0 0 45.2 52.51 58.34
+4 "A4" 0 100 0 0 35.66 21.75 16.18
+5 "A5" 0 70 0 0 41.16 28.04 22.51
+6 "A6" 0 40 0 0 54.44 44.85 37.56
+7 "A7" 0 0 100 0 70.46 73.51 10.34
+8 "A8" 0 0 70 0 72.54 76.67 16.6
+9 "A9" 0 0 40 0 76.58 81.29 31.57
+10 "A10" 20 70 70 0 26.84 20.24 9.68
+11 "A11" 40 70 70 20 15.21 13.33 8.47
+12 "A12" 40 100 100 20 13.26 10.8 6.56
+13 "A13" 40 100 40 20 15.41 12.16 10.32
+14 "A14" 40 40 100 20 17.64 18.07 7.7
+15 "A15" 100 40 100 20 8.74 11.04 7.8
+16 "A16" 100 40 40 20 10.64 12.84 14.75
+17 "A17" 100 100 40 20 8.44 8.45 10.12
+18 "A18" 0 0 0 10 69.21 72.04 55.31
+19 "A19" 0 0 0 20 57.67 59.99 46.27
+20 "A20" 0 0 0 40 37.79 39.2 30.25
+21 "A21" 0 0 0 60 22.87 23.62 18.11
+22 "A22" 0 0 0 80 12.52 12.83 9.74
+23 "A23" 0 0 0 100 7.34 7.42 5.6
+24 "B1" 100 100 0 0 10.64 10.02 15.7
+25 "B2" 70 70 0 0 15.73 14.48 21.18
+26 "B3" 40 40 0 0 31.46 29.92 34.72
+27 "B4" 0 100 100 0 32.06 19.73 6.79
+28 "B5" 0 70 70 0 37.86 26.24 10.23
+29 "B6" 0 40 40 0 50.42 41.91 21.32
+30 "B7" 100 0 100 0 11.84 18.76 9.74
+31 "B8" 70 0 70 0 20.00 28.29 14.84
+32 "B9" 40 0 40 0 37.71 46.37 28.51
+33 "B10" 10 40 40 0 44.02 38.09 21.16
+34 "B11" 0 40 100 0 46.00 37.51 8.7
+35 "B12" 0 100 40 0 34.28 21.23 12.07
+36 "B13" 40 100 0 0 20.58 15.09 16.73
+37 "B14" 40 0 100 0 32.29 40.42 10.44
+38 "B15" 100 0 40 0 15.35 22.58 24.53
+39 "B16" 100 40 0 0 14.68 16.88 29.74
+40 "B17" 0 0 0 0 83.77 87.26 66.79
+41 "B18" 10 6 6 0 69.49 73.01 57.1
+42 "B19" 20 12 12 0 53.95 56.73 46.26
+43 "B20" 40 27 27 0 31.75 33.56 28.39
+44 "B21" 60 45 45 0 18.83 20.03 17.45
+45 "B22" 80 65 65 0 11.98 12.82 11.37
+46 "B23" 100 85 85 0 8.30 8.90 8.39
+END_DATA
+
+
diff --git a/ref/FograStrip3.ti1 b/ref/FograStrip3.ti1
new file mode 100644
index 0000000..4cf126f
--- /dev/null
+++ b/ref/FograStrip3.ti1
@@ -0,0 +1,146 @@
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Manualy created for FOGRA strip #3 "
+CREATED "Thu Jan 12 15:06:24 2011"
+KEYWORD "DEFAULT_EXPECTED_VALUES"
+DEFAULT_EXPECTED_VALUES "true"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "87.38 90.38 75.45"
+KEYWORD "TOTAL_INK_LIMIT"
+TOTAL_INK_LIMIT "270.0"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 72
+BEGIN_DATA
+1 100 0 0 0 14.91 22.41 53.72
+2 70 0 0 0 24.6 32.11 56.56
+3 40 0 0 0 41.86 48.84 63.97
+4 20 0 0 0 59.49 65.47 69.4
+5 10 0 0 0 71.85 76.74 72.45
+6 0 100 0 0 35.87 18.39 16.7
+7 0 70 0 0 42.6 27.5 24.95
+8 0 40 0 0 56.48 44.98 40.26
+9 0 20 0 0 69.77 63.34 55.08
+10 0 10 0 0 79.71 77.36 66.28
+11 0 0 100 0 74.36 78.79 7.06
+12 0 0 70 0 75.77 80.62 16.06
+13 0 0 40 0 78.94 83.73 32.04
+14 0 0 20 0 82.9 87.23 49.82
+15 0 0 10 0 85.2 88.98 61.85
+16 0 0 0 10 67.91 70.15 58.39
+17 0 0 0 20 49.47 51.05 42.55
+18 0 0 0 40 30.07 30.99 26.02
+19 0 0 0 60 15.9 16.31 13.78
+20 0 0 0 80 7.04 7.13 6.22
+21 0 0 0 100 1.69 1.61 1.67
+22 0 100 0 100 1.41 1.14 1.48
+23 0 70 70 60 9.68 7.17 3.38
+24 0 0 70 80 7.27 7.64 3.38
+25 100 100 0 0 4.35 2.81 13.31
+26 70 70 0 0 12.04 10.07 21.64
+27 40 40 0 0 28.32 26.36 35.63
+28 20 20 0 0 47.53 46.5 50.03
+29 10 10 0 0 64.23 64.56 61.64
+30 0 100 100 0 32.69 17.25 2.74
+31 0 70 70 0 39.4 25.83 7.73
+32 0 40 40 0 52.14 42.32 20.67
+33 0 20 20 0 66.2 60.84 38.79
+34 0 10 10 0 77.01 75.27 54.63
+35 100 0 100 0 6.66 16.31 5.63
+36 70 0 70 0 16.97 26.86 13.73
+37 40 0 40 0 35.31 44.25 29.06
+38 20 0 20 0 55.17 62.38 46.73
+39 10 0 10 0 69.88 75.46 59.92
+40 10 6 6 0 66.27 68.73 60.0
+41 20 12 12 0 48.71 50.74 45.17
+42 40 27 27 0 28.15 29.54 26.91
+43 60 45 45 0 15.65 16.58 15.62
+44 80 65 65 0 7.41 7.92 7.94
+45 100 85 85 0 3.11 3.51 4.29
+46 100 0 0 100 1.00 1.07 1.42
+47 20 100 70 60 6.34 3.91 2.68
+48 70 0 70 80 3.22 4.15 3.04
+49 100 100 100 0 2.42 2.16 2.69
+50 70 70 70 0 8.92 8.36 6.83
+51 40 40 40 0 24.72 24.12 18.8
+52 20 20 20 0 44.17 44.18 35.62
+53 10 10 10 0 61.84 62.76 51.51
+54 20 70 70 0 26.95 19.18 7.57
+55 40 70 70 20 13.71 10.9 5.89
+56 40 100 100 20 10.62 6.33 2.41
+57 40 100 40 20 11.7 6.77 7.24
+58 40 40 100 20 16.45 16.81 3.73
+59 100 40 100 20 3.62 6.84 3.5
+60 100 40 40 20 5.33 8.00 12.8
+61 100 100 40 20 2.75 2.07 6.41
+62 10 40 40 0 43.46 36.9 20.39
+63 0 40 100 0 49.78 40.72 4.88
+64 0 100 40 0 34.02 17.62 9.73
+65 40 100 0 0 16.66 9.11 14.75
+66 40 0 100 0 31.1 40.61 6.39
+67 100 0 40 0 9.99 19.02 25.24
+68 100 40 0 0 9.18 11.79 30.55
+69 0 0 0 0 87.38 90.38 75.45
+70 0 0 100 100 1.57 1.54 1.33
+71 0 70 0 60 10.61 7.67 7.74
+72 70 0 0 80 3.84 4.59 6.23
+END_DATA
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Argyll targen"
+KEYWORD "DENSITY_EXTREME_VALUES"
+DENSITY_EXTREME_VALUES "8"
+CREATED "April 22, 2008"
+
+KEYWORD "INDEX"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+INDEX CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 8
+BEGIN_DATA
+0 0.0000 0.0000 0.0000 0.0000 96.420 100.00 82.490
+1 100.00 0.0000 0.0000 0.0000 12.000 18.000 48.000
+2 0.0000 100.00 0.0000 0.0000 38.000 19.000 20.000
+3 100.00 0.0000 0.0000 45.486 3.2503 4.8706 13.063
+4 0.0000 17.988 100.00 0.0000 59.720 57.803 8.0538
+5 100.00 0.0000 100.00 40.023 3.1381 4.8335 2.1311
+6 0.0000 100.00 100.00 18.089 19.420 9.9765 1.7309
+7 0.0000 31.327 0.0000 100.00 0.65916 0.54433 0.57384
+END_DATA
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Argyll targen"
+KEYWORD "DEVICE_COMBINATION_VALUES"
+DEVICE_COMBINATION_VALUES "9"
+CREATED "April 22, 2008"
+
+KEYWORD "INDEX"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+INDEX CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 9
+BEGIN_DATA
+0 0.0000 0.0000 0.0000 0.0000 96.420 100.00 82.490
+1 100.00 0.0000 0.0000 0.0000 12.000 18.000 48.000
+2 0.0000 100.00 0.0000 0.0000 38.000 19.000 20.000
+3 100.00 100.00 0.0000 0.0000 4.7293 3.4200 11.638
+4 0.0000 0.0000 100.00 0.0000 76.000 81.000 11.000
+5 100.00 0.0000 100.00 0.0000 9.4586 14.580 6.4008
+6 0.0000 100.00 100.00 0.0000 29.952 15.390 2.6670
+7 100.00 100.00 100.00 100.00 0.038661 0.027702 0.018813
+8 40.000 40.000 40.000 0.0000 19.978 17.645 12.009
+END_DATA
diff --git a/ref/FograStrip3_3.ti2 b/ref/FograStrip3_3.ti2
new file mode 100644
index 0000000..8f9822e
--- /dev/null
+++ b/ref/FograStrip3_3.ti2
@@ -0,0 +1,101 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+ORIGINATOR "Manualy created for FOGRA strip #3 in 3 strip layout (E3Z)"
+CREATED "Thu Jan 12 15:06:24 2011"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "83.77 87.26 66.79"
+KEYWORD "TOTAL_INK_LIMIT"
+TOTAL_INK_LIMIT "270.0"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "24"
+KEYWORD "PASSES_IN_STRIPS"
+PASSES_IN_STRIPS "3"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 72
+BEGIN_DATA
+1 "A1" 100 0 0 0 14.91 22.41 53.72
+2 "A2" 70 0 0 0 24.6 32.11 56.56
+3 "A3" 40 0 0 0 41.86 48.84 63.97
+4 "A4" 20 0 0 0 59.49 65.47 69.4
+5 "A5" 10 0 0 0 71.85 76.74 72.45
+6 "A6" 0 100 0 0 35.87 18.39 16.7
+7 "A7" 0 70 0 0 42.6 27.5 24.95
+8 "A8" 0 40 0 0 56.48 44.98 40.26
+9 "A9" 0 20 0 0 69.77 63.34 55.08
+10 "A10" 0 10 0 0 79.71 77.36 66.28
+11 "A11" 0 0 100 0 74.36 78.79 7.06
+12 "A12" 0 0 70 0 75.77 80.62 16.06
+13 "A13" 0 0 40 0 78.94 83.73 32.04
+14 "A14" 0 0 20 0 82.9 87.23 49.82
+15 "A15" 0 0 10 0 85.2 88.98 61.85
+16 "A16" 0 0 0 10 67.91 70.15 58.39
+17 "A17" 0 0 0 20 49.47 51.05 42.55
+18 "A18" 0 0 0 40 30.07 30.99 26.02
+19 "A19" 0 0 0 60 15.9 16.31 13.78
+20 "A20" 0 0 0 80 7.04 7.13 6.22
+21 "A21" 0 0 0 100 1.69 1.61 1.67
+22 "A22" 0 100 0 100 1.41 1.14 1.48
+23 "A23" 0 70 70 60 9.68 7.17 3.38
+24 "A24" 0 0 70 80 7.27 7.64 3.38
+25 "B1" 100 100 0 0 4.35 2.81 13.31
+26 "B2" 70 70 0 0 12.04 10.07 21.64
+27 "B3" 40 40 0 0 28.32 26.36 35.63
+28 "B4" 20 20 0 0 47.53 46.5 50.03
+29 "B5" 10 10 0 0 64.23 64.56 61.64
+30 "B6" 0 100 100 0 32.69 17.25 2.74
+31 "B7" 0 70 70 0 39.4 25.83 7.73
+32 "B8" 0 40 40 0 52.14 42.32 20.67
+33 "B9" 0 20 20 0 66.2 60.84 38.79
+34 "B10" 0 10 10 0 77.01 75.27 54.63
+35 "B11" 100 0 100 0 6.66 16.31 5.63
+36 "B12" 70 0 70 0 16.97 26.86 13.73
+37 "B13" 40 0 40 0 35.31 44.25 29.06
+38 "B14" 20 0 20 0 55.17 62.38 46.73
+39 "B15" 10 0 10 0 69.88 75.46 59.92
+40 "B16" 10 6 6 0 66.27 68.73 60.0
+41 "B17" 20 12 12 0 48.71 50.74 45.17
+42 "B18" 40 27 27 0 28.15 29.54 26.91
+43 "B19" 60 45 45 0 15.65 16.58 15.62
+44 "B20" 80 65 65 0 7.41 7.92 7.94
+45 "B21" 100 85 85 0 3.11 3.51 4.29
+46 "B22" 100 0 0 100 1.00 1.07 1.42
+47 "B23" 20 100 70 60 6.34 3.91 2.68
+48 "B24" 70 0 70 80 3.22 4.15 3.04
+49 "C1" 100 100 100 0 2.42 2.16 2.69
+50 "C2" 70 70 70 0 8.92 8.36 6.83
+51 "C3" 40 40 40 0 24.72 24.12 18.8
+52 "C4" 20 20 20 0 44.17 44.18 35.62
+53 "C5" 10 10 10 0 61.84 62.76 51.51
+54 "C6" 20 70 70 0 26.95 19.18 7.57
+55 "C7" 40 70 70 20 13.71 10.9 5.89
+56 "C8" 40 100 100 20 10.62 6.33 2.41
+57 "C9" 40 100 40 20 11.7 6.77 7.24
+58 "C10" 40 40 100 20 16.45 16.81 3.73
+59 "C11" 100 40 100 20 3.62 6.84 3.5
+60 "C12" 100 40 40 20 5.33 8.00 12.8
+61 "C13" 100 100 40 20 2.75 2.07 6.41
+62 "C14" 10 40 40 0 43.46 36.9 20.39
+63 "C15" 0 40 100 0 49.78 40.72 4.88
+64 "C16" 0 100 40 0 34.02 17.62 9.73
+65 "C17" 40 100 0 0 16.66 9.11 14.75
+66 "C18" 40 0 100 0 31.1 40.61 6.39
+67 "C19" 100 0 40 0 9.99 19.02 25.24
+68 "C20" 100 40 0 0 9.18 11.79 30.55
+69 "C21" 0 0 0 0 87.38 90.38 75.45
+70 "C22" 0 0 100 100 1.57 1.54 1.33
+71 "C23" 0 70 0 60 10.61 7.67 7.74
+72 "C24" 70 0 0 80 3.84 4.59 6.23
+END_DATA
+
+
diff --git a/ref/GTIPlus.sp b/ref/GTIPlus.sp
new file mode 100644
index 0000000..4c4c164
--- /dev/null
+++ b/ref/GTIPlus.sp
@@ -0,0 +1,64 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for GTI D50 viewer - extended to 350nm with high estimation of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Thu May 20 15:12:32 2004"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "340.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "50.000"
+
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_380"
+KEYWORD "SPEC_390"
+KEYWORD "SPEC_400"
+KEYWORD "SPEC_410"
+KEYWORD "SPEC_420"
+KEYWORD "SPEC_430"
+KEYWORD "SPEC_440"
+KEYWORD "SPEC_450"
+KEYWORD "SPEC_460"
+KEYWORD "SPEC_470"
+KEYWORD "SPEC_480"
+KEYWORD "SPEC_490"
+KEYWORD "SPEC_500"
+KEYWORD "SPEC_510"
+KEYWORD "SPEC_520"
+KEYWORD "SPEC_530"
+KEYWORD "SPEC_540"
+KEYWORD "SPEC_550"
+KEYWORD "SPEC_560"
+KEYWORD "SPEC_570"
+KEYWORD "SPEC_580"
+KEYWORD "SPEC_590"
+KEYWORD "SPEC_600"
+KEYWORD "SPEC_610"
+KEYWORD "SPEC_620"
+KEYWORD "SPEC_630"
+KEYWORD "SPEC_640"
+KEYWORD "SPEC_650"
+KEYWORD "SPEC_660"
+KEYWORD "SPEC_670"
+KEYWORD "SPEC_680"
+KEYWORD "SPEC_690"
+KEYWORD "SPEC_700"
+KEYWORD "SPEC_710"
+KEYWORD "SPEC_720"
+KEYWORD "SPEC_730"
+NUMBER_OF_FIELDS 40
+BEGIN_DATA_FORMAT
+SPEC_340 SPEC_350 SPEC_360 SPEC_370 SPEC_380 SPEC_390 SPEC_400 SPEC_410 SPEC_420 SPEC_430 SPEC_440 SPEC_450 SPEC_460 SPEC_470 SPEC_480 SPEC_490 SPEC_500 SPEC_510 SPEC_520 SPEC_530 SPEC_540 SPEC_550 SPEC_560 SPEC_570 SPEC_580 SPEC_590 SPEC_600 SPEC_610 SPEC_620 SPEC_630 SPEC_640 SPEC_650 SPEC_660 SPEC_670 SPEC_680 SPEC_690 SPEC_700 SPEC_710 SPEC_720 SPEC_730
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+5.0 7.0 7.0 6.0 3.257189 6.165859 19.269892 21.802994 16.533678 39.975159 57.056049 30.274649 30.155033 32.977394 35.03986 36.617123 37.617252 38.191128 38.476234 39.155827 51.626312 62.044827 42.804649 43.08567 48.201847 44.268539 43.22028 43.416119 42.784763 41.291107 39.292709 36.579609 33.26786 29.675453 26.125034 22.980124 19.86338 16.922205 13.994864 11.727232
+END_DATA
+
diff --git a/ref/Hutchcolor.cht b/ref/Hutchcolor.cht
new file mode 100644
index 0000000..fcc5135
--- /dev/null
+++ b/ref/Hutchcolor.cht
@@ -0,0 +1,597 @@
+
+BOXES 639
+ F _ _ 99.5 25.5 815.5 25.5 816.5 565.5 99.5 565.5
+ D ALL ALL _ _ 716 540 99.5 25.5 0 0
+ Y 01 29 A V 24.689655 24.545454 99.5 25.5 24.689655 24.545454
+
+BOX_SHRINK 3.0
+
+REF_ROTATION 0.0
+
+XLIST 29
+ 100.0 0.362323 0.148148
+ 110.211740 0.039102 0.222222
+ 125.481836 0.971171 0.333333
+ 150.418808 0.792286 0.925926
+ 174.477814 0.734537 0.962963
+ 199.527718 0.787966 1.000000
+ 224.576901 0.650620 0.925926
+ 248.755279 0.417736 0.888889
+ 274.032480 0.613223 0.888889
+ 298.327154 0.543354 0.925926
+ 323.197333 0.847712 0.925926
+ 347.120895 0.812650 0.925926
+ 372.370502 0.860240 0.777778
+ 396.353101 0.679006 0.703704
+ 421.201328 1.000000 0.814815
+ 446.684199 0.456817 0.703704
+ 470.550542 0.508343 0.740741
+ 495.397842 0.625561 0.703704
+ 520.420248 0.386812 0.777778
+ 544.869239 0.452824 0.777778
+ 569.748767 0.547266 0.666667
+ 594.755774 0.465053 0.666667
+ 618.496351 0.477468 0.703704
+ 644.014919 0.454719 0.703704
+ 668.040606 0.479467 0.666667
+ 693.095409 0.514558 0.666667
+ 717.270886 0.882612 0.666667
+ 791.542805 0.771497 0.444444
+ 817.003432 0.882693 0.111111
+
+YLIST 24
+ 25.546595 1.000000 0.071429
+ 49.424472 0.975749 0.392857
+ 75.392921 0.738973 0.964286
+ 99.186517 0.910072 1.000000
+ 124.186786 0.852166 0.964286
+ 149.214757 0.795826 0.892857
+ 173.106047 0.641529 0.857143
+ 198.089764 0.742257 0.928571
+ 223.213674 0.604765 0.928571
+ 246.745099 0.949854 1.000000
+ 271.506325 0.862745 0.857143
+ 294.880215 0.786340 0.571429
+ 320.004798 0.644361 0.750000
+ 344.432584 0.421439 0.857143
+ 369.861483 0.378724 0.678571
+ 393.074962 0.877958 0.964286
+ 418.078441 0.680991 1.000000
+ 442.078222 0.783297 1.000000
+ 466.901848 0.648933 0.678571
+ 491.506012 0.239702 0.642857
+ 515.663175 0.154566 0.285714
+ 524.564065 0.106932 0.250000
+ 540.560259 0.769595 0.250000
+ 565.915658 0.797211 0.178571
+
+EXPECTED XYZ 528
+ A01 76.63 79.337 62.787
+ A15 0.049 0.047 0.04
+ A16 76.799 79.369 62.869
+ A29 76.788 79.423 62.902
+ B01 0.051 0.046 0.042
+ B02 23.742 12.069 27.69
+ B03 29.571 17.273 33.401
+ B04 36.377 24.341 39.101
+ B05 46.402 36.285 46.046
+ B06 60.163 54.778 54.102
+ B07 76.815 79.257 62.889
+ B08 70.22 73.135 37.781
+ B09 52.398 46.914 32.877
+ B10 37.18 27.08 27.417
+ B11 25.856 14.882 21.359
+ B12 19.163 9.224 17.005
+ B13 12.41 5.017 11.384
+ B14 68.099 66.231 58.21
+ B15 64.604 64.824 58.092
+ B16 58.787 61.057 57.489
+ B17 60.985 65.447 59.249
+ B18 62.617 69.06 60.756
+ B19 61.499 67.999 56.83
+ B20 59.996 66.835 49.738
+ B21 66.383 71.172 50.262
+ B22 72.856 75.172 50.47
+ B23 68.187 68.027 48.999
+ B24 63.438 60.952 47.208
+ B25 65.486 62.759 54.536
+ B26 74.738 77.87 62.671
+ B27 76.752 79.251 62.956
+ B28 72.734 74.343 59.875
+ B29 0.046 0.043 0.032
+ C01 21.633 22.888 20.349
+ C02 18.412 9.88 27.737
+ C03 22.631 14.555 33.706
+ C04 27.389 20.594 38.954
+ C05 34.465 30.776 45.359
+ C06 43.817 46.079 52.702
+ C07 51.156 60.04 58.504
+ C08 46.443 56.25 36.915
+ C09 37.868 39.579 33.063
+ C10 27.157 22.631 27.438
+ C11 19.372 12.293 21.901
+ C12 14.769 7.361 17.468
+ C13 9.986 4.001 11.409
+ C14 53.009 44.867 50.025
+ C15 43.073 40.486 49.663
+ C16 33.474 35.535 49.096
+ C17 39.616 46.653 54.254
+ C18 43.877 54.8 57.684
+ C19 39.842 51.529 40.856
+ C20 37.241 49.298 27.293
+ C21 49.103 57.6 26.678
+ C22 68.052 71.088 26.663
+ C23 54.158 50.585 23.324
+ C24 42.126 34.204 20.788
+ C25 44.759 35.882 34.073
+ C26 63.526 65.924 58.034
+ C27 66.134 68.606 57.21
+ C28 66.402 69.263 52.556
+ C29 21.945 23.311 20.081
+ D02 11.393 6.774 27.149
+ D03 14.898 11.118 33.316
+ D04 18.919 16.908 38.782
+ D05 25.042 26.809 45.487
+ D06 32.814 40.626 52.643
+ D07 38.506 50.724 57.005
+ D08 34.084 47.3 37.959
+ D09 27.203 34.516 34.19
+ D10 18.226 18.563 28.41
+ D11 11.924 8.905 22.544
+ D12 8.489 4.576 17.784
+ D13 5.402 2.081 11.094
+ D14 41.275 29.968 42.582
+ D15 28.108 24.154 42.115
+ D16 20.099 21.735 43.019
+ D17 29.182 37.879 52.109
+ D18 35.153 47.891 56.53
+ D19 30.314 44.189 35.897
+ D20 26.406 40.305 16.077
+ D21 38.111 48.316 13.175
+ D22 65.451 67.965 13.429
+ D23 43.805 37.363 9.249
+ D24 27.598 18.034 7.037
+ D25 30.174 19.545 20.547
+ D26 58.48 57.966 51.192
+ D27 54.554 56.734 46.744
+ D28 53.009 56.386 44.417
+ E02 8.386 5.781 27.763
+ E03 11.574 10.412 34.225
+ E04 15.311 16.641 40.002
+ E05 21.099 27.099 47.037
+ E06 27.464 38.835 53.265
+ E07 30.583 43.614 55.324
+ E08 27.553 41.253 43.72
+ E09 23.131 33.91 40.619
+ E10 15.049 18.612 33.316
+ E11 9.165 8.213 26.012
+ E12 5.821 3.476 19.352
+ E13 3.178 1.134 11.065
+ E14 32.772 20.441 36.137
+ E15 18.574 14.486 36.000
+ E16 12.165 13.283 37.532
+ E17 20.936 30.082 49.114
+ E18 26.179 39.081 53.662
+ E19 21.215 35.148 32.511
+ E20 16.763 30.052 8.608
+ E21 30.574 41.333 6.293
+ E22 63.883 65.154 6.804
+ E23 36.079 27.5 3.064
+ E24 18.426 9.673 1.782
+ E25 20.328 10.668 11.479
+ E26 47.129 50.747 43.494
+ E27 45.528 47.626 39.123
+ E28 44.554 44.762 35.204
+ F02 6.368 4.959 27.103
+ F03 8.954 9.421 33.626
+ F04 12.046 15.412 39.432
+ F05 16.445 24.385 45.858
+ F06 20.113 31.659 50.153
+ F07 22.051 34.426 51.578
+ F08 19.632 32.109 44.547
+ F09 17.001 27.957 42.024
+ F10 11.577 16.618 35.22
+ F11 6.918 7.101 27.029
+ F12 4.309 2.758 19.695
+ F13 2.222 0.731 10.705
+ F14 26.945 14.78 30.904
+ F15 12.401 8.777 30.923
+ F16 6.658 6.438 29.4
+ F17 12.797 19.297 42.136
+ F18 18.427 29.885 49.126
+ F19 12.294 24.337 23.523
+ F20 8.47 18.427 2.954
+ F21 25.113 35.116 2.692
+ F22 62.917 62.389 3.348
+ F23 29.138 19.14 0.691
+ F24 12.647 5.718 0.185
+ F25 14.014 6.371 5.555
+ F26 35.636 36.998 34.385
+ F27 37.357 39.073 32.505
+ F28 39.18 41.212 29.994
+ G02 4.654 3.718 23.728
+ G03 6.283 6.908 29.334
+ G04 8.163 11.056 34.327
+ G05 10.842 17.236 39.952
+ G06 13.027 21.956 43.616
+ G07 14.821 24.858 45.838
+ G08 12.501 21.969 39.898
+ G09 10.848 18.953 37.473
+ G10 7.763 11.612 31.571
+ G11 5.023 5.215 24.355
+ G12 3.357 2.126 17.864
+ G13 1.743 0.552 9.45
+ G14 13.383 5.464 14.796
+ G15 4.308 1.645 13.987
+ G16 2.167 0.77 11.785
+ G17 6.278 7.264 29.187
+ G18 12.468 21.262 42.54
+ G19 7.159 16.892 13.939
+ G20 4.6 10.846 0.834
+ G21 19.409 27.107 1.076
+ G22 47.378 44.339 1.058
+ G23 22.289 13.428 0.239
+ G24 8.959 3.816 0.018
+ G25 9.579 4.041 2.544
+ G26 31.736 31.893 28.491
+ G27 30.165 31.682 26.269
+ G28 29.662 31.861 25.568
+ H02 0.461 0.186 2.441
+ H03 0.941 0.992 4.564
+ H04 1.756 3.154 6.521
+ H05 3.582 8.288 8.926
+ H06 6.013 14.762 11.175
+ H07 7.642 17.876 13.524
+ H08 9.843 19.999 25.663
+ H09 8.177 16.912 23.1
+ H10 5.372 9.823 18.883
+ H11 3.192 4.082 14.531
+ H12 2.003 1.475 10.492
+ H13 1.061 0.343 5.739
+ H14 6.674 2.663 8.453
+ H15 2.34 0.823 8.659
+ H16 1.424 0.443 7.72
+ H17 3.7 3.583 18.392
+ H18 8.309 14.901 28.931
+ H19 4.341 11.205 6.88
+ H20 3.147 7.651 0.625
+ H21 10.944 16.126 0.762
+ H22 21.411 20.364 0.606
+ H23 9.9 6.02 0.151
+ H24 5.002 2.171 0.019
+ H25 5.207 2.252 1.331
+ H26 26.152 28.536 24.809
+ H27 24.71 26.089 21.71
+ H28 23.442 23.841 19.131
+ I02 0.623 0.275 2.27
+ I03 1.358 1.348 4.048
+ I04 2.894 4.478 5.928
+ I05 6.469 12.434 8.339
+ I06 11.078 22.462 10.722
+ I07 13.785 26.952 13.421
+ I08 16.457 29.743 27.76
+ I09 13.658 25.303 24.605
+ I10 8.595 14.351 20.015
+ I11 4.549 5.587 14.961
+ I12 2.594 1.929 10.771
+ I13 1.342 0.462 6.167
+ I14 2.562 1.067 3.842
+ I15 1.095 0.427 4.104
+ I16 0.725 0.257 3.88
+ I17 1.545 1.606 7.557
+ I18 3.219 6.001 11.357
+ I19 1.747 4.545 2.842
+ I20 1.353 3.291 0.356
+ I21 4.249 6.369 0.411
+ I22 7.927 7.76 0.334
+ I23 3.799 2.502 0.109
+ I24 1.902 0.861 0.02
+ I25 1.978 0.901 0.681
+ I26 19.442 20.5 19.781
+ I27 19.851 21.168 17.794
+ I28 20.769 22.202 16.051
+ J02 1.401 0.622 2.136
+ J03 2.702 2.007 3.488
+ J04 5.051 5.588 5.045
+ J05 9.951 14.434 7.059
+ J06 16.982 27.791 9.331
+ J07 21.361 35.241 11.98
+ J08 23.982 38.364 25.345
+ J09 19.362 30.687 21.964
+ J10 11.868 16.245 17.578
+ J11 6.56 6.591 13.379
+ J12 3.902 2.573 9.871
+ J13 2.147 0.819 6.098
+ J14 0.76 0.365 1.233
+ J15 0.36 0.181 1.226
+ J16 0.239 0.122 1.194
+ J17 0.451 0.554 1.991
+ J18 0.797 1.511 2.705
+ J19 0.492 1.178 0.84
+ J20 0.405 0.916 0.16
+ J21 0.959 1.409 0.164
+ J22 2.126 2.146 0.166
+ J23 1.144 0.84 0.077
+ J24 0.574 0.286 0.025
+ J25 0.588 0.301 0.282
+ J26 15.996 16.353 15.287
+ J27 15.535 16.669 14.029
+ J28 15.219 16.756 13.611
+ K02 3.453 1.498 2.025
+ K03 5.457 3.199 3.005
+ K04 8.24 6.666 4.026
+ K05 13.803 15.032 5.462
+ K06 22.068 29.259 7.331
+ K07 28.861 41.569 10.129
+ K08 30.536 43.905 20.585
+ K09 23.641 31.285 17.109
+ K10 15.215 16.368 13.852
+ K11 9.442 7.446 10.876
+ K12 6.523 3.691 8.576
+ K13 4.218 1.708 5.864
+ K14 0.11 0.08 0.178
+ K15 0.057 0.052 0.165
+ K16 0.056 0.05 0.163
+ K17 0.084 0.11 0.219
+ K18 0.12 0.202 0.266
+ K19 0.097 0.169 0.114
+ K20 0.092 0.152 0.055
+ K21 0.091 0.149 0.054
+ K22 0.176 0.204 0.055
+ K23 0.118 0.109 0.036
+ K24 0.083 0.058 0.024
+ K25 0.084 0.062 0.055
+ K26 13.207 14.81 13.496
+ K27 11.931 12.895 11.183
+ K28 11.35 11.769 9.683
+ L01 76.732 79.364 62.827
+ L02 7.664 3.259 1.993
+ L03 11.545 5.898 2.9
+ L04 15.727 10.146 3.785
+ L05 23.087 19.47 4.953
+ L06 33.342 35.063 6.642
+ L07 41.546 50.533 9.282
+ L08 43.151 53.11 19.221
+ L09 34.773 37.02 16.135
+ L10 24.286 20.62 13.122
+ L11 16.886 10.882 10.491
+ L12 12.652 6.416 8.353
+ L13 8.532 3.519 5.826
+ L14 76.675 79.226 62.699
+ L15 0.038 0.035 0.025
+ L16 21.288 22.639 19.359
+ L26 9.11 9.854 9.906
+ L27 9.204 10.05 8.65
+ L28 9.602 10.532 7.77
+ L29 0.04 0.037 0.028
+ M02 9.87 4.175 1.899
+ M03 15.719 7.67 2.788
+ M04 22.009 12.713 3.541
+ M05 32.688 23.723 4.613
+ M06 47.45 42.107 6.039
+ M07 64.575 66.511 9.359
+ M08 66.43 69.356 18.887
+ M09 48.955 44.07 15.064
+ M10 34.018 24.945 12.469
+ M11 23.221 13.444 9.974
+ M12 16.908 8.226 8.018
+ M13 10.7 4.424 5.556
+ M14 37.403 32.664 35.56
+ M15 32.819 30.306 35.072
+ M16 26.055 26.69 34.653
+ M17 31.517 36.319 38.023
+ M18 34.22 41.544 39.547
+ M19 33.174 40.732 33.899
+ M20 31.317 39.16 23.785
+ M21 39.198 43.977 23.638
+ M22 45.035 47.614 23.798
+ M23 41.489 41.406 22.88
+ M24 34.664 30.711 20.744
+ M25 36.343 31.891 30.185
+ M26 7.308 7.575 7.29
+ M27 7.054 7.689 6.661
+ M28 6.736 7.597 6.317
+ N02 9.564 4.071 0.433
+ N03 15.244 7.361 0.692
+ N04 21.49 12.159 0.981
+ N05 32.074 22.601 1.513
+ N06 46.699 40.175 2.375
+ N07 63.358 63.683 4.666
+ N08 61.976 59.689 1.924
+ N09 46.634 38.442 0.816
+ N10 32.085 21.804 0.415
+ N11 21.453 11.832 0.181
+ N12 15.04 7.149 0.074
+ N13 9.388 3.991 0.02
+ N14 35.079 32.892 32.747
+ N15 32.606 31.487 32.409
+ N16 28.131 29.186 32.205
+ N17 31.664 35.404 34.064
+ N18 33.404 38.542 34.958
+ N19 32.65 37.87 31.68
+ N20 31.542 36.992 25.464
+ N21 36.414 39.679 25.151
+ N22 39.129 41.364 25.394
+ N23 37.199 38.042 24.882
+ N24 33.221 31.488 23.357
+ N25 34.4 32.364 29.693
+ N26 5.531 6.401 6.067
+ N27 4.987 5.505 4.891
+ N28 4.581 4.801 4.063
+ O02 7.307 3.137 0.433
+ O03 11.063 5.574 0.707
+ O04 15.275 9.584 1.061
+ O05 22.42 18.23 1.628
+ O06 32.349 32.649 2.497
+ O07 40.54 47.841 4.313
+ O08 40.237 44.49 1.571
+ O09 32.794 30.944 0.812
+ O10 22.853 17.525 0.434
+ O11 15.44 9.303 0.194
+ O12 11.054 5.451 0.077
+ O13 7.224 3.094 0.021
+ O14 34.294 34.203 31.000
+ O15 33.121 33.542 30.87
+ O16 31.021 32.405 30.573
+ O17 32.709 35.229 31.551
+ O18 33.535 36.782 31.879
+ O19 33.11 36.372 30.011
+ O20 32.623 35.989 27.478
+ O21 34.678 37.087 27.421
+ O22 35.836 37.705 27.441
+ O23 35.015 36.226 27.209
+ O24 33.385 33.432 26.6
+ O25 34.104 34.07 29.423
+ O26 3.264 3.634 3.923
+ O27 3.356 3.715 3.454
+ O28 3.505 3.974 3.077
+ P02 3.123 1.387 0.434
+ P03 4.978 2.868 0.72
+ P04 7.69 6.024 1.097
+ P05 13.026 13.656 1.794
+ P06 20.866 26.635 2.733
+ P07 27.647 38.762 4.545
+ P08 26.873 34.908 1.482
+ P09 20.633 24.173 0.833
+ P10 13.01 12.581 0.452
+ P11 7.668 5.626 0.201
+ P12 4.955 2.744 0.083
+ P13 3.065 1.355 0.022
+ P14 11.506 6.825 13.879
+ P15 7.899 5.228 14.444
+ P16 5.052 4.19 17.555
+ P17 10.715 14.734 26.092
+ P18 15.327 24.08 30.67
+ P19 13.062 22.129 18.974
+ P20 10.514 18.873 5.22
+ P21 16.35 20.537 3.911
+ P22 21.802 22.81 3.581
+ P23 16.148 14.308 2.827
+ P24 9.332 5.626 1.729
+ P25 10.413 6.295 7.89
+ P26 2.481 2.647 2.748
+ P27 2.24 2.556 2.402
+ P28 2.085 2.463 2.166
+ Q02 1.092 0.522 0.456
+ Q03 2.16 1.621 0.814
+ Q04 4.314 4.723 1.353
+ Q05 8.882 12.573 2.169
+ Q06 15.507 24.675 3.276
+ Q07 19.737 32.052 4.983
+ Q08 18.787 28.048 1.414
+ Q09 15.056 21.662 0.911
+ Q10 8.8 11.263 0.541
+ Q11 4.288 4.253 0.241
+ Q12 2.144 1.488 0.093
+ Q13 1.037 0.489 0.025
+ Q14 9.661 6.986 11.373
+ Q15 7.814 6.216 12.03
+ Q16 5.87 5.682 14.411
+ Q17 9.735 12.66 18.551
+ Q18 12.576 18.175 20.725
+ Q19 11.486 17.281 14.793
+ Q20 9.913 15.513 6.281
+ Q21 13.03 15.869 5.096
+ Q22 15.405 16.598 4.712
+ Q23 12.441 11.949 4.157
+ Q24 8.247 6.088 3.129
+ Q25 9.056 6.64 7.831
+ Q26 1.635 1.969 1.965
+ Q27 1.464 1.693 1.616
+ Q28 1.358 1.499 1.326
+ R02 0.299 0.171 0.464
+ R03 0.8 0.952 0.9
+ R04 2.08 3.512 1.535
+ R05 5.297 10.401 2.45
+ R06 9.536 19.375 3.545
+ R07 12.138 24.003 5.201
+ R08 11.159 20.153 1.28
+ R09 9.046 16.391 0.89
+ R10 5.192 9.04 0.572
+ R11 2.019 3.032 0.264
+ R12 0.731 0.781 0.098
+ R13 0.242 0.135 0.024
+ R14 9.08 8.401 9.714
+ R15 8.492 8.242 10.094
+ R16 7.625 8.08 10.952
+ R17 9.408 11.104 12.207
+ R18 10.351 12.767 12.774
+ R19 9.979 12.455 10.779
+ R20 9.358 11.859 7.552
+ R21 10.401 11.969 6.926
+ R22 11.128 12.163 6.697
+ R23 10.211 10.67 6.45
+ R24 8.438 7.916 5.779
+ R25 8.908 8.293 8.294
+ R26 0.824 0.967 1.118
+ R27 0.892 1.044 0.995
+ R28 0.898 1.066 0.866
+ S02 0.108 0.076 0.463
+ S03 0.314 0.595 0.923
+ S04 0.895 2.271 1.497
+ S05 2.381 6.453 2.317
+ S06 4.54 12.112 3.23
+ S07 6 15.207 4.627
+ S08 5.164 12.038 1.021
+ S09 3.972 9.549 0.735
+ S10 2.102 5.137 0.479
+ S11 0.748 1.782 0.243
+ S12 0.201 0.412 0.099
+ S13 0.034 0.033 0.023
+ S14 1.725 1.253 2.271
+ S15 1.29 1.041 2.329
+ S16 0.733 0.725 2.351
+ S17 1.231 1.755 3.158
+ S18 1.614 2.609 3.588
+ S19 1.41 2.414 2.387
+ S20 1.173 2.065 0.872
+ S21 2.237 2.832 0.862
+ S22 2.94 3.185 0.824
+ S23 2.319 2.239 0.688
+ S24 1.415 1.023 0.463
+ S25 1.59 1.165 1.443
+ S26 0.517 0.577 0.634
+ S27 0.418 0.508 0.509
+ S28 0.389 0.49 0.474
+ T01 20.906 22.173 18.934
+ T14 1.673 1.457 2.146
+ T15 1.39 1.301 2.148
+ T16 0.95 1.044 2.135
+ T17 1.331 1.79 2.561
+ T18 1.571 2.278 2.786
+ T19 1.464 2.181 2.147
+ T20 1.302 1.983 1.137
+ T21 1.948 2.412 1.151
+ T22 2.312 2.604 1.125
+ T23 1.997 2.087 1.027
+ T24 1.446 1.262 0.839
+ T25 1.578 1.38 1.593
+ T26 0.226 0.308 0.356
+ T27 0.189 0.243 0.247
+ T28 0.177 0.205 0.205
+ T29 76.694 79.235 62.936
+ U01 0.04 0.037 0.026
+ U14 1.521 1.579 1.795
+ U15 1.449 1.541 1.83
+ U16 1.215 1.388 1.789
+ U17 1.372 1.691 1.882
+ U18 1.47 1.863 1.965
+ U19 1.436 1.833 1.767
+ U20 1.377 1.769 1.375
+ U21 1.604 1.908 1.358
+ U22 1.702 1.968 1.36
+ U23 1.61 1.806 1.34
+ U24 1.417 1.476 1.246
+ U25 1.493 1.552 1.626
+ U26 0.045 0.043 0.088
+ U27 0.044 0.048 0.036
+ U28 0.059 0.074 0.038
+ U29 0.042 0.039 0.029
+ V01 76.341 78.885 62.676
+ V14 21.197 22.447 19.277
+ V15 76.612 79.131 62.823
+ V26 0.039 0.036 0.025
+ V27 0.04 0.037 0.026
+ V28 0.039 0.037 0.026
+ V29 0.038 0.035 0.027
+
diff --git a/ref/LaserSoftDCPro.cht b/ref/LaserSoftDCPro.cht
new file mode 100644
index 0000000..e5df741
--- /dev/null
+++ b/ref/LaserSoftDCPro.cht
@@ -0,0 +1,202 @@
+
+BOXES 141
+ F _ _ 26.09 18.7 239.15 18.7 239.15 171.9 26.09 171.9
+ D ALL ALL _ _ 263.95 185.5 0 0 0 0
+ Y 1 14 A J 12.675 12.75 27.5 20.0 15.175 15.25
+
+BOX_SHRINK 1.6
+
+XLIST 28
+ 27.5 1.0 1.0
+ 40.175 1.0 1.0
+ 42.675 1.0 1.0
+ 55.35 1.0 1.0
+ 57.85 1.0 1.0
+ 70.525 1.0 1.0
+ 73.025 1.0 1.0
+ 85.7 1.0 1.0
+ 88.2 1.0 1.0
+ 100.875 1.0 1.0
+ 103.375 1.0 1.0
+ 116.05 1.0 1.0
+ 118.55 1.0 1.0
+ 131.225 1.0 1.0
+ 133.725 1.0 1.0
+ 146.4 1.0 1.0
+ 148.9 1.0 1.0
+ 161.575 1.0 1.0
+ 164.075 1.0 1.0
+ 176.75 1.0 1.0
+ 179.25 1.0 1.0
+ 191.925 1.0 1.0
+ 194.425 1.0 1.0
+ 207.1 1.0 1.0
+ 209.6 1.0 1.0
+ 222.275 1.0 1.0
+ 224.775 1.0 1.0
+ 237.45 1.0 1.0
+
+YLIST 20
+ 20.0 1.0 1.0
+ 32.75 1.0 1.0
+ 35.25 1.0 1.0
+ 48.0 1.0 1.0
+ 50.5 1.0 1.0
+ 63.25 1.0 1.0
+ 65.75 1.0 1.0
+ 78.5 1.0 1.0
+ 81.0 1.0 1.0
+ 93.75 1.0 1.0
+ 96.25 1.0 1.0
+ 109.0 1.0 1.0
+ 111.5 1.0 1.0
+ 124.25 1.0 1.0
+ 126.75 1.0 1.0
+ 139.5 1.0 1.0
+ 142.0 1.0 1.0
+ 154.75 1.0 1.0
+ 157.25 1.0 1.0
+ 170.0 1.0 1.0
+
+EXPECTED XYZ 140
+ A1 95.054 99.997 108.93
+ A2 1.1997 1.1177 1.8435
+ A3 6.7205 6.2574 11.555
+ A4 95.054 99.997 108.93
+ A5 95.054 99.997 108.93
+ A6 95.054 99.997 108.93
+ A7 0.49927 0.43693 0.87678
+ A8 95.054 99.997 108.93
+ A9 95.054 99.997 108.93
+ A10 95.054 99.997 108.93
+ A11 95.054 99.997 108.93
+ A12 5.5560 5.1972 9.8224
+ A13 1.0432 0.94378 1.8118
+ A14 95.054 99.997 108.93
+ B1 95.054 99.997 108.93
+ B2 67.091 47.876 87.898
+ B3 11.506 12.701 30.786
+ B4 58.530 82.881 29.773
+ B5 51.017 26.596 49.038
+ B6 13.118 10.105 52.231
+ B7 81.415 94.542 37.089
+ B8 44.474 25.101 11.115
+ B9 21.340 12.736 95.969
+ B10 66.377 85.211 107.59
+ B11 42.717 22.847 6.6395
+ B12 95.054 99.997 108.93
+ B13 78.392 91.406 108.15
+ B14 95.054 99.997 108.93
+ C1 0.91819 0.83268 1.3889
+ C2 78.242 93.273 20.381
+ C3 39.945 21.012 96.586
+ C4 95.054 99.997 108.93
+ C5 8.0062 6.3371 5.5237
+ C6 95.054 99.997 108.93
+ C7 95.054 99.997 108.93
+ C8 95.054 99.997 108.93
+ C9 95.054 99.997 108.93
+ C10 26.464 19.481 13.094
+ C11 55.073 48.678 101.13
+ C12 77.003 92.778 13.853
+ C13 43.434 22.924 11.065
+ C14 0.78528 0.68981 1.5301
+ D1 5.7964 5.4769 9.7970
+ D2 72.996 88.624 107.90
+ D3 86.456 96.558 63.644
+ D4 62.452 84.629 42.335
+ D5 92.459 98.959 95.262
+ D6 35.935 71.602 11.974
+ D7 60.015 81.931 107.29
+ D8 59.633 29.164 97.123
+ D9 20.716 10.192 95.511
+ D10 95.054 99.997 108.93
+ D11 77.045 92.795 14.074
+ D12 43.764 31.444 13.884
+ D13 95.054 99.997 108.93
+ D14 5.4327 5.0906 9.4972
+ E1 95.054 99.997 108.93
+ E2 93.580 97.048 108.44
+ E3 95.054 99.997 108.93
+ E4 95.054 99.997 108.93
+ E5 95.054 99.997 108.93
+ E6 95.054 99.997 108.93
+ E7 0.56064 0.49941 0.85338
+ E8 95.054 99.997 108.93
+ E9 55.394 48.320 10.491
+ E10 95.054 99.997 108.93
+ E11 18.067 9.9172 10.525
+ E12 95.054 99.997 108.93
+ E13 51.153 77.999 78.081
+ E14 95.054 99.997 108.93
+ F1 95.054 99.997 108.93
+ F2 77.003 92.778 13.854
+ F3 95.054 99.997 108.93
+ F4 34.402 22.375 97.141
+ F5 95.054 99.997 108.93
+ F6 53.813 78.733 107.00
+ F7 95.054 99.997 108.93
+ F8 0.67207 0.58997 1.0828
+ F9 60.272 30.442 97.336
+ F10 52.097 40.728 12.472
+ F11 77.003 92.778 13.853
+ F12 95.054 99.997 108.93
+ F13 10.781 6.4490 18.321
+ F14 95.054 99.997 108.93
+ G1 95.054 99.997 108.93
+ G2 55.324 79.512 107.07
+ G3 95.054 99.997 108.93
+ G4 83.272 95.285 46.871
+ G5 58.118 49.046 25.961
+ G6 42.215 22.651 3.9825
+ G7 35.762 71.514 11.921
+ G8 19.846 9.7483 95.471
+ G9 77.003 92.778 13.853
+ G10 95.054 99.997 108.93
+ G11 77.003 92.778 13.853
+ G12 95.054 99.997 108.93
+ G13 60.898 82.386 107.33
+ G14 95.054 99.997 108.93
+ H1 0.54264 0.48279 0.79835
+ H2 89.532 88.954 107.09
+ H3 77.759 93.080 17.834
+ H4 42.861 43.829 100.84
+ H5 36.752 71.940 15.774
+ H6 95.054 99.997 108.93
+ H7 95.054 99.997 108.93
+ H8 95.054 99.997 108.93
+ H9 95.054 99.997 108.93
+ H10 53.813 78.733 107.00
+ H11 15.498 10.161 46.468
+ H12 54.711 27.778 69.401
+ H13 46.548 76.933 18.826
+ H14 0.62698 0.56386 0.99911
+ I1 95.054 99.997 108.93
+ I2 78.269 93.284 20.520
+ I3 79.484 91.969 108.20
+ I4 95.054 99.997 108.93
+ I5 7.1761 7.4119 9.1084
+ I6 68.605 86.360 107.69
+ I7 49.882 38.374 5.3364
+ I8 6.2853 7.7839 9.5291
+ I9 95.054 99.997 108.93
+ I10 71.643 79.666 19.448
+ I11 61.032 72.662 49.370
+ I12 54.931 79.309 107.05
+ I13 79.147 93.635 25.144
+ I14 95.054 99.997 108.93
+ J1 95.054 99.997 108.93
+ J2 0.42397 0.37158 0.62164
+ J3 95.054 99.997 108.93
+ J4 95.054 99.997 108.93
+ J5 95.054 99.997 108.93
+ J6 95.054 99.997 108.93
+ J7 95.054 99.997 108.93
+ J8 95.054 99.997 108.93
+ J9 94.564 99.017 108.77
+ J10 50.473 49.809 73.299
+ J11 17.292 16.601 26.910
+ J12 3.7657 3.5269 5.6717
+ J13 0.50304 0.44681 0.73017
+ J14 95.054 99.997 108.93
+
diff --git a/ref/License.txt b/ref/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/ref/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/ref/Makefile.am b/ref/Makefile.am
new file mode 100644
index 0000000..cdb98ee
--- /dev/null
+++ b/ref/Makefile.am
@@ -0,0 +1,7 @@
+refdir = $(datadir)/color/argyll/ref
+
+ref_DATA = $(wildcard *.cal) $(wildcard *.cht) $(wildcard *.cie) \
+ $(wildcard *.icm) $(wildcard *.sp) $(wildcard *.ti1) \
+ $(wildcard *.ti2)
+
+EXTRA_DIST = $(ref_DATA)
diff --git a/ref/Office.sp b/ref/Office.sp
new file mode 100644
index 0000000..290d310
--- /dev/null
+++ b/ref/Office.sp
@@ -0,0 +1,103 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for Typical Office lighting (Ref), extended to 355nm by estimate of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Wed Sep 12 15:12:32 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "380.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000"
+
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+NUMBER_OF_FIELDS 80
+BEGIN_DATA_FORMAT
+SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 3.0 5.0 6.0 8.0 9.4368 10.6036 13.842 20.7332 34.842 32.098 26.2668 24.5324 24.5532 33.8892 67.0204 82.9432 65.6956 48.8256 39.5772 38.0888 37.9392 37.624 37.78 37.4864 37.5828 37.4708 37.6088 37.4588 37.4644 37.622 38.0968 39.4056 41.7988 45.5484 50.8436 69.6052 106.3616 130.678 114.7876 97.5064 99.306 107.0748 117.8096 127.0744 126.3964 116.4272 111.9564 106.0416 99.828 93.2196 85.5196 77.282 69.6072 62.604 55.1144 48.3624 42.4144 37.872 33.3228 29.2668 25.792 23.0656 19.8412 17.7056 15.4692 13.7852 12.314 10.8312 9.4588 8.542 7.4892 6.912 5.8156 5.7536 5.3348 5.1076 4.636 4.0384 4.1468
+END_DATA
diff --git a/ref/QPcard_201.cht b/ref/QPcard_201.cht
new file mode 100644
index 0000000..a9d9542
--- /dev/null
+++ b/ref/QPcard_201.cht
@@ -0,0 +1,76 @@
+
+BOXES 31
+ F _ _ 0.0 0.0 1654.0 0.0 1654.0 478.0 0.0 478.0
+ D ALL ALL _ _ 1654.0 478.0 0.0 0.0 0 0
+ Y 1 10 A C 118.0 119.0 239.0 66.0 141.5 142.0
+
+BOX_SHRINK 15.0
+
+REF_ROTATION 0.0
+
+XLIST 22
+ 150.618062 0.144363 0.166667
+ 161.602137 0.245110 0.333333
+ 238.956434 0.946427 1.000000
+ 357.016882 0.855510 1.000000
+ 379.969304 0.948635 1.000000
+ 497.948383 0.927859 1.000000
+ 521.902072 1.000000 1.000000
+ 640.004059 0.922588 1.000000
+ 662.964760 0.948369 1.000000
+ 782.052769 0.951028 1.000000
+ 804.971146 0.886492 1.000000
+ 923.008950 0.922731 1.000000
+ 946.989395 0.865832 1.000000
+ 1066.007371 0.876333 1.000000
+ 1088.986522 0.865792 1.000000
+ 1208.017128 0.871015 1.000000
+ 1229.826796 0.868345 1.000000
+ 1349.181703 0.847707 1.000000
+ 1372.210921 0.767835 1.000000
+ 1490.553264 0.783286 1.000000
+ 1513.822380 0.891664 1.000000
+ 1633.171522 0.868381 1.000000
+
+YLIST 8
+ 65.941330 0.342831 1.000000
+ 184.978043 0.345580 1.000000
+ 207.991441 0.442638 1.000000
+ 325.524788 1.000000 1.000000
+ 348.940333 0.208095 1.000000
+ 366.421405 0.090483 0.647059
+ 378.396408 0.079155 0.617647
+ 466.955243 0.226972 0.000000
+
+EXPECTED XYZ 30
+ A1 47.8 50.5 53.2
+ A2 9.3 9.6 27.6
+ A3 60.7 62.1 11.2
+ A4 4.4 4.6 4.9
+ A5 10.5 11.1 11.9
+ A6 16.8 17.8 19.5
+ A7 32.9 34.7 36.8
+ A8 65.1 68.9 72.5
+ A9 81.8 86.6 91.0
+ A10 47.8 50.5 53.2
+ B1 36.9 43.1 7.0
+ B2 15.7 26.5 17.4
+ B3 29.8 19.5 20.8
+ B4 6.2 5.7 7.9
+ B5 10.1 12.3 6.8
+ B6 19.9 20.5 6.5
+ B7 11.0 9.9 6.8
+ B8 36.2 34.2 25.0
+ B9 60.7 67.5 73.7
+ B10 56.3 56.5 70.3
+ C1 47.8 50.5 53.2
+ C2 14.5 8.9 4.3
+ C3 18.6 24.8 52.5
+ C4 9.6 7.2 6.1
+ C5 18.0 19.8 34.8
+ C6 43.0 30.9 5.8
+ C7 57.0 49.6 6.6
+ C8 69.3 68.9 47.9
+ C9 64.5 69.9 59.9
+ C10 47.8 50.5 53.2
+
diff --git a/ref/QPcard_201.cie b/ref/QPcard_201.cie
new file mode 100644
index 0000000..ecd1a3a
--- /dev/null
+++ b/ref/QPcard_201.cie
@@ -0,0 +1,42 @@
+IT8.7/2
+ORIGINATOR "Graeme Gill, ArgyllCMS"
+DESCRIPTOR "QPCard 201"
+CREATED "Nov 29, 2007"
+MANUFACTURER "QPcard AB"
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+SAMPLE_ID XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+NUMBER_OF_SETS 30
+BEGIN_DATA
+A1 47.8 50.5 53.2
+A2 9.3 9.6 27.6
+A3 60.7 62.1 11.2
+A4 4.4 4.6 4.9
+A5 10.5 11.1 11.9
+A6 16.8 17.8 19.5
+A7 32.9 34.7 36.8
+A8 65.1 68.9 72.5
+A9 81.8 86.6 91.0
+A10 47.8 50.5 53.2
+B1 36.9 43.1 7.0
+B2 15.7 26.5 17.4
+B3 29.8 19.5 20.8
+B4 6.2 5.7 7.9
+B5 10.1 12.3 6.8
+B6 19.9 20.5 6.5
+B7 11.0 9.9 6.8
+B8 36.2 34.2 25.0
+B9 60.7 67.5 73.7
+B10 56.3 56.5 70.3
+C1 47.8 50.5 53.2
+C2 14.5 8.9 4.3
+C3 18.6 24.8 52.5
+C4 9.6 7.2 6.1
+C5 18.0 19.8 34.8
+C6 43.0 30.9 5.8
+C7 57.0 49.6 6.6
+C8 69.3 68.9 47.9
+C9 64.5 69.9 59.9
+C10 47.8 50.5 53.2
+END_DATA
diff --git a/ref/QPcard_202.cht b/ref/QPcard_202.cht
new file mode 100644
index 0000000..4d10406
--- /dev/null
+++ b/ref/QPcard_202.cht
@@ -0,0 +1,80 @@
+BOXES 36
+ F _ _ 22 20 638 22 638 440 20 440
+ D ALL ALL _ _ 655 455 0 0 0 0
+ Y 1 7 A E 68 68 45 30 83 83
+
+BOX_SHRINK 4.0
+
+REF_ROTATION 0.0
+
+XLIST 19
+ 43.608721 0.740781 0.800000
+ 114.976109 0.783190 0.800000
+ 126.951628 0.918228 0.900000
+ 198.016123 0.974824 0.900000
+ 210.073338 0.901194 1.000000
+ 281.139260 0.985920 1.000000
+ 294.215088 0.898482 1.000000
+ 364.783383 0.991485 1.000000
+ 377.849374 0.904129 1.000000
+ 448.984652 1.000000 1.000000
+ 460.979320 0.954860 1.000000
+ 532.024333 0.997190 1.000000
+ 544.239647 0.898460 1.000000
+ 615.407960 0.946305 1.000000
+ 631.910471 0.186078 0.000000
+ 636.058422 0.233922 0.000000
+ 642.588462 0.132382 0.000000
+ 643.533506 0.270593 0.000000
+ 644.296155 0.191706 0.000000
+
+YLIST 12
+ 26.695891 1.000000 0.875000
+ 98.238688 0.936512 1.000000
+ 110.194036 0.994019 1.000000
+ 181.442800 0.892945 1.000000
+ 194.417673 0.992089 0.937500
+ 264.518175 0.877113 0.875000
+ 277.701905 0.986234 1.000000
+ 347.941384 0.877209 1.000000
+ 360.406157 0.132648 0.312500
+ 361.033254 0.706971 0.875000
+ 431.983255 0.253427 0.750000
+ 432.622344 0.399964 0.000000
+
+EXPECTED XYZ 35
+A1 67.856459 69.512840 9.015609
+A2 67.076305 59.459332 7.827210
+A3 58.305183 45.461038 7.748888
+A4 52.785392 65.096997 59.594305
+A5 45.322673 55.739548 35.288307
+A6 58.323014 65.546227 28.470190
+A7 75.997301 76.369564 28.920869
+B1 27.185068 21.163573 31.661582
+B2 19.566090 10.470287 2.899649
+B3 7.735493 16.256731 8.259450
+B4 7.305847 10.044629 23.599855
+B5 38.157321 40.254508 6.905462
+B6 12.286120 18.850102 28.606420
+B7 70.618705 63.122300 27.332985
+C1 27.875888 20.161730 25.953035
+C2 21.562223 11.180011 4.672983
+C3 9.915698 19.077936 6.906382
+C4 9.400751 9.282240 29.346924
+C5 33.030305 38.085875 6.761389
+C6 12.379400 21.440342 24.610384
+C7 68.775747 59.666057 36.778798
+D1 30.312295 21.545103 20.899732
+D2 19.513673 10.562642 7.925905
+D3 9.957248 17.257178 4.623671
+D4 9.916827 8.308213 24.940996
+D5 24.060360 31.480055 7.467898
+D6 11.633929 19.652104 17.324887
+D7 64.052575 58.473280 56.362590
+E1 81.660435 84.707213 65.484182
+E2 61.845146 64.255877 51.551387
+E3 35.051455 36.358983 29.400605
+E4 22.483519 23.314508 19.344460
+E5 10.265340 10.652815 8.624928
+E6 5.291836 5.472343 4.344900
+E7 3.074245 3.153171 2.547055
diff --git a/ref/QPcard_202.cie b/ref/QPcard_202.cie
new file mode 100644
index 0000000..683b6c0
--- /dev/null
+++ b/ref/QPcard_202.cie
@@ -0,0 +1,48 @@
+IT8.7/2
+ORIGINATOR "jose pereira jpereira.net"
+DESCRIPTOR "QPCARD 202"
+CREATED "may 2012"
+MANUFACTURER "QPcard"
+NUMBER_OF_FIELDS 7
+BEGIN_DATA_FORMAT
+SAMPLE_ID XYZ_X XYZ_Y XYZ_Z LAB_L LAB_A LAB_B
+END_DATA_FORMAT
+NUMBER_OF_SETS 35
+BEGIN_DATA
+A01 67.856459 69.512840 9.015609 86.757375 1.825575 81.545134
+A02 67.076305 59.459332 7.827210 81.543425 22.588491 76.956535
+A03 58.305183 45.461038 7.748888 73.194438 38.355857 62.867015
+A04 52.785392 65.096997 59.594305 84.533694 -24.307666 -6.124730
+A05 45.322673 55.739548 35.288307 79.465357 -22.724528 13.897787
+A06 58.323014 65.546227 28.470190 84.764423 -11.471673 33.441882
+A07 75.997301 76.369564 28.920869 90.030651 4.834878 41.785201
+B01 27.185068 21.163573 31.661582 53.128052 29.896273 -26.161046
+B02 19.566090 10.470287 2.899649 38.673581 58.158660 28.749194
+B03 7.735493 16.256731 8.259450 47.309526 -57.238786 16.283396
+B04 7.305847 10.044629 23.599855 37.922410 -20.845869 -38.815336
+B05 38.157321 40.254508 6.905462 69.650420 -2.091972 60.182723
+B06 12.286120 18.850102 28.606420 50.511369 -35.081968 -25.838514
+B07 70.618705 63.122300 27.332985 83.506686 21.791859 33.166706
+C01 27.875888 20.161730 25.953035 52.019576 37.428172 -18.752022
+C02 21.562223 11.180011 4.672983 39.882016 62.620005 19.536557
+C03 9.915698 19.077936 6.906382 50.778263 -53.582415 27.640637
+C04 9.400751 9.282240 29.346924 36.522120 3.739027 -51.160034
+C05 33.030305 38.085875 6.761389 68.083859 -12.577785 58.094494
+C06 12.379400 21.440342 24.610384 53.428091 -47.018893 -13.936155
+C07 68.775747 59.666057 36.778798 81.656338 25.812200 15.582830
+D01 30.312295 21.545103 20.899732 53.540986 40.234784 -6.655919
+D02 19.513673 10.562642 7.925905 38.833864 57.205173 2.937550
+D03 9.957248 17.257178 4.623671 48.582459 -43.791000 34.808467
+D04 9.916827 8.308213 24.940996 34.616704 16.088365 -46.965354
+D05 24.060360 31.480055 7.467898 62.910807 -25.347082 46.249115
+D06 11.633929 19.652104 17.324887 51.441570 -43.624665 -2.604415
+D07 64.052575 58.473280 56.362590 81.001208 18.165842 -8.910822
+E01 81.660435 84.707213 65.484182 93.756804 -0.027533 4.049779
+E02 61.845146 64.255877 51.551387 84.098816 -0.256360 1.591948
+E03 35.051455 36.358983 29.400605 66.793307 -0.019940 0.945311
+E04 22.483519 23.314508 19.344460 55.394826 0.016750 -0.239174
+E05 10.265340 10.652815 8.624928 38.989459 -0.046959 0.588338
+E06 5.291836 5.472343 4.344900 28.040182 0.184525 0.961005
+E07 3.074245 3.153171 2.547055 20.647174 0.585930 0.440283
+
+END_DATA
diff --git a/ref/ReadMe.txt b/ref/ReadMe.txt
new file mode 100644
index 0000000..ab03ad5
--- /dev/null
+++ b/ref/ReadMe.txt
@@ -0,0 +1,61 @@
+
+The files in this directory are for examples and refererence.
+------------------------------------------------------------
+
+The following files are in the public domain:
+
+ sRGB.icm
+ ClayRGB1998.icm
+ lab2lab.icm
+
+The following files are licensed acording to the
+GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+see the License.txt file for licensing details.
+
+
+ ccxx.ti1
+ CMP_DT_003.cht
+ CMP_Digital_Target-3.cht
+ CMP_Digital_Target-3.ti2
+ CMP_Digital_Target-3.cie
+ ColorChecker.cht
+ ColorChecker.cie
+ ColorChecker.ti2
+ ColorCheckerDC.cht
+ ColorCheckerSG.cht
+ ECI2002.ti2
+ ECI2002R.ti2
+ FograStrip2.ti1
+ FograStrip2.ti2
+ FograStrip3.ti1
+ FograStrip3.ti2
+ Hutchcolor.cht
+ LaserSoftDCPro.cht
+ QPcard_201.cht
+ QPcard_201.cie
+ i1_RGB_Scan_1.4.cht
+ i1_RGB_Scan_1.4.ti2
+ it8.cht
+ linear.cal
+ strange.cal
+ 3dap5k.sp
+ CIE_C.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
+ GTIPlus.sp
+ Office.sp
+ SOtele.sp
+ Trulux.sp
+ TruluxPlus.sp
+ example.sp
+ example121.sp
diff --git a/ref/SOtele.sp b/ref/SOtele.sp
new file mode 100644
index 0000000..f63d90e
--- /dev/null
+++ b/ref/SOtele.sp
@@ -0,0 +1,23 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectrolino tele adapter compensation filter"
+ORIGINATOR "Argyll CMS"
+CREATED "Wed Jun 21 17:49:57 2006"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "36"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "380.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "730.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "1.000000"
+
+NUMBER_OF_FIELDS 36
+BEGIN_DATA_FORMAT
+SPEC_380 SPEC_390 SPEC_400 SPEC_410 SPEC_420 SPEC_430 SPEC_440 SPEC_450 SPEC_460 SPEC_470 SPEC_480 SPEC_490 SPEC_500 SPEC_510 SPEC_520 SPEC_530 SPEC_540 SPEC_550 SPEC_560 SPEC_570 SPEC_580 SPEC_590 SPEC_600 SPEC_610 SPEC_620 SPEC_630 SPEC_640 SPEC_650 SPEC_660 SPEC_670 SPEC_680 SPEC_690 SPEC_700 SPEC_710 SPEC_720 SPEC_730
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+1.7378 1.3294 1.1691 1.1313 1.1326 1.1301 1.1302 1.1290 1.1288 1.1274 1.1286 1.1280 1.1273 1.1263 1.1242 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231
+END_DATA
diff --git a/ref/SpyderChecker.cht b/ref/SpyderChecker.cht
new file mode 100644
index 0000000..1c0ef3a
--- /dev/null
+++ b/ref/SpyderChecker.cht
@@ -0,0 +1,115 @@
+BOXES 49
+ F _ _ 5 4 470 5 470 307 5 307
+
+ D ALL ALL _ _ 475 315 0 0 0 0
+
+ X A D 1 6 42 42 11 10 49 50
+ X E H 1 6 42 42 274 10 49 50
+
+
+BOX_SHRINK 3.0
+
+REF_ROTATION 0.0
+
+XLIST 27
+ 4.984973 0.109746 0.076923
+ 9.286927 0.952526 1.000000
+ 52.887948 0.925344 1.000000
+ 59.167435 1.000000 0.923077
+ 102.212773 0.458586 0.923077
+ 102.919173 0.494117 0.384615
+ 108.965439 0.995672 1.000000
+ 152.335524 0.929079 1.000000
+ 158.540776 0.956677 1.000000
+ 202.023990 0.948802 1.000000
+ 207.819679 0.348860 0.076923
+ 213.309915 0.948588 0.000000
+ 230.603930 0.364584 0.000000
+ 234.074857 0.305779 0.000000
+ 240.406366 0.419481 0.000000
+ 243.970119 0.780089 0.000000
+ 260.767091 0.913272 0.000000
+ 266.441147 0.117583 0.076923
+ 271.869223 0.913611 1.000000
+ 315.052562 0.921224 1.000000
+ 321.439873 0.976014 1.000000
+ 364.747788 0.940719 1.000000
+ 371.336194 0.968158 1.000000
+ 414.647393 0.874415 1.000000
+ 420.992026 0.882322 1.000000
+ 464.404335 0.944708 1.000000
+ 469.433263 0.121537 0.076923
+
+YLIST 22
+ 4.526138 1.000000 0.000000
+ 9.908960 0.796520 0.730769
+ 53.044496 0.103192 0.730769
+ 53.524920 0.636430 0.576923
+ 60.203792 0.830553 0.730769
+ 103.048172 0.307118 0.730769
+ 103.492169 0.530702 0.615385
+ 109.526018 0.312034 0.153846
+ 109.974584 0.523340 0.730769
+ 153.023131 0.597133 0.730769
+ 153.456869 0.213758 0.461538
+ 159.493872 0.317053 0.115385
+ 159.963940 0.430105 0.884615
+ 202.530321 0.801088 0.884615
+ 209.038198 0.511082 0.115385
+ 209.470794 0.321862 0.846154
+ 252.013363 0.513537 0.884615
+ 252.528335 0.297345 0.538462
+ 258.522376 0.203926 0.076923
+ 258.989151 0.557818 1.000000
+ 301.519003 0.098341 1.000000
+ 302.011325 0.695429 0.000000
+
+EXPECTED XYZ 48
+ A1 35.76 28.63 20.95
+ A2 45.15 47.41 16.97
+ A3 26.68 36.02 22.61
+ A4 24.43 30.51 49.72
+ A5 27.36 28.54 55.85
+ A6 33.51 26.53 34.35
+ B1 58.65 60.38 64.15
+ B2 55.22 59.80 62.04
+ B3 57.62 60.06 69.00
+ B4 5.28 5.14 5.28
+ B5 4.44 5.04 5.06
+ B6 5.12 5.19 6.86
+ C1 64.60 65.02 55.99
+ C2 45.46 45.77 29.03
+ C3 33.13 32.26 14.73
+ C4 15.61 13.92 7.09
+ C5 5.16 5.03 3.92
+ C6 4.01 4.17 4.76
+ D1 77.89 81.93 87.49
+ D2 70.10 73.80 78.79
+ D3 43.43 45.76 48.92
+ D4 24.24 25.51 27.51
+ D5 12.32 12.98 13.91
+ D6 5.22 5.50 6.02
+ E1 85.00 89.31 96.33
+ E2 54.09 56.94 61.35
+ E3 32.55 34.33 36.79
+ E4 17.72 18.68 20.09
+ E5 7.89 8.30 8.87
+ E6 2.65 2.78 3.12
+ F1 12.84 18.14 36.39
+ F2 28.20 18.34 29.84
+ F3 57.08 61.01 8.56
+ F4 19.63 11.29 4.87
+ F5 13.70 22.39 9.24
+ F6 7.32 5.35 26.41
+ G1 35.76 28.16 5.45
+ G2 12.71 11.07 36.60
+ G3 27.74 18.51 13.48
+ G4 9.34 6.93 16.38
+ G5 33.22 43.77 10.98
+ G6 46.49 42.42 7.53
+ H1 30.35 42.13 42.95
+ H2 24.45 23.05 44.34
+ H3 9.73 12.51 6.59
+ H4 17.28 18.47 34.69
+ H5 36.71 34.18 24.66
+ H6 10.43 9.32 6.27
diff --git a/ref/SpyderChecker.cie b/ref/SpyderChecker.cie
new file mode 100644
index 0000000..302e416
--- /dev/null
+++ b/ref/SpyderChecker.cie
@@ -0,0 +1,62 @@
+IT8.7/2
+ORIGINATOR "Jose Pereira"
+DESCRIPTOR "Datacolor SpyderCheckr (D65)"
+CREATED "dec, 19. 2011"
+MANUFACTURER "DataColor"
+
+NUMBER_OF_FIELDS 7
+BEGIN_DATA_FORMAT
+SAMPLE_ID XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 48
+BEGIN_DATA
+A1 35.76 28.63 20.95
+A2 45.15 47.41 16.97
+A3 26.68 36.02 22.61
+A4 24.43 30.51 49.72
+A5 27.36 28.54 55.85
+A6 33.51 26.53 34.35
+B1 58.65 60.38 64.15
+B2 55.22 59.80 62.04
+B3 57.62 60.06 69.00
+B4 5.28 5.14 5.28
+B5 4.44 5.04 5.06
+B6 5.12 5.19 6.86
+C1 64.60 65.02 55.99
+C2 45.46 45.77 29.03
+C3 33.13 32.26 14.73
+C4 15.61 13.92 7.09
+C5 5.16 5.03 3.92
+C6 4.01 4.17 4.76
+D1 77.89 81.93 87.49
+D2 70.10 73.80 78.79
+D3 43.43 45.76 48.92
+D4 24.24 25.51 27.51
+D5 12.32 12.98 13.91
+D6 5.22 5.50 6.02
+E1 85.00 89.31 96.33
+E2 54.09 56.94 61.35
+E3 32.55 34.33 36.79
+E4 17.72 18.68 20.09
+E5 7.89 8.30 8.87
+E6 2.65 2.78 3.12
+F1 12.84 18.14 36.39
+F2 28.20 18.34 29.84
+F3 57.08 61.01 8.56
+F4 19.63 11.29 4.87
+F5 13.70 22.39 9.24
+F6 7.32 5.35 26.41
+G1 35.76 28.16 5.45
+G2 12.71 11.07 36.60
+G3 27.74 18.51 13.48
+G4 9.34 6.93 16.38
+G5 33.22 43.77 10.98
+G6 46.49 42.42 7.53
+H1 30.35 42.13 42.95
+H2 24.45 23.05 44.34
+H3 9.73 12.51 6.59
+H4 17.28 18.47 34.69
+H5 36.71 34.18 24.66
+H6 10.43 9.32 6.27
+END_DATA
diff --git a/ref/Trulux.sp b/ref/Trulux.sp
new file mode 100644
index 0000000..fc5bb0f
--- /dev/null
+++ b/ref/Trulux.sp
@@ -0,0 +1,103 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for Trulux D50 viewer - Foam reflector, extended to 355nm with estimation of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Fri Oct 5 15:12:32 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "380.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000"
+
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+NUMBER_OF_FIELDS 80
+BEGIN_DATA_FORMAT
+SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.0 0.685175 1.37035 2.255525 3.0407 4.11105 4.09644 5.01837 7.36485 11.98614 11.19519 7.11198 3.33963 6.44973 21.99549 67.47228 93.88269 79.77081 64.85577 57.85737 65.37378 75.29142 82.82394 87.81939 90.44277 92.28321 93.10557 93.11004 92.17122 89.96841 87.65004 84.8304 82.13712 77.75847 74.04651 74.87289 91.45155 123.67365 139.4193 115.8867 87.2391 79.06761 81.88944 91.58172 101.15043 102.11544 94.71408 93.87819 94.00419 95.28195 97.80723 99.53307 99.40416 98.43141 97.50237 95.58378 93.41358 91.00236 88.69698 85.72017 83.18451 80.22261 77.45886 73.79589 70.02708 66.29484 62.08128 57.95706 53.89545 49.70493 45.99504 42.19815 38.68413 35.16609 32.78418 30.1482 27.3201 24.13857 21.88494 20.10168
+END_DATA
diff --git a/ref/TruluxPlus.sp b/ref/TruluxPlus.sp
new file mode 100644
index 0000000..0fd9c39
--- /dev/null
+++ b/ref/TruluxPlus.sp
@@ -0,0 +1,103 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectral Power information for Trulux D50 viewer - Foam reflector, extended to 355nm with larger estimation of UV"
+ORIGINATOR "Argyll CMS"
+CREATED "Fri Oct 5 15:12:32 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "80"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "355.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000"
+
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+NUMBER_OF_FIELDS 80
+BEGIN_DATA_FORMAT
+SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+10.0 10.0 10.0 10.0 10.0407 6.11105 5.09644 5.01837 7.36485 11.98614 11.19519 7.11198 3.33963 6.44973 21.99549 67.47228 93.88269 79.77081 64.85577 57.85737 65.37378 75.29142 82.82394 87.81939 90.44277 92.28321 93.10557 93.11004 92.17122 89.96841 87.65004 84.8304 82.13712 77.75847 74.04651 74.87289 91.45155 123.67365 139.4193 115.8867 87.2391 79.06761 81.88944 91.58172 101.15043 102.11544 94.71408 93.87819 94.00419 95.28195 97.80723 99.53307 99.40416 98.43141 97.50237 95.58378 93.41358 91.00236 88.69698 85.72017 83.18451 80.22261 77.45886 73.79589 70.02708 66.29484 62.08128 57.95706 53.89545 49.70493 45.99504 42.19815 38.68413 35.16609 32.78418 30.1482 27.3201 24.13857 21.88494 20.10168
+END_DATA
diff --git a/ref/afiles b/ref/afiles
new file mode 100644
index 0000000..17bdef2
--- /dev/null
+++ b/ref/afiles
@@ -0,0 +1,59 @@
+afiles
+ReadMe.txt
+License.txt
+sRGB.icm
+ClayRGB1998.icm
+lab2lab.icm
+ccxx.ti1
+CMP_DT_003.cht
+CMP_Digital_Target-3.cht
+CMP_Digital_Target-3.ti2
+CMP_Digital_Target-3.cie
+ColorChecker.cht
+ColorChecker.cie
+ColorChecker.ti2
+ColorCheckerDC.cht
+ColorCheckerSG.cht
+ColorCheckerPassport.cht
+ColorCheckerPassport.cie
+SpyderChecker.cht
+SpyderChecker.cie
+ECI2002.ti2
+ECI2002R.ti2
+FograStrip2.ti1
+FograStrip2_2.ti2
+FograStrip3.ti1
+FograStrip3_3.ti2
+Hutchcolor.cht
+LaserSoftDCPro.cht
+QPcard_201.cht
+QPcard_201.cie
+QPcard_202.cht
+QPcard_202.cie
+i1_RGB_Scan_1.4.cht
+i1_RGB_Scan_1.4.ti2
+it8.cht
+linear.cal
+strange.cal
+3dap5k.sp
+CIE_C.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
+GTIPlus.sp
+Office.sp
+SOtele.sp
+Trulux.sp
+TruluxPlus.sp
+example.sp
+example121.sp
+CRT.ccss
diff --git a/ref/ccxx.ti1 b/ref/ccxx.ti1
new file mode 100644
index 0000000..47f2b13
--- /dev/null
+++ b/ref/ccxx.ti1
@@ -0,0 +1,22 @@
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1 for creating .ti3 for ccxxmake"
+ORIGINATOR "Argyll targen"
+CREATED "Thu Apr 19 13:24:37 2012"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "95.045781 100.000003 108.905751"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+
+NUMBER_OF_FIELDS 7
+BEGIN_DATA_FORMAT
+SAMPLE_ID RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 4
+BEGIN_DATA
+1 100.00 100.00 100.00 95.046 100.00 108.91
+2 100.00 0.0000 0.0000 41.238 21.260 1.9306
+3 0.0000 100.00 0.0000 35.757 71.520 11.921
+4 0.0000 0.0000 100.00 18.050 7.2205 95.055
+END_DATA
diff --git a/ref/example.sp b/ref/example.sp
new file mode 100644
index 0000000..08d836e
--- /dev/null
+++ b/ref/example.sp
@@ -0,0 +1,132 @@
+SPECT
+
+DESCRIPTOR "Argyll Example Spectral power/reflectance information (D50)"
+ORIGINATOR "Argyll CMS"
+CREATED "Fri Jul 06 17:49:57 2001"
+# If you want the FWA compensation to work properly, you need to specify your
+# light source down to 300nm
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.020000 1.0300 2.0500 4.9100 7.7800 11.260 14.750 16.350 17.950 19.480 21.010 22.480 23.940 25.450 26.960 25.720 24.490 27.180 29.870 39.590 49.310 52.910 56.510 58.270 60.030 58.930 57.820 66.320 74.820 81.040 87.250 88.930 90.610 90.990 91.370 93.240 95.110 93.540 91.960 93.840 95.720 96.170 96.610 96.870 97.130 99.610 102.10 101.43 100.75 101.54 102.32 101.16 100.00 98.870 97.740 98.330 98.920 96.210 93.500 95.590 97.690 98.480 99.270 99.160 99.040 97.380 95.720 97.290 98.860 97.260 95.670 96.930 98.190 100.60 103.00 101.07 99.130 93.260 87.380 89.490 91.600 92.250 92.890 84.870 76.850 81.680 86.510 89.550 92.580 85.400 78.230 67.960 57.690 70.310 82.920 80.600 78.270 78.910 79.550 76.480 73.400 68.660 63.920 67.350 70.780 72.610 74.440
+END_DATA
diff --git a/ref/example121.sp b/ref/example121.sp
new file mode 100644
index 0000000..d139c38
--- /dev/null
+++ b/ref/example121.sp
@@ -0,0 +1,147 @@
+SPECT
+
+DESCRIPTOR "Argyll Example Spectral power/reflectance information with 121 bands from an i1 pro (Fluorescent lamp)"
+ORIGINATOR "Argyll CMS"
+CREATED "Wed Sep 12 16:45:26 2007"
+# If you want the FWA compensation to work properly, you need to specify your
+# light source down to 300nm
+
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "121"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "350"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "750"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100"
+
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_353"
+KEYWORD "SPEC_357"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_363"
+KEYWORD "SPEC_367"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_373"
+KEYWORD "SPEC_377"
+KEYWORD "SPEC_380"
+KEYWORD "SPEC_383"
+KEYWORD "SPEC_387"
+KEYWORD "SPEC_390"
+KEYWORD "SPEC_393"
+KEYWORD "SPEC_397"
+KEYWORD "SPEC_400"
+KEYWORD "SPEC_403"
+KEYWORD "SPEC_407"
+KEYWORD "SPEC_410"
+KEYWORD "SPEC_413"
+KEYWORD "SPEC_417"
+KEYWORD "SPEC_420"
+KEYWORD "SPEC_423"
+KEYWORD "SPEC_427"
+KEYWORD "SPEC_430"
+KEYWORD "SPEC_433"
+KEYWORD "SPEC_437"
+KEYWORD "SPEC_440"
+KEYWORD "SPEC_443"
+KEYWORD "SPEC_447"
+KEYWORD "SPEC_450"
+KEYWORD "SPEC_453"
+KEYWORD "SPEC_457"
+KEYWORD "SPEC_460"
+KEYWORD "SPEC_463"
+KEYWORD "SPEC_467"
+KEYWORD "SPEC_470"
+KEYWORD "SPEC_473"
+KEYWORD "SPEC_477"
+KEYWORD "SPEC_480"
+KEYWORD "SPEC_483"
+KEYWORD "SPEC_487"
+KEYWORD "SPEC_490"
+KEYWORD "SPEC_493"
+KEYWORD "SPEC_497"
+KEYWORD "SPEC_500"
+KEYWORD "SPEC_503"
+KEYWORD "SPEC_507"
+KEYWORD "SPEC_510"
+KEYWORD "SPEC_513"
+KEYWORD "SPEC_517"
+KEYWORD "SPEC_520"
+KEYWORD "SPEC_523"
+KEYWORD "SPEC_527"
+KEYWORD "SPEC_530"
+KEYWORD "SPEC_533"
+KEYWORD "SPEC_537"
+KEYWORD "SPEC_540"
+KEYWORD "SPEC_543"
+KEYWORD "SPEC_547"
+KEYWORD "SPEC_550"
+KEYWORD "SPEC_553"
+KEYWORD "SPEC_557"
+KEYWORD "SPEC_560"
+KEYWORD "SPEC_563"
+KEYWORD "SPEC_567"
+KEYWORD "SPEC_570"
+KEYWORD "SPEC_573"
+KEYWORD "SPEC_577"
+KEYWORD "SPEC_580"
+KEYWORD "SPEC_583"
+KEYWORD "SPEC_587"
+KEYWORD "SPEC_590"
+KEYWORD "SPEC_593"
+KEYWORD "SPEC_597"
+KEYWORD "SPEC_600"
+KEYWORD "SPEC_603"
+KEYWORD "SPEC_607"
+KEYWORD "SPEC_610"
+KEYWORD "SPEC_613"
+KEYWORD "SPEC_617"
+KEYWORD "SPEC_620"
+KEYWORD "SPEC_623"
+KEYWORD "SPEC_627"
+KEYWORD "SPEC_630"
+KEYWORD "SPEC_633"
+KEYWORD "SPEC_637"
+KEYWORD "SPEC_640"
+KEYWORD "SPEC_643"
+KEYWORD "SPEC_647"
+KEYWORD "SPEC_650"
+KEYWORD "SPEC_653"
+KEYWORD "SPEC_657"
+KEYWORD "SPEC_660"
+KEYWORD "SPEC_663"
+KEYWORD "SPEC_667"
+KEYWORD "SPEC_670"
+KEYWORD "SPEC_673"
+KEYWORD "SPEC_677"
+KEYWORD "SPEC_680"
+KEYWORD "SPEC_683"
+KEYWORD "SPEC_687"
+KEYWORD "SPEC_690"
+KEYWORD "SPEC_693"
+KEYWORD "SPEC_697"
+KEYWORD "SPEC_700"
+KEYWORD "SPEC_703"
+KEYWORD "SPEC_707"
+KEYWORD "SPEC_710"
+KEYWORD "SPEC_713"
+KEYWORD "SPEC_717"
+KEYWORD "SPEC_720"
+KEYWORD "SPEC_723"
+KEYWORD "SPEC_727"
+KEYWORD "SPEC_730"
+KEYWORD "SPEC_733"
+KEYWORD "SPEC_737"
+KEYWORD "SPEC_740"
+KEYWORD "SPEC_743"
+KEYWORD "SPEC_747"
+KEYWORD "SPEC_750"
+NUMBER_OF_FIELDS 121
+BEGIN_DATA_FORMAT
+SPEC_350 SPEC_353 SPEC_357 SPEC_360 SPEC_363 SPEC_367 SPEC_370 SPEC_373 SPEC_377 SPEC_380 SPEC_383 SPEC_387 SPEC_390 SPEC_393 SPEC_397 SPEC_400 SPEC_403 SPEC_407 SPEC_410 SPEC_413 SPEC_417 SPEC_420 SPEC_423 SPEC_427 SPEC_430 SPEC_433 SPEC_437 SPEC_440 SPEC_443 SPEC_447 SPEC_450 SPEC_453 SPEC_457 SPEC_460 SPEC_463 SPEC_467 SPEC_470 SPEC_473 SPEC_477 SPEC_480 SPEC_483 SPEC_487 SPEC_490 SPEC_493 SPEC_497 SPEC_500 SPEC_503 SPEC_507 SPEC_510 SPEC_513 SPEC_517 SPEC_520 SPEC_523 SPEC_527 SPEC_530 SPEC_533 SPEC_537 SPEC_540 SPEC_543 SPEC_547 SPEC_550 SPEC_553 SPEC_557 SPEC_560 SPEC_563 SPEC_567 SPEC_570 SPEC_573 SPEC_577 SPEC_580 SPEC_583 SPEC_587 SPEC_590 SPEC_593 SPEC_597 SPEC_600 SPEC_603 SPEC_607 SPEC_610 SPEC_613 SPEC_617 SPEC_620 SPEC_623 SPEC_627 SPEC_630 SPEC_633 SPEC_637 SPEC_640 SPEC_643 SPEC_647 SPEC_650 SPEC_653 SPEC_657 SPEC_660 SPEC_663 SPEC_667 SPEC_670 SPEC_673 SPEC_677 SPEC_680 SPEC_683 SPEC_687 SPEC_690 SPEC_693 SPEC_697 SPEC_700 SPEC_703 SPEC_707 SPEC_710 SPEC_713 SPEC_717 SPEC_720 SPEC_723 SPEC_727 SPEC_730 SPEC_733 SPEC_737 SPEC_740 SPEC_743 SPEC_747 SPEC_750
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+-0.041690 0.24392 4.3572 5.4017 6.5222 7.0710 8.6925 12.563 16.482 18.309 17.829 17.021 16.072 16.687 87.378 282.88 411.34 306.20 188.94 221.27 286.97 368.32 461.52 591.86 962.15 2078.2 2435.7 1583.7 985.14 1000.3 1013.1 1010.9 994.64 967.45 926.07 875.50 826.62 776.65 728.56 729.41 894.38 1230.5 1346.3 1108.1 831.25 636.32 518.37 473.21 477.58 492.45 491.10 457.30 399.25 348.62 326.58 367.02 707.07 1919.0 3813.6 4662.9 3291.3 1432.5 513.04 229.68 141.83 108.25 90.996 144.02 387.80 680.40 822.45 858.52 763.41 621.14 498.90 391.19 345.59 749.61 2255.0 3078.6 1993.9 866.06 750.13 785.14 718.71 498.72 228.97 128.41 127.71 158.54 217.06 231.70 191.86 166.43 164.48 146.81 124.29 112.00 109.04 115.61 129.27 146.74 143.18 117.28 87.783 80.151 141.77 286.25 374.19 308.51 156.95 59.626 32.257 32.390 32.801 33.930 35.539 37.845 36.214 31.438 23.866
+END_DATA
diff --git a/ref/i1_RGB_Scan_1.4.cht b/ref/i1_RGB_Scan_1.4.cht
new file mode 100644
index 0000000..3a3d7c9
--- /dev/null
+++ b/ref/i1_RGB_Scan_1.4.cht
@@ -0,0 +1,341 @@
+
+BOXES 289
+ F _ _ 49 33 662 33 662 466 49 466
+ D ALL ALL _ _ 613 433 49.0 33.0 0 0
+ X A R 1 16 34.0 27.0 49.0 33.0 34.0 27.0
+
+BOX_SHRINK 3.3
+
+REF_ROTATION 0.0
+
+XLIST 19
+ 49.0 1.0 1.0
+ 83.0 1.0 1.0
+ 117.0 1.0 1.0
+ 151.0 1.0 1.0
+ 185.0 1.0 1.0
+ 219.0 1.0 1.0
+ 253.0 1.0 1.0
+ 287.0 1.0 1.0
+ 321.0 1.0 1.0
+ 355.0 1.0 1.0
+ 389.0 1.0 1.0
+ 423.0 1.0 1.0
+ 457.0 1.0 1.0
+ 491.0 1.0 1.0
+ 525.0 1.0 1.0
+ 559.0 1.0 1.0
+ 593.0 1.0 1.0
+ 627.0 1.0 1.0
+ 662.0 1.0 1.0
+
+YLIST 17
+ 33.0 1.0 1.0
+ 60.0 1.0 1.0
+ 87.0 1.0 1.0
+ 114.0 1.0 1.0
+ 141.0 1.0 1.0
+ 168.0 1.0 1.0
+ 195.0 1.0 1.0
+ 222.0 1.0 1.0
+ 249.0 1.0 1.0
+ 276.0 1.0 1.0
+ 303.0 1.0 1.0
+ 330.0 1.0 1.0
+ 357.0 1.0 1.0
+ 384.0 1.0 1.0
+ 411.0 1.0 1.0
+ 439.0 1.0 1.0
+ 466.0 1.0 1.0
+
+EXPECTED XYZ 288
+ A1 0.52 0.59 0.56
+ A2 10.27 10 32.62
+ A3 13.89 7.3 2.84
+ A4 33.34 23.69 4.75
+ A5 31.79 33.22 28.61
+ A6 13.85 14.51 12.72
+ A7 35.52 25.53 10.91
+ A8 27.16 27.04 25.26
+ A9 6.12 6.42 5.76
+ A10 6.04 6.8 6.75
+ A11 4.4 3.47 20.55
+ A12 6.34 3.41 11.34
+ A13 9.03 7.05 14.88
+ A14 7.91 6.52 8.41
+ A15 16.18 10.77 24.37
+ A16 1.97 1.1 8.66
+ B1 27.55 34.83 6.23
+ B2 17.94 11.4 1.02
+ B3 34.87 35.19 5.79
+ B4 13.05 19.54 29.87
+ B5 6.88 9.15 27.74
+ B6 70.59 73.69 44.02
+ B7 2.04 2.19 1.41
+ B8 1.35 2.84 0.94
+ B9 49.51 40.62 36.32
+ B10 43.26 35.61 12.01
+ B11 2.65 3.13 3.25
+ B12 17.77 24.45 21.08
+ B13 8.51 14.13 31.85
+ B14 7.84 11.93 30.12
+ B15 5.81 12.04 16.38
+ B16 11.49 8.06 0.99
+ C1 34.5 19.81 37.1
+ C2 42.27 43.99 33.47
+ C3 4.36 7.54 14.12
+ C4 58.73 57.76 6.5
+ C5 11.22 5.5 17.82
+ C6 1.55 1.89 2.09
+ C7 37.5 39.03 33.61
+ C8 23.67 18.54 4.44
+ C9 8.12 14.07 4.81
+ C10 2.9 7.38 1.41
+ C11 34.09 35.82 26.91
+ C12 9.45 9.34 9.05
+ C13 41.11 33.34 5.29
+ C14 27.38 21.65 19.2
+ C15 27.38 28.66 24.61
+ C16 48.58 49.16 58.53
+ D1 7.47 12.02 1.86
+ D2 17.27 8.47 18.91
+ D3 24.86 14.78 0.99
+ D4 8.61 4.81 2.74
+ D5 28.85 26.03 5.07
+ D6 20.34 26.75 33.64
+ D7 5.39 3.09 6.34
+ D8 7.42 3.7 17.12
+ D9 60.57 66.88 64.61
+ D10 4.42 4.33 4.38
+ D11 2.63 2.73 10.91
+ D12 46.48 54.19 25.5
+ D13 1.24 2.02 2.92
+ D14 2.43 5.58 3.81
+ D15 4.46 2.69 0.72
+ D16 23.58 11.3 19.67
+ E1 18.33 16.26 18.07
+ E2 13.25 17.2 1.73
+ E3 16.1 22.52 11.75
+ E4 50.7 52.96 40.49
+ E5 0.93 1.03 0.98
+ E6 2.58 1.28 12.24
+ E7 61.11 63.67 49.46
+ E8 9.69 16.36 11.19
+ E9 19.64 20.4 5.14
+ E10 68.63 71.55 34.47
+ E11 33.86 33.75 30.83
+ E12 18.65 9.44 0.83
+ E13 12.88 22.5 20.49
+ E14 40.57 35.97 51.8
+ E15 25.89 26.22 33.39
+ E16 30.29 39.21 13.78
+ F1 3.2 7.65 4.38
+ F2 3.71 3.35 16.24
+ F3 23.31 14.61 25.55
+ F4 20.14 13.3 9.05
+ F5 19.65 21.55 20.22
+ F6 1.21 1.33 0.75
+ F7 5.8 8.65 21.51
+ F8 20.82 10.37 7.25
+ F9 12.98 6.05 24.77
+ F10 15.96 14.23 4.62
+ F11 54.03 50.45 2.31
+ F12 23.38 24.4 20.86
+ F13 4.42 5.8 1.14
+ F14 17.42 25.87 5.81
+ F15 1.8 3.63 3.4
+ F16 12.33 9.08 3.65
+ G1 41.01 28.98 32.18
+ G2 14.7 24.18 31.92
+ G3 4.63 5.68 19.04
+ G4 73.8 76.63 58.3
+ G5 25.16 11.63 27.13
+ G6 23.64 27.52 5.74
+ G7 40.74 42.65 24.74
+ G8 5.04 6.8 4
+ G9 15.6 21.51 42.53
+ G10 47.5 50.89 46.6
+ G11 11.95 13.23 12.63
+ G12 0.74 0.68 2.21
+ G13 20.56 17.42 28.91
+ G14 3.34 3.61 2.24
+ G15 15.88 7.93 12.58
+ G16 32.76 42.79 24.95
+ H1 1.99 1.85 1.96
+ H2 5.23 4.73 13.17
+ H3 35.1 45.5 39.54
+ H4 15.44 16.22 14.02
+ H5 18.85 19.72 16.96
+ H6 19.88 10.01 3.06
+ H7 12.31 8.36 31.05
+ H8 37.11 33.66 35.77
+ H9 31.4 29.01 12.25
+ H10 5.92 7.65 8.81
+ H11 65.82 68.12 58.73
+ H12 15.16 18.34 19.38
+ H13 14.99 12.73 1.65
+ H14 56.71 60.58 54.75
+ H15 9.34 13.22 17.86
+ H16 14.91 7.72 6.98
+ I1 25.37 20.12 10.52
+ I2 49.34 51.3 44.11
+ I3 6.63 6.47 6.58
+ I4 1.07 0.94 1.24
+ I5 8.34 4.69 0.92
+ I6 23.16 18.65 41.02
+ I7 6.72 10.56 4.53
+ I8 27.97 23.98 1.71
+ I9 3.27 1.46 15.75
+ I10 55.74 51.88 24.53
+ I11 7.7 11.77 9.88
+ I12 1.57 1.7 1.49
+ I13 28.92 28.09 47.66
+ I14 28.27 17.22 9.16
+ I15 72.13 75.17 50.99
+ I16 3.58 5.09 12.93
+ J1 13.14 15.8 38.03
+ J2 9.81 17.93 5.25
+ J3 68.6 65.82 63.75
+ J4 43.83 30.19 45.87
+ J5 18.39 8.6 26.07
+ J6 5.36 10.17 15.84
+ J7 55.67 57.15 61.71
+ J8 17.35 19.86 30.55
+ J9 9.34 5.12 6.56
+ J10 4.06 4.65 4.46
+ J11 59.67 55.56 40.66
+ J12 49.63 49.42 45.4
+ J13 41.62 45.81 6.35
+ J14 4.44 4.57 7.21
+ J15 12.73 12.57 11.83
+ J16 33.9 31.33 21.78
+ K1 39.02 40.41 2.14
+ K2 6.59 5.47 20
+ K3 11 14.42 27.43
+ K4 1.86 2.4 6.45
+ K5 18.68 28.5 12.59
+ K6 75.76 78.23 67.4
+ K7 7.32 7.87 5.36
+ K8 18.49 18.14 1.64
+ K9 37.54 38.95 13.07
+ K10 55.35 62.8 63.8
+ K11 8.76 9.83 9.34
+ K12 8.38 8.86 7.56
+ K13 21.69 14.04 16.27
+ K14 16.19 22.43 2.19
+ K15 62.66 63.7 14.84
+ K16 7.22 13.33 24.18
+ L1 4.75 2.89 2.62
+ L2 38.93 48.68 58.9
+ L3 65.92 71 57.4
+ L4 66.52 69 26.91
+ L5 15.55 13.99 36.92
+ L6 17.18 15.48 10.42
+ L7 51.65 59.75 43.16
+ L8 18.25 11.8 33.47
+ L9 3.47 3.71 3.23
+ L10 12.9 9.35 8.48
+ L11 64.65 59.55 61.46
+ L12 45.13 38.69 1.96
+ L13 6.43 10.92 22.75
+ L14 21.35 21.35 19.83
+ L15 33.05 24.65 43.94
+ L16 22.66 23.84 17.58
+ M1 65.11 63.01 48.58
+ M2 1.94 1.46 0.65
+ M3 22.58 16.86 1.28
+ M4 10.28 5.41 11.55
+ M5 11.02 20.07 11.6
+ M6 59.78 59.84 54.76
+ M7 2.71 4.6 7.83
+ M8 23.91 34.53 36.93
+ M9 30.27 18.26 16.91
+ M10 26.5 36.45 52.65
+ M11 13.33 16.63 10.94
+ M12 4.04 8.83 9.08
+ M13 5.17 5.59 5.05
+ M14 3.61 9.2 4.51
+ M15 10.14 10.8 7.78
+ M16 3.13 3.26 0.84
+ N1 3.29 6.6 8.25
+ N2 4.65 10.78 9.31
+ N3 30.72 33.49 30.48
+ N4 10.72 12.58 1.45
+ N5 10.17 7.54 21.82
+ N6 11.18 18 19.3
+ N7 53.3 49.34 13.79
+ N8 7.14 6.18 3.7
+ N9 7.18 8.54 15.43
+ N10 10.26 10.86 9.44
+ N11 64.17 66.15 63.94
+ N12 29.82 22.94 30.75
+ N13 41.27 41.14 38.01
+ N14 13.72 13.09 26.73
+ N15 67.54 72.16 65.85
+ N16 59.57 51.66 57.98
+ O1 13.5 7.07 0.76
+ O2 49.21 44.05 5.87
+ O3 18.71 12.3 3.74
+ O4 38.42 41.38 37.84
+ O5 14.29 19.83 5.34
+ O6 38.12 27.36 19.84
+ O7 0.82 1.5 0.8
+ O8 58.19 65.09 49.46
+ O9 22.03 24.06 1.89
+ O10 54.38 44.04 54.64
+ O11 17.33 18.31 13.39
+ O12 3.07 2.92 2.94
+ O13 8.57 8.65 1.33
+ O14 2.04 4.54 1.45
+ O15 5.58 2.53 20.51
+ O16 9.55 10.01 4.38
+ P1 27.28 32.46 22.7
+ P2 1.26 0.88 4.93
+ P3 33.17 37.11 53.34
+ P4 8.31 3.84 22.57
+ P5 0.65 0.9 1.06
+ P6 3.58 1.97 10.4
+ P7 17.53 26.57 45.79
+ P8 38.54 30.11 1.74
+ P9 70.01 70.01 56.41
+ P10 45.98 54.96 61.34
+ P11 5.76 6.4 24.4
+ P12 27.4 28.95 21.64
+ P13 8.91 9.56 24.29
+ P14 14.32 10.16 15.55
+ P15 44.13 50.38 14.14
+ P16 25.91 15.77 35.63
+ Q1 7.89 5.75 27.26
+ Q2 19.45 21.15 43.11
+ Q3 2.18 1.59 2.48
+ Q4 2.47 2.57 2.36
+ Q5 71.98 71.6 65.38
+ Q6 25.4 27.72 25.57
+ Q7 46.78 38.92 22.52
+ Q8 30.85 35.91 37
+ Q9 9.11 15.52 1.94
+ Q10 11.65 11.86 16.65
+ Q11 20.6 21.96 11.36
+ Q12 2.49 6.09 1.38
+ Q13 43.66 45.37 39.11
+ Q14 56.73 58.92 50.71
+ Q15 13.37 14.14 10.18
+ Q16 25.67 30.42 12.63
+ R1 11.96 14.98 5.06
+ R2 25.55 30.36 2.16
+ R3 20.96 31.53 22.46
+ R4 26.63 16.16 3.75
+ R5 15.45 17.15 15.99
+ R6 2.87 1.83 5.87
+ R7 5.94 8.9 1.32
+ R8 22.2 10.8 12.85
+ R9 32.45 19.2 26.87
+ R10 31.17 21.44 1.48
+ R11 4.71 2.36 15.65
+ R12 16.81 16.68 15.67
+ R13 33.39 31.69 1.87
+ R14 6.67 5.46 0.93
+ R15 23.87 29.65 49.1
+ R16 5.1 5.43 3.45
+
+
diff --git a/ref/i1_RGB_Scan_1.4.ti2 b/ref/i1_RGB_Scan_1.4.ti2
new file mode 100644
index 0000000..8aaf081
--- /dev/null
+++ b/ref/i1_RGB_Scan_1.4.ti2
@@ -0,0 +1,319 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2 for Eye-One Scan Target 1.4"
+ORIGINATOR "Argyll printtarg"
+CREATED "Wed Sep 12 00:02:26 2007"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth i1 Pro"
+KEYWORD "ACCURATE_EXPECTED_VALUES"
+ACCURATE_EXPECTED_VALUES "true"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "18"
+KEYWORD "PASSES_IN_STRIPS2"
+PASSES_IN_STRIPS2 "16"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "A-Z, A-Z"
+KEYWORD "INDEX_ORDER"
+INDEX_ORDER "PATCH_THEN_STRIP"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 288
+BEGIN_DATA
+1 "A1" 0 0 0 0.52 0.59 0.56
+2 "A2" 20 40 100 10.27 10 32.62
+3 "A3" 80 0 20 13.89 7.3 2.84
+4 "A4" 100 40 20 33.34 23.69 4.75
+5 "A5" 69.8 69.8 69.8 31.79 33.22 28.61
+6 "A6" 46.67 46.67 46.67 13.85 14.51 12.72
+7 "A7" 100 40 40 35.52 25.53 10.91
+8 "A8" 66.67 60 66.67 27.16 27.04 25.26
+9 "A9" 29.8 29.8 29.8 6.12 6.42 5.76
+10 "A10" 26.67 33.33 33.33 6.04 6.8 6.75
+11 "A11" 0 20 100 4.4 3.47 20.55
+12 "A12" 40 0 60 6.34 3.41 11.34
+13 "A13" 40 20 60 9.03 7.05 14.88
+14 "A14" 40 20 40 7.91 6.52 8.41
+15 "A15" 60 20 80 16.18 10.77 24.37
+16 "A16" 0 0 60 1.97 1.1 8.66
+17 "B1" 60 100 20 27.55 34.83 6.23
+18 "B2" 80 20 0 17.94 11.4 1.02
+19 "B3" 80 80 20 34.87 35.19 5.79
+20 "B4" 20 80 80 13.05 19.54 29.87
+21 "B5" 0 60 100 6.88 9.15 27.74
+22 "B6" 100 100 80 70.59 73.69 44.02
+23 "B7" 13.33 13.33 6.67 2.04 2.19 1.41
+24 "B8" 0 40 0 1.35 2.84 0.94
+25 "B9" 100 60 80 49.51 40.62 36.32
+26 "B10" 100 60 40 43.26 35.61 12.01
+27 "B11" 13.33 20 20 2.65 3.13 3.25
+28 "B12" 40 80 60 17.77 24.45 21.08
+29 "B13" 0 100 100 8.51 14.13 31.85
+30 "B14" 0 80 100 7.84 11.93 30.12
+31 "B15" 0 100 60 5.81 12.04 16.38
+32 "B16" 60 20 0 11.49 8.06 0.99
+33 "C1" 100 20 100 34.5 19.81 37.1
+34 "C2" 80 80 73.33 42.27 43.99 33.47
+35 "C3" 0 60 60 4.36 7.54 14.12
+36 "C4" 100 100 20 58.73 57.76 6.5
+37 "C5" 60 0 80 11.22 5.5 17.82
+38 "C6" 6.67 13.33 13.33 1.55 1.89 2.09
+39 "C7" 74.9 74.9 74.9 37.5 39.03 33.61
+40 "C8" 80 40 20 23.67 18.54 4.44
+41 "C9" 20 80 20 8.12 14.07 4.81
+42 "C10" 0 100 0 2.9 7.38 1.41
+43 "C11" 73.33 73.33 66.67 34.09 35.82 26.91
+44 "C12" 40 33.33 40 9.45 9.34 9.05
+45 "C13" 100 60 20 41.11 33.34 5.29
+46 "C14" 80 40 60 27.38 21.65 19.2
+47 "C15" 64.71 64.71 64.71 27.38 28.66 24.61
+48 "C16" 80 80 100 48.58 49.16 58.53
+49 "D1" 20 80 0 7.47 12.02 1.86
+50 "D2" 80 0 80 17.27 8.47 18.91
+51 "D3" 100 20 0 24.86 14.78 0.99
+52 "D4" 60 0 20 8.61 4.81 2.74
+53 "D5" 80 60 20 28.85 26.03 5.07
+54 "D6" 40 80 80 20.34 26.75 33.64
+55 "D7" 40 0 40 5.39 3.09 6.34
+56 "D8" 40 0 80 7.42 3.7 17.12
+57 "D9" 86.67 100 100 60.57 66.88 64.61
+58 "D10" 26.67 20 26.67 4.42 4.33 4.38
+59 "D11" 0 20 60 2.63 2.73 10.91
+60 "D12" 80 100 60 46.48 54.19 25.5
+61 "D13" 0 20 20 1.24 2.02 2.92
+62 "D14" 0 60 20 2.43 5.58 3.81
+63 "D15" 40 0 0 4.46 2.69 0.72
+64 "D16" 100 0 80 23.58 11.3 19.67
+65 "E1" 60 40 60 18.33 16.26 18.07
+66 "E2" 40 80 0 13.25 17.2 1.73
+67 "E3" 40 80 40 16.1 22.52 11.75
+68 "E4" 86.67 86.67 80 50.7 52.96 40.49
+69 "E5" 4.71 4.71 4.71 0.93 1.03 0.98
+70 "E6" 0 0 80 2.58 1.28 12.24
+71 "E7" 93.33 93.33 86.67 61.11 63.67 49.46
+72 "E8" 20 80 40 9.69 16.36 11.19
+73 "E9" 60 60 20 19.64 20.4 5.14
+74 "E10" 100 100 69.8 68.63 71.55 34.47
+75 "E11" 73.33 66.67 73.33 33.86 33.75 30.83
+76 "E12" 100 0 0 18.65 9.44 0.83
+77 "E13" 20 100 60 12.88 22.5 20.49
+78 "E14" 80 60 100 40.57 35.97 51.8
+79 "E15" 60 60 80 25.89 26.22 33.39
+80 "E16" 60 100 40 30.29 39.21 13.78
+81 "F1" 0 80 20 3.2 7.65 4.38
+82 "F2" 0 20 80 3.71 3.35 16.24
+83 "F3" 80 20 80 23.31 14.61 25.55
+84 "F4" 80 20 40 20.14 13.3 9.05
+85 "F5" 53.33 60 60 19.65 21.55 20.22
+86 "F6" 6.67 6.67 0 1.21 1.33 0.75
+87 "F7" 0 60 80 5.8 8.65 21.51
+88 "F8" 100 0 40 20.82 10.37 7.25
+89 "F9" 60 0 100 12.98 6.05 24.77
+90 "F10" 60 40 20 15.96 14.23 4.62
+91 "F11" 100 100 0 54.03 50.45 2.31
+92 "F12" 60 60 60 23.38 24.4 20.86
+93 "F13" 20 40 0 4.42 5.8 1.14
+94 "F14" 40 100 20 17.42 25.87 5.81
+95 "F15" 0 40 20 1.8 3.63 3.4
+96 "F16" 60 20 20 12.33 9.08 3.65
+97 "G1" 100 40 80 41.01 28.98 32.18
+98 "G2" 20 100 80 14.7 24.18 31.92
+99 "G3" 0 40 80 4.63 5.68 19.04
+100 "G4" 100 100 93.33 73.8 76.63 58.3
+101 "G5" 100 0 100 25.16 11.63 27.13
+102 "G6" 60 80 20 23.64 27.52 5.74
+103 "G7" 80 80 60 40.74 42.65 24.74
+104 "G8" 20 40 20 5.04 6.8 4
+105 "G9" 20 80 100 15.6 21.51 42.53
+106 "G10" 80 86.67 86.67 47.5 50.89 46.6
+107 "G11" 40 46.67 46.67 11.95 13.23 12.63
+108 "G12" 0 0 20 0.74 0.68 2.21
+109 "G13" 60 40 80 20.56 17.42 28.91
+110 "G14" 20 20 13.33 3.34 3.61 2.24
+111 "G15" 80 0 60 15.88 7.93 12.58
+112 "G16" 60 100 60 32.76 42.79 24.95
+113 "H1" 13.33 6.67 13.33 1.99 1.85 1.96
+114 "H2" 20 20 60 5.23 4.73 13.17
+115 "H3" 60 100 80 35.1 45.5 39.54
+116 "H4" 49.8 49.8 49.8 15.44 16.22 14.02
+117 "H5" 54.9 54.9 54.9 18.85 19.72 16.96
+118 "H6" 100 0 20 19.88 10.01 3.06
+119 "H7" 40 20 100 12.31 8.36 31.05
+120 "H8" 80 60 80 37.11 33.66 35.77
+121 "H9" 80 60 40 31.4 29.01 12.25
+122 "H10" 20 40 40 5.92 7.65 8.81
+123 "H11" 94.9 94.9 94.9 65.82 68.12 58.73
+124 "H12" 40 60 60 15.16 18.34 19.38
+125 "H13" 60 40 0 14.99 12.73 1.65
+126 "H14" 86.67 93.33 93.33 56.71 60.58 54.75
+127 "H15" 20 60 60 9.34 13.22 17.86
+128 "H16" 80 0 40 14.91 7.72 6.98
+129 "I1" 80 40 40 25.37 20.12 10.52
+130 "I2" 84.71 84.71 84.71 49.34 51.3 44.11
+131 "I3" 33.33 26.67 33.33 6.63 6.47 6.58
+132 "I4" 6.67 0 6.67 1.07 0.94 1.24
+133 "I5" 60 0 0 8.34 4.69 0.92
+134 "I6" 60 40 100 23.16 18.65 41.02
+135 "I7" 20 60 20 6.72 10.56 4.53
+136 "I8" 80 60 0 27.97 23.98 1.71
+137 "I9" 0 0 100 3.27 1.46 15.75
+138 "I10" 100 80 60 55.74 51.88 24.53
+139 "I11" 20 60 40 7.7 11.77 9.88
+140 "I12" 9.8 9.8 9.8 1.57 1.7 1.49
+141 "I13" 60 60 100 28.92 28.09 47.66
+142 "I14" 100 20 40 28.27 17.22 9.16
+143 "I15" 100 100 86.67 72.13 75.17 50.99
+144 "I16" 0 40 60 3.58 5.09 12.93
+145 "J1" 20 60 100 13.14 15.8 38.03
+146 "J2" 20 100 20 9.81 17.93 5.25
+147 "J3" 100 86.67 100 68.6 65.82 63.75
+148 "J4" 100 40 100 43.83 30.19 45.87
+149 "J5" 80 0 100 18.39 8.6 26.07
+150 "J6" 0 80 60 5.36 10.17 15.84
+151 "J7" 86.67 86.67 100 55.67 57.15 61.71
+152 "J8" 40 60 80 17.35 19.86 30.55
+153 "J9" 60 0 40 9.34 5.12 6.56
+154 "J10" 20 26.67 26.67 4.06 4.65 4.46
+155 "J11" 100 80 80 59.67 55.56 40.66
+156 "J12" 86.67 80 86.67 49.63 49.42 45.4
+157 "J13" 80 100 20 41.62 45.81 6.35
+158 "J14" 20 20 40 4.44 4.57 7.21
+159 "J15" 46.67 40 46.67 12.73 12.57 11.83
+160 "J16" 80 60 60 33.9 31.33 21.78
+161 "K1" 80 100 0 39.02 40.41 2.14
+162 "K2" 20 20 80 6.59 5.47 20
+163 "K3" 20 60 80 11 14.42 27.43
+164 "K4" 0 20 40 1.86 2.4 6.45
+165 "K5" 40 100 40 18.68 28.5 12.59
+166 "K6" 100 100 100 75.76 78.23 67.4
+167 "K7" 33.33 33.33 26.67 7.32 7.87 5.36
+168 "K8" 60 60 0 18.49 18.14 1.64
+169 "K9" 80 80 40 37.54 38.95 13.07
+170 "K10" 80 100 100 55.35 62.8 63.8
+171 "K11" 33.33 40 40 8.76 9.83 9.34
+172 "K12" 34.9 34.9 34.9 8.38 8.86 7.56
+173 "K13" 80 20 60 21.69 14.04 16.27
+174 "K14" 40 100 0 16.19 22.43 2.19
+175 "K15" 100 100 40 62.66 63.7 14.84
+176 "K16" 0 100 80 7.22 13.33 24.18
+177 "L1" 40 0 20 4.75 2.89 2.62
+178 "L2" 60 100 100 38.93 48.68 58.9
+179 "L3" 93.33 100 93.33 65.92 71 57.4
+180 "L4" 100 100 60 66.52 69 26.91
+181 "L5" 40 40 100 15.55 13.99 36.92
+182 "L6" 60 40 40 17.18 15.48 10.42
+183 "L7" 80 100 80 51.65 59.75 43.16
+184 "L8" 60 20 100 18.25 11.8 33.47
+185 "L9" 20 20 20 3.47 3.71 3.23
+186 "L10" 60 20 40 12.9 9.35 8.48
+187 "L11" 100 80 100 64.65 59.55 61.46
+188 "L12" 100 80 0 45.13 38.69 1.96
+189 "L13" 0 80 80 6.43 10.92 22.75
+190 "L14" 60 53.33 60 21.35 21.35 19.83
+191 "L15" 80 40 100 33.05 24.65 43.94
+192 "L16" 60 60 53.33 22.66 23.84 17.58
+193 "M1" 100 86.67 86.67 65.11 63.01 48.58
+194 "M2" 20 0 0 1.94 1.46 0.65
+195 "M3" 80 40 0 22.58 16.86 1.28
+196 "M4" 60 0 60 10.28 5.41 11.55
+197 "M5" 20 100 40 11.02 20.07 11.6
+198 "M6" 93.33 86.67 93.33 59.78 59.84 54.76
+199 "M7" 0 40 40 2.71 4.6 7.83
+200 "M8" 40 100 80 23.91 34.53 36.93
+201 "M9" 100 20 60 30.27 18.26 16.91
+202 "M10" 40 100 100 26.5 36.45 52.65
+203 "M11" 40 60 40 13.33 16.63 10.94
+204 "M12" 0 80 40 4.04 8.83 9.08
+205 "M13" 26.67 26.67 26.67 5.17 5.59 5.05
+206 "M14" 0 100 20 3.61 9.2 4.51
+207 "M15" 40 40 33.33 10.14 10.8 7.78
+208 "M16" 20 20 0 3.13 3.26 0.84
+209 "N1" 0 60 40 3.29 6.6 8.25
+210 "N2" 0 100 40 4.65 10.78 9.31
+211 "N3" 66.67 73.33 73.33 30.72 33.49 30.48
+212 "N4" 40 60 0 10.72 12.58 1.45
+213 "N5" 40 20 80 10.17 7.54 21.82
+214 "N6" 20 80 60 11.18 18 19.3
+215 "N7" 100 80 40 53.3 49.34 13.79
+216 "N8" 40 20 20 7.14 6.18 3.7
+217 "N9" 20 40 60 7.18 8.54 15.43
+218 "N10" 40 40 40 10.26 10.86 9.44
+219 "N11" 93.33 93.33 100 64.17 66.15 63.94
+220 "N12" 80 40 80 29.82 22.94 30.75
+221 "N13" 80 73.33 80 41.27 41.14 38.01
+222 "N14" 40 40 80 13.72 13.09 26.73
+223 "N15" 93.33 100 100 67.54 72.16 65.85
+224 "N16" 100 69.8 100 59.57 51.66 57.98
+225 "O1" 80 0 0 13.5 7.07 0.76
+226 "O2" 100 80 20 49.21 44.05 5.87
+227 "O3" 80 20 20 18.71 12.3 3.74
+228 "O4" 73.33 80 80 38.42 41.38 37.84
+229 "O5" 40 80 20 14.29 19.83 5.34
+230 "O6" 100 40 60 38.12 27.36 19.84
+231 "O7" 0 20 0 0.82 1.5 0.8
+232 "O8" 86.67 100 86.67 58.19 65.09 49.46
+233 "O9" 60 80 0 22.03 24.06 1.89
+234 "O10" 100 60 100 54.38 44.04 54.64
+235 "O11" 53.33 53.33 46.67 17.33 18.31 13.39
+236 "O12" 20 13.33 20 3.07 2.92 2.94
+237 "O13" 40 40 0 8.57 8.65 1.33
+238 "O14" 0 60 0 2.04 4.54 1.45
+239 "O15" 20 0 100 5.58 2.53 20.51
+240 "O16" 40 40 20 9.55 10.01 4.38
+241 "P1" 60 80 60 27.28 32.46 22.7
+242 "P2" 0 0 40 1.26 0.88 4.93
+243 "P3" 60 80 100 33.17 37.11 53.34
+244 "P4" 40 0 100 8.31 3.84 22.57
+245 "P5" 0 6.67 6.67 0.65 0.9 1.06
+246 "P6" 20 0 60 3.58 1.97 10.4
+247 "P7" 20 100 100 17.53 26.57 45.79
+248 "P8" 100 60 0 38.54 30.11 1.74
+249 "P9" 100 93.33 93.33 70.01 70.01 56.41
+250 "P10" 69.8 100 100 45.98 54.96 61.34
+251 "P11" 0 40 100 5.76 6.4 24.4
+252 "P12" 66.67 66.67 60 27.4 28.95 21.64
+253 "P13" 20 40 80 8.91 9.56 24.29
+254 "P14" 60 20 60 14.32 10.16 15.55
+255 "P15" 80 100 40 44.13 50.38 14.14
+256 "P16" 80 20 100 25.91 15.77 35.63
+257 "Q1" 20 20 100 7.89 5.75 27.26
+258 "Q2" 40 60 100 19.45 21.15 43.11
+259 "Q3" 20 0 20 2.18 1.59 2.48
+260 "Q4" 14.9 14.9 14.9 2.47 2.57 2.36
+261 "Q5" 100 93.33 100 71.98 71.6 65.38
+262 "Q6" 60 66.67 66.67 25.4 27.72 25.57
+263 "Q7" 100 60 60 46.78 38.92 22.52
+264 "Q8" 60 80 80 30.85 35.91 37
+265 "Q9" 20 100 0 9.11 15.52 1.94
+266 "Q10" 40 40 60 11.65 11.86 16.65
+267 "Q11" 60 60 40 20.6 21.96 11.36
+268 "Q12" 0 80 0 2.49 6.09 1.38
+269 "Q13" 80 80 80 43.66 45.37 39.11
+270 "Q14" 89.8 89.8 89.8 56.73 58.92 50.71
+271 "Q15" 46.67 46.67 40 13.37 14.14 10.18
+272 "Q16" 60 80 40 25.67 30.42 12.63
+273 "R1" 40 60 20 11.96 14.98 5.06
+274 "R2" 60 100 0 25.55 30.36 2.16
+275 "R3" 40 100 60 20.96 31.53 22.46
+276 "R4" 100 20 20 26.63 16.16 3.75
+277 "R5" 46.67 53.33 53.33 15.45 17.15 15.99
+278 "R6" 20 0 40 2.87 1.83 5.87
+279 "R7" 20 60 0 5.94 8.9 1.32
+280 "R8" 100 0 60 22.2 10.8 12.85
+281 "R9" 100 20 80 32.45 19.2 26.87
+282 "R10" 100 40 0 31.17 21.44 1.48
+283 "R11" 20 0 80 4.71 2.36 15.65
+284 "R12" 53.33 46.67 53.33 16.81 16.68 15.67
+285 "R13" 80 80 0 33.39 31.69 1.87
+286 "R14" 40 20 0 6.67 5.46 0.93
+287 "R15" 40 80 100 23.87 29.65 49.1
+288 "R16" 26.67 26.67 20 5.1 5.43 3.45
+END_DATA
diff --git a/ref/it8.cht b/ref/it8.cht
new file mode 100644
index 0000000..f1e256d
--- /dev/null
+++ b/ref/it8.cht
@@ -0,0 +1,338 @@
+
+
+BOXES 290
+ F _ _ 1 1 616.0 1.5 615.5 358 1 358.5
+ D ALL ALL _ _ 615 409 1 1 0 0
+ D MARK MARK _ _ 14 14 1 1 0 0
+ Y 01 22 A L 25.625 25.625 26.625 26.625 25.625 25.625
+ X GS00 GS23 _ _ 25.625 51.25 0.0 358.75 25.625 0.0
+
+BOX_SHRINK 3.2
+
+REF_ROTATION -0.002006
+
+XLIST 32
+ 1.799625 1.000000 0.312500
+ 27.064987 0.874039 0.750000
+ 52.592403 0.133439 0.687500
+ 78.196610 0.264191 0.687500
+ 104.117756 0.165427 0.937500
+ 129.377994 0.844432 0.937500
+ 155.144274 0.501218 0.875000
+ 180.839181 0.491428 0.937500
+ 206.359758 0.212384 0.937500
+ 232.038808 0.851851 0.937500
+ 257.854725 0.162956 0.625000
+ 283.552463 0.101243 0.812500
+ 300.534000 0.024750 0.812500
+ 309.507688 0.093829 1.000000
+ 334.711314 0.856821 1.000000
+ 360.428194 0.787677 1.000000
+ 385.849730 0.748130 0.937500
+ 386.650071 0.039487 0.687500
+ 394.630372 0.024725 0.687500
+ 411.835654 0.802501 0.750000
+ 414.017731 0.041974 0.937500
+ 437.133504 0.674062 0.937500
+ 437.975355 0.103714 1.000000
+ 462.938460 0.671643 1.000000
+ 463.880560 0.093836 0.937500
+ 488.517995 0.679022 1.000000
+ 514.338544 0.760511 1.000000
+ 540.037492 0.111108 0.625000
+ 565.856396 0.133330 0.562500
+ 591.114717 0.565475 0.562500
+ 603.447516 0.032097 0.312500
+ 615.984915 0.829608 0.250000
+
+YLIST 22
+ 2.477956 0.993407 0.142857
+ 12.988903 0.016393 0.190476
+ 14.739109 0.036082 0.190476
+ 26.746171 0.911487 0.428571
+ 52.537114 0.303282 0.904762
+ 78.060317 0.585303 0.857143
+ 103.498271 0.606862 0.761905
+ 128.994535 0.567266 0.761905
+ 154.483041 0.550814 0.714286
+ 179.935985 0.623055 0.666667
+ 205.552940 0.350826 0.714286
+ 212.051372 0.016393 0.714286
+ 231.153547 0.824618 0.857143
+ 256.697418 0.744268 0.952381
+ 282.145841 0.736126 0.904762
+ 307.899015 0.536075 0.952381
+ 333.262903 0.903282 0.809524
+ 340.217754 0.019722 0.190476
+ 344.988867 0.019671 0.095238
+ 346.988885 0.018032 0.095238
+ 358.840278 0.999967 1.000000
+ 409.201393 1.000000 0.000000
+
+EXPECTED XYZ 264
+ A01 3.85 3.22 1.9
+ A02 4.89 3.27 1.6
+ A03 5.87 3.31 1.33
+ A04 6.3 3.38 1.19
+ A05 13.01 11.44 7.64
+ A06 16.14 11.99 6.81
+ A07 19.35 12.41 6.06
+ A08 20.41 11.97 5.3
+ A09 43.5 42.81 32.65
+ A10 45.58 42.37 30.95
+ A11 48.99 43.2 29.9
+ A12 50.73 44.02 29.96
+ A13 74.46 78.76 66.06
+ A14 75.66 76.42 64.08
+ A15 78.36 81.34 65.41
+ A16 70.52 73.3 59.16
+ A17 74.98 75.98 60.69
+ A18 72.85 77.3 60.25
+ A19 73.09 75.52 64.54
+ B01 3.47 3.08 1.41
+ B02 4.41 3.25 0.9
+ B03 5.04 3.23 0.58
+ B04 5.19 3.11 0.47
+ B05 13.36 11.59 5.56
+ B06 15.97 12.03 3.69
+ B07 19.2 12.49 2.2
+ B08 19.73 11.52 1.17
+ B09 42.19 41.84 29.34
+ B10 44.83 42.17 25.93
+ B11 48.06 42.9 23.01
+ B12 49.63 43.08 21.34
+ B13 66.21 72.54 64.61
+ B14 70.16 67.1 60.33
+ B15 75.46 78.69 51.58
+ B16 57.47 59.58 47.66
+ B17 68.33 66.45 49.05
+ B18 63.89 70.29 51.3
+ B19 61.12 62.16 59.79
+ C01 4.97 4.75 1.98
+ C02 5.18 4.65 1.23
+ C03 5.51 4.58 0.71
+ C04 5.77 4.61 0.67
+ C05 24.57 23.44 10.14
+ C06 28.1 24.64 5.22
+ C07 31.15 25.28 2.2
+ C08 30.85 23.68 1.35
+ C09 49.16 49.36 32.37
+ C10 51.72 50.72 26.53
+ C11 55.24 53.14 21.93
+ C12 56.87 53.62 18.46
+ C13 57.68 65.65 62.7
+ C14 63.46 56.66 55.49
+ C15 73 76.11 40.78
+ C16 44.73 46.38 36.8
+ C17 60.64 55.73 38.1
+ C18 52.15 60.27 41.5
+ C19 48.13 49.18 54.38
+ D01 4.19 4.41 1.93
+ D02 4.48 4.72 1.24
+ D03 4.55 4.78 0.8
+ D04 4.32 4.53 0.78
+ D05 27.33 28.55 12.95
+ D06 28.68 30.04 7.25
+ D07 29.51 31.01 3.41
+ D08 27.55 28.44 1.83
+ D09 56.06 58.19 38.21
+ D10 56.03 58.46 30.02
+ D11 56.2 59.33 24.44
+ D12 56.19 59.41 19.14
+ D13 48.21 57.42 59.53
+ D14 58.18 49.14 51.36
+ D15 70.98 73.73 33.63
+ D16 34.31 35.73 28.22
+ D17 54.27 47.53 29.58
+ D18 41.67 50.64 32.28
+ D19 36.95 37.82 48.09
+ E01 4.15 4.75 2.03
+ E02 4 4.98 1.37
+ E03 3.3 4.49 0.86
+ E04 3.11 4.3 0.86
+ E05 13.11 14.9 7.06
+ E06 12.26 15.23 4.18
+ E07 11.53 15.57 2.27
+ E08 9.69 13.74 1.51
+ E09 39.15 42.08 27.33
+ E10 37.43 41.51 22.23
+ E11 36.99 42.5 18.85
+ E12 36.4 42.58 16.27
+ E13 39.97 49.81 56.15
+ E14 52.08 41.07 46.36
+ E15 68.71 70.76 26.45
+ E16 25.7 26.97 21.28
+ E17 48.53 40.6 22
+ E18 31.62 40.82 23.35
+ E19 31.19 31.19 43.4
+ F01 1.51 1.91 1.06
+ F02 1.29 2.04 0.98
+ F03 1.16 2.09 0.82
+ F04 1.14 2.04 0.8
+ F05 6.53 8.25 5.13
+ F06 5.61 8.66 4.38
+ F07 4.6 8.77 3.7
+ F08 3.45 7.63 2.78
+ F09 37.8 41.07 30.91
+ F10 35.92 40.76 29.03
+ F11 35.42 41.99 29.07
+ F12 34 41.8 28
+ F13 32.13 42.12 51.99
+ F14 45.72 33.34 40.77
+ F15 66.26 67.29 19.65
+ F16 17.02 18.07 14.4
+ F17 41.59 32.53 15.16
+ F18 26.26 35.26 18.81
+ F19 24.3 23.6 37.48
+ G01 2.31 3 2.27
+ G02 2 3.21 2.58
+ G03 1.66 3.21 2.75
+ G04 1.58 3.03 2.6
+ G05 8.99 11.08 8.79
+ G06 7.68 11.3 9.56
+ G07 6.52 11.5 10.2
+ G08 5.5 10.85 10.55
+ G09 38.29 41.75 33.45
+ G10 35.83 41.16 34.11
+ G11 34.56 41.83 35.63
+ G12 33.69 42.14 36.7
+ G13 25.95 35.68 48
+ G14 40.6 27.62 36.14
+ G15 63.72 63.63 14.35
+ G16 10.85 11.82 9.58
+ G17 37.23 27.64 11.62
+ G18 20.28 28.97 14.15
+ G19 17.7 16.74 31.7
+ H01 2.56 3.04 2.92
+ H02 2.34 3.2 4.12
+ H03 2.12 3.28 5.43
+ H04 2.06 3.18 5.29
+ H05 10.07 11.6 11.24
+ H06 9.01 11.68 14.81
+ H07 8.22 12 19.42
+ H08 7.25 11.55 21.45
+ H09 39.25 42.31 36.81
+ H10 37.58 41.85 40.37
+ H11 37.16 43.07 45.79
+ H12 36.27 43.78 49.47
+ H13 21.47 30.78 44.22
+ H14 36.49 23.35 32.38
+ H15 61.58 60.55 10.95
+ H16 8.21 8.71 6.91
+ H17 33.04 23.26 8.38
+ H18 16.22 24.35 10.41
+ H19 12.86 11.84 26.82
+ I01 4.22 4.44 5.28
+ I02 4.35 4.48 8.36
+ I03 4.4 4.44 11.94
+ I04 4.48 4.58 12.17
+ I05 15.15 15.78 15.23
+ I06 14.56 15.12 19.52
+ I07 14.37 14.81 24.48
+ I08 14.11 14.76 30.03
+ I09 41.03 42.58 36.94
+ I10 40.85 42.23 40.73
+ I11 40.86 42.33 45.05
+ I12 41.31 42.73 47.77
+ I13 17.26 25.93 40.23
+ I14 32.66 19.63 28.81
+ I15 59.37 57.18 7.79
+ I16 4.97 5.32 4.32
+ I17 28.62 18.88 5.48
+ I18 11.58 18.98 7.25
+ I19 9.58 8.34 22.87
+ I20 0.45 0.4 0.33
+ I21 2.28 1.78 0.98
+ I22 2.37 1.95 0.85
+ J01 2.15 1.9 2.6
+ J02 2.57 2 4.72
+ J03 2.93 1.95 8.1
+ J04 3.15 1.92 10.76
+ J05 11.73 11.6 11.81
+ J06 12.98 11.93 16.19
+ J07 13.91 12.07 20.95
+ J08 14.01 11.59 24.35
+ J09 40.75 41.22 36.34
+ J10 41.26 41.07 39.74
+ J11 42.63 41.68 44.51
+ J12 44.02 41.78 49.25
+ J13 13.82 21.69 35.98
+ J14 28.87 16.33 25.08
+ J15 56.04 52.29 4.97
+ J16 2.46 2.63 2.29
+ J17 24.04 14.75 3.15
+ J18 8.12 14.49 4.55
+ J19 5.98 4.79 17.76
+ J20 8.26 5.37 1.04
+ J21 11.52 7.81 1.62
+ J22 14.67 10.72 2.6
+ K01 5.63 4.7 4.86
+ K02 6.74 4.58 7.23
+ K03 8.04 4.48 9.73
+ K04 9.39 4.76 11.79
+ K05 16.66 15.39 14.44
+ K06 18.72 15.18 18.23
+ K07 21.56 15.5 22.97
+ K08 23 15.02 25.37
+ K09 42.5 42.02 36.05
+ K10 44.55 41.63 39.71
+ K11 47.19 41.96 44.03
+ K12 49.9 43.14 47.21
+ K13 10.61 17.44 31.24
+ K14 24.84 13.19 21
+ K15 53.12 48.05 3.19
+ K16 1.05 1.14 1.13
+ K17 19.93 11.34 1.67
+ K18 5.3 10.47 2.73
+ K19 3.95 2.76 13.94
+ K20 30.61 26.43 11.04
+ K21 34.91 29.6 11.78
+ K22 38.95 34.57 18.4
+ L01 3.88 3.12 2.32
+ L02 4.93 3.2 2.69
+ L03 5.75 3.14 3.02
+ L04 7.31 3.79 3.4
+ L05 13.29 11.54 9.39
+ L06 16.22 11.73 10.32
+ L07 19.95 12.08 12.06
+ L08 20.79 11.31 12.01
+ L09 43.22 42.09 33.78
+ L10 45.52 41.88 34.65
+ L11 49.04 42.87 35.98
+ L12 51.03 43.83 37.78
+ L13 7.45 12.77 25.59
+ L14 21.26 10.76 17.73
+ L15 49.45 43.12 2.14
+ L16 0.47 0.49 0.5
+ L17 16.04 8.49 0.78
+ L18 2.91 6.5 1.39
+ L19 2.5 1.45 10.28
+ L20 38.7 33.98 20.86
+ L21 39.36 35.23 21.23
+ L22 41.36 38.77 23.51
+ GS00 79.47 82.51 69.04
+ GS01 72.62 74.94 59.17
+ GS02 63.15 65.11 51.57
+ GS03 54.72 56.51 45.03
+ GS04 48.1 49.81 39.24
+ GS05 42.22 43.64 34.45
+ GS06 37.33 38.7 30.5
+ GS07 32.38 33.61 26.11
+ GS08 27.56 28.7 22.11
+ GS09 22.5 23.4 17.99
+ GS10 18.77 19.55 14.83
+ GS11 15.48 16.08 12.04
+ GS12 12.69 13.29 9.98
+ GS13 10.35 10.81 7.97
+ GS14 8.39 8.77 6.37
+ GS15 6.45 6.79 4.97
+ GS16 4.95 5.18 3.7
+ GS17 3.58 3.82 2.76
+ GS18 2.76 2.89 2.06
+ GS19 1.97 2.08 1.45
+ GS20 1.22 1.31 0.98
+ GS21 1 1.05 0.74
+ GS22 0.87 0.89 0.65
+ GS23 0.34 0.32 0.32
+
+
diff --git a/ref/lab2lab.icm b/ref/lab2lab.icm
new file mode 100644
index 0000000..fe518e6
--- /dev/null
+++ b/ref/lab2lab.icm
Binary files differ
diff --git a/ref/linear.cal b/ref/linear.cal
new file mode 100644
index 0000000..30da145
--- /dev/null
+++ b/ref/linear.cal
@@ -0,0 +1,275 @@
+CAL
+
+DESCRIPTOR "Argyll Device Calibration Curves"
+ORIGINATOR "Argyll synthcal"
+CREATED "Sat Mar 09 18:33:22 2013"
+KEYWORD "DEVICE_CLASS"
+DEVICE_CLASS "DISPLAY"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+
+KEYWORD "RGB_I"
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+RGB_I RGB_R RGB_G RGB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 256
+BEGIN_DATA
+0.0000 0.0000 0.0000 0.0000
+3.9216e-003 3.9216e-003 3.9216e-003 3.9216e-003
+7.8431e-003 7.8431e-003 7.8431e-003 7.8431e-003
+0.011765 0.011765 0.011765 0.011765
+0.015686 0.015686 0.015686 0.015686
+0.019608 0.019608 0.019608 0.019608
+0.023529 0.023529 0.023529 0.023529
+0.027451 0.027451 0.027451 0.027451
+0.031373 0.031373 0.031373 0.031373
+0.035294 0.035294 0.035294 0.035294
+0.039216 0.039216 0.039216 0.039216
+0.043137 0.043137 0.043137 0.043137
+0.047059 0.047059 0.047059 0.047059
+0.050980 0.050980 0.050980 0.050980
+0.054902 0.054902 0.054902 0.054902
+0.058824 0.058824 0.058824 0.058824
+0.062745 0.062745 0.062745 0.062745
+0.066667 0.066667 0.066667 0.066667
+0.070588 0.070588 0.070588 0.070588
+0.074510 0.074510 0.074510 0.074510
+0.078431 0.078431 0.078431 0.078431
+0.082353 0.082353 0.082353 0.082353
+0.086275 0.086275 0.086275 0.086275
+0.090196 0.090196 0.090196 0.090196
+0.094118 0.094118 0.094118 0.094118
+0.098039 0.098039 0.098039 0.098039
+0.10196 0.10196 0.10196 0.10196
+0.10588 0.10588 0.10588 0.10588
+0.10980 0.10980 0.10980 0.10980
+0.11373 0.11373 0.11373 0.11373
+0.11765 0.11765 0.11765 0.11765
+0.12157 0.12157 0.12157 0.12157
+0.12549 0.12549 0.12549 0.12549
+0.12941 0.12941 0.12941 0.12941
+0.13333 0.13333 0.13333 0.13333
+0.13725 0.13725 0.13725 0.13725
+0.14118 0.14118 0.14118 0.14118
+0.14510 0.14510 0.14510 0.14510
+0.14902 0.14902 0.14902 0.14902
+0.15294 0.15294 0.15294 0.15294
+0.15686 0.15686 0.15686 0.15686
+0.16078 0.16078 0.16078 0.16078
+0.16471 0.16471 0.16471 0.16471
+0.16863 0.16863 0.16863 0.16863
+0.17255 0.17255 0.17255 0.17255
+0.17647 0.17647 0.17647 0.17647
+0.18039 0.18039 0.18039 0.18039
+0.18431 0.18431 0.18431 0.18431
+0.18824 0.18824 0.18824 0.18824
+0.19216 0.19216 0.19216 0.19216
+0.19608 0.19608 0.19608 0.19608
+0.20000 0.20000 0.20000 0.20000
+0.20392 0.20392 0.20392 0.20392
+0.20784 0.20784 0.20784 0.20784
+0.21176 0.21176 0.21176 0.21176
+0.21569 0.21569 0.21569 0.21569
+0.21961 0.21961 0.21961 0.21961
+0.22353 0.22353 0.22353 0.22353
+0.22745 0.22745 0.22745 0.22745
+0.23137 0.23137 0.23137 0.23137
+0.23529 0.23529 0.23529 0.23529
+0.23922 0.23922 0.23922 0.23922
+0.24314 0.24314 0.24314 0.24314
+0.24706 0.24706 0.24706 0.24706
+0.25098 0.25098 0.25098 0.25098
+0.25490 0.25490 0.25490 0.25490
+0.25882 0.25882 0.25882 0.25882
+0.26275 0.26275 0.26275 0.26275
+0.26667 0.26667 0.26667 0.26667
+0.27059 0.27059 0.27059 0.27059
+0.27451 0.27451 0.27451 0.27451
+0.27843 0.27843 0.27843 0.27843
+0.28235 0.28235 0.28235 0.28235
+0.28627 0.28627 0.28627 0.28627
+0.29020 0.29020 0.29020 0.29020
+0.29412 0.29412 0.29412 0.29412
+0.29804 0.29804 0.29804 0.29804
+0.30196 0.30196 0.30196 0.30196
+0.30588 0.30588 0.30588 0.30588
+0.30980 0.30980 0.30980 0.30980
+0.31373 0.31373 0.31373 0.31373
+0.31765 0.31765 0.31765 0.31765
+0.32157 0.32157 0.32157 0.32157
+0.32549 0.32549 0.32549 0.32549
+0.32941 0.32941 0.32941 0.32941
+0.33333 0.33333 0.33333 0.33333
+0.33725 0.33725 0.33725 0.33725
+0.34118 0.34118 0.34118 0.34118
+0.34510 0.34510 0.34510 0.34510
+0.34902 0.34902 0.34902 0.34902
+0.35294 0.35294 0.35294 0.35294
+0.35686 0.35686 0.35686 0.35686
+0.36078 0.36078 0.36078 0.36078
+0.36471 0.36471 0.36471 0.36471
+0.36863 0.36863 0.36863 0.36863
+0.37255 0.37255 0.37255 0.37255
+0.37647 0.37647 0.37647 0.37647
+0.38039 0.38039 0.38039 0.38039
+0.38431 0.38431 0.38431 0.38431
+0.38824 0.38824 0.38824 0.38824
+0.39216 0.39216 0.39216 0.39216
+0.39608 0.39608 0.39608 0.39608
+0.40000 0.40000 0.40000 0.40000
+0.40392 0.40392 0.40392 0.40392
+0.40784 0.40784 0.40784 0.40784
+0.41176 0.41176 0.41176 0.41176
+0.41569 0.41569 0.41569 0.41569
+0.41961 0.41961 0.41961 0.41961
+0.42353 0.42353 0.42353 0.42353
+0.42745 0.42745 0.42745 0.42745
+0.43137 0.43137 0.43137 0.43137
+0.43529 0.43529 0.43529 0.43529
+0.43922 0.43922 0.43922 0.43922
+0.44314 0.44314 0.44314 0.44314
+0.44706 0.44706 0.44706 0.44706
+0.45098 0.45098 0.45098 0.45098
+0.45490 0.45490 0.45490 0.45490
+0.45882 0.45882 0.45882 0.45882
+0.46275 0.46275 0.46275 0.46275
+0.46667 0.46667 0.46667 0.46667
+0.47059 0.47059 0.47059 0.47059
+0.47451 0.47451 0.47451 0.47451
+0.47843 0.47843 0.47843 0.47843
+0.48235 0.48235 0.48235 0.48235
+0.48627 0.48627 0.48627 0.48627
+0.49020 0.49020 0.49020 0.49020
+0.49412 0.49412 0.49412 0.49412
+0.49804 0.49804 0.49804 0.49804
+0.50196 0.50196 0.50196 0.50196
+0.50588 0.50588 0.50588 0.50588
+0.50980 0.50980 0.50980 0.50980
+0.51373 0.51373 0.51373 0.51373
+0.51765 0.51765 0.51765 0.51765
+0.52157 0.52157 0.52157 0.52157
+0.52549 0.52549 0.52549 0.52549
+0.52941 0.52941 0.52941 0.52941
+0.53333 0.53333 0.53333 0.53333
+0.53725 0.53725 0.53725 0.53725
+0.54118 0.54118 0.54118 0.54118
+0.54510 0.54510 0.54510 0.54510
+0.54902 0.54902 0.54902 0.54902
+0.55294 0.55294 0.55294 0.55294
+0.55686 0.55686 0.55686 0.55686
+0.56078 0.56078 0.56078 0.56078
+0.56471 0.56471 0.56471 0.56471
+0.56863 0.56863 0.56863 0.56863
+0.57255 0.57255 0.57255 0.57255
+0.57647 0.57647 0.57647 0.57647
+0.58039 0.58039 0.58039 0.58039
+0.58431 0.58431 0.58431 0.58431
+0.58824 0.58824 0.58824 0.58824
+0.59216 0.59216 0.59216 0.59216
+0.59608 0.59608 0.59608 0.59608
+0.60000 0.60000 0.60000 0.60000
+0.60392 0.60392 0.60392 0.60392
+0.60784 0.60784 0.60784 0.60784
+0.61176 0.61176 0.61176 0.61176
+0.61569 0.61569 0.61569 0.61569
+0.61961 0.61961 0.61961 0.61961
+0.62353 0.62353 0.62353 0.62353
+0.62745 0.62745 0.62745 0.62745
+0.63137 0.63137 0.63137 0.63137
+0.63529 0.63529 0.63529 0.63529
+0.63922 0.63922 0.63922 0.63922
+0.64314 0.64314 0.64314 0.64314
+0.64706 0.64706 0.64706 0.64706
+0.65098 0.65098 0.65098 0.65098
+0.65490 0.65490 0.65490 0.65490
+0.65882 0.65882 0.65882 0.65882
+0.66275 0.66275 0.66275 0.66275
+0.66667 0.66667 0.66667 0.66667
+0.67059 0.67059 0.67059 0.67059
+0.67451 0.67451 0.67451 0.67451
+0.67843 0.67843 0.67843 0.67843
+0.68235 0.68235 0.68235 0.68235
+0.68627 0.68627 0.68627 0.68627
+0.69020 0.69020 0.69020 0.69020
+0.69412 0.69412 0.69412 0.69412
+0.69804 0.69804 0.69804 0.69804
+0.70196 0.70196 0.70196 0.70196
+0.70588 0.70588 0.70588 0.70588
+0.70980 0.70980 0.70980 0.70980
+0.71373 0.71373 0.71373 0.71373
+0.71765 0.71765 0.71765 0.71765
+0.72157 0.72157 0.72157 0.72157
+0.72549 0.72549 0.72549 0.72549
+0.72941 0.72941 0.72941 0.72941
+0.73333 0.73333 0.73333 0.73333
+0.73725 0.73725 0.73725 0.73725
+0.74118 0.74118 0.74118 0.74118
+0.74510 0.74510 0.74510 0.74510
+0.74902 0.74902 0.74902 0.74902
+0.75294 0.75294 0.75294 0.75294
+0.75686 0.75686 0.75686 0.75686
+0.76078 0.76078 0.76078 0.76078
+0.76471 0.76471 0.76471 0.76471
+0.76863 0.76863 0.76863 0.76863
+0.77255 0.77255 0.77255 0.77255
+0.77647 0.77647 0.77647 0.77647
+0.78039 0.78039 0.78039 0.78039
+0.78431 0.78431 0.78431 0.78431
+0.78824 0.78824 0.78824 0.78824
+0.79216 0.79216 0.79216 0.79216
+0.79608 0.79608 0.79608 0.79608
+0.80000 0.80000 0.80000 0.80000
+0.80392 0.80392 0.80392 0.80392
+0.80784 0.80784 0.80784 0.80784
+0.81176 0.81176 0.81176 0.81176
+0.81569 0.81569 0.81569 0.81569
+0.81961 0.81961 0.81961 0.81961
+0.82353 0.82353 0.82353 0.82353
+0.82745 0.82745 0.82745 0.82745
+0.83137 0.83137 0.83137 0.83137
+0.83529 0.83529 0.83529 0.83529
+0.83922 0.83922 0.83922 0.83922
+0.84314 0.84314 0.84314 0.84314
+0.84706 0.84706 0.84706 0.84706
+0.85098 0.85098 0.85098 0.85098
+0.85490 0.85490 0.85490 0.85490
+0.85882 0.85882 0.85882 0.85882
+0.86275 0.86275 0.86275 0.86275
+0.86667 0.86667 0.86667 0.86667
+0.87059 0.87059 0.87059 0.87059
+0.87451 0.87451 0.87451 0.87451
+0.87843 0.87843 0.87843 0.87843
+0.88235 0.88235 0.88235 0.88235
+0.88627 0.88627 0.88627 0.88627
+0.89020 0.89020 0.89020 0.89020
+0.89412 0.89412 0.89412 0.89412
+0.89804 0.89804 0.89804 0.89804
+0.90196 0.90196 0.90196 0.90196
+0.90588 0.90588 0.90588 0.90588
+0.90980 0.90980 0.90980 0.90980
+0.91373 0.91373 0.91373 0.91373
+0.91765 0.91765 0.91765 0.91765
+0.92157 0.92157 0.92157 0.92157
+0.92549 0.92549 0.92549 0.92549
+0.92941 0.92941 0.92941 0.92941
+0.93333 0.93333 0.93333 0.93333
+0.93725 0.93725 0.93725 0.93725
+0.94118 0.94118 0.94118 0.94118
+0.94510 0.94510 0.94510 0.94510
+0.94902 0.94902 0.94902 0.94902
+0.95294 0.95294 0.95294 0.95294
+0.95686 0.95686 0.95686 0.95686
+0.96078 0.96078 0.96078 0.96078
+0.96471 0.96471 0.96471 0.96471
+0.96863 0.96863 0.96863 0.96863
+0.97255 0.97255 0.97255 0.97255
+0.97647 0.97647 0.97647 0.97647
+0.98039 0.98039 0.98039 0.98039
+0.98431 0.98431 0.98431 0.98431
+0.98824 0.98824 0.98824 0.98824
+0.99216 0.99216 0.99216 0.99216
+0.99608 0.99608 0.99608 0.99608
+1.0000 1.0000 1.0000 1.0000
+END_DATA
diff --git a/ref/sRGB.icm b/ref/sRGB.icm
new file mode 100644
index 0000000..db0355f
--- /dev/null
+++ b/ref/sRGB.icm
Binary files differ
diff --git a/ref/strange.cal b/ref/strange.cal
new file mode 100644
index 0000000..23c1e87
--- /dev/null
+++ b/ref/strange.cal
@@ -0,0 +1,275 @@
+CAL
+
+DESCRIPTOR "Argyll Device Calibration Curves"
+ORIGINATOR "Argyll synthcal"
+CREATED "Sat Mar 09 18:33:22 2013"
+KEYWORD "DEVICE_CLASS"
+DEVICE_CLASS "DISPLAY"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+
+KEYWORD "RGB_I"
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+RGB_I RGB_R RGB_G RGB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 256
+BEGIN_DATA
+0.0000 0.0000 0.0000 0.0000
+3.9216e-003 5.6752e-005 0.011879 0.018606
+7.8431e-003 1.8439e-004 0.020682 0.030226
+0.011765 3.6735e-004 0.028607 0.040147
+0.015686 5.9908e-004 0.036009 0.049103
+0.019608 8.7544e-004 0.043047 0.057404
+0.023529 1.1935e-003 0.049807 0.065218
+0.027451 1.5511e-003 0.056344 0.072650
+0.031373 1.9464e-003 0.062696 0.079768
+0.035294 2.3779e-003 0.068891 0.086623
+0.039216 2.8443e-003 0.074949 0.093253
+0.043137 3.3446e-003 0.080888 0.099687
+0.047059 3.8778e-003 0.086719 0.10595
+0.050980 4.4431e-003 0.092453 0.11205
+0.054902 5.0396e-003 0.098100 0.11802
+0.058824 5.6668e-003 0.10367 0.12386
+0.062745 6.3239e-003 0.10916 0.12958
+0.066667 7.0104e-003 0.11458 0.13520
+0.070588 7.7258e-003 0.11995 0.14072
+0.074510 8.4696e-003 0.12525 0.14615
+0.078431 9.2413e-003 0.13049 0.15149
+0.082353 0.010040 0.13569 0.15675
+0.086275 0.010867 0.14083 0.16194
+0.090196 0.011720 0.14593 0.16706
+0.094118 0.012599 0.15099 0.17211
+0.098039 0.013504 0.15600 0.17710
+0.10196 0.014436 0.16097 0.18203
+0.10588 0.015392 0.16590 0.18690
+0.10980 0.016374 0.17080 0.19172
+0.11373 0.017380 0.17567 0.19649
+0.11765 0.018411 0.18049 0.20121
+0.12157 0.019467 0.18529 0.20588
+0.12549 0.020546 0.19006 0.21051
+0.12941 0.021650 0.19480 0.21509
+0.13333 0.022777 0.19950 0.21963
+0.13725 0.023927 0.20418 0.22414
+0.14118 0.025101 0.20884 0.22860
+0.14510 0.026298 0.21347 0.23303
+0.14902 0.027518 0.21807 0.23742
+0.15294 0.028760 0.22265 0.24177
+0.15686 0.030025 0.22720 0.24610
+0.16078 0.031312 0.23174 0.25039
+0.16471 0.032621 0.23625 0.25465
+0.16863 0.033953 0.24074 0.25888
+0.17255 0.035306 0.24521 0.26308
+0.17647 0.036681 0.24965 0.26725
+0.18039 0.038077 0.25408 0.27139
+0.18431 0.039495 0.25849 0.27551
+0.18824 0.040935 0.26288 0.27960
+0.19216 0.042395 0.26725 0.28366
+0.19608 0.043876 0.27161 0.28770
+0.20000 0.045378 0.27595 0.29172
+0.20392 0.046901 0.28027 0.29571
+0.20784 0.048445 0.28457 0.29968
+0.21176 0.050009 0.28886 0.30363
+0.21569 0.051594 0.29313 0.30755
+0.21961 0.053198 0.29738 0.31146
+0.22353 0.054824 0.30163 0.31534
+0.22745 0.056469 0.30585 0.31920
+0.23137 0.058134 0.31006 0.32304
+0.23529 0.059819 0.31426 0.32687
+0.23922 0.061523 0.31844 0.33067
+0.24314 0.063248 0.32261 0.33446
+0.24706 0.064992 0.32677 0.33822
+0.25098 0.066755 0.33091 0.34197
+0.25490 0.068538 0.33504 0.34570
+0.25882 0.070340 0.33916 0.34942
+0.26275 0.072162 0.34326 0.35312
+0.26667 0.074002 0.34736 0.35680
+0.27059 0.075862 0.35144 0.36046
+0.27451 0.077740 0.35551 0.36411
+0.27843 0.079638 0.35956 0.36774
+0.28235 0.081554 0.36361 0.37136
+0.28627 0.083489 0.36764 0.37496
+0.29020 0.085442 0.37167 0.37855
+0.29412 0.087415 0.37568 0.38213
+0.29804 0.089405 0.37968 0.38569
+0.30196 0.091414 0.38367 0.38923
+0.30588 0.093442 0.38765 0.39276
+0.30980 0.095487 0.39162 0.39628
+0.31373 0.097551 0.39559 0.39979
+0.31765 0.099633 0.39954 0.40328
+0.32157 0.10173 0.40348 0.40676
+0.32549 0.10385 0.40741 0.41022
+0.32941 0.10599 0.41133 0.41368
+0.33333 0.10814 0.41524 0.41712
+0.33725 0.11031 0.41915 0.42055
+0.34118 0.11250 0.42304 0.42396
+0.34510 0.11471 0.42693 0.42737
+0.34902 0.11693 0.43080 0.43076
+0.35294 0.11918 0.43467 0.43414
+0.35686 0.12144 0.43853 0.43752
+0.36078 0.12371 0.44238 0.44088
+0.36471 0.12601 0.44623 0.44422
+0.36863 0.12832 0.45006 0.44756
+0.37255 0.13065 0.45389 0.45089
+0.37647 0.13300 0.45770 0.45421
+0.38039 0.13536 0.46151 0.45751
+0.38431 0.13774 0.46532 0.46081
+0.38824 0.14014 0.46911 0.46410
+0.39216 0.14255 0.47290 0.46737
+0.39608 0.14499 0.47668 0.47064
+0.40000 0.14743 0.48045 0.47390
+0.40392 0.14990 0.48421 0.47715
+0.40784 0.15238 0.48797 0.48038
+0.41176 0.15488 0.49172 0.48361
+0.41569 0.15740 0.49546 0.48683
+0.41961 0.15993 0.49920 0.49004
+0.42353 0.16248 0.50293 0.49324
+0.42745 0.16505 0.50665 0.49644
+0.43137 0.16763 0.51037 0.49962
+0.43529 0.17023 0.51407 0.50279
+0.43922 0.17284 0.51778 0.50596
+0.44314 0.17547 0.52147 0.50912
+0.44706 0.17812 0.52516 0.51227
+0.45098 0.18079 0.52884 0.51541
+0.45490 0.18347 0.53252 0.51854
+0.45882 0.18616 0.53619 0.52167
+0.46275 0.18888 0.53985 0.52479
+0.46667 0.19161 0.54351 0.52789
+0.47059 0.19435 0.54716 0.53100
+0.47451 0.19711 0.55080 0.53409
+0.47843 0.19989 0.55444 0.53718
+0.48235 0.20268 0.55807 0.54025
+0.48627 0.20549 0.56170 0.54332
+0.49020 0.20832 0.56532 0.54639
+0.49412 0.21116 0.56894 0.54944
+0.49804 0.21402 0.57255 0.55249
+0.50196 0.21689 0.57615 0.55553
+0.50588 0.21978 0.57975 0.55857
+0.50980 0.22268 0.58334 0.56160
+0.51373 0.22560 0.58693 0.56462
+0.51765 0.22854 0.59051 0.56763
+0.52157 0.23149 0.59409 0.57064
+0.52549 0.23445 0.59766 0.57364
+0.52941 0.23744 0.60122 0.57663
+0.53333 0.24043 0.60478 0.57962
+0.53725 0.24345 0.60834 0.58260
+0.54118 0.24648 0.61189 0.58557
+0.54510 0.24952 0.61543 0.58854
+0.54902 0.25258 0.61897 0.59150
+0.55294 0.25565 0.62251 0.59445
+0.55686 0.25874 0.62603 0.59740
+0.56078 0.26185 0.62956 0.60034
+0.56471 0.26497 0.63308 0.60328
+0.56863 0.26811 0.63659 0.60621
+0.57255 0.27126 0.64010 0.60913
+0.57647 0.27442 0.64361 0.61205
+0.58039 0.27760 0.64711 0.61496
+0.58431 0.28080 0.65060 0.61787
+0.58824 0.28401 0.65410 0.62077
+0.59216 0.28724 0.65758 0.62366
+0.59608 0.29048 0.66106 0.62655
+0.60000 0.29373 0.66454 0.62943
+0.60392 0.29701 0.66801 0.63231
+0.60784 0.30029 0.67148 0.63518
+0.61176 0.30359 0.67494 0.63805
+0.61569 0.30691 0.67840 0.64091
+0.61961 0.31024 0.68186 0.64376
+0.62353 0.31358 0.68531 0.64661
+0.62745 0.31694 0.68875 0.64945
+0.63137 0.32032 0.69220 0.65229
+0.63529 0.32371 0.69563 0.65513
+0.63922 0.32711 0.69907 0.65795
+0.64314 0.33053 0.70249 0.66078
+0.64706 0.33397 0.70592 0.66360
+0.65098 0.33741 0.70934 0.66641
+0.65490 0.34088 0.71276 0.66922
+0.65882 0.34435 0.71617 0.67202
+0.66275 0.34785 0.71958 0.67482
+0.66667 0.35135 0.72298 0.67761
+0.67059 0.35487 0.72638 0.68040
+0.67451 0.35841 0.72978 0.68318
+0.67843 0.36196 0.73317 0.68596
+0.68235 0.36552 0.73656 0.68873
+0.68627 0.36910 0.73994 0.69150
+0.69020 0.37269 0.74332 0.69426
+0.69412 0.37630 0.74670 0.69702
+0.69804 0.37992 0.75007 0.69977
+0.70196 0.38356 0.75344 0.70252
+0.70588 0.38721 0.75681 0.70527
+0.70980 0.39087 0.76017 0.70801
+0.71373 0.39455 0.76353 0.71075
+0.71765 0.39824 0.76688 0.71348
+0.72157 0.40195 0.77023 0.71620
+0.72549 0.40567 0.77358 0.71893
+0.72941 0.40940 0.77692 0.72164
+0.73333 0.41315 0.78026 0.72436
+0.73725 0.41692 0.78360 0.72707
+0.74118 0.42069 0.78693 0.72977
+0.74510 0.42448 0.79026 0.73247
+0.74902 0.42829 0.79359 0.73517
+0.75294 0.43211 0.79691 0.73786
+0.75686 0.43594 0.80023 0.74055
+0.76078 0.43979 0.80354 0.74323
+0.76471 0.44365 0.80686 0.74591
+0.76863 0.44752 0.81016 0.74859
+0.77255 0.45141 0.81347 0.75126
+0.77647 0.45531 0.81677 0.75393
+0.78039 0.45923 0.82007 0.75659
+0.78431 0.46316 0.82336 0.75925
+0.78824 0.46710 0.82666 0.76191
+0.79216 0.47106 0.82994 0.76456
+0.79608 0.47503 0.83323 0.76721
+0.80000 0.47902 0.83651 0.76985
+0.80392 0.48302 0.83979 0.77249
+0.80784 0.48703 0.84307 0.77512
+0.81176 0.49105 0.84634 0.77776
+0.81569 0.49509 0.84961 0.78038
+0.81961 0.49915 0.85287 0.78301
+0.82353 0.50321 0.85614 0.78563
+0.82745 0.50729 0.85940 0.78825
+0.83137 0.51139 0.86265 0.79086
+0.83529 0.51550 0.86591 0.79347
+0.83922 0.51962 0.86916 0.79608
+0.84314 0.52375 0.87241 0.79868
+0.84706 0.52790 0.87565 0.80128
+0.85098 0.53206 0.87889 0.80387
+0.85490 0.53624 0.88213 0.80646
+0.85882 0.54042 0.88537 0.80905
+0.86275 0.54463 0.88860 0.81163
+0.86667 0.54884 0.89183 0.81421
+0.87059 0.55307 0.89506 0.81679
+0.87451 0.55731 0.89828 0.81937
+0.87843 0.56157 0.90150 0.82194
+0.88235 0.56584 0.90472 0.82450
+0.88627 0.57012 0.90793 0.82707
+0.89020 0.57441 0.91115 0.82963
+0.89412 0.57872 0.91436 0.83218
+0.89804 0.58304 0.91756 0.83474
+0.90196 0.58738 0.92077 0.83729
+0.90588 0.59173 0.92397 0.83983
+0.90980 0.59609 0.92717 0.84238
+0.91373 0.60046 0.93036 0.84492
+0.91765 0.60485 0.93356 0.84745
+0.92157 0.60925 0.93675 0.84999
+0.92549 0.61366 0.93993 0.85252
+0.92941 0.61809 0.94312 0.85504
+0.93333 0.62253 0.94630 0.85757
+0.93725 0.62698 0.94948 0.86009
+0.94118 0.63145 0.95266 0.86261
+0.94510 0.63593 0.95583 0.86512
+0.94902 0.64042 0.95900 0.86763
+0.95294 0.64493 0.96217 0.87014
+0.95686 0.64945 0.96534 0.87264
+0.96078 0.65398 0.96850 0.87515
+0.96471 0.65852 0.97166 0.87765
+0.96863 0.66308 0.97482 0.88014
+0.97255 0.66765 0.97798 0.88263
+0.97647 0.67223 0.98113 0.88512
+0.98039 0.67683 0.98428 0.88761
+0.98431 0.68144 0.98743 0.89009
+0.98824 0.68606 0.99058 0.89258
+0.99216 0.69069 0.99372 0.89505
+0.99608 0.69534 0.99686 0.89753
+1.0000 0.70000 1.0000 0.90000
+END_DATA
diff --git a/render/Jamfile b/render/Jamfile
new file mode 100644
index 0000000..fe975ea
--- /dev/null
+++ b/render/Jamfile
@@ -0,0 +1,31 @@
+
+# Optimization and Debug flags
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Link with debug info
+#PREF_CCFLAGS += $(CCPROFFLAG) ; # Profile flags
+#PREF_LINKFLAGS += $(LINKPROFFLAG) ; # Profile flags
+
+#Products
+Libraries = librender ;
+Executables = timage ;
+Headers = render.h ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+HDRS = ../h ../numlib $(TIFFINC) ;
+
+# 2D Rendering library
+Library librender : render.c thscreen.c ;
+
+Main timage : timage.c : : : : : librender ../numlib/libnum $(TIFFLIB) $(JPEGLIB) ;
+
+
+if $(BUILD_JUNK) {
+ Main tt : tt.c : : : ../plot : : ../numlib/libnum ../plot/libplot ;
+}
diff --git a/render/License.txt b/render/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/render/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/render/Makefile.am b/render/Makefile.am
new file mode 100644
index 0000000..2f88d0f
--- /dev/null
+++ b/render/Makefile.am
@@ -0,0 +1,13 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = librender.la
+privatelibdir = $(pkglibdir)
+
+librender_la_SOURCES = render.h render.c thscreen.h thscreen.c
+librender_la_LIBADD = $(TIFF_LIBS) ../numlib/libargyllnum.la
+
+LDADD = ./librender.la ../numlib/libargyllnum.la $(TIFF_LIBS)
+
+check_PROGRAMS = timage
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/render/Readme.txt b/render/Readme.txt
new file mode 100644
index 0000000..6ed3ea7
--- /dev/null
+++ b/render/Readme.txt
@@ -0,0 +1,10 @@
+
+2D Raster rendering support.
+---------------------------
+
+This is a very simple 2D rendering library, intended to
+support test and verification chart generation, and
+raster color test chart creation. Speed is not
+an objective of this library, just simplicity.
+
+
diff --git a/render/afiles b/render/afiles
new file mode 100644
index 0000000..26a7384
--- /dev/null
+++ b/render/afiles
@@ -0,0 +1,11 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+makecharts.ksh
+render.h
+render.c
+timage.c
+thscreen.h
+thscreen.c
+screens.h
diff --git a/render/makecharts.ksh b/render/makecharts.ksh
new file mode 100644
index 0000000..98ceb11
--- /dev/null
+++ b/render/makecharts.ksh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+# create some gamut mapping test charts
+./timage cube.tif
+./timage -x cube16.tif
+./timage -g 20 cubeG20.tif
+./timage -g 50 cubeG50.tif
+./timage -4 cmykcube.tif
+./timage -t -s surface.tif
+./timage -t -s -x surface16.tif
+./timage -t -s -g 20 surfaceG20.tif
+./timage -t -s -g 50 surfaceG50.tif
diff --git a/render/render.c b/render/render.c
new file mode 100644
index 0000000..cbeb78d
--- /dev/null
+++ b/render/render.c
@@ -0,0 +1,2425 @@
+
+/*
+ * render2d
+ *
+ * Simple 2D raster rendering support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/12/2005
+ *
+ * Copyright 2005, 2008, 2012 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.
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "sort.h"
+#include "numlib.h"
+#include "tiffio.h"
+#include "render.h"
+#include "thscreen.h"
+
+/* ------------------------------------------------------------- */
+/* Utilities */
+
+/* Standard L*a*b* to TIFF 8 bit CIELAB */
+static void cvt_Lab_to_CIELAB8(double *out, double *in) {
+ out[0] = in[0];
+ if (out[0] < 0.0)
+ out[0] = 0.0;
+ else if (out[0] > 100.0)
+ out[0] = 100.0;
+ out[0] = out[0] / 100.0 * 255.0;
+
+ out[1] = in[1];
+ if (out[1] < -128.0)
+ out[1] = -128.0;
+ else if (out[1] > 127.0)
+ out[1] = 127.0;
+ if (out[1] < 0.0)
+ out[1] = 256.0 + out[1];
+
+ out[2] = in[2];
+ if (out[2] < -128.0)
+ out[2] = -128.0;
+ else if (out[2] > 127.0)
+ out[2] = 127.0;
+ if (out[2] < 0.0)
+ out[2] = 256.0 + out[2];
+}
+
+/* Standard L*a*b* to TIFF 16 bit CIELAB */
+static void cvt_Lab_to_CIELAB16(double *out, double *in) {
+ out[0] = in[0];
+ if (out[0] < 0.0)
+ out[0] = 0.0;
+ else if (out[0] > 100.0)
+ out[0] = 100.0;
+ out[0] = out[0] / 100.0 * 65535.0;
+
+ out[1] = in[1];
+ if (out[1] < -32768.0)
+ out[1] = -32768.0;
+ else if (out[1] > 32767.0)
+ out[1] = 32767.0;
+ if (out[1] < 0.0)
+ out[1] = 65536.0 + out[1];
+
+ out[2] = in[2];
+ if (out[2] < -32768.0)
+ out[2] = -32768.0;
+ else if (out[2] > 32767.0)
+ out[2] = 32767.0;
+ if (out[2] < 0.0)
+ out[2] = 65536.0 + out[2];
+}
+
+/* ------------------------------------------------------------- */
+/* Main class implementation */
+
+/* Free ourselves and all primitives */
+static void render2d_del(render2d *s) {
+ prim2d *th, *nx;
+
+ /* Delete all the primitives */
+ for (th = s->head; th != NULL; th = nx) {
+ nx = th->next;
+ th->del(th);
+ }
+
+ /* And then ourselves */
+ free(s);
+}
+
+/* Add a primitive */
+static void render2d_add(render2d *s, prim2d *p) {
+ if (p == NULL)
+ error("render2d: Adding NULL primitive");
+
+ p->next = s->head;
+ s->head = p;
+ p->ix = s->ix;
+ s->ix++;
+}
+
+/* Set the default color */
+static void render2d_set_defc(render2d *s, color2d c) {
+ int j;
+
+ for (j = 0; j < s->ncc; j++)
+ s->defc[j] = c[j];
+ s->defc[PRIX2D] = c[PRIX2D];
+}
+
+
+/* Set background color function */
+static void render2d_set_bg_func(render2d *s,
+ void (*func)(void *cntx, color2d c, double x, double y),
+ void *cntx
+) {
+ s->bgfunc = func;
+ s->cntx = cntx;
+}
+
+/* Compute the length of a double nul terminated string, including */
+/* the nuls. */
+static int zzstrlen(char *s) {
+ int i;
+ for (i = 0;; i++) {
+ if (s[i] == '\000' && s[i+1] == '\000')
+ return i+2;
+ }
+ return 0;
+}
+
+/* Decide whether a color is different enough to need anti-aliasing */
+static int colordiff(render2d *s, color2d c1, color2d c2) {
+ int j;
+
+ for (j = 0; j < s->ncc; j++) {
+ if (fabs(c1[j] - c2[j]) > 1e-5)
+ return 1;
+ }
+ return 0;
+}
+
+#define MIXPOW 1.3
+#define OSAMLS 16
+
+/* Render and write to a TIFF file */
+/* Return NZ on error */
+static int render2d_write(render2d *s, char *filename, int comprn) {
+ TIFF *wh = NULL;
+ uint16 samplesperpixel = 0, bitspersample = 0;
+ uint16 extrasamples = 0; /* Extra "alpha" samples */
+ uint16 extrainfo[MXCH2D]; /* Info about extra samples */
+ uint16 photometric = 0;
+ uint16 inkset = 0xffff;
+ char *inknames = NULL;
+ tdata_t *outbuf;
+ unsigned char *tempbuf = NULL; /* 16 bit buffer for dithering */
+ thscreens *screen = NULL; /* dithering object */
+ prim2d *th, **pthp;
+ prim2d **xlist, **ylist; /* X, Y sorted start lists */
+ int xli, yli; /* Indexes into X, Y list */
+ int noix; /* Number in x list */
+ color2d *pixv0, *_pixv0; /* Storage for pixel values around current */
+ color2d *pixv1, *_pixv1;
+ sobol *so; /* Random sampler for anti-aliasing */
+ int i, j;
+
+ double rx0, rx1, ry0, ry1; /* Box being processed, newest sample is rx1, ry1 */
+ int x, y; /* Pixel x & y index */
+
+ if ((so = new_sobol(2)) == NULL)
+ return 1;
+
+ switch (s->csp) {
+ case w_2d: /* Video style grey */
+ samplesperpixel = 1;
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case k_2d: /* Printing style grey */
+ samplesperpixel = 1;
+ photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ case lab_2d: /* TIFF CIE L*a*b* */
+ samplesperpixel = 3;
+ photometric = PHOTOMETRIC_CIELAB;
+ break;
+ case rgb_2d: /* RGB */
+ samplesperpixel = 3;
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ case cmyk_2d: /* CMYK */
+ samplesperpixel = 4;
+ photometric = PHOTOMETRIC_SEPARATED;
+ inkset = INKSET_CMYK;
+ inknames = "cyan\000magenta\000yellow\000\000";
+ break;
+ case ncol_2d: /* N color */
+ samplesperpixel = s->ncc;
+ extrasamples = 0;
+ photometric = PHOTOMETRIC_SEPARATED;
+ inkset = 0; // ~~99 should fix this
+ inknames = NULL; // ~~99 should fix this
+ break;
+ case ncol_a_2d: /* N color with extras in alpha */
+ samplesperpixel = s->ncc;
+ extrasamples = 0;
+ if (samplesperpixel > 4) {
+ extrasamples = samplesperpixel - 4; /* Call samples > 4 "alpha" samples */
+ for (j = 0; j < extrasamples; j++)
+ extrainfo[j] = EXTRASAMPLE_UNASSALPHA;
+ }
+ photometric = PHOTOMETRIC_SEPARATED;
+ inkset = 0; // ~~99 should fix this
+ inknames = NULL; // ~~99 should fix this
+ break;
+ default:
+ error("render2d: Illegal colorspace for file '%s'",filename);
+ }
+ if (samplesperpixel != s->ncc)
+ error("render2d: mismatched number of color components");
+
+ switch (s->dpth) {
+ case bpc8_2d: /* 8 bits per component */
+ bitspersample = 8;
+ break;
+ case bpc16_2d: /* 16 bits per component */
+ bitspersample = 16;
+ break;
+ default:
+ error("render2d: Illegal bits per component for file '%s'",filename);
+ }
+
+ if ((wh = TIFFOpen(filename, "w")) == NULL)
+ error("render2d: Can\'t create TIFF file '%s'!",filename);
+
+ TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, s->pw);
+ TIFFSetField(wh, TIFFTAG_IMAGELENGTH, s->ph);
+ TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
+ TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, bitspersample);
+ TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, photometric);
+ if (extrasamples > 0)
+ TIFFSetField(wh, TIFFTAG_EXTRASAMPLES, extrasamples, extrainfo);
+
+ if (inknames != NULL) {
+ int inlen = zzstrlen(inknames);
+ TIFFSetField(wh, TIFFTAG_INKSET, inkset);
+ TIFFSetField(wh, TIFFTAG_INKNAMES, inlen, inknames);
+ }
+ TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, RESUNIT_CENTIMETER);
+ TIFFSetField(wh, TIFFTAG_XRESOLUTION, 10.0 * s->hres); /* Cvt. to pixels/cm */
+ TIFFSetField(wh, TIFFTAG_YRESOLUTION, 10.0 * s->vres);
+ TIFFSetField(wh, TIFFTAG_XPOSITION, 0.1 * s->lm); /* Cvt. to cm */
+ TIFFSetField(wh, TIFFTAG_YPOSITION, 0.1 * s->tm);
+ if (comprn) {
+ TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
+ }
+ TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, "Test chart created with Argyll");
+
+ /* Allocate pixel value storage for aliasing detection */
+ if ((_pixv0 = malloc(sizeof(color2d) * (s->pw+2))) == NULL)
+ return 1;
+ pixv0 = _pixv0+1;
+ if ((_pixv1 = malloc(sizeof(color2d) * (s->pw+2))) == NULL)
+ return 1;
+ pixv1 = _pixv1+1;
+
+ /* Allocate one TIFF line buffer */
+ outbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+
+ if (s->dpth == bpc8_2d && s->dither) {
+#ifdef NEVER // For testing by making screen visible
+# define LEVELS 16
+ int i, olevs[LEVELS];
+ for (i = 0; i < LEVELS; i++)
+ olevs[i] = (int)(i/(LEVELS-1.0) * 255.0 + 0.5);
+ if ((screen = new_thscreens(0, s->ncc, 1.0, 79, scie_16, 8, LEVELS, olevs,
+ scoo_l, 0.1, NULL, NULL)) == NULL)
+#else
+ if ((screen = new_thscreens(0, s->ncc, 1.0, 79, scie_16, 8, 256, NULL,
+ scoo_l, 0.1, NULL, NULL)) == NULL)
+#endif
+ return 1;
+ if ((tempbuf = malloc(s->pw * s->ncc * 2)) == NULL)
+ return 1;
+ }
+
+ /* To accelerate rendering, we keep sorted Y and X lists, */
+ /* and Y and X active linked lists derived from them. */
+ /* Typically this means that we're calling render on */
+ /* none, 1 or a handful of the primitives, greatly speeding up */
+ /* rendering. */
+
+ /* Allocate X and Y ordered lists */
+ if ((ylist = malloc(sizeof(prim2d *) * s->ix)) == NULL)
+ return 1;
+ if ((xlist = malloc(sizeof(prim2d *) * s->ix)) == NULL)
+ return 1;
+
+ /* Initialise the Y list */
+ for (th = s->head, i = 0; th != NULL; th = th->next, i++)
+ ylist[i] = th;
+
+ /* Sort the Y lists by y1 (because we rasterise top to bottom) */
+#define HEAP_COMPARE(A,B) (A->y1 > B->y1)
+ HEAPSORT(prim2d *,ylist,s->ix)
+#undef HEAP_COMPARE
+ yli = 0;
+ s->yl = NULL;
+
+ /* Render each line and write it. */
+ /* We sample +- half a pixel around the pixel we want. */
+ /* We make the active element list encompass this region, */
+ /* so that we can super sample it for anti-aliasing. */
+ for (y = -1; y < s->ph; y++) {
+
+ ry0 = (((s->ph-1) - y) - 0.5) / s->vres;
+ ry1 = (((s->ph-1) - y) + 0.5) / s->vres;
+
+ /* Remove any objects from the y list that are now out of range */
+ for (pthp = &s->yl, th = s->yl; th != NULL;) {
+ if (ry1 < th->y0) {
+ *pthp = th->yl;
+ th = th->yl;
+ } else {
+ pthp = &th->yl;
+ th = th->yl;
+ }
+ }
+
+ /* Add any objects that are now within this range to our y list */
+ for(; yli < s->ix && ry0 < ylist[yli]->y1; yli++) {
+ ylist[yli]->yl = s->yl;
+ s->yl = ylist[yli];
+ }
+
+ /* Initialise the current X list */
+ for (th = s->yl, noix = 0; th != NULL; th = th->yl, noix++)
+ xlist[noix] = th;
+
+ /* Sort the X lists by x0 */
+#define HEAP_COMPARE(A,B) (A->x0 < B->x0)
+ HEAPSORT(prim2d *,xlist,noix)
+#undef HEAP_COMPARE
+ xli = 0;
+ s->xl = NULL;
+
+ for (x = -1; x < s->pw; x++) {
+ int j;
+ color2d rv;
+
+ rx0 = (x - 0.5) / s->hres;
+ rx1 = (x + 0.5) / s->hres;
+
+ /* Add any objects that are now within this range to our x list */
+ for(; xli < noix && rx1 > xlist[xli]->x0; xli++) {
+ xlist[xli]->xl = s->xl;
+ s->xl = xlist[xli];
+ }
+
+ /* Set the default current color */
+ for (j = 0; j < s->ncc; j++)
+ pixv1[x][j] = s->defc[j];
+ pixv1[x][PRIX2D] = -1; /* Make sure all primitive ovewrite the default */
+
+ /* Allow callback to set per pixel background color (or not) */
+ if (s->bgfunc != NULL)
+ s->bgfunc(s->cntx, pixv1[x], x, y);
+
+ /* Overwrite it with any primitives, */
+ /* and remove any that are out of range now */
+ for (pthp = &s->xl, th = s->xl; th != NULL;) {
+ if (rx0 > th->x1) {
+ *pthp = th->xl;
+ th = th->xl;
+ } else {
+ if (th->rend(th, rv, rx1, ry0) && th->ix > pixv1[x][PRIX2D]) {
+ /* Overwrite the current color */
+ /* (This is where we should handle depth and opacity */
+ for (j = 0; j < s->ncc; j++)
+ pixv1[x][j] = rv[j];
+ pixv1[x][PRIX2D] = rv[PRIX2D];
+ }
+ pthp = &th->xl;
+ th = th->xl;
+ }
+ }
+ /* Check if anti-aliasing is neded for previous lines previous pixel */
+ if (y >= 0 && x >= 0) {
+ color2d cc;
+
+ for (j = 0; j < s->ncc; j++)
+ cc[j] = pixv1[x][j];
+ cc[PRIX2D] = pixv1[x][PRIX2D];
+
+ /* See if anti aliasing is needed */
+ if ((pixv0[x+0][PRIX2D] != cc[PRIX2D] && colordiff(s, pixv0[x+0], cc))
+ || (pixv0[x-1][PRIX2D] != cc[PRIX2D] && colordiff(s, pixv0[x-1], cc))
+ || (pixv1[x-1][PRIX2D] != cc[PRIX2D] && colordiff(s, pixv1[x-1], cc))) {
+ double nn = 0;
+
+ so->reset(so);
+
+ for (j = 0; j < s->ncc; j++)
+ cc[j] = 0.0;
+
+ /* Compute the sample value by re-sampling the region */
+ /* around the pixel. */
+ for (nn = 0; nn < OSAMLS; nn++) {
+ double pos[2];
+ double rx, ry;
+ color2d ccc;
+
+ so->next(so, pos);
+
+ rx = (rx1 - rx0) * pos[0] + rx0;
+ ry = (ry1 - ry0) * pos[1] + ry0;
+
+ /* Set the default current color */
+ for (j = 0; j < s->ncc; j++)
+ ccc[j] = s->defc[j];
+ ccc[PRIX2D] = -1;
+
+ for (th = s->xl; th != NULL; th = th->xl) {
+ if (th->rend(th, rv, rx, ry) && th->ix > ccc[PRIX2D]) {
+ /* Overwrite the current color */
+ /* (This is where we should handle depth and opacity */
+ for (j = 0; j < s->ncc; j++)
+ ccc[j] = rv[j];
+ ccc[PRIX2D] = rv[PRIX2D];
+ }
+ }
+ for (j = 0; j < s->ncc; j++)
+ cc[j] += pow(ccc[j], MIXPOW);
+ }
+ for (j = 0; j < s->ncc; j++)
+ cc[j] = pow(cc[j]/nn, 1.0/MIXPOW);
+
+#ifdef NEVER /* Mark aliased pixels */
+ cc[0] = 0.5;
+ cc[1] = 0.0;
+ cc[2] = 1.0;
+#endif
+ } else {
+
+ /* Compute output value as mean of surrounding samples */
+ for (j = 0; j < s->ncc; j++) {
+ cc[j] = cc[j]
+ + pixv0[x-1][j]
+ + pixv0[x][j]
+ + pixv1[x-1][j];
+ cc[j] = cc[j] * 0.25;
+
+ }
+ }
+
+ /* Translate from render value to output pixel value */
+ if (s->dpth == bpc8_2d) {
+ if (s->dither) {
+ unsigned short *p = ((unsigned short *)tempbuf) + x * s->ncc;
+ if (s->csp == lab_2d) {
+ cvt_Lab_to_CIELAB16(cc, cc);
+ for (j = 0; j < s->ncc; j++)
+ p[j] = (int)(cc[j] + 0.5);
+ } else {
+ for (j = 0; j < s->ncc; j++)
+ p[j] = (int)(65535.0 * cc[j] + 0.5);
+ }
+ } else {
+ unsigned char *p = ((unsigned char *)outbuf) + x * s->ncc;
+ if (s->csp == lab_2d) {
+ cvt_Lab_to_CIELAB8(cc, cc);
+ for (j = 0; j < s->ncc; j++)
+ p[j] = (int)(cc[j] + 0.5);
+ } else {
+ for (j = 0; j < s->ncc; j++)
+ p[j] = (int)(255.0 * cc[j] + 0.5);
+ }
+ }
+ } else {
+ unsigned short *p = ((unsigned short *)outbuf) + x * s->ncc;
+ if (s->csp == lab_2d) {
+ cvt_Lab_to_CIELAB16(cc, cc);
+ for (j = 0; j < s->ncc; j++)
+ p[j] = (int)(cc[j] + 0.5);
+ } else {
+ for (j = 0; j < s->ncc; j++)
+ p[j] = (int)(65535.0 * cc[j] + 0.5);
+ }
+ }
+ }
+ }
+
+ if (y >= 0) {
+ if (s->dpth == bpc8_2d && s->dither)
+ screen->screen(screen, s->pw, 1, 0, y, tempbuf, s->pw * s->ncc * 2,
+ (unsigned char *)outbuf, s->pw * s->ncc);
+
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF file '%s' line %d",filename,y);
+ }
+
+ /* Shuffle the pointers */
+ {
+ color2d *ttt;
+ ttt = pixv0;
+ pixv0 = pixv1;
+ pixv1 = ttt;
+ }
+ }
+
+ free(ylist);
+ free(xlist);
+ free(_pixv0);
+ free(_pixv1);
+
+ if (tempbuf != NULL)
+ free(tempbuf);
+ if (screen != NULL)
+ screen->del(screen);
+ _TIFFfree(outbuf);
+ TIFFClose(wh); /* Close Output file */
+
+ so->del(so);
+
+ return 0;
+}
+
+/* Constructor */
+render2d *new_render2d(
+double w, /* width in mm */
+double h, /* height in mm */
+double ma[4], /* Margines, left, right, top, bottom, NULL for zero in mm */
+double hres, /* horizontal resolution in pixels/mm */
+double vres, /* horizontal resolution in pixels/mm */
+colort2d csp, /* Color type */
+int nd, /* Number of channels if c = ncol */
+depth2d dpth, /* Pixel depth */
+int dither /* Dither flag */
+) {
+ render2d *s;
+
+ if ((s = (render2d *)calloc(1, sizeof(render2d))) == NULL) {
+ return NULL;
+ }
+
+ s->fw = w;
+ s->fh = h;
+ if (ma != NULL) {
+ s->lm = ma[0];
+ s->rm = ma[1];
+ s->tm = ma[2];
+ s->bm = ma[3];
+ }
+ w = s->fw - s->lm - s->rm;
+ h = s->fh - s->tm - s->bm;
+ if (w < 0.0)
+ error("render2d: Left & Right margines %f %f exceed width %f",s->lm,s->rm,s->fw);
+ if (h < 0.0)
+ error("render2d: Top & Bottom margines %f %f exceed height %f",s->tm,s->bm,s->fh);
+ s->hres = hres;
+ s->vres = vres;
+ s->csp = csp;
+ s->dpth = dpth;
+ s->dither = dither;
+
+ s->del = render2d_del;
+ s->set_defc = render2d_set_defc;
+ s->set_bg_func = render2d_set_bg_func;
+ s->add = render2d_add;
+ s->write = render2d_write;
+
+ /* Figure the raster size and actuall size */
+ s->pw = (int)(s->hres * w + 0.5);
+ s->ph = (int)(s->vres * h + 0.5);
+ s->w = s->pw * s->hres;
+ s->h = s->ph * s->vres;
+
+ switch (s->csp) {
+ case w_2d: /* Video style grey */
+ case k_2d: /* Printing style grey */
+ s->ncc = 1;
+ break;
+ case lab_2d: /* TIFF CIE L*a*b* */
+ s->ncc = 3;
+ break;
+ case rgb_2d: /* RGB */
+ s->ncc = 3;
+ break;
+ case cmyk_2d: /* CMYK */
+ s->ncc = 4;
+ break;
+ case ncol_2d:
+ case ncol_a_2d:
+ if (nd > MXCH2D)
+ error("render2d: Too many color chanels %d, max is %d",nd,MXCH2D);
+ s->ncc = nd;
+ break;
+ default:
+ error("render2d: Illegal colorspace");
+ }
+ return s;
+}
+
+/* ------------------------------------------------------------- */
+/* Primitive implementations */
+
+/* Primitive destructor for no sub-allocation */
+static void prim2d_del(prim2d *s) {
+ free(s);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Flat shaded rectangle */
+
+/* Render the rectangle object at location. Return nz if in primitive */
+static int rect2d_rend(prim2d *ss, color2d rv, double x, double y) {
+ rect2d *s = (rect2d *)ss;
+ int j;
+
+ if (y < s->ry0 || y > s->ry1
+ || x < s->rx0 || x > s->rx1)
+ return 0;
+
+ for (j = 0; j < s->ncc; j++)
+ rv[j] = s->c[j];
+ rv[PRIX2D] = s->ix;
+
+ return 1;
+}
+
+prim2d *new_rect2d(
+render2d *ss,
+double x,
+double y,
+double w,
+double h,
+color2d c
+) {
+ int j;
+ rect2d *s;
+
+ if ((s = (rect2d *)calloc(1, sizeof(rect2d))) == NULL) {
+ return NULL;
+ }
+
+ /* Account for margines */
+ x -= ss->lm;
+ y -= ss->bm;
+
+ s->ncc = ss->ncc;
+ s->del = prim2d_del;
+ s->rend = rect2d_rend;
+
+ /* Set bounding box */
+ s->x0 = x;
+ s->y0 = y;
+ s->x1 = x + w;
+ s->y1 = y + h;
+
+ /* Set rectangle extent */
+ s->rx0 = s->x0;
+ s->ry0 = s->y0;
+ s->rx1 = s->x1;
+ s->ry1 = s->y1;
+
+ for (j = 0; j < s->ncc; j++)
+ s->c[j] = c[j];
+
+ return (prim2d *)s;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Vertex shaded rectangle */
+
+/* Render the rectangle object at location. Return nz if in primitive */
+static int rectvs2d_rend(prim2d *ss, color2d rv, double x, double y) {
+ rectvs2d *s = (rectvs2d *)ss;
+ double bx, by, b[4];
+ int i, j;
+
+ if (y < s->ry0 || y > s->ry1
+ || x < s->rx0 || x > s->rx1)
+ return 0;
+
+ /* Compute linear blend */
+ bx = (x - s->x0)/(s->x1 - s->x0);
+ by = (y - s->y0)/(s->y1 - s->y0);
+
+ if (s->x_blend == 1) {
+ bx = bx * bx * (3.0 - 2.0 * bx); /* Cubic spline */
+ } else if (s->x_blend == 2) {
+ bx = bx - 0.5; /* Sine */
+ bx *= 3.141592654;
+ bx = sin(bx);
+ bx = 0.5 + (0.5 * bx);
+ }
+ if (s->y_blend == 1) {
+ by = by * by * (3.0 - 2.0 * by); /* Spline */
+ } else if (s->y_blend == 2) {
+ double ty;
+ ty = by * by * (3.0 - 2.0 * by); /* spline at y == 1, linear at y == 0 */
+ by = by * ty + (1.0 - by) * by;
+ } else if (s->y_blend == 3) {
+ double ty;
+ ty = by * by * (3.0 - 2.0 * by); /* linear at y == 1, spline at y == 0 */
+ by = (1.0 - by) * ty + by * by;
+ }
+
+ /* Compute 2d blend */
+ b[0] = (1.0 - by) * (1.0 - bx);
+ b[1] = (1.0 - by) * bx;
+ b[2] = by * (1.0 - bx);
+ b[3] = by * bx;
+
+ /* Compute the resulting color */
+ for (j = 0; j < s->ncc; j++) {
+ rv[j] = 0.0;
+ for (i = 0; i < 4; i++)
+ rv[j] += b[i] * s->c[i][j];
+ rv[j] = rv[j];
+ }
+ rv[PRIX2D] = s->ix;
+
+ return 1;
+}
+
+prim2d *new_rectvs2d(
+render2d *ss,
+double x,
+double y,
+double w,
+double h,
+color2d c[4]
+) {
+ int i, j;
+ rectvs2d *s;
+
+ if ((s = (rectvs2d *)calloc(1, sizeof(rectvs2d))) == NULL) {
+ return NULL;
+ }
+
+ /* Account for margines */
+ x -= ss->lm;
+ y -= ss->bm;
+
+ s->ncc = ss->ncc;
+ s->del = prim2d_del;
+ s->rend = rectvs2d_rend;
+
+ /* Set bounding box */
+ s->x0 = x;
+ s->y0 = y;
+ s->x1 = x + w;
+ s->y1 = y + h;
+
+ /* Set rectangle extent */
+ s->rx0 = s->x0;
+ s->ry0 = s->y0;
+ s->rx1 = s->x1;
+ s->ry1 = s->y1;
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < s->ncc; j++)
+ s->c[i][j] = c[i][j];
+
+ return (prim2d *)s;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Vertex shaded triangle */
+
+/* Render the triangle object at location. Return nz if in primitive */
+static int trivs2d_rend(prim2d *ss, color2d rv, double x, double y) {
+ trivs2d *s = (trivs2d *)ss;
+ double b[3];
+ int i, j;
+
+ /* Compute the baricentric values for the input point, */
+ /* and reject this point if it is outside the triangle */
+ for (i = 0; i < 3; i++) {
+ b[i] = s->be[i][0] * x + s->be[i][1] * y + s->be[i][2];
+ if (b[i] < 0.0 || b[i] > 1.0)
+ return 0;
+ }
+
+#ifdef NEVER /* Experiment with smoothing hue blending */
+ {
+ double ss = b[1] + b[2];
+ if (ss > 1e-6) {
+ b[1] /= ss;
+ b[2] /= ss;
+// b[1] = b[1] * b[1] * (3.0 - 2.0 * b[1]);
+
+ b[1] = b[1] - 0.5;
+ b[1] *= 3.141592654;
+ b[1] = sin(b[1]);
+ b[1] = 0.5 + (0.5 * b[1]);
+
+ b[2] = 1.0 - b[1];
+ b[1] *= ss;
+ b[2] *= ss;
+ }
+ }
+#endif
+
+ /* Compute the resulting color */
+ for (j = 0; j < s->ncc; j++) {
+ rv[j] = 0.0;
+ for (i = 0; i < 3; i++)
+ rv[j] += b[i] * s->c[i][j];
+ }
+ rv[PRIX2D] = s->ix;
+
+ return 1;
+}
+
+static int inverse3x3(double out[3][3], double in[3][3]);
+
+prim2d *new_trivs2d(
+render2d *ss,
+double v[3][2], /* Vertex locations */
+color2d c[3] /* Corresponding colors */
+) {
+ int i, j;
+ trivs2d *s;
+ double vv[3][2]; /* Margin adjusted vertex locations */
+ double tt[3][3];
+
+ if ((s = (trivs2d *)calloc(1, sizeof(trivs2d))) == NULL) {
+ return NULL;
+ }
+
+ /* Account for margines */
+ for (i = 0; i < 3; i++) {
+ vv[i][0] = v[i][0] - ss->lm;
+ vv[i][1] = v[i][1] - ss->bm;
+ }
+
+ s->ncc = ss->ncc;
+ s->del = prim2d_del;
+ s->rend = trivs2d_rend;
+
+ /* Set the bounding box values */
+ s->x0 = s->y0 = 1e38;
+ s->x1 = s->y1 = -1e38;
+ for (i = 0; i < 3; i++) {
+ if (vv[i][0] < s->x0)
+ s->x0 = vv[i][0];
+ if (vv[i][1] < s->y0)
+ s->y0 = vv[i][1];
+ if (vv[i][0] > s->x1)
+ s->x1 = vv[i][0];
+ if (vv[i][1] > s->y1)
+ s->y1 = vv[i][1];
+ }
+
+ /* Compute baricentric equations */
+ for (i = 0; i < 3; i++) {
+ tt[0][i] = vv[i][0];
+ tt[1][i] = vv[i][1];
+ tt[2][i] = 1.0;
+ }
+ if (inverse3x3(s->be, tt))
+ error("trivs2d: Matrix inversion failed");
+
+ /* Copy vertex colors */
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < s->ncc; j++)
+ s->c[i][j] = c[i][j];
+ }
+
+ return (prim2d *)s;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A single Rounded end line. Mainly for supporting Hershey text output. */
+
+/* Render the line object at this location */
+static int line2d_rend(prim2d *ss, color2d rv, double x, double y) {
+ line2d *s = (line2d *)ss;
+ double rr, px, py;
+ int j;
+
+ px = x - s->lx0; /* Input relative to x0 y0 */
+ py = y - s->ly0;
+
+ /* It's actually a point */
+ if (s->t) {
+
+ rr = (px * px) + (py * py) ;
+
+ if (s->cap != 1)
+ return 0;
+ if (rr > s->ww)
+ return 0;
+
+ } else {
+ /* Locate point on line between 0 and 1 closest to input point */
+ double t, nx, ny;
+
+ /* Closest point on line parametric value */
+ t = (s->vx * px + s->vy * py)/(s->vx * s->vx + s->vy * s->vy);
+
+ if (t < 0.0) { /* 0 side end cap */
+ if (s->cap != 1)
+ return 0;
+ rr = (px * px) + (py * py) ;
+ if (rr > s->ww)
+ return 0; /* 1 side end cap */
+
+ } else if (t > 1.0) {
+ if (s->cap != 1)
+ return 0;
+ rr = (x - s->lx1) * (x - s->lx1)
+ + (y - s->ly1) * (y - s->ly1);
+ if (rr > s->ww)
+ return 0;
+
+ } else { /* Within rectangular part of line */
+ double nx, ny;
+
+ nx = t * s->vx; /* Closest point on line relative to x0 y0 */
+ ny = t * s->vy;
+
+ rr = (px - nx) * (px - nx) + (py - ny) * (py - ny);
+ if (rr > s->ww)
+ return 0;
+ }
+ }
+
+ for (j = 0; j < s->ncc; j++)
+ rv[j] = s->c[j];
+ rv[PRIX2D] = s->ix;
+
+ return 1;
+}
+
+prim2d *new_line2d(
+render2d *ss,
+double x0, double y0, double x1, double y1,
+double w,
+int cap, /* 0 = butt, 1 = round, 2 = square */
+color2d c
+) {
+ int i, j;
+ line2d *s;
+ double tt[3][3];
+
+ if ((s = (line2d *)calloc(1, sizeof(line2d))) == NULL) {
+ return NULL;
+ }
+
+ /* Account for margines */
+ x0 -= ss->lm;
+ y0 -= ss->bm;
+ x1 -= ss->lm;
+ y1 -= ss->bm;
+
+ s->ncc = ss->ncc;
+ s->del = prim2d_del;
+ s->rend = line2d_rend;
+
+ w *= 0.5; /* half width */
+
+ for (j = 0; j < s->ncc; j++)
+ s->c[j] = c[j];
+
+ /* Compute the line vector relative to x0 y0 */
+ s->vx = x1 - x0;
+ s->vy = y1 - y0;
+
+ /* For square, extend the line by w/2 and render as butt */
+ if (cap == 2) {
+ double nvx, nvy;
+ double ll = sqrt(s->vx * s->vx + s->vy * s->vy);
+
+ /* Compute normalized vector */
+ if (ll < 1e-6) {
+ nvx = 1.0;
+ nvy = 0.0;
+ } else {
+ nvx = s->vx/ll;
+ nvy = s->vy/ll;
+ }
+ x0 -= w * nvx;
+ y0 -= w * nvy;
+ x1 += w * nvx;
+ y1 += w * nvy;
+ s->vx = x1 - x0;
+ s->vy = y1 - y0;
+ }
+
+ s->lx0 = x0;
+ s->ly0 = y0;
+ s->lx1 = x1;
+ s->ly1 = y1;
+ s->ww = w * w;
+ s->cap = cap;
+
+ /* Set the bouding box values */
+ if (x1 > x0) {
+ s->x1 = x1 + w;
+ s->x0 = x0 - w;
+ } else {
+ s->x1 = x0 + w;
+ s->x0 = x1 - w;
+ }
+ if (y1 > y0) {
+ s->y1 = y1 + w;
+ s->y0 = y0 - w;
+ } else {
+ s->y1 = y0 + w;
+ s->y0 = y1 - w;
+ }
+
+ /* Figure out if the line is degenerate */
+ if (fabs(s->vx) < 1e-6 && fabs(s->vy) < 1e-6) {
+ s->t = 1;
+ }
+
+ return (prim2d *)s;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Primitive Macros. */
+
+/* add a dashed line */
+void add_dashed_line2d(
+struct _render2d *s,
+double x0, double y0,
+double x1, double y1,
+double w,
+double on, double off,
+int cap,
+color2d c) {
+ double ll, rl; /* Line length, rounded length */
+ double vx, vy;
+ double nvx, nvy; /* Normalized vector */
+
+ vx = x1 - x0;
+ vy = y1 - y0;
+ ll = sqrt(vx * vx + vy * vy);
+
+ if (ll < 1e-6) {
+ s->add(s, new_line2d(s, x0, y0, x1, y1, w, cap, c));
+ return ;
+ }
+ nvx = vx/ll;
+ nvy = vy/ll;
+
+ for (;ll > 0.0;) {
+ rl = ll;
+ if (rl > on) {
+ rl = on;
+ }
+ x1 = x0 + rl * nvx;
+ y1 = y0 + rl * nvy;
+ s->add(s, new_line2d(s, x0, y0, x1, y1, w, cap, c));
+ x0 = x1;
+ y0 = y1;
+ ll -= rl;
+ if (ll <= 0.0)
+ return;
+ rl = ll;
+ if (rl > off) {
+ rl = off;
+ }
+ x0 += rl * nvx;
+ y0 += rl * nvy;
+ ll -= rl;
+ }
+}
+
+
+/* Text */
+struct _hyfont {
+ char *name;
+ double sx, sy; /* X and Y scaling */
+ double sxi; /* X spacing extra scale */
+ double sw; /* Line width scale */
+ double ho; /* horizontal alignment offset */
+ double vo; /* vertical alignment offset */
+ char *enc[128]; /* Hershey encoded font */
+}; typedef struct _hyfont hyfont;
+
+hyfont fonts[];
+
+double h2dbl(unsigned char c) { return (double)(c-'R'); }
+
+/* Add a text character at the given location using lines */
+static void add_char_imp(
+render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char ch, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+int or, /* Orintation, 0 = right, 1 = down, 2 = left, 3 = right */
+color2d c, /* Color of text */
+int add /* NZ if character is to be added */
+) {
+ hyfont *fp = &fonts[fo];
+ char *cp = fp->enc[ch % 128];
+ double lm, rm;
+ double x0, y0, x1 = 0.0, y1 = 0.0;
+ int got1 = 0;
+ double w = fp->sw * h;
+ double tx, ty;
+ double mat[2][2]; /* Transformation matrix */
+
+ if (or == 0) {
+ mat[0][0] = 1.0;
+ mat[0][1] = 0.0;
+ mat[1][0] = 0.0;
+ mat[1][1] = 1.0;
+ } else if (or == 1) {
+ mat[0][0] = 0.0;
+ mat[0][1] = 1.0;
+ mat[1][0] = -1.0;
+ mat[1][1] = 0.0;
+ } else if (or == 2) {
+ mat[0][0] = -1.0;
+ mat[0][1] = 0.0;
+ mat[1][0] = 0.0;
+ mat[1][1] = -1.0;
+ } else {
+ mat[0][0] = 0.0;
+ mat[0][1] = -1.0;
+ mat[1][0] = 1.0;
+ mat[1][1] = 0.0;
+ }
+ if (cp[0] == '\000' || cp[1] == '\000') {
+ if (xinc != NULL && yinc != NULL) {
+ *xinc = 0.0;
+ *yinc = 0.0;
+ }
+ return;
+ }
+
+ lm = h2dbl(cp[0]);
+ rm = h2dbl(cp[1]);
+ cp += 2;
+
+ if (add) {
+ for (;; cp += 2) {
+ if (cp[0] == '\000' || cp[1] == '\000') {
+ break;
+ }
+ /* End of polyline */
+ if (cp[0] == ' ' && cp[1] == 'R' ) {
+ got1 = 0;
+ } else {
+ x0 = x1;
+ y0 = y1;
+ tx = h * fp->sx * (h2dbl(cp[0]) -lm + fp->ho);
+ ty = -h * fp->sy * (h2dbl(cp[1]) -fp->vo);
+ x1 = x + mat[0][0] * tx + mat[0][1] * ty;
+ y1 = y + mat[1][0] * tx + mat[1][1] * ty;
+ if (got1) {
+ s->add(s, new_line2d(s, x0, y0, x1, y1, w, 1, c));
+ }
+ got1 = 1;
+ }
+ }
+ }
+
+ tx = fp->sxi * h * fp->sx * (rm - lm);
+ ty = 0.0;
+ if (xinc != NULL)
+ *xinc += mat[0][0] * tx + mat[0][1] * ty;
+ if (yinc != NULL)
+ *yinc += mat[1][0] * tx + mat[1][1] * ty;
+}
+
+/* Add a text character at the given location using lines */
+void add_char2d(
+render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char ch, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+int or, /* Orintation, 0 = right, 1 = down, 2 = left, 3 = right */
+color2d c /* Color of text */
+) {
+ add_char_imp(s, xinc, yinc, fo, ch, x, y, h, or, c, 1);
+}
+
+/* Return the total width of the character without adding it */
+void meas_char2d(
+render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char ch, /* Character code to be printed */
+double h, /* Height of text in normal orientation */
+int or /* Orintation, 0 = right, 1 = down, 2 = left, 3 = right */
+) {
+ color2d c;
+
+ add_char_imp(s, xinc, yinc, fo, ch, 0.0, 0.0, h, or, c, 0);
+}
+
+/* Add a string from the given location using lines. */
+/* Return the total width of the string */
+void add_string2d(
+render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char *string, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+int or, /* Orintation, 0 = right, 1 = down, 2 = left, 3 = right */
+color2d c /* Color of text */
+) {
+ char *ch;
+ double xoff = 0.0, yoff = 0.0;
+
+ for (ch = string; *ch != '\000'; ch++) {
+ add_char2d(s, &xoff, &yoff, fo, *ch, x + xoff, y + yoff, h, or, c);
+ }
+
+ if (xinc != NULL)
+ *xinc = xoff;
+ if (yinc != NULL)
+ *yinc = yoff;
+}
+
+/* Return the total width of the string without adding it */
+void meas_string2d(
+struct _render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char *string, /* Character code to be printed */
+double h, /* Height of text in normal orientation */
+int or /* Orintation, 0 = right, 1 = down, 2 = left, 3 = right */
+) {
+ char *ch;
+ double xoff = 0.0, yoff = 0.0;
+
+ for (ch = string; *ch != '\000'; ch++) {
+ meas_char2d(s, &xoff, &yoff, fo, *ch, h, or);
+ }
+
+ if (xinc != NULL)
+ *xinc = xoff;
+ if (yinc != NULL)
+ *yinc = yoff;
+}
+
+/* ==================================================== */
+/* Misc. support functions. */
+
+/*
+ Matrix Inversion
+ by Richard Carling
+ from "Graphics Gems", Academic Press, 1990
+*/
+
+/*
+ * adjoint( original_matrix, inverse_matrix )
+ *
+ * calculate the adjoint of a 3x3 matrix
+ *
+ * Let a denote the minor determinant of matrix A obtained by
+ * ij
+ *
+ * deleting the ith row and jth column from A.
+ *
+ * i+j
+ * Let b = (-1) a
+ * ij ji
+ *
+ * The matrix B = (b ) is the adjoint of A
+ * ij
+ */
+
+#define det2x2(a, b, c, d) (a * d - b * c)
+
+static void adjoint(
+double out[3][3],
+double in[3][3]
+) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+
+ /* assign to individual variable names to aid */
+ /* selecting correct values */
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ /* row column labeling reversed since we transpose rows & columns */
+
+ out[0][0] = det2x2(b2, b3, c2, c3);
+ out[1][0] = - det2x2(a2, a3, c2, c3);
+ out[2][0] = det2x2(a2, a3, b2, b3);
+
+ out[0][1] = - det2x2(b1, b3, c1, c3);
+ out[1][1] = det2x2(a1, a3, c1, c3);
+ out[2][1] = - det2x2(a1, a3, b1, b3);
+
+ out[0][2] = det2x2(b1, b2, c1, c2);
+ out[1][2] = - det2x2(a1, a2, c1, c2);
+ out[2][2] = det2x2(a1, a2, b1, b2);
+}
+
+/*
+ * double = det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3 )
+ *
+ * calculate the determinant of a 3x3 matrix
+ * in the form
+ *
+ * | a1, b1, c1 |
+ * | a2, b2, c2 |
+ * | a3, b3, c3 |
+ */
+
+static double det3x3(double in[3][3]) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+ double ans;
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ ans = a1 * det2x2(b2, b3, c2, c3)
+ - b1 * det2x2(a2, a3, c2, c3)
+ + c1 * det2x2(a2, a3, b2, b3);
+ return ans;
+}
+
+#define SMALL_NUMBER 1.e-8
+/*
+ * inverse( original_matrix, inverse_matrix )
+ *
+ * calculate the inverse of a 4x4 matrix
+ *
+ * -1
+ * A = ___1__ adjoint A
+ * det A
+ */
+
+/* Return non-zero if not invertable */
+static int inverse3x3(
+double out[3][3],
+double in[3][3]
+) {
+ int i, j;
+ double det;
+
+ /* calculate the 3x3 determinant
+ * if the determinant is zero,
+ * then the inverse matrix is not unique.
+ */
+ det = det3x3(in);
+
+ if ( fabs(det) < SMALL_NUMBER)
+ return 1;
+
+ /* calculate the adjoint matrix */
+ adjoint(out, in);
+
+ /* scale the adjoint matrix to get the inverse */
+ for (i = 0; i < 3; i++)
+ for(j = 0; j < 3; j++)
+ out[i][j] /= det;
+ return 0;
+}
+
+/* ==================================================== */
+// Hershey.C
+// extracted from the hershey font
+//
+// Charles Schwieters 6/14/99
+// Various tweaks and updates by John Stone
+//
+// font info:
+//
+//Peter Holzmann, Octopus Enterprises
+//USPS: 19611 La Mar Court, Cupertino, CA 95014
+//UUCP: {hplabs!hpdsd,pyramid}!octopus!pete
+//Phone: 408/996-7746
+//
+//This distribution is made possible through the collective encouragement
+//of the Usenet Font Consortium, a mailing list that sprang to life to get
+//this accomplished and that will now most likely disappear into the mists
+//of time... Thanks are especially due to Jim Hurt, who provided the packed
+//font data for the distribution, along with a lot of other help.
+//
+//This file describes the Hershey Fonts in general, along with a description of
+//the other files in this distribution and a simple re-distribution restriction.
+//
+//USE RESTRICTION:
+// This distribution of the Hershey Fonts may be used by anyone for
+// any purpose, commercial or otherwise, providing that:
+// 1. The following acknowledgements must be distributed with
+// the font data:
+// - The Hershey Fonts were originally created by Dr.
+// A. V. Hershey while working at the U. S.
+// National Bureau of Standards.
+// - The format of the Font data in this distribution
+// was originally created by
+// James Hurt
+// Cognition, Inc.
+// 900 Technology Park Drive
+// Billerica, MA 01821
+// (mit-eddie!ci-dandelion!hurt)
+// 2. The font data in this distribution may be converted into
+// any other format *EXCEPT* the format distributed by
+// the U.S. NTIS (which organization holds the rights
+// to the distribution and use of the font data in that
+// particular format). Not that anybody would really
+// *want* to use their format... each point is described
+// in eight bytes as "xxx yyy:", where xxx and yyy are
+// the coordinate values as ASCII numbers.
+//
+
+/*
+ * The Hershey romans font in ascii order (first 32 places held by space)
+ * NOTE: This font has been modified to yield fixed-width numeric
+ * characters. This makes it possible to produce justified numeric
+ * text that correctly lines up in columns.
+ * The font was specifically changed for:
+ * ' ' (ascii 32), '+' (ascii 43), '-' (ascii 45), and '.' (ascii 46)
+ */
+
+hyfont fonts[] = {
+{
+ "Rowman Single",
+ 0.040, /* X scale */
+ 0.040, /* Y scale */
+ 0.95, /* X spacing extra scale */
+ 0.08, /* Line width scale */
+ 1.1, /* horizontal offset */
+ 11.0, /* vertical offset */
+ {
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "MWRFRT RRYQZR[SZRY",
+ "JZNFNM RVFVM",
+ "H]SBLb RYBRb RLOZO RKUYU",
+ "H\\PBP_ RTBT_ RYIWGTFPFMGKIKKLMMNOOUQWRXSYUYXWZT[P[MZKX",
+ "F^[FI[ RNFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F RWTUUTWTYV[X[ZZ[X[VYTWT",
+ "E_\\O\\N[MZMYNXPVUTXRZP[L[JZIYHWHUISJRQNRMSKSIRGPFNGMIMKNNPQUXWZY[",
+ "MWRHQGRFSGSIRKQL",
+ "KYVBTDRGPKOPOTPYR]T`Vb",
+ "KYNBPDRGTKUPUTTYR]P`Nb",
+ "JZRLRX RMOWU RWOMU",
+ "E_RIR[ RIR[R",
+ "NVSWRXQWRVSWSYQ[",
+ "E_IR[R",
+ "NVRVQWRXSWRV",
+ "G][BIb",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF",
+ "H\\NJPISFS[",
+ "H\\LKLJMHNGPFTFVGWHXJXLWNUQK[Y[",
+ "H\\MFXFRNUNWOXPYSYUXXVZS[P[MZLYKW",
+ "H\\UFKTZT RUFU[",
+ "H\\WFMFLOMNPMSMVNXPYSYUXXVZS[P[MZLYKW",
+ "H\\XIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQLT",
+ "H\\YFO[ RKFYF",
+ "H\\PFMGLILKMMONSOVPXRYTYWXYWZT[P[MZLYKWKTLRNPQOUNWMXKXIWGTFPF",
+ "H\\XMWPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLX",
+ "NVROQPRQSPRO RRVQWRXSWRV",
+ "NVROQPRQSPRO RSWRXQWRVSWSYQ[",
+ "F^ZIJRZ[",
+ "E_IO[O RIU[U",
+ "F^JIZRJ[",
+ "I[LKLJMHNGPFTFVGWHXJXLWNVORQRT RRYQZR[SZRY",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS RQKOMNPNSOUPV RWKVSVUXVZV\\T]Q]O\\L[J",
+ "I[RFJ[ RRFZ[ RMTWT",
+ "G\\KFK[ RKFTFWGXHYJYLXNWOTP RKPTPWQXRYTYWXYWZT[K[",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV",
+ "G\\KFK[ RKFRFUGWIXKYNYSXVWXUZR[K[",
+ "H[LFL[ RLFYF RLPTP RL[Y[",
+ "HZLFL[ RLFYF RLPTP",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZS RUSZS",
+ "G]KFK[ RYFY[ RKPYP",
+ "NVRFR[",
+ "JZVFVVUYTZR[P[NZMYLVLT",
+ "G\\KFK[ RYFKT RPOY[",
+ "HYLFL[ RL[X[",
+ "F^JFJ[ RJFR[ RZFR[ RZFZ[",
+ "G]KFK[ RKFY[ RYFY[",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF",
+ "G\\KFK[ RKFTFWGXHYJYMXOWPTQKQ",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF RSWY]",
+ "G\\KFK[ RKFTFWGXHYJYLXNWOTPKP RRPY[",
+ "H\\YIWGTFPFMGKIKKLMMNOOUQWRXSYUYXWZT[P[MZKX",
+ "JZRFR[ RKFYF",
+ "G]KFKULXNZQ[S[VZXXYUYF",
+ "I[JFR[ RZFR[",
+ "F^HFM[ RRFM[ RRFW[ R\\FW[",
+ "H\\KFY[ RYFK[",
+ "I[JFRPR[ RZFRP",
+ "H\\YFK[ RKFYF RK[Y[",
+ "KYOBOb RPBPb ROBVB RObVb",
+ "KYKFY^",
+ "KYTBTb RUBUb RNBUB RNbUb",
+ "JZRDJR RRDZR",
+ "I[Ib[b",
+ "NVSKQMQORPSORNQO",
+ "I\\XMX[ RXPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "H[LFL[ RLPNNPMSMUNWPXSXUWXUZS[P[NZLX",
+ "I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I\\XFX[ RXPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I[LSXSXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "MYWFUFSGRJR[ ROMVM",
+ "I\\XMX]W`VaTbQbOa RXPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I\\MFM[ RMQPNRMUMWNXQX[",
+ "NVQFRGSFREQF RRMR[",
+ "MWRFSGTFSERF RSMS^RaPbNb",
+ "IZMFM[ RWMMW RQSX[",
+ "NVRFR[",
+ "CaGMG[ RGQJNLMOMQNRQR[ RRQUNWMZM\\N]Q][",
+ "I\\MMM[ RMQPNRMUMWNXQX[",
+ "I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM",
+ "H[LMLb RLPNNPMSMUNWPXSXUWXUZS[P[NZLX",
+ "I\\XMXb RXPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "KXOMO[ ROSPPRNTMWM",
+ "J[XPWNTMQMNNMPNRPSUTWUXWXXWZT[Q[NZMX",
+ "MYRFRWSZU[W[ ROMVM",
+ "I\\MMMWNZP[S[UZXW RXMX[",
+ "JZLMR[ RXMR[",
+ "G]JMN[ RRMN[ RRMV[ RZMV[",
+ "J[MMX[ RXMM[",
+ "JZLMR[ RXMR[P_NaLbKb",
+ "J[XMM[ RMMXM RM[X[",
+ "KYTBRCQDPFPHQJRKSMSOQQ RRCQEQGRISJTLTNSPORSTTVTXSZR[Q]Q_Ra RQSSU",
+ "NVRBRb",
+ "KYPBRCSDTFTHSJRKQMQOSQ RRCSESGRIQJPLPNQPURQTPVPXQZR[S]S_Ra RSSQU",
+ "F^IUISJPLONOPPTSVTXTZS[Q RISJQLPNPPQTTVUXUZT[Q[O",
+ "JZJFJ[K[KFLFL[M[MFNFN[O[OFPFP[Q[QFRFR[S[SFTFT[U[UFVFV[W[WFXFX[Y[YFZFZ["
+ }
+},
+{
+ "Rowman Double",
+ 0.040, /* X scale */
+ 0.040, /* Y scale */
+ 0.95, /* X spacing extra scale */
+ 0.08, /* Line width scale */
+ 0.0, /* horizontal offset */
+ 11.0, /* vertical offset */
+ {
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "MXRFRTST RRFSFST RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "I[NFMGMM RNGMM RNFOGMM RWFVGVM RWGVM RWFXGVM",
+ "H]SFLb RYFRb RLQZQ RKWYW",
+ "I\\RBR_S_ RRBSBS_ RWIYIWGTFQFNGLILKMMNNVRWSXUXWWYTZQZOYNX RWIVHTGQGNHMIMKNMVQXSYUYWXYWZT[Q[NZLXNX RXXUZ",
+ "F^[FI[ RNFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F RWTUUTWTYV[X[ZZ[X[VYTWT",
+ "F_\\MZMXNWPUVTXSYQZMZKYJWJUKSLRQOSMTKTISGQFPFNGMIMKNNPQUWXZZ[\\[ R\\M\\NZNXO RYNXPVVUXSZQ[M[KZJYIWIUJSLQQNRMSKSIRG RSHQGPGNH ROGNINKONQQVWXYZZ\\Z\\[",
+ "MXTHSIRIQHQGRFSFTGTJSLQM RRGRHSHSGRG RSITJ RTHSL",
+ "KYUBSDQGOKNPNTOYQ]S`UbVb RUBVBTDRGPKOPOTPYR]T`Vb",
+ "KYNBPDRGTKUPUTTYR]P`NbOb RNBOBQDSGUKVPVTUYS]Q`Ob",
+ "JZRFQGSQRR RRFRR RRFSGQQRR RMINIVOWO RMIWO RMIMJWNWO RWIVINOMO RWIMO RWIWJMNMO",
+ "F_RIRZSZ RRISISZ RJQ[Q[R RJQJR[R",
+ "MXTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^",
+ "F_JQ[Q[R RJQJR[R",
+ "MXRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "G^[BIbJb R[B\\BJb",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF ROGMJLOLRMWOZ RNYQZSZVY RUZWWXRXOWJUG RVHSGQGNH",
+ "H\\NJPISFS[ RNJNKPJRHR[S[",
+ "H\\LKLJMHNGPFTFVGWHXJXLWNUQL[ RLKMKMJNHPGTGVHWJWLVNTQK[ RLZYZY[ RK[Y[",
+ "H\\MFXFQO RMFMGWG RWFPO RQNSNVOXQYTYUXXVZS[P[MZLYKWLW RPOSOVPXS RTOWQXTXUWXTZ RXVVYSZPZMYLW ROZLX",
+ "H\\UIU[V[ RVFV[ RVFKVZV RUILV RLUZUZV",
+ "H\\MFLO RNGMN RMFWFWG RNGWG RMNPMSMVNXPYSYUXXVZS[P[MZLYKWLW RLOMOONSNVOXR RTNWPXSXUWXTZ RXVVYSZPZMYLW ROZLX",
+ "H\\VGWIXIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQ RWHTGRGOH RPGNJMOMTNXQZ RMVOYRZSZVYXV RTZWXXUXTWQTO RXSVPSOROOPMS RQONQMT",
+ "H\\KFYFO[ RKFKGXG RXFN[O[",
+ "H\\PFMGLILKMMNNPOTPVQWRXTXWWYTZPZMYLWLTMRNQPPTOVNWMXKXIWGTFPF RNGMIMKNMPNTOVPXRYTYWXYWZT[P[MZLYKWKTLRNPPOTNVMWKWIVG RWHTGPGMH RLXOZ RUZXX",
+ "H\\WPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLXMXNZ RWMVPSR RWNUQRRQRNQLN RPRMPLMLLMIPG RLKNHQGRGUHWK RSGVIWMWRVWTZ RUYRZPZMY",
+ "MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^",
+ "F^ZIJRZ[",
+ "F_JM[M[N RJMJN[N RJU[U[V RJUJV[V",
+ "F^JIZRJ[",
+ "I\\LKLJMHNGQFTFWGXHYJYLXNWOUPRQ RLKMKMJNHQGTGWHXJXLWNUORP RMIPG RUGXI RXMTP RRPRTSTSP RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS RQKOMNPNSOUPV RWKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX RXKWSWUXV",
+ "H\\RFJ[ RRIK[J[ RRIY[Z[ RRFZ[ RMUWU RLVXV",
+ "H\\LFL[ RMGMZ RLFTFWGXHYJYMXOWPTQ RMGTGWHXJXMWOTP RMPTPWQXRYTYWXYWZT[L[ RMQTQWRXTXWWYTZMZ",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV RZKYKXIWHUGQGOHMKLNLSMVOYQZUZWYXXYVZV",
+ "H]LFL[ RMGMZ RLFSFVGXIYKZNZSYVXXVZS[L[ RMGSGVHWIXKYNYSXVWXVYSZMZ",
+ "I\\MFM[ RNGNZ RMFYF RNGYGYF RNPTPTQ RNQTQ RNZYZY[ RM[Y[",
+ "I[MFM[ RNGN[M[ RMFYF RNGYGYF RNPTPTQ RNQTQ",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZRUR RZKYKXIWHUGQGOHNIMKLNLSMVNXOYQZUZWYXXYVYSUSUR",
+ "G]KFK[ RKFLFL[K[ RYFXFX[Y[ RYFY[ RLPXP RLQXQ",
+ "NWRFR[S[ RRFSFS[",
+ "J[VFVVUYSZQZOYNVMV RVFWFWVVYUZS[Q[OZNYMV",
+ "H]LFL[M[ RLFMFM[ RZFYFMR RZFMS RPOY[Z[ RQOZ[",
+ "IZMFM[ RMFNFNZ RNZYZY[ RM[Y[",
+ "F^JFJ[ RKKK[J[ RKKR[ RJFRX RZFRX RYKR[ RYKY[Z[ RZFZ[",
+ "G]KFK[ RLIL[K[ RLIY[ RKFXX RXFXX RXFYFY[",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF RQGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG",
+ "H\\LFL[ RMGM[L[ RLFUFWGXHYJYMXOWPUQMQ RMGUGWHXJXMWOUPMP",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF RQGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG RSXX]Y] RSXTXY]",
+ "H\\LFL[ RMGM[L[ RLFTFWGXHYJYMXOWPTQMQ RMGTGWHXJXMWOTPMP RRQX[Y[ RSQY[",
+ "H\\YIWGTFPFMGKIKKLMMNOOTQVRWSXUXXWYTZPZNYMXKX RYIWIVHTGPGMHLILKMMONTPVQXSYUYXWZT[P[MZKX",
+ "J[RGR[ RSGS[R[ RLFYFYG RLFLGYG",
+ "G]KFKULXNZQ[S[VZXXYUYF RKFLFLUMXNYQZSZVYWXXUXFYF",
+ "H\\JFR[ RJFKFRX RZFYFRX RZFR[",
+ "E_GFM[ RGFHFMX RRFMX RRIM[ RRIW[ RRFWX R]F\\FWX R]FW[",
+ "H\\KFX[Y[ RKFLFY[ RYFXFK[ RYFL[K[",
+ "I\\KFRPR[S[ RKFLFSP RZFYFRP RZFSPS[",
+ "H\\XFK[ RYFL[ RKFYF RKFKGXG RLZYZY[ RK[Y[",
+ "KYOBOb RPBPb ROBVB RObVb",
+ "KYKFY^",
+ "KYTBTb RUBUb RNBUB RNbUb",
+ "JZPLRITL RMORJWO RRJR[",
+ "JZJ]Z]",
+ "MXTFRGQIQLRMSMTLTKSJRJQK RRKRLSLSKRK RRGQK RQIRJ",
+ "H\\WMW[X[ RWMXMX[ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX",
+ "H\\LFL[M[ RLFMFM[ RMPONQMTMVNXPYSYUXXVZT[Q[OZMX RMPQNTNVOWPXSXUWXVYTZQZMX",
+ "I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX RXPWQVOTNQNOONPMSMUNXOYQZTZVYWWXX",
+ "H\\WFW[X[ RWFXFX[ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX",
+ "I[MTXTXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX RMSWSWQVOTNQNOONPMSMUNXOYQZTZVYWWXX",
+ "LZWFUFSGRJR[S[ RWFWGUGSH RTGSJS[ ROMVMVN ROMONVN",
+ "H\\XMWMW\\V_U`SaQaO`N_L_ RXMX\\W_UaSbPbNaL_ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX",
+ "H\\LFL[M[ RLFMFM[ RMQPNRMUMWNXQX[ RMQPORNTNVOWQW[X[",
+ "NWRFQGQHRISITHTGSFRF RRGRHSHSGRG RRMR[S[ RRMSMS[",
+ "NWRFQGQHRISITHTGSFRF RRGRHSHSGRG RRMRbSb RRMSMSb",
+ "H[LFL[M[ RLFMFM[ RXMWMMW RXMMX RPTV[X[ RQSX[",
+ "NWRFR[S[ RRFSFS[",
+ "CbGMG[H[ RGMHMH[ RHQKNMMPMRNSQS[ RHQKOMNONQORQR[S[ RSQVNXM[M]N^Q^[ RSQVOXNZN\\O]Q][^[",
+ "H\\LML[M[ RLMMMM[ RMQPNRMUMWNXQX[ RMQPORNTNVOWQW[X[",
+ "I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM RQNOONPMSMUNXOYQZTZVYWXXUXSWPVOTNQN",
+ "H\\LMLbMb RLMMMMb RMPONQMTMVNXPYSYUXXVZT[Q[OZMX RMPQNTNVOWPXSXUWXVYTZQZMX",
+ "H\\WMWbXb RWMXMXb RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX",
+ "KYOMO[P[ ROMPMP[ RPSQPSNUMXM RPSQQSOUNXNXM",
+ "J[XPWNTMQMNNMPNRPSUUWV RVUWWWXVZ RWYTZQZNY ROZNXMX RXPWPVN RWOTNQNNO RONNPOR RNQPRUTWUXWXXWZT[Q[NZMX",
+ "MXRFR[S[ RRFSFS[ ROMVMVN ROMONVN",
+ "H\\LMLWMZO[R[TZWW RLMMMMWNYPZRZTYWW RWMW[X[ RWMXMX[",
+ "JZLMR[ RLMMMRY RXMWMRY RXMR[",
+ "F^IMN[ RIMJMNX RRMNX RRPN[ RRPV[ RRMVX R[MZMVX R[MV[",
+ "I[LMW[X[ RLMMMX[ RXMWML[ RXMM[L[",
+ "JZLMR[ RLMMMRY RXMWMRYNb RXMR[ObNb",
+ "I[VNL[ RXMNZ RLMXM RLMLNVN RNZXZX[ RL[X[",
+ "KYTBRCQDPFPHQJRKSMSOQQ RRCQEQGRISJTLTNSPORSTTVTXSZR[Q]Q_Ra RQSSUSWRYQZP\\P^Q`RaTb",
+ "NVRBRb",
+ "KYPBRCSDTFTHSJRKQMQOSQ RRCSESGRIQJPLPNQPURQTPVPXQZR[S]S_Ra RSSQUQWRYSZT\\T^S`RaPb",
+ "F^IUISJPLONOPPTSVTXTZS[Q RISJQLPNPPQTTVUXUZT[Q[O",
+ "KYQFOGNINKOMQNSNUMVKVIUGSFQF RQFNIOMSNVKUGQF RSFOGNKQNUMVISF"
+ }
+},
+{
+ "Rowman Triple",
+ 0.040, /* X scale */
+ 0.040, /* Y scale */
+ 0.96, /* X spacing extra scale */
+ 0.08, /* Line width scale */
+ 0.3, /* horizontal offset */
+ 11.0, /* vertical offset */
+ {
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "MXRFQGQIRQ RRFRTST RRFSFST RSFTGTISQ RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "I[NFMGMM RNGMM RNFOGMM RWFVGVM RWGVM RWFXGVM",
+ "H]SFLb RYFRb RLQZQ RKWYW",
+ "H\\PBP_ RTBT_ RXKXJWJWLYLYJXHWGTFPFMGKIKLLNOPURWSXUXXWZ RLLMNOOUQWRXT RMGLILKMMONUPXRYTYWXYWZT[P[MZLYKWKUMUMWLWLV",
+ "F^[FI[ RNFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F RWTUUTWTYV[X[ZZ[X[VYTWT",
+ "E_[O[NZNZP\\P\\N[MZMYNXPVUTXRZP[L[JZIXIUJSPORMSKSIRGPFNGMIMLNOPRTWWZY[[[\\Y\\X RKZJXJUKSLR RRMSI RSKRG RNGMK RNNPQTVWYYZ RN[LZKXKULSPO RMINMQQUVXYZZ[Z\\Y",
+ "MXTHSIRIQHQGRFSFTGTJSLQM RRGRHSHSGRG RSITJ RTHSL",
+ "KYUBSDQGOKNPNTOYQ]S`Ub RQHPKOOOUPYQ\\ RSDRFQIPOPUQ[R^S`",
+ "KYOBQDSGUKVPVTUYS]Q`Ob RSHTKUOUUTYS\\ RQDRFSITOTUS[R^Q`",
+ "JZRFQGSQRR RRFRR RRFSGQQRR RMINIVOWO RMIWO RMIMJWNWO RWIVINOMO RWIMO RWIWJMNMO",
+ "F_RIRZSZ RRISISZ RJQ[Q[R RJQJR[R",
+ "MXTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^",
+ "F_JQ[Q[R RJQJR[R",
+ "MXRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "G^[BIbJb R[B\\BJb",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF RNHMJLNLSMWNY RVYWWXSXNWJVH RQFOGNIMNMSNXOZQ[ RS[UZVXWSWNVIUGSF",
+ "H\\QHQ[ RRHRZ RSFS[ RSFPINJ RM[W[ RQZO[ RQYP[ RSYT[ RSZU[",
+ "H\\LJLKMKMJLJ RLIMINJNKMLLLKKKJLHMGPFTFWGXHYJYLXNUPPRNSLUKXK[ RWHXJXLWN RTFVGWJWLVNTPPR RKYLXNXSYWYYX RNXSZWZXY RNXS[W[XZYXYV",
+ "H\\LJLKMKMJLJ RLIMINJNKMLLLKKKJLHMGPFTFWGXIXLWNTO RVGWIWLVN RSFUGVIVLUNSO RQOTOVPXRYTYWXYWZT[P[MZLYKWKVLUMUNVNWMXLX RWRXTXWWY RSOUPVQWTWWVZT[ RLVLWMWMVLV",
+ "H\\SIS[ RTHTZ RUFU[ RUFJUZU RP[X[ RSZQ[ RSYR[ RUYV[ RUZW[",
+ "H\\MFKPMNPMSMVNXPYSYUXXVZS[P[MZLYKWKVLUMUNVNWMXLX RWPXRXVWX RSMUNVOWRWVVYUZS[ RLVLWMWMVLV RMFWF RMGUG RMHQHUGWF",
+ "H\\VIVJWJWIVI RWHVHUIUJVKWKXJXIWGUFRFOGMILKKOKULXNZQ[S[VZXXYUYTXQVOSNQNOONPMR RNIMKLOLUMXNY RWXXVXSWQ RRFPGOHNJMNMUNXOZQ[ RS[UZVYWVWSVPUOSN",
+ "H\\KFKL RYFYIXLTQSSRWR[ RSRRTQWQ[ RXLSQQTPWP[R[ RKJLHNFPFUIWIXHYF RMHNGPGRH RKJLINHPHUI",
+ "H\\PFMGLILLMNPOTOWNXLXIWGTFPF RNGMIMLNN RVNWLWIVG RPFOGNINLONPO RTOUNVLVIUGTF RPOMPLQKSKWLYMZP[T[WZXYYWYSXQWPTO RMQLSLWMY RWYXWXSWQ RPONPMSMWNZP[ RT[VZWWWSVPTO",
+ "H\\MWMXNXNWMW RWOVQURSSQSNRLPKMKLLINGQFSFVGXIYLYRXVWXUZR[O[MZLXLWMVNVOWOXNYMY RMPLNLKMI RVHWIXLXRWVVX RQSORNQMNMKNHOGQF RSFUGVIWLWSVWUYTZR[",
+ "MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^",
+ "F^ZIJRZ[",
+ "F_JM[M[N RJMJN[N RJU[U[V RJUJV[V",
+ "F^JIZRJ[",
+ "I\\MKMJNJNLLLLJMHNGPFTFWGXHYJYLXNWOSQ RWHXIXMWN RTFVGWIWMVOUP RRQRTSTSQRQ RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS RQKOMNPNSOUPV RWKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX RXKWSWUXV",
+ "H\\RFKZ RQIW[ RRIX[ RRFY[ RMUVU RI[O[ RT[[[ RKZJ[ RKZM[ RWZU[ RWYV[ RXYZ[",
+ "G]LFL[ RMGMZ RNFN[ RIFUFXGYHZJZLYNXOUP RXHYJYLXN RUFWGXIXMWOUP RNPUPXQYRZTZWYYXZU[I[ RXRYTYWXY RUPWQXSXXWZU[ RJFLG RKFLH ROFNH RPFNG RLZJ[ RLYK[ RNYO[ RNZP[",
+ "G\\XIYFYLXIVGTFQFNGLIKKJNJSKVLXNZQ[T[VZXXYV RMILKKNKSLVMX RQFOGMJLNLSMWOZQ[",
+ "G]LFL[ RMGMZ RNFN[ RIFSFVGXIYKZNZSYVXXVZS[I[ RWIXKYNYSXVWX RSFUGWJXNXSWWUZS[ RJFLG RKFLH ROFNH RPFNG RLZJ[ RLYK[ RNYO[ RNZP[",
+ "G\\LFL[ RMGMZ RNFN[ RIFYFYL RNPTP RTLTT RI[Y[YU RJFLG RKFLH ROFNH RPFNG RTFYG RVFYH RWFYI RXFYL RTLSPTT RTNRPTR RTOPPTQ RLZJ[ RLYK[ RNYO[ RNZP[ RT[YZ RV[YY RW[YX RX[YU",
+ "G[LFL[ RMGMZ RNFN[ RIFYFYL RNPTP RTLTT RI[Q[ RJFLG RKFLH ROFNH RPFNG RTFYG RVFYH RWFYI RXFYL RTLSPTT RTNRPTR RTOPPTQ RLZJ[ RLYK[ RNYO[ RNZP[",
+ "G^XIYFYLXIVGTFQFNGLIKKJNJSKVLXNZQ[T[VZXZY[YS RMILKKNKSLVMX RQFOGMJLNLSMWOZQ[ RXTXY RWSWYVZ RTS\\S RUSWT RVSWU RZSYU R[SYT",
+ "F^KFK[ RLGLZ RMFM[ RWFW[ RXGXZ RYFY[ RHFPF RTF\\F RMPWP RH[P[ RT[\\[ RIFKG RJFKH RNFMH ROFMG RUFWG RVFWH RZFYH R[FYG RKZI[ RKYJ[ RMYN[ RMZO[ RWZU[ RWYV[ RYYZ[ RYZ[[",
+ "LXQFQ[ RRGRZ RSFS[ RNFVF RN[V[ ROFQG RPFQH RTFSH RUFSG RQZO[ RQYP[ RSYT[ RSZU[",
+ "JYSFSWRZQ[ RTGTWSZ RUFUWTZQ[O[MZLXLVMUNUOVOWNXMX RMVMWNWNVMV RPFXF RQFSG RRFSH RVFUH RWFUG",
+ "F]KFK[ RLGLZ RMFM[ RXGMR RPPW[ RQPX[ RQNY[ RHFPF RUF[F RH[P[ RT[[[ RIFKG RJFKH RNFMH ROFMG RWFXG RZFXG RKZI[ RKYJ[ RMYN[ RMZO[ RWYU[ RWYZ[",
+ "I[NFN[ ROGOZ RPFP[ RKFSF RK[Z[ZU RLFNG RMFNH RQFPH RRFPG RNZL[ RNYM[ RPYQ[ RPZR[ RU[ZZ RW[ZY RX[ZX RY[ZU",
+ "E_JFJZ RJFQ[ RKFQX RLFRX RXFQ[ RXFX[ RYGYZ RZFZ[ RGFLF RXF]F RG[M[ RU[][ RHFJG R[FZH R\\FZG RJZH[ RJZL[ RXZV[ RXYW[ RZY[[ RZZ\\[",
+ "F^KFKZ RKFY[ RLFXX RMFYX RYGY[ RHFMF RVF\\F RH[N[ RIFKG RWFYG R[FYG RKZI[ RKZM[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF RMILKKNKSLVMX RWXXVYSYNXKWI RQFOGMJLNLSMWOZQ[ RS[UZWWXSXNWJUGSF",
+ "G]LFL[ RMGMZ RNFN[ RIFUFXGYHZJZMYOXPUQNQ RXHYJYMXO RUFWGXIXNWPUQ RI[Q[ RJFLG RKFLH ROFNH RPFNG RLZJ[ RLYK[ RNYO[ RNZP[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF RMILKKNKSLVMX RWXXVYSYNXKWI RQFOGMJLNLSMWOZQ[ RS[UZWWXSXNWJUGSF RNXOVQURUTVUXV^W`Y`Z^Z\\ RV\\W^X_Y_ RUXW]X^Y^Z]",
+ "G]LFL[ RMGMZ RNFN[ RIFUFXGYHZJZLYNXOUPNP RXHYJYLXN RUFWGXIXMWOUP RRPTQUSWYX[Z[[Y[W RWWXYYZZZ RTQURXXYYZY[X RI[Q[ RJFLG RKFLH ROFNH RPFNG RLZJ[ RLYK[ RNYO[ RNZP[",
+ "H\\XIYFYLXIVGSFPFMGKIKLLNOPURWSXUXXWZ RLLMNOOUQWRXT RMGLILKMMONUPXRYTYWXYWZT[Q[NZLXKUK[LX",
+ "H\\JFJL RQFQ[ RRGRZ RSFS[ RZFZL RJFZF RN[V[ RKFJL RLFJI RMFJH ROFJG RUFZG RWFZH RXFZI RYFZL RQZO[ RQYP[ RSYT[ RSZU[",
+ "F^KFKULXNZQ[S[VZXXYUYG RLGLVMX RMFMVNYOZQ[ RHFPF RVF\\F RIFKG RJFKH RNFMH ROFMG RWFYG R[FYG",
+ "H\\KFR[ RLFRXR[ RMFSX RYGR[ RIFPF RUF[F RJFLH RNFMH ROFMG RWFYG RZFYG",
+ "F^JFN[ RKFNVN[ RLFOV RRFOVN[ RRFV[ RSFVVV[ RTFWV RZGWVV[ RGFOF RRFTF RWF]F RHFKG RIFKH RMFLH RNFLG RXFZG R\\FZG",
+ "H\\KFW[ RLFX[ RMFY[ RXGLZ RIFPF RUF[F RI[O[ RT[[[ RJFMH RNFMH ROFMG RVFXG RZFXG RLZJ[ RLZN[ RWZU[ RWYV[ RWYZ[",
+ "G]JFQQQ[ RKFRQRZ RLFSQS[ RYGSQ RHFOF RVF\\F RN[V[ RIFKG RNFLG RWFYG R[FYG RQZO[ RQYP[ RSYT[ RSZU[",
+ "H\\YFKFKL RWFK[ RXFL[ RYFM[ RK[Y[YU RLFKL RMFKI RNFKH RPFKG RT[YZ RV[YY RW[YX RX[YU",
+ "KYOBOb RPBPb ROBVB RObVb",
+ "KYKFY^",
+ "KYTBTb RUBUb RNBUB RNbUb",
+ "JZPLRITL RMORJWO RRJR[",
+ "JZJ]Z]",
+ "MXTFRGQIQLRMSMTLTKSJRJQK RRKRLSLSKRK RRGQK RQIRJ",
+ "I]NPNOOOOQMQMONNPMTMVNWOXQXXYZZ[ RVOWQWXXZ RTMUNVPVXWZZ[[[ RVRUSPTMULWLXMZP[S[UZVX RNUMWMXNZ RUSQTOUNWNXOZP[",
+ "G\\LFL[MZOZ RMGMY RIFNFNZ RNPONQMSMVNXPYSYUXXVZS[Q[OZNX RWPXRXVWX RSMUNVOWRWVVYUZS[ RJFLG RKFLH",
+ "H[WQWPVPVRXRXPVNTMQMNNLPKSKULXNZQ[S[VZXX RMPLRLVMX RQMONNOMRMVNYOZQ[",
+ "H]VFV[[[ RWGWZ RSFXFX[ RVPUNSMQMNNLPKSKULXNZQ[S[UZVX RMPLRLVMX RQMONNOMRMVNYOZQ[ RTFVG RUFVH RXYY[ RXZZ[",
+ "H[MSXSXQWOVNSMQMNNLPKSKULXNZQ[S[VZXX RWRWQVO RMPLRLVMX RVSVPUNSM RQMONNOMRMVNYOZQ[",
+ "KYWHWGVGVIXIXGWFTFRGQHPKP[ RRHQKQZ RTFSGRIR[ RMMVM RM[U[ RPZN[ RPYO[ RRYS[ RRZT[",
+ "I\\XNYOZNYMXMVNUO RQMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM ROONQNSOU RUUVSVQUO RQMPNOPOTPVQW RSWTVUTUPTNSM RNUMVLXLYM[N\\Q]U]X^Y_ RN[Q\\U\\X] RLYMZP[U[X\\Y^Y_XaUbObLaK_K^L\\O[ RObMaL_L^M\\O[",
+ "G^LFL[ RMGMZ RIFNFN[ RNQOOPNRMUMWNXOYRY[ RWOXRXZ RUMVNWQW[ RI[Q[ RT[\\[ RJFLG RKFLH RLZJ[ RLYK[ RNYO[ RNZP[ RWZU[ RWYV[ RYYZ[ RYZ[[",
+ "LXQFQHSHSFQF RRFRH RQGSG RQMQ[ RRNRZ RNMSMS[ RN[V[ ROMQN RPMQO RQZO[ RQYP[ RSYT[ RSZU[",
+ "KXRFRHTHTFRF RSFSH RRGTG RRMR^QaPb RSNS]R` ROMTMT]S`RaPbMbLaL_N_NaMaM` RPMRN RQMRO",
+ "G]LFL[ RMGMZ RIFNFN[ RWNNW RRSY[ RRTX[ RQTW[ RTM[M RI[Q[ RT[[[ RJFLG RKFLH RUMWN RZMWN RLZJ[ RLYK[ RNYO[ RNZP[ RWYU[ RVYZ[",
+ "LXQFQ[ RRGRZ RNFSFS[ RN[V[ ROFQG RPFQH RQZO[ RQYP[ RSYT[ RSZU[",
+ "AcFMF[ RGNGZ RCMHMH[ RHQIOJNLMOMQNROSRS[ RQORRRZ ROMPNQQQ[ RSQTOUNWMZM\\N]O^R^[ R\\O]R]Z RZM[N\\Q\\[ RC[K[ RN[V[ RY[a[ RDMFN REMFO RFZD[ RFYE[ RHYI[ RHZJ[ RQZO[ RQYP[ RSYT[ RSZU[ R\\ZZ[ R\\Y[[ R^Y_[ R^Z`[",
+ "G^LML[ RMNMZ RIMNMN[ RNQOOPNRMUMWNXOYRY[ RWOXRXZ RUMVNWQW[ RI[Q[ RT[\\[ RJMLN RKMLO RLZJ[ RLYK[ RNYO[ RNZP[ RWZU[ RWYV[ RYYZ[ RYZ[[",
+ "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM RMPLRLVMX RWXXVXRWP RQMONNOMRMVNYOZQ[ RS[UZVYWVWRVOUNSM",
+ "G\\LMLb RMNMa RIMNMNb RNPONQMSMVNXPYSYUXXVZS[Q[OZNX RWPXRXVWX RSMUNVOWRWVVYUZS[ RIbQb RJMLN RKMLO RLaJb RL`Kb RN`Ob RNaPb",
+ "H\\VNVb RWOWa RUNWNXMXb RVPUNSMQMNNLPKSKULXNZQ[S[UZVX RMPLRLVMX RQMONNOMRMVNYOZQ[ RSb[b RVaTb RV`Ub RX`Yb RXaZb",
+ "IZNMN[ RONOZ RKMPMP[ RWOWNVNVPXPXNWMUMSNQPPS RK[S[ RLMNN RMMNO RNZL[ RNYM[ RPYQ[ RPZR[",
+ "J[WOXMXQWOVNTMPMNNMOMQNSPTUUWVXY RNNMQ RNRPSUTWU RXVWZ RMONQPRUSWTXVXYWZU[Q[OZNYMWM[NY",
+ "KZPHPVQYRZT[V[XZYX RQHQWRY RPHRFRWSZT[ RMMVM",
+ "G^LMLVMYNZP[S[UZVYWW RMNMWNY RIMNMNWOZP[ RWMW[\\[ RXNXZ RTMYMY[ RJMLN RKMLO RYYZ[ RYZ[[",
+ "I[LMR[ RMMRY RNMSY RXNSYR[ RJMQM RTMZM RKMNO RPMNN RVMXN RYMXN",
+ "F^JMN[ RKMNX RLMOX RRMOXN[ RRMV[ RSMVX RRMTMWX RZNWXV[ RGMOM RWM]M RHMKN RNMLN RXMZN R\\MZN",
+ "H\\LMV[ RMMW[ RNMX[ RWNMZ RJMQM RTMZM RJ[P[ RS[Z[ RKMMN RPMNN RUMWN RYMWN RMZK[ RMZO[ RVZT[ RWZY[",
+ "H[LMR[ RMMRY RNMSY RXNSYP_NaLbJbIaI_K_KaJaJ` RJMQM RTMZM RKMNO RPMNN RVMXN RYMXN",
+ "I[VML[ RWMM[ RXMN[ RXMLMLQ RL[X[XW RMMLQ RNMLP ROMLO RQMLN RS[XZ RU[XY RV[XX RW[XW",
+ "KYTBRCQDPFPHQJRKSMSOQQ RRCQEQGRISJTLTNSPORSTTVTXSZR[Q]Q_Ra RQSSUSWRYQZP\\P^Q`RaTb",
+ "NVRBRb",
+ "KYPBRCSDTFTHSJRKQMQOSQ RRCSESGRIQJPLPNQPURQTPVPXQZR[S]S_Ra RSSQUQWRYSZT\\T^S`RaPb",
+ "F^IUISJPLONOPPTSVTXTZS[Q RISJQLPNPPQTTVUXUZT[Q[O",
+ "KYQFOGNINKOMQNSNUMVKVIUGSFQF RQFNIOMSNVKUGQF RSFOGNKQNUMVISF"
+ }
+},
+{
+ "Times Roman",
+ 0.041, /* X scale */
+ 0.041, /* Y scale */
+ 0.95, /* X spacing extra scale */
+ 0.055, /* Line width scale */
+ 0.0, /* horizontal offset */
+ 10.5, /* vertical offset */
+ {
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "MWRFQHRTSHRF RRHRN RRYQZR[SZRY",
+ "I[NFMGMM RNGMM RNFOGMM RWFVGVM RWGVM RWFXGVM",
+ "H]SBLb RYBRb RLOZO RKUYU",
+ "H\\PBP_ RTBT_ RXIWJXKYJYIWGTFPFMGKIKKLMMNOOUQWRYT RKKMMONUPWQXRYTYXWZT[P[MZKXKWLVMWLX",
+ "F^[FI[ RNFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F RWTUUTWTYV[X[ZZ[X[VYTWT",
+ "F_[NZO[P\\O\\N[MZMYNXPVUTXRZP[M[JZIXIUJSPORMSKSIRGPFNGMIMKNNPQUXWZZ[[[\\Z\\Y RM[KZJXJUKSMQ RMKNMVXXZZ[",
+ "NVRFQM RSFQM",
+ "KYVBTDRGPKOPOTPYR]T`Vb RTDRHQKPPPTQYR\\T`",
+ "KYNBPDRGTKUPUTTYR]P`Nb RPDRHSKTPTTSYR\\P`",
+ "JZRLRX RMOWU RWOMU",
+ "E_RIR[ RIR[R",
+ "NVSWRXQWRVSWSYQ[",
+ "E_IR[R",
+ "NVRVQWRXSWRV",
+ "G][BIb",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF RQFOGNHMJLOLRMWNYOZQ[ RS[UZVYWWXRXOWJVHUGSF",
+ "H\\NJPISFS[ RRGR[ RN[W[",
+ "H\\LJMKLLKKKJLHMGPFTFWGXHYJYLXNUPPRNSLUKXK[ RTFVGWHXJXLWNTPPR RKYLXNXSZVZXYYX RNXS[W[XZYXYV",
+ "H\\LJMKLLKKKJLHMGPFTFWGXIXLWNTOQO RTFVGWIWLVNTO RTOVPXRYTYWXYWZT[P[MZLYKWKVLUMVLW RWQXTXWWYVZT[",
+ "H\\THT[ RUFU[ RUFJUZU RQ[X[",
+ "H\\MFKP RKPMNPMSMVNXPYSYUXXVZS[P[MZLYKWKVLUMVLW RSMUNWPXSXUWXUZS[ RMFWF RMGRGWF",
+ "H\\WIVJWKXJXIWGUFRFOGMILKKOKULXNZQ[S[VZXXYUYTXQVOSNRNOOMQLT RRFPGNIMKLOLUMXOZQ[ RS[UZWXXUXTWQUOSN",
+ "H\\KFKL RKJLHNFPFUIWIXHYF RLHNGPGUI RYFYIXLTQSSRVR[ RXLSQRSQVQ[",
+ "H\\PFMGLILLMNPOTOWNXLXIWGTFPF RPFNGMIMLNNPO RTOVNWLWIVGTF RPOMPLQKSKWLYMZP[T[WZXYYWYSXQWPTO RPONPMQLSLWMYNZP[ RT[VZWYXWXSWQVPTO",
+ "H\\XMWPURRSQSNRLPKMKLLINGQFSFVGXIYLYRXVWXUZR[O[MZLXLWMVNWMX RQSORMPLMLLMIOGQF RSFUGWIXLXRWVVXTZR[",
+ "NVROQPRQSPRO RRVQWRXSWRV",
+ "NVROQPRQSPRO RSWRXQWRVSWSYQ[",
+ "F^ZIJRZ[",
+ "E_IO[O RIU[U",
+ "F^JIZRJ[",
+ "I[MJNKMLLKLJMHNGPFSFVGWHXJXLWNVORQRT RSFUGVHWJWLVNTP RRYQZR[SZRY",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS RQKOMNPNSOUPV RWKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX RXKWSWUXV",
+ "H\\RFK[ RRFY[ RRIX[ RMUVU RI[O[ RU[[[",
+ "G]LFL[ RMFM[ RIFUFXGYHZJZLYNXOUP RUFWGXHYJYLXNWOUP RMPUPXQYRZTZWYYXZU[I[ RUPWQXRYTYWXYWZU[",
+ "G\\XIYLYFXIVGSFQFNGLIKKJNJSKVLXNZQ[S[VZXXYV RQFOGMILKKNKSLVMXOZQ[",
+ "G]LFL[ RMFM[ RIFSFVGXIYKZNZSYVXXVZS[I[ RSFUGWIXKYNYSXVWXUZS[",
+ "G\\LFL[ RMFM[ RSLST RIFYFYLXF RMPSP RI[Y[YUX[",
+ "G[LFL[ RMFM[ RSLST RIFYFYLXF RMPSP RI[P[",
+ "G^XIYLYFXIVGSFQFNGLIKKJNJSKVLXNZQ[S[VZXX RQFOGMILKKNKSLVMXOZQ[ RXSX[ RYSY[ RUS\\S",
+ "F^KFK[ RLFL[ RXFX[ RYFY[ RHFOF RUF\\F RLPXP RH[O[ RU[\\[",
+ "MXRFR[ RSFS[ ROFVF RO[V[",
+ "KZUFUWTZR[P[NZMXMVNUOVNW RTFTWSZR[ RQFXF",
+ "F\\KFK[ RLFL[ RYFLS RQOY[ RPOX[ RHFOF RUF[F RH[O[ RU[[[",
+ "I[NFN[ ROFO[ RKFRF RK[Z[ZUY[",
+ "F_KFK[ RLFRX RKFR[ RYFR[ RYFY[ RZFZ[ RHFLF RYF]F RH[N[ RV[][",
+ "G^LFL[ RMFYY RMHY[ RYFY[ RIFMF RVF\\F RI[O[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF RQFOGMILKKOKRLVMXOZQ[ RS[UZWXXVYRYOXKWIUGSF",
+ "G]LFL[ RMFM[ RIFUFXGYHZJZMYOXPUQMQ RUFWGXHYJYMXOWPUQ RI[P[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF RQFOGMILKKOKRLVMXOZQ[ RS[UZWXXVYRYOXKWIUGSF RNYNXOVQURUTVUXV_W`Y`Z^Z] RUXV\\W^X_Y_Z^",
+ "G]LFL[ RMFM[ RIFUFXGYHZJZLYNXOUPMP RUFWGXHYJYLXNWOUP RI[P[ RRPTQURXYYZZZ[Y RTQUSWZX[Z[[Y[X",
+ "H\\XIYFYLXIVGSFPFMGKIKKLMMNOOUQWRYT RKKMMONUPWQXRYTYXWZT[Q[NZLXKUK[LX",
+ "I\\RFR[ RSFS[ RLFKLKFZFZLYF RO[V[",
+ "F^KFKULXNZQ[S[VZXXYUYF RLFLUMXOZQ[ RHFOF RVF\\F",
+ "H\\KFR[ RLFRX RYFR[ RIFOF RUF[F",
+ "F^JFN[ RKFNV RRFN[ RRFV[ RSFVV RZFV[ RGFNF RWF]F",
+ "H\\KFX[ RLFY[ RYFK[ RIFOF RUF[F RI[O[ RU[[[",
+ "H]KFRQR[ RLFSQS[ RZFSQ RIFOF RVF\\F RO[V[",
+ "H\\XFK[ RYFL[ RLFKLKFYF RK[Y[YUX[",
+ "KYOBOb RPBPb ROBVB RObVb",
+ "KYKFY^",
+ "KYTBTb RUBUb RNBUB RNbUb",
+ "G]JTROZT RJTRPZT",
+ "H\\Hb\\b",
+ "LXPFUL RPFOGUL",
+ "I]NONPMPMONNPMTMVNWOXQXXYZZ[ RWOWXXZZ[[[ RWQVRPSMTLVLXMZP[S[UZWX RPSNTMVMXNZP[",
+ "G\\LFL[ RMFM[ RMPONQMSMVNXPYSYUXXVZS[Q[OZMX RSMUNWPXSXUWXUZS[ RIFMF",
+ "H[WPVQWRXQXPVNTMQMNNLPKSKULXNZQ[S[VZXX RQMONMPLSLUMXOZQ[",
+ "H]WFW[ RXFX[ RWPUNSMQMNNLPKSKULXNZQ[S[UZWX RQMONMPLSLUMXOZQ[ RTFXF RW[[[",
+ "H[LSXSXQWOVNTMQMNNLPKSKULXNZQ[S[VZXX RWSWPVN RQMONMPLSLUMXOZQ[",
+ "KXUGTHUIVHVGUFSFQGPIP[ RSFRGQIQ[ RMMUM RM[T[",
+ "I\\QMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM RONNPNTOV RUVVTVPUN RVOWNYMYNWN RNUMVLXLYM[P\\U\\X]Y^ RLYMZP[U[X\\Y^Y_XaUbObLaK_K^L\\O[",
+ "G]LFL[ RMFM[ RMPONRMTMWNXPX[ RTMVNWPW[ RIFMF RI[P[ RT[[[",
+ "MXRFQGRHSGRF RRMR[ RSMS[ ROMSM RO[V[",
+ "MXSFRGSHTGSF RTMT_SaQbObNaN`O_P`Oa RSMS_RaQb RPMTM",
+ "G\\LFL[ RMFM[ RWMMW RRSX[ RQSW[ RIFMF RTMZM RI[P[ RT[Z[",
+ "MXRFR[ RSFS[ ROFSF RO[V[",
+ "BcGMG[ RHMH[ RHPJNMMOMRNSPS[ ROMQNRPR[ RSPUNXMZM]N^P^[ RZM\\N]P][ RDMHM RD[K[ RO[V[ RZ[a[",
+ "G]LML[ RMMM[ RMPONRMTMWNXPX[ RTMVNWPW[ RIMMM RI[P[ RT[[[",
+ "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM RQMONMPLSLUMXOZQ[ RS[UZWXXUXSWPUNSM",
+ "G\\LMLb RMMMb RMPONQMSMVNXPYSYUXXVZS[Q[OZMX RSMUNWPXSXUWXUZS[ RIMMM RIbPb",
+ "H\\WMWb RXMXb RWPUNSMQMNNLPKSKULXNZQ[S[UZWX RQMONMPLSLUMXOZQ[ RTb[b",
+ "IZNMN[ ROMO[ ROSPPRNTMWMXNXOWPVOWN RKMOM RK[R[",
+ "J[WOXMXQWOVNTMPMNNMOMQNRPSUUWVXW RMPNQPRUTWUXVXYWZU[Q[OZNYMWM[NY",
+ "KZPFPWQZS[U[WZXX RQFQWRZS[ RMMUM",
+ "G]LMLXMZP[R[UZWX RMMMXNZP[ RWMW[ RXMX[ RIMMM RTMXM RW[[[",
+ "I[LMR[ RMMRY RXMR[ RJMPM RTMZM",
+ "F^JMN[ RKMNX RRMN[ RRMV[ RSMVX RZMV[ RGMNM RWM]M",
+ "H\\LMW[ RMMX[ RXML[ RJMPM RTMZM RJ[P[ RT[Z[",
+ "H[LMR[ RMMRY RXMR[P_NaLbKbJaK`La RJMPM RTMZM",
+ "I[WML[ RXMM[ RMMLQLMXM RL[X[XWW[",
+ "KYTBRCQDPFPHQJRKSMSOQQ RRCQEQGRISJTLTNSPORSTTVTXSZR[Q]Q_Ra RQSSUSWRYQZP\\P^Q`RaTb",
+ "NVRBRb",
+ "KYPBRCSDTFTHSJRKQMQOSQ RRCSESGRIQJPLPNQPURQTPVPXQZR[S]S_Ra RSSQUQWRYSZT\\T^S`RaPb",
+ "F^IUISJPLONOPPTSVTXTZS[Q RISJQLPNPPQTTVUXUZT[Q[O",
+ "JZJFJ[K[KFLFL[M[MFNFN[O[OFPFP[Q[QFRFR[S[SFTFT[U[UFVFV[W[WFXFX[Y[YFZFZ["
+ }
+},
+{
+ "Times Roman Bold",
+ 0.041, /* X scale */
+ 0.041, /* Y scale */
+ 0.95, /* X spacing extra scale */
+ 0.055, /* Line width scale */
+ 0.0, /* horizontal offset */
+ 10.5, /* vertical offset */
+ {
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "MXRFQGQIRQ RRFRTST RRFSFST RSFTGTISQ RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "I[NFMGMM RNGMM RNFOGMM RWFVGVM RWGVM RWFXGVM",
+ "H]SBLb RYBRb RLOZO RKUYU",
+ "H\\PBP_ RTBT_ RXKXJWJWLYLYJXHWGTFPFMGKIKLLNOPURWSXUXXWZ RLLMNOOUQWRXT RMGLILKMMONUPXRYTYWXYWZT[P[MZLYKWKUMUMWLWLV",
+ "F^[FI[ RNFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F RWTUUTWTYV[X[ZZ[X[VYTWT",
+ "E_[O[NZNZP\\P\\N[MZMYNXPVUTXRZP[L[JZIXIUJSPORMSKSIRGPFNGMIMLNOPRTWWZY[[[\\Y\\X RKZJXJUKSLR RRMSI RSKRG RNGMK RNNPQTVWYYZ RN[LZKXKULSPO RMINMQQUVXYZZ[Z\\Y",
+ "NWSFRGRM RSGRM RSFTGRM",
+ "KYUBSDQGOKNPNTOYQ]S`Ub RQHPKOOOUPYQ\\ RSDRFQIPOPUQ[R^S`",
+ "KYOBQDSGUKVPVTUYS]Q`Ob RSHTKUOUUTYS\\ RQDRFSITOTUS[R^Q`",
+ "JZRFQGSQRR RRFRR RRFSGQQRR RMINIVOWO RMIWO RMIMJWNWO RWIVINOMO RWIMO RWIWJMNMO",
+ "F_RIRZSZ RRISISZ RJQ[Q[R RJQJR[R",
+ "MXTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^",
+ "E_IR[R",
+ "MXRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "G^[BIbJb R[B\\BJb",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF RNHMJLNLSMWNY RVYWWXSXNWJVH RQFOGNIMNMSNXOZQ[ RS[UZVXWSWNVIUGSF",
+ "H\\QHQ[ RRHRZ RSFS[ RSFPINJ RM[W[ RQZO[ RQYP[ RSYT[ RSZU[",
+ "H\\LJLKMKMJLJ RLIMINJNKMLLLKKKJLHMGPFTFWGXHYJYLXNUPPRNSLUKXK[ RWHXJXLWN RTFVGWJWLVNTPPR RKYLXNXSYWYYX RNXSZWZXY RNXS[W[XZYXYV",
+ "H\\LJLKMKMJLJ RLIMINJNKMLLLKKKJLHMGPFTFWGXIXLWNTO RVGWIWLVN RSFUGVIVLUNSO RQOTOVPXRYTYWXYWZT[P[MZLYKWKVLUMUNVNWMXLX RWRXTXWWY RSOUPVQWTWWVZT[ RLVLWMWMVLV",
+ "H\\SIS[ RTHTZ RUFU[ RUFJUZU RP[X[ RSZQ[ RSYR[ RUYV[ RUZW[",
+ "H\\MFKPMNPMSMVNXPYSYUXXVZS[P[MZLYKWKVLUMUNVNWMXLX RWPXRXVWX RSMUNVOWRWVVYUZS[ RLVLWMWMVLV RMFWF RMGUG RMHQHUGWF",
+ "H\\VIVJWJWIVI RWHVHUIUJVKWKXJXIWGUFRFOGMILKKOKULXNZQ[S[VZXXYUYTXQVOSNQNOONPMR RNIMKLOLUMXNY RWXXVXSWQ RRFPGOHNJMNMUNXOZQ[ RS[UZVYWVWSVPUOSN",
+ "H\\KFKL RYFYIXLTQSSRWR[ RSRRTQWQ[ RXLSQQTPWP[R[ RKJLHNFPFUIWIXHYF RMHNGPGRH RKJLINHPHUI",
+ "H\\PFMGLILLMNPOTOWNXLXIWGTFPF RNGMIMLNN RVNWLWIVG RPFOGNINLONPO RTOUNVLVIUGTF RPOMPLQKSKWLYMZP[T[WZXYYWYSXQWPTO RMQLSLWMY RWYXWXSWQ RPONPMSMWNZP[ RT[VZWWWSVPTO",
+ "H\\MWMXNXNWMW RWOVQURSSQSNRLPKMKLLINGQFSFVGXIYLYRXVWXUZR[O[MZLXLWMVNVOWOXNYMY RMPLNLKMI RVHWIXLXRWVVX RQSORNQMNMKNHOGQF RSFUGVIWLWSVWUYTZR[",
+ "MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^",
+ "F^ZIJRZ[",
+ "F_JM[M[N RJMJN[N RJU[U[V RJUJV[V",
+ "F^JIZRJ[",
+ "I\\MKMJNJNLLLLJMHNGPFTFWGXHYJYLXNWOSQ RWHXIXMWN RTFVGWIWMVOUP RRQRTSTSQRQ RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS RQKOMNPNSOUPV RWKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX RXKWSWUXV",
+ "H\\RFKZ RQIW[ RRIX[ RRFY[ RMUVU RI[O[ RT[[[ RKZJ[ RKZM[ RWZU[ RWYV[ RXYZ[",
+ "G]LFL[ RMGMZ RNFN[ RIFUFXGYHZJZLYNXOUP RXHYJYLXN RUFWGXIXMWOUP RNPUPXQYRZTZWYYXZU[I[ RXRYTYWXY RUPWQXSXXWZU[ RJFLG RKFLH ROFNH RPFNG RLZJ[ RLYK[ RNYO[ RNZP[",
+ "G\\XIYFYLXIVGTFQFNGLIKKJNJSKVLXNZQ[T[VZXXYV RMILKKNKSLVMX RQFOGMJLNLSMWOZQ[",
+ "G]LFL[ RMGMZ RNFN[ RIFSFVGXIYKZNZSYVXXVZS[I[ RWIXKYNYSXVWX RSFUGWJXNXSWWUZS[ RJFLG RKFLH ROFNH RPFNG RLZJ[ RLYK[ RNYO[ RNZP[",
+ "G\\LFL[ RMGMZ RNFN[ RIFYFYL RNPTP RTLTT RI[Y[YU RJFLG RKFLH ROFNH RPFNG RTFYG RVFYH RWFYI RXFYL RTLSPTT RTNRPTR RTOPPTQ RLZJ[ RLYK[ RNYO[ RNZP[ RT[YZ RV[YY RW[YX RX[YU",
+ "G[LFL[ RMGMZ RNFN[ RIFYFYL RNPTP RTLTT RI[Q[ RJFLG RKFLH ROFNH RPFNG RTFYG RVFYH RWFYI RXFYL RTLSPTT RTNRPTR RTOPPTQ RLZJ[ RLYK[ RNYO[ RNZP[",
+ "G^XIYFYLXIVGTFQFNGLIKKJNJSKVLXNZQ[T[VZXZY[YS RMILKKNKSLVMX RQFOGMJLNLSMWOZQ[ RXTXY RWSWYVZ RTS\\S RUSWT RVSWU RZSYU R[SYT",
+ "F^KFK[ RLGLZ RMFM[ RWFW[ RXGXZ RYFY[ RHFPF RTF\\F RMPWP RH[P[ RT[\\[ RIFKG RJFKH RNFMH ROFMG RUFWG RVFWH RZFYH R[FYG RKZI[ RKYJ[ RMYN[ RMZO[ RWZU[ RWYV[ RYYZ[ RYZ[[",
+ "LXQFQ[ RRGRZ RSFS[ RNFVF RN[V[ ROFQG RPFQH RTFSH RUFSG RQZO[ RQYP[ RSYT[ RSZU[",
+ "JZSFSWRZQ[ RTGTWSZ RUFUWTZQ[O[MZLXLVMUNUOVOWNXMX RMVMWNWNVMV RPFXF RQFSG RRFSH RVFUH RWFUG",
+ "F\\KFK[ RLGLZ RMFM[ RXGMR RPPW[ RQPX[ RQNY[ RHFPF RUF[F RH[P[ RT[[[ RIFKG RJFKH RNFMH ROFMG RWFXG RZFXG RKZI[ RKYJ[ RMYN[ RMZO[ RWYU[ RWYZ[",
+ "I[NFN[ ROGOZ RPFP[ RKFSF RK[Z[ZU RLFNG RMFNH RQFPH RRFPG RNZL[ RNYM[ RPYQ[ RPZR[ RU[ZZ RW[ZY RX[ZX RY[ZU",
+ "E_JFJZ RJFQ[ RKFQX RLFRX RXFQ[ RXFX[ RYGYZ RZFZ[ RGFLF RXF]F RG[M[ RU[][ RHFJG R[FZH R\\FZG RJZH[ RJZL[ RXZV[ RXYW[ RZY[[ RZZ\\[",
+ "F^KFKZ RKFY[ RLFXX RMFYX RYGY[ RHFMF RVF\\F RH[N[ RIFKG RWFYG R[FYG RKZI[ RKZM[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF RMILKKNKSLVMX RWXXVYSYNXKWI RQFOGMJLNLSMWOZQ[ RS[UZWWXSXNWJUGSF",
+ "G]LFL[ RMGMZ RNFN[ RIFUFXGYHZJZMYOXPUQNQ RXHYJYMXO RUFWGXIXNWPUQ RI[Q[ RJFLG RKFLH ROFNH RPFNG RLZJ[ RLYK[ RNYO[ RNZP[",
+ "G]QFNGLIKKJOJRKVLXNZQ[S[VZXXYVZRZOYKXIVGSFQF RMILKKNKSLVMX RWXXVYSYNXKWI RQFOGMJLNLSMWOZQ[ RS[UZWWXSXNWJUGSF RNXOVQURUTVUXV^W`Y`Z^Z\\ RV\\W^X_Y_ RUXW]X^Y^Z]",
+ "G]LFL[ RMGMZ RNFN[ RIFUFXGYHZJZLYNXOUPNP RXHYJYLXN RUFWGXIXMWOUP RRPTQUSWYX[Z[[Y[W RWWXYYZZZ RTQURXXYYZY[X RI[Q[ RJFLG RKFLH ROFNH RPFNG RLZJ[ RLYK[ RNYO[ RNZP[",
+ "H\\XIYFYLXIVGSFPFMGKIKLLNOPURWSXUXXWZ RLLMNOOUQWRXT RMGLILKMMONUPXRYTYWXYWZT[Q[NZLXKUK[LX",
+ "H\\JFJL RQFQ[ RRGRZ RSFS[ RZFZL RJFZF RN[V[ RKFJL RLFJI RMFJH ROFJG RUFZG RWFZH RXFZI RYFZL RQZO[ RQYP[ RSYT[ RSZU[",
+ "F^KFKULXNZQ[S[VZXXYUYG RLGLVMX RMFMVNYOZQ[ RHFPF RVF\\F RIFKG RJFKH RNFMH ROFMG RWFYG R[FYG",
+ "H\\KFR[ RLFRXR[ RMFSX RYGR[ RIFPF RUF[F RJFLH RNFMH ROFMG RWFYG RZFYG",
+ "F^JFN[ RKFNVN[ RLFOV RRFOVN[ RRFV[ RSFVVV[ RTFWV RZGWVV[ RGFOF RRFTF RWF]F RHFKG RIFKH RMFLH RNFLG RXFZG R\\FZG",
+ "H\\KFW[ RLFX[ RMFY[ RXGLZ RIFPF RUF[F RI[O[ RT[[[ RJFMH RNFMH ROFMG RVFXG RZFXG RLZJ[ RLZN[ RWZU[ RWYV[ RWYZ[",
+ "G]JFQQQ[ RKFRQRZ RLFSQS[ RYGSQ RHFOF RVF\\F RN[V[ RIFKG RNFLG RWFYG R[FYG RQZO[ RQYP[ RSYT[ RSZU[",
+ "H\\YFKFKL RWFK[ RXFL[ RYFM[ RK[Y[YU RLFKL RMFKI RNFKH RPFKG RT[YZ RV[YY RW[YX RX[YU",
+ "KYOBOb RPBPb ROBVB RObVb",
+ "KYKFY^",
+ "KYTBTb RUBUb RNBUB RNbUb",
+ "G]JTROZT RJTRPZT",
+ "H\\Hb\\b",
+ "LXPFUL RPFOGUL",
+ "I]NPNOOOOQMQMONNPMTMVNWOXQXXYZZ[ RVOWQWXXZ RTMUNVPVXWZZ[[[ RVRUSPTMULWLXMZP[S[UZVX RNUMWMXNZ RUSQTOUNWNXOZP[",
+ "G\\LFL[MZOZ RMGMY RIFNFNZ RNPONQMSMVNXPYSYUXXVZS[Q[OZNX RWPXRXVWX RSMUNVOWRWVVYUZS[ RJFLG RKFLH",
+ "H[WQWPVPVRXRXPVNTMQMNNLPKSKULXNZQ[S[VZXX RMPLRLVMX RQMONNOMRMVNYOZQ[",
+ "H]VFV[[[ RWGWZ RSFXFX[ RVPUNSMQMNNLPKSKULXNZQ[S[UZVX RMPLRLVMX RQMONNOMRMVNYOZQ[ RTFVG RUFVH RXYY[ RXZZ[",
+ "H[MSXSXQWOVNSMQMNNLPKSKULXNZQ[S[VZXX RWRWQVO RMPLRLVMX RVSVPUNSM RQMONNOMRMVNYOZQ[",
+ "KYWHWGVGVIXIXGWFTFRGQHPKP[ RRHQKQZ RTFSGRIR[ RMMVM RM[U[ RPZN[ RPYO[ RRYS[ RRZT[",
+ "I\\XNYOZNYMXMVNUO RQMONNOMQMSNUOVQWSWUVVUWSWQVOUNSMQM ROONQNSOU RUUVSVQUO RQMPNOPOTPVQW RSWTVUTUPTNSM RNUMVLXLYM[N\\Q]U]X^Y_ RN[Q\\U\\X] RLYMZP[U[X\\Y^Y_XaUbObLaK_K^L\\O[ RObMaL_L^M\\O[",
+ "G^LFL[ RMGMZ RIFNFN[ RNQOOPNRMUMWNXOYRY[ RWOXRXZ RUMVNWQW[ RI[Q[ RT[\\[ RJFLG RKFLH RLZJ[ RLYK[ RNYO[ RNZP[ RWZU[ RWYV[ RYYZ[ RYZ[[",
+ "LXQFQHSHSFQF RRFRH RQGSG RQMQ[ RRNRZ RNMSMS[ RN[V[ ROMQN RPMQO RQZO[ RQYP[ RSYT[ RSZU[",
+ "KXRFRHTHTFRF RSFSH RRGTG RRMR^QaPb RSNS]R` ROMTMT]S`RaPbMbLaL_N_NaMaM` RPMRN RQMRO",
+ "G]LFL[ RMGMZ RIFNFN[ RWNNW RRSY[ RRTX[ RQTW[ RTM[M RI[Q[ RT[[[ RJFLG RKFLH RUMWN RZMWN RLZJ[ RLYK[ RNYO[ RNZP[ RWYU[ RVYZ[",
+ "LXQFQ[ RRGRZ RNFSFS[ RN[V[ ROFQG RPFQH RQZO[ RQYP[ RSYT[ RSZU[",
+ "AcFMF[ RGNGZ RCMHMH[ RHQIOJNLMOMQNROSRS[ RQORRRZ ROMPNQQQ[ RSQTOUNWMZM\\N]O^R^[ R\\O]R]Z RZM[N\\Q\\[ RC[K[ RN[V[ RY[a[ RDMFN REMFO RFZD[ RFYE[ RHYI[ RHZJ[ RQZO[ RQYP[ RSYT[ RSZU[ R\\ZZ[ R\\Y[[ R^Y_[ R^Z`[",
+ "G^LML[ RMNMZ RIMNMN[ RNQOOPNRMUMWNXOYRY[ RWOXRXZ RUMVNWQW[ RI[Q[ RT[\\[ RJMLN RKMLO RLZJ[ RLYK[ RNYO[ RNZP[ RWZU[ RWYV[ RYYZ[ RYZ[[",
+ "H\\QMNNLPKSKULXNZQ[S[VZXXYUYSXPVNSMQM RMPLRLVMX RWXXVXRWP RQMONNOMRMVNYOZQ[ RS[UZVYWVWRVOUNSM",
+ "G\\LMLb RMNMa RIMNMNb RNPONQMSMVNXPYSYUXXVZS[Q[OZNX RWPXRXVWX RSMUNVOWRWVVYUZS[ RIbQb RJMLN RKMLO RLaJb RL`Kb RN`Ob RNaPb",
+ "H\\VNVb RWOWa RUNWNXMXb RVPUNSMQMNNLPKSKULXNZQ[S[UZVX RMPLRLVMX RQMONNOMRMVNYOZQ[ RSb[b RVaTb RV`Ub RX`Yb RXaZb",
+ "IZNMN[ RONOZ RKMPMP[ RWOWNVNVPXPXNWMUMSNQPPS RK[S[ RLMNN RMMNO RNZL[ RNYM[ RPYQ[ RPZR[",
+ "J[WOXMXQWOVNTMPMNNMOMQNSPTUUWVXY RNNMQ RNRPSUTWU RXVWZ RMONQPRUSWTXVXYWZU[Q[OZNYMWM[NY",
+ "KZPHPVQYRZT[V[XZYX RQHQWRY RPHRFRWSZT[ RMMVM",
+ "G^LMLVMYNZP[S[UZVYWW RMNMWNY RIMNMNWOZP[ RWMW[\\[ RXNXZ RTMYMY[ RJMLN RKMLO RYYZ[ RYZ[[",
+ "I[LMR[ RMMRY RNMSY RXNSYR[ RJMQM RTMZM RKMNO RPMNN RVMXN RYMXN",
+ "F^JMN[ RKMNX RLMOX RRMOXN[ RRMV[ RSMVX RRMTMWX RZNWXV[ RGMOM RWM]M RHMKN RNMLN RXMZN R\\MZN",
+ "H\\LMV[ RMMW[ RNMX[ RWNMZ RJMQM RTMZM RJ[P[ RS[Z[ RKMMN RPMNN RUMWN RYMWN RMZK[ RMZO[ RVZT[ RWZY[",
+ "H[LMR[ RMMRY RNMSY RXNSYP_NaLbJbIaI_K_KaJaJ` RJMQM RTMZM RKMNO RPMNN RVMXN RYMXN",
+ "I[VML[ RWMM[ RXMN[ RXMLMLQ RL[X[XW RMMLQ RNMLP ROMLO RQMLN RS[XZ RU[XY RV[XX RW[XW",
+ "KYTBRCQDPFPHQJRKSMSOQQ RRCQEQGRISJTLTNSPORSTTVTXSZR[Q]Q_Ra RQSSUSWRYQZP\\P^Q`RaTb",
+ "NVRBRb",
+ "KYPBRCSDTFTHSJRKQMQOSQ RRCSESGRIQJPLPNQPURQTPVPXQZR[S]S_Ra RSSQUQWRYSZT\\T^S`RaPb",
+ "F^IUISJPLONOPPTSVTXTZS[Q RISJQLPNPPQTTVUXUZT[Q[O",
+ "JZJFJ[K[KFLFL[M[MFNFN[O[OFPFP[Q[QFRFR[S[SFTFT[U[UFVFV[W[WFXFX[Y[YFZFZ["
+ }
+},
+{
+ "Futura Light",
+ 0.041, /* X scale */
+ 0.041, /* Y scale */
+ 0.95, /* X spacing extra scale */
+ 0.08, /* Line width scale */
+ 0.9, /* horizontal offset */
+ 10.5, /* vertical offset */
+ {
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "MWRFRT RRYQZR[SZRY",
+ "JZNFNM RVFVM",
+ "H]SBLb RYBRb RLOZO RKUYU",
+ "H\\PBP_ RTBT_ RYIWGTFPFMGKIKKLMMNOOUQWRXSYUYXWZT[P[MZKX",
+ "F^[FI[ RNFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F RWTUUTWTYV[X[ZZ[X[VYTWT",
+ "E_\\O\\N[MZMYNXPVUTXRZP[L[JZIYHWHUISJRQNRMSKSIRGPFNGMIMKNNPQUXWZY[[[\\Z\\Y",
+ "MWRHQGRFSGSIRKQL",
+ "KYVBTDRGPKOPOTPYR]T`Vb",
+ "KYNBPDRGTKUPUTTYR]P`Nb",
+ "JZRLRX RMOWU RWOMU",
+ "E_RIR[ RIR[R",
+ "NVSWRXQWRVSWSYQ[",
+ "E_IR[R",
+ "NVRVQWRXSWRV",
+ "G][BIb",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF",
+ "H\\NJPISFS[",
+ "H\\LKLJMHNGPFTFVGWHXJXLWNUQK[Y[",
+ "H\\MFXFRNUNWOXPYSYUXXVZS[P[MZLYKW",
+ "H\\UFKTZT RUFU[",
+ "H\\WFMFLOMNPMSMVNXPYSYUXXVZS[P[MZLYKW",
+ "H\\XIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQLT",
+ "H\\YFO[ RKFYF",
+ "H\\PFMGLILKMMONSOVPXRYTYWXYWZT[P[MZLYKWKTLRNPQOUNWMXKXIWGTFPF",
+ "H\\XMWPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLX",
+ "NVROQPRQSPRO RRVQWRXSWRV",
+ "NVROQPRQSPRO RSWRXQWRVSWSYQ[",
+ "F^ZIJRZ[",
+ "E_IO[O RIU[U",
+ "F^JIZRJ[",
+ "I[LKLJMHNGPFTFVGWHXJXLWNVORQRT RRYQZR[SZRY",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS RQKOMNPNSOUPV RWKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX RXKWSWUXV",
+ "I[RFJ[ RRFZ[ RMTWT",
+ "G\\KFK[ RKFTFWGXHYJYLXNWOTP RKPTPWQXRYTYWXYWZT[K[",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV",
+ "G\\KFK[ RKFRFUGWIXKYNYSXVWXUZR[K[",
+ "H[LFL[ RLFYF RLPTP RL[Y[",
+ "HZLFL[ RLFYF RLPTP",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZS RUSZS",
+ "G]KFK[ RYFY[ RKPYP",
+ "NVRFR[",
+ "JZVFVVUYTZR[P[NZMYLVLT",
+ "G\\KFK[ RYFKT RPOY[",
+ "HYLFL[ RL[X[",
+ "F^JFJ[ RJFR[ RZFR[ RZFZ[",
+ "G]KFK[ RKFY[ RYFY[",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF",
+ "G\\KFK[ RKFTFWGXHYJYMXOWPTQKQ",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF RSWY]",
+ "G\\KFK[ RKFTFWGXHYJYLXNWOTPKP RRPY[",
+ "H\\YIWGTFPFMGKIKKLMMNOOUQWRXSYUYXWZT[P[MZKX",
+ "JZRFR[ RKFYF",
+ "G]KFKULXNZQ[S[VZXXYUYF",
+ "I[JFR[ RZFR[",
+ "F^HFM[ RRFM[ RRFW[ R\\FW[",
+ "H\\KFY[ RYFK[",
+ "I[JFRPR[ RZFRP",
+ "H\\YFK[ RKFYF RK[Y[",
+ "KYOBOb RPBPb ROBVB RObVb",
+ "KYKFY^",
+ "KYTBTb RUBUb RNBUB RNbUb",
+ "JZRDJR RRDZR",
+ "I[Ib[b",
+ "NVSKQMQORPSORNQO",
+ "I\\XMX[ RXPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "H[LFL[ RLPNNPMSMUNWPXSXUWXUZS[P[NZLX",
+ "I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I\\XFX[ RXPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I[LSXSXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "MYWFUFSGRJR[ ROMVM",
+ "I\\XMX]W`VaTbQbOa RXPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "I\\MFM[ RMQPNRMUMWNXQX[",
+ "NVQFRGSFREQF RRMR[",
+ "MWRFSGTFSERF RSMS^RaPbNb",
+ "IZMFM[ RWMMW RQSX[",
+ "NVRFR[",
+ "CaGMG[ RGQJNLMOMQNRQR[ RRQUNWMZM\\N]Q][",
+ "I\\MMM[ RMQPNRMUMWNXQX[",
+ "I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM",
+ "H[LMLb RLPNNPMSMUNWPXSXUWXUZS[P[NZLX",
+ "I\\XMXb RXPVNTMQMONMPLSLUMXOZQ[T[VZXX",
+ "KXOMO[ ROSPPRNTMWM",
+ "J[XPWNTMQMNNMPNRPSUTWUXWXXWZT[Q[NZMX",
+ "MYRFRWSZU[W[ ROMVM",
+ "I\\MMMWNZP[S[UZXW RXMX[",
+ "JZLMR[ RXMR[",
+ "G]JMN[ RRMN[ RRMV[ RZMV[",
+ "J[MMX[ RXMM[",
+ "JZLMR[ RXMR[P_NaLbKb",
+ "J[XMM[ RMMXM RM[X[",
+ "KYTBRCQDPFPHQJRKSMSOQQ RRCQEQGRISJTLTNSPORSTTVTXSZR[Q]Q_Ra RQSSUSWRYQZP\\P^Q`RaTb",
+ "NVRBRb",
+ "KYPBRCSDTFTHSJRKQMQOSQ RRCSESGRIQJPLPNQPURQTPVPXQZR[S]S_Ra RSSQUQWRYSZT\\T^S`RaPb",
+ "F^IUISJPLONOPPTSVTXTZS[Q RISJQLPNPPQTTVUXUZT[Q[O",
+ "JZJFJ[K[KFLFL[M[MFNFN[O[OFPFP[Q[QFRFR[S[SFTFT[U[UFVFV[W[WFXFX[Y[YFZFZ[",
+ }
+},
+{
+ "Futura Medium",
+ 0.041, /* X scale */
+ 0.041, /* Y scale */
+ 0.95, /* X spacing extra scale */
+ 0.065, /* Line width scale */
+ 0.1, /* horizontal offset */
+ 10.5, /* vertical offset */
+ {
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "JZ",
+ "MXRFRTST RRFSFST RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "I[NFMGMM RNGMM RNFOGMM RWFVGVM RWGVM RWFXGVM",
+ "H]SBLb RYBRb RLOZO RKUYU",
+ "I\\RBR_S_ RRBSBS_ RWIYIWGTFQFNGLILKMMNNVRWSXUXWWYTZQZOYNX RWIVHTGQGNHMIMKNMVQXSYUYWXYWZT[Q[NZLXNX RXXUZ",
+ "F^[FI[ RNFPHPJOLMMKMIKIIJGLFNFPGSHVHYG[F RWTUUTWTYV[X[ZZ[X[VYTWT",
+ "F_[NZO[P\\O\\N[MZMYNXPVUTXRZP[M[JZIXIUJSPORMSKSIRGPFNGMIMKNNPQUXWZZ[[[\\Z\\Y RM[KZJXJUKSMQ RMKNMVXXZZ[",
+ "NWSFRGRM RSGRM RSFTGRM",
+ "KYVBTDRGPKOPOTPYR]T`Vb RTDRHQKPPPTQYR\\T`",
+ "KYNBPDRGTKUPUTTYR]P`Nb RPDRHSKTPTTSYR\\P`",
+ "JZRFQGSQRR RRFRR RRFSGQQRR RMINIVOWO RMIWO RMIMJWNWO RWIVINOMO RWIMO RWIWJMNMO",
+ "F_RIRZSZ RRISISZ RJQ[Q[R RJQJR[R",
+ "MXTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^",
+ "E_IR[R",
+ "MXRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "G^[BIbJb R[B\\BJb",
+ "H\\QFNGLJKOKRLWNZQ[S[VZXWYRYOXJVGSFQF ROGMJLOLRMWOZ RNYQZSZVY RUZWWXRXOWJUG RVHSGQGNH",
+ "H\\NJPISFS[ RNJNKPJRHR[S[",
+ "H\\LKLJMHNGPFTFVGWHXJXLWNUQL[ RLKMKMJNHPGTGVHWJWLVNTQK[ RLZYZY[ RK[Y[",
+ "H\\MFXFQO RMFMGWG RWFPO RQNSNVOXQYTYUXXVZS[P[MZLYKWLW RPOSOVPXS RTOWQXTXUWXTZ RXVVYSZPZMYLW ROZLX",
+ "H\\UIU[V[ RVFV[ RVFKVZV RUILV RLUZUZV",
+ "H\\MFLO RNGMN RMFWFWG RNGWG RMNPMSMVNXPYSYUXXVZS[P[MZLYKWLW RLOMOONSNVOXR RTNWPXSXUWXTZ RXVVYSZPZMYLW ROZLX",
+ "H\\VGWIXIWGTFRFOGMJLOLTMXOZR[S[VZXXYUYTXQVOSNRNOOMQ RWHTGRGOH RPGNJMOMTNXQZ RMVOYRZSZVYXV RTZWXXUXTWQTO RXSVPSOROOPMS RQONQMT",
+ "H\\KFYFO[ RKFKGXG RXFN[O[",
+ "H\\PFMGLILKMMNNPOTPVQWRXTXWWYTZPZMYLWLTMRNQPPTOVNWMXKXIWGTFPF RNGMIMKNMPNTOVPXRYTYWXYWZT[P[MZLYKWKTLRNPPOTNVMWKWIVG RWHTGPGMH RLXOZ RUZXX",
+ "H\\WPURRSQSNRLPKMKLLINGQFRFUGWIXMXRWWUZR[P[MZLXMXNZ RWMVPSR RWNUQRRQRNQLN RPRMPLMLLMIPG RLKNHQGRGUHWK RSGVIWMWRVWTZ RUYRZPZMY",
+ "MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "MXRMQNQORPSPTOTNSMRM RRNROSOSNRN RTZS[R[QZQYRXSXTYT\\S^Q_ RRYRZSZSYRY RS[T\\ RTZS^",
+ "F^ZIJRZ[",
+ "F_JM[M[N RJMJN[N RJU[U[V RJUJV[V",
+ "F^JIZRJ[",
+ "I\\LKLJMHNGQFTFWGXHYJYLXNWOUPRQ RLKMKMJNHQGTGWHXJXLWNUORP RMIPG RUGXI RXMTP RRPRTSTSP RRXQYQZR[S[TZTYSXRX RRYRZSZSYRY",
+ "E`WNVLTKQKOLNMMPMSNUPVSVUUVS RQKOMNPNSOUPV RWKVSVUXVZV\\T]Q]O\\L[JYHWGTFQFNGLHJJILHOHRIUJWLYNZQ[T[WZYYZX RXKWSWUXV",
+ "H\\RFJ[ RRIK[J[ RRIY[Z[ RRFZ[ RMUWU RLVXV",
+ "H\\LFL[ RMGMZ RLFTFWGXHYJYMXOWPTQ RMGTGWHXJXMWOTP RMPTPWQXRYTYWXYWZT[L[ RMQTQWRXTXWWYTZMZ",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZV RZKYKXIWHUGQGOHMKLNLSMVOYQZUZWYXXYVZV",
+ "H]LFL[ RMGMZ RLFSFVGXIYKZNZSYVXXVZS[L[ RMGSGVHWIXKYNYSXVWXVYSZMZ",
+ "I\\MFM[ RNGNZ RMFYF RNGYGYF RNPTPTQ RNQTQ RNZYZY[ RM[Y[",
+ "I[MFM[ RNGN[M[ RMFYF RNGYGYF RNPTPTQ RNQTQ",
+ "H]ZKYIWGUFQFOGMILKKNKSLVMXOZQ[U[WZYXZVZRUR RZKYKXIWHUGQGOHNIMKLNLSMVNXOYQZUZWYXXYVYSUSUR",
+ "G]KFK[ RKFLFL[K[ RYFXFX[Y[ RYFY[ RLPXP RLQXQ",
+ "NWRFR[S[ RRFSFS[",
+ "J[VFVVUYSZQZOYNVMV RVFWFWVVYUZS[Q[OZNYMV",
+ "H]LFL[M[ RLFMFM[ RZFYFMR RZFMS RPOY[Z[ RQOZ[",
+ "IZMFM[ RMFNFNZ RNZYZY[ RM[Y[",
+ "F^JFJ[ RKKK[J[ RKKR[ RJFRX RZFRX RYKR[ RYKY[Z[ RZFZ[",
+ "G]KFK[ RLIL[K[ RLIY[ RKFXX RXFXX RXFYFY[",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF RQGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG",
+ "H\\LFL[ RMGM[L[ RLFUFWGXHYJYMXOWPUQMQ RMGUGWHXJXMWOUPMP",
+ "G]PFNGLIKKJNJSKVLXNZP[T[VZXXYVZSZNYKXIVGTFPF RQGNHLKKNKSLVNYQZSZVYXVYSYNXKVHSGQG RSXX]Y] RSXTXY]",
+ "H\\LFL[ RMGM[L[ RLFTFWGXHYJYMXOWPTQMQ RMGTGWHXJXMWOTPMP RRQX[Y[ RSQY[",
+ "H\\YIWGTFPFMGKIKKLMMNOOTQVRWSXUXXWYTZPZNYMXKX RYIWIVHTGPGMHLILKMMONTPVQXSYUYXWZT[P[MZKX",
+ "J[RGR[ RSGS[R[ RLFYFYG RLFLGYG",
+ "G]KFKULXNZQ[S[VZXXYUYF RKFLFLUMXNYQZSZVYWXXUXFYF",
+ "H\\JFR[ RJFKFRX RZFYFRX RZFR[",
+ "E_GFM[ RGFHFMX RRFMX RRIM[ RRIW[ RRFWX R]F\\FWX R]FW[",
+ "H\\KFX[Y[ RKFLFY[ RYFXFK[ RYFL[K[",
+ "I\\KFRPR[S[ RKFLFSP RZFYFRP RZFSPS[",
+ "H\\XFK[ RYFL[ RKFYF RKFKGXG RLZYZY[ RK[Y[",
+ "KYOBOb RPBPb ROBVB RObVb",
+ "KYKFY^",
+ "KYTBTb RUBUb RNBUB RNbUb",
+ "G]JTROZT RJTRPZT",
+ "H\\Hb\\b",
+ "LXPFUL RPFOGUL",
+ "H\\WMW[X[ RWMXMX[ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX",
+ "H\\LFL[M[ RLFMFM[ RMPONQMTMVNXPYSYUXXVZT[Q[OZMX RMPQNTNVOWPXSXUWXVYTZQZMX",
+ "I[XPVNTMQMONMPLSLUMXOZQ[T[VZXX RXPWQVOTNQNOONPMSMUNXOYQZTZVYWWXX",
+ "H\\WFW[X[ RWFXFX[ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX",
+ "I[MTXTXQWOVNTMQMONMPLSLUMXOZQ[T[VZXX RMSWSWQVOTNQNOONPMSMUNXOYQZTZVYWWXX",
+ "LZWFUFSGRJR[S[ RWFWGUGSH RTGSJS[ ROMVMVN ROMONVN",
+ "H\\XMWMW\\V_U`SaQaO`N_L_ RXMX\\W_UaSbPbNaL_ RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX",
+ "H\\LFL[M[ RLFMFM[ RMQPNRMUMWNXQX[ RMQPORNTNVOWQW[X[",
+ "NWRFQGQHRISITHTGSFRF RRGRHSHSGRG RRMR[S[ RRMSMS[",
+ "NWRFQGQHRISITHTGSFRF RRGRHSHSGRG RRMRbSb RRMSMSb",
+ "H[LFL[M[ RLFMFM[ RXMWMMW RXMMX RPTV[X[ RQSX[",
+ "NWRFR[S[ RRFSFS[",
+ "CbGMG[H[ RGMHMH[ RHQKNMMPMRNSQS[ RHQKOMNONQORQR[S[ RSQVNXM[M]N^Q^[ RSQVOXNZN\\O]Q][^[",
+ "H\\LML[M[ RLMMMM[ RMQPNRMUMWNXQX[ RMQPORNTNVOWQW[X[",
+ "I\\QMONMPLSLUMXOZQ[T[VZXXYUYSXPVNTMQM RQNOONPMSMUNXOYQZTZVYWXXUXSWPVOTNQN",
+ "H\\LMLbMb RLMMMMb RMPONQMTMVNXPYSYUXXVZT[Q[OZMX RMPQNTNVOWPXSXUWXVYTZQZMX",
+ "H\\WMWbXb RWMXMXb RWPUNSMPMNNLPKSKULXNZP[S[UZWX RWPSNPNNOMPLSLUMXNYPZSZWX",
+ "KYOMO[P[ ROMPMP[ RPSQPSNUMXM RPSQQSOUNXNXM",
+ "J[XPWNTMQMNNMPNRPSUUWV RVUWWWXVZ RWYTZQZNY ROZNXMX RXPWPVN RWOTNQNNO RONNPOR RNQPRUTWUXWXXWZT[Q[NZMX",
+ "MXRFR[S[ RRFSFS[ ROMVMVN ROMONVN",
+ "H\\LMLWMZO[R[TZWW RLMMMMWNYPZRZTYWW RWMW[X[ RWMXMX[",
+ "JZLMR[ RLMMMRY RXMWMRY RXMR[",
+ "F^IMN[ RIMJMNX RRMNX RRPN[ RRPV[ RRMVX R[MZMVX R[MV[",
+ "I[LMW[X[ RLMMMX[ RXMWML[ RXMM[L[",
+ "JZLMR[ RLMMMRY RXMWMRYNb RXMR[ObNb",
+ "I[VNL[ RXMNZ RLMXM RLMLNVN RNZXZX[ RL[X[",
+ "KYUBNRUb",
+ "NVRBRb",
+ "KYOBVROb",
+ "F^IUISJPLONOPPTSVTXTZS[Q RISJQLPNPPQTTVUXUZT[Q[O",
+ "JZJFJ[K[KFLFL[M[MFNFN[O[OFPFP[Q[QFRFR[S[SFTFT[U[UFVFV[W[WFXFX[Y[YFZFZ[",
+ }
+}
+};
+
+
diff --git a/render/render.h b/render/render.h
new file mode 100644
index 0000000..e7bcdee
--- /dev/null
+++ b/render/render.h
@@ -0,0 +1,239 @@
+
+#ifndef RENDER2D_H
+#define RENDER2D_H
+
+/*
+ * render2d
+ *
+ * Simple 2D raster rendering support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/12/2005
+ *
+ * Copyright 2005, 2008, 2012 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.
+ */
+
+/* This is basically a simple 2D ray tracing renderer, so it's not especially */
+/* efficient, but it's simple and direct, easy to add new primitives or */
+/* capabilities, is high quality, and has an accelleration algorithm that */
+/* makes it fast enough for printed output. */
+
+/* Mathematical coordinate in mm are used for primitives, ie. the origin is */
+/* the bottom left corner. */
+/* Device color values range from 0.0 to 1.0 */
+
+#define MXCH2D 8 /* Maximum color channels */
+#define TOTC2D (MXCH2D+1) /* Maximum total components */
+#define PRIX2D (MXCH2D) /* Index of primitive */
+
+/* Color type */
+/* Shouldn't this be an xcolorants mask ? */
+typedef enum {
+ w_2d, /* Video style grey */
+ k_2d, /* Printing style grey */
+ lab_2d, /* Lab */
+ rgb_2d, /* RGB */
+ cmyk_2d, /* CMYK */
+ ncol_2d, /* N color */
+ ncol_a_2d /* N color with extra as alpha */
+} colort2d;
+
+/* Pixel depth */
+typedef enum {
+ bpc8_2d, /* 8 bits per component */
+ bpc16_2d /* 16 bits per component */
+} depth2d;
+
+typedef double color2d[TOTC2D];
+
+/* Font type */
+typedef enum {
+ rowman_s = 0, /* Rownman, single stroke */
+ rowman_d = 1, /* Rownman, double stroke */
+ rowman_t = 2, /* Rownman, triple stroke */
+ timesr = 3, /* Times Roman */
+ timesr_b = 4, /* Times Roman, Bold */
+ futura_l = 5, /* Futura, Light */
+ futura_m = 6 /* Futura, Medium */
+} font2d;
+
+/* ------------------------------------ */
+
+struct _render2d;
+
+#define PRIM_STRUCT \
+/* primt2d tag; */ /* Type of primitive */ \
+ int ix; /* Index (order added) */ \
+ int ncc; /* Number of color components */ \
+ struct _prim2d *next; /* Linked list to next primitive */ \
+ struct _prim2d *yl0; /* Previous lines Y list linked list */ \
+ struct _prim2d *yl; /* Active Y list linked list */ \
+ struct _prim2d *xl; /* Active X list linked list */ \
+ double x0, y0, x1, y1; /* Extent, top & left inclusive, bot & right non-inclusive */ \
+ void (*del)(struct _prim2d *s); /* Delete the object */ \
+ /* Render the object at location. Return nz if in primitive */ \
+ int (*rend)(struct _prim2d *s, color2d rv, double x, double y);
+
+struct _prim2d {
+ PRIM_STRUCT
+}; typedef struct _prim2d prim2d;
+
+/* ------------------------------------ */
+/* Solid rectange primitive */
+struct _rect2d {
+ PRIM_STRUCT
+ double rx0, ry0, rx1, ry1; /* Rectangle verticies */
+ color2d c; /* Color of rectangle */
+}; typedef struct _rect2d rect2d;
+
+prim2d *new_rect2d(struct _render2d *s, double x, double y, double w, double h, color2d c);
+
+/* ------------------------------------ */
+/* Vertex shaded rectange */
+struct _rectvs2d {
+ PRIM_STRUCT
+ double rx0, ry0, rx1, ry1; /* Rectangle verticies */
+ color2d c[4]; /* Bot left, bot right, top left, top right */
+ int x_blend; /* Blending rule flags, 0 = linear, 1 = spline, 2 = sine */
+ int y_blend;
+ int y_sine;
+}; typedef struct _rectvs2d rectvs2d;
+
+prim2d *new_rectvs2d(struct _render2d *s, double x, double y, double w, double h, color2d c[4]);
+
+/* ------------------------------------ */
+/* Vertex shaded triangle */
+struct _trivs2d {
+ PRIM_STRUCT
+ double be[3][3]; /* baricentric equations */
+ color2d c[3]; /* Color of each vertex */
+}; typedef struct _trivs2d trivs2d;
+
+prim2d *new_trivs2d(struct _render2d *s, double v[3][2], color2d c[3]);
+
+/* ------------------------------------ */
+/* A single line. */
+
+struct _line2d {
+ PRIM_STRUCT
+ double lx0, ly0, lx1, ly1; /* Line verticies */
+ double ww; /* half width of line squared */
+ int cap; /* 0 = butt, 1 = round, 2 = square */
+ color2d c; /* Color of the line */
+ int t; /* nz if line is degenerate */
+ double vx, vy; /* Vector relative to x0 y0 */
+}; typedef struct _line2d line2d;
+
+prim2d *new_line2d(struct _render2d *s, double x0, double y0, double x1, double y1, double w, int cap, color2d c);
+
+/* ------------------------------------ */
+
+/* add a dashed line */
+void add_dashed_line2d(
+struct _render2d *s,
+double x0, double y0,
+double x1, double y1,
+double w,
+double on, double off,
+int cap,
+color2d c);
+
+/* Add a text character at the given location using lines */
+void add_char2d(
+struct _render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char ch, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+int or, /* Orintation, 0 = right, 1 = down, 2 = left, 3 = up */
+color2d c /* Color of text */
+);
+
+/* Add a string from the given location using lines. */
+void add_string2d(
+struct _render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char *string, /* Character code to be printed */
+double x, double y, /* Location of bottom left of normal orientation text */
+double h, /* Height of text in normal orientation */
+int or, /* Orintation, 0 = right, 1 = down, 2 = left, 3 = up */
+color2d c /* Color of text */
+);
+
+/* Return the total width of the string without adding it */
+void meas_string2d(
+struct _render2d *s,
+double *xinc, /* Add increment to next character */
+double *yinc,
+font2d fo, /* Font to use */
+char *string, /* Character code to be printed */
+double h, /* Height of text in normal orientation */
+int or /* Orintation, 0 = right, 1 = down, 2 = left, 3 = up */
+);
+
+/* ------------------------------------ */
+/* Render object */
+
+struct _render2d {
+
+/* Private: */
+ int ix; /* Next primitive index */
+ double fw, fh; /* Page size in mm including margines */
+ double lm, rm, tm, bm; /* Page margines in mm */
+ double w, h; /* Page size in mm excluding margines */
+ double hres, vres; /* Page pixel resolution in pixels/mm */
+ int pw, ph; /* Page size in pixels */
+ colort2d csp; /* Color space */
+ int ncc; /* Number of color components */
+ depth2d dpth; /* Depth of the components */
+ int dither; /* Dither flag */
+
+ color2d defc; /* Default color value */
+
+ void (*bgfunc)(void *cntx, color2d c, double x, double y); /* BG color function */
+ void *cntx;
+
+ prim2d *head; /* Start of list of primitives in rendering order */
+ prim2d *yl; /* Active Y list linked list head */
+ prim2d *xl; /* Active X list linked list head */
+
+/* Public: */
+ /* Methods */
+ void (*del)(struct _render2d *s); /* Free ourselves and all primitives */
+
+ void (*set_defc)(struct _render2d *s, color2d c); /* Set the default/background color */
+
+ void (*set_bg_func)(struct _render2d *s, /* Set background color function */
+ void (*func)(void *cntx, color2d c, double x, double y), /* Func can choose not to set */
+ void *cntx
+ );
+
+ void (*add)(struct _render2d *s, prim2d *p); /* Add a primitive */
+
+ int (*write)(struct _render2d *s, char *filename, int comprn);
+ /* Render and write to a TIFF file */
+}; typedef struct _render2d render2d;
+
+/* Constructor */
+render2d *new_render2d(
+ double w, /* width in mm */
+ double h, /* height in mm */
+ double ma[4], /* Margines, left, right, top, bottom, NULL for zero in mm */
+ double hres, /* horizontal resolution in pixels/mm */
+ double vres, /* horizontal resolution in pixels/mm */
+ colort2d csp, /* Color type */
+ int nd, /* Number of channels if c = ncol */
+ depth2d dpth, /* Pixel depth */
+ int dither /* Dither flag */
+);
+
+#endif /* RENDER2D_H */
+
diff --git a/render/screens.h b/render/screens.h
new file mode 100644
index 0000000..353597b
--- /dev/null
+++ b/render/screens.h
@@ -0,0 +1,811 @@
+
+/* screens.h is output from makescreen */
+/* (Simplified from DPS code) */
+
+/*
+ * Copyright 2005, 2012 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.
+ */
+
+static ccoord screen0_0[6241] = {
+ { 31, 36 },{ 70, 70 },{ 73, 27 },{ 28, 72 },{ 48, 13 },{ 8, 47 },{ 50, 52 },{ 14, 13 },
+ { 62, 40 },{ 14, 64 },{ 55, 3 },{ 25, 24 },{ 37, 58 },{ 78, 2 },{ 56, 27 },{ 69, 57 },
+ { 37, 1 },{ 11, 31 },{ 26, 48 },{ 67, 17 },{ 43, 33 },{ 9, 76 },{ 47, 65 },{ 77, 48 },
+ { 30, 14 },{ 61, 64 },{ 1, 14 },{ 17, 57 },{ 49, 40 },{ 18, 1 },{ 5, 36 },{ 50, 75 },
+ { 42, 17 },{ 0, 61 },{ 65, 9 },{ 19, 40 },{ 39, 47 },{ 67, 36 },{ 22, 8 },{ 8, 20 },
+ { 60, 50 },{ 36, 25 },{ 36, 68 },{ 61, 73 },{ 28, 60 },{ 59, 19 },{ 1, 67 },{ 20, 32 },
+ { 75, 42 },{ 32, 7 },{ 74, 7 },{ 53, 33 },{ 7, 55 },{ 56, 59 },{ 44, 4 },{ 7, 6 },
+ { 37, 40 },{ 3, 28 },{ 17, 70 },{ 20, 51 },{ 47, 26 },{ 19, 19 },{ 43, 53 },{ 71, 0 },
+ { 65, 26 },{ 42, 73 },{ 73, 54 },{ 56, 9 },{ 23, 63 },{ 31, 29 },{ 11, 42 },{ 58, 43 },
+ { 54, 68 },{ 0, 19 },{ 25, 77 },{ 34, 51 },{ 5, 70 },{ 39, 14 },{ 67, 46 },{ 51, 19 },
+ { 18, 24 },{ 66, 78 },{ 75, 32 },{ 46, 60 },{ 26, 40 },{ 67, 64 },{ 28, 4 },{ 9, 62 },
+ { 14, 6 },{ 43, 44 },{ 71, 11 },{ 2, 52 },{ 31, 19 },{ 32, 67 },{ 60, 35 },{ 58, 78 },
+ { 11, 23 },{ 3, 75 },{ 18, 45 },{ 53, 49 },{ 46, 7 },{ 39, 30 },{ 69, 20 },{ 78, 35 },
+ { 31, 56 },{ 5, 12 },{ 73, 63 },{ 31, 77 },{ 62, 56 },{ 24, 16 },{ 13, 54 },{ 60, 13 },
+ { 30, 43 },{ 49, 70 },{ 14, 73 },{ 14, 33 },{ 62, 30 },{ 40, 63 },{ 41, 22 },{ 2, 41 },
+ { 46, 37 },{ 72, 72 },{ 39, 5 },{ 74, 22 },{ 66, 52 },{ 27, 34 },{ 22, 73 },{ 3, 4 },
+ { 52, 6 },{ 50, 58 },{ 51, 29 },{ 23, 59 },{ 10, 10 },{ 73, 46 },{ 63, 70 },{ 10, 37 },
+ { 38, 75 },{ 55, 21 },{ 18, 13 },{ 62, 5 },{ 25, 54 },{ 54, 44 },{ 9, 67 },{ 35, 16 },
+ { 71, 35 },{ 7, 27 },{ 4, 57 },{ 46, 49 },{ 29, 27 },{ 77, 71 },{ 74, 13 },{ 48, 77 },
+ { 37, 36 },{ 11, 1 },{ 12, 50 },{ 58, 65 },{ 33, 47 },{ 64, 23 },{ 25, 10 },{ 41, 67 },
+ { 23, 30 },{ 46, 20 },{ 67, 42 },{ 23, 68 },{ 2, 24 },{ 5, 44 },{ 55, 54 },{ 35, 10 },
+ { 69, 3 },{ 76, 59 },{ 55, 38 },{ 52, 12 },{ 14, 21 },{ 18, 63 },{ 22, 43 },{ 41, 57 },
+ { 75, 77 },{ 69, 30 },{ 56, 71 },{ 21, 1 },{ 33, 23 },{ 34, 73 },{ 42, 41 },{ 5, 18 },
+ { 15, 47 },{ 62, 16 },{ 66, 58 },{ 31, 64 },{ 44, 30 },{ 78, 8 },{ 63, 48 },{ 18, 36 },
+ { 40, 10 },{ 44, 78 },{ 12, 58 },{ 65, 74 },{ 15, 28 },{ 53, 25 },{ 17, 5 },{ 75, 52 },
+ { 51, 64 },{ 5, 65 },{ 26, 19 },{ 1, 33 },{ 31, 53 },{ 66, 13 },{ 7, 78 },{ 71, 40 },
+ { 49, 44 },{ 35, 44 },{ 55, 76 },{ 17, 76 },{ 33, 32 },{ 32, 3 },{ 55, 14 },{ 71, 66 },
+ { 76, 24 },{ 64, 33 },{ 26, 65 },{ 10, 15 },{ 60, 59 },{ 39, 54 },{ 6, 49 },{ 13, 39 },
+ { 45, 24 },{ 61, 2 },{ 21, 13 },{ 48, 34 },{ 73, 17 },{ 12, 71 },{ 23, 48 },{ 45, 73 },
+ { 36, 61 },{ 77, 38 },{ 78, 74 },{ 20, 27 },{ 58, 52 },{ 49, 2 },{ 58, 28 },{ 78, 55 },
+ { 28, 9 },{ 36, 19 },{ 22, 36 },{ 66, 5 },{ 19, 60 },{ 48, 55 },{ 7, 30 },{ 65, 67 },
+ { 3, 9 },{ 57, 35 },{ 49, 16 },{ 26, 71 },{ 28, 50 },{ 69, 50 },{ 43, 8 },{ 6, 61 },
+ { 69, 24 },{ 21, 21 },{ 33, 41 },{ 3, 0 },{ 25, 2 },{ 52, 62 },{ 2, 46 },{ 40, 25 },
+ { 41, 70 },{ 61, 44 },{ 16, 53 },{ 73, 4 },{ 42, 49 },{ 16, 18 },{ 7, 40 },{ 59, 22 },
+ { 75, 66 },{ 58, 8 },{ 39, 38 },{ 10, 4 },{ 0, 29 },{ 40, 1 },{ 52, 46 },{ 32, 70 },
+ { 19, 68 },{ 27, 29 },{ 72, 60 },{ 43, 14 },{ 77, 14 },{ 68, 74 },{ 44, 61 },{ 16, 42 },
+ { 4, 21 },{ 68, 38 },{ 54, 73 },{ 33, 12 },{ 50, 32 },{ 18, 9 },{ 29, 57 },{ 12, 66 },
+ { 63, 62 },{ 29, 37 },{ 63, 12 },{ 71, 43 },{ 6, 73 },{ 46, 42 },{ 13, 25 },{ 51, 9 },
+ { 29, 22 },{ 10, 53 },{ 29, 77 },{ 66, 31 },{ 45, 68 },{ 22, 56 },{ 37, 32 },{ 62, 78 },
+ { 53, 56 },{ 6, 33 },{ 7, 10 },{ 49, 21 },{ 70, 53 },{ 14, 78 },{ 2, 64 },{ 24, 45 },
+ { 65, 19 },{ 34, 63 },{ 58, 47 },{ 35, 78 },{ 71, 6 },{ 38, 51 },{ 0, 50 },{ 11, 17 },
+ { 59, 69 },{ 60, 26 },{ 26, 14 },{ 16, 31 },{ 52, 78 },{ 23, 5 },{ 74, 37 },{ 53, 40 },
+ { 41, 27 },{ 13, 46 },{ 74, 73 },{ 72, 20 },{ 24, 38 },{ 19, 72 },{ 46, 11 },{ 55, 62 },
+ { 34, 55 },{ 10, 60 },{ 36, 6 },{ 77, 27 },{ 0, 78 },{ 42, 37 },{ 62, 37 },{ 57, 5 },
+ { 78, 44 },{ 37, 22 },{ 13, 11 },{ 62, 54 },{ 45, 55 },{ 27, 68 },{ 68, 11 },{ 25, 27 },
+ { 2, 60 },{ 28, 46 },{ 57, 31 },{ 9, 34 },{ 39, 72 },{ 78, 17 },{ 68, 69 },{ 17, 49 },
+ { 52, 17 },{ 47, 46 },{ 1, 6 },{ 21, 76 },{ 34, 29 },{ 71, 49 },{ 46, 0 },{ 7, 24 },
+ { 16, 61 },{ 65, 61 },{ 50, 68 },{ 8, 70 },{ 29, 12 },{ 70, 26 },{ 56, 18 },{ 36, 47 },
+ { 38, 64 },{ 5, 51 },{ 48, 28 },{ 16, 15 },{ 65, 2 },{ 64, 45 },{ 15, 38 },{ 26, 61 },
+ { 40, 19 },{ 8, 2 },{ 74, 57 },{ 52, 37 },{ 25, 33 },{ 3, 37 },{ 49, 4 },{ 0, 70 },
+ { 33, 0 },{ 23, 18 },{ 70, 14 },{ 56, 50 },{ 44, 64 },{ 72, 30 },{ 59, 74 },{ 22, 51 },
+ { 6, 16 },{ 38, 11 },{ 40, 43 },{ 21, 66 },{ 15, 2 },{ 9, 43 },{ 58, 39 },{ 70, 76 },
+ { 35, 37 },{ 59, 10 },{ 22, 25 },{ 56, 66 },{ 30, 5 },{ 33, 60 },{ 51, 24 },{ 69, 62 },
+ { 9, 56 },{ 0, 11 },{ 48, 50 },{ 62, 23 },{ 13, 75 },{ 41, 76 },{ 11, 26 },{ 0, 41 },
+ { 30, 40 },{ 75, 3 },{ 29, 18 },{ 66, 55 },{ 18, 55 },{ 69, 33 },{ 31, 74 },{ 44, 18 },
+ { 76, 65 },{ 40, 34 },{ 12, 7 },{ 48, 61 },{ 53, 1 },{ 77, 22 },{ 18, 30 },{ 64, 42 },
+ { 27, 52 },{ 26, 6 },{ 57, 16 },{ 58, 58 },{ 16, 66 },{ 1, 56 },{ 67, 7 },{ 31, 26 },
+ { 21, 40 },{ 52, 72 },{ 3, 31 },{ 45, 32 },{ 39, 59 },{ 42, 6 },{ 2, 71 },{ 74, 48 },
+ { 20, 3 },{ 16, 22 },{ 61, 32 },{ 62, 68 },{ 75, 9 },{ 10, 47 },{ 29, 65 },{ 52, 53 },
+ { 32, 45 },{ 33, 15 },{ 54, 29 },{ 12, 35 },{ 24, 75 },{ 48, 10 },{ 7, 65 },{ 68, 22 },
+ { 44, 46 },{ 2, 17 },{ 5, 3 },{ 35, 71 },{ 73, 69 },{ 52, 42 },{ 59, 3 },{ 70, 45 },
+ { 20, 10 },{ 21, 47 },{ 47, 71 },{ 31, 33 },{ 4, 42 },{ 64, 15 },{ 14, 58 },{ 38, 17 },
+ { 43, 58 },{ 75, 29 },{ 65, 49 },{ 63, 75 },{ 9, 12 },{ 44, 27 },{ 36, 53 },{ 11, 72 },
+ { 26, 21 },{ 35, 4 },{ 65, 38 },{ 5, 25 },{ 77, 63 },{ 25, 56 },{ 49, 36 },{ 54, 9 },
+ { 73, 78 },{ 59, 55 },{ 4, 54 },{ 21, 35 },{ 56, 24 },{ 28, 0 },{ 11, 20 },{ 39, 66 },
+ { 27, 43 },{ 14, 69 },{ 74, 39 },{ 46, 16 },{ 20, 16 },{ 54, 60 },{ 63, 8 },{ 38, 28 },
+ { 67, 28 },{ 66, 71 },{ 5, 77 },{ 56, 46 },{ 42, 3 },{ 15, 44 },{ 41, 50 },{ 75, 15 },
+ { 70, 59 },{ 8, 38 },{ 21, 70 },{ 34, 21 },{ 30, 61 },{ 15, 9 },{ 47, 75 },{ 44, 39 },
+ { 4, 47 },{ 13, 29 },{ 62, 19 },{ 53, 66 },{ 4, 7 },{ 76, 34 },{ 7, 59 },{ 42, 12 },
+ { 30, 48 },{ 56, 0 },{ 56, 41 },{ 76, 75 },{ 28, 32 },{ 23, 0 },{ 21, 62 },{ 48, 23 },
+ { 63, 51 },{ 1, 21 },{ 36, 74 },{ 77, 51 },{ 46, 52 },{ 69, 8 },{ 17, 26 },{ 32, 10 },
+ { 14, 51 },{ 63, 28 },{ 63, 65 },{ 38, 42 },{ 11, 77 },{ 24, 12 },{ 53, 14 },{ 3, 68 },
+ { 35, 66 },{ 55, 33 },{ 17, 34 },{ 71, 18 },{ 21, 54 },{ 67, 1 },{ 47, 57 },{ 76, 45 },
+ { 35, 33 },{ 49, 6 },{ 8, 14 },{ 44, 70 },{ 71, 55 },{ 12, 63 },{ 28, 24 },{ 0, 26 },
+ { 59, 61 },{ 29, 70 },{ 77, 4 },{ 50, 48 },{ 38, 8 },{ 24, 41 },{ 70, 37 },{ 43, 23 },
+ { 20, 6 },{ 60, 76 },{ 8, 51 },{ 32, 50 },{ 9, 30 },{ 69, 66 },{ 53, 21 },{ 17, 74 },
+ { 60, 41 },{ 13, 17 },{ 57, 12 },{ 34, 58 },{ 78, 58 },{ 44, 35 },{ 39, 78 },{ 1, 38 },
+ { 23, 23 },{ 76, 11 },{ 49, 63 },{ 1, 76 },{ 33, 38 },{ 72, 24 },{ 14, 41 },{ 27, 75 },
+ { 58, 71 },{ 59, 33 },{ 20, 58 },{ 28, 16 },{ 13, 4 },{ 64, 57 },{ 46, 3 },{ 35, 27 },
+ { 4, 62 },{ 61, 7 },{ 68, 48 },{ 38, 45 },{ 4, 34 },{ 49, 30 },{ 24, 66 },{ 3, 13 },
+ { 42, 62 },{ 36, 13 },{ 76, 68 },{ 19, 43 },{ 65, 21 },{ 54, 52 },{ 9, 22 },{ 8, 74 },
+ { 53, 75 },{ 73, 33 },{ 28, 54 },{ 21, 29 },{ 47, 39 },{ 68, 77 },{ 30, 2 },{ 7, 45 },
+ { 60, 17 },{ 61, 47 },{ 9, 7 },{ 38, 69 },{ 47, 18 },{ 26, 37 },{ 11, 68 },{ 65, 35 },
+ { 74, 61 },{ 41, 54 },{ 24, 8 },{ 53, 4 },{ 72, 9 },{ 18, 52 },{ 41, 31 },{ 18, 20 },
+ { 1, 48 },{ 47, 67 },{ 76, 19 },{ 19, 77 },{ 58, 25 },{ 57, 63 },{ 33, 18 },{ 69, 41 },
+ { 26, 58 },{ 71, 74 },{ 44, 10 },{ 15, 36 },{ 37, 49 },{ 11, 56 },{ 51, 35 },{ 1, 2 },
+ { 43, 75 },{ 5, 29 },{ 67, 60 },{ 17, 11 },{ 68, 15 },{ 51, 56 },{ 39, 21 },{ 19, 65 },
+ { 72, 51 },{ 24, 31 },{ 34, 76 },{ 50, 43 },{ 63, 3 },{ 77, 31 },{ 6, 68 },{ 30, 8 },
+ { 10, 40 },{ 52, 27 },{ 60, 67 },{ 24, 50 },{ 50, 13 },{ 35, 41 },{ 8, 18 },{ 24, 72 },
+ { 74, 1 },{ 76, 54 },{ 37, 56 },{ 67, 25 },{ 32, 25 },{ 52, 70 },{ 59, 45 },{ 16, 0 },
+ { 13, 61 },{ 22, 15 },{ 76, 40 },{ 50, 0 },{ 44, 48 },{ 38, 3 },{ 61, 11 },{ 10, 28 },
+ { 30, 67 },{ 59, 37 },{ 19, 48 },{ 6, 8 },{ 67, 68 },{ 33, 35 },{ 57, 56 },{ 4, 73 },
+ { 44, 21 },{ 6, 53 },{ 3, 23 },{ 43, 66 },{ 20, 23 },{ 65, 29 },{ 28, 42 },{ 55, 7 },
+ { 0, 65 },{ 34, 8 },{ 5, 39 },{ 66, 44 },{ 72, 15 },{ 27, 63 },{ 46, 29 },{ 64, 72 },
+ { 16, 7 },{ 20, 38 },{ 55, 48 },{ 57, 20 },{ 41, 39 },{ 6, 1 },{ 12, 48 },{ 43, 1 },
+ { 68, 54 },{ 41, 15 },{ 31, 59 },{ 70, 5 },{ 26, 3 },{ 15, 24 },{ 50, 60 },{ 3, 58 },
+ { 71, 28 },{ 29, 30 },{ 15, 71 },{ 57, 75 },{ 4, 15 },{ 54, 36 },{ 73, 43 },{ 38, 61 },
+ { 71, 64 },{ 30, 21 },{ 15, 55 },{ 41, 46 },{ 54, 16 },{ 12, 14 },{ 32, 72 },{ 77, 6 },
+ { 61, 52 },{ 12, 33 },{ 49, 73 },{ 38, 24 },{ 1, 44 },{ 30, 51 },{ 61, 25 },{ 75, 71 },
+ { 27, 12 },{ 64, 0 },{ 10, 65 },{ 74, 25 },{ 45, 43 },{ 47, 8 },{ 25, 44 },{ 20, 74 },
+ { 62, 59 },{ 23, 34 },{ 67, 34 },{ 44, 56 },{ 65, 11 },{ 18, 17 },{ 34, 2 },{ 12, 44 },
+ { 50, 26 },{ 10, 0 },{ 38, 34 },{ 2, 35 },{ 22, 61 },{ 56, 69 },{ 1, 10 },{ 51, 50 },
+ { 1, 53 },{ 37, 71 },{ 45, 14 },{ 59, 30 },{ 6, 22 },{ 77, 78 },{ 24, 20 },{ 25, 69 },
+ { 57, 2 },{ 66, 40 },{ 33, 53 },{ 72, 58 },{ 22, 3 },{ 36, 30 },{ 69, 17 },{ 16, 59 },
+ { 51, 39 },{ 40, 7 },{ 69, 72 },{ 17, 39 },{ 49, 66 },{ 1, 30 },{ 9, 50 },{ 31, 16 },
+ { 59, 15 },{ 9, 72 },{ 53, 58 },{ 32, 43 },{ 12, 9 },{ 72, 47 },{ 36, 64 },{ 75, 20 },
+ { 18, 28 },{ 65, 64 },{ 51, 22 },{ 45, 76 },{ 7, 63 },{ 47, 33 },{ 71, 2 },{ 23, 53 },
+ { 27, 26 },{ 7, 35 },{ 44, 51 },{ 27, 78 },{ 63, 39 },{ 59, 6 },{ 17, 67 },{ 64, 53 },
+ { 37, 15 },{ 1, 73 },{ 13, 19 },{ 71, 32 },{ 28, 39 },{ 41, 60 },{ 22, 11 },{ 3, 49 },
+ { 61, 21 },{ 51, 3 },{ 55, 43 },{ 77, 61 },{ 42, 29 },{ 73, 12 },{ 40, 74 },{ 20, 45 },
+ { 12, 3 },{ 61, 71 },{ 9, 25 },{ 32, 62 },{ 54, 31 },{ 35, 49 },{ 73, 67 },{ 27, 7 },
+ { 75, 36 },{ 50, 11 },{ 54, 64 },{ 3, 19 },{ 8, 57 },{ 48, 47 },{ 19, 33 },{ 5, 5 },
+ { 29, 74 },{ 42, 20 },{ 6, 42 },{ 64, 6 },{ 59, 49 },{ 40, 36 },{ 15, 76 },{ 75, 50 },
+ { 43, 69 },{ 67, 20 },{ 23, 27 },{ 24, 57 },{ 66, 76 },{ 36, 9 },{ 16, 50 },{ 78, 25 },
+ { 62, 34 },{ 49, 54 },{ 18, 4 },{ 35, 23 },{ 3, 66 },{ 61, 62 },{ 29, 35 },{ 55, 11 },
+ { 37, 77 },{ 78, 13 },{ 16, 64 },{ 67, 50 },{ 12, 37 },{ 54, 23 },{ 54, 77 },{ 40, 52 },
+ { 15, 16 },{ 73, 76 },{ 77, 43 },{ 34, 68 },{ 30, 46 },{ 27, 17 },{ 45, 40 },{ 45, 5 },
+ { 75, 56 },{ 6, 75 },{ 69, 10 },{ 8, 32 },{ 46, 63 },{ 57, 38 },{ 22, 69 },{ 49, 18 },
+ { 6, 13 },{ 12, 52 },{ 72, 38 },{ 33, 28 },{ 60, 0 },{ 33, 5 },{ 57, 53 },{ 71, 22 },
+ { 29, 55 },{ 78, 69 },{ 14, 27 },{ 36, 39 },{ 43, 25 },{ 0, 5 },{ 22, 78 },{ 68, 63 },
+ { 63, 26 },{ 22, 46 },{ 50, 72 },{ 62, 43 },{ 19, 14 },{ 5, 59 },{ 40, 12 },{ 25, 63 },
+ { 64, 17 },{ 2, 27 },{ 35, 57 },{ 10, 45 },{ 51, 45 },{ 58, 67 },{ 9, 5 },{ 31, 11 },
+ { 26, 31 },{ 13, 68 },{ 52, 31 },{ 47, 1 },{ 69, 46 },{ 68, 4 },{ 45, 59 },{ 0, 36 },
+ { 19, 56 },{ 22, 20 },{ 37, 44 },{ 67, 56 },{ 51, 15 },{ 2, 1 },{ 23, 39 },{ 26, 73 },
+ { 68, 29 },{ 19, 7 },{ 55, 57 },{ 76, 17 },{ 41, 78 },{ 1, 62 },{ 46, 35 },{ 14, 31 },
+ { 65, 69 },{ 37, 18 },{ 0, 46 },{ 62, 14 },{ 33, 65 },{ 11, 74 },{ 17, 43 },{ 56, 29 },
+ { 57, 73 },{ 12, 22 },{ 27, 49 },{ 51, 7 },{ 39, 26 },{ 42, 65 },{ 11, 12 },{ 3, 55 },
+ { 48, 42 },{ 31, 0 },{ 74, 30 },{ 72, 70 },{ 14, 60 },{ 76, 8 },{ 31, 23 },{ 64, 47 },
+ { 39, 56 },{ 3, 40 },{ 47, 22 },{ 51, 67 },{ 32, 39 },{ 18, 71 },{ 61, 9 },{ 6, 19 },
+ { 60, 57 },{ 25, 5 },{ 63, 36 },{ 76, 0 },{ 42, 9 },{ 19, 25 },{ 7, 69 },{ 42, 45 },
+ { 57, 23 },{ 71, 61 },{ 28, 66 },{ 8, 41 },{ 63, 77 },{ 32, 31 },{ 0, 22 },{ 47, 53 },
+ { 44, 72 },{ 73, 41 },{ 13, 1 },{ 14, 49 },{ 34, 14 },{ 68, 13 },{ 57, 42 },{ 25, 52 },
+ { 25, 15 },{ 78, 53 },{ 54, 5 },{ 4, 10 },{ 25, 35 },{ 20, 64 },{ 64, 31 },{ 33, 75 },
+ { 42, 34 },{ 64, 60 },{ 5, 32 },{ 69, 0 },{ 54, 19 },{ 53, 51 },{ 16, 12 },{ 40, 4 },
+ { 9, 59 },{ 34, 46 },{ 17, 37 },{ 51, 76 },{ 76, 73 },{ 66, 23 },{ 40, 68 },{ 71, 52 },
+ { 27, 22 },{ 47, 31 },{ 18, 78 },{ 78, 32 },{ 27, 59 },{ 52, 60 },{ 47, 15 },{ 6, 47 },
+ { 0, 16 },{ 3, 77 },{ 40, 41 },{ 75, 63 },{ 56, 34 },{ 29, 7 },{ 8, 26 },{ 62, 66 },
+ { 37, 52 },{ 58, 13 },{ 21, 42 },{ 30, 69 },{ 69, 43 },{ 72, 7 },{ 11, 62 },{ 35, 20 },
+ { 17, 21 },{ 54, 70 },{ 54, 47 },{ 8, 9 },{ 20, 53 },{ 36, 2 },{ 69, 35 },{ 46, 25 },
+ { 22, 32 },{ 60, 4 },{ 4, 69 },{ 75, 26 },{ 32, 57 },{ 50, 38 },{ 67, 73 },{ 23, 76 },
+ { 11, 39 },{ 45, 12 },{ 48, 58 },{ 76, 47 },{ 36, 35 },{ 21, 9 },{ 61, 28 },{ 9, 54 },
+ { 46, 69 },{ 9, 16 },{ 60, 53 },{ 26, 46 },{ 71, 16 },{ 16, 73 },{ 40, 16 },{ 77, 57 },
+ { 55, 1 },{ 26, 28 },{ 37, 62 },{ 7, 3 },{ 60, 39 },{ 4, 26 },{ 57, 61 },{ 18, 59 },
+ { 63, 20 },{ 40, 48 },{ 71, 68 },{ 28, 13 },{ 16, 33 },{ 47, 5 },{ 40, 29 },{ 78, 39 },
+ { 37, 73 },{ 75, 5 },{ 16, 46 },{ 16, 3 },{ 55, 26 },{ 78, 67 },{ 65, 51 },{ 67, 9 },
+ { 23, 65 },{ 21, 18 },{ 42, 55 },{ 30, 38 },{ 27, 1 },{ 53, 10 },{ 4, 50 },{ 69, 27 },
+ { 46, 45 },{ 61, 75 },{ 10, 70 },{ 11, 29 },{ 46, 74 },{ 62, 46 },{ 2, 12 },{ 34, 26 },
+ { 68, 59 },{ 31, 49 },{ 37, 6 },{ 73, 21 },{ 13, 56 },{ 49, 25 },{ 6, 37 },{ 14, 8 },
+ { 55, 65 },{ 29, 62 },{ 54, 41 },{ 78, 76 },{ 32, 20 },{ 72, 34 },{ 58, 17 },{ 23, 71 },
+ { 4, 64 },{ 24, 25 },{ 66, 3 },{ 43, 38 },{ 13, 42 },{ 42, 0 },{ 47, 62 },{ 73, 50 },
+ { 15, 19 },{ 8, 77 },{ 21, 49 },{ 45, 19 },{ 66, 66 },{ 37, 67 },{ 68, 40 },{ 49, 51 },
+ { 74, 10 },{ 30, 32 },{ 27, 10 },{ 15, 67 },{ 3, 44 },{ 52, 34 },{ 57, 77 },{ 2, 20 },
+ { 34, 42 },{ 30, 72 },{ 66, 15 },{ 1, 59 },{ 37, 12 },{ 57, 49 },{ 17, 29 },{ 72, 75 },
+ { 35, 54 },{ 49, 9 },{ 21, 5 },{ 60, 31 },{ 10, 35 },{ 59, 63 },{ 2, 7 },{ 24, 60 },
+ { 25, 42 },{ 72, 56 },{ 49, 78 },{ 39, 32 },{ 77, 29 },{ 10, 18 },{ 52, 20 },{ 42, 59 },
+ { 7, 52 },{ 31, 4 },{ 3, 72 },{ 67, 32 },{ 63, 10 },{ 40, 23 },{ 54, 55 },{ 12, 76 },
+ { 74, 44 },{ 23, 13 },{ 40, 71 },{ 20, 36 },{ 60, 70 },{ 17, 62 },{ 48, 38 },{ 74, 18 },
+ { 29, 52 },{ 64, 55 },{ 14, 23 },{ 60, 23 },{ 9, 64 },{ 44, 7 },{ 72, 1 },{ 45, 50 },
+ { 28, 20 },{ 10, 49 },{ 11, 6 },{ 65, 43 },{ 32, 76 },{ 56, 6 },{ 2, 32 },{ 29, 44 },
+ { 45, 28 },{ 73, 65 },{ 50, 65 },{ 20, 0 },{ 35, 60 },{ 5, 23 },{ 34, 34 },{ 58, 36 },
+ { 62, 1 },{ 15, 52 },{ 44, 16 },{ 4, 2 },{ 70, 23 },{ 18, 41 },{ 32, 13 },{ 57, 45 },
+ { 52, 74 },{ 26, 67 },{ 78, 49 },{ 21, 26 },{ 68, 71 },{ 56, 15 },{ 43, 42 },{ 13, 15 },
+ { 21, 57 },{ 74, 35 },{ 38, 0 },{ 75, 60 },{ 45, 65 },{ 77, 12 },{ 37, 27 },{ 5, 56 },
+ { 53, 28 },{ 20, 69 },{ 6, 28 },{ 39, 50 },{ 63, 58 },{ 24, 1 },{ 66, 18 },{ 27, 36 },
+ { 0, 72 },{ 45, 2 },{ 70, 48 },{ 19, 11 },{ 8, 44 },{ 33, 69 },{ 51, 47 },{ 65, 7 },
+ { 14, 35 },{ 38, 20 },{ 3, 16 },{ 27, 55 },{ 63, 73 },{ 66, 37 },{ 7, 72 },{ 38, 39 },
+ { 33, 9 },{ 49, 56 },{ 64, 25 },{ 29, 25 },{ 13, 65 },{ 48, 69 },{ 2, 39 },{ 54, 12 },
+ { 76, 2 },{ 68, 52 },{ 19, 50 },{ 8, 11 },{ 49, 32 },{ 26, 76 },{ 64, 63 },{ 20, 30 },
+ { 52, 2 },{ 40, 61 },{ 70, 12 },{ 25, 18 },{ 61, 42 },{ 78, 23 },{ 34, 48 },{ 78, 64 },
+ { 48, 20 },{ 15, 4 },{ 39, 9 },{ 77, 41 },{ 55, 72 },{ 25, 47 },{ 51, 41 },{ 12, 27 },
+ { 8, 61 },{ 70, 77 },{ 59, 27 },{ 19, 75 },{ 56, 55 },{ 36, 76 },{ 14, 45 },{ 43, 31 },
+ { 72, 26 },{ 30, 58 },{ 32, 17 },{ 9, 1 },{ 74, 53 },{ 53, 63 },{ 19, 22 },{ 58, 11 },
+ { 31, 41 },{ 75, 69 },{ 8, 36 },{ 62, 49 },{ 43, 77 },{ 16, 56 },{ 0, 9 },{ 61, 18 },
+ { 42, 52 },{ 24, 7 },{ 70, 39 },{ 35, 31 },{ 58, 1 },{ 16, 69 },{ 7, 21 },{ 40, 65 },
+ { 43, 11 },{ 22, 38 },{ 55, 37 },{ 2, 54 },{ 69, 65 },{ 15, 11 },{ 50, 17 },{ 31, 66 },
+ { 73, 31 },{ 39, 44 },{ 69, 6 },{ 5, 67 },{ 29, 3 },{ 57, 68 },{ 30, 28 },{ 5, 46 },
+ { 58, 32 },{ 1, 4 },{ 10, 32 },{ 47, 48 },{ 21, 60 },{ 42, 24 },{ 58, 60 },{ 17, 16 },
+ { 48, 74 },{ 70, 19 },{ 18, 47 },{ 10, 75 },{ 66, 47 },{ 34, 6 },{ 45, 36 },{ 65, 77 },
+ { 32, 55 },{ 0, 34 },{ 27, 70 },{ 58, 21 },{ 7, 15 },{ 70, 56 },{ 24, 29 },{ 50, 8 },
+ { 45, 57 },{ 11, 54 },{ 74, 75 },{ 41, 18 },{ 16, 40 },{ 77, 20 },{ 36, 70 },{ 50, 28 },
+ { 4, 60 },{ 24, 22 },{ 55, 51 },{ 64, 13 },{ 16, 77 },{ 63, 32 },{ 27, 41 },{ 64, 68 },
+ { 41, 5 },{ 10, 8 },{ 1, 42 },{ 38, 57 },{ 29, 15 },{ 4, 78 },{ 38, 37 },{ 23, 55 },
+ { 4, 30 },{ 42, 71 },{ 64, 4 },{ 53, 45 },{ 72, 45 },{ 10, 24 },{ 20, 67 },{ 66, 27 },
+ { 51, 61 },{ 23, 10 },{ 0, 57 },{ 73, 14 },{ 47, 12 },{ 30, 34 },{ 66, 62 },{ 25, 74 },
+ { 64, 40 },{ 52, 23 },{ 15, 62 },{ 59, 77 },{ 37, 46 },{ 16, 25 },{ 2, 74 },{ 32, 1 },
+ { 23, 44 },{ 52, 68 },{ 76, 37 },{ 34, 24 },{ 72, 4 },{ 33, 63 },{ 47, 43 },{ 2, 50 },
+ { 57, 7 },{ 8, 66 },{ 61, 55 },{ 17, 8 },{ 1, 25 },{ 36, 17 },{ 12, 41 },{ 53, 35 },
+ { 46, 77 },{ 5, 9 },{ 26, 51 },{ 72, 62 },{ 18, 32 },{ 70, 31 },{ 43, 63 },{ 45, 22 },
+ { 70, 73 },{ 51, 54 },{ 19, 2 },{ 55, 17 },{ 13, 72 },{ 41, 35 },{ 9, 48 },{ 77, 16 },
+ { 48, 3 },{ 22, 17 },{ 60, 46 },{ 24, 62 },{ 24, 36 },{ 39, 76 },{ 63, 22 },{ 11, 59 },
+ { 60, 65 },{ 36, 51 },{ 30, 10 },{ 61, 36 },{ 0, 0 },{ 10, 21 },{ 4, 38 },{ 41, 13 },
+ { 59, 72 },{ 43, 47 },{ 75, 46 },{ 30, 75 },{ 60, 8 },{ 1, 69 },{ 37, 29 },{ 17, 54 },
+ { 75, 23 },{ 34, 39 },{ 67, 53 },{ 71, 8 },{ 28, 64 },{ 55, 30 },{ 11, 13 },{ 13, 32 },
+ { 37, 4 },{ 74, 59 },{ 45, 53 },{ 21, 72 },{ 26, 23 },{ 54, 0 },{ 57, 40 },{ 29, 47 },
+ { 6, 4 },{ 76, 28 },{ 49, 14 },{ 44, 67 },{ 6, 57 },{ 43, 28 },{ 67, 75 },{ 24, 4 },
+ { 59, 51 },{ 11, 46 },{ 61, 15 },{ 72, 36 },{ 12, 78 },{ 36, 59 },{ 28, 30 },{ 4, 17 },
+ { 68, 44 },{ 35, 12 },{ 70, 67 },{ 19, 37 },{ 51, 71 },{ 48, 36 },{ 3, 63 },{ 20, 15 },
+ { 68, 19 },{ 33, 71 },{ 55, 59 },{ 23, 50 },{ 8, 29 },{ 68, 2 },{ 54, 25 },{ 77, 52 },
+ { 51, 5 },{ 12, 69 },{ 36, 43 },{ 32, 22 },{ 77, 9 },{ 9, 39 },{ 49, 59 },{ 66, 33 },
+ { 19, 62 },{ 41, 2 },{ 14, 18 },{ 32, 52 },{ 74, 70 },{ 44, 41 },{ 26, 9 },{ 62, 61 },
+ { 48, 27 },{ 67, 12 },{ 37, 65 },{ 11, 51 },{ 22, 28 },{ 13, 5 },{ 72, 42 },{ 56, 74 },
+ { 43, 19 },{ 68, 25 },{ 49, 46 },{ 5, 74 },{ 27, 57 },{ 3, 34 },{ 45, 9 },{ 32, 37 },
+ { 26, 0 },{ 68, 57 },{ 5, 14 },{ 20, 44 },{ 58, 4 },{ 59, 42 },{ 46, 72 },{ 77, 66 },
+ { 16, 27 },{ 56, 22 },{ 3, 45 },{ 18, 66 },{ 40, 55 },{ 30, 17 },{ 3, 6 },{ 53, 38 },
+ { 34, 78 },{ 74, 16 },{ 58, 54 },{ 14, 57 },{ 1, 28 },{ 37, 23 },{ 64, 71 },{ 15, 74 },
+ { 27, 38 },{ 60, 29 },{ 53, 8 },{ 4, 52 },{ 48, 64 },{ 20, 20 },{ 74, 0 },{ 29, 68 },
+ { 41, 32 },{ 70, 51 },{ 14, 38 },{ 18, 6 },{ 52, 15 },{ 52, 48 },{ 41, 74 },{ 76, 33 },
+ { 31, 45 },{ 8, 68 },{ 38, 14 },{ 66, 10 },{ 1, 18 },{ 32, 61 },{ 78, 60 },{ 55, 67 },
+ { 16, 48 },{ 67, 39 },{ 31, 6 },{ 21, 33 },{ 15, 14 },{ 50, 34 },{ 77, 76 },{ 22, 75 },
+ { 60, 20 },{ 64, 50 },{ 33, 30 },{ 43, 60 },{ 5, 41 },{ 63, 1 },{ 8, 23 },{ 41, 43 },
+ { 50, 77 },{ 22, 64 },{ 70, 29 },{ 8, 0 },{ 74, 55 },{ 47, 24 },{ 25, 13 },{ 74, 6 },
+ { 19, 54 },{ 61, 69 },{ 48, 52 },{ 41, 8 },{ 78, 47 },{ 15, 30 },{ 39, 70 },{ 62, 27 },
+ { 70, 63 },{ 30, 24 },{ 11, 64 },{ 38, 48 },{ 60, 12 },{ 13, 10 },{ 22, 41 },{ 56, 44 },
+ { 28, 76 },{ 70, 21 },{ 61, 58 },{ 6, 31 },{ 42, 26 },{ 25, 59 },{ 3, 11 },{ 52, 57 },
+ { 6, 71 },{ 53, 18 },{ 35, 7 },{ 8, 53 },{ 21, 24 },{ 61, 38 },{ 71, 71 },{ 36, 55 },
+ { 75, 40 },{ 17, 2 },{ 51, 1 },{ 37, 33 },{ 71, 13 },{ 24, 70 },{ 27, 45 },{ 62, 6 },
+ { 34, 17 },{ 7, 43 },{ 47, 40 },{ 56, 64 },{ 9, 19 },{ 78, 3 },{ 63, 44 },{ 35, 74 },
+ { 27, 33 },{ 6, 63 },{ 56, 32 },{ 44, 13 },{ 30, 54 },{ 3, 25 },{ 62, 76 },{ 41, 64 },
+ { 22, 6 },{ 69, 60 },{ 14, 43 },{ 73, 23 },{ 46, 31 },{ 76, 49 },{ 44, 2 },{ 10, 3 },
+ { 43, 50 },{ 11, 34 },{ 56, 13 },{ 10, 57 },{ 77, 72 },{ 26, 16 },{ 64, 35 },{ 48, 68 },
+ { 18, 73 },{ 65, 16 },{ 34, 36 },{ 22, 52 },{ 17, 23 },{ 65, 56 },{ 50, 20 },{ 34, 65 },
+ { 69, 78 },{ 0, 37 },{ 28, 5 },{ 57, 48 },{ 75, 12 },{ 39, 40 },{ 0, 63 },{ 39, 18 },
+ { 48, 7 },{ 46, 56 },{ 74, 28 },{ 20, 12 },{ 14, 53 },{ 64, 66 },{ 7, 7 },{ 57, 26 },
+ { 16, 35 },{ 35, 1 },{ 32, 48 },{ 53, 71 },{ 14, 66 },{ 70, 42 },{ 26, 26 },{ 7, 76 },
+ { 30, 63 },{ 52, 43 },{ 12, 24 },{ 0, 54 },{ 56, 3 },{ 66, 24 },{ 25, 39 },{ 44, 74 },
+ { 1, 15 },{ 43, 36 },{ 67, 70 },{ 7, 49 },{ 36, 21 },{ 40, 58 },{ 70, 34 },{ 24, 78 },
+ { 67, 5 },{ 67, 48 },{ 22, 58 },{ 37, 10 },{ 52, 30 },{ 12, 16 },{ 54, 61 },{ 2, 67 },
+ { 32, 27 },{ 19, 46 },{ 31, 71 },{ 0, 31 },{ 14, 0 },{ 46, 17 },{ 53, 53 },{ 74, 64 },
+ { 63, 18 },{ 73, 2 },{ 33, 44 },{ 5, 20 },{ 58, 75 },{ 25, 67 },{ 0, 43 },{ 45, 47 },
+ { 23, 21 },{ 52, 11 },{ 12, 60 },{ 58, 34 },{ 39, 2 },{ 2, 78 },{ 7, 34 },{ 62, 52 },
+ { 45, 62 },{ 24, 33 },{ 28, 11 },{ 25, 49 },{ 65, 30 },{ 0, 7 },{ 72, 53 },{ 39, 27 },
+ { 42, 68 },{ 10, 73 },{ 50, 23 },{ 9, 27 },{ 59, 66 },{ 16, 10 },{ 17, 51 },{ 57, 10 },
+ { 38, 53 },{ 76, 21 },{ 29, 1 },{ 2, 57 },{ 54, 39 },{ 48, 0 },{ 10, 42 },{ 70, 9 },
+ { 18, 69 },{ 28, 19 },{ 65, 41 },{ 73, 74 },{ 29, 59 },{ 45, 33 },{ 65, 59 },{ 29, 41 },
+ { 7, 12 },{ 53, 76 },{ 19, 29 },{ 49, 49 },{ 59, 24 },{ 43, 5 },{ 73, 38 },{ 17, 60 },
+ { 17, 19 },{ 58, 57 },{ 35, 69 },{ 41, 21 },{ 2, 48 },{ 69, 16 },{ 22, 2 },{ 66, 0 },
+ { 32, 34 },{ 3, 70 },{ 18, 39 },{ 34, 11 },{ 50, 62 },{ 71, 46 },{ 33, 56 },{ 1, 23 },
+ { 68, 67 },{ 42, 40 },{ 61, 4 },{ 27, 73 },{ 7, 38 },{ 56, 19 },{ 8, 4 },{ 76, 58 },
+ { 60, 48 },{ 43, 15 },{ 13, 48 },{ 38, 73 },{ 68, 31 },{ 23, 14 },{ 26, 53 },{ 49, 41 },
+ { 14, 70 },{ 62, 72 },{ 28, 28 },{ 73, 19 },{ 12, 30 },{ 39, 62 },{ 48, 29 },{ 7, 60 },
+ { 2, 3 },{ 48, 72 },{ 62, 10 },{ 20, 8 },{ 40, 46 },{ 77, 36 },{ 7, 17 },{ 38, 31 },
+ { 74, 68 },{ 49, 12 },{ 56, 52 },{ 20, 77 },{ 23, 42 },{ 52, 65 },{ 71, 25 },{ 31, 14 },
+ { 22, 67 },{ 73, 49 },{ 61, 33 },{ 34, 50 },{ 0, 75 },{ 13, 21 },{ 40, 77 },{ 6, 54 },
+ { 73, 10 },{ 44, 54 },{ 13, 36 },{ 54, 6 },{ 52, 26 },{ 62, 63 },{ 33, 4 },{ 10, 67 },
+ { 36, 38 },{ 4, 27 },{ 65, 46 },{ 11, 8 },{ 19, 58 },{ 33, 20 },{ 60, 78 },{ 66, 21 },
+ { 71, 58 },{ 35, 62 },{ 22, 31 },{ 51, 37 },{ 17, 44 },{ 69, 75 },{ 39, 7 },{ 13, 77 },
+ { 76, 43 },{ 0, 13 },{ 45, 26 },{ 46, 66 },{ 59, 40 },{ 27, 62 },{ 17, 14 },{ 59, 14 },
+ { 5, 48 },{ 29, 49 },{ 57, 70 },{ 3, 61 },{ 30, 78 },{ 76, 30 },{ 37, 25 },{ 50, 55 },
+ { 46, 6 },{ 68, 36 },{ 76, 5 },{ 28, 36 },{ 15, 63 },{ 45, 44 },{ 22, 22 },{ 5, 0 },
+ { 48, 17 },{ 65, 54 },{ 4, 35 },{ 62, 24 },{ 38, 67 },{ 76, 62 },{ 26, 8 },{ 23, 47 },
+ { 55, 78 },{ 14, 26 },{ 66, 8 },{ 55, 45 },{ 12, 55 },{ 23, 73 },{ 39, 35 },{ 15, 6 },
+ { 47, 59 },{ 78, 18 },{ 36, 15 },{ 0, 51 },{ 57, 29 },{ 19, 35 },{ 72, 77 },{ 58, 62 },
+ { 45, 78 },{ 35, 45 },{ 9, 45 },{ 9, 13 },{ 28, 69 },{ 64, 37 },{ 67, 65 },{ 43, 22 },
+ { 65, 14 },{ 6, 66 },{ 31, 30 },{ 6, 26 },{ 41, 51 },{ 51, 73 },{ 24, 55 },{ 41, 11 },
+ { 19, 17 },{ 1, 40 },{ 70, 3 },{ 51, 32 },{ 16, 75 },{ 69, 55 },{ 33, 74 },{ 52, 50 },
+ { 77, 26 },{ 58, 18 },{ 77, 70 },{ 33, 59 },{ 15, 40 },{ 31, 8 },{ 50, 4 },{ 27, 24 },
+ { 2, 8 },{ 46, 38 },{ 64, 74 },{ 20, 61 },{ 68, 45 },{ 64, 28 },{ 9, 71 },{ 31, 42 },
+ { 20, 4 },{ 45, 71 },{ 9, 33 },{ 56, 58 },{ 54, 13 },{ 20, 49 },{ 56, 36 },{ 77, 55 },
+ { 25, 30 },{ 75, 14 },{ 12, 2 },{ 42, 57 },{ 74, 33 },{ 36, 0 },{ 30, 20 },{ 10, 52 },
+ { 60, 2 },{ 60, 44 },{ 25, 64 },{ 47, 21 },{ 12, 19 },{ 68, 61 },{ 4, 76 },{ 36, 28 },
+ { 53, 69 },{ 3, 43 },{ 48, 45 },{ 47, 10 },{ 3, 22 },{ 20, 71 },{ 37, 42 },{ 77, 1 },
+ { 27, 3 },{ 67, 22 },{ 23, 37 },{ 8, 58 },{ 61, 60 },{ 19, 26 },{ 35, 52 },{ 72, 40 },
+ { 54, 22 },{ 41, 72 },{ 6, 11 },{ 72, 66 },{ 39, 16 },{ 59, 7 },{ 28, 56 },{ 61, 50 },
+ { 24, 11 },{ 11, 38 },{ 1, 65 },{ 72, 28 },{ 42, 30 },{ 34, 67 },{ 66, 72 },{ 15, 58 },
+ { 69, 14 },{ 47, 51 },{ 27, 15 },{ 74, 51 },{ 48, 76 },{ 26, 43 },{ 14, 12 },{ 54, 27 },
+ { 17, 65 },{ 2, 30 },{ 41, 38 },{ 73, 8 },{ 51, 59 },{ 36, 5 },{ 63, 41 },{ 14, 47 },
+ { 75, 74 },{ 17, 0 },{ 54, 2 },{ 15, 32 },{ 37, 60 },{ 77, 45 },{ 39, 22 },{ 65, 4 },
+ { 54, 42 },{ 29, 73 },{ 24, 19 },{ 61, 67 },{ 29, 33 },{ 64, 20 },{ 10, 63 },{ 5, 6 },
+ { 51, 16 },{ 20, 55 },{ 69, 49 },{ 78, 21 },{ 47, 34 },{ 49, 67 },{ 6, 40 },{ 12, 73 },
+ { 42, 4 },{ 15, 22 },{ 41, 48 },{ 63, 30 },{ 59, 56 },{ 20, 41 },{ 4, 71 },{ 31, 12 },
+ { 31, 51 },{ 62, 13 },{ 69, 37 },{ 55, 74 },{ 3, 51 },{ 23, 3 },{ 33, 26 },{ 78, 10 },
+ { 31, 68 },{ 73, 58 },{ 46, 14 },{ 54, 49 },{ 6, 24 },{ 33, 40 },{ 42, 76 },{ 54, 34 },
+ { 70, 69 },{ 11, 10 },{ 15, 50 },{ 2, 36 },{ 42, 61 },{ 72, 18 },{ 52, 8 },{ 9, 78 },
+ { 24, 26 },{ 33, 77 },{ 46, 27 },{ 5, 62 },{ 64, 76 },{ 68, 27 },{ 27, 47 },{ 63, 54 },
+ { 21, 65 },{ 13, 28 },{ 46, 54 },{ 34, 19 },{ 70, 1 },{ 11, 44 },{ 19, 9 },{ 50, 40 },
+ { 39, 68 },{ 0, 68 },{ 58, 23 },{ 3, 14 },{ 36, 34 },{ 57, 65 },{ 39, 12 },{ 28, 61 },
+ { 78, 33 },{ 17, 72 },{ 74, 45 },{ 20, 34 },{ 68, 7 },{ 60, 34 },{ 5, 55 },{ 29, 6 },
+ { 38, 55 },{ 47, 4 },{ 9, 17 },{ 60, 73 },{ 42, 43 },{ 66, 50 },{ 60, 16 },{ 24, 52 },
+ { 21, 16 },{ 76, 77 },{ 49, 24 },{ 46, 64 },{ 14, 3 },{ 8, 31 },{ 0, 59 },{ 58, 46 },
+ { 29, 39 },{ 25, 72 },{ 74, 24 },{ 55, 10 },{ 7, 46 },{ 36, 72 },{ 66, 63 },{ 40, 28 },
+ { 13, 62 },{ 71, 33 },{ 37, 8 },{ 52, 55 },{ 18, 22 },{ 21, 45 },{ 6, 2 },{ 43, 17 },
+ { 36, 48 },{ 64, 9 },{ 66, 42 },{ 51, 69 },{ 21, 78 },{ 73, 71 },{ 29, 23 },{ 50, 30 },
+ { 32, 64 },{ 78, 15 },{ 16, 37 },{ 75, 54 },{ 10, 69 },{ 57, 0 },{ 44, 37 },{ 75, 38 },
+ { 18, 53 },{ 4, 19 },{ 31, 2 },{ 55, 20 },{ 57, 51 },{ 26, 32 },{ 74, 4 },{ 44, 0 },
+ { 56, 39 },{ 73, 61 },{ 18, 12 },{ 33, 54 },{ 78, 28 },{ 55, 63 },{ 34, 31 },{ 68, 18 },
+ { 23, 61 },{ 7, 74 },{ 32, 15 },{ 1, 47 },{ 63, 69 },{ 44, 58 },{ 10, 26 },{ 46, 9 },
+ { 65, 32 },{ 11, 5 },{ 13, 51 },{ 50, 44 },{ 38, 77 },{ 9, 36 },{ 72, 11 },{ 41, 24 },
+ { 27, 66 },{ 52, 77 },{ 66, 57 },{ 23, 7 },{ 19, 31 },{ 1, 77 },{ 59, 28 },{ 31, 47 },
+ { 15, 68 },{ 51, 13 },{ 44, 49 },{ 5, 58 },{ 65, 1 },{ 14, 16 },{ 38, 63 },{ 78, 42 },
+ { 27, 18 },{ 18, 42 },{ 61, 22 },{ 76, 67 },{ 40, 33 },{ 47, 70 },{ 62, 45 },{ 26, 77 },
+ { 58, 5 },{ 36, 41 },{ 8, 8 },{ 69, 53 },{ 4, 33 },{ 48, 19 },{ 26, 56 },{ 54, 58 },
+ { 72, 22 },{ 7, 50 },{ 35, 14 },{ 21, 74 },{ 60, 37 },{ 76, 7 },{ 25, 37 },{ 60, 62 },
+ { 13, 59 },{ 23, 24 },{ 40, 3 },{ 68, 76 },{ 49, 35 },{ 8, 21 },{ 43, 67 },{ 71, 38 },
+ { 4, 67 },{ 57, 14 },{ 32, 58 },{ 26, 11 },{ 51, 52 },{ 12, 40 },{ 35, 25 },{ 57, 72 },
+ { 67, 30 },{ 14, 75 },{ 72, 48 },{ 2, 5 },{ 40, 45 },{ 16, 29 },{ 50, 2 },{ 22, 49 },
+ { 75, 18 },{ 34, 3 },{ 72, 64 },{ 31, 35 },{ 54, 32 },{ 24, 68 },{ 63, 7 },{ 10, 14 },
+ { 48, 60 },{ 10, 55 },{ 44, 20 },{ 5, 43 },{ 78, 73 },{ 32, 73 },{ 46, 41 },{ 67, 14 },
+ { 16, 20 },{ 40, 53 },{ 42, 10 },{ 66, 68 },{ 73, 29 },{ 16, 5 },{ 18, 57 },{ 60, 54 },
+ { 28, 44 },{ 53, 24 },{ 8, 64 },{ 43, 73 },{ 3, 29 },{ 70, 44 },{ 30, 27 },{ 1, 55 },
+ { 29, 9 },{ 45, 30 },{ 54, 66 },{ 4, 12 },{ 65, 24 },{ 34, 61 },{ 61, 77 },{ 16, 45 },
+ { 54, 46 },{ 38, 19 },{ 0, 1 },{ 21, 19 },{ 63, 38 },{ 18, 64 },{ 55, 8 },{ 13, 34 },
+ { 25, 1 },{ 66, 60 },{ 28, 53 },{ 0, 24 },{ 78, 62 },{ 49, 75 },{ 40, 37 },{ 62, 17 },
+ { 0, 39 },{ 36, 66 },{ 10, 77 },{ 21, 39 },{ 71, 4 },{ 46, 47 },{ 44, 6 },{ 22, 12 },
+ { 65, 48 },{ 21, 28 },{ 71, 73 },{ 55, 28 },{ 19, 70 },{ 76, 51 },{ 51, 63 },{ 5, 16 },
+ { 37, 50 },{ 53, 17 },{ 37, 75 },{ 11, 49 },{ 34, 22 },{ 66, 35 },{ 5, 72 },{ 31, 38 },
+ { 13, 8 },{ 58, 69 },{ 8, 28 },{ 24, 58 },{ 69, 11 },{ 52, 40 },{ 34, 9 },{ 73, 56 },
+ { 46, 23 },{ 43, 56 },{ 5, 37 },{ 19, 0 },{ 52, 4 },{ 76, 13 },{ 11, 66 },{ 58, 50 },
+ { 24, 46 },{ 25, 21 },{ 28, 71 },{ 73, 35 },{ 63, 64 },{ 44, 34 },{ 60, 10 },{ 13, 24 },
+ { 41, 66 },{ 3, 53 },{ 42, 14 },{ 69, 23 },{ 67, 78 },{ 34, 43 },{ 58, 41 },{ 30, 76 },
+ { 9, 41 },{ 4, 1 },{ 29, 31 },{ 15, 54 },{ 49, 57 },{ 61, 26 },{ 19, 5 },{ 56, 76 },
+ { 1, 71 },{ 74, 41 },{ 36, 57 },{ 50, 10 },{ 1, 20 },{ 23, 35 },{ 18, 15 },{ 70, 61 },
+ { 38, 5 },{ 30, 65 },{ 51, 27 },{ 59, 59 },{ 10, 61 },{ 31, 18 },{ 50, 49 },{ 76, 25 },
+ { 62, 3 },{ 18, 50 },{ 35, 29 },{ 2, 10 },{ 67, 43 },{ 45, 75 },{ 15, 72 },{ 57, 33 },
+ { 69, 70 },{ 17, 32 },{ 26, 4 },{ 4, 45 },{ 39, 42 },{ 75, 78 },{ 70, 17 },{ 28, 51 },
+ { 2, 62 },{ 48, 15 },{ 44, 63 },{ 11, 21 },{ 64, 52 },{ 34, 70 },{ 44, 25 },{ 8, 6 },
+ { 21, 63 },{ 75, 31 },{ 59, 20 },{ 24, 40 },{ 36, 11 },{ 55, 53 },{ 75, 48 },{ 47, 78 },
+ { 15, 1 },{ 44, 45 },{ 18, 27 },{ 64, 11 },{ 75, 65 },{ 13, 44 },{ 28, 14 },{ 55, 70 },
+ { 35, 36 },{ 62, 31 },{ 26, 60 },{ 12, 12 },{ 49, 37 },{ 7, 56 },{ 73, 6 },{ 40, 0 },
+ { 5, 31 },{ 39, 60 },{ 65, 73 },{ 51, 21 },{ 68, 51 },{ 23, 77 },{ 33, 49 },{ 27, 27 },
+ { 9, 74 },{ 56, 4 },{ 69, 39 },{ 40, 20 },{ 7, 19 },{ 56, 61 },{ 22, 54 },{ 70, 27 },
+ { 11, 36 },{ 7, 67 },{ 43, 70 },{ 24, 17 },{ 53, 43 },{ 76, 56 },{ 78, 6 },{ 48, 31 },
+ { 32, 6 },{ 62, 57 },{ 63, 15 },{ 15, 65 },{ 1, 35 },{ 43, 52 },{ 48, 6 },{ 74, 72 },
+ { 15, 42 },{ 38, 26 },{ 4, 24 },{ 26, 69 },{ 51, 66 },{ 61, 40 },{ 23, 9 },{ 67, 3 },
+ { 0, 45 },{ 26, 35 },{ 30, 56 },{ 54, 15 },{ 73, 15 },{ 18, 75 },{ 63, 67 },{ 32, 78 },
+ { 6, 51 },{ 42, 32 },{ 15, 17 },{ 68, 33 },{ 30, 44 },{ 59, 1 },{ 6, 77 },{ 49, 53 },
+ { 10, 30 },{ 38, 13 },{ 71, 54 },{ 57, 25 },{ 18, 61 },{ 32, 24 },{ 49, 71 },{ 4, 8 },
+ { 39, 49 },{ 63, 46 },{ 20, 47 },{ 3, 65 },{ 38, 70 },{ 20, 25 },{ 71, 20 },{ 55, 35 },
+ { 42, 7 },{ 69, 64 },{ 16, 8 },{ 46, 61 },{ 33, 33 },{ 71, 78 },{ 12, 57 },{ 4, 39 },
+ { 58, 9 },{ 31, 60 },{ 28, 2 },{ 2, 15 },{ 56, 47 },{ 45, 17 },{ 43, 39 },{ 13, 70 },
+ { 77, 34 },{ 18, 38 },{ 62, 74 },{ 28, 21 },{ 67, 26 },{ 1, 58 },{ 10, 2 },{ 53, 74 },
+ { 8, 48 },{ 21, 68 },{ 47, 44 },{ 70, 7 },{ 11, 25 },{ 39, 74 },{ 55, 56 },{ 35, 18 },
+ { 58, 30 },{ 2, 75 },{ 24, 43 },{ 37, 54 },{ 69, 47 },{ 62, 21 },{ 46, 2 },{ 23, 29 },
+ { 21, 14 },{ 67, 58 },{ 0, 27 },{ 37, 38 },{ 77, 68 },{ 21, 52 },{ 76, 10 },{ 35, 64 },
+ { 45, 11 },{ 65, 39 },{ 25, 75 },{ 0, 49 },{ 59, 64 },{ 9, 10 },{ 49, 27 },{ 30, 13 },
+ { 15, 34 },{ 56, 17 },{ 35, 46 },{ 24, 64 },{ 53, 0 },{ 52, 36 },{ 77, 18 },{ 12, 47 },
+ { 36, 3 },{ 48, 65 },{ 72, 68 },{ 38, 30 },{ 75, 44 },{ 12, 18 },{ 18, 3 },{ 65, 6 },
+ { 15, 60 },{ 58, 44 },{ 28, 40 },{ 47, 55 },{ 66, 19 },{ 4, 4 },{ 25, 6 },{ 3, 59 },
+ { 60, 71 },{ 6, 35 },{ 63, 34 },{ 40, 17 },{ 28, 48 },{ 31, 70 },{ 63, 60 },{ 53, 7 },
+ { 19, 21 },{ 75, 1 },{ 72, 31 },{ 41, 58 },{ 42, 28 },{ 12, 67 },{ 5, 22 },{ 61, 49 },
+ { 51, 18 },{ 8, 42 },{ 35, 77 },{ 75, 61 },{ 21, 59 },{ 26, 29 },{ 12, 0 },{ 45, 69 },
+ { 49, 42 },{ 59, 12 },{ 12, 53 },{ 77, 39 },{ 8, 15 },{ 53, 61 },{ 68, 73 },{ 31, 9 },
+ { 22, 34 },{ 63, 25 },{ 42, 47 },{ 7, 70 },{ 39, 24 },{ 15, 26 },{ 73, 52 },{ 28, 58 },
+ { 64, 78 },{ 42, 1 },{ 72, 12 },{ 21, 7 },{ 53, 30 },{ 34, 53 },{ 75, 27 },{ 22, 72 },
+ { 17, 46 },{ 57, 37 },{ 77, 74 },{ 33, 37 },{ 47, 13 },{ 59, 53 },{ 39, 65 },{ 15, 13 },
+ { 1, 52 },{ 60, 5 },{ 68, 41 },{ 25, 23 },{ 65, 65 },{ 40, 40 },{ 6, 29 },{ 28, 75 },
+ { 7, 62 },{ 49, 22 },{ 51, 74 },{ 74, 21 },{ 47, 50 },{ 14, 39 },{ 34, 13 },{ 26, 50 },
+ { 0, 3 },{ 67, 16 },{ 17, 68 },{ 56, 67 },{ 40, 9 },{ 70, 58 },{ 46, 33 },{ 29, 63 },
+ { 2, 42 },{ 31, 22 },{ 2, 18 },{ 16, 78 },{ 54, 50 },{ 12, 31 },{ 58, 76 },{ 55, 24 },
+ { 15, 56 },{ 34, 72 },{ 1, 12 },{ 71, 36 },{ 32, 29 },{ 50, 6 },{ 78, 66 },{ 50, 46 },
+ { 24, 15 },{ 20, 42 },{ 68, 9 },{ 41, 62 },{ 7, 1 },{ 3, 47 },{ 61, 29 },{ 17, 10 },
+ { 47, 73 },{ 66, 53 },{ 38, 35 },{ 2, 69 },{ 33, 45 },{ 9, 23 },{ 72, 44 },{ 29, 0 },
+ { 58, 15 },{ 71, 76 },{ 8, 55 },{ 52, 59 },{ 1, 32 },{ 44, 23 },{ 35, 56 },{ 38, 2 },
+ { 18, 34 },{ 11, 75 },{ 65, 70 },{ 62, 42 },{ 20, 18 },{ 19, 52 },{ 53, 12 },{ 66, 28 },
+ { 32, 66 },{ 51, 33 },{ 33, 16 },{ 28, 34 },{ 10, 6 },{ 41, 69 },{ 46, 58 },{ 72, 3 },
+ { 77, 60 },{ 8, 39 },{ 71, 24 },{ 23, 66 },{ 49, 1 },{ 44, 43 },{ 28, 7 },{ 57, 55 },
+ { 55, 40 },{ 2, 26 },{ 23, 57 },{ 42, 16 },{ 26, 41 },{ 4, 75 },{ 69, 68 },{ 14, 20 },
+ { 66, 12 },{ 66, 45 },{ 10, 58 },{ 37, 21 },{ 23, 2 },{ 53, 67 },{ 6, 10 },{ 71, 50 },
+ { 39, 52 },{ 61, 0 },{ 28, 26 },{ 9, 46 },{ 57, 22 },{ 19, 73 },{ 47, 36 },{ 75, 34 },
+ { 43, 76 },{ 63, 56 },{ 30, 50 },{ 75, 11 },{ 45, 8 },{ 17, 24 },{ 12, 64 },{ 59, 35 },
+ { 32, 40 },{ 62, 8 },{ 3, 56 },{ 44, 29 },{ 60, 68 },{ 26, 12 },{ 77, 23 },{ 78, 78 },
+ { 17, 41 },{ 29, 67 },{ 33, 2 },{ 36, 32 },{ 48, 63 },{ 77, 46 },{ 68, 21 },{ 11, 71 },
+ { 7, 32 },{ 38, 59 },{ 71, 63 },{ 53, 3 },{ 23, 32 },{ 11, 15 },{ 54, 20 },{ 52, 47 },
+ { 16, 51 },{ 13, 7 },{ 36, 8 },{ 59, 47 },{ 65, 36 },{ 24, 48 },{ 69, 1 },{ 54, 72 },
+ { 38, 44 },{ 46, 19 },{ 76, 70 },{ 78, 37 },{ 23, 74 },{ 76, 15 },{ 6, 64 },{ 29, 17 },
+ { 45, 52 },{ 69, 32 },{ 40, 75 },{ 9, 51 },{ 22, 26 },{ 57, 59 },{ 49, 11 },{ 77, 53 },
+ { 61, 19 },{ 21, 11 },{ 26, 63 },{ 11, 28 },{ 46, 39 },{ 78, 5 },{ 17, 58 },{ 37, 69 },
+ { 41, 26 },{ 13, 37 },{ 64, 62 },{ 6, 14 },{ 55, 5 },{ 18, 77 },{ 21, 37 },{ 63, 49 },
+ { 32, 54 },{ 58, 27 },{ 65, 75 },{ 43, 3 },{ 74, 42 },{ 30, 36 },{ 45, 66 },{ 71, 14 },
+ { 2, 73 },{ 36, 24 },{ 78, 30 },{ 53, 54 },{ 6, 44 },{ 21, 2 },{ 40, 14 },{ 71, 57 },
+ { 42, 36 },{ 51, 25 },{ 16, 71 },{ 3, 20 },{ 58, 73 },{ 25, 53 },{ 7, 5 },{ 59, 38 },
+ { 42, 54 },{ 33, 7 },{ 65, 17 },{ 5, 60 },{ 26, 20 },{ 56, 11 },{ 31, 73 },{ 22, 45 },
+ { 68, 5 },{ 74, 62 },{ 8, 25 },{ 35, 59 },{ 17, 17 },{ 70, 41 },{ 38, 47 },{ 19, 66 },
+ { 61, 65 },{ 47, 28 },{ 74, 76 },{ 17, 30 },{ 4, 49 },{ 51, 0 },{ 71, 30 },{ 50, 69 },
+ { 13, 2 },{ 51, 42 },{ 30, 30 },{ 15, 48 },{ 68, 55 },{ 27, 5 },{ 64, 2 },{ 8, 72 },
+ { 60, 32 },{ 35, 40 },{ 37, 16 },{ 37, 78 },{ 9, 37 },{ 1, 9 },{ 21, 56 },{ 65, 22 },
+ { 36, 63 },{ 50, 57 },{ 1, 64 },{ 2, 38 },{ 56, 43 },{ 51, 14 },{ 19, 13 },{ 25, 70 },
+ { 40, 6 },{ 78, 20 },{ 67, 66 },{ 12, 43 },{ 21, 22 },{ 62, 12 },{ 29, 42 },{ 50, 51 },
+ { 14, 10 },{ 40, 31 },{ 14, 62 },{ 67, 49 },{ 3, 2 },{ 43, 65 },{ 64, 29 },{ 78, 56 },
+ { 43, 21 },{ 30, 60 },{ 58, 3 },{ 5, 27 },{ 46, 76 },{ 74, 47 },{ 74, 8 },{ 49, 33 },
+ { 29, 10 },{ 9, 68 },{ 21, 31 },{ 41, 44 },{ 62, 70 },{ 30, 25 },{ 67, 38 },{ 10, 19 },
+ { 49, 61 },{ 27, 77 },{ 74, 67 },{ 26, 45 },{ 53, 19 },{ 14, 55 },{ 60, 56 },{ 72, 16 },
+ { 44, 12 },{ 35, 50 },{ 74, 26 },{ 18, 7 },{ 33, 68 },{ 14, 29 },{ 70, 72 },{ 54, 37 },
+ { 14, 76 },{ 4, 41 },{ 53, 64 },{ 32, 21 },{ 48, 8 },{ 5, 52 },{ 56, 31 },{ 76, 3 },
+ { 20, 62 },{ 56, 77 },{ 35, 75 },{ 48, 48 },{ 6, 17 },{ 30, 53 },{ 73, 37 },{ 26, 38 },
+ { 34, 28 },{ 59, 17 },{ 60, 43 },{ 5, 69 },{ 67, 61 },{ 23, 16 },{ 11, 33 },{ 43, 72 },
+ { 30, 4 },{ 41, 56 },{ 9, 3 },{ 60, 25 },{ 70, 10 },{ 21, 50 },{ 77, 50 },{ 39, 36 },
+ { 63, 5 },{ 9, 60 },{ 62, 51 },{ 23, 70 },{ 69, 25 },{ 41, 19 },{ 20, 39 },{ 11, 11 },
+ { 44, 60 },{ 75, 58 },{ 48, 25 },{ 1, 0 },{ 32, 11 },{ 45, 4 },{ 13, 23 },{ 64, 43 },
+ { 60, 74 },{ 2, 33 },{ 32, 46 },{ 24, 61 },{ 60, 60 },{ 48, 40 },{ 22, 4 },{ 78, 71 },
+ { 13, 49 },{ 2, 22 },{ 25, 25 },{ 38, 10 },{ 56, 8 },{ 76, 41 },{ 46, 68 },{ 43, 48 },
+ { 8, 75 },{ 62, 35 },{ 74, 19 },{ 20, 76 },{ 18, 44 },{ 44, 32 },{ 38, 72 },{ 73, 0 },
+ { 56, 49 },{ 27, 32 },{ 48, 16 },{ 6, 58 },{ 55, 68 },{ 5, 11 },{ 28, 65 },{ 71, 47 },
+ { 64, 18 },{ 14, 67 },{ 8, 34 },{ 49, 76 },{ 52, 29 },{ 67, 77 },{ 32, 32 },{ 26, 54 },
+ { 13, 14 },{ 30, 16 },{ 70, 65 },{ 38, 41 },{ 76, 32 },{ 17, 35 },{ 52, 9 },{ 54, 57 },
+ { 25, 9 },{ 77, 64 },{ 78, 12 },{ 34, 0 },{ 10, 43 },{ 33, 58 },{ 57, 19 },{ 52, 44 },
+ { 17, 4 },{ 70, 54 },{ 18, 25 },{ 64, 27 },{ 54, 75 },{ 2, 45 },{ 16, 63 },{ 42, 51 },
+ { 36, 26 },{ 66, 11 },{ 17, 55 },{ 30, 71 },{ 64, 59 },{ 5, 7 },{ 73, 25 },{ 13, 74 },
+ { 40, 64 },{ 45, 38 },{ 73, 73 },{ 23, 19 },{ 68, 35 },{ 45, 1 },{ 44, 15 },{ 32, 42 },
+ { 8, 52 },{ 52, 22 },{ 56, 63 },{ 6, 20 },{ 25, 78 },{ 24, 28 },{ 66, 6 },{ 4, 65 },
+ { 52, 39 },{ 2, 29 },{ 33, 62 },{ 22, 40 },{ 62, 47 },{ 37, 7 },{ 56, 1 },{ 48, 54 },
+ { 1, 50 },{ 35, 22 },{ 5, 78 },{ 18, 18 },{ 66, 69 },{ 18, 49 },{ 63, 14 },{ 0, 17 },
+ { 33, 51 },{ 73, 40 },{ 42, 77 },{ 35, 34 },{ 14, 5 },{ 73, 59 },{ 43, 26 },{ 7, 37 },
+ { 28, 74 },{ 72, 5 },{ 56, 28 },{ 50, 71 },{ 25, 57 },{ 65, 34 },{ 0, 74 },{ 39, 57 },
+ { 13, 40 },{ 43, 9 },{ 63, 53 },{ 29, 19 },{ 18, 67 },{ 60, 9 },{ 10, 22 },{ 44, 42 },
+ { 58, 66 },{ 69, 29 },{ 9, 63 },{ 50, 19 },{ 52, 51 },{ 19, 28 },{ 30, 1 },{ 29, 45 },
+ { 69, 74 },{ 68, 47 },{ 9, 9 },{ 36, 67 },{ 1, 61 },{ 76, 22 },{ 27, 14 },{ 47, 30 },
+ { 11, 47 },{ 49, 5 },{ 25, 34 },{ 49, 64 },{ 77, 8 },{ 78, 40 },{ 62, 39 },{ 25, 66 },
+ { 36, 45 },{ 63, 0 },{ 16, 1 },{ 37, 14 },{ 63, 23 },{ 75, 53 },{ 19, 59 },{ 7, 25 },
+ { 22, 10 },{ 53, 32 },{ 56, 53 },{ 69, 18 },{ 40, 73 },{ 11, 78 },{ 39, 33 },{ 23, 51 },
+ { 4, 36 },{ 59, 70 },{ 55, 13 },{ 34, 5 },{ 16, 38 },{ 45, 46 },{ 11, 70 },{ 75, 72 },
+ { 38, 22 },{ 4, 55 },{ 2, 13 },{ 16, 23 },{ 44, 62 },{ 65, 57 },{ 28, 37 },{ 55, 41 },
+ { 21, 71 },{ 69, 13 },{ 39, 1 },{ 74, 32 },{ 46, 21 },{ 13, 52 },{ 51, 78 },{ 40, 49 },
+ { 68, 0 },{ 16, 13 },{ 6, 45 },{ 31, 63 },{ 2, 66 },{ 65, 44 },{ 13, 31 },{ 60, 6 },
+ { 50, 36 },{ 28, 23 },{ 55, 60 },{ 3, 5 },{ 25, 3 },{ 34, 38 },{ 68, 62 },{ 55, 23 },
+ { 11, 61 },{ 78, 27 },{ 40, 69 },{ 21, 44 },{ 51, 11 },{ 31, 55 },{ 10, 16 },{ 69, 51 },
+ { 33, 13 },{ 5, 76 },{ 47, 56 },{ 68, 23 },{ 39, 29 },{ 32, 75 },{ 72, 69 },{ 76, 36 },
+ { 59, 76 },{ 58, 48 },{ 22, 0 },{ 9, 29 },{ 58, 31 },{ 75, 16 },{ 22, 60 },{ 46, 71 },
+ { 31, 28 },{ 78, 52 },{ 41, 41 },{ 40, 11 },{ 75, 2 },{ 15, 45 },{ 60, 63 },{ 61, 14 },
+ { 18, 10 },{ 27, 50 },{ 71, 42 },{ 22, 23 },{ 16, 70 },{ 47, 3 },{ 40, 59 },{ 58, 38 },
+ { 63, 72 },{ 11, 57 },{ 42, 18 },{ 4, 31 },{ 11, 4 },{ 49, 47 },{ 55, 16 },{ 27, 71 },
+ { 77, 59 },{ 26, 17 },{ 25, 40 },{ 7, 13 },{ 71, 9 },{ 1, 43 },{ 43, 35 },{ 50, 66 },
+ { 66, 30 },{ 6, 70 },{ 37, 53 },{ 20, 33 },{ 60, 52 },{ 60, 21 },{ 27, 8 },{ 0, 77 },
+ { 54, 4 },{ 6, 48 },{ 39, 4 },{ 15, 20 },{ 27, 61 },{ 71, 60 },{ 53, 26 },{ 33, 19 },
+ { 70, 36 },{ 51, 58 },{ 20, 56 },{ 66, 74 },{ 35, 72 },{ 12, 26 },{ 32, 35 },{ 9, 66 },
+ { 72, 21 },{ 74, 49 },{ 53, 72 },{ 35, 47 },{ 46, 13 },{ 15, 77 },{ 10, 38 },{ 3, 17 },
+ { 53, 48 },{ 69, 4 },{ 49, 29 },{ 37, 64 },{ 27, 30 },{ 74, 65 },{ 62, 33 },{ 17, 48 },
+ { 21, 6 },{ 42, 23 },{ 1, 8 },{ 43, 55 },{ 64, 65 },{ 7, 54 },{ 64, 8 },{ 22, 65 },
+ { 66, 41 },{ 33, 10 },{ 1, 24 },{ 25, 46 },{ 44, 77 },{ 49, 39 },{ 3, 73 },{ 14, 36 },
+ { 59, 58 },{ 24, 76 },{ 50, 15 },{ 71, 27 },{ 19, 16 },{ 59, 2 },{ 36, 31 },{ 67, 54 },
+ { 30, 57 },{ 7, 41 },{ 46, 51 },{ 7, 0 },{ 44, 68 },{ 70, 15 },{ 37, 19 },{ 78, 46 },
+ { 13, 64 },{ 57, 44 },{ 31, 3 },{ 16, 28 },{ 60, 24 },{ 75, 76 },{ 30, 39 },{ 56, 73 },
+ { 32, 69 },{ 15, 7 },{ 2, 58 },{ 40, 39 },{ 7, 22 },{ 43, 6 },{ 16, 57 },{ 55, 34 },
+ { 57, 9 },{ 5, 34 },{ 52, 63 },{ 24, 13 },{ 75, 6 },{ 72, 55 },{ 29, 48 },{ 33, 25 },
+ { 18, 74 },{ 72, 33 },{ 67, 71 },{ 48, 22 },{ 22, 30 },{ 10, 50 },{ 61, 45 },{ 36, 77 },
+ { 78, 14 },{ 42, 63 },{ 0, 67 },{ 64, 21 },{ 48, 44 },{ 14, 15 },{ 50, 74 },{ 16, 43 },
+ { 28, 68 },{ 45, 34 },{ 50, 7 },{ 69, 44 },{ 6, 5 },{ 38, 50 },{ 1, 37 },{ 66, 2 },
+ { 23, 54 },{ 39, 15 },{ 57, 57 },{ 14, 72 },{ 19, 23 },{ 5, 63 },{ 77, 25 },{ 41, 29 },
+ { 59, 68 },{ 20, 1 },{ 23, 36 },{ 63, 16 },{ 36, 58 },{ 62, 29 },{ 30, 11 },{ 35, 42 },
+ { 68, 66 },{ 19, 63 },{ 74, 11 },{ 48, 1 },{ 72, 50 },{ 10, 12 },{ 4, 28 },{ 51, 53 },
+ { 29, 78 },{ 50, 24 },{ 22, 48 },{ 27, 20 },{ 64, 38 },{ 72, 78 },{ 0, 55 },{ 42, 74 },
+ { 47, 60 },{ 15, 33 },{ 8, 73 },{ 54, 11 },{ 75, 39 },{ 37, 37 },{ 63, 61 },{ 35, 3 },
+ { 12, 45 },{ 12, 20 },{ 53, 36 },{ 33, 66 },{ 67, 10 },{ 1, 70 },{ 29, 29 },{ 45, 18 },
+ { 59, 78 },{ 11, 53 },{ 24, 6 },{ 64, 49 },{ 66, 26 },{ 29, 53 },{ 43, 46 },{ 7, 9 },
+ { 20, 68 },{ 77, 30 },{ 34, 16 },{ 76, 63 },{ 54, 69 },{ 56, 25 },{ 19, 38 },{ 55, 46 },
+ { 1, 3 },{ 47, 9 },{ 3, 48 },{ 38, 66 },{ 71, 19 },{ 27, 42 },{ 14, 59 },{ 26, 25 },
+ { 54, 78 },{ 45, 27 },{ 7, 18 },{ 24, 73 },{ 68, 58 },{ 9, 31 },{ 59, 41 },{ 41, 53 },
+ { 58, 16 },{ 70, 75 },{ 12, 6 },{ 41, 7 },{ 27, 58 },{ 73, 45 },{ 48, 67 },{ 22, 18 },
+ { 6, 39 },{ 51, 31 },{ 8, 59 },{ 62, 4 },{ 10, 76 },{ 43, 40 },{ 77, 19 },{ 62, 55 },
+ { 39, 25 },{ 31, 76 },{ 17, 53 },{ 69, 34 },{ 19, 8 },{ 71, 67 },{ 32, 49 },{ 41, 0 },
+ { 14, 25 },{ 57, 62 },{ 34, 32 },{ 65, 13 },{ 45, 58 },{ 4, 68 },{ 42, 13 },{ 11, 41 },
+ { 77, 0 },{ 60, 36 },{ 25, 62 },{ 4, 14 },{ 30, 7 },{ 23, 43 },{ 54, 18 },{ 62, 75 },
+ { 0, 33 },{ 45, 49 },{ 4, 53 },{ 25, 32 },{ 54, 54 },{ 39, 71 },{ 57, 6 },{ 13, 69 },
+ { 4, 23 },{ 66, 51 },{ 20, 13 },{ 34, 56 },{ 47, 37 },{ 69, 21 },{ 75, 57 },{ 31, 20 },
+ { 14, 1 },{ 48, 73 },{ 77, 42 },{ 70, 6 },{ 31, 44 },{ 60, 27 },{ 20, 73 },{ 62, 67 },
+ { 35, 9 },{ 18, 31 },{ 77, 11 },{ 41, 33 },{ 37, 61 },{ 67, 40 },{ 4, 61 },{ 49, 19 },
+ { 19, 47 },{ 2, 76 },{ 53, 41 },{ 27, 2 },{ 72, 29 },{ 52, 3 },{ 20, 21 },{ 16, 65 },
+ { 39, 46 },{ 58, 51 },{ 72, 71 },{ 10, 34 },{ 40, 21 },{ 59, 11 },{ 78, 48 },{ 31, 62 },
+ { 54, 65 },{ 14, 9 },{ 34, 27 },{ 38, 76 },{ 0, 21 },{ 8, 49 },{ 4, 3 },{ 58, 33 },
+ { 26, 68 },{ 65, 63 },{ 29, 13 },{ 28, 35 },{ 60, 18 },{ 25, 51 },{ 51, 49 },{ 3, 41 },
+ { 48, 11 },{ 76, 69 },{ 73, 13 },{ 45, 64 },{ 21, 27 },{ 19, 3 },{ 66, 32 },{ 8, 65 },
+ { 64, 77 },{ 17, 40 },{ 48, 32 },{ 47, 77 },{ 7, 28 },{ 66, 46 },{ 17, 61 },{ 38, 6 },
+ { 37, 43 },{ 8, 16 },{ 53, 59 },{ 74, 3 },{ 46, 24 },{ 26, 74 },{ 73, 53 },{ 71, 39 },
+ { 16, 17 },{ 39, 55 },{ 57, 71 },{ 67, 24 },{ 13, 55 },{ 35, 17 },{ 9, 0 },{ 47, 42 },
+ { 42, 70 },{ 56, 21 },{ 21, 53 },{ 71, 62 },{ 25, 22 },{ 75, 24 },{ 27, 39 },{ 67, 8 },
+ { 33, 73 },{ 77, 35 },{ 25, 11 },{ 61, 57 },{ 9, 69 },{ 53, 6 },{ 9, 44 },{ 34, 52 },
+ { 3, 8 },{ 37, 28 },{ 59, 43 },{ 0, 60 },{ 45, 15 },{ 27, 64 },{ 10, 27 },{ 64, 70 },
+ { 22, 77 },{ 55, 29 },{ 19, 36 },{ 50, 61 },{ 68, 16 },{ 44, 3 },{ 77, 75 },{ 2, 51 },
+ { 36, 36 },{ 1, 16 },{ 44, 53 },{ 32, 5 },{ 56, 38 },{ 61, 1 },{ 13, 13 },{ 14, 50 },
+ { 70, 49 },{ 51, 70 },{ 31, 25 },{ 12, 74 },{ 3, 32 },{ 53, 15 },{ 35, 68 },{ 51, 44 },
+ { 28, 55 },{ 70, 2 },{ 43, 30 },{ 14, 30 },{ 7, 57 },{ 69, 28 },{ 37, 11 },{ 23, 69 },
+ { 69, 59 },{ 19, 42 },{ 52, 76 },{ 17, 6 },{ 55, 50 },{ 30, 33 },{ 62, 11 },{ 9, 20 },
+ { 76, 44 },{ 42, 60 },{ 4, 72 },{ 25, 16 },{ 51, 28 },{ 58, 64 },{ 22, 59 },{ 78, 7 },
+ { 63, 42 },{ 33, 1 },{ 30, 47 },{ 3, 26 },{ 73, 66 },{ 44, 8 },{ 12, 38 },{ 41, 37 },
+ { 66, 20 },{ 17, 77 },{ 40, 67 },{ 67, 37 },{ 12, 61 },{ 25, 28 },{ 55, 2 },{ 65, 55 },
+ { 36, 20 },{ 74, 17 },{ 37, 48 },{ 4, 46 },{ 8, 3 },{ 68, 72 },{ 50, 54 },{ 61, 30 },
+ { 16, 21 },{ 29, 72 },{ 34, 60 },{ 52, 21 },{ 1, 63 },{ 23, 41 },{ 25, 7 },{ 74, 36 },
+ { 45, 74 },{ 64, 3 },{ 51, 38 },{ 16, 68 },{ 76, 55 },{ 31, 15 },{ 34, 40 },{ 75, 28 },
+ { 57, 13 },{ 10, 7 },{ 61, 48 },{ 19, 51 },{ 44, 24 },{ 61, 72 },{ 37, 2 },{ 3, 38 },
+ { 2, 11 },{ 42, 44 },{ 73, 77 },{ 17, 27 },{ 48, 57 },{ 22, 63 },{ 22, 14 },{ 62, 25 },
+ { 47, 69 },{ 14, 46 },{ 47, 17 },{ 61, 61 },{ 6, 67 },{ 70, 46 },{ 73, 9 },{ 31, 31 },
+ { 46, 5 },{ 29, 60 },{ 5, 21 },{ 24, 0 },{ 46, 48 },{ 9, 55 },{ 52, 33 },{ 2, 0 },
+ { 7, 33 },{ 26, 44 },{ 66, 67 },{ 41, 10 },{ 17, 12 },{ 57, 54 },{ 59, 8 },{ 30, 22 },
+ { 72, 23 },{ 36, 73 },{ 5, 50 },{ 76, 72 },{ 62, 36 },{ 21, 34 },{ 18, 70 },{ 52, 67 },
+ { 31, 52 },{ 58, 20 },{ 12, 17 },{ 45, 41 },{ 69, 56 },{ 39, 23 },{ 57, 78 },{ 18, 56 },
+ { 70, 32 },{ 13, 78 },{ 39, 63 },{ 13, 35 },{ 68, 12 },{ 29, 4 },{ 76, 50 },{ 31, 37 },
+ { 51, 10 },{ 11, 65 },{ 48, 26 },{ 40, 51 },{ 78, 4 },{ 20, 24 },{ 30, 66 },{ 0, 40 },
+ { 54, 45 },{ 78, 65 },{ 41, 16 },{ 8, 13 },{ 43, 0 },{ 1, 27 },{ 54, 62 },{ 67, 76 },
+ { 25, 48 },{ 68, 43 },{ 38, 33 },{ 6, 74 },{ 58, 26 },{ 15, 41 },{ 21, 8 },{ 2, 56 },
+ { 66, 16 },{ 44, 57 },{ 28, 17 },{ 61, 53 },{ 50, 3 },{ 11, 24 },{ 21, 75 },{ 47, 35 },
+ { 73, 60 },{ 55, 75 },{ 24, 56 },{ 75, 21 },{ 33, 43 },{ 6, 43 },{ 35, 13 },{ 64, 32 },
+ { 34, 64 },{ 15, 3 },{ 67, 4 },{ 62, 64 },{ 23, 26 },{ 34, 75 },{ 56, 42 },{ 4, 18 },
+ { 52, 13 },{ 13, 58 },{ 24, 37 },{ 47, 63 },{ 69, 69 },{ 42, 27 },{ 74, 43 },{ 5, 1 },
+ { 63, 19 },{ 20, 65 },{ 32, 8 },{ 49, 50 },{ 0, 30 },{ 16, 52 },{ 44, 71 },{ 61, 6 },
+ { 56, 35 },{ 18, 19 },{ 6, 60 },{ 36, 54 },{ 76, 14 },{ 65, 52 },{ 35, 24 },{ 9, 40 },
+ { 28, 78 },{ 1, 72 },{ 40, 42 },{ 41, 3 },{ 12, 10 },{ 57, 69 },{ 17, 33 },{ 52, 24 },
+ { 72, 74 },{ 69, 38 },{ 21, 46 },{ 52, 56 },{ 10, 72 },{ 43, 12 },{ 1, 46 },{ 29, 26 },
+ { 75, 7 },{ 24, 67 },{ 45, 31 },{ 65, 27 },{ 38, 58 },{ 12, 29 },{ 70, 52 },{ 23, 4 },
+ { 50, 78 },{ 6, 7 },{ 61, 41 },{ 30, 41 },{ 60, 14 },{ 75, 64 },{ 42, 66 },{ 25, 19 },
+ { 11, 48 },{ 45, 20 },{ 73, 34 },{ 16, 74 },{ 62, 77 },{ 47, 45 },{ 6, 25 },{ 25, 60 },
+ { 64, 58 },{ 37, 0 },{ 72, 17 },{ 35, 30 },{ 78, 57 },{ 33, 48 },{ 28, 10 },{ 64, 10 },
+ { 6, 36 },{ 59, 46 },{ 14, 63 },{ 54, 8 },{ 35, 70 },{ 55, 31 },{ 17, 15 },{ 72, 2 },
+ { 24, 34 },{ 67, 63 },{ 38, 18 },{ 31, 58 },{ 11, 2 },{ 1, 19 },{ 52, 73 },{ 9, 53 },
+ { 38, 38 },{ 57, 60 },{ 70, 25 },{ 75, 47 },{ 26, 72 },{ 50, 16 },{ 2, 68 },{ 20, 29 },
+ { 42, 50 },{ 35, 6 },{ 13, 22 },{ 59, 23 },{ 19, 45 },{ 47, 66 },{ 64, 46 },{ 5, 10 },
+ { 50, 41 },{ 65, 0 },{ 8, 62 },{ 27, 53 },{ 0, 35 },{ 32, 18 },{ 19, 78 },{ 58, 74 },
+ { 42, 35 },{ 53, 52 },{ 78, 1 },{ 41, 75 },{ 11, 32 },{ 47, 7 },{ 0, 53 },{ 59, 31 },
+ { 23, 11 },{ 20, 59 },{ 74, 29 },{ 75, 68 },{ 8, 46 },{ 71, 10 },{ 33, 36 },{ 45, 61 },
+ { 7, 77 },{ 50, 21 },{ 30, 70 },{ 60, 66 },{ 16, 36 },{ 5, 15 },{ 39, 8 },{ 50, 35 },
+ { 27, 46 },{ 72, 39 },{ 13, 67 },{ 57, 4 },{ 27, 23 },{ 60, 51 },{ 16, 9 },{ 64, 24 },
+ { 36, 50 },{ 73, 57 },{ 32, 77 },{ 42, 21 },{ 6, 30 },{ 65, 72 },{ 45, 54 },{ 78, 24 },
+ { 13, 43 },{ 57, 17 },{ 22, 70 },{ 27, 31 },{ 47, 0 },{ 64, 39 },{ 69, 7 },{ 4, 58 },
+ { 27, 6 },{ 36, 62 },{ 40, 27 },{ 56, 56 },{ 0, 10 },{ 20, 54 },{ 21, 17 },{ 2, 43 },
+ { 7, 71 },{ 44, 38 },{ 48, 70 },{ 67, 18 },{ 66, 48 },{ 11, 18 },{ 48, 14 },{ 22, 39 },
+ { 71, 70 },{ 18, 2 },{ 41, 47 },{ 54, 28 },{ 29, 64 },{ 77, 77 },{ 67, 33 },{ 16, 60 },
+ { 39, 13 },{ 50, 64 },{ 15, 25 },{ 66, 59 },{ 29, 50 },{ 57, 39 },{ 52, 1 },{ 33, 22 },
+ { 76, 38 },{ 9, 11 },{ 26, 1 },{ 70, 78 },{ 16, 49 },{ 51, 46 },{ 56, 12 },{ 76, 61 },
+ { 38, 68 },{ 76, 16 },{ 36, 40 },{ 14, 71 },{ 26, 13 },{ 73, 51 },{ 55, 71 },{ 46, 28 },
+ { 5, 40 },{ 12, 4 },{ 40, 56 },{ 70, 22 },{ 26, 36 },{ 40, 78 },{ 64, 5 },{ 5, 53 },
+ { 9, 24 },{ 5, 66 },{ 61, 34 },{ 63, 68 },{ 45, 10 },{ 24, 49 },{ 37, 30 },{ 2, 6 },
+ { 56, 48 },{ 30, 74 },{ 22, 21 },{ 77, 32 },{ 33, 57 },{ 61, 16 },{ 17, 64 },{ 71, 44 },
+ { 32, 14 },{ 50, 59 },{ 70, 64 },{ 15, 39 },{ 53, 22 },{ 1, 75 },{ 34, 45 },{ 46, 75 },
+ { 2, 21 },{ 20, 5 },{ 12, 54 },{ 53, 39 },{ 24, 30 },{ 67, 29 },{ 58, 0 },{ 36, 4 },
+ { 72, 13 },{ 47, 52 },{ 25, 65 },{ 8, 35 },{ 59, 60 },{ 32, 28 },{ 13, 76 },{ 0, 48 },
+ { 49, 8 },{ 49, 31 },{ 73, 5 },{ 21, 43 },{ 41, 61 },{ 3, 62 },{ 15, 18 },{ 38, 16 },
+ { 67, 52 },{ 62, 9 },{ 46, 44 },{ 26, 55 },{ 20, 11 },{ 57, 67 },{ 76, 27 },{ 38, 74 },
+ { 78, 70 },{ 57, 27 },{ 29, 38 },{ 19, 71 },{ 3, 36 },{ 8, 5 },{ 63, 43 },{ 43, 18 },
+ { 11, 50 },{ 66, 75 },{ 13, 27 },{ 35, 65 },{ 42, 33 },{ 0, 15 },{ 52, 5 },{ 9, 58 },
+ { 58, 55 },{ 24, 24 },{ 62, 20 },{ 32, 0 },{ 39, 43 },{ 74, 54 },{ 3, 78 },{ 35, 11 },
+ { 69, 40 },{ 19, 32 },{ 43, 68 },{ 52, 18 },{ 22, 57 },{ 60, 75 },{ 9, 14 },{ 58, 35 },
+ { 10, 68 },{ 28, 43 },{ 73, 26 },{ 66, 64 },{ 23, 75 },{ 7, 47 },{ 36, 23 },{ 52, 61 },
+ { 66, 14 },{ 24, 9 },{ 53, 47 },{ 74, 74 },{ 42, 5 },{ 35, 55 },{ 5, 26 },{ 17, 47 },
+ { 47, 25 },{ 73, 47 },{ 76, 4 },{ 31, 67 },{ 34, 35 },{ 58, 7 },{ 14, 11 },{ 63, 50 },
+ { 11, 37 },{ 49, 72 },{ 29, 20 },{ 71, 31 },{ 43, 59 },{ 8, 76 },{ 49, 38 },{ 73, 62 },
+ { 16, 54 },{ 74, 20 },{ 68, 1 },{ 21, 67 },{ 30, 6 },{ 78, 43 },{ 41, 25 },{ 48, 49 },
+ { 15, 31 },{ 62, 71 },{ 64, 36 },{ 32, 60 },{ 4, 13 },{ 50, 12 },{ 18, 76 },{ 28, 27 },
+ { 0, 66 },{ 41, 71 },{ 38, 46 },{ 2, 31 },{ 61, 23 },{ 6, 56 },{ 48, 2 },{ 62, 58 },
+ { 19, 20 },{ 23, 45 },{ 24, 2 },{ 53, 34 },{ 64, 12 },{ 53, 65 },{ 11, 63 },{ 28, 15 },
+ { 42, 39 },{ 76, 9 },{ 67, 45 },{ 20, 37 },{ 7, 23 },{ 28, 59 },{ 47, 20 },{ 68, 68 },
+ { 53, 77 },{ 29, 76 },{ 78, 51 },{ 11, 9 },{ 46, 55 },{ 63, 27 },{ 7, 42 },{ 38, 9 },
+ { 32, 51 },{ 4, 74 },{ 32, 33 },{ 61, 3 },{ 57, 46 },{ 75, 35 },{ 16, 4 },{ 19, 61 },
+ { 50, 27 },{ 70, 57 },{ 34, 71 },{ 55, 15 },{ 18, 26 },{ 70, 16 },{ 14, 42 },{ 44, 75 },
+ { 53, 55 },{ 4, 5 },{ 39, 31 },{ 2, 59 },{ 60, 40 },{ 23, 52 },{ 19, 15 },{ 35, 15 },
+ { 74, 71 },{ 42, 64 },{ 0, 23 },{ 15, 73 },{ 31, 40 },{ 52, 69 },{ 68, 6 },{ 38, 52 },
+ { 78, 38 },{ 39, 20 },{ 59, 29 },{ 27, 67 },{ 8, 19 },{ 67, 55 },{ 42, 2 },{ 11, 45 },
+ { 48, 43 },{ 11, 0 },{ 23, 33 },{ 56, 10 },{ 7, 64 },{ 68, 26 },{ 59, 62 },{ 29, 8 },
+ { 9, 32 },{ 45, 35 },{ 71, 75 },{ 2, 49 },{ 35, 0 },{ 23, 62 },{ 57, 21 },{ 72, 41 },
+ { 0, 12 },{ 31, 46 },{ 45, 13 },{ 59, 50 },{ 23, 20 },{ 15, 57 },{ 48, 62 },{ 72, 65 },
+ { 56, 2 },{ 12, 15 },{ 44, 50 },{ 36, 27 },{ 25, 71 },{ 66, 34 },{ 2, 2 },{ 20, 50 },
+ { 68, 20 },{ 59, 71 },{ 29, 32 },{ 5, 33 },{ 21, 4 },{ 54, 43 },{ 3, 69 },{ 45, 6 },
+ { 77, 54 },{ 38, 60 },{ 15, 23 },{ 54, 26 },{ 72, 8 },{ 25, 41 },{ 15, 66 },{ 30, 18 },
+ { 68, 50 },{ 51, 75 },{ 42, 42 },{ 4, 44 },{ 37, 70 },{ 74, 78 },{ 0, 28 },{ 45, 23 },
+ { 64, 61 },{ 11, 73 },{ 61, 12 },{ 29, 56 },{ 34, 7 },{ 18, 35 },{ 76, 18 },{ 55, 52 },
+ { 37, 35 },{ 19, 10 },{ 10, 56 },{ 63, 74 },{ 71, 37 },{ 46, 67 },{ 47, 32 },{ 7, 8 },
+ { 78, 63 },{ 41, 14 },{ 22, 27 },{ 63, 31 },{ 26, 75 },{ 14, 52 },{ 56, 65 },{ 35, 48 },
+ { 65, 8 },{ 8, 27 },{ 25, 14 },{ 55, 19 },{ 32, 65 },{ 60, 38 },{ 19, 41 },{ 39, 77 },
+ { 7, 2 },{ 50, 56 },{ 7, 51 },{ 33, 24 },{ 69, 71 },{ 74, 14 },{ 71, 48 },{ 19, 69 },
+ { 51, 6 },{ 12, 34 },{ 43, 45 },{ 28, 3 },{ 66, 22 },{ 72, 59 },{ 5, 17 },{ 28, 49 },
+ { 54, 38 },{ 17, 1 },{ 63, 2 },{ 2, 40 },{ 49, 17 },{ 42, 56 },{ 8, 69 },{ 74, 31 },
+ { 35, 38 },{ 32, 12 },{ 61, 54 },{ 46, 73 },{ 13, 20 },{ 19, 57 },{ 44, 28 },{ 77, 73 },
+ { 64, 67 },{ 27, 25 },{ 63, 45 },{ 28, 62 },{ 40, 5 },{ 11, 40 },{ 0, 6 },{ 3, 54 },
+ { 57, 30 },{ 53, 9 },{ 16, 14 },{ 46, 59 },{ 74, 23 },{ 20, 48 },{ 56, 75 },{ 11, 60 },
+ { 50, 45 },{ 35, 19 },{ 21, 0 },{ 76, 46 },{ 69, 12 },{ 26, 34 },{ 32, 71 },{ 3, 24 },
+ { 55, 58 },{ 71, 1 },{ 66, 38 },{ 37, 55 },{ 13, 6 },{ 43, 10 },{ 3, 64 },{ 51, 34 },
+ { 15, 29 },{ 69, 61 },{ 36, 44 },{ 59, 18 },{ 45, 0 },{ 15, 69 },{ 1, 34 },{ 41, 30 },
+ { 49, 68 },{ 16, 44 },{ 27, 11 },{ 59, 5 },{ 68, 30 },{ 25, 58 },{ 6, 78 },{ 77, 58 },
+ { 33, 3 },{ 46, 40 },{ 21, 23 },{ 38, 65 },{ 3, 10 },{ 49, 23 },{ 60, 47 },{ 23, 38 },
+ { 69, 77 },{ 6, 38 },{ 64, 16 },{ 29, 69 },{ 61, 68 },{ 33, 29 },{ 49, 52 },{ 68, 42 },
+ { 22, 7 },{ 15, 61 },{ 2, 16 },{ 45, 16 },{ 76, 66 },{ 27, 51 },{ 36, 75 },{ 5, 47 },
+ { 11, 22 },{ 57, 24 },{ 64, 56 },{ 39, 39 },{ 15, 78 },{ 54, 1 },{ 77, 2 },{ 26, 18 },
+ { 72, 27 },{ 41, 49 },{ 71, 53 },{ 21, 30 },{ 5, 71 },{ 44, 65 },{ 57, 36 },{ 61, 78 },
+ { 25, 43 },{ 40, 18 },{ 21, 73 },{ 4, 29 },{ 75, 41 },{ 35, 61 },{ 48, 4 },{ 10, 51 },
+ { 58, 14 },{ 55, 61 },{ 12, 13 },{ 30, 35 },{ 70, 18 },{ 21, 64 },{ 51, 30 },{ 30, 0 },
+ { 68, 65 },{ 15, 37 },{ 58, 42 },{ 71, 5 },{ 38, 25 },{ 7, 61 },{ 31, 54 },{ 54, 71 },
+ { 22, 16 },{ 70, 35 },{ 40, 72 },{ 9, 6 },{ 75, 51 },{ 36, 12 },{ 53, 50 },{ 4, 20 },
+ { 13, 47 },{ 52, 14 },{ 0, 76 },{ 33, 42 },{ 65, 25 },{ 22, 55 },{ 10, 29 },{ 61, 63 },
+ { 17, 7 },{ 43, 32 },{ 12, 70 },{ 38, 4 },{ 66, 1 },{ 0, 44 },{ 40, 54 },{ 30, 23 },
+ { 49, 77 },{ 76, 12 },{ 74, 69 },{ 48, 37 },{ 26, 78 },{ 65, 47 },{ 17, 20 },{ 47, 11 },
+ { 28, 45 },{ 0, 56 },{ 77, 21 },{ 51, 62 },{ 63, 33 },{ 9, 75 },{ 25, 29 },{ 62, 7 },
+ { 47, 47 },{ 18, 65 },{ 9, 42 },{ 42, 22 },{ 40, 62 },{ 66, 70 },{ 78, 31 },{ 24, 5 },
+ { 54, 24 },{ 18, 51 },{ 59, 57 },{ 7, 11 },{ 33, 67 },{ 55, 6 },{ 16, 32 },{ 64, 41 },
+ { 32, 9 },{ 10, 66 },{ 65, 18 },{ 40, 35 },{ 45, 70 },{ 78, 61 },{ 33, 52 },{ 68, 10 },
+ { 10, 17 },{ 57, 52 },{ 28, 73 },{ 18, 40 },{ 55, 32 },{ 3, 52 },{ 33, 17 },{ 75, 75 },
+ { 56, 68 },{ 74, 38 },{ 17, 73 },{ 42, 78 },{ 29, 28 },{ 52, 41 },{ 17, 59 },{ 71, 23 },
+ { 17, 25 },{ 69, 54 },{ 53, 16 },{ 37, 41 },{ 5, 4 },{ 30, 62 },{ 10, 36 },{ 39, 11 },
+ { 65, 76 },{ 45, 51 },{ 22, 13 },{ 61, 27 },{ 24, 47 },{ 0, 71 },{ 1, 26 },{ 49, 58 },
+ { 13, 3 },{ 47, 29 },{ 59, 73 },{ 71, 45 },{ 34, 77 },{ 12, 56 },{ 74, 9 },{ 34, 33 },
+ { 67, 59 },{ 47, 19 },{ 24, 69 },{ 3, 35 },{ 27, 21 },{ 37, 57 },{ 0, 18 },{ 58, 10 },
+ { 26, 39 },{ 9, 47 },{ 49, 74 },{ 60, 45 },{ 5, 64 },{ 15, 12 },{ 42, 8 },{ 62, 22 },
+ { 24, 53 },{ 74, 56 },{ 73, 32 },{ 41, 68 },{ 45, 37 },{ 74, 2 },{ 10, 25 },{ 22, 76 },
+ { 39, 48 },{ 70, 68 },{ 30, 12 },{ 64, 51 },{ 21, 36 },{ 55, 77 },{ 68, 14 },{ 10, 1 },
+ { 35, 21 },{ 61, 37 },{ 26, 64 },{ 52, 66 },{ 51, 26 },{ 5, 57 },{ 7, 31 },{ 38, 1 },
+ { 76, 48 },{ 1, 7 },{ 32, 47 },{ 51, 48 },{ 26, 5 },{ 49, 10 },{ 18, 46 },{ 66, 4 },
+ { 38, 27 },{ 7, 73 },{ 7, 16 },{ 62, 65 },{ 1, 39 },{ 34, 59 },{ 20, 19 },{ 56, 40 },
+ { 69, 31 },{ 13, 66 },{ 46, 62 },{ 43, 20 },{ 19, 30 },{ 74, 63 },{ 73, 20 },{ 37, 72 },
+ { 44, 44 },{ 13, 50 },{ 58, 2 },{ 20, 9 },{ 53, 57 },{ 31, 39 },{ 60, 19 },{ 3, 76 },
+ { 24, 59 },{ 46, 4 },{ 5, 42 },{ 32, 26 },{ 69, 73 },{ 69, 48 },{ 14, 17 },{ 53, 29 },
+ { 32, 4 },{ 43, 54 },{ 76, 29 },{ 78, 68 },{ 15, 75 },{ 13, 33 },{ 61, 59 },{ 63, 13 },
+ { 8, 54 },{ 42, 15 },{ 28, 70 },{ 1, 13 },{ 48, 41 },{ 24, 27 },{ 59, 32 },{ 44, 73 },
+ { 19, 55 },{ 12, 8 },{ 72, 43 },{ 35, 51 },{ 54, 10 },{ 58, 49 },{ 6, 23 },{ 38, 32 },
+ { 23, 1 },{ 57, 64 },{ 13, 41 },{ 77, 5 },{ 2, 61 },{ 53, 20 },{ 30, 15 },{ 61, 76 },
+ { 29, 43 },{ 22, 66 },{ 67, 35 },{ 50, 1 },{ 71, 12 },{ 5, 49 },{ 37, 66 },{ 28, 33 },
+ { 66, 61 },{ 45, 25 },{ 48, 53 },{ 13, 60 },{ 36, 7 },{ 68, 24 },{ 18, 23 },{ 28, 57 },
+ { 76, 78 },{ 53, 44 },{ 18, 5 },{ 77, 37 },{ 53, 70 },{ 7, 68 },{ 20, 43 },{ 31, 75 },
+ { 66, 7 },{ 49, 34 },{ 12, 28 },{ 37, 17 },{ 75, 59 },{ 41, 59 },{ 64, 54 },{ 4, 9 },
+ { 59, 25 },{ 39, 45 },{ 24, 18 },{ 1, 45 },{ 47, 14 },{ 12, 77 },{ 76, 23 },{ 64, 73 },
+ { 22, 50 },{ 65, 40 },{ 44, 1 },{ 18, 68 },{ 9, 21 },{ 39, 37 },{ 49, 65 },{ 9, 38 },
+ { 26, 10 },{ 72, 73 },{ 65, 28 },{ 57, 15 },{ 27, 37 },{ 72, 52 },{ 32, 63 },{ 3, 1 },
+ { 55, 4 },{ 40, 24 },{ 15, 53 },{ 73, 16 },{ 55, 55 },{ 20, 75 },{ 55, 36 },{ 18, 14 },
+ { 40, 76 },{ 10, 62 },{ 5, 28 },{ 33, 31 },{ 65, 66 },{ 30, 52 },{ 68, 3 },{ 1, 54 },
+ { 29, 2 },{ 72, 35 },{ 43, 41 },{ 17, 36 },{ 55, 73 },{ 3, 71 },{ 50, 22 },{ 62, 48 },
+ { 24, 23 },{ 36, 69 },{ 6, 12 },{ 47, 58 },{ 61, 10 },{ 10, 44 },{ 41, 12 },{ 18, 62 },
+ { 70, 28 },{ 39, 51 },{ 70, 62 },{ 15, 8 },{ 44, 31 },{ 23, 31 },{ 66, 43 },{ 23, 72 },
+ { 77, 17 },{ 51, 8 },{ 27, 48 },{ 55, 47 },{ 34, 10 },{ 60, 69 },{ 78, 41 },{ 64, 22 },
+ { 1, 66 },{ 43, 62 },{ 33, 21 },{ 9, 2 },{ 47, 76 },{ 3, 33 },{ 34, 44 },{ 71, 7 },
+ { 15, 27 },{ 6, 59 },{ 51, 36 },{ 36, 1 },{ 32, 56 },{ 77, 49 },{ 19, 1 },{ 55, 22 },
+ { 15, 46 },{ 63, 78 },{ 51, 51 },{ 3, 21 },{ 12, 72 },{ 72, 67 },{ 27, 16 },{ 23, 40 },
+ { 45, 7 },{ 59, 34 },{ 58, 59 },{ 24, 63 },{ 78, 9 },{ 36, 29 },{ 40, 66 },{ 63, 17 },
+ { 14, 19 },{ 71, 56 },{ 44, 47 },{ 28, 77 },{ 50, 18 },{ 8, 50 },{ 50, 70 },{ 76, 26 },
+ { 34, 37 },{ 72, 76 },{ 10, 11 },{ 61, 43 },{ 20, 26 },{ 31, 69 },{ 5, 38 },{ 21, 58 },
+ { 60, 1 },{ 43, 27 },{ 28, 8 },{ 68, 37 },{ 6, 76 },{ 54, 63 },{ 69, 19 },{ 24, 44 },
+ { 59, 54 },{ 39, 6 },{ 11, 58 },{ 29, 24 },{ 74, 46 },{ 0, 2 },{ 43, 37 },{ 56, 7 },
+ { 10, 31 },{ 17, 71 },{ 64, 30 },{ 42, 72 },{ 21, 12 },{ 66, 56 },{ 27, 54 },{ 44, 17 },
+ { 75, 70 },{ 50, 42 },{ 16, 39 },{ 3, 15 },{ 45, 56 },{ 65, 10 },{ 55, 27 },{ 34, 74 },
+ { 7, 66 },{ 30, 31 },{ 77, 33 },{ 53, 78 },{ 1, 51 },{ 36, 14 },{ 36, 49 },{ 15, 5 },
+ { 67, 74 },{ 12, 23 },{ 34, 62 },{ 68, 46 },{ 49, 13 },{ 19, 53 },{ 74, 12 },{ 63, 63 },
+ { 49, 28 },{ 22, 35 },{ 23, 8 },{ 7, 44 },{ 58, 40 },{ 0, 73 },{ 45, 67 },{ 2, 25 },
+ { 26, 66 },{ 38, 23 },{ 77, 62 },{ 60, 15 },{ 38, 40 },{ 51, 55 },{ 14, 65 },{ 43, 4 },
+ { 9, 8 },{ 72, 25 },{ 58, 72 },{ 28, 41 },{ 24, 77 },{ 70, 40 },{ 39, 58 },{ 14, 34 },
+ { 73, 3 },{ 30, 19 },{ 56, 33 },{ 4, 56 },{ 6, 18 },{ 51, 4 },{ 48, 46 },{ 15, 49 },
+ { 16, 16 },{ 65, 50 },{ 46, 22 },{ 30, 59 },{ 63, 6 },{ 13, 0 },{ 55, 66 },{ 31, 1 },
+ { 6, 34 },{ 76, 53 },{ 59, 21 },{ 27, 28 },{ 10, 71 },{ 67, 69 },{ 41, 34 },{ 67, 15 },
+ { 22, 47 },{ 63, 37 },{ 47, 72 },{ 23, 15 },{ 43, 51 },{ 2, 4 },{ 76, 42 },{ 21, 61 },
+ { 35, 5 },{ 70, 60 },{ 56, 45 },{ 1, 29 },{ 53, 13 },{ 30, 49 },{ 18, 29 },{ 68, 78 },
+ { 21, 69 },{ 39, 19 },{ 49, 60 },{ 11, 52 },{ 75, 19 },{ 62, 28 },{ 32, 38 },{ 37, 76 },
+ { 3, 67 },{ 46, 34 },{ 28, 12 },{ 3, 46 },{ 58, 77 },{ 11, 14 },{ 37, 63 },{ 12, 39 },
+ { 62, 53 },{ 17, 78 },{ 44, 11 },{ 41, 45 },{ 6, 3 },{ 70, 33 },{ 22, 24 },{ 0, 58 },
+ { 59, 65 },{ 27, 72 },{ 69, 9 },{ 35, 26 },{ 16, 58 },{ 53, 31 },{ 46, 78 },{ 7, 26 },
+ { 34, 54 },{ 56, 51 },{ 18, 43 },{ 78, 77 },{ 55, 18 },{ 25, 4 },{ 73, 64 },{ 67, 21 },
+ { 50, 39 },{ 2, 37 },{ 51, 68 },{ 78, 11 },{ 29, 36 },{ 40, 2 },{ 72, 49 },{ 18, 11 },
+ { 12, 68 },{ 26, 59 },{ 60, 7 },{ 34, 15 },{ 53, 60 },{ 73, 30 },{ 14, 22 },{ 36, 46 },
+ { 8, 60 },{ 50, 25 },{ 39, 69 },{ 63, 71 },{ 21, 32 },{ 5, 73 },{ 36, 33 },{ 71, 15 },
+ { 61, 39 },{ 13, 45 },{ 29, 66 },{ 48, 5 },{ 68, 53 },{ 26, 22 },{ 0, 20 },{ 47, 49 },
+ { 10, 5 },{ 25, 50 },{ 58, 12 },{ 63, 59 },{ 6, 52 },{ 31, 7 },{ 70, 0 },{ 73, 39 },
+ { 46, 30 },{ 52, 75 },{ 20, 2 },{ 43, 57 },{ 8, 30 },{ 60, 30 },{ 75, 67 },{ 33, 72 },
+ { 31, 43 },{ 41, 20 },{ 17, 63 },{ 76, 6 },{ 55, 42 },{ 19, 18 },{ 8, 40 },{ 41, 9 },
+ { 9, 77 },{ 47, 64 },{ 67, 27 },{ 20, 40 },{ 9, 18 },{ 2, 63 },{ 60, 3 },{ 64, 44 },
+ { 45, 42 },{ 14, 56 },{ 31, 27 },{ 47, 16 },{ 24, 74 },{ 68, 64 },{ 38, 54 },{ 76, 35 },
+ { 3, 12 },{ 42, 75 },{ 58, 22 },{ 71, 72 },{ 56, 57 },{ 25, 31 },{ 3, 42 },{ 25, 55 },
+ { 33, 11 },{ 73, 55 },{ 40, 30 },{ 14, 74 },{ 53, 2 },{ 71, 21 },{ 39, 61 },{ 12, 25 },
+ { 53, 37 },{ 70, 4 },{ 19, 6 },{ 19, 49 },{ 56, 70 },{ 65, 33 },{ 31, 17 },{ 52, 52 },
+ { 9, 65 },{ 34, 66 },{ 11, 35 },{ 51, 20 },{ 0, 47 },{ 76, 74 },{ 36, 42 },{ 5, 8 },
+ { 27, 0 },{ 64, 19 },{ 60, 49 },{ 78, 26 },{ 50, 9 },{ 19, 67 },{ 25, 38 },{ 24, 21 },
+ { 62, 69 },{ 42, 25 },{ 70, 43 },{ 33, 78 },{ 10, 48 },{ 77, 15 },{ 42, 48 },{ 15, 10 },
+ { 44, 69 },{ 76, 57 },{ 65, 3 },{ 38, 12 },{ 29, 61 },{ 19, 34 },{ 57, 28 },{ 58, 61 },
+ { 4, 0 },{ 6, 21 },{ 47, 38 },{ 3, 60 },{ 29, 46 },{ 49, 0 },{ 34, 23 },{ 20, 72 },
+ { 68, 49 },{ 64, 14 },{ 34, 57 },{ 1, 31 },{ 24, 10 },{ 2, 70 },{ 47, 54 },{ 17, 22 },
+ { 55, 12 },{ 17, 52 },{ 63, 35 },{ 61, 74 },{ 31, 34 },{ 39, 73 },{ 75, 10 },{ 67, 57 },
+ { 50, 31 },{ 13, 63 },{ 77, 44 },{ 29, 5 },{ 54, 48 },{ 13, 30 },{ 7, 14 },{ 40, 15 },
+ { 43, 64 },{ 75, 0 },{ 41, 40 },{ 8, 56 },{ 63, 24 },{ 14, 2 },{ 15, 43 },{ 51, 72 },
+ { 70, 66 },{ 27, 69 },{ 46, 8 },{ 73, 36 },{ 37, 34 },{ 33, 50 },{ 1, 22 },{ 48, 24 },
+ { 3, 50 },{ 61, 56 },{ 13, 16 },{ 23, 56 },{ 65, 78 },{ 35, 2 },{ 22, 42 },{ 57, 43 },
+ { 10, 74 },{ 67, 11 },{ 25, 17 },{ 50, 63 },{ 7, 36 },{ 52, 16 },{ 71, 29 },{ 23, 64 },
+ { 20, 28 },{ 56, 78 },{ 77, 65 },{ 41, 52 },{ 37, 20 },{ 19, 76 },{ 74, 50 },{ 58, 37 },
+ { 73, 7 },{ 30, 73 },{ 35, 39 },{ 37, 9 },{ 65, 62 },{ 73, 24 },{ 50, 47 },{ 6, 46 },
+ { 6, 6 },{ 57, 8 },{ 26, 27 },{ 28, 52 },{ 6, 69 },{ 55, 25 },{ 43, 78 },{ 14, 37 },
+ { 20, 14 },{ 66, 39 },{ 58, 68 },{ 45, 60 },{ 5, 30 },{ 44, 33 },{ 14, 54 },{ 61, 17 },
+ { 2, 77 },{ 34, 69 },{ 67, 72 },{ 22, 5 },{ 44, 22 },{ 74, 60 },{ 10, 20 },{ 63, 47 },
+ { 26, 47 },{ 31, 21 },{ 36, 60 },{ 73, 18 },{ 16, 67 },{ 47, 2 },{ 67, 31 },{ 4, 40 },
+ { 39, 28 },{ 52, 58 },{ 13, 9 },{ 6, 62 },{ 24, 35 },{ 63, 9 },{ 45, 45 },{ 46, 12 },
+ { 73, 44 },{ 26, 62 },{ 3, 18 },{ 58, 53 },{ 29, 14 },{ 73, 72 },{ 21, 51 },{ 54, 33 },
+ { 39, 3 },{ 16, 26 },{ 0, 4 },{ 54, 74 },{ 5, 54 },{ 42, 67 },{ 32, 41 },{ 75, 33 },
+ { 16, 2 },{ 56, 16 },{ 27, 76 },{ 11, 43 },{ 51, 43 },{ 65, 68 },{ 34, 30 },{ 18, 60 },
+ { 67, 23 },{ 57, 3 },{ 4, 25 },{ 37, 51 },{ 69, 52 },{ 8, 78 },{ 26, 7 },{ 46, 26 },
+ { 56, 62 },{ 70, 13 },{ 17, 38 },{ 0, 69 },{ 31, 65 },{ 22, 19 },{ 61, 31 },{ 48, 71 },
+ { 78, 36 },{ 42, 38 },{ 12, 59 },{ 67, 2 },{ 43, 13 },{ 8, 10 },{ 62, 41 },{ 49, 55 },
+ { 16, 72 },{ 28, 29 },{ 0, 52 },{ 52, 7 },{ 30, 55 },{ 9, 28 },{ 38, 78 },{ 71, 59 },
+ { 34, 18 },{ 0, 14 },{ 20, 46 },{ 52, 28 },{ 72, 0 },{ 34, 47 },{ 61, 51 },{ 24, 71 },
+ { 17, 31 },{ 33, 8 },{ 69, 42 },{ 51, 65 },{ 61, 20 },{ 9, 70 },{ 17, 13 },{ 40, 57 },
+ { 48, 35 },{ 12, 49 },{ 63, 76 },{ 77, 28 },{ 48, 18 },{ 1, 57 },{ 27, 40 },{ 22, 1 },
+ { 62, 60 },{ 38, 71 },{ 3, 7 },{ 54, 40 },{ 68, 17 },{ 31, 24 },{ 48, 75 },{ 1, 41 },
+ { 1, 74 },{ 40, 44 },{ 16, 19 },{ 41, 6 },{ 17, 56 },{ 60, 11 },{ 10, 33 },{ 73, 68 },
+ { 54, 53 },{ 23, 67 },{ 62, 26 },{ 12, 5 },{ 38, 36 },{ 67, 47 },{ 39, 64 },{ 25, 12 },
+ { 74, 5 },{ 10, 54 },{ 53, 23 },{ 23, 25 },{ 61, 66 },{ 68, 34 },{ 31, 78 },{ 46, 50 },
+ { 21, 38 },{ 75, 22 },{ 57, 76 },{ 41, 17 },{ 23, 60 },{ 4, 66 },{ 8, 24 },{ 58, 45 },
+ { 61, 5 },{ 76, 39 },{ 12, 75 },{ 32, 59 },{ 43, 29 },{ 9, 15 },{ 8, 45 },{ 53, 11 },
+ { 47, 68 },{ 29, 34 },{ 69, 76 },{ 74, 52 },{ 30, 9 },{ 24, 51 },{ 69, 26 },{ 65, 58 },
+ { 20, 78 },{ 37, 24 },{ 72, 10 },{ 45, 39 },{ 44, 76 },{ 10, 64 },{ 4, 32 },{ 42, 53 },
+ { 18, 8 },{ 57, 32 },{ 17, 45 },{ 75, 62 },{ 50, 5 },{ 35, 73 },{ 27, 19 },{ 54, 67 },
+ { 30, 45 },{ 1, 1 },{ 78, 19 },{ 4, 48 },{ 57, 18 },{ 52, 45 },{ 20, 63 },{ 19, 24 },
+ { 65, 53 },{ 67, 6 },{ 37, 13 },{ 16, 34 },{ 44, 59 },{ 65, 37 },{ 26, 2 },{ 69, 67 },
+ { 48, 21 },{ 5, 75 },{ 35, 53 },{ 75, 45 },{ 5, 13 },{ 32, 68 },{ 35, 32 },{ 10, 41 },
+ { 44, 5 },{ 50, 33 },{ 15, 70 },{ 74, 27 },{ 60, 72 },{ 24, 42 },{ 13, 12 },{ 1, 60 },
+ { 57, 58 },{ 59, 26 },{ 34, 4 },{ 38, 43 },{ 74, 15 },{ 26, 57 },{ 51, 77 },{ 14, 28 },
+ { 50, 14 },{ 50, 50 },{ 76, 76 },{ 9, 57 },{ 26, 33 },{ 70, 38 },{ 11, 3 },{ 40, 22 },
+ { 62, 2 },{ 36, 65 },{ 4, 37 },{ 70, 55 },{ 20, 17 },{ 65, 15 },{ 52, 38 },{ 43, 71 },
+ { 14, 61 },{ 4, 22 },{ 27, 74 },{ 62, 44 },{ 32, 16 },{ 64, 64 },{ 18, 48 },{ 0, 8 },
+ { 47, 61 },{ 33, 27 },{ 77, 69 },{ 37, 47 },{ 22, 9 },{ 66, 29 },{ 56, 5 },{ 17, 75 },
+ { 1, 49 },{ 2, 28 },{ 44, 36 },{ 40, 8 },{ 21, 55 },{ 57, 50 },{ 12, 21 },{ 44, 19 },
+ { 66, 73 },{ 28, 63 },{ 16, 41 },{ 65, 20 },{ 77, 56 },{ 30, 37 },{ 35, 76 },{ 7, 4 },
+ { 59, 36 },{ 59, 13 },{ 11, 67 },{ 53, 62 },{ 28, 22 },{ 70, 47 },{ 38, 56 },{ 68, 8 },
+ { 8, 37 },{ 22, 29 },{ 41, 1 },{ 72, 63 },{ 48, 30 },{ 46, 43 },{ 75, 30 },{ 22, 71 },
+ { 31, 50 },{ 48, 9 },{ 76, 1 },{ 7, 53 },{ 4, 16 },{ 55, 69 },{ 56, 23 },{ 27, 13 },
+ { 41, 63 },{ 73, 42 },{ 16, 6 },{ 60, 55 },{ 6, 72 },{ 40, 32 },{ 23, 46 },{ 59, 0 },
+ { 70, 20 },{ 30, 3 },{ 11, 27 },{ 5, 61 },{ 46, 53 },{ 70, 71 },{ 34, 41 },{ 78, 34 },
+ { 36, 16 },{ 28, 67 },{ 15, 15 },{ 15, 51 },{ 62, 32 },{ 50, 73 },{ 77, 13 },{ 68, 60 },
+ { 20, 35 },{ 52, 25 },{ 14, 77 },{ 55, 49 },{ 4, 43 },{ 46, 15 },{ 31, 57 },{ 20, 22 },
+ { 51, 2 },{ 0, 64 },{ 65, 42 },{ 71, 3 },{ 32, 74 },{ 40, 26 },{ 60, 64 },{ 17, 66 },
+ { 77, 24 },{ 43, 49 },{ 10, 9 },{ 12, 46 },{ 46, 65 },{ 32, 30 },{ 63, 11 },{ 55, 39 },
+ { 24, 3 },{ 12, 32 },{ 71, 51 },{ 36, 10 },{ 6, 0 },{ 27, 44 },{ 54, 14 },{ 71, 34 },
+ { 51, 57 },{ 41, 73 },{ 20, 57 },{ 73, 75 },{ 56, 30 },{ 7, 20 },{ 36, 37 },{ 2, 53 },
+ { 24, 14 },{ 57, 74 },{ 33, 64 },{ 65, 23 },{ 49, 43 },{ 1, 11 },{ 28, 25 },{ 8, 63 },
+ { 37, 5 },{ 13, 38 },{ 66, 49 },{ 65, 5 },{ 23, 78 },{ 26, 52 },{ 78, 72 },{ 44, 26 },
+ { 0, 38 },{ 45, 3 },{ 64, 69 },{ 40, 47 },{ 14, 24 },{ 52, 19 },{ 13, 71 },{ 59, 44 },
+ { 71, 17 },{ 37, 59 },{ 24, 32 },{ 9, 49 },{ 50, 67 },{ 19, 4 },{ 72, 57 },{ 34, 20 },
+ { 55, 9 },{ 6, 27 },{ 25, 68 },{ 77, 47 },{ 75, 8 },{ 52, 35 },{ 60, 61 },{ 31, 10 },
+ { 15, 59 },{ 29, 40 },{ 70, 24 },{ 66, 77 },{ 37, 68 },{ 10, 13 },{ 48, 56 },{ 41, 36 },
+ { 44, 9 },{ 5, 68 },{ 68, 39 },{ 19, 39 },{ 60, 22 },{ 63, 55 },{ 17, 18 },{ 3, 3 },
+ { 29, 54 },{ 55, 0 },{ 6, 32 },{ 19, 74 },{ 38, 29 },{ 13, 53 },{ 61, 35 },{ 45, 77 },
+ { 28, 6 },{ 49, 48 },{ 1, 17 },{ 69, 63 },{ 43, 16 },{ 2, 44 },{ 67, 13 },{ 33, 46 },
+ { 19, 64 },{ 25, 26 },{ 10, 78 },{ 54, 59 },{ 72, 32 },{ 29, 71 },{ 47, 27 },{ 3, 57 },
+ { 59, 9 },{ 41, 42 },{ 17, 28 },{ 42, 69 },{ 76, 71 },{ 23, 49 },{ 21, 10 },{ 67, 44 },
+ { 56, 20 },{ 57, 66 },{ 34, 1 },{ 7, 39 },{ 77, 3 },{ 28, 18 },{ 41, 55 },{ 63, 29 },
+ { 27, 60 },{ 76, 60 },{ 2, 23 },{ 62, 0 },{ 25, 36 },{ 48, 39 },{ 11, 7 },{ 59, 48 },
+ { 39, 17 },{ 10, 59 },{ 53, 73 },{ 14, 44 },{ 70, 11 },{ 33, 34 },{ 74, 40 },{ 39, 75 },
+ { 11, 19 },{ 3, 74 },{ 49, 7 },{ 33, 61 },{ 75, 49 },{ 68, 70 },{ 54, 30 },{ 15, 0 },
+ { 36, 22 },{ 52, 54 },{ 2, 34 },{ 18, 54 },{ 62, 18 },{ 25, 76 },{ 21, 20 },{ 45, 63 },
+ { 46, 32 },{ 4, 11 },{ 63, 52 },{ 6, 50 },{ 51, 12 },{ 22, 44 },{ 36, 52 },{ 73, 22 },
+ { 31, 13 },{ 71, 77 },{ 12, 65 },{ 59, 39 },{ 18, 33 },{ 66, 65 },{ 53, 5 },{ 20, 70 },
+ { 68, 28 },{ 16, 11 },{ 46, 70 },{ 28, 31 },{ 2, 65 },{ 46, 46 },{ 45, 21 },{ 9, 35 },
+ { 33, 6 },{ 69, 5 },{ 78, 54 },{ 58, 70 },{ 31, 48 },{ 9, 73 },{ 78, 29 },{ 30, 77 },
+ { 53, 42 },{ 75, 13 },{ 40, 60 },{ 22, 62 },{ 58, 24 },{ 42, 11 },{ 68, 56 },{ 8, 22 },
+ { 39, 41 },{ 48, 78 },{ 66, 36 },{ 21, 15 },{ 14, 48 },{ 74, 66 },{ 34, 25 },{ 8, 7 },
+ { 56, 54 },{ 61, 13 },{ 22, 53 },{ 33, 70 },{ 72, 46 },{ 64, 75 },{ 16, 30 },{ 49, 20 },
+ { 25, 8 },{ 33, 39 },{ 1, 78 },{ 52, 64 },{ 8, 43 },{ 76, 20 },{ 42, 31 },{ 39, 0 },
+ { 33, 55 },{ 75, 37 },{ 59, 4 },{ 14, 68 },{ 23, 22 },{ 57, 34 },{ 7, 58 },{ 17, 3 },
+ { 44, 52 },{ 60, 58 },{ 24, 39 },{ 8, 17 },{ 66, 17 },{ 39, 67 },{ 64, 48 },{ 77, 7 },
+ { 40, 13 },{ 24, 65 },{ 50, 29 },{ 0, 42 },{ 73, 70 },{ 17, 42 },{ 43, 2 },{ 53, 46 },
+ { 3, 27 },{ 30, 29 },{ 59, 75 },{ 64, 26 },{ 4, 63 },{ 48, 59 },{ 28, 1 },{ 8, 1 },
+ { 54, 17 },{ 38, 49 },{ 75, 55 },{ 15, 21 },{ 64, 7 },{ 16, 62 },{ 33, 14 },{ 63, 40 },
+ { 12, 36 },{ 41, 23 },{ 28, 47 },{ 73, 1 },{ 30, 64 },{ 70, 30 },{ 47, 74 },{ 65, 60 },
+ { 44, 40 },{ 22, 74 },{ 9, 52 },{ 2, 9 },{ 19, 27 },{ 38, 7 },{ 4, 70 },{ 35, 35 },
+ { 61, 70 },{ 72, 14 },{ 50, 37 },{ 19, 12 },{ 0, 32 },{ 27, 56 },{ 54, 3 },{ 70, 50 },
+ { 29, 21 },{ 43, 61 },{ 49, 15 },{ 9, 26 },{ 54, 51 },{ 11, 76 },{ 17, 50 },{ 60, 28 },
+ { 37, 74 },{ 5, 45 },{ 58, 63 },{ 23, 6 },{ 68, 75 },{ 26, 42 },{ 2, 19 },{ 51, 23 },
+ { 76, 64 },{ 57, 41 },{ 35, 58 },{ 14, 7 },{ 72, 37 },{ 22, 33 },{ 52, 71 },{ 59, 16 },
+ { 18, 58 },{ 37, 26 },{ 26, 70 },{ 78, 50 },{ 11, 16 },{ 46, 10 },{ 35, 43 },{ 8, 67 },
+ { 70, 8 },{ 75, 25 },{ 48, 51 },{ 26, 15 },{ 72, 61 },{ 14, 40 },{ 48, 66 },{ 43, 34 },
+ { 78, 75 },{ 32, 2 },{ 64, 34 },{ 11, 55 },{ 58, 6 },{ 61, 46 },{ 18, 0 },{ 11, 30 },
+ { 35, 67 },{ 36, 18 },{ 4, 6 },{ 69, 22 },{ 42, 46 },{ 64, 1 },{ 3, 39 },{ 53, 27 },
+ { 63, 66 },{ 27, 35 },{ 23, 58 },{ 49, 3 },{ 17, 69 },{ 69, 45 },{ 21, 25 },{ 58, 56 },
+ { 78, 16 },{ 29, 11 },{ 78, 59 },{ 43, 74 },{ 29, 51 },{ 54, 35 },{ 43, 24 },{ 4, 77 },
+ { 44, 55 },{ 8, 12 },{ 19, 44 },{ 65, 12 },{ 29, 75 },{ 75, 43 },{ 37, 31 },{ 54, 76 },
+ { 4, 51 },{ 43, 7 },{ 66, 54 },{ 7, 29 },{ 12, 62 },{ 38, 62 },{ 25, 20 },{ 68, 32 },
+ { 75, 4 },{ 47, 41 },{ 56, 14 },{ 67, 67 },{ 14, 14 },{ 32, 44 },{ 21, 3 },{ 15, 35 },
+ { 51, 60 },{ 46, 18 },{ 1, 68 },{ 63, 21 },{ 36, 78 },{ 10, 46 },{ 20, 66 },{ 73, 28 },
+ { 30, 26 },{ 57, 47 },{ 67, 0 },{ 31, 61 },{ 13, 73 },{ 40, 38 },{ 5, 35 },{ 55, 64 },
+ { 39, 10 },{ 5, 19 },{ 20, 52 },{ 72, 54 },{ 56, 26 },{ 39, 53 },{ 9, 4 },{ 52, 10 },
+ { 16, 24 },{ 71, 69 },{ 67, 41 },{ 31, 72 },{ 22, 37 },{ 48, 33 },{ 72, 19 },{ 44, 66 },
+ { 6, 55 },{ 27, 4 },{ 62, 73 },{ 32, 23 },{ 73, 11 },{ 52, 49 },{ 8, 71 },{ 26, 49 },
+ { 52, 0 },{ 78, 45 },{ 18, 16 },{ 0, 25 },{ 32, 36 },{ 35, 8 },{ 60, 33 },{ 67, 62 },
+ { 25, 61 },{ 74, 77 },{ 47, 23 },{ 40, 70 },{ 10, 39 },{ 62, 50 },{ 61, 8 },{ 17, 9 },
+ { 4, 59 },{ 26, 30 },{ 49, 45 },{ 21, 77 },{ 66, 25 },{ 49, 69 },{ 74, 34 },{ 34, 49 },
+ { 1, 5 },{ 38, 15 },{ 13, 57 },{ 46, 1 },{ 10, 23 },{ 46, 57 },{ 58, 19 },{ 41, 28 },
+ { 74, 58 },{ 21, 41 },{ 60, 42 },{ 12, 1 },{ 27, 65 },{ 2, 14 },{ 56, 60 },{ 23, 17 },
+ { 75, 73 },{ 16, 47 },{ 48, 12 },{ 1, 36 },{ 37, 39 },{ 60, 77 },{ 18, 72 },{ 37, 3 },
+ { 69, 15 },{ 56, 37 },{ 36, 56 },{ 2, 47 },{ 32, 19 },{ 6, 65 },{ 14, 32 },{ 63, 57 },
+ { 69, 2 },{ 27, 9 },{ 45, 48 },{ 49, 26 },{ 71, 41 },{ 53, 68 },{ 6, 9 },{ 24, 54 },
+ { 36, 71 },{ 23, 28 },{ 57, 11 },{ 3, 30 },{ 77, 67 },{ 46, 36 },{ 25, 73 },{ 30, 42 },
+ { 67, 51 },{ 65, 31 },{ 7, 75 },{ 41, 77 },{ 42, 19 },{ 13, 18 },{ 16, 55 },{ 66, 9 },
+ { 54, 56 },{ 7, 48 },{ 78, 22 },{ 56, 72 },{ 35, 28 },{ 20, 7 },{ 15, 64 },{ 61, 24 },
+ { 40, 50 },{ 76, 52 },{ 47, 6 },{ 35, 63 },{ 18, 37 },{ 78, 0 },{ 52, 32 },{ 65, 71 },
+ { 29, 16 },{ 69, 36 },{ 25, 45 },{ 75, 17 },{ 62, 62 },{ 31, 5 },{ 55, 44 },{ 6, 41 },
+ { 14, 4 },{ 57, 1 },{ 29, 58 },{ 13, 26 },{ 54, 21 },{ 9, 61 },{ 41, 65 },{ 31, 32 },
+ { 72, 6 },{ 43, 43 },{ 0, 62 },{ 22, 68 },{ 44, 14 },{ 6, 15 },{ 65, 45 },{ 76, 31 },
+ { 45, 72 },{ 18, 21 },{ 62, 15 },{ 71, 65 },{ 50, 53 },{ 25, 0 },{ 12, 51 },{ 45, 29 },
+ { 2, 72 },{ 28, 38 },{ 54, 7 },{ 73, 48 },{ 33, 76 },{ 71, 26 },{ 8, 33 },{ 42, 58 },
+ { 34, 12 },{ 12, 11 },{ 37, 45 },{ 62, 38 },{ 11, 69 },{ 63, 4 },{ 21, 48 },{ 26, 24 },
+ { 69, 58 },{ 50, 76 },{ 5, 2 },{ 58, 29 },{ 38, 21 },{ 59, 67 },{ 20, 60 },{ 77, 40 },
+ { 77, 10 },{ 20, 31 },{ 51, 40 },{ 32, 53 },{ 16, 76 },{ 41, 4 },{ 67, 19 },{ 49, 62 },
+ { 2, 55 },{ 23, 12 },{ 12, 42 },{ 39, 34 },{ 70, 74 },{ 51, 17 },{ 59, 52 },{ 30, 68 },
+ { 5, 24 }
+};
+
+static ccoord *screens0[1] = {
+ screen0_0
+};
+
+#define NO_SCREENS 1
+static thscdef screens[NO_SCREENS] = {
+ {
+ 79, /* Size */
+ 79, /* Width */
+ 79, /* Height */
+ 1.000000, /* Aspect Ratio */
+ 1, /* Joint screens */
+ screens0 /* list of pointers to screen threshold arrays */
+ }
+};
+
diff --git a/render/thscreen.c b/render/thscreen.c
new file mode 100644
index 0000000..c0a5548
--- /dev/null
+++ b/render/thscreen.c
@@ -0,0 +1,474 @@
+
+/*
+ * render2d
+ *
+ * Threshold screen pixel processing object.
+ * (Simplified from DPS code)
+ *
+ * Author: Graeme W. Gill
+ * Date: 8/9/2005
+ * Version: 1.00
+ *
+ * Copyright 2005, 2012 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "aconfig.h"
+#include "numlib.h"
+//#include "icc.h"
+#include "sort.h"
+//#include "xcolorants.h"
+#include "thscreen.h"
+
+/* Configuration: */
+#undef DEBUG
+
+/* ----------------------------------------------------------- */
+
+#ifdef DEBUG
+# define DBG(text) printf text ; fflush(stdout);
+#else
+# define DBG(text)
+#endif
+
+/* ----------------------------------------------------------- */
+/* Setup a set of screens */
+/* Screen data is used that best matches the requested parameters. */
+
+#include "screens.h" /* Pre-generated screen patterns */
+
+/* Screen a single color plane */
+void screen_thscreens( /* Pointer to dither function */
+ thscreens *t, /* Screening object pointer */
+ int width, int height, /* Width and height to screen in pixels */
+ int xoff, int yoff, /* Offset into screening pattern */
+ unsigned char *in, /* Input pixel buffer */
+ unsigned long ipitch, /* Increment between input lines */
+ unsigned char *out, /* Output pixel buffer */
+ unsigned long opitch /* Increment between output lines */
+) {
+ int i;
+ for (i = 0; i < t->np; i++)
+ t->sc[i]->screen(t->sc[i], width, height, xoff, yoff, in + 2 * i, t->np, ipitch,
+ out + i, t->np, opitch);
+}
+
+/* Delete a thscreens */
+void del_thscreens(thscreens *t) {
+ int i;
+
+ for (i = 0; i < t->np; i++)
+ t->sc[i]->del(t->sc[i]);
+ free(t->sc);
+ free(t);
+}
+
+/* Create a new thscreens object matching the parameters */
+thscreens *new_thscreens(
+ int exact, /* Return only exact matches */
+ int nplanes, /* Number of planes to screen */
+ double asp, /* Target aspect ratio (== dpiX/dpiY) */
+ int size, /* Target size */
+ sc_iencoding ie, /* Input encoding - must be scie_16 */
+ int oebpc, /* Output encoding bits per component - must be 8 */
+ int oelev, /* Output encoding levels. Must be <= 2 ^ oebpc */
+ int *oevalues, /* Optional output encoding values for each level */
+ /* Must be oelev entries. Default is 0 .. oelev-1 */
+ sc_oorder oo, /* Output bit ordering */
+ double overlap, /* Overlap between levels, 0 - 1.0 */
+ void **cntx, /* List of contexts for lookup table callback */
+ double (**lutfunc)(void *cntx, double in) /* List of callback function, NULL if none */
+) {
+ thscreens *t;
+ int i, bi = -1;
+ double bamatch; /* Best aspect match */
+ int bsize = 100000; /* Best size match */
+ int swap = 0; /* width and height will need swapping */
+
+ DBG(("thscreens: new called with:\n"));
+ DBG((" nplanes = 0x%x\n",nplanes));
+ DBG((" asp = %f\n",asp));
+ DBG((" ie = %d\n",ie));
+ DBG((" oebpc = %d\n",oebpc));
+ DBG((" oelev = %d\n",oelev));
+ DBG((" oo = %d\n",oo));
+ DBG((" overlap = %f\n",overlap));
+
+ if (asp < 1.0) { /* All screens[] have asp >= 1.0 */
+ asp = 1.0/asp;
+ swap = 1;
+ DBG(("thscreens: aspect swap needed\n"));
+ }
+
+ if ((t = (thscreens *)calloc(1, sizeof(thscreens))) == NULL) {
+ DBG(("thscreens: malloc of thscreens failed\n"));
+ return NULL;
+ }
+
+ t->np = nplanes; /* Number of planes */
+
+ DBG(("thscreens no planes = %d\n",t->np));
+
+ t->screen = screen_thscreens;
+ t->del = del_thscreens;
+
+ if ((t->sc = malloc(sizeof(thscreen *) * t->np)) == NULL) {
+ free(t);
+ DBG(("thscreens: malloc of thscreens->sc[] failed\n"));
+ return NULL;
+ }
+
+ DBG(("thscreens: searching amongst %d screens, exact = %d\n",NO_SCREENS,exact));
+
+ DBG(("thscreens: looking for non-exact match\n"));
+
+ /* Synthesise a set of screens from what's there */
+ /* (Don't bother with matching the colorspace) */
+ for (i = 0;i < NO_SCREENS; i++) {
+ double thamatch; /* This aspect match */
+ int thsize; /* This size match */
+
+ thamatch = asp/screens[i].asp;
+ if (thamatch < 1.0)
+ thamatch = 1.0/thamatch;
+
+ if (bi < 0 || (thamatch < bamatch)) { /* No best or new best */
+ bamatch = thamatch;
+ bi = i;
+ DBG(("thscreens: new best with aspmatch %f\n",bamatch));
+ continue; /* On to next */
+ }
+ if (thamatch > bamatch) /* Worse aspect match */
+ continue;
+ /* Same on aspect ratio. Check size */
+ thsize = size - screens[i].size;
+ if (thsize < 0)
+ thsize = -thsize;
+ if (thsize < bsize) { /* New better size match */
+ bsize = thsize;
+ bi = i;
+ DBG(("thscreens: new best with size %d\n",bsize));
+ }
+ }
+
+ if (bi < 0) /* Strange */
+ return NULL;
+
+ /* Create each screening object from one defined screen. */
+ /* Use the 0'th plane screen */
+ /* Stagger the screens with a round of 9 offset */
+ for (i = 0; i < t->np; i++) {
+ int xoff = ((i % 3) * screens[bi].width)/3;
+ int yoff = (((i/3) % 3) * screens[bi].height)/3;
+ void *cx = NULL;
+ double (*lf)(void *cntx, double in) = 0;
+ if (cntx != NULL)
+ cx = cntx[i];
+ if (lutfunc != NULL)
+ lf = lutfunc[i];
+
+ DBG(("thscreens: creating plane %d/%d thscreen, offset %d %d\n",i,t->np,xoff,yoff));
+ if ((t->sc[i] = new_thscreen(screens[bi].width, screens[bi].height, xoff, yoff,
+ screens[bi].asp, swap, screens[bi].list[0],
+ ie, oebpc, oelev, oevalues, oo, overlap,
+ cx, lf)) == NULL) {
+ for (--i; i >= 0; i--)
+ t->sc[i]->del(t->sc[i]);
+ free(t->sc);
+ free(t);
+ DBG(("thscreens: new_thscreen() failed\n"));
+ return NULL;
+ }
+ }
+ DBG(("thscreens: returning nonexact match\n"));
+ return t;
+}
+
+/* ----------------------------------------------------------- */
+/* The kernel screening routin */
+
+void thscreen16_8(
+ struct _thscreen *t, /* Screening object pointer */
+ int width, int height, /* Width and height to screen in pixels */
+ int xoff, int yoff, /* Offset into screening pattern (must be +ve) */
+ unsigned char *_in, /* Input pixel buffer */
+ unsigned long ipinc, /* Increment between input pixels */
+ unsigned long ipitch, /* Increment between input lines */
+ unsigned char *out, /* Output pixel buffer */
+ unsigned long opinc, /* Increment between output pixels */
+ unsigned long opitch /* Increment between output lines */
+) {
+ unsigned short *in = (unsigned short *)_in; /* Pointer to input pixel sized values */
+ int *lut = t->lut; /* Copy of 8 or 16 -> 16 bit lookup table */
+ unsigned char **oth, **eth; /* Current lines start, origin and end in screening table. */
+ int thtsize; /* Overall size of threshold table */
+ unsigned char **eeth; /* Very end of threshold table */
+ unsigned short *ein = in + height * ipitch; /* Vertical end pixel marker */
+ unsigned short *ein1; /* Horizontal end pixel markers */
+
+ {
+ unsigned char **sth; /* Start point of line intable */
+ sth = t->thp + (yoff % t->sheight) * t->twidth;
+ oth = sth + (xoff % t->swidth); /* Orgin of pattern to start from */
+ eth = sth + t->swidth; /* Ending point to wrap back */
+ thtsize = t->twidth * t->theight;
+ eeth = t->thp + thtsize; /* very end of table */
+ }
+
+ ein1 = in + ipinc * width;
+
+ /* For each line: */
+ for (; in < ein; in += ipitch, ein1 += ipitch, out += opitch) {
+ unsigned char **th = oth; /* Threshold table origin */
+ unsigned short *ip = in; /* Horizontal input pointer */
+ unsigned char *op = out; /* Horizontal output pointer */
+
+ /* Do pixels one output byte at a time */
+ for (; ip < ein1; ip += ipinc, op += opinc) {
+ int tt = lut[*ip];
+ *op = (unsigned char)th[0][tt];
+ if (++th >= eth)
+ th -= t->swidth;
+ }
+
+ /* Advance screen table pointers with vertical wrap */
+ oth += t->twidth;
+ eth += t->twidth;
+ if (eth > eeth) {
+ oth -= thtsize;
+ eth -= thtsize;
+ }
+ }
+}
+
+/* ----------------------------------------------------------- */
+
+/* We're done with the screening object */
+static void th_del(
+ thscreen *t
+) {
+ if (t->lut != NULL)
+ free(t->lut);
+ if (t->thp != NULL)
+ free(t->thp);
+ free(t);
+}
+
+/* Create a new thscreen object */
+/* Return NULL on error */
+thscreen *new_thscreen(
+ int width, /* width in pixels of screen */
+ int height, /* Height in pixels of screen */
+ int xoff, int yoff, /* Pattern offsets into width & height */
+ double asp, /* Aspect ratio of screen (== dpiX/dpiY) */
+ int swap, /* Swap X & Y to invert aspect ratio & swap width/height */
+ ccoord *thli, /* Pointer to list of threshold coordinates */
+ sc_iencoding ie, /* Input encoding - must be scie_16 */
+ int oebpc, /* Output encoding bits per component - must be 8 */
+ int oelev, /* Output encoding levels. Must be <= 2 ^ oebpc */
+ int *oevalues, /* Optional output encoding values for each level */
+ /* Must be oelev entries. Default is 0 .. oelev-1 */
+ sc_oorder oo, /* Output bit ordering */
+ double olap, /* Overlap between levels, 0 - 1.0 */
+ void *cntx, /* Context for LUT table callback */
+ double (*lutfunc)(void *cntx, double in) /* Callback function, NULL if none */
+) {
+ thscreen *t; /* Object being created */
+ int npix; /* Total pixels in screen */
+ double mrang; /* threshold modulation range */
+ double **fthr; /* Floating point threshold array */
+ int i, j;
+
+ DBG(("new_thscreen() called, oebpc = %d\n",oebpc));
+ DBG(("new_thscreen() called, oelev = %d\n",oelev));
+
+ /* Sanity check overlap */
+ if (olap < 0.0)
+ olap = 0.0;
+ else if (olap > 1.0)
+ olap = 1.0;
+
+ /* Sanity check parameters */
+ if (ie != scie_16) {
+ DBG(("new_thscreen() ie %d != scie_16\n",ie));
+ return NULL;
+ }
+ if (oebpc != 8) {
+ DBG(("new_thscreen() oebpc %d != 8\n",oebpc));
+ return NULL;
+ }
+
+ if (oelev < 2 || oelev > (1 << oebpc)) {
+ DBG(("new_thscreen() oelev %d > 2^%d = %d\n",oelev,1 << oebpc,oebpc));
+ return NULL;
+ }
+
+ if ((t = (thscreen *)calloc(1, sizeof(thscreen))) == NULL) {
+ DBG(("new_thscreen() calloc failed\n"));
+ return NULL;
+ }
+
+ /* Instantiation parameters */
+ t->ie = ie;
+ t->oebpc = oebpc;
+ t->oelev = oelev;
+ if (oevalues != NULL) {
+ for (i = 0; i < t->oelev; i++) {
+ if (oevalues[i] >= (1 << t->oebpc)) {
+ DBG(("new_thscreen() oevalues[%d] value %d can't fit in %d bits\n",i,oevalues[i],t->oebpc));
+ free(t);
+ return NULL;
+ }
+ t->oevalues[i] = oevalues[i];
+ }
+ } else {
+ for (i = 0; i < t->oelev; i++)
+ t->oevalues[i] = i;
+ }
+
+ t->oo = oo;
+ t->overlap = olap;
+
+ /* Create a suitable LUT from the given function */
+ /* Input is either 8 or 16 bits, output is always 16 bits */
+ DBG(("new_thscreen() about to create LUT\n"));
+ if ((t->lut = (int *)malloc(sizeof(int) * 65536)) == NULL) {
+ free(t);
+ DBG(("new_thscreen() malloc of 16 bit LUT failed\n"));
+ return NULL;
+ }
+ for (i = 0; i < 65536; i++) {
+ if (lutfunc != NULL) {
+ double v = i/65535.0;
+ v = lutfunc(cntx, v);
+ t->lut[i] = (int)(v * 65535.0 + 0.5);
+ } else
+ t->lut[i] = i;
+ }
+
+ /* Screen definition parameters */
+ if (swap) {
+ t->asp = 1.0/asp;
+ t->swidth = height;
+ t->sheight = width;
+ } else {
+ t->asp = asp;
+ t->swidth = width;
+ t->sheight = height;
+ }
+ DBG(("new_thscreen() target width %d, height %d, asp %f\n",t->swidth,t->sheight,t->asp));
+ DBG(("new_thscreen() given width %d, height %d, asp %f\n",width,height,asp));
+
+ npix = t->swidth * t->sheight; /* Total pixels */
+ /* Allow for read of a words worth of pixels from within screen: */
+ DBG(("new_thscreen() tot pix %d, lev %d, bpp %d\n",npix,t->oelev,t->oebpc));
+
+ t->twidth = t->swidth + (8/t->oebpc) -1;
+ t->theight = t->sheight;
+
+ DBG(("new_thscreen() th table size = %d x %d\n",t->twidth,t->theight));
+ DBG(("new_thscreen() about to turn screen list into float threshold matrix\n"));
+
+ /* Convert the list of screen cells into a floating point threshold array */
+ fthr = dmatrix(0, t->sheight-1, 0, t->swidth-1); /* Temporary matrix */
+ if (swap) {
+ double tt = xoff; /* Swap offsets to align with orientation */
+ xoff = yoff;
+ yoff = tt;
+ for (i = 0; i < npix; i++)
+ fthr[thli[i].x][thli[i].y] = (double)(i/(npix - 1.0));
+ } else {
+ for (i = 0; i < npix; i++)
+ fthr[thli[i].y][thli[i].x] = (double)(i/(npix - 1.0));
+ }
+
+ /* The range that the screen has to modulate */
+ /* over to cross all the thresholds evenly. */
+ mrang = 65535.0/(t->oelev - 1.0);
+ DBG(("new_thscreen() raw modulation rande = %f\n",mrang));
+
+ /* Modify the modulation range to accomodate any level overlap */
+ if (olap > 0.0 && t->oelev > 2) {
+ mrang = ((t->oelev - 2.0) * olap * mrang + 65535.0)/(t->oelev - 1.0);
+ DBG(("new_thscreen() modulation adjusted for overlap = %f\n",mrang));
+ }
+
+ /* Init the threshold table. It holds the quantized, encoded output */
+ /* values, allowing an input value offset by the screen to be */
+ /* thresholded directly into the output value. We allow a guard band at */
+ /* each end for the effects of the screen modulating the input value. */
+
+ DBG(("new_thscreen() about to init threshold table\n"));
+ t->tht = &t->_tht[32768]; /* base allows for -ve & +ve range */
+ for (i = -32768; i < (2 * 65536) + 32768; i++) {
+ if (i < mrang) { /* Lower guard band */
+ t->tht[i] = t->oevalues[0];
+ } else if (i >= 65535) { /* Upper guard band */
+ t->tht[i] = t->oevalues[t->oelev-1];
+ } else { /* Middle range */
+ t->tht[i] = t->oevalues[1 + (int)((t->oelev - 2.0) * (i - mrang)/(65535.0 - mrang))];
+ }
+ }
+
+ /* Allocate the 2D table of pointers into the */
+ /* threshold table that encodes the screen offset. */
+ if ((t->thp = (unsigned char **)malloc(sizeof(unsigned char *)
+ * t->twidth * t->theight)) == NULL) {
+ free_dmatrix(fthr, 0, t->sheight-1, 0, t->swidth-1);
+ free(t->lut);
+ free(t);
+ DBG(("new_thscreen() malloc of threshold pointer matrix failed\n"));
+ return NULL;
+ }
+
+ /* Setup the threshold pointer array to point into the apropriate */
+ /* point into the threshold array itself. This implicitly adds */
+ /* the screen pattern offset value to the input before thresholding it. */
+ /* The input screen offsets are applied at this point too. */
+ DBG(("new_thscreen() about to init threshold pointer table\n"));
+ for (i = 0; i < t->twidth; i++) {
+ for (j = 0; j < t->theight; j++) {
+ double sov = fthr[(j+yoff) % t->sheight][(i+xoff) % t->swidth];
+ int tho = (int)((mrang - 1.0) * (1.0 - sov) + 0.5);
+ t->thp[j * t->twidth + i] = &t->tht[tho];
+ }
+ }
+ free_dmatrix(fthr, 0, t->sheight-1, 0, t->swidth-1);
+
+ DBG(("new_thscreen() about to setup method pointers\n"));
+
+ /* Methods */
+ t->screen = thscreen16_8;
+ t->del = th_del;
+
+ DBG(("new_thscreen() done\n"));
+ return t;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/render/thscreen.h b/render/thscreen.h
new file mode 100644
index 0000000..d3ac9b1
--- /dev/null
+++ b/render/thscreen.h
@@ -0,0 +1,156 @@
+
+#ifndef THSCREEN_H
+#define THSCREEN_H
+
+/*
+ * render2d
+ *
+ * Threshold screen pixel processing object.
+ * (Simplified from DPS code)
+ *
+ * Author: Graeme W. Gill
+ * Date: 11/7/2005
+ * Version: 1.00
+ *
+ * Copyright 2005, 2012 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.
+ *
+ */
+
+/* Light Separation in screening flag */
+typedef enum {
+ scls_false = 0, /* Don't do light ink separation during screening. */
+ scls_true = 0 /* Do light ink separation during screening. */
+} sc_lightsep;
+
+/* Input encoding */
+typedef enum {
+ scie_8 = 0, /* 8 bit per component */
+ scie_16 = 1 /* 16 bit per component */
+} sc_iencoding;
+
+/* Output bit order within byte */
+typedef enum {
+ scoo_l = 0, /* Little endian */
+ scoo_b = 1 /* Big endian */
+} sc_oorder;
+
+
+/* ---------------------------- */
+/* Setup a set of screens */
+
+struct _thscreens {
+ int np; /* Number of planes */
+ struct _thscreen **sc; /* List of screens */
+
+ /* Screen a single color plane */
+ void (* screen)( /* Pointer to dither function */
+ struct _thscreens *t, /* Screening object pointer */
+ int width, int height, /* Width and height to screen in pixels */
+ int xoff, int yoff, /* Offset into screening pattern */
+ unsigned char *in, /* Input pixel buffer */
+ unsigned long ipitch, /* Increment between input lines */
+ unsigned char *out, /* Output pixel buffer */
+ unsigned long opitch); /* Increment between output lines */
+
+ void (* del)( /* Destructor */
+ struct _thscreens *t); /* Screening objects pointer */
+
+}; typedef struct _thscreens thscreens;
+
+
+/* Return a thscreens object */
+/* Screen data is used that best matches the requested parameters. */
+/* Return NULL on error */
+thscreens *new_thscreens(
+ int exact, /* Return only exact matches */
+ int nplanes, /* Number of planes to screen */
+ double asp, /* Target aspect ratio (== dpiX/dpiY) */
+ int size, /* Target size */
+ sc_iencoding ie, /* Input encoding - must be scie_16 */
+ int oebpc, /* Output encoding bits per component - must be 8 */
+ int oelev, /* Output encoding levels. Must be <= 2 ^ oebpc */
+ int *oevalues, /* Optional output encoding values for each level */
+ /* Must be oelev entries. Default is 0 .. oelev-1 */
+ sc_oorder oo, /* Output bit ordering */
+ double overlap, /* Overlap between levels, 0 - 1.0 */
+ void **cntx, /* List of contexts for lookup table callback */
+ double (**lutfunc)(void *cntx, double in) /* List of callback function, NULL if none */
+);
+
+/* ---------------------------- */
+/* Screen defintion information */
+
+typedef struct {
+ int x;
+ int y;
+} ccoord;
+
+typedef struct {
+ int size; /* General size */
+ int width; /* width in pixels */
+ int height; /* Height in pixels */
+ double asp; /* Aspect ratio (== dpiX/dpiY) */
+ int joint; /* na for joint screens */
+ ccoord **list; /* Pointer to list of pointers to threshold coordinates */
+} thscdef;
+
+/* ------------------------ */
+/* Setup of a single screen */
+
+struct _thscreen {
+ sc_iencoding ie; /* Input encoding */
+ int oebpc; /* Output encoding bits per component, 1,2,4 or 8 */
+ int oelev; /* Output encoding levels. Must be <= 2 ^ oebpc */
+ int oevalues[256]; /* Output encoding values for each level */
+ sc_oorder oo; /* Output bit ordering */
+ double asp; /* Aspect ratio (== dpiX/dpiY) */
+ double overlap; /* Overlap between levels, 0 - 1.0 */
+ int *lut; /* Lookup table */
+ unsigned char _tht[65536 * 3];/* Threshold table */
+ unsigned char *tht; /* Pointer to base of threshold table */
+ unsigned char **thp; /* Pointers to threshold table (offset int _tht) */
+ int swidth; /* Given screen width */
+ int sheight; /* Given screen height */
+ int twidth; /* Rounded up screen table width & stride */
+ int theight; /* Screen table height */
+
+ void (* screen)( /* Pointer to dither function */
+ struct _thscreen *t, /* Screening object pointer */
+ int width, int height, /* Width and height to screen in pixels */
+ int xoff, int yoff, /* Offset into screening pattern */
+ unsigned char *in, /* Input pixel buffer */
+ unsigned long ipinc, /* Increment between input pixels */
+ unsigned long ipitch, /* Increment between input lines */
+ unsigned char *out, /* Output pixel buffer */
+ unsigned long opinc, /* Increment between output pixels */
+ unsigned long opitch); /* Increment between output lines */
+
+ void (* del)( /* Destructor */
+ struct _thscreen *t); /* Screening object pointer */
+
+}; typedef struct _thscreen thscreen;
+
+/* Create a new thscreen object */
+/* Return NULL on error */
+thscreen *new_thscreen(
+ int width, /* width in pixels */
+ int height, /* Height in pixels */
+ int xoff, int yoff, /* Pattern offsets into width & height (must be +ve) */
+ double asp, /* Aspect ratio (== dpiX/dpiY) */
+ int swap, /* Swap X & Y to invert aspect ratio */
+ ccoord *thli, /* List of screen initialisation threshold coordinates */
+ sc_iencoding ie, /* Input encoding - must be scie_16 */
+ int oebpc, /* Output encoding bits per component - must be 8 */
+ int oelev, /* Output encoding levels. Must be <= 2 ^ oebpc */
+ int *oevalues, /* Optional output encoding values for each level */
+ /* Must be oelev entries. Default is 0 .. oelev-1 */
+ sc_oorder oo, /* Output bit ordering */
+ double olap, /* Overlap between levels, 0 - 1.0 */
+ void *cntx, /* Context for LUT table callback */
+ double (*lutfunc)(void *cntx, double in) /* Callback function, NULL if none */
+);
+
+#endif /* THSCREEN_H */
diff --git a/render/timage.c b/render/timage.c
new file mode 100644
index 0000000..c4404f7
--- /dev/null
+++ b/render/timage.c
@@ -0,0 +1,682 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * RGB gamut boundary test image generator
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/12/2005
+ *
+ * Copyright 2005 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.
+ */
+
+/*
+ * Generate TIFF image with two RGB cube surface hexagons,
+ * plus a rectangular grey wedges between them, on a grey
+ * background, or a rectangular gamut surface test image.
+ */
+
+/*
+ * TTBD:
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numsup.h"
+#include "render.h"
+
+#define DEF_DPI 200
+#define DITHER 0 /* Test 8 bit didthering */
+
+void
+usage(void) {
+ fprintf(stderr,"Create test images, default hex RGB surface and wedge, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: timage [-options] outfile.tif\n");
+// fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -t Generate rectangular gamut boundary test chart\n");
+ fprintf(stderr," -p steps Generate a colorspace step chart with L* steps^2\n");
+ fprintf(stderr," -r res Resolution in DPI (default %d)\n",DEF_DPI);
+ fprintf(stderr," -s Smooth blend\n");
+ fprintf(stderr," -x 16 bit output\n");
+ fprintf(stderr," -4 CMYK output\n");
+ fprintf(stderr," -g prop Percentage towards grey (default 0%%)\n");
+// fprintf(stderr," -D Debug primitives plot */
+ fprintf(stderr," outfile.tif Profile to check against\n");
+ exit(1);
+ }
+
+int main(int argc, char *argv[])
+{
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ int rchart = 0; /* Rectangular chart */
+ int schart = 0; /* Step chart with steps^2 */
+ int smooth = 0; /* Use smooth blending */
+ int debugchart = 0; /* Debug chart */
+ double res = DEF_DPI;
+ depth2d depth = bpc8_2d;
+ int cmyk = 0; /* Do CMYK output */
+ char outname[MAXNAMEL+1] = { 0 }; /* Output TIFF name */
+ render2d *r;
+ color2d c;
+ double vv[4][2];
+ color2d cc[4];
+ double gbf = 1.0; /* Grey blend factor */
+ double w, h; /* Size of page in mm */
+ int i, j;
+
+ error_program = "timage";
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ /* Rectangular chart */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ rchart = 1;
+ schart = 0;
+
+ /* Smooth blending */
+ } else if (argv[fa][1] == 's' || argv[fa][1] == 'S')
+ smooth = 1;
+
+ /* 16 bit depth */
+ else if (argv[fa][1] == 'x' || argv[fa][1] == 'X')
+ depth = bpc16_2d;
+
+ /* cmyk */
+ else if (argv[fa][1] == '4')
+ cmyk = 1;
+
+ /* step chart */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage();
+ schart = atoi(na);
+ if (schart <= 0) usage();
+ rchart = 0;
+ }
+
+ /* debug chart */
+ else if (argv[fa][1] == 'D') {
+ debugchart = 1;
+ }
+
+ /* resolution */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ res = atof(na);
+ if (res <= 0.0) usage();
+ }
+
+ /* grey blend */
+ else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') {
+ fa = nfa;
+ if (na == NULL) usage();
+ gbf = 1.0 - 0.01 * atof(na);
+ if (gbf < 0.0 || gbf > 1.0) usage();
+ }
+ else
+ usage();
+ } else
+ break;
+ }
+
+ /* Get the file name arguments */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(outname,argv[fa++],MAXNAMEL); outname[MAXNAMEL] = '\000';
+
+ res /= 25.4; /* Convert to DPmm */
+
+ /* Debug chart - test each primitive in RGB space */
+ if (debugchart) {
+ font2d fo;
+
+ h = 140.0;
+ w = 200.0;
+
+ if (cmyk)
+ error("CMYK not supported for test chart");
+
+ if ((r = new_render2d(w, h, NULL, res, res, rgb_2d, 0, depth, DITHER)) == NULL) {
+ error("new_render2d() failed");
+ }
+
+ /* Set the background color */
+// c[0] = 0.5;
+// c[1] = 0.5;
+// c[2] = 0.5;
+ c[0] = 1.0;
+ c[1] = 1.0;
+ c[2] = 1.0;
+ r->set_defc(r, c);
+
+ c[0] = 1.0; /* Red rectangle, bottom left */
+ c[1] = 0.0;
+ c[2] = 0.0;
+ r->add(r, new_rect2d(r, 5.0, 5.0, 8.0, 8.0, c)) ;
+
+ c[0] = 0.0; /* Green to the right of red */
+ c[1] = 1.0;
+ c[2] = 0.0;
+ r->add(r, new_rect2d(r, 15.0, 5.0, 8.0, 8.0, c)) ;
+
+ c[0] = 0.0; /* Blue to the right of green */
+ c[1] = 0.0;
+ c[2] = 1.0;
+ r->add(r, new_rect2d(r, 25.0, 5.0, 8.0, 8.0, c)) ;
+
+ /* A vertex shaded rectangle */
+ cc[0][0] = 1.0; /* Red */
+ cc[0][1] = 0.0;
+ cc[0][2] = 0.0;
+ cc[1][0] = 0.0; /* Green */
+ cc[1][1] = 1.0;
+ cc[1][2] = 0.0;
+ cc[2][0] = 0.0; /* Blue */
+ cc[2][1] = 0.0;
+ cc[2][2] = 1.0;
+ cc[3][0] = 1.0; /* Yellow */
+ cc[3][1] = 1.0;
+ cc[3][2] = 0.0;
+
+ r->add(r, new_rectvs2d(r, 5.0, 20.0, 18.0, 18.0, cc));
+
+ /* A shaded triangle to the right of the shaded rectangle */
+ vv[0][0] = 30.0;
+ vv[0][1] = 20.0;
+ cc[0][0] = 0.0;
+ cc[0][1] = 1.0;
+ cc[0][2] = 1.0;
+
+ vv[1][0] = 50.0;
+ vv[1][1] = 20.0;
+ cc[1][0] = 1.0;
+ cc[1][1] = 0.0;
+ cc[1][2] = 1.0;
+
+ vv[2][0] = 40.0;
+ vv[2][1] = 40.0;
+ cc[2][0] = 1.0;
+ cc[2][1] = 1.0;
+ cc[2][2] = 0.0;
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ /* A diagonal wide line */
+ c[0] = 0.0;
+ c[1] = 0.0;
+ c[2] = 0.0;
+ r->add(r, new_line2d(r, 10.0, 45.0, 11.0, 55.0, 3.0, 1, c));
+
+ /* A dashed line */
+ add_dashed_line2d(r, 20.0, 45.0, 100.0, 65.0, 1.0, 3.0, 5.0, 1, c);
+
+ fo = futura_l;
+
+ /* rectange the size the letter A should be */
+ c[0] = 0.7;
+ c[1] = 0.0;
+ c[2] = 0.0;
+ r->add(r, new_rect2d(r, 10.0, 60.0, 7.7, 10.0, c)) ;
+
+ c[0] = 0.0;
+ c[1] = 0.0;
+ c[2] = 0.0;
+ /* The letter A */
+ add_char2d(r, NULL, NULL, fo, 'A', 10.0, 60.0, 10.0, 0, c);
+
+ /* A test string */
+ add_string2d(r, NULL, NULL, fo, "Testing 1234", 10.0, 70.0, 7.0, 3, c);
+
+ {
+ double x, y;
+ char chars[33];
+
+ x = 10.0;
+ y = 125.0;
+ for (j = 0; j < 4; j++) {
+ for (i = 0; i < 32; i++)
+ chars[i] = j * 32 + i;
+ chars[i] = '\000';
+ add_string2d(r, NULL, NULL, fo, chars, x, y, 7.0, 0, c);
+ y -= 10.0;
+ }
+ }
+
+ /* RGB Hexagon chart */
+ } else if (rchart == 0 && schart == 0) {
+ double r3o2; /* 0.866025 */
+ double bb = 0.07; /* Border proportion */
+ double hh = 40.0; /* Height of hexagon in mm */
+ color2d white;
+ color2d red;
+ color2d green;
+ color2d blue;
+ color2d cyan;
+ color2d magenta;
+ color2d yellow;
+ color2d black;
+ color2d grey;
+ color2d kblack;
+
+ r3o2 = sqrt(3.0)/2.0; /* Width to heigh of hexagon */
+ h = (1.0 + 2.0 * bb) * hh;
+ w = (4.0 * bb + 0.25 + 2.0 * r3o2) * hh;
+
+ if ((r = new_render2d(w, h, NULL, res, res, cmyk ? cmyk_2d : rgb_2d, 0, depth, DITHER)) == NULL) {
+ error("new_render2d() failed");
+ }
+
+ if (cmyk) {
+ white[0] = 0.0;
+ white[1] = 0.0;
+ white[2] = 0.0;
+ white[3] = 0.0;
+ red[0] = 0.0;
+ red[1] = 1.0;
+ red[2] = 1.0;
+ red[3] = 0.0;
+ green[0] = 1.0;
+ green[1] = 0.0;
+ green[2] = 1.0;
+ green[3] = 0.0;
+ blue[0] = 1.0;
+ blue[1] = 1.0;
+ blue[2] = 0.0;
+ blue[3] = 0.0;
+ cyan[0] = 1.0;
+ cyan[1] = 0.0;
+ cyan[2] = 0.0;
+ cyan[3] = 0.0;
+ magenta[0] = 0.0;
+ magenta[1] = 1.0;
+ magenta[2] = 0.0;
+ magenta[3] = 0.0;
+ yellow[0] = 0.0;
+ yellow[1] = 0.0;
+ yellow[2] = 1.0;
+ yellow[3] = 0.0;
+ kblack[0] = 0.0;
+ kblack[1] = 0.0;
+ kblack[2] = 0.0;
+ kblack[3] = 1.0;
+ grey[0] = 0.0;
+ grey[1] = 0.0;
+ grey[2] = 0.0;
+ grey[3] = 0.5;
+ black[0] = 1.0;
+ black[1] = 1.0;
+ black[2] = 1.0;
+ black[3] = 0.0;
+ } else {
+ white[0] = 1.0;
+ white[1] = 1.0;
+ white[2] = 1.0;
+ red[0] = 1.0;
+ red[1] = 0.0;
+ red[2] = 0.0;
+ green[0] = 0.0;
+ green[1] = 1.0;
+ green[2] = 0.0;
+ blue[0] = 0.0;
+ blue[1] = 0.0;
+ blue[2] = 1.0;
+ cyan[0] = 0.0;
+ cyan[1] = 1.0;
+ cyan[2] = 1.0;
+ magenta[0] = 1.0;
+ magenta[1] = 0.0;
+ magenta[2] = 1.0;
+ yellow[0] = 1.0;
+ yellow[1] = 1.0;
+ yellow[2] = 0.0;
+ black[0] = 0.0;
+ black[1] = 0.0;
+ black[2] = 0.0;
+ grey[0] = 0.5;
+ grey[1] = 0.5;
+ grey[2] = 0.5;
+ }
+
+ /* Set the default color */
+ r->set_defc(r, grey);
+
+ /* Left hand hex */
+ vv[0][0] = hh * bb + r3o2 * 0.5 * hh;
+ vv[0][1] = hh * bb + hh/2.0;
+ cc[0][0] = white[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[0][1] = white[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[0][2] = white[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[0][3] = white[3] * gbf + (1.0 - gbf) * grey[3];
+
+ vv[1][0] = hh * bb + r3o2 * 0.5 * hh;
+ vv[1][1] = hh * bb;
+ cc[1][0] = red[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = red[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = red[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = red[3] * gbf + (1.0 - gbf) * grey[3];
+
+ vv[2][0] = hh * bb;
+ vv[2][1] = hh * bb + 0.25 * hh;
+ cc[2][0] = magenta[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[2][1] = magenta[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[2][2] = magenta[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[2][3] = magenta[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[1][0] = hh * bb;
+ vv[1][1] = hh * bb + 0.75 * hh;
+ cc[1][0] = blue[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = blue[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = blue[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = blue[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[2][0] = hh * bb + r3o2 * 0.5 * hh;
+ vv[2][1] = hh * bb + 1.0 * hh;
+ cc[2][0] = cyan[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[2][1] = cyan[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[2][2] = cyan[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[2][3] = cyan[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[1][0] = hh * bb + r3o2 * 1.0 * hh;;
+ vv[1][1] = hh * bb + 0.75 * hh;
+ cc[1][0] = green[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = green[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = green[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = green[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[2][0] = hh * bb + r3o2 * 1.0 * hh;
+ vv[2][1] = hh * bb + 0.25 * hh;
+ cc[2][0] = yellow[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[2][1] = yellow[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[2][2] = yellow[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[2][3] = yellow[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[1][0] = hh * bb + r3o2 * 0.5 * hh;;
+ vv[1][1] = hh * bb;
+ cc[1][0] = red[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = red[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = red[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = red[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+
+ /* Right hand hex */
+ vv[0][0] = hh * (3.0 * bb + 0.25 + r3o2) + r3o2 * 0.5 * hh;
+ vv[0][1] = hh * bb + hh/2.0;
+ cc[0][0] = black[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[0][1] = black[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[0][2] = black[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[0][3] = black[3] * gbf + (1.0 - gbf) * grey[3];
+
+ vv[1][0] = hh * (3.0 * bb + 0.25 + r3o2) + r3o2 * 0.5 * hh;
+ vv[1][1] = hh * bb;
+ cc[1][0] = red[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = red[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = red[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = red[3] * gbf + (1.0 - gbf) * grey[3];
+
+ vv[2][0] = hh * (3.0 * bb + 0.25 + r3o2);
+ vv[2][1] = hh * bb + 0.25 * hh;
+ cc[2][0] = magenta[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[2][1] = magenta[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[2][2] = magenta[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[2][3] = magenta[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[1][0] = hh * (3.0 * bb + 0.25 + r3o2);
+ vv[1][1] = hh * bb + 0.75 * hh;
+ cc[1][0] = blue[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = blue[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = blue[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = blue[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[2][0] = hh * (3.0 * bb + 0.25 + r3o2) + r3o2 * 0.5 * hh;
+ vv[2][1] = hh * bb + 1.0 * hh;
+ cc[2][0] = cyan[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[2][1] = cyan[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[2][2] = cyan[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = cyan[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[1][0] = hh * (3.0 * bb + 0.25 + r3o2) + r3o2 * 1.0 * hh;;
+ vv[1][1] = hh * bb + 0.75 * hh;
+ cc[1][0] = green[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = green[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = green[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = green[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[2][0] = hh * (3.0 * bb + 0.25 + r3o2) + r3o2 * 1.0 * hh;
+ vv[2][1] = hh * bb + 0.25 * hh;
+ cc[2][0] = yellow[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[2][1] = yellow[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[2][2] = yellow[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[2][3] = yellow[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ vv[1][0] = hh * (3.0 * bb + 0.25 + r3o2) + r3o2 * 0.5 * hh;;
+ vv[1][1] = hh * bb;
+ cc[1][0] = red[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = red[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = red[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = red[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_trivs2d(r, vv, cc));
+
+ /* Center wedge */
+ cc[0][0] = black[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[0][1] = black[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[0][2] = black[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[0][3] = black[3] * gbf + (1.0 - gbf) * grey[3];
+ cc[1][0] = black[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = black[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = black[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = black[3] * gbf + (1.0 - gbf) * grey[3];
+ cc[2][0] = white[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[2][1] = white[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[2][2] = white[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[2][3] = white[3] * gbf + (1.0 - gbf) * grey[3];
+ cc[3][0] = white[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[3][1] = white[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[3][2] = white[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[3][3] = white[3] * gbf + (1.0 - gbf) * grey[3];
+ if (cmyk)
+ r->add(r, new_rectvs2d(r, (2.0 * bb + r3o2) * hh, bb * hh, 0.125 * hh, hh, cc));
+ else
+ r->add(r, new_rectvs2d(r, (2.0 * bb + r3o2) * hh, bb * hh, 0.25 * hh, hh, cc));
+
+ /* Center CMY wedge */
+ if (cmyk) {
+ cc[0][0] = kblack[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[0][1] = kblack[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[0][2] = kblack[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[0][3] = kblack[3] * gbf + (1.0 - gbf) * grey[3];
+ cc[1][0] = kblack[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[1][1] = kblack[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[1][2] = kblack[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[1][3] = kblack[3] * gbf + (1.0 - gbf) * grey[3];
+ cc[2][0] = white[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[2][1] = white[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[2][2] = white[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[2][3] = white[3] * gbf + (1.0 - gbf) * grey[3];
+ cc[3][0] = white[0] * gbf + (1.0 - gbf) * grey[0];
+ cc[3][1] = white[1] * gbf + (1.0 - gbf) * grey[1];
+ cc[3][2] = white[2] * gbf + (1.0 - gbf) * grey[2];
+ cc[3][3] = white[3] * gbf + (1.0 - gbf) * grey[3];
+ r->add(r, new_rectvs2d(r, (2.0 * bb + r3o2 + 0.125) * hh, bb * hh, 0.125 * hh, hh, cc));
+ }
+
+
+ /* RGB Rectangular chart */
+ } else if (schart == 0) {
+ double bb = 0.07; /* Border proportion */
+ double hh = 50.0; /* Height of hexagon in mm */
+ double sc[6][3] = { /* Saturated color sequence */
+ { 1, 0, 0 },
+ { 1, 0, 1 },
+ { 0, 0, 1 },
+ { 0, 1, 1 },
+ { 0, 1, 0 },
+ { 1, 1, 0 }
+ };
+
+ if (cmyk)
+ error("CMYK not supported for test chart");
+
+ h = (1.0 + 2.0 * bb) * hh;
+ w = (2.0 * bb + 0.20 * 7.0) * hh;
+
+ if ((r = new_render2d(w, h, NULL, res, res, rgb_2d, 0, depth, DITHER)) == NULL) {
+ error("new_render2d() failed");
+ }
+
+ /* Set the default color */
+ c[0] = 0.5;
+ c[1] = 0.5;
+ c[2] = 0.5;
+ r->set_defc(r, c);
+
+ for (i = 0; i < 7; i++) {
+ prim2d *p;
+
+ /* Top rectangle */
+ cc[0][0] = sc[i % 6][0] * gbf + (1.0 - gbf) * 0.5;
+ cc[0][1] = sc[i % 6][1] * gbf + (1.0 - gbf) * 0.5;
+ cc[0][2] = sc[i % 6][2] * gbf + (1.0 - gbf) * 0.5;
+ cc[1][0] = sc[(i+1) % 6][0] * gbf + (1.0 - gbf) * 0.5;
+ cc[1][1] = sc[(i+1) % 6][1] * gbf + (1.0 - gbf) * 0.5;
+ cc[1][2] = sc[(i+1) % 6][2] * gbf + (1.0 - gbf) * 0.5;
+ cc[2][0] = 1.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[2][1] = 1.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[2][2] = 1.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[3][0] = 1.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[3][1] = 1.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[3][2] = 1.0 * gbf + (1.0 - gbf) * 0.5;
+ p = new_rectvs2d(r, (bb + i * 0.2) * hh, (bb + 0.5) * hh, 0.2 * hh, 0.5 * hh, cc);
+ if (smooth) {
+ rectvs2d *pp = (rectvs2d *)p;
+ pp->x_blend = 2;
+ pp->y_blend = 3;
+ }
+ r->add(r, p);
+
+ /* Bottom rectangle */
+ cc[0][0] = 0.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[0][1] = 0.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[0][2] = 0.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[1][0] = 0.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[1][1] = 0.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[1][2] = 0.0 * gbf + (1.0 - gbf) * 0.5;
+ cc[2][0] = sc[i % 6][0] * gbf + (1.0 - gbf) * 0.5;
+ cc[2][1] = sc[i % 6][1] * gbf + (1.0 - gbf) * 0.5;
+ cc[2][2] = sc[i % 6][2] * gbf + (1.0 - gbf) * 0.5;
+ cc[3][0] = sc[(i+1) % 6][0] * gbf + (1.0 - gbf) * 0.5;
+ cc[3][1] = sc[(i+1) % 6][1] * gbf + (1.0 - gbf) * 0.5;
+ cc[3][2] = sc[(i+1) % 6][2] * gbf + (1.0 - gbf) * 0.5;
+ p = new_rectvs2d(r, (bb + i * 0.2) * hh, bb * hh, 0.2 * hh, 0.5 * hh, cc);
+ if (smooth) {
+ rectvs2d *pp = (rectvs2d *)p;
+ pp->x_blend = 2;
+ pp->y_blend = 2;
+ }
+ r->add(r, p);
+ }
+
+ } else { /* Lab step chart */
+ double hh = 50.0; /* Height of hexagon in mm */
+ double bb = 0.05; /* Border proportion */
+ double ss, bs; /* Step size, border size */
+
+ h = hh;
+ w = hh;
+
+ if (cmyk)
+ error("CMYK not supported for test chart");
+
+ bs = (bb * hh)/(schart + 1.0);
+ ss = hh * (1.0 - bb)/schart;
+
+ if ((r = new_render2d(w, h, NULL, res, res, lab_2d, 0, depth, DITHER)) == NULL) {
+ error("new_render2d() failed");
+ }
+
+ /* Set the default color */
+ c[0] = 0.0;
+ c[1] = 0.0;
+ c[2] = 0.0;
+ r->set_defc(r, c);
+
+ for (i = 0; i < schart; i++) {
+ for (j = 0; j < schart; j++) {
+ double lv;
+
+ lv = (double)(j * schart + i)/(schart * schart - 1.0) * 100.0;
+
+ cc[0][0] = lv;
+ cc[0][1] = -127.0;
+ cc[0][2] = -127.0;
+ cc[1][0] = lv;
+ cc[1][1] = 127.0;
+ cc[1][2] = -127.0;
+ cc[2][0] = lv;
+ cc[2][1] = -127.0;
+ cc[2][2] = 127.0;
+ cc[3][0] = lv;
+ cc[3][1] = 127.0;
+ cc[3][2] = 127.0;
+ r->add(r, new_rectvs2d(r, bs + i * (bs + ss),
+ bs + j * (bs + ss),
+ ss, ss, cc));
+ }
+ }
+ }
+
+ r->write(r, outname,1);
+ r->del(r);
+
+ return 0;
+}
+
+
diff --git a/rspl/Jamfile b/rspl/Jamfile
new file mode 100644
index 0000000..a3f2e8c
--- /dev/null
+++ b/rspl/Jamfile
@@ -0,0 +1,83 @@
+
+# Regular spline library
+
+# Optimization and Debug flags
+
+PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+#PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCPROFFLAG) ; # Profile flags
+#PREF_LINKFLAGS += $(LINKPROFFLAG) ; # Profile flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Link with debug info
+
+SCAT = scat ; # Use thps scattered interpolation library
+
+#Products
+Libraries = librspl ;
+Headers = rspl.h ;
+
+#Install
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+
+# Multi-dimensional regular spline library
+Library librspl : rspl.c $(SCAT).c rev.c gam.c spline.c opt.c : : : ../h ../numlib ../plot ;
+
+HDRS = ../h ../numlib ../plot $(TIFFINC) ;
+LINKLIBS = librspl ../numlib/libnum ../plot/libplot ../plot/libvrml ../icc/libicc $(TIFFLIB) $(JPEGLIB) ;
+
+# Test programs
+MainsFromSources revbench.c c1.c c1df.c t2d.c t2ddf.c t3d.c t3ddf.c tnd.c trnd.c ;
+
+BUILD_TESTS = true ;
+
+if $(BUILD_TESTS) {
+
+ HDRS = ../h ../numlib ../plot ../icc ../rspl ../xicc ../gamut ../cgats ../spectro $(TIFFINC) ;
+ LINKLIBS = ../xicc/libxicc ../gamut/libgamut ../spectro/libinsttypes librspl
+ ../cgats/libcgats ../icc/libicc ../plot/libplot ../plot/libvrml
+ ../numlib/libnum $(TIFFLIB) $(JPEGLIB) ;
+
+ # Smoothness factor tuning test in Nd.
+ Main smtnd : smtnd.c ;
+
+ # Smoothness factor tuning test in Nd.
+ Main smtmpp : smtmpp.c ;
+
+# Main rand_check : rand_check.c ;
+
+# Main tt : tt.c ;
+
+ HDRS = ;
+ LINKLIBS = ;
+
+ Main sm1 : sm1.c ;
+ Main sm2 : sm2.c ;
+ Main sm3 : sm3.c ;
+
+}
+
+
+# Main tt : tt.c : : ../xicc : : : ../plot/libvrml ../icc/libicc ;
+
+if $(BUILD_JUNK) {
+
+ HDRS = ../h ../numlib ;
+ LINKLIBS = ..//numlib/libnum ;
+
+ #Main temp : temp.c ;
+
+ MainsFromSources prime.c combo.c combo2.c combo3.c combo4.c combo5.c combo9.c ;
+
+ #Main cache : cache.c ;
+
+ # Nearest point test code
+ Main nptest : nptest.c ;
+
+ # Nearest object test code
+ Main notest : notest.c ;
+
+ #direct mlbs scattered interpolation test
+ Main mlbs_test : mlbs_test.c ;
+}
+
diff --git a/rspl/License.txt b/rspl/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/rspl/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/rspl/Makefile.am b/rspl/Makefile.am
new file mode 100644
index 0000000..cfa0ec2
--- /dev/null
+++ b/rspl/Makefile.am
@@ -0,0 +1,15 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = librspl.la
+privatelibdir = $(pkglibdir)
+
+librspl_la_SOURCES = rspl.h rspl_imp.h mlbs.h rspl.c scat.c rev.c \
+ rev.h gam.c spline.c opt.c
+librspl_la_LIBADD = ../numlib/libargyllnum.la ../plot/libvrml.la
+
+LDADD = ./librspl.la ../numlib/libargyllnum.la ../plot/libplot.la \
+ ../plot/libvrml.la $(X_LIBS) $(TIFF_LIBS) $(ICC_LIBS)
+
+check_PROGRAMS = revbench c1 c1df t2d t2ddf t3d t3ddf tnd trnd
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/rspl/Readme.txt b/rspl/Readme.txt
new file mode 100644
index 0000000..4f6c8c0
--- /dev/null
+++ b/rspl/Readme.txt
@@ -0,0 +1,39 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+rspl now supports different resolution grids in each dimension.
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+This is the second generation Regular Spline library.
+
+It contains scattered data point to regular grid interpolation,
+as well as spline smoothing, and the reverse interpolation
+code. This version is more modular, and uses better solution
+algorithms than the earlier REGSPL, and generally replaces it.
+
+The reverse interpolation algorithms support features needed
+for devices like CMYK printers, such as total ink limiting,
+black locus selection, gamut boundary detection, vector
+and nearest gamut clipping.
+
+It has been written with operation with 6 color printing
+devices in mind (ie. 3 extra degrees of freedom, and hence
+a 3 dimensional inking locus), although this usage is likely
+to be unwealdy.
+
+
+Misc test files:
+
+c1.c Test 1D curves. First test is to check tracking at multiple resolutions
+c1df.c Test 1D curve with weak default function.
+c1i.c Test 1D curve with incremental points
+sm1.c Discover 1D smoothness factor vs resolution tracking factor
+sm2.c Discover 2D smoothness factor vs resolution tracking factor
+sm3.c Discover 3D smoothness factor vs resolution tracking factor
+t2d.c Test 2D fitting. Test againt two resolutions.
+t2ddf.c Test 2D fitting with weak default function.
+t3d.c Test 3D fitting. Test againt two resolutions.
+t3ddf.c Test 3D fitting with weak default function.
+tnd.c Simple test of 4D
+trnd.c Simple test of 4D reverse lookup.
+smtnd.c Sythetic function, nD multi-parameter fitting test function.
+smtmpp.c MPP function, nD multi-parameter fitting test function.
+
diff --git a/rspl/afiles b/rspl/afiles
new file mode 100644
index 0000000..af20c44
--- /dev/null
+++ b/rspl/afiles
@@ -0,0 +1,34 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+rspl.h
+rspl_imp.h
+rspl.c
+rev.h
+rev.c
+scat.c
+scat2.c
+mlbs.c
+mlbs.h
+opt.c
+gam.h
+gam.c
+revbench.c
+c1.c
+c1df.c
+spline.c
+t2d.c
+t2ddf.c
+t3d.c
+t3ddf.c
+tnd.c
+trnd.c
+sm1.c
+sm2.c
+sm3.c
+stest.c
+smtnd.c
+smtmpp.c
+rspl1.h
+rspl1.c
diff --git a/rspl/c1.c b/rspl/c1.c
new file mode 100644
index 0000000..8172cef
--- /dev/null
+++ b/rspl/c1.c
@@ -0,0 +1,396 @@
+
+/************************************************/
+/* Investigate various curve approximations */
+/************************************************/
+
+/* Discrete regularized spline versions */
+/* Standard test + Random testing */
+
+/* Author: Graeme Gill
+ * Date: 4/10/95
+ * Date: 5/4/96
+ *
+ * Copyright 1995, 1996 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+#undef DIAG
+#undef DIAG2
+#undef GLOB_CHECK
+#undef RES2 /* Do multiple test at various resolutions */
+#define AVGDEV 0.0 /* Average deviation of function data */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "plot.h"
+#include "rspl.h"
+
+double lin();
+void usage(void);
+
+#define TRIALS 20 /* Number of random trials */
+#define SKIP 0 /* Number of random trials to skip */
+
+#define MIN_PNTS 5
+#define MAX_PNTS 40
+
+#define MIN_RES 20
+#define MAX_RES 2000
+
+double xa[MAX_PNTS];
+double ya[MAX_PNTS];
+
+#define XRES 100
+
+#define PNTS1 10
+#define GRES1 400
+//#define GRES 800
+double t1xa[PNTS1] = { 0.2, 0.25, 0.30, 0.35, 0.40, 0.44, 0.48, 0.51, 0.64, 0.75 };
+double t1ya[PNTS1] = { 0.3, 0.35, 0.4, 0.41, 0.42, 0.46, 0.5, 0.575, 0.48, 0.75 };
+
+#ifndef NEVER
+
+// Reverse in x */
+#define PNTS2 10
+#define GRES2 400
+double t2xa[PNTS2] = { 0.25, 0.36, 0.49, 0.52, 0.56, 0.60, 0.65, 0.70, 0.75, 0.8 };
+double t2ya[PNTS2] = { 0.75, 0.48, 0.575, 0.5, 0.46, 0.42, 0.41, 0.4, 0.35, 0.3 };
+
+#else
+
+#define PNTS2 10
+#define GRES2 400
+// reverse in y
+double t2xa[PNTS2] = { 0.2, 0.25, 0.30, 0.35, 0.40, 0.44, 0.48, 0.51, 0.64, 0.75 };
+double t2ya[PNTS2] = { 0.7, 0.65, 0.6, 0.59, 0.58, 0.54, 0.5, 0.425, 0.52, 0.25 };
+
+#endif /* NEVER */
+
+//#define PNTS2 2
+//#define GRES2 5
+//double t2xa[PNTS2] = { 0.0, 1.0 };
+//double t2ya[PNTS2] = { 0.33, 0.66 };
+
+co test_points[MAX_PNTS];
+
+double lin(double x, double xa[], double ya[], int n);
+
+void usage(void) {
+ fprintf(stderr,"Test 1D rspl interpolation\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: c1 [options]\n");
+ fprintf(stderr," -s smooth Use given smoothness (default 1.0)\n");
+ fprintf(stderr," -2 Use two pass smoothing\n");
+ fprintf(stderr," -x Use extra fitting\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int i,j, n;
+ double x;
+ double xx[XRES];
+ double yy[6][XRES];
+ rspl *rss; /* incremental solution version */
+ datai low,high;
+ int gres[MXDI];
+ double smooth = 1.0;
+ int twopass = 0;
+ int extra = 0;
+ double avgdev[MXDO];
+
+ low[0] = 0.0;
+ high[0] = 1.0;
+ avgdev[0] = AVGDEV;
+
+ error_program = "c1";
+ check_if_not_interactive();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* smoothness */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ fa = nfa;
+ if (na == NULL) usage();
+ smooth = atof(na);
+ }
+
+ else if (argv[fa][1] == '2') {
+ twopass = 1;
+ }
+ else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ extra = 1;
+ }
+ else
+ usage();
+ } else
+ break;
+ }
+
+ for (n = 0; n < TRIALS; n++) {
+ double lrand = 0.0; /* Amount of level randomness */
+ int pnts;
+ int fres;
+
+ if (n == 0) { /* Standard versions */
+#ifdef NEVER /* Doubled up points */
+ pnts = 2 * PNTS;
+ fres = GRES;
+ for (i = 0; i < pnts; i++) {
+ xa[i * 2 + 0] = t1xa[i] - 0.01;
+ ya[i * 2 + 0] = t1ya[i];
+ xa[i * 2 + 1] = t1xa[i] + 0.01;
+ ya[i * 2 + 1] = t1ya[i];
+ }
+#else
+ pnts = PNTS1;
+ fres = GRES1;
+ for (i = 0; i < pnts; i++) {
+ xa[i] = t1xa[i];
+ ya[i] = t1ya[i];
+ }
+#endif
+ printf("Trial %d, points = %d, res = %d, level randomness = %f\n",n,pnts,fres,lrand);
+ } else if (n == 1) { /* Second test versions */
+ pnts = PNTS2;
+ fres = GRES2;
+ for (i = 0; i < pnts; i++) {
+ xa[i] = t2xa[i];
+ ya[i] = t2ya[i];
+ }
+ printf("Trial %d, points = %d, res = %d, level randomness = %f\n",n,pnts,fres,lrand);
+ } else { /* Random versions */
+ lrand = d_rand(0.0,0.1); /* Amount of level randomness */
+ pnts = i_rand(MIN_PNTS,MAX_PNTS);
+ fres = i_rand(MIN_RES,MAX_RES);
+
+ printf("Trial %d, points = %d, res = %d, level randomness = %f\n",n,pnts,fres,lrand);
+
+ /* Create X values */
+ xa[0] = d_rand(0.5,1.0);
+ for (i = 1; i < pnts; i++)
+ xa[i] = xa[i-1] + d_rand(0.5,1.0);
+ for (i = 0; i < pnts; i++) /* Divide out */
+ xa[i] = (xa[i]/xa[pnts-1]);
+
+ /* Create y values */
+ ya[0] = xa[0];
+ for (i = 0; i < pnts; i++)
+ ya[i] = ya[i-1] + d_rand(0.2,1.0) + d_rand(-0.2,0.3) + d_rand(-0.2,0.3);
+ for (i = 0; i < pnts; i++) /* Divide out */
+ ya[i] = (ya[i]/ya[pnts-1]);
+ }
+
+ if (n < SKIP)
+ continue;
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS,
+ 1, /* di */
+ 1); /* fdi */
+
+ for (i = 0; i < pnts; i++) {
+ test_points[i].p[0] = xa[i];
+ test_points[i].v[0] = ya[i];
+ }
+ gres[0] = fres;
+
+#ifdef RES2
+ if (n != 0) {
+#endif
+ /* Fit to scattered data */
+ rss->fit_rspl(rss,
+ 0 | (twopass ? RSPL_2PASSSMTH : 0)
+ | (extra ? RSPL_EXTRAFIT2 : 0) ,
+ test_points, /* Test points */
+ pnts, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ smooth, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+
+
+ /* Display the result */
+ for (i = 0; i < XRES; i++) {
+ co tp; /* Test point */
+ x = i/(double)(XRES-1);
+ xx[i] = x;
+ yy[0][i] = lin(x,xa,ya,pnts);
+ tp.p[0] = x;
+ rss->interp(rss, &tp);
+ yy[1][i] = tp.v[0];
+ if (yy[1][i] < -0.2)
+ yy[1][i] = -0.2;
+ else if (yy[1][i] > 1.2)
+ yy[1][i] = 1.2;
+ }
+
+ do_plot(xx,yy[0],yy[1],NULL,XRES);
+
+#ifdef RES2
+ } else { /* Multiple resolution version */
+ int gresses[5];
+ for (j = 0; j < 5; j++) {
+#ifndef NEVER
+ if (j == 0)
+ gres[0] = fres/8;
+ else if (j == 1)
+ gres[0] = fres/4;
+ else if (j == 2)
+ gres[0] = fres/2;
+ else if (j == 3)
+ gres[0] = fres;
+ else
+ gres[0] = fres * 2;
+#else /* Check sensitivity to griding of data points */
+ if (j == 0)
+ gres[0] = 192;
+ else if (j == 1)
+ gres[0] = 193;
+ else if (j == 2)
+ gres[0] = 194;
+ else if (j == 3)
+ gres[0] = 195;
+ else
+ gres[0] = 196;
+#endif
+ gresses[j] = gres[0];
+
+ rss->fit_rspl(rss,
+ 0 | (twopass ? RSPL_2PASSSMTH : 0)
+ | (extra ? RSPL_EXTRAFIT2 : 0) ,
+ 0,
+ test_points, /* Test points */
+ pnts, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ smooth, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+
+ /* Get the result */
+ for (i = 0; i < XRES; i++) {
+ co tp; /* Test point */
+ x = i/(double)(XRES-1);
+ xx[i] = x;
+ yy[0][i] = lin(x,xa,ya,pnts);
+ tp.p[0] = x;
+ rss->interp(rss, &tp);
+ yy[1+j][i] = tp.v[0];
+ if (yy[1+j][i] < -0.2)
+ yy[1+j][i] = -0.2;
+ else if (yy[1+j][i] > 1.2)
+ yy[1+j][i] = 1.2;
+ }
+ }
+
+ printf("Black = lin, Red = %d, Green = %d, Blue = %d, Yellow = %d, Purple = %d\n",
+ gresses[0], gresses[1], gresses[2], gresses[3], gresses[4]);
+ do_plot6(xx,yy[0],yy[1],yy[2],yy[3],yy[4],yy[5],XRES);
+ }
+#endif /* RES2 */
+ } /* next trial */
+ return 0;
+}
+
+
+/* Simple linear interpolation */
+double
+lin(
+double x,
+double xa[],
+double ya[],
+int n) {
+ int i;
+ double y;
+
+ if (x < xa[0])
+ return ya[0];
+ else if (x > xa[n-1])
+ return ya[n-1];
+
+ for (i = 0; i < (n-1); i++)
+ if (x >=xa[i] && x <= xa[i+1])
+ break;
+
+ x = (x - xa[i])/(xa[i+1] - xa[i]);
+
+ y = ya[i] + (ya[i+1] - ya[i]) * x;
+
+ return y;
+}
+
+
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+/* Next u function done with optimization */
+
+/* Structure to hold data for optimization function */
+struct _edatas {
+ rspl *rss;
+ int j;
+ }; typedef struct _edatas edatas;
+
+#ifdef GLOB_CHECK
+/* Overall Global optimization method */
+/* Definition of the optimization function handed to powell() */
+double efunc2(void *edata, double p[])
+ {
+ int j;
+ double rv;
+ rspl *rss = (rspl *)edata;
+ for (j = 0; j < rss->nig; j++) /* Ugg */
+ rss->u[j].v = p[j];
+ rv = rss->efactor(rss);
+#ifdef DIAG2
+ /* printf("%c%e",cr_char,rv); */
+ printf("%e\n",rv);
+#endif
+ return rv;
+ }
+
+solveu(rss)
+rspl *rss;
+ {
+ int j;
+ double *cp;
+ double *s;
+
+ cp = dvector(0,rss->nig);
+ s = dvector(0,rss->nig);
+ for (j = 0; j < rss->nig; j++) /* Ugg */
+ {
+ cp[j] = rss->u[j].v;
+ s[j] = 0.1;
+ }
+ powell(rss->nig,cp,s,1e-7,1000,efunc2,(void *)rss);
+ }
+#endif /* GLOB_CHECK */
diff --git a/rspl/c1df.c b/rspl/c1df.c
new file mode 100644
index 0000000..5d8dc32
--- /dev/null
+++ b/rspl/c1df.c
@@ -0,0 +1,313 @@
+
+/************************************************/
+/* Investigate various curve approximations */
+/************************************************/
+
+/* Discrete regularized spline versions */
+/* Standard test with weak default function */
+
+/* Author: Graeme Gill
+ * Date: 20/11/2005
+ *
+ * Copyright 1995, 1996, 2005 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+#undef DIAG
+#undef DIAG2
+#undef GLOB_CHECK
+#define RES2 /* Do multiple test at various resolutions */
+#undef EXTRAFIT /* Test extra fitting effort */
+#define SMOOTH 1.0
+#define AVGDEV 0.0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "plot.h"
+#include "rspl.h"
+
+double lin();
+void usage(void);
+
+#define TRIALS 15 /* Number of random trials */
+#define SKIP 0 /* Number of random trials to skip */
+
+#define MIN_PNTS 1
+#define MAX_PNTS 7
+
+#define MIN_RES 20
+#define MAX_RES 300
+
+double xa[MAX_PNTS];
+double ya[MAX_PNTS];
+double wa[MAX_PNTS];
+
+#define XRES 100
+
+#define PNTS 2
+#define GRES 200
+//double t1xa[PNTS] = { 0.325, 0.625 };
+//double t1ya[PNTS] = { 0.4, 0.70 };
+double t1xa[PNTS] = { 0.325, 0.625 };
+double t1ya[PNTS] = { 0.5, 0.8 };
+double t1wa[PNTS] = { 1.0, 1.0 };
+cow test_points[MAX_PNTS];
+
+double lin(double x, double xa[], double ya[], int n);
+
+/* Weak default function */
+static void wfunc(void *cbntx, double *out, double *in) {
+ out[0] = in[0];
+}
+
+void usage(void) {
+ fprintf(stderr,"Test 1D rspl interpolation with weak default function\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: c1df [options]\n");
+ fprintf(stderr," -w wweight Set weak default function weight (default 1.0)\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int i,j, n;
+ double x;
+ double xx[XRES];
+ double yy[6][XRES];
+ rspl *rss; /* incremental solution version */
+ datai low,high;
+ int gres[MXDI];
+ double avgdev[MXDO];
+ double wweight = 1.0;
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?') {
+ usage();
+
+ } else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage();
+ wweight = atof(na);
+ } else
+ usage();
+ } else
+ break;
+ }
+
+ low[0] = 0.0;
+ high[0] = 1.0;
+ avgdev[0] = AVGDEV;
+
+ error_program = "Curve1";
+
+ for (n = 0; n < TRIALS; n++) {
+ double lrand = 0.0; /* Amount of level randomness */
+ int pnts;
+ int fres;
+
+ if (n == 0) { /* Standard versions */
+ pnts = PNTS;
+ fres = GRES;
+ for (i = 0; i < pnts; i++) {
+ xa[i] = t1xa[i];
+ ya[i] = t1ya[i];
+ wa[i] = t1wa[i];
+ }
+ printf("Trial %d, points = %d, res = %d, level randomness = %f\n",n,pnts,fres,lrand);
+ } else { /* Random versions */
+ double xmx;
+ lrand = d_rand(0.0,0.1); /* Amount of level randomness */
+ pnts = i_rand(MIN_PNTS,MAX_PNTS);
+ fres = i_rand(MIN_RES,MAX_RES);
+
+ printf("Trial %d, points = %d, res = %d, level randomness = %f\n",n,pnts,fres,lrand);
+
+ /* Create X values */
+ xa[0] = d_rand(0.3, 0.5);
+ for (i = 1; i < pnts; i++)
+ xa[i] = xa[i-1] + d_rand(0.2,0.7);
+ xmx = d_rand(0.6, 0.9);
+ for (i = 0; i < pnts; i++) /* Divide out */
+ xa[i] *= (xmx/xa[pnts-1]);
+
+ /* Create y values */
+ for (i = 0; i < pnts; i++) {
+ ya[i] = xa[i] + d_rand(-lrand,lrand);
+ wa[i] = 1.0;
+ }
+ }
+
+ if (n < SKIP)
+ continue;
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS, 1, /* di */
+ 1); /* fdi */
+
+ for (i = 0; i < pnts; i++) {
+ test_points[i].p[0] = xa[i];
+ test_points[i].v[0] = ya[i];
+ test_points[i].w = wa[i];
+ }
+ gres[0] = fres;
+
+#ifdef RES2
+ if (n != 0) {
+#endif
+ /* Fit to scattered data */
+ rss->fit_rspl_w_df(rss,
+#ifdef EXTRAFIT
+ RSPL_EXTRAFIT | /* Extra fit flag */
+#endif
+ 0,
+ test_points, /* Test points */
+ pnts, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ low, high, /* Data scale */
+ SMOOTH, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL, /* iwidth */
+ wweight, /* weak function weight */
+ NULL, /* No context */
+ wfunc /* Weak function */
+ );
+
+ /* Display the result */
+ for (i = 0; i < XRES; i++) {
+ co tp; /* Test point */
+ x = i/(double)(XRES-1);
+ xx[i] = x;
+ yy[0][i] = lin(x,xa,ya,pnts);
+ tp.p[0] = x;
+ rss->interp(rss, &tp);
+ yy[1][i] = tp.v[0];
+ if (yy[1][i] < -0.2)
+ yy[1][i] = -0.2;
+ else if (yy[1][i] > 1.2)
+ yy[1][i] = 1.2;
+ }
+
+ do_plot(xx,yy[0],yy[1],NULL,XRES);
+
+#ifdef RES2
+ } else { /* Multiple resolution version */
+ int gresses[5];
+ for (j = 0; j < 5; j++) {
+#ifndef NEVER
+ if (j == 0)
+ gres[0] = fres/8;
+ else if (j == 1)
+ gres[0] = fres/4;
+ else if (j == 2)
+ gres[0] = fres/2;
+ else if (j == 3)
+ gres[0] = fres;
+ else
+ gres[0] = fres * 2;
+#else /* Check sensitivity to griding of data points */
+ if (j == 0)
+ gres[0] = 192;
+ else if (j == 1)
+ gres[0] = 193;
+ else if (j == 2)
+ gres[0] = 194;
+ else if (j == 3)
+ gres[0] = 195;
+ else
+ gres[0] = 196;
+#endif
+ gresses[j] = gres[0];
+
+ rss->fit_rspl_w_df(rss,
+#ifdef EXTRAFIT
+ RSPL_EXTRAFIT | /* Extra fit flag */
+#endif
+ 0,
+ test_points, /* Test points */
+ pnts, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ low, high, /* Data scale */
+ SMOOTH, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL, /* iwidth */
+ wweight, /* weak function weight */
+ NULL, /* No context */
+ wfunc /* Weak function */
+ );
+
+ /* Get the result */
+ for (i = 0; i < XRES; i++) {
+ co tp; /* Test point */
+ x = i/(double)(XRES-1);
+ xx[i] = x;
+ yy[0][i] = lin(x,xa,ya,pnts);
+ tp.p[0] = x;
+ rss->interp(rss, &tp);
+ yy[1+j][i] = tp.v[0];
+ if (yy[1+j][i] < -0.2)
+ yy[1+j][i] = -0.2;
+ else if (yy[1+j][i] > 1.2)
+ yy[1+j][i] = 1.2;
+ }
+ }
+
+ printf("Black = lin, Red = %d, Green = %d, Blue = %d, Yellow = %d, Purple = %d\n",
+ gresses[0], gresses[1], gresses[2], gresses[3], gresses[4]);
+ do_plot6(xx,yy[0],yy[1],yy[2],yy[3],yy[4],yy[5],XRES);
+ }
+#endif /* RES2 */
+ } /* next trial */
+ return 0;
+}
+
+
+double
+lin(
+double x,
+double xa[],
+double ya[],
+int n)
+ {
+ int i;
+ double y;
+
+ if (x < xa[0])
+ return ya[0];
+ else if (x > xa[n-1])
+ return ya[n-1];
+
+ for (i = 0; i < (n-1); i++)
+ if (x >=xa[i] && x <= xa[i+1])
+ break;
+
+ x = (x - xa[i])/(xa[i+1] - xa[i]);
+
+ y = ya[i] + (ya[i+1] - ya[i]) * x;
+
+ return y;
+ }
+
+
diff --git a/rspl/gam.c b/rspl/gam.c
new file mode 100644
index 0000000..f8d02d0
--- /dev/null
+++ b/rspl/gam.c
@@ -0,0 +1,1220 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized spline data structure
+ *
+ * Precice gamut surface, gamut pruning, ink limiting and K min/max
+ * support routine.s
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/11/21
+ *
+ * Copyright 1999 - 2008 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.
+ *
+ * Latest simplex/linear equation version.
+ */
+
+/* TTBD:
+
+ Add ouutput curve lookup callback support.
+ Cache these values in the vertex structures ?
+
+ Add ink limit support. This be done by breaking
+ a cell into a fixed geometry of smaller simplexes
+ by dividing the cell into two on each axis.
+
+ Need to then add scan that detects areas to prune,
+ that then ties in with rev code to mark such
+ areas out of gamut.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <memory.h>
+#include <time.h>
+
+#include "rspl_imp.h"
+#include "numlib.h"
+#include "sort.h" /* Heap sort */
+#include "counters.h" /* Counter macros */
+
+#include "vrml.h" /* If there is VRML stuff here */
+
+/* Print a vectors value */
+#define DBGVI(text, dim, out, vec, end) \
+{ int pveci; \
+ printf("%s",text); \
+ for (pveci = 0 ; pveci < (dim); pveci++) \
+ printf(out,(vec)[pveci]); \
+ printf(end); \
+}
+
+/* Print a matrix value */
+#define DBGMI(text, rows, cols, out, mat, end) \
+{ int pveci, pvecr; \
+ printf("%s",text); \
+ for (pvecr = 0 ; pvecr < (rows); pvecr++) { \
+ for (pveci = 0 ; pveci < (cols); pveci++) \
+ printf(out,(mat)[pvecr][pveci]); \
+ if ((pvecr+1) < (rows)) \
+ printf("\n"); \
+ } \
+ printf(end); \
+}
+
+#undef VRML_TRACE /* Save a vrml at each step */
+
+/* Do an arbitrary printf */
+#define DBGI(text) printf text ;
+
+#define DEBUG1
+#undef DBG
+#undef DBGV
+#undef DBGM
+
+#undef NEVER
+#define ALWAYS
+
+#ifdef DEBUG1
+#undef DBGS
+#undef DBG
+#undef DBGV
+#undef DBGM
+#define DEBUG
+#define DBGS(xxx) xxx
+#define DBG(xxx) DBGI(xxx)
+#define DBGV(xxx) DBGVI xxx
+#define DBGM(xxx) DBGMI xxx
+#else
+#undef DEBUG
+#undef DBGS
+#undef DBG
+#undef DBGV
+#undef DBGM
+#define DBGS(xxx)
+#define DBG(xxx)
+#define DBGV(xxx)
+#define DBGM(xxx)
+#endif
+
+/* Convention is to use:
+ i to index grid points u.a
+ n to index data points d.a
+ e to index position dimension di
+ f to index output function dimension fdi
+ j misc and cube corners
+ k misc
+ */
+
+#define EPS (1e-10) /* Allowance for numeric error */
+
+/* ====================================================== */
+/* Support functions */
+
+/* Compute the norm (length) squared of a vector define by two points */
+static double norm33sq(double in1[3], double in0[3]) {
+ int j;
+ double rv;
+ for (rv = 0.0, j = 0; j < 3; j++) {
+ double tt = in1[j] - in0[j];
+ rv += tt * tt;
+ }
+ return rv;
+}
+
+
+static rvert *get_vert(rspl *s, int gix);
+
+/* Given an output value, return the gamut radius */
+static double gvprad(rspl *s, double *v) {
+ int f, fdi = s->fdi;
+ double rr = 0.0;
+
+ for (f = 0; f < fdi; f++) {
+ double tt;
+ tt = s->gam.scale[f] * (v[f] - s->gam.cent[f]);
+ rr += tt * tt;
+ }
+ rr = sqrt(rr);
+ return rr;
+}
+
+
+/* Given an output value, create the radial coordinate */
+static void radcoord(rspl *s, double *rad, double *v) {
+ int f, fdi = s->fdi;
+ double rr = 0.0;
+
+ for (f = 0; f < fdi; f++) {
+ double tt;
+ tt = s->gam.scale[f] * (v[f] - s->gam.cent[f]);
+ rr += tt * tt;
+ }
+ rr = sqrt(rr);
+
+ rad[0] = rr;
+}
+
+/* Given an output value and an edge, return the side, */
+/* 0 = -vem 1 = +ve */
+static int eside(rspl *s, redge *ep, double *v) {
+ int f, fdi = s->fdi;
+ double tt;
+
+ for (tt = 0.0, f = 0; f < fdi; f++) {
+ tt += v[f] * ep->pe[f];
+ }
+ tt += ep->pe[f];
+ return (tt >= 0.0 ? 1 : 0);
+}
+
+
+/* Given a list of nodes that form an sdi-1 sub-simplex, */
+/* return a list of nodes that could be added to make */
+/* an sdi sub-simplex. */
+/* Nodes are identified by their grid index. */
+/* All possible nodes are returned, even if they are already */
+/* in our surface triangulation. */
+/* NOTE that inodes will be sorted into sub-simplex order! */
+// ~~99 we aren't currently taking ink limit into account
+
+/* return nz on fatal error */
+static int get_ssimplex_nodes(
+rspl *s,
+int sdi, /* Dimensionality of target sub-simplex */
+rvert **inodes, /* sdi input nodes that form an sdi-1 dimensional input sub-simplex */
+int aonodes, /* Number of output nodes allowed for */
+int *nonodes, /* Number of output nodes set */
+rvert **onodes /* Space for up to 3^MXDI-1 output nodes */
+) {
+ int e, di = s->di;
+ int i, j, k;
+
+ *nonodes = 0;
+
+//printf("\n~1 get_ssimplex_nodes called with sdi = %d\n",sdi);
+ /* Sort the input nodes into normal sub-simplex order */
+ /* (We are assuming all the nodes are in the grid) */
+ for (i = 0; i < sdi-1; i++) {
+ for (j = i+1; j < sdi; j++) {
+ if (inodes[i]->gix < inodes[j]->gix) {
+ rvert *tt;
+ tt = inodes[i]; inodes[i] = inodes[j]; inodes[j] = tt;
+ }
+ }
+ }
+//printf("~2 input nodes = %d %d\n", inodes[0]-gix, inodes[1]->gix);
+
+ /* For each sub-simplex */
+ for (i = 0; i < s->gam.ssi[sdi].nospx; i++) {
+ int kk;
+//printf("~1 sub simplex %d\n",i);
+ /* For leaving out one node of the ssimplex in turn, */
+ /* check the inodes match the remaining ssimplex nodes */
+ for (kk = 0; kk <= sdi; kk++) { /* ssimplex node being left out */
+ int bix = 0; /* ssimplex base node */
+
+ if (kk == 0)
+ bix++;
+
+//printf("~1 anchor node %d = %d\n",j,s->gam.ssi[sdi].spxi[i].goffs[bix]);
+//printf("~2 candidate node offsets = %d %d %d\n",
+//s->gam.ssi[sdi].spxi[i].offs[0],
+//s->gam.ssi[sdi].spxi[i].offs[1],
+//s->gam.ssi[sdi].spxi[i].offs[2]);
+
+ for (j = k = 0; j < sdi; j++, k++) { /* Check all inodes[] */
+ if (k == kk)
+ k++; /* Skip the ssimplex node being left out */
+ if (inodes[j]->gix != (inodes[0]->gix + s->gam.ssi[sdi].spxi[i].goffs[k]
+ - s->gam.ssi[sdi].spxi[i].goffs[bix])) {
+//printf("~1 not a match\n");
+ break;
+ }
+//printf("~1 matched node %d\n",inodes[k]->gix);
+ }
+ if (j >= sdi) { /* they all match */
+//printf("~1 all match\n");
+ /* Check if kk offset to the base is still in the grid */
+ for (e = 0; e < di; e++) {
+ int doff = ((s->gam.ssi[sdi].spxi[i].offs[kk] >> e) & 1)
+ - ((s->gam.ssi[sdi].spxi[i].offs[bix] >> e) & 1);
+ int eflags = G_FL(inodes[0]->fg,e);
+//printf("~1 checking dim %d, doff = %d, eflags = %d\n",e,doff,eflags);
+ if ((doff < 0 && (eflags & 4) && (eflags & 3) < 1)
+ || (doff > 0 && !(eflags & 4) && (eflags & 3) < 1)) {
+//printf("~1 outside grid\n");
+ break; /* Offset will take us past edge */
+ }
+ }
+ if (e >= di) { /* Remaining point is within grid */
+ int gix;
+
+ /* Add the remaining node to the onodes */
+ if (*nonodes >= aonodes)
+ return 1; /* Oops - ran out of return space! */
+
+ gix = inodes[0]->gix + s->gam.ssi[sdi].spxi[i].goffs[kk]
+ - s->gam.ssi[sdi].spxi[i].goffs[bix];
+ onodes[*nonodes] = get_vert(s, gix);
+
+//printf("~1 Returning node %d\n",(onodes[*nonodes]->gix);
+//printf("~1 Value %f %f %f\n", onodes[*nonodes]->p[0], onodes[*nonodes]->p[1], onodes[*nonodes]->p[2]);
+ (*nonodes)++;
+ }
+ }
+ }
+ }
+//printf("~1 onodes = %d\n",*nonodes);
+ return 0;
+}
+
+/* ====================================================== */
+/* Search for an existing vertex, and return it. */
+/* If there is no existing edge, create it. */
+/* (This is where we apply the output functions to the grid values) */
+static rvert *get_vert(rspl *s, int gix) {
+ int f, fdi = s->fdi;
+ int hash;
+ rvert *vp = NULL;
+
+ if (gix < 0 || gix >= s->g.no) { /* Assert */
+ error("rspl_gam: get_vert got out of range gix %d\n",gix);
+ }
+
+ /* See if it is in our hash list */
+ hash = gix % s->gam.vhsize;
+
+ for (vp = s->gam.verts[hash]; vp != NULL; vp = vp->next) {
+ if (vp->gix == gix)
+ break;
+ }
+ if (vp == NULL) { /* No such vertex */
+ float *fg;
+
+ if ((vp = calloc(1, sizeof(rvert))) == NULL)
+ error("rspl_gam: get_vert calloc failed");
+
+ fg = s->g.a + gix * s->g.pss;
+ vp->n = s->gam.rvert_no++; /* serial number */
+ vp->fg = fg; /* Pointer to node float data */
+ vp->gix = gix; /* grid index */
+ for (f = 0; f < fdi; f++) /* Node output value */
+ vp->v[f] = (double)fg[f];
+ if (s->gam.outf != NULL)
+ s->gam.outf(s->gam.cntxf, vp->v, vp->v); /* Apply output lookup */
+
+ radcoord(s, vp->r, vp->v); /* Compute radial coordinate */
+
+ /* Add vertex to hash */
+ vp->next = s->gam.verts[hash];
+ s->gam.verts[hash] = vp;
+
+ /* Add the vertex to the bottom of the list of vertex */
+ if (s->gam.vbot == NULL) {
+ s->gam.vtop = s->gam.vbot = vp;
+ } else {
+ s->gam.vbot->list = vp;
+ s->gam.vbot = vp;
+ }
+ }
+
+ return vp;
+}
+
+/* Search for an existing edge containing the given verticies, */
+/* and return it. If there is no existing edge, create it. */
+/* Note that edges have fdi-2 dimensions == fdi-1 verticies. */
+static redge *get_edge(rspl *s, rvert **_vv) {
+ int i, j, f, fdi = s->fdi;
+ rvert *vv[MXDO-1]; /* Sorted verticies */
+ int gix, hash;
+ redge *ep = NULL;
+
+ /* Sort the input nodes into normal sub-simplex order */
+ /* (We are assuming all the nodes are in the grid) */
+ for (i = 0; i < (fdi-1); i++)
+ vv[i] = _vv[i];
+ for (i = 0; i < (fdi-2); i++) {
+ for (j = i+1; j < (fdi-1); j++) {
+ if (vv[i]->gix < vv[j]->gix) {
+ rvert *tt;
+ tt = vv[i]; vv[i] = vv[j]; vv[j] = tt;
+ }
+ }
+ }
+ for (gix = i = 0; i < (fdi-1); i++)
+ gix += vv[i]->gix;
+//printf("~1 get edge with nodes = %d %d\n", vv[0]->gix, vv[1]->gix);
+
+ /* See if it is in our hash list */
+ hash = gix % s->gam.ehsize;
+//printf("~1 get edge gix = %d, hash = %d\n", gix, hash);
+
+ for (ep = s->gam.edges[hash]; ep != NULL; ep = ep->next) {
+ for (i = 0; i < (fdi-1); i++) {
+ if (ep->v[i] != vv[i]) {
+//printf("~1 verticies don't match\n");
+ break; /* No match */
+ }
+ }
+ if (i >= (fdi-1)) {
+//printf("~1 all verticies match\n");
+ break; /* All match */
+ }
+ }
+ if (ep == NULL) { /* No such edge */
+ int sm, lg;
+
+ if ((ep = calloc(1, sizeof(redge))) == NULL)
+ error("rspl_gam: get_edge calloc failed");
+
+ ep->n = s->gam.redge_no++; /* serial number */
+ for (i = 0; i < (fdi-1); i++)
+ ep->v[i] = vv[i]; /* Vertex */
+printf("~1 new edge %d with nodes = %d %d\n", ep->n, ep->v[0]->gix, ep->v[1]->gix);
+
+ /* Compute plane equation to center of gamut, so */
+ /* that we can quickly determine which side a triangle lies on. */
+
+ /* Compute plane equation */
+ if (fdi < 2 || fdi > 3)
+ error("rspl_gam: plane equation for out dimensions other than 2 or 3 not supported!");
+ if (fdi == 2) {
+
+ } else {
+ double v1[3], v2[3];
+
+ /* Compute two vectors from the three points */
+ for (f = 0; f < fdi; f++) {
+ v1[f] = ep->v[0]->v[f] - s->gam.cent[f];
+ v2[f] = ep->v[1]->v[f] - s->gam.cent[f];
+ }
+
+ /* Compute normal to the plane using the cross product */
+ ep->pe[0] = ep->v[0]->v[1] * (ep->v[1]->v[2] - s->gam.cent[2])
+ + ep->v[1]->v[1] * (s->gam.cent[2] - ep->v[0]->v[2])
+ + s->gam.cent[1] * (ep->v[0]->v[2] - ep->v[1]->v[2]);
+ ep->pe[1] = ep->v[0]->v[2] * (ep->v[1]->v[0] - s->gam.cent[0])
+ + ep->v[1]->v[2] * (s->gam.cent[0] - ep->v[0]->v[0])
+ + s->gam.cent[2] * (ep->v[0]->v[0] - ep->v[1]->v[0]);
+ ep->pe[2] = ep->v[0]->v[0] * (ep->v[1]->v[1] - s->gam.cent[1])
+ + ep->v[1]->v[0] * (s->gam.cent[1] - ep->v[0]->v[1])
+ + s->gam.cent[0] * (ep->v[0]->v[1] - ep->v[1]->v[1]);
+ ep->pe[3] = - (ep->v[0]->v[0] * (ep->v[1]->v[1] * s->gam.cent[2] - s->gam.cent[1] * ep->v[1]->v[2])
+ + ep->v[1]->v[0] * (s->gam.cent[1] * ep->v[0]->v[2] - ep->v[0]->v[1] * s->gam.cent[2])
+ + s->gam.cent[0] * (ep->v[0]->v[1] * ep->v[1]->v[2] - ep->v[1]->v[1] * ep->v[0]->v[2]));
+
+ }
+
+ /* Add edge to hash */
+ ep->next = s->gam.edges[hash];
+ s->gam.edges[hash] = ep;
+
+ /* Add the edge to the bottom of the list of edges */
+ if (s->gam.ebot == NULL) {
+ s->gam.etop = s->gam.ebot = ep;
+ } else {
+ s->gam.ebot->list = ep;
+ s->gam.ebot = ep;
+ }
+ }
+
+printf("~1 returning edge no %d\n",ep->n);
+ return ep;
+}
+
+/* Check whether a triangle like this already exists */
+/* Return NULL if it doesn't */
+static rtri *check_tri(rspl *s, redge *ep, rvert *_vv) {
+ int i, j, k, f, fdi = s->fdi;
+ rvert *vv[MXDO]; /* Sorted verticies */
+ int gix, hash;
+ rtri *tp = NULL;
+
+ /* Copy edge verticies from edge */
+ for (i = 0; i < (fdi-1); i++)
+ vv[i] = ep->v[i];
+ vv[i] = _vv; /* And new vertex */
+
+ /* Sort verticies */
+ for (i = 0; i < (fdi-1); i++) {
+ for (j = i+1; j < fdi; j++) {
+ if (vv[i]->gix < vv[j]->gix) {
+ rvert *tv;
+ tv = vv[i]; vv[i] = vv[j]; vv[j] = tv;
+ }
+ }
+ }
+
+ /* Create hash */
+ for (gix = i = 0; i < fdi; i++)
+ gix += vv[i]->gix;
+
+ /* See if it is in our hash list */
+ hash = gix % s->gam.thsize;
+//printf("~1 make tri gix = %d, hash = %d\n", gix, hash);
+
+ for (tp = s->gam.tris[hash]; tp != NULL; tp = tp->next) {
+ for (i = 0; i < fdi; i++) {
+ if (tp->v[i] != vv[i]) {
+//printf("~1 verticies don't match\n");
+ break; /* No match */
+ }
+ }
+ if (i >= fdi) {
+//printf("~1 all verticies match\n");
+ break; /* All match */
+ }
+ }
+
+ return tp;
+}
+
+/* Create a triangle given an edge with fdi-1 verticies and a grid vertex. */
+/* if inv is set, triangle is upside down wrt to center point, */
+/* and so all the oppositive verticies should be placed on the */
+/* opposite to their natural side. */
+static rtri *make_tri(rspl *s, redge *ep, rvert *_vv, int inv) {
+ int i, j, k, f, fdi = s->fdi;
+ rvert *vv[MXDO]; /* Sorted verticies */
+ int gix, hash;
+ rtri *tp = NULL;
+
+printf("~1 make_tri called\n");
+
+ /* Copy edge verticies from edge */
+ for (i = 0; i < (fdi-1); i++)
+ vv[i] = ep->v[i];
+ vv[i] = _vv; /* And new vertex */
+
+ /* Sort verticies */
+ for (i = 0; i < (fdi-1); i++) {
+ for (j = i+1; j < fdi; j++) {
+ if (vv[i]->gix < vv[j]->gix) {
+ rvert *tv;
+ tv = vv[i]; vv[i] = vv[j]; vv[j] = tv;
+ }
+ }
+ }
+
+ /* Create hash */
+ for (gix = i = 0; i < fdi; i++)
+ gix += vv[i]->gix;
+
+ /* See if it is in our hash list */
+ hash = gix % s->gam.thsize;
+printf("~1 make tri gix = %d, hash = %d\n", gix, hash);
+
+ for (tp = s->gam.tris[hash]; tp != NULL; tp = tp->next) {
+ for (i = 0; i < fdi; i++) {
+ if (tp->v[i] != vv[i]) {
+//printf("~1 verticies don't match\n");
+ break; /* No match */
+ }
+ }
+ if (i >= fdi) {
+//printf("~1 all verticies match\n");
+ break; /* All match */
+ }
+ }
+
+ if (tp == NULL) { /* No such triangle */
+
+//printf("~1 creating a new triangle\n");
+ /* Create triangle */
+ if ((tp = calloc(1, sizeof(rtri))) == NULL)
+ error("rspl_gam: make_tri calloc failed");
+
+ tp->n = s->gam.rtri_no++; /* serial number */
+
+ /* Copy edge verticies to triangle */
+ for (i = 0; i < fdi; i++)
+ tp->v[i] = vv[i];
+
+ /* Link all the triangles edges to this triangle */
+ printf("~1 triangle nodes = %d %d %d\n", tp->v[0]->gix, tp->v[1]->gix, tp->v[2]->gix);
+//printf("~2 triangle vert 0 = %f %f %f\n", tp->v[0]->v[0], tp->f[0]->v[1], tp->f[0]->v[2]);
+//printf("~2 triangle vert 1 = %f %f %f\n", tp->v[1]->v[0], tp->f[1]->v[1], tp->f[1]->v[2]);
+//printf("~2 triangle vert 2 = %f %f %f\n", tp->v[2]->v[0], tp->f[2]->v[1], tp->f[2]->v[2]);
+ for (i = 0; i < fdi; i++) { /* For each tri verticy being odd one out */
+ rvert *ov, *rr[MXDO-1]; /* Odd verticy, remaining edge verticies */
+ int ss; /* Side */
+
+ ov = tp->v[i]; /* Odd node */
+ for (k = j = 0; j < fdi; j++) {
+ if (i == j)
+ continue;
+ rr[k++] = tp->v[j]; /* Remaining nodes */
+ }
+//printf("~1 edge nodes = %d %d, odd = %d\n", rr[0]->gix, rr[1]->gix, ov->gix);
+ ep = get_edge(s, rr);
+
+ if (ep->nt >= MXNE)
+ error("rspl_gam: make_tri run out of triangle space %d in edge",MXNE);
+ ep->t[ep->nt++] = tp;
+
+ /* See which side of the edge the remaining vertex is */
+ ss = eside(s, ep, ov->v);
+//printf("~1 node gix %d has side %d to edge %d %d\n", ov->gix, ss, ep->v[0]->gix, ep->v[1]->gix);
+ if (inv)
+ ss = 1-ss;
+ if (ss) { /* +ve side */
+ ep->t[ep->npt++] = tp;
+ } else {
+ ep->t[ep->nnt++] = tp;
+ }
+ }
+
+ /* Add triangle to hash */
+ tp->next = s->gam.tris[hash];
+ s->gam.tris[hash] = tp;
+
+ /* Add them to the linked list */
+ tp->list = s->gam.ttop;
+ s->gam.ttop = tp;
+
+ }
+
+ return tp;
+}
+
+
+/* ====================================================== */
+
+/* Create a surface gamut representation. */
+/* Return NZ on error */
+/* Could add more flexibility with:
+ optional function instead of default radial distance function
+ option use sub set of output dimensions (ie allow for CMYK->LabK etc. ? )
+*/
+static int
+gam_comp_gamut(
+rspl *s,
+double *cent, /* Optional center of gamut [fdi], default center of out range */
+double *scale, /* Optional Scale of output values in vector to center [fdi], def. 1.0 */
+void (*outf)(void *cntxf, double *out, double *in), /* Optional rspl val -> output value */
+void *cntxf, /* Context for function */
+void (*outb)(void *cntxb, double *out, double *in), /* Optional output value -> rspl val */
+void *cntxb /* Context for function */
+) {
+ int e, f, di = s->di, fdi = s->fdi;
+ int i, j, ssdi;
+ int maxp[MXDO]; /* Grid indexes of maxium function values */
+ rvert *fedge[MXDO-1]; /* The first "edge" containing fdi-1 verticies */
+ rvert *onodes[50]; /* float pointers of canditate nodes */
+ int aonodes = 50; /* Allocated out nodes */
+ int nonodes; /* Number of nodes returned */
+
+ rvert *cnodes[2][50]; /* Negative, positive candidate nodes */
+ double rcnodes[2][50]; /* Radius of negative, positive candidate nodes */
+ int ncnodes[2]; /* Number of negative, positive candidate nodes */
+
+ if (fdi < 2 || fdi > di) {
+ DBG(("gam: gam_comp_gamut called for di = %d, fdi = %d\n", di, fdi));
+ return 2;
+ }
+
+ /* Save output value conversion functions */
+ s->gam.outf = outf;
+ s->gam.cntxf = cntxf;
+ s->gam.outb = outb;
+ s->gam.cntxb = cntxb;
+
+ /* Deal with gamut center point, and scale */
+ if (cent == NULL) {
+ double min[MXDO], max[MXDO];
+
+ s->get_out_range(s, min, max);
+ if (s->gam.outf != NULL) {
+ s->gam.outf(s->gam.cntxf, min, min); /* Apply output lookup */
+ s->gam.outf(s->gam.cntxf, max, max); /* Apply output lookup */
+ }
+ for (f = 0; f < fdi; f++)
+ s->gam.cent[f] = 0.5 * (min[f] + max[f]);
+ } else {
+ for (f = 0; f < fdi; f++)
+ s->gam.cent[f] = cent[f];
+ }
+ DBGVI("Gamut center is ", fdi, "%f ", s->gam.cent, "\n")
+
+ if (scale == NULL) {
+ for (f = 0; f < fdi; f++)
+ s->gam.scale[f] = 1.0;
+ } else {
+ for (f = 0; f < fdi; f++)
+ s->gam.scale[f] = scale[f];
+ }
+ DBGVI("Gamut scale is ", fdi, "%f ", s->gam.scale, "\n")
+
+ for (ssdi = 1; ssdi <= fdi-1; ssdi++) {
+ int i, j;
+
+ /* Compute gamut surface sub-simplex geometry info */
+ rspl_init_ssimplex_info(s, &s->gam.ssi[ssdi], ssdi);
+
+ /* Filter the sub-simplex geometry to only include subsimplexes that */
+ /* use the base vertex, so that there are no duplicates. */
+ for (i = j = 0; i < s->gam.ssi[ssdi].nospx; i++) {
+ if (s->gam.ssi[ssdi].spxi[i].offs[s->gam.ssi[ssdi].sdi] == 0) {
+ s->gam.ssi[ssdi].spxi[j] = s->gam.ssi[ssdi].spxi[i]; /* Structure copy */
+ j++;
+ }
+ }
+ s->gam.ssi[ssdi].nospx = j;
+
+#ifdef DEBUG
+ printf("Sub-simplex dim %d out of input %d\n",s->gam.ssi[ssdi].sdi,di);
+ printf("Number of subsimplex = %d\n",s->gam.ssi[ssdi].nospx);
+ for (i = 0; i < s->gam.ssi[ssdi].nospx; i++) {
+ printf("Cube Offset = ");
+ for (e = 0; e <= s->gam.ssi[ssdi].sdi; e++)
+ printf("%d ",s->gam.ssi[ssdi].spxi[i].offs[e]);
+ printf("\n");
+
+ printf("Grid Offset = ");
+ for (e = 0; e <= s->gam.ssi[ssdi].sdi; e++)
+ printf("%d ",s->gam.ssi[ssdi].spxi[i].foffs[e]);
+ printf("\n");
+ printf("\n");
+ }
+#endif /* DEBUG */
+ }
+
+ /* Allocate the vertex hash array */
+ if ((s->gam.verts = calloc(VHASHSIZE, sizeof(rvert *))) == NULL) {
+ DBG(("gam: allocating vertex hash array failed\n"));
+ return 1;
+ }
+ s->gam.vhsize = VHASHSIZE;
+
+ /* Allocate the edge hash array */
+ if ((s->gam.edges = calloc(EHASHSIZE, sizeof(redge *))) == NULL) {
+ DBG(("gam: allocating edge hash array failed\n"));
+ return 1;
+ }
+ s->gam.ehsize = EHASHSIZE;
+
+ /* Allocate the triangle hash array */
+ if ((s->gam.tris = calloc(THASHSIZE, sizeof(rtri *))) == NULL) {
+ DBG(("gam: allocating tris hash array failed\n"));
+ return 1;
+ }
+ s->gam.thsize = THASHSIZE;
+
+ /* Get a starting gid point for surface */
+ // ~~99 this isn't right if the point we get is over the ink limit!!!. */
+ s->get_out_range_points(s, NULL, maxp); /* Maximum */
+// s->get_out_range_points(s, maxp, NULL); /* Minium */
+
+ DBG(("Starting point = gix %d/%d\n",maxp[0], s->g.no));
+
+ /* Now work it up to an fdi-2 sub-simplex, so that we have a */
+ /* "triangle edge", and can enter the main loop. */
+ // ~~~9 this needs fixing to switch to "maximum angle" calculation
+ fedge[0] = get_vert(s, maxp[0]); /* grid index of first vertex */
+
+ if (fdi == 2) {
+ /* We just need one point, and we've got it */
+
+ } else if (fdi == 3) { /* Usual case */
+ double ba = -1.0; /* Bigest angle */
+ /* We just need two points, so find the other points */
+ /* that makes the greatest angle to the center */
+
+ if (get_ssimplex_nodes(s, 1, fedge, aonodes, &nonodes, onodes)) {
+ error("rspl_gam: get_ssimplex_nodes fatal error - too many nodes?");
+ }
+ if (nonodes == 0)
+ error("rspl_gam: get_ssimplex_nodes fatal error - retrurned no nodes?");
+
+printf("~1 get_ssimplex_nodes returned %d nodes\n",nonodes);
+for(i = 0; i < nonodes; i++)
+printf(" ~1 %d: %d\n",i,onodes[i]->gix);
+
+ /* Evaluate the choice of verticies to choose the one that */
+ /* will best enclose the gamut. (We use a really dumb criteria - maximum radius) */
+ for (i = 0; i < nonodes; i++) {
+ double tt, a, b, c; /* Lenght of sides of triangle squared */
+ a = norm33sq(onodes[i]->v, s->gam.cent);
+ b = norm33sq(onodes[i]->v, fedge[0]->v);
+ c = norm33sq(fedge[0]->v, s->gam.cent);
+ tt = acos((b + c - a)/(2.0 * sqrt(b * c)));
+printf("~1 node %d angle = %f\n",onodes[i]->gix,tt);
+ if (tt > ba) {
+ ba = tt;
+ fedge[1] = onodes[i]; /* Use candidate with largest gamut as next base */
+ }
+ }
+printf("~1 chosen node %d\n",fedge[1]->gix);
+
+ } else if (fdi > 3) { /* General case */
+ /* This isn't a correct approach ... */
+
+ for (ssdi = 1; ssdi <= fdi-2; ssdi++) {
+ double br = -1.0; /* Bigest radius */
+
+ DBG(("Working up ssdim %d -> %d\n",ssdi-1, ssdi));
+
+ if (get_ssimplex_nodes(s, ssdi, fedge, aonodes, &nonodes, onodes)) {
+ error("rspl_gam: get_ssimplex_nodes fatal error - too many nodes?");
+ }
+ if (nonodes == 0)
+ error("rspl_gam: get_ssimplex_nodes fatal error - retrurned no nodes?");
+
+printf("~1 get_ssimplex_nodes returned %d nodes\n",nonodes);
+for(i = 0; i < nonodes; i++)
+printf(" ~1 %d: %d\n",i,onodes[i]->gix);
+
+ /* Evaluate the choice of verticies to choose the one that */
+ /* will best enclose the gamut. (We use a really dumb criteria - maximum radius) */
+ for (i = 0; i < nonodes; i++) {
+ double tt;
+ tt = gvprad(s, onodes[i]->v); /* Compute radius */
+ if (tt > br) {
+ br = tt;
+ fedge[ssdi] = onodes[i]; /* Use candidate with largest gamut as next base */
+ }
+ }
+printf("~1 chosen node %d\n",fedge[ssdi]->gix);
+ }
+ }
+
+ /* Creat the initial "edge" */
+ get_edge(s, fedge);
+
+printf("~1 Created initial edge\n");
+
+ {
+ redge *ep;
+
+ double **A; /* lu value -> baricentric matrix */
+ double *B;
+ int *pivx;
+
+ pivx = ivector(0, fdi-1); /* pixv[fdi] */
+ A = dmatrix(0, fdi-1, 0, fdi-1); /* A[fdi][fdi] */
+ B = dvector(0, fdi-1); /* B[fdi] */
+
+ /* The main loop: */
+ /* We start with any "edges" that have less than two associated "triangles", */
+ /* and evaluate the vertex nodes that can make "triangles" with the "edge". */
+ /* We choose the node that will give the greatest slope, and make a "triangle". */
+ /* Loop until there are no "edges" with less than two associated "triangles". */
+ for (ep = s->gam.etop; ep != NULL; ep = ep->list) {
+
+printf("~1 expanding from edge no %d\n",ep->n);
+printf("~1 edge v1 = %d = %f %f %f\n", ep->v[0]->gix, ep->v[0]->v[0], ep->v[0]->v[1], ep->v[0]->v[2]);
+printf("~1 edge v2 = %d = %f %f %f\n", ep->v[1]->gix, ep->v[1]->v[0], ep->v[1]->v[1], ep->v[1]->v[2]);
+
+// if (ep->npt < 1 || ep->nnt < 1)
+ {
+ int ss;
+
+ if (get_ssimplex_nodes(s, fdi-1, ep->v, aonodes, &nonodes, onodes)) {
+ error("rspl_gam: get_ssimplex_nodes fatal error - too many nodes?");
+ }
+
+ /* Clasify the returned nodes as positive or negative side */
+ ncnodes[0] = ncnodes[1] = 0;
+ for (i = 0; i < nonodes; i++) {
+ double tt;
+ tt = gvprad(s, onodes[i]->v); /* Compute radius */
+ ss = eside(s, ep, onodes[i]->v); /* Side */
+printf("~1 node gix %d has rad %f side %d to edge %d %d\n", onodes[i]->gix, tt, ss, ep->v[0]->gix, ep->v[1]->gix);
+
+#ifdef NEVER /* This messes things up ? */
+ /* Check if this node is already in a triangle with this edge, */
+ /* to avoid costly matrix solution check below. */
+ if (check_tri(s, ep, onodes[i]) == NULL)
+#endif
+ {
+ cnodes[ss][ncnodes[ss]] = onodes[i];
+ rcnodes[ss][ncnodes[ss]++] = tt;
+ }
+ }
+
+ /* Sort them */
+ for (ss = 0; ss < 2; ss++) { /* Negative side then positive */
+ for (i = 0; i < (ncnodes[ss]-1); i++) {
+ for (j = i+1; j < ncnodes[ss]; j++) {
+ if (rcnodes[ss][i] < rcnodes[ss][j]) {
+ rvert *tt;
+ double tr;
+ tt = cnodes[ss][i]; cnodes[ss][i] = cnodes[ss][j];
+ cnodes[ss][j] = tt;
+ tr = rcnodes[ss][i]; rcnodes[ss][i] = rcnodes[ss][j];
+ rcnodes[ss][j] = tr;
+ }
+ }
+ }
+ }
+
+// ~~1
+for (ss = 0; ss < 2; ss++) { /* Negative side then positive */
+ if (ss == 0)
+ printf("~1 -ve nodes:\n");
+ else
+ printf("~1 +ve nodes:\n");
+ for (i = 0; i < ncnodes[ss]; i++) {
+ printf("~1 node %d, rad %f\n",cnodes[ss][i]->gix,rcnodes[ss][i]);
+ }
+}
+
+#ifdef VRML_TRACE
+{
+ vrml *wrl;
+ int i, j, k;
+ ECOUNT(gc, MXDIDO, di, 0, s->g.res, 0);/* coordinates */
+ DCOUNT(cc, MXDIDO, s->di, 0, 0, 2); /* Surrounding cube counter */
+ float *gp; /* Grid point pointer */
+ rvert *vp;
+ rtri *tp;
+ double col[3], pos[3];
+
+ if ((wrl = new_vrml("gam_diag.wrl", 1)) == NULL)
+ error("new_vrml failed\n");
+
+ /* Display the grid */
+ EC_INIT(gc);
+ for (gp = s->g.a; !EC_DONE(gc); gp += s->g.pss) {
+ /* Itterate cube from this base */
+ DC_INIT(cc)
+ for (i = 0; !DC_DONE(cc); i++ ) {
+ float *sp = s->g.a;
+
+ for (e = 0; e < s->di; e++) { /* Input tables */
+ int j;
+ j = gc[e] + cc[e];
+ if (j < 0 || j >= s->g.res[e]) {
+ sp = NULL; /* outside grid */
+ break;
+ }
+ sp += s->g.fci[e] * j; /* Compute pointer to surrounder */
+ }
+ if (i> 0 && e >= s->di) {
+ /* Create vector from base to surrounder */
+ pos[0] = (double)gp[0];
+ pos[1] = (double)gp[1];
+ pos[2] = (double)gp[2];
+ if (s->gam.outf != NULL)
+ s->gam.outf(s->gam.cntxf, pos, pos); /* Apply output lookup */
+ wrl->add_vertex(wrl, pos);
+ pos[0] = (double)sp[0];
+ pos[1] = (double)sp[1];
+ pos[2] = (double)sp[2];
+ if (s->gam.outf != NULL)
+ s->gam.outf(s->gam.cntxf, pos, pos); /* Apply output lookup */
+ wrl->add_vertex(wrl, pos);
+ }
+ DC_INC(cc);
+ }
+ EC_INC(gc);
+ }
+ wrl->make_lines(wrl, 2);
+ wrl->clear(wrl);
+
+ /* Display the current triangles transparently */
+ if (s->gam.ttop != NULL) {
+ for (vp = s->gam.vtop; vp != NULL; vp = vp->list) {
+ wrl->add_vertex(wrl, vp->v);
+ }
+
+ /* Set the triangles */
+ for (tp = s->gam.ttop; tp != NULL; tp = tp->list) {
+ int ix[3];
+ ix[0] = tp->v[0]->n;
+ ix[1] = tp->v[1]->n;
+ ix[2] = tp->v[2]->n;
+ wrl->add_triangle(wrl, ix);
+ }
+
+// wrl->make_triangles(wrl, 0.3, NULL);
+ wrl->make_triangles(wrl, 0.0, NULL);
+ wrl->clear(wrl);
+ }
+
+ /* Show the active edge as a red cone */
+ col[0] = 1.0; col[1] = 0.0; col[2] = 0.0; /* Red */
+ wrl->add_cone(wrl, ep->v[0]->v, ep->v[1]->v, col, 1.0);
+printf("~1 edge v1 = %d = %f %f %f\n", ep->v[0]->gix, ep->v[0]->v[0], ep->v[0]->v[1], ep->v[0]->v[2]);
+printf("~1 edge v2 = %d = %f %f %f\n", ep->v[1]->gix, ep->v[1]->v[0], ep->v[1]->v[1], ep->v[1]->v[2]);
+
+ /* Show the candidate verticies */
+ for (ss = 0; ss < 2; ss++) {
+ for (i = 0; i < ncnodes[ss]; i++) { /* +ve */
+ if (ss) {
+ col[0] = 0.0; col[1] = 1.0; col[2] = 0.0; /* Green +ve */
+ } else {
+ col[0] = 0.0; col[1] = 0.0; col[2] = 1.0; /* Blue -ve */
+ }
+ wrl->add_marker(wrl, cnodes[ss][i]->v, col, 1.0);
+ }
+ }
+ wrl->del(wrl);
+ getchar();
+}
+#endif
+ /* See if we can make a triangle */
+ for (ss = 0; ss < 2; ss++) { /* For -ve and +ve sides */
+ int ii, si;
+ int sta, end, inc;
+ rvert **nods;
+ double rip; /* Row interchange parity */
+
+printf("~1 direction = %d\n",ss);
+#ifdef NEVER
+ if (( ss && ep->npt >= 1) /* Not looking for a positive node */
+ || (!ss && ep->nnt >= 1)) { /* Not looking for a negative node */
+printf("~1 no need to look for node in this direction\n");
+ continue;
+ }
+#endif
+
+ if (ncnodes[ss] > 0) { /* There are nodes in wanted direction */
+ si = ss; /* use wanted direction nodes */
+ sta = 0; /* Start at max radius node */
+ end = ncnodes[si]; /* End and least radius node */
+ inc = 1; /* Increment */
+ nods = cnodes[si]; /* +ve nodes */
+printf("~1 Looking for biggest angle, inc = %d\n",inc);
+#ifdef NEVER /* Convex tracing ? */
+ } else if (ncnodes[1-ss] > 0) { /* There are opposited direction nodes */
+ si = 1-ss; /* use opposite direction nodes */
+ sta = ncnodes[si]-1; /* Start at min radius node */
+ end = -1; /* end and max radius node */
+ inc = -1; /* Decrement */
+ nods = cnodes[si];
+printf("~1 Looking for smallest angle, inc = %d\n",-1);
+#endif /* NEVER */
+ } else {
+printf("~1 No points to search\n");
+ continue;
+ }
+ ii = 0;
+ if (ncnodes[si] > 1) { /* If there is more than one to choose from */
+ /* Go through each candidate in the most likely order */
+ for (ii = sta; ii != end; ii += inc) {
+
+printf("~1 Candidate %d: node %d\n",ii,nods[ii]->gix);
+ /* Create the baricentric conversion for this candidate */
+ for (f = 0; f < fdi; f++) /* The center point */
+ A[f][0] = s->gam.cent[f] - nods[ii]->v[f];
+ for (j = 0; j < (fdi-1); j++) { /* The edge points */
+ for (f = 0; f < fdi; f++)
+ A[f][j+1] = ep->v[j]->v[f] - nods[ii]->v[f];
+ }
+
+ if (lu_decomp(A, fdi, pivx, &rip)) {
+printf("~1 lu_decomp failed\n");
+for (f = 0; f < fdi; f++) /* The center point */
+ A[f][0] = s->gam.cent[f] - nods[ii]->v[f];
+for (j = 0; j < (fdi-1); j++) { /* The edge points */
+ for (f = 0; f < fdi; f++)
+ A[f][j+1] = ep->v[j]->v[f] - nods[ii]->v[f];
+}
+printf("~1 A = \n");
+printf("~1 %f %f %f\n", A[0][0], A[0][1], A[0][2]);
+printf("~1 %f %f %f\n", A[1][0], A[1][1], A[1][2]);
+printf("~1 %f %f %f\n", A[2][0], A[2][1], A[2][2]);
+ warning("lu_decomp failed");
+ continue;
+ }
+
+ /* Test the remainder candidates against this simplex */
+ for (i = sta; i != end; i += inc) {
+ if (i == ii)
+ continue;
+
+printf("~1 Test %d: node %d\n",i,nods[i]->gix);
+ for (f = 0; f < fdi; f++) /* The candidate point */
+ B[f] = nods[i]->v[f] - nods[ii]->v[f];
+ lu_backsub(A, fdi, pivx, B);
+
+#ifdef NEVER
+printf("~1 baricentric = %f %f %f %f\n",B[0],B[1],B[2],1.0-B[0]-B[1]-B[2]);
+{
+double tt[3], B3;
+/* Check baricentric */
+B3 = 1.0-B[0]-B[1]-B[2];
+for (f = 0; f < fdi; f++)
+ tt[f] = 0.0;
+for (f = 0; f < fdi; f++)
+ tt[f] += B[0] * s->gam.cent[f];
+for (f = 0; f < fdi; f++)
+ tt[f] += B[1] * ep->v[0]->v[f];
+for (f = 0; f < fdi; f++)
+ tt[f] += B[2] * ep->v[1]->v[f];
+for (f = 0; f < fdi; f++)
+ tt[f] += B3 * nods[ii]->v[f];
+printf("~1 target point %f %f %f\n", (double)nods[i][0], (double)nods[i][1], (double)nods[i][2]);
+printf("~1 barice check %f %f %f\n", tt[0],tt[1],tt[2]);
+}
+#endif /* NEVER */
+ if ((inc == 1 && B[0] < -EPS) /* other point is at higher angle */
+ || (inc == -1 && B[0] > EPS)) { /* other point is at lower angle */
+printf("~1 candidate isn't best\n");
+ break;
+ }
+ }
+ if (i == end) {
+printf("~1 candidate IS the best\n");
+ break; /* Candidate is at highest angle */
+ }
+ }
+ if (ii == end) {
+printf("~1Inconsistent candidate ordering\n");
+ error("Inconsistent candidate ordering");
+ }
+ } else {
+printf("~1 there are only %d nodes, so don't search them\n",ncnodes[si]);
+ }
+printf("~1 Making triangle with %d: node %d\n",ii,nods[ii]->gix);
+ make_tri(s, ep, nods[ii], inc == -1);
+ }
+ if (ep->npt < 1 || ep->nnt < 1) {
+ if (ep->npt < 1)
+ warning("###### Unable to locate +ve triangles for edge %d\n",ep->n);
+ if (ep->nnt < 1)
+ warning("###### Unable to locate -ve triangles for edge %d\n",ep->n);
+ }
+ }
+ }
+
+ free_ivector(pivx, 0, fdi-1);
+ free_dmatrix(A, 0, fdi-1, 0, fdi-1);
+ free_dvector(B, 0, fdi-1);
+
+ /* Dump out the edges */
+ for (ep = s->gam.etop; ep != NULL; ep = ep->list) {
+
+printf("~1 edge no %d, npt = %d, nnt = %d\n",ep->n, ep->npt, ep->nnt);
+ }
+ }
+ return 0;
+}
+
+/* ====================================================== */
+/* Gamut rspl setup functions */
+
+/* Called by rspl initialisation */
+void
+init_gam(rspl *s) {
+
+ /* Methods */
+ s->comp_gamut = gam_comp_gamut;
+}
+
+/* Free up all the gamut info */
+void free_gam(
+rspl *s /* Pointer to rspl grid */
+) {
+ int i;
+ int ssdi;
+ rvert *vp, *nvp;
+ redge *ep, *nep;
+ rtri *tp, *ntp;
+
+ for (ssdi = 1; ssdi <= s->fdi-1; ssdi++)
+ rspl_free_ssimplex_info(s, &s->gam.ssi[ssdi]);
+
+ /* Free the verticies */
+ for (vp = s->gam.vtop; vp != NULL; vp = nvp) {
+ nvp = vp->list;
+ free(vp);
+ }
+ free(s->gam.verts);
+
+ /* Free the edges */
+ for (ep = s->gam.etop; ep != NULL; ep = nep) {
+ nep = ep->list;
+ free(ep);
+ }
+ free(s->gam.edges);
+
+ /* Free the triangles */
+ for (tp = s->gam.ttop; tp != NULL; tp = ntp) {
+ ntp = tp->list;
+ free(tp);
+ }
+ free(s->gam.tris);
+}
+
+
+/* Create the gamut surface structure. */
+/* Current this is:
+
+ not rationalized to be non-overlapping
+ culled to eliminate overlaps
+ Have ink limits applied
+
+*/
+
+/* ~~~ we need space ing gam to:
+
+ store radial coordinates of output values
+ mark nodes as being visited.
+ store surface triangle structures
+ hold tadial output bounding acceleration structures
+
+
+ There is a lot in common with rev here.
+ we need to know input channel significance (what's black)
+ plus ink limit info.
+ we're going to create black generation information used by rev.
+*/
+
+/* ---------------------- */
+/* rspl gam diagnostic */
+
+/* Diagnostic */
+void rspl_gam_plot(rspl *s, char *name) {
+ int i;
+ double col[3] = { 0.7, 0.7, 0.7 };
+ rvert *vp, *nvp;
+ rtri *tp, *ntp;
+
+ vrml *wrl;
+
+ if ((wrl = new_vrml(name, 1, 0)) == NULL)
+ error("new_vrml failed\n");
+
+ /* Set the verticies */
+ for (vp = s->gam.vtop; vp != NULL; vp = vp->list) {
+ wrl->add_vertex(wrl, 0, vp->v);
+ }
+
+ /* Set the triangles */
+ for (tp = s->gam.ttop; tp != NULL; tp = ntp) {
+ int ix[3];
+ ntp = tp->list;
+ ix[0] = tp->v[0]->n;
+ ix[1] = tp->v[1]->n;
+ ix[2] = tp->v[2]->n;
+ wrl->add_triangle(wrl, 0, ix);
+ }
+
+ wrl->make_triangles(wrl, 0, 0.0, NULL);
+// wrl->make_triangles(wrl, 0, 0.0, col);
+
+ wrl->del(wrl);
+}
+
+#undef DEBUG
+#undef DBGV
+#undef DBG
+#define DBGV(xxx)
+#define DBG(xxx)
+
+
+
+
+
+
diff --git a/rspl/gam.h b/rspl/gam.h
new file mode 100644
index 0000000..0892e4d
--- /dev/null
+++ b/rspl/gam.h
@@ -0,0 +1,131 @@
+#ifndef RSPL_GAM_H
+#define RSPL_GAM_H
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized spline data structure
+ *
+ * Precise gamut surface, gamut pruning, ink limiting and K min/max
+ * support routine.s
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/11/21
+ *
+ * Copyright 1999 - 2008 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.
+ *
+ * Latest simplex/linear equation version.
+ */
+
+/* In practice the gamut is only ever computed for 2D or 3D output */
+/* dimensions. The gamut surface is composed of simplexes ("triangles") */
+/* of dimensions fdi-1, with fdi verticies */
+
+#include "llist.h"
+
+#define MXNE 16 /* Maximum number of edges per triangle allowed */
+
+#define VHASHSIZE 6863 /* Vertex hash index size */
+#define EHASHSIZE 2659 /* Edge hash index size */
+#define THASHSIZE 2659 /* Triangle hash index size */
+
+/* ----------------------------------------- */
+
+/* Vertex node - all vertex nodes are part of the grid */
+struct _rvert {
+ struct _rvert *next; /* Hash linked list */
+ int n; /* Index number of vertex */
+ int gix; /* Grid index - used to identify and order nodes */
+ float *fg; /* Pointer to grid data */
+
+// double p[MXDO]; /* Poistion of node */
+ double v[MXDO]; /* Output value of node */
+ double r[MXDO]; /* Radial coordinates */
+ struct _rvert *list; /* Next in linked list */
+}; typedef struct _rvert rvert;
+
+/* ------------------------------------ */
+
+/* An edge shared by one or more triangle in the mesh */
+struct _redge {
+ struct _redge *next; /* Hash linked list */
+ int n; /* Serial number */
+// float *f[MXDO-1]; /* fdi-1 grid verticies of edge in base simplex order. */
+ struct _rvert *v[MXDO-1]; /* fdi-1 Verticies of edge in base simplex order. */
+ double pe[MXDO+1]; /* Plane equation for edge for side of edge testing. */
+ /* fdi for normal + constant */
+ int nt; /* Total number of triangles that share this edge */
+ int npt; /* Positive side triangles that share this edge */
+ int nnt; /* Negative side triangles that share this edge */
+ struct _rtri *t[MXNE]; /* nt triangles edge is part of */
+
+ struct _redge *list; /* Next in linked list */
+}; typedef struct _redge redge;
+
+/* ------------------------------------ */
+
+/* A "triangle" (simplex dimension fdi-1) in the surface mesh */
+struct _rtri {
+ struct _rtri *next; /* Hash linked list */
+ int n; /* Serial number */
+// float *f[MXDO]; /* fdi grid verticies in gix order */
+ struct _rvert *v[MXDO]; /* fdi verticies in gix order */
+
+// struct _redge *e[((MXDO+1) * MXDO)/2]; /* Edges in vertex sorted order */
+// double mix[2][MXDO]; /* nn: Bounding box min and max */
+
+ struct _rtri *list; /* Next in linked list */
+}; typedef struct _rtri rtri;
+
+/* ----------------------------------------- */
+/* Gamut info stored in main rspl function */
+struct _gam_struct {
+ int inited;
+
+ double cent[MXDO]; /* Center of radial distance calculation */
+ double scale[MXDO]; /* Scale of radial distance calculation */
+
+ void (*outf)(void *cntxf, double *out, double *in); /* Optional rspl val -> output value */
+ void *cntxf; /* Context for function */
+ void (*outb)(void *cntxb, double *out, double *in); /* Optional output value -> rspl val */
+ void *cntxb; /* Context for function */
+
+ ssxinfo ssi[MXDO-1]; /* Sub-simplex information for sdi from 0..fdi-1 */
+
+ int rvert_no; /* Number of rverts allocated */
+ int vhsize; /* Vertex hash list size */
+ rvert **verts; /* Hash list, NULL if not allocated */
+ rvert *vtop; /* Top of list of verticies */
+ rvert *vbot; /* Bottom of list of verticies */
+
+ int redge_no; /* Number of redges allocated */
+ int ehsize; /* Edge hash list size */
+ redge **edges; /* Edges between the triangles linked list */
+ redge *etop; /* Top of list of edges */
+ redge *ebot; /* Bottom of list of edges */
+
+ int rtri_no; /* Number of rtris allocated */
+ int thsize; /* Triangle hash list size */
+ rtri **tris; /* Hash list, NULL if not allocated */
+ rtri *ttop; /* Surface triangles linked list */
+
+}; typedef struct _gam_struct gam_struct;
+
+#endif /* RSPL_GAM_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rspl/mlbs.c b/rspl/mlbs.c
new file mode 100644
index 0000000..bbe3865
--- /dev/null
+++ b/rspl/mlbs.c
@@ -0,0 +1,605 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Scattered Data Interpolation with multilevel B-splines library.
+ * This can be used by rspl, or independently by any other routine.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2001/1/1
+ *
+ * Copyright 2000 - 2001 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.
+ */
+
+/*
+ * This is from the paper
+ * "Scattered Data Interpolation with Multilevel B-Splines"
+ * by Seungyong Lee, George Wolberg and Sung Yong Shin,
+ * IEEE Transactions on Visualisation and Computer Graphics
+ * Vol. 3, No. 3, July-September 1997, pp 228.
+ */
+
+/* TTBD:
+ *
+ * Figure out why the results are rubbish ?
+ *
+ * Can this be adapted to be adaptive in it smoothness,
+ * like the non-linear regularized spline stuff that Don Bone used ?
+ *
+ * Get rid of error() calls - return status instead
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "numlib.h"
+#include "mlbs.h"
+
+#ifndef NUMSUP_H
+void error(char *fmt, ...), warning(char *fmt, ...);
+#endif
+
+static void delete_mlbs(mlbs *p);
+static int lookup_mlbs(mlbs *p, co *c);
+
+/* Allocate a new empty mlbs */
+mlbs *alloc_mlbs(
+int di, /* Input dimensionality */
+int fdi, /* Output dimesionality */
+int res, /* Target resolution */
+double smf /* Smoothing factor */
+) {
+ mlbs *p;
+ if ((p = (mlbs *)malloc(sizeof(mlbs))) == NULL)
+ error("Malloc mlbs failed");
+
+ p->di = di;
+ p->fdi = fdi;
+ p->tres = res;
+ p->smf = smf;
+ p->s = NULL;
+
+ p->lookup = lookup_mlbs;
+ p->del = delete_mlbs;
+
+ return p;
+}
+
+static void delete_slbs(slbs *s);
+
+static void delete_mlbs(mlbs *p) {
+
+ if (p != NULL) {
+ delete_slbs(p->s);
+ free(p);
+ }
+}
+
+/* Create a new empty slbs */
+static slbs *new_slbs(
+mlbs *p, /* Parent mlbs */
+int res /* Resolution of this slbs */
+) {
+ slbs *s;
+ int e, f;
+ double *_lat, *lat; /* Latice base address */
+ int ix, oe, oo[MXDI]; /* Neighborhood offset index, counter */
+
+ if ((s = (slbs *)malloc(sizeof(slbs))) == NULL)
+ error("Malloc slbs failed");
+
+ s->p = p;
+ s->res = res;
+
+ for (s->lsize = p->fdi, s->nsize = 1, e = 0; e < p->di; e++) {
+ s->coi[e] = s->lsize; /* (double) increment in this input dimension */
+ s->lsize *= (res + 2); /* Latice in 1D +/- 1 */
+ s->nsize *= 4; /* Neighborhood of 4 */
+ }
+
+ if ((s->_lat = (double *)malloc(s->lsize * sizeof(double))) == NULL)
+ error("Malloc slbs latice failed");
+
+ /* Compute the base address */
+ for (s->loff = 0, e = 0; e < p->di; e++) {
+ s->loff += s->coi[e]; /* Offset by 1 in each input dimension */
+ }
+ s->lat = s->_lat + s->loff;
+
+ /* Figure the cell width */
+ for (e = 0; e < p->di; e++)
+ s->w[e] = (p->h[e] - p->l[e])/(res-1.0);
+
+ /* Setup neighborhood cache info */
+ if ((s->n = (neigh *)malloc(s->nsize * sizeof(neigh))) == NULL)
+ error("Malloc slbs neighborhood failed");
+
+ for (oe = 0; oe < p->di; oe++)
+ oo[oe] = 0;
+
+ for(ix = oe = 0; oe < p->di; ix++) {
+ int xo;
+ for (xo = e = 0; e < p->di; e++) {
+ s->n[ix].c[e] = oo[e];
+ xo += s->coi[e] * oo[e]; /* Accumulate latice offset */
+ }
+ s->n[ix].xo = xo;
+ s->n[ix].w = 0.0;
+
+ /* Increment destination offset counter */
+ for (oe = 0; oe < p->di; oe++) {
+ if (++oo[oe] <= 3) /* Counting from 0 ... 3 */
+ break;
+ oo[oe] = 0;
+ }
+ }
+
+ return s;
+}
+
+/* Destroy a slbs */
+static void delete_slbs(slbs *s) {
+ if (s != NULL) {
+ free(s->_lat);
+ free(s->n);
+ free(s);
+ }
+}
+
+/* Dump the 2D -> 1D contents of an slbs */
+static void dump_slbs(slbs *s) {
+ int e, f;
+ int ce, co[MXDI]; /* latice counter */
+ mlbs *p = s->p; /* Parent object */
+
+ /* Init the counter */
+ for (ce = 0; ce < p->di; ce++)
+ co[ce] = -1;
+ ce = 0;
+
+ f = 0;
+ while(ce < p->di) {
+ double v;
+ int off = 0; /* Latice offset */
+ for (e = 0; e < p->di; e++) {
+ off += co[e] * s->coi[e]; /* Accumulate latice offset */
+ }
+ v = s->lat[off + f]; /* Value of this latice point */
+
+ printf("Latice at [%d][%d] = %f\n",co[1],co[0],v);
+
+ /* Increment the latice counter */
+ for (ce = 0; ce < p->di; ce++) {
+ if (++co[ce] <= s->res) /* Counting from -1 ... s->res */
+ break;
+ co[ce] = -1;
+ }
+ }
+}
+
+/* Initialise an slbs with a linear approximation to the scattered data */
+static void linear_slbs(
+slbs *s
+) {
+ int i, e, f;
+ mlbs *p = s->p; /* Parent object */
+ double **A; /* A matrix holding scattered data points */
+ double *B; /* B matrix holding RHS & solution */
+
+ /* Allocate the matricies */
+ B = dvector(0, p->npts-1);
+ A = dmatrix(0, p->npts-1, 0, p->di);
+
+ /* For each output dimension, solve the linear equation coeficients */
+ for (f = 0; f < p->fdi; f++) {
+ int ce, co[MXDI]; /* latice counter */
+
+ /* Init A[][] with the scattered data points positions */
+ /* Also init B[] with the value for this output dimension */
+ for (i = 0; i < p->npts; i++) {
+ for (e = 0; e < p->di; e++)
+ A[i][e] = p->pts[i].p[e];
+ A[i][e] = 1.0;
+ B[i] = p->pts[i].v[f];
+ }
+
+ /* Solve the equation A.x = b using SVD */
+ /* (The w[] values are thresholded for best accuracy) */
+ /* Return non-zero if no solution found */
+ if (svdsolve(A, B, p->npts, p->di+1) != 0)
+ error("SVD least squares failed");
+ /* A[][] will have been changed, and B[] holds the p->di+1 coefficients */
+
+ /* Use the coefficients to initialise the slbs values */
+ for (ce = 0; ce < p->di; ce++)
+ co[ce] = -1;
+ ce = 0;
+
+ while(ce < p->di) {
+ double v = B[p->di]; /* Constant */
+ int off = 0; /* Latice offset */
+ for (e = 0; e < p->di; e++) {
+ double lv;
+ lv = p->l[e] + s->w[e] * co[e]; /* Input value for this latice location */
+ v += B[e] * lv;
+ off += co[e] * s->coi[e]; /* Accumulate latice offset */
+ }
+ s->lat[off + f] = v; /* Value of this latice point */
+
+ /* Increment the latice counter */
+ for (ce = 0; ce < p->di; ce++) {
+ if (++co[ce] <= s->res) /* Counting from -1 ... s->res */
+ break;
+ co[ce] = -1;
+ }
+ }
+ }
+ free_dmatrix(A, 0, p->npts-1, 0, p->di);
+ free_dvector(B, 0, p->npts-1);
+}
+
+/* Do a latice refinement - upsample the current */
+/* source latice to the destination latice. */
+static void refine_slbs(
+slbs *ds, /* Destination slbs */
+slbs *ss /* Source slbs */
+) {
+ mlbs *p = ss->p; /* Parent object */
+ int ce, co[MXDI]; /* Source coordinate counter */
+ int six; /* Source index */
+ int dix; /* destination index */
+ static double _wt[5] = { 1.0/8.0, 4.0/8.0, 6.0/8.0, 4.0/8.0, 1.0/8.0 };
+ static double *wt = &_wt[2]; /* 1D Distribution weighting */
+
+ /* Zero the destination latice before accumulating values */
+ for (dix = 0; dix < ds->lsize; dix++)
+ ds->_lat[dix] = 0.0;
+
+ /* Now for each source latice entry, add weighted portions */
+ /* to the associated destination points */
+
+ /* Init the source coordinate counter */
+ for (ce = 0; ce < p->di; ce++)
+ co[ce] = -1;
+ ce = 0;
+ six = -ss->loff;
+
+ while(ce < p->di) {
+ int oe, oo[MXDI]; /* Destination offset counter */
+
+//printf("Source coord %d %d, offset %d, value %f\n",co[0], co[1], six, ss->lat[six]);
+ /* calc destination index, and init offest counter */
+ for (dix = oe = 0; oe < p->di; oe++) {
+ oo[oe] = -2;
+ dix += co[oe] * 2 * ds->coi[oe]; /* Accumulate dest offset */
+ }
+ oe = 0;
+
+//printf("Dest coord %d %d\n",co[0] * 2, co[1] * 2);
+ /* For all the offsets from the destination point */
+ while(oe < p->di) {
+ int e, f, dixo; /* Destination index offset */
+ double w = 1.0; /* Weighting */
+
+//printf("dest offset %d %d\n",oo[0], oo[1]);
+ /* Compute dest index offset, and check that we are not outside the destination */
+ for (dixo = e = 0; e < p->di; e++) {
+ int x = co[e] * 2 + oo[e]; /* dest coord */
+ dixo += oo[e] * ds->coi[e]; /* Accumulate dest offset */
+//printf("x[%d] = %d\n",e, x);
+ w *= wt[oo[e]]; /* Compute distribution weighting */
+ if (x < -1 || x > ds->res)
+ break; /* No good */
+ }
+ if (e >= p->di) { /* We are within the destination latice */
+//if ((co[0] * 2 + oo[0]) == 0 && (co[1] * 2 + oo[1]) == 0) {
+//printf("Source coord %d %d, offset %d, value %f\n",co[0], co[1], six, ss->lat[six]);
+//printf("Dest coord %d %d ix %d, weight %f\n",co[0] * 2 + oo[0], co[1] * 2 + oo[1], dix+dixo, w);
+//}
+
+ for (f = 0; f < p->fdi; f++) { /* Distribute weighted values */
+ double v = ss->lat[six + f];
+//if ((co[0] * 2 + oo[0]) == 0 && (co[1] * 2 + oo[1]) == 0)
+//printf("Value being dist %f, weighted value %f\n", v, v * w);
+ ds->lat[dix + dixo + f] += v * w;
+ }
+ }
+
+ /* Increment destination offset counter */
+ for (oe = 0; oe < p->di; oe++) {
+ if (++oo[oe] <= 2) /* Counting from -2 ... +2 */
+ break;
+ oo[oe] = -2;
+ }
+ }
+
+ /* Increment the source index and coordinat counter */
+ six += p->fdi;
+ for (ce = 0; ce < p->di; ce++) {
+ if (++co[ce] <= ss->res) /* Counting from -1 ... ss->res */
+ break;
+ co[ce] = -1;
+ }
+ }
+}
+
+/* Compute the Cubic B-spline weightings for a given t */
+void basis(double b[4], double t) {
+ double _t3, _t2, _t1, _3t3, _3t2, _3t1, _6t2;
+
+ _t1 = t/6.0;
+ _t2 = _t1 * _t1;
+ _t3 = _t2 * _t1;
+ _3t1 = 3.0 * _t1;
+ _3t2 = 3.0 * _t2;
+ _3t3 = 3.0 * _t3;
+ _6t2 = 6.0 * _t2;
+
+ b[0] = - _t3 + _3t2 - _3t1 + 1.0/6.0;
+ b[1] = _3t3 - _6t2 + 4.0/6.0;
+ b[2] = -_3t3 + _3t2 + _3t1 + 1.0/6.0;
+ b[3] = _t3;
+}
+
+
+/* Improve an slbs to make it closer to the scattered data */
+static void improve_slbs(
+slbs *s
+) {
+ int i, e, f;
+ mlbs *p = s->p; /* Parent object */
+ double *delta; /* Delta accumulation */
+ double *omega; /* Omega accumulation */
+
+ /* Allocate temporary accumulation arrays */
+ if ((delta = (double *)calloc(sizeof(double), s->lsize)) == NULL)
+ error("Malloc slbs temp latice failed");
+ delta += s->loff;
+ if ((omega = (double *)calloc(sizeof(double), s->lsize)) == NULL)
+ error("Malloc slbs temp latice failed");
+ omega += s->loff;
+
+ /* For each scattered data point */
+ for (i = 0; i < p->npts; i++) {
+ int ix; /* Latice index of base of neighborhood */
+ double b[MXDI][4]; /* B-spline basis factors for each dimension */
+ double sws; /* Sum of all the basis factors squared */
+ double ve[MXDO]; /* Current output value error */
+ int nn; /* Neighbor counter */
+
+ /* Figure out our neighborhood */
+ for (ix = e = 0; e < p->di; e++) {
+ int x;
+ double t, sp, fp;
+ sp = (p->pts[i].p[e] - p->l[e])/s->w[e]; /* Scaled position */
+ fp = floor(sp);
+ x = (int)(fp - 1.0); /* Grid coordinate */
+ ix += s->coi[e] * x; /* Accume latice offset */
+ t = sp - fp; /* Spline parameter */
+ basis(b[e], t); /* Compute basis function values */
+ }
+
+ /* Compute the grid basis weight functions, */
+ /* the sum of the weights squared, and the current */
+ /* output value estimate. */
+ for (f = 0; f < p->fdi; f++)
+ ve[f] = p->pts[i].v[f]; /* Target output value */
+ for (sws = 0.0, nn = 0; nn < s->nsize; nn++) {
+ double w;
+ for (w = 1.0, e = 0; e < p->di; e++)
+ w *= b[e][s->n[nn].c[e]];
+ s->n[nn].w = w; /* cache weighting */
+ sws += w * w;
+ for (f = 0; f < p->fdi; f++)
+ ve[f] -= w * s->lat[ix + s->n[nn].xo + f]; /* Subtract current aprox value */
+ }
+//printf("Error at point %d = %f\n",i,ve[0]);
+
+ /* Accumulate the delta and omega factors */
+ /* for this resolutions improvement. */
+ for (nn = 0; nn < s->nsize; nn++) {
+ double ws, ww, w = s->n[nn].w;
+ int xo = ix + s->n[nn].xo; /* Latice offset */
+ ww = w * w;
+ ws = ww * w/sws; /* Scale factor for delta */
+ omega[xo] += ww; /* Accumulate omega */
+ for (f = 0; f < p->fdi; f++)
+ delta[xo + f] += ws * ve[f]; /* Accumulate delta */
+//printf("Distributing omega %f to %d %d\n",ww,s->n[nn].c[0],s->n[nn].c[1]);
+//printf("Distributing delta %f to %d %d\n",ws * ve[0],s->n[nn].c[0],s->n[nn].c[1]);
+ }
+ }
+
+ omega -= s->loff; /* Base them back to -1 corner */
+ delta -= s->loff;
+
+ /* Go through the delta and omega arrays, */
+ /* compute and add the refinements to the current */
+ /* B-spline control latice. */
+ for (i = 0; i < s->lsize; i++) {
+ double om = omega[i];
+ if (om != 0.0) {
+ for (f = 0; f < p->fdi; f++)
+ s->_lat[i] += delta[i + f]/om;
+//printf("Adjusting latice index %d by %f to give %f\n",i, delta[i]/om, s->_lat[i]);
+ }
+ }
+
+ /* Done with temporary arrays */
+ free(omega);
+ free(delta);
+}
+
+/* Return the interpolated value for a given point */
+/* Return NZ if input point is out of range */
+static int lookup_mlbs(
+mlbs *p,
+co *c /* Point to interpolate */
+) {
+ slbs *s = p->s;
+ int e, f;
+ int ix; /* Latice index of base of neighborhood */
+ double b[MXDI][4]; /* B-spline basis factors for each dimension */
+ int nn; /* Neighbor counter */
+
+ /* Figure out our neighborhood */
+ for (ix = e = 0; e < p->di; e++) {
+ int x;
+ double t, sp, fp;
+ sp = c->p[e];
+ if (sp < p->l[e] || sp > p->h[e])
+ return 1;
+ sp = (sp - p->l[e])/s->w[e]; /* Scaled position */
+ fp = floor(sp);
+ x = (int)(fp - 1.0); /* Grid coordinate */
+ ix += s->coi[e] * x; /* Accume latice offset */
+ t = sp - fp; /* Spline parameter */
+ basis(b[e], t); /* Compute basis function values */
+ }
+
+ /* Compute the the current output value. */
+ for (f = 0; f < p->fdi; f++)
+ c->v[f] = 0.0;
+ for (nn = 0; nn < s->nsize; nn++) {
+ double w;
+ for (w = 1.0, e = 0; e < p->di; e++)
+ w *= b[e][s->n[nn].c[e]];
+ for (f = 0; f < p->fdi; f++)
+ c->v[f] += w * s->lat[ix + s->n[nn].xo + f]; /* Accume spline value */
+ }
+
+ return 0;
+}
+
+/* Take a list of scattered data points, */
+/* and setup the mlbs. */
+static void set_mlbs(
+mlbs *p, /* mlbs to set up */
+dpnts *pts, /* scattered data points and weights */
+int npts, /* number of scattered data points */
+double *l, /* Input data range, low (May be NULL) */
+double *h /* Input data range, high (May be NULL) */
+) {
+ int res;
+ int i, e, f;
+ slbs *s0 = NULL, *s1;
+
+ /* Establish the input data range */
+ for (e = 0; e < p->di; e++) {
+ if (l == NULL)
+ p->l[e] = 1e60;
+ else
+ p->l[e] = l[e];
+ if (h == NULL)
+ p->h[e] = -1e60;
+ else
+ p->h[e] = h[e];
+ }
+ for (i = 0; i < npts; i++) {
+ for (e = 0; e < p->di; e++) {
+ if (pts[i].p[e] < p->l[e])
+ p->l[e] = pts[i].p[e];
+ if (pts[i].p[e] > p->h[e])
+ p->h[e] = pts[i].p[e];
+ }
+ }
+
+ /* Make point data available during init */
+ p->pts = pts;
+ p->npts = npts;
+
+ /* Create an initial slbs */
+ res = 2;
+ if ((s1 = new_slbs(p, 2)) == NULL)
+ error("new_slbs failed");
+
+ /* Set it up with a linear first approximation */
+ linear_slbs(s1);
+//dump_slbs(s1);
+
+ /* Build up the resolution */
+ for (; res < p->tres;) {
+
+ res = 2 * res -1;
+
+printf("~1 doing resolution %d\n",res);
+ delete_slbs(s0);
+ s0 = s1;
+ if ((s1 = new_slbs(p, res)) == NULL)
+ error("new_slbs failed");
+
+ refine_slbs(s1, s0);
+//dump_slbs(s1);
+ improve_slbs(s1);
+ }
+
+ delete_slbs(s0);
+ p->s = s1; /* Final resolution */
+
+ /* We can't assume point data will stick around */
+ p->pts = NULL;
+ p->npts = 0;
+}
+
+
+/* Create a new empty mlbs */
+mlbs *new_mlbs(
+int di, /* Input dimensionality */
+int fdi, /* Output dimesionality */
+int res, /* Minimum final resolution */
+dpnts *pts, /* scattered data points and weights */
+int npts, /* number of scattered data points */
+double *l, /* Input data range, low (May be NULL) */
+double *h, /* Input data range, high (May be NULL) */
+double smf /* Smoothing factor */
+) {
+ mlbs *p;
+
+ if ((p = alloc_mlbs(di, fdi, res, smf)) == NULL)
+ return p;
+
+ set_mlbs(p, pts, npts, l, h);
+
+ return p;
+}
+
+#ifndef NUMSUP_H
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"stest: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"stest: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#endif /* NUMSUP_H */
+
diff --git a/rspl/mlbs.h b/rspl/mlbs.h
new file mode 100644
index 0000000..4678cfd
--- /dev/null
+++ b/rspl/mlbs.h
@@ -0,0 +1,77 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Scattered Data Interpolation with multilevel B-splines library.
+ * This can be used by rspl, or independently by any other routine.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2001/1/1
+ *
+ * Copyright 2000 - 2001 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.
+ */
+
+/*
+ * This is from the paper
+ * "Scattered Data Interpolation with Multilevel B-Splines"
+ * by Seungyong Lee, George Wolberg and Sung Yong Shin,
+ * IEEE Transactions on Visualisation and Computer Graphics
+ * Vol. 3, No. 3, July-September 1997, pp 228.
+ */
+
+#include "rspl.h" /* Define some common elements */
+
+/* Neighborhood latice cache data */
+typedef struct {
+ int c[MXDI]; /* Coordinate */
+ int xo; /* Offset into slbs latice */
+ double w; /* B-spline basis weight */
+} neigh;
+
+/* Structure that represents a resolution level of B-splines */
+struct _slbs {
+ struct _mlbs *p; /* Parent structure */
+ int res; /* Basic resolution */
+ int coi[MXDI]; /* Double increment for each input dimension into latice */
+ double *lat; /* Control latice, extending from +/- 1 from 0..res-1 */
+ double *_lat; /* Allocation base of lat */
+ int lsize, loff; /* Number of doubles in _lat, offset of lat from _lat */
+ double w[MXDI]; /* Input data cell width */
+ neigh *n; /* Neighborhood latice cache */
+ int nsize; /* Number of n entries */
+}; typedef struct _slbs slbs;
+
+/* Structure that represents the whole scattered interpolation state */
+struct _mlbs {
+ int di; /* Input dimensions */
+ int fdi; /* Output dimensions */
+ int tres; /* Target resolution */
+ double smf; /* Smoothing factor */
+ int npts; /* Number of data points */
+ dpnts *pts; /* Coordinate points and weights (valid while creating) */
+ double l[MXDI], h[MXDI]; /* Input data range, cell width */
+ slbs *s; /* Current B-spline latice */
+
+ int (*lookup)(struct _mlbs *p, co *c);
+
+ void (*del)(struct _mlbs *p);
+
+}; typedef struct _mlbs mlbs;
+
+
+/* Create a new empty mlbs */
+mlbs *new_mlbs(
+int di, /* Input dimensionality */
+int fdi, /* Output dimesionality */
+int res, /* Minimum final resolution */
+dpnts *pts, /* scattered data points and weights */
+int npts, /* number of scattered data points */
+double *l, /* Input data range, low (May be NULL) */
+double *h, /* Input data range, high (May be NULL) */
+double smf /* Smoothing factor */
+);
+
diff --git a/rspl/opt.c b/rspl/opt.c
new file mode 100644
index 0000000..d5a70ce
--- /dev/null
+++ b/rspl/opt.c
@@ -0,0 +1,725 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized splines
+ * optimiser based initialiser.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2001/5/16
+ *
+ * Copyright 1996 - 2001 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.
+ */
+
+/* This file contains an rspl initialiser that */
+/* works from an optimisation function callback. */
+/* It is intended to support the creation of optimised */
+/* color separations, although this usage is not hard coded */
+/* here. */
+
+/* TTBD:
+ *
+ * !!! fix so that this can also be used for smoothed
+ * inversion, ie. PCS -> DevN, as well as
+ * separation PseudoCMY/K -> DevN.
+ *
+ * Plan:
+ * Have additional callback function used for invert,
+ * called at grid initialisation that initialised
+ * the target values to fixed PCS values.
+ * For separation, these are dynamic, and adjusted by
+ * the usual optimisation callback.
+ * (Or can the usual callback figure out when the
+ * initial initialisation is needed ?)
+ *
+ * Need to return average/extrapolated surround values
+ * on the edge, just like fit, so smoothness can be
+ * evaluated in inversion.
+ * Provide another mechanism for sep to know
+ * it is on the edge of the grid, and should expand
+ * gamut if possible.
+ *
+ * Get rid of error() calls - return status instead
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+
+#include "rspl_imp.h"
+#include "numlib.h"
+#include "counters.h" /* Counter macros */
+
+#undef DEBUG
+
+/* Tuning parameters */
+#define TOL 1e-6 /* Tollerance of result */
+#define GRATIO 1.7 /* Multi-grid ratio */
+#define SMOOTH 80.0 /* Set nominal smoothing (1.0) */
+
+#undef NEVER
+#define ALWAYS
+
+/* Implemented in rspl.c: */
+extern void alloc_grid(rspl *s);
+
+extern int is_mono(rspl *s);
+
+/* Convention is to use:
+ i to index grid points u.a
+ n to index data points d.a
+ e to index position dimension di
+ f to index output function dimension fdi
+ j misc and cube corners
+ k misc
+ */
+
+/* ================================================= */
+/* Structure to hold temporary data for multi-grid caliculations */
+/* Only used in this file. */
+struct _omgtp {
+ rspl *s; /* Associated rspl */
+
+ /* Configuration data */
+ int tdi; /* Target guide values dimensionality (must be <= MXDI) */
+ /* (Typically the Lab aim values corresponding to this pseudo device value) */
+ int adi; /* Additional grid point data allowance (must be <= 2 * MXDI) */
+ /* (Typically black locus range) */
+
+ double (*func)(void *fdata, double *inout, double *surav, int first, double *cw);
+ /* Optimisation function */
+ void *fdata; /* Pointer to opaque data needed by callback function */
+
+ struct {
+ double cw[MXDI]; /* Curvature weight factor for each dimension */
+ } sf;
+
+ /* Grid points data */
+ struct {
+ int res[MXDI]; /* Single dimension grid resolution for each dimension */
+ int bres, brix; /* Biggest resolution and its index */
+ double mres; /* Geometric mean res[] */
+ int no; /* Total number of points in grid = res ^ di */
+ datai l,h,w; /* Grid low, high, grid cell width */
+
+
+ double *a; /* Grid point data */
+ /* Array is res ^ di entries double[fdi+tdi+adi] */
+ /* The output values start at offset 0, the */
+ /* target data values start at offset fdi, and */
+ /* the additional data starts at offset fdi+tdi. */
+ int pss; /* Grid point structure size = fdi+tdi */
+
+ /* Grid array offset lookups */
+ int ci[MXDI]; /* Grid coordinate increments for each dimension */
+ int fci[MXDI]; /* Grid coordinate increments for each dimension in doubles */
+ int *hi; /* 2^di Combination offset for sequence through cube. */
+ int *fhi; /* Combination offset for sequence through cube of */
+ /* 2^di points, starting at base, in floats */
+ int a_hi[DEF2MXDI]; /* Default allocation for *hi */
+ int a_fhi[DEF2MXDI];/* Default allocation for *fhi */
+ } g;
+
+}; typedef struct _omgtp omgtp;
+
+/* ================================================= */
+static omgtp *new_omgtp(rspl *s, int tdi, int adi, int mxres,
+ double (*func)(void *fdata, double *inout, double *surav, int first, double *cw),
+ void *fdata);
+static void free_omgtp(omgtp *m);
+static void solve_gres(omgtp *m, double tol);
+static void init_soln(omgtp *m1, omgtp *m2);
+static void init_fsoln(omgtp *m, double **vdata);
+
+/* Initialise the regular spline from the optimisation callback function. */
+/* The target data is auxiliary data used to "target" the optimisation */
+/* callback function. */
+/* The callback function arguments are as follows:
+ * void *fdata,
+ * double *inout, Pointers to fdi+tdi+adi values for the grid point being optimised.
+ * double *surav, Pointers to fdi+tdi values which are the average of the
+ * neighbors of this grid point. Pointer will NULL if this
+ * is a surface grid point.
+ * int first, Flag, NZ if this is the first optimisation of this point.
+ * double *cw the (grid resolution) curvature weighting factor for each dimension
+ *
+ * Returns value is the "error" for this point.
+ */
+
+int
+opt_rspl_imp(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ int tdi, /* Dimensionality of target data */
+ int adi, /* Additional per grid point data allocation */
+ double **vdata, /* di^2 array of function, target and additional values to init */
+ /* array corners with. Corners are ordered with lowest index */
+ /* dimension changing most rapidly. */
+ double (*func)(void *fdata, double *inout, double *surav, int first, double *cw),
+ /* Optimisation function */
+ void *fdata, /* Opaque data needed by function */
+ datai glow, /* Grid low scale - NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution for each dimension */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh /* Data value high normalize - NULL = default 1.0 */
+) {
+// int di = s->di
+ int fdi = s->fdi;
+ int i, e, f;
+// int n;
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+#endif
+ /* set debug level */
+ s->debug = (flags >> 24);
+
+ if (flags & RSPL_VERBOSE) /* Turn on progress messages to stdout */
+ s->verbose = 1;
+ if (flags & RSPL_NOVERBOSE) /* Turn off progress messages to stdout */
+ s->verbose = 0;
+
+ s->symdom = (flags & RSPL_SYMDOMAIN) ? 1 : 0; /* Turn on symetric smoothness with gres */
+
+ if (tdi >= MXDI)
+ error("rspl, opt: tdi %d > MXDI %d",tdi,MXDI);
+
+ if (adi >= (2 * MXDI))
+ error("rspl, opt: adi %d > 2 * MXDI %d",adi,2 * MXDI);
+
+ /* transfer desired grid range to structure */
+ s->g.mres = 1.0;
+ s->g.bres = 0;
+ for (e = 0; e < s->di; e++) {
+ if (gres[e] < 2)
+ error("rspl: grid res must be >= 2!");
+ s->g.res[e] = gres[e]; /* record the desired resolution of the grid */
+ s->g.mres *= gres[e];
+ if (gres[e] > s->g.bres) {
+ s->g.bres = gres[e];
+ s->g.brix = e;
+ }
+
+ if (glow == NULL)
+ s->g.l[e] = 0.0;
+ else
+ s->g.l[e] = glow[e];
+
+ if (ghigh == NULL)
+ s->g.h[e] = 1.0;
+ else
+ s->g.h[e] = ghigh[e];
+ }
+ s->g.mres = pow(s->g.mres, 1.0/e); /* geometric mean */
+
+ /* compute width of each grid cell */
+ for (e = 0; e < s->di; e++) {
+ s->g.w[e] = (s->g.h[e] - s->g.l[e])/(double)(gres[e]-1);
+ }
+
+ /* record low and width data normalizing factors */
+ for (f = 0; f < s->fdi; f++) {
+ if (vlow == NULL)
+ s->d.vl[f] = 0.0;
+ else
+ s->d.vl[f] = vlow[f];
+
+ if (vhigh == NULL)
+ s->d.vw[f] = 1.0 - s->d.vl[f];
+ else
+ s->d.vw[f] = vhigh[f] - s->d.vl[f];
+ }
+
+ /* Do optimisation of data points */
+ {
+ int nn, res, sres;
+ double fres, gratio = GRATIO;
+ float *gp; /* rspl grid pointer */
+ double *mgp; /* Temp muligrid pointer */
+ omgtp *m, *om = NULL;
+
+ sres = 4; /* Start at initial grid res of 4 */
+ if (sres > s->g.bres)
+ sres = s->g.bres; /* Drop to target resolution */
+
+ /* Calculate the resolution scaling ratio */
+ if (((double)s->g.bres/(double)sres) <= gratio) {
+ gratio = (double)s->g.bres/(double)sres;
+ nn = 1;
+ } else { /* More than one needed */
+ nn = (int)((log((double)s->g.bres) - log((double)sres))/log(gratio) + 0.5);
+ gratio = exp((log((double)s->g.bres) - log((double)sres))/(double)nn);
+ }
+
+ /* Do each grid resolution in turn */
+ for (fres = (double)sres, res = sres;;) {
+ m = new_omgtp(s, tdi, adi, res, func, fdata);
+
+ if (om == NULL) {
+ init_fsoln(m, vdata); /* Set the initial targets & values from corners */
+ } else {
+ init_soln(m, om); /* Scale targets & values from from previous resolution */
+ free_omgtp(om); /* Free previous grid res solution */
+ }
+ solve_gres(m, TOL * s->g.mres/res); /* Use itterative */
+
+ if (res >= s->g.mres)
+ break; /* Done */
+
+ fres *= gratio;
+ res = (int)(fres + 0.5);
+ if ((res + 1) >= s->g.mres) /* If close enough */
+ res = (int)s->g.mres;
+ om = m;
+ }
+
+ /* Allocate the final rspl grid data */
+ alloc_grid(s);
+
+ /* Transfer result in x[] to appropriate grid point value */
+ for (gp = s->g.a, mgp = m->g.a, i = 0; i < s->g.no; gp += s->g.pss, mgp += m->g.pss, i++)
+ for (f = 0; f < fdi; f++)
+ gp[f] = (float)mgp[f];
+ free_omgtp(m);
+ }
+
+ /* Return non-mono check */
+ return is_mono(s);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -*/
+/* omgtp routines */
+
+/* Create a new omgtp. */
+/* Grid data will be uninitialised */
+static omgtp *new_omgtp(
+ rspl *s, /* associated rspl */
+ int tdi, /* Target dimensions */
+ int adi, /* Additional per grid point data allocation */
+ int mxres, /* maximum resolution to create */
+ double (*func)(void *fdata, double *inout, double *surav, int first, double *cw),
+ /* Optimisation function */
+ void *fdata /* Opaque data needed by function */
+) {
+ omgtp *m;
+ int di = s->di, fdi = s->fdi;
+// int dno = s->d.no;
+ int gno;
+ int e, g, i;
+// int f, n, j, k;
+
+ /* Allocate a structure */
+ if ((m = (omgtp *) calloc(1, sizeof(omgtp))) == NULL)
+ error("rspl: malloc failed - omgtp");
+
+ /* Allocate space for cube offset arrays */
+ m->g.hi = m->g.a_hi;
+ m->g.fhi = m->g.a_fhi;
+ if ((1 << di) > DEF2MXDI) {
+ if ((m->g.hi = (int *) malloc(sizeof(int) * (1 << di))) == NULL)
+ error("rspl omgtp malloc failed - hi[]");
+ if ((m->g.fhi = (int *) malloc(sizeof(int) * (1 << di))) == NULL)
+ error("rspl omgtp malloc failed - fhi[]");
+ }
+
+ /* General stuff */
+ m->s = s;
+ m->tdi = tdi;
+ m->adi = adi;
+ m->func = func;
+ m->fdata = fdata;
+
+ /* Grid related */
+ m->g.mres = 1.0;
+ m->g.bres = 0;
+ for (gno = 1, e = 0; e < di; e++) {
+ if (mxres >= s->g.res[e]) /* Shoose smaller of gres and target res */
+ m->g.res[e] = s->g.res[e];
+ else
+ m->g.res[e] = mxres;
+
+ m->g.mres *= m->g.res[e];
+ if (m->g.res[e] > m->g.bres) {
+ m->g.bres = m->g.res[e];
+ m->g.brix = e;
+ }
+ gno *= m->g.res[e];
+ }
+ m->g.mres = pow(m->g.mres, 1.0/e); /* geometric mean */
+ m->g.no = gno;
+
+ m->g.pss = fdi+tdi+adi; /* doubles for each output value + target data + additional data */
+
+ /* record high, low limits, and width of each grid cell */
+ for (e = 0; e < s->di; e++) {
+ m->g.l[e] = s->g.l[e];
+ m->g.h[e] = s->g.h[e];
+ m->g.w[e] = (s->g.h[e] - s->g.l[e])/(double)(m->g.res[e]-1);
+ }
+
+ /* Compute index coordinate increments into linear grid for each dimension */
+ /* ie. 1, gres, gres^2, gres^3 */
+ for (m->g.ci[0] = 1, e = 1; e < di; e++) {
+ m->g.ci[e] = m->g.ci[e-1] * m->g.res[e-1]; /* In grid points */
+ m->g.fci[e] = m->g.ci[e] * m->g.pss; /* In doubles */
+ }
+
+ /* Compute index offsets from base of cube to other corners */
+ for (m->g.hi[0] = 0, e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++) {
+ m->g.hi[g+i] = m->g.hi[i] + m->g.ci[e]; /* In grid points */
+ m->g.fhi[g+i] = m->g.hi[g+i] * m->g.pss; /* In doubles */
+ }
+ }
+
+ /* Allocate space for grid */
+ if ((m->g.a = (double *) malloc(sizeof(double) * gno * m->g.pss)) == NULL)
+ error("rspl malloc failed - multi-grid points");
+
+ /* Compute curvature weighting for matching intermediate resolutions. */
+ /* cw[] is multiplied by the grid curvature_errors_squared[] to keep */
+ /* the same ratio with the sum of data position errors squared. */
+ for (e = 0; e < di; e++) {
+ double rsm; /* Resolution smoothness factor */
+ if (s->symdom)
+ rsm = m->g.res[e]-1.0; /* Relative final grid size */
+ else
+ rsm = m->g.mres-1.0; /* Relative mean final grid size */
+ rsm = pow(rsm,8.0/di);
+ rsm /= pow(200.0,8.0/di)/pow(200.0, 4.0); /* (Scale factor to adjust power) */
+
+ m->sf.cw[e] = (s->smooth * SMOOTH)/(rsm * (double)di);
+ }
+
+ return m;
+}
+
+/* Completely free an omgtp */
+static void free_omgtp(omgtp *m) {
+
+ free((void *)m->g.a);
+
+ /* Free structure */
+ if (m->g.hi != m->g.a_hi) {
+ free(m->g.hi);
+ free(m->g.fhi);
+ }
+ free((void *)m);
+}
+
+/* Set the first targets & values from the corner values. */
+static void init_fsoln(
+omgtp *m, /* Destination */
+double **vdata /* di^2 array of function and target values to init array corners with. */
+ /* Corners are ordered with lowest index dimension changing most rapidly. */
+ /* (Function data at index 0, target data at index fdi) */
+) {
+ rspl *s = m->s;
+ int di = s->di;
+ int fdi = s->fdi;
+ int gno = m->g.no;
+ int gres_1[MXDI];
+ int e, n;
+ double *gp; /* Pointer to dest g.a[] grid cube base */
+ ECOUNT(gc, MXDIDO, di, 0, m->g.res, 0); /* Counter for output points */
+ double *gw; /* weight for each grid cube corner */
+ double a_gw[DEF2MXDI]; /* default allocation for gw */
+
+ gw = a_gw;
+ if ((1 << di) > DEF2MXDI) {
+ if ((gw = (double *) malloc(sizeof(double) * (1 << di))) == NULL)
+ error("rspl malloc failed - interp_rspl_nl");
+ }
+
+ for (e = 0; e < di; e++)
+ gres_1[e] = m->g.res[e]-1;
+
+ /* For all output grid points (could skip non-surface points ?) */
+ EC_INIT(gc);
+ for (n = 0, gp = m->g.a; n < gno; n++, gp += m->g.pss) {
+ double we[MXDI]; /* 1.0 - Weight in each dimension */
+
+ /* Figure out the pointer to the grid data and its weighting */
+ {
+ gp = m->g.a; /* Base of output array */
+ for (e = 0; e < di; e++)
+ we[e] = (double)gc[e]/gres_1[e]; /* 1.0 - weight */
+ }
+
+ /* Compute corner weights needed for interpolation */
+ {
+ int i, g;
+ gw[0] = 1.0;
+ for (e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * we[e];
+ gw[i] *= (1.0 - we[e]);
+ }
+ }
+ }
+
+ /* Compute the output values */
+ {
+ int i, f;
+ double w = gw[0];
+ double *d = vdata[0];
+
+ for (f = 0; f < m->g.pss; f++) /* Base of cube */
+ gp[f] = w * d[f];
+
+ for (i = 1; i < (1 << di); i++) { /* For all other corners of cube */
+ w = gw[i]; /* Strength reduce */
+ d = vdata[i];
+ for (f = 0; f < fdi; f++)
+ gp[f] += w * d[f];
+ }
+
+ }
+
+ EC_INC(gc);
+ }
+
+ if (gw != a_gw)
+ free(gw);
+}
+
+
+/* Transfer a device and target values solution from one omgtp to another. */
+/* (We assume that they are for the same problem) */
+static void init_soln(
+ omgtp *m1, /* Destination */
+ omgtp *m2 /* Source */
+) {
+ rspl *s = m1->s;
+ int di = s->di;
+ int gno = m1->g.no;
+ int gres1_1[MXDI];
+ int gres2_1[MXDI];
+ int e, n;
+ double *a; /* Pointer to dest g.a[] grid cube base */
+ ECOUNT(gc, MXDIDO, di, 0, m1->g.res, 0); /* Counter for output points */
+ double *gw; /* weight for each grid cube corner */
+ double a_gw[DEF2MXDI]; /* default allocation for gw */
+
+ gw = a_gw;
+ if ((1 << di) > DEF2MXDI) {
+ if ((gw = (double *) malloc(sizeof(double) * (1 << di))) == NULL)
+ error("rspl malloc failed - interp_rspl_nl");
+ }
+
+ for (e = 0; e < di; e++) {
+ gres1_1[e] = m1->g.res[e]-1;
+ gres2_1[e] = m2->g.res[e]-1;
+ }
+
+ /* For all output grid points */
+ EC_INIT(gc);
+ for (n = 0, a = m1->g.a; n < gno; n++, a += m1->g.pss) {
+ double we[MXDI]; /* 1.0 - Weight in each dimension */
+ double *gp; /* Pointer to source g.a[] grid cube base */
+
+ /* Figure out which grid cell the point falls into */
+ {
+ double t;
+ int mi;
+ gp = m2->g.a; /* Base of solution array */
+ for (e = 0; e < di; e++) {
+ t = (double)gc[e] * gres2_1[e]/gres1_1[e];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres2_1[e])
+ mi = gres2_1[e]-1;
+ gp += mi * m2->g.fci[e]; /* Add Index offset for grid cube base in dimen */
+ we[e] = t - (double)mi; /* 1.0 - weight */
+ }
+ }
+
+ /* Compute corner weights needed for interpolation */
+ {
+ int i, g;
+ gw[0] = 1.0;
+ for (e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * we[e];
+ gw[i] *= (1.0 - we[e]);
+ }
+ }
+ }
+
+ /* Compute the output values */
+ {
+ int i, f;
+ double w = gw[0];
+ double *d = gp + m2->g.fhi[0];
+
+ for (f = 0; f < m1->g.pss; f++) /* Base of cube */
+ a[f] = w * d[f];
+
+ for (i = 1; i < (1 << di); i++) { /* For all other corners of cube */
+ w = gw[i]; /* Strength reduce */
+ d = gp + m2->g.fhi[i];
+ for (f = 0; f < m1->g.pss; f++)
+ a[f] += w * d[f];
+ }
+
+ }
+ EC_INC(gc);
+ }
+
+ if (gw != a_gw)
+ free(gw);
+}
+
+/* - - - - - - - - - - - - - - - - - - - -*/
+static double one_itter(omgtp *m, int first);
+
+/* Itterate the optimisation functions until we are happy things have settled */
+static void
+solve_gres(
+omgtp *m,
+double tol
+) {
+ int i;
+ double dtol = tol * 0.1; /* Delta tol limit */
+ double ltt, tt;
+
+ ltt = 1.0;
+ tt = tol * 10.0;
+
+ for (i = 0; i < 500; i++) {
+ if (i == 0)
+ tt = one_itter(m, 1);
+
+ ltt = tt;
+ tt = one_itter(m, 0);
+
+ if (tt < tol || (ltt - tt) < dtol) /* Get within 0.1 % */
+ break;
+ }
+}
+
+/* Optimise the points values and (optionally) targets */
+/* Use Red/Black order, return total error after this itteration. */
+/* Return the total optimisation error */
+static double
+one_itter(
+omgtp *m,
+int first /* Flag, NZ if this is the first pass at this resolution */
+) {
+ int di = m->s->di, fdi = m->s->fdi;
+ int tdi = m->tdi;
+ int i, e, f;
+ int gc[MXDI];
+ int *gres = m->g.res;
+ int gres_1[MXDI];
+ DCOUNT(cc, MXDIDO, di, -1, -1, 2); /* Surrounding cube counter */
+ double *gpp; /* Current grid point pointer */
+ double ssum[MXDO+MXDI+2*MXDI]; /* Pointer to surrounding average values */
+ double *surav; /* Surrounding average values */
+ double awt; /* Average weight */
+ double terr = 0.0; /* Total error */
+ int surf; /* This point is on the surface */
+
+ for (e = 0; e < di; e++) {
+ gc[e] = 0; /* init coords */
+ gres_1[e] = gres[e] - 1;
+ }
+
+ /* Until done */
+ for (;;) {
+
+ /* See if we are on the surface */
+ surf = 0;
+ gpp = m->g.a;
+ for (e = 0; e < di; e++) {
+ gpp += m->g.fci[e] * gc[e]; /* Compute pointer to current point */
+
+ if (gc[e] == 0 || gc[e] == gres_1[e])
+ surf = 1;
+ }
+
+ surav = NULL;
+ if (!surf) {
+
+ for (f = 0; f < (fdi + tdi); f++)
+ ssum[f] = 0.0;
+ awt = 0.0;
+
+ /* Average the 3x3 surrounders */
+ DC_INIT(cc)
+ for (i = 0; !DC_DONE(cc); i++ ) {
+ double *gp = m->g.a;
+
+ for (e = 0; e < di; e++) {
+ int j;
+ j = gc[e] + cc[e];
+ if (j < 0 && j > gres_1[e]) { /* outside */
+ break;
+ }
+ gp += m->g.fci[e] * j; /* Compute pointer to surrounder */
+ }
+ if (e >= di) { /* We have a valid point */
+ for (f = 0; f < (fdi + tdi); f++)
+ ssum[f] += gp[f];
+ awt += 1.0;
+ }
+ DC_INC(cc);
+ }
+ if (awt > 0.0) { /* Compute the average */
+ for (f = 0; f < (fdi + tdi); f++)
+ ssum[f] /= awt;
+ surav = ssum;
+ }
+ }
+
+ /* Call optimisation function */
+ terr += m->func(m->fdata, gpp, surav, first, m->sf.cw);
+
+ /* Increment index in red/black order */
+ for (e = 0; e < di; e++) {
+ if (e == 0) {
+ gc[0] += 2; /* Inc coordinate by 2 */
+ } else {
+ gc[e] += 1; /* Inc coordinate */
+ }
+ if (gc[e] < gres[e])
+ break; /* No carry */
+ gc[e] -= gres[e]; /* Reset coord */
+
+ if ((gres[e] & 1) == 0) { /* Compensate for odd grid */
+ gc[0] ^= 1; /* XOR lsb */
+ }
+ }
+ /* Stop on reaching 0 */
+ for(e = 0; e < di; e++)
+ if (gc[e] != 0)
+ break;
+ if (e == di)
+ break; /* Finished */
+ }
+
+ return terr;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rspl/rev.c b/rspl/rev.c
new file mode 100644
index 0000000..237dbe3
--- /dev/null
+++ b/rspl/rev.c
@@ -0,0 +1,6608 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized spline data structure
+ *
+ * Reverse interpolation support code.
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/1/00
+ *
+ * Copyright 1999 - 2008 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.
+ *
+ * Latest simplex/linear equation version.
+ */
+
+/* TTBD:
+
+ Should fix the clipping case so that a direction weighting
+ funtion can be applied. This should be used just like
+ the perceptual case to increase L* constance for dark
+ colors. Will this stuff up the geometric consistency though ?
+ [ See fill_nncell(), fill_nncell() and users of calc_fwd_nn_cell_list(),
+ ie. nnearest_clip_solve(), clipn_setsort() etc. ]
+ The SVD least squares computation case makes this hard to change ?
+ Would have to feed in a weighting function, or can it be general ?
+
+ Allow function callback to set auxiliary values for
+ flag RSPL_AUXLOCUS.
+ How to pass enough info back to aux_compute() ?
+
+ Should auxil return multiple solutions if it finds them ???
+
+ */
+
+/* TTBD:
+ Get rid of error() calls - return status instead
+
+ Need to add a hefty overview and explanation of
+ how all this works, before I forget it !
+
+ ie:
+
+ Basic function requirements: exact, auxil, locus, clip
+
+ Fwd cell - reverse cell list lookup
+
+ Basic layout di -> fdi + auxils + ink limit
+
+ Basic search strategy
+
+ Sub Simplex decomposition & properties
+
+ How each type of function finds solutions
+ Sub-simplex dimensionality & dof + target dim & dof
+ Linear algebra choices.
+
+ How final solutions are chosen
+
+ */
+
+/* PROBLEMS:
+
+ Sometimes the aux locus doesn't correspond exactly to
+ the inversion :- ie. one locus segment is returned,
+ yet the inversion can't return a solution with
+ a particular aux target that lies within that segment.
+ (1150 near black, k ~= 0.4).
+
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <memory.h>
+#include <time.h>
+
+#ifdef NT
+# ifdef WINVER
+# undef WINVER
+# endif
+# define WINVER 0x0500 /* We need 2k features */
+# include <windows.h>
+#else
+# include <unistd.h>
+# ifdef __APPLE__
+# include <fcntl.h>
+# include <sys/types.h>
+# include <sys/sysctl.h>
+# endif
+#endif
+
+#define INKSCALE 5000.0 /* For ink limit weighting to fudge SVD least squares solution */
+
+#include "rspl_imp.h"
+#include "numlib.h"
+#include "sort.h" /* Heap sort */
+#include "counters.h" /* Counter macros */
+
+//#define DMALLOC_GLOBALS
+//#include "dmalloc.h"
+//#undef DMALLOC_GLOBALS
+
+#undef DEBUG1 /* Higher level code */
+#undef DEBUG2 /* Lower level code */
+
+/* Debug memory usage accounting */
+#ifdef NEVER
+#ifdef NEVER
+int thissz, lastsz = -1;
+#define INCSZ(s, bbb) { \
+ (s)->rev.sz += (bbb); \
+ (s)->rev.thissz = (s)->rev.sz/1000000; \
+ if ((s)->rev.thissz != (s)->rev.lastsz) fprintf(stderr,"~1 0x%x: %s, %d: rev size = %d Mbytes, delta %d, limit %d\n",((int)(s) >> 8) & 0xf, __FILE__, __LINE__,(s)->rev.thissz,(bbb),(s)->rev.max_sz/1000000); \
+ (s)->rev.lastsz = (s)->rev.thissz; \
+ }
+#define DECSZ(s, bbb) { \
+ (s)->rev.sz -= (bbb); \
+ (s)->rev.thissz = (s)->rev.sz/1000000; \
+ if ((s)->rev.thissz != (s)->rev.lastsz) fprintf(stderr,"~1 0x%x: %s, %d: rev size = %d Mbytes, delta %d, limit %d\n",((int)(s) >> 8) & 0xf, __FILE__, __LINE__,(s)->rev.thissz,-(bbb),(s)->rev.max_sz/1000000); \
+ (s)->rev.lastsz = (s)->rev.thissz; \
+ }
+#else
+#define INCSZ(s, bbb) (s)->rev.sz += (bbb); \
+ fprintf(stderr,"%s, %d: rev.sz += %d\n",__FILE__, __LINE__, bbb)
+#define DECSZ(s, bbb) (s)->rev.sz -= (bbb); \
+ fprintf(stderr,"%s, %d: rev.sz -= %d\n",__FILE__, __LINE__, bbb)
+#endif
+#else
+#define INCSZ(s, bbb) (s)->rev.sz += (bbb)
+#define DECSZ(s, bbb) (s)->rev.sz -= (bbb)
+#endif
+
+/* Set STATS in rev.h */
+
+#define DOSORT /* Cell sort */
+
+/* Print a vectors value */
+#define DBGVI(text, dim, out, vec, end) \
+{ int pveci; \
+ printf("%s",text); \
+ for (pveci = 0 ; pveci < (dim); pveci++) \
+ printf(out,(vec)[pveci]); \
+ printf(end); \
+}
+
+/* Print a matrix value */
+#define DBGMI(text, rows, cols, out, mat, end) \
+{ int pveci, pvecr; \
+ printf("%s",text); \
+ for (pvecr = 0 ; pvecr < (rows); pvecr++) { \
+ for (pveci = 0 ; pveci < (cols); pveci++) \
+ printf(out,(mat)[pvecr][pveci]); \
+ if ((pvecr+1) < (rows)) \
+ printf("\n"); \
+ } \
+ printf(end); \
+}
+
+/* Do an arbitrary printf */
+#define DBGI(text) printf text ;
+
+#undef DEBUG
+#undef DBG
+#undef DBGV
+#undef DBGM
+
+#undef NEVER
+#define ALWAYS
+
+#ifdef DEBUG1
+#undef DBGS
+#undef DBG
+#undef DBGV
+#undef DBGM
+#define DEBUG
+#define DBGS(xxx) xxx
+#define DBG(xxx) DBGI(xxx)
+#define DBGV(xxx) DBGVI xxx
+#define DBGM(xxx) DBGMI xxx
+#else
+#undef DEBUG
+#undef DBGS
+#undef DBG
+#undef DBGV
+#undef DBGM
+#define DBGS(xxx)
+#define DBG(xxx)
+#define DBGV(xxx)
+#define DBGM(xxx)
+#endif
+
+/* Debug string routines */
+static char *pcellorange(cell *c);
+
+/* Convention is to use:
+ i to index grid points u.a
+ n to index data points d.a
+ e to index position dimension di
+ f to index output function dimension fdi
+ j misc and cube corners
+ k misc
+ */
+
+#define EPS (2e-6) /* 2e-6 Allowance for numeric error */
+
+static void make_rev(rspl *s);
+static void init_revaccell(rspl *s);
+
+static cell *get_rcell(schbase *b, int ix, int force);
+static void uncache_rcell(revcache *r, cell *cp);
+#define unget_rcell(r, cp) uncache_rcell(r, cp) /* These are the same */
+static void invalidate_revaccell(rspl *s);
+static int decrease_revcache(revcache *rc);
+
+/* ====================================================== */
+
+static schbase *init_search(rspl *s, int flags, double *av, int *auxm,
+ double *v, double *cdir, co *cpp, int mxsoln, enum ops op);
+static void adjust_search(rspl *s, int flags, double *av, enum ops op);
+static schbase *set_search_limit(rspl *s, double (*limit)(void *vcntx, double *in),
+ void *lcntx, double limitv);
+static void set_lsearch(rspl *s, int e);
+static void free_search(schbase *b);
+
+static int *calc_fwd_cell_list(rspl *s, double *v);
+
+static int *calc_fwd_nn_cell_list(rspl *s, double *v);
+
+static void init_line_eq(schbase *b, double st[MXRO], double de[MXRO]);
+static int *init_line(rspl *s, line *l, double st[MXRO], double de[MXRO]);
+static int *next_line_cell(line *l);
+
+static void search_list(schbase *b, int *rip, unsigned int tcount);
+
+static void clear_limitv(rspl *s);
+
+static double get_limitv(schbase *b, int ix, float *fcb, double *p);
+
+#ifdef STATS
+static char *opnames[6] = { "exact", "clipv", "clipn", "auxil", "locus" };
+#endif /* STATS */
+
+#define INF_DIST 1e38 /* Stands for infinite "current best" distance */
+
+/* ====================================================== */
+/* Globals that track overall usage of reverse cache to aportion memory */
+/* This is incremented for rspl with di > 1 when rev.rev_valid != 0 */
+size_t g_avail_ram = 0; /* Total maximum memory to be used */
+size_t g_test_ram = 0; /* Amount of memory that has been tested to be allocatable */
+int g_no_rev_cache_instances = 0;
+rev_struct *g_rev_instances = NULL;
+
+/* ------------------------------------------------------ */
+/* Retry allocation routines - if the malloc fails, */
+/* try reducing the cache size and trying again */
+/* (This won't catch the problem if it occurs in a malloc outside rev) */
+
+/* When a malloc fails, reduce the maximum cache to */
+/* it's current allocation minus the given size. */
+static void rev_reduce_cache(size_t size) {
+ rev_struct *rsi;
+ size_t ram;
+
+ /* Compute how much ram is currently allocated */
+ for (ram = 0, rsi = g_rev_instances; rsi != NULL; rsi = rsi->next)
+ ram += rsi->sz;
+
+ if (size > ram)
+ error("rev_reduce_cache: run out of rev virtual memory!");
+
+//printf("~1 size = %d, g_test_ram = %d\n",size,g_test_ram);
+//printf("~1 rev: Reducing cache because alloc of %d bytes failed. Reduced from %d to %d MB\n",
+//size, g_avail_ram/1000000, (ram - size)/1000000);
+ ram = g_avail_ram = ram - size;
+
+ /* Aportion the memory, and reduce the cache allocation to match */
+ ram /= g_no_rev_cache_instances;
+ for (rsi = g_rev_instances; rsi != NULL; rsi = rsi->next) {
+ revcache *rc = rsi->cache;
+
+ rsi->max_sz = ram;
+ while (rc->nunlocked > 0 && rsi->sz > rsi->max_sz) {
+ if (decrease_revcache(rc) == 0)
+ break;
+ }
+//printf("~1 rev instance ram = %d MB\n",rsi->sz/1000000);
+ }
+//fprintf(stdout, "%c~~1 There %s %d rev cache instance%s with %d Mbytes limit\n",
+// cr_char,
+// g_no_rev_cache_instances > 1 ? "are" : "is",
+// g_no_rev_cache_instances,
+// g_no_rev_cache_instances > 1 ? "s" : "",
+// ram/1000000);
+}
+
+/* Check that the requested allocation plus 20 M Bytes */
+/* can be allocated, and if not, reduce the rev-cache limit. */
+/* This is so as to detect running out of VM before */
+/* we actually run out and (on OS X) avoid emitting a warning. */
+static void rev_test_vram(size_t size) {
+ char *a1;
+#ifdef __APPLE__
+ int old_stderr, new_stderr;
+
+ /* OS X malloc() blabs about a malloc failure. This */
+ /* will confuse users, so we temporarily redirect stdout */
+ fflush(stderr);
+ old_stderr = dup(fileno(stderr));
+ new_stderr = open("/dev/null", O_WRONLY | O_APPEND);
+ dup2(new_stderr, fileno(stderr));
+#endif
+ size += 20 * 1024 * 1024; /* This depends on the VM region allocation size */
+ if ((a1 = malloc(size)) == NULL) {
+ rev_reduce_cache(size);
+ } else {
+ free(a1);
+ }
+ g_test_ram = size/2; /* Allow for twice as much VM to be used for each allocation */
+#ifdef __APPLE__
+ fflush(stderr);
+ dup2(old_stderr, fileno(stderr)); /* Restore stderr */
+ close(new_stderr);
+ close(old_stderr);
+#endif
+}
+
+static void *rev_malloc(rspl *s, size_t size) {
+ void *rv;
+
+ if ((size + 1 * 1024 * 1204) > g_test_ram)
+ rev_test_vram(size);
+ if ((rv = malloc(size)) == NULL) {
+ rev_reduce_cache(size);
+ rv = malloc(size);
+ }
+ if (rv != NULL)
+ g_test_ram -= size;
+
+ return rv;
+}
+
+static void *rev_calloc(rspl *s, size_t num, size_t size) {
+ void *rv;
+
+ if (((num * size) + 1 * 1024 * 1204) > g_test_ram)
+ rev_test_vram(size);
+ if ((rv = calloc(num, size)) == NULL) {
+ rev_reduce_cache(num * size);
+ rv = calloc(num, size);
+ }
+ if (rv != NULL)
+ g_test_ram -= size;
+
+ return rv;
+}
+
+static void *rev_realloc(rspl *s, void *ptr, size_t size) {
+ void *rv;
+
+ if ((size + 1 * 1024 * 1204) > g_test_ram)
+ rev_test_vram(size);
+ if ((rv = realloc(ptr, size)) == NULL) {
+ rev_reduce_cache(size); /* approximation */
+ rv = realloc(ptr, size);
+ }
+ if (rv != NULL)
+ g_test_ram -= size;
+
+ return rv;
+}
+
+
+/* ====================================================== */
+/* Set the ink limit information for any reverse interpolation. */
+/* Calling this will clear the reverse interpolaton cache and acceleration structures. */
+static void
+rev_set_limit_rspl(
+ rspl *s, /* this */
+ double (*limit)(void *lcntx, double *in), /* Optional input space limit function. Function */
+ /* should evaluate in[0..di-1], and return number that is not to exceed */
+ /* limitv. NULL if not used */
+ void *lcntx, /* Context passed to limit() */
+ double limitv /* Value that limit() is not to exceed */
+) {
+ schbase *b;
+
+ DBG(("rev: setting ink limit function 0x%x and limit %f\n",limit,limitv));
+ /* This is a restricted size function */
+ if (s->di > MXRI)
+ error("rspl: rev_set_limit can't handle di = %d",s->di);
+ if (s->fdi > MXRO)
+ error("rspl: rev_set_limit can't handle fdi = %d",s->fdi);
+
+ b = set_search_limit(s, limit, lcntx, limitv); /* Init and set limit info */
+
+ if (s->rev.inited) { /* If cache and acceleration has been allocated */
+ invalidate_revaccell(s); /* Invalidate the reverse cache */
+ }
+
+ /* Invalidate any ink limit values cached with the fwd grid data */
+ clear_limitv(s);
+}
+
+/* Get the ink limit information for any reverse interpolation. */
+static void
+rev_get_limit_rspl(
+ rspl *s, /* this */
+ double (**limitf)(void *lcntx, double *in), /* Return pointer to function of NULL if not set */
+ void **lcntx, /* return context pointer */
+ double *limitv /* Return limit value */
+) {
+ schbase *b = s->rev.sb;
+
+ /* This is a restricted size function */
+ if (s->di > MXRI)
+ error("rspl: rev_get_limit can't handle di = %d",s->di);
+ if (s->fdi > MXRO)
+ error("rspl: rev_get_limit can't handle fdi = %d",s->fdi);
+
+ if (b == NULL) {
+ *limitf = NULL;
+ *lcntx = NULL;
+ *limitv = 0.0;
+ } else {
+ *limitf = s->limitf;
+ *lcntx = s->lcntx;
+ *limitv = s->limitv/INKSCALE;
+ }
+}
+
+#define RSPL_CERTAIN 0x80000000 /* WILLCLIP hint is certain */
+#define RSPL_WILLCLIP2 (RSPL_CERTAIN | RSPL_WILLCLIP) /* Clipping will certainly be needed */
+
+/* Do reverse interpolation given target output values and (optional) auxiliary target */
+/* input values. Return number of results and clipping flag. If return value == mxsoln, */
+/* then there might be more results. The target values returned will correspond to the */
+/* actual (posssibly clipped) point. The return value is the number of solutions + */
+/* a clipped flag. Properly set hint flags improve performance, but a correct result should */
+/* be returned if the RSPL_NEARCLIP is set, even if they are not set correctly. */
+static int
+rev_interp_rspl(
+ rspl *s, /* this */
+ int flags, /* Hint flag */
+ int mxsoln, /* Maximum number of solutions allowed for */
+ int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no auxiliaries) */
+ double cdir[MXRO], /* Clip vector direction wrt to cpp[0].v and length - NULL if not used */
+ co *cpp /* Given target output space value in cpp[0].v[] + */
+ /* target input space auxiliaries in cpp[0].p[], return */
+ /* input space solutions in cpp[0..retval-1].p[], and */
+) {
+ int e, di = s->di;
+ int fdi = s->fdi;
+ int i, *rip = NULL;
+ schbase *b = NULL; /* Base search information */
+ double auxv[MXRI]; /* Locus proportional auxiliary values */
+ int didclip = 0; /* flag - set if we clipped the target */
+
+ DBGV(("\nrev interp called with out targets", fdi, " %f", cpp[0].v, "\n"));
+
+ /* This is a restricted size function */
+ if (di > MXRI)
+ error("rspl: rev_interp can't handle di = %d",di);
+ if (fdi > MXRO)
+ error("rspl: rev_interp can't handle fdi = %d",fdi);
+
+ if (auxm != NULL) {
+ double ax[MXRI];
+ for (i = 0; i < di; i++) {
+ if (auxm[i] != 0)
+ ax[i] = cpp[0].p[i];
+ else
+ ax[i] = 0.0;
+ }
+ DBGV((" auxiliaries mask", di, " %d", auxm, "\n"));
+ DBGV((" auxiliaries values", di, " %f", ax, "\n"));
+ }
+ DBG(("di = %d, fdi = %d\n",di, fdi));
+ DBG(("flags = 0x%x\n",flags));
+
+ mxsoln &= RSPL_NOSOLNS; /* Prevent silliness */
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Auxiliary is proportion of locus, so we need to find locus extent */
+ if (flags & RSPL_AUXLOCUS) {
+ DBG(("rev interp has aux targets as proportion of locus\n"));
+
+ flags &= ~RSPL_WILLCLIP; /* Reset hint flag, as we will figure it out */
+
+ /* For each valid auxiliary */
+ for (e = 0; e < di; e++) {
+ if (auxm[e] == 0)
+ continue; /* Skip unsused auxiliaries */
+
+ /* Do search for min and max */
+ DBG(("rev locus searching for aux %d min/max\n", e));
+ if (b == NULL) {
+ b = init_search(s, flags, cpp[0].p, auxm, cpp[0].v, cdir, cpp, mxsoln, locus);
+#ifdef STATS
+ s->rev.st[b->op].searchcalls++;
+#endif /* STATS */
+ } else
+ set_lsearch(s, e); /* Reset locus search for next auxiliary */
+
+ if (rip == NULL) { /* Not done this yet */
+ rip = calc_fwd_cell_list(s, cpp[0].v); /* Reverse grid index for out target */
+ if (rip == NULL) {
+ DBG(("Got NULL list (point outside range) for auxiliary locus search\n"));
+ flags |= RSPL_WILLCLIP2;
+ break;
+ }
+ }
+
+ search_list(b, rip, s->get_next_touch(s)); /* Setup, sort and search the list */
+
+ if (b->min > b->max) { /* Failed to find locus */
+ DBG(("rev interp failed to find locus for aux %d, so expect clip\n",e));
+ flags |= RSPL_WILLCLIP2;
+ break;
+ }
+ auxv[e] = (cpp[0].p[e] * (b->max - b->min)) + b->min;
+ }
+
+ DBG(("rev interp got all locuses, so expect exact result\n",e));
+ if (!(flags & RSPL_WILLCLIP)) {
+ flags |= RSPL_EXACTAUX; /* Got locuses, so expect exact result */
+ }
+ }
+
+ /* Init the search information */
+ if (b == NULL)
+ b = init_search(s, flags, cpp[0].p, auxm, cpp[0].v, cdir, cpp, mxsoln, exact);
+ else
+ adjust_search(s, flags, auxv, exact); /* Using proportion of locus aux */
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* If hinted that we will not need to clip, look for exact solution. */
+ if (!(flags & RSPL_WILLCLIP)) {
+ DBG(("Hint we won't clip, so trying exact search\n"));
+
+ /* First do an exact search (init will select auxil if requested) */
+ adjust_search(s, flags, NULL, exact);
+
+ /* Figure out the reverse grid index appropriate for this request */
+ if (rip == NULL) /* Not done this yet */
+ rip = calc_fwd_cell_list(s, cpp[0].v);
+
+#ifdef STATS
+ s->rev.st[b->op].searchcalls++;
+#endif /* STATS */
+ if (rip != NULL) {
+ /* Setup, sort and search the list */
+ search_list(b, rip, s->get_next_touch(s));
+ } else {
+ DBG(("Got NULL list (point outside range) for first exact reverse cell\n"));
+ }
+
+ /* If we selected exact aux, but failed to find a solution, relax expectation */
+ if (b->nsoln == 0 && b->naux > 0 && (flags & RSPL_EXACTAUX)) {
+//printf("~1 relaxing notclip expactation when nsoln == %d, naux = %d, falgs & RSPL_EXACTAUX = 0x%x\n", b->nsoln,b->naux,flags & RSPL_EXACTAUX);
+ DBG(("Searching for exact match to auxiliary target failed, so try again\n"));
+ adjust_search(s, flags & ~RSPL_EXACTAUX, NULL, exact);
+
+#ifdef STATS
+ s->rev.st[b->op].searchcalls++;
+#endif /* STATS */
+ /* Candidate cell list should be the same */
+ if (rip != NULL) {
+ /* Setup, sort and search the list */
+ search_list(b, rip, s->get_next_touch(s));
+ } else {
+ DBG(("Got NULL list (point outside range) for nearest search reverse cell\n"));
+ }
+ }
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* If the exact search failed, and we should look for a nearest solution */
+ if (b->nsoln == 0 && (flags & RSPL_NEARCLIP)) {
+ DBG(("Trying nearest search\n"));
+
+#ifdef STATS
+ s->rev.st[b->op].searchcalls++;
+#endif /* STATS */
+
+ /* We get returned a list of cube base indexes of all cubes that have */
+ /* the closest valid vertex value to the target value. */
+ /* (This may not result in the true closest point if the geometry of */
+ /* the vertex values is localy non-smooth or self intersecting, */
+ /* but seems to return a good result in most realistic situations ?) */
+
+ adjust_search(s, flags, NULL, clipn);
+
+ /* Get list of cells enclosing nearest vertex */
+ if ((rip = calc_fwd_nn_cell_list(s, cpp[0].v)) != NULL) {
+ search_list(b, rip, s->get_next_touch(s)); /* Setup, sort and search the list */
+ } else {
+ DBG(("Got NULL list! (point inside gamut \?\?) for nearest search\n"));
+ }
+
+ if (b->nsoln > 0)
+ didclip = RSPL_DIDCLIP;
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* If we still don't have a solution, do a vector direction clip */
+ if (b->nsoln == 0 && b->canvecclip) {
+ /* Find clipping solution in vector direction */
+ line ln; /* Structure to hold line context */
+ unsigned int tcount; /* grid touch count for this opperation */
+
+ DBG(("Starting a clipping vector search now!!\n"));
+
+ adjust_search(s, flags, NULL, clipv);
+
+ tcount = s->get_next_touch(s); /* Get next grid touched generation count */
+
+#ifdef STATS
+ s->rev.st[b->op].searchcalls++;
+#endif /* STATS */
+ init_line_eq(b, b->v, cdir); /* Init the implicit line equation */
+ rip = init_line(s, &ln, cpp[0].v, cdir); /* Init the line cell dda */
+//~~1 HACK!!! should be <= 1.0 !!!
+ for (; ln.t <= 2.0; rip = next_line_cell(&ln)) {
+ if (rip == NULL) {
+ DBG(("Got NULL list for this reverse cell\n"));
+ continue;
+ }
+
+ /* Setup, sort and search the list */
+ search_list(b, rip, tcount);
+
+ /* If we have found a solution, then abort the search - */
+ /* this line will be taking us away from the best solution. */
+ if (b->nsoln > 0)
+ break;
+ }
+ if (b->nsoln > 0)
+ didclip = RSPL_DIDCLIP;
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* If the clipped solution seems to have been jumping to conclusions, */
+ /* search for an exact solution. */
+ if (didclip && (flags & RSPL_WILLCLIP && !(flags & RSPL_CERTAIN))
+ && (b->cdist/s->get_out_scale(s)) < 0.002) {
+ co c_cpp = b->cpp[0]; /* Save clip solution in case we want it */
+ double c_idist = b->idist;
+ int c_iabove = b->iabove;
+ int c_nsoln = b->nsoln;
+ int c_pauxcell = b->pauxcell;
+ double c_cdist = b->cdist;
+ int c_iclip = b->iclip;
+
+ DBG(("Trying exact search again\n"));
+
+ /* Do an exact search (init will select auxil if requested) */
+ adjust_search(s, flags & ~RSPL_WILLCLIP, NULL, exact);
+
+ /* Figure out the reverse grid index appropriate for this request */
+ rip = calc_fwd_cell_list(s, cpp[0].v);
+
+#ifdef STATS
+ s->rev.st[b->op].searchcalls++;
+#endif /* STATS */
+ if (rip != NULL) {
+ /* Setup, sort and search the list */
+ search_list(b, rip, s->get_next_touch(s));
+ } else {
+ DBG(("Got NULL list (point outside range) for first exact reverse cell\n"));
+ }
+
+ /* If we selected exact aux, but failed to find a solution, relax expectation */
+ if (b->nsoln == 0 && b->naux > 0 && (flags & RSPL_EXACTAUX)) {
+ DBG(("Searching for exact match to auxiliary target failed, so try again\n"));
+//printf("~1 relaxing didclip expactation when nsoln == %d, naux = %d, flags & RSPL_EXACTAUX = 0x%x\n", b->nsoln,b->naux,flags & RSPL_EXACTAUX);
+ adjust_search(s, flags & ~RSPL_EXACTAUX, NULL, exact);
+
+#ifdef STATS
+ s->rev.st[b->op].searchcalls++;
+#endif /* STATS */
+ /* Candidate cell list should be the same */
+ if (rip != NULL) {
+ /* Setup, sort and search the list */
+ search_list(b, rip, s->get_next_touch(s));
+ } else {
+ DBG(("Got NULL list (point outside range) for nearest search reverse cell\n"));
+ }
+ }
+
+ /* If we did get an exact solution */
+ if (b->nsoln > 0) {
+ DBG(("Deciding to return exact solution after finding clipped\n"));
+ didclip = 0; /* Reset did-clip and return exact solution */
+
+ } else {
+ DBG(("keeping clipped solution\n"));
+ /* Restore the clipped solution */
+ b->cpp[0] = c_cpp;
+ b->idist = c_idist;
+ b->iabove = c_iabove;
+ b->nsoln = c_nsoln;
+ b->pauxcell = c_pauxcell;
+ b->cdist = c_cdist;
+ b->iclip = c_iclip;
+ }
+ }
+
+ if (b->nsoln > 0) {
+ DBGV(("rev interp returning 1st soln: ",di," %f", cpp[0].p, "\n"));
+ }
+ DBG(("rev interp returning %d solutions%s\n",b->nsoln, didclip ? " [clip]" : ""));
+
+ return b->nsoln | didclip;
+}
+
+/* ------------------------------------------------------------------------------------ */
+/* Do reverse search for the auxiliary min/max ranges of the solution locus for the */
+/* given target output values. */
+/* Return number of locus segments found, up to mxsoln. 0 will be returned if no solutions */
+/* are found. */
+
+static int
+rev_locus_segs_rspl (
+ rspl *s, /* this */
+ int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no auxiliaries) */
+ co *cpp, /* Input value in cpp[0].v[] */
+ int mxsoln, /* Maximum number of solutions allowed for */
+ double min[][MXRI], /* Array of min[MXRI] to hold return segment minimum values. */
+ double max[][MXRI] /* Array of max[MXRI] to hold return segment maximum values. */
+) {
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+ int six; /* solution index */
+ int *rip = NULL;
+ int rv = 1; /* Return value */
+ schbase *b = NULL; /* Base search information */
+
+ DBGV(("rev locus called with out targets", fdi, " %f", cpp[0].v, "\n"));
+
+ /* This is a restricted size function */
+ if (di > MXRI)
+ error("rspl: rev_locus_segs can't handle di = %d",di);
+ if (fdi > MXRO)
+ error("rspl: rev_locus_segs can't handle fdi = %d",fdi);
+
+ if (mxsoln < 1) {
+ return 0; /* Guard against silliness */
+ }
+
+ if (auxm != NULL) {
+ int i;
+ double ax[MXRI];
+ for (i = 0; i < di; i++) {
+ if (auxm[i] != 0)
+ ax[i] = cpp[0].p[i];
+ else
+ ax[i] = 0.0;
+ }
+ DBGV((" auxiliaries mask", di, " %d", auxm, "\n"));
+ DBGV((" auxiliaries values", di, " %f", ax, "\n"));
+ }
+
+ /* Init default return values */
+ for (six = 0; six < mxsoln; six++) {
+ for (e = 0; e < di; e++) {
+ if (auxm[e] == 0) {
+ min[six][e] = max[six][e] = 0; /* Return 0 for unused auxiliaries */
+ } else {
+ min[six][e] = 1.0; /* max < min indicates invalid range */
+ max[six][e] = 0.0;
+ }
+ }
+ }
+
+ /* For each valid auxiliary */
+ for (e = 0; e < di; e++) {
+ if (auxm[e] == 0)
+ continue; /* Skip unsused auxiliaries */
+
+ /* Do search for min and max */
+ DBG(("rev locus searching for aux %d min/max\n", e));
+ if (b == NULL)
+ b = init_search(s, 0, cpp[0].p, auxm, cpp[0].v, NULL, cpp, mxsoln, locus);
+ else
+ set_lsearch(s, e); /* Reset locus search for next auxiliary */
+
+ if (rip == NULL) { /* Not done this yet */
+ rip = calc_fwd_cell_list(s, cpp[0].v); /* Reverse grid index for this request */
+ if (rip == NULL) {
+ DBG(("Got NULL list (point outside range) for auxiliary locus search\n"));
+ rv = 0;
+ break;
+ }
+ }
+
+ search_list(b, rip, s->get_next_touch(s)); /* Setup, sort and search the list */
+
+ if (b->min > b->max) {
+ rv = 0; /* Failed to find a result */
+ break;
+ }
+
+ if (b->asegs == 0) { /* Overall min max only */
+
+ min[0][e] = b->min; /* Save single result */
+ max[0][e] = b->max;
+
+ } else { /* Tracking auxiliary segments */
+ int si; /* Start i */
+ int i, j, ff;
+
+ /* Sort the segment list */
+#define HEAP_COMPARE(A,B) (A.xval < B.xval)
+ HEAPSORT(axisec, b->axisl, b->axisln)
+#undef HEAP_COMPARE
+
+#ifdef NEVER
+for (i = 0; i < b->axisln; i++) {
+printf("~2 xval = %f, verts = ",b->axisl[i].xval);
+for (f = 0; f < b->axisl[i].nv; f++)
+printf(" %d", b->axisl[i].vix[f]);
+printf("\n");
+}
+#endif
+ /* Find the segments by finding common verticies */
+ six = si = i = 0;
+
+ min[six][e] = b->axisl[i].xval;
+
+ for (i++; i < (b->axisln-1); i++) {
+ /* Check if any i and i-1 to j are connected */
+ for (j = i-1; j >= si; j--) {
+ for (f = 0; f < b->axisl[j].nv; f++) {
+ for (ff = 0; ff < b->axisl[i].nv; ff++) {
+ if (b->axisl[j].vix[f] == b->axisl[i].vix[ff])
+ break; /* Found a link */
+ }
+ if (ff < b->axisl[i].nv)
+ break;
+ }
+ if (f < b->axisl[j].nv)
+ break;
+ }
+ if (j < si) { /* Wasn't linked */
+ int ii, jj;
+ /* Think we found a break. Check that all the rest of */
+ /* the entries don't have any links to the previous group */
+
+ /* This could be rather a slow way of checking ! (On^2) */
+ for (ii = i+1; ii < (b->axisln); ii++) {
+ for (jj = i-1; jj >= si; jj--) {
+ for (f = 0; f < b->axisl[jj].nv; f++) {
+ for (ff = 0; ff < b->axisl[ii].nv; ff++) {
+ if (b->axisl[jj].vix[f] == b->axisl[ii].vix[ff])
+ break; /* Found a link */
+ }
+ if (ff < b->axisl[ii].nv)
+ break;
+ }
+ if (f < b->axisl[jj].nv)
+ break;
+ }
+ if (jj >= si)
+ break;
+ }
+ if (ii >= b->axisln) { /* Wasn't forward linked */
+ /* Nothing ahead links to last group */
+ max[six][e] = b->axisl[i-1].xval;
+
+ /* If we run out of solution space */
+ /* merge the last segments */
+ if ((six+1) < mxsoln) {
+ six++;
+ min[six][e] = b->axisl[i].xval;
+ }
+ }
+ }
+ }
+ max[six++][e] = b->axisl[i].xval;
+
+ if (six > rv)
+ rv = six;
+ }
+ }
+
+#ifdef STATS
+ s->rev.st[b->op].searchcalls++;
+#endif /* STATS */
+ if (rv) {
+ for (six = 0; six < rv; six++) {
+ DBG(("rev locus returning:\n"));
+ DBGV((" min", di, " %f", min[six], "\n"));
+ DBGV((" max", di, " %f", max[six], "\n"));
+ }
+ }
+
+ DBG(("rev locus returning status %d\n",rv));
+ return rv;
+}
+
+/* ------------------------------------------------------------------------------------ */
+typedef double mxdi_ary[MXRI];
+
+/* Do reverse search for the locus of the auxiliary input values given a target output. */
+/* Return 1 on finding a valid solution, and 0 if no solutions are found. */
+static int
+rev_locus_rspl(
+ rspl *s, /* this */
+ int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no auxiliaries) */
+ co *cpp, /* Input value in cpp[0].v[] */
+ double min[MXRI],/* Return minimum auxiliary values */
+ double max[MXRI] /* Return maximum auxiliary values */
+) {
+
+ /* Use segment routine to compute oveall locus */
+ return rev_locus_segs_rspl (s, auxm, cpp, 1, (mxdi_ary *)min, (mxdi_ary *)max);
+}
+
+/* ------------------------------------------------------------------------------------ */
+
+#ifdef DEBUG2
+#define DEBUG
+#undef DBG
+#undef DBGV
+#undef DBGM
+#define DBG(xxx) DBGI(xxx)
+#define DBGV(xxx) DBGVI xxx
+#define DBGM(xxx) DBGMI xxx
+#else
+#undef DEBUG
+#undef DBG
+#undef DBGV
+#undef DBGM
+#define DBG(xxx)
+#define DBGV(xxx)
+#define DBGM(xxx)
+#endif
+
+/* ------------------------------------------------ */
+/* subroutines of top level reverse lookup routine */
+
+static int exact_setsort(schbase *b, cell *c);
+static int exact_compute(schbase *b, simplex *x);
+
+static int auxil_setsort(schbase *b, cell *c);
+static int auxil_check(schbase *b, cell *c);
+static int auxil_compute(schbase *b, simplex *x);
+
+static int locus_setsort(schbase *b, cell *c);
+static int locus_check(schbase *b, cell *c);
+static int locus_compute(schbase *b, simplex *x);
+
+static int clipv_setsort(schbase *b, cell *c);
+static int clipv_check(schbase *b, cell *c);
+static int clipv_compute(schbase *b, simplex *x);
+
+static int clipn_setsort(schbase *b, cell *c);
+static int clipn_check(schbase *b, cell *c);
+static int clipn_compute(schbase *b, simplex *x);
+
+/* Allocate the search base structure */
+static schbase *
+alloc_sb(rspl *s) {
+ schbase *b;
+ if ((b = s->rev.sb = (schbase *)rev_calloc(s, 1, sizeof(schbase))) == NULL)
+ error("rspl malloc failed - rev.sb structure");
+ INCSZ(s, sizeof(schbase));
+
+ b->s = s; /* rsp */
+ b->pauxcell = /* Previous solution cell indexes */
+ b->plmaxcell =
+ b->plmincell = -1;
+
+ return b;
+}
+
+/* Free the search base structure */
+static void
+free_sb(schbase *b) {
+ DECSZ(b->s, sizeof(schbase));
+ free(b);
+}
+
+/* Do the basic search type independent initialization */
+static schbase * /* Return pointer to base search information */
+init_search(
+ rspl *s, /* rsp; */
+ int flags, /* Hint flag */
+
+ double *av, /* Auxiliary input values - may be NULL */
+ int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no auxiliaries) */
+ /* Locus search will search for max/min of first valid auxlilary */
+ double *v, /* Output value target, NULL if none */
+ double *cdir, /* Clip vector direction, NULL if none */
+ co *cpp, /* Array that hold solutions, NULL if none. */
+ int mxsoln, /* Maximum number of solutions allowed for */
+ enum ops op /* Type of reverse search operation requested */
+) {
+ schbase *b = NULL; /* Pointer to search base information structure */
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+
+ DBG(("Initializing search\n"));
+
+ if (s->rev.inited == 0) /* Compute reverse info if it doesn't exist */
+ make_rev(s);
+
+ /* If first time initialisation (Fourth section init) */
+ if ((b = s->rev.sb) == NULL) {
+ b = alloc_sb(s);
+ }
+
+ /* Init some basic search info */
+ b->op = op; /* operation */
+ b->flags = flags; /* hint flags */
+ b->canvecclip = 0; /* Assume invalid clip direction */
+
+ b->ixc = (1<<di)-1; /* Cube index of corner that holds maximum input values */
+
+ /* Figure out if auxiliaries have been requested */
+ b->naux = 0;
+ b->auxbm = 0;
+ if (auxm != NULL) {
+ unsigned bm;
+
+ if (mxsoln > 1)
+ b->asegs = 1; /* Find all segments */
+ else
+ b->asegs = 0; /* Find only overall aux locus range */
+
+ for (e = di-1, bm = 1 << e; e >= 0; e--, bm >>= 1) { /* Record auxiliary mask bits */
+ if (av != NULL)
+ b->av[e] = av[e]; /* Auxiliary target values */
+ b->auxm[e] = auxm[e]; /* Auxiliary mask */
+ if (auxm[e] != 0) {
+ b->auxbm |= bm; /* Auxiliary bit mask */
+ b->auxi[b->naux++] = e; /* Index of next auxiliary input to be used */
+ /* Auxiliary locus extent */
+ b->lxi = e; /* Assume first one */
+ b->max = -INF_DIST; /* In case searching for max */
+ b->min = INF_DIST; /* In case searching for minimum */
+ b->axisln = 0; /* No intersects in list */
+ }
+ }
+ }
+
+ /* Figure out if the clip direction is meaningfull */
+ /* Check that the clip vector makes sense */
+ if (cdir != NULL) { /* Clip vector is specified */
+ double ss;
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = cdir[f];
+ b->cdir[f] = tt;
+ ss += tt * tt;
+ }
+
+ if (ss > 1e-6) {
+ b->canvecclip = 1; /* It has a non-zero length */
+ ss = sqrt(ss);
+ /* Compute normalised clip vector direction */
+ for (f = 0; f < fdi; f++) {
+ b->ncdir[f] = b->cdir[f]/ss;
+ }
+ }
+ }
+
+ if (di <= fdi) /* Only allow auxiliaries if di > fdi */
+ b->naux = 0;
+
+ /* Switch to appropriate operation */
+ if (b->op == exact && (b->naux > 0 || di != fdi)) {
+ b->op = auxil;
+ } else if (b->op == auxil && b->naux == 0 && di == fdi) {
+ b->op = exact;
+ }
+
+ /* Set appropriate functions for type of operation */
+ switch (b->op) {
+ case exact:
+ b->setsort = exact_setsort;
+ b->check = NULL;
+ b->compute = exact_compute;
+ b->snsdi = b->ensdi = di; /* Search full dimension simplex, expect point soln. */
+ break;
+ case auxil:
+ b->setsort = auxil_setsort;
+ b->check = auxil_check;
+ b->compute = auxil_compute;
+ b->snsdi = di; /* Start here DOF = di-fdi locus solutions */
+ b->ensdi = fdi; /* End with DOF = 0 for point solutions */
+ break;
+ case locus:
+ b->setsort = locus_setsort;
+ b->check = locus_check;
+ b->compute = locus_compute;
+ b->snsdi = b->ensdi = fdi; /* Search for point solutions */
+ break;
+ case clipv:
+ b->setsort = clipv_setsort;
+ b->check = clipv_check;
+ b->compute = clipv_compute;
+ /* Clip vector 1 dimension in output space, */
+ b->snsdi = b->ensdi = fdi-1; /* search planes for combined point solution */
+ break;
+ case clipn:
+ b->setsort = clipn_setsort;
+ b->check = clipn_check;
+ b->compute = clipn_compute;
+ b->snsdi = 0; /* Start with DOF = 0 for point solutions */
+ b->ensdi = fdi-1; /* End on DOF = di-fdi-1 on surfaces of simplexes */
+ break;
+ default:
+ error("init_search: Unknown operation %d\n",b->op);
+ }
+
+ if (v != NULL) {
+ for (f = 0; f < fdi; f++) /* Record target output values */
+ b->v[f] = v[f];
+ b->v[fdi] = s->limitv; /* Limitvalue is output target for limit clip subsimplexes */
+ }
+
+ b->mxsoln = mxsoln; /* Allow solutions to be returned */
+ b->cpp = cpp; /* Put solutions here */
+ b->nsoln = 0; /* No solutions at present */
+ b->iclip = 0; /* Default solution isn't above ink limit */
+
+ if (flags & RSPL_EXACTAUX) /* Expect to be able to match auxiliary target exactly */
+ b->idist = 2.0 * EPS; /* Best input distance to beat - helps sort/triage */
+ else
+ b->idist = INF_DIST; /* Best input distance to beat. */
+ b->iabove = 0; /* Best isn't known to be above (yet) */
+
+ b->cdist = INF_DIST; /* Best clip distance to beat. */
+
+ DBG(("Search initialized\n"));
+
+ return b;
+}
+
+/* Adjust the search */
+static void
+adjust_search(
+ rspl *s, /* rsp; */
+ int flags, /* Hint flag */
+ double *av, /* Auxiliary input values - may be NULL */
+ enum ops op /* Type of reverse search operation requested */
+) {
+ schbase *b = s->rev.sb; /* Pointer to search base information structure */
+ int e, di = s->di;
+ int fdi = s->fdi;
+
+ DBG(("Adjusting search\n"));
+
+ b->op = op; /* operation */
+ b->flags = flags; /* hint flags */
+
+ /* Switch from exact to aux if we need to */
+ if (b->op == exact && (b->naux > 0 || di != fdi)) {
+ b->op = auxil;
+ } else if (b->op == auxil && b->naux == 0 && di == fdi) {
+ b->op = exact;
+ }
+
+ /* Update auxiliary target values */
+ if (av != NULL) {
+ for (e = 0; e < b->naux; e++) {
+ int ee = b->auxi[e];
+ b->av[ee] = av[ee];
+ }
+ }
+
+ /* Set appropriate functions for type of operation */
+ switch (b->op) {
+ case exact:
+ b->setsort = exact_setsort;
+ b->check = NULL;
+ b->compute = exact_compute;
+ b->snsdi = b->ensdi = di; /* Expect point solution */
+ break;
+ case auxil:
+ b->setsort = auxil_setsort;
+ b->check = auxil_check;
+ b->compute = auxil_compute;
+ b->snsdi = di; /* Start here DOF = di-fdi locus solutions */
+ b->ensdi = fdi; /* End with DOF = 0 for point solutions, */
+ break; /* will early exit DOF if good soln found. */
+ case locus:
+ b->setsort = locus_setsort;
+ b->check = locus_check;
+ b->compute = locus_compute;
+ b->snsdi = b->ensdi = fdi; /* Search for point solutions */
+ break;
+ case clipv:
+ b->setsort = clipv_setsort;
+ b->check = clipv_check;
+ b->compute = clipv_compute;
+ /* Clip vector 1 dimension in output space, */
+ b->snsdi = b->ensdi = fdi-1; /* so the intersection with the simplex is a point. */
+ break;
+ case clipn:
+ b->setsort = clipn_setsort;
+ b->check = clipn_check;
+ b->compute = clipn_compute;
+ b->snsdi = 0; /* Start with DOF = 0 for point solutions */
+ b->ensdi = fdi-1; /* End on DOF = di-fdi-1 on surfaces of simplexes */
+ break; /* Will go through all DOF */
+ default:
+ error("init_search: Unknown operation %d\n",b->op);
+ }
+
+ b->nsoln = 0; /* No solutions at present */
+
+ if (flags & RSPL_EXACTAUX) /* Expect to be able to match auxiliary target exactly */
+ b->idist = 2.0 * EPS; /* Best input distance to beat - helps sort/triage */
+ else
+ b->idist = INF_DIST; /* Best input distance to beat. */
+ b->iabove = 0; /* Best isn't known to be above (yet) */
+
+ b->cdist = INF_DIST; /* Best clip distance to beat. */
+
+ DBG(("Search adjusted\n"));
+}
+
+/* Adjust existing locus search for a different auxiliary */
+static void
+set_lsearch(
+rspl *s,
+int e /* Next auxiliary */
+) {
+ schbase *b = s->rev.sb; /* Pointer to search base information structure */
+
+ b->lxi = e; /* Assume first one */
+ b->max = -INF_DIST; /* In case searching for max */
+ b->min = INF_DIST; /* In case searching for minimum */
+ b->axisln = 0; /* No intersects in list */
+}
+
+/* Set the limit search information */
+/* Note this doesn't create or init the main rev information. */
+static schbase * /* Return pointer to base search information */
+set_search_limit(
+ rspl *s, /* rsp; */
+ double (*limitf)(void *vcntx, double *in), /* Optional input space limit function. Function */
+ /* should evaluate in[0..di-1], and return number that is not to exceed */
+ /* limitv. NULL if not used */
+ void *lcntx, /* Context passed to limit() */
+ double limitv /* Value that limit() is not to exceed */
+) {
+ schbase *b = NULL; /* Pointer to search base information structure */
+
+ /* If sb info needs initialising (Fourth section init) */
+ if ((b = s->rev.sb) == NULL) {
+ b = alloc_sb(s);
+ }
+
+ s->limitf = limitf; /* Input limit function */
+ s->lcntx = lcntx; /* Context passed to limit() */
+ s->limitv= INKSCALE * limitv; /* Context passed to values not to be exceedded by limit() */
+ if (limitf != NULL) {
+ s->limiten = 1; /* enable limiting by default */
+ } else
+ s->limiten = 0; /* No limit function, so limiting not enabled. */
+
+ return b;
+}
+
+/* Free any search specific data, plus the search base. */
+static void
+free_search(
+schbase *b /* Base search information */
+) {
+ DBG(("Freeing search\n"));
+
+ /* Clip line implicit equation (incuding space for ink target) */
+ if (b->cla != NULL) {
+ int fdi = b->s->fdi;
+ free_dmatrix(b->cla, 0, fdi-1, 0, fdi);
+ b->cla = NULL;
+ }
+
+ /* Auxiliary segment list */
+ if (b->axislz > 0) {
+ free(b->axisl);
+ DECSZ(b->s, b->axislz * sizeof(axisec));
+ b->axisl = NULL;
+ b->axislz = 0;
+ b->axisln = 0;
+ }
+
+ /* Sorted cell list */
+ if (b->lclistz > 0) {
+ free(b->lclist);
+ DECSZ(b->s, b->lclistz * sizeof(cell *));
+ b->lclist = NULL;
+ b->lclistz = 0;
+ }
+
+ /* Simplex filter list */
+ if (b->lsxfilt > 0) {
+ free(b->sxfilt);
+ DECSZ(b->s, b->lsxfilt * sizeof(char));
+ b->sxfilt = NULL;
+ b->lsxfilt = 0;
+ }
+
+ free_sb(b);
+}
+
+/* Return the pointer to the list of fwd cells given */
+/* the target output values. The pointer will be to the first */
+/* index in the list (ie. list address + 3) */
+/* Return NULL if none in list (out of gamut). */
+static int *
+calc_fwd_cell_list(
+ rspl *s, /* this */
+ double *v /* Output values */
+) {
+ int f, fdi = s->fdi;
+ int **rpp;
+ int rgres_1 = s->rev.res - 1;
+
+ if (s->rev.rev_valid == 0)
+ init_revaccell(s);
+
+ for (rpp = s->rev.rev, f = 0; f < fdi; f++) {
+ int mi;
+ double t = (v[f] - s->rev.gl[f])/s->rev.gw[f];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0 || mi > rgres_1) { /* If outside valid reverse range */
+ return NULL;
+ }
+ rpp += mi * s->rev.coi[f]; /* Accumulate reverse grid pointer */
+ }
+ if (*rpp == NULL)
+ return NULL;
+ return (*rpp) + 3;
+}
+
+void alloc_simplexes(cell *c, int nsdi);
+
+/* Given a pointer to a list of fwd cells, cull cells that */
+/* cannot contain or improve the solution, sort the list, */
+/* and then compute the final best solution. */
+static void
+search_list(
+schbase *b, /* Base search information */
+int *rip, /* Pointer to first index in cell list */
+unsigned int tcount /* grid touch count for this operation */
+) {
+ rspl *s = b->s;
+ int nsdi;
+ int i;
+ int nilist; /* Number in cell list */
+ unsigned int stouch; /* Simplex touch count */
+
+ DBG(("search_list called\n"));
+
+ /* (rip[-3] contains allocation for fwd cells in the list) */
+ /* (rip[-2] contains the index of the next free entry in the list) */
+ /* (rip[-1] contains the reference count for the list) */
+ if (b->lclistz < rip[-3]) { /* Allocate more space if needed */
+
+ if (b->lclistz > 0) { /* Free old space before allocating new */
+ free(b->lclist);
+ DECSZ(b->s, b->lclistz * sizeof(cell *));
+ }
+ b->lclistz = 0;
+ /* Allocate enough space for all the candidate cells */
+ if ((b->lclist = (cell **)rev_malloc(s, rip[-3] * sizeof(cell *))) == NULL)
+ error("rev: malloc failed - candidate cell list, count %d",rip[-3]);
+ b->lclistz = rip[-3]; /* Current allocated space */
+ INCSZ(b->s, b->lclistz * sizeof(cell *));
+ }
+
+ /* Get the next simplex touch count, so that we don't search shared */
+ /* face simplexes more than once in this pass through the cells. */
+ if ((stouch = ++s->rev.stouch) == 0) { /* If touch count rolls over */
+ cell *cp;
+ stouch = s->rev.stouch = 1;
+
+ DBG(("touch has rolled over, resetting it\n"));
+ /* For all of the cells */
+ for (cp = s->rev.cache->mrubot; cp != NULL; cp = cp->mruup) {
+ int nsdi;
+
+ if (cp->s == NULL) /* Cell has never been used */
+ continue;
+
+ /* For all the simplexes in the cell */
+ for (nsdi = 0; nsdi <= s->di; nsdi++) {
+ if (cp->sx[nsdi] != NULL) {
+ int si;
+
+ for (si = 0; si < cp->sxno[nsdi]; si++) {
+ cp->sx[nsdi][si]->touch = 0;
+ }
+ }
+ }
+ }
+ }
+
+ /* For each chunk of the list that we can fit in the rcache: */
+ for(; *rip != -1;) {
+
+ /* Go through all the candidate fwd cells, and build up the list of search cells */
+ for(nilist = 0; *rip != -1; rip++) {
+ int ix = *rip; /* Fwd cell index */
+ float *fcb = s->g.a + ix * s->g.pss; /* Pointer to base float of fwd cell */
+ cell *c;
+
+ if (TOUCHF(fcb) >= tcount) { /* If we have visited this cell before */
+ DBG((" Already touched cell index %d\n",ix));
+ continue;
+ }
+ /* Get pointers to cells from cache, and lock it in the cache */
+ if ((c = get_rcell(b, ix, nilist == 0 ? 1 : 0)) == NULL) {
+ static int warned = 0;
+ if (!warned) {
+ warning("%cWarning - Reverse Cell Cache exausted, processing in chunks",cr_char);
+ warned = 1;
+ }
+ DBG(("revcache is exausted, do search in chunks\n"));
+ if (nilist == 0) {
+ /* This should never happen, because nz force should prevent it */
+ revcache *rc = s->rev.cache;
+ cell *cp;
+ int nunlk = 0;
+ /* Double check that there are no unlocked cells */
+ for (cp = rc->mrubot; cp != NULL && cp->refcount > 0; cp = cp->mruup) {
+ if (cp->refcount == 0)
+ nunlk++;
+ }
+ fprintf(stdout,"Diagnostic: rev.sz = %lu, rev.max_sz = %lu, numlocked = %d, nunlk = %d\n",
+ rc->s->rev.sz, rc->s->rev.max_sz, rc->nunlocked,nunlk);
+ error("Not enough memory to process in chunks");
+ }
+ break; /* cache has run out of room, so abandon, and do it next time */
+ }
+
+ DBG(("checking out cell %d range %s\n",ix,pcellorange(c)));
+ TOUCHF(fcb) = tcount; /* Touch it */
+
+ /* Check mandatory conditions, and compute search key */
+ if (!b->setsort(b, c)) {
+ DBG(("cell %d rejected from list\n",ix));
+ unget_rcell(s->rev.cache, c);
+ continue;
+ }
+ DBG(("cell %d accepted into list\n",ix));
+
+ b->lclist[nilist++] = c; /* Cell is accepted as recursion candidate */
+ }
+
+ if (nilist == 0) {
+ DBG(("List was empty\n"));
+ }
+
+#ifdef DOSORT
+ /* If appropriate, sort child cells into best order */
+ /* == sort key smallest to largest */
+ switch (b->op) {
+ case locus:
+ { /* Special case, adjust sort values */
+ double min = INF_DIST, max = -INF_DIST;
+ for (i = 0; i < nilist; i++) {
+ cell *c = b->lclist[i];
+ if (c->sort < min)
+ min = c->sort;
+ if (c->sort > max)
+ max = c->sort;
+ }
+ max = min + max; /* Total of min/max */
+ min = 0.5 * max; /* Average sort value */
+ for (i = 0; i < nilist; i++) {
+ cell *c = b->lclist[i];
+ if (c->ix == b->plmincell || c->ix == b->plmaxcell) {
+ c->sort = -1.0; /* Put previous solution cells at head of list */
+ } else if (c->sort > min) {
+ c->sort = max - c->sort; /* Reflect about average */
+ }
+ }
+ }
+ /* Fall through to sort */
+ case auxil:
+ case clipv:
+ case clipn:
+#define HEAP_COMPARE(A,B) (A->sort < B->sort)
+ HEAPSORT(cell *,b->lclist, nilist)
+#undef HEAP_COMPARE
+ break;
+ default:
+ break;
+ }
+#endif /* DOSORT */
+
+ DBG(("List sorted, about to search\n"));
+#ifdef NEVER
+ printf("\n~1 Op = %s, Cell sort\n",opnames[b->op]);
+ for (i = 0; i < nilist; i++) {
+ printf("~1 List %d, cell %d, sort = %f\n",i,b->lclist[i]->ix,b->lclist[i]->sort);
+ }
+#endif /* NEVER */
+
+ /*
+ Tried reversing the "for each cell" and "for each level" loops,
+ but it made a negligible difference to the performance.
+ We choose to have cell on the outer so that we can unlock
+ them as we go, so that they may be freed, even though
+ this is a couple of percent slower (?).
+ */
+
+ /* For each cell in the list */
+ for (i = 0; i < nilist; i++) {
+ cell *c = b->lclist[i];
+
+#ifdef STATS
+ s->rev.st[b->op].csearched++;
+#endif /* STATS */
+
+ /* For each dimensionality of sub-simplexes, in given order */
+ DBG(("Searching from level %d to level %d\n",b->snsdi, b->ensdi));
+ for (nsdi = b->snsdi;;) {
+ int j, nospx; /* Number of simplexes in cell */
+
+ DBG(("\n******************\n"));
+ DBG(("Searching level %d\n",nsdi));
+
+ /* For those searches that have an optimisation goal, */
+ /* re-check the cell to see if the goal can still improve on. */
+ if (b->check != NULL && !b->check(b, c))
+ break;
+
+ if (c->sx[nsdi] == NULL) {
+ alloc_simplexes(c, nsdi); /* Do level 1 initialisation for nsdi */
+ }
+
+ /* For each simplex in a cell */
+ nospx = c->sxno[nsdi]; /* Number of nsdi simplexes */
+ for (j = 0; j < nospx; j++) {
+ simplex *x = c->sx[nsdi][j];
+
+ if (x->touch >= stouch) {
+ continue; /* We've already seen this one */
+ }
+
+ if (s->limiten == 0) {
+ if (x->flags & SPLX_CLIPSX) /* If limiting is disabled, we're */
+ continue; /* not interested in clip plane simplexes */
+ }
+#ifdef STATS
+ s->rev.st[b->op].ssearched++;
+#endif /* STATS */
+ if (b->compute(b, x)) {
+ DBG(("search aborted by compute\n"));
+ break; /* Found enough solutions */
+ }
+ x->touch = stouch; /* Don't look at it again */
+
+ } /* Next Simplex */
+
+ if (nsdi == b->ensdi)
+ break; /* We're done with levels */
+
+ /* Next Simplex dimensionality */
+ if (b->ensdi < b->snsdi) {
+ if (nsdi == b->snsdi && b->nsoln > 0
+ && (b->op != auxil || b->idist <= 2.0 * EPS))
+ break; /* Don't continue though decreasing */
+ /* sub-simplex dimensions if we found a solution at */
+ /* the highest dimension level. */
+ nsdi--;
+ } else if (b->ensdi > b->snsdi) {
+ nsdi++; /* Continue through increasing sub-simplex dimenionality */
+ } /* until we get to the top. */
+ }
+ /* Unlock the cache cell now that we're done with it */
+ unget_rcell(s->rev.cache, b->lclist[i]);
+ } /* Next cell */
+
+ } /* Next chunk */
+
+ DBG(("search_list complete\n"));
+ return;
+}
+
+/* ------------------------------------- */
+/* Vector search in output space support */
+
+/* Setup the line, and fetch the first cell */
+/* Return the pointer to the list of fwd cells, NULL if none in list. */
+static int *
+init_line(
+ rspl *s, /* this */
+ line *l, /* line structure */
+ double st[MXRO], /* start of line */
+ double de[MXRO] /* line direction and length */
+) {
+ int f, fdi = s->fdi;
+ int **rpp;
+ int rgres_1 = s->rev.res - 1;
+ int nvalid = 0; /* Flag set if outside reverse grid range */
+
+ DBGV(("Line from ", fdi, " %f", st, "\n"));
+ DBGV(("In dir ", fdi, " %f", de, "\n"));
+ DBGV(("gl ", fdi, " %f", s->rev.gl, "\n"));
+ DBGV(("gh ", fdi, " %f", s->rev.gh, "\n"));
+ DBGV(("gw ", fdi, " %f", s->rev.gw, "\n"));
+
+ /* Init */
+ l->s = s;
+ for (f = 0; f < fdi; f++) {
+ l->st[f] = st[f] - s->rev.gl[f];
+ l->de[f] = de[f];
+ if (de[f] > 0.0)
+ l->di[f] = 1; /* Axis increments */
+ else if (de[f] < 0.0)
+ l->di[f] = -1;
+ else
+ l->di[f] = 0;
+ }
+ l->t = 0.0;
+ DBGV(("increments =", fdi, " %d", l->di, "\n"));
+
+ /* Figure out the starting cell */
+ for (rpp = s->rev.rev, f = 0; f < fdi; f++) {
+ double t = l->st[f]/s->rev.gw[f];
+ l->ci[f] = (int)floor(t); /* Grid coordinate */
+ if (l->ci[f] < 0 || l->ci[f] > rgres_1) /* If outside valid reverse range */
+ nvalid = 1;
+ rpp += l->ci[f] * s->rev.coi[f]; /* Accumulate reverse grid pointer */
+ }
+ DBGV(("current line cell = ", fdi, " %d", l->ci, "")); DBG((", t = %f, nvalid = %d\n",l->t,nvalid));
+#ifdef DEBUG
+{
+int ii;
+double tt;
+printf("Current cell = ");
+for (ii = 0; ii < fdi; ii++) {
+ tt = l->ci[ii] * s->rev.gw[ii] + s->rev.gl[ii];
+ printf(" %f - %f",tt,tt+s->rev.gw[ii]);
+}
+printf("\n");
+}
+#endif /* DEBUG */
+ if (nvalid)
+ return NULL;
+ if (*rpp == NULL)
+ return NULL;
+ return *rpp + 3;
+}
+
+/* Get the next cell on the line. */
+/* Return the pointer to the list of fwd cells, NULL if none in list. */
+static int *
+next_line_cell(
+ line *l /* line structure */
+) {
+ rspl *s = l->s;
+ int bf = 0, f, fdi = s->fdi;
+ int **rpp;
+ int rgres_1 = s->rev.res - 1;
+ double bt = 100.0; /* Best (smalest +ve) parameter value to move */
+
+ /* See which axis cell crossing we will hit next */
+ for (f = 0; f < fdi; f++) {
+ double t;
+ if (l->de[f] != 0) {
+ t = ((l->ci[f] + l->di[f]) * s->rev.gw[f] - l->st[f])/l->de[f];
+ DBG(("t for dim %d = %f\n",f,t));
+ if (t < bt) {
+ bt = t;
+ bf = f; /* Best direction to move */
+ }
+ }
+ }
+
+ /* Move to the next reverse grid coordinate */
+ l->ci[bf] += l->di[bf];
+ l->t = bt;
+
+ DBGV(("current line cell =", fdi, " %d", l->ci, "")); DBG((", t = %f\n",l->t));
+
+#ifdef DEBUG
+{
+int ii;
+double tt;
+printf("Current cell = ");
+for (ii = 0; ii < fdi; ii++) {
+ tt = l->ci[ii] * s->rev.gw[ii] + s->rev.gl[ii];
+ printf(" %f - %f",tt,tt+s->rev.gw[ii]);
+}
+printf("\n");
+}
+#endif /* DEBUG */
+
+ /* Compute reverse cell index */
+ for (rpp = s->rev.rev, f = 0; f < fdi; f++) {
+ if (l->ci[f] < 0 || l->ci[f] > rgres_1) { /* If outside valid reverse range */
+ DBG(("Outside list on dim %d, 0 <= %d <= %d\n", f, l->ci[f],rgres_1));
+ return NULL;
+ }
+ rpp += l->ci[f] * s->rev.coi[f]; /* Accumulate reverse grid pointer */
+ }
+ if (*rpp == NULL)
+ return NULL;
+ return *rpp + 3;
+}
+
+/* ------------------------------------- */
+/* Clip nearest support. */
+
+/* Track candidate cells nearest and furthest */
+struct _nncell_nf{
+ double n, f;
+}; typedef struct _nncell_nf nncell_nf;
+
+/* Given and empty nnrev index, create a list of */
+/* the forward cells that may contain the nearest value by */
+/* using and exaustive search. This is used for faststart. */
+static void fill_nncell(
+ rspl *s,
+ int *co, /* Integer coords of cell to be filled */
+ int ix /* Index of cell to be filled */
+) {
+ int i;
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+ double cc[MXDO]; /* Cell center */
+ double rr = 0.0; /* Cell radius */
+ int **rpp, *rp;
+ int gno = s->g.no;
+ float *gp; /* Pointer to fwd grid points */
+ nncell_nf *nf; /* cloase and far distances corresponding to list */
+ double clfu = 1e38; /* closest furthest distance in list */
+
+ rpp = s->rev.nnrev + ix;
+ rp = *rpp;
+
+ /* Compute the center location and radius of the target cell */
+ for (f = 0; f < fdi; f++) {
+ cc[f] = s->rev.gw[f] * (co[f] + 0.5) + s->rev.gl[f];
+ rr += 0.25 * s->rev.gw[f] * s->rev.gw[f];
+ }
+ rr = sqrt(rr);
+//printf("~1 fill_nncell() cell ix %d, coord %d %d %d, cent %f %f %f, rad %f\n",
+//ix, co[0], co[1], co[2], cc[0], cc[1], cc[2], rr);
+//printf("~1 total of %d fwd cells\n",gno);
+
+ /* For all the forward cells: */
+ for (gp = s->g.a, i = 0; i < gno; gp += s->g.pss, i++) {
+ int ee;
+ int uil; /* One is under the ink limit */
+ double dn, df; /* Nearest and farthest distance of fwd cell values */
+
+ /* Skip cubes that are on the outside edge of the grid */
+ for (e = 0; e < di; e++) {
+ if(G_FL(gp, e) == 0) /* At the top edge */
+ break;
+ }
+ if (e < di) { /* Top edge - skip this cube */
+ continue;
+ }
+
+ /* Compute the closest and furthest distances of nodes of current cell */
+ dn = 1e38, df = 0.0;
+ for (uil = ee = 0; ee < (1 << di); ee++) { /* For all grid points in the cube */
+ double r;
+ float *gt = gp + s->g.fhi[ee]; /* Pointer to cube vertex */
+
+ if (!s->limiten || gt[-1] <= s->limitv)
+ uil = 1;
+
+ /* Update bounding box for this grid point */
+ for (r = 0.0, f = 0; f < fdi; f++) {
+ double tt = cc[f] - (double)gt[f];
+ r += tt * tt;
+ }
+//printf("~1 grid location %f %f %f rad %f\n",gt[0],gt[1],gt[2],sqrt(r));
+ if (r < dn)
+ dn = r;
+ if (r > df)
+ df = r;
+ }
+ /* Skip any fwd cells that are over the ink limit */
+ if (!uil)
+ continue;
+
+ dn = sqrt(dn) - rr;
+ df = sqrt(df) + rr;
+
+//printf("~1 checking cell %d, near %f, far %f\n",i,dn,df);
+
+ /* Skip any that have a closest distance larger that the lists */
+ /* closest furthest distance. */
+ if (dn > clfu) {
+//printf("~1 skipping cell %d, near %f, far %f clfu %f\n",i,dn,df,clfu);
+ continue;
+ }
+
+//printf("~1 adding cell %d\n",i);
+ if (rp == NULL) {
+ if ((nf = (nncell_nf *) rev_malloc(s, 6 * sizeof(nncell_nf))) == NULL)
+ error("rspl malloc failed - nncell_nf list");
+ INCSZ(s, 6 * sizeof(nncell_nf));
+ if ((rp = (int *) rev_malloc(s, 6 * sizeof(int))) == NULL)
+ error("rspl malloc failed - rev.grid entry");
+ INCSZ(s, 6 * sizeof(int));
+ *rpp = rp;
+ rp[0] = 6; /* Allocation */
+ rp[1] = 4; /* Next empty cell */
+ rp[2] = 1; /* Reference count */
+ rp[3] = i;
+ nf[3].n = dn;
+ nf[3].f = df;
+ rp[4] = -1;
+ } else {
+ int z = rp[1], ll = rp[0];
+ if (z >= (ll-1)) { /* Not enough space */
+ INCSZ(s, ll * sizeof(nncell_nf));
+ INCSZ(s, ll * sizeof(int));
+ ll *= 2;
+ if ((nf = (nncell_nf *) rev_realloc(s, nf, sizeof(nncell_nf) * ll)) == NULL)
+ error("rspl realloc failed - nncell_nf list");
+ if ((rp = (int *) rev_realloc(s, rp, sizeof(int) * ll)) == NULL)
+ error("rspl realloc failed - rev.grid entry");
+ *rpp = rp;
+ rp[0] = ll;
+ }
+ rp[z] = i;
+ nf[z].n = dn;
+ nf[z++].f = df;
+ rp[z] = -1;
+ rp[1] = z;
+ }
+
+ if (df < clfu)
+ clfu = df;
+ }
+//printf("~1 Current list is:\n");
+//for (e = 3; rp[e] != -1; e++)
+//printf(" %d: Cell %d near %f far %f\n",e,rp[e],nf[e].n,nf[e].f);
+
+ /* Now filter out any cells that have a closest point that is further than */
+ /* closest furthest point */
+ {
+ int z, w, ll = rp[0];
+
+ /* For all the cells in the current list: */
+ for (w = z = 3; rp[z] != -1; z++) {
+
+ /* If the new cell nearest is greater than the existing cell closest, */
+ /* then don't omit existing cell from the list. */
+ if (clfu >= nf[z].n) {
+ rp[w] = rp[z];
+ nf[w].n = nf[z].n;
+ nf[w].f = nf[z].f;
+ w++;
+ }
+//else printf("~1 deleting cell %d because %f >= %f\n",rp[z],clfu, nf[z].f);
+ }
+ rp[w] = rp[z];
+ }
+//printf("~1 Current list is:\n");
+//for (e = 3; rp[e] != -1; e++)
+//printf(" %d: Cell %d near %f far %f\n",e,rp[e],nf[e].n,nf[e].f);
+ free(nf);
+//printf("~1 Done\n");
+}
+
+/* Return the pointer to the list of nearest fwd cells given */
+/* the target output values. The pointer will be to the first */
+/* index in the list (ie. list address + 3) */
+/* Return NULL if none in list (out of gamut). */
+static int *
+calc_fwd_nn_cell_list(
+ rspl *s, /* this */
+ double *v /* Output values */
+) {
+ int f, fdi = s->fdi, ix;
+ int **rpp;
+ int rgres_1 = s->rev.res - 1;
+ int mi[MXDO];
+
+ if (s->rev.rev_valid == 0)
+ init_revaccell(s);
+
+ for (ix = 0, f = 0; f < fdi; f++) {
+ double t = (v[f] - s->rev.gl[f])/s->rev.gw[f];
+ mi[f] = (int)floor(t); /* Grid coordinate */
+ if (mi[f] < 0) /* Clip to reverse range, so we always return a result */
+ mi[f] = 0;
+ else if (mi[f] > rgres_1)
+ mi[f] = rgres_1;
+ ix += mi[f] * s->rev.coi[f]; /* Accumulate reverse grid index */
+ }
+ rpp = s->rev.nnrev + ix;
+ if (*rpp == NULL) {
+ if (s->rev.fastsetup)
+ fill_nncell(s, mi, ix);
+ if (*rpp == NULL)
+ rpp = s->rev.rev + ix; /* fall back to in-gamut lookup */
+ }
+ if (*rpp == NULL)
+ return NULL;
+ return (*rpp) + 3;
+}
+
+/* =================================================== */
+/* The cell and simplex solver top level routines */
+
+static int add_lu_svd(simplex *x);
+static int add_locus(schbase *b, simplex *x);
+static int add_auxil_lu_svd(schbase *b, simplex *x);
+static int within_simplex(simplex *x, double *p);
+static void simplex_to_abs(simplex *x, double *in, double *out);
+
+static int auxil_solve(schbase *b, simplex *x, double *xp);
+
+/* ---------------------- */
+/* Exact search functions */
+/* Return non-zero if cell is acceptable */
+static int exact_setsort(schbase *b, cell *c) {
+ rspl *s = b->s;
+ int f, fdi = s->fdi;
+ double ss;
+
+ DBG(("Reverse exact search, evaluate and set sort key on cell\n"));
+
+ /* Check that the target lies within the cell bounding sphere */
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = c->bcent[f] - b->v[f];
+ ss += tt * tt;
+ }
+ if (ss > c->bradsq) {
+ DBG(("Cell rejected - %s outside sphere c %s rad %f\n",icmPdv(fdi,b->v),icmPdv(fdi,c->bcent),sqrt(c->bradsq)));
+ return 0;
+ }
+
+ if (s->limiten != 0 && c->limmin > s->limitv) {
+ DBG(("Cell is rejected - ink limit, min = %f, limit = %f\n",c->limmin,s->limitv));
+ return 0;
+ }
+
+ /* Sort can't be used, because we return all solutions */
+ c->sort = 0.0;
+
+ DBG(("Cell is accepted\n"));
+
+ return 1;
+}
+
+/* Compute a solution for a given sub-simplex (if there is one) */
+/* Return 1 if search should be aborted */
+static int exact_compute(schbase *b, simplex *x) {
+ rspl *s = b->s;
+ int e, di = s->di, sdi = x->sdi;
+ int f, fdi = s->fdi;
+ int i;
+ datai xp; /* solution in simplex relative coord order */
+ datai p; /* absolute solution */
+ int wsrv; /* Within simplex return value */
+
+ DBG(("\nExact: computing possible solution\n"));
+
+#ifdef DEBUG
+ /* Sanity check */
+ if (sdi != fdi || sdi != di || x->efdi != fdi) {
+ printf("di = %d, fdi = %d\n",di,fdi);
+ printf("sdi = %d, efdi = %d\n",sdi,x->efdi);
+ error("rspl exact reverse interp called with sdi != fdi, sdi != di, efdi != fdi");
+ /* !!! could switch to SVD solution if di != fdi ?? !!! */
+ }
+#endif
+
+ /* This may not be worth it here since it may not filter out */
+ /* many more simplexes than the cube check did. */
+ /* This is due to full dimension simplexes all sharing the main */
+ /* diagonal axis. */
+
+ /* Check that the target lies within the simplex bounding cube */
+ for (f = 0; f < fdi; f++) {
+ if (b->v[f] < x->min[f] || b->v[f] > x->max[f]) {
+ DBG(("Simplex is rejected - bounding cube\n"));
+ return 0;
+ }
+ }
+
+ /* Create the LU decomp needed to exactly solve */
+ if (add_lu_svd(x)) {
+ DBG(("LU decomp was singular, skip simplex\n"));
+ return 0;
+ }
+
+ /* Init the RHS B[] vector (note di == fdi) */
+ for (f = 0; f < fdi; f++) {
+ xp[f] = b->v[f] - x->v[di][f];
+ }
+
+ /* Compute the solution (in simplex space) */
+ lu_backsub(x->d_u, sdi, (int *)x->d_w, xp);
+
+ /* Check that the solution is within the simplex */
+ if ((wsrv = within_simplex(x, xp)) == 0) {
+ DBG(("Solution rejected because not in simplex\n"));
+ return 0;
+ }
+
+ /* Convert solution from simplex relative to absolute space */
+ simplex_to_abs(x, p, xp);
+
+ /* Check if a very similiar input solution has been found before */
+ for (i = 0; i < b->nsoln; i++) {
+ double tt;
+ for (e = 0; e < di; e++) {
+ tt = b->cpp[i].p[e] - p[e];
+ if (fabs(tt) > (2 * EPS))
+ break; /* Mismatch */
+ }
+ if (e >= di) /* Found good match */
+ break;
+ }
+
+ /* Probably alias caused by solution lying close to a simplex boundary */
+ if (i < b->nsoln) {
+ DBG(("Another solution has been found before - index %d\n",i));
+ return 0; /* Skip this, since betters been found before */
+ }
+
+ /* Check we haven't overflowed space */
+ if (i >= b->mxsoln) {
+ DBG(("Run out of space for new solution\n"));
+ return 1; /* Abort */
+ }
+
+ DBG(("######## Accepting new solution\n"));
+
+ /* Put solution in place */
+ for (e = 0; e < di; e++)
+ b->cpp[i].p[e] = p[e];
+ for (f = 0; f < fdi; f++)
+ b->cpp[i].v[f] = b->v[f]; /* Assumed to be an exact solution */
+ if (i == b->nsoln)
+ b->nsoln++;
+ if (wsrv == 2) /* Is above (disabled) ink limit */
+ b->iclip = 1;
+ return 0;
+}
+
+/* -------------------------- */
+/* Auxiliary search functions */
+static int auxil_setsort(schbase *b, cell *c) {
+ rspl *s = b->s;
+ int f, fdi = b->s->fdi;
+ int ee, ixc = b->ixc;
+ double ss, sort, nabove;
+
+ DBG(("Reverse auxiliary search, evaluate and set sort key on cell\n"));
+
+ if (b->s->di <= fdi) { /* Assert */
+ error("rspl auxiliary reverse interp called with di <= fdi (%d %d)", b->s->di, fdi);
+ }
+
+ /* Check that the target lies within the cell bounding sphere */
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = c->bcent[f] - b->v[f];
+ ss += tt * tt;
+ }
+ if (ss > c->bradsq) {
+ DBG(("Cell rejected - %s outside sphere c %s rad %f\n",icmPdv(fdi,b->v),icmPdv(fdi,c->bcent),sqrt(c->bradsq)));
+ return 0;
+ }
+
+ if (s->limiten != 0 && c->limmin > s->limitv) {
+ DBG(("Cell is rejected - ink limit, min = %f, limit = %f\n",c->limmin,s->limitv));
+ return 0;
+ }
+
+ /* Check if this cell could possible improve b->idist */
+ /* and compute sort key as the distance to auxilliary target */
+ /* (We may have a non INF_DIST idist before commencing the */
+ /* search if we already know that the auxiliary target is */
+ /* within gamut - the usual usage case!) */
+ for (sort = 0.0, nabove = ee = 0; ee < b->naux; ee++) {
+ int ei = b->auxi[ee];
+ double tt = (c->p[0][ei] + c->p[ixc][ei]) - b->av[ei];
+ sort += tt * tt;
+ if (c->p[ixc][ei] >= (b->av[ei] - EPS)) /* Could be above */
+ nabove++;
+ }
+
+ if (b->flags & RSPL_MAXAUX && nabove < b->iabove) {
+ DBG(("Doesn't contain solution that has as many aux above auxiliary goal\n"));
+ return 0;
+ }
+ if (!(b->flags & RSPL_MAXAUX) || nabove == b->iabove) {
+ for (ee = 0; ee < b->naux; ee++) {
+ int ei = b->auxi[ee];
+ if (c->p[0][ei] >= (b->av[ei] + b->idist)
+ || c->p[ixc][ei] <= (b->av[ei] - b->idist)) {
+ DBG(("Doesn't contain solution that will be closer to auxiliary goal\n"));
+ return 0;
+ }
+ }
+ }
+ c->sort = sort + 0.01 * ss;
+
+ if (c->ix == b->pauxcell)
+ c->sort = -1.0; /* Put previous calls solution cell at top of sort list */
+
+ DBG(("Cell is accepted\n"));
+ return 1;
+}
+
+/* Re-check whether it's worth searching cell */
+static int auxil_check(schbase *b, cell *c) {
+ int ee, ixc = b->ixc, nabove;
+
+ DBG(("Reverse auxiliary search, re-check cell\n"));
+
+ /* Check if this cell could possible improve b->idist */
+ /* and compute sort key as the distance to auxilliary target */
+
+ for (nabove = ee = 0; ee < b->naux; ee++) {
+ int ei = b->auxi[ee];
+ if (c->p[ixc][ei] >= (b->av[ei] - EPS)) /* Could be above */
+ nabove++;
+ }
+
+ if (b->flags & RSPL_MAXAUX && nabove < b->iabove) {
+ DBG(("Doesn't contain solution that has as many aux above auxiliary goal\n"));
+ return 0;
+ }
+ if (!(b->flags & RSPL_MAXAUX) || nabove == b->iabove) {
+ for (ee = 0; ee < b->naux; ee++) {
+ int ei = b->auxi[ee];
+ if (c->p[0][ei] >= (b->av[ei] + b->idist)
+ || c->p[ixc][ei] <= (b->av[ei] - b->idist)) {
+ DBG(("Doesn't contain solution that will be closer to auxiliary goal\n"));
+ return 0;
+ }
+ }
+ }
+ DBG(("Cell is still ok\n"));
+ return 1;
+}
+
+/* Compute a solution for a given simplex (if there is one) */
+/* Return 1 if search should be aborted */
+static int auxil_compute(schbase *b, simplex *x) {
+ rspl *s = b->s;
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+ datai xp; /* solution in simplex relative coord order */
+ datai p; /* absolute solution */
+ double idist; /* Auxiliary input distance */
+ int wsrv; /* Within simplex return value */
+ int nabove; /* Number above aux target */
+
+ DBG(("\nAuxil: computing possible solution\n"));
+
+#ifdef DEBUG
+ {
+ unsigned int sum = 0;
+ for (f = 0; f <= x->sdi; f++)
+ sum += x->vix[f];
+ printf("Simplex of cell ix %d, sum 0x%x, sdi = %d, efdi = %d\n",x->ix, sum, x->sdi, x->efdi);
+ printf("Target val %s\n",icmPdv(fdi, b->v));
+ for (f = 0; f <= x->sdi; f++) {
+ int ix = x->vix[f], i;
+ float *fcb = s->g.a + ix * s->g.pss; /* Pointer to base float of fwd cell */
+ printf("Simplex vtx %d [cell ix %d] val %s\n",f,ix,icmPfv(fdi, fcb));
+ }
+ }
+#endif
+
+ /* Check that the target lies within the simplex bounding cube */
+ for (f = 0; f < fdi; f++) {
+ if (b->v[f] < x->min[f] || b->v[f] > x->max[f]) {
+ DBG(("Simplex is rejected - bounding cube\n"));
+ return 0;
+ }
+ }
+
+ /* Check if this cell could possible improve b->idist */
+ for (nabove = e = 0; e < b->naux; e++) {
+ int ei = b->auxi[e]; /* pmin/max[] is indexed in input space */
+ if (x->pmax[ei] >= (b->av[ei] - EPS)) /* Could be above */
+ nabove++;
+ }
+ if ((b->flags & RSPL_MAXAUX) && nabove < b->iabove) {
+ DBG(("Simplex doesn't contain solution that has as many aux above auxiliary goal\n"));
+ return 0;
+ }
+ if (!(b->flags & RSPL_MAXAUX) || nabove == b->iabove) {
+ for (nabove = e = 0; e < b->naux; e++) {
+ int ei = b->auxi[e]; /* pmin/max[] is indexed in input space */
+ if (x->pmin[ei] >= (b->av[ei] + b->idist)
+ || x->pmax[ei] <= (b->av[ei] - b->idist)) {
+ DBG(("Simplex doesn't contain solution that will be closer to auxiliary goal\n"));
+ return 0;
+ }
+ }
+ }
+
+//printf("~~ About to create svd decomp\n");
+ /* Create the SVD or LU decomp needed to compute solution or locus */
+ if (add_lu_svd(x)) {
+ DBG(("SVD decomp failed, skip simplex\n"));
+ return 0;
+ }
+
+//printf("~~ About to solve locus for aux target\n");
+ /* Now solve for locus parameter that minimises */
+ /* distance to auxliary target. */
+ if ((wsrv = auxil_solve(b, x, xp)) == 0) {
+ DBG(("Target auxiliary along locus is outside simplex,\n"));
+ DBG(("or computation failed, skip simplex\n"));
+ return 0;
+ }
+
+//printf("~~ About to convert solution to absolute space\n");
+ /* Convert solution from simplex relative to absolute space */
+ simplex_to_abs(x, p, xp);
+
+ DBG(("Got solution at %s\n", icmPdv(di,p)));
+
+//printf("~~ soln = %f %f %f %f\n",p[0],p[1],p[2],p[3]);
+//printf("~~ About to compute auxil distance\n");
+ /* Compute distance to auxiliary target */
+ for (idist = 0.0, nabove = e = 0; e < b->naux; e++) {
+ int ei = b->auxi[e];
+ double tt = b->av[ei] - p[ei];
+ idist += tt * tt;
+ if (p[ei] >= (b->av[ei] - EPS))
+ nabove++;
+ }
+ idist = sqrt(idist);
+//printf("~1 idist %f, nabove %d\n",idist, nabove);
+//printf("~1 best idist %f, best iabove %d\n",b->idist, b->iabove);
+
+ /* We want the smallest error from auxiliary target */
+ if (b->flags & RSPL_MAXAUX) {
+ if (nabove < b->iabove || (nabove == b->iabove && idist >= b->idist)) {
+ DBG(("nsoln %d, nabove %d, iabove %d, idist = %f, better solution has been found before\n",b->nsoln, nabove, b->iabove, idist));
+ return 0;
+ }
+ } else {
+ if (idist >= b->idist) { /* Equal or worse auxiliary solution */
+ DBG(("nsoln %d, idist = %f, better solution has been found before\n",b->nsoln,idist));
+ return 0;
+ }
+ }
+
+ /* Solution is accepted */
+ DBG(("######## Accepting new solution with nabove %d <= iabove %d and idist %f <= %f\n",nabove,b->iabove,idist,b->idist));
+ for (e = 0; e < di; e++)
+ b->cpp[0].p[e] = p[e];
+ for (f = 0; f < fdi; f++)
+ b->cpp[0].v[f] = b->v[f]; /* Assumed to be an exact solution */
+ b->idist = idist;
+ b->iabove = nabove;
+ b->nsoln = 1;
+ b->pauxcell = x->ix;
+ if (wsrv == 2) /* Is above (disabled) ink limit */
+ b->iclip = 1;
+
+ return 0;
+}
+
+/* ------------------------------------ */
+/* Locus range search functions */
+
+static int locus_setsort(schbase *b, cell *c) {
+ rspl *s = b->s;
+ int f, fdi = s->fdi;
+ int lxi = b->lxi; /* Auxiliary we are finding min/max of */
+ int ixc = b->ixc;
+ double sort, ss;
+
+ DBG(("Reverse locus evaluate and set sort key on cell\n"));
+
+#ifdef DEBUG
+ if (b->s->di <= fdi) { /* Assert ~1 */
+ error("rspl auxiliary locus interp called with di <= fdi");
+ }
+#endif /* DEBUG */
+
+ /* Check that the target lies within the cell bounding sphere */
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = c->bcent[f] - b->v[f];
+ ss += tt * tt;
+ }
+ if (ss > c->bradsq) {
+ DBG(("Cell rejected - %s outside sphere c %s rad %f\n",icmPdv(fdi,b->v),icmPdv(fdi,c->bcent),sqrt(c->bradsq)));
+ return 0;
+ }
+
+ if (s->limiten != 0 && c->limmin > s->limitv) {
+ DBG(("Cell is rejected - ink limit, min = %f, limit = %f\n",c->limmin,s->limitv));
+ return 0;
+ }
+
+ /* Check if this cell could possible improve the locus min/max */
+ if (b->asegs == 0) { /* If we aren't find all segments of the locus */
+ if (c->p[0][lxi] >= b->min && c->p[ixc][lxi] <= b->max ) {
+ DBG(("Doesn't contain solution that will expand the locus\n"));
+ return 0;
+ }
+ }
+
+ /* Compute sort index from average of auxiliary values */
+ sort = (c->p[0][b->lxi] + c->p[ixc][b->lxi]);
+
+ c->sort = sort + 0.01 * ss;
+
+ DBG(("Cell is accepted\n"));
+ return 1;
+}
+
+/* Re-check whether it's worth searching simplexes */
+static int locus_check(schbase *b, cell *c) {
+ int lxi = b->lxi; /* Auxiliary we are finding min/max of */
+ int ixc = b->ixc;
+
+ DBG(("Reverse locus re-check\n"));
+
+ /* Check if this cell could possible improve the locus min/max */
+ if (b->asegs == 0) { /* If we aren't find all segments of the locus */
+ if (c->p[0][lxi] >= b->min && c->p[ixc][lxi] <= b->max ) {
+ DBG(("Doesn't contain solution that will expand the locus\n"));
+ return 0;
+ }
+ }
+
+ DBG(("Cell is still ok\n"));
+ return 1;
+}
+
+static int auxil_locus(schbase *b, simplex *x);
+
+/* We expect to be given a sub-simplex with no DOF, to give an exact solution */
+static int locus_compute(schbase *b, simplex *x) {
+ rspl *s = b->s;
+ int f, fdi = s->fdi;
+ int lxi = b->lxi; /* Auxiliary we are finding min/max of */
+
+ DBG(("\nLocus: computing possible solution\n"));
+
+#ifdef DEBUG
+ {
+ unsigned int sum = 0;
+ for (f = 0; f <= x->sdi; f++)
+ sum += x->vix[f];
+ printf("Simplex of cell ix %d, sum 0x%x, sdi = %d, efdi = %d\n",x->ix, sum, x->sdi, x->efdi);
+ printf("Target val %s\n",icmPdv(fdi, b->v));
+ for (f = 0; f <= x->sdi; f++) {
+ int ix = x->vix[f], i;
+ float *fcb = s->g.a + ix * s->g.pss; /* Pointer to base float of fwd cell */
+ double v[MXDO];
+ printf("Simplex vtx %d [cell ix %d] val %s\n",f,ix,icmPfv(fdi, fcb));
+ }
+ }
+#endif
+
+ /* Check that the target lies within the simplex bounding cube */
+ for (f = 0; f < fdi; f++) {
+ if (b->v[f] < x->min[f] || b->v[f] > x->max[f]) {
+ DBG(("Simplex is rejected - bounding cube\n"));
+ return 0;
+ }
+ }
+
+ /* Check if simplex could possible improve the locus min/max */
+ if (b->asegs == 0) { /* If we aren't find all segments of the locus */
+ if (x->pmin[lxi] >= b->min && x->pmax[lxi] <= b->max ) {
+ DBG(("Simplex doesn't contain solution that will expand the locus\n"));
+ return 0;
+ }
+ }
+
+//printf("~~ About to create svd decomp\n");
+ /* Create the SVD decomp needed to compute solution extreme points */
+ if (add_lu_svd(x)) {
+ DBG(("SVD decomp failed, skip simplex\n"));
+ return 0;
+ }
+
+//printf("~~ About to solve locus for aux extremes\n");
+ /* Now solve for locus parameter that are at the extremes */
+ /* of the axiliary we are interested in. */
+ if (!auxil_locus(b, x)) {
+ DBG(("Target auxiliary is outside simplex,\n"));
+ DBG(("or computation failed, skip simplex\n"));
+ return 0;
+ }
+
+ return 0;
+}
+
+/* ------------------- */
+/* Vector clipping search functions */
+static int clipv_setsort(schbase *b, cell *c) {
+ rspl *s = b->s;
+ int f, fdi = s->fdi;
+ double ss, dp;
+
+ DBG(("Reverse clipping search evaluate cell\n"));
+
+//printf("~~sphere center = %f %f %f, radius %f\n",c->bcent[0],c->bcent[1],c->bcent[2],sqrt(c->bradsq));
+ /* Check if the clipping line intersects the bounding sphere */
+ /* First compute dot product cdir . (bcent - v) */
+ /* == distance to center of sphere in direction of clip vector */
+ for (dp = 0.0, f = 0; f < fdi; f++) {
+ dp += b->ncdir[f] * (c->bcent[f] - b->v[f]);
+ }
+
+ if (s->limiten != 0 && c->limmin > s->limitv) {
+ DBG(("Cell is rejected - ink limit, min = %f, limit = %f\n",c->limmin,s->limitv));
+ return 0;
+ }
+
+//printf("~~ dot product = %f\n",dp);
+ /* Now compute closest distance to sphere center */
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = b->v[f] + dp * b->ncdir[f] - c->bcent[f];
+ ss += tt * tt;
+ }
+
+//printf("~~ distance to sphere center = %f\n",sqrt(ss));
+ if (ss > c->bradsq) {
+ DBG(("Cell is rejected - wrong direction or bounding sphere\n"));
+ return 0;
+ }
+ c->sort = dp; /* May be -ve if beyond clip target point ? */
+
+ DBG(("Cell is accepted\n"));
+ return 1;
+}
+
+/* Clipping check functions */
+/* Note that we don't bother with this check in setsort(), */
+/* because we assume that nothing will set a small cdist */
+/* before the search commences (unlike auxil). */
+/* Note that line search loop exits on finding any solution. */
+static int clipv_check(schbase *b, cell *c) {
+
+ DBG(("Reverse clipping re-check\n"));
+
+ if (b->cdist < INF_DIST) { /* If some clip solution has been found */
+ int f, fdi = b->s->fdi;
+ double dist;
+ /* Compute a conservative "best possible solution clip distance" */
+ for (dist = 0.0, f = 0; f < fdi ; f++) {
+ double tt = (c->bcent[f] - b->v[f]);
+ dist += tt * tt;
+ }
+ dist = sqrt(dist); /* Target distance to bounding */
+
+ if (dist >= (c->brad + b->cdist)) { /* Equal or worse clip solution */
+ DBG(("Cell best possible solution worse than current\n"));
+ return 0;
+ }
+ }
+
+ DBG(("Cell is still ok\n"));
+ return 1;
+}
+
+static int vnearest_clip_solve(schbase *b, simplex *x, double *xp, double *xv, double *err);
+
+/* Compute a clip solution */
+static int clipv_compute(schbase *b, simplex *x) {
+ rspl *s = b->s;
+ int f, fdi = s->fdi;
+ datai p; /* Input space solution */
+ datao v; /* Output space solution */
+ double err; /* output error of solution */
+ int wsrv; /* Within simplex return value */
+
+ DBG(("Clips: computing possible solution\n"));
+
+ /* Compute a solution value */
+ if ((wsrv = vnearest_clip_solve(b, x, p, v, &err)) == 0) {
+ DBG(("Doesn't contain a solution\n"));
+ return 0;
+ }
+
+ /* We want the smallest clip error */
+ /* (Should we reject points in -ve vector direction ??) */
+ if (err >= b->cdist) { /* Equal or worse clip solution */
+ DBG(("better solution has been found before\n"));
+ return 0;
+ }
+
+ simplex_to_abs(x, b->cpp[0].p, p); /* Convert to abs. space & copy */
+
+ DBG(("######## Accepting new clipv solution with error %f\n",err));
+#ifdef DEBUG
+ if (s->limiten != 0) {
+ DBG(("######## Ink value = %f, limit %f\n",get_limitv(b, x->ix, NULL, b->cpp[0].p), s->limitv));
+ }
+#endif
+
+ /* Put solution in place */
+ for (f = 0; f < fdi; f++)
+ b->cpp[0].v[f] = v[f];
+ b->cdist = err;
+ b->nsoln = 1;
+ if (wsrv == 2) /* Is above (disabled) ink limit */
+ b->iclip = 1;
+
+ return 0;
+}
+
+/* ------------------- */
+/* Nearest clipping search functions */
+static int clipn_setsort(schbase *b, cell *c) {
+ rspl *s = b->s;
+ int f, fdi = s->fdi;
+ double ss;
+
+ DBG(("Reverse nearest clipping search evaluate cell\n"));
+
+ /* Compute a conservative "best possible solution clip distance" */
+ for (ss = 0.0, f = 0; f < fdi ; f++) {
+ double tt = (c->bcent[f] - b->v[f]);
+ ss += tt * tt;
+ }
+ ss = sqrt(ss); /* Target distance to bounding sphere */
+ ss -= c->brad;
+ if (ss < 0.0)
+ ss = 0.0;
+
+ /* Check that the cell could possibly improve the solution */
+ if (b->cdist < INF_DIST) { /* If some clip solution has been found */
+ if (ss >= b->cdist) { /* Equal or worse clip solution */
+ DBG(("Cell best possible solution worse than current\n"));
+ return 0;
+ }
+ }
+
+ if (s->limiten != 0 && c->limmin > s->limitv) {
+ DBG(("Cell is rejected - ink limit, min = %f, limit = %f\n",c->limmin,s->limitv));
+ return 0;
+ }
+
+ c->sort = ss; /* May be -ve if beyond clip target point ? */
+
+ DBG(("Cell is accepted\n"));
+ return 1;
+}
+
+/* Clipping check functions */
+static int clipn_check(schbase *b, cell *c) {
+
+ DBG(("Reverse nearest clipping re-check\n"));
+
+ if (b->cdist < INF_DIST) { /* If some clip solution has been found */
+ /* re-use sort value, best possible distance to solution */
+ if (c->sort >= b->cdist) { /* Equal or worse clip solution */
+ DBG(("Cell best possible solution worse than current\n"));
+ return 0;
+ }
+ }
+
+ DBG(("Cell is still ok\n"));
+ return 1;
+}
+
+static int nnearest_clip_solve(schbase *b, simplex *x, double *xp, double *xv, double *err);
+
+/* Compute a clip solution */
+static int clipn_compute(schbase *b, simplex *x) {
+ rspl *s = b->s;
+ int f, fdi = s->fdi;
+ datai p; /* Input space solution */
+ datao v; /* Output space solution */
+ double err; /* output error of solution */
+ int wsrv; /* Within simplex return value */
+
+ DBG(("Clipn: computing possible solution simplex %d, sdi = %d, efdi = %d\n",x->si,x->sdi,x->efdi));
+
+ /* Compute a solution value */
+ if ((wsrv = nnearest_clip_solve(b, x, p, v, &err)) == 0) {
+ DBG(("Doesn't contain a solution\n"));
+ return 0;
+ }
+
+ /* We want the smallest clip error */
+ if (err >= b->cdist) { /* Equal or worse clip solution */
+ DBG(("better solution has been found before\n"));
+ return 0;
+ }
+
+ DBG(("######## Accepting new clipn solution with error %f\n",err));
+
+ simplex_to_abs(x, b->cpp[0].p, p); /* Convert to abs. space & copy */
+
+ /* Put solution in place */
+ for (f = 0; f < fdi; f++)
+ b->cpp[0].v[f] = v[f];
+ b->cdist = err;
+ b->nsoln = 1;
+ if (wsrv == 2) /* Is above (disabled) ink limit */
+ b->iclip = 1;
+
+ return 0;
+}
+
+/* -------------------------------------------------------- */
+/* Cell/simplex solver middle level code */
+
+/* Find the point on this sub-simplexes solution locus that is */
+/* closest to the target auxiliary values, and return it in xp[] */
+/* Return zero if this point canot be calculated, */
+/* or it lies outside the simplex. */
+/* Return 1 normally, and 2 if the solution would be over the ink limit */
+static int
+auxil_solve(
+schbase *b,
+simplex *x,
+double *xp /* Return solution xp[sdi] */
+) {
+ rspl *s = b->s;
+ int ee, e, di = s->di, sdi = x->sdi;
+ int f, efdi = x->efdi;
+ int dof = sdi-efdi; /* Degree of freedom of simplex locus */
+ int *icomb = x->psxi->icomb; /* abs -> simplex coordinate translation */
+ double auxt[MXRI]; /* Simplex relative auxiliary targets */
+ double bb[MXRI];
+ int wsrv; /* Within simplex return value */
+
+ DBG(("axuil_solve called\n"));
+
+ if (dof < 0)
+ error("Error - auxil_solve got sdi < efdi (%d < %d) - don't know how to handle this",sdi, efdi);
+
+ /* If there is no locus, compute an exact solution */
+ if (dof == 0) {
+ DBG(("axuil_solve dof = zero\n"));
+
+ /* Init the RHS B[] vector (note sdi == efdi) */
+ for (f = 0; f < efdi; f++) {
+ xp[f] = b->v[f] - x->v[sdi][f];
+ }
+
+ /* Compute the solution (in simplex space) */
+ lu_backsub(x->d_u, sdi, (int *)x->d_w, xp);
+
+ if ((wsrv = within_simplex(x, xp)) != 0) {
+ DBG(("Got solution at %s\n", icmPdv(sdi,xp)));
+ return wsrv; /* OK, got solution */
+ }
+
+ DBG(("No solution (not within simplex)\n"));
+ return 0;
+ }
+
+ /* There is a locus, so find solution nearest auxiliaries */
+
+ /* Compute locus for target function values (if sdi > efdi) */
+ if (add_locus(b, x)) {
+ DBG(("Locus computation failed, skip simplex\n"));
+ return 0;
+ }
+
+ /* Convert aux targets from absolute space to simplex relative */
+ for (e = 0; e < di; e++) { /* For abs coords */
+ int ei = icomb[e]; /* Simplex coord */
+
+ if (ei >= 0 && b->auxm[e] != 0) {
+ auxt[ei] = (b->av[e] - x->p0[e])/s->g.w[e]; /* Only sets those needed */
+ }
+ }
+
+ if (dof == 1 && b->naux == 1) { /* Special case, because it's common and easy! */
+ int ei = icomb[b->auxi[0]]; /* Simplex relative auxiliary index */
+ double tt;
+
+ DBG(("axuil_solve dof = naux = 1\n"));
+ if (ei < 0)
+ return 0; /* Not going to find solution */
+ if ((tt = x->lo_l[ei][0]) == 0.0)
+ return 0;
+ tt = (auxt[ei] - x->lo_bd[ei])/tt; /* Parameter solution for target auxiliary */
+
+ /* Back substitute parameter */
+ for (e = 0; e < sdi; e++) {
+ xp[e] = x->lo_bd[e] + tt * x->lo_l[e][0];
+ }
+ if ((wsrv = within_simplex(x, xp)) != 0) {
+ DBG(("Got solution %s\n",icmPdv(di,xp)));
+ return wsrv; /* OK, got solution */
+ }
+ DBG(("No solution (not within simplex)\n"));
+ return 0;
+ }
+
+ /* Compute the locus decompositions needed (info #5) */
+ if (add_auxil_lu_svd(b, x)) { /* Will set x->naux */
+ DBG(("LU/SVD decomp failed\n"));
+ return 0;
+ }
+
+ /* Setup B[], equation RHS */
+ for (e = ee = 0; ee < b->naux; ee++) {
+ int ei = icomb[b->auxi[ee]]; /* Simplex relative auxiliary index */
+ if (ei >= 0) /* Usable auxiliary on this sub simplex */
+ bb[e++] = auxt[ei] - x->lo_bd[ei];
+ }
+ if (e != x->naux) /* Assert */
+ error("Internal error - auxil_solve got mismatching number of auxiliaries");
+
+ if (x->naux == dof) { /* Use LU decomp to solve */
+ DBG(("axuil_solve using LU\n"));
+ lu_backsub(x->ax_u, dof, (int *)x->ax_w, bb);
+
+ } else if (x->naux > 0) { /* Use SVD to solve least squares */
+ DBG(("axuil_solve using SVD\n"));
+ svdbacksub(x->ax_u, x->ax_w, x->ax_v, bb, bb, x->naux, dof);
+
+ } else { /* x->naux == 0 */
+ DBG(("axuil_solve naux = 0\n"));
+ for (f = 0; f < dof; f++)
+ bb[f] = 0.0; /* Use base solution ?? */
+ }
+
+ /* Now back substitute the locus parameters */
+ /* to calculate the solution point (in simplex space) */
+ for (e = 0; e < sdi; e++) {
+ double tt;
+ for (tt = 0.0, f = 0; f < dof; f++) {
+ tt += bb[f] * x->lo_l[e][f];
+ }
+ xp[e] = x->lo_bd[e] + tt;
+ }
+
+ if ((wsrv = within_simplex(x, xp)) != 0) {
+ DBG(("Got solution %s\n",icmPdv(di,xp)));
+ return wsrv; /* OK, got solution */
+ }
+ DBG(("No solution (not within simplex)\n"));
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Compute the min/max values for the current auxiliary of interest. */
+/* Return zero if this point canot be calculated, */
+/* or it lies outside the simplex. */
+/* Return 1 normally, 2 if it would be outside the simplex if limting was enabled */
+/* We expect to get a sub-simplex that will give an exact solution. */
+static int
+auxil_locus(
+schbase *b,
+simplex *x
+) {
+ rspl *s = b->s;
+ int sdi = x->sdi;
+ int f, efdi = x->efdi;
+ double pp[MXRI];
+ int wsrv; /* Within simplex return value */
+
+ DBG(("axuil_locus called\n"));
+
+ if (sdi != efdi)
+ warning("Internal error - auxil_locus got sdi != efdi (%d < %d)",sdi, efdi);
+
+ /* Init the RHS B[] vector (note sdi == efdi) */
+ for (f = 0; f < efdi; f++) {
+ pp[f] = b->v[f] - x->v[sdi][f];
+ }
+
+ /* Compute the solution (in simplex space) */
+ lu_backsub(x->d_u, sdi, (int *)x->d_w, pp);
+
+ /* Check that the solution is within the simplex */
+ if ((wsrv = within_simplex(x, pp)) != 0) {
+ double xval;
+ int lxi = b->lxi; /* Auxiliary we are finding min/max of (Abs space) */
+ int xlxi = x->psxi->icomb[lxi]; /* Auxiliary we are finding min/max of (simplex space) */
+
+ DBG(("Got locus solution within simplex\n"));
+
+ /* Compute auxiliary value for this solution (absolute space) */
+ xval = x->p0[lxi];
+ if (xlxi >= 0) /* Simplex param value */
+ xval += s->g.w[lxi] * pp[xlxi];
+ else if (xlxi == -2) /* 1 value */
+ xval += s->g.w[lxi];
+ /* Else 0 value */
+
+ if (b->asegs != 0) { /* Tracking auxiliary segments */
+ if (b->axisln >= b->axislz) { /* Need some more space in list */
+ if (b->axislz == 0) {
+ b->axislz = 10;
+ if ((b->axisl = (axisec *)rev_malloc(s, b->axislz * sizeof(axisec))) == NULL)
+ error("rev: malloc failed - Auxiliary intersect list size %d",b->axislz);
+ INCSZ(b->s, b->axislz * sizeof(axisec));
+ } else {
+ INCSZ(b->s, b->axislz * sizeof(axisec));
+ b->axislz *= 2;
+ if ((b->axisl = (axisec *)rev_realloc(s, b->axisl, b->axislz * sizeof(axisec)))
+ == NULL)
+ error("rev: realloc failed - Auxiliary intersect list size %d",b->axislz);
+ }
+ }
+ b->axisl[b->axisln].xval = xval;
+ b->axisl[b->axisln].nv = x->sdi + 1;
+ for (f = 0; f <= x->sdi; f++) {
+ b->axisl[b->axisln].vix[f] = x->vix[f];
+ }
+ b->axisln++;
+ }
+
+#ifdef DEBUG
+ if (xval >= b->min && xval <= b->max)
+ DBG(("auxil_locus: solution %f doesn't improve on min %f, max %f\n",xval,b->min,b->max));
+#endif
+ /* If this solution is expands the min or max, save it */
+ if (xval < b->min) {
+ DBG(("######## Improving minimum to %f\n",xval));
+ b->min = xval;
+ b->plmincell = x->ix;
+ }
+ if (xval > b->max) {
+ DBG(("######## Improving maximum to %f\n",xval));
+ b->max = xval;
+ b->plmaxcell = x->ix;
+ }
+ } else {
+ DBG(("Solution wasn't within the simplex\n"));
+ return 0;
+ }
+
+ return wsrv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Find the point on the clip line locus and simplexes */
+/* valid surface, that is closest to the target output value. */
+/* We expect to be given a sub simplex with sdi = fdi-1, and efdi = fdi */
+/* or a limit sub-simplex with sdi = fdi, and efdi = fdi+1 */
+/* Return zero if solution canot be calculated, */
+/* return 1 normally, 2 if solution would be above the (disabled) ink limit */
+static int
+vnearest_clip_solve(
+schbase *b,
+simplex *x,
+double *xp, /* Return solution (simplex parameter space) */
+double *xv, /* Return solution (output space) */
+double *err /* Output error distance at solution point */
+) {
+ rspl *s = b->s;
+ int e, sdi = x->sdi;
+ int f, fdi = s->fdi, efdi = x->efdi;
+ int g;
+ int wsrv; /* Within simplex return value */
+
+ double *ta[MXRO], TA[MXRO][MXRO];
+ double tb[MXRO];
+
+ DBG(("Vector nearest clip solution called, cell %d, splx %d\n", x->ix, x->si));
+
+ /* Setup temporary matricies */
+ for (f = 0; f < sdi; f++) {
+ ta[f] = TA[f];
+ }
+
+ /* Substitute simplex equation for output values V */
+ /* in terms of sub-simplex parameters P, */
+ /* into clip line implicit equation in V, to give */
+ /* clip line simplex implicit equation in terms of P (simplex input space) */
+ /* If this is a limit sub-simlex, the ink limit part of the clip vector */
+ /* equations will be used. */
+
+ /* LHS: ta[sdi][sdi] = cla[sdi][efdi] * vv[efdi][sdi] */
+ /* RHS: tb[sdi] = clb[sdi] - cla[sdi][efdi] * vv_di[efdi] */
+ for (f = 0; f < sdi; f++) {
+ double tt;
+ for (e = 0; e < sdi; e++) {
+ for (tt = 0.0, g = 0; g < efdi; g++)
+ tt += b->cla[f][g] * (x->v[e][g] - x->v[e+1][g]);
+ ta[f][e] = tt;
+ }
+ for (tt = 0.0, g = 0; g < efdi; g++)
+ tt += b->cla[f][g] * x->v[sdi][g];
+ tb[f] = b->clb[f] - tt;
+ }
+
+ /* Compute the solution */
+ if (gen_solve_se(ta, tb, sdi, sdi)) {
+ DBG(("Equation solution failed!\n"));
+ return 0; /* No solution */
+ }
+
+ /* Check that the solution is within the simplex */
+ if ((wsrv = within_simplex(x, tb)) != 0) {
+ double dist; /* distance to clip target */
+
+ DBG(("Got solution within simplex %s\n", icmPdv(sdi,tb)));
+
+ /* Compute the output space solution point */
+ for (f = 0; f < fdi; f++) {
+ double tt = 0.0;
+ for (e = 0; e < sdi; e++) {
+ tt += (x->v[e][f] - x->v[e+1][f]) * tb[e];
+ }
+ xv[f] = tt + x->v[sdi][f];
+ }
+
+ /* Copy to return array */
+ for (e = 0; e < sdi; e++)
+ xp[e] = tb[e];
+
+ /* Compute distance to clip target */
+ for (dist = 0.0, f = 0; f < fdi ; f++) {
+ double tt = (b->v[f] - xv[f]);
+ dist += tt * tt;
+ }
+ DBGV(("Vector clip output soln: ",fdi," %f", xv, "\n"));
+
+ /* Return the solution in xp[]m xv[] and *err */
+ *err = sqrt(dist);
+
+ DBG(("Vector clip returning a solution with error %f\n",*err));
+ return wsrv;
+ }
+
+ DBG(("Vector clip solution not in simplex\n"));
+ return 0; /* No solution */
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Find the point on the simplexes valid surface, that is closest */
+/* to the target output value. */
+/* We expect to be given a sub simplex with sdi = fdi-1, and efdi = fdi */
+/* or a limit sub-simplex with sdi = fdi, and efdi = fdi+1 */
+/* Return zero if solution canot be calculated, */
+/* return 1 normally, 2 if solution would be above the (disabled) ink limit */
+static int
+nnearest_clip_solve(
+schbase *b,
+simplex *x,
+double *xp, /* Return solution (simplex parameter space) */
+double *xv, /* Return solution (output space) */
+double *err /* Output error distance at solution point */
+) {
+ rspl *s = b->s;
+ int e, sdi = x->sdi;
+ int f, fdi = s->fdi, efdi = x->efdi;
+ double tb[MXRO]; /* RHS & Parameter solution */
+ double dist; /* distance to clip target */
+ int wsrv = 0; /* Within simplex return value */
+
+ DBG(("Nearest clip solution called, cell %d, splx %d\n", x->ix, x->si));
+
+ if (sdi == 0) { /* Solution is vertex */
+ wsrv = 1;
+ for (f = 0; f < efdi; f++)
+ xv[f] = x->v[sdi][f]; /* Copy vertex value */
+ if (x->v[sdi][fdi] > s->limitv) {
+ if (s->limiten) /* Needed when limiten == 0 */
+ return 0; /* Over ink limit - no good */
+ wsrv = 2; /* Would be over */
+ }
+ DBG(("Got assumed vertex solution\n"));
+ } else {
+#ifdef NEVER /* Don't specialise ink limit version - use INKSCALE fudge instead */
+ if (!(x->flags & SPLX_CLIPSX)) { /* Not an ink limited plane simplex */
+
+#endif
+ /* Create the SVD decomp needed for least squares solution */
+ if (add_lu_svd(x)) {
+ DBG(("SVD decomp failed, skip simplex\n"));
+ return 0;
+ }
+
+ /* Setup RHS to solve */
+ for (f = 0; f < efdi; f++)
+ tb[f] = b->v[f] - x->v[sdi][f];
+
+ /* Find least squares solution */
+ svdbacksub(x->d_u, x->d_w, x->d_v, tb, tb, efdi, sdi);
+
+ /* Check that the solution is within the simplex */
+ if ((wsrv = within_simplex(x, tb)) == 0) {
+ DBG(("Nearest clip solution not in simplex\n"));
+ return 0; /* No solution */
+ }
+
+ DBG(("Got solution within simplex %s\n",icmPdv(sdi,tb)));
+
+ /* Compute the output space solution point */
+ for (f = 0; f < fdi; f++) {
+ double tt = 0.0;
+ for (e = 0; e < sdi; e++) {
+ tt += (x->v[e][f] - x->v[e+1][f]) * tb[e];
+ }
+ xv[f] = tt + x->v[sdi][f];
+ }
+#ifdef NEVER /* ~~1 Haven't figured out equations to make this a special case. */
+ /* Content to use INKSCALE fudge and rely on SVD least squares. */
+ } else {
+ /* We can't use the given equations, because we want the solution */
+ /* to lie exactly on the ink limit plane, and be least squares to the */
+ /* other target parameters. */
+ /* Extract the ink limit parameters, and transform them into */
+ /* a parameterised surface for this simplex. */
+ /* Substitute the ink plane equation into the remaining target */
+ /* parameter equations, and solve for least squares. */
+
+ }
+#endif
+ }
+
+ /* Copy to return array */
+ for (e = 0; e < sdi; e++)
+ xp[e] = tb[e];
+
+ /* Compute distance to clip target */
+ for (dist = 0.0, f = 0; f < fdi ; f++) {
+ double tt = (b->v[f] - xv[f]);
+ dist += tt * tt;
+ }
+ DBGV(("Nearest clip output soln: ",fdi," %f", xv, "\n"));
+
+ /* Return the solution in xp[]m xv[] and *err */
+ *err = sqrt(dist);
+
+ DBG(("Nearest clip returning a solution with error %f\n",*err));
+ return wsrv;
+}
+
+
+#ifdef NEVER
+/* Utility to convert an implicit ink limit plane equation */
+/* (held at the end of the simplex output value equations), */
+/* into a parameterized surface equation. */
+static void
+compute_param_limit_surface(
+schbase *b,
+simplex *x
+) {
+ rspl *s = b->s;
+ int ff, f, fdi = s->fdi;
+ int i, p;
+ double lgst;
+
+double st[MXRO], /* Start point */
+double de[MXRO] /* Delta */
+ DBG(("Computing clipping line implicit equation, dim = %d\n", fdi));
+
+ /* Pick a pivot element - the smallest */
+ for (lgst = -1.0, p = -1, f = 0; f < fdi; f++) {
+ double tt = de[f];
+ b->cdir[f] = tt; /* Stash this away */
+ tt = fabs(tt);
+ if (tt > lgst) {
+ lgst = tt;
+ p = f;
+ }
+ }
+ if (p < 0) /* Shouldn't happen */
+ error("rspl rev, internal, trying to cope with zero length clip line\n");
+
+ if (b->cla == NULL)
+ b->cla = dmatrix(0, fdi-1, 0, fdi); /* Allow for ink limit supliment */
+
+ for (i = ff = 0; ff < fdi; ff++) { /* For the input rows */
+ if (ff == p) {
+ continue; /* Skip pivot row */
+ }
+ for (f = 0; f < fdi; f++) { /* For input & output columns */
+ if (f == p) {
+ b->cla[i][f] = -de[ff]; /* Last column is -ve delta value */
+ } else if (f == ff) {
+ b->cla[i][f] = de[p]; /* Diagonal is pivot value */
+ } else {
+ b->cla[i][f] = 0.0; /* Else zero */
+ }
+ }
+ b->clb[i] = de[p] * st[ff] - de[ff] * st[p];
+ i++;
+ }
+
+ /* Add ink limit target equation - */
+ /* interpolated ink value == target */
+ if (s->limitf != NULL) {
+ for (i = 0; i < (fdi-1); i++)
+ b->cla[i][fdi] = 0.0;
+
+ for (f = 0; f < fdi; f++)
+ b->cla[fdi-1][f] = 0.0;
+
+ b->cla[fdi-1][fdi] = 1.0;
+ b->clb[fdi-1] = s->limitv;
+ }
+
+#ifdef NEVER
+/* Verify that the implicit equation is correct */
+{
+ double pnt[MXRO], v[MXRO];
+ double pa; /* Parameter */
+ for (pa = 0.0; pa <= 1.0; pa += 0.125) {
+ for (f = 0; f < fdi; f++) {
+ pnt[f] = st[f] + pa * de[f];
+ }
+
+ /* Verify the implicit equation */
+ for (ff = 0; ff < (fdi-1); ff++) {
+ v[ff] = 0.0;
+ for (f = 0; f < fdi; f++) {
+ v[ff] += b->cla[ff][f] * pnt[f];
+ }
+ v[ff] -= b->clb[ff];
+ if (v[ff] < 0.0)
+ v[ff] = -v[ff];
+ if (v[ff] > 0.000001) {
+ printf("Point on clip line = %f %f %f\n",pnt[0],pnt[1],pnt[2]);
+ printf("Implicit %d error of = %f\n",ff, v[ff]);
+ }
+ }
+ }
+}
+#endif /* NEVER */
+
+}
+
+#endif
+
+
+
+
+/* -------------------------------------------------------- */
+/* Cell/simplex object lower level code */
+
+/* Utility to get or calculate a vertexes ink limit value */
+static double get_limitv(
+schbase *b, /* Base search information */
+int ix, /* fwd index of cell */
+float *fcb, /* Pointer to base of vertex value array (ix is used if NULL) */
+double *p /* Array of input values (can be NULL to compute) */
+) {
+ rspl *s = b->s;
+ float *base = fcb;
+ double lv;
+ if (base == NULL)
+ base = s->g.a + ix * s->g.pss;
+ lv = base[-1]; /* Fetch existing ink limit function value */
+ if ((float)lv == L_UNINIT) { /* Not been computed yet */
+ if (p != NULL) {
+ lv = INKSCALE * s->limitf(s->lcntx, p); /* Do it */
+ base[-1] = (float)lv;
+ } else {
+ int e, di = s->di;
+ double pp[MXRI]; /* Copy from float to double */
+ int tix; /* Temp fwd cell index */
+
+ for (tix = ix, e = 0; e < di; e++) {
+ int dix;
+ dix = tix % s->g.res[e];
+ tix /= s->g.res[e];
+ pp[e] = s->g.l[e] + (double)dix * s->g.w[e]; /* Base point */
+ }
+ lv = INKSCALE * s->limitf(s->lcntx, pp); /* Do it */
+ base[-1] = (float)lv;
+ }
+ s->g.limitv_cached = 1; /* At least one limit value is cached */
+ }
+ return lv;
+}
+
+/* Utility to invalidate all the ink limit values */
+/* cached in the main rspl array */
+static void clear_limitv(
+rspl *s
+) {
+ int i;
+ float *gp; /* Grid point pointer */
+
+ if (s->g.limitv_cached != 0) { /* If any have been set */
+ /* Unset them all */
+ for (i = 0, gp = s->g.a; i < s->g.no; i++, gp += s->g.pss) {
+ gp[-1] = L_UNINIT;
+ }
+ s->g.limitv_cached = 0;
+ }
+}
+
+/* Cell code */
+
+static void free_cell_contents(cell *c);
+static cell *cache_rcell(revcache *r, int ix, int force);
+static void uncache_rcell(revcache *r, cell *cp);
+
+/* Return a pointer to an appropriate reverse cell */
+/* cache structure. None of the sub simplex lists will */
+/* be initialised. */
+/* NOTE: must unget_cell() (== uncache_rcell()) when cell */
+/* is no longer needed */
+/* Return NULL if we ran out of room in the cache. */
+static cell *get_rcell(
+schbase *b, /* Base search information */
+int ix, /* fwd index of cell */
+int force /* if nz, force memory allocation, so that we have at least one cell */
+) {
+ rspl *s = b->s;
+ int ee, e, di = s->di;
+ int p2di = (1<<di);
+ int ff, f, fdi = s->fdi;
+ cell *c;
+
+ c = cache_rcell(s->rev.cache, ix, force); /* Fetch it from the cache and lock it */
+ if (c == NULL)
+ return NULL;
+
+ if (!(c->flags & CELL_FLAG_1)) { /* Have to (re)initialize cell & simplexes */
+ int tix; /* Temp fwd cell index */
+ float *fcb = s->g.a + ix * s->g.pss; /* Pointer to base float of fwd cell */
+
+ /* Compute basic Cell info and vertex output values */
+ for (ee = 0; ee < p2di; ee++) {
+ float *vp = fcb + s->g.fhi[ee];
+ for (f = 0; f < fdi; f++) /* Transfer cell verticy values from grid */
+ c->v[ee][f] = vp[f];
+
+ /* ~~ reset any other cell info that will be stale */
+ }
+
+ /* Convert from cell index, to absolute fwd coord base values */
+ c->limmin = INF_DIST; /* and min/max values */
+ c->limmax = -INF_DIST;
+ for (tix = ix, e = 0; e < di; e++) {
+ int dix;
+ dix = tix % s->g.res[e];
+ tix /= s->g.res[e];
+ c->p[0][e] = s->g.l[e] + (double)dix * s->g.w[e]; /* Base point */
+ }
+ if (s->limitf != NULL) { /* Compute ink limit values at base verticy */
+ double lv = get_limitv(b, ix, fcb, c->p[0]); /* Fetch or generate limit value */
+ c->v[0][fdi] = lv;
+ if (lv < c->limmin) /* And min/max for this cell */
+ c->limmin = lv;
+ if (lv > c->limmax)
+ c->limmax = lv;
+ }
+
+ /* Setup cube verticy input position values, and ink limit values */
+ for (ee = 1; ee < p2di; ee++) {
+ for (e = 0; e < di; e++) {
+ c->p[ee][e] = c->p[0][e];
+ if (ee & (1 << e))
+ c->p[ee][e] += s->g.w[e]; /* In input space offset */
+ }
+ if (s->limitf != NULL) { /* Compute ink limit values at cell verticies */
+ double lv = get_limitv(b, ix, fcb + s->g.fhi[ee], c->p[ee]);
+ c->v[ee][fdi] = lv;
+ if (lv < c->limmin) /* And min/max for this cell */
+ c->limmin = lv;
+ if (lv > c->limmax)
+ c->limmax = lv;
+ }
+ }
+
+ /* Compute the output bounding sphere for fast rejection testing */
+ {
+ double *min[MXRO], *max[MXRO]; /* Pointers to points with min/max values */
+ double radsq = -1.0; /* Span/radius squared */
+ double rad;
+ int spf = 0;
+
+ /* Find verticies of cell that have min and max values in output space */
+ for (f = 0; f < fdi; f++)
+ min[f] = max[f] = NULL;
+
+ for (ee = 0; ee < p2di; ee++) {
+ double *vp = c->v[ee];
+ for (f = 0; f < fdi; f++) {
+ if (min[f] == NULL || min[f][f] > vp[f])
+ min[f] = vp;
+ if (max[f] == NULL || max[f][f] < vp[f])
+ max[f] = vp;
+ }
+ }
+
+ /* Find the pair of points with the largest span (diameter) in output space */
+ for (ff = 0; ff < fdi; ff++) {
+ double ss;
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt;
+ tt = max[ff][f] - min[ff][f];
+ ss += tt * tt;
+ }
+ if (ss > radsq) {
+ radsq = ss;
+ spf = ff; /* Output dimension max was in */
+ }
+ }
+
+ /* Set initial bounding sphere */
+ for (f = 0; f < fdi; f++) {
+ c->bcent[f] = (max[spf][f] + min[spf][f])/2.0;
+ }
+ radsq /= 4.0; /* diam^2 -> rad^2 */
+ c->bradsq = radsq;
+ rad = c->brad = sqrt(radsq);
+
+ /* Go though all the points again, expanding sphere if necessary */
+ for (ee = 0; ee < p2di; ee++) {
+ double ss;
+ double *vp = c->v[ee];
+
+ /* Compute distance squared of point to bounding shere */
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = vp[f] - c->bcent[f];
+ ss += tt * tt;
+ }
+ if (ss > radsq) {
+ double tt;
+ /* DBG(("Expanding bounding sphere by %f\n",sqrt(ss) - rad)); */
+
+ ss = sqrt(ss) + EPS; /* Radius to point */
+ rad = (rad + ss)/2.0;
+ c->bradsq = radsq = rad * rad;
+ tt = ss - rad;
+ for (f = 0; f < fdi; f++) {
+ c->bcent[f] = (rad * c->bcent[f] + tt * vp[f])/ss;
+ }
+
+ } else {
+ /* DBG(("Bounding sphere encloses by %f\n",rad - sqrt(ss))); */
+ }
+ }
+ c->bradsq += EPS;
+ }
+ c->flags = CELL_FLAG_1;
+ }
+
+ return c;
+}
+
+void free_simplex_info(cell *c, int dof);
+
+/* Free up any allocated simplexes in a cell, */
+/* and set the pointers to NULL. */
+/* Nothing else is changed (ie. it's NOT removed from */
+/* the cache index or unthrheaded from the mru list). */
+static void
+free_cell_contents(
+cell *c
+) {
+ int nsdi;
+
+ /* Free up all the simplexes */
+ if (c->s != NULL) {
+ for (nsdi = 0; nsdi <= c->s->di; nsdi++) {
+ if (c->sx[nsdi] != NULL) {
+ free_simplex_info(c, nsdi);
+ c->sx[nsdi] = NULL;
+ }
+ }
+ }
+ /* ~~ free any other cell information */
+}
+
+/* - - - - - - */
+/* Simplex code */
+
+/* Simplex and Cell hash index size increments */
+int primes[] = {
+ 367,
+ 853,
+ 1489,
+ 3373,
+ 3373,
+ 6863,
+ 12919,
+ 23333,
+ 43721,
+ 97849,
+ 146221,
+ 254941,
+ -1
+};
+
+/* Compute a simplex hash index */
+unsigned int simplex_hash(revcache *rc, int sdi, int efdi, int *vix) {
+ unsigned int hash = 0;
+ int i;
+
+ for (i = 0; i <= sdi; i++)
+ hash = hash * 17 + vix[i];
+ hash = hash * 17 + sdi;
+ hash = hash * 17 + efdi;
+
+ hash %= rc->spx_hash_size;
+ return hash;
+}
+
+/* Allocate and do the basic initialisation for a DOF list of simplexes */
+void alloc_simplexes(
+cell *c,
+int nsdi /* Non limited sub simplex dimensionality */
+) {
+ rspl *s = c->s;
+ schbase *b = s->rev.sb;
+ revcache *rc = s->rev.cache;
+ int ee, e, di = s->di;
+ int f, fdi = s->fdi;
+ int lsdi; /* Ink limited Sub-simplex sdi */
+ int tsxno; /* Total number of DOF simplexes */
+ int nsxno; /* Number of non-ink limited DOF simplexes */
+ int si, so; /* simplex index in and out */
+
+ DBG(("Allocating level %d sub simplexes in cell %d\n",nsdi,c->ix));
+ if (c->sx[nsdi] != NULL)
+ error("rspl rev, internal, trying allocate already allocated simplexes\n");
+
+ /* Figure out how many simplexes will be at this nsdi */
+ lsdi = nsdi + 1; /* Ink limit simplexes sdi */
+
+ tsxno = nsxno = s->rev.sspxi[nsdi].nospx;
+
+ if (s->limitf != NULL && lsdi <= di)
+ tsxno += s->rev.sspxi[lsdi].nospx; /* Second set with extra input dimension */
+
+ /* Make sure there is enough space in temp simplex filter list */
+ if (b->lsxfilt < tsxno) { /* Allocate more space if needed */
+
+ if (b->lsxfilt > 0) { /* Free old space before allocating new */
+ free(b->sxfilt);
+ DECSZ(b->s, b->lsxfilt * sizeof(char));
+ }
+ b->lsxfilt = 0;
+ /* Allocate enough space for all the candidate cells */
+ if ((b->sxfilt = (char *)rev_malloc(s, tsxno * sizeof(char))) == NULL)
+ error("rev: malloc failed - temp simplex filter list, count %d",tsxno);
+ b->lsxfilt = tsxno; /* Current allocated space */
+ INCSZ(b->s, b->lsxfilt * sizeof(char));
+ }
+
+ /* Figure out the number of simplexes that will actually be needed */
+ for (si = so = 0; si < tsxno; si++) {
+ psxinfo *psxi = NULL;
+ int *icomb, *offs;
+ int sdi = nsdi;
+ int efdi = fdi;
+ int ssi = si;
+ int isclip = 0;
+ if (si >= nsxno) { /* If limit boundary simplex */
+ sdi++; /* One more dimension */
+ efdi++; /* One more constraint */
+ ssi -= nsxno; /* In second half of list */
+ isclip++; /* Limit clipped simplex */
+ }
+ psxi = &s->rev.sspxi[sdi].spxi[ssi];
+ icomb = psxi->icomb;
+ offs = psxi->offs;
+
+ b->sxfilt[si] = 0; /* Assume simplex won't be used */
+
+ /* Check if simplex should be discared due to the ink limit */
+ if (s->limitf != NULL) {
+ double max = -INF_DIST;
+ double min = INF_DIST;
+
+ /* Find the range of ink limit values covered by simplex */
+ for (e = 0; e <= sdi; e++) { /* For all the simplex verticies */
+ int i = offs[e];
+ double vv = c->v[i][fdi]; /* Ink limit value */
+ if (vv < min)
+ min = vv;
+ if (vv > max)
+ max = vv;
+ }
+
+//if ((max - min) > EPS) printf("~1 Found simplex sdi %d, efdi %d, min = %f, max = %f, limitv = %f\n", sdi, efdi, min,max,s->limitv);
+ if (isclip) { /* Limit clipped simplex */
+ /* (Make sure it straddles the limit boundary) */
+ if (max < s->limitv || min > s->limitv)
+ continue; /* Discard this simplex - it can't straddle the ink limit */
+//printf("~1 using sub simplex sdi %d, efdi %d, min = %f, max = %f, limitv = %f\n", sdi, efdi, min,max,s->limitv);
+ } else {
+ if (min > s->limitv)
+ continue; /* Discard this simplex - it is above the ink limit */
+ }
+ }
+
+ b->sxfilt[si] |= 1; /* This cell will be OK */
+ so++;
+ }
+
+ DBG(("There are %d level %d sub simplexes\n",so, nsdi));
+ /* Allocate space for all the DOF simplexes that will be used */
+ if (so > 0) {
+ if ((c->sx[nsdi] = (simplex **) rev_calloc(s, so, sizeof(simplex *))) == NULL)
+ error("rspl malloc failed - reverse cell simplexes - list of pointers");
+ INCSZ(s, so * sizeof(simplex *));
+ }
+
+ /* Setup SPLX_FLAG_1 level information in the simplex */
+ for (si = so = 0; si < tsxno; si++) {
+ simplex *x;
+ psxinfo *psxi = NULL;
+ int *icomb;
+ int sdi, efdi;
+ int ssi;
+ int vix[MXRI+1]; /* fwd cell vertex indexes of this simplex [sdi+1] */
+
+ if (b->sxfilt[si] == 0) /* Decided not to use this one */
+ continue;
+
+#ifdef STATS
+ s->rev.st[b->op].sinited++;
+#endif /* STATS */
+
+ sdi = nsdi;
+ efdi = fdi;
+ ssi = si;
+ if (si >= nsxno) { /* If limit boundary simplex */
+ sdi++; /* One more dimension */
+ efdi++; /* One more constraint */
+ ssi -= nsxno; /* In second half of list */
+ }
+
+ psxi = &s->rev.sspxi[sdi].spxi[ssi];
+ icomb = psxi->icomb;
+
+ /* Compute simplex vertexes so we can match it in the cache */
+ for (e = 0; e <= sdi; e++)
+ vix[e] = c->ix + s->g.hi[psxi->offs[e]];
+
+ x = c->sx[nsdi][so];
+
+ /* If this is a shared simplex, see if we already have it in another cell */
+ if (x == NULL && psxi->face) {
+ unsigned int hash;
+//printf("~1 looking for existing simplex nsdi = %d\n",nsdi);
+ hash = simplex_hash(rc, sdi, efdi, vix);
+ for (x = rc->spxhashtop[hash]; x != NULL; x = x->hlink) {
+ if (x->sdi != sdi
+ || x->efdi != efdi)
+ continue; /* miss */
+ for (e = 0; e <= sdi; e++) {
+ if (x->vix[e] != vix[e])
+ break; /* miss */
+ }
+ if (e > sdi)
+ break; /* hit */
+ }
+ if (x != NULL) {
+ x->refcount++;
+//printf("~1 found hit in simplex face list hash %d, refcount = %d\n",hash,x->refcount);
+ }
+ }
+ /* Doesn't already exist */
+ if (x == NULL) {
+ if ((x = (simplex *) rev_calloc(s, 1, sizeof(simplex))) == NULL)
+ error("rspl malloc failed - reverse cell simplexes - base simplex %d bytes",sizeof(simplex));
+ INCSZ(s, sizeof(simplex));
+ x->refcount = 1;
+ x->touch = s->rev.stouch-1;
+ x->flags = 0;
+
+ if (si >= nsxno) { /* If limit boundary simplex */
+ x->flags |= SPLX_CLIPSX; /* Limit clipped simplex */
+ }
+
+ /* Fill in the other simplex details */
+ x->s = s; /* Parent rspl */
+ x->ix = c->ix; /* Construction cube base index */
+ for (e = 0; e <= sdi; e++) /* Indexs of fwd verticies that make up this simplex */
+ x->vix[e] = vix[e];
+ x->psxi = psxi; /* Pointer to constant per simplex info */
+//printf("~1 set simplex 0x%x psxi = 0x%x\n",x,x->psxi);
+ x->si = so; /* Diagnostic, simplex offset in list */
+ x->sdi = sdi; /* Copy of simplex dimensionaity */
+ x->efdi = efdi; /* Copy of effective output dimensionality */
+
+ /* Copy cell simplex vertex output and limit values */
+ for (e = 0; e <= sdi; e++) { /* For all the simplex verticies */
+ int i = x->psxi->offs[e];
+
+ for (f = 0; f <= fdi; f++) /* Copy vertex value + ink sum */
+ x->v[e][f] = c->v[i][f];
+
+ /* Setup output bounding box values (the hard way) */
+ if (e == 0) { /* Init to first vertex of simplex */
+ for (f = 0; f <= fdi; f++) /* Output space */
+ x->min[f] = x->max[f] = c->v[i][f];
+ } else {
+ for (f = 0; f <= fdi; f++) { /* Output space + ink sum */
+ double vv;
+// if (f == fdi && s->limit == NULL)
+// continue; /* Skip ink */
+ vv = c->v[i][f];
+ if (vv < x->min[f])
+ x->min[f] = vv;
+ else if (vv > x->max[f])
+ x->max[f] = vv;
+ }
+ }
+ }
+ /* Add a margin */
+ for (f = 0; f <= fdi; f++) { /* Output space + ink sum */
+ x->min[f] -= EPS;
+ x->max[f] += EPS;
+ }
+
+ /* Setup input bounding box value pointers (the easy way) */
+ for (ee = 0; ee < di; ee++) {
+ x->p0[ee] = c->p[0][ee]; /* Construction base cube origin */
+ x->pmin[ee] = c->p[x->psxi->pmino[ee]][ee] - EPS;
+ x->pmax[ee] = c->p[x->psxi->pmaxo[ee]][ee] + EPS;
+ }
+
+ x->flags |= SPLX_FLAG_1; /* vv & iv done, nothing else */
+
+ x->aloc2 = x->aloc5 = NULL; /* Matrix allocations not done yet */
+
+ /* Add it to the face shared simplex hash index */
+ if (x->psxi->face) {
+ unsigned int hash;
+ int i;
+ /* See if we should re-size the simplex hash index */
+ if (++rc->nspx > (HASH_FILL_RATIO * rc->spx_hash_size)) {
+ for (i = 0; primes[i] > 0 && primes[i] <= rc->spx_hash_size; i++)
+ ;
+ if (primes[i] > 0) {
+ int spx_hash_size = rc->spx_hash_size; /* Old */
+ simplex **spxhashtop = rc->spxhashtop;
+
+ rc->spx_hash_size = primes[i];
+
+ DBG(("Increasing face simplex hash index to %d\n",spx_hash_size));
+//printf("~1 increasing simplex hash index size to %d\n",spx_hash_size);
+ /* Allocate a new index */
+ if ((rc->spxhashtop = (simplex **) rev_calloc(s, rc->spx_hash_size,
+ sizeof(simplex *))) == NULL)
+ error("rspl malloc failed - reverse simplex cache index");
+ INCSZ(s, rc->spx_hash_size * sizeof(simplex *));
+
+ /* Transfer all the simplexes to the new index */
+ for (i = 0; i < spx_hash_size; i++) {
+ simplex *x, *nx;
+ for (x = spxhashtop[i]; x != NULL; x = nx) {
+ nx = x->hlink;
+ hash = simplex_hash(rc, x->sdi, x->efdi, x->vix); /* New hash */
+ x->hlink = rc->spxhashtop[hash]; /* Add to new hash index */
+ rc->spxhashtop[hash] = x;
+ }
+ }
+ free(spxhashtop); /* Done with old index */
+ DECSZ(s, spx_hash_size * sizeof(simplex *));
+ }
+ }
+ hash = simplex_hash(rc, sdi, efdi, vix);
+
+ /* Add this to hash index */
+ x->hlink = rc->spxhashtop[hash];
+ rc->spxhashtop[hash] = x;
+//printf("~1 Added simplex to hash %d, rc->nspx = %d\n",hash,rc->nspx);
+ }
+
+//if (rc->nunlocked == 0 && rc->s->rev.sz > rc->s->rev.max_sz)
+//printf("~1 unable to decrease_revcache 1\n");
+
+ /* keep memory in check */
+ while (rc->nunlocked > 0 && rc->s->rev.sz > rc->s->rev.max_sz) {
+ if (decrease_revcache(rc) == 0)
+ break;
+ }
+ }
+ c->sx[nsdi][so] = x;
+ so++;
+ }
+ c->sxno[nsdi] = so; /* Record actual number in list */
+ c->flags |= CELL_FLAG_2; /* Note that cell now has simplexes */
+}
+
+/* Free up any allocated for a list of sub-simplexes */
+void
+free_simplex_info(
+cell *c,
+int nsdi /* non limit sub simplex dimensionaity */
+) {
+ int si, sxno = c->sxno[nsdi]; /* Number of simplexes */
+
+ for (si = 0; si < sxno; si++) { /* For all the simplexes */
+ simplex *x = c->sx[nsdi][si];
+ int dof = x->sdi - x->efdi;
+
+//printf("~1 freeing simplex, refcount = %d\n",x->refcount);
+ if (--x->refcount <= 0) { /* Last reference to this simplex */
+
+//printf("~1 freeing simplex 0x%x psxi = 0x%x\n",x,x->psxi);
+ if (x->psxi->face) {
+ unsigned int hash;
+ revcache *rc = c->s->rev.cache;
+
+ hash = simplex_hash(rc, x->sdi, x->efdi, x->vix);
+
+ /* Free it from the hash list */
+ if (rc->spxhashtop[hash] == x) {
+ rc->spxhashtop[hash] = x->hlink;
+ rc->nspx--;
+//printf("~1 removed simplex from hash %d, nspx now = %d\n",hash,rc->nspx);
+ } else {
+ simplex *xx;
+ for (xx = rc->spxhashtop[hash]; xx != NULL && xx->hlink != x; xx = xx->hlink)
+ ;
+ if (xx != NULL) { /* Found it */
+ xx->hlink = x->hlink;
+ rc->nspx--;
+//printf("~1 removed simplex from hash %d, nspx now = %d\n",hash,rc->nspx);
+ }
+//else
+//printf("~1 warning, failed to find face simplex hash %d, sdi = %d in cache index (nspx = %d)!!\n",hash,x->sdi,rc->nspx);
+ }
+ }
+ if (x->aloc2 != NULL) {
+ int adof = dof >= 0 ? dof : 0; /* Allocation dof */
+ int asize;
+ if (dof == 0)
+ asize = sizeof(double) * (x->efdi * x->sdi)
+ + sizeof(double *) * x->efdi
+ + sizeof(int) * x->sdi;
+ else
+ asize = sizeof(double) * (x->sdi * (x->efdi + x->sdi + adof + 2) + x->efdi)
+ + sizeof(double *) * (x->efdi + 2 * x->sdi);
+ free(x->aloc2);
+ DECSZ(x->s, asize);
+ }
+
+ if (x->aloc5 != NULL) {
+ int asize;
+ if (x->naux == dof)
+ asize = sizeof(double *) * x->naux
+ + sizeof(double) * (x->naux * dof)
+ + sizeof(int) * dof;
+ else
+ asize = sizeof(double *) * (x->naux + dof)
+ + sizeof(double) * (dof * (x->naux + dof + 1));
+ free(x->aloc5);
+ DECSZ(x->s, asize);
+ }
+
+ /* ~~ free any other simplex information */
+
+ free(x);
+ DECSZ(c->s, sizeof(simplex));
+ c->sx[nsdi][si] = NULL;
+ }
+ }
+ free(c->sx[nsdi]);
+ DECSZ(c->s, c->sxno[nsdi] * sizeof(simplex *));
+ c->sx[nsdi] = NULL;
+ c->sxno[nsdi] = 0;
+
+ /* ~~ free any other cell information */
+}
+
+/* - - - - - - - - - - - - */
+/* Check that an input space vector is within a given simplex, */
+/* and that it meets any ink limit. */
+/* Return zero if outside the simplex, */
+/* 1 normally if within the simplex, */
+/* and 2 if it would be over the ink limit if limit was enabled. */
+static int
+within_simplex(
+simplex *x, /* Simplex */
+double *p /* Input coords in simplex space */
+) {
+ rspl *s = x->s;
+ schbase *b = s->rev.sb;
+ int fdi = s->fdi;
+ int e, sdi = x->sdi; /* simplex dimensionality */
+ double cp, lp;
+ int rv = 1;
+ /* EPS is allowance for numeric error */
+ /* (Don't want solutions falling down */
+ /* the numerical cracks between the simplexes) */
+
+ /* Check we are within baricentric limits */
+ for (lp = 0.0, e = 0; e < sdi; e++) {
+ cp = p[e];
+ if ((cp+EPS) < lp) /* Outside baricentric or not in correct */
+ return 0; /* order for this simplex */
+ lp = cp;
+ }
+ if ((1.0+EPS) < lp) /* outside baricentric range */
+ return 0;
+
+ /* Compute limit using interp. - assume simplex would have been trivially rejected */
+ if (s->limitf != NULL) {
+ double sum = 0.0; /* Might be over the limit */
+ for (e = 0; e < sdi; e++)
+ sum += p[e] * (x->v[e][fdi] - x->v[e+1][fdi]);
+ sum += x->v[sdi][fdi];
+ if (sum > s->limitv) {
+ if (s->limiten != 0)
+ return 0; /* Exceeds ink limit */
+ else
+ rv = 2; /* would have exceeded limit */
+ }
+ }
+
+#ifdef NEVER
+ /* Constrain to legal values */
+ /* (Is this needed ?????) */
+ for (e = 0; e < sdi; e++) {
+ cp = p[e];
+ if (cp < 0.0)
+ p[e] = 0.0;
+ else if (cp > 1.0)
+ p[e] = 1.0;
+ }
+#endif
+ return rv;
+}
+
+/* Convert vector from simplex space to absolute cartesian space */
+static void simplex_to_abs(
+simplex *x,
+double *out, /* output in absolute space */
+double *in /* Input in simplex space */
+) {
+ rspl *s = x->s;
+ int e, di = s->di;
+ int *icomb = x->psxi->icomb; /* Coord combination order */
+
+ for (e = 0; e < di; e++) { /* For each absolute coord */
+ double ov = x->p0[e]; /* Base value */
+ int ee = icomb[e]; /* Simplex param index */
+ if (ee >= 0) /* Simplex param value */
+ ov += s->g.w[e] * in[ee];
+ else if (ee == -2) /* 1 value */
+ ov += s->g.w[e];
+ /* Else 0 value */
+ out[e] = ov;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given the parametric clip line equation, compute the */
+/* implicit equation in terms of the absolute output space. */
+/* Pad equation with target ink limit in case it is use */
+/* with CLIPSX sub-simplexes. */
+/* Note that no line equation values are returned if fdi = 1, */
+/* since there is no such thing as an implicit line equation. */
+static void
+init_line_eq(
+schbase *b,
+double st[MXRO], /* Start point */
+double de[MXRO] /* Delta */
+) {
+ rspl *s = b->s;
+ int ff, f, fdi = s->fdi;
+ int i, p;
+ double lgst;
+
+ DBG(("Computing clipping line implicit equation, dim = %d\n", fdi));
+
+ /* Pick a pivot element */
+ for (lgst = -1.0, p = -1, f = 0; f < fdi; f++) {
+ double tt = de[f];
+ b->cdir[f] = tt; /* Stash this away */
+ tt = fabs(tt);
+ if (tt > lgst) {
+ lgst = tt;
+ p = f;
+ }
+ }
+ if (p < 0) /* Shouldn't happen */
+ error("rspl rev, internal, trying to cope with zero length clip line\n");
+
+ if (b->cla == NULL)
+ b->cla = dmatrix(0, fdi-1, 0, fdi); /* Allow for ink limit supliment */
+
+ for (i = ff = 0; ff < fdi; ff++) { /* For the input rows */
+ if (ff == p) {
+ continue; /* Skip pivot row */
+ }
+ for (f = 0; f < fdi; f++) { /* For input & output columns */
+ if (f == p) {
+ b->cla[i][f] = -de[ff]; /* Last column is -ve delta value */
+ } else if (f == ff) {
+ b->cla[i][f] = de[p]; /* Diagonal is pivot value */
+ } else {
+ b->cla[i][f] = 0.0; /* Else zero */
+ }
+ }
+ b->clb[i] = de[p] * st[ff] - de[ff] * st[p];
+ i++;
+ }
+
+ /* Add ink limit target equation - */
+ /* interpolated ink value == target */
+ if (s->limitf != NULL) {
+ for (i = 0; i < (fdi-1); i++)
+ b->cla[i][fdi] = 0.0;
+
+ for (f = 0; f < fdi; f++)
+ b->cla[fdi-1][f] = 0.0;
+
+ b->cla[fdi-1][fdi] = 1.0;
+ b->clb[fdi-1] = s->limitv;
+ }
+
+#ifdef NEVER
+/* Verify that the implicit equation is correct */
+{
+ double pnt[MXRO], v[MXRO];
+ double pa; /* Parameter */
+ for (pa = 0.0; pa <= 1.0; pa += 0.125) {
+ for (f = 0; f < fdi; f++) {
+ pnt[f] = st[f] + pa * de[f];
+ }
+
+ /* Verify the implicit equation */
+ for (ff = 0; ff < (fdi-1); ff++) {
+ v[ff] = 0.0;
+ for (f = 0; f < fdi; f++) {
+ v[ff] += b->cla[ff][f] * pnt[f];
+ }
+ v[ff] -= b->clb[ff];
+ if (v[ff] < 0.0)
+ v[ff] = -v[ff];
+ if (v[ff] > 0.000001) {
+ printf("Point on clip line = %f %f %f\n",pnt[0],pnt[1],pnt[2]);
+ printf("Implicit %d error of = %f\n",ff, v[ff]);
+ }
+ }
+ }
+}
+#endif /* NEVER */
+
+}
+
+/* - - - - - - */
+/* Simpex solution info #2 */
+
+/* Create the LU or SVD decomp needed to compute solution or locus. */
+/* Return non-zero if it cannot be created */
+static int
+add_lu_svd(simplex *x) {
+
+ if (x->flags & SPLX_FLAG_2F) { /* Previously failed */
+ return 1;
+ }
+ if (!(x->flags & SPLX_FLAG_2)) {
+ int ee, e, sdi = x->sdi;
+ int f, efdi = x->efdi;
+ int dof = sdi-efdi; /* Degree of freedom of locus, or -ve over specification */
+ int adof = dof >= 0 ? dof : 0; /* Allocation dof */
+ int i;
+
+ if (x->aloc2 == NULL) { /* Allocate space for matricies and arrays */
+ /* Do this in one hit to minimise malloc overhead */
+ if (dof == 0) {
+ int i;
+ char *mem;
+ int asize = sizeof(double) * (efdi * sdi)
+ + sizeof(double *) * efdi
+ + sizeof(int) * sdi;
+
+ if ((x->aloc2 = mem = (char *) rev_malloc(x->s, asize)) == NULL)
+ error("rspl malloc failed - reverse cell sub-simplex matricies");
+ INCSZ(x->s, asize);
+
+ /* Allocate biggest to smallest (double, pointers, ints) */
+ /* to make sure that items lie on the natural boundaries. */
+
+ /* Reserve matrix doubles */
+ mem += efdi * sdi * sizeof(double);
+
+ /* Allocate pointers */
+ x->d_u = (double **)mem, mem += efdi * sizeof(double *);
+
+ /* Allocate ints */
+ x->d_w = (double *)mem, mem += sdi * sizeof(int);
+
+#ifdef DEBUG
+ if (mem != (x->aloc2 + asize))
+ error("~1 aloc2a assert failed! Is %d, should be %d\n",mem - x->aloc2,asize);
+#endif /* DEBUG */
+
+ /* Reset and allocate matrix doubles */
+ mem = x->aloc2;
+ for (i = 0; i < efdi; i++)
+ x->d_u[i] = (double *)mem, mem += sdi * sizeof(double);
+
+ } else {
+ int i;
+ char *mem;
+ int asize = sizeof(double) * (sdi * (efdi + sdi + adof + 2) + efdi)
+ + sizeof(double *) * (efdi + 2 * sdi);
+
+ if ((x->aloc2 = mem = (char *) rev_malloc(x->s, asize)) == NULL)
+ error("rspl malloc failed - reverse cell sub-simplex matricies");
+ INCSZ(x->s, asize);
+
+ /* Allocate biggest to smallest (double, pointers, ints) */
+ /* to make sure that items lie on the natural boundaries. */
+
+ /* Reserve matrix doubles */
+ mem += sdi * (efdi + sdi + adof) * sizeof(double);
+
+ /* Allocate doubles */
+ x->lo_xb = (double *)mem, mem += efdi * sizeof(double);
+ x->lo_bd = (double *)mem; mem += sdi * sizeof(double);
+ x->d_w = (double *)mem, mem += sdi * sizeof(double);
+
+ /* Allocate pointers */
+ x->d_u = (double **)mem, mem += efdi * sizeof(double *);
+ x->d_v = (double **)mem, mem += sdi * sizeof(double *);
+ x->lo_l = (double **)mem, mem += sdi * sizeof(double *);
+
+#ifdef DEBUG
+ if (mem != (x->aloc2 + asize))
+ error("~1 aloc2b assert failed! Is %d, should be %d\n",mem - x->aloc2,asize);
+#endif /* DEBUG */
+
+ /* Reset and allocate matrix doubles */
+ mem = x->aloc2;
+ for (i = 0; i < efdi; i++)
+ x->d_u[i] = (double *)mem, mem += sdi * sizeof(double);
+ for (i = 0; i < sdi; i++)
+ x->d_v[i] = (double *)mem, mem += sdi * sizeof(double);
+ for (i = 0; i < sdi; i++)
+ x->lo_l[i] = (double *)mem, mem += adof * sizeof(double);
+
+ /* Init any values that will be read before being written to. */
+ for (f = 0; f < efdi; f++)
+ x->lo_xb[f] = 1e100; /* Silly value */
+ }
+ }
+
+ /* Setup matrix from vertex values */
+ for (f = 0; f < efdi; f++)
+ for (e = 0; e < sdi; e++)
+ x->d_u[f][e] = x->v[e][f] - x->v[e+1][f];
+
+ if (dof == 0) { /* compute LU */
+ double rip;
+#ifdef STATS
+ x->s->rev.st[x->s->rev.sb->op].sinited2a++;
+#endif /* STATS */
+ if (lu_decomp(x->d_u, sdi, (int *)x->d_w, &rip)) {
+ x->flags |= SPLX_FLAG_2F; /* Failed */
+ return 1;
+ }
+ } else {
+//printf("~~ Creating SVD decomp, sdi = %d, efdi = %d\n", sdi, efdi);
+
+#ifdef STATS
+ x->s->rev.st[x->s->rev.sb->op].sinited2b++;
+#endif /* STATS */
+ if (svdecomp(x->d_u, x->d_w, x->d_v, efdi, sdi)) {
+ x->flags |= SPLX_FLAG_2F; /* Failed */
+ return 1;
+ }
+
+ /* Threshold the singular values W[] */
+ svdthresh(x->d_w, sdi);
+
+ if (dof >= 0) { /* If we expect a locus */
+//printf("~~ got dif %d locus from SVD\n",dof);
+ /* copy the locus direction coefficients out */
+ for (i = e = 0; e < sdi; e++) {
+ if (x->d_w[e] == 0.0) { /* Found a zero W[] */
+ if (i < dof) {
+ for (ee = 0; ee < sdi; ee++) { /* Copy column of V[][] */
+ x->lo_l[ee][i] = x->d_v[ee][e];
+ }
+ }
+ i++;
+ }
+ }
+ if (i != dof) {
+//printf("~~ got unexpected dof in svd\n");
+ x->flags |= SPLX_FLAG_2F; /* Failed */
+ return 1; /* Didn't get expected d.o.f. */
+ }
+ }
+ }
+ x->flags |= SPLX_FLAG_2; /* Set flag so that it isn't attempted again */
+
+//if (x->s->rev.cache->nunlocked == 0 && x->s->rev.sz > x->s->rev.max_sz)
+//printf("~1 unable to decrease_revcache 2\n");
+
+ /* keep memory in check */
+ while (x->s->rev.cache->nunlocked > 0 && x->s->rev.sz > x->s->rev.max_sz) {
+ if (decrease_revcache(x->s->rev.cache) == 0)
+ break;
+ }
+ }
+ return 0;
+}
+
+/* - - - - - - */
+/* Simplex solution info #4 */
+
+/* Calculate the solution locus equation for this simplex and target */
+/* (The direction was calculated by add_svd(), but now calculate */
+/* the base solution point for this particular reverse lookup) */
+/* Return non-zero if this point canot be calculated */
+/* We are assuming that sdi > efdi */
+static int
+add_locus(
+schbase *b,
+simplex *x
+) {
+ int sdi = x->sdi;
+ int f, efdi = x->efdi;
+ int doback = 0;
+
+#ifdef STATS
+ x->s->rev.st[x->s->rev.sb->op].sinited4++;
+#endif /* STATS */
+ /* Use output of svdcmp() to solve overspecified and/or */
+ /* singular equation A.x = b */
+
+ /* Init the RHS B[] vector, and check if it doesn't match */
+ /* that used to compute base value last time. */
+ for (f = 0; f < efdi; f++) {
+ double xb = b->v[f] - x->v[sdi][f];
+ if (x->lo_xb[f] != xb) {
+ x->lo_xb[f] = xb;
+ doback = 1; /* RHS differs, so re-compute */
+ }
+ }
+
+#ifdef STATS
+ if (doback && (x->flags & SPLX_FLAG_4))
+ x->s->rev.st[x->s->rev.sb->op].sinited4i++;
+#endif /* STATS */
+
+ /* Compute locus */
+ if (doback || !(x->flags & SPLX_FLAG_4))
+ svdbacksub(x->d_u, x->d_w, x->d_v, x->lo_xb, x->lo_bd, efdi, sdi);
+
+ x->flags |= SPLX_FLAG_4;
+
+//if (x->s->rev.cache->nunlocked == 0 && x->s->rev.sz > x->s->rev.max_sz)
+//printf("~1 unable to decrease_revcache 3\n");
+
+ /* keep memory in check */
+ while (x->s->rev.cache->nunlocked > 0 && x->s->rev.sz > x->s->rev.max_sz) {
+ if (decrease_revcache(x->s->rev.cache) == 0)
+ break;
+ }
+
+ return 0;
+}
+
+/* - - - - - - */
+/* Simplex solution info #5 */
+
+/* Compute LU or SVD decomp of lo_l */
+/* Allocates the memory for the various matricies */
+/* Return non-zero if this canot be calculated. */
+static int
+add_auxil_lu_svd(
+schbase *b,
+simplex *x
+) {
+ int ee, sdi = x->sdi;
+ int f, efdi = x->efdi;
+ int dof = sdi-efdi; /* Degree of freedom of locus */
+ int naux = b->naux; /* Number of auxiliaries actually available */
+
+#ifdef STATS
+ if (x->aaux != b->naux || x->auxbm != b->auxbm)
+ x->s->rev.st[x->s->rev.sb->op].sinited5i++;
+#endif /* STATS */
+
+ if (x->aaux != b->naux) { /* Number of auxiliaries has changed */
+ if (x->aloc5 != NULL) {
+ int asize;
+ if (x->naux == dof)
+ asize = sizeof(double *) * x->naux
+ + sizeof(double) * (x->naux * dof)
+ + sizeof(int) * dof;
+ else
+ asize = sizeof(double *) * (x->naux + dof)
+ + sizeof(double) * (dof * (x->naux + dof + 1));
+ free(x->aloc5);
+ x->aloc5 = NULL;
+ DECSZ(x->s, asize);
+ }
+ x->flags &= ~(SPLX_FLAG_5 | SPLX_FLAG_5F); /* Force recompute */
+ }
+
+ if (x->auxbm != b->auxbm) { /* Different selection of auxiliaries */
+ x->flags &= ~(SPLX_FLAG_5 | SPLX_FLAG_5F); /* Force recompute */
+ }
+
+ if (x->flags & SPLX_FLAG_5F) { /* Previously failed */
+ return 1;
+ }
+ if (!(x->flags & SPLX_FLAG_5)) {
+ int *icomb = x->psxi->icomb; /* abs -> simplex coordinate translation */
+
+ if (x->aloc5 == NULL) { /* Allocate space for matricies and arrays */
+ /* Do this in one hit to minimise malloc overhead */
+ if (naux == dof) {
+ int i;
+ char *mem;
+ int asize = sizeof(double *) * naux
+ + sizeof(double) * (naux * dof)
+ + sizeof(int) * dof;
+
+ if ((x->aloc5 = mem = (char *) rev_malloc(x->s, asize)) == NULL)
+ error("rspl malloc failed - reverse cell sub-simplex matricies");
+ INCSZ(x->s, asize);
+
+ /* Allocate biggest to smallest (double, pointers, ints) */
+ /* to make sure that items lie on the natural boundaries. */
+
+ /* Reserve matrix doubles */
+ mem += naux * dof * sizeof(double);
+
+ /* Allocate pointers and ints */
+ x->d_u = (double **)mem, mem += naux * sizeof(double *);
+ x->d_w = (double *)mem, mem += dof * sizeof(int);
+
+#ifdef DEBUG
+ if (mem != (x->aloc5 + asize))
+ error("aloc5a assert failed! Is %d, should be %d\n",mem - x->aloc5,asize);
+#endif /* DEBUG */
+
+ /* Reset and allocate matrix doubles */
+ mem = x->aloc5;
+ for (i = 0; i < naux; i++)
+ x->d_u[i] = (double *)mem, mem += dof * sizeof(double);
+ } else {
+ int i;
+ char *mem;
+ int asize = sizeof(double *) * (naux + dof)
+ + sizeof(double) * (dof * (naux + dof + 1));
+
+ if ((x->aloc5 = mem = (char *) rev_malloc(x->s, asize)) == NULL)
+ error("rspl malloc failed - reverse cell sub-simplex matricies");
+ INCSZ(x->s, asize);
+
+ /* Allocate biggest to smallest (double, pointers, ints) */
+ /* to make sure that items lie on the natural boundaries. */
+
+ /* Reserve matrix doubles */
+ mem += dof * (naux + dof) * sizeof(double);
+
+ /* Allocate doubles */
+ x->ax_w = (double *)mem, mem += dof * sizeof(double);
+
+ /* Allocate pointers, ints */
+ x->ax_u = (double **)mem, mem += naux * sizeof(double *);
+ x->ax_v = (double **)mem, mem += dof * sizeof(double *);
+
+#ifdef DEBUG
+ if (mem != (x->aloc5 + asize))
+ error("aloc5b assert failed! Is %d, should be %d\n",mem - x->aloc5,asize);
+#endif /* DEBUG */
+
+ /* Reset and allocate matrix doubles */
+ mem = x->aloc5;
+ for (i = 0; i < naux; i++)
+ x->ax_u[i] = (double *)mem, mem += dof * sizeof(double);
+ for (i = 0; i < dof; i++)
+ x->ax_v[i] = (double *)mem, mem += dof * sizeof(double);
+ }
+ x->aaux = naux; /* Number of auxiliaries allocated for */
+ }
+
+ /* Setup A[][] matrix to decompose, and figure number of auxiliaries actually needed */
+ for (ee = naux = 0; ee < b->naux; ee++) {
+ int ei = icomb[b->auxi[ee]]; /* Simplex relative auxiliary index */
+ if (ei < 0)
+ continue; /* aux corresponds with fixed input value for this simplex */
+ for (f = 0; f < dof; f++)
+ x->ax_u[naux][f] = x->lo_l[ei][f];
+ naux++;
+ }
+ x->naux = naux; /* Number of auxiliaries actually available */
+ x->auxbm = b->auxbm; /* Mask of auxiliaries used */
+
+ if (naux == dof) { /* Use LU decomp to solve exactly */
+ double rip;
+
+#ifdef STATS
+ x->s->rev.st[x->s->rev.sb->op].sinited5a++;
+#endif /* STATS */
+ if (lu_decomp(x->ax_u, dof, (int *)x->ax_w, &rip)) {
+ x->flags |= SPLX_FLAG_5F;
+ return 1;
+ }
+
+ } else if (naux > 0) { /* Use SVD to solve least squares */
+
+#ifdef STATS
+ x->s->rev.st[x->s->rev.sb->op].sinited5b++;
+#endif /* STATS */
+ if (svdecomp(x->ax_u, x->ax_w, x->ax_v, naux, dof)) {
+ x->flags |= SPLX_FLAG_5F;
+ return 1;
+ }
+
+ /* Threshold the singular values W[] */
+ svdthresh(x->ax_w, dof);
+ } /* else naux == 0, don't setup anything */
+
+ x->flags |= SPLX_FLAG_5;
+
+//if (x->s->rev.cache->nunlocked == 0 && x->s->rev.sz > x->s->rev.max_sz)
+//printf("~1 unable to decrease_revcache 4\n");
+
+ /* keep memory in check */
+ while (x->s->rev.cache->nunlocked > 0 && x->s->rev.sz > x->s->rev.max_sz) {
+ if (decrease_revcache(x->s->rev.cache) == 0)
+ break;
+ }
+ }
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Initialise a static sub-simplex verticy information table */
+void
+rspl_init_ssimplex_info(
+rspl *s,
+ssxinfo *xip, /* Pointer to sub-simplex info structure to init. */
+int sdi /* Sub-simplex dimensionality (range 0 - di) */
+) {
+ int e, di = s->di; /* Dimensionality */
+ int vi, nospx; /* Number of sub-simplexes */
+ XCOMBO(vcmb, MXDI, sdi+1, 1 << di);/* Simplex dimension sdi out of cube dimension di counter */
+
+ DBG(("init_ssimplex_info called with sdi = %d\n",sdi));
+ /* First count the number of sub-simplexes */
+ nospx = 0;
+ XCB_INIT(vcmb);
+ while (!XCB_DONE(vcmb)) {
+ nospx++;
+ XCB_INC(vcmb);
+ }
+
+ xip->sdi = sdi;
+ xip->nospx = nospx;
+ if ((xip->spxi = (psxinfo *) rev_calloc(s, nospx, sizeof(psxinfo))) == NULL)
+ error("rspl malloc failed - reverse cell sub-simplex info array");
+ INCSZ(s, nospx * sizeof(psxinfo));
+
+ DBG(("Number of subsimplex = %d\n",nospx));
+ /* For all sub-simplexes */
+ XCB_INIT(vcmb);
+ for (vi = 0; vi < nospx; vi++) {
+ psxinfo *x = &xip->spxi[vi];
+ int i;
+ int andm, orm;
+
+ /* XCOMB generates verticies in order from max to min offset */
+
+ /* Compute Absolute -> Parameter mapping */
+ for (e = 0; e < di; e++) { /* For each absolute axis */
+
+ if ((vcmb[sdi] & (1<<e)) != 0) {
+ x->icomb[e] = -2; /* This abs is always '1' */
+
+ } else if ((vcmb[0] & (1<<e)) == 0) {
+ x->icomb[e] = -1; /* This abs is always '0' */
+
+ } else {
+ for (i = 0; i < sdi; i++) { /* For each verticy in large to small order (!first) */
+ if ((vcmb[i] & (1<<e)) != 0 &&
+ (vcmb[i+1] & (1<<e)) == 0) {/* Transition from offset 1 to 0 */
+ x->icomb[e] = i; /* This is parameter */
+ break;
+ }
+ }
+ }
+ }
+
+ /* Compute fwd grid offsets for each simplex vertex in baricentric order */
+ for (i = 0; i <= sdi; i++) { /* For each verticy */
+ int pmin[MXRI], pmax[MXRI];
+ x->offs[i] = vcmb[i];
+ x->goffs[i] = s->g.hi[vcmb[i]];
+ x->foffs[i] = s->g.fhi[vcmb[i]];
+
+ /* Setup input coordinate bounding box value offsets */
+ if (i == 0) { /* Init to first vertex of simplex */
+ for (e = 0; e < di; e++) { /* Input space */
+ x->pmino[e] = x->pmaxo[e] = vcmb[i];
+ pmin[e] = pmax[e] = vcmb[i] & (1<<e);
+ }
+ } else {
+ for (e = 0; e < di; e++) { /* Input space */
+ int vv = vcmb[i] & (1<<e);
+ if (vv < pmin[e]) { /* Adjust min/max offsets */
+ x->pmino[e] = vcmb[i];
+ pmin[e] = vv;
+ } else if (vv > pmax[e]) {
+ x->pmaxo[e] = vcmb[i];
+ pmax[e] = vv;
+ }
+ }
+ }
+ }
+
+ /* See if the sub-simplex lies on a cube face */
+ andm = ~0;
+ orm = 0;
+ for (i = 0; i <= sdi; i++) { /* For each verticy */
+ andm &= vcmb[i];
+ orm |= vcmb[i];
+ }
+ /* If one coordinate is common (all 0 or all 1) to the verticies, */
+ /* they must all be on the same cube face. */
+ if (andm != 0 || orm != ((1 << di)-1))
+ x->face = 1;
+ else
+ x->face = 0;
+
+#ifdef DEBUG
+ printf("Verticies = ");
+ for (i = 0; i <= sdi; i++)
+ printf("%d ",vcmb[i]);
+ printf("\n");
+
+ printf("Face = %s\n",x->face ? "True" : "False");
+
+ printf("Abs -> Parm = ");
+ for (e = 0; e < di; e++)
+ printf("%d ",x->icomb[e]);
+ printf("\n");
+
+ printf("Grid Offset = ");
+ for (e = 0; e <= sdi; e++)
+ printf("%d ",x->goffs[e]);
+ printf("Float Offset = ");
+ for (e = 0; e <= sdi; e++)
+ printf("%d ",x->foffs[e]);
+ printf("\n");
+ printf("\n");
+#endif /* DEBUG */
+
+ /* Increment the counter value */
+ XCB_INC(vcmb);
+ }
+}
+
+/* Free the given sub-simplex verticy information */
+void
+rspl_free_ssimplex_info(
+rspl *s,
+ssxinfo *xip /* Pointer to sub-simplex info structure */
+) {
+ if (xip == NULL) /* Assert */
+ return;
+
+ free(xip->spxi);
+ DECSZ(s, xip->nospx * sizeof(psxinfo));
+ xip->spxi = NULL;
+}
+
+/* ====================================================== */
+/* Reverse cell cache code */
+
+/* Allocate and initialise the reverse cell cache */
+static revcache *
+alloc_revcache(
+rspl *s
+) {
+ revcache *rc;
+
+ DBG(("alloc_revcache called\n"));
+ if ((rc = (revcache *) rev_calloc(s, 1, sizeof(revcache))) == NULL)
+ error("rspl malloc failed - reverse cell cache");
+ INCSZ(s, sizeof(revcache));
+
+ rc->s = s; /* For stats */
+
+ /* Allocate an initial cell hash index */
+ rc->cell_hash_size = primes[0];
+
+ if ((rc->hashtop = (cell **) rev_calloc(s, rc->cell_hash_size, sizeof(cell *))) == NULL)
+ error("rspl malloc failed - reverse cell cache index");
+ INCSZ(s, rc->cell_hash_size * sizeof(cell *));
+
+ /* Allocate an initial simplex face match hash index */
+ rc->spx_hash_size = primes[0];
+
+ if ((rc->spxhashtop = (simplex **) rev_calloc(s, rc->spx_hash_size, sizeof(simplex *))) == NULL)
+ error("rspl malloc failed - reverse simplex cache index");
+ INCSZ(s, rc->spx_hash_size * sizeof(simplex *));
+
+ return rc;
+}
+
+/* Free the reverse cell cache */
+static void
+free_revcache(revcache *rc) {
+ int i;
+ cell *cp, *ncp;
+
+ /* Free any stuff allocated in the cell contents, and the cell itself. */
+ for (cp = rc->mrubot; cp != NULL; cp = ncp) {
+ ncp = cp->mruup;
+ free_cell_contents(cp);
+ free(cp);
+ DECSZ(rc->s, sizeof(cell));
+ }
+
+ /* Free the hash indexes */
+ free(rc->hashtop);
+ DECSZ(rc->s, rc->cell_hash_size * sizeof(cell *));
+ free(rc->spxhashtop);
+ DECSZ(rc->s, rc->spx_hash_size * sizeof(simplex *));
+
+ DECSZ(rc->s, sizeof(revcache));
+ free(rc);
+}
+
+/* Invalidate the whole cache */
+static void
+invalidate_revcache(
+revcache *rc)
+{
+ int i;
+ cell *cp;
+
+ rc->nunlocked = 0;
+
+ /* Free any stuff allocated in the cell contents */
+ for (cp = rc->mrubot; cp != NULL; cp = cp->mruup) {
+ free_cell_contents(cp);
+ cp->refcount = 0; /* Make sure they can now be reused */
+ cp->ix = 0;
+ cp->flags = 0; /* Contents needs re-initializing */
+ rc->nunlocked++;
+ }
+
+ /* Clear the hash table so they can't be hit */
+ for (i = 0; i < rc->cell_hash_size; i++) {
+ rc->hashtop[i] = NULL;
+ }
+
+}
+
+#define HASH(xx, yy) ((yy) % xx->cell_hash_size)
+
+/* Allocate another cell, and add it to the cache. */
+/* This may re-size the hash index too. */
+/* Return the pointer to the new cell. */
+/* (Note it's not our job here to honour the memory limit) */
+static cell *
+increase_revcache(
+revcache *rc
+) {
+ cell *nxcell; /* Newly allocated cell */
+ int i;
+
+ DBG(("Adding another chunk of cells to cache\n"));
+
+#ifdef NEVER /* We may be called with force != 0 */
+ if (rc->s->rev.sz >= rc->s->rev.max_sz)
+ return NULL;
+#endif
+
+ if ((nxcell = (cell *) rev_calloc(rc->s, 1, sizeof(cell))) == NULL)
+ error("rspl malloc failed - reverse cache cells");
+ INCSZ(rc->s, sizeof(cell));
+
+ nxcell->s = rc->s;
+
+ /* Add cell to the bottom of the cache mru linked list */
+ if (rc->mrutop == NULL) /* List was empty */
+ rc->mrutop = nxcell;
+ else {
+ rc->mrubot->mrudown = nxcell; /* Splice into bottom */
+ nxcell->mruup = rc->mrubot;
+ }
+ rc->mrubot = nxcell;
+ rc->nacells++;
+ rc->nunlocked++;
+
+ DBG(("cache is now %d cells\n",rc->nacells));
+
+ /* See if the hash index should be re-sized */
+ if (rc->nacells > (HASH_FILL_RATIO * rc->cell_hash_size)) {
+ for (i = 0; primes[i] > 0 && primes[i] <= rc->cell_hash_size; i++)
+ ;
+ if (primes[i] > 0) {
+ int cell_hash_size = rc->cell_hash_size; /* Old */
+ cell **hashtop = rc->hashtop;
+
+ rc->cell_hash_size = primes[i];
+
+ DBG(("Increasing cell cache hash index to %d\n",cell_hash_size));
+ /* Allocate a new index */
+ if ((rc->hashtop = (cell **) rev_calloc(rc->s, rc->cell_hash_size, sizeof(cell *))) == NULL)
+ error("rspl malloc failed - reverse cell cache index");
+ INCSZ(rc->s, rc->cell_hash_size * sizeof(cell *));
+
+ /* Transfer all the cells to the new index */
+ for (i = 0; i < cell_hash_size; i++) {
+ cell *c, *nc;
+ for (c = hashtop[i]; c != NULL; c = nc) {
+ int hash;
+ nc = c->hlink;
+ hash = HASH(rc, c->ix); /* New hash */
+ c->hlink = rc->hashtop[hash]; /* Add to new hash index */
+ rc->hashtop[hash] = c;
+ }
+ }
+
+ /* Done with old index */
+ free(hashtop);
+ DECSZ(rc->s, cell_hash_size * sizeof(cell *));
+ }
+ }
+
+ return nxcell;
+}
+
+/* Reduce the cache memory usage by freeing the least recently used unlocked cell. */
+/* Return nz if we suceeeded in freeing some memory. */
+static int decrease_revcache(
+revcache *rc /* Reverse cache structure */
+) {
+ int hit = 0;
+ int hash;
+ cell *cp;
+
+ DBG(("Decreasing cell cache memory allocation by freeing a cell\n"));
+
+ /* Use the least recently used unlocked cell */
+ for (cp = rc->mrubot; cp != NULL && cp->refcount > 0; cp = cp->mruup)
+ ;
+
+ /* Run out of unlocked cells */
+ if (cp == NULL) {
+ DBG(("Failed to find unlocked cell to free\n"));
+//printf("~1 failed to decrease memory\n");
+ return 0;
+ }
+
+ /* If it has been used before, free up the simplexes */
+ free_cell_contents(cp);
+
+ /* Remove from current hash index (if it is in it) */
+ hash = HASH(rc,cp->ix); /* Old hash */
+ if (rc->hashtop[hash] == cp) {
+ rc->hashtop[hash] = cp->hlink;
+ } else {
+ cell *c;
+ for (c = rc->hashtop[hash]; c != NULL && c->hlink != cp; c = c->hlink)
+ ;
+ if (c != NULL)
+ c->hlink = cp->hlink;
+ }
+
+ /* Free up this cell - Remove it from LRU list */
+ if (rc->mrutop == cp)
+ rc->mrutop = cp->mrudown;
+ if (rc->mrubot == cp)
+ rc->mrubot = cp->mruup;
+ if (cp->mruup != NULL)
+ cp->mruup->mrudown = cp->mrudown;
+ if (cp->mrudown != NULL)
+ cp->mrudown->mruup = cp->mruup;
+ cp->mruup = cp->mrudown = NULL;
+ free(cp);
+ DECSZ(rc->s, sizeof(cell));
+ rc->nacells--;
+ rc->nunlocked--;
+
+ DBG(("Freed a rev cache cell\n"));
+ return 1;
+}
+
+/* Return a pointer to an appropriate reverse cell */
+/* cache structure. cell->flags will be 0 if the cell */
+/* has been reallocated. cell contents will be 0 if */
+/* never used before. */
+/* The cell reference count is incremented, so that it */
+/* can't be thrown out of the cache. The cell must be */
+/* released with uncache_rcell() when it's no longer needed. */
+/* return NULL if we ran out of room in the cache */
+static cell *cache_rcell(
+revcache *rc, /* Reverse cache structure */
+int ix, /* fwd index of cell */
+int force /* if nz, force memory allocation, so that we have at least one cell */
+) {
+ int hit = 0;
+ int hash;
+ cell *cp;
+
+ /* keep memory in check - fail if we're out of memory and can't free any */
+ /* (Doesn't matter if it might be a hit, it will get picked up the next time) */
+ if (!force && rc->s->rev.sz > rc->s->rev.max_sz && rc->nunlocked <= 0) {
+ return NULL;
+ }
+
+//if (rc->nunlocked == 0 && rc->s->rev.sz > rc->s->rev.max_sz)
+//printf("~1 unable to decrease_revcache 5\n");
+
+ /* Free up memory to get below threshold */
+ while (rc->nunlocked > 0 && rc->s->rev.sz > rc->s->rev.max_sz) {
+ if (decrease_revcache(rc) == 0)
+ break;
+ }
+
+ hash = HASH(rc,ix); /* Compute hash of fwd cell index */
+
+ /* See if we get a cache hit */
+ for (cp = rc->hashtop[hash]; cp != NULL; cp = cp->hlink) {
+ if (ix == cp->ix) { /* Hit */
+ hit = 1;
+#ifdef STATS
+ rc->s->rev.st[rc->s->rev.sb->op].chits++;
+#endif /* STATS */
+ break;
+ }
+ }
+ if (!hit) { /* No hit, use new cell or the least recently used cell */
+ int ohash;
+
+ /* If we haven't used all our memory, or if we are forced and have */
+ /* no cell we can re-use, then noallocate another cell */
+ if (rc->s->rev.sz < rc->s->rev.max_sz || (force && rc->nunlocked == 0)) {
+ cp = increase_revcache(rc);
+ hash = HASH(rc,ix); /* Re-compute hash in case hash size changed */
+//printf("~1 using new cell\n");
+ } else {
+//printf("~1 memory limit has been reached, using old cell\n");
+
+ for (;;) {
+ /* Use the least recently used unlocked cell */
+ for (cp = rc->mrubot; cp != NULL && cp->refcount > 0; cp = cp->mruup)
+ ;
+
+ /* Run out of unlocked cells */
+ if (cp == NULL) {
+//printf("~1 none available\n");
+ return NULL;
+ }
+
+ /* If it has been used before, free up the simplexes */
+ free_cell_contents(cp);
+
+ /* Remove from current hash index (if it is in it) */
+ ohash = HASH(rc,cp->ix); /* Old hash */
+ if (rc->hashtop[ohash] == cp) {
+ rc->hashtop[ohash] = cp->hlink;
+ } else {
+ cell *c;
+ for (c = rc->hashtop[ohash]; c != NULL && c->hlink != cp; c = c->hlink)
+ ;
+ if (c != NULL)
+ c->hlink = cp->hlink;
+ }
+
+ /* If we're now under the memory limit, use this cell */
+ if (rc->s->rev.sz < rc->s->rev.max_sz) {
+ break;
+ }
+
+//printf("~1 freeing a cell\n");
+ /* Free up this cell and look for another one */
+ /* Remove it from LRU list */
+ if (rc->mrutop == cp)
+ rc->mrutop = cp->mrudown;
+ if (rc->mrubot == cp)
+ rc->mrubot = cp->mruup;
+ if (cp->mruup != NULL)
+ cp->mruup->mrudown = cp->mrudown;
+ if (cp->mrudown != NULL)
+ cp->mrudown->mruup = cp->mruup;
+ cp->mruup = cp->mrudown = NULL;
+ free(cp);
+ DECSZ(rc->s, sizeof(cell));
+ rc->nacells--;
+ rc->nunlocked--;
+ }
+ }
+
+#ifdef STATS
+ rc->s->rev.st[rc->s->rev.sb->op].cmiss++;
+#endif /* STATS */
+
+ /* Add this cell to hash index */
+ cp->hlink = rc->hashtop[hash];
+ rc->hashtop[hash] = cp; /* Add to hash table and list */
+
+ cp->ix = ix;
+ cp->flags = 0; /* Contents needs re-initializing */
+//printf("~1 returning fresh cell\n");
+ }
+
+ /* Move slected cell to the top of the mru list */
+ if (cp->mruup != NULL) { /* This one wasn't already at top */
+ cp->mruup->mrudown = cp->mrudown;
+ if (cp->mrudown == NULL) /* This was bottom */
+ rc->mrubot = cp->mruup; /* New bottom */
+ else
+ cp->mrudown->mruup = cp->mruup;
+ /* Put this one at the top */
+ rc->mrutop->mruup = cp;
+ cp->mrudown = rc->mrutop;
+ rc->mrutop = cp;
+ cp->mruup = NULL;
+ }
+ if (cp->refcount == 0) {
+ rc->nunlocked--;
+ }
+
+ cp->refcount++;
+
+ return cp;
+}
+
+/* Tell the cache that we aren't using this cell anymore, */
+/* but to keep it in case it is needed again. */
+static void uncache_rcell(
+revcache *rc, /* Reverse cache structure */
+cell *cp
+) {
+ if (cp->refcount > 0) {
+ cp->refcount--;
+ if (cp->refcount == 0) {
+ rc->nunlocked++;
+ }
+ } else
+ warning("rspl cell cache assert: refcount overdecremented!");
+}
+
+/* ====================================================== */
+/* Reverse rspl setup functions */
+
+/* Called by rspl initialisation */
+/* Note that reverse cell lookup tables are not */
+/* allocated & created until the first call */
+/* to a reverse interpolation function. */
+void
+init_rev(rspl *s) {
+
+ /* First section */
+ s->rev.inited = 0;
+ s->rev.res = 0;
+ s->rev.no = 0;
+ s->rev.rev = NULL;
+
+ /* Second section */
+ s->rev.rev_valid = 0;
+ s->rev.nnrev = NULL;
+
+ /* Third section */
+ s->rev.cache = NULL;
+
+ /* Fourth section */
+ s->rev.sb = NULL;
+
+ /* Methods */
+ s->rev_set_limit = rev_set_limit_rspl;
+ s->rev_get_limit = rev_get_limit_rspl;
+ s->rev_interp = rev_interp_rspl;
+ s->rev_locus = rev_locus_rspl;
+ s->rev_locus_segs = rev_locus_segs_rspl;
+}
+
+/* Free up all the reverse interpolation info */
+void free_rev(
+rspl *s /* Pointer to rspl grid */
+) {
+ int e, di = s->di;
+ int **rpp, *rp;
+
+#ifdef STATS
+ {
+ int i, totcalls = 0;
+ for (i = 0; i < 5; i++) {
+ totcalls += s->rev.st[i].searchcalls;
+ }
+
+ printf("\n===============================\n");
+ printf("di = %d, do = %d\n",s->di, s->fdi);
+ for (i = 0; i < 5; i++) {
+ int calls = s->rev.st[i].searchcalls;
+ if (calls == 0)
+ continue;
+ printf("\n- - - - - - - - - - - - - - - -\n");
+ printf("Operation %s\n",opnames[i]);
+ printf("Search calls = %d = %f%%\n",s->rev.st[i].searchcalls,
+ 100.0 * s->rev.st[i].searchcalls/totcalls);
+ printf("Cells searched/call = %f\n",s->rev.st[i].csearched/(double)calls);
+ printf("Simplexes searched/call = %f\n",s->rev.st[i].ssearched/(double)calls);
+ printf("Simplexes inited level 1/call = %f\n",s->rev.st[i].sinited/(double)calls);
+ printf("Simplexes inited level 2 (LU)/call = %f\n",s->rev.st[i].sinited2a/(double)calls);
+ printf("Simplexes inited level 2 (SVD)/call = %f\n",s->rev.st[i].sinited2b/(double)calls);
+ printf("Simplexes invalidated level 4/call = %f\n",s->rev.st[i].sinited4i/(double)calls);
+ printf("Simplexes inited level 4/call = %f\n",s->rev.st[i].sinited4/(double)calls);
+ printf("Simplexes invalidated level 5/call = %f\n",s->rev.st[i].sinited5i/(double)calls);
+ printf("Simplexes inited level 5 (LU)/call = %f\n",s->rev.st[i].sinited5a/(double)calls);
+ printf("Simplexes inited level 5 (SVD)/call = %f\n",s->rev.st[i].sinited5b/(double)calls);
+ if ((s->rev.st[i].chits + s->rev.st[i].cmiss) == 0)
+ printf("No cache calls\n");
+ else
+ printf("Cell hit rate = %f%%\n",
+ 100.0 * s->rev.st[i].chits/(double)(s->rev.st[i].chits + s->rev.st[i].cmiss));
+ }
+ printf("\n===============================\n");
+ }
+#endif /* STATS */
+
+ /* Free up Fourth section */
+ if (s->rev.sb != NULL) {
+ free_search(s->rev.sb);
+ s->rev.sb = NULL;
+ }
+ /* Free up the Third section */
+ if (s->rev.cache != NULL) {
+ free_revcache(s->rev.cache); /* Reverse cell cache */
+ s->rev.cache = NULL;
+ }
+
+ /* Free up the Second section */
+ if (s->rev.nnrev != NULL) {
+ /* Free arrays at grid points, taking care of reference count */
+ for (rpp = s->rev.nnrev; rpp < (s->rev.nnrev + s->rev.no); rpp++) {
+ if ((rp = *rpp) != NULL && --rp[2] <= 0) {
+ DECSZ(s, rp[0] * sizeof(int));
+ free(*rpp);
+ *rpp = NULL;
+ }
+ }
+ free(s->rev.nnrev);
+ DECSZ(s, s->rev.no * sizeof(int *));
+ s->rev.nnrev = NULL;
+ }
+
+ if (di > 1 && s->rev.rev_valid) {
+ rev_struct *rsi, **rsp;
+ size_t ram_portion = g_avail_ram;
+
+ /* Remove it from the linked list */
+ for (rsp = &g_rev_instances; *rsp != NULL; rsp = &((*rsp)->next)) {
+ if (*rsp == &s->rev) {
+ *rsp = (*rsp)->next;
+ break;
+ }
+ }
+
+ /* Aportion the memory */
+ g_no_rev_cache_instances--;
+
+ if (g_no_rev_cache_instances > 0) {
+ ram_portion /= g_no_rev_cache_instances;
+ for (rsi = g_rev_instances; rsi != NULL; rsi = rsi->next)
+ rsi->max_sz = ram_portion;
+ if (s->verbose)
+ fprintf(stdout, "%cThere %s %d rev cache instance%s with %lu Mbytes limit\n",
+ cr_char,
+ g_no_rev_cache_instances > 1 ? "are" : "is",
+ g_no_rev_cache_instances,
+ g_no_rev_cache_instances > 1 ? "s" : "",
+ ram_portion/1000000);
+ }
+ }
+
+ s->rev.rev_valid = 0;
+
+ if (s->rev.rev != NULL) {
+ /* Free arrays at grid points, taking care of reference count */
+ for (rpp = s->rev.rev; rpp < (s->rev.rev + s->rev.no); rpp++) {
+ if ((rp = *rpp) != NULL && --rp[2] <= 0) {
+ DECSZ(s, rp[0] * sizeof(int));
+ free(*rpp);
+ *rpp = NULL;
+ }
+ }
+ free(s->rev.rev);
+ DECSZ(s, s->rev.no * sizeof(int *));
+ s->rev.rev = NULL;
+ }
+
+ /* If first section has been initialised */
+ if (s->rev.inited != 0) {
+
+ /* Sub-simplex information */
+ for (e = 0; e <= di; e++) {
+ rspl_free_ssimplex_info(s, &s->rev.sspxi[e]);
+ }
+ s->rev.res = 0;
+ s->rev.no = 0;
+ s->rev.inited = 0;
+ }
+ DBG(("rev allocation left after free = %d bytes\n",s->rev.sz));
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef NEVER /* Test code */
+/* Reverse closest find using exaustive pseudo hilbert search */
+static void debug_find_closest_rev(
+rspl *s,
+double *out,
+double *in
+) {
+ double best = 1e38;
+ int e, f;
+ rpsh counter; /* Pseudo-hilbert counter */
+ int gc[MXDI]; /* Grid index value */
+ double iv[MXDI];
+ float *gp; /* Pointer to grid data */
+
+ rpsh_init(&counter, s->di, (unsigned int *)s->g.res, gc); /* Initialise counter */
+ for (;;) {
+ double dist;
+
+ /* Compute grid pointer and input sample values */
+ gp = s->g.a; /* Base of grid data */
+ for (e = 0; e < s->di; e++) { /* Input tables */
+ gp += s->g.fci[e] * gc[e]; /* Grid value pointer */
+ iv[e] = s->g.l[e] + gc[e] * s->g.w[e]; /* Input sample values */
+ }
+
+ dist = 0.0;
+ for (f = 0; f < s->fdi; f++) {
+ double tt = in[f] - (double)gp[f];
+ dist += tt * tt;
+ }
+ if (dist < best) {
+ best = dist;
+ for (e = 0; e < s->di; e++)
+ out[e] = iv[e];
+ }
+
+ /* Increment counter */
+ if (rpsh_inc(&counter, gc))
+ break;
+ }
+}
+#endif /* NEVER */
+
+/* ========================================================== */
+/* reverse lookup acceleration structure initialisation code */
+
+/* The reverse lookup relies on a search of the fwd interpolation tables. */
+/* To eliminate out of gamut points quickly, to provide a starting point for */
+/* the search, and to guarantee that all possible reverse solutions are discovered, */
+/* a spatial indexing structure is used to provide a list of starting candidate */
+/* forward indexes for a given output value. (rev.rev[]) */
+/* The reverse structure contains an fdi dimensional cell grid, each element of the */
+/* cell grid holding the indexes of the forward interpolation grid, which intersect */
+/* that ranges of output values. A reverse cell will be empty if there is no */
+/* potential exact solution. */
+/* Note that unlike the forward grid which is composed of verticies, */
+/* this grid is composed of cells (there is an extra row allocated */
+/* during construction using verticies, that are not used when converted. */
+/* to cells) */
+/* For accelleration of the nearest lookup, a parallel reverse grid is */
+/* constructed that holds lists of forward grid cells that may hold the */
+/* nearest point within the gamut. These lists may be empty if we are within */
+/* gamut - ie. the rev.nnrev[] array is the complement of the rev.rev[] array. */
+/* During construction of rev.nnrev[], it is initially filled with lists for */
+/* the potential nearest cell list for each vertex (hence the extra rows allocated */
+/* for rev[] and nnrev[]), and these are then merged down to form the list */
+/* for each cell extent. The nnrev[] array is filled using a seed fill algorithm, */
+/* starting from the edges of the filled cells in rev[]. */
+/* Since many of the cells map to the same surface region, many of the fwd cell lists */
+/* are shared. */
+
+/* NOTE: that the nnrev accuracy doesn't seem as good as fill_nncell() ! */
+/* Could we fix this with better geometry calculations ??? */
+
+/* rev.nnrev[] cache entry record */
+struct _nncache{
+ int min[MXRO]; /* bwd vertex extent covered by this list */
+ int max[MXRO];
+ int *rip; /* Fwd cell list */
+ struct _nncache *next; /* Link list for this cache key */
+}; typedef struct _nncache nncache;
+
+/* Structure to hold prime seed vertex information */
+struct _primevx{
+ int ix; /* Index of prime seed */
+ int gc[MXRO]; /* coordinate of the prime seed vertex */
+ struct _primevx *next; /* Linked list for final conversion */
+ int *clist; /* Cell list generated for prime cell */
+}; typedef struct _primevx primevx;
+
+/* Structure to hold temporary nn reverse vertex propogation information */
+struct _propvx{
+ int ix; /* Index of this secondary seed */
+ int gc[MXRO]; /* coordinate of this secondary seed */
+ int cix; /* Index of the closest surface nnrev vertex */
+ double dsq; /* Distance to the closest point squared */
+ int pass; /* Propogation pass */
+ struct _propvx *next; /* Linked list for next seeds */
+}; typedef struct _propvx propvx;
+
+/* Initialise the rev Second section acceleration information. */
+/* This is called when it is discovered on a call that s->rev.rev_valid == 0 */
+static void init_revaccell(
+rspl *s
+) {
+ int i, j; /* Index of fwd grid point */
+ int e, f, ee, ff;
+ int di = s->di;
+ int fdi = s->fdi;
+ int gno = s->g.no;
+ int rgno = s->rev.no;
+ int argres = s->rev.ares; /* Allocation rgres, = no bwd cells +1 */
+ int rgres = s->rev.res; /* no bwd cells */
+ int rgres_1 = rgres-1; /* rgres -1 == maximum base coord value */
+
+ schbase *b = s->rev.sb; /* Base search information */
+ char *vflag = NULL; /* Per vertex flag used during construction of nnrev */
+ float *gp; /* Pointer to fwd grid points */
+ primevx *plist = NULL, *ptail = NULL; /* Prime seed list for last pass */
+ propvx *alist = NULL; /* Linked list of active secondary seeds */
+ propvx *nlist = NULL; /* Linked list of next secondary seeds */
+ DCOUNT(gg, MXRO, fdi, 0, 0, argres);/* Track the prime seed coordinate */
+ DCOUNT(cc, MXRO, fdi, -1, -1, 2); /* Neighborhood offset counter */
+ int nn[MXRO]; /* Neighbor coordinate */
+ int pass = 0; /* Propogation pass */
+ int nncsize; /* Size of the rev.nnrev construction cache index */
+ nncache **nnc; /* nn cache index, used during construction of nnrev */
+ unsigned hashk; /* Hash key */
+ nncache *ncp; /* Hash entry pointer */
+ int nskcells = 0; /* Number of skiped cells (debug) */
+#ifdef DEBUG
+ int cellinrevlist = 0;
+ int fwdcells = 0;
+#endif
+
+ DBG(("init_revaccell called, di = %d, fdi = %d, mgres = %d\n",di,fdi,(int)s->g.mres));
+
+ if (!s->rev.fastsetup) {
+ /* Temporary per bwd vertex/cell flag */
+ if ((vflag = (char *) calloc(rgno, sizeof(char))) == NULL)
+ error("rspl malloc failed - rev.vflag points");
+ INCSZ(s, rgno * sizeof(char));
+ }
+
+ /*
+ * The rev[] and nnrev[] grids contain pointers to lists of grid cube base indexes.
+ * If the pointer is NULL, then there are no base indexes in that list.
+ * A non NULL list uses element [0] to indicate the alocation size of the list,
+ * [1] contains the index of the next free location, [2] contains the reference
+ * count (lists may be shared), the list starts at [3]. The last entry is marked with -1.
+ */
+
+ /* We won't include any fwd cells that are over the ink limit, */
+ /* so makes sure that the fwd cell nodes all have an ink limit value. */
+ if (b != NULL && s->limiten) {
+ ECOUNT(gc, MXDIDO, s->di, 0, s->g.res, 0); /* coordinates */
+ double iv[MXDI]; /* Input value corresponding to grid */
+
+ DBG(("Looking up fwd vertex ink limit values\n"));
+ /* Calling the limit function for each fwd vertex could be bad */
+ /* if the limit function is slow. Maybe an octree type algorithm */
+ /* could be used if this is a problem ? */
+ EC_INIT(gc);
+ for (i = 0, gp = s->g.a; i < s->g.no; i++, gp += s->g.pss) {
+ if (gp[-1] == L_UNINIT) {
+ for (e = 0; e < di; e++)
+ iv[e] = s->g.l[e] + gc[e] * s->g.w[e]; /* Input sample values */
+ gp[-1] = (float)(INKSCALE * s->limitf(s->lcntx, iv));
+ }
+ EC_INC(gc);
+ }
+ s->g.limitv_cached = 1;
+ }
+
+ /* We then fill in the in-gamut reverse grid lookups, */
+ /* and identify nnrev prime seed verticies */
+
+ DBG(("filling in rev.rev[] grid\n"));
+
+ /* To create rev.rev[], for all fwd grid points, form the cube with that */
+ /* point at its base, and determine the bounding box of the output values */
+ /* that could intersect that cube. */
+ /* As a start for creating rev.nnrevp[], flag which bwd verticies are */
+ /* covered by the fwd grid output range. */
+ for (gp = s->g.a, i = 0; i < gno; gp += s->g.pss, i++) {
+ datao min, max;
+ int imin[MXRO], imax[MXRO], gc[MXRO];
+ int uil; /* One is under the ink limit */
+
+//printf("~1 i = %d/%d\n",i,gno);
+ /* Skip grid points on the upper edge of the grid, since there */
+ /* is no further grid point to form a cube range with. */
+ for (e = 0; e < di; e++) {
+ if(G_FL(gp, e) == 0) /* At the top edge */
+ break;
+ }
+ if (e < di) { /* Top edge - skip this cube */
+ continue;
+ }
+
+ /* Find the output value bounding box values for this grid cell */
+ uil = 0;
+ for (f = 0; f < fdi; f++) /* Init output min/max */
+ min[f] = max[f] = gp[f];
+ if (b == NULL || !s->limiten || gp[-1] <= s->limitv)
+ uil = 1;
+
+ /* For all other grid points in the cube */
+ for (ee = 1; ee < (1 << di); ee++) {
+ float *gt = gp + s->g.fhi[ee]; /* Pointer to cube vertex */
+
+ if (b == NULL || !s->limiten || gt[-1] <= s->limitv)
+ uil = 1;
+
+ /* Update bounding box for this grid point */
+ for (f = 0; f < fdi; f++) {
+ if (min[f] > gt[f])
+ min[f] = gt[f];
+ if (max[f] < gt[f])
+ max[f] = gt[f];
+ }
+ }
+
+ /* Skip any fwd cells that are over the ink limit */
+ if (!uil) {
+ nskcells++;
+ continue;
+ }
+
+ /* Figure out intersection range in reverse grid */
+ for (f = 0; f < fdi; f++) {
+ double t;
+ int mi;
+ double gw = s->rev.gw[f];
+ double gl = s->rev.gl[f];
+ t = (min[f] - gl)/gw;
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi > rgres_1)
+ mi = rgres_1;
+ imin[f] = mi;
+ t = (max[f] - gl)/gw;
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi > rgres_1)
+ mi = rgres_1;
+ imax[f] = mi;
+ }
+
+//printf("Scanning over grid:\n");
+//for (f = 0; f < fdi; f++)
+//printf("Min[%d] = %d -> Max[%d] = %d\n",f,imin[f],f,imax[f]);
+
+ /* Now create forward index and vector with all the reverse grid cells */
+ for (f = 0; f < fdi; f++)
+ gc[f] = imin[f]; /* init coords */
+
+ for (f = 0; f < fdi;) { /* For all of intersect cube */
+ int **rpp, *rp;
+
+ /* Compute pointer to grid cell */
+ for (rpp = s->rev.rev, f = 0; f < fdi; f++)
+ rpp += gc[f] * s->rev.coi[f];
+ rp = *rpp;
+
+//printf("Currently at grid:\n");
+//for (f = 0; f < fdi; f++)
+//printf("gc[%d] = %d\n",f,gc[f]);
+
+ if (rp == NULL) {
+ if ((rp = (int *) rev_malloc(s, 6 * sizeof(int))) == NULL)
+ error("rspl malloc failed - rev.grid entry");
+ INCSZ(s, 6 * sizeof(int));
+ *rpp = rp;
+ rp[0] = 6; /* Allocation */
+ rp[1] = 4; /* Next free Cell */
+ rp[2] = 1; /* Reference count */
+ rp[3] = i;
+ rp[4] = -1; /* End marker */
+ } else {
+ int z = rp[1], ll = rp[0];
+ if (z >= (ll-1)) { /* Not enough space */
+ INCSZ(s, ll * sizeof(int));
+ ll *= 2;
+ if ((rp = (int *) rev_realloc(s, rp, sizeof(int) * ll)) == NULL)
+ error("rspl realloc failed - rev.grid entry");
+ *rpp = rp;
+ rp[0] = ll;
+ }
+ rp[z++] = i;
+ rp[z] = -1;
+ rp[1] = z;
+ }
+ /* Increment index */
+ for (f = 0; f < fdi; f++) {
+ gc[f]++;
+ if (gc[f] <= imax[f])
+ break; /* No carry */
+ gc[f] = imin[f];
+ }
+ } /* Next reverse grid point in intersecting cube */
+
+ if (s->rev.fastsetup)
+ continue; /* Skip nnrev setup */
+
+
+ /* Now also register which grid points are in-gamut and are part of cells */
+ /* than have a rev.rev[] list. */
+
+ /* Figure out intersection range in reverse nn (construction) vertex grid */
+ /* This range may be empty if a grid isn't stradled by the fwd cell output */
+ /* range. */
+ for (f = 0; f < fdi; f++) {
+ double t;
+ int mi;
+ double gw = s->rev.gw[f];
+ double gl = s->rev.gl[f];
+ t = (min[f] - gl)/gw;
+ mi = (int)ceil(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= argres)
+ mi = rgres;
+ imin[f] = mi;
+ t = (max[f] - gl)/gw;
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= argres)
+ mi = rgres;
+ imax[f] = mi;
+ if (imax[f] < imin[f])
+ break; /* Doesn't straddle any verticies */
+ }
+
+ if (f >= fdi) { /* There are seed verticies to mark */
+
+//printf("~1 marking prime seed vertex %d\n",i);
+
+ /* Mark an initial seed point nnrev vertex, and */
+ /* create a surface point propogation record for it */
+ for (f = 0; f < fdi; f++)
+ gc[f] = imin[f]; /* init coords */
+
+ for (f = 0; f < fdi;) { /* For all of intersect cube */
+ int **rpp, *rp;
+ char *fpp;
+
+ /* Compute pointer to grid cell */
+ for (rpp = s->rev.nnrev, fpp = vflag, f = 0; f < fdi; f++) {
+ int inc = gc[f] * s->rev.coi[f];
+ rpp += inc;
+ fpp += inc;
+ }
+ rp = *rpp;
+
+ *fpp = 3; /* Initial seed point */
+
+ /* Increment index */
+ for (f = 0; f < fdi; f++) {
+ gc[f]++;
+ if (gc[f] <= imax[f])
+ break; /* No carry */
+ gc[f] = imin[f];
+ }
+ }
+ }
+ } /* Next base grid point */
+
+ DBG(("We skipped %d cells that were over the limit\n",nskcells));
+
+ /* Setup the nnrev array if we are not doing a fast setup. */
+ /* (fastsetup will instead fill the nnrev array on demand, */
+ /* using an exaustive search.) */
+ if (!s->rev.fastsetup) {
+
+ /* The next step is to use all the prime seed grid points to set and propogate */
+ /* the index of the closest fwd vertex through the revnn[] array. */
+ /* (This doesn't work perfectly. Sometimes a vertex is not linked to it's closest */
+ /* prime. I'm not sure if this is due to a bug here, or is a quirk of geometry */
+ /* that a prime that is closest to a vertex isn't closest for any of its neighbors.) */
+ DBG(("filling in rev.nnrev[] grid\n"));
+
+ /* For all the primary seed points */
+ DC_INIT(gg);
+ for (i = 0; i < rgno; i++) {
+ int **rpp;
+ primevx *prime= NULL; /* prime cell information structure */
+
+ if (vflag[i] != 3) { /* Not a prime seed point */
+ goto next_seed_point;
+ }
+
+ rpp = s->rev.nnrev + i;
+
+//printf("~1 potential rev.nnrev[] prime seed %d, about to scan neibors\n",i);
+ /* For all the neigbors of this seed */
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ propvx *prop; /* neighor cell propogation structure */
+ int nix = 0; /* Neighbor cell index */
+ char *fpp = vflag;
+ int **nrpp = s->rev.nnrev;
+ double dsq;
+
+ for (f = 0; f < fdi; f++) {
+ nn[f] = gg[f] + cc[f];
+ if (nn[f] < 0 || nn[f] >= argres)
+ break; /* Out of bounds */
+ nix += nn[f] * s->rev.coi[f];
+ }
+ fpp = vflag + nix;
+
+ /* If neighbor out of bounds, or is a prime seed point, skip it */
+ if (f < fdi || *fpp == 3) {
+ goto next_neighbor;
+ }
+
+//printf("~1 identified prime seed %d with neighbor %d\n",i,nix);
+ /* We now know that this prime seed will propogate, */
+ /* so get/create the temporary information record for it */
+ if (prime == NULL) {
+
+ /* If this prime seed hasn't be setup before */
+ if (*rpp != NULL) {
+ prime = *((primevx **)rpp);
+ } else {
+ /* Allocate a primevx if there isn't one */
+ if ((prime = (primevx *) calloc(1, sizeof(primevx))) == NULL)
+ error("rspl malloc failed - rev.nnrev prime info structs");
+ *((primevx **)rpp) = prime;
+ prime->ix = i;
+ for (f = 0; f < fdi; f++)
+ prime->gc[f] = gg[f];
+//if (fdi > 1) printf("~1 setting prime %d, gc = %d, %d, %d\n", i, prime->gc[0], prime->gc[1], prime->gc[2]);
+ }
+ }
+
+ /* Pointer to nnrev vertex neighbor point */
+ nrpp = s->rev.nnrev + nix;
+
+ /* Compute the distance squared from this prime seed to this neighbor */
+ for (dsq = 0.0, f = 0; f < fdi; f++) {
+ double tt = (gg[f] - nn[f]) * s->rev.gw[f];
+ dsq += tt * tt;
+ }
+
+ /* Get or allocate a prop structure for it */
+ if (*nrpp != NULL) {
+ prop = *((propvx **)nrpp);
+ if ((dsq + 1e-6) < prop->dsq) { /* This prime is closer than previous */
+ prop->cix = i; /* The index of the closest prime */
+ prop->dsq = dsq; /* Distance squared to closest prime */
+ }
+ } else {
+ if ((prop = (propvx *) calloc(1, sizeof(propvx))) == NULL)
+ error("rspl malloc failed - rev.nnrev propogation structs");
+ *((propvx **)nrpp) = prop;
+ prop->ix = nix;
+ for (f = 0; f < fdi; f++)
+ prop->gc[f] = nn[f]; /* This neighbors coord */
+ prop->cix = i;
+ prop->dsq = dsq;
+ prop->pass = pass;
+ prop->next = nlist; /* Add new seed to list of next seeds */
+ nlist = prop;
+ *fpp = 1;
+
+ }
+ next_neighbor:;
+ DC_INC(cc);
+ }
+
+ next_seed_point:;
+ DC_INC(gg);
+ }
+
+//printf("~1 about to propogate secondary seeds\n");
+ /* Now we propogate the secondary seed points until there are no more left */
+ while(nlist != NULL) {
+ propvx *next;
+ propvx *tlp;
+
+ if ((pass += 2) < 0)
+ error("Assert rev: excessive propogation passes");
+//printf("~1 about to do a round of propogation pass %d\n",(pass+2)/2);
+
+ /* Mark all seed points on the current list with pass-1 */
+ for (tlp = nlist; tlp != NULL; tlp = tlp->next) {
+ *(vflag + tlp->ix) = 2;
+ tlp->pass = pass-1;
+ }
+
+ /* Go through each secondary seed in the active list, propogating them */
+ for (alist = nlist, nlist = NULL; alist != NULL; alist = next) {
+ int **rpp;
+ primevx *prime= NULL; /* prime cell information structure */
+
+ next = alist->next; /* Next unless we re-insert one */
+
+ /* Grab this seed points coodinate and index */
+ for (i = f = 0; f < fdi; f++) {
+ gg[f] = alist->gc[f];
+ i += gg[f] * s->rev.coi[f];
+ }
+
+//printf("\n~1 propogating from seed %d\n",i);
+ /* rpp = s->rev.nnrev + i; */
+
+ /* Grab the corresponding prime seed information record */
+ prime = *((primevx **)(s->rev.nnrev + alist->cix));
+
+ /* For all the neigbors of this seed */
+ DC_INIT(cc);
+ while (!DC_DONE(cc)) {
+ propvx *prop; /* neighor cell propogation structure */
+ int nix; /* Neighbor cell index */
+ char *fpp = vflag;
+ int **nrpp = s->rev.nnrev;
+ double dsq;
+
+ for (nix = f = 0; f < fdi; f++) {
+ nn[f] = gg[f] + cc[f];
+ if (nn[f] < 0 || nn[f] >= argres)
+ break; /* Out of bounds */
+ nix += nn[f] * s->rev.coi[f];
+ }
+ fpp = vflag + nix;
+//printf("~1 neighbor ix %d, flag %d\n",nix,*fpp);
+
+ /* If neighbor out of bounds, current vertex or prime, skip it */
+ if (f < fdi || i == nix || *fpp >= 3) {
+//printf("~1 skipping neighbour %d\n",nix);
+ goto next_neighbor2;
+ }
+
+ /* Pointer to nnrev vertex neighbor point */
+ nrpp = s->rev.nnrev + nix;
+
+ /* Compute the distance squared from the prime seed to this neighbor */
+ for (dsq = 0.0, f = 0; f < fdi; f++) {
+ double tt = (prime->gc[f] - nn[f]) * s->rev.gw[f];
+ dsq += tt * tt;
+ }
+
+ /* Get or allocate a prop structure for it */
+ if (*nrpp != NULL) {
+ prop = *((propvx **)nrpp);
+//if (prop->ix != nix) error ("Assert: prop index %d doesn't match index %d",prop->ix, nix);
+
+ if ((dsq + 1e-6) < prop->dsq) { /* This prime is closer than previous */
+//printf("~1 updating %d to prime %d, dsq = %f from %f\n",nix, prime->ix, dsq, prop->dsq);
+ prop->cix = prime->ix; /* The index of the new closest prime */
+ prop->dsq = dsq; /* Distance squared to closest prime */
+ /* If this is a vertex from previous pass that has changed, */
+ /* and it's not ahead of us in the current list, */
+ /* put it next on the current list. */
+ if (*fpp == 2 && prop->pass != (pass-1)) {
+//printf("~1 re-shedule %d (%d) for next propogate\n",nix,prop->ix);
+//if (next == NULL)
+//printf("Before insert, next = NULL\n");
+//else
+//printf("Before insert, next = %d\n",next->ix);
+ prop->pass = pass-1; /* Re-shedule once only */
+ prop->next = next;
+ next = prop;
+ }
+ }
+ } else {
+ if ((prop = (propvx *) calloc(1, sizeof(propvx))) == NULL)
+ error("rspl malloc failed - rev.nnrev propogation structs");
+ *((propvx **)nrpp) = prop;
+ prop->ix = nix;
+ for (f = 0; f < fdi; f++)
+ prop->gc[f] = nn[f]; /* This neighbors coord */
+ prop->cix = prime->ix;
+ prop->dsq = dsq;
+//printf("~1 propogating to new, %d, dsq = %f, prime %d\n",nix, dsq, prime->ix);
+ prop->pass = pass;
+ prop->next = nlist; /* Add new seed to list of next seeds */
+ nlist = prop;
+ *fpp = 1;
+ }
+
+ next_neighbor2:;
+ DC_INC(cc);
+ }
+ alist->pass = pass;
+ }
+ }
+
+#ifdef DEBUG
+ DBG(("checking that every vertex is now touched\n"));
+ for (i = 0; i < rgno; i++) {
+ if (vflag[i] < 2) {
+ printf("~1 problem: vertex %d flag = %d\n",i, vflag[i]);
+ }
+ if (vflag[i] == 2 && *(s->rev.nnrev + i) == NULL) {
+ printf("~1 problem: vertex %d flag = %d and struct = NULL\n",i, vflag[i]);
+ }
+ }
+#endif /* DEBUG */
+
+#ifdef NEVER /* Check that all cells are closest to their primes than any other */
+DC_INIT(gg);
+for (i = 0; i < rgno; i++) { /* For all the verticies */
+ if (vflag[i] == 2) {
+ propvx *prop = (propvx *) *(s->rev.nnrev + i);
+ for (j = 0; j < rgno; j++) { /* For all the primes */
+ if (vflag[j] == 3) {
+ primevx *prime = (primevx *) *(s->rev.nnrev + j);
+ double dsq;
+ if (prime == NULL)
+ continue;
+ for (dsq = 0.0, f = 0; f < fdi; f++) {
+ double tt = (prime->gc[f] - prop->gc[f]) * s->rev.gw[f];
+ dsq += tt * tt;
+ }
+ if ((dsq + 1e-6) < prop->dsq) {
+ warning("~1 vertex %d prime %d, dsq = %f, is closer to prime %d, dsq %f\n", i,prop->cix, prop->dsq, j, dsq);
+ /* See if any of the neighbors have the closer prime */
+ DC_INIT(cc); /* For all the neigbors of this seed */
+ while (!DC_DONE(cc)) {
+ propvx *nprop; /* neighor cell propogation structure */
+ int nix; /* Neighbor cell index */
+ char *fpp = vflag;
+ int **nrpp = s->rev.nnrev;
+ double dsq;
+
+ for (nix = f = 0; f < fdi; f++) {
+ nn[f] = gg[f] + cc[f];
+ if (nn[f] < 0 || nn[f] >= argres)
+ break; /* Out of bounds */
+ nix += nn[f] * s->rev.coi[f];
+ }
+ fpp = vflag + nix;
+//printf("~1 neighbor ix %d, flag %d\n",nix,*fpp);
+
+ /* If neighbor out of bounds, current vertex or prime, skip it */
+ if (f < fdi || i == nix || *fpp != 2) {
+//printf("~1 skipping neighbour %d\n",nix);
+ goto next_neighbor3;
+ }
+
+ /* Pointer to nnrev vertex neighbor point */
+ nrpp = s->rev.nnrev + nix;
+ if ((nprop = *((propvx **)nrpp)) != NULL) {
+//printf("~1 neighbor %d %d %d has prime %d dsq %f\n",cc[0],cc[1],cc[2],nprop->cix,nprop->dsq);
+ if (nprop->cix == j) {
+//warning("~1 but neighbor has this prime point!\n");
+
+ }
+ }
+ next_neighbor3:;
+ DC_INC(cc);
+ }
+// prop->cix = j; /* Fix it and see what happens */
+// prop->dsq = dsq;
+ }
+ }
+ }
+ }
+ DC_INC(gg);
+}
+
+#endif /* NEVER */
+
+
+ DBG(("about to do convert vertex values to cell lists\n"));
+ /* Setup a cache for the fwd cell lists created, so that we can */
+ /* avoid the list creation and memory allocation for identical lists */
+ nncsize = s->rev.ares * s->rev.ares;
+ if ((nnc = (nncache **) calloc(nncsize, sizeof(nncache *))) == NULL)
+ error("rspl malloc failed - rev.nnc cache entries");
+
+ /* Now convert the nnrev secondary vertex points to pointers to fwd cell lists */
+ /* Do this in order, so that we don't need the verticies after */
+ /* they are converted to cell lists. */
+ DC_INIT(gg);
+ for (i = 0; i < rgno; i++) {
+ int **rpp, *rp;
+ propvx *prop = NULL; /* vertex information structure */
+ primevx *prime= NULL; /* prime cell information structure */
+ int imin[MXRO], imax[MXRO]; /* Prime vertex range for each axis */
+ double rmin[MXRO], rmax[MXRO]; /* Float prime vertex value range */
+ unsigned int tcount; /* grid touch count for this opperation */
+ datao min, max; /* Fwd cell output range */
+ int lpix; /* Last prime index seen */
+
+//if (fdi > 1) printf("~1 converting vertex %d\n",i);
+//if (fdi > 1) printf("~1 coord %d %d %d\n",gg[0],gg[1],gg[2]);
+
+ rpp = s->rev.nnrev + i;
+ if (vflag[i] == 3) { /* Cell base is prime */
+ prime = (primevx *) *rpp;
+
+ if (prime != NULL) { /* It's a propogating prime */
+ /* Add prime to the end of the ptime linked list */
+ prime->next = NULL;
+ if (plist == NULL) {
+ plist = ptail = prime;
+ } else {
+ ptail->next = prime;
+ ptail = prime;
+ }
+ }
+ } else if (vflag[i] == 2) { /* Cell base is secondary */
+ prop = (propvx *)*rpp;
+ } else { /* Hmm */
+ /* This seems to happen if the space explored is not really 3D ? */
+ if (s->rev.primsecwarn == 0) {
+ warning("rev: bwd vertex %d is not prime or secondary (vflag = %d)"
+ "(Check that your measurement data is sane!)",i,vflag[i]);
+ s->rev.primsecwarn = 1;
+ }
+ fill_nncell(s, gg, i); /* Is this valid to do ?? */
+ continue;
+ }
+
+ /* Setup to scan of cube corners, and check that base is within cube grid */
+ for (f = 0; f < fdi; f++) {
+ if (gg[f] > rgres_1) { /* Vertex outside bwd cell range, */
+ if (prop != NULL && prime == NULL) {
+ free(prop);
+ *rpp = NULL;
+ }
+//printf("~1 done vertex %d because its out of cell bounds\n",i);
+ goto next_vertex;
+ }
+ imin[f] = 0x7fffffff;
+ imax[f] = -1;
+ }
+
+ /* For all the vertex points in the nnrev cube starting at this base (i), */
+ /* Check if any of them are secondary seed points */
+ for (ff = 0; ff < (1 << fdi); ff++) {
+ if (vflag[i + s->rev.hoi[ff]] == 2)
+ break;
+ }
+
+ /* If not a cell that we want to create a nearest fwd cell list for */
+ if (ff >= (1 << fdi)) {
+ /* Don't free anything, because we leave a prime in place, */
+ /* and it can't be a prop. */
+ goto next_vertex;
+ }
+
+ /* For all the vertex points in the nnrev cube starting at this base (i), */
+ /* accumulate the range they cover */
+ lpix = -1;
+ for (f = 0; f < fdi; f++) {
+ imin[f] = 0x7fffffff;
+ imax[f] = -1;
+ }
+ for (ff = 0; ff < (1 << fdi); ff++) {
+ int ii = i + s->rev.hoi[ff]; /* cube vertex index */
+ primevx *tprime= NULL;
+
+ /* Grab vertex info and corresponding prime vertex info */
+ if (vflag[ii] == 3) { /* Corner is a prime */
+ tprime = (primevx *) *(s->rev.nnrev + ii); /* Use itself */
+ if (tprime == NULL)
+ continue; /* Not a propogated in-gamut vertex */
+ } else if (vflag[ii] == 2) {
+ propvx *tprop = (propvx *) *(s->rev.nnrev + ii); /* Use propogated prime */
+ tprime = (primevx *) *(s->rev.nnrev + tprop->cix);
+ } else {
+ continue; /* Hmm */
+ }
+ if (tprime->ix == lpix)
+ continue; /* Don't waste time */
+
+//if (fdi > 1) printf("~1 corner %d, ix %d, prime %d gc = %d, %d, %d\n", ff, ii, tprime->ix, tprime->gc[0], tprime->gc[1], tprime->gc[2]);
+
+ /* Update bounding box for this prime grid point */
+ for (f = 0; f < fdi; f++) {
+ if (tprime->gc[f] < imin[f])
+ imin[f] = tprime->gc[f];
+ if (tprime->gc[f] > imax[f])
+ imax[f] = tprime->gc[f];
+ }
+ lpix = tprime->ix;
+ }
+
+//if (fdi > 1) printf("~1 prime vertex index range = %d - %d, %d - %d, %d - %d\n", imin[0], imax[0], imin[1], imax[1], imin[2], imax[2]);
+
+ /* See if a list matching this range is in the cache */
+ hashk = 0;
+ for (hashk = f = 0; f < fdi; f++)
+ hashk = hashk * 97 + imin[f] + 43 * (imax[f] - imin[f]);
+ hashk = hashk % nncsize;
+//if (fdi > 1) printf("~1 hashk = %d from %d - %d %d - %d %d - %d\n", hashk, imin[0], imax[0], imin[1], imax[1], imin[2], imax[2]);
+
+ /* See if we can locate an existing list for this range */
+ for (ncp = nnc[hashk]; ncp != NULL; ncp = ncp->next) {
+//if (fdi > 1) printf("~1 checking %d - %d %d - %d %d - %d\n", ncp->min[0], ncp->max[0], ncp->min[1], ncp->max[1], ncp->min[2], ncp->max[2]);
+ for (f = 0; f < fdi; f++) {
+ if (ncp->min[f] != imin[f]
+ || ncp->max[f] != imax[f]) {
+//if (fdi > 1) printf("~1 not a match\n");
+ break;
+ }
+ }
+ if (f >= fdi) {
+//if (fdi > 1) printf("~1 got a match\n");
+ break; /* Found a matching cache entry */
+ }
+ }
+
+ if (ncp != NULL) {
+ rp = ncp->rip;
+//if (fdi > 1) printf("~1 got cache hit hashk = %d, with ref count %d\n\n",hashk, rp[1]);
+ rp[2]++; /* Increase reference count */
+
+ } else {
+ /* This section seems to be the most time consuming part of the nnrev setup. */
+
+ /* Allocate a cache entry and place it */
+ if ((ncp = (nncache *)calloc(1, sizeof(nncache))) == NULL)
+ error("rspl malloc failed - rev.nn cach record");
+
+ for (f = 0; f < fdi; f++) {
+ ncp->min[f] = imin[f];
+ ncp->max[f] = imax[f];
+ }
+ ncp->next = nnc[hashk];
+ nnc[hashk] = ncp;
+
+ /* Convert the nn destination vertex range into an output value range. */
+ for (f = 0; f < fdi; f++) {
+ double gw = s->rev.gw[f];
+ double gl = s->rev.gl[f];
+ rmin[f] = gl + imin[f] * gw;
+ rmax[f] = gl + imax[f] * gw;
+ }
+
+ /* Do any adjustment of the range needed to acount for the inacuracies */
+ /* caused by the vertex quantization. */
+ /* (I don't really understand the need for the extra avggw expansion, */
+ /* but there are artefacts without this. This size of this sampling */
+ /* expansion has a great effect on the performance.) */
+ {
+ double avggw = 0.0;
+ for (f = 0; f < fdi; f++)
+ avggw += s->rev.gw[f];
+ avggw /= (double)fdi;
+ for (f = 0; f < fdi; f++) { /* Quantizing range plus extra */
+ double gw = s->rev.gw[f];
+ rmin[f] -= (0.5 * gw + 0.99 * avggw);
+ rmax[f] += (0.5 * gw + 0.99 * avggw);
+ }
+ }
+//if (fdi > 1) printf("~1 prime vertex value adjusted range = %f - %f, %f - %f, %f - %fn", rmin[0], rmax[0], rmin[1], rmax[1], rmin[2], rmax[2]);
+
+ /* computue the rev.rev cell grid range we will need to cover to */
+ /* get all the cell output ranges that could touch our nn reverse range */
+ for (f = 0; f < fdi; f++) {
+ double gw = s->rev.gw[f];
+ double gl = s->rev.gl[f];
+ imin[f] = (int)floor((rmin[f] - gl)/gw);
+ if (imin[f] < 0)
+ imin[f] = 0;
+ else if (imin[f] > rgres_1)
+ imin[f] = rgres_1;
+ imax[f] = (int)floor((rmax[f] - gl)/gw);
+ if (imax[f] < 0)
+ imax[f] = 0;
+ else if (imax[f] > rgres_1)
+ imax[f] = rgres_1;
+ cc[f] = imin[f]; /* Set grid starting value */
+ }
+ tcount = s->get_next_touch(s); /* Get next grid touched generation count */
+
+//if (fdi > 1) printf("~1 Cells to scan = %d - %d, %d - %d, %d - %d\n", imin[0], imax[0], imin[1], imax[1], imin[2], imax[2]);
+
+ rp = NULL; /* We always allocate a new list initially */
+ for (f = 0; f < fdi;) { /* For all the cells in the min/max range */
+ int ii;
+ int **nrpp, *nrp; /* Pointer to base of cell list, entry 0 = allocated space */
+
+ /* Get pointer to rev.rev[] cell list */
+ for (nrpp = s->rev.rev, f = 0; f < fdi; f++)
+ nrpp += cc[f] * s->rev.coi[f];
+
+ if ((nrp = *nrpp) == NULL)
+ goto next_range_list; /* This rev.rev[] cell is empty */
+
+
+//if (fdi > 1) printf("~1 adding list from cell %d, list length %d\n",nrpp - s->rev.rev, nrp[0]);
+ /* For all the fwd cells in the rev.rev[] list */
+ for(nrp += 3; *nrp != -1; nrp++) {
+ int ix = *nrp; /* Fwd cell index */
+ float *fcb = s->g.a + ix * s->g.pss; /* Pntr to base float of fwd cell */
+
+ if (TOUCHF(fcb) >= tcount) { /* If we seen visited this fwd cell before */
+//if (fdi > 1) printf("~1 skipping cell %d because we alread have it\n",ix);
+ continue;
+ }
+ TOUCHF(fcb) = tcount; /* Touch it so we will skip it next time */
+
+ /* Compute the range of output values this cell covers */
+ for (f = 0; f < fdi; f++) /* Init output min/max */
+ min[f] = max[f] = fcb[f];
+
+ /* For all other grid points in the fwd cell cube */
+ for (ee = 1; ee < (1 << di); ee++) {
+ float *gt = fcb + s->g.fhi[ee]; /* Pointer to cube vertex */
+
+ /* Update bounding box for this grid point */
+ for (f = 0; f < fdi; f++) {
+ if (min[f] > gt[f])
+ min[f] = gt[f];
+ if (max[f] < gt[f])
+ max[f] = gt[f];
+ }
+ }
+
+//if (fdi > 1) printf("~1 cell %d range = %f - %f, %f - %f, %f - %f\n", ix, min[0], max[0], min[1], max[1], min[2], max[2]);
+
+ /* See if this fwd cell output values overlaps our region of interest */
+ for (f = 0; f < fdi; f++) {
+ if (min[f] > rmax[f]
+ || max[f] < rmin[f]) {
+ break; /* Doesn't overlap */
+ }
+ }
+
+ if (f < fdi) {
+//if (fdi > 1) printf("~1 skipping cell %d because we doesn't overlap\n",ix);
+ continue; /* It doesn't overlap */
+ }
+
+//if (fdi > 1) printf("~1 adding fwd index %d to list\n",ix);
+//if (fdi > 1) printf("~1 cell %d range = %f - %f, %f - %f, %f - %f\n", ix, min[0], max[0], min[1], max[1], min[2], max[2]);
+#ifdef DEBUG
+ fwdcells++;
+#endif
+ /* It does, add it to our new list */
+ if (rp == NULL) {
+ if ((rp = (int *) rev_malloc(s, 6 * sizeof(int))) == NULL)
+ error("rspl malloc failed - rev.nngrid entry");
+ INCSZ(s, 6 * sizeof(int));
+ rp[0] = 6; /* Allocation */
+ rp[1] = 4; /* Next free Cell */
+ rp[2] = 1; /* reference count */
+ rp[3] = ix;
+ rp[4] = -1;
+ } else {
+ int z = rp[1], ll = rp[0];
+ if (z >= (ll-1)) { /* Not enough space */
+ INCSZ(s, ll * sizeof(int));
+ ll *= 2;
+ if ((rp = (int *) rev_realloc(s, rp, sizeof(int) * ll)) == NULL)
+ error("rspl realloc failed - rev.grid entry");
+ rp[0] = ll;
+ }
+ rp[z++] = ix;
+ rp[z] = -1;
+ rp[1] = z;
+ }
+ } /* Next fwd cell in list */
+
+ /* Increment index */
+ next_range_list:;
+ for (f = 0; f < fdi; f++) {
+ if (++cc[f] <= imax[f])
+ break; /* No carry */
+ cc[f] = imin[f];
+ }
+ }
+
+ ncp->rip = rp; /* record nnrev cell in cache */
+#ifdef DEBUG
+ cellinrevlist++;
+#endif
+//if (fdi > 1) printf("~1 adding cache entry with hashk = %d\n\n",hashk);
+ }
+
+ /* Put the resulting list in place */
+ if (prime != NULL)
+ prime->clist = rp; /* Save it untill we get rid of the primes */
+ else
+ *rpp = rp;
+
+//if (*rpp == NULL) printf("~1 problem: we ended up with no list or prime struct at cell %d\n",i);
+
+#ifdef NEVER
+/* Sanity check the list, to see if the list cells corner contain an output value */
+/* that is at least closer to the target than the prime. */
+if (prop != NULL) {
+ int *tp = rp;
+ double bdist = 1e60;
+ double bdist2 = 1e60;
+ double vx[MXRO]; /* Vertex location */
+ double px[MXRO]; /* Prime location */
+ double cl[MXRO]; /* Closest output value from list */
+ double acl[MXRO]; /* Absolute closest output value */
+ double dst; /* Distance to prime */
+ int ti;
+
+ primevx *prm = (primevx *) *(s->rev.nnrev + prop->cix);
+ for (f = 0; f < fdi; f++) {
+ double gw = s->rev.gw[f];
+ double gl = s->rev.gl[f];
+ vx[f] = gl + prop->gc[f] * gw;
+ px[f] = gl + prm->gc[f] * gw;
+ }
+
+ for(tp++; *tp != -1; tp++) {
+ int ix = *tp; /* Fwd cell index */
+ float *fcb = s->g.a + ix * s->g.pss; /* Pntr to base float of fwd cell */
+
+ for (ee = 0; ee < (1 << di); ee++) {
+ double ss;
+ float *gt = fcb + s->g.fhi[ee]; /* Pointer to cube vertex */
+
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = vx[f] - gt[f];
+ ss += tt * tt;
+ }
+ if (ss < bdist) {
+ bdist = ss;
+ for (f = 0; f < fdi; f++)
+ cl[f] = gt[f];
+ }
+ }
+ }
+ bdist = sqrt(bdist);
+ dst = sqrt(prop->dsq);
+
+ /* Lookup best distance to any output value */
+ if (dst < bdist) {
+ float *gt;
+ for (ti = 0, gt = s->g.a; ti < s->g.no; ti++, gt += s->g.pss) {
+ double ss;
+
+ for (ss = 0.0, f = 0; f < fdi; f++) {
+ double tt = vx[f] - gt[f];
+ ss += tt * tt;
+ }
+ if (ss < bdist2) {
+ bdist2 = ss;
+ for (f = 0; f < fdi; f++)
+ acl[f] = gt[f];
+ }
+ }
+ }
+ bdist2 = sqrt(bdist2);
+
+ if (dst < bdist) {
+ printf("~1 vertex %d has worse distance to values than prime\n",i);
+ printf("~1 vertex loc %f %f %f\n", vx[0], vx[1], vx[2]);
+ printf("~1 prime loc %f %f %f, dist %f\n", px[0], px[1], px[2],dst);
+ printf("~1 closest loc %f %f %f, dist %f\n", cl[0], cl[1], cl[2],bdist);
+ printf("~1 abs clst loc %f %f %f, dist %f\n", acl[0], acl[1], acl[2], bdist2);
+ }
+}
+#endif // NEVER
+
+ if (prop != NULL && prime == NULL) {
+ free(prop);
+ }
+
+ next_vertex:;
+ DC_INC(gg);
+ }
+
+ DBG(("freeing up the prime seed structurs\n"));
+ /* Finaly convert all the prime verticies to cell lists */
+ /* Free up all the prime seed structures */
+ for (;plist != NULL; ) {
+ primevx *prime, *next = plist->next;
+ int **rpp;
+
+ rpp = s->rev.nnrev + plist->ix;
+ if ((prime = (primevx *)(*rpp)) != NULL) {
+ if (prime->clist != NULL) /* There is a nn list for this cell */
+ *rpp = prime->clist;
+ else
+ *rpp = NULL;
+ free(prime);
+ } else {
+ error("assert, prime cell %d was empty",plist->ix);
+ }
+ plist = next;
+ }
+
+#ifdef DEBUG
+ DBG(("sanity check that all rev accell cells are filled\n"));
+ DC_INIT(gg);
+ for (i = 0; i < rgno; i++) {
+ for (f = 0; f < fdi; f++) {
+ if (gg[f] > rgres_1) { /* Vertex outside bwd cell range, */
+ goto next_vertex3;
+ }
+ }
+
+ if (*(s->rev.nnrev + i) == NULL
+ && *(s->rev.rev + i) == NULL) {
+// printf("~1 warning, cell %d [ %d %d %d] has a NULL list\n",i, gg[0],gg[1],gg[2]);
+ error("cell %d has a NULL list\n",i);
+ }
+ next_vertex3:;
+ DC_INC(gg);
+ }
+#endif /* DEBUG */
+
+ /* Free up flag array used for construction */
+ if (vflag != NULL) {
+ DECSZ(s, rgno * sizeof(char));
+ free(vflag);
+ }
+
+ /* Free up nn list cache indexing structure used in construction */
+ if (nnc != 0) {
+ for (i = 0; i < nncsize; i++) {
+ nncache *nncp;
+ /* Run through linked list freeing entries */
+ for (ncp = nnc[i]; ncp != NULL; ncp = nncp) {
+ nncp = ncp->next;
+ free(ncp);
+ }
+ }
+ free(nnc);
+ nnc = NULL;
+ }
+ }
+
+ if (s->rev.rev_valid == 0 && di > 1) {
+ rev_struct *rsi;
+ size_t ram_portion = g_avail_ram;
+
+ /* Add into linked list */
+ s->rev.next = g_rev_instances;
+ g_rev_instances = &s->rev;
+
+ /* Aportion the memory, and reduce cache if it is over new limit. */
+ g_no_rev_cache_instances++;
+ ram_portion /= g_no_rev_cache_instances;
+ for (rsi = g_rev_instances; rsi != NULL; rsi = rsi->next) {
+ revcache *rc = rsi->cache;
+
+ rsi->max_sz = ram_portion;
+ while (rc->nunlocked > 0 && rsi->sz > rsi->max_sz) {
+ if (decrease_revcache(rc) == 0)
+ break;
+ }
+//printf("~1 rev instance ram = %d MB\n",rsi->sz/1000000);
+ }
+
+ if (s->verbose)
+ fprintf(stdout, "%cThere %s %d rev cache instance%s with %lu Mbytes limit\n",
+ cr_char,
+ g_no_rev_cache_instances > 1 ? "are" : "is",
+ g_no_rev_cache_instances,
+ g_no_rev_cache_instances > 1 ? "s" : "",
+ ram_portion/1000000);
+ }
+ s->rev.rev_valid = 1;
+
+#ifdef DEBUG
+ if (fdi > 1) printf("%d cells in rev nn list\n",cellinrevlist);
+ if (fdi > 1) printf("%d fwd cells in rev nn list\n",fwdcells);
+ if (cellinrevlist > 1) printf("Avg list size = %f\n",(double)fwdcells/cellinrevlist);
+#endif
+
+ DBG(("init_revaccell finished\n"));
+}
+
+/* Invalidate the reverse acceleration structures (section Two) */
+static void invalidate_revaccell(
+rspl *s /* Pointer to rspl grid */
+) {
+ int e, di = s->di;
+ int **rpp, *rp;
+
+ /* Invalidate the whole rev cache (Third section) */
+ invalidate_revcache(s->rev.cache);
+
+ /* Free up the contents of rev.rev[] and rev.nnrev[] */
+ if (s->rev.rev != NULL) {
+ for (rpp = s->rev.rev; rpp < (s->rev.rev + s->rev.no); rpp++) {
+ if ((rp = *rpp) != NULL && --rp[2] <= 0) {
+ DECSZ(s, rp[0] * sizeof(int));
+ free(*rpp);
+ *rpp = NULL;
+ }
+ }
+ }
+ if (s->rev.nnrev != NULL) {
+ for (rpp = s->rev.nnrev; rpp < (s->rev.nnrev + s->rev.no); rpp++) {
+ if ((rp = *rpp) != NULL && --rp[2] <= 0) {
+ DECSZ(s, rp[0] * sizeof(int));
+ free(*rpp);
+ *rpp = NULL;
+ }
+ }
+ }
+
+ if (di > 1 && s->rev.rev_valid) {
+ rev_struct *rsi, **rsp;
+ size_t ram_portion = g_avail_ram;
+
+ /* Remove it from the linked list */
+ for (rsp = &g_rev_instances; *rsp != NULL; rsp = &((*rsp)->next)) {
+ if (*rsp == &s->rev) {
+ *rsp = (*rsp)->next;
+ break;
+ }
+ }
+
+ /* Aportion the memory */
+ g_no_rev_cache_instances--;
+
+ if (g_no_rev_cache_instances > 0) {
+ ram_portion /= g_no_rev_cache_instances;
+ for (rsi = g_rev_instances; rsi != NULL; rsi = rsi->next)
+ rsi->max_sz = ram_portion;
+ if (s->verbose)
+ fprintf(stdout, "%cThere %s %d rev cache instance%s with %lu Mbytes limit\n",
+ cr_char,
+ g_no_rev_cache_instances > 1 ? "are" : "is",
+ g_no_rev_cache_instances,
+ g_no_rev_cache_instances > 1 ? "s" : "",
+ ram_portion/1000000);
+ }
+ }
+ s->rev.rev_valid = 0;
+}
+
+/* ====================================================== */
+
+/* Initialise the rev First section, basic information that doesn't change */
+/* This is called on initial setup when s->rev.inited == 0 */
+static void make_rev_one(
+rspl *s
+) {
+ int i, j; /* Index of fwd grid point */
+ int e, f, ee, ff;
+ int di = s->di;
+ int fdi = s->fdi;
+ int rgno, gno = s->g.no;
+ int argres; /* Allocation rgres, = no cells +1 */
+ int rgres;
+ int rgres_1; /* rgres -1 == maximum base coord value */
+ datao rgmin, rgmax;
+
+ DBG(("make_rev_one called, di = %d, fdi = %d, mgres = %d\n",di,fdi,(int)s->g.mres));
+
+//printf("~1 nnb = %d\n",nnb);
+
+ s->get_out_range(s, rgmin, rgmax); /* overall output min/max */
+
+ /* Expand out range to encompass declared range */
+ /* The declared range is assumed to be the range over which */
+ /* we may want an reasonably accurate nearest reverse lookup. */
+ for (f = 0; f < fdi; f++) {
+ if ((s->d.vl[f] + s->d.vw[f]) > rgmax[f])
+ rgmax[f] = s->d.vl[f] + s->d.vw[f];
+ if (s->d.vl[f] < rgmin[f])
+ rgmin[f] = s->d.vl[f];
+ }
+
+ /* Expand out range slightly to allow for out of gamut points */
+ for (f = 0; f < fdi; f++) {
+ double del = (rgmax[f] - rgmin[f]) * 0.10; /* Expand by +/- 10% */
+ rgmax[f] += del;
+ rgmin[f] -= del;
+ }
+//printf("~~got output range\n");
+
+ /* Heuristic - reverse grid acceleration resolution ? */
+ /* Should this really be adapted to be constant in output space ? */
+ /* (ie. make the gw aprox equal ?) Would complicate code rev accell */
+ /* indexing though. */
+ {
+ char *ev;
+ double gresmul = REV_ACC_GRES_MUL; /* Typically 2.0 */
+
+ if ((gresmul * s->g.mres) > (double)REV_ACC_GRES_LIMIT) {
+ gresmul = (double)REV_ACC_GRES_LIMIT/s->g.mres; /* Limit target res to typ. 43. */
+ }
+
+ /* Allow the user to override if it causes memory consumption problems */
+ /* or to speed things up if more memory is available */
+ if ((ev = getenv("ARGYLL_REV_ACC_GRID_RES_MULT")) != NULL) {
+ double mm;
+ mm = atof(ev);
+ if (mm > 0.1 && mm < 20.0)
+ gresmul *= mm;
+ }
+ /* Less than 4 is not functional */
+ if ((rgres = (int) gresmul * s->g.mres) < 4)
+ rgres = 4;
+ }
+ argres = rgres+1;
+ s->rev.ares = argres; /* == number of verticies per side, used for construction */
+ s->rev.res = rgres; /* == number of cells per side */
+ rgres_1 = rgres-1;
+
+ /* Number of elements in the rev.grid, including construction extra rows */
+ for (rgno = 1, f = 0; f < fdi; f++, rgno *= argres);
+ s->rev.no = rgno;
+
+//printf("~1 argres = %d\n",argres);
+ /* Compute coordinate increments */
+ s->rev.coi[0] = 1;
+//printf("~1 coi[0] = %d\n",s->rev.coi[0]);
+ for (f = 1; f < fdi; f++) {
+ s->rev.coi[f] = s->rev.coi[f-1] * argres;
+//printf("~1 coi[%d] = %d\n",f,s->rev.coi[f]);
+ }
+
+ /* Compute index offsets from base of cube to other corners. */
+
+ for (s->rev.hoi[0] = f = 0, j = 1; f < fdi; j *= 2, f++) {
+ for (i = 0; i < j; i++)
+ s->rev.hoi[j+i] = s->rev.hoi[i] + s->rev.coi[f]; /* In grid points */
+ }
+//for (ff = 0; ff < (1 << fdi); ff++)
+//printf("~1 hoi[%d] = %d\n",ff,s->rev.hoi[ff]);
+
+ /* Conversion from output value to cell indexes */
+ for (f = 0; f < fdi; f++) {
+ s->rev.gl[f] = rgmin[f];
+ s->rev.gh[f] = rgmax[f];
+ s->rev.gw[f] = (rgmax[f] - rgmin[f])/(double)rgres;
+ }
+
+ if ((s->rev.rev = (int **) rev_calloc(s, rgno, sizeof(int *))) == NULL)
+ error("rspl malloc failed - rev.grid points");
+ INCSZ(s, rgno * sizeof(int *));
+
+ if ((s->rev.nnrev = (int **) rev_calloc(s, rgno, sizeof(int *))) == NULL)
+ error("rspl malloc failed - rev.nngrid points");
+ INCSZ(s, rgno * sizeof(int *));
+
+ s->rev.inited = 1;
+
+ s->rev.stouch = 1;
+
+ DBG(("make_rev_one finished\n"));
+}
+
+/* ====================================================== */
+
+/* First section of rev_struct init. */
+/* Initialise the reverse cell cache, sub simplex information */
+/* and reverse lookup acceleration structures. */
+/* This is called by a reverse interpolation call */
+/* that discovers that the reverse index list haven't */
+/* been initialised. */
+static void make_rev(
+rspl *s
+) {
+ int e, di = s->di;
+ char *ev;
+ size_t avail_ram = 256 * 1024 * 1024; /* Default assumed RAM in the system */
+ size_t ram1, ram2; /* First Gig and rest */
+ static int repsr = 0; /* Have we reported system RAM size ? */
+ size_t max_vmem = 0;
+
+ DBG(("make_rev called, di = %d, fdi = %d, mgres = %d\n",di,s->fdi,(int)s->g.mres));
+
+ /* Figure out how much RAM we can use for the rev cache. */
+ /* (We compute this for each rev instance, to account for any VM */
+ /* limit changes due to intervening allocations) */
+ if (di > 1 || g_avail_ram == 0) {
+ #ifdef NT
+ {
+ BOOL (WINAPI* pGlobalMemoryStatusEx)(MEMORYSTATUSEX *) = NULL;
+ MEMORYSTATUSEX mstat;
+
+ pGlobalMemoryStatusEx = (BOOL (WINAPI*)(MEMORYSTATUSEX *))
+ GetProcAddress(LoadLibrary("KERNEL32"), "GlobalMemoryStatusEx");
+
+ if (pGlobalMemoryStatusEx == NULL)
+ error("Unable to link to GlobalMemoryStatusEx()");
+ mstat.dwLength = sizeof(MEMORYSTATUSEX);
+ if ((*pGlobalMemoryStatusEx)(&mstat) != 0) {
+ if (sizeof(avail_ram) < 8 && mstat.ullTotalPhys > 0xffffffffL)
+ mstat.ullTotalPhys = 0xffffffffL;
+ avail_ram = mstat.ullTotalPhys;
+ } else {
+ warning("%cWarning - Unable to get system memory size",cr_char);
+ }
+ }
+ #else
+ #ifdef __APPLE__
+ {
+ long long memsize;
+ size_t memsize_sz = sizeof(long long);
+ if (sysctlbyname("hw.memsize", &memsize, &memsize_sz, NULL, 0) == 0) {
+ if (sizeof(avail_ram) < 8 && memsize > 0xffffffffL)
+ memsize = 0xffffffff;
+ avail_ram = memsize;
+ } else {
+ warning("%cWarning - Unable to get system memory size",cr_char);
+ }
+
+ }
+ #else /* Linux */
+ {
+ long long total;
+ total = (long long)sysconf(_SC_PAGESIZE) * (long long)sysconf(_SC_PHYS_PAGES);
+ if (sizeof(avail_ram) < 8 && total > 0xffffffffL)
+ total = 0xffffffffL;
+ avail_ram = total;
+ }
+ #endif
+ #endif
+ DBG(("System RAM = %d Mbytes\n",avail_ram/1000000));
+
+ /* Make it sane */
+ if (avail_ram < (256 * 1024 * 1024)) {
+ warning("%cWarning - System RAM size seems very small (%d MBytes),"
+ " assuming 256Mb instead",cr_char,avail_ram/1000000);
+ avail_ram = 256 * 1024 * 1024;
+ }
+ // avail_ram = -1; /* Fake 4GB of RAM. This will swap! */
+
+ ram1 = avail_ram;
+ ram2 = 0;
+ if (ram1 > (1024 * 1024 * 1024)) {
+ ram1 = 1024 * 1024 * 1024;
+ ram2 = avail_ram - ram1;
+ }
+
+ /* Default maximum reverse memory (typically 50% of the first Gig, 75% of the rest) */
+ g_avail_ram = (size_t)(REV_MAX_MEM_RATIO * ram1
+ + REV_MAX_MEM_RATIO2 * ram2);
+
+ /* Many 32 bit systems have a virtual memory limit, so we'd better stay under it. */
+ /* This is slightly dodgy though, since we don't know how much memory other */
+ /* software will need to malloc. A more sophisticated approach would be to */
+ /* replace all malloc/calloc/realloc calls in the exe with a version that on failure, */
+ /* sets the current memory usage as the new limit, and then */
+ /* frees up some rev cache space before re-trying. This is a non-trivial change */
+ /* to the source code though, and really has to include all user mode */
+ /* libraries we're linked to, making implementation problematic. */
+ /* Instead we do a simple test to see what the maximum allocation is, and */
+ /* then use 75% of that for cache, and free cache and retry if */
+ /* malloc failes in rev.c. Too bad if 25% isn't enough, and a malloc fails */
+ /* outside rev.c... */
+ if (sizeof(avail_ram) < 8) {
+ char *alocs[4 * 1024];
+ size_t safe_max_vmem = 0;
+ int i;
+
+#ifdef __APPLE__
+ int old_stderr, new_stderr;
+
+ /* OS X malloc() blabs about a malloc failure. This */
+ /* will confuse users, so we temporarily redirect stdout */
+ fflush(stderr);
+ old_stderr = dup(fileno(stderr));
+ new_stderr = open("/dev/null", O_WRONLY | O_APPEND);
+ dup2(new_stderr, fileno(stderr));
+#endif
+ for (i = 0; (i < 4 * 1024);i++) {
+ if ((alocs[i] = malloc(1024 * 1024)) == NULL) {
+ break;
+ }
+ max_vmem = (i+1) * 1024 * 1024;
+ }
+ for (--i; i >= 0; i--) {
+ free(alocs[i]);
+ }
+#ifdef __APPLE__
+ fflush(stderr);
+ dup2(old_stderr, fileno(stderr)); /* Restore stderr */
+ close(new_stderr);
+ close(old_stderr);
+#endif
+ /* To compute a true value, we need to allow for any VM already */
+ /* used by any rev instances. */
+ {
+ rev_struct *rsi;
+
+ for (rsi = g_rev_instances; rsi != NULL; rsi = rsi->next)
+ max_vmem += rsi->sz;
+ }
+
+//fprintf(stdout,"~ Abs max VM = %d Mbytes\n",max_vmem/1000000);
+ safe_max_vmem = (size_t)(0.85 * max_vmem);
+ if (g_avail_ram > safe_max_vmem) {
+ g_avail_ram = safe_max_vmem;
+ if (s->verbose && repsr == 0)
+ fprintf(stdout,"%cTrimmed maximum cache RAM to %lu Mbytes to allow for VM limit\n",cr_char,g_avail_ram/1000000);
+ }
+ }
+
+ /* Check for environment variable tweak */
+ if ((ev = getenv("ARGYLL_REV_CACHE_MULT")) != NULL) {
+ double mm, gg;
+ mm = atof(ev);
+ if (mm < 0.01) /* Make it sane */
+ mm = 0.01;
+ else if (mm > 100.0)
+ mm = 100.0;
+ gg = g_avail_ram * mm + 0.5;
+ if (gg > (double)(((size_t)0)-1))
+ gg = (double)(((size_t)0)-1);
+ g_avail_ram = (size_t)(gg);
+ }
+ if (max_vmem != 0 && g_avail_ram > max_vmem && repsr == 0) {
+ g_avail_ram = (size_t)(0.95 * max_vmem);
+ fprintf(stdout,"%cARGYLL_REV_CACHE_MULT * RAM trimmed to %lu Mbytes to allow for VM limit\n",cr_char,g_avail_ram/1000000);
+ }
+ }
+
+ /* Default - this will get aportioned as more instances appear */
+ s->rev.max_sz = g_avail_ram;
+
+ DBG(("reverse cache max memory = %d Mbytes\n",s->rev.max_sz/1000000));
+ if (s->verbose && repsr == 0) {
+ fprintf(stdout, "%cRev cache RAM = %lu Mbytes\n",cr_char,g_avail_ram/1000000);
+ repsr = 1;
+ }
+
+ /* Sub-simplex information for each sub dimension */
+ for (e = 0; e <= di; e++) {
+ if (s->rev.sspxi[e].spxi != NULL) /* Assert */
+ error("rspl rev, internal, init_ssimplex_info called on already init'd\n");
+
+ rspl_init_ssimplex_info(s, &s->rev.sspxi[e], e);
+ }
+
+ make_rev_one(s);
+
+ /* Reverse cell cache allocation */
+ s->rev.cache = alloc_revcache(s);
+
+ DBG(("make_rev finished\n"));
+}
+
+/* ====================================================== */
+
+#if defined(DEBUG1) || defined(DEBUG2)
+
+/* Utility - return a string containing a cells output value range */
+static char *pcellorange(cell *c) {
+ static char buf[5][300];
+ static ix = 0;
+ char *bp;
+ rspl *s = c->s;
+ int di = s->di, fdi = s->fdi;
+ int ee, e, f;
+
+ datao min, max;
+
+// double p[POW2MXRI][MXRI]; /* Vertex input positions for this cube. */
+// double v[POW2MXRI][MXRO+1]; /* Vertex data for this cube. Copied to x->v[] */
+// /* v[][fdi] is the ink limit values, if relevant */
+
+ for (f = 0; f < fdi; f++) {
+ min[f] = 1e60;
+ max[f] = -1e60;
+ }
+
+ /* For all other grid points in the cube */
+ for (ee = 0; ee < (1 << di); ee++) {
+
+ /* Update bounding box for this grid point */
+ for (f = 0; f < fdi; f++) {
+ if (min[f] > c->v[ee][f])
+ min[f] = c->v[ee][f];
+ if (max[f] < c->v[ee][f])
+ max[f] = c->v[ee][f];
+ }
+ }
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ for (e = 0; e < fdi; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%f:%f", min[e],max[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+#endif
+/* ====================================================== */
+
+#undef DEBUG
+#undef DBGV
+#undef DBG
+#define DBGV(xxx)
+#define DBG(xxx)
+
+
+
+
+
+
diff --git a/rspl/rev.h b/rspl/rev.h
new file mode 100644
index 0000000..b947cbe
--- /dev/null
+++ b/rspl/rev.h
@@ -0,0 +1,457 @@
+#ifndef RSPL_REV_H
+#define RSPL_REV_H
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized spline data structure
+ *
+ * Reverse interpolation support code.
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/1/00
+ *
+ * Copyright 1999 - 2008 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.
+ *
+ * Latest simplex/linear equation version.
+ */
+
+#undef STATS /* Collect and print reverse cach stats */
+
+/* Data structures used by reverse lookup code. */
+/* Note that the reverse lookup code only supports a more limited */
+/* dimension range than the general rspl code. */
+
+/*
+ * Note on simplex parameter space.
+ *
+ * Simplex interpolation is normaly done in Baricentric space, where there
+ * is one more baricentric coordinate than dimensions, and the sum of all
+ * the baricentric coordinates must be 1.
+ *
+ * To simplify things, we work in a "Simplex parameter" space, in which
+ * there are only dimension parameters, and each directly corresponds
+ * with a cartesian coordinate, but the parameter order corresponds with
+ * the baricentric order.
+ *
+ * For example, given cartesian coordinates D0, D1, D2
+ * these should be sorted from smallest to largest, thereby
+ * choosing a particular simplex within a cube, and allowing
+ * a correspondence to the parameter coordinates, ie:
+ *
+ * D1 D0 D2 Smallest -> Largest cartesian sort
+ * P2 P1 P0 Corresponding Parameter coordinates (note reverse order!)
+ *
+ * B0 = P0 Conversion to Baricentric coordinates
+ * B1 = P1 - P0
+ * B2 = P2 - P1
+ * B3 = 1 - P2
+ *
+ * The vertex values directly correspond to Baricentric coordinates,
+ * giving the usual interpolation equation of:
+ *
+ * VV0 * B0
+ * + VV1 * B1
+ * + VV2 * B2
+ * + VV3 * B3
+ *
+ * Reversing the Parameter -> Baricentric equations gives the
+ * following interpolation equation using Parameter coordinates:
+ *
+ * VV0 - VV1 * P0
+ * + VV1 - VV2 * P1
+ * + VV2 - VV3 * P2
+ * + VV3
+ *
+ * It is this which is used in rev.c for solving the reverse
+ * interpolation problem.
+ */
+
+/* A structure to hold per simplex coordinate and vertex mapping */
+/* This is relative to the construction cube. A face sub-simplex */
+/* that is common between cubes, will have a different psxinfo */
+/* depending on which cube created it. */
+typedef struct {
+ int face; /* Flag, nz if simplex lies on cube surface */
+ int icomb[MXDI]; /* Index by Absolute[di] -> Simplex Parameter[sdi], */
+ /* -1 == value 0, -2 == value 1 */
+ /* Note that many Abs can map to one Param to form a sum. */
+ /* icomb[] specifies the equation to convert simplex space */
+ /* coordinates back into cartesian space. */
+ int offs[MXDI+1]; /* Offsets to simplex verticies within cube == bit per dim */
+ int goffs[MXDI+1]; /* Offsets to simplex verticies within grid */
+ int foffs[MXDI+1]; /* Fwd grid floating offsets to simplex verticies from cube base */
+ int pmino[MXDI], pmaxo[MXDI]; /* Cube verticy offsets to setup simplex pmin[] and */
+ /* pmax[] bounding box pointers. */
+} psxinfo;
+
+/* Sub simplexes of a cube information structure */
+typedef struct {
+ int sdi; /* Sub-simplex dimensionality */
+ int nospx; /* Number of sub-simplexs per cube */
+ psxinfo *spxi; /* Per sub-simplex info array, NULL if not initialised */
+} ssxinfo;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* NOTE :- This should really be re-arranged to be per-sub-simplex caching, */
+/* rather than cell caching. Rather than stash the simplex info in the cells, */
+/* create a separate cache or some other way of sharing the common simplexes. */
+/* The code that ignores common face simplexes in cells could then be removed. */
+
+/* Simplex definition. Each top level fwd interpolation cell, */
+/* is decomposed into sub-simplexes. Sub-simplexes are of equal or */
+/* lower dimensionality (ie. faces, edges, verticies) to the cube. */
+struct _simplex {
+ int refcount; /* reference count */
+ struct _rspl *s; /* Pointer to parent rspl */
+ int ix; /* Construction Fwd cell index */
+ int si; /* Diagnostic - simplex number within level */
+ int sdi; /* Sub-simplex dimensionality */
+ int efdi; /* Effective fdi. This will be = fdi for a non clip */
+ /* plane simplex, and fdi+1 for a clip plane simplex */
+ /* The DOF (Degress of freedom) withing this simplex = sdi - efdi */
+
+ psxinfo *psxi; /* Generic per simplex info (construction cube relative) */
+ int vix[MXRI+1]; /* fwd cell vertex indexes of this simplex [sdi+1] */
+ /* This is a universal identification of this simplex */
+ struct _simplex *hlink; /* Link to other cells with this hash */
+ unsigned int touch; /* Last touch count. */
+ short flags; /* Various flags */
+
+#define SPLX_CLIPSX 0x01 /* This is a clip plane simplex */
+
+#define SPLX_FLAG_1 0x04 /* v, linmin/max initialised */
+#define SPLX_FLAG_2 0x08 /* lu/svd initialised */
+#define SPLX_FLAG_2F 0x10 /* lu/svd init. failed */
+#define SPLX_FLAG_4 0x20 /* locus found */
+#define SPLX_FLAG_5 0x40 /* auxiliary lu/svd initialised */
+#define SPLX_FLAG_5F 0x80 /* auxiliary lu/svd init. failed */
+
+
+#define SPLX_FLAGS (SPLX_FLAG_1 | SPLX_FLAG_2 | SPLX_FLAG_2F \
+ | SPLX_FLAG_4 | SPLX_FLAG_5 | SPLX_FLAG_5F)
+
+ double v[MXRI+1][MXRO+1]; /* Simplex Vertex values */
+ /* v[0..sdi][0..fdi-1] are the output interpolation values */
+ /* v[0..sdi][fdi] are the ink limit interpolation values */
+
+ /* Baricentric vv[x][y] = (v[y][x] - v[y+1][x]) */
+ /* and vv[x][sdi] = v[sdi][x] */
+
+ /* Note that #num indicates appropriate flag number */
+ /* and *num indicates a validator */
+
+ double p0[MXRI]; /* Simplex base position = construction cube p[0] */
+ double pmin[MXRI]; /* Simplex vertex input space min and */
+ double pmax[MXRI]; /* max values [di] */
+
+ double min[MXRO+1], max[MXRO+1]; /* Simplex vertex output space [fdi+1] and */
+ /* ink limit bounding values at minmax[fdi] */
+
+ /* If sdi == efdi, this holds the LU decomposition */
+ /* else this holds the SVD and solution locus info */
+
+ char *aloc2; /* Memory allocation for #2 & #4 */
+
+ /* double **d_u; LU decomp of vv, U[0..efdi-1][0..sdi-1] #2 */
+ /* int *d_w; LU decomp of vv, W[0..sdi-1] #2 */
+
+ double **d_u; /* SVD decomp of vv, U[0..efdi-1][0..sdi-1] #2 */
+ double *d_w; /* SVD decomp of vv, W[0..sdi-1] #2 */
+ double **d_v; /* SVD decomp of vv, V[0..sdi-1][0..sdi-1] #2 */
+
+ /* Degrees of freedom = dof = sdi - efdi */
+ double **lo_l; /* Locus coefficients, [0..sdi-1][0..dof-1] #2 */
+
+ double *lo_xb; /* RHS used to compute lo_bd [0..efdi-1] *4 */
+ double *lo_bd; /* Locus base solution, [0..sdi-1] #4 */
+
+ unsigned auxbm; /* aux bitmap mask for ax_lu and ax_svd *5 */
+ int aaux; /* naux count for allocation *5 */
+ int naux; /* naux for calculation (may be < aaux ?) *5 */
+
+ /* if (sdi-efdi = dof) == naux this holds LU of lo_l */
+ /* else this holds the SVD of lo_l */
+
+ char *aloc5; /* Memory allocation for #5 */
+
+ /* double **ax_u; LU decomp of lo_l #5 */
+ /* int *ax_w; Pivot record for ax_lu decomp #5 */
+
+ double **ax_u; /* SVD decomp of lo_l, U[0..naux-1][0..dof-1] #5 */
+ double *ax_w; /* SVD decomp of lo_l, W[0..dof-1] #5 */
+ double **ax_v; /* SVD decomp of lo_l, V[0..dof-1][0..dof-1] #5 */
+
+}; typedef struct _simplex simplex;
+
+/* A candidate search cell (cell cache entry structure) */
+struct _cell {
+ struct _rspl *s; /* Pointer to parent rspl */
+
+ /* Cache information */
+ int ix; /* Fwd cell index */
+ struct _cell *hlink; /* Link to other cells with this hash */
+ struct _cell *mrudown; /* Links to next most recently used cell */
+ struct _cell *mruup;
+ int refcount; /* Reference count */
+ int flags; /* Non-zero if the cell has been initialised */
+#define CELL_FLAG_1 0x01 /* Basic initialisation */
+#define CELL_FLAG_2 0x02 /* Simplex information initialised */
+
+ /* Use information */
+ double sort; /* Sort key */
+
+ double limmin, limmax; /* limit() min/max for this cell */
+ double bcent[MXRO]; /* Output value bounding shere center */
+ double brad; /* Output value bounding shere radius */
+ double bradsq; /* Output value bounding shere radius squared */
+
+ double p[POW2MXRI][MXRI]; /* Vertex input positions for this cube. */
+ /* Copied to x->pmin/pmax[] & ink limit */
+
+ double v[POW2MXRI][MXRO+1]; /* Vertex data for this cube. Copied to x->v[] */
+ /* v[][fdi] is the ink limit values, if relevant */
+
+ simplex **sx[MXRI+1]; /* Lists of simplexes that make up this cell. */
+ /* Each list indexed by the non-limited simplex */
+ /* dimensionality (similar to sspxi[]) */
+ /* Each list will be NULL if it hasn't been created yet */
+ int sxno[MXRI+1]; /* Corresponding count of each list */
+
+}; typedef struct _cell cell;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+/* Enough space is needed to cache all the cells/simplexes */
+/* for a full aux. locus, or the query will be processed in */
+/* several "chunks" and will be slower. */
+/* This sets the basic memory usage of the rev code. */
+
+#define REV_ACC_GRES_MUL 2.0 /* 2.0 Reverse accelleration grid resolution */
+ /* multiplier over fwd grid resolution */
+#define REV_ACC_GRES_LIMIT 43 /* Reverse accelln. grid resolution limit before env. mult. */
+#define REV_MAX_MEM_RATIO 0.3 /* 0.3 Proportion of first 1G of Ram to use */
+#define REV_MAX_MEM_RATIO2 0.4 /* 0.4 Proportion of rest of Ram to use */
+ /* rev as a fraction of the System RAM. */
+#define HASH_FILL_RATIO 3 /* 3 Ratio of entries to hash size */
+
+/* The structure where cells are allocated and cached. */
+
+/* Holds the cell and simplex match cache specific information */
+typedef struct {
+ struct _rspl *s; /* Pointer to parent rspl */
+ int nacells; /* Number of allocated cells */
+ int nunlocked; /* Number of unlocked cells that could be freed */
+ int cell_hash_size; /* Current size of cell hash list */
+ cell **hashtop; /* Top of hash list [cell_hash_size] */
+ cell *mrutop, *mrubot; /* Top and bottom pointers of mru list */
+ /* that tracks allocated cells */
+
+ int spx_hash_size; /* Current size of simplex hash list */
+ simplex **spxhashtop; /* Face simplex hash index list */
+ int nspx; /* Number of simplexes in hash list */
+} revcache;
+
+/* common search information */
+/* Type of (internal) reverse search */
+enum ops {
+ exact = 0, /* Search for all input values that exactly map to given output value */
+ clipv = 1, /* Search for input values that map to outermost solution along a vector */
+ clipn = 2, /* Search for input values that map to closest solution */
+ auxil = 3, /* Search for input values that map to given output, and closest to auxiliary target */
+ locus = 4 }; /* Return range of auxiliary values that contains solution */
+
+/* + possible exact with clip */
+
+/* Structure to hold clip line state information */
+typedef struct {
+ struct _rspl *s; /* Pointer to parent rspl */
+ double st[MXRO]; /* start of line - reverse grid base value */
+ double de[MXRO]; /* direction of line */
+ int di[MXRO]; /* incerement in line direction */
+ int ci[MXRO]; /* current rev grid coordinate */
+ double t; /* Parameter 0.0 - 1.0, line finished if t > 1.0 */
+} line;
+
+
+/* Structure to hold aux value of an intersection of a */
+/* solution locus with a sub-simplex. Used when asegs flag is set */
+typedef struct {
+ double xval; /* Auxiliary value */
+ int nv; /* Number of verticies valid */
+ int vix[MXRI+1]; /* Verticy indexes of sub-simplex involved */
+} axisec;
+
+/* -------------------------------------------- */
+/* Information needed/cached for reverse lookup */
+struct _schbase {
+ struct _rspl *s; /* Pointer to parent rspl */
+
+ int flags; /* Hint flags */
+ enum ops op; /* Type of reverse search operation */
+ int ixc; /* Cube index of corner that holds maximum input values */
+
+ int snsdi, ensdi; /* Start and end extra sub-simplex dimensionality */
+ int (*setsort)(struct _schbase *b, cell *c); /* Function to triage & set cube sort index */
+ int (*check)(struct _schbase *b, cell *c); /* Function to recheck cube worth keeping */
+ int (*compute)(struct _schbase *b, simplex *x); /* Function to compute a simplex solution */
+
+ double v[MXRO+1]; /* Target output value, + ink limit */
+ double av[MXRI]; /* Target auxiliary values */
+ int auxm[MXRI]; /* aux mask flags */
+ unsigned auxbm; /* aux bitmap mask */
+ int naux; /* Number of auxiliary target input values */
+ int auxi[MXRI]; /* aux list of auxiliary target input values */
+ double idist; /* best input distance auxiliary target found (smaller is better) */
+ int iabove; /* Number of auxiliaries at or above zero */
+
+ int canvecclip; /* Non-zero if vector clip direction usable */
+ double cdir[MXRO]; /* Clip vector direction and length wrt. v[] */
+ double ncdir[MXRO]; /* Normalised clip vector */
+ double **cla; /* Clip vector LHS implicit equation matrix [fdi][fdi+1] (inc. ink tgt.) */
+ double clb[MXRO+1]; /* Clip vector RHS implicit equation vector [fdi+1] (inc. ink tgt.) */
+ double cdist; /* Best clip locus distance found (aim is min +ve) */
+ int iclip; /* NZ if result is above (disabled) ink limit */
+
+ int mxsoln; /* Maximum number of solutions that we want */
+ int nsoln; /* Current number of solutions found */
+ co *cpp; /* Store solutions here */
+
+ int lxi; /* Locus search axiliary index */
+ double min, max; /* current extreme locus values for locus search */
+ int asegs; /* flag - find all search segments */
+ int axisln; /* Number of elements used in axisl[] */
+ int axislz; /* Space allocated to axisl[] */
+ axisec *axisl; /* Auxiliary intersections */
+
+ int lclistz; /* Allocated space to cell sort list */
+ cell **lclist; /* Sorted list of pointers to candidate cells */
+
+ int pauxcell; /* Indexe of previous call solution cell, -1 if not relevant */
+ int plmaxcell; /* Indexe of previous call solution cell, -1 if not relevant */
+ int plmincell; /* Indexe of previous call solution cell, -1 if not relevant */
+
+ int lsxfilt; /* Allocated space of simplex filter list */
+ char *sxfilt; /* Flag for simplexes that should be in a cell */
+
+ double crad; /* nn current radius distance */
+ double bw; /* nn current window distance */
+ int wex[MXRO * 2]; /* nn current window edge indexes */
+ double wed[MXRO * 2]; /* nn current window edge distances */
+
+}; typedef struct _schbase schbase;
+
+/* ----------------------------------------- */
+
+#ifdef STATS
+struct _stats {
+ int searchcalls;/* Number of top level searches */
+ int csearched; /* Cells searched */
+ int ssearched; /* Simplexes searched */
+ int sinited; /* Simplexes initialised to base level */
+ int sinited2a; /* Simplexes initialised to 2nd level with LU */
+ int sinited2b; /* Simplexes initialised to 2nd level with SVD */
+ int sinited4i; /* Simplexes invalidated at 4th level */
+ int sinited4; /* Simplexes initialised to 4th level */
+ int sinited5i; /* Simplexes invalidated at 5th level */
+ int sinited5a; /* Simplexes initialised to 5th level with LU */
+ int sinited5b; /* Simplexes initialised to 5th level with SVD */
+ int chits; /* Cells hit in cache */
+ int cmiss; /* Cells misses in cache */
+}; typedef struct _stats stats;
+#endif /* STATS */
+
+/* ----------------------------------------- */
+/* Reverse info stored in main rspl function */
+struct _rev_struct {
+
+ /* First section, basic information that doesn't change */
+ /* Has been initialised if inited != 0 */
+
+ int inited; /* Non-zero if first section has been initialised */
+ /* All other sections depend on this. */
+ int fastsetup; /* Flag - NZ if fast setup at cost of slow throughput */
+
+ struct _rev_struct *next; /* Linked list of instances sharing memory */
+ size_t max_sz; /* Maximum size permitted */
+ size_t sz; /* Total memory current allocated by rev */
+
+#ifdef NEVER
+ int thissz, lastsz; /* Debug reporting */
+#endif
+
+ /* Reverse grid lookup information */
+ int ares; /* Reverse grid allocated resolution, = res + 1, */
+ /* allows for extra row used during construction */
+ int res; /* Reverse grid resolution == ncells on a side */
+ int no; /* Total number of points in reverse grid = rev.ares ^ fdi */
+ int coi[MXRO]; /* Coordinate increments for each dimension */
+ int hoi[1 << MXRO]; /* Coordinate increments for progress through cube */
+ datao gl,gh,gw; /* Reverse grid low, high, grid cell width */
+
+ /* Second section, accelleration information that changes with ink limit. */
+ int rev_valid; /* nz if this information in rev[] and nnrev[] is valid */
+ int **rev; /* Exact reverse lookup starting list. */
+ /* rev.no pointers to lists of fwd grid indexes. */
+ /* First int is allocation length */
+ /* Second int is reference count */
+ /* Then follows cube indexes */
+ /* Last int is -1 */
+ int **nnrev; /* Nearest reverse lookup starting list. */
+ /* rev.no pointers to lists of fwd grid indexes. */
+ /* [0] is allocation length */
+ /* [1] is the next free entry index */
+ /* [2] is reference count */
+ /* Then follows cube indexes */
+ /* The last entry is marked with -1 */
+
+ /* Third section */
+ revcache *cache; /* Where cells are allocated and cached */
+ /* Sub-dimension simplex information */
+ ssxinfo sspxi[MXRI+1];/* One per sub dimenstionality at offset sdi */
+
+ /* Fourth section */
+ /* Has been initialise if sb != NULL */
+ schbase *sb; /* Structure holding calculated per-search call information */
+
+ unsigned int stouch; /* Simplex touch count to avoid searching shared simplexs twice */
+#ifdef STATS
+ stats st[5]; /* Set of stats info indexed by enum ops */
+#endif /* STATS */
+
+ int primsecwarn; /* Not primary or secondary warning has been issued */
+
+}; typedef struct _rev_struct rev_struct;
+
+
+/* ------------------------------------ */
+/* Utility functions used by other parts of rspl implementation */
+
+/* Initialise a static sub-simplex verticy information table */
+void rspl_init_ssimplex_info(struct _rspl *s, /* RSPL object */
+ssxinfo *xip, /* Pointer to sub-simplex info structure to init. */
+int sdi); /* Sub-simplex dimensionality (range 0 - di) */
+
+/* Free the given sub-simplex verticy information */
+void rspl_free_ssimplex_info(struct _rspl *s,
+ssxinfo *xip); /* Pointer to sub-simplex info structure */
+
+#endif /* RSPL_REV_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rspl/revbench.c b/rspl/revbench.c
new file mode 100644
index 0000000..d0c7566
--- /dev/null
+++ b/rspl/revbench.c
@@ -0,0 +1,306 @@
+
+/************************************************/
+/* Benchmark RSPL reverse lookup */
+/************************************************/
+
+/* Author: Graeme Gill
+ * Date: 31/10/96
+ * Derived from tnd.c
+ * Copyright 1999 - 2000 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "rspl.h"
+#include "numlib.h"
+
+#undef DOLIMIT /* Define to have ink limit */
+#define LIMITVAL 2.5 /* Total ink limit sum */
+#undef DOCHECK
+
+#define SHOW_OUTPUT /* Define for printf on each conversion */
+
+/* 11, 19 give about 60 seconds */
+#define GRES 17 /* Default grid resolution */
+#define RRES 43 /* Default reverse test resolution */
+#define DI 4 /* Dimensions in */
+#define FDI 3 /* Function (out) Dimensions */
+#define NIP 10 /* Number of solutions allowed */
+
+#define flimit(vv) ((vv) < 0.0 ? 0.0 : ((vv) > 1.0 ? 1.0 : (vv)))
+#define fmin(a,b) ((a) < (b) ? (a) : (b))
+#define fmin3(a,b,c) (fmin((a), fmin((b),(c))))
+#define fmax(a,b) ((a) > (b) ? (a) : (b))
+#define fmax3(a,b,c) (fmax((a), fmax((b),(c))))
+
+/* Fwd function approximated by rspl */
+/* Dummy cmyk->rgb conversion. This simulates our device */
+void func(
+void *cbctx,
+double *out,
+double *in) {
+ double kk;
+ double ci = in[0];
+ double mi = in[1];
+ double yi = in[2];
+ double ki = in[3];
+ double r,g,b;
+
+ ci += ki; /* Add black back in */
+ mi += ki;
+ yi += ki;
+ kk = fmax3(ci,mi,yi);
+ if (kk > 1.0) {
+ ci /= kk;
+ mi /= kk;
+ yi /= kk;
+ }
+ r = 1.0 - ci;
+ g = 1.0 - mi;
+ b = 1.0 - yi;
+ out[0] = flimit(r);
+ out[1] = flimit(g);
+ out[2] = flimit(b);
+}
+
+/* Simplex ink limit function */
+double limitf(
+void *lcntx,
+float *in
+) {
+ int i;
+ double ov;
+
+ for (ov = 0.0, i = 0; i < DI; i++) {
+ ov += in[i];
+ }
+ return ov;
+}
+
+
+void usage(void) {
+ fprintf(stderr,"Benchmark rspl reverse, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"usage: revbench [-f fwdres] [-r revres] [-v level] iccin iccout\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -f res Set forward grid res\n");
+ fprintf(stderr," -r res Set reverse test res\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int clutres = GRES;
+ int rres = RRES;
+ int verb = 0;
+ int gres[MXDI];
+ int e;
+
+ clock_t stime,ttime;
+ rspl *rss; /* Multi-resolution regularized spline structure */
+
+ error_program = argv[0];
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage();
+ clutres = atoi(na);
+ }
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ rres = atoi(na);
+ }
+ else
+ usage();
+ } else
+ break;
+ }
+
+ printf("Started benchmark\n");
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS, DI, FDI);
+
+ for (e = 0; e < DI; e++)
+ gres[e] = clutres;
+
+ printf("Rspl allocated\n");
+ rss->set_rspl(rss, 0, (void *)NULL, func,
+ NULL, NULL, gres, NULL, NULL);
+
+ printf("Rspl set\n");
+
+ /* Start exploring the reverse test grid */
+ {
+ int ops = 0;
+ double secs;
+ rpsh counter;
+ unsigned rcount;
+ int ii[10];
+ int f, rgres[MXDO];
+
+ int flags = 0; /* rev hint flags */
+ co tp[NIP]; /* Test point */
+ double cvec[4]; /* Text clip vector */
+ int auxm[4]; /* Auxiliary target value valid flag */
+#ifdef DOCHECK
+ int j;
+#endif
+#ifdef NEVER
+ double lmin[4], lmax[4]; /* Locus min/max values */
+#endif
+
+#ifdef DOCHECK
+ char *check; /* Check that we hit every cell */
+#endif /* DOCHECK */
+
+ /* Set auxiliary target mask */
+ auxm[0] = 0;
+ auxm[1] = 0;
+ auxm[2] = 0;
+ auxm[3] = 1;
+
+#ifdef DOLIMIT
+ rss->rev_set_limit(rss,
+ limitf,
+ NULL,
+ LIMITVAL /* limit maximum value */
+ );
+#endif /* DOLIMIT */
+
+ printf("Forward resolution %d\n",clutres);
+ printf("Reverse resolution %d\n",rres);
+
+#ifdef DOCHECK
+ if ((check = (char *)calloc(1, rcount)) == NULL)
+ error("Malloc of check array\n");
+#endif /* DOCHECK */
+
+ for (f = 0; f < FDI; f++)
+ rgres[f] = rres;
+
+ rcount = rpsh_init(&counter, FDI, (unsigned int *)rgres, ii); /* Initialise counter */
+
+ stime = clock();
+
+ /* Itterate though the grid */
+ for (ops = 0;; ops++) {
+ int r;
+ int e; /* Table index */
+
+#ifdef DOCHECK
+ check[((ii[2] * rres + ii[1]) * rres) + ii[0]] = 1;
+#endif /* DOCHECK */
+
+ for (e = 0; e < FDI; e++) { /* Input tables */
+ tp[0].v[e] = ii[e]/(rres-1.0); /* Vertex coordinates */
+ }
+
+ if (verb)
+ printf("Input = %f %f %f\n",tp[0].v[0], tp[0].v[1], tp[0].v[2]);
+
+#ifdef NEVER /* Do locus lookup explicitly ? */
+ /* Lookup the locus for the auxiliary (Black) chanel */
+ if ((r = rss->rev_locus(rss,
+ auxm, /* auxm Auxiliary mask flags */
+ tp, /* Input and auxiliary values */
+ lmin, /* Locus min/max return values */
+ lmax
+ )) == 0) {
+ /* Rev locus failed - means that it will clip ? */
+ tp[0].p[3] = 0.5;
+ flags = RSPL_WILLCLIP; /* Since there was no locus, we expect to clip */
+ } else {
+ /* Set the auxiliary target */
+ tp[0].p[3] = (lmin[3] + lmax[3])/2.0;
+ flags = RSPL_EXACTAUX; /* Since we got locus, expect exact auxiliary match */
+ }
+#else
+ tp[0].p[3] = 0.5;
+ flags = RSPL_AUXLOCUS; /* Auxiliary target is proportion of locus */
+#endif /* NEVER */
+
+ /* Clip vector to 0.5 */
+ cvec[0] = 0.5 - tp[0].v[0];
+ cvec[1] = 0.5 - tp[0].v[1];
+ cvec[2] = 0.5 - tp[0].v[2];
+ cvec[3] = 0.5 - tp[0].v[3];
+
+ /* Do reverse interpolation */
+ if ((r = rss->rev_interp(rss,
+ flags, /* Hint flags */
+ NIP, /* Number of solutions allowed */
+ auxm, /* auxm Auxiliary mask flags */
+ cvec, /* cvec Clip vector direction & length */
+ tp) /* Input and output values */
+ ) == 0) {
+ error("rev_interp failed\n");
+ }
+
+ r &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (verb)
+ printf("Output 1 of %d: %f, %f, %f, %f%s\n",
+ r & RSPL_NOSOLNS, tp[0].p[0], tp[0].p[1], tp[0].p[2], tp[0].p[3],
+ (r & RSPL_DIDCLIP) ? " [Clipped]" : "");
+
+
+ if (rpsh_inc(&counter, ii))
+ break;
+
+ } /* Next grid point */
+
+ ttime = clock() - stime;
+ secs = (double)ttime/CLOCKS_PER_SEC;
+ printf("Done - %d ops in %f seconds, rate = %f ops/sec\n",ops, secs,ops/secs);
+#ifdef DOCHECK
+ for (j = 0; j < rcount; j++) {
+ if (check[j] != 1) {
+ printf("~~CHeck error at %d\n",j);
+ }
+ }
+#endif /* DOCHECK */
+ }
+
+ rss->del(rss);
+ return 0;
+}
+
+
+
+
+
+
diff --git a/rspl/rspl.c b/rspl/rspl.c
new file mode 100644
index 0000000..13a1776
--- /dev/null
+++ b/rspl/rspl.c
@@ -0,0 +1,1511 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized splines data fitter
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/1/00
+ *
+ * Copyright 1996 - 2004 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.
+ */
+
+/* Version that a combination of relaxation and conjugate gradient */
+/* solution techniques. */
+
+/* TTBD:
+
+ To save space, the full columns of A should only be allocated when needed ?
+ (Does this actually save much space for a realistic data sample set ?)
+
+ Get rid of error() calls - return status instead.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+
+#include "rspl_imp.h"
+#include "numlib.h"
+#include "counters.h" /* Counter macros */
+
+#undef DEBUG
+#undef DEBUGLU /* Debug fwd interpolation */
+#undef VERBOSE
+
+#undef NEVER
+#define ALWAYS
+
+#ifdef DEBUGLU
+# define DEBLU(xxxx) printf xxxx
+#else
+# define DEBLU(xxxx)
+#endif
+
+/* Implemeted in this file: */
+rspl *new_rspl(int flags, int di, int fdi);
+static void free_rspl(rspl *s);
+static void init_grid(rspl *s);
+static void free_grid(rspl *s);
+static void get_in_range(rspl *s, double *min, double *max);
+static void get_out_range(rspl *s, double *min, double *max);
+static void get_out_range_points(rspl *s, int *minp, int *maxp);
+static double get_out_scale(rspl *s);
+static unsigned int get_next_touch(rspl *s);
+static int within_restrictedsize(rspl *s);
+static int interp_rspl_sx(rspl *s, co *pp);
+static int part_interp_rspl_sx(rspl *s, co *p1, co *p2);
+static int interp_rspl_nl(rspl *s, co *p);
+int is_mono(rspl *s);
+static int set_rspl(rspl *s, int flags, void *cbctx,
+ void (*func)(void *cbctx, double *out, double *in),
+ datai glow, datai ghigh, int gres[MXDI], datao vlow, datao vhigh);
+static int re_set_rspl(struct _rspl *s, int flags, void *cbntx,
+ void (*func)(void *cbntx, double *out, double *in));
+static void scan_rspl(struct _rspl *s, int flags, void *cbntx,
+ void (*func)(void *cbntx, double *out, double *in));
+static void filter_rspl(struct _rspl *s, int flags, void *cbctx,
+ void (*func)(void *cbntx, float **out, double *in, int cvi));
+
+extern int add_rspl(rspl *s, int flags, co *d, int dno);
+extern void init_data(rspl *s);
+extern void free_data(rspl *s);
+
+/* Implemented in rev.c: */
+void init_rev(rspl *s);
+void free_rev(rspl *s);
+
+/* Implemented in gam.c: */
+void init_gam(rspl *s);
+void free_gam(rspl *s);
+
+/* Implemented in spline.c: */
+void init_spline(rspl *s);
+void free_spline(rspl *s);
+
+/* Implemented in opt.c: */
+int opt_rspl_imp(struct _rspl *s, int flags, int tdi, int adi, double **vdata,
+ double (*func)(void *fdata, double *inout, double *surav, int first, double *cw),
+ void *fdata, datai glow, datai ghigh, int gres[MXDI], datao vlow, datao vhigh);
+
+
+/* Convention is to use:
+ i to index grid points u.a
+ n to index data points d.a
+ e to index position dimension di
+ f to index output function dimension fdi
+ j misc and cube corners
+ k misc
+ */
+
+/* ================================ */
+/* Allocate an empty rspl object. */
+rspl *
+new_rspl(
+ int flags,
+ int di,
+ int fdi
+) {
+ rspl *s;
+
+#ifdef DEBUG
+ fprintf(stderr,"new_rspl with flags 0x%x, di %d, fdi %d\n",flags,di,fdi);
+#endif
+ /* Allocate a structure */
+ if ((s = (rspl *) calloc(1, sizeof(rspl))) == NULL)
+ error("rspl: malloc failed - main structure");
+
+ /* Set our fundamental parameters */
+ if (di < 1 || di > MXDI)
+ error("rspl: can't handle input dimension %d",di);
+ s->di = di;
+
+ if (fdi < 1 || fdi > MXDO)
+ error("rspl: can't handle output dimension %d",fdi);
+ s->fdi = fdi;
+
+ /* And appropriate flags */
+ if (flags & RSPL_VERBOSE) /* Turn on progress messages to stdout */
+ s->verbose = 1;
+ if (flags & RSPL_NOVERBOSE) /* Turn off progress messages to stdout */
+ s->verbose = 0;
+
+ /* Allocate space for cube offset arrays */
+ s->g.hi = s->g.a_hi;
+ s->g.fhi = s->g.a_fhi;
+ if ((1 << di) > DEF2MXDI) {
+ if ((s->g.hi = (int *) malloc(sizeof(int) * (1 << di))) == NULL)
+ error("rspl malloc failed - hi[]");
+ if ((s->g.fhi = (int *) malloc(sizeof(int) * (1 << di))) == NULL)
+ error("rspl malloc failed - fhi[]");
+ }
+
+ /* Init sub sections */
+ init_data(s);
+ init_grid(s);
+ init_rev(s);
+ init_gam(s);
+ init_spline(s);
+
+ if (flags & RSPL_FASTREVSETUP)
+ s->rev.fastsetup = 1;
+ else
+ s->rev.fastsetup = 0;
+
+ /* Set pointers to methods in this file */
+ s->del = free_rspl;
+ s->interp = interp_rspl_sx; /* Default to simplex interp */
+#ifdef NEVER
+#define USING_INTERP_NL
+printf("!!!! rspl.c using interp_rspl_nl !!!!");
+ s->interp = interp_rspl_nl;
+#endif
+ s->part_interp = part_interp_rspl_sx;
+ s->set_rspl = set_rspl;
+ s->scan_rspl = scan_rspl;
+ s->re_set_rspl = re_set_rspl;
+ s->opt_rspl = opt_rspl_imp;
+ s->filter_rspl = filter_rspl;
+ s->get_in_range = get_in_range;
+ s->get_out_range = get_out_range;
+ s->get_out_range_points = get_out_range_points;
+ s->get_out_scale = get_out_scale;
+ s->get_next_touch = get_next_touch;
+ s->within_restrictedsize = within_restrictedsize;
+
+ return s;
+}
+
+/* Free the rspl and all its contents */
+static void free_rspl(rspl *s) {
+ int e;
+
+ /* Free everying contained */
+ free_data(s); /* Free any scattered data */
+ free_rev(s); /* Free any reverse lookup data */
+ free_gam(s); /* Free any grid data */
+ free_grid(s); /* Free any grid data */
+
+ /* Free spline interpolation data ~~~~ */
+
+ /* Free structure */
+ for (e = 0; e < s->di; e++) {
+ if (s->g.ipos[e] != NULL)
+ free(s->g.ipos[e]);
+ }
+ if (s->g.hi != s->g.a_hi) {
+ free(s->g.hi);
+ free(s->g.fhi);
+ }
+ free((void *) s);
+}
+
+/* ======================================================== */
+/* Allocate rspl grid data, and initialise grid associated stuff */
+void
+alloc_grid(rspl *s) {
+ int di = s->di, fdi = s->fdi;
+ int e,g,i;
+ int gno; /* Number of points in grid */
+ ECOUNT(gc, MXDIDO, di, 0, s->g.res, 0);/* coordinates */
+ float *gp; /* Grid point pointer */
+
+#ifdef DEBUG
+ fprintf(stderr,"rspl allocating grid res %s\n",icmPiv(di, s->g.res));
+#endif
+
+ /* Compute total number of elements in the grid */
+ for (gno = 1, e = 0; e < di; gno *= s->g.res[e], e++)
+ ;
+ s->g.no = gno;
+
+ s->g.pss = fdi+G_XTRA; /* float for each output value + nme + flags */
+
+ /* Compute index coordinate increments into linear grid for each dimension */
+ /* ie. 1, gres, gres^2, gres^3 */
+ for (s->g.ci[0] = 1, e = 1; e < di; e++)
+ s->g.ci[e] = s->g.ci[e-1] * s->g.res[e-1]; /* In grid points */
+ for (e = 0; e < di; e++)
+ s->g.fci[e] = s->g.ci[e] * s->g.pss; /* In floats */
+
+ /* Compute index offsets from base of cube to other corners. */
+ for (s->g.hi[0] = e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++)
+ s->g.hi[g+i] = s->g.hi[i] + s->g.ci[e]; /* In grid points */
+ }
+ /* same as hi, but in floats */
+ for (i = 0; i < (1 << di); i++)
+ s->g.fhi[i] = s->g.hi[i] * s->g.pss; /* In floats */
+
+ /* Allocate space for grid */
+ if ((s->g.alloc = (float *) malloc(sizeof(float) * gno * s->g.pss)) == NULL)
+ error("rspl malloc failed - grid points");
+ s->g.a = s->g.alloc + G_XTRA; /* make -1 be nme, and -2 be (unsigned int) flags */
+
+ /* Set initial value of cell touch count */
+ s->g.touch = 0;
+
+ /* Init near edge flags, and touched flag */
+ EC_INIT(gc);
+ for (i = 0, gp = s->g.a; !EC_DONE(gc); i++, gp += s->g.pss) {
+ gp[-1] = L_UNINIT; /* Init Ink limit function value to -1e38 */
+ I_FL(gp); /* Init all flags to zero */
+ for (e = 0; e < di; e++) {
+ int e1,e2;
+ e1 = gc[e]; /* Dist to bottom edge */
+ e2 = (s->g.res[e]-1) - gc[e]; /* Dist to top edge */
+ if (e2 < e1) { /* Top edge is closer */
+ if (e2 > 2)
+ e2 = 2; /* Max dist = 2 */
+ S_FL(gp,e,e2); /* Set flag value */
+ } else { /* Bot edge is closer */
+ if (e1 > 2)
+ e1 = 2; /* Max dist = 2 */
+ S_FL(gp,e,e1 | 0x4); /* Set flag value */
+ }
+ }
+ TOUCHF(gp) = 0;
+
+ EC_INC(gc);
+ }
+ s->g.limitv_cached = 0; /* No limit values are current cached */
+}
+
+/* Init grid related elements of rspl */
+static void
+init_grid(rspl *s) {
+ s->g.alloc = NULL;
+}
+
+/* Free the grid allocation */
+static void
+free_grid(rspl *s) {
+ if (s->g.alloc != NULL)
+ free((void *)s->g.alloc);
+}
+
+/* ============================================ */
+/* Return the range of possible input values that the grid can represent */
+static void
+get_in_range(
+rspl *s, /* Grid to search */
+double *min, double *max /* Return min/max values */
+) {
+ int e;
+ for (e = 0; e < s->di; e++) {
+ min[e] = s->g.l[e];
+ max[e] = s->g.h[e];
+ }
+}
+
+/* ============================================ */
+/* Discover the range of possible output values */
+static void
+get_out_range(
+rspl *s, /* Grid to search */
+double *min, double *max /* Return min/max values */
+) {
+ float *gp,*ep; /* Grid pointer */
+ int f;
+
+ if (s->g.fminmax_valid == 0) { /* Not valid, so compute it */
+ for (f = 0; f < s->fdi; f++) {
+ s->g.fmin[f] = 1e30;
+ s->g.fmax[f] = -1e30;
+ s->g.fminx[f] = -1;
+ s->g.fmaxx[f] = -1;
+ }
+
+ /* Scan the Grid points for min/max values */
+ for (gp = s->g.a, ep = s->g.a + s->g.no * s->g.pss; gp < ep; gp += s->g.pss) {
+ for (f = 0; f < s->fdi; f++) {
+ if (s->g.fmin[f] > gp[f]) {
+ s->g.fmin[f] = gp[f];
+ s->g.fminx[f] = (gp - s->g.a)/s->g.pss;
+ }
+ if (s->g.fmax[f] < gp[f]) {
+ s->g.fmax[f] = gp[f];
+ s->g.fmaxx[f] = (gp - s->g.a)/s->g.pss;
+ }
+ }
+ }
+
+ /* Compute overall output scale */
+ for (s->g.fscale = 0.0, f = 0; f < s->fdi; f++) {
+ double tt = s->g.fmax[f] - s->g.fmin[f];
+ s->g.fscale += tt * tt;
+ }
+ s->g.fscale = sqrt(s->g.fscale);
+ s->g.fminmax_valid = 1; /* Now is valid */
+ }
+ for (f = 0; f < s->fdi; f++) {
+ if (min != NULL)
+ min[f] = s->g.fmin[f];
+ if (max != NULL)
+ max[f] = s->g.fmax[f];
+ }
+}
+
+/* ============================================ */
+/* return the grid index of the grid values at the min & max output values */
+static void get_out_range_points(rspl *s, int *minp, int *maxp) {
+ int f;
+
+ if (s->g.fminmax_valid == 0) /* Not valid, so compute it */
+ get_out_range(s, NULL, NULL);
+
+ for (f = 0; f < s->fdi; f++) {
+ if (minp != NULL)
+ minp[f] = s->g.fminx[f];
+ if (maxp != NULL)
+ maxp[f] = s->g.fmaxx[f];
+ }
+}
+
+/* ============================================ */
+/* Discover the csale of the output values */
+static double
+get_out_scale(rspl *s) {
+
+ if (s->g.fminmax_valid == 0) /* Not valid, so compute it */
+ get_out_range(s, NULL, NULL);
+
+ return s->g.fscale;
+}
+
+/* ============================================ */
+/* Return the next touched flag count value. */
+/* Whenever this rolls over, all the flags in the grid array will be reset. */
+/* */
+/* The touch flag is a way of some grid accessor (ie. rev()) making sure */
+/* that it doesn't access cells more than once for a particular operation, */
+/* without sorting a list of items to be accessed, or having to reset a */
+/* binary flag on all the cells for each operation. */
+/* If the value of a cells TOUCHF() is less than s->g.touch, then it hasn't */
+/* been accessed yet. Once the cell has been acessed, then TOUCHF() should */
+/* be set to s->g.touch. After 2^32 operations, the cell touch flags will */
+/* have been set to values between 0 and 2^32-1, so it is time to reset */
+/* all the flags. For that reason, the following method should be used */
+/* to get the next touch generation value at the start of each operation. */
+static unsigned int
+get_next_touch(
+rspl *s
+) {
+ unsigned int tg;
+ float *gp,*ep; /* Grid pointer */
+
+ if ((tg = ++s->g.touch) == 0) {
+
+ /* We have to reset all the cell flags to zero before we roll over */
+ for (gp = s->g.a, ep = s->g.a + s->g.no * s->g.pss; gp < ep; gp += s->g.pss) {
+ TOUCHF(gp) = 0;
+ }
+ tg = ++s->g.touch; /* return 1 */
+ }
+ return tg;
+}
+
+/* ============================================ */
+/* Return non-zero if this rspl can be */
+/* used with Restricted Size functions. */
+static int within_restrictedsize(
+rspl *s
+) {
+ if (s->di <= MXRI && s->fdi <= MXRO)
+ return 1;
+ return 0;
+}
+
+/* ============================================ */
+/* Do a forward interpolation using an simplex interpolation method. */
+/* Return 0 if OK, 1 if input was clipped to grid */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+// ~~999
+//int rspldb = 0;
+
+static int interp_rspl_sx(
+rspl *s,
+co *p /* Input value and returned function value */
+) {
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+ double we[MXDI]; /* Coordinate offset within the grid cell */
+ int si[MXDI]; /* we[] Sort index, [0] = smallest */
+ float *gp; /* Pointer to grid cube base */
+ int rv = 0; /* Register clip */
+
+ /* We are using a simplex (ie. tetrahedral for 3D input) interpolation. */
+
+ DEBLU(("In %s\n", icmPdv(di, p->p)));
+
+ /* Figure out which grid cell the point falls into */
+ {
+ gp = s->g.a; /* Base of grid array */
+ for (e = 0; e < di; e++) {
+ int gres_1 = s->g.res[e]-1;
+ double pe, t;
+ int mi;
+ pe = p->p[e];
+ if (pe < s->g.l[e]) { /* Clip to grid */
+ pe = s->g.l[e];
+ rv = 1;
+ }
+ if (pe > s->g.h[e]) {
+ pe = s->g.h[e];
+ rv = 1;
+ }
+ t = (pe - s->g.l[e])/s->g.w[e];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres_1)
+ mi = gres_1-1;
+ gp += mi * s->g.fci[e]; /* Add Index offset for grid cube base in dimen */
+ we[e] = t - (double)mi; /* 1.0 - weight */
+//if (rspldb && di == 3) printf("~1 e = %d, ix = %d, we = %f\n", e, mi, we[e]);
+ }
+ DEBLU(("ix %d, we %s\n", (gp - s->g.a)/s->g.pss, icmPdv(di, p->p)));
+ }
+
+ /* Do selection sort on coordinates */
+ {
+ for (e = 0; e < di; e++)
+ si[e] = e; /* Initial unsorted indexes */
+ for (e = 0; e < (di-1); e++) {
+ double cosn;
+ cosn = we[si[e]]; /* Current smallest value */
+ for (f = e+1; f < di; f++) { /* Check against rest */
+ int tt;
+ tt = si[f];
+ if (cosn > we[tt]) {
+ si[f] = si[e]; /* Exchange */
+ si[e] = tt;
+ cosn = we[tt];
+ }
+ }
+ }
+ }
+ DEBLU(("si[] = %s\n", icmPiv(di, si)));
+
+ /* Now compute the weightings, simplex vertices and output values */
+ {
+ double w; /* Current vertex weight */
+
+ w = 1.0 - we[si[di-1]]; /* Vertex at base of cell */
+ for (f = 0; f < fdi; f++)
+ p->v[f] = w * gp[f];
+
+ DEBLU(("ix %d: w %f * val %s\n", (gp - s->g.a)/s->g.pss, w, icmPfv(fdi,gp)));
+
+ for (e = di-1; e > 0; e--) { /* Middle verticies */
+ w = we[si[e]] - we[si[e-1]];
+ gp += s->g.fci[si[e]]; /* Move to top of cell in next largest dimension */
+ for (f = 0; f < fdi; f++)
+ p->v[f] += w * gp[f];
+ DEBLU(("ix %d: w %f * val %s\n", (gp - s->g.a)/s->g.pss, w, icmPfv(fdi,gp)));
+ }
+
+ w = we[si[0]];
+ gp += s->g.fci[si[0]]; /* Far corner from base of cell */
+ for (f = 0; f < fdi; f++)
+ p->v[f] += w * gp[f];
+ DEBLU(("ix %d: w %f * val %s\n", (gp - s->g.a)/s->g.pss, w, icmPfv(fdi,gp)));
+ DEBLU(("Outval %s\n", icmPdv(fdi, p->v)));
+ }
+ return rv;
+}
+
+/* ============================================ */
+/* Do forward (partial) interpolation to allow input & output curves to be applied, */
+/* and allow input delta E to be estimated from output delta E. */
+/* Call with input value in p1[0].p[], */
+/* In order smallest to largest weight: */
+/* Return di+1 vertex values in p1[]].v[] and */
+/* 0-1 sub-cell weight values as (p1[].p[0] - p1[].p[1]). */
+/* Optionally in input channel order: */
+/* Returns di+1 partial derivatives + base value in p2[].v[], */
+/* with matching weight values for each in p2[].p[0] (last weight = 1)*/
+/* Return 0 if OK, 1 if input was clipped to grid */
+static int part_interp_rspl_sx(
+struct _rspl *s, /* this */
+co *p1,
+co *p2 /* optional - return partial derivatives for each input channel */
+) {
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+ double we[MXDI]; /* Coordinate offset within the grid cell */
+ int si[MXDI]; /* we[] Sort index, [0] = smallest */
+ float *gp; /* Pointer to grid cube base */
+ int rv = 0; /* Register clip */
+
+ /* We are using a simplex (ie. tetrahedral for 3D input) interpolation. */
+
+ /* Figure out which grid cell the point falls into */
+ {
+ gp = s->g.a; /* Base of grid array */
+ for (e = 0; e < di; e++) {
+ int gres_1 = s->g.res[e]-1;
+ double pe, t;
+ int mi;
+ pe = p1[0].p[e];
+ if (pe < s->g.l[e]) { /* Clip to grid */
+ pe = s->g.l[e];
+ rv = 1;
+ }
+ if (pe > s->g.h[e]) {
+ pe = s->g.h[e];
+ rv = 1;
+ }
+ t = (pe - s->g.l[e])/s->g.w[e];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres_1)
+ mi = gres_1-1;
+ gp += mi * s->g.fci[e]; /* Add Index offset for grid cube base in dimen */
+ we[e] = t - (double)mi; /* 1.0 - weight */
+ }
+ }
+
+ /* Do selection sort on coordinates */
+ {
+ for (e = 0; e < di; e++)
+ si[e] = e; /* Initial unsorted indexes */
+ for (e = 0; e < (di-1); e++) {
+ double cosn;
+ cosn = we[si[e]]; /* Current smallest value */
+ for (f = e+1; f < di; f++) { /* Check against rest */
+ int tt;
+ tt = si[f];
+ if (cosn > we[tt]) {
+ si[f] = si[e]; /* Exchange */
+ si[e] = tt;
+ cosn = we[tt];
+ }
+ }
+ }
+ }
+ /* Now compute the vertex values that correspond */
+ /* to the input faction weightings + fixed value */
+ /* Scale the slopes + weights to make slopes */
+ /* valid as partial derivative of input values */
+ {
+
+ p1[di].p[0] = 1.0;
+ p1[di].p[1] = we[si[di-1]]; /* Vertex at base of cell */
+ for (f = 0; f < fdi; f++)
+ p1[di].v[f] = gp[f];
+
+ if (p2 != NULL) {
+ for (f = 0; f < fdi; f++)
+ p2[di].v[f] = gp[f]; /* Constant term @ vertex base */
+ p2[di].p[0] = 1.0;
+ }
+
+ for (e = di-1; e >= 0; e--) { /* Middle verticies to far vertex from base */
+ int ee = si[e];
+ float *lgp = gp; /* Last gp[] */
+
+ gp += s->g.fci[ee]; /* Move to top of cell in next largest dimension */
+
+ p1[e].p[0] = we[si[e]];
+ p1[e].p[1] = e > 0 ? we[si[e-1]] : 0.0;
+ for (f = 0; f < fdi; f++)
+ p1[e].v[f] = gp[f];
+
+ if (p2 != NULL) {
+ for (f = 0; f < fdi; f++)
+ p2[ee].v[f] = (gp[f] - lgp[f]) / s->g.w[ee];
+ p2[ee].p[0] = we[ee] * s->g.w[ee];
+ }
+ }
+ }
+ return rv;
+}
+
+#ifdef NEVER
+/* Test out part_interp_rspl_sx() */
+/* Designed to test with a CMYK->Lab lookup */
+static int interp_rspl_sx(
+rspl *s,
+co *p /* Input value and returned function value */
+) {
+ int rv, rv2;
+ int e, f, m;
+ co p1[MXDI+1];
+ co p2[MXDI+1];
+ co p3;
+ double v1[MXDO];
+ double v2[MXDO];
+
+ for (e = 0; e < s->di; e++) {
+ p1[0].p[e] = p->p[e];
+ p3.p[e] = p->p[e];
+ }
+
+ rv = _interp_rspl_sx(s, p);
+
+ if ((s->di != 4 || s->fdi != 3)
+ && (s->di != 3 || s->fdi != 4))
+ return rv;
+
+ rv2 = part_interp_rspl_sx(s, p1, p2);
+
+ /* Check interpolation values returned in p1 and p2 form */
+ for (f = 0; f < s->fdi; f++)
+ v1[f] = v2[f] = 0.0;
+
+ for (e = 0; e <= s->di; e++) {
+ for (f = 0; f < s->fdi; f++) {
+ /* We could converts p1[].p[0] and p1[].p[1] through sub curve lookup, */
+ /* and p1[].v[] though inverse output curve lookup, */
+ /* then convert v1[] through output curve lookup. */
+ v1[f] += p1[e].v[f] * (p1[e].p[0] - p1[e].p[1]);
+
+ /* v2 is using base + partial derivatives */
+ v2[f] += p2[e].v[f] * p2[e].p[0];
+ }
+ }
+
+ if (s->di == 4) {
+ printf("~1 %f %f %f %f ->\n",p->p[0], p->p[1], p->p[2], p->p[3]);
+ printf("~1 ref %d -> %f %f %f\n", rv, p->v[0], p->v[1], p->v[2]);
+ printf("~1 check1 %d -> %f %f %f\n", rv2, v1[0], v1[1], v1[2]);
+ printf("~1 check2 %d -> %f %f %f\n", rv2, v2[0], v2[1], v2[2]);
+ } else {
+ printf("~1 %f %f %f ->\n",p->p[0], p->p[1], p->p[2]);
+ printf("~1 ref %d -> %f %f %f %f\n", rv, p->v[0], p->v[1], p->v[2], p->v[3]);
+ printf("~1 check1 %d -> %f %f %f %f\n", rv2, v1[0], v1[1], v1[2], v1[3]);
+ printf("~1 check2 %d -> %f %f %f %f\n", rv2, v2[0], v2[1], v2[2], v2[3]);
+ }
+
+ /* Check partial derivs in p2 */
+ for (m = 0; m < s->di; m++) {
+
+ p3.p[m] += 1e-5;
+
+ _interp_rspl_sx(s, &p3);
+ for (f = 0; f < s->fdi; f++)
+ p3.v[f] = (p3.v[f] - p->v[f])/1e-5;
+
+ if (s->di == 4) {
+ printf("~1 deriv %d:\n", m);
+ printf("~1 ref del %f %f %f\n", p3.v[0], p3.v[1], p3.v[2]);
+ printf("~1 check del %f %f %f\n", p2[m].v[0], p2[m].v[1], p2[m].v[2]);
+ } else {
+ printf("~1 deriv %d:\n", m);
+ printf("~1 ref del %f %f %f %f\n", p3.v[0], p3.v[1], p3.v[2], p3.v[3]);
+ printf("~1 check del %f %f %f %f\n", p2[m].v[0], p2[m].v[1], p2[m].v[2], p2[m].v[3]);
+ }
+
+ p3.p[m] -= 1e-5;
+ }
+
+ return rv;
+}
+#endif
+
+/* ============================================ */
+
+#ifdef USING_INTERP_NL
+/* Alternate, not currently used */
+/* Do a forward interpolation using an n-linear method. */
+/* Return 0 if OK, 1 if input was clipped to grid */
+/* Alternative to interp_rspl_sx */
+static int interp_rspl_nl(
+rspl *s,
+co *p /* Input value and returned function value */
+) {
+ int e, di = s->di;
+ int f, fdi = s->fdi;
+ double we[MXDI]; /* 1.0 - Weight in each dimension */
+ double *gw; /* weight for each grid cube corner */
+ double a_gw[DEF2MXDI]; /* Default space for gw */
+ float *gp; /* Pointer to grid cube base */
+ int rv = 0;
+
+ gw = a_gw;
+ if ((1 << di) > DEF2MXDI) {
+ if ((gw = (double *) malloc(sizeof(double) * (1 << di))) == NULL)
+ error("rspl malloc failed - interp_rspl_nl");
+ }
+ /* Figure out which grid cell the point falls into */
+ {
+ gp = s->g.a; /* Base of grid array */
+ for (e = 0; e < di; e++) {
+ int gres_1 = s->g.res[e]-1;
+ double pe, t;
+ int mi;
+ pe = p->p[e];
+ if (pe < s->g.l[e]) { /* Clip to grid */
+ pe = s->g.l[e];
+ rv = 1;
+ }
+ if (pe > s->g.h[e]) {
+ pe = s->g.h[e];
+ rv = 1;
+ }
+ t = (pe - s->g.l[e])/s->g.w[e];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres_1)
+ mi = gres_1-1;
+ gp += mi * s->g.fci[e]; /* Add Index offset for grid cube base in dimen */
+ we[e] = t - (double)mi; /* 1.0 - weight */
+ }
+ }
+
+ /* Compute corner weights needed for interpolation */
+ {
+ int i, g;
+ gw[0] = 1.0;
+ for (e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * we[e];
+ gw[i] *= (1.0 - we[e]);
+ }
+ }
+ }
+
+ /* Now compute the output values */
+ {
+ int i;
+ double w = gw[0];
+ float *d = gp + s->g.fhi[0];
+ for (f = 0; f < fdi; f++) /* Base of cube */
+ p->v[f] = w * d[f];
+
+ for (i = 1; i < (1 << di); i++) { /* For all other corners of cube */
+ double w = gw[i]; /* Strength reduce */
+ float *d = gp + s->g.fhi[i];
+ for (f = 0; f < fdi; f++)
+ p->v[f] += w * d[f];
+ }
+
+ }
+
+ if (gw != a_gw)
+ free(gw);
+
+ return rv;
+}
+#endif /* USING_INTERP_NL */
+
+/* ============================================ */
+/* Non-mono calculations */
+/* Compute non-monotonicity factor for each grid point, and */
+/* return non-zero if the overall grid is monotonic. */
+/* (Note that this is not a true non-monotonicity test. */
+/* A true test has to deal with PCS combination values.) */
+int
+is_mono(
+rspl *s
+) {
+ int f;
+ int di = s->di;
+ int fdi = s->fdi;
+ int *fci = s->g.fci; /* Strength reduction */
+ float *gp, *ep;
+ double mcinc = MCINC/(s->g.mres-1); /* Scaled version of MCINC */
+ double min = 1e20; /* Minimum clearance found */
+
+ /* Find the minimum step between grid points */
+ for (gp = s->g.a, ep = s->g.a + s->g.no * s->g.pss; gp < ep; gp += s->g.pss) {
+ for (f = 0; f < fdi; f++) {
+ int e;
+ double e1,e2; /* Smallest/largest surrounting point */
+ double u; /* Current output value we are considering */
+ double ce; /* nm error */
+
+ /* Find smallest and largest surrounding points */
+ /* In +/- 1 dimension directions */
+ e1 = 1e20; e2 = -1e20;
+ for (e = 0; e < di; e++) {
+ int dof; /* Double offset */
+ float vv;
+
+ if ((G_FL(gp,e) & 3) < 1)
+ break; /* Skip to next grid point if on edge */
+ dof = fci[e];
+ vv = gp[f + dof];
+ if (vv < e1)
+ e1 = vv;
+ if (vv > e2)
+ e2 = vv;
+ vv = gp[f - dof];
+ if (vv < e1)
+ e1 = vv;
+ if (vv > e2)
+ e2 = vv;
+ }
+ if (e < di) /* We broke because we are on the edge */
+ continue;
+
+ u = gp[f];
+
+ e1 = u - e1;
+ e2 = e2 - u;
+ ce = (e1 < e2 ? e1 : e2); /* Smallest step */
+
+ if (ce < min) /* Current smallest step */
+ min = ce;
+ }
+ }
+//if (min < mcinc) printf("~1 is_mono failed by %e < %e\n",min,mcinc);
+ return min < mcinc;
+}
+
+/* ============================================ */
+/* Initialize the grid from a provided function. By default the grid */
+/* values are set to exactly the value returned fy func(), unless the */
+/* RSPL_SET_APXLS flag is set, in which case an attempt is made to have */
+/* the grid points represent a least squares aproximation to the underlying */
+/* surface, by using extra samples in the middle of grid cells. */
+/* RSPL_SET_APXLS tends to improve the fit to the underlying function. */
+/* Grid index values are supplied "under" in[] at *((int*)&iv[-e-1]), */
+/* but if RSPL_SET_APXLS is set, the grid index will be the base of */
+/* the cell the center point is sampled from every second sample. */
+/* Return non-monotonic status */
+static int set_rspl(
+ struct _rspl *s,/* this */
+ int flags, /* Combination of flags */
+ void *cbctx, /* Opaque function context */
+ void (*func)(void *cbctx, double *out, double *in), /* Function to set from */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution for each dimension */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh /* Data value high normalize - NULL = default 1.0 */
+) {
+ int e, f, j;
+ rpsh counter; /* Pseudo-hilbert counter */
+ int gc[MXDI]; /* Grid index value */
+ float *gp; /* Pointer to grid data */
+ float *cc = NULL; /* Pointer to cell center data */
+ double _iv[2 * MXDI], *iv = &_iv[MXDI]; /* Real index value/table value */
+ double ov[MXDO];
+
+ if (flags & RSPL_VERBOSE) /* Turn on progress messages to stdout */
+ s->verbose = 1;
+ if (flags & RSPL_NOVERBOSE) /* Turn off progress messages to stdout */
+ s->verbose = 0;
+
+ /* transfer desired grid range to structure */
+ s->g.mres = 1.0;
+ s->g.bres = 0;
+ for (e = 0; e < s->di; e++) {
+
+ if (gres[e] < 2)
+ error("rspl: grid res must be >= 2!");
+ s->g.res[e] = gres[e]; /* record the desired resolution of the grid */
+ s->g.mres *= gres[e];
+ if (gres[e] > s->g.bres) {
+ s->g.bres = gres[e];
+ s->g.brix = e;
+ }
+
+ if (glow == NULL)
+ s->g.l[e] = 0.0;
+ else
+ s->g.l[e] = glow[e];
+
+ if (ghigh == NULL)
+ s->g.h[e] = 1.0;
+ else
+ s->g.h[e] = ghigh[e];
+
+ /* compute width of each grid cell */
+ s->g.w[e] = (s->g.h[e] - s->g.l[e])/(double)(s->g.res[e]-1);
+
+ /* ?? Should h be recomputed as (l + gres-1) * w ?? */
+ }
+ s->g.mres = pow(s->g.mres, 1.0/e); /* geometric mean */
+
+ /* record low and width data normalizing factors */
+ for (f = 0; f < s->fdi; f++) {
+ if (vlow == NULL)
+ s->d.vl[f] = 0.0;
+ else
+ s->d.vl[f] = vlow[f];
+
+ if (vhigh == NULL)
+ s->d.vw[f] = 1.0 - s->d.vl[f];
+ else
+ s->d.vw[f] = vhigh[f] - s->d.vl[f];
+ }
+
+ /* Allocate the grid data */
+ alloc_grid(s);
+
+ /* Allocate space for cell center value lookup */
+ if (flags & RSPL_SET_APXLS) {
+ if ((cc = (float *)malloc(sizeof(float) * s->g.no * s->fdi)) == NULL)
+ error("rspl malloc failed - center cell points");
+ }
+
+ /* Reset output min/max */
+ for (f = 0; f < s->fdi; f++) {
+ s->g.fmin[f] = 1e30;
+ s->g.fmax[f] = -1e30;
+ s->g.fminx[f] = -1;
+ s->g.fmaxx[f] = -1;
+ }
+
+ /* Set the grid points value from the provided function */
+
+ /* To make this clut function cache friendly, we use the pseudo-hilbert */
+ /* count sequence. This keeps each point close to the last in the */
+ /* multi-dimensional space. */
+ rpsh_init(&counter, s->di, (unsigned int *)gres, gc); /* Initialise counter */
+ for (;;) {
+
+ /* Compute grid pointer and input sample values */
+ gp = s->g.a; /* Base of grid data */
+ for (e = 0; e < s->di; e++) { /* Input tables */
+ gp += gc[e] * s->g.fci[e]; /* Grid value pointer */
+ iv[e] = s->g.l[e] + gc[e] * s->g.w[e]; /* Input sample values */
+ *((int *)&iv[-e-1]) = gc[e]; /* Trick to supply grid index in iv[] */
+ }
+
+ /* Apply incolor -> outcolor function we want to represent */
+ func(cbctx, ov, iv);
+
+ for (f = 0; f < s->fdi; f++) { /* Output chans */
+ gp[f] = (float)ov[f]; /* Set output value */
+ if (s->g.fmin[f] > gp[f]) {
+ s->g.fmin[f] = gp[f];
+ s->g.fminx[f] = (gp - s->g.a)/s->g.pss;
+ }
+ if (s->g.fmax[f] < gp[f]) {
+ s->g.fmax[f] = gp[f];
+ s->g.fmaxx[f] = (gp - s->g.a)/s->g.pss;
+ }
+ }
+
+ /* For RSPL_SET_APXLS, get the center of the cell values as well. */
+ if (cc != NULL) {
+ float *ccp;
+
+ ccp = cc;
+ for (e = 0; e < s->di; e++) { /* Input tables */
+ if (gc[e] >= (gres[e]-1))
+ break; /* No center for outer row */
+ iv[e] = s->g.l[e] + (gc[e] + 0.5) * s->g.w[e]; /* Input sample values */
+ ccp += gc[e] * s->g.ci[e] * s->fdi; /* cc location */
+ }
+
+ if (e >= s->di) { /* Not outer row */
+ /* Apply incolor -> outcolor function we want to represent */
+ func(cbctx, ov, iv);
+
+ for (f = 0; f < s->fdi; f++) { /* Output chans */
+ ccp[f] = (float)ov[f]; /* Set output value */
+ }
+ }
+ }
+
+ /* Increment counter */
+ if (rpsh_inc(&counter, gc))
+ break;
+ }
+
+ /* For RSPL_SET_APXLS, deal with cell center value, aproximate least squares adjustment */
+ if (cc != NULL) {
+ int ee;
+ double cw = 1.0/(double)(1 << s->di); /* Weight for each cube corner */
+ float *ccp;
+
+ for (e = 0; e < s->di; e++)
+ gc[e] = 0; /* init coords */
+
+ /* Compute linear interpolated error to actual cell center value */
+ for (ee = 0; ee < s->di;) {
+
+ gp = s->g.a; /* Base of grid data */
+ ccp = cc; /* Base of center data */
+ for (e = 0; e < s->di; e++) { /* Input tables */
+ gp += gc[e] * s->g.fci[e]; /* Grid value pointer */
+ ccp += gc[e] * s->g.ci[e] * s->fdi; /* cc location */
+ }
+
+ for (f = 0; f < s->fdi; f++) { /* Output chans */
+ double sum = 0.0;
+
+ for (j = 0; j < (1 << s->di); j++) /* For corners of cube */
+ sum += (gp + s->g.fhi[j])[f];
+ sum *= cw; /* Interpolated value */
+ ccp[f] -= sum; /* Correction to actual value */
+
+ /* Average half the error to cube corners */
+ ccp[f] *= 0.5 * cw; /* Distribution fraction */
+ }
+
+ /* Increment coord */
+ for (ee = 0; ee < s->di; ee++) {
+ if (++gc[ee] < (gres[ee]-1)) /* Don't go through upper edge */
+ break; /* No carry */
+ gc[ee] = 0;
+ }
+ }
+
+ for (e = 0; e < s->di; e++)
+ gc[e] = 0; /* init coords */
+
+ /* Distribute the center error to the cell corners */
+ for (ee = 0; ee < s->di;) {
+
+ gp = s->g.a; /* Base of grid data */
+ ccp = cc; /* Base of center data */
+ for (e = 0; e < s->di; e++) { /* Input tables */
+ gp += gc[e] * s->g.fci[e]; /* Grid value pointer */
+ ccp += gc[e] * s->g.ci[e] * s->fdi; /* cc location */
+ }
+
+ for (j = 0; j < (1 << s->di); j++) { /* For corners of cube */
+ double sc = 1.0; /* Scale factor for non-edge nodes */
+
+ /* Don't distribute error to edge nodes since there may */
+ /* an expectation that they have precicely set values */
+ /* (ie. white and black points) */
+ for (e = 0; e < s->di; e++) {
+ if ((gc[e] == 0 && (j & (1 << e)) == 0)
+ || (gc[e] == ((gres[e]-2)) && (j & (1 << e)) != 0))
+ sc *= 0.0;
+ }
+
+ for (f = 0; f < s->fdi; f++) { /* Output chans */
+ double vv;
+ vv = (gp + s->g.fhi[j])[f]; /* Current value */
+ vv += sc * cc[f]; /* Correction */
+ (gp + s->g.fhi[j])[f] = vv;
+ if (s->g.fmin[f] > vv) {
+ s->g.fmin[f] = vv;
+ s->g.fminx[f] = (gp + s->g.fhi[j] - s->g.a)/s->g.pss;
+ }
+ if (s->g.fmax[f] < vv) {
+ s->g.fmax[f] = vv;
+ s->g.fmaxx[f] = (gp + s->g.fhi[j] - s->g.a)/s->g.pss;
+ }
+ }
+ }
+
+ /* Increment coord */
+ for (ee = 0; ee < s->di; ee++) {
+ if (++gc[ee] < (gres[ee]-1)) /* Don't go through upper edge */
+ break; /* No carry */
+ gc[ee] = 0;
+ }
+ }
+
+ free((void *)cc);
+ }
+
+ /* Compute overall output scale */
+ for (s->g.fscale = 0.0, f = 0; f < s->fdi; f++) {
+ double tt = s->g.fmax[f] - s->g.fmin[f];
+ s->g.fscale += tt * tt;
+ }
+ s->g.fscale = sqrt(s->g.fscale);
+
+ s->g.fminmax_valid = 1; /* Now is valid */
+
+ /* Return non-mono check */
+ return is_mono(s);
+}
+
+/* ============================================ */
+/* Scan or change each grid point in the rspl. */
+static int scan_set_rspl(
+struct _rspl *s, /* this */
+int flags, /* Combination of flags */
+void *cbctx, /* Opaque function context */
+void (*func)(void *cbntx, double *out, double *in), /* Function to get/set from */
+int change /* Flag - nz means change values, 0 means scan values */
+) {
+ int e, f;
+ rpsh counter; /* Pseudo-hilbert counter */
+ int gc[MXDI]; /* Grid index value */
+ float *gp; /* Pointer to grid data */
+ double _iv[2 * MXDI], *iv = &_iv[MXDI]; /* Real index value/table value */
+ double ov[MXDO];
+
+ if (flags & RSPL_VERBOSE) /* Turn on progress messages to stdout */
+ s->verbose = 1;
+ if (flags & RSPL_NOVERBOSE) /* Turn off progress messages to stdout */
+ s->verbose = 0;
+
+ if (change) {
+ /* Reset output min/max */
+ for (f = 0; f < s->fdi; f++) {
+ s->g.fmin[f] = 1e30;
+ s->g.fmax[f] = -1e30;
+ s->g.fminx[f] = -1;
+ s->g.fmaxx[f] = -1;
+ }
+ }
+
+ /* Set the grid points value from the provided function */
+ /* Give the function both the grid position and the existing output values */
+
+ /* To make this clut function cache friendly, we use the pseudo-hilbert */
+ /* count sequence. This keeps each point close to the last in the */
+ /* multi-dimensional space. */
+ rpsh_init(&counter, s->di, (unsigned int *)s->g.res, gc); /* Initialise counter */
+ for (;;) {
+
+ /* Compute grid pointer and input sample values */
+ gp = s->g.a; /* Base of grid data */
+ for (e = 0; e < s->di; e++) { /* Input tables */
+ gp += s->g.fci[e] * gc[e]; /* Grid value pointer */
+ iv[e] = s->g.l[e] + gc[e] * s->g.w[e]; /* Input sample values */
+ *((int *)&iv[-e-1]) = gc[e]; /* Trick to supply grid index in iv[] */
+ }
+
+ for (f = 0; f < s->fdi; f++) /* Output chans */
+ ov[f] = gp[f];
+
+ /* Let function scan the input and output values, or */
+ /* Apply incolor -> outcolor, or oldoutcolor->outcolor function we want to represent */
+ func(cbctx, ov, iv);
+
+ if (change) { /* Put new output values back */
+ for (f = 0; f < s->fdi; f++) { /* Output chans */
+ gp[f] = (float)ov[f];
+ if (s->g.fmin[f] > gp[f]) {
+ s->g.fmin[f] = gp[f];
+ s->g.fminx[f] = (gp - s->g.a)/s->g.pss;
+ }
+ if (s->g.fmax[f] < gp[f]) {
+ s->g.fmax[f] = gp[f];
+ s->g.fmaxx[f] = (gp - s->g.a)/s->g.pss;
+ }
+ }
+ }
+
+ /* Increment counter */
+ if (rpsh_inc(&counter, gc))
+ break;
+ }
+
+ if (change == 0) {
+ return 0;
+ }
+
+ /* Compute overall output scale */
+ for (s->g.fscale = 0.0, f = 0; f < s->fdi; f++) {
+ double tt = s->g.fmax[f] - s->g.fmin[f];
+ s->g.fscale += tt * tt;
+ }
+ s->g.fscale = sqrt(s->g.fscale);
+
+ s->g.fminmax_valid = 1; /* Now is valid */
+
+ /* Invalidate various things */
+ free_data(s); /* Free any scattered data */
+ free_rev(s); /* Free any reverse lookup data */
+
+ /* Return non-mono check */
+ return is_mono(s);
+}
+
+/* Re-initialize the grid from existing grid values, and the provided function */
+/* Grid index values are supplied "under" in[] at *((int*)&iv[-e-1]) */
+/* Return non-monotonic status. We assume that the ouput scale factors don't change. */
+static int re_set_rspl(
+struct _rspl *s, /* this */
+int flags, /* Combination of flags */
+void *cbctx, /* Opaque function context */
+void (*func)(void *cbntx, double *out, double *in) /* Function to set from */
+) {
+ return scan_set_rspl(s, flags, cbctx, func, 1);
+}
+
+/* Scan the rspl grid point locations and values. Grid index values are */
+/* supplied "under" in[] *((int*)&iv[-e-1]) */
+static void scan_rspl(
+struct _rspl *s, /* this */
+int flags, /* Combination of flags */
+void *cbctx, /* Opaque function context */
+void (*func)(void *cbntx, double *out, double *in) /* Function to get from */
+) {
+ scan_set_rspl(s, flags, cbctx, func, 0);
+}
+
+
+/* ============================================ */
+/* Allow the grid values to be filtered. */
+/* For each grid value, provide the input value and */
+/* pointers to all the output values in a 3^di grid around */
+/* the output value. Pointers will be NULL if neigbour is outside */
+/* the grid. cvi is the index of the output value. */
+/* Grid index values are supplied "under" in[] at *((int*)&iv[-e-1]) */
+/* After all the grid values have been done, they will be updated */
+/* with their new values. */
+static void filter_rspl(
+struct _rspl *s, /* this */
+int flags, /* Combination of flags */
+void *cbctx, /* Opaque function context */
+void (*func)(void *cbntx, float **out, double *in, int cvi) /* Function to set from */
+) {
+ int e, f;
+ ECOUNT(gc, MXDIDO, s->di, 0, s->g.res, 0); /* coordinates */
+ DCOUNT(cc, MXDIDO, s->di, -1, -1, 2); /* Surrounding cube counter */
+ float *gp, *ep; /* Pointer to grid data */
+ float *tarry, *tp; /* Temporary array of values */
+ double _iv[2 * MXDI], *iv = &_iv[MXDI]; /* Real index value/table value */
+ int cvi; /* Center value index = 3^di-1)/2 */
+ int pow3di = 1;
+ float **svals; /* Pointer to surrounding output values */
+ float *a_svals[DEF3MXDI];/* default allocation for svals */
+
+ if (flags & RSPL_VERBOSE) /* Turn on progress messages to stdout */
+ s->verbose = 1;
+ if (flags & RSPL_NOVERBOSE) /* Turn off progress messages to stdout */
+ s->verbose = 0;
+
+ /* Allocate svals array */
+ svals = a_svals;
+ for (e = 0; e < s->di; e++)
+ pow3di *= 3;
+ if (pow3di > DEF3MXDI) {
+ if ((svals = (float **) malloc(sizeof(float *) * pow3di)) == NULL)
+ error("rspl malloc failed - filter_rspl");
+ }
+
+ /* Compute the center value index */
+ for (cvi = 1, e = 0; e < s->di; e++)
+ cvi *= 3;
+ cvi = (cvi-1)/2;
+
+ /* Allocate a temporary array for the new output values */
+ if ((tarry = (float *)malloc(sizeof(float) * s->g.no * s->fdi)) == NULL) {
+ if (svals != a_svals)
+ free(svals);
+ error("rspl malloc failed - filter_rspl array");
+ }
+
+ /* Set the grid points value from the provided function */
+ /* Give the function both the grid position and the existing output values */
+ /* in the 3x3 surrounding grid */
+ EC_INIT(gc);
+ for (tp = tarry; !EC_DONE(gc); tp += s->fdi) {
+ int i;
+
+ /* Compute grid pointer and input sample values */
+ for (e = 0; e < s->di; e++) {
+ iv[e] = s->g.l[e] + gc[e] * s->g.w[e]; /* Input sample values */
+ *((int *)&iv[-e-1]) = gc[e]; /* Trick to supply grid index in iv[] */
+ }
+
+ /* Set pointers to 3x3 surrounders */
+ DC_INIT(cc)
+ for (i = 0; !DC_DONE(cc); i++ ) {
+ float *sp = s->g.a;
+
+ for (e = 0; e < s->di; e++) { /* Input tables */
+ int j;
+ j = gc[e] + cc[e];
+ if (j < 0 || j >= s->g.res[e]) {
+ sp = NULL; /* outside grid */
+ break;
+ }
+ sp += s->g.fci[e] * j; /* Compute pointer to surrounder */
+ }
+
+ svals[i] = sp;
+ DC_INC(cc);
+ }
+
+ for (f = 0; f < s->fdi; f++) /* Set default no change new values */
+ tp[f] = svals[cvi][f];
+ svals[cvi] = tp; /* Make sure output value goes into temp array */
+
+ /* Apply incolor -> outcolor, or oldoutcolor->outcolor function we want to represent */
+ func(cbctx, svals, iv, cvi);
+
+ EC_INC(gc);
+ }
+
+ /* Reset output min/max */
+ for (f = 0; f < s->fdi; f++) {
+ s->g.fmin[f] = 1e30;
+ s->g.fmax[f] = -1e30;
+ s->g.fminx[f] = -1;
+ s->g.fmaxx[f] = -1;
+ }
+
+ /* Now update all the values */
+ for (tp = tarry, gp = s->g.a, ep = s->g.a + s->g.no * s->g.pss;
+ gp < ep; gp += s->g.pss, tp += s->fdi) {
+
+ for (f = 0; f < s->fdi; f++) /* Output chans */
+ gp[f] = tp[f];
+
+ for (f = 0; f < s->fdi; f++) { /* Output chans */
+ if (s->g.fmin[f] > gp[f]) {
+ s->g.fmin[f] = gp[f];
+ s->g.fminx[f] = (gp - s->g.a)/s->g.pss;
+ }
+ if (s->g.fmax[f] < gp[f]) {
+ s->g.fmax[f] = gp[f];
+ s->g.fmaxx[f] = (gp - s->g.a)/s->g.pss;
+ }
+ }
+ }
+
+ /* Compute overall output scale */
+ for (s->g.fscale = 0.0, f = 0; f < s->fdi; f++) {
+ double tt = s->g.fmax[f] - s->g.fmin[f];
+ s->g.fscale += tt * tt;
+ }
+ s->g.fscale = sqrt(s->g.fscale);
+
+ s->g.fminmax_valid = 1; /* Now is valid */
+
+ if (svals != a_svals)
+ free(svals);
+ free(tarry);
+
+ /* Invalidate various things */
+ free_data(s); /* Free any scattered data */
+ free_rev(s); /* Free any reverse lookup data */
+}
+
+
+/* =============================================== */
+/* Utility function */
+/* Pseudo - Hilbert count sequencer */
+
+/* Initialise, returns total usable count */
+unsigned rpsh_init(
+rpsh *p, /* Pointer to structure to initialise */
+int di, /* Dimensionality */
+unsigned int *res, /* Size per coordinate */
+int co[] /* Coordinates to initialise (May be NULL) */
+) {
+ int e;
+
+ p->di = di;
+ p->tbits = 0;
+ for (e = 0; e < di; e++) {
+ p->res[e] = res[e];
+
+ /* Compute bits */
+ for (p->bits[e] = 0; (1u << p->bits[e]) < res[e]; p->bits[e]++)
+ ;
+ p->tbits += p->bits[e];
+ }
+
+ /* Compute the total count mask */
+ p->tmask = ((((unsigned)1) << p->tbits)-1);
+
+ /* Compute usable count */
+ p->count = 1;
+ for (e = 0; e < di; e++)
+ p->count *= res[e];
+
+ /* Reset the counter */
+ p->ix = 0;
+
+ if (co != NULL) {
+ for (e = 0; e < di; e++)
+ co[e] = 0;
+ }
+ return p->count;
+}
+
+
+/* Reset the counter */
+void rpsh_reset(
+rpsh *p /* Pointer to structure */
+) {
+ p->ix = 0;
+}
+
+
+/* Increment pseudo-hilbert coordinates */
+/* Return non-zero if count rolls over to 0 */
+int rpsh_inc(
+rpsh *p, /* Pointer to structure */
+int coa[] /* Coordinates to return */
+) {
+ int di = p->di;
+ int e;
+
+ do {
+ unsigned int b, tb;
+ int gix; /* Gray code index */
+
+ p->ix = (p->ix + 1) & p->tmask;
+
+ gix = p->ix ^ (p->ix >> 1); /* Convert to gray code index */
+
+ for (e = 0; e < di; e++)
+ coa[e] = 0;
+
+ for (b = tb = 0; tb < p->tbits ; b++) { /* Distribute bits */
+ if (b & 1) {
+ for (e = di-1; e >= 0; e--) { /* In reverse coord order */
+ if (b < p->bits[e]) {
+ coa[e] |= (gix & 1) << b; /* ls bits of gix */
+ gix >>= 1;
+ tb++;
+ }
+ }
+ } else {
+ for (e = 0; e < di; e++) { /* In normal coord order */
+ if (b < p->bits[e]) {
+ coa[e] |= (gix & 1) << b; /* ls bits of gix */
+ gix >>= 1;
+ tb++;
+ }
+ }
+ }
+ }
+
+ /* Convert from Gray to binary coordinates */
+ for (e = 0; e < di; e++) {
+ unsigned sh, tv;
+
+ for(sh = 1, tv = coa[e];; sh <<= 1) {
+ unsigned ptv = tv;
+ tv ^= (tv >> sh);
+ if (ptv <= 1 || sh == 16)
+ break;
+ }
+ if (tv >= p->res[e]) /* Dumbo filter - increment again if outside cube range */
+ break;
+ coa[e] = tv;
+ }
+
+ } while (e < di);
+
+ return (p->ix == 0);
+}
+
+/* =============================================== */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rspl/rspl.h b/rspl/rspl.h
new file mode 100644
index 0000000..5bccba7
--- /dev/null
+++ b/rspl/rspl.h
@@ -0,0 +1,645 @@
+#ifndef RSPL_H
+#define RSPL_H
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized spline data structure
+ *
+ * Author: Graeme W. Gill
+ * Date: 2000/10/29
+ *
+ * Copyright 1996 - 2004 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.
+ */
+
+#include "numsup.h"
+
+/** Configuration **/
+
+/** General Limits **/
+
+#define MXDI 10 /* Maximum input dimensionality */
+#define MXDO 10 /* Maximum output dimensionality (Is not fully tested!!!) */
+#define LOG2MXDI 4 /* log2 MXDI */
+#define DEF2MXDI 16 /* Default allocation size for 2^di (di=4) */
+#define POW2MXDI 1024 /* 2 ^ MXDI */
+#define DEF3MXDI 81 /* Default allocation size for 3^di (di=4) */
+#define POW3MXDI 59049 /* 3 ^ MXDI */
+
+#if MXDI > MXDO /* Maximum of either DI or DO */
+# define MXDIDO MXDI
+#else
+# define MXDIDO MXDO
+#endif
+
+/* RESTRICTED SIZE Limits, used for reverse, spline and scattered interpolation */
+
+#define MXRI 4 /* Maximum input dimensionality */
+#define MXRO 10 /* Maximum output dimensionality (Is not fully tested!!!) */
+#define LOG2MXRI 2 /* log2 MXRI */
+#define POW2MXRI 16 /* 2 ^ MXRI */
+#define POW3MXRI 81 /* 3 ^ MXRI */
+#define HACOMPS ((POW3MXRI + 2 * MXRI + 1)/2) /* Maximum number of array components */
+
+#if MXRI > MXRO /* Maximum of either RI or RO */
+# define MXRIRO MXRI
+#else
+# define MXRIRO MXRO
+#endif
+
+
+/** Definitions **/
+
+/* General data point position/value structure */
+/* This is mean't to be compatible with color structure */
+/* when MXDI and MXDO == 4 */
+typedef double datai[MXDI];
+typedef double datao[MXDO];
+typedef float dati[MXDI];
+typedef float dato[MXDO];
+
+/* Restricted size versions */
+typedef double ratai[MXRI];
+typedef double ratao[MXRO];
+typedef float rati[MXRI];
+typedef float rato[MXRO];
+
+/* Interface coordinate value */
+typedef struct {
+ double p[MXDI]; /* coordinate position */
+ double v[MXDO]; /* function values */
+} co;
+
+/* Interface coordinate value + weighting */
+typedef struct {
+ double p[MXDI]; /* coordinate position */
+ double v[MXDO]; /* function values */
+ double w; /* Weight to give this point, nominally 1.0 */
+} cow;
+
+/* Interface coordinate value + per out component weighting */
+typedef struct {
+ double p[MXDI]; /* coordinate position */
+ double v[MXDO]; /* function values */
+ double w[MXDO]; /* Weight to give this point, nominally 1.0 */
+} coww;
+
+/* Scattered data Per data point data (internal) */
+struct _rpnts {
+ double p[MXRI]; /* Data position [di] */
+ double v[MXRO]; /* Data value [fdi] */
+ double k[MXRO]; /* Weight factor (nominally 1.0, less for lower confidence data point) */
+ double cv[MXRO]; /* Extra fit corrected v[fdi] */
+}; typedef struct _rpnts rpnts;
+
+/* Hermite interpolation magic data */
+typedef struct {
+ int p; /* The parameter power combination */
+ int i; /* The surrounding cube vertex index */
+ int j; /* The dimension combination */
+ float wgt;
+} magic_data;
+
+#include "rev.h" /* Reverse interpolation defintions */
+#include "gam.h" /* Gamut defintions */
+
+/* Structure for final resolution multi-dimensional regularized spline data */
+struct _rspl {
+
+ /* Global rspl state */
+ int debug; /* 0 = no debug */
+ int verbose; /* 0 = no verbose */
+ double smooth; /* Smoothness factor */
+ double avgdev[MXDO];
+ /* Average Deviation of function values as proportion of function range. */
+ int symdom; /* 0 = non-symetric smoothness with different grid resolutions, */
+ /* 1 = symetric smoothness with different grid resolutions, */
+
+ int di; /* Input dimensionality */
+ int fdi; /* Output function dimensionality */
+
+ /* Weak default function related information */
+ double weak; /* Weak total weighting, nominal = 1.0 */
+ void *dfctx; /* Opaque function context */
+ void (*dfunc)(void *cbntx, double *out, double *in);
+ /* Function to set from */
+
+ /* Scattered Data point related information */
+ int zf; /* Extra fitting flag - Compensate for data fit errors each round */
+ int tpsm; /* Two pass smoothing flag (if set to 1). */
+ int tpsm2; /* Two pass smoothing 2nd pass flag */
+ struct {
+ int no; /* Number of data points in array */
+ rpnts *a; /* Array of data points */
+ datao vl,vw; /* Data value low/width - used to normalize smoothness values */
+ datao va; /* Data value averages */
+ } d;
+ int niters; /* Number of multigrid itterations needed */
+ int **ires; /* Resolution for each itteration and dimension */
+ void **mgtmps[MXRO]; /* Store pointers to re-usable mgtmp when incremental */
+
+
+ /* Grid points data */
+ struct {
+ int res[MXDI]; /* Single dimension grid resolution for each axis */
+ int bres, brix; /* Biggest resolution and its index */
+ double mres; /* Geometric mean res[] */
+ int no; /* Total number of points in grid = res[0] * res[1] * .. res[di-1] */
+ datai l,h,w; /* Grid low, high, grid cell width */
+ /* This is used to map from the input domain to the grid */
+
+ datao fmin, fmax; /* Min & max values of grid output (function) variables */
+ int fminx[MXDO], fmaxx[MXDO]; /* Grid indexes of points that set min/max output values */
+ double fscale; /* Overall magnitude of output values */
+ double *ipos[MXDI]; /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Allows for the possibility of */
+ /* a non-uniform grid spacing, by adjusting the curvature evaluation */
+ /* appropriately. */
+ double **ccv; /* Curvature compensation array for current outpu (May be NULL) */
+ int fminmax_valid; /* Min/max/scale cached values valid flag. */
+ int limitv_cached; /* Flag: Ink limit values have been set in the grid array */
+
+#define G_XTRA 3 /* Extra floats per grid point */
+ float *alloc; /* Grid points allocated address */
+ float *a; /* Grid point flags + data */
+ /* Array is res[] ^ di entries float[fdi+G_XTRA], offset by G_XTRA */
+ /* (But is expanded when spline interpolaton is active) */
+ /* float[-1] contains the ink limit function value, L_UNINIT if not initd */
+ /* float[-2] contains the edge flag values, 2 bits per in dim. */
+ /* float[-3] contains the touched flag generation count. */
+ /* (k value for non-linear fit would be another entry.) */
+ /* Flag values are 3 bits for each dimension. Bits 1,0 form */
+ /* 2 bit distance from edge: 0 for on edge of grid, */
+ /* 1 for next row, 2 for 3rd row and beyond. If bit 2 is set, */
+ /* then we are on the lower edge. This limits di to 10 or less, */
+ /* with the two MS bits spare. */
+ int pss; /* Grid point structure size = fdi+G_XTRA */
+
+ /* Uninitialised limit value */
+#define L_UNINIT ((float)-1e38)
+
+ /* Macros to access flags. Arguments are a pointer to base grid point and */
+ /* Flag value is distance from edge in bottom 2 bits, values 0, 1 or 2 maximum. */
+ /* bit 2 is set if the distance is to the lower edge. */
+#define FLV(fp) (*((unsigned int *)((fp)-2)))
+ /* Init the flag values to 0 */
+#define I_FL(fp) (FLV(fp) = 0)
+ /* Return 3 bit flag data */
+#define G_FL(fp,di) ((FLV(fp) >> (3 * (di))) & 7)
+ /* Set 3 bit flag data */
+#define S_FL(fp,di,v) (FLV(fp) = (FLV(fp) & ~(7 << (3 * (di)))) | (((v) & 7) << (3 * (di))))
+
+ /* Macro to access touched flag. Arguments are a pointer to base grid point. */
+#define TOUCHF(fp) (*((unsigned int *)((fp)-3)))
+
+ /* Grid array offset lookups - in floats */
+ int ci[MXDI]; /* Grid coordinate increments for each dimension */
+ int fci[MXDI]; /* Grid coordinate increments for each dimension in floats */
+ int *hi; /* 2^di Combination offset for sequence through cube. */
+ int a_hi[DEF2MXDI]; /* Default allocation for *hi */
+ int *fhi; /* Combination offset for sequence through cube of */
+ /* 2^di points, starting at base, in floats */
+ int a_fhi[DEF2MXDI];/* Default allocation for *hi */
+
+ unsigned int touch; /* Cell touched flag count */
+ } g;
+
+
+ /* Ink limit related information */
+ int limiten; /* Flag - limiting is enabled */
+ double (*limitf)(void *cntx, double *in); /* Optional input space qualifier function. */
+ void *lcntx; /* Context passed to limit() */
+ double limitv; /* Value not to be exceeded by limit() */
+
+ /* Hermite spline interpolation support */
+ struct {
+ magic_data *magic; /* Magic matrix - non-zero elements only, Non-NULL if splining */
+ int nm; /* number in magic data list */
+ int spline; /* Non-zero if spline data is present in g.a */
+ /* Changes from float g.a[res ^ di][fdi+G_XTRA], offset by G_XTRA, */
+ /* to float g.a[res ^ di][(2^di * fdi)+G_XTRA], offset by G_XTRA, */
+ } spline;
+
+ /* Gamut support */
+ gam_struct gam; /* See gam.h */
+
+ /* Reverse Interpolation support */
+ rev_struct rev; /* See rev.h */
+
+ /* Methods */
+
+ /* Free ourselves */
+ void (*del)(struct _rspl *ss);
+
+ /* Combination lags used by various functions */
+ /* NOTE that RSPL_2PASSSMTH and RSPL_EXTRAFIT2 are available, but the smoothing */
+ /* factors are not setup for them, and they are not sufficiently different from the */
+ /* default smoothing to be useful. */
+#define RSPL_NOFLAGS 0x0000
+#define RSPL_2PASSSMTH 0x0001 /* Use gaussian filter in 2nd pass to smooth */
+#define RSPL_EXTRAFIT2 0x0002 /* Compensate for data errors each round */
+#define RSPL_SYMDOMAIN 0x0004 /* Maintain symetric smoothness with nonsym. resolution */
+#define RSPL_SET_APXLS 0x0020 /* For set_rspl, adjust samples for aproximate least squares */
+#define RSPL_FASTREVSETUP 0x0010 /* Do a fast reverse setup at the cost of subsequent speed */
+#define RSPL_VERBOSE 0x8000 /* Turn on print progress messages */
+#define RSPL_NOVERBOSE 0x4000 /* Turn off print progress messages */
+
+ /* Initialise from scattered data. RESTRICTED SIZE */
+ /* Return non-zero if result is non-monotonic */
+ int
+ (*fit_rspl)(
+ struct _rspl *s, /* this */
+ int flags, /* Combination of flags */
+ co *d, /* Array holding position and function values of data points */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range, */
+ /* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
+ /* NULL = default 0.005 */
+ double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+ );
+
+ /* Initialise from scattered data, with per point weighting. RESTRICTED SIZE */
+ /* Return non-zero if result is non-monotonic */
+ int
+ (*fit_rspl_w)(
+ struct _rspl *s, /* this */
+ int flags, /* Combination of flags */
+ cow *d, /* Array holding position, function and weight values of data points */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range, */
+ /* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
+ /* NULL = default 0.005 */
+ double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+ );
+
+ /* Initialise from scattered data, with per point individual out weighting. */
+ /* RESTRICTED SIZE Return non-zero if result is non-monotonic */
+ int
+ (*fit_rspl_ww)(
+ struct _rspl *s, /* this */
+ int flags, /* Combination of flags */
+ coww *d, /* Array holding position, function and weight values of data points */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range, */
+ /* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
+ /* NULL = default 0.005 */
+ double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+ );
+
+ /* Initialise from scattered data, with weak default function. */
+ /* RESTRICTED SIZE */
+ /* Return non-zero if result is non-monotonic */
+ int
+ (*fit_rspl_df)(
+ struct _rspl *s, /* this */
+ int flags, /* Combination of flags */
+ co *d, /* Array holding position and function values of data points */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range, */
+ /* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
+ /* NULL = default 0.005 */
+ double *ipos[MXDI],/* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+ double weak, /* Weak weighting, nominal = 1.0 */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, double *out, double *in) /* Function to set from */
+ );
+
+ /* Initialise from scattered data, with per point weighting and weak default function. */
+ /* RESTRICTED SIZE */
+ /* Return non-zero if result is non-monotonic */
+ int
+ (*fit_rspl_w_df)(
+ struct _rspl *s, /* this */
+ int flags, /* Combination of flags */
+ cow *d, /* Array holding position, function and weight values of data points */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range, */
+ /* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
+ /* NULL = default 0.005 */
+ double *ipos[MXDI],/* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+ double weak, /* Weak weighting, nominal = 1.0 */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, double *out, double *in) /* Function to set from */
+ );
+
+ /* Initialize the grid from a provided function. By default the grid */
+ /* values are set to exactly the value returned by func(), unless the */
+ /* RSPL_SET_APXLS flag is set, in which case an attempt is made to have */
+ /* the grid points represent a least squares aproximation to the underlying */
+ /* surface. */
+ /* Grid index values are supplied "under" in[] at *((int*)&in[-e-1]) */
+ /* Return non-monotonic status */
+ int
+ (*set_rspl)(
+ struct _rspl *s, /* this */
+ int flags, /* Combination of flags */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, double *out, double *in), /* Function to set from */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh /* Data value high normalize - NULL = default 1.0 */
+ );
+
+ /* Re-set values from a function. Grid index values are supplied */
+ /* "under" in[] at *((int*)&iv[-e-1]) */
+ /* Return non-monotonic status. Clears all the reverse lookup information. */
+ /* It is assumed that the output range remains unchanged. */
+ /* Existing output values are supplied in out[] */
+ int
+ (*re_set_rspl)(
+ struct _rspl *s,/* this */
+ int flags, /* Combination of flags (not used) */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, double *out, double *in) /* Function to set from */
+ );
+
+ /* Scan the rspl grid point locations and values. Grid index values are */
+ /* supplied "under" in[] at *((int*)&iv[-e-1]) */
+ /* Return non-monotonic status. */
+ void
+ (*scan_rspl)(
+ struct _rspl *s, /* this */
+ int flags, /* Combination of flags (not used) */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, double *out, double *in) /* Function that gets given values */
+ );
+
+ /* Set values by multi-grid optimisation using the provided function. */
+ int (*opt_rspl)(
+ struct _rspl *s,/* this */
+ int flags, /* Combination of flags */
+ int tdi, /* Dimensionality of target data */
+ int adi, /* Additional grid point data allowance */
+ double **vdata, /* di^2 array of function, target and additional values to init */
+ /* array corners with. */
+ double (*func)(void *fdata, double *inout, double *surav, int first, double *cw),
+ /* Optimisation function */
+ void *fdata, /* Opaque data needed by function */
+ datai glow, /* Grid low scale - NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution */
+ datao vlow, /* Data value low normalize - NULL = default 0.0 */
+ datao vhigh /* Data value high normalize - NULL = default 1.0 */
+ );
+
+ /* Filter the existing values using the surrounding 3x3 cells. */
+ /* Grid index values are supplied "under" in[] */
+ void
+ (*filter_rspl)(
+ struct _rspl *s, /* this */
+ int flags, /* Combination of flags (not used) */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, float **out, double *in, int cvi) /* Function to set from */
+ );
+
+ /* Do forward interpolation */
+ /* Return 0 if OK, 1 if input was clipped to grid */
+ int (*interp)(
+ struct _rspl *s, /* this */
+ co *p); /* Input and output values */
+
+ /* Do forward (partial) interpolation to allow input & output curves to be applied, */
+ /* and allow input delta E to be estimated from output delta E. */
+ /* Call with input value in p1[0].p[], */
+ /* In order smallest to largest weight: */
+ /* Return di+1 vertex values in p1[]].v[] and */
+ /* 0-1 sub-cell weight values as (p1[].p[0] - p1[].p[1]). */
+ /* Optionally in input channel order: */
+ /* Returns di+1 partial derivatives + base value in p2[].v[], */
+ /* with matching weight values for each in p2[].p[0] (last weight = 1)*/
+ /* Return 0 if OK, 1 if input was clipped to grid */
+ int (*part_interp)(
+ struct _rspl *s, /* this */
+ co *p1,
+ co *p2); /* optional - return partial derivatives for each input channel */
+
+ /* Do splined forward interpolation. RESTRICTED SIZE */
+ /* Return 0 if OK, 1 if input was clipped to grid */
+ int (*spline_interp)(
+ struct _rspl *s, /* this */
+ co *p); /* Input and output values */
+
+
+ /* ------------------------------- */
+ /* Create a surface gamut representation. */
+ /* Return NZ on error */
+ int (*comp_gamut)(struct _rspl *s,
+ double *cent, /* Optional center of gamut [fdi], default center of out range */
+ double *scale, /* Optional Scale of output values in vector to center [fdi] */
+ /* default 1.0 */
+ void (*outf)(void *cntxf, double *out, double *in), /* Optional rspl val -> output value */
+ void *cntxf, /* Context for function */
+ void (*outb)(void *cntxb, double *out, double *in), /* Optional output value -> rspl val */
+ void *cntxb /* Context for function */
+ );
+
+ /* ------------------------------- */
+
+ /* Set the ink limit information for any reverse interpolation. */
+ /* Calling this will clear the reverse interpolaton cache. */
+ void (*rev_set_limit)(
+ struct _rspl *s, /* this */
+ double (*limitf)(void *lcntx, double *in), /* Optional input space limit function. */
+ /* Function should evaluate in[0..di-1], and return number */
+ /* that is not to exceed limitv. NULL if not used. */
+ void *lcntx, /* Context passed to limit() */
+ double limitv /* Value that limit() is not to exceed */
+ );
+
+ /* Get the ink limit information for any reverse interpolation. */
+ void (*rev_get_limit)(
+ struct _rspl *s, /* this */
+ double (**limitf)(void *lcntx, double *in),
+ /* Return pointer to function of NULL if not set */
+ void **lcntx, /* return context pointer */
+ double *limitv /* Return limit value */
+ );
+
+ /* Possible reverse hint flags */
+#define RSPL_WILLCLIP 0x0001 /* Hint that clipping will be needed */
+#define RSPL_EXACTAUX 0x0002 /* Hint that auxiliary target will be matched exactly */
+#define RSPL_MAXAUX 0x0004 /* If not possible to match exactly, return the */
+ /* closest value larger than the target, rather than */
+ /* absolute closest. */
+#define RSPL_AUXLOCUS 0x0008 /* Auxiliary target is proportion of locus, not */
+ /* absolute. Implies EXACTAUX hint. */
+#define RSPL_NEARCLIP 0x0010 /* If clipping occurs, return the nearest solution, */
+ /* rather than the one in the clip direction. */
+
+ /* Return value masks */
+#define RSPL_DIDCLIP 0x8000 /* If this bit is set, at least one soln. and clipping occured */
+#define RSPL_NOSOLNS 0x7fff /* And return value with this mask to get number of solutions */
+
+ /* Do reverse interpolation given target output values and (optional) auxiliary target */
+ /* input values. Return number of results and clip flag. If return value == mxsoln, then */
+ /* there might be more results. RESTRICTED SIZE */
+ int (*rev_interp)(
+ struct _rspl *s, /* this */
+ int flags, /* Hint flag */
+ int mxsoln, /* Maximum number of solutions allowed for */
+ int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no aux) */
+ double cdir[MXRO], /* Clip vector direction and length - NULL if not used */
+ co *p); /* Given target output space value in cpp[0].v[] + */
+ /* target input space auxiliaries in cpp[0].p[], return */
+ /* input space solutions in cpp[0..retval-1].p[], and */
+ /* (possibly) clipped target values in cpp[0].v[] */
+
+ /* Do reverse search for the locus of the auxiliary input values given a target output. */
+ /* Return 1 on finding a valid solution, and 0 if no solutions are found. RESTRICTED SIZE */
+ int (*rev_locus)(
+ struct _rspl *s,/* this */
+ int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no aux) */
+ co *cpp, /* Input target value in cpp[0].v[] */
+ double min[MXRI],/* Return minimum auxiliary values */
+ double max[MXRI]); /* Return maximum auxiliary values */
+
+ /* Do reverse search for the auxiliary min/max ranges of the solution locus for the */
+ /* given target output values. RESTRICTED SIZE */
+ /* Return number of locus segments found, up to mxsoln. 0 will be returned if no solutions */
+ /* are found. */
+ int (*rev_locus_segs)(
+ struct _rspl *s,/* this */
+ int *auxm, /* Array of di mask flags, !=0 for valid auxliaries (NULL if no aux) */
+ co *cpp, /* Input value in cpp[0].v[] */
+ int mxsoln, /* Maximum number of solutions allowed for */
+ double min[][MXRI], /* Array of min[MXRI] to hold return segment minimum values. */
+ double max[][MXRI] /* Array of max[MXRI] to hold return segment maximum values. */
+ );
+
+
+ /* ------------------------------- */
+
+ /* Return the min and max of the input values valid in the grid */
+ void (*get_in_range)(
+ struct _rspl *s, /* this */
+ double *min, double *max); /* Return min/max values */
+
+ /* return the min and max of the output values contained in the grid */
+ void (*get_out_range)(
+ struct _rspl *s, /* this */
+ double *min, double *max); /* Return min/max values */
+
+ /* return the grid index of the grid values at the min & max output values */
+ void (*get_out_range_points)(struct _rspl *s, int *minp, int *maxp);
+
+ /* return the overall scale of the output values contained in the grid */
+ double (*get_out_scale)(struct _rspl *s);
+
+ /* return the next touched flag count value. */
+ /* Whenever this rolls over, all the flags in the grid array will be reset */
+ unsigned int (*get_next_touch)(
+ struct _rspl *s); /* this */
+
+# define wvals ad##jw
+
+ /* Return non-zero if this rspl can be */
+ /* used with Restricted Size functions. */
+ int (*within_restrictedsize)(
+ struct _rspl *s); /* this */
+
+}; typedef struct _rspl rspl;
+
+/* Create a new, empty rspl object */
+rspl *new_rspl(int flags, int di, int fdi); /* Input and output dimentiality */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Utility functions */
+
+/* The multi-dimensional access sequence is a distributed */
+/* Gray code sequence, with direction reversal */
+/* on every alternate power of 2 scale. */
+/* It is intended to aid cache access locality in multi-dimensional */
+/* regular sampling. It approximates the Hilbert curve sequence. */
+
+/* Structure to hold sequencer info */
+struct _rpsh {
+ int di; /* Dimensionality */
+ unsigned res[MXDI]; /* Resolution per coordinate */
+ unsigned bits[MXDI]; /* Bits per coordinate */
+ unsigned tbits; /* Total bits */
+ unsigned ix; /* Current binary index */
+ unsigned tmask; /* Total 2^n count mask */
+ unsigned count; /* Usable count */
+}; typedef struct _rpsh rpsh;
+
+/* Initialise, returns total usable count */
+unsigned
+rpsh_init(rpsh *p, int di, unsigned res[], int co[]);
+
+/* Reset the counter */
+void rpsh_reset(rpsh *p);
+
+/* Increment pseudo-hilbert coordinates */
+/* Return non-zero if count rolls over to 0 */
+int rpsh_inc(rpsh *p, int co[]);
+
+#endif /* RSPL_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rspl/rspl1.c b/rspl/rspl1.c
new file mode 100644
index 0000000..dc3588b
--- /dev/null
+++ b/rspl/rspl1.c
@@ -0,0 +1,391 @@
+
+ /* Single dimension regularized spline data structure */
+
+/*
+ * Argyll Color Correction System
+ * Author: Graeme W. Gill
+ * Date: 2000/10/29
+ *
+ * Copyright 1996 - 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * This is a simple 1D version of rspl, useful for standalone purposes.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include "numsup.h"
+#include "rspl1.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define DBGA g_log, 0 /* First argument to DBGF() */
+# define DBGF(xx) a1logd xx
+#else
+# define DBGF(xx)
+#endif
+
+
+/* Do an interpolation based on the grid */
+/* Use a linear interp between grid points. */
+/* If the input is outside the grid range, it will */
+/* be clamped to the nearest grid point. */
+static int interp(
+rspl *t,
+co *p
+) {
+ int rv = 0;
+ double x, y, xx, w1;
+ int i;
+
+ x = p->p[0];
+
+ if (x < t->gl) {
+ x = t->gl;
+ rv = 1;
+ } else if (x > t->gh) {
+ x = t->gh;
+ rv = 1;
+ }
+
+ xx = (x - t->gl)/t->gw; /* Grid location of point */
+ i = (int)floor(xx); /* Lower grid of point */
+ if (i >= (t->nig-2))
+ i = t->nig-2;
+
+ w1 = xx - (double)i; /* Weight to upper grid point */
+
+ y = ((1.0 - w1) * t->x[i]) + (w1 * t->x[i+1]);
+
+ p->v[0] = y * t->vw + t->vl; /* Rescale the data */
+
+ return rv;
+}
+
+/* Destructor */
+static void del_rspl(rspl *t) {
+ if (t != NULL) {
+ if (t->x != NULL)
+ free_dvector(t->x, 0, t->nig);
+ free(t);
+ }
+}
+
+/* Initialise the regular spline from scattered data */
+/* Return nz on error */
+static int fit_rspl_imp(
+ struct _rspl *t,/* this */
+ int flags, /* (Not used) */
+ void *d, /* Array holding position and function values of data points */
+ int dtp, /* Flag indicating data type, 0 = (co *), 1 = (cow *), 2 = (coww *) */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int *gres, /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double *avgdev, /* (Not used) */
+ double **ipos /* (not used) */
+) {
+ int n;
+ double cw;
+
+ DBGF((DBGA, "rspl1:fit_rspl_imp() with %d points called, dtp = %d\n",ndp,dtp));
+
+ /* Allocate space for interpolation grid */
+ t->nig = *gres;
+
+ if ((t->x = dvector(0, t->nig)) == NULL) {
+ DBGF((DBGA, "rspl1:Malloc of vector x failed\n"));
+ return 1;
+ }
+
+ /* Normalize curve weight to grid resolution. */
+ cw = 0.0000005 * smooth * pow((t->nig-1),4.0) / (t->nig - 2);
+ DBGF((DBGA, "rspl1:cw = %e\n",cw));
+
+ /* cw is multiplied by the sum of grid curvature errors squared to keep */
+ /* the same ratio with the sum of data position errors squared */
+
+ /* Determine the data range */
+ t->xl = 1e300;
+ t->xh = -1e300;
+ t->dl = 1e300;
+ t->dh = -1e300;
+ if (dtp == 0) {
+ co *dd = (co *)d;
+
+ for (n = 0; n < ndp; n++) {
+ if (dd[n].p[0] < t->xl)
+ t->xl = dd[n].p[0];
+ if (dd[n].p[0] > t->xh)
+ t->xh = dd[n].p[0];
+ if (dd[n].v[0] < t->dl)
+ t->dl = dd[n].v[0];
+ if (dd[n].v[0] > t->dh)
+ t->dh = dd[n].v[0];
+
+ DBGF((DBGA, "rspl1:Point %d = %f, %f\n",n,dd[n].p[0],dd[n].v[0]));
+ }
+ } else if (dtp == 1) {
+ cow *dd = (cow *)d;
+
+ for (n = 0; n < ndp; n++) {
+ if (dd[n].p[0] < t->xl)
+ t->xl = dd[n].p[0];
+ if (dd[n].p[0] > t->xh)
+ t->xh = dd[n].p[0];
+ if (dd[n].v[0] < t->dl)
+ t->dl = dd[n].v[0];
+ if (dd[n].v[0] > t->dh)
+ t->dh = dd[n].v[0];
+ DBGF((DBGA, "rspl1:Point %d = %f, %f (%f)\n",n,dd[n].p[0],dd[n].v[0],dd[n].w));
+ }
+ } else {
+ DBGF((DBGA, "rspl1:Internal error, unknown dtp value %d\n",dtp));
+ return 1;
+ }
+
+ t->gl = glow != NULL ? *glow : 0.0;
+ t->gh = ghigh != NULL ? *ghigh : 1.0;
+
+ /* adjust input ranges to encompass data */
+ if (t->xl < t->gl)
+ t->gl = t->xl;
+ if (t->xh > t->gh)
+ t->gh = t->xh;
+
+ /* Set the input and output scaling */
+ t->gw = (t->gh - t->gl)/(double)(t->nig-1);
+
+ t->vl = vlow != NULL ? *vlow : 0.0;
+ t->vw = ((vhigh != NULL ? *vhigh : 1.0) - t->vl);
+
+ DBGF((DBGA, "rspl1:gl %f, gh %f, gw %f, vl %f, vw %f\n",t->gl,t->gh,t->gw,t->vl,t->vw));
+
+ /* create smoothed grid data */
+ {
+ int n,i,k;
+ double **A; /* A matrix of interpoint weights */
+ double *b; /* b vector for RHS of simultabeous equation */
+
+ /* We just store the diagonal of the A matrix */
+ if ((A = dmatrix(0, t->nig, 0, 2)) == NULL) {
+ DBGF((DBGA, "rspl1:Malloc of matrix A failed\n"));
+ return 1;
+ }
+
+ if ((b = dvector(0,t->nig)) == NULL) {
+ free_dvector(b,0,t->nig);
+ DBGF((DBGA, "rspl1:Malloc of vector b failed\n"));
+ return 1;
+ }
+
+ /* Initialize the A and b matricies */
+ for (i = 0; i < t->nig; i++) {
+ for (k = 0; k < 3; k++)
+ A[i][k] = 0.0;
+ t->x[i] = b[i] = 0.0;
+ }
+
+ /* Accumulate data dependent factors */
+ for (n = 0; n < ndp; n++) {
+ double bf, cbf;
+ double xv, yv, wv;
+
+ if (dtp == 0) {
+ co *dd = (co *)d;
+
+ xv = dd[n].p[0];
+ yv = dd[n].v[0];
+ wv = 1.0;
+ } else if (dtp == 1) {
+ cow *dd = (cow *)d;
+
+ xv = dd[n].p[0];
+ yv = dd[n].v[0];
+ wv = dd[n].w;
+ } else {
+ DBGF((DBGA, "rspl1:Internal error, unknown dtp value %d\n",dtp));
+ return 1;
+ }
+ yv = (yv - t->vl)/t->vw; /* Normalize the value */
+
+ /* Figure out which grid cell data is in */
+ i = (int)((xv - t->gl)/t->gw); /* Index of next lowest data point */
+
+ bf = ((((double)(i+1) * t->gw) + t->gl) - xv)/t->gw; /* weight to lower grid point */
+ cbf = 1.0 - bf; /* weight to upper grid point */
+
+ b[i] -= 2.0 * bf * -yv * wv; /* dui component due to dn */
+ A[i][0] += 2.0 * bf * bf * wv; /* dui component due to ui */
+ A[i][1] += 2.0 * bf * cbf * wv; /* dui component due to ui+1 */
+
+ if ((i+1) < t->nig) {
+ b[i+1] -= 2.0 * cbf * -yv * wv; /* dui component due to dn */
+ A[i+1][0] += 2.0 * cbf * cbf * wv; /* dui component due to ui */
+ }
+ }
+
+ /* Accumulate curvature dependent factors */
+ for (i = 0; i < t->nig; i++) {
+
+ if ((i-2) >= 0) { /* Curvature of cell below */
+ A[i][0] += 2.0 * cw;
+ }
+
+ if ((i-1) >= 0 && (i+1) < t->nig) { /* Curvature of t cell */
+ A[i][0] += 8.0 * cw;
+ A[i][1] += -4.0 * cw;
+ }
+ if ((i+2) < t->nig) { /* Curvature of cell above */
+ A[i][0] += 2.0 * cw;
+ A[i][1] += -4.0 * cw;
+ A[i][2] += 2.0 * cw;
+ }
+ }
+
+#ifdef DEBUG
+ DBGF((DBGA, "A matrix:\n"));
+ for (i = 0; i < t->nig; i++) {
+ for (k = 0; k < 3; k++)
+ DBGF((DBGA, "A[%d][%d] = %f\n",i,k,A[i][k]));
+ }
+ DBGF((DBGA, "b vector:\n"));
+ for (i = 0; i < t->nig; i++)
+ DBGF((DBGA, "b[%d] = %f\n",i,b[i]));
+#endif /* DEBUG */
+
+ /* Apply Cholesky decomposition to A[][] to create L[][] */
+ for (i = 0; i < t->nig; i++) {
+ double sm;
+ for (n = 0; n < 3; n++) {
+ sm = A[i][n];
+ for (k = 1; (n+k) < 3 && (i-k) >=0; k++) {
+ sm -= A[i-k][n+k] * A[i-k][k];
+ }
+ if (n == 0) {
+ if (sm <= 0.0) {
+ free_dvector(b,0,t->nig);
+ free_dmatrix(A,0,t->nig,0,2);
+ DBGF((DBGA, "rspl1:Sum is -ve - loss of accuracy ?\n"));
+ return 1;
+ }
+ A[i][0] = sqrt(sm);
+ } else {
+ A[i][n] = sm/A[i][0];
+ }
+ }
+ }
+
+ /* Solve L . y = b, storing y in x */
+ for (i = 0; i < t->nig; i++) {
+ double sm;
+ sm = b[i];
+ for (k = 1; k < 3 && (i-k) >= 0; k++) {
+ sm -= A[i-k][k] * t->x[i-k];
+ }
+ t->x[i] = sm/A[i][0];
+ }
+
+ /* Solve LT . x = y */
+ for (i = t->nig-1; i >= 0; i--) {
+ double sm;
+ sm = t->x[i];
+ for (k = 1; k < 3 && (i+k) < t->nig; k++) {
+ sm -= A[i][k] * t->x[i+k];
+ }
+ t->x[i] = sm/A[i][0];
+ }
+#ifdef DEBUG
+ DBGF((DBGA, "Solution vector:\n"));
+ for (i = 0; i < t->nig; i++) {
+ DBGF((DBGA, "x[%d] = %f\n",i,t->x[i]));
+ }
+#endif /* DEBUG */
+
+ free_dvector(b,0,t->nig);
+ free_dmatrix(A,0,t->nig,0,2);
+ }
+ return 0;
+}
+
+/* Initialise from scattered data. */
+/* Return nz on error */
+static int fit_rspl(
+ struct _rspl *t,/* this */
+ int flags, /* (Not used) */
+ co *d, /* Array holding position and function values of data points */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int *gres, /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double *avgdev, /* (Not used) */
+ double **ipos /* (not used) */
+) {
+ /* Call implementation with (co *) data */
+ return fit_rspl_imp(t, flags, (void *)d, 0, ndp, glow, ghigh, gres, vlow, vhigh,
+ smooth, avgdev, ipos);
+}
+
+/* Initialise the regular spline from scattered data with weights */
+/* Return nz on error */
+static int
+fit_rspl_w(
+ rspl *t, /* this */
+ int flags, /* Combination of flags */
+ cow *d, /* Array holding position, function and weight values of data points */
+ int dno, /* Number of data points */
+ ratai glow, /* Grid low scale - will be expanded to enclose data, NULL = default 0.0 */
+ ratai ghigh, /* Grid high scale - will be expanded to enclose data, NULL = default 1.0 */
+ int *gres, /* Spline grid resolution */
+ ratao vlow, /* Data value low normalize, NULL = default 0.0 */
+ ratao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double *avgdev, /* (Not used) */
+ double **ipos /* (not used) */
+) {
+ /* Call implementation with (cow *) data */
+ return fit_rspl_imp(t, flags, (void *)d, 1, dno, glow, ghigh, gres, vlow, vhigh,
+ smooth, avgdev, ipos);
+}
+
+/* Construct an empty rspl1 */
+/* Return NULL if something goes wrong. */
+rspl *new_rspl(int flags, int di, int fdi) {
+ rspl *t; /* this */
+
+ if (flags != RSPL_NOFLAGS || di != 1 || fdi != 1) {
+ DBGF((DBGA, "rspl1:Can't handle general rspl: flags %d, di %d, do %d\n",flags,di,fdi));
+ return NULL;
+ }
+
+ if ((t = (rspl *)calloc(1, sizeof(rspl))) == NULL) {
+ DBGF((DBGA, "rspl1:Malloc of structure failed\n"));
+ return NULL;
+ }
+
+ /* Initialise the classes methods */
+ t->interp = interp;
+ t->fit_rspl = fit_rspl;
+ t->fit_rspl_w = fit_rspl_w;
+ t->del = del_rspl;
+
+ return t;
+}
+
+
+
+
+
diff --git a/rspl/rspl1.h b/rspl/rspl1.h
new file mode 100644
index 0000000..d5ea0b9
--- /dev/null
+++ b/rspl/rspl1.h
@@ -0,0 +1,115 @@
+
+#ifndef _RSPL1_H_
+
+ /* Single dimension regularized spline data structure */
+
+/*
+ * Argyll Color Correction System
+ * Author: Graeme W. Gill
+ * Date: 2000/10/29
+ *
+ * Copyright 1996 - 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * This is a simple 1D version of rspl, useful for standalone purposes.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* General data point position/value structure */
+typedef double datai[1];
+typedef double datao[1];
+typedef double ratai[1];
+typedef double ratao[1];
+
+/* Interface coordinate value */
+typedef struct {
+ double p[1]; /* coordinate position */
+ double v[1]; /* function values */
+} co;
+
+/* Interface coordinate value */
+typedef struct {
+ double p[1]; /* coordinate position */
+ double v[1]; /* function values */
+ double w; /* Weight to give this point, nominally 1.0 */
+} cow;
+
+#define RSPL_NOFLAGS 0
+
+struct _rspl {
+
+ /* Private: */
+ int nig; /* number in interpolation grid */
+ double gl,gh,gw;/* Interpolation grid scale low, high, grid cell width */
+ double vl,vw; /* low & range */
+ double xl,xh; /* Actual X data exremes low, high */
+ double dl,dh; /* Actual Y Data scale low, high */
+ double *x; /* Array of nig grid point scaled y values */
+
+ /* Public: */
+
+ /* destructor */
+ void (*del)(struct _rspl *t);
+
+ /* Initialise from scattered data. */
+ /* Returns nz on error */
+ int
+ (*fit_rspl)(
+ struct _rspl *s, /* this */
+ int flags, /* (Not used) */
+ co *d, /* Array holding position and function values of data points */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int *gres, /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double *avgdev, /* (Not used) */
+ double **ipos /* (not used) */
+ );
+
+ /* Initialise from scattered data with weighting. */
+ /* Returns nz on error */
+ int
+ (*fit_rspl_w)(
+ struct _rspl *s, /* this */
+ int flags, /* (Not used) */
+ cow *d, /* Array holding position and function values of data points */
+ int ndp, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int *gres, /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ double *avgdev, /* (Not used) */
+ double **ipos /* (not used) */
+ );
+
+ /* Do forward interpolation */
+ /* Return 0 if OK, 1 if input was clipped to grid */
+ int (*interp)(
+ struct _rspl *s, /* this */
+ co *p); /* Input and output values */
+
+}; typedef struct _rspl rspl;
+
+/* Create a new, empty rspl object */
+rspl *new_rspl(int flags, int di, int fdi);
+
+#ifdef __cplusplus
+}
+#endif
+
+#define _RSPL1_H_
+#endif /* _RSPL1_H_ */
+
+
diff --git a/rspl/rspl_imp.h b/rspl/rspl_imp.h
new file mode 100644
index 0000000..0cd8805
--- /dev/null
+++ b/rspl/rspl_imp.h
@@ -0,0 +1,27 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized spline
+ * Implementation header.
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/96
+ *
+ * Copyright 1996, 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.
+ */
+
+#include "rspl.h"
+
+#ifndef RSPL_IMP_H
+
+/* These three factors controll how the monotonic stuff behaves. */
+#define MCINC 0.05 /* The tollerance for detecting non-monoticity */
+#define BALLEV 0.8 /* Balance level of adjusted points */
+#define RADF 0.01 /* Radius factor of nme influence */
+
+#define RSPL_IMP_H
+#endif /* RSPL_IMP_H */
diff --git a/rspl/scat.c b/rspl/scat.c
new file mode 100644
index 0000000..b4ed978
--- /dev/null
+++ b/rspl/scat.c
@@ -0,0 +1,2861 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized splines data fitter
+ *
+ * Author: Graeme W. Gill
+ * Date: 2004/8/14
+ *
+ * Copyright 1996 - 2009 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.
+ */
+
+/*
+ * This file contains the scattered data solution specific code.
+ *
+ * The regular spline implementation was inspired by the following technical reports:
+ *
+ * D.J. Bone, "Adaptive Multi-Dimensional Interpolation Using Regularized Linear Splines,"
+ * Proc. SPIE Vol. 1902, p.243-253, Nonlinear Image Processing IV, Edward R. Dougherty;
+ * Jaakko T. Astola; Harold G. Longbotham;(Eds)(1993).
+ *
+ * D.J. Bone, "Adaptive Colour Printer Modeling using regularized linear splines,"
+ * Proc. SPIE Vol. 1909, p. 104-115, Device-Independent Color Imaging and Imaging
+ * Systems Integration, Ricardo J. Motta; Hapet A. Berberian; Eds.(1993)
+ *
+ * Don Bone and Duncan Stevenson, "Modelling of Colour Hard Copy Devices Using Regularised
+ * Linear Splines," Proceedings of the APRS workshop on Colour Imaging and Applications,
+ * Canberra (1994)
+ *
+ * see <http://www.cmis.csiro.au/Don.Bone/>
+ *
+ * Also of interest was:
+ *
+ * "Discrete Smooth Interpolation", Jean-Laurent Mallet, ACM Transactions on Graphics,
+ * Volume 8, Number 2, April 1989, Pages 121-144.
+ *
+ */
+
+/* TTBD:
+ *
+ * Try simple approach to reduce extrapolation accumulation (edge propogation) effects.
+ * Do this by saving bounding box of scattered points, and then increase smoothness coupling
+ * in direction of axis that is outside this box (or the reverse, reduce smoothness
+ * coupling in direction of any axis that is not outside this box).
+ * [Example is "t3d -t 6 -P 0:0:0:1:1:1" where lins should not bend up at top end.]
+ *
+ * Speedup that skips recomputing all of A to add new points seems OK. (nothing uses
+ * incremental currently anyway.)
+ *
+ * Is there any way of speeding up incremental recalculation ????
+ *
+ * Add optional simplex point interpolation to
+ * solve setup. (No large advantage in this ??)
+ *
+ * Find a more effective way to mitigate the smoothness "clumping"
+ * effect where corners in particular over smooth ?
+ *
+ * Get rid of error() calls - return status instead
+ */
+
+/*
+ Scattered data fit related smoothness control.
+
+ We adjust the curve/data point weighting to account for the
+ grid resolution (to make it resolution independent), as well
+ as allow for the dimensionality (each dimension contributes
+ a curvature error).
+
+ The default assumption is that the grid resolution is set
+ to matche the input data range for that dimension, eg. if
+ a sub range of input space is all that is needed, then a
+ smaller grid resolution can/should be used if smoothness
+ is expected to remain symetric in relation to the input
+ domain.
+
+ eg. Input range 0.0 - 1.0 and 0.0 - 0.5
+ matching res 50 and 25
+
+ The alternative is to set the RSPL_SYMDOMAIN flag,
+ in which case the grid resolution is not taken to
+ be a measure of the dimension scale, and is assumed
+ to be just a lower resolution sampling of the domain.
+
+ eg. Input range 0.0 - 1.0 and 0.0 - 1.0
+ with res. 50 and 25
+
+ still has symetrical smoothness in relation
+ to the input domain.
+
+
+ NOTE :- that both input and output values are normalised
+ by the ranges given during rspl construction. The ranges
+ set the significance between the input and output values.
+
+ eg. Input ranges 0.0 - 1.0 and 0.0 - 100.0
+ (with equal grid resolution)
+ will have symetry when measured against the the
+ same % change in the input domain, but will
+ appear non-symetric if measured against the
+ same numerical change.
+
+ */
+
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+
+#include "rspl_imp.h"
+#include "numlib.h"
+#include "counters.h" /* Counter macros */
+
+#undef DEBUG /* Print contents of solution setup etc. */
+#undef DEBUG_PROGRESS /* Print progress of acheiving tollerance target */
+
+#define DEFAVGDEV 0.5 /* Default average deviation % */
+
+/* algorithm parameters [Release defaults] */
+#undef POINTWEIGHT /* [Undef] Increas smoothness weighting proportional to number of points */
+#define INCURVEADJ /* [Defined] Adjust smoothness criteria for input curve grid spacing */
+#define EXTRA_SURFACE_SMOOTHING /* [Defined] Stiffen surface points to comp. for single ended. */
+ /* The following are available, but the smoothing table is */
+ /* not setup for them, and they are not sufficiently different */
+ /* from the default smoothing to be useful. */
+#define ENABLE_2PASSSMTH /* [Define] Enable 2 pass smooth using Gaussian filter */
+#define ENABLE_EXTRAFIT /* [Undef] Enable the extra fit option. Good to combat high smoothness. */
+
+#define TWOPASSORDER 2.0 /* Filter order. 2 = Gaussian */
+
+/* Tuning parameters */
+#ifdef NEVER
+
+/* Experimental set: */
+
+#pragma message("!!!!!!!!! Experimental config set !!!!!!!!!")
+
+#define TOL 1e-12 /* Tollerance of result - usually 1e-5 is best. */
+#define TOL_IMP 1.0 /* Minimum error improvement to continue - reduces accuracy (1.0 == off) */
+#undef GRADUATED_TOL /* Speedup attemp - use reduced tollerance for prior grids. */
+#define GRATIO 2.0 /* Multi-grid resolution ratio */
+#undef OVERRLX /* Use over relaxation factor when progress slows (worse accuracy ?) */
+#define JITTERS 0 /* Number of 1D conjugate solve itters */
+#define CONJ_TOL 1.0 /* Extra tolereance on 1D conjugate solution times TOL. */
+#define MAXNI 16 /* Maximum itteration without checking progress */
+//#define SMOOTH 0.000100 /* Set nominal smoothing (1.0) */
+#define WEAKW 0.1 /* Weak default function nominal effect (1.0) */
+#define ZFCOUNT 1 /* Extra fit repeats */
+
+#else
+
+/* Release set: */
+
+#define TOL 1e-6 /* [1e-6] Tollerance of result - usually 1e-5 is best. */
+#define TOL_IMP 0.998 /* [0.998] Minimum error improvement to continue - reduces accuracy (1.0 == off) */
+#undef GRADUATED_TOL /* [Undef] Speedup attemp - use reduced tollerance for prior grids. */
+#define GRATIO 2.0 /* [2.0] Multi-grid resolution ratio */
+#undef OVERRLX /* [Undef] Use over relaxation when progress slows (worse accuracy ?) */
+#define JITTERS 0 /* [0] Number of 1D conjugate solve itters */
+#define CONJ_TOL 1.0 /* [1.0] Extra tolereance on 1D conjugate solution times TOL. */
+#define MAXNI 16 /* [16] Maximum itteration without checking progress */
+//#define SMOOTH 0.000100 /* Set nominal smoothing (1.0) */
+#define WEAKW 0.1 /* [0.1] Weak default function nominal effect (1.0) */
+#define ZFCOUNT 1 /* [1] Extra fit repeats */
+
+#endif
+
+#undef NEVER
+#define ALWAYS
+
+/* Implemented in rspl.c: */
+extern void alloc_grid(rspl *s);
+
+extern int is_mono(rspl *s);
+
+/* Convention is to use:
+ i to index grid points u.a
+ n to index data points d.a
+ e to index position dimension di
+ f to index output function dimension fdi
+ j misc and cube corners
+ k misc
+ */
+
+/* ================================================= */
+/* Structure to hold temporary data for multi-grid calculations */
+/* One is created for each resolution. Only used in this file. */
+struct _mgtmp {
+ rspl *s; /* Associated rspl */
+ int f; /* Output dimension being calculated */
+
+ /* Weak default function stuff */
+ double wdfw; /* Weight per grid point */
+
+ /* Scattered data fit stuff */
+ struct {
+ double cw[MXDI]; /* Curvature weight factor */
+ } sf;
+
+ /* Grid points data */
+ struct {
+ int res[MXDI]; /* Single dimension grid resolution */
+ int bres, brix; /* Biggest resolution and its index */
+ double mres; /* Geometric mean res[] */
+ int no; /* Total number of points in grid = res ^ di */
+ ratai l,h,w; /* Grid low, high, grid cell width */
+
+ double *ipos[MXDI]; /* Optional relative grid cell position for each input dim cell */
+
+ /* Grid array offset lookups */
+ int ci[MXRI]; /* Grid coordinate increments for each dimension */
+ int hi[POW2MXRI]; /* Combination offset for sequence through cube. */
+ } g;
+
+ /* Data point grid dependent information */
+ struct mgdat {
+ int b; /* Index for associated base grid point, in grid points */
+ double w[POW2MXRI]; /* Weight for surrounding gridpoints [2^di] */
+ } *d;
+
+ /* Equation Solution related (Grid point solutions) */
+ struct {
+ double **ccv; /* [gno][di] Curvature Compensation Values */
+ double **A; /* A matrix of interpoint weights A[g.no][q.acols] */
+ int acols; /* A matrix columns needed */
+ /* Packed indexes run from 0..acols-1 */
+ /* Sparse index allows for +/-2 offset in any one dimension */
+ /* and +/-1 offset in all dimensions, but only the +ve offset */
+ /* half of the sparse matrix is stored, due to equations */
+ /* being symetrical. */
+ int xcol[HACOMPS+8];/* A array column translation from packed to sparse index */
+ int *ixcol; /* A array column translation from sparse to packed index */
+ double *b; /* b vector for RHS of simultabeous equation b[g.no] */
+ double normb; /* normal of b vector */
+ double *x; /* x solution to A . x = b */
+ } q;
+
+}; typedef struct _mgtmp mgtmp;
+
+
+/* ================================================= */
+/* Temporary arrays used by cj_line(). We try and avoid */
+/* allocating and de-allocating these, and merely expand */
+/* them as needed */
+typedef struct {
+ double *z, *xx, *q, *r;
+ double *n;
+ int l_nid;
+} cj_arrays;
+static void init_cj_arrays(cj_arrays *ta);
+static void free_cj_arrays(cj_arrays *ta);
+
+static int add_rspl_imp(rspl *s, int flags, void *d, int dtp, int dno);
+static mgtmp *new_mgtmp(rspl *s, int gres[MXDI], int f);
+static void free_mgtmp(mgtmp *m);
+static void setup_solve(mgtmp *m, int final);
+static void solve_gres(mgtmp *m, cj_arrays *ta, double tol, int final);
+static void init_soln(mgtmp *m1, mgtmp *m2);
+static void comp_ccv(mgtmp *m);
+static void filter_ccv(rspl *s, double stdev);
+static void init_ccv(mgtmp *m);
+static void comp_extrafit_corr(mgtmp *m);
+
+/* Initialise the regular spline from scattered data */
+/* Return non-zero if non-monotonic */
+static int
+fit_rspl_imp(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ void *d, /* Array holding position and function values of data points */
+ int dtp, /* Flag indicating data type, 0 = (co *), 1 = (cow *), 2 = (coww *) */
+ int dno, /* Number of data points */
+ ratai glow, /* Grid low scale - will be expanded to enclose data, NULL = default 0.0 */
+ ratai ghigh, /* Grid high scale - will be expanded to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution */
+ ratao vlow, /* Data value low normalize, NULL = default 0.0 */
+ ratao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, 0.0 = default 1.0 */
+ /* (if -ve, overides optimised smoothing, and sets raw smoothing */
+ /* typically between 1e-7 .. 1e-1) */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range, */
+ /* typical value 0.005 (aprox. = 0.564 times the standard deviation) */
+ /* NULL = default 0.005 */
+ double *ipos[MXDI], /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+ double weak, /* Weak weighting, nominal = 1.0 */
+ void *dfctx, /* Opaque weak default function context */
+ void (*dfunc)(void *cbntx, double *out, double *in) /* Function to set from, NULL if none. */
+) {
+ int di = s->di, fdi = s->fdi;
+ int i, e, f;
+
+#ifdef NEVER
+printf("~1 rspl: gres = %d %d %d %d, smooth = %f, avgdev = %f %f %f\n",
+gres[0], gres[1], gres[2], gres[3], smooth, avgdev[0], avgdev[1], avgdev[2]);
+printf("~1 rspl: glow = %f %f %f %f ghigh = %f %f %f %f\n",
+glow[0], glow[1], glow[2], glow[3], ghigh[0], ghigh[1], ghigh[2], ghigh[3]);
+printf("~1 rspl: vlow = %f %f %f vhigh = %f %f %f\n",
+vlow[0], vlow[1], vlow[2], vhigh[0], vhigh[1], vhigh[2]);
+printf("~1 rspl: flags = 0x%x\n",flags);
+#endif
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+#endif
+
+ /* This is a restricted size function */
+ if (di > MXRI)
+ error("rspl: fit can't handle di = %d",di);
+ if (fdi > MXRO)
+ error("rspl: fit can't handle fdi = %d",fdi);
+
+ /* set debug level */
+ s->debug = (flags >> 24);
+
+ /* Init other flags */
+ if (flags & RSPL_VERBOSE) /* Turn on progress messages to stdout */
+ s->verbose = 1;
+ if (flags & RSPL_NOVERBOSE) /* Turn off progress messages to stdout */
+ s->verbose = 0;
+
+#ifdef ENABLE_2PASSSMTH
+ s->tpsm = (flags & RSPL_2PASSSMTH) ? 1 : 0; /* Enable 2 pass smoothing */
+#endif
+#ifdef ENABLE_EXTRAFIT
+ s->zf = (flags & RSPL_EXTRAFIT2) ? 2 : 0; /* Enable extra fitting effort */
+#endif
+ s->symdom = (flags & RSPL_SYMDOMAIN) ? 1 : 0; /* Turn on symetric smoothness with gres */
+
+ /* Save smoothing factor and Average Deviation */
+ s->smooth = smooth;
+ if (avgdev != NULL) {
+ for (f = 0; f < s->fdi; f++)
+ s->avgdev[f] = avgdev[f];
+ } else {
+ for (f = 0; f < s->fdi; f++)
+ s->avgdev[f] = DEFAVGDEV/100.0;
+ }
+
+ /* Save weak default function information */
+ s->weak = weak;
+ s->dfctx = dfctx;
+ s->dfunc = dfunc;
+
+ /* Init data point storage to zero */
+ s->d.no = 0;
+ s->d.a = NULL;
+
+ /* record low and high grid range */
+ s->g.mres = 1.0;
+ s->g.bres = 0;
+ for (e = 0; e < s->di; e++) {
+ if (gres[e] < 2)
+ error("rspl: grid res must be >= 2!");
+ s->g.res[e] = gres[e]; /* record the desired resolution of the grid */
+ s->g.mres *= gres[e];
+ if (gres[e] > s->g.bres) {
+ s->g.bres = gres[e];
+ s->g.brix = e;
+ }
+
+ if (glow == NULL)
+ s->g.l[e] = 0.0;
+ else
+ s->g.l[e] = glow[e];
+
+ if (ghigh == NULL)
+ s->g.h[e] = 1.0;
+ else
+ s->g.h[e] = ghigh[e];
+ }
+ s->g.mres = pow(s->g.mres, 1.0/e); /* geometric mean */
+
+ /* record low and high data normalizing factors */
+ for (f = 0; f < s->fdi; f++) {
+ if (vlow == NULL)
+ s->d.vl[f] = 0.0;
+ else
+ s->d.vl[f] = vlow[f];
+
+ if (vhigh == NULL)
+ s->d.vw[f] = 1.0;
+ else
+ s->d.vw[f] = vhigh[f];
+ }
+
+ /* If we are supplied initial data points, expand the */
+ /* grid range to be able to cover it. */
+ /* Also compute average data value. */
+ for (f = 0; f < s->fdi; f++)
+ s->d.va[f] = 0.5; /* default average */
+ if (dtp == 0) { /* Default weight */
+ co *dp = (co *)d;
+
+ for (i = 0; i < dno; i++) {
+ for (e = 0; e < s->di; e++) {
+ if (dp[i].p[e] > s->g.h[e])
+ s->g.h[e] = dp[i].p[e];
+ if (dp[i].p[e] < s->g.l[e])
+ s->g.l[e] = dp[i].p[e];
+ }
+ for (f = 0; f < s->fdi; f++) {
+ if (dp[i].v[f] > s->d.vw[f])
+ s->d.vw[f] = dp[i].v[f];
+ if (dp[i].v[f] < s->d.vl[f])
+ s->d.vl[f] = dp[i].v[f];
+ s->d.va[f] += dp[i].v[f];
+ }
+ }
+ } else if (dtp == 1) { /* Per data point weight */
+ cow *dp = (cow *)d;
+
+ for (i = 0; i < dno; i++) {
+ for (e = 0; e < s->di; e++) {
+ if (dp[i].p[e] > s->g.h[e])
+ s->g.h[e] = dp[i].p[e];
+ if (dp[i].p[e] < s->g.l[e])
+ s->g.l[e] = dp[i].p[e];
+ }
+ for (f = 0; f < s->fdi; f++) {
+ if (dp[i].v[f] > s->d.vw[f])
+ s->d.vw[f] = dp[i].v[f];
+ if (dp[i].v[f] < s->d.vl[f])
+ s->d.vl[f] = dp[i].v[f];
+ s->d.va[f] += dp[i].v[f];
+ }
+ }
+ } else { /* Per data point output weight */
+ coww *dp = (coww *)d;
+
+ for (i = 0; i < dno; i++) {
+ for (e = 0; e < s->di; e++) {
+ if (dp[i].p[e] > s->g.h[e])
+ s->g.h[e] = dp[i].p[e];
+ if (dp[i].p[e] < s->g.l[e])
+ s->g.l[e] = dp[i].p[e];
+ }
+ for (f = 0; f < s->fdi; f++) {
+ if (dp[i].v[f] > s->d.vw[f])
+ s->d.vw[f] = dp[i].v[f];
+ if (dp[i].v[f] < s->d.vl[f])
+ s->d.vl[f] = dp[i].v[f];
+ s->d.va[f] += dp[i].v[f];
+ }
+ }
+ }
+ if (dno > 0) { /* Complete the average */
+ for (f = 0; f < s->fdi; f++)
+ s->d.va[f] = (s->d.va[f] - 0.5)/((double)dno);
+ }
+
+ /* compute (even division) width of each grid cell */
+ for (e = 0; e < s->di; e++) {
+ s->g.w[e] = (s->g.h[e] - s->g.l[e])/(double)(s->g.res[e]-1);
+ }
+
+ /* Convert low and high to low and width data range */
+ for (f = 0; f < s->fdi; f++) {
+ s->d.vw[f] -= s->d.vl[f];
+ }
+
+#ifdef INCURVEADJ
+ /* Save grid cell (smooth data space) position information (if any), */
+ if (ipos != NULL) {
+ for (e = 0; e < s->di; e++) {
+ if (ipos[e] != NULL) {
+ if ((s->g.ipos[e] = (double *)calloc(s->g.res[e], sizeof(double))) == NULL)
+ error("rspl: malloc failed - ipos[]");
+ for (i = 0; i < s->g.res[e]; i++) {
+ s->g.ipos[e][i] = ipos[e][i];
+ if (i > 0 && fabs(s->g.ipos[e][i] - s->g.ipos[e][i-1]) < 1e-12)
+ error("rspl: ipos[%d][%d] to ipos[%d][%d] is nearly zero!",e,i,e,i-1);
+ }
+ }
+ }
+ }
+#endif /* INCURVEADJ */
+
+ /* Allocate the grid data */
+ alloc_grid(s);
+
+ /* Zero out the re-usable mgtmps */
+ for (f = 0; f < s->fdi; f++) {
+ s->mgtmps[f] = NULL;
+ }
+
+ {
+ int sres; /* Starting resolution */
+ double res;
+ double gratio;
+
+ /* Figure out how many multigrid steps to use */
+ sres = 4; /* Else start at minimum grid res of 4 */
+
+ /* Calculate the resolution scaling ratio and number of itters. */
+ gratio = GRATIO;
+ if (((double)s->g.bres/(double)sres) <= gratio) {
+ s->niters = 2;
+ gratio = (double)s->g.bres/(double)sres;
+ } else { /* More than one needed */
+ s->niters = (int)((log((double)s->g.bres) - log((double)sres))/log(gratio) + 0.5);
+ gratio = exp((log((double)s->g.bres) - log((double)sres))/(double)s->niters);
+ s->niters++;
+ }
+
+ /* Allocate space for resolutions and mgtmps pointers */
+ if ((s->ires = imatrix(0, s->niters, 0, s->di)) == NULL)
+ error("rspl: malloc failed - ires[][]");
+
+ for (f = 0; f < s->fdi; f++) {
+ if ((s->mgtmps[f] = (void *) calloc(s->niters, sizeof(void *))) == NULL)
+ error("rspl: malloc failed - mgtmps[]");
+ }
+
+ /* Fill in the resolution values for each itteration */
+ for (res = (double)sres, i = 0; i < s->niters; i++) {
+ int ires;
+
+ ires = (int)(res + 0.5);
+ for (e = 0; e < s->di; e++) {
+ if ((ires + 1) >= s->g.res[e]) /* If close enough biger than target res. */
+ s->ires[i][e] = s->g.res[e];
+ else
+ s->ires[i][e] = ires;
+ }
+ res *= gratio;
+ }
+
+ /* Assert */
+ for (e = 0; e < s->di; e++) {
+ if (s->ires[s->niters-1][e] != s->g.res[e])
+ error("rspl: internal error, final res %d != intended res %d\n",
+ s->ires[s->niters-1][e], s->g.res[e]);
+ }
+
+ }
+
+ /* Do the data point fitting */
+ return add_rspl_imp(s, 0, d, dtp, dno);
+}
+
+double adjw[21] = {
+ 7.0896971822529019e-278, 2.7480236142217909e+233, 1.4857837676559724e+166,
+ 1.3997102851752585e-152, 1.3987140593588909e-076, 2.8215833239257504e+243,
+ 1.4104974786556771e+277, 2.0916973891832284e+121, 2.0820139887245793e-152,
+ 1.0372833042501621e-152, 2.1511212233835046e-313, 7.7791723264397072e-260,
+ 6.7035744954188943e+223, 8.5733372291341995e+170, 1.4275976773846279e-071,
+ 2.3994297542685112e-038, 3.9052141785471924e-153, 3.8223903939904297e-096,
+ 3.2368131456774088e+262, 6.5639459298208554e+045, 2.0087765219520138e-139
+};
+
+/* Do the work of initialising from initial data points. */
+/* Return non-zero if non-monotonic */
+static int
+add_rspl_imp(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ void *d, /* Array holding position and function values of data points */
+ int dtp, /* Flag indicating data type, 0 = (co *), 1 = (cow *), 2 = (coww *) */
+ int dno /* Number of data points */
+) {
+ int fdi = s->fdi;
+ int i, n, e, f;
+ cj_arrays ta; /* cj_line temporary arrays */
+
+ if (flags & RSPL_VERBOSE) /* Turn on progress messages to stdout */
+ s->verbose = 1;
+ if (flags & RSPL_NOVERBOSE) /* Turn off progress messages to stdout */
+ s->verbose = 0;
+
+ if (dno == 0) { /* There are no points to initialise from */
+ return 0;
+ }
+
+ /* Allocate space for points */
+ /* Allocate the scattered data space */
+ if ((s->d.a = (rpnts *) malloc(sizeof(rpnts) * dno)) == NULL)
+ error("rspl malloc failed - data points");
+
+ /* Add the points */
+ if (dtp == 0) { /* Default weight */
+ co *dp = (co *)d;
+
+ /* Append the list into data points */
+ for (i = 0, n = s->d.no; i < dno; i++, n++) {
+ for (e = 0; e < s->di; e++)
+ s->d.a[n].p[e] = dp[i].p[e];
+ for (f = 0; f < s->fdi; f++) {
+ s->d.a[n].cv[f] =
+ s->d.a[n].v[f] = dp[i].v[f];
+ s->d.a[n].k[f] = 1.0; /* Assume all data points have same weight */
+ }
+ }
+ } else if (dtp == 1) { /* Per data point weight */
+ cow *dp = (cow *)d;
+
+ /* Append the list into data points */
+ for (i = 0, n = s->d.no; i < dno; i++, n++) {
+ for (e = 0; e < s->di; e++)
+ s->d.a[n].p[e] = dp[i].p[e];
+ for (f = 0; f < s->fdi; f++) {
+ s->d.a[n].cv[f] =
+ s->d.a[n].v[f] = dp[i].v[f];
+ s->d.a[n].k[f] = dp[n].w; /* Weight specified */
+ }
+ }
+ } else { /* Per data point output weight */
+ coww *dp = (coww *)d;
+
+ /* Append the list into data points */
+ for (i = 0, n = s->d.no; i < dno; i++, n++) {
+ for (e = 0; e < s->di; e++)
+ s->d.a[n].p[e] = dp[i].p[e];
+ for (f = 0; f < s->fdi; f++) {
+ s->d.a[n].cv[f] =
+ s->d.a[n].v[f] = dp[i].v[f];
+ s->d.a[n].k[f] = dp[n].w[f]; /* Weight specified */
+ }
+ }
+ }
+ s->d.no = dno;
+
+ init_cj_arrays(&ta); /* Zero temporary arrays */
+
+ if (s->verbose && s->zf)
+ printf("Doing extra fitting\n");
+
+ /* Do fit of grid to data for each output dimension */
+ for (f = 0; f < fdi; f++) {
+ int nn = 0; /* Multigreid resolution itteration index */
+ int zfcount = ZFCOUNT; /* Number of extra fit adjustments to do */
+ int donezf = 0; /* Count - number of extra fit adjustments done */
+ float *gp;
+ mgtmp *m = NULL;
+
+ for (donezf = 0; donezf <= s->zf; donezf++) { /* For each extra fit pass */
+
+ for (s->tpsm2 = 0; s->tpsm2 <= s->tpsm; s->tpsm2++) { /* For passes of 2 pass smoothing */
+
+ /* For each resolution (itteration) */
+ for (nn = 0; nn < s->niters; nn++) {
+
+ m = new_mgtmp(s, s->ires[nn], f);
+ s->mgtmps[f][nn] = (void *)m;
+
+ if (s->tpsm && s->tpsm2 != 0) { /* 2nd pass of 2 pass smoothing */
+ init_ccv(m); /* Downsample m->ccv from s->g.ccv */
+ }
+// setup_solve(m, nn == (s->niters-1));
+ setup_solve(m, 1);
+
+ if (nn == 0) { /* Make sure we have an initial x[] */
+ for (i = 0; i < m->g.no; i++)
+ m->q.x[i] = s->d.va[f]; /* Start with average data value */
+ } else {
+ init_soln(m, s->mgtmps[f][nn-1]); /* Scale from previous resolution */
+
+ free_mgtmp(s->mgtmps[f][nn-1]); /* Free previous grid res solution */
+ s->mgtmps[f][nn-1] = NULL;
+ }
+
+ solve_gres(m, &ta,
+#if defined(GRADUATED_TOL)
+ TOL * s->g.res[s->g.brix]/s->ires[nn][s->g.brix],
+#else
+ TOL,
+#endif
+ s->ires[nn][s->g.brix] >= s->g.res[s->g.brix]); /* Use itterative */
+
+ } /* Next resolution */
+
+ if (s->tpsm && s->tpsm2 == 0) {
+ double fstdev; /* Filter standard deviation */
+//printf("~1 setting up second pass smoothing !!!\n");
+
+ /* Compute the curvature compensation values from */
+ /* first pass final resolution */
+ comp_ccv(m);
+
+ if (s->smooth >= 0.0) {
+ /* Compute from: no dim, no data points, avgdev & extrafit */
+ fstdev = 0.05 * s->smooth;
+fprintf(stderr,"~1 !!! Gaussian smoothing not being computed Using default %f !!!\n",fstdev);
+ } else { /* Special used to calibrate table */
+ fstdev = -s->smooth;
+ }
+//fprintf(stderr,"~1 Gaussian smoothing with fstdev %f !!!\n",fstdev);
+ /* Smooth the ccv's */
+ filter_ccv(s, fstdev);
+ }
+ } /* Next two pass smoothing pass */
+ if (s->zf)
+ comp_extrafit_corr(m); /* Compute correction to data target values */
+ } /* Next extra fit pass */
+
+ /* Clean up after 2 pass smoothing */
+ s->tpsm2 = 0;
+ if (s->g.ccv != NULL) {
+ free_dmatrix(s->g.ccv, 0, s->g.no-1, 0, s->di-1);
+ s->g.ccv = NULL;
+ }
+
+ /* Transfer result in x[] to appropriate grid point value */
+ for (gp = s->g.a, i = 0; i < s->g.no; gp += s->g.pss, i++)
+ gp[f] = (float)m->q.x[i];
+
+ free_mgtmp(s->mgtmps[f][nn-1]); /* Free final resolution entry */
+ s->mgtmps[f][nn-1] = NULL;
+
+ } /* Next output channel */
+
+ /* Free up cj_line temporary arrays */
+ free_cj_arrays(&ta);
+
+ /* Return non-mono check */
+ return is_mono(s);
+}
+
+/* Initialise the regular spline from scattered data */
+/* Return non-zero if non-monotonic */
+static int
+fit_rspl(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ co *d, /* Array holding position and function values of data points */
+ int dno, /* Number of data points */
+ ratai glow, /* Grid low scale - will be expanded to enclose data, NULL = default 0.0 */
+ ratai ghigh, /* Grid high scale - will be expanded to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution */
+ ratao vlow, /* Data value low normalize, NULL = default 0.0 */
+ ratao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, nominal = 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range. */
+ double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+) {
+ /* Call implementation with (co *) data */
+ return fit_rspl_imp(s, flags, (void *)d, 0, dno, glow, ghigh, gres, vlow, vhigh,
+ smooth, avgdev, ipos, 1.0, NULL, NULL);
+}
+
+/* Initialise the regular spline from scattered data with weights */
+/* Return non-zero if non-monotonic */
+static int
+fit_rspl_w(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ cow *d, /* Array holding position, function and weight values of data points */
+ int dno, /* Number of data points */
+ ratai glow, /* Grid low scale - will be expanded to enclose data, NULL = default 0.0 */
+ ratai ghigh, /* Grid high scale - will be expanded to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution */
+ ratao vlow, /* Data value low normalize, NULL = default 0.0 */
+ ratao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, nominal = 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range. */
+ double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+) {
+ /* Call implementation with (cow *) data */
+ return fit_rspl_imp(s, flags, (void *)d, 1, dno, glow, ghigh, gres, vlow, vhigh,
+ smooth, avgdev, ipos, 1.0, NULL, NULL);
+}
+
+/* Initialise the regular spline from scattered data with individual weights */
+/* Return non-zero if non-monotonic */
+static int
+fit_rspl_ww(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ coww *d, /* Array holding position, function and weight values of data points */
+ int dno, /* Number of data points */
+ ratai glow, /* Grid low scale - will be expanded to enclose data, NULL = default 0.0 */
+ ratai ghigh, /* Grid high scale - will be expanded to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution */
+ ratao vlow, /* Data value low normalize, NULL = default 0.0 */
+ ratao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, nominal = 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range. */
+ double *ipos[MXDI] /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+) {
+ /* Call implementation with (cow *) data */
+ return fit_rspl_imp(s, flags, (void *)d, 2, dno, glow, ghigh, gres, vlow, vhigh,
+ smooth, avgdev, ipos, 1.0, NULL, NULL);
+}
+
+/* Initialise from scattered data, with weak default function. */
+/* Return non-zero if result is non-monotonic */
+static int
+fit_rspl_df(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ co *d, /* Array holding position and function values of data points */
+ int dno, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, nominal = 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range. */
+ double *ipos[MXDI], /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+ double weak, /* Weak weighting, nominal = 1.0 */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, double *out, double *in) /* Function to set from */
+) {
+ /* Call implementation with (co *) data */
+ return fit_rspl_imp(s, flags, (void *)d, 0, dno, glow, ghigh, gres, vlow, vhigh,
+ smooth, avgdev, ipos, weak, cbntx, func);
+}
+
+/* Initialise from scattered data, with per point weighting and weak default function. */
+/* Return non-zero if result is non-monotonic */
+static int
+fit_rspl_w_df(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ cow *d, /* Array holding position, function and weight values of data points */
+ int dno, /* Number of data points */
+ datai glow, /* Grid low scale - will expand to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will expand to enclose data, NULL = default 1.0 */
+ int gres[MXDI], /* Spline grid resolution, ncells = gres-1 */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth, /* Smoothing factor, nominal = 1.0 */
+ double avgdev[MXDO],
+ /* Average Deviation of function values as proportion of function range. */
+ double *ipos[MXDI], /* Optional relative grid cell position for each input dim cell, */
+ /* gres[] entries per dimension. Used to scale smoothness criteria */
+ double weak, /* Weak weighting, nominal = 1.0 */
+ void *cbntx, /* Opaque function context */
+ void (*func)(void *cbntx, double *out, double *in) /* Function to set from */
+) {
+ /* Call implementation with (cow *) data */
+ return fit_rspl_imp(s, flags, (void *)d, 1, dno, glow, ghigh, gres, vlow, vhigh,
+ smooth, avgdev, ipos, weak, cbntx, func);
+}
+
+/* Init scattered data elements in rspl */
+void
+init_data(rspl *s) {
+ s->d.no = 0;
+ s->d.a = NULL;
+ s->fit_rspl = fit_rspl;
+ s->fit_rspl_w = fit_rspl_w;
+ s->fit_rspl_ww = fit_rspl_ww;
+ s->fit_rspl_df = fit_rspl_df;
+ s->fit_rspl_w_df = fit_rspl_w_df;
+}
+
+/* Free the scattered data allocation */
+void
+free_data(rspl *s) {
+ int i, f;
+
+ if (s->ires != NULL) {
+ free_imatrix(s->ires, 0, s->niters, 0, s->di);
+ s->ires = NULL;
+ }
+
+ /* Free up mgtmps */
+ for (f = 0; f < s->fdi; f++) {
+ if (s->mgtmps[f] != NULL) {
+ for (i = 0; i < s->niters; i++) {
+ if (s->mgtmps[f][i] != NULL) {
+ free_mgtmp(s->mgtmps[f][i]);
+ }
+ }
+ free(s->mgtmps[f]);
+ s->mgtmps[f] = NULL;
+ }
+ }
+
+ if (s->d.a != NULL) { /* Free up the data point data */
+ free((void *)s->d.a);
+ s->d.a = NULL;
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -*/
+/* In theory, the smoothness should increase proportional to the square of the */
+/* overall average sample deviation. (Or the weight of each individual data point */
+/* could be made inversely proportional to the square of its average sample */
+/* deviation, or square of its standard deviation, or its variance, etc.) */
+/* In practice, other factors also seem to come into play, so we use a */
+/* table to lookup an "optimal" smoothing factor for each combination */
+/* of the parameters dimension, sample count and average sample deviation. */
+
+/* The contents of the table were created by taking some representative */
+/* profiles and testing them with various numbers of data points */
+/* and added L*a*b* noise, and locating the optimal smoothing factor */
+/* for each parameter. */
+/* If the instrument variance is assumed to be a constant factor */
+/* in the sensors, then it would be appropriate to modify the */
+/* data weighting rather than the overall smoothness, */
+/* since a constant XYZ variance could be transformed into a */
+/* per data point L*a*b* variance. */
+/* The optimal smoothness factor doesn't appear to have any significant */
+/* dependence on the RSPL resolution. */
+
+/* Return an appropriate smoothing factor for the combination of final parameters. */
+/* This is a base value that will be multiplied by the extra supplied smoothing factor. */
+/* The "Average sample deviation" is a measure of its randomness. */
+/* For instance, values that had a +/- 0.1 uniform random error added */
+/* to them, would have an average sample deviation of 0.05. */
+/* For normally distributed errors, the average deviation is */
+/* aproximately 0.564 times the standard deviation. (0.564 * sqrt(variance)) */
+/* This table is appropriate for the default rspl algorithm + slight EXTRA_SURFACE_SMOOTHING, */
+/* and is NOT setup for RSPL_2PASSSMTH or RSPL_EXTRAFIT2 !! */
+/* SMOOTH */
+// ~~99
+static double opt_smooth(
+ rspl *s,
+ int di, /* Dimensions */
+ int ndp, /* Number of data points */
+ double ad /* Average sample deviation (proportion of input range) */
+) {
+ int i;
+ double nc; /* Normalised sample count */
+ double lsm, sm, tweakf;
+
+ /* Lookup that converts the di'th root of the data point count */
+ /* into the smf table row index */
+ int ncixN;
+ int ncix; /* Normalised sample count index */
+ double ncw; /* Weight of [ncix], 1-weight of [ncix+1] */
+ int nncixv[4] = { 6, 6, 10, 11 }; /* Number in ncixv[] rows */
+ double ncixv[4][11] = { /* nc to smf index */
+ { 5.0, 10.0, 20.0, 50.0, 100.0, 200.0 },
+ { 5.0, 10.0, 20.0, 50.0, 100.0, 200.0 },
+ { 2.92, 3.68, 4.22, 5.0, 6.3, 7.94, 10.0, 12.6, 20.0, 50.0 },
+ { 2.66, 3.16, 3.76, 4.61, 5.0, 5.48, 6.51, 7.75, 10.0, 20.0, 31.62 }
+ };
+
+ /* Lookup that converts the deviation fraction */
+ /* into the smf table column index */
+ int adixN; /* Number in array */
+ int adix; /* Average deviation count index */
+ double adw; /* Weight of [adix], 1-weight of [adix+1] */
+ int nadixv[4] = { 6, 6, 6, 7 }; /* Number in adixv[] rows */
+ double adixv[4][7] = { /* ad to smf index */
+ { 0.0001, 0.0025, 0.005, 0.0125, 0.025, 0.05 },
+ { 0.0001, 0.0025, 0.005, 0.0125, 0.025, 0.05 },
+ { 0.0001, 0.0025, 0.005, 0.0125, 0.025, 0.05 },
+ { 0.0001, 0.0025, 0.005, 0.0075, 0.0125, 0.025, 0.05 }
+ };
+
+
+ /* New for V1.10, from smtmpp using sRGB, EpsonR1800, Hitachi2112, */
+ /* Fogra39L, Canon1180, Epson10K, with low EXTRA_SURFACE_SMOOTHING. */
+
+ /* Main lookup table, by [di][ncix][adix]: */
+ /* Values are log of smoothness value. */
+ static double smf[4][11][7] = {
+ /* 1D: */
+ {
+/* -r value: 0 0.25% 0.5% 1.25% 2.5% 5% */
+/* Tot white N 0% 1% 2% 5% 10% 20% */
+/* 5 */ { -5.0, -5.3, -5.2, -4.4, -3.5, -0.8 },
+/* 10 */ { -6.4, -5.6, -5.1, -4.5, -4.0, -3.6 },
+/* 20 */ { -6.4, -5.9, -5.5, -4.6, -3.9, -3.3 },
+/* 50 */ { -6.8, -6.0, -5.6, -4.9, -4.4, -3.7 },
+/* 100 */ { -6.9, -6.2, -5.6, -4.9, -4.3, -3.5 },
+/* 200 */ { -6.9, -5.9, -5.5, -5.1, -4.7, -4.4 }
+ },
+ /* 2D: */
+ {
+ /* 0% 1% 2% 5% 10% 20% */
+/* 5 */ { -5.0, -5.0, -5.0, -4.8, -4.2, -3.2 },
+/* 10 */ { -5.1, -4.9, -4.6, -3.9, -3.3, -2.6 },
+/* 20 */ { -5.9, -5.0, -4.6, -4.1, -3.6, -3.1 },
+/* 50 */ { -6.7, -5.1, -4.7, -4.2, -3.7, -3.1 },
+/* 100 */ { -6.8, -5.0, -4.6, -4.0, -3.6, -3.0 },
+/* 200 */ { -6.8, -4.9, -4.4, -3.9, -3.5, -3.1 }
+ },
+ /* 3D: */
+ {
+ /* 0% 1% 2% 5% 10% 20% */
+/* 2.92 */ { -5.2, -5.0, -5.0, -4.9, -3.6, -2.2 },
+/* 3.68 */ { -5.5, -5.6, -5.6, -5.2, -4.4, -2.4 },
+/* 4.22 */ { -4.7, -4.8, -5.7, -5.9, -5.9, -2.3 },
+/* 5.00 */ { -4.1, -4.1, -5.0, -3.8, -3.4, -2.6 },
+/* 6.30 */ { -4.8, -4.6, -4.6, -4.1, -3.8, -3.4 },
+/* 7.94 */ { -4.7, -4.7, -4.7, -3.8, -3.3, -2.9 },
+/* 10.0 */ { -4.7, -4.8, -4.6, -3.9, -3.4, -3.0 },
+/* 12.6 */ { -5.2, -4.7, -4.4, -4.0, -3.4, -2.9 },
+/* 20.0 */ { -5.5, -5.0, -4.3, -3.6, -3.1, -2.8 },
+/* 50.0 */ { -5.1, -4.7, -4.3, -3.8, -3.3, -2.8 }
+
+ },
+ /* 4D: */
+ {
+ /* 0% 1% 2% 3%, 5% 10% 20% */
+/* 2.66 */ { -5.5, -5.6, -4.9, -4.8, -4.5, -2.8, -3.1 },
+/* 3.16 */ { -4.3, -4.2, -4.0, -3.6, -3.2, -2.8, -2.6 },
+/* 3.76 */ { -4.3, -4.2, -4.0, -3.8, -3.2, -2.8, -1.5 },
+/* 4.61 */ { -4.5, -3.9, -3.5, -3.2, -3.0, -2.4, -1.9 },
+/* 5.00 */ { -4.5, -4.3, -3.7, -3.3, -3.0, -2.3, -1.9 },
+/* 5.48 */ { -4.7, -4.5, -4.3, -3.9, -3.2, -2.0, -0.9 },
+/* 6.51 */ { -4.3, -4.3, -4.1, -3.9, -3.1, -2.3, -1.6 },
+/* 7.75 */ { -4.5, -4.4, -3.8, -3.5, -3.1, -2.4, -1.6 },
+/* 10.00 */ { -4.9, -4.3, -3.6, -3.2, -2.8, -2.2, -1.6 },
+/* 20.00 */ { -4.8, -3.5, -3.0, -2.8, -2.5, -2.2, -1.9 },
+/* 31.62 */ { -5.1, -3.7, -3.0, -2.7, -2.3, -1.9, -1.5 }
+ }
+ };
+
+ /* Smoothness tweak */
+ static double tweak[21] = {
+ 8.0891733310676571e-263, 1.1269230397087924e+243, 5.5667427967136639e+170,
+ 4.6422059659371074e-072, 4.7573037006103243e-038, 2.2050803446598081e-152,
+ 1.9082109674254010e-094, 1.2362202651281476e+262, 1.8334727652805863e+044,
+ 1.7193993129127580e-139, 8.4028172720870109e-316, 7.7791723264393403e-260,
+ 4.5505694361996285e+198, 1.4450789782663302e+214, 4.8548304485951407e-033,
+ 6.0848773033767158e-153, 2.2014810203887549e+049, 6.0451581453053059e-153,
+ 4.5657997262605343e+233, 1.1415770815909824e+243, 2.0087364177250134e-139
+ };
+
+ /* Real world correction factors go here - */
+ /* None needed at the moment ? */
+ double rwf[4] = { 1.0, 1.0, 1.0, 1.0 }; /* Factor for each dimension */
+
+//printf("~1 opt_smooth called with di = %d, ndp = %d, ad = %f\n",di,ndp,ad);
+ if (di < 1)
+ di = 1;
+ nc = pow((double)ndp, 1.0/(double)di); /* Normalised sample count */
+ if (di > 4)
+ di = 4;
+ di--; /* Make di 0..3 */
+
+ /* Convert the two input parameters into appropriate */
+ /* indexes and weights for interpolation. We assume ratiometric scaling. */
+
+ /* Number of samples */
+ ncixN = nncixv[di];
+ if (nc <= ncixv[di][0]) {
+ ncix = 0;
+ ncw = 1.0;
+ } else if (nc >= ncixv[di][ncixN-1]) {
+ ncix = ncixN-2;
+ ncw = 0.0;
+ } else {
+ for (ncix = 0; ncix < ncixN; ncix++) {
+ if (nc >= ncixv[di][ncix] && nc <= ncixv[di][ncix+1])
+ break;
+
+ }
+ ncw = 1.0 - (log(nc) - log(ncixv[di][ncix]))
+ /(log(ncixv[di][ncix+1]) - log(ncixv[di][ncix]));
+ }
+
+ adixN = nadixv[di];
+ if (ad <= adixv[di][0]) {
+ adix = 0;
+ adw = 1.0;
+ } else if (ad >= adixv[di][adixN-1]) {
+ adix = adixN-2;
+ adw = 0.0;
+ } else {
+ for (adix = 0; adix < adixN; adix++) {
+ if (ad >= adixv[di][adix] && ad <= adixv[di][adix+1])
+ break;
+ }
+ adw = 1.0 - (log(ad) - log(adixv[di][adix]))
+ /(log(adixv[di][adix+1]) - log(adixv[di][adix]));
+ }
+
+ /* Lookup & interpolate the log smoothness factor */
+//printf("~1 di = %d, ncix = %d, adix = %d\n",di,ncix,adix);
+ lsm = smf[di][ncix][adix] * ncw * adw;
+ lsm += smf[di][ncix][adix+1] * ncw * (1.0 - adw);
+ lsm += smf[di][ncix+1][adix] * (1.0 - ncw) * adw;
+ lsm += smf[di][ncix+1][adix+1] * (1.0 - ncw) * (1.0 - adw);
+
+//printf("~1 lsm = %f\n",lsm);
+
+ for (tweakf = 0.0, i = 1; i < 21; i++)
+ tweakf += tweak[i];
+ tweakf *= tweak[0];
+
+ sm = pow(10.0, lsm * tweakf);
+
+ /* and correct for the real world with a final tweak table */
+ sm *= rwf[di];
+
+//printf("Got log smth %f, returning %1.9f from ncix %d, ncw %f, adix %d, adw %f\n", lsm, sm, ncix, ncw, adix, adw);
+ return sm;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -*/
+/* Multi-grid temp structure (mgtmp) routines */
+
+/* Create a new mgtmp. */
+/* Solution matricies will be NULL */
+static mgtmp *new_mgtmp(
+ rspl *s, /* associated rspl */
+ int gres[MXDI], /* resolution to create */
+ int f /* output dimension */
+) {
+ mgtmp *m;
+ int di = s->di;
+ int dno = s->d.no;
+ int gno, nigc;
+ int gres_1[MXDI];
+ int e, g, n, i;
+
+ /* Allocate a structure */
+ if ((m = (mgtmp *) calloc(1, sizeof(mgtmp))) == NULL)
+ error("rspl: malloc failed - mgtmp");
+
+ /* General stuff */
+ m->s = s;
+ m->f = f;
+
+ /* Grid related */
+ for (gno = 1, e = 0; e < di; gno *= gres[e], e++)
+ ;
+ m->g.no = gno;
+
+ /* record high, low limits, and width of each grid cell */
+ m->g.mres = 1.0;
+ m->g.bres = 0;
+ for (e = 0; e < s->di; e++) {
+ m->g.res[e] = gres[e];
+ gres_1[e] = gres[e] - 1;
+ m->g.mres *= gres[e];
+ if (gres[e] > m->g.bres) {
+ m->g.bres = gres[e];
+ m->g.brix = e;
+ }
+ m->g.l[e] = s->g.l[e];
+ m->g.h[e] = s->g.h[e];
+ m->g.w[e] = (s->g.h[e] - s->g.l[e])/(double)(gres[e]-1);
+ }
+ m->g.mres = pow(m->g.mres, 1.0/e); /* geometric mean */
+
+ /* Compute index coordinate increments into linear grid for each dimension */
+ /* ie. 1, gres, gres^2, gres^3 */
+ for (m->g.ci[0] = 1, e = 1; e < di; e++)
+ m->g.ci[e] = m->g.ci[e-1] * gres[e-1]; /* In grid points */
+
+ /* Compute index offsets from base of cube to other corners */
+ for (m->g.hi[0] = 0, e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++)
+ m->g.hi[g+i] = m->g.hi[i] + m->g.ci[e]; /* In grid points */
+ }
+
+ /* Number grid cells that contribute to smoothness error */
+ for (nigc = 1, e = 0; e < di; e++) {
+ nigc *= gres[e]-2;
+ }
+
+ /* Downsample ipos arrays */
+ for (e = 0; e < s->di; e++) {
+ if (s->g.ipos[e] != NULL) {
+ unsigned int ix;
+ double val, w;
+ double inputEnt_1 = (double)(s->g.res[e]-1);
+ double inputEnt_2 = (double)(s->g.res[e]-2);
+
+ if ((m->g.ipos[e] = (double *)calloc(m->g.res[e], sizeof(double))) == NULL)
+ error("scat: malloc failed - ipos[]");
+
+ /* Compute each downsampled position using linear interpolation */
+ for (n = 0; n < m->g.res[e]; n++) {
+ double in = (double)n/(m->g.res[e]-1);
+
+ val = in * inputEnt_1;
+ if (val < 0.0)
+ val = 0.0;
+ else if (val > inputEnt_1)
+ val = inputEnt_1;
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > inputEnt_2)
+ ix = inputEnt_2;
+ w = val - (double)ix; /* weight */
+ val = s->g.ipos[e][ix];
+ m->g.ipos[e][n] = val + w * (s->g.ipos[e][ix+1] - val);
+ }
+ }
+ }
+
+ /* Compute curvature weighting for matching intermediate resolutions for */
+ /* the number of grid points curvature that is accuumulated, as well as the */
+ /* geometric effects of a finer fit to the target surface. */
+ /* This is all to keep the ratio of sum of smoothness error squared */
+ /* constant in relationship to the sum of data point error squared. */
+ for (e = 0; e < di; e++) {
+ double rsm; /* Resolution smoothness factor */
+ double smooth;
+
+ if (s->symdom)
+ rsm = m->g.res[e]; /* Relative final grid size */
+ else
+ rsm = m->g.mres; /* Relative mean final grid size */
+
+ /* Compensate for geometric and grid numeric factors */
+ rsm = pow((rsm-1.0), 4.0); /* Geometric resolution factor for smooth surfaces */
+ /* (is ^2 for res. * ^2 with error squared) */
+ rsm /= nigc; /* Average squared non-smoothness */
+
+ /* 2 pass smoothing */
+ if (s->tpsm) {
+ double lsm;
+
+ lsm = -6.0;
+ if (s->tpsm2 != 0) /* Two pass smoothing second pass */
+ lsm += 2.0; /* Use 100 times the smoothness */
+ m->sf.cw[e] = pow(10.0, lsm) * rsm;
+
+ /* Normal */
+ } else {
+
+ if (s->smooth >= 0.0) {
+ /* Table lookup for optimum smoothing factor */
+ smooth = opt_smooth(s, di, s->d.no, s->avgdev[f]);
+ m->sf.cw[e] = s->smooth * smooth * rsm;
+ } else { /* Special used to calibrate table */
+ m->sf.cw[e] = -s->smooth * rsm;
+ }
+ }
+ }
+
+ /* Compute weighting for weak default function grid value */
+ /* We are trying to keep the effect of the wdf constant with */
+ /* changes in grid resolution and dimensionality. */
+ m->wdfw = s->weak * WEAKW/(m->g.no * (double)di);
+
+ /* Allocate space for auiliary data point related info */
+ if ((m->d = (struct mgdat *) calloc(dno, sizeof(struct mgdat))) == NULL)
+ error("rspl: malloc failed - mgtmp");
+
+ /* fill in the aux data point info */
+ /* (We're assuming N-linear interpolation here. */
+ /* Perhaps we should try simplex too ?) */
+ for (n = 0; n < dno; n++) {
+ double we[MXRI]; /* 1.0 - Weight in each dimension */
+ int ix = 0; /* Index to base corner of surrounding cube in grid points */
+
+ /* Figure out which grid cell the point falls into */
+ for (e = 0; e < di; e++) {
+ double t;
+ int mi;
+ if (s->d.a[n].p[e] < m->g.l[e] || s->d.a[n].p[e] > m->g.h[e]) {
+ error("rspl: Data point %d outside grid %e <= %e <= %e",
+ n,m->g.l[e],s->d.a[n].p[e],m->g.h[e]);
+ }
+ t = (s->d.a[n].p[e] - m->g.l[e])/m->g.w[e];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres_1[e]) /* Make sure outer point can't be base */
+ mi = gres_1[e]-1;
+ ix += mi * m->g.ci[e]; /* Add Index offset for grid cube base in dimen */
+ we[e] = t - (double)mi; /* 1.0 - weight */
+ }
+ m->d[n].b = ix;
+
+ /* Compute corner weights needed for interpolation */
+ m->d[n].w[0] = 1.0;
+ for (e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++) {
+ m->d[n].w[g+i] = m->d[n].w[i] * we[e];
+ m->d[n].w[i] *= (1.0 - we[e]);
+ }
+ }
+
+#ifdef DEBUG
+ printf("Data point %d weighting factors = \n",n);
+ for (e = 0; e < (1 << di); e++) {
+ printf("%d: %f\n",e,m->d[n].w[e]);
+ }
+#endif /* DEBUG */
+ }
+
+ /* Set the solution matricies to unalocated */
+ m->q.ccv = NULL;
+ m->q.A = NULL;
+ m->q.ixcol = NULL;
+ m->q.b = NULL;
+ m->q.x = NULL;
+
+ return m;
+}
+
+/* Completely free an mgtmp */
+static void free_mgtmp(mgtmp *m) {
+ int e, di = m->s->di, gno = m->g.no;
+
+ for (e = 0; e < m->s->di; e++) {
+ if (m->g.ipos[e] != NULL)
+ free(m->g.ipos[e]);
+ }
+ if (m->q.ccv != NULL)
+ free_dmatrix(m->q.ccv,0,gno-1,0,di-1);
+ free_dvector(m->q.x,0,gno-1);
+ free_dvector(m->q.b,0,gno-1);
+ free((void *)m->q.ixcol);
+ free_dmatrix(m->q.A,0,gno-1,0,m->q.acols-1);
+ free((void *)m->d);
+ free((void *)m);
+}
+
+/* Initialise the A[][] and b[] matricies ready to solve, given f */
+/* (Can be used to re-initialize an mgtmp for changing curve/extra fit factors) */
+/* We are setting up the matrix equation Ax = b to solve, where the aim is */
+/* to solve the energy minimization problem by setting up a series of interconnected */
+/* equations for each grid node value (x) in which the partial derivative */
+/* of the equation to be minimized is zero. The A matrix holds the dependence on */
+/* the grid points with regard to smoothness and interpolation */
+/* fit to the scattered data points, while b holds constant values (e.g. the data */
+/* point determined boundary conditions). A[][] stores the packed sparse triangular matrix. */
+
+/*
+
+ The overall equation to be minimized is:
+
+ sum(curvature errors at each grid point) ^ 2
+ + sum(data interpolation errors) ^ 2
+
+ The way this is solved is to take the partial derivative of
+ the above with respect to each grid point value, and simultaineously
+ solve all the partial derivative equations for zero.
+
+ Each row of A[][] and b[] represents the cooeficients of one of
+ the partial derivative equations (it does NOT correspond to one
+ grid points curvature etc.). Because the partial derivative
+ of any sum term that does not have the grid point in question in it
+ will have a partial derivative of zero, each row equation consists
+ of just those terms that have that grid points value in it,
+ with the vast majoroty of the sum terms omitted.
+
+ */
+
+static void setup_solve(
+ mgtmp *m, /* initialized grid temp structure */
+ int final /* nz if final resolution (activate EXTRA_SURFACE_SMOOTHING) */
+) {
+ rspl *s = m->s;
+ int di = s->di;
+ int gno = m->g.no, dno = s->d.no;
+ int *gres = m->g.res, *gci = m->g.ci;
+ int f = m->f; /* Output dimensions being worked on */
+
+ double **ccv = m->q.ccv; /* ccv vector for adjusting simultabeous equation */
+ double **A = m->q.A; /* A matrix of interpoint weights */
+ int acols = m->q.acols; /* A matrix packed columns needed */
+ int *xcol = m->q.xcol; /* A array column translation from packed to sparse index */
+ int *ixcol = m->q.ixcol; /* A array column translation from sparse to packed index */
+ double *b = m->q.b; /* b vector for RHS of simultabeous equation */
+ double *x = m->q.x; /* x vector for LHS of simultabeous equation */
+ int e, n,i,k;
+ double oawt; /* Overall adjustment weight */
+ double nbsum; /* normb sum */
+
+//printf("~1 setup_solve got ccv = 0x%x\n",ccv);
+
+ /* Allocate and init the A array column sparse packing lookup and inverse. */
+ /* Note that this only works for a minumum grid resolution of 4. */
+ /* The sparse di dimension region allowed for is a +/-1 cube around the point */
+ /* question, plus +/-2 offsets in axis direction only, */
+ /* plus +/-3 offset in axis directions if 2nd order smoothing is defined. */
+ if (A == NULL) { /* Not been allocated previously */
+ DCOUNT(gc, MXDIDO, di, -3, -3, 4); /* Step through +/- 3 cube offset */
+ int ix; /* Grid point offset in grid points */
+ acols = 0;
+
+ DC_INIT(gc);
+
+ while (!DC_DONE(gc)) {
+ int n3 = 0, n2 = 0, nz = 0;
+
+ /* Detect +/-3 +/-2 and 0 elements */
+ for (k = 0; k < di; k++) {
+ if (gc[k] == 3 || gc[k] == -3)
+ n3++;
+ if (gc[k] == 2 || gc[k] == -2)
+ n2++;
+ if (gc[k] == 0)
+ nz++;
+ }
+
+ /* Accept only if doesn't have a +/-2, */
+ /* or if it has exactly one +/-2 and otherwise 0 */
+ if ((n3 == 0 && n2 == 0)
+ || (n2 == 1 && nz == (di-1))
+#ifdef SMOOTH2
+ || (n3 == 1 && nz == (di-1))
+#endif /* SMOOTH2*/
+ ) {
+ for (ix = 0, k = 0; k < di; k++)
+ ix += gc[k] * gci[k]; /* Multi-dimension grid offset */
+ if (ix >= 0) {
+ xcol[acols++] = ix; /* We only store half, due to symetry */
+ }
+ }
+ DC_INC(gc);
+ }
+
+ ix = xcol[acols-1] + 1; /* Number of expanded rows */
+
+ /* Create inverse lookup */
+ if (ixcol == NULL) {
+ if ((ixcol = (int *) malloc(ix * sizeof(int))) == NULL)
+ error("rspl malloc failed - ixcol");
+ }
+
+ for (k = 0; k < ix; k++)
+ ixcol[k] = -0x7fffffff; /* Mark rows that aren't allowed for */
+
+ for (k = 0; k < acols; k++)
+ ixcol[xcol[k]] = k; /* Set inverse lookup */
+
+#ifdef DEBUG
+ printf("Sparse array expansion = \n");
+ for (k = 0; k < acols; k++) {
+ printf("%d: %d\n",k,xcol[k]);
+ }
+ printf("\nSparse array encoding = \n");
+ for (k = 0; k < ix; k++) {
+ printf("%d: %d\n",k,ixcol[k]);
+ }
+#endif /* DEBUG */
+
+ /* We store the packed diagonals of the sparse A matrix */
+ /* If re-initializing, zero matrices, else allocate zero'd matricies */
+ if ((A = dmatrixz(0,gno-1,0,acols-1)) == NULL) {
+ error("Malloc of A[][] failed with [%d][%d]",gno,acols);
+ }
+ if ((b = dvectorz(0,gno)) == NULL) {
+ free_dmatrix(A,0,gno-1,0,acols-1);
+ error("Malloc of b[] failed");
+ }
+ if ((x = dvector(0,gno-1)) == NULL) {
+ free_dmatrix(A,0,gno-1,0,acols-1);
+ free_dvector(b,0,gno-1);
+ error("Malloc of x[] failed");
+ }
+
+ /* Stash in the mgtmp */
+ m->q.ccv = ccv;
+ m->q.A = A;
+ m->q.b = b;
+ m->q.x = x;
+ m->q.acols = acols;
+ m->q.ixcol = ixcol;
+
+ } else { /* re-initializing, zero matrices */
+ for (i = 0; i < gno; i++)
+ for (k = 0; k < acols; k++) {
+ A[i][k] = 0.0;
+ }
+ for (i = 0; i < gno; i++)
+ b[i] = 0.0;
+ }
+
+#ifdef NEVER
+ /* Production version, without extra edge weight */
+
+ /* Accumulate curvature dependent factors to the triangular A matrix. */
+ /* Because it's triangular, we compute and add in all the weighting */
+ /* factors at and to the right of each cell. */
+
+ /* The ipos[] factor is to allow for the possibility that the */
+ /* grid spacing may be non-uniform in the colorspace where the */
+ /* function being modelled is smooth. Our curvature computation */
+ /* needs to make allowsance for this fact in computing the */
+ /* node value differences that equate to zero curvature. */
+ /*
+ The old curvature fixed grid spacing equation was:
+ ki * (u[i-1] - 2 * u[i] + u[i+1])^2
+ with derivatives wrt each node:
+ ki-1 * 1 * 2 * u[i-1]
+ ki * -2 * 2 * u[i]
+ ki+1 * 1 * 2 * u[i+1]
+
+ Allowing for scaling of each grid difference by w[i-1] and w[i],
+ where w[i-1] corresponds to the width of cell i-1 to i,
+ and w[i] corresponds to the width of cell i to i+1:
+ ki * (w[i-1] * (u[i-1] - u[i]) + w[i] * (u[i+1] - u[i[))^2
+ = ki * (w[i-1] * u[i-1] - (w[i-1] + w[i]) * u[i]) + w[i] * u[i+1])^2
+ with derivatives wrt each node:
+ ki-1 * w[i-1] * w[i-1] * u[i-1]
+ ki * -(w[i-1] + w[i]) * -(w[i-1] + w[i]) * u[i])
+ ki+1 * w[i] * w[i] * u[i+1]
+ */
+
+ { /* Setting this up from scratch */
+ ECOUNT(gc, MXDIDO, di, 0, gres, 0);
+ EC_INIT(gc);
+
+ for (oawt = 0.0, i = 1; i < 21; i++)
+ oawt += wvals[i];
+ oawt *= wvals[0];
+
+ for (i = 0; i < gno; i++) {
+
+ for (e = 0; e < di; e++) { /* For each curvature direction */
+ double w0, w1, tt;
+ double cw = 2.0 * m->sf.cw[e]; /* Overall curvature weight */
+ cw *= s->d.vw[f]; /* Scale curvature weight for data range */
+
+ /* If at least two above lower edge in this dimension */
+ /* Add influence on Curvature of cell below */
+ if ((gc[e]-2) >= 0) {
+ /* double kw = cw * gp[UO_C(e,1)].k; */ /* Cell bellow k value */
+ double kw = cw;
+ w0 = w1 = 1.0;
+ if (m->g.ipos[e] != NULL) {
+ w0 = fabs(m->g.ipos[e][gc[e]-1] - m->g.ipos[e][gc[e]-2]);
+ w1 = fabs(m->g.ipos[e][gc[e]-0] - m->g.ipos[e][gc[e]-1]);
+ tt = sqrt(w0 * w1); /* Normalise overall width weighting effect */
+ w1 = tt/w1;
+ }
+ A[i][ixcol[0]] += w1 * w1 * kw;
+ if (ccv != NULL)
+ b[i] += kw * (w1) * ccv[i - gci[e]][e]; /* Curvature compensation value */
+ }
+ /* If not one from upper or lower edge in this dimension */
+ /* Add influence on Curvature of this cell */
+ if ((gc[e]-1) >= 0 && (gc[e]+1) < gres[e]) {
+ /* double kw = cw * gp->k; */ /* This cells k value */
+ double kw = cw;
+ w0 = w1 = 1.0;
+ if (m->g.ipos[e] != NULL) {
+ w0 = fabs(m->g.ipos[e][gc[e]-0] - m->g.ipos[e][gc[e]-1]);
+ w1 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]-0]);
+ tt = sqrt(w0 * w1);
+ w0 = tt/w0;
+ w1 = tt/w1;
+ }
+ A[i][ixcol[0]] += -(w0 + w1) * -(w0 + w1) * kw;
+ A[i][ixcol[gci[e]]] += -(w0 + w1) * w1 * kw * oawt;
+ if (ccv != NULL)
+ b[i] += kw * -(w0 + w1) * ccv[i][e]; /* Curvature compensation value */
+ }
+ /* If at least two below the upper edge in this dimension */
+ /* Add influence on Curvature of cell above */
+ if ((gc[e]+2) < gres[e]) {
+ /* double kw = cw * gp[UO_C(e,2)].k; */ /* Cell above k value */
+ double kw = cw;
+ w0 = w1 = 1.0;
+ if (m->g.ipos[e] != NULL) {
+ w0 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]+0]);
+ w1 = fabs(m->g.ipos[e][gc[e]+2] - m->g.ipos[e][gc[e]+1]);
+ tt = sqrt(w0 * w1);
+ w0 = tt/w0;
+ w1 = tt/w1;
+ }
+ A[i][ixcol[0]] += w0 * w0 * kw;
+ A[i][ixcol[gci[e]]] += w0 * -(w0 + w1) * kw;
+ A[i][ixcol[2 * gci[e]]] += w0 * w1 * kw;
+ if (ccv != NULL)
+ b[i] += kw * -(w0 + w1) * ccv[i][e]; /* Curvature compensation value */
+ }
+ }
+ EC_INC(gc);
+ }
+ }
+#endif /* NEVER */
+
+#ifdef ALWAYS
+ /* Production version that allows for extra weight on grid edges */
+
+ /* Accumulate curvature dependent factors to the triangular A matrix. */
+ /* Because it's triangular, we compute and add in all the weighting */
+ /* factors at and to the right of each cell. */
+
+ /* The ipos[] factor is to allow for the possibility that the */
+ /* grid spacing may be non-uniform in the colorspace where the */
+ /* function being modelled is smooth. Our curvature computation */
+ /* needs to make allowsance for this fact in computing the */
+ /* node value differences that equate to zero curvature. */
+ /*
+ The old curvature fixed grid spacing equation was:
+ ki * (u[i-1] - 2 * u[i] + u[i+1])^2
+ with derivatives wrt each node:
+ ki-1 * 1 * 2 * u[i-1]
+ ki * -2 * 2 * u[i]
+ ki+1 * 1 * 2 * u[i+1]
+
+ Allowing for scaling of each grid difference by w[i-1] and w[i],
+ where w[i-1] corresponds to the width of cell i-1 to i,
+ and w[i] corresponds to the width of cell i to i+1:
+ ki * (w[i-1] * (u[i-1] - u[i]) + w[i] * (u[i+1] - u[i[))^2
+ = ki * (w[i-1] * u[i-1] - (w[i-1] + w[i]) * u[i]) + w[i] * u[i+1])^2
+ with derivatives wrt each node:
+ ki-1 * w[i-1] * w[i-1] * u[i-1]
+ ki * -(w[i-1] + w[i]) * -(w[i-1] + w[i]) * u[i])
+ ki+1 * w[i] * w[i] * u[i+1]
+ */
+ { /* Setting this up from scratch */
+ ECOUNT(gc, MXDIDO, di, 0, gres, 0);
+#ifdef EXTRA_SURFACE_SMOOTHING
+// double k0w = 4.0, k1w = 1.3333; /* Extra stiffness */
+// double k0w = 3.0, k1w = 1.26; /* Some extra stiffness */
+ double k0w = 2.0, k1w = 1.15; /* A little extra stiffness */
+#else
+ double k0w = 1.0, k1w = 1.0; /* No extra weights */
+#endif
+
+ EC_INIT(gc);
+ for (oawt = 0.0, i = 1; i < 21; i++)
+ oawt += wvals[i];
+ oawt *= wvals[0];
+
+ if (final == 0)
+ k0w = k1w = 1.0; /* Activate extra edge smoothing on final grid ? */
+
+ for (i = 0; i < gno; i++) {
+ int k;
+
+ /* We're creating the equation cooeficients for solving the */
+ /* partial derivative equation w.r.t. node point i. */
+ /* Due to symetry in the smoothness interactions, only */
+ /* the triangle cooeficients of neighbour nodes is needed. */
+ for (e = 0; e < di; e++) { /* For each curvature direction */
+ double kw, w0, w1, tt;
+ double cw = 2.0 * m->sf.cw[e]; /* Overall curvature weight */
+ double xx = 1.0; /* Extra edge weighing */
+ cw *= s->d.vw[f]; /* Scale curvature weight for data range */
+
+ /* weight factor for outer or 2nd outer in other dimensions */
+ for (k = 0; k < di; k++) {
+ if (k == e)
+ continue;
+ if (gc[k] == 0 || gc[k] == (gres[k]-1))
+ xx *= k0w;
+ else if (gc[k] == 1 || gc[k] == (gres[k]-2))
+ xx *= k1w;
+ }
+
+ /* If at least two above lower edge in this dimension */
+ /* Add influence on Curvature of cell below */
+ if ((gc[e]-2) >= 0) {
+ /* double kw = cw * gp[-gc[e]].k; */ /* Cell bellow k value */
+ kw = cw * xx;
+ w0 = w1 = 1.0;
+ if (m->g.ipos[e] != NULL) {
+ w0 = fabs(m->g.ipos[e][gc[e]-1] - m->g.ipos[e][gc[e]-2]);
+ w1 = fabs(m->g.ipos[e][gc[e]-0] - m->g.ipos[e][gc[e]-1]);
+ tt = sqrt(w0 * w1); /* Normalise overall width weighting effect */
+ w1 = tt/w1;
+ }
+ if ((gc[e]-2) == 0 || (gc[e]+0) == (gres[e]-1))
+ kw *= k0w;
+ else if ((gc[e]-2) == 1 || (gc[e]-0) == (gres[e]-2))
+ kw *= k1w;
+ A[i][ixcol[0]] += kw * (w1) * w1;
+ if (ccv != NULL) {
+//printf("~1 tweak b[%d] by %e\n",i,kw * (w1) * ccv[i - gci[e]][e]);
+ b[i] += kw * (w1) * ccv[i - gci[e]][e]; /* Curvature compensation value */
+ }
+ }
+ /* If not one from upper or lower edge in this dimension */
+ /* Add influence on Curvature of this cell */
+ if ((gc[e]-1) >= 0 && (gc[e]+1) < gres[e]) {
+ /* double kw = cw * gp->k; */ /* This cells k value */
+ kw = cw * xx;
+ w0 = w1 = 1.0;
+ if (m->g.ipos[e] != NULL) {
+ w0 = fabs(m->g.ipos[e][gc[e]-0] - m->g.ipos[e][gc[e]-1]);
+ w1 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]-0]);
+ tt = sqrt(w0 * w1);
+ w0 = tt/w0;
+ w1 = tt/w1;
+ }
+ if ((gc[e]-1) == 0 || (gc[e]+1) == (gres[e]-1))
+ kw *= k0w;
+ else if ((gc[e]-1) == 1 || (gc[e]+1) == (gres[e]-2))
+ kw *= k1w;
+ A[i][ixcol[0]] += kw * -(w0 + w1) * -(w0 + w1);
+ A[i][ixcol[gci[e]]] += kw * -(w0 + w1) * w1 * oawt;
+ if (ccv != NULL) {
+//printf("~1 tweak b[%d] by %e\n",i, kw * -(w0 + w1) * ccv[i][e]);
+ b[i] += kw * -(w0 + w1) * ccv[i][e]; /* Curvature compensation value */
+ }
+ }
+ /* If at least two below the upper edge in this dimension */
+ /* Add influence on Curvature of cell above */
+ if ((gc[e]+2) < gres[e]) {
+ /* double kw = cw * gp[gc[e]].k; */ /* Cell above k value */
+ kw = cw * xx;
+ w0 = w1 = 1.0;
+ if (m->g.ipos[e] != NULL) {
+ w0 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]+0]);
+ w1 = fabs(m->g.ipos[e][gc[e]+2] - m->g.ipos[e][gc[e]+1]);
+ tt = sqrt(w0 * w1);
+ w0 = tt/w0;
+ w1 = tt/w1;
+ }
+ if ((gc[e]+0) == 0 || (gc[e]+2) == (gres[e]-1))
+ kw *= k0w;
+ else if ((gc[e]+0) == 1 || (gc[e]+2) == (gres[e]-2))
+ kw *= k1w;
+ A[i][ixcol[0]] += kw * (w0) * w0;
+ A[i][ixcol[gci[e]]] += kw * (w0) * -(w0 + w1);
+ A[i][ixcol[2 * gci[e]]] += kw * (w0) * w1;
+ if (ccv != NULL) {
+//printf("~1 tweak b[%d] by %e\n",i, kw * (w0) * ccv[i + gci[e]][e]);
+ b[i] += kw * (w0) * ccv[i + gci[e]][e]; /* Curvature compensation value */
+ }
+ }
+ }
+ EC_INC(gc);
+ }
+ }
+#endif /* ALWAYS */
+
+#ifdef DEBUG
+ printf("After adding curvature equations:\n");
+ for (i = 0; i < gno; i++) {
+ printf("b[%d] = %f\n",i,b[i]);
+ for (k = 0; k < acols; k++) {
+ printf("A[%d][%d] = %f\n",i,k,A[i][k]);
+ }
+ printf("\n");
+ }
+#endif /* DEBUG */
+
+ nbsum = 0.0; /* Zero sum of b[] squared */
+
+#ifdef ALWAYS
+ /* Accumulate weak default function factors. These are effectively a */
+ /* weak "data point" exactly at each grid point. */
+ /* (Note we're not currently doing this in a cache friendly order, */
+ /* and we're calling the function once for each output component..) */
+ if (s->dfunc != NULL) { /* Setting this up from scratch */
+ double iv[MXDI], ov[MXDO];
+ ECOUNT(gc, MXDIDO, di, 0, gres, 0);
+ EC_INIT(gc);
+ for (i = 0; i < gno; i++) {
+ double d, tt;
+
+ /* Get weak default function value for this grid point */
+ for (e = 0; e < s->di; e++)
+ iv[e] = m->g.l[e] + gc[e] * m->g.w[e]; /* Input sample values */
+ s->dfunc(s->dfctx, ov, iv);
+
+ /* Compute values added to matrix */
+ d = 2.0 * m->wdfw;
+ tt = d * ov[f]; /* Change in data component */
+ nbsum += (2.0 * b[i] + tt) * tt; /* += (b[i] + tt)^2 - b[i]^2 */
+ b[i] += tt; /* New data component value */
+ A[i][0] += d; /* dui component to itself */
+
+ EC_INC(gc);
+ }
+
+#ifdef DEBUG
+ printf("After adding weak default equations:\n");
+ for (i = 0; i < gno; i++) {
+ printf("b[%d] = %f\n",i,b[i]);
+ for (k = 0; k < acols; k++) {
+ printf("A[%d][%d] = %f\n",i,k,A[i][k]);
+ }
+ printf("\n");
+ }
+#endif /* DEBUG */
+
+ }
+#endif /* ALWAYS */
+
+#ifdef ALWAYS
+ /* Accumulate data point dependent factors */
+ for (n = 0; n < dno; n++) { /* Go through all the data points */
+ int j,k;
+ int bp = m->d[n].b; /* index to base grid point in grid points */
+
+ /* For each point in the cube as the base grid point, */
+ /* add in the appropriate weighting for its weighted neighbors. */
+ for (j = 0; j < (1 << di); j++) { /* Binary sequence */
+ double d, w, tt;
+ int ai;
+
+ ai = bp + m->g.hi[j]; /* A matrix index */
+
+ w = m->d[n].w[j]; /* Base point grid weight */
+ d = 2.0 * s->d.a[n].k[f] * w; /* (2.0, w are derivative factors, k data pnt wgt) */
+ tt = d * s->d.a[n].cv[f]; /* Change in (corrected) data component */
+
+ nbsum += (2.0 * b[ai] + tt) * tt; /* += (b[ai] + tt)^2 - b[ai]^2 */
+ b[ai] += tt; /* New data component value */
+ A[ai][0] += d * w; /* dui component to itself */
+
+ /* For all the other simplex points ahead of this one, */
+ /* add in linear interpolation derivative weightings */
+ for (k = j+1; k < (1 << di); k++) { /* Binary sequence */
+ int ii;
+ ii = ixcol[m->g.hi[k] - m->g.hi[j]]; /* A matrix column index */
+ A[ai][ii] += d * m->d[n].w[k]; /* dui component due to ui+1 */
+ }
+ }
+ }
+
+ /* Compute norm of b[] from sum of squares */
+ nbsum = sqrt(nbsum);
+ if (nbsum < 1e-4)
+ nbsum = 1e-4;
+ m->q.normb = nbsum;
+
+#endif /* ALWAYS */
+
+#ifdef DEBUG
+ printf("After adding data point equations:\n");
+ for (i = 0; i < gno; i++) {
+ printf("b[%d] = %f\n",i,b[i]);
+ for (k = 0; k < acols; k++) {
+ printf("A[%d][%d] = %f\n",i,k,A[i][k]);
+ }
+ printf("\n");
+ }
+#endif /* DEBUG */
+
+// exit(0);
+}
+
+
+/* Given that we've done a complete fit at the current resolution, */
+/* allocate and compute the curvature error of each grid point and put it in */
+/* s->g.ccv[gno][di] */
+static void comp_ccv(
+ mgtmp *m /* Solution to use */
+) {
+ rspl *s = m->s;
+ int gno = m->g.no, *gres = m->g.res, *gci = m->g.ci;
+ int di = s->di;
+ double *x = m->q.x; /* Grid solution values */
+ int f = m->f; /* Output dimensions being worked on */
+ int e, i;
+
+ ECOUNT(gc, MXDIDO, di, 0, gres, 0);
+ EC_INIT(gc);
+
+ if (s->g.ccv == NULL) {
+ if ((s->g.ccv = dmatrixz(0, gno-1, 0, di-1)) == NULL) {
+ error("Malloc of ccv[] failed with [%d][%d]",di,gno);
+ }
+ }
+
+ for (i = 0; i < gno; i++) {
+ for (e = 0; e < di; e++) { /* For each curvature direction */
+ double w0, w1, tt;
+
+ s->g.ccv[i][e] = 0.0; /* Default value */
+
+ /* If not one from upper or lower edge in this dimension */
+ if ((gc[e]-1) >= 0 && (gc[e]+1) < gres[e]) {
+ /* double kw = cw * gp->k; */ /* This cells k value */
+ w0 = w1 = 1.0;
+ if (m->g.ipos[e] != NULL) {
+ w0 = fabs(m->g.ipos[e][gc[e]-0] - m->g.ipos[e][gc[e]-1]);
+ w1 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]-0]);
+ tt = sqrt(w0 * w1);
+ w0 = tt/w0;
+ w1 = tt/w1;
+ }
+ s->g.ccv[i][e] += w0 * x[i - gci[e]];
+ s->g.ccv[i][e] += -(w0 + w1) * x[i];
+ s->g.ccv[i][e] += w1 * x[i + gci[e]];
+ }
+//printf("~1 computing ccv for node %d is %f\n",i,s->g.ccv[i][0]);
+ }
+ EC_INC(gc);
+ }
+}
+
+/* Down sample the curvature compensation values in s->g.ccv to */
+/* a given solution. Allocate the m->q.ccv if necessary. */
+static void init_ccv(
+ mgtmp *m /* Destination */
+) {
+ rspl *s = m->s;
+ int f = m->f; /* Output dimensions being worked on */
+ int di = s->di;
+ int gno = m->g.no;
+ int gres1_1[MXDI]; /* Destination */
+ int gres2_1[MXDI]; /* Source */
+ double scale[MXDI]; /* ccv scale factor */
+ int e, n;
+ ECOUNT(gc, MXDIDO, di, 0, m->g.res, 0); /* Counter for output points */
+
+ for (e = 0; e < di; e++) {
+ gres1_1[e] = m->g.res[e]-1;
+ gres2_1[e] = s->g.res[e]-1;
+ }
+
+ if (m->q.ccv == NULL) {
+ if ((m->q.ccv = dmatrixz(0, gno-1, 0, di-1)) == NULL) {
+ error("Malloc of ccv[] failed with [%d][%d]",di,gno);
+ }
+ }
+
+ /* Compute the scale factor to compensate for the grid resolution */
+ /* effect on the grid difference values. */
+ for (e = 0; e < di; e++) {
+ double rsm_s, rsm_d;
+
+ if (s->symdom) { /* Relative final grid size */
+ rsm_s = s->g.res[e];
+ rsm_d = m->g.res[e];
+ } else { /* Relative mean final grid size */
+ rsm_s = s->g.mres;
+ rsm_d = m->g.mres;
+ }
+
+ rsm_s = pow((rsm_s-1.0), 2.0); /* Geometric resolution factor for smooth surfaces */
+ rsm_d = pow((rsm_d-1.0), 2.0); /* (It's ^2 rather than ^4 as it's is before squaring) */
+
+ scale[e] = rsm_s/rsm_d;
+ }
+
+ /* Point sampling is probably not the ideal way of down sampling, */
+ /* but it's easy, and won't be too bad if the s->g.ccv has been */
+ /* low pass filtered. */
+
+ /* For all grid ccv's */
+ EC_INIT(gc);
+ for (n = 0; n < gno; n++) {
+ double we[MXRI]; /* 1.0 - Weight in each dimension */
+ double gw[POW2MXRI]; /* weight for each grid cube corner */
+ int ix; /* Index of source ccv grid cube base */
+
+ /* Figure out which grid cell the point falls into */
+ {
+ double t;
+ int mi;
+ ix = 0;
+ for (e = 0; e < di; e++) {
+ t = ((double)gc[e]/(double)gres1_1[e]) * (double)gres2_1[e];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres2_1[e])
+ mi = gres2_1[e]-1;
+ ix += mi * s->g.ci[e]; /* Add Index offset for grid cube base in dimen */
+ we[e] = t - (double)mi; /* 1.0 - weight */
+ }
+ }
+
+ /* Compute corner weights needed for interpolation */
+ {
+ int i, g;
+ gw[0] = 1.0;
+ for (e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * we[e];
+ gw[i] *= (1.0 - we[e]);
+ }
+ }
+ }
+
+ /* Compute the output values */
+ {
+ int i;
+ for (e = 0; e < di; e++)
+ m->q.ccv[n][e] = 0.0; /* Zero output value */
+ for (i = 0; i < (1 << di); i++) { /* For all corners of cube */
+ int oix = ix + s->g.hi[i];
+ for (e = 0; e < di; e++)
+ m->q.ccv[n][e] += gw[i] * s->g.ccv[oix][e];
+ }
+ /* Rescale curvature for grid spacing */
+ for (e = 0; e < di; e++)
+ m->q.ccv[n][e] *= scale[e];
+//printf("~1 downsampling ccv for node %d is %f\n",n,m->q.ccv[n][0]);
+ }
+ EC_INC(gc);
+ }
+}
+
+/* Apply a gaussian filter to the curvature compensation values */
+/* s->g.ccv[gno][di], to apply smoothing. */
+static void filter_ccv(
+ rspl *s,
+ double stdev /* Standard deviation diameter of filter (in input) */
+ /* 1.0 = grid width */
+) {
+ int k, e, ee, i, j, di = s->di;
+ int gno = s->g.no, *gres = s->g.res, *gci = s->g.ci;
+ double *_fkern[MXDI], *fkern[MXDI]; /* Filter kernels */
+ int kmin[MXDI], kmax[MXDI]; /* Kernel index range (inclusive) */
+ double *_row, *row; /* Extended copy of each row processed */
+
+//printf("Doing filter stdev %f\n",stdev);
+
+//printf("~1 bres = %d, index %d to %d\n",s->g.bres,-s->g.bres+1,s->g.bres+s->g.bres-1);
+ if ((_row = (double *) malloc(sizeof(double) * (s->g.bres * 3 - 2))) == NULL)
+ error("rspl malloc failed - ccv row copy");
+ row = _row + s->g.bres-1; /* Allow +/- gres-1 */
+
+ /* Compute the kernel weightings for the given stdev */
+ for (ee = 0; ee < di; ee++) { /* For each dimension direction */
+ int cres; /* Current res */
+ double k1, k2, tot;
+
+//printf("Filter along dim %d:\n",ee);
+ if ((_fkern[ee] = (double *) malloc(sizeof(double) * (gres[ee] * 2 - 1))) == NULL)
+ error("rspl malloc failed - ccv filter kernel");
+ fkern[ee] = _fkern[ee] + gres[ee]-1; /* node of interest at center */
+
+ /* Take gaussian constants out of the loop */
+ k2 = 1.0 / (2.0 * pow(fabs(stdev), TWOPASSORDER));
+ k1 = k2 / 3.1415926;
+
+ /* Comute the range needed */
+ if (s->symdom) {
+ cres = gres[ee];
+ } else {
+ cres = s->g.mres;
+ }
+ kmin[ee] = (int)floor(-5.0 * stdev * (cres-1.0));
+ kmax[ee] = (int)ceil(5.0 * stdev * (cres-1.0));
+
+ if (kmin[ee] < (-gres[ee]+1))
+ kmin[ee] = -gres[ee]+1;
+ else if (kmin[ee] > -1)
+ kmin[ee] = -1;
+ if (kmax[ee] > (gres[ee]-1))
+ kmax[ee] = gres[ee]-1;
+ else if (kmax[ee] < 1)
+ kmax[ee] = 1;
+//printf("kmin = %d, kmax = %d\n",kmin[ee], kmax[ee]);
+
+ for (tot = 0.0, i = kmin[ee]; i <= kmax[ee]; i++) {
+ double fi = (double)i;
+
+ /* Do a discrete integration of the gassian function */
+ /* to compute discrete weightings */
+ fkern[ee][i] = 0.0;
+ for (k = -4; k < 5; k++) {
+ double oset = (fi + k/9.0)/(cres-1.0);
+ double val;
+
+ val = k1 * exp(-k2 * pow(fabs(oset), TWOPASSORDER));
+ fkern[ee][i] += val;
+ tot += val;
+ }
+ }
+ /* Normalize the sum */
+ for (tot = 1.0/tot, i = kmin[ee]; i <= kmax[ee]; i++)
+ fkern[ee][i] *= tot;
+//printf("Filter cooefs:\n");
+//for (i = kmin[ee]; i <= kmax[ee]; i++)
+//printf("%d: %e\n",i,fkern[ee][i]);
+ }
+
+ for (k = 0; k < di; k++) { /* For each curvature direction */
+ for (ee = 0; ee < di; ee++) { /* For each dimension direction */
+ int tgres[MXDI-1];
+
+//printf("~1 Filtering curv dir %d, dim dir %d\n",k,ee);
+ /* Setup counters for scanning through all other dimensions */
+ for (j = e = 0; e < di; e++) {
+ if (e == ee)
+ continue;
+ tgres[j++] = gres[e];
+ }
+ /* For each row of this dimension */
+ {
+ ECOUNT(gc, MXDIDO-1, di-1, 0, tgres, 0); /* Count other dimensions */
+
+ EC_INIT(gc);
+ for (; di <= 1 || !EC_DONE(gc);) {
+ int ix;
+
+ /* Compute index of start of row */
+ for (ix = j = e = 0; e < di; e++) {
+ if (e == ee)
+ continue;
+ ix += gc[j++] * gci[e];
+ }
+
+ /* Copy row to temporary array, and expand */
+ /* edge values by mirroring them. */
+ for (i = 0; i < gres[ee]; i++)
+ row[i] = s->g.ccv[ix + i * gci[ee]][k];
+ for (i = kmin[ee]; i < 0; i++)
+ row[i] = 2.0 * row[0] - row[-i]; /* Mirror the value */
+ for (i = gres[ee]-1 + kmax[ee]; i > (gres[ee]-1); i--)
+ row[i] = 2.0 * row[gres[ee]-1] - row[gres[ee]-1-i]; /* Mirror the value */
+//printf("~1 Row = \n");
+//for (i = kmin[ee]; i <= (gres[ee]-1 + kmax[ee]); i++)
+//printf("%d: %f\n",i,row[i]);
+
+ /* Apply the 1D convolution to the temporary array */
+ /* to produce the filtered values. */
+ for (i = 0; i < gres[ee]; i++) {
+ double fv;
+
+ for (fv = 0.0, j = kmin[ee]; j <= kmax[ee]; j++)
+ fv += fkern[ee][j] * row[i + j];
+ s->g.ccv[ix + i * gci[ee]][k] = fv;
+ }
+ if (di <= 1)
+ break;
+ EC_INC(gc);
+ }
+ }
+ }
+ }
+
+ for (ee = 0; ee < di; ee++)
+ free(_fkern[ee] );
+ free(_row);
+}
+
+/* Given that we've done a complete fit at the current resolution, */
+/* compute the error of each data point, and then compute */
+/* a correction factor .cv[] for each point from this. */
+static void comp_extrafit_corr(
+ mgtmp *m /* Current resolution mgtmp */
+) {
+ rspl *s = m->s;
+ int n;
+ int dno = s->d.no;
+ int di = s->di;
+ double *x = m->q.x; /* Grid solution values */
+ int f = m->f; /* Output dimensions being worked on */
+
+ /* Compute error for each data point */
+ for (n = 0; n < dno; n++) {
+ int j;
+ int bp = m->d[n].b; /* index to base grid point in grid points */
+ double val; /* Current interpolated value */
+ double err;
+ double gain = 1.0;
+
+ /* Compute the interpolated grid value for this data point */
+ for (val = 0.0, j = 0; j < (1 << di); j++) { /* Binary sequence */
+ val += m->d[n].w[j] * x[bp + m->g.hi[j]];
+ }
+
+ err = s->d.a[n].v[f] - val;
+
+#ifdef NEVER
+ /* Compute gain from previous move */
+ if (fabs(s->d.a[n].pe[f]) > 0.001) {
+ gain = (val - s->d.a[n].pv[f])/s->d.a[n].pe[f];
+ if (gain < 0.2)
+ gain = 0.2;
+ else if (gain > 5.0)
+ gain = 5.0;
+ gain = pow(gain, 0.6);
+ } else {
+ gain = 1.0;
+ }
+#endif
+ /* Correct the target data point value by the error */
+ s->d.a[n].cv[f] += err / gain;
+
+//printf("~1 Data point %d, v = %f, cv = %f, change = %f\n",n,s->d.a[n].v[f],s->d.a[n].cv[f],-val);
+//printf("~1 Data point %d, pe = %f, change = %f, gain = %f\n",n,s->d.a[n].pe[f],val - s->d.a[n].pv[f],gain);
+//printf("~1 Data point %d err = %f, target %f, was %f, now %f\n",n,err,s->d.a[n].v[f],val,s->d.a[n].cv[f]);
+// s->d.a[n].pe[f] = err / gain;
+// s->d.a[n].pv[f] = val;
+ }
+}
+
+/* Transfer a solution from one mgtmp to another */
+/* (We assume that they are for the same problem) */
+static void init_soln(
+ mgtmp *m1, /* Destination */
+ mgtmp *m2 /* Source */
+) {
+ rspl *s = m1->s;
+ int di = s->di;
+ int gno = m1->g.no;
+ int gres1_1[MXDI];
+ int gres2_1[MXDI];
+ int e, n;
+ ECOUNT(gc, MXDIDO, di, 0, m1->g.res, 0); /* Counter for output points */
+
+ for (e = 0; e < di; e++) {
+ gres1_1[e] = m1->g.res[e]-1;
+ gres2_1[e] = m2->g.res[e]-1;
+ }
+
+ /* For all output grid points */
+ EC_INIT(gc);
+ for (n = 0; n < gno; n++) {
+ double we[MXRI]; /* 1.0 - Weight in each dimension */
+ double gw[POW2MXRI]; /* weight for each grid cube corner */
+ double *gp; /* Pointer to x2[] grid cube base */
+
+ /* Figure out which grid cell the point falls into */
+ {
+ double t;
+ int mi;
+ gp = m2->q.x; /* Base of solution array */
+ for (e = 0; e < di; e++) {
+ t = ((double)gc[e]/(double)gres1_1[e]) * (double)gres2_1[e];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres2_1[e])
+ mi = gres2_1[e]-1;
+ gp += mi * m2->g.ci[e]; /* Add Index offset for grid cube base in dimen */
+ we[e] = t - (double)mi; /* 1.0 - weight */
+ }
+ }
+
+ /* Compute corner weights needed for interpolation */
+ {
+ int i, g;
+ gw[0] = 1.0;
+ for (e = 0, g = 1; e < di; g *= 2, e++) {
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * we[e];
+ gw[i] *= (1.0 - we[e]);
+ }
+ }
+ }
+
+ /* Compute the output values */
+ {
+ int i;
+ m1->q.x[n] = 0.0; /* Zero output value */
+ for (i = 0; i < (1 << di); i++) { /* For all corners of cube */
+ m1->q.x[n] += gw[i] * gp[m2->g.hi[i]];
+ }
+ }
+ EC_INC(gc);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - -*/
+
+static double one_itter1(cj_arrays *ta, double **A, double *x, double *b, double normb,
+ int gno, int acols, int *xcol, int di, int *gres, int *gci,
+ int max_it, double tol);
+static void one_itter2(double **A, double *x, double *b, int gno, int acols, int *xcol,
+ int di, int *gres, int *gci, double ovsh);
+static double soln_err(double **A, double *x, double *b, double normb, int gno, int acols, int *xcol);
+static double cj_line(cj_arrays *ta, double **A, double *x, double *b, int gno, int acols,
+ int *xcol, int sof, int nid, int inc, int max_it, double tol);
+
+/* Solve scattered data to grid point fit */
+static void
+solve_gres(mgtmp *m, cj_arrays *ta, double tol, int final)
+{
+ rspl *s = m->s;
+ int di = s->di;
+ int gno = m->g.no, *gres = m->g.res, *gci = m->g.ci;
+ int i;
+ double **A = m->q.A; /* A matrix of interpoint weights */
+ int acols = m->q.acols; /* A matrix columns needed */
+ int *xcol = m->q.xcol; /* A array column translation from packed to sparse index */
+ double *b = m->q.b; /* b vector for RHS of simultabeous equation */
+ double *x = m->q.x; /* x vector for result */
+
+ /*
+ * The regular spline fitting problem to be solved here strongly
+ * resembles those involved in solving partial differential equation
+ * problems. The scattered data points equate to boundary conditions,
+ * while the smoothness criteria equate to partial differential equations.
+ */
+
+ /*
+ * There are many approaches that can be used to solve the
+ * symetric positive-definite system Ax = b, where A is a
+ * sparse diagonal matrix with fringes. A direct method
+ * would be Cholesky decomposition, and this works well for
+ * the 1D case (no fringes), but for more than 1D, it generates
+ * fill-ins between the fringes. Given that the widest spaced
+ * fringes are at 2 * gres ^ (dim-1) spacing, this leads
+ * to an unacceptable storage requirement for A, at the resolutions
+ * and dimensions needed in color correction.
+ *
+ * The approaches that minimise A storage are itterative schemes,
+ * such as Gauss-Seidel relaxation, or conjugate-gradient methods.
+ *
+ * There are two methods allowed for below, depending on the
+ * value of JITTERS.
+ * If JITTERS is non-zero, then there will be JITTERS passes of
+ * a combination of multi-grid, Gauss-Seidel relaxation,
+ * and conjugate gradient.
+ *
+ * The outermost loop will use a series of grid resolutions that
+ * approach the final resolution. Each solution gives us a close
+ * starting point for the next higher resolution.
+ *
+ * The middle loop, uses Gauss-Seidel relaxation to approach
+ * the desired solution at a given grid resolution.
+ *
+ * The inner loop can use the conjugate-gradient method to solve
+ * a line of values simultaniously in a particular dimension.
+ * All the lines in each dimension are processed in red/black order
+ * to optimise convergence rate.
+ *
+ * (conjugate gradient seems to be slower than pure relaxation, so
+ * it is not currently used.)
+ *
+ * If JITTERS is zero, then a pure Gauss-Seidel relaxation approach
+ * is used, with the solution elements being updated in RED-BLACK
+ * order. Experimentation seems to prove that this is the overall
+ * fastest approach.
+ *
+ * The equation Ax = b solves the fitting for the derivative of
+ * the fit error == 0. The error metric used is the norm(b - A * x)/norm(b).
+ * I'm not sure if that is the best metric for the problem at hand though.
+ * b[] is only non-zero where there are scattered data points (or a weak
+ * default function), so the error metric is being normalised to number
+ * of scattered data points. Perhaps normb should always be == 1.0 ?
+ *
+ * The norm(b - A * x) is effectively the RMS error of the derivative
+ * fit, so it balances average error and peak error, but another
+ * approach might be to work on peak error, and apply Gauss-Seidel relaxation
+ * to grid points in peak error order (ie. relax the top 10% of grid
+ * points each itteration round) ??
+ *
+ */
+
+ /* Note that we process the A[][] sparse columns in compact form */
+
+#ifdef DEBUG_PROGRESS
+ printf("Target tol = %f\n",tol);
+#endif
+ /* If the number of point is small, or it is just one */
+ /* dimensional, solve it more directly. */
+ if (m->g.bres <= 4) { /* Don't want to multigrid below this */
+ /* Solve using just conjugate-gradient */
+ cj_line(ta, A, x, b, gno, acols, xcol, 0, gno, 1, 10 * gno, tol);
+#ifdef DEBUG_PROGRESS
+ printf("Solved at res %d using conjugate-gradient\n",gres[0]);
+#endif
+ } else { /* Try relax till done */
+ double lerr = 1.0, err = tol * 10.0, derr, ovsh = 1.0;
+ int jitters = JITTERS;
+
+ /* Compute an initial error */
+ err = soln_err(A, x, b, m->q.normb, gno, acols, xcol);
+#ifdef DEBUG_PROGRESS
+ printf("Initial error res %d is %f\n",gres[0],err);
+#endif
+
+ for (i = 0; i < 500; i++) {
+ if (i < jitters) { /* conjugate-gradient and relaxation */
+ lerr = err;
+ err = one_itter1(ta, A, x, b, m->q.normb, gno, acols, xcol, di, gres, gci, (int)m->g.mres, tol * CONJ_TOL);
+
+ derr = err/lerr;
+ if (derr > 0.8) /* We're not improving using itter1() fast enough */
+ jitters = i-1; /* Move to just relaxation */
+#ifdef DEBUG_PROGRESS
+ printf("one_itter1 at res %d has err %f, derr %f\n",gres[0],err,derr);
+#endif
+ } else { /* Use just relaxation */
+ int j, ni = 0; /* Number of itters */
+ if (i == jitters) { /* Never done a relaxation itter before */
+ ni = 1; /* Just do one, to get estimate */
+ } else {
+ ni = (int)(((log(tol) - log(err)) * (double)ni)/(log(err) - log(lerr)));
+ if (ni < 1)
+ ni = 1; /* Minimum of 1 at a time */
+ else if (ni > MAXNI)
+ ni = MAXNI; /* Maximum of MAXNI at a time */
+ }
+ for (j = 0; j < ni; j++) /* Do them in groups for efficiency */
+ one_itter2(A, x, b, gno, acols, xcol, di, gres, gci, ovsh);
+ lerr = err;
+ err = soln_err(A, x, b, m->q.normb, gno, acols, xcol);
+ derr = pow(err/lerr, 1.0/ni);
+#ifdef DEBUG_PROGRESS
+ printf("%d * one_itter2 at res %d has err %f, derr %f\n",ni,gres[0],err,derr);
+#endif
+ if (s->verbose) {
+ printf("*"); fflush(stdout);
+ }
+ }
+#ifdef OVERRLX
+ if (derr > 0.7 && derr < 1.0) {
+ ovsh = 1.0 * derr/0.7;
+ }
+#endif /* OVERRLX */
+ if (err < tol || (derr <= 1.0 && derr > TOL_IMP)) /* within tol or < tol_improvement */
+ break;
+ }
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -*/
+/* Do one relaxation itteration of applying */
+/* cj_line to solve each line of x[] values, in */
+/* each line of each dimension. Return the */
+/* current solution error. */
+static double
+one_itter1(
+ cj_arrays *ta, /* cj_line temporary arrays */
+ double **A, /* Sparse A[][] matrix */
+ double *x, /* x[] matrix */
+ double *b, /* b[] matrix */
+ double normb, /* Norm of b[] */
+ int gno, /* Total number of unknowns */
+ int acols, /* Use colums in A[][] */
+ int *xcol, /* sparse expansion lookup array */
+ int di, /* number of dimensions */
+ int *gres, /* Grid resolution */
+ int *gci, /* Array increment for each dimension */
+ int max_it, /* maximum number of itterations to use (min gres) */
+ double tol /* Tollerance to solve line */
+) {
+ int e,d;
+
+ /* For each dimension */
+ for (d = 0; d < di; d++) {
+ int ld = d == 0 ? 1 : 0; /* lowest dim */
+ int sof, gc[MXRI];
+
+//printf("~1 doing one_itter1 for dim %d\n",d);
+ for (e = 0; e < di; e++)
+ gc[e] = 0; /* init coords */
+
+ /* Until we've done all lines in direction d, */
+ /* processed in red/black order */
+ for (sof = 0, e = 0; e < di;) {
+
+ /* Solve a line */
+//printf("~~solve line start %d, inc %d, len %d\n",sof,gci[d],gres[d]);
+ cj_line(ta, A, x, b, gno, acols, xcol, sof, gres[d], gci[d], max_it, tol);
+
+ /* Increment index */
+ for (e = 0; e < di; e++) {
+ if (e == d) /* Don't go in direction d */
+ continue;
+ if (e == ld) {
+ gc[e] += 2; /* Inc coordinate */
+ sof += 2 * gci[e]; /* Track start point */
+ } else {
+ gc[e] += 1; /* Inc coordinate */
+ sof += 1 * gci[e]; /* Track start point */
+ }
+ if (gc[e] < gres[e])
+ break; /* No carry */
+ gc[e] -= gres[e]; /* Reset coord */
+ sof -= gres[e] * gci[e]; /* Track start point */
+
+ if ((gres[e] & 1) == 0) { /* Compensate for odd grid */
+ if ((gc[ld] & 1) == 1) {
+ gc[ld] -= 1; /* XOR lsb */
+ sof -= gci[ld];
+ } else {
+ gc[ld] += 1;
+ sof += gci[ld];
+ }
+ }
+ }
+ /* Stop on reaching 0 */
+ for(e = 0; e < di; e++)
+ if (gc[e] != 0)
+ break;
+ }
+ }
+
+ return soln_err(A, x, b, normb, gno, acols, xcol);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -*/
+/* Do one relaxation itteration of applying */
+/* direct relaxation to x[] values, in */
+/* red/black order */
+static void
+one_itter2(
+ double **A, /* Sparse A[][] matrix */
+ double *x, /* x[] matrix */
+ double *b, /* b[] matrix */
+ int gno, /* Total number of unknowns */
+ int acols, /* Use colums in A[][] */
+ int *xcol, /* sparse expansion lookup array */
+ int di, /* number of dimensions */
+ int *gres, /* Grid resolution */
+ int *gci, /* Array increment for each dimension */
+ double ovsh /* Overshoot to use, 1.0 for none */
+) {
+ int e,i,k;
+ int gc[MXRI];
+
+ for (i = e = 0; e < di; e++)
+ gc[e] = 0; /* init coords */
+
+ for (e = 0; e < di;) {
+ int k0,k1,k2,k3;
+ double sm = 0.0;
+
+ /* Right of diagonal in 4's */
+ for (k = 1, k3 = i+xcol[k+3]; (k+3) < acols && k3 < gno; k += 4, k3 = i+xcol[k+3]) {
+ k0 = i + xcol[k+0];
+ k1 = i + xcol[k+1];
+ k2 = i + xcol[k+2];
+ sm += A[i][k+0] * x[k0];
+ sm += A[i][k+1] * x[k1];
+ sm += A[i][k+2] * x[k2];
+ sm += A[i][k+3] * x[k3];
+ }
+ /* Finish any remaining */
+ for (k3 = i + xcol[k]; k < acols && k3 < gno; k++, k3 = i + xcol[k])
+ sm += A[i][k] * x[k3];
+
+ /* Left of diagonal in 4's */
+ /* (We take advantage of the symetry: what would be in the row */
+ /* to the left is repeated in the column above.) */
+ for (k = 1, k3 = i-xcol[k+3]; (k+3) < acols && k3 >= 0; k += 4, k3 = i-xcol[k+3]) {
+ k0 = i-xcol[k+0];
+ k1 = i-xcol[k+1];
+ k2 = i-xcol[k+2];
+ sm += A[k0][k+0] * x[k0];
+ sm += A[k1][k+1] * x[k1];
+ sm += A[k2][k+2] * x[k2];
+ sm += A[k3][k+3] * x[k3];
+ }
+ /* Finish any remaining */
+ for (k3 = i-xcol[k]; k < acols && k3 >= 0; k++, k3 = i-xcol[k])
+ sm += A[k3][k] * x[k3];
+
+// x[i] = (b[i] - sm)/A[i][0];
+ x[i] += ovsh * ((b[i] - sm)/A[i][0] - x[i]);
+
+#ifdef RED_BLACK
+ /* Increment index */
+ for (e = 0; e < di; e++) {
+ if (e == 0) {
+ gc[0] += 2; /* Inc coordinate by 2 */
+ i += 2; /* Track start point */
+ } else {
+ gc[e] += 1; /* Inc coordinate */
+ i += gci[e]; /* Track start point */
+ }
+ if (gc[e] < gres[e])
+ break; /* No carry */
+ gc[e] -= gres[e]; /* Reset coord */
+ i -= gres[e] * gci[e]; /* Track start point */
+
+ if ((gres[e] & 1) == 0) { /* Compensate for odd grid */
+ gc[0] ^= 1; /* XOR lsb */
+ i ^= 1;
+ }
+ }
+ /* Stop on reaching 0 */
+ for(e = 0; e < di; e++)
+ if (gc[e] != 0)
+ break;
+#else
+ if (++i >= gno)
+ break;
+#endif
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -*/
+/* This function returns the current solution error. */
+static double
+soln_err(
+ double **A, /* Sparse A[][] matrix */
+ double *x, /* x[] matrix */
+ double *b, /* b[] matrix */
+ double normb, /* Norm of b[] */
+ int gno, /* Total number of unknowns */
+ int acols, /* Use colums in A[][] */
+ int *xcol /* sparse expansion lookup array */
+) {
+ int i, k;
+ double resid;
+
+ /* Compute norm of b - A * x */
+ resid = 0.0;
+ for (i = 0; i < gno; i++) {
+ int k0,k1,k2,k3;
+ double sm = 0.0;
+
+ /* Diagonal and to right in 4's */
+ for (k = 0, k3 = i+xcol[k+3]; (k+3) < acols && k3 < gno; k += 4, k3 = i+xcol[k+3]) {
+ k0 = i + xcol[k+0];
+ k1 = i + xcol[k+1];
+ k2 = i + xcol[k+2];
+ sm += A[i][k+0] * x[k0];
+ sm += A[i][k+1] * x[k1];
+ sm += A[i][k+2] * x[k2];
+ sm += A[i][k+3] * x[k3];
+ }
+ /* Finish any remaining */
+ for (k3 = i + xcol[k]; k < acols && k3 < gno; k++, k3 = i + xcol[k])
+ sm += A[i][k] * x[k3];
+
+ /* Left of diagonal in 4's */
+ /* (We take advantage of the symetry: what would be in the row */
+ /* to the left is repeated in the column above.) */
+ for (k = 1, k3 = i-xcol[k+3]; (k+3) < acols && k3 >= 0; k += 4, k3 = i-xcol[k+3]) {
+ k0 = i-xcol[k+0];
+ k1 = i-xcol[k+1];
+ k2 = i-xcol[k+2];
+ sm += A[k0][k+0] * x[k0];
+ sm += A[k1][k+1] * x[k1];
+ sm += A[k2][k+2] * x[k2];
+ sm += A[k3][k+3] * x[k3];
+ }
+ /* Finish any remaining */
+ for (k3 = i-xcol[k]; k < acols && k3 >= 0; k++, k3 = i-xcol[k])
+ sm += A[k3][k] * x[k3];
+
+ sm = b[i] - sm;
+ resid += sm * sm;
+ }
+ resid = sqrt(resid);
+
+ return resid/normb;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -*/
+
+/* Init temporary vectors */
+static void init_cj_arrays(cj_arrays *ta) {
+ memset((void *)ta, 0, sizeof(cj_arrays));
+}
+
+/* Alloc, or re-alloc temporary vectors */
+static void realloc_cj_arrays(cj_arrays *ta, int nid) {
+
+ if (nid > ta->l_nid) {
+ if (ta->l_nid > 0) {
+ free_dvector(ta->z,0,ta->l_nid);
+ free_dvector(ta->r,0,ta->l_nid);
+ free_dvector(ta->q,0,ta->l_nid);
+ free_dvector(ta->xx,0,ta->l_nid);
+ free_dvector(ta->n,0,ta->l_nid);
+ }
+ if ((ta->n = dvector(0,nid)) == NULL)
+ error("Malloc of n[] failed");
+ if ((ta->z = dvector(0,nid)) == NULL)
+ error("Malloc of z[] failed");
+ if ((ta->xx = dvector(0,nid)) == NULL)
+ error("Malloc of xx[] failed");
+ if ((ta->q = dvector(0,nid)) == NULL)
+ error("Malloc of q[] failed");
+ if ((ta->r = dvector(0,nid)) == NULL)
+ error("Malloc of r[] failed");
+ ta->l_nid = nid;
+ }
+}
+
+/* De-alloc temporary vectors */
+static void free_cj_arrays(cj_arrays *ta) {
+
+ if (ta->l_nid > 0) {
+ free_dvector(ta->z,0,ta->l_nid);
+ free_dvector(ta->r,0,ta->l_nid);
+ free_dvector(ta->q,0,ta->l_nid);
+ free_dvector(ta->xx,0,ta->l_nid);
+ free_dvector(ta->n,0,ta->l_nid);
+ }
+}
+
+
+/* This function applies the conjugate gradient */
+/* algorithm to completely solve a line of values */
+/* in one of the dimensions of the grid. */
+/* Return the normalised tollerance achieved. */
+/* This is used by an outer relaxation algorithm */
+static double
+cj_line(
+ cj_arrays *ta, /* Temporary array data */
+ double **A, /* Sparse A[][] matrix */
+ double *x, /* x[] matrix */
+ double *b, /* b[] matrix */
+ int gno, /* Total number of unknowns */
+ int acols, /* Use colums in A[][] */
+ int *xcol, /* sparse expansion lookup array */
+ int sof, /* start offset of x[] to be found */
+ int nid, /* Number in dimension */
+ int inc, /* Increment to move in lines dimension */
+ int max_it, /* maximum number of itterations to use (min nid) */
+ double tol /* Normalised tollerance to stop on */
+) {
+ int i, ii, k, it;
+ double sm;
+ double resid;
+ double alpha, rho = 0.0, rho_1 = 0.0;
+ double normb;
+ int eof = sof + nid * inc; /* End offset */
+
+ /* Alloc, or re-alloc temporary vectors */
+ realloc_cj_arrays(ta, nid);
+
+ /* Compute initial norm of b[] */
+ for (sm = 0.0, ii = sof; ii < eof; ii += inc)
+ sm += b[ii] * b[ii];
+ normb = sqrt(sm);
+ if (normb == 0.0)
+ normb = 1.0;
+
+ /* Compute r = b - A * x */
+ for (i = 0, ii = sof; i < nid; i++, ii += inc) {
+ int k0,k1,k2,k3;
+ sm = 0.0;
+
+ /* Diagonal and to right in 4's */
+ for (k = 0, k3 = ii+xcol[k+3]; (k+3) < acols && k3 < gno; k += 4, k3 = ii+xcol[k+3]) {
+ k0 = ii + xcol[k+0];
+ k1 = ii + xcol[k+1];
+ k2 = ii + xcol[k+2];
+ sm += A[ii][k+0] * x[k0];
+ sm += A[ii][k+1] * x[k1];
+ sm += A[ii][k+2] * x[k2];
+ sm += A[ii][k+3] * x[k3];
+ }
+ /* Finish any remaining */
+ for (k3 = ii + xcol[k]; k < acols && k3 < gno; k++, k3 = ii + xcol[k])
+ sm += A[ii][k] * x[k3];
+
+ /* Left of diagonal in 4's */
+ /* (We take advantage of the symetry: what would be in the row */
+ /* to the left is repeated in the column above.) */
+ for (k = 1, k3 = ii-xcol[k+3]; (k+3) < acols && k3 >= 0; k += 4, k3 = ii-xcol[k+3]) {
+ k0 = ii-xcol[k+0];
+ k1 = ii-xcol[k+1];
+ k2 = ii-xcol[k+2];
+ sm += A[k0][k+0] * x[k0];
+ sm += A[k1][k+1] * x[k1];
+ sm += A[k2][k+2] * x[k2];
+ sm += A[k3][k+3] * x[k3];
+ }
+ /* Finish any remaining */
+ for (k3 = ii-xcol[k]; k < acols && k3 >= 0; k++, k3 = ii-xcol[k])
+ sm += A[k3][k] * x[k3];
+
+ ta->r[i] = b[ii] - sm;
+ }
+
+ /* Transfer the x[] values we are trying to solve into */
+ /* temporary xx[]. The values of interest in x[] will be */
+ /* used to hold the p[] values, so that q = A * p can be */
+ /* computed in the context of the x[] values we are not */
+ /* trying to solve. */
+ /* We also zero out p[] (== x[] in range), to compute n[]. */
+ /* n[] is used to normalize the q = A * p calculation. If we */
+ /* were solving all x[], then q = A * p will be 0 for p = 0. */
+ /* Since we are only solving some x[], this will not be true. */
+ /* We compensate for this by computing q = A * p - n */
+ /* (Note that n[] could probably be combined with b[]) */
+
+ for (i = 0, ii = sof; i < nid; i++, ii += inc) {
+ ta->xx[i] = x[ii];
+ x[ii] = 0.0;
+ }
+ /* Compute n = A * 0 */
+ for (i = 0, ii = sof; i < nid; i++, ii += inc) {
+ sm = 0.0;
+ for (k = 0; k < acols && (ii+xcol[k]) < gno; k++)
+ sm += A[ii][k] * x[ii+xcol[k]]; /* Diagonal and to right */
+ for (k = 1; k < acols && (ii-xcol[k]) >= 0; k++)
+ sm += A[ii-xcol[k]][k] * x[ii-xcol[k]]; /* Left of diagonal */
+ ta->n[i] = sm;
+ }
+
+ /* Compute initial error = norm of r[] */
+ for (sm = 0.0, i = 0; i < nid; i++)
+ sm += ta->r[i] * ta->r[i];
+ resid = sqrt(sm)/normb;
+
+ /* Initial conditions don't need improvement */
+ if (resid <= tol) {
+ tol = resid;
+ max_it = 0;
+ }
+
+ for (it = 1; it <= max_it; it++) {
+
+ /* Aproximately solve for z[] given r[], */
+ /* and also compute rho = r.z */
+ for (rho = 0.0, i = 0, ii = sof; i < nid; i++, ii += inc) {
+ sm = A[ii][0];
+ ta->z[i] = sm != 0.0 ? ta->r[i] / sm : ta->r[i]; /* Simple aprox soln. */
+ rho += ta->r[i] * ta->z[i];
+ }
+
+ if (it == 1) {
+ for (i = 0, ii = sof; i < nid; i++, ii += inc)
+ x[ii] = ta->z[i];
+ } else {
+ sm = rho / rho_1;
+ for (i = 0, ii = sof; i < nid; i++, ii += inc)
+ x[ii] = ta->z[i] + sm * x[ii];
+ }
+ /* Compute q = A * p - n, */
+ /* and also alpha = p.q */
+ for (alpha = 0.0, i = 0, ii = sof; i < nid; i++, ii += inc) {
+ sm = A[ii][0] * x[ii];
+ for (k = 1; k < acols; k++) {
+ int pxk = xcol[k];
+ int nxk = ii-pxk;
+ pxk += ii;
+ if (pxk < gno)
+ sm += A[ii][k] * x[pxk];
+ if (nxk >= 0)
+ sm += A[nxk][k] * x[nxk];
+ }
+ ta->q[i] = sm - ta->n[i];
+ alpha += ta->q[i] * x[ii];
+ }
+
+ if (alpha != 0.0)
+ alpha = rho / alpha;
+ else
+ alpha = 0.5; /* ?????? */
+
+ /* Adjust soln and residual vectors, */
+ /* and also norm of r[] */
+ for (resid = 0.0, i = 0, ii = sof; i < nid; i++, ii += inc) {
+ ta->xx[i] += alpha * x[ii];
+ ta->r[i] -= alpha * ta->q[i];
+ resid += ta->r[i] * ta->r[i];
+ }
+ resid = sqrt(resid)/normb;
+
+ /* If we're done as far as we want */
+ if (resid <= tol) {
+ tol = resid;
+ max_it = it;
+ break;
+ }
+ rho_1 = rho;
+ }
+ /* Substitute solution xx[] back into x[] */
+ for (i = 0, ii = sof; i < nid; i++, ii += inc)
+ x[ii] = ta->xx[i];
+
+// printf("~~ CJ Itters = %d, tol = %f\n",max_it,tol);
+ return tol;
+}
+
+/* ============================================ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rspl/scat2.c b/rspl/scat2.c
new file mode 100644
index 0000000..7579366
--- /dev/null
+++ b/rspl/scat2.c
@@ -0,0 +1,233 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional multilevel spline data fitter
+ * mlbs base version.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2000/11/10
+ *
+ * Copyright 1996 - 2000 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.
+ */
+
+/* This file contains the scattered data solution specific code */
+
+/* TTBD:
+ *
+ * mlbs code doesn't work. Results are rubbish.
+ *
+ * Fix bugs ?
+ * merge stest.c into this file.
+ *
+ * Get rid of error() calls - return status instead
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+
+#include "rspl_imp.h"
+#include "numlib.h"
+#include "mlbs.h"
+
+extern void error(char *fmt, ...), warning(char *fmt, ...);
+
+#undef DEBUG
+
+#undef NEVER
+#define ALWAYS
+
+/* Implemented in rspl.c: */
+extern void alloc_grid(rspl *s);
+
+extern int is_mono(rspl *s);
+
+/* ============================================ */
+void set_from_mlbs(void *cbctx, double *out, double *in) {
+ mlbs *p = (mlbs *)cbctx;
+ co tp;
+ int i;
+
+ for (i = 0; i < p->di; i++)
+ tp.p[i] = in[i];
+
+ if (p->lookup(p, &tp))
+ error("Internal, set_from_mlbs failed!");
+
+ for (i = 0; i < p->di; i++)
+ out[i] = tp.v[i];
+}
+
+/* Initialise the regular spline from scattered data */
+/* Return non-zero if non-monotonic */
+static int
+fit_rspl_imp(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ void *d, /* Array holding position and function values of data points */
+ int dtp, /* Flag indicating data type, 0 = (co *), 1 = (cow *) */
+ int dno, /* Number of data points */
+ datai glow, /* Grid low scale - will be expanded to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will be expanded to enclose data, NULL = default 1.0 */
+ int gres, /* Spline grid resolution */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth /* Smoothing factor, nominal = 1.0 */
+) {
+ int di = s->di, fdi = s->fdi;
+ int i, n, e, f;
+ int rv;
+ int nigc;
+ int bres;
+ mlbs *p;
+
+#if defined(__IBMC__) && defined(_M_IX86)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+#endif
+ /* set debug level */
+ s->debug = (flags >> 24);
+
+ /* Init other flags */
+ if (flags & RSPL_NONMON) /* Enable elimination of non-monoticities */
+ s->nm = 1;
+ else
+ s->nm = 0;
+
+ if (flags & RSPL_VERBOSE) /* Turn on progress messages to stdout */
+ s->verbose = 1;
+ else
+ s->verbose = 0;
+
+ /* Save smoothing factor */
+ s->smooth = smooth;
+
+ /* Stash the data points away */
+ s->d.no = dno; /* Number of data points */
+
+ /* Allocate the scattered data space */
+ if ((s->d.a = (dpnts *) malloc(sizeof(dpnts) * s->d.no)) == NULL)
+ error("rspl malloc failed - data points");
+
+ if (dtp == 0) { /* Default weight */
+ co *dp = (co *)d;
+
+ /* Copy the list into data points */
+ for (n = 0; n < s->d.no; n++) {
+ for (e = 0; e < s->di; e++)
+ s->d.a[n].p[e] = dp[n].p[e];
+ for (f = 0; f < s->fdi; f++)
+ s->d.a[n].v[f] = dp[n].v[f];
+ s->d.a[n].k = 1.0; /* Assume all data points have same weight */
+ }
+ } else { /* Per data point weight */
+ cow *dp = (cow *)d;
+
+ /* Copy the list into data points */
+ for (n = 0; n < s->d.no; n++) {
+ for (e = 0; e < s->di; e++)
+ s->d.a[n].p[e] = dp[n].p[e];
+ for (f = 0; f < s->fdi; f++)
+ s->d.a[n].v[f] = dp[n].v[f];
+ s->d.a[n].k = dp[n].w; /* Weight specified */
+ }
+ }
+
+ /* Compute target B-Spline resolution */
+ /* Make it worst case half the target rspl resolution */
+ for (bres = 2; (2 * bres) < gres; bres = 2 * bres -1)
+ ;
+
+ /* Create multilevel B-Spline fit */
+ p = new_mlbs(di, fdi, bres, s->d.a, s->d.no, glow, ghigh, smooth);
+ if (p == NULL)
+ error("new_mlbs() failed");
+
+ /* Create rspl grid points by looking up the B-Spline values */
+ rv = s->set_rspl(s, 0, (void *)p, set_from_mlbs, glow, ghigh, gres, vlow, vhigh);
+
+ /* Don't need B-Spline any more */
+ p->del(p);
+
+ return rv;
+}
+
+/* Initialise the regular spline from scattered data */
+/* Return non-zero if non-monotonic */
+int
+fit_rspl(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ co *d, /* Array holding position and function values of data points */
+ int dno, /* Number of data points */
+ datai glow, /* Grid low scale - will be expanded to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will be expanded to enclose data, NULL = default 1.0 */
+ int gres, /* Spline grid resolution */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth /* Smoothing factor, nominal = 1.0 */
+) {
+ /* Call implementation with (co *) data */
+ return fit_rspl_imp(s, flags, (void *)d, 0, dno, glow, ghigh, gres, vlow, vhigh, smooth);
+}
+
+/* Initialise the regular spline from scattered data with weights */
+/* Return non-zero if non-monotonic */
+int
+fit_rspl_w(
+ rspl *s, /* this */
+ int flags, /* Combination of flags */
+ cow *d, /* Array holding position, function and weight values of data points */
+ int dno, /* Number of data points */
+ datai glow, /* Grid low scale - will be expanded to enclose data, NULL = default 0.0 */
+ datai ghigh, /* Grid high scale - will be expanded to enclose data, NULL = default 1.0 */
+ int gres, /* Spline grid resolution */
+ datao vlow, /* Data value low normalize, NULL = default 0.0 */
+ datao vhigh, /* Data value high normalize - NULL = default 1.0 */
+ double smooth /* Smoothing factor, nominal = 1.0 */
+) {
+ /* Call implementation with (cow *) data */
+ return fit_rspl_imp(s, flags, (void *)d, 1, dno, glow, ghigh, gres, vlow, vhigh, smooth);
+}
+
+/* Init scattered data elements in rspl */
+void
+init_data(rspl *s) {
+ s->d.no = 0;
+ s->d.a = NULL;
+ s->fit_rspl = fit_rspl;
+ s->fit_rspl_w = fit_rspl_w;
+}
+
+/* Free the scattered data allocation */
+void
+free_data(rspl *s) {
+ if (s->d.a != NULL) {
+ free((void *)s->d.a);
+ s->d.a = NULL;
+ }
+}
+
+/* ============================================ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rspl/sm1.c b/rspl/sm1.c
new file mode 100644
index 0000000..5bcf26e
--- /dev/null
+++ b/rspl/sm1.c
@@ -0,0 +1,88 @@
+
+/* Test smoothness scaling behaviour for 1D */
+
+#include <stdio.h>
+#include <math.h>
+
+double trans(double *v, int luord, double vv);
+
+double f(double x) {
+ double fp[5] = { +1.0, 0.7, -0.3, 0.0, 0.0 };
+ double y;
+
+ y = trans(fp, 5, x);
+
+ return y;
+}
+
+int main() {
+ double min = 0.0;
+ double max = 1.0;
+ int i, res = 4;
+ int di = 1;
+
+#define LOC(xx) (min + (max-min) * (xx)/(res-1.0))
+
+ /* For each resolution */
+ for (i = 0; i < 10; i++, res *= 2) {
+ double tse = 0.0; /* Total squared error */
+ int j;
+
+ /* For each grid point with neigbors */
+ for (j = 1; j < (res-1); j++) {
+ double err;
+ double y1, y2, y3;
+
+ y1 = f(LOC(j-1));
+ y2 = f(LOC(j));
+ y3 = f(LOC(j+1));
+ err = 0.5 * (y3 + y1) - y2;
+ tse += err * err;
+// tse += fabs(err);
+ }
+ /* Apply adjustments and corrections to error squared */
+ tse *= pow((res-1.0), 4.0); /* Aprox. geometric resolution factor */
+ tse /= pow((res-2.0),(double)di); /* Average squared non-smoothness */
+
+// tse /= (di * pow((res-2.0),(double)di)); /* Average squared non-smoothness */
+ printf("Res %d, tse = %f\n",res,tse);
+ }
+
+
+ return 0;
+}
+
+/* Transfer function */
+double trans(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+) {
+ double g;
+ int ord;
+
+ for (ord = 0; ord < luord; ord++) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ return vv;
+}
diff --git a/rspl/sm2.c b/rspl/sm2.c
new file mode 100644
index 0000000..84bc8cf
--- /dev/null
+++ b/rspl/sm2.c
@@ -0,0 +1,110 @@
+
+/* Test smoothness scaling behaviour for 2D */
+
+#include <stdio.h>
+#include <math.h>
+
+double trans(double *v, int luord, double vv);
+
+double f(double x, double y) {
+ double fp[2][5] = {
+ { 1.0, 0.7, -0.3, 0.0, 0.0 },
+ { 1.0, 0.7, -0.3, 0.0, 0.0 }
+ };
+ double v;
+
+#ifdef NEVER
+ /* 1D function */
+ v = trans(fp[0], 5, x);
+#else
+ /* 1D on angle */
+ v = trans(fp[0], 5, 0.5 * (x+y));
+ v *= 2.0 * sqrt(2.0); // ?????
+#endif
+
+// v = trans(fp[0], 5, x)
+// + trans(fp[0], 5, y);
+
+ return v;
+}
+
+int main() {
+ double min = 0.0;
+ double max = 1.0;
+ int di = 2;
+ int i, res = 4;
+
+#define LOC(xx) (min + (max-min) * (xx)/(res-1.0))
+
+ /* For each resolution */
+ for (i = 0; i < 10; i++, res *= 2) {
+ double tse = 0.0; /* Total squared error */
+ int j, k;
+
+ /* For each grid point with neigbors */
+ for (j = 1; j < (res-1); j++) {
+ for (k = 1; k < (res-1); k++) {
+ double err;
+ double y1, y2, y3;
+
+ y1 = f(LOC(j-1), LOC(k));
+ y2 = f(LOC(j+0), LOC(k));
+ y3 = f(LOC(j+1), LOC(k));
+ err = 0.5 * (y3 + y1) - y2;
+ tse += err * err;
+// tse += fabs(err);
+
+ y1 = f(LOC(j), LOC(k-1));
+ y2 = f(LOC(j), LOC(k+0));
+ y3 = f(LOC(j), LOC(k+1));
+ err = 0.5 * (y3 + y1) - y2;
+ tse += err * err;
+// tse += fabs(err);
+ }
+ }
+ /* Apply adjustments and corrections */
+ tse *= pow((res-1.0), 4.0); /* Aprox. geometric resolution factor */
+ tse /= pow((res-2.0),(double)di); /* Average squared non-smoothness */
+
+// tse /= (di * pow((res-2.0),(double)di)); /* Average squared non-smoothness */
+ printf("Res %d, tse = %f\n",res,tse);
+ }
+
+
+ return 0;
+}
+
+/* Transfer function */
+double trans(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+) {
+ double g;
+ int ord;
+
+ for (ord = 0; ord < luord; ord++) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ return vv;
+}
diff --git a/rspl/sm3.c b/rspl/sm3.c
new file mode 100644
index 0000000..9307787
--- /dev/null
+++ b/rspl/sm3.c
@@ -0,0 +1,110 @@
+
+/* Test smoothness scaling behaviour for 1D */
+
+#include <stdio.h>
+#include <math.h>
+
+double trans(double *v, int luord, double vv);
+
+double f(double x, double y, double z) {
+ double fp[5] = { 1.0, 0.7, -0.3, 0.0, 0.0 };
+ double v;
+
+#ifdef NEVER
+ /* 1D function */
+ v = trans(fp, 5, x);
+#else
+ /* 1D on angle */
+ v = trans(fp, 5, (x+y+z)/3.0);
+ v *= 3.0 * sqrt(3.0); // ?????
+#endif
+
+ return v;
+}
+
+int main() {
+ double min = 0.0;
+ double max = 1.0;
+ int di = 3;
+ int i, res = 4;
+
+#define LOC(xx) (min + (max-min) * (xx)/(res-1.0))
+
+ /* For each resolution */
+ for (i = 0; i < 10; i++, res *= 2) {
+ double tse = 0.0; /* Total squared error */
+ int j, k, m;
+
+ /* For each grid point with neigbors */
+ for (j = 1; j < (res-1); j++) {
+ for (k = 1; k < (res-1); k++) {
+ for (m = 1; m < (res-1); m++) {
+ double err;
+ double y1, y2, y3;
+
+ y1 = f(LOC(j-1), LOC(k), LOC(m));
+ y2 = f(LOC(j+0), LOC(k), LOC(m));
+ y3 = f(LOC(j+1), LOC(k), LOC(m));
+ err = 0.5 * (y3 + y1) - y2;
+ tse += err * err;
+
+ y1 = f(LOC(j), LOC(k-1), LOC(m));
+ y2 = f(LOC(j), LOC(k+0), LOC(m));
+ y3 = f(LOC(j), LOC(k+1), LOC(m));
+ err = 0.5 * (y3 + y1) - y2;
+ tse += err * err;
+
+ y1 = f(LOC(j), LOC(k), LOC(m-1));
+ y2 = f(LOC(j), LOC(k), LOC(m+0));
+ y3 = f(LOC(j), LOC(k), LOC(m+1));
+ err = 0.5 * (y3 + y1) - y2;
+ tse += err * err;
+ }
+ }
+ }
+ /* Apply adjustments and corrections */
+ tse *= pow((res-1.0), 4.0); /* Aprox. geometric resolution factor */
+ tse /= pow((res-2.0),(double)di); /* Average squared non-smoothness */
+
+// tse /= (di * pow((res-2.0),(double)di)); /* Average squared non-smoothness */
+ printf("Res %d, tse = %f\n",res,tse);
+ }
+
+
+ return 0;
+}
+
+/* Transfer function */
+double trans(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+) {
+ double g;
+ int ord;
+
+ for (ord = 0; ord < luord; ord++) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ return vv;
+}
diff --git a/rspl/smtmpp.c b/rspl/smtmpp.c
new file mode 100644
index 0000000..ed7bac7
--- /dev/null
+++ b/rspl/smtmpp.c
@@ -0,0 +1,1203 @@
+
+/*****************************************************************/
+/* Smoothness factor tuning of RSPL in N Dimensions, using MPP's */
+/*****************************************************************/
+
+/* Author: Graeme Gill
+ * Date: 28/11/2005
+ * Derived from cmatch.c
+ * Copyright 1995 - 2005 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ *
+ * Test set for tuning smoothness factor for optimal interpolation
+ * with respect to dimension, number of sample points, and uncertainty
+ * of the sample points.
+ *
+ * The reference is an RGB or CMYK .mpp profile. For 1 and 2 dimensions,
+ * combinations of 1 or 2 input channels are used.
+ */
+
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <math.h>
+#include "rspl.h"
+#include "numlib.h"
+#include "xicc.h"
+#include "plot.h"
+#include "rspl_imp.h"
+#include "counters.h" /* Counter macros */
+
+#ifdef DEBUG
+#define DBG(xxxx) printf xxxx
+#else
+#define DBG(xxxx)
+#endif
+
+#define MXCHPARAMS 8
+
+#define PLOTRES 256
+
+/* Reference convertion object */
+struct _refconv {
+ char *fname; /* File name */
+ mpp *mppo; /* Underlying MPP */
+ inkmask imask; /* Device Ink mask */
+ int pdi; /* mpp input dim */
+ int di; /* effective input dim */
+ int ix; /* channel to use/not use */
+ double dmedia[MXDI]; /* Media color */
+
+ /* Do reference lookup */
+ void (*lookup)(
+ struct _refconv *s, /* this */
+ double *out,
+ double *in);
+
+}; typedef struct _refconv refconv;
+
+
+/* Do a straight conversion */
+static void refconv_default(
+refconv *rco,
+double *out,
+double *in) {
+ rco->mppo->lookup(rco->mppo, out, in);
+}
+
+/* Do a 1d emulation */
+static void refconv_1d(
+refconv *s,
+double *out,
+double *in
+) {
+ double dval[MXDI];
+ int e;
+
+ for (e = 0; e < s->pdi; e++) {
+ if (e == s->ix) {
+ if (s->imask & ICX_INVERTED)
+ dval[e] = 1.0 - in[0];
+ else
+ dval[e] = in[0];
+ } else {
+ dval[e] = s->dmedia[e];
+ }
+ }
+ s->mppo->lookup(s->mppo, out, dval);
+//printf("~1 1D %f == %f %f %f -> %f %f %f\n", in[0], dval[0], dval[1], dval[2], out[0], out[1], out[2]);
+}
+
+/* Do a 2d emulation */
+static void refconv_2d(
+refconv *s,
+double *out,
+double *in
+) {
+ double dval[MXDI];
+ int e, j;
+
+ for (j = e = 0; e < s->pdi; e++) {
+ if (e < 3 && e != s->ix) {
+ if (s->imask & ICX_INVERTED)
+ dval[e] = 1.0 - in[j++];
+ else
+ dval[e] = in[j++];
+ } else {
+ dval[e] = s->dmedia[e];
+ }
+ }
+
+ s->mppo->lookup(s->mppo, out, dval);
+//printf("~1 2D %f %f == %f %f %f -> %f %f %f\n", in[0], in[1], dval[0], dval[1], dval[2], out[0], out[1], out[2]);
+}
+
+
+/* Setup the reference convertion object to imitate the given dimentionality */
+/* return nz if the given idex is out of range */
+static int set_refconv(
+ refconv *s,
+ int ix, /* Index of convertion, typicall 0-3 */
+ int di /* Chosen dimentionalty */
+) {
+ int e;
+
+ s->di = di;
+ s->ix = ix;
+
+ if (di == s->pdi) {
+ if (ix == 0) {
+ s->lookup = refconv_default;
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ if (di == 3 || di == 4)
+ return 1;
+
+ /* Have to emulate a lower dimension. */
+
+ /* Decide what the media color is */
+ if (s->imask & ICX_INVERTED) {
+ for (e = 0; e < s->pdi; e++)
+ s->dmedia[e] = 1.0;
+ } else {
+ for (e = 0; e < s->pdi; e++)
+ s->dmedia[e] = 0.0;
+ }
+
+ /* See where we're up to */
+ if (di == 1) {
+ if (ix < 0 || ix >= s->pdi) /* RGB or CMYK channels */
+ return 1;
+
+ s->lookup = refconv_1d;
+ return 0;
+
+ } else if (di == 2) {
+ if (ix < 0 || ix >= 3) /* Just RGB or CMY */
+ return 1;
+ s->di = di;
+ s->lookup = refconv_2d;
+ return 0;
+ }
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* Do one set of tests and return the results */
+static void do_test(
+ refconv *rco,
+ double *trmse, /* RETURN total RMS error */
+ double *tmaxe, /* RETURN total maximum error */
+ double *tavge, /* RETURN total average error */
+ int verb, /* Verbosity */
+ int plot, /* Plot graphs */
+ int di, /* Dimensions */
+ int res, /* RSPL grid resolution */
+ int ntps, /* Number of sample points */
+ double noise, /* Sample point noise volume */
+ int unif, /* nz for uniform noise, else normal */
+ double smooth, /* Smoothness to test */
+ int twopass, /* Two pass flag */
+ int extra /* Extra fit flag */
+);
+
+/* Compute smoothness of function */
+static double do_stest(
+ refconv *rco,
+ int verb, /* Verbosity */
+ int di, /* Dimensions */
+ int its, /* Number of function tests */
+ int res /* RSPL grid resolution */
+
+);
+
+
+
+/* ---------------------------------------------------------------------- */
+/* Locate minimum of smoothness series result */
+
+#define MXMSS 50 /* Maximum smoothness series */
+
+/* Return the optimal smoothness value, based on the */
+/* minimum RMS value. */
+static double best(int n, double *rmse, double *smv) {
+ int i, bi;
+ rspl *curve;
+ co *tps = NULL;
+ int ns = 500; /* Number of steps to search */
+ datai low,high;
+ int gres[1];
+ datai dlow,dhigh;
+ double avgdev[1];
+ double brmse; /* best solution value */
+ double blsmv = 0.0; /* best solution location */
+ double rv; /* Return value */
+
+ /* Create interpolated curve */
+ if ((curve = new_rspl(RSPL_NOFLAGS,1, 1)) == NULL)
+ error ("New rspl failed");
+
+ /* Create the list of sampling points */
+ if ((tps = (co *)malloc(n * sizeof(co))) == NULL)
+ error ("malloc failed");
+
+ for (i = 0; i < n; i++) {
+ tps[i].p[0] = log10(smv[i]);
+ tps[i].v[0] = rmse[i];
+ }
+
+ gres[0] = 100;
+ low[0] = log10(smv[0]);
+ high[0] = log10(smv[n-1]);
+ dlow[0] = 0.0;
+ dhigh[0] = 1.0;
+ avgdev[0] = 0.0;
+
+ curve->fit_rspl(curve,
+ 0, /* Non-mon and clip flags */
+ tps, /* Test points */
+ n, /* Number of test points */
+ NULL, NULL, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ -0.000005, /* Underlying smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+
+#ifdef NEVER
+ /* Check the fit */
+ for (i = 0; i < n; i++) {
+ co tp;
+
+ tp.p[0] = log10(smv[i]);
+ curve->interp(curve, &tp);
+
+ printf("Point %d at %f, should be %f is %f\n",i,log10(smv[i]),rmse[i],tp.v[0]);
+ }
+
+#define TPRES 100
+ /* Plot the result */
+ {
+ double xx[TPRES], yy[TPRES];
+
+ for (i = 0; i < TPRES; i++) {
+ co tp;
+ double vi = i/(TPRES-1.0);
+
+ tp.p[0] = log10(smv[0]) + (log10(smv[n-1]) - log10(smv[0])) * vi;
+ curve->interp(curve, &tp);
+ xx[i] = tp.p[0];
+ yy[i] = tp.v[0];
+ }
+ do_plot(xx,yy,NULL,NULL,TPRES);
+ }
+#endif
+
+ /* Choose a solution */
+
+ /* First find the very lowest error */
+ brmse = 1e38;
+ for (i = 0; i < ns ; i++) {
+ co tp;
+ double vi;
+
+ vi = i/(ns-1.0);
+ tp.p[0] = log10(smv[0]) + (log10(smv[n-1]) - log10(smv[0])) * vi;
+ curve->interp(curve, &tp);
+
+ if (tp.v[0] < brmse) {
+ blsmv = tp.p[0];
+ brmse = tp.v[0];
+ bi = i;
+ }
+ }
+
+//printf("~1 located minimum at %f err %f\n",pow(10.0, blsmv), brmse);
+
+ /* Then locate the larger smoothness value that */
+ /* gives a slightly higher error. */
+ if ((brmse * 1.1) < (brmse + 1.0))
+ brmse *= 1.1; /* + 10% */
+ else
+ brmse += 1.0; /* or 1 delta E */
+ for (i = bi; i < ns ; i++) {
+ co tp;
+ double vi;
+
+ vi = i/(ns-1.0);
+ tp.p[0] = log10(smv[0]) + (log10(smv[n-1]) - log10(smv[0])) * vi;
+ curve->interp(curve, &tp);
+
+ if (tp.v[0] >= brmse) {
+ blsmv = tp.p[0];
+ brmse = tp.v[0];
+ break;
+ }
+ }
+//printf("~1 located minimum + 20%% at %f err %f\n",pow(10.0, blsmv), brmse);
+
+ rv = pow(10.0, blsmv);
+ return rv;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Explore ideal smoothness change with test point number and noise volume */
+static void do_series_1(refconv* rco, int tdi, int unif, int tntps, int tnlev, int twopass, int extra) {
+ int verb = 0;
+ int plot = 0;
+ int sdi = 1, edi = 4, di;
+ int res = 0;
+ int ntps = 0;
+ double noise = 0.0;
+ double smooth = 0.0;
+ double trmse, tavge, tmaxe;
+ int i, j, k;
+
+ /* Resolution of grid for each dimension */
+ int reses[4][4] = {
+ { 257, 129, 65, 33 },
+ { 128, 65, 33, 17 },
+ { 65, 33, 17, 9 },
+ { 33, 17, 9, 5 }
+ };
+
+ /* Set of smoothnesses to explore */
+ double smset[20] = {
+ -0.0000001,
+ -0.0000010,
+ -0.0000050,
+ -0.0000100,
+ -0.0000500,
+ -0.0001000,
+ -0.0005000,
+ -0.0010000,
+ -0.0050000,
+ -0.0100000,
+ -0.0500000,
+ -0.1000000,
+ -0.5000000,
+ -1.0000000,
+ 0
+ };
+
+ /* For 2 pass smoothing */
+ double smset2[20] = {
+ -0.0200000,
+ -0.0500000,
+ -0.0800000,
+ -0.1000000,
+ -0.1500000,
+ -0.2000000,
+ -0.3000000,
+ -0.4000000,
+ -0.5000000,
+ -0.6000000,
+ -0.7000000,
+ -0.8000000,
+ -1.0000000,
+ 0
+ };
+
+
+ /* Set of sample points to explore */
+ int nset[4][20] = {
+ {
+ 5, 10, 20, 50, 100, 200, 0 /* di = 1 */
+ },
+ {
+ 25, 100, 400, 2500, 10000, 40000, 0, /* di = 2 */
+ },
+ {
+ 25, 50, 75, 125, 250, 500, 1000, 2000, 8000, 125000, 0, /* di = 3 */
+ },
+ {
+ 50, 100, 200, 450, 625, 900, 1800, 3600, 10000, 160000, 1000000, 0, /* di = 4 */
+ }
+ };
+
+ /* Set of total noise levels to explore */
+ /* Set of noise levels to explore (average deviation * 4) */
+ double noiseset[4][20] = {
+ {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ -1.0,
+ },
+ {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ -1.0,
+ },
+ {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ -1.0,
+ },
+ {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.03, /* 3.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ -1.0,
+ },
+ };
+
+
+ printf("Testing underlying smoothness\n");
+
+ printf("Profile is '%s'\n",rco->fname);
+
+ if (twopass)
+ printf("Two Pass smoothing\n");
+ if (extra)
+ printf("Extra fitting\n");
+
+ /* For dimensions */
+ if (tdi != 0)
+ sdi = edi = tdi;
+ DBG(("sdi = %d, edi = %d\n",sdi,edi));
+ for (di = sdi; di <= edi; di++) { // dimensions
+
+ res = reses[di-1][1]; /* Just 2nd highest res */
+
+ printf("Dimensions %d\n",di);
+ printf("RSPL resolution %d\n",res);
+
+ /* For number of sample points */
+ for (i = 0; i < 20; i++) {
+ ntps = nset[di-1][i];
+
+ if (ntps == 0) {
+ DBG(("nset[%d][%d] = %d, ntps == 0\n",di-1,i,nset[di-1][i]));
+ break;
+ }
+
+ if (tntps != 0 && ntps != tntps) { /* Skip any not requested */
+ DBG(("tntps %d != 0 && ntps %d != tntps\n",tntps,ntps));
+ continue;
+ }
+
+ printf("No. Sample points %d\n",ntps);
+
+ /* For noise levels */
+ for (j = tnlev; j < 20; j++) {
+ double smv[20];
+ double rmse[20];
+ double maxe[20];
+ double bfit;
+
+ int ix;
+ double avgbest = 0.0; /* Average best smoothness */
+
+ if (tnlev != 0 && j != tnlev) {
+ DBG(("tnlev != 0 && j != tnlev\n"));
+ break;
+ }
+
+ noise = noiseset[di-1][j];
+ if (noise < 0.0)
+ break;
+ printf("Noise volume %f%%\n",noise * 100.0);
+
+ /* For each channel combination within profile */
+ for (ix = 0; ; ix++) {
+
+ if (set_refconv(rco, ix, di)) {
+ DBG(("set_refconv returned nz with ix %f\n",ix));
+ break;
+ }
+
+ if (di == 1 || di == 2)
+ printf("Channel %d\n",ix);
+
+ /* For smooth factors */
+ for (k = 0; k < 20; k++) {
+ if (twopass)
+ smooth = smset2[k];
+ else
+ smooth = smset[k];
+ if (smooth == 0.0) {
+ DBG(("smooth == 0\n"));
+ break;
+ }
+
+ printf("Smooth %9.7f, ",-smooth); fflush(stdout);
+
+ do_test(rco, &trmse, &tmaxe, &tavge, verb, plot, di, res, ntps, noise, unif, smooth, twopass, extra);
+ smv[k] = -smooth;
+ rmse[k] = trmse;
+ maxe[k] = tmaxe;
+
+ printf("maxerr %f, avgerr %f, rmserr %f\n", tmaxe, tavge, trmse);
+ }
+// bfit = best(k, rmse, smv); /* Best or RMS */
+ bfit = best(k, maxe, smv); /* Best of max error */
+ printf("Best smoothness = %9.7f, log10 = %4.1f\n",bfit,log10(bfit));
+ avgbest += log10(bfit);
+ }
+ if (ix > 0) {
+ avgbest /= (double)ix;
+ printf("Average best smoothness of %d = %9.7f, log10 = %4.1f\n",ix,pow(10.0,avgbest),avgbest);
+ }
+ }
+
+ }
+ printf("\n");
+ }
+}
+
+/* Verify the current behaviour with test point number and noise volume */
+static void do_series_2(refconv *rco, int di, int unif, int twopass, int extra) {
+ int verb = 0;
+ int plot = 0;
+ int res = 0;
+ int ntps = 0;
+ double noise = 0.0;
+ double smooth = 0.0;
+ double trmse, tavge, tmaxe;
+ int i, j, k;
+
+ /* Number of trials to do for each dimension */
+ int trials[4] = {
+ 8,
+ 8,
+ 8,
+ 5
+ };
+
+ /* Resolution of grid for each dimension */
+ int reses[4] = {
+ 129,
+ 65,
+ 33,
+ 17
+ };
+
+ /* Set of smoothnesses to explore */
+ double smset[5] = {
+ 00.01,
+ 00.10,
+ 01.00,
+ 10.00,
+ 100.0
+ };
+
+#ifdef NEVER
+ /* Set of sample points to explore */
+ int nset[4][20] = {
+ {
+ 5, 10, 20, 50, 100, 200, 0 /* di = 1 */
+ },
+ {
+ 25, 100, 400, 2500, 10000, 40000, 0, /* di = 2 */
+ },
+ {
+ 25, 50, 75, 125, 250, 500, 1000, 2000, 8000, 125000, 0, /* di = 3 */
+ },
+ {
+ 50, 100, 200, 450, 625, 900, 1800, 3600, 10000, 160000, 1000000, 0, /* di = 4 */
+ }
+ };
+
+#else
+ /* Set of sample points to explore */
+ int nset[4][20] = {
+ {
+ 5, 10, 20, 50, 0
+ },
+ {
+ 25, 100, 400, 2500 , 0
+ },
+ {
+ 250, 500, 1000, 2000, 4000, 8000, 0
+ },
+ {
+ 450, 900, 1800, 3600, 0
+ }
+ };
+#endif /* NEVER */
+
+ /* Set of noise levels to explore */
+ double noiseset[6] = {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ };
+
+ res = reses[di-1];
+
+ printf("Verification\n");
+ printf("Dimensions %d\n",di);
+ printf("RSPL resolution %d\n",res);
+
+ /* For number of sample points */
+ for (i = 0; i < 20; i++) {
+ ntps = nset[di-1][i];
+
+ if (ntps == 0)
+ break;
+
+ printf("No. Sample points %d\n",ntps);
+
+ /* For noise levels */
+ for (j = 0; j < 6; j++) {
+ noise = noiseset[j];
+
+ printf("Noise volume %f%%\n",noise * 100.0);
+
+ /* For smooth factors */
+ for (k = 0; k < 5; k++) {
+ smooth = smset[k];
+
+ printf("Smooth %9.7f, ",smooth); fflush(stdout);
+
+ do_test(rco, &trmse, &tmaxe, &tavge, verb, plot, di, res, ntps, noise, unif, smooth, twopass, extra);
+
+ printf("maxerr %f, avgerr %f, rmserr %f\n", tmaxe, tavge, trmse);
+ }
+ }
+ }
+ printf("\n");
+}
+
+/* ---------------------------------------------------------------------- */
+void usage(void) {
+ fprintf(stderr,"Test smoothness factor tuning of RSPL in N Dimensions with MPP\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: smtmpp [options] profile.mpp\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -p Plot graphs\n");
+ fprintf(stderr," -z n Do test series ""n""\n");
+ fprintf(stderr," 1 = underlying smoothness\n");
+ fprintf(stderr," 2 = verification of optimal smoothness\n");
+ fprintf(stderr," -S Compute smoothness factor instead\n");
+ fprintf(stderr," -u Use uniformly distributed noise\n");
+ fprintf(stderr," -d n Test ""d"" dimension, 1-4 (default 1)\n");
+ fprintf(stderr," -r res Rspl resolution (defaults 129, 65, 33, 17)\n");
+ fprintf(stderr," -n no Test ""no"" sample points (default 20, 40, 80, 100)\n");
+ fprintf(stderr," -a amnt Add total level amnt randomness (default 0.0)\n");
+ fprintf(stderr," -A n Just do the n'th noise level of series\n");
+ fprintf(stderr," -2 Use two pass smoothing\n");
+ fprintf(stderr," -x Use extra fitting\n");
+ fprintf(stderr," -s smooth RSPL extra smoothness factor to test (default 1.0)\n");
+ fprintf(stderr," -g smooth RSPL underlying smoothness factor to test\n");
+ fprintf(stderr," profile.mpp MPP profile to use\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char prof_name[500];
+ refconv rco;
+ char *ident = NULL; /* Device colorspec description */
+ int verb = 0;
+ int plot = 0;
+ int series = 0;
+ int unif = 0;
+ int di = 0; /* Test input dimensions */
+ int its = 3; /* Smooth test itterations */
+ int res = -1;
+ int ntps = 0;
+ double noise = 0.0;
+ int nlev = 0;
+ double smooth = 1.0;
+ double gsmooth = 0.0;
+ int twopass = 0;
+ int extra = 0;
+ int smfunc = 0;
+ double trmse, tavge, tmaxe;
+
+ int rv;
+
+ error_program = "smtmpp";
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?') {
+ usage();
+
+ } else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+
+ } else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ plot = 1;
+
+ } else if (argv[fa][1] == 'u' || argv[fa][1] == 'U') {
+ unif = 1;
+
+ /* Test series */
+ } else if (argv[fa][1] == 'z' || argv[fa][1] == 'Z') {
+ fa = nfa;
+ if (na == NULL) usage();
+ series = atoi(na);
+ if (series <= 0) usage();
+
+ /* Compute smoothness factor */
+ } else if (argv[fa][1] == 'S') {
+ smfunc = 1;
+
+ /* Dimension */
+ } else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ fa = nfa;
+ if (na == NULL) usage();
+ di = atoi(na);
+ if (di <= 0 || di > 4) usage();
+
+ /* Resolution */
+ } else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ res = atoi(na);
+ if (res <= 0) usage();
+
+ /* Number of sample points */
+ } else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ fa = nfa;
+ if (na == NULL) usage();
+ ntps = atoi(na);
+ if (ntps <= 0) usage();
+
+ /* Randomness */
+ } else if (argv[fa][1] == 'a') {
+ fa = nfa;
+ if (na == NULL) usage();
+ noise = atof(na);
+ if (noise < 0.0) usage();
+
+ /* Series Noise Level */
+ } else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage();
+ nlev = atoi(na);
+ if (noise < 0) usage();
+
+ } else if (argv[fa][1] == '2') {
+ twopass = 1;
+
+ } else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ extra = 1;
+
+ /* Extra smooth factor */
+ } else if (argv[fa][1] == 's') {
+ fa = nfa;
+ if (na == NULL) usage();
+ smooth = atof(na);
+ if (smooth < 0.0) usage();
+
+ /* Underlying smoothnes factor */
+ } else if (argv[fa][1] == 'g') {
+ fa = nfa;
+ if (na == NULL) usage();
+ smooth = atof(na);
+ if (gsmooth < 0.0) usage();
+
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(prof_name,argv[fa]);
+
+ rco.fname = prof_name;
+
+ if ((rco.mppo = new_mpp()) == NULL)
+ error ("Creation of MPP object failed");
+
+ if ((rv = rco.mppo->read_mpp(rco.mppo,prof_name)) != 0)
+ error ("%d, %s",rv,rco.mppo->err);
+
+ rco.mppo->get_info(rco.mppo, &rco.imask, &rco.pdi, NULL, NULL, NULL, NULL, NULL, NULL);
+ ident = icx_inkmask2char(rco.imask, 1);
+
+ if (rco.pdi != 3 && rco.pdi != 4)
+ error("Expect RGB or CMYK .mpp");
+
+ if (verb) {
+ printf("MPP profile with %d colorants, type %s\n",rco.pdi,ident);
+ }
+
+ /* Select Lab return value details */
+ if ((rv = rco.mppo->set_ilob(rco.mppo, icxIT_default, NULL, icxOT_default, NULL, icSigLabData, 0)) != 0) {
+ if (rv == 1)
+ error("Spectral profile needed for custom illuminant, observer or FWA");
+ error("Error setting illuminant, observer, or FWA");
+ }
+
+ if (series > 0) {
+ if (series == 1)
+ do_series_1(&rco, di, unif, ntps, nlev, twopass, extra);
+ else if (series == 2)
+ do_series_2(&rco, di, unif, twopass, extra);
+ else
+ error("Unknown series %d\n",series);
+ return 0;
+ }
+
+ if (res < 0) {
+ if (di == 1)
+ res = 129;
+ else if (di == 2)
+ res = 65;
+ else if (di == 3)
+ res = 33;
+ else
+ res = 17;
+ }
+
+ if (ntps < 0) {
+ if (di == 1)
+ ntps = 20;
+ else if (di == 2)
+ ntps = 40;
+ else if (di == 3)
+ ntps = 60;
+ else
+ ntps = 80;
+ }
+
+ if (smfunc) {
+ double sm;
+
+ if (verb) {
+ printf("Dimensions %d\n",di);
+ printf("Tests %d\n",its);
+ printf("Grid resolution %d\n",res);
+ }
+
+ sm = do_stest(&rco, verb, di, its, res);
+
+ printf("Results: smoothness factor = %f\n",sm);
+
+ } else {
+
+ if (verb) {
+ printf("Dimensions %d\n",di);
+ printf("RSPL resolution %d\n",res);
+ printf("No. Sample points %d (norm %f)\n",ntps, pow((double)ntps, 1.0/di));
+ printf("Noise volume total %f, == avg. dev. %f\n",noise, 0.25 * noise);
+ if (gsmooth > 0.0)
+ printf("Underlying smooth %f\n",gsmooth);
+ else
+ printf("Extra smooth %f\n",smooth);
+ }
+
+ if (gsmooth > 0.0)
+ do_test(&rco, &trmse, &tmaxe, &tavge, verb, plot, di, res, ntps, noise, unif, -gsmooth, twopass, extra);
+ else
+ do_test(&rco, &trmse, &tmaxe, &tavge, verb, plot, di, res, ntps, noise, unif, smooth, twopass, extra);
+
+ printf("Results: maxerr %f, avgerr %f, rmserr %f\n",
+ tmaxe, tavge, trmse);
+ }
+
+ rco.mppo->del(rco.mppo);
+
+ free(ident);
+
+ return 0;
+}
+
+/* ----------------------------------------------- */
+
+/* Do one set of tests and return the results */
+static void do_test(
+ refconv *rco,
+ double *trmse, /* RETURN total RMS error */
+ double *tmaxe, /* RETURN total maximum error */
+ double *tavge, /* RETURN total average error */
+ int verb, /* Verbosity */
+ int plot, /* Plot graphs */
+ int di, /* Dimensions in */
+ int res, /* RSPL grid resolution */
+ int ntps, /* Number of sample points */
+ double noise, /* Sample point noise volume */
+ int unif, /* nz for uniform noise, else normal */
+ double smooth, /* Smoothness to test, +ve for extra, -ve for underlying */
+ int twopass, /* Two pass flag */
+ int extra /* Extra fit flag */
+) {
+ sobol *so; /* Sobol sequence generator */
+ co *tps = NULL;
+ rspl *rss; /* Multi-resolution regularized spline structure */
+ datai low,high;
+ int gres[MXDI];
+ double avgdev[MXDO];
+ int i, j, it;
+ int flags = RSPL_NOFLAGS;
+
+ *trmse = 0.0;
+ *tmaxe = 0.0;
+ *tavge = 0.0;
+
+ for (j = 0; j < di; j++) {
+ low[j] = 0.0;
+ high[j] = 1.0;
+ gres[j] = res;
+ }
+
+ if (twopass)
+ flags |= RSPL_2PASSSMTH;
+
+ if (extra)
+ flags |= RSPL_EXTRAFIT2;
+
+ /* Make repeatable by setting random seed before a test set. */
+ rand32(0x12345678);
+
+ if ((so = new_sobol(di)) == NULL)
+ error("Creating sobol sequence generator failed");
+
+ {
+ double rmse, avge, maxe;
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS,di, 3);
+
+ /* Create the list of sampling points */
+ tps = (co *)malloc(ntps * sizeof(co));
+
+ so->reset(so);
+
+ if (verb) printf("Generating the sample points\n");
+
+ /* Random sobol test set */
+ for (i = 0; i < ntps; i++) {
+ double out[3];
+ int f;
+
+ so->next(so, tps[i].p);
+ rco->lookup(rco, out, tps[i].p);
+ /* Add randomness to the PCS values */
+ /* 0.25 * converts total volume to average deviation */
+ for (f = 0; f < 3; f++) {
+ if (unif) {
+ tps[i].v[f] = out[f] + 100.0 * d_rand(-0.5 * noise, 0.5 * noise);
+ } else {
+ tps[i].v[f] = out[f] + 100.0 * noise * 0.25 * 1.2533 * norm_rand();
+ }
+ }
+//printf("~1 data %d: %f %f %f -> %f %f %f, inc noise %f %f %f\n", i, tps[i].p[0], tps[i].p[1], tps[i].p[2], out[0], out[1], out[2], tps[i].v[0], tps[i].v[1], tps[i].v[2]);
+ }
+
+ /* Average deviation of ouput % */
+ avgdev[0] = 0.25 * noise;
+ avgdev[1] = 0.25 * noise;
+ avgdev[2] = 0.25 * noise;
+
+ /* Fit to scattered data */
+ if (verb) printf("Fitting the scattered data\n");
+ rss->fit_rspl(rss,
+ flags, /* Non-mon and clip flags */
+ tps, /* Test points */
+ ntps, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ smooth, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+
+ /* Plot out function values */
+ if (plot) {
+ int slice;
+ printf("Black is target, Red is rspl\n");
+ for (slice = 0; slice < (di+1); slice++) {
+ co tp; /* Test point */
+ double x[PLOTRES];
+ double ya[PLOTRES];
+ double yb[PLOTRES];
+ double yc[PLOTRES];
+ double pp[MXDI], p1[MXDI], p2[MXDI], ss[MXDI];
+ int n = PLOTRES;
+
+ /* setup slices on each axis at 0.5 and diagonal */
+ if (slice < di) {
+ for (j = 0; j < di; j++)
+ p1[j] = p2[j] = 0.5;
+ p1[slice] = 0.0;
+ p2[slice] = 1.0;
+ printf("Slice along axis %d\n",slice);
+ } else {
+ for (j = 0; j < di; j++) {
+ p1[j] = 0.0;
+ p2[j] = 1.0;
+ }
+ printf("Slice along diagonal\n");
+ }
+
+ for (j = 0; j < di; j++) {
+ ss[j] = (p2[j] - p1[j])/n;
+ pp[j] = p1[j];
+ }
+
+ for (i = 0; i < n; i++) {
+ double out[3];
+ double vv = i/(n-1.0);
+ x[i] = vv;
+
+ /* Reference */
+ rco->lookup(rco, out, pp);
+ ya[i] = 0.01 * out[0];
+
+ /* RSPL aproximation */
+ for (j = 0; j < di; j++)
+ tp.p[j] = pp[j];
+
+ if (rss->interp(rss, &tp))
+ tp.v[0] = -0.1;
+ yb[i] = tp.v[0];
+
+ /* Crude way of setting the scale: */
+ yc[i] = 0.0;
+ if (i == (n-1))
+ yc[0] = 1.0;
+
+ for (j = 0; j < di; j++)
+ pp[j] += ss[j];
+ }
+
+ /* Plot the result */
+ do_plot(x,ya,yb,yc,n);
+ }
+ }
+
+ /* Compute statistics */
+ rmse = 0.0;
+ avge = 0.0;
+ maxe = 0.0;
+// so->reset(so);
+
+
+ /* Fit to scattered data */
+ if (verb) printf("Fitting the scattered data\n");
+ for (i = 0; i < 100000; i++) {
+// for (i = 0; i < 100; i++) {
+ double out[3];
+ co tp; /* Test point */
+ double err;
+
+ if (so->next(so, tp.p))
+ error("Ran out of pseudo radom points");
+
+ /* Reference */
+ rco->lookup(rco, out, tp.p);
+
+ /* RSPL aproximation */
+ rss->interp(rss, &tp);
+
+//printf("~1 point %f %f %f -> ref %f %f %f, test %f %f %f\n", tp.p[0], tp.p[1], tp.p[2], out[0], out[1], out[2], tp.v[0], tp.v[1], tp.v[2]);
+
+ err = icmLabDE(out, tp.v);
+ avge += err;
+ rmse += err * err;
+ if (err > maxe)
+ maxe = err;
+ }
+ avge /= (double)i;
+ rmse /= (double)i;
+
+ if (verb)
+ printf("Dim %d, res %d, noise %f, points %d, maxerr %f, rmserr %f, avgerr %f\n",
+ di, res, noise, ntps, maxe, sqrt(rmse), avge);
+
+ *trmse += rmse;
+ if (maxe > *tmaxe)
+ *tmaxe = maxe;
+ *tavge += avge;
+
+ rss->del(rss);
+ free(tps);
+ }
+ so->del(so);
+
+ *trmse = sqrt(*trmse);
+}
+
+/* Do smoothness scaling check & return results */
+static double do_stest(
+ refconv *rco,
+ int verb, /* Verbosity */
+ int di, /* Dimensions */
+ int its, /* Number of function tests */
+ int res /* RSPL grid resolution */
+) {
+ DCOUNT(gc, MXDIDO, di, 1, 1, res-1);
+ int it;
+ double atse = 0.0;
+
+ /* Make repeatable by setting random seed before a test set. */
+ rand32(0x12345678);
+
+ for (it = 0; it < its; it++) {
+ double tse;
+ int fdi = it % 3; /* Rotate amongsth L, a, b */
+
+ DC_INIT(gc)
+ tse = 0.0;
+ for (; !DC_DONE(gc);) {
+ double out[3];
+ double g[MXDI];
+ int e, k;
+ double y1, y2, y3;
+ double del;
+
+ for (e = 0; e < di; e++)
+ g[e] = gc[e]/(res-1.0);
+ rco->lookup(rco, out, g);
+ y2 = 0.01 * out[fdi];
+
+ del = 1.0/(res-1.0);
+
+ for (k = 0 ; k < di; k++) {
+ double err;
+
+ g[k] -= del;
+ rco->lookup(rco, out, g);
+ y1 = 0.01 * out[fdi];
+ g[k] += 2.0 * del;
+ rco->lookup(rco, out, g);
+ y3 = 0.01 * out[fdi];
+ g[k] -= del;
+
+ err = 0.5 * (y3 + y1) - y2;
+ tse += err * err;
+ }
+
+ DC_INC(gc);
+ }
+ /* Apply adjustments and corrections */
+ tse *= pow((res-1.0), 4.0); /* Aprox. geometric resolution factor */
+ tse /= pow((res-2.0),(double)di); /* Average squared non-smoothness */
+
+ if (verb)
+ printf("smf for it %d = %f\n",it,tse);
+ atse += tse;
+ }
+
+ return atse/(double)its;
+}
+
+
diff --git a/rspl/smtnd.c b/rspl/smtnd.c
new file mode 100644
index 0000000..cdef0a2
--- /dev/null
+++ b/rspl/smtnd.c
@@ -0,0 +1,1171 @@
+
+/*****************************************************/
+/* Smoothness factor tuning of RSPL in N Dimensions. */
+/*****************************************************/
+
+/* Author: Graeme Gill
+ * Date: 28/11/2005
+ * Derived from cmatch.c
+ * Copyright 1995 - 2005 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ *
+ * Test set for tuning smoothness factor for optimal interpolation
+ * with respect to dimension, number of sample points, and uncertainty
+ * of the sample points.
+ */
+
+
+#undef DEBUG
+#undef DETAILED
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <math.h>
+#include "rspl.h"
+#include "numlib.h"
+#include "xicc.h" /* For mpp support */
+#include "plot.h"
+#include "rspl_imp.h"
+#include "counters.h" /* Counter macros */
+
+/* rspl flags */
+#define MXCHPARAMS 8
+
+#define PLOTRES 256
+
+/* Function being modeled by rspl */
+/* Similar to MPP model */
+typedef struct {
+ int di; /* Number of dimensions */
+ double ip[MXDI][MXCHPARAMS]; /* Input channel parameters */
+ double shape[MXDI][1 << MXDI]; /* Channel interaction shape parameters */
+ double op[1 << MXDI]; /* Output channel combination parameters */
+} funcp;
+
+
+/* Setup a random function in the given dimensions */
+static void setup_func(funcp *p, int di) {
+ double mn,mx;
+ int i, j;
+
+ p->di = di;
+
+ /* Setup random input parameters */
+ /* (This is the one that effects smoothness of function the most) */
+ for (j = 0; j < di; j++) {
+ for (mx = 3.0, i = 0; i < MXCHPARAMS; i++, mx *= 0.6) {
+ p->ip[j][i] = d_rand(-mx, mx);
+ }
+ }
+
+ /* Setup random shape parameters */
+ for (j = 0; j < di; j++) {
+ for (i = 0; i < (1 << di); i++) { /* Initially random */
+ p->shape[j][i] = d_rand(-1.0, 1.0);
+ }
+ }
+
+ /* Setup the random output parameters */
+ mn = 2.0;
+ mx = -1.0;
+ for (i = 0; i < (1 << di); i++) { /* Initially random */
+ p->op[i] = d_rand(0.0, 1.0);
+ if (p->op[i] < mn)
+ mn = p->op[i];
+ if (p->op[i] > mx)
+ mx = p->op[i];
+ }
+ for (i = 0; i < (1 << di); i++) { /* Then scale to between 0.0 and 1.0 */
+ p->op[i] = (p->op[i] - mn)/(mx - mn);
+ }
+}
+
+/* Lookup the function value */
+static double lookup_func(funcp *p, double *v) {
+ int m, k;
+ int di = p->di;
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ double ov; /* Output value */
+
+ /* Input curve lookup */
+ for (m = 0; m < di; m++) {
+ tcnv[m] = icxTransFunc(p->ip[m],MXCHPARAMS,v[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ }
+
+ for (m = 0; m < di; m++)
+ ww[m] = 0.0;
+
+ /* Lookup the shape values */
+ for (k = 0; k < (1 << di); k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < di; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ for (m = 0; m < di; m++) {
+ ww[m] += p->shape[m][k & ~(1<<m)] * vv; /* Apply weighting to shape vertex value */
+ }
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < di; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double vv = tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ tcnv[m] = vv;
+ tcnv1[m] = 1.0 - vv;
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < (1 << di); k++) {
+ double vv = p->op[k];
+ for (m = 0; m < di; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ return ov;
+}
+
+/* Do one set of tests and return the results */
+static void do_test(
+ double *trmse, /* RETURN total RMS error */
+ double *tmaxe, /* RETURN total maximum error */
+ double *tavge, /* RETURN total average error */
+ int verb, /* Verbosity */
+ int plot, /* Plot graphs */
+ int di, /* Dimensions */
+ int its, /* Number of function tests */
+ int res, /* RSPL grid resolution */
+ int ntps, /* Number of sample points */
+ double noise, /* Sample point noise volume */
+ int unif, /* NZ if uniform rather than standard deistribution noise */
+ double smooth, /* Smoothness to test */
+ int twopass, /* Two pass flag */
+ int extra /* Extra fit flag */
+);
+
+/* Compute smoothness of function */
+static double do_stest(
+ int verb, /* Verbosity */
+ int di, /* Dimensions */
+ int its, /* Number of function tests */
+ int res /* RSPL grid resolution */
+);
+
+/* ---------------------------------------------------------------------- */
+/* Locate minimum of smoothness series result */
+
+#define MXMSS 50 /* Maximum smoothness series */
+
+/* Return the optimal smoothness value, based on the */
+/* minimum RMS value. */
+static double best(int n, double *rmse, double *smv) {
+ int i;
+ rspl *curve;
+ co *tps = NULL;
+ int ns = 500; /* Number of samples */
+ datai low,high;
+ int gres[1];
+ datai dlow,dhigh;
+ double avgdev[1];
+ double brmse; /* best solution value */
+ double blsmv = 0.0; /* best solution location */
+ double rv; /* Return value */
+
+ /* Create interpolated curve */
+ if ((curve = new_rspl(RSPL_NOFLAGS,1, 1)) == NULL)
+ error ("New rspl failed");
+
+ /* Create the list of sampling points */
+ if ((tps = (co *)malloc(n * sizeof(co))) == NULL)
+ error ("malloc failed");
+
+ for (i = 0; i < n; i++) {
+ tps[i].p[0] = log10(smv[i]);
+ tps[i].v[0] = rmse[i];
+ }
+
+ gres[0] = 100;
+ low[0] = log10(smv[0]);
+ high[0] = log10(smv[n-1]);
+ dlow[0] = 0.0;
+ dhigh[0] = 1.0;
+ avgdev[0] = 0.0;
+
+ curve->fit_rspl(curve,
+ 0, /* Non-mon and clip flags */
+ tps, /* Test points */
+ n, /* Number of test points */
+ NULL, NULL, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ -0.00001, /* Underlying smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+
+#ifdef NEVER
+ /* Check the fit */
+ for (i = 0; i < n; i++) {
+ co tp;
+
+ tp.p[0] = log10(smv[i]);
+ curve->interp(curve, &tp);
+
+ printf("Point %d at %f, should be %f is %f\n",i,log10(smv[i]),rmse[i],tp.v[0]);
+ }
+
+#define TPRES 100
+ /* Plot the result */
+ {
+ double xx[TPRES], yy[TPRES];
+
+ for (i = 0; i < TPRES; i++) {
+ co tp;
+ double vi = i/(TPRES-1.0);
+
+ tp.p[0] = log10(smv[0]) + (log10(smv[n-1]) - log10(smv[0])) * vi;
+ curve->interp(curve, &tp);
+ xx[i] = tp.p[0];
+ yy[i] = tp.v[0];
+ }
+ do_plot(xx,yy,NULL,NULL,TPRES);
+ }
+#endif
+
+ /* Choose a solution */
+ brmse = 1e38;
+ for (i = 0; i < ns ; i++) {
+ co tp;
+ double vi;
+
+ vi = i/(ns-1.0);
+ tp.p[0] = log10(smv[0]) + (log10(smv[n-1]) - log10(smv[0])) * vi;
+ curve->interp(curve, &tp);
+
+ if (tp.v[0] < brmse) {
+ blsmv = tp.p[0];
+ brmse = tp.v[0];
+ }
+ }
+
+ rv = pow(10.0, blsmv);
+ return rv;
+}
+
+/* ---------------------------------------------------------------------- */
+/* Test series */
+
+/* Explore ideal smoothness change with test point number and noise volume */
+/* If tdi != 0, just do the given dimension */
+/* If tntps != 0, just do the given number of points */
+/* If tnlev != 0, just do the given noise level */
+static void do_series_1(int unif, int tdi, int tntps, int tnlev, int twopass, int extra) {
+ int verb = 0;
+ int plot = 0;
+ int sdi = 1, edi = 4, di;
+ int its;
+ int res = 0;
+ int ntps = 0;
+ double noise = 0.0;
+ double smooth = 0.0;
+ double trmse, tavge, tmaxe;
+ int m, i, j, k;
+
+ /* Number of trials to do for each dimension */
+ int trials[4] = {
+ 8,
+ 6,
+ 4,
+ 3
+ };
+
+ /* Resolution of grid for each dimension */
+ int reses[4][4] = {
+ { 257, 129, 65, 33 },
+ { 128, 65, 33, 17 },
+ { 65, 33, 17, 9 },
+ { 33, 17, 9, 5 }
+ };
+
+ /* Set of sample points to explore */
+ int nset[4][20] = {
+ {
+ 5, 10, 20, 50, 100, 200, /* di = 1 */
+ },
+ {
+ 25, 100, 400, 2500, 10000, 40000, /* di = 2 */
+ },
+ {
+ 25, 50, 75, 125, 250, 500, 1000, 2000, 8000, 125000, /* di = 3 */
+ },
+ {
+ 50, 100, 200, 450, 625, 900, 1800, 3600, 10000, 160000, 1000000, /* di = 4 */
+ }
+ };
+
+ /* Set of smoothnesses to explore */
+ double smset[4][20] = {
+ {
+ -0.0000001,
+ -0.0000010,
+ -0.0000100,
+ -0.0001000,
+ -0.0010000,
+ -0.0100000,
+ -0.1000000,
+ -1.0000000,
+ 0.0
+ },
+ {
+ -0.0000001,
+ -0.0000010,
+ -0.0000100,
+ -0.0001000,
+ -0.0010000,
+ -0.0100000,
+ -0.1000000,
+ -1.0000000,
+ 0.0
+ },
+ {
+ -0.0000010,
+ -0.0000100,
+ -0.0001000,
+ -0.0010000,
+ -0.0100000,
+ -0.1000000,
+ -1.0000000,
+ 0.0
+ },
+ {
+ -0.0000100,
+ -0.0001000,
+ -0.0010000,
+ -0.0100000,
+ -0.1000000,
+ -1.0000000,
+ -10.000000,
+ 0.0
+ }
+ };
+
+ /* Set of smoothnesses for twopass smoothing */
+ double smset2[4][20] = {
+ {
+ -0.0000001,
+ -0.0000010,
+ -0.0000100,
+ -0.0001000,
+ -0.0010000,
+ -0.0100000,
+ -0.1000000,
+ -1.0000000,
+ 0.0
+ },
+ {
+ -0.0000001,
+ -0.0000010,
+ -0.0000100,
+ -0.0001000,
+ -0.0010000,
+ -0.0100000,
+ -0.1000000,
+ -1.0000000,
+ 0.0
+ },
+ {
+ -0.0000010,
+ -0.0000100,
+ -0.0001000,
+ -0.0010000,
+ -0.0100000,
+ -0.1000000,
+ -1.0000000,
+ 0.0
+ },
+ {
+ -0.0000100,
+ -0.0001000,
+ -0.0010000,
+ -0.0100000,
+ -0.1000000,
+ -1.0000000,
+ -10.000000,
+ 0.0
+ }
+ };
+
+ /* Set of noise levels to explore (average deviation * 4) */
+ double noiseset[4][20] = {
+ {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ -1.0,
+ },
+ {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ -1.0,
+ },
+ {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ -1.0,
+ },
+ {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.03, /* 3.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ -1.0,
+ },
+ };
+
+
+ printf("Testing effect of underlying smoothness factors\n");
+ if (twopass)
+ printf("Two Pass smoothing\n");
+ if (extra)
+ printf("Extra fitting\n");
+
+ /* For dimensions */
+ if (tdi != 0)
+ sdi = edi = tdi;
+ for (di = sdi; di <= edi; di++) { // dimensions
+
+ its = trials[di-1];
+
+ for (m = 1; m < 2; m++) { // Just 2nd-highest resolution
+ res = reses[di-1][m];
+
+ printf("Tests %d\n",its);
+ printf("Dimensions %d\n",di);
+ printf("RSPL resolution %d\n",res);
+
+ /* For noise levels */
+ for (j = tnlev; j < 20; j++) { // All noise levels
+ double smv[20];
+ double rmse[20];
+ double bfit;
+
+ if (tnlev != 0 && j != tnlev)
+ break;
+
+ noise = noiseset[di-1][j];
+ if (noise < 0.0)
+ break;
+ printf("\nNoise volume %f%%, average deviation %f%%\n",noise * 100.0, noise * 25.0);
+
+ /* For number of sample points */
+ for (i = 0; i < 20; i++) { // All test points
+ int rpts;
+ ntps = nset[di-1][i];
+
+ if (ntps == 0)
+ break;
+
+ if (tntps != 0 && ntps != tntps) /* Skip any not requested */
+ continue;
+
+ /* Make sure at least 100 points are tested */
+ rpts = 1 + 100/ntps;
+ if (rpts > 5)
+ rpts = 5;
+
+ printf("\nNo. Sample points %d, norm %8.2f, total its %d\n",ntps, pow((double)ntps, 1.0/di),its * rpts);
+
+ /* For smooth factors */
+ for (k = 0; k < 20; k++) { // All smoothing levels
+ if (twopass)
+ smooth = smset2[di-1][k];
+ else
+ smooth = smset[di-1][k];
+ if (smooth == 0.0)
+ break;
+
+ printf("Underlying smooth %9.7f, ",-smooth); fflush(stdout);
+
+ do_test(&trmse, &tmaxe, &tavge, verb, plot, di, its * rpts, res, ntps, noise, unif,smooth, twopass, extra);
+ smv[k] = -smooth;
+ rmse[k] = trmse;
+ printf("maxerr %f%%, avgerr %f%%, rmserr %f%%\n",
+ tmaxe * 100.0, tavge * 100.0, trmse * 100.0);
+ }
+
+ bfit = best(k, rmse, smv);
+ printf("Best smoothness = %9.7f, log10 = %4.1f\n",bfit,log10(bfit));
+ }
+ }
+ }
+ printf("\n");
+ }
+}
+
+/* Explore performance of "optimised" smoothness over test point number and noise volume */
+static void do_series_2(int unif, int twopass, int extra) {
+ int verb = 0;
+ int plot = 0;
+ int di = 0;
+ int its;
+ int res = 0;
+ int ntps = 0;
+ double noise = 0.0;
+ double smooth = 0.0;
+ double trmse, tavge, tmaxe;
+ int i, j, k;
+
+ /* Number of trials to do for each dimension */
+ int trials[4] = {
+ 16,
+ 12,
+ 8,
+ 5
+ };
+
+
+ /* Resolution of grid for each dimension */
+ int reses[4] = {
+ 129,
+ 65,
+ 33,
+ 17
+ };
+
+#ifdef NEVER
+ /* Set of sample points to explore */
+ int nset[4][20] = {
+ {
+ 5, 10, 20, 50, 0
+ },
+ {
+ 25, 100, 400, 2500, 0
+ },
+ {
+ 125, 1000, 8000, 125000, 0
+ },
+ {
+ 625, 10000, 160000, 1000000, 0
+ }
+ };
+#else
+ /* Set of sample points to explore */
+ int nset[4][20] = {
+ {
+ 5, 10, 20, 50, 0
+ },
+ {
+ 25, 100, 400, 2500, 0
+ },
+ {
+ 250, 500, 1000, 2000, 0
+ },
+ {
+ 450, 900, 1800, 3600, 0
+ }
+ };
+#endif /* NEVER */
+
+
+ /* Set of smoothnesses to explore */
+ double smset[5] = {
+ 00.01,
+ 00.10,
+ 01.00,
+ 10.00,
+ 100.0
+ };
+
+ /* Set of noise levels to explore (average deviation * 4) */
+ double noiseset[6] = {
+ 0.0, /* Perfect data */
+ 0.01, /* 1.0 % */
+ 0.02, /* 2.0 % */
+ 0.05, /* 5.0 % */
+ 0.10, /* 10.0 % */
+ 0.20, /* 20.0 % */
+ };
+
+
+ printf("Verifying optimised smoothness factors\n");
+
+ /* For dimensions */
+ for (di = 1; di <= 4; di++) {
+
+ its = trials[di-1];
+ res = reses[di-1];
+
+ printf("Tests %d\n",its);
+ printf("Dimensions %d\n",di);
+ printf("RSPL resolution %d\n",res);
+
+ /* For number of sample points */
+ for (i = 0; i < 20; i++) {
+ ntps = nset[di-1][i];
+
+ if (ntps == 0)
+ break;
+
+ printf("\nNo. Sample points %d, norm %8.2f\n",ntps, pow((double)ntps, 1.0/di));
+
+ /* For noise levels */
+ for (j = 0; j < 6; j++) {
+ double rmse[20];
+ double bfit;
+
+ noise = noiseset[j];
+ printf("Noise volume %f%%, average deviation %f%%\n",noise * 100.0, noise * 25.0);
+
+ /* For smooth factors */
+ for (k = 0; k < 5; k++) {
+ smooth = smset[k];
+
+ printf("Extra smooth %f, ",smooth); fflush(stdout);
+
+ do_test(&trmse, &tmaxe, &tavge, verb, plot, di, its, res, ntps, noise, unif, smooth, twopass, extra);
+
+ rmse[k] = trmse;
+ printf("maxerr %f%%, avgerr %f%%, rmserr %f%%\n",
+ tmaxe * 100.0, tavge * 100.0, trmse * 100.0);
+ }
+ bfit = best(5, rmse, smset);
+ printf("Best smoothness = %9.7f, log10 = %4.1f\n",bfit,log10(bfit));
+ }
+ }
+ printf("\n");
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+void usage(void) {
+ fprintf(stderr,"Test smoothness factor tuning of RSPL in N Dimensions\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: smtnd [options]\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -p Plot graphs\n");
+ fprintf(stderr," -z n Do test series ""n"" else single test\n");
+ fprintf(stderr," 1 = Underlying smoothness\n");
+ fprintf(stderr," 2 = Verify optimised smoothness\n");
+ fprintf(stderr," -S Compute smoothness factor instead\n");
+ fprintf(stderr," -u Use uniformly distributed noise\n");
+ fprintf(stderr," -d n Test ""d"" dimension, 1-4 (default 1)\n");
+ fprintf(stderr," -t n Test ""n"" random functions (default 1)\n");
+ fprintf(stderr," -r res Rspl resolution (defaults 129, 65, 33, 17)\n");
+ fprintf(stderr," -n no Test ""no"" sample points (default 20, 40, 80, 100)\n");
+ fprintf(stderr," -a amnt Add total randomness to function value (default 0.0)\n");
+ fprintf(stderr," -A n Just do the n'th noise level of series\n");
+ fprintf(stderr," -2 Use two pass smoothing\n");
+ fprintf(stderr," -x Use extra fitting\n");
+ fprintf(stderr," -s smooth RSPL extra smoothness factor to test (default 1.0)\n");
+ fprintf(stderr," -g smooth RSPL underlying smoothness factor to test\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int plot = 0;
+ int series = 0;
+ int unif = 0;
+ int di = 0;
+ int its = 1;
+ int res = -1;
+ int ntps = 0;
+ double noise = 0.0;
+ int nlev = 0;
+ double smooth = 1.0;
+ double gsmooth = 0.0;
+ int twopass = 0;
+ int extra = 0;
+ int smfunc = 0;
+ double trmse, tavge, tmaxe;
+
+ error_program = "smtnd";
+
+#ifdef NEVER
+ {
+ double rmse[10], smv[10], rv;
+
+ smv[0] = 0.0000100, rmse[0] = 2.566116;
+ smv[1] = 0.0001000, rmse[1] = 2.528666;
+ smv[2] = 0.0010000, rmse[2] = 2.489116;
+ smv[3] = 0.0100000, rmse[3] = 3.409045;
+ smv[4] = 0.1000000, rmse[4] = 5.727079;
+ smv[5] = 1.0000000, rmse[5] = 6.653747;
+
+ rv = best(6,rmse, smv);
+ printf("~1 best = %f\n",rv);
+ exit(0);
+ }
+#endif
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?') {
+ usage();
+
+ } else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+
+ } else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ plot = 1;
+
+ } else if (argv[fa][1] == 'u' || argv[fa][1] == 'U') {
+ unif = 1;
+
+ /* Test series */
+ } else if (argv[fa][1] == 'z' || argv[fa][1] == 'Z') {
+ fa = nfa;
+ if (na == NULL) usage();
+ series = atoi(na);
+ if (series <= 0) usage();
+
+ /* Compute smoothness factor */
+ } else if (argv[fa][1] == 'S') {
+ smfunc = 1;
+
+ /* Dimension */
+ } else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ fa = nfa;
+ if (na == NULL) usage();
+ di = atoi(na);
+ if (di <= 0 || di > 4) usage();
+printf("~1 Got -d %s = %d\n",na,di);
+
+ /* Number of tests */
+ } else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage();
+ its = atoi(na);
+ if (its <= 0) usage();
+
+ /* Resolution */
+ } else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ res = atoi(na);
+ if (res <= 0) usage();
+
+ /* Number of sample points */
+ } else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ fa = nfa;
+ if (na == NULL) usage();
+ ntps = atoi(na);
+ if (ntps <= 0) usage();
+
+ /* Randomness */
+ } else if (argv[fa][1] == 'a') {
+ fa = nfa;
+ if (na == NULL) usage();
+ noise = atof(na);
+ if (noise < 0.0) usage();
+
+ /* Series Noise Level */
+ } else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage();
+ nlev = atoi(na);
+ if (noise < 0) usage();
+
+ } else if (argv[fa][1] == '2') {
+ twopass = 1;
+
+ } else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ extra = 1;
+
+ /* Extra smooth factor */
+ } else if (argv[fa][1] == 's') {
+ fa = nfa;
+ if (na == NULL) usage();
+ smooth = atof(na);
+ if (smooth < 0.0) usage();
+
+ /* Underlying smoothnes factor */
+ } else if (argv[fa][1] == 'g') {
+ fa = nfa;
+ if (na == NULL) usage();
+ smooth = atof(na);
+ if (gsmooth < 0.0) usage();
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+ if (series > 0) {
+ if (series == 1)
+ do_series_1(unif, di, ntps, nlev, twopass, extra);
+ else if (series == 2)
+ do_series_2(unif, twopass, extra);
+ else
+ error("Unknown series %d\n",series);
+ return 0;
+ }
+
+ if (di == 0)
+ di = 1;
+
+ if (res < 0) {
+ if (di == 1)
+ res = 129;
+ else if (di == 2)
+ res = 65;
+ else if (di == 3)
+ res = 33;
+ else
+ res = 17;
+ }
+
+ if (ntps <= 0) {
+ if (di == 1)
+ ntps = 20;
+ else if (di == 2)
+ ntps = 40;
+ else if (di == 3)
+ ntps = 60;
+ else
+ ntps = 80;
+ }
+
+ if (smfunc) {
+ double sm;
+
+ if (verb) {
+ printf("Dimensions %d\n",di);
+ printf("Tests %d\n",its);
+ printf("Grid resolution %d\n",res);
+ }
+
+ sm = do_stest(verb, di, its, res);
+
+ printf("Results: smoothness factor = %f\n",sm);
+
+ } else {
+
+ if (verb) {
+ printf("Dimensions %d\n",di);
+ printf("Tests %d\n",its);
+ printf("RSPL resolution %d\n",res);
+ printf("No. Sample points %d (norm %f)\n",ntps, pow((double)ntps, 1.0/di));
+ printf("Noise volume %f\n",noise);
+ if (gsmooth > 0.0)
+ printf("Underlying smooth %f\n",gsmooth);
+ else
+ printf("Extra smooth %f\n",smooth);
+ }
+
+ if (gsmooth > 0.0)
+ do_test(&trmse, &tmaxe, &tavge, verb, plot, di, its, res, ntps, noise, unif, -gsmooth, twopass, extra);
+ else
+ do_test(&trmse, &tmaxe, &tavge, verb, plot, di, its, res, ntps, noise, unif, smooth, twopass, extra);
+
+ printf("Results: maxerr %f%%, avgerr %f%%, rmserr %f%%\n",
+ tmaxe * 100.0, tavge * 100.0, trmse * 100.0);
+ }
+
+ return 0;
+}
+
+/* Do one set of tests and return the results */
+static void do_test(
+ double *trmse, /* RETURN total RMS error */
+ double *tmaxe, /* RETURN total maximum error */
+ double *tavge, /* RETURN total average error */
+ int verb, /* Verbosity */
+ int plot, /* Plot graphs */
+ int di, /* Dimensions */
+ int its, /* Number of function tests */
+ int res, /* RSPL grid resolution */
+ int ntps, /* Number of sample points */
+ double noise, /* Sample point noise volume (total = 4 x average deviation) */
+ int unif, /* NZ if uniform rather than standard deistribution noise */
+ double smooth, /* Smoothness to test, +ve for extra, -ve for underlying */
+ int twopass, /* Two pass flag */
+ int extra /* Extra fit flag */
+) {
+ funcp fp; /* Function parameters */
+ sobol *so; /* Sobol sequence generator */
+ co *tps = NULL;
+ rspl *rss; /* Multi-resolution regularized spline structure */
+ datai low,high;
+ double avgdev[MXDO];
+ int gres[MXDI];
+ int i, j, it;
+ int flags = RSPL_NOFLAGS;
+
+ *trmse = 0.0;
+ *tmaxe = 0.0;
+ *tavge = 0.0;
+
+ for (j = 0; j < di; j++) {
+ low[j] = 0.0;
+ high[j] = 1.0;
+ gres[j] = res;
+ }
+
+ if (twopass)
+ flags |= RSPL_2PASSSMTH;
+
+ if (extra)
+ flags |= RSPL_EXTRAFIT2;
+
+ if ((so = new_sobol(di)) == NULL)
+ error("Creating sobol sequence generator failed");
+
+ for (it = 0; it < its; it++) {
+ double rmse, avge, maxe;
+
+ /* Make repeatable by setting random seed before a test set. */
+ rand32(0x12345678 + 0x1000 * it);
+
+ /* New function */
+ setup_func(&fp, di);
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS,di, 1);
+
+ /* Create the list of sampling points */
+ if ((tps = (co *)malloc(ntps * sizeof(co))) == NULL)
+ error ("malloc failed");
+
+ so->reset(so);
+
+ if (verb) printf("Generating the sample points\n");
+
+ for (i = 0; i < ntps; i++) {
+ so->next(so, tps[i].p);
+ tps[i].v[0] = lookup_func(&fp, tps[i].p);
+ if (unif)
+ tps[i].v[0] += d_rand(-0.5 * noise, 0.5 * noise);
+ else
+ tps[i].v[0] += noise * 0.25 * 1.2533 * norm_rand();
+ }
+
+ /* Fit to scattered data */
+ if (verb) printf("Fitting the scattered data\n");
+ avgdev[0] = 0.25 * noise;
+ rss->fit_rspl(rss,
+ flags, /* Non-mon and clip flags */
+ tps, /* Test points */
+ ntps, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ low, high, /* Default data scale */
+ smooth, /* Smoothing to test */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+
+ /* Plot out function values */
+ if (plot) {
+ int slice;
+ printf("Black is target, Red is rspl\n");
+ for (slice = 0; slice < (di+1); slice++) {
+ co tp; /* Test point */
+ double x[PLOTRES];
+ double ya[PLOTRES];
+ double yb[PLOTRES];
+ double yc[PLOTRES];
+ double pp[MXDI], p1[MXDI], p2[MXDI], ss[MXDI];
+ int n = PLOTRES;
+
+ /* setup slices on each axis at 0.5 and diagonal */
+ if (slice < di) {
+ for (j = 0; j < di; j++)
+ p1[j] = p2[j] = 0.5;
+ p1[slice] = 0.0;
+ p2[slice] = 1.0;
+ printf("Slice along axis %d\n",slice);
+ } else {
+ for (j = 0; j < di; j++) {
+ p1[j] = 0.0;
+ p2[j] = 1.0;
+ }
+ printf("Slice along diagonal\n");
+ }
+
+ for (j = 0; j < di; j++) {
+ ss[j] = (p2[j] - p1[j])/n;
+ pp[j] = p1[j];
+ }
+
+ for (i = 0; i < n; i++) {
+ double vv = i/(n-1.0);
+ x[i] = vv;
+
+ /* Reference */
+ ya[i] = lookup_func(&fp, pp);
+
+ /* RSPL aproximation */
+ for (j = 0; j < di; j++)
+ tp.p[j] = pp[j];
+
+ if (rss->interp(rss, &tp))
+ tp.v[0] = -0.1;
+ yb[i] = tp.v[0];
+
+ /* Crude way of setting the scale: */
+ yc[i] = 0.0;
+ if (i == (n-1))
+ yc[0] = 1.0;
+
+ for (j = 0; j < di; j++)
+ pp[j] += ss[j];
+ }
+
+ /* Plot the result */
+ do_plot(x,ya,yb,yc,n);
+ }
+ }
+
+ /* Compute statistics */
+ rmse = 0.0;
+ avge = 0.0;
+ maxe = 0.0;
+// so->reset(so);
+
+ /* Fit to scattered data */
+ if (verb) printf("Fitting the scattered data\n");
+ for (i = 0; i <100000; i++) {
+ co tp; /* Test point */
+ double aa, bb, err;
+
+ so->next(so, tp.p);
+
+ /* Reference */
+ aa = lookup_func(&fp, tp.p);
+
+ /* RSPL aproximation */
+ rss->interp(rss, &tp);
+ bb = tp.v[0];
+
+ err = fabs(aa - bb);
+ avge += err;
+ rmse += err * err;
+ if (err > maxe)
+ maxe = err;
+ }
+ avge /= (double)i;
+ rmse /= (double)i;
+
+ if (verb)
+ printf("Dim %d, res %d, noise %f, points %d, maxerr %f%%, rmserr %f%%, avgerr %f%%\n",
+ di, res, noise, ntps, maxe * 100.0, sqrt(rmse) * 100.0, avge * 100.0);
+
+ *trmse += rmse;
+ *tmaxe += maxe;
+ *tavge += avge;
+
+ rss->del(rss);
+ free(tps);
+ }
+ so->del(so);
+
+ *trmse = sqrt(*trmse/(double)its);
+ *tmaxe /= (double)its;
+ *tavge /= (double)its;
+}
+
+/* Do smoothness scaling check & return results */
+static double do_stest(
+ int verb, /* Verbosity */
+ int di, /* Dimensions */
+ int its, /* Number of function tests */
+ int res /* RSPL grid resolution */
+) {
+ funcp fp; /* Function parameters */
+ DCOUNT(gc, MXDIDO, di, 1, 1, res-1);
+ int it;
+ double atse = 0.0;
+
+ /* Make repeatable by setting random seed before a test set. */
+ rand32(0x12345678);
+
+ for (it = 0; it < its; it++) {
+ double tse;
+ setup_func(&fp, di); /* New function */
+
+ DC_INIT(gc)
+ tse = 0.0;
+ for (; !DC_DONE(gc);) {
+ double g[MXDI];
+ int e, k;
+ double y1, y2, y3;
+ double del;
+
+ for (e = 0; e < di; e++)
+ g[e] = gc[e]/(res-1.0);
+ y2 = lookup_func(&fp, g);
+
+ del = 1.0/(res-1.0);
+
+ for (k = 0 ; k < di; k++) {
+ double err;
+
+ g[k] -= del;
+ y1 = lookup_func(&fp, g);
+ g[k] += 2.0 * del;
+ y3 = lookup_func(&fp, g);
+ g[k] -= del;
+
+ err = 0.5 * (y3 + y1) - y2;
+ tse += err * err;
+ }
+
+ DC_INC(gc);
+ }
+ /* Apply adjustments and corrections */
+ tse *= pow((res-1.0), 4.0); /* Aprox. geometric resolution factor */
+ tse /= pow((res-2.0),(double)di); /* Average squared non-smoothness */
+
+ if (verb)
+ printf("smf for it %d = %f\n",it,tse);
+ atse += tse;
+ }
+
+ return atse/(double)its;
+}
+
+
diff --git a/rspl/spline.c b/rspl/spline.c
new file mode 100644
index 0000000..dabeb0f
--- /dev/null
+++ b/rspl/spline.c
@@ -0,0 +1,352 @@
+
+/*
+ * Argyll Color Correction System
+ * Multi-dimensional regularized spline data structure
+ *
+ * Spline forward interpolation support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/10/98
+ *
+ * Copyright 1998, 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.
+ */
+
+/* TTBD:
+ Get rid of error() calls - return status instead
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <time.h>
+//#if defined(__IBMC__) && defined(_M_IX86)
+//#include <float.h>
+//#endif
+
+#include "rspl_imp.h"
+#include "numlib.h"
+
+int spline_interp_rspl(rspl *ss, co *cp);
+
+#undef DEBUG
+
+#undef NEVER
+#define ALWAYS
+
+/* Convention is to use:
+ i to index grid points u.a
+ n to index data points d.a
+ e to index position dimension di
+ f to index output function dimension fdi
+ j misc and cube corners
+ k misc
+ */
+
+/* ====================================================== */
+
+/* Init spline elements in rspl */
+void
+init_spline(rspl *s) {
+ s->spline.nm = 0;
+ s->spline.spline = 0;
+ s->spline.magic = NULL;
+
+ s->spline_interp = spline_interp_rspl;
+}
+
+/* Free up the spline interpolation info */
+void free_spline(
+rspl *s /* Pointer to rspl grid */
+) {
+ if (s->spline.magic != NULL) {
+ free(s->spline.magic);
+ }
+ s->spline.nm = 0;
+ s->spline.spline = 0;
+}
+
+/* ====================================================== */
+/* Setup functions first: */
+
+/* Hermite spline, magic matrix */
+/* Indexes are: param powers 0, 1, 2, 3; Offset from base vertex 0,1; Dimension mask 0,1 */
+static double hmagic[4][2][2] = {
+ { { 1.0, 0.0}, { 0.0, 0.0} },
+ { { 0.0, 1.0}, { 0.0, 0.0} },
+ { {-3.0, -2.0}, { 3.0, -1.0} },
+ { { 2.0, 1.0}, {-2.0, 1.0} }
+};
+
+/* Allocate and initialize tangency information for each grid point */
+static void make_tang(
+rspl *s /* Pointer to rspl grid */
+) {
+ int i,p,j;
+ int di = s->di;
+ int fdi = s->fdi;
+ int nig = s->g.no;
+ float *tp; /* Pointer to tangent values */
+ int nim, mix; /* Number in magic, magic index */
+ float *tang_alloc, *tang; /* Tangency info */
+ float *gt; /* Working grid point */
+
+//printf("~~make_tang called\n");
+ /* Organized as: tang[[grid]][di combs.][fdi] */
+ /* Allocate space for tangency info */
+ if ((tang_alloc = (float *) malloc(sizeof(float) * nig * (((1 << di) * fdi)+G_XTRA))) == NULL)
+ error("rspl malloc failed - tangecy points");
+ tang = tang_alloc + G_XTRA; /* Offset for flags and non-mono error */
+
+ /* For all grid points */
+ for (tp = tang, gt = s->g.a, i = 0; i < nig; i++, gt += s->g.pss, tp += G_XTRA) {
+ int ee;
+/* printf("\n~~ grid point %d\n",i); */
+
+ /* Look at surrounding grid points in combinations of +- 1 all dimensions */
+ for (ee = 0; ee < (1 << di); ee++) {
+ double av[MXRO]; /* average */
+ int nia = 0; /* Number in average */
+ int f, ec;
+
+/* printf("Dim combo %d\n",ee); */
+ /* special case - base value */
+ if (ee == 0) {
+ *((int *)(tp-2)) = *((int *)(gt-2)); /* Copy flags */
+ tp[-1] = gt[-1]; /* Copy ink limit function value */
+ for (f = 0; f < fdi; f++) {
+ *tp++ = gt[f];
+/* printf("Tang value out %d = %f\n",f,tp[-1]); */
+ }
+ continue;
+ }
+ for (f = 0; f < fdi; f++)
+ av[f] = 0.0; /* Init average */
+ /* For all surroundin grid points in this combination */
+ for (ec = 0; ec < (1 << di); ec++) {
+ int xo, io, sgn, e, ex;
+/* printf("~~checking out surrounding combo %d\n",ec); */
+ if (ec & ~ee) {
+/* printf("~~being skipped\n"); */
+ continue; /* Skip invalid combo */
+ }
+ xo = io = 0; /* Grid float offset */
+ sgn = 1; /* Sign */
+ ex = 0; /* Flag - No extrapolation */
+ for (e = 0; e < di; e++) { /* For each dimension */
+/* printf("~~checking dimension %d\n",e); */
+ if (!(ee & (1 << e))) {
+/* printf("~~dimension not active\n"); */
+ continue; /* Dimension is not active */
+ }
+ if (ec & (1 << e)) {
+ /* If + dimension is valid */
+ if (((G_FL(gt,e) & 3) > 0) || (G_FL(gt,e) & 0x4)) {
+ int to = s->g.fci[e]; /* +1 in dimension */
+ io += to; /* real/pivot point */
+ xo += to; /* reflected point */
+ } else {
+ ex = 1; /* Use extrapolation */
+ xo -= s->g.fci[e]; /* -1 in dimension */
+ }
+ } else {
+ sgn = -sgn; /* Reverse sign */
+ /* If - dimension is valid */
+ if (((G_FL(gt,e) & 3) > 0) || !(G_FL(gt,e) & 0x4)) {
+ int to = -s->g.fci[e]; /* -1 in dimension */
+ io += to; /* real/pivot point */
+ xo += to; /* reflected point */
+ } else {
+ ex = 1; /* Use extrapolation */
+ xo += s->g.fci[e]; /* +1 in dimension */
+ }
+ }
+ }
+ /* Add surrounding grid points value into the average */
+ if (!ex) {
+ for (f = 0; f < fdi; f++)
+ av[f] += (double)sgn * gt[io + f];
+ } else { /* Extrapolate point beyond edge */
+ /* Use an extrapolation that tries to maintain curvature */
+ for (f = 0; f < fdi; f++) {
+ double v0,v1,v2;
+ v0 = gt[io + f]; /* Pivot point */
+ v1 = gt[xo + f]; /* Reflection of target in pivot */
+ v2 = gt[2 * xo - io + f]; /* Reflection +2 */
+ av[f] += (double)sgn * (3.0 * (v0 - v1) + v2);
+ }
+ }
+ nia++;
+ }
+ for (f = 0; f < fdi; f++) {
+ *tp++ = (float)(av[f]/(double)nia);
+/* printf("Tang value out %d = %f, average of %d\n",f,tp[-1],nia); */
+ }
+ } /* Next dimension combination */
+ } /* Next grid point */
+
+ /* Create a full sized hermite magic matrix */
+ /* Organized as: magic[4^di][2^di][2^di] */
+ /* = [param power combos][cube vertex index][di combos], */
+ /* but then only store non-zero weight values. */
+ for (i = 0, nim = 1; i < di; nim *= 10, i++); /* Number of entries needed */
+ if (s->spline.magic == NULL) { /* Allocate space for magic matrix info */
+ if ((s->spline.magic = (magic_data *) malloc(sizeof(magic_data) * nim)) == NULL)
+ error("rspl malloc failed - hermite magic matrix data");
+ }
+
+ mix = 0;
+ for (p = 0; p < (1 << (2 * di)); p++) { /* For all combinations of parameter powers */
+ for (i = 0; i < (1 << di); i++) { /* For all corners of cube */
+ for (j = 0; j < (1 << di); j++) { /* For all dimension combinations */
+ int ii;
+ double wgt = 1.0;
+ for (ii = 0; ii < di; ii++) {
+ wgt *= hmagic[3&(p>>(2*ii))][1&(i>>ii)][1&(j>>ii)];
+ }
+ if (wgt != 0.0) { /* record non-zero weight value */
+ s->spline.magic[mix].p = p;
+ s->spline.magic[mix].i = i;
+ s->spline.magic[mix].j = fdi * j; /* Pre-scale */
+ s->spline.magic[mix].wgt = (float)wgt;
+ mix++;
+ }
+ }
+ }
+ }
+ /* mix should == nim! */
+ s->spline.nm = nim;
+
+ /* Free basic grid info, and substitute tangency enhanced version */
+ /* ~~~~!! need to free any other structures in rspl that depend on */
+ /* ~~~~!! g.pss size, ie. rev stuff ??? */
+ if (s->g.alloc != NULL)
+ free((void *)s->g.alloc);
+
+ s->g.alloc = tang_alloc;
+ s->g.a = tang;
+
+ /* Adjust index tables */
+ s->g.pss = (1 << di) * fdi + G_XTRA;
+ for (i = 0; i < di; i++)
+ s->g.fci[i] = s->g.ci[i] * s->g.pss; /* In floats */
+ for (i = 0; i < (1 << di); i++)
+ s->g.fhi[i] = s->g.hi[i] * s->g.pss; /* In floats */
+
+ s->spline.spline = 1;
+
+//printf("~~make_tang finished\n");
+}
+
+/* Do a Hermite spline smooth interpolation based on the finest grid */
+/* (To do this more accurately, the data point interpolation within */
+/* the grid itteration should be of the same order. This increases */
+/* itteration complexity quite a bit, so we won't bother for the moment.) */
+/* This code is not optimised for speed. */
+/* Return 0 if OK, 1 if input was clipped to grid */
+int spline_interp_rspl(
+rspl *s,
+co *cp /* Input value and returned function value */
+) {
+ int e,f,p,i;
+ int di = s->di;
+ int fdi = s->fdi;
+ double ppw[MXRI][4]; /* Parameter powers of 0, 1, 2, 3 */
+ float *ga[POW2MXRI]; /* Pointers to grid cubes data in tang[] */
+ magic_data *tp; /* Pointer to items in magic matrix */
+ int rv = 0;
+
+/* printf("~~smooth interp called\n"); */
+
+ /* This is a restricted size function */
+ if (di > MXRI)
+ error("rspl: spline can't handle di = %d",di);
+ if (fdi > MXRO)
+ error("rspl: spline can't handle fdi = %d",fdi);
+
+ if (s->spline.spline == 0) /* Compute tangent info if it doesn't exist */
+ make_tang(s);
+
+ /* Locate grid base point, and position with base cube */
+ ga[0] = s->g.a; /* Base pointer of cube */
+ for (e = 0; e < di; e++) {
+ double t, pe;
+ int mi, gres_1 = s->g.res[e]-1;
+
+ pe = cp->p[e];
+ if (pe < s->g.l[e]) { /* Clip to grid */
+ pe = s->g.l[e];
+ rv = 1;
+ }
+ if (pe > s->g.h[e]) {
+ pe = s->g.h[e];
+ rv = 1;
+ }
+ t = (pe - s->g.l[e])/s->g.w[e];
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres_1)
+ mi = gres_1-1;
+ ga[0] += s->g.fci[e] * mi; /* Add offset in dimen */
+ t = t - (double)mi;; /* sub-cube offset = parameter in dimension e */
+ ppw[e][0] = 1.0; /* Powers of parameter */
+ ppw[e][1] = t;
+ ppw[e][2] = t * t;
+ ppw[e][3] = t * t * t;
+ }
+
+ /* Compute indexes into cube corners in tangent array */
+ for (i = 1; i < (1 << di); i++)
+ ga[i] = ga[0] + s->g.fhi[i];
+
+ /* Now compute the output values */
+ for (f = 0; f < fdi; f++) /* Zero output value sums */
+ cp->v[f] = 0.0;
+
+ /* For all non-zero combinations of parameter powers */
+ {
+ double ppc = -1000.0; /* Parameter power combination */
+ for (tp = s->spline.magic, p = -1; tp < &s->spline.magic[s->spline.nm]; tp++) {
+ double wgt; /* Magic matrix weight */
+ float *gp; /* Pointer to vertex data */
+
+ if (p != tp->p) { /* Param power needs re-calculating */
+ int pp;
+ p = tp->p;
+ for (ppc = 1.0, pp = 0; pp < di; pp++)
+ ppc *= ppw[pp][3&(p>>(2*pp))]; /* comb. of param powers value */
+ }
+
+ wgt = tp->wgt * ppc; /* matrix times parameter */
+ gp = ga[tp->i] + tp->j; /* Point to base of vertex data */
+ for (f = 0; f < fdi; f++) /* For all output values */
+ cp->v[f] += wgt * gp[f];
+ }
+ }
+/* printf("~~smooth interp finished\n"); */
+ return rv;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rspl/stest.c b/rspl/stest.c
new file mode 100644
index 0000000..d1cf2da
--- /dev/null
+++ b/rspl/stest.c
@@ -0,0 +1,654 @@
+
+/*
+ * Scattered Data Interpolation
+ * with multilevel B-splines
+ * research.
+ *
+ * This is from the paper
+ * "Scattered Data Interpolation with Multilevel B-Splines"
+ * by Seungyong Lee, George Wolberg and Sung Yong Shin,
+ */
+
+/*
+ * Author: Graeme W. Gill
+ * Date: 2001/1/1
+ *
+ * Copyright 2000 - 2001 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "../numeric/numlib.h"
+
+
+#ifndef NUMSUP_H
+void error(char *fmt, ...), warning(char *fmt, ...);
+#endif
+
+#define MXDI 4
+#define MXDO 4
+
+/* A control point */
+typedef struct {
+ double p[MXDI];
+ double v[MXDO];
+} co;
+
+/* Neighborhood latice cache data */
+typedef struct {
+ int c[MXDI]; /* Coordinate */
+ int xo; /* Offset into srbs latice */
+ double w; /* B-spline basis weight */
+} neigh;
+
+/* Structure that represents a resolution level of B-splines */
+struct _srbs {
+ struct _mrbs *p; /* Parent structure */
+ int res; /* Basic resolution */
+ int coi[MXDI]; /* Double increment for each input dimension into latice */
+ double *lat; /* Control latice, extending from +/- 1 from 0..res-1 */
+ double *_lat; /* Allocation base of lat */
+ int lsize, loff; /* Number of doubles in _lat, offset of lat from _lat */
+ double w[MXDI]; /* Input data cell width */
+ neigh *n; /* Neighborhood latice cache */
+ int nsize; /* Number of n entries */
+}; typedef struct _srbs srbs;
+
+/* Structure that represents the whole scattered interpolation state */
+struct _mrbs {
+ int di; /* Input dimensions */
+ int fdi; /* Output dimensions */
+ int tres; /* Target resolution */
+ double smf; /* Smoothing factor */
+ int npts; /* Number of data points */
+ co *pts; /* Coordinate points */
+ double l[MXDI], h[MXDI]; /* Input data range, cell width */
+ srbs *s; /* Current B-spline latice */
+}; typedef struct _mrbs mrbs;
+
+static void delete_srbs(srbs *s);
+
+/* Create a new empty mrbs */
+static mrbs *new_mrbs(
+int di, /* Input dimensionality */
+int fdi, /* Output dimesionality */
+int res, /* Target resolution */
+double smf /* Smoothing factor */
+) {
+ mrbs *p;
+ if ((p = (mrbs *)malloc(sizeof(mrbs))) == NULL)
+ error("Malloc mrbs failed");
+
+ p->di = di;
+ p->fdi = fdi;
+ p->tres = res;
+ p->smf = smf;
+ p->s = NULL;
+
+ return p;
+}
+
+static void delete_mrbs(mrbs *p) {
+
+ if (p != NULL) {
+ delete_srbs(p->s);
+ free(p);
+ }
+}
+
+/* Create a new empty srbs */
+static srbs *new_srbs(
+mrbs *p, /* Parent mrbs */
+int res /* Resolution of this srbs */
+) {
+ srbs *s;
+ int e, f;
+ double *_lat, *lat; /* Latice base address */
+ int ix, oe, oo[MXDI]; /* Neighborhood offset index, counter */
+
+ if ((s = (srbs *)malloc(sizeof(srbs))) == NULL)
+ error("Malloc srbs failed");
+
+ s->p = p;
+ s->res = res;
+
+ for (s->lsize = p->fdi, s->nsize = 1, e = 0; e < p->di; e++) {
+ s->coi[e] = s->lsize; /* (double) increment in this input dimension */
+ s->lsize *= (res + 2); /* Latice in 1D +/- 1 */
+ s->nsize *= 4; /* Neighborhood of 4 */
+ }
+
+ if ((s->_lat = (double *)malloc(s->lsize * sizeof(double))) == NULL)
+ error("Malloc srbs latice failed");
+
+ /* Compute the base address */
+ for (s->loff = 0, e = 0; e < p->di; e++) {
+ s->loff += s->coi[e]; /* Offset by 1 in each input dimension */
+ }
+ s->lat = s->_lat + s->loff;
+
+ /* Figure the cell width */
+ for (e = 0; e < p->di; e++)
+ s->w[e] = (p->h[e] - p->l[e])/(res-1.0);
+
+ /* Setup neighborhood cache info */
+ if ((s->n = (neigh *)malloc(s->nsize * sizeof(neigh))) == NULL)
+ error("Malloc srbs neighborhood failed");
+
+ for (oe = 0; oe < p->di; oe++)
+ oo[oe] = 0;
+
+ for(ix = oe = 0; oe < p->di; ix++) {
+ int xo;
+ for (xo = e = 0; e < p->di; e++) {
+ s->n[ix].c[e] = oo[e];
+ xo += s->coi[e] * oo[e]; /* Accumulate latice offset */
+ }
+ s->n[ix].xo = xo;
+ s->n[ix].w = 0.0;
+
+ /* Increment destination offset counter */
+ for (oe = 0; oe < p->di; oe++) {
+ if (++oo[oe] <= 3) /* Counting from 0 ... 3 */
+ break;
+ oo[oe] = 0;
+ }
+ }
+
+ return s;
+}
+
+/* Destroy a srbs */
+static void delete_srbs(srbs *s) {
+ if (s != NULL) {
+ free(s->_lat);
+ free(s->n);
+ free(s);
+ }
+}
+
+/* Dump the 2D -> 1D contents of an srbs */
+static void dump_srbs(srbs *s) {
+ int e, f;
+ int ce, co[MXDI]; /* latice counter */
+ mrbs *p = s->p; /* Parent object */
+
+ /* Init the counter */
+ for (ce = 0; ce < p->di; ce++)
+ co[ce] = -1;
+ ce = 0;
+
+ f = 0;
+ while(ce < p->di) {
+ double v;
+ int off = 0; /* Latice offset */
+ for (e = 0; e < p->di; e++) {
+ off += co[e] * s->coi[e]; /* Accumulate latice offset */
+ }
+ v = s->lat[off + f]; /* Value of this latice point */
+
+ printf("Latice at [%d][%d] = %f\n",co[1],co[0],v);
+
+ /* Increment the latice counter */
+ for (ce = 0; ce < p->di; ce++) {
+ if (++co[ce] <= s->res) /* Counting from -1 ... s->res */
+ break;
+ co[ce] = -1;
+ }
+ }
+}
+
+/* Initialise an srbs with a linear approximation to the scattered data */
+static void linear_srbs(
+srbs *s
+) {
+ int i, e, f;
+ mrbs *p = s->p; /* Parent object */
+ double **A; /* A matrix holding scattered data points */
+ double *B; /* B matrix holding RHS & solution */
+
+ /* Allocate the matricies */
+ B = dvector(0, p->npts-1);
+ A = dmatrix(0, p->npts-1, 0, p->di);
+
+ /* For each output dimension, solve the linear equation coeficients */
+ for (f = 0; f < p->fdi; f++) {
+ int ce, co[MXDI]; /* latice counter */
+
+ /* Init A[][] with the scattered data points positions */
+ /* Also init B[] with the value for this output dimension */
+ for (i = 0; i < p->npts; i++) {
+ for (e = 0; e < p->di; e++)
+ A[i][e] = p->pts[i].p[e];
+ A[i][e] = 1.0;
+ B[i] = p->pts[i].v[f];
+ }
+
+ /* Solve the equation A.x = b using SVD */
+ /* (The w[] values are thresholded for best accuracy) */
+ /* Return non-zero if no solution found */
+ if (svdsolve(A, B, p->npts, p->di+1) != 0)
+ error("SVD least squares failed");
+ /* A[][] will have been changed, and B[] holds the p->di+1 coefficients */
+
+ /* Use the coefficients to initialise the srbs values */
+ for (ce = 0; ce < p->di; ce++)
+ co[ce] = -1;
+ ce = 0;
+
+ while(ce < p->di) {
+ double v = B[p->di]; /* Constant */
+ int off = 0; /* Latice offset */
+ for (e = 0; e < p->di; e++) {
+ double lv;
+ lv = p->l[e] + s->w[e] * co[e]; /* Input value for this latice location */
+ v += B[e] * lv;
+ off += co[e] * s->coi[e]; /* Accumulate latice offset */
+ }
+ s->lat[off + f] = v; /* Value of this latice point */
+
+ /* Increment the latice counter */
+ for (ce = 0; ce < p->di; ce++) {
+ if (++co[ce] <= s->res) /* Counting from -1 ... s->res */
+ break;
+ co[ce] = -1;
+ }
+ }
+ }
+ free_dmatrix(A, 0, p->npts-1, 0, p->di);
+ free_dvector(B, 0, p->npts-1);
+}
+
+/* Do a latice refinement - upsample the current */
+/* source latice to the destination latice. */
+static void refine_srbs(
+srbs *ds, /* Destination srbs */
+srbs *ss /* Source srbs */
+) {
+ mrbs *p = ss->p; /* Parent object */
+ int ce, co[MXDI]; /* Source coordinate counter */
+ int six; /* Source index */
+ int dix; /* destination index */
+ static double _wt[5] = { 1.0/8.0, 4.0/8.0, 6.0/8.0, 4.0/8.0, 1.0/8.0 };
+ static double *wt = &_wt[2]; /* 1D Distribution weighting */
+
+ /* Zero the destination latice before accumulating values */
+ for (dix = 0; dix < ds->lsize; dix++)
+ ds->_lat[dix] = 0.0;
+
+ /* Now for each source latice entry, add weighted portions */
+ /* to the associated destination points */
+
+ /* Init the source coordinate counter */
+ for (ce = 0; ce < p->di; ce++)
+ co[ce] = -1;
+ ce = 0;
+ six = -ss->loff;
+
+ while(ce < p->di) {
+ int oe, oo[MXDI]; /* Destination offset counter */
+
+//printf("Source coord %d %d, offset %d, value %f\n",co[0], co[1], six, ss->lat[six]);
+ /* calc destination index, and init offest counter */
+ for (dix = oe = 0; oe < p->di; oe++) {
+ oo[oe] = -2;
+ dix += co[oe] * 2 * ds->coi[oe]; /* Accumulate dest offset */
+ }
+ oe = 0;
+
+//printf("Dest coord %d %d\n",co[0] * 2, co[1] * 2);
+ /* For all the offsets from the destination point */
+ while(oe < p->di) {
+ int e, f, dixo; /* Destination index offset */
+ double w = 1.0; /* Weighting */
+
+//printf("dest offset %d %d\n",oo[0], oo[1]);
+ /* Compute dest index offset, and check that we are not outside the destination */
+ for (dixo = e = 0; e < p->di; e++) {
+ int x = co[e] * 2 + oo[e]; /* dest coord */
+ dixo += oo[e] * ds->coi[e]; /* Accumulate dest offset */
+//printf("x[%d] = %d\n",e, x);
+ w *= wt[oo[e]]; /* Compute distribution weighting */
+ if (x < -1 || x > ds->res)
+ break; /* No good */
+ }
+ if (e >= p->di) { /* We are within the destination latice */
+//if ((co[0] * 2 + oo[0]) == 0 && (co[1] * 2 + oo[1]) == 0) {
+//printf("Source coord %d %d, offset %d, value %f\n",co[0], co[1], six, ss->lat[six]);
+//printf("Dest coord %d %d ix %d, weight %f\n",co[0] * 2 + oo[0], co[1] * 2 + oo[1], dix+dixo, w);
+//}
+
+ for (f = 0; f < p->fdi; f++) { /* Distribute weighted values */
+ double v = ss->lat[six + f];
+//if ((co[0] * 2 + oo[0]) == 0 && (co[1] * 2 + oo[1]) == 0)
+//printf("Value being dist %f, weighted value %f\n", v, v * w);
+ ds->lat[dix + dixo + f] += v * w;
+ }
+ }
+
+ /* Increment destination offset counter */
+ for (oe = 0; oe < p->di; oe++) {
+ if (++oo[oe] <= 2) /* Counting from -2 ... +2 */
+ break;
+ oo[oe] = -2;
+ }
+ }
+
+ /* Increment the source index and coordinat counter */
+ six += p->fdi;
+ for (ce = 0; ce < p->di; ce++) {
+ if (++co[ce] <= ss->res) /* Counting from -1 ... ss->res */
+ break;
+ co[ce] = -1;
+ }
+ }
+}
+
+/* Compute the Cubic B-spline weightings for a given t */
+void basis(double b[4], double t) {
+ double _t3, _t2, _t1, _3t3, _3t2, _3t1, _6t2;
+
+ _t1 = t/6.0;
+ _t2 = _t1 * _t1;
+ _t3 = _t2 * _t1;
+ _3t1 = 3.0 * _t1;
+ _3t2 = 3.0 * _t2;
+ _3t3 = 3.0 * _t3;
+ _6t2 = 6.0 * _t2;
+
+ b[0] = - _t3 + _3t2 - _3t1 + 1.0/6.0;
+ b[1] = _3t3 - _6t2 + 4.0/6.0;
+ b[2] = -_3t3 + _3t2 + _3t1 + 1.0/6.0;
+ b[3] = _t3;
+}
+
+
+/* Improve an srbs to make it closer to the scattered data */
+static void improve_srbs(
+srbs *s
+) {
+ int i, e, f;
+ mrbs *p = s->p; /* Parent object */
+ double *delta; /* Delta accumulation */
+ double *omega; /* Omega accumulation */
+
+ /* Allocate temporary accumulation arrays */
+ if ((delta = (double *)calloc(sizeof(double), s->lsize)) == NULL)
+ error("Malloc srbs temp latice failed");
+ delta += s->loff;
+ if ((omega = (double *)calloc(sizeof(double), s->lsize)) == NULL)
+ error("Malloc srbs temp latice failed");
+ omega += s->loff;
+
+ /* For each scattered data point */
+ for (i = 0; i < p->npts; i++) {
+ int ix; /* Latice index of base of neighborhood */
+ double b[MXDI][4]; /* B-spline basis factors for each dimension */
+ double sws; /* Sum of all the basis factors squared */
+ double ve[MXDO]; /* Current output value error */
+ int nn; /* Neighbor counter */
+
+ /* Figure out our neighborhood */
+ for (ix = e = 0; e < p->di; e++) {
+ int x;
+ double t, sp, fp;
+ sp = (p->pts[i].p[e] - p->l[e])/s->w[e]; /* Scaled position */
+ fp = floor(sp);
+ x = (int)(fp - 1.0); /* Grid coordinate */
+ ix += s->coi[e] * x; /* Accume latice offset */
+ t = sp - fp; /* Spline parameter */
+ basis(b[e], t); /* Compute basis function values */
+ }
+
+ /* Compute the grid basis weight functions, */
+ /* the sum of the weights squared, and the current */
+ /* output value estimate. */
+ for (f = 0; f < p->fdi; f++)
+ ve[f] = p->pts[i].v[f]; /* Target output value */
+ for (sws = 0.0, nn = 0; nn < s->nsize; nn++) {
+ double w;
+ for (w = 1.0, e = 0; e < p->di; e++)
+ w *= b[e][s->n[nn].c[e]];
+ s->n[nn].w = w; /* cache weighting */
+ sws += w * w;
+ for (f = 0; f < p->fdi; f++)
+ ve[f] -= w * s->lat[ix + s->n[nn].xo + f]; /* Subtract current aprox value */
+ }
+printf("Error at point %d = %f\n",i,ve[0]);
+
+ /* Accumulate the delta and omega factors */
+ /* for this resolutions improvement. */
+ for (nn = 0; nn < s->nsize; nn++) {
+ double ws, ww, w = s->n[nn].w;
+ int xo = ix + s->n[nn].xo; /* Latice offset */
+ ww = w * w;
+ ws = ww * w/sws; /* Scale factor for delta */
+ omega[xo] += ww; /* Accumulate omega */
+ for (f = 0; f < p->fdi; f++)
+ delta[xo + f] += ws * ve[f]; /* Accumulate delta */
+printf("Distributing omega %f to %d %d\n",ww,s->n[nn].c[0],s->n[nn].c[1]);
+printf("Distributing delta %f to %d %d\n",ws * ve[0],s->n[nn].c[0],s->n[nn].c[1]);
+ }
+ }
+
+ omega -= s->loff; /* Base them back to -1 corner */
+ delta -= s->loff;
+
+ /* Go through the delta and omega arrays, */
+ /* compute and add the refinements to the current */
+ /* B-spline control latice. */
+ for (i = 0; i < s->lsize; i++) {
+ double om = omega[i];
+ if (om != 0.0) {
+ for (f = 0; f < p->fdi; f++)
+ s->_lat[i] += delta[i + f]/om;
+printf("Adjusting latice index %d by %f to give %f\n",i, delta[i]/om, s->_lat[i]);
+ }
+ }
+
+ /* Done with temporary arrays */
+ free(omega);
+ free(delta);
+}
+
+/* Return the interpolated value for a given point */
+/* Return NZ if input point is out of range */
+static int lookup_srbs(
+mrbs *p,
+co *c /* Point to interpolate */
+) {
+ srbs *s = p->s;
+ int e, f;
+ int ix; /* Latice index of base of neighborhood */
+ double b[MXDI][4]; /* B-spline basis factors for each dimension */
+ int nn; /* Neighbor counter */
+
+ /* Figure out our neighborhood */
+ for (ix = e = 0; e < p->di; e++) {
+ int x;
+ double t, sp, fp;
+ sp = c->p[e];
+ if (sp < p->l[e] || sp > p->h[e])
+ return 1;
+ sp = (sp - p->l[e])/s->w[e]; /* Scaled position */
+ fp = floor(sp);
+ x = (int)(fp - 1.0); /* Grid coordinate */
+ ix += s->coi[e] * x; /* Accume latice offset */
+ t = sp - fp; /* Spline parameter */
+ basis(b[e], t); /* Compute basis function values */
+ }
+
+ /* Compute the the current output value. */
+ for (f = 0; f < p->fdi; f++)
+ c->v[f] = 0.0;
+ for (nn = 0; nn < s->nsize; nn++) {
+ double w;
+ for (w = 1.0, e = 0; e < p->di; e++)
+ w *= b[e][s->n[nn].c[e]];
+ for (f = 0; f < p->fdi; f++)
+ c->v[f] += w * s->lat[ix + s->n[nn].xo + f]; /* Accume spline value */
+ }
+
+ return 0;
+}
+
+/* Take a list of scattered data points, */
+/* and setup the mrbs. */
+void set_mrbs(
+mrbs *p, /* mrbs to set up */
+co *pts, /* scattered data points (taken) */
+int npts, /* number of scattered data points */
+double *l, /* Input data range, low (May be NULL) */
+double *h /* Input data range, high (May be NULL) */
+) {
+ int res;
+ int i, e, f;
+ srbs *s0 = NULL, *s1;
+
+ /* Establish the input data range */
+ for (e = 0; e < p->di; e++) {
+ if (l == NULL)
+ p->l[e] = 1e60;
+ else
+ p->l[e] = l[e];
+ if (h == NULL)
+ p->h[e] = -1e60;
+ else
+ p->h[e] = h[e];
+ }
+ for (i = 0; i < npts; i++) {
+ for (e = 0; e < p->di; e++) {
+ if (pts[i].p[e] < p->l[e])
+ p->l[e] = pts[i].p[e];
+ if (pts[i].p[e] > p->h[e])
+ p->h[e] = pts[i].p[e];
+ }
+ }
+
+ /* Take ownership the data */
+ p->pts = pts;
+ p->npts = npts;
+
+ /* Create an initial srbs */
+ res = 2;
+ if ((s1 = new_srbs(p, 2)) == NULL)
+ error("new_srbs failed");
+
+ /* Set it up with a linear first approximation */
+ linear_srbs(s1);
+dump_srbs(s1);
+
+ /* Build up the resolution */
+ for (res = 2 * res -1; res < p->tres; res = 2 * res -1) {
+
+printf("~1 doing resolution %d\n",res);
+ delete_srbs(s0);
+ s0 = s1;
+ if ((s1 = new_srbs(p, res)) == NULL)
+ error("new_srbs failed");
+
+ refine_srbs(s1, s0);
+dump_srbs(s1);
+ improve_srbs(s1);
+ }
+
+ delete_srbs(s0);
+ p->s = s1; /* Final resolution */
+}
+
+
+/* - - - - - - - - - - - - - - - - */
+
+/* Some test points */
+#define NP 5
+co tpts[NP] = {
+ { { 1, 5 }, { 3 } },
+ { { 2, 9 }, { 6 } },
+ { { 8, 0 }, { 1 } },
+ { { 5, 4 }, { 10 } },
+ { { 3, 9 }, { 4 } }
+};
+
+#define FRES 33
+
+int
+main(void) {
+ double ll[MXDI], hh[MXDI];
+ mrbs *p;
+ int i;
+
+#ifdef NEVER /* Make points be on a plane */
+{
+for (i = 0; i < NP; i++) {
+ tpts[i].v[0] = 0.5 * tpts[i].p[0] + 0.7 * tpts[i].p[1] + 3.0;
+printf("%f, %f -> %f\n", tpts[i].p[0], tpts[i].p[1], tpts[i].v[0]);
+}
+}
+#endif
+ error_program = "stest";
+
+ printf("Starting test\n");
+ p = new_mrbs(2, 1, FRES, 1.0);
+
+ ll[0] = 0.0;
+ ll[1] = 0.0;
+ hh[0] = 10.0;
+ hh[1] = 10.0;
+ set_mrbs(p, tpts, NP, ll, hh);
+
+ printf("Interpolation setup\n");
+
+ /* Check out the accuracy */
+ for (i = 0; i < NP; i++) {
+ co tp;
+ tp.p[0] = tpts[i].p[0];
+ tp.p[1] = tpts[i].p[1];
+ if (lookup_srbs(p, &tp))
+ printf("Point %d, %f %f outside domain\n",i,tpts[i].p[0],tpts[i].p[1]);
+ else {
+ printf("Point %d has value %f, should be %f\n",i,tp.v[0], tpts[i].v[0]);
+ }
+ }
+
+ printf("Test done\n");
+ return 0;
+}
+
+#ifndef NUMSUP_H
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"stest: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"stest: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#endif /* NUMSUP_H */
+
diff --git a/rspl/t2d.c b/rspl/t2d.c
new file mode 100644
index 0000000..b1167ef
--- /dev/null
+++ b/rspl/t2d.c
@@ -0,0 +1,1016 @@
+/************************************************/
+/* Test RSPL in 2D */
+/************************************************/
+
+/* Author: Graeme Gill
+ * Date: 22/4/96
+ * Derived from cmatch.c
+ * Copyright 1995 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+#define DEBUG
+#define DETAILED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include "rspl.h"
+#include "tiffio.h"
+#include "plot.h"
+
+
+#ifdef NEVER
+FILE *verbose_out = stdout;
+int verbose_level = 6; /* Current verbosity level */
+ /* 0 = none */
+ /* !0 = diagnostics */
+#endif /* NEVER */
+
+#define PLOTRES 256
+#define WIDTH 400 /* Raster size */
+#define HEIGHT 400
+
+#define MAX_ITS 500
+#define IT_TOL 0.0005
+#define GRES0 25 /* Default resolutions */
+#define GRES1 25
+#undef NEVER
+#define ALWAYS
+
+//double t1xa[PNTS] = { 0.2, 0.25, 0.30, 0.35, 0.40, 0.44, 0.48, 0.51, 0.64, 0.75 };
+//double t1ya[PNTS] = { 0.3, 0.35, 0.4, 0.41, 0.42, 0.46, 0.5, 0.575, 0.48, 0.75 };
+
+/* 1D test function repeated 3 times along x = 0.5 */
+co test_points1[] = {
+ {{ 0.4,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.4,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.4,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.4,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.4,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.4,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.4,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.4,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.4,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.4,0.75 },{ 0.75 }}, /* 9 */
+
+ {{ 0.5,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.5,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.5,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.5,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.5,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.5,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.5,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.5,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.5,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.5,0.75 },{ 0.75 }}, /* 9 */
+
+ {{ 0.6,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.6,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.6,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.6,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.6,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.6,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.6,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.6,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.6,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.6,0.75 },{ 0.75 }} /* 9 */
+};
+
+/* x + y^2 function with one non-monotonic point */
+co test_points2[] = {
+ {{ 0.1,0.1,0.5,0.0 },{ 0.11 }}, /* 0 */
+ {{ 0.2,0.7,0.1,0.3 },{ 0.69 }}, /* 1 */
+ {{ 0.8,0.8,0.8,0.2 },{ 1.44 }}, /* 2 */
+ {{ 0.5,0.6,0.4,0.9 },{ 0.86 }}, /* 3 */
+ {{ 0.2,0.5,0.2,0.7 },{ 0.45 }}, /* 4 */
+// {{ 0.3,0.7,0.2,0.8 },{ 0.35 }}, /* nm 5 */
+ {{ 0.5,0.5,0.2,0.8 },{ 0.30 }}, /* nm 5 */
+ {{ 0.5,0.4,0.9,0.3 },{ 0.66 }}, /* 6 */
+ {{ 0.1,0.9,0.7,0.4 },{ 0.91 }}, /* 7 */
+ {{ 0.7,0.2,0.1,0.3 },{ 0.74 }}, /* 8 */
+ {{ 0.8,0.4,0.3,0.7 },{ 0.96 }}, /* 9 */
+ {{ 0.3,0.3,0.4,0.1 },{ 0.39 }} /* 10 */
+ };
+
+/* x + y^2 function */
+co test_points3[] = {
+ {{ 0.1,0.1,0.5,0.0 },{ 0.11 }}, /* 0 */
+ {{ 0.2,0.7,0.1,0.3 },{ 0.69 }}, /* 1 */
+ {{ 0.8,0.8,0.8,0.2 },{ 1.44 }}, /* 2 */
+ {{ 0.5,0.6,0.4,0.9 },{ 0.86 }}, /* 3 */
+ {{ 0.2,0.5,0.2,0.7 },{ 0.45 }}, /* 4 */
+ {{ 0.3,0.7,0.2,0.8 },{ 0.79 }}, /* 5 */
+ {{ 0.5,0.4,0.9,0.3 },{ 0.66 }}, /* 6 */
+ {{ 0.1,0.9,0.7,0.4 },{ 0.91 }}, /* 7 */
+ {{ 0.7,0.2,0.1,0.3 },{ 0.74 }}, /* 8 */
+ {{ 0.8,0.4,0.3,0.7 },{ 0.96 }}, /* 9 */
+ {{ 0.3,0.3,0.4,0.1 },{ 0.39 }} /* 10 */
+ };
+
+/* Arbitrary values */
+co test_points4[] = {
+ {{ 0.1,0.1,0.5,0.0 },{ 0.0 }}, /* 0 */
+ {{ 0.2,0.7,0.1,0.3 },{ 0.1 }}, /* 1 */
+ {{ 0.8,0.8,0.8,0.2 },{ 0.2 }}, /* 2 */
+ {{ 0.5,0.6,0.4,0.9 },{ 0.3 }}, /* 3 */
+ {{ 0.2,0.5,0.2,0.7 },{ 0.4 }}, /* 4 */
+ {{ 0.3,0.7,0.2,0.8 },{ 0.5 }}, /* 5 */
+ {{ 0.5,0.4,0.9,0.3 },{ 0.6 }}, /* 6 */
+ {{ 0.1,0.9,0.7,0.4 },{ 0.7 }}, /* 7 */
+ {{ 0.7,0.2,0.1,0.3 },{ 0.8 }}, /* 8 */
+ {{ 0.8,0.4,0.3,0.7 },{ 0.9 }}, /* 9 */
+ {{ 0.3,0.3,0.4,0.1 },{ 1.0 }} /* 10 */
+ };
+
+/* single dimension line */
+co test_points5[] = {
+ {{ 0.4,0.2 },{ 0.10 }}, /* 0 */
+ {{ 0.5,0.4 },{ 0.50 }}, /* 1 */
+ {{ 0.6,0.6 },{ 0.90 }} /* 2 */
+ };
+
+/* Single value, many points */
+co test_points6[] = {
+ {{ 0.5,0.6 },{ 0.4 }}, /* 0 */
+ {{ 0.4,0.4 },{ 0.4 }}, /* 1 */
+ {{ 0.6,0.4 },{ 0.4 }}, /* 2 */
+ {{ 0.5,0.8 },{ 0.4 }}, /* 3 */
+ {{ 0.8,0.6 },{ 0.4 }}, /* 4 */
+ {{ 0.8,0.3 },{ 0.4 }}, /* 5 */
+ {{ 0.5,0.15 },{ 0.4 }}, /* 6 */
+ {{ 0.2,0.3 },{ 0.4 }}, /* 7 */
+ {{ 0.2,0.6 },{ 0.4 }} /* 8 */
+ };
+
+/* single value triangle */
+co test_points7[] = {
+ {{ 0.2,0.5 },{ 0.4 }}, /* 0 */
+ {{ 0.6,0.2 },{ 0.4 }}, /* 1 */
+ {{ 0.6,0.8 },{ 0.4 }} /* 2 */
+ };
+
+/* 3dap C+M L* values */
+co test_points8[] = {
+ {{ 0.0, 0.0 }, { 0.96433 }},
+ {{ 1.0, 0.0 }, { 0.54532 }},
+ {{ 0.0, 1.0 }, { 0.13844 }},
+ {{ 1.0, 1.0 }, { 0.10533 }},
+ {{ 0.52015, 0.51226 }, { 0.44379 }},
+ {{ 0.016882, 0.4899 }, { 0.55744 }},
+ {{ 0.48229, 0.014288 }, { 0.71457 }},
+ {{ 0.32501, 0.99594 }, { 0.14023 }},
+ {{ 0.9429, 0.39117 }, { 0.40529 }},
+ {{ 0.25639, 0.25624 }, { 0.65594 }},
+ {{ 0.80601, 0.62945 }, { 0.32338 }},
+ {{ 0.74113, 0.20699 }, { 0.528 }},
+ {{ 0.21766, 0.72345 }, { 0.37442 }},
+ {{ 0.64679, 0.94379 }, { 0.16175 }},
+ {{ 0.24217, 0.012757 }, { 0.81892 }},
+ {{ 0.013911, 0.25268 }, { 0.72574 }},
+ {{ 0.54723, 0.74872 }, { 0.30302 }},
+ {{ 0.016488, 0.77535 }, { 0.33234 }},
+ {{ 0.82135, 0.044133 }, { 0.57191 }},
+ {{ 0.52377, 0.2403 }, { 0.58315 }},
+ {{ 0.27798, 0.51935 }, { 0.49399 }},
+ {{ 0.1186, 0.93321 }, { 0.19912 }},
+ {{ 0.95827, 0.18481 }, { 0.48037 }},
+ {{ 0.7714, 0.48664 }, { 0.39652 }},
+ {{ 0.94209, 0.7863 }, { 0.22555 }},
+ {{ 0.9429, 0.58967 }, { 0.32235 }},
+ {{ 0.12251, 0.12897 }, { 0.78743 }},
+ {{ 0.14563, 0.38536 }, { 0.60355 }},
+ {{ 0.41616, 0.65055 }, { 0.3876 }},
+ {{ 0.38091, 0.14221 }, { 0.68198 }},
+ {{ 0.388, 0.38098 }, { 0.54479 }},
+ {{ 0.74149, 0.77517 }, { 0.25597 }},
+ {{ 0.11267, 0.62485 }, { 0.45976 }},
+ {{ 0.62755, 0.37228 }, { 0.48943 }},
+ {{ 0.6502, 0.59695 }, { 0.37031 }},
+ {{ 0.32033, 0.81669 }, { 0.28831 }},
+ {{ 0.664, 0.096944 }, { 0.60575 }},
+ {{ 0.82772, 0.33242 }, { 0.45496 }},
+ {{ 0.49121, 0.89468 }, { 0.20858 }},
+ {{ 0.84729, 0.94866 }, { 0.1453 }}
+};
+
+/* 3dap C+M a* values */
+co test_points9[] = {
+ {{ 0.0, 0.0 }, { 0.504266 }},
+ {{ 1.0, 0.0 }, { 0.14962 }},
+ {{ 0.0, 1.0 }, { 0.538792 }},
+ {{ 1.0, 1.0 }, { 0.481662 }},
+ {{ 0.52015, 0.51226 }, { 0.39446 }},
+ {{ 0.016882, 0.4899 }, { 0.5038104 }},
+ {{ 0.48229, 0.014288 }, { 0.32387 }},
+ {{ 0.32501, 0.99594 }, { 0.5028343 }},
+ {{ 0.9429, 0.39117 }, { 0.24127 }},
+ {{ 0.25639, 0.25624 }, { 0.43018 }},
+ {{ 0.80601, 0.62945 }, { 0.34684 }},
+ {{ 0.74113, 0.20699 }, { 0.274 }},
+ {{ 0.21766, 0.72345 }, { 0.480491 }},
+ {{ 0.64679, 0.94379 }, { 0.472241 }},
+ {{ 0.24217, 0.012757 }, { 0.39938 }},
+ {{ 0.013911, 0.25268 }, { 0.5035042 }},
+ {{ 0.54723, 0.74872 }, { 0.433005 }},
+ {{ 0.016488, 0.77535 }, { 0.513262 }},
+ {{ 0.82135, 0.044133 }, { 0.21553 }},
+ {{ 0.52377, 0.2403 }, { 0.35082 }},
+ {{ 0.27798, 0.51935 }, { 0.451019 }},
+ {{ 0.1186, 0.93321 }, { 0.513378 }},
+ {{ 0.95827, 0.18481 }, { 0.19309 }},
+ {{ 0.7714, 0.48664 }, { 0.32019 }},
+ {{ 0.94209, 0.7863 }, { 0.37573 }},
+ {{ 0.9429, 0.58967 }, { 0.29975 }},
+ {{ 0.12251, 0.12897 }, { 0.460094 }},
+ {{ 0.14563, 0.38536 }, { 0.471575 }},
+ {{ 0.41616, 0.65055 }, { 0.439078 }},
+ {{ 0.38091, 0.14221 }, { 0.37965 }},
+ {{ 0.388, 0.38098 }, { 0.409296 }},
+ {{ 0.74149, 0.77517 }, { 0.403494 }},
+ {{ 0.11267, 0.62485 }, { 0.4905027 }},
+ {{ 0.62755, 0.37228 }, { 0.34157 }},
+ {{ 0.6502, 0.59695 }, { 0.37896 }},
+ {{ 0.32033, 0.81669 }, { 0.477444 }},
+ {{ 0.664, 0.096944 }, { 0.28 }},
+ {{ 0.82772, 0.33242 }, {0.26821 }},
+ {{ 0.49121, 0.89468 }, { 0.47241 }},
+ {{ 0.84729, 0.94866 }, { 0.459256 }}
+};
+
+/* 3dap C+M b* values */
+co test_points10[] = {
+ {{ 0.0, 0.0 }, { 0.4918362 }},
+ {{ 1.0, 0.0 }, { 0.0 }},
+ {{ 0.0, 1.0 }, { 0.457067 }},
+ {{ 1.0, 1.0 }, { 0.407021 }},
+ {{ 0.52015, 0.51226 }, { 0.34029 }},
+ {{ 0.016882, 0.4899 }, { 0.48672 }},
+ {{ 0.48229, 0.014288 }, { 0.19406 }},
+ {{ 0.32501, 0.99594 }, { 0.453116 }},
+ {{ 0.9429, 0.39117 }, { 0.1766 }},
+ {{ 0.25639, 0.25624 }, { 0.37533 }},
+ {{ 0.80601, 0.62945 }, { 0.29851 }},
+ {{ 0.74113, 0.20699 }, { 0.16808 }},
+ {{ 0.21766, 0.72345 }, { 0.448783 }},
+ {{ 0.64679, 0.94379 }, { 0.415526 }},
+ {{ 0.24217, 0.012757 }, { 0.32194 }},
+ {{ 0.013911, 0.25268 }, { 0.486404 }},
+ {{ 0.54723, 0.74872 }, { 0.38695 }},
+ {{ 0.016488, 0.77535 }, { 0.484031 }},
+ {{ 0.82135, 0.044133 }, { 0.07184 }},
+ {{ 0.52377, 0.2403 }, { 0.26192 }},
+ {{ 0.27798, 0.51935 }, { 0.412787 }},
+ {{ 0.1186, 0.93321 }, { 0.463822 }},
+ {{ 0.95827, 0.18481 }, { 0.09177 }},
+ {{ 0.7714, 0.48664 }, { 0.26049 }},
+ {{ 0.94209, 0.7863 }, { 0.3249 }},
+ {{ 0.9429, 0.58967 }, { 0.25115 }},
+ {{ 0.12251, 0.12897 }, { 0.419966 }},
+ {{ 0.14563, 0.38536 }, { 0.436771 }},
+ {{ 0.41616, 0.65055 }, { 0.39638 }},
+ {{ 0.38091, 0.14221 }, { 0.29133 }},
+ {{ 0.388, 0.38098 }, { 0.35442 }},
+ {{ 0.74149, 0.77517 }, { 0.35501 }},
+ {{ 0.11267, 0.62485 }, { 0.466548 }},
+ {{ 0.62755, 0.37228 }, { 0.2675 }},
+ {{ 0.6502, 0.59695 }, { 0.32833 }},
+ {{ 0.32033, 0.81669 }, { 0.438066 }},
+ {{ 0.664, 0.096944 }, { 0.15598 }},
+ {{ 0.82772, 0.33242 }, { 0.18834 }},
+ {{ 0.49121, 0.89468 }, { 0.423113 }},
+ {{ 0.84729, 0.94866 }, { 0.3979 }}
+};
+
+/* Values at edges test */
+double test_f11(double x, double y) { /* Function that computes values */
+ double val = 0.0;
+
+ val = (x * x - 0.5) * 0.6
+ + (y * y - 0.5) * 0.4
+ + 0.5;
+
+ return val;
+}
+co test_points11[] = {
+ {{ 0.0, 0.0 }},
+ {{ 0.0, 0.25 }},
+ {{ 0.0, 0.5 }},
+ {{ 0.0, 0.75 }},
+ {{ 0.0, 1.0 }},
+
+ {{ 0.25, 0.0 }},
+ {{ 0.25, 0.25 }},
+ {{ 0.25, 0.5 }},
+ {{ 0.25, 0.75 }},
+ {{ 0.25, 1.0 }},
+
+ {{ 0.5, 0.0 }},
+ {{ 0.5, 0.25 }},
+ {{ 0.5, 0.5 }},
+ {{ 0.5, 0.75 }},
+ {{ 0.5, 1.0 }},
+
+ {{ 0.75, 0.0 }},
+ {{ 0.75, 0.25 }},
+ {{ 0.75, 0.5 }},
+ {{ 0.75, 0.75 }},
+ {{ 0.75, 1.0 }},
+
+ {{ 1.0, 0.0 }},
+ {{ 1.0, 0.25 }},
+ {{ 1.0, 0.5 }},
+ {{ 1.0, 0.75 }},
+ {{ 1.0, 1.0 }},
+
+
+ {{ 0.2, 0.7 }},
+ {{ 0.2, 0.8 }},
+ {{ 0.2, 0.9 }},
+ {{ 0.2, 1.0 }},
+
+ {{ 0.1, 0.7 }},
+ {{ 0.1, 0.8 }},
+ {{ 0.1, 0.9 }},
+ {{ 0.1, 1.0 }},
+
+ {{ 0.0, 0.7 }},
+ {{ 0.0, 0.8 }},
+ {{ 0.0, 0.9 }}
+};
+
+/* Points consistent with a matrix interpolation */
+co test_points12[] = {
+ {{ 0.1, 0.1 }, { 0.1 }},
+ {{ 0.5, 0.1 }, { 0.5 }},
+ {{ 0.9, 0.1 }, { 0.9 }},
+ {{ 0.1, 0.5 }, { 0.1 }},
+ {{ 0.5, 0.5 }, { 0.35 }},
+ {{ 0.9, 0.5 }, { 0.6 }},
+ {{ 0.1, 0.9 }, { 0.1 }},
+ {{ 0.5, 0.9 }, { 0.2 }},
+ {{ 0.9, 0.9 }, { 0.3 }}
+};
+
+/* Points down the "neutral axis" extrapolation test */
+co test_points13[] = {
+ {{ 0.0069, 0.0071 }, { 0.0726 }},
+ {{ 0.0068, 0.0071 }, { 0.0704 }},
+ {{ 0.0069, 0.0072 }, { 0.0720 }},
+ {{ 0.0069, 0.0072 }, { 0.0734 }},
+ {{ 0.0069, 0.0072 }, { 0.0750 }},
+ {{ 0.0070, 0.0072 }, { 0.0779 }},
+ {{ 0.0070, 0.0072 }, { 0.0741 }},
+ {{ 0.0069, 0.0072 }, { 0.0745 }},
+ {{ 0.0069, 0.0072 }, { 0.0747 }},
+ {{ 0.0071, 0.0073 }, { 0.0760 }},
+ {{ 0.0070, 0.0073 }, { 0.0751 }},
+ {{ 0.0070, 0.0073 }, { 0.0759 }},
+ {{ 0.0071, 0.0074 }, { 0.0693 }},
+ {{ 0.0071, 0.0074 }, { 0.0740 }},
+ {{ 0.0072, 0.0075 }, { 0.0741 }},
+ {{ 0.0199, 0.0209 }, { 0.1019 }},
+ {{ 0.0296, 0.0306 }, { 0.1213 }},
+ {{ 0.0627, 0.0651 }, { 0.1779 }},
+ {{ 0.0831, 0.0863 }, { 0.2095 }},
+ {{ 0.1091, 0.1134 }, { 0.2487 }},
+ {{ 0.1442, 0.1497 }, { 0.2949 }},
+ {{ 0.1745, 0.1814 }, { 0.3360 }},
+ {{ 0.1747, 0.1816 }, { 0.3367 }},
+ {{ 0.1747, 0.1816 }, { 0.3364 }},
+ {{ 0.1748, 0.1816 }, { 0.3355 }},
+ {{ 0.1749, 0.1817 }, { 0.3344 }},
+ {{ 0.1748, 0.1817 }, { 0.3356 }},
+ {{ 0.1748, 0.1817 }, { 0.3354 }},
+ {{ 0.1749, 0.1817 }, { 0.3361 }},
+ {{ 0.1749, 0.1818 }, { 0.3368 }},
+ {{ 0.1749, 0.1818 }, { 0.3335 }},
+ {{ 0.1750, 0.1818 }, { 0.3367 }},
+ {{ 0.1750, 0.1819 }, { 0.3362 }},
+ {{ 0.1750, 0.1819 }, { 0.3359 }},
+ {{ 0.1751, 0.1820 }, { 0.3354 }},
+ {{ 0.1752, 0.1821 }, { 0.3355 }},
+ {{ 0.1754, 0.1823 }, { 0.3369 }},
+ {{ 0.1756, 0.1824 }, { 0.3360 }},
+ {{ 0.2743, 0.2842 }, { 0.4381 }},
+ {{ 0.3289, 0.3411 }, { 0.4922 }},
+ {{ 0.4036, 0.4184 }, { 0.5617 }},
+ {{ 0.4689, 0.4854 }, { 0.6147 }},
+ {{ 0.5379, 0.5567 }, { 0.6709 }},
+ {{ 0.7137, 0.7420 }, { 0.8045 }},
+ {{ 0.8730, 0.9105 }, { 0.9150 }},
+ {{ 0.8738, 0.9113 }, { 0.9141 }},
+ {{ 0.8741, 0.9116 }, { 0.9120 }},
+ {{ 0.8744, 0.9118 }, { 0.9173 }},
+ {{ 0.8748, 0.9123 }, { 0.9219 }},
+ {{ 0.8748, 0.9123 }, { 0.9133 }},
+ {{ 0.8748, 0.9124 }, { 0.9210 }},
+ {{ 0.8751, 0.9127 }, { 0.9207 }},
+ {{ 0.8751, 0.9127 }, { 0.9225 }},
+ {{ 0.8754, 0.9130 }, { 0.9137 }},
+ {{ 0.8757, 0.9133 }, { 0.9219 }},
+ {{ 0.8759, 0.9135 }, { 0.9166 }},
+ {{ 0.8761, 0.9137 }, { 0.9162 }},
+ {{ 0.8759, 0.9137 }, { 0.9151 }},
+ {{ 0.8765, 0.9141 }, { 0.9167 }}
+};
+
+#ifdef NEVER
+#ifdef __STDC__
+#include <stdarg.h>
+void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...);
+#else
+#include <varargs.h>
+void error(), warning(), verbose();
+#endif
+#endif /* NEVER */
+
+void write_rgb_tiff(char *name, int width, int height, unsigned char *data);
+
+void usage(void) {
+ fprintf(stderr,"Test 2D rspl interpolation\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: t2d [options]\n");
+ fprintf(stderr," -t n Test set:\n");
+ fprintf(stderr," * 1 = 1D curve along x = 0.5\n");
+ fprintf(stderr," 2 = x + y^2 with nonmon point\n");
+ fprintf(stderr," 3 = x + y^2\n");
+ fprintf(stderr," 4 = arbitrary11\n");
+ fprintf(stderr," 5 = 1D line of 3 points\n");
+ fprintf(stderr," 6 = same value 11 points\n");
+ fprintf(stderr," 7 = same value 3 points\n");
+ fprintf(stderr," 8 = C + M printer L* values\n");
+ fprintf(stderr," 9 = C + M printer a* values\n");
+ fprintf(stderr," 10 = C + M printer b* values\n");
+ fprintf(stderr," 11 = Points up to edge test\n");
+ fprintf(stderr," 12 = Four points with high smoothing\n");
+ fprintf(stderr," 13 = Neutral axis extrapolation\n");
+ fprintf(stderr," -r resx,resy Set grid resolutions (def %d %d)\n",GRES0,GRES1);
+ fprintf(stderr," -h Test half scale resolution too\n");
+ fprintf(stderr," -q Test quarter scale resolution too\n");
+ fprintf(stderr," -2 Use two pass smoothing\n");
+ fprintf(stderr," -x Use extra fitting\n");
+ fprintf(stderr," -s Test symetric smoothness (set asymetric -r !)\n");
+ fprintf(stderr," -S Test spline interpolation\n");
+ fprintf(stderr," -p plot 3 slices, x = 0.5, y = 0.5, x = y\n");
+ fprintf(stderr," -P x1:y1:x2:y2 plot a slice from x1,y1 to x2,y2\n");
+ fprintf(stderr," -m No red point markers in TIFF\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ rspl *rss; /* Regularized spline structure */
+ rspl *rss2 = NULL; /* Regularized spline structure at half resolution */
+ datai low,high;
+ int gres[MXDI];
+ int gres2[MXDI];
+ double avgdev[MXDO];
+ co *test_points = test_points1;
+ int npoints = sizeof(test_points1)/sizeof(co);
+ int dospline = 0;
+ int twopass = 0;
+ int extra = 0;
+ int dosym = 0;
+ int doplot = 0;
+ double plotpts[2][2]; /* doplot == 2 start/end points */
+ int doh = 0; /* half scale */
+ int doq = 0;
+ int rsv;
+ int flags = RSPL_NOFLAGS;
+ int markers = 1;
+ double smooth = 1.0;
+
+ low[0] = 0.0;
+ low[1] = 0.0;
+ high[0] = 1.0;
+ high[1] = 1.0;
+ gres[0] = GRES0;
+ gres[1] = GRES1;
+ avgdev[0] = 0.0;
+ avgdev[1] = 0.0;
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* test set */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage();
+ ix = atoi(na);
+ switch (ix) {
+ case 1:
+ test_points = test_points1;
+ npoints = sizeof(test_points1)/sizeof(co);
+ break;
+ case 2:
+ test_points = test_points2;
+ npoints = sizeof(test_points2)/sizeof(co);
+ break;
+ case 3:
+ test_points = test_points3;
+ npoints = sizeof(test_points3)/sizeof(co);
+ break;
+ case 4:
+ test_points = test_points4;
+ npoints = sizeof(test_points4)/sizeof(co);
+ break;
+ case 5:
+ test_points = test_points5;
+ npoints = sizeof(test_points5)/sizeof(co);
+ break;
+ case 6:
+ test_points = test_points6;
+ npoints = sizeof(test_points6)/sizeof(co);
+ break;
+ case 7:
+ test_points = test_points7;
+ npoints = sizeof(test_points7)/sizeof(co);
+ break;
+ case 8:
+ test_points = test_points8;
+ npoints = sizeof(test_points8)/sizeof(co);
+ break;
+ case 9:
+ test_points = test_points9;
+ npoints = sizeof(test_points9)/sizeof(co);
+ break;
+ case 10:
+ test_points = test_points10;
+ npoints = sizeof(test_points10)/sizeof(co);
+ break;
+ case 11: {
+ int i;
+ test_points = test_points11;
+ npoints = sizeof(test_points11)/sizeof(co);
+ for (i = 0; i < npoints; i++) {
+ test_points[i].v[0] = test_f11(test_points[i].p[0],test_points[i].p[1]);
+ }
+ break;
+ case 12:
+ test_points = test_points12;
+ npoints = sizeof(test_points12)/sizeof(co);
+// smooth = -100000.0;
+// smooth = 1e-4;
+ avgdev[0] = 0.1;
+ avgdev[1] = 0.1;
+ break;
+ case 13:
+ test_points = test_points13;
+ npoints = sizeof(test_points13)/sizeof(co);
+ break;
+ }
+ default:
+ usage();
+ }
+
+ } else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (sscanf(na, " %d,%d ", &gres[0], &gres[1]) != 2)
+ usage();
+
+ } else if (argv[fa][1] == 'h' || argv[fa][1] == 'H') {
+ doh = 1;
+
+ } else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') {
+ doh = 1;
+ doq = 1;
+
+ } else if (argv[fa][1] == 'p') {
+ doplot = 1;
+
+ } else if (argv[fa][1] == 'P') {
+ doplot = 2;
+ fa = nfa;
+ if (na == NULL) usage();
+ if (sscanf(na,"%lf:%lf:%lf:%lf",&plotpts[0][0],&plotpts[0][1],&plotpts[1][0],&plotpts[1][1]) != 4) {
+ usage();
+ }
+
+ } else if (argv[fa][1] == 'S') {
+ dospline = 1;
+
+ } else if (argv[fa][1] == '2') {
+ twopass = 1;
+
+ } else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ extra = 1;
+
+ } else if (argv[fa][1] == 's') {
+ dosym = 1;
+
+ } else if (argv[fa][1] == 'm') {
+ markers = 0;
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+
+ if (twopass)
+ flags |= RSPL_2PASSSMTH;
+
+ if (extra)
+ flags |= RSPL_EXTRAFIT2;
+
+ if (dosym)
+ flags |= RSPL_SYMDOMAIN;
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS, 2, 1);
+
+ /* Fit to scattered data */
+ rss->fit_rspl(rss,
+ flags, /* Non-mon and clip flags */
+ test_points, /* Test points */
+ npoints, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ smooth, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+ if (doh) {
+
+ if (doq) {
+ gres2[0] = gres[0]/4;
+ gres2[1] = gres[1]/4;
+ } else {
+ gres2[0] = gres[0]/2;
+ gres2[1] = gres[1]/2;
+ }
+
+ rss2 = new_rspl(RSPL_NOFLAGS, 2, 1);
+
+ /* Fit to scattered data */
+ rss2->fit_rspl(rss2,
+ flags, /* Non-mon and clip flags */
+ test_points, /* Test points */
+ npoints, /* Number of test points */
+ low, high, gres2, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ 1.0, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+ }
+
+ /* Plot the interpolation in 2D */
+ for (rsv = 0; rsv <= doh; rsv++) {
+ double x1 = -0.2; /* Plot range */
+ double x2 = 1.2;
+ double y1 = -0.2;
+ double y2 = 1.2;
+ double min = -0.0;
+ double max = 1.0;
+ rspl *rs;
+ unsigned char pa[HEIGHT][WIDTH][3];
+ co tco; /* Test point */
+ double sx,sy;
+ int i,j,k;
+
+ if (rsv == 0)
+ rs = rss;
+ else
+ rs = rss2;
+
+ sx = (x2 - x1)/(double)WIDTH;
+ sy = (y2 - y1)/(double)HEIGHT;
+
+ for (j=0; j < HEIGHT; j++) {
+ tco.p[1] = (double)((HEIGHT-1) - j) * sy + y1;
+ for (i=0; i < WIDTH; i++) {
+ tco.p[0] = (double)i * sx + x1;
+ if ((dospline && rs->spline_interp(rs, &tco))
+ || (!dospline && rs->interp(rs, &tco))) {
+ pa[j][i][0] = 0; /* Out of bounds in green */
+ pa[j][i][1] = 100;
+ pa[j][i][2] = 0;
+ } else {
+ int m;
+ /* printf("%d %d, %f %f returned %f\n",i,j,tco.p[0],tco.p[1],tco.v[0]); */
+ m = (int)((255.0 * (tco.v[0] - min)/(max - min)) + 0.5);
+ if (m < 0) {
+ pa[j][i][0] = 20; /* Dark blue */
+ pa[j][i][1] = 20;
+ pa[j][i][2] = 50;
+ } else if (m > 255) {
+ pa[j][i][0] = 230; /* Light blue */
+ pa[j][i][1] = 230;
+ pa[j][i][2] = 255;
+ } else {
+ pa[j][i][0] = m; /* Level in grey */
+ pa[j][i][1] = m;
+ pa[j][i][2] = m;
+ }
+ }
+ }
+ }
+
+ if (markers) {
+ /* Mark verticies in red */
+ for(k = 0; k < npoints; k++) {
+ j = (int)((HEIGHT * (y2 - test_points[k].p[1])/(y2 - y1)) + 0.5);
+ i = (int)((WIDTH * (test_points[k].p[0] - x1)/(x2 - x1)) + 0.5);
+ pa[j][i][0] = 255;
+ pa[j][i][1] = 0;
+ pa[j][i][2] = 0;
+ }
+ }
+ write_rgb_tiff(rsv == 0 ? "t2d.tif" : "t2dh.tif" ,WIDTH,HEIGHT,(unsigned char *)pa);
+ }
+
+ /* Plot out 3 slices */
+ if (doplot == 1) {
+ int slice;
+
+ for (slice = 0; slice < 3; slice++) {
+ co tp; /* Test point */
+ double x[PLOTRES];
+ double ya[PLOTRES];
+ double yb[PLOTRES];
+ double xx,yy;
+ double x1,x2,y1,y2;
+ double sx,sy;
+ int i,n;
+
+ /* Set up slice to plot */
+ if (slice == 0) {
+ printf("Slice along x = 0.5\n");
+ x1 = 0.5; y1 = 0.0;
+ x2 = 0.5; y2 = 1.0;
+ n = PLOTRES;
+ } else if (slice == 1) {
+ printf("Slice along y = 0.5\n");
+ x1 = 0.0; y1 = 0.5;
+ x2 = 1.0; y2 = 0.5;
+ n = PLOTRES;
+ } else {
+ printf("Slice along x = y\n");
+ x1 = 0.0; y1 = 0.0;
+ x2 = 1.0; y2 = 1.0;
+ n = PLOTRES;
+ }
+
+ sx = (x2 - x1)/n;
+ sy = (y2 - y1)/n;
+
+ xx = x1;
+ yy = y1;
+ for (i = 0; i < n; i++) {
+ double vv = i/(n-1.0);
+ x[i] = vv;
+ tp.p[0] = xx;
+ tp.p[1] = yy;
+
+ if ((dospline && rss->spline_interp(rss, &tp))
+ || (!dospline && rss->interp(rss, &tp)))
+ tp.v[0] = -0.1;
+ ya[i] = tp.v[0];
+
+ if (doh) {
+ if ((dospline && rss2->spline_interp(rss2, &tp))
+ || (!dospline && rss2->interp(rss2, &tp)))
+ tp.v[0] = -0.1;
+ yb[i] = tp.v[0];
+ }
+
+ xx += sx;
+ yy += sy;
+ }
+
+ /* Plot the result */
+ if (doh)
+ do_plot(x,ya,yb,NULL,n);
+ else
+ do_plot(x,ya,NULL,NULL,n);
+ }
+ } else if (doplot == 2) { /* Plot a given slice */
+ co tp; /* Test point */
+ double x[PLOTRES];
+ double ya[PLOTRES];
+ double yb[PLOTRES];
+ double xx,yy;
+ double x1,x2,y1,y2;
+ double sx,sy;
+ int i,n;
+
+ x1 = plotpts[0][0];
+ y1 = plotpts[0][1];
+ x2 = plotpts[1][0];
+ y2 = plotpts[1][1];
+
+ printf("Slice from %f,%f to %f,%f\n",x1,y1,x2,y2);
+ n = PLOTRES;
+
+ sx = (x2 - x1)/n;
+ sy = (y2 - y1)/n;
+
+ xx = x1;
+ yy = y1;
+ for (i = 0; i < n; i++) {
+ double vv = i/(n-1.0);
+ x[i] = vv;
+ tp.p[0] = xx;
+ tp.p[1] = yy;
+
+ if ((dospline && rss->spline_interp(rss, &tp))
+ || (!dospline && rss->interp(rss, &tp)))
+ tp.v[0] = -0.1;
+ ya[i] = tp.v[0];
+
+ if (doh) {
+ if ((dospline && rss2->spline_interp(rss2, &tp))
+ || (!dospline && rss2->interp(rss2, &tp)))
+ tp.v[0] = -0.1;
+ yb[i] = tp.v[0];
+ }
+
+ xx += sx;
+ yy += sy;
+ }
+
+ /* Plot the result */
+ if (doh)
+ do_plot(x,ya,yb,NULL,n);
+ else
+ do_plot(x,ya,NULL,NULL,n);
+ }
+
+ /* Report the fit */
+ {
+ co tco; /* Test point */
+ int k;
+ double avg = 0;
+ double max = 0.0;
+
+ for(k = 0; k < npoints; k++) {
+ double err;
+ tco.p[0] = test_points[k].p[0];
+ tco.p[1] = test_points[k].p[1];
+ if (dospline)
+ rss->spline_interp(rss, &tco);
+ else
+ rss->interp(rss, &tco);
+
+ err = tco.v[0] - test_points[k].v[0];
+ err = fabs(err);
+
+ avg += err;
+ if (err > max)
+ max = err;
+ }
+ avg /= (double)npoints;
+ printf("Max error %f%%, average %f%%\n",100.0 * max, 100.0 * avg);
+ }
+ return 0;
+}
+
+/* ---------------------- */
+/* Tiff diagnostic output */
+
+void
+write_rgb_tiff(
+char *name,
+int width,
+int height,
+unsigned char *data
+) {
+ int y;
+ unsigned char *dp;
+ TIFF *tif;
+
+ if ((tif = TIFFOpen(name, "w")) == NULL) {
+ fprintf(stderr,"Failed to open output TIFF file '%s'\n",name);
+ exit (-1);
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+
+ for (dp = data, y = 0; y < height; y++, dp += 3 * width) {
+ if (TIFFWriteScanline(tif, (tdata_t)dp, y, 0) < 0) {
+ fprintf(stderr,"WriteScanline Failed at line %d\n",y);
+ exit (-1);
+ }
+ }
+ (void) TIFFClose(tif);
+}
+
+#ifdef NEVER
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+/* Basic printf type error() and warning() routines */
+
+#ifdef __STDC__
+void
+error(char *fmt, ...)
+#else
+void
+error(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Error - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ exit (-1);
+}
+
+#ifdef __STDC__
+void
+warning(char *fmt, ...)
+#else
+void
+warning(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Warning - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#ifdef __STDC__
+void
+verbose(int level, char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+#else
+verbose(va_alist)
+va_dcl
+{
+ va_list args;
+ int level;
+ char *fmt;
+ va_start(args);
+ level = va_arg(args, int);
+ fmt = va_arg(args, char *);
+#endif
+ if (verbose_level >= level)
+ {
+ fprintf(verbose_out,"cmatch: ");
+ vfprintf(verbose_out, fmt, args);
+ fprintf(verbose_out, "\n");
+ fflush(verbose_out);
+ }
+ va_end(args);
+}
+#endif /* NEVER */
diff --git a/rspl/t2ddf.c b/rspl/t2ddf.c
new file mode 100644
index 0000000..92e7e3f
--- /dev/null
+++ b/rspl/t2ddf.c
@@ -0,0 +1,517 @@
+/************************************************/
+/* Test RSPL in 2D with a weak default function */
+/************************************************/
+
+/* Author: Graeme Gill
+ * Date: 20/11/2005
+ * Derived from cmatch.c
+ * Copyright 1995, 2005 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+#define DEBUG
+#define DETAILED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include "rspl.h"
+#include "tiffio.h"
+#include "plot.h"
+
+#ifdef NEVER
+#define INTERP spline_interp
+#else
+#define INTERP interp
+#endif
+
+#ifdef NEVER
+FILE *verbose_out = stdout;
+int verbose_level = 6; /* Current verbosity level */
+ /* 0 = none */
+ /* !0 = diagnostics */
+#endif /* NEVER */
+
+/* rspl flags */
+#define FLAGS (0 /* | RSPL_EXTRAFIT */)
+
+#define PLOTRES 256
+#define WIDTH 400 /* Raster size */
+#define HEIGHT 400
+
+#define MAX_ITS 500
+#define IT_TOL 0.0005
+#define GRES0 25 /* Default resolutions */
+#define GRES1 25
+#undef NEVER
+#define ALWAYS
+
+/* two correction points along x = 0.5 */
+co test_points1[] = {
+// {{ 0.5,0.325 },{ 0.4 }}, /* 0 */
+// {{ 0.5,0.625 },{ 0.70 }} /* 1 */
+ {{ 0.4,0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.4,0.625 },{ 0.8 }}, /* 1 */
+ {{ 0.5,0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.5,0.625 },{ 0.8 }}, /* 1 */
+ {{ 0.6,0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.6,0.625 },{ 0.8 }} /* 1 */
+};
+
+#ifdef NEVER
+#ifdef __STDC__
+#include <stdarg.h>
+void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...);
+#else
+#include <varargs.h>
+void error(), warning(), verbose();
+#endif
+#endif /* NEVER */
+
+void write_rgb_tiff(char *name, int width, int height, unsigned char *data);
+
+/* Weak default function */
+/* Linear along y, independent of x */
+static void wfunc(void *cbntx, double *out, double *in) {
+ out[0] = in[1];
+}
+
+void usage(void) {
+ fprintf(stderr,"Test 2D rspl interpolation with weak default function\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: t2d [options]\n");
+ fprintf(stderr," -t n Test set:\n");
+ fprintf(stderr," * 1 = two points along x\n");
+ fprintf(stderr," -w wweight Set weak default function weight (default 1.0)\n");
+ fprintf(stderr," -r resx,resy Set grid resolutions (def %d %d)\n",GRES0,GRES1);
+ fprintf(stderr," -h Test half scale resolution too\n");
+ fprintf(stderr," -q Test quarter scale resolution too\n");
+ fprintf(stderr," -s Test symetric smoothness\n");
+ fprintf(stderr," -p plot 3 slices, x = 0.5, y = 0.5, x = y\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ rspl *rss; /* Regularized spline structure */
+ rspl *rss2 = NULL; /* Regularized spline structure at half resolution */
+ datai low,high;
+ int gres[MXDI];
+ int gres2[MXDI];
+ double avgdev[MXDO];
+ co *test_points = test_points1;
+ int npoints = sizeof(test_points1)/sizeof(co);
+ double wweight = 1.0;
+ int dosym = 0;
+ int doplot = 0;
+ int doh = 0;
+ int doq = 0;
+ int rsv;
+ int flags = FLAGS;
+
+ low[0] = 0.0;
+ low[1] = 0.0;
+ high[0] = 1.0;
+ high[1] = 1.0;
+ gres[0] = GRES0;
+ gres[1] = GRES1;
+ avgdev[0] = 0.0;
+ avgdev[1] = 0.0;
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* test set */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage();
+ ix = atoi(na);
+ switch (ix) {
+ case 1:
+ test_points = test_points1;
+ npoints = sizeof(test_points1)/sizeof(co);
+ break;
+ default:
+ usage();
+ }
+
+ } else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage();
+ wweight = atof(na);
+
+ } else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (sscanf(na, " %d,%d ", &gres[0], &gres[1]) != 2)
+ usage();
+
+ } else if (argv[fa][1] == 'h' || argv[fa][1] == 'H') {
+ doh = 1;
+
+ } else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') {
+ doh = 1;
+ doq = 1;
+
+ } else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ doplot = 1;
+
+ } else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ dosym = 1;
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+
+ if (dosym)
+ flags |= RSPL_SYMDOMAIN;
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS, 2, 1);
+
+ /* Fit to scattered data */
+ rss->fit_rspl_df(rss,
+ flags, /* Non-mon and clip flags */
+ test_points, /* Test points */
+ npoints, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ 1.0, /* Smoothing */
+ avgdev, /* Average Deviation */
+ NULL, /* iwidth */
+ wweight, /* weak function weight */
+ NULL, /* No context */
+ wfunc /* Weak function */
+ );
+
+ if (doh) {
+
+ if (doq) {
+ gres2[0] = gres[0]/4;
+ gres2[1] = gres[1]/4;
+ } else {
+ gres2[0] = gres[0]/2;
+ gres2[1] = gres[1]/2;
+ }
+
+ rss2 = new_rspl(RSPL_NOFLAGS, 2, 1);
+
+ /* Fit to scattered data */
+ rss2->fit_rspl_df(rss2,
+ flags, /* Non-mon and clip flags */
+ test_points, /* Test points */
+ npoints, /* Number of test points */
+ low, high, gres2, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ 1.0, /* Smoothing */
+ avgdev, /* Average Deviation */
+ NULL, /* iwidth */
+ wweight, /* weak function weight */
+ NULL, /* No context */
+ wfunc /* Weak function */
+ );
+ }
+
+ /* Test the interpolation in 2D */
+ for (rsv = 0; rsv <= doh; rsv++) {
+ double x1 = -0.2;
+ double x2 = 1.2;
+ double y1 = -0.2;
+ double y2 = 1.2;
+ double min = -0.0;
+ double max = 1.0;
+ rspl *rs;
+ unsigned char pa[HEIGHT][WIDTH][3];
+ co tco; /* Test point */
+ double sx,sy;
+ int i,j,k;
+
+ if (rsv == 0)
+ rs = rss;
+ else
+ rs = rss2;
+
+ sx = (x2 - x1)/(double)WIDTH;
+ sy = (y2 - y1)/(double)HEIGHT;
+
+ for (j=0; j < HEIGHT; j++) {
+ tco.p[1] = (double)((HEIGHT-1) - j) * sy + y1;
+ for (i=0; i < WIDTH; i++) {
+ tco.p[0] = (double)i * sx + x1;
+ if (rs->INTERP(rs, &tco)) {
+ pa[j][i][0] = 0; /* Out of bounds in green */
+ pa[j][i][1] = 100;
+ pa[j][i][2] = 0;
+ } else {
+ int m;
+ /* printf("%d %d, %f %f returned %f\n",i,j,tco.p[0],tco.p[1],tco.v[0]); */
+ m = (int)((255.0 * (tco.v[0] - min)/(max - min)) + 0.5);
+ if (m < 0) {
+ pa[j][i][0] = 20; /* Dark blue */
+ pa[j][i][1] = 20;
+ pa[j][i][2] = 50;
+ } else if (m > 255) {
+ pa[j][i][0] = 230; /* Light blue */
+ pa[j][i][1] = 230;
+ pa[j][i][2] = 255;
+ } else {
+ pa[j][i][0] = m; /* Level in grey */
+ pa[j][i][1] = m;
+ pa[j][i][2] = m;
+ }
+ }
+ }
+ }
+
+ /* Mark verticies in red */
+ for(k = 0; k < npoints; k++) {
+ j = (int)((HEIGHT * (y2 - test_points[k].p[1])/(y2 - y1)) + 0.5);
+ i = (int)((WIDTH * (test_points[k].p[0] - x1)/(x2 - x1)) + 0.5);
+ pa[j][i][0] = 255;
+ pa[j][i][1] = 0;
+ pa[j][i][2] = 0;
+ }
+ write_rgb_tiff(rsv == 0 ? "t2d.tif" : "t2dh.tif" ,WIDTH,HEIGHT,(unsigned char *)pa);
+ }
+
+ /* Plot out 3 slices */
+ if (doplot) {
+ int slice;
+
+ for (slice = 0; slice < 3; slice++) {
+ co tp; /* Test point */
+ double x[PLOTRES];
+ double ya[PLOTRES];
+ double yb[PLOTRES];
+ double xx,yy;
+ double x1,x2,y1,y2;
+ double sx,sy;
+ int i,n;
+
+ /* Set up slice to plot */
+ if (slice == 0) {
+ x1 = 0.5; y1 = 0.0;
+ x2 = 0.5; y2 = 1.0;
+ n = PLOTRES;
+ printf("Plot along y at x = 0.5\n");
+ } else if (slice == 1) {
+ x1 = 0.0; y1 = 0.5;
+ x2 = 1.0; y2 = 0.5;
+ n = PLOTRES;
+ printf("Plot along x at y = 0.5\n");
+ } else {
+ x1 = 0.0; y1 = 0.0;
+ x2 = 1.0; y2 = 1.0;
+ n = PLOTRES;
+ printf("Plot along x = y\n");
+ }
+
+ sx = (x2 - x1)/n;
+ sy = (y2 - y1)/n;
+
+ xx = x1;
+ yy = y1;
+ for (i = 0; i < n; i++) {
+ double vv = i/(n-1.0);
+ x[i] = vv;
+ tp.p[0] = xx;
+ tp.p[1] = yy;
+
+ if (rss->INTERP(rss, &tp))
+ tp.v[0] = -0.1;
+ ya[i] = tp.v[0];
+
+ if (doh) {
+ if (rss2->INTERP(rss2, &tp))
+ tp.v[0] = -0.1;
+ yb[i] = tp.v[0];
+ }
+
+ xx += sx;
+ yy += sy;
+ }
+
+ /* Plot the result */
+ if (doh)
+ do_plot(x,ya,yb,NULL,n);
+ else
+ do_plot(x,ya,NULL,NULL,n);
+ }
+ }
+
+ /* Report the fit */
+ {
+ co tco; /* Test point */
+ int k;
+ double avg = 0;
+ double max = 0.0;
+
+ for(k = 0; k < npoints; k++) {
+ double err;
+ tco.p[0] = test_points[k].p[0];
+ tco.p[1] = test_points[k].p[1];
+ rss->INTERP(rss, &tco);
+
+ err = tco.v[0] - test_points[k].v[0];
+ err = fabs(err);
+
+ avg += err;
+ if (err > max)
+ max = err;
+ }
+ avg /= (double)npoints;
+ printf("Max error %f%%, average %f%%\n",100.0 * max, 100.0 * avg);
+ }
+ return 0;
+}
+
+/* ---------------------- */
+/* Tiff diagnostic output */
+
+void
+write_rgb_tiff(
+char *name,
+int width,
+int height,
+unsigned char *data
+) {
+ int y;
+ unsigned char *dp;
+ TIFF *tif;
+
+ if ((tif = TIFFOpen(name, "w")) == NULL) {
+ fprintf(stderr,"Failed to open output TIFF file '%s'\n",name);
+ exit (-1);
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+
+ for (dp = data, y = 0; y < height; y++, dp += 3 * width) {
+ if (TIFFWriteScanline(tif, (tdata_t)dp, y, 0) < 0) {
+ fprintf(stderr,"WriteScanline Failed at line %d\n",y);
+ exit (-1);
+ }
+ }
+ (void) TIFFClose(tif);
+}
+
+#ifdef NEVER
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+/* Basic printf type error() and warning() routines */
+
+#ifdef __STDC__
+void
+error(char *fmt, ...)
+#else
+void
+error(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Error - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ exit (-1);
+}
+
+#ifdef __STDC__
+void
+warning(char *fmt, ...)
+#else
+void
+warning(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Warning - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#ifdef __STDC__
+void
+verbose(int level, char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+#else
+verbose(va_alist)
+va_dcl
+{
+ va_list args;
+ int level;
+ char *fmt;
+ va_start(args);
+ level = va_arg(args, int);
+ fmt = va_arg(args, char *);
+#endif
+ if (verbose_level >= level)
+ {
+ fprintf(verbose_out,"cmatch: ");
+ vfprintf(verbose_out, fmt, args);
+ fprintf(verbose_out, "\n");
+ fflush(verbose_out);
+ }
+ va_end(args);
+}
+#endif /* NEVER */
diff --git a/rspl/t3d.c b/rspl/t3d.c
new file mode 100644
index 0000000..1935545
--- /dev/null
+++ b/rspl/t3d.c
@@ -0,0 +1,905 @@
+/************************************************/
+/* Test RSPL in 3D */
+/************************************************/
+
+/* Author: Graeme Gill
+ * Date: 22/4/96
+ * Derived from cmatch.c
+ * Copyright 1995 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+#define DEBUG
+#define DETAILED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include "rspl.h"
+#include "tiffio.h"
+#include "plot.h"
+
+#ifdef NEVER
+#define INTERP spline_interp
+#else
+#define INTERP interp
+#endif
+
+#ifdef NEVER
+FILE *verbose_out = stdout;
+int verbose_level = 6; /* Current verbosity level */
+ /* 0 = none */
+ /* !0 = diagnostics */
+#endif /* NEVER */
+
+#define PLOTRES 256
+#define WIDTH 400 /* Raster size */
+#define HEIGHT 400
+
+#define MAX_ITS 500
+#define IT_TOL 0.0005
+#define GRES0 33 /* Default rspl resolutions */
+#define GRES1 33
+#define GRES2 33
+#undef NEVER
+#define ALWAYS
+
+//double t1xa[PNTS] = { 0.2, 0.25, 0.30, 0.35, 0.40, 0.44, 0.48, 0.51, 0.64, 0.75 };
+//double t1ya[PNTS] = { 0.3, 0.35, 0.4, 0.41, 0.42, 0.46, 0.5, 0.575, 0.48, 0.75 };
+
+/* 1D test function repeated 3 times along x = y = 0.5 */
+co test_points1[] = {
+ {{ 0.4,0.4,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.4,0.4,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.4,0.4,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.4,0.4,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.4,0.4,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.4,0.4,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.4,0.4,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.4,0.4,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.4,0.4,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.4,0.4,0.75 },{ 0.75 }}, /* 9 */
+
+ {{ 0.5,0.4,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.5,0.4,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.5,0.4,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.5,0.4,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.5,0.4,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.5,0.4,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.5,0.4,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.5,0.4,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.5,0.4,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.5,0.4,0.75 },{ 0.75 }}, /* 9 */
+
+ {{ 0.6,0.4,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.6,0.4,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.6,0.4,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.6,0.4,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.6,0.4,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.6,0.4,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.6,0.4,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.6,0.4,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.6,0.4,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.6,0.4,0.75 },{ 0.75 }}, /* 9 */
+
+
+ {{ 0.4,0.5,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.4,0.5,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.4,0.5,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.4,0.5,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.4,0.5,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.4,0.5,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.4,0.5,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.4,0.5,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.4,0.5,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.4,0.5,0.75 },{ 0.75 }}, /* 9 */
+
+ {{ 0.5,0.5,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.5,0.5,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.5,0.5,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.5,0.5,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.5,0.5,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.5,0.5,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.5,0.5,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.5,0.5,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.5,0.5,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.5,0.5,0.75 },{ 0.75 }}, /* 9 */
+
+ {{ 0.6,0.5,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.6,0.5,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.6,0.5,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.6,0.5,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.6,0.5,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.6,0.5,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.6,0.5,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.6,0.5,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.6,0.5,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.6,0.5,0.75 },{ 0.75 }}, /* 9 */
+
+
+ {{ 0.4,0.6,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.4,0.6,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.4,0.6,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.4,0.6,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.4,0.6,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.4,0.6,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.4,0.6,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.4,0.6,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.4,0.6,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.4,0.6,0.75 },{ 0.75 }}, /* 9 */
+
+ {{ 0.5,0.6,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.5,0.6,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.5,0.6,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.5,0.6,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.5,0.6,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.5,0.6,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.5,0.6,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.5,0.6,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.5,0.6,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.5,0.6,0.75 },{ 0.75 }}, /* 9 */
+
+ {{ 0.6,0.6,0.20 },{ 0.30 }}, /* 0 */
+ {{ 0.6,0.6,0.25 },{ 0.35 }}, /* 1 */
+ {{ 0.6,0.6,0.30 },{ 0.40 }}, /* 2 */
+ {{ 0.6,0.6,0.35 },{ 0.41 }}, /* 3 */
+ {{ 0.6,0.6,0.40 },{ 0.42 }}, /* 4 */
+ {{ 0.6,0.6,0.44 },{ 0.46 }}, /* 5 */
+ {{ 0.6,0.6,0.48 },{ 0.50 }}, /* 6 */
+ {{ 0.6,0.6,0.51 },{ 0.575 }}, /* 7 */
+ {{ 0.6,0.6,0.64 },{ 0.48 }}, /* 8 */
+ {{ 0.6,0.6,0.75 },{ 0.75 }} /* 9 */
+};
+
+/* function */
+co test_points2[] = {
+ {{ 0.50915, 0.50936, 0.57048 },{ 0.36209169635 }},
+ {{ 0.85943, 0.84331, 0.81487 },{ 0.91571493013 }},
+ {{ 0.11381, 0.80378, 0.82951 },{ 0.16052707023 }},
+ {{ 0.79087, 0.11157, 0.83913 },{ 0.30641388193 }},
+ {{ 0.16297, 0.23090, 0.96417 },{ 0.15005479047 }},
+ {{ 0.78181, 0.80097, 0.00192 },{ 0.32179402798 }},
+ {{ 0.16141, 0.84321, 0.16561 },{ 0.14446082013 }},
+ {{ 0.79859, 0.11111, 0.15547 },{ -0.1308162293 }},
+ {{ 0.12959, 0.16184, 0.21825 },{ 0.03520247555 }},
+ {{ 1.00000, 0.46395, 0.84399 },{ 0.63914200000 }},
+ {{ 0.48724, 0.76024, 1.00000 },{ 0.64150992880 }},
+ {{ 0.40744, 0.00000, 0.65533 },{ 0.13060244736 }},
+ {{ 0.10931, 0.43216, 0.25195 },{ 0.06329759515 }},
+ {{ 0.69401, 0.99412, 0.55335 },{ 0.75632862795 }},
+ {{ 0.51759, 0.30372, 0.13622 },{ 0.07965761859 }},
+ {{ 0.98628, 0.40857, 0.47688 },{ 0.29286006552 }},
+ {{ 0.44474, 0.26024, 1.00000 },{ 0.37263430380 }},
+ {{ 0.15229, 0.52694, 0.75101 },{ 0.16014862087 }},
+ {{ 0.50968, 0.74522, 0.14058 },{ 0.30725752992 }},
+ {{ 0.82291, 0.10614, 0.49956 },{ 0.07762756903 }},
+ {{ 0.15674, 0.78167, 0.50766 },{ 0.17389174472 }},
+ {{ 0.12961, 0.17234, 0.65990 },{ 0.08236132255 }},
+ {{ 1.00000, 0.83202, 0.35206 },{ 0.61366800000 }},
+ {{ 0.36633, 0.89555, 0.76014 },{ 0.48373766601 }},
+ {{ 0.85641, 0.39194, 0.18691 },{ 0.09699956583 }},
+ {{ 0.50918, 0.23923, 0.42132 },{ 0.16380116928 }},
+ {{ 0.65513, 0.40585, 0.83832 },{ 0.49065371733 }},
+ {{ 0.66726, 0.75472, 0.25419 },{ 0.41666516892 }},
+ {{ 0.22193, 0.58555, 0.13920 },{ 0.13003877385 }},
+ {{ 0.41507, 0.89581, 0.25539 },{ 0.37048608609 }},
+ {{ 0.43231, 0.12362, 0.17297 },{ 0.01981752271 }},
+ {{ 0.78191, 0.63297, 0.72639 },{ 0.64361123257 }}
+};
+
+co test_points3[] = {
+ {{ 0.50915, 0.50936, 0.57048 },{ -0.00010 }},
+ {{ 0.85943, 0.84331, 0.81487 },{ 0.46573 }},
+ {{ 0.11381, 0.80378, 0.82951 },{ 0.56085 }},
+ {{ 0.79087, 0.11157, 0.83913 },{ 0.33378 }},
+ {{ 0.16297, 0.23090, 0.96417 },{ 0.38872 }},
+ {{ 0.78181, 0.80097, 0.00192 },{ 0.28654 }},
+ {{ 0.16141, 0.84321, 0.16561 },{ 0.43410 }},
+ {{ 0.79859, 0.11111, 0.15547 },{ 0.35140 }},
+ {{ 0.12959, 0.16184, 0.21825 },{ 0.46711 }},
+ {{ 1.00000, 0.46395, 0.84399 },{ 0.94213 }},
+ {{ 0.48724, 0.76024, 1.00000 },{ 0.00058 }},
+ {{ 0.40744, 0.00000, 0.65533 },{ 0.00859 }},
+ {{ 0.10931, 0.43216, 0.25195 },{ 0.54679 }},
+ {{ 0.69401, 0.99412, 0.55335 },{ 0.12494 }},
+ {{ 0.51759, 0.30372, 0.13622 },{ -0.00126 }},
+ {{ 0.98628, 0.40857, 0.47688 },{ 0.89573 }},
+ {{ 0.44474, 0.26024, 1.00000 },{ 0.00280 }},
+ {{ 0.15229, 0.52694, 0.75101 },{ 0.43807 }},
+ {{ 0.50968, 0.74522, 0.14058 },{ 0.00004 }},
+ {{ 0.82291, 0.10614, 0.49956 },{ 0.40990 }},
+ {{ 0.15674, 0.78167, 0.50766 },{ 0.44271 }},
+ {{ 0.12961, 0.17234, 0.65990 },{ 0.46804 }},
+ {{ 1.00000, 0.83202, 0.35206 },{ 0.90938 }},
+ {{ 0.36633, 0.89555, 0.76014 },{ 0.07020 }},
+ {{ 0.85641, 0.39194, 0.18691 },{ 0.48559 }},
+ {{ 0.50918, 0.23923, 0.42132 },{ -0.00391 }},
+ {{ 0.65513, 0.40585, 0.83832 },{ 0.09449 }},
+ {{ 0.66726, 0.75472, 0.25419 },{ 0.10065 }},
+ {{ 0.22193, 0.58555, 0.13920 },{ 0.28186 }},
+ {{ 0.41507, 0.89581, 0.25539 },{ 0.02877 }},
+ {{ 0.43231, 0.12362, 0.17297 },{ 0.00237 }},
+ {{ 0.78191, 0.63297, 0.72639 },{ 0.29573 }}
+};
+
+
+/* x + y^2 + z^1/3 function with one non-monotonic point */
+co test_points4[] = {
+ {{ 0.1,0.1,0.5 },{ 0.11 }}, /* 0 */
+ {{ 0.2,0.7,0.1 },{ 0.69 }}, /* 1 */
+ {{ 0.8,0.8,0.8 },{ 1.44 }}, /* 2 */
+ {{ 0.5,0.6,0.4 },{ 0.86 }}, /* 3 */
+ {{ 0.2,0.5,0.2 },{ 0.45 }}, /* 4 */
+ {{ 0.3,0.7,0.2 },{ 0.35 }}, /* nm 5 */
+ {{ 0.5,0.4,0.9 },{ 0.66 }}, /* 6 */
+ {{ 0.1,0.9,0.7 },{ 0.91 }}, /* 7 */
+ {{ 0.7,0.2,0.1 },{ 0.74 }}, /* 8 */
+ {{ 0.8,0.4,0.3 },{ 0.96 }}, /* 9 */
+ {{ 0.3,0.3,0.4 },{ 0.39 }} /* 10 */
+ };
+
+/* doubled up x + y^2 + z^1/3 function with one non-monotonic point */
+co test_points5[] = {
+ {{ 0.1,0.1,0.5 },{ 0.11 }}, /* 0 */
+ {{ 0.101,0.101,0.501 },{ 0.11 }}, /* 0d */
+ {{ 0.2,0.7,0.1 },{ 0.69 }}, /* 1 */
+ {{ 0.201,0.701,0.101 },{ 0.69 }}, /* 1d */
+ {{ 0.8,0.8,0.8 },{ 1.44 }}, /* 2 */
+ {{ 0.801,0.801,0.801 },{ 1.44 }}, /* 2d */
+ {{ 0.5,0.6,0.4 },{ 0.86 }}, /* 3 */
+ {{ 0.501,0.601,0.401 },{ 0.86 }}, /* 3d */
+ {{ 0.2,0.5,0.2 },{ 0.45 }}, /* 4 */
+ {{ 0.201,0.501,0.201 },{ 0.45 }}, /* 4d */
+ {{ 0.3,0.7,0.2 },{ 0.35 }}, /* nm 5 */
+ {{ 0.301,0.701,0.201 },{ 0.35 }}, /* nm 5d */
+ {{ 0.5,0.4,0.9 },{ 0.66 }}, /* 6 */
+ {{ 0.501,0.401,0.901 },{ 0.66 }}, /* 6d */
+ {{ 0.1,0.9,0.7 },{ 0.91 }}, /* 7 */
+ {{ 0.101,0.901,0.701 },{ 0.91 }}, /* 7d */
+ {{ 0.7,0.2,0.1 },{ 0.74 }}, /* 8 */
+ {{ 0.701,0.201,0.101 },{ 0.74 }}, /* 8d */
+ {{ 0.8,0.4,0.3 },{ 0.96 }}, /* 9 */
+ {{ 0.801,0.401,0.301 },{ 0.96 }}, /* 9d */
+ {{ 0.3,0.3,0.4 },{ 0.39 }}, /* 10 */
+ {{ 0.301,0.301,0.401 },{ 0.39 }} /* 10d */
+ };
+
+co test_points6[] = {
+ {{ 0.0069, 0.0071, 0.0061 },{ 0.0726 }},
+ {{ 0.0068, 0.0071, 0.0060 },{ 0.0704 }},
+ {{ 0.0069, 0.0072, 0.0062 },{ 0.0720 }},
+ {{ 0.0069, 0.0072, 0.0061 },{ 0.0734 }},
+ {{ 0.0069, 0.0072, 0.0063 },{ 0.0750 }},
+ {{ 0.0070, 0.0072, 0.0062 },{ 0.0779 }},
+ {{ 0.0070, 0.0072, 0.0063 },{ 0.0741 }},
+ {{ 0.0069, 0.0072, 0.0061 },{ 0.0745 }},
+ {{ 0.0069, 0.0072, 0.0061 },{ 0.0747 }},
+ {{ 0.0071, 0.0073, 0.0063 },{ 0.0760 }},
+ {{ 0.0070, 0.0073, 0.0063 },{ 0.0751 }},
+ {{ 0.0070, 0.0073, 0.0062 },{ 0.0759 }},
+ {{ 0.0071, 0.0074, 0.0062 },{ 0.0693 }},
+ {{ 0.0071, 0.0074, 0.0064 },{ 0.0740 }},
+ {{ 0.0072, 0.0075, 0.0064 },{ 0.0741 }},
+ {{ 0.0199, 0.0209, 0.0184 },{ 0.1019 }},
+ {{ 0.0296, 0.0306, 0.0257 },{ 0.1213 }},
+ {{ 0.0627, 0.0651, 0.0548 },{ 0.1779 }},
+ {{ 0.0831, 0.0863, 0.0718 },{ 0.2095 }},
+ {{ 0.1091, 0.1134, 0.0946 },{ 0.2487 }},
+ {{ 0.1442, 0.1497, 0.1227 },{ 0.2949 }},
+ {{ 0.1745, 0.1814, 0.1495 },{ 0.3360 }},
+ {{ 0.1747, 0.1816, 0.1498 },{ 0.3367 }},
+ {{ 0.1747, 0.1816, 0.1496 },{ 0.3364 }},
+ {{ 0.1748, 0.1816, 0.1497 },{ 0.3355 }},
+ {{ 0.1749, 0.1817, 0.1497 },{ 0.3344 }},
+ {{ 0.1748, 0.1817, 0.1498 },{ 0.3356 }},
+ {{ 0.1748, 0.1817, 0.1498 },{ 0.3354 }},
+ {{ 0.1749, 0.1817, 0.1496 },{ 0.3361 }},
+ {{ 0.1749, 0.1818, 0.1498 },{ 0.3368 }},
+ {{ 0.1749, 0.1818, 0.1498 },{ 0.3335 }},
+ {{ 0.1750, 0.1818, 0.1499 },{ 0.3367 }},
+ {{ 0.1750, 0.1819, 0.1500 },{ 0.3362 }},
+ {{ 0.1750, 0.1819, 0.1498 },{ 0.3359 }},
+ {{ 0.1751, 0.1820, 0.1500 },{ 0.3354 }},
+ {{ 0.1752, 0.1821, 0.1501 },{ 0.3355 }},
+ {{ 0.1754, 0.1823, 0.1502 },{ 0.3369 }},
+ {{ 0.1756, 0.1824, 0.1504 },{ 0.3360 }},
+ {{ 0.2743, 0.2842, 0.2367 },{ 0.4381 }},
+ {{ 0.3289, 0.3411, 0.2834 },{ 0.4922 }},
+ {{ 0.4036, 0.4184, 0.3475 },{ 0.5617 }},
+ {{ 0.4689, 0.4854, 0.4020 },{ 0.6147 }},
+ {{ 0.5379, 0.5567, 0.4606 },{ 0.6709 }},
+ {{ 0.7137, 0.7420, 0.6169 },{ 0.8045 }},
+ {{ 0.8730, 0.9105, 0.7433 },{ 0.9150 }},
+ {{ 0.8738, 0.9113, 0.7435 },{ 0.9141 }},
+ {{ 0.8741, 0.9116, 0.7445 },{ 0.9120 }},
+ {{ 0.8744, 0.9118, 0.7443 },{ 0.9173 }},
+ {{ 0.8748, 0.9123, 0.7457 },{ 0.9219 }},
+ {{ 0.8748, 0.9123, 0.7450 },{ 0.9133 }},
+ {{ 0.8748, 0.9124, 0.7445 },{ 0.9210 }},
+ {{ 0.8751, 0.9127, 0.7462 },{ 0.9207 }},
+ {{ 0.8751, 0.9127, 0.7457 },{ 0.9225 }},
+ {{ 0.8754, 0.9130, 0.7454 },{ 0.9137 }},
+ {{ 0.8757, 0.9133, 0.7456 },{ 0.9219 }},
+ {{ 0.8759, 0.9135, 0.7470 },{ 0.9166 }},
+ {{ 0.8761, 0.9137, 0.7469 },{ 0.9162 }},
+ {{ 0.8759, 0.9137, 0.7469 },{ 0.9151 }},
+ {{ 0.8765, 0.9141, 0.7470 },{ 0.9167 }},
+};
+
+
+#ifdef NEVER
+#ifdef __STDC__
+#include <stdarg.h>
+void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...);
+#else
+#include <varargs.h>
+void error(), warning(), verbose();
+#endif
+#endif /* NEVER */
+
+void write_rgb_tiff(char *name, int width, int height, unsigned char *data);
+
+void usage(void) {
+ fprintf(stderr,"Test 3D rspl interpolation\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: t2d [options]\n");
+ fprintf(stderr," -t n Test set:\n");
+ fprintf(stderr," * 1 = 1D test set along x = y = 0.5\n");
+ fprintf(stderr," 2 = Test set 1\n");
+ fprintf(stderr," 3 = Test set 2\n");
+ fprintf(stderr," 4 = x + y^2 + z^1/3 with nonmon point\n");
+ fprintf(stderr," 5 = doubled up x + y^2 + z^1/3 with nonmon point\n");
+ fprintf(stderr," 6 = neutral axis extrapolation\n");
+ fprintf(stderr," -r resx,resy,resz Set grid resolutions (def %d %d %d)\n",GRES0,GRES1,GRES2);
+ fprintf(stderr," -h Test half scale resolution too\n");
+ fprintf(stderr," -q Test quarter scale resolution too\n");
+ fprintf(stderr," -2 Use two pass smoothing\n");
+ fprintf(stderr," -x Use extra fitting\n");
+ fprintf(stderr," -s Test symetric smoothness\n");
+ fprintf(stderr," -p plot 4 slices, xy = 0.5, yz = 0.5, xz = 0.5, x=y=z\n");
+ fprintf(stderr," -P x1:y1:z1:x2:y2:z2 plot slice from x1,y1,z1,x2,y2,z2\n");
+ fprintf(stderr," -S factor smoothing factor (default 1.0)\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ rspl *rss; /* Regularized spline structure */
+ rspl *rss2 = NULL; /* Regularized spline structure at half/quarter resolution */
+ datai low,high;
+ int gres[MXDI];
+ int gres2[MXDI];
+ double avgdev[MXDO];
+ co *test_points = test_points1;
+ int npoints = sizeof(test_points1)/sizeof(co);
+ int dosym = 0;
+ int twopass = 0;
+ int extra = 0;
+ int doplot = 0;
+ double plotpts[2][3]; /* doplot == 2 start/end points */
+ int doh = 0; /* half scale */
+ int doq = 0;
+ int rsv;
+ double smoothf = 1.0;
+ int flags = RSPL_NOFLAGS;
+
+ low[0] = 0.0;
+ low[1] = 0.0;
+ low[2] = 0.0;
+ high[0] = 1.0;
+ high[1] = 1.0;
+ high[2] = 1.0;
+ gres[0] = GRES0;
+ gres[1] = GRES1;
+ gres[2] = GRES2;
+ avgdev[0] = 0.0;
+ avgdev[1] = 0.0;
+ avgdev[2] = 0.0;
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* test set */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage();
+ ix = atoi(na);
+ switch (ix) {
+ case 1:
+ test_points = test_points1;
+ npoints = sizeof(test_points1)/sizeof(co);
+ break;
+ case 2:
+ test_points = test_points2;
+ npoints = sizeof(test_points2)/sizeof(co);
+ break;
+ case 3:
+ test_points = test_points3;
+ npoints = sizeof(test_points3)/sizeof(co);
+ break;
+ case 4:
+ test_points = test_points4;
+ npoints = sizeof(test_points4)/sizeof(co);
+ break;
+ case 5:
+ test_points = test_points5;
+ npoints = sizeof(test_points5)/sizeof(co);
+ break;
+ case 6:
+ test_points = test_points6;
+ npoints = sizeof(test_points6)/sizeof(co);
+ break;
+ default:
+ usage();
+ }
+
+ } else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (sscanf(na, " %d,%d,%d ", &gres[0], &gres[1], &gres[2]) != 3)
+ usage();
+
+ } else if (argv[fa][1] == 'h' || argv[fa][1] == 'H') {
+ doh = 1;
+
+ } else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') {
+ doh = 1;
+ doq = 1;
+
+ } else if (argv[fa][1] == 'p') {
+ doplot = 1;
+
+ } else if (argv[fa][1] == 'P') {
+ doplot = 2;
+ fa = nfa;
+ if (na == NULL) usage();
+ if (sscanf(na,"%lf:%lf:%lf:%lf:%lf:%lf",&plotpts[0][0],&plotpts[0][1],&plotpts[0][2],&plotpts[1][0],&plotpts[1][1],&plotpts[1][2]) != 6) {
+ usage();
+ }
+
+ } else if (argv[fa][1] == 's') {
+ dosym = 1;
+
+ } else if (argv[fa][1] == '2') {
+ twopass = 1;
+
+ } else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ extra = 1;
+
+ /* smoothing factor */
+ } else if (argv[fa][1] == 'S') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage();
+ smoothf = atof(na);
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+
+ if (twopass)
+ flags |= RSPL_2PASSSMTH;
+
+ if (extra)
+ flags |= RSPL_EXTRAFIT2;
+
+ if (dosym)
+ flags |= RSPL_SYMDOMAIN;
+
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS, 3, 1);
+
+ /* Fit to scattered data */
+ rss->fit_rspl(rss,
+ flags, /* Non-mon and clip flags */
+ test_points, /* Test points */
+ npoints, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ smoothf, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+ if (doh) {
+
+ if (doq) {
+ gres2[0] = gres[0]/4;
+ gres2[1] = gres[1]/4;
+ gres2[2] = gres[2]/4;
+ } else {
+ gres2[0] = gres[0]/2;
+ gres2[1] = gres[1]/2;
+ gres2[2] = gres[2]/2;
+ }
+
+ rss2 = new_rspl(RSPL_NOFLAGS, 3, 1);
+
+ /* Fit to scattered data */
+ rss2->fit_rspl(rss2,
+ flags, /* Non-mon and clip flags */
+ test_points, /* Test points */
+ npoints, /* Number of test points */
+ low, high, gres2, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ smoothf, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+ }
+
+ /* Test the interpolation with a slice in 2D */
+ for (rsv = 0; rsv <= doh; rsv++) {
+ double z[2][2] = { { 0.1, 0.5 } , { 0.5, 0.9 } };
+ double x1 = -0.2;
+ double x2 = 1.2;
+ double y1 = -0.2;
+ double y2 = 1.2;
+ double min = -0.0;
+ double max = 1.0;
+ rspl *rs;
+ unsigned char pa[HEIGHT][WIDTH][3];
+ co tco; /* Test point */
+ double sx,sy;
+ int i,j,k;
+
+ if (rsv == 0)
+ rs = rss;
+ else
+ rs = rss2;
+
+ sx = (x2 - x1)/(double)WIDTH;
+ sy = (y2 - y1)/(double)HEIGHT;
+
+ for (j=0; j < HEIGHT; j++) {
+ double jj = j/(HEIGHT-1.0);
+ tco.p[1] = (double)((HEIGHT-1) - j) * sy + y1;
+ for (i = 0; i < WIDTH; i++) {
+ double ii = j/(HEIGHT-1.0);
+ tco.p[0] = (double)i * sx + x1;
+
+ tco.p[2] = (1.0-ii) * (1.0-jj) * z[0][0]
+ + (1.0-ii) * jj * z[0][1]
+ + ii * (1.0-jj) * z[1][0]
+ + ii * jj * z[1][1];
+
+ if (rs->INTERP(rs, &tco)) {
+ pa[j][i][0] = 0; /* Out of bounds in green */
+ pa[j][i][1] = 100;
+ pa[j][i][2] = 0;
+ } else {
+ int m;
+ /* printf("%d %d, %f %f returned %f\n",i,j,tco.p[0],tco.p[1],tco.v[0]); */
+ m = (int)((255.0 * (tco.v[0] - min)/(max - min)) + 0.5);
+ if (m < 0) {
+ pa[j][i][0] = 20; /* Dark blue */
+ pa[j][i][1] = 20;
+ pa[j][i][2] = 50;
+ } else if (m > 255) {
+ pa[j][i][0] = 230; /* Light blue */
+ pa[j][i][1] = 230;
+ pa[j][i][2] = 255;
+ } else {
+ pa[j][i][0] = m; /* Level in grey */
+ pa[j][i][1] = m;
+ pa[j][i][2] = m;
+ }
+ }
+ }
+ }
+
+ /* Mark verticies in red */
+ for(k = 0; k < npoints; k++) {
+ j = (int)((HEIGHT * (y2 - test_points[k].p[1])/(y2 - y1)) + 0.5);
+ i = (int)((WIDTH * (test_points[k].p[0] - x1)/(x2 - x1)) + 0.5);
+ pa[j][i][0] = 255;
+ pa[j][i][1] = 0;
+ pa[j][i][2] = 0;
+ }
+ write_rgb_tiff(rsv == 0 ? "t3d.tif" : "t3dh.tif" ,WIDTH,HEIGHT,(unsigned char *)pa);
+ }
+
+ /* Plot out 4 slices */
+ if (doplot == 1) {
+ int slice;
+
+ for (slice = 0; slice < 4; slice++) {
+ co tp; /* Test point */
+ double x[PLOTRES];
+ double ya[PLOTRES];
+ double yb[PLOTRES];
+ double xx,yy,zz;
+ double x1,x2,y1,y2,z1,z2;
+ double sx,sy,sz;
+ int i,n;
+
+ /* Set up slice to plot */
+ if (slice == 0) {
+ x1 = 0.5; y1 = 0.5, z1 = 0.0;
+ x2 = 0.5; y2 = 0.5, z2 = 1.0;
+ printf("Plot along z at x = y = 0.5\n");
+ n = PLOTRES;
+ } else if (slice == 1) {
+ x1 = 0.0; y1 = 0.5, z1 = 0.5;
+ x2 = 1.0; y2 = 0.5, z2 = 0.5;
+ printf("Plot along x at y = z = 0.5\n");
+ n = PLOTRES;
+ } else if (slice == 2) {
+ x1 = 0.5; y1 = 0.0, z1 = 0.5;
+ x2 = 0.5; y2 = 1.0, z2 = 0.5;
+ printf("Plot along y at x = z = 0.5\n");
+ n = PLOTRES;
+ } else {
+ x1 = 0.0; y1 = 0.0, z1 = 0.0;
+ x2 = 1.0; y2 = 1.0, z2 = 1.0;
+ printf("Plot along x = y = z\n");
+ n = PLOTRES;
+ }
+
+ sx = (x2 - x1)/n;
+ sy = (y2 - y1)/n;
+ sz = (z2 - z1)/n;
+
+ xx = x1;
+ yy = y1;
+ zz = z1;
+ for (i = 0; i < n; i++) {
+ double vv = i/(n-1.0);
+ x[i] = vv;
+ tp.p[0] = xx;
+ tp.p[1] = yy;
+ tp.p[2] = zz;
+
+ if (rss->INTERP(rss, &tp))
+ tp.v[0] = -0.1;
+ ya[i] = tp.v[0];
+
+ if (doh) {
+ if (rss2->INTERP(rss2, &tp))
+ tp.v[0] = -0.1;
+ yb[i] = tp.v[0];
+ }
+
+ xx += sx;
+ yy += sy;
+ zz += sz;
+ }
+
+ /* Plot the result */
+ if (doh)
+ do_plot(x,ya,yb,NULL,n);
+ else
+ do_plot(x,ya,NULL,NULL,n);
+ }
+ } else if (doplot == 2) {
+ co tp; /* Test point */
+ double x[PLOTRES];
+ double ya[PLOTRES];
+ double yb[PLOTRES];
+ double xx,yy,zz;
+ double x1,x2,y1,y2,z1,z2;
+ double sx,sy,sz;
+ int i,n;
+
+
+ x1 = plotpts[0][0];
+ y1 = plotpts[0][1];
+ z1 = plotpts[0][2];
+ x2 = plotpts[1][0];
+ y2 = plotpts[1][1];
+ z2 = plotpts[1][2];
+
+ printf("Plot along z at x = y = 0.5\n");
+ n = PLOTRES;
+
+ sx = (x2 - x1)/n;
+ sy = (y2 - y1)/n;
+ sz = (z2 - z1)/n;
+
+ xx = x1;
+ yy = y1;
+ zz = z1;
+ for (i = 0; i < n; i++) {
+ double vv = i/(n-1.0);
+ x[i] = vv;
+ tp.p[0] = xx;
+ tp.p[1] = yy;
+ tp.p[2] = zz;
+
+ if (rss->INTERP(rss, &tp))
+ tp.v[0] = -0.1;
+ ya[i] = tp.v[0];
+
+ if (doh) {
+ if (rss2->INTERP(rss2, &tp))
+ tp.v[0] = -0.1;
+ yb[i] = tp.v[0];
+ }
+
+ xx += sx;
+ yy += sy;
+ zz += sz;
+ }
+
+ /* Plot the result */
+ if (doh)
+ do_plot(x,ya,yb,NULL,n);
+ else
+ do_plot(x,ya,NULL,NULL,n);
+ }
+
+ /* Report the fit */
+ {
+ co tco; /* Test point */
+ int k;
+ double avg = 0;
+ double max = 0.0;
+
+ for(k = 0; k < npoints; k++) {
+ double err;
+ tco.p[0] = test_points[k].p[0];
+ tco.p[1] = test_points[k].p[1];
+ tco.p[2] = test_points[k].p[2];
+ rss->INTERP(rss, &tco);
+
+ err = tco.v[0] - test_points[k].v[0];
+ err = fabs(err);
+
+ avg += err;
+ if (err > max)
+ max = err;
+ }
+ avg /= (double)npoints;
+ printf("Max error %f%%, average %f%%\n",100.0 * max, 100.0 * avg);
+ }
+ return 0;
+}
+
+/* ---------------------- */
+/* Tiff diagnostic output */
+
+void
+write_rgb_tiff(
+char *name,
+int width,
+int height,
+unsigned char *data
+) {
+ int y;
+ unsigned char *dp;
+ TIFF *tif;
+
+ if ((tif = TIFFOpen(name, "w")) == NULL) {
+ fprintf(stderr,"Failed to open output TIFF file '%s'\n",name);
+ exit (-1);
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+
+ for (dp = data, y = 0; y < height; y++, dp += 3 * width) {
+ if (TIFFWriteScanline(tif, (tdata_t)dp, y, 0) < 0) {
+ fprintf(stderr,"WriteScanline Failed at line %d\n",y);
+ exit (-1);
+ }
+ }
+ (void) TIFFClose(tif);
+}
+
+#ifdef NEVER
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+/* Basic printf type error() and warning() routines */
+
+#ifdef __STDC__
+void
+error(char *fmt, ...)
+#else
+void
+error(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Error - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ exit (-1);
+}
+
+#ifdef __STDC__
+void
+warning(char *fmt, ...)
+#else
+void
+warning(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Warning - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#ifdef __STDC__
+void
+verbose(int level, char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+#else
+verbose(va_alist)
+va_dcl
+{
+ va_list args;
+ int level;
+ char *fmt;
+ va_start(args);
+ level = va_arg(args, int);
+ fmt = va_arg(args, char *);
+#endif
+ if (verbose_level >= level)
+ {
+ fprintf(verbose_out,"cmatch: ");
+ vfprintf(verbose_out, fmt, args);
+ fprintf(verbose_out, "\n");
+ fflush(verbose_out);
+ }
+ va_end(args);
+}
+#endif /* NEVER */
diff --git a/rspl/t3ddf.c b/rspl/t3ddf.c
new file mode 100644
index 0000000..b0e7d18
--- /dev/null
+++ b/rspl/t3ddf.c
@@ -0,0 +1,570 @@
+/************************************************/
+/* Test RSPL in 3D with weak default function */
+/************************************************/
+
+/* Author: Graeme Gill
+ * Date: 20/11/2005
+ * Derived from cmatch.c
+ * Copyright 1995, 2005 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+#define DEBUG
+#define DETAILED
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include "rspl.h"
+#include "tiffio.h"
+#include "plot.h"
+
+#ifdef NEVER
+#define INTERP spline_interp
+#else
+#define INTERP interp
+#endif
+
+#ifdef NEVER
+FILE *verbose_out = stdout;
+int verbose_level = 6; /* Current verbosity level */
+ /* 0 = none */
+ /* !0 = diagnostics */
+#endif /* NEVER */
+
+#define PLOTRES 256
+#define WIDTH 400 /* Raster size */
+#define HEIGHT 400
+
+#define MAX_ITS 500
+#define IT_TOL 0.0005
+#define GRES0 33 /* Default rspl resolutions */
+#define GRES1 33
+#define GRES2 33
+#undef NEVER
+#define ALWAYS
+
+/* two correction points along x = y = 0.5 */
+co test_points1[] = {
+// {{ 0.5, 0.5, 0.325 },{ 0.4 }}, /* 0 */
+// {{ 0.5, 0.5, 0.625 },{ 0.70 }} /* 1 */
+
+ {{ 0.4, 0.4, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.4, 0.4, 0.625 },{ 0.8 }}, /* 1 */
+ {{ 0.5, 0.4, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.5, 0.4, 0.625 },{ 0.8 }}, /* 1 */
+ {{ 0.6, 0.4, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.6, 0.4, 0.625 },{ 0.8 }}, /* 1 */
+
+ {{ 0.4, 0.5, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.4, 0.5, 0.625 },{ 0.8 }}, /* 1 */
+ {{ 0.5, 0.5, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.5, 0.5, 0.625 },{ 0.8 }}, /* 1 */
+ {{ 0.6, 0.5, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.6, 0.5, 0.625 },{ 0.8 }}, /* 1 */
+
+ {{ 0.4, 0.6, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.4, 0.6, 0.625 },{ 0.8 }}, /* 1 */
+ {{ 0.5, 0.6, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.5, 0.6, 0.625 },{ 0.8 }}, /* 1 */
+ {{ 0.6, 0.6, 0.325 },{ 0.5 }}, /* 0 */
+ {{ 0.6, 0.6, 0.625 },{ 0.8 }} /* 1 */
+};
+
+#ifdef NEVER
+#ifdef __STDC__
+#include <stdarg.h>
+void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...);
+#else
+#include <varargs.h>
+void error(), warning(), verbose();
+#endif
+#endif /* NEVER */
+
+void write_rgb_tiff(char *name, int width, int height, unsigned char *data);
+
+/* Weak default function */
+/* Linear along z, independent of x & y */
+static void wfunc(void *cbntx, double *out, double *in) {
+ out[0] = in[2];
+}
+
+void usage(void) {
+ fprintf(stderr,"Test 3D rspl interpolation with weak default function\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: t2d [options]\n");
+ fprintf(stderr," -t n Test set:\n");
+ fprintf(stderr," * 1 = two points along x & y\n");
+ fprintf(stderr," -w wweight Set weak default function weight (default 1.0)\n");
+ fprintf(stderr," -r resx,resy,resz Set grid resolutions (def %d %d %d)\n",GRES0,GRES1,GRES2);
+ fprintf(stderr," -h Test half scale resolution too\n");
+ fprintf(stderr," -q Test quarter scale resolution too\n");
+ fprintf(stderr," -x Use extra fitting\n");
+ fprintf(stderr," -s Test symetric smoothness (set asymetric -r !)\n");
+ fprintf(stderr," -s Test symetric smoothness\n");
+ fprintf(stderr," -p plot 4 slices, xy = 0.5, yz = 0.5, xz = 0.5, x=y=z\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ rspl *rss; /* Regularized spline structure */
+ rspl *rss2 = NULL; /* Regularized spline structure at half/quarter resolution */
+ datai low,high;
+ int gres[MXDI];
+ int gres2[MXDI];
+ double avgdev[MXDO];
+ co *test_points = test_points1;
+ int npoints = sizeof(test_points1)/sizeof(co);
+ double wweight = 1.0;
+ int twopass = 0;
+ int extra = 0;
+ int dosym = 0;
+ int doplot = 0;
+ int doh = 0;
+ int doq = 0;
+ int rsv;
+ int flags = RSPL_NOFLAGS;
+
+ low[0] = 0.0;
+ low[1] = 0.0;
+ low[2] = 0.0;
+ high[0] = 1.0;
+ high[1] = 1.0;
+ high[2] = 1.0;
+ gres[0] = GRES0;
+ gres[1] = GRES1;
+ gres[2] = GRES2;
+ avgdev[0] = 0.0;
+ avgdev[1] = 0.0;
+ avgdev[2] = 0.0;
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* test set */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage();
+ ix = atoi(na);
+ switch (ix) {
+ case 1:
+ test_points = test_points1;
+ npoints = sizeof(test_points1)/sizeof(co);
+ break;
+ default:
+ usage();
+ }
+
+ } else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage();
+ wweight = atof(na);
+
+ } else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (sscanf(na, " %d,%d,%d ", &gres[0], &gres[1], &gres[2]) != 2)
+ usage();
+
+ } else if (argv[fa][1] == 'h' || argv[fa][1] == 'H') {
+ doh = 1;
+
+ } else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') {
+ doh = 1;
+ doq = 1;
+
+ } else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ doplot = 1;
+
+ } else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ dosym = 1;
+
+ } else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ extra = 1;
+
+ } else if (argv[fa][1] == 's') {
+ dosym = 1;
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+
+ if (twopass)
+ flags |= RSPL_2PASSSMTH;
+
+ if (extra)
+ flags |= RSPL_EXTRAFIT2;
+
+ if (dosym)
+ flags |= RSPL_SYMDOMAIN;
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS, 3, 1);
+
+ /* Fit to scattered data */
+ rss->fit_rspl_df(rss,
+ flags, /* Non-mon and clip flags */
+ test_points, /* Test points */
+ npoints, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ low, high, /* Default data scale */
+ 1.0, /* Smoothing */
+ avgdev, /* Average Deviation */
+ NULL, /* iwidth */
+ wweight, /* weak function weight */
+ NULL, /* No context */
+ wfunc /* Weak function */
+ );
+ if (doh) {
+
+ if (doq) {
+ gres2[0] = gres[0]/4;
+ gres2[1] = gres[1]/4;
+ gres2[2] = gres[2]/4;
+ } else {
+ gres2[0] = gres[0]/2;
+ gres2[1] = gres[1]/2;
+ gres2[2] = gres[2]/2;
+ }
+
+ rss2 = new_rspl(RSPL_NOFLAGS, 3, 1);
+
+ /* Fit to scattered data */
+ rss2->fit_rspl_df(rss2,
+ flags, /* Non-mon and clip flags */
+ test_points, /* Test points */
+ npoints, /* Number of test points */
+ low, high, gres2, /* Low, high, resolution of grid */
+ low, high, /* Default data scale */
+ 1.0, /* Smoothing */
+ avgdev, /* Average Deviation */
+ NULL, /* iwidth */
+ wweight, /* weak function weight */
+ NULL, /* No context */
+ wfunc /* Weak function */
+ );
+ }
+
+ /* Test the interpolation with a slice in 2D */
+ for (rsv = 0; rsv <= doh; rsv++) {
+ double z[2][2] = { { 0.1, 0.5 }, { 0.5, 0.9 } };
+ double x1 = -0.2;
+ double x2 = 1.2;
+ double y1 = -0.2;
+ double y2 = 1.2;
+ double min = -0.0;
+ double max = 1.0;
+ rspl *rs;
+ unsigned char pa[HEIGHT][WIDTH][3];
+ co tco; /* Test point */
+ double sx,sy;
+ int i,j,k;
+
+ if (rsv == 0)
+ rs = rss;
+ else
+ rs = rss2;
+
+ sx = (x2 - x1)/(double)WIDTH;
+ sy = (y2 - y1)/(double)HEIGHT;
+
+ for (j=0; j < HEIGHT; j++) {
+ double jj = j/(HEIGHT-1.0);
+ tco.p[1] = (double)((HEIGHT-1) - j) * sy + y1;
+ for (i = 0; i < WIDTH; i++) {
+ double ii = j/(HEIGHT-1.0);
+ tco.p[0] = (double)i * sx + x1;
+
+ tco.p[2] = (1.0-ii) * (1.0-jj) * z[0][0]
+ + (1.0-ii) * jj * z[0][1]
+ + ii * (1.0-jj) * z[1][0]
+ + ii * jj * z[1][1];
+
+ if (rs->INTERP(rs, &tco)) {
+ pa[j][i][0] = 0; /* Out of bounds in green */
+ pa[j][i][1] = 100;
+ pa[j][i][2] = 0;
+ } else {
+ int m;
+ /* printf("%d %d, %f %f returned %f\n",i,j,tco.p[0],tco.p[1],tco.v[0]); */
+ m = (int)((255.0 * (tco.v[0] - min)/(max - min)) + 0.5);
+ if (m < 0) {
+ pa[j][i][0] = 20; /* Dark blue */
+ pa[j][i][1] = 20;
+ pa[j][i][2] = 50;
+ } else if (m > 255) {
+ pa[j][i][0] = 230; /* Light blue */
+ pa[j][i][1] = 230;
+ pa[j][i][2] = 255;
+ } else {
+ pa[j][i][0] = m; /* Level in grey */
+ pa[j][i][1] = m;
+ pa[j][i][2] = m;
+ }
+ }
+ }
+ }
+
+ /* Mark verticies in red */
+ for(k = 0; k < npoints; k++) {
+ j = (int)((HEIGHT * (y2 - test_points[k].p[1])/(y2 - y1)) + 0.5);
+ i = (int)((WIDTH * (test_points[k].p[0] - x1)/(x2 - x1)) + 0.5);
+ pa[j][i][0] = 255;
+ pa[j][i][1] = 0;
+ pa[j][i][2] = 0;
+ }
+ write_rgb_tiff(rsv == 0 ? "t3d.tif" : "t3dh.tif" ,WIDTH,HEIGHT,(unsigned char *)pa);
+ }
+
+ /* Plot out 4 slices */
+ if (doplot) {
+ int slice;
+
+ for (slice = 0; slice < 4; slice++) {
+ co tp; /* Test point */
+ double x[PLOTRES];
+ double ya[PLOTRES];
+ double yb[PLOTRES];
+ double xx,yy,zz;
+ double x1,x2,y1,y2,z1,z2;
+ double sx,sy,sz;
+ int i,n;
+
+ /* Set up slice to plot */
+ if (slice == 0) {
+ x1 = 0.5; y1 = 0.5, z1 = 0.0;
+ x2 = 0.5; y2 = 0.5, z2 = 1.0;
+ printf("Plot along z at x = y = 0.5\n");
+ n = PLOTRES;
+ } else if (slice == 1) {
+ x1 = 0.0; y1 = 0.5, z1 = 0.5;
+ x2 = 1.0; y2 = 0.5, z2 = 0.5;
+ printf("Plot along x at y = z = 0.5\n");
+ n = PLOTRES;
+ } else if (slice == 2) {
+ x1 = 0.5; y1 = 0.0, z1 = 0.5;
+ x2 = 0.5; y2 = 1.0, z2 = 0.5;
+ printf("Plot along y at x = z = 0.5\n");
+ n = PLOTRES;
+ } else {
+ x1 = 0.0; y1 = 0.0, z1 = 0.0;
+ x2 = 1.0; y2 = 1.0, z2 = 1.0;
+ printf("Plot along x = y = z\n");
+ n = PLOTRES;
+ }
+
+ sx = (x2 - x1)/n;
+ sy = (y2 - y1)/n;
+ sz = (z2 - z1)/n;
+
+ xx = x1;
+ yy = y1;
+ zz = z1;
+ for (i = 0; i < n; i++) {
+ double vv = i/(n-1.0);
+ x[i] = vv;
+ tp.p[0] = xx;
+ tp.p[1] = yy;
+ tp.p[2] = zz;
+
+ if (rss->INTERP(rss, &tp))
+ tp.v[0] = -0.1;
+ ya[i] = tp.v[0];
+
+ if (doh) {
+ if (rss2->INTERP(rss2, &tp))
+ tp.v[0] = -0.1;
+ yb[i] = tp.v[0];
+ }
+
+ xx += sx;
+ yy += sy;
+ zz += sz;
+ }
+
+ /* Plot the result */
+ if (doh)
+ do_plot(x,ya,yb,NULL,n);
+ else
+ do_plot(x,ya,NULL,NULL,n);
+ }
+ }
+
+ /* Report the fit */
+ {
+ co tco; /* Test point */
+ int k;
+ double avg = 0;
+ double max = 0.0;
+
+ for(k = 0; k < npoints; k++) {
+ double err;
+ tco.p[0] = test_points[k].p[0];
+ tco.p[1] = test_points[k].p[1];
+ tco.p[2] = test_points[k].p[2];
+ rss->INTERP(rss, &tco);
+
+ err = tco.v[0] - test_points[k].v[0];
+ err = fabs(err);
+
+ avg += err;
+ if (err > max)
+ max = err;
+ }
+ avg /= (double)npoints;
+ printf("Max error %f%%, average %f%%\n",100.0 * max, 100.0 * avg);
+ }
+ return 0;
+}
+
+/* ---------------------- */
+/* Tiff diagnostic output */
+
+void
+write_rgb_tiff(
+char *name,
+int width,
+int height,
+unsigned char *data
+) {
+ int y;
+ unsigned char *dp;
+ TIFF *tif;
+
+ if ((tif = TIFFOpen(name, "w")) == NULL) {
+ fprintf(stderr,"Failed to open output TIFF file '%s'\n",name);
+ exit (-1);
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+
+ for (dp = data, y = 0; y < height; y++, dp += 3 * width) {
+ if (TIFFWriteScanline(tif, (tdata_t)dp, y, 0) < 0) {
+ fprintf(stderr,"WriteScanline Failed at line %d\n",y);
+ exit (-1);
+ }
+ }
+ (void) TIFFClose(tif);
+}
+
+#ifdef NEVER
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+/* Basic printf type error() and warning() routines */
+
+#ifdef __STDC__
+void
+error(char *fmt, ...)
+#else
+void
+error(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Error - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ exit (-1);
+}
+
+#ifdef __STDC__
+void
+warning(char *fmt, ...)
+#else
+void
+warning(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Warning - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#ifdef __STDC__
+void
+verbose(int level, char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+#else
+verbose(va_alist)
+va_dcl
+{
+ va_list args;
+ int level;
+ char *fmt;
+ va_start(args);
+ level = va_arg(args, int);
+ fmt = va_arg(args, char *);
+#endif
+ if (verbose_level >= level)
+ {
+ fprintf(verbose_out,"cmatch: ");
+ vfprintf(verbose_out, fmt, args);
+ fprintf(verbose_out, "\n");
+ fflush(verbose_out);
+ }
+ va_end(args);
+}
+#endif /* NEVER */
diff --git a/rspl/tnd.c b/rspl/tnd.c
new file mode 100644
index 0000000..95e4d16
--- /dev/null
+++ b/rspl/tnd.c
@@ -0,0 +1,489 @@
+
+/************************************************/
+/* Test RSPL in 3/4D */
+/************************************************/
+
+/* Author: Graeme Gill
+ * Date: 22/4/96
+ * Derived from cmatch.c
+ * Copyright 1995 - 2000 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+#undef DEBUG
+#undef DETAILED
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <math.h>
+#include "rspl.h"
+#include "numlib.h"
+#include "tiffio.h"
+
+#ifdef NEVER
+FILE *verbose_out = stdout;
+int verbose_level = 6; /* Current verbosity level */
+ /* 0 = none */
+ /* !0 = diagnostics */
+#endif /* NEVER */
+
+#define spline_interp interp
+
+/* rspl flags */
+#define FLAGS (0 /* */)
+
+#define TEST_FWD_2D
+#define TEST_REV_LOOKUP
+#undef TEST_SLICE
+#undef TEST_RANDOM_POINTS
+
+#define MAX_ITS 500
+#define IT_TOL 0.0005
+#define GRES 17 /* Grid resolution */
+#define DI 4 /* Dimensions in */
+#define FDI 4 /* Function (out) Dimensions */
+#undef NEVER
+#define ALWAYS
+
+/* Arbitrary values */
+static co test_points[] = {
+ {{ 0.1,0.1,0.5,0.0 },{ 0.6, 0.2, 0.3, 0.99 }}, /* 0 */
+ {{ 0.2,0.7,0.1,0.3 },{ 0.3, 0.1, 0.1, 0.45 }}, /* 1 */
+ {{ 0.8,0.8,0.8,0.2 },{ 0.1, 0.7, 0.7, 0.7 }}, /* 2 */
+ {{ 0.5,0.6,0.4,0.9 },{ 0.7, 0.6, 0.5, 0.4 }}, /* 3 */
+ {{ 0.2,0.5,0.2,0.7 },{ 0.2, 0.3, 0.2, 0.2 }}, /* 4 */
+ {{ 0.3,0.7,0.2,0.8 },{ 0.8, 0.9, 0.3, 0.5 }}, /* 5 */
+ {{ 0.5,0.4,0.9,0.3 },{ 0.6, 0.4, 0.2, 0.01 }}, /* 6 */
+ {{ 0.1,0.9,0.7,0.4 },{ 1.0, 0.9, 0.3, 0.6 }}, /* 7 */
+ {{ 0.7,0.2,0.1,0.3 },{ 0.2, 0.3, 0.7, 0.3 }}, /* 8 */
+ {{ 0.8,0.4,0.3,0.7 },{ 0.4, 0.5, 0.6, 0.2 }}, /* 9 */
+ {{ 0.3,0.3,0.4,0.1 },{ 0.8, 0.6, 0.8, 0.1 }} /* 10 */
+ };
+
+#ifdef NEVER
+/* Inverting table */
+static co test_points[] = {
+ {{ 0.1,0.1,0.5,0.0 },{ 0.9, 0.9, 0.5, 1.0 }}, /* 0 */
+ {{ 0.2,0.7,0.1,0.3 },{ 0.8, 0.3, 0.9, 0.7 }}, /* 1 */
+ {{ 0.8,0.8,0.8,0.2 },{ 0.2, 0.2, 0.2, 0.8 }}, /* 2 */
+ {{ 0.5,0.6,0.4,0.9 },{ 0.5, 0.4, 0.6, 0.1 }}, /* 3 */
+ {{ 0.2,0.5,0.2,0.7 },{ 0.8, 0.5, 0.8, 0.3 }}, /* 4 */
+ {{ 0.3,0.7,0.2,0.8 },{ 0.7, 0.3, 0.8, 0.2 }}, /* 5 */
+ {{ 0.5,0.4,0.9,0.3 },{ 0.5, 0.6, 0.1, 0.7 }}, /* 6 */
+ {{ 0.1,0.9,0.7,0.4 },{ 0.9, 0.1, 0.3, 0.6 }}, /* 7 */
+ {{ 0.7,0.2,0.1,0.3 },{ 0.3, 0.8, 0.9, 0.7 }}, /* 8 */
+ {{ 0.8,0.4,0.3,0.7 },{ 0.2, 0.6, 0.7, 0.3 }}, /* 9 */
+ {{ 0.3,0.3,0.4,0.1 },{ 0.7, 0.7, 0.6, 0.9 }} /* 10 */
+ };
+#endif /* NEVER */
+
+#ifdef NEVER
+#ifdef __STDC__
+#include <stdarg.h>
+void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...);
+#else
+#include <varargs.h>
+void error(), warning(), verbose();
+#endif
+#endif /* NEVER */
+
+void write_rgb_tiff(char *name, int width, int height, unsigned char *data);
+
+int main(int argc, char *argv[]) {
+ co *tps = NULL;
+ int ntps = 0;
+ rspl *rss; /* Multi-resolution regularized spline structure */
+ datai low,high;
+ int gres[MXDI];
+ double avgdev[MXDO];
+ low[0] = 0.0;
+ low[1] = 0.0;
+ low[2] = 0.0;
+ low[3] = 0.0;
+ high[0] = 1.0;
+ high[1] = 1.0;
+ high[2] = 1.0;
+ high[3] = 1.0;
+ gres[0] = GRES;
+ gres[1] = GRES;
+ gres[2] = GRES;
+ gres[3] = GRES;
+ avgdev[0] = 0.0;
+ avgdev[1] = 0.0;
+ avgdev[2] = 0.0;
+ avgdev[3] = 0.0;
+
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS, DI, /* di */
+ FDI); /* fdi */
+
+#ifdef TEST_RANDOM_POINTS
+ {
+ int i;
+ ntps = i_rand(30,150);
+ tps = (co *)malloc(ntps * sizeof(co));
+ for (i = 0; i < ntps; i++) {
+ tps[i].p[0] = d_rand(0.0,1.0);
+ tps[i].p[1] = d_rand(0.0,1.0);
+ tps[i].p[2] = d_rand(0.0,1.0);
+ tps[i].p[3] = d_rand(0.0,1.0);
+ tps[i].v[0] = d_rand(0.0,1.0);
+ tps[i].v[1] = d_rand(0.0,1.0);
+ tps[i].v[2] = d_rand(0.0,1.0);
+ tps[i].v[3] = d_rand(0.0,1.0);
+ }
+ }
+#else
+ tps = test_points;
+ ntps = sizeof(test_points)/sizeof(co);
+#endif
+
+ /* Fit to scattered data */
+ rss->fit_rspl(rss,
+ FLAGS, /* Non-mon and clip flags */
+ tps, /* Test points */
+ ntps, /* Number of test points */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ 1.0, /* Smoothing */
+ avgdev, /* Average deviation */
+ NULL); /* iwidth */
+ /* IT_TOL, MAX_ITS); */
+
+/* verbose(1,"Regular spline fit error = %f\n",rss->efactor(rss,0)); */
+
+ /* Do a quick check */
+ {
+ co tco; /* Test point */
+ int i,j;
+ double df,sm;
+ for (i = 0; i < ntps; i++) {
+ for (j = 0; j < DI; j++)
+ tco.p[j] = tps[i].p[j];
+
+ rss->spline_interp(rss, &tco);
+ sm = 0.0;
+ for (j = 0; j < DI; j++) {
+ df = tco.v[j] - tps[i].v[j];
+ sm += df * df;
+ }
+ printf("Error at data point %d = %f\n",i,sqrt(sm));
+ }
+ }
+
+#ifdef TEST_REV_LOOKUP
+ {
+#define NIP 10
+ int i, r;
+ double v[MXDO]; /* Target output value */
+ co tp[NIP], chp; /* Test point, check point */
+ double cvec[4]; /* Text clip vector */
+ int auxm[4]; /* Auxiliary target value valid flag */
+
+ tp[0].v[0] = v[0] = 0.5;
+ tp[0].v[1] = v[1] = 0.5;
+ tp[0].v[2] = v[2] = 0.5;
+ tp[0].v[3] = v[3] = 0.5;
+
+ /* Set auxiliary target */
+ auxm[0] = 0;
+ auxm[1] = 0;
+ auxm[2] = 1;
+ auxm[3] = 0;
+ tp[0].p[0] = -1.0;
+ tp[0].p[1] = -1.0;
+ tp[0].p[2] = 0.5;
+ tp[0].p[3] = -1.0;
+
+ for (i = 1; i < NIP; i++) { /* Make sure we can see changes */
+ tp[i].p[0] = -1.0;
+ tp[i].p[1] = -1.0;
+ tp[i].p[2] = -1.0;
+ tp[i].p[3] = -1.0;
+ }
+
+ /* Clip center */
+ cvec[0] = 0.0 - tp[0].v[0];
+ cvec[1] = 0.0 - tp[0].v[1];
+ cvec[2] = 0.0 - tp[0].v[2];
+ cvec[3] = 0.0 - tp[0].v[3];
+
+ /* Do reverse interpolation ~~~1 */
+ if ((r = rss->rev_interp(rss, 0, NIP, auxm, NULL /*cvec*/, tp)) > 0) {
+ printf("Total of %d Results\n",r);
+ for (i = 0; i < r; i++)
+ printf("Result %d = %f, %f, %f, %f\n",i, tp[i].p[0],tp[i].p[1],tp[i].p[2],tp[i].p[3]);
+
+ /* Check test result */
+ for (i = 0; i < r; i++) {
+ chp.p[0] = tp[i].p[0];
+ chp.p[1] = tp[i].p[1];
+ chp.p[2] = tp[i].p[2];
+ chp.p[3] = tp[i].p[3];
+ chp.v[0] = -1.0;
+ chp.v[1] = -1.0;
+ chp.v[2] = -1.0;
+ chp.v[3] = -1.0;
+ if (rss->interp(rss, &chp))
+ printf("Fwd check %d failed!\n",i);
+ else {
+ int p;
+ double er = 0.0;
+ for (p = 0; p < FDI; p++)
+ er += (v[p] - chp.v[p]) * (v[p] - chp.v[p]);
+ printf("Fwd check error %d = %f\n",i,er);
+ }
+ }
+ } else
+ printf("Rev lookup result returned none\n");
+ }
+#endif /* TEST_REV_LOOKUP */
+
+#ifdef TEST_SLICE
+ /* Test the interpolation */
+ {
+ co tp; /* Test point */
+ double x[50000];
+ double y[50000];
+ double ya[50000];
+ double xx,yy;
+ double x1,x2,y1,y2;
+ double sx,sy;
+ int i,j,n;
+
+ /* Set up slice to plot */
+ x1 = 0.1; y1 = 0.5; /* ~4 */
+ x2 = 0.9; y2 = 0.5;
+ n = 100;
+
+ sx = (x2 - x1)/n;
+ sy = (y2 - y1)/n;
+
+ xx = x1;
+ yy = y1;
+ for (j = i = 0; i < n; i++)
+ {
+ tp.p[0] = xx;
+ tp.p[1] = yy;
+ if (rss->spline_interp(rss, &tp))
+ {
+ tp.v[0] = -0.1;
+ }
+ x[j] = xx;
+ y[j] = tp.v[0];
+ j++;
+ xx += sx;
+ yy += sy;
+ }
+
+ /* Plot the result */
+ do_plot(x,y,NULL,NULL,j);
+ }
+#endif /* TEST_SLICE */
+
+#ifdef TEST_FWD_2D
+ /* Test the interpolation in 2D */
+ {
+#define WIDTH 200
+#define HEIGHT 200
+ double x1 = -0.2;
+ double x2 = 1.2;
+ double y1 = -0.2;
+ double y2 = 1.2;
+ double min = -0.0;
+ double max = 1.0;
+
+ unsigned char pa[HEIGHT][WIDTH][3];
+ co tco; /* Test point */
+ double sx,sy;
+ int i,j,k;
+
+ sx = (x2 - x1)/(double)WIDTH;
+ sy = (y2 - y1)/(double)HEIGHT;
+
+ tco.p[2] = 0.5; /* Set slice */
+ tco.p[3] = 0.5;
+ for (j=0; j < HEIGHT; j++)
+ {
+ tco.p[1] = (double)((HEIGHT-1) - j) * sy + y1;
+ for (i=0; i < WIDTH; i++)
+ {
+ tco.p[0] = (double)i * sx + x1;
+ if (rss->spline_interp(rss, &tco))
+ {
+ pa[j][i][0] = 0; /* Out of bounds in green */
+ pa[j][i][1] = 100;
+ pa[j][i][2] = 0;
+ }
+ else
+ {
+ int m;
+/* printf("%d %d, %f %f returned %f\n",i,j,tco.p[0],tco.p[1],tco.v[0]); */
+ m = (int)((255.0 * (tco.v[0] - min)/(max - min)) + 0.5);
+ if (m < 0)
+ {
+ pa[j][i][0] = 0; /* Dark blue */
+ pa[j][i][1] = 0;
+ pa[j][i][2] = 40;
+ }
+ else if (m > 255)
+ {
+ pa[j][i][0] = 220; /* Light blue */
+ pa[j][i][1] = 220;
+ pa[j][i][2] = 255;
+ }
+ else
+ {
+ pa[j][i][0] = m; /* Level in grey */
+ pa[j][i][1] = m;
+ pa[j][i][2] = m;
+ }
+ }
+ }
+ }
+
+ /* Mark verticies in red */
+ for(k = 0; k < ntps; k++)
+ {
+ j = (int)((HEIGHT * (y2 - tps[k].p[1])/(y2 - y1)) + 0.5);
+ i = (int)((WIDTH * (tps[k].p[0] - x1)/(x2 - x1)) + 0.5);
+ pa[j][i][0] = 255;
+ pa[j][i][1] = 0;
+ pa[j][i][2] = 0;
+ }
+
+ write_rgb_tiff("tnd.tif",WIDTH,HEIGHT,(unsigned char *)pa);
+ }
+#endif /* TEST_FWD_2D */
+ return 0;
+ }
+
+/* ---------------------- */
+/* Tiff diagnostic output */
+
+void
+write_rgb_tiff(
+char *name,
+int width,
+int height,
+unsigned char *data
+) {
+ int y;
+ unsigned char *dp;
+ TIFF *tif;
+
+ if ((tif = TIFFOpen(name, "w")) == NULL) {
+ fprintf(stderr,"Failed to open output TIFF file '%s'\n",name);
+ exit (-1);
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+
+ for (dp = data, y = 0; y < height; y++, dp += 3 * width) {
+ if (TIFFWriteScanline(tif, (tdata_t)dp, y, 0) < 0) {
+ fprintf(stderr,"WriteScanline Failed at line %d\n",y);
+ exit (-1);
+ }
+ }
+ (void) TIFFClose(tif);
+}
+
+#ifdef NEVER
+
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+/* Basic printf type error() and warning() routines */
+
+#ifdef __STDC__
+void
+error(char *fmt, ...)
+#else
+void
+error(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Error - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ exit (-1);
+}
+
+#ifdef __STDC__
+void
+warning(char *fmt, ...)
+#else
+void
+warning(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"cmatch: Warning - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+#ifdef __STDC__
+void
+verbose(int level, char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+#else
+verbose(va_alist)
+va_dcl
+{
+ va_list args;
+ int level;
+ char *fmt;
+ va_start(args);
+ level = va_arg(args, int);
+ fmt = va_arg(args, char *);
+#endif
+ if (verbose_level >= level)
+ {
+ fprintf(verbose_out,"cmatch: ");
+ vfprintf(verbose_out, fmt, args);
+ fprintf(verbose_out, "\n");
+ fflush(verbose_out);
+ }
+ va_end(args);
+}
+#endif /* NEVER */
diff --git a/rspl/trnd.c b/rspl/trnd.c
new file mode 100644
index 0000000..2676182
--- /dev/null
+++ b/rspl/trnd.c
@@ -0,0 +1,275 @@
+
+/************************************************/
+/* Test RSPL reverse lookup in 3/4D */
+/************************************************/
+
+/* Author: Graeme Gill
+ * Date: 31/10/96
+ * Derived from tnd.c
+ * Copyright 1999 - 2000 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+#undef DEBUG
+#undef DETAILED
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <math.h>
+#include "rspl.h"
+#include "numlib.h"
+
+#ifdef NEVER
+FILE *verbose_out = stdout;
+int verbose_level = 6; /* Current verbosity level */
+ /* 0 = none */
+ /* !0 = diagnostics */
+#endif /* NEVER */
+
+#define GRES 10 /* Grid resolution */
+#define DI 4 /* Dimensions in */
+#define FDI 3 /* Function (out) Dimensions */
+#define DOLIMIT
+#define LIMITV 1.50
+
+/* Fwd function approximated by rspl */
+void func(
+void *cbctx,
+double *out,
+double *in) {
+ double tt[4];
+
+#ifdef NEVER
+printf(" Got input %f %f\n",in[0],in[1]);
+ if (in[1] < 0.5 && in[0] < 0.5) { /* 0,0 */
+ out[0] = 0.1;
+ out[1] = 0.5;
+ }
+ if (in[1] < 0.5 && in[0] > 0.5) { /* 0,1 */
+ out[0] = 0.5;
+ out[1] = 0.0;
+ }
+ if (in[1] > 0.5 && in[0] < 0.5) { /* 0,1 */
+ out[0] = 0.9;
+ out[1] = 0.8;
+ }
+ if (in[1] > 0.5 && in[0] > 0.5) { /* 0,1 */
+ out[0] = 0.9;
+ out[1] = 0.2;
+ }
+#endif /* NEVER */
+
+#if DI >= 3
+ tt[0] = 0.7 * in[0] + 0.2 * in[1] + 0.1 * in[2];
+ tt[0] = tt[0] * tt[0];
+ tt[1] = 0.2 * in[0] + 0.8 * in[1] - 0.1 * in[2];
+ tt[1] = tt[1] * tt[1];
+ tt[2] = 0.3 * in[0] - 0.2 * in[1] + 0.9 * in[2];
+ tt[2] = tt[2] * tt[2];
+#endif
+
+#if DI == 4
+ tt[0] *= in[3];
+ tt[1] *= in[3];
+ tt[2] *= in[3];
+#endif
+
+ tt[3] = 0.3 * in[0] + 0.4 * in[1] + 0.3 * in[2];
+
+#if FDI > 0
+ out[0] = tt[0];
+#endif
+#if FDI > 1
+ out[1] = tt[1];
+#endif
+#if FDI > 2
+ out[2] = tt[2];
+#endif
+#if FDI > 3
+ out[3] = tt[3];
+#endif
+}
+
+/* Simplex ink limit function */
+double limitf(
+void *lcntx,
+double *in
+) {
+ int i;
+ double ov;
+
+ for (ov = 0.0, i = 0; i < DI; i++) {
+ ov += in[i];
+ }
+ return ov;
+}
+
+int
+main(
+int argc,
+char *argv[]
+) {
+ int e;
+ rspl *rss; /* Multi-resolution regularized spline structure */
+ int gres[MXDI];
+
+ for (e = 0; e < DI; e++)
+ gres[e] = GRES;
+
+ printf("Started test\n");
+ /* Create the object */
+ rss = new_rspl(RSPL_NOFLAGS, DI, FDI);
+
+ printf("Rspl allocated\n");
+ rss->set_rspl(rss, 0, (void *)NULL, func, NULL, NULL, gres, NULL, NULL);
+// rss->set_rspl(rss, RSPL_SET_APXLS, (void *)NULL, func, NULL, NULL, gres, NULL, NULL);
+
+ printf("Rspl set\n");
+
+ {
+#define NIP 10 /* Number of solutions allowed */
+ int i, r, cl;
+ double v[MXDO]; /* Target output value */
+ co tp[NIP], chp; /* Test point, check point */
+ double cvec[4]; /* Text clip vector */
+ int auxm[4]; /* Auxiliary target value valid flag */
+ double lmin[4], lmax[4]; /* Locus min/max values */
+
+ /* Output value being looked for */
+/*
+ tp[0].v[0] = v[0] = 1.5;
+ tp[0].v[1] = v[1] = 0.9;
+ tp[0].v[2] = v[2] = 1.2;
+ tp[0].v[3] = v[3] = 0.0;
+*/
+ tp[0].v[0] = v[0] = 0.3;
+ tp[0].v[1] = v[1] = 0.4;
+ tp[0].v[2] = v[2] = 0.26;
+ tp[0].v[3] = v[3] = 0.0;
+
+ /* Set auxiliary target */
+ auxm[0] = 0;
+ auxm[1] = 0;
+ auxm[2] = 0;
+ auxm[3] = 1;
+ tp[0].p[0] = 0;
+ tp[0].p[1] = 0;
+ tp[0].p[2] = 0.0;
+ tp[0].p[3] = 0.87;
+
+ for (i = 1; i < NIP; i++) { /* Make sure we can see changes */
+ tp[i].p[0] = -1.0;
+ tp[i].p[1] = -1.0;
+ tp[i].p[2] = -1.0;
+ tp[i].p[3] = -1.0;
+ }
+
+ /* Clip center */
+ cvec[0] = 0.1 - tp[0].v[0];
+ cvec[1] = 0.1 - tp[0].v[1];
+ cvec[2] = 0.1 - tp[0].v[2];
+ cvec[3] = 0.1 - tp[0].v[3];
+
+#ifdef DOLIMIT
+ /* Setup limit */
+ rss->rev_set_limit(rss,
+ limitf, /* limit function */
+ NULL, /* Function context */
+ LIMITV /* limit maximum value */
+ );
+#endif /* DOLIMIT */
+
+#if DI > FDI
+ /* Check out the locus size */
+ if ((r = rss->rev_locus(rss,
+ auxm, /* auxm Auxiliary mask flags */
+ tp, /* Input and auxiliary values */
+ lmin, /* Locus min/max return values */
+ lmax
+ )) > 0) {
+
+ printf("Total of %d Results\n",r);
+ for (i = 0; i < FDI; i++) {
+ if (auxm[i] == 0)
+ continue;
+ printf("Auxiliary %d min = %f, max = %f\n",i, lmin[i], lmax[i]);
+ }
+ } else {
+ printf("Failed to find gamut range\n");
+ }
+ printf("\n\n");
+#endif
+
+ /* Do reverse interpolation ~~~1 */
+ if ((r = rss->rev_interp(rss,
+ 0 /* RSPL_EXACTAUX */, /* Hint flags */
+ NIP, /* Number of solutions allowed */
+ auxm, /* auxm Auxiliary mask flags */
+ cvec, /* cvec Clip vector direction & length */
+ tp) /* Input and output values */
+ ) > 0) {
+
+ printf("Total of %d Results\n", r &= RSPL_NOSOLNS);
+
+ printf("Target output %f, %f, %f, %f\n", v[0], v[1], v[2], v[3]);
+
+ cl = r & RSPL_DIDCLIP; /* clipped flag */
+ r &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ /* Check test result */
+ for (i = 0; i < r; i++) {
+ chp.p[0] = tp[i].p[0];
+ chp.p[1] = tp[i].p[1];
+ chp.p[2] = tp[i].p[2];
+ chp.p[3] = tp[i].p[3];
+ chp.v[0] = -1.0;
+ chp.v[1] = -1.0;
+ chp.v[2] = -1.0;
+ chp.v[3] = -1.0;
+ printf("Result %d = inp: %f, %f, %f, %f\n",i, tp[i].p[0],tp[i].p[1],tp[i].p[2],tp[i].p[3]);
+ printf(" out: %f, %f, %f, %f\n",tp[i].v[0],tp[i].v[1],tp[i].v[2],tp[i].v[3]);
+
+ if (rss->interp(rss, &chp))
+ printf("Fwd check %d failed!\n",i);
+ else {
+ int p;
+ double er = 0.0;
+ for (p = 0; p < FDI; p++)
+ er += (v[p] - chp.v[p]) * (v[p] - chp.v[p]);
+ er = sqrt(er);
+ printf("Fwd check error %d = %f\n",i,er);
+
+ if (cl != 0) {
+ /* Check if clipped result us reasonable */
+ /* ~~~ */
+ }
+ }
+ {
+ printf("Output limit = %f\n",limitf(NULL, tp[i].p));
+ }
+ }
+ } else
+ printf("Rev lookup result returned none\n");
+ }
+ rss->del(rss);
+ return 0;
+}
+
+
+#ifdef NEVER
+/* Standard interface for powell function */
+/* return err on sucess, -1.0 on failure */
+/* Result will be in cp */
+double powell(
+int di, /* Dimensionality */
+double cp[], /* Initial starting point */
+double s[], /* Size of initial search area */
+double ftol, /* Tollerance of error change to stop on */
+int maxit, /* Maximum iterations allowed */
+double (*func)(void *fdata, double tp[]), /* Error function to evaluate */
+void *fdata /* Opaque data needed by function */
+) {
+#endif
diff --git a/scanin/CMP_DT_003.cht b/scanin/CMP_DT_003.cht
new file mode 100644
index 0000000..37411af
--- /dev/null
+++ b/scanin/CMP_DT_003.cht
@@ -0,0 +1,336 @@
+
+BOXES 286
+ F _ _ 22 14 522 14 522 402 22 402
+ D ALL ALL _ _ 500 388 22 14 0 0
+ X A S 1 15 24.21052632 22.4 44.5 43.5 24.21052632 22.4
+
+BOX_SHRINK 3.0
+
+REF_ROTATION 0.0
+
+XLIST 20
+ 44.500000 1.0 1.0
+ 68.710526 1.0 1.0
+ 92.921053 1.0 1.0
+ 117.131579 1.0 1.0
+ 141.342105 1.0 1.0
+ 165.552632 1.0 1.0
+ 189.763158 1.0 1.0
+ 213.973684 1.0 1.0
+ 238.184211 1.0 1.0
+ 262.394737 1.0 1.0
+ 286.605263 1.0 1.0
+ 310.815790 1.0 1.0
+ 335.026316 1.0 1.0
+ 359.236842 1.0 1.0
+ 383.447368 1.0 1.0
+ 407.657895 1.0 1.0
+ 431.868421 1.0 1.0
+ 456.078947 1.0 1.0
+ 480.289474 1.0 1.0
+ 504.500000 1.0 1.0
+
+YLIST 16
+ 43.5000000 1.0 1.0
+ 65.9000000 1.0 1.0
+ 88.3000000 1.0 1.0
+ 110.7000000 1.0 1.0
+ 133.1000000 1.0 1.0
+ 155.5000000 1.0 1.0
+ 177.9000000 1.0 1.0
+ 200.3000000 1.0 1.0
+ 222.7000000 1.0 1.0
+ 245.1000000 1.0 1.0
+ 267.5000000 1.0 1.0
+ 289.9000000 1.0 1.0
+ 312.3000000 1.0 1.0
+ 334.7000000 1.0 1.0
+ 357.1000000 1.0 1.0
+ 379.5000000 1.0 1.0
+
+EXPECTED XYZ 285
+ A1 9.46 8.62 29.26
+ A2 75.93 84.68 17.08
+ A3 44.11 49.20 9.06
+ A4 74.02 82.54 15.47
+ A5 37.88 42.42 7.93
+ A6 70.26 78.24 13.90
+ A7 33.59 37.74 7.04
+ A8 64.25 71.82 12.27
+ A9 30.32 34.10 6.32
+ A10 57.13 63.83 11.22
+ A11 26.62 30.10 5.61
+ A12 51.96 58.23 10.31
+ A13 24.04 26.72 5.25
+ A14 47.16 52.59 9.77
+ A15 37.64 22.85 4.57
+ B1 8.18 6.87 23.20
+ B2 3.61 3.38 6.33
+ B3 20.88 23.43 4.87
+ B4 6.33 6.95 2.79
+ B5 16.96 19.17 4.20
+ B6 5.33 5.76 2.62
+ B7 13.34 14.75 3.69
+ B8 4.19 4.42 2.51
+ B9 11.50 12.44 3.41
+ B10 3.35 3.48 2.29
+ B11 9.89 10.67 3.24
+ B12 2.58 2.69 2.00
+ B13 8.23 9.01 3.11
+ B14 6.56 5.16 3.23
+ B15 24.38 14.64 3.70
+ C1 68.17 69.38 68.07
+ C2 36.78 42.46 59.62
+ C3 75.58 84.30 16.75
+ C4 75.91 84.25 23.05
+ C5 74.70 83.33 16.21
+ C6 75.40 83.27 27.19
+ C7 72.95 81.42 15.76
+ C8 76.66 83.97 33.57
+ C9 71.33 79.64 15.34
+ C10 76.21 82.14 39.39
+ C11 70.81 79.26 15.13
+ C12 78.61 84.06 47.87
+ C13 73.95 82.35 17.71
+ C14 60.78 52.94 41.53
+ C15 36.37 21.94 4.40
+ D1 7.77 6.43 21.76
+ D2 3.42 3.25 4.79
+ D3 10.85 14.71 3.95
+ D4 45.74 31.43 7.66
+ D5 64.97 58.40 40.57
+ D6 19.20 20.77 4.47
+ D7 75.67 77.88 68.77
+ D8 46.56 58.50 11.12
+ D9 63.18 64.06 65.19
+ D10 81.64 85.77 61.30
+ D11 65.37 58.65 46.40
+ D12 61.29 55.60 29.97
+ D13 39.33 30.42 13.58
+ D14 5.41 4.44 3.00
+ D15 21.48 13.05 3.51
+ E1 51.91 51.52 63.01
+ E2 33.50 39.48 59.55
+ E3 19.80 26.35 5.19
+ E4 40.01 32.11 15.48
+ E5 37.52 50.89 23.01
+ E6 12.96 19.59 4.87
+ E7 40.98 31.63 14.39
+ E8 82.08 84.89 69.04
+ E9 42.04 30.96 10.93
+ E10 22.65 16.11 3.94
+ E11 16.97 31.21 9.80
+ E12 17.85 13.86 4.54
+ E13 37.65 30.47 11.22
+ E14 59.56 52.44 35.78
+ E15 37.21 22.38 4.99
+ F1 7.29 5.92 19.97
+ F2 2.90 2.84 3.47
+ F3 23.09 24.88 26.94
+ F4 12.29 23.07 7.35
+ F5 3.78 3.96 3.02
+ F6 35.90 39.27 26.05
+ F7 31.18 36.48 44.00
+ F8 14.33 10.91 3.47
+ F9 51.06 46.54 12.01
+ F10 62.15 71.68 13.67
+ F11 45.60 30.43 40.49
+ F12 27.89 15.62 6.31
+ F13 39.47 27.31 5.08
+ F14 4.49 3.88 2.77
+ F15 19.73 12.17 3.49
+ G1 40.25 39.39 58.62
+ G2 19.66 22.70 47.78
+ G3 14.05 21.04 21.63
+ G4 25.20 38.40 38.99
+ G5 2.23 2.29 1.82
+ G6 32.34 44.38 25.97
+ G7 39.08 40.35 45.16
+ G8 21.91 25.22 7.66
+ G9 51.20 40.45 19.47
+ G10 53.69 54.84 12.82
+ G11 43.69 29.70 5.63
+ G12 14.51 14.92 41.81
+ G13 48.91 38.08 7.33
+ G14 57.75 51.93 23.98
+ G15 40.27 24.75 7.03
+ H1 6.40 5.14 17.21
+ H2 2.50 2.51 2.41
+ H3 29.45 31.10 6.27
+ H4 8.45 13.05 6.25
+ H5 86.92 89.85 72.02
+ H6 55.25 57.23 44.58
+ H7 61.04 63.45 50.22
+ H8 66.13 68.64 54.49
+ H9 72.30 74.84 59.86
+ H10 77.76 80.54 64.40
+ H11 51.45 33.36 33.30
+ H12 34.29 19.71 5.84
+ H13 58.12 53.49 9.49
+ H14 3.19 3.01 2.34
+ H15 17.14 10.82 3.44
+ I1 28.84 27.18 51.31
+ I2 26.22 30.11 55.57
+ I3 8.61 12.78 13.10
+ I4 33.19 47.31 44.96
+ I5 2.15 2.20 1.76
+ I6 49.64 51.25 39.42
+ I7 5.60 5.83 4.56
+ I8 7.15 7.43 5.74
+ I9 8.78 9.28 7.44
+ I10 10.72 11.21 8.69
+ I11 40.19 25.72 5.17
+ I12 24.06 30.11 17.13
+ I13 37.28 22.42 4.86
+ I14 55.52 50.69 14.17
+ I15 43.35 28.37 10.26
+ J1 5.89 4.70 15.90
+ J2 2.28 2.31 1.96
+ J3 27.11 24.41 4.88
+ J4 7.74 9.84 6.03
+ J5 89.34 92.52 73.92
+ J6 43.85 45.42 35.57
+ J7 4.30 4.50 3.43
+ J8 2.15 2.19 1.76
+ J9 2.09 2.14 1.72
+ J10 13.73 14.17 11.04
+ J11 48.54 31.76 20.77
+ J12 32.08 17.94 10.34
+ J13 40.10 26.64 5.08
+ J14 2.38 2.39 1.88
+ J15 14.87 9.67 3.40
+ K1 20.70 19.17 45.35
+ K2 50.77 57.51 66.01
+ K3 5.13 6.59 5.77
+ K4 39.68 52.97 51.16
+ K5 2.10 2.15 1.70
+ K6 38.94 40.21 31.90
+ K7 3.21 3.34 2.69
+ K8 2.41 2.47 1.98
+ K9 2.13 2.17 1.74
+ K10 15.60 16.15 12.73
+ K11 33.32 21.81 4.35
+ K12 27.52 31.82 32.36
+ K13 56.60 50.73 8.89
+ K14 45.02 29.35 9.98
+ K15 33.62 20.13 4.15
+ L1 5.46 4.40 14.88
+ L2 2.11 2.16 1.70
+ L3 25.77 20.56 4.52
+ L4 7.71 9.80 5.98
+ L5 84.08 86.79 69.98
+ L6 33.50 34.70 27.85
+ L7 29.61 30.66 23.86
+ L8 24.73 25.62 19.83
+ L9 21.29 22.01 17.44
+ L10 18.36 19.06 15.25
+ L11 46.52 30.74 11.47
+ L12 24.42 16.78 15.94
+ L13 52.38 41.58 7.87
+ L14 2.21 2.25 1.78
+ L15 13.22 8.72 3.42
+ M1 14.98 13.99 39.67
+ M2 11.85 13.25 28.34
+ M3 12.36 12.97 3.50
+ M4 61.64 70.63 61.46
+ M5 2.71 2.82 2.20
+ M6 19.68 32.16 26.16
+ M7 22.82 21.24 9.05
+ M8 18.52 24.40 39.35
+ M9 12.91 11.12 3.85
+ M10 30.16 32.59 40.27
+ M11 19.93 15.24 35.28
+ M12 23.31 32.50 35.69
+ M13 40.57 29.47 5.44
+ M14 48.37 32.78 13.33
+ M15 33.33 19.90 4.09
+ N1 4.94 4.06 12.92
+ N2 2.11 2.17 1.71
+ N3 24.26 17.39 4.08
+ N4 7.07 6.36 6.03
+ N5 4.99 5.20 4.01
+ N6 16.13 29.37 14.18
+ N7 26.00 22.77 21.27
+ N8 19.90 28.01 35.06
+ N9 13.59 11.19 8.53
+ N10 25.06 17.40 4.36
+ N11 45.92 30.60 7.35
+ N12 23.35 22.39 17.67
+ N13 32.06 32.06 6.36
+ N14 2.19 2.22 1.79
+ N15 11.33 7.77 3.42
+ O1 10.02 9.28 31.17
+ O2 10.76 11.90 24.53
+ O3 42.31 54.55 53.67
+ O4 19.88 26.90 37.20
+ O5 13.56 15.96 37.55
+ O6 4.92 5.13 7.76
+ O7 5.99 4.89 16.71
+ O8 86.01 88.32 70.07
+ O9 41.28 54.49 46.60
+ O10 54.51 66.41 49.82
+ O11 6.39 4.76 7.70
+ O12 7.47 7.24 24.02
+ O13 10.20 9.57 23.31
+ O14 53.00 38.17 18.52
+ O15 32.29 19.09 3.94
+ P1 4.39 3.79 10.44
+ P2 23.77 36.35 37.44
+ P3 9.32 10.17 16.69
+ P4 21.20 34.66 29.30
+ P5 13.42 11.68 33.90
+ P6 85.83 89.93 70.83
+ P7 10.92 10.20 33.11
+ P8 68.39 77.72 54.98
+ P9 74.31 69.95 50.96
+ P10 76.65 83.76 61.45
+ P11 22.36 24.83 36.36
+ P12 53.63 58.46 57.53
+ P13 5.08 4.20 5.62
+ P14 56.95 44.27 24.67
+ P15 9.35 6.75 3.46
+ Q1 8.80 8.07 28.22
+ Q2 23.52 36.04 37.29
+ Q3 20.50 35.70 11.97
+ Q4 30.51 46.22 20.80
+ Q5 20.45 35.69 11.99
+ Q6 36.10 51.62 25.45
+ Q7 20.44 35.71 12.27
+ Q8 41.63 56.54 30.57
+ Q9 21.38 36.76 13.48
+ Q10 51.17 64.25 39.66
+ Q11 23.24 38.80 15.22
+ Q12 62.32 72.88 49.66
+ Q13 26.49 42.23 17.36
+ Q14 60.98 51.36 33.35
+ Q15 29.32 17.44 3.82
+ R1 3.95 3.59 8.36
+ R2 20.13 30.86 31.56
+ R3 10.16 18.47 6.04
+ R4 4.78 6.56 3.40
+ R5 9.21 15.96 5.65
+ R6 4.38 5.64 3.17
+ R7 8.46 14.35 5.50
+ R8 3.97 4.84 3.01
+ R9 7.21 11.73 4.98
+ R10 3.21 3.65 2.53
+ R11 6.23 9.66 4.43
+ R12 2.54 2.69 2.07
+ R13 5.50 7.95 3.98
+ R14 65.19 58.07 40.38
+ R15 7.60 5.78 3.43
+ S1 8.92 8.17 28.21
+ S2 20.24 35.38 11.78
+ S3 17.56 32.25 10.31
+ S4 19.54 34.67 11.34
+ S5 17.29 31.99 10.02
+ S6 18.80 33.75 11.17
+ S7 16.23 30.73 9.38
+ S8 16.69 31.26 9.79
+ S9 14.30 27.57 7.99
+ S10 19.72 34.91 12.50
+ S11 12.91 24.49 7.31
+ S12 26.55 41.95 17.28
+ S13 11.56 21.36 6.62
+ S14 33.15 44.32 24.54
+ S15 26.38 15.91 3.70
diff --git a/scanin/CMP_Digital_Target-3.cht b/scanin/CMP_Digital_Target-3.cht
new file mode 100644
index 0000000..eb95ed8
--- /dev/null
+++ b/scanin/CMP_Digital_Target-3.cht
@@ -0,0 +1,1210 @@
+
+BOXES 571
+ F _ _ 100 200 3100 200 3100 2100 100 2100
+ D ALL ALL _ _ 3200 200 0 0 0 0
+ X A Z 1 19 100 100 100 200 100 100
+ X 2A 2D 1 19 100 100 2700 200 100 100
+
+BOX_SHRINK 12
+
+REF_ROTATION 0.0
+
+XLIST 31
+ 100 1 1
+ 200 1 1
+ 300 1 1
+ 400 1 1
+ 500 1 1
+ 600 1 1
+ 700 1 1
+ 800 1 1
+ 900 1 1
+ 1000 1 1
+ 1100 1 1
+ 1200 1 1
+ 1300 1 1
+ 1400 1 1
+ 1500 1 1
+ 1600 1 1
+ 1700 1 1
+ 1800 1 1
+ 1900 1 1
+ 2000 1 1
+ 2100 1 1
+ 2200 1 1
+ 2300 1 1
+ 2400 1 1
+ 2500 1 1
+ 2600 1 1
+ 2700 1 1
+ 2800 1 1
+ 2900 1 1
+ 3000 1 1
+ 3100 1 1
+
+YLIST 21
+ 200 1 1
+ 300 1 1
+ 400 1 1
+ 500 1 1
+ 600 1 1
+ 700 1 1
+ 800 1 1
+ 900 1 1
+ 1000 1 1
+ 1100 1 1
+ 1200 1 1
+ 1300 1 1
+ 1400 1 1
+ 1500 1 1
+ 1500 1 1
+ 1600 1 1
+ 1700 1 1
+ 1800 1 1
+ 1900 1 1
+ 2000 1 1
+ 2100 1 1
+
+EXPECTED XYZ 570
+A1 19.991 14.120 27.886
+B1 19.926 34.054 14.005
+C1 6.2319 5.6339 19.078
+D1 32.785 35.198 16.672
+E1 38.996 22.658 25.805
+F1 16.011 17.612 14.561
+G1 39.496 24.997 12.003
+H1 7.4905 6.2468 18.358
+I1 11.987 23.286 6.5928
+J1 16.591 12.444 27.331
+K1 63.038 64.179 58.403
+L1 4.3513 3.8393 2.7750
+M1 27.386 30.873 42.527
+N1 31.789 44.281 40.439
+O1 59.453 61.985 40.335
+P1 26.783 15.713 3.5833
+Q1 3.0238 3.6843 3.0876
+R1 15.462 28.885 12.776
+S1 23.694 16.421 29.352
+T1 65.900 73.381 11.377
+U1 8.3333 15.036 13.749
+V1 72.416 77.985 33.423
+W1 16.393 25.254 38.122
+X1 2.3144 2.3581 1.9303
+Y1 27.102 23.276 16.813
+Z1 2.6994 2.8850 2.2332
+2A1 10.757 20.588 4.8216
+2B1 40.765 45.919 58.857
+2C1 22.864 16.381 33.839
+2D1 28.289 21.404 20.483
+A2 10.412 10.567 30.978
+B2 24.139 14.085 3.5857
+C2 19.473 21.752 38.376
+D2 26.280 16.991 28.035
+E2 42.573 39.671 9.6556
+F2 17.113 18.705 43.690
+G2 35.850 22.548 3.8554
+H2 13.037 10.392 26.425
+I2 14.946 28.262 8.1825
+J2 3.1780 3.3914 2.3047
+K2 35.880 35.178 26.683
+L2 36.434 22.147 28.386
+M2 17.689 17.022 15.072
+N2 36.396 23.022 13.623
+O2 19.884 26.988 39.544
+P2 10.294 7.4271 3.4839
+Q2 24.415 37.008 36.288
+R2 36.078 21.682 26.898
+S2 12.232 12.247 33.412
+T2 12.486 23.920 5.4357
+U2 38.913 47.091 40.794
+V2 8.3779 6.8387 3.7119
+W2 2.3401 2.3804 1.9157
+X2 17.501 20.678 9.7225
+Y2 60.324 56.490 9.7029
+Z2 18.340 14.257 6.9452
+2A2 39.051 50.700 6.0515
+2B2 5.3134 8.7205 3.7883
+2C2 24.040 16.842 14.641
+2D2 10.963 22.720 8.1563
+A3 3.2215 2.8069 3.1344
+B3 35.703 49.122 24.276
+C3 9.6710 9.2674 28.141
+D3 39.368 42.329 16.693
+E3 9.8448 9.8037 29.501
+F3 50.040 60.997 38.371
+G3 9.8731 9.2375 28.216
+H3 31.926 43.409 5.2962
+I3 18.889 24.530 52.235
+J3 36.271 22.167 11.952
+K3 34.281 37.060 50.573
+L3 2.4511 2.5353 2.0398
+M3 34.120 37.136 30.510
+N3 28.309 16.461 3.7229
+O3 12.851 10.508 27.052
+P3 24.532 27.910 7.4170
+Q3 29.800 23.719 40.761
+R3 11.420 17.249 4.2060
+S3 30.098 17.923 3.6411
+T3 15.102 16.455 41.548
+U3 16.816 29.880 6.2892
+V3 19.054 17.886 40.635
+W3 21.160 13.146 3.6418
+X3 56.827 44.647 36.033
+Y3 7.3224 13.350 4.3645
+Z3 34.447 20.515 11.595
+2A3 10.795 11.448 32.464
+2B3 20.617 25.691 5.5795
+2C3 11.126 10.174 28.914
+2D3 68.724 66.102 56.410
+A4 19.671 15.554 33.919
+B4 17.501 19.753 3.8498
+C4 21.509 25.734 51.674
+D4 51.958 42.451 9.1213
+E4 14.112 17.806 42.697
+F4 61.487 65.884 27.427
+G4 38.420 23.239 29.457
+H4 9.8759 9.7311 29.126
+I4 75.793 79.718 46.695
+J4 10.595 15.480 24.653
+K4 32.187 21.331 32.814
+L4 13.777 17.753 16.663
+M4 27.339 16.027 3.5603
+N4 16.922 28.995 29.336
+O4 6.3066 4.7610 6.9921
+P4 22.390 29.210 15.592
+Q4 30.657 20.369 32.268
+R4 19.152 19.807 15.592
+S4 13.948 25.671 5.2122
+T4 14.991 27.898 19.745
+U4 11.486 7.6381 12.484
+V4 10.749 11.899 3.2945
+W4 77.699 80.782 67.995
+X4 24.430 21.610 7.1800
+Y4 3.2104 3.1999 4.2513
+Z4 14.450 27.763 8.5197
+2A4 21.679 16.235 32.574
+2B4 15.737 29.267 10.078
+2C4 3.9226 4.4418 7.5674
+2D4 24.022 34.375 15.022
+A5 16.920 10.945 3.6233
+B5 32.876 32.373 51.547
+C5 23.454 37.144 7.5202
+D5 24.762 25.266 23.702
+E5 29.192 16.958 3.5359
+F5 23.640 37.186 26.447
+G5 20.387 28.842 4.7028
+H5 3.3636 4.0809 2.6833
+I5 23.272 35.820 35.198
+J5 30.642 19.573 30.103
+K5 22.753 35.416 35.064
+L5 11.209 7.8786 3.5144
+M5 17.513 29.721 30.234
+N5 2.9935 2.9559 2.2837
+O5 44.139 49.035 35.423
+P5 14.200 13.959 3.6761
+Q5 59.021 56.831 48.262
+R5 6.3401 9.2262 3.4989
+S5 45.700 49.818 40.124
+T5 9.3142 14.437 4.0636
+U5 2.3535 2.3975 1.9290
+V5 27.766 28.925 20.091
+W5 3.0887 2.9300 2.3596
+X5 8.7239 16.803 5.0276
+Y5 70.161 75.882 63.247
+Z5 11.191 11.244 16.654
+2A5 62.394 68.771 47.096
+2B5 12.640 10.459 27.333
+2C5 11.160 21.761 5.5099
+2D5 77.413 80.592 53.936
+A6 37.703 22.453 27.499
+B6 14.943 18.301 44.058
+C6 44.282 30.956 7.9185
+D6 10.440 18.144 6.5076
+E6 32.892 20.486 29.274
+F6 17.819 31.263 19.184
+G6 3.7468 3.6058 6.3752
+H6 45.907 41.132 28.818
+I6 4.4472 4.1158 9.1204
+J6 20.388 31.549 44.358
+K6 2.3970 2.4515 1.9961
+L6 14.323 24.343 14.536
+M6 2.3623 2.4293 1.9541
+N6 41.190 36.767 50.714
+O6 62.357 69.847 6.3069
+P6 10.124 10.811 31.915
+Q6 67.127 65.762 49.352
+R6 39.128 23.959 27.822
+S6 10.413 15.222 6.7952
+T6 41.195 30.074 26.292
+U6 8.4099 9.5591 6.5834
+V6 43.942 26.976 32.439
+W6 33.397 44.263 15.513
+X6 56.629 45.672 50.137
+Y6 10.198 10.583 6.9283
+Z6 42.782 29.822 40.386
+2A6 61.567 65.013 61.274
+2B6 21.335 15.115 28.916
+2C6 3.2203 3.7212 2.6005
+2D6 35.799 34.854 29.422
+A7 19.123 33.078 10.667
+B7 12.915 10.831 28.225
+C7 77.518 80.587 57.622
+D7 11.348 10.154 28.703
+E7 12.442 24.254 5.6475
+F7 15.345 13.969 34.910
+G7 52.703 61.988 5.9513
+H7 9.9056 10.888 32.881
+I7 67.471 66.483 44.705
+J7 8.8426 9.6268 8.1730
+K7 61.925 56.855 24.968
+L7 9.6349 10.726 32.427
+M7 32.435 45.157 6.1480
+N7 30.427 18.146 3.6270
+O7 16.928 17.695 11.911
+P7 56.094 48.894 4.9467
+Q7 11.934 11.778 20.573
+R7 15.285 28.434 6.3346
+S7 3.5054 4.3615 2.7830
+T7 35.099 44.589 58.771
+U7 26.155 17.005 28.079
+V7 8.9086 14.924 14.071
+W7 30.611 33.536 8.6858
+X7 79.113 81.784 66.503
+Y7 10.240 10.764 31.229
+Z7 11.976 23.218 5.4228
+2A7 9.9976 9.7574 28.929
+2B7 25.572 39.297 14.262
+2C7 66.257 69.908 5.8960
+2D7 14.893 16.603 41.626
+A8 12.100 24.359 8.4071
+B8 42.436 39.900 4.7260
+C8 20.574 15.216 20.136
+D8 12.701 25.255 8.1803
+E8 18.324 13.039 26.409
+F8 16.724 30.035 13.212
+G8 3.3200 3.1831 3.0291
+H8 20.304 33.570 24.443
+I8 2.9169 2.9009 3.0168
+J8 48.038 46.099 39.891
+K8 5.2241 8.0427 3.5985
+L8 38.619 50.368 44.407
+M8 2.3428 2.3959 1.9273
+N8 3.1956 3.3116 2.6415
+O8 10.494 10.847 8.8081
+P8 22.233 23.005 18.548
+Q8 39.317 40.778 33.056
+R8 63.147 65.480 53.862
+S8 28.252 23.514 24.400
+T8 14.520 26.909 5.4756
+U8 18.057 24.054 51.817
+V8 2.3402 2.3911 1.9209
+W8 77.838 79.255 64.883
+X8 14.232 12.342 3.5677
+Y8 31.451 43.594 39.472
+Z8 3.8429 5.0881 3.0661
+2A8 27.844 41.491 21.140
+2B8 2.4921 2.5648 2.0613
+2C8 34.635 36.777 50.964
+2D8 2.3436 2.3905 1.9440
+A9 46.811 59.109 25.406
+B9 35.695 26.905 33.928
+C9 8.0578 15.313 4.8058
+D9 70.562 68.540 46.575
+E9 10.633 11.656 33.787
+F9 54.113 43.360 23.933
+G9 7.1200 11.358 10.328
+H9 31.237 20.786 32.756
+I9 14.469 27.174 19.553
+J9 11.813 8.1727 3.4750
+K9 51.613 51.265 59.093
+L9 11.232 21.889 5.3482
+M9 2.3389 2.3932 1.9205
+N9 4.6543 4.8363 3.9004
+O9 11.973 12.444 10.082
+P9 24.548 25.410 20.720
+Q9 43.270 44.842 36.215
+R9 68.113 71.034 59.864
+S9 31.468 18.903 5.4734
+T9 3.2297 3.6435 2.9170
+U9 31.779 25.042 15.321
+V9 30.098 43.673 10.856
+W9 65.360 57.273 55.175
+X9 7.8261 15.682 5.0934
+Y9 30.151 17.603 3.5424
+Z9 14.169 10.872 25.545
+2A9 49.740 51.961 35.295
+2B9 19.293 14.167 28.533
+2C9 23.305 29.469 10.465
+2D9 22.420 16.254 30.792
+A10 7.4766 14.316 6.7672
+B10 30.693 34.185 4.8132
+C10 11.568 23.235 13.773
+D10 2.4307 2.4999 2.0171
+E10 30.140 19.949 31.751
+F10 15.810 25.353 37.521
+G10 2.4272 2.4936 1.9887
+H10 12.549 25.096 11.562
+I10 2.3402 2.3788 1.9223
+J10 13.387 24.235 23.958
+K10 25.478 22.853 4.3681
+L10 5.0366 4.2550 2.8902
+M10 2.3374 2.3915 1.9194
+N10 5.8942 6.1054 4.9143
+O10 13.462 14.013 11.428
+P10 27.055 28.014 23.007
+Q10 47.406 49.169 39.386
+R10 73.974 77.043 65.729
+S10 7.8358 8.0794 7.9176
+T10 54.395 42.563 48.165
+U10 11.113 22.841 7.7084
+V10 2.9394 3.4387 2.9247
+W10 13.284 25.973 11.867
+X10 2.4768 2.5120 2.1182
+Y10 27.102 26.481 19.829
+Z10 23.978 16.698 3.6586
+2A10 24.659 30.178 27.108
+2B10 13.618 8.1445 8.4106
+2C10 24.412 26.496 22.533
+2D10 5.2897 4.2252 10.803
+A11 15.662 9.9371 16.757
+B11 6.3528 11.756 4.1276
+C11 70.247 65.054 58.834
+D11 42.904 30.283 4.3741
+E11 33.675 37.292 27.259
+F11 7.3260 5.3398 8.4321
+G11 56.748 56.026 41.441
+H11 8.1585 8.7147 3.0001
+I11 54.512 56.195 42.466
+J11 4.9736 7.2275 6.1574
+K11 50.413 50.352 29.675
+L11 11.783 8.3671 18.993
+M11 2.4004 2.4632 1.9865
+N11 7.0502 7.2979 5.9348
+O11 15.157 15.663 12.643
+P11 30.809 31.935 26.037
+Q11 51.029 52.827 42.179
+R11 78.892 82.077 69.152
+S11 9.0391 9.3614 7.5795
+T11 54.688 46.067 27.270
+U11 7.0672 5.5203 3.1542
+V11 19.018 30.251 40.808
+W11 2.6438 2.7813 2.1741
+X11 20.294 33.254 28.954
+Y11 4.7917 4.3367 10.461
+Z11 39.678 51.335 44.730
+2A11 11.397 22.075 5.4606
+2B11 43.396 54.386 47.692
+2C11 9.0264 8.0855 4.5632
+2D11 29.263 17.239 3.6542
+A12 42.435 55.238 11.960
+B12 10.244 9.5241 28.550
+C12 25.557 39.490 11.397
+D12 9.5983 9.1448 8.3283
+E12 71.285 77.444 27.463
+F12 32.592 33.399 30.058
+G12 5.1430 4.3541 13.182
+H12 18.517 32.087 22.562
+I12 6.9977 5.1440 3.8014
+J12 69.246 76.042 17.844
+K12 10.642 7.6407 17.593
+L12 21.927 35.477 19.681
+M12 2.4287 2.4921 1.9949
+N12 7.9937 8.3172 6.7360
+O12 17.120 17.761 14.285
+P12 33.242 34.486 28.221
+Q12 55.136 57.000 45.303
+R12 84.047 87.070 71.496
+S12 46.799 45.618 34.284
+T12 6.6921 6.0185 19.773
+U12 31.583 45.365 15.646
+V12 35.975 22.808 7.0470
+W12 15.632 16.004 15.333
+X12 32.188 19.569 3.7849
+Y12 9.9981 9.6287 28.171
+Z12 14.429 27.348 6.4901
+2A12 13.822 12.446 29.936
+2B12 68.261 74.431 52.067
+2C12 2.4685 2.5621 2.0287
+2D12 28.798 30.974 45.549
+A13 14.129 10.884 26.286
+B13 21.280 29.662 4.6515
+C13 32.064 17.966 13.604
+D13 9.9611 10.733 32.277
+E13 51.845 54.927 28.181
+F13 6.3441 8.5421 15.068
+G13 68.699 71.452 46.387
+H13 10.374 10.902 29.169
+I13 26.203 23.997 4.3858
+J13 25.753 36.554 54.373
+K13 5.9068 4.9157 15.287
+L13 35.348 27.270 4.1933
+M13 2.6154 2.7053 2.1626
+N13 9.3637 9.6843 7.8391
+O13 19.359 20.106 16.147
+P13 36.624 37.957 30.671
+Q13 59.859 61.861 49.702
+R13 89.957 93.025 75.604
+S13 17.613 12.665 26.369
+T13 22.969 25.114 7.7873
+U13 13.623 8.3610 7.6135
+V13 59.661 54.433 33.140
+W13 15.045 10.609 3.4373
+X13 26.676 39.190 37.659
+Y13 16.770 18.831 3.7976
+Z13 16.243 13.004 15.620
+2A13 62.079 69.145 59.254
+2B13 9.8300 11.508 34.315
+2C13 13.378 8.4024 4.1065
+2D13 11.706 16.228 24.708
+A14 27.260 17.709 28.446
+B14 10.007 11.116 33.309
+C14 55.170 63.826 56.969
+D14 22.474 12.791 7.8220
+E14 17.833 19.340 7.6068
+F14 25.508 15.387 3.5019
+G14 28.674 42.244 25.294
+H14 20.013 14.167 27.201
+I14 2.4079 2.4331 1.9867
+J14 23.527 21.066 41.374
+K14 23.203 12.509 8.0121
+L14 48.486 42.511 43.112
+M14 8.6031 15.926 4.6200
+N14 53.107 53.884 48.977
+O14 3.9836 3.7404 6.5852
+P14 35.517 35.068 43.001
+Q14 37.782 22.314 19.042
+R14 17.467 17.105 13.104
+S14 22.370 35.508 5.9931
+T14 23.886 13.985 16.868
+U14 19.591 19.252 12.172
+V14 63.345 63.812 5.6645
+W14 12.028 10.481 3.3856
+X14 42.635 43.420 39.912
+Y14 19.856 32.192 5.1431
+Z14 15.570 17.641 12.711
+2A14 29.733 19.495 31.105
+2B14 81.209 84.285 67.959
+2C14 16.972 13.897 32.504
+2D14 20.262 27.906 7.7177
+A15 24.922 14.319 17.652
+B15 20.394 32.266 39.177
+C15 28.847 42.042 6.3345
+D15 27.579 26.553 23.681
+E15 38.874 23.290 19.357
+F15 36.703 46.352 27.027
+G15 34.061 22.803 34.531
+H15 10.113 11.921 31.879
+I15 64.423 58.008 39.281
+J15 9.4542 9.1717 6.7120
+K15 48.073 52.062 16.154
+L15 22.225 20.657 33.169
+M15 32.410 43.840 8.6168
+N15 19.932 29.141 53.896
+O15 8.2354 6.1612 3.2448
+P15 21.186 33.689 34.860
+Q15 2.8839 2.9372 2.7235
+R15 16.647 10.677 18.389
+S15 35.874 22.454 3.7685
+T15 18.024 31.495 21.231
+U15 26.027 17.635 30.172
+V15 5.7623 9.6302 3.8733
+W15 53.522 58.991 41.376
+X15 23.991 17.693 34.060
+Y15 3.5595 3.8688 2.3978
+Z15 34.055 35.265 28.241
+2A15 29.379 16.826 7.3609
+2B15 9.2107 8.5579 25.691
+2C15 25.707 18.129 3.6532
+2D15 13.875 19.568 19.948
+A16 32.441 19.582 3.7464
+B16 43.738 40.362 16.554
+C16 4.9159 8.3065 7.2559
+D16 37.197 27.832 7.4910
+E16 36.691 35.876 51.695
+F16 38.836 30.036 4.3338
+G16 17.555 13.363 28.888
+H16 75.466 77.836 67.216
+I16 16.954 15.112 7.2992
+J16 47.072 52.200 10.669
+K16 55.962 60.759 50.287
+L16 10.165 9.7715 28.705
+M16 36.859 23.500 3.8297
+N16 29.735 43.076 29.229
+O16 7.3545 6.2503 2.9745
+P16 46.114 46.965 33.568
+Q16 6.2218 6.8107 2.7776
+R16 29.663 17.214 6.8286
+S16 8.0381 10.138 16.410
+T16 31.088 18.734 3.6263
+U16 18.911 32.215 23.899
+V16 26.145 16.883 27.363
+W16 33.705 20.761 3.7986
+X16 14.361 27.487 7.1744
+Y16 29.882 22.982 39.138
+Z16 2.4233 2.4412 1.9648
+2A16 42.519 39.188 21.270
+2B16 5.2349 4.4461 13.823
+2C16 32.492 19.465 7.0806
+2D16 33.454 46.863 22.481
+A17 18.355 31.722 19.048
+B17 4.8626 4.2833 10.526
+C17 39.631 36.092 16.781
+D17 3.8471 5.8319 4.8962
+E17 43.491 44.349 22.904
+F17 35.028 21.444 3.8305
+G17 23.826 20.302 40.464
+H17 44.211 56.679 16.435
+I17 6.5115 6.2807 3.6004
+J17 35.464 48.530 31.500
+K17 31.217 18.833 4.2081
+L17 6.1796 5.0138 3.0160
+M17 21.355 33.511 36.981
+N17 31.382 17.339 13.539
+O17 20.515 20.076 24.934
+P17 32.143 19.447 3.7592
+Q17 60.501 50.532 52.708
+R17 12.657 24.420 5.6873
+S17 3.4355 3.1639 2.5372
+T17 28.192 29.771 51.322
+U17 52.660 42.651 15.019
+V17 69.823 71.393 63.731
+W17 44.995 50.413 5.2421
+X17 37.401 38.967 26.702
+Y17 8.0339 5.5483 9.9052
+Z17 10.382 21.829 11.599
+2A17 34.325 21.131 7.2263
+2B17 9.1863 9.9839 3.1512
+2C17 75.534 73.388 61.922
+2D17 19.258 14.916 29.290
+A18 74.089 78.770 59.424
+B18 42.903 30.204 40.715
+C18 8.7363 10.837 6.0872
+D18 75.509 74.636 56.066
+E18 10.413 9.8011 28.727
+F18 11.836 22.861 5.4226
+G18 26.954 18.177 29.358
+H18 16.220 29.699 13.154
+I18 2.3647 2.3980 1.9090
+J18 77.786 81.283 65.463
+K18 14.363 11.898 6.7644
+L18 60.378 57.128 5.2726
+M18 30.554 20.123 31.743
+N18 24.748 27.645 20.451
+O18 44.929 31.003 12.389
+P18 11.881 10.425 27.990
+Q18 25.737 39.690 14.823
+R18 52.300 42.856 4.6545
+S18 7.2126 14.429 7.1944
+T18 77.679 78.425 65.193
+U18 47.084 32.209 22.319
+V18 6.6683 11.848 10.189
+W18 65.207 70.970 60.729
+X18 6.2806 11.330 4.1095
+Y18 60.571 56.044 16.070
+Z18 15.673 16.045 40.153
+2A18 41.178 25.901 19.845
+2B18 13.693 16.674 24.407
+2C18 74.223 78.952 41.733
+2D18 38.135 24.817 4.1395
+A19 39.239 29.094 15.479
+B19 4.7416 7.0454 3.4644
+C19 49.395 43.657 28.522
+D19 42.332 52.372 5.7052
+E19 24.242 22.424 14.026
+F19 2.4551 2.5226 2.0256
+G19 16.677 25.667 25.825
+H19 13.124 8.8453 3.5763
+I19 28.527 37.076 34.358
+J19 22.891 16.490 6.9749
+K19 22.666 35.279 35.631
+L19 5.4212 4.5484 2.9627
+M19 11.199 21.925 5.4425
+N19 22.708 12.897 3.6335
+O19 12.507 23.738 22.498
+P19 2.3442 2.3896 1.9267
+Q19 30.303 17.749 3.5777
+R19 10.104 9.7374 28.448
+S19 13.901 26.685 6.3873
+T19 2.4391 2.4780 2.0610
+U19 45.972 49.473 57.247
+V19 4.8275 8.3485 3.9886
+W19 63.154 70.855 7.5811
+X19 14.863 14.166 8.5770
+Y19 74.340 78.986 66.286
+Z19 49.996 33.344 36.894
+2A19 10.165 11.287 33.081
+2B19 62.642 69.515 6.2139
+2C19 38.429 24.741 7.3479
+2D19 12.944 12.283 32.608
+
+A1 106.60 73.896 140.50
+B1 101.22 157.76 91.298
+C1 56.474 54.712 116.20
+D1 142.23 143.96 106.67
+E1 161.58 92.303 143.82
+F1 90.405 96.497 94.153
+G1 163.39 98.124 88.178
+H1 63.278 55.370 115.21
+I1 71.385 133.64 49.363
+J1 97.757 75.383 143.28
+K1 194.49 193.52 200.39
+L1 43.729 37.037 36.612
+M1 128.36 143.53 178.51
+N1 136.71 176.12 173.90
+O1 190.25 190.03 173.26
+P1 139.89 69.074 45.054
+Q1 34.433 40.188 37.667
+R1 87.362 153.04 89.833
+S1 124.79 84.048 151.84
+T1 201.42 206.76 79.283
+U1 59.875 104.70 93.370
+V1 205.39 208.60 159.63
+W1 91.572 136.12 167.03
+X1 30.336 29.306 28.957
+Y1 132.60 110.17 107.91
+Z1 32.956 33.215 31.185
+2A1 70.282 129.32 46.946
+2B1 159.00 173.65 202.91
+2C1 121.19 88.150 161.84
+2D1 136.59 101.50 125.83
+A2 75.414 80.525 150.43
+B2 128.64 63.027 42.872
+C2 101.62 116.40 166.26
+D2 129.62 78.772 146.55
+E2 164.20 144.75 82.589
+F2 96.904 110.83 179.21
+G2 157.24 84.071 46.359
+H2 84.439 70.424 140.26
+I2 81.661 147.44 58.864
+J2 35.433 35.856 32.072
+K2 150.66 144.08 140.58
+L2 158.35 93.379 154.74
+M2 100.38 93.492 99.897
+N2 158.93 93.968 95.921
+O2 102.60 137.21 171.09
+P2 74.932 50.703 44.902
+Q2 115.12 165.78 166.70
+R2 157.97 92.663 150.58
+S2 83.913 88.787 161.27
+T2 72.772 133.20 48.154
+U2 155.64 177.45 175.23
+V2 65.311 50.797 44.712
+W2 30.304 29.389 28.630
+X2 98.383 112.57 76.501
+Y2 196.95 176.56 81.174
+Z2 106.87 76.461 64.020
+2A2 149.29 180.57 55.756
+2B2 46.850 72.093 42.887
+2C2 126.21 86.097 104.74
+2D2 68.443 138.05 59.668
+A3 40.703 34.668 43.170
+B3 140.80 177.61 130.47
+C3 71.422 72.467 144.63
+D3 157.83 159.05 109.87
+E3 74.511 78.412 148.91
+F3 172.35 192.98 167.60
+G3 72.505 72.322 146.66
+H3 132.85 167.63 50.020
+I3 99.822 132.27 193.48
+J3 158.78 88.817 87.144
+K3 146.32 156.61 192.38
+L3 30.978 30.641 29.826
+M3 146.27 153.30 150.57
+N3 144.16 70.919 46.534
+O3 85.091 72.947 144.27
+P3 122.91 131.12 67.881
+Q3 140.27 116.77 178.48
+R3 73.020 103.31 46.082
+S3 148.58 74.828 46.145
+T3 92.676 106.61 179.17
+U3 89.067 149.36 56.522
+V3 104.27 103.98 177.68
+W3 122.27 64.970 44.965
+X3 190.80 157.08 167.65
+Y3 55.033 94.759 44.077
+Z3 157.08 85.576 87.558
+2A3 79.250 88.578 159.52
+2B3 108.15 127.71 55.172
+2C3 78.102 75.847 150.05
+2D3 202.83 194.20 199.16
+A4 105.09 86.729 157.14
+B4 99.696 102.26 43.923
+C4 107.26 130.81 190.72
+D4 178.30 141.51 75.719
+E4 86.201 111.97 176.39
+F4 192.41 193.92 143.50
+G4 161.20 95.317 155.94
+H4 74.863 77.945 149.59
+I4 207.61 208.23 184.16
+J4 70.931 101.90 131.71
+K4 147.01 94.545 162.80
+L4 81.586 103.83 104.84
+M4 141.06 69.848 45.247
+N4 90.494 151.07 150.65
+O4 55.294 41.016 63.313
+P4 111.84 140.47 103.22
+Q4 144.45 93.249 162.31
+R4 105.31 104.82 101.31
+S4 79.325 137.68 48.973
+T4 84.189 150.82 120.01
+U4 81.413 52.379 93.432
+V4 76.459 77.531 42.048
+W4 211.28 212.44 213.00
+X4 125.79 102.06 67.469
+Y4 36.736 36.340 46.306
+Z4 83.114 150.29 61.891
+2A4 117.71 90.574 160.37
+2B4 89.463 153.87 72.494
+2C4 42.498 47.832 65.570
+2D4 115.91 156.34 101.73
+A5 100.43 57.576 43.875
+B5 139.57 140.52 191.37
+C5 106.24 157.82 63.346
+D5 120.63 119.68 128.56
+E5 144.32 70.530 44.643
+F5 112.12 164.88 139.23
+G5 103.37 136.87 47.413
+H5 36.251 41.780 35.395
+I5 111.24 162.80 164.26
+J5 143.56 87.562 156.55
+K5 109.54 163.06 164.19
+L5 79.627 52.133 45.354
+M5 92.456 152.33 153.19
+N5 34.714 33.013 32.281
+O5 166.35 175.94 163.99
+P5 89.669 79.549 47.144
+Q5 191.24 182.85 188.48
+R5 51.675 70.899 41.770
+S5 170.53 177.54 173.76
+T5 63.890 93.942 45.687
+U5 30.168 29.299 28.940
+V5 133.08 133.14 122.05
+W5 36.054 32.923 33.276
+X5 61.314 111.77 45.755
+Y5 203.39 209.40 208.06
+Z5 76.353 77.670 109.77
+2A5 193.86 202.18 186.73
+2B5 84.630 73.965 145.61
+2C5 68.392 129.05 45.336
+2D5 210.46 210.49 195.89
+A6 156.79 90.614 148.03
+B6 88.481 111.82 178.46
+C6 167.90 108.82 66.983
+D6 66.578 110.85 54.360
+E6 148.31 87.735 154.80
+F6 93.611 155.13 115.73
+G6 40.190 39.280 58.763
+H6 170.89 152.59 147.19
+I6 46.469 44.545 75.326
+J6 102.48 151.18 180.03
+K6 30.872 30.164 29.516
+L6 83.294 137.00 98.315
+M6 30.722 30.150 29.446
+N6 163.74 151.67 194.83
+O6 199.83 203.65 49.970
+P6 77.512 86.873 159.07
+Q6 200.99 194.31 190.45
+R6 165.39 100.99 154.68
+S6 69.496 98.026 61.986
+T6 167.68 124.93 146.98
+U6 62.706 68.483 60.211
+V6 174.63 108.06 166.14
+W6 138.60 174.02 106.27
+X6 192.12 161.59 197.05
+Y6 71.207 70.503 63.173
+Z6 171.42 121.85 182.26
+2A6 193.77 197.98 207.14
+2B6 117.80 82.965 151.94
+2C6 36.305 39.517 34.462
+2D6 152.48 145.44 148.89
+A7 93.637 153.35 73.710
+B7 83.277 73.755 144.52
+C7 206.85 206.70 197.33
+D7 77.454 73.349 146.72
+E7 70.809 132.64 47.023
+F7 91.049 88.345 163.10
+G7 177.87 190.87 53.018
+H7 75.960 87.720 159.98
+I7 199.48 192.77 181.55
+J7 64.713 68.090 67.610
+K7 193.08 175.48 139.54
+L7 75.430 87.876 159.79
+M7 133.24 173.17 56.742
+N7 148.49 75.098 46.216
+O7 97.134 97.177 86.559
+P7 191.20 160.30 54.685
+Q7 80.068 80.251 125.32
+R7 83.368 147.19 55.358
+S7 37.747 44.719 36.907
+T7 146.52 175.26 205.50
+U7 133.97 82.941 152.98
+V7 63.182 103.22 97.125
+W7 144.22 147.07 76.384
+X7 212.78 213.19 211.89
+Y7 77.896 86.298 158.37
+Z7 71.313 133.52 47.389
+2A7 75.926 78.650 151.98
+2B7 118.08 168.98 98.781
+2C7 207.34 198.34 43.623
+2D7 92.639 108.26 179.66
+A8 69.904 137.36 58.325
+B8 167.09 144.55 49.599
+C8 111.10 78.672 121.83
+D8 74.340 141.34 56.829
+E8 104.13 74.055 141.65
+F8 90.075 154.61 90.911
+G8 36.341 33.896 36.868
+H8 101.65 159.66 134.07
+I8 34.216 33.499 37.712
+J8 174.41 165.56 173.38
+K8 46.252 66.300 42.397
+L8 152.69 184.12 182.69
+M8 30.240 29.863 28.939
+N8 35.593 35.467 34.190
+O8 71.728 71.553 70.937
+P8 115.92 116.10 114.68
+Q8 159.85 160.38 159.13
+R8 196.60 197.21 197.12
+S8 137.57 112.53 140.33
+T8 80.940 142.13 50.952
+U8 99.365 133.93 196.43
+V8 30.957 30.566 29.813
+W8 212.09 210.69 210.55
+X8 90.920 71.799 46.751
+Y8 137.72 177.30 175.40
+Z8 39.524 49.911 38.685
+2A8 130.39 176.13 127.05
+2B8 31.904 31.437 30.690
+2C8 149.77 158.18 196.00
+2D8 30.719 29.824 29.600
+A9 160.64 188.72 135.75
+B9 151.09 113.48 161.82
+C9 56.378 101.12 44.028
+D9 200.86 192.61 183.06
+E9 77.639 89.149 161.20
+F9 183.43 148.52 132.23
+G9 53.868 83.869 77.703
+H9 144.68 93.693 163.06
+I9 80.625 147.05 117.46
+J9 82.612 53.093 45.342
+K9 179.05 178.11 205.03
+L9 68.256 128.21 45.397
+M9 30.122 29.559 28.786
+N9 44.132 44.030 43.113
+O9 77.603 77.496 77.212
+P9 123.38 123.35 123.35
+Q9 167.61 168.12 167.11
+R9 202.61 204.17 205.53
+S9 152.34 81.269 59.657
+T9 36.525 39.233 37.120
+U9 147.79 112.59 105.57
+V9 128.85 175.42 85.449
+W9 202.12 182.11 203.04
+X9 58.841 111.22 46.014
+Y9 150.27 74.574 46.780
+Z9 91.373 72.814 142.15
+2A9 178.42 178.87 165.68
+2B9 110.21 82.066 150.83
+2C9 115.57 141.00 82.227
+2D9 120.44 87.308 156.62
+A10 54.278 98.104 59.100
+B10 141.49 142.92 50.130
+C10 69.545 135.98 93.417
+D10 30.772 30.009 29.471
+E10 140.52 89.479 159.03
+F10 88.149 135.62 165.23
+G10 30.508 30.075 29.389
+H10 75.794 144.13 86.030
+I10 29.881 29.286 28.915
+J10 78.427 139.08 135.09
+K10 127.69 103.24 52.122
+L10 47.518 38.484 37.887
+M10 30.202 29.466 28.978
+N10 50.671 50.438 49.901
+O10 84.087 84.218 84.130
+P10 130.92 131.27 131.19
+Q10 174.24 174.94 173.31
+R10 208.46 209.75 212.17
+S10 61.440 61.759 68.112
+T10 189.59 154.63 195.61
+U10 70.065 139.76 58.155
+V10 34.382 38.877 37.374
+W10 81.185 148.91 88.683
+X10 31.337 30.706 30.647
+Y10 132.10 124.54 122.36
+Z10 128.86 77.259 44.848
+2A10 121.07 144.71 145.24
+2B10 91.404 54.498 76.524
+2C10 122.45 129.19 129.52
+2D10 52.091 43.712 85.349
+A11 95.121 56.945 109.13
+B11 49.247 84.978 41.595
+C11 201.38 188.28 201.57
+D11 165.99 106.71 48.883
+E11 142.45 151.87 140.77
+F11 59.895 43.373 70.686
+G11 185.60 179.80 175.52
+H11 62.810 62.001 39.464
+I11 182.38 181.99 177.01
+J11 44.613 62.579 56.523
+K11 177.26 171.26 154.02
+L11 81.706 58.921 119.57
+M11 30.648 29.769 29.464
+N11 56.534 56.324 55.689
+O11 89.911 89.936 88.980
+P11 140.77 141.41 140.88
+Q11 179.84 180.21 178.58
+R11 212.60 213.84 215.53
+S11 66.493 66.184 65.558
+T11 187.32 160.61 146.99
+U11 59.842 44.929 41.517
+V11 100.71 151.70 177.40
+W11 32.433 32.983 31.555
+X11 103.41 161.56 150.03
+Y11 49.930 46.756 84.028
+Z11 157.24 187.57 185.20
+2A11 69.840 130.51 46.639
+2B11 164.73 190.77 189.92
+2C11 67.660 57.565 50.639
+2D11 146.88 73.255 46.894
+A12 149.18 183.06 84.464
+B12 72.446 71.794 146.17
+C12 111.58 163.80 82.344
+D12 67.115 62.023 67.669
+E12 202.25 206.59 144.16
+F12 142.52 142.52 149.46
+G12 52.218 46.843 96.005
+H12 95.301 157.62 128.66
+I12 58.804 42.199 45.333
+J12 201.67 207.01 112.57
+K12 76.878 56.433 113.86
+L12 110.43 164.87 121.89
+M12 31.073 30.502 29.828
+N12 60.863 60.999 60.221
+O12 97.436 97.414 96.425
+P12 146.96 147.76 147.68
+Q12 186.04 186.49 184.52
+R12 217.03 217.69 217.80
+S12 173.81 166.67 164.48
+T12 61.998 59.133 126.43
+U12 133.08 178.53 107.01
+V12 159.59 92.307 67.569
+W12 92.823 93.091 102.67
+X12 153.31 79.910 48.385
+Y12 76.169 77.765 152.48
+Z12 80.867 145.82 55.209
+2A12 88.726 84.091 155.13
+2B12 201.37 208.14 195.53
+2C12 32.004 31.705 30.813
+2D12 135.53 145.08 187.78
+A13 86.415 69.301 138.07
+B13 104.58 136.42 46.559
+C13 147.82 79.114 100.32
+D13 75.334 85.157 157.26
+E13 178.81 179.96 148.24
+F13 55.482 72.327 100.16
+G13 200.09 199.75 184.43
+H13 76.688 84.710 151.41
+I13 129.73 107.35 52.022
+J13 119.03 160.66 198.42
+K13 56.473 50.032 106.16
+L13 153.18 106.56 46.936
+M13 32.264 31.978 31.289
+N13 66.470 66.520 66.246
+O13 105.28 105.86 104.76
+P13 153.75 154.63 154.12
+Q13 192.03 192.25 191.27
+R13 221.68 221.89 221.96
+S13 104.20 75.856 145.33
+T13 121.87 124.18 72.370
+U13 91.392 55.886 72.021
+V13 193.01 176.53 161.70
+W13 97.047 61.496 44.638
+X13 124.18 171.27 172.48
+Y13 100.95 103.55 45.932
+Z13 98.719 76.722 108.03
+2A13 193.99 204.68 205.71
+2B13 77.619 94.368 167.50
+2C13 91.512 53.191 50.701
+2D13 76.609 104.98 135.45
+A14 129.84 79.131 147.61
+B14 74.731 86.884 158.53
+C14 178.45 194.65 198.02
+D14 122.80 65.789 71.805
+E14 99.529 101.15 66.691
+F14 133.73 68.160 43.803
+G14 130.31 174.28 137.87
+H14 110.49 77.413 145.63
+I14 30.999 29.764 29.587
+J14 120.14 114.13 178.99
+K14 128.29 64.544 74.117
+L14 176.70 157.34 183.40
+M14 59.777 105.00 45.141
+N14 182.00 181.11 190.30
+O14 42.651 40.749 62.042
+P14 151.32 150.31 182.91
+Q14 162.51 94.932 125.82
+R14 99.745 94.301 93.467
+S14 107.25 159.78 58.090
+T14 128.01 72.369 117.84
+U14 107.76 101.18 90.766
+V14 204.14 190.16 48.644
+W14 82.597 65.626 44.970
+X14 166.39 166.20 175.82
+Y14 100.69 152.17 51.384
+Z14 91.650 100.20 90.746
+2A14 143.62 91.243 162.04
+2B14 214.71 215.34 214.31
+2C14 101.32 87.875 161.74
+2D14 105.18 138.75 68.497
+A15 124.84 68.758 114.78
+B15 99.929 150.22 167.53
+C15 121.25 165.78 57.133
+D15 129.49 121.04 130.58
+E15 161.27 95.254 123.97
+F15 148.20 174.03 142.22
+G15 150.41 98.923 167.42
+H15 75.180 91.615 158.04
+I15 196.22 179.25 172.32
+J15 66.558 62.105 60.696
+K15 174.25 177.65 112.40
+L15 116.33 112.29 162.02
+M15 133.68 171.46 73.038
+N15 102.47 146.49 198.15
+O15 64.715 46.574 43.032
+P15 105.91 159.08 164.78
+Q15 34.379 33.754 36.003
+R15 102.62 61.271 119.89
+S15 159.62 86.224 48.021
+T15 95.611 158.57 127.45
+U15 133.03 87.140 157.87
+V15 48.894 77.368 43.484
+W15 182.54 191.20 178.40
+X15 126.00 95.308 166.74
+Y15 38.376 39.986 33.590
+Z15 148.30 148.94 147.37
+2A15 146.55 75.055 68.429
+2B15 71.706 70.645 144.63
+2C15 133.02 80.816 44.452
+2D15 82.777 113.54 117.52
+A16 147.43 75.104 45.417
+B16 162.22 145.05 108.87
+C16 43.273 69.681 61.261
+D16 154.15 106.72 65.606
+E16 149.19 148.83 193.98
+F16 157.80 111.38 47.573
+G16 100.61 79.449 149.13
+H16 206.92 207.61 211.44
+I16 97.895 82.272 66.348
+J16 172.80 178.46 82.595
+K16 183.90 191.17 190.75
+L16 75.048 76.021 151.02
+M16 159.42 88.282 47.938
+N16 133.24 176.09 150.50
+O16 59.749 48.251 40.198
+P16 171.06 168.69 161.58
+Q16 53.260 54.841 37.700
+R16 147.03 76.735 66.424
+S16 63.206 78.809 107.93
+T16 150.22 77.352 47.226
+U16 97.824 159.49 134.64
+V16 133.39 81.567 151.23
+W16 155.32 82.024 48.477
+X16 81.301 147.86 56.013
+Y16 141.53 112.75 178.08
+Z16 31.556 30.196 30.075
+2A16 166.04 149.78 129.15
+2B16 53.939 48.402 100.70
+2C16 152.96 83.435 68.500
+2D16 141.97 181.00 131.63
+A17 93.002 152.57 112.99
+B17 48.562 44.595 81.595
+C17 155.24 137.12 108.13
+D17 37.723 54.820 48.270
+E17 163.04 158.68 133.73
+F17 155.10 81.151 47.477
+G17 119.76 108.26 175.73
+H17 155.83 188.69 108.40
+I17 54.125 49.417 43.252
+J17 146.89 182.65 155.76
+K17 148.71 77.345 50.119
+L17 53.925 41.854 39.291
+M17 105.46 156.83 167.45
+N17 149.16 79.222 103.08
+O17 109.98 107.89 138.78
+P17 151.99 78.765 47.620
+Q17 195.13 169.06 200.08
+R17 73.599 136.55 49.271
+S17 37.757 33.718 34.938
+T17 132.61 142.77 197.68
+U17 181.82 145.93 103.48
+V17 204.10 203.91 210.35
+W17 175.82 179.36 52.229
+X17 155.69 156.50 143.88
+Y17 65.731 44.495 80.654
+Z17 67.930 138.21 88.916
+2A17 156.40 87.866 68.881
+2B17 68.870 68.990 41.254
+2C17 209.60 202.66 207.60
+2D17 108.97 87.062 152.98
+A18 200.70 204.40 197.90
+B18 164.93 117.44 177.68
+C18 61.227 72.827 56.013
+D18 204.51 199.19 195.95
+E18 73.692 73.322 148.06
+F18 68.313 128.24 45.392
+G18 131.14 85.288 152.52
+H18 89.609 153.68 93.128
+I18 30.179 29.676 28.922
+J18 208.65 210.69 209.48
+K18 88.863 70.346 63.498
+L18 197.92 177.16 54.602
+M18 143.55 91.470 162.00
+N18 121.99 131.52 122.44
+O18 172.04 115.00 91.328
+P18 81.187 74.923 148.64
+Q18 117.91 169.48 101.12
+R18 183.93 145.62 52.297
+S18 55.452 105.38 65.438
+T18 211.11 208.92 210.90
+U18 177.41 124.39 134.00
+V18 53.506 90.891 78.889
+W18 197.65 205.13 206.81
+X18 51.396 86.860 43.674
+Y18 193.58 175.18 113.92
+Z18 96.313 103.94 178.60
+2A18 168.53 106.08 128.73
+2B18 85.496 104.15 136.89
+2C18 208.09 210.26 179.31
+2D18 161.94 92.492 50.116
+A19 156.71 112.54 101.12
+B19 42.513 58.501 40.536
+C19 172.17 152.13 143.40
+D19 159.73 183.13 54.703
+E19 119.21 105.48 95.518
+F19 30.235 29.764 29.269
+G19 88.689 134.99 136.69
+H19 86.392 53.901 45.566
+I19 126.88 158.15 160.78
+J19 120.42 79.125 64.241
+K19 108.34 160.80 164.56
+L19 49.327 39.952 38.592
+M19 67.917 128.27 44.976
+N19 127.84 62.080 45.945
+O19 74.380 138.45 130.11
+P19 30.060 29.337 28.817
+Q19 147.97 73.539 46.480
+R19 75.153 76.608 151.15
+S19 78.339 144.41 52.936
+T19 31.312 30.556 30.767
+U19 169.32 177.98 203.35
+V19 44.471 72.376 45.634
+W19 199.02 205.39 55.979
+X19 90.125 81.954 73.039
+Y19 207.33 211.44 212.22
+Z19 182.95 126.85 175.69
+2A19 77.857 90.598 163.13
+2B19 202.16 204.23 49.052
+2C19 162.94 96.440 68.740
+2D19 83.952 84.116 160.97
+
diff --git a/scanin/CMP_Digital_Target-3.cie b/scanin/CMP_Digital_Target-3.cie
new file mode 100644
index 0000000..6c8ff5d
--- /dev/null
+++ b/scanin/CMP_Digital_Target-3.cie
@@ -0,0 +1,591 @@
+CTI3
+
+DESCRIPTOR "Argyll Calibration Target chart information 3"
+ORIGINATOR "Argyll chartread"
+CREATED "Mon Sep 7 08:33:21 2009"
+KEYWORD "DEVICE_CLASS"
+DEVICE_CLASS "OUTPUT"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB_XYZ"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth i1 Pro"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 570
+BEGIN_DATA
+1 "A1" 106.60 73.896 140.50 19.991 14.120 27.886
+2 "B1" 101.22 157.76 91.298 19.926 34.054 14.005
+3 "C1" 56.474 54.712 116.20 6.2319 5.6339 19.078
+4 "D1" 142.23 143.96 106.67 32.785 35.198 16.672
+5 "E1" 161.58 92.303 143.82 38.996 22.658 25.805
+6 "F1" 90.405 96.497 94.153 16.011 17.612 14.561
+7 "G1" 163.39 98.124 88.178 39.496 24.997 12.003
+8 "H1" 63.278 55.370 115.21 7.4905 6.2468 18.358
+9 "I1" 71.385 133.64 49.363 11.987 23.286 6.5928
+10 "J1" 97.757 75.383 143.28 16.591 12.444 27.331
+11 "K1" 194.49 193.52 200.39 63.038 64.179 58.403
+12 "L1" 43.729 37.037 36.612 4.3513 3.8393 2.7750
+13 "M1" 128.36 143.53 178.51 27.386 30.873 42.527
+14 "N1" 136.71 176.12 173.90 31.789 44.281 40.439
+15 "O1" 190.25 190.03 173.26 59.453 61.985 40.335
+16 "P1" 139.89 69.074 45.054 26.783 15.713 3.5833
+17 "Q1" 34.433 40.188 37.667 3.0238 3.6843 3.0876
+18 "R1" 87.362 153.04 89.833 15.462 28.885 12.776
+19 "S1" 124.79 84.048 151.84 23.694 16.421 29.352
+20 "T1" 201.42 206.76 79.283 65.900 73.381 11.377
+21 "U1" 59.875 104.70 93.370 8.3333 15.036 13.749
+22 "V1" 205.39 208.60 159.63 72.416 77.985 33.423
+23 "W1" 91.572 136.12 167.03 16.393 25.254 38.122
+24 "X1" 30.336 29.306 28.957 2.3144 2.3581 1.9303
+25 "Y1" 132.60 110.17 107.91 27.102 23.276 16.813
+26 "Z1" 32.956 33.215 31.185 2.6994 2.8850 2.2332
+27 "2A1" 70.282 129.32 46.946 10.757 20.588 4.8216
+28 "2B1" 159.00 173.65 202.91 40.765 45.919 58.857
+29 "2C1" 121.19 88.150 161.84 22.864 16.381 33.839
+30 "2D1" 136.59 101.50 125.83 28.289 21.404 20.483
+31 "A2" 75.414 80.525 150.43 10.412 10.567 30.978
+32 "B2" 128.64 63.027 42.872 24.139 14.085 3.5857
+33 "C2" 101.62 116.40 166.26 19.473 21.752 38.376
+34 "D2" 129.62 78.772 146.55 26.280 16.991 28.035
+35 "E2" 164.20 144.75 82.589 42.573 39.671 9.6556
+36 "F2" 96.904 110.83 179.21 17.113 18.705 43.690
+37 "G2" 157.24 84.071 46.359 35.850 22.548 3.8554
+38 "H2" 84.439 70.424 140.26 13.037 10.392 26.425
+39 "I2" 81.661 147.44 58.864 14.946 28.262 8.1825
+40 "J2" 35.433 35.856 32.072 3.1780 3.3914 2.3047
+41 "K2" 150.66 144.08 140.58 35.880 35.178 26.683
+42 "L2" 158.35 93.379 154.74 36.434 22.147 28.386
+43 "M2" 100.38 93.492 99.897 17.689 17.022 15.072
+44 "N2" 158.93 93.968 95.921 36.396 23.022 13.623
+45 "O2" 102.60 137.21 171.09 19.884 26.988 39.544
+46 "P2" 74.932 50.703 44.902 10.294 7.4271 3.4839
+47 "Q2" 115.12 165.78 166.70 24.415 37.008 36.288
+48 "R2" 157.97 92.663 150.58 36.078 21.682 26.898
+49 "S2" 83.913 88.787 161.27 12.232 12.247 33.412
+50 "T2" 72.772 133.20 48.154 12.486 23.920 5.4357
+51 "U2" 155.64 177.45 175.23 38.913 47.091 40.794
+52 "V2" 65.311 50.797 44.712 8.3779 6.8387 3.7119
+53 "W2" 30.304 29.389 28.630 2.3401 2.3804 1.9157
+54 "X2" 98.383 112.57 76.501 17.501 20.678 9.7225
+55 "Y2" 196.95 176.56 81.174 60.324 56.490 9.7029
+56 "Z2" 106.87 76.461 64.020 18.340 14.257 6.9452
+57 "2A2" 149.29 180.57 55.756 39.051 50.700 6.0515
+58 "2B2" 46.850 72.093 42.887 5.3134 8.7205 3.7883
+59 "2C2" 126.21 86.097 104.74 24.040 16.842 14.641
+60 "2D2" 68.443 138.05 59.668 10.963 22.720 8.1563
+61 "A3" 40.703 34.668 43.170 3.2215 2.8069 3.1344
+62 "B3" 140.80 177.61 130.47 35.703 49.122 24.276
+63 "C3" 71.422 72.467 144.63 9.6710 9.2674 28.141
+64 "D3" 157.83 159.05 109.87 39.368 42.329 16.693
+65 "E3" 74.511 78.412 148.91 9.8448 9.8037 29.501
+66 "F3" 172.35 192.98 167.60 50.040 60.997 38.371
+67 "G3" 72.505 72.322 146.66 9.8731 9.2375 28.216
+68 "H3" 132.85 167.63 50.020 31.926 43.409 5.2962
+69 "I3" 99.822 132.27 193.48 18.889 24.530 52.235
+70 "J3" 158.78 88.817 87.144 36.271 22.167 11.952
+71 "K3" 146.32 156.61 192.38 34.281 37.060 50.573
+72 "L3" 30.978 30.641 29.826 2.4511 2.5353 2.0398
+73 "M3" 146.27 153.30 150.57 34.120 37.136 30.510
+74 "N3" 144.16 70.919 46.534 28.309 16.461 3.7229
+75 "O3" 85.091 72.947 144.27 12.851 10.508 27.052
+76 "P3" 122.91 131.12 67.881 24.532 27.910 7.4170
+77 "Q3" 140.27 116.77 178.48 29.800 23.719 40.761
+78 "R3" 73.020 103.31 46.082 11.420 17.249 4.2060
+79 "S3" 148.58 74.828 46.145 30.098 17.923 3.6411
+80 "T3" 92.676 106.61 179.17 15.102 16.455 41.548
+81 "U3" 89.067 149.36 56.522 16.816 29.880 6.2892
+82 "V3" 104.27 103.98 177.68 19.054 17.886 40.635
+83 "W3" 122.27 64.970 44.965 21.160 13.146 3.6418
+84 "X3" 190.80 157.08 167.65 56.827 44.647 36.033
+85 "Y3" 55.033 94.759 44.077 7.3224 13.350 4.3645
+86 "Z3" 157.08 85.576 87.558 34.447 20.515 11.595
+87 "2A3" 79.250 88.578 159.52 10.795 11.448 32.464
+88 "2B3" 108.15 127.71 55.172 20.617 25.691 5.5795
+89 "2C3" 78.102 75.847 150.05 11.126 10.174 28.914
+90 "2D3" 202.83 194.20 199.16 68.724 66.102 56.410
+91 "A4" 105.09 86.729 157.14 19.671 15.554 33.919
+92 "B4" 99.696 102.26 43.923 17.501 19.753 3.8498
+93 "C4" 107.26 130.81 190.72 21.509 25.734 51.674
+94 "D4" 178.30 141.51 75.719 51.958 42.451 9.1213
+95 "E4" 86.201 111.97 176.39 14.112 17.806 42.697
+96 "F4" 192.41 193.92 143.50 61.487 65.884 27.427
+97 "G4" 161.20 95.317 155.94 38.420 23.239 29.457
+98 "H4" 74.863 77.945 149.59 9.8759 9.7311 29.126
+99 "I4" 207.61 208.23 184.16 75.793 79.718 46.695
+100 "J4" 70.931 101.90 131.71 10.595 15.480 24.653
+101 "K4" 147.01 94.545 162.80 32.187 21.331 32.814
+102 "L4" 81.586 103.83 104.84 13.777 17.753 16.663
+103 "M4" 141.06 69.848 45.247 27.339 16.027 3.5603
+104 "N4" 90.494 151.07 150.65 16.922 28.995 29.336
+105 "O4" 55.294 41.016 63.313 6.3066 4.7610 6.9921
+106 "P4" 111.84 140.47 103.22 22.390 29.210 15.592
+107 "Q4" 144.45 93.249 162.31 30.657 20.369 32.268
+108 "R4" 105.31 104.82 101.31 19.152 19.807 15.592
+109 "S4" 79.325 137.68 48.973 13.948 25.671 5.2122
+110 "T4" 84.189 150.82 120.01 14.991 27.898 19.745
+111 "U4" 81.413 52.379 93.432 11.486 7.6381 12.484
+112 "V4" 76.459 77.531 42.048 10.749 11.899 3.2945
+113 "W4" 211.28 212.44 213.00 77.699 80.782 67.995
+114 "X4" 125.79 102.06 67.469 24.430 21.610 7.1800
+115 "Y4" 36.736 36.340 46.306 3.2104 3.1999 4.2513
+116 "Z4" 83.114 150.29 61.891 14.450 27.763 8.5197
+117 "2A4" 117.71 90.574 160.37 21.679 16.235 32.574
+118 "2B4" 89.463 153.87 72.494 15.737 29.267 10.078
+119 "2C4" 42.498 47.832 65.570 3.9226 4.4418 7.5674
+120 "2D4" 115.91 156.34 101.73 24.022 34.375 15.022
+121 "A5" 100.43 57.576 43.875 16.920 10.945 3.6233
+122 "B5" 139.57 140.52 191.37 32.876 32.373 51.547
+123 "C5" 106.24 157.82 63.346 23.454 37.144 7.5202
+124 "D5" 120.63 119.68 128.56 24.762 25.266 23.702
+125 "E5" 144.32 70.530 44.643 29.192 16.958 3.5359
+126 "F5" 112.12 164.88 139.23 23.640 37.186 26.447
+127 "G5" 103.37 136.87 47.413 20.387 28.842 4.7028
+128 "H5" 36.251 41.780 35.395 3.3636 4.0809 2.6833
+129 "I5" 111.24 162.80 164.26 23.272 35.820 35.198
+130 "J5" 143.56 87.562 156.55 30.642 19.573 30.103
+131 "K5" 109.54 163.06 164.19 22.753 35.416 35.064
+132 "L5" 79.627 52.133 45.354 11.209 7.8786 3.5144
+133 "M5" 92.456 152.33 153.19 17.513 29.721 30.234
+134 "N5" 34.714 33.013 32.281 2.9935 2.9559 2.2837
+135 "O5" 166.35 175.94 163.99 44.139 49.035 35.423
+136 "P5" 89.669 79.549 47.144 14.200 13.959 3.6761
+137 "Q5" 191.24 182.85 188.48 59.021 56.831 48.262
+138 "R5" 51.675 70.899 41.770 6.3401 9.2262 3.4989
+139 "S5" 170.53 177.54 173.76 45.700 49.818 40.124
+140 "T5" 63.890 93.942 45.687 9.3142 14.437 4.0636
+141 "U5" 30.168 29.299 28.940 2.3535 2.3975 1.9290
+142 "V5" 133.08 133.14 122.05 27.766 28.925 20.091
+143 "W5" 36.054 32.923 33.276 3.0887 2.9300 2.3596
+144 "X5" 61.314 111.77 45.755 8.7239 16.803 5.0276
+145 "Y5" 203.39 209.40 208.06 70.161 75.882 63.247
+146 "Z5" 76.353 77.670 109.77 11.191 11.244 16.654
+147 "2A5" 193.86 202.18 186.73 62.394 68.771 47.096
+148 "2B5" 84.630 73.965 145.61 12.640 10.459 27.333
+149 "2C5" 68.392 129.05 45.336 11.160 21.761 5.5099
+150 "2D5" 210.46 210.49 195.89 77.413 80.592 53.936
+151 "A6" 156.79 90.614 148.03 37.703 22.453 27.499
+152 "B6" 88.481 111.82 178.46 14.943 18.301 44.058
+153 "C6" 167.90 108.82 66.983 44.282 30.956 7.9185
+154 "D6" 66.578 110.85 54.360 10.440 18.144 6.5076
+155 "E6" 148.31 87.735 154.80 32.892 20.486 29.274
+156 "F6" 93.611 155.13 115.73 17.819 31.263 19.184
+157 "G6" 40.190 39.280 58.763 3.7468 3.6058 6.3752
+158 "H6" 170.89 152.59 147.19 45.907 41.132 28.818
+159 "I6" 46.469 44.545 75.326 4.4472 4.1158 9.1204
+160 "J6" 102.48 151.18 180.03 20.388 31.549 44.358
+161 "K6" 30.872 30.164 29.516 2.3970 2.4515 1.9961
+162 "L6" 83.294 137.00 98.315 14.323 24.343 14.536
+163 "M6" 30.722 30.150 29.446 2.3623 2.4293 1.9541
+164 "N6" 163.74 151.67 194.83 41.190 36.767 50.714
+165 "O6" 199.83 203.65 49.970 62.357 69.847 6.3069
+166 "P6" 77.512 86.873 159.07 10.124 10.811 31.915
+167 "Q6" 200.99 194.31 190.45 67.127 65.762 49.352
+168 "R6" 165.39 100.99 154.68 39.128 23.959 27.822
+169 "S6" 69.496 98.026 61.986 10.413 15.222 6.7952
+170 "T6" 167.68 124.93 146.98 41.195 30.074 26.292
+171 "U6" 62.706 68.483 60.211 8.4099 9.5591 6.5834
+172 "V6" 174.63 108.06 166.14 43.942 26.976 32.439
+173 "W6" 138.60 174.02 106.27 33.397 44.263 15.513
+174 "X6" 192.12 161.59 197.05 56.629 45.672 50.137
+175 "Y6" 71.207 70.503 63.173 10.198 10.583 6.9283
+176 "Z6" 171.42 121.85 182.26 42.782 29.822 40.386
+177 "2A6" 193.77 197.98 207.14 61.567 65.013 61.274
+178 "2B6" 117.80 82.965 151.94 21.335 15.115 28.916
+179 "2C6" 36.305 39.517 34.462 3.2203 3.7212 2.6005
+180 "2D6" 152.48 145.44 148.89 35.799 34.854 29.422
+181 "A7" 93.637 153.35 73.710 19.123 33.078 10.667
+182 "B7" 83.277 73.755 144.52 12.915 10.831 28.225
+183 "C7" 206.85 206.70 197.33 77.518 80.587 57.622
+184 "D7" 77.454 73.349 146.72 11.348 10.154 28.703
+185 "E7" 70.809 132.64 47.023 12.442 24.254 5.6475
+186 "F7" 91.049 88.345 163.10 15.345 13.969 34.910
+187 "G7" 177.87 190.87 53.018 52.703 61.988 5.9513
+188 "H7" 75.960 87.720 159.98 9.9056 10.888 32.881
+189 "I7" 199.48 192.77 181.55 67.471 66.483 44.705
+190 "J7" 64.713 68.090 67.610 8.8426 9.6268 8.1730
+191 "K7" 193.08 175.48 139.54 61.925 56.855 24.968
+192 "L7" 75.430 87.876 159.79 9.6349 10.726 32.427
+193 "M7" 133.24 173.17 56.742 32.435 45.157 6.1480
+194 "N7" 148.49 75.098 46.216 30.427 18.146 3.6270
+195 "O7" 97.134 97.177 86.559 16.928 17.695 11.911
+196 "P7" 191.20 160.30 54.685 56.094 48.894 4.9467
+197 "Q7" 80.068 80.251 125.32 11.934 11.778 20.573
+198 "R7" 83.368 147.19 55.358 15.285 28.434 6.3346
+199 "S7" 37.747 44.719 36.907 3.5054 4.3615 2.7830
+200 "T7" 146.52 175.26 205.50 35.099 44.589 58.771
+201 "U7" 133.97 82.941 152.98 26.155 17.005 28.079
+202 "V7" 63.182 103.22 97.125 8.9086 14.924 14.071
+203 "W7" 144.22 147.07 76.384 30.611 33.536 8.6858
+204 "X7" 212.78 213.19 211.89 79.113 81.784 66.503
+205 "Y7" 77.896 86.298 158.37 10.240 10.764 31.229
+206 "Z7" 71.313 133.52 47.389 11.976 23.218 5.4228
+207 "2A7" 75.926 78.650 151.98 9.9976 9.7574 28.929
+208 "2B7" 118.08 168.98 98.781 25.572 39.297 14.262
+209 "2C7" 207.34 198.34 43.623 66.257 69.908 5.8960
+210 "2D7" 92.639 108.26 179.66 14.893 16.603 41.626
+211 "A8" 69.904 137.36 58.325 12.100 24.359 8.4071
+212 "B8" 167.09 144.55 49.599 42.436 39.900 4.7260
+213 "C8" 111.10 78.672 121.83 20.574 15.216 20.136
+214 "D8" 74.340 141.34 56.829 12.701 25.255 8.1803
+215 "E8" 104.13 74.055 141.65 18.324 13.039 26.409
+216 "F8" 90.075 154.61 90.911 16.724 30.035 13.212
+217 "G8" 36.341 33.896 36.868 3.3200 3.1831 3.0291
+218 "H8" 101.65 159.66 134.07 20.304 33.570 24.443
+219 "I8" 34.216 33.499 37.712 2.9169 2.9009 3.0168
+220 "J8" 174.41 165.56 173.38 48.038 46.099 39.891
+221 "K8" 46.252 66.300 42.397 5.2241 8.0427 3.5985
+222 "L8" 152.69 184.12 182.69 38.619 50.368 44.407
+223 "M8" 30.240 29.863 28.939 2.3428 2.3959 1.9273
+224 "N8" 35.593 35.467 34.190 3.1956 3.3116 2.6415
+225 "O8" 71.728 71.553 70.937 10.494 10.847 8.8081
+226 "P8" 115.92 116.10 114.68 22.233 23.005 18.548
+227 "Q8" 159.85 160.38 159.13 39.317 40.778 33.056
+228 "R8" 196.60 197.21 197.12 63.147 65.480 53.862
+229 "S8" 137.57 112.53 140.33 28.252 23.514 24.400
+230 "T8" 80.940 142.13 50.952 14.520 26.909 5.4756
+231 "U8" 99.365 133.93 196.43 18.057 24.054 51.817
+232 "V8" 30.957 30.566 29.813 2.3402 2.3911 1.9209
+233 "W8" 212.09 210.69 210.55 77.838 79.255 64.883
+234 "X8" 90.920 71.799 46.751 14.232 12.342 3.5677
+235 "Y8" 137.72 177.30 175.40 31.451 43.594 39.472
+236 "Z8" 39.524 49.911 38.685 3.8429 5.0881 3.0661
+237 "2A8" 130.39 176.13 127.05 27.844 41.491 21.140
+238 "2B8" 31.904 31.437 30.690 2.4921 2.5648 2.0613
+239 "2C8" 149.77 158.18 196.00 34.635 36.777 50.964
+240 "2D8" 30.719 29.824 29.600 2.3436 2.3905 1.9440
+241 "A9" 160.64 188.72 135.75 46.811 59.109 25.406
+242 "B9" 151.09 113.48 161.82 35.695 26.905 33.928
+243 "C9" 56.378 101.12 44.028 8.0578 15.313 4.8058
+244 "D9" 200.86 192.61 183.06 70.562 68.540 46.575
+245 "E9" 77.639 89.149 161.20 10.633 11.656 33.787
+246 "F9" 183.43 148.52 132.23 54.113 43.360 23.933
+247 "G9" 53.868 83.869 77.703 7.1200 11.358 10.328
+248 "H9" 144.68 93.693 163.06 31.237 20.786 32.756
+249 "I9" 80.625 147.05 117.46 14.469 27.174 19.553
+250 "J9" 82.612 53.093 45.342 11.813 8.1727 3.4750
+251 "K9" 179.05 178.11 205.03 51.613 51.265 59.093
+252 "L9" 68.256 128.21 45.397 11.232 21.889 5.3482
+253 "M9" 30.122 29.559 28.786 2.3389 2.3932 1.9205
+254 "N9" 44.132 44.030 43.113 4.6543 4.8363 3.9004
+255 "O9" 77.603 77.496 77.212 11.973 12.444 10.082
+256 "P9" 123.38 123.35 123.35 24.548 25.410 20.720
+257 "Q9" 167.61 168.12 167.11 43.270 44.842 36.215
+258 "R9" 202.61 204.17 205.53 68.113 71.034 59.864
+259 "S9" 152.34 81.269 59.657 31.468 18.903 5.4734
+260 "T9" 36.525 39.233 37.120 3.2297 3.6435 2.9170
+261 "U9" 147.79 112.59 105.57 31.779 25.042 15.321
+262 "V9" 128.85 175.42 85.449 30.098 43.673 10.856
+263 "W9" 202.12 182.11 203.04 65.360 57.273 55.175
+264 "X9" 58.841 111.22 46.014 7.8261 15.682 5.0934
+265 "Y9" 150.27 74.574 46.780 30.151 17.603 3.5424
+266 "Z9" 91.373 72.814 142.15 14.169 10.872 25.545
+267 "2A9" 178.42 178.87 165.68 49.740 51.961 35.295
+268 "2B9" 110.21 82.066 150.83 19.293 14.167 28.533
+269 "2C9" 115.57 141.00 82.227 23.305 29.469 10.465
+270 "2D9" 120.44 87.308 156.62 22.420 16.254 30.792
+271 "A10" 54.278 98.104 59.100 7.4766 14.316 6.7672
+272 "B10" 141.49 142.92 50.130 30.693 34.185 4.8132
+273 "C10" 69.545 135.98 93.417 11.568 23.235 13.773
+274 "D10" 30.772 30.009 29.471 2.4307 2.4999 2.0171
+275 "E10" 140.52 89.479 159.03 30.140 19.949 31.751
+276 "F10" 88.149 135.62 165.23 15.810 25.353 37.521
+277 "G10" 30.508 30.075 29.389 2.4272 2.4936 1.9887
+278 "H10" 75.794 144.13 86.030 12.549 25.096 11.562
+279 "I10" 29.881 29.286 28.915 2.3402 2.3788 1.9223
+280 "J10" 78.427 139.08 135.09 13.387 24.235 23.958
+281 "K10" 127.69 103.24 52.122 25.478 22.853 4.3681
+282 "L10" 47.518 38.484 37.887 5.0366 4.2550 2.8902
+283 "M10" 30.202 29.466 28.978 2.3374 2.3915 1.9194
+284 "N10" 50.671 50.438 49.901 5.8942 6.1054 4.9143
+285 "O10" 84.087 84.218 84.130 13.462 14.013 11.428
+286 "P10" 130.92 131.27 131.19 27.055 28.014 23.007
+287 "Q10" 174.24 174.94 173.31 47.406 49.169 39.386
+288 "R10" 208.46 209.75 212.17 73.974 77.043 65.729
+289 "S10" 61.440 61.759 68.112 7.8358 8.0794 7.9176
+290 "T10" 189.59 154.63 195.61 54.395 42.563 48.165
+291 "U10" 70.065 139.76 58.155 11.113 22.841 7.7084
+292 "V10" 34.382 38.877 37.374 2.9394 3.4387 2.9247
+293 "W10" 81.185 148.91 88.683 13.284 25.973 11.867
+294 "X10" 31.337 30.706 30.647 2.4768 2.5120 2.1182
+295 "Y10" 132.10 124.54 122.36 27.102 26.481 19.829
+296 "Z10" 128.86 77.259 44.848 23.978 16.698 3.6586
+297 "2A10" 121.07 144.71 145.24 24.659 30.178 27.108
+298 "2B10" 91.404 54.498 76.524 13.618 8.1445 8.4106
+299 "2C10" 122.45 129.19 129.52 24.412 26.496 22.533
+300 "2D10" 52.091 43.712 85.349 5.2897 4.2252 10.803
+301 "A11" 95.121 56.945 109.13 15.662 9.9371 16.757
+302 "B11" 49.247 84.978 41.595 6.3528 11.756 4.1276
+303 "C11" 201.38 188.28 201.57 70.247 65.054 58.834
+304 "D11" 165.99 106.71 48.883 42.904 30.283 4.3741
+305 "E11" 142.45 151.87 140.77 33.675 37.292 27.259
+306 "F11" 59.895 43.373 70.686 7.3260 5.3398 8.4321
+307 "G11" 185.60 179.80 175.52 56.748 56.026 41.441
+308 "H11" 62.810 62.001 39.464 8.1585 8.7147 3.0001
+309 "I11" 182.38 181.99 177.01 54.512 56.195 42.466
+310 "J11" 44.613 62.579 56.523 4.9736 7.2275 6.1574
+311 "K11" 177.26 171.26 154.02 50.413 50.352 29.675
+312 "L11" 81.706 58.921 119.57 11.783 8.3671 18.993
+313 "M11" 30.648 29.769 29.464 2.4004 2.4632 1.9865
+314 "N11" 56.534 56.324 55.689 7.0502 7.2979 5.9348
+315 "O11" 89.911 89.936 88.980 15.157 15.663 12.643
+316 "P11" 140.77 141.41 140.88 30.809 31.935 26.037
+317 "Q11" 179.84 180.21 178.58 51.029 52.827 42.179
+318 "R11" 212.60 213.84 215.53 78.892 82.077 69.152
+319 "S11" 66.493 66.184 65.558 9.0391 9.3614 7.5795
+320 "T11" 187.32 160.61 146.99 54.688 46.067 27.270
+321 "U11" 59.842 44.929 41.517 7.0672 5.5203 3.1542
+322 "V11" 100.71 151.70 177.40 19.018 30.251 40.808
+323 "W11" 32.433 32.983 31.555 2.6438 2.7813 2.1741
+324 "X11" 103.41 161.56 150.03 20.294 33.254 28.954
+325 "Y11" 49.930 46.756 84.028 4.7917 4.3367 10.461
+326 "Z11" 157.24 187.57 185.20 39.678 51.335 44.730
+327 "2A11" 69.840 130.51 46.639 11.397 22.075 5.4606
+328 "2B11" 164.73 190.77 189.92 43.396 54.386 47.692
+329 "2C11" 67.660 57.565 50.639 9.0264 8.0855 4.5632
+330 "2D11" 146.88 73.255 46.894 29.263 17.239 3.6542
+331 "A12" 149.18 183.06 84.464 42.435 55.238 11.960
+332 "B12" 72.446 71.794 146.17 10.244 9.5241 28.550
+333 "C12" 111.58 163.80 82.344 25.557 39.490 11.397
+334 "D12" 67.115 62.023 67.669 9.5983 9.1448 8.3283
+335 "E12" 202.25 206.59 144.16 71.285 77.444 27.463
+336 "F12" 142.52 142.52 149.46 32.592 33.399 30.058
+337 "G12" 52.218 46.843 96.005 5.1430 4.3541 13.182
+338 "H12" 95.301 157.62 128.66 18.517 32.087 22.562
+339 "I12" 58.804 42.199 45.333 6.9977 5.1440 3.8014
+340 "J12" 201.67 207.01 112.57 69.246 76.042 17.844
+341 "K12" 76.878 56.433 113.86 10.642 7.6407 17.593
+342 "L12" 110.43 164.87 121.89 21.927 35.477 19.681
+343 "M12" 31.073 30.502 29.828 2.4287 2.4921 1.9949
+344 "N12" 60.863 60.999 60.221 7.9937 8.3172 6.7360
+345 "O12" 97.436 97.414 96.425 17.120 17.761 14.285
+346 "P12" 146.96 147.76 147.68 33.242 34.486 28.221
+347 "Q12" 186.04 186.49 184.52 55.136 57.000 45.303
+348 "R12" 217.03 217.69 217.80 84.047 87.070 71.496
+349 "S12" 173.81 166.67 164.48 46.799 45.618 34.284
+350 "T12" 61.998 59.133 126.43 6.6921 6.0185 19.773
+351 "U12" 133.08 178.53 107.01 31.583 45.365 15.646
+352 "V12" 159.59 92.307 67.569 35.975 22.808 7.0470
+353 "W12" 92.823 93.091 102.67 15.632 16.004 15.333
+354 "X12" 153.31 79.910 48.385 32.188 19.569 3.7849
+355 "Y12" 76.169 77.765 152.48 9.9981 9.6287 28.171
+356 "Z12" 80.867 145.82 55.209 14.429 27.348 6.4901
+357 "2A12" 88.726 84.091 155.13 13.822 12.446 29.936
+358 "2B12" 201.37 208.14 195.53 68.261 74.431 52.067
+359 "2C12" 32.004 31.705 30.813 2.4685 2.5621 2.0287
+360 "2D12" 135.53 145.08 187.78 28.798 30.974 45.549
+361 "A13" 86.415 69.301 138.07 14.129 10.884 26.286
+362 "B13" 104.58 136.42 46.559 21.280 29.662 4.6515
+363 "C13" 147.82 79.114 100.32 32.064 17.966 13.604
+364 "D13" 75.334 85.157 157.26 9.9611 10.733 32.277
+365 "E13" 178.81 179.96 148.24 51.845 54.927 28.181
+366 "F13" 55.482 72.327 100.16 6.3441 8.5421 15.068
+367 "G13" 200.09 199.75 184.43 68.699 71.452 46.387
+368 "H13" 76.688 84.710 151.41 10.374 10.902 29.169
+369 "I13" 129.73 107.35 52.022 26.203 23.997 4.3858
+370 "J13" 119.03 160.66 198.42 25.753 36.554 54.373
+371 "K13" 56.473 50.032 106.16 5.9068 4.9157 15.287
+372 "L13" 153.18 106.56 46.936 35.348 27.270 4.1933
+373 "M13" 32.264 31.978 31.289 2.6154 2.7053 2.1626
+374 "N13" 66.470 66.520 66.246 9.3637 9.6843 7.8391
+375 "O13" 105.28 105.86 104.76 19.359 20.106 16.147
+376 "P13" 153.75 154.63 154.12 36.624 37.957 30.671
+377 "Q13" 192.03 192.25 191.27 59.859 61.861 49.702
+378 "R13" 221.68 221.89 221.96 89.957 93.025 75.604
+379 "S13" 104.20 75.856 145.33 17.613 12.665 26.369
+380 "T13" 121.87 124.18 72.370 22.969 25.114 7.7873
+381 "U13" 91.392 55.886 72.021 13.623 8.3610 7.6135
+382 "V13" 193.01 176.53 161.70 59.661 54.433 33.140
+383 "W13" 97.047 61.496 44.638 15.045 10.609 3.4373
+384 "X13" 124.18 171.27 172.48 26.676 39.190 37.659
+385 "Y13" 100.95 103.55 45.932 16.770 18.831 3.7976
+386 "Z13" 98.719 76.722 108.03 16.243 13.004 15.620
+387 "2A13" 193.99 204.68 205.71 62.079 69.145 59.254
+388 "2B13" 77.619 94.368 167.50 9.8300 11.508 34.315
+389 "2C13" 91.512 53.191 50.701 13.378 8.4024 4.1065
+390 "2D13" 76.609 104.98 135.45 11.706 16.228 24.708
+391 "A14" 129.84 79.131 147.61 27.260 17.709 28.446
+392 "B14" 74.731 86.884 158.53 10.007 11.116 33.309
+393 "C14" 178.45 194.65 198.02 55.170 63.826 56.969
+394 "D14" 122.80 65.789 71.805 22.474 12.791 7.8220
+395 "E14" 99.529 101.15 66.691 17.833 19.340 7.6068
+396 "F14" 133.73 68.160 43.803 25.508 15.387 3.5019
+397 "G14" 130.31 174.28 137.87 28.674 42.244 25.294
+398 "H14" 110.49 77.413 145.63 20.013 14.167 27.201
+399 "I14" 30.999 29.764 29.587 2.4079 2.4331 1.9867
+400 "J14" 120.14 114.13 178.99 23.527 21.066 41.374
+401 "K14" 128.29 64.544 74.117 23.203 12.509 8.0121
+402 "L14" 176.70 157.34 183.40 48.486 42.511 43.112
+403 "M14" 59.777 105.00 45.141 8.6031 15.926 4.6200
+404 "N14" 182.00 181.11 190.30 53.107 53.884 48.977
+405 "O14" 42.651 40.749 62.042 3.9836 3.7404 6.5852
+406 "P14" 151.32 150.31 182.91 35.517 35.068 43.001
+407 "Q14" 162.51 94.932 125.82 37.782 22.314 19.042
+408 "R14" 99.745 94.301 93.467 17.467 17.105 13.104
+409 "S14" 107.25 159.78 58.090 22.370 35.508 5.9931
+410 "T14" 128.01 72.369 117.84 23.886 13.985 16.868
+411 "U14" 107.76 101.18 90.766 19.591 19.252 12.172
+412 "V14" 204.14 190.16 48.644 63.345 63.812 5.6645
+413 "W14" 82.597 65.626 44.970 12.028 10.481 3.3856
+414 "X14" 166.39 166.20 175.82 42.635 43.420 39.912
+415 "Y14" 100.69 152.17 51.384 19.856 32.192 5.1431
+416 "Z14" 91.650 100.20 90.746 15.570 17.641 12.711
+417 "2A14" 143.62 91.243 162.04 29.733 19.495 31.105
+418 "2B14" 214.71 215.34 214.31 81.209 84.285 67.959
+419 "2C14" 101.32 87.875 161.74 16.972 13.897 32.504
+420 "2D14" 105.18 138.75 68.497 20.262 27.906 7.7177
+421 "A15" 124.84 68.758 114.78 24.922 14.319 17.652
+422 "B15" 99.929 150.22 167.53 20.394 32.266 39.177
+423 "C15" 121.25 165.78 57.133 28.847 42.042 6.3345
+424 "D15" 129.49 121.04 130.58 27.579 26.553 23.681
+425 "E15" 161.27 95.254 123.97 38.874 23.290 19.357
+426 "F15" 148.20 174.03 142.22 36.703 46.352 27.027
+427 "G15" 150.41 98.923 167.42 34.061 22.803 34.531
+428 "H15" 75.180 91.615 158.04 10.113 11.921 31.879
+429 "I15" 196.22 179.25 172.32 64.423 58.008 39.281
+430 "J15" 66.558 62.105 60.696 9.4542 9.1717 6.7120
+431 "K15" 174.25 177.65 112.40 48.073 52.062 16.154
+432 "L15" 116.33 112.29 162.02 22.225 20.657 33.169
+433 "M15" 133.68 171.46 73.038 32.410 43.840 8.6168
+434 "N15" 102.47 146.49 198.15 19.932 29.141 53.896
+435 "O15" 64.715 46.574 43.032 8.2354 6.1612 3.2448
+436 "P15" 105.91 159.08 164.78 21.186 33.689 34.860
+437 "Q15" 34.379 33.754 36.003 2.8839 2.9372 2.7235
+438 "R15" 102.62 61.271 119.89 16.647 10.677 18.389
+439 "S15" 159.62 86.224 48.021 35.874 22.454 3.7685
+440 "T15" 95.611 158.57 127.45 18.024 31.495 21.231
+441 "U15" 133.03 87.140 157.87 26.027 17.635 30.172
+442 "V15" 48.894 77.368 43.484 5.7623 9.6302 3.8733
+443 "W15" 182.54 191.20 178.40 53.522 58.991 41.376
+444 "X15" 126.00 95.308 166.74 23.991 17.693 34.060
+445 "Y15" 38.376 39.986 33.590 3.5595 3.8688 2.3978
+446 "Z15" 148.30 148.94 147.37 34.055 35.265 28.241
+447 "2A15" 146.55 75.055 68.429 29.379 16.826 7.3609
+448 "2B15" 71.706 70.645 144.63 9.2107 8.5579 25.691
+449 "2C15" 133.02 80.816 44.452 25.707 18.129 3.6532
+450 "2D15" 82.777 113.54 117.52 13.875 19.568 19.948
+451 "A16" 147.43 75.104 45.417 32.441 19.582 3.7464
+452 "B16" 162.22 145.05 108.87 43.738 40.362 16.554
+453 "C16" 43.273 69.681 61.261 4.9159 8.3065 7.2559
+454 "D16" 154.15 106.72 65.606 37.197 27.832 7.4910
+455 "E16" 149.19 148.83 193.98 36.691 35.876 51.695
+456 "F16" 157.80 111.38 47.573 38.836 30.036 4.3338
+457 "G16" 100.61 79.449 149.13 17.555 13.363 28.888
+458 "H16" 206.92 207.61 211.44 75.466 77.836 67.216
+459 "I16" 97.895 82.272 66.348 16.954 15.112 7.2992
+460 "J16" 172.80 178.46 82.595 47.072 52.200 10.669
+461 "K16" 183.90 191.17 190.75 55.962 60.759 50.287
+462 "L16" 75.048 76.021 151.02 10.165 9.7715 28.705
+463 "M16" 159.42 88.282 47.938 36.859 23.500 3.8297
+464 "N16" 133.24 176.09 150.50 29.735 43.076 29.229
+465 "O16" 59.749 48.251 40.198 7.3545 6.2503 2.9745
+466 "P16" 171.06 168.69 161.58 46.114 46.965 33.568
+467 "Q16" 53.260 54.841 37.700 6.2218 6.8107 2.7776
+468 "R16" 147.03 76.735 66.424 29.663 17.214 6.8286
+469 "S16" 63.206 78.809 107.93 8.0381 10.138 16.410
+470 "T16" 150.22 77.352 47.226 31.088 18.734 3.6263
+471 "U16" 97.824 159.49 134.64 18.911 32.215 23.899
+472 "V16" 133.39 81.567 151.23 26.145 16.883 27.363
+473 "W16" 155.32 82.024 48.477 33.705 20.761 3.7986
+474 "X16" 81.301 147.86 56.013 14.361 27.487 7.1744
+475 "Y16" 141.53 112.75 178.08 29.882 22.982 39.138
+476 "Z16" 31.556 30.196 30.075 2.4233 2.4412 1.9648
+477 "2A16" 166.04 149.78 129.15 42.519 39.188 21.270
+478 "2B16" 53.939 48.402 100.70 5.2349 4.4461 13.823
+479 "2C16" 152.96 83.435 68.500 32.492 19.465 7.0806
+480 "2D16" 141.97 181.00 131.63 33.454 46.863 22.481
+481 "A17" 93.002 152.57 112.99 18.355 31.722 19.048
+482 "B17" 48.562 44.595 81.595 4.8626 4.2833 10.526
+483 "C17" 155.24 137.12 108.13 39.631 36.092 16.781
+484 "D17" 37.723 54.820 48.270 3.8471 5.8319 4.8962
+485 "E17" 163.04 158.68 133.73 43.491 44.349 22.904
+486 "F17" 155.10 81.151 47.477 35.028 21.444 3.8305
+487 "G17" 119.76 108.26 175.73 23.826 20.302 40.464
+488 "H17" 155.83 188.69 108.40 44.211 56.679 16.435
+489 "I17" 54.125 49.417 43.252 6.5115 6.2807 3.6004
+490 "J17" 146.89 182.65 155.76 35.464 48.530 31.500
+491 "K17" 148.71 77.345 50.119 31.217 18.833 4.2081
+492 "L17" 53.925 41.854 39.291 6.1796 5.0138 3.0160
+493 "M17" 105.46 156.83 167.45 21.355 33.511 36.981
+494 "N17" 149.16 79.222 103.08 31.382 17.339 13.539
+495 "O17" 109.98 107.89 138.78 20.515 20.076 24.934
+496 "P17" 151.99 78.765 47.620 32.143 19.447 3.7592
+497 "Q17" 195.13 169.06 200.08 60.501 50.532 52.708
+498 "R17" 73.599 136.55 49.271 12.657 24.420 5.6873
+499 "S17" 37.757 33.718 34.938 3.4355 3.1639 2.5372
+500 "T17" 132.61 142.77 197.68 28.192 29.771 51.322
+501 "U17" 181.82 145.93 103.48 52.660 42.651 15.019
+502 "V17" 204.10 203.91 210.35 69.823 71.393 63.731
+503 "W17" 175.82 179.36 52.229 44.995 50.413 5.2421
+504 "X17" 155.69 156.50 143.88 37.401 38.967 26.702
+505 "Y17" 65.731 44.495 80.654 8.0339 5.5483 9.9052
+506 "Z17" 67.930 138.21 88.916 10.382 21.829 11.599
+507 "2A17" 156.40 87.866 68.881 34.325 21.131 7.2263
+508 "2B17" 68.870 68.990 41.254 9.1863 9.9839 3.1512
+509 "2C17" 209.60 202.66 207.60 75.534 73.388 61.922
+510 "2D17" 108.97 87.062 152.98 19.258 14.916 29.290
+511 "A18" 200.70 204.40 197.90 74.089 78.770 59.424
+512 "B18" 164.93 117.44 177.68 42.903 30.204 40.715
+513 "C18" 61.227 72.827 56.013 8.7363 10.837 6.0872
+514 "D18" 204.51 199.19 195.95 75.509 74.636 56.066
+515 "E18" 73.692 73.322 148.06 10.413 9.8011 28.727
+516 "F18" 68.313 128.24 45.392 11.836 22.861 5.4226
+517 "G18" 131.14 85.288 152.52 26.954 18.177 29.358
+518 "H18" 89.609 153.68 93.128 16.220 29.699 13.154
+519 "I18" 30.179 29.676 28.922 2.3647 2.3980 1.9090
+520 "J18" 208.65 210.69 209.48 77.786 81.283 65.463
+521 "K18" 88.863 70.346 63.498 14.363 11.898 6.7644
+522 "L18" 197.92 177.16 54.602 60.378 57.128 5.2726
+523 "M18" 143.55 91.470 162.00 30.554 20.123 31.743
+524 "N18" 121.99 131.52 122.44 24.748 27.645 20.451
+525 "O18" 172.04 115.00 91.328 44.929 31.003 12.389
+526 "P18" 81.187 74.923 148.64 11.881 10.425 27.990
+527 "Q18" 117.91 169.48 101.12 25.737 39.690 14.823
+528 "R18" 183.93 145.62 52.297 52.300 42.856 4.6545
+529 "S18" 55.452 105.38 65.438 7.2126 14.429 7.1944
+530 "T18" 211.11 208.92 210.90 77.679 78.425 65.193
+531 "U18" 177.41 124.39 134.00 47.084 32.209 22.319
+532 "V18" 53.506 90.891 78.889 6.6683 11.848 10.189
+533 "W18" 197.65 205.13 206.81 65.207 70.970 60.729
+534 "X18" 51.396 86.860 43.674 6.2806 11.330 4.1095
+535 "Y18" 193.58 175.18 113.92 60.571 56.044 16.070
+536 "Z18" 96.313 103.94 178.60 15.673 16.045 40.153
+537 "2A18" 168.53 106.08 128.73 41.178 25.901 19.845
+538 "2B18" 85.496 104.15 136.89 13.693 16.674 24.407
+539 "2C18" 208.09 210.26 179.31 74.223 78.952 41.733
+540 "2D18" 161.94 92.492 50.116 38.135 24.817 4.1395
+541 "A19" 156.71 112.54 101.12 39.239 29.094 15.479
+542 "B19" 42.513 58.501 40.536 4.7416 7.0454 3.4644
+543 "C19" 172.17 152.13 143.40 49.395 43.657 28.522
+544 "D19" 159.73 183.13 54.703 42.332 52.372 5.7052
+545 "E19" 119.21 105.48 95.518 24.242 22.424 14.026
+546 "F19" 30.235 29.764 29.269 2.4551 2.5226 2.0256
+547 "G19" 88.689 134.99 136.69 16.677 25.667 25.825
+548 "H19" 86.392 53.901 45.566 13.124 8.8453 3.5763
+549 "I19" 126.88 158.15 160.78 28.527 37.076 34.358
+550 "J19" 120.42 79.125 64.241 22.891 16.490 6.9749
+551 "K19" 108.34 160.80 164.56 22.666 35.279 35.631
+552 "L19" 49.327 39.952 38.592 5.4212 4.5484 2.9627
+553 "M19" 67.917 128.27 44.976 11.199 21.925 5.4425
+554 "N19" 127.84 62.080 45.945 22.708 12.897 3.6335
+555 "O19" 74.380 138.45 130.11 12.507 23.738 22.498
+556 "P19" 30.060 29.337 28.817 2.3442 2.3896 1.9267
+557 "Q19" 147.97 73.539 46.480 30.303 17.749 3.5777
+558 "R19" 75.153 76.608 151.15 10.104 9.7374 28.448
+559 "S19" 78.339 144.41 52.936 13.901 26.685 6.3873
+560 "T19" 31.312 30.556 30.767 2.4391 2.4780 2.0610
+561 "U19" 169.32 177.98 203.35 45.972 49.473 57.247
+562 "V19" 44.471 72.376 45.634 4.8275 8.3485 3.9886
+563 "W19" 199.02 205.39 55.979 63.154 70.855 7.5811
+564 "X19" 90.125 81.954 73.039 14.863 14.166 8.5770
+565 "Y19" 207.33 211.44 212.22 74.340 78.986 66.286
+566 "Z19" 182.95 126.85 175.69 49.996 33.344 36.894
+567 "2A19" 77.857 90.598 163.13 10.165 11.287 33.081
+568 "2B19" 202.16 204.23 49.052 62.642 69.515 6.2139
+569 "2C19" 162.94 96.440 68.740 38.429 24.741 7.3479
+570 "2D19" 83.952 84.116 160.97 12.944 12.283 32.608
+END_DATA
diff --git a/scanin/CMP_Digital_Target-3.ti2 b/scanin/CMP_Digital_Target-3.ti2
new file mode 100644
index 0000000..e4b15e9
--- /dev/null
+++ b/scanin/CMP_Digital_Target-3.ti2
@@ -0,0 +1,601 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2 for Christopher Metarie Digital Target 3"
+ORIGINATOR "Argyll printtarg"
+CREATED "Wed Sep 12 00:02:26 2007"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth i1 Pro"
+KEYWORD "ACCURATE_EXPECTED_VALUES"
+ACCURATE_EXPECTED_VALUES "true"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "30"
+KEYWORD "PASSES_IN_STRIPS2"
+PASSES_IN_STRIPS2 "19"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "A-Z, 2-9"
+KEYWORD "INDEX_ORDER"
+INDEX_ORDER "PATCH_THEN_STRIP"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 570
+BEGIN_DATA
+1 "A1" 106.60 73.896 140.50 19.991 14.120 27.886
+2 "B1" 101.22 157.76 91.298 19.926 34.054 14.005
+3 "C1" 56.474 54.712 116.20 6.2319 5.6339 19.078
+4 "D1" 142.23 143.96 106.67 32.785 35.198 16.672
+5 "E1" 161.58 92.303 143.82 38.996 22.658 25.805
+6 "F1" 90.405 96.497 94.153 16.011 17.612 14.561
+7 "G1" 163.39 98.124 88.178 39.496 24.997 12.003
+8 "H1" 63.278 55.370 115.21 7.4905 6.2468 18.358
+9 "I1" 71.385 133.64 49.363 11.987 23.286 6.5928
+10 "J1" 97.757 75.383 143.28 16.591 12.444 27.331
+11 "K1" 194.49 193.52 200.39 63.038 64.179 58.403
+12 "L1" 43.729 37.037 36.612 4.3513 3.8393 2.7750
+13 "M1" 128.36 143.53 178.51 27.386 30.873 42.527
+14 "N1" 136.71 176.12 173.90 31.789 44.281 40.439
+15 "O1" 190.25 190.03 173.26 59.453 61.985 40.335
+16 "P1" 139.89 69.074 45.054 26.783 15.713 3.5833
+17 "Q1" 34.433 40.188 37.667 3.0238 3.6843 3.0876
+18 "R1" 87.362 153.04 89.833 15.462 28.885 12.776
+19 "S1" 124.79 84.048 151.84 23.694 16.421 29.352
+20 "T1" 201.42 206.76 79.283 65.900 73.381 11.377
+21 "U1" 59.875 104.70 93.370 8.3333 15.036 13.749
+22 "V1" 205.39 208.60 159.63 72.416 77.985 33.423
+23 "W1" 91.572 136.12 167.03 16.393 25.254 38.122
+24 "X1" 30.336 29.306 28.957 2.3144 2.3581 1.9303
+25 "Y1" 132.60 110.17 107.91 27.102 23.276 16.813
+26 "Z1" 32.956 33.215 31.185 2.6994 2.8850 2.2332
+27 "2A1" 70.282 129.32 46.946 10.757 20.588 4.8216
+28 "2B1" 159.00 173.65 202.91 40.765 45.919 58.857
+29 "2C1" 121.19 88.150 161.84 22.864 16.381 33.839
+30 "2D1" 136.59 101.50 125.83 28.289 21.404 20.483
+31 "A2" 75.414 80.525 150.43 10.412 10.567 30.978
+32 "B2" 128.64 63.027 42.872 24.139 14.085 3.5857
+33 "C2" 101.62 116.40 166.26 19.473 21.752 38.376
+34 "D2" 129.62 78.772 146.55 26.280 16.991 28.035
+35 "E2" 164.20 144.75 82.589 42.573 39.671 9.6556
+36 "F2" 96.904 110.83 179.21 17.113 18.705 43.690
+37 "G2" 157.24 84.071 46.359 35.850 22.548 3.8554
+38 "H2" 84.439 70.424 140.26 13.037 10.392 26.425
+39 "I2" 81.661 147.44 58.864 14.946 28.262 8.1825
+40 "J2" 35.433 35.856 32.072 3.1780 3.3914 2.3047
+41 "K2" 150.66 144.08 140.58 35.880 35.178 26.683
+42 "L2" 158.35 93.379 154.74 36.434 22.147 28.386
+43 "M2" 100.38 93.492 99.897 17.689 17.022 15.072
+44 "N2" 158.93 93.968 95.921 36.396 23.022 13.623
+45 "O2" 102.60 137.21 171.09 19.884 26.988 39.544
+46 "P2" 74.932 50.703 44.902 10.294 7.4271 3.4839
+47 "Q2" 115.12 165.78 166.70 24.415 37.008 36.288
+48 "R2" 157.97 92.663 150.58 36.078 21.682 26.898
+49 "S2" 83.913 88.787 161.27 12.232 12.247 33.412
+50 "T2" 72.772 133.20 48.154 12.486 23.920 5.4357
+51 "U2" 155.64 177.45 175.23 38.913 47.091 40.794
+52 "V2" 65.311 50.797 44.712 8.3779 6.8387 3.7119
+53 "W2" 30.304 29.389 28.630 2.3401 2.3804 1.9157
+54 "X2" 98.383 112.57 76.501 17.501 20.678 9.7225
+55 "Y2" 196.95 176.56 81.174 60.324 56.490 9.7029
+56 "Z2" 106.87 76.461 64.020 18.340 14.257 6.9452
+57 "2A2" 149.29 180.57 55.756 39.051 50.700 6.0515
+58 "2B2" 46.850 72.093 42.887 5.3134 8.7205 3.7883
+59 "2C2" 126.21 86.097 104.74 24.040 16.842 14.641
+60 "2D2" 68.443 138.05 59.668 10.963 22.720 8.1563
+61 "A3" 40.703 34.668 43.170 3.2215 2.8069 3.1344
+62 "B3" 140.80 177.61 130.47 35.703 49.122 24.276
+63 "C3" 71.422 72.467 144.63 9.6710 9.2674 28.141
+64 "D3" 157.83 159.05 109.87 39.368 42.329 16.693
+65 "E3" 74.511 78.412 148.91 9.8448 9.8037 29.501
+66 "F3" 172.35 192.98 167.60 50.040 60.997 38.371
+67 "G3" 72.505 72.322 146.66 9.8731 9.2375 28.216
+68 "H3" 132.85 167.63 50.020 31.926 43.409 5.2962
+69 "I3" 99.822 132.27 193.48 18.889 24.530 52.235
+70 "J3" 158.78 88.817 87.144 36.271 22.167 11.952
+71 "K3" 146.32 156.61 192.38 34.281 37.060 50.573
+72 "L3" 30.978 30.641 29.826 2.4511 2.5353 2.0398
+73 "M3" 146.27 153.30 150.57 34.120 37.136 30.510
+74 "N3" 144.16 70.919 46.534 28.309 16.461 3.7229
+75 "O3" 85.091 72.947 144.27 12.851 10.508 27.052
+76 "P3" 122.91 131.12 67.881 24.532 27.910 7.4170
+77 "Q3" 140.27 116.77 178.48 29.800 23.719 40.761
+78 "R3" 73.020 103.31 46.082 11.420 17.249 4.2060
+79 "S3" 148.58 74.828 46.145 30.098 17.923 3.6411
+80 "T3" 92.676 106.61 179.17 15.102 16.455 41.548
+81 "U3" 89.067 149.36 56.522 16.816 29.880 6.2892
+82 "V3" 104.27 103.98 177.68 19.054 17.886 40.635
+83 "W3" 122.27 64.970 44.965 21.160 13.146 3.6418
+84 "X3" 190.80 157.08 167.65 56.827 44.647 36.033
+85 "Y3" 55.033 94.759 44.077 7.3224 13.350 4.3645
+86 "Z3" 157.08 85.576 87.558 34.447 20.515 11.595
+87 "2A3" 79.250 88.578 159.52 10.795 11.448 32.464
+88 "2B3" 108.15 127.71 55.172 20.617 25.691 5.5795
+89 "2C3" 78.102 75.847 150.05 11.126 10.174 28.914
+90 "2D3" 202.83 194.20 199.16 68.724 66.102 56.410
+91 "A4" 105.09 86.729 157.14 19.671 15.554 33.919
+92 "B4" 99.696 102.26 43.923 17.501 19.753 3.8498
+93 "C4" 107.26 130.81 190.72 21.509 25.734 51.674
+94 "D4" 178.30 141.51 75.719 51.958 42.451 9.1213
+95 "E4" 86.201 111.97 176.39 14.112 17.806 42.697
+96 "F4" 192.41 193.92 143.50 61.487 65.884 27.427
+97 "G4" 161.20 95.317 155.94 38.420 23.239 29.457
+98 "H4" 74.863 77.945 149.59 9.8759 9.7311 29.126
+99 "I4" 207.61 208.23 184.16 75.793 79.718 46.695
+100 "J4" 70.931 101.90 131.71 10.595 15.480 24.653
+101 "K4" 147.01 94.545 162.80 32.187 21.331 32.814
+102 "L4" 81.586 103.83 104.84 13.777 17.753 16.663
+103 "M4" 141.06 69.848 45.247 27.339 16.027 3.5603
+104 "N4" 90.494 151.07 150.65 16.922 28.995 29.336
+105 "O4" 55.294 41.016 63.313 6.3066 4.7610 6.9921
+106 "P4" 111.84 140.47 103.22 22.390 29.210 15.592
+107 "Q4" 144.45 93.249 162.31 30.657 20.369 32.268
+108 "R4" 105.31 104.82 101.31 19.152 19.807 15.592
+109 "S4" 79.325 137.68 48.973 13.948 25.671 5.2122
+110 "T4" 84.189 150.82 120.01 14.991 27.898 19.745
+111 "U4" 81.413 52.379 93.432 11.486 7.6381 12.484
+112 "V4" 76.459 77.531 42.048 10.749 11.899 3.2945
+113 "W4" 211.28 212.44 213.00 77.699 80.782 67.995
+114 "X4" 125.79 102.06 67.469 24.430 21.610 7.1800
+115 "Y4" 36.736 36.340 46.306 3.2104 3.1999 4.2513
+116 "Z4" 83.114 150.29 61.891 14.450 27.763 8.5197
+117 "2A4" 117.71 90.574 160.37 21.679 16.235 32.574
+118 "2B4" 89.463 153.87 72.494 15.737 29.267 10.078
+119 "2C4" 42.498 47.832 65.570 3.9226 4.4418 7.5674
+120 "2D4" 115.91 156.34 101.73 24.022 34.375 15.022
+121 "A5" 100.43 57.576 43.875 16.920 10.945 3.6233
+122 "B5" 139.57 140.52 191.37 32.876 32.373 51.547
+123 "C5" 106.24 157.82 63.346 23.454 37.144 7.5202
+124 "D5" 120.63 119.68 128.56 24.762 25.266 23.702
+125 "E5" 144.32 70.530 44.643 29.192 16.958 3.5359
+126 "F5" 112.12 164.88 139.23 23.640 37.186 26.447
+127 "G5" 103.37 136.87 47.413 20.387 28.842 4.7028
+128 "H5" 36.251 41.780 35.395 3.3636 4.0809 2.6833
+129 "I5" 111.24 162.80 164.26 23.272 35.820 35.198
+130 "J5" 143.56 87.562 156.55 30.642 19.573 30.103
+131 "K5" 109.54 163.06 164.19 22.753 35.416 35.064
+132 "L5" 79.627 52.133 45.354 11.209 7.8786 3.5144
+133 "M5" 92.456 152.33 153.19 17.513 29.721 30.234
+134 "N5" 34.714 33.013 32.281 2.9935 2.9559 2.2837
+135 "O5" 166.35 175.94 163.99 44.139 49.035 35.423
+136 "P5" 89.669 79.549 47.144 14.200 13.959 3.6761
+137 "Q5" 191.24 182.85 188.48 59.021 56.831 48.262
+138 "R5" 51.675 70.899 41.770 6.3401 9.2262 3.4989
+139 "S5" 170.53 177.54 173.76 45.700 49.818 40.124
+140 "T5" 63.890 93.942 45.687 9.3142 14.437 4.0636
+141 "U5" 30.168 29.299 28.940 2.3535 2.3975 1.9290
+142 "V5" 133.08 133.14 122.05 27.766 28.925 20.091
+143 "W5" 36.054 32.923 33.276 3.0887 2.9300 2.3596
+144 "X5" 61.314 111.77 45.755 8.7239 16.803 5.0276
+145 "Y5" 203.39 209.40 208.06 70.161 75.882 63.247
+146 "Z5" 76.353 77.670 109.77 11.191 11.244 16.654
+147 "2A5" 193.86 202.18 186.73 62.394 68.771 47.096
+148 "2B5" 84.630 73.965 145.61 12.640 10.459 27.333
+149 "2C5" 68.392 129.05 45.336 11.160 21.761 5.5099
+150 "2D5" 210.46 210.49 195.89 77.413 80.592 53.936
+151 "A6" 156.79 90.614 148.03 37.703 22.453 27.499
+152 "B6" 88.481 111.82 178.46 14.943 18.301 44.058
+153 "C6" 167.90 108.82 66.983 44.282 30.956 7.9185
+154 "D6" 66.578 110.85 54.360 10.440 18.144 6.5076
+155 "E6" 148.31 87.735 154.80 32.892 20.486 29.274
+156 "F6" 93.611 155.13 115.73 17.819 31.263 19.184
+157 "G6" 40.190 39.280 58.763 3.7468 3.6058 6.3752
+158 "H6" 170.89 152.59 147.19 45.907 41.132 28.818
+159 "I6" 46.469 44.545 75.326 4.4472 4.1158 9.1204
+160 "J6" 102.48 151.18 180.03 20.388 31.549 44.358
+161 "K6" 30.872 30.164 29.516 2.3970 2.4515 1.9961
+162 "L6" 83.294 137.00 98.315 14.323 24.343 14.536
+163 "M6" 30.722 30.150 29.446 2.3623 2.4293 1.9541
+164 "N6" 163.74 151.67 194.83 41.190 36.767 50.714
+165 "O6" 199.83 203.65 49.970 62.357 69.847 6.3069
+166 "P6" 77.512 86.873 159.07 10.124 10.811 31.915
+167 "Q6" 200.99 194.31 190.45 67.127 65.762 49.352
+168 "R6" 165.39 100.99 154.68 39.128 23.959 27.822
+169 "S6" 69.496 98.026 61.986 10.413 15.222 6.7952
+170 "T6" 167.68 124.93 146.98 41.195 30.074 26.292
+171 "U6" 62.706 68.483 60.211 8.4099 9.5591 6.5834
+172 "V6" 174.63 108.06 166.14 43.942 26.976 32.439
+173 "W6" 138.60 174.02 106.27 33.397 44.263 15.513
+174 "X6" 192.12 161.59 197.05 56.629 45.672 50.137
+175 "Y6" 71.207 70.503 63.173 10.198 10.583 6.9283
+176 "Z6" 171.42 121.85 182.26 42.782 29.822 40.386
+177 "2A6" 193.77 197.98 207.14 61.567 65.013 61.274
+178 "2B6" 117.80 82.965 151.94 21.335 15.115 28.916
+179 "2C6" 36.305 39.517 34.462 3.2203 3.7212 2.6005
+180 "2D6" 152.48 145.44 148.89 35.799 34.854 29.422
+181 "A7" 93.637 153.35 73.710 19.123 33.078 10.667
+182 "B7" 83.277 73.755 144.52 12.915 10.831 28.225
+183 "C7" 206.85 206.70 197.33 77.518 80.587 57.622
+184 "D7" 77.454 73.349 146.72 11.348 10.154 28.703
+185 "E7" 70.809 132.64 47.023 12.442 24.254 5.6475
+186 "F7" 91.049 88.345 163.10 15.345 13.969 34.910
+187 "G7" 177.87 190.87 53.018 52.703 61.988 5.9513
+188 "H7" 75.960 87.720 159.98 9.9056 10.888 32.881
+189 "I7" 199.48 192.77 181.55 67.471 66.483 44.705
+190 "J7" 64.713 68.090 67.610 8.8426 9.6268 8.1730
+191 "K7" 193.08 175.48 139.54 61.925 56.855 24.968
+192 "L7" 75.430 87.876 159.79 9.6349 10.726 32.427
+193 "M7" 133.24 173.17 56.742 32.435 45.157 6.1480
+194 "N7" 148.49 75.098 46.216 30.427 18.146 3.6270
+195 "O7" 97.134 97.177 86.559 16.928 17.695 11.911
+196 "P7" 191.20 160.30 54.685 56.094 48.894 4.9467
+197 "Q7" 80.068 80.251 125.32 11.934 11.778 20.573
+198 "R7" 83.368 147.19 55.358 15.285 28.434 6.3346
+199 "S7" 37.747 44.719 36.907 3.5054 4.3615 2.7830
+200 "T7" 146.52 175.26 205.50 35.099 44.589 58.771
+201 "U7" 133.97 82.941 152.98 26.155 17.005 28.079
+202 "V7" 63.182 103.22 97.125 8.9086 14.924 14.071
+203 "W7" 144.22 147.07 76.384 30.611 33.536 8.6858
+204 "X7" 212.78 213.19 211.89 79.113 81.784 66.503
+205 "Y7" 77.896 86.298 158.37 10.240 10.764 31.229
+206 "Z7" 71.313 133.52 47.389 11.976 23.218 5.4228
+207 "2A7" 75.926 78.650 151.98 9.9976 9.7574 28.929
+208 "2B7" 118.08 168.98 98.781 25.572 39.297 14.262
+209 "2C7" 207.34 198.34 43.623 66.257 69.908 5.8960
+210 "2D7" 92.639 108.26 179.66 14.893 16.603 41.626
+211 "A8" 69.904 137.36 58.325 12.100 24.359 8.4071
+212 "B8" 167.09 144.55 49.599 42.436 39.900 4.7260
+213 "C8" 111.10 78.672 121.83 20.574 15.216 20.136
+214 "D8" 74.340 141.34 56.829 12.701 25.255 8.1803
+215 "E8" 104.13 74.055 141.65 18.324 13.039 26.409
+216 "F8" 90.075 154.61 90.911 16.724 30.035 13.212
+217 "G8" 36.341 33.896 36.868 3.3200 3.1831 3.0291
+218 "H8" 101.65 159.66 134.07 20.304 33.570 24.443
+219 "I8" 34.216 33.499 37.712 2.9169 2.9009 3.0168
+220 "J8" 174.41 165.56 173.38 48.038 46.099 39.891
+221 "K8" 46.252 66.300 42.397 5.2241 8.0427 3.5985
+222 "L8" 152.69 184.12 182.69 38.619 50.368 44.407
+223 "M8" 30.240 29.863 28.939 2.3428 2.3959 1.9273
+224 "N8" 35.593 35.467 34.190 3.1956 3.3116 2.6415
+225 "O8" 71.728 71.553 70.937 10.494 10.847 8.8081
+226 "P8" 115.92 116.10 114.68 22.233 23.005 18.548
+227 "Q8" 159.85 160.38 159.13 39.317 40.778 33.056
+228 "R8" 196.60 197.21 197.12 63.147 65.480 53.862
+229 "S8" 137.57 112.53 140.33 28.252 23.514 24.400
+230 "T8" 80.940 142.13 50.952 14.520 26.909 5.4756
+231 "U8" 99.365 133.93 196.43 18.057 24.054 51.817
+232 "V8" 30.957 30.566 29.813 2.3402 2.3911 1.9209
+233 "W8" 212.09 210.69 210.55 77.838 79.255 64.883
+234 "X8" 90.920 71.799 46.751 14.232 12.342 3.5677
+235 "Y8" 137.72 177.30 175.40 31.451 43.594 39.472
+236 "Z8" 39.524 49.911 38.685 3.8429 5.0881 3.0661
+237 "2A8" 130.39 176.13 127.05 27.844 41.491 21.140
+238 "2B8" 31.904 31.437 30.690 2.4921 2.5648 2.0613
+239 "2C8" 149.77 158.18 196.00 34.635 36.777 50.964
+240 "2D8" 30.719 29.824 29.600 2.3436 2.3905 1.9440
+241 "A9" 160.64 188.72 135.75 46.811 59.109 25.406
+242 "B9" 151.09 113.48 161.82 35.695 26.905 33.928
+243 "C9" 56.378 101.12 44.028 8.0578 15.313 4.8058
+244 "D9" 200.86 192.61 183.06 70.562 68.540 46.575
+245 "E9" 77.639 89.149 161.20 10.633 11.656 33.787
+246 "F9" 183.43 148.52 132.23 54.113 43.360 23.933
+247 "G9" 53.868 83.869 77.703 7.1200 11.358 10.328
+248 "H9" 144.68 93.693 163.06 31.237 20.786 32.756
+249 "I9" 80.625 147.05 117.46 14.469 27.174 19.553
+250 "J9" 82.612 53.093 45.342 11.813 8.1727 3.4750
+251 "K9" 179.05 178.11 205.03 51.613 51.265 59.093
+252 "L9" 68.256 128.21 45.397 11.232 21.889 5.3482
+253 "M9" 30.122 29.559 28.786 2.3389 2.3932 1.9205
+254 "N9" 44.132 44.030 43.113 4.6543 4.8363 3.9004
+255 "O9" 77.603 77.496 77.212 11.973 12.444 10.082
+256 "P9" 123.38 123.35 123.35 24.548 25.410 20.720
+257 "Q9" 167.61 168.12 167.11 43.270 44.842 36.215
+258 "R9" 202.61 204.17 205.53 68.113 71.034 59.864
+259 "S9" 152.34 81.269 59.657 31.468 18.903 5.4734
+260 "T9" 36.525 39.233 37.120 3.2297 3.6435 2.9170
+261 "U9" 147.79 112.59 105.57 31.779 25.042 15.321
+262 "V9" 128.85 175.42 85.449 30.098 43.673 10.856
+263 "W9" 202.12 182.11 203.04 65.360 57.273 55.175
+264 "X9" 58.841 111.22 46.014 7.8261 15.682 5.0934
+265 "Y9" 150.27 74.574 46.780 30.151 17.603 3.5424
+266 "Z9" 91.373 72.814 142.15 14.169 10.872 25.545
+267 "2A9" 178.42 178.87 165.68 49.740 51.961 35.295
+268 "2B9" 110.21 82.066 150.83 19.293 14.167 28.533
+269 "2C9" 115.57 141.00 82.227 23.305 29.469 10.465
+270 "2D9" 120.44 87.308 156.62 22.420 16.254 30.792
+271 "A10" 54.278 98.104 59.100 7.4766 14.316 6.7672
+272 "B10" 141.49 142.92 50.130 30.693 34.185 4.8132
+273 "C10" 69.545 135.98 93.417 11.568 23.235 13.773
+274 "D10" 30.772 30.009 29.471 2.4307 2.4999 2.0171
+275 "E10" 140.52 89.479 159.03 30.140 19.949 31.751
+276 "F10" 88.149 135.62 165.23 15.810 25.353 37.521
+277 "G10" 30.508 30.075 29.389 2.4272 2.4936 1.9887
+278 "H10" 75.794 144.13 86.030 12.549 25.096 11.562
+279 "I10" 29.881 29.286 28.915 2.3402 2.3788 1.9223
+280 "J10" 78.427 139.08 135.09 13.387 24.235 23.958
+281 "K10" 127.69 103.24 52.122 25.478 22.853 4.3681
+282 "L10" 47.518 38.484 37.887 5.0366 4.2550 2.8902
+283 "M10" 30.202 29.466 28.978 2.3374 2.3915 1.9194
+284 "N10" 50.671 50.438 49.901 5.8942 6.1054 4.9143
+285 "O10" 84.087 84.218 84.130 13.462 14.013 11.428
+286 "P10" 130.92 131.27 131.19 27.055 28.014 23.007
+287 "Q10" 174.24 174.94 173.31 47.406 49.169 39.386
+288 "R10" 208.46 209.75 212.17 73.974 77.043 65.729
+289 "S10" 61.440 61.759 68.112 7.8358 8.0794 7.9176
+290 "T10" 189.59 154.63 195.61 54.395 42.563 48.165
+291 "U10" 70.065 139.76 58.155 11.113 22.841 7.7084
+292 "V10" 34.382 38.877 37.374 2.9394 3.4387 2.9247
+293 "W10" 81.185 148.91 88.683 13.284 25.973 11.867
+294 "X10" 31.337 30.706 30.647 2.4768 2.5120 2.1182
+295 "Y10" 132.10 124.54 122.36 27.102 26.481 19.829
+296 "Z10" 128.86 77.259 44.848 23.978 16.698 3.6586
+297 "2A10" 121.07 144.71 145.24 24.659 30.178 27.108
+298 "2B10" 91.404 54.498 76.524 13.618 8.1445 8.4106
+299 "2C10" 122.45 129.19 129.52 24.412 26.496 22.533
+300 "2D10" 52.091 43.712 85.349 5.2897 4.2252 10.803
+301 "A11" 95.121 56.945 109.13 15.662 9.9371 16.757
+302 "B11" 49.247 84.978 41.595 6.3528 11.756 4.1276
+303 "C11" 201.38 188.28 201.57 70.247 65.054 58.834
+304 "D11" 165.99 106.71 48.883 42.904 30.283 4.3741
+305 "E11" 142.45 151.87 140.77 33.675 37.292 27.259
+306 "F11" 59.895 43.373 70.686 7.3260 5.3398 8.4321
+307 "G11" 185.60 179.80 175.52 56.748 56.026 41.441
+308 "H11" 62.810 62.001 39.464 8.1585 8.7147 3.0001
+309 "I11" 182.38 181.99 177.01 54.512 56.195 42.466
+310 "J11" 44.613 62.579 56.523 4.9736 7.2275 6.1574
+311 "K11" 177.26 171.26 154.02 50.413 50.352 29.675
+312 "L11" 81.706 58.921 119.57 11.783 8.3671 18.993
+313 "M11" 30.648 29.769 29.464 2.4004 2.4632 1.9865
+314 "N11" 56.534 56.324 55.689 7.0502 7.2979 5.9348
+315 "O11" 89.911 89.936 88.980 15.157 15.663 12.643
+316 "P11" 140.77 141.41 140.88 30.809 31.935 26.037
+317 "Q11" 179.84 180.21 178.58 51.029 52.827 42.179
+318 "R11" 212.60 213.84 215.53 78.892 82.077 69.152
+319 "S11" 66.493 66.184 65.558 9.0391 9.3614 7.5795
+320 "T11" 187.32 160.61 146.99 54.688 46.067 27.270
+321 "U11" 59.842 44.929 41.517 7.0672 5.5203 3.1542
+322 "V11" 100.71 151.70 177.40 19.018 30.251 40.808
+323 "W11" 32.433 32.983 31.555 2.6438 2.7813 2.1741
+324 "X11" 103.41 161.56 150.03 20.294 33.254 28.954
+325 "Y11" 49.930 46.756 84.028 4.7917 4.3367 10.461
+326 "Z11" 157.24 187.57 185.20 39.678 51.335 44.730
+327 "2A11" 69.840 130.51 46.639 11.397 22.075 5.4606
+328 "2B11" 164.73 190.77 189.92 43.396 54.386 47.692
+329 "2C11" 67.660 57.565 50.639 9.0264 8.0855 4.5632
+330 "2D11" 146.88 73.255 46.894 29.263 17.239 3.6542
+331 "A12" 149.18 183.06 84.464 42.435 55.238 11.960
+332 "B12" 72.446 71.794 146.17 10.244 9.5241 28.550
+333 "C12" 111.58 163.80 82.344 25.557 39.490 11.397
+334 "D12" 67.115 62.023 67.669 9.5983 9.1448 8.3283
+335 "E12" 202.25 206.59 144.16 71.285 77.444 27.463
+336 "F12" 142.52 142.52 149.46 32.592 33.399 30.058
+337 "G12" 52.218 46.843 96.005 5.1430 4.3541 13.182
+338 "H12" 95.301 157.62 128.66 18.517 32.087 22.562
+339 "I12" 58.804 42.199 45.333 6.9977 5.1440 3.8014
+340 "J12" 201.67 207.01 112.57 69.246 76.042 17.844
+341 "K12" 76.878 56.433 113.86 10.642 7.6407 17.593
+342 "L12" 110.43 164.87 121.89 21.927 35.477 19.681
+343 "M12" 31.073 30.502 29.828 2.4287 2.4921 1.9949
+344 "N12" 60.863 60.999 60.221 7.9937 8.3172 6.7360
+345 "O12" 97.436 97.414 96.425 17.120 17.761 14.285
+346 "P12" 146.96 147.76 147.68 33.242 34.486 28.221
+347 "Q12" 186.04 186.49 184.52 55.136 57.000 45.303
+348 "R12" 217.03 217.69 217.80 84.047 87.070 71.496
+349 "S12" 173.81 166.67 164.48 46.799 45.618 34.284
+350 "T12" 61.998 59.133 126.43 6.6921 6.0185 19.773
+351 "U12" 133.08 178.53 107.01 31.583 45.365 15.646
+352 "V12" 159.59 92.307 67.569 35.975 22.808 7.0470
+353 "W12" 92.823 93.091 102.67 15.632 16.004 15.333
+354 "X12" 153.31 79.910 48.385 32.188 19.569 3.7849
+355 "Y12" 76.169 77.765 152.48 9.9981 9.6287 28.171
+356 "Z12" 80.867 145.82 55.209 14.429 27.348 6.4901
+357 "2A12" 88.726 84.091 155.13 13.822 12.446 29.936
+358 "2B12" 201.37 208.14 195.53 68.261 74.431 52.067
+359 "2C12" 32.004 31.705 30.813 2.4685 2.5621 2.0287
+360 "2D12" 135.53 145.08 187.78 28.798 30.974 45.549
+361 "A13" 86.415 69.301 138.07 14.129 10.884 26.286
+362 "B13" 104.58 136.42 46.559 21.280 29.662 4.6515
+363 "C13" 147.82 79.114 100.32 32.064 17.966 13.604
+364 "D13" 75.334 85.157 157.26 9.9611 10.733 32.277
+365 "E13" 178.81 179.96 148.24 51.845 54.927 28.181
+366 "F13" 55.482 72.327 100.16 6.3441 8.5421 15.068
+367 "G13" 200.09 199.75 184.43 68.699 71.452 46.387
+368 "H13" 76.688 84.710 151.41 10.374 10.902 29.169
+369 "I13" 129.73 107.35 52.022 26.203 23.997 4.3858
+370 "J13" 119.03 160.66 198.42 25.753 36.554 54.373
+371 "K13" 56.473 50.032 106.16 5.9068 4.9157 15.287
+372 "L13" 153.18 106.56 46.936 35.348 27.270 4.1933
+373 "M13" 32.264 31.978 31.289 2.6154 2.7053 2.1626
+374 "N13" 66.470 66.520 66.246 9.3637 9.6843 7.8391
+375 "O13" 105.28 105.86 104.76 19.359 20.106 16.147
+376 "P13" 153.75 154.63 154.12 36.624 37.957 30.671
+377 "Q13" 192.03 192.25 191.27 59.859 61.861 49.702
+378 "R13" 221.68 221.89 221.96 89.957 93.025 75.604
+379 "S13" 104.20 75.856 145.33 17.613 12.665 26.369
+380 "T13" 121.87 124.18 72.370 22.969 25.114 7.7873
+381 "U13" 91.392 55.886 72.021 13.623 8.3610 7.6135
+382 "V13" 193.01 176.53 161.70 59.661 54.433 33.140
+383 "W13" 97.047 61.496 44.638 15.045 10.609 3.4373
+384 "X13" 124.18 171.27 172.48 26.676 39.190 37.659
+385 "Y13" 100.95 103.55 45.932 16.770 18.831 3.7976
+386 "Z13" 98.719 76.722 108.03 16.243 13.004 15.620
+387 "2A13" 193.99 204.68 205.71 62.079 69.145 59.254
+388 "2B13" 77.619 94.368 167.50 9.8300 11.508 34.315
+389 "2C13" 91.512 53.191 50.701 13.378 8.4024 4.1065
+390 "2D13" 76.609 104.98 135.45 11.706 16.228 24.708
+391 "A14" 129.84 79.131 147.61 27.260 17.709 28.446
+392 "B14" 74.731 86.884 158.53 10.007 11.116 33.309
+393 "C14" 178.45 194.65 198.02 55.170 63.826 56.969
+394 "D14" 122.80 65.789 71.805 22.474 12.791 7.8220
+395 "E14" 99.529 101.15 66.691 17.833 19.340 7.6068
+396 "F14" 133.73 68.160 43.803 25.508 15.387 3.5019
+397 "G14" 130.31 174.28 137.87 28.674 42.244 25.294
+398 "H14" 110.49 77.413 145.63 20.013 14.167 27.201
+399 "I14" 30.999 29.764 29.587 2.4079 2.4331 1.9867
+400 "J14" 120.14 114.13 178.99 23.527 21.066 41.374
+401 "K14" 128.29 64.544 74.117 23.203 12.509 8.0121
+402 "L14" 176.70 157.34 183.40 48.486 42.511 43.112
+403 "M14" 59.777 105.00 45.141 8.6031 15.926 4.6200
+404 "N14" 182.00 181.11 190.30 53.107 53.884 48.977
+405 "O14" 42.651 40.749 62.042 3.9836 3.7404 6.5852
+406 "P14" 151.32 150.31 182.91 35.517 35.068 43.001
+407 "Q14" 162.51 94.932 125.82 37.782 22.314 19.042
+408 "R14" 99.745 94.301 93.467 17.467 17.105 13.104
+409 "S14" 107.25 159.78 58.090 22.370 35.508 5.9931
+410 "T14" 128.01 72.369 117.84 23.886 13.985 16.868
+411 "U14" 107.76 101.18 90.766 19.591 19.252 12.172
+412 "V14" 204.14 190.16 48.644 63.345 63.812 5.6645
+413 "W14" 82.597 65.626 44.970 12.028 10.481 3.3856
+414 "X14" 166.39 166.20 175.82 42.635 43.420 39.912
+415 "Y14" 100.69 152.17 51.384 19.856 32.192 5.1431
+416 "Z14" 91.650 100.20 90.746 15.570 17.641 12.711
+417 "2A14" 143.62 91.243 162.04 29.733 19.495 31.105
+418 "2B14" 214.71 215.34 214.31 81.209 84.285 67.959
+419 "2C14" 101.32 87.875 161.74 16.972 13.897 32.504
+420 "2D14" 105.18 138.75 68.497 20.262 27.906 7.7177
+421 "A15" 124.84 68.758 114.78 24.922 14.319 17.652
+422 "B15" 99.929 150.22 167.53 20.394 32.266 39.177
+423 "C15" 121.25 165.78 57.133 28.847 42.042 6.3345
+424 "D15" 129.49 121.04 130.58 27.579 26.553 23.681
+425 "E15" 161.27 95.254 123.97 38.874 23.290 19.357
+426 "F15" 148.20 174.03 142.22 36.703 46.352 27.027
+427 "G15" 150.41 98.923 167.42 34.061 22.803 34.531
+428 "H15" 75.180 91.615 158.04 10.113 11.921 31.879
+429 "I15" 196.22 179.25 172.32 64.423 58.008 39.281
+430 "J15" 66.558 62.105 60.696 9.4542 9.1717 6.7120
+431 "K15" 174.25 177.65 112.40 48.073 52.062 16.154
+432 "L15" 116.33 112.29 162.02 22.225 20.657 33.169
+433 "M15" 133.68 171.46 73.038 32.410 43.840 8.6168
+434 "N15" 102.47 146.49 198.15 19.932 29.141 53.896
+435 "O15" 64.715 46.574 43.032 8.2354 6.1612 3.2448
+436 "P15" 105.91 159.08 164.78 21.186 33.689 34.860
+437 "Q15" 34.379 33.754 36.003 2.8839 2.9372 2.7235
+438 "R15" 102.62 61.271 119.89 16.647 10.677 18.389
+439 "S15" 159.62 86.224 48.021 35.874 22.454 3.7685
+440 "T15" 95.611 158.57 127.45 18.024 31.495 21.231
+441 "U15" 133.03 87.140 157.87 26.027 17.635 30.172
+442 "V15" 48.894 77.368 43.484 5.7623 9.6302 3.8733
+443 "W15" 182.54 191.20 178.40 53.522 58.991 41.376
+444 "X15" 126.00 95.308 166.74 23.991 17.693 34.060
+445 "Y15" 38.376 39.986 33.590 3.5595 3.8688 2.3978
+446 "Z15" 148.30 148.94 147.37 34.055 35.265 28.241
+447 "2A15" 146.55 75.055 68.429 29.379 16.826 7.3609
+448 "2B15" 71.706 70.645 144.63 9.2107 8.5579 25.691
+449 "2C15" 133.02 80.816 44.452 25.707 18.129 3.6532
+450 "2D15" 82.777 113.54 117.52 13.875 19.568 19.948
+451 "A16" 147.43 75.104 45.417 32.441 19.582 3.7464
+452 "B16" 162.22 145.05 108.87 43.738 40.362 16.554
+453 "C16" 43.273 69.681 61.261 4.9159 8.3065 7.2559
+454 "D16" 154.15 106.72 65.606 37.197 27.832 7.4910
+455 "E16" 149.19 148.83 193.98 36.691 35.876 51.695
+456 "F16" 157.80 111.38 47.573 38.836 30.036 4.3338
+457 "G16" 100.61 79.449 149.13 17.555 13.363 28.888
+458 "H16" 206.92 207.61 211.44 75.466 77.836 67.216
+459 "I16" 97.895 82.272 66.348 16.954 15.112 7.2992
+460 "J16" 172.80 178.46 82.595 47.072 52.200 10.669
+461 "K16" 183.90 191.17 190.75 55.962 60.759 50.287
+462 "L16" 75.048 76.021 151.02 10.165 9.7715 28.705
+463 "M16" 159.42 88.282 47.938 36.859 23.500 3.8297
+464 "N16" 133.24 176.09 150.50 29.735 43.076 29.229
+465 "O16" 59.749 48.251 40.198 7.3545 6.2503 2.9745
+466 "P16" 171.06 168.69 161.58 46.114 46.965 33.568
+467 "Q16" 53.260 54.841 37.700 6.2218 6.8107 2.7776
+468 "R16" 147.03 76.735 66.424 29.663 17.214 6.8286
+469 "S16" 63.206 78.809 107.93 8.0381 10.138 16.410
+470 "T16" 150.22 77.352 47.226 31.088 18.734 3.6263
+471 "U16" 97.824 159.49 134.64 18.911 32.215 23.899
+472 "V16" 133.39 81.567 151.23 26.145 16.883 27.363
+473 "W16" 155.32 82.024 48.477 33.705 20.761 3.7986
+474 "X16" 81.301 147.86 56.013 14.361 27.487 7.1744
+475 "Y16" 141.53 112.75 178.08 29.882 22.982 39.138
+476 "Z16" 31.556 30.196 30.075 2.4233 2.4412 1.9648
+477 "2A16" 166.04 149.78 129.15 42.519 39.188 21.270
+478 "2B16" 53.939 48.402 100.70 5.2349 4.4461 13.823
+479 "2C16" 152.96 83.435 68.500 32.492 19.465 7.0806
+480 "2D16" 141.97 181.00 131.63 33.454 46.863 22.481
+481 "A17" 93.002 152.57 112.99 18.355 31.722 19.048
+482 "B17" 48.562 44.595 81.595 4.8626 4.2833 10.526
+483 "C17" 155.24 137.12 108.13 39.631 36.092 16.781
+484 "D17" 37.723 54.820 48.270 3.8471 5.8319 4.8962
+485 "E17" 163.04 158.68 133.73 43.491 44.349 22.904
+486 "F17" 155.10 81.151 47.477 35.028 21.444 3.8305
+487 "G17" 119.76 108.26 175.73 23.826 20.302 40.464
+488 "H17" 155.83 188.69 108.40 44.211 56.679 16.435
+489 "I17" 54.125 49.417 43.252 6.5115 6.2807 3.6004
+490 "J17" 146.89 182.65 155.76 35.464 48.530 31.500
+491 "K17" 148.71 77.345 50.119 31.217 18.833 4.2081
+492 "L17" 53.925 41.854 39.291 6.1796 5.0138 3.0160
+493 "M17" 105.46 156.83 167.45 21.355 33.511 36.981
+494 "N17" 149.16 79.222 103.08 31.382 17.339 13.539
+495 "O17" 109.98 107.89 138.78 20.515 20.076 24.934
+496 "P17" 151.99 78.765 47.620 32.143 19.447 3.7592
+497 "Q17" 195.13 169.06 200.08 60.501 50.532 52.708
+498 "R17" 73.599 136.55 49.271 12.657 24.420 5.6873
+499 "S17" 37.757 33.718 34.938 3.4355 3.1639 2.5372
+500 "T17" 132.61 142.77 197.68 28.192 29.771 51.322
+501 "U17" 181.82 145.93 103.48 52.660 42.651 15.019
+502 "V17" 204.10 203.91 210.35 69.823 71.393 63.731
+503 "W17" 175.82 179.36 52.229 44.995 50.413 5.2421
+504 "X17" 155.69 156.50 143.88 37.401 38.967 26.702
+505 "Y17" 65.731 44.495 80.654 8.0339 5.5483 9.9052
+506 "Z17" 67.930 138.21 88.916 10.382 21.829 11.599
+507 "2A17" 156.40 87.866 68.881 34.325 21.131 7.2263
+508 "2B17" 68.870 68.990 41.254 9.1863 9.9839 3.1512
+509 "2C17" 209.60 202.66 207.60 75.534 73.388 61.922
+510 "2D17" 108.97 87.062 152.98 19.258 14.916 29.290
+511 "A18" 200.70 204.40 197.90 74.089 78.770 59.424
+512 "B18" 164.93 117.44 177.68 42.903 30.204 40.715
+513 "C18" 61.227 72.827 56.013 8.7363 10.837 6.0872
+514 "D18" 204.51 199.19 195.95 75.509 74.636 56.066
+515 "E18" 73.692 73.322 148.06 10.413 9.8011 28.727
+516 "F18" 68.313 128.24 45.392 11.836 22.861 5.4226
+517 "G18" 131.14 85.288 152.52 26.954 18.177 29.358
+518 "H18" 89.609 153.68 93.128 16.220 29.699 13.154
+519 "I18" 30.179 29.676 28.922 2.3647 2.3980 1.9090
+520 "J18" 208.65 210.69 209.48 77.786 81.283 65.463
+521 "K18" 88.863 70.346 63.498 14.363 11.898 6.7644
+522 "L18" 197.92 177.16 54.602 60.378 57.128 5.2726
+523 "M18" 143.55 91.470 162.00 30.554 20.123 31.743
+524 "N18" 121.99 131.52 122.44 24.748 27.645 20.451
+525 "O18" 172.04 115.00 91.328 44.929 31.003 12.389
+526 "P18" 81.187 74.923 148.64 11.881 10.425 27.990
+527 "Q18" 117.91 169.48 101.12 25.737 39.690 14.823
+528 "R18" 183.93 145.62 52.297 52.300 42.856 4.6545
+529 "S18" 55.452 105.38 65.438 7.2126 14.429 7.1944
+530 "T18" 211.11 208.92 210.90 77.679 78.425 65.193
+531 "U18" 177.41 124.39 134.00 47.084 32.209 22.319
+532 "V18" 53.506 90.891 78.889 6.6683 11.848 10.189
+533 "W18" 197.65 205.13 206.81 65.207 70.970 60.729
+534 "X18" 51.396 86.860 43.674 6.2806 11.330 4.1095
+535 "Y18" 193.58 175.18 113.92 60.571 56.044 16.070
+536 "Z18" 96.313 103.94 178.60 15.673 16.045 40.153
+537 "2A18" 168.53 106.08 128.73 41.178 25.901 19.845
+538 "2B18" 85.496 104.15 136.89 13.693 16.674 24.407
+539 "2C18" 208.09 210.26 179.31 74.223 78.952 41.733
+540 "2D18" 161.94 92.492 50.116 38.135 24.817 4.1395
+541 "A19" 156.71 112.54 101.12 39.239 29.094 15.479
+542 "B19" 42.513 58.501 40.536 4.7416 7.0454 3.4644
+543 "C19" 172.17 152.13 143.40 49.395 43.657 28.522
+544 "D19" 159.73 183.13 54.703 42.332 52.372 5.7052
+545 "E19" 119.21 105.48 95.518 24.242 22.424 14.026
+546 "F19" 30.235 29.764 29.269 2.4551 2.5226 2.0256
+547 "G19" 88.689 134.99 136.69 16.677 25.667 25.825
+548 "H19" 86.392 53.901 45.566 13.124 8.8453 3.5763
+549 "I19" 126.88 158.15 160.78 28.527 37.076 34.358
+550 "J19" 120.42 79.125 64.241 22.891 16.490 6.9749
+551 "K19" 108.34 160.80 164.56 22.666 35.279 35.631
+552 "L19" 49.327 39.952 38.592 5.4212 4.5484 2.9627
+553 "M19" 67.917 128.27 44.976 11.199 21.925 5.4425
+554 "N19" 127.84 62.080 45.945 22.708 12.897 3.6335
+555 "O19" 74.380 138.45 130.11 12.507 23.738 22.498
+556 "P19" 30.060 29.337 28.817 2.3442 2.3896 1.9267
+557 "Q19" 147.97 73.539 46.480 30.303 17.749 3.5777
+558 "R19" 75.153 76.608 151.15 10.104 9.7374 28.448
+559 "S19" 78.339 144.41 52.936 13.901 26.685 6.3873
+560 "T19" 31.312 30.556 30.767 2.4391 2.4780 2.0610
+561 "U19" 169.32 177.98 203.35 45.972 49.473 57.247
+562 "V19" 44.471 72.376 45.634 4.8275 8.3485 3.9886
+563 "W19" 199.02 205.39 55.979 63.154 70.855 7.5811
+564 "X19" 90.125 81.954 73.039 14.863 14.166 8.5770
+565 "Y19" 207.33 211.44 212.22 74.340 78.986 66.286
+566 "Z19" 182.95 126.85 175.69 49.996 33.344 36.894
+567 "2A19" 77.857 90.598 163.13 10.165 11.287 33.081
+568 "2B19" 202.16 204.23 49.052 62.642 69.515 6.2139
+569 "2C19" 162.94 96.440 68.740 38.429 24.741 7.3479
+570 "2D19" 83.952 84.116 160.97 12.944 12.283 32.608
+END_DATA
diff --git a/scanin/ColorChecker.cht b/scanin/ColorChecker.cht
new file mode 100644
index 0000000..1da441b
--- /dev/null
+++ b/scanin/ColorChecker.cht
@@ -0,0 +1,59 @@
+
+BOXES 25
+ F _ _ 10.0 9.75 321.25 9.75 321.26 217 10.0 217
+ D ALL ALL _ _ 330 228 0 0 0 0
+ Y 1 6 A D 46.0 46.0 12.0 11.5 52.5 52.5
+
+BOX_SHRINK 6.0
+
+REF_ROTATION 0.0
+
+XLIST 12
+ 12.0 1.0 1.0
+ 58.5 1.0 1.0
+ 64.5 1.0 1.0
+ 110.5 1.0 1.0
+ 117.0 1.0 1.0
+ 163.0 1.0 1.0
+ 169.5 1.0 1.0
+ 215.5 1.0 1.0
+ 221.5 1.0 1.0
+ 267.5 1.0 1.0
+ 274.0 1.0 1.0
+ 320.0 1.0 1.0
+
+YLIST 8
+ 11.5 1.0 1.0
+ 58.0 1.0 1.0
+ 64.0 1.0 1.0
+ 110.0 1.0 1.0
+ 116.5 1.0 1.0
+ 163.0 1.0 1.0
+ 169.0 1.0 1.0
+ 215.0 1.0 1.0
+
+EXPECTED XYZ 24
+ A1 11.773 10.213 4.9219
+ A2 40.174 36.201 20.217
+ A3 17.675 19.409 26.983
+ A4 11.121 13.530 5.5615
+ A5 25.551 24.404 34.847
+ A6 31.744 43.164 35.249
+ B1 40.056 30.947 4.8180
+ B2 12.544 11.700 28.648
+ B3 30.675 20.352 10.837
+ B4 8.3961 6.5047 10.849
+ B5 36.036 44.991 8.9494
+ B6 50.203 44.570 6.2773
+ C1 7.4590 6.0952 23.518
+ C2 15.439 23.986 7.7482
+ C3 22.850 13.022 4.1188
+ C4 59.637 60.332 7.3520
+ C5 30.450 20.015 22.947
+ C6 13.591 19.466 30.479
+ D1 86.776 90.361 70.642
+ D2 56.865 59.038 48.218
+ D3 34.763 36.036 29.378
+ D4 18.884 19.603 16.309
+ D5 8.4332 8.7464 7.1022
+ D6 3.0110 3.0971 2.5475
diff --git a/scanin/ColorChecker.cie b/scanin/ColorChecker.cie
new file mode 100644
index 0000000..8c78ff6
--- /dev/null
+++ b/scanin/ColorChecker.cie
@@ -0,0 +1,39 @@
+IT8.7/2
+ORIGINATOR "Graeme Gill, ArgyllCMS from Gretag Macbeth reference"
+DESCRIPTOR "ColorChecker 24"
+CREATED "Feb 18, 2008"
+MANUFACTURER "X-Rite/Gretag Macbeth"
+
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+SAMPLE_ID LAB_L LAB_A LAB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 24
+BEGIN_DATA
+A01 37.99 13.56 14.06
+A02 65.71 18.13 17.81
+A03 49.93 -4.88 -21.93
+A04 43.14 -13.10 21.91
+A05 55.11 8.84 -25.40
+A06 70.72 -33.40 -0.20
+B01 62.66 36.07 57.10
+B02 40.02 10.41 -45.96
+B03 51.12 48.24 16.25
+B04 30.33 22.98 -21.59
+B05 72.53 -23.71 57.26
+B06 71.94 19.36 67.86
+C01 28.78 14.18 -50.30
+C02 55.26 -38.34 31.37
+C03 42.10 53.38 28.19
+C04 81.73 4.04 79.82
+C05 51.94 49.99 -14.57
+C06 51.04 -28.63 -28.64
+D01 96.54 -0.43 1.19
+D02 81.26 -0.64 -0.34
+D03 66.77 -0.73 -0.50
+D04 50.87 -0.15 -0.27
+D05 35.66 -0.42 -1.23
+D06 20.46 -0.08 -0.97
+END_DATA
+
diff --git a/scanin/ColorCheckerDC.cht b/scanin/ColorCheckerDC.cht
new file mode 100644
index 0000000..ad7ea29
--- /dev/null
+++ b/scanin/ColorCheckerDC.cht
@@ -0,0 +1,318 @@
+
+BOXES 241
+ F _ _ 26.09 18.7 330.2 18.7 330.2 202.4 26.09 202.4
+ D ALL ALL _ _ 355 216 0 0 0 0
+ X A T 01 12 12.675 12.75 27.5 20.0 15.175 15.25
+
+BOX_SHRINK 1.6
+
+XLIST 40
+ 27.5 1.0 1.0
+ 40.175 1.0 1.0
+ 42.675 1.0 1.0
+ 55.35 1.0 1.0
+ 57.85 1.0 1.0
+ 70.525 1.0 1.0
+ 73.025 1.0 1.0
+ 85.7 1.0 1.0
+ 88.2 1.0 1.0
+ 100.875 1.0 1.0
+ 103.375 1.0 1.0
+ 116.05 1.0 1.0
+ 118.55 1.0 1.0
+ 131.225 1.0 1.0
+ 133.725 1.0 1.0
+ 146.4 1.0 1.0
+ 148.9 1.0 1.0
+ 161.575 1.0 1.0
+ 164.075 1.0 1.0
+ 176.75 1.0 1.0
+ 179.25 1.0 1.0
+ 191.925 1.0 1.0
+ 194.425 1.0 1.0
+ 207.1 1.0 1.0
+ 209.6 1.0 1.0
+ 222.275 1.0 1.0
+ 224.775 1.0 1.0
+ 237.45 1.0 1.0
+ 239.95 1.0 1.0
+ 252.625 1.0 1.0
+ 255.125 1.0 1.0
+ 267.8 1.0 1.0
+ 270.3 1.0 1.0
+ 282.975 1.0 1.0
+ 285.475 1.0 1.0
+ 298.15 1.0 1.0
+ 300.65 1.0 1.0
+ 313.325 1.0 1.0
+ 315.825 1.0 1.0
+ 328.5 1.0 1.0
+
+YLIST 24
+ 20.0 1.0 1.0
+ 32.75 1.0 1.0
+ 35.25 1.0 1.0
+ 48.0 1.0 1.0
+ 50.5 1.0 1.0
+ 63.25 1.0 1.0
+ 65.75 1.0 1.0
+ 78.5 1.0 1.0
+ 81.0 1.0 1.0
+ 93.75 1.0 1.0
+ 96.25 1.0 1.0
+ 109.0 1.0 1.0
+ 111.5 1.0 1.0
+ 124.25 1.0 1.0
+ 126.75 1.0 1.0
+ 139.5 1.0 1.0
+ 142.0 1.0 1.0
+ 154.75 1.0 1.0
+ 157.25 1.0 1.0
+ 170.0 1.0 1.0
+ 172.5 1.0 1.0
+ 185.25 1.0 1.0
+ 187.75 1.0 1.0
+ 200.5 1.0 1.0
+
+EXPECTED XYZ 240
+A01 74.79 77.56 64.46
+A02 3.08 3.19 2.77
+A03 18.98 19.71 16.53
+A04 74.57 77.34 64.38
+A05 3.1 3.21 2.78
+A06 18.88 19.62 16.44
+A07 74.65 77.43 64.37
+A08 3.05 3.16 2.74
+A09 18.86 19.59 16.42
+A10 74.33 77.13 64.18
+A11 3.05 3.16 2.74
+A12 18.94 19.67 16.48
+B01 18.98 19.71 16.53
+B02 9.28 6.32 3.27
+B03 7.34 6.63 3.64
+B04 19.71 19.69 11.13
+B05 10.69 11.58 6.54
+B06 5.55 6.26 3.53
+B07 4.69 6.4 3.88
+B08 4.45 6.24 5.6
+B09 5.26 6.13 6.71
+B10 4.16 4.4 7.55
+B11 7.13 6.18 5.2
+B12 74.68 77.45 64.31
+C01 3.03 3.14 2.72
+C02 22.27 12.45 5.91
+C03 13.73 11.57 5.26
+C04 12.35 11.83 4.46
+C05 16.62 19.15 7.75
+C06 8.81 11.49 5.72
+C07 7.38 11.51 5.94
+C08 7.96 11.09 9.57
+C09 5.61 6.35 9.68
+C10 5.49 6.22 12.37
+C11 8.5 6.58 6.19
+C12 3.04 3.15 2.73
+D01 74.7 77.48 64.38
+D02 23.6 12.43 3.41
+D03 15.71 12.25 4.16
+D04 19.85 19.78 4.3
+D05 15.7 19.2 4.89
+D06 22.07 30.17 8.05
+D07 6.22 11.44 6.34
+D08 11.56 19.31 16.65
+D09 5.69 6.13 12.53
+D10 5.6 5.88 14.72
+D11 9.13 6.35 7.28
+D12 18.91 19.64 16.46
+E01 18.95 19.69 16.5
+E02 35.41 20.25 6.45
+E03 28.25 20.38 3.83
+E04 20.73 19.59 4.47
+E05 16.4 19.03 4.34
+E06 34.81 43.02 17.75
+E07 11.78 19.58 11.32
+E08 6.88 11.75 14.39
+E09 7.88 11.31 19.64
+E10 9.22 11.09 27.08
+E11 17.84 11.47 13.98
+E12 74.56 77.32 64.24
+F01 3.04 3.15 2.73
+F02 48.3 30.25 11.41
+F03 16.14 10.93 3.9
+F04 31.33 29.91 8.52
+F05 14.11 18.71 6.4
+F06 38.16 43.99 9.51
+F07 10.52 19.33 8.14
+F08 7.96 11.49 16.13
+F09 8.63 11.3 17.86
+F10 10.41 11.24 27.64
+F11 21.49 12.15 9.52
+F12 3.04 3.15 2.73
+G01 74.73 77.5 64.38
+G02 44.51 29.8 15.52
+G03 24.34 19.34 8.11
+G04 25.26 19.88 4.38
+G05 13.65 19.52 4.62
+G06 36.49 43.18 5.73
+G07 19.42 29.58 14.51
+G08 19.86 28.9 37.67
+G09 14.15 18.75 25.13
+G10 10.69 11.62 23.13
+G11 31.57 19.76 17.91
+G12 18.91 19.64 16.46
+H01 18.98 19.71 16.53
+H02 33.5 20.33 9.91
+H03 34.67 28.65 13.17
+H04 16.86 12.12 2.75
+H05 21.16 30.06 6.66
+H06 52.08 58.65 19.39
+H07 22.63 29.16 10.83
+H08 21.74 29.15 34.08
+H09 13.59 18.65 33.2
+H10 17.32 18.86 39.16
+H11 29.3 19.82 17.88
+H12 74.65 77.41 64.27
+I01 3.05 3.16 2.74
+I02 22.03 19.1 15.09
+I03 31.97 28.79 15.9
+I04 42.69 29.41 6.24
+I05 82.21 85.41 69.86
+I06 30.96 32.15 26.58
+I07 16.49 17.18 14.34
+I08 7.03 7.28 6.15
+I09 24.91 29.34 38.48
+I10 29.04 29.31 45.2
+I11 41.09 29.82 26.18
+I12 3.05 3.16 2.75
+J01 74.72 77.5 64.44
+J02 26.91 19.35 14.94
+J03 34.54 29.66 11.16
+J04 58.1 42.93 8.71
+J05 64.14 66.75 54.99
+J06 87.06 90.39 72.76
+J07 86.82 90.15 72.56
+J08 4.28 4.47 3.84
+J09 24.87 28.59 45.17
+J10 41.47 42.2 57.7
+J11 53.38 42.55 36.49
+J12 18.92 19.65 16.47
+K01 18.97 19.7 16.52
+K02 36.7 29.69 19.45
+K03 36.83 30.22 8.83
+K04 53.42 43.05 10.13
+K05 51.78 53.86 44.86
+K06 86.85 90.18 72.55
+K07 86.91 90.25 72.64
+K08 3.45 3.59 3.07
+K09 21.49 28.73 46.46
+K10 21.85 19.42 36.39
+K11 32.48 29.05 24.22
+K12 74.63 77.39 64.28
+L01 3.03 3.14 2.73
+L02 53.85 42.1 29.27
+L03 58.21 42.93 21.15
+L04 40.96 30.79 3.87
+L05 40.79 42.45 35.04
+L06 23.51 24.47 20.31
+L07 11.1 11.62 9.8
+L08 3.02 3.13 2.71
+L09 31.86 41.84 53.57
+L10 7.9 6.16 10.17
+L11 62.34 57.68 47.93
+L12 3.03 3.14 2.72
+M01 74.74 77.52 64.43
+M02 68.21 58.76 45.3
+M03 54.32 42.79 26.91
+M04 68.17 58.65 13.41
+M05 76.51 80.88 14.08
+M06 15.06 19.36 18.82
+M07 16.03 29.31 11.79
+M08 52.05 57.11 51.73
+M09 32.54 42.52 46.33
+M10 7.2 6.19 8.57
+M11 78.01 78.48 67.07
+M12 18.93 19.67 16.48
+N01 18.97 19.7 16.51
+N02 65.97 60.13 42.01
+N03 50.5 42.33 28.58
+N04 63.78 59.07 15.95
+N05 62.58 58.72 7.2
+N06 21.33 29.57 29.73
+N07 17.06 29.9 17.13
+N08 54.05 58.63 61.58
+N09 49.41 57.82 58.22
+N10 16.9 12.02 19.29
+N11 41.76 29.82 32.52
+N12 74.67 77.43 64.28
+O01 3.02 3.13 2.71
+O02 47.1 42.51 31.08
+O03 51.87 42.51 15.81
+O04 77.2 77.91 50.55
+O05 45.99 42.6 4.49
+O06 23.64 29.5 29.06
+O07 26.97 42.73 19.28
+O08 27.97 29.35 28.33
+O09 50.32 57.45 48.38
+O10 23.06 19.58 23.21
+O11 32.18 29.25 34.95
+O12 3.01 3.12 2.7
+P01 74.64 77.41 64.32
+P02 44.39 42.98 33.4
+P03 71.49 59.42 23.1
+P04 79.86 78.26 38.44
+P05 31.59 29.6 5.37
+P06 20.07 28.76 23.92
+P07 31.22 42.07 27.31
+P08 17.15 18.99 23.19
+P09 37.97 42.95 38.15
+P10 19.91 19.24 17.99
+P11 44.36 43.41 45.48
+P12 18.95 19.68 16.49
+Q01 18.96 19.69 16.51
+Q02 59.99 58.87 41.85
+Q03 67.98 58.85 30.96
+Q04 82.15 79.03 48.34
+Q05 33.18 29.48 5.74
+Q06 18.92 29.39 27.97
+Q07 44.1 58.65 39.14
+Q08 37.51 41.38 26.69
+Q09 40.27 42.04 17.38
+Q10 24.86 28.48 22.3
+Q11 9.43 11.28 9.5
+Q12 74.61 77.37 64.24
+R01 3.05 3.16 2.74
+R02 31.16 30.09 20.86
+R03 56.92 56.98 36.53
+R04 79.37 78.57 56.95
+R05 42.68 42.54 8.26
+R06 28.15 41.91 31.53
+R07 48.61 58.02 33.46
+R08 26.81 28.91 16.95
+R09 39.83 43.08 12.47
+R10 11.8 11.72 5.87
+R11 17.1 19.71 16.41
+R12 3.02 3.13 2.71
+S01 74.66 77.43 64.34
+S02 40.67 42.42 26.09
+S03 65.09 68.67 41.71
+S04 3.01 3.34 15.4
+S05 3.26 11.22 2.89
+S06 17.7 8.11 0.42
+S07 89.01 92.27 74.63
+S08 0.28 0.29 0.24
+S09 72.92 74.82 4.56
+S10 17.03 7.57 3.05
+S11 6.56 11.29 24.29
+S12 18.91 19.64 16.46
+T01 18.91 19.64 16.46
+T02 3.05 3.16 2.73
+T03 74.38 77.15 64.2
+T04 18.94 19.68 16.48
+T05 3.12 3.24 2.79
+T06 74.2 76.97 63.98
+T07 18.87 19.61 16.43
+T08 3.04 3.16 2.73
+T09 74.41 77.19 64.05
+T10 18.9 19.63 16.46
+T11 3.09 3.2 2.78
+T12 74.57 77.32 64.19
+
diff --git a/scanin/ColorCheckerPassport.cht b/scanin/ColorCheckerPassport.cht
new file mode 100644
index 0000000..758cad7
--- /dev/null
+++ b/scanin/ColorCheckerPassport.cht
@@ -0,0 +1,122 @@
+BOXES 51
+ F _ _ 97.0 17.0 157.3 17.0 157.3 107.0 97.0 107.0
+ D ALL ALL _ _ 59.0 5.0 98.0 11.0 0.0 0.0
+ X SAT SAT 1 8 10.0 10.0 13.5 102.1 0.0 -12.9
+ X WBP WBP 1 5 13.4 13.4 26.4 87.0 0.0 -16.0
+ X WBL WBL 1 5 13.4 13.4 42.5 87.0 0.0 -16.0
+ X NEU NEU 1 8 10.0 10.0 58.6 102.1 0.0 -12.9
+ X A D 1 6 12.4 12.4 98.5 93.4 15.0 -15.0
+
+BOX_SHRINK 2.0
+
+REF_ROTATION 0.0
+
+XLIST 16
+ 13.5 1.0 1.0
+ 23.5 1.0 1.0
+ 26.4 1.0 1.0
+ 39.8 1.0 1.0
+ 42.5 1.0 1.0
+ 55.9 1.0 1.0
+ 58.6 1.0 1.0
+ 68.6 1.0 1.0
+ 98.5 1.0 1.0
+ 110.9 1.0 1.0
+ 113.5 1.0 1.0
+ 125.9 1.0 1.0
+ 128.5 1.0 1.0
+ 140.9 1.0 1.0
+ 143.5 1.0 1.0
+ 155.9 1.0 1.0
+
+YLIST 38
+ 11.5 1.0 1.0
+ 18.5 1.0 1.0
+ 21.6 1.0 1.0
+ 23.4 1.0 1.0
+ 24.3 1.0 1.0
+ 30.9 1.0 1.0
+ 33.5 1.0 1.0
+ 34.6 1.0 1.0
+ 36.5 1.0 1.0
+ 37.2 1.0 1.0
+ 39.2 1.0 1.0
+ 45.8 1.0 1.0
+ 47.5 1.0 1.0
+ 48.4 1.0 1.0
+ 50.2 1.0 1.0
+ 52.5 1.0 1.0
+ 55.2 1.0 1.0
+ 60.4 1.0 1.0
+ 60.7 1.0 1.0
+ 63.1 1.0 1.0
+ 63.4 1.0 1.0
+ 68.4 1.0 1.0
+ 71.1 1.0 1.0
+ 73.3 1.0 1.0
+ 75.7 1.0 1.0
+ 76.1 1.0 1.0
+ 78.4 1.0 1.0
+ 84.3 1.0 1.0
+ 86.3 1.0 1.0
+ 87.0 1.0 1.0
+ 89.0 1.0 1.0
+ 90.6 1.0 1.0
+ 93.4 1.0 1.0
+ 99.4 1.0 1.0
+ 100.4 1.0 1.0
+ 102.1 1.0 1.0
+ 105.7 1.0 1.0
+ 112.4 1.0 1.0
+
+EXPECTED XYZ
+SAT1 31.444334 19.286094 6.888559
+SAT2 56.064662 44.030373 6.427599
+SAT3 67.324242 67.447159 7.468562
+SAT4 15.570651 29.465796 11.20434
+SAT5 21.619963 29.778971 41.25516
+SAT6 17.456572 19.372800 46.61877
+SAT7 24.114288 18.910816 30.96444
+SAT8 30.360635 18.858573 16.93814
+WBP1 55.603171 57.729295 46.42132
+WBP2 57.049606 60.324512 49.89966
+WBP3 53.811668 58.177050 49.42470
+WBP4 52.378305 57.343255 49.64556
+WBP5 52.469763 58.680177 51.97625
+WBL1 59.661034 59.332741 48.55177
+WBL2 59.041480 59.368909 48.29234
+WBL3 55.920447 58.052670 47.03935
+WBL4 55.083575 58.526581 51.10275
+WBL5 53.892264 58.200472 53.59833
+NEU1 3.151107 3.263644 2.737095
+NEU2 3.610326 3.768524 3.225077
+NEU3 4.585675 4.814770 4.063276
+NEU4 5.242110 5.523981 4.582603
+NEU5 44.365128 46.364955 37.75652
+NEU6 55.836099 58.281967 47.53593
+NEU7 70.627230 73.603361 59.69403
+NEU8 88.638466 92.368156 71.51666
+A1 11.411919 10.072672 5.112897
+A2 38.118655 34.074205 18.53409
+A3 16.687521 18.224488 25.41503
+A4 11.119565 13.272712 5.165291
+A5 23.995041 23.022599 32.25695
+A6 29.864887 41.242607 33.61720
+B1 40.774497 30.980646 4.853984
+B2 12.786912 11.654674 29.31582
+B3 29.900282 19.631992 10.31426
+B4 8.854344 6.750602 10.88177
+B5 35.445183 44.094908 8.863355
+B6 49.113465 43.647237 6.214123
+C1 6.659992 5.799339 20.11315
+C2 15.407588 23.700772 7.772715
+C3 21.254733 12.710445 3.970060
+C4 58.616280 59.203678 6.871706
+C5 31.444170 20.458848 23.34756
+C6 13.290512 19.046913 29.20373
+D1 87.016740 90.636247 69.99650
+D2 57.632418 59.860806 48.52846
+D3 35.434916 36.927843 30.23039
+D4 18.558911 19.319142 15.73822
+D5 8.770657 9.165214 7.636996
+D6 3.216922 3.320339 2.732945
diff --git a/scanin/ColorCheckerPassport.cie b/scanin/ColorCheckerPassport.cie
new file mode 100644
index 0000000..f25c019
--- /dev/null
+++ b/scanin/ColorCheckerPassport.cie
@@ -0,0 +1,64 @@
+CTI3
+DESCRIPTOR "ColorChecker Passport CIE data"
+ORIGINATOR "Ben Goren <ben@trumpetpower.com>"
+CREATED "Fri Aug 3 15:35:05 MST 2012"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 7
+BEGIN_DATA_FORMAT
+SAMPLE_LOC XYZ_X XYZ_Y XYZ_Z LAB_L LAB_A LAB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 50
+BEGIN_DATA
+SAT1 31.444334 19.286094 6.888559 51.020256 55.280672 28.133194
+SAT2 56.064662 44.030373 6.427599 72.248793 36.945117 66.729238
+SAT3 67.324242 67.447159 7.468562 85.729258 5.091307 85.588609
+SAT4 15.570651 29.465796 11.204340 61.190534 -60.437314 30.279584
+SAT5 21.619963 29.778971 41.255169 61.463043 -30.131006 -25.196180
+SAT6 17.456572 19.372800 46.618774 51.120542 -6.455450 -49.629615
+SAT7 24.114288 18.910816 30.964446 50.582702 28.026310 -29.474885
+SAT8 30.360635 18.858573 16.938149 50.521331 53.431168 -3.299773
+WBP1 55.603171 57.729295 46.421327 80.588052 -0.148185 1.410213
+WBP2 57.049606 60.324512 49.899666 82.014259 -2.717710 -0.156044
+WBP3 53.811668 58.177050 49.424708 80.837125 -5.740350 -1.647214
+WBP4 52.378305 57.343255 49.645561 80.372273 -7.424711 -2.699450
+WBP5 52.469763 58.680177 51.976257 81.115480 -10.390873 -4.020205
+WBL1 59.661034 59.332741 48.551776 81.474151 5.919789 0.449649
+WBL2 59.041480 59.368909 48.292349 81.493953 4.354460 0.782852
+WBL3 55.920447 58.052670 47.039351 80.768065 -0.134018 0.991035
+WBL4 55.083575 58.526581 51.102758 81.030672 -3.356452 -3.200486
+WBL5 53.892264 58.200472 53.598335 80.850119 -5.590938 -6.243136
+NEU1 3.151107 3.263644 2.737095 21.070257 0.072763 -0.353478
+NEU2 3.610326 3.768524 3.225077 22.890939 -0.358852 -0.826826
+NEU3 4.585675 4.814770 4.063276 26.200395 -0.743922 -0.554941
+NEU4 5.242110 5.523981 4.582603 28.178271 -1.007717 -0.143878
+NEU5 44.365128 46.364955 37.756524 73.781723 -0.983457 0.663808
+NEU6 55.836099 58.281967 47.535933 80.895303 -0.892210 0.628840
+NEU7 70.627230 73.603361 59.694037 88.734687 -0.724494 1.018307
+NEU8 88.638466 92.368156 71.516660 96.970594 -0.771975 4.070471
+A1 11.411919 10.072672 5.112897 37.972545 12.849750 13.905933
+A2 38.118655 34.074205 18.534096 65.021429 17.736538 18.105244
+A3 16.687521 18.224488 25.415039 49.767263 -4.838656 -21.688821
+A4 11.119565 13.272712 5.165291 43.171313 -11.673243 22.599880
+A5 23.995041 23.022599 32.256955 55.095608 8.054000 -23.674108
+A6 29.864887 41.242607 33.617201 70.345563 -33.879730 0.591375
+B1 40.774497 30.980646 4.853984 62.491292 36.974257 57.538878
+B2 12.786912 11.654674 29.315826 40.661930 10.745627 -43.972357
+B3 29.900282 19.631992 10.314269 51.418556 47.835790 16.229131
+B4 8.854344 6.750602 10.881778 31.232269 21.992198 -20.376399
+B5 35.445183 44.094908 8.863355 72.291888 -22.389553 57.145982
+B6 49.113465 43.647237 6.214123 71.992078 20.037754 67.243006
+C1 6.659992 5.799339 20.113152 28.900464 11.613838 -47.531575
+C2 15.407588 23.700772 7.772715 55.786947 -38.099805 32.761011
+C3 21.254733 12.710445 3.970060 42.323678 50.646029 27.808803
+C4 58.616280 59.203678 6.871706 81.403423 3.722966 80.589317
+C5 31.444170 20.458848 23.347563 52.352077 49.539466 -13.465303
+C6 13.290512 19.046913 29.203736 50.742046 -29.398805 -26.412062
+D1 87.016740 90.636247 69.996509 96.260066 -0.692605 4.206323
+D2 57.632418 59.860806 48.528468 81.762472 -0.207864 0.973581
+D3 35.434916 36.927843 30.230398 67.222860 -0.574879 0.364223
+D4 18.558911 19.319142 15.738222 51.058515 -0.355289 0.481164
+D5 8.770657 9.165214 7.636996 36.300462 -0.566396 -0.303560
+D6 3.216922 3.320339 2.732945 21.283684 0.258119 0.046995
+END_DATA
diff --git a/scanin/ColorCheckerSG.cht b/scanin/ColorCheckerSG.cht
new file mode 100644
index 0000000..1836f73
--- /dev/null
+++ b/scanin/ColorCheckerSG.cht
@@ -0,0 +1,203 @@
+
+BOXES 141
+ F _ _ 26.09 18.7 239.15 18.7 239.15 171.9 26.09 171.9
+ D ALL ALL _ _ 263.95 185.5 0 0 0 0
+ X A N 1 10 12.675 12.75 27.5 20.0 15.175 15.25
+
+BOX_SHRINK 1.6
+
+XLIST 28
+ 27.5 1.0 1.0
+ 40.175 1.0 1.0
+ 42.675 1.0 1.0
+ 55.35 1.0 1.0
+ 57.85 1.0 1.0
+ 70.525 1.0 1.0
+ 73.025 1.0 1.0
+ 85.7 1.0 1.0
+ 88.2 1.0 1.0
+ 100.875 1.0 1.0
+ 103.375 1.0 1.0
+ 116.05 1.0 1.0
+ 118.55 1.0 1.0
+ 131.225 1.0 1.0
+ 133.725 1.0 1.0
+ 146.4 1.0 1.0
+ 148.9 1.0 1.0
+ 161.575 1.0 1.0
+ 164.075 1.0 1.0
+ 176.75 1.0 1.0
+ 179.25 1.0 1.0
+ 191.925 1.0 1.0
+ 194.425 1.0 1.0
+ 207.1 1.0 1.0
+ 209.6 1.0 1.0
+ 222.275 1.0 1.0
+ 224.775 1.0 1.0
+ 237.45 1.0 1.0
+
+YLIST 20
+ 20.0 1.0 1.0
+ 32.75 1.0 1.0
+ 35.25 1.0 1.0
+ 48.0 1.0 1.0
+ 50.5 1.0 1.0
+ 63.25 1.0 1.0
+ 65.75 1.0 1.0
+ 78.5 1.0 1.0
+ 81.0 1.0 1.0
+ 93.75 1.0 1.0
+ 96.25 1.0 1.0
+ 109.0 1.0 1.0
+ 111.5 1.0 1.0
+ 124.25 1.0 1.0
+ 126.75 1.0 1.0
+ 139.5 1.0 1.0
+ 142.0 1.0 1.0
+ 154.75 1.0 1.0
+ 157.25 1.0 1.0
+ 170.0 1.0 1.0
+
+
+EXPECTED XYZ 140
+ A1 88.25 87.51 67.62
+ A2 0.79 0.79 0.62
+ A3 18.38 18.15 14.12
+ A4 88.68 87.94 68.1
+ A5 0.82 0.81 0.66
+ A6 18.44 18.2 14.18
+ A7 88.65 87.9 67.95
+ A8 0.83 0.82 0.66
+ A9 18.12 17.89 13.95
+ A10 88.87 88.13 68.08
+ B1 18.02 17.8 13.91
+ B2 13.95 7.23 8.27
+ B3 35.63 27.85 32.84
+ B4 10.67 5.28 15.25
+ B5 14.41 15.79 39.4
+ B6 20.68 26.24 36.89
+ B7 1.45 2.35 2.56
+ B8 18.04 25.72 27.04
+ B9 3.38 3.27 1.58
+ B10 18.48 18.24 14.19
+ C1 0.83 0.81 0.66
+ C2 4.58 3.29 5.62
+ C3 14.6 11.31 24.29
+ C4 2.74 2.49 8.91
+ C5 22.92 25.79 40.25
+ C6 1.84 2.4 5.03
+ C7 26.45 26.69 42.35
+ C8 10.25 16.92 17.28
+ C9 19.05 27.21 12.27
+ C10 0.81 0.8 0.64
+ D1 88.5 87.75 67.91
+ D2 61.95 61.45 55.8
+ D3 70.83 63.53 49.33
+ D4 55.96 62.69 49.91
+ D5 71.17 64.56 44.57
+ D6 58.43 62.22 28.86
+ D7 38.57 30.13 8.72
+ D8 38.93 32.31 15.64
+ D9 9.71 17.25 8.69
+ D10 88.85 88.1 68.15
+ E1 18.14 17.91 13.97
+ E2 8.92 6.95 2.01
+ E3 39.66 29.42 2.06
+ E4 3.85 2.22 16.31
+ E5 88.54 87.8 67.91
+ E6 0.8 0.79 0.64
+ E7 57.95 50.11 24.14
+ E8 55.65 45.09 20.47
+ E9 1.8 2.87 1.55
+ E10 18.29 18.05 14.05
+ F1 0.82 0.81 0.65
+ F2 37.55 31.16 14.86
+ F3 9.34 7.46 25.35
+ F4 12.16 19.3 4.13
+ F5 54.56 53.71 42.14
+ F6 6.41 6.34 5.07
+ F7 35.94 31.61 12.54
+ F8 37.12 32.69 16.79
+ F9 17.63 26.21 16.52
+ F10 0.82 0.8 0.65
+ G1 88.12 87.38 67.64
+ G2 14.14 14.42 21.78
+ G3 27.07 16.15 6.53
+ G4 19.38 9.32 1.23
+ G5 33.43 32.97 25.94
+ G6 11.06 10.95 8.66
+ G7 16.15 13.52 3.95
+ G8 37.66 32.45 16.85
+ G9 21.4 28.64 6.94
+ G10 88.76 88.01 68.03
+ H1 18.23 18 14.03
+ H2 7.94 10.03 2.21
+ H3 5.33 3.13 7.61
+ H4 58.28 57.39 3.84
+ H5 18.06 17.83 13.93
+ H6 27.87 27.48 21.66
+ H7 40.98 36.13 18.85
+ H8 38.13 32.77 16.09
+ H9 10.91 18.91 3.26
+ H10 18.32 18.08 14.08
+ I1 0.88 0.87 0.69
+ I2 20.96 18.51 28.03
+ I3 33.58 40.91 5.29
+ I4 28.76 16.58 19.42
+ I5 8.34 8.25 6.47
+ I6 47.53 46.8 36.74
+ I7 18.56 14.28 2.54
+ I8 10.92 8.92 2.27
+ I9 17.44 28.57 5.55
+ I10 0.82 0.81 0.65
+ J1 88.45 87.71 67.89
+ J2 28.25 36.79 28.98
+ J3 46.48 40.82 3.05
+ J4 10.73 14.67 25.45
+ J5 1.95 1.94 1.63
+ J6 72.43 71.6 56.6
+ J7 39 31.84 12.66
+ J8 41.29 34.62 13.36
+ J9 34.26 30.19 5.4
+ J10 88.69 87.94 67.95
+ K1 18.29 18.06 14.09
+ K2 69.8 64.78 36.61
+ K3 65.69 71.95 50.54
+ K4 65.74 62.36 54.38
+ K5 56.64 60.89 55.78
+ K6 40.88 40.32 31.77
+ K7 14.74 14.56 11.28
+ K8 2.93 2.89 2.29
+ K9 26.26 30.23 4.54
+ K10 18.27 18.04 14.06
+ L1 0.86 0.85 0.69
+ L2 6.16 3.5 1.81
+ L3 26.34 13.44 1.4
+ L4 38.55 28.09 19.93
+ L5 39.77 29.23 14.66
+ L6 46.55 31.09 1.68
+ L7 40.32 44.89 2.28
+ L8 30.88 30.54 4.31
+ L9 34.35 43.52 4.2
+ L10 0.8 0.79 0.64
+ M1 18.19 17.97 14.01
+ M2 23.95 12.47 6.9
+ M3 4.92 2.88 3.25
+ M4 22.84 11.31 2.24
+ M5 37.86 20.94 3.23
+ M6 68.62 59.75 4.77
+ M7 62.14 60.57 3.46
+ M8 36.4 42.08 3.08
+ M9 3.85 2.98 0.82
+ M10 18.24 18.01 14.03
+ N1 88.23 87.51 67.77
+ N2 18.24 18.01 14.03
+ N3 0.9 0.89 0.72
+ N4 88.57 87.82 67.97
+ N5 18.12 17.9 13.96
+ N6 0.91 0.9 0.73
+ N7 88.71 87.96 67.97
+ N8 18.2 17.97 14
+ N9 0.84 0.83 0.67
+ N10 88.82 88.07 68.12
+
diff --git a/scanin/Hutchcolor.cht b/scanin/Hutchcolor.cht
new file mode 100644
index 0000000..fcc5135
--- /dev/null
+++ b/scanin/Hutchcolor.cht
@@ -0,0 +1,597 @@
+
+BOXES 639
+ F _ _ 99.5 25.5 815.5 25.5 816.5 565.5 99.5 565.5
+ D ALL ALL _ _ 716 540 99.5 25.5 0 0
+ Y 01 29 A V 24.689655 24.545454 99.5 25.5 24.689655 24.545454
+
+BOX_SHRINK 3.0
+
+REF_ROTATION 0.0
+
+XLIST 29
+ 100.0 0.362323 0.148148
+ 110.211740 0.039102 0.222222
+ 125.481836 0.971171 0.333333
+ 150.418808 0.792286 0.925926
+ 174.477814 0.734537 0.962963
+ 199.527718 0.787966 1.000000
+ 224.576901 0.650620 0.925926
+ 248.755279 0.417736 0.888889
+ 274.032480 0.613223 0.888889
+ 298.327154 0.543354 0.925926
+ 323.197333 0.847712 0.925926
+ 347.120895 0.812650 0.925926
+ 372.370502 0.860240 0.777778
+ 396.353101 0.679006 0.703704
+ 421.201328 1.000000 0.814815
+ 446.684199 0.456817 0.703704
+ 470.550542 0.508343 0.740741
+ 495.397842 0.625561 0.703704
+ 520.420248 0.386812 0.777778
+ 544.869239 0.452824 0.777778
+ 569.748767 0.547266 0.666667
+ 594.755774 0.465053 0.666667
+ 618.496351 0.477468 0.703704
+ 644.014919 0.454719 0.703704
+ 668.040606 0.479467 0.666667
+ 693.095409 0.514558 0.666667
+ 717.270886 0.882612 0.666667
+ 791.542805 0.771497 0.444444
+ 817.003432 0.882693 0.111111
+
+YLIST 24
+ 25.546595 1.000000 0.071429
+ 49.424472 0.975749 0.392857
+ 75.392921 0.738973 0.964286
+ 99.186517 0.910072 1.000000
+ 124.186786 0.852166 0.964286
+ 149.214757 0.795826 0.892857
+ 173.106047 0.641529 0.857143
+ 198.089764 0.742257 0.928571
+ 223.213674 0.604765 0.928571
+ 246.745099 0.949854 1.000000
+ 271.506325 0.862745 0.857143
+ 294.880215 0.786340 0.571429
+ 320.004798 0.644361 0.750000
+ 344.432584 0.421439 0.857143
+ 369.861483 0.378724 0.678571
+ 393.074962 0.877958 0.964286
+ 418.078441 0.680991 1.000000
+ 442.078222 0.783297 1.000000
+ 466.901848 0.648933 0.678571
+ 491.506012 0.239702 0.642857
+ 515.663175 0.154566 0.285714
+ 524.564065 0.106932 0.250000
+ 540.560259 0.769595 0.250000
+ 565.915658 0.797211 0.178571
+
+EXPECTED XYZ 528
+ A01 76.63 79.337 62.787
+ A15 0.049 0.047 0.04
+ A16 76.799 79.369 62.869
+ A29 76.788 79.423 62.902
+ B01 0.051 0.046 0.042
+ B02 23.742 12.069 27.69
+ B03 29.571 17.273 33.401
+ B04 36.377 24.341 39.101
+ B05 46.402 36.285 46.046
+ B06 60.163 54.778 54.102
+ B07 76.815 79.257 62.889
+ B08 70.22 73.135 37.781
+ B09 52.398 46.914 32.877
+ B10 37.18 27.08 27.417
+ B11 25.856 14.882 21.359
+ B12 19.163 9.224 17.005
+ B13 12.41 5.017 11.384
+ B14 68.099 66.231 58.21
+ B15 64.604 64.824 58.092
+ B16 58.787 61.057 57.489
+ B17 60.985 65.447 59.249
+ B18 62.617 69.06 60.756
+ B19 61.499 67.999 56.83
+ B20 59.996 66.835 49.738
+ B21 66.383 71.172 50.262
+ B22 72.856 75.172 50.47
+ B23 68.187 68.027 48.999
+ B24 63.438 60.952 47.208
+ B25 65.486 62.759 54.536
+ B26 74.738 77.87 62.671
+ B27 76.752 79.251 62.956
+ B28 72.734 74.343 59.875
+ B29 0.046 0.043 0.032
+ C01 21.633 22.888 20.349
+ C02 18.412 9.88 27.737
+ C03 22.631 14.555 33.706
+ C04 27.389 20.594 38.954
+ C05 34.465 30.776 45.359
+ C06 43.817 46.079 52.702
+ C07 51.156 60.04 58.504
+ C08 46.443 56.25 36.915
+ C09 37.868 39.579 33.063
+ C10 27.157 22.631 27.438
+ C11 19.372 12.293 21.901
+ C12 14.769 7.361 17.468
+ C13 9.986 4.001 11.409
+ C14 53.009 44.867 50.025
+ C15 43.073 40.486 49.663
+ C16 33.474 35.535 49.096
+ C17 39.616 46.653 54.254
+ C18 43.877 54.8 57.684
+ C19 39.842 51.529 40.856
+ C20 37.241 49.298 27.293
+ C21 49.103 57.6 26.678
+ C22 68.052 71.088 26.663
+ C23 54.158 50.585 23.324
+ C24 42.126 34.204 20.788
+ C25 44.759 35.882 34.073
+ C26 63.526 65.924 58.034
+ C27 66.134 68.606 57.21
+ C28 66.402 69.263 52.556
+ C29 21.945 23.311 20.081
+ D02 11.393 6.774 27.149
+ D03 14.898 11.118 33.316
+ D04 18.919 16.908 38.782
+ D05 25.042 26.809 45.487
+ D06 32.814 40.626 52.643
+ D07 38.506 50.724 57.005
+ D08 34.084 47.3 37.959
+ D09 27.203 34.516 34.19
+ D10 18.226 18.563 28.41
+ D11 11.924 8.905 22.544
+ D12 8.489 4.576 17.784
+ D13 5.402 2.081 11.094
+ D14 41.275 29.968 42.582
+ D15 28.108 24.154 42.115
+ D16 20.099 21.735 43.019
+ D17 29.182 37.879 52.109
+ D18 35.153 47.891 56.53
+ D19 30.314 44.189 35.897
+ D20 26.406 40.305 16.077
+ D21 38.111 48.316 13.175
+ D22 65.451 67.965 13.429
+ D23 43.805 37.363 9.249
+ D24 27.598 18.034 7.037
+ D25 30.174 19.545 20.547
+ D26 58.48 57.966 51.192
+ D27 54.554 56.734 46.744
+ D28 53.009 56.386 44.417
+ E02 8.386 5.781 27.763
+ E03 11.574 10.412 34.225
+ E04 15.311 16.641 40.002
+ E05 21.099 27.099 47.037
+ E06 27.464 38.835 53.265
+ E07 30.583 43.614 55.324
+ E08 27.553 41.253 43.72
+ E09 23.131 33.91 40.619
+ E10 15.049 18.612 33.316
+ E11 9.165 8.213 26.012
+ E12 5.821 3.476 19.352
+ E13 3.178 1.134 11.065
+ E14 32.772 20.441 36.137
+ E15 18.574 14.486 36.000
+ E16 12.165 13.283 37.532
+ E17 20.936 30.082 49.114
+ E18 26.179 39.081 53.662
+ E19 21.215 35.148 32.511
+ E20 16.763 30.052 8.608
+ E21 30.574 41.333 6.293
+ E22 63.883 65.154 6.804
+ E23 36.079 27.5 3.064
+ E24 18.426 9.673 1.782
+ E25 20.328 10.668 11.479
+ E26 47.129 50.747 43.494
+ E27 45.528 47.626 39.123
+ E28 44.554 44.762 35.204
+ F02 6.368 4.959 27.103
+ F03 8.954 9.421 33.626
+ F04 12.046 15.412 39.432
+ F05 16.445 24.385 45.858
+ F06 20.113 31.659 50.153
+ F07 22.051 34.426 51.578
+ F08 19.632 32.109 44.547
+ F09 17.001 27.957 42.024
+ F10 11.577 16.618 35.22
+ F11 6.918 7.101 27.029
+ F12 4.309 2.758 19.695
+ F13 2.222 0.731 10.705
+ F14 26.945 14.78 30.904
+ F15 12.401 8.777 30.923
+ F16 6.658 6.438 29.4
+ F17 12.797 19.297 42.136
+ F18 18.427 29.885 49.126
+ F19 12.294 24.337 23.523
+ F20 8.47 18.427 2.954
+ F21 25.113 35.116 2.692
+ F22 62.917 62.389 3.348
+ F23 29.138 19.14 0.691
+ F24 12.647 5.718 0.185
+ F25 14.014 6.371 5.555
+ F26 35.636 36.998 34.385
+ F27 37.357 39.073 32.505
+ F28 39.18 41.212 29.994
+ G02 4.654 3.718 23.728
+ G03 6.283 6.908 29.334
+ G04 8.163 11.056 34.327
+ G05 10.842 17.236 39.952
+ G06 13.027 21.956 43.616
+ G07 14.821 24.858 45.838
+ G08 12.501 21.969 39.898
+ G09 10.848 18.953 37.473
+ G10 7.763 11.612 31.571
+ G11 5.023 5.215 24.355
+ G12 3.357 2.126 17.864
+ G13 1.743 0.552 9.45
+ G14 13.383 5.464 14.796
+ G15 4.308 1.645 13.987
+ G16 2.167 0.77 11.785
+ G17 6.278 7.264 29.187
+ G18 12.468 21.262 42.54
+ G19 7.159 16.892 13.939
+ G20 4.6 10.846 0.834
+ G21 19.409 27.107 1.076
+ G22 47.378 44.339 1.058
+ G23 22.289 13.428 0.239
+ G24 8.959 3.816 0.018
+ G25 9.579 4.041 2.544
+ G26 31.736 31.893 28.491
+ G27 30.165 31.682 26.269
+ G28 29.662 31.861 25.568
+ H02 0.461 0.186 2.441
+ H03 0.941 0.992 4.564
+ H04 1.756 3.154 6.521
+ H05 3.582 8.288 8.926
+ H06 6.013 14.762 11.175
+ H07 7.642 17.876 13.524
+ H08 9.843 19.999 25.663
+ H09 8.177 16.912 23.1
+ H10 5.372 9.823 18.883
+ H11 3.192 4.082 14.531
+ H12 2.003 1.475 10.492
+ H13 1.061 0.343 5.739
+ H14 6.674 2.663 8.453
+ H15 2.34 0.823 8.659
+ H16 1.424 0.443 7.72
+ H17 3.7 3.583 18.392
+ H18 8.309 14.901 28.931
+ H19 4.341 11.205 6.88
+ H20 3.147 7.651 0.625
+ H21 10.944 16.126 0.762
+ H22 21.411 20.364 0.606
+ H23 9.9 6.02 0.151
+ H24 5.002 2.171 0.019
+ H25 5.207 2.252 1.331
+ H26 26.152 28.536 24.809
+ H27 24.71 26.089 21.71
+ H28 23.442 23.841 19.131
+ I02 0.623 0.275 2.27
+ I03 1.358 1.348 4.048
+ I04 2.894 4.478 5.928
+ I05 6.469 12.434 8.339
+ I06 11.078 22.462 10.722
+ I07 13.785 26.952 13.421
+ I08 16.457 29.743 27.76
+ I09 13.658 25.303 24.605
+ I10 8.595 14.351 20.015
+ I11 4.549 5.587 14.961
+ I12 2.594 1.929 10.771
+ I13 1.342 0.462 6.167
+ I14 2.562 1.067 3.842
+ I15 1.095 0.427 4.104
+ I16 0.725 0.257 3.88
+ I17 1.545 1.606 7.557
+ I18 3.219 6.001 11.357
+ I19 1.747 4.545 2.842
+ I20 1.353 3.291 0.356
+ I21 4.249 6.369 0.411
+ I22 7.927 7.76 0.334
+ I23 3.799 2.502 0.109
+ I24 1.902 0.861 0.02
+ I25 1.978 0.901 0.681
+ I26 19.442 20.5 19.781
+ I27 19.851 21.168 17.794
+ I28 20.769 22.202 16.051
+ J02 1.401 0.622 2.136
+ J03 2.702 2.007 3.488
+ J04 5.051 5.588 5.045
+ J05 9.951 14.434 7.059
+ J06 16.982 27.791 9.331
+ J07 21.361 35.241 11.98
+ J08 23.982 38.364 25.345
+ J09 19.362 30.687 21.964
+ J10 11.868 16.245 17.578
+ J11 6.56 6.591 13.379
+ J12 3.902 2.573 9.871
+ J13 2.147 0.819 6.098
+ J14 0.76 0.365 1.233
+ J15 0.36 0.181 1.226
+ J16 0.239 0.122 1.194
+ J17 0.451 0.554 1.991
+ J18 0.797 1.511 2.705
+ J19 0.492 1.178 0.84
+ J20 0.405 0.916 0.16
+ J21 0.959 1.409 0.164
+ J22 2.126 2.146 0.166
+ J23 1.144 0.84 0.077
+ J24 0.574 0.286 0.025
+ J25 0.588 0.301 0.282
+ J26 15.996 16.353 15.287
+ J27 15.535 16.669 14.029
+ J28 15.219 16.756 13.611
+ K02 3.453 1.498 2.025
+ K03 5.457 3.199 3.005
+ K04 8.24 6.666 4.026
+ K05 13.803 15.032 5.462
+ K06 22.068 29.259 7.331
+ K07 28.861 41.569 10.129
+ K08 30.536 43.905 20.585
+ K09 23.641 31.285 17.109
+ K10 15.215 16.368 13.852
+ K11 9.442 7.446 10.876
+ K12 6.523 3.691 8.576
+ K13 4.218 1.708 5.864
+ K14 0.11 0.08 0.178
+ K15 0.057 0.052 0.165
+ K16 0.056 0.05 0.163
+ K17 0.084 0.11 0.219
+ K18 0.12 0.202 0.266
+ K19 0.097 0.169 0.114
+ K20 0.092 0.152 0.055
+ K21 0.091 0.149 0.054
+ K22 0.176 0.204 0.055
+ K23 0.118 0.109 0.036
+ K24 0.083 0.058 0.024
+ K25 0.084 0.062 0.055
+ K26 13.207 14.81 13.496
+ K27 11.931 12.895 11.183
+ K28 11.35 11.769 9.683
+ L01 76.732 79.364 62.827
+ L02 7.664 3.259 1.993
+ L03 11.545 5.898 2.9
+ L04 15.727 10.146 3.785
+ L05 23.087 19.47 4.953
+ L06 33.342 35.063 6.642
+ L07 41.546 50.533 9.282
+ L08 43.151 53.11 19.221
+ L09 34.773 37.02 16.135
+ L10 24.286 20.62 13.122
+ L11 16.886 10.882 10.491
+ L12 12.652 6.416 8.353
+ L13 8.532 3.519 5.826
+ L14 76.675 79.226 62.699
+ L15 0.038 0.035 0.025
+ L16 21.288 22.639 19.359
+ L26 9.11 9.854 9.906
+ L27 9.204 10.05 8.65
+ L28 9.602 10.532 7.77
+ L29 0.04 0.037 0.028
+ M02 9.87 4.175 1.899
+ M03 15.719 7.67 2.788
+ M04 22.009 12.713 3.541
+ M05 32.688 23.723 4.613
+ M06 47.45 42.107 6.039
+ M07 64.575 66.511 9.359
+ M08 66.43 69.356 18.887
+ M09 48.955 44.07 15.064
+ M10 34.018 24.945 12.469
+ M11 23.221 13.444 9.974
+ M12 16.908 8.226 8.018
+ M13 10.7 4.424 5.556
+ M14 37.403 32.664 35.56
+ M15 32.819 30.306 35.072
+ M16 26.055 26.69 34.653
+ M17 31.517 36.319 38.023
+ M18 34.22 41.544 39.547
+ M19 33.174 40.732 33.899
+ M20 31.317 39.16 23.785
+ M21 39.198 43.977 23.638
+ M22 45.035 47.614 23.798
+ M23 41.489 41.406 22.88
+ M24 34.664 30.711 20.744
+ M25 36.343 31.891 30.185
+ M26 7.308 7.575 7.29
+ M27 7.054 7.689 6.661
+ M28 6.736 7.597 6.317
+ N02 9.564 4.071 0.433
+ N03 15.244 7.361 0.692
+ N04 21.49 12.159 0.981
+ N05 32.074 22.601 1.513
+ N06 46.699 40.175 2.375
+ N07 63.358 63.683 4.666
+ N08 61.976 59.689 1.924
+ N09 46.634 38.442 0.816
+ N10 32.085 21.804 0.415
+ N11 21.453 11.832 0.181
+ N12 15.04 7.149 0.074
+ N13 9.388 3.991 0.02
+ N14 35.079 32.892 32.747
+ N15 32.606 31.487 32.409
+ N16 28.131 29.186 32.205
+ N17 31.664 35.404 34.064
+ N18 33.404 38.542 34.958
+ N19 32.65 37.87 31.68
+ N20 31.542 36.992 25.464
+ N21 36.414 39.679 25.151
+ N22 39.129 41.364 25.394
+ N23 37.199 38.042 24.882
+ N24 33.221 31.488 23.357
+ N25 34.4 32.364 29.693
+ N26 5.531 6.401 6.067
+ N27 4.987 5.505 4.891
+ N28 4.581 4.801 4.063
+ O02 7.307 3.137 0.433
+ O03 11.063 5.574 0.707
+ O04 15.275 9.584 1.061
+ O05 22.42 18.23 1.628
+ O06 32.349 32.649 2.497
+ O07 40.54 47.841 4.313
+ O08 40.237 44.49 1.571
+ O09 32.794 30.944 0.812
+ O10 22.853 17.525 0.434
+ O11 15.44 9.303 0.194
+ O12 11.054 5.451 0.077
+ O13 7.224 3.094 0.021
+ O14 34.294 34.203 31.000
+ O15 33.121 33.542 30.87
+ O16 31.021 32.405 30.573
+ O17 32.709 35.229 31.551
+ O18 33.535 36.782 31.879
+ O19 33.11 36.372 30.011
+ O20 32.623 35.989 27.478
+ O21 34.678 37.087 27.421
+ O22 35.836 37.705 27.441
+ O23 35.015 36.226 27.209
+ O24 33.385 33.432 26.6
+ O25 34.104 34.07 29.423
+ O26 3.264 3.634 3.923
+ O27 3.356 3.715 3.454
+ O28 3.505 3.974 3.077
+ P02 3.123 1.387 0.434
+ P03 4.978 2.868 0.72
+ P04 7.69 6.024 1.097
+ P05 13.026 13.656 1.794
+ P06 20.866 26.635 2.733
+ P07 27.647 38.762 4.545
+ P08 26.873 34.908 1.482
+ P09 20.633 24.173 0.833
+ P10 13.01 12.581 0.452
+ P11 7.668 5.626 0.201
+ P12 4.955 2.744 0.083
+ P13 3.065 1.355 0.022
+ P14 11.506 6.825 13.879
+ P15 7.899 5.228 14.444
+ P16 5.052 4.19 17.555
+ P17 10.715 14.734 26.092
+ P18 15.327 24.08 30.67
+ P19 13.062 22.129 18.974
+ P20 10.514 18.873 5.22
+ P21 16.35 20.537 3.911
+ P22 21.802 22.81 3.581
+ P23 16.148 14.308 2.827
+ P24 9.332 5.626 1.729
+ P25 10.413 6.295 7.89
+ P26 2.481 2.647 2.748
+ P27 2.24 2.556 2.402
+ P28 2.085 2.463 2.166
+ Q02 1.092 0.522 0.456
+ Q03 2.16 1.621 0.814
+ Q04 4.314 4.723 1.353
+ Q05 8.882 12.573 2.169
+ Q06 15.507 24.675 3.276
+ Q07 19.737 32.052 4.983
+ Q08 18.787 28.048 1.414
+ Q09 15.056 21.662 0.911
+ Q10 8.8 11.263 0.541
+ Q11 4.288 4.253 0.241
+ Q12 2.144 1.488 0.093
+ Q13 1.037 0.489 0.025
+ Q14 9.661 6.986 11.373
+ Q15 7.814 6.216 12.03
+ Q16 5.87 5.682 14.411
+ Q17 9.735 12.66 18.551
+ Q18 12.576 18.175 20.725
+ Q19 11.486 17.281 14.793
+ Q20 9.913 15.513 6.281
+ Q21 13.03 15.869 5.096
+ Q22 15.405 16.598 4.712
+ Q23 12.441 11.949 4.157
+ Q24 8.247 6.088 3.129
+ Q25 9.056 6.64 7.831
+ Q26 1.635 1.969 1.965
+ Q27 1.464 1.693 1.616
+ Q28 1.358 1.499 1.326
+ R02 0.299 0.171 0.464
+ R03 0.8 0.952 0.9
+ R04 2.08 3.512 1.535
+ R05 5.297 10.401 2.45
+ R06 9.536 19.375 3.545
+ R07 12.138 24.003 5.201
+ R08 11.159 20.153 1.28
+ R09 9.046 16.391 0.89
+ R10 5.192 9.04 0.572
+ R11 2.019 3.032 0.264
+ R12 0.731 0.781 0.098
+ R13 0.242 0.135 0.024
+ R14 9.08 8.401 9.714
+ R15 8.492 8.242 10.094
+ R16 7.625 8.08 10.952
+ R17 9.408 11.104 12.207
+ R18 10.351 12.767 12.774
+ R19 9.979 12.455 10.779
+ R20 9.358 11.859 7.552
+ R21 10.401 11.969 6.926
+ R22 11.128 12.163 6.697
+ R23 10.211 10.67 6.45
+ R24 8.438 7.916 5.779
+ R25 8.908 8.293 8.294
+ R26 0.824 0.967 1.118
+ R27 0.892 1.044 0.995
+ R28 0.898 1.066 0.866
+ S02 0.108 0.076 0.463
+ S03 0.314 0.595 0.923
+ S04 0.895 2.271 1.497
+ S05 2.381 6.453 2.317
+ S06 4.54 12.112 3.23
+ S07 6 15.207 4.627
+ S08 5.164 12.038 1.021
+ S09 3.972 9.549 0.735
+ S10 2.102 5.137 0.479
+ S11 0.748 1.782 0.243
+ S12 0.201 0.412 0.099
+ S13 0.034 0.033 0.023
+ S14 1.725 1.253 2.271
+ S15 1.29 1.041 2.329
+ S16 0.733 0.725 2.351
+ S17 1.231 1.755 3.158
+ S18 1.614 2.609 3.588
+ S19 1.41 2.414 2.387
+ S20 1.173 2.065 0.872
+ S21 2.237 2.832 0.862
+ S22 2.94 3.185 0.824
+ S23 2.319 2.239 0.688
+ S24 1.415 1.023 0.463
+ S25 1.59 1.165 1.443
+ S26 0.517 0.577 0.634
+ S27 0.418 0.508 0.509
+ S28 0.389 0.49 0.474
+ T01 20.906 22.173 18.934
+ T14 1.673 1.457 2.146
+ T15 1.39 1.301 2.148
+ T16 0.95 1.044 2.135
+ T17 1.331 1.79 2.561
+ T18 1.571 2.278 2.786
+ T19 1.464 2.181 2.147
+ T20 1.302 1.983 1.137
+ T21 1.948 2.412 1.151
+ T22 2.312 2.604 1.125
+ T23 1.997 2.087 1.027
+ T24 1.446 1.262 0.839
+ T25 1.578 1.38 1.593
+ T26 0.226 0.308 0.356
+ T27 0.189 0.243 0.247
+ T28 0.177 0.205 0.205
+ T29 76.694 79.235 62.936
+ U01 0.04 0.037 0.026
+ U14 1.521 1.579 1.795
+ U15 1.449 1.541 1.83
+ U16 1.215 1.388 1.789
+ U17 1.372 1.691 1.882
+ U18 1.47 1.863 1.965
+ U19 1.436 1.833 1.767
+ U20 1.377 1.769 1.375
+ U21 1.604 1.908 1.358
+ U22 1.702 1.968 1.36
+ U23 1.61 1.806 1.34
+ U24 1.417 1.476 1.246
+ U25 1.493 1.552 1.626
+ U26 0.045 0.043 0.088
+ U27 0.044 0.048 0.036
+ U28 0.059 0.074 0.038
+ U29 0.042 0.039 0.029
+ V01 76.341 78.885 62.676
+ V14 21.197 22.447 19.277
+ V15 76.612 79.131 62.823
+ V26 0.039 0.036 0.025
+ V27 0.04 0.037 0.026
+ V28 0.039 0.037 0.026
+ V29 0.038 0.035 0.027
+
diff --git a/scanin/Jamfile b/scanin/Jamfile
new file mode 100644
index 0000000..b6e58f1
--- /dev/null
+++ b/scanin/Jamfile
@@ -0,0 +1,33 @@
+
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ;
+
+#Products
+Libraries = libscanrd ;
+Executables = scanin ;
+Headers = scanrd.h ;
+Samples = it8.cht ColorChecker.cht ColorChecker.cie ColorCheckerDC.cht
+ ColorCheckerSG.cht Hutchcolor.cht i1_RGB_Scan_1.4.cht
+ ColorCheckerPassport.cht ColorCheckerPassport.cie
+ QPcard_201.cht QPcard_201.cie QPcard_202.cht QPcard_202.cie CMP_DT_003.cht
+ CMP_Digital_Target-3.cht CMP_Digital_Target-3.ti2 CMP_Digital_Target-3.cie
+ LaserSoftDCPro.cht SpyderChecker.cht SpyderChecker.cie ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+InstallFile $(DESTDIR)$(PREFIX)/$(REFSUBDIR) : $(Samples) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+# Chart recognition library
+Library libscanrd : scanrd.c : : : ../numlib ;
+
+# IT8 chart reader - sucks in tiff file and spits out cgats file
+Main scanin : scanin.c ;
+# ObjectHdrs scanin : ../h ../cgats ../numlib ../icc ../rspl ../gamut ../xicc $(TIFFINC) ;
+ObjectHdrs scanin : ../h ../numlib ../icc ../cgats ../rspl ../xicc ../gamut ../spectro $(TIFFINC) ;
+LinkLibraries scanin : libscanrd ../xicc/libxicc ../spectro/libinsttypes
+ ../gamut/libgamut ../rspl/librspl ../cgats/libcgats
+ ../icc/libicc ../numlib/libnum ../plot/libplot ../plot/libvrml $(TIFFLIB) $(JPEGLIB) ;
diff --git a/scanin/LaserSoftDCPro.cht b/scanin/LaserSoftDCPro.cht
new file mode 100644
index 0000000..e5df741
--- /dev/null
+++ b/scanin/LaserSoftDCPro.cht
@@ -0,0 +1,202 @@
+
+BOXES 141
+ F _ _ 26.09 18.7 239.15 18.7 239.15 171.9 26.09 171.9
+ D ALL ALL _ _ 263.95 185.5 0 0 0 0
+ Y 1 14 A J 12.675 12.75 27.5 20.0 15.175 15.25
+
+BOX_SHRINK 1.6
+
+XLIST 28
+ 27.5 1.0 1.0
+ 40.175 1.0 1.0
+ 42.675 1.0 1.0
+ 55.35 1.0 1.0
+ 57.85 1.0 1.0
+ 70.525 1.0 1.0
+ 73.025 1.0 1.0
+ 85.7 1.0 1.0
+ 88.2 1.0 1.0
+ 100.875 1.0 1.0
+ 103.375 1.0 1.0
+ 116.05 1.0 1.0
+ 118.55 1.0 1.0
+ 131.225 1.0 1.0
+ 133.725 1.0 1.0
+ 146.4 1.0 1.0
+ 148.9 1.0 1.0
+ 161.575 1.0 1.0
+ 164.075 1.0 1.0
+ 176.75 1.0 1.0
+ 179.25 1.0 1.0
+ 191.925 1.0 1.0
+ 194.425 1.0 1.0
+ 207.1 1.0 1.0
+ 209.6 1.0 1.0
+ 222.275 1.0 1.0
+ 224.775 1.0 1.0
+ 237.45 1.0 1.0
+
+YLIST 20
+ 20.0 1.0 1.0
+ 32.75 1.0 1.0
+ 35.25 1.0 1.0
+ 48.0 1.0 1.0
+ 50.5 1.0 1.0
+ 63.25 1.0 1.0
+ 65.75 1.0 1.0
+ 78.5 1.0 1.0
+ 81.0 1.0 1.0
+ 93.75 1.0 1.0
+ 96.25 1.0 1.0
+ 109.0 1.0 1.0
+ 111.5 1.0 1.0
+ 124.25 1.0 1.0
+ 126.75 1.0 1.0
+ 139.5 1.0 1.0
+ 142.0 1.0 1.0
+ 154.75 1.0 1.0
+ 157.25 1.0 1.0
+ 170.0 1.0 1.0
+
+EXPECTED XYZ 140
+ A1 95.054 99.997 108.93
+ A2 1.1997 1.1177 1.8435
+ A3 6.7205 6.2574 11.555
+ A4 95.054 99.997 108.93
+ A5 95.054 99.997 108.93
+ A6 95.054 99.997 108.93
+ A7 0.49927 0.43693 0.87678
+ A8 95.054 99.997 108.93
+ A9 95.054 99.997 108.93
+ A10 95.054 99.997 108.93
+ A11 95.054 99.997 108.93
+ A12 5.5560 5.1972 9.8224
+ A13 1.0432 0.94378 1.8118
+ A14 95.054 99.997 108.93
+ B1 95.054 99.997 108.93
+ B2 67.091 47.876 87.898
+ B3 11.506 12.701 30.786
+ B4 58.530 82.881 29.773
+ B5 51.017 26.596 49.038
+ B6 13.118 10.105 52.231
+ B7 81.415 94.542 37.089
+ B8 44.474 25.101 11.115
+ B9 21.340 12.736 95.969
+ B10 66.377 85.211 107.59
+ B11 42.717 22.847 6.6395
+ B12 95.054 99.997 108.93
+ B13 78.392 91.406 108.15
+ B14 95.054 99.997 108.93
+ C1 0.91819 0.83268 1.3889
+ C2 78.242 93.273 20.381
+ C3 39.945 21.012 96.586
+ C4 95.054 99.997 108.93
+ C5 8.0062 6.3371 5.5237
+ C6 95.054 99.997 108.93
+ C7 95.054 99.997 108.93
+ C8 95.054 99.997 108.93
+ C9 95.054 99.997 108.93
+ C10 26.464 19.481 13.094
+ C11 55.073 48.678 101.13
+ C12 77.003 92.778 13.853
+ C13 43.434 22.924 11.065
+ C14 0.78528 0.68981 1.5301
+ D1 5.7964 5.4769 9.7970
+ D2 72.996 88.624 107.90
+ D3 86.456 96.558 63.644
+ D4 62.452 84.629 42.335
+ D5 92.459 98.959 95.262
+ D6 35.935 71.602 11.974
+ D7 60.015 81.931 107.29
+ D8 59.633 29.164 97.123
+ D9 20.716 10.192 95.511
+ D10 95.054 99.997 108.93
+ D11 77.045 92.795 14.074
+ D12 43.764 31.444 13.884
+ D13 95.054 99.997 108.93
+ D14 5.4327 5.0906 9.4972
+ E1 95.054 99.997 108.93
+ E2 93.580 97.048 108.44
+ E3 95.054 99.997 108.93
+ E4 95.054 99.997 108.93
+ E5 95.054 99.997 108.93
+ E6 95.054 99.997 108.93
+ E7 0.56064 0.49941 0.85338
+ E8 95.054 99.997 108.93
+ E9 55.394 48.320 10.491
+ E10 95.054 99.997 108.93
+ E11 18.067 9.9172 10.525
+ E12 95.054 99.997 108.93
+ E13 51.153 77.999 78.081
+ E14 95.054 99.997 108.93
+ F1 95.054 99.997 108.93
+ F2 77.003 92.778 13.854
+ F3 95.054 99.997 108.93
+ F4 34.402 22.375 97.141
+ F5 95.054 99.997 108.93
+ F6 53.813 78.733 107.00
+ F7 95.054 99.997 108.93
+ F8 0.67207 0.58997 1.0828
+ F9 60.272 30.442 97.336
+ F10 52.097 40.728 12.472
+ F11 77.003 92.778 13.853
+ F12 95.054 99.997 108.93
+ F13 10.781 6.4490 18.321
+ F14 95.054 99.997 108.93
+ G1 95.054 99.997 108.93
+ G2 55.324 79.512 107.07
+ G3 95.054 99.997 108.93
+ G4 83.272 95.285 46.871
+ G5 58.118 49.046 25.961
+ G6 42.215 22.651 3.9825
+ G7 35.762 71.514 11.921
+ G8 19.846 9.7483 95.471
+ G9 77.003 92.778 13.853
+ G10 95.054 99.997 108.93
+ G11 77.003 92.778 13.853
+ G12 95.054 99.997 108.93
+ G13 60.898 82.386 107.33
+ G14 95.054 99.997 108.93
+ H1 0.54264 0.48279 0.79835
+ H2 89.532 88.954 107.09
+ H3 77.759 93.080 17.834
+ H4 42.861 43.829 100.84
+ H5 36.752 71.940 15.774
+ H6 95.054 99.997 108.93
+ H7 95.054 99.997 108.93
+ H8 95.054 99.997 108.93
+ H9 95.054 99.997 108.93
+ H10 53.813 78.733 107.00
+ H11 15.498 10.161 46.468
+ H12 54.711 27.778 69.401
+ H13 46.548 76.933 18.826
+ H14 0.62698 0.56386 0.99911
+ I1 95.054 99.997 108.93
+ I2 78.269 93.284 20.520
+ I3 79.484 91.969 108.20
+ I4 95.054 99.997 108.93
+ I5 7.1761 7.4119 9.1084
+ I6 68.605 86.360 107.69
+ I7 49.882 38.374 5.3364
+ I8 6.2853 7.7839 9.5291
+ I9 95.054 99.997 108.93
+ I10 71.643 79.666 19.448
+ I11 61.032 72.662 49.370
+ I12 54.931 79.309 107.05
+ I13 79.147 93.635 25.144
+ I14 95.054 99.997 108.93
+ J1 95.054 99.997 108.93
+ J2 0.42397 0.37158 0.62164
+ J3 95.054 99.997 108.93
+ J4 95.054 99.997 108.93
+ J5 95.054 99.997 108.93
+ J6 95.054 99.997 108.93
+ J7 95.054 99.997 108.93
+ J8 95.054 99.997 108.93
+ J9 94.564 99.017 108.77
+ J10 50.473 49.809 73.299
+ J11 17.292 16.601 26.910
+ J12 3.7657 3.5269 5.6717
+ J13 0.50304 0.44681 0.73017
+ J14 95.054 99.997 108.93
+
diff --git a/scanin/License.txt b/scanin/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/scanin/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/scanin/Makefile.am b/scanin/Makefile.am
new file mode 100644
index 0000000..0e4f65a
--- /dev/null
+++ b/scanin/Makefile.am
@@ -0,0 +1,19 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libscanrd.la
+privatelibdir = $(pkglibdir)
+
+libscanrd_la_SOURCES = scanrd.h scanrd_.h scanrd.c
+libscanrd_la_LIBADD = ../rspl/librspl.la ../numlib/libargyllnum.la
+
+LDADD = ./libscanrd.la ../numlib/libargyllnum.la $(ICC_LIBS) \
+ ../cgats/libcgats.la ../xicc/libxicc.la $(TIFF_LIBS) \
+ ../libargyll.la
+
+bin_PROGRAMS = scanin
+
+refdir = $(datadir)/color/argyll/ref
+
+ref_DATA = $(wildcard *.cht) $(wildcard *.cie) $(wildcard *.ti2)
+
+EXTRA_DIST = $(ref_DATA) License.txt Readme.txt
diff --git a/scanin/QPcard_201.cht b/scanin/QPcard_201.cht
new file mode 100644
index 0000000..a9d9542
--- /dev/null
+++ b/scanin/QPcard_201.cht
@@ -0,0 +1,76 @@
+
+BOXES 31
+ F _ _ 0.0 0.0 1654.0 0.0 1654.0 478.0 0.0 478.0
+ D ALL ALL _ _ 1654.0 478.0 0.0 0.0 0 0
+ Y 1 10 A C 118.0 119.0 239.0 66.0 141.5 142.0
+
+BOX_SHRINK 15.0
+
+REF_ROTATION 0.0
+
+XLIST 22
+ 150.618062 0.144363 0.166667
+ 161.602137 0.245110 0.333333
+ 238.956434 0.946427 1.000000
+ 357.016882 0.855510 1.000000
+ 379.969304 0.948635 1.000000
+ 497.948383 0.927859 1.000000
+ 521.902072 1.000000 1.000000
+ 640.004059 0.922588 1.000000
+ 662.964760 0.948369 1.000000
+ 782.052769 0.951028 1.000000
+ 804.971146 0.886492 1.000000
+ 923.008950 0.922731 1.000000
+ 946.989395 0.865832 1.000000
+ 1066.007371 0.876333 1.000000
+ 1088.986522 0.865792 1.000000
+ 1208.017128 0.871015 1.000000
+ 1229.826796 0.868345 1.000000
+ 1349.181703 0.847707 1.000000
+ 1372.210921 0.767835 1.000000
+ 1490.553264 0.783286 1.000000
+ 1513.822380 0.891664 1.000000
+ 1633.171522 0.868381 1.000000
+
+YLIST 8
+ 65.941330 0.342831 1.000000
+ 184.978043 0.345580 1.000000
+ 207.991441 0.442638 1.000000
+ 325.524788 1.000000 1.000000
+ 348.940333 0.208095 1.000000
+ 366.421405 0.090483 0.647059
+ 378.396408 0.079155 0.617647
+ 466.955243 0.226972 0.000000
+
+EXPECTED XYZ 30
+ A1 47.8 50.5 53.2
+ A2 9.3 9.6 27.6
+ A3 60.7 62.1 11.2
+ A4 4.4 4.6 4.9
+ A5 10.5 11.1 11.9
+ A6 16.8 17.8 19.5
+ A7 32.9 34.7 36.8
+ A8 65.1 68.9 72.5
+ A9 81.8 86.6 91.0
+ A10 47.8 50.5 53.2
+ B1 36.9 43.1 7.0
+ B2 15.7 26.5 17.4
+ B3 29.8 19.5 20.8
+ B4 6.2 5.7 7.9
+ B5 10.1 12.3 6.8
+ B6 19.9 20.5 6.5
+ B7 11.0 9.9 6.8
+ B8 36.2 34.2 25.0
+ B9 60.7 67.5 73.7
+ B10 56.3 56.5 70.3
+ C1 47.8 50.5 53.2
+ C2 14.5 8.9 4.3
+ C3 18.6 24.8 52.5
+ C4 9.6 7.2 6.1
+ C5 18.0 19.8 34.8
+ C6 43.0 30.9 5.8
+ C7 57.0 49.6 6.6
+ C8 69.3 68.9 47.9
+ C9 64.5 69.9 59.9
+ C10 47.8 50.5 53.2
+
diff --git a/scanin/QPcard_201.cie b/scanin/QPcard_201.cie
new file mode 100644
index 0000000..ecd1a3a
--- /dev/null
+++ b/scanin/QPcard_201.cie
@@ -0,0 +1,42 @@
+IT8.7/2
+ORIGINATOR "Graeme Gill, ArgyllCMS"
+DESCRIPTOR "QPCard 201"
+CREATED "Nov 29, 2007"
+MANUFACTURER "QPcard AB"
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+SAMPLE_ID XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+NUMBER_OF_SETS 30
+BEGIN_DATA
+A1 47.8 50.5 53.2
+A2 9.3 9.6 27.6
+A3 60.7 62.1 11.2
+A4 4.4 4.6 4.9
+A5 10.5 11.1 11.9
+A6 16.8 17.8 19.5
+A7 32.9 34.7 36.8
+A8 65.1 68.9 72.5
+A9 81.8 86.6 91.0
+A10 47.8 50.5 53.2
+B1 36.9 43.1 7.0
+B2 15.7 26.5 17.4
+B3 29.8 19.5 20.8
+B4 6.2 5.7 7.9
+B5 10.1 12.3 6.8
+B6 19.9 20.5 6.5
+B7 11.0 9.9 6.8
+B8 36.2 34.2 25.0
+B9 60.7 67.5 73.7
+B10 56.3 56.5 70.3
+C1 47.8 50.5 53.2
+C2 14.5 8.9 4.3
+C3 18.6 24.8 52.5
+C4 9.6 7.2 6.1
+C5 18.0 19.8 34.8
+C6 43.0 30.9 5.8
+C7 57.0 49.6 6.6
+C8 69.3 68.9 47.9
+C9 64.5 69.9 59.9
+C10 47.8 50.5 53.2
+END_DATA
diff --git a/scanin/QPcard_202.cht b/scanin/QPcard_202.cht
new file mode 100644
index 0000000..4d10406
--- /dev/null
+++ b/scanin/QPcard_202.cht
@@ -0,0 +1,80 @@
+BOXES 36
+ F _ _ 22 20 638 22 638 440 20 440
+ D ALL ALL _ _ 655 455 0 0 0 0
+ Y 1 7 A E 68 68 45 30 83 83
+
+BOX_SHRINK 4.0
+
+REF_ROTATION 0.0
+
+XLIST 19
+ 43.608721 0.740781 0.800000
+ 114.976109 0.783190 0.800000
+ 126.951628 0.918228 0.900000
+ 198.016123 0.974824 0.900000
+ 210.073338 0.901194 1.000000
+ 281.139260 0.985920 1.000000
+ 294.215088 0.898482 1.000000
+ 364.783383 0.991485 1.000000
+ 377.849374 0.904129 1.000000
+ 448.984652 1.000000 1.000000
+ 460.979320 0.954860 1.000000
+ 532.024333 0.997190 1.000000
+ 544.239647 0.898460 1.000000
+ 615.407960 0.946305 1.000000
+ 631.910471 0.186078 0.000000
+ 636.058422 0.233922 0.000000
+ 642.588462 0.132382 0.000000
+ 643.533506 0.270593 0.000000
+ 644.296155 0.191706 0.000000
+
+YLIST 12
+ 26.695891 1.000000 0.875000
+ 98.238688 0.936512 1.000000
+ 110.194036 0.994019 1.000000
+ 181.442800 0.892945 1.000000
+ 194.417673 0.992089 0.937500
+ 264.518175 0.877113 0.875000
+ 277.701905 0.986234 1.000000
+ 347.941384 0.877209 1.000000
+ 360.406157 0.132648 0.312500
+ 361.033254 0.706971 0.875000
+ 431.983255 0.253427 0.750000
+ 432.622344 0.399964 0.000000
+
+EXPECTED XYZ 35
+A1 67.856459 69.512840 9.015609
+A2 67.076305 59.459332 7.827210
+A3 58.305183 45.461038 7.748888
+A4 52.785392 65.096997 59.594305
+A5 45.322673 55.739548 35.288307
+A6 58.323014 65.546227 28.470190
+A7 75.997301 76.369564 28.920869
+B1 27.185068 21.163573 31.661582
+B2 19.566090 10.470287 2.899649
+B3 7.735493 16.256731 8.259450
+B4 7.305847 10.044629 23.599855
+B5 38.157321 40.254508 6.905462
+B6 12.286120 18.850102 28.606420
+B7 70.618705 63.122300 27.332985
+C1 27.875888 20.161730 25.953035
+C2 21.562223 11.180011 4.672983
+C3 9.915698 19.077936 6.906382
+C4 9.400751 9.282240 29.346924
+C5 33.030305 38.085875 6.761389
+C6 12.379400 21.440342 24.610384
+C7 68.775747 59.666057 36.778798
+D1 30.312295 21.545103 20.899732
+D2 19.513673 10.562642 7.925905
+D3 9.957248 17.257178 4.623671
+D4 9.916827 8.308213 24.940996
+D5 24.060360 31.480055 7.467898
+D6 11.633929 19.652104 17.324887
+D7 64.052575 58.473280 56.362590
+E1 81.660435 84.707213 65.484182
+E2 61.845146 64.255877 51.551387
+E3 35.051455 36.358983 29.400605
+E4 22.483519 23.314508 19.344460
+E5 10.265340 10.652815 8.624928
+E6 5.291836 5.472343 4.344900
+E7 3.074245 3.153171 2.547055
diff --git a/scanin/QPcard_202.cie b/scanin/QPcard_202.cie
new file mode 100644
index 0000000..683b6c0
--- /dev/null
+++ b/scanin/QPcard_202.cie
@@ -0,0 +1,48 @@
+IT8.7/2
+ORIGINATOR "jose pereira jpereira.net"
+DESCRIPTOR "QPCARD 202"
+CREATED "may 2012"
+MANUFACTURER "QPcard"
+NUMBER_OF_FIELDS 7
+BEGIN_DATA_FORMAT
+SAMPLE_ID XYZ_X XYZ_Y XYZ_Z LAB_L LAB_A LAB_B
+END_DATA_FORMAT
+NUMBER_OF_SETS 35
+BEGIN_DATA
+A01 67.856459 69.512840 9.015609 86.757375 1.825575 81.545134
+A02 67.076305 59.459332 7.827210 81.543425 22.588491 76.956535
+A03 58.305183 45.461038 7.748888 73.194438 38.355857 62.867015
+A04 52.785392 65.096997 59.594305 84.533694 -24.307666 -6.124730
+A05 45.322673 55.739548 35.288307 79.465357 -22.724528 13.897787
+A06 58.323014 65.546227 28.470190 84.764423 -11.471673 33.441882
+A07 75.997301 76.369564 28.920869 90.030651 4.834878 41.785201
+B01 27.185068 21.163573 31.661582 53.128052 29.896273 -26.161046
+B02 19.566090 10.470287 2.899649 38.673581 58.158660 28.749194
+B03 7.735493 16.256731 8.259450 47.309526 -57.238786 16.283396
+B04 7.305847 10.044629 23.599855 37.922410 -20.845869 -38.815336
+B05 38.157321 40.254508 6.905462 69.650420 -2.091972 60.182723
+B06 12.286120 18.850102 28.606420 50.511369 -35.081968 -25.838514
+B07 70.618705 63.122300 27.332985 83.506686 21.791859 33.166706
+C01 27.875888 20.161730 25.953035 52.019576 37.428172 -18.752022
+C02 21.562223 11.180011 4.672983 39.882016 62.620005 19.536557
+C03 9.915698 19.077936 6.906382 50.778263 -53.582415 27.640637
+C04 9.400751 9.282240 29.346924 36.522120 3.739027 -51.160034
+C05 33.030305 38.085875 6.761389 68.083859 -12.577785 58.094494
+C06 12.379400 21.440342 24.610384 53.428091 -47.018893 -13.936155
+C07 68.775747 59.666057 36.778798 81.656338 25.812200 15.582830
+D01 30.312295 21.545103 20.899732 53.540986 40.234784 -6.655919
+D02 19.513673 10.562642 7.925905 38.833864 57.205173 2.937550
+D03 9.957248 17.257178 4.623671 48.582459 -43.791000 34.808467
+D04 9.916827 8.308213 24.940996 34.616704 16.088365 -46.965354
+D05 24.060360 31.480055 7.467898 62.910807 -25.347082 46.249115
+D06 11.633929 19.652104 17.324887 51.441570 -43.624665 -2.604415
+D07 64.052575 58.473280 56.362590 81.001208 18.165842 -8.910822
+E01 81.660435 84.707213 65.484182 93.756804 -0.027533 4.049779
+E02 61.845146 64.255877 51.551387 84.098816 -0.256360 1.591948
+E03 35.051455 36.358983 29.400605 66.793307 -0.019940 0.945311
+E04 22.483519 23.314508 19.344460 55.394826 0.016750 -0.239174
+E05 10.265340 10.652815 8.624928 38.989459 -0.046959 0.588338
+E06 5.291836 5.472343 4.344900 28.040182 0.184525 0.961005
+E07 3.074245 3.153171 2.547055 20.647174 0.585930 0.440283
+
+END_DATA
diff --git a/scanin/Readme.txt b/scanin/Readme.txt
new file mode 100644
index 0000000..2976595
--- /dev/null
+++ b/scanin/Readme.txt
@@ -0,0 +1,8 @@
+
+This directory contains the code to extract charts from
+TIFF scan files, and output the patch values using the
+CGATS file format. Typically this is used to get the
+patch information from a scan of an IT8 calibration
+chart.
+
+scanin.exe processes a TIFF file into a CGATS file.
diff --git a/scanin/SpyderChecker.cht b/scanin/SpyderChecker.cht
new file mode 100644
index 0000000..1c0ef3a
--- /dev/null
+++ b/scanin/SpyderChecker.cht
@@ -0,0 +1,115 @@
+BOXES 49
+ F _ _ 5 4 470 5 470 307 5 307
+
+ D ALL ALL _ _ 475 315 0 0 0 0
+
+ X A D 1 6 42 42 11 10 49 50
+ X E H 1 6 42 42 274 10 49 50
+
+
+BOX_SHRINK 3.0
+
+REF_ROTATION 0.0
+
+XLIST 27
+ 4.984973 0.109746 0.076923
+ 9.286927 0.952526 1.000000
+ 52.887948 0.925344 1.000000
+ 59.167435 1.000000 0.923077
+ 102.212773 0.458586 0.923077
+ 102.919173 0.494117 0.384615
+ 108.965439 0.995672 1.000000
+ 152.335524 0.929079 1.000000
+ 158.540776 0.956677 1.000000
+ 202.023990 0.948802 1.000000
+ 207.819679 0.348860 0.076923
+ 213.309915 0.948588 0.000000
+ 230.603930 0.364584 0.000000
+ 234.074857 0.305779 0.000000
+ 240.406366 0.419481 0.000000
+ 243.970119 0.780089 0.000000
+ 260.767091 0.913272 0.000000
+ 266.441147 0.117583 0.076923
+ 271.869223 0.913611 1.000000
+ 315.052562 0.921224 1.000000
+ 321.439873 0.976014 1.000000
+ 364.747788 0.940719 1.000000
+ 371.336194 0.968158 1.000000
+ 414.647393 0.874415 1.000000
+ 420.992026 0.882322 1.000000
+ 464.404335 0.944708 1.000000
+ 469.433263 0.121537 0.076923
+
+YLIST 22
+ 4.526138 1.000000 0.000000
+ 9.908960 0.796520 0.730769
+ 53.044496 0.103192 0.730769
+ 53.524920 0.636430 0.576923
+ 60.203792 0.830553 0.730769
+ 103.048172 0.307118 0.730769
+ 103.492169 0.530702 0.615385
+ 109.526018 0.312034 0.153846
+ 109.974584 0.523340 0.730769
+ 153.023131 0.597133 0.730769
+ 153.456869 0.213758 0.461538
+ 159.493872 0.317053 0.115385
+ 159.963940 0.430105 0.884615
+ 202.530321 0.801088 0.884615
+ 209.038198 0.511082 0.115385
+ 209.470794 0.321862 0.846154
+ 252.013363 0.513537 0.884615
+ 252.528335 0.297345 0.538462
+ 258.522376 0.203926 0.076923
+ 258.989151 0.557818 1.000000
+ 301.519003 0.098341 1.000000
+ 302.011325 0.695429 0.000000
+
+EXPECTED XYZ 48
+ A1 35.76 28.63 20.95
+ A2 45.15 47.41 16.97
+ A3 26.68 36.02 22.61
+ A4 24.43 30.51 49.72
+ A5 27.36 28.54 55.85
+ A6 33.51 26.53 34.35
+ B1 58.65 60.38 64.15
+ B2 55.22 59.80 62.04
+ B3 57.62 60.06 69.00
+ B4 5.28 5.14 5.28
+ B5 4.44 5.04 5.06
+ B6 5.12 5.19 6.86
+ C1 64.60 65.02 55.99
+ C2 45.46 45.77 29.03
+ C3 33.13 32.26 14.73
+ C4 15.61 13.92 7.09
+ C5 5.16 5.03 3.92
+ C6 4.01 4.17 4.76
+ D1 77.89 81.93 87.49
+ D2 70.10 73.80 78.79
+ D3 43.43 45.76 48.92
+ D4 24.24 25.51 27.51
+ D5 12.32 12.98 13.91
+ D6 5.22 5.50 6.02
+ E1 85.00 89.31 96.33
+ E2 54.09 56.94 61.35
+ E3 32.55 34.33 36.79
+ E4 17.72 18.68 20.09
+ E5 7.89 8.30 8.87
+ E6 2.65 2.78 3.12
+ F1 12.84 18.14 36.39
+ F2 28.20 18.34 29.84
+ F3 57.08 61.01 8.56
+ F4 19.63 11.29 4.87
+ F5 13.70 22.39 9.24
+ F6 7.32 5.35 26.41
+ G1 35.76 28.16 5.45
+ G2 12.71 11.07 36.60
+ G3 27.74 18.51 13.48
+ G4 9.34 6.93 16.38
+ G5 33.22 43.77 10.98
+ G6 46.49 42.42 7.53
+ H1 30.35 42.13 42.95
+ H2 24.45 23.05 44.34
+ H3 9.73 12.51 6.59
+ H4 17.28 18.47 34.69
+ H5 36.71 34.18 24.66
+ H6 10.43 9.32 6.27
diff --git a/scanin/SpyderChecker.cie b/scanin/SpyderChecker.cie
new file mode 100644
index 0000000..302e416
--- /dev/null
+++ b/scanin/SpyderChecker.cie
@@ -0,0 +1,62 @@
+IT8.7/2
+ORIGINATOR "Jose Pereira"
+DESCRIPTOR "Datacolor SpyderCheckr (D65)"
+CREATED "dec, 19. 2011"
+MANUFACTURER "DataColor"
+
+NUMBER_OF_FIELDS 7
+BEGIN_DATA_FORMAT
+SAMPLE_ID XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 48
+BEGIN_DATA
+A1 35.76 28.63 20.95
+A2 45.15 47.41 16.97
+A3 26.68 36.02 22.61
+A4 24.43 30.51 49.72
+A5 27.36 28.54 55.85
+A6 33.51 26.53 34.35
+B1 58.65 60.38 64.15
+B2 55.22 59.80 62.04
+B3 57.62 60.06 69.00
+B4 5.28 5.14 5.28
+B5 4.44 5.04 5.06
+B6 5.12 5.19 6.86
+C1 64.60 65.02 55.99
+C2 45.46 45.77 29.03
+C3 33.13 32.26 14.73
+C4 15.61 13.92 7.09
+C5 5.16 5.03 3.92
+C6 4.01 4.17 4.76
+D1 77.89 81.93 87.49
+D2 70.10 73.80 78.79
+D3 43.43 45.76 48.92
+D4 24.24 25.51 27.51
+D5 12.32 12.98 13.91
+D6 5.22 5.50 6.02
+E1 85.00 89.31 96.33
+E2 54.09 56.94 61.35
+E3 32.55 34.33 36.79
+E4 17.72 18.68 20.09
+E5 7.89 8.30 8.87
+E6 2.65 2.78 3.12
+F1 12.84 18.14 36.39
+F2 28.20 18.34 29.84
+F3 57.08 61.01 8.56
+F4 19.63 11.29 4.87
+F5 13.70 22.39 9.24
+F6 7.32 5.35 26.41
+G1 35.76 28.16 5.45
+G2 12.71 11.07 36.60
+G3 27.74 18.51 13.48
+G4 9.34 6.93 16.38
+G5 33.22 43.77 10.98
+G6 46.49 42.42 7.53
+H1 30.35 42.13 42.95
+H2 24.45 23.05 44.34
+H3 9.73 12.51 6.59
+H4 17.28 18.47 34.69
+H5 36.71 34.18 24.66
+H6 10.43 9.32 6.27
+END_DATA
diff --git a/scanin/afiles b/scanin/afiles
new file mode 100644
index 0000000..bc4d9c7
--- /dev/null
+++ b/scanin/afiles
@@ -0,0 +1,28 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+scanin.c
+scanrd.c
+scanrd.h
+scanrd_.h
+it8.cht
+ColorChecker.cht
+ColorChecker.cie
+ColorCheckerDC.cht
+ColorCheckerSG.cht
+Hutchcolor.cht
+i1_RGB_Scan_1.4.cht
+ColorCheckerPassport.cht
+ColorCheckerPassport.cie
+QPcard_201.cht
+QPcard_201.cie
+QPcard_202.cht
+QPcard_202.cie
+CMP_DT_003.cht
+CMP_Digital_Target-3.cht
+CMP_Digital_Target-3.ti2
+CMP_Digital_Target-3.cie
+LaserSoftDCPro.cht
+SpyderChecker.cht
+SpyderChecker.cie
diff --git a/scanin/i1_RGB_Scan_1.4.cht b/scanin/i1_RGB_Scan_1.4.cht
new file mode 100644
index 0000000..3a3d7c9
--- /dev/null
+++ b/scanin/i1_RGB_Scan_1.4.cht
@@ -0,0 +1,341 @@
+
+BOXES 289
+ F _ _ 49 33 662 33 662 466 49 466
+ D ALL ALL _ _ 613 433 49.0 33.0 0 0
+ X A R 1 16 34.0 27.0 49.0 33.0 34.0 27.0
+
+BOX_SHRINK 3.3
+
+REF_ROTATION 0.0
+
+XLIST 19
+ 49.0 1.0 1.0
+ 83.0 1.0 1.0
+ 117.0 1.0 1.0
+ 151.0 1.0 1.0
+ 185.0 1.0 1.0
+ 219.0 1.0 1.0
+ 253.0 1.0 1.0
+ 287.0 1.0 1.0
+ 321.0 1.0 1.0
+ 355.0 1.0 1.0
+ 389.0 1.0 1.0
+ 423.0 1.0 1.0
+ 457.0 1.0 1.0
+ 491.0 1.0 1.0
+ 525.0 1.0 1.0
+ 559.0 1.0 1.0
+ 593.0 1.0 1.0
+ 627.0 1.0 1.0
+ 662.0 1.0 1.0
+
+YLIST 17
+ 33.0 1.0 1.0
+ 60.0 1.0 1.0
+ 87.0 1.0 1.0
+ 114.0 1.0 1.0
+ 141.0 1.0 1.0
+ 168.0 1.0 1.0
+ 195.0 1.0 1.0
+ 222.0 1.0 1.0
+ 249.0 1.0 1.0
+ 276.0 1.0 1.0
+ 303.0 1.0 1.0
+ 330.0 1.0 1.0
+ 357.0 1.0 1.0
+ 384.0 1.0 1.0
+ 411.0 1.0 1.0
+ 439.0 1.0 1.0
+ 466.0 1.0 1.0
+
+EXPECTED XYZ 288
+ A1 0.52 0.59 0.56
+ A2 10.27 10 32.62
+ A3 13.89 7.3 2.84
+ A4 33.34 23.69 4.75
+ A5 31.79 33.22 28.61
+ A6 13.85 14.51 12.72
+ A7 35.52 25.53 10.91
+ A8 27.16 27.04 25.26
+ A9 6.12 6.42 5.76
+ A10 6.04 6.8 6.75
+ A11 4.4 3.47 20.55
+ A12 6.34 3.41 11.34
+ A13 9.03 7.05 14.88
+ A14 7.91 6.52 8.41
+ A15 16.18 10.77 24.37
+ A16 1.97 1.1 8.66
+ B1 27.55 34.83 6.23
+ B2 17.94 11.4 1.02
+ B3 34.87 35.19 5.79
+ B4 13.05 19.54 29.87
+ B5 6.88 9.15 27.74
+ B6 70.59 73.69 44.02
+ B7 2.04 2.19 1.41
+ B8 1.35 2.84 0.94
+ B9 49.51 40.62 36.32
+ B10 43.26 35.61 12.01
+ B11 2.65 3.13 3.25
+ B12 17.77 24.45 21.08
+ B13 8.51 14.13 31.85
+ B14 7.84 11.93 30.12
+ B15 5.81 12.04 16.38
+ B16 11.49 8.06 0.99
+ C1 34.5 19.81 37.1
+ C2 42.27 43.99 33.47
+ C3 4.36 7.54 14.12
+ C4 58.73 57.76 6.5
+ C5 11.22 5.5 17.82
+ C6 1.55 1.89 2.09
+ C7 37.5 39.03 33.61
+ C8 23.67 18.54 4.44
+ C9 8.12 14.07 4.81
+ C10 2.9 7.38 1.41
+ C11 34.09 35.82 26.91
+ C12 9.45 9.34 9.05
+ C13 41.11 33.34 5.29
+ C14 27.38 21.65 19.2
+ C15 27.38 28.66 24.61
+ C16 48.58 49.16 58.53
+ D1 7.47 12.02 1.86
+ D2 17.27 8.47 18.91
+ D3 24.86 14.78 0.99
+ D4 8.61 4.81 2.74
+ D5 28.85 26.03 5.07
+ D6 20.34 26.75 33.64
+ D7 5.39 3.09 6.34
+ D8 7.42 3.7 17.12
+ D9 60.57 66.88 64.61
+ D10 4.42 4.33 4.38
+ D11 2.63 2.73 10.91
+ D12 46.48 54.19 25.5
+ D13 1.24 2.02 2.92
+ D14 2.43 5.58 3.81
+ D15 4.46 2.69 0.72
+ D16 23.58 11.3 19.67
+ E1 18.33 16.26 18.07
+ E2 13.25 17.2 1.73
+ E3 16.1 22.52 11.75
+ E4 50.7 52.96 40.49
+ E5 0.93 1.03 0.98
+ E6 2.58 1.28 12.24
+ E7 61.11 63.67 49.46
+ E8 9.69 16.36 11.19
+ E9 19.64 20.4 5.14
+ E10 68.63 71.55 34.47
+ E11 33.86 33.75 30.83
+ E12 18.65 9.44 0.83
+ E13 12.88 22.5 20.49
+ E14 40.57 35.97 51.8
+ E15 25.89 26.22 33.39
+ E16 30.29 39.21 13.78
+ F1 3.2 7.65 4.38
+ F2 3.71 3.35 16.24
+ F3 23.31 14.61 25.55
+ F4 20.14 13.3 9.05
+ F5 19.65 21.55 20.22
+ F6 1.21 1.33 0.75
+ F7 5.8 8.65 21.51
+ F8 20.82 10.37 7.25
+ F9 12.98 6.05 24.77
+ F10 15.96 14.23 4.62
+ F11 54.03 50.45 2.31
+ F12 23.38 24.4 20.86
+ F13 4.42 5.8 1.14
+ F14 17.42 25.87 5.81
+ F15 1.8 3.63 3.4
+ F16 12.33 9.08 3.65
+ G1 41.01 28.98 32.18
+ G2 14.7 24.18 31.92
+ G3 4.63 5.68 19.04
+ G4 73.8 76.63 58.3
+ G5 25.16 11.63 27.13
+ G6 23.64 27.52 5.74
+ G7 40.74 42.65 24.74
+ G8 5.04 6.8 4
+ G9 15.6 21.51 42.53
+ G10 47.5 50.89 46.6
+ G11 11.95 13.23 12.63
+ G12 0.74 0.68 2.21
+ G13 20.56 17.42 28.91
+ G14 3.34 3.61 2.24
+ G15 15.88 7.93 12.58
+ G16 32.76 42.79 24.95
+ H1 1.99 1.85 1.96
+ H2 5.23 4.73 13.17
+ H3 35.1 45.5 39.54
+ H4 15.44 16.22 14.02
+ H5 18.85 19.72 16.96
+ H6 19.88 10.01 3.06
+ H7 12.31 8.36 31.05
+ H8 37.11 33.66 35.77
+ H9 31.4 29.01 12.25
+ H10 5.92 7.65 8.81
+ H11 65.82 68.12 58.73
+ H12 15.16 18.34 19.38
+ H13 14.99 12.73 1.65
+ H14 56.71 60.58 54.75
+ H15 9.34 13.22 17.86
+ H16 14.91 7.72 6.98
+ I1 25.37 20.12 10.52
+ I2 49.34 51.3 44.11
+ I3 6.63 6.47 6.58
+ I4 1.07 0.94 1.24
+ I5 8.34 4.69 0.92
+ I6 23.16 18.65 41.02
+ I7 6.72 10.56 4.53
+ I8 27.97 23.98 1.71
+ I9 3.27 1.46 15.75
+ I10 55.74 51.88 24.53
+ I11 7.7 11.77 9.88
+ I12 1.57 1.7 1.49
+ I13 28.92 28.09 47.66
+ I14 28.27 17.22 9.16
+ I15 72.13 75.17 50.99
+ I16 3.58 5.09 12.93
+ J1 13.14 15.8 38.03
+ J2 9.81 17.93 5.25
+ J3 68.6 65.82 63.75
+ J4 43.83 30.19 45.87
+ J5 18.39 8.6 26.07
+ J6 5.36 10.17 15.84
+ J7 55.67 57.15 61.71
+ J8 17.35 19.86 30.55
+ J9 9.34 5.12 6.56
+ J10 4.06 4.65 4.46
+ J11 59.67 55.56 40.66
+ J12 49.63 49.42 45.4
+ J13 41.62 45.81 6.35
+ J14 4.44 4.57 7.21
+ J15 12.73 12.57 11.83
+ J16 33.9 31.33 21.78
+ K1 39.02 40.41 2.14
+ K2 6.59 5.47 20
+ K3 11 14.42 27.43
+ K4 1.86 2.4 6.45
+ K5 18.68 28.5 12.59
+ K6 75.76 78.23 67.4
+ K7 7.32 7.87 5.36
+ K8 18.49 18.14 1.64
+ K9 37.54 38.95 13.07
+ K10 55.35 62.8 63.8
+ K11 8.76 9.83 9.34
+ K12 8.38 8.86 7.56
+ K13 21.69 14.04 16.27
+ K14 16.19 22.43 2.19
+ K15 62.66 63.7 14.84
+ K16 7.22 13.33 24.18
+ L1 4.75 2.89 2.62
+ L2 38.93 48.68 58.9
+ L3 65.92 71 57.4
+ L4 66.52 69 26.91
+ L5 15.55 13.99 36.92
+ L6 17.18 15.48 10.42
+ L7 51.65 59.75 43.16
+ L8 18.25 11.8 33.47
+ L9 3.47 3.71 3.23
+ L10 12.9 9.35 8.48
+ L11 64.65 59.55 61.46
+ L12 45.13 38.69 1.96
+ L13 6.43 10.92 22.75
+ L14 21.35 21.35 19.83
+ L15 33.05 24.65 43.94
+ L16 22.66 23.84 17.58
+ M1 65.11 63.01 48.58
+ M2 1.94 1.46 0.65
+ M3 22.58 16.86 1.28
+ M4 10.28 5.41 11.55
+ M5 11.02 20.07 11.6
+ M6 59.78 59.84 54.76
+ M7 2.71 4.6 7.83
+ M8 23.91 34.53 36.93
+ M9 30.27 18.26 16.91
+ M10 26.5 36.45 52.65
+ M11 13.33 16.63 10.94
+ M12 4.04 8.83 9.08
+ M13 5.17 5.59 5.05
+ M14 3.61 9.2 4.51
+ M15 10.14 10.8 7.78
+ M16 3.13 3.26 0.84
+ N1 3.29 6.6 8.25
+ N2 4.65 10.78 9.31
+ N3 30.72 33.49 30.48
+ N4 10.72 12.58 1.45
+ N5 10.17 7.54 21.82
+ N6 11.18 18 19.3
+ N7 53.3 49.34 13.79
+ N8 7.14 6.18 3.7
+ N9 7.18 8.54 15.43
+ N10 10.26 10.86 9.44
+ N11 64.17 66.15 63.94
+ N12 29.82 22.94 30.75
+ N13 41.27 41.14 38.01
+ N14 13.72 13.09 26.73
+ N15 67.54 72.16 65.85
+ N16 59.57 51.66 57.98
+ O1 13.5 7.07 0.76
+ O2 49.21 44.05 5.87
+ O3 18.71 12.3 3.74
+ O4 38.42 41.38 37.84
+ O5 14.29 19.83 5.34
+ O6 38.12 27.36 19.84
+ O7 0.82 1.5 0.8
+ O8 58.19 65.09 49.46
+ O9 22.03 24.06 1.89
+ O10 54.38 44.04 54.64
+ O11 17.33 18.31 13.39
+ O12 3.07 2.92 2.94
+ O13 8.57 8.65 1.33
+ O14 2.04 4.54 1.45
+ O15 5.58 2.53 20.51
+ O16 9.55 10.01 4.38
+ P1 27.28 32.46 22.7
+ P2 1.26 0.88 4.93
+ P3 33.17 37.11 53.34
+ P4 8.31 3.84 22.57
+ P5 0.65 0.9 1.06
+ P6 3.58 1.97 10.4
+ P7 17.53 26.57 45.79
+ P8 38.54 30.11 1.74
+ P9 70.01 70.01 56.41
+ P10 45.98 54.96 61.34
+ P11 5.76 6.4 24.4
+ P12 27.4 28.95 21.64
+ P13 8.91 9.56 24.29
+ P14 14.32 10.16 15.55
+ P15 44.13 50.38 14.14
+ P16 25.91 15.77 35.63
+ Q1 7.89 5.75 27.26
+ Q2 19.45 21.15 43.11
+ Q3 2.18 1.59 2.48
+ Q4 2.47 2.57 2.36
+ Q5 71.98 71.6 65.38
+ Q6 25.4 27.72 25.57
+ Q7 46.78 38.92 22.52
+ Q8 30.85 35.91 37
+ Q9 9.11 15.52 1.94
+ Q10 11.65 11.86 16.65
+ Q11 20.6 21.96 11.36
+ Q12 2.49 6.09 1.38
+ Q13 43.66 45.37 39.11
+ Q14 56.73 58.92 50.71
+ Q15 13.37 14.14 10.18
+ Q16 25.67 30.42 12.63
+ R1 11.96 14.98 5.06
+ R2 25.55 30.36 2.16
+ R3 20.96 31.53 22.46
+ R4 26.63 16.16 3.75
+ R5 15.45 17.15 15.99
+ R6 2.87 1.83 5.87
+ R7 5.94 8.9 1.32
+ R8 22.2 10.8 12.85
+ R9 32.45 19.2 26.87
+ R10 31.17 21.44 1.48
+ R11 4.71 2.36 15.65
+ R12 16.81 16.68 15.67
+ R13 33.39 31.69 1.87
+ R14 6.67 5.46 0.93
+ R15 23.87 29.65 49.1
+ R16 5.1 5.43 3.45
+
+
diff --git a/scanin/it8.cht b/scanin/it8.cht
new file mode 100644
index 0000000..f1e256d
--- /dev/null
+++ b/scanin/it8.cht
@@ -0,0 +1,338 @@
+
+
+BOXES 290
+ F _ _ 1 1 616.0 1.5 615.5 358 1 358.5
+ D ALL ALL _ _ 615 409 1 1 0 0
+ D MARK MARK _ _ 14 14 1 1 0 0
+ Y 01 22 A L 25.625 25.625 26.625 26.625 25.625 25.625
+ X GS00 GS23 _ _ 25.625 51.25 0.0 358.75 25.625 0.0
+
+BOX_SHRINK 3.2
+
+REF_ROTATION -0.002006
+
+XLIST 32
+ 1.799625 1.000000 0.312500
+ 27.064987 0.874039 0.750000
+ 52.592403 0.133439 0.687500
+ 78.196610 0.264191 0.687500
+ 104.117756 0.165427 0.937500
+ 129.377994 0.844432 0.937500
+ 155.144274 0.501218 0.875000
+ 180.839181 0.491428 0.937500
+ 206.359758 0.212384 0.937500
+ 232.038808 0.851851 0.937500
+ 257.854725 0.162956 0.625000
+ 283.552463 0.101243 0.812500
+ 300.534000 0.024750 0.812500
+ 309.507688 0.093829 1.000000
+ 334.711314 0.856821 1.000000
+ 360.428194 0.787677 1.000000
+ 385.849730 0.748130 0.937500
+ 386.650071 0.039487 0.687500
+ 394.630372 0.024725 0.687500
+ 411.835654 0.802501 0.750000
+ 414.017731 0.041974 0.937500
+ 437.133504 0.674062 0.937500
+ 437.975355 0.103714 1.000000
+ 462.938460 0.671643 1.000000
+ 463.880560 0.093836 0.937500
+ 488.517995 0.679022 1.000000
+ 514.338544 0.760511 1.000000
+ 540.037492 0.111108 0.625000
+ 565.856396 0.133330 0.562500
+ 591.114717 0.565475 0.562500
+ 603.447516 0.032097 0.312500
+ 615.984915 0.829608 0.250000
+
+YLIST 22
+ 2.477956 0.993407 0.142857
+ 12.988903 0.016393 0.190476
+ 14.739109 0.036082 0.190476
+ 26.746171 0.911487 0.428571
+ 52.537114 0.303282 0.904762
+ 78.060317 0.585303 0.857143
+ 103.498271 0.606862 0.761905
+ 128.994535 0.567266 0.761905
+ 154.483041 0.550814 0.714286
+ 179.935985 0.623055 0.666667
+ 205.552940 0.350826 0.714286
+ 212.051372 0.016393 0.714286
+ 231.153547 0.824618 0.857143
+ 256.697418 0.744268 0.952381
+ 282.145841 0.736126 0.904762
+ 307.899015 0.536075 0.952381
+ 333.262903 0.903282 0.809524
+ 340.217754 0.019722 0.190476
+ 344.988867 0.019671 0.095238
+ 346.988885 0.018032 0.095238
+ 358.840278 0.999967 1.000000
+ 409.201393 1.000000 0.000000
+
+EXPECTED XYZ 264
+ A01 3.85 3.22 1.9
+ A02 4.89 3.27 1.6
+ A03 5.87 3.31 1.33
+ A04 6.3 3.38 1.19
+ A05 13.01 11.44 7.64
+ A06 16.14 11.99 6.81
+ A07 19.35 12.41 6.06
+ A08 20.41 11.97 5.3
+ A09 43.5 42.81 32.65
+ A10 45.58 42.37 30.95
+ A11 48.99 43.2 29.9
+ A12 50.73 44.02 29.96
+ A13 74.46 78.76 66.06
+ A14 75.66 76.42 64.08
+ A15 78.36 81.34 65.41
+ A16 70.52 73.3 59.16
+ A17 74.98 75.98 60.69
+ A18 72.85 77.3 60.25
+ A19 73.09 75.52 64.54
+ B01 3.47 3.08 1.41
+ B02 4.41 3.25 0.9
+ B03 5.04 3.23 0.58
+ B04 5.19 3.11 0.47
+ B05 13.36 11.59 5.56
+ B06 15.97 12.03 3.69
+ B07 19.2 12.49 2.2
+ B08 19.73 11.52 1.17
+ B09 42.19 41.84 29.34
+ B10 44.83 42.17 25.93
+ B11 48.06 42.9 23.01
+ B12 49.63 43.08 21.34
+ B13 66.21 72.54 64.61
+ B14 70.16 67.1 60.33
+ B15 75.46 78.69 51.58
+ B16 57.47 59.58 47.66
+ B17 68.33 66.45 49.05
+ B18 63.89 70.29 51.3
+ B19 61.12 62.16 59.79
+ C01 4.97 4.75 1.98
+ C02 5.18 4.65 1.23
+ C03 5.51 4.58 0.71
+ C04 5.77 4.61 0.67
+ C05 24.57 23.44 10.14
+ C06 28.1 24.64 5.22
+ C07 31.15 25.28 2.2
+ C08 30.85 23.68 1.35
+ C09 49.16 49.36 32.37
+ C10 51.72 50.72 26.53
+ C11 55.24 53.14 21.93
+ C12 56.87 53.62 18.46
+ C13 57.68 65.65 62.7
+ C14 63.46 56.66 55.49
+ C15 73 76.11 40.78
+ C16 44.73 46.38 36.8
+ C17 60.64 55.73 38.1
+ C18 52.15 60.27 41.5
+ C19 48.13 49.18 54.38
+ D01 4.19 4.41 1.93
+ D02 4.48 4.72 1.24
+ D03 4.55 4.78 0.8
+ D04 4.32 4.53 0.78
+ D05 27.33 28.55 12.95
+ D06 28.68 30.04 7.25
+ D07 29.51 31.01 3.41
+ D08 27.55 28.44 1.83
+ D09 56.06 58.19 38.21
+ D10 56.03 58.46 30.02
+ D11 56.2 59.33 24.44
+ D12 56.19 59.41 19.14
+ D13 48.21 57.42 59.53
+ D14 58.18 49.14 51.36
+ D15 70.98 73.73 33.63
+ D16 34.31 35.73 28.22
+ D17 54.27 47.53 29.58
+ D18 41.67 50.64 32.28
+ D19 36.95 37.82 48.09
+ E01 4.15 4.75 2.03
+ E02 4 4.98 1.37
+ E03 3.3 4.49 0.86
+ E04 3.11 4.3 0.86
+ E05 13.11 14.9 7.06
+ E06 12.26 15.23 4.18
+ E07 11.53 15.57 2.27
+ E08 9.69 13.74 1.51
+ E09 39.15 42.08 27.33
+ E10 37.43 41.51 22.23
+ E11 36.99 42.5 18.85
+ E12 36.4 42.58 16.27
+ E13 39.97 49.81 56.15
+ E14 52.08 41.07 46.36
+ E15 68.71 70.76 26.45
+ E16 25.7 26.97 21.28
+ E17 48.53 40.6 22
+ E18 31.62 40.82 23.35
+ E19 31.19 31.19 43.4
+ F01 1.51 1.91 1.06
+ F02 1.29 2.04 0.98
+ F03 1.16 2.09 0.82
+ F04 1.14 2.04 0.8
+ F05 6.53 8.25 5.13
+ F06 5.61 8.66 4.38
+ F07 4.6 8.77 3.7
+ F08 3.45 7.63 2.78
+ F09 37.8 41.07 30.91
+ F10 35.92 40.76 29.03
+ F11 35.42 41.99 29.07
+ F12 34 41.8 28
+ F13 32.13 42.12 51.99
+ F14 45.72 33.34 40.77
+ F15 66.26 67.29 19.65
+ F16 17.02 18.07 14.4
+ F17 41.59 32.53 15.16
+ F18 26.26 35.26 18.81
+ F19 24.3 23.6 37.48
+ G01 2.31 3 2.27
+ G02 2 3.21 2.58
+ G03 1.66 3.21 2.75
+ G04 1.58 3.03 2.6
+ G05 8.99 11.08 8.79
+ G06 7.68 11.3 9.56
+ G07 6.52 11.5 10.2
+ G08 5.5 10.85 10.55
+ G09 38.29 41.75 33.45
+ G10 35.83 41.16 34.11
+ G11 34.56 41.83 35.63
+ G12 33.69 42.14 36.7
+ G13 25.95 35.68 48
+ G14 40.6 27.62 36.14
+ G15 63.72 63.63 14.35
+ G16 10.85 11.82 9.58
+ G17 37.23 27.64 11.62
+ G18 20.28 28.97 14.15
+ G19 17.7 16.74 31.7
+ H01 2.56 3.04 2.92
+ H02 2.34 3.2 4.12
+ H03 2.12 3.28 5.43
+ H04 2.06 3.18 5.29
+ H05 10.07 11.6 11.24
+ H06 9.01 11.68 14.81
+ H07 8.22 12 19.42
+ H08 7.25 11.55 21.45
+ H09 39.25 42.31 36.81
+ H10 37.58 41.85 40.37
+ H11 37.16 43.07 45.79
+ H12 36.27 43.78 49.47
+ H13 21.47 30.78 44.22
+ H14 36.49 23.35 32.38
+ H15 61.58 60.55 10.95
+ H16 8.21 8.71 6.91
+ H17 33.04 23.26 8.38
+ H18 16.22 24.35 10.41
+ H19 12.86 11.84 26.82
+ I01 4.22 4.44 5.28
+ I02 4.35 4.48 8.36
+ I03 4.4 4.44 11.94
+ I04 4.48 4.58 12.17
+ I05 15.15 15.78 15.23
+ I06 14.56 15.12 19.52
+ I07 14.37 14.81 24.48
+ I08 14.11 14.76 30.03
+ I09 41.03 42.58 36.94
+ I10 40.85 42.23 40.73
+ I11 40.86 42.33 45.05
+ I12 41.31 42.73 47.77
+ I13 17.26 25.93 40.23
+ I14 32.66 19.63 28.81
+ I15 59.37 57.18 7.79
+ I16 4.97 5.32 4.32
+ I17 28.62 18.88 5.48
+ I18 11.58 18.98 7.25
+ I19 9.58 8.34 22.87
+ I20 0.45 0.4 0.33
+ I21 2.28 1.78 0.98
+ I22 2.37 1.95 0.85
+ J01 2.15 1.9 2.6
+ J02 2.57 2 4.72
+ J03 2.93 1.95 8.1
+ J04 3.15 1.92 10.76
+ J05 11.73 11.6 11.81
+ J06 12.98 11.93 16.19
+ J07 13.91 12.07 20.95
+ J08 14.01 11.59 24.35
+ J09 40.75 41.22 36.34
+ J10 41.26 41.07 39.74
+ J11 42.63 41.68 44.51
+ J12 44.02 41.78 49.25
+ J13 13.82 21.69 35.98
+ J14 28.87 16.33 25.08
+ J15 56.04 52.29 4.97
+ J16 2.46 2.63 2.29
+ J17 24.04 14.75 3.15
+ J18 8.12 14.49 4.55
+ J19 5.98 4.79 17.76
+ J20 8.26 5.37 1.04
+ J21 11.52 7.81 1.62
+ J22 14.67 10.72 2.6
+ K01 5.63 4.7 4.86
+ K02 6.74 4.58 7.23
+ K03 8.04 4.48 9.73
+ K04 9.39 4.76 11.79
+ K05 16.66 15.39 14.44
+ K06 18.72 15.18 18.23
+ K07 21.56 15.5 22.97
+ K08 23 15.02 25.37
+ K09 42.5 42.02 36.05
+ K10 44.55 41.63 39.71
+ K11 47.19 41.96 44.03
+ K12 49.9 43.14 47.21
+ K13 10.61 17.44 31.24
+ K14 24.84 13.19 21
+ K15 53.12 48.05 3.19
+ K16 1.05 1.14 1.13
+ K17 19.93 11.34 1.67
+ K18 5.3 10.47 2.73
+ K19 3.95 2.76 13.94
+ K20 30.61 26.43 11.04
+ K21 34.91 29.6 11.78
+ K22 38.95 34.57 18.4
+ L01 3.88 3.12 2.32
+ L02 4.93 3.2 2.69
+ L03 5.75 3.14 3.02
+ L04 7.31 3.79 3.4
+ L05 13.29 11.54 9.39
+ L06 16.22 11.73 10.32
+ L07 19.95 12.08 12.06
+ L08 20.79 11.31 12.01
+ L09 43.22 42.09 33.78
+ L10 45.52 41.88 34.65
+ L11 49.04 42.87 35.98
+ L12 51.03 43.83 37.78
+ L13 7.45 12.77 25.59
+ L14 21.26 10.76 17.73
+ L15 49.45 43.12 2.14
+ L16 0.47 0.49 0.5
+ L17 16.04 8.49 0.78
+ L18 2.91 6.5 1.39
+ L19 2.5 1.45 10.28
+ L20 38.7 33.98 20.86
+ L21 39.36 35.23 21.23
+ L22 41.36 38.77 23.51
+ GS00 79.47 82.51 69.04
+ GS01 72.62 74.94 59.17
+ GS02 63.15 65.11 51.57
+ GS03 54.72 56.51 45.03
+ GS04 48.1 49.81 39.24
+ GS05 42.22 43.64 34.45
+ GS06 37.33 38.7 30.5
+ GS07 32.38 33.61 26.11
+ GS08 27.56 28.7 22.11
+ GS09 22.5 23.4 17.99
+ GS10 18.77 19.55 14.83
+ GS11 15.48 16.08 12.04
+ GS12 12.69 13.29 9.98
+ GS13 10.35 10.81 7.97
+ GS14 8.39 8.77 6.37
+ GS15 6.45 6.79 4.97
+ GS16 4.95 5.18 3.7
+ GS17 3.58 3.82 2.76
+ GS18 2.76 2.89 2.06
+ GS19 1.97 2.08 1.45
+ GS20 1.22 1.31 0.98
+ GS21 1 1.05 0.74
+ GS22 0.87 0.89 0.65
+ GS23 0.34 0.32 0.32
+
+
diff --git a/scanin/scanin.c b/scanin/scanin.c
new file mode 100644
index 0000000..94771fe
--- /dev/null
+++ b/scanin/scanin.c
@@ -0,0 +1,1436 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Scanin: Input the scan of a test chart, and output cgats data
+ * Uses scanrd to do the hard work.
+ *
+ * Author: Graeme W. Gill
+ * Date: 29/1/97
+ *
+ * Copyright 1995 - 2002 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.
+ */
+
+/*
+ TTBD
+
+ Add "single pixel patch" mode, for pure digital processing for
+ abstract profile creation.
+
+
+ */
+
+#include <stdio.h>
+#include <fcntl.h> /* In case DOS binary stuff is needed */
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+
+#include <time.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "icc.h"
+#include "xicc.h"
+#include "scanrd.h"
+#include "tiffio.h"
+
+/* Utilities */
+
+void fix_it8(char *o, char *i);
+
+#ifdef NT /* You'd think there might be some standards.... */
+# ifndef __BORLANDC__
+# define stricmp _stricmp
+# endif
+#else
+# define stricmp strcasecmp
+#endif
+
+#define TXBUF (256*1024L)
+
+/* NOTE: We aren't handling the libtiff error/warning messages !! */
+
+/* Read a line of data from the input Grey, RGB or CMYK tiff file */
+/* return non-zero on error */
+int read_line(
+void *fdata,
+int y,
+char *dst
+) {
+ if (TIFFReadScanline((TIFF *)fdata, (tdata_t)dst, y, 0) < 0)
+ return 1;
+ return 0;
+}
+
+/* Write a line of data to the diagnostic RGB tiff file */
+/* return non-zero on error */
+static int
+write_line(
+void *ddata,
+int y,
+char *src
+) {
+ if (TIFFWriteScanline((TIFF *)ddata, (tdata_t)src, y, 0) < 0)
+ return 1;
+ return 0;
+}
+
+void
+usage(void) {
+ fprintf(stderr,"Scanin, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"usage: scanin [options] input.tif recogin.cht valin.cie [diag.tif]\n");
+ fprintf(stderr," :- inputs 'input.tif' and outputs scanner 'input.ti3', or\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"usage: scanin -g [options] input.tif recogout.cht [diag.tif]\n");
+ fprintf(stderr," :- outputs file 'recogout.cht', or\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"usage: scanin -o [options] input.tif recogin.cht [diag.tif]\n");
+ fprintf(stderr," :- outputs file 'input.val', or\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"usage: scanin -c [options] input.tif recogin.cht scanprofile.[%s|mpp] pbase [diag.tif]\n",ICC_FILE_EXT_ND);
+ fprintf(stderr," :- inputs pbase.ti2 and outputs printer pbase.ti3, or\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr,"usage: scanin -r [options] input.tif recogin.cht pbase [diag.tif]\n");
+ fprintf(stderr," :- inputs pbase.ti2+.ti3 and outputs pbase.ti3\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr," -g Generate a chart reference (.cht) file\n");
+ fprintf(stderr," -o Output patch values in .val file\n");
+ fprintf(stderr," -c Use image to measure color to convert printer pbase .ti2 to .ti3\n");
+ fprintf(stderr," -ca Same as -c, but accumulates more values to pbase .ti3\n");
+ fprintf(stderr," from subsequent pages\n");
+ fprintf(stderr," -r Replace device values in pbase .ti2/.ti3\n");
+ fprintf(stderr," Default is to create a scanner .ti3 file\n");
+ fprintf(stderr," -F x1,y1,x2,y2,x3,y3,x4,y4\n");
+ fprintf(stderr," Don't auto recognize, locate using four fiducual marks\n");
+ fprintf(stderr," -p Compensate for perspective distortion\n");
+ fprintf(stderr," -a Recognise chart in normal orientation only (-A fallback as is)\n");
+ fprintf(stderr," Default is to recognise all possible chart angles\n");
+ fprintf(stderr," -m Return true mean (default is robust mean)\n");
+ fprintf(stderr," -G gamma Approximate gamma encoding of image\n");
+ fprintf(stderr," -v [n] Verbosity level 0-9\n");
+ fprintf(stderr," -d [ihvglLIcrsonap] Generate diagnostic output (try -dipn)\n");
+ fprintf(stderr," i diag - B&W of input image\n");
+ fprintf(stderr," h diag - Horizontal edge/tick detection\n");
+ fprintf(stderr," v diag - Vertical edge/tick detection\n");
+ fprintf(stderr," g diag - Groups detected\n");
+ fprintf(stderr," l diag - Lines detected\n");
+ fprintf(stderr," L diag - All lines detected\n");
+ fprintf(stderr," I diag - lines used to improve fit\n");
+ fprintf(stderr," c diag - lines perspective corrected\n");
+ fprintf(stderr," r diag - lines rotated\n");
+ fprintf(stderr," s diag - diagnostic sample boxes rotated\n");
+ fprintf(stderr," o diag - sample box outlines\n");
+ fprintf(stderr," n diag - sample box names\n");
+ fprintf(stderr," a diag - sample box areas\n");
+ fprintf(stderr," p diag - pixel areas sampled\n");
+ fprintf(stderr," -O outputfile Override the default output filename & extension.\n");
+ exit(1);
+ }
+
+
+int main(int argc, char *argv[])
+{
+ int fa,nfa; /* current argument we're looking at */
+ static char tiffin_name[MAXNAMEL+1] = { 0 }; /* TIFF Input file name (.tif) */
+ static char datin_name[MAXNAMEL+4+1] = { 0 }; /* Data input name (.cie/.q60) */
+ static char datout_name[MAXNAMEL+4+1] = { 0 }; /* Data output name (.ti3/.val) */
+ static char recog_name[MAXNAMEL+1] = { 0 }; /* Reference chart name (.cht) */
+ static char prof_name[MAXNAMEL+1] = { 0 }; /* scanner profile name (.cht) */
+ static char diag_name[MAXNAMEL+1] = { 0 }; /* Diagnostic Output (.tif) name, if used */
+ int verb = 1;
+ int tmean = 0; /* Return true mean, rather than robust mean */
+ int repl = 0; /* Replace .ti3 device values from raster file */
+ int outo = 0; /* Output the values read, rather than creating scanner .ti3 */
+ int colm = 0; /* Use inage values to measure color for print profile. > 1 == append */
+ int flags = SI_GENERAL_ROT; /* Default allow all rotations */
+
+ TIFF *rh = NULL, *wh = NULL;
+ uint16 depth, bps; /* Useful depth, bits per sample */
+ uint16 tdepth; /* Total depth including alpha */
+ uint16 pconfig, photometric;
+ uint16 rextrasamples; /* Extra "alpha" samples */
+ uint16 *rextrainfo; /* Info about extra samples */
+ int gotres = 0;
+ uint16 resunits;
+ float resx, resy;
+
+ icColorSpaceSignature tiffs = 0; /* Type of tiff color space */
+
+ int i, j;
+ double gamma = 0.0; /* default */
+ double _sfid[8], *sfid = NULL; /* Specified fiducials */
+ int width, height; /* x and y size */
+
+ scanrd *sr; /* Scanrd object */
+ int err;
+ char *errm;
+ int pnotscan = 0; /* Number of patches that wern't scanned */
+
+ if (argc <= 1)
+ usage();
+
+ error_program = argv[0];
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') /* Look for any flags */
+ {
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else
+ {
+ if ((fa+1) < argc)
+ {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?') {
+ usage();
+ } else if (argv[fa][1] == 'v') {
+ verb = 2;
+ if (na != NULL && isdigit(na[0])) {
+ verb = atoi(na);
+ }
+ } else if (argv[fa][1] == 'm') {
+ tmean = 1;
+
+ } else if (argv[fa][1] == 'g') {
+ flags |= SI_BUILD_REF;
+ repl = 0;
+ outo = 0;
+ colm = 0;
+
+ } else if (argv[fa][1] == 'r') {
+ repl = 1;
+ outo = 0;
+ colm = 0;
+
+ } else if (argv[fa][1] == 'o') {
+ repl = 0;
+ outo = 1;
+ colm = 0;
+
+ } else if (argv[fa][1] == 'c') {
+ repl = 0;
+ outo = 0;
+ colm = 1;
+ if (argv[fa][2] != '\000' && argv[fa][2] == 'a')
+ colm = 2;
+
+ /* Approximate gamma encoding of image */
+ } else if (argv[fa][1] == 'G') {
+ fa = nfa;
+ if (na == NULL) usage();
+ gamma = atof(na);
+ if (gamma < 0.0 || gamma > 5.0)
+ usage();
+
+ /* Use specified fiducials instead of auto recognition */
+ } else if (argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (sscanf(na, " %lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf ",
+ &_sfid[0], &_sfid[1], &_sfid[2], &_sfid[3],
+ &_sfid[4], &_sfid[5], &_sfid[6], &_sfid[7]) != 8) {
+ usage();
+ }
+
+ sfid = _sfid;
+
+ /* Compensate for perspective */
+ } else if (argv[fa][1] == 'p') {
+ flags |= SI_PERSPECTIVE;
+
+ /* Don't recognise rotations */
+ } else if (argv[fa][1] == 'a') {
+ flags &= ~SI_GENERAL_ROT;
+
+ /* Don't recognise rotations, and read patches */
+ /* anyway "as is", if everything else failes */
+ } else if (argv[fa][1] == 'A') {
+ flags &= ~SI_GENERAL_ROT;
+ flags |= SI_ASISIFFAIL;
+
+ } else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ while (na != NULL && *na != '\000') {
+ switch (*na) {
+ case 'i':
+ flags |= SI_SHOW_IMAGE;
+ break;
+ case 'h':
+ flags |= SI_SHOW_DIFFSH;
+ break;
+ case 'v':
+ flags |= SI_SHOW_DIFFSV;
+ break;
+ case 'g':
+ flags |= SI_SHOW_GROUPS;
+ break;
+ case 'l':
+ flags |= SI_SHOW_LINES;
+ break;
+ case 'L':
+ flags |= SI_SHOW_ALL_LINES;
+ break;
+ case 'I':
+ flags |= SI_SHOW_IMPL;
+ break;
+ case 'c':
+ flags |= SI_SHOW_PERS;
+ break;
+ case 'r':
+ flags |= SI_SHOW_ROT;
+ break;
+ case 's':
+ flags |= SI_SHOW_SBOX;
+ break;
+ case 'o':
+ flags |= SI_SHOW_SBOX_OUTLINES;
+ break;
+ case 'n':
+ flags |= SI_SHOW_SBOX_NAMES;
+ break;
+ case 'a':
+ flags |= SI_SHOW_SBOX_AREAS;
+ break;
+ case 'p':
+ flags |= SI_SHOW_SAMPLED_AREA;
+ break;
+ default:
+ usage();
+ }
+ na++;
+ }
+
+ /* Output file name */
+ } else if (argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ strncpy(datout_name,na,MAXNAMEL); datout_name[MAXNAMEL] = '\000';
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+ /* TIFF Raster input file name */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(tiffin_name,argv[fa],MAXNAMEL); tiffin_name[MAXNAMEL] = '\000';
+
+ if (datout_name[0] == '\000' /* Not been overridden */
+ && (flags & SI_BUILD_REF) == 0
+ && repl == 0 && colm == 0) { /* Not generate ref or replacing .ti3 dev */
+ char *xl;
+ strncpy(datout_name,argv[fa],MAXNAMEL); datout_name[MAXNAMEL] = '\000';
+ if ((xl = strrchr(datout_name, '.')) == NULL) /* Figure where extention is */
+ xl = datout_name + strlen(datout_name);
+ if (outo == 0) /* Creating scan calib data */
+ strcpy(xl,".ti3");
+ else /* Just outputing values for some other purpose */
+ strcpy(xl,".val");
+ }
+
+ /* .cht Reference file in or out */
+ if (++fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(recog_name,argv[fa],MAXNAMEL); recog_name[MAXNAMEL] = '\000';
+
+ if (colm > 0) {
+ if (++fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(prof_name,argv[fa],MAXNAMEL); prof_name[MAXNAMEL] = '\000';
+ }
+
+ /* CGATS Data file input/output */
+ if ((flags & SI_BUILD_REF) == 0 && outo == 0) { /* Not generate ref or just outputing */
+ if (++fa >= argc || argv[fa][0] == '-') usage();
+ if (outo == 0) { /* Creating scan calib data */
+ /* Data file */
+ strncpy(datin_name,argv[fa],MAXNAMEL); datin_name[MAXNAMEL] = '\000';
+ }
+ if (repl != 0 || colm > 0) { /* Color from image or replacing .ti3 device data */
+ strcpy(datin_name,argv[fa]);
+ strcat(datin_name,".ti2");
+ strcpy(datout_name,argv[fa]);
+ strcat(datout_name,".ti3");
+ }
+ }
+
+ /* optional diagnostic file */
+ if (++fa < argc) {
+ if (argv[fa][0] == '-')
+ usage();
+ strncpy(diag_name,argv[fa],MAXNAMEL); diag_name[MAXNAMEL] = '\000';
+ } else { /* Provide a default name */
+ strcpy(diag_name,"diag.tif");
+ }
+
+ if (stricmp(diag_name, tiffin_name) == 0) {
+ error("Diagnostic output '%s' might overwrite the input '%s'!",diag_name,tiffin_name);
+ }
+
+ /* ----------------------------------------- */
+ /* Open up input tiff file ready for reading */
+ /* Got arguments, so setup to process the file */
+ if ((rh = TIFFOpen(tiffin_name, "r")) == NULL)
+ error("error opening read file '%s'",tiffin_name);
+
+ TIFFGetField(rh, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);
+
+ TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bps);
+ if (bps != 8 && bps != 16)
+ error("TIFF Input file '%s' must be 8 or 16 bits/channel",tiffin_name);
+
+ /* See if there are alpha planes */
+ TIFFGetFieldDefaulted(rh, TIFFTAG_EXTRASAMPLES, &rextrasamples, &rextrainfo);
+
+ TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &depth);
+
+ if (rextrasamples > 0 && verb)
+ printf("%d extra (alpha ?) samples will be ignored\n",rextrasamples);
+
+ tdepth = depth;
+ depth = tdepth - rextrasamples;
+
+ if (depth != 1 && depth != 3 && depth != 4)
+ error("Input '%s' must be a Grey, RGB or CMYK tiff file",tiffin_name);
+
+ TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &photometric);
+ if (depth == 1 && photometric != PHOTOMETRIC_MINISBLACK
+ && photometric != PHOTOMETRIC_MINISWHITE)
+ error("1 chanel input '%s' must be a Grey tiff file",tiffin_name);
+ else if (depth == 3 && photometric != PHOTOMETRIC_RGB)
+ error("3 chanel input '%s' must be an RGB tiff file",tiffin_name);
+ else if (depth == 4 && photometric != PHOTOMETRIC_SEPARATED)
+ error("4 chanel input '%s' must be a CMYK tiff file",tiffin_name);
+
+ if (depth == 1)
+ tiffs = icSigGrayData;
+ else if (depth == 3)
+ tiffs = icSigRgbData;
+ else if (depth == 4)
+ tiffs = icSigCmykData;
+
+ TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
+ if (pconfig != PLANARCONFIG_CONTIG)
+ error("TIFF Input file '%s' must be planar",tiffin_name);
+
+
+ if (TIFFGetField(rh, TIFFTAG_RESOLUTIONUNIT, &resunits) != 0) {
+ TIFFGetField(rh, TIFFTAG_XRESOLUTION, &resx);
+ TIFFGetField(rh, TIFFTAG_YRESOLUTION, &resy);
+
+ if (resunits == RESUNIT_NONE /* If it looks valid */
+ || resunits == RESUNIT_INCH
+ || resunits == RESUNIT_CENTIMETER)
+ gotres = 1;
+ }
+
+ /* -------------------------- */
+ /* setup the diag output file */
+ if (flags & SI_SHOW_FLAGS) {
+ if ((wh = TIFFOpen(diag_name, "w")) == NULL)
+ error("Can\'t create TIFF file '%s'!",diag_name);
+
+ TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(wh, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ if (gotres) {
+ TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, resunits);
+ TIFFSetField(wh, TIFFTAG_XRESOLUTION, resx);
+ TIFFSetField(wh, TIFFTAG_YRESOLUTION, resy);
+ }
+ TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, "Scanin diagnosis output");
+ }
+
+ /* -------------------------- */
+ if (verb >= 2) {
+ printf("Input file '%s': w=%d, h=%d, d = %d, bpp = %d\n",
+ tiffin_name, width, height, depth, bps);
+ if (flags & SI_BUILD_REF)
+ printf("Build Scan Chart reference file '%s'\n",recog_name);
+ else {
+ printf("Data input file '%s'\n",datin_name);
+ printf("Data output file '%s'\n",datout_name);
+ printf("Chart reference file '%s'\n",recog_name);
+ }
+ if (flags & SI_SHOW_FLAGS)
+ printf("Creating diagnostic tiff file '%s'\n",diag_name);
+ }
+
+ /* -------------------------- */
+ /* Do the operation */
+
+ if ((sr = do_scanrd(
+ flags, /* option flags */
+ verb, /* verbosity level */
+
+ gamma,
+ sfid, /* Specified fiducuals, if any */
+ width, height, depth, tdepth, bps, /* Width, Height and Depth of input in pixels */
+ read_line, /* Read line function */
+ (void *)rh, /* Opaque data for read_line */
+
+ recog_name, /* reference file name */
+
+ write_line, /* Write line function */
+ (void *)wh /* Opaque data for write_line */
+ )) == NULL) {
+ if (flags & SI_SHOW_FLAGS)
+ TIFFClose(wh);
+ error("Unable to allocate scanrd object");
+ }
+
+ if ((err = sr->error(sr, &errm)) != 0) {
+ if ((flags & SI_SHOW_FLAGS) && err != SI_DIAG_WRITE_ERR)
+ TIFFClose(wh); /* Close diagnostic file */
+ error("Scanin failed with code 0x%x, %s",err,errm);
+ }
+
+ /* Read an output the values */
+ if ((flags & SI_BUILD_REF) == 0) { /* Not generate ref */
+
+ /* -------------------------------------------------- */
+ if (outo != 0) { /* Just output the values */
+ /* Note value range is raw 0..255, */
+ /* while all others output formats are out of 100 */
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "VALS"); /* Dummy type */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration raster values",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll scanin", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+ if (depth == 1) {
+ ocg->add_field(ocg, 0, "GREY", r_t);
+ } else if (depth == 3) {
+ ocg->add_field(ocg, 0, "RGB_R", r_t);
+ ocg->add_field(ocg, 0, "RGB_G", r_t);
+ ocg->add_field(ocg, 0, "RGB_B", r_t);
+ } else if (depth == 4) {
+ ocg->add_field(ocg, 0, "CMYK_C", r_t);
+ ocg->add_field(ocg, 0, "CMYK_M", r_t);
+ ocg->add_field(ocg, 0, "CMYK_Y", r_t);
+ ocg->add_field(ocg, 0, "CMYK_K", r_t);
+ }
+
+ /* Initialise, ready to read out all the values */
+ for (j = 0; ; j++) {
+ char id[100]; /* Input patch id */
+ double P[4]; /* Robust/true mean values */
+ int pixcnt; /* PIxel count */
+
+ if (tmean) {
+ if (sr->read(sr, id, NULL, P, NULL, &pixcnt) != 0)
+ break;
+ } else {
+ if (sr->read(sr, id, P, NULL, NULL, &pixcnt) != 0)
+ break;
+ }
+
+ if (pixcnt == 0)
+ pnotscan++;
+
+ if (depth == 1) {
+ ocg->add_set( ocg, 0, id, P[0]);
+ } else if (depth == 3) {
+ ocg->add_set( ocg, 0, id, P[0], P[1], P[2]);
+ } else if (depth == 4) {
+ ocg->add_set( ocg, 0, id, P[0], P[1], P[2], P[3]);
+ }
+ }
+
+ if (verb)
+ printf("Writing output values to file '%s'\n",datout_name);
+
+ if (ocg->write_name(ocg, datout_name))
+ error("Write error to '%s' : %s",datout_name,ocg->err);
+
+ ocg->del(ocg); /* Clean up */
+
+ /* -------------------------------------------------- */
+ } else if (repl != 0) { /* Replace .ti3 device values */
+ cgats *icg; /* input .ti2 cgats structure */
+ cgats *ocg; /* input/output .ti3 cgats structure */
+ int npat; /* Number of test patches */
+ int dim = 0; /* Dimenstionality of device space */
+ int fi; /* Field index */
+ int isi, ili; /* Input file sample and location indexes */
+ char *dfnames[5][4] = { /* Device colorspace names */
+ { "" },
+ { "GRAY_W" },
+ { "" },
+ { "RGB_R", "RGB_G", "RGB_B" },
+ { "CMYK_C", "CMYK_M", "CMYK_Y", "CMYK_K" }
+ };
+ int odim = 0; /* Output file device dimensionality */
+ int dfi[5][4]; /* Output file device colorspace indexes */
+ int osi; /* Output file sample id index */
+
+ /* Setup input .ti2 file */
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI2"); /* Calibration Target Information 2 */
+ if (icg->read_name(icg, datin_name))
+ error("CGATS file '%s' read error : %s",datin_name,icg->err);
+
+ if (icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error("Input file '%s' isn't a CTI2 format file",datin_name);
+
+ if (icg->ntables < 1)
+ error("Input file '%s' doesn't contain at least one table",datin_name);
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error("Input file '%s' doesn't contain any data sets",datin_name);
+
+ /* Figure out the color space */
+ if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error("Input file '%s' doesn't contain keyword COLOR_REP",datin_name);
+
+ if (strcmp(icg->t[0].kdata[fi],"CMYK") == 0) {
+ dim = 4;
+ } else if (strcmp(icg->t[0].kdata[fi],"RGB") == 0) {
+ dim = 3;
+ } else if (strcmp(icg->t[0].kdata[fi],"W") == 0) {
+ dim = 1;
+ } else
+ error("Input file '%s' keyword COLOR_REP has unknown value",datin_name);
+
+ /* Find fields we want in the input file */
+ if ((isi = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_ID",datin_name);
+ if (icg->t[0].ftype[isi] != nqcs_t)
+ error("Input file '%s' Field SAMPLE_ID is wrong type",datin_name);
+
+ if ((ili = icg->find_field(icg, 0, "SAMPLE_LOC")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_LOC",datin_name);
+ if (icg->t[0].ftype[ili] != cs_t
+ && icg->t[0].ftype[ili] != nqcs_t)
+ error("Input file '%s' Field SAMPLE_LOC is wrong type",datin_name);
+
+ /* Setup input/output .ti3 file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* Calibration Target Information 3 */
+ if (ocg->read_name(ocg, datout_name))
+ error("CGATS file '%s' read error : %s",datout_name,ocg->err);
+
+ if (ocg->t[0].tt != tt_other || ocg->t[0].oi != 0)
+ error("Input file '%s' isn't a CTI3 format file",datout_name);
+
+ if (ocg->ntables < 1)
+ error("Input file '%s' doesn't contain at least one table",datout_name);
+
+ if (npat != ocg->t[0].nsets)
+ error("Input file '%s' doesn't contain same number of data sets",datout_name);
+
+
+ /* Find the fields we want in the output file */
+
+ /* Figure out the color space */
+ if ((fi = ocg->find_kword(ocg, 0, "COLOR_REP")) < 0)
+ error("Input file '%s' doesn't contain keyword COLOR_REP",datout_name);
+
+ if (strncmp(ocg->t[0].kdata[fi],"CMYK",4) == 0) {
+ odim = 4;
+ } else if (strncmp(ocg->t[0].kdata[fi],"RGB",3) == 0) {
+ odim = 3;
+ } else if (strncmp(ocg->t[0].kdata[fi],"W",1) == 0) {
+ odim = 1;
+ } else
+ error("Input file '%s' keyword COLOR_REP has unknown value",datout_name);
+
+ if (odim != dim)
+ error("File '%s' has different device space to '%s'",datin_name, datout_name);
+
+ if ((osi = ocg->find_field(ocg, 0, "SAMPLE_ID")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_ID",datout_name);
+ if (ocg->t[0].ftype[osi] != nqcs_t)
+ error("Input file '%s' Field SAMPLE_ID is wrong type",datout_name);
+
+ for (i = 0; i < dim; i++) {
+ if ((dfi[dim][i] = ocg->find_field(ocg, 0, dfnames[dim][i])) < 0)
+ error("Input '%s' file doesn't contain field %s", datout_name, dfnames[dim][i]);
+ if (ocg->t[0].ftype[dfi[dim][i]] != r_t)
+ error("Input '%s' Field %s is wrong type",datout_name,dfnames[dim][i]);
+ }
+
+ /* Initialise, ready to read out all the values */
+ for (i = sr->reset(sr); i > 0; i--) { /* For all samples in .tiff file */
+ char loc[100]; /* Target patch location */
+ double P[4]; /* Robust/raw mean values */
+ int pixcnt; /* Pixel count */
+ int k, e;
+
+ if (tmean)
+ sr->read(sr, loc, NULL, P, NULL, &pixcnt);
+ else
+ sr->read(sr, loc, P, NULL, NULL, &pixcnt);
+
+ if (pixcnt == 0)
+ pnotscan++;
+
+ /* Search for this location in the .ti2 file */
+ for (j = 0; j < npat; j++) {
+ if (strcmp(loc, (char *)icg->t[0].fdata[j][ili]) == 0) {
+ char *sidp = (char *)icg->t[0].fdata[j][isi];
+
+ /* Search for this sample id in .ti3 file */
+ for (k = 0; k < npat; k++) {
+ if (strcmp(sidp, (char *)ocg->t[0].fdata[k][osi]) == 0) {
+ /* Update the device values */
+ for (e = 0; e < dim; e++) {
+ double vv = 100.0 * P[e]/255.0;
+ *((double *)ocg->t[0].fdata[k][dfi[dim][e]]) = vv;
+ }
+ break;
+ }
+ }
+ if (k >= npat && verb >= 1)
+ printf("Warning: Couldn't find sample '%s' in '%s'\n",sidp,datout_name);
+ break;
+ }
+ }
+ if (j >= npat && verb >= 1)
+ printf("Warning: Couldn't find location '%s' in '%s'\n",loc,datin_name);
+ }
+
+ /* Flush our changes */
+ if (verb)
+ printf("Writing output values to file '%s'\n",datout_name);
+
+ if (ocg->write_name(ocg, datout_name))
+ error("Write error to file '%s' : %s",datout_name,ocg->err);
+
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ /* ---------------------------------------------------------- */
+ } else if (colm > 0) { /* Using the image to measure color */
+ /* All this needs to track the code in spectro/printread.c */
+ cgats *icg; /* input .ti2 cgats structure */
+ cgats *ocg; /* input/output .ti3 cgats structure */
+ icmFile *rd_fp = NULL; /* Image to CIE lookup */
+ icc *rd_icco = NULL;
+ icmLuBase *luo;
+ mpp *mlu = NULL;
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ int nmask = 0; /* Device colorant mask */
+ int nchan = 0; /* Number of device chanels */
+ int npat; /* Number of input patches (inc. padding) */
+ int nopat = 0; /* Number of output patches */
+ int si; /* Sample id index */
+ int li; /* Location id index */
+ int ti; /* Temp index */
+ int fi; /* Colorspace index */
+
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI2"); /* special type Calibration Target Information 2 */
+ icg->add_other(icg, "CAL"); /* There may be a calibration too */
+
+ if (icg->read_name(icg, datin_name))
+ error("CGATS file '%s' read error : %s",datin_name,icg->err);
+
+ if (icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error("Input file '%s' isn't a CTI2 format file",datin_name);
+ if (icg->ntables < 1)
+ error("Input file '%s' doesn't contain at least one table",datin_name);
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error("Input file '%s' has no sets of data",datin_name);
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* special type Calibration Target Information 3 */
+
+ if (colm > 1) { /* Appending information to .ti3 */
+
+ if (ocg->read_name(ocg, datout_name))
+ error("CGATS file read error on '%s': %s",datout_name, ocg->err);
+
+ if (ocg->t[0].tt != tt_other || ocg->t[0].oi != 0)
+ error("Input file '%s' isn't a CTI3 format file",datout_name);
+ if (ocg->ntables < 1)
+ error("Input file '%s' doesn't at least exactly one table",datout_name);
+ if ((nopat = ocg->t[0].nsets) <= 0)
+ error("Input file '%s' has no existing sets of data",datout_name);
+
+ } else { /* Creating .ti3 */
+
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll printread", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL); /* What sort of device this is */
+ if ((ti = icg->find_kword(icg, 0, "SINGLE_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "SINGLE_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "COMP_GREY_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "COMP_GREY_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "MULTI_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "MULTI_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "FULL_SPREAD_PATCHES")) >= 0)
+ ocg->add_kword(ocg, 0, "FULL_SPREAD_PATCHES",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0)
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT",icg->t[0].kdata[ti], NULL);
+
+ /* See if there is a calibration in the .ti2, and copy it if there is */
+ {
+ int oi, tab;
+
+ oi = icg->get_oi(icg, "CAL");
+
+ for (tab = 0; tab < icg->ntables; tab++) {
+ if (icg->t[tab].tt == tt_other && icg->t[tab].oi == oi) {
+ break;
+ }
+ }
+ if (tab < icg->ntables) {
+ xcal *cal = NULL;
+
+ if (verb)
+ printf("Copying .cal from '%s' to '%s'\n",datin_name,datout_name);
+
+ if ((cal = new_xcal()) == NULL) {
+ error("new_xcal failed");
+ }
+ if (cal->read_cgats(cal, icg, tab, datin_name) != 0) {
+ error("%s",cal->err);
+ }
+
+ if (cal->write_cgats(cal, ocg)) {
+ error("%s",cal->err);
+ }
+
+ cal->del(cal);
+ }
+ }
+ }
+
+ if ((si = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_ID",datin_name);
+ if (icg->t[0].ftype[si] != nqcs_t)
+ error("Input file '%s' Field SAMPLE_ID is wrong type",datin_name);
+
+ /* Fields we want */
+ if (colm > 1) { /* Appending information to .ti3 */
+ if ((ti = ocg->find_field(ocg, 0, "SAMPLE_ID")) != 0)
+ error("Input file '%s' field SAMPLE_ID (%d) not in expected location (%d)",
+ datout_name, ti, 0);
+ } else {
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+ }
+
+ if ((li = icg->find_field(icg, 0, "SAMPLE_LOC")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_LOC",datin_name);
+ if (icg->t[0].ftype[li] != cs_t)
+ error("Input file '%s' field SAMPLE_LOC is wrong type",datin_name);
+
+ /* Figure out the color space */
+ if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error("Input file '%s' doesn't contain keyword COLOR_REPS",datin_name);
+
+ if ((nmask = icx_char2inkmask(icg->t[0].kdata[fi])) != 0) {
+ int i, j, ii;
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ int xyzix[3]; /* XYZ chanel indexes */
+ char *ident, *bident;
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+
+ nchan = icx_noofinks(nmask);
+ ident = icx_inkmask2char(nmask, 1);
+ bident = icx_inkmask2char(nmask, 0);
+
+ /* Device channels */
+ for (j = 0; j < nchan; j++) {
+ int imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 0, fname)) < 0)
+ error("Input file '%s' doesn't contain field %s",datin_name,fname);
+ if (icg->t[0].ftype[ii] != r_t)
+ error("Field %s is wrong type",fname);
+
+ if (colm > 1) { /* Appending information to .ti3 */
+ if (ocg->find_field(ocg, 0, fname) != 1 + j)
+ error("Input file '%s' field %s not in expected location",datout_name,fname);
+ } else {
+ ocg->add_field(ocg, 0, fname, r_t);
+ }
+ chix[j] = ii;
+ }
+
+ /* Approximate XYZ and real XYZ */
+ for (j = 0; j < 3; j++) {
+ if ((ii = icg->find_field(icg, 0, xyzfname[j])) >= 0) {
+
+ if (icg->t[0].ftype[ii] != r_t)
+ error("Input file '%s' field %s is wrong type",datin_name,xyzfname[j]);
+ }
+
+ if (colm > 1) { /* Appending information to .ti3 */
+ if (ocg->find_field(ocg, 0, xyzfname[j]) != 1 + nchan + j)
+ error("Input file '%s' field %s not in expected location",
+ datout_name,xyzfname[j]);
+ } else {
+ ocg->add_field(ocg, 0, xyzfname[j], r_t);
+ }
+ xyzix[j] = ii;
+ }
+
+ if (colm <= 1) { /* Creating .ti3 */
+ char fname[100];
+ sprintf(fname, "%s_XYZ", ident);
+ ocg->add_kword(ocg, 0, "COLOR_REP", fname, NULL);
+ }
+
+ if (colm > 1) { /* Appending .ti3 data */
+
+ /* Check that all the patches match */
+ for (ii = i = 0; i < npat; i++) {
+
+ if (strcmp(((char *)icg->t[0].fdata[i][si]), "0") == 0)
+ continue; /* Padding, so skip it */
+
+ /* Id's */
+ if (strcmp (((char *)icg->t[0].fdata[i][si]),
+ ((char *)ocg->t[0].fdata[ii][si])) != 0)
+ error("'%s' and '%s' field id's don't match at patch %d\n",datin_name,datout_name,i+1);
+
+ /* device values */
+ for (j = 0; j < nchan; j++) {
+ double ival, oval;
+ ival = *((double *)icg->t[0].fdata[i][chix[j]]);
+ oval = *((double *)ocg->t[0].fdata[ii][1 + j]);
+ if (fabs(ival - oval) > 0.001)
+ error("'%s' and '%s' device values (%f %f) don't match at patch %d %d\n",datin_name,datout_name,ival, oval, i+1, ii+1);
+ }
+ ii++;
+ }
+ if (ii != nopat)
+ error("Different number of patches in '%s' (%d) to expected(%d)",datout_name,nopat,ii);
+
+ } else { /* Read all the test patches in, and create output slots */
+ cgats_set_elem *setel; /* Array of set value elements */
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * (1 + nchan + 3))) == NULL)
+ error("Malloc failed!");
+
+
+ for (ii = i = 0; i < npat; i++) {
+ int k = 0;
+
+ if (strcmp(((char *)icg->t[0].fdata[i][si]), "0") == 0)
+ continue; /* Padding, so skip it */
+
+ /* Id */
+ setel[k++].c = ((char *)icg->t[0].fdata[i][si]);
+
+ /* device values */
+ for (j = 0; j < nchan; j++) {
+ setel[k++].d = *((double *)icg->t[0].fdata[i][chix[j]]);
+ }
+
+ /* Unset XYZ values */
+ setel[k++].d = -1.0;
+ setel[k++].d = -1.0;
+ setel[k++].d = -1.0;
+
+ ocg->add_setarr(ocg, 0, setel);
+
+ ii++;
+ }
+ nopat = ii;
+ free(setel);
+ }
+ free(ident);
+ free(bident);
+
+ } else
+ error("Input file '%s' keyword COLOR_REPS has unknown value",datin_name);
+
+ /* Setup RGB to XYZ conversion */
+ {
+ int inn, outn; /* Chanels for input and output spaces */
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int rv;
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(prof_name,"r")) == NULL)
+ error("Write: Can't open file '%s'",prof_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) == 0) {
+
+ /* Get the Fwd table, absolute with XYZ override */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric,
+ icSigXYZData, icmLuOrdNorm)) == NULL) {
+ error("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ /* Get details of conversion */
+ luo->spaces(luo, &ins, &inn, &outs, &outn, NULL, NULL, NULL, NULL, NULL);
+
+ /* Check that it matches what we expect */
+
+ } else { /* Not a valid ICC */
+ inkmask cnv_nmask = 0; /* Conversion input nmask */
+
+ /* Close out the ICC profile */
+ rd_icco->del(rd_icco);
+ rd_icco = NULL;
+ rd_fp->del(rd_fp);
+ rd_fp = NULL;
+
+ /* If we don't have an ICC lookup object, look for an MPP */
+
+ if ((mlu = new_mpp()) == NULL)
+ error ("Creation of MPP object failed");
+
+ if ((rv = mlu->read_mpp(mlu, prof_name)) == 0) {
+
+ /* mlu defaults to absolute XYZ lookup */
+ mlu->get_info(mlu, &cnv_nmask, &inn, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ outn = 3;
+ outs = icSigXYZData;
+
+ if ((ins = icx_colorant_comb_to_icc(cnv_nmask)) == 0)
+ error ("Couldn't match MPP mask to valid ICC colorspace");
+
+ } else {
+ mlu->del(mlu);
+ mlu = NULL;
+ error("File '%s' failed to read as ICC or MPP profile",prof_name);
+ }
+ }
+ if (inn != depth || tiffs != ins)
+ error("%s profile '%s' doesn't match TIFF file type",luo != NULL ? "ICC" : "MPP", prof_name);
+ }
+
+ /* Initialise, ready to read out all the values */
+ for (i = sr->reset(sr); i > 0; i--) { /* For all samples in .tiff file */
+ char loc[100]; /* Target patch location */
+ double P[ICX_MXINKS]; /* Robust/true mean values */
+ double xyz[3]; /* profile XYZ value */
+ int pixcnt; /* Pixel count */
+ int k, e;
+
+ if (tmean)
+ sr->read(sr, loc, NULL, P, NULL, &pixcnt);
+ else
+ sr->read(sr, loc, P, NULL, NULL, &pixcnt);
+
+ if (pixcnt == 0)
+ pnotscan++;
+
+ /* Search for this location in the .ti2 file */
+ for (j = 0; j < npat; j++) {
+ if (strcmp(loc, (char *)icg->t[0].fdata[j][li]) == 0) { /* Got location */
+ char *sidp = (char *)icg->t[0].fdata[j][si]; /* Get id */
+
+ if (strcmp(sidp, "0") == 0)
+ break; /* Padding, so ignore it */
+
+ /* Search for this sample id in .ti3 file */
+ for (k = 0; k < nopat; k++) {
+ if (strcmp(sidp, (char *)ocg->t[0].fdata[k][si]) == 0) {
+
+//printf("Loc %s, ID %s got RGB value %f %f %f\n",sidp, loc, P[0], P[1], P[2]);
+
+ /* Convert RGB to XYZ */
+ for (e = 0; e < depth; e++)
+ P[e] /= 255.0; /* Convert to 0.0 .. 1.0 range */
+
+ /* Convert to XYZ */
+ if (luo != NULL)
+ luo->lookup(luo, xyz, P);
+ else
+ mlu->lookup(mlu, xyz, P);
+
+ /* Sanity check XYZ ? */
+ // ~~~99
+
+ /* Update the XYZ values */
+ for (e = 0; e < 3; e++) {
+ double ev = *((double *)ocg->t[0].fdata[k][1 + nchan + e]);
+
+ if (ev != -1.0)
+ error("Found an existing value in '%s' file (%f)",datout_name,ev);
+
+ *((double *)ocg->t[0].fdata[k][1 + nchan + e]) = 100.0 * xyz[e];
+ }
+ break;
+ }
+ }
+ if (k >= nopat)
+ error("Couldn't find sample '%s' in '%s'\n",sidp,datout_name);
+ break;
+ }
+ }
+ if (j >= npat && verb >= 1)
+ error("Couldn't find location '%s' in '%s'\n",loc, datin_name);
+ }
+
+ /* Warn if not all patch values have been filled */
+ if (verb) {
+ int e, k;
+ for (k = 0; k < nopat; k++) {
+ for (e = 0; e < 3; e++) {
+ double ev = *((double *)ocg->t[0].fdata[k][1 + nchan + e]);
+
+ if (ev == -1.0)
+ break;
+ }
+ if (e < 3)
+ break;
+ }
+ if (k < nopat)
+ printf("Not all sample values have been filled\n");
+ else
+ printf("All sample values have been filled\n");
+ }
+
+ if (verb)
+ printf("Writing output values to file '%s'\n",datout_name);
+
+ if (ocg->write_name(ocg, datout_name))
+ error("File '%s' write error : %s",datout_name,ocg->err);
+
+ if (luo != NULL)
+ luo->del(luo);
+ if (rd_icco != NULL)
+ rd_icco->del(rd_icco);
+ if (rd_fp != NULL)
+ rd_fp->del(rd_fp);
+ if (mlu != NULL)
+ mlu->del(mlu);
+
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ /* ----------------------------------- */
+ } else { /* Normal scan calibration */
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ int ti; /* Temp index */
+ int sx; /* Sample id index */
+ int isLab = 0; /* D50 Lab reference */
+ int Xx, Yx, Zx; /* XYZ_X, XYZ_Y, XYZ_Z index */
+ int spec_n = 0; /* Number of spectral bands */
+ double spec_wl_short;/* First reading wavelength in nm (shortest) */
+ double spec_wl_long; /* Last reading wavelength in nm (longest) */
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ int npat; /* Number of test patches in it8 chart */
+ int nsetel = 0; /* Number of output set elements */
+ cgats_set_elem *setel; /* Array of set value elements */
+
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, ""); /* Accept any type */
+ if (icg->read_name(icg, datin_name))
+ error("CGATS file '%s' read error : %s",datin_name,icg->err);
+
+ /* ~~ should accept ti2 file and convert RGB to XYZ using */
+ /* device cal., to make W/RGB/CMYK ->XYZ reading chart ~~ */
+ if (icg->ntables < 1)
+ error("Input file '%s' doesn't contain at least one table",datin_name);
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error("File '%s' no sets of data in first table",datin_name);
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll target", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","INPUT", NULL); /* What sort of device this is */
+ ocg->add_kword(ocg, 0, "COLOR_REP","XYZ_RGB", NULL);
+
+ /* Fields we want from input chart reference file */
+ if ((sx = icg->find_field(icg, 0, "Sample_Name")) < 0) {
+ if ((sx = icg->find_field(icg, 0, "SAMPLE_NAME")) < 0) {
+ if ((sx = icg->find_field(icg, 0, "SAMPLE_LOC")) < 0) {
+ if ((sx = icg->find_field(icg, 0, "SAMPLE_ID")) < 0) {
+ error("Input file '%s' doesn't contain field SAMPLE_ID, Sample_Name or SAMPLE_NAME",datin_name);
+ }
+ }
+ }
+ }
+ if (icg->t[0].ftype[sx] != nqcs_t && icg->t[0].ftype[sx] != cs_t)
+ error("Input file '%s' field %s is wrong type", datin_name, icg->t[0].fsym[sx]);
+
+ if ((Xx = icg->find_field(icg, 0, "XYZ_X")) < 0) {
+ if ((Xx = icg->find_field(icg, 0, "LAB_L")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_X or LAB_L",datin_name);
+
+ isLab = 1;
+ if (icg->t[0].ftype[Xx] != r_t)
+ error("Input file '%s' field LAB_L is wrong type",datin_name);
+ if ((Yx = icg->find_field(icg, 0, "LAB_A")) < 0)
+ error("Input file doesn't contain field LAB_A",datin_name);
+ if (icg->t[0].ftype[Yx] != r_t)
+ error("Input file '%s' field LAB_A is wrong type",datin_name);
+ if ((Zx = icg->find_field(icg, 0, "LAB_B")) < 0)
+ error("Input file '%s' doesn't contain field LAB_B",datin_name);
+ if (icg->t[0].ftype[Zx] != r_t)
+ error("Input file '%s' field LAB_B is wrong type",datin_name);
+ } else {
+ if (icg->t[0].ftype[Xx] != r_t)
+ error("Input file '%s' field XYZ_X is wrong type",datin_name);
+ if ((Yx = icg->find_field(icg, 0, "XYZ_Y")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Y",datin_name);
+ if (icg->t[0].ftype[Yx] != r_t)
+ error("Input file '%s' field XYZ_Y is wrong type",datin_name);
+ if ((Zx = icg->find_field(icg, 0, "XYZ_Z")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Z",datin_name);
+ if (icg->t[0].ftype[Zx] != r_t)
+ error("Input file '%s' field XYZ_Z is wrong type",datin_name);
+ }
+
+ /* Find possible spectral fields in reference */
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) >= 0) {
+ spec_n = atoi(icg->t[0].kdata[ti]);
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_START_NM",datin_name);
+ spec_wl_short = atof(icg->t[0].kdata[ti]);
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_END_NM",datin_name);
+ spec_wl_long = atof(icg->t[0].kdata[ti]);
+
+ /* Find the fields for spectral values */
+ for (i = 0; i < spec_n; i++) {
+ char buf[100];
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(spec_wl_short + ((double)i/(spec_n-1.0))
+ * (spec_wl_long - spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[i] = icg->find_field(icg, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",datin_name);
+ }
+ }
+
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+ nsetel += 1;
+ ocg->add_field(ocg, 0, "XYZ_X", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Y", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Z", r_t);
+ nsetel += 3;
+
+ /* If we have spectral information, output it too */
+ if (spec_n > 0) {
+ char buf[100];
+
+ nsetel += spec_n; /* Spectral values */
+ sprintf(buf,"%d", spec_n);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+ sprintf(buf,"%f", spec_wl_short);
+ ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
+ sprintf(buf,"%f", spec_wl_long);
+ ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);
+
+ /* Generate fields for spectral values */
+ for (i = 0; i < spec_n; i++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(spec_wl_short + ((double)i/(spec_n-1.0))
+ * (spec_wl_long - spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+ ocg->add_field(ocg, 0, buf, r_t);
+ }
+ }
+
+ if (depth == 1) {
+ ocg->add_field(ocg, 0, "GREY", r_t);
+ ocg->add_field(ocg, 0, "STDEV_GREY", r_t);
+ } else if (depth == 3) {
+ ocg->add_field(ocg, 0, "RGB_R", r_t);
+ ocg->add_field(ocg, 0, "RGB_G", r_t);
+ ocg->add_field(ocg, 0, "RGB_B", r_t);
+ ocg->add_field(ocg, 0, "STDEV_R", r_t);
+ ocg->add_field(ocg, 0, "STDEV_G", r_t);
+ ocg->add_field(ocg, 0, "STDEV_B", r_t);
+ } else if (depth == 4) {
+ ocg->add_field(ocg, 0, "CMYK_C", r_t);
+ ocg->add_field(ocg, 0, "CMYK_M", r_t);
+ ocg->add_field(ocg, 0, "CMYK_Y", r_t);
+ ocg->add_field(ocg, 0, "CMYK_K", r_t);
+ ocg->add_field(ocg, 0, "STDEV_C", r_t);
+ ocg->add_field(ocg, 0, "STDEV_M", r_t);
+ ocg->add_field(ocg, 0, "STDEV_Y", r_t);
+ ocg->add_field(ocg, 0, "STDEV_K", r_t);
+ }
+ nsetel += 2 * depth;
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL)
+ error("Malloc failed!");
+
+ /* Initialise, ready to read out all the values */
+ for (j = 0; j < npat; j++) {
+ char id[100]; /* Input patch id */
+
+ /* Normalise labels */
+ fix_it8(id,((char *)icg->t[0].fdata[j][sx])); /* Copy and fix */
+
+ /* Search for matching id */
+ for (i = sr->reset(sr); i > 0; i--) {
+ char tod[100]; /* Output patch id */
+ char od[100]; /* Output patch id */
+ double P[4]; /* Robust/true mean values */
+ double sdP[4]; /* Standard deviation */
+ int pixcnt; /* Pixel count */
+
+ if (tmean)
+ sr->read(sr, tod, NULL, P, sdP, &pixcnt);
+ else
+ sr->read(sr, tod, P, NULL, sdP, &pixcnt);
+
+ if (pixcnt == 0)
+ pnotscan++;
+
+ fix_it8(od,tod);
+
+ if (strcmp(id,od) == 0) {
+ int k = 0, m;
+ double XYZ[3];
+
+ setel[k++].c = id;
+
+ XYZ[0] = *((double *)icg->t[0].fdata[j][Xx]);
+ XYZ[1] = *((double *)icg->t[0].fdata[j][Yx]);
+ XYZ[2] = *((double *)icg->t[0].fdata[j][Zx]);
+ if (isLab) {
+ icmLab2XYZ(&icmD50, XYZ, XYZ);
+ XYZ[0] *= 100.0;
+ XYZ[1] *= 100.0;
+ XYZ[2] *= 100.0;
+ }
+
+ setel[k++].d = XYZ[0];
+ setel[k++].d = XYZ[1];
+ setel[k++].d = XYZ[2];
+
+ if (spec_n > 0) {
+ for (m = 0; m < spec_n; m++) {
+ setel[k++].d = *((double *)icg->t[0].fdata[j][spi[m]]);
+ }
+ }
+
+ for (m = 0; m < depth; m++)
+ setel[k++].d = P[m] * 100.0/255.0;
+ for (m = 0; m < depth; m++)
+ setel[k++].d = sdP[m] * 100.0/255.0;
+
+ ocg->add_setarr(ocg, 0, setel);
+
+ break;
+ }
+ }
+ if (i <= 0 && verb >= 1)
+ printf("Warning: Couldn't match field '%s'\n",id);
+ }
+
+ if (verb)
+ printf("Writing output values to file '%s'\n",datout_name);
+
+ if (ocg->write_name(ocg, datout_name))
+ error("Output file '%s' write error : %s",datout_name, ocg->err);
+
+ free(setel);
+
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ }
+ }
+
+ if (pnotscan > 0)
+ warning("A total of %d patches had no value set!",pnotscan);
+
+ /* Clean up */
+ sr->free(sr);
+
+ TIFFClose(rh);
+
+ if (flags & SI_SHOW_FLAGS)
+ TIFFClose(wh);
+
+ return 0;
+}
+
+/* Fix IT8 chart labels */
+void fix_it8(char *o, char *i) {
+ if (strcmp(i,"Dmin")==0) {
+ strcpy(o,"GS00");
+ return;
+ }
+ if (strcmp(i,"Dmax")==0) {
+ strcpy(o,"GS23");
+ return;
+ }
+ while (!isdigit(*i) && *i != '\000') /* Skip non-numbers */
+ *o++ = *i++;
+ if (i[0] != '\000' && i[1] == '\000') /* Single last digit */
+ *o++ = '0'; /* Add leading zero */
+ strcpy(o, i); /* Copy remainder */
+}
+
+/********************************************************************************/
diff --git a/scanin/scanrd.c b/scanin/scanrd.c
new file mode 100644
index 0000000..a915e44
--- /dev/null
+++ b/scanin/scanrd.c
@@ -0,0 +1,4659 @@
+
+/*
+ * Raster Color Target Scan Input module
+ * This is the core chart recognition code.
+ *
+ * Author: Graeme Gill
+ *
+ * Copyright 1995 - 2008 Graeme W. Gill, All right reserved.
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/*
+ * To Do:
+ * Add option to output a raster file made from the .cht and example values.
+ *
+ * Fix sboxes parameters/digitization to fix "droop" in box areas.
+ * Scale parameters with image size.
+ * To handle high res, introduce automatic sub-sampler.
+ * Change reference parser to make it more forgiving - use cgats parser ?
+ */
+
+#undef DEBUG
+
+#define VERSION "1.0"
+
+/* Behaviour defines */
+#undef DIAGN /* Allow diagonal connectivity of groups */
+#define AA_LINES /* Plot diagnostics using anti-aliased lines */
+
+#define MATCHCC 0.3 /* Match correlation threshold - reject any match under this */
+ /* (Might want to be able to override this in command line) */
+
+#define ALT_ROT_TH 0.7 /* Correlation threshold of alternate rotations to be greater than this */
+
+#define TH (20.0 * 20.0) /* Initial color change threshhold */
+
+#undef DBG
+#define dbgo stdout
+#define DBG(aaa) fprintf aaa, fflush(dbgo)
+
+#include <stdio.h>
+/* #include <fcntl.h> */ /* In case DOS binary stuff is needed */
+#include <string.h>
+#include <math.h>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+/* #include <fname.h> */
+
+#include "numlib.h"
+#include "scanrd_.h"
+
+/* ------------------------------------------------- */
+/* Implementations of public functions */
+static void free_scanrd(scanrd *s);
+static int scanrd_reset(scanrd *s);
+static int scanrd_read(scanrd *ps, char *id, double *P, double *mP,
+ double *sdP, int *cnt);
+static unsigned int scanrd_error(scanrd *s, char **errm);
+
+/* Forward internal function declaration */
+static scanrd_ *new_scanrd(int flags, int verb, double gammav,
+ int (*write_line)(void *ddata, int y, char *src), void *ddata,
+ int w, int h, int d, int td, int p,
+ int (*read_line)(void *fdata, int y, char *dst), void *fdata,
+ char *refname);
+static int read_input(scanrd_ *s);
+static int calc_lines(scanrd_ *s);
+static int show_lines(scanrd_ *s);
+static int calc_perspective(scanrd_ *s);
+static int calc_rotation(scanrd_ *s);
+static int calc_elists(scanrd_ *s, int ref);
+static int write_elists(scanrd_ *s);
+static int read_relists(scanrd_ *s);
+static int do_match(scanrd_ *s);
+static int compute_ptrans(scanrd_ *s);
+static int compute_man_ptrans(scanrd_ *s, double *sfids);
+static int improve_match(scanrd_ *s);
+static int setup_sboxes(scanrd_ *s);
+static int do_value_scan(scanrd_ *s);
+static int compute_xcc(scanrd_ *s);
+//static int restore_best(scanrd_ *s);
+static int show_sbox(scanrd_ *s);
+static int show_groups(scanrd_ *s);
+static int scanrd_write_diag(scanrd_ *s);
+static void toRGB(unsigned char *dst, unsigned char *src, int depth, int bpp);
+static void XYZ2Lab(double *out, double *in);
+static void pval2Lab(double *out, double *in, int depth);
+/* ------------------------------------------------- */
+
+/* Read in a chart, and either create a reference or make values available, */
+/* by using reset() and read() to get values read */
+scanrd *do_scanrd(
+int flags, /* option flags */
+int verb, /* verbosity level */
+
+double gammav, /* Apprimate gamma encoding of image (0.0 = default 2.2) */
+double *sfid, /* Specified four fiducials x1, y1 .. x4, y4, NULL if auto recognition */
+ /* Typical clockwise from top left */
+
+int w, int h, /* Width and Height of input raster in pixels */
+int d, int td, int p, /* Useful plane depth, Total depth, Bit presision of input pixels */
+int (*read_line)(void *fdata, int y, char *dst), /* Read RGB line of source file */
+void *fdata, /* Opaque data for read_line */
+
+char *refname, /* reference file name */
+
+int (*write_line)(void *ddata, int y, char *src), /* Write RGB line of diag file */
+void *ddata /* Opaque data for write_line */
+) {
+ scanrd_ *s;
+
+ /* allocate the basic object */
+ if (verb >= 2)
+ DBG((dbgo,"About to allocate scanrd_ object\n"));
+ if ((s = new_scanrd(flags, verb, gammav, write_line, ddata, w, h, d, td, p, read_line, fdata, refname)) == NULL)
+ return NULL;
+
+ if (s->errv != 0) /* Some other error from new_scanrd() */
+ return (scanrd *)s;
+
+ if (s->verb >= 2)
+ DBG((dbgo,"About to read input tiff file and discover groups\n"));
+ if (read_input(s))
+ goto sierr; /* Error */
+
+ if (s->flags & SI_SHOW_GROUPS)
+ if (show_groups(s))
+ goto sierr; /* Error */
+
+ if (s->verb >= 2)
+ DBG((dbgo,"About to calculate edge lines\n"));
+ if (calc_lines(s))
+ goto sierr; /* Error */
+ if (s->verb >= 2)
+ DBG((dbgo,"%d useful edges out of %d\n",s->novlines, s->noslines));
+
+ if (s->flags & SI_PERSPECTIVE) {
+ if (s->verb >= 2)
+ DBG((dbgo,"About to calculate perspective correction\n"));
+ if (calc_perspective(s)) {
+ 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 */
+ }
+ }
+
+ if (s->verb >= 2)
+ DBG((dbgo,"About to calculate rotation\n"));
+ if (calc_rotation(s)) {
+ if (s->flags & SI_SHOW_LINES) {
+ s->flags &= ~SI_SHOW_ROT; /* Calc rotation failed! */
+ show_lines(s);
+ }
+ goto sierr; /* Error */
+ }
+
+ if (s->flags & SI_BUILD_REF) { /* If generating a chart reference file */
+ /* Calculate the edge lists and write it to the file */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to build feature information\n"));
+ if (calc_elists(s, 1)) /* reference */
+ goto sierr; /* Error */
+
+ if (s->verb >= 2)
+ DBG((dbgo,"About to write feature reference information\n"));
+ if (write_elists(s))
+ goto sierr; /* Error */
+ } else {
+ /* If we are matching to the reference and generating an output data file */
+ int rv;
+
+ /* Calculate the edge lists read for a match */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to calculate feature information\n"));
+ if (calc_elists(s, 0)) /* match */
+ goto sierr; /* Error */
+
+ if (s->verb >= 2)
+ DBG((dbgo,"About to read reference feature information\n"));
+ if (read_relists(s))
+ goto sierr; /* Error */
+ if (s->verb >= 2)
+ DBG((dbgo,"Read of chart reference file succeeded\n"));
+
+ if (sfid != NULL) { /* Manual matching */
+ if (s->verb >= 2)
+ DBG((dbgo,"Using manual matching\n"));
+
+ if (s->havefids == 0) {
+ s->errv = SI_NO_FIDUCIALS_ERR;
+ sprintf(s->errm,"Chart recognition definition file doesn't contain fiducials");
+ goto sierr; /* Error */
+ }
+ if (compute_man_ptrans(s, sfid))
+ goto sierr;
+
+ /* Do the actual scan given out manual transformation matrix */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to setup value scanrdg boxes\n"));
+ if (setup_sboxes(s))
+ goto sierr;
+ if (s->verb >= 2)
+ DBG((dbgo,"About to read raster values\n"));
+ if (do_value_scan(s))
+ goto sierr;
+
+ } else { /* Automatic matching */
+
+ /* Attempt to match input file with reference */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to match features\n"));
+ if ((rv = do_match(s)) != 0) {
+ if (rv == 1) { /* No reasonable rotation found */
+ s->errv = SI_POOR_MATCH;
+ sprintf(s->errm,"Pattern match wasn't good enough");
+ }
+ goto sierr;
+ }
+
+ /* If there is patch matching data and more than one */
+ /* feasible matching rotation, try and discriminate between them. */
+ if (s->xpt && s->norots > 1) {
+ int i, j;
+ int flags = s->flags;
+
+ s->flags &= ~SI_SHOW_SAMPLED_AREA; /* Don't show areas for trials */
+
+ /* For each candidate rotation, scan in the pixel values */
+ for (s->crot = 0; s->crot < s->norots; s->crot++) {
+
+ /* Compute transformation from reference to input file */
+ 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))
+ goto sierr;
+
+ /* Setup the input boxes ready for scanning in the input values */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to setup value scanrdg boxes\n"));
+ if (setup_sboxes(s))
+ goto sierr;
+
+ /* Scan in the pixel values */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to read raster values\n"));
+ if (do_value_scan(s))
+ goto sierr;
+
+ /* Copy to this rotation values so that the best can be restored */
+ if (s->xpt != 0) { /* Got expected patch values to compare with */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to compute expected value correlation\n"));
+ if (compute_xcc(s))
+ goto sierr;
+ }
+ }
+
+ /* Pick the best from the candidate rotation */
+ if (s->verb >= 2) {
+ DBG((dbgo,"Expected value distance values are:\n"));
+ for (i = 0; i < s->norots; i++) {
+ DBG((dbgo,"%d, rot %f: %f\n", i, DEG(s->rots[i].irot), s->rots[i].xcc));
+ }
+ }
+
+ for (j = 0, i = 1; i < s->norots; i++) {
+ if (s->rots[i].xcc < s->rots[j].xcc)
+ j = i;
+ }
+
+ if (s->verb >= 2)
+ DBG((dbgo,"Chosen rotation %f deg. as best\n",DEG(s->rots[j].irot)));
+
+ s->crot = j;
+ s->flags = flags; /* Restore flags */
+ }
+
+ /* Setup transformation to be that for chosen rotation for diagnostics */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to compute final match transform\n"));
+ if (compute_ptrans(s))
+ goto sierr;
+
+ if (s->verb >= 2)
+ DBG((dbgo,"Improve match\n"));
+ if (improve_match(s))
+ goto sierr;
+
+ /* After choosing rotation of improving the fit, rescan the values */
+ if (s->verb >= 2)
+ DBG((dbgo,"About to setup value scanrdg boxes\n"));
+ if (setup_sboxes(s))
+ goto sierr;
+ if (s->verb >= 2)
+ DBG((dbgo,"About to read raster values\n"));
+ if (do_value_scan(s))
+ goto sierr;
+ }
+
+ if (s->flags & SI_SHOW_SBOX) {
+ show_sbox(s); /* Draw sample box outlines on diagnostic raster */
+ }
+ }
+ 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))
+ return (scanrd *)s; /* Error */
+
+ return (scanrd *)s;
+}
+
+
+/********************************************************************************/
+
+/* Allocate the basic scanrd object */
+/* Return NULL on failure to allocate */
+/* Need to check errv for other problems */
+static scanrd_
+*new_scanrd(
+ int flags, /* option flags */
+ int verb, /* verbosity level */
+ double gammav, /* Approximate gamma encoding of image (0.0 = default 2.2) */
+ int (*write_line)(void *ddata, int y, char *src), /* Write RGB line of diag file */
+ void *ddata, /* Opaque data for write_line() */
+ int w, int h, /* Width and Height of input raster in pixels */
+ int d, int td, int p, /* Useful plane Depth, Total depth, Bit presision of input pixels */
+ int (*read_line)(void *fdata, int y, char *dst), /* Read RGB line of source file */
+ void *fdata, /* Opaque data for read_line() */
+
+ char *refname /* reference file name */
+) {
+ scanrd_ *s;
+
+ if ((s = (scanrd_ *)calloc(1, sizeof(scanrd_))) == NULL)
+ return NULL;
+
+ /* Public functions */
+ s->public.reset = scanrd_reset;
+ s->public.read = scanrd_read;
+ s->public.error = scanrd_error;
+ s->public.free = free_scanrd;
+
+ if (flags & (SI_SHOW_ROT | SI_SHOW_PERS | SI_SHOW_IMPL | SI_SHOW_ALL_LINES))
+ flags |= SI_SHOW_LINES; /* Key all line stuff off SI_SHOW_LINES */
+
+ if (flags & (SI_SHOW_SBOX_OUTLINES | SI_SHOW_SBOX_NAMES | SI_SHOW_SBOX_AREAS))
+ flags |= SI_SHOW_SBOX;; /* Key all sample box stuff off SI_SHOW_SBOX */
+
+ if (write_line == NULL)
+ flags &= ~SI_SHOW_FLAGS; /* If no diag file, turn off show flags */
+
+ s->flags = flags;
+ s->verb = verb;
+
+ s->errv = 0;
+ s->errm[0] = '\0';
+
+ if (gammav <= 0.0)
+ gammav = 2.2; /* default */
+ s->gammav = gammav;
+ s->width = w;
+ s->height = h;
+ s->depth = d;
+ s->tdepth = td;
+ s->bpp = p;
+
+ if (d > MXDE) {
+ s->errv = SI_PIX_DEPTH_ERR;
+ sprintf(s->errm,"scanrd: Pixel depth is too large");
+ return s;
+ }
+
+ if (p != 8 && p != 16) {
+ s->errv = SI_BIT_DEPTH_ERR;
+ sprintf(s->errm,"scanrd: Pixel bits/pixel is not 8 or 16");
+ return s;
+ }
+ if (p == 8)
+ s->bypp = 1;
+ else
+ s->bypp = 2;
+
+ if (verb >= 2)
+ DBG((dbgo,"Verbosity = %d, flags = 0x%x\n",verb, flags));
+
+ /* RGB Diagnostic output raster array requested */
+ if ((flags & SI_SHOW_FLAGS) && write_line != NULL) {
+ if ((s->out = malloc(3 * w * h)) == NULL) {
+ s->errv = SI_MALLOC_DIAG_RAST;
+ sprintf(s->errm,"scanrd: Diagnostic output raster array malloc failed");
+ return s;
+ }
+ }
+
+ s->noslines = 0;
+ s->novlines = 0;
+ s->gdone = NULL;
+ s->irot = 0.0;
+ s->norots = 0;
+
+ s->ppc[0] = 0.0;
+ s->ppc[1] = 0.0;
+ s->ppc[2] = 0.0;
+ s->ppc[3] = 0.0;
+
+ /* Set overall perspective transform to null */
+ s->ptrans[0] = 1.0;
+ s->ptrans[1] = 0.0;
+ s->ptrans[2] = 0.0;
+ s->ptrans[3] = 0.0;
+ s->ptrans[4] = 1.0;
+ s->ptrans[5] = 0.0;
+ s->ptrans[6] = 0.0;
+ s->ptrans[7] = 0.0;
+
+ INIT_ELIST(s->xelist);
+ INIT_ELIST(s->yelist);
+ INIT_ELIST(s->ixelist);
+ INIT_ELIST(s->iyelist);
+ INIT_ELIST(s->rxelist);
+ INIT_ELIST(s->ryelist);
+ s->rbox_shrink = 0.9;
+ s->xpt = 0;
+
+ s->nsbox = 0;
+ s->sboxes = NULL;
+ s->sbstart = NULL;
+ s->sbend = NULL;
+ s->csi = 0;
+ s->cei = 0;
+ s->alist = NULL;
+
+ s->next_read = 0;
+
+ s->refname = refname;
+
+ s->inited = 0;
+ s->vrego = s->vregn = NULL;
+ s->no_vo = s->no_vn = 0;
+ s->hrego = s->hregn = NULL;
+ s->no_ho = s->no_hn = 0;
+ s->th = TH;
+ s->divval = 0.25;
+ s->adivval = 0.0;
+ s->divc = 0;
+
+ /* aa line init */
+ s->aa_inited = 0; /* Let line init do the rest */
+ s->coverage = NULL;
+
+ /* Callbacks */
+ s->read_line = read_line;
+ s->fdata = fdata;
+
+ s->write_line = write_line;
+ s->ddata = ddata;
+
+ return s;
+}
+
+static void free_elist_array(elist *el);
+
+/* Free the object up */
+static void
+free_scanrd(
+scanrd *ps
+) {
+ scanrd_ *s = (scanrd_ *)ps; /* Cast public to private */
+ points *tp;
+
+ free_elist_array(&s->xelist);
+ free_elist_array(&s->yelist);
+ free_elist_array(&s->ixelist);
+ free_elist_array(&s->iyelist);
+ free_elist_array(&s->rxelist);
+ free_elist_array(&s->ryelist);
+
+ if (s->sboxes != NULL)
+ free(s->sboxes);
+ if (s->sbstart != NULL)
+ free(s->sbstart);
+ if (s->sbend != NULL)
+ free(s->sbend);
+ s->alist = NULL;
+
+ /* Free up done line list */
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->r != NULL)
+ free(tp->r);
+ free(tp);
+ END_FOR_ALL_ITEMS(tp);
+ s->gdone = NULL;
+
+ /* Points were deleted with gdone ??? */
+ if(s->vrego != NULL)
+ free(s->vrego);
+ if(s->vregn)
+ free(s->vregn);
+ if(s->hrego != NULL)
+ free(s->hrego);
+ if(s->hregn != NULL)
+ free(s->hregn);
+ s->inited = 1;
+
+ /* Free up output diag array */
+ if (s->out != NULL)
+ free(s->out);
+
+ /* Free up aa line array */
+ if (s->coverage != NULL)
+ free(s->coverage);
+ free(s);
+}
+
+
+/* Return the error flag, and set the message pointer */
+static unsigned int
+scanrd_error(scanrd *ps, char **errm) {
+ scanrd_ *s = (scanrd_ *)ps; /* Cast public to private */
+ *errm = s->errm;
+ return s->errv;
+}
+
+/********************************************************************************/
+static int analize(scanrd_ *s, unsigned char *inp[6], int y);
+
+/* Read in and process the input file */
+/* Return non-zero on error */
+static int
+read_input(scanrd_ *s) {
+ unsigned char *in[6]; /* Pointer to six input buffers */
+ int w = s->width; /* Raster width */
+ int h = s->height; /* Raster height */
+ int i, y;
+
+ /* Allocate input line buffers */
+ for (i = 0; i < 6; i++) {
+ if ((in[i] = malloc(s->tdepth * w * s->bypp)) == NULL) {
+ s->errv = SI_MALLOC_INPUT_BUF;
+ sprintf(s->errm,"scanrd: Failed to malloc input line buffers");
+ return 1;
+ }
+ }
+
+ /* Prime the input buffers with 5 lines */
+ for (y = 0; y < 5; y++) {
+ if (s->read_line(s->fdata, y, (char *)in[y])) {
+ s->errv = SI_RAST_READ_ERR;
+ sprintf(s->errm,"scanrd: read_line() returned error");
+ return 1;
+ }
+ }
+ /* Process the tiff file line by line (Assume at least 6 lines in total raster) */
+ for (; y < h; ++y) {
+ unsigned char *tt;
+ if (s->read_line(s->fdata, y, (char *)in[5])) {
+ s->errv = SI_RAST_READ_ERR;
+ sprintf(s->errm,"scanrd: read_line() returned error");
+ return 1;
+ }
+
+ if (analize(s, in, y)) {
+ return 1;
+ }
+
+ tt = in[0]; /* Shuffle buffers about */
+ in[0] = in[1];
+ in[1] = in[2];
+ in[2] = in[3];
+ in[3] = in[4];
+ in[4] = in[5];
+ in[5] = tt;
+
+ }
+ s->adivval /= (double)s->divc; /* Average divider value, 1.0 = 0 degrees, 0.0 = 45 degrees */
+ if (s->adivval < 0.0)
+ s->adivval = 0.0;
+ else if (s->adivval > 1.0)
+ s->adivval = 1.0;
+
+ if (s->verb >= 2)
+ DBG((dbgo,"adivval = %f\n",s->adivval));
+
+ /* Free the input line buffers */
+ for (i = 0; i < 6; i++)
+ free(in[i]);
+
+ return 0;
+}
+
+/********************************************************************************/
+
+#ifdef NEVER /* Before 22/5/2004 */
+#define THRN 1.0 /* Threshold above average ratio - numerator */
+#define THRD 2.0 /* Threshold above average ratio - denominator */
+
+#define THAWF 1.0 /* Threshold average adaptation filter weight, fixed value (TH) */
+#define THAWP 4.0 /* Threshold average adaptation filter weight, previous value */
+#define THAWN 1.0 /* Threshold average adaptation filter weight, new value */
+
+#else /* Current values */
+
+#define THRN 1.0 /* Threshold above average ratio - numerator */
+#define THRD 1.5 /* Threshold above average ratio - denominator */
+
+#define THAWF 1.0 /* Threshold average adaptation filter weight, fixed value (TH) */
+#define THAWP 5.0 /* Threshold average adaptation filter weight, previous value */
+#define THAWN 1.0 /* Threshold average adaptation filter weight, new value */
+
+#endif
+
+/* ~~~ minimum raster size needs to be specified/checked ~~~~ */
+#define MIN_NO_LINES 16 /* Minimum number of valid fitted lines to estimate rotation */
+
+/* Criteria for accepting lines for angle calculation (valid lines) */
+#define MAX_MWID_TO_LEN 0.1
+#define MIN_POINT_TO_AREA 0.9 /* Minimum point desity over the lines area */
+#define SD_WINDOW 1.5 /* Allow += 1.5 of a standard deviation for robust angle calc. */
+#define ELISTCDIST 800 /* 1/ELISTCDIST = portion of refence edge list legth to coalesce over */
+
+/* Criteria for accepting lines for improring final fit */
+#define IMP_MATCH 0.10 /* Proportion of average tick spacing */
+
+/* The following should be scaled to the resolution of the image ? */
+#define MIN_POINTS 10 /* Minimum points to calculate line */
+#define MIN_LINE_LENGTH 10.0
+#define CUT_CHUNKS 128 /* cut groups along diagonals - must be power of 2 */
+
+static int add_region(scanrd_ *s, region *rego, int no_o, region *regn, int no_n, int y);
+
+/* Process a line of the TIFF file */
+/* return non-zero on error */
+static int
+analize(
+scanrd_ *s,
+unsigned char *inp[6], /* current and previous 5 lines */
+int y /* Current line y */
+) {
+ int w = s->width;
+ int stride = s->tdepth * s->width; /* In pixels */
+ unsigned short *gamma = s->gamma;
+ int x,i;
+ unsigned short *inp2[6]; /* current and previous 5 lines (16bpp) equivalent of inp[] */
+ unsigned char *in[6]; /* six input lines (8bpp) */
+ unsigned short *in2[6]; /* six input lines (16bpp) */
+ region *tr;
+ double tdh,tdv; /* Horizontal/virtical detect levels */
+ double tdmag;
+ double atdmag = 0.0; /* Average magnitude over a line */
+ int atdmagc = 0; /* Average magnitude over a line count */
+ double linedv = 0.0; /* Lines average divider value */
+ int linedc = 0; /* Lines average count */
+ int xo3 = s->tdepth * 3; /* Xoffset by 3 pixels */
+ int xo2 = s->tdepth * 2; /* Xoffset by 2 pixels */
+ int xo1 = s->tdepth * 1; /* Xoffset by 1 pixels */
+
+ for (x = 0; x < 6; x++) /* Create 16 bpp version of line pointers */
+ inp2[x] = (unsigned short *)inp[x];
+
+ if (s->inited == 0) {
+ /* Init gamma conversion lookup and region tracking. */
+ /* The assumption is that a typical chart has an approx. visually */
+ /* uniform distribution of samples, so that a typically gamma */
+ /* encoded scan image will have an average pixel value of 50%. */
+ /* If a the chart has a different gamma encoding (ie. linear), */
+ /* then we convert it to gamma 2.2 encoded to (hopefuly) enhance */
+ /* the patch contrast. */
+ if (s->bpp == 8)
+ for (i = 0; i < 256; i++) {
+ int byteb1;
+
+ byteb1 = (int)(0.5 + 255 * pow( i / 255.0, s->gammav/2.2 ));
+ gamma[i] = byteb1;
+ }
+ else
+ for (i = 0; i < 65536; i++) {
+ int byteb1;
+
+ byteb1 = (int)(0.5 + 65535 * pow( i / 65535.0, s->gammav/2.2 ));
+ gamma[i] = byteb1;
+ }
+
+ if ((s->vrego = (region *) malloc(sizeof(region) * (w+1)/2)) == NULL) {
+ s->errv = SI_MALLOC_VREGION;
+ sprintf(s->errm,"vreg malloc failed");
+ return 1;
+ }
+ s->no_vo = 0;
+ if ((s->vregn = (region *) malloc(sizeof(region) * (w+1)/2)) == NULL) {
+ s->errv = SI_MALLOC_VREGION;
+ sprintf(s->errm,"vreg malloc failed");
+ return 1;
+ }
+ s->no_vn = 0;
+ if ((s->hrego = (region *) malloc(sizeof(region) * (w+1)/2)) == NULL) {
+ s->errv = SI_MALLOC_VREGION;
+ sprintf(s->errm,"vreg malloc failed");
+ return 1;
+ }
+ s->no_ho = 0;
+ if ((s->hregn = (region *) malloc(sizeof(region) * (w+1)/2)) == NULL) {
+ s->errv = SI_MALLOC_VREGION;
+ sprintf(s->errm,"vreg malloc failed");
+ return 1;
+ }
+ s->no_hn = 0;
+ INIT_LIST(s->gdone);
+ s->inited = 1;
+ }
+
+ /* Un-gamma correct the latest input line */
+ if (s->bpp == 8)
+ for (x = 0; x < stride; x++)
+ inp[5][x] = (unsigned char)gamma[inp[5][x]];
+ else
+ for (x = 0; x < stride; x++)
+ inp2[5][x] = gamma[inp2[5][x]];
+
+ /* Compute difference output for line y-3 */
+ atdmagc = w - 5; /* Magnitude count (to compute average) */
+ for (x = 3; x < (w-2); x++) { /* Allow for -3 to +2 from x */
+ unsigned char *out = s->out;
+ int e;
+ int ss;
+ int idx = ((y-2) * w + x) * 3; /* Output raster index in bytes */
+
+ if (s->bpp == 8)
+ for (i = 0; i < 6; i++)
+ in[i] = inp[i] + x * s->tdepth; /* Strength reduce */
+ else
+ for (i = 0; i < 6; i++) {
+ in2[i] = inp2[i] + x * s->tdepth; /* Strength reduce */
+ in[i] = (unsigned char *)in2[i]; /* track 8bpp pointers */
+ }
+
+ if (s->flags & SI_SHOW_IMAGE) { /* Create B&W image */
+ toRGB(out + idx, in[2], s->depth, s->bpp); /* Convert to RGB */
+ out[idx] = out[idx+1] = out[idx+2] = (2 * out[idx] + 7 * out[idx+1] + out[idx+2])/10;
+ }
+
+ ss = 0; /* Sign of cross components the same vote */
+ tdh = tdv = 0.0;
+
+ if (s->bpp == 8)
+ for (e = 0; e < s->depth; e++) {
+ int d1,d2;
+ /* Compute Gxp */
+ d1 = -in[0][-xo3+e] + -in[0][-xo2+e] + -in[0][-xo1+e]
+ + -in[0][ 0+e] + -in[0][ xo1+e] + -in[0][ xo2+e]
+ + -in[1][-xo3+e] + -in[1][-xo2+e] + -in[1][-xo1+e]
+ + -in[1][ 0+e] + -in[1][ xo1+e] + -in[1][ xo2+e]
+ + -in[2][-xo3+e] + -in[2][-xo2+e] + -in[2][-xo1+e]
+ + -in[2][ 0+e] + -in[2][ xo1+e] + -in[2][ xo2+e]
+ + in[3][-xo3+e] + in[3][-xo2+e] + in[3][-xo1+e]
+ + in[3][ 0+e] + in[3][ xo1+e] + in[3][ xo2+e]
+ + in[4][-xo3+e] + in[4][-xo2+e] + in[4][-xo1+e]
+ + in[4][ 0+e] + in[4][ xo1+e] + in[4][ xo2+e]
+ + in[5][-xo3+e] + in[5][-xo2+e] + in[5][-xo1+e]
+ + in[5][ 0+e] + in[5][ xo1+e] + in[5][ xo2+e];
+ /* Compute Gyp */
+ d2 = -in[0][-xo3+e] + -in[1][-xo3+e] + -in[2][-xo3+e]
+ + -in[3][-xo3+e] + -in[4][-xo3+e] + -in[5][-xo3+e]
+ + -in[0][-xo2+e] + -in[1][-xo2+e] + -in[2][-xo2+e]
+ + -in[3][-xo2+e] + -in[4][-xo2+e] + -in[5][-xo2+e]
+ + -in[0][-xo1+e] + -in[1][-xo1+e] + -in[2][-xo1+e]
+ + -in[3][-xo1+e] + -in[4][-xo1+e] + -in[5][-xo1+e]
+ + in[0][ 0+e] + in[1][ 0+e] + in[2][ 0+e]
+ + in[3][ 0+e] + in[4][ 0+e] + in[5][ 0+e]
+ + in[0][+xo1+e] + in[1][+xo1+e] + in[2][+xo1+e]
+ + in[3][+xo1+e] + in[4][+xo1+e] + in[5][+xo1+e]
+ + in[0][+xo2+e] + in[1][+xo2+e] + in[2][+xo2+e]
+ + in[3][+xo2+e] + in[4][+xo2+e] + in[5][+xo2+e];
+
+ if ((d1 >= 0 && d2 >=0)
+ || (d1 < 0 && d2 < 0))
+ ss++; /* Sign was the same */
+ tdh += d1/4.5 * d1/4.5; /* (4.5 = 6x6/4x2, to scale original tuned values) */
+ tdv += d2/4.5 * d2/4.5;
+ }
+ else
+ for (e = 0; e < s->depth; e++) {
+ int d1,d2;
+ /* Compute Gxp */
+ d1 = -in2[0][-xo3+e] + -in2[0][-xo2+e] + -in2[0][-xo1+e]
+ + -in2[0][ 0+e] + -in2[0][ xo1+e] + -in2[0][ xo2+e]
+ + -in2[1][-xo3+e] + -in2[1][-xo2+e] + -in2[1][-xo1+e]
+ + -in2[1][ 0+e] + -in2[1][ xo1+e] + -in2[1][ xo2+e]
+ + -in2[2][-xo3+e] + -in2[2][-xo2+e] + -in2[2][-xo1+e]
+ + -in2[2][ 0+e] + -in2[2][ xo1+e] + -in2[2][ xo2+e]
+ + in2[3][-xo3+e] + in2[3][-xo2+e] + in2[3][-xo1+e]
+ + in2[3][ 0+e] + in2[3][ xo1+e] + in2[3][ xo2+e]
+ + in2[4][-xo3+e] + in2[4][-xo2+e] + in2[4][-xo1+e]
+ + in2[4][ 0+e] + in2[4][ xo1+e] + in2[4][ xo2+e]
+ + in2[5][-xo3+e] + in2[5][-xo2+e] + in2[5][-xo1+e]
+ + in2[5][ 0+e] + in2[5][ xo1+e] + in2[5][ xo2+e];
+ /* Compute Gyp */
+ d2 = -in2[0][-xo3+e] + -in2[1][-xo3+e] + -in2[2][-xo3+e]
+ + -in2[3][-xo3+e] + -in2[4][-xo3+e] + -in2[5][-xo3+e]
+ + -in2[0][-xo2+e] + -in2[1][-xo2+e] + -in2[2][-xo2+e]
+ + -in2[3][-xo2+e] + -in2[4][-xo2+e] + -in2[5][-xo2+e]
+ + -in2[0][-xo1+e] + -in2[1][-xo1+e] + -in2[2][-xo1+e]
+ + -in2[3][-xo1+e] + -in2[4][-xo1+e] + -in2[5][-xo1+e]
+ + in2[0][ 0+e] + in2[1][ 0+e] + in2[2][ 0+e]
+ + in2[3][ 0+e] + in2[4][ 0+e] + in2[5][ 0+e]
+ + in2[0][+xo1+e] + in2[1][+xo1+e] + in2[2][+xo1+e]
+ + in2[3][+xo1+e] + in2[4][+xo1+e] + in2[5][+xo1+e]
+ + in2[0][+xo2+e] + in2[1][+xo2+e] + in2[2][+xo2+e]
+ + in2[3][+xo2+e] + in2[4][+xo2+e] + in2[5][+xo2+e];
+
+ if ((d1 >= 0 && d2 >=0)
+ || (d1 < 0 && d2 < 0))
+ ss++; /* Sign was the same */
+
+ tdh += d1/(4.5 * 257) * d1/(4.5 * 257); /* Scale to 0..255 range */
+ tdv += d2/(4.5 * 257) * d2/(4.5 * 257);
+ }
+
+ tdmag = tdh + tdv;
+
+ if (tdmag < (32.0 * s->th))
+ atdmag += tdmag; /* Average magnitude over a line */
+ else
+ atdmag += 32.0 * s->th;
+
+ /* if over threshold */
+ /* (Cut long lines up to prevent long lines being */
+ /* (thrown away due to attached blobs) */
+ if (tdmag >= s->th
+ && (x & (CUT_CHUNKS-1)) != (y & (CUT_CHUNKS-1))) {
+ double tt;
+ double av; /* Angle value of current pixel */
+ tt = (tdv - tdh)/(tdh + tdv); /* Partial angle */
+ linedv += fabs(tt);
+ linedc++;
+
+ if (ss >= (s->depth/2+1)) /* Assume signs are the same if clear majority */
+ av = 3.0 + tt;
+ else
+ av = 1.0 - tt;
+
+ /* Separate the orthogonal elements */
+ if (av >= s->divval && av < (s->divval + 2.0)) {
+ if (s->flags & SI_SHOW_DIFFSH)
+ out[idx] = (char)255; /* Red */
+ /* Add point to new region */
+ /* See if we can add to last region */
+ if (s->no_hn > 0 && x == s->hregn[s->no_hn-1].hx)
+ s->hregn[s->no_hn-1].hx++;
+ else { /* Add another */
+ if (s->no_hn >= (w+1)/2) {
+ s->errv = SI_INTERNAL;
+ sprintf(s->errm,"Internal, no_hn is too large");
+ return 1;
+ }
+ s->hregn[s->no_hn].lx = x;
+ s->hregn[s->no_hn].hx = x+1;
+ s->hregn[s->no_hn].p = NULL;
+ s->no_hn++;
+ }
+ } else {
+ if (s->flags & SI_SHOW_DIFFSV)
+ out[idx+1] = (char)255; /* Green */
+ /* Add point to new region */
+ /* See if we can add to last region */
+ if (s->no_vn > 0 && x == s->vregn[s->no_vn-1].hx)
+ s->vregn[s->no_vn-1].hx++;
+ else { /* Add another */
+ if (s->no_vn >= (w+1)/2) {
+ s->errv = SI_INTERNAL;
+ sprintf(s->errm,"Internal, no_vn is too large");
+ return 1;
+ }
+ s->vregn[s->no_vn].lx = x;
+ s->vregn[s->no_vn].hx = x+1;
+ s->vregn[s->no_vn].p = NULL;
+ s->no_vn++;
+ }
+ }
+ }
+ }
+
+ if (linedc != 0) { /* Adapt divider value to line */
+ linedv /= (double)linedc; /* Compute average over the line */
+ linedv = (linedv * linedv); /* Square to even out linedv vs angle */
+ linedv = (1.65 * (linedv - 0.12)); /* Compensate for random offsets */
+ s->adivval += linedv;
+ s->divc++;
+ s->divval = (7.0 * s->divval + linedv)/8.0; /* Average over 8 lines */
+ if (s->divval < 0.0)
+ s->divval = 0.0;
+ else if (s->divval > 1.0)
+ s->divval = 1.0;
+ if (s->verb >= 5)
+ DBG((dbgo,"linedv = %f, divval = %f\n",linedv,s->divval));
+ }
+
+ /* Adjust the threshold */
+ atdmag /= (double)atdmagc; /* compute average magnitude over the line */
+ s->th = (s->th * THRD)/(THRN + s->divval);/* Convert threshold to average */
+ s->th = ((THAWF * TH) + (THAWP * s->th) + (THAWN * atdmag))/(THAWF + THAWP + THAWN);
+ s->th = (s->th * (THRN + s->divval))/THRD; /* Convert average back to threshold */
+
+ /* Add vertical regions */
+ if (add_region(s,s->vrego,s->no_vo,s->vregn,s->no_vn,y-2))
+ return 1;
+
+ /* Add horizontal regions */
+ if (add_region(s,s->hrego,s->no_ho,s->hregn,s->no_hn,y-2))
+ return 1;
+
+ /* shuffle them along */
+ tr = s->vrego;
+ s->vrego = s->vregn; /* move new to old */
+ s->vregn = tr; /* old to new */
+ s->no_vo = s->no_vn;
+ s->no_vn = 0;
+
+ tr = s->hrego;
+ s->hrego = s->hregn; /* move new to old */
+ s->hregn = tr; /* old to new */
+ s->no_ho = s->no_hn;
+ s->no_hn = 0;
+
+ return 0;
+}
+
+/********************************************************************************/
+/* Point list code */
+
+/* allocate a new (empty) points structure */
+/* return NULL on error */
+static points *
+new_points(
+scanrd_ *s
+) {
+ points *ps;
+ static int pn = 0;
+ if ((ps = (points *) malloc(sizeof(points))) == NULL) {
+ s->errv = SI_MALLOC_POINTS;
+ sprintf(s->errm,"new_points: malloc failed");
+ return NULL;
+ }
+ ps->mxno = 0;
+ ps->no = 0;
+ ps->nop = 0;
+ ps->r = NULL;
+ ps->pn = pn;
+ pn++;
+ return ps;
+}
+
+/* destroy a points structure */
+static void
+destroy_points(
+scanrd_ *s,
+points *ps) {
+ if (ps->r != NULL) /* Free any array pointed to */
+ free(ps->r);
+ free (ps);
+}
+
+/* Add another run to a points object */
+/* return non-zero on error */
+static int
+add_run(
+scanrd_ *s,
+points *ps,
+int lx,
+int hx,
+int y)
+ {
+ if (ps->no == ps->mxno) { /* Need some more space */
+ ps->mxno = (2 * ps->mxno) + 5; /* New size */
+ if ((ps->r = (run *) realloc(ps->r, sizeof(run) * ps->mxno)) == NULL) {
+ s->errv = SI_REALLOC_POINTS;
+ sprintf(s->errm,"add_run: realloc failed");
+ return 1;
+ }
+ }
+ ps->r[ps->no].lx = lx;
+ ps->r[ps->no].hx = hx;
+ ps->r[ps->no].y = y;
+ ps->no++; /* One more run */
+ ps->nop += hx - lx; /* Total of pixels */
+ return 0;
+}
+
+/* copy src points to dest */
+/* Return non-zero on error */
+static int
+copy_points(
+scanrd_ *s,
+points *dst,
+points *src
+) {
+ int i;
+ for (i = 0; i < src->no; i++) {
+ if (add_run(s,dst,src->r[i].lx,src->r[i].hx,src->r[i].y))
+ return 1;
+ }
+ return 0;
+}
+
+/********************************************************************************/
+
+/* Add a new region of points to the line points lists */
+/* Note that regions are assumed to be non-overlapping x sorted */
+/* Return non-zero on error */
+static int
+add_region(
+scanrd_ *s,
+region *rego, /* Old regions */
+int no_o, /* No of old region */
+region *regn, /* New regions */
+int no_n, /* No of new region */
+int y /* Y value */
+) {
+ int osp,op,np; /* Old/new pointers */
+
+ osp = 0;
+ for (np = 0; np < no_n; np++) { /* Process all new runs */
+ /* Advance start pointer until we get to runs that may touch */
+#ifdef DIAGN
+ while (osp < no_o && rego[osp].hx < regn[np].lx)
+#else
+ while (osp < no_o && rego[osp].hx <= regn[np].lx)
+#endif
+ osp++;
+ /* For all old runs that may touch new */
+#ifdef DIAGN
+ for(op = osp; op < no_o && rego[op].lx <= regn[np].hx; op++) {
+#else
+ for(op = osp; op < no_o && rego[op].lx < regn[np].hx; op++) {
+#endif
+
+#ifdef DIAGN
+ if (rego[op].hx >= regn[np].lx && rego[op].lx <= regn[np].hx) {
+#else
+ if (rego[op].hx > regn[np].lx && rego[op].lx < regn[np].hx) {
+#endif
+ /* Old region touches new */
+ if (regn[np].p == NULL) { /* No group for new yet */
+ regn[np].p = rego[op].p; /* Make part of the same group */
+ if (add_run(s, regn[np].p,regn[np].lx,regn[np].hx,y)) /* add new run to group */
+ return 1;
+ } else if (regn[np].p != rego[op].p) { /* Touches different group */
+ int j;
+ points *tp = rego[op].p; /* Old region to be renamed/merged */
+ if (copy_points(s,regn[np].p,tp)) /* Merge old with current new */
+ return 1; /* Error */
+ DEL_LINK(s->gdone,tp); /* Don't need other any more */
+ for (j = 0; j < no_o; j++) /* Fix all references to this group */
+ if (rego[j].p == tp)
+ rego[j].p = regn[np].p;
+ for (j = 0; j < no_n; j++)
+ if (regn[j].p == tp)
+ regn[j].p = regn[np].p;
+ destroy_points(s,tp);
+ }
+ }
+ }
+ /* Finished all relevant old runs */
+ if (regn[np].p == NULL) { /* No old touched, so start new group */
+ if ((regn[np].p = new_points(s)) == NULL)
+ return 1; /* Error */
+ ADD_ITEM_TO_TOP(s->gdone,regn[np].p); /* Stash it in points list */
+ if (add_run(s, regn[np].p,regn[np].lx,regn[np].hx,y)) /* add new run to group */
+ return 1; /* Error */
+ }
+ }
+ return 0;
+}
+
+/********************************************************************************/
+
+/* Apply partial perspective to an xy point */
+/* (We omit the two offset parameters, since we don't need them) */
+void ppersp(scanrd_ *s, double *xx, double *yy, double x, double y, double *ppc) {
+ double den;
+
+ /* Offset the partial perspective transform */
+ x -= ppc[2];
+ y -= ppc[3];
+
+ den = ppc[0] * x + ppc[1] * y + 1.0;
+
+ if (fabs(den) < 1e-6) {
+ if (den < 0.0)
+ den = -1e-6;
+ else
+ den = 1e-6;
+ }
+ *xx = x/den + ppc[2];
+ *yy = y/den + ppc[3];
+}
+
+
+/* Apply inverse partial perspective to an xy point */
+void invppersp(scanrd_ *s, double *x, double *y, double xx, double yy, double *ppc) {
+ double den;
+
+ /* Offset the partial perspective transform */
+ xx -= ppc[2];
+ yy -= ppc[3];
+
+ den = - ppc[0] * xx - ppc[1] * yy + 1.0;
+
+ if (fabs(den) < 1e-6) {
+ if (den < 0.0)
+ den = -1e-6;
+ else
+ den = 1e-6;
+ }
+ *x = xx/den + ppc[2];
+ *y = yy/den + ppc[3];
+}
+
+/********************************************************************************/
+
+/* Compute the least squares best line fit for a group */
+/* Return non-zero if failed */
+static int
+points_to_line(
+scanrd_ *s,
+points *ps) {
+ int i,j;
+ point *vv; /* Point vectors */
+ int nop = ps->nop; /* Number of points */
+ double sx,sy; /* Sum */
+ double mx,my; /* Mean */
+ double a; /* Angle, Clockwise from 12o'clock */
+ double mw,len; /* mean width, length */
+ double x1,y1,x2,y2; /* Start/end point of fitted line */
+
+ ps->flag = 0;
+
+ if (nop < MIN_POINTS) /* Don't bother if too few pixels */
+ return 0;
+
+ /* Convert runs to individual points, and compute mean */
+ if ((vv = (point *) malloc(sizeof(point) * nop)) == NULL) {
+ s->errv = SI_MALLOC_POINT2LINE;
+ sprintf(s->errm,"scanrd: points_to_line: malloc failed");
+ return 1;
+ }
+
+ sx = sy = 0.0;
+ for (j = i = 0; i < ps->no; i++) { /* For all runs */
+ int x,y;
+ int hx = ps->r[i].hx, lx = ps->r[i].lx;
+
+ y = ps->r[i].y;
+ sy += (hx - lx) * y;
+ for (x = lx; x < hx; x++, j++) { /* Convert to points */
+ sx += x;
+ vv[j].x = x;
+ vv[j].y = y;
+ }
+ }
+ mx = sx/(double)nop; /* Centroid (mean) of points */
+ my = sy/(double)nop;
+
+ /* Offset points to centroid */
+ for (i=0; i < nop; i++) {
+ vv[i].x -= mx;
+ vv[i].y -= my;
+ }
+
+ /* Compute ad and bd, then A, B, C */
+ /* From Graphics Gems V, pp 91-97, */
+ /* "The Best Least-Squares Line Fit" */
+ /* by David Alciatore and Rick Miranda. */
+ {
+ double ad, bd; /* a' and b' values */
+ double xd, yd; /* temp x' and y' */
+ double A, B; /* line equation */
+ double abn; /* A & B normalizer */
+
+ xd = yd = bd = 0.0;
+ for (i = 0; i < nop; i++) {
+ double x, y;
+
+ x = vv[i].x;
+ y = vv[i].y;
+ xd += x * x;
+ yd += y * y;
+ bd += x * y;
+ }
+ ad = xd - yd;
+
+ /* Equation of best fit line is Ax + By = C */
+ A = 2 * bd;
+ B = -(ad + sqrt(ad * ad + 4.0 * bd * bd));
+ /* C = A * mx + B * my; */
+
+ /* Compute angle */
+ /* A = abn * cos(a), B = -abn * sin(a) */
+
+ abn = sqrt(A * A + B * B); /* Normalize A & B */
+ if (fabs(abn) < 1e-6) { /* No dominant direction */
+ a = 0.0;
+ } else {
+ a = acos(A/abn);
+ }
+ /* Make angle +ve */
+ while (a < 0.0) a += M_PI;
+ }
+
+ /* Now figure out the bounding box for the line + other stats */
+ {
+ double s,c;
+ double pl,nl; /* Positive length, negative length */
+ s = sin(a);
+ c = cos(a);
+ for (mw = 0.0, pl = 0.0, nl = 0.0, i = 0; i < nop; i++)
+ {
+ double npj; /* Projection onto normal */
+ double lpj; /* Projection onto line */
+ npj = -c * vv[i].x + s * vv[i].y;
+ if (npj < 0)
+ mw -= npj;
+ else
+ mw += npj;
+ lpj = s * vv[i].x + c * vv[i].y;
+ if (lpj > pl)
+ pl = lpj;
+ if (lpj < nl)
+ nl = lpj;
+ }
+ mw = 2.0 * mw/(double)nop; /* Mean width */
+
+ x1 = mx + s * nl;
+ y1 = my + c * nl;
+ x2 = mx + s * pl;
+ y2 = my + c * pl;
+ len = pl - nl;
+ }
+
+ ps->mx = mx; /* Mean point */
+ ps->my = my;
+ ps->a = a; /* Angle */
+ ps->mw = mw; /* Mean width */
+ ps->len = len; /* Mean length */
+ ps->x1 = x1; /* Start/end point of fitted line */
+ ps->y1 = y1;
+ ps->x2 = x2;
+ ps->y2 = y2;
+ ps->flag = F_LINESTATS; /* Line stats valid */
+
+ /* Compute the Constrained to 90 degrees angle */
+ /* We use the adivval to figure out where to split angles */
+ /* Split at 0 if adivval == 0.0, split at 45 if adivval == 1.0 */
+ if (a >= (M_PI * (1.0 - s->adivval/4.0)))
+ ps->ca = a - M_PI;
+ else if (a >= (M_PI * (0.5 - s->adivval/4.0)))
+ ps->ca = a - M_PI_2;
+ else
+ ps->ca = a;
+
+ if (s->verb >= 5)
+ DBG((dbgo,"Angle %f, CA = %f, length = %f, mean width = %f, Line %f,%f to %f,%f\n",
+ DEG(a),DEG(ps->ca),len,mw,x1,y1,x2,y2));
+ free(vv);
+
+/* printf("~~stats: mw = %f, len = %f, mw/len = %f, area = %f\n",
+ mw, len, mw/len, ((double)nop/(len * (mw + 0.01)))); */
+ /* Look at stats to see what lines are acceptable for further processing */
+ if ( len >= MIN_LINE_LENGTH
+ && mw/len <= MAX_MWID_TO_LEN
+ && ((double)nop/(len * (mw + 0.01))) >= MIN_POINT_TO_AREA) {
+ ps->flag |= F_VALID; /* Line stats valid to use */
+/* printf("~~set valid\n"); */
+ }
+ return 0;
+}
+
+static int
+calc_lines(
+scanrd_ *s
+) {
+ points *tp;
+ s->noslines = 0;
+ s->novlines = 0;
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (points_to_line(s,tp))
+ return 1; /* Error */
+ if (tp->flag & F_LINESTATS) /* Line stats valid */
+ s->noslines++;
+ if (tp->flag & F_VALID) /* Valid for angle calcs */
+ s->novlines++;
+
+ /* Save orininal raster (non partial perspective corrected) values */
+ if (tp->flag & F_VALID) {
+ tp->pmx = tp->mx;
+ tp->pmy = tp->my;
+ tp->px1 = tp->x1;
+ tp->py1 = tp->y1;
+ tp->px2 = tp->x2;
+ tp->py2 = tp->y2;
+ }
+ END_FOR_ALL_ITEMS(tp);
+ return 0;
+}
+
+static int show_line(scanrd_ *s, int x1, int y1, int x2, int y2, unsigned long c);
+
+/* Show the edge detected lines */
+static int
+show_lines(
+scanrd_ *s
+) {
+ points *tp;
+ int outw = s->width;
+ int outh = s->height;
+ /* For SI_SHOW_ROT */
+ double cirot,sirot; /* cos and sin of -irot */
+ cirot = cos(-s->irot);
+ sirot = sin(-s->irot);
+
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if ((s->flags & SI_SHOW_ALL_LINES) || (tp->flag & F_VALID))
+ {
+ unsigned long col = 0xffffff; /* default color is white */
+ double x1 = tp->px1, y1 = tp->py1, x2 = tp->px2, y2 = tp->py2;
+ /* For SI_SHOW_ROT */
+
+ /* Show partial perspective corrected lines */
+ if (s->flags & (SI_SHOW_ROT | SI_SHOW_PERS)) {
+ invppersp(s, &x1, &y1, x1, y1, s->ppc);
+ invppersp(s, &x2, &y2, x2, y2, s->ppc);
+ col = 0xffff00; /* cyan */
+ }
+
+ /* Show rotation correction of lines + color coding yellow and red */
+ if (s->flags & SI_SHOW_ROT) {
+ double tx1, ty1, tx2, ty2;
+ double a = tp->a - s->irot;
+
+ tx1 = x1;
+ ty1 = y1;
+ tx2 = x2;
+ ty2 = y2;
+
+ /* Rotate about center of raster */
+ x1 = (tx1-outw/2.0) * cirot + (ty1-outh/2.0) * sirot;
+ y1 = -(tx1-outw/2.0) * sirot + (ty1-outh/2.0) * cirot;
+ x2 = (tx2-outw/2.0) * cirot + (ty2-outh/2.0) * sirot;
+ y2 = -(tx2-outw/2.0) * sirot + (ty2-outh/2.0) * cirot;
+
+ x1 += outw/2.0; /* Rotate about center of raster */
+ y1 += outh/2.0;
+ x2 += outw/2.0;
+ y2 += outh/2.0;
+ if ((a >= -0.08 && a <= 0.08) || (a >= (M_PI-0.08) && a <= (M_PI+0.08))
+ || (a >= (M_PI_2-0.08) && a <= (M_PI_2+0.08)))
+ col = 0x00ffff; /* yellow */
+ else
+ col = 0x0000ff; /* Red */
+ }
+ /* Show just lines used for fit improvement in blue */
+ if (s->flags & SI_SHOW_IMPL) {
+ if (tp->flag & F_IMPROVE)
+ col = 0xff4040; /* blue */
+ }
+ show_line(s,(int)(x1+0.5),(int)(y1+0.5),(int)(x2+0.5),(int)(y2+0.5),col);
+ }
+ END_FOR_ALL_ITEMS(tp);
+ return 0;
+}
+
+
+/********************************************************************************/
+
+/* Definition of the optimization function handed to powell() */
+static double
+pfunc(void *ss, double p[]) {
+ scanrd_ *s = (scanrd_ *)ss;
+ points *tp;
+ double aa; /* Average angle */
+ double va, rva; /* Variance */
+ double wt; /* Total weighting = sum of line lengths */
+ double pw;
+ double dw; /* Discrimination width */
+
+//printf("~1 %f %f %f %f %f %f\n", p[0],p[1],p[2],p[3],p[4],p[5]);
+
+ /* Correct the perspective of all the edge lines using the parameters */
+ /* and compute the mean angle */
+ aa = 0.0; /* Average constrained angle */
+ wt = 0.0; /* Total weighting = sum of line lengths */
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_LONGENOUGH) {
+ double a, ca;
+ invppersp(s, &tp->x1, &tp->y1, tp->px1, tp->py1, p);
+ invppersp(s, &tp->x2, &tp->y2, tp->px2, tp->py2, p);
+
+ /* Compute the angle */
+ a = atan2(tp->x2 - tp->x1,tp->y2 - tp->y1);
+
+ /* Make angle +ve */
+ while (a < 0.0)
+ a += M_PI;
+
+ /* Compute the Constrained to 90 degrees angle */
+ /* We use the adivval to figure out where to split angles */
+ /* Split at 0 if adivval == 0.0, split at 45 if adivval == 1.0 */
+ if (a >= (M_PI * (1.0 - s->adivval/4.0)))
+ ca = a - M_PI;
+ else if (a >= (M_PI * (0.5 - s->adivval/4.0)))
+ ca = a - M_PI_2;
+ else
+ ca = a;
+
+ tp->a = a;
+ tp->ca = ca;
+
+ aa += tp->len * ca;
+ wt += tp->len;
+ }
+ END_FOR_ALL_ITEMS(tp);
+ aa /= wt;
+
+ /* Calculate the angle variance */
+ va = 0.0;
+ tp = s->gdone;
+ wt = 0.0;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_LONGENOUGH) {
+ double tt;
+ tt = tp->ca - aa;
+ va += tp->len * tt * tt;
+ wt += tp->len;
+ }
+ END_FOR_ALL_ITEMS(tp);
+ va = va/wt;
+
+ /* Calculate the a robust angle variance */
+ rva = 0.0;
+ wt = 0.0;
+ dw = sqrt(va) * 3.1; /* Allow += 0.5 of a standard deviation */
+ if (dw < 0.0001) /* A perfect chart may have dw of zero */
+ dw = 0.0001;
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_LONGENOUGH && fabs(tp->ca - aa) <= dw) {
+ double tt;
+ tt = tp->ca - aa;
+ rva += tp->len * tt * tt;
+ wt += tp->len;
+ }
+ END_FOR_ALL_ITEMS(tp);
+ if (wt > 0.0) {
+ rva = rva/wt;
+ va = rva;
+ }
+
+ /* Add some regularization to stop it going crazy */
+ pw = 0.0;
+ pw += 0.01 * (fabs(p[0]) + fabs(p[1]));
+ pw += 0.0001 * (fabs(p[2]/s->width - 0.5) + fabs(p[3]/s->height - 0.5));
+ va += pw;
+
+ return va;
+}
+
+/* Calculate the partial perspective correction factors */
+/* Return non-zero if failed */
+static int
+calc_perspective(
+scanrd_ *s
+) {
+ points *tp;
+ int nl; /* Number of lines used */
+ double ml; /* Minimum length */
+ double pc[4]; /* Perspective factors */
+ double ss[4]; /* Initial search distance */
+ double rv; /* Return value */
+ int rc = 0; /* Return code */
+
+ if (s->novlines < MIN_NO_LINES) {
+ s->errv = SI_FIND_PERSPECTIVE_FAILED;
+ sprintf(s->errm,"Not enough valid lines to compute perspective");
+ return 1;
+ }
+
+ /* Find the longest line */
+ ml = 0.0;
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_VALID) {
+ if (tp->len > ml)
+ ml = tp->len;
+ }
+ END_FOR_ALL_ITEMS(tp);
+
+ /* Make minimum line length to be included in angle */
+ /* calculation 1% of longest line */
+ ml *= 0.01;
+
+ /* Mark lines long enough to participate in angle calculation */
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_VALID && tp->len >= ml)
+ tp->flag |= F_LONGENOUGH;
+ END_FOR_ALL_ITEMS(tp);
+
+ /* Locate the perspective correction factors that minimze the */
+ /* variance of the mean angle. */
+
+ pc[0] = 0.0;
+ pc[1] = 0.0;
+ pc[2] = 0.5 * s->width;
+ pc[3] = 0.5 * s->height;
+
+ ss[0] = 0.0001;
+ ss[1] = 0.0001;
+ ss[2] = 1.0001;
+ ss[3] = 1.0001;
+ rc = powell(&rv, 4, pc,ss,1e-8,2000,pfunc,s, NULL, NULL);
+
+ if (rc == 0) {
+ points *tp;
+
+ DBG((dbgo,"Perspective correction factors = %f %f %f %f\n",
+ pc[0],pc[1],pc[2],pc[3]));
+
+ s->ppc[0] = pc[0];
+ s->ppc[1] = pc[1];
+ s->ppc[2] = pc[2];
+ s->ppc[3] = pc[3];
+
+ /* Implement the perspective correction */
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_LONGENOUGH) {
+ double a, ca;
+ invppersp(s, &tp->x1, &tp->y1, tp->px1, tp->py1, s->ppc);
+ invppersp(s, &tp->x2, &tp->y2, tp->px2, tp->py2, s->ppc);
+ tp->mx = 0.5 * (tp->x2 + tp->x1);
+ tp->my = 0.5 * (tp->y2 + tp->y1);
+ tp->len = sqrt((tp->x2 - tp->x1) * (tp->x2 - tp->x1)
+ + (tp->y2 - tp->y1) * (tp->y2 - tp->y1));
+
+ /* Compute the angle */
+ a = atan2(tp->x2 - tp->x1,tp->y2 - tp->y1);
+
+ /* Make angle +ve */
+ while (a < 0.0)
+ a += M_PI;
+
+ /* Compute the Constrained to 90 degrees angle */
+ /* We use the adivval to figure out where to split angles */
+ /* Split at 0 if adivval == 0.0, split at 45 if adivval == 1.0 */
+ if (a >= (M_PI * (1.0 - s->adivval/4.0)))
+ ca = a - M_PI;
+ else if (a >= (M_PI * (0.5 - s->adivval/4.0)))
+ ca = a - M_PI_2;
+ else
+ ca = a;
+
+ tp->a = a;
+ tp->ca = ca;
+ }
+ END_FOR_ALL_ITEMS(tp);
+ }
+
+ return 0;
+}
+
+/********************************************************************************/
+/* Calculate the image rotation */
+/* Return non-zero if failed */
+static int
+calc_rotation(
+scanrd_ *s
+) {
+ points *tp;
+ int nl; /* Number of lines used */
+ double ml; /* Minimum length */
+ double aa; /* Average angle */
+ double sd,dw; /* Standard deviation, deviation window */
+ double wt; /* Total weighting = sum of line lengths */
+
+ if (s->novlines < MIN_NO_LINES) {
+ s->errv = SI_FIND_ROTATION_FAILED;
+ sprintf(s->errm,"Not enough valid lines to compute rotation angle");
+ return 1;
+ }
+
+ /* Find the longest line */
+ tp = s->gdone;
+ ml = 0.0;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_VALID) {
+ if (tp->len > ml)
+ ml = tp->len;
+ }
+ END_FOR_ALL_ITEMS(tp);
+
+ /* Make minimum line length to be included in angle */
+ /* calculation 1% of longest line */
+ ml *= 0.01;
+
+ /* Calculate the mean angle */
+ aa = 0.0;
+ wt = 0.0; /* Total weighting = sum of line lengths */
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_VALID && tp->len >= ml) {
+ aa += tp->len * tp->ca;
+ wt += tp->len;
+ }
+ END_FOR_ALL_ITEMS(tp);
+ aa /= wt;
+
+ if (s->verb >= 2)
+ DBG((dbgo,"Mean angle = %f\n",DEG(aa)));
+
+ /* Calculate the angle standard deviation */
+ tp = s->gdone;
+ sd = 0.0;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_VALID && tp->len >= ml) {
+ double tt;
+ tt = tp->ca - aa;
+ sd += tp->len * tt * tt;
+ }
+ END_FOR_ALL_ITEMS(tp);
+
+ sd = sqrt(sd/wt);
+
+ if (s->verb >= 2)
+ DBG((dbgo,"Standard deviation = %f\n",DEG(sd)));
+
+ /* Now re-compute the angle while rejecting any that fall outside one standard deviation */
+ s->irot = 0.0;
+ wt = 0.0; /* Total weighting = sum of line lengths */
+ nl = 0;
+ dw = sd * SD_WINDOW; /* Allow += 0.5 of a standard deviation */
+ if (dw < 0.01) /* A perfect chart may have dw of zero */
+ dw = 0.01;
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_VALID && tp->len >= ml && fabs(tp->ca - aa) <= dw) {
+ s->irot += tp->len * tp->ca;
+ wt += tp->len;
+ nl++;
+ }
+ END_FOR_ALL_ITEMS(tp);
+ if (nl < (MIN_NO_LINES/2)) {
+ s->errv = SI_FIND_ROTATION_FAILED;
+ sprintf(s->errm,"%d consistent lines is not enough to compute rotation angle",nl);
+ return 1;
+ }
+ s->irot /= wt;
+
+ if (s->verb >= 2)
+ DBG((dbgo,"Robust mean angle = %f from %d lines\n",DEG(s->irot),nl));
+
+ return 0;
+}
+
+/********************************************************************************/
+/* Coalesce close entries of an edge list */
+/* return non-zero on error */
+static int
+coalesce_elist(
+scanrd_ *s,
+elist *el,
+int close /* Closeness factor, smaller = coarser */
+) {
+ double r; /* Margin for coalescence */
+ int i,k;
+
+ if (el->c < 2) /* Need at least 2 entries */
+ return 0;
+
+ r = (el->a[el->c-1].pos - el->a[0].pos)/(double)close;
+ for (k = 0, i = 1; i < el->c; i++) {
+ if ((el->a[i].pos - el->a[k].pos) <= r) {
+ /* Merge the two */
+ double lk = el->a[k].len;
+ double li = el->a[i].len;
+ el->a[k].pos = (el->a[k].pos * lk + el->a[i].pos * li)/(lk + li);
+ el->a[k].len = lk + li;
+ if (el->a[k].p1 > el->a[i].p1) /* Track overall start/end points */
+ el->a[k].p1 = el->a[i].p1;
+ if (el->a[k].p2 < el->a[i].p2)
+ el->a[k].p2 = el->a[i].p2;
+ continue;
+ }
+ k++; /* Inc destination pointer */
+ if (k != i)
+ el->a[k] = el->a[i]; /* shuffle data down */
+ }
+ k++; /* one past last out entry */
+ el->c = k;
+ return 0;
+}
+
+static int invert_elist(scanrd_ *s, elist *dl, elist *sl);
+static void debug_elist(scanrd_ *s, elist *el);
+
+/* Make up the x and y edge lists */
+/* Return non-zero if failed */
+static int
+calc_elists(
+scanrd_ *s,
+int ref /* 1 if generating reference lists */
+) {
+ int outw = s->width;
+ int outh = s->height;
+ points *tp;
+ int i,j;
+ double cirot,sirot; /* cos and sin of -irot */
+ elist xl, yl; /* Temporary X and Y edge lists array */
+ elist tl; /* temporary crossing list */
+
+ /* Allocate structures for edge lists */
+ if ((xl.a = (epoint *) malloc(sizeof(epoint) * s->novlines)) == NULL) {
+ s->errv = SI_MALLOC_ELIST;
+ sprintf(s->errm,"scanrd: calc_elist: malloc failed - novlines = %d",s->novlines);
+ return 1;
+ }
+ xl.c = 0;
+ if ((yl.a = (epoint *) malloc(sizeof(epoint) * s->novlines)) == NULL) {
+ s->errv = SI_MALLOC_ELIST;
+ sprintf(s->errm,"scanrd: calc_elist: malloc failed - novlines = %d",s->novlines);
+ return 1;
+ }
+ yl.c = 0;
+
+ /* Put valid lines into one of the two edge list arrays */
+ cirot = cos(-s->irot);
+ sirot = sin(-s->irot);
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_VALID) {
+ /* Rotate the point about 0,0 by angle -irot */
+ double x,y,a;
+ double mx = tp->mx, my = tp->my;
+
+ if (ref) { /* Rotate about center of raster for reference generation */
+ mx -= outw/2.0; /* Rotate about center of raster */
+ my -= outh/2.0;
+ x = mx * cirot + my * sirot + outw/2.0;
+ y = -mx * sirot + my * cirot + outh/2.0;
+ } else { /* Rotate about 0,0 for matching */
+ x = mx * cirot + my * sirot;
+ y = -mx * sirot + my * cirot;
+ }
+ a = tp->a - s->irot;
+ if ((a >= -0.08 && a <= 0.08) || (a >= (M_PI-0.08) && a <= (M_PI+0.08))) {
+ xl.a[xl.c].pos = x;
+ xl.a[xl.c].len = tp->len;
+ xl.a[xl.c].p1 = y - tp->len/2.0;
+ xl.a[xl.c].p2 = y + tp->len/2.0;
+ xl.c++;
+ } else if (a >= (M_PI_2-0.08) && a <= (M_PI_2+0.08)) {
+ yl.a[yl.c].pos = y;
+ yl.a[yl.c].len = tp->len;
+ yl.a[yl.c].p1 = x - tp->len/2.0;
+ yl.a[yl.c].p2 = x + tp->len/2.0;
+ yl.c++;
+ }
+ }
+ END_FOR_ALL_ITEMS(tp);
+
+ /* ~~~~ need to check that lists have a reasonable number of entries ~~~~~ */
+
+ /* now sort the lists */
+#define HEAP_COMPARE(A,B) (A.pos < B.pos)
+ HEAPSORT(epoint,xl.a,xl.c);
+ HEAPSORT(epoint,yl.a,yl.c);
+#undef HEAP_COMPARE
+
+ /* Copy the temporary lists to the real lists */
+ if ((s->xelist.a = (epoint *) malloc(sizeof(epoint) * xl.c)) == NULL) {
+ s->errv = SI_MALLOC_ELIST;
+ sprintf(s->errm,"scanrd: calc_elist: malloc failed, xl.c = %d",xl.c);
+ return 1;
+ }
+ s->xelist.c = xl.c;
+ for (i=0; i < xl.c; i++)
+ s->xelist.a[i] = xl.a[i];
+ if ((s->yelist.a = (epoint *) malloc(sizeof(epoint) * yl.c)) == NULL) {
+ s->errv = SI_MALLOC_ELIST;
+ sprintf(s->errm,"scanrd: calc_elist: malloc failed, yl.c = %d",yl.c);
+ return 1;
+ }
+ s->yelist.c = yl.c;
+ for (i=0; i < yl.c; i++)
+ s->yelist.a[i] = yl.a[i];
+
+ /* Coalese close entries of the final lists */
+ if (coalesce_elist(s, &s->xelist,ELISTCDIST))
+ return 1;
+ if (coalesce_elist(s, &s->yelist,ELISTCDIST))
+ return 1;
+
+ /* Calculate crossing count for lines in the X and y lists */
+ if ((tl.a = (epoint *) malloc(sizeof(epoint) * (xl.c > yl.c ? xl.c : yl.c))) == NULL) {
+ s->errv = SI_MALLOC_ELIST;
+ sprintf(s->errm,"scanrd: calc_elist: malloc failed, xl.c = %d, yl.c = %d",xl.c,yl.c);
+ return 1;
+ }
+ /* X list */
+ for (i = 0; i < s->xelist.c; i++) {
+ double ppos = s->xelist.a[i].pos;
+ double pp,np; /* Previous and next pos */
+ if ((i-1) >= 0)
+ pp = (ppos + s->xelist.a[i-1].pos)/2.0; /* Half distance to next line */
+ else
+ pp = -1e6;
+ if ((i+1) < s->xelist.c)
+ np = (ppos + s->xelist.a[i+1].pos)/2.0; /* Half distance to next line */
+ else
+ np = 1e6;
+
+ /* For all the lines in the Y list */
+ for (tl.c = j = 0; j < yl.c; j++) {
+ double pos = yl.a[j].pos;
+ double p1 = yl.a[j].p1;
+ double p2 = yl.a[j].p2;
+ if (p1 <= pp)
+ p1 = pp;
+ if (p2 >= np)
+ p2 = np;
+ /* If crosses on this lines X within +-0.5 of line each side */
+ if (p1 <= np && p2 >= pp) {
+ tl.a[tl.c].pos = pos;
+ tl.a[tl.c].len = p2 - p1;
+ tl.a[tl.c].p1 = p1;
+ tl.a[tl.c].p2 = p2;
+ tl.c++;
+ }
+ }
+ /* now coalesce the crossings */
+ if (coalesce_elist(s,&tl,200))
+ return 1;
+ /* Put count in line we're working on */
+ s->xelist.a[i].ccount = (double)tl.c;
+ pp = ppos;
+ }
+
+ /* Y list */
+ for (i = 0; i < s->yelist.c; i++) {
+ double ppos = s->yelist.a[i].pos;
+ double pp,np; /* Previous and next pos */
+ if ((i-1) >= 0)
+ pp = (ppos + s->yelist.a[i-1].pos)/2.0; /* Half distance to next line */
+ else
+ pp = -1e6;
+ if ((i+1) < s->xelist.c)
+ np = (ppos + s->yelist.a[i+1].pos)/2.0; /* Half distance to next line */
+ else
+ np = 1e6;
+
+ for (tl.c = j = 0; j < xl.c; j++) {
+ double pos = xl.a[j].pos;
+ double p1 = xl.a[j].p1;
+ double p2 = xl.a[j].p2;
+ if (p1 <= pp)
+ p1 = pp;
+ if (p2 >= np)
+ p2 = np;
+ /* If crosses on this lines Y within +-0.5 of line each side */
+ if (p1 <= np && p2 >= pp) {
+ tl.a[tl.c].pos = pos;
+ tl.a[tl.c].len = p2 - p1;
+ tl.a[tl.c].p1 = p1;
+ tl.a[tl.c].p2 = p2;
+ tl.c++;
+ }
+ }
+ /* now coalesce the crossings */
+ if (coalesce_elist(s,&tl,200))
+ return 1;
+ /* Put count in line we're working on */
+ s->yelist.a[i].ccount = (double)tl.c;
+ pp = ppos;
+ }
+
+ /* Normalize the length and ccount */
+ {
+ double tlen; /* Total length maximum */
+ double tcmax; /* Total count maximum */
+ for (tlen = tcmax = 0.0, i=0; i < s->xelist.c; i++) {
+ if (tlen < s->xelist.a[i].len)
+ tlen = s->xelist.a[i].len;
+ if (tcmax < s->xelist.a[i].ccount)
+ tcmax = s->xelist.a[i].ccount;
+ }
+ for (i=0; i < s->xelist.c; i++) {
+ s->xelist.a[i].len /= tlen;
+ s->xelist.a[i].ccount /= tcmax;
+ }
+ for (tlen = tcmax = 0.0, i=0; i < s->yelist.c; i++) {
+ if (tlen < s->yelist.a[i].len)
+ tlen = s->yelist.a[i].len;
+ if (tcmax < s->yelist.a[i].ccount)
+ tcmax = s->yelist.a[i].ccount;
+ }
+ for (i=0; i < s->yelist.c; i++) {
+ s->yelist.a[i].len /= tlen;
+ s->yelist.a[i].ccount /= tcmax;
+ }
+ }
+
+ /* Create the inverted lists for any rotation matching */
+ if (invert_elist(s, &s->ixelist, &s->xelist))
+ return 1;
+ if (invert_elist(s, &s->iyelist, &s->yelist))
+ return 1;
+
+ if (s->verb >= 3) {
+ DBG((dbgo,"\nxelist:\n"));
+ debug_elist(s,&s->xelist);
+ DBG((dbgo,"\nixelist:\n"));
+ debug_elist(s,&s->ixelist);
+ DBG((dbgo,"\nyelist:\n"));
+ debug_elist(s,&s->yelist);
+ DBG((dbgo,"\niyelist:\n"));
+ debug_elist(s,&s->iyelist);
+ }
+
+ /* Clean up */
+ free(xl.a);
+ free(yl.a);
+ free(tl.a);
+ return 0;
+}
+
+/********************************************************************************/
+/* Write the elists out to a file */
+
+/* Increment a string counter */
+static void
+strinc(
+char *s
+) {
+ int i,n,c; /* Length of string and carry flag */
+ n = strlen(s);
+ for (c = 1, i = n-1; i >= 0 && c != 0; i--) {
+ char sval = ' ';
+ if (s[i] == '9') {
+ s[i] = '0';
+ sval = '1';
+ c = 1;
+ } else if (s[i] == 'z') {
+ s[i] = 'a';
+ sval = 'a';
+ c = 1;
+ } else if (s[i] == 'Z') {
+ s[i] = 'A';
+ sval = 'A';
+ c = 1;
+ } else {
+ s[i]++;
+ c = 0;
+ }
+ if (i == 0 && c != 0) {
+ /* Assume there is some more space */
+ for (i = n; i >= 0; i--)
+ s[i+1] = s[i];
+ s[0] = sval;
+ break;
+ }
+ }
+}
+
+/* Write out the match reference information */
+/* Return non-zero on error */
+static int
+write_elists(
+scanrd_ *s
+) {
+ char *fname = s->refname; /* Path of file to write to */
+ FILE *elf;
+ int i;
+
+ if ((elf=fopen(fname,"w"))==NULL) {
+ s->errv = SI_REF_WRITE_ERR;
+ sprintf(s->errm,"write_elists: error opening match reference file '%s'",fname);
+ return 1;
+ }
+
+ fprintf(elf,"REF_ROTATION %f\n\n",DEG(s->irot));
+
+ fprintf(elf,"XLIST %d\n",s->xelist.c);
+ for (i = 0; i < s->xelist.c; i++)
+ fprintf(elf," %f %f %f\n",s->xelist.a[i].pos, s->xelist.a[i].len, s->xelist.a[i].ccount);
+ fprintf(elf,"\n");
+
+ fprintf(elf,"YLIST %d\n",s->yelist.c);
+ for (i = 0; i < s->yelist.c; i++)
+ fprintf(elf," %f %f %f\n",s->yelist.a[i].pos, s->yelist.a[i].len, s->yelist.a[i].ccount);
+ fprintf(elf,"\n");
+
+ if ((fclose(elf)) == EOF) {
+ s->errv = SI_REF_WRITE_ERR;
+ error("write_elists: Unable to close match reference file '%s'\n",fname);
+ return 1;
+ }
+ return 0;
+}
+
+/* Read in an elist reference file */
+/* return non-zero on error */
+/* (~~~ the line counting is rather broken ~~~) */
+static int
+read_relists(
+scanrd_ *s
+) {
+ char *fname = s->refname; /* Path of file to read from */
+ FILE *elf;
+ int i,l = 1;
+ int rv;
+ char *em; /* Read error message */
+
+ if ((elf=fopen(fname,"r"))==NULL) {
+ s->errv = SI_REF_READ_ERR;
+ sprintf(s->errm,"read_elists: error opening match reference file '%s'",fname);
+ return 1;
+ }
+
+ s->fid[0] = s->fid[1] = 0.0;
+ s->fid[2] = s->fid[3] = 0.0;
+ s->fid[4] = s->fid[5] = 0.0;
+ s->fid[6] = s->fid[7] = 0.0;
+
+ /* BOXES */
+ for(;;) {
+ if((rv = fscanf(elf,"BOXES %d",&s->nsbox)) == 1) {
+ l++;
+ break;
+ }
+ if (rv == EOF) {
+ em = "Didn't find BOXES before end of file";
+ goto read_error;
+ }
+ if (rv == 0) {
+ while ((rv = getc(elf)) != '\n' && rv != EOF);
+ l++;
+ }
+ }
+
+ /* Allocate structures for boxes */
+ if ((s->sboxes = (sbox *) calloc(s->nsbox, sizeof(sbox))) == NULL) {
+ s->errv = SI_MALLOC_REFREAD;
+ sprintf(s->errm,"read_elist, malloc failed");
+ return 1;
+ }
+ for (i = 0; i < s->nsbox;) {
+ char xfix1[20], xfix2[20], yfix1[20],yfix2[20];
+ char xfirst[20];
+ double ox,oy,w,h,xi,yi;
+ char xf[20];
+ double x;
+
+ if(fscanf(elf," %19s %19s %19s %19s %19s %lf %lf %lf %lf %lf %lf",xfirst ,xfix1, xfix2, yfix1, yfix2, &w, &h, &ox, &oy, &xi, &yi) != 11) {
+ em = "Read of BOX failed";
+ goto read_error;
+ }
+ l++;
+
+ /* If Fiducial. Typically top left, top right, botton right, bottom left. */
+ if (xfirst[0] == 'F') {
+ s->fid[0] = atof(yfix1);
+ s->fid[1] = atof(yfix2);
+ s->fid[2] = w;
+ s->fid[3] = h;
+ s->fid[4] = ox;
+ s->fid[5] = oy;
+ s->fid[6] = xi;
+ s->fid[7] = yi;
+ s->fidsize = fabs(s->fid[2] - s->fid[0]) + fabs(s->fid[5] - s->fid[3]);
+ s->fidsize /= 80.0;
+ s->havefids = 1;
+
+//printf("~1 fiducials %f %f, %f %f %f, %f\n",w, h, ox,oy, xi, yi);
+ continue;
+ }
+ for(;;) { /* Do Y increment */
+ x = ox;
+ strcpy(xf,xfix1);
+ for(;;) { /* Do X increment */
+ if (i >= s->nsbox) {
+ em = "More BOXes that declared";
+ goto read_error;
+ }
+ /* '_' is used as a null string marker for single character single cells */
+ if (xf[0] == '_')
+ sprintf(s->sboxes[i].name,"%s",yfix1);
+ else if (yfix1[0] == '_')
+ sprintf(s->sboxes[i].name,"%s",xf);
+ else { /* Y indicates Y name comes first */
+ if (xfirst[0] == 'Y')
+ sprintf(s->sboxes[i].name,"%s%s",yfix1,xf);
+ else /* X or D */
+ sprintf(s->sboxes[i].name,"%s%s",xf,yfix1);
+ }
+ if (xfirst[0] == 'D')
+ s->sboxes[i].diag = 1; /* Diagnostic box - don't print name or read pixels */
+ else
+ s->sboxes[i].diag = 0;
+ s->sboxes[i].x1 = x;
+ s->sboxes[i].y1 = oy;
+ s->sboxes[i].x2 = x + w;
+ s->sboxes[i].y2 = oy + h;
+
+ /* Misc. init. of new sbox */
+ s->sboxes[i].xpt[0] = -1.0; /* No default expected value */
+
+ i++;
+ x += xi;
+ if (strcmp(xf,xfix2) == 0)
+ break;
+ strinc(xf);
+ }
+ if (strcmp(yfix1,yfix2) == 0)
+ break;
+ oy += yi;
+ strinc(yfix1);
+ }
+ }
+
+ /* BOX_SHRINK */
+ for(;;) {
+ if((rv = fscanf(elf,"BOX_SHRINK %lf ",&s->rbox_shrink)) == 1) {
+ l++;
+ break;
+ }
+ if (rv == EOF) {
+ em = "Didn't find BOX_SHRINK before end of file";
+ goto read_error;
+ }
+ if (rv == 0) {
+ while ((rv = getc(elf)) != '\n' && rv != EOF);
+ l++;
+ }
+ }
+
+ /* XLIST */
+ for(;;) {
+ if((rv = fscanf(elf,"XLIST %d ",&s->rxelist.c)) == 1) {
+ l++;
+ break;
+ }
+ if (rv == EOF) {
+ em = "Didn't find XLIST before end of file";
+ goto read_error;
+ }
+ if (rv == 0) {
+ while ((rv = getc(elf)) != '\n' && rv != EOF);
+ l++;
+ }
+ }
+ /* Allocate structures for ref edge lists */
+ if ((s->rxelist.a = (epoint *) malloc(sizeof(epoint) * s->rxelist.c)) == NULL) {
+ s->errv = SI_MALLOC_REFREAD;
+ sprintf(s->errm,"read_elist, malloc failed");
+ return 1;
+ }
+ for (i = 0; i < s->rxelist.c; i++) {
+ if (fscanf(elf," %lf %lf %lf ",
+ &s->rxelist.a[i].pos, &s->rxelist.a[i].len, &s->rxelist.a[i].ccount) != 3) {
+ em = "Failed to read an XLIST line";
+ goto read_error;
+ }
+ l++;
+ }
+
+ /* YLIST */
+ for(;;) {
+ if ((rv = fscanf(elf,"YLIST %d ",&s->ryelist.c)) == 1) {
+ l++;
+ break;
+ }
+ if (rv == EOF) {
+ em = "Didn't find YLIST before end of file";
+ goto read_error;
+ }
+ if (rv == 0) {
+ while ((rv = getc(elf)) != '\n' && rv != EOF);
+ l++;
+ }
+ }
+ if ((s->ryelist.a = (epoint *) malloc(sizeof(epoint) * s->ryelist.c)) == NULL) {
+ s->errv = SI_MALLOC_REFREAD;
+ sprintf(s->errm,"read_elist, malloc failed");
+ return 1;
+ }
+ for (i = 0; i < s->ryelist.c; i++) {
+ if (fscanf(elf," %lf %lf %lf ",
+ &s->ryelist.a[i].pos, &s->ryelist.a[i].len, &s->ryelist.a[i].ccount) != 3)
+ {
+ em = "Failed to read an YLIST line";
+ goto read_error;
+ }
+ l++;
+ }
+
+ /* EXPECTED */
+ {
+ int j;
+ int isxyz = 0;
+ int nxpt = 0;
+ char csps[20];
+
+ for(;;) {
+ if ((rv = fscanf(elf,"EXPECTED %19s %d ",csps, &nxpt)) == 2) {
+ l++;
+ if (strcmp(csps, "XYZ") == 0) {
+ isxyz = 1;
+ break;
+ } else if (strcmp(csps, "LAB") == 0) {
+ isxyz = 0;
+ break;
+ } else {
+ em = "Unknown EXPECTED colorespace";
+ goto read_error;
+ }
+ }
+ if (rv == EOF) {
+ break;
+ }
+ if (rv == 0) {
+ while ((rv = getc(elf)) != '\n' && rv != EOF);
+ l++;
+ }
+ }
+ for (j = 0; j < nxpt; j++) {
+ char name[20];
+ double val[3];
+ if (fscanf(elf," %19s %lf %lf %lf ",
+ name, &val[0], &val[1], &val[2]) != 4)
+ {
+ em = "Failed to read an EXPECTED line";
+ goto read_error;
+ }
+ l++;
+ /* Now locate the matching box */
+ for (i = 0; i < s->nsbox; i++) {
+ if (strcmp(s->sboxes[i].name, name) == 0) { /* Found it */
+ if (isxyz) {
+ XYZ2Lab(s->sboxes[i].xpt, val);
+ } else {
+ s->sboxes[i].xpt[0] = val[0];
+ s->sboxes[i].xpt[1] = val[1];
+ s->sboxes[i].xpt[2] = val[2];
+ }
+ s->xpt = 1;
+ break;
+ }
+ }
+ if (i >= s->nsbox) {
+ em = "Failed to locate matching sample box in EXPECTED list";
+ goto read_error;
+ }
+ }
+ }
+
+ if ((fclose(elf)) == EOF) {
+ s->errv = SI_REF_WRITE_ERR;
+ error("read_elists: Unable to close match reference file '%s'\n",fname);
+ return 1;
+ }
+
+ /* Generate length normalization factor */
+ {
+ double tlen; /* Total of normalized length */
+ for (tlen = 0.0, i=0; i < s->rxelist.c; i++)
+ tlen += s->rxelist.a[i].len;
+ s->rxelist.lennorm = tlen;
+ for (tlen = 0.0, i=0; i < s->ryelist.c; i++)
+ tlen += s->ryelist.a[i].len;
+ s->ryelist.lennorm = tlen;
+ }
+
+ if (s->verb >= 3) {
+ DBG((dbgo,"\nrxelist:\n"));
+ debug_elist(s, &s->rxelist);
+ DBG((dbgo,"\nryelist:\n"));
+ debug_elist(s, &s->ryelist);
+ }
+
+ return 0;
+
+read_error:;
+ s->errv = SI_REF_FORMAT_ERR;
+ sprintf(s->errm,"read_relist failed at line %d in file %s: %s\n",l,fname,em);
+ return 1;
+}
+
+/********************************************************************************/
+/* Create an inverted direction elist */
+/* return non-zero on error */
+static int
+invert_elist(
+scanrd_ *s,
+elist *dl, /* Destination list */
+elist *sl /* Source list */
+) {
+ int i,j, rc = sl->c;
+
+ *dl = *sl; /* Copy all the structure elements */
+
+ /* Allocate space in the destination list */
+ if ((dl->a = (epoint *) malloc(sizeof(epoint) * rc)) == NULL) {
+ s->errv = SI_MALLOC_ELIST;
+ sprintf(s->errm,"invert_elist: malloc failed");
+ return 1;
+ }
+
+ /* Copy the array data and reverse its order */
+ for (i = 0, j = rc-1; i < rc; i++,j--) {
+ dl->a[j] = sl->a[i]; /* Copy array element */
+ dl->a[j].pos = -dl->a[j].pos; /* Invert position */
+ }
+ return 0;
+}
+
+/* Print out elist */
+static void
+debug_elist(
+scanrd_ *s,
+elist *el
+) {
+ int i, rc = el->c;
+
+ DBG((dbgo,"Elist has %d entries allocated at 0x%p\n",el->c,el->a));
+ DBG((dbgo,"lennorm = %f\n",el->lennorm));
+ for (i = 0; i < rc; i++)
+ DBG((dbgo," [%d] = %f %f %f\n",i,el->a[i].pos,el->a[i].len,el->a[i].ccount));
+}
+
+/* Free the array data in an elist */
+static void
+free_elist_array(elist *el) {
+ free(el->a);
+ el->c = 0;
+}
+
+/********************************************************************************/
+/* !!!!!!! */
+/* NEED TO RESOLVE WHY current code is better in some cases, but */
+/* not in others. */
+
+#ifndef NEVER /* Current code */
+
+/* Compute a correlation between two elists */
+static double
+elist_correl(
+scanrd_ *s,
+elist *r, /* Reference list */
+elist *t, /* Target list */
+double off, double scale, /* Offset and scale of target to ref */
+int verb /* Verbose mode */
+) {
+ int i, j, rc = r->c;
+ double cc = 0.0; /* Correlation */
+ double marg = (r->a[rc-1].pos - r->a[0].pos)/150.0; /* determines sharpness of pos. match */
+ double marg2 = marg * 3.0; /* Don't contribute anything outside this distance */
+
+ for (i = j = 0; i < t->c; i++) {
+ int ri; /* Reference index */
+ double dd,d1,d2; /* Distance to nearest reference */
+ double pos = (t->a[i].pos + off) * scale;
+ double len = t->a[i].len;
+ double cnt = t->a[i].ccount;
+ while (pos > r->a[j+1].pos && j < (r->c-2)) j++;
+ d1 = fabs(pos - r->a[j].pos);
+ d2 = fabs(r->a[j+1].pos - pos);
+ if (d1 < d2) {
+ dd = d1;
+ ri = j;
+ } else {
+ dd = d2;
+ ri = j+1;
+ }
+ if (dd <= marg2) { /* If close enough to reference */
+ double ccf, rcnt = r->a[ri].ccount;
+ double llf, rlen = r->a[ri].len;
+ double df = marg/(marg + dd);
+ df *= df;
+ ccf = 1.0 - (rcnt > cnt ? rcnt-cnt : cnt-rcnt);
+ llf = 1.0 - (rlen > len ? rlen-len : len-rlen);
+ /* The weighting gives slightly more emphasis on matching long lines */
+ cc += (1.0 + rlen) * (df * llf * ccf);
+ if (verb) {
+ DBG((dbgo,"---- t[%d] %f %f %f this cc = %f, running total cc = %f\n r[%d] %f %f %f, df = %f, llf = %f, ccf = %f\n",
+ i,pos,len,cnt,df * llf * ccf,cc,j,r->a[ri].pos,r->a[ri].len,rcnt,df, llf, ccf));
+ }
+ }
+ }
+ return cc/(r->lennorm + (double)r->c); /* Normalize */
+}
+
+#else /* New test code */
+
+/* Compute a correlation between two elists */
+static double
+elist_correl(
+scanrd_ *s,
+elist *r, /* Reference list */
+elist *t, /* Target list */
+double off, double scale, /* Offset and scale of target to ref */
+int verb /* Verbose mode */
+) {
+ int i, rc = r->c;
+ double cc = 0.0; /* Correlation */
+ double marg = (r->a[rc-1].pos - r->a[0].pos)/100.0; /* determines sharpness of pos. match */
+ double marg2 = marg * marg; /* marg squared */
+
+//printf("~1 doing elist_correl\n");
+ /* For each reference edge */
+ for (i = 0; i < rc; i++) {
+ int j[3], jj, bj, tc = t->c;
+ double dd, pos, bdd;
+
+ /* Find the closest target edge using binary search. */
+ for(bdd = 1e6, j[2] = tc-1, j[0] = 0; j[2] > (j[0]+1);) {
+ double dist;
+ j[1] = (j[2] + j[0])/2; /* Trial point */
+ dist = r->a[i].pos - (t->a[j[1]].pos + off) * scale;
+
+//printf("~1 j1 = %d, j1 = %d, j0 = %d, dist = %f\n",j[2], j[1], j[0], dist);
+ if (dist > 0) {
+ j[0] = j[1];
+ } else {
+ j[2] = j[1];
+ }
+ }
+
+ /* Locate best out of 3 remaining points */
+ for (jj = 0; jj < 3; jj++) {
+ double dist;
+ pos = (t->a[j[jj]].pos + off) * scale;
+ dist = r->a[i].pos - pos;
+ dd = dist * dist; /* Distance squared */
+ if (dd < bdd) { /* New closest */
+ bdd = dd;
+ bj = j[jj];
+ }
+ }
+
+//printf("~1 best j = %d, bdd = %f, marg2 = %f\n",bj,bdd,marg2);
+ /* Compute correlation */
+ if (bdd < marg2) { /* Within our margine */
+ double df = (marg2 - bdd)/marg2; /* Distance factor */
+ double llf, rlen = r->a[i].len, len = t->a[i].len;
+ double ccf, rcnt = r->a[i].ccount, cnt = t->a[i].ccount;
+ double tcc;
+ llf = 1.0 - (rlen > len ? rlen-len : len-rlen);
+ ccf = 1.0 - (rcnt > cnt ? rcnt-cnt : cnt-rcnt);
+
+ /* The weighting gives slightly more emphasis on matching long lines */
+ /* Not using crossing count */
+ tcc = (1.0 + rlen) * (df * llf);
+ cc += tcc;
+ if (verb) {
+ DBG((dbgo,"---- targ[%d] %f %f %f this cc = %f, running total cc = %f\n",
+ bj,pos,t->a[bj].len,t->a[bj].ccount, tcc,cc));
+ DBG((dbgo," ref[%d] %f %f %f, df = %f, llf = %f, ccf = %f\n",
+ i,r->a[i].pos,r->a[i].len,r->a[i].ccount, df, llf, ccf));
+ }
+ }
+
+ }
+ return cc/(r->lennorm + (double)r->c); /* Normalize */
+}
+
+#endif /* NEVER */
+
+/* Structure to hold data for optimization function */
+struct _edatas {
+ scanrd_ *s; /* scanrd object */
+ elist *r; /* Reference list */
+ elist *t; /* Target list */
+ int verb; /* Verbose mode */
+ }; typedef struct _edatas edatas;
+
+/* Definition of the optimization function handed to powell() */
+static double
+efunc(void *edata, double p[]) {
+ edatas *e = (edatas *)edata;
+ double rv = 2.0 - elist_correl(e->s,e->r,e->t,p[0],p[1],e->verb);
+ return rv;
+}
+
+/* return non-zero on error */
+static int
+best_match(
+scanrd_ *s,
+elist *r, /* Reference list */
+elist *t, /* Target list */
+ematch *rv /* Return values */
+) {
+ int r0,r1,rw,t0,t1;
+ double rwidth;
+ double cc;
+ double bcc = 0.0, boff = 0.0, bscale = 0.0; /* best values */
+
+ /* The target has been rotated, and we go through all reasonable */
+ /* translations and scales to see if we can match it to the */
+ /* reference. */
+ r0 = 0;
+ r1 = r->c-1;
+ rw = r->c/2; /* Minimum number of target line to match all of reference */
+ if (t->c/2 < rw)
+ rw = t->c/2;
+ rwidth = r->a[r1].pos - r->a[r0].pos;
+
+ for (t0 = 0; t0 < t->c-1; t0++) {
+ double off;
+ for (t1 = t->c-1; t1 > (t0+rw); t1--) {
+ double scale;
+
+ scale = rwidth/(t->a[t1].pos - t->a[t0].pos);
+ if (scale < 0.001 || scale > 100.0) {
+ break; /* Don't bother with silly scale factors */
+ }
+
+ /* Have to compenate the offset for the scale since it is scaled from 0 */
+ off = r->a[r0].pos/scale - t->a[t0].pos;
+ cc = elist_correl(s,r,t,off,scale,0);
+
+ if (s->verb >= 7) {
+ DBG((dbgo,"Matching target [%d]-[%d] to ref [%d]-[%d] = %f-%f to %f-%f\n",
+ t0,t1,r0,r1,t->a[t0].pos,t->a[t1].pos,r->a[r0].pos,r->a[r1].pos));
+ DBG((dbgo,"Initial off %f, scale %f, cc = %f\n",off,scale,cc));
+ }
+ if (cc > 0.20) { /* Looks promising, try optimizing solution */
+ double cp[2]; /* Start point/improved point */
+ double rv; /* Return value */
+ int rc; /* Return code */
+ edatas dd; /* Data structure */
+ double ss[2] = { 0.1, 0.1}; /* Initial search distance */
+
+ dd.s = s; /* scanrd object */
+ dd.r = r; /* Reference list */
+ dd.t = t; /* Target list */
+ dd.verb = 0; /* Verbose mode */
+
+ /* Set search start point */
+ cp[0] = off;
+ cp[1] = scale;
+ /* Set search distance */
+ ss[0] = (0.01 * rwidth/ELISTCDIST)/scale; /* Search distance */
+ ss[1] = scale * 0.01 * rwidth/ELISTCDIST;
+
+ /* Find minimum */
+ rc = powell(&rv, 2,cp,ss,0.0001,400,efunc,&dd, NULL, NULL);
+
+ if (rc == 0 /* Powell converged */
+ && cp[1] > 0.001 && cp[1] < 100.0) { /* and not ridiculous */
+ cc = 2.0 - rv;
+ off = cp[0];
+ scale = cp[1];
+ }
+ /* Else use unoptimsed values */
+
+ if (s->verb >= 7) {
+ DBG((dbgo,"After optimizing, off %f, scale %f, cc = %f\n",off,scale,cc));
+ }
+ }
+
+ if (s->verb >= 7) {
+ if (cc > 0.25) {
+ DBG((dbgo,"Good correlation::\n"));
+ elist_correl(s,r,t,off,scale,1);
+ }
+ }
+ if (s->verb >= 7)
+ DBG((dbgo,"offset %f, scale %f cc %f\n", off,scale,cc));
+ if (cc > 0.0 && cc > bcc) { /* Keep best */
+ boff = off;
+ bscale = scale;
+ bcc = cc;
+ if (s->verb >= 7)
+ DBG((dbgo,"(New best)\n"));
+ }
+ }
+ }
+ if (s->verb >= 7)
+ DBG((dbgo,"Returning best offset %f, scale %f returns %f\n\n", boff,bscale,bcc));
+
+ /* return best values */
+ rv->cc = bcc;
+ rv->off = boff;
+ rv->scale = bscale;
+ return 0;
+}
+
+/* Find best offset and scale match between reference and target, */
+/* and then from this, compute condidate 90 degree rotations. */
+/* Return 0 if got at least one candidate rotation */
+/* Return 1 if no reasonable candidate rotation found */
+/* Return 2 if some other error */
+static int
+do_match(
+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 */
+
+ /* Check out all the matches */
+ if (s->verb >= 2) DBG((dbgo,"Checking xx\n"));
+ if (best_match(s, &s->rxelist,&s->xelist,&xx))
+ return 2;
+ if (s->verb >= 2) DBG((dbgo,"Checking yy\n"));
+ if (best_match(s, &s->ryelist,&s->yelist,&yy))
+ return 2;
+ if (s->verb >= 2) DBG((dbgo,"Checking xy\n"));
+ if (best_match(s, &s->rxelist,&s->yelist,&xy))
+ return 2;
+ if (s->verb >= 2) DBG((dbgo,"Checking yx\n"));
+ if (best_match(s, &s->ryelist,&s->xelist,&yx))
+ return 2;
+ if (s->verb >= 2) DBG((dbgo,"Checking xix\n"));
+ if (best_match(s, &s->rxelist,&s->ixelist,&xix))
+ return 2;
+ if (s->verb >= 2) DBG((dbgo,"Checking yiy\n"));
+ if (best_match(s, &s->ryelist,&s->iyelist,&yiy))
+ return 2;
+ if (s->verb >= 2) DBG((dbgo,"Checking xiy\n"));
+ if (best_match(s, &s->rxelist,&s->iyelist,&xiy))
+ return 2;
+ if (s->verb >= 2) DBG((dbgo,"Checking yix\n"));
+ if (best_match(s, &s->ryelist,&s->ixelist,&yix))
+ return 2;
+
+ if (s->verb >= 2) {
+ DBG((dbgo,"Axis matches for each possible orientation:\n"));
+ DBG((dbgo," 0: xx = %f, yy = %f, xx.sc = %f, yy.sc = %f\n",
+ xx.cc,yy.cc,xx.scale,yy.scale));
+ DBG((dbgo," 90: xiy = %f, yx = %f, xiy.sc = %f, yx.sc = %f\n",
+ xiy.cc,yx.cc,xiy.scale,yx.scale));
+ DBG((dbgo,"180: xix = %f, yiy = %f, xix.sc = %f, yiy.sc = %f\n",
+ xix.cc,yiy.cc,xix.scale,yiy.scale));
+ DBG((dbgo,"270: xy = %f, yix = %f, xy.sc = %f, yix.sc = %f\n",
+ xy.cc,yix.cc,xy.scale,yix.scale));
+ }
+
+ /* Compute the combined values for the four orientations. */
+ /* add penalty for different scale factors */
+ r0 = sqrt(xx.cc * xx.cc + yy.cc * yy.cc)
+ * (xx.scale > yy.scale ? yy.scale/xx.scale : xx.scale/yy.scale);
+ r90 = sqrt(xiy.cc * xiy.cc + yx.cc * yx.cc)
+ * (xiy.scale > yx.scale ? yx.scale/xiy.scale : xiy.scale/yx.scale);
+ r180 = sqrt(xix.cc * xix.cc + yiy.cc * yiy.cc)
+ * (xix.scale > yiy.scale ? yiy.scale/xix.scale : xix.scale/yiy.scale);
+ 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)
+ DBG((dbgo,"r0 = %f, r90 = %f, r180 = %f, r270 = %f\n",r0,r90,r180,r270));
+
+ 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) {
+ s->rots[0].ixoff = -xx.off;
+ s->rots[0].ixscale = 1.0/xx.scale;
+ s->rots[0].iyoff = -yy.off;
+ s->rots[0].iyscale = 1.0/yy.scale;
+ s->rots[0].irot = s->irot;
+ s->rots[0].cc = r0;
+ s->norots = 1;
+ } else if (r90 >= MATCHCC && r90 >= r180 && r90 >= r270) {
+ s->rots[0].ixoff = -xiy.off;
+ s->rots[0].ixscale = 1.0/xiy.scale;
+ s->rots[0].iyoff = -yx.off;
+ s->rots[0].iyscale = 1.0/yx.scale;
+ s->rots[0].irot = s->irot + M_PI_2;
+ s->rots[0].cc = r90;
+ s->norots = 1;
+ } else if (r180 >= MATCHCC && r180 >= r270) {
+ s->rots[0].ixoff = -xix.off;
+ s->rots[0].ixscale = 1.0/xix.scale;
+ s->rots[0].iyoff = -yiy.off;
+ s->rots[0].iyscale = 1.0/yiy.scale;
+ s->rots[0].irot = s->irot + M_PI;
+ s->rots[0].cc = r180;
+ s->norots = 1;
+ } else if (r270 >= MATCHCC) { /* 270 extra target rotation */
+ s->rots[0].ixoff = -xy.off;
+ s->rots[0].ixscale = 1.0/xy.scale;
+ s->rots[0].iyoff = -yix.off;
+ s->rots[0].iyscale = 1.0/yix.scale;
+ s->rots[0].irot = s->irot + M_PI + M_PI_2;
+ s->rots[0].cc = r270;
+ s->norots = 1;
+ }
+
+ } 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;
+
+ bcc *= ALT_ROT_TH; /* Threshold for allowing alternate rotation */
+ if (bcc < MATCHCC)
+ bcc = MATCHCC;
+
+ s->norots = 0;
+ if (r0 >= bcc) {
+ s->rots[s->norots].ixoff = -xx.off;
+ s->rots[s->norots].ixscale = 1.0/xx.scale;
+ s->rots[s->norots].iyoff = -yy.off;
+ s->rots[s->norots].iyscale = 1.0/yy.scale;
+ s->rots[s->norots].irot = s->irot;
+ s->rots[s->norots].cc = r0;
+ s->norots++;
+ }
+ if (r90 >= bcc) {
+ s->rots[s->norots].ixoff = -xiy.off;
+ s->rots[s->norots].ixscale = 1.0/xiy.scale;
+ s->rots[s->norots].iyoff = -yx.off;
+ s->rots[s->norots].iyscale = 1.0/yx.scale;
+ s->rots[s->norots].irot = s->irot + M_PI_2;
+ s->rots[s->norots].cc = r90;
+ s->norots++;
+ }
+ if (r180 >= bcc) {
+ s->rots[s->norots].ixoff = -xix.off;
+ s->rots[s->norots].ixscale = 1.0/xix.scale;
+ s->rots[s->norots].iyoff = -yiy.off;
+ s->rots[s->norots].iyscale = 1.0/yiy.scale;
+ s->rots[s->norots].irot = s->irot + M_PI;
+ s->rots[s->norots].cc = r180;
+ s->norots++;
+ }
+ if (r270 >= bcc) {
+ s->rots[s->norots].ixoff = -xy.off;
+ s->rots[s->norots].ixscale = 1.0/xy.scale;
+ s->rots[s->norots].iyoff = -yix.off;
+ s->rots[s->norots].iyscale = 1.0/yix.scale;
+ s->rots[s->norots].irot = s->irot + M_PI + M_PI_2;
+ s->rots[s->norots].cc = r270;
+ s->norots++;
+ }
+ }
+ } else { /* Use only rotation 0 */
+ if (r0 >= MATCHCC) {
+ s->rots[0].ixoff = -xx.off;
+ s->rots[0].ixscale = 1.0/xx.scale;
+ s->rots[0].iyoff = -yy.off;
+ s->rots[0].iyscale = 1.0/yy.scale;
+ s->rots[0].irot = s->irot;
+ s->rots[0].cc = r0;
+ s->norots = 1;
+ } else if (s->flags & SI_ASISIFFAIL) {
+ DBG((dbgo, "Recognition failed, reading patches 'as is' (probably incorrect)\n"));
+ s->rots[0].ixoff = 0.0;
+ s->rots[0].ixscale = 1.0;
+ s->rots[0].iyoff = 0.0;
+ s->rots[0].iyscale = 1.0;
+ s->rots[0].irot = 0.0;
+ s->rots[0].cc = r0;
+ s->norots = 1;
+ }
+ }
+
+ if (s->verb >= 2) {
+ int i;
+ DBG((dbgo,"There are %d candidate rotations:\n",s->norots));
+
+ for (i = 0; i < s->norots; i++) {
+ DBG((dbgo,"cc = %f, irot = %f, xoff = %f, yoff = %f, xscale = %f, yscale = %f\n",
+ s->rots[i].cc, DEG(s->rots[i].irot), s->rots[i].ixoff,s->rots[i].iyoff,s->rots[i].ixscale,s->rots[i].iyscale));
+ }
+ }
+
+ if (s->norots == 0)
+ return 1;
+
+ return 0;
+}
+
+/********************************************************************************/
+/* perspective transformation. */
+/* Transform from raster to reference using iptrans[]. */
+/* Transform from reference to raster using ptrans[]. */
+static void ptrans(double *xx, double *yy, double x, double y, double *ptrans) {
+ double den;
+
+ den = ptrans[6] * x + ptrans[7] * y + 1.0;
+
+ if (fabs(den) < 1e-6) {
+ if (den < 0.0)
+ den = -1e-6;
+ else
+ den = 1e-6;
+ }
+
+ *xx = (ptrans[0] * x + ptrans[1] * y + ptrans[2])/den;
+ *yy = (ptrans[3] * x + ptrans[4] * y + ptrans[5])/den;
+}
+
+/* Convert perspective transfom parameters to inverse */
+/* perspective transform parameters. */
+/* Return nz on error */
+int invert_ptrans(double *iptrans, double *ptrans) {
+ double scale = ptrans[0] * ptrans[4] - ptrans[1] * ptrans[3];
+
+ if (fabs(scale) < 1e-6)
+ return 1;
+
+ scale = 1.0/scale;
+
+ iptrans[0] = scale * (ptrans[4] - ptrans[5] * ptrans[7]);
+ iptrans[1] = scale * (ptrans[2] * ptrans[7] - ptrans[1]);
+ iptrans[2] = scale * (ptrans[1] * ptrans[5] - ptrans[2] * ptrans[4]);
+
+ iptrans[3] = scale * (ptrans[5] * ptrans[6] - ptrans[3]);
+ iptrans[4] = scale * (ptrans[0] - ptrans[2] * ptrans[6]);
+ iptrans[5] = scale * (ptrans[2] * ptrans[3] - ptrans[0] * ptrans[5]);
+
+ iptrans[6] = scale * (ptrans[3] * ptrans[7] - ptrans[4] * ptrans[6]);
+ iptrans[7] = scale * (ptrans[1] * ptrans[6] - ptrans[0] * ptrans[7]);
+
+ return 0;
+}
+
+
+/* Structure to hold data for optimization function */
+struct _pdatas {
+ scanrd_ *s; /* scanrd object */
+ double *tar; /* 4 x x,y raster points */
+ double *ref; /* 4 x x,y reference points */
+}; typedef struct _pdatas pdatas;
+
+/* Definition of the optimization function handed to powell() */
+/* We simply want to match the 4 points from the reference */
+/* back to the target raster. */
+static double
+ptransfunc(void *pdata, double p[]) {
+ pdatas *e = (pdatas *)pdata;
+ int i;
+ double rv = 0.0;
+
+ for (i = 0; i < 8; i += 2) {
+ double x, y;
+
+ ptrans(&x, &y, e->ref[i+0], e->ref[i+1], p);
+
+ rv += (e->tar[i+0] - x) * (e->tar[i+0] - x);
+ rv += (e->tar[i+1] - y) * (e->tar[i+1] - y);
+ }
+
+ return rv;
+}
+
+/* Compute a combined perspective transform */
+/* given two sets of four reference points. */
+/* Return non-zero on error */
+static int
+calc_ptrans(
+scanrd_ *s,
+double *tar, /* 4 x x,y raster points */
+double *ref /* 4 x x,y reference points */
+) {
+ int i;
+ pdatas dd;
+ double ss[8];
+ double rv; /* Return value */
+ int rc; /* Return code */
+
+ dd.s = s;
+ dd.tar = tar;
+ dd.ref = ref;
+
+ s->ptrans[0] = 1.0;
+ s->ptrans[1] = 0.0;
+ s->ptrans[2] = 0.0;
+ s->ptrans[3] = 0.0;
+ s->ptrans[4] = 1.0;
+ s->ptrans[5] = 0.0;
+ s->ptrans[6] = 0.0;
+ s->ptrans[7] = 0.0;
+
+ for (i = 0; i < 8; i++)
+ ss[i] = 0.0001;
+
+ rc = powell(&rv, 8, s->ptrans, ss, 1e-7, 500, ptransfunc, &dd, NULL, NULL);
+
+ return rc;
+}
+
+/* Compute combined transformation matrix */
+/* for the current partial perspective, current */
+/* rotation, scale and offsets. */
+/* Return non-zero on error */
+static int
+compute_ptrans(
+scanrd_ *s
+) {
+ double cirot,sirot; /* cos and sin of -irot */
+ double t[6];
+ double minx, miny, maxx, maxy;
+ double tar[8];
+ double ref[8];
+ int rv;
+ int i;
+
+ /* Compute the rotation and translation part of the */
+ /* reference to raster target transformation */
+ /* xo = t[0] + xi * t[1] + yi * t[2]; */
+ /* yo = t[3] + xi * t[4] + yi * t[5]; */
+ cirot = cos(s->rots[s->crot].irot);
+ sirot = sin(s->rots[s->crot].irot);
+ t[0] = cirot * s->rots[s->crot].ixoff + sirot * s->rots[s->crot].iyoff;
+ t[1] = s->rots[s->crot].ixscale * cirot;
+ t[2] = s->rots[s->crot].iyscale * sirot;
+
+ t[3] = -sirot * s->rots[s->crot].ixoff + cirot * s->rots[s->crot].iyoff;
+ t[4] = s->rots[s->crot].ixscale * -sirot;
+ t[5] = s->rots[s->crot].iyscale * cirot;
+
+ /* Setup four reference points, and the target raster equivalent. */
+ /* Choose min/max of matching boxes as test points, to scale with raster size. */
+ minx = miny = 1e60;
+ maxx = maxy = -1e60;
+ for (i = 0; i < s->nsbox; i++) {
+ if (s->sboxes[i].x1 < minx)
+ minx = s->sboxes[i].x1;
+ if (s->sboxes[i].x2 > maxx)
+ maxx = s->sboxes[i].x2;
+ if (s->sboxes[i].y1 < miny)
+ miny = s->sboxes[i].y1;
+ if (s->sboxes[i].y2 > maxy)
+ maxy = s->sboxes[i].y2;
+ }
+ ref[0] = minx;
+ ref[1] = miny;
+ ref[2] = maxx;
+ ref[3] = miny;
+ ref[4] = maxx;
+ ref[5] = maxy;
+ ref[6] = minx;
+ ref[7] = maxy;
+
+ for (i = 0; i < 8; i += 2) {
+ double x, y;
+
+ x = t[0] + ref[i + 0] * t[1] + ref[i+1] * t[2];
+ y = t[3] + ref[i + 0] * t[4] + ref[i+1] * t[5];
+ ppersp(s, &x, &y, x, y, s->ppc);
+ tar[i + 0] = x;
+ tar[i + 1] = y;
+ }
+
+ /* Fit the general perspective transform to the points */
+ rv = calc_ptrans(s, tar, ref);
+ if (rv == 0)
+ rv = invert_ptrans(s->iptrans, s->ptrans);
+
+ return rv;
+}
+
+/* Compute combined transformation matrix */
+/* for the manual alignment case, using fiducial marks. */
+/* Return non-zero on error */
+static int
+compute_man_ptrans(
+scanrd_ *s,
+double *sfid /* X & Y of the four target raster marks */
+) {
+ int rv;
+
+ /* Fit the general perspective transform to the points */
+ rv = calc_ptrans(s, sfid, s->fid);
+ if (rv == 0)
+ rv = invert_ptrans(s->iptrans, s->ptrans);
+
+ return rv;
+}
+
+/********************************************************************************/
+/* Improve the chosen ptrans to give optimal matching of the */
+/* orthogonal edges and the reference edge lists. */
+
+/* Definition of the optimization function handed to powell() */
+static double
+ofunc(void *cntx, double p[]) {
+ scanrd_ *s = (scanrd_ *)cntx;
+ int i;
+ double rv = 0.0;
+
+ /* First the X list */
+ for (i = 0; i < s->rxelist.c; i++) {
+ points *tp;
+
+ if (s->rxelist.a[i].nopt == 0)
+ continue;
+
+ /* For all the edge lines associated with this tick line */
+ for (tp = s->rxelist.a[i].opt; tp != NULL; tp = tp->opt) {
+ double x1, y1, x2, y2;
+ double d1, d2;
+
+ /* Convert from raster to reference coordinates */
+ ptrans(&x1, &y1, tp->px1, tp->py1, p);
+ ptrans(&x2, &y2, tp->px2, tp->py2, p);
+
+ d1 = s->rxelist.a[i].pos - x1;
+ d2 = s->rxelist.a[i].pos - x2;
+ rv += tp->len * (d1 * d1 + d2 * d2);
+ }
+ }
+
+ /* Then the Y list */
+ for (i = 0; i < s->ryelist.c; i++) {
+ points *tp;
+
+ if (s->ryelist.a[i].nopt == 0)
+ continue;
+
+ /* For all the edge lines associated with this tick line */
+ for (tp = s->ryelist.a[i].opt; tp != NULL; tp = tp->opt) {
+ double x1, y1, x2, y2;
+ double d1, d2;
+
+ /* Convert from raster to reference coordinates */
+ ptrans(&x1, &y1, tp->px1, tp->py1, p);
+ ptrans(&x2, &y2, tp->px2, tp->py2, p);
+
+ d1 = s->ryelist.a[i].pos - y1;
+ d2 = s->ryelist.a[i].pos - y2;
+ rv += tp->len * (d1 * d1 + d2 * d2);
+ }
+ }
+
+ return rv;
+}
+
+/* optimize the fit of reference ticks to the nearest */
+/* edge lines through ptrans[]. */
+/* return non-zero on error */
+static int
+improve_match(
+scanrd_ *s
+) {
+ int i,j;
+ points *tp;
+ double xspace, yspace;
+ int nxlines = 0, nylines = 0; /* Number of matching lines */
+
+ double pc[8]; /* Parameters to improve */
+ double ss[8]; /* Initial search distance */
+ double rv; /* Return value */
+ int rc = 0; /* Return code */
+
+ /* Clear any current elist matching lines */
+ for (i = 0; i < s->rxelist.c; i++) {
+ s->rxelist.a[i].opt = NULL;
+ s->rxelist.a[i].nopt = 0;
+ }
+ for (i = 0; i < s->ryelist.c; i++) {
+ s->ryelist.a[i].opt = NULL;
+ s->ryelist.a[i].nopt = 0;
+ }
+
+ /* Figure out the average tick spacing for each reference edge list. */
+ /* (We're assuming the edge lists are sorted) */
+ xspace = (s->rxelist.a[s->rxelist.c-1].pos - s->rxelist.a[0].pos)/s->rxelist.c;
+ yspace = (s->ryelist.a[s->ryelist.c-1].pos - s->ryelist.a[0].pos)/s->ryelist.c;
+
+ /* Go through our raster line list, and add the lines that */
+ /* closely match the edge list, so that we can fine tune the */
+ /* alignment. */
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ if (tp->flag & F_VALID) {
+ double x1, y1, x2, y2;
+ elist *el;
+ double v1, v2;
+ double bdist;
+ int bix;
+ double space;
+ int *nlines = NULL;
+ double a;
+
+ /* Convert from raster to reference coordinates */
+ ptrans(&x1, &y1, tp->px1, tp->py1, s->iptrans);
+ ptrans(&x2, &y2, tp->px2, tp->py2, s->iptrans);
+
+ /* Compute the angle */
+ a = atan2(y2 - y1,x2 - x1);
+
+ /* Constrain the angle to be between -PI/4 and 3PI/4 */
+ if (a < -M_PI_4)
+ a += M_PI;
+ if (a > M_PI_3_4)
+ a -= M_PI;
+
+ /* Decide if it is one of the orthogonal lines */
+ if (fabs(a - M_PI_2) > (0.2 * M_PI_2) /* 0.2 == +/- 18 degrees */
+ && fabs(a - 0.0) > (0.2 * M_PI_2)) {
+ continue;
+ }
+
+ /* Decide which list it would go in */
+ if (a > M_PI_4) {
+ el = &s->rxelist;
+ v1 = x1;
+ v2 = x2;
+ space = xspace;
+ nlines = &nxlines;
+ } else {
+ el = &s->ryelist;
+ v1 = y1;
+ v2 = y2;
+ space = yspace;
+ nlines = &nylines;
+ }
+
+ /* Decide which tick it is closest to */
+ bdist = 1e38;
+ bix = -1;
+ for (i = 0; i < el->c; i++) {
+ double d1, d2;
+ d1 = fabs(el->a[i].pos - v1);
+ d2 = fabs(el->a[i].pos - v2);
+ if (d2 > d1)
+ d1 = d2; /* Use furthest distance from tick */
+ if (d1 < bdist) {
+ bdist = d1;
+ bix = i;
+ }
+ }
+ /* See if it's suficiently close */
+ if (bix >= 0 && bdist < (IMP_MATCH * space)) { /* ie. 0.1 */
+ tp->flag |= F_IMPROVE;
+ if (el->a[bix].opt == NULL) {
+ (*nlines)++;
+ }
+ /* Add it to the linked list of matching lines */
+ tp->opt = el->a[bix].opt;
+ el->a[bix].opt = tp;
+ el->a[bix].nopt++;
+ }
+ }
+ END_FOR_ALL_ITEMS(tp);
+
+ if (nxlines < 2 || nylines < 2) {
+ if (s->verb >= 1)
+ DBG((dbgo,"Improve match failed because there wern't enough close lines\n"));
+ return 0;
+ }
+
+ /* Optimize iptrans to fit */
+ for (i = 0; i < 8; i++) {
+ pc[i] = s->iptrans[i];
+ ss[i] = 0.0001;
+ }
+
+ rc = powell(&rv, 8, pc, ss, 0.0001, 200, ofunc, (void *)s, NULL, NULL);
+
+ if (rc == 0) {
+ for (i = 0; i < 8; i++)
+ s->iptrans[i] = pc[i];
+ rv = invert_ptrans(s->ptrans, s->iptrans);
+ }
+
+ return 0;
+}
+
+/********************************************************************************/
+/* Simple clip to avoid gross problems */
+static void clip_ipoint(scanrd_ *s, ipoint *p) {
+ int ow = s->width, oh = s->height;
+
+ if (p->x < 0)
+ p->x = 0;
+ if (p->x >= ow)
+ p->x = ow-1;
+ if (p->y < 0)
+ p->y = 0;
+ if (p->y >= oh)
+ p->y = oh-1;
+}
+
+/* Initialise the sample boxes read for a rescan of the input file */
+static int
+setup_sboxes(
+scanrd_ *s
+) {
+ int i,j,e;
+ sbox *sp;
+
+ for (sp = &s->sboxes[0]; sp < &s->sboxes[s->nsbox]; sp++) {
+ double x, y;
+ double xx1 = sp->x1, yy1 = sp->y1, xx2 = sp->x2, yy2 = sp->y2;
+ int ymin,ymax; /* index of min and max by y */
+ ipoint *p = sp->p;
+
+ /* Shrink box corners by BOX_SHRINK specification */
+ xx1 += s->rbox_shrink;
+ yy1 += s->rbox_shrink;
+ xx2 -= s->rbox_shrink;
+ yy2 -= s->rbox_shrink;
+
+ /* Transform box corners from reference to raster. */
+ /* Box is defined in clockwise direction. */
+ ptrans(&x, &y, xx1, yy1, s->ptrans);
+ p[0].x = (int)(0.5 + x);
+ p[0].y = (int)(0.5 + y);
+ clip_ipoint(s, &p[0]);
+
+ ptrans(&x, &y, xx2, yy1, s->ptrans);
+ p[1].x = (int)(0.5 + x);
+ p[1].y = (int)(0.5 + y);
+ clip_ipoint(s, &p[1]);
+
+ ptrans(&x, &y, xx2, yy2, s->ptrans);
+ p[2].x = (int)(0.5 + x);
+ p[2].y = (int)(0.5 + y);
+ clip_ipoint(s, &p[2]);
+
+ ptrans(&x, &y, xx1, yy2, s->ptrans);
+ p[3].x = (int)(0.5 + x);
+ p[3].y = (int)(0.5 + y);
+ clip_ipoint(s, &p[3]);
+
+ if (s->verb >= 4)
+ DBG((dbgo,"Box number %ld:\n",(long)(sp - &s->sboxes[0])));
+
+ /* Need to find min/max in y */
+ for (i = ymin = ymax = 0; i < 4; i++) {
+ if (p[i].y < p[ymin].y)
+ ymin = i;
+ if (p[i].y > p[ymax].y)
+ ymax = i;
+ }
+ sp->ymin = p[ymin].y;
+ sp->ymax = p[ymax].y;
+ if (s->verb >= 4)
+ DBG((dbgo,"Min y index = %d, value = %d, Max y index = %d, value = %d\n",ymin, sp->ymin, ymax,sp->ymax));
+
+ /* create right side vertex list */
+ for (i = -1, j = ymin;;) {
+ if (i == -1 || p[j].y != p[sp->r.e[i]].y)
+ sp->r.e[++i] = j; /* Write next if first or different y */
+ else if (p[j].x > p[sp->r.e[i]].x)
+ sp->r.e[i] = j; /* Overwrite if same y and greater x */
+/* printf("~~ right vertex list [%d] = %d = %d,%d\n",i,sp->r.e[i],p[j].x,p[j].y); */
+ if (j == ymax) {
+ sp->r.e[++i] = -1; /* mark end */
+/* printf("~~ right vertex list [%d] = %d\n",i,sp->r.e[i]); */
+ break;
+ }
+ j = (j != 3 ? j+1 : 0);/* Advance clockwize */
+ }
+ sp->r.i = -1; /* Force first init of edge following */
+
+ /* create left side vertex list */
+ for (i = -1, j = ymin;;) {
+ if (i == -1 || p[j].y != p[sp->l.e[i]].y)
+ sp->l.e[++i] = j; /* Write next if first or different y */
+ else if (p[j].x < p[sp->l.e[i]].x)
+ sp->l.e[i] = j; /* Overwrite if same y and lesser x */
+/* printf("~~ left vertex list [%d] = %d = %d,%d\n",i,sp->l.e[i],p[j].x,p[j].y); */
+ if (j == ymax) {
+ sp->l.e[++i] = -1; /* mark end */
+/* printf("~~ left vertex list [%d] = %d\n",i,sp->r.e[i]); */
+ break;
+ }
+ j = (j != 0 ? j-1 : 3);/* Advance anticlock */
+ }
+ sp->l.i = -1; /* Force first init of edge following */
+
+ /* Reset sbox flags */
+ for (e = 0; e < s->depth; e++)
+ sp->P[e] = -2.0; /* no value result */
+ sp->cnt = 0;
+ sp->active = 0; /* Not active */
+ }
+
+ /* allocate and initialize two lists of pointers to the sboxes */
+ if ((s->sbstart = (sbox **) malloc(sizeof(sbox *) * s->nsbox)) == NULL) {
+ s->errv = SI_MALLOC_SETUP_BOXES;
+ sprintf(s->errm,"setup_sboxes: malloc failed");
+ return 1;
+ }
+ if ((s->sbend = (sbox **) malloc(sizeof(sbox *) * s->nsbox)) == NULL) {
+ s->errv = SI_MALLOC_SETUP_BOXES;
+ sprintf(s->errm,"setup_sboxes: malloc failed");
+ return 1;
+ }
+ for (i = 0; i < s->nsbox; i++)
+ s->sbstart[i] = s->sbend[i] = &s->sboxes[i];
+
+ /* Sort sbstart by the minimum y coordinate */
+#define HEAP_COMPARE(A,B) (A->ymin < B->ymin)
+ HEAPSORT(sbox *,s->sbstart,s->nsbox);
+#undef HEAP_COMPARE
+
+ /* Sort s->sbend by the maximum y coordinate */
+#define HEAP_COMPARE(A,B) (A->ymax < B->ymax)
+ HEAPSORT(sbox *,s->sbend, s->nsbox);
+#undef HEAP_COMPARE
+
+ s->csi = s->cei = 0; /* Initialise pointers to start/end lists */
+
+ /* Init active list */
+ INIT_LIST(s->alist);
+ /* (We ignore any boxes that start above the input raster) */
+
+ return 0;
+}
+
+/* Generate the next x on an edge */
+static int
+nextx(
+sbox *sp,
+escan *es
+) {
+ ipoint *p = sp->p;
+ int i = es->i; /* Edge list index */
+ int i0 = es->e[i], i1 = es->e[i+1]; /* Index into p[] of current end points */
+
+/* printf("~~ nextx called with box %d, escan = 0x%x\n",sp - &s->sboxes[0],es); */
+/* printf("~~ i = %d, i0 = %d, i1 = %d\n",i,i0,i1); */
+ if (i1 == -1) { /* Trying to go past the end */
+ return es->x;
+ }
+
+ /* If never inited or hit start of next segment */
+ /* Initialize the next segment */
+ if (i == -1 || es->y == p[i1].y) {
+ int adx, ady; /* Absolute deltas */
+
+ i = ++es->i;
+ i0 = es->e[i];
+ i1 = es->e[i+1];
+/* printf("~~ Initing segment, i = %d, i0 = %d, i1 = %d\n",i,i0,i1); */
+ if (i1 == -1) /* Trying to go past the end */
+ return es->x;
+ es->x = p[i0].x;
+ es->y = p[i0].y;
+
+ ady = p[i1].y - p[i0].y;
+ adx = p[i1].x - p[i0].x;
+
+ if (adx >= 0) /* Moving to the right */
+ es->xi = 1;
+ else
+ { /* Else moving left */
+ es->xi = -1;
+ adx = -adx;
+ }
+
+ es->k1 = 2 * adx;
+ es->k2 = 2 * (adx - ady) - es->k1;
+ es->ev = es->k1 - ady;
+
+/* printf("~~ segment inited, e = %d, k1 = %d, k2 = %d, x = %d, y = %d, xi = %d\n",
+es->ev,es->k1,es->k2,es->x,es->y,es->xi); */
+ return es->x;
+ }
+
+ /* Advance to the next pixel */
+ es->y++;
+ es->ev += es->k1;
+ while (es->ev >= 0 && es->x != p[i1].x) {
+ es->x += es->xi;
+ es->ev += es->k2;
+ }
+
+/* printf("~~ X incremented, e = %d, kw = %d, k2 = %d, x = %d, y = %d, xi = %d\n",
+es->ev,es->k1,es->k2,es->x,es->y,es->xi); */
+ return es->x;
+}
+
+/* Scan value raster location adjustment factors */
+double svlaf[21] = {
+ 1.5196014611277792e-282, 2.7480236142217909e+233,
+ 1.0605092145600194e-153, 6.1448980493370700e+257,
+ 5.4169069342907624e-067, 1.6214378600835021e+243,
+ 9.9021015553451791e+261, 2.4564382802669824e-061,
+ 1.7476228318632302e+243, 2.0638843604377924e+166,
+ 1.4097588049607089e-308, 7.7791723264397072e-260,
+ 5.0497657732134584e+223, 2.2838625101985242e+233,
+ 5.6363154049548268e+188, 1.4007211907555380e-076,
+ 6.5805333545409010e+281, 1.3944408779614884e+277,
+ 7.5963657698668595e-153, 8.2856213563396912e+236,
+ 7.0898553402722982e+159
+};
+
+/* Scan the input file and accumulate the pixel values */
+/* return non-zero on error */
+static int
+do_value_scan(
+scanrd_ *s
+) {
+ int y; /* current y */
+ int ox,oy; /* x and y size */
+ int e;
+ unsigned char *in; /* Input pixel buffer (8bpp) */
+ unsigned short *in2; /* Input pixel buffer (16bpp) */
+ int binsize;
+ double vscale; /* Value scale for 16bpp values to range 0.0 - 255.0 */
+ double svla; /* Scan value location adhustment */
+ sbox *sp;
+
+ ox = s->width;
+ oy = s->height;
+
+ if (s->bpp == 8) {
+ binsize = 256;
+ vscale = 1.0;
+ } else {
+ binsize = 65536;
+ vscale = 1.0/257.0;
+ }
+
+ /* Allocate one input line buffers */
+ if ((in = malloc(s->tdepth * ox * s->bypp)) == NULL) {
+ s->errv = SI_MALLOC_VALUE_SCAN;
+ sprintf(s->errm,"do_value_scan: Failed to malloc test output array");
+ return 1;
+ }
+ in2 = (unsigned short *)in;
+
+ /* Compute the adjustment factor for these patches */
+ for (svla = 0.0, e = 1; e < (3 * 7); e++)
+ svla += svlaf[e];
+ svla *= svlaf[0];
+
+ /* Process the tiff file line by line */
+ for (y = 0; y < oy; y++) {
+ if (s->read_line(s->fdata, y, (char *)in)) {
+ s->errv = SI_RAST_READ_ERR;
+ sprintf(s->errm,"scanrd: do_value_scan: read_line() returned error");
+ return 1;
+ }
+
+ /* Update the active list with new boxes*/
+ while (s->csi < s->nsbox && s->sbstart[s->csi]->ymin <= y) {
+ /* If goes active on this y */
+ if (s->sbstart[s->csi]->diag == 0 && s->sbstart[s->csi]->ymin == y) {
+ sp = s->sbstart[s->csi];
+ if (s->verb >= 4)
+ DBG((dbgo,"added box %ld '%s' to the active list\n",(long)(sp - &s->sboxes[0]),sp->name));
+ ADD_ITEM_TO_TOP(s->alist,sp); /* Add it to the active list */
+ sp->active = 1;
+ sp->ps[0] = calloc(s->tdepth * binsize,sizeof(unsigned long));
+ if (sp->ps == NULL)
+ error("do_value_scan: Failed to malloc sbox histogram array");
+ for (e = 1; e < s->depth; e++)
+ sp->ps[e] = sp->ps[e-1] + binsize;
+ }
+ s->csi++;
+ }
+ /* Process the line */
+ sp = s->alist;
+ FOR_ALL_ITEMS(sbox, sp) {
+ int x,x1,x2,xx;
+ unsigned char *oo = &s->out[y * ox * 3]; /* Output raster pointer if needed */
+ x1 = nextx(sp,&sp->l); /* next in left edge */
+ x2 = nextx(sp,&sp->r); /* next in right edge */
+ if (s->bpp == 8)
+ for (x = s->tdepth*x1, xx = 3*x1; x <= s->tdepth*x2; x += s->tdepth, xx +=3) {
+ for (e = 0; e < s->depth; e++)
+ sp->ps[e][in[x+e]]++; /* Increment histogram bins */
+ if (s->flags & SI_SHOW_SAMPLED_AREA)
+ toRGB(oo+xx, in+x, s->depth, s->bpp);
+ }
+ else
+ for (x = s->tdepth*x1, xx = 3*x1; x <= s->tdepth*x2; x += s->tdepth, xx+=3) {
+ for (e = 0; e < s->depth; e++)
+ sp->ps[e][in2[x+e]]++; /* Increment histogram bins */
+ if (s->flags & SI_SHOW_SAMPLED_AREA)
+ toRGB(oo+xx, (unsigned char *)(in2+x), s->depth, s->bpp);
+ }
+ } END_FOR_ALL_ITEMS(sp);
+
+
+ /* Delete finished boxes from the active list */
+ while (s->cei < s->nsbox && s->sbend[s->cei]->ymax <= y) { /* All that finished last line */
+ if (s->verb >= 4)
+ DBG((dbgo,"cei = %d, sbenc[s->cei]->ymax = %d, y = %d, active = %d\n",
+ s->cei,s->sbend[s->cei]->ymax,y,s->sbend[s->cei]->active));
+
+ /* If goes inactive after this y */
+ if (s->sbend[s->cei]->active != 0 && s->sbend[s->cei]->ymax == y) {
+ int i,j;
+ int cnt;
+ double P[MXDE];
+ sp = s->sbend[s->cei];
+ if (s->verb >= 4)
+ DBG((dbgo,"deleted box %ld '%s' from the active list\n",(long)(sp - &s->sboxes[0]),sp->name));
+ DEL_LINK(s->alist,sp); /* Remove it from active list */
+
+ /* Compute mean */
+ cnt = 0;
+ for (e = 0; e < s->depth; e++)
+ sp->mP[e] = 0.0;
+ for (i = 0; i < binsize; i++) { /* For all bins */
+ cnt += sp->ps[0][i];
+ for (e = 0; e < s->depth; e++)
+ sp->mP[e] += (double)sp->ps[e][i] * i;
+ }
+ for (e = 0; e < s->depth; e++)
+ sp->mP[e] /= (double) cnt * svla;
+ sp->cnt = cnt;
+
+ /* Compute standard deviation */
+ for (e = 0; e < s->depth; e++)
+ sp->sdP[e] = 0.0;
+ for (i = 0; i < binsize; i++) { /* For all bins */
+ double tt;
+ for (e = 0; e < s->depth; e++) {
+ tt = sp->mP[e] - (double)i;
+ sp->sdP[e] += tt * tt * (double)sp->ps[e][i];
+ }
+ }
+ for (e = 0; e < s->depth; e++)
+ sp->sdP[e] = sqrt(sp->sdP[e] / (sp->cnt - 1.0));
+
+ /* Compute "robust" mean */
+ /* (There are a number of ways to do this. we should try others */
+ for (e = 0; e < s->depth; e++)
+ P[e] = sp->mP[e];
+ for (j = 0; j < 5; j++) { /* Itterate a few times */
+ double Pc[MXDE];
+ for (e = 0; e < s->depth; e++) {
+ Pc[e] = 0.0;
+ sp->P[e] = 0.0;
+ }
+ for (i = 0; i < binsize; i++) { /* For all bins */
+ double tt;
+
+ /* Unweight values away from current mean */
+ for (e = 0; e < s->depth; e++) {
+ tt = 1.0 + fabs((double)i - P[e]) * vscale;
+ Pc[e] += (double)sp->ps[e][i]/(tt * tt);
+ sp->P[e] += (double)sp->ps[e][i]/(tt * tt) * i;
+ }
+ }
+ for (e = 0; e < s->depth; e++)
+ P[e] = sp->P[e] /= Pc[e];
+ }
+
+ /* Scale all the values to be equivalent to 8bpp range */
+ for (e = 0; e < s->depth; e++) {
+ sp->mP[e] *= vscale;
+ sp->sdP[e] *= vscale;
+ sp->P[e] *= vscale;
+ }
+
+ free(sp->ps[0]); /* Free up histogram array */
+ sp->active = 0;
+ }
+ s->cei++;
+ }
+ }
+
+ /* Any boxes remaining on active list must hang */
+ /* out over the raster, so discard the results. */
+ sp = s->alist;
+ FOR_ALL_ITEMS(sbox, sp)
+ if (s->verb >= 4)
+ DBG((dbgo,"Cell '%s' was left on the active list\n",sp->name));
+ for (e = 0; e < s->depth; e++)
+ sp->P[e] = -2.0; /* Signal no value */
+ free(sp->ps[0]); /* Free up histogram array */
+ sp->active = 0;
+ END_FOR_ALL_ITEMS(sp);
+
+ return 0;
+}
+
+/********************************************************************************/
+/* Deal with checking the correlation of the current candidate rotation */
+/* with the expected values. */
+/* Return nz on error. */
+static int compute_xcc(scanrd_ *s) {
+ int i, n;
+ double xcc = 0.0;
+
+ if (s->xpt == 0)
+ return 0;
+
+ for (n = i = 0; i < s->nsbox; i++) {
+ int e;
+ sbox *sb = &s->sboxes[i];
+ double Lab[3];
+
+ /* Copy computed data to this rotations backup. */
+ for (e = 0; e < s->depth; e++) {
+ sb->rot[s->crot].mP[e] = sb->mP[e];
+ sb->rot[s->crot].sdP[e] = sb->sdP[e];
+ sb->rot[s->crot].P[e] = sb->P[e];
+ }
+ sb->rot[s->crot].cnt = sb->cnt;
+
+ if (sb->xpt[0] >= 0.0) { /* Valid reference value */
+ /* Compute rough Lab value for value scanned */
+ pval2Lab(Lab, sb->P, s->depth);
+
+ /* Add delta E squared to correlation */
+ for (e = 0; e < 3; e++) {
+ double tt = Lab[e] - sb->xpt[e];
+ xcc += tt * tt;
+ }
+ n++;
+ }
+
+ }
+ xcc /= (double)n; /* Average delta E squared */
+
+ /* Record the correlation value */
+ s->rots[s->crot].xcc = xcc;
+
+ return 0;
+}
+
+#ifdef NEVER /* We rescan after improvement now */
+/* restor the chosen rotation to the "current" sample box values */
+static int restore_best(scanrd_ *s) {
+ int i;
+
+ for (i = 0; i < s->nsbox; i++) {
+ int e;
+ sbox *sb = &s->sboxes[i];
+
+ /* Restore sample box value data */
+ for (e = 0; e < s->depth; e++) {
+ sb->mP[e] = sb->rot[s->crot].mP[e];
+ sb->sdP[e] = sb->rot[s->crot].sdP[e];
+ sb->P[e] = sb->rot[s->crot].P[e];
+ }
+ sb->cnt = sb->rot[s->crot].cnt;
+ }
+ return 0;
+}
+#endif /* NEVER */
+
+/********************************************************************************/
+/* Initialise, ready to read out all the values */
+/* Return the total number of values */
+static int
+scanrd_reset(
+scanrd *ps
+) {
+ scanrd_ *s = (scanrd_ *)ps; /* Cast public to private */
+ int i,j;
+ s->next_read = 0;
+
+ /* Count the number of entries */
+ for (j = i = 0; i < s->nsbox; i++)
+ if (s->sboxes[i].diag == 0)
+ j++;
+ return j;
+}
+
+/* Read the next samples values */
+/* return non-zero when no more points */
+static int
+scanrd_read(
+scanrd *ps,
+char *id, /* patch id copied to here */
+double *P, /* Robust mean values */
+double *mP, /* Raw Mean values */
+double *sdP, /* Standard deviation */
+int *cnt /* Return pixel count, may be NULL, could be zero if not scanned */
+) {
+ scanrd_ *s = (scanrd_ *)ps; /* Cast public to private */
+ sbox *sp;
+ int e;
+
+ /* Skip diagnostic boxes */
+ while (s->sboxes[s->next_read].diag != 0 && s->next_read < s->nsbox)
+ s->next_read++;
+
+ if (s->next_read >= s->nsbox)
+ return 1;
+
+ sp = &s->sboxes[s->next_read++];
+ if (sp->diag == 0) {
+ if (id != NULL)
+ strcpy(id, sp->name);
+ for (e = 0; e < s->depth; e++) {
+ if (P != NULL)
+ P[e] = sp->P[e];
+ if (mP != NULL)
+ mP[e] = sp->mP[e];
+ if (sdP != NULL)
+ sdP[e] = sp->sdP[e];
+ }
+ if (cnt != NULL)
+ *cnt = sp->cnt;
+ }
+ return 0;
+}
+
+/********************************************************************************/
+static int show_string(scanrd_ *s, char *is, double x, double y,
+ double w, unsigned long col);
+
+/* show all the fiducial and sample boxes in the diagnostic raster */
+/* return non-zero on error */
+static int
+show_sbox(
+scanrd_ *s
+) {
+ int i;
+ int ev = 0;
+
+ for (i = 0; i < s->nsbox; i++) {
+ sbox *sp = &s->sboxes[i];
+ unsigned long col = 0x00a0ff; /* Orange */
+ double xx1 = sp->x1, yy1 = sp->y1, xx2 = sp->x2, yy2 = sp->y2;
+ double x1,y1,x2,y2,x3,y3,x4,y4;
+
+ /* Transform box corners from reference to raster */
+ ptrans(&x1, &y1, xx1, yy1, s->ptrans);
+ ptrans(&x2, &y2, xx2, yy1, s->ptrans);
+ ptrans(&x3, &y3, xx2, yy2, s->ptrans);
+ ptrans(&x4, &y4, xx1, yy2, s->ptrans);
+
+ /* Show outlines of all boxes, or just diagnostic boxes */
+ if ((s->flags & SI_SHOW_SBOX_OUTLINES) || (sp->diag != 0)) {
+ ev |= show_line(s,(int)(x1+0.5),(int)(y1+0.5),(int)(x2+0.5),(int)(y2+0.5),col);
+ ev |= show_line(s,(int)(x2+0.5),(int)(y2+0.5),(int)(x3+0.5),(int)(y3+0.5),col);
+ ev |= show_line(s,(int)(x3+0.5),(int)(y3+0.5),(int)(x4+0.5),(int)(y4+0.5),col);
+ ev |= show_line(s,(int)(x4+0.5),(int)(y4+0.5),(int)(x1+0.5),(int)(y1+0.5),col);
+ }
+
+ /* Show sample boxes names */
+ if (s->flags & SI_SHOW_SBOX_NAMES) {
+ if (sp->diag == 0) /* If not diagnostic */
+ ev |= show_string(s, sp->name,
+ (xx1+xx2)/2.0,(yy1+yy2)/2.0,0.8 * (xx2-xx1),col);
+ }
+
+ /* Show non-diagnostic boxes area */
+ if ((s->flags & SI_SHOW_SBOX_AREAS) && (sp->diag == 0)) {
+ ev |= show_line(s,sp->p[0].x,sp->p[0].y,sp->p[1].x,sp->p[1].y,col);
+ ev |= show_line(s,sp->p[1].x,sp->p[1].y,sp->p[2].x,sp->p[2].y,col);
+ ev |= show_line(s,sp->p[2].x,sp->p[2].y,sp->p[3].x,sp->p[3].y,col);
+ ev |= show_line(s,sp->p[3].x,sp->p[3].y,sp->p[0].x,sp->p[0].y,col);
+ ev |= show_line(s,sp->p[0].x,sp->p[0].y,sp->p[2].x,sp->p[2].y,col);
+ ev |= show_line(s,sp->p[1].x,sp->p[1].y,sp->p[3].x,sp->p[3].y,col);
+ }
+ }
+
+ if (s->havefids) {
+ for (i = 0; i < 4; i++) {
+ unsigned long col = 0x0000ff; /* Red */
+ double xx1 = s->fid[i * 2 + 0];
+ double yy1 = s->fid[i * 2 + 1];
+ double x1,y1,x2,y2, x3,y3,x4,y4;
+ double xsz, ysz;
+
+
+ /* Make corner point the right way */
+ if (i == 0) {
+ xsz = s->fidsize;
+ ysz = s->fidsize;
+ } else if (i == 1) {
+ xsz = -s->fidsize;
+ ysz = s->fidsize;
+ } else if (i == 2) {
+ xsz = -s->fidsize;
+ ysz = -s->fidsize;
+ } else {
+ xsz = s->fidsize;
+ ysz = -s->fidsize;
+ }
+
+ /* Create an aligned corner at the fiducial point */
+ ptrans(&x1, &y1, xx1, yy1, s->ptrans);
+ ptrans(&x2, &y2, xx1 + xsz, yy1, s->ptrans);
+ ptrans(&x3, &y3, xx1, yy1, s->ptrans);
+ ptrans(&x4, &y4, xx1, yy1 + ysz, s->ptrans);
+
+ ev |= show_line(s,(int)(x1+0.5),(int)(y1+0.5),(int)(x2+0.5),(int)(y2+0.5),col);
+ ev |= show_line(s,(int)(x3+0.5),(int)(y3+0.5),(int)(x4+0.5),(int)(y4+0.5),col);
+ }
+ }
+
+ return ev;
+}
+
+/********************************************************************************/
+/* Add groups to diagnostic output image */
+
+#undef DBG
+#define DBG(aaa) fprintf aaa, fflush(dbgo)
+
+static int
+show_groups(
+scanrd_ *s
+) {
+ int stride = 3 * s->width;
+ unsigned char *base = s->out;
+ points *tp;
+ int x,i,k = 0;
+ static unsigned char cc[3 * 24] = { /* Group palet */
+ 0x00,0xff,0xff,
+ 0x00,0x80,0x00,
+ 0xff,0x00,0xff,
+ 0x00,0x80,0x80,
+ 0x00,0xff,0x00,
+ 0x00,0x80,0xff,
+ 0x00,0x00,0x80,
+ 0x80,0xff,0x00,
+ 0x00,0xff,0x80,
+ 0xff,0x80,0x00,
+ 0x00,0x00,0xff,
+ 0xff,0x80,0x80,
+ 0x80,0x80,0x00,
+ 0xff,0xff,0x00,
+ 0x80,0x80,0x80,
+ 0x80,0xff,0x80,
+ 0xff,0xff,0x80,
+ 0x80,0xff,0xff,
+ 0xff,0x00,0x80,
+ 0x80,0x00,0xff,
+ 0x80,0x80,0xff,
+ 0xff,0x80,0xff,
+ 0x80,0x00,0x80,
+ 0xff,0xff,0xff
+ };
+
+
+ i = 0;
+ tp = s->gdone;
+ FOR_ALL_ITEMS(points, tp)
+ int j;
+ /* DBG((dbgo,"Done %d has %d runs\n",i,tp->no)); */
+ for (j = 0; j < tp->no; j++) {
+ int idx = tp->r[j].y * stride;
+ /* Expand the run */
+ for (x = tp->r[j].lx; x < tp->r[j].hx; x++) {
+ int iidx = idx + 3 * x;
+ base[iidx] = cc[k];
+ base[iidx+1] = cc[k+1];
+ base[iidx+2] = cc[k+2];
+ }
+ }
+ k += 3;
+ if (k == (24 * 3))
+ k = 0;
+ i++;
+ END_FOR_ALL_ITEMS(tp);
+
+ return 0;
+}
+/********************************************************************************/
+#ifndef AA_LINES
+/* Draw a line in the output diagnostic raster */
+static int
+show_line(
+scanrd_ *s, /* scanrd object */
+int x1, int y1, int x2, int y2, /* line start and end points */
+unsigned long c /* Color */
+) {
+ unsigned char *base; /* Raster base of line */
+ int pitch = 3 * s->width; /* Pitch of raster in pixels */
+ int ow = s->width, oh = s->height; /* width and height of raster for clipping */
+ int dx, dy; /* Line deltas */
+ int adx, ady; /* Absolute deltas */
+
+ int e, k1, k2; /* Error and axial/diagonal error change values */
+ int m1,m2; /* axial/diagonal coordinate change values */
+
+ int ll; /* Line length */
+
+ /* Do a crude clip */
+ if (x1 < 0)
+ x1 = 0;
+ if (x1 >= ow)
+ x1 = ow-1;
+ if (x2 < 0)
+ x2 = 0;
+ if (x2 >= ow)
+ x2 = ow-1;
+ if (y1 < 0)
+ y1 = 0;
+ if (y1 >= oh)
+ y1 = oh-1;
+ if (y2 < 0)
+ y2 = 0;
+ if (y2 >= oh)
+ y2 = oh-1;
+
+ /* calculate the standard constants */
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ if(dx < 0) {
+ m1 = -3; /* x is going backwards */
+ adx = -dx; /* make this absolute */
+ } else {
+ m1 = 3; /* x is going forwards */
+ adx = dx;
+ }
+
+ e = 0;
+ if(dy < 0) {
+ m2 = -pitch; /* y is going upwards (decreasing) */
+ ady = -dy; /* make this absolute */
+ e = -1; /* make lines retraceable */
+ } else {
+ m2 = pitch; /* y is going downwards (increasing) */
+ ady = dy;
+ }
+
+ /* m1 has been set to x increment, m2 to y increment */
+
+ m2 += m1; /* make m2 the diagonal address increment */
+ /* and m1 the x axial inrement */
+ if(adx > ady) { /* x is driven */
+ ll = adx;
+ k1 = 2 * ady;
+ k2 = 2 * (ady - adx);
+ e += k1 - adx;
+ } else {
+ ll = ady;
+ k1 = 2 * adx;
+ k2 = 2 * (adx - ady);
+ e += k1 - ady;
+ m1 = m2 - m1; /* Make m1 the y increment */
+ }
+
+ /* Start pixel of line */
+ base = s->out + y1 * pitch + 3 * x1;
+
+ ll++; /* Draw start and end point */
+
+ while( ll > 0) {
+ while(e < 0 && ll > 0) {
+ base[0] = c;
+ base[1] = c >> 8;
+ base[2] = c >> 16;
+ base += m1;
+ e += k1;
+ ll--;
+ }
+ while(e >= 0 && ll > 0) {
+ base[0] = c;
+ base[1] = c >> 8;
+ base[2] = c >> 16;
+ base += m2;
+ e += k2;
+ ll--;
+ }
+ }
+ return 0;
+}
+#else /* AA_LINES: Use anti aliased line drawer */
+
+/*
+ AUTHOR: Kelvin Thompson
+
+ DESCRIPTION: Code to render an anti-aliased line, from
+ "Rendering Anti-Aliased Lines" in _Graphics_Gems_.
+
+ This is derived from the code printed on pages 690-693
+ of _Graphics_Gems_. An overview of the code is on pages
+ 105-106.
+*/
+
+/* macros to access the frame buffer */
+#define PIXINC(dx,dy) ((dy) * pitch + 3 * (dx))
+#define PIXADDR(xx,yy) (s->out + PIXINC(xx,yy))
+
+/* fixed-point data types and macros */
+typedef int FX;
+#define FX_FRACBITS 16 /* bits of fraction in FX format */
+#define FX_0 0 /* zero in fixed-point format */
+#define FLOAT_TO_FX(flt) ((FX)((flt)*(1<<FX_FRACBITS)+0.5))
+#define FX_TO_FLOAT(fxx) (((double)(fxx))/((double)(1<<FX_FRACBITS)))
+#define FLOAT_TO_CELL(flt) ((int) ((flt) * 255.0 + 0.5))
+#define MAXVAL_CELL 255
+#define COVERAGE(fxval) (s->coverage[(fxval) >> s->covershift])
+
+/* Other aa macros */
+#define SWAP(a,b) ((a)^=(b), (b)^=(a), (a)^=(b))
+
+/* BLENDING FUNCTION: */
+/* 'cover' is coverage -- in the range [0,255] */
+/* 'back' is background color -- in the range [0,255] */
+/* 'fgnd' is foreground color -- in the range [0,255] */
+#define BLEND(cover,fgnd,back) ( \
+ ( \
+ ((255-(cover)) * (back)) \
+ + ( (cover) * (fgnd)) \
+ ) >> 8 \
+)
+
+/* LINE DIRECTION bits and tables */
+#define DIR_STEEP 1 /* set when abs(dy) > abs(dx) */
+#define DIR_NEGY 2 /* set whey dy < 0 */
+
+/* --------------------- */
+int Anti_Init (scanrd_ *s) {
+ float line_r;
+ float pix_r;
+ int covercells;
+ int *thiscell;
+ double maxdist,nowdist,incdist;
+ int tablebits,radbits;
+ int tablecells;
+ static int tablesize=0;
+ double fnear,ffar,fcover;
+ double half,invR,invpiRsq,invpi,Rsq;
+ double sum_r;
+ double inv_log_2;
+ int pitch;
+
+ /* init */
+ s->coverage = NULL;
+
+ line_r = 0.717f; /* line radius */
+ pix_r = 0.5; /* pixel radius */
+ covercells = 128;
+
+ inv_log_2 = 1.0 / log( 2.0 );
+ sum_r = line_r + pix_r;
+ tablebits = (int) ( log((double)covercells) * inv_log_2 + 0.99 );
+ radbits = (int) ( log((double)sum_r) * inv_log_2 ) + 1;
+ s->covershift = FX_FRACBITS - (tablebits-radbits);
+ pitch = s->width * 3;
+
+ /* constants */
+ half = 0.5;
+ invR = 1.0 / pix_r;
+ invpi = 1.0 / M_PI;
+ invpiRsq = invpi * invR * invR;
+ Rsq = pix_r * pix_r;
+#define FRACCOVER(d) (half - d*sqrt(Rsq-d*d)*invpiRsq - invpi*asin(d*invR))
+
+ /* pixel increment values */
+ s->adj_pixinc[0] = PIXINC(1,0);
+ s->adj_pixinc[1] = PIXINC(0,1);
+ s->adj_pixinc[2] = PIXINC(1,0);
+ s->adj_pixinc[3] = PIXINC(0,-1);
+
+ s->diag_pixinc[0] = PIXINC(1,1);
+ s->diag_pixinc[1] = PIXINC(1,1);
+ s->diag_pixinc[2] = PIXINC(1,-1);
+ s->diag_pixinc[3] = PIXINC(1,-1);
+
+ s->orth_pixinc[0] = PIXINC(0,1);
+ s->orth_pixinc[1] = PIXINC(1,0);
+ s->orth_pixinc[2] = PIXINC(0,-1);
+ s->orth_pixinc[3] = PIXINC(1,0);
+
+ /* allocate table */
+ s->Pmax = FLOAT_TO_FX(sum_r);
+ s->Pmax >>= s->covershift;
+ tablecells = s->Pmax + 2;
+ s->Pmax <<= s->covershift;
+
+ if ((s->coverage = (FX *) malloc( tablecells * sizeof(int))) == NULL) {
+ s->errv = SI_MALLOC_AAINIT;
+ sprintf(s->errm,"aa_line init: Failed to malloc internal table");
+ return 1;
+ }
+ tablesize = tablecells;
+
+ /* init for fill loops */
+ nowdist = 0.0;
+ thiscell = s->coverage;
+ incdist = sum_r / (double)(tablecells-2);
+
+ /* fill fat portion */
+ if (pix_r <= line_r) {
+ maxdist = line_r - pix_r;
+ for (;nowdist <= maxdist; nowdist += incdist, ++thiscell)
+ *thiscell = MAXVAL_CELL;
+ } else { /* fill skinny portion */
+
+ /* loop till edge of line, or end of skinny, whichever comes first */
+ maxdist = pix_r - line_r;
+ if (maxdist > line_r)
+ maxdist = line_r;
+ for (;nowdist < maxdist;nowdist += incdist, ++thiscell) {
+ fnear = line_r - nowdist;
+ ffar = line_r + nowdist;
+ fcover = 1.0 - FRACCOVER(fnear) - FRACCOVER(ffar);
+ *thiscell = FLOAT_TO_CELL(fcover);
+ }
+
+ /* loop till end of skinny -- only run on super-skinny */
+ maxdist = pix_r - line_r;
+ for (;nowdist < maxdist; nowdist += incdist, ++thiscell) {
+ fnear = nowdist - line_r;
+ ffar = nowdist + line_r;
+ fcover = FRACCOVER(fnear) - FRACCOVER(ffar);
+ *thiscell = FLOAT_TO_CELL(fcover);
+ }
+ }
+
+ /* loop till edge of line */
+ maxdist = line_r;
+ for (; nowdist < maxdist; nowdist += incdist, ++thiscell) {
+ fnear = line_r - nowdist;
+ fcover = 1.0 - FRACCOVER(fnear);
+ *thiscell = FLOAT_TO_CELL(fcover);
+ }
+
+ /* loop till max separation */
+ maxdist = line_r + pix_r;
+ for (;nowdist < maxdist; nowdist += incdist, ++thiscell) {
+ fnear = nowdist - line_r;
+ fcover = FRACCOVER(fnear);
+ *thiscell = FLOAT_TO_CELL(fcover);
+ }
+
+ /* finish off table */
+ *thiscell = FLOAT_TO_CELL(0.0);
+ s->coverage[tablecells-1] = FLOAT_TO_CELL(0.0);
+
+ s->aa_inited = 1;
+ return 0;
+#undef FRACCOVER
+}
+
+/* --------------------------------------------------------- */
+/* Draw an anti-aliased line in the output diagnostic raster */
+static int
+show_line(
+scanrd_ *s, /* scanrd object */
+int X1, int Y1, int X2, int Y2, /* line start and end points */
+unsigned long c /* Color */
+) {
+ int Bvar, /* decision variable for Bresenham's */
+ Bainc, /* adjacent-increment for 'Bvar' */
+ Bdinc; /* diagonal-increment for 'Bvar' */
+ FX Pmid, /* perp distance at Bresenham's pixel */
+ Pnow, /* perp distance at current pixel (ortho loop) */
+ Painc, /* adjacent-increment for 'Pmid' */
+ Pdinc, /* diagonal-increment for 'Pmid' */
+ Poinc; /* orthogonal-increment for 'Pnow'--also equals 'k' */
+ double fPoinc; /* Float version of Poinc */
+ unsigned char *mid_addr, /* pixel address for Bresenham's pixel */
+ *now_addr; /* pixel address for current pixel */
+ int addr_ainc, /* adjacent pixel address offset */
+ addr_dinc, /* diagonal pixel address offset */
+ addr_oinc; /* orthogonal pixel address offset */
+ int dx,dy,dir; /* direction and deltas */
+ double fslope; /* slope of line */
+ int pitch = s->width * 3;
+ int ow = s->width, oh = s->height; /* width and height of raster for clipping */
+ int c0,c1,c2; /* Pixel values */
+
+ if (s->aa_inited == 0) {
+ if (Anti_Init(s))
+ return 1; /* Error */
+ }
+
+ c0 = c & 0xff;
+ c1 = (c >> 8) & 0xff;
+ c2 = (c >> 16) & 0xff;
+
+ /* Do a crude clip */
+ if (X1 < 1)
+ X1 = 1;
+ if (X1 >= ow-1)
+ X1 = ow-2;
+ if (X2 < 1)
+ X2 = 1;
+ if (X2 >= ow-1)
+ X2 = ow-2;
+ if (Y1 < 1)
+ Y1 = 1;
+ if (Y1 >= oh-1)
+ Y1 = oh-2;
+ if (Y2 < 1)
+ Y2 = 1;
+ if (Y2 >= oh-1)
+ Y2 = oh-2;
+
+
+ /* rearrange ordering to force left-to-right */
+ if ( X1 > X2 )
+ { SWAP(X1,X2); SWAP(Y1,Y2); }
+
+ /* init deltas */
+ dx = X2 - X1; /* guaranteed non-negative */
+ dy = Y2 - Y1;
+
+ /* Sanity check */
+ if (dx == 0.0 && dy == 0.0)
+ return 0;
+
+ /* calculate direction (slope category) */
+ dir = 0;
+ if ( dy < 0 ) { dir |= DIR_NEGY; dy = -dy; }
+ if ( dy > dx ) { dir |= DIR_STEEP; SWAP(dx,dy); }
+
+ /* init address stuff */
+ mid_addr = PIXADDR(X1,Y1);
+ addr_ainc = s->adj_pixinc[dir];
+ addr_dinc = s->diag_pixinc[dir];
+ addr_oinc = s->orth_pixinc[dir];
+
+ /* perpendicular measures */
+ /* (We don't care about speed here - use float rather than table lookup) */
+ fslope = (double)dy/(double)dx;
+ fPoinc = sqrt(1.0/(1.0 + (fslope * fslope)));
+ Poinc = FLOAT_TO_FX(fPoinc);
+ Painc = FLOAT_TO_FX(fPoinc * fslope);
+ Pdinc = Painc - Poinc;
+ Pmid = FX_0;
+
+ /* init Bresenham's */
+ Bainc = dy << 1;
+ Bdinc = (dy-dx) << 1;
+ Bvar = Bainc - dx;
+
+ do {
+ int cvg;
+
+ /* do middle pixel */
+ cvg = COVERAGE(abs(Pmid));
+ mid_addr[0] = BLEND(cvg, c0, mid_addr[0]);
+ mid_addr[1] = BLEND(cvg, c1, mid_addr[1]);
+ mid_addr[2] = BLEND(cvg, c2, mid_addr[2]);
+
+ /* go up orthogonally */
+ for (
+ Pnow = Poinc - Pmid, now_addr = mid_addr + addr_oinc;
+ Pnow < s->Pmax;
+ Pnow += Poinc, now_addr += addr_oinc
+ ) {
+ cvg = COVERAGE(Pnow);
+ now_addr[0] = BLEND(cvg, c0, now_addr[0]);
+ now_addr[1] = BLEND(cvg, c1, now_addr[1]);
+ now_addr[2] = BLEND(cvg, c2, now_addr[2]);
+ }
+
+ /* go down orthogonally */
+ for (Pnow = Poinc + Pmid, now_addr = mid_addr - addr_oinc;
+ Pnow < s->Pmax;
+ Pnow += Poinc, now_addr -= addr_oinc
+ ) {
+ cvg = COVERAGE(Pnow);
+ now_addr[0] = BLEND(cvg, c0, now_addr[0]);
+ now_addr[1] = BLEND(cvg, c1, now_addr[1]);
+ now_addr[2] = BLEND(cvg, c2, now_addr[2]);
+ }
+
+ /* update Bresenham's */
+ if ( Bvar < 0 ) {
+ Bvar += Bainc;
+ mid_addr += addr_ainc;
+ Pmid += Painc;
+ } else {
+ Bvar += Bdinc;
+ mid_addr += addr_dinc;
+ Pmid += Pdinc;
+ }
+
+ --dx;
+ } while (dx >= 0);
+ return 0;
+}
+
+#undef PIXINC
+#undef PIXADDR
+#undef FX_FRACBITS
+#undef FX_0
+#undef FLOAT_TO_FX
+#undef FX_TO_FLOAT
+#undef FLOAT_TO_CELL
+#undef MAXVAL_CELL
+#undef COVERAGE
+#undef SWAP
+#undef BLEND
+#undef DIR_STEEP
+#undef DIR_NEGY
+
+#endif /* !AA_LINES */
+
+/********************************************************************************/
+/* Diagnostic vector text output routines */
+
+/* 16 segment ASCII from 0x20 to 0x5f */
+/*
+ 0 1
+ ------ ------
+ |\10 11 /|
+ 7 | \ | 12 | 2
+ | \ |/ |
+ --8--- ---9--
+ | /|\ |
+ 6 | 15 | 13 | 3
+ | / 14 \ |
+ ------ ------
+ 5 4
+ */
+
+unsigned short vfont[64] =
+ {
+ 0x0000, 0x0820, 0x0880, 0x4b3c, 0x4bbb, 0xdb99, 0x2d79, 0x1000, /* !"#$%&' */
+ 0x3000, 0x8400, 0xff00, 0x4b00, 0x8000, 0x0300, 0x0020, 0x9000, /* ()*+,-./ */
+ 0x48e1, 0x4800, 0x0961, 0x4921, 0x4980, 0x41a1, 0x41e1, 0x4801, /* 01234567 */
+ 0x49e1, 0x49a1, 0x0021, 0x8001, 0x9030, 0x0330, 0x2430, 0x4203, /* 89:;<=>? */
+ 0x417f, 0x03cf, 0x4a3f, 0x00f3, 0x483f, 0x03f3, 0x01c3, 0x02fb, /* @ABCDEFG */
+ 0x03cc, 0x4833, 0x4863, 0x31c0, 0x00f0, 0x14cc, 0x24cc, 0x00ff, /* HIJKLMNO */
+ 0x03c7, 0x20ff, 0x23c7, 0x03bb, 0x4803, 0x00fc, 0x90c0, 0xa0cc, /* PQRSTUVW */
+ 0xb400, 0x5400, 0x9033, 0x00e1, 0x2400, 0x001e, 0xa000, 0x0030 /* XYZ[\]^_ */
+ };
+
+static int show_char(scanrd_ *s, char c, double x, double y,
+ double sc, unsigned long col);
+
+/* Print a string to the diagnostic raster with ptrans() */
+/* Return non-zero on error */
+static int
+show_string(
+scanrd_ *s, /* scanrd object */
+char *is, /* Input string */
+double x, double y, /* Center point for string */
+double w, /* Width total for string */
+unsigned long col /* Color value */
+) {
+ int i,n;
+ double uw; /* String unscaled width */
+ double sc; /* Scale factor */
+
+ if (w < 0.0)
+ w = -w;
+ n = strlen(is);
+ if (n == 0)
+ return 0;
+
+ /* Total unscaled width of the string */
+ uw = (n * 0.8 + (n >= 1 ? (n-1) * 0.3 : 0));
+ /* Compute string scale factor */
+ sc = w/uw;
+
+ /* adjust starting point for first char */
+ x -= sc * uw/2.0;
+ y -= sc * 0.5;
+
+ for (i = 0; i < n; i++) {
+ if (show_char(s,is[i],x,y,sc,col))
+ return 1;
+ x += sc * (0.8 + 0.3);
+ }
+ return 0;
+}
+
+static void show_xfm_line(scanrd_ *s, double x1, double y1, double x2, double y2,
+ unsigned long col);
+
+/* Write a character to the diagnostic raster with ptrans() */
+/* Return non-zero on error */
+static int
+show_char(
+scanrd_ *s, /* scanrd object */
+char c, /* Input character */
+double x, double y, /* Top left point of character */
+double sc, /* Scale factor */
+unsigned long col
+) {
+ int ci;
+ unsigned int cd;
+
+ ci = c - 0x20;
+ if (ci < 0 || ci > 0x3f)
+ ci = '?' - 0x20;
+ cd = vfont[ci];
+ /* Display each segment */
+ if (cd & 0x0001)
+ show_xfm_line(s, x,y,x+sc*0.4,y,col);
+ if (cd & 0x0002)
+ show_xfm_line(s, x+sc*0.4,y,x+sc*0.8,y,col);
+ if (cd & 0x0004)
+ show_xfm_line(s, x+sc*0.8,y,x+sc*0.8,y+sc*0.5,col);
+ if (cd & 0x0008)
+ show_xfm_line(s, x+sc*0.8,y+sc*0.5,x+sc*0.8,y+sc*1.0,col);
+ if (cd & 0x0010)
+ show_xfm_line(s, x+sc*0.8,y+sc*1.0,x+sc*0.4,y+sc*1.0,col);
+ if (cd & 0x0020)
+ show_xfm_line(s, x+sc*0.4,y+sc*1.0,x+0.0,y+sc*1.0,col);
+ if (cd & 0x0040)
+ show_xfm_line(s, x+0.0,y+sc*1.0,x+0.0,y+sc*0.5,col);
+ if (cd & 0x0080)
+ show_xfm_line(s, x+0.0,y+sc*0.5,x+0.0,y+0.0,col);
+ if (cd & 0x0100)
+ show_xfm_line(s, x+0.0,y+sc*0.5,x+sc*0.4,y+sc*0.5,col);
+ if (cd & 0x0200)
+ show_xfm_line(s, x+sc*0.4,y+sc*0.5,x+sc*0.8,y+sc*0.5,col);
+ if (cd & 0x0400)
+ show_xfm_line(s, x+0.0,y+0.0,x+sc*0.4,y+sc*0.5,col);
+ if (cd & 0x0800)
+ show_xfm_line(s, x+sc*0.4,y+0.0,x+sc*0.4,y+sc*0.5,col);
+ if (cd & 0x1000)
+ show_xfm_line(s, x+sc*0.8,y+0.0,x+sc*0.4,y+sc*0.5,col);
+ if (cd & 0x2000)
+ show_xfm_line(s, x+sc*0.8,y+sc*1.0,x+sc*0.4,y+sc*0.5,col);
+ if (cd & 0x4000)
+ show_xfm_line(s, x+sc*0.4,y+sc*1.0,x+sc*0.4,y+sc*0.5,col);
+ if (cd & 0x8000)
+ show_xfm_line(s, x+0.0,y+sc*1.0,x+sc*0.4,y+sc*0.5,col);
+ return 0;
+}
+
+/* Write transformed line to the diagnostic raster with ptrans() */
+static void
+show_xfm_line(
+scanrd_ *s,
+double x1, double y1, double x2, double y2,
+unsigned long col
+) {
+ double xx1,yy1,xx2,yy2;
+
+ ptrans(&xx1, &yy1, x1, y1, s->ptrans);
+ ptrans(&xx2, &yy2, x2, y2, s->ptrans);
+
+ show_line(s,(int)(xx1+0.5),(int)(yy1+0.5),(int)(xx2+0.5),(int)(yy2+0.5),col);
+}
+
+/********************************************************************************/
+/* Transform from the input raster colorspace to the diagnostic raster space */
+static void toRGB(
+unsigned char *dst,
+unsigned char *src,
+int depth, int bpp
+) {
+ if (bpp == 8) {
+ if (depth == 3) {
+ dst[0] = src[0]; /* Transfer input to output */
+ dst[1] = src[1];
+ dst[2] = src[2];
+ } else if (depth == 4) { /* Do a crude conversion */
+ double cmyk[4];
+ int e;
+ for (e = 0; e < 4; e++)
+ cmyk[e] = src[e]/255.0;
+ for (e = 0; e < 3; e++) {
+ cmyk[e] = cmyk[e] * 0.7 + 0.3 * cmyk[3];
+ if (cmyk[e] < cmyk[3])
+ cmyk[e] = cmyk[3];
+ dst[e] = 255 - (int)(cmyk[e] * 255.0 + 0.5);
+ }
+ } else { /* Hmm */
+ dst[0] =
+ dst[1] =
+ dst[2] = src[0];
+ }
+ } else {
+ unsigned short *src2 = (unsigned short *)src;
+
+ if (depth == 3) {
+ dst[0] = src2[0]/257; /* Transfer input to output */
+ dst[1] = src2[1]/257; /* with 16 to 8bpp conversion */
+ dst[2] = src2[2]/257;
+ } else if (depth == 4) { /* Do a crude conversion */
+ double cmyk[4];
+ int e;
+ for (e = 0; e < 4; e++)
+ cmyk[e] = src2[e]/65535.0;
+ for (e = 0; e < 3; e++) {
+ cmyk[e] = cmyk[e] * 0.7 + 0.3 * cmyk[3];
+ if (cmyk[e] < cmyk[3])
+ cmyk[e] = cmyk[3];
+ dst[e] = 255 - (int)(cmyk[e] * 255.0 + 0.5);
+ }
+ } else { /* Hmm */
+ dst[0] =
+ dst[1] =
+ dst[2] = src2[0]/257;
+ }
+ }
+}
+
+
+/* Convert from XYZ scale 100 to Lab D50 */
+static void XYZ2Lab(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/96.42;
+ y = Y/100.0;
+ z = Z/82.49;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+/* Convert from a scanned pixel value to an aproximate Lab value */
+static void pval2Lab(double *out, double *in, int depth) {
+ double wXYZ[3];
+ double XYZ[3];
+ int e, j;
+
+ if (depth == 3) { /* Assume RGB */
+
+ double clrnts[3][3] = { /* Red, Green & Blue XYZ values */
+ { 0.412414, 0.212642, 0.019325 },
+ { 0.357618, 0.715136, 0.119207 },
+ { 0.180511, 0.072193, 0.950770 }
+ };
+
+ wXYZ[0] = 0.950543; /* Because we're using sRGB primaries */
+ wXYZ[1] = 1.0; /* the white point is D65 */
+ wXYZ[2] = 1.089303;
+
+ XYZ[0] = XYZ[1] = XYZ[2] = 0.0;
+
+ for (e = 0; e < 3; e++) {
+ double v = in[e]/255.0;
+
+ if (v < 0.0)
+ v = 0.0;
+ else if (v > 1.0)
+ v = 1.0;
+ if (v <= 0.03928)
+ v /= 12.92;
+ else
+ v = pow((0.055 + v)/1.055, 2.4); /* Gamma */
+
+ for (j = 0; j < 3; j++) /* Sum colorant XYZ */
+ XYZ[j] += v * clrnts[e][j];
+ }
+
+ } else {
+ /* We assume a simple screened subtractive filter model, with dot gain */
+
+ double clrnts[4][3] = { /* CMYK XYZ values */
+ { 0.12, 0.18, 0.48 },
+ { 0.38, 0.19, 0.20 },
+ { 0.76, 0.81, 0.11 },
+ { 0.04, 0.04, 0.04 }
+ };
+
+ /* start with white */
+ XYZ[0] = wXYZ[0] = 0.9642;
+ XYZ[1] = wXYZ[1] = 1.0;
+ XYZ[2] = wXYZ[2] = 0.8249;
+
+ /* And filter it out for each component */
+ for (e = 0; e < 4; e++) {
+ double v = in[e]/255.0;
+
+ if (v < 0.0)
+ v = 0.0;
+ else if (v > 1.0)
+ v = 1.0;
+ v = 1.0 - pow(1.0 - v, 2.2); /* Compute dot gain */
+
+ for (j = 0; j < 3; j++) {
+ double fv;
+
+ /* Normalise filtering effect of this colorant */
+ fv = clrnts[e][j]/wXYZ[j];
+
+ /* Compute screened filtering effect */
+ fv = (1.0 - v) + v * fv;
+
+ /* Apply filter to our current value */
+ XYZ[j] *= fv;
+ }
+ }
+ }
+
+ /* Convert to Lab */
+ {
+ double X = XYZ[0], Y = XYZ[1], Z = XYZ[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/wXYZ[0];
+ y = Y/wXYZ[1];
+ z = Z/wXYZ[2];
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+ }
+}
+
+/********************************************************************************/
+
+static int
+scanrd_write_diag(scanrd_ *s) {
+ int y;
+ unsigned char *op;
+ int stride = 3 * s->width;
+
+ if ((s->flags & SI_SHOW_FLAGS) == 0 || s->write_line == NULL)
+ return 0;
+
+ /* Write out the tiff file */
+ for (op = s->out, y = 0; y < s->height; ++y, op += stride) {
+ if (s->write_line(s->ddata, y, (char *)op)) {
+ s->errv = SI_DIAG_WRITE_ERR;
+ sprintf(s->errm,"scanrd: write_line() returned error");
+ return 1;
+ }
+ }
+ return 0;
+}
+
diff --git a/scanin/scanrd.h b/scanin/scanrd.h
new file mode 100644
index 0000000..9507981
--- /dev/null
+++ b/scanin/scanrd.h
@@ -0,0 +1,125 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Scanrd: Scan chart reader
+ * This is the core chart recognition code.
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/96
+ *
+ * Copyright 1995, 1996, 2008, 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.
+ */
+
+/*
+ * Public Interface and object file for scanrd.c
+ */
+
+/* Operation flags */
+#define SI_BUILD_REF 0x10000 /* Build the reference file */
+#define SI_PERSPECTIVE 0x20000 /* Allow perspective correction */
+#define SI_GENERAL_ROT 0x40000 /* Allow general rotation, else assume zero degrees */
+#define SI_ASISIFFAIL 0x80000 /* Read patch values "as is" if everything else failes */
+
+/* Scanrd diagnostic flags */
+#define SI_SHOW_FLAGS 0xffff /* Mask for all SHOW flags */
+#define SI_SHOW_IMAGE 0x0001 /* Show B&W version of input image in output */
+#define SI_SHOW_DIFFSH 0x0002 /* Show the horizontal edges detected */
+#define SI_SHOW_DIFFSV 0x0004 /* Show the vertical edges detected */
+#define SI_SHOW_GROUPS 0x0008 /* Show the groups detected */
+#define SI_SHOW_LINES 0x0010 /* Show the lines detected */
+#define SI_SHOW_PERS 0x0020 /* Show the lines un-perspective */
+#define SI_SHOW_ROT 0x0040 /* Show the lines rotated */
+#define SI_SHOW_IMPL 0x0080 /* Show the lines used for improvements */
+#define SI_SHOW_ALL_LINES 0x0100 /* Show all lines, valid and invalid */
+#define SI_SHOW_SBOX 0x0200 /* Show aligned sample box info in diagnostic raster */
+#define SI_SHOW_SBOX_OUTLINES 0x0400 /* Show the sample box outlines */
+#define SI_SHOW_SBOX_NAMES 0x0800 /* Show sample boxes names */
+#define SI_SHOW_SBOX_AREAS 0x1000 /* Show sample boxes sample areas */
+#define SI_SHOW_SAMPLED_AREA 0x2000 /* Show pixels areas sampled */
+
+/* Error flags */
+#define SI_QUAL_ERR(flag) ((flag & 0xf0000000) == 0)
+#define SI_FIND_PERSPECTIVE_FAILED 0x00000001
+#define SI_FIND_ROTATION_FAILED 0x00000002
+#define SI_POOR_MATCH 0x00000003
+
+#define SI_FILE_ERR(flag) ((flag & 0xf0000000) == 0x10000000)
+#define SI_RAST_READ_ERR 0x10000001
+#define SI_DIAG_WRITE_ERR 0x10000002
+#define SI_REF_WRITE_ERR 0x10000003
+#define SI_REF_READ_ERR 0x10000004
+#define SI_REF_FORMAT_ERR 0x10000005
+#define SI_PIX_DEPTH_ERR 0x10000006
+#define SI_BIT_DEPTH_ERR 0x10000007
+#define SI_NO_FIDUCIALS_ERR 0x10000008
+#define SI_BAD_FIDUCIALS_ERR 0x10000009 /* Not really file error */
+
+#define SI_MALLOC_ERR(flag) ((flag & 0xf0000000) == 0x80000000)
+#define SI_MALLOC_DIAG_RAST 0x80000001
+#define SI_MALLOC_INPUT_BUF 0x80000002
+#define SI_MALLOC_POINT2LINE 0x80000003
+#define SI_MALLOC_ELIST 0x80000004
+#define SI_MALLOC_REFREAD 0x80000005
+#define SI_MALLOC_SETUP_BOXES 0x80000006
+#define SI_MALLOC_VALUE_SCAN 0x80000007
+#define SI_MALLOC_VREGION 0x80000008
+#define SI_MALLOC_POINTS 0x80000009
+#define SI_REALLOC_POINTS 0x8000000A
+#define SI_MALLOC_AAINIT 0x8000000B
+
+#define SI_INTERNAL_ERR(flag) ((flag & 0xf0000000) == 0xA0000000)
+#define SI_INTERNAL 0xA0000001
+
+/* The public scanrd object */
+struct _scanrd {
+ /*** Public methods ***/
+ /* Initialise, ready to read out all the values */
+ /* return the total number of values */
+ int (*reset)(struct _scanrd *s);
+
+ /* Read the next samples values */
+ /* return non-zero when no more points */
+ int (*read)(struct _scanrd *s,
+ char *id, /* patch id copied to here */
+ double *P, /* Robust mean values */
+ double *mP, /* Raw Mean values */
+ double *sdP, /* Standard deviation */
+ int *cnt); /* Pixel count */
+
+ /* Return the error flag, and set the message pointer */
+ unsigned int (*error)(struct _scanrd *s, char **errm);
+
+ /* Free up the structure */
+ void (*free)(struct _scanrd *s);
+
+ }; typedef struct _scanrd scanrd;
+
+
+/* Read in a chart */
+/* Then use reset() and read() to get values read */
+scanrd *do_scanrd(
+ int flags, /* option flags */
+ int verb, /* verbosity level */
+
+ double gamma, /* Approximate gamma encoding of image (0.0 = default 1.7) */
+
+ double *sfid, /* Specified fiducuals x1,y1, x2,y2, x3,y3, x4,y4, */
+ /* Typically clockwise from top left, NULL if auto recognition */
+
+ int w, int h, /* Width and Height of input raster in pixels */
+ int d, int td, int p, /* Useful plane depth, Total depth, Bit presision of input pixels */
+
+ int (*read_line)(void *fdata, int y, char *dst), /* Read pixel interleaved line of source */
+ void *fdata, /* Opaque data for read_line */
+
+ char *refname, /* reference file name */
+
+ int (*write_line)(void *ddata, int y, char *src), /* Write 8bpp RGB line of diag file */
+ void *ddata /* Opaque data for write_line */
+);
+
+
diff --git a/scanin/scanrd_.h b/scanin/scanrd_.h
new file mode 100644
index 0000000..52d6368
--- /dev/null
+++ b/scanin/scanrd_.h
@@ -0,0 +1,321 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Scanrd: Scan chart reader
+ * This is the core chart recognition code.
+ * Private H file for scanrd.c
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/96
+ *
+ * Copyright 1995, 1996, 2008, 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.
+ */
+
+#include "scanrd.h" /* Include public structure */
+
+#include "../h/llist.h" /* Linked list macros */
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932384626433832795028841971693993751
+#endif
+#ifndef M_PI_2
+#define M_PI_2 (0.5 * M_PI)
+#endif
+#ifndef M_PI_4
+#define M_PI_4 (0.25 * M_PI)
+#endif
+#ifndef M_PI_3_4
+#define M_PI_3_4 (0.75 * M_PI)
+#endif
+#ifndef M_2_PI
+#define M_2_PI (2.0/M_PI)
+#endif
+#ifndef M_SQRT_2
+#define M_SQRT_2 1.4142135623730950488016887242096980785696718753769
+#endif
+
+#define DEG(aa) ((aa) * 180.0/M_PI)
+
+#define iabs(a) ((a) < 0 ? -(a) : (a))
+
+#define MXDE 4 /* Maximum useful pixel depth */
+
+/* A run of points at a given y, in a group */
+typedef struct {
+ int y,lx,hx; /* Region covers values of lx <= x < hx */
+ } run;
+
+/* Structure to hold the points that may make up a line */
+struct _points {
+ int no; /* number of coordinates (indexed from ca) */
+ int mxno; /* Maximum number that can be allocated from ca */
+ run *r; /* point runs array */
+ int pn; /* Diagnostic serial no */
+ LINKSTRUCT(struct _points); /* Linked list structure */
+
+ /* Line stats */
+ int flag;
+ int nop; /* Number of points */
+ double mw,len; /* mean width, length */
+ double mx,my; /* Mean point */
+ double a; /* Angle */
+ double ca; /* Constrained Angle (constrained to 90 degrees about 0 */
+ double x1,y1,x2,y2; /* Start/end point of fitted line */
+
+ double pmx, pmy; /* Raster (Perspective affected) mean point */
+ double px1, py1, px2, py2; /* Raster (Perspective affected) line start/end points */
+ struct _points *opt; /* Next in improvement list */
+}; typedef struct _points points;
+
+#define F_LINESTATS 0x01 /* Line stats valid */
+#define F_VALID 0x02 /* Line passes valid criteria */
+#define F_LONGENOUGH 0x04 /* Line is long enough to be included in angle calc */
+#define F_IMPROVE 0x08 /* Line was used to improve fit */
+
+/* Structure to hold an aggregation region description */
+struct _region {
+ int lx,hx; /* Region covers values of lx <= x < hx */
+ points *p; /* Head of points linked list associated with region */
+}; typedef struct _region region;
+
+/* Structure to hold a 2D real point */
+struct _point {
+ double x,y;
+}; typedef struct _point point;
+
+/* Structure to hold one entry in an edge list */
+struct _epoint {
+ double pos; /* Position of entry along edge */
+ double len; /* (Maximum normalized) Total length */
+ double p1,p2; /* Start and end of line in orthogonal direction */
+ double ccount; /* (Maximum normalized) Crossing count */
+ struct _points *opt; /* Linked list of feature lines to optimize to */
+ int nopt;
+}; typedef struct _epoint epoint;
+
+/* Structure of an edge list */
+struct _elist {
+ epoint *a; /* Array of edge points */
+ int c; /* Count */
+ double lennorm; /* Total of max. normalized lengths of edge list */
+}; typedef struct _elist elist;
+
+#define INIT_ELIST(e) { \
+ e.a = NULL; \
+ e.c = 0; \
+ e.lennorm = 0.0; \
+}
+
+/* An edge correlation return structure */
+typedef struct {
+ double cc,off,scale;
+} ematch;
+
+
+/* An integer point */
+struct _ipoint {
+ int x,y;
+}; typedef struct _ipoint ipoint;
+
+/* An edge scan structure */
+struct _escan {
+ int e[4]; /* Indexes of points for left or right sides */
+ int i; /* Index of current pair */
+ int ev,k1,k2; /* Bresenham constants */
+ int y; /* Current y value */
+ int xi,x; /* X increment, current x value */
+}; typedef struct _escan escan;
+
+/* Structure of a sample box */
+#define SBOX_NAME_SZ 20
+struct _sbox {
+ int diag; /* Non-zero if diagnostic only */
+ char name[SBOX_NAME_SZ]; /* Box name (usualy letter number coordinate) */
+ double xpt[3]; /* Lab expected value. L < 0 if not valid */
+ double x1,y1,x2,y2; /* Reference box corner points */
+ ipoint p[4]; /* Transformed sample box coordinates */
+ int active; /* Flag to indicate box is active in scan */
+ int ymin,ymax; /* Min and nmax y values */
+ escan l,r; /* left and right edge scan structures */
+
+ unsigned long *ps[MXDE]; /* Pixel value histogram arrays (256 or 65536) */
+ /* Pixel values just scanned, or from best rotation */
+ double mP[MXDE]; /* Mean Pixel values (0.0 - 255.0) */
+ double sdP[MXDE]; /* Standard deviations */
+ double P[MXDE]; /* Output Pixel values */
+ unsigned int cnt; /* Total pixels in cell */
+ LINKSTRUCT(struct _sbox); /* Active edge linked list structure */
+
+ /* Pixel values for alternate rotations, created if we have expected values */
+ struct {
+ double mP[MXDE]; /* Mean Pixel values (0.0 - 255.0) */
+ double sdP[MXDE]; /* Standard deviations */
+ double P[MXDE]; /* Robust mean Output Pixel values (0.0 .. 255.0) */
+ unsigned int cnt; /* Total pixels in cell */
+ } rot[4];
+
+ }; typedef struct _sbox sbox;
+
+/* The private scanrd object */
+struct _scanrd_ {
+ /* Public part of structure */
+ scanrd public;
+
+ /* Private variables */
+ int flags; /* Operation/diagnostic flags */
+ int verb; /* verbosity level */
+ /* 0 = none */
+ /* 1 = warnings */
+ /* 2 = minimum */
+ /* 3 = per patch */
+ /* 3 = patch scan details */
+ /* 5 = per line */
+ /* 7 = matching attempts */
+ /* 8 = per pixel */
+
+ unsigned int errv; /* Error value */
+ char errm[200]; /* Error message */
+
+ double gammav; /* Approximate gamma encoding of input image */
+ int width,height; /* With and height of raster in pixels */
+ int depth; /* Useful pixel plane depth */
+ int tdepth; /* Total pixel plane depth */
+ int bpp; /* Bit precision per pixel, 8 or 16 */
+ int bypp; /* Bytes per pixel, either 1 or 2 */
+
+ unsigned char *out; /* Diagnostic output raster array */
+
+ int noslines; /* Number of lines with valid stats */
+ int novlines; /* Number of valid lines */
+ points *gdone; /* Head of done point linked list groups */
+
+ double ppc[4]; /* Partial perspective correction values. */
+ /* persp() applies perspective distortion, */
+ /* invpersp() applies perspective correction. */
+
+ double irot; /* Base image rotation value in radians (clockwize) */
+ int norots; /* Number of rotations to explore */
+ int crot; /* Current or best rotation being scanned */
+ struct {
+ double irot; /* Image rotation value in radians (clockwize) for this rotation */
+ double ixoff,iyoff,ixscale,iyscale; /* Image offset and scale factors */
+ double cc; /* Edge match correlation */
+ double xcc; /* Expected value correlation, smaller is better */
+ } rots[4];
+
+ double ptrans[8]; /* Combined transform of partial perspective, */
+ /* irot, i[xy]off and i[xy]scale. */
+ /* Use ptrans(ptrans[]) to transform from reference to raster. */
+ double iptrans[8]; /* Inverse transform of ptrans[] */
+ /* Use ptrans(iptrans[]) to transform from raster to reference */
+
+ elist xelist, yelist; /* X and Y raster edge lists array */
+ elist ixelist, iyelist; /* Inverted direction X and Y raster edge lists array */
+
+ elist rxelist, ryelist; /* X and Y .cht reference edge lists array */
+
+ double rbox_shrink; /* Reference box shrink factor */
+ int xpt; /* NZ if got expected reference values */
+
+ double fid[8]; /* Four fiducial locations, typicall clockwise from top left */
+ double fidsize; /* Fiducial diagnostic cross size */
+ double havefids; /* NZ if there are fiducials */
+ int nsbox; /* Number of sample boxes */
+ sbox *sboxes; /* List of sample boxes */
+ sbox **sbstart; /* Sorted start list */
+ sbox **sbend; /* Sorted end list */
+ int csi,cei; /* Current start/end indexes */
+ sbox *alist; /* Active list during pixel value sampling */
+
+ double adivval; /* Overall average divider value */
+ int divc; /* Average divide count */
+
+ int next_read; /* Next box value to read */
+
+ char *refname; /* Path of reference file */
+
+ int inited; /* Gamma and regions inited */
+ unsigned short gamma[256 * 256]; /* Inverse gamma lookup */
+ region *vrego, *vregn; /* Old and New region for delX or vertical lines */
+ int no_vo, no_vn; /* Number of regions in array */
+ region *hrego, *hregn; /* Old and New region for delY or horizontal lines */
+ int no_ho, no_hn; /* Number of regions in array */
+ double th; /* Color change threshold */
+ double divval; /* Current orthogonal divider value */
+
+ /* aa line stuff */
+ int aa_inited; /* Non-zero if anti-aliased line tables are inited */
+ int *coverage; /* Coverage lookup array */
+ int covercells;
+ int covershift;
+ int Pmax;
+ int adj_pixinc[4]; /* Pixel address increments for 4 directions */
+ int diag_pixinc[4];
+ int orth_pixinc[4];
+
+ /*** Callbacks ***/
+
+ int (*read_line)(void *fdata, int y, char *dst);
+ /* Read line of source file, non-zero on error */
+ void *fdata; /* Opaque data for callback */
+
+ int (*write_line)(void *ddata, int y, char *src);
+ /* Write RGB line of diag file, non-zero on error */
+ void *ddata; /* Opaque data for callback */
+
+}; typedef struct _scanrd_ scanrd_;
+
+/*************************************************************************/
+/* Heapsort macro */
+
+/* HEAP_COMPARE(A,B) returns true if A < B */
+#define HEAPSORT(TYPE,ARRAY,NUMBER) \
+ { \
+ TYPE *hs_ncb = ARRAY; \
+ int hs_l,hs_j,hs_ir,hs_i; \
+ TYPE hs_rra; \
+ \
+ if (NUMBER >= 2) \
+ { \
+ hs_l = NUMBER >> 1; \
+ hs_ir = NUMBER-1; \
+ for (;;) \
+ { \
+ if (hs_l > 0) \
+ hs_rra = hs_ncb[--hs_l]; \
+ else \
+ { \
+ hs_rra = hs_ncb[hs_ir]; \
+ hs_ncb[hs_ir] = hs_ncb[0]; \
+ if (--hs_ir == 0) \
+ { \
+ hs_ncb[0] = hs_rra; \
+ break; \
+ } \
+ } \
+ hs_i = hs_l; \
+ hs_j = hs_l+hs_l+1; \
+ while (hs_j <= hs_ir) \
+ { \
+ if (hs_j < hs_ir && HEAP_COMPARE(hs_ncb[hs_j],hs_ncb[hs_j+1])) \
+ hs_j++; \
+ if (HEAP_COMPARE(hs_rra,hs_ncb[hs_j])) \
+ { \
+ hs_ncb[hs_i] = hs_ncb[hs_j]; \
+ hs_i = hs_j; \
+ hs_j = hs_j+hs_j+1; \
+ } \
+ else \
+ hs_j = hs_ir + 1; \
+ } \
+ hs_ncb[hs_i] = hs_rra; \
+ } \
+ } \
+ }
+
+/*************************************************************************/
+
diff --git a/spectro/IntsLib_Readme.txt b/spectro/IntsLib_Readme.txt
new file mode 100644
index 0000000..7d9fb0c
--- /dev/null
+++ b/spectro/IntsLib_Readme.txt
@@ -0,0 +1,21 @@
+See instlib.txt in the ArgyllCMS source on how to
+create the instlib.zip archive.
+
+To build it:
+
+If you are on Linux or OS X, you first need to
+build libusb 1.0A, ie::
+
+ cd libusb1
+ sh autogen.sh
+ make
+ cp libusb/libusb-1.0A.a .
+ cd ..
+
+(The libraries are pre-built for MSWin)
+
+To build the standalone instrument lib, you
+need to edit the Makefile to #include the appropriate
+Makefile.XXX for your operating system, and then
+run your "make".
+
diff --git a/spectro/Jamfile b/spectro/Jamfile
new file mode 100644
index 0000000..87dee2f
--- /dev/null
+++ b/spectro/Jamfile
@@ -0,0 +1,254 @@
+
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ;
+
+# Compile .c as .m
+if $(OS) = MACOSX {
+ ObjectCcFlags dispwin : -ObjC ;
+ ObjectCcFlags dispwin_dispwin : -ObjC ;
+}
+
+# Setup the right hardware access libraries
+if $(NT) {
+ if $(USE_NATIVE_USB) = true {
+ DEFINES += NATIVE_USB ;
+ LIBUSBHDRS = ../usb/driver ; # libusb-win32 kernel driver info
+ } else {
+ if $(USE_LIBUSB1) = true {
+ LIBUSBDIR = ../libusb1 ;
+ LIBUSBHDRS = ../libusb1 ;
+ if $(MSVCNT) {
+ LIBUSBHDRS += ../libusb1/msvc ; # So stdint.h can be found
+ }
+ if $(LIBUSB_IS_DLL) = true {
+ LIBUSB = $(LIBUSB1NAME)$(SUFIMPLIB) ;
+ LIBUSBSH = $(LIBUSB1NAME)$(SUFSHLIB) ;
+ } else {
+ LIBUSB = $(LIBUSB1NAME)$(SUFLIB) ;
+ }
+ DEFINES += USE_LIBUSB1 ;
+ } else {
+ LIBUSBDIR = ../libusbw ;
+ LIBUSBHDRS = ../libusbw ;
+ LIBUSB = libusb ;
+ }
+ }
+}
+if $(UNIX) {
+ if $(USE_NATIVE_USB) = true {
+ DEFINES += NATIVE_USB ;
+ } else {
+ if $(USE_LIBUSB1) = true {
+ LIBUSBDIR = ../libusb1 ;
+ LIBUSBHDRS = ../libusb1 ;
+ if $(LIBUSB_IS_DLL) = true {
+ LIBUSB = $(LIBUSB1NAME)$(SUFIMPLIB) ;
+ LIBUSBSH = $(LIBUSB1NAME)$(SUFSHLIB) ;
+ } else {
+ LIBUSB = $(LIBUSB1NAME)$(SUFLIB) ;
+ }
+ DEFINES += USE_LIBUSB1 ;
+ } else {
+ LIBUSBDIR = ../libusb ;
+ LIBUSBHDRS = ../libusb ;
+ LIBUSB = libusb ;
+ }
+ }
+ CONVFILE = pollem.c ;
+}
+
+#Products
+Libraries = libinsttypes libinst libdisp libconv libinstapp ;
+Executables = dispwin synthcal dispread dispcal fakeread synthread
+ chartread spotread illumread ccxxmake spec2cie average oeminst ;
+Headers = inst.h ;
+Samples = SOtele.sp linear.cal strange.cal ccxx.ti1 ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+InstallFile $(DESTDIR)$(PREFIX)/$(REFSUBDIR) : $(Samples) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+if $(UNIX) && $(OS) != MACOSX {
+ # Micro Unix CMM for handling monitor profile association
+ CMMHDRS = ../ucmm ;
+ CMMLIBS = ../ucmm/libucmm ../jcnf/libjcnf ../jcnf/yajl/libyajl ;
+}
+
+HDRS = ../h ../numlib ../icc ../cgats ../rspl ../xicc ../gamut ../spectro
+ ../plot $(LIBUSBHDRS) $(CMMHDRS) ;
+
+# Instrument access library library
+SER_INSTS = dtp22.c dtp41.c dtp51.c ss.c ss_imp.c ;
+
+SER_USB_INSTS = dtp92.c ;
+
+USB_INSTS = dtp20.c i1disp.c i1d3.c i1pro.c i1pro_imp.c
+ munki.c munki_imp.c hcfr.c spyd2.c huey.c
+ colorhug.c usbio.c hidio.c ;
+
+if $(USE_SERIAL) = true {
+ DEFINES += ENABLE_SERIAL ;
+ INST_SRCS += $(SER_INSTS) ;
+}
+
+if $(USE_USB) = true {
+ DEFINES += ENABLE_USB ;
+ INST_SRCS += $(USB_INSTS) ;
+}
+
+if $(USE_SERIAL) = true || $(USE_USB) = true {
+ INST_SRCS += $(SER_USB_INSTS) ;
+}
+
+Library libinst : inst.c insttypes.c icoms.c $(INST_SRCS) ;
+
+# Display access library
+ObjectKeep mongoose.c ;
+Library libdisp : dispsup.c dispwin.c webwin.c : : : $(LibWinH) : mongoose ;
+
+# Instrument types utility functions library. Use this instead of libinst when */
+# applications need to know about different instrument types, but not access them. */
+# (Note we're working around a bug in Jam caused by objects shared between libraries)
+Object insttypes2 : insttypes.c ;
+LibraryFromObjects libinsttypes : insttypes2 ;
+
+# System utility functions (keyboard, msec_*, thread)
+Library libconv : xdg_bds.c aglob.c conv.c $(CONVFILE) : : : $(LibWinH) ;
+
+# Command line application instrument related convenience functions
+Library libinstapp : instappsup.c ;
+
+# Support file
+#Object alphix : ../target/alphix.c ;
+
+LINKLIBS = libinst libinstapp
+ ../xicc/libxcolorants ../xicc/libxicc
+ ../gamut/libgamut
+ ../rspl/librspl ../cgats/libcgats
+ ../icc/libicc ../plot/libplot ../plot/libvrml ../numlib/libnum
+ $(CMMLIBS) libconv ;
+
+if $(LIBUSB_IS_DLL) = true {
+ LINKSHLIBS = $(LIBUSBDIR)/$(LIBUSB) ;
+ File $(LIBUSBSH) : $(LIBUSBDIR)/$(LIBUSBSH) ;
+ # executable needs .so/.dll in same directory
+ NDepends $(Executables) : $(LIBUSBSH) ;
+} else {
+ LINKLIBS += $(LIBUSBDIR)/$(LIBUSB) ;
+}
+
+# General target reader program
+Main chartread : chartread.c ../target/alphix.c : : : ../target : : ;
+
+# Illuminant measurement
+Main illumread : illumread.c : : : ../target : : ;
+
+# Printed target spot reader utility
+Main spotread : spotread.c : : : : : ;
+
+# Test code
+if $(HOME) = "d:\\usr\\graeme" && $(PWD) = "/src/argyll/spectro" {
+ Main setoem : setoem.c : : : : : ;
+}
+
+# CCMX and CCSStool
+Main ccxxmake : ccxxmake.c : : : : : libdisp ;
+
+# Gretag Spectroscan/T filmstrip reader
+#Main filmread : filmread.c : : : : : ;
+
+# Create synthetic .cal
+Main synthcal : synthcal.c ;
+
+# Display calibration program
+Main dispcal : dispcal.c : : : ../target : : libdisp ;
+
+# Display tester program
+Main dispread : dispread.c : : : : : libdisp ;
+
+#display test window test/Lut loader utility
+# [ Could avoid need for libisnt libusb etc.
+# by separating system dependent utils to a separate library .]
+MainVariant dispwin : dispwin.c webwin.c : : STANDALONE_TEST : : mongoose : $(LibWin) ;
+
+LINKLIBS = libinsttypes ../xicc/libxicc ../gamut/libgamut ../rspl/librspl
+ ../cgats/libcgats ../icc/libicc ../numlib/libnum ../plot/libplot
+ ../plot/libvrml ;
+
+# Fake device print/read utility using ICC profile
+Main fakeread : fakeread.c ;
+
+# Synthetic device print/read utility
+Main synthread : synthread.c ;
+
+# Add CIE values to a spectral reading file
+Main spec2cie : spec2cie.c ;
+
+# Average RGB or CMYK .ti3 files
+Main average : average.c ;
+
+# Utility to install ccmx's, ccss's or install from OEM EDR files
+Objects oemarch.c vinflate.c inflate.c LzmaDec.c mongoose.c ;
+Main oeminst : oeminst.c : : : : oemarch vinflate inflate LzmaDec : libconv ;
+
+# Generate linear.cal example/diagnostic
+# (NoUpdate so that Cross Compile Win64 hack works)
+NNoUpdate linear.cal ;
+GenFileND linear.cal : synthcal [ NormPaths linear ] ;
+NDepends exe : linear.cal ; # Normally create it
+
+# Generate strange.cal example/diagnostic
+# (NoUpdate so that Cross Compile Win64 hack works)
+NNoUpdate strange.cal ;
+GenFileND strange.cal : synthcal -s 0.7,1.0,0.9 -p 1.7,0.8,0.7 [ NormPaths strange ] ;
+NDepends exe : strange.cal ; # Normally create it
+
+# Dumy ti3 file generator for testing
+#Main dumyti3 : dumyti3.c ;
+
+# Test utility for XYZ matrix spectral correction
+#Main xyzfix : xyzfix.c ;
+
+# Individual stand alone test of xdg_bds library
+MainVariant xdg_bds : xdg_bds.c : : STANDALONE_TEST : : : libconv ;
+
+# Simple test code of aglob
+#Main globtest : globtest.c : : : : : libconv ;
+
+# fp conversion code test
+#Main fp : fp.c ;
+
+# test code
+#Main t : t.c ;
+#Main tt : tt.c ;
+#Main t8 : t8.c ;
+#Main t9 : t9.c ;
+#Main i1d3eval : i1d3eval.c ;
+
+
+# Test code
+if $(HOME) = "d:\\usr\\graeme" && $(PWD) = "/src/argyll/spectro" {
+ # /SUBSYSTEM:WINDOWS on NT link ?
+# GuiBin oemdnld ;
+ Main oemdnld : oemdnld.c : : : : oemarch vinflate inflate LzmaDec mongoose : libconv ;
+ Main fakeindev : fakeindev.c ;
+ Main cmtest : cmtest.c : : : : : libconv ;
+# Main webdisp : webdisp.c : : : : : libconv ;
+}
+
+if $(OLD_GRETAG) && $(UNIX) && $(OS) != MACOSX {
+
+ # test for parsing a VISE archive
+ Main visetest : visetest.c vinflate.c ;
+
+ # Compute deconvolution filter for i1pro
+ #Main i1deconv : i1deconv.c ;
+
+ # Compute stray light calibration for i1pro
+ #Main i1stray : i1stray.c ;
+}
+
diff --git a/spectro/License.txt b/spectro/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/spectro/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/spectro/License2.txt b/spectro/License2.txt
new file mode 100644
index 0000000..05ca889
--- /dev/null
+++ b/spectro/License2.txt
@@ -0,0 +1,282 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
diff --git a/spectro/License3.txt b/spectro/License3.txt
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/spectro/License3.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/spectro/LzmaDec.c b/spectro/LzmaDec.c
new file mode 100644
index 0000000..8c1a148
--- /dev/null
+++ b/spectro/LzmaDec.c
@@ -0,0 +1,993 @@
+/* LzmaDec.c -- LZMA Decoder
+2010-12-15 : Igor Pavlov : Public domain */
+
+#include "LzmaDec.h"
+
+#include <string.h>
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_INIT_SIZE 5
+
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p); i = (i + i); A0; } else \
+ { UPDATE_1(p); i = (i + i) + 1; A1; }
+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
+
+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ i -= 0x40; }
+#endif
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/* First LZMA-symbol is always decoded.
+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
+Out:
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : Flush marker
+ = kMatchSpecLenStart + 2 : State Init Marker
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = p->probs;
+
+ unsigned state = p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
+ unsigned lc = p->prop.lc;
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = processedPos & pbMask;
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (checkDicSize != 0 || processedPos != 0)
+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+
+ if (state < kNumLitStates)
+ {
+ state -= (state < 4) ? state : 3;
+ symbol = 1;
+ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ state -= (state < 10) ? 3 : 6;
+ symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ dic[dicPos++] = (Byte)symbol;
+ processedPos++;
+ continue;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob);
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob);
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = (1 << kLenNumMidBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance);
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ int numDirectBits = (int)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos + distance - posSlot - 1;
+ {
+ UInt32 mask = 1;
+ unsigned i = 1;
+ do
+ {
+ GET_BIT2(prob + i, i, ; , distance |= mask);
+ mask <<= 1;
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ GET_BIT2(prob + i, i, ; , distance |= 1);
+ GET_BIT2(prob + i, i, ; , distance |= 2);
+ GET_BIT2(prob + i, i, ; , distance |= 4);
+ GET_BIT2(prob + i, i, ; , distance |= 8);
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len += kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ if (checkDicSize == 0)
+ {
+ if (distance >= processedPos)
+ return SZ_ERROR_DATA;
+ }
+ else if (distance >= checkDicSize)
+ return SZ_ERROR_DATA;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ }
+
+ len += kMatchMinLen;
+
+ if (limit == dicPos)
+ return SZ_ERROR_DATA;
+ {
+ SizeT rem = limit - dicPos;
+ unsigned curLen = ((rem < len) ? (unsigned)rem : len);
+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (pos + curLen <= dicBufSize)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += curLen;
+ do
+ *(dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+ NORMALIZE;
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = len;
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = state;
+
+ return SZ_OK;
+}
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
+ {
+ Byte *dic = p->dic;
+ SizeT dicPos = p->dicPos;
+ SizeT dicBufSize = p->dicBufSize;
+ unsigned len = p->remainLen;
+ UInt32 rep0 = p->reps[0];
+ if (limit - dicPos < len)
+ len = (unsigned)(limit - dicPos);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len != 0)
+ {
+ len--;
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ do
+ {
+ SizeT limit2 = limit;
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit2 = p->dicPos + rem;
+ }
+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
+ if (p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ p->remainLen = kMatchSpecLenStart;
+ }
+ return 0;
+}
+
+typedef enum
+{
+ DUMMY_ERROR, /* unexpected end of input stream */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = buf + inSize;
+ CLzmaProb *probs = p->probs;
+ unsigned state = p->state;
+ ELzmaDummy res;
+
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += (LZMA_LIT_SIZE *
+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK;
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ NORMALIZE_CHECK;
+ return DUMMY_REP;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumMidBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ do
+ {
+ GET_BIT_CHECK(prob + i, i);
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+
+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
+{
+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->needFlush = 1;
+ p->remainLen = 0;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->needInitState = 1;
+ }
+ if (initState)
+ p->needInitState = 1;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+static void LzmaDec_InitStateReal(CLzmaDec *p)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
+ UInt32 i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ p->needInitState = 0;
+}
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ LzmaDec_WriteRem(p, dicLimit);
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int checkEndMarkNow;
+
+ if (p->needFlush != 0)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitRc(p, p->tempBuf);
+ p->tempBufSize = 0;
+ }
+
+ checkEndMarkNow = 0;
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ checkEndMarkNow = 1;
+ }
+
+ if (p->needInitState)
+ LzmaDec_InitStateReal(p);
+
+ if (p->tempBufSize == 0)
+ {
+ SizeT processed;
+ const Byte *bufLimit;
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, src, inSize);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ memcpy(p->tempBuf, src, inSize);
+ p->tempBufSize = (unsigned)inSize;
+ (*srcLen) += inSize;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ bufLimit = src;
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+ p->buf = src;
+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
+ return SZ_ERROR_DATA;
+ processed = (SizeT)(p->buf - src);
+ (*srcLen) += processed;
+ src += processed;
+ inSize -= processed;
+ }
+ else
+ {
+ unsigned rem = p->tempBufSize, lookAhead = 0;
+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
+ p->tempBuf[rem++] = src[lookAhead++];
+ p->tempBufSize = rem;
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ (*srcLen) += lookAhead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ }
+ p->buf = p->tempBuf;
+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
+ return SZ_ERROR_DATA;
+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+ if (p->code == 0)
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+}
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->probs);
+ p->probs = 0;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->dic);
+ p->dic = 0;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = d % 9;
+ d /= 9;
+ p->pb = d / 5;
+ p->lp = d % 5;
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (p->probs == 0 || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ p->numProbs = numProbs;
+ if (p->probs == 0)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ dicBufSize = propNew.dicSize;
+ if (p->dic == 0 || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+ if (p->dic == 0)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+ LzmaDec_Construct(&p);
+ RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc));
+ p.dic = dest;
+ p.dicBufSize = outSize;
+ LzmaDec_Init(&p);
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+ *destLen = p.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/spectro/LzmaDec.h b/spectro/LzmaDec.h
new file mode 100644
index 0000000..6045fae
--- /dev/null
+++ b/spectro/LzmaDec.h
@@ -0,0 +1,231 @@
+/* LzmaDec.h -- LZMA Decoder
+2009-02-07 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_DEC_H
+#define __LZMA_DEC_H
+
+#include "LzmaTypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ unsigned lc, lp, pb;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ Byte *dic;
+ const Byte *buf;
+ UInt32 range, code;
+ SizeT dicPos;
+ SizeT dicBufSize;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ unsigned state;
+ UInt32 reps[4];
+ unsigned remainLen;
+ int needFlush;
+ int needInitState;
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Constr()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/spectro/LzmaTypes.h b/spectro/LzmaTypes.h
new file mode 100644
index 0000000..7732c24
--- /dev/null
+++ b/spectro/LzmaTypes.h
@@ -0,0 +1,254 @@
+/* Types.h -- Basic types
+2010-10-09 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#include <stddef.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+#ifdef _WIN32
+typedef DWORD WRes;
+#else
+typedef int WRes;
+#endif
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#define UINT64_CONST(n) n
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#define UINT64_CONST(n) n ## ULL
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+
+#ifdef _WIN32
+#define MY_STD_CALL __stdcall
+#else
+#define MY_STD_CALL
+#endif
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else
+
+#define MY_CDECL
+#define MY_FAST_CALL
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
+} IByteIn;
+
+typedef struct
+{
+ void (*Write)(void *p, Byte b);
+} IByteOut;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+} ISeqInStream;
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
+
+typedef struct
+{
+ size_t (*Write)(void *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+} ISeqOutStream;
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ISeekInStream;
+
+typedef struct
+{
+ SRes (*Look)(void *p, const void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(void *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ILookInStream;
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
+
+#define LookToRead_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ ILookInStream s;
+ ISeekInStream *realStream;
+ size_t pos;
+ size_t size;
+ Byte buf[LookToRead_BUF_SIZE];
+} CLookToRead;
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
+void LookToRead_Init(CLookToRead *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+typedef struct
+{
+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+} ICompressProgress;
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
+#define IAlloc_Free(p, a) (p)->Free((p), a)
+
+#ifdef _WIN32
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/spectro/Makefile.OSX b/spectro/Makefile.OSX
new file mode 100644
index 0000000..f98d078
--- /dev/null
+++ b/spectro/Makefile.OSX
@@ -0,0 +1,44 @@
+# MAC OSX, derived from UNIX setup
+
+# 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.
+
+SLASH = /
+SUFLIB = .a
+SUFOBJ = .o
+SUFEXE =
+CMDSEP = ;
+
+INCFLAG = -I
+DEFFLAG = -D
+UNDEFFLAG = -U
+CCOPTFLAG = -O
+CCDEBUGFLAG = -g
+CCPROFFLAG =
+LINKDEBUGFLAG =
+LINKPROFFLAG =
+
+STDHDRSDEF = /usr/include
+
+MAKEU = make
+LIBU = ar -r
+LIBOF =
+RANLIB = ranlib
+AS = as
+CCFLAGSDEF = -DUNIX -c
+CC = cc $(CCFLAGS) $(STDHDRS)
+CCOF = -o
+LINKFLAGSDEF = -lm -framework Carbon -framework IOKit -framework CoreFoundation -framework AudioToolbox
+LINKLIBS =
+LINK = cc $(LINKFLAGS) $(LINKLIBS)
+LINKOF = -o
+CP = cp
+RM = rm
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/spectro/Makefile.SA b/spectro/Makefile.SA
new file mode 100644
index 0000000..4d253ec
--- /dev/null
+++ b/spectro/Makefile.SA
@@ -0,0 +1,183 @@
+
+# Boilerplate Makefile for compiling standalone instrumement driver
+
+# 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.
+
+# "include" the right environment for your system,
+# by uncommenting the appropriate line:
+
+# Microsoft VC++, WinNT setup
+include Makefile.WNT
+
+# Generic UNIX setup
+#include Makefile.UNIX
+
+# Apple OS X
+#include Makefile.OSX
+
+###############################
+
+
+CCDEFINES = $(DEFFLAG)SALONEINSTLIB $(DEFFLAG)ENABLE_SERIAL $(DEFFLAG)ENABLE_USB $(DEFFLAG)NATIVE_USB
+
+#Set optimisation on
+CCFLAGS = $(CCFLAGSDEF) $(CCOPTFLAG) $(CCDEFINES) $(BCONFIG)
+
+# Set debugging on
+#CCFLAGS = $(CCFLAGSDEF) $(CCDEBUGFLAG) $(CCDEFINES) $(BCONFIG)
+# Debugging and debugging #define
+#CCFLAGS = $(CCFLAGSDEF) $(CCDEBUGFLAG) $(CCDEFINES) $(DEFFLAG)DEBUG
+
+LINKFLAGS = $(LINKFLAGSDEF) $(LINKDEBUGFLAG)
+
+# Where headers come from
+STDHDRS = $(INCFLAG)$(STDHDRSDEF)
+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 spyd2setup.h spyd2PLD.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)
+
+HEADERS = pollem.h conv.h aglob.h hidio.h icoms.h inst.c inst.h insttypeinst.h insttypes.h $(INSTHEADERS) usbio.h xspect.h rspl1.h sort.h xdg_bds.h ccss.h ccmx.h pars.h cgats.h instappsup.h usb$(SLASH)driver$(SLASH)driver_api.h
+
+# libinst objects
+OBJS = conv$(SUFOBJ) aglob$(SUFOBJ) inst$(SUFOBJ) numsup$(SUFOBJ) rspl1$(SUFOBJ) icoms$(SUFOBJ) usbio$(SUFOBJ) hidio$(SUFOBJ) insttypes$(SUFOBJ) pollem$(SUFOBJ) xspect$(SUFOBJ) xdg_bds$(SUFOBJ) ccss$(SUFOBJ) ccmx$(SUFOBJ) pars$(SUFOBJ) cgats$(SUFOBJ) $(INSOBJS)
+
+
+# instrument library
+
+conv$(SUFOBJ): conv.c $(HEADERS)
+ $(CC) conv.c
+
+aglob$(SUFOBJ): aglob.c $(HEADERS)
+ $(CC) aglob.c
+
+inst$(SUFOBJ): inst.c $(HEADERS)
+ $(CC) inst.c
+
+numsup$(SUFOBJ): numsup.c $(HEADERS)
+ $(CC) numsup.c
+
+rspl1$(SUFOBJ): rspl1.c $(HEADERS)
+ $(CC) rspl1.c
+
+icoms$(SUFOBJ): icoms.c $(HEADERS)
+ $(CC) icoms.c
+
+usbio$(SUFOBJ): usbio.c $(HEADERS)
+ $(CC) usbio.c
+
+hidio$(SUFOBJ): hidio.c $(HEADERS)
+ $(CC) hidio.c
+
+insttypes$(SUFOBJ): insttypes.c $(HEADERS)
+ $(CC) insttypes.c
+
+pollem$(SUFOBJ): pollem.c $(HEADERS)
+ $(CC) pollem.c
+
+xspect$(SUFOBJ): xspect.c $(HEADERS)
+ $(CC) xspect.c
+
+pars$(SUFOBJ): pars.c parsstd.c $(HEADERS)
+ $(CC) pars.c
+
+cgats$(SUFOBJ): cgats.c cgatsstd.c $(HEADERS)
+ $(CC) cgats.c
+
+dtp20$(SUFOBJ): dtp20.c $(HEADERS)
+ $(CC) dtp20.c
+
+dtp22$(SUFOBJ): dtp22.c $(HEADERS)
+ $(CC) dtp22.c
+
+dtp41$(SUFOBJ): dtp41.c $(HEADERS)
+ $(CC) dtp41.c
+
+dtp51$(SUFOBJ): dtp51.c $(HEADERS)
+ $(CC) dtp51.c
+
+dtp92$(SUFOBJ): dtp92.c $(HEADERS)
+ $(CC) dtp92.c
+
+ss$(SUFOBJ): ss.c $(HEADERS)
+ $(CC) ss.c
+
+ss_imp$(SUFOBJ): ss_imp.c $(HEADERS)
+ $(CC) ss_imp.c
+
+i1disp$(SUFOBJ): i1disp.c $(HEADERS)
+ $(CC) i1disp.c
+
+i1d3$(SUFOBJ): i1d3.c $(HEADERS)
+ $(CC) i1d3.c
+
+i1pro$(SUFOBJ): i1pro.c $(HEADERS)
+ $(CC) i1pro.c
+
+i1pro_imp$(SUFOBJ): i1pro_imp.c $(HEADERS)
+ $(CC) i1pro_imp.c
+
+munki$(SUFOBJ): munki.c $(HEADERS)
+ $(CC) munki.c
+
+munki_imp$(SUFOBJ): munki_imp.c $(HEADERS)
+ $(CC) munki_imp.c
+
+hcfr$(SUFOBJ): hcfr.c $(HEADERS)
+ $(CC) hcfr.c
+
+huey$(SUFOBJ): huey.c $(HEADERS)
+ $(CC) huey.c
+
+colorhug$(SUFOBJ): colorhug.c $(HEADERS)
+ $(CC) colorhug.c
+
+spyd2$(SUFOBJ): spyd2.c $(HEADERS)
+ $(CC) spyd2.c
+
+oemarch$(SUFOBJ): oemarch.c $(HEADERS)
+ $(CC) oemarch.c
+
+oeminst$(SUFOBJ): oeminst.c $(HEADERS)
+ $(CC) oeminst.c
+
+vinflate$(SUFOBJ): vinflate.c $(HEADERS)
+ $(CC) vinflate.c
+
+inflate$(SUFOBJ): inflate.c $(HEADERS)
+ $(CC) inflate.c
+
+LzmaDec$(SUFOBJ): LzmaDec.c LzmaDec.h LzmaTypes.h $(HEADERS)
+ $(CC) LzmaDec.c
+
+libinst$(SUFLIB): $(OBJS)
+ $(LIBU) $(LIBOF)$@ $(OBJS)
+ $(RANLIB) libinst$(SUFLIB)
+
+# instappsup objects
+SUPOBJS = instappsup$(SUFOBJ)
+
+# instappsup library
+
+instappsup$(SUFOBJ): instappsup.c $(HEADERS)
+ $(CC) instappsup.c
+
+libinstappsup$(SUFLIB): $(SUPOBJS)
+ $(LIBU) $(LIBOF)$@ $(SUPOBJS)
+ $(RANLIB) instappsup$(SUFLIB)
+
+# test/example code
+
+spotread$(SUFEXE): spotread$(SUFOBJ) libinst$(SUFLIB) inst.h
+ $(LINK) $(LINKOF)spotread$(SUFEXE) spotread$(SUFOBJ) libinst$(SUFLIB) libinstappsup$(SUFLIB) $(LINKLIBS)
+
+oeminst$(SUFEXE): oeminst$(SUFOBJ) oemarch$(SUFOBJ) inflate$(SUFOBJ) vinflate$(SUFOBJ) LzmaDec$(SUFOBJ) libinst$(SUFLIB) libinstappsup$(SUFLIB)
+ $(LINK) $(LINKOF)oeminst$(SUFEXE) oeminst$(SUFOBJ) oemarch$(SUFOBJ) inflate$(SUFOBJ) vinflate$(SUFOBJ) LzmaDec$(SUFOBJ) libinst$(SUFLIB) libinstappsup$(SUFLIB) $(LINKLIBS)
+
+clean:
+ $(RM) *$(SUFOBJ) *$(SUFLIB) spotread$(SUFEXE) i1d3css$(SUFEXE)
+
diff --git a/spectro/Makefile.UNIX b/spectro/Makefile.UNIX
new file mode 100644
index 0000000..5eaf6b5
--- /dev/null
+++ b/spectro/Makefile.UNIX
@@ -0,0 +1,44 @@
+# Generic UNIX setup
+
+# 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.
+
+SLASH = /
+SUFLIB = .a
+SUFOBJ = .o
+SUFEXE =
+CMDSEP = ;
+
+INCFLAG = -I
+DEFFLAG = -D
+UNDEFFLAG = -U
+CCOPTFLAG = -O
+CCDEBUGFLAG = -g
+CCPROFFLAG =
+LINKDEBUGFLAG =
+LINKPROFFLAG =
+
+STDHDRSDEF = /usr/include
+
+MAKEU = make
+LIBU = ar -r
+LIBOF =
+RANLIB = echo
+AS = as
+CCFLAGSDEF = -DUNIX -DNATIVE_USB -c
+CC = cc $(CCFLAGS) $(STDHDRS)
+CCOF = -o
+LINKFLAGSDEF = -lm -lpthread -lrt
+LINKLIBS =
+LINK = cc $(LINKFLAGS) $(LINKLIBS)
+LINKOF = -o
+CP = cp
+RM = rm
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/spectro/Makefile.WNT b/spectro/Makefile.WNT
new file mode 100644
index 0000000..83eef28
--- /dev/null
+++ b/spectro/Makefile.WNT
@@ -0,0 +1,47 @@
+# Microsoft VC++, WinNT setup
+
+# 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.
+
+SLASH = \
+SUFLIB = .lib
+SUFOBJ = .obj
+SUFEXE = .exe
+CMDSEP = &
+
+INCFLAG = /I
+DEFFLAG = /D
+UNDEFFLAG = /U
+CCOPTFLAG = /Ox
+CCDEBUGFLAG = /Z7 /Od
+CCPROFFLAG = /Z7
+LINKDEBUGFLAG = /DEBUG
+LINKPROFFLAG = /PROFILE
+
+STDHDRSDEF = $(VCINSTALLDIR)\include
+LINKDIR = $(MSSDK)
+
+MAKEU = nmake
+LIBU = lib
+LIBOF = /OUT:
+RANLIB = rem
+AS = masm386
+# DLL build by default
+# /Wall /wd4820 /wd4100 /wd4255 /wd4711 /wd4668 /wd4018 /wd4389
+CCFLAGSDEF = /DNT /MD /c $(DEFFLAG)_CRT_SECURE_NO_DEPRECATE $(DEFFLAG)_CRT_NONSTDC_NO_DEPRECATE
+CC = cl /nologo $(CCFLAGS) $(STDHDRS) $(WIN_STDHDRS)
+CCOF = /Fo
+LINKLIBS = $(LINKDIR)\lib\user32.lib $(LINKDIR)\lib\gdi32.lib $(LINKDIR)\lib\advapi32.lib $(LINKDIR)\lib\setupapi.lib $(LINKDIR)\lib\ole32.lib
+LINKFLAGSDEF = /link /INCREMENTAL:NO
+LINK = link $(LINKFLAGS)
+LINKOF = /OUT:
+CP = copy
+RM = del
+
+.SUFFIXES:
+.SUFFIXES: .c $(SUFLIB) $(SUFOBJ) $(SUFEXE)
+
+.c$(SUFOBJ):
+ $(CC) $(CCOF)$*$(SUFOBJ) $<
+
diff --git a/spectro/Makefile.am b/spectro/Makefile.am
new file mode 100644
index 0000000..835336b
--- /dev/null
+++ b/spectro/Makefile.am
@@ -0,0 +1,53 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libinsttypes.la libconv.la libinst.la libinstapp.la libdisp.la
+privatelibdir = $(pkglibdir)
+
+libinsttypes_la_SOURCES = insttypes.h insttypes.c insttypeinst.h
+libinsttypes_la_LIBADD = ../libargyll.la
+
+libinst_la_SOURCES = inst.h inst.c insttypes.c dtp20.c dtp20.h dtp22.c \
+ dtp22.h dtp41.c dtp41.h dtp51.c dtp51.h dtp92.c dtp92.h \
+ i1disp.c i1disp.h i1pro.c i1pro.h i1pro_imp.c i1pro_imp.h \
+ munki.c munki_imp.c ss.c ss.h ss_imp.c ss_imp.h hcfr.c hcfr.h \
+ spyd2.c spyd2.h spyd2setup.h spyd2PLD.h huey.c huey.h \
+ usbio.c hidio.c pollem.c pollem.h icoms.h conv.h usbio.h \
+ hidio.h i1d3.h i1d3.c colorhug.c colorhug.h icoms.c \
+ oemarch.h oemarch.c iusb.h vinflate.c inflate.c
+libinst_la_LIBADD = $(ICC_LIBS) ../numlib/libargyllnum.la \
+ ../libargyll.la ../rspl/librspl.la libconv.la
+
+libinst_la_LDFLAGS = $(shell libusb-config --libs)
+
+libdisp_la_SOURCES = dispsup.c dispwin.c dispwin.h dispsup.h webwin.c webwin.h mongoose.c mongoose.h
+libdisp_la_LIBADD = $(X_LIBS) ../ucmm/libucmm.la $(ICC_LIBS) -ldl \
+ ../numlib/libargyllnum.la libconv.la libinst.la libinstapp.la \
+ ../libargyll.la
+
+libconv_la_SOURCES = conv.c pollem.c xdg_bds.h xdg_bds.c aglob.c ../xicc/ccss.c
+libconv_la_LIBADD = ../libargyll.la ../numlib/libargyllnum.la \
+ ../cgats/libcgats.la
+
+libinstapp_la_SOURCES = instappsup.c instappsup.h
+libinstapp_la_LIBADD = libinst.la ../libargyll.la ../numlib/libargyllnum.la \
+ libconv.la
+
+LDADD = ./libinsttypes.la ./libinstapp.la ./libdisp.la ./libinst.la \
+ ./libconv.la ../ucmm/libucmm.la ../jcnf/libjcnf.la $(YAJL_LIBS) \
+ ../xicc/libxicc.la $(ICC_LIBS) ../cgats/libcgats.la \
+ ../rspl/librspl.la ../gamut/libgamut.la ../target/libtarget.la \
+ ../plot/libplot.la ../numlib/libargyllnum.la $(X_LIBS) \
+ ../libargyll.la
+
+bin_PROGRAMS = dispwin synthcal dispread dispcal fakeread synthread \
+ chartread spotread illumread ccxxmake spec2cie average oeminst
+
+dispwin_CFLAGS = $(AM_CFLAGS) -DSTANDALONE_TEST
+
+synthcal_DEPENDENCIES = ../gamut/libgammap.la ../target/libtarget.la
+
+refdir = $(datadir)/color/argyll/ref
+
+ref_DATA = ccxx.ti1 SOtele.sp $(wildcard *.cal)
+
+EXTRA_DIST = Readme.txt
diff --git a/spectro/Readme.txt b/spectro/Readme.txt
new file mode 100644
index 0000000..b9fe0aa
--- /dev/null
+++ b/spectro/Readme.txt
@@ -0,0 +1,37 @@
+This directory containts the routines to operate a variety
+of color instruments.
+
+If you make use of the instrument driver code here, please note
+that it is the author(s) of the code who take responsibility
+for its operation. Any problems or queries regarding driving
+instruments with the Argyll drivers, should be directed to
+the Argyll's author(s), and not to any other party.
+
+If there is some instrument feature or function that you
+would like supported here, it is recommended that you
+contact Argyll's author(s) first, rather than attempt to
+modify the software yourself, if you don't have firm knowledge
+of the instrument communicate protocols. There is a chance
+that an instrument could be damaged by an incautious command
+sequence, and the instrument companies generally cannot and
+will not support developers that they have not qualified
+and agreed to support.
+
+
+chartread.exe Is used to read the test chart and create
+ the chart readings file.
+
+filmread.exe Is used to read the film test chart and create
+ the chart readings file.
+
+dispcal.exe Calibrate a display
+
+dispread.exe Read test chart values for a display
+
+fakeread.exe Fake reading of a device, using a profile instead.
+
+spec2cie.exe Convert a spectral reading file into a CIE tristimulus file.
+
+spotread.exe Read spot values.
+
+instlib.txt Explanation of how to extract and build a standalone instrument library.
diff --git a/spectro/SOtele.sp b/spectro/SOtele.sp
new file mode 100644
index 0000000..f63d90e
--- /dev/null
+++ b/spectro/SOtele.sp
@@ -0,0 +1,23 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectrolino tele adapter compensation filter"
+ORIGINATOR "Argyll CMS"
+CREATED "Wed Jun 21 17:49:57 2006"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "36"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "380.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "730.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "1.000000"
+
+NUMBER_OF_FIELDS 36
+BEGIN_DATA_FORMAT
+SPEC_380 SPEC_390 SPEC_400 SPEC_410 SPEC_420 SPEC_430 SPEC_440 SPEC_450 SPEC_460 SPEC_470 SPEC_480 SPEC_490 SPEC_500 SPEC_510 SPEC_520 SPEC_530 SPEC_540 SPEC_550 SPEC_560 SPEC_570 SPEC_580 SPEC_590 SPEC_600 SPEC_610 SPEC_620 SPEC_630 SPEC_640 SPEC_650 SPEC_660 SPEC_670 SPEC_680 SPEC_690 SPEC_700 SPEC_710 SPEC_720 SPEC_730
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+1.7378 1.3294 1.1691 1.1313 1.1326 1.1301 1.1302 1.1290 1.1288 1.1274 1.1286 1.1280 1.1273 1.1263 1.1242 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231 1.1231
+END_DATA
diff --git a/spectro/afiles b/spectro/afiles
new file mode 100644
index 0000000..045614c
--- /dev/null
+++ b/spectro/afiles
@@ -0,0 +1,110 @@
+Readme.txt
+instlib.txt
+instlib.ksh
+IntsLib_Readme.txt
+License.txt
+License2.txt
+License3.txt
+afiles
+ifiles
+Jamfile
+chartread.c
+dispread.c
+dispcal.c
+illumread.c
+ccxxmake.c
+dispsup.h
+dispsup.c
+webwin.h
+webwin.c
+mongoose.h
+mongoose.c
+insttypes.h
+insttypes.c
+insttypeinst.h
+inst.c
+inst.h
+instappsup.c
+instappsup.h
+dtp20.c
+dtp20.h
+dtp22.c
+dtp22.h
+dtp41.c
+dtp41.h
+dtp51.c
+dtp51.h
+dtp92.c
+dtp92.h
+ss.h
+ss.c
+ss_imp.h
+ss_imp.c
+i1disp.c
+i1disp.h
+i1d3.c
+i1d3.h
+i1pro.h
+i1pro.c
+i1pro_imp.h
+i1pro_imp.c
+munki.h
+munki.c
+munki_imp.h
+munki_imp.c
+hcfr.c
+hcfr.h
+spyd2.c
+spyd2.h
+spyd2setup.h
+spyd2PLD.h
+oemarch.h
+oemarch.c
+oeminst.c
+inflate.c
+vinflate.c
+LzmaTypes.h
+LzmaDec.h
+LzmaDec.c
+huey.c
+huey.h
+colorhug.c
+colorhug.h
+spec2cie.c
+average.c
+conv.h
+conv.c
+aglob.h
+aglob.c
+xdg_bds.h
+xdg_bds.c
+icoms.h
+icoms.c
+icoms_nt.c
+icoms_ux.c
+iusb.h
+usbio.h
+usbio.c
+usbio_lusb.c
+usbio_nt.c
+usbio_ox.c
+usbio_lx.c
+hidio.h
+hidio.c
+pollem.h
+pollem.c
+dispwin.c
+dispwin.h
+synthcal.c
+spotread.c
+fakeread.c
+synthread.c
+linear.sp
+SOtele.sp
+linear.cal
+strange.cal
+ccxx.ti1
+Makefile.SA
+Makefile.OSX
+Makefile.UNIX
+Makefile.WNT
diff --git a/spectro/aglob.c b/spectro/aglob.c
new file mode 100644
index 0000000..8d4c846
--- /dev/null
+++ b/spectro/aglob.c
@@ -0,0 +1,141 @@
+
+/* Provide a system independent glob type function */
+
+/*************************************************************************
+ Copyright 2011 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+#if defined (NT)
+# if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
+# if defined _WIN32_WINNT
+# undef _WIN32_WINNT
+# endif
+# define _WIN32_WINNT 0x0501
+# endif
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <io.h>
+#endif
+
+#if defined (UNIX)
+# include <unistd.h>
+# include <glob.h>
+# include <pthread.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+#include "numsup.h"
+#include "aglob.h"
+
+/* Create the aglob */
+/* Return nz on malloc error */
+int aglob_create(aglob *g, char *spath) {
+#ifdef NT
+ char *pp;
+ int rlen;
+ /* Figure out where the filename starts */
+ if ((pp = strrchr(spath, '/')) == NULL
+ && (pp = strrchr(spath, '\\')) == NULL)
+ rlen = 0;
+ else
+ rlen = pp - spath + 1;
+
+ if ((g->base = malloc(rlen + 1)) == NULL) {
+ a1loge(g_log, 1, "aglob_create: malloc failed\n");
+ return 1;
+ }
+
+ memmove(g->base, spath, rlen);
+ g->base[rlen] = '\000';
+
+ g->first = 1;
+ g->ff = _findfirst(spath, &g->ffs);
+#else /* UNIX */
+ memset(&g->g, 0, sizeof(g->g));
+ g->rv = glob(spath, GLOB_NOSORT, NULL, &g->g);
+//a1loge(g_log, 0, "~1 glob '%s' returns %d and gl_pathc = %d\n",spath,g->rv,g->g.gl_pathc);
+ if (g->rv == GLOB_NOSPACE) {
+ a1loge(g_log, 1, "aglob_create: glob returned GLOB_NOSPACE\n");
+ return 1;
+ }
+ g->ix = 0;
+#endif
+ g->merr = 0;
+ return 0;
+}
+
+/* Return an allocated string of the next match. */
+/* Return NULL if no more matches */
+char *aglob_next(aglob *g) {
+ char *fpath;
+
+#ifdef NT
+ if (g->ff == -1L) {
+ return NULL;
+ }
+ if (g->first == 0) {
+ if (_findnext(g->ff, &g->ffs) != 0) {
+ return NULL;
+ }
+ }
+ g->first = 0;
+
+ /* Convert match filename to full path */
+ if ((fpath = malloc(strlen(g->base) + strlen(g->ffs.name) + 1)) == NULL) {
+ a1loge(g_log, 1, "aglob_next: malloc failed\n");
+ g->merr = 1;
+ return NULL;
+ }
+ strcpy(fpath, g->base);
+ strcat(fpath, g->ffs.name);
+ return fpath;
+#else
+ if (g->rv != 0 || g->ix >= g->g.gl_pathc)
+ return NULL;
+ if ((fpath = strdup(g->g.gl_pathv[g->ix])) == NULL) {
+ a1loge(g_log, 1, "aglob_next: strdup failed\n");
+ g->merr = 1;
+ return NULL;
+ }
+ g->ix++;
+ return fpath;
+#endif
+}
+
+void aglob_cleanup(aglob *g) {
+#ifdef NT
+ if (g->ff != -1L)
+ _findclose(g->ff);
+ free(g->base);
+#else /* UNIX */
+ if (g->rv == 0)
+ globfree(&g->g);
+#endif
+}
+
diff --git a/spectro/aglob.h b/spectro/aglob.h
new file mode 100644
index 0000000..6c46746
--- /dev/null
+++ b/spectro/aglob.h
@@ -0,0 +1,63 @@
+#ifndef AGLOB_H
+
+/* Provide a system independent glob type function */
+
+/*************************************************************************
+ Copyright 2011 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef struct {
+#ifdef NT
+ char *base; /* Base path */
+ struct _finddata_t ffs;
+ long ff;
+ int first;
+#else /* UNIX */
+ glob_t g;
+ int rv; /* glob return value */
+ size_t ix;
+#endif
+ int merr; /* NZ on malloc error */
+} aglob;
+
+
+/* Create the aglob for files matching the given path and pattern. */
+/* Return nz on malloc error */
+int aglob_create(aglob *g, char *spath);
+
+/* Return an allocated string of the next match. */
+/* Return NULL if no more matches */
+char *aglob_next(aglob *g);
+
+/* Free the aglob once we're done with it */
+void aglob_cleanup(aglob *g);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define AGLOB_H
+#endif /* AGLOB_H */
diff --git a/spectro/average.c b/spectro/average.c
new file mode 100644
index 0000000..d031154
--- /dev/null
+++ b/spectro/average.c
@@ -0,0 +1,405 @@
+/*
+ * Argyll Color Correction System
+ * Average one or more .ti3 (or other CGATS like) file values together.
+ *
+ * Author: Graeme W. Gill
+ * Date: 18/1/2011
+ *
+ * Copyright 2005, 2010, 2011 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.
+ *
+ * (based on splitti3.c)
+ */
+
+/*
+ * TTBD:
+
+ Should probably re-index SAMPLE_ID field
+
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "insttypes.h"
+
+void usage(char *diag, ...) {
+ int i;
+ fprintf(stderr,"Average or merge values in .ti3 like files, Version %s\n",ARGYLL_VERSION_STR);
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: average [-options] input1.ti3 input2.ti3 ... output.ti3\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -m Merge rather than average\n");
+ fprintf(stderr," input1.ti3 First input file\n");
+ fprintf(stderr," input2.ti3 Second input file\n");
+ fprintf(stderr," ... etc.\n");
+ fprintf(stderr," output.ti3 Resulting averaged or merged output file\n");
+ exit(1);
+}
+
+/* Information about each file */
+struct _inpinfo {
+ char name[MAXNAMEL+1];
+ cgats *c;
+}; typedef struct _inpinfo inpinfo;
+
+int main(int argc, char *argv[]) {
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ int domerge = 0; /* Merge rather than average */
+
+ int ninps = 0; /* Number of input files */
+ inpinfo *inps; /* Input file info. inp[ninp] == output file */
+ cgats *ocg; /* Copy of output cgats * */
+
+ cgats_set_elem *setel; /* Array of set value elements */
+ int *flags; /* Point to destination of set */
+
+ int nchan; /* Number of device channels */
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ int pcsix[3]; /* PCS chanel indexes */
+ int isLab = 0;
+
+ int i, j, n;
+
+ error_program = "average";
+
+ if (argc <= 3)
+ usage("Too few arguments (%d, minimum is 2)",argc-1);
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ /* Merge */
+ else if (argv[fa][1] == 'm' || argv[fa][1] == 'M') {
+ domerge = 1;
+ }
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ else {
+ usage("Unknown flag '%c'",argv[fa][1]);
+ }
+
+ } else if (argv[fa][0] != '\000') {
+ /* Get the next filename */
+
+ if (ninps == 0)
+ inps = (inpinfo *)malloc(sizeof(inpinfo));
+ else
+ inps = (inpinfo *)realloc(inps, (ninps+1) * sizeof(inpinfo));
+ if (inps == NULL)
+ error("Malloc failed in allocating space for file info.");
+
+ memset((void *)&inps[ninps], 0, sizeof(inpinfo));
+ strncpy(inps[ninps].name,argv[fa],MAXNAMEL);
+ inps[ninps].name[MAXNAMEL] = '\000';
+
+ ninps++;
+ } else {
+ break;
+ }
+ }
+
+ if (ninps < 2)
+ error("Must be at least one input and one output file specified");
+
+ ninps--; /* Number of inputs */
+
+ /* Open and read each input file */
+ for (n = 0; n <= ninps; n++) {
+
+ if ((inps[n].c = new_cgats()) == NULL)
+ error("Failed to create cgats object for file '%s'",inps[n].name);
+
+ if (n < ninps) { /* If input file, read it */
+ inps[n].c->add_other(inps[n].c, ""); /* Allow any signature file */
+
+ if (inps[n].c->read_name(inps[n].c, inps[n].name))
+ error("CGATS file '%s' read error : %s",inps[n].name,inps[n].c->err);
+
+ if (inps[n].c->ntables < 1)
+ error ("Input file '%s' doesn't contain at least one table",inps[n].name);
+ }
+ }
+ ocg = inps[ninps].c; /* Alias for output file */
+
+ /* Duplicate everything from the first input file into the output file. */
+ for (n = 0; n < inps[0].c->ntables; n++) {
+
+ if (inps[0].c->t[n].tt == cgats_X) {
+ ocg->add_other(ocg, inps[0].c->cgats_type);
+ ocg->add_table(ocg, tt_other, 0);
+ } else if (inps[0].c->t[n].tt == tt_other) {
+ int oi;
+ oi = ocg->add_other(ocg, inps[0].c->others[inps[0].c->t[n].oi]);
+ ocg->add_table(ocg, tt_other, oi);
+ } else {
+ ocg->add_table(ocg, inps[0].c->t[n].tt, 0);
+ }
+
+ /* Duplicate all the keywords */
+ for (i = 0; i < inps[0].c->t[n].nkwords; i++) {
+//printf("~1 table %d, adding keyword '%s'\n",n,inps[0].c->t[n].ksym[i]);
+ ocg->add_kword(ocg, n, inps[0].c->t[n].ksym[i], inps[0].c->t[n].kdata[i], NULL);
+ }
+
+ /* Duplicate all of the fields */
+ for (i = 0; i < inps[0].c->t[n].nfields; i++) {
+ ocg->add_field(ocg, n, inps[0].c->t[n].fsym[i], inps[0].c->t[n].ftype[i]);
+ }
+
+ /* Duplicate all of the data */
+ if ((setel = (cgats_set_elem *)malloc(
+ sizeof(cgats_set_elem) * inps[0].c->t[n].nfields)) == NULL)
+ error("Malloc failed!");
+
+ for (i = 0; i < inps[0].c->t[n].nsets; i++) {
+ inps[0].c->get_setarr(inps[0].c, n, i, setel);
+ ocg->add_setarr(ocg, n, setel);
+ }
+ free(setel);
+ }
+
+ /* Figure out the indexes of the device channels */
+ {
+ int ti;
+ char *buf;
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+ char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
+ char *outc;
+ int nmask;
+ char *bident;
+
+ if ((ti = inps[0].c->find_kword(inps[0].c, 0, "COLOR_REP")) < 0)
+ error("Input file '%s' doesn't contain keyword COLOR_REP", inps[0].name);
+
+ if ((buf = strdup(inps[0].c->t[0].kdata[ti])) == NULL)
+ error("Malloc failed");
+
+ /* Split COLOR_REP into device and PCS space */
+ if ((outc = strchr(buf, '_')) == NULL)
+ error("COLOR_REP '%s' invalid", inps[0].c->t[0].kdata[ti]);
+ *outc++ = '\000';
+
+ if (strcmp(outc, "XYZ") == 0) {
+ isLab = 0;
+ } else if (strcmp(outc, "LAB") == 0) {
+ isLab = 1;
+ } else
+ error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", inps[0].c->t[0].kdata[ti]);
+
+ if ((nmask = icx_char2inkmask(buf)) == 0) {
+ error ("File '%s' keyword COLOR_REP has unknown device value '%s'",inps[0].name,buf);
+ }
+
+ nchan = icx_noofinks(nmask);
+ bident = icx_inkmask2char(nmask, 0);
+
+ /* Find device fields */
+ for (j = 0; j < nchan; j++) {
+ int ii, imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = inps[0].c->find_field(inps[0].c, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (inps[0].c->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+ chix[j] = ii;
+ }
+
+ /* Find PCS fields */
+ for (j = 0; j < 3; j++) {
+ int ii;
+
+ if ((ii = inps[0].c->find_field(inps[0].c, 0, isLab ? labfname[j] : xyzfname[j])) < 0)
+ error ("Input file doesn't contain field %s",isLab ? labfname[j] : xyzfname[j]);
+ if (inps[0].c->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",isLab ? labfname[j] : xyzfname[j]);
+ pcsix[j] = ii;
+ }
+ free(bident);
+ }
+
+ if (!domerge && verb) {
+ printf("Averaging the following fields:");
+ for (j = 0; j < inps[0].c->t[0].nfields; j++) {
+ int jj;
+
+ /* Only real types */
+ if (inps[0].c->t[0].ftype[j] != r_t) {
+ continue;
+ }
+
+ /* Not device channels */
+ for (jj = 0; jj < nchan; jj++) {
+ if (chix[jj] == j)
+ break;
+ }
+ if (jj < nchan) {
+ continue;
+ }
+
+ printf(" %s",inps[0].c->t[0].fsym[j]);
+ }
+ printf("\n");
+ }
+
+ /* Get ready to add more values to output */
+ if ((setel = (cgats_set_elem *)malloc(
+ sizeof(cgats_set_elem) * inps[0].c->t[0].nfields)) == NULL)
+ error("Malloc failed!");
+
+ /* Process all the other input files */
+ for (n = 1; n < ninps; n++) {
+
+ /* Check all the fields match */
+ if (inps[0].c->t[0].nfields != inps[n].c->t[0].nfields)
+ error ("File '%s' has %d fields, file '%s has %d",
+ inps[n].name, inps[n].c->t[0].nfields, inps[0].name, inps[0].c->t[0].nfields);
+ for (j = 0; j < inps[0].c->t[0].nfields; j++) {
+ if (inps[0].c->t[0].ftype[j] != inps[n].c->t[0].ftype[j])
+ error ("File '%s' field no. %d named '%s' doesn't match file '%s' field '%s'",
+ inps[n].name, j, inps[n].c->t[0].fsym[j], inps[0].name, inps[0].c->t[0].fsym[j]);
+ }
+
+ /* If merging, append all the values */
+ if (domerge) {
+ for (i = 0; i < inps[n].c->t[0].nsets; i++) {
+ inps[n].c->get_setarr(inps[0].c, 0, i, setel);
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ } else { /* Averaging */
+ /* Check the number of values matches */
+ if (inps[0].c->t[0].nsets != inps[n].c->t[0].nsets)
+ error ("File '%s' has %d sets, file '%s has %d",
+ inps[n].name, inps[n].c->t[0].nsets, inps[0].name, inps[0].c->t[0].nsets);
+
+ /* Add the numeric field values to corresponding output */
+ for (i = 0; i < inps[n].c->t[0].nsets; i++) {
+
+ /* Check that the device values match */
+ for (j = 0; j < nchan; j++) {
+ double diff;
+ diff = *((double *)inps[0].c->t[0].fdata[i][chix[j]])
+ - *((double *)inps[n].c->t[0].fdata[i][chix[j]]);
+
+ if (diff > 0.001)
+ error ("File '%s' set %d has field '%s' value that differs from '%s'",
+ inps[n].name, i+1, inps[n].c->t[0].fsym[j], inps[0].name);
+ }
+
+ /* Add all the non-device real field values */
+ for (j = 0; j < inps[0].c->t[0].nfields; j++) {
+ int jj;
+
+ /* Only real types */
+ if (inps[0].c->t[0].ftype[j] != r_t)
+ continue;
+
+ /* Not device channels */
+ for (jj = 0; jj < nchan; jj++) {
+ if (chix[jj] == j)
+ break;
+ }
+ if (jj < nchan)
+ continue;
+
+ *((double *)ocg->t[0].fdata[i][j])
+ += *((double *)inps[n].c->t[0].fdata[i][j]);
+ }
+ }
+ }
+ }
+
+ /* If averaging, divide out the number of files */
+ if (!domerge) {
+
+ for (i = 0; i < inps[n].c->t[0].nsets; i++) {
+
+ for (j = 0; j < inps[0].c->t[0].nfields; j++) {
+ int jj;
+
+ /* Only real types */
+ if (inps[0].c->t[0].ftype[j] != r_t)
+ continue;
+
+ /* Not device channels */
+ for (jj = 0; jj < nchan; jj++) {
+ if (chix[jj] == j)
+ break;
+ }
+ if (jj < nchan)
+ continue;
+
+ *((double *)ocg->t[0].fdata[i][j]) /= (double)ninps;
+ }
+ }
+ }
+
+ /* Write out the output and free the cgats * */
+ for (n = 0; n <= ninps; n++) {
+
+ if (n >= ninps) { /* If ouput file, write it */
+ if (inps[n].c->write_name(inps[n].c, inps[ninps].name))
+ error("CGATS file '%s' write error : %s",inps[n].name,inps[n].c->err);
+ }
+ inps[n].c->del(inps[n].c);
+ }
+
+ free(setel);
+ free(inps);
+
+ return 0;
+}
+
+
+
+
+
diff --git a/spectro/ccxx.ti1 b/spectro/ccxx.ti1
new file mode 100644
index 0000000..47f2b13
--- /dev/null
+++ b/spectro/ccxx.ti1
@@ -0,0 +1,22 @@
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1 for creating .ti3 for ccxxmake"
+ORIGINATOR "Argyll targen"
+CREATED "Thu Apr 19 13:24:37 2012"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "95.045781 100.000003 108.905751"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+
+NUMBER_OF_FIELDS 7
+BEGIN_DATA_FORMAT
+SAMPLE_ID RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 4
+BEGIN_DATA
+1 100.00 100.00 100.00 95.046 100.00 108.91
+2 100.00 0.0000 0.0000 41.238 21.260 1.9306
+3 0.0000 100.00 0.0000 35.757 71.520 11.921
+4 0.0000 0.0000 100.00 18.050 7.2205 95.055
+END_DATA
diff --git a/spectro/ccxxmake.c b/spectro/ccxxmake.c
new file mode 100644
index 0000000..737600c
--- /dev/null
+++ b/spectro/ccxxmake.c
@@ -0,0 +1,1446 @@
+
+/* Colorimeter Correction Matrix and */
+/* Colorimeter Calibration Spectral Sample creation utility */
+
+/*
+ * Argyll Color Correction System
+ * Author: Graeme W. Gill
+ * Date: 19/8/2010
+ *
+ * Copyright 2010, 2011, 2013 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.
+ */
+
+/* This program uses display measurements from a colorimeter and */
+/* a spectrometer to create a correction matrix for a particular */
+/* colorimeter/display combination,. */
+/* or */
+/* It uses display measurements from a spectrometer to create */
+/* calibration samples that can be used with a Colorimeter that */
+/* knowns its own spectral sensitivity curves (ie. X-Rite i1d3, Spyder 4). */
+
+/* Based on spotread.c, illumread.c, dispcal.c */
+
+/*
+ TTBD:
+
+ Should add an option to set a UI_SELECTORS value.
+
+ If any spectrometer gets a display type function (ie. refresh/non-refresh)
+ then it becomes difficult to know what to do with the -y option :-
+
+ * Ignore the problem - don't set -y option on spectrometers.
+ Error shouldn't be significant for ref/nonref ?
+
+ * Force the colorimeter to go first, record the ref/nonref state and
+ set in the spectrometer ? Make .ti3 file order the same for consistency ?
+
+ Would be nice to have a veryify option that produces
+ a fit report of a matrix vs. the input files.
+
+ Would be nice to have the option of procssing a Spyder 3 correction.txt file.
+ (See post from umberto.guidali@tiscali.it)
+
+ Would be nice to be able to use an i1D3 to correct other instruments,
+ or an i1D3 created .ti3 as the reference.
+
+ Would be nice to have an option of providing two ICC profiles,
+ instead of using .ti3 files (?? How well would it work though ?)
+ */
+
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include <stdarg.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "inst.h"
+#include "dispwin.h"
+#include "webwin.h"
+#include "dispsup.h"
+#include "ccss.h"
+#include "ccmx.h"
+#include "instappsup.h"
+#include "spyd2setup.h"
+
+#if defined (NT)
+#include <conio.h>
+#endif
+
+#define DEFAULT_MSTEPS 1
+#undef SHOW_WINDOW_ONFAKE /* Display a test window up for a fake device */
+#define COMPORT 1 /* Default com port 1..4 */
+
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+/* Workaround for a ppc gcc 3.3 optimiser bug... */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+/* Invoke with -dfake for testing with a fake device. */
+/* Invoke with -dFAKE for automatic creation of test matrix. */
+/* Will use a fake.icm/.icc profile if present, or a built in fake */
+/* device behaviour if not. */
+
+void
+usage(char *diag, ...) {
+ disppath **dp;
+ icompaths *icmps = new_icompaths(0);
+ inst2_capability cap = 0;
+
+ fprintf(stderr,"Create CCMX or CCSS, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (setup_spyd2() == 2)
+ fprintf(stderr,"WARNING: This file contains a proprietary firmware image, and may not be freely distributed !\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: ccmxmake [-options] output.ccmx\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -S Create CCSS rather than CCMX\n");
+ fprintf(stderr," -f file1.ti3[,file2.ti3] Create from one or two .ti3 files rather than measure.\n");
+#if defined(UNIX_X11)
+ fprintf(stderr," -display displayname Choose X11 display name\n");
+ fprintf(stderr," -d n[,m] Choose the display n from the following list (default 1)\n");
+ fprintf(stderr," Optionally choose different display m for VideoLUT access\n");
+#else
+ fprintf(stderr," -d n Choose the display from the following list (default 1)\n");
+#endif
+ dp = get_displays();
+ if (dp == NULL || dp[0] == NULL)
+ fprintf(stderr," ** No displays found **\n");
+ else {
+ int i;
+ for (i = 0; ; i++) {
+ if (dp[i] == NULL)
+ break;
+ fprintf(stderr," %d name = '%s'\n",i+1,dp[i]->name);
+ fprintf(stderr," %d = '%s'\n",i+1,dp[i]->description);
+ }
+ }
+ free_disppaths(dp);
+ fprintf(stderr," -dweb[:port] Display via a web server at port (default 8080)\n");
+// fprintf(stderr," -d fake Use a fake 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");
+ cap = inst_show_disptype_options(stderr, " -y c|l ", icmps, 1);
+ 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");
+ fprintf(stderr," ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.\n");
+ fprintf(stderr," -F Fill whole screen with black background\n");
+#if defined(UNIX_X11)
+ fprintf(stderr," -n Don't set override redirect on test window\n");
+#endif
+ fprintf(stderr," -N Disable initial calibration of instrument if possible\n");
+ fprintf(stderr," -H Use high resolution spectrum mode (if available)\n");
+// fprintf(stderr," -V Use adaptive measurement mode (if available)\n");
+ fprintf(stderr," -C \"command\" Invoke shell \"command\" each time a color is set\n");
+ fprintf(stderr," -o observ Choose CIE Observer for CCMX spectrometer data:\n");
+ fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
+ fprintf(stderr," -s steps Override default patch sequence combination steps (default %d)\n",DEFAULT_MSTEPS);
+ fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
+ fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
+ fprintf(stderr," -E desciption Override the default overall description\n");
+ fprintf(stderr," -I displayname Set display make and model description\n");
+ fprintf(stderr," -T displaytech Set display technology description (ie. CRT, LCD etc.)\n");
+ fprintf(stderr," -U c Set UI selection character(s)\n");
+ fprintf(stderr," -Y r|n Set or override refresh/non-refresh display type\n");
+ fprintf(stderr," -Y A Use non-adaptive integration time mode (if available).\n");
+ fprintf(stderr," correction.ccmx | calibration.ccss\n");
+ fprintf(stderr," File to save result to\n");
+ if (icmps != NULL)
+ icmps->del(icmps);
+ exit(1);
+}
+
+typedef double ary3[3];
+
+int main(int argc, char *argv[])
+{
+ int i,j;
+ int fa, nfa, mfa; /* current argument we're looking at */
+ disppath *disp = NULL; /* Display being used */
+ double hpatscale = 1.0, vpatscale = 1.0; /* scale factor for test patch size */
+ double ho = 0.0, vo = 0.0; /* Test window offsets, -1.0 to 1.0 */
+ int blackbg = 0; /* NZ if whole screen should be filled with black */
+ int verb = 0;
+ int debug = 0;
+ int doccss = 0; /* Create CCSS rather than CCMX */
+ int fake = 0; /* Use the fake device for testing, 2 for auto */
+ int faketoggle = 0; /* Toggle fake between "colorimeter" and "spectro" */
+ int fakeseq = 0; /* Fake auto CCMX sequence */
+ int spec = 0; /* Need spectral data to implement option */
+ icxObserverType observ = icxOT_CIE_1931_2;
+ int override = 1; /* Override redirect on X11 */
+ icompaths *icmps = NULL; /* Ports to choose from */
+ int comno = COMPORT; /* COM port used */
+ flow_control fc = fc_nc; /* Default flow control */
+ int highres = 0; /* High res mode if available */
+ int dtype = 0; /* Display kind, 0 = default, 1 = CRT, 2 = LCD */
+ int refrmode = -1; /* Refresh mode */
+ int cbid = 0; /* Calibration base display mode ID */
+ int nadaptive = 0; /* Use non-adaptive mode if available */
+ int tele = 0; /* NZ if telephoto mode */
+ int noinitcal = 0; /* Disable initial calibration */
+ int webdisp = 0; /* NZ for web display, == port number */
+ char *ccallout = NULL; /* Change color Shell callout */
+ int msteps = DEFAULT_MSTEPS; /* Patch surface size */
+ int npat = 0; /* Number of patches/colors */
+ ary3 *refs = NULL; /* Reference XYZ values */
+ int gotref = 0;
+ char *refname = NULL; /* Name of reference instrument */
+ ary3 *cols = NULL; /* Colorimeter XYZ values */
+ int gotcol = 0;
+ char *colname = NULL; /* Name of colorimeter instrument */
+ col *rdcols = NULL; /* Internal storage of all the patch colors */
+ int saved = 0; /* Saved result */
+ char innames[2][MAXNAMEL+1] = { "\000", "\000" }; /* .ti3 input names */
+ char outname[MAXNAMEL+1] = "\000"; /* ccmx output file name */
+ char *description = NULL; /* Given overall description */
+ char *displayname = NULL; /* Given display name */
+ char *displaytech = NULL; /* Given display technology */
+ char *uisel = NULL; /* UI selection letters */
+ int rv;
+
+ set_exe_path(argv[0]); /* Set global exe_path and error_program */
+ check_if_not_interactive();
+ setup_spyd2(); /* Load firware if available */
+
+ /* Process the arguments */
+ mfa = 0; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?') {
+ usage("Usage requested");
+
+ } else if (argv[fa][1] == 'v') {
+ verb = 1;
+ g_log->verb = verb;
+
+ } else if (argv[fa][1] == 'S') {
+ doccss = 1;
+
+ } else if (argv[fa][1] == 'f') {
+ char *cna, *f1 = NULL;
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to input file flag -f");
+
+ if ((cna = strdup(na)) == NULL)
+ error("Malloc failed");
+
+ /* If got just one file - enough for CCSS */
+ if ((f1 = strchr(cna, ',')) == NULL) {
+ strncpy(innames[0],cna,MAXNAMEL-1); innames[0][MAXNAMEL-1] = '\000';
+ free(cna);
+
+ /* Got two files - needed for CCMX */
+ } else {
+ *f1++ = '\000';
+ strncpy(innames[0],cna,MAXNAMEL-1); innames[0][MAXNAMEL-1] = '\000';
+ strncpy(innames[1],f1,MAXNAMEL-1); innames[1][MAXNAMEL-1] = '\000';
+ free(cna);
+ }
+
+ /* Display number */
+ } else if (argv[fa][1] == 'd') {
+ if (strncmp(na,"web",3) == 0
+ || strncmp(na,"WEB",3) == 0) {
+ webdisp = 8080;
+ if (na[3] == ':') {
+ webdisp = atoi(na+4);
+ if (webdisp == 0 || webdisp > 65535)
+ usage("Web port number must be in range 1..65535");
+ }
+ fa = nfa;
+ } else {
+#if defined(UNIX_X11)
+ int ix, iv;
+
+ if (strcmp(&argv[fa][2], "isplay") == 0 || strcmp(&argv[fa][2], "ISPLAY") == 0) {
+ if (++fa >= argc || argv[fa][0] == '-') usage("Parameter expected following -display");
+ setenv("DISPLAY", argv[fa], 1);
+ } else {
+ if (na == NULL) usage("Parameter expected following -d");
+ fa = nfa;
+ if (strcmp(na,"fake") == 0 || strcmp(na,"FAKE") == 0) {
+ fake = 1;
+ if (strcmp(na,"FAKE") == 0)
+ fakeseq = 1;
+ } else {
+ if (sscanf(na, "%d,%d",&ix,&iv) != 2) {
+ ix = atoi(na);
+ iv = 0;
+ }
+ if (disp != NULL)
+ free_a_disppath(disp);
+ if ((disp = get_a_display(ix-1)) == NULL)
+ usage("-d parameter %d out of range",ix);
+ if (iv > 0)
+ disp->rscreen = iv-1;
+ }
+ }
+#else
+ int ix;
+ if (na == NULL) usage("Parameter expected following -d");
+ fa = nfa;
+ if (strcmp(na,"fake") == 0 || strcmp(na,"FAKE") == 0) {
+ fake = 1;
+ if (strcmp(na,"FAKE") == 0)
+ fakeseq = 1;
+ } else {
+ ix = atoi(na);
+ if (disp != NULL)
+ free_a_disppath(disp);
+ if ((disp = get_a_display(ix-1)) == NULL)
+ usage("-d parameter %d out of range",ix);
+ }
+#endif
+ }
+#if defined(UNIX_X11)
+ } else if (argv[fa][1] == 'n') {
+ override = 0;
+#endif /* UNIX */
+
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -c");
+ comno = atoi(na);
+ if (comno < 1 || comno > 40) usage("-c parameter %d out of range",comno);
+
+ /* Telephoto */
+ } else if (argv[fa][1] == 'p') {
+ tele = 1;
+
+ /* Display type */
+ } else if (argv[fa][1] == 'y') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -y");
+ dtype = na[0];
+
+ /* For ccss, set a default */
+ if (na[0] == 'r') {
+ refrmode = 1;
+ } else if (na[0] == 'n') {
+ refrmode = 0;
+ }
+
+ /* Test patch offset and size */
+ } else if (argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -P");
+ if (sscanf(na, " %lf,%lf,%lf,%lf ", &ho, &vo, &hpatscale, &vpatscale) == 4) {
+ ;
+ } else if (sscanf(na, " %lf,%lf,%lf ", &ho, &vo, &hpatscale) == 3) {
+ vpatscale = hpatscale;
+ } else {
+ usage("-P parameter '%s' not recognised",na);
+ }
+ if (ho < 0.0 || ho > 1.0
+ || vo < 0.0 || vo > 1.0
+ || hpatscale <= 0.0 || hpatscale > 50.0
+ || vpatscale <= 0.0 || vpatscale > 50.0)
+ usage("-P parameters %f %f %f %f out of range",ho,vo,hpatscale,vpatscale);
+ ho = 2.0 * ho - 1.0;
+ vo = 2.0 * vo - 1.0;
+
+ /* Black background */
+ } else if (argv[fa][1] == 'F') {
+ blackbg = 1;
+
+ /* No initial calibration */
+ } else if (argv[fa][1] == 'N') {
+ noinitcal = 1;
+
+ /* High res spectral mode */
+ } else if (argv[fa][1] == 'H') {
+ highres = 1;
+
+ /* Adaptive mode - now default, so flag is deprecated */
+ } else if (argv[fa][1] == 'V') {
+ warning("dispcal -V flag is deprecated");
+
+ /* Spectral Observer type (only relevant for CCMX) */
+ } else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expecte after -o");
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ spec = 2;
+ observ = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ spec = 2;
+ observ = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ spec = 2;
+ observ = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ spec = 2;
+ observ = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ spec = 2;
+ observ = icxOT_Shaw_Fairchild_2;
+ } else
+ usage("-o parameter '%s' not recognised",na);
+
+ } else if (argv[fa][1] == 's') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expecte after -s");
+ msteps = atoi(na);
+ if (msteps < 1 || msteps > 16)
+ usage("-s parameter value %d is outside the range 1 to 16",msteps);
+
+ /* Change color callout */
+ } else if (argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -C");
+ ccallout = na;
+
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -W");
+ if (na[0] == 'n' || na[0] == 'N')
+ fc = fc_none;
+ else if (na[0] == 'h' || na[0] == 'H')
+ fc = fc_Hardware;
+ else if (na[0] == 'x' || na[0] == 'X')
+ fc = fc_XonXOff;
+ else
+ usage("-W parameter '%c' not recognised",na[0]);
+
+ } else if (argv[fa][1] == 'D') {
+ debug = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ debug = atoi(na);
+ fa = nfa;
+ }
+ g_log->debug = debug;
+
+ } else if (argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to display description flag -I");
+ displayname = strdup(na);
+
+ } else if (argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to display technology flag -T");
+ displaytech = strdup(na);
+
+ /* Copyright string */
+ } else if (argv[fa][1] == 'E') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to overall description flag -E");
+ description = strdup(na);
+
+ /* Extra flags */
+ } else if (argv[fa][1] == 'Y') {
+ if (na == NULL)
+ usage("Flag '-Y' expects extra flag");
+
+ if (na[0] == 'A') {
+ nadaptive = 1;
+ } else if (na[0] == 'r') {
+ refrmode = 1;
+ } else if (na[0] == 'n') {
+ refrmode = 0;
+ } else {
+ usage("Flag '-Z %c' not recognised",na[0]);
+ }
+
+ /* UI selection character */
+ } else if (argv[fa][1] == 'U') {
+ fa = nfa;
+ if (na == NULL || na[0] == '\000') usage("Expect argument to flag -U");
+ uisel = na;
+ for (i = 0; uisel[i] != '\000'; i++) {
+ if (!( (uisel[i] >= '0' && uisel[i] <= '9')
+ || (uisel[i] >= 'A' && uisel[i] <= 'Z')
+ || (uisel[i] >= 'a' && uisel[i] <= 'z'))) {
+ usage("-U character(s) must be 0-9,A-Z,a-z");
+ }
+ }
+
+ } else
+ usage("Flag '-%c' not recognised",argv[fa][1]);
+ }
+ else
+ break;
+ }
+
+ /* Get the output ccmx file name argument */
+ if (fa >= argc)
+ usage("Output filname expected");
+
+ strncpy(outname,argv[fa++],MAXNAMEL-1); outname[MAXNAMEL-1] = '\000';
+
+ if (fakeseq && doccss)
+ error("Fake CCSS test not implemeted");
+
+ printf("\n");
+
+ if (displayname == NULL && displaytech == NULL)
+ error("Either the display description (-I) or technology (-T) needs to be set");
+
+ /* CCSS: See if we're working from a .ti3 file */
+ if (doccss && innames[0][0] != '\000') {
+ cgats *cgf = NULL; /* cgats file data */
+ int sidx; /* Sample ID index */
+ int ii, ti;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xspect sp, *samples = NULL;
+ ccss *cc;
+ double bigv = -1e60;
+
+ /* Open spectral values file */
+ cgf = new_cgats(); /* Create a CGATS structure */
+ cgf->add_other(cgf, ""); /* Allow any signature file */
+
+ if (cgf->read_name(cgf, innames[0]))
+ error("CGATS file '%s' read error : %s",innames[0],cgf->err);
+
+ if (cgf->ntables < 1)
+ error ("Input file '%s' doesn't contain at least one table",innames[0]);
+
+ if ((npat = cgf->t[0].nsets) <= 0)
+ error("No sets of data in file '%s'",innames[0]);
+
+ if ((samples = (xspect *)malloc(npat * sizeof(xspect))) == NULL)
+ error("malloc failed");
+
+ if ((ii = cgf->find_kword(cgf, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Can't find keyword TARGET_INSTRUMENT in '%s'",innames[0]);
+
+ if ((ti = cgf->find_kword(cgf, 0, "DISPLAY_TYPE_REFRESH")) >= 0) {
+ if (stricmp(cgf->t[0].kdata[ti], "YES") == 0)
+ refrmode = 1;
+ else if (stricmp(cgf->t[0].kdata[ti], "NO") == 0)
+ refrmode = 0;
+ }
+
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_BANDS",innames[0]);
+ sp.spec_n = atoi(cgf->t[0].kdata[ii]);
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_START_NM",innames[0]);
+ sp.spec_wl_short = atof(cgf->t[0].kdata[ii]);
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_END_NM",innames[0]);
+ sp.spec_wl_long = atof(cgf->t[0].kdata[ii]);
+ sp.norm = 1.0; /* We assume emssive */
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = cgf->find_field(cgf, 0, buf)) < 0)
+ error("Input file '%s' doesn't contain field %s",innames[0],buf);
+ }
+
+ /* Transfer all the spectral values */
+ for (i = 0; i < npat; i++) {
+
+ XSPECT_COPY_INFO(&samples[i], &sp);
+
+ for (j = 0; j < sp.spec_n; j++) {
+ samples[i].spec[j] = *((double *)cgf->t[0].fdata[i][spi[j]]);
+ }
+ }
+ cgf->del(cgf); /* Clean up */
+ cgf = NULL;
+
+ if (description == NULL) {
+ char *disp = displaytech != NULL ? displaytech : displayname;
+ char *tt = "CCSS for ";
+ if ((description = malloc(strlen(disp) + strlen(tt) + 1)) == NULL)
+ error("Malloc failed");
+ strcpy(description, tt);
+ strcat(description, disp);
+ }
+
+ /* See what the highest value is */
+ for (i = 0; i < npat; i++) { /* For all grid points */
+
+ for (j = 0; j < samples[i].spec_n; j++) {
+ if (samples[i].spec[j] > bigv)
+ bigv = samples[i].spec[j];
+ }
+ }
+
+ /* Normalize the values */
+ for (i = 0; i < npat; i++) { /* For all grid points */
+ double scale = 100.0;
+
+ for (j = 0; j < samples[i].spec_n; j++)
+ samples[i].spec[j] *= scale / bigv;
+ }
+
+ if (refrmode < 0)
+ error("The display refresh mode is not known - use the -Y flag");
+
+ if ((cc = new_ccss()) == NULL)
+ error("new_ccss() failed");
+
+ if (cc->set_ccss(cc, "Argyll ccxxmake", NULL, description, displayname,
+ displaytech, refrmode, uisel, refname, samples, npat)) {
+ error("set_ccss failed with '%s'\n",cc->err);
+ }
+ if(cc->write_ccss(cc, outname))
+ printf("\nWriting CCXX file '%s' failed\n",outname);
+ else
+ printf("\nWriting CCXX file '%s' succeeded\n",outname);
+ cc->del(cc);
+ free(samples);
+
+#ifdef DEBUG
+ printf("About to exit\n");
+#endif
+ return 0;
+ }
+
+ /* CCMX: See if we're working from two files */
+ if (!doccss && innames[0][0] != '\000') {
+ int n;
+ char *oname = NULL; /* Observer name */
+ ccmx *cc;
+
+ if (innames[1][0] == '\000') {
+ error("Need two .ti3 files to create CCMX");
+ }
+
+ /* Open up each CIE 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 */
+ double wxyz[3], scale = 1.0;/* Scale factor back to absolute */
+ int sidx; /* Sample ID index */
+ int xix, yix, zix;
+ ary3 *current = NULL; /* Current value array */
+ int ii, ti;
+ int instspec = 0; /* File is spectrale */
+
+ /* Open CIE target values */
+ cgf = new_cgats(); /* Create a CGATS structure */
+ cgf->add_other(cgf, ""); /* Allow any signature file */
+
+ if (cgf->read_name(cgf, innames[n]))
+ error("CGATS file '%s' read error : %s",innames[n],cgf->err);
+
+ if (cgf->ntables < 1)
+ error ("Input file '%s' doesn't contain at least one table",innames[n]);
+
+ /* Check if the file is suitable */
+ if (cgf->find_field(cgf, 0, "LAB_L") < 0
+ && cgf->find_field(cgf, 0, "XYZ_X") < 0) {
+
+ error ("No CIE data found in file '%s'",innames[n]);
+ }
+
+ if (cgf->find_field(cgf, 0, "LAB_L") >= 0)
+ isLab = 1;
+
+ if (cols == NULL) {
+ if ((npat = cgf->t[0].nsets) <= 0)
+ error("No sets of data in file '%s'",innames[n]);
+
+ if ((refs = (ary3 *)malloc(npat * sizeof(ary3))) == NULL)
+ error("malloc failed");
+ if ((cols = (ary3 *)malloc(npat * sizeof(ary3))) == NULL)
+ error("malloc failed");
+
+ } else {
+ if (npat != cgf->t[0].nsets)
+ error ("Number of sets %d in file '%s' doesn't match other file %d",cgf->t[0].nsets,innames[n],npat);
+ }
+
+ if ((ii = cgf->find_kword(cgf, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Can't find keyword TARGET_INSTRUMENT in '%s'",innames[n]);
+
+ if ((ti = cgf->find_kword(cgf, 0, "INSTRUMENT_TYPE_SPECTRAL")) < 0)
+ error ("Can't find keyword INSTRUMENT_TYPE_SPECTRAL in '%s'",innames[n]);
+
+ if (strcmp(cgf->t[0].kdata[ti],"YES") == 0) {
+ instspec = 1; /* Currently is a spectral file */
+ if (gotref)
+ error("Found two spectral files - expect one colorimtric file");
+ current = refs;
+ refname = strdup(cgf->t[0].kdata[ii]);
+ gotref = 1;
+
+ } else if (strcmp(cgf->t[0].kdata[ti],"NO") == 0) {
+ instspec = 0; /* Currently is not spectral file */
+ if (gotcol) {
+ /* Copy what we though was cols to refs */
+ refname = colname;
+ for (i = 0; i < npat; i++) {
+ refs[i][0] = cols[i][0];
+ refs[i][1] = cols[i][1];
+ refs[i][2] = cols[i][2];
+ }
+ gotref = 1;
+ warning("Got two colorimetric files - assuming '%s' is the refrence",innames[0]);
+ refrmode = -1;
+ cbid = 0;
+
+ if (spec) {
+ error("Spectral reference is required to use non-standard observer");
+ }
+ }
+ if ((ti = cgf->find_kword(cgf, 0, "DISPLAY_TYPE_REFRESH")) >= 0) {
+ if (stricmp(cgf->t[0].kdata[ti], "YES") == 0)
+ refrmode = 1;
+ else if (stricmp(cgf->t[0].kdata[ti], "NO") == 0)
+ refrmode = 0;
+ }
+ if ((ti = cgf->find_kword(cgf, 0, "DISPLAY_TYPE_BASE_ID")) >= 0) {
+ cbid = atoi(cgf->t[0].kdata[ti]);
+ } else {
+ cbid = 0;
+ }
+ current = cols;
+ colname = strdup(cgf->t[0].kdata[ii]);
+ gotcol = 1;
+ } else {
+ error ("Unknown INSTRUMENT_TYPE_SPECTRAL value '%s'",cgf->t[0].kdata[ti]);
+ }
+
+ if ((ti = cgf->find_kword(cgf, 0, "NORMALIZED_TO_Y_100")) < 0
+ || strcmp(cgf->t[0].kdata[ti],"NO") == 0) {
+ scale = 1.0; /* Leave absolute */
+ } else {
+ if ((ti = cgf->find_kword(cgf, 0, "LUMINANCE_XYZ_CDM2")) < 0)
+ error ("Can't find keyword LUMINANCE_XYZ_CDM2 in '%s'",innames[n]);
+ if (sscanf(cgf->t[0].kdata[ti],"%lf %lf %lf", &wxyz[0], &wxyz[1], &wxyz[2]) != 3)
+ error ("Unable to parse LUMINANCE_XYZ_CDM2 in '%s'",innames[n]);
+ scale = wxyz[1]/100.0; /* Convert from Y = 100 normalise back to absolute */
+ }
+
+ if (instspec && spec) {
+ int ii;
+ xspect sp;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xsp2cie *sp2cie; /* Spectral conversion object */
+
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_BANDS",innames[n]);
+ sp.spec_n = atoi(cgf->t[0].kdata[ii]);
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_START_NM",innames[n]);
+ sp.spec_wl_short = atof(cgf->t[0].kdata[ii]);
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file '%s' doesn't contain keyword SPECTRAL_END_NM",innames[n]);
+ sp.spec_wl_long = atof(cgf->t[0].kdata[ii]);
+ sp.norm = 1.0; /* We assume emssive */
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = cgf->find_field(cgf, 0, buf)) < 0)
+ error("Input file '%s' doesn't contain field %s",innames[n],buf);
+ }
+
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie(icxIT_none, NULL, observ, NULL, icSigXYZData, icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+
+ for (i = 0; i < npat; i++) {
+
+ /* Read the spectral values for this patch */
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)cgf->t[0].fdata[i][spi[j]]) * scale;
+ }
+
+ /* Convert it to CIE space */
+ sp2cie->convert(sp2cie, current[i], &sp);
+ }
+ sp2cie->del(sp2cie); /* Done with this */
+
+ /* Colorimetric file - assume it's the target */
+ } else {
+
+ if (isLab) { /* Expect Lab */
+ if ((xix = cgf->find_field(cgf, 0, "LAB_L")) < 0)
+ error("Input file '%s' doesn't contain field LAB_L",innames[n]);
+ if (cgf->t[0].ftype[xix] != r_t)
+ error("Field LAB_L is wrong type");
+ if ((yix = cgf->find_field(cgf, 0, "LAB_A")) < 0)
+ error("Input file '%s' doesn't contain field LAB_A",innames[n]);
+ if (cgf->t[0].ftype[yix] != r_t)
+ error("Field LAB_A is wrong type");
+ if ((zix = cgf->find_field(cgf, 0, "LAB_B")) < 0)
+ error("Input file '%s' doesn't contain field LAB_B",innames[n]);
+ if (cgf->t[0].ftype[zix] != r_t)
+ error("Field LAB_B is wrong type");
+
+ } else { /* Expect XYZ */
+ if ((xix = cgf->find_field(cgf, 0, "XYZ_X")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_X",innames[n]);
+ if (cgf->t[0].ftype[xix] != r_t)
+ error("Field XYZ_X is wrong type");
+ if ((yix = cgf->find_field(cgf, 0, "XYZ_Y")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Y",innames[n]);
+ if (cgf->t[0].ftype[yix] != r_t)
+ error("Field XYZ_Y is wrong type");
+ if ((zix = cgf->find_field(cgf, 0, "XYZ_Z")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Z",innames[n]);
+ if (cgf->t[0].ftype[zix] != r_t)
+ error("Field XYZ_Z is wrong type");
+ }
+
+ for (i = 0; i < npat; i++) {
+ current[i][0] = *((double *)cgf->t[0].fdata[i][xix]);
+ current[i][1] = *((double *)cgf->t[0].fdata[i][yix]);
+ current[i][2] = *((double *)cgf->t[0].fdata[i][zix]);
+ if (isLab) { /* Convert test patch Lab to XYZ scale 100 */
+ icmLab2XYZ(&icmD50_100, current[i], current[i]);
+ }
+ /* Rescale to absolute if needed */
+ current[i][0] *= scale;
+ current[i][1] *= scale;
+ current[i][2] *= scale;
+ }
+ }
+ cgf->del(cgf); /* Clean up */
+ cgf = NULL;
+ }
+
+ if (spec != 0 && observ != icxOT_CIE_1931_2)
+ oname = standardObserverDescription(observ);
+
+ if (oname != NULL) {
+ char *tt = colname;
+
+ if ((colname = malloc(strlen(tt) + strlen(oname) + 3)) == NULL)
+ error("Malloc failed");
+ strcpy(colname, tt);
+ strcat(colname, " (");
+ strcat(colname, oname);
+ strcat(colname, ")");
+ }
+ if (description == NULL) {
+ char *disp = displaytech != NULL ? displaytech : displayname;
+ if ((description = malloc(strlen(colname) + strlen(disp) + 4)) == NULL)
+ error("Malloc failed");
+ strcpy(description, colname);
+ strcat(description, " & ");
+ strcat(description, disp);
+ }
+
+ if (refrmode < 0)
+ error("The display refresh mode is not known - use the -Y flag");
+
+ if (cbid == 0)
+ error("The calibration base display mode not specified in the .ti3 file");
+
+ if ((cc = new_ccmx()) == NULL)
+ error("new_ccmx() failed");
+
+ if (cc->create_ccmx(cc, description, colname, displayname, displaytech,
+ refrmode, cbid, uisel, refname, npat, refs, cols)) {
+ error("create_ccmx failed with '%s'\n",cc->err);
+ }
+ if (verb) {
+ printf("Fit error is max %f, avg %f DE94\n",cc->mx_err,cc->av_err);
+ printf("Correction matrix is:\n");
+ printf(" %f %f %f\n", cc->matrix[0][0], cc->matrix[0][1], cc->matrix[0][2]);
+ printf(" %f %f %f\n", cc->matrix[1][0], cc->matrix[1][1], cc->matrix[1][2]);
+ printf(" %f %f %f\n", cc->matrix[2][0], cc->matrix[2][1], cc->matrix[2][2]);
+ }
+
+ if(cc->write_ccmx(cc, outname))
+ printf("\nWriting CCMX file '%s' failed\n",outname);
+ else
+ printf("\nWriting CCMX file '%s' succeeded\n",outname);
+ cc->del(cc);
+
+ /* Do interactive measurements */
+ } else {
+
+ /* No explicit display has been set */
+ if (
+#ifndef SHOW_WINDOW_ONFAKE
+ !fake &&
+#endif
+ webdisp == 0 && disp == NULL) {
+ int ix = 0;
+#if defined(UNIX_X11)
+ char *dn, *pp;
+
+ if ((dn = getenv("DISPLAY")) != NULL) {
+ if ((pp = strrchr(dn, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) != NULL) {
+ if (pp[1] != '\000')
+ ix = atoi(pp+1);
+ }
+ }
+ }
+#endif
+ if ((disp = get_a_display(ix)) == NULL)
+ error("Unable to open the default display");
+
+ if (displayname == NULL && (displayname = strdup(disp->description)) == NULL)
+ error("Malloc failed");
+
+ printf("Display description is '%s'\n",displayname);
+ }
+ if (fake) {
+ displayname = strdup("fake display");
+ }
+
+ /* Create grid of device test values */
+ {
+ int j;
+ int gc[3]; /* Grid coordinate */
+
+ if (msteps == 1)
+ npat = 4;
+ else
+ npat = msteps * msteps * msteps;
+
+ if ((rdcols = (col *)malloc(npat * sizeof(col))) == NULL) {
+ error("malloc failed");
+ }
+ if ((refs = (ary3 *)malloc(npat * sizeof(ary3))) == NULL) {
+ free(rdcols);
+ error("malloc failed");
+ }
+ if ((cols = (ary3 *)malloc(npat * sizeof(ary3))) == NULL) {
+ free(rdcols);
+ free(refs);
+ error("malloc failed");
+ }
+
+ /* RGBW */
+ if (msteps == 1) {
+ npat = 0;
+ rdcols[npat].r = 1.0;
+ rdcols[npat].g = 0.0;
+ rdcols[npat].b = 0.0;
+ npat++;
+ rdcols[npat].r = 0.0;
+ rdcols[npat].g = 1.0;
+ rdcols[npat].b = 0.0;
+ npat++;
+ rdcols[npat].r = 0.0;
+ rdcols[npat].g = 0.0;
+ rdcols[npat].b = 1.0;
+ npat++;
+ rdcols[npat].r = 1.0;
+ rdcols[npat].g = 1.0;
+ rdcols[npat].b = 1.0;
+ npat++;
+#ifdef DEBUG
+ for (j = 0; j < 4; j++)
+ printf("Dev val %f %f %f\n",rdcols[j].r,rdcols[j].g,rdcols[j].b);
+#endif
+ } else {
+ for (j = 0; j < 3; j++)
+ gc[j] = 0; /* init coords */
+
+ for (npat = 0; ;) { /* For all grid points */
+
+ /* Just colors with at least one channel at 100% */
+ if (gc[0] == (msteps-1)
+ || gc[1] == (msteps-1)
+ || gc[2] == (msteps-1))
+ {
+
+ rdcols[npat].r = (double)gc[0]/(msteps-1);
+ rdcols[npat].g = (double)gc[1]/(msteps-1);
+ rdcols[npat].b = (double)gc[2]/(msteps-1);
+#ifdef DEBUG
+ printf("Dev val %f %f %f\n",rdcols[npat].r,rdcols[npat].g,rdcols[npat].b);
+#endif
+ npat++;
+ }
+
+ /* Increment grid index and position */
+ for (j = 0; j < 3; j++) {
+ gc[j]++;
+ if (gc[j] < msteps)
+ break; /* No carry */
+ gc[j] = 0;
+ }
+ if (j >= 3)
+ break; /* Done grid */
+ }
+ }
+ if (verb)
+ printf("Total test patches = %d\n",npat);
+ }
+
+ /* Until the measurements are done, or we give up */
+ for (;;) {
+ int c;
+
+ /* Print the menue of adjustments */
+ printf("\n");
+ if (gotref)
+ printf("[Got spectrometer readings]\n");
+ if (gotcol)
+ printf("[Got colorimeter readings]\n");
+ printf("Press 1 .. 4:\n");
+ {
+ printf("1) Select an instrument, Currently %d (", comno);
+ if (icmps == NULL)
+ icmps = new_icompaths(g_log);
+ else
+ icmps->refresh(icmps);
+ if (icmps != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ if ((i+1) == comno) {
+ printf(" '%s'",paths[i]->name);
+ break;
+ }
+ }
+ }
+ }
+ printf(")\n");
+ }
+ if (doccss)
+ printf("2) Measure test patches with current (spectrometer) instrument\n");
+ else
+ printf("2) Measure test patches with current instrument\n");
+
+ if (doccss) {
+ if (gotref)
+ printf("3) Save Colorimeter Calibration Spectral Set\n");
+ else
+ printf("3) [ Save Colorimeter Calibration Spectral Set ]\n");
+
+ } else {
+ if (gotref && gotcol)
+ printf("3) Compute Colorimeter Correction Matrix & save it\n");
+ else
+ printf("3) [ Compute Colorimeter Correction Matrix & save it ]\n");
+ }
+ printf("4) Exit\n");
+
+ if (fakeseq == 0) {
+ empty_con_chars();
+ c = next_con_char();
+ } else {
+ switch (fakeseq) {
+ case 1:
+ c = '2';
+ fakeseq = 2;
+ break;
+ case 2:
+ c = '2';
+ fakeseq = 3;
+ break;
+ case 3:
+ c = '3';
+ fakeseq = 4;
+ break;
+ default:
+ c = '4';
+ break;
+ }
+ }
+ printf("'%c'\n",c);
+
+
+ /* Deal with selecting the instrument */
+ if (c == '1') {
+ if (icmps == NULL)
+ icmps = new_icompaths(g_log);
+ else
+ icmps->refresh(icmps);
+ if (icmps != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ if (paths[i]->itype == instSpyder2 && setup_spyd2() == 0)
+ fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
+ else
+ fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
+ }
+ printf("Select device 1 - %d: \n",i);
+ empty_con_chars();
+ c = next_con_char();
+
+ if (c < '1' || c > ('0' + i)) {
+ printf("'%c' is out of range - ignored !\n",c);
+ } else {
+ comno = c - '0';
+ }
+
+ } else {
+ fprintf(stderr,"No ports to select from!\n");
+ }
+ }
+ continue;
+ }
+
+ /* Deal with doing a measurement */
+ if (c == '2') {
+ int errc; /* Return value from new_disprd() */
+ disprd *dr; /* Display patch read object */
+ inst *it; /* Instrument */
+ inst_mode cap = inst_mode_none; /* Instrument mode capabilities */
+ inst2_capability cap2 = inst2_none; /* Instrument capabilities 2 */
+ inst3_capability cap3 = inst3_none; /* Instrument capabilities 3 */
+
+ if (fake)
+ comno = -99;
+ if (icmps == NULL)
+ icmps = new_icompaths(g_log);
+
+ /* Should we use current cal rather than native ??? */
+ if ((dr = new_disprd(&errc, icmps->get_path(icmps, comno),
+ fc, dtype, 1, tele, nadaptive,
+ noinitcal, highres, 2, NULL, NULL, 0, 0, disp, blackbg,
+ override, webdisp, ccallout, NULL,
+ 100.0 * hpatscale, 100.0 * vpatscale, ho, vo,
+ NULL, NULL, 0, 2, icxOT_default, NULL,
+ 0, 0, "fake" ICC_FILE_EXT, g_log)) == NULL)
+ error("new_disprd failed with '%s'\n",disprd_err(errc));
+
+ it = dr->it;
+
+ if (fake) {
+ if (faketoggle)
+ cap = inst_mode_spectral;
+ else
+ cap = inst_mode_colorimeter;
+ cap2 = inst2_none;
+ cap3 = inst3_none;
+ refrmode = 0;
+ cbid = 1;
+ } else {
+ it->capabilities(it, &cap, &cap2, &cap3);
+ if (!IMODETST(cap, inst_mode_spectral)) {
+ dr->get_disptype(dr, &refrmode, &cbid); /* Get the display type info */
+ }
+ }
+
+ if (doccss && !IMODETST(cap, inst_mode_spectral)) {
+ printf("You have to use a spectrometer to create a CCSS!\n");
+ continue;
+ }
+
+ if (faketoggle)
+ dr->fake2 = 1;
+ else
+ dr->fake2 = -1;
+
+ /* Test the CRT with all of the test points */
+ if ((rv = dr->read(dr, rdcols, npat, 1, npat, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("disprd returned error code %d\n",rv);
+ }
+
+ if (doccss) { /* We'll use the rdcols values */
+ gotref = 1;
+ } else {
+ if (IMODETST(cap, inst_mode_spectral)) {
+ xsp2cie *sp2cie = NULL;
+
+ if (spec) {
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie(icxIT_none, NULL, observ, NULL, icSigXYZData, icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+ }
+ for (i = 0; i < npat; i++) { /* For all grid points */
+ if (spec) {
+ if (rdcols[i].sp.spec_n <= 0)
+ error("Didn't get spectral value");
+ sp2cie->convert(sp2cie, refs[i], &rdcols[i].sp);
+ } else {
+ if (rdcols[i].XYZ_v == 0)
+ error("Didn't get XYZ value");
+ refs[i][0] = rdcols[i].XYZ[0];
+ refs[i][1] = rdcols[i].XYZ[1];
+ refs[i][2] = rdcols[i].XYZ[2];
+ }
+ }
+ if (fake)
+ refname = "fake spectrometer";
+ else
+ refname = inst_name(it->itype);
+ gotref = 1;
+ if (sp2cie != NULL)
+ sp2cie->del(sp2cie);
+ } else if (IMODETST(cap, inst_mode_colorimeter)) {
+ for (i = 0; i < npat; i++) { /* For all grid points */
+ if (rdcols[i].XYZ_v == 0)
+ error("Didn't get XYZ value");
+ cols[i][0] = rdcols[i].XYZ[0];
+ cols[i][1] = rdcols[i].XYZ[1];
+ cols[i][2] = rdcols[i].XYZ[2];
+ }
+ if (fake)
+ colname = "fake colorimeter";
+ else
+ colname = inst_name(it->itype);
+ gotcol = 1;
+ }
+ }
+ dr->del(dr);
+
+ faketoggle ^= 1;
+
+ } /* End of take a measurement */
+
+ if (c == '3') { /* Compute result and save */
+ /* Save the CCSS */
+ if (doccss) {
+ ccss *cc;
+ xspect *samples = NULL;
+ double bigv = -1e60;
+
+ if (!gotref) {
+ printf("You have to read the spectrometer values first!\n");
+ continue;
+ }
+
+ if (description == NULL) {
+ char *disp = displaytech != NULL ? displaytech : displayname;
+ char *tt = "CCSS for ";
+ if ((description = malloc(strlen(disp) + strlen(tt) + 1)) == NULL)
+ error("Malloc failed");
+ strcpy(description, tt);
+ strcat(description, disp);
+ }
+
+ if ((samples = (xspect *)malloc(sizeof(xspect) * npat)) == NULL)
+ error("Malloc failed");
+
+ /* See what the highest value is */
+ for (i = 0; i < npat; i++) { /* For all grid points */
+ if (rdcols[i].sp.spec_n <= 0)
+ error("Didn't get spectral values");
+ for (j = 0; j < rdcols[i].sp.spec_n; j++) {
+ if (rdcols[i].sp.spec[j] > bigv)
+ bigv = rdcols[i].sp.spec[j];
+ }
+ }
+
+ /* Copy all the values and normalize them */
+ for (i = 0; i < npat; i++) { /* For all grid points */
+ double scale = 100.0;
+
+ samples[i] = rdcols[i].sp; /* Structure copy */
+ for (j = 0; j < rdcols[i].sp.spec_n; j++)
+ samples[i].spec[j] *= scale / bigv;
+ }
+
+ if (refrmode < 0)
+ warning("No refresh mode specified! Assuming non-refresh !");
+
+ if ((cc = new_ccss()) == NULL)
+ error("new_ccss() failed");
+
+ if (cc->set_ccss(cc, "Argyll ccxxmake", NULL, description, displayname,
+ displaytech, refrmode, NULL, refname, samples, npat)) {
+ error("set_ccss failed with '%s'\n",cc->err);
+ }
+ if(cc->write_ccss(cc, outname))
+ printf("\nWriting CCSS file '%s' failed\n",outname);
+ else
+ printf("\nWriting CCSS file '%s' succeeded\n",outname);
+ cc->del(cc);
+ free(samples);
+ saved = 1;
+
+ /* Compute and save CCMX */
+ } else {
+ char *oname = NULL; /* Observer desciption */
+ ccmx *cc;
+
+ if (!gotref) {
+ printf("You have to read the spectrometer values first!\n");
+ continue;
+ }
+ if (!gotcol) {
+ printf("You have to read the colorimeter values first!\n");
+ continue;
+ }
+
+ if (spec != 0 && observ != icxOT_CIE_1931_2)
+ oname = standardObserverDescription(observ);
+
+ if (oname != NULL) { /* Incorporate observer name in colname */
+ char *tt = colname;
+
+ if ((colname = malloc(strlen(tt) + strlen(oname) + 3)) == NULL)
+ error("Malloc failed");
+ strcpy(colname, tt);
+ strcat(colname, " (");
+ strcat(colname, oname);
+ strcat(colname, ")");
+ }
+ if (description == NULL) {
+ if ((description = malloc(strlen(colname) + strlen(displayname) + 4)) == NULL)
+ error("Malloc failed");
+ strcpy(description, colname);
+ strcat(description, " & ");
+ strcat(description, displayname);
+ }
+
+ if (refrmode < 0)
+ error("Internal error - the instrument did not return a refmode");
+ if (cbid == 0)
+ error("Internal error - the instrument did not return a cbid");
+
+ if ((cc = new_ccmx()) == NULL)
+ error("new_ccmx() failed");
+
+ if (cc->create_ccmx(cc, description, colname, displayname, displaytech,
+ refrmode, cbid, uisel, refname, npat, refs, cols)) {
+ error("create_ccmx failed with '%s'\n",cc->err);
+ }
+ if (verb) {
+ printf("Fit error is avg %f, max %f DE94\n",cc->av_err,cc->mx_err);
+ printf("Correction matrix is:\n");
+ printf(" %f %f %f\n", cc->matrix[0][0], cc->matrix[0][1], cc->matrix[0][2]);
+ printf(" %f %f %f\n", cc->matrix[1][0], cc->matrix[1][1], cc->matrix[1][2]);
+ printf(" %f %f %f\n", cc->matrix[2][0], cc->matrix[2][1], cc->matrix[2][2]);
+ }
+
+ if(cc->write_ccmx(cc, outname))
+ printf("\nWriting CCMX file '%s' failed\n",outname);
+ else
+ printf("\nWriting CCMX file '%s' succeeded\n",outname);
+ cc->del(cc);
+ saved = 1;
+ }
+ }
+
+ if (c == '4' || c == 0x3) { /* Exit */
+ if (!saved) {
+ printf("Not saved yet, are you sure ? (y/n): "); fflush(stdout);
+ empty_con_chars();
+ c = next_con_char();
+ printf("\n");
+ if (c != 'y' && c != 'Y')
+ continue;
+ }
+ break;
+ }
+
+ } /* Next command */
+
+ free(displayname);
+ if (icmps != NULL)
+ icmps->del(icmps);
+ }
+
+#ifdef DEBUG
+ /* Do a CCMX verification */
+ if (!doccss) {
+ ccmx *cc;
+ double av_err, mx_err;
+ int wix;
+ double maxy = -1e6;
+ icmXYZNumber wh;
+
+ for (i = 0; i < npat; i++) {
+ if (refs[i][1] > maxy) {
+ maxy = refs[i][1];
+ wix = i;
+ }
+ }
+ wh.X = refs[wix][0];
+ wh.Y = refs[wix][1];
+ wh.Z = refs[wix][2];
+
+ if ((cc = new_ccmx()) == NULL)
+ error("new_ccmx() failed");
+ if(cc->read_ccmx(cc, outname))
+ printf("Reading file '%s' failed\n",outname);
+
+ av_err = mx_err = 0.0;
+ for (i = 0; i < npat; i++) {
+ double txyz[3], tlab[3], xyz[3], _xyz[3], lab[3], de;
+ icmCpy3(txyz, refs[i]);
+ icmXYZ2Lab(&wh, tlab, txyz);
+ icmCpy3(xyz, cols[i]);
+ cc->xform(cc,_xyz, xyz);
+ icmXYZ2Lab(&wh, lab, _xyz);
+ de = icmCIE94(tlab, lab);
+ av_err += de;
+ if (de > mx_err)
+ mx_err = de;
+ printf("%d: txyz %f %f %f\n",i,txyz[0], txyz[1], txyz[2]);
+ printf("%d: xyz %f %f %f, _xyz %f %f %f\n",i,xyz[0], xyz[1], xyz[2], _xyz[0], _xyz[1], _xyz[2]);
+ printf("%d: tlab %f %f %f, lab %f %f %f\n",i,tlab[0], tlab[1], tlab[2], lab[0], lab[1], lab[2]);
+ printf("%d: de %f\n",i,de);
+ }
+ av_err /= npat;
+ printf("Avg = %f, max = %f\n",av_err,mx_err);
+ cc->del(cc);
+ }
+#endif
+
+#ifdef DEBUG
+ printf("About to exit\n");
+#endif
+
+ return 0;
+}
+
+
+
+
diff --git a/spectro/chartread.c b/spectro/chartread.c
new file mode 100644
index 0000000..1c2117a
--- /dev/null
+++ b/spectro/chartread.c
@@ -0,0 +1,2993 @@
+
+/*
+ * Argyll Color Correction System
+ * Spectrometer/Colorimeter target test chart reader
+ *
+ * Author: Graeme W. Gill
+ * Date: 4/10/96
+ *
+ * Copyright 1996 - 2013, 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.
+ */
+
+/* This program reads a reflective or transmissive print target chart */
+/* using a spectrometer or colorimeter. */
+
+/* TTBD
+ *
+ * Should an a -X [xl] mode that reads a simple list of readings
+ * from a file.
+ *
+ * Someone reported that XY mode (spectroscan) didn't work for one paper
+ * orientation ?
+ *
+ * Should fix XY chart read to also allow interruption/save/resume,
+ * just like the strip reading code.
+ *
+ * Should add verbose option to print average & max DE to expected value
+ * for each patch/strip read.
+ *
+ */
+
+/*
+ * Nomencalture:
+ *
+ * Largely due to how the strip readers name things, the following terms
+ * are used for how patches are grouped:
+ *
+ * Step: One test patch in a pass, usually labelled with a number.
+ * Pass: One row of patches in a strip. A pass is usually labeled
+ * with a unique alphabetic label.
+ * Strip: A group of passes that can be read by a strip reader.
+ * For an XY instrument, the strip is a complete sheet, and
+ * a each pass is one column. The rows of an XY chart are
+ * the step numbers within a pass.
+ * Sheet: One sheet of paper, containing full and partial strips.
+ * For an XY instrument, there will be only one strip per sheet.
+ *
+ */
+
+#undef DEBUG
+
+#define COMPORT 1 /* Default com port 1..4 */
+
+#ifdef __MINGW32__
+# define WINVER 0x0500
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <ctype.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "cgats.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xicc.h"
+#include "ccmx.h"
+#include "ccss.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "inst.h"
+#include "dispwin.h"
+#include "dispsup.h"
+#include "alphix.h"
+#include "sort.h"
+#include "instappsup.h"
+#include "spyd2setup.h"
+
+#include <stdarg.h>
+
+#if defined (NT)
+#include <conio.h>
+#endif
+
+#ifdef NEVER /* Not currently used */
+
+/* Convert control chars to ^[A-Z] notation in a string */
+static char *
+fix_asciiz(char *s) {
+ static char buf [200];
+ char *d;
+ for(d = buf; ;) {
+ if (*s < ' ' && *s > '\000') {
+ *d++ = '^';
+ *d++ = *s++ + '@';
+ } else
+ *d++ = *s++;
+ if (s[-1] == '\000')
+ break;
+ }
+ return buf;
+}
+#endif /* NEVER */
+
+/* Return the normal Delta E, given two 100 scaled XYZ values */
+static double xyzLabDE(double ynorm, double *pat, double *ref) {
+ int i;
+ double Lab1[3];
+ double Lab2[3];
+
+ for (i = 0; i < 3; i++) {
+ Lab1[i] = ynorm * pat[i]/100.0;
+ Lab2[i] = ref[i]/100.0;
+ }
+
+ icmXYZ2Lab(&icmD50, Lab1, Lab1);
+ icmXYZ2Lab(&icmD50, Lab2, Lab2);
+
+ return icmLabDE(Lab1, Lab2);
+}
+
+/* A chart read color structure */
+/* This can hold all representations simultaniously */
+typedef struct {
+ char *id; /* Id string (e.g. "1") */
+ char *loc; /* Location string (e.g. "A1") */
+ int loci; /* Location integer = pass * 256 + step */
+
+ int n; /* Number of colorants */
+ double dev[ICX_MXINKS]; /* Value of colorants */
+ double eXYZ[3]; /* Expected XYZ values (100.0 scale for ref.) */
+
+ int rr; /* nz if reading read (used for tracking unread patches) */
+
+ inst_meas_type mtype; /* Measurement type */
+ double XYZ[3]; /* Colorimeter readings (100.0 scale for ref.) */
+
+ xspect sp; /* Spectrum. sp.spec_n > 0 if valid, 100 scaled for ref. */
+} chcol;
+
+/* Convert a base 62 character into a number */
+/* (This is used for converting the PASSES_IN_STRIPS string */
+/* (Could convert this to using an alphix("0-9A-Za-Z")) */
+static int b62_int(char *p) {
+ int cv, rv;
+
+ cv = *p;
+ if (cv == '\000')
+ rv = 0;
+ else if (cv <= '9')
+ rv = cv - '0';
+ else if (cv <= 'Z')
+ rv = cv - 'A' + 10;
+ else
+ rv = cv - 'a' + 36;
+ return rv;
+}
+
+/* Deal with an instrument error. */
+/* Return 0 to retry, 1 to abort */
+static int ierror(inst *it, inst_code ic) {
+ int ch;
+ empty_con_chars();
+ printf("Got '%s' (%s) error.\nHit Esc or 'q' to give up, any other key to retry:",
+ it->inst_interp_error(it, ic), it->interp_error(it, ic));
+ fflush(stdout);
+ ch = next_con_char();
+ printf("\n");
+ if (ch == 0x03 || ch == 0x1b || ch == 'q' || ch == 'Q') /* ^C, Escape or Q */
+ return 1;
+ return 0;
+}
+
+/* Read all the strips, and return nonzero on abort/error */
+static int
+read_strips(
+instType itype, /* Chart instrument type */
+chcol **scols, /* Location sorted pointers to cols (return values) */
+instType *atype, /* Return the instrument type used to read the chart */
+int npat, /* Total valid patches */
+int totpa, /* Total passes (rows) */
+int stipa, /* Steps (patches) in pass (Excluding DTP51 Max/Min) */
+int *pis, /* Passes in each strip (rows in each sheet), 0 terminated */
+alphix *paix, /* Pass (row) index generators */
+alphix *saix, /* Step (patch) index generators */
+int ixord, /* Index order, 0 = pass then step */
+int rstart, /* Random start/chart id */
+int hex, /* Hexagon test patches */
+icompath *ipath, /* Instrument path to open */
+flow_control fc, /* flow control */
+double plen, /* Patch length in mm (used by DTP20/41) */
+double glen, /* Gap length in mm (used by DTP20/41) */
+double tlen, /* Trailer length in mm (used by DTP41T) */
+int trans, /* Use transmission mode */
+int emis, /* Use emissive mode */
+int displ, /* 1 = Use display emissive mode, 2 = display bright rel. */
+ /* 3 = display white rel. */
+int dtype, /* Display type selection charater */
+inst_opt_filter fe, /* Optional filter */
+int nocal, /* Disable initial calibration */
+int disbidi, /* Disable automatic bi-directional strip recognition */
+int highres, /* Use high res spectral mode */
+char *ccxxname, /* Colorimeter Correction/Colorimeter Calibration name */
+icxObserverType obType, /* ccss observer */
+double scan_tol, /* Modify patch consistency tolerance */
+int pbypatch, /* Patch by patch measurement */
+int xtern, /* Use external (user supplied) values rather than instument read */
+int spectral, /* Generate spectral info flag */
+int uvmode, /* ~~~ i1pro2 test mode ~~~ */
+int accurate_expd, /* Expected values can be assumed to be accurate */
+int emit_warnings, /* Emit warnings for wrong strip, unexpected value */
+a1log *log /* verb, debug & error log */
+) {
+ inst *it = NULL;
+ inst_mode cap; /* Mode capability */
+ inst2_capability cap2;
+ inst3_capability cap3;
+ int n, i, j;
+ int rmode = 0; /* Read mode, 0 = spot, 1 = strip, 2 = xy, 3 = chart */
+ int svdmode = 0; /* Saved mode, 0 = no, 1 = use saved mode */
+ inst_code rv;
+ baud_rate br = baud_38400; /* Target baud rate */
+ int skipp = 0; /* Initial strip readings to skip */
+ int nextrap = 0; /* Number of extra patches for max and min */
+ int ch;
+
+ if (xtern == 0) { /* Use instrument values */
+
+ /* Instrument that the chart is set up for */
+ if (itype == instDTP51) {
+ skipp = 1; /* First reading is the Max density patch */
+ nextrap = 2;
+ }
+
+ if ((it = new_inst(ipath, 0, log, DUIH_FUNC_AND_CONTEXT)) == NULL) {
+ printf("Unknown, inappropriate or no instrument detected\n");
+ return -1;
+ }
+ /* Establish communications */
+ if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
+ printf("Establishing communications with instrument failed with message '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ /* set filter configuration before initialising/calibrating */
+ if (fe != inst_opt_filter_unknown) {
+ if ((rv = it->get_set_opt(it, inst_opt_set_filter, fe)) != inst_ok) {
+ printf("Setting filter configuration not supported by instrument\n");
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* Set it up the way we want */
+ if ((rv = it->init_inst(it)) != inst_ok) {
+ printf("Initialising instrument failed with message '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ *atype = it->get_itype(it); /* Actual instrument type */
+ if (*atype != itype)
+ a1logv(log, 1, "Warning: chart is for %s, using instrument %s\n",inst_name(itype),inst_name(*atype));
+
+ {
+ int ccssset = 0;
+ inst_mode mode = 0;
+
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ if (trans) {
+ if (!IMODETST(cap, inst_mode_transmission)) {
+ printf("Need transmission reading capability,\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+
+ } else if (emis || displ) {
+
+ if (emis) {
+ if (!IMODETST(cap, inst_mode_emis_spot)
+ && !IMODETST(cap, inst_mode_emis_strip)) {
+ printf("Need emissive spot or strip reading capability\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+ } else {
+ /* Should we allow for non-adaptive mode ? */
+ if (!IMODETST(cap, inst_mode_emis_spot)) {
+ printf("Need emissive reading capability\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+ }
+
+ } else {
+ if (!IMODETST(cap, inst_mode_reflection)) {
+ printf("Need reflection spot, strip, xy or chart reading capability,\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* Set display type */
+ if (dtype != 0) {
+
+ if (cap2 & inst2_disptype) {
+ int ix;
+ if ((ix = inst_get_disptype_index(it, dtype, 0)) < 0) {
+ printf("Setting display type ix %d failed\n",ix);
+ it->del(it);
+ return -1;
+ }
+
+ if ((rv = it->set_disptype(it, ix)) != inst_ok) {
+ printf("Setting display type ix %d not supported by instrument\n",ix);
+ it->del(it);
+ return -1;
+ }
+ } else
+ printf("Display type ignored - instrument doesn't support display type\n");
+ }
+
+ if (spectral && !IMODETST(cap, inst_mode_spectral)) {
+ printf("Warning: Instrument isn't capable of spectral measurement\n");
+ spectral = 0;
+ }
+
+ /* Colorimeter Correction Matrix */
+ if (ccxxname[0] != '\000') {
+ ccss *cs = NULL;
+ ccmx *cx = NULL;
+
+ if ((cx = new_ccmx()) == NULL) {
+ printf("\nnew_ccmx failed\n");
+ it->del(it);
+ return -1;
+ }
+ if (cx->read_ccmx(cx,ccxxname) == 0) {
+ if ((cap2 & inst2_ccmx) == 0) {
+ printf("\nInstrument doesn't have Colorimeter Correction Matrix capability\n");
+ it->del(it);
+ return -1;
+ }
+ if ((rv = it->col_cor_mat(it, cx->matrix)) != inst_ok) {
+ printf("\nSetting Colorimeter Correction Matrix failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ cx->del(cx);
+ it->del(it);
+ return -1;
+ }
+ cx->del(cx);
+ } else {
+ cx->del(cx);
+ cx = NULL;
+
+ /* CCMX failed, try CCSS */
+ if ((cs = new_ccss()) == NULL) {
+ printf("\nnew_ccss failed\n");
+ it->del(it);
+ return -1;
+ }
+ if (cs->read_ccss(cs,ccxxname)) {
+ printf("\nReading CCMX/CCSS File '%s' failed with error %d:'%s'\n",
+ ccxxname, cs->errc, cs->err);
+ cs->del(cs);
+ it->del(it);
+ return -1;
+ }
+ if ((cap2 & inst2_ccss) == 0) {
+ printf("\nInstrument doesn't have Colorimeter Calibration Spectral Sample capability\n");
+ cs->del(cs);
+ it->del(it);
+ return -1;
+ }
+ if ((rv = it->get_set_opt(it, inst_opt_set_ccss_obs, obType, NULL)) != inst_ok) {
+ printf("\nSetting CCSS observer failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ cs->del(cs);
+ it->del(it);
+ return -1;
+ }
+ if ((rv = it->col_cal_spec_set(it, cs->samples, cs->no_samp)) != inst_ok) {
+ printf("\nSetting Colorimeter Calibration Spectral Samples failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ cs->del(cs);
+ it->del(it);
+ return -1;
+ }
+ ccssset = 1;
+ cs->del(cs);
+ }
+ }
+
+ /* If non-standard observer wasn't set by a CCSS file above */
+ if (obType != icxOT_default && (cap2 & inst2_ccss) && ccssset == 0) {
+ if ((rv = it->get_set_opt(it, inst_opt_set_ccss_obs, obType, NULL)) != inst_ok) {
+ printf("\nSetting CCSS observer failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* Disable initial calibration of machine if selected */
+ if (nocal != 0){
+ if ((rv = it->get_set_opt(it,inst_opt_noinitcalib, 0)) != inst_ok) {
+ printf("Setting no-initial calibrate failed with '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ printf("Disable inital-calibrate not supported\n");
+ }
+ }
+
+ /* If it battery powered, show the status of the battery */
+ if ((cap2 & inst2_has_battery)) {
+ double batstat = 0.0;
+ if ((rv = it->get_set_opt(it, inst_stat_battery, &batstat)) != inst_ok) {
+ printf("\nGetting instrument battery status failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ printf("The battery charged level is %.0f%%\n",batstat * 100.0);
+ }
+
+ /* Set it to the appropriate mode */
+ if (highres) {
+ if (IMODETST(cap, inst_mode_highres)) {
+ inst_code ev;
+ if ((ev = it->get_set_opt(it, inst_opt_highres)) != inst_ok) {
+ printf("\nSetting high res mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+ highres = 1;
+ } else {
+ a1logv(log, 1, "high resolution ignored - instrument doesn't support high res. mode\n");
+ }
+ }
+
+ if (scan_tol != 1.0) {
+ if (cap2 & inst2_has_scan_toll) {
+ inst_code ev;
+ if ((ev = it->get_set_opt(it, inst_opt_scan_toll, scan_tol)) != inst_ok) {
+ printf("\nSetting patch consistency tolerance to %f failed with error :'%s' (%s)\n",
+ scan_tol, it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+ highres = 1;
+ } else {
+ a1logv(log, 1, "Modified patch consistency tolerance ignored - instrument doesn't support it\n");
+ }
+ }
+
+ /* Should look at instrument type & user spec ??? */
+ if (trans) {
+ if (pbypatch && IMODETST(cap, inst_mode_trans_spot)
+ && it->check_mode(it, inst_mode_trans_spot) == inst_ok) {
+ mode = inst_mode_trans_spot;
+ rmode = 0;
+ } else if (IMODETST(cap, inst_mode_trans_chart)
+ && it->check_mode(it, inst_mode_trans_chart) == inst_ok) {
+ mode = inst_mode_trans_chart;
+ rmode = 3;
+ } else if (IMODETST(cap, inst_mode_trans_xy)
+ && it->check_mode(it, inst_mode_trans_xy) == inst_ok) {
+ mode = inst_mode_trans_xy;
+ rmode = 2;
+ } else if (IMODETST(cap, inst_mode_trans_strip)
+ && it->check_mode(it, inst_mode_trans_strip) == inst_ok) {
+ mode = inst_mode_trans_strip;
+ rmode = 1;
+ } else {
+ mode = inst_mode_trans_spot;
+ rmode = 0;
+ }
+ } else if (displ) {
+ /* We assume a display mode will always be spot by spot */
+ mode = inst_mode_emis_spot;
+ rmode = 0;
+ } else if (emis) {
+ if (pbypatch && IMODETST(cap, inst_mode_emis_spot)
+ && it->check_mode(it, inst_mode_emis_spot) == inst_ok) {
+ mode = inst_mode_emis_spot;
+ rmode = 0;
+ } else if (IMODETST(cap, inst_mode_emis_strip)
+ && it->check_mode(it, inst_mode_emis_strip) == inst_ok) {
+ mode = inst_mode_emis_strip;
+ rmode = 1;
+ } else {
+ mode = inst_mode_emis_spot;
+ rmode = 0;
+ }
+ } else {
+ inst_stat_savdrd sv = inst_stat_savdrd_none;
+
+ /* See if instrument has a saved mode, and if it has data that */
+ /* could match this chart */
+ if (IMODETST(cap, inst_mode_s_reflection)) {
+
+ a1logv(log, 2, "Instrument has a svaed chart mode\n");
+
+ if ((rv = it->get_set_opt(it, inst_stat_saved_readings, &sv)) != inst_ok) {
+ printf("Getting saved reading status failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ if (sv & inst_stat_savdrd_chart) {
+ int no_patches, no_rows, pat_per_row, chart_id, missing_row;
+
+ a1logv(log, 2, "There is a saved chart\n");
+
+ if ((rv = it->get_set_opt(it, inst_stat_s_chart,
+ &no_patches, &no_rows, &pat_per_row, &chart_id, &missing_row))
+ != inst_ok) {
+ printf("Getting saved chart details failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ if (npat != no_patches || totpa != no_rows
+ || stipa != pat_per_row || rstart != chart_id) {
+ printf("Can't use saved chart because it doesn't match\n");
+ sv &= ~inst_stat_savdrd_chart;
+ }
+
+ if (missing_row >= 0) {
+ printf("Can't use saved chart because row %d hasn't been read\n",missing_row);
+ sv &= ~inst_stat_savdrd_chart;
+ }
+ }
+
+ if (sv & inst_stat_savdrd_xy) {
+ int nstr;
+ int no_sheets, no_patches, no_rows, pat_per_row;
+
+ /* Count the number of strips (sheets) */
+ for (nstr = 0; pis[nstr] != 0; nstr++)
+ ;
+
+ if ((rv = it->get_set_opt(it, inst_stat_s_xy,
+ &no_sheets, &no_patches, &no_rows, &pat_per_row)) != inst_ok) {
+ printf("Getting saved sheet details failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ if (nstr != no_sheets || npat != no_patches
+ || totpa != no_rows || stipa != pat_per_row) {
+ a1logv(log, 1, "Can't use saved sheets because they don't match chart\n");
+ a1logv(log, 1, "Got %d sheets, expect %d. Got %d patches, expect %d.\n",
+ no_sheets,nstr,no_patches,npat);
+ a1logv(log, 1, "Got %d rows, expect %d. Got %d patches per row, expect %d.\n",
+ no_rows,totpa,pat_per_row,stipa);
+ sv &= ~inst_stat_savdrd_xy;
+ }
+ }
+
+ if (sv & inst_stat_savdrd_strip) {
+ int no_patches, no_rows, pat_per_row;
+
+ if ((rv = it->get_set_opt(it, inst_stat_s_strip,
+ &no_patches, &no_rows, &pat_per_row)) != inst_ok) {
+ printf("Getting saved strip details failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ if (npat != no_patches || totpa != no_rows || stipa != pat_per_row) {
+ a1logv(log, 1, "Can't use saved strips because they don't match chart\n");
+ sv &= ~inst_stat_savdrd_strip;
+ }
+ }
+
+ if (sv & inst_stat_savdrd_spot) {
+ int no_patches;
+
+ if ((rv = it->get_set_opt(it, inst_stat_s_spot, &no_patches)) != inst_ok) {
+ printf("Getting saved spot details failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ if (npat != no_patches) {
+ a1logv(log, 1, "Can't use saved spots because they don't match chart - got %d patches, expect %d\n",no_patches,npat);
+ sv &= ~inst_stat_savdrd_spot;
+ }
+ }
+ }
+
+ if (pbypatch
+ && IMODETST(cap, inst_mode_s_ref_spot)
+ && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok
+ && (sv & inst_stat_savdrd_spot)) {
+ mode = inst_mode_s_ref_spot;
+ svdmode = 1;
+ rmode = 0;
+
+ } else if (IMODETST(cap, inst_mode_s_ref_chart)
+ && it->check_mode(it, inst_mode_s_ref_chart) == inst_ok
+ && (sv & inst_stat_savdrd_chart)) {
+ mode = inst_mode_s_ref_chart;
+ svdmode = 1;
+ rmode = 3;
+
+ } else if (IMODETST(cap, inst_mode_s_ref_xy)
+ && it->check_mode(it, inst_mode_s_ref_xy) == inst_ok
+ && (sv & inst_stat_savdrd_xy)) {
+ mode = inst_mode_s_ref_xy;
+ svdmode = 1;
+ rmode = 2;
+
+ } else if (IMODETST(cap, inst_mode_s_ref_strip)
+ && it->check_mode(it, inst_mode_s_ref_strip) == inst_ok
+ && (sv & inst_stat_savdrd_strip)) {
+ mode = inst_mode_s_ref_strip;
+ svdmode = 1;
+ rmode = 1;
+
+ } else if (IMODETST(cap, inst_mode_s_ref_spot)
+ && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok
+ && (sv & inst_stat_savdrd_spot)) {
+ mode = inst_mode_s_ref_spot;
+ svdmode = 1;
+ rmode = 0;
+
+ } else if (pbypatch && IMODETST(cap, inst_mode_ref_spot)
+ && it->check_mode(it, inst_mode_ref_spot) == inst_ok) {
+ mode = inst_mode_ref_spot;
+ rmode = 0;
+
+ } else if (IMODETST(cap, inst_mode_ref_chart)
+ && it->check_mode(it, inst_mode_ref_chart) == inst_ok) {
+ mode = inst_mode_ref_chart;
+ rmode = 3;
+
+ } else if (IMODETST(cap, inst_mode_ref_xy)
+ && it->check_mode(it, inst_mode_ref_xy) == inst_ok) {
+ mode = inst_mode_ref_xy;
+ rmode = 2;
+
+ } else if (IMODETST(cap, inst_mode_ref_strip)
+ && it->check_mode(it, inst_mode_ref_strip) == inst_ok) {
+ mode = inst_mode_ref_strip;
+ rmode = 1;
+
+ } else {
+ mode = inst_mode_ref_spot;
+ rmode = 0;
+ }
+ }
+ if (spectral)
+ mode |= inst_mode_spectral;
+
+ // ~~~ i1pro2 test code ~~~ */
+ if (uvmode) {
+ if (!IMODETST(cap, inst_mode_ref_uv)) {
+ warning("UV measurement mode requested, but instrument doesn't support this mode");
+ uvmode = 0;
+ } else {
+ mode |= inst_mode_ref_uv;
+ }
+ }
+
+ if ((rv = it->set_mode(it, mode)) != inst_ok) {
+ printf("\nSetting instrument mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ it->capabilities(it, &cap, &cap2, &cap3);
+ }
+ }
+
+ /* -------------------------------------------------- */
+ if (rmode == 3) { /* For chart mode, read all at once */
+ int chid; /* Chart ID number */
+ ipatch *vals; /* Array of values */
+
+ if (svdmode)
+ printf("Reading chart from values saved in instrument\n");
+ else {
+ /* ~~999 ??? Need to setup trigger and wait for it appropriately ??? */
+ printf("Reading the whole chart in one go\n");
+ }
+
+ /* Allocate space for patches */
+ if ((vals = (ipatch *)calloc(sizeof(ipatch), npat)) == NULL)
+ error("Malloc failed!");
+
+ /* Initialise return values */
+ for (i = 0; i < npat; i++) {
+ strncpy(vals[i].loc, scols[i]->loc, ICOM_MAX_LOC_LEN-1);
+ vals[i].loc[ICOM_MAX_LOC_LEN-1] = '\000';
+ vals[i].XYZ_v = 0;
+ }
+
+ for (;;) { /* retry loop */
+ if ((rv = it->read_chart(it, npat, totpa, stipa, pis, rstart, vals)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ free(vals);
+ it->del(it);
+ return -1;
+ }
+
+ printf("Chart read OK\n");
+
+ /* Transfer the values */
+ /* We assume they are all in the right order */
+ for (i = 0; i < npat; i++) {
+ /* Copy XYZ */
+ if (vals[i].XYZ_v == 0)
+ error("Instrument didn't return XYZ value for patch %d, loc %s",i,scols[i]->loc);
+ for (j = 0; j < 3; j++)
+ scols[i]->XYZ[j] = vals[i].XYZ[j];
+
+ /* Copy spectral */
+ if (vals[i].sp.spec_n > 0) {
+ scols[i]->sp = vals[i].sp;
+ }
+ scols[i]->mtype = vals[i].mtype;
+ scols[i]->rr = 1; /* Has been read */
+ }
+ free(vals);
+
+ /* -------------------------------------------------- */
+ /* !!! Hmm. Should really allow user to navigate amongst the sheets, */
+ /* !!! and skip any sheets already read. */
+ } else if (rmode == 2) { /* For xy mode, read each sheet */
+ ipatch *vals;
+ int nsheets, sheet; /* Total sheets/current sheet (sheet == pass) */
+ int rpat = npat; /* Remaining total patches */
+ int pai; /* Overall pass index */
+ int sti; /* Overall step index */
+ char *pn[3] = { NULL, NULL, NULL} ; /* Location 1/2/3 Pass name (letters) */
+ char *sn[3] = { NULL, NULL, NULL} ; /* Location 1/2/3 Step name (numbers) */
+ int k;
+
+ { /* Figure the maximum number sheets and of patches in a sheet, for allocation */
+ int lpaist = 0; /* Largest number of passes in strip/sheet */
+ for (nsheets = 0; pis[nsheets] != 0; nsheets++) {
+ if (pis[nsheets] > lpaist)
+ lpaist = pis[nsheets];
+ }
+
+ if ((vals = (ipatch *)calloc(sizeof(ipatch), (lpaist * stipa))) == NULL)
+ error("Malloc failed!");
+ }
+
+ /* Make sure we can access the instrument table */
+ if (cap2 & inst2_xy_holdrel) {
+ it->xy_clear(it);
+ }
+
+ /* XY mode doesn't use the trigger mode */
+
+ /* For each pass (==sheet) */
+ for (sheet = 1, pai = sti = 0; pis[sheet-1] != 0; sheet++) {
+ int paist; /* Passes in current Strip (== columns in current sheet) */
+ int rnpatch; /* Rounded up (inc. padding) Patches in current pass (sheet) */
+ int npatch; /* Patches in pass (sheet), excluding padding */
+ int fspipa; /* First pass steps in pass */
+ int nloc; /* Number of fiducial locations needed */
+ double ox = 0.0, oy = 0.0; /* Origin */
+ double ax = 1.0, ay = 0.0; /* pass increment */
+ double aax = 0.0, aay = 0.0; /* pass offset for hex odd steps */
+ double px = 0.0, py = 1.0; /* step (==patch) increment */
+
+ fspipa = stipa;
+ paist = pis[sheet-1]; /* columns (letters) in sheet (strip) */
+ npatch = rnpatch = paist * stipa; /* Total patches including padding */
+ if (npatch > rpat) { /* This is a non-full pass */
+ if (paist == 1) {
+ fspipa -= (npatch - rpat);/* Last patch in first strip */
+ if (fspipa < 1)
+ error ("Assert in read_strips, fspipa = %d",fspipa);
+ }
+ npatch = rpat; /* Total patches excluding padding */
+ }
+
+ nloc = 3;
+ if (paist == 1) {
+ nloc = 2; /* Only one strip, so only 2 locations needed */
+ if (fspipa == 1)
+ nloc = 1; /* Only one strip, one patch, so one location */
+ }
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ pn[0] = paix->aix(paix, pai); /* First pass (letter) */
+ sn[0] = saix->aix(saix, 0); /* First step (patch) (number) */
+ pn[1] = paix->aix(paix, pai); /* First pass (letter) */
+ sn[1] = saix->aix(saix, 0 + fspipa-1); /* Last step (patch) (number) */
+ pn[2] = paix->aix(paix, pai + paist-1); /* Last pass (letter) */
+ sn[2] = saix->aix(saix, 0); /* First step (patch) (number) */
+
+ empty_con_chars();
+ if (sheet == 1) {
+ printf("Please place sheet %d of %d on table, then\n",sheet, nsheets);
+ } else
+ printf("\nPlease remove previous sheet, then place sheet %d of %d on table, then\n",sheet, nsheets);
+ printf("hit return to continue, Esc or 'q' to give up"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+
+ if (cap2 & inst2_xy_holdrel) {
+
+ /* Hold table */
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_sheet_hold(it)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ it->del(it);
+ return -1;
+ }
+ }
+
+ if (cap2 & inst2_xy_locate) {
+ int ll;
+ double x[3], y[3];
+
+ /* Allow user location of points */
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_locate_start(it)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ it->del(it);
+ return -1;
+ }
+
+ /* For each location point */
+ for (ll = 0; ll < nloc; ll++) {
+ empty_con_chars();
+ printf("\nUsing the XY table controls, locate patch %s%s with the sight,\n",
+ pn[ll], sn[ll]);
+ printf("then hit return to continue, Esc or 'q' to give up"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_get_location(it, &x[ll], &y[ll])) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* We're done with user control */
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_locate_end(it)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ it->del(it);
+ return -1;
+ }
+
+ /* Convert point locations into navigation values */
+ ox = x[0];
+ oy = y[0];
+ if (hex) {
+ double kk = sqrt(1.0/3.0);
+ double nn = fspipa - 1.0;
+ if (((fspipa-1) & 1) == 0) { /* [0] & [1] are lined up */
+ if (nloc == 3) {
+ px = (x[1] - x[0])/nn;
+ py = (y[1] - y[0])/nn;
+ ax = (x[2] - x[0])/(paist-1);
+ ay = (y[2] - y[0])/(paist-1);
+ aax = 0.5 * ax;
+ aay = 0.5 * ay;
+ } else if (nloc == 2) {
+ px = (x[1] - x[0])/nn;
+ py = (y[1] - y[0])/nn;
+ aax = kk * py; /* Scale and rotate */
+ aay = kk * -px;
+ }
+ } else { /* [0] & [1] are offset by aa[xy] */
+ if (nloc == 3) {
+ ax = (x[2] - x[0])/(paist-1);
+ ay = (y[2] - y[0])/(paist-1);
+ aax = 0.5 * ax;
+ aay = 0.5 * ay;
+ px = (x[1] - x[0] - aax)/nn;
+ py = (y[1] - y[0] - aay)/nn;
+ } else if (nloc == 2) {
+ px = (nn * (x[1] - x[0]) - kk * (y[1] - y[0]))/(kk * kk + nn * nn);
+ py = (nn * (y[1] - y[0]) + kk * (x[1] - x[0]))/(kk * kk + nn * nn);
+ aax = kk * py; /* Scale and rotate */
+ aay = kk * -px;
+ }
+ }
+
+ } else { /* Rectangular patches */
+ if (paist > 1) {
+ ax = (x[2] - x[0])/(paist-1);
+ ay = (y[2] - y[0])/(paist-1);
+ }
+ if (fspipa > 1) {
+ px = (x[1] - x[0])/(fspipa-1);
+ py = (y[1] - y[0])/(fspipa-1);
+ }
+ aax = aay = 0.0;
+ }
+ }
+
+ /* Read the sheets patches */
+ for (;;) { /* retry loop */
+ if ((rv = it->read_xy(it, paist, stipa, npatch, pn[0], sn[0],
+ ox, oy, ax, ay, aax, aay, px, py, vals)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ it->del(it);
+ return -1;
+ }
+
+ printf("Sheet %d of %d read OK\n",sheet, nsheets);
+
+ /* Transfer the values */
+ /* We assume they are all in the right order */
+ for (i = 0; i < npatch; i++, sti++) {
+ /* Copy XYZ */
+ if (vals[i].XYZ_v == 0)
+ error("Instrument didn't return XYZ value for patch %d, loc %s",i,scols[sti]->loc);
+ for (j = 0; j < 3; j++)
+ scols[sti]->XYZ[j] = vals[i].XYZ[j];
+
+ /* Copy spectral */
+ if (vals[i].sp.spec_n > 0) {
+ scols[sti]->sp = vals[i].sp;
+ }
+ scols[sti]->rr = 1; /* Has been read */
+ }
+
+ if (cap2 & inst2_xy_holdrel) {
+
+ /* Release table and reset head */
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_clear(it)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ it->del(it);
+ return -1;
+ }
+ }
+
+ pai += paist; /* Tracj next first pass in strip */
+ rpat -= npatch; /* Track remaining patches */
+ }
+ for (k = 0; k < 3; k++) {
+ if (pn[k] != NULL)
+ free(pn[k]);
+ if (sn[k] != NULL)
+ free(sn[k]);
+ }
+ free(vals);
+
+ printf("\nPlease remove last sheet from table\n"); fflush(stdout);
+
+ /* -------------------------------------------------- */
+ } else if (rmode == 1) { /* For strip mode, simply read each strip */
+ int uswitch = 0; /* 0 if switch can be used, 1 if switch or keyboard */
+ ipatch *vals; /* Values read for a strip pass */
+ int incflag = 0; /* 0 = no change, 1 = increment, 2 = inc unread, */
+ /* -1 = decrement, -2 = done */
+ int stix; /* Strip index */
+ int pai; /* Current pass in current strip */
+ int oroi; /* Overall row index */
+
+ /* Do any needed calibration before the user places the instrument on a desired spot */
+ if (it->needs_calibration(it) & inst_calt_n_dfrble_mask) {
+ if ((rv = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL))
+ != inst_ok) {
+ printf("\nCalibration failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* Enable switch or user via uicallback trigger if possible */
+ if (cap2 & inst2_user_switch_trig) {
+ rv = it->get_set_opt(it, inst_opt_trig_user_switch);
+ uswitch = 2;
+
+ /* Or use just switch trigger */
+ } else if (cap2 & inst2_switch_trig) {
+ rv = it->get_set_opt(it, inst_opt_trig_switch);
+ uswitch = 1;
+
+ /* Or go for user vi uicallback trigger */
+ } else if (cap2 & inst2_user_trig) {
+ rv = it->get_set_opt(it, inst_opt_trig_user);
+
+ /* Or something is wrong with instrument capabilities */
+ } else {
+ printf("\nNo reasonable trigger mode avilable for this instrument\n");
+ it->del(it);
+ return -1;
+ }
+ if (rv != inst_ok) {
+ printf("\nSetting trigger mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ /* Set so that return or any other key triggers, */
+ /* but retain our abort keys */
+ inst_set_uih(0x00, 0xff, DUIH_TRIG);
+ inst_set_uih('f', 'f', DUIH_CMND);
+ inst_set_uih('F', 'F', DUIH_CMND);
+ inst_set_uih('b', 'b', DUIH_CMND);
+ inst_set_uih('B', 'B', DUIH_CMND);
+ inst_set_uih('n', 'n', DUIH_CMND);
+ inst_set_uih('N', 'N', DUIH_CMND);
+ inst_set_uih('g', 'g', DUIH_CMND);
+ inst_set_uih('G', 'G', DUIH_CMND);
+ inst_set_uih('d', 'd', DUIH_CMND);
+ inst_set_uih('D', 'D', DUIH_CMND);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
+ inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
+
+ /* Allocate space for values from a pass/strip */
+ if ((vals = (ipatch *)calloc(sizeof(ipatch), (stipa+nextrap))) == NULL)
+ error("Malloc failed!");
+
+ /* Until we're done reading rows */
+ incflag = 0;
+
+ /* Skip to next unread if first has been read */
+ if (pis[0] != 0 && scols[0]->rr != 0)
+ incflag = 2;
+
+ for (oroi = stix = pai = 0;pis[0] != 0;) {
+ char *nn = NULL; /* Pass name */
+ int guide;
+ chcol **scb;
+ int boff = 0; /* Best offset */
+ int bdir = 0; /* Best overall direction */
+ int done = 0; /* nz if there are no unread rows */
+
+//printf("\n~1 incflag = %d, oroi %d, pai %d, stix %d\n", incflag, oroi, pai, stix);
+
+ /* Increment or decrement to the next row */
+ if (incflag > 0) {
+ int s_oroi = oroi;
+
+ /* Until we get to an unread pass */
+ for (;;) {
+ oroi++;
+ if (++pai >= pis[stix]) { /* Carry */
+ if (pis[++stix] == 0) { /* Carry */
+ stix = 0;
+ oroi = 0;
+ }
+ pai = 0;
+ }
+//printf("~1 stix = %d, pis[stix] = %d, oroi = %d, rr %d\n",stix, pis[stix],oroi,scols[oroi * stipa]->rr);
+ if (incflag == 1 || scols[oroi * stipa]->rr == 0 || oroi == s_oroi)
+ break;
+ }
+
+ /* Decrement the row */
+ } else if (incflag < 0) {
+ oroi--;
+ if (--pai < 0) { /* Carry */
+ if (--stix < 0) { /* Carry */
+ for (oroi = stix = 0; pis[stix] != 0; stix++) {
+ oroi += pis[stix];
+ }
+ stix--;
+ oroi--;
+ }
+ pai = pis[stix]-1;
+ }
+ }
+ incflag = 0;
+
+ /* See if there are any unread patches */
+ for (done = i = 0; i < npat; i += stipa) {
+ if (scols[i]->rr == 0)
+ break; /* At least one patch read */
+ }
+ if (i >= npat)
+ done = 1;
+
+//printf("~1 oroi %d, pai %d, stix %d pis[stix] %d, rr = %d\n", oroi, pai, stix, pis[stix],scols[oroi * stipa]->rr);
+ /* Convert overall pass number index into alpha label */
+ if (nn != NULL)
+ free(nn);
+ nn = paix->aix(paix, oroi);
+
+ guide = (pis[stix] - pai) * 5; /* Mechanical guide offset */
+
+ for (;;) { /* Until we give up reading this row */
+
+ /* Read a strip pass */
+ printf("\nReady to read strip pass %s%s\n",nn, done ? " (!! ALL ROWS READ !!)" : scols[oroi *stipa]->rr ? " (This row has been read)" : "" );
+ printf("Press 'f' to move forward, 'b' to move back, 'n' for next unread,\n");
+ printf(" 'd' when done, Esc or 'q' to quit without saving.\n");
+
+ if (uswitch == 1) {
+ printf("Trigger instrument switch to start reading,");
+ } else if (uswitch == 2) {
+ printf("Trigger instrument switch or any other key to start:");
+ } else {
+ printf("Press any other key to start:");
+ }
+ fflush(stdout);
+ if ((rv = it->read_strip(it, "STRIP", stipa+nextrap, nn, guide, plen, glen, tlen, vals)) != inst_ok
+ && (rv & inst_mask) != inst_user_trig) {
+
+#ifdef DEBUG
+ printf("read_strip returned '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+#endif /* DEBUG */
+ /* Deal with user abort or command */
+ if ((rv & inst_mask) == inst_user_abort) {
+ int keyc = inst_get_uih_char();
+
+ /* Deal with a command */
+ if (keyc & DUIH_CMND) {
+ ch = keyc & 0xff;
+
+ printf("\n");
+ if (ch == 'f' || ch == 'F') {
+ incflag = 1;
+ break;
+ } else if (ch == 'b' || ch == 'B') {
+ incflag = -1;
+ break;
+ } else if (ch == 'n' || ch == 'N') {
+ incflag = 2;
+ break;
+ } else { /* Assume 'd' or 'D' */
+
+ /* See if there are any unread patches */
+ for (done = i = 0; i < npat; i += stipa) {
+ if (scols[i]->rr == 0)
+ break; /* At least one patch read */
+ }
+ if (i >= npat)
+ done = 1;
+
+ if (done) {
+ incflag = -2;
+ break;
+ }
+
+ /* Not all rows have been read */
+ empty_con_chars();
+ printf("\nDone ? - At least one unread patch (%s), Are you sure [y/n]: ",
+ scols[i]->loc);
+ fflush(stdout);
+ ch = next_con_char();
+ printf("\n");
+ if (ch == 'y' || ch == 'Y') {
+ incflag = -2;
+ break;
+ }
+ continue;
+ }
+
+ /* Deal with a user abort */
+ } else if (keyc & DUIH_ABORT) {
+ empty_con_chars();
+ printf("\n\nStrip read stopped at user request!\n");
+ printf("Hit Esc or 'q' to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ continue;
+ }
+
+ /* Deal with needs calibration */
+ } else if ((rv & inst_mask) == inst_needs_cal) {
+ inst_code ev;
+
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ printf("\nStrip read failed because instruments needs calibration\n");
+ ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ it->del(it);
+ return -1;
+ }
+ continue;
+
+ /* Deal with a bad sensor position */
+ } else if ((rv & inst_mask) == inst_wrong_config) {
+ printf("\n\nSpot read failed due to the sensor being in the wrong position\n(%s)\n",it->interp_error(it, rv));
+ continue;
+
+ /* Deal with a misread */
+ } else if ((rv & inst_mask) == inst_misread) {
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ empty_con_chars();
+ printf("\nStrip read failed due to misread (%s)\n",it->interp_error(it, rv));
+ printf("Hit Esc to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ continue;
+ /* Deal with a communications error */
+ } else if ((rv & inst_mask) == inst_coms_fail) {
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ empty_con_chars();
+ printf("\nStrip read failed due to communication problem.\n");
+ printf("Hit Esc or 'q' to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ if (it->icom->port_type(it->icom) == icomt_serial) {
+ /* Allow retrying at a lower baud rate */
+ int tt = it->last_scomerr(it);
+ if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
+ if (br == baud_57600) br = baud_38400;
+ else if (br == baud_38400) br = baud_9600;
+ else if (br == baud_9600) br = baud_4800;
+ else if (br == baud_9600) br = baud_4800;
+ else if (br == baud_2400) br = baud_1200;
+ else br = baud_1200;
+ }
+ if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
+#ifdef DEBUG
+ printf("init_coms returned '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+#endif /* DEBUG */
+ it->del(it);
+ return -1;
+ }
+ }
+ continue;
+ } else {
+ /* Some other error. Treat it as fatal */
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ printf("\nStrip read failed due unexpected error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ printf("Hit Esc or 'q' to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ continue;
+ }
+
+ /* Successfully read the strip */
+ /* See which expected row best correlates with the one we've read. */
+ /* Figure out if there is an "off by one" error for a DTP51 */
+ } else {
+ int choroi; /* Check overall row index */
+ double corr; /* Correlation with expected value */
+ int loff = 0, hoff = 0; /* DTP51 offset test range */
+ int toff; /* Test offset */
+ int dir, dirrg = 1; /* Direction range, 1 = forward, 2 = fwd & bwd */
+
+ int boroi = -1; /* Best overall row index */
+
+ double bcorr = 1e6; /* Best correlation value */
+ double werror = 0.0; /* Worst case error in best correlation strip */
+
+ double xbcorr = 1e6; /* Expected pass correlation value */
+ int xboff; /* Expected pass offset */
+ int xbdir; /* Expected pass overall pass direction */
+ double xwerror = 0.0; /* Expected pass worst error in best strip */
+
+ if (disbidi == 0 && (cap2 & inst2_bidi_scan))
+ dirrg = 2; /* Enable bi-directional strip recognition */
+
+ /* DTP51 has a nasty habit of misaligning test squares by +/- 1 */
+ /* See if this might have happened */
+ if (it->itype == instDTP51) {
+ loff = -1;
+ hoff = 1;
+ }
+
+ for (choroi = 0; choroi < totpa; choroi++) {
+ /* Explore strip direction */
+ for (dir = 0; dir < dirrg; dir++) {
+ double pwerr; /* This rows worst error */
+ scb = &scols[choroi * stipa];
+
+ /* Explore off by +/-1 error for DTP51 */
+ for (toff = loff; toff <= hoff; toff++) {
+ double ynorm = 1.0;
+
+ /* Compute a Y scaling value to give correlation */
+ /* a chance for absolute readings */
+ if (vals[skipp+toff].XYZ_v != 0) {
+ double refnorm = 0.0;
+ ynorm = 0.0;
+ for (i = 0; i < stipa; i++) {
+ int ix = i+skipp+toff;
+ if (dir != 0)
+ ix = stipa - 1 - ix;
+ refnorm += scb[i]->eXYZ[1];
+ ynorm += vals[ix].XYZ[1];
+ }
+ ynorm = refnorm/ynorm;
+ }
+
+ /* Compare just sample patches (not padding Max/Min) */
+ for (pwerr = corr = 0.0, n = 0, i = 0; i < stipa; i++, n++) {
+ double vcorr;
+ int ix = i+skipp+toff;
+ if (dir != 0)
+ ix = stipa - 1 - ix;
+ if (vals[ix].XYZ_v == 0)
+ error("Instrument didn't return XYZ value");
+ vcorr = xyzLabDE(ynorm, vals[ix].XYZ, scb[i]->eXYZ);
+//printf("DE %f from vals[%d] %f %f %f and scols[%d] %f %f %f\n", vcorr, ix, vals[ix].XYZ[0], vals[ix].XYZ[1], vals[ix].XYZ[2], i + choroi * stipa, scb[i]->eXYZ[0], scb[i]->eXYZ[1], scb[i]->eXYZ[2]);
+ corr += vcorr;
+ if (vcorr > pwerr)
+ pwerr = vcorr;
+ }
+ corr /= (double)n;
+#ifdef DEBUG
+ printf(" Strip %d dir %d offset %d correlation = %f\n",choroi,dir,toff,corr);
+
+#endif
+ /* Expected strip correlation and */
+ /* best fir to off by 1 and direction */
+ if (choroi == oroi && corr < xbcorr) {
+ xbcorr = corr;
+ xboff = toff;
+ xbdir = dir;
+ xwerror = pwerr; /* Expected passes worst error */
+ }
+
+ /* Best matched strip correlation */
+ if (corr < bcorr) {
+ boroi = choroi;
+ bcorr = corr;
+ boff = toff;
+ bdir = dir;
+ werror = pwerr;
+ }
+ }
+ }
+ }
+ if (emit_warnings != 0 && boroi != oroi) { /* Looks like the wrong strip */
+ char *mm = NULL;
+ mm = paix->aix(paix, boroi);
+#ifdef DEBUG
+ printf("Strip pass %s (%d) seems to have a better correlation that strip %s (%d)\n",
+ mm, boroi, nn, oroi);
+#endif
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ empty_con_chars();
+ printf("\n(Warning) Seem to have read strip pass %s rather than %s!\n",mm,nn);
+ printf("Hit Return to use it anyway, any other key to retry, Esc or 'q' to give up:"); fflush(stdout);
+ free(mm);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ if (ch != 0x0d && ch != 0x0a) { /* !(CR or LF) */
+ printf("\n");
+ continue; /* Try again */
+ }
+ printf("\n");
+
+ /* Switch to state for expected strip */
+ bcorr = xbcorr;
+ boff = xboff;
+ bdir = xbdir;
+ werror = xwerror;
+ }
+ /* Arbitrary threshold. Good seems about 15-35, bad 95-130 */
+ if (emit_warnings != 0 && accurate_expd != 0 && werror >= 30.0) {
+#ifdef DEBUG
+ printf("(Warning) Patch error %f (>35 not good, >95 bad)\n",werror);
+#endif
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ empty_con_chars();
+ printf("\nThere is at least one patch with an very unexpected response! (DeltaE %f)\n",werror);
+ printf("Hit Return to use it anyway, any other key to retry, Esc or 'q' to give up:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ if (ch != 0x0d && ch != 0x0a) { /* !Cr */
+ printf("\n");
+ continue;
+ }
+ printf("\n");
+ break;
+ }
+
+ /* Must be OK - save the readings */
+ if (cap2 & inst2_no_feedback)
+ good_beep();
+ printf(" Strip read OK");
+ if (boff != 0)
+ printf(" (DTP51 offset fix of %d applied)",boff);
+ if (bdir != 0)
+ printf(" (Strip read in reverse direction)");
+ printf("\n");
+ break; /* Break out of retry loop */
+ }
+ }
+
+ if (nn != NULL) /* Finished with strip alpha index */
+ free(nn);
+ nn = NULL;
+
+ /* If we're done */
+ if (incflag == -2)
+ break;
+
+ /* If we are moving row, rather than having read one. */
+ if (incflag != 0)
+ continue;
+
+ /* Transfer the values (including DTP51 offset) */
+ scb = &scols[oroi * stipa];
+ for (n = 0, i = 0; i < stipa; i++, n++) {
+ int ix = i+skipp+boff;
+ if (bdir != 0)
+ ix = stipa - 1 - ix;
+
+ /* Copy XYZ */
+ if (vals[ix].XYZ_v == 0)
+ error("Instrument didn't return XYZ value");
+ for (j = 0; j < 3; j++)
+ scb[i]->XYZ[j] = vals[ix].XYZ[j];
+
+ /* Copy spectral */
+ if (vals[ix].sp.spec_n > 0) {
+ scb[i]->sp = vals[ix].sp;
+ }
+ scb[i]->rr = 1; /* Has been read */
+ }
+ incflag = 2; /* Skip to next unread */
+ } /* Go around to read another row */
+ free(vals);
+
+ /* -------------------------------------------------- */
+ /* Spot mode. This will be used if xtern != 0 */
+ } else {
+ int pix = 0;
+ int uswitch = 0; /* nz if switch can be used */
+ int incflag = 0; /* 0 = no change, 1 = increment, 2 = inc by 10, */
+ /* 3 = inc next unread, -1 = decrement, -2 = dec by 10 */
+ /* 4 = goto specific patch */
+ inst_opt_type omode; /* The option mode used */
+ ipatch val;
+
+ if (xtern == 0) { /* Instrument patch by patch */
+
+ /* Do any needed calibration before the user places the instrument on a desired spot */
+ if (it->needs_calibration(it) & inst_calt_n_dfrble_mask) {
+ if ((rv = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL))
+ != inst_ok) {
+ printf("\nCalibration failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* Enable switch or user via uicallback trigger if possible */
+ if (cap2 & inst2_user_switch_trig) {
+ omode = inst_opt_trig_user_switch;
+ rv = it->get_set_opt(it, omode);
+ uswitch = 1;
+
+ /* Or go for user via uicallback trigger */
+ } else if (cap2 & inst2_user_trig) {
+ omode = inst_opt_trig_user;
+ rv = it->get_set_opt(it, omode);
+
+ /* Or something is wrong with instrument capabilities */
+ } else {
+ printf("\nNo reasonable trigger mode avilable for this instrument\n");
+ it->del(it);
+ return -1;
+ }
+ if (rv != inst_ok) {
+ printf("\nSetting trigger mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ /* Setup the keyboard trigger to return our commands */
+ inst_set_uih('f', 'f', DUIH_CMND);
+ inst_set_uih('F', 'F', DUIH_CMND);
+ inst_set_uih('b', 'b', DUIH_CMND);
+ inst_set_uih('B', 'B', DUIH_CMND);
+ inst_set_uih('n', 'n', DUIH_CMND);
+ inst_set_uih('N', 'N', DUIH_CMND);
+ inst_set_uih('g', 'g', DUIH_CMND);
+ inst_set_uih('G', 'G', DUIH_CMND);
+ inst_set_uih('d', 'd', DUIH_CMND);
+ inst_set_uih('D', 'D', DUIH_CMND);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0xd, 0xd, DUIH_TRIG); /* Return */
+ inst_set_uih(' ', ' ', DUIH_TRIG);
+ }
+
+ /* Skip to next unread if first has been read */
+ /* !!! would be nice to skip padding patches !!! */
+ incflag = 0;
+ if (npat > 0 && scols[0]->rr != 0)
+ incflag = 3;
+
+ /* Until we're done */
+ for(;pix < npat;) {
+ char buf[200], *bp = NULL, *ep = NULL;
+ char ch = 0;
+
+ /* Adjust the location */
+ if (incflag > 0 && incflag <= 2) { /* Incremente by 1 or 10 */
+
+ if (incflag == 2)
+ pix += 10;
+ else
+ pix++;
+ pix = pix % npat;
+
+ } else if (incflag < 0 && incflag >= -2) { /* Decrement by 1 or 10 */
+
+ if (incflag == -2)
+ pix -= 10;
+ else
+ pix--;
+ pix = pix % npat;
+ if (pix < 0)
+ pix += npat;
+
+ } else if (incflag == 3) { /* Increment to next unread */
+ int opix = pix;
+
+ if (pix >= npat)
+ pix = 0;
+ for (;;) {
+ if (scols[pix]->rr == 0 && strcmp(scols[pix]->id, "0") != 0)
+ break;
+ pix++;
+ if (pix >= npat)
+ pix = 0;
+ if (pix == opix)
+ break;
+ }
+ } else if (incflag == 4) { /* Goto specific patch */
+ printf("\nEnter patch to go to: "); fflush(stdout);
+
+ /* Read in the next line from stdin. */
+ if (fgets(buf, 200, stdin) == NULL) {
+ printf("Error - unrecognised input\n");
+ } else {
+ int opix = pix;
+
+ /* Skip whitespace */
+ for (bp = buf; *bp != '\000' && isspace(*bp); bp++)
+ ;
+
+ /* Skip non-whitespace */
+ for (ep = bp; *ep != '\000' && !isspace(*ep); ep++)
+ ;
+ *ep = '\000';
+
+ if (pix >= npat)
+ pix = 0;
+ for (;;) {
+ if (stricmp(scols[pix]->loc, bp) == 0)
+ break;
+ pix++;
+ if (pix >= npat)
+ pix = 0;
+ if (pix == opix) {
+ printf("Patch '%s' not found\n",bp);
+ break;
+ }
+ }
+ }
+ }
+ incflag = 0;
+
+ /* See if there are any unread patches */
+ for (i = 0; i < npat; i++) {
+ if (scols[i]->rr == 0 && strcmp(scols[i]->id, "0") != 0)
+ break; /* At least one patch read */
+ }
+
+ if (xtern != 0) { /* User entered values */
+ printf("\nReady to read patch '%s'%s\n",scols[pix]->loc,
+ i >= npat ? "(All patches read!)" :
+ strcmp(scols[pix]->id, "0") == 0 ? " (Padding Patch)" :
+ scols[pix]->rr ? " (Already read)" : "");
+ printf("Enter %s value (separated by spaces), or\n",
+ xtern == 1 ? "L*a*b*" : "XYZ");
+ printf(" 'f' to move forward, 'F' move forward 10,\n");
+ printf(" 'b' to move back, 'B; to move back 10,\n");
+ printf(" 'n' for next unread, 'g' to goto patch,\n");
+ printf(" 'd' when done, 'q' to abort, then press <return>: ");
+ fflush(stdout);
+
+ /* Read in the next line from stdin. */
+ if (fgets(buf, 200, stdin) == NULL) {
+ printf("Error - unrecognised input\n");
+ continue;
+ }
+ /* Skip whitespace */
+ for (bp = buf; *bp != '\000' && isspace(*bp); bp++)
+ ;
+
+ ch = *bp;
+ if (ch == '\000') {
+ printf("Error - unrecognised input\n");
+ continue;
+ }
+
+ } else { /* Using instrument */
+
+ empty_con_chars();
+
+ printf("\nReady to read patch '%s'%s\n",scols[pix]->loc,
+ i >= npat ? "(All patches read!)" :
+ strcmp(scols[pix]->id, "0") == 0 ? " (Padding Patch)" :
+ scols[pix]->rr ? " (Already read)" : "");
+
+ printf("hit 'f' to move forward, 'F' move forward 10,\n");
+ printf(" 'b' to move back, 'B; to move back 10,\n");
+ printf(" 'n' for next unread, 'g' to goto patch,\n");
+ printf(" 'd' when done, <esc> to abort,\n");
+
+ if (uswitch)
+ printf(" Instrument switch, <return> or <space> to read:");
+ else
+ printf(" <return> or <space> to read:");
+ fflush(stdout);
+
+ rv = it->read_sample(it, "SPOT", &val, 1);
+
+ /* Deal with reading */
+ if (rv == inst_ok) {
+ /* Read OK */
+ if (cap2 & inst2_no_feedback)
+ good_beep();
+ ch = '0';
+
+ /* Deal with user trigger */
+ } else if ((rv & inst_mask) == inst_user_trig) {
+ if (cap2 & inst2_no_feedback)
+ good_beep();
+ ch = inst_get_uih_char();
+
+ /* Deal with a abort or command */
+ } else if ((rv & inst_mask) == inst_user_abort) {
+ int keyc = inst_get_uih_char();
+
+ /* User issued a command */
+ if (keyc & DUIH_CMND) {
+ ch = keyc & 0xff;
+ printf("\n");
+
+ /* User aborted */
+ } else if (keyc & DUIH_ABORT) {
+ empty_con_chars();
+ printf("\n\nSpot read stopped at user request!\n");
+ printf("Hit Esc or 'q' to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ continue;
+ }
+
+ /* Deal with needs calibration */
+ } else if ((rv & inst_mask) == inst_needs_cal) {
+ inst_code ev;
+
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ printf("\nSpot read failed because instruments needs calibration\n");
+ ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ it->del(it);
+ return -1;
+ }
+ continue;
+ /* Deal with a misread */
+ } else if ((rv & inst_mask) == inst_misread) {
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ empty_con_chars();
+ printf("\nStrip read failed due to misread (%s)\n",it->interp_error(it, rv));
+ printf("Hit Esc or 'q' to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ continue;
+ /* Deal with a communications error */
+ } else if ((rv & inst_mask) == inst_coms_fail) {
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ empty_con_chars();
+ printf("\nStrip read failed due to communication problem.\n");
+ printf("Hit Esc or 'q' to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ if (it->icom->port_type(it->icom) == icomt_serial) {
+ /* Allow retrying at a lower baud rate */
+ int tt = it->last_scomerr(it);
+ if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
+ if (br == baud_57600) br = baud_38400;
+ else if (br == baud_38400) br = baud_9600;
+ else if (br == baud_9600) br = baud_4800;
+ else if (br == baud_9600) br = baud_4800;
+ else if (br == baud_2400) br = baud_1200;
+ else br = baud_1200;
+ }
+ if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
+#ifdef DEBUG
+ printf("init_coms returned '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+#endif /* DEBUG */
+ it->del(it);
+ return -1;
+ }
+ }
+ continue;
+
+
+ } else {
+ /* Some other error. Treat it as fatal */
+ if (cap2 & inst2_no_feedback)
+ bad_beep();
+ printf("\nPatch read failed due unexpected error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ printf("Hit Esc or 'q' to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ continue;
+ }
+ }
+
+ if (ch == 'q' || ch == 0x1b || ch == 0x03) { /* q or Esc or ^C */
+ empty_con_chars();
+ printf("\nAbort ? - Are you sure ? [y/n]:"); fflush(stdout);
+ if ((ch = next_con_char()) == 'y' || ch == 'Y') {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ continue;
+ } else if (ch == 'f') {
+ incflag = 1;
+ continue;
+ } else if (ch == 'F') {
+ incflag = 2;
+ continue;
+ } else if (ch == 'b') {
+ incflag = -1;
+ continue;
+ } else if (ch == 'B') {
+ incflag = -2;
+ continue;
+ } else if (ch == 'n' || ch == 'N') {
+ incflag = 3;
+ continue;
+ } else if (ch == 'g' || ch == 'G') {
+ incflag = 4;
+ continue;
+ } else if (ch == 'd' || ch == 'D') {
+ int i;
+ for (i = 0; i < npat; i++) {
+ if (scols[i]->rr == 0 && strcmp(scols[i]->id, "0") != 0)
+ break;
+ }
+ if (i >= npat)
+ break; /* None unread, so done */
+
+ /* Not all patches have been read */
+ empty_con_chars();
+ printf("\nDone ? - At least one unread patch (%s), Are you sure [y/n]: ",
+ scols[i]->loc);
+ fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b) {
+ printf("\n");
+ it->del(it);
+ return -1;
+ }
+ printf("\n");
+ if (ch == 'y' || ch == 'Y')
+ break;
+ continue;
+
+ /* Read the external sample */
+ } else if (xtern != 0 && (isdigit(*bp) || ch == '-' || ch == '+' || ch == '.')) {
+ int i;
+
+ /* For each input number */
+ for (i = 0; *bp != '\000' && i < 3; i++) {
+ char *tp, *nbp;
+
+ /* Find the start of the number */
+ while(*bp != '\000' && !isdigit(*bp)
+ && *bp != '-' && *bp != '+' && *bp != '.')
+ bp++;
+ if (!isdigit(*bp) && *bp != '-' && *bp != '+' && *bp != '.')
+ break;
+
+ /* Find the end of the number */
+ for (tp = bp+1; isdigit(*tp) || *tp == 'e' || *tp == 'E'
+ || *tp == '-' || *tp == '+' || *tp == '.'; tp++)
+ ;
+ if (*tp != '\000')
+ nbp = tp+1;
+ else
+ nbp = tp;
+ *tp = '\000';
+
+ /* Read the number */
+ scols[pix]->XYZ[i] = atof(bp);
+
+ bp = nbp;
+ }
+ if (i < 3) { /* Didn't find 3 numbers */
+ printf("Error - unrecognised input\n");
+ continue;
+ }
+ if (xtern == 1) {
+ icmLab2XYZ(&icmD50, scols[pix]->XYZ,scols[pix]->XYZ);
+ scols[pix]->XYZ[0] *= 100.0;
+ scols[pix]->XYZ[1] *= 100.0;
+ scols[pix]->XYZ[2] *= 100.0;
+ }
+
+ scols[pix]->rr = 1; /* Has been read */
+ printf(" Got XYZ value %f %f %f\n",scols[pix]->XYZ[0], scols[pix]->XYZ[1], scols[pix]->XYZ[2]);
+
+ /* Advance to next patch. */
+ incflag = 1;
+
+ /* We've read the spot sample */
+ } else if (xtern == 0 && (ch == '0' || ch == ' ' || ch == '\r')) {
+
+ /* Save the reading */
+ if (val.XYZ_v == 0)
+ error("Instrument didn't return XYZ value");
+
+ for (j = 0; j < 3; j++)
+ scols[pix]->XYZ[j] = val.XYZ[j];
+
+ /* Copy spectral */
+ if (val.sp.spec_n > 0) {
+ scols[pix]->sp = val.sp;
+ }
+ scols[pix]->rr = 1; /* Has been read */
+ printf(" Patch read OK\n");
+ /* Advance to next patch. */
+ incflag = 1;
+ } else { /* Unrecognised response */
+ continue;
+ }
+ }
+ }
+ /* clean up */
+ if (it != NULL)
+ it->del(it);
+ return 0;
+}
+
+void
+usage() {
+ icompaths *icmps;
+ inst2_capability cap2 = 0;
+ fprintf(stderr,"Read Target Test Chart, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: chartread [-options] outfile\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -c listno Set communication port from the following list (default %d)\n",COMPORT);
+ if ((icmps = new_icompaths(NULL)) != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
+ }
+ } else
+ fprintf(stderr," ** No ports found **\n");
+ }
+ 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);
+ 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");
+ fprintf(stderr," -n Don't save spectral information (default saves spectral)\n");
+ fprintf(stderr," -l Save CIE as D50 L*a*b* rather than XYZ\n");
+ fprintf(stderr," -L Save CIE as D50 L*a*b* as well as XYZ\n");
+ fprintf(stderr," -r Resume reading partly read chart\n");
+ fprintf(stderr," -I file.cal Override calibration info from .ti2 in resulting .ti3\n");
+ fprintf(stderr," -F filter Set filter configuration (if aplicable):\n");
+ fprintf(stderr," n None\n");
+ fprintf(stderr," p Polarising filter\n");
+ fprintf(stderr," 6 D65\n");
+ fprintf(stderr," u U.V. Cut\n");
+ fprintf(stderr," -N Disable initial calibration of instrument if possible\n");
+ fprintf(stderr," -B Disable auto bi-directional strip recognition\n");
+ fprintf(stderr," -H Use high resolution spectrum mode (if available)\n");
+ if (cap2 & inst2_ccmx)
+ fprintf(stderr," -X file.ccmx Apply Colorimeter Correction Matrix\n");
+ if (cap2 & inst2_ccss) {
+ int i;
+ fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n");
+ fprintf(stderr," -Q observ Choose CIE Observer for CCSS instrument:\n");
+ fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
+ }
+ fprintf(stderr," -T ratio Modify strip patch consistency tolerance by ratio\n");
+ fprintf(stderr," -S Suppress wrong strip & unexpected value warnings\n");
+// fprintf(stderr," -Y U Test i1pro2 UV measurement mode\n");
+ fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
+ fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
+ fprintf(stderr," outfile Base name for input[ti2]/output[ti3] file\n");
+ if (icmps != NULL)
+ icmps->del(icmps);
+ exit(1);
+ }
+
+int main(int argc, char *argv[]) {
+ int i, j;
+ int fa, nfa, mfa; /* current argument we're looking at */
+ int verb = 0;
+ int debug = 0;
+ int comport = COMPORT; /* COM port used */
+ icompaths *icmps = NULL;
+ icompath *ipath = NULL;
+ flow_control fc = fc_nc; /* Default flow control */
+ instType itype = instUnknown; /* Instrument chart is targeted to */
+ instType atype = instUnknown; /* Instrument used to read the chart */
+ int trans = 0; /* Use transmission mode */
+ int emis = 0; /* Use emissive mode */
+ int displ = 0; /* 1 = Use display emissive mode, 2 = display bright rel. */
+ /* 3 = display white rel. */
+ int dtype = 0; /* Display type selection charater */
+ inst_opt_filter fe = inst_opt_filter_unknown;
+ int pbypatch = 0; /* Read patch by patch */
+ int disbidi = 0; /* Disable bi-directional strip recognition */
+ int highres = 0; /* Use high res mode if available */
+ double scan_tol = 1.0; /* Patch consistency tolerance modification */
+ int xtern = 0; /* Take external values, 1 = Lab, 2 = XYZ */
+ int spectral = 1; /* Save spectral information */
+ int uvmode = 0; /* ~~~ i1pro2 test mode ~~~ */
+ int accurate_expd = 0; /* Expected value assumed to be accurate */
+ int emit_warnings = 1; /* Emit warnings for wrong strip, unexpected value */
+ int dolab = 0; /* 1 = Save CIE as Lab, 2 = Save CIE as XYZ and Lab */
+ int doresume = 0; /* Resume reading a chart */
+ int nocal = 0; /* Disable initial calibration */
+ char ccxxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction/Colorimeter Calibration name */
+ icxObserverType obType = icxOT_default; /* ccss observer */
+ static char inname[MAXNAMEL+1] = { 0 }; /* Input cgats file base name */
+ static char outname[MAXNAMEL+1] = { 0 }; /* Output cgats file base name */
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ static char calname[MAXNAMEL+1] = { 0 }; /* User supplied calibration filename */
+ xcal *cal = NULL; /* Any calibration to be output as well */
+ int nmask = 0; /* Device colorant mask */
+ char *pixpat = "A-Z, A-Z"; /* Pass index pattern */
+ char *sixpat = "0-9,@-9,@-9;1-999"; /* Step index pattern */
+ alphix *paix, *saix; /* Pass and Step index generators */
+ int ixord = 0; /* Index order, 0 = pass then step */
+ int rstart = 0; /* Random start/chart id */
+ int hex = 0; /* Hexagon pattern layout */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ chcol *cols; /* Internal storage of all the patch colors */
+ chcol **scols; /* Location sorted pointers to cols */
+ int nchan = 0; /* Number of device chanels */
+ int npat; /* Number of overall patches */
+ int *pis; /* Passes in eachstrip, zero terminated */
+ int stipa; /* Steps in each Pass */
+ int totpa; /* Total Passes Needed */
+ int runpat; /* Rounded Up to (totpa * stipa) Number of patches */
+ int wpat; /* Set to index of white patch for display */
+ int si; /* Sample id index */
+ int li; /* Location id index */
+ int ti; /* Temp index */
+ int fi; /* Colorspace index */
+ double plen = 7.366, glen = 2.032, tlen = 18.8; /* Patch, gap and trailer length in mm */
+
+ set_exe_path(argv[0]); /* Set global exe_path and error_program */
+ check_if_not_interactive();
+
+ setup_spyd2(); /* Load firware if available */
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ mfa = 1; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbose */
+ else if (argv[fa][1] == 'v') {
+ verb = 1;
+ g_log->verb = verb;
+
+ /* No auto calibration */
+ } else if (argv[fa][1] == 'N')
+ nocal = 1;
+
+ /* Disable bi-directional strip recognition */
+ else if (argv[fa][1] == 'B')
+ disbidi = 1;
+
+ /* High res mode */
+ else if (argv[fa][1] == 'H')
+ highres = 1;
+
+ /* Colorimeter Correction Matrix or */
+ /* or Colorimeter Calibration Spectral Samples */
+ else if (argv[fa][1] == 'X') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage();
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+
+ /* CCSS Spectral Observer type */
+ } else if (argv[fa][1] == 'Q') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ obType = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ obType = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ obType = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ obType = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ obType = icxOT_Shaw_Fairchild_2;
+ } else
+ usage();
+ }
+
+ /* Scan tolerance ratio */
+ else if (argv[fa][1] == 'T') {
+ if (na == NULL)
+ usage();
+ scan_tol = atof(na);
+
+ /* Suppress warnings */
+ } else if (argv[fa][1] == 'S') {
+ emit_warnings = 0;
+
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (na[0] == 'n' || na[0] == 'N')
+ fc = fc_none;
+ else if (na[0] == 'h' || na[0] == 'H')
+ fc = fc_Hardware;
+ else if (na[0] == 'x' || na[0] == 'X')
+ fc = fc_XonXOff;
+ else
+ usage();
+
+
+ /* Debug coms */
+ } else if (argv[fa][1] == 'D') {
+ debug = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ debug = atoi(na);
+ fa = nfa;
+ }
+ g_log->debug = debug;
+
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+ if (na == NULL) usage();
+ comport = atoi(na);
+ if (comport < 1 || comport > 99) usage();
+
+ /* Request transmission measurement */
+ } else if (argv[fa][1] == 't') {
+ emis = 0;
+ trans = 1;
+ displ = 0;
+
+ /* Request display measurement */
+ } else if (argv[fa][1] == 'd') {
+
+ emis = 0;
+ trans = 0;
+ displ = 2;
+
+ /* Request emissive measurement */
+ } else if (argv[fa][1] == 'e') {
+ emis = 1;
+ trans = 0;
+ displ = 0;
+
+ /* Display type */
+ } else if (argv[fa][1] == 'y') {
+ fa = nfa;
+ if (na == NULL) usage();
+ dtype = na[0];
+
+ /* Request patch by patch measurement */
+ } else if (argv[fa][1] == 'p') {
+ pbypatch = 1;
+
+ /* Request external values */
+ } else if (argv[fa][1] == 'x') {
+ fa = nfa;
+ if (na == NULL) usage();
+
+ if (na[0] == 'l' || na[0] == 'L')
+ xtern = 1;
+ else if (na[0] == 'x' || na[0] == 'X')
+ xtern = 2;
+ else
+ usage();
+
+ /* Turn off spectral measurement */
+ } else if (argv[fa][1] == 'n')
+ spectral = 0;
+
+ /* Save as Lab */
+ else if (argv[fa][1] == 'l')
+ dolab = 1;
+
+ /* Save as Lab */
+ else if (argv[fa][1] == 'L')
+ dolab = 2;
+
+ /* Resume reading a chart */
+ else if (argv[fa][1] == 'r')
+ doresume = 1;
+
+ /* Printer calibration info */
+ else if (argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ strncpy(calname,na,MAXNAMEL); calname[MAXNAMEL] = '\000';
+
+ /* Filter configuration */
+ } else if (argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (na[0] == 'n' || na[0] == 'N')
+ fe = inst_opt_filter_none;
+ else if (na[0] == 'p' || na[0] == 'P')
+ fe = inst_opt_filter_pol;
+ else if (na[0] == '6')
+ fe = inst_opt_filter_D65;
+ else if (na[0] == 'u' || na[0] == 'U')
+ fe = inst_opt_filter_UVCut;
+ else
+ usage();
+
+ /* Extra flags */
+ } else if (argv[fa][1] == 'Y') {
+ if (na == NULL)
+ usage();
+
+ /* ~~~ i1pro2 test code ~~~ */
+ if (na[0] == 'U') {
+ uvmode = 1;
+ } else {
+ usage();
+ }
+
+ } else
+ usage();
+ } else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(inname,argv[fa]);
+ strcat(inname,".ti2");
+ strcpy(outname,argv[fa]);
+ strcat(outname,".ti3");
+
+ /* See if there is an environment variable ccxx */
+ if (ccxxname[0] == '\000') {
+ char *na;
+ if ((na = getenv("ARGYLL_COLMTER_CAL_SPEC_SET")) != NULL) {
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+
+ } else if ((na = getenv("ARGYLL_COLMTER_COR_MATRIX")) != NULL) {
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+ }
+ }
+
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI2"); /* our special input type is Calibration Target Information 2 */
+ icg->add_other(icg, "CAL"); /* There may be a calibration too */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI2 format file");
+ if (icg->ntables < 1)
+ error ("Input file doesn't contain at least one table");
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("No sets of data in first table");
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll chartread", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+ if (displ != 0)
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL); /* What sort of device this is */
+ else
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL); /* What sort of device this is */
+
+ if (itype == instUnknown) {
+ if ((ti = icg->find_kword(icg, 0, "TARGET_INSTRUMENT")) >= 0) {
+
+ if ((itype = inst_enum(icg->t[0].kdata[ti])) == instUnknown)
+ error ("Unrecognised chart target instrument '%s'", icg->t[0].kdata[ti]);
+ } else {
+ itype = instDTP41; /* Default chart target instrument */
+ }
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "SINGLE_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "SINGLE_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "COMP_GREY_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "COMP_GREY_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "MULTI_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "MULTI_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "FULL_SPREAD_PATCHES")) >= 0)
+ ocg->add_kword(ocg, 0, "FULL_SPREAD_PATCHES",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "ACCURATE_EXPECTED_VALUES")) >= 0
+ && strcmp(icg->t[0].kdata[ti], "true") == 0)
+ accurate_expd = 1;
+
+ if ((ti = icg->find_kword(icg, 0, "STEPS_IN_PASS")) < 0)
+ error ("Input file doesn't contain keyword STEPS_IN_PASS");
+ stipa = atoi(icg->t[0].kdata[ti]);
+
+ /* Old style */
+ if ((ti = icg->find_kword(icg, 0, "PASSES_IN_STRIPS")) >= 0) {
+ char *paists = icg->t[0].kdata[ti];
+ int nstr;
+
+ /* Count the number of strips (sheets) */
+ for (nstr = 0; paists[nstr] != '\000'; nstr++)
+ ;
+
+ /* Allocate space for passes in strips */
+ if ((pis = (int *)calloc(sizeof(int), nstr+1)) == NULL)
+ error("Malloc failed!");
+
+ /* Set the number or passes per strip */
+ for (i = 0; i < nstr; i++) {
+ pis[i] = b62_int(&paists[i]);
+ }
+ pis[i] = 0;
+
+ /* New style */
+ } else if ((ti = icg->find_kword(icg, 0, "PASSES_IN_STRIPS2")) >= 0) {
+ char *cp, *paists = icg->t[0].kdata[ti];
+ int nstr;
+
+
+ /* Count the number of strips (sheets) */
+ for (nstr = 1, cp = paists; *cp != '\000'; cp++) {
+ if (*cp == ',') {
+ nstr++;
+ *cp = '\000';
+ }
+ }
+
+
+ /* Allocate space for passes in strips */
+ if ((pis = (int *)calloc(sizeof(int), nstr+1)) == NULL)
+ error("Malloc failed!");
+
+ /* Set the number or passes per strip */
+ for (i = 0, cp = paists; i < nstr; i++) {
+ pis[i] = atoi(cp);
+ cp += strlen(cp) + 1;
+ }
+ pis[i] = 0;
+
+ } else
+ error ("Input file doesn't contain keyword PASSES_IN_STRIPS");
+
+ /* Get specified location indexing patterns */
+ if ((ti = icg->find_kword(icg, 0, "STRIP_INDEX_PATTERN")) >= 0)
+ pixpat = icg->t[0].kdata[ti];
+ if ((ti = icg->find_kword(icg, 0, "PATCH_INDEX_PATTERN")) >= 0)
+ sixpat = icg->t[0].kdata[ti];
+ if ((ti = icg->find_kword(icg, 0, "INDEX_ORDER")) >= 0) {
+ if (strcmp(icg->t[0].kdata[ti], "PATCH_THEN_STRIP") == 0)
+ ixord = 1;
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "RANDOM_START")) >= 0)
+ rstart = atoi(icg->t[0].kdata[ti]);
+ else if ((ti = icg->find_kword(icg, 0, "CHART_ID")) >= 0)
+ rstart = atoi(icg->t[0].kdata[ti]);
+
+ if ((ti = icg->find_kword(icg, 0, "HEXAGON_PATCHES")) >= 0)
+ hex = 1;
+
+ if ((paix = new_alphix(pixpat)) == NULL)
+ error("Strip indexing pattern '%s' doesn't parse",pixpat);
+
+ if ((saix = new_alphix(sixpat)) == NULL)
+ error("Patch in strip indexing pattern '%s' doesn't parse",sixpat);
+
+ if ((ti = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0)
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT",icg->t[0].kdata[ti], NULL);
+
+ if (itype == instDTP20
+ || itype == instDTP41) { /* DTP20/41 specific info */
+ if ((ti = icg->find_kword(icg, 0, "PATCH_LENGTH")) < 0)
+ error ("Input file doesn't contain keyword PATCH_LENGTH");
+ plen = atof(icg->t[0].kdata[ti]);
+ if ((ti = icg->find_kword(icg, 0, "GAP_LENGTH")) < 0)
+ error ("Input file doesn't contain keyword GAP_LENGTH");
+ glen = atof(icg->t[0].kdata[ti]);
+ if ((ti = icg->find_kword(icg, 0, "TRAILER_LENGTH")) < 0) {
+ tlen = 18.0; /* Default for backwards compatibility */
+ } else
+ tlen = atof(icg->t[0].kdata[ti]);
+ }
+
+ if (verb) {
+ printf("Steps in each Pass = %d\n",stipa);
+ printf("Passes in each Strip = ");
+ for (i = 0; pis[i] != 0; i++) {
+ printf("%s%d",i > 0 ? ", " : "", pis[i]);
+ }
+ printf("\n");
+ }
+
+ /* Fields we want */
+
+ if ((si = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error ("Input file doesn't contain field SAMPLE_ID");
+ if (icg->t[0].ftype[si] != nqcs_t)
+ error ("Field SAMPLE_ID is wrong type");
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+
+ if ((li = icg->find_field(icg, 0, "SAMPLE_LOC")) < 0)
+ error ("Input file doesn't contain field SAMPLE_LOC");
+ if (icg->t[0].ftype[li] != cs_t)
+ error ("Field SAMPLE_LOC is wrong type");
+ ocg->add_field(ocg, 0, "SAMPLE_LOC", cs_t);
+
+ totpa = (npat + stipa -1)/stipa; /* Total passes for all strips */
+ runpat = stipa * totpa; /* Rounded up totao number of patches */
+ if ((cols = (chcol *)malloc(sizeof(chcol) * runpat)) == NULL)
+ error("Malloc failed!");
+ if ((scols = (chcol **)calloc(sizeof(chcol *), runpat)) == NULL)
+ error("Malloc failed!");
+
+ /* Figure out the color space */
+ if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error ("Input file doesn't contain keyword COLOR_REP");
+
+ if ((nmask = icx_char2inkmask(icg->t[0].kdata[fi])) != 0) {
+ int i, j, ii;
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ int xyzix[3]; /* XYZ/Lab chanel indexes */
+ char *ident; /* Full ident */
+ char *bident; /* Base ident */
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+ char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
+ int gotexyz = 1; /* Flag set if input file already has approx XYZ */
+ icxColorantLu *clu; /* Xcolorants model based Device -> CIE */
+
+ nchan = icx_noofinks(nmask);
+ ident = icx_inkmask2char(nmask, 1);
+ bident = icx_inkmask2char(nmask, 0);
+
+ /* Device channels */
+ for (j = 0; j < nchan; j++) {
+ int imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (icg->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+
+ ocg->add_field(ocg, 0, fname, r_t);
+ chix[j] = ii;
+ }
+
+ /* Approximate XYZ */
+ for (j = 0; j < 3; j++) {
+ if ((ii = icg->find_field(icg, 0, xyzfname[j])) >= 0) {
+ if (icg->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",xyzfname[j]);
+ xyzix[j] = ii;
+ } else {
+ gotexyz = 0;
+ }
+ }
+
+ /* Measured XYZ and/or Lab */
+ if (dolab == 0 || dolab == 2) {
+ for (j = 0; j < 3; j++)
+ ocg->add_field(ocg, 0, xyzfname[j], r_t);
+ }
+ if (dolab == 1 || dolab == 2) {
+ for (j = 0; j < 3; j++)
+ ocg->add_field(ocg, 0, labfname[j], r_t);
+ }
+
+ if ((clu = new_icxColorantLu(nmask)) == NULL)
+ error ("Creation of xcolorant lu object failed");
+
+ {
+ char fname[100];
+ if (dolab)
+ sprintf(fname, "%s_LAB", ident);
+ else
+ sprintf(fname, "%s_XYZ", ident);
+ ocg->add_kword(ocg, 0, "COLOR_REP", fname, NULL);
+ }
+
+ /* Read all the test patches in */
+ for (i = 0; i < npat; i++) {
+ cols[i].id = ((char *)icg->t[0].fdata[i][si]);
+ cols[i].loc = ((char *)icg->t[0].fdata[i][li]);
+ cols[i].n = nchan;
+ for (j = 0; j < nchan; j++)
+ cols[i].dev[j] = *((double *)icg->t[0].fdata[i][chix[j]]) / 100.0;
+ if (gotexyz) {
+ for (j = 0; j < 3; j++)
+ cols[i].eXYZ[j] = *((double *)icg->t[0].fdata[i][xyzix[j]]);
+ } else {
+ clu->dev_to_XYZ(clu, cols[i].eXYZ, cols[i].dev);
+ for (j = 0; j < 3; j++)
+ cols[i].eXYZ[j] *= 100.0;
+ }
+ cols[i].XYZ[0] = cols[i].XYZ[1] = cols[i].XYZ[2] = -1.0;
+ }
+
+ for (; i < runpat; i++) {
+ cols[i].id = cols[i].loc = "-1";
+ for (j = 0; j < nchan; j++)
+ cols[i].dev[j] = 0.0;
+ clu->dev_to_XYZ(clu, cols[i].eXYZ, cols[i].dev);
+ for (j = 0; j < 3; j++)
+ cols[i].eXYZ[j] *= 100.0;
+ cols[i].XYZ[0] = cols[i].XYZ[1] = cols[i].XYZ[2] = -1.0;
+ }
+
+ clu->del(clu);
+ free(ident);
+ free(bident);
+ } else
+ error ("Input file keyword COLOR_REP has unknown value");
+
+ /* Read any user supplied calibration information */
+ if (calname[0] != '\000') {
+ if ((cal = new_xcal()) == NULL)
+ error("new_xcal failed");
+ if ((cal->read(cal, calname)) != 0)
+ error("%s",cal->err);
+ }
+
+ /* If the user hasn't overridden it, get any calibration in the .ti2 */
+ if (cal == NULL) { /* No user supplied calibration info */
+ int oi, tab;
+
+ oi = icg->get_oi(icg, "CAL");
+
+ for (tab = 0; tab < icg->ntables; tab++) {
+ if (icg->t[tab].tt == tt_other && icg->t[tab].oi == oi) {
+ break;
+ }
+ }
+ if (tab < icg->ntables) {
+ if ((cal = new_xcal()) == NULL) {
+ error("new_xcal failed");
+ }
+ if (cal->read_cgats(cal, icg, tab, inname) != 0) {
+ error("%s",cal->err);
+ }
+ }
+ }
+
+ /* If there is calibration information, write it to the .ti3 */
+ if (cal != NULL) { /* No user supplied calibration info */
+ if (cal->write_cgats(cal, ocg) != 0) {
+ error("%s",cal->err);
+ }
+ cal->del(cal);
+ cal = NULL;
+ }
+
+ /* Set up the location sorted array of pointers */
+ for (i = 0; i < npat; i++) {
+ scols[i] = &cols[i];
+ if ((cols[i].loci = patch_location_order(paix, saix, ixord, cols[i].loc)) < 0)
+ error ("Bad location field value '%s' on patch %d", cols[i].loc, i);
+ }
+ for (; i < runpat; i++) { /* Extra on end */
+ scols[i] = &cols[i];
+ cols[i].loci = (totpa-1) * (256 - stipa) + i;
+/* printf("~~extra = %d, %d\n",cols[i].loci >> 8, cols[i].loci & 255); */
+ }
+
+ /* Reset 'read' flag and all data */
+ for (i = 0; i < runpat; i++) {
+ cols[i].rr = 0;
+ cols[i].XYZ[0] = -1.0;
+ cols[i].XYZ[1] = -1.0;
+ cols[i].XYZ[2] = -1.0;
+ cols[i].sp.spec_n = 0;
+ }
+
+#define HEAP_COMPARE(A,B) (A->loci < B->loci)
+ HEAPSORT(chcol *, scols, npat);
+
+ /* If we're resuming a chartread, fill in all the patches that */
+ /* have been read. */
+ if (doresume) {
+ cgats *rcg; /* output cgats structure */
+ int nrpat; /* Number of resumed patches */
+ int lix; /* Patch location index */
+ int islab = 0; /* nz if Lab, z if XYZ */
+ int cieix[3]; /* CIE value indexes */
+ int hasspec = 0; /* nz if has spectral */
+ xspect sp; /* Parameters of spectrum */
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ char *fname[2][3] = { { "XYZ_X", "XYZ_Y", "XYZ_Z" },
+ { "LAB_L", "LAB_A", "LAB_B" } };
+ int k, ii;
+ char buf[200];
+
+ /* Open and look at the .ti3 profile patches file */
+ rcg = new_cgats(); /* Create a CGATS structure */
+ rcg->add_other(rcg, "CTI3"); /* our special input type is Calibration Target Information 3 */
+ rcg->add_other(rcg, "CAL"); /* our special device Calibration state */
+
+ if (rcg->read_name(rcg, outname))
+ error("Unable to read chart being resumed '%s' : %s",outname, rcg->err);
+
+ if (rcg->ntables == 0 || rcg->t[0].tt != tt_other || rcg->t[0].oi != 0)
+ error ("Resumed file '%s' isn't a CTI3 format file",outname);
+ if (rcg->ntables < 1)
+ error ("Resumed file '%s' doesn't contain at least one table",outname);
+
+ if ((lix = rcg->find_field(rcg, 0, "SAMPLE_LOC")) < 0)
+ error ("Resumed file '%s' doesn't contain SAMPLE_LOC field",outname);
+ if (rcg->t[0].ftype[lix] != cs_t)
+ error("Field SAMPLE_LOC is wrong type - corrupted file ?");
+
+ /* Get the CIE field indexes */
+ if (rcg->find_field(rcg, 0, "LAB_L") >= 0)
+ islab = 1;
+
+ for (j = 0; j < 3; j++) {
+ if ((cieix[j] = rcg->find_field(rcg, 0, fname[islab][j])) < 0)
+ error("Input file doesn't contain field %s",fname[islab][j]);
+ if (rcg->t[0].ftype[cieix[j]] != r_t)
+ error("Field %s is wrong type - corrupted file ?",fname[islab][j]);
+ }
+
+ if ((ii = rcg->find_kword(rcg, 0, "SPECTRAL_BANDS")) >= 0) {
+ hasspec = 1;
+ sp.spec_n = atoi(rcg->t[0].kdata[ii]);
+ if ((ii = rcg->find_kword(rcg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Resumed file '%s' doesn't contain keyword SPECTRAL_START_NM",outname);
+ sp.spec_wl_short = atof(rcg->t[0].kdata[ii]);
+ if ((ii = rcg->find_kword(rcg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Resumed file '%s' doesn't contain keyword SPECTRAL_END_NM",outname);
+ sp.spec_wl_long = atof(rcg->t[0].kdata[ii]);
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = rcg->find_field(rcg, 0, buf)) < 0)
+ error("Resumed file '%s' doesn't contain field %s",outname,buf);
+ }
+ }
+
+ nrpat = rcg->t[0].nsets;
+
+ /* Now see if we can match the previously read patches. */
+ /* We'll use the patch location to do this. */
+ for (i = 0; i < runpat; i++) {
+ int k;
+ for (k = 0; k < nrpat; k++) {
+ if (strcmp(cols[i].loc, ((char *)rcg->t[0].fdata[k][lix])) == 0)
+ break;
+ }
+ if (k >= nrpat)
+ continue;
+
+#ifdef DEBUG
+ printf("Recovering patch '%s' value from .ti3 file\n",cols[i].loc);
+#endif
+ cols[i].XYZ[0] = *((double *)rcg->t[0].fdata[k][cieix[0]]);
+ cols[i].XYZ[1] = *((double *)rcg->t[0].fdata[k][cieix[1]]);
+ cols[i].XYZ[2] = *((double *)rcg->t[0].fdata[k][cieix[2]]);
+ if (islab) {
+ icmLab2XYZ(&icmD50, cols[i].XYZ, cols[i].XYZ);
+ cols[i].XYZ[0] *= 100.0;
+ cols[i].XYZ[1] *= 100.0;
+ cols[i].XYZ[2] *= 100.0;
+ }
+ if (hasspec) {
+ cols[i].sp.spec_n = sp.spec_n;
+ cols[i].sp.spec_wl_short = sp.spec_wl_short;
+ cols[i].sp.spec_wl_long = sp.spec_wl_long;
+ for (j = 0; j < sp.spec_n; j++)
+ cols[i].sp.spec[j] = *((double *)rcg->t[0].fdata[k][spi[j]]);
+ }
+ cols[i].rr = 1;
+ }
+ rcg->del(rcg);
+ }
+
+ /* We can't fiddle white point with spectral data, */
+ /* so turn spectral off for display with white point relative. */
+ if (displ == 2 || displ == 3) {
+ spectral = 0;
+
+ /* Check that there is a white patch, so that we can compute Y relative */
+ /* Read all the test patches in */
+ if (nmask != ICX_RGB)
+ error("Don't know how to handle non-RGB display space");
+
+ for (wpat = 0; wpat < npat; wpat++) {
+ if (cols[wpat].dev[0] > 0.9999999 &&
+ cols[wpat].dev[1] > 0.9999999 &&
+ cols[wpat].dev[2] > 0.9999999) {
+ break;
+ }
+ }
+ if (wpat >= npat) { /* Create a white patch */
+ error("Can't compute white Y relative display values without a white test patch");
+ }
+ }
+
+ if ((icmps = new_icompaths(g_log)) == NULL)
+ error("Finding instrument paths failed");
+ if ((ipath = icmps->get_path(icmps, comport)) == NULL)
+ error("No instrument at port %d",comport);
+
+ /* Read all of the strips in */
+ if (read_strips(itype, scols, &atype, npat, totpa, stipa, pis, paix,
+ saix, ixord, rstart, hex, ipath, fc, plen, glen, tlen,
+ trans, emis, displ, dtype, fe, nocal, disbidi, highres, ccxxname, obType,
+ scan_tol, pbypatch, xtern, spectral, uvmode, accurate_expd,
+ emit_warnings, g_log) == 0) {
+ /* And save the result */
+
+ int nrpat; /* Number of read patches */
+ int vpix = 0; /* Valid patch index, if nrpatch > 0 */
+ int nsetel = 0;
+ cgats_set_elem *setel; /* Array of set value elements */
+
+ /* Note what instrument the chart was read with */
+ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(atype) , NULL);
+
+ /* Count patches actually read */
+ for (nrpat = i = 0; i < npat; i++) {
+ if (cols[i].rr) {
+ vpix = i;
+ nrpat++;
+ }
+ }
+
+ /* If we've used a display white relative mode, record the absolute white */
+ if (displ == 2 || displ == 3) {
+ double nn[3];
+ char buf[100];
+
+ if (cols[wpat].rr == 0) {
+ error("Can't compute white Y relative display values without reading a white test patch");
+ }
+ sprintf(buf,"%f %f %f", cols[wpat].XYZ[0], cols[wpat].XYZ[1], cols[wpat].XYZ[2]);
+ ocg->add_kword(ocg, 0, "LUMINANCE_XYZ_CDM2",buf, NULL);
+
+ /* Normalise to white Y 100 */
+ if (displ == 2) {
+ nn[0] = 100.0 / cols[wpat].XYZ[1];
+ nn[1] = 100.0 / cols[wpat].XYZ[1];
+ nn[2] = 100.0 / cols[wpat].XYZ[1];
+ /* Normalise to the white point */
+ } else {
+ nn[0] = 100.0 * icmD50.X / cols[wpat].XYZ[0];
+ nn[1] = 100.0 * icmD50.Y / cols[wpat].XYZ[1];
+ nn[2] = 100.0 * icmD50.Z / cols[wpat].XYZ[2];
+ }
+
+ for (i = 0; i < npat; i++) {
+ if (cols[i].rr) {
+ cols[i].XYZ[0] *= nn[0];
+ cols[i].XYZ[1] *= nn[1];
+ cols[i].XYZ[2] *= nn[2];
+ }
+ }
+ }
+
+ nsetel += 1; /* For id */
+ nsetel += 1; /* For loc */
+ nsetel += nchan; /* For device values */
+ nsetel += 3; /* For XYZ or Lab */
+ if (dolab == 2)
+ nsetel += 3; /* For XYZ and Lab */
+
+ /* If we have spectral information, output it too */
+ if (nrpat > 0 && cols[vpix].sp.spec_n > 0) {
+ char buf[100];
+
+ nsetel += cols[vpix].sp.spec_n; /* Spectral values */
+ sprintf(buf,"%d", cols[vpix].sp.spec_n);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+ sprintf(buf,"%f", cols[vpix].sp.spec_wl_short);
+ ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
+ sprintf(buf,"%f", cols[vpix].sp.spec_wl_long);
+ ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);
+
+ /* Generate fields for spectral values */
+ for (i = 0; i < cols[vpix].sp.spec_n; i++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(cols[vpix].sp.spec_wl_short + ((double)i/(cols[vpix].sp.spec_n-1.0))
+ * (cols[vpix].sp.spec_wl_long - cols[vpix].sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+ ocg->add_field(ocg, 0, buf, r_t);
+ }
+ }
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL)
+ error("Malloc failed!");
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < npat; i++) {
+ int k = 0;
+
+ if (cols[i].rr == 0 /* If this patch wasn't read */
+ || strcmp(cols[i].id, "0") == 0) /* or it is a padding patch. */
+ continue; /* Skip it */
+
+ setel[k++].c = cols[i].id;
+ setel[k++].c = cols[i].loc;
+
+ for (j = 0; j < nchan; j++)
+ setel[k++].d = 100.0 * cols[i].dev[j];
+
+ if (dolab == 0 || dolab == 2) {
+ setel[k++].d = cols[i].XYZ[0];
+ setel[k++].d = cols[i].XYZ[1];
+ setel[k++].d = cols[i].XYZ[2];
+ }
+ if (dolab == 1 || dolab == 2) {
+ double lab[3];
+ double xyz[3];
+
+ xyz[0] = cols[i].XYZ[0]/100.0;
+ xyz[1] = cols[i].XYZ[1]/100.0;
+ xyz[2] = cols[i].XYZ[2]/100.0;
+ icmXYZ2Lab(&icmD50, lab, xyz);
+ setel[k++].d = lab[0];
+ setel[k++].d = lab[1];
+ setel[k++].d = lab[2];
+ }
+
+ /* Check that the spectral matches, in case we're resuming */
+ if ( cols[i].sp.spec_n != cols[vpix].sp.spec_n
+ || fabs(cols[i].sp.spec_wl_short - cols[vpix].sp.spec_wl_short) > 0.01
+ || fabs(cols[i].sp.spec_wl_long - cols[vpix].sp.spec_wl_long) > 0.01 ) {
+ error("The resumed spectral type seems to have changed!");
+ }
+
+ for (j = 0; j < cols[i].sp.spec_n; j++) {
+ setel[k++].d = cols[i].sp.spec[j];
+ }
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+ }
+
+ icmps->del(icmps);
+ free(pis);
+ saix->del(saix);
+ paix->del(paix);
+ free(cols);
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+
diff --git a/spectro/colorhug.c b/spectro/colorhug.c
new file mode 100644
index 0000000..dad7012
--- /dev/null
+++ b/spectro/colorhug.c
@@ -0,0 +1,1093 @@
+
+
+/*
+ * Argyll Color Correction System
+ *
+ * Hughski ColorHug related functions
+ *
+ * Author: Richard Hughes
+ * Date: 30/11/2011
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * Copyright 2011, Richard Hughes
+ * All rights reserved.
+ *
+ * (Based on huey.c)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "colorhug.h"
+
+static inst_code colorhug_interp_code(inst *pp, int ec);
+
+/* Interpret an icoms error into a ColorHug error */
+static int icoms2colorhug_err(int se) {
+ if (se != ICOM_OK)
+ return COLORHUG_COMS_FAIL;
+ return COLORHUG_OK;
+}
+
+/* ColorHug commands that we care about */
+typedef enum {
+ ch_set_mult = 0x04, /* Set multiplier value */
+ ch_set_integral = 0x06, /* Set integral time */
+ ch_get_firmware_version = 0x07, /* Get the Firmware version number */
+ ch_get_serial = 0x0b, /* Gets the serial number */
+ ch_set_leds = 0x0e, /* Sets the LEDs */
+ ch_take_reading = 0x22, /* Takes a raw reading minus dark offset */
+ ch_take_reading_xyz = 0x23, /* Takes an XYZ reading using the current matrix */
+ ch_get_post_scale = 0x2a /* Get the post scaling factor */
+} ColorHugCmd;
+
+/* Diagnostic - return a description given the instruction code */
+static char *inst_desc(int cc) {
+ static char buf[40];
+ switch(cc) {
+ case 0x04:
+ return "SetMultiplier";
+ case 0x06:
+ return "SetIntegral";
+ case 0x07:
+ return "GetFirmwareVersion";
+ case 0x0b:
+ return "GetSerial";
+ case 0x0e:
+ return "SetLeds";
+ case 0x22:
+ return "TakeReading";
+ case 0x23:
+ return "TakeReadingXYZ";
+ case 0x2a:
+ return "GetPostScale";
+ }
+ sprintf(buf,"Unknown %02x",cc);
+ return buf;
+}
+
+/* Error codes interpretation */
+static char *
+colorhug_interp_error(inst *pp, int ec) {
+ ec &= inst_imask;
+ switch (ec) {
+ case COLORHUG_INTERNAL_ERROR:
+ return "Internal software error";
+ case COLORHUG_COMS_FAIL:
+ return "Communications failure";
+ case COLORHUG_UNKNOWN_MODEL:
+ return "Not a known ColorHug Model";
+
+ case COLORHUG_OK:
+ return "OK";
+ case COLORHUG_UNKNOWN_CMD:
+ return "Unknown connamd";
+ case COLORHUG_WRONG_UNLOCK_CODE:
+ return "Wrong unlock code";
+ case COLORHUG_NOT_IMPLEMENTED:
+ return "Not implemented";
+ case COLORHUG_UNDERFLOW_SENSOR:
+ return "Sensor underflow";
+ case COLORHUG_NO_SERIAL:
+ return "No serial";
+ case COLORHUG_WATCHDOG:
+ return "Watchdog";
+ case COLORHUG_INVALID_ADDRESS:
+ return "Invalid address";
+ case COLORHUG_INVALID_LENGTH:
+ return "Invalid length";
+ case COLORHUG_INVALID_CHECKSUM:
+ return "Invlid checksum";
+ case COLORHUG_INVALID_VALUE:
+ return "Invalid value";
+ case COLORHUG_UNKNOWN_CMD_FOR_BOOTLOADER:
+ return "Unknown command for bootloader";
+ case COLORHUG_NO_CALIBRATION:
+ return "No calibration";
+ case COLORHUG_OVERFLOW_MULTIPLY:
+ return "Multiply overflow";
+ case COLORHUG_OVERFLOW_ADDITION:
+ return "Addition overflow";
+ case COLORHUG_OVERFLOW_SENSOR:
+ return "Sensor overflow";
+ case COLORHUG_OVERFLOW_STACK:
+ return "Stack overflow";
+ case COLORHUG_DEVICE_DEACTIVATED:
+ return "Device deactivated";
+ case COLORHUG_INCOMPLETE_REQUEST:
+ return "Incomplete request";
+
+ /* Internal errors */
+ case COLORHUG_NO_COMS:
+ return "Communications hasn't been established";
+ case COLORHUG_NOT_INITED:
+ return "Insrument hasn't been initialised";
+ default:
+ return "Unknown error code";
+ }
+}
+
+/* Do a command/response exchange with the colorhug */
+static inst_code
+colorhug_command(colorhug *p,
+ ColorHugCmd cmd,
+ unsigned char *in, unsigned int in_size,
+ unsigned char *out, unsigned int out_size,
+ double timeout)
+{
+ int i;
+ unsigned char buf[64];
+ int xwbytes, wbytes;
+ int xrbytes, rbytes;
+ int se, ua = 0, rv = inst_ok;
+ int ishid = p->icom->port_type(p->icom) == icomt_hid;
+
+ a1logd(p->log,5,"colorhg_command: sending cmd '%s' args '%s'\n",
+ inst_desc(cmd), icoms_tohex(in, in_size));
+
+ /* Send the command with any specified data */
+ memset(buf, 0, 64);
+ buf[0] = cmd;
+ if (in != NULL)
+ memcpy(buf + 1, in, in_size);
+ if (ishid) {
+ xwbytes = 64;
+ se = p->icom->hid_write(p->icom, buf, xwbytes, &wbytes, timeout);
+ } else {
+// xwbytes = in_size + 1; /* cmd + arguments */
+ xwbytes = 64;
+ se = p->icom->usb_write(p->icom, NULL, 0x01, buf, xwbytes, &wbytes, timeout);
+ }
+ if (se != 0) {
+ a1logd(p->log,1,"colorhug_command: command send failed with ICOM err 0x%x\n",se);
+ return colorhug_interp_code((inst *)p, COLORHUG_COMS_FAIL);
+ }
+ rv = colorhug_interp_code((inst *)p, icoms2colorhug_err(ua));
+ if (rv == inst_ok && wbytes != xwbytes)
+ rv = colorhug_interp_code((inst *)p, COLORHUG_BAD_WR_LENGTH);
+ a1logd(p->log,6,"colorhug_command: got inst code \n",rv);
+
+ if (rv != inst_ok) {
+ /* Flush any response if write failed */
+ if (ishid)
+ p->icom->hid_read(p->icom, buf, 64, &rbytes, timeout);
+ else
+ p->icom->usb_read(p->icom, NULL, 0x81, buf, out_size + 2, &rbytes, timeout);
+ return rv;
+ }
+
+ /* Now fetch the response */
+ a1logd(p->log,6,"colorhug_command: Reading response\n");
+
+ if (ishid) {
+ xrbytes = 64;
+ se = p->icom->hid_read(p->icom, buf, xrbytes, &rbytes, timeout);
+ } else {
+// xrbytes = out_size + 2;
+ xrbytes = 64;
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf, xrbytes, &rbytes, timeout);
+ }
+
+ if (rbytes >= 2) {
+ a1logd(p->log,6,"colorhug_command: recieved cmd '%s' error '%s' args '%s'\n",
+ inst_desc(buf[1]),
+ colorhug_interp_error((inst *) p, buf[0]),
+ icoms_tohex(buf, rbytes - 2));
+ }
+
+ if (se != 0) {
+
+ /* deal with command error */
+// if (rbytes == 2 && buf[0] != COLORHUG_OK) {
+ if (buf[0] != COLORHUG_OK) {
+ a1logd(p->log,1,"colorhug_command: Got Colorhug !OK\n");
+ rv = colorhug_interp_code((inst *)p, buf[0]);
+ return rv;
+ }
+
+ /* deal with underrun or overrun */
+ if (rbytes != xrbytes) {
+ a1logd(p->log,1,"colorhug_command: got underrun or overrun\n");
+ rv = colorhug_interp_code((inst *)p, COLORHUG_BAD_RD_LENGTH);
+ return rv;
+ }
+
+ /* there's another reason it failed */
+ a1logd(p->log,1,"colorhug_command: read failed with ICOM err 0x%x\n",se);
+ return colorhug_interp_code((inst *)p, COLORHUG_COMS_FAIL);
+ }
+ rv = colorhug_interp_code((inst *)p, icoms2colorhug_err(ua));
+
+ /* check the command was the same */
+ if (rv == inst_ok && buf[1] != cmd) {
+ a1logd(p->log,1,"colorhug_command: command wasn't echo'd\n");
+ rv = colorhug_interp_code((inst *)p, COLORHUG_BAD_RET_CMD);
+ return rv;
+ }
+ if (rv == inst_ok && out != NULL)
+ memcpy(out, buf + 2, out_size);
+
+ a1logd(p->log,5,"colorhg_command: returning '%s' ICOM err 0x%x\n",
+ icoms_tohex(buf + 2, out_size),ua);
+ return rv;
+}
+
+/* --------------------------------------------- */
+/* Little endian wire format conversion routines */
+
+/* Take an int, and convert it into a byte buffer */
+static void int2buf_le(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+ buf[2] = (inv >> 16) & 0xff;
+ buf[3] = (inv >> 24) & 0xff;
+}
+
+/* Take an unsigned int, and convert it into a byte buffer */
+static void uint2buf_le(unsigned char *buf, unsigned int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+ buf[2] = (inv >> 16) & 0xff;
+ buf[3] = (inv >> 24) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer */
+static void short2buf_le(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+}
+
+/* Take an unsigned short, and convert it into a byte buffer */
+static void ushort2buf_le(unsigned char *buf, unsigned int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+}
+
+/* Take a word sized buffer, and convert it to an int */
+static int buf2int_le(unsigned char *buf) {
+ int val;
+ val = buf[3];
+ val = ((val << 8) + buf[2]);
+ val = ((val << 8) + buf[1]);
+ val = ((val << 8) + buf[0]);
+ return val;
+}
+
+/* Take a word sized buffer, and convert it to an unsigned int */
+static unsigned int buf2uint_le(unsigned char *buf) {
+ unsigned int val;
+ val = buf[3];
+ val = ((val << 8) + buf[2]);
+ val = ((val << 8) + buf[1]);
+ val = ((val << 8) + buf[0]);
+ return val;
+}
+
+/* Take a short sized buffer, and convert it to an int */
+static int buf2short_le(unsigned char *buf) {
+ int val;
+ val = buf[1];
+ val = ((val << 8) + buf[0]);
+ return val;
+}
+
+/* Take an unsigned short sized buffer, and convert it to an int */
+static unsigned int buf2ushort_le(unsigned char *buf) {
+ unsigned int val;
+ val = buf[1];
+ val = ((val << 8) + buf[0]);
+ return val;
+}
+
+/* --------------------------------------------- */
+
+
+/* Converts 4 bytes of packed float into a double */
+static double buf2pfdouble(unsigned char *buf)
+{
+ return (double) buf2int_le(buf) / (double) 0x10000;
+}
+
+/* Set the device LED state */
+static inst_code
+colorhug_set_LEDs(colorhug *p, int mask)
+{
+ int i;
+ unsigned char ibuf[4];
+ inst_code ev;
+
+ mask &= 0x3;
+ p->led_state = mask;
+
+ ibuf[0] = mask;
+ ibuf[1] = 0; /* repeat */
+ ibuf[2] = 0; /* on */
+ ibuf[3] = 0; /* off */
+
+ /* Do command */
+ ev = colorhug_command(p, ch_set_leds,
+ ibuf, sizeof (ibuf), /* input */
+ NULL, 0, /* output */
+ 2.0);
+ return ev;
+}
+
+/* Take a measurement from the device */
+/* There are 64 calibration matricies, index 0..63 */
+/* 0 is the factory calibration, while 1..63 are */
+/* applied on top of the factory calibration as corrections. */
+/* Index 64..70 are mapped via the mapping table */
+/* to an index between 0 and 63, and notionaly correspond */
+/* as follows: */
+/* LCD = 0 */
+/* CRT = 1 */
+/* Projector = 2 */
+/* LED = 3 */
+/* Custom1 = 4 */
+/* Custom2 = 5 */
+static inst_code
+colorhug_take_measurement(colorhug *p, double XYZ[3])
+{
+ inst_code ev;
+ int i;
+ ORD8 ibuf[2];
+
+ if (!p->inited)
+ return colorhug_interp_code((inst *)p, COLORHUG_NOT_INITED);
+
+ if (p->icx == 11) { /* Raw */
+ unsigned char obuf[3 * 4];
+
+ /* Do the measurement, and return the values */
+ ev = colorhug_command(p, ch_take_reading,
+ NULL, 0,
+ obuf, 3 * 4,
+ 30.0);
+ if (ev != inst_ok)
+ return ev;
+
+ /* Convert to doubles */
+ for (i = 0; i < 3; i++)
+ XYZ[i] = p->postscale * buf2pfdouble(obuf + i * 4);
+ } else {
+ int icx = 64 + p->icx;
+ unsigned char obuf[3 * 4];
+
+ if (p->icx == 10) /* Factory */
+ icx = 0;
+
+ /* Choose the calibration matrix */
+ short2buf_le(ibuf + 0, icx);
+
+ /* Do the measurement, and return the values */
+ ev = colorhug_command(p, ch_take_reading_xyz,
+ ibuf, sizeof (ibuf),
+ obuf, 3 * 4,
+ 30.0);
+ if (ev != inst_ok)
+ return ev;
+
+ /* Convert to doubles */
+ for (i = 0; i < 3; i++)
+ XYZ[i] = buf2pfdouble(obuf + i * 4);
+ }
+
+ /* Apply the colorimeter correction matrix */
+ icmMulBy3x3(XYZ, p->ccmat, XYZ);
+
+ a1logd(p->log,3,"colorhug_take_measurement: XYZ = %f %f %f\n",XYZ[0],XYZ[1],XYZ[2]);
+
+ return inst_ok;
+}
+
+/* Establish communications with a ColorHug */
+static inst_code
+colorhug_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ int se;
+ colorhug *p = (colorhug *) pp;
+
+ a1logd(p->log, 2, "colorhug_init_coms: About to init coms\n");
+
+ /* Open as an HID if available */
+ if (p->icom->port_type(p->icom) == icomt_hid) {
+
+ a1logd(p->log, 3, "colorhug_init_coms: About to init HID\n");
+
+ /* Set config, interface */
+ if ((se = p->icom->set_hid_port(p->icom, icomuf_none, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "colorhug_init_coms: set_hid_port failed ICOM err 0x%x\n",se);
+ return colorhug_interp_code((inst *)p, icoms2colorhug_err(se));
+ }
+
+ } else if (p->icom->port_type(p->icom) == icomt_usb) {
+
+ a1logd(p->log, 3, "colorhug_init_coms: About to init USB\n");
+
+ /* Set config, interface, write end point, read end point */
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, icomuf_detach, 0, NULL))
+ != ICOM_OK) {
+ a1logd(p->log, 1, "colorhug_init_coms: set_usb_port failed ICOM err 0x%x\n",se);
+ return colorhug_interp_code((inst *)p, icoms2colorhug_err(se));
+ }
+
+ } else {
+ a1logd(p->log, 1, "colorhug_init_coms: wrong communications type for device!\n");
+ return colorhug_interp_code((inst *)p, COLORHUG_UNKNOWN_MODEL);
+ }
+
+ a1logd(p->log, 2, "colorhug_init_coms: inited coms OK\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+/* Get the firmware version */
+static inst_code
+colorhug_get_firmwareversion (colorhug *p)
+{
+ inst_code ev;
+ unsigned char obuf[6];
+
+ /* Hmm. The post scale is in the 2nd short returned */
+ ev = colorhug_command(p, ch_get_firmware_version,
+ NULL, 0,
+ obuf, 6,
+ 2.0);
+ if (ev != inst_ok)
+ return ev;
+
+ p->maj = buf2short_le(obuf + 0);
+ p->min = buf2short_le(obuf + 2);
+ p->uro = buf2short_le(obuf + 4);
+
+ a1logd(p->log,2,"colorhug: Firware version = %d.%d.%d\n",p->maj,p->min,p->uro);
+
+ return ev;
+}
+
+/* Set the device multiplier */
+static inst_code
+colorhug_set_multiplier (colorhug *p, int multiplier)
+{
+ inst_code ev;
+ unsigned char ibuf[1];
+
+ /* Set the desired multiplier */
+ ibuf[0] = multiplier;
+ ev = colorhug_command(p, ch_set_mult,
+ ibuf, sizeof (ibuf),
+ NULL, 0,
+ 2.0);
+ return ev;
+}
+
+/* Set the device integral time */
+static inst_code
+colorhug_set_integral (colorhug *p, int integral)
+{
+ inst_code ev;
+ unsigned char ibuf[2];
+
+ /* Set the desired integral time */
+ short2buf_le(ibuf + 0, integral);
+ ev = colorhug_command(p, ch_set_integral,
+ ibuf, sizeof (ibuf),
+ NULL, 0,
+ 2.0);
+ return ev;
+}
+
+/* Get the post scale factor */
+static inst_code
+colorhug_get_postscale (colorhug *p, double *postscale)
+{
+ inst_code ev;
+ unsigned char obuf[4];
+
+ /* Hmm. The post scale is in the 2nd short returned */
+ ev = colorhug_command(p, ch_get_post_scale,
+ NULL, 0,
+ obuf, 4,
+ 2.0);
+ *postscale = buf2pfdouble(obuf);
+ return ev;
+}
+
+static inst_code set_default_disp_type(colorhug *p);
+
+/* Initialise the ColorHug */
+static inst_code
+colorhug_init_inst(inst *pp)
+{
+ colorhug *p = (colorhug *)pp;
+ inst_code ev;
+ int i;
+
+ a1logd(p->log, 2, "colorhug_init_coms: About to init coms\n");
+
+ /* Must establish coms first */
+ if (p->gotcoms == 0)
+ return colorhug_interp_code((inst *)p, COLORHUG_NO_COMS);
+
+ /* Get the firmware version */
+ ev = colorhug_get_firmwareversion(p);
+ if (ev != inst_ok)
+ return ev;
+
+ /* Turn the LEDs off */
+ ev = colorhug_set_LEDs(p, 0x0);
+ if (ev != inst_ok)
+ return ev;
+
+ /* Turn the sensor on */
+ ev = colorhug_set_multiplier(p, 0x03);
+ if (ev != inst_ok)
+ return ev;
+
+ /* Set the integral time to maximum precision */
+ ev = colorhug_set_integral(p, 0xffff);
+ if (ev != inst_ok)
+ return ev;
+
+ if (p->maj <= 1 && p->min <= 1 && p->uro <= 4) {
+
+ /* Get the post scale factor */
+ ev = colorhug_get_postscale(p, &p->postscale);
+ if (ev != inst_ok)
+ return ev;
+
+
+ /* In firmware >= 1.1.5, the postscale is done in the firmware */
+ } else {
+ p->postscale = 1.0;
+ }
+
+ p->trig = inst_opt_trig_user;
+
+ /* Setup the default display type */
+ if ((ev = set_default_disp_type(p)) != inst_ok) {
+ return ev;
+ }
+
+ p->inited = 1;
+ a1logd(p->log, 2, "colorhug_init: inited coms OK\n");
+
+ /* Flash the LEDs */
+ ev = colorhug_set_LEDs(p, 0x1);
+ if (ev != inst_ok)
+ return ev;
+ msec_sleep(50);
+ ev = colorhug_set_LEDs(p, 0x2);
+ if (ev != inst_ok)
+ return ev;
+ msec_sleep(50);
+ ev = colorhug_set_LEDs(p, 0x1);
+ if (ev != inst_ok)
+ return ev;
+ msec_sleep(50);
+ ev = colorhug_set_LEDs(p, 0x0);
+ if (ev != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* Read a single sample */
+static inst_code
+colorhug_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ colorhug *p = (colorhug *)pp;
+ int user_trig = 0;
+ int rv = inst_protocol_error;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "colorhug: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rv == inst_user_abort)
+ return rv; /* Abort */
+ if (rv == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return rv; /* Abort */
+ }
+
+ /* Read the XYZ value */
+ if ((rv = colorhug_take_measurement(p, val->XYZ)) != inst_ok) {
+ return rv;
+ }
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+
+ val->mtype = inst_mrt_emission;
+ val->XYZ_v = 1; /* These are absolute XYZ readings ? */
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (user_trig)
+ return inst_user_trig;
+ return rv;
+}
+
+/* Insert a colorimetric correction matrix */
+inst_code colorhug_col_cor_mat(
+inst *pp,
+double mtx[3][3]
+) {
+ colorhug *p = (colorhug *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+
+ if (mtx == NULL) {
+ icmSetUnity3x3(p->ccmat);
+ } else {
+ if (p->cbid == 0) {
+ a1loge(p->log, 1, "colorhug: can't set col_cor_mat over non base display type\n");
+ inst_wrong_setup;
+ }
+ icmCpy3x3(p->ccmat, mtx);
+ }
+
+ return inst_ok;
+}
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+colorhug_interp_code(inst *pp, int ec) {
+ ec &= inst_imask;
+ switch (ec) {
+
+ case COLORHUG_OK:
+ return inst_ok;
+
+ case COLORHUG_INTERNAL_ERROR:
+ case COLORHUG_NO_COMS:
+ case COLORHUG_NOT_INITED:
+ return inst_internal_error | ec;
+
+ case COLORHUG_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case COLORHUG_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+ case COLORHUG_UNKNOWN_CMD:
+ case COLORHUG_WRONG_UNLOCK_CODE:
+ case COLORHUG_NOT_IMPLEMENTED:
+ case COLORHUG_UNDERFLOW_SENSOR:
+ case COLORHUG_NO_SERIAL:
+ case COLORHUG_WATCHDOG:
+ case COLORHUG_INVALID_ADDRESS:
+ case COLORHUG_INVALID_LENGTH:
+ case COLORHUG_INVALID_CHECKSUM:
+ case COLORHUG_INVALID_VALUE:
+ case COLORHUG_UNKNOWN_CMD_FOR_BOOTLOADER:
+ case COLORHUG_NO_CALIBRATION:
+ case COLORHUG_OVERFLOW_MULTIPLY:
+ case COLORHUG_OVERFLOW_ADDITION:
+ case COLORHUG_OVERFLOW_SENSOR:
+ case COLORHUG_OVERFLOW_STACK:
+ case COLORHUG_DEVICE_DEACTIVATED:
+ case COLORHUG_INCOMPLETE_REQUEST:
+ case COLORHUG_BAD_WR_LENGTH:
+ case COLORHUG_BAD_RD_LENGTH:
+ case COLORHUG_BAD_RET_CMD:
+ case COLORHUG_BAD_RET_STAT:
+ return inst_protocol_error | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+colorhug_del(inst *pp) {
+ colorhug *p = (colorhug *)pp;
+ if (p != NULL) {
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ inst_del_disptype_list(p->dtlist, p->ndtlist);
+ free(p);
+ }
+}
+
+/* Return the instrument mode capabilities */
+void colorhug_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ colorhug *p = (colorhug *)pp;
+ inst_mode cap = 0;
+ inst2_capability cap2 = 0;
+
+ cap |= inst_mode_emis_spot
+ | inst_mode_colorimeter
+ ;
+
+ cap2 |= inst2_prog_trig
+ | inst2_user_trig
+ | inst2_has_leds
+ | inst2_disptype
+ | inst2_ccmx
+ ;
+
+ if (pcap1 != NULL)
+ *pcap1 = cap;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Check device measurement mode */
+inst_code colorhug_check_mode(inst *pp, inst_mode m) {
+ colorhug *p = (colorhug *)pp;
+ inst_mode cap;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* only display emission mode and ambient supported */
+ if (!IMODETST(m, inst_mode_emis_spot)
+ && !IMODETST(m, inst_mode_emis_ambient)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code colorhug_set_mode(inst *pp, inst_mode m) {
+ colorhug *p = (colorhug *)pp;
+ inst_code ev;
+
+ if ((ev = colorhug_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->mode = m;
+
+ return inst_ok;
+}
+
+/* The HW handles up to 6, + 2 special */
+static inst_disptypesel colorhug_disptypesel[7] = {
+ {
+ inst_dtflags_default, /* flags */
+ 0, /* cbix */
+ "l", /* sel */
+ "LCD, CCFL Backlight", /* desc */
+ 0, /* refr */
+ 0 /* ix */
+ },
+ {
+ inst_dtflags_none,
+ 0,
+ "c",
+ "CRT display",
+ 0,
+ 1
+ },
+ {
+ inst_dtflags_none,
+ 0,
+ "p",
+ "Projector",
+ 0,
+ 2
+ },
+ {
+ inst_dtflags_none,
+ 0,
+ "e",
+ "LCD, White LED Backlight",
+ 0,
+ 3
+ },
+ {
+ inst_dtflags_none,
+ 1,
+ "F",
+ "Factory matrix (For Calibration)",
+ 0,
+ 10
+ },
+ {
+ inst_dtflags_none,
+ 2,
+ "R",
+ "Raw Reading (For Factory matrix Calibration)",
+ 0,
+ 11
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+/* Get mode and option details */
+static inst_code colorhug_get_disptypesel(
+inst *pp,
+int *pnsels, /* Return number of display types */
+inst_disptypesel **psels, /* Return the array of display types */
+int allconfig, /* nz to return list for all configs, not just current. */
+int recreate /* nz to re-check for new ccmx & ccss files */
+) {
+ colorhug *p = (colorhug *)pp;
+ inst_code rv = inst_ok;
+
+ /* Create/Re-create a current list of abailable display types */
+ if (p->dtlist == NULL || recreate) {
+ if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ colorhug_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return rv;
+ }
+
+ if (pnsels != NULL)
+ *pnsels = p->ndtlist;
+
+ if (psels != NULL)
+ *psels = p->dtlist;
+
+ return inst_ok;
+}
+
+/* Given a display type entry, setup for that type */
+static inst_code set_disp_type(colorhug *p, inst_disptypesel *dentry) {
+ int ix;
+
+ /* The HW handles up to 6 calibrations */
+ ix = dentry->ix;
+ if (ix != 10 && ix != 11 && (ix < 0 || ix > 3))
+ return inst_unsupported;
+
+ p->icx = ix;
+ p->refrmode = dentry->refr;
+ p->cbid = dentry->cbid;
+ if (dentry->flags & inst_dtflags_ccmx) {
+ icmCpy3x3(p->ccmat, dentry->mat);
+ } else {
+ icmSetUnity3x3(p->ccmat);
+ }
+
+ return inst_ok;
+}
+
+/* Setup the default display type */
+static inst_code set_default_disp_type(colorhug *p) {
+ inst_code ev;
+ int i;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist,
+ colorhug_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) {
+ if (p->dtlist[i].flags & inst_dtflags_default)
+ break;
+ }
+ if (p->dtlist[i].flags & inst_dtflags_end) {
+ a1loge(p->log, 1, "set_default_disp_type: failed to find type!\n");
+ return inst_internal_error;
+ }
+ if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/* Set the display type */
+static inst_code colorhug_set_disptype(inst *pp, int ix) {
+ colorhug *p = (colorhug *)pp;
+ inst_code ev;
+ inst_disptypesel *dentry;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ colorhug_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ if (ix < 0 || ix >= p->ndtlist)
+ return inst_unsupported;
+
+ dentry = &p->dtlist[ix];
+
+ if ((ev = set_disp_type(p, dentry)) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * Set or reset an optional mode.
+ *
+ * Some options talk to the instrument, and these will
+ * error if it hasn't been initialised.
+ */
+static inst_code
+colorhug_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ colorhug *p = (colorhug *)pp;
+ inst_code ev = inst_ok;
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user) {
+ p->trig = m;
+ return inst_ok;
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Get the display type information */
+ if (m == inst_opt_get_dtinfo) {
+ va_list args;
+ int *refrmode, *cbid;
+
+ va_start(args, m);
+ refrmode = va_arg(args, int *);
+ cbid = va_arg(args, int *);
+ va_end(args);
+
+ if (refrmode != NULL)
+ *refrmode = p->refrmode;
+ if (cbid != NULL)
+ *cbid = p->cbid;
+
+ return inst_ok;
+ }
+
+ /* Operate the LEDs */
+ if (m == inst_opt_get_gen_ledmask) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = 0x3; /* Two general LEDs */
+ return inst_ok;
+ } else if (m == inst_opt_get_led_state) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = p->led_state;
+ return inst_ok;
+ } else if (m == inst_opt_set_led_state) {
+ va_list args;
+ int mask = 0;
+
+ va_start(args, m);
+ mask = va_arg(args, int);
+ va_end(args);
+ return colorhug_set_LEDs(p, mask);
+ }
+
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern colorhug *new_colorhug(icoms *icom, instType itype) {
+ colorhug *p;
+ int i;
+
+ if ((p = (colorhug *)calloc(sizeof(colorhug),1)) == NULL) {
+ a1loge(icom->log, 1, "new_colorhug: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = colorhug_init_coms;
+ p->init_inst = colorhug_init_inst;
+ p->capabilities = colorhug_capabilities;
+ p->check_mode = colorhug_check_mode;
+ p->set_mode = colorhug_set_mode;
+ p->get_disptypesel = colorhug_get_disptypesel;
+ p->set_disptype = colorhug_set_disptype;
+ p->get_set_opt = colorhug_get_set_opt;
+ p->read_sample = colorhug_read_sample;
+ p->col_cor_mat = colorhug_col_cor_mat;
+ p->interp_error = colorhug_interp_error;
+ p->del = colorhug_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ icmSetUnity3x3(p->ccmat);
+
+ return p;
+}
+
diff --git a/spectro/colorhug.h b/spectro/colorhug.h
new file mode 100644
index 0000000..a591608
--- /dev/null
+++ b/spectro/colorhug.h
@@ -0,0 +1,90 @@
+#ifndef COLORHUG_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Hughski ColorHug related defines
+ *
+ * Author: Richard Hughes
+ * Date: 30/11/2011
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * Copyright 2011, Richard Hughes
+ * All rights reserved.
+ *
+ * (Based on huey.h)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include "inst.h"
+
+/* Note: update colorhug_interp_error() and colorhug_interp_code() in colorhug.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define COLORHUG_INTERNAL_ERROR 0x61 /* Internal software error */
+#define COLORHUG_COMS_FAIL 0x62 /* Communication failure */
+#define COLORHUG_UNKNOWN_MODEL 0x63 /* Not an colorhug */
+#define COLORHUG_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error codes */
+#define COLORHUG_OK 0x00
+#define COLORHUG_UNKNOWN_CMD 0x01
+#define COLORHUG_WRONG_UNLOCK_CODE 0x02
+#define COLORHUG_NOT_IMPLEMENTED 0x03
+#define COLORHUG_UNDERFLOW_SENSOR 0x04
+#define COLORHUG_NO_SERIAL 0x05
+#define COLORHUG_WATCHDOG 0x06
+#define COLORHUG_INVALID_ADDRESS 0x07
+#define COLORHUG_INVALID_LENGTH 0x08
+#define COLORHUG_INVALID_CHECKSUM 0x09
+#define COLORHUG_INVALID_VALUE 0x0a
+#define COLORHUG_UNKNOWN_CMD_FOR_BOOTLOADER 0x0b
+#define COLORHUG_NO_CALIBRATION 0x0c
+#define COLORHUG_OVERFLOW_MULTIPLY 0x0d
+#define COLORHUG_OVERFLOW_ADDITION 0x0e
+#define COLORHUG_OVERFLOW_SENSOR 0x0f
+#define COLORHUG_OVERFLOW_STACK 0x10
+#define COLORHUG_DEVICE_DEACTIVATED 0x11
+#define COLORHUG_INCOMPLETE_REQUEST 0x12
+
+/* Internal errors */
+#define COLORHUG_NO_COMS 0x22
+#define COLORHUG_NOT_INITED 0x23
+#define COLORHUG_BAD_WR_LENGTH 0x25
+#define COLORHUG_BAD_RD_LENGTH 0x26
+#define COLORHUG_BAD_RET_CMD 0x27
+#define COLORHUG_BAD_RET_STAT 0x28
+
+
+/* COLORHUG communication object */
+struct _colorhug {
+ INST_OBJ_BASE
+
+ inst_mode mode; /* Currently selected mode */
+
+ inst_opt_type trig; /* Reading trigger mode */
+
+ int maj, min, uro; /* Version number */
+ int ser_no; /* Serial number */
+
+ inst_disptypesel *dtlist; /* Display Type list */
+ int ndtlist; /* Number of valid dtlist entries */
+ int icx; /* Internal calibration matrix index, 11 = Raw */
+ int cbid; /* calibration base ID, 0 if not a base */
+ int refrmode; /* Refresh mode (always 0) */
+ double postscale; /* Post scale factor (for Raw) */
+ double ccmat[3][3]; /* Colorimeter correction matrix */
+
+ int led_state; /* Current LED state */
+
+}; typedef struct _colorhug colorhug;
+
+/* Constructor */
+extern colorhug *new_colorhug(icoms *icom, instType itype);
+
+
+#define COLORHUG_H
+#endif /* COLORHUG_H */
diff --git a/spectro/conv.c b/spectro/conv.c
new file mode 100644
index 0000000..0f56ff9
--- /dev/null
+++ b/spectro/conv.c
@@ -0,0 +1,1471 @@
+
+ /* Platform isolation convenience functions */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/97
+ *
+ * Copyright 1997 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+
+#ifdef NT
+# if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
+# define _WIN32_WINNT 0x0501
+# endif
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+#include <conio.h>
+#include <tlhelp32.h>
+#include <direct.h>
+#endif
+
+#if defined(UNIX)
+#include <fcntl.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+
+/* select() defined, but not poll(), so emulate poll() */
+#if defined(FD_CLR) && !defined(POLLIN)
+#include "pollem.h"
+#define poll_x pollem
+#else
+#include <sys/poll.h> /* Else assume poll() is native */
+#define poll_x poll
+#endif
+#endif
+
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#else
+#include "sa_config.h"
+#endif
+#include "numsup.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+
+#ifdef __APPLE__
+//#include <stdbool.h>
+#include <sys/sysctl.h>
+#include <sys/param.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/serial/IOSerialKeys.h>
+#include <IOKit/IOBSD.h>
+#include <mach/mach_init.h>
+#include <mach/task_policy.h>
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+# include <AudioToolbox/AudioServices.h>
+#endif
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+# include <objc/objc-auto.h>
+#endif
+#endif /* __APPLE__ */
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define DBG(xx) a1logd(g_log, 0, xx )
+# define DBGA g_log, 0 /* First argument to DBGF() */
+# define DBGF(xx) a1logd xx
+#else
+# define DBG(xx)
+# define DBGF(xx)
+#endif
+
+#ifdef __BORLANDC__
+#define _kbhit kbhit
+#endif
+
+/* ============================================================= */
+/* MS WINDOWS */
+/* ============================================================= */
+#ifdef NT
+
+/* wait for and then return the next character from the keyboard */
+/* (If not_interactive, return getchar()) */
+int next_con_char(void) {
+ int c;
+
+ if (not_interactive) {
+ HANDLE stdinh;
+ char buf[1];
+ DWORD bread;
+
+ if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+
+ /* Ignore end of line characters */
+ for (;;) {
+ if (ReadFile(stdinh, buf, 1, &bread, NULL)
+ && bread == 1
+ && buf[0] != '\r' && buf[0] != '\n') {
+ return buf[0];
+ }
+ }
+ }
+
+ c = _getch();
+ return c;
+}
+
+/* Horrible hack to poll stdin when we're not interactive */
+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)
+ return 0;
+
+ if (ReadFile(stdinh, buf, 1, &bread, NULL)
+ && bread == 1
+ && buf[0] != '\r' && buf[0] != '\n') {
+ *rp = buf[0];
+ }
+
+ return 0;
+}
+
+/* If there is one, return the next character from the keyboard, else return 0 */
+/* (If not_interactive, always returns 0) */
+int poll_con_char(void) {
+
+ if (not_interactive) { /* Can't assume that it's the console */
+ athread *getch_thread = NULL;
+ char c = 0;
+
+ /* 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... */
+ if ((getch_thread = new_athread(th_read_char, &c)) != NULL) {
+ HANDLE stdinh;
+
+ if ((stdinh = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+
+ Sleep(1); /* We just hope 1 msec is enough for the thread to start */
+ CancelIo(stdinh);
+ getch_thread->del(getch_thread);
+ return c;
+ }
+ return 0;
+ }
+
+ /* Assume it's the console */
+ if (_kbhit() != 0) {
+ int c = next_con_char();
+ return c;
+ }
+ return 0;
+}
+
+/* Suck all characters from the keyboard */
+/* (If not_interactive, does nothing) */
+void empty_con_chars(void) {
+
+ if (not_interactive) {
+ return;
+ }
+
+ Sleep(50); /* _kbhit seems to have a bug */
+ while (_kbhit()) {
+ if (next_con_char() == 0x3) /* ^C Safety */
+ break;
+ }
+}
+
+/* Sleep for the given number of seconds */
+void sleep(unsigned int secs) {
+ Sleep(secs * 1000);
+}
+
+/* Sleep for the given number of msec */
+void msec_sleep(unsigned int msec) {
+ Sleep(msec);
+}
+
+/* Return the current time in msec since */
+/* the first invokation of msec_time() */
+/* (Is this based on timeGetTime() ? ) */
+unsigned int msec_time() {
+ unsigned int rv;
+ static unsigned int startup = 0;
+
+ rv = GetTickCount();
+ if (startup == 0)
+ startup = rv;
+
+ return rv - startup;
+}
+
+/* Return the current time in usec */
+/* since the first invokation of usec_time() */
+/* Return -1.0 if not available */
+double usec_time() {
+ double rv;
+ LARGE_INTEGER val;
+ static double scale = 0.0;
+ static LARGE_INTEGER startup;
+
+ if (scale == 0.0) {
+ if (QueryPerformanceFrequency(&val) == 0)
+ return -1.0;
+ scale = 1000000.0/val.QuadPart;
+ QueryPerformanceCounter(&val);
+ startup.QuadPart = val.QuadPart;
+
+ } else {
+ QueryPerformanceCounter(&val);
+ }
+ val.QuadPart -= startup.QuadPart;
+
+ rv = val.QuadPart * scale;
+
+ return rv;
+}
+
+static athread *beep_thread = NULL;
+static int beep_delay;
+static int beep_freq;
+static int beep_msec;
+
+/* Delayed beep handler */
+static int delayed_beep(void *pp) {
+ msec_sleep(beep_delay);
+ Beep(beep_freq, beep_msec);
+ return 0;
+}
+
+/* Activate the system beeper */
+void msec_beep(int delay, int freq, int msec) {
+ if (delay > 0) {
+ if (beep_thread != NULL)
+ beep_thread->del(beep_thread);
+ beep_delay = delay;
+ beep_freq = freq;
+ beep_msec = msec;
+ if ((beep_thread = new_athread(delayed_beep, NULL)) == NULL)
+ a1logw(g_log, "msec_beep: Delayed beep failed to create thread\n");
+ } else {
+ Beep(freq, msec);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef NEVER /* Not currently needed, or effective */
+
+/* Set the current threads priority */
+int set_interactive_priority() {
+ if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST) == 0)
+ return 1;
+ return 0;
+}
+
+int set_normal_priority() {
+ if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL) == 0)
+ return 1;
+ return 0;
+}
+
+#endif /* NEVER */
+
+
+#undef USE_BEGINTHREAD
+
+/* Wait for the thread to exit. Return the result */
+static int athread_wait(struct _athread *p) {
+
+ if (p->finished)
+ return p->result;
+
+ WaitForSingleObject(p->th, INFINITE);
+
+ return p->result;
+}
+
+/* Destroy the thread */
+static void athread_del(
+athread *p
+) {
+ DBG("athread_del called\n");
+
+ if (p == NULL)
+ return;
+
+ if (p->th != NULL) {
+ if (!p->finished) {
+ DBG("athread_del calling TerminateThread() because thread hasn't finished\n");
+ TerminateThread(p->th, (DWORD)-1); /* But it is worse to leave it hanging around */
+ }
+ CloseHandle(p->th);
+ }
+
+ free(p);
+}
+
+/* _beginthread doesn't leak memory, but */
+/* needs to be linked to a different library */
+#ifdef USE_BEGINTHREAD
+/* Thread function */
+static void __cdecl threadproc(
+ void *lpParameter
+) {
+#else
+DWORD WINAPI threadproc(
+ LPVOID lpParameter
+) {
+#endif
+ athread *p = (athread *)lpParameter;
+
+ p->result = p->function(p->context);
+ p->finished = 1;
+#ifdef USE_BEGINTHREAD
+#else
+ return 0;
+#endif
+}
+
+
+athread *new_athread(
+ int (*function)(void *context),
+ void *context
+) {
+ athread *p = NULL;
+
+ DBG("new_athread called\n");
+
+ if ((p = (athread *)calloc(sizeof(athread), 1)) == NULL) {
+ a1loge(g_log, 1, "new_athread: calloc failed\n");
+ return NULL;
+ }
+
+ p->function = function;
+ p->context = context;
+ p->wait = athread_wait;
+ p->del = athread_del;
+
+ /* Create a thread */
+#ifdef USE_BEGINTHREAD
+ p->th = _beginthread(threadproc, 0, (void *)p);
+ if (p->th == -1) {
+#else
+ p->th = CreateThread(NULL, 0, threadproc, (void *)p, 0, NULL);
+ if (p->th == NULL) {
+#endif
+ a1loge(g_log, 1, "new_athread: CreateThread failed with %d\n",GetLastError());
+ p->th = NULL;
+ athread_del(p);
+ return NULL;
+ }
+
+ DBG("new_athread returning OK\n");
+ return p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Delete a file */
+void delete_file(char *fname) {
+ _unlink(fname);
+}
+
+/* Given the path to a file, ensure that all the parent directories */
+/* are created. return nz on error */
+int create_parent_directories(char *path) {
+ struct _stat sbuf;
+ char *pp = path;
+
+ if (*pp != '\000' /* Skip drive number */
+ && ((*pp >= 'a' && *pp <= 'z') || (*pp >= 'A' && *pp <= 'Z'))
+ && pp[1] == ':')
+ pp += 2;
+ if (*pp == '/')
+ pp++; /* Skip root directory */
+ for (;pp != NULL && *pp != '\000';) {
+ if ((pp = strchr(pp, '/')) != NULL) {
+ *pp = '\000';
+ if (_stat(path,&sbuf) != 0)
+ {
+ if (_mkdir(path) != 0)
+ return 1;
+ }
+ *pp = '/';
+ pp++;
+ }
+ }
+ return 0;
+}
+
+#endif /* NT */
+
+
+/* ============================================================= */
+/* UNIX/OS X */
+/* ============================================================= */
+
+#if defined(UNIX)
+
+/* Wait for and return the next character from the keyboard */
+/* (If not_interactive, return getchar()) */
+int next_con_char(void) {
+ struct pollfd pa[1]; /* Poll array to monitor stdin */
+ struct termios origs, news;
+ char rv = 0;
+
+ 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;
+ news.c_lflag &= ~(ICANON | ECHO);
+ news.c_cc[VTIME] = 0;
+ news.c_cc[VMIN] = 1;
+ if (tcsetattr(STDIN_FILENO,TCSANOW, &news) < 0)
+ a1logw(g_log, "next_con_char: tcsetattr failed with '%s' on stdin", strerror(errno));
+ }
+
+ /* Wait for stdin to have a character */
+ pa[0].fd = STDIN_FILENO;
+ pa[0].events = POLLIN | POLLPRI;
+ pa[0].revents = 0;
+
+ if (poll_x(pa, 1, -1) > 0
+ && (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] ;
+ }
+ } 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 */
+ if (!not_interactive && tcsetattr(STDIN_FILENO, TCSANOW, &origs) < 0) {
+ a1logw(g_log, "next_con_char: tcsetattr failed with '%s' on stdin", strerror(errno));
+ }
+
+ return rv;
+}
+
+/* If here is one, return the next character from the keyboard, else return 0 */
+/* (If not_interactive, always returns 0) */
+int poll_con_char(void) {
+ struct pollfd pa[1]; /* Poll array to monitor stdin */
+ struct termios origs, news;
+ char rv = 0;
+
+ 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;
+ news.c_lflag &= ~(ICANON | ECHO);
+ news.c_cc[VTIME] = 0;
+ news.c_cc[VMIN] = 1;
+ if (tcsetattr(STDIN_FILENO,TCSANOW, &news) < 0)
+ a1logw(g_log, "poll_con_char: tcsetattr failed with '%s' on stdin", strerror(errno));
+ }
+
+ /* Wait for stdin to have a character */
+ pa[0].fd = STDIN_FILENO;
+ pa[0].events = POLLIN | POLLPRI;
+ pa[0].revents = 0;
+
+ if (poll_x(pa, 1, 0) > 0
+ && (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] ;
+ }
+ }
+
+ /* Restore stdin */
+ 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) */
+void empty_con_chars(void) {
+ if (not_interactive)
+ return;
+
+ tcflush(STDIN_FILENO, TCIFLUSH);
+}
+
+/* Sleep for the given number of msec */
+void msec_sleep(unsigned int msec) {
+#ifdef NEVER
+ if (msec > 1000) {
+ unsigned int secs;
+ secs = msec / 1000;
+ msec = msec % 1000;
+ sleep(secs);
+ }
+ usleep(msec * 1000);
+#else
+ struct timespec ts;
+
+ ts.tv_sec = msec / 1000;
+ ts.tv_nsec = (msec % 1000) * 1000000;
+ nanosleep(&ts, NULL);
+#endif
+}
+
+/* Return the current time in msec */
+/* since the first invokation of msec_time() */
+unsigned int msec_time() {
+ unsigned int rv;
+ static struct timeval startup = { 0, 0 };
+ struct timeval cv;
+
+ /* Is this monotonic ? */
+ /* On Linux, should clock_gettime with CLOCK_MONOTONIC be used instead ? */
+ /* On OS X, should mach_absolute_time() be used ? */
+ /* or host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clk) */
+ gettimeofday(&cv, NULL);
+
+ /* Set time to 0 on first invocation */
+ if (startup.tv_sec == 0 && startup.tv_usec == 0)
+ startup = cv;
+
+ /* Subtract, taking care of carry */
+ cv.tv_sec -= startup.tv_sec;
+ if (startup.tv_usec > cv.tv_usec) {
+ cv.tv_sec--;
+ cv.tv_usec += 1000000;
+ }
+ cv.tv_usec -= startup.tv_usec;
+
+ /* Convert usec to msec */
+ rv = cv.tv_sec * 1000 + cv.tv_usec / 1000;
+
+ return rv;
+}
+
+/* Return the current time in usec */
+/* since the first invokation of usec_time() */
+double usec_time() {
+ double rv;
+ static struct timeval startup = { 0, 0 };
+ struct timeval cv;
+
+ /* Is this monotonic ? */
+ /* On Linux, should clock_gettime with CLOCK_MONOTONIC/CLOCK_REALTIME/CLOCK_REALTIME_HR ? */
+ /* On OS X, should mach_absolute_time() be used ? */
+ /* or host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clk) */
+ gettimeofday(&cv, NULL);
+
+ /* Set time to 0 on first invocation */
+ if (startup.tv_sec == 0 && startup.tv_usec == 0)
+ startup = cv;
+
+ /* Subtract, taking care of carry */
+ cv.tv_sec -= startup.tv_sec;
+ if (startup.tv_usec > cv.tv_usec) {
+ cv.tv_sec--;
+ cv.tv_usec += 1000000;
+ }
+ cv.tv_usec -= startup.tv_usec;
+
+ /* Convert to usec */
+ rv = cv.tv_sec * 1000000.0 + cv.tv_usec;
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef NEVER /* Not currently needed, or effective */
+
+/* Set the current threads priority */
+int set_interactive_priority() {
+#ifdef __APPLE__
+#ifdef NEVER
+ int rv = 0;
+ struct task_category_policy tcatpolicy;
+
+ tcatpolicy.role = TASK_FOREGROUND_APPLICATION;
+
+ if (task_policy_set(mach_task_self(),
+ TASK_CATEGORY_POLICY, (thread_policy_t)&tcatpolicy,
+ TASK_CATEGORY_POLICY_COUNT) != KERN_SUCCESS)
+ rv = 1;
+// a1logd(g_log, 8, "set_interactive_priority: set to forground got %d\n",rv);
+ return rv;
+#else
+ int rv = 0;
+ struct thread_precedence_policy tppolicy;
+
+ tppolicy.importance = 500;
+
+ if (thread_policy_set(mach_thread_self(),
+ THREAD_PRECEDENCE_POLICY, (thread_policy_t)&tppolicy,
+ THREAD_PRECEDENCE_POLICY_COUNT) != KERN_SUCCESS)
+ rv = 1;
+// a1logd(g_log, 8, "set_interactive_priority: set to important got %d\n",rv);
+ return rv;
+#endif /* NEVER */
+#else /* !APPLE */
+ int rv;
+ struct sched_param param;
+ param.sched_priority = 32;
+
+ /* This doesn't work unless we're running as su :-( */
+ rv = pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);
+// a1logd(g_log, 8, "set_interactive_priority: set got %d\n",rv);
+ return rv;
+#endif /* !APPLE */
+}
+
+int set_normal_priority() {
+#ifdef __APPLE__
+#ifdef NEVER
+ int rv = 0;
+ struct task_category_policy tcatpolicy;
+
+ tcatpolicy.role = TASK_UNSPECIFIED;
+
+ if (task_policy_set(mach_task_self(),
+ TASK_CATEGORY_POLICY, (thread_policy_t)&tcatpolicy,
+ TASK_CATEGORY_POLICY_COUNT) != KERN_SUCCESS)
+ rev = 1;
+// a1logd(g_log, 8, "set_normal_priority: set to normal got %d\n",rv);
+#else
+ int rv = 0;
+ struct thread_precedence_policy tppolicy;
+
+ tppolicy.importance = 1;
+
+ if (thread_policy_set(mach_thread_self(),
+ THREAD_STANDARD_POLICY, (thread_policy_t)&tppolicy,
+ THREAD_STANDARD_POLICY_COUNT) != KERN_SUCCESS)
+ rv = 1;
+// a1logd(g_log, 8, "set_normal_priority: set to standard got %d\n",rv);
+ return rv;
+#endif /* NEVER */
+#else /* !APPLE */
+ struct sched_param param;
+ param.sched_priority = 0;
+ int rv;
+
+ rv = pthread_setschedparam(pthread_self(), SCHED_OTHER, &param);
+// a1logd(g_log, 8, "set_normal_priority: reset got %d\n",rv);
+ return rv;
+#endif /* !APPLE */
+}
+
+#endif /* NEVER */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static athread *beep_thread = NULL;
+static int beep_delay;
+static int beep_freq;
+static int beep_msec;
+
+/* Delayed beep handler */
+static int delayed_beep(void *pp) {
+ msec_sleep(beep_delay);
+#ifdef __APPLE__
+# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+ AudioServicesPlayAlertSound(kUserPreferredAlert);
+# else
+ SysBeep((beep_msec * 60)/1000);
+# endif
+#else /* UNIX */
+ /* Linux is pretty lame in this regard... */
+ fprintf(stdout, "\a"); fflush(stdout);
+#endif
+ return 0;
+}
+
+/* Activate the system beeper */
+void msec_beep(int delay, int freq, int msec) {
+ if (delay > 0) {
+ if (beep_thread != NULL)
+ beep_thread->del(beep_thread);
+ beep_delay = delay;
+ beep_freq = freq;
+ beep_msec = msec;
+ if ((beep_thread = new_athread(delayed_beep, NULL)) == NULL)
+ a1logw(g_log, "msec_beep: Delayed beep failed to create thread\n");
+ } else {
+#ifdef __APPLE__
+# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+ AudioServicesPlayAlertSound(kUserPreferredAlert);
+# else
+ SysBeep((msec * 60)/1000);
+# endif
+#else /* UNIX */
+ fprintf(stdout, "\a"); fflush(stdout);
+#endif
+ }
+}
+
+
+#ifdef NEVER
+/* If we're UNIX and running on X11, we could do this */
+/* sort of thing (from xset) to sound a beep, */
+/* IF we were linking with X11: */
+
+static void
+set_bell_vol(Display *dpy, int percent) {
+ XKeyboardControl values;
+ XKeyboardState kbstate;
+ values.bell_percent = percent;
+ if (percent == DEFAULT_ON)
+ values.bell_percent = SERVER_DEFAULT;
+ XChangeKeyboardControl(dpy, KBBellPercent, &values);
+ if (percent == DEFAULT_ON) {
+ XGetKeyboardControl(dpy, &kbstate);
+ if (!kbstate.bell_percent) {
+ values.bell_percent = -percent;
+ XChangeKeyboardControl(dpy, KBBellPercent, &values);
+ }
+ }
+ return;
+}
+
+static void
+set_bell_pitch(Display *dpy, int pitch) {
+ XKeyboardControl values;
+ values.bell_pitch = pitch;
+ XChangeKeyboardControl(dpy, KBBellPitch, &values);
+ return;
+}
+
+static void
+set_bell_dur(Display *dpy, int duration) {
+ XKeyboardControl values;
+ values.bell_duration = duration;
+ XChangeKeyboardControl(dpy, KBBellDuration, &values);
+ return;
+}
+
+XBell(..);
+
+#endif /* NEVER */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Wait for the thread to exit. Return the result */
+static int athread_wait(struct _athread *p) {
+
+ if (p->finished)
+ return p->result;
+
+ pthread_join(p->thid, NULL);
+
+ return p->result;
+}
+
+/* Destroy the thread */
+static void athread_del(
+athread *p
+) {
+ DBG("athread_del called\n");
+
+ if (p == NULL)
+ return;
+
+ if (!p->finished) {
+ pthread_cancel(p->thid);
+ }
+ pthread_join(p->thid, NULL);
+ free(p);
+}
+
+static void *threadproc(
+ void *param
+) {
+ athread *p = (athread *)param;
+
+ /* Register this thread with the Objective-C garbage collector */
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+ objc_registerThreadWithCollector();
+#endif
+
+ p->result = p->function(p->context);
+ p->finished = 1;
+
+ return 0;
+}
+
+
+athread *new_athread(
+ int (*function)(void *context),
+ void *context
+) {
+ int rv;
+ athread *p = NULL;
+
+ DBG("new_athread called\n");
+
+ if ((p = (athread *)calloc(sizeof(athread), 1)) == NULL) {
+ a1loge(g_log, 1, "new_athread: calloc failed\n");
+ return NULL;
+ }
+
+ p->function = function;
+ p->context = context;
+ p->wait = athread_wait;
+ p->del = athread_del;
+
+ /* Create a thread */
+ rv = pthread_create(&p->thid, NULL, threadproc, (void *)p);
+ if (rv != 0) {
+ a1loge(g_log, 1, "new_athread: pthread_create failed with %d\n",rv);
+ athread_del(p);
+ return NULL;
+ }
+
+ DBG("About to exit new_athread()\n");
+ return p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Delete a file */
+void delete_file(char *fname) {
+ unlink(fname);
+}
+
+/* Given the path to a file, ensure that all the parent directories */
+/* are created. return nz on error */
+int create_parent_directories(char *path) {
+ struct stat sbuf;
+ char *pp = path;
+ mode_t mode = 0700; /* Default directory mode */
+
+ if (*pp == '/')
+ pp++; /* Skip root directory */
+ for (;pp != NULL && *pp != '\000';) {
+ if ((pp = strchr(pp, '/')) != NULL) {
+ *pp = '\000';
+ if (stat(path,&sbuf) != 0)
+ {
+ if (mkdir(path, mode) != 0)
+ return 1;
+ } else
+ mode = sbuf.st_mode;
+ *pp = '/';
+ pp++;
+ }
+ }
+ return 0;
+}
+
+#endif /* defined(UNIX) */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+#if defined(__APPLE__) || defined(NT)
+
+/* Thread to monitor and kill the named processes */
+static int th_kkill_nprocess(void *pp) {
+ kkill_nproc_ctx *ctx = (kkill_nproc_ctx *)pp;
+
+ while(ctx->stop == 0) {
+ kill_nprocess(ctx->pname, ctx->log);
+ msec_sleep(20); /* Don't hog the CPU */
+ }
+ ctx->done = 1;
+
+ return 0;
+}
+
+static void kkill_nprocess_del(kkill_nproc_ctx *p) {
+ int i;
+
+ p->stop = 1;
+
+ DBG("kkill_nprocess del called\n");
+ for (i = 0; p->done == 0 && i < 100; i++) {
+ msec_sleep(50);
+ }
+
+ if (p->done == 0) { /* Hmm */
+ a1logw(p->log,"kkill_nprocess del failed to stop - killing thread\n");
+ p->th->del(p->th);
+ }
+
+ del_a1log(p->log);
+ free(p);
+
+ DBG("kkill_nprocess del done\n");
+}
+
+/* Start a thread to constantly kill a process. */
+/* Call ctx->del() when done */
+kkill_nproc_ctx *kkill_nprocess(char **pname, a1log *log) {
+ kkill_nproc_ctx *p;
+
+ DBG("kkill_nprocess called\n");
+ if (log != NULL && log->debug >= 8) {
+ int i;
+ a1logv(log, 8, "kkill_nprocess called with");
+ for (i = 0; pname[i] != NULL; i++)
+ a1logv(log, 8, " '%s'",pname[i]);
+ a1logv(log, 8, "\n");
+ }
+
+ if ((p = (kkill_nproc_ctx *)calloc(sizeof(kkill_nproc_ctx), 1)) == NULL) {
+ a1loge(log, 1, "kkill_nprocess: calloc failed\n");
+ return NULL;
+ }
+
+ p->pname = pname;
+ p->log = new_a1log_d(log);
+ p->del = kkill_nprocess_del;
+
+ if ((p->th = new_athread(th_kkill_nprocess, p)) == NULL) {
+ del_a1log(p->log);
+ free(p);
+ return NULL;
+ }
+ return p;
+}
+
+#ifdef NT
+
+/* Kill a list of named process. */
+/* Kill the first process found, then return */
+/* return < 0 if this fails. */
+/* return 0 if there is no such process */
+/* return 1 if a process was killed */
+int kill_nprocess(char **pname, a1log *log) {
+ PROCESSENTRY32 entry;
+ HANDLE snapshot;
+ int j;
+
+ /* Get a snapshot of the current processes */
+ if ((snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0)) == NULL) {
+ return -1;
+ }
+
+ while(Process32Next(snapshot,&entry) != FALSE) {
+ HANDLE proc;
+
+ if (strcmp(entry.szExeFile, "spotread.exe") == 0
+ && (proc = OpenProcess(PROCESS_TERMINATE, FALSE, entry.th32ProcessID)) != NULL) {
+ if (TerminateProcess(proc,0) == 0) {
+ a1logv(log, 8, "kill_nprocess: Failed to kill '%s'\n",entry.szExeFile);
+ } else {
+ a1logv(log, 8, "kill_nprocess: Killed '%s'\n",entry.szExeFile);
+ }
+ CloseHandle(proc);
+ }
+ for (j = 0;; j++) {
+ if (pname[j] == NULL) /* End of list */
+ break;
+ a1logv(log, 8, "kill_nprocess: Checking process '%s' against list '%s'\n",
+ entry.szExeFile,pname[j]);
+ if (strcmp(entry.szExeFile,pname[j]) == 0) {
+ a1logv(log, 1, "kill_nprocess: killing process '%s' pid %d\n",
+ entry.szExeFile,entry.th32ProcessID);
+
+ if ((proc = OpenProcess(PROCESS_TERMINATE, FALSE, entry.th32ProcessID)) == NULL
+ || TerminateProcess(proc,0) == 0) {
+ a1logv(log, 1, "kill_nprocess: kill process '%s' failed with %d\n",
+ pname[j],GetLastError());
+ CloseHandle(proc);
+ CloseHandle(snapshot);
+ return -1;
+ }
+ CloseHandle(proc);
+ /* Stop on first one found ? */
+ CloseHandle(snapshot);
+ return 1;
+ }
+ }
+ }
+ CloseHandle(snapshot);
+ return 0;
+}
+
+#endif /* NT */
+
+#if defined(__APPLE__)
+
+/* Kill a list of named process. */
+/* Kill the first process found, then return */
+/* return < 0 if this fails. */
+/* return 0 if there is no such process */
+/* return 1 if a process was killed */
+int kill_nprocess(char **pname, a1log *log) {
+ struct kinfo_proc *procList = NULL;
+ size_t procCount = 0;
+ static int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+ size_t length;
+ int rv = 0;
+ int i, j;
+
+ procList = NULL;
+ for (;;) {
+ int err;
+
+ /* Establish the amount of memory needed */
+ length = 0;
+ if (sysctl(name, (sizeof(name) / sizeof(*name)) - 1,
+ NULL, &length,
+ NULL, 0) == -1) {
+ DBGF((DBGA,"sysctl #1 failed with %d\n", errno));
+ return -1;
+ }
+
+ /* Add some more entries in case the number of processors changed */
+ length += 10 * sizeof(struct kinfo_proc);
+ if ((procList = malloc(length)) == NULL) {
+ DBGF((DBGA,"malloc failed for %d bytes\n", length));
+ return -1;
+ }
+
+ /* Call again with memory */
+ if ((err = sysctl(name, (sizeof(name) / sizeof(*name)) - 1,
+ procList, &length,
+ NULL, 0)) == -1) {
+ DBGF((DBGA,"sysctl #1 failed with %d\n", errno));
+ free(procList);
+ return -1;
+ }
+ if (err == 0) {
+ break;
+ } else if (err == ENOMEM) {
+ free(procList);
+ procList = NULL;
+ }
+ }
+
+ procCount = length / sizeof(struct kinfo_proc);
+
+ /* Locate the processes */
+ for (i = 0; i < procCount; i++) {
+ for (j = 0;; j++) {
+ if (pname[j] == NULL) /* End of list */
+ break;
+ a1logv(log, 8, "kill_nprocess: Checking process '%s' against list '%s'\n",
+ procList[i].kp_proc.p_comm,pname[j]);
+ if (strncmp(procList[i].kp_proc.p_comm,pname[j],MAXCOMLEN) == 0) {
+ a1logv(log, 1, "kill_nprocess: killing process '%s' pid %d\n",
+ pname[j],procList[i].kp_proc.p_pid);
+ if (kill(procList[i].kp_proc.p_pid, SIGTERM) != 0) {
+ a1logv(log, 1, "kill_nprocess: kill process '%s' failed with %d\n",
+ pname[j],errno);
+ free(procList);
+ return -1;
+ }
+ /* Stop on first one found ? */
+ free(procList);
+ return 1;
+ }
+ }
+ }
+ free(procList);
+ return rv;
+}
+
+#endif /* __APPLE__ */
+
+#endif /* __APPLE__ || NT */
+
+/* ============================================================= */
+
+/* A very small subset of icclib, copied to here. */
+/* This is just enough to support the standalone instruments */
+#ifdef SALONEINSTLIB
+
+sa_XYZNumber sa_D50 = {
+ 0.9642, 1.0000, 0.8249
+};
+
+void sa_SetUnity3x3(double mat[3][3]) {
+ int i, j;
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ if (i == j)
+ mat[j][i] = 1.0;
+ else
+ mat[j][i] = 0.0;
+ }
+ }
+
+}
+
+void sa_Cpy3x3(double dst[3][3], double src[3][3]) {
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ dst[j][i] = src[j][i];
+ }
+}
+
+void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]) {
+ double tt[3];
+
+ tt[0] = mat[0][0] * in[0] + mat[0][1] * in[1] + mat[0][2] * in[2];
+ tt[1] = mat[1][0] * in[0] + mat[1][1] * in[1] + mat[1][2] * in[2];
+ tt[2] = mat[2][0] * in[0] + mat[2][1] * in[1] + mat[2][2] * in[2];
+
+ out[0] = tt[0];
+ out[1] = tt[1];
+ out[2] = tt[2];
+}
+
+void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]) {
+ int i, j, k;
+ double td[3][3]; /* Temporary dest */
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ double tt = 0.0;
+ for (k = 0; k < 3; k++)
+ tt += src1[j][k] * src2[k][i];
+ td[j][i] = tt;
+ }
+ }
+
+ /* Copy result out */
+ for (j = 0; j < 3; j++)
+ for (i = 0; i < 3; i++)
+ dst[j][i] = td[j][i];
+}
+
+
+/* Matrix Inversion by Richard Carling from "Graphics Gems", Academic Press, 1990 */
+#define det2x2(a, b, c, d) (a * d - b * c)
+
+static void adjoint(
+double out[3][3],
+double in[3][3]
+) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+
+ /* assign to individual variable names to aid */
+ /* selecting correct values */
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ /* row column labeling reversed since we transpose rows & columns */
+
+ out[0][0] = det2x2(b2, b3, c2, c3);
+ out[1][0] = - det2x2(a2, a3, c2, c3);
+ out[2][0] = det2x2(a2, a3, b2, b3);
+
+ out[0][1] = - det2x2(b1, b3, c1, c3);
+ out[1][1] = det2x2(a1, a3, c1, c3);
+ out[2][1] = - det2x2(a1, a3, b1, b3);
+
+ out[0][2] = det2x2(b1, b2, c1, c2);
+ out[1][2] = - det2x2(a1, a2, c1, c2);
+ out[2][2] = det2x2(a1, a2, b1, b2);
+}
+
+static double sa_Det3x3(double in[3][3]) {
+ double a1, a2, a3, b1, b2, b3, c1, c2, c3;
+ double ans;
+
+ a1 = in[0][0]; b1 = in[0][1]; c1 = in[0][2];
+ a2 = in[1][0]; b2 = in[1][1]; c2 = in[1][2];
+ a3 = in[2][0]; b3 = in[2][1]; c3 = in[2][2];
+
+ ans = a1 * det2x2(b2, b3, c2, c3)
+ - b1 * det2x2(a2, a3, c2, c3)
+ + c1 * det2x2(a2, a3, b2, b3);
+ return ans;
+}
+
+#define SA__SMALL_NUMBER 1.e-8
+
+int sa_Inverse3x3(double out[3][3], double in[3][3]) {
+ int i, j;
+ double det;
+
+ /* calculate the 3x3 determinant
+ * if the determinant is zero,
+ * then the inverse matrix is not unique.
+ */
+ det = sa_Det3x3(in);
+
+ if ( fabs(det) < SA__SMALL_NUMBER)
+ return 1;
+
+ /* calculate the adjoint matrix */
+ adjoint(out, in);
+
+ /* scale the adjoint matrix to get the inverse */
+ for (i = 0; i < 3; i++)
+ for(j = 0; j < 3; j++)
+ out[i][j] /= det;
+ return 0;
+}
+
+#undef SA__SMALL_NUMBER
+#undef det2x2
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Transpose a 3x3 matrix */
+void sa_Transpose3x3(double out[3][3], double in[3][3]) {
+ int i, j;
+ if (out != in) {
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = in[j][i];
+ } else {
+ double tt[3][3];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ tt[i][j] = in[j][i];
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ out[i][j] = tt[i][j];
+ }
+}
+
+/* Scale a 3 vector by the given ratio */
+void sa_Scale3(double out[3], double in[3], double rat) {
+ out[0] = in[0] * rat;
+ out[1] = in[1] * rat;
+ out[2] = in[2] * rat;
+}
+
+/* Clamp a 3 vector to be +ve */
+void sa_Clamp3(double out[3], double in[3]) {
+ int i;
+ for (i = 0; i < 3; i++)
+ out[i] = in[i] < 0.0 ? 0.0 : in[i];
+}
+
+/* Return the normal Delta E given two Lab values */
+double sa_LabDE(double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ rv += tt * tt;
+
+ return sqrt(rv);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+/* A sub-set of ludecomp code from numlib */
+
+int sa_lu_decomp(double **a, int n, int *pivx, double *rip) {
+ int i, j;
+ double *rscale, RSCALE[10];
+
+ if (n <= 10)
+ rscale = RSCALE;
+ else
+ rscale = dvector(0, n-1);
+
+ for (i = 0; i < n; i++) {
+ double big;
+ for (big = 0.0, j=0; j < n; j++) {
+ double temp;
+ temp = fabs(a[i][j]);
+ if (temp > big)
+ big = temp;
+ }
+ if (fabs(big) <= DBL_MIN) {
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 1;
+ }
+ rscale[i] = 1.0/big;
+ }
+
+ for (*rip = 1.0, j = 0; j < n; j++) {
+ double big;
+ int k, bigi = 0;
+
+ for (i = 0; i < j; i++) {
+ double sum;
+ sum = a[i][j];
+ for (k = 0; k < i; k++)
+ sum -= a[i][k] * a[k][j];
+ a[i][j] = sum;
+ }
+
+ for (big = 0.0, i = j; i < n; i++) {
+ double sum, temp;
+ sum = a[i][j];
+ for (k = 0; k < j; k++)
+ sum -= a[i][k] * a[k][j];
+ a[i][j] = sum;
+ temp = rscale[i] * fabs(sum);
+ if (temp >= big) {
+ big = temp;
+ bigi = i;
+ }
+ }
+
+ if (j != bigi) {
+ {
+ double *temp;
+ temp = a[bigi];
+ a[bigi] = a[j];
+ a[j] = temp;
+ }
+ *rip = -(*rip);
+ rscale[bigi] = rscale[j];
+ }
+
+ pivx[j] = bigi;
+ if (fabs(a[j][j]) <= DBL_MIN) {
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 1;
+ }
+
+ if (j != (n-1)) {
+ double temp;
+ temp = 1.0/a[j][j];
+ for (i = j+1; i < n; i++)
+ a[i][j] *= temp;
+ }
+ }
+ if (rscale != RSCALE)
+ free_dvector(rscale, 0, n-1);
+ return 0;
+}
+
+void sa_lu_backsub(double **a, int n, int *pivx, double *b) {
+ int i, j;
+ int nvi;
+
+ for (nvi = -1, i = 0; i < n; i++) {
+ int px;
+ double sum;
+
+ px = pivx[i];
+ sum = b[px];
+ b[px] = b[i];
+ if (nvi >= 0) {
+ for (j = nvi; j < i; j++)
+ sum -= a[i][j] * b[j];
+ } else {
+ if (sum != 0.0)
+ nvi = i;
+ }
+ b[i] = sum;
+ }
+
+ for (i = (n-1); i >= 0; i--) {
+ double sum;
+ sum = b[i];
+ for (j = i+1; j < n; j++)
+ sum -= a[i][j] * b[j];
+ b[i] = sum/a[i][i];
+ }
+}
+
+int sa_lu_invert(double **a, int n) {
+ int i, j;
+ double rip;
+ int *pivx, PIVX[10];
+ double **y;
+
+ if (n <= 10)
+ pivx = PIVX;
+ else
+ pivx = ivector(0, n-1);
+
+ if (sa_lu_decomp(a, n, pivx, &rip)) {
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+ return 1;
+ }
+
+ y = dmatrix(0, n-1, 0, n-1);
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++) {
+ y[i][j] = a[i][j];
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < n; j++)
+ a[i][j] = 0.0;
+ a[i][i] = 1.0;
+ sa_lu_backsub(y, n, pivx, a[i]);
+ }
+
+ free_dmatrix(y, 0, n-1, 0, n-1);
+ if (pivx != PIVX)
+ free_ivector(pivx, 0, n-1);
+
+ return 0;
+}
+
+int sa_lu_psinvert(double **out, double **in, int m, int n) {
+ int rv = 0;
+ double **tr;
+ double **sq;
+
+ tr = dmatrix(0, n-1, 0, m-1);
+ matrix_trans(tr, in, m, n);
+
+ if (m > n) {
+ sq = dmatrix(0, n-1, 0, n-1);
+ if ((rv = matrix_mult(sq, n, n, tr, n, m, in, m, n)) == 0) {
+ if ((rv = sa_lu_invert(sq, n)) == 0) {
+ rv = matrix_mult(out, n, m, sq, n, n, tr, n, m);
+ }
+ }
+ free_dmatrix(sq, 0, n-1, 0, n-1);
+ } else {
+ sq = dmatrix(0, m-1, 0, m-1);
+ if ((rv = matrix_mult(sq, m, m, in, m, n, tr, n, m)) == 0) {
+ if ((rv = sa_lu_invert(sq, m)) == 0) {
+ rv = matrix_mult(out, n, m, tr, n, m, sq, m, m);
+ }
+ }
+ free_dmatrix(sq, 0, m-1, 0, m-1);
+ }
+
+ free_dmatrix(tr, 0, n-1, 0, m-1);
+ return rv;
+}
+
+
+#endif /* SALONEINSTLIB */
+/* ============================================================= */
+
+
diff --git a/spectro/conv.h b/spectro/conv.h
new file mode 100644
index 0000000..ab5e850
--- /dev/null
+++ b/spectro/conv.h
@@ -0,0 +1,297 @@
+#ifndef CONV_H
+
+/*
+ * Some system dependent comvenience functions.
+ * Implemented in unixio.c and ntio.c
+ */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/2/9
+ *
+ * Copyright 1996 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from icoms.h
+ */
+
+#if defined (NT)
+# if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
+# if defined _WIN32_WINNT
+# undef _WIN32_WINNT
+# endif
+# define _WIN32_WINNT 0x0501
+# endif
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# include <io.h>
+#endif
+
+#if defined (UNIX) || defined(__APPLE__)
+# include <unistd.h>
+# include <glob.h>
+# include <pthread.h>
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* - - - - - - - - - - - - - - - - - - -- */
+/* System compatibility #defines */
+#if defined (NT)
+
+#ifndef sys_stat
+# define sys_stat _stat
+#endif
+#ifndef sys_mkdir
+# define sys_mkdir _mkdir
+#endif
+#ifndef sys_read
+# define sys_read _read
+#endif
+#ifndef sys_utime
+# define sys_utime _utime
+# define sys_utimbuf _utimbuf
+#endif
+#ifndef sys_access
+# define sys_access _access
+#endif
+
+#ifndef snprintf
+# define snprintf _snprintf
+# define vsnprintf _vsnprintf
+#endif
+#ifndef stricmp
+# define stricmp _stricmp
+#endif
+
+#endif /* NT */
+
+#if defined (UNIX)
+
+#ifndef sys_stat
+# define sys_stat stat
+#endif
+#ifndef sys_mkdir
+# define sys_mkdir mkdir
+#endif
+#ifndef sys_read
+# define sys_read read
+#endif
+#ifndef sys_utime
+# define sys_utime utime
+# define sys_utimbuf utimbuf
+#endif
+#ifndef sys_access
+# define sys_access access
+#endif
+
+#ifndef stricmp
+# define stricmp strcasecmp
+#endif
+
+#endif /* UNIX */
+
+/* - - - - - - - - - - - - - - - - - - -- */
+/* System dependent convenience functions */
+
+/* wait for and then return the next character from the keyboard */
+/* (If not_interactive, return getchar()) */
+int next_con_char(void);
+
+/* If there is one, return the next character from the keyboard, else return 0 */
+/* (If not_interactive, always returns 0) */
+int poll_con_char(void);
+
+/* Empty the console of any pending characters */
+/* (If not_interactive, does nothing) */
+void empty_con_chars(void);
+
+/* Sleep for the given number of msec */
+void msec_sleep(unsigned int msec);
+
+/* Return the current time in msec since */
+/* the first invokation of msec_time() */
+unsigned int msec_time();
+
+/* Return the current time in usec */
+/* the first invokation of usec_time() */
+double usec_time();
+
+/* Activate the system beeper after a delay */
+/* (Note frequancy and duration may not be honoured on all systems) */
+void msec_beep(int delay, int freq, int msec);
+
+void normal_beep(); /* Emit a "normal" beep */
+void good_beep(); /* Emit a "good" beep */
+void bad_beep(); /* Emit a "bad" double beep */
+
+/* - - - - - - - - - - - - - - - - - - -- */
+
+#ifdef NEVER /* Not currently needed, or effective */
+
+/* Set the current threads priority */
+/* return nz if this fails */
+int set_interactive_priority();
+
+int set_normal_priority();
+
+#endif /* NEVER */
+
+/* - - - - - - - - - - - - - - - - - - -- */
+/* An Argyll mutex */
+
+/* amutex_trylock() returns nz if it can't lock the mutex */
+
+#ifdef NT
+# define amutex CRITICAL_SECTION
+# define amutex_init(lock) InitializeCriticalSection(&(lock))
+# define amutex_del(lock) DeleteCriticalSection(&(lock))
+# define amutex_lock(lock) EnterCriticalSection(&(lock))
+# define amutex_trylock(lock) (!TryEnterCriticalSection(&(lock)))
+# define amutex_unlock(lock) LeaveCriticalSection(&(lock))
+#endif
+
+#ifdef UNIX
+# define amutex pthread_mutex_t
+# define amutex_init(lock) pthread_mutex_init(&(lock), NULL)
+# define amutex_del(lock) pthread_mutex_destroy(&(lock))
+# define amutex_lock(lock) pthread_mutex_lock(&(lock))
+# define amutex_trylock(lock) pthread_mutex_trylock(&(lock))
+# define amutex_unlock(lock) pthread_mutex_unlock(&(lock))
+#endif
+
+/* - - - - - - - - - - - - - - - - - - -- */
+
+/* An Argyll thread. */
+struct _athread {
+#if defined (NT)
+ HANDLE th; /* Thread */
+#endif
+#if defined (UNIX) || defined(__APPLE__)
+ pthread_t thid; /* Thread ID */
+#endif
+ int finished; /* Set when the thread returned */
+ int result; /* Return code from thread function */
+
+ /* Thread function to call */
+ int (*function)(void *context);
+
+ /* And the context to call it with */
+ void *context;
+
+ /* Wait for the thread to exit. Return the result */
+ int (*wait)(struct _athread *p);
+
+ /* Kill the thread and delete the object */
+ /* (Killing it may have side effects, so this is a last */
+ /* resort if the thread hasn't exited) */
+ void (*del)(struct _athread *p);
+
+}; typedef struct _athread athread;
+
+/* Create and start a thread */
+/* Thread function should only return on completion or error. */
+/* It should return 0 on completion or exit, nz on error. */
+athread *new_athread(int (*function)(void *context), void *context);
+
+
+/* - - - - - - - - - - - - - - - - - - -- */
+
+/* Delete a file */
+void delete_file(char *fname);
+
+/* Given the path to a file, ensure that all the parent directories */
+/* are created. return nz on error */
+int create_parent_directories(char *path);
+
+/* - - - - - - - - - - - - - - - - - - -- */
+
+struct _kkill_nproc_ctx {
+ athread *th;
+ char **pname;
+ a1log *log;
+ int stop;
+ int done;
+ void (*del)(struct _kkill_nproc_ctx *p);
+}; typedef struct _kkill_nproc_ctx kkill_nproc_ctx;
+
+#if defined(__APPLE__) || defined(NT)
+
+/* Kill a list of named processes. NULL for last */
+/* return < 0 if this fails. */
+/* return 0 if there is no such process */
+/* return 1 if a process was killed */
+int kill_nprocess(char **pname, a1log *log);
+
+/* Start a thread to constantly kill a process. */
+/* Call ctx->del() when done */
+kkill_nproc_ctx *kkill_nprocess(char **pname, a1log *log);
+
+#endif /* __APPLE__ || NT */
+
+#include "xdg_bds.h"
+
+/* - - - - - - - - - - - - - - - - - - -- */
+/* A very small subset of icclib */
+#ifdef SALONEINSTLIB
+
+typedef struct {
+ double X;
+ double Y;
+ double Z;
+} sa_XYZNumber;
+
+typedef enum {
+ sa_SigXYZData = 0x58595A20L, /* 'XYZ ' */
+ sa_SigLabData = 0x4C616220L /* 'Lab ' */
+} sa_ColorSpaceSignature;
+
+extern sa_XYZNumber sa_D50;
+void sa_SetUnity3x3(double mat[3][3]);
+void sa_Cpy3x3(double out[3][3], double mat[3][3]);
+void sa_MulBy3x3(double out[3], double mat[3][3], double in[3]);
+void sa_Mul3x3_2(double dst[3][3], double src1[3][3], double src2[3][3]);
+int sa_Inverse3x3(double out[3][3], double in[3][3]);
+void sa_Transpose3x3(double out[3][3], double in[3][3]);
+void sa_Scale3(double out[3], double in[3], double rat);
+double sa_LabDE(double *in0, double *in1);
+
+
+#define icmXYZNumber sa_XYZNumber
+#define icColorSpaceSignature sa_ColorSpaceSignature
+#define icSigXYZData sa_SigXYZData
+#define icSigLabData sa_SigLabData
+#define icmD50 sa_D50
+#define icmSetUnity3x3 sa_SetUnity3x3
+#define icmCpy3x3 sa_Cpy3x3
+#define icmMulBy3x3 sa_MulBy3x3
+#define icmMul3x3_2 sa_Mul3x3_2
+#define icmInverse3x3 sa_Inverse3x3
+#define icmTranspose3x3 sa_Transpose3x3
+#define icmScale3 sa_Scale3
+#define icmClamp3 sa_Clamp3
+#define icmLabDE sa_LabDE
+
+/* A subset of numlib */
+
+int sa_lu_psinvert(double **out, double **in, int m, int n);
+
+#define lu_psinvert sa_lu_psinvert
+
+#endif /* SALONEINSTLIB */
+/* - - - - - - - - - - - - - - - - - - -- */
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define CONV_H
+#endif /* CONV_H */
diff --git a/spectro/dispcal.c b/spectro/dispcal.c
new file mode 100644
index 0000000..accb79a
--- /dev/null
+++ b/spectro/dispcal.c
@@ -0,0 +1,5356 @@
+
+/*
+ * Argyll Color Correction System
+ * Display callibrator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 14/10/2005
+ *
+ * Copyright 1996 - 2013 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.
+ */
+
+/* This program displays test patches, and takes readings from a display device */
+/* in order to create a RAMDAC calibration curve (usually stored in the ICC vcgt tag) */
+
+/* This is the third version of the program. */
+
+/* TTBD
+
+ Try to improve calibration speed by using adaptive
+ measurement set, rather than fixed resolution doubling ?
+ (ie. just measure at troublesome points using a "divide in half"
+ strategy ?. Estimate error between measurement points and
+ pick the next largest error.)
+
+ Add option to use L*u*v* DE's, as this is used in
+ some video standards. They sometime use u*v* as
+ a color tollerance too (see EBU TECH 3320).
+
+ Add a white point option that makes the target the
+ closest temperature to the native one of the display :-
+ ie. it moves the display to the closest point on the
+ chosen locus to RGB 1,1,1.
+ ie. should it do this if "-t" or "-T"
+ with no specific temperature is chosen ?
+
+ Change white point gamut clipping to be a measurement
+ search rather than computing from primary XYZ ?
+
+ Add bell at end of calibration ?
+
+
+ Add option to plot graph of native and calibrated RGB ?
+
+ Add a "delta E" number to the interactive adjustments,
+ so the significance of the error can be judged ?
+
+ Need to add flare measure/subtract, to improve
+ projector calibration ? - need to add to dispread too.
+
+ Instead of measuring/matching output at 50% device input as
+ measure of gamma, what about inverting it - measure/match device
+ values at 50% perceptual (18%) output value ?
+ [ Hmm. Current method is OK because a good perceptual
+ display gives about 18% output at 50% device input.]
+
+
+ The verify (-E) may not be being done correctly.
+ Like update, shouldn't it read the .cal file to set what's
+ being calibrated aganist ? (This would fix missing ambient value too!)
+
+ What about the "Read the base test set" - aren't
+ there numbers then used to tweak the black aim point
+ in "Figure out the black point target" - Yes they are !!
+ Verify probably shouldn't work this way.
+
+ */
+
+#ifdef __MINGW32__
+# define WINVER 0x0500
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include <stdarg.h>
+#if defined (NT)
+#include <conio.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "xicc.h"
+#include "xspect.h"
+#include "xcolorants.h"
+#include "ccmx.h"
+#include "ccss.h"
+#include "cgats.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "inst.h"
+#include "dispwin.h"
+#include "dispsup.h"
+#include "rspl.h"
+#include "moncurve.h"
+#include "targen.h"
+#include "ofps.h"
+#include "icc.h"
+#include "sort.h"
+#include "instappsup.h"
+#include "spyd2setup.h" /* Enable Spyder 2 access */
+
+#undef DEBUG
+#undef DEBUG_OFFSET /* Keep test window out of the way */
+#undef DEBUG_PLOT /* Plot curve each time around */
+#undef CHECK_MODEL /* Do readings to check the accuracy of our model */
+#undef SHOW_WINDOW_ONFAKE /* Display a test window up for a fake device */
+
+/* Invoke with -dfake for testing with a fake device. */
+/* Will use a fake.icm/.icc profile if present, or a built in fake */
+/* device behaviour if not. */
+
+#define COMPORT 1 /* Default com port 1..4 */
+#define OPTIMIZE_MODEL /* Adjust model for best fit */
+#define REFINE_GAIN 0.80 /* Refinement correction damping/gain */
+#define MAX_RPTS 12 /* Maximum tries at making a sample meet the current threshold */
+#define VER_RES 100 /* Verification resolution */
+#define NEUTRAL_BLEND_RATE 4.0 /* Default rate of transition for -k factor < 1.0 (power) */
+#define ADJ_JACOBIAN /* Adjust the Jacobian predictor matrix each time */
+#define JAC_COR_FACT 0.4 /* Amount to correct Jacobian by (to filter noise) */
+#define REMEAS_JACOBIAN /* Re-measure Jacobian */
+#define MOD_DIST_POW 1.6 /* Power used to distribute test samples for model building */
+#define REFN_DIST_POW 1.6 /* Power used to distribute test samples for grey axis refinement */
+#define CHECK_DIST_POW 1.6 /* Power used to distribute test samples for grey axis checking */
+#define THRESH_SCALE_POW 0.5 /* Amount to loosen threshold for first itterations */
+#define CAL_RES 256 /* Resolution of calibration table to produce. */
+#define CLIP /* Clip RGB during refinement */
+#define RDAC_SMOOTH 0.3 /* RAMDAC curve fitting smoothness */
+#define MEAS_RES /* Measure the RAMNDAC entry size */
+
+#ifdef DEBUG_PLOT
+#include "plot.h"
+#endif
+
+#if defined(DEBUG)
+
+#define DBG(xxx) fprintf xxx ;
+#define dbgo stderr
+#else
+#define DBG(xxx)
+#endif /* DEBUG */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Sample points used in initial device model optimisation */
+
+typedef struct {
+ double dev[3]; /* Device values */
+ double lab[3]; /* Read value */
+ double w; /* Weighting */
+} optref;
+
+/* - - - - - - - - - - - - - - - - - - - */
+/* device RGB inverse solution code */
+
+/* Selected transfer curve */
+typedef enum {
+ gt_power = 0, /* A simple power */
+ gt_Lab = 1, /* The L* curve */
+ gt_sRGB = 2, /* The sRGB curve */
+ gt_Rec709 = 3, /* REC 709 video standard */
+ gt_SMPTE240M = 4 /* SMTPE 240M video standard */
+} gammatype;
+
+/* Context for calibration solution */
+typedef struct {
+ double wh[3]; /* White absolute XYZ value */
+ double bk[3]; /* Black absolute XYZ value */
+
+ /* Target model */
+ gammatype gammat; /* Transfer curve type */
+ double egamma; /* Effective Gamma target */
+ double oofff; /* proportion of output offset vs input offset (default 1.0) */
+ double gioff; /* Gamma curve input zero offset */
+ double gooff; /* Target output offset (normalised to Y max of 1.0) */
+ int nat; /* Flag - nz if native white target */
+ double nbrate; /* Neutral blend weight (power) */
+
+ /* Viewing conditions adjustment */
+ int vc; /* Flag, nz to enable viewing conditions adjustment */
+ icxcam *svc; /* Source viewing conditions */
+ icxcam *dvc; /* Destination viewing conditions */
+ double vn0, vn1; /* Normalisation values */
+
+ double nwh[3]; /* Target white normalised XYZ value (Y = 1.0) */
+ double twh[3]; /* Target white absolute XYZ value */
+ icmXYZNumber twN; /* Same as above as XYZNumber */
+
+ double tbk[3]; /* Target black point color */
+ icmXYZNumber tbN; /* Same as above as XYZNumber */
+
+ /* Device model */
+ double fm[3][3]; /* Forward, aprox. linear RGB -> XYZ */
+ double bm[3][3]; /* Backwards, aprox. XYZ -> linear RGB */
+ mcv *dcvs[3]; /* Device RGB channel to linearised RGB curves */
+ /* These are always normalized to map 1.0 to 1.0 */
+
+ /* Current state */
+ mcv *rdac[3]; /* Current RGB to RGB ramdac curves */
+
+ double xyz[3]; /* Target xyz value */
+
+ /* optimisation information */
+ int np; /* Total number of optimisation parameters */
+ int co[3]; /* Offset in the parameters to each curve offset */
+ int nc[3]; /* Number of for each curve */
+ int nrp; /* Total number of reference points */
+ optref *rp; /* reference points */
+ double *dtin_iv; /* Temporary array :- dp for input curves */
+} calx;
+
+/* - - - - - - - - - - - - - - - - - - - */
+/* Ideal target curve definitions */
+
+/* Convert ideal device (0..1) to target Y value (0..1) */
+static double dev2Y(calx *x, double egamma, double vv) {
+
+ switch(x->gammat) {
+ case gt_power: {
+ vv = pow(vv, egamma);
+ break;
+ }
+ case gt_Lab: {
+ vv = icmL2Y(vv * 100.0);
+ break;
+ }
+ case gt_sRGB: {
+ if (vv <= 0.03928)
+ vv = vv/12.92;
+ else
+ vv = pow((0.055 + vv)/1.055, 2.4);
+ break;
+ }
+ case gt_Rec709: {
+ if (vv <= 0.081)
+ vv = vv/4.5;
+ else
+ vv = pow((0.099 + vv)/1.099, 1.0/0.45);
+ break;
+ }
+ case gt_SMPTE240M: {
+ if (vv <= 0.0913)
+ vv = vv/4.0;
+ else
+ vv = pow((0.1115 + vv)/1.1115, 1.0/0.45);
+ break;
+ }
+ default:
+ error("Unknown gamma type");
+ }
+ return vv;
+}
+
+/* Convert target Y value (0..1) to ideal device (0..1) */
+static double Y2dev(calx *x, double egamma, double vv) {
+
+ switch(x->gammat) {
+ case gt_power: {
+ vv = pow(vv, 1.0/egamma);
+ break;
+ }
+ case gt_Lab: {
+ vv = icmY2L(vv) * 0.01;
+ break;
+ }
+ case gt_sRGB: {
+ if (vv <= 0.00304)
+ vv = vv * 12.92;
+ else
+ vv = pow(vv, 1.0/2.4) * 1.055 - 0.055;
+ break;
+ }
+ case gt_Rec709: {
+ if (vv <= 0.018)
+ vv = vv * 4.5;
+ else
+ vv = pow(vv, 0.45) * 1.099 - 0.099;
+ break;
+ }
+ case gt_SMPTE240M: {
+ if (vv <= 0.0228)
+ vv = vv * 4.0;
+ else
+ vv = pow(vv, 0.45) * 1.1115 - 0.1115;
+ break;
+ }
+ default:
+ error("Unknown gamma type");
+ }
+ return vv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - */
+/* Compute a viewing environment Y transform */
+
+static double view_xform(calx *x, double in) {
+ double out = in;
+
+ if (x->vc != 0) {
+ double xyz[3], Jab[3];
+
+ xyz[0] = in * x->nwh[0]; /* Compute value on neutral axis */
+ xyz[1] = in * x->nwh[1];
+ xyz[2] = in * x->nwh[2];
+ x->svc->XYZ_to_cam(x->svc, Jab, xyz);
+ x->dvc->cam_to_XYZ(x->dvc, xyz, Jab);
+
+ out = xyz[1] * x->vn1 + x->vn0; /* Apply scaling factors */
+ }
+ return out;
+}
+
+/* - - - - - - - - - - - - - - - - - - - */
+
+/* Info for optimization */
+typedef struct {
+ double thyr; /* 50% input target */
+ double roo; /* 0% input target */
+} gam_fits;
+
+/* gamma + input offset function handed to powell() */
+static double gam_fit(void *dd, double *v) {
+ gam_fits *gf = (gam_fits *)dd;
+ double gamma = v[0];
+ double ioff = v[1];
+ double rv = 0.0;
+ double tt;
+
+ if (gamma < 0.0) {
+ rv += 100.0 * -gamma;
+ gamma = 0.0;
+ }
+ if (ioff < 0.0) {
+ rv += 100.0 * -ioff;
+ ioff = 0.0;
+ } else if (ioff > 0.999) {
+ rv += 100.0 * (ioff - 0.999);
+ ioff = 0.999;
+ }
+ tt = gf->roo - pow(ioff, gamma);
+ rv += tt * tt;
+ tt = gf->thyr - pow(0.5 + (1.0 - 0.5) * ioff, gamma);
+ rv += tt * tt;
+
+//printf("~1 gam_fit %f %f returning %f\n",ioff,gamma,rv);
+ return rv;
+}
+
+
+/* Given the advertised gamma and the output offset, compute the */
+/* effective gamma and input offset needed. */
+/* Return the expected output value for 50% input. */
+/* (It's assumed that gooff is normalised the target brightness) */
+static double tech_gamma(
+ calx *x,
+ double *pegamma, /* return effective gamma needed */
+ double *pooff, /* return output offset needed */
+ double *pioff, /* return input offset needed */
+ double egamma, /* effective gamma needed (> 0.0 if valid, overrides gamma) */
+ double gamma, /* advertised gamma needed */
+ double tooff /* Total ouput offset needed */
+) {
+ int i;
+ double rv;
+ double gooff = 0.0; /* The output offset applied */
+ double gioff = 0.0; /* The input offset applied */
+ double roo; /* Remaining output offset accounted for by input offset */
+
+ /* Compute the output offset that will be applied */
+ gooff = tooff * x->oofff;
+ roo = (tooff - gooff)/(1.0 - gooff);
+
+//printf("~1 gooff = %f, roo = %f\n",gooff,roo);
+
+ /* Now compute the input offset that will be needed */
+ if (x->gammat == gt_power && egamma <= 0.0) {
+ gam_fits gf;
+ double op[2], sa[2], rv;
+
+ gf.thyr = pow(0.5, gamma); /* Advetised 50% target */
+ gf.thyr = (gf.thyr - gooff)/(1.0 - gooff); /* Target before gooff is added */
+ gf.roo = roo;
+
+ op[0] = gamma;
+ op[1] = pow(roo, 1.0/gamma);
+ sa[0] = 0.1;
+ sa[1] = 0.01;
+
+ if (powell(&rv, 2, op, sa, 1e-6, 500, gam_fit, (void *)&gf, NULL, NULL) != 0)
+ warning("Computing effective gamma and input offset is inaccurate");
+
+ if (rv > 1e-5) {
+ warning("Computing effective gamma and input offset is inaccurate (%f)",rv);
+ }
+ egamma = op[0];
+ gioff = op[1];
+
+//printf("~1 Result gioff %f, gooff %f, egamma %f\n",gioff, gooff, egamma);
+//printf("~1 Verify 0.0 in -> out = %f, tooff = %f\n",gooff + dev2Y(x, egamma, gioff) * (1.0 - gooff),tooff);
+//printf("~1 Verify 0.5 out = %f, target %f\n",gooff + dev2Y(x, egamma, gioff + 0.5 * (1.0 - gioff)) * (1.0 - gooff), pow(0.5, gamma));
+
+ } else {
+ gioff = Y2dev(x, egamma, roo);
+//printf("~1 Result gioff %f, gooff %f\n",gioff, gooff);
+//printf("~1 Verify 0.0 in -> out = %f, tooff = %f\n",gooff + dev2Y(x, egamma, gioff) * (1.0 - gooff),tooff);
+ }
+
+ /* Compute the 50% output value */
+ rv = gooff + dev2Y(x, egamma, gioff + 0.5 * (1.0 - gioff)) * (1.0 - gooff);
+
+ if (pegamma != NULL)
+ *pegamma = egamma;
+ if (pooff != NULL)
+ *pooff = gooff;
+ if (pioff != NULL)
+ *pioff = gioff;
+ return rv;
+}
+
+/* Compute approximate advertised gamma from black/50% grey/white readings, */
+/* (assumes a zero based gamma curve shape) */
+static double pop_gamma(double bY, double gY, double wY) {
+ int i;
+ double grat, brat, gioff, gvv, gamma;
+
+ grat = gY/wY;
+ brat = bY/wY;
+
+ gamma = log(grat) / log(0.5);
+ return gamma;
+}
+
+/* - - - - - - - - - - - - - - - - - - - */
+
+/* Return the xyz that is predicted by our aproximate device model */
+/* by the given device RGB. */
+static void fwddev(calx *x, double xyz[3], double rgb[3]) {
+ double lrgb[3];
+ int j;
+
+//printf("~1 fwddev called with rgb %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ /* Convert device RGB into linear light RGB via curves */
+ for (j = 0; j < 3; j++)
+ lrgb[j] = x->dcvs[j]->interp(x->dcvs[j], rgb[j]);
+
+//printf("~1 fwddev got linear RGB %f %f %f\n",lrgb[0],lrgb[1],lrgb[2]);
+
+ /* Convert linear light RGB into XYZ via the matrix */
+ icmMulBy3x3(xyz, x->fm, lrgb);
+
+//printf("~1 fwddev got final xyz %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+}
+
+/* Return the closest device RGB predicted by our aprox. device model */
+/* to generate the given xyz. */
+static void invdev(calx *x, double rgb[3], double xyz[3]) {
+ double lrgb[3];
+ int j;
+
+//printf("~1 invdev called with xyz %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+
+ /* Convert XYZ to linear light RGB via the inverse matrix */
+ icmMulBy3x3(lrgb, x->bm, xyz);
+//printf("~1 invdev; lin light rgb = %f %f %f\n",lrgb[0],lrgb[1],lrgb[2]);
+
+ /* Convert linear light RGB to device RGB via inverse curves */
+ for (j = 0; j < 3; j++) {
+ lrgb[j] = x->dcvs[j]->inv_interp(x->dcvs[j], lrgb[j]);
+ if (lrgb[j] < 0.0) {
+#ifdef CLIP
+ lrgb[j] = 0.0;
+#endif
+ } else if (lrgb[j] > 1.0) {
+#ifdef CLIP
+ lrgb[j] = 1.0;
+#endif
+ }
+ }
+//printf("~1 invdev; inverse curves rgb = %f %f %f\n",lrgb[0],lrgb[1],lrgb[2]);
+ if (rgb != NULL) {
+ rgb[0] = lrgb[0];
+ rgb[1] = lrgb[1];
+ rgb[2] = lrgb[2];
+ }
+}
+
+/* Return the closest linear device RGB predicted by our aprox. device matrix */
+/* to generate the given xyz. */
+/* Return > 0 if clipped */
+static double invlindev(calx *x, double rgb[3], double xyz[3]) {
+ double lrgb[3];
+ double clip = 0.0;
+ int j;
+
+//printf("~1 invlindev called with xyz %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+
+ /* Convert XYZ to linear light RGB via the inverse matrix */
+ icmMulBy3x3(lrgb, x->bm, xyz);
+//printf("~1 invlindev; lin light rgb = %f %f %f\n",lrgb[0],lrgb[1],lrgb[2]);
+
+ /* Check for out of gamut */
+ for (j = 0; j < 3; j++) {
+ if (lrgb[j] < 0.0) {
+ if (-lrgb[j] > clip)
+ clip = -lrgb[j];
+ lrgb[j] = 0.0;
+ } else if (lrgb[j] > 1.0) {
+ if ((lrgb[j]-1.0) > clip)
+ clip = (lrgb[j]-1.0);
+ lrgb[j] = 1.0;
+ }
+ }
+//printf("~1 invlindev; clipped rgb = %f %f %f, clip = %f \n",lrgb[0],lrgb[1],lrgb[2],clip);
+ if (rgb != NULL) {
+ rgb[0] = lrgb[0];
+ rgb[1] = lrgb[1];
+ rgb[2] = lrgb[2];
+ }
+ return clip;
+}
+
+/* Overall optimisation support */
+
+/* Set the optimsation parameter number and offset values in calx, */
+/* and return an array filled in with the current parameters. */
+/* Allocate temporary arrays */
+static double *dev_get_params(calx *x) {
+ double *p, *tp;
+ int i, j;
+
+ x->np = 9;
+ for (i = 0; i < 3; i++)
+ x->np += x->dcvs[i]->luord;
+
+ if ((p = (double *)malloc(x->np * sizeof(double))) == NULL)
+ error("dev_params malloc failed");
+
+ tp = p;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ *tp++ = x->fm[i][j];
+
+ for (i = 0; i < 3; i++) {
+ x->co[i] = tp - p; /* Offset to start */
+ for (j = 0; j < x->dcvs[i]->luord; j++)
+ *tp++ = x->dcvs[i]->pms[j];
+ x->nc[i] = (tp - p) - x->co[i]; /* Number */
+ }
+
+ if ((x->dtin_iv = (double *)malloc(x->np * sizeof(double))) == NULL)
+ error("dev_params malloc failed");
+
+ return p;
+}
+
+/* Given a set of parameters, put them back into the model */
+/* Normalize them so that the curve maximum is 1.0 too. */
+static void dev_put_params(calx *x, double *p) {
+ int i, j;
+ double scale[3];
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ x->fm[i][j] = *p++;
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < x->dcvs[i]->luord; j++)
+ x->dcvs[i]->pms[j] = *p++;
+
+ /* Figure out how we have to scale the curves */
+ for (j = 0; j < 3; j++) {
+ scale[j] = x->dcvs[j]->interp(x->dcvs[j], 1.0);
+ x->dcvs[j]->force_scale(x->dcvs[j], 1.0);
+ }
+
+ /* Scale the matrix to compensate */
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ x->fm[i][j] *= scale[j];
+}
+
+/* Device model optimisation function handed to powell() */
+static double dev_opt_func(void *edata, double *v) {
+ calx *x = (calx *)edata;
+ int i, j;
+ double tw = 0.0;
+ double rv, smv;
+
+#ifdef NEVER
+ printf("params =");
+ for (i = 0; i < x->np; i++)
+ printf(" %f",v[i]);
+ printf("\n");
+#endif
+
+ /* For all our data points */
+ rv = 0.0;
+ for (i = 0; i < x->nrp; i++) {
+ double lrgb[3]; /* Linear light RGB */
+ double xyz[3], lab[3];
+ double de;
+
+ /* Convert through device curves */
+ for (j = 0; j < 3; j++)
+ lrgb[j] = x->dcvs[j]->interp_p(x->dcvs[j], v + x->co[j], x->rp[i].dev[j]);
+
+ /* Convert linear light RGB into XYZ via the matrix */
+ icxMulBy3x3Parm(xyz, v, lrgb);
+
+ /* Convert to Lab */
+ icmXYZ2Lab(&x->twN, lab, xyz);
+
+ /* Compute delta E squared */
+ de = icmCIE94sq(lab, x->rp[i].lab) * x->rp[i].w;
+#ifdef NEVER
+ printf("point %d DE %f, Lab is %f %f %f, should be %f %f %f\n",
+i, sqrt(de), lab[0], lab[1], lab[2], x->rp[i].lab[0], x->rp[i].lab[1], x->rp[i].lab[2]);
+#endif
+ rv += de;
+ tw += x->rp[i].w;
+ }
+
+ /* Normalise error to be a weighted average delta E squared and scale smoothing */
+ rv /= (tw * 5.0);
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles" */
+ smv = 0.0;
+ for (j = 0; j < 3; j++)
+ smv += x->dcvs[j]->shweight_p(x->dcvs[j], v + x->co[j], 1.0);
+ rv += smv;
+
+#ifdef NEVER
+ printf("rv = %f (%f)\n",rv, smv);
+#endif
+ return rv;
+}
+
+
+/* Device model optimisation function handed to conjgrad() */
+static double dev_dopt_func(void *edata, double *dv, double *v) {
+ calx *x = (calx *)edata;
+ int i, j, k;
+ int f, ee, ff, jj;
+ double tw = 0.0;
+ double rv, smv;
+
+ double dmato_mv[3][9]; /* Del in mat out due to del in matrix param vals */
+ double dmato_tin[3][3]; /* Del in mat out due to del in matrix input values */
+ double dout_lab[3][3]; /* Del in out due to XYZ to Lab conversion */
+ double de_dout[2][3]; /* Del in delta E due to input Lab values */
+
+#ifdef NEVER
+ printf("params =");
+ for (i = 0; i < x->np; i++)
+ printf(" %f",v[i]);
+ printf("\n");
+#endif
+
+ /* Zero the accumulated partial derivatives */
+ for (i = 0; i < x->np; i++)
+ dv[i] = 0.0;
+
+ /* For all our data points */
+ rv = 0.0;
+ for (i = 0; i < x->nrp; i++) {
+ double lrgb[3]; /* Linear light RGB */
+ double xyz[3], lab[3];
+
+ /* Apply the input channel curves */
+ for (j = 0; j < 3; j++)
+ lrgb[j] = x->dcvs[j]->dinterp_p(x->dcvs[j], v + x->co[j],
+ x->dtin_iv + x->co[j], x->rp[i].dev[j]);
+
+ /* Convert linear light RGB into XYZ via the matrix */
+ icxdpdiMulBy3x3Parm(xyz, dmato_mv, dmato_tin, v, lrgb);
+
+ /* Convert to Lab */
+ icxdXYZ2Lab(&x->twN, lab, dout_lab, xyz);
+
+ /* Compute delta E squared */
+//printf("~1 point %d: Lab is %f %f %f, should be %f %f %f\n",
+//i, lab[0], lab[1], lab[2], x->rp[i].lab[0], x->rp[i].lab[1], x->rp[i].lab[2]);
+ rv += icxdCIE94sq(de_dout, lab, x->rp[i].lab) * x->rp[i].w;
+ de_dout[0][0] *= x->rp[i].w;
+ de_dout[0][1] *= x->rp[i].w;
+ de_dout[0][2] *= x->rp[i].w;
+ tw += x->rp[i].w;
+
+ /* Compute and accumulate partial difference values for each parameter value */
+
+ /* Input channel curves */
+ for (ee = 0; ee < 3; ee++) { /* Parameter input chanel */
+ for (k = 0; k < x->nc[ee]; k++) { /* Param within channel */
+ double vv = 0.0;
+ jj = x->co[ee] + k; /* Overall input curve param */
+
+ for (ff = 0; ff < 3; ff++) { /* Lab channels */
+ for (f = 0; f < 3; f++) { /* XYZ channels */
+ vv += de_dout[0][ff] * dout_lab[ff][f]
+ * dmato_tin[f][ee] * x->dtin_iv[jj];
+ }
+ }
+ dv[jj] += vv;
+ }
+ }
+
+ /* Matrix parameters */
+ for (k = 0; k < 9; k++) { /* Matrix parameter */
+ double vv = 0.0;
+
+ for (ff = 0; ff < 3; ff++) { /* Lab channels */
+ for (f = 0; f < 3; f++) { /* XYZ channels */
+ vv += de_dout[0][ff] * dout_lab[ff][f]
+ * dmato_mv[f][k];
+ }
+ }
+ dv[k] += vv;
+ }
+ }
+
+ /* Normalise error to be a weighted average delta E squared and scale smoothing */
+ rv /= (tw * 1200.0);
+ for (i = 0; i < x->np; i++)
+ dv[i] /= (tw * 900.0);
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles" */
+ smv = 0.0;
+ for (j = 0; j < 3; j++)
+ smv += x->dcvs[j]->dshweight_p(x->dcvs[j], v + x->co[j], x->dtin_iv + x->co[j], 1.0);
+ rv += smv;
+
+#ifdef NEVER
+ printf("drv = %f (%f)\n",rv, smv);
+#endif
+ return rv;
+}
+
+#ifdef NEVER
+/* Check partial derivative function within dev_opt_func() using powell() */
+
+static double dev_opt_func(void *edata, double *v) {
+ calx *x = (calx *)edata;
+ int i;
+ double dv[2000];
+ double rv, drv;
+ double trv;
+
+ rv = dev_opt_func_(edata, v);
+ drv = dev_dopt_func(edata, dv, v);
+
+ if (fabs(rv - drv) > 1e-6) {
+ printf("######## RV MISMATCH is %f should be %f ########\n",drv, rv);
+ exit(0);
+ }
+
+ /* Check each parameter delta */
+ for (i = 0; i < x->np; i++) {
+ double del;
+
+ v[i] += 1e-7;
+ trv = dev_opt_func_(edata, v);
+ v[i] -= 1e-7;
+
+ /* Check that del is correct */
+ del = (trv - rv)/1e-7;
+ if (fabs(dv[i] - del) > 1.0) {
+//printf("~1 del = %f from (trv %f - rv %f)/0.1\n",del,trv,rv);
+ printf("######## EXCESSIVE at v[%d] is %f should be %f ########\n",i,dv[i],del);
+ exit(0);
+ }
+ }
+ return rv;
+}
+#endif
+
+/* =================================================================== */
+
+/* White point brightness optimization function handed to powell. */
+/* Maximize brigtness while staying within gamut */
+static double wp_opt_func(void *edata, double *v) {
+ calx *x = (calx *)edata;
+ double wxyz[3], rgb[3];
+ int j;
+ double rv = 0.0;
+
+ wxyz[0] = v[0] * x->twh[0];
+ wxyz[1] = v[0] * x->twh[1];
+ wxyz[2] = v[0] * x->twh[2];
+
+//printf("~1 wp_opt_func got scale %f, xyz = %f %f %f\n",
+//v[0],wxyz[0],wxyz[1],wxyz[2]);
+
+ if ((rv = invlindev(x, rgb, wxyz)) > 0.0) { /* Out of gamut */
+ rv *= 1e5;
+//printf("~1 out of gamut %f %f %f returning %f\n", rgb[0], rgb[1], rgb[2], rv);
+ return rv;
+ }
+ /* Maximize scale factor */
+ if (v[0] < 0.00001)
+ rv = 1.0/0.00001;
+ else
+ rv = 1.0/v[0];
+
+//printf("~1 %f %f %f returning %f\n", rgb[0], rgb[1], rgb[2], rv);
+ return rv;
+}
+
+/* =================================================================== */
+/* Structure to save aproximate model readings in */
+typedef struct {
+ double v; /* Input value */
+ double xyz[3]; /* Reading */
+} sxyz;
+
+/* ------------------------------------------------------------------- */
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a ppc gcc 3.3 optimiser bug... */
+/* It seems to cause a segmentation fault instead of */
+/* converting an integer loop index into a float, */
+/* when there are sufficient variables in play. */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+
+/* =================================================================== */
+/* Calibration sample point support. This allows the successive */
+/* refinement of our neutral sample points */
+
+/* A sample point */
+typedef struct {
+ double v; /* Desired input value */
+ double rgb[3]; /* Input value through calibration curves */
+ double tXYZ[3]; /* Target XYZ */
+ double XYZ[3]; /* Read XYZ */
+ double deXYZ[3]; /* Delta XYZ wanted to target */
+ double de; /* Delta Lab to neutral target */
+ double dc; /* Delta XYZ to neutral target */
+ double peqde; /* Delta Lab to previous point value (last pass) */
+ double hde; /* Hybrid de composed of de and peqde */
+
+ double pXYZ[3]; /* Previous measured XYZ */
+ double pdXYZ[3]; /* Delta XYZ intended from previous measure */
+ double pdrgb[3]; /* Delta rgb made to previous */
+
+ double dXYZ[3]; /* Actual delta XYZ resulting from previous delta rgb */
+
+ double j[3][3]; /* Aproximate Jacobian (del RGB -> XYZ) */
+ double ij[3][3]; /* Aproximate inverse Jacobian (del XYZ-> del RGB) */
+ double fb_ij[3][3]; /* Copy of initial inverse Jacobian, used as a fallback */
+} csp;
+
+/* All the sample points */
+typedef struct {
+ int no; /* Number of samples */
+ int _no; /* Allocation */
+ csp *s; /* List of samples */
+} csamp;
+
+static void free_alloc_csamp(csamp *p) {
+ if (p->s != NULL)
+ free(p->s);
+ p->s = NULL;
+}
+
+/* Initialise v values */
+static void init_csamp_v(csamp *p, calx *x, int psrand) {
+ int i, j;
+ sobol *so = NULL;
+
+ if (psrand != 0) { /* Use pseudo random distribution for verification */
+ if ((so = new_sobol(1)) == NULL)
+ error("New sobol failed");
+ }
+
+ /* Generate the sample points */
+ for (i = 0; i < p->no; i++) {
+ double vv;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ if (so != NULL) {
+ if (i == 0)
+ vv = 1.0;
+ else if (i == 1)
+ vv = 0.0;
+ else
+ so->next(so, &vv);
+ } else
+ vv = i/(p->no - 1.0);
+ vv = pow(vv, REFN_DIST_POW); /* Skew sample points to be slightly perceptual */
+ p->s[i].v = vv;
+ }
+
+ if (so != NULL) {
+ /* Sort it so white is last */
+#define HEAP_COMPARE(A,B) (A.v < B.v)
+ HEAPSORT(csp,p->s,p->no)
+#undef HEAP_COMPARE
+ so->del(so);
+ }
+}
+
+/* Initialise txyz values from v values */
+static void init_csamp_txyz(csamp *p, calx *x, int fixdev) {
+ int i, j;
+ double tbL[3]; /* tbk as Lab */
+
+ /* Convert target black from XYZ to Lab here, */
+ /* in case twN has changed at some point. */
+ icmXYZ2Lab(&x->twN, tbL, x->tbk);
+
+ /* Set the sample points targets */
+ for (i = 0; i < p->no; i++) {
+ double y, vv;
+ double XYZ[3]; /* Existing XYZ value */
+ double Lab[3];
+ double bl;
+
+ vv = p->s[i].v;
+
+ /* Compute target relative Y value for this device input. */
+ /* We allow for any input and/or output offset */
+ y = x->gooff + dev2Y(x, x->egamma, x->gioff + vv * (1.0 - x->gioff)) * (1.0 - x->gooff);
+
+ /* Add viewing environment transform */
+ y = view_xform(x, y);
+
+ /* Convert Y to L* */
+ Lab[0] = icmY2L(y);
+ Lab[1] = Lab[2] = 0.0; /* Target is neutral */
+
+ /* Compute blended neutral target a* b* */
+ bl = pow((1.0 - vv), x->nbrate); /* Crossover near the black */
+ Lab[1] = bl * tbL[1];
+ Lab[2] = bl * tbL[2];
+
+ icmAry2Ary(XYZ, p->s[i].tXYZ); /* Save the existing values */
+ icmLab2XYZ(&x->twN, p->s[i].tXYZ, Lab); /* New XYZ Value to aim for */
+
+#ifdef DEBUG
+ printf("%d: target XYZ %.2f %.2f %.2f, Lab %.2f %.2f %.2f\n",i, p->s[i].tXYZ[0],p->s[i].tXYZ[1],p->s[i].tXYZ[2], Lab[0],Lab[1],Lab[2]);
+#endif
+ }
+}
+
+
+/* Allocate the sample points and initialise them with the */
+/* target device and XYZ values, and first cut device values. */
+static void init_csamp(csamp *p, calx *x, int doupdate, int verify, int psrand, int no) {
+ int i, j;
+
+ p->_no = p->no = no;
+
+ if ((p->s = (csp *)malloc(p->_no * sizeof(csp))) == NULL)
+ error("csamp malloc failed");
+
+ /* Compute v and txyz */
+ init_csamp_v(p, x, psrand);
+ init_csamp_txyz(p, x, 0);
+
+ /* Generate the sample points */
+ for (i = 0; i < no; i++) {
+ double dd, vv;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ vv = p->s[i].v;
+
+ if (verify == 2) { /* Verifying through installed curve */
+ /* Make RGB values the input value */
+ p->s[i].rgb[0] = p->s[i].rgb[1] = p->s[i].rgb[2] = vv;
+
+ } else if (doupdate) { /* Start or verify through current cal curves */
+ for (j = 0; j < 3; j++) {
+ p->s[i].rgb[j] = x->rdac[j]->interp(x->rdac[j], vv);
+#ifdef CLIP
+ if (p->s[i].rgb[j] < 0.0)
+ p->s[i].rgb[j] = 0.0;
+ else if (p->s[i].rgb[j] > 1.0)
+ p->s[i].rgb[j] = 1.0;
+#endif
+ }
+ } else { /* we have model */
+ /* Lookup an initial device RGB for that target by inverting */
+ /* the approximate forward device model */
+ p->s[i].rgb[0] = p->s[i].rgb[1] = p->s[i].rgb[2] = vv;
+ invdev(x, p->s[i].rgb, p->s[i].tXYZ);
+ }
+ /* Force white to be native if native flag set */
+ if (x->nat && i == (no-1)) {
+//printf("~1 Forcing white rgb to be 1,1,1\n");
+ p->s[i].rgb[0] = p->s[i].rgb[1] = p->s[i].rgb[2] = 1.0;
+ }
+
+//printf("~1 Inital point %d rgb %f %f %f\n",i,p->s[i].rgb[0],p->s[i].rgb[1],p->s[i].rgb[2]);
+
+ /* Compute the approximate inverse Jacobian at this point */
+ /* by taking the partial derivatives wrt to each device */
+ /* channel of our aproximate forward model */
+ if (verify != 2) {
+ double refXYZ[3], delXYZ[3];
+ fwddev(x, refXYZ, p->s[i].rgb);
+ if (vv < 0.5)
+ dd = 0.02;
+ else
+ dd = -0.02;
+ /* Matrix organization is J[XYZ][RGB] for del RGB->del XYZ*/
+ for (j = 0; j < 3; j++) {
+ p->s[i].rgb[j] += dd;
+ fwddev(x, delXYZ, p->s[i].rgb);
+ p->s[i].j[0][j] = (delXYZ[0] - refXYZ[0]) / dd;
+ p->s[i].j[1][j] = (delXYZ[1] - refXYZ[1]) / dd;
+ p->s[i].j[2][j] = (delXYZ[2] - refXYZ[2]) / dd;
+ p->s[i].rgb[j] -= dd;
+ }
+ if (icmInverse3x3(p->s[i].ij, p->s[i].j)) {
+ error("dispcal: inverting Jacobian failed (1)");
+ }
+ /* Make a copy of this Jacobian in case we get an invert failure later */
+ icmCpy3x3(p->s[i].fb_ij, p->s[i].ij);
+ }
+ }
+}
+
+/* Return a linear XYZ interpolation */
+static void csamp_interp(csamp *p, double xyz[3], double v) {
+ int i, j;
+ double b;
+
+ if (p->no < 2)
+ error("Calling csamp_interp with less than two existing samples");
+
+ /* Locate the pair surrounding our input value */
+ for (i = 0; i < (p->no-1); i++) {
+ if (v >= p->s[i].v && v <= p->s[i+1].v)
+ break;
+ }
+ if (i >= (p->no-1))
+ error("csamp_interp out of range");
+
+ b = (v - p->s[i].v)/(p->s[i+1].v - p->s[i].v);
+
+ for (j = 0; j < 3; j++) {
+ xyz[j] = b * p->s[i+1].XYZ[j] + (1.0 - b) * p->s[i].XYZ[j];
+ }
+}
+
+/* Re-initialise a CSP with a new number of points. */
+/* Interpolate the device values and jacobian. */
+/* Set the current rgb from the current RAMDAC curves if not verifying */
+static void reinit_csamp(csamp *p, calx *x, int verify, int psrand, int no) {
+ csp *os; /* Old list of samples */
+ int ono; /* Old number of samples */
+ int i, j, k, m;
+
+ if (no == p->no)
+ return; /* Nothing has changed */
+
+ os = p->s; /* Save the existing per point information */
+ ono = p->no;
+
+ init_csamp(p, x, 0, 2, psrand, no);
+
+ p->_no = p->no = no;
+
+ /* Interpolate the current device values */
+ for (i = 0; i < no; i++) {
+ double vv, b;
+
+ vv = p->s[i].v;
+
+ /* Locate the pair surrounding our target value */
+ for (j = 0; j < ono-1; j++) {
+ if (vv >= os[j].v && vv <= os[j+1].v)
+ break;
+ }
+ if (j >= (ono-1))
+ error("csamp interp. out of range");
+
+ b = (vv - os[j].v)/(os[j+1].v - os[j].v);
+
+ for (k = 0; k < 3; k++) {
+ if (verify == 2) {
+
+ p->s[i].rgb[k] = b * os[j+1].rgb[k] + (1.0 - b) * os[j].rgb[k];
+
+ } else { /* Lookup rgb from current calibration curves */
+ for (m = 0; m < 3; m++) {
+ p->s[i].rgb[m] = x->rdac[m]->interp(x->rdac[m], vv);
+#ifdef CLIP
+ if (p->s[i].rgb[m] < 0.0)
+ p->s[i].rgb[m] = 0.0;
+ else if (p->s[i].rgb[m] > 1.0)
+ p->s[i].rgb[m] = 1.0;
+#endif
+ }
+ }
+ p->s[i].XYZ[k] = b * os[j+1].XYZ[k] + (1.0 - b) * os[j].XYZ[k];
+ p->s[i].deXYZ[k] = b * os[j+1].deXYZ[k] + (1.0 - b) * os[j].deXYZ[k];
+ p->s[i].pXYZ[k] = b * os[j+1].pXYZ[k] + (1.0 - b) * os[j].pXYZ[k];
+ p->s[i].pdrgb[k] = b * os[j+1].pdrgb[k] + (1.0 - b) * os[j].pdrgb[k];
+ p->s[i].dXYZ[k] = b * os[j+1].dXYZ[k] + (1.0 - b) * os[j].dXYZ[k];
+#ifdef INTERP_JAC
+ for (m = 0; m < 3; m++)
+ p->s[i].j[k][m] = b * os[j+1].j[k][m] + (1.0 - b) * os[j].j[k][m];
+#endif
+
+ }
+#ifndef INTERP_JAC
+ /* Create a Jacobian at this location from our forward model */
+ {
+ double dd, refXYZ[3], delXYZ[3];
+ fwddev(x, refXYZ, p->s[i].rgb);
+ if (vv < 0.5)
+ dd = 0.02;
+ else
+ dd = -0.02;
+ /* Matrix organization is J[XYZ][RGB] for del RGB->del XYZ*/
+ for (j = 0; j < 3; j++) {
+ p->s[i].rgb[j] += dd;
+ fwddev(x, delXYZ, p->s[i].rgb);
+ p->s[i].j[0][j] = (delXYZ[0] - refXYZ[0]) / dd;
+ p->s[i].j[1][j] = (delXYZ[1] - refXYZ[1]) / dd;
+ p->s[i].j[2][j] = (delXYZ[2] - refXYZ[2]) / dd;
+ p->s[i].rgb[j] -= dd;
+ }
+ }
+#endif
+ if (icmInverse3x3(p->s[i].ij, p->s[i].j)) {
+ error("dispcal: inverting Jacobian failed (2)");
+ }
+ /* Make a copy of this Jacobian in case we get an invert failure later */
+ icmCpy3x3(p->s[i].fb_ij, p->s[i].ij);
+
+ /* Compute expected delta XYZ using new Jacobian */
+ icmMulBy3x3(p->s[i].pdXYZ, p->s[i].j, p->s[i].pdrgb);
+
+ p->s[i].de = b * os[j+1].de + (1.0 - b) * os[j].de;
+ p->s[i].dc = b * os[j+1].dc + (1.0 - b) * os[j].dc;
+ }
+
+ free(os);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef NEVER
+/* Do a linear interp of the ramdac */
+static void interp_ramdac(double cal[CAL_RES][3], double drgb[3], double rgb[3]) {
+ int i, j;
+ int gres = CAL_RES;
+ double w;
+
+ /* For r,g & b */
+ for (j = 0; j < 3; j++) {
+ int mi, gres_1 = gres-1;
+ double t, vv = rgb[j];
+ t = gres * vv;
+ mi = (int)floor(t); /* Grid coordinate */
+ if (mi < 0) /* Limit to valid cube base index range */
+ mi = 0;
+ else if (mi >= gres_1)
+ mi = gres_1-1;
+ w = t - (double)mi; /* 1.0 - weight */
+
+ drgb[j] = (1.0 - w) * cal[mi][j] + w * cal[mi+1][j];
+ }
+}
+#endif /* NEVER */
+
+/* Given an XYZ, compute the color temperature and the delta E 2K to the locus */
+static double comp_ct(
+ double *de, /* If non-NULL, return CIEDE2000 to locus */
+ double lxyz[3], /* If non-NULL, return normalised XYZ on locus */
+ int plank, /* NZ if Plankian locus, 0 if Daylight locus */
+ int dovct, /* NZ if visual match, 0 if traditional correlation */
+ icxObserverType obType, /* If not default, set a custom observer */
+ double xyz[3] /* Color to match */
+) {
+ double ct_xyz[3]; /* XYZ on locus */
+ double nxyz[3]; /* Normalised input color */
+ double ct, ctde; /* Color temperature & delta E to Black Body locus */
+ icmXYZNumber wN;
+
+
+ if (obType == icxOT_default)
+ obType = icxOT_CIE_1931_2;
+
+ if ((ct = icx_XYZ2ill_ct(ct_xyz, plank != 0 ? icxIT_Ptemp : icxIT_Dtemp,
+ obType, NULL, xyz, NULL, dovct)) < 0)
+ error ("Got bad color temperature conversion\n");
+
+ if (de != NULL) {
+ icmAry2XYZ(wN, ct_xyz);
+ icmAry2Ary(nxyz, xyz);
+ nxyz[0] /= xyz[1];
+ nxyz[2] /= xyz[1];
+ nxyz[1] /= xyz[1];
+ ctde = icmXYZCIE2K(&wN, nxyz, ct_xyz);
+ *de = ctde;
+ }
+ if (lxyz != NULL) {
+ icmAry2Ary(lxyz, ct_xyz);
+ }
+ return ct;
+}
+
+/* =================================================================== */
+
+/* Default gamma */
+double g_def_gamma = 2.4;
+
+/*
+
+ Flags used:
+
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ upper .......... ....... . ...
+ lower ....... . ...... .... .
+
+*/
+
+void usage(char *diag, ...) {
+ int i;
+ disppath **dp;
+ icompaths *icmps;
+ inst2_capability cap2 = inst2_none;
+
+ fprintf(stderr,"Calibrate a Display, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (setup_spyd2() == 2)
+ fprintf(stderr,"WARNING: This file contains a proprietary firmware image, and may not be freely distributed !\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: dispcal [options] outfile\n");
+ fprintf(stderr," -v [n] Verbose mode\n");
+#if defined(UNIX_X11)
+ fprintf(stderr," -display displayname Choose X11 display name\n");
+ fprintf(stderr," -d n[,m] Choose the display n from the following list (default 1)\n");
+ fprintf(stderr," Optionally choose different display m for VideoLUT access\n");
+#else
+ fprintf(stderr," -d n Choose the display from the following list (default 1)\n");
+#endif
+ dp = get_displays();
+ if (dp == NULL || dp[0] == NULL)
+ fprintf(stderr," ** No displays found **\n");
+ else {
+ int i;
+ for (i = 0; ; i++) {
+ if (dp[i] == NULL)
+ break;
+ fprintf(stderr," %d = '%s'\n",i+1,dp[i]->description);
+ }
+ }
+ free_disppaths(dp);
+ fprintf(stderr," -dweb[:port] Display via a web server at port (default 8080)\n");
+// fprintf(stderr," -d fake Use a fake display device for testing, fake%s if present\n",ICC_FILE_EXT);
+ fprintf(stderr," -c listno Set communication port from the following list (default %d)\n",COMPORT);
+ if ((icmps = new_icompaths(g_log)) != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ if (paths[i]->itype == instSpyder2 && setup_spyd2() == 0)
+ fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
+ else
+ fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
+ }
+ } else
+ fprintf(stderr," ** No ports found **\n");
+ }
+ fprintf(stderr," -r Report on the calibrated display then exit\n");
+ fprintf(stderr," -R Report on the uncalibrated display then exit\n");
+ fprintf(stderr," -m Skip adjustment of the monitor controls\n");
+ fprintf(stderr," -o [profile%s] Create fast matrix/shaper profile [different filename to outfile%s]\n",ICC_FILE_EXT,ICC_FILE_EXT);
+ fprintf(stderr," -O \"description\" Fast ICC Profile Description string (Default \"outfile\")\n");
+ fprintf(stderr," -u Update previous calibration and (if -o used) ICC profile VideoLUTs\n");
+ fprintf(stderr," -q [vlmh] Quality - Very Low, Low, Medium (def), High\n");
+// 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");
+ cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 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");
+#ifdef NEVER /* Not worth confusing people about this ? */
+ fprintf(stderr," -L Show CCT/CDT rather than VCT/VDT during native white point adjustment\n");
+#endif
+ fprintf(stderr," -b bright Set the target white brightness in cd/m^2\n");
+ fprintf(stderr," -g gamma Set the target response curve advertised gamma (Def. %3.1f)\n",g_def_gamma);
+ fprintf(stderr," Use \"-gl\" for L*a*b* curve\n");
+ fprintf(stderr," Use \"-gs\" for sRGB curve\n");
+ fprintf(stderr," Use \"-g709\" for REC 709 curve (should use -a as well!)\n");
+ fprintf(stderr," Use \"-g240\" for SMPTE 240M curve (should use -a as well!)\n");
+ fprintf(stderr," Use \"-G2.4 -f0\" for BT.1886\n");
+ fprintf(stderr," -G gamma Set the target response curve actual technical gamma\n");
+ fprintf(stderr," -f [degree] Amount of black level accounted for with output offset (default all output offset)\n");
+ fprintf(stderr," -a ambient Use viewing condition adjustment for ambient in Lux\n");
+ fprintf(stderr," -k factor Amount to correct black hue, 0 = none, 1 = full, Default = Automatic\n");
+ fprintf(stderr," -A rate Rate of blending from neutral to black point. Default %.1f\n",NEUTRAL_BLEND_RATE);
+ fprintf(stderr," -B blkbright Set the target black brightness in cd/m^2\n");
+ fprintf(stderr," -e [n] Run n verify passes on final curves\n");
+ fprintf(stderr," -E Run only verify pass on installed calibration curves\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");
+ fprintf(stderr," ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.\n");
+ fprintf(stderr," -F Fill whole screen with black background\n");
+#if defined(UNIX_X11)
+ fprintf(stderr," -n Don't set override redirect on test window\n");
+#endif
+ fprintf(stderr," -J Run instrument calibration first (used rarely)\n");
+ fprintf(stderr," -N Disable initial calibration of instrument if possible\n");
+ fprintf(stderr," -H Use high resolution spectrum mode (if available)\n");
+// fprintf(stderr," -V Use adaptive measurement mode (if available)\n");
+ if (cap2 & inst2_ccmx)
+ fprintf(stderr," -X file.ccmx Apply Colorimeter Correction Matrix\n");
+ if (cap2 & inst2_ccss) {
+ fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n");
+ fprintf(stderr," -Q observ Choose CIE Observer for spectrometer or CCSS colorimeter data:\n");
+ fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2, 1964_10c\n");
+ }
+ fprintf(stderr," -I b|w Drift compensation, Black: -Ib, White: -Iw, Both: -Ibw\n");
+ fprintf(stderr," -Y A Use non-adaptive integration time mode (if available).\n");
+ fprintf(stderr," -C \"command\" Invoke shell \"command\" each time a color is set\n");
+ fprintf(stderr," -M \"command\" Invoke shell \"command\" each time a color is measured\n");
+ fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
+ fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
+ fprintf(stderr," inoutfile Base name for created or updated .cal and %s output files\n",ICC_FILE_EXT);
+ if (icmps != NULL)
+ icmps->del(icmps);
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int i, j, k;
+ int fa, nfa, mfa; /* current argument we're looking at */
+ disppath *disp = NULL; /* Display being used */
+ double hpatscale = 1.0, vpatscale = 1.0; /* scale factor for test patch size */
+ double ho = 0.0, vo = 0.0; /* Test window offsets, -1.0 to 1.0 */
+ int blackbg = 0; /* NZ if whole screen should be filled with black */
+ int verb = 0;
+ int debug = 0;
+ int fake = 0; /* Use the fake device for testing */
+ int override = 1; /* Override redirect on X11 */
+ int docalib = 0; /* Do a manual instrument calibration */
+ int doreport = 0; /* 1 = Report the current uncalibrated display response */
+ /* 2 = Report the current calibrated display response */
+ int docontrols = 1; /* Do adjustment of the display controls */
+ int doprofile = 0; /* Create/update ICC profile */
+ char *profDesc = NULL; /* Created profile description string */
+ char *copyright = NULL; /* Copyright string */
+ char *deviceMfgDesc = NULL; /* Device manufacturer string */
+ char *modelDesc = NULL; /* Device model description string */
+ int doupdate = 0; /* Do an update rather than a fresh calbration */
+ int comport = COMPORT; /* COM port used */
+ icompaths *icmps = NULL;
+ icompath *ipath = NULL;
+ flow_control fc = fc_nc; /* Default flow control */
+ int dtype = 0; /* Display type selection charater */
+ int tele = 0; /* nz if telephoto mode */
+ int nocal = 0; /* Disable auto calibration */
+ int highres = 0; /* Use high res mode if available */
+ int nadaptive = 0; /* Use non-adaptive mode if available */
+ int bdrift = 0; /* Flag, nz for black drift compensation */
+ int wdrift = 0; /* Flag, nz for white drift compensation */
+ double temp = 0.0; /* Color temperature (0 = native) */
+ int planckian = 0; /* 0 = Daylight, 1 = Planckian color locus */
+ int dovct = 1; /* Show VXT rather than CXT for adjusting white point */
+ double wpx = 0.0, wpy = 0.0; /* White point xy (native) */
+ double tbright = 0.0; /* Target white brightness ( 0.0 == max) */
+ double gamma = 0.0; /* Advertised Gamma target */
+ double egamma = 0.0; /* Effective Gamma target, NZ if set */
+ double ambient = 0.0; /* NZ if viewing cond. adjustment to be used (cd/m^2) */
+ double bkcorrect = -1.0; /* Level of black point correction, < 0 = auto */
+ double bkbright = 0.0; /* Target black brightness ( 0.0 == min) */
+ int quality = -99; /* Quality level, -2 = v, -1 = l, 0 = m, 1 = h, 2 = u */
+ int isteps = 22; /* Initial measurement steps/3 (medium) */
+ int rsteps = 64; /* Refinement measurement steps (medium) */
+ double errthr = 1.5; /* Error threshold for refinement steps (medium) */
+ int thrfail = 0; /* Set to NZ if failed to meet threshold target */
+ double failerr = 0.0; /* Delta E of worst failed target */
+ int mxits = 3; /* maximum iterations (medium) */
+ int verify = 0; /* Do a verify after last refinement, 2 = do only verify. */
+ int nver = 0; /* Number of verify passes after refinement */
+ int webdisp = 0; /* NZ for web display, == port number */
+ char *ccallout = NULL; /* Change color Shell callout */
+ char *mcallout = NULL; /* Measure color Shell callout */
+ char outname[MAXNAMEL+1] = { 0 }; /* Output cgats file base name */
+ char iccoutname[MAXNAMEL+1] = { 0 };/* Output icc file base name */
+ char ccxxname[MAXNAMEL+1] = "\000"; /* CCMX or CCSS file name */
+ ccmx *cmx = NULL; /* Colorimeter Correction Matrix */
+ ccss *ccs = NULL; /* Colorimeter Calibration Spectral Samples */
+ int spec = 0; /* Want spectral data from instrument */
+ icxObserverType obType = icxOT_default;
+ disprd *dr = NULL; /* Display patch read object */
+ csamp asgrey; /* Main calibration loop test points */
+ double dispLum = 0.0; /* Display luminence reading */
+ int it; /* verify & refine iteration */
+ int rv;
+ int fitord = 30; /* More seems to make curves smoother */
+ int native = 1; /* 0 = use current or given calibration curve */
+ /* 1 = set native linear op and use ramdac high prec'n */
+ int noramdac = 0; /* Will be set to nz if can't set ramdac */
+ int errc; /* Return value from new_disprd() */
+ calx x; /* Context for calibration solution */
+
+ set_exe_path(argv[0]); /* Set global exe_path and error_program */
+ check_if_not_interactive();
+
+#if defined(__APPLE__)
+ {
+ SInt32 MacVers;
+
+ /* Hmm. Maybe this should actually be 1.72 ?? */
+ g_def_gamma = 1.8;
+
+ /* OS X 10.6 uses a nominal gamma of 2.2 */
+ if (Gestalt(gestaltSystemVersion, &MacVers) == noErr) {
+ if (MacVers >= 0x1060) {
+ g_def_gamma = 2.4;
+ }
+ }
+ }
+#else
+ g_def_gamma = 2.4; /* Typical CRT gamma */
+#endif
+ gamma = g_def_gamma;
+
+ setup_spyd2(); /* Load firware if available */
+
+ x.gammat = gt_power ; /* Default gamma type */
+ x.egamma = 0.0; /* Default effective gamma none */
+ x.oofff = 1.0; /* Default is all output ofset */
+ x.vc = 0; /* No viewing conditions adjustment */
+ x.svc = NULL;
+ x.dvc = NULL;
+ x.nbrate = NEUTRAL_BLEND_RATE; /* Rate of blending from black point to neutral axis */
+
+#ifdef DEBUG_OFFSET
+ ho = 0.8;
+ vo = -0.8;
+#endif
+
+#if defined(DEBUG) || defined(DEBUG_OFFSET) || defined(DEBUG_PLOT)
+ printf("!!!!!! Debug turned on !!!!!!\n");
+#endif
+
+ if (argc <= 1)
+ usage("Too few arguments");
+
+ /* Process the arguments */
+ mfa = 1; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') /* Look for any flags */
+ {
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?' || argv[fa][1] == '-') {
+ usage("Usage requested");
+
+ } else if (argv[fa][1] == 'v') {
+ verb = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ verb = atoi(na);
+ fa = nfa;
+ }
+ g_log->verb = verb;
+
+ /* Display number */
+ } else if (argv[fa][1] == 'd') {
+ if (strncmp(na,"web",3) == 0
+ || strncmp(na,"WEB",3) == 0) {
+ webdisp = 8080;
+ if (na[3] == ':') {
+ webdisp = atoi(na+4);
+ if (webdisp == 0 || webdisp > 65535)
+ usage("Web port number must be in range 1..65535");
+ }
+ fa = nfa;
+ } else {
+#if defined(UNIX_X11)
+ int ix, iv;
+
+ if (strcmp(&argv[fa][2], "isplay") == 0 || strcmp(&argv[fa][2], "ISPLAY") == 0) {
+ if (++fa >= argc || argv[fa][0] == '-') usage("Parameter expected following -display");
+ setenv("DISPLAY", argv[fa], 1);
+ } else {
+ if (na == NULL) usage("Parameter expected following -d");
+ fa = nfa;
+ if (strcmp(na,"fake") == 0) {
+ fake = 1;
+ } else {
+ if (sscanf(na, "%d,%d",&ix,&iv) != 2) {
+ ix = atoi(na);
+ iv = 0;
+ }
+ if (disp != NULL)
+ free_a_disppath(disp);
+ if ((disp = get_a_display(ix-1)) == NULL)
+ usage("-d parameter %d out of range",ix);
+ if (iv > 0)
+ disp->rscreen = iv-1;
+ }
+ }
+#else
+ int ix;
+ if (na == NULL) usage("Parameter expected following -d");
+ fa = nfa;
+ if (strcmp(na,"fake") == 0) {
+ fake = 1;
+ } else {
+ ix = atoi(na);
+ if (disp != NULL)
+ free_a_disppath(disp);
+ if ((disp = get_a_display(ix-1)) == NULL)
+ usage("-d parameter %d out of range",ix);
+ }
+#endif
+ }
+
+ } else if (argv[fa][1] == 'J') {
+ docalib = 1;
+
+ } else if (argv[fa][1] == 'N') {
+ nocal = 1;
+
+ /* High res mode */
+ } else if (argv[fa][1] == 'H') {
+ highres = 1;
+
+ /* Adaptive mode - now default, so flag is deprecated */
+ } else if (argv[fa][1] == 'V') {
+ warning("dispcal -V flag is deprecated");
+
+ /* Colorimeter Correction Matrix */
+ /* or Colorimeter Calibration Spectral Samples */
+ } else if (argv[fa][1] == 'X') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected following -X");
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+
+ /* Drift Compensation */
+ } else if (argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL || na[0] == '\000') usage("Parameter expected after -I");
+ for (i=0; ; i++) {
+ if (na[i] == '\000')
+ break;
+ if (na[i] == 'b' || na[i] == 'B')
+ bdrift = 1;
+ else if (na[i] == 'w' || na[i] == 'W')
+ wdrift = 1;
+ else
+ usage("-I parameter '%c' not recognised",na[i]);
+ }
+
+ /* Spectral Observer type */
+ } else if (argv[fa][1] == 'Q') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expecte after -Q");
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ obType = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ obType = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1964_10c") == 0) { /* 10 degree corrected */
+ obType = icxOT_CIE_1964_10c;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ obType = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ obType = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ obType = icxOT_Shaw_Fairchild_2;
+ } else
+ usage("-Q parameter '%s' not recognised",na);
+
+ /* Change color callout */
+ } else if (argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -C");
+ ccallout = na;
+
+ /* Measure color callout */
+ } else if (argv[fa][1] == 'M') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -M");
+ mcallout = na;
+
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -W");
+ if (na[0] == 'n' || na[0] == 'N')
+ fc = fc_none;
+ else if (na[0] == 'h' || na[0] == 'H')
+ fc = fc_Hardware;
+ else if (na[0] == 'x' || na[0] == 'X')
+ fc = fc_XonXOff;
+ else
+ usage("-W parameter '%c' not recognised",na[0]);
+
+ /* Debug coms */
+ } else if (argv[fa][1] == 'D') {
+ debug = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ debug = atoi(na);
+ fa = nfa;
+ }
+ g_log->debug = debug;
+ callback_ddebug = 1; /* dispwin global */
+
+ /* Black point correction amount */
+ } else if (argv[fa][1] == 'k') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -k");
+ bkcorrect = atof(na);
+ if (bkcorrect < 0.0 || bkcorrect > 1.0) usage("-k parameter must be between 0.0 and 1.0");
+ /* Neutral blend rate (power) */
+ } else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -A");
+ x.nbrate = atof(na);
+ if (x.nbrate < 0.05 || x.nbrate > 20.0) usage("-A parameter must be between 0.05 and 20.0");
+ /* Black brightness */
+ } else if (argv[fa][1] == 'B') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -B");
+ bkbright = atof(na);
+ if (bkbright <= 0.0 || bkbright > 100000.0) usage("-B parameter %f out of range",bkbright);
+
+ /* Number of verify passes */
+ } else if (argv[fa][1] == 'e') {
+ verify = 1;
+ nver = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ nver = atoi(na);
+ fa = nfa;
+ }
+
+ } else if (argv[fa][1] == 'E') {
+ verify = 2;
+ mfa = 0;
+
+#if defined(UNIX_X11)
+ } else if (argv[fa][1] == 'n') {
+ override = 0;
+#endif /* UNIX */
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -c");
+ comport = atoi(na);
+ if (comport < 1 || comport > 50) usage("-c parameter %d out of range",comport);
+
+ /* Telephoto */
+ } else if (argv[fa][1] == 'p') {
+ tele = 1;
+
+ } else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ if (argv[fa][1] == 'R')
+ doreport = 1; /* raw */
+ else
+ doreport = 2; /* Calibrated */
+ mfa = 0;
+
+ } else if (argv[fa][1] == 'm') {
+ docontrols = 0;
+
+ /* Output/update ICC profile [optional different name] */
+ } else if (argv[fa][1] == 'o') {
+ doprofile = 1;
+
+ if (na != NULL) { /* Found an optional icc profile name */
+ fa = nfa;
+ strncpy(iccoutname,na,MAXNAMEL); iccoutname[MAXNAMEL] = '\000';
+ }
+
+ /* Fast Profile Description */
+ } else if (argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to profile description flag -O");
+ profDesc = na;
+
+ /* Update calibration and (optionally) profile */
+ } else if (argv[fa][1] == 'u') {
+ doupdate = 1;
+ docontrols = 0;
+
+ /* Speed/Quality */
+ } else if (argv[fa][1] == 'q') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected following -q");
+ switch (na[0]) {
+ case 'L': /* Test value */
+ quality = -3;
+ break;
+ case 'v': /* very fast */
+ quality = -2;
+ break;
+ case 'f': /* fast */
+ case 'l':
+ quality = -1;
+ break;
+ case 'm': /* medium */
+ case 'M':
+ quality = 0;
+ break;
+ case 's': /* slow */
+ case 'h':
+ case 'H':
+ quality = 1;
+ break;
+ case 'u': /* ultra slow */
+ case 'U':
+ quality = 2;
+ break;
+ default:
+ usage("-q parameter '%c' not recognised",na[0]);
+ }
+
+ /* Display type */
+ } else if (argv[fa][1] == 'y') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -y");
+ dtype = na[0];
+
+ /* Daylight color temperature */
+ } else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ if (argv[fa][1] == 'T')
+ planckian = 1;
+ else
+ planckian = 0;
+ if (na != NULL) {
+ fa = nfa;
+ temp = atof(na);
+ if (temp < 1000.0 || temp > 15000.0) usage("-%c parameter %f out of range",argv[fa][1], temp);
+ }
+
+ /* White point as x, y */
+ } else if (argv[fa][1] == 'w') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -w");
+ if (sscanf(na, " %lf,%lf ", &wpx, &wpy) != 2)
+ usage("-w parameter '%s' not recognised",na);
+
+ /* Show CXT rather than VXT when adjusting native white point */
+ } else if (argv[fa][1] == 'L') {
+ dovct = 0;
+
+ /* White brightness */
+ } else if (argv[fa][1] == 'b') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -b");
+ tbright = atof(na);
+ if (tbright <= 0.0 || tbright > 100000.0) usage("-b parameter %f out of range",tbright);
+
+ /* Target transfer curve */
+ } else if (argv[fa][1] == 'g') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -g");
+ if ((na[0] == 'l' || na[0] == 'L') && na[1] == '\000')
+ x.gammat = gt_Lab;
+ else if ((na[0] == 's' || na[0] == 'S') && na[1] == '\000')
+ x.gammat = gt_sRGB;
+ else if (strcmp(na, "709") == 0)
+ x.gammat = gt_Rec709;
+ else if (strcmp(na, "240") == 0)
+ x.gammat = gt_SMPTE240M;
+ else {
+ gamma = atof(na);
+ if (gamma <= 0.0 || gamma > 10.0) usage("-g parameter %f out of range",gamma);
+ x.gammat = gt_power;
+ }
+
+ /* Effective gamma power */
+ } else if (argv[fa][1] == 'G') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -G");
+ egamma = atof(na);
+ if (egamma <= 0.0 || egamma > 10.0) usage("-G parameter %f out of range",egamma);
+ x.gammat = gt_power;
+
+ /* Degree of output offset */
+ } else if (argv[fa][1] == 'f') {
+ fa = nfa;
+ if (na == NULL) {
+ x.oofff = 0.0;
+ } else {
+ x.oofff = atof(na);
+ if (x.oofff < 0.0 || x.oofff > 1.0)
+ usage("-f parameter %f out of range",x.oofff);
+ }
+
+ /* Ambient light level */
+ } else if (argv[fa][1] == 'a') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -a");
+ ambient = atof(na);
+ if (ambient < 0.0)
+ usage("-a parameter %f out of range",ambient);
+ ambient /= 3.141592654; /* Convert from Lux to cd/m^2 */
+
+ /* Test patch offset and size */
+ } else if (argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -P");
+ if (sscanf(na, " %lf,%lf,%lf,%lf ", &ho, &vo, &hpatscale, &vpatscale) == 4) {
+ ;
+ } else if (sscanf(na, " %lf,%lf,%lf ", &ho, &vo, &hpatscale) == 3) {
+ vpatscale = hpatscale;
+ } else {
+ usage("-P parameter '%s' not recognised",na);
+ }
+ if (ho < 0.0 || ho > 1.0
+ || vo < 0.0 || vo > 1.0
+ || hpatscale <= 0.0 || hpatscale > 50.0
+ || vpatscale <= 0.0 || vpatscale > 50.0)
+ usage("-P parameters %f %f %f %f out of range",ho,vo,hpatscale,vpatscale);
+ ho = 2.0 * ho - 1.0;
+ vo = 2.0 * vo - 1.0;
+
+ /* Black background */
+ } else if (argv[fa][1] == 'F') {
+ blackbg = 1;
+
+ /* Extra flags */
+ } else if (argv[fa][1] == 'Y') {
+ if (na == NULL)
+ usage("Flag '-Y' expects extra flag");
+
+ if (na[0] == 'A') {
+ nadaptive = 1;
+ } else {
+ usage("Flag '-Y %c' not recognised",na[0]);
+ }
+
+ } else
+ usage("Flag '-%c' not recognised",argv[fa][1]);
+ } else
+ break;
+ }
+
+ /* No explicit display has been set */
+ if (
+#ifndef SHOW_WINDOW_ONFAKE
+ !fake &&
+#endif
+ disp == NULL) {
+ int ix = 0;
+#if defined(UNIX_X11)
+ char *dn, *pp;
+
+ if ((dn = getenv("DISPLAY")) != NULL) {
+ if ((pp = strrchr(dn, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) != NULL) {
+ if (pp[1] != '\000')
+ ix = atoi(pp+1);
+ }
+ }
+ }
+#endif
+ if ((disp = get_a_display(ix)) == NULL)
+ error("Unable to open the default display");
+ }
+
+ /* See if there is an environment variable ccxx */
+ if (ccxxname[0] == '\000') {
+ char *na;
+ if ((na = getenv("ARGYLL_COLMTER_CAL_SPEC_SET")) != NULL) {
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+
+ } else if ((na = getenv("ARGYLL_COLMTER_COR_MATRIX")) != NULL) {
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+ }
+ }
+
+ /* Load up CCMX or CCSS */
+ if (ccxxname[0] != '\000') {
+ if ((cmx = new_ccmx()) == NULL
+ || cmx->read_ccmx(cmx, ccxxname)) {
+ if (cmx != NULL) {
+ cmx->del(cmx);
+ cmx = NULL;
+ }
+
+ /* CCMX failed, try CCSS */
+ if ((ccs = new_ccss()) == NULL
+ || ccs->read_ccss(ccs, ccxxname)) {
+ if (ccs != NULL) {
+ ccs->del(ccs);
+ ccs = NULL;
+ error("Reading CCMX/CCSS File '%s' failed\n", ccxxname);
+ }
+ }
+ }
+ }
+
+ if (fake)
+ comport = -99;
+ if ((icmps = new_icompaths(g_log)) == NULL)
+ error("Finding instrument paths failed");
+ if ((ipath = icmps->get_path(icmps, comport)) == NULL)
+ error("No instrument at port %d",comport);
+
+ if (docalib) {
+ if ((rv = disprd_calibration(ipath, fc, dtype, 0, tele, nadaptive, nocal, disp,
+ webdisp, blackbg, override,
+ 100.0 * hpatscale, 100.0 * vpatscale,
+ ho, vo, g_log)) != 0) {
+ error("docalibration failed with return value %d\n",rv);
+ }
+ }
+
+ if (verify != 2 && doreport == 0) {
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage("Output filname parameter not found");
+ strncpy(outname,argv[fa],MAXNAMEL-4); outname[MAXNAMEL-4] = '\000';
+ strcat(outname,".cal");
+ if (iccoutname[0] == '\000') {
+ strncpy(iccoutname,argv[fa++],MAXNAMEL-4); iccoutname[MAXNAMEL-4] = '\000';
+ strcat(iccoutname,ICC_FILE_EXT);
+ }
+ }
+
+ if (verify == 2) {
+ if (doupdate)
+ warning("Update flag ignored because we're doing a verify only");
+ doupdate = 0;
+ docontrols = 0;
+ }
+
+ if (doreport != 0) {
+ if (verify == 2)
+ warning("Verify flag ignored because we're doing a report only");
+ verify = 0;
+ }
+
+ /* Normally calibrate against native response */
+ if (verify == 2 || doreport == 2)
+ native = 0; /* But measure calibrated response of verify or report calibrated */
+
+ /* Get ready to do some readings */
+ if ((dr = new_disprd(&errc, ipath, fc, dtype, 0, tele, nadaptive, nocal,
+ highres, native, &noramdac, NULL, 0, 0, disp, blackbg, override,
+ webdisp, ccallout, mcallout,
+ 100.0 * hpatscale, 100.0 * vpatscale, ho, vo,
+ cmx != NULL ? cmx->matrix : NULL,
+ ccs != NULL ? ccs->samples : NULL, ccs != NULL ? ccs->no_samp : 0,
+ spec, obType, NULL, bdrift, wdrift,
+ "fake" ICC_FILE_EXT, g_log)) == NULL)
+ error("new_disprd() failed with '%s'\n",disprd_err(errc));
+
+ if (native != 0 && noramdac) {
+ warning("No access to VideoLUTs, so calibrating display as-is rather than native");
+ if (doprofile)
+ warning("Profile will reflect the as-is display response and not contain a 'vcgt' tag");
+ native = 0;
+
+ if (doupdate && doprofile)
+ error("Can't update a profile that doesn't use the 'vcgt' tag for calibration");
+ }
+
+ if (icmps != NULL) {
+ icmps->del(icmps);
+ icmps = NULL;
+ }
+ if (cmx != NULL) {
+ cmx->del(cmx);
+ cmx = NULL;
+ }
+ if (ccs != NULL) {
+ ccs->del(ccs);
+ ccs = NULL;
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ if (doreport) {
+ col tcols[3] = { /* Base set of test colors */
+ { 0.0, 0.0, 0.0 },
+ { 0.5, 0.5, 0.5 },
+ { 1.0, 1.0, 1.0 }
+ };
+ double cct, cct_de; /* Color temperatures and DE 2K */
+ double cdt, cdt_de;
+ double vct, vct_de;
+ double vdt, vdt_de;
+ double cgamma, w[3], wp[2];
+ int sigbits = 0; /* Number of significant bits in VideoLUT/display/instrument */
+
+ if ((rv = dr->read(dr, tcols, 3, 1, 3, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+
+//printf("~1 Got black = %f, half = %f, white = %f\n",tcols[0].XYZ[1],tcols[1].XYZ[1],tcols[2].XYZ[1]);
+ /* Normalised XYZ white point */
+ w[0] = tcols[2].XYZ[0]/tcols[2].XYZ[1];
+ w[1] = tcols[2].XYZ[1]/tcols[2].XYZ[1];
+ w[2] = tcols[2].XYZ[2]/tcols[2].XYZ[1];
+
+ /* White point chromaticity coordinates */
+ wp[0] = w[0]/(w[0] + w[1] + w[2]);
+ wp[1] = w[1]/(w[0] + w[1] + w[2]);
+
+ cct = comp_ct(&cct_de, NULL, 1, 0, obType, w); /* Compute CCT */
+ cdt = comp_ct(&cdt_de, NULL, 0, 0, obType, w); /* Compute CDT */
+ vct = comp_ct(&vct_de, NULL, 1, 1, obType, w); /* Compute VCT */
+ vdt = comp_ct(&vdt_de, NULL, 0, 1, obType, w); /* Compute VDT */
+
+ /* Compute advertised current gamma - use the gross curve shape for robustness */
+ cgamma = pop_gamma(tcols[0].XYZ[1], tcols[1].XYZ[1], tcols[2].XYZ[1]);
+
+#ifdef MEAS_RES
+ /* See if we can detect what sort of precision the LUT entries */
+ /* have. Our ability to detect this may be limited by the instrument */
+ /* (ie. Huey and Spyder 2) */
+ if (doreport == 1) {
+#define MAX_RES_SAMPS 24
+ col ttt[MAX_RES_SAMPS];
+ int res_samps = 6;
+ double a0, a1, a2, dd;
+ int n;
+ int issig = 0;
+
+ if (verb)
+ printf("Measuring VideoLUT table entry precision.\n");
+
+ /* Run a small state machine until we come to a conclusion */
+ sigbits = 8;
+ for (issig = 0; issig < 2; ) {
+
+ DBG((dbgo,"Trying %d bits\n",sigbits));
+ /* Do the test */
+ for (n = 0; n < res_samps; n++) {
+ double v;
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(sigbits);
+#endif
+ /* Notional test value */
+ v = (5 << (sigbits-3))/((1 << sigbits) - 1.0);
+ /* And -1, 0 , +1 bit test values */
+ if ((n % 3) == 2)
+ v += 1.0/((1 << sigbits) - 1.0);
+ else if ((n % 3) == 1)
+ v += 0.0/((1 << sigbits) - 1.0);
+ else
+ v += -1.0/((1 << sigbits) - 1.0);
+ ttt[n].r = ttt[n].g = ttt[n].b = v;
+ }
+ if ((rv = dr->read(dr, ttt, res_samps, 1, res_samps, 1, 0, instNoClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ /* Average the readings for each test value */
+ a0 = a1 = a2 = 0.0;
+ for (n = 0; n < res_samps; n++) {
+ double v = ttt[n].XYZ[1];
+ if ((n % 3) == 2) {
+ a2 += v;
+ } else if ((n % 3) == 1) {
+ a1 += v;
+ } else {
+ a0 += v;
+ }
+ }
+ a0 /= (res_samps / 3.0);
+ a1 /= (res_samps / 3.0);
+ a2 /= (res_samps / 3.0);
+ /* Judge significance of any differences */
+ dd = 0.0;
+ for (n = 0; n < res_samps; n++) {
+ double tt;
+ if ((n % 3) == 2)
+ tt = fabs(a2 - ttt[n].XYZ[1]);
+ else if ((n % 3) == 1)
+ tt = fabs(a1 - ttt[n].XYZ[1]);
+ else
+ tt = fabs(a0 - ttt[n].XYZ[1]);
+ dd += tt * tt;
+ }
+ dd /= res_samps;
+ dd = sqrt(dd);
+ if (fabs(a1 - a0) > (2.0 * dd) && fabs(a2 - a1) > (2.0 * dd))
+ issig = 1; /* Noticable difference */
+ else
+ issig = 0; /* No noticable difference */
+ DBG((dbgo,"Bits %d: Between = %f, %f within = %f, sig = %s\n",sigbits, fabs(a1 - a0), fabs(a2 - a1),dd, issig ? "yes" : "no"));
+
+ switch(sigbits) {
+ case 8: /* Do another trial */
+ if (issig) {
+ sigbits = 10;
+ res_samps = 6;
+ } else {
+ sigbits = 6;
+ }
+ break;
+ case 6: /* Do another trial or give up */
+ if (issig) {
+ sigbits = 7;
+ } else {
+ sigbits = 0;
+ issig = 2; /* Give up */
+ }
+ break;
+ case 7: /* Terminal */
+ if (!issig)
+ sigbits = 6;
+ issig = 2; /* Stop here */
+ break;
+ case 10: /* Do another trial */
+ if (issig) {
+ sigbits = 12;
+ res_samps = 9;
+ } else {
+ sigbits = 9;
+ }
+ break;
+ case 12: /* Do another trial or give up */
+ if (issig) {
+ issig = 2; /* Stop here */
+ } else {
+ sigbits = 11;
+ }
+ break;
+ case 11: /* Terminal */
+ if (!issig)
+ sigbits = 10;
+ issig = 2; /* Stop here */
+ break;
+ case 9: /* Terminal */
+ if (!issig)
+ sigbits = 8;
+ issig = 2; /* Stop here */
+ break;
+
+ default:
+ error("Unexpected number of bits in depth test (bits)",sigbits);
+ }
+ }
+ }
+#endif /* MEAS_RES */
+
+ if (doreport == 2)
+ printf("Current calibration response:\n");
+ else
+ printf("Uncalibrated response:\n");
+ printf("Black level = %.2f cd/m^2\n",tcols[0].XYZ[1]);
+ printf("White level = %.2f cd/m^2\n",tcols[2].XYZ[1]);
+ printf("Aprox. gamma = %.2f\n",cgamma);
+ printf("Contrast ratio = %.0f:1\n",tcols[2].XYZ[1]/tcols[0].XYZ[1]);
+ printf("White chromaticity coordinates %.4f, %.4f\n",wp[0],wp[1]);
+ printf("White Correlated Color Temperature = %.0fK, DE 2K to locus = %4.1f\n",cct,cct_de);
+ printf("White Correlated Daylight Temperature = %.0fK, DE 2K to locus = %4.1f\n",cdt,cdt_de);
+ printf("White Visual Color Temperature = %.0fK, DE 2K to locus = %4.1f\n",vct,vct_de);
+ printf("White Visual Daylight Temperature = %.0fK, DE 2K to locus = %4.1f\n",vdt,vdt_de);
+#ifdef MEAS_RES
+ if (doreport == 1) {
+ if (sigbits == 0) {
+ warning("Unable to determine LUT entry bit depth - problems ?");
+ } else {
+ printf("Effective LUT entry depth seems to be %d bits\n",sigbits);
+ }
+ }
+#endif /* MEAS_RES */
+ dr->del(dr);
+ exit(0);
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* If we're updating, retrieve the previously used settings, */
+ /* and device model */
+ if (doupdate) {
+ cgats *icg; /* output cgats structure */
+ int nsamp;
+ mcvco *rdv[3]; /* Scattered data for ramdac curves */
+ int fi; /* Field index */
+ int si[4]; /* Set fields */
+
+ if (verb) {
+ if (doprofile)
+ printf("Updating previous calibration and profile\n");
+ else
+ printf("Updating previous calibration\n");
+ }
+
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CAL"); /* our special type is Calibration file */
+
+ if (icg->read_name(icg, outname)) {
+ dr->del(dr);
+ error("Can't update '%s' - read error : %s",outname, icg->err);
+ }
+
+ if (icg->ntables == 0
+ || icg->t[0].tt != tt_other || icg->t[0].oi != 0
+ || icg->t[1].tt != tt_other || icg->t[1].oi != 0) {
+ dr->del(dr);
+ error("Can't update '%s' - wrong type of file",outname);
+ }
+ if (icg->ntables < 2) {
+ dr->del(dr);
+ error("Can't update '%s' - there aren't two tables",outname);
+ }
+
+//printf("~1 reading previous cal, got 2 tables\n");
+
+ /* Read in the setup, user and model values */
+
+ if (dtype == 0) { /* If the use hasn't set anything */
+ if ((fi = icg->find_kword(icg, 0, "DEVICE_TYPE")) >= 0) {
+ if (strcmp(icg->t[0].kdata[fi], "CRT") == 0)
+ dtype = 'c';
+ else if (strcmp(icg->t[0].kdata[fi], "LCD") == 0)
+ dtype = 'l';
+ else
+ dtype = icg->t[0].kdata[fi][0];
+ }
+ }
+//printf("~1 dealt with device type\n");
+
+ if ((fi = icg->find_kword(icg, 0, "TARGET_WHITE_XYZ")) < 0) {
+ dr->del(dr);
+ error ("Can't update '%s' - can't find field 'TARGET_WHITE_XYZ'",outname);
+ }
+ if (sscanf(icg->t[0].kdata[fi], "%lf %lf %lf", &x.twh[0], &x.twh[1], &x.twh[2]) != 3) {
+ dr->del(dr);
+ error ("Can't update '%s' - reading field 'TARGET_WHITE_XYZ' failed",outname);
+ }
+ x.nwh[0] = x.twh[0] / x.twh[1];
+ x.nwh[1] = x.twh[1] / x.twh[1];
+ x.nwh[2] = x.twh[2] / x.twh[1];
+
+ if ((fi = icg->find_kword(icg, 0, "NATIVE_TARGET_WHITE")) >= 0) {
+ wpx = wpy = 0.0;
+ temp = 0.0;
+ tbright = 0.0;
+ } else {
+ wpx = wpy = 0.0001;
+ temp = 1.0;
+ tbright = 1.0;
+ }
+//printf("~1 dealt with target white\n");
+
+ if ((fi = icg->find_kword(icg, 0, "TARGET_GAMMA")) < 0) {
+ dr->del(dr);
+ error ("Can't update '%s' - can't find field 'TARGET_GAMMA'",outname);
+ }
+ if (strcmp(icg->t[0].kdata[fi], "L_STAR") == 0)
+ x.gammat = gt_Lab;
+ else if (strcmp(icg->t[0].kdata[fi], "sRGB") == 0)
+ x.gammat = gt_sRGB;
+ else if (strcmp(icg->t[0].kdata[fi], "REC709") == 0)
+ x.gammat = gt_Rec709;
+ else if (strcmp(icg->t[0].kdata[fi], "SMPTE240M") == 0)
+ x.gammat = gt_SMPTE240M;
+ else {
+ x.gammat = 0;
+ gamma = atof(icg->t[0].kdata[fi]);
+
+ if (fabs(gamma) < 0.1 || fabs(gamma) > 5.0) {
+ dr->del(dr);
+ error ("Can't update '%s' - field 'TARGET_GAMMA' has bad value %f",outname,fabs(gamma));
+ }
+ if (gamma < 0.0) { /* Effective gamma = actual power value */
+ egamma = -gamma;
+ }
+ }
+ if ((fi = icg->find_kword(icg, 0, "DEGREE_OF_BLACK_OUTPUT_OFFSET")) < 0) {
+ /* Backward compatibility if value is not present */
+ if (x.gammat == gt_Lab || x.gammat == gt_sRGB)
+ x.oofff = 1.0;
+ else
+ x.oofff = 0.0;
+ } else {
+ x.oofff = atof(icg->t[0].kdata[fi]);
+ }
+ if ((fi = icg->find_kword(icg, 0, "TARGET_BLACK_BRIGHTNESS")) < 0) {
+ bkbright = 0.0; /* Native */
+ } else {
+ bkbright = atof(icg->t[0].kdata[fi]);
+ }
+
+
+ if ((fi = icg->find_kword(icg, 0, "BLACK_POINT_CORRECTION")) < 0) {
+ dr->del(dr);
+ error ("Can't update '%s' - can't find field 'BLACK_POINT_CORRECTION'",outname);
+ }
+ bkcorrect = atof(icg->t[0].kdata[fi]);
+ if (bkcorrect < 0.0 || bkcorrect > 1.0) {
+ dr->del(dr);
+ error ("Can't update '%s' - field 'BLACK_POINT_CORRECTION' has bad value %f",outname,bkcorrect);
+ }
+
+ if ((fi = icg->find_kword(icg, 0, "BLACK_NEUTRAL_BLEND_RATE")) < 0) {
+ x.nbrate = 8.0; /* Backwards compatibility value */
+ } else {
+ x.nbrate = atof(icg->t[0].kdata[fi]);
+ if (x.nbrate < 0.05 || x.nbrate > 20.0) {
+ dr->del(dr);
+ error ("Can't update '%s' - field 'BLACK_NEUTRAL_BLEND_RATE' has bad value %f",outname,x.nbrate);
+ }
+ }
+
+ if ((fi = icg->find_kword(icg, 0, "QUALITY")) < 0) {
+ dr->del(dr);
+ error ("Can't update '%s' - can't find field 'QUALITY'",outname);
+ }
+ if (quality < -50) { /* User hasn't overridden quality */
+ if (strcmp(icg->t[0].kdata[fi], "ultra low") == 0)
+ quality = -3;
+ else if (strcmp(icg->t[0].kdata[fi], "very low") == 0)
+ quality = -2;
+ else if (strcmp(icg->t[0].kdata[fi], "low") == 0)
+ quality = -1;
+ else if (strcmp(icg->t[0].kdata[fi], "medium") == 0)
+ quality = 0;
+ else if (strcmp(icg->t[0].kdata[fi], "high") == 0)
+ quality = 1;
+ else if (strcmp(icg->t[0].kdata[fi], "ultra high") == 0)
+ quality = 2;
+ else {
+ dr->del(dr);
+ error ("Can't update '%s' - field 'QUALITY' has unrecognised value '%s'",
+ outname,icg->t[0].kdata[fi]);
+ }
+ }
+//printf("~1 dealt with quality\n");
+
+ /* Read in the last set of calibration curves used */
+ if ((nsamp = icg->t[0].nsets) < 2) {
+ dr->del(dr);
+ error("Can't update '%s' - %d not enough data points in calibration curves",
+ outname,nsamp);
+ }
+//printf("~1 got %d points in calibration curves\n",nsamp);
+
+ for (k = 0; k < 3; k++) {
+ if ((x.rdac[k] = new_mcv()) == NULL) {
+ dr->del(dr);
+ error("new_mcv x.rdac[%d] failed",k);
+ }
+ if ((rdv[k] = malloc(sizeof(mcvco) * nsamp)) == NULL) {
+ dr->del(dr);
+ error ("Malloc of scattered data points failed");
+ }
+ }
+//printf("~1 allocated calibration curve objects\n");
+
+ /* Read the current calibration curve points (usually CAL_RES of them) */
+ for (k = 0; k < 4; k++) {
+ char *fnames[4] = { "RGB_I", "RGB_R", "RGB_G", "RGB_B" };
+
+ if ((si[k] = icg->find_field(icg, 0, fnames[k])) < 0) {
+ dr->del(dr);
+ error ("Can't updata '%s' - can't find field '%s'",outname,fnames[k]);
+ }
+ if (icg->t[0].ftype[si[k]] != r_t) {
+ dr->del(dr);
+ error ("Can't updata '%s' - field '%s' is wrong type",outname,fnames[k]);
+ }
+ }
+//printf("~1 Found calibration curve fields\n");
+
+ for (i = 0; i < nsamp; i++) {
+ rdv[0][i].p =
+ rdv[1][i].p =
+ rdv[2][i].p =
+ *((double *)icg->t[0].fdata[i][si[0]]);
+ for (k = 0; k < 3; k++) { /* RGB */
+ rdv[k][i].v = *((double *)icg->t[0].fdata[i][si[k + 1]]);
+ }
+ rdv[0][i].w = rdv[1][i].w = rdv[2][i].w = 1.0;
+ }
+//printf("~1 Read calibration curve data points\n");
+ for (k = 0; k < 3; k++) {
+ x.rdac[k]->fit(x.rdac[k], 0, fitord, rdv[k], nsamp, RDAC_SMOOTH);
+ free (rdv[k]);
+ }
+//printf("~1 Fitted calibration curves\n");
+
+ /* Read in the per channel forward model curves */
+ for (k = 0; k < 3; k++) {
+ char *fnames[3] = { "R_P", "G_P", "B_P" };
+ double *pp;
+
+//printf("~1 Reading device curve channel %d\n",k);
+ if ((si[k] = icg->find_field(icg, 1, fnames[k])) < 0) {
+ dr->del(dr);
+ error ("Can't updata '%s' - can't find field '%s'",outname,fnames[k]);
+ }
+ if (icg->t[1].ftype[si[k]] != r_t) {
+ dr->del(dr);
+ error ("Can't updata '%s' - field '%s' is wrong type",outname,fnames[k]);
+ }
+ /* Create the model curves */
+ if ((pp = (double *)malloc(icg->t[1].nsets * sizeof(double))) == NULL) {
+ dr->del(dr);
+ error ("Malloc of device curve parameters");
+ }
+ for (i = 0; i < icg->t[1].nsets; i++)
+ pp[i] = *((double *)icg->t[1].fdata[i][si[k]]);
+
+ if ((x.dcvs[k] = new_mcv_p(pp, icg->t[1].nsets)) == NULL) {
+ dr->del(dr);
+ error("new_mcv x.dcvs[%d] failed",k);
+ }
+ free(pp);
+ }
+
+ icg->del(icg);
+//printf("~1 read in previous settings and device model\n");
+ }
+
+ /* Be nice - check we can read the iccprofile before calibrating the display */
+ if (verify != 2 && doupdate && doprofile) {
+ icmFile *ic_fp;
+ icc *icco;
+
+ if ((icco = new_icc()) == NULL) {
+ dr->del(dr);
+ error ("Creation of ICC object to read profile '%s' failed",iccoutname);
+ }
+
+ /* Open up the profile for reading */
+ if ((ic_fp = new_icmFileStd_name(iccoutname,"r")) == NULL) {
+ dr->del(dr);
+ error ("Can't open file '%s'",iccoutname);
+ }
+
+ /* Read header etc. */
+ if ((rv = icco->read(icco,ic_fp,0)) != 0) {
+ dr->del(dr);
+ error ("Reading profile '%s' failed with %d, %s",iccoutname, rv,icco->err);
+ }
+
+ ic_fp->del(ic_fp);
+
+ if (icco->find_tag(icco, icSigVideoCardGammaTag) != 0) {
+ dr->del(dr);
+ error("Can't find VideoCardGamma tag in file '%s': %d, %s",
+ iccoutname, icco->errc,icco->err);
+ }
+ icco->del(icco);
+ }
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Convert quality level to iterations etc. */
+ /* Note that final tolerance is often double the */
+ /* final errth, because one more corrections is always */
+ /* performed after the last reading. */
+ switch (quality) {
+ case -3: /* Test value */
+ isteps = 3;
+ rsteps = 9;
+ mxits = 1;
+ errthr = 2.0;
+ break;
+ case -2: /* Very low */
+ isteps = 10;
+ rsteps = 16;
+ errthr = 1.5;
+ if (doupdate)
+ mxits = 1;
+ else
+ mxits = 1;
+ break;
+ case -1: /* Low */
+ if (verify != 2 && doprofile && !doupdate)
+ isteps = 24; /* Use more steps if we're creating a profile */
+ else
+ isteps = 12;
+ rsteps = 32;
+ errthr = 0.9;
+ if (doupdate)
+ mxits = 1;
+ else
+ mxits = 2;
+ break;
+ default:
+ case 0: /* Medum */
+ quality = 0; /* In case it wasn't set */
+ if (verify != 2 && doprofile && !doupdate)
+ isteps = 32; /* Use more steps if we're creating a profile */
+ else
+ isteps = 16;
+ rsteps = 64;
+ errthr = 0.6;
+ if (doupdate)
+ mxits = 1;
+ else
+ mxits = 3;
+ break;
+ case 1: /* High */
+ if (verify != 2 && doprofile && !doupdate)
+ isteps = 40; /* Use more steps if we're creating a profile */
+ else
+ isteps = 20;
+ rsteps = 96;
+ errthr = 0.4;
+ if (doupdate)
+ mxits = 1;
+ else
+ mxits = 4;
+ break;
+ case 2: /* Ultra */
+ if (verify != 2 && doprofile && !doupdate)
+ isteps = 48; /* Use more steps if we're creating a profile */
+ else
+ isteps = 24;
+ rsteps = 128;
+ errthr = 0.25;
+ if (doupdate)
+ mxits = 1;
+ else
+ mxits = 5;
+ break;
+ }
+
+ /* Set native white target flag in calx so that other things can play the game.. */
+ if (wpx == 0.0 && wpy == 0.0 && temp == 0.0 && tbright == 0.0)
+ x.nat = 1;
+ else
+ x.nat = 0;
+
+ /* Say something about what we're doing */
+ if (verb) {
+ if (dtype > 0)
+ printf("Display type is '%c'\n",dtype);
+
+ if (doupdate) {
+ if (x.nat)
+ printf("Target white = native white point & brightness\n");
+ else
+ printf("Target white = XYZ %f %f %f\n",
+ x.twh[0], x.twh[1], x.twh[2]);
+ } else {
+ if (wpx > 0.0 || wpy > 0.0)
+ printf("Target white = xy %f %f\n",wpx,wpy);
+ else if (temp > 0.0) {
+ if (planckian)
+ printf("Target white = %f degrees kelvin Planckian (black body) spectrum\n",temp);
+ else
+ printf("Target white = %f degrees kelvin Daylight spectrum\n",temp);
+ } else
+ printf("Target white = native white point\n");
+
+ if (tbright > 0.0)
+ printf("Target white brightness = %f cd/m^2\n",tbright);
+ else
+ printf("Target white brightness = native brightness\n");
+ if (bkbright > 0.0)
+ printf("Target black brightness = %f cd/m^2\n",bkbright);
+ else
+ printf("Target black brightness = native brightness\n");
+ }
+
+ switch(x.gammat) {
+ case gt_power:
+ if (egamma > 0.0)
+ printf("Target effective gamma = %f\n",egamma);
+ else
+ printf("Target advertised gamma = %f\n",gamma);
+ break;
+ case gt_Lab:
+ printf("Target gamma = L* curve\n");
+ break;
+ case gt_sRGB:
+ printf("Target gamma = sRGB curve\n");
+ break;
+ case gt_Rec709:
+ printf("Target gamma = REC 709 curve\n");
+ break;
+ case gt_SMPTE240M:
+ printf("Target gamma = SMPTE 240M curve\n");
+ break;
+ default:
+ error("Unknown gamma type");
+ }
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Go through the procedure of adjusting monitor controls */
+ if (docontrols) {
+ int rgbch = 0; /* Got RBG Yxy ? */
+ double rgbXYZ[3][3]; /* The RGB XYZ */
+
+ /* Make sure drift comp. is off for interactive adjustment */
+ dr->change_drift_comp(dr, 0, 0);
+
+ /* Until the user is done */
+ printf("\nDisplay adjustment menu:");
+ for (;;) {
+ int c;
+
+ /* Print the menue of adjustments */
+ printf("\nPress 1 .. 7\n");
+ printf("1) Black level (CRT: Offset/Brightness)\n");
+ printf("2) White point (Color temperature, R,G,B, Gain/Contrast)\n");
+ printf("3) White level (CRT: Gain/Contrast, LCD: Brightness/Backlight)\n");
+ printf("4) Black point (R,G,B, Offset/Brightness)\n");
+ printf("5) Check all\n");
+ printf("6) Measure and set ambient for viewing condition adjustment\n");
+ printf("7) Continue on to calibration\n");
+ printf("8) Exit\n");
+
+ empty_con_chars();
+ c = next_con_char();
+
+ /* Black level adjustment */
+ /* Due to the possibility of the channel offsets not being even, */
+ /* we use the largest of the XYZ values after they have been */
+ /* scaled to be even acording to the white XYZ balance. */
+ /* It's safer to set the black level a bit low, and then the */
+ /* calibration curves can bump the low ones up. */
+ if (c == '1') {
+ col tcols[3] = { /* Base set of test colors */
+ { 0.0, 0.0, 0.0 },
+ { 0.5, 0.5, 0.5 }, /* And 1% values */
+ { 1.0, 1.0, 1.0 }
+ };
+ int ff;
+ double mgamma, tar1, dev1;
+
+ printf("Doing some initial measurements\n");
+ /* Do an initial set of readings to set 1% output mark */
+ if ((rv = dr->read(dr, tcols, 3, 0, 0, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+
+ if (verb) {
+ printf("Black = XYZ %6.2f %6.2f %6.2f\n",tcols[0].XYZ[0],
+ tcols[0].XYZ[1], tcols[0].XYZ[2]);
+ printf("Grey = XYZ %6.2f %6.2f %6.2f\n",tcols[1].XYZ[0],
+ tcols[1].XYZ[1], tcols[1].XYZ[2]);
+ printf("White = XYZ %6.2f %6.2f %6.2f\n",tcols[2].XYZ[0],
+ tcols[2].XYZ[1], tcols[2].XYZ[2]);
+ }
+
+ /* Advertised Gamma - Gross curve shape */
+ mgamma = pop_gamma(tcols[0].XYZ[1], tcols[1].XYZ[1], tcols[2].XYZ[1]);
+
+ dev1 = pow(0.01, 1.0/mgamma);
+//printf("~1 device level for 1%% output = %f\n",dev1);
+ tcols[1].r = tcols[1].g = tcols[1].b = dev1;
+ tar1 = 0.01 * tcols[2].XYZ[1];
+
+ printf("\nAdjust CRT brightness to get target level. Press space when done.\n");
+ printf(" Target %.2f\n",tar1);
+ for (ff = 0;; ff ^= 1) {
+ double dir; /* Direction to adjust brightness */
+ double sv[3], val1; /* Scaled values */
+ if ((rv = dr->read(dr, tcols+1, 1, 0, 0, 1, ' ',instClamp)) != 0) {
+ if (rv == 4)
+ break; /* User is done with this adjustment */
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ /* Scale 1% values by ratio of Y to white XYZ */
+ sv[0] = tcols[1].XYZ[0] * tcols[2].XYZ[1]/tcols[2].XYZ[0];
+ sv[1] = tcols[1].XYZ[1];
+ sv[2] = tcols[1].XYZ[2] * tcols[2].XYZ[1]/tcols[2].XYZ[2];
+//printf("~1 scaled readings = %f %f %f\n",sv[0],sv[1],sv[2]);
+ val1 = sv[1];
+ if (sv[0] > val1)
+ val1 = sv[0];
+ if (sv[2] > val1)
+ val1 = sv[2];
+ dir = tar1 - val1;
+ if (fabs(dir) < 0.01)
+ dir = 0.0;
+ printf("%c%c Current %.2f %c",
+ cr_char,
+ ff == 0 ? '/' : '\\',
+ val1,
+ dir < 0.0 ? '-' : dir > 0.0 ? '+' : '=');
+ fflush(stdout);
+ }
+ printf("\n");
+
+ /* White point adjustment */
+ } else if (c == '2') {
+ int nat = 0; /* NZ if using native white as target */
+ col tcols[1] = { /* Base set of test colors */
+ { 1.0, 1.0, 1.0 }
+ };
+ int ff;
+ double tYxy[3]; /* Target white chromaticities */
+ icmXYZNumber tXYZ; /* Target white as XYZ */
+ double tLab[3]; /* Target white as Lab or UCS */
+ double tarw; /* Target brightness */
+ double Lab[3]; /* Last measured point Lab or UCS */
+ double ct = 0.0, ct_de; /* Color temperature & delta E to white locus */
+
+ printf("Doing some initial measurements\n");
+
+ if (rgbch == 0) { /* Figure the RGB chromaticities */
+ col ccols[3] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+ if ((rv = dr->read(dr, ccols, 3, 0, 0, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ if (verb) {
+ printf("Red = XYZ %6.2f %6.2f %6.2f\n",ccols[0].XYZ[0],
+ ccols[0].XYZ[1], ccols[0].XYZ[2]);
+ printf("Green = XYZ %6.2f %6.2f %6.2f\n",ccols[1].XYZ[0],
+ ccols[1].XYZ[1], ccols[1].XYZ[2]);
+ printf("Blue = XYZ %6.2f %6.2f %6.2f\n",ccols[2].XYZ[0],
+ ccols[2].XYZ[1], ccols[2].XYZ[2]);
+ }
+ for (i = 0; i < 3; i++)
+ icmAry2Ary(rgbXYZ[i], ccols[i].XYZ);
+ rgbch = 1;
+ }
+ /* Do an initial set of readings to set full output mark */
+ if ((rv = dr->read(dr, tcols, 1, 0, 0, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ if (verb) {
+ printf("White = XYZ %6.2f %6.2f %6.2f\n",tcols[0].XYZ[0],
+ tcols[0].XYZ[1], tcols[0].XYZ[2]);
+ }
+
+ /* Figure out the target white chromaticity */
+ if (wpx > 0.0 || wpy > 0.0) { /* xy coordinates */
+ tYxy[0] = 1.0;
+ tYxy[1] = wpx;
+ tYxy[2] = wpy;
+ } else if (temp > 0.0) { /* Daylight color temperature */
+ double XYZ[3];
+ if (planckian)
+ rv = icx_ill_sp2XYZ(XYZ, icxOT_default, NULL, icxIT_Ptemp, temp, NULL);
+ else
+ rv = icx_ill_sp2XYZ(XYZ, icxOT_default, NULL, icxIT_Dtemp, temp, NULL);
+ if (rv != 0)
+ error("Failed to compute XYZ of target color temperature %f\n",temp);
+ icmXYZ2Yxy(tYxy, XYZ);
+ } else { /* Native white */
+ icmXYZ2Yxy(tYxy, tcols[0].XYZ);
+ nat = 1;
+ }
+
+ /* Figure out the target white brightness */
+ /* Note we're not taking the device gamut into account here */
+ if (tbright > 0.0) { /* Given brightness */
+ tarw = tbright;
+//printf("~1 set tarw %f from tbright\n",tarw);
+ } else { /* Native/maximum brightness */
+ tarw = tcols[0].XYZ[1];
+//printf("~1 set tarw %f from tcols[1]\n",tarw);
+ }
+
+ if (!nat) { /* Target is a specified white */
+ printf("\nAdjust R,G & B gain to get target x,y. Press space when done.\n");
+ printf(" Target Br %.2f, x %.4f , y %.4f \n",
+ tarw, tYxy[1],tYxy[2]);
+
+ } else { /* Target is native white */
+ printf("\nAdjust R,G & B gain to desired white point. Press space when done.\n");
+ /* Compute the CT and delta E to white locus of target */
+ ct = comp_ct(&ct_de, NULL, planckian, dovct, obType, tcols[0].XYZ);
+ printf(" Initial Br %.2f, x %.4f , y %.4f , %c%cT %4.0fK DE 2K %4.1f\n",
+ tarw, tYxy[1],tYxy[2],
+ dovct ? 'V' : 'C', planckian ? 'C' : 'D', ct,ct_de);
+ }
+ for (ff = 0;; ff ^= 1) {
+ double dir; /* Direction to adjust brightness */
+ double Yxy[3]; /* Yxy of current reading */
+ double rgbdir[3]; /* Direction to adjust RGB */
+ double rgbxdir[3]; /* Biggest to move */
+ double bdir, terr;
+ int bx = 0;
+
+ if ((rv = dr->read(dr, tcols, 1, 0, 0, 1, ' ', instClamp)) != 0) {
+ if (rv == 4)
+ break; /* User is done with this adjustment */
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ dir = tarw - tcols[0].XYZ[1];
+ if (fabs(dir) < 0.01)
+ dir = 0.0;
+
+ icmXYZ2Yxy(Yxy, tcols[0].XYZ);
+
+ if (!nat) { /* Target is a specified white */
+ /* Compute values we need for delta E and RGB direction */
+ icmYxy2XYZ(tLab, tYxy);
+ tLab[0] /= tLab[1];
+ tLab[2] /= tLab[1];
+ tLab[1] /= tLab[1];
+ icmAry2XYZ(tXYZ, tLab); /* Lab white reference */
+ icmXYZ2Lab(&tXYZ, tLab, tLab); /* Target Lab */
+
+ icmAry2Ary(Lab, tcols[0].XYZ);
+ Lab[0] /= Lab[1];
+ Lab[2] /= Lab[1];
+ Lab[1] /= Lab[1];
+ icmXYZ2Lab(&tXYZ, Lab, Lab); /* Current Lab */
+
+ } else { /* Target is native white */
+ double lxyz[3]; /* Locus XYZ */
+ ct = comp_ct(&ct_de, lxyz, planckian, dovct, obType, tcols[0].XYZ);
+
+ icmXYZ2Yxy(tYxy, lxyz);
+ /* lxyz is already normalised */
+ icmAry2XYZ(tXYZ, lxyz); /* Lab white reference */
+ if (dovct)
+ icmXYZ2Lab(&tXYZ, tLab, lxyz); /* Target Lab */
+ else
+ icmXYZ21960UCS(tLab, lxyz); /* Target UCS */
+
+ icmAry2Ary(Lab, tcols[0].XYZ);
+ Lab[0] /= Lab[1];
+ Lab[2] /= Lab[1];
+ Lab[1] /= Lab[1];
+ if (dovct)
+ icmXYZ2Lab(&tXYZ, Lab, Lab); /* Current Lab */
+ else
+ icmXYZ21960UCS(Lab, Lab); /* Current UCS */
+ }
+
+ /* Compute dot products */
+ bdir = 0.0;
+ for (i = 0; i < 3; i++) {
+ double rgbLab[3];
+
+ if (dovct)
+ icmXYZ2Lab(&tXYZ, rgbLab, rgbXYZ[i]);
+ else
+ icmXYZ21960UCS(rgbLab, rgbXYZ[i]);
+ rgbdir[i] = (tLab[1] - Lab[1]) * (rgbLab[1] - Lab[1])
+ + (tLab[2] - Lab[2]) * (rgbLab[2] - Lab[2]);
+ rgbxdir[i] = 0.0;
+ if (fabs(rgbdir[i]) > fabs(bdir)) {
+ bdir = rgbdir[i];
+ bx = i;
+ }
+ }
+
+ /* See how close to the target we are */
+ terr = sqrt((tLab[1] - Lab[1]) * (tLab[1] - Lab[1])
+ + (tLab[2] - Lab[2]) * (tLab[2] - Lab[2]));
+ if (terr < 0.1)
+ rgbdir[0] = rgbdir[1] = rgbdir[2] = 0.0;
+ rgbxdir[bx] = rgbdir[bx];
+
+
+ if (!nat) {
+ printf("%c%c Current Br %.2f, x %.4f%c, y %.4f%c DE %4.1f R%c%c G%c%c B%c%c ",
+ cr_char,
+ ff == 0 ? '/' : '\\',
+ tcols[0].XYZ[1],
+ Yxy[1],
+ Yxy[1] > tYxy[1] ? '-' : Yxy[1] < tYxy[1] ? '+' : '=',
+ Yxy[2],
+ Yxy[2] > tYxy[2] ? '-' : Yxy[2] < tYxy[2] ? '+' : '=',
+ icmCIE2K(tLab, Lab),
+ rgbdir[0] < 0.0 ? '-' : rgbdir[0] > 0.0 ? '+' : '=',
+ rgbxdir[0] < 0.0 ? '-' : rgbxdir[0] > 0.0 ? '+' : ' ',
+ rgbdir[1] < 0.0 ? '-' : rgbdir[1] > 0.0 ? '+' : '=',
+ rgbxdir[1] < 0.0 ? '-' : rgbxdir[1] > 0.0 ? '+' : ' ',
+ rgbdir[2] < 0.0 ? '-' : rgbdir[2] > 0.0 ? '+' : '=',
+ rgbxdir[2] < 0.0 ? '-' : rgbxdir[2] > 0.0 ? '+' : ' ');
+ } else {
+ printf("%c%c Current Br %.2f, x %.4f%c, y %.4f%c %c%cT %4.0fK DE 2K %4.1f R%c%c G%c%c B%c%c ",
+ cr_char,
+ ff == 0 ? '/' : '\\',
+ tcols[0].XYZ[1],
+ Yxy[1],
+ Yxy[1] > tYxy[1] ? '-': Yxy[1] < tYxy[1] ? '+' : '=',
+ Yxy[2],
+ Yxy[2] > tYxy[2] ? '-': Yxy[2] < tYxy[2] ? '+' : '=',
+ dovct ? 'V' : 'C', planckian ? 'C' : 'D', ct,ct_de,
+ rgbdir[0] < 0.0 ? '-' : rgbdir[0] > 0.0 ? '+' : '=',
+ rgbxdir[0] < 0.0 ? '-' : rgbxdir[0] > 0.0 ? '+' : ' ',
+ rgbdir[1] < 0.0 ? '-' : rgbdir[1] > 0.0 ? '+' : '=',
+ rgbxdir[1] < 0.0 ? '-' : rgbxdir[1] > 0.0 ? '+' : ' ',
+ rgbdir[2] < 0.0 ? '-' : rgbdir[2] > 0.0 ? '+' : '=',
+ rgbxdir[2] < 0.0 ? '-' : rgbxdir[2] > 0.0 ? '+' : ' ');
+ }
+ fflush(stdout);
+ }
+ printf("\n");
+
+ /* White level adjustment */
+ } else if (c == '3') {
+ col tcols[1] = { /* Base set of test colors */
+ { 1.0, 1.0, 1.0 }
+ };
+ int ff;
+ double tarw;
+
+ printf("Doing some initial measurements\n");
+ /* Do an initial set of readings to set full output mark */
+ if ((rv = dr->read(dr, tcols, 1, 0, 0, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ if (verb) {
+ printf("White = XYZ %6.2f %6.2f %6.2f\n",tcols[0].XYZ[0],
+ tcols[0].XYZ[1], tcols[0].XYZ[2]);
+ }
+
+ /* Figure out the target white brightness */
+ /* Note we're not taking the device gamut into account here */
+ if (tbright > 0.0) /* Given brightness */
+ tarw = tbright;
+ else /* Native/maximum brightness */
+ tarw = tcols[0].XYZ[1];
+
+ if (tbright > 0.0) {
+ printf("\nAdjust CRT Contrast or LCD Brightness to get target level. Press space when done.\n");
+ printf(" Target %.2f\n", tarw);
+ } else {
+ printf("\nAdjust CRT Contrast or LCD Brightness to desired level. Press space when done.\n");
+ printf(" Initial %.2f\n", tarw);
+ }
+ for (ff = 0;; ff ^= 1) {
+ double dir; /* Direction to adjust brightness */
+
+ if ((rv = dr->read(dr, tcols, 1, 0, 0, 1, ' ', instClamp)) != 0) {
+ if (rv == 4)
+ break; /* User is done with this adjustment */
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ dir = tarw - tcols[0].XYZ[1];
+ if (fabs(dir) < 0.01)
+ dir = 0.0;
+
+ if (tbright > 0.0)
+ printf("%c%c Current %.2f %c",
+ cr_char,
+ ff == 0 ? '/' : '\\',
+ tcols[0].XYZ[1],
+ dir < 0.0 ? '-' : dir > 0.0 ? '+' : '=');
+ else
+ printf("%c%c Current %.2f ",
+ cr_char,
+ ff == 0 ? '/' : '\\',
+ tcols[0].XYZ[1]);
+ fflush(stdout);
+ }
+ printf("\n");
+
+ /* Black point adjustment */
+ } else if (c == '4') {
+ col tcols[3] = { /* Base set of test colors */
+ { 0.0, 0.0, 0.0 },
+ { 0.5, 0.5, 0.5 }, /* And 1% values */
+ { 1.0, 1.0, 1.0 }
+ };
+ int ff;
+ double tYxy[3]; /* Target white chromaticities */
+ icmXYZNumber tXYZ; /* Target white as XYZ */
+ double tLab[3]; /* Target white as Lab or UCS */
+ double mgamma, tar1, dev1;
+ double Lab[3]; /* Last measured point Lab */
+
+ printf("Doing some initial measurements\n");
+
+ if (rgbch == 0) { /* Figure the RGB chromaticities */
+ col ccols[3] = {
+ { 1.0, 0.0, 0.0 },
+ { 0.0, 1.0, 0.0 },
+ { 0.0, 0.0, 1.0 }
+ };
+ if ((rv = dr->read(dr, ccols, 3, 0, 0, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ if (verb) {
+ printf("Red = XYZ %6.2f %6.2f %6.2f\n",ccols[0].XYZ[0],
+ ccols[0].XYZ[1], ccols[0].XYZ[2]);
+ printf("Green = XYZ %6.2f %6.2f %6.2f\n",ccols[1].XYZ[0],
+ ccols[1].XYZ[1], ccols[1].XYZ[2]);
+ printf("Blue = XYZ %6.2f %6.2f %6.2f\n",ccols[2].XYZ[0],
+ ccols[2].XYZ[1], ccols[2].XYZ[2]);
+ }
+ for (i = 0; i < 3; i++)
+ icmAry2Ary(rgbXYZ[i], ccols[i].XYZ);
+ rgbch = 1;
+ }
+ /* Do an initial set of readings to set 1% output mark */
+ if ((rv = dr->read(dr, tcols, 3, 0, 0, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ if (verb) {
+ printf("Black = XYZ %6.2f %6.2f %6.2f\n",tcols[0].XYZ[0],
+ tcols[0].XYZ[1], tcols[0].XYZ[2]);
+ printf("Grey = XYZ %6.2f %6.2f %6.2f\n",tcols[1].XYZ[0],
+ tcols[1].XYZ[1], tcols[1].XYZ[2]);
+ printf("White = XYZ %6.2f %6.2f %6.2f\n",tcols[2].XYZ[0],
+ tcols[2].XYZ[1], tcols[2].XYZ[2]);
+ }
+
+ /* Advertised Gamma - Gross curve shape */
+ mgamma = pop_gamma(tcols[0].XYZ[1], tcols[1].XYZ[1], tcols[2].XYZ[1]);
+
+ dev1 = pow(0.01, 1.0/mgamma);
+ tcols[1].r = tcols[1].g = tcols[1].b = dev1;
+ tar1 = 0.01 * tcols[2].XYZ[1];
+
+ /* Figure out the target white chromaticity */
+ if (wpx > 0.0 || wpy > 0.0) { /* xy coordinates */
+ tYxy[0] = 1.0;
+ tYxy[1] = wpx;
+ tYxy[2] = wpy;
+
+ } else if (temp > 0.0) { /* Daylight color temperature */
+ double XYZ[3];
+ if (planckian)
+ rv = icx_ill_sp2XYZ(XYZ, icxOT_default, NULL, icxIT_Ptemp, temp, NULL);
+ else
+ rv = icx_ill_sp2XYZ(XYZ, icxOT_default, NULL, icxIT_Dtemp, temp, NULL);
+ if (rv != 0)
+ error("Failed to compute XYZ of target color temperature %f\n",temp);
+ icmXYZ2Yxy(tYxy, XYZ);
+ } else { /* Native white */
+ icmXYZ2Yxy(tYxy, tcols[2].XYZ);
+ }
+
+ printf("\nAdjust R,G & B offsets to get target x,y. Press space when done.\n");
+ printf(" Target Br %.2f, x %.4f , y %.4f \n", tar1, tYxy[1],tYxy[2]);
+ for (ff = 0;; ff ^= 1) {
+ double dir; /* Direction to adjust brightness */
+ double sv[3], val1; /* Scaled values */
+ double Yxy[3]; /* Yxy of current reading */
+ double rgbdir[3]; /* Direction to adjust RGB */
+ double rgbxdir[3]; /* Biggest to move */
+ double bdir, terr;
+ int bx = 0;
+
+ if ((rv = dr->read(dr, tcols+1, 1, 0, 0, 1, ' ', instClamp)) != 0) {
+ if (rv == 4)
+ break; /* User is done with this adjustment */
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+
+ /* Scale 1% values by ratio of Y to white XYZ */
+ sv[0] = tcols[1].XYZ[0] * tcols[2].XYZ[1]/tcols[2].XYZ[0];
+ sv[1] = tcols[1].XYZ[1];
+ sv[2] = tcols[1].XYZ[2] * tcols[2].XYZ[1]/tcols[2].XYZ[2];
+ val1 = sv[1];
+ if (sv[0] > val1)
+ val1 = sv[0];
+ if (sv[2] > val1)
+ val1 = sv[2];
+
+ /* Compute 1% direction */
+ dir = tar1 - val1;
+ if (fabs(dir) < 0.01)
+ dir = 0.0;
+
+ /* Compute numbers for black point error and direction */
+ icmYxy2XYZ(tLab, tYxy);
+ tLab[0] /= tLab[1];
+ tLab[2] /= tLab[1];
+ tLab[1] /= tLab[1];
+ icmAry2XYZ(tXYZ, tLab); /* Lab white reference */
+ icmXYZ2Lab(&tXYZ, tLab, tLab);
+
+ icmXYZ2Yxy(Yxy, tcols[1].XYZ);
+ icmAry2Ary(Lab, tcols[1].XYZ);
+ Lab[0] /= Lab[1];
+ Lab[2] /= Lab[1];
+ Lab[1] /= Lab[1];
+ icmXYZ2Lab(&tXYZ, Lab, Lab);
+
+ /* Compute dot products */
+ bdir = 0.0;
+ for (i = 0; i < 3; i++) {
+ double rgbLab[3];
+
+ icmXYZ2Lab(&tXYZ, rgbLab, rgbXYZ[i]);
+ rgbdir[i] = (tLab[1] - Lab[1]) * (rgbLab[1] - Lab[1])
+ + (tLab[2] - Lab[2]) * (rgbLab[2] - Lab[2]);
+ rgbxdir[i] = 0.0;
+ if (fabs(rgbdir[i]) > fabs(bdir)) {
+ bdir = rgbdir[i];
+ bx = i;
+ }
+ }
+
+ /* See how close to the target we are */
+ terr = sqrt((tLab[1] - Lab[1]) * (tLab[1] - Lab[1])
+ + (tLab[2] - Lab[2]) * (tLab[2] - Lab[2]));
+ if (terr < 0.1)
+ rgbdir[0] = rgbdir[1] = rgbdir[2] = 0.0;
+ rgbxdir[bx] = rgbdir[bx];
+
+ printf("%c%c Current Br %.2f, x %.4f%c, y %.4f%c DE %4.1f R%c%c G%c%c B%c%c ",
+ cr_char,
+ ff == 0 ? '/' : '\\',
+ val1,
+ Yxy[1],
+ Yxy[1] > tYxy[1] ? '-': Yxy[1] < tYxy[1] ? '+' : '=',
+ Yxy[2],
+ Yxy[2] > tYxy[2] ? '-': Yxy[2] < tYxy[2] ? '+' : '=',
+ icmCIE2K(tLab, Lab),
+ rgbdir[0] < 0.0 ? '-' : rgbdir[0] > 0.0 ? '+' : '=',
+ rgbxdir[0] < 0.0 ? '-' : rgbxdir[0] > 0.0 ? '+' : ' ',
+ rgbdir[1] < 0.0 ? '-' : rgbdir[1] > 0.0 ? '+' : '=',
+ rgbxdir[1] < 0.0 ? '-' : rgbxdir[1] > 0.0 ? '+' : ' ',
+ rgbdir[2] < 0.0 ? '-' : rgbdir[2] > 0.0 ? '+' : '=',
+ rgbxdir[2] < 0.0 ? '-' : rgbxdir[2] > 0.0 ? '+' : ' ');
+ fflush(stdout);
+ }
+ printf("\n");
+
+ /* Report on how well we current meet the targets */
+ } else if (c == '5') {
+ int nat = 0; /* NZ if using native white as target */
+ col tcols[4] = { /* Set of test colors */
+ { 0.0, 0.0, 0.0 },
+ { 0.5, 0.5, 0.5 },
+ { 1.0, 1.0, 1.0 },
+ { 0.0, 0.0, 0.0 } /* 1% test value */
+ };
+ double tYxy[3]; /* Target white chromaticities */
+ double sv[3], val1; /* Scaled values */
+ double mgamma, tarw, tar1, dev1, tarh;
+ double gooff; /* Aproximate output offset needed */
+ icmXYZNumber tXYZ;
+ double tLab[3], wYxy[3], wLab[3], bYxy[3], bLab[3];
+ double ct, ct_de; /* Color temperature & delta E to white locus */
+
+ printf("Doing check measurements\n");
+
+ /* Do an initial set of readings to set 1% output mark */
+ if ((rv = dr->read(dr, tcols, 3, 0, 0, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ if (verb) {
+ printf("Black = XYZ %6.2f %6.2f %6.2f\n",tcols[0].XYZ[0],
+ tcols[0].XYZ[1], tcols[0].XYZ[2]);
+ printf("Grey = XYZ %6.2f %6.2f %6.2f\n",tcols[1].XYZ[0],
+ tcols[1].XYZ[1], tcols[1].XYZ[2]);
+ printf("White = XYZ %6.2f %6.2f %6.2f\n",tcols[2].XYZ[0],
+ tcols[2].XYZ[1], tcols[2].XYZ[2]);
+ }
+
+ /* Approximate Gamma - use the gross curve shape for robustness */
+ mgamma = pop_gamma(tcols[0].XYZ[1], tcols[1].XYZ[1], tcols[2].XYZ[1]);
+
+ dev1 = pow(0.01, 1.0/mgamma);
+ tcols[3].r = tcols[3].g = tcols[3].b = dev1;
+ tar1 = 0.01 * tcols[2].XYZ[1];
+
+ /* Read the 1% value */
+ if ((rv = dr->read(dr, tcols+3, 1, 0, 0, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ if (verb) {
+ printf("1%% = XYZ %6.2f %6.2f %6.2f\n",tcols[3].XYZ[0],
+ tcols[3].XYZ[1], tcols[3].XYZ[2]);
+ }
+
+ /* Scale 1% values by ratio of Y to white XYZ */
+ /* (Note we're assuming -k1 here, which may not be true...) */
+ sv[0] = tcols[3].XYZ[0] * tcols[2].XYZ[1]/tcols[2].XYZ[0];
+ sv[1] = tcols[3].XYZ[1];
+ sv[2] = tcols[3].XYZ[2] * tcols[2].XYZ[1]/tcols[2].XYZ[2];
+ val1 = sv[1];
+ if (sv[0] > val1)
+ val1 = sv[0];
+ if (sv[2] > val1)
+ val1 = sv[2];
+
+ /* Figure out the target white brightness */
+ /* Note we're not taking the device gamut into account here */
+ if (tbright > 0.0) /* Given brightness */
+ tarw = tbright;
+ else /* Native/maximum brightness */
+ tarw = tcols[2].XYZ[1];
+
+ /* Figure out the target white chromaticity */
+ if (wpx > 0.0 || wpy > 0.0) { /* xy coordinates */
+ tYxy[0] = 1.0;
+ tYxy[1] = wpx;
+ tYxy[2] = wpy;
+
+ } else if (temp > 0.0) { /* Daylight color temperature */
+ double XYZ[3];
+ if (planckian)
+ rv = icx_ill_sp2XYZ(XYZ, icxOT_default, NULL, icxIT_Ptemp, temp, NULL);
+ else
+ rv = icx_ill_sp2XYZ(XYZ, icxOT_default, NULL, icxIT_Dtemp, temp, NULL);
+ if (rv != 0)
+ error("Failed to compute XYZ of target color temperature %f\n",temp);
+ icmXYZ2Yxy(tYxy, XYZ);
+ } else { /* Native white */
+ icmXYZ2Yxy(tYxy, tcols[2].XYZ);
+ nat = 1;
+ }
+
+ /* Figure out the target 50% device output value */
+ gooff = tcols[0].XYZ[1]/tcols[2].XYZ[1]; /* Aprox. normed black output offset */
+
+ /* Use tech_gamma() to do the hard work */
+ tarh = tech_gamma(&x, NULL, NULL, NULL, egamma, gamma, gooff);
+
+ /* Convert from Y fraction to absolute Y */
+ tarh = tarh * tcols[2].XYZ[1];
+
+ /* Compute various white point values */
+ icmYxy2XYZ(tLab, tYxy);
+ tLab[0] /= tLab[1];
+ tLab[2] /= tLab[1];
+ tLab[1] /= tLab[1];
+ icmAry2XYZ(tXYZ, tLab);
+ icmXYZ2Lab(&tXYZ, tLab, tLab);
+
+ icmXYZ2Yxy(wYxy, tcols[2].XYZ);
+ icmAry2Ary(wLab, tcols[2].XYZ);
+ wLab[0] /= wLab[1];
+ wLab[2] /= wLab[1];
+ wLab[1] /= wLab[1];
+ icmXYZ2Lab(&tXYZ, wLab, wLab);
+
+ icmXYZ2Yxy(bYxy, tcols[3].XYZ);
+ icmAry2Ary(bLab, tcols[3].XYZ);
+ bLab[0] /= bLab[1];
+ bLab[2] /= bLab[1];
+ bLab[1] /= bLab[1];
+ icmXYZ2Lab(&tXYZ, bLab, bLab);
+
+ /* And color temperature */
+ ct = comp_ct(&ct_de, NULL, planckian, dovct, obType, tcols[2].XYZ);
+
+ printf("\n");
+
+ if (tbright > 0.0) /* Given brightness */
+ printf(" Target Brightness = %.2f, Current = %5.2f, error = % .1f%%\n",
+ tarw, tcols[2].XYZ[1],
+ 100.0 * (tcols[2].XYZ[1] - tarw)/tarw);
+ else
+ printf(" Current Brightness = %.2f\n", tcols[2].XYZ[1]);
+
+ printf(" Target 50%% Level = %.2f, Current = %5.2f, error = % .1f%%\n",
+ tarh, tcols[1].XYZ[1],
+ 100.0 * (tcols[1].XYZ[1] - tarh)/tarw);
+
+ printf(" Target Near Black = %5.2f, Current = %5.2f, error = % .1f%%\n",
+ tar1, val1,
+ 100.0 * (val1 - tar1)/tarw);
+
+ if (!nat)
+ printf(" Target white = x %.4f, y %.4f, Current = x %.4f, y %.4f, error = %5.2f DE\n",
+ tYxy[1], tYxy[2], wYxy[1], wYxy[2], icmCIE2K(tLab, wLab));
+ else
+ printf(" Current white = x %.4f, y %.4f, %c%cT %4.0fK DE 2K %4.1f\n",
+ wYxy[1], wYxy[2], dovct ? 'V' : 'C', planckian ? 'C' : 'D', ct,ct_de);
+
+ printf(" Target black = x %.4f, y %.4f, Current = x %.4f, y %.4f, error = %5.2f DE\n",
+ tYxy[1], tYxy[2], bYxy[1], bYxy[2], icmCIE2K(tLab, bLab));
+
+
+ /* Measure and set ambient for viewing condition adjustment */
+ } else if (c == '6') {
+ if ((rv = dr->ambient(dr, &ambient, 1)) != 0) {
+ if (rv == 8) {
+ printf("Instrument doesn't have an ambient reading capability\n");
+ } else {
+ dr->del(dr);
+ error("ambient measure failed with '%s'\n",disprd_err(rv));
+ }
+ } else {
+ printf("Measured ambient level = %.1f Lux\n",ambient * 3.141592654);
+ }
+
+ } else if (c == '7') {
+ if (!verb) { /* Tell user command has been accepted */
+ if (verify == 2)
+ printf("Commencing device verification\n");
+ else
+ printf("Commencing device calibration\n");
+ }
+ break;
+ } else if (c == '8' || c == 0x03 || c == 0x1b) {
+ printf("Exiting\n");
+ dr->del(dr);
+ exit(0);
+ }
+ }
+
+ /* Make sure drift comp. is set to the command line options */
+ dr->change_drift_comp(dr, bdrift, wdrift);
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ /* Take a small number of readings, and compute basic */
+ /* informations such as black & white, white target, */
+ /* aproximate matrix based display forward and reverse model. */
+ /* If bkcorrect is auto, determine a level. */
+
+ /* Read the base test set */
+ {
+ icmXYZNumber mrd; /* Number for matrix */
+ icmXYZNumber mgn;
+ icmXYZNumber mbl;
+ icmXYZNumber mwh;
+ ramdac *or = NULL;
+
+ col base[6] = { /* Base set of test colors */
+ { 0.0, 0.0, 0.0 }, /* 0 - Black */
+ { 1.0, 0.0, 0.0 }, /* 1 - Red */
+ { 0.0, 1.0, 0.0 }, /* 2 - Green */
+ { 0.0, 0.0, 1.0 }, /* 3 - Blue */
+ { 1.0, 1.0, 1.0 }, /* 4 - White */
+ { 0.0, 0.0, 0.0 } /* 5 - Black */
+ };
+
+ if (verb) {
+ if (verify == 2)
+ printf("Commencing device verification\n");
+ else
+ printf("Commencing device calibration\n");
+ }
+
+ /* Switch to native for this, so the black calc is realistic. */
+ /* (Should we really get black aim from previous .cal though ???) */
+ if (verify == 2) {
+ if ((or = dr->dw->get_ramdac(dr->dw)) != NULL) {
+ ramdac *r;
+ if (verb) printf("Switching to native response for base measurements\n");
+ r = or->clone(or);
+ r->setlin(r);
+ dr->dw->set_ramdac(dr->dw, r, 0);
+ r->del(r);
+ }
+ }
+
+ /* Read the patches without clamping */
+ if ((rv = dr->read(dr, base, 6, 1, 6, 1, 0, instNoClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+
+ /* Restore the cal we're verifying */
+ if (verify == 2 && or != NULL) {
+ if (verb) printf("Switching back to calibration being verified\n");
+ dr->dw->set_ramdac(dr->dw, or, 0);
+ or->del(or);
+ }
+
+ if (base[0].XYZ_v == 0) {
+ dr->del(dr);
+ error("Failed to get an XYZ value from the instrument!\n");
+ }
+
+ /* Average black relative from 2 readings */
+ x.bk[0] = 0.5 * (base[0].XYZ[0] + base[5].XYZ[0]);
+ x.bk[1] = 0.5 * (base[0].XYZ[1] + base[5].XYZ[1]);
+ x.bk[2] = 0.5 * (base[0].XYZ[2] + base[5].XYZ[2]);
+ icmClamp3(x.bk, x.bk); /* And clamp them */
+ for (i = 1; i < 5; i++)
+ icmClamp3(base[i].XYZ, base[i].XYZ);
+
+ /* Copy other readings into place */
+ dispLum = base[4].XYZ[1]; /* White Y */
+ icmAry2Ary(x.wh, base[4].XYZ);
+ icmAry2XYZ(x.twN, x.wh); /* Use this as Lab reference white until we establish target */
+
+ icmAry2XYZ(mrd, base[1].XYZ);
+ icmAry2XYZ(mgn, base[2].XYZ);
+ icmAry2XYZ(mbl, base[3].XYZ);
+ icmAry2XYZ(mwh, base[4].XYZ);
+
+ if (verb) {
+ printf("Black = XYZ %6.2f %6.2f %6.2f\n",x.bk[0],x.bk[1],x.bk[2]);
+ printf("Red = XYZ %6.2f %6.2f %6.2f\n",base[1].XYZ[0], base[1].XYZ[1], base[1].XYZ[2]);
+ printf("Green = XYZ %6.2f %6.2f %6.2f\n",base[2].XYZ[0], base[2].XYZ[1], base[2].XYZ[2]);
+ printf("Blue = XYZ %6.2f %6.2f %6.2f\n",base[3].XYZ[0], base[3].XYZ[1], base[3].XYZ[2]);
+ printf("White = XYZ %6.2f %6.2f %6.2f\n",base[4].XYZ[0], base[4].XYZ[1], base[4].XYZ[2]);
+ }
+
+ /* Setup forward matrix */
+ if (icmRGBprim2matrix(mwh, mrd, mgn, mbl, x.fm)) {
+ dr->del(dr);
+ error("Aprox. fwd matrix unexpectedly singular\n");
+ }
+
+#ifdef DEBUG
+ if (verb) {
+ printf("Forward matrix is:\n");
+ printf("%f %f %f\n", x.fm[0][0], x.fm[0][1], x.fm[0][2]);
+ printf("%f %f %f\n", x.fm[1][0], x.fm[1][1], x.fm[1][2]);
+ printf("%f %f %f\n", x.fm[2][0], x.fm[2][1], x.fm[2][2]);
+ }
+#endif
+
+ /* Compute bwd matrix */
+ if (icmInverse3x3(x.bm, x.fm)) {
+ dr->del(dr);
+ error("Inverting aprox. fwd matrix failed");
+ }
+
+ /* Decide on the level of black correction. */
+ if (bkcorrect < 0.0) {
+ double rat;
+
+ /* rat is 0 for displays with a good black, */
+ /* and 1 for displays with a bad black level. */
+ /* (Not sure if this should be scaled by the white, */
+ /* making it contrast ratio sensitive?) */
+ rat = (x.bk[1] - 0.02)/(0.3 - 0.02);
+ if (rat < 0.0)
+ rat = 0.0;
+ else if (rat > 1.0)
+ rat = 1.0;
+ /* Make transition more perceptual */
+ rat = sqrt(rat);
+ bkcorrect = 1.0 - rat;
+ if (verb)
+ printf("Automatic black point hue correction level = %1.2f\n", bkcorrect);
+ }
+ }
+
+ /* Now do some more readings, to compute the basic per channel */
+ /* transfer characteristics, and then a device model. */
+ if (verify != 2 && !doupdate) {
+ col *cols; /* Read 4 x isteps patches from display */
+ sxyz *asrgb[4]; /* samples for r, g, b & w */
+
+ if ((cols = (col *)malloc(isteps * 4 * sizeof(col))) == NULL) {
+ dr->del(dr);
+ error ("Malloc of array of readings failed");
+ }
+ for (j = 0; j < 4; j++) {
+ if ((asrgb[j] = (sxyz *)malloc(isteps * sizeof(sxyz))) == NULL) {
+ free(cols);
+ dr->del(dr);
+ error ("Malloc of array of readings failed");
+ }
+ }
+
+ /* Set the device colors to read */
+ for (i = 0; i < isteps; i++) {
+ double vv;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ vv = i/(isteps - 1.0);
+ vv = pow(vv, MOD_DIST_POW);
+ for (j = 0; j < 4; j++) {
+ cols[i * 4 + j].r = cols[i * 4 + j].g = cols[i * 4 + j].b = 0.0;
+ if (j == 0)
+ cols[i * 4 + j].r = vv;
+ else if (j == 1)
+ cols[i * 4 + j].g = vv;
+ else if (j == 2)
+ cols[i * 4 + j].b = vv;
+ else
+ cols[i * 4 + j].r = cols[i * 4 + j].g = cols[i * 4 + j].b = vv;
+ }
+ }
+
+ /* Read the patches */
+ if ((rv = dr->read(dr, cols, isteps * 4, 1, isteps * 4, 1, 0, instClamp)) != 0) {
+ free(cols); free(asrgb[0]); free(asrgb[1]); free(asrgb[2]); free(asrgb[3]);
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+
+ /* Transfer readings to asrgb[] */
+ for (i = 0; i < isteps; i++) {
+ double vv = cols[i * 4 + 0].r;
+ for (j = 0; j < 4; j++) {
+//printf("~1 R = %f, G = %f, B = %f, XYZ = %f %f %f\n",
+//cols[i * 4 + j].r, cols[i * 4 + j].g, cols[i * 4 + j].b, cols[i * 4 + j].XYZ[0], cols[i * 4 + j].XYZ[1], cols[i * 4 + j].XYZ[2]);
+ asrgb[j][i].v = vv;
+ asrgb[j][i].xyz[0] = cols[i * 4 + j].XYZ[0];
+ asrgb[j][i].xyz[1] = cols[i * 4 + j].XYZ[1];
+ asrgb[j][i].xyz[2] = cols[i * 4 + j].XYZ[2];
+ }
+ }
+
+ /* Convert RGB channel samples to curves */
+ {
+ mcvco *sdv; /* Points used to create cvs[], RGB */
+ double blrgb[3];
+ double *op; /* Parameters to optimise */
+ double *sa; /* Search area */
+ double re; /* Residual error */
+
+ /* Transform measured black back to linearised RGB values */
+ icmMulBy3x3(blrgb, x.bm, x.bk);
+//printf("~1 model black should be %f %f %f\n", x.bk[0], x.bk[1], x.bk[2]);
+//printf("~1 linearised RGB should be %f %f %f\n", blrgb[0], blrgb[1], blrgb[2]);
+
+ if ((sdv = malloc(sizeof(mcvco) * isteps)) == NULL) {
+ free(cols); free(asrgb[0]); free(asrgb[1]); free(asrgb[2]); free(asrgb[3]);
+ dr->del(dr);
+ error ("Malloc of scattered data points failed");
+ }
+ for (k = 0; k < 3; k++) { /* Create the model curves */
+ for (i = 0; i < isteps; i++) {
+ sdv[i].p = asrgb[k][i].v;
+ sdv[i].v = ICMNORM3(asrgb[k][i].xyz);
+ sdv[i].w = 1.0;
+//printf("~1 chan %d, entry %d, p = %f, v = %f from XYZ %f %f %f\n",
+//k,i,x.sdv[k][i].p,x.sdv[k][i].v, asrgb[k][i].xyz[0], asrgb[k][i].xyz[1], asrgb[k][i].xyz[2]);
+ }
+ if ((x.dcvs[k] = new_mcv()) == NULL) {
+ free(cols); free(asrgb[0]); free(asrgb[1]); free(asrgb[2]); free(asrgb[3]);
+ dr->del(dr);
+ error("new_mcv x.dcvs[%d] failed",k);
+ }
+ x.dcvs[k]->fit(x.dcvs[k], 0, fitord, sdv, isteps, 5.0);
+
+ /* Scale the whole curve so the output is scaled to 1.0 */
+ x.dcvs[k]->force_scale(x.dcvs[k], 1.0);
+
+ /* Force curves to produce this lrgb for 0.0 */
+ x.dcvs[k]->force_0(x.dcvs[k], blrgb[k]);
+ }
+ free(sdv);
+
+#ifdef OPTIMIZE_MODEL
+ /* Setup list of reference points ready for optimisation */
+ x.nrp = 4 * isteps;
+ if ((x.rp = (optref *)malloc(sizeof(optref) * x.nrp)) == NULL) {
+ free(cols); free(asrgb[0]); free(asrgb[1]); free(asrgb[2]); free(asrgb[3]);
+ dr->del(dr);
+ error ("Malloc of measurement reference points failed");
+ }
+ for (k = 0; k < 4; k++) {
+ for (i = 0; i < isteps; i++) {
+ int ii = k * isteps + i;
+ double v[3];
+
+ v[0] = v[1] = v[2] = 0.0;
+ if (k == 0)
+ v[k] = asrgb[k][i].v;
+ else if (k == 1)
+ v[k] = asrgb[k][i].v;
+ else if (k == 2)
+ v[k] = asrgb[k][i].v;
+ else
+ v[0] = v[1] = v[2] = asrgb[k][i].v;
+ icmAry2Ary(x.rp[ii].dev, v);
+ icmXYZ2Lab(&x.twN, x.rp[ii].lab, asrgb[k][i].xyz);
+ if (k == 3) /* White */
+ x.rp[ii].w = 0.5;
+ else
+ x.rp[ii].w = 0.16667;
+ }
+ }
+
+ /* Get parameters and setup for optimisation */
+ op = dev_get_params(&x);
+ if ((sa = malloc(x.np * sizeof(double))) == NULL) {
+ free(cols); free(asrgb[0]); free(asrgb[1]); free(asrgb[2]); free(asrgb[3]);
+ dr->del(dr);
+ error ("Malloc of scattered data points failed");
+ }
+
+ for (i = 0; i < x.np; i++)
+ sa[i] = 0.1;
+
+ /* Do optimisation */
+#ifdef NEVER
+ if (powell(&re, x.np, op, sa, 1e-5, 3000, dev_opt_func, (void *)&x, NULL, NULL) != 0) {
+ free(cols); free(asrgb[0]); free(asrgb[1]); free(asrgb[2]); free(asrgb[3]);
+ dr->del(dr);
+ error ("Model powell failed, re = %f",re);
+ }
+#else
+ if (conjgrad(&re, x.np, op, sa, 1e-5, 3000,
+ dev_opt_func, dev_dopt_func, (void *)&x, NULL, NULL) != 0) {
+ if (re > 1e-2) {
+ free(cols); free(asrgb[0]); free(asrgb[1]); free(asrgb[2]); free(asrgb[3]);
+ dr->del(dr);
+ error("Model conjgrad failed, residual error = %f",re);
+ } else
+ warning("Model conjgrad failed, residual error = %f",re);
+ }
+#endif
+
+ /* Put optimised parameters in place */
+ dev_put_params(&x, op);
+
+ free(x.rp);
+ x.rp = NULL;
+ x.nrp = 0;
+ free(x.dtin_iv); /* Free temporary arrays */
+ x.dtin_iv = NULL;
+ free(sa);
+ free(op);
+#endif /* OPTIMIZE_MODEL */
+ }
+
+#ifdef DEBUG_PLOT
+ /* Plot the current calc curves */
+ {
+ #define XRES 256
+ double xx[XRES];
+ double yy[3][XRES];
+ double xyz[3];
+ for (i = 0; i < XRES; i++) {
+ xx[i] = i/(XRES-1.0);
+ for (j = 0; j < 3; j++)
+ yy[j][i] = x.dcvs[j]->interp(x.dcvs[j], xx[i]);
+ }
+ printf("Channel curves\n");
+ do_plot(xx,yy[0],yy[1],yy[2],XRES);
+ #undef XRES
+ }
+#endif
+
+ /* We're done with cols[] and asrgb[] */
+ free(cols); free(asrgb[0]); free(asrgb[1]); free(asrgb[2]); free(asrgb[3]);
+ }
+
+#ifdef CHECK_MODEL
+ /* Check how well our fwd model agrees with the device */
+ if (verify != 2) {
+ col set[3]; /* Variable to read up to 3 values from the display */
+ int nn = 27;
+ double alab[3], mxyz[3], mlab[3]; /* Actual and model Lab */
+ double mnerr; /* Maximum neutral error */
+ double mnv; /* Value where maximum error is */
+ double anerr; /* Average neutral error */
+
+ mnerr = anerr = 0.0;
+ /* !!! Should change this to single batch to work better with drift comp. !!! */
+ for (i = 0; i < (nn + 3); i++) {
+ double vv, v[3];
+ double de;
+
+ if (i < nn) {
+ vv = i/(nn - 1.0);
+ vv = pow(vv, CHECK_DIST_POW);
+ v[0] = v[1] = v[2] = vv;
+ set[0].r = set[0].g = set[0].b = vv;
+
+ } else { /* Do R, G, B */
+ v[0] = v[1] = v[2] = 0.0;
+ v[i - nn] = 1.0;
+ set[0].r = v[0];
+ set[0].g = v[1];
+ set[0].b = v[2];
+ }
+
+ if ((rv = dr->read(dr, set, 1, i+1, nn+3, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ icmXYZ2Lab(&x.twN, alab, set[0].XYZ);
+
+ fwddev(&x, mxyz, v);
+ icmXYZ2Lab(&x.twN, mlab, mxyz);
+
+ de = icmCIE2K(mlab, alab);
+ if (de > mnerr) {
+ mnerr = de;
+ mnv = vv;
+ }
+ anerr += de;
+
+ printf("RGB %.3f %.3f %.3f -> XYZ %.2f %.2f %.2f, model %.2f %.2f %.2f\n",
+ set[0].r, set[0].g, set[0].b,
+ set[0].XYZ[0], set[0].XYZ[1],
+ set[0].XYZ[2], mxyz[0], mxyz[1], mxyz[2]);
+
+ printf("RGB %.3f %.3f %.3f -> Lab %.2f %.2f %.2f, model %.2f %.2f %.2f, DE %f\n",
+ set[0].r, set[0].g, set[0].b, alab[0], alab[1], alab[2], mlab[0], mlab[1], mlab[2],de);
+ }
+ anerr /= (double)(nn+3);
+ printf("Model maximum error (@ %f) = %f deltaE\n",mnv, mnerr);
+ printf("Model average error = %f deltaE\n",anerr);
+ }
+#endif /* CHECK_MODEL */
+
+ /* Figure out our calibration curve parameter targets */
+ if (!doupdate) {
+
+ /* Figure out the target white point */
+ if (wpx > 0.0 || wpy > 0.0) { /* xy coordinates */
+ double Yxy[3];
+ Yxy[0] = 1.0;
+ Yxy[1] = wpx;
+ Yxy[2] = wpy;
+ icmYxy2XYZ(x.twh, Yxy);
+
+ } else if (temp > 0.0) { /* Daylight color temperature */
+ if (planckian)
+ rv = icx_ill_sp2XYZ(x.twh, icxOT_default, NULL, icxIT_Ptemp, temp, NULL);
+ else
+ rv = icx_ill_sp2XYZ(x.twh, icxOT_default, NULL, icxIT_Dtemp, temp, NULL);
+ if (rv != 0)
+ error("Failed to compute XYZ of target color temperature %f\n",temp);
+//printf("~1 Raw target from temp %f XYZ = %f %f %f\n",temp,x.twh[0],x.twh[1],x.twh[2]);
+ } else { /* Native white */
+ x.twh[0] = x.wh[0]/x.wh[1];
+ x.twh[1] = x.wh[1]/x.wh[1];
+ x.twh[2] = x.wh[2]/x.wh[1];
+ }
+ x.nwh[0] = x.twh[0];
+ x.nwh[1] = x.twh[1];
+ x.nwh[2] = x.twh[2];
+
+ /* Convert it to absolute white target */
+ if (tbright > 0.0) { /* Given brightness */
+ x.twh[0] *= tbright;
+ x.twh[1] *= tbright;
+ x.twh[2] *= tbright;
+ } else { /* Native/maximum brightness */
+ x.twh[0] *= x.wh[1];
+ x.twh[1] *= x.wh[1];
+ x.twh[2] *= x.wh[1];
+ if (verb)
+ printf("Initial native brightness target = %f cd/m^2\n", x.twh[1]);
+ }
+
+ /* Now make sure the target white will fit in gamut. */
+ if (verify != 2 &&
+ ((tbright > 0.0 && invlindev(&x, NULL, x.twh) > 0.0) /* Defined brightness and clips */
+ || (tbright <= 0.0 && x.nat == 0))) { /* Max non-native white */
+ double rgb[3];
+ double scale = 0.5;
+ double sa = 0.1;
+
+ if (powell(NULL, 1, &scale, &sa, 1e-7, 500, wp_opt_func, (void *)&x, NULL, NULL) != 0)
+ error ("WP scale powell failed");
+
+ x.twh[0] *= scale;
+ x.twh[1] *= scale;
+ x.twh[2] *= scale;
+ invdev(&x, rgb, x.twh);
+ if (verb) {
+ printf("Had to scale brightness from %f to %f to fit within gamut,\n",x.twh[1]/scale, x.twh[1]);
+ printf("corresponding to aprox. RGB %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+ }
+ }
+
+ if (verb)
+ printf("Target white value is XYZ %f %f %f\n",x.twh[0],x.twh[1],x.twh[2]);
+ }
+
+ /* Need this for Lab conversions */
+ icmAry2XYZ(x.twN, x.twh);
+
+ /* Figure out the black point target */
+ {
+ double tbL[3];
+ double tbkLab[3];
+
+ icmXYZ2Lab(&x.twN, tbkLab, x.bk); /* Convert measured black to Lab */
+
+//printf("~1 black point Lab = %f %f %f\n", tbkLab[0], tbkLab[1], tbkLab[2]);
+
+ /* Now blend the a* b* with that of the target white point */
+ tbL[0] = tbkLab[0];
+ tbL[1] = bkcorrect * 0.0 + (1.0 - bkcorrect) * tbkLab[1];
+ tbL[2] = bkcorrect * 0.0 + (1.0 - bkcorrect) * tbkLab[2];
+
+//printf("~1 blended black Lab = %f %f %f\n", tbL[0], tbL[1], tbL[2]);
+
+ if (bkbright > 0.0 && (bkbright <= x.bk[1] || (2.0 * bkbright) >= x.twh[1]))
+ warning("Black brigtness %f ignored because it is out of range",bkbright);
+ else if (bkbright > 0.0) {
+ double bkbxyz[3], bkbLab[3], vv, bl;
+ /* Figure out the L value of the target brightness */
+ bkbxyz[0] = 0.0;
+ bkbxyz[1] = bkbright;
+ bkbxyz[2] = 0.0;
+ icmXYZ2Lab(&x.twN, bkbLab, bkbxyz);
+
+ /* Do crossover to white neutral */
+ vv = bkbLab[0] / (100.0 - tbL[0]);
+ bl = pow((1.0 - vv), x.nbrate); /* Crossover near the black */
+ tbL[0] = bkbLab[0];
+ tbL[1] = (1.0 - bl) * 0.0 + bl * tbL[1];
+ tbL[2] = (1.0 - bl) * 0.0 + bl * tbL[2];
+//printf("~1 brighted black Lab = %f %f %f\n", tbL[0], tbL[1], tbL[2]);
+ }
+
+ /* And make this the black hue to aim for */
+ icmLab2XYZ(&x.twN, x.tbk, tbL);
+ icmAry2XYZ(x.tbN, x.tbk);
+ if (verb)
+ printf("Adjusted target black XYZ %.2f %.2f %.2f, Lab %.2f %.2f %.2f\n",
+ x.tbk[0], x.tbk[1], x.tbk[2], tbL[0], tbL[1], tbL[2]);
+ }
+
+ /* Figure out the gamma curve black offset value */
+ /* that will give us the black level we actually have. */
+ {
+ double yy, tby; /* Target black y */
+
+ /* Make target black Y as high as necessary */
+ /* to get the black point hue */
+ /* ????? should do this by increasing L* until XYZ > x.bk ????? */
+ tby = x.bk[1];
+//printf("Target Y from Y = %f\n",tby);
+ yy = x.bk[0] * x.tbk[1]/x.tbk[0];
+//printf("Target Y from X = %f\n",yy);
+ if (yy > tby)
+ tby = yy;
+ yy = x.bk[2] * x.tbk[1]/x.tbk[2];
+//printf("Target Y from Z = %f\n",yy);
+ if (yy > tby)
+ tby = yy;
+
+ if (x.tbk[1] > tby) /* If target is already high enough */
+ tby = x.tbk[1];
+
+ if (verb) {
+ double tbp[3], tbplab[3];
+ tbp[0] = x.tbk[0] * tby/x.tbk[1];
+ tbp[1] = tby;
+ tbp[2] = x.tbk[2] * tby/x.tbk[1];
+ icmXYZ2Lab(&x.twN, tbplab, tbp);
+ printf("Target black after min adjust: XYZ %.3f %.3f %.3f, Lab %.3f %.3f %.3f\n",
+ tbp[0], tbp[1], tbp[2], tbplab[0], tbplab[1], tbplab[2]);
+ }
+
+ /* Figure out the x.gioff and egamma needed to get this x.gooff and gamma */
+ x.gooff = tby / x.twh[1]; /* Convert to relative */
+
+ /* tech_gamma() does the hard work */
+ tech_gamma(&x, &x.egamma, &x.gooff, &x.gioff, egamma, gamma, x.gooff);
+ }
+
+ if (verb)
+ printf("Gamma curve input offset = %f, output offset = %f, power = %f\n",x.gioff,x.gooff,x.egamma);
+
+ /* For ambient light compensation, we make use of CIECAM02 */
+ if (ambient > 0.0) {
+ double xyz[3], Jab[3];
+ double t1, t0, a1, a0;
+
+ /* Setup default source viewing conditions */
+ if ((x.svc = new_icxcam(cam_default)) == NULL
+ || (x.dvc = new_icxcam(cam_default)) == NULL) {
+ error("Failed to create source and destination CAMs");
+ }
+
+ switch(x.gammat) {
+ case gt_power: /* There's nothing obvious for these cases, */
+ case gt_Lab: /* So default to a computerish source viewing condition */
+
+ case gt_sRGB: /* sRGB standard viewing conditions */
+ x.svc->set_view(x.svc, vc_none,
+ x.nwh, /* Display normalised white point */
+ 0.2 * 80.0, /* Adapting luminence, 20% of display 80 cd/m^2 */
+ 0.2, /* Background relative to reference white */
+ 80.0, /* Display is 80 cd/m^2 */
+ 0.01, x.nwh, /* 1% flare same white point */
+ 0);
+ break;
+
+ case gt_Rec709:
+ case gt_SMPTE240M: /* Television studio conditions */
+ x.svc->set_view(x.svc, vc_none,
+ x.nwh, /* Display normalised white point */
+ 0.2 * 1000.0/3.1415, /* Adapting luminence, 20% of 1000 lux in cd/m^2 */
+ 0.2, /* Background relative to reference white */
+ 1000.0/3.1415, /* Luminance of white in the Image field (cd/m^2) */
+ 0.01, x.nwh, /* 1% flare same white point */
+ 0);
+ break;
+
+ default:
+ error("Unknown gamma type");
+ }
+ /* The display we're calibratings situation */
+ x.dvc->set_view(x.dvc, vc_none,
+ x.nwh, /* Display normalised white point */
+ 0.2 * ambient, /* Adapting luminence, 20% of ambient in cd/m^2 */
+ 0.2, /* Background relative to reference white */
+ x.twh[1], /* Target white level (cd/m^2) */
+ 0.01, x.nwh, /* 1% flare same white point */
+ 0);
+
+ /* Compute the normalisation values */
+ x.svc->XYZ_to_cam(x.svc, Jab, x.nwh); /* Relative white point */
+ x.dvc->cam_to_XYZ(x.dvc, xyz, Jab);
+ t1 = x.nwh[1];
+ a1 = xyz[1];
+
+ xyz[0] = x.tbk[1]/x.twh[1] * x.nwh[0];
+ xyz[1] = x.tbk[1]/x.twh[1] * x.nwh[1];
+ xyz[2] = x.tbk[1]/x.twh[1] * x.nwh[2];
+ t0 = xyz[1];
+ x.svc->XYZ_to_cam(x.svc, Jab, xyz); /* Relative black Y */
+ x.dvc->cam_to_XYZ(x.dvc, xyz, Jab);
+ a0 = xyz[1];
+
+//printf("~1 t1 = %f, t0 = %f\n",t1,t0);
+//printf("~1 a1 = %f, a0 = %f\n",a1,a0);
+ x.vn1 = (t1 - t0)/(a1 - a0); /* Scale factor */
+ x.vn0 = t0 - (a0 * x.vn1); /* Then offset */
+//printf("~1 vn1 = %f, vn0 = %f\n",x.vn1, x.vn0);
+//printf("~1 fix a1 = %f, should be = %f\n",a1 * x.vn1 + x.vn0, t1);
+//printf("~1 fix a0 = %f, should be = %f\n",a0 * x.vn1 + x.vn0, t0);
+
+ x.vc = 1;
+
+ /* Compute aproximate power of viewing transform */
+ if (verb) {
+ double v;
+ v = view_xform(&x, 0.5);
+ v = log(v) / log(0.5);
+ printf("Viewing conditions adjustment aprox. power = %f\n",v);
+ }
+#ifdef NEVER
+{
+ int i;
+
+ printf("~1 viewing xtranform:\n");
+ for (i = 0; i <= 10; i++) {
+ double w, v = i/10.0;
+
+ w = view_xform(&x, v);
+ printf("~1 in %f -> %f\n",v,w);
+ }
+}
+#endif /* NEVER */
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - */
+ /* Start with a scaled down number of test points and refine threshold, */
+ /* and double/halve these on each iteration. */
+ if (verb && verify != 2)
+ printf("Total Iteration %d, Final Samples = %d Final Repeat threshold = %f\n",
+ mxits, rsteps, errthr);
+ if (verify == 2) {
+ rsteps = VER_RES;
+ errthr = 0.0;
+ } else {
+ rsteps /= (1 << (mxits-1));
+ errthr *= pow((double)(1 << (mxits-1)), THRESH_SCALE_POW);
+ }
+
+ /* Setup the initial calibration test point values */
+ init_csamp(&asgrey, &x, doupdate, verify, verify == 2 ? 1 : 0, rsteps);
+
+ /* Calculate the initial calibration curve values */
+ if (verify != 2 && !doupdate) {
+ int nsamp = 128;
+ mcvco *sdv[3]; /* Scattered data for creating mcv */
+
+ for (j = 0; j < 3; j++) {
+ if ((x.rdac[j] = new_mcv()) == NULL) {
+ dr->del(dr);
+ error("new_mcv x.rdac[%d] failed",j);
+ }
+ }
+
+ for (j = 0; j < 3; j++) {
+ if ((sdv[j] = malloc(sizeof(mcvco) * rsteps)) == NULL) {
+ dr->del(dr);
+ error ("Malloc of scattered data points failed");
+ }
+ }
+
+ if (verb)
+ printf("Creating initial calibration curves...\n");
+
+ /* Copy the sample points */
+ for (i = 0; i < rsteps; i++) {
+ for (j = 0; j < 3; j++) {
+ sdv[j][i].p = asgrey.s[i].v;
+ sdv[j][i].v = asgrey.s[i].rgb[j];
+ sdv[j][i].w = 1.0;
+ }
+ }
+ if (x.nat) /* Make curve go thought white if possible */
+ sdv[0][rsteps-1].w = sdv[1][rsteps-1].w = sdv[2][rsteps-1].w = 50.0;
+
+ /* Create an initial set of RAMDAC curves */
+ for (j = 0; j < 3; j++)
+ x.rdac[j]->fit(x.rdac[j], 0, fitord, sdv[j], rsteps, RDAC_SMOOTH);
+
+ /* Make sure that if we are using native brightness and white point, */
+ /* that the curves go to a perfect 1.0 ... */
+ if (x.nat) {
+ for (j = 0; j < 3; j++)
+ x.rdac[j]->force_1(x.rdac[j], 1.0);
+ }
+
+ for (j = 0; j < 3; j++)
+ free (sdv[j]);
+ }
+
+#ifdef DEBUG_PLOT
+ /* Plot the initial curves */
+ if (verify != 2) {
+ #define XRES 255
+ double xx[XRES];
+ double y1[XRES];
+ double y2[XRES];
+ double y3[XRES];
+ double rgb[3];
+ for (i = 0; i < XRES; i++) {
+ double drgb[3], rgb[3];
+ xx[i] = i/(XRES-1.0);
+ rgb[0] = rgb[1] = rgb[2] = xx[i];
+ for (j = 0; j < 3; j++)
+ drgb[j] = x.rdac[j]->interp(x.rdac[j], rgb[j]);
+ y1[i] = drgb[0];
+ y2[i] = drgb[1];
+ y3[i] = drgb[2];
+ }
+ printf("Initial ramdac curves\n");
+ do_plot(xx,y1,y2,y3,XRES);
+ #undef XRES
+ }
+#endif
+
+ dr->reset_targ_w(dr); /* Reset white drift target at start of main cal. */
+
+ /* Now we go into the main verify & refine loop */
+ for (it = verify == 2 ? mxits : 0; it < mxits || verify != 0;
+ rsteps *= 2, errthr /= (it < mxits) ? pow(2.0,THRESH_SCALE_POW) : 1.0, it++) {
+ int totmeas = 0; /* Total number of measurements in this pass */
+ col set[3]; /* Variable to read one to three values from the display */
+
+ /* Verify pass */
+ if (it >= mxits)
+ rsteps = VER_RES; /* Fixed verification resolution */
+ else
+ thrfail = 0; /* Not verify pass */
+
+
+ /* re-init asgrey if the number of test points has changed */
+ reinit_csamp(&asgrey, &x, verify, (verify == 2 || it >= mxits) ? 1 : 0, rsteps);
+
+ if (verb) {
+ if (it >= mxits)
+ printf("Doing verify pass with %d sample points\n",rsteps);
+ else
+ printf("Doing iteration %d with %d sample points and repeat threshold of %f DE\n",
+ it+1,rsteps, errthr);
+ }
+ /* Read and adjust each step */
+ /* Do this white to black to track drift in native white point */
+ for (i = rsteps-1; i >= 0; i--) {
+ double rpt;
+ double peqXYZ[3]; /* Previous steps equivalent aim point */
+ double bestrgb[3]; /* In case we fail */
+ double bestxyz[3];
+ double prevde = 1e7;
+ double bestde = 1e7;
+ double bestdc = 1e7;
+ double bestpeqde = 1e7;
+ double besthde = 1e7;
+ double rgain = REFINE_GAIN; /* Scale down if lots of repeats */
+ int mjac = 0; /* We measured the Jacobian */
+
+ /* Setup a second termination threshold chriteria based on */
+ /* the delta E to the previous step point for the last pass. */
+ if (i == (rsteps-1) || it < (mxits-1)) {
+ icmAry2Ary(peqXYZ, asgrey.s[i].tXYZ); /* Its own aim point */
+ } else {
+ double Lab1[3], Lab2[3], Lab3[3];
+ icmXYZ2Lab(&x.twN, Lab1, asgrey.s[i+1].XYZ);
+ icmXYZ2Lab(&x.twN, Lab2, asgrey.s[i].tXYZ);
+ Lab3[0] = Lab2[0];
+ Lab3[1] = 0.5 * (Lab1[1] + Lab2[1]); /* Compute aim point between actual target */
+ Lab3[2] = 0.5 * (Lab1[2] + Lab2[2]); /* and previous point. */
+ icmLab2XYZ(&x.twN, asgrey.s[i].tXYZ, Lab3);
+ Lab1[0] = Lab2[0]; /* L of current target with ab of previous as 2nd threshold */
+ icmLab2XYZ(&x.twN, peqXYZ, Lab1);
+ }
+
+ /* Until we meet the necessary accuracy or give up */
+ for (rpt = 0;rpt < MAX_RPTS; rpt++) {
+ int gworse = 0; /* information flag */
+ double wde; /* informational */
+
+ set[0].r = asgrey.s[i].rgb[0];
+ set[0].g = asgrey.s[i].rgb[1];
+ set[0].b = asgrey.s[i].rgb[2];
+ set[0].id = NULL;
+
+ /* Read patches (no auto cr in case we repeat last patch) */
+ if ((rv = dr->read(dr, set, 1, rsteps-i, rsteps, 0, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ totmeas++;
+
+ icmAry2Ary(asgrey.s[i].pXYZ, asgrey.s[i].XYZ); /* Remember previous XYZ */
+ icmAry2Ary(asgrey.s[i].XYZ, set[0].XYZ); /* Transfer current reading */
+
+ /* If native white and we've just measured it, */
+ /* and we're not doing a verification, */
+ /* adjust all the other point targets txyz to track the white. */
+ if (x.nat && i == (rsteps-1) && it < mxits && asgrey.s[i].v == 1.0) {
+
+ icmAry2Ary(x.twh, asgrey.s[i].XYZ); /* Set current white */
+ icmAry2XYZ(x.twN, x.twh); /* Need this for Lab conversions */
+ init_csamp_txyz(&asgrey, &x, 1); /* Recompute txyz's */
+ icmAry2Ary(peqXYZ, asgrey.s[i].tXYZ); /* Fix peqXYZ */
+//printf("~1 Just reset target white to native white\n");
+ if (wdrift) { /* Make sure white drift is reset on next read. */
+ dr->reset_targ_w(dr); /* Reset this */
+ }
+ }
+
+ /* Compute the current change wanted to hit target */
+ icmSub3(asgrey.s[i].deXYZ, asgrey.s[i].tXYZ, asgrey.s[i].XYZ);
+ asgrey.s[i].de = icmXYZLabDE(&x.twN, asgrey.s[i].tXYZ, asgrey.s[i].XYZ);
+ asgrey.s[i].peqde = icmXYZLabDE(&x.twN, peqXYZ, asgrey.s[i].XYZ);
+ asgrey.s[i].hde = 0.8 * asgrey.s[i].de + 0.2 * asgrey.s[i].peqde;
+ /* Eudclidian difference of XYZ, because this doesn't always track Lab */
+ asgrey.s[i].dc = icmLabDE(asgrey.s[i].tXYZ, asgrey.s[i].XYZ);
+
+ /* Compute change from last XYZ */
+ icmSub3(asgrey.s[i].dXYZ, asgrey.s[i].XYZ, asgrey.s[i].pXYZ);
+
+#ifdef DEBUG
+ printf("\n\nTest point %d, v = %f\n",rsteps - i,asgrey.s[i].v);
+ printf("Current rgb %f %f %f -> XYZ %f %f %f, de %f, dc %f\n",
+ asgrey.s[i].rgb[0], asgrey.s[i].rgb[1], asgrey.s[i].rgb[2],
+ asgrey.s[i].XYZ[0], asgrey.s[i].XYZ[1], asgrey.s[i].XYZ[2],
+ asgrey.s[i].de, asgrey.s[i].dc);
+ printf("Target XYZ %f %f %f, delta needed %f %f %f\n",
+ asgrey.s[i].tXYZ[0], asgrey.s[i].tXYZ[1], asgrey.s[i].tXYZ[2],
+ asgrey.s[i].deXYZ[0], asgrey.s[i].deXYZ[1], asgrey.s[i].deXYZ[2]);
+ if (rpt > 0) {
+ printf("Intended XYZ change %f %f %f, actual change %f %f %f\n",
+ asgrey.s[i].pdXYZ[0], asgrey.s[i].pdXYZ[1], asgrey.s[i].pdXYZ[2],
+ asgrey.s[i].dXYZ[0], asgrey.s[i].dXYZ[1], asgrey.s[i].dXYZ[2]);
+ }
+#endif
+
+ if (it < mxits) { /* Not verify, apply correction */
+ int impj = 0; /* We improved the Jacobian */
+ int dclip = 0; /* We clipped the new RGB */
+#ifdef ADJ_JACOBIAN
+ int isclipped = 0;
+
+#ifndef CLIP /* Check for cliping */
+ /* Don't try and update the Jacobian if the */
+ /* device values are going out of gamut, */
+ /* and being clipped without Jac correction being aware. */
+ for (j = 0; j < 3; j++) {
+ if (asgrey.s[i].rgb[j] <= 0.0 || asgrey.s[i].rgb[j] >= 1.0) {
+ isclipped = 1;
+ break;
+ }
+ }
+#endif /* !CLIP */
+
+#ifdef REMEAS_JACOBIAN
+ /* If the de hasn't improved, try and measure the Jacobian */
+ if (it < (rsteps-1) && mjac == 0 && asgrey.s[i].de > (0.8 * prevde)) {
+ double dd;
+ if (asgrey.s[i].v < 0.5)
+ dd = 0.05;
+ else
+ dd= -0.05;
+ set[0].r = asgrey.s[i].rgb[0] + dd;
+ set[0].g = asgrey.s[i].rgb[1];
+ set[0].b = asgrey.s[i].rgb[2];
+ set[0].id = NULL;
+ set[1].r = asgrey.s[i].rgb[0];
+ set[1].g = asgrey.s[i].rgb[1] + dd;
+ set[1].b = asgrey.s[i].rgb[2];
+ set[1].id = NULL;
+ set[2].r = asgrey.s[i].rgb[0];
+ set[2].g = asgrey.s[i].rgb[1];
+ set[2].b = asgrey.s[i].rgb[2] + dd;
+ set[2].id = NULL;
+
+ if ((rv = dr->read(dr, set, 1, rsteps-i, rsteps, 0, 0, instClamp)) != 0
+ || (rv = dr->read(dr, set+1, 1, rsteps-i, rsteps, 0, 0, instClamp)) != 0
+ || (rv = dr->read(dr, set+2, 1, rsteps-i, rsteps, 0, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("display read failed with '%s'\n",disprd_err(rv));
+ }
+ totmeas += 3;
+
+ /* Matrix organization is J[XYZ][RGB] for del RGB->del XYZ*/
+ for (j = 0; j < 3; j++) {
+ asgrey.s[i].j[0][j] = (set[j].XYZ[0] - asgrey.s[i].XYZ[0]) / dd;
+ asgrey.s[i].j[1][j] = (set[j].XYZ[1] - asgrey.s[i].XYZ[1]) / dd;
+ asgrey.s[i].j[2][j] = (set[j].XYZ[2] - asgrey.s[i].XYZ[2]) / dd;
+ }
+ if (icmInverse3x3(asgrey.s[i].ij, asgrey.s[i].j)) {
+ /* Should repeat with bigger dd ? */
+//printf("~1 matrix =\n");
+//printf("~1 %f %f %f\n", asgrey.s[i].j[0][0], asgrey.s[i].j[0][1], asgrey.s[i].j[0][2]);
+//printf("~1 %f %f %f\n", asgrey.s[i].j[1][0], asgrey.s[i].j[1][1], asgrey.s[i].j[1][2]);
+//printf("~1 %f %f %f\n", asgrey.s[i].j[2][0], asgrey.s[i].j[2][1], asgrey.s[i].j[2][2]);
+ if (verb)
+ printf("dispcal: inverting Jacobian failed (3) - falling back\n");
+
+ /* Revert to the initial Jacobian */
+ icmCpy3x3(asgrey.s[i].ij, asgrey.s[i].fb_ij);
+ }
+ /* Restart at the best we've had */
+ if (asgrey.s[i].hde > besthde) {
+ asgrey.s[i].de = bestde;
+ asgrey.s[i].dc = bestdc;
+ asgrey.s[i].peqde = bestpeqde;
+ asgrey.s[i].hde = besthde;
+ asgrey.s[i].rgb[0] = bestrgb[0];
+ asgrey.s[i].rgb[1] = bestrgb[1];
+ asgrey.s[i].rgb[2] = bestrgb[2];
+ asgrey.s[i].XYZ[0] = bestxyz[0];
+ asgrey.s[i].XYZ[1] = bestxyz[1];
+ asgrey.s[i].XYZ[2] = bestxyz[2];
+ icmSub3(asgrey.s[i].deXYZ, asgrey.s[i].tXYZ, asgrey.s[i].XYZ);
+ }
+ mjac = 1;
+ impj = 1;
+ }
+#endif /* REMEAS_JACOBIAN */
+
+ /* Compute a correction to the Jacobian if we can. */
+ /* (Don't do this unless we have a solid previous */
+ /* reading for this patch) */
+ if (impj == 0 && rpt > 0 && isclipped == 0) {
+ double nsdrgb; /* Norm squared of pdrgb */
+ double spdrgb[3]; /* Scaled previous delta rgb */
+ double dXYZerr[3]; /* Error in previous prediction */
+ double jadj[3][3]; /* Adjustment to Jacobian */
+ double tj[3][3]; /* Temp Jacobian */
+ double itj[3][3]; /* Temp inverse Jacobian */
+
+ /* Use Broyden's Formula */
+ icmSub3(dXYZerr, asgrey.s[i].dXYZ, asgrey.s[i].pdXYZ);
+//printf("~1 Jacobian error = %f %f %f\n", dXYZerr[0], dXYZerr[1], dXYZerr[2]);
+ nsdrgb = icmNorm3sq(asgrey.s[i].pdrgb);
+ /* If there was sufficient change in device values */
+ /* to be above any noise: */
+ if (nsdrgb >= (0.005 * 0.005)) {
+ icmScale3(spdrgb, asgrey.s[i].pdrgb, 1.0/nsdrgb);
+ icmTensMul3(jadj, dXYZerr, spdrgb);
+
+#ifdef DEBUG
+ /* Check that new Jacobian predicts previous delta XYZ */
+ {
+ double eXYZ[3];
+
+ /* Make a full adjustment to temporary Jac */
+ icmAdd3x3(tj, asgrey.s[i].j, jadj);
+ icmMulBy3x3(eXYZ, tj, asgrey.s[i].pdrgb);
+ icmSub3(eXYZ, eXYZ, asgrey.s[i].dXYZ);
+ printf("Jac check resid %f %f %f\n", eXYZ[0], eXYZ[1], eXYZ[2]);
+ }
+#endif /* DEBUG */
+
+ /* Add part of our correction to actual Jacobian */
+ icmScale3x3(jadj, jadj, JAC_COR_FACT);
+ icmAdd3x3(tj, asgrey.s[i].j, jadj);
+ if (icmInverse3x3(itj, tj) == 0) { /* Invert OK */
+ icmCpy3x3(asgrey.s[i].j, tj); /* Use adjusted */
+ icmCpy3x3(asgrey.s[i].ij, itj);
+ impj = 1;
+ }
+//else printf("~1 ij failed\n");
+ }
+//else printf("~1 nsdrgb was below threshold\n");
+ }
+//else if (isclipped) printf("~1 no j update: rgb is clipped\n");
+#endif /* ADJ_JACOBIAN */
+
+ /* Track the best solution we've found */
+ if (asgrey.s[i].hde <= besthde) {
+ bestde = asgrey.s[i].de;
+ bestdc = asgrey.s[i].dc;
+ bestpeqde = asgrey.s[i].peqde;
+ besthde = asgrey.s[i].hde;
+ bestrgb[0] = asgrey.s[i].rgb[0];
+ bestrgb[1] = asgrey.s[i].rgb[1];
+ bestrgb[2] = asgrey.s[i].rgb[2];
+ bestxyz[0] = asgrey.s[i].XYZ[0];
+ bestxyz[1] = asgrey.s[i].XYZ[1];
+ bestxyz[2] = asgrey.s[i].XYZ[2];
+
+ } else if (asgrey.s[i].dc > bestdc) {
+ /* we got worse in Lab and XYZ ! */
+
+ wde = asgrey.s[i].de;
+
+ /* If we've wandered too far, return to best we found */
+ if (asgrey.s[i].hde > (3.0 * besthde)) {
+ asgrey.s[i].de = bestde;
+ asgrey.s[i].dc = bestdc;
+ asgrey.s[i].peqde = bestpeqde;
+ asgrey.s[i].hde = besthde;
+ asgrey.s[i].rgb[0] = bestrgb[0];
+ asgrey.s[i].rgb[1] = bestrgb[1];
+ asgrey.s[i].rgb[2] = bestrgb[2];
+ asgrey.s[i].XYZ[0] = bestxyz[0];
+ asgrey.s[i].XYZ[1] = bestxyz[1];
+ asgrey.s[i].XYZ[2] = bestxyz[2];
+ icmSub3(asgrey.s[i].deXYZ, asgrey.s[i].tXYZ, asgrey.s[i].XYZ);
+ }
+
+ /* If the Jacobian hasn't changed, moderate the gain */
+ if (impj == 0)
+ rgain *= 0.8; /* We might be overshooting */
+ gworse = 1;
+ }
+
+ /* See if we need to repeat */
+ if (asgrey.s[i].de <= errthr && asgrey.s[i].peqde < errthr) {
+ if (verb > 1)
+ if (it < (mxits-1))
+ printf("Point %d Delta E %f, OK\n",rsteps - i,asgrey.s[i].de);
+ else
+ printf("Point %d Delta E %f, peqDE %f, OK\n",rsteps - i,asgrey.s[i].de, asgrey.s[i].peqde);
+ break; /* No more retries */
+ }
+ if ((rpt+1) >= MAX_RPTS) {
+ asgrey.s[i].de = bestde; /* Restore to best we found */
+ asgrey.s[i].dc = bestdc;
+ asgrey.s[i].peqde = bestpeqde; /* Restore to best we found */
+ asgrey.s[i].hde = besthde; /* Restore to best we found */
+ asgrey.s[i].rgb[0] = bestrgb[0];
+ asgrey.s[i].rgb[1] = bestrgb[1];
+ asgrey.s[i].rgb[2] = bestrgb[2];
+ asgrey.s[i].XYZ[0] = bestxyz[0];
+ asgrey.s[i].XYZ[1] = bestxyz[1];
+ asgrey.s[i].XYZ[2] = bestxyz[2];
+ if (verb > 1)
+ if (it < (mxits-1))
+ printf("Point %d Delta E %f, Fail\n",rsteps - i,asgrey.s[i].de);
+ else
+ printf("Point %d Delta E %f, peqDE %f, Fail\n",rsteps - i,asgrey.s[i].de,asgrey.s[i].peqde);
+ thrfail = 1; /* Failed to meet target */
+ if (bestde > failerr)
+ failerr = bestde; /* Worst failed delta E */
+ break; /* No more retries */
+ }
+ if (verb > 1) {
+ if (gworse)
+ if (it < (mxits-1))
+ printf("Point %d Delta E %f, Repeat (got worse)\n", rsteps - i, wde);
+ else
+ printf("Point %d Delta E %f, peqDE %f, Repeat (got worse)\n", rsteps - i, wde,asgrey.s[i].peqde);
+ else
+ if (it < (mxits-1))
+ printf("Point %d Delta E %f, Repeat\n", rsteps - i,asgrey.s[i].de);
+ else
+ printf("Point %d Delta E %f, peqDE %f, Repeat\n", rsteps - i,asgrey.s[i].de,asgrey.s[i].peqde);
+ }
+
+ /* Compute refinement of rgb */
+ icmMulBy3x3(asgrey.s[i].pdrgb, asgrey.s[i].ij, asgrey.s[i].deXYZ);
+//printf("~1 delta needed %f %f %f -> delta RGB %f %f %f\n",
+//asgrey.s[i].deXYZ[0], asgrey.s[i].deXYZ[1], asgrey.s[i].deXYZ[2],
+//asgrey.s[i].pdrgb[0], asgrey.s[i].pdrgb[1], asgrey.s[i].pdrgb[2]);
+
+ /* Gain scale */
+ icmScale3(asgrey.s[i].pdrgb, asgrey.s[i].pdrgb, rgain);
+//printf("~1 delta RGB after gain scale %f %f %f\n",
+//asgrey.s[i].pdrgb[0], asgrey.s[i].pdrgb[1], asgrey.s[i].pdrgb[2]);
+
+#ifdef CLIP
+ /* Component wise clip */
+ for (j = 0; j < 3; j++) { /* Check for clip */
+ if ((-asgrey.s[i].pdrgb[j]) > asgrey.s[i].rgb[j]) {
+ asgrey.s[i].pdrgb[j] = -asgrey.s[i].rgb[j];
+ dclip = 1;
+ }
+ if (asgrey.s[i].pdrgb[j] > (1.0 - asgrey.s[i].rgb[j])) {
+ asgrey.s[i].pdrgb[j] = (1.0 - asgrey.s[i].rgb[j]);
+ dclip = 1;
+ }
+ }
+#ifdef DEBUG
+ if (dclip) printf("delta RGB after clip %f %f %f\n",
+ asgrey.s[i].pdrgb[0], asgrey.s[i].pdrgb[1], asgrey.s[i].pdrgb[2]);
+#endif /* DEBUG */
+#endif /* CLIP */
+ /* Compute next on the basis of this one RGB */
+ icmAdd3(asgrey.s[i].rgb, asgrey.s[i].rgb, asgrey.s[i].pdrgb);
+
+ /* Save expected change in XYZ */
+ icmMulBy3x3(asgrey.s[i].pdXYZ, asgrey.s[i].j, asgrey.s[i].pdrgb);
+#ifdef DEBUG
+ printf("New rgb %f %f %f from expected del XYZ %f %f %f\n",
+ asgrey.s[i].rgb[0], asgrey.s[i].rgb[1], asgrey.s[i].rgb[2],
+ asgrey.s[i].pdXYZ[0], asgrey.s[i].pdXYZ[1], asgrey.s[i].pdXYZ[2]);
+#endif
+ } else { /* Verification, so no repeat */
+ break;
+ }
+
+ prevde = asgrey.s[i].de;
+ } /* Next repeat */
+ } /* Next resolution step */
+ if (verb)
+ printf("\n"); /* Final return for patch count */
+
+#ifdef DEBUG_PLOT
+ /* Plot the measured response XYZ */
+ {
+ #define XRES 256
+ double xx[XRES];
+ double yy[3][XRES];
+ double xyz[3];
+ for (i = 0; i < XRES; i++) {
+ xx[i] = i/(XRES-1.0);
+ csamp_interp(&asgrey, xyz, xx[i]);
+ for (j = 0; j < 3; j++)
+ yy[j][i] = xyz[j];
+ }
+ printf("Measured neutral axis XYZ\n",k);
+ do_plot(xx,yy[0],yy[1],yy[2],XRES);
+ #undef XRES
+ }
+#endif
+
+ /* Check out the accuracy of the results: */
+ {
+ double ctwh[3]; /* Current target white */
+ icmXYZNumber ctwN; /* Same as above as XYZNumber */
+ double brerr; /* Brightness error */
+ double cterr; /* Color temperature delta E */
+ double mnerr; /* Maximum neutral error */
+ double mnv = 0.0; /* Value where maximum error is */
+ double anerr; /* Average neutral error */
+ double lab1[3], lab2[3];
+
+ /* Brightness */
+ brerr = asgrey.s[asgrey.no-1].XYZ[1] - x.twh[1];
+
+ /* Compensate for brightness error */
+ for (j = 0; j < 3; j++)
+ ctwh[j] = x.twh[j] * asgrey.s[asgrey.no-1].XYZ[1]/x.twh[1];
+ icmAry2XYZ(ctwN, ctwh); /* Need this for Lab conversions */
+
+ /* Color temperature error */
+ icmXYZ2Lab(&ctwN, lab1, ctwh); /* Should be 100,0,0 */
+ icmXYZ2Lab(&ctwN, lab2, asgrey.s[asgrey.no-1].XYZ);
+ cterr = icmLabDE(lab1, lab2);
+
+ /* check delta E of all the sample points */
+ /* We're checking against our given brightness and */
+ /* white point target. */
+ mnerr = anerr = 0.0;
+ init_csamp_txyz(&asgrey, &x, 0); /* In case the targets were tweaked */
+ for (i = 0; i < asgrey.no; i++) {
+ double err;
+
+ /* Re-compute de in case last pass had tweaked targets */
+ asgrey.s[i].de = icmXYZLabDE(&x.twN, asgrey.s[i].tXYZ, asgrey.s[i].XYZ);
+ err = asgrey.s[i].de;
+//printf("RGB %.3f -> Lab %.2f %.2f %.2f, target %.2f %.2f %.2f, DE %f\n",
+//asgrey.s[i].v, lab2[0], lab2[1], lab2[2], lab1[0], lab1[1], lab1[2], err);
+ if (err > mnerr) {
+ mnerr = err;
+ mnv = asgrey.s[i].v;
+ }
+ anerr += err;
+ }
+ anerr /= (double)asgrey.no;
+
+ if (verb || it >= mxits) {
+ if (it >= mxits)
+ printf("Verification results:\n");
+ printf("Brightness error = %f cd/m^2 (is %f, should be %f)\n",brerr,asgrey.s[asgrey.no-1].XYZ[1],x.twh[1]);
+ printf("White point error = %f deltaE\n",cterr);
+ printf("Maximum neutral error (@ %f) = %f deltaE\n",mnv, mnerr);
+ printf("Average neutral error = %f deltaE\n",anerr);
+ if (it < mxits && thrfail)
+ printf("Failed to meet target %f delta E, got worst case %f\n",errthr,failerr);
+ printf("Number of measurements taken = %d\n",totmeas);
+ }
+ }
+
+ /* Verify loop exit */
+ if (it >= (mxits + nver -1)) {
+ break;
+ }
+
+ /* Convert our test points into calibration curves. */
+ /* The call to reinit_csamp() will then convert the */
+ /* curves back to current test point values. */
+ /* This applies some level of cohesion between the test points, */
+ /* as well as forcing monotomicity */
+ if (it < mxits) {
+ mcvco *sdv[3]; /* Scattered data for mcv */
+
+ for (j = 0; j < 3; j++) {
+ if ((sdv[j] = malloc(sizeof(mcvco) * asgrey.no)) == NULL) {
+ dr->del(dr);
+ error ("Malloc of scattered data points failed");
+ }
+ }
+
+ if (verb)
+ printf("Computing update to calibration curves...\n");
+
+ /* Use fixed rgb's */
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < asgrey.no; i++) {
+ sdv[j][i].p = asgrey.s[i].v;
+ sdv[j][i].v = asgrey.s[i].rgb[j];
+ sdv[j][i].w = 1.0;
+// ~~999
+#ifdef NEVER
+ printf("rdac %d point %d = %f, %f\n",j,i,sdv[j][i].p,sdv[j][i].v);
+#endif
+ }
+ }
+ if (x.nat) /* Make curve go thought white if possible */
+ sdv[0][rsteps-1].w = sdv[1][rsteps-1].w = sdv[2][rsteps-1].w = 10.0;
+
+ for (j = 0; j < 3; j++)
+ x.rdac[j]->fit(x.rdac[j], 0, fitord, sdv[j], asgrey.no, RDAC_SMOOTH);
+
+ /* Make sure that if we are using native brightness and white point, */
+ /* that the curves go to a perfect 1.0 ... */
+ if (x.nat) {
+ for (j = 0; j < 3; j++)
+ x.rdac[j]->force_1(x.rdac[j], 1.0);
+ }
+
+ for (j = 0; j < 3; j++)
+ free(sdv[j]);
+#ifdef DEBUG_PLOT
+ /* Plot the current curves */
+ {
+ #define XRES 255
+ double xx[XRES];
+ double y1[XRES];
+ double y2[XRES];
+ double y3[XRES];
+ double rgb[3];
+ for (i = 0; i < XRES; i++) {
+ double drgb[3], rgb[3];
+ xx[i] = i/(XRES-1.0);
+ rgb[0] = rgb[1] = rgb[2] = xx[i];
+ for (j = 0; j < 3; j++)
+ drgb[j] = x.rdac[j]->interp(x.rdac[j], rgb[j]);
+ y1[i] = drgb[0];
+ y2[i] = drgb[1];
+ y3[i] = drgb[2];
+ }
+ printf("Current ramdac curves\n");
+ do_plot(xx,y1,y2,y3,XRES);
+ #undef XRES
+ }
+#endif
+ }
+ } /* Next refine/verify loop */
+
+ free_alloc_csamp(&asgrey); /* We're done with test points */
+ dr->del(dr); /* Now we're done with test window */
+
+ /* Write out the resulting calibration file */
+ if (verify != 2) {
+ int calres = CAL_RES; /* steps in calibration table saved */
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats_set_elem *setel; /* Array of set value elements */
+ int ncps; /* Number of curve parameters */
+ double *cps[3]; /* Arrays of curve parameters */
+ char *bp = NULL, buf[100]; /* Buffer to sprintf into */
+
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CAL"); /* our special type is Calibration file */
+
+ ocg->add_table(ocg, tt_other, 0); /* Add a table for RAMDAC values */
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Device Calibration Curves",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll dispcal", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL);
+ ocg->add_kword(ocg, 0, "COLOR_REP","RGB", NULL);
+ /* Tell downstream whether they can expect that this calibration */
+ /* will be applied in hardware or not. */
+ ocg->add_kword(ocg, 0, "VIDEO_LUT_CALIBRATION_POSSIBLE",noramdac ? "NO" : "YES", NULL);
+
+ /* Put the target parameters in the CGATS file too */
+ if (dtype != 0) {
+ sprintf(buf,"%c",dtype);
+ ocg->add_kword(ocg, 0, "DEVICE_TYPE", buf, NULL);
+ }
+
+ if (wpx == 0.0 && wpy == 0.0 && temp == 0.0 && tbright == 0.0)
+ ocg->add_kword(ocg, 0, "NATIVE_TARGET_WHITE","", NULL);
+
+ sprintf(buf,"%f %f %f", x.twh[0], x.twh[1], x.twh[2]);
+ ocg->add_kword(ocg, 0, "TARGET_WHITE_XYZ",buf, NULL);
+
+ switch(x.gammat) {
+ case gt_power:
+ if (egamma > 0.0)
+ sprintf(buf,"%f", -egamma);
+ else
+ sprintf(buf,"%f", gamma);
+ break;
+ case gt_Lab:
+ strcpy(buf,"L_STAR");
+ break;
+ case gt_sRGB:
+ strcpy(buf,"sRGB");
+ break;
+ case gt_Rec709:
+ strcpy(buf,"REC709");
+ break;
+ case gt_SMPTE240M:
+ strcpy(buf,"SMPTE240M");
+ break;
+ default:
+ error("Unknown gamma type");
+ }
+ ocg->add_kword(ocg, 0, "TARGET_GAMMA",buf, NULL);
+
+ sprintf(buf,"%f", x.oofff);
+ ocg->add_kword(ocg, 0, "DEGREE_OF_BLACK_OUTPUT_OFFSET",buf, NULL);
+
+ sprintf(buf,"%f", bkcorrect);
+ ocg->add_kword(ocg, 0, "BLACK_POINT_CORRECTION", buf, NULL);
+
+ sprintf(buf,"%f", x.nbrate);
+ ocg->add_kword(ocg, 0, "BLACK_NEUTRAL_BLEND_RATE", buf, NULL);
+
+ if (bkbright > 0.0) {
+ sprintf(buf,"%f", bkbright);
+ ocg->add_kword(ocg, 0, "TARGET_BLACK_BRIGHTNESS",buf, NULL);
+ }
+
+ /* Write rest of setup */
+ switch (quality) {
+ case -3: /* Test value */
+ bp = "ultra low";
+ break;
+ case -2: /* Very low */
+ bp = "very low";
+ break;
+ case -1: /* Low */
+ bp = "low";
+ break;
+ case 0: /* Medum */
+ bp = "medium";
+ break;
+ case 1: /* High */
+ bp = "high";
+ break;
+ case 2: /* Ultra */
+ bp = "ultra high";
+ break;
+ default:
+ error("unknown quality level %d",quality);
+ }
+ ocg->add_kword(ocg, 0, "QUALITY",bp, NULL);
+
+ ocg->add_field(ocg, 0, "RGB_I", r_t);
+ ocg->add_field(ocg, 0, "RGB_R", r_t);
+ ocg->add_field(ocg, 0, "RGB_G", r_t);
+ ocg->add_field(ocg, 0, "RGB_B", r_t);
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * 4)) == NULL)
+ error("Malloc failed!");
+
+ /* Write the video lut curve values */
+ for (i = 0; i < calres; i++) {
+ double vv, rgb[3];
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ vv = i/(calres-1.0);
+ for (j = 0; j < 3; j++) {
+ double cc;
+ cc = x.rdac[j]->interp(x.rdac[j], vv);
+ if (cc < 0.0)
+ cc = 0.0;
+ else if (cc > 1.0)
+ cc = 1.0;
+ rgb[j] = cc;
+ }
+
+ setel[0].d = vv;
+ setel[1].d = rgb[0];
+ setel[2].d = rgb[1];
+ setel[3].d = rgb[2];
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+
+ /* Write some of the device model information to a second */
+ /* table, so that we can update the calibration latter on without */
+ /* having to read R,G & B curves. */
+
+ ocg->add_table(ocg, tt_other, 0); /* Add a second table for setup and model */
+ ocg->add_kword(ocg, 1, "DESCRIPTOR", "Argyll Calibration options and model",NULL);
+ ocg->add_kword(ocg, 1, "ORIGINATOR", "Argyll dispcal", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 1, "CREATED",atm, NULL);
+
+
+ /* Write device model curves */
+ ocg->add_field(ocg, 1, "R_P", r_t);
+ ocg->add_field(ocg, 1, "G_P", r_t);
+ ocg->add_field(ocg, 1, "B_P", r_t);
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * 3)) == NULL)
+ error("Malloc failed!");
+
+ ncps = -1;
+ for (i = 0; i < 3; i++) {
+ int nn;
+ nn = x.dcvs[i]->get_params(x.dcvs[i], &cps[i]);
+ if (ncps != -1 && ncps != nn)
+ error("Expect device model linearisation curves to have the same order");
+ ncps = nn;
+ }
+
+ for (i = 0; i < ncps; i++) {
+ setel[0].d = cps[0][i];
+ setel[1].d = cps[1][i];
+ setel[2].d = cps[2][i];
+ ocg->add_setarr(ocg, 1, setel);
+ }
+
+ for (i = 0; i < 3; i++)
+ free(cps[i]);
+ free(setel);
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ if (verb)
+ printf("Written calibration file '%s'\n",outname);
+
+ ocg->del(ocg); /* Clean up */
+
+ }
+
+ /* Update the ICC file with the new 'vcgt' curves */
+ if (verify != 2 && doupdate && doprofile) {
+ icmFile *ic_fp;
+ icc *icco;
+ int j, i;
+ icmVideoCardGamma *wo;
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object to read profile '%s' failed",iccoutname);
+
+ /* Open up the profile for reading */
+ if ((ic_fp = new_icmFileStd_name(iccoutname,"r")) == NULL)
+ error ("Can't open file '%s'",iccoutname);
+
+ /* Read header etc. */
+ if ((rv = icco->read(icco,ic_fp,0)) != 0)
+ error ("Reading profile '%s' failed with %d, %s",iccoutname, rv,icco->err);
+
+ /* Read every tag */
+ if (icco->read_all_tags(icco) != 0) {
+ error("Unable to read all tags from '%s': %d, %s",iccoutname, icco->errc,icco->err);
+ }
+
+ ic_fp->del(ic_fp);
+
+ wo = (icmVideoCardGamma *)icco->read_tag(icco, icSigVideoCardGammaTag);
+ if (wo == NULL)
+ error("Can't find VideoCardGamma tag in file '%s': %d, %s",
+ iccoutname, icco->errc,icco->err);
+
+ wo->tagType = icmVideoCardGammaTableType;
+ wo->u.table.channels = 3; /* rgb */
+ wo->u.table.entryCount = CAL_RES; /* full lut */
+ wo->u.table.entrySize = 2; /* 16 bits */
+ wo->allocate((icmBase*)wo);
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < CAL_RES; i++) {
+ double cc, vv;
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ vv = i/(CAL_RES-1.0);
+
+ cc = x.rdac[j]->interp(x.rdac[j], vv);
+
+ if (cc < 0.0)
+ cc = 0.0;
+ else if (cc > 1.0)
+ cc = 1.0;
+ ((unsigned short*)wo->u.table.data)[CAL_RES * j + i] = (int)(cc * 65535.0 + 0.5);
+ }
+ }
+
+ /* Open up the profile again writing */
+ if ((ic_fp = new_icmFileStd_name(iccoutname,"w")) == NULL)
+ error ("Can't open file '%s' for writing",iccoutname);
+
+ if ((rv = icco->write(icco,ic_fp,0)) != 0)
+ error ("Write to file '%s' failed: %d, %s",iccoutname, rv,icco->err);
+
+ if (verb)
+ printf("Updated profile '%s'\n",iccoutname);
+
+ ic_fp->del(ic_fp);
+ icco->del(icco);
+
+ /* Create a fast matrix/shaper profile */
+ /*
+ [ Another way of doing this would be to run all the
+ measured points through the calibration curves, and
+ then re-fit the curve/matrix to the calibrated points.
+ This might be more accurate ?]
+
+ Ideally we should also re-measure primaries through calibration
+ rather than computing the calibrated values ?
+
+ */
+
+ } else if (verify != 2 && doprofile) {
+ icmFile *wr_fp;
+ icc *wr_icco;
+ double uwp[3]; /* Absolute Uncalibrated White point in XYZ */
+ double wp[3]; /* Absolute White point in XYZ */
+ double bp[3]; /* Absolute Black point in XYZ */
+ double mat[3][3]; /* Device to XYZ matrix */
+ double calrgb[3]; /* 1.0 through calibration curves */
+ double clrgb[3]; /* 1.0 through calibration and linearization */
+
+ /* Lookup white and black points */
+ {
+ int j;
+ double rgb[3];
+
+ calrgb[0] = calrgb[1] = calrgb[2] = 1.0;
+
+ fwddev(&x, uwp, calrgb); /* absolute uncalibrated WP (native white point) */
+
+//printf("~1 native abs white point XYZ %f %f %f\n", uwp[0], uwp[1], uwp[2]);
+
+ /* RGB 1.0 Through calibration */
+ for (j = 0; j < 3; j++) {
+ calrgb[j] = x.rdac[j]->interp(x.rdac[j], calrgb[j]);
+ if (calrgb[j] < 0.0)
+ calrgb[j] = 0.0;
+ else if (calrgb[j] > 1.0)
+ calrgb[j] = 1.0;
+ }
+ fwddev(&x, wp, calrgb); /* absolute calibrated WP */
+//printf("~1 calibrated rgb = %f %f %f\n", calrgb[0], calrgb[1], calrgb[2]);
+//printf("~1 calibrated abs white point XYZ %f %f %f\n", wp[0], wp[1], wp[2]);
+
+ for (j = 0; j < 3; j++)
+ clrgb[j] = x.dcvs[j]->interp(x.dcvs[j], calrgb[j]);
+//printf("~1 cal & lin rgb = %f %f %f\n", clrgb[0], clrgb[1], clrgb[2]);
+
+ rgb[0] = rgb[1] = rgb[2] = 0.0;
+
+ /* RGB 0.0 through calibration */
+ for (j = 0; j < 3; j++) {
+ rgb[j] = x.rdac[j]->interp(x.rdac[j], rgb[j]);
+ if (rgb[j] < 0.0)
+ rgb[j] = 0.0;
+ else if (rgb[j] > 1.0)
+ rgb[j] = 1.0;
+ }
+ fwddev(&x, bp, rgb); /* Absolute calibrated BP */
+ }
+
+ /* Apply calibration to matrix, and then adjust it to be */
+ /* relative to D50 white point, rather than absolute. */
+ {
+ double rgb[3];
+ icmXYZNumber swp;
+
+ /* Transfer from parameter to matrix */
+ icmCpy3x3(mat, x.fm);
+
+ /* Compute the calibrated matrix values so that the curves */
+ /* device curves end at 1.0. */
+
+ /* In the HW calibrated case this represents the lower XYZ due to */
+ /* the HW calibrated lower RGB values of white compared to the raw */
+ /* model response, so that the calibration curve concatentation with the */
+ /* device curves can be scaled up to end at 1.0. */
+ if (noramdac == 0) {
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ rgb[i] = 0.0;
+ rgb[j] = clrgb[j];
+ icmMulBy3x3(rgb, x.fm, rgb); /* clrgb -> matrix -> RGB */
+ for (i = 0; i < 3; i++)
+ mat[i][j] = rgb[i];
+ }
+#ifdef NEVER
+ {
+ double rgb[3], xyz[3], lab[3];
+
+ rgb[0] = rgb[1] = rgb[2] = 1.0;
+ icmMulBy3x3(xyz, mat, rgb);
+ icmXYZ2Lab(&icmD50, lab, xyz);
+
+ printf("RGB 1 through matrix = XYZ %f %f %f, Lab %f %f %f\n", xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
+ }
+#endif
+ /* Adapt matrix */
+ icmAry2XYZ(swp, wp);
+ icmChromAdaptMatrix(ICM_CAM_MULMATRIX | ICM_CAM_BRADFORD, icmD50, swp, mat);
+#ifdef NEVER
+ {
+ double rgb[3], xyz[3], lab[3];
+
+ rgb[0] = rgb[1] = rgb[2] = 1.0;
+ icmMulBy3x3(xyz, mat, rgb);
+ icmXYZ2Lab(&icmD50, lab, xyz);
+
+ printf("RGB 1 through chrom matrix = XYZ %f %f %f, Lab %f %f %f\n", xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
+ }
+#endif
+
+ /* For the calibration incororated in profile case, we should boost the */
+ /* XYZ by 1/calrgb[] so that the lower calibrated RGB values results in the native */
+ /* white point, but we want to reduce it by callinrgb[] to move from the native */
+ /* white point to the calibrated white point. */
+ } else {
+ icmCpy3x3(mat, x.fm);
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++)
+ rgb[i] = 0.0;
+ rgb[j] = clrgb[j]/calrgb[j];
+ icmMulBy3x3(rgb, x.fm, rgb); /* 1/calrgb -> matrix -> RGB */
+ for (i = 0; i < 3; i++)
+ mat[i][j] = rgb[i];
+ }
+#ifdef NEVER
+ {
+ double rgb[3], xyz[3], lab[3];
+
+ for (j = 0; j < 3; j++)
+ rgb[j] = calrgb[j];
+ icmMulBy3x3(xyz, mat, rgb);
+ icmXYZ2Lab(&icmD50, lab, xyz);
+
+ printf("RGB cal through matrix = XYZ %f %f %f, Lab %f %f %f\n", xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
+ }
+#endif
+ /* Adapt matrix */
+ icmAry2XYZ(swp, wp);
+ icmChromAdaptMatrix(ICM_CAM_MULMATRIX | ICM_CAM_BRADFORD, icmD50, swp, mat);
+#ifdef NEVER
+ {
+ double rgb[3], xyz[3], lab[3];
+
+ icmMulBy3x3(xyz, mat, calrgb);
+ icmXYZ2Lab(&icmD50, lab, xyz);
+
+ printf("RGB cal through chrom matrix = XYZ %f %f %f, Lab %f %f %f\n", xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
+ }
+#endif
+ }
+ }
+
+ /* Open up the file for writing */
+ if ((wr_fp = new_icmFileStd_name(iccoutname,"w")) == NULL)
+ error("Write: Can't open file '%s'",iccoutname);
+
+ if ((wr_icco = new_icc()) == NULL)
+ error("Write: Creation of ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icco->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigDisplayClass;
+ wh->colorSpace = icSigRgbData; /* Display is RGB */
+ wh->pcs = icSigXYZData; /* XYZ for matrix based profile */
+ wh->renderingIntent = icRelativeColorimetric; /* For want of something */
+
+ wh->manufacturer = icmSigUnknownType;
+ wh->model = icmSigUnknownType;
+#ifdef NT
+ wh->platform = icSigMicrosoft;
+#endif
+#ifdef __APPLE__
+ wh->platform = icSigMacintosh;
+#endif
+#if defined(UNIX_X11)
+ wh->platform = icmSig_nix;
+#endif
+ }
+
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst, dstm[200]; /* description */
+
+ if (profDesc != NULL)
+ dst = profDesc;
+ else {
+ dst = iccoutname;
+ }
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt;
+
+ if (copyright != NULL)
+ crt = copyright;
+ else
+ crt = "Copyright, the creator of this profile";
+
+ if ((wo = (icmText *)wr_icco->add_tag(
+ wr_icco, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* Device Manufacturers Description Tag: */
+ if (deviceMfgDesc != NULL) {
+ icmTextDescription *wo;
+ char *dst = deviceMfgDesc;
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigDeviceMfgDescTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Model Description Tag: */
+ if (modelDesc != NULL) {
+ icmTextDescription *wo;
+ char *dst = modelDesc;
+
+ if ((wo = (icmTextDescription *)wr_icco->add_tag(
+ wr_icco, icSigDeviceModelDescTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Luminance tag */
+ {
+ icmXYZArray *wo;;
+
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigLuminanceTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.0;
+ wo->data[0].Y = dispLum * wp[1]/uwp[1]; /* Adjust for effect of calibration */
+ wo->data[0].Z = 0.0;
+
+ if (verb)
+ printf("Luminance XYZ = %f %f %f\n", wo->data[0].X, wo->data[0].Y, wo->data[0].Z);
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = wp[0] * 1.0/wp[1];
+ wo->data[0].Y = wp[1] * 1.0/wp[1];
+ wo->data[0].Z = wp[2] * 1.0/wp[1];
+
+ if (verb)
+ printf("White point XYZ = %f %f %f\n", wo->data[0].X, wo->data[0].Y, wo->data[0].Z);
+ }
+ /* Black Point Tag: */
+ {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigMediaBlackPointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = bp[0] * 1.0/wp[1];
+ wo->data[0].Y = bp[1] * 1.0/wp[1];
+ wo->data[0].Z = bp[2] * 1.0/wp[1];
+
+ if (verb)
+ printf("Black point XYZ = %f %f %f\n", wo->data[0].X, wo->data[0].Y, wo->data[0].Z);
+ }
+
+ /* vcgt tag, if the display has an accessible VideoLUT */
+ if (noramdac == 0) {
+ int j, i;
+ icmVideoCardGamma *wo;
+ wo = (icmVideoCardGamma *)wr_icco->add_tag(wr_icco,
+ icSigVideoCardGammaTag, icSigVideoCardGammaType);
+ if (wo == NULL)
+ error("add_tag failed: %d, %s",wr_icco->errc,wr_icco->err);
+
+ wo->tagType = icmVideoCardGammaTableType;
+ wo->u.table.channels = 3; /* rgb */
+ wo->u.table.entryCount = CAL_RES; /* full lut */
+ wo->u.table.entrySize = 2; /* 16 bits */
+ wo->allocate((icmBase*)wo);
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < CAL_RES; i++) {
+ double cc, vv = i/(CAL_RES-1.0);
+ cc = x.rdac[j]->interp(x.rdac[j], vv);
+ if (cc < 0.0)
+ cc = 0.0;
+ else if (cc > 1.0)
+ cc = 1.0;
+ ((unsigned short*)wo->u.table.data)[CAL_RES * j + i] = (int)(cc * 65535.0 + 0.5);
+ }
+ }
+ }
+
+ /* Red, Green and Blue Colorant Tags: */
+ {
+ icmXYZArray *wor, *wog, *wob;
+ if ((wor = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigRedColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wog = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigGreenColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmXYZArray *)wr_icco->add_tag(
+ wr_icco, icSigBlueColorantTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wor->size = wog->size = wob->size = 1;
+ wor->allocate((icmBase *)wor); /* Allocate space */
+ wog->allocate((icmBase *)wog);
+ wob->allocate((icmBase *)wob);
+
+ wor->data[0].X = mat[0][0]; wor->data[0].Y = mat[1][0]; wor->data[0].Z = mat[2][0];
+ wog->data[0].X = mat[0][1]; wog->data[0].Y = mat[1][1]; wog->data[0].Z = mat[2][1];
+ wob->data[0].X = mat[0][2]; wob->data[0].Y = mat[1][2]; wob->data[0].Z = mat[2][2];
+ }
+
+ /* Red, Green and Blue Tone Reproduction Curve Tags: */
+ {
+ icmCurve *wor, *wog, *wob;
+ int ui;
+
+ if ((wor = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigRedTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wog = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigGreenTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+ if ((wob = (icmCurve *)wr_icco->add_tag(
+ wr_icco, icSigBlueTRCTag, icSigCurveType)) == NULL)
+ error("add_tag failed: %d, %s",rv,wr_icco->err);
+
+ wor->flag = wog->flag = wob->flag = icmCurveSpec;
+ wor->size = wog->size = wob->size = 256; /* Number of entries */
+ wor->allocate((icmBase *)wor); /* Allocate space */
+ wog->allocate((icmBase *)wog);
+ wob->allocate((icmBase *)wob);
+
+ /* For the HW calibrated case, we have lowered the matrix */
+ /* values to reflect the calibrated RGB through the native */
+ /* device model, so now we can scale up the comcatenation */
+ /* of the calibration and linearisation curves so that */
+ /* 1.0 in maps to 1.0 out. */
+ if (noramdac == 0) {
+
+ for (ui = 0; ui < wor->size; ui++) {
+ double in, rgb[3];
+
+ for (j = 0; j < 3; j++) {
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(ui);
+#endif
+ in = (double)ui / (wor->size - 1.0);
+
+ /* Transform through calibration curve */
+ in = x.rdac[j]->interp(x.rdac[j], in);
+
+ if (in < 0.0)
+ in = 0.0;
+ else if (in > 1.0)
+ in = 1.0;
+
+ /* Trandform though device model linearisation */
+ in = x.dcvs[j]->interp(x.dcvs[j], in);
+
+ /* Scale back so that 1.0 in gets 1.0 out */
+ in /= clrgb[j];
+
+
+ if (in < 0.0)
+ in = 0.0;
+ else if (in > 1.0)
+ in = 1.0;
+ rgb[j] = in;
+//printf("Step %d, Chan %d, %f -> %f\n",ui,j,(double)ui / (wor->size - 1.0),in);
+ }
+ wor->data[ui] = rgb[0]; /* Curve values 0.0 - 1.0 */
+ wog->data[ui] = rgb[1];
+ wob->data[ui] = rgb[2];
+ }
+
+ /* For the calibration incororated in profile case, */
+ /* we bypass the inverse calibration curve if it would */
+ /* result in saturation, and then scale the overall output */
+ /* back by the calrgb[] value so that the overall curve */
+ /* maps 1.0 to 1.0. The scaled up values in the matrix */
+ /* then result in a calibrated RGB input mapping to the */
+ /* PCS white point. */
+ } else {
+
+ for (ui = 0; ui < wor->size; ui++) {
+ double in, rgb[3];
+
+ for (j = 0; j < 3; j++) {
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(ui);
+#endif
+ in = (double)ui / (wor->size - 1.0);
+
+ /* If within the inversion range, */
+ /* transform through the inverse calibration curve. */
+ if (in < calrgb[j]) {
+ in = x.rdac[j]->inv_interp(x.rdac[j], in);
+ if (in < 0.0)
+ in = 0.0;
+ else if (in > 1.0)
+ in = 1.0;
+ /* Pass through device model linearisation. */
+ in = x.dcvs[j]->interp(x.dcvs[j], in);
+
+ /* Linearly extrapolate when outside inv range */
+ } else {
+ in /= calrgb[j];
+ }
+
+ /* Scale it back again to 0.0 to 1.0, */
+ /* which is compensated for by matrix scale. */
+ in *= calrgb[j];
+
+ if (in < 0.0)
+ in = 0.0;
+ else if (in > 1.0)
+ in = 1.0;
+ rgb[j] = in;
+//printf("Step %d, Chan %d, %f -> %f\n",ui,j,(double)ui / (wor->size - 1.0),in);
+ }
+ wor->data[ui] = rgb[0]; /* Curve values 0.0 - 1.0 */
+ wog->data[ui] = rgb[1];
+ wob->data[ui] = rgb[2];
+ }
+ }
+ }
+
+ /* Write the file (including all tags) out */
+ if ((rv = wr_icco->write(wr_icco,wr_fp,0)) != 0) {
+ error("Write file: %d, %s",rv,wr_icco->err);
+ }
+
+ if (verb)
+ printf("Created fast shaper/matrix profile '%s'\n",iccoutname);
+
+ /* Close the file */
+ wr_icco->del(wr_icco);
+ wr_fp->del(wr_fp);
+ }
+
+ if (verify != 2) {
+ for (j = 0; j < 3; j++)
+ x.rdac[j]->del(x.rdac[j]);
+
+ for (k = 0; k < 3; k++)
+ x.dcvs[k]->del(x.dcvs[k]);
+ }
+
+ if (x.svc != NULL) {
+ x.svc->del(x.svc);
+ x.svc = NULL;
+ }
+ if (x.dvc != NULL) {
+ x.dvc->del(x.svc);
+ x.dvc = NULL;
+ }
+
+ free_a_disppath(disp);
+
+ return 0;
+}
+
+
diff --git a/spectro/dispread.c b/spectro/dispread.c
new file mode 100644
index 0000000..4a8d364
--- /dev/null
+++ b/spectro/dispread.c
@@ -0,0 +1,969 @@
+/*
+ * Argyll Color Correction System
+ * DTP92/Spectrolino display target reader
+ *
+ * Author: Graeme W. Gill
+ * Date: 4/10/96
+ *
+ * Copyright 1996 - 2013 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.
+ */
+
+/* This program displays test patches, and takes readings from a display device */
+
+/* TTBD
+
+ Add bell at end of readings ?
+
+ Ideally this should be changed to always create non-normalized (absolute)
+ readings, since normalised readings are not natural, but everything
+ that deals with .ti3 data then needs fixing to deal with non-normalized
+ readings !
+ */
+
+#undef DEBUG
+#undef DEBUG_OFFSET /* Keep test window out of the way */
+
+/* Invoke with -dfake for testing with a fake device */
+/* Will use fake.icm/.icc if present */
+
+#define COMPORT 1 /* Default com port 1..4 */
+
+#ifdef __MINGW32__
+# define WINVER 0x0500
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#if defined (NT)
+#include <conio.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "xspect.h"
+#include "ccmx.h"
+#include "ccss.h"
+#include "cgats.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "inst.h"
+#include "dispwin.h"
+#include "dispsup.h"
+#include "sort.h"
+#include "instappsup.h"
+#include "spyd2setup.h" /* Enable Spyder 2 access */
+
+/* ------------------------------------------------------------------- */
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a PPC gcc 3.3 optimiser bug... */
+/* It seems to cause a segmentation fault instead of */
+/* converting an integer loop index into a float, */
+/* when there are sufficient variables in play. */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+/* ------------------------------------------------------------------- */
+
+/*
+
+ Flags used:
+
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ upper .. . .... .. .. ...
+ lower .. . . . . .. .
+
+*/
+
+void usage(char *diag, ...) {
+ int i;
+ disppath **dp;
+ icompaths *icmps;
+ inst2_capability cap2 = inst2_none;
+
+ fprintf(stderr,"Read a Display, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (setup_spyd2() == 2)
+ fprintf(stderr,"WARNING: This file contains a proprietary firmware image, and may not be freely distributed !\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: dispread [options] outfile\n");
+ fprintf(stderr," -v Verbose mode\n");
+#if defined(UNIX_X11)
+ fprintf(stderr," -display displayname Choose X11 display name\n");
+ fprintf(stderr," -d n[,m] Choose the display n from the following list (default 1)\n");
+ fprintf(stderr," Optionally choose different display m for VideoLUT access\n");
+#else
+ fprintf(stderr," -d n Choose the display from the following list (default 1)\n");
+#endif
+ dp = get_displays();
+ if (dp == NULL || dp[0] == NULL)
+ fprintf(stderr," ** No displays found **\n");
+ else {
+ int i;
+ for (i = 0; ; i++) {
+ if (dp[i] == NULL)
+ break;
+ fprintf(stderr," %d = '%s'\n",i+1,dp[i]->description);
+ }
+ }
+ free_disppaths(dp);
+ fprintf(stderr," -dweb[:port] Display via a web server at port (default 8080)\n");
+// fprintf(stderr," -d fake Use a fake display device for testing, fake%s if present\n",ICC_FILE_EXT);
+ fprintf(stderr," -c listno Set communication port from the following list (default %d)\n",COMPORT);
+ if ((icmps = new_icompaths(g_log)) != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ if (paths[i]->itype == instSpyder2 && setup_spyd2() == 0)
+ fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
+ else
+ fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
+ }
+ } else
+ fprintf(stderr," ** No ports found **\n");
+ }
+ fprintf(stderr," -p Use telephoto mode (ie. for a projector) (if available)\n");
+ cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 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");
+ fprintf(stderr," -s Save spectral information (default don't save)\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");
+ fprintf(stderr," ss: 0.5 = half, 1.0 = normal, 2.0 = double etc.\n");
+ fprintf(stderr," -F Fill whole screen with black background\n");
+#if defined(UNIX_X11)
+ fprintf(stderr," -n Don't set override redirect on test window\n");
+#endif
+ fprintf(stderr," -J Run instrument calibration first (used rarely)\n");
+ fprintf(stderr," -N Disable initial calibration of instrument if possible\n");
+ fprintf(stderr," -H Use high resolution spectrum mode (if available)\n");
+// fprintf(stderr," -V Use adaptive measurement mode (if available)\n");
+ fprintf(stderr," -w Disable normalisation of white to Y = 100\n");
+ if (cap2 & inst2_ccmx)
+ fprintf(stderr," -X file.ccmx Apply Colorimeter Correction Matrix\n");
+ if (cap2 & inst2_ccss) {
+ fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n");
+ fprintf(stderr," -Q observ Choose CIE Observer for spectrometer or CCSS colorimeter data:\n");
+ fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2, 1964_10c\n");
+ }
+ fprintf(stderr," -I b|w Drift compensation, Black: -Ib, White: -Iw, Both: -Ibw\n");
+ fprintf(stderr," -Y A Use non-adaptive integration time mode (if available).\n");
+ fprintf(stderr," -C \"command\" Invoke shell \"command\" each time a color is set\n");
+ fprintf(stderr," -M \"command\" Invoke shell \"command\" each time a color is measured\n");
+ fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
+ fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
+ fprintf(stderr," outfile Base name for input[ti1]/output[ti3] file\n");
+ if (icmps != NULL)
+ icmps->del(icmps);
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int i,j;
+ int fa, nfa, mfa; /* current argument we're looking at */
+ disppath *disp = NULL; /* Display being used */
+ double hpatscale = 1.0, vpatscale = 1.0; /* scale factor for test patch size */
+ double ho = 0.0, vo = 0.0; /* Test window offsets, -1.0 to 1.0 */
+ int blackbg = 0; /* NZ if whole screen should be filled with black */
+ int verb = 0;
+ int debug = 0;
+ int fake = 0; /* Use the fake device for testing */
+ int override = 1; /* Override redirect on X11 */
+ int comport = COMPORT; /* COM port used */
+ icompaths *icmps = NULL;
+ icompath *ipath = NULL;
+ flow_control fc = fc_nc; /* Default flow control */
+ int docalib = 0; /* Do a calibration */
+ int highres = 0; /* Use high res mode if available */
+ int nadaptive = 0; /* Use non-adaptive mode if available */
+ int bdrift = 0; /* Flag, nz for black drift compensation */
+ int wdrift = 0; /* Flag, nz for white drift compensation */
+ int dtype = 0; /* Display type selection charater */
+ int tele = 0; /* NZ if telephoto mode */
+ int noautocal = 0; /* Disable auto calibration */
+ int nonorm = 0; /* Disable normalisation */
+ char ccxxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction Matrix name */
+ ccmx *cmx = NULL; /* Colorimeter Correction Matrix */
+ ccss *ccs = NULL; /* Colorimeter Calibration Spectral Samples */
+ int spec = 0; /* Don't save spectral information */
+ icxObserverType obType = icxOT_default;
+ int webdisp = 0; /* NZ for web display, == port number */
+ char *ccallout = NULL; /* Change color Shell callout */
+ char *mcallout = NULL; /* Measure color Shell callout */
+ char inname[MAXNAMEL+1] = "\000"; /* Input cgats file base name */
+ char outname[MAXNAMEL+1] = "\000"; /* Output cgats file base name */
+ char calname[MAXNAMEL+1] = "\000"; /* Calibration file name (if any) */
+ int softcal = 0; /* nz if cal applied to values rather than hardware */
+ double cal[3][MAX_CAL_ENT]; /* Display calibration */
+ int ncal = 256; /* number of cal entries used */
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ col *cols; /* Internal storage of all the patch colors */
+ int dim = 0; /* Dimensionality - 1, 3, or 4 */
+ int npat; /* Number of patches/colors */
+ int xpat = 0; /* Set to number of extra patches */
+ int wpat; /* Set to index of white patch */
+ int si; /* Sample id index */
+ int ti; /* Temp index */
+ int fi; /* Colorspace index */
+ int nsetel = 0;
+ cgats_set_elem *setel; /* Array of set value elements */
+ disprd *dr; /* Display patch read object */
+ int noramdac = 0; /* Will be set to nz if can't set ramdac */
+ int errc; /* Return value from new_disprd() */
+ int rv;
+
+ set_exe_path(argv[0]); /* Set global exe_path and error_program */
+ check_if_not_interactive();
+ setup_spyd2(); /* Load firware if available */
+
+#ifdef DEBUG_OFFSET
+ ho = 0.8;
+ vo = -0.8;
+#endif
+
+#if defined(DEBUG) || defined(DEBUG_OFFSET)
+ printf("!!!!!! Debug turned on !!!!!!\n");
+#endif
+
+ if (argc <= 1)
+ usage("Too few arguments");
+
+ if (ncal > MAX_CAL_ENT)
+ error("Internal, ncal = %d > MAX_CAL_ENT %d\n",ncal,MAX_CAL_ENT);
+
+ /* Process the arguments */
+ mfa = 1; /* Minimum final arguments */
+ for (fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?' || argv[fa][1] == '-') {
+ usage("Usage requested");
+
+ } else if (argv[fa][1] == 'v') {
+ verb = 1;
+ g_log->verb = verb;
+
+ /* Display number */
+ } else if (argv[fa][1] == 'd') {
+ if (strncmp(na,"web",3) == 0
+ || strncmp(na,"WEB",3) == 0) {
+ webdisp = 8080;
+ if (na[3] == ':') {
+ webdisp = atoi(na+4);
+ if (webdisp == 0 || webdisp > 65535)
+ usage("Web port number must be in range 1..65535");
+ }
+ fa = nfa;
+ } else {
+#if defined(UNIX_X11)
+ int ix, iv;
+
+ if (strcmp(&argv[fa][2], "isplay") == 0 || strcmp(&argv[fa][2], "ISPLAY") == 0) {
+ if (++fa >= argc || argv[fa][0] == '-') usage("Parameter expected following -display");
+ setenv("DISPLAY", argv[fa], 1);
+ } else {
+ if (na == NULL) usage("Parameter expected following -d");
+ fa = nfa;
+ if (strcmp(na,"fake") == 0) {
+ fake = 1;
+ } else {
+ if (sscanf(na, "%d,%d",&ix,&iv) != 2) {
+ ix = atoi(na);
+ iv = 0;
+ }
+ if (disp != NULL)
+ free_a_disppath(disp);
+ if ((disp = get_a_display(ix-1)) == NULL)
+ usage("-d parameter %d out of range",ix);
+ if (iv > 0)
+ disp->rscreen = iv-1;
+ }
+ }
+#else
+ int ix;
+ if (na == NULL) usage("Parameter expected following -d");
+ fa = nfa;
+ if (strcmp(na,"fake") == 0) {
+ fake = 1;
+ } else {
+ ix = atoi(na);
+ if (disp != NULL)
+ free_a_disppath(disp);
+ if ((disp = get_a_display(ix-1)) == NULL)
+ usage("-d parameter %d out of range",ix);
+ }
+#endif
+ }
+#if defined(UNIX_X11)
+ } else if (argv[fa][1] == 'n') {
+ override = 0;
+#endif /* UNIX */
+
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -c");
+ comport = atoi(na);
+ if (comport < 1 || comport > 50) usage("-c parameter %d out of range",comport);
+
+ /* Telephoto */
+ } else if (argv[fa][1] == 'p') {
+ tele = 1;
+
+ /* Display type */
+ } else if (argv[fa][1] == 'y') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -y");
+ dtype = na[0];
+
+ /* Calibration file */
+ } else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -k/-K");
+ strncpy(calname,na,MAXNAMEL); calname[MAXNAMEL] = '\000';
+ softcal = 0;
+ if (argv[fa][1] == 'K')
+ softcal = 1;
+ }
+
+ /* Save spectral data */
+ else if (argv[fa][1] == 's') {
+ spec = 1;
+
+ /* Test patch offset and size */
+ } else if (argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -P");
+ if (sscanf(na, " %lf,%lf,%lf,%lf ", &ho, &vo, &hpatscale, &vpatscale) == 4) {
+ ;
+ } else if (sscanf(na, " %lf,%lf,%lf ", &ho, &vo, &hpatscale) == 3) {
+ vpatscale = hpatscale;
+ } else {
+ usage("-P parameter '%s' not recognised",na);
+ }
+ if (ho < 0.0 || ho > 1.0
+ || vo < 0.0 || vo > 1.0
+ || hpatscale <= 0.0 || hpatscale > 50.0
+ || vpatscale <= 0.0 || vpatscale > 50.0)
+ usage("-P parameters %f %f %f %f out of range",ho,vo,hpatscale,vpatscale);
+ ho = 2.0 * ho - 1.0;
+ vo = 2.0 * vo - 1.0;
+
+ /* Black background */
+ } else if (argv[fa][1] == 'F') {
+ blackbg = 1;
+
+ /* Force calibration */
+ } else if (argv[fa][1] == 'J') {
+ docalib = 1;
+
+ /* No auto-cal */
+ } else if (argv[fa][1] == 'N') {
+ noautocal = 1;
+
+ /* High res mode */
+ } else if (argv[fa][1] == 'H') {
+ highres = 1;
+
+ /* Adaptive mode - default, so flag is deprecated */
+ } else if (argv[fa][1] == 'V') {
+ warning("dispread -V flag is deprecated");
+
+ /* No normalisation */
+ } else if (argv[fa][1] == 'w') {
+ nonorm = 1;
+
+ /* Colorimeter Correction Matrix */
+ /* or Colorimeter Calibration Spectral Samples */
+ } else if (argv[fa][1] == 'X') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected following -X");
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+
+ } else if (argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL || na[0] == '\000') usage("Parameter expected after -I");
+ for (i=0; ; i++) {
+ if (na[i] == '\000')
+ break;
+ if (na[i] == 'b' || na[i] == 'B')
+ bdrift = 1;
+ else if (na[i] == 'w' || na[i] == 'W')
+ wdrift = 1;
+ else
+ usage("-I parameter '%c' not recognised",na[i]);
+ }
+
+ /* Spectral Observer type */
+ } else if (argv[fa][1] == 'Q') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expecte after -Q");
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ obType = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ obType = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1964_10c") == 0) { /* 10 degree corrected */
+ obType = icxOT_CIE_1964_10c;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ obType = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ obType = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ obType = icxOT_Shaw_Fairchild_2;
+ } else
+ usage("-Q parameter '%s' not recognised",na);
+
+
+ /* Change color callout */
+ } else if (argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -C");
+ ccallout = na;
+
+ /* Measure color callout */
+ } else if (argv[fa][1] == 'M') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -M");
+ mcallout = na;
+
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -W");
+ if (na[0] == 'n' || na[0] == 'N')
+ fc = fc_none;
+ else if (na[0] == 'h' || na[0] == 'H')
+ fc = fc_Hardware;
+ else if (na[0] == 'x' || na[0] == 'X')
+ fc = fc_XonXOff;
+ else
+ usage("-W parameter '%s' not recognised",na);
+
+ } else if (argv[fa][1] == 'D') {
+ debug = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ debug = atoi(na);
+ fa = nfa;
+ }
+ g_log->debug = debug;
+ callback_ddebug = 1; /* dispwin global */
+
+ /* Extra flags */
+ } else if (argv[fa][1] == 'Y') {
+ if (na == NULL)
+ usage("Flag '-Y' expects extra flag");
+
+ if (na[0] == 'A') {
+ nadaptive = 1;
+ } else {
+ usage("Flag '-Y %c' not recognised",na[0]);
+ }
+
+ } else
+ usage("Flag '-%c' not recognised",argv[fa][1]);
+ }
+ else
+ break;
+ }
+
+ /* No explicit display has been set */
+ if (!fake && disp == NULL) {
+ int ix = 0;
+#if defined(UNIX_X11)
+ char *dn, *pp;
+
+ if ((dn = getenv("DISPLAY")) != NULL) {
+ if ((pp = strrchr(dn, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) != NULL) {
+ if (pp[1] != '\000')
+ ix = atoi(pp+1);
+ }
+ }
+ }
+#endif
+ if ((disp = get_a_display(ix)) == NULL)
+ error("Unable to open the default display");
+ }
+
+ /* See if there is an environment variable ccxx */
+ if (ccxxname[0] == '\000') {
+ char *na;
+ if ((na = getenv("ARGYLL_COLMTER_CAL_SPEC_SET")) != NULL) {
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+
+ } else if ((na = getenv("ARGYLL_COLMTER_COR_MATRIX")) != NULL) {
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+ }
+ }
+
+ /* Load up CCMX or CCSS */
+ if (ccxxname[0] != '\000') {
+ if ((cmx = new_ccmx()) == NULL
+ || cmx->read_ccmx(cmx, ccxxname)) {
+ if (cmx != NULL) {
+ cmx->del(cmx);
+ cmx = NULL;
+ }
+
+ /* CCMX failed, try CCSS */
+ if ((ccs = new_ccss()) == NULL
+ || ccs->read_ccss(ccs, ccxxname)) {
+ if (ccs != NULL) {
+ ccs->del(ccs);
+ ccs = NULL;
+ error("Reading CCMX/CCSS File '%s' failed\n", ccxxname);
+ }
+ }
+ }
+ }
+
+ if (fake)
+ comport = -99;
+ if ((icmps = new_icompaths(g_log)) == NULL)
+ error("Finding instrument paths failed");
+ if ((ipath = icmps->get_path(icmps, comport)) == NULL)
+ error("No instrument at port %d",comport);
+
+ if (docalib) {
+ if ((rv = disprd_calibration(ipath, fc, dtype, 0, tele, nadaptive, noautocal, disp,
+ webdisp, blackbg, override,
+ 100.0 * hpatscale, 100.0 * vpatscale, ho, vo,
+ g_log)) != 0) {
+ error("docalibration failed with return value %d\n",rv);
+ }
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage("Filname parameter not found");
+ strncpy(inname,argv[fa++],MAXNAMEL-4); inname[MAXNAMEL-4] = '\000';
+ strcpy(outname,inname);
+ strcat(inname,".ti1");
+ strcat(outname,".ti3");
+
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI1"); /* our special input type is Calibration Target Information 1 */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file '%s' isn't a CTI1 format file",inname);
+ if (icg->ntables < 1) /* We don't use second table at the moment */
+ error ("Input file '%s' doesn't contain at least one table",inname);
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("Input file '%s' has no sets of data",inname);
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll dispread", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL); /* What sort of device this is */
+
+ if ((ti = icg->find_kword(icg, 0, "SINGLE_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "SINGLE_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "COMP_GREY_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "COMP_GREY_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "MULTI_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "MULTI_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "FULL_SPREAD_PATCHES")) >= 0)
+ ocg->add_kword(ocg, 0, "FULL_SPREAD_PATCHES",icg->t[0].kdata[ti], NULL);
+
+ if (verb) {
+ printf("Number of patches = %d\n",npat);
+ }
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+
+ if ((si = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error ("Input file '%s' doesn't contain field SAMPLE_ID",inname);
+ if (icg->t[0].ftype[si] != nqcs_t)
+ error ("Input file %s' field SAMPLE_ID is wrong type",inname);
+
+ if ((cols = (col *)malloc(sizeof(col) * (npat+1))) == NULL)
+ error("Malloc failed!");
+
+ /* Figure out the color space */
+ if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error ("Input file '%s' doesn't contain keyword COLOR_REP",inname);
+ if (strcmp(icg->t[0].kdata[fi],"RGB") == 0) {
+ int ri, gi, bi;
+ dim = 3;
+ if ((ri = icg->find_field(icg, 0, "RGB_R")) < 0)
+ error ("Input file '%s' doesn't contain field RGB_R",inname);
+ if (icg->t[0].ftype[ri] != r_t)
+ error ("Input file '%s' field RGB_R is wrong type",inname);
+ if ((gi = icg->find_field(icg, 0, "RGB_G")) < 0)
+ error ("Input file '%s' doesn't contain field RGB_G",inname);
+ if (icg->t[0].ftype[gi] != r_t)
+ error ("Input file '%s' field RGB_G is wrong type",inname);
+ if ((bi = icg->find_field(icg, 0, "RGB_B")) < 0)
+ error ("Input file '%s' doesn't contain field RGB_B",inname);
+ if (icg->t[0].ftype[bi] != r_t)
+ error ("Input file '%s' field RGB_B is wrong type",inname);
+ ocg->add_field(ocg, 0, "RGB_R", r_t);
+ ocg->add_field(ocg, 0, "RGB_G", r_t);
+ ocg->add_field(ocg, 0, "RGB_B", r_t);
+ ocg->add_kword(ocg, 0, "COLOR_REP","RGB_XYZ", NULL);
+ ocg->add_field(ocg, 0, "XYZ_X", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Y", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Z", r_t);
+ for (i = 0; i < npat; i++) {
+ cols[i].id = ((char *)icg->t[0].fdata[i][si]);
+ cols[i].r = *((double *)icg->t[0].fdata[i][ri]) / 100.0;
+ cols[i].g = *((double *)icg->t[0].fdata[i][gi]) / 100.0;
+ cols[i].b = *((double *)icg->t[0].fdata[i][bi]) / 100.0;
+ cols[i].XYZ[0] = cols[i].XYZ[1] = cols[i].XYZ[2] = -1.0;
+ }
+ } else
+ error ("Input file '%s' keyword COLOR_REP has illegal value (RGB colorspace expected)",inname);
+
+ /* Check that there is a white patch, and if not, add one, */
+ /* so that we can normalize the values to white. */
+ for (wpat = 0; wpat < npat; wpat++) {
+ if (cols[wpat].r > 0.9999999 &&
+ cols[wpat].g > 0.9999999 &&
+ cols[wpat].b > 0.9999999) {
+ break;
+ }
+ }
+ if (wpat >= npat) { /* Create a white patch */
+ if (verb)
+ printf("Adding one white patch\n");
+ xpat = 1;
+ cols[wpat].r = cols[wpat].g = cols[wpat].b = 1.0;
+ }
+
+ /* Setup a display calibration set if we are given one */
+ /* (Should switch to xcal ?) */
+ if (calname[0] != '\000') {
+ cgats *ccg; /* calibration cgats structure */
+ int ii, ri, gi, bi;
+
+ ccg = new_cgats(); /* Create a CGATS structure */
+ ccg->add_other(ccg, "CAL"); /* our special calibration type */
+
+ if (ccg->read_name(ccg, calname))
+ error("CGATS calibration file read error %s on file '%s'",ccg->err,calname);
+
+ if (ccg->ntables == 0 || ccg->t[0].tt != tt_other || ccg->t[0].oi != 0)
+ error ("Calibration file isn't a CAL format file");
+ if (ccg->ntables < 1)
+ error ("Calibration file '%s' doesn't contain at least one table",calname);
+
+ if ((ncal = ccg->t[0].nsets) <= 0)
+ error ("No data in set of file '%s'",calname);
+
+ if (ncal != 256)
+ error ("Expect 256 data sets in file '%s'",calname);
+ if (ncal > MAX_CAL_ENT)
+ error ("Cant handle %d data sets in file '%s', max is %d",ncal,calname,MAX_CAL_ENT);
+
+ if ((fi = ccg->find_kword(ccg, 0, "DEVICE_CLASS")) < 0)
+ error ("Calibration file '%s' doesn't contain keyword DEVICE_CLASS",calname);
+ if (strcmp(ccg->t[0].kdata[fi],"DISPLAY") != 0)
+ error ("Calibration file '%s' doesn't have DEVICE_CLASS of DISPLAY",calname);
+
+ if ((fi = ccg->find_kword(ccg, 0, "VIDEO_LUT_CALIBRATION_POSSIBLE")) >= 0) {
+ if (stricmp(ccg->t[0].kdata[fi],"NO") == 0) {
+ softcal = 1;
+ if (verb) printf("Switching to soft cal because there is no access to VideoLUTs\n");
+ }
+ }
+
+ if ((fi = ccg->find_kword(ccg, 0, "COLOR_REP")) < 0)
+ error ("Calibration file '%s' doesn't contain keyword COLOR_REP",calname);
+ if (strcmp(ccg->t[0].kdata[fi],"RGB") != 0)
+ error ("Calibration file '%s' doesn't have COLOR_REP of RGB",calname);
+
+ if ((ii = ccg->find_field(ccg, 0, "RGB_I")) < 0)
+ error ("Calibration file '%s' doesn't contain field RGB_I",calname);
+ if (ccg->t[0].ftype[ii] != r_t)
+ error ("Field RGB_R in file '%s' is wrong type",calname);
+ if ((ri = ccg->find_field(ccg, 0, "RGB_R")) < 0)
+ error ("Calibration file '%s' doesn't contain field RGB_R",calname);
+ if (ccg->t[0].ftype[ri] != r_t)
+ error ("Field RGB_R in file '%s' is wrong type",calname);
+ if ((gi = ccg->find_field(ccg, 0, "RGB_G")) < 0)
+ error ("Calibration file '%s' doesn't contain field RGB_G",calname);
+ if (ccg->t[0].ftype[gi] != r_t)
+ error ("Field RGB_G in file '%s' is wrong type",calname);
+ if ((bi = ccg->find_field(ccg, 0, "RGB_B")) < 0)
+ error ("Calibration file '%s' doesn't contain field RGB_B",calname);
+ if (ccg->t[0].ftype[bi] != r_t)
+ error ("Field RGB_B in file '%s' is wrong type",calname);
+ for (i = 0; i < ncal; i++) {
+ cal[0][i] = *((double *)ccg->t[0].fdata[i][ri]);
+ cal[1][i] = *((double *)ccg->t[0].fdata[i][gi]);
+ cal[2][i] = *((double *)ccg->t[0].fdata[i][bi]);
+ }
+ ccg->del(ccg);
+ } else {
+ cal[0][0] = -1.0; /* Not used */
+ }
+
+ if ((dr = new_disprd(&errc, ipath, fc, dtype, 0, tele, nadaptive, noautocal,
+ highres, 0, &noramdac, cal, ncal, softcal, disp, blackbg, override,
+ webdisp, ccallout, mcallout, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo,
+ cmx != NULL ? cmx->matrix : NULL,
+ ccs != NULL ? ccs->samples : NULL, ccs != NULL ? ccs->no_samp : 0,
+ spec, obType, NULL, bdrift, wdrift,
+ "fake" ICC_FILE_EXT, g_log)) == NULL)
+ error("new_disprd failed with '%s'\n",disprd_err(errc));
+
+ if (cmx != NULL)
+ cmx->del(cmx);
+ if (ccs != NULL)
+ ccs->del(ccs);
+
+ /* Test the CRT with all of the test points */
+ if ((rv = dr->read(dr, cols, npat + xpat, 1, npat + xpat, 1, 0, instClamp)) != 0) {
+ dr->del(dr);
+ error("test_crt returned error code %d\n",rv);
+ }
+ /* Note what instrument the chart was read with */
+ if (dr->it != NULL) {
+ int refrmode, cbid;
+ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(dr->it->get_itype(dr->it)) , NULL);
+ dr->get_disptype(dr, &refrmode, &cbid);
+ if (refrmode >= 0)
+ ocg->add_kword(ocg, 0, "DISPLAY_TYPE_REFRESH", refrmode ? "YES" : "NO", NULL);
+ if (cbid != 0) {
+ char buf[100];
+ sprintf(buf, "%d", cbid);
+ ocg->add_kword(ocg, 0, "DISPLAY_TYPE_BASE_ID", buf, NULL);
+ }
+ } else {
+ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", "Fake" , NULL);
+ }
+
+ /* Note if the instrument is natively spectral or not */
+ if (dr->it != NULL) {
+ inst_mode cap;
+ dr->it->capabilities(dr->it, &cap, NULL, NULL);
+
+ if (dr->it != NULL && cap & inst_mode_spectral)
+ ocg->add_kword(ocg, 0, "INSTRUMENT_TYPE_SPECTRAL", "YES" , NULL);
+ else
+ ocg->add_kword(ocg, 0, "INSTRUMENT_TYPE_SPECTRAL", "NO" , NULL);
+ } else {
+ ocg->add_kword(ocg, 0, "INSTRUMENT_TYPE_SPECTRAL", "NO" , NULL);
+ }
+
+ dr->del(dr);
+
+ /* And save the result: */
+
+ /* Convert from absolute XYZ to relative XYZ */
+ if (npat > 0) {
+ double nn;
+
+ /* Make sure there is a copy of the white patch beyond npat, */
+ /* so that it can be left absolute. */
+ if (wpat != npat) {
+ cols[npat].r = cols[npat].g = cols[npat].b = 1.0;
+ cols[npat].XYZ[0] = cols[wpat].XYZ[0];
+ cols[npat].XYZ[1] = cols[wpat].XYZ[1];
+ cols[npat].XYZ[2] = cols[wpat].XYZ[2];
+ cols[npat].XYZ_v = cols[wpat].XYZ_v;
+ wpat = npat;
+ }
+
+ if (nonorm)
+ nn = 1.0;
+ else {
+ if (cols[wpat].XYZ_v == 0)
+ error("XYZ of white patch is not valid!",i);
+
+ nn = 100.0 / cols[wpat].XYZ[1]; /* Normalise Y of white to 100 */
+ }
+
+ for (i = 0; i < npat; i++) {
+
+ if (cols[i].XYZ_v == 0)
+ error("XYZ %d is not valid!",i);
+
+ for (j = 0; j < 3; j++)
+ cols[i].XYZ[j] = nn * cols[i].XYZ[j];
+
+ /* Keep spectral aligned with normalised XYZ */
+ if (cols[i].sp.spec_n > 0) {
+ for (j = 0; j < cols[i].sp.spec_n; j++)
+ cols[i].sp.spec[j] *= nn;
+ }
+ }
+ }
+
+ nsetel += 1; /* For id */
+ nsetel += dim; /* For device values */
+ nsetel += 3; /* For XYZ */
+
+ /* If we have spectral information, output it too */
+ if (npat > 0 && cols[0].sp.spec_n > 0) {
+ char buf[100];
+
+ nsetel += cols[0].sp.spec_n; /* Spectral values */
+ sprintf(buf,"%d", cols[0].sp.spec_n);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+ sprintf(buf,"%f", cols[0].sp.spec_wl_short);
+ ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
+ sprintf(buf,"%f", cols[0].sp.spec_wl_long);
+ ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);
+
+ /* Generate fields for spectral values */
+ for (i = 0; i < cols[0].sp.spec_n; i++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(cols[0].sp.spec_wl_short + ((double)i/(cols[0].sp.spec_n-1.0))
+ * (cols[0].sp.spec_wl_long - cols[0].sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+ ocg->add_field(ocg, 0, buf, r_t);
+ }
+ }
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL)
+ error("Malloc failed!");
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < npat; i++) {
+ int k = 0;
+
+ setel[k++].c = cols[i].id;
+ setel[k++].d = 100.0 * cols[i].r;
+ setel[k++].d = 100.0 * cols[i].g;
+ setel[k++].d = 100.0 * cols[i].b;
+
+ setel[k++].d = cols[i].XYZ[0];
+ setel[k++].d = cols[i].XYZ[1];
+ setel[k++].d = cols[i].XYZ[2];
+
+ for (j = 0; j < cols[i].sp.spec_n; j++) {
+ setel[k++].d = cols[i].sp.spec[j];
+ }
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+
+ /* If we have the absolute brightness of the display, record it */
+ if (cols[wpat].XYZ_v != 0) {
+ char buf[100];
+
+ sprintf(buf,"%f %f %f", cols[wpat].XYZ[0], cols[wpat].XYZ[1], cols[wpat].XYZ[2]);
+ ocg->add_kword(ocg, 0, "LUMINANCE_XYZ_CDM2",buf, NULL);
+ }
+
+ if (nonorm == 0)
+ ocg->add_kword(ocg, 0, "NORMALIZED_TO_Y_100","YES", NULL);
+ else
+ ocg->add_kword(ocg, 0, "NORMALIZED_TO_Y_100","NO", NULL);
+
+ /* Write out the calibration if we have it */
+ if (cal != NULL && cal[0][0] >= 0.0) {
+ ocg->add_other(ocg, "CAL"); /* our special type is Calibration file */
+ ocg->add_table(ocg, tt_other, 1); /* Add another table for RAMDAC values */
+ ocg->add_kword(ocg, 1, "DESCRIPTOR", "Argyll Device Calibration State",NULL);
+ ocg->add_kword(ocg, 1, "ORIGINATOR", "Argyll dispread", NULL);
+ ocg->add_kword(ocg, 1, "CREATED",atm, NULL);
+
+ ocg->add_kword(ocg, 1, "DEVICE_CLASS","DISPLAY", NULL);
+ ocg->add_kword(ocg, 1, "COLOR_REP","RGB", NULL);
+ ocg->add_kword(ocg, 0, "VIDEO_LUT_CALIBRATION_POSSIBLE",noramdac ? "NO" : "YES", NULL);
+
+ ocg->add_field(ocg, 1, "RGB_I", r_t);
+ ocg->add_field(ocg, 1, "RGB_R", r_t);
+ ocg->add_field(ocg, 1, "RGB_G", r_t);
+ ocg->add_field(ocg, 1, "RGB_B", r_t);
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * 4)) == NULL)
+ error("Malloc failed!");
+
+ for (i = 0; i < ncal; i++) {
+ double vv;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ vv = i/(ncal-1.0);
+
+ setel[0].d = vv;
+ setel[1].d = cal[0][i];
+ setel[2].d = cal[1][i];
+ setel[3].d = cal[2][i];
+
+ ocg->add_setarr(ocg, 1, setel);
+ }
+
+ free(setel);
+ }
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ if (verb)
+ printf("Written '%s'\n",outname);
+
+ icmps->del(icmps);
+ free(cols);
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+ free_a_disppath(disp);
+
+ return 0;
+}
+
+
diff --git a/spectro/dispsup.c b/spectro/dispsup.c
new file mode 100644
index 0000000..0dc29ad
--- /dev/null
+++ b/spectro/dispsup.c
@@ -0,0 +1,2343 @@
+
+
+/*
+ * Argyll Color Correction System
+ * Common display patch reading support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2/11/2005
+ *
+ * Copyright 1998 - 2013 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.
+ */
+
+/*
+ TTBD:
+
+ If verb, report white/black drift
+
+ Should add option to ask for a black cal every N readings, for spectro's
+ */
+
+#ifdef __MINGW32__
+# define WINVER 0x0500
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "inst.h"
+#include "spyd2.h"
+#include "dispwin.h"
+#include "dispsup.h"
+#include "webwin.h"
+#include "instappsup.h"
+
+#undef SIMPLE_MODEL /* Make fake device well behaved */
+ /* else has offsets, quantization, noise etc. */
+
+#define DRIFT_IPERIOD 40 /* Number of samples between drift interpolation measurements */
+#define DRIFT_EPERIOD 20 /* Number of samples between drift extrapolation measurements */
+//#define DRIFT_IPERIOD 6 /* Test values */
+//#define DRIFT_EPERIOD 3
+
+#ifdef SIMPLE_MODEL
+# undef FAKE_NOISE /* Add noise to _fake_ devices XYZ */
+# undef FAKE_BITS /* Number of bits of significance of fake device */
+#else
+# define FAKE_NOISE 0.01 /* Add noise to _fake_ devices XYZ */
+# define FAKE_BITS 9 /* Number of bits of significance of fake device */
+#endif
+
+
+/* -------------------------------------------------------- */
+/* A default callback that can be provided as an argument to */
+/* inst_handle_calibrate() to handle the display part of a */
+/* calibration callback. */
+/* Call this again with calc = inst_calc_none to cleanup afterwards. */
+inst_code setup_display_calibrate(
+ inst *p,
+ inst_cal_cond calc, /* Current condition. inst_calc_none for not setup */
+ disp_win_info *dwi /* Information to be able to open a display test patch */
+) {
+ inst_code rv = inst_ok, ev;
+ dispwin *dw; /* Display window to display test patches on, NULL if none. */
+ a1logd(p->log,1,"setup_display_calibrate called\n");
+
+ switch (calc) {
+ case inst_calc_none: /* Use this as a cleanup flag */
+ if (dwi->dw == NULL && dwi->_dw != NULL) {
+ dwi->_dw->del(dwi->_dw);
+ dwi->_dw = NULL;
+ }
+ break;
+
+ case inst_calc_emis_white:
+ if (dwi->dw == NULL) {
+ if (dwi->webdisp != 0) {
+ if ((dwi->_dw = new_webwin(dwi->webdisp, dwi->hpatsize, dwi->vpatsize,
+ dwi->ho, dwi->vo, 0, dwi->blackbg,
+ p->log->verb, p->log->debug)) == NULL) {
+ a1logd(p->log,1,"inst_handle_calibrate failed to create test window 0x%x\n",inst_other_error);
+ return inst_other_error;
+ }
+ } else {
+ if ((dwi->_dw = new_dispwin(dwi->disp, dwi->hpatsize, dwi->vpatsize,
+ dwi->ho, dwi->vo, 0, 0, NULL, dwi->blackbg,
+ dwi->override, p->log->debug)) == NULL) {
+ a1logd(p->log,1,"inst_handle_calibrate failed to create test window 0x%x\n",inst_other_error);
+ return inst_other_error;
+ }
+ }
+ printf("Frequency calibration, Place instrument on test window.\n");
+ printf(" Hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort:");
+ } else {
+ dwi->_dw = dwi->dw;
+ }
+ p->cal_gy_level = 1.0;
+ dwi->_dw->set_color(dwi->_dw, 1.0, 1.0, 1.0);
+ break;
+
+ case inst_calc_emis_grey:
+ case inst_calc_emis_grey_darker:
+ case inst_calc_emis_grey_ligher:
+ if (dwi->dw == NULL) {
+ if (dwi->webdisp != 0) {
+ if ((dwi->_dw = new_webwin(dwi->webdisp, dwi->hpatsize, dwi->vpatsize,
+ dwi->ho, dwi->vo, 0, dwi->blackbg,
+ p->log->verb, p->log->debug)) == NULL) {
+ a1logd(p->log,1,"inst_handle_calibrate failed to create test window 0x%x\n",inst_other_error);
+ return inst_other_error;
+ }
+ } else {
+ if ((dwi->_dw = new_dispwin(dwi->disp, dwi->hpatsize, dwi->vpatsize,
+ dwi->ho, dwi->vo, 0, 0, NULL, dwi->blackbg,
+ dwi->override, p->log->debug)) == NULL) {
+ a1logd(p->log,1,"inst_handle_calibrate failed to create test window 0x%x\n",inst_other_error);
+ return inst_other_error;
+ }
+ }
+ printf("Cell ratio calibration, Place instrument on test window.\n");
+ printf(" Hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort:");
+ } else {
+ dwi->_dw = dwi->dw;
+ }
+ if (calc == inst_calc_emis_grey) {
+ p->cal_gy_level = 0.6;
+ p->cal_gy_count = 0;
+ } else if (calc == inst_calc_emis_grey_darker) {
+ p->cal_gy_level *= 0.7;
+ p->cal_gy_count++;
+ } else if (calc == inst_calc_emis_grey_ligher) {
+ p->cal_gy_level *= 1.4;
+ if (p->cal_gy_level > 1.0)
+ p->cal_gy_level = 1.0;
+ p->cal_gy_count++;
+ }
+ if (p->cal_gy_count > 4) {
+ printf("Cell ratio calibration failed - too many tries at setting grey level.\n");
+ a1logd(p->log,1,"inst_handle_calibrate too many tries at setting grey level 0x%x\n",inst_internal_error);
+ return inst_internal_error;
+ }
+ dwi->_dw->set_color(dwi->_dw, p->cal_gy_level, p->cal_gy_level, p->cal_gy_level);
+ break;
+
+ default:
+ /* Something isn't being handled */
+ a1logd(p->log,1,"inst_handle_calibrate unhandled calc case 0x%x, err 0x%x\n",calc,inst_internal_error);
+ return inst_internal_error;
+ }
+ return inst_ok;
+}
+
+/* -------------------------------------------------------- */
+/* User requested calibration of the display instrument */
+/* Do all available non-deferrable calibrations */
+/* Should add an argument to be able to select type of calibration, */
+/* rather than guessing what the user wants ? */
+int disprd_calibration(
+icompath *ipath, /* Instrument path to open, &icomFakeDevice == fake */
+flow_control fc, /* Serial flow control */
+int dtype, /* Display type selection character */
+int docbid, /* NZ to only allow cbid dtypes */
+int tele, /* NZ for tele mode, falls back to spot mode */
+int nadaptive, /* NZ for non-adaptive mode */
+int noinitcal, /* NZ to disable initial instrument calibration */
+disppath *disp, /* display to calibrate. */
+int webdisp, /* If nz, port number for web display */
+int blackbg, /* NZ if whole screen should be filled with black */
+int override, /* Override_redirect on X11 */
+double hpatsize, /* Size of dispwin */
+double vpatsize,
+double ho, double vo, /* Position of dispwin */
+a1log *log /* Verb, debug & error log */
+) {
+ instType itype = instUnknown;
+ inst *p = NULL;
+ int c;
+ inst_code rv;
+ baud_rate br = baud_19200;
+ disp_win_info dwi;
+ inst_cal_type calt = inst_calt_needed;
+ inst_mode cap;
+ inst2_capability cap2;
+ inst3_capability cap3;
+ inst_mode mode = 0;
+
+ memset((void *)&dwi, 0, sizeof(disp_win_info));
+ dwi.webdisp = webdisp;
+ dwi.disp = disp;
+ dwi.blackbg = blackbg;
+ dwi.override = override;
+ dwi.hpatsize = hpatsize;
+ dwi.vpatsize = vpatsize;
+ dwi.ho = ho;
+ dwi.vo = vo;
+
+ p->log = new_a1log_d(log);
+
+ a1logv(log, 1, "Setting up the instrument\n");
+
+ if ((p = new_inst(ipath, 0, log, DUIH_FUNC_AND_CONTEXT)) == NULL) {
+ a1logd(log, 1, "new_inst failed\n");
+ return -1;
+ }
+
+ /* Establish communications */
+ if ((rv = p->init_coms(p, br, fc, 15.0)) != inst_ok) {
+ a1logd(p->log, 1, "init_coms returned '%s' (%s)\n",
+ p->inst_interp_error(p, rv), p->interp_error(p, rv));
+ p->del(p);
+ return -1;
+ }
+
+ /* Initialise the instrument */
+ if ((rv = p->init_inst(p)) != inst_ok) {
+ a1logd(log,1,"init_inst returned '%s' (%s)\n",
+ p->inst_interp_error(p, rv), p->interp_error(p, rv));
+ p->del(p);
+ return -1;
+ }
+
+ itype = p->get_itype(p); /* Actual type */
+ p->capabilities(p, &cap, &cap2, &cap3);
+
+ if (tele && !IMODETST(cap, inst_mode_emis_tele)) {
+ printf("Want telephoto measurement capability but instrument doesn't support it\n");
+ printf("so falling back to emissive spot mode.\n");
+ tele = 0;
+ }
+
+ /* Set to emission mode to read a display */
+ if (tele)
+ mode = inst_mode_emis_tele;
+ else
+ mode = inst_mode_emis_spot;
+ if (nadaptive)
+ mode |= inst_mode_emis_nonadaptive;
+
+ /* (We're assuming spectral doesn't affect calibration ?) */
+
+ if ((rv = p->set_mode(p, mode)) != inst_ok) {
+ a1logd(log,1,"Set_mode failed with '%s' (%s)\n",
+ p->inst_interp_error(p, rv), p->interp_error(p, rv));
+ return -1;
+ }
+ p->capabilities(p, &cap, &cap2, &cap3);
+
+ /* Set the display type */
+ if (dtype != 0) { /* Given selection character */
+ if (cap2 & inst2_disptype) {
+ int ix;
+ if ((ix = inst_get_disptype_index(p, dtype, docbid)) < 0) {
+ a1logd(log,1,"Display type selection '%c' is not valid for instrument\n",dtype);
+ p->del(p);
+ return -1;
+ }
+
+ if ((rv = p->set_disptype(p, ix)) != inst_ok) {
+ a1logd(log,1,"Setting display type failed failed with '%s' (%s)\n",
+ p->inst_interp_error(p, rv), p->interp_error(p, rv));
+ p->del(p);
+ return -1;
+ }
+ } else
+ printf("Display type ignored - instrument doesn't support display type\n");
+ }
+
+ /* Disable initial calibration of machine if selected */
+ if (noinitcal != 0) {
+ if ((rv = p->get_set_opt(p,inst_opt_noinitcalib, 0)) != inst_ok) {
+ a1logd(log,1,"Setting no-initail calibrate failed with '%s' (%s)\n",
+ p->inst_interp_error(p, rv), p->interp_error(p, rv));
+ printf("Disable initial-calibrate not supported\n");
+ }
+ }
+
+ /* Do the calibration */
+ rv = inst_handle_calibrate(p, inst_calt_available, inst_calc_none, setup_display_calibrate, &dwi);
+ setup_display_calibrate(p,inst_calc_none, &dwi);
+ if (rv == inst_unsupported) {
+ printf("No calibration available for instrument in this mode\n");
+ } else if (rv != inst_ok) { /* Abort or fatal error */
+ printf("Calibrate failed with '%s' (%s)\n",
+ p->inst_interp_error(p, rv), p->interp_error(p, rv));
+ p->del(p);
+ return -1;
+ }
+
+ /* clean up */
+ p->del(p);
+ a1logv(log, 1, "Finished setting up the instrument\n");
+
+ return 0;
+}
+
+/* Take a series of readings from the display - implementation */
+/* Return nz on fail/abort */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 3 = window access failed */
+/* 4 = user hit terminate key */
+/* 5 = system error */
+/* Use disprd_err() to interpret it */
+static int disprd_read_imp(
+ disprd *p,
+ col *cols, /* Array of patch colors to be tested */
+ int npat, /* Number of patches to be tested */
+ int spat, /* Start patch index for "verb", 0 if not used */
+ int tpat, /* Total patch index for "verb", 0 if not used */
+ int acr, /* If nz, do automatic final carriage return */
+ int noinc, /* If nz, don't increment the count */
+ int tc, /* If nz, termination key */
+ instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */
+) {
+ int j, rv;
+ int patch;
+ ipatch val; /* Return value */
+ int ch; /* Character */
+ int cal_type;
+ char id[CALIDLEN];
+ inst2_capability cap2;
+
+ /* Setup the keyboard trigger to return our commands */
+ inst_set_uih(0x0, 0xff, DUIH_TRIG);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
+ inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
+
+ /* Setup user termination character */
+ inst_set_uih(tc, tc, DUIH_TERM);
+
+ p->it->capabilities(p->it, NULL, &cap2, NULL);
+
+ /* See if we should calibrate the display update */
+ if (!p->update_delay_set && (cap2 & inst2_meas_disp_update) != 0) {
+ int cdelay, mdelay;
+
+ /* Set white with a normal delay */
+ if ((rv = p->dw->set_color(p->dw, 1.0, 1.0, 1.0)) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+
+ /* Set a zero delay */
+ cdelay = p->dw->set_update_delay(p->dw, 0);
+
+ /* Set black with zero delay */
+ if ((rv = p->dw->set_color(p->dw, 0.0, 0.0, 0.0)) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+
+ /* Measure the delay */
+ if ((rv = p->it->meas_delay(p->it, &mdelay)) != inst_ok) {
+ a1logd(p->log,1,"warning, measure display update delay failed with '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ p->dw->set_update_delay(p->dw, cdelay); /* Restore the default */
+ } else {
+ a1logv(p->log, 1, "Measured display update delay of %d msec",mdelay);
+ mdelay += mdelay/2 + 50;
+ p->dw->set_update_delay(p->dw, mdelay);
+ a1logv(p->log, 1, ", using delay of %d msec\n",mdelay);
+ }
+ p->update_delay_set = 1;
+ }
+
+ /* See if we should do a frequency calibration or display integration time cal. first */
+ if (p->it->needs_calibration(p->it) & inst_calt_ref_freq
+ && npat > 0
+ && (cols[0].r != 1.0 || cols[0].g != 1.0 || cols[0].b != 1.0)) {
+ col tc;
+ inst_cal_type calt = inst_calt_ref_freq;
+ inst_cal_cond calc = inst_calc_emis_white;
+
+ if ((rv = p->dw->set_color(p->dw, 1.0, 1.0, 1.0)) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+ /* Do calibrate, but ignore return code. Press on regardless. */
+ if ((rv = p->it->calibrate(p->it, &calt, &calc, id)) != inst_ok) {
+ a1logd(p->log,1,"warning, frequency calibrate failed with '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ }
+ }
+
+ /* See if we should do a display integration calibration first */
+ if (p->it->needs_calibration(p->it) & inst_calt_emis_int_time) {
+ col tc;
+ inst_cal_type calt = inst_calt_emis_int_time;
+ inst_cal_cond calc = inst_calc_emis_white;
+
+ if ((rv = p->dw->set_color(p->dw, 1.0, 1.0, 1.0)) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+ /* Do calibrate, but ignore return code. Press on regardless. */
+ if ((rv = p->it->calibrate(p->it, &calt, &calc, id)) != inst_ok) {
+ a1logd(p->log,1,"warning, display integration calibrate failed with '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ }
+ }
+
+ for (patch = 0; patch < npat; patch++) {
+ col *scb = &cols[patch];
+ double rgb[3];
+
+ scb->mtype = inst_mrt_none;
+ scb->XYZ_v = 0; /* No readings are valid */
+ scb->sp.spec_n = 0;
+ scb->duration = 0.0;
+
+ if (spat != 0 && tpat != 0)
+ a1logv(p->log, 1, "%cpatch %d of %d",cr_char,spat + (noinc != 0 ? 0 : patch),tpat);
+ a1logd(p->log,1,"About to read patch %d\n",patch);
+
+ rgb[0] = scb->r;
+ rgb[1] = scb->g;
+ rgb[2] = scb->b;
+
+ /* If we are doing a soft cal, apply it to the test color */
+ if (p->softcal && p->cal[0][0] >= 0.0) {
+ int j;
+ double inputEnt_1 = (double)(p->ncal-1);
+
+ for (j = 0; j < 3; j++) {
+ unsigned int ix;
+ double val, w;
+ val = rgb[j] * inputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ } else if (val > inputEnt_1) {
+ val = inputEnt_1;
+ }
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (p->ncal-2))
+ ix = (p->ncal-2);
+ w = val - (double)ix; /* weight */
+ val = p->cal[j][ix];
+ rgb[j] = val + w * (p->cal[j][ix+1] - val);
+ }
+ }
+ if ((rv = p->dw->set_color(p->dw, rgb[0], rgb[1], rgb[2])) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+
+ /* Until we give up retrying */
+ for (;;) {
+ val.mtype = inst_mrt_none;
+ val.XYZ_v = 0; /* No readings are valid */
+ val.sp.spec_n = 0;
+ val.duration = 0.0;
+
+ if ((rv = p->it->read_sample(p->it, scb->id, &val, 1)) != inst_ok
+ && (rv & inst_mask) != inst_user_trig) {
+ a1logd(p->log,1,"read_sample returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+
+ /* deal with a user terminate or abort */
+ if ((rv & inst_mask) == inst_user_abort) {
+ int keyc = inst_get_uih_char();
+
+ /* Deal with a user terminate */
+ if (keyc & DUIH_TERM) {
+ return 4;
+
+ /* Deal with a user abort */
+ } else if (keyc & DUIH_ABORT) {
+ empty_con_chars();
+ printf("\nSample read stopped at user request!\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ continue;
+ }
+
+ /* Deal with needing calibration */
+ } else if ((rv & inst_mask) == inst_needs_cal) {
+ disp_win_info dwi;
+ dwi.dw = p->dw; /* Set window to use */
+ printf("\nSample read failed because instruments needs calibration\n");
+ rv = inst_handle_calibrate(p->it, inst_calt_needed, inst_calc_none,
+ setup_display_calibrate, &dwi);
+ setup_display_calibrate(p->it, inst_calc_none, &dwi);
+ if (rv != inst_ok) { /* Abort or fatal error */
+ return 1;
+ }
+ continue;
+
+ /* Deal with a bad sensor position */
+ } else if ((rv & inst_mask) == inst_wrong_config) {
+ empty_con_chars();
+ printf("\n\nSpot read failed due to the sensor being in the wrong position\n");
+ printf("(%s)\n",p->it->interp_error(p->it, rv));
+ printf("Correct position then hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ continue;
+
+ /* Deal with a misread */
+ } else if ((rv & inst_mask) == inst_misread) {
+ empty_con_chars();
+ printf("\nSample read failed due to misread\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ continue;
+
+ /* Deal with a communications error */
+ } else if ((rv & inst_mask) == inst_coms_fail) {
+ empty_con_chars();
+ printf("\nSample read failed due to communication problem.\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ if (p->it->icom->port_type(p->it->icom) == icomt_serial) {
+ /* Allow retrying at a lower baud rate */
+ int tt = p->it->last_scomerr(p->it);
+ if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
+ if (p->br == baud_19200) p->br = baud_9600;
+ else if (p->br == baud_9600) p->br = baud_4800;
+ else if (p->br == baud_2400) p->br = baud_1200;
+ else p->br = baud_1200;
+ }
+ if ((rv = p->it->init_coms(p->it, p->br, p->fc, 15.0)) != inst_ok) {
+ a1logd(p->log,1,"init_coms returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+ }
+ continue;
+ }
+ } else {
+ break; /* Sucesful reading */
+ }
+ }
+ /* We only fall through with a valid reading */
+ scb->serno = p->serno++;
+ scb->msec = msec_time();
+
+ a1logd(p->log,1, "got reading %f %f %f, transfering to col\n",
+ val.XYZ[0], val.XYZ[1], val.XYZ[2]);
+
+ scb->mtype = val.mtype;
+
+ /* Copy XYZ */
+ if (val.XYZ_v != 0) {
+ for (j = 0; j < 3; j++)
+ scb->XYZ[j] = val.XYZ[j];
+ scb->XYZ_v = 1;
+ }
+
+ /* Copy spectral */
+ if (p->spectral && val.sp.spec_n > 0) {
+ scb->sp = val.sp;
+ }
+ a1logd(p->log,1,"on to next reading\n");
+ }
+ /* Final return. */
+ if (acr && spat != 0 && tpat != 0 && (spat+patch-1) == tpat)
+ a1logv(p->log, 1, "\n");
+ return 0;
+}
+
+/* A structure to hold info about drift samples */
+typedef struct {
+ col dcols[2]; /* Black and white readings */
+
+ int off, count; /* Offset and count into cols */
+
+} dsamples;
+
+/* Take a series of readings from the display - drift compensation */
+/* Return nz on fail/abort */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 3 = window access failed */
+/* 4 = user hit terminate key */
+/* 5 = system error */
+/* Use disprd_err() to interpret it */
+static int disprd_read_drift(
+ disprd *p,
+ col *cols, /* Array of patch colors to be tested */
+ int npat, /* Number of patches to be tested */
+ int spat, /* Start patch index for "verb", 0 if not used */
+ int tpat, /* Total patch index for "verb", 0 if not used */
+ int acr, /* If nz, do automatic final carriage return */
+ int tc, /* If nz, termination key */
+ instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */
+) {
+ int rv, i, j, e;
+ double fper, foff;
+ int off, poff;
+ int boff, eoff, dno; /* b&w offsets and count */
+
+//printf("~1 DRIFT_EPERIOD %d, DRIFT_IPERIOD %d, npat %d\n",DRIFT_EPERIOD,DRIFT_IPERIOD,npat);
+
+ /* Figure number and offset for b&w */
+ if (p->bdrift == 0) { /* Must be just wdrift */
+ boff = eoff = 1;
+ dno = 1;
+ } else if (p->bdrift == 0) { /* Must be just bdrift */
+ boff = eoff = 0;
+ dno = 1;
+ } else { /* Must be both */
+ boff = eoff = 0;
+ dno = 2;
+ }
+
+ /* If the last drift readings are invalid or too old, */
+ /* or if we will use interpolation, read b&w */
+#ifdef NEVER
+ printf("last_bw_v = %d (%d)\n",p->last_bw_v,p->last_bw_v == 0);
+ printf("npat = %d > %d, serno %d, last serno %d (%d)\n",npat, DRIFT_EPERIOD, p->serno,p->last_bw[eoff].serno,(npat > DRIFT_EPERIOD && p->serno > p->last_bw[eoff].serno));
+ printf("serno - lastserno %d > %d (%d)\n",p->serno - p->last_bw[eoff].serno, DRIFT_EPERIOD,(p->serno - p->last_bw[eoff].serno) > DRIFT_EPERIOD);
+ printf("msec %d - last %d = %d > 10000 (%d)\n",msec_time(),p->last_bw[boff].msec,msec_time() - p->last_bw[boff].msec,(msec_time() - p->last_bw[eoff].msec) > 10000);
+#endif /* NEVER */
+ if (p->last_bw_v == 0 /* There are none */
+ || (npat > DRIFT_EPERIOD && p->serno > p->last_bw[eoff].serno) /* We will interpolate */
+ || (p->serno - p->last_bw[eoff].serno - dno) > DRIFT_EPERIOD /* extrapolate would be too far */
+ || (msec_time() - p->last_bw[eoff].msec) > 10000) { /* The current is too long ago */
+
+//printf("~1 refreshing last bw\n");
+ /* Read the black and/or white drift patch */
+ p->last_bw[0].r =
+ p->last_bw[0].g =
+ p->last_bw[0].b = 0.0;
+ p->last_bw[1].r =
+ p->last_bw[1].g =
+ p->last_bw[1].b = 1.0;
+ if ((rv = disprd_read_imp(p, &p->last_bw[boff], dno, spat, tpat, 0, 1, tc, 0)) != 0) {
+ return rv;
+ }
+ p->last_bw_v = 1;
+
+ /* If there is no reference b&w, set them from this first b&w */
+ if (p->ref_bw_v == 0) {
+ p->ref_bw[0] = p->last_bw[0];
+ p->ref_bw[1] = p->last_bw[1];
+ p->ref_bw_v = 1;
+ }
+ }
+
+ /* If there are enough patches to bracket with drift readings */
+ if (npat > DRIFT_EPERIOD) {
+ int ndrift = 2; /* Number of drift records */
+ dsamples *dss;
+
+ /* Figure out the number of drift samples we need */
+ ndrift += (npat-1)/DRIFT_IPERIOD;
+//printf("~1 spat %d, npat = %d, tpat %d, ndrift = %d\n",spat,npat,tpat,ndrift);
+
+ if ((dss = (dsamples *)calloc(sizeof(dsamples), ndrift)) == NULL) {
+ a1logd(p->log,1, "malloc of %d dsamples failed\n",ndrift);
+ return 5;
+ }
+
+ /* Set up bookeeping */
+ fper = (double)npat/(ndrift-1.0);
+//printf("~1 fper = %f\n",fper);
+ foff = 0.0;
+ for (poff = off = i = 0; i < ndrift; i++) {
+ dss[i].off = off;
+ foff += fper;
+ off = (int)floor(foff + 0.5);
+ if (i < (ndrift-1))
+ dss[i].count = off - poff;
+ else
+ dss[i].count = 0;
+ poff = off;
+//printf("~1 dss[%d] off = %d, count = %d\n",i, dss[i].off,dss[i].count);
+
+ dss[i].dcols[0].r =
+ dss[i].dcols[0].g =
+ dss[i].dcols[0].b = 0.0;
+ dss[i].dcols[1].r =
+ dss[i].dcols[1].g =
+ dss[i].dcols[1].b = 1.0;
+ }
+
+ /* For each batch of patches bracketed by drift patch readings */
+ for (i = 0; i < (ndrift-1); i++) {
+
+ if (i == 0) { /* Already done very first drift patches, so use them */
+ /* Use last b&w */
+ dss[i].dcols[0] = p->last_bw[0];
+ dss[i].dcols[1] = p->last_bw[1];
+ } else {
+ /* Read the black and/or white drift patchs before next batch */
+ if ((rv = disprd_read_imp(p, &dss[i].dcols[boff], dno, spat+dss[i].off, tpat, 0, 1, tc, 0)) != 0) {
+ free(dss);
+ return rv;
+ }
+ }
+ /* Read this batch of patches */
+ if ((rv = disprd_read_imp(p, &cols[dss[i].off], dss[i].count,spat+dss[i].off,tpat,0,0,tc, 0)) != 0) {
+ free(dss);
+ return rv;
+ }
+ }
+ /* Read the black and/or white drift patchs after last batch */
+ if ((rv = disprd_read_imp(p, &dss[i].dcols[boff], dno, spat+dss[i].off-1, tpat, 0, 1, tc, 0)) != 0) {
+ free(dss);
+ return rv;
+ }
+ /* Remember the last for next time */
+ p->last_bw[0] = dss[i].dcols[0];
+ p->last_bw[1] = dss[i].dcols[1];
+ p->last_bw_v = 1;
+
+ /* Set the white drift target to be the last one for batch */
+ p->targ_w = p->last_bw[1];
+ p->targ_w_v = 1;
+
+//printf("~1 ref b = %f %f %f\n", p->ref_bw[0].XYZ[0], p->ref_bw[0].XYZ[1], p->ref_bw[0].XYZ[2]);
+//printf("~1 ref w = %f %f %f\n", p->ref_bw[1].XYZ[0], p->ref_bw[1].XYZ[1], p->ref_bw[1].XYZ[2]);
+//printf("~1 ndrift-1 b = %f %f %f\n", dss[ndrift-1].dcols[0].XYZ[0], dss[ndrift-1].dcols[0].XYZ[1], dss[ndrift-1].dcols[0].XYZ[2]);
+//printf("~1 ndrift-1 w = %f %f %f\n", dss[ndrift-1].dcols[1].XYZ[0], dss[ndrift-1].dcols[1].XYZ[1], dss[ndrift-1].dcols[1].XYZ[2]);
+
+ /* Apply the drift compensation using interpolation */
+ for (i = 0; i < (ndrift-1); i++) {
+
+ for (j = 0; j < dss[i].count; j++) {
+ int k = dss[i].off + j;
+ double we; /* Interpolation weight of eairlier value */
+ col bb, ww; /* Interpolated black and white */
+//double uXYZ[3];
+//icmCpy3(uXYZ, cols[k].XYZ);
+//printf("~1 patch %d = %f %f %f\n", k, cols[k].XYZ[0], cols[k].XYZ[1], cols[k].XYZ[2]);
+ if (p->bdrift) {
+ we = (double)(dss[i+1].dcols[0].msec - cols[k].msec)/
+ (double)(dss[i+1].dcols[0].msec - dss[i].dcols[0].msec);
+
+ if (cols[k].XYZ_v) {
+ for (e = 0; e < 3; e++) {
+ bb.XYZ[e] = we * dss[i].dcols[0].XYZ[e]
+ + (1.0 - we) * dss[i+1].dcols[0].XYZ[e];
+ }
+//printf("~1 bb = %f %f %f\n", bb.XYZ[0], bb.XYZ[1], bb.XYZ[2]);
+ }
+ if (cols[k].sp.spec_n > 0) {
+ for (e = 0; e < cols[k].sp.spec_n; e++) {
+ bb.sp.spec[e] = we * dss[i].dcols[0].sp.spec[e]
+ + (1.0 - we) * dss[i+1].dcols[0].sp.spec[e];
+ }
+ }
+ }
+ if (p->wdrift) {
+ we = (double)(dss[i+1].dcols[1].msec - cols[k].msec)/
+ (double)(dss[i+1].dcols[1].msec - dss[i].dcols[1].msec);
+
+ if (cols[k].XYZ_v) {
+ for (e = 0; e < 3; e++) {
+ ww.XYZ[e] = we * dss[i].dcols[1].XYZ[e]
+ + (1.0 - we) * dss[i+1].dcols[1].XYZ[e];
+ }
+//printf("~1 ww = %f %f %f\n", ww.XYZ[0], ww.XYZ[1], ww.XYZ[2]);
+ }
+ if (cols[k].sp.spec_n > 0) {
+ for (e = 0; e < cols[k].sp.spec_n; e++) {
+ ww.sp.spec[e] = we * dss[i].dcols[1].sp.spec[e]
+ + (1.0 - we) * dss[i+1].dcols[1].sp.spec[e];
+ }
+ }
+ }
+
+ if (p->bdrift) {
+ /* Compensate interpolated black for any white change from ref. */
+ if (p->wdrift) {
+ if (cols[k].XYZ_v) {
+ for (e = 0; e < 3; e++) {
+ bb.XYZ[e] *= p->ref_bw[1].XYZ[e]/ww.XYZ[e];
+ }
+//printf("~1 wcomp bb = %f %f %f\n", bb.XYZ[0], bb.XYZ[1], bb.XYZ[2]);
+ }
+ if (cols[k].sp.spec_n > 0) {
+ for (e = 0; e < cols[k].sp.spec_n; e++) {
+ bb.sp.spec[e] *= p->ref_bw[1].sp.spec[e]/ww.sp.spec[e];
+ }
+ }
+ }
+
+ /* Compensate the reading for any black drift from ref. */
+ if (cols[k].XYZ_v) {
+ for (e = 0; e < 3; e++) {
+ cols[k].XYZ[e] += p->ref_bw[0].XYZ[e] - bb.XYZ[e];
+ }
+//printf("~1 bcomp patch = %f %f %f\n", cols[k].XYZ[0], cols[k].XYZ[1], cols[k].XYZ[2]);
+ }
+ if (cols[k].sp.spec_n > 0) {
+ for (e = 0; e < cols[k].sp.spec_n; e++) {
+ cols[k].sp.spec[e] += p->ref_bw[0].sp.spec[e] - bb.sp.spec[e];
+ }
+ }
+ }
+ /* Compensate the reading for any white drift to target white */
+ if (p->wdrift) {
+ if (cols[k].XYZ_v) {
+ for (e = 0; e < 3; e++) {
+ cols[k].XYZ[e] *= p->targ_w.XYZ[e]/ww.XYZ[e];
+ }
+//printf("~1 wcomp patch = %f %f %f\n", cols[k].XYZ[0], cols[k].XYZ[1], cols[k].XYZ[2]);
+ }
+ if (cols[k].sp.spec_n > 0) {
+ for (e = 0; e < cols[k].sp.spec_n; e++) {
+ cols[k].sp.spec[e] *= p->targ_w.sp.spec[e]/ww.sp.spec[e];
+ }
+ }
+ }
+//printf("~1 %d: drift change %f DE\n",k,icmXYZLabDE(&icmD50, uXYZ, cols[k].XYZ));
+ }
+ }
+ free(dss);
+
+ /* Else too small a batch, use extrapolation from the last b&w */
+ } else {
+
+//printf("~1 doing small number of readings\n");
+ /* Read the small number of patches */
+ if ((rv = disprd_read_imp(p, cols,npat,spat,tpat,acr,0,tc,0)) != 0)
+ return rv;
+
+ if (p->targ_w_v == 0) {
+ /* Set the white drift reference to be the last one */
+ p->targ_w = p->last_bw[1];
+ p->targ_w_v = 1;
+//printf("~1 set white drift target\n");
+ }
+
+//printf("~1 ref b = %f %f %f\n", p->ref_bw[0].XYZ[0], p->ref_bw[0].XYZ[1], p->ref_bw[0].XYZ[2]);
+//printf("~1 ref w = %f %f %f\n", p->ref_bw[1].XYZ[0], p->ref_bw[1].XYZ[1], p->ref_bw[1].XYZ[2]);
+//printf("~1 last b = %f %f %f\n", p->last_bw[0].XYZ[0], p->last_bw[0].XYZ[1], p->last_bw[0].XYZ[2]);
+//printf("~1 last w = %f %f %f\n", p->last_bw[1].XYZ[0], p->last_bw[1].XYZ[1], p->last_bw[1].XYZ[2]);
+//printf("~1 target w = %f %f %f\n", p->targ_w.XYZ[0], p->targ_w.XYZ[1], p->targ_w.XYZ[2]);
+ /* Apply the drift compensation using extrapolation */
+ for (j = 0; j < npat; j++) {
+ double we; /* Interpolation weight of eairlier value */
+ col bb, ww; /* Interpolated black and white */
+
+//printf("~1 patch %d = %f %f %f\n", j, cols[j].XYZ[0], cols[j].XYZ[1], cols[j].XYZ[2]);
+//double uXYZ[3];
+//icmCpy3(uXYZ, cols[j].XYZ);
+
+ if (p->bdrift) {
+ bb = p->last_bw[0];
+//printf("~1 bb = %f %f %f\n", bb.XYZ[0], bb.XYZ[1], bb.XYZ[2]);
+ }
+ if (p->wdrift) {
+ ww = p->last_bw[1];
+//printf("~1 ww = %f %f %f\n", ww.XYZ[0], ww.XYZ[1], ww.XYZ[2]);
+ }
+
+ if (p->bdrift) {
+ /* Compensate interpolated black for any white change from ref. */
+ if (p->wdrift) {
+ if (cols[j].XYZ_v) {
+ for (e = 0; e < 3; e++) {
+ bb.XYZ[e] *= p->ref_bw[1].XYZ[e]/ww.XYZ[e];
+ }
+//printf("~1 wcomp bb = %f %f %f\n", bb.XYZ[0], bb.XYZ[1], bb.XYZ[2]);
+ }
+ if (cols[j].sp.spec_n > 0) {
+ for (e = 0; e < cols[j].sp.spec_n; e++) {
+ bb.sp.spec[e] *= p->ref_bw[1].sp.spec[e]/ww.sp.spec[e];
+ }
+ }
+ }
+
+ /* Compensate the reading for any black drift from ref. */
+ if (cols[j].XYZ_v) {
+ for (e = 0; e < 3; e++) {
+ cols[j].XYZ[e] += p->ref_bw[0].XYZ[e] - bb.XYZ[e];
+ }
+//printf("~1 bcomp patch = %f %f %f\n", cols[j].XYZ[0], cols[j].XYZ[1], cols[j].XYZ[2]);
+ }
+ if (cols[j].sp.spec_n > 0) {
+ for (e = 0; e < cols[j].sp.spec_n; e++) {
+ cols[j].sp.spec[e] += p->ref_bw[0].sp.spec[e] - bb.sp.spec[e];
+ }
+ }
+ }
+ /* Compensate the reading for any white drift to target white */
+ if (p->wdrift) {
+ if (cols[j].XYZ_v) {
+ for (e = 0; e < 3; e++) {
+ cols[j].XYZ[e] *= p->targ_w.XYZ[e]/ww.XYZ[e];
+ }
+//printf("~1 wcomp patch = %f %f %f\n", cols[j].XYZ[0], cols[j].XYZ[1], cols[j].XYZ[2]);
+ }
+ if (cols[j].sp.spec_n > 0) {
+ for (e = 0; e < cols[j].sp.spec_n; e++) {
+ cols[j].sp.spec[e] *= p->targ_w.sp.spec[e]/ww.sp.spec[e];
+ }
+ }
+ }
+//printf("~1 %d: drift change %f DE\n",j,icmXYZLabDE(&icmD50, uXYZ, cols[j].XYZ));
+ }
+ }
+
+ if (acr && spat != 0 && tpat != 0 && (spat+npat-1) == tpat)
+ a1logv(p->log, 1, "\n");
+
+ if (clamp) {
+ for (j = 0; j < npat; j++) {
+ if (cols[j].XYZ_v)
+ icmClamp3(cols[j].XYZ, cols[j].XYZ);
+ }
+ }
+ return rv;
+}
+
+/* Reset the white drift target white value, for non-batch */
+/* readings when white drift comp. is enabled */
+static void disprd_reset_targ_w(disprd *p) {
+ p->targ_w_v = 0;
+}
+
+/* Change the black/white drift compensation options. */
+/* Note that this simply invalidates any reference readings, */
+/* and therefore will not make for good black compensation */
+/* if it is done a long time since the instrument calibration. */
+static void disprd_change_drift_comp(disprd *p,
+ int bdrift, /* Flag, nz for black drift compensation */
+ int wdrift /* Flag, nz for white drift compensation */
+) {
+ if (p->bdrift && !bdrift) { /* Turning black drift off */
+ p->bdrift = 0;
+ p->ref_bw_v = 0;
+ p->last_bw_v = 0;
+ p->targ_w_v = 0;
+
+ } else if (!p->bdrift && bdrift) { /* Turning black drift on */
+ p->bdrift = 1;
+ p->ref_bw_v = 0;
+ p->last_bw_v = 0;
+ p->targ_w_v = 0;
+ }
+
+ if (p->wdrift && !wdrift) { /* Turning white drift off */
+ p->wdrift = 0;
+ p->ref_bw_v = 0;
+ p->last_bw_v = 0;
+ p->targ_w_v = 0;
+
+ } else if (!p->wdrift && wdrift) { /* Turning white drift on */
+ p->wdrift = 1;
+ p->ref_bw_v = 0;
+ p->last_bw_v = 0;
+ p->targ_w_v = 0;
+ }
+}
+
+/* Take a series of readings from the display */
+/* Return nz on fail/abort */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 3 = window access failed */
+/* 4 = user hit terminate key */
+/* 5 = system error */
+/* Use disprd_err() to interpret it */
+static int disprd_read(
+ disprd *p,
+ col *cols, /* Array of patch colors to be tested */
+ int npat, /* Number of patches to be tested */
+ int spat, /* Start patch index for "verb", 0 if not used */
+ int tpat, /* Total patch index for "verb", 0 if not used */
+ int acr, /* If nz, do automatic final carriage return */
+ int tc, /* If nz, termination key */
+ instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */
+) {
+ int rv, i;
+
+ if (p->bdrift || p->wdrift) {
+ if ((rv = disprd_read_drift(p, cols,npat,spat,tpat,acr,tc,clamp)) != 0)
+ return rv;
+ } else {
+ if ((rv = disprd_read_imp(p, cols,npat,spat,tpat,acr,0,tc,clamp)) != 0)
+ return rv;
+ }
+
+ /* Use spectral if available. */
+ /* Since this is a display, assume that this is absolute spectral */
+ if (p->sp2cie != NULL) {
+ for (i = 0; i < npat; i++) {
+ if (cols[i].sp.spec_n > 0) {
+ p->sp2cie->convert(p->sp2cie, cols[i].XYZ, &cols[i].sp);
+ if (clamp)
+ icmClamp3(cols[i].XYZ, cols[i].XYZ);
+ cols[i].XYZ_v = 1;
+ }
+ }
+ }
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Return the refresh mode and cbid */
+static void disprd_get_disptype(disprd *p, int *refrmode, int *cbid) {
+ if (refrmode != NULL)
+ *refrmode = p->refrmode;
+ if (cbid != NULL)
+ *cbid = p->cbid;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static int config_inst_displ(disprd *p);
+
+/* Take an ambient reading if the instrument has the capability. */
+/* return nz on fail/abort */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 4 = user hit terminate key */
+/* 5 = system error */
+/* 8 = no ambient capability */
+/* Use disprd_err() to interpret it */
+int disprd_ambient(
+ struct _disprd *p,
+ double *ambient, /* return ambient in cd/m^2 */
+ int tc /* If nz, termination key */
+) {
+ inst_mode cap = 0;
+ inst2_capability cap2 = 0;
+ inst3_capability cap3 = 0;
+ inst_opt_type trigmode = inst_opt_unknown; /* Chosen trigger mode */
+ int uswitch = 0; /* Instrument switch is enabled */
+ ipatch val;
+ int rv;
+
+ if (p->it != NULL) { /* Not fake */
+ p->it->capabilities(p->it, &cap, &cap2, &cap3);
+ }
+
+ if (!IMODETST(cap, inst_mode_emis_ambient)) {
+ printf("Need ambient measurement capability,\n");
+ printf("but instrument doesn't support it\n");
+ return 8;
+ }
+
+ printf("\nPlease make sure the instrument is fitted with\n");
+ printf("the appropriate ambient light measuring head.\n");
+
+ if ((rv = p->it->set_mode(p->it, inst_mode_emis_ambient)) != inst_ok) {
+ a1logd(p->log,1,"set_mode returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+ if (p->it != NULL) { /* Not fake */
+ p->it->capabilities(p->it, &cap, &cap2, &cap3);
+ }
+
+ /* Select a reasonable trigger mode */
+ if (cap2 & inst2_user_switch_trig) {
+ trigmode = inst_opt_trig_user_switch;
+ uswitch = 1;
+
+ /* Or go for user via uicallback trigger */
+ } else if (cap2 & inst2_user_trig) {
+ trigmode = inst_opt_trig_user;
+
+ /* Or something is wrong with instrument capabilities */
+ } else {
+ printf("No reasonable trigger mode avilable for this instrument\n");
+ return 2;
+ }
+
+ if ((rv = p->it->get_set_opt(p->it, trigmode)) != inst_ok) {
+ printf("\nSetting trigger mode failed with error :'%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+
+ /* Setup the keyboard trigger to return our commands */
+ inst_set_uih(0x0, 0xff, DUIH_TRIG);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
+ inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
+
+ /* Setup user termination character */
+ inst_set_uih(tc, tc, DUIH_TERM);
+
+ /* Until we give up retrying */
+ for (;;) {
+ char ch;
+ val.mtype = inst_mrt_none;
+ val.XYZ_v = 0; /* No readings are valid */
+ val.sp.spec_n = 0;
+ val.duration = 0.0;
+
+ printf("\nPlace the instrument so as to measure ambient upwards, beside the display,\n");
+ if (uswitch)
+ printf("Hit ESC or Q to exit, instrument switch or any other key to take a reading: ");
+ else
+ printf("Hit ESC or Q to exit, any other key to take a reading: ");
+ fflush(stdout);
+
+ if ((rv = p->it->read_sample(p->it, "AMBIENT", &val, 1)) != inst_ok
+ && (rv & inst_mask) != inst_user_trig) {
+ a1logd(p->log,1,"read_sample returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+
+ /* deal with a user terminate or abort */
+ if ((rv & inst_mask) == inst_user_abort) {
+ int keyc = inst_get_uih_char();
+
+ /* Deal with a user terminate */
+ if (keyc & DUIH_TERM) {
+ return 4;
+
+ /* Deal with a user abort */
+ } else if (keyc & DUIH_ABORT) {
+ empty_con_chars();
+ printf("\nMeasure stopped at user request!\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ continue;
+ }
+
+ /* Deal with needs calibration */
+ } else if ((rv & inst_mask) == inst_needs_cal) {
+ disp_win_info dwi;
+ dwi.dw = p->dw; /* Set window to use */
+ printf("\nSample read failed because instruments needs calibration\n");
+ rv = inst_handle_calibrate(p->it, inst_calt_needed, inst_calc_none,
+ setup_display_calibrate, &dwi);
+ setup_display_calibrate(p->it,inst_calc_none, &dwi);
+ if (rv != inst_ok) { /* Abort or fatal error */
+ return 1;
+ }
+ continue;
+
+ /* Deal with a bad sensor position */
+ } else if ((rv & inst_mask) == inst_wrong_config) {
+ empty_con_chars();
+ printf("\n\nSpot read failed due to the sensor being in the wrong position\n");
+ printf("(%s)\n",p->it->interp_error(p->it, rv));
+ printf("Correct position then hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ continue;
+
+ /* Deal with a misread */
+ } else if ((rv & inst_mask) == inst_misread) {
+ empty_con_chars();
+ printf("\nMeasurement failed due to misread\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ continue;
+
+ /* Deal with a communications error */
+ } else if ((rv & inst_mask) == inst_coms_fail) {
+ empty_con_chars();
+ printf("\nMeasurement read failed due to communication problem.\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ if (p->it->icom->port_type(p->it->icom) == icomt_serial) {
+ /* Allow retrying at a lower baud rate */
+ int tt = p->it->last_scomerr(p->it);
+ if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
+ if (p->br == baud_19200) p->br = baud_9600;
+ else if (p->br == baud_9600) p->br = baud_4800;
+ else if (p->br == baud_2400) p->br = baud_1200;
+ else p->br = baud_1200;
+ }
+ if ((rv = p->it->init_coms(p->it, p->br, p->fc, 15.0)) != inst_ok) {
+ a1logd(p->log,1,"init_coms returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+ }
+ continue;
+ }
+ } else {
+ break; /* Sucesful reading */
+ }
+ }
+ /* Convert spectral to XYZ */
+ if (p->sp2cie != NULL && val.sp.spec_n > 0) {
+ p->sp2cie->convert(p->sp2cie, val.XYZ, &val.sp);
+ icmClamp3(val.XYZ, val.XYZ);
+ val.XYZ_v = 1;
+ }
+
+ if (val.XYZ_v == 0) {
+ printf("Unexpected failure to get measurement\n");
+ return 2;
+ }
+
+ a1logd(p->log,1,"Measured ambient of %f\n",val.XYZ[1]);
+ if (ambient != NULL)
+ *ambient = val.XYZ[1];
+
+ /* Configure the instrument mode back to reading the display */
+ if ((rv = config_inst_displ(p)) != 0)
+ return rv;
+
+ printf("\nPlace the instrument back on the test window\n");
+ fflush(stdout);
+
+ return 0;
+}
+
+
+/* Test without a spectrometer using a fake device */
+/* Return nz on fail/abort */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 3 = window access failed */
+/* 4 = user hit terminate key */
+/* 5 = system error */
+/* Use disprd_err() to interpret it */
+static int disprd_fake_read(
+ disprd *p,
+ col *cols, /* Array of patch colors to be tested */
+ int npat, /* Number of patches to be tested */
+ int spat, /* Start patch index for "verb", 0 if not used */
+ int tpat, /* Total patch index for "verb", 0 if not used */
+ int acr, /* If nz, do automatic final carriage return */
+ int tc, /* If nz, termination key */
+ instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */
+) {
+ icmXYZNumber white; /* White point */
+ icmXYZNumber red; /* Red colorant */
+ icmXYZNumber green; /* Green colorant */
+ icmXYZNumber blue; /* Blue colorant */
+ double doff[3]; /* device offsets */
+ double mat[3][3]; /* Destination matrix */
+ double xmat[3][3]; /* Extra matrix */
+ double ooff[3]; /* XYZ offsets */
+ double rgb[3]; /* Given test values */
+ double crgb[3]; /* Calibrated test values */
+// double br = 35.4; /* Overall brightness */
+ double br = 120.0; /* Overall brightness */
+ int patch, j;
+ int ttpat = tpat;
+ inst_code (*uicallback)(void *, inst_ui_purp) = NULL;
+ void *uicontext = NULL;
+
+ if (ttpat < npat)
+ ttpat = npat;
+
+ /* Setup fake device */
+ white.X = br * 0.955; /* Somewhere between D50 and D65 */
+ white.Y = br * 1.00;
+ white.Z = br * 0.97;
+ red.X = br * 0.41;
+ red.Y = br * 0.21;
+ red.Z = br * 0.02;
+ green.X = br * 0.30;
+ green.Y = br * 0.55;
+ green.Z = br * 0.15;
+ blue.X = br * 0.15;
+ blue.Y = br * 0.10;
+ blue.Z = br * 0.97;
+#ifdef SIMPLE_MODEL
+ doff[0] = doff[1] = doff[2] = 0.0; /* Input offset */
+ ooff[0] = ooff[1] = ooff[2] = 0.0; /* Output offset */
+#else
+ /* Input offset, equivalent to RGB offsets having various values */
+ doff[0] = 0.10;
+ doff[1] = 0.06;
+ doff[2] = 0.08;
+ /* Output offset - equivalent to flare [range 0.0 - 1.0] */
+ ooff[0] = 0.03;
+ ooff[1] = 0.04;
+ ooff[2] = 0.09;
+#endif
+
+ if (icmRGBprim2matrix(white, red, green, blue, mat))
+ error("Fake read unexpectedly got singular matrix\n");
+
+ icmSetUnity3x3(xmat);
+
+ if (p->fake2 == 1) {
+ /* Target matrix */
+ xmat[0][0] = 1.0; xmat[0][1] = 0.01; xmat[0][2] = 0.02;
+ xmat[1][0] = 0.1; xmat[1][1] = 1.11; xmat[1][2] = 0.12;
+ xmat[2][0] = 0.2; xmat[2][1] = 0.2; xmat[2][2] = 1.22;
+ }
+
+ uicallback = inst_get_uicallback();
+ uicontext = inst_get_uicontext();
+
+ /* Setup the keyboard trigger to return our commands */
+ inst_set_uih(0x0, 0xff, DUIH_TRIG);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
+ inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
+
+ /* Setup user termination character */
+ inst_set_uih(tc, tc, DUIH_TERM);
+
+ for (patch = 0; patch < npat; patch++) {
+ if (spat != 0 && tpat != 0)
+ a1logv(p->log, 1, "%cpatch %d of %d",cr_char,spat+patch,tpat);
+ crgb[0] = rgb[0] = cols[patch].r;
+ crgb[1] = rgb[1] = cols[patch].g;
+ crgb[2] = rgb[2] = cols[patch].b;
+
+ /* deal with a user terminate or abort */
+ if (uicallback(uicontext, inst_measuring) == inst_user_abort) {
+ int ch, keyc = inst_get_uih_char();
+
+ /* Deal with a user terminate */
+ if (keyc & DUIH_TERM) {
+ return 4;
+
+ /* Deal with a user abort */
+ } else if (keyc & DUIH_ABORT) {
+ empty_con_chars();
+ printf("\nSample read stopped at user request!\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ }
+ }
+
+//printf("~1 patch %d RGB %f %f %f\n",patch,rgb[0], rgb[1], rgb[2]);
+ /* If we have a calibration, apply it to the color */
+ if (p->cal[0][0] >= 0.0) {
+ double inputEnt_1 = (double)(p->ncal-1);
+
+ for (j = 0; j < 3; j++) {
+ unsigned int ix;
+ double val, w;
+ val = rgb[j] * inputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ } else if (val > inputEnt_1) {
+ val = inputEnt_1;
+ }
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (p->ncal-2))
+ ix = (p->ncal-2);
+ w = val - (double)ix; /* weight */
+ val = p->cal[j][ix];
+ crgb[j] = val + w * (p->cal[j][ix+1] - val);
+ }
+//printf("~1 patch %d cal RGB %f %f %f\n",patch, crgb[0], crgb[1], crgb[2]);
+ }
+
+ /* If we have a test window, display the patch color */
+ if (p->dw) {
+ inst_code rv;
+ if (p->softcal) { /* Display value with calibration */
+ if ((rv = p->dw->set_color(p->dw, crgb[0], crgb[1], crgb[2])) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+ } else { /* Hardware will apply calibration */
+ if ((rv = p->dw->set_color(p->dw, rgb[0], rgb[1], rgb[2])) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+ }
+ }
+
+ /* Apply the fake devices level of quantization */
+#ifdef FAKE_BITS
+ if (p->fake2 == 0) {
+ for (j = 0; j < 3; j++) {
+ int vv;
+ vv = (int) (crgb[j] * ((1 << FAKE_BITS) - 1.0) + 0.5);
+ crgb[j] = vv/((1 << FAKE_BITS) - 1.0);
+ }
+ }
+#endif
+
+ /* Apply device offset */
+ for (j = 0; j < 3; j++) {
+ if (crgb[j] < 0.0)
+ crgb[j] = 0.0;
+ else if (crgb[j] > 1.0)
+ crgb[j] = 1.0;
+ crgb[j] = doff[j] + (1.0 - doff[j]) * crgb[j];
+ }
+
+ /* Apply gamma */
+ for (j = 0; j < 3; j++) {
+ if (crgb[j] >= 0.0)
+ crgb[j] = pow(crgb[j], 2.5);
+ else
+ crgb[j] = 0.0;
+ }
+
+ /* Convert to XYZ */
+ icmMulBy3x3(cols[patch].XYZ, mat, crgb);
+
+ /* Apply XYZ offset */
+ for (j = 0; j < 3; j++)
+ cols[patch].XYZ[j] += ooff[j];
+
+ /* Apply extra matrix */
+ icmMulBy3x3(cols[patch].XYZ, xmat, cols[patch].XYZ);
+
+#ifdef FAKE_NOISE
+ if (p->fake2 == 0) {
+ cols[patch].XYZ[0] += 2.0 * FAKE_NOISE * d_rand(-1.0, 1.0);
+ cols[patch].XYZ[1] += FAKE_NOISE * d_rand(-1.0, 1.0);
+ cols[patch].XYZ[2] += 4.0 * FAKE_NOISE * d_rand(-1.0, 1.0);
+ }
+#endif
+ if (clamp)
+ icmClamp3(cols[patch].XYZ, cols[patch].XYZ);
+//printf("~1 patch %d XYZ %f %f %f\n",patch,cols[patch].XYZ[0], cols[patch].XYZ[1], cols[patch].XYZ[2]);
+ cols[patch].XYZ_v = 1;
+ cols[patch].sp.spec_n = 0;
+ cols[patch].mtype = inst_mrt_emission;
+ }
+ if (acr && spat != 0 && tpat != 0 && (spat+patch-1) == tpat)
+ a1logv(p->log, 1, "\n");
+ return 0;
+}
+
+/* Test without a spectrometer using a fake ICC profile device */
+/* Return nz on fail/abort */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 3 = window access failed */
+/* 4 = user hit terminate key */
+/* 5 = system error */
+/* Use disprd_err() to interpret it */
+static int disprd_fake_read_lu(
+ disprd *p,
+ col *cols, /* Array of patch colors to be tested */
+ int npat, /* Number of patches to be tested */
+ int spat, /* Start patch index for "verb", 0 if not used */
+ int tpat, /* Total patch index for "verb", 0 if not used */
+ int acr, /* If nz, do automatic final carriage return */
+ int tc, /* If nz, termination key */
+ instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */
+) {
+ int patch, j;
+ int ttpat = tpat;
+ double br = 120.4; /* Overall brightness */
+ inst_code (*uicallback)(void *, inst_ui_purp) = NULL;
+ void *uicontext = NULL;
+
+ if (ttpat < npat)
+ ttpat = npat;
+
+ uicallback = inst_get_uicallback();
+ uicontext = inst_get_uicontext();
+
+ /* Setup the keyboard trigger to return our commands */
+ inst_set_uih(0x0, 0xff, DUIH_TRIG);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
+ inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
+
+ /* Setup user termination character */
+ inst_set_uih(tc, tc, DUIH_TERM);
+
+ for (patch = 0; patch < npat; patch++) {
+ double rgb[3];;
+ if (spat != 0 && tpat != 0)
+ a1logv(p->log, 1, "%cpatch %d of %d",cr_char,spat+patch,tpat);
+ rgb[0] = cols[patch].r;
+ rgb[1] = cols[patch].g;
+ rgb[2] = cols[patch].b;
+
+ /* deal with a user terminate or abort */
+ if (uicallback(uicontext, inst_measuring) == inst_user_abort) {
+ int ch, keyc = inst_get_uih_char();
+
+ /* Deal with a user terminate */
+ if (keyc & DUIH_TERM) {
+ return 4;
+
+ /* Deal with a user abort */
+ } else if (keyc & DUIH_ABORT) {
+ empty_con_chars();
+ printf("\nSample read stopped at user request!\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ }
+ }
+
+ /* If we have a test window, display the patch color */
+ if (p->dw) {
+ inst_code rv;
+ if ((rv = p->dw->set_color(p->dw, rgb[0], rgb[1], rgb[2])) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+ }
+
+ /* If we have a RAMDAC, apply it to the color */
+ if (p->cal[0][0] >= 0.0) {
+ double inputEnt_1 = (double)(p->ncal-1);
+
+ for (j = 0; j < 3; j++) {
+ unsigned int ix;
+ double val, w;
+
+ val = rgb[j] * inputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ } else if (val > inputEnt_1) {
+ val = inputEnt_1;
+ }
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (p->ncal-2))
+ ix = (p->ncal-2);
+ w = val - (double)ix; /* weight */
+ val = p->cal[j][ix];
+ rgb[j] = val + w * (p->cal[j][ix+1] - val);
+ }
+ }
+
+ p->fake_lu->lookup(p->fake_lu, cols[patch].XYZ, rgb);
+ for (j = 0; j < 3; j++)
+ cols[patch].XYZ[j] *= br;
+#ifdef FAKE_NOISE
+ cols[patch].XYZ[0] += 2.0 * FAKE_NOISE * d_rand(-1.0, 1.0);
+ cols[patch].XYZ[1] += FAKE_NOISE * d_rand(-1.0, 1.0);
+ cols[patch].XYZ[2] += 4.0 * FAKE_NOISE * d_rand(-1.0, 1.0);
+#endif
+ if (clamp)
+ icmClamp3(cols[patch].XYZ, cols[patch].XYZ);
+ cols[patch].XYZ_v = 1;
+ cols[patch].sp.spec_n = 0;
+ cols[patch].mtype = inst_mrt_emission;
+ }
+ if (acr && spat != 0 && tpat != 0 && (spat+patch-1) == tpat)
+ a1logv(p->log, 1, "\n");
+ return 0;
+}
+
+/* Use without a direct connect spectrometer using shell callout */
+/* Return nz on fail/abort */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 3 = window access failed */
+/* 4 = user hit terminate key */
+/* 5 = system error */
+/* Use disprd_err() to interpret it */
+static int disprd_fake_read_co(disprd *p,
+ col *cols, /* Array of patch colors to be tested */
+ int npat, /* Number of patches to be tested */
+ int spat, /* Start patch index for "verb", 0 if not used */
+ int tpat, /* Total patch index for "verb", 0 if not used */
+ int acr, /* If nz, do automatic final carriage return */
+ int tc, /* If nz, termination key */
+ instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */
+) {
+ int patch, j;
+ int ttpat = tpat;
+ inst_code (*uicallback)(void *, inst_ui_purp) = NULL;
+ void *uicontext = NULL;
+
+ if (ttpat < npat)
+ ttpat = npat;
+
+ uicallback = inst_get_uicallback();
+ uicontext = inst_get_uicontext();
+
+ /* Setup the keyboard trigger to return our commands */
+ inst_set_uih(0x0, 0xff, DUIH_TRIG);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
+ inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
+
+ /* Setup user termination character */
+ inst_set_uih(tc, tc, DUIH_TERM);
+
+ for (patch = 0; patch < npat; patch++) {
+ double rgb[3];
+ int rv;
+ char *cmd;
+ FILE *fp;
+
+ /* deal with a user terminate or abort */
+ if (uicallback(uicontext, inst_measuring) == inst_user_abort) {
+ int ch, keyc = inst_get_uih_char();
+
+ /* Deal with a user terminate */
+ if (keyc & DUIH_TERM) {
+ return 4;
+
+ /* Deal with a user abort */
+ } else if (keyc & DUIH_ABORT) {
+ empty_con_chars();
+ printf("\nSample read stopped at user request!\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ return 1;
+ }
+ printf("\n");
+ }
+ }
+
+ if (spat != 0 && tpat != 0)
+ a1logv(p->log, 1, "%cpatch %d of %d",cr_char,spat+patch,tpat);
+ rgb[0] = cols[patch].r;
+ rgb[1] = cols[patch].g;
+ rgb[2] = cols[patch].b;
+
+ /* If we have a test window, display the patch color */
+ if (p->dw) {
+ inst_code rv;
+ if ((rv = p->dw->set_color(p->dw, rgb[0], rgb[1], rgb[2])) != 0) {
+ a1logd(p->log,1,"set_color() returned %s\n",rv);
+ return 3;
+ }
+ }
+
+ /* If we have a RAMDAC, apply it to the color */
+ if (p->cal[0][0] >= 0.0) {
+ double inputEnt_1 = (double)(p->ncal-1);
+
+ for (j = 0; j < 3; j++) {
+ unsigned int ix;
+ double val, w;
+
+ val = rgb[j] * inputEnt_1;
+ if (val < 0.0) {
+ val = 0.0;
+ } else if (val > inputEnt_1) {
+ val = inputEnt_1;
+ }
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (p->ncal-2))
+ ix = (p->ncal-2);
+ w = val - (double)ix; /* weight */
+ val = p->cal[j][ix];
+ rgb[j] = val + w * (p->cal[j][ix+1] - val);
+ }
+ }
+
+ if ((cmd = malloc(strlen(p->mcallout) + 200)) == NULL)
+ error("Malloc of command string failed");
+
+ sprintf(cmd, "%s %d %d %d %f %f %f",p->mcallout,
+ (int)(rgb[0] * 255.0 + 0.5),
+ (int)(rgb[1] * 255.0 + 0.5),
+ (int)(rgb[2] * 255.0 + 0.5), rgb[0], rgb[1], rgb[2]);
+ if ((rv = system(cmd)) != 0)
+ error("System command '%s' failed with %d",cmd,rv);
+
+ /* Now read the XYZ result from the mcallout.meas file */
+ sprintf(cmd, "%s.meas",p->mcallout);
+ if ((fp = fopen(cmd,"r")) == NULL)
+ error("Unable to open measurement value file '%s'",cmd);
+
+ if (fscanf(fp, " %lf %lf %lf", &cols[patch].XYZ[0], &cols[patch].XYZ[1],
+ &cols[patch].XYZ[2]) != 3)
+ error("Unable to parse measurement value file '%s'",cmd);
+ fclose(fp);
+ free(cmd);
+
+ if (clamp)
+ icmClamp3(cols[patch].XYZ, cols[patch].XYZ);
+ cols[patch].XYZ_v = 1;
+ cols[patch].mtype = inst_mrt_emission;
+
+ a1logv(p->log, 2, "Read XYZ %f %f %f from '%s'\n", cols[patch].XYZ[0],
+ cols[patch].XYZ[1],cols[patch].XYZ[2], cmd);
+
+ }
+ if (acr && spat != 0 && tpat != 0 && (spat+patch-1) == tpat)
+ a1logv(p->log, 1, "\n");
+ return 0;
+}
+
+/* Return a string describing the error code */
+char *disprd_err(int en) {
+ switch(en) {
+ case 1:
+ return "User Aborted";
+ case 2:
+ return "Instrument Access Failed";
+ case 22:
+ return "Instrument Access Failed (No PLD Pattern - have you run spyd2en ?)";
+ case 3:
+ return "Window Access Failed";
+ case 4:
+ return "VideoLUT Access Failed";
+ case 5:
+ return "User Terminated";
+ case 6:
+ return "System Error";
+ case 7:
+ return "Either CRT or LCD must be selected";
+ case 8:
+ return "Instrument has no ambient measurement capability";
+ case 9:
+ return "Creating spectral conversion object failed";
+ case 10:
+ return "Instrument has no CCMX capability";
+ case 11:
+ return "Instrument has no CCSS capability";
+ case 12:
+ return "Internal: trying to set calibration when not using calibration";
+ }
+ return "Unknown";
+}
+
+static void disprd_del(disprd *p) {
+
+ if (p->log->verb >= 1 && p->bdrift && p->ref_bw_v && p->last_bw_v) {
+ icmXYZNumber w;
+ double de;
+ icmAry2XYZ(w, p->ref_bw[1].XYZ);
+ de = icmXYZLabDE(&w, p->ref_bw[0].XYZ, p->last_bw[0].XYZ);
+ a1logv(p->log, 1, "Black drift was %f DE\n",de);
+ }
+ if (p->log->verb >= 1 && p->wdrift && p->ref_bw_v && p->last_bw_v) {
+ icmXYZNumber w;
+ double de;
+ icmAry2XYZ(w, p->ref_bw[1].XYZ);
+ de = icmXYZLabDE(&w, p->ref_bw[1].XYZ, p->last_bw[1].XYZ);
+ a1logv(p->log, 1, "White drift was %f DE\n",de);
+ }
+
+ /* The user may remove the instrument */
+ if (p->dw != NULL)
+ printf("The instrument can be removed from the screen.\n");
+
+ if (p->fake_lu != NULL)
+ p->fake_lu->del(p->fake_lu);
+ if (p->fake_icc != NULL)
+ p->fake_icc->del(p->fake_icc);
+ if (p->fake_fp != NULL)
+ p->fake_fp->del(p->fake_fp);
+
+ if (p->it != NULL)
+ p->it->del(p->it);
+ if (p->dw != NULL) {
+ if (p->or != NULL)
+ p->dw->set_ramdac(p->dw,p->or, 0);
+ p->dw->del(p->dw);
+ }
+ if (p->sp2cie != NULL)
+ p->sp2cie->del(p->sp2cie);
+ p->log = del_a1log(p->log);
+ free(p);
+}
+
+/* Helper to configure the instrument mode ready */
+/* for reading the display */
+/* return new_disprd() error code */
+static int config_inst_displ(disprd *p) {
+ inst_mode cap;
+ inst2_capability cap2;
+ inst3_capability cap3;
+ inst_mode mode = 0;
+ int rv;
+
+ p->it->capabilities(p->it, &cap, &cap2, &cap3);
+
+ if (p->tele && !IMODETST(cap, inst_mode_emis_tele)) {
+ printf("Want telephoto measurement capability but instrument doesn't support it\n");
+ printf("so falling back to spot mode.\n");
+ a1logd(p->log,1,"No telephoto mode so falling back to spot mode.\n");
+ p->tele = 0;
+ }
+
+ if (( p->tele && !IMODETST(cap, inst_mode_emis_tele))
+ || (!p->tele && !IMODETST(cap, inst_mode_emis_spot))) {
+ printf("Need %s emissive measurement capability,\n", p->tele ? "telephoto" : "spot");
+ printf("but instrument doesn't support it\n");
+ a1logd(p->log,1,"Need %s emissive measurement capability but device doesn't support it,\n",
+ p->tele ? "telephoto" : "spot");
+ return 2;
+ }
+
+ if (p->nadaptive && !IMODETST(cap, inst_mode_emis_nonadaptive)) {
+ printf("Need non-adaptives measurement mode, but instrument doesn't support it\n");
+ a1logd(p->log,1, "Need non-adaptives measurement mode, but instrument doesn't support it\n");
+ return 2;
+ }
+
+ if (p->obType != icxOT_none
+ && p->obType != icxOT_default) {
+ if (!IMODETST(cap, inst_mode_spectral) && (cap2 & inst2_ccss) == 0) {
+ printf("A non-standard observer was requested,\n");
+ printf("but instrument doesn't support spectral or CCSS\n");
+ a1logd(p->log,1,"A non-standard observer was requested,\n"
+ "but instrument doesn't support spectral or CCSS\n");
+ return 2;
+ }
+ /* Make sure spectral is turned on if an observer is requested */
+ if (!p->spectral && (cap2 & inst2_ccss) == 0)
+ p->spectral = 1;
+ }
+
+ if (p->spectral && !IMODETST(cap,inst_mode_spectral)) {
+ if (p->spectral != 2) { /* Not soft */
+ printf("Spectral information was requested,\n");
+ printf("but instrument doesn't support it\n");
+ a1logd(p->log,1,"Spectral information was requested,\nbut instrument doesn't support it\n");
+ return 2;
+ }
+ p->spectral = 0;
+ }
+
+ if (p->tele) {
+ mode = inst_mode_emis_tele;
+ } else {
+ mode = inst_mode_emis_spot;
+ }
+ if (p->nadaptive)
+ mode |= inst_mode_emis_nonadaptive;
+
+ if (p->spectral) {
+ mode |= inst_mode_spectral;
+ p->spectral = 1;
+ } else {
+ p->spectral = 0;
+ }
+
+ /* Set the display type */
+
+ if (p->dtype != 0) {
+ if (cap2 & inst2_disptype) {
+ int ix;
+ if ((ix = inst_get_disptype_index(p->it, p->dtype, p->docbid)) < 0) {
+ a1logd(p->log,1,"Display type selection '%c' is not valid for instrument\n",p->dtype);
+ return 2;
+ }
+ if ((rv = p->it->set_disptype(p->it, ix)) != inst_ok) {
+ a1logd(p->log,1,"Setting display type failed failed with '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+ } else
+ printf("Display type ignored - instrument doesn't support display type\n");
+ }
+
+ /* Get the refresh mode and cbid */
+ if (cap2 & inst2_disptype) {
+ p->it->get_set_opt(p->it, inst_opt_get_dtinfo, &p->refrmode, &p->cbid);
+ }
+
+ /* Disable initcalibration of machine if selected */
+ if (p->noinitcal != 0) {
+ if ((rv = p->it->get_set_opt(p->it,inst_opt_noinitcalib, 0)) != inst_ok) {
+ a1logd(p->log,1,"Setting no-initial calibrate failed failed with '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ printf("Disable initial-calibrate not supported\n");
+ }
+ }
+
+ if (p->highres) {
+ if (IMODETST(cap, inst_mode_highres)) {
+ inst_code ev;
+ if ((ev = p->it->get_set_opt(p->it, inst_opt_highres)) != inst_ok) {
+ a1logd(p->log,1,"\nSetting high res mode failed with error :'%s' (%s)\n",
+ p->it->inst_interp_error(p->it, ev), p->it->interp_error(p->it, ev));
+ return 2;
+ }
+ } else {
+ a1logv(p->log, 1, "high resolution ignored - instrument doesn't support high res. mode\n");
+ }
+ }
+ if ((rv = p->it->set_mode(p->it, mode)) != inst_ok) {
+ a1logd(p->log,1,"set_mode returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+ p->it->capabilities(p->it, &cap, &cap2, &cap3);
+
+ if (p->ccmtx != NULL) {
+ if ((cap2 & inst2_ccmx) == 0) {
+ a1logd(p->log,1,"Instrument doesn't support ccmx correction\n");
+ return 10;
+ }
+ if ((rv = p->it->col_cor_mat(p->it, p->ccmtx)) != inst_ok) {
+ a1logd(p->log,1,"col_cor_mat returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+ }
+
+ if (p->sets != NULL
+ || ((cap2 & inst2_ccss) != 0 && p->obType != icxOT_default)) {
+
+ if ((cap2 & inst2_ccss) == 0) {
+ a1logd(p->log,1,"Instrument doesn't support ccss calibration\n");
+ return 11;
+ }
+ if ((rv = p->it->get_set_opt(p->it, inst_opt_set_ccss_obs, p->obType, p->custObserver))
+ != inst_ok) {
+ a1logd(p->log,1,"inst_opt_set_ccss_obs returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+ if ((rv = p->it->col_cal_spec_set(p->it, p->sets, p->no_sets)) != inst_ok) {
+ a1logd(p->log,1,"col_cal_spec_set returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+ }
+
+ /* Set the trigger mode to program triggered */
+ if ((rv = p->it->get_set_opt(p->it,inst_opt_trig_prog)) != inst_ok) {
+ a1logd(p->log,1,"Setting program trigger mode failed failed with '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ return 2;
+ }
+
+ /* Reset key meanings */
+ inst_reset_uih();
+
+ a1logd(p->log,1,"config_inst_displ suceeded\n");
+ return 0;
+}
+
+/* Create a display reading object. */
+/* Return NULL if error */
+/* Set *errc to code: */
+/* 0 = no error */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 22 = instrument access failed - no PLD pattern */
+/* 3 = window access failed */
+/* 4 = RAMDAC access failed */
+/* 5 = user hit terminate key */
+/* 6 = system error */
+/* 7 = CRT or LCD must be selected */
+/* 9 = spectral conversion failed */
+/* 10 = no ccmx support */
+/* 11 = no ccss support */
+/* 12 = cal to set but native != 0 */
+/* Use disprd_err() to interpret *errc */
+disprd *new_disprd(
+int *errc, /* Error code. May be NULL (could use log for this instead?) */
+icompath *ipath, /* Instrument path to open, &icomFakeDevice == fake */
+flow_control fc, /* Flow control */
+int dtype, /* Display type selection character */
+int docbid, /* NZ to only allow cbid dtypes */
+int tele, /* NZ for tele mode. Falls back to display mode */
+int nadaptive, /* NZ for non-adaptive mode */
+int noinitcal, /* No initial instrument calibration */
+int highres, /* Use high res mode if available */
+int native, /* 0 = use current current or given calibration curve */
+ /* 1 = use native linear out & high precision */
+int *noramdac, /* Return nz if no ramdac access. native is set to 0 */
+double cal[3][MAX_CAL_ENT], /* Calibration set/return (cal[0][0] < 0.0 or NULL if not used) */
+ /* native must be 0 if cal is set */
+int ncal, /* Number of cal[] entries */
+int softcal, /* NZ if apply cal to readings rather than hardware */
+disppath *disp, /* Display to calibrate. NULL if fake and no dispwin */
+int blackbg, /* NZ if whole screen should be filled with black */
+int override, /* Override_redirect on X11 */
+int webdisp, /* If nz, port number for web color display */
+char *ccallout, /* Shell callout on set color */
+char *mcallout, /* Shell callout on measure color (forced fake) */
+double hpatsize, /* Size of dispwin */
+double vpatsize,
+double ho, /* Horizontal offset */
+double vo, /* Vertical offset */
+double ccmtx[3][3], /* Colorimeter Correction matrix, NULL if none */
+xspect *sets, /* CCSS Set of sample spectra, NULL if none */
+int no_sets, /* CCSS Number on set, 0 if none */
+int spectral, /* Generate spectral info flag */
+icxObserverType obType, /* Use alternate observer if spectral or CCSS and != icxOT_none */
+xspect custObserver[3], /* Optional custom observer */
+int bdrift, /* Flag, nz for black drift compensation */
+int wdrift, /* Flag, nz for white drift compensation */
+char *fake_name, /* Name of profile to use as a fake device */
+a1log *log /* Verb, debug & error log */
+) {
+ disprd *p = NULL;
+ int ch;
+ inst_code rv;
+
+ if (errc != NULL) *errc = 0; /* default return code = no error */
+
+ if (cal != NULL && cal[0][0] >= 0.0 && native != 0) {
+ if (errc != NULL) *errc = 12;
+ return NULL;
+ }
+
+ /* Allocate a disprd */
+ if ((p = (disprd *)calloc(sizeof(disprd), 1)) == NULL) {
+ a1logd(log, 1, "new_disprd failed due to malloc failure\n");
+ if (errc != NULL) *errc = 6;
+ return NULL;
+ }
+ p->log = new_a1log_d(log);
+ p->del = disprd_del;
+ p->read = disprd_read;
+ p->get_disptype = disprd_get_disptype;
+ p->reset_targ_w = disprd_reset_targ_w;
+ p->change_drift_comp = disprd_change_drift_comp;
+ p->ambient = disprd_ambient;
+ p->fake_name = fake_name;
+
+ p->ccmtx = ccmtx;
+ p->sets = sets;
+ p->no_sets = no_sets; /* CCSS */
+ p->spectral = spectral;
+ p->obType = obType; /* CCSS or spectral */
+ p->custObserver = custObserver;
+ p->bdrift = bdrift;
+ p->wdrift = wdrift;
+ p->dtype = dtype;
+ p->docbid = docbid;
+ p->refrmode = -1; /* Unknown */
+ p->cbid = 0; /* Unknown */
+ p->tele = tele;
+ p->nadaptive = nadaptive;
+ p->noinitcal = noinitcal;
+ p->highres = highres;
+ if (mcallout != NULL)
+ ipath = &icomFakeDevice; /* Force fake device */
+ p->mcallout = mcallout;
+ p->ipath = ipath;
+ p->br = baud_19200;
+ p->fc = fc;
+
+ /* Save this in case we are using a fake device */
+ if (cal != NULL && cal[0][0] >= 0.0) {
+ int j, i;
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < ncal; i++) {
+ p->cal[j][i] = cal[j][i];
+ }
+ }
+ p->ncal = ncal;
+ p->softcal = softcal;
+ } else {
+ p->cal[0][0] = -1.0;
+ p->ncal = 0;
+ p->softcal = 0;
+ }
+
+ /* If non-real instrument */
+ if (ipath == &icomFakeDevice) {
+ p->fake = 1;
+
+ p->fake_fp = NULL;
+ p->fake_icc = NULL;
+ p->fake_lu = NULL;
+
+ /* See if there is a profile we should use as the fake device */
+ if (p->mcallout == NULL && p->fake_name != NULL
+ && (p->fake_fp = new_icmFileStd_name(p->fake_name,"r")) != NULL) {
+ if ((p->fake_icc = new_icc()) != NULL) {
+ if (p->fake_icc->read(p->fake_icc,p->fake_fp,0) == 0) {
+ icColorSpaceSignature ins;
+ p->fake_lu = p->fake_icc->get_luobj(p->fake_icc, icmFwd, icAbsoluteColorimetric,
+ icSigXYZData, icmLuOrdNorm);
+ p->fake_lu->spaces(p->fake_lu, &ins, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (ins != icSigRgbData) {
+ p->fake_lu->del(p->fake_lu);
+ p->fake_lu = NULL;
+ }
+ }
+ }
+ }
+
+ if (p->fake_lu != NULL) {
+ a1logv(p->log, 1, "Using profile '%s' rather than real device\n",p->fake_name);
+ p->read = disprd_fake_read_lu;
+ } else if (p->mcallout != NULL) {
+ a1logv(p->log, 1, "Using shell callout '%s' rather than real device\n",p->mcallout);
+ p->read = disprd_fake_read_co;
+ } else
+ p->read = disprd_fake_read;
+
+ if (disp == NULL) {
+ a1logd(log,1,"new_disprd returning fake device\n");
+ return p;
+ }
+
+ /* Setup the instrument */
+ } else {
+
+ a1logv(p->log, 1, "Setting up the instrument\n");
+
+ if ((p->it = new_inst(ipath, 0, log, DUIH_FUNC_AND_CONTEXT)) == NULL) {
+ a1logd(p->log,1,"new_disprd failed because new_inst failed\n");
+ p->del(p);
+ if (errc != NULL) *errc = 2;
+ return NULL;
+ }
+
+ /* Establish communications */
+ if ((rv = p->it->init_coms(p->it, p->br, p->fc, 15.0)) != inst_ok) {
+ a1logd(log,1,"init_coms returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ a1logd(log,1,"new_disprd failed because init_coms failed\n");
+ p->del(p);
+ if (errc != NULL) *errc = 2;
+ return NULL;
+ }
+
+ /* Initialise the instrument */
+ if ((rv = p->it->init_inst(p->it)) != inst_ok) {
+ a1logd(log,1,"init_inst returned '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ a1logd(log,1,"new_disprd failed because init_inst failed\n");
+ p->del(p);
+ if (errc != NULL) {
+ *errc = 2;
+ if ((rv & inst_imask) == SPYD2_NO_PLD_PATTERN)
+ *errc = 22;
+ }
+ return NULL;
+ }
+
+ /* Configure the instrument mode for reading the display */
+ if ((rv = config_inst_displ(p)) != 0) {
+ a1logd(log,1,"new_disprd failed because config_inst_displ failed\n");
+ p->del(p);
+ if (errc != NULL) *errc = rv;
+ return NULL;
+ }
+ }
+
+ /* Create a spectral conversion object if needed */
+ if (p->spectral && p->obType != icxOT_none) {
+ if ((p->sp2cie = new_xsp2cie(icxIT_none, NULL, p->obType, custObserver, icSigXYZData, icxNoClamp))
+ == NULL) {
+ a1logd(log,1,"new_disprd failed because creation of spectral conversion object failed\n");
+ p->del(p);
+ if (errc != NULL) *errc = 9;
+ return NULL;
+ }
+ }
+
+ if (webdisp != 0) {
+ /* Open web display */
+ if ((p->dw = new_webwin(webdisp, hpatsize, vpatsize, ho, vo, 0, 0,
+ p->log->verb, p->log->debug)) == NULL) {
+ a1logd(log,1,"new_disprd failed because new_webwin failed\n");
+ p->del(p);
+ if (errc != NULL) *errc = 3;
+ return NULL;
+ }
+ if (noramdac != NULL)
+ *noramdac = 1;
+ } else {
+ /* Open display window for positioning (no blackbg) */
+ if ((p->dw = new_dispwin(disp, hpatsize, vpatsize, ho, vo, 0, native, noramdac, 0,
+ override, p->log->debug)) == NULL) {
+ a1logd(log,1,"new_disprd failed because new_dispwin failed\n");
+ p->del(p);
+ if (errc != NULL) *errc = 3;
+ return NULL;
+ }
+ }
+
+ if (p->it != NULL) {
+ /* Do a calibration up front, so as not to get in the users way, */
+ /* but ignore a CRT frequency or display integration calibration, */
+ /* since these will be done automatically. */
+ if (p->it->needs_calibration(p->it) & inst_calt_n_dfrble_mask) {
+ disp_win_info dwi;
+ dwi.dw = p->dw; /* Set window to use */
+
+ rv = inst_handle_calibrate(p->it, inst_calt_needed, inst_calc_none,
+ setup_display_calibrate, &dwi);
+ setup_display_calibrate(p->it,inst_calc_none, &dwi);
+ printf("\n");
+ if (rv != inst_ok) { /* Abort or fatal error */
+ a1logd(log,1,"new_disprd failed because calibrate failed with '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ printf("Calibrate failed with '%s' (%s)\n",
+ p->it->inst_interp_error(p->it, rv), p->it->interp_error(p->it, rv));
+ p->del(p);
+ if (errc != NULL) *errc = 2;
+ return NULL;
+ }
+ }
+ }
+
+ /* Ask user to put instrument on screen */
+ empty_con_chars();
+ printf("Place instrument on test window.\n");
+ printf("Hit Esc or Q to give up, any other key to continue:"); fflush(stdout);
+ if ((ch = next_con_char()) == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ a1logd(log,1,"new_disprd failed because user aborted when placing device\n");
+ p->del(p);
+ if (errc != NULL) *errc = 1;
+ return NULL;
+ }
+ printf("\n");
+
+ if (webdisp == 0) {
+ /* Close the positioning window */
+ if (p->dw != NULL) {
+ if (p->or != NULL)
+ p->dw->set_ramdac(p->dw,p->or, 0);
+ p->dw->del(p->dw);
+ }
+
+ /* Open display window again for measurement */
+ if ((p->dw = new_dispwin(disp, hpatsize, vpatsize, ho, vo, 0, native, noramdac, blackbg,
+ override, p->log->debug)) == NULL) {
+ a1logd(log,1,"new_disprd failed new_dispwin failed\n");
+ p->del(p);
+ if (errc != NULL) *errc = 3;
+ return NULL;
+ }
+ }
+
+ /* Set color change callout */
+ if (ccallout) {
+ p->dw->set_callout(p->dw, ccallout);
+ }
+
+ /* If we have a calibration to set */
+ /* (This is only typically the case for disread) */
+ if (!p->softcal && cal != NULL && cal[0][0] >= 0.0) {
+
+ /* Save current RAMDAC so that we can restore it */
+ p->or = NULL;
+ if ((p->or = p->dw->get_ramdac(p->dw)) == NULL) {
+ warning("Unable to read or set display RAMDAC - switching to softcal");
+ p->softcal = softcal = 1;
+ }
+
+ /* Set the given RAMDAC so we can characterise through it */
+ if (p->or != NULL) {
+ ramdac *r;
+ int j, i;
+
+ r = p->or->clone(p->or);
+
+ /* Set the ramdac contents. */
+ /* We linearly interpolate from cal[ncal] to RAMDAC[nent] resolution */
+ for (i = 0; i < r->nent; i++) {
+ double val, w;
+ unsigned int ix;
+
+ val = (ncal-1.0) * i/(r->nent-1.0);
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (ncal-2))
+ ix = (ncal-2);
+ w = val - (double)ix; /* weight */
+ for (j = 0; j < 3; j++) {
+ val = cal[j][ix];
+ r->v[j][i] = val + w * (cal[j][ix+1] - val);
+ }
+ }
+ if (p->dw->set_ramdac(p->dw, r, 0)) {
+ a1logd(log,1,"new_disprd failed becayse set_ramdac failed\n");
+ a1logv(p->log, 1, "Failed to set RAMDAC to desired calibration.\n");
+ a1logv(p->log, 1, "Perhaps the operating system is being fussy ?\n");
+ r->del(r);
+ p->del(p);
+ if (errc != NULL) *errc = 4;
+ return NULL;
+ }
+ r->del(r);
+ }
+ }
+
+ /* Return the ramdac being used */
+ if (p->or != NULL && cal != NULL) {
+ ramdac *r;
+ int j, i;
+
+ if ((r = p->dw->get_ramdac(p->dw)) == NULL) {
+ a1logd(log,1,"new_disprd failed becayse get_ramdac failed\n");
+ a1logv(p->log, 1, "Failed to read current RAMDAC\n");
+ p->del(p);
+ if (errc != NULL) *errc = 4;
+ return NULL;
+ }
+ /* Get the ramdac contents. */
+ /* We linearly interpolate from RAMDAC[nent] to cal[ncal] resolution */
+ for (i = 0; i < ncal; i++) {
+ double val, w;
+ unsigned int ix;
+
+ val = (r->nent-1.0) * i/(ncal-1.0);
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (r->nent-2))
+ ix = (r->nent-2);
+ w = val - (double)ix; /* weight */
+ for (j = 0; j < 3; j++) {
+ val = r->v[j][ix];
+ cal[j][i] = val + w * (r->v[j][ix+1] - val);
+ }
+ }
+ r->del(r);
+ }
+
+ a1logd(log,1,"new_disprd succeeded\n");
+ return p;
+}
+
diff --git a/spectro/dispsup.h b/spectro/dispsup.h
new file mode 100644
index 0000000..837e16a
--- /dev/null
+++ b/spectro/dispsup.h
@@ -0,0 +1,247 @@
+
+#ifndef DISPSUP_H
+
+/*
+ * Argyll Color Correction System
+ * Common display patch reading support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2/11/2005
+ *
+ * Copyright 1998 - 2013 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.
+ */
+
+/* A helper function to handle presenting a display test patch */
+struct _disp_win_info {
+ int webdisp; /* nz if web display is to be used */
+ disppath *disp; /* display to calibrate. */
+ int blackbg; /* NZ if whole screen should be filled with black */
+ int override; /* Override_redirect on X11 */
+ double hpatsize; /* Size of dispwin */
+ double vpatsize; /* Size of dispwin */
+ double ho, vo; /* Position of dispwin */
+ dispwin *dw; /* Display window if already open */
+ dispwin *_dw; /* Privare window if not already open */
+}; typedef struct _disp_win_info disp_win_info;
+
+/* A defauult callback that can be provided as an argument to */
+/* inst_handle_calibrate() to handle the display part of a */
+/* calibration callback. */
+/* Call this again with calc = inst_calc_none to cleanup afterwards. */
+inst_code setup_display_calibrate(
+ inst *p,
+ inst_cal_cond calc, /* Current condition. inst_calc_none for not setup */
+ disp_win_info *dwi /* Information to be able to open a display test patch */
+);
+
+/* User requested calibration of the display instrument */
+int disprd_calibration(
+icompath *ipath, /* Instrument path to open, &icomFakeDevice == fake */
+flow_control fc, /* Serial flow control */
+int dtype, /* Display type, 0 = unknown, 1 = CRT, 2 = LCD */
+int docbid, /* NZ to only allow cbid dtypes */
+int tele, /* NZ for tele mode */
+int nadaptive, /* NZ for non-adaptive mode */
+int noinitcal, /* NZ to disable initial instrument calibration */
+disppath *screen, /* Screen to calibrate. */
+int webdisp, /* If nz, port number for web display */
+int blackbg, /* NZ if whole screen should be filled with black */
+int override, /* Override_redirect on X11 */
+double hpatsize, /* Size of dispwin */
+double vpatsize,
+double ho, double vo, /* Position of dispwin */
+a1log *log /* Verb, debug & error log */
+);
+
+
+/* A color structure to return values with. */
+/* This can hold all representations simultaniously */
+typedef struct {
+ double r,g,b;
+ char *id; /* Id string */
+
+ inst_meas_type mtype; /* Measurement type */
+
+ int XYZ_v;
+ double XYZ[3]; /* Colorimeter readings */
+
+ xspect sp; /* Spectrum. sp.spec_n > 0 if valid */
+
+ double duration; /* Total duration in seconds (flash measurement) */
+
+ int serno; /* Reading serial number */
+ unsigned int msec; /* Timestamp */
+} col;
+
+
+/* Maximum number of entries to setup for calibration */
+#define MAX_CAL_ENT 4096
+
+/* Display reading context */
+struct _disprd {
+
+/* private: */
+ a1log *log; /* Verb, debug & error log */
+ int fake; /* Fake display/instrument flag */
+ int fake2; /* Flag to apply extra matrix to fake response */
+ char *fake_name; /* Fake profile name */
+ icmFile *fake_fp;
+ icc *fake_icc; /* NZ if ICC profile is being used for fake */
+ double cal[3][MAX_CAL_ENT]; /* Calibration being worked through (cal[0][0] < 0.0 or NULL if not used) */
+ int ncal; /* Number of entries used in cal[] */
+ int softcal; /* NZ if apply cal to readings rather than hardware */
+ icmLuBase *fake_lu;
+ char *mcallout; /* fake instrument shell callout */
+ icompath *ipath; /* Instrument path to open, &icomFakeDevice == fake */
+ baud_rate br;
+ flow_control fc;
+ inst *it; /* Instrument */
+ int dtype; /* Display type, 0 = unknown, 1 = CRT, 2 = LCD */
+ int docbid; /* NZ to only allow cbid dtypes */
+ int refrmode; /* Refresh display mode, -1 if unknow, 0 = if no, 1 if yes */
+ int cbid; /* The Calibration Base display mode ID, 0 if unknown */
+ int tele; /* NZ for tele mode */
+ int nadaptive; /* NZ for non-adaptive mode */
+ int highres; /* Use high res mode if available */
+ int update_delay_set; /* NZ if we've calibrated the disp. update delay, or tried and failed */
+ double (*ccmtx)[3]; /* Colorimeter Correction Matrix, NULL if none */
+ icxObserverType obType; /* CCSS Observer */
+ xspect *custObserver; /* CCSS Optional custom observer */
+ xspect *sets; /* CCSS Set of sample spectra, NULL if none */
+ int no_sets; /* CCSS Number on set, 0 if none */
+ int spectral; /* 1 = Generate spectral info flag, 2 = don't print error if not capable */
+ icxObserverType observ; /* Compute XYZ from spectral if spectral and != icxOT_none */
+ xsp2cie *sp2cie; /* Spectral to XYZ conversion */
+ int bdrift; /* Flag, nz for black drift compensation */
+ int wdrift; /* Flag, nz for white drift compensation */
+ int noinitcal; /* No initial instrument calibration */
+ dispwin *dw; /* Window */
+ ramdac *or; /* Original ramdac if we set one */
+
+ int serno; /* Reading serial number */
+ col ref_bw[2]; /* Reference black and white readings for drift comp. */
+ int ref_bw_v; /* Reference valid flag */
+ col last_bw[2]; /* Last black and white readings for drift comp. */
+ int last_bw_v; /* Last valid flag */
+ col targ_w; /* Target white to normalise to. last_bw[1] for batch, first white for */
+ /* non-batch, but latter can be reset. */
+ int targ_w_v; /* target_w valid flag */
+
+/* public: */
+
+ /* Destroy ourselves */
+ void (*del)(struct _disprd *p);
+
+ /* Take a series of readings from the display */
+ /* return nz on fail/abort */
+ /* 1 = user aborted */
+ /* 2 = instrument access failed */
+ /* 3 = window access failed */
+ /* 4 = user hit terminate key */
+ /* 5 = system error */
+ int (*read)(struct _disprd *p,
+ col *cols, /* Array of patch colors to be tested */
+ int npat, /* Number of patches to be tested */
+ int spat, /* Start patch index for "verb", 0 if not used */
+ int tpat, /* Total patch index for "verb", 0 if not used */
+ int acr, /* If nz, do automatic final carriage return */
+ int tc, /* If nz, termination key */
+ instClamping clamp /* NZ if clamp XYZ/Lab to be +ve */
+ );
+
+ /* Return the display type information */
+ void (*get_disptype)(struct _disprd *p, int *refrmode, int *cbid);
+
+ /* Reset the white drift target white value, for non-batch */
+ /* readings when white drift comp. is enabled */
+ void (*reset_targ_w)(struct _disprd *p);
+
+ /* Change the black/white drift compensation options */
+ /* Note that this simply invalidates any reference readings, */
+ /* and therefore will not make for good black compensation */
+ /* if it is done a long time since the instrument calibration. */
+ void (*change_drift_comp)(struct _disprd *p,
+ int bdrift, /* Flag, nz for black drift compensation */
+ int wdrift /* Flag, nz for white drift compensation */
+ );
+
+ /* Take an ambient reading if the instrument has the capability. */
+ /* return nz on fail/abort */
+ /* 1 = user aborted */
+ /* 2 = instrument access failed */
+ /* 3 = no ambient capability */
+ /* 4 = user hit terminate key */
+ /* 5 = system error */
+ /* 8 = no ambient capability */
+ int (*ambient)(struct _disprd *p,
+ double *ambient, /* return ambient in cd/m^2 */
+ int tc /* If nz, termination key */
+ );
+
+}; typedef struct _disprd disprd;
+
+
+/* Create a display reading object. */
+/* Return NULL if error */
+/* Set *errc to code: */
+/* 0 = no error */
+/* 1 = user aborted */
+/* 2 = instrument access failed */
+/* 3 = window access failed */
+/* 4 = user hit terminate key */
+/* 5 = system error */
+/* 6 = system error */
+/* 7 = CRT or LCD must be selected */
+/* 9 = spectral conversion failed */
+/* 10 = no ccmx support */
+/* 11 = no ccss support */
+/* 12 = cal to set but native != 0 */
+/* Use disprd_err() to interpret errc */
+disprd *new_disprd(
+int *errc, /* Error code. May be NULL */
+icompath *ipath, /* Instrument path to open, &icomFakeDevice == fake */
+flow_control fc, /* Serial flow control */
+int dtype, /* Display type, 0 = unknown, 1 = CRT, 2 = LCD */
+int docbid, /* NZ to only allow cbid dtypes */
+int tele, /* NZ for tele mode */
+int nadaptive, /* NZ for non-adaptive mode */
+int noinitcal, /* No initial instrument calibration */
+int highres, /* Use high res mode if available */
+int native, /* 0 = use current current or given calibration curve */
+ /* 1 = use native linear out & high precision */
+int *noramdac, /* Return nz if no ramdac access. native is set to 0 */
+double cal[3][MAX_CAL_ENT], /* Calibration set/return (cal[0][0] < 0.0 if can't/not to be used) */
+ /* native must be 0 if cal is set */
+int ncal, /* number of entries use in cal */
+int softcal, /* NZ if apply cal to readings rather than hardware */
+disppath *screen, /* Screen to calibrate. */
+int blackbg, /* NZ if whole screen should be filled with black */
+int override, /* Override_redirect on X11 */
+int webdisp, /* If nz, port number for web display */
+char *ccallout, /* Shell callout on set color */
+char *mcallout, /* Shell callout on measure color (forced fake) */
+double hpatsize, /* Size of dispwin */
+double vpatsize,
+double ho, /* Horizontal offset */
+double vo, /* Vertical offset */
+double ccmtx[3][3], /* Colorimeter Correction matrix, NULL if none */
+xspect *sets, /* CCSS Set of sample spectra, NULL if none */
+int no_sets, /* CCSS Number on set, 0 if none */
+int spectral, /* 1 = Generate spectral info flag, 2 = don't print error if not capable */
+icxObserverType obType, /* Use alternate observer if spectral or CCSS and != icxOT_none */
+xspect custObserver[3], /* Optional custom observer */
+int bdrift, /* Flag, nz for black drift compensation */
+int wdrift, /* Flag, nz for white drift compensation */
+char *fake_name, /* Name of profile to use as a fake device */
+a1log *log /* Verb, debug & error log */
+);
+/* Return a string describing the error code */
+char * disprd_err(int en);
+
+#define DISPSUP_H
+#endif /* DISPSUP_H */
+
diff --git a/spectro/dispwin.c b/spectro/dispwin.c
new file mode 100644
index 0000000..4a6acd6
--- /dev/null
+++ b/spectro/dispwin.c
@@ -0,0 +1,6321 @@
+
+/*
+ * Argyll Color Correction System
+ * Display target patch window
+ *
+ * Author: Graeme W. Gill
+ * Date: 4/10/96
+ *
+ * Copyright 1998 - 2013, 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.
+ */
+
+/* This program displays test patches on a WinNT, MAC OSX or X11 windowing system. */
+
+/* TTBD
+ *
+ * Nice to have option to create non-square test window ?
+ *
+ * Should probably check the display attributes (like visual depth)
+ * and complain if we aren't using 24 bit color or better.
+ *
+ * Ideally should distinguish clearly between not having access to RAMDAC/VideoLuts
+ * (fail) vs. the display not having them at all.
+ *
+ * Is there a >8 bit way of setting frame buffer value on MSWin (see "Quantize")
+ * when using higher bit depth frame buffers ?
+ *
+ * Is there a >8 bit way of getting/setting RAMDAC indexes ?
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <signal.h>
+#ifndef NT
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "icc.h"
+#include "numsup.h"
+#include "cgats.h"
+#include "conv.h"
+#include "dispwin.h"
+#include "webwin.h"
+#if defined(UNIX_X11) && defined(USE_UCMM)
+#include "ucmm.h"
+#endif
+
+#ifdef __APPLE__
+
+#include <Foundation/Foundation.h>
+
+#include <AppKit/AppKit.h>
+
+# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+# include <copyfile.h>
+# endif
+
+#ifndef CGFLOAT_DEFINED
+#ifdef __LP64__
+typedef double CGFloat;
+#else
+typedef float CGFloat;
+#endif /* defined(__LP64__) */
+#endif /* !CGFLOAT_DEFINED */
+
+#include <IOKit/Graphics/IOGraphicsLib.h>
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED <= 1060
+/* This wasn't declared in 10.6, although it is needed */
+CFUUIDRef CGDisplayCreateUUIDFromDisplayID (uint32_t displayID);
+#endif /* < 10.6 */
+
+#endif /* __APPLE__ */
+
+#define VERIFY_TOL (1.0/255.0)
+#undef DISABLE_RANDR /* Disable XRandR code */
+
+#undef DEBUG
+//#define STANDALONE_TEST
+
+#ifdef DEBUG
+#define errout stderr
+# define debug(xx) fprintf(errout, xx )
+# define debug2(xx) fprintf xx
+# define debugr(xx) fprintf(errout, xx )
+# define debugr2(xx) fprintf xx
+# define debugrr(xx) fprintf(errout, xx )
+# define debugrr2(xx) fprintf xx
+# define debugrr2l(lev, xx) fprintf xx
+#else
+#define errout stderr
+# define debug(xx)
+# define debug2(xx)
+# define debugr(xx) if (p->ddebug) fprintf(errout, xx )
+# define debugr2(xx) if (p->ddebug) fprintf xx
+# define debugrr(xx) if (callback_ddebug) fprintf(errout, xx )
+# define debugrr2(xx) if (callback_ddebug) fprintf xx
+# define debugrr2l(lev, xx) if (callback_ddebug >= lev) fprintf xx
+#endif
+
+/* ----------------------------------------------- */
+/* Dealing with locating displays */
+
+int callback_ddebug = 0; /* Diagnostic global for get_displays() and get_a_display() */
+ /* and events */
+
+#ifdef NT
+
+#define sleep(secs) Sleep((secs) * 1000)
+
+static BOOL CALLBACK MonitorEnumProc(
+ HMONITOR hMonitor, /* handle to display monitor */
+ HDC hdcMonitor, /* NULL, because EnumDisplayMonitors hdc is NULL */
+ LPRECT lprcMonitor, /* Virtual screen coordinates of this monitor */
+ LPARAM dwData /* Context data */
+) {
+ disppath ***pdisps = (disppath ***)dwData;
+ disppath **disps = *pdisps;
+ MONITORINFOEX pmi;
+ int ndisps = 0;
+
+ debugrr2((errout, "MonitorEnumProc() called with hMonitor = 0x%x\n",hMonitor));
+
+ /* Get some more information */
+ pmi.cbSize = sizeof(MONITORINFOEX);
+ if (GetMonitorInfo(hMonitor, (MONITORINFO *)&pmi) == 0) {
+ debugrr("get_displays failed GetMonitorInfo - ignoring display\n");
+ return TRUE;
+ }
+
+ /* See if it seems to be a pseudo-display */
+ if (strncmp(pmi.szDevice, "\\\\.\\DISPLAYV", 12) == 0) {
+ debugrr("Seems to be invisible pseudo-display - ignoring it\n");
+ return TRUE;
+ }
+
+ /* Add the display to the list */
+ if (disps == NULL) {
+ if ((disps = (disppath **)calloc(sizeof(disppath *), 1 + 1)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ return FALSE;
+ }
+ } else {
+ /* Count current number on list */
+ for (ndisps = 0; disps[ndisps] != NULL; ndisps++)
+ ;
+ if ((disps = (disppath **)realloc(disps,
+ sizeof(disppath *) * (ndisps + 2))) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ return FALSE;
+ }
+ disps[ndisps+1] = NULL; /* End marker */
+ }
+
+ if ((disps[ndisps] = calloc(sizeof(disppath),1)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ return FALSE;
+ }
+
+ if ((disps[ndisps]->name = strdup(pmi.szDevice)) == NULL) {
+ debugrr("malloc failed\n");
+ return FALSE;
+ }
+ disps[ndisps]->prim = (pmi.dwFlags & MONITORINFOF_PRIMARY) ? 1 : 0;
+
+ disps[ndisps]->sx = lprcMonitor->left;
+ disps[ndisps]->sy = lprcMonitor->top;
+ disps[ndisps]->sw = lprcMonitor->right - lprcMonitor->left;
+ disps[ndisps]->sh = lprcMonitor->bottom - lprcMonitor->top;
+
+ disps[ndisps]->description = NULL;
+
+ debugrr2((errout, "MonitorEnumProc() set initial monitor info: %d,%d %d,%d name '%s'\n",disps[ndisps]->sx,disps[ndisps]->sy,disps[ndisps]->sw,disps[ndisps]->sh, disps[ndisps]->name));
+
+ *pdisps = disps;
+ return TRUE;
+}
+
+/* Dynamically linked function support */
+
+BOOL (WINAPI* pEnumDisplayDevices)(PVOID,DWORD,PVOID,DWORD) = NULL;
+
+#if !defined(NTDDI_LONGHORN) || NTDDI_VERSION < NTDDI_LONGHORN
+
+typedef enum {
+ WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE,
+ WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER
+} WCS_PROFILE_MANAGEMENT_SCOPE;
+
+BOOL (WINAPI* pWcsAssociateColorProfileWithDevice)(WCS_PROFILE_MANAGEMENT_SCOPE,PCWSTR,PCWSTR) = NULL;
+BOOL (WINAPI* pWcsDisassociateColorProfileFromDevice)(WCS_PROFILE_MANAGEMENT_SCOPE,PCWSTR,PCWSTR) = NULL;
+
+#endif /* NTDDI_VERSION < NTDDI_LONGHORN */
+
+/* See if we can get the wanted function calls */
+/* return nz if OK */
+static int setup_dyn_calls() {
+ static int dyn_inited = 0;
+
+ if (dyn_inited == 0) {
+ dyn_inited = 1;
+
+ /* EnumDisplayDevicesA was left out of lib32.lib on earlier SDK's ... */
+ pEnumDisplayDevices = (BOOL (WINAPI*)(PVOID,DWORD,PVOID,DWORD)) GetProcAddress(LoadLibrary("USER32"), "EnumDisplayDevicesA");
+ if (pEnumDisplayDevices == NULL)
+ dyn_inited = 0;
+
+ /* Vista calls */
+#if !defined(NTDDI_LONGHORN) || NTDDI_VERSION < NTDDI_LONGHORN
+ pWcsAssociateColorProfileWithDevice = (BOOL (WINAPI*)(WCS_PROFILE_MANAGEMENT_SCOPE,PCWSTR,PCWSTR)) GetProcAddress(LoadLibrary("mscms"), "WcsAssociateColorProfileWithDevice");
+ pWcsDisassociateColorProfileFromDevice = (BOOL (WINAPI*)(WCS_PROFILE_MANAGEMENT_SCOPE,PCWSTR,PCWSTR)) GetProcAddress(LoadLibrary("mscms"), "WcsDisassociateColorProfileFromDevice");
+ /* These are checked individually */
+#endif /* NTDDI_VERSION < NTDDI_LONGHORN */
+ }
+
+ return dyn_inited;
+}
+
+/* Simple up conversion from char string to wchar string */
+/* Return NULL if malloc fails */
+/* ~~~ Note, should probably replace this with mbstowcs() ???? */
+static unsigned short *char2wchar(char *s) {
+ unsigned char *cp;
+ unsigned short *w, *wp;
+
+ if ((w = malloc(sizeof(unsigned short) * (strlen(s) + 1))) == NULL)
+ return w;
+
+ for (cp = (unsigned char *)s, wp = w; ; cp++, wp++) {
+ *wp = *cp; /* Zero extend */
+ if (*cp == 0)
+ break;
+ }
+
+ return w;
+}
+
+#endif /* NT */
+
+
+#if defined(UNIX_X11)
+/* Hack to notice if the error handler has been triggered */
+/* when a function doesn't return a value. */
+
+int g_error_handler_triggered = 0;
+
+/* A noop X11 error handler */
+int null_error_handler(Display *disp, XErrorEvent *ev) {
+ g_error_handler_triggered = 1;
+ return 0;
+}
+#endif /* X11 */
+
+/* Return pointer to list of disppath. Last will be NULL. */
+/* Return NULL on failure. Call free_disppaths() to free up allocation */
+disppath **get_displays() {
+ disppath **disps = NULL;
+
+#ifdef NT
+ DISPLAY_DEVICE dd;
+ char buf[200];
+ int i, j;
+
+ if (setup_dyn_calls() == 0) {
+ debugrr("Dynamic linking to EnumDisplayDevices or Vista AssociateColorProfile failed\n");
+ free_disppaths(disps);
+ return NULL;
+ }
+
+ /* Create an initial list of monitors */
+ /* (It might be better to call pEnumDisplayDevices(NULL, i ..) instead ??, */
+ /* then we can use the StateFlags to distingish monitors not attached to the desktop etc.) */
+ if (EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&disps) == 0) {
+ debugrr("EnumDisplayMonitors failed\n");
+ free_disppaths(disps);
+ return NULL;
+ }
+
+ /* Now locate detailed information about displays */
+ for (i = 0; ; i++) {
+ if (disps == NULL || disps[i] == NULL)
+ break;
+
+ dd.cb = sizeof(dd);
+
+ debugrr2((errout, "get_displays about to get monitor information for %d\n",i));
+ /* Get monitor information */
+ for (j = 0; ;j++) {
+ if ((*pEnumDisplayDevices)(disps[i]->name, j, &dd, 0) == 0) {
+ debugrr2((errout,"EnumDisplayDevices failed on '%s' Mon = %d\n",disps[i]->name,j));
+ if (j == 0) {
+ strcpy(disps[i]->monid, ""); /* We won't be able to set a profile */
+ }
+ break;
+ }
+ if (callback_ddebug) {
+ fprintf(errout,"Mon %d, name '%s'\n",j,dd.DeviceName);
+ fprintf(errout,"Mon %d, string '%s'\n",j,dd.DeviceString);
+ fprintf(errout,"Mon %d, flags 0x%x\n",j,dd.StateFlags);
+ fprintf(errout,"Mon %d, id '%s'\n",j,dd.DeviceID);
+ fprintf(errout,"Mon %d, key '%s'\n",j,dd.DeviceKey);
+ }
+ if (j == 0) {
+ strcpy(disps[i]->monid, dd.DeviceID);
+ }
+ }
+
+ sprintf(buf,"%s, at %d, %d, width %d, height %d%s",disps[i]->name+4,
+ disps[i]->sx, disps[i]->sy, disps[i]->sw, disps[i]->sh,
+ disps[i]->prim ? " (Primary Display)" : "");
+
+ if ((disps[i]->description = strdup(buf)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free_disppaths(disps);
+ return NULL;
+ }
+
+ debugrr2((errout, "get_displays added description '%s' to display %d\n",disps[i]->description,i));
+
+ /* Note that calling EnumDisplayDevices(NULL, j, ..) for the adapter can return other */
+ /* information, such as the graphics card name, and additional state flags. */
+ /* EnumDisplaySettings() can also be called to get information such as display depth etc. */
+ }
+
+#ifdef NEVER
+ /* Explore adapter information */
+ for (j = 0; ; j++) {
+ /* Get adapater information */
+ if ((*pEnumDisplayDevices)(NULL, j, &dd, 0) == 0)
+ break;
+ printf("Adapt %d, name '%s'\n",j,dd.DeviceName);
+ printf("Adapt %d, string '%s'\n",j,dd.DeviceString);
+ printf("Adapt %d, flags 0x%x\n",j,dd.StateFlags);
+ printf("Adapt %d, id '%s'\n",j,dd.DeviceID);
+ printf("Adapt %d, key '%s'\n",j,dd.DeviceKey);
+ }
+#endif /* NEVER */
+
+#endif /* NT */
+
+#ifdef __APPLE__
+ /* Note :- some recent releases of OS X have a feature which */
+ /* automatically adjusts the screen brigtness with ambient level. */
+ /* We may have to find a way of disabling this during calibration and profiling. */
+ /* See the "pset -g" command. */
+
+ /*
+ We could possibly use NSScreen instead of CG here,
+ but we'd need to have a an NSApp first, so perhaps not.
+
+ */
+
+ int i;
+ CGDisplayErr dstat;
+ CGDisplayCount dcount; /* Number of display IDs */
+ CGDirectDisplayID *dids; /* Array of display IDs */
+
+ if ((dstat = CGGetActiveDisplayList(0, NULL, &dcount)) != kCGErrorSuccess || dcount < 1) {
+ debugrr("CGGetActiveDisplayList #1 returned error\n");
+ return NULL;
+ }
+ if ((dids = (CGDirectDisplayID *)malloc(dcount * sizeof(CGDirectDisplayID))) == NULL) {
+ debugrr("malloc of CGDirectDisplayID's failed\n");
+ return NULL;
+ }
+ if ((dstat = CGGetActiveDisplayList(dcount, dids, &dcount)) != kCGErrorSuccess) {
+ debugrr("CGGetActiveDisplayList #2 returned error\n");
+ free(dids);
+ return NULL;
+ }
+
+ /* Found dcount displays */
+ debugrr2((errout,"Found %d screens\n",dcount));
+
+ /* Allocate our list */
+ if ((disps = (disppath **)calloc(sizeof(disppath *), dcount + 1)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free(dids);
+ return NULL;
+ }
+ for (i = 0; i < dcount; i++) {
+ if ((disps[i] = calloc(sizeof(disppath), 1)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+ disps[i]->ddid = dids[i];
+ }
+
+ /* Got displays, now figure out a description for each one */
+ for (i = 0; i < dcount; i++) {
+ CGRect dbound; /* Bounding rectangle of chosen display */
+ io_service_t dport;
+ CFDictionaryRef ddr, pndr;
+ CFIndex dcount;
+ char *dp = NULL, desc[50];
+ char buf[200];
+
+ dbound = CGDisplayBounds(dids[i]);
+ disps[i]->sx = dbound.origin.x;
+ disps[i]->sy = dbound.origin.y;
+ disps[i]->sw = dbound.size.width;
+ disps[i]->sh = dbound.size.height;
+
+ /* Try and get some information about the display */
+ if ((dport = CGDisplayIOServicePort(dids[i])) == MACH_PORT_NULL) {
+ debugrr("CGDisplayIOServicePort returned error\n");
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+
+#ifdef NEVER
+ {
+ io_name_t name;
+ if (IORegistryEntryGetName(dport, name) != KERN_SUCCESS) {
+ debugrr("IORegistryEntryGetName returned error\n");
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+ printf("Driver %d name = '%s'\n",i,name);
+ }
+#endif
+ if ((ddr = IODisplayCreateInfoDictionary(dport, 0)) == NULL) {
+ debugrr("IODisplayCreateInfoDictionary returned NULL\n");
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+ if ((pndr = CFDictionaryGetValue(ddr, CFSTR(kDisplayProductName))) == NULL) {
+ debugrr("CFDictionaryGetValue returned NULL\n");
+ CFRelease(ddr);
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+ if ((dcount = CFDictionaryGetCount(pndr)) > 0) {
+ const void **keys;
+ const void **values;
+ int j;
+
+ keys = (const void **)calloc(sizeof(void *), dcount);
+ values = (const void **)calloc(sizeof(void *), dcount);
+ if (keys == NULL || values == NULL) {
+ if (keys != NULL)
+ free(keys);
+ if (values != NULL)
+ free(values);
+ debugrr("malloc failed\n");
+ CFRelease(ddr);
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+ CFDictionaryGetKeysAndValues(pndr, keys, values);
+ for (j = 0; j < dcount; j++) {
+ const char *k, *v;
+ char kbuf[50], vbuf[50];
+ k = CFStringGetCStringPtr(keys[j], kCFStringEncodingMacRoman);
+ if (k == NULL) {
+ if (CFStringGetCString(keys[j], kbuf, 50, kCFStringEncodingMacRoman))
+ k = kbuf;
+ }
+ v = CFStringGetCStringPtr(values[j], kCFStringEncodingMacRoman);
+ if (v == NULL) {
+ if (CFStringGetCString(values[j], vbuf, 50, kCFStringEncodingMacRoman))
+ v = vbuf;
+ }
+ /* We're only grabing the english description... */
+ if (k != NULL && v != NULL && strcmp(k, "en_US") == 0) {
+ strncpy(desc, v, 49);
+ desc[49] = '\000';
+ dp = desc;
+ }
+ }
+ free(keys);
+ free(values);
+ }
+ CFRelease(ddr);
+
+ if (dp == NULL) {
+ strcpy(desc, "(unknown)");
+ dp = desc;
+ }
+ sprintf(buf,"%s, at %d, %d, width %d, height %d%s",dp,
+ disps[i]->sx, disps[i]->sy, disps[i]->sw, disps[i]->sh,
+ CGDisplayIsMain(dids[i]) ? " (Primary Display)" : "");
+
+ if ((disps[i]->name = strdup(dp)) == NULL
+ || (disps[i]->description = strdup(buf)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+ }
+
+ free(dids);
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11)
+ int i, j, k;
+ int defsix = 0; /* default screen index */
+ int dcount; /* Number of screens */
+ char *dname;
+ char dnbuf[100];
+ int evb = 0, erb = 0;
+ int majv, minv; /* Version */
+ Display *mydisplay;
+ int ndisps = 0;
+ XineramaScreenInfo *xai = NULL;
+ char desc1[100], desc2[200];
+
+ /* There seems to be no way of getting the available displays */
+ /* on an X11 system. Attempting to open them in sequence */
+ /* takes too long. We just rely on the user supplying the */
+ /* right display. We can enumerate screens though. */
+
+ /* Open the base display, and then enumerate all the screens */
+ if ((dname = getenv("DISPLAY")) != NULL) {
+ char *pp;
+ strncpy(dnbuf,dname,99); dnbuf[99] = '\000';
+ if ((pp = strrchr(dnbuf, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) == NULL)
+ strcat(dnbuf,".0");
+ else {
+ if (pp[1] == '\000')
+ strcat(dnbuf,"0");
+ else {
+ pp[1] = '0';
+ pp[2] = '\000';
+ }
+ }
+ }
+ } else
+ strcpy(dnbuf,":0.0");
+
+ if ((mydisplay = XOpenDisplay(dnbuf)) == NULL) {
+ debugrr2((errout, "failed to open display '%s'\n",dnbuf));
+ return NULL;
+ }
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ /* Use Xrandr 1.2 if it's available, and if it's not disabled */
+ if (getenv("ARGYLL_IGNORE_XRANDR1_2") == NULL
+ && XRRQueryExtension(mydisplay, &evb, &erb) != 0
+ && XRRQueryVersion(mydisplay, &majv, &minv)
+ && majv == 1 && minv >= 2) {
+
+ if (XSetErrorHandler(null_error_handler) == 0) {
+ debugrr("get_displays failed on XSetErrorHandler\n");
+ XCloseDisplay(mydisplay);
+ free_disppaths(disps);
+ return NULL;
+ }
+
+ dcount = ScreenCount(mydisplay);
+
+ /* Go through all the screens */
+ for (i = 0; i < dcount; i++) {
+ XRRScreenResources *scrnres;
+ int jj; /* Screen index */
+
+ if ((scrnres = XRRGetScreenResources(mydisplay, RootWindow(mydisplay,i))) == NULL) {
+ debugrr("XRRGetScreenResources failed\n");
+ XCloseDisplay(mydisplay);
+ free_disppaths(disps);
+ return NULL;
+ }
+
+ /* Look at all the screens outputs */
+ for (jj = j = 0; j < scrnres->noutput; j++) {
+ XRROutputInfo *outi;
+ XRRCrtcInfo *crtci;
+
+ if ((outi = XRRGetOutputInfo(mydisplay, scrnres, scrnres->outputs[j])) == NULL) {
+ debugrr("XRRGetOutputInfo failed\n");
+ XRRFreeScreenResources(scrnres);
+ XCloseDisplay(mydisplay);
+ free_disppaths(disps);
+ return NULL;
+ }
+
+ if (outi->connection == RR_Disconnected ||
+ outi->crtc == None) {
+ continue;
+ }
+
+ /* Check that the VideoLUT's are accessible */
+ {
+ XRRCrtcGamma *crtcgam;
+
+ debugrr("Checking XRandR 1.2 VideoLUT access\n");
+ if ((crtcgam = XRRGetCrtcGamma(mydisplay, outi->crtc)) == NULL
+ || crtcgam->size == 0) {
+ fprintf(stderr,"XRandR 1.2 is faulty - falling back to older extensions\n");
+ if (crtcgam != NULL)
+ XRRFreeGamma(crtcgam);
+ free_disppaths(disps);
+ disps = NULL;
+ j = scrnres->noutput;
+ i = dcount;
+ continue; /* Abort XRandR 1.2 */
+ }
+ }
+#ifdef NEVER
+ {
+ Atom *oprops;
+ int noprop;
+
+ /* Get a list of the properties of the output */
+ oprops = XRRListOutputProperties(mydisplay, scrnres->outputs[j], &noprop);
+
+ printf("num props = %d\n", noprop);
+ for (k = 0; k < noprop; k++) {
+ printf("%d: atom 0x%x, name = '%s'\n", k, oprops[k], XGetAtomName(mydisplay, oprops[k]));
+ }
+ }
+#endif /* NEVER */
+
+ if ((crtci = XRRGetCrtcInfo(mydisplay, scrnres, outi->crtc)) != NULL) {
+ char *pp;
+
+ /* Add the output to the list */
+ if (disps == NULL) {
+ if ((disps = (disppath **)calloc(sizeof(disppath *), 1 + 1)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ XRRFreeCrtcInfo(crtci);
+ XRRFreeScreenResources(scrnres);
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+ } else {
+ if ((disps = (disppath **)realloc(disps,
+ sizeof(disppath *) * (ndisps + 2))) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ XRRFreeCrtcInfo(crtci);
+ XRRFreeScreenResources(scrnres);
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+ disps[ndisps+1] = NULL; /* End marker */
+ }
+ /* ndisps is current display we're filling in */
+ if ((disps[ndisps] = calloc(sizeof(disppath),1)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ XRRFreeCrtcInfo(crtci);
+ XRRFreeScreenResources(scrnres);
+ XCloseDisplay(mydisplay);
+ free_disppaths(disps);
+ return NULL;
+ }
+
+ disps[ndisps]->screen = i;
+ disps[ndisps]->uscreen = i;
+ disps[ndisps]->rscreen = i;
+ disps[ndisps]->sx = crtci->x;
+ disps[ndisps]->sy = crtci->y;
+ disps[ndisps]->sw = crtci->width;
+ disps[ndisps]->sh = crtci->height;
+ disps[ndisps]->crtc = outi->crtc; /* XID of crtc */
+ disps[ndisps]->output = scrnres->outputs[j]; /* XID of output */
+
+ sprintf(desc1,"Screen %d, Output %s",ndisps+1,outi->name);
+ sprintf(desc2,"%s at %d, %d, width %d, height %d",desc1,
+ disps[ndisps]->sx, disps[ndisps]->sy, disps[ndisps]->sw, disps[ndisps]->sh);
+
+ /* See if it is a clone */
+ for (k = 0; k < ndisps; k++) {
+ if (disps[k]->crtc == disps[ndisps]->crtc) {
+ sprintf(desc1, "[ Clone of %d ]",k+1);
+ strcat(desc2, desc1);
+ }
+ }
+ if ((disps[ndisps]->description = strdup(desc2)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ XRRFreeCrtcInfo(crtci);
+ XRRFreeScreenResources(scrnres);
+ XCloseDisplay(mydisplay);
+ free_disppaths(disps);
+ return NULL;
+ }
+
+ /* Form the display name */
+ if ((pp = strrchr(dnbuf, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) != NULL) {
+ sprintf(pp,".%d",i);
+ }
+ }
+ if ((disps[ndisps]->name = strdup(dnbuf)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ XRRFreeCrtcInfo(crtci);
+ XRRFreeScreenResources(scrnres);
+ XCloseDisplay(mydisplay);
+ free_disppaths(disps);
+ return NULL;
+ }
+ debugrr2((errout, "Display %d name = '%s'\n",ndisps,disps[ndisps]->name));
+
+ /* Create the X11 root atom of the default screen */
+ /* that may contain the associated ICC profile */
+ /* (The _%d variant will probably break with non-Xrandr */
+ /* aware software if Xrandr is configured to have more than */
+ /* a single virtual screen.) */
+ if (jj == 0)
+ strcpy(desc1, "_ICC_PROFILE");
+ else
+ sprintf(desc1, "_ICC_PROFILE_%d",jj);
+
+ if ((disps[ndisps]->icc_atom = XInternAtom(mydisplay, desc1, False)) == None)
+ error("Unable to intern atom '%s'",desc1);
+
+ /* Create the atom of the output that may contain the associated ICC profile */
+ if ((disps[ndisps]->icc_out_atom = XInternAtom(mydisplay, "_ICC_PROFILE", False)) == None)
+ error("Unable to intern atom '%s'","_ICC_PROFILE");
+
+ /* Grab the EDID from the output */
+ {
+ Atom edid_atom, ret_type;
+ int ret_format;
+ long ret_len = 0, ret_togo;
+ unsigned char *atomv = NULL;
+ int ii;
+ char *keys[] = { /* Possible keys that may be used */
+ "EDID_DATA",
+ "EDID",
+ ""
+ };
+
+ /* Try each key in turn */
+ for (ii = 0; keys[ii][0] != '\000'; ii++) {
+ /* Get the atom for the EDID data */
+ if ((edid_atom = XInternAtom(mydisplay, keys[ii], True)) == None) {
+ debugrr2((errout, "Unable to intern atom '%s'\n",keys[ii]));
+ /* Try the next key */
+ } else {
+
+ /* Get the EDID_DATA */
+ if (XRRGetOutputProperty(mydisplay, scrnres->outputs[j], edid_atom,
+ 0, 0x7ffffff, False, False, XA_INTEGER,
+ &ret_type, &ret_format, &ret_len, &ret_togo, &atomv) == Success
+ && (ret_len == 128 || ret_len == 256)) {
+ if ((disps[ndisps]->edid = malloc(sizeof(unsigned char) * ret_len)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ XRRFreeCrtcInfo(crtci);
+ XRRFreeScreenResources(scrnres);
+ XCloseDisplay(mydisplay);
+ free_disppaths(disps);
+ return NULL;
+ }
+ memmove(disps[ndisps]->edid, atomv, ret_len);
+ disps[ndisps]->edid_len = ret_len;
+ XFree(atomv);
+ debugrr2((errout, "Got EDID for display\n"));
+ break;
+ }
+ /* Try the next key */
+ }
+ }
+ if (keys[ii][0] == '\000')
+ debugrr2((errout, "Failed to get EDID for display\n"));
+ }
+
+ jj++; /* Next enabled index */
+ ndisps++; /* Now it's number of displays */
+ XRRFreeCrtcInfo(crtci);
+ }
+ XRRFreeOutputInfo(outi);
+ }
+
+ XRRFreeScreenResources(scrnres);
+ }
+ XSetErrorHandler(NULL);
+ defsix = DefaultScreen(mydisplay);
+ }
+#endif /* randr >= V 1.2 */
+
+ if (disps == NULL) { /* Use Older style identification */
+ debugrr("get_displays checking for Xinerama\n");
+
+ if (XSetErrorHandler(null_error_handler) == 0) {
+ debugrr("get_displays failed on XSetErrorHandler\n");
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+
+ if (XineramaQueryExtension(mydisplay, &evb, &erb) != 0
+ && XineramaIsActive(mydisplay)) {
+
+ xai = XineramaQueryScreens(mydisplay, &dcount);
+
+ if (xai == NULL || dcount == 0) {
+ debugrr("XineramaQueryScreens failed\n");
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+ defsix = 0;
+ } else {
+ dcount = ScreenCount(mydisplay);
+ defsix = DefaultScreen(mydisplay);
+ }
+
+ /* Allocate our list */
+ if ((disps = (disppath **)calloc(sizeof(disppath *), dcount + 1)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+ for (i = 0; i < dcount; i++) {
+ if ((disps[i] = calloc(sizeof(disppath), 1)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free_disppaths(disps);
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+ }
+
+ /* Create a description for each screen */
+ for (i = 0; i < dcount; i++) {
+ XF86VidModeMonitor monitor;
+ int evb = 0, erb = 0;
+ char *pp;
+
+ /* Form the display name */
+ if ((pp = strrchr(dnbuf, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) != NULL) {
+ sprintf(pp,".%d",i);
+ }
+ }
+ if ((disps[i]->name = strdup(dnbuf)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free_disppaths(disps);
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+
+ debugrr2((errout, "Display %d name = '%s'\n",i,disps[i]->name));
+ if (xai != NULL) { /* Xinerama */
+ disps[i]->screen = 0; /* We are asuming Xinerame creates a single virtual screen */
+ disps[i]->uscreen = i; /* We are assuming xinerama lists screens in the same order */
+ disps[i]->rscreen = i;
+ disps[i]->sx = xai[i].x_org;
+ disps[i]->sy = xai[i].y_org;
+ disps[i]->sw = xai[i].width;
+ disps[i]->sh = xai[i].height;
+ } else {
+ disps[i]->screen = i;
+ disps[i]->uscreen = i;
+ disps[i]->rscreen = i;
+ disps[i]->sx = 0; /* Must be 0 */
+ disps[i]->sy = 0;
+ disps[i]->sw = DisplayWidth(mydisplay, disps[i]->screen);
+ disps[i]->sh = DisplayHeight(mydisplay, disps[i]->screen);
+ }
+
+ /* Create the X11 root atom of the default screen */
+ /* that may contain the associated ICC profile */
+ if (disps[i]->uscreen == 0)
+ strcpy(desc1, "_ICC_PROFILE");
+ else
+ sprintf(desc1, "_ICC_PROFILE_%d",disps[i]->uscreen);
+
+ if ((disps[i]->icc_atom = XInternAtom(mydisplay, desc1, False)) == None)
+ error("Unable to intern atom '%s'",desc1);
+
+ /* See if we can locate the EDID of the monitor for this screen */
+ for (j = 0; j < 2; j++) {
+ char edid_name[50];
+ Atom edid_atom, ret_type;
+ int ret_format = 8;
+ long ret_len, ret_togo;
+ unsigned char *atomv = NULL;
+
+ if (disps[i]->uscreen == 0) {
+ if (j == 0)
+ strcpy(edid_name,"XFree86_DDC_EDID1_RAWDATA");
+ else
+ strcpy(edid_name,"XFree86_DDC_EDID2_RAWDATA");
+ } else {
+ if (j == 0)
+ sprintf(edid_name,"XFree86_DDC_EDID1_RAWDATA_%d",disps[i]->uscreen);
+ else
+ sprintf(edid_name,"XFree86_DDC_EDID2_RAWDATA_%d",disps[i]->uscreen);
+ }
+
+ if ((edid_atom = XInternAtom(mydisplay, edid_name, True)) == None)
+ continue;
+ if (XGetWindowProperty(mydisplay, RootWindow(mydisplay, disps[i]->uscreen), edid_atom,
+ 0, 0x7ffffff, False, XA_INTEGER,
+ &ret_type, &ret_format, &ret_len, &ret_togo, &atomv) == Success
+ && (ret_len == 128 || ret_len == 256)) {
+ if ((disps[i]->edid = malloc(sizeof(unsigned char) * ret_len)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free_disppaths(disps);
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+ memmove(disps[i]->edid, atomv, ret_len);
+ disps[i]->edid_len = ret_len;
+ XFree(atomv);
+ debugrr2((errout, "Got EDID for display\n"));
+ break;
+ } else {
+ debugrr2((errout, "Failed to get EDID for display\n"));
+ }
+ }
+
+ if (XF86VidModeQueryExtension(mydisplay, &evb, &erb) != 0) {
+ /* Some propietary multi-screen drivers (ie. TwinView & MergeFB) */
+ /* don't implement the XVidMode extension properly. */
+ monitor.model = NULL;
+ if (XF86VidModeGetMonitor(mydisplay, disps[i]->uscreen, &monitor) != 0
+ && monitor.model != NULL && monitor.model[0] != '\000')
+ sprintf(desc1, "%s",monitor.model);
+ else
+ sprintf(desc1,"Screen %d",i+1);
+ } else
+ sprintf(desc1,"Screen %d",i+1);
+
+ sprintf(desc2,"%s at %d, %d, width %d, height %d",desc1,
+ disps[i]->sx, disps[i]->sy, disps[i]->sw, disps[i]->sh);
+ if ((disps[i]->description = strdup(desc2)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free_disppaths(disps);
+ XCloseDisplay(mydisplay);
+ return NULL;
+ }
+ }
+ XSetErrorHandler(NULL);
+ }
+
+ /* Put the screen given by the display name at the top */
+ {
+ disppath *tdispp;
+ tdispp = disps[defsix];
+ disps[defsix] = disps[0];
+ disps[0] = tdispp;
+ }
+
+ if (xai != NULL)
+ XFree(xai);
+
+ XCloseDisplay(mydisplay);
+
+#endif /* UNIX X11 */
+
+ return disps;
+}
+
+/* Free a whole list of display paths */
+void free_disppaths(disppath **disps) {
+ if (disps != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (disps[i] == NULL)
+ break;
+
+ if (disps[i]->name != NULL)
+ free(disps[i]->name);
+ if (disps[i]->description != NULL)
+ free(disps[i]->description);
+#if defined(UNIX_X11)
+ if (disps[i]->edid != NULL)
+ free(disps[i]->edid);
+#endif
+ free(disps[i]);
+ }
+ free(disps);
+ }
+}
+
+/* Delete a single display from the list of display paths */
+void del_disppath(disppath **disps, int ix) {
+ if (disps != NULL) {
+ int i, j, k;
+ for (i = 0; ; i++) {
+ if (disps[i] == NULL)
+ break;
+
+ if (i == ix) { /* One to delete */
+ if (disps[i]->name != NULL)
+ free(disps[i]->name);
+ if (disps[i]->description != NULL)
+ free(disps[i]->description);
+#if defined(UNIX_X11)
+ if (disps[i]->edid != NULL)
+ free(disps[i]->edid);
+#endif
+ free(disps[i]);
+
+ /* Shuffle the rest down */
+ for (j = i, k = i + 1; ;j++, k++) {
+ disps[j] = disps[k];
+ if (disps[k] == NULL)
+ break;
+ }
+ return;
+ }
+ }
+ }
+}
+
+/* ----------------------------------------------- */
+/* Deal with selecting a display */
+
+/* Return the given display given its index 0..n-1 */
+disppath *get_a_display(int ix) {
+ disppath **paths, *rv = NULL;
+ int i;
+
+ if ((paths = get_displays()) == NULL)
+ return NULL;
+
+ for (i = 0; ;i++) {
+ if (paths[i] == NULL) {
+ free_disppaths(paths);
+ return NULL;
+ }
+ if (i == ix)
+ break;
+ }
+ if ((rv = malloc(sizeof(disppath))) == NULL) {
+ debugrr("get_a_display failed malloc\n");
+ free_disppaths(paths);
+ return NULL;
+ }
+ *rv = *paths[i]; /* Structure copy */
+ if ((rv->name = strdup(paths[i]->name)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free(rv->description);
+ free(rv);
+ free_disppaths(paths);
+ return NULL;
+ }
+ if ((rv->description = strdup(paths[i]->description)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free(rv);
+ free_disppaths(paths);
+ return NULL;
+ }
+#if defined(UNIX_X11)
+ if (paths[i]->edid != NULL) {
+ if ((rv->edid = malloc(sizeof(unsigned char) * paths[i]->edid_len)) == NULL) {
+ debugrr("get_displays failed on malloc\n");
+ free(rv);
+ free_disppaths(paths);
+ return NULL;
+ }
+ rv->edid_len = paths[i]->edid_len;
+ memmove(rv->edid, paths[i]->edid, rv->edid_len );
+ }
+#endif
+ free_disppaths(paths);
+ return rv;
+}
+
+void free_a_disppath(disppath *path) {
+ if (path != NULL) {
+ if (path->name != NULL)
+ free(path->name);
+ if (path->description != NULL)
+ free(path->description);
+#if defined(UNIX_X11)
+ if (path->edid != NULL)
+ free(path->edid);
+#endif
+ free(path);
+ }
+}
+
+/* ----------------------------------------------- */
+
+static ramdac *dispwin_clone_ramdac(ramdac *r);
+static void dispwin_setlin_ramdac(ramdac *r);
+static void dispwin_del_ramdac(ramdac *r);
+
+/* For VideoLUT/RAMDAC use, we assume that the number of entries in the RAMDAC */
+/* meshes perfectly with the display raster depth, so that we can */
+/* figure out how to apportion device values. We fail if they don't */
+/* seem to mesh. */
+
+/* !!! Would be nice to add an error message return to dispwin and */
+/* !!! pass errors back to it so that the detail can be reported */
+/* !!! to the user. */
+
+/* Get RAMDAC values. ->del() when finished. */
+/* Return NULL if not possible */
+static ramdac *dispwin_get_ramdac(dispwin *p) {
+ ramdac *r = NULL;
+ int i, j;
+
+#ifdef NT
+ WORD vals[3][256]; /* 256 x 16 bit elements (Quantize) */
+
+ debugr("dispwin_get_ramdac called\n");
+
+#ifdef NEVER /* Doesn't seem to return correct information on win2K systems */
+ if ((GetDeviceCaps(p->hdc, COLORMGMTCAPS) & CM_GAMMA_RAMP) == 0) {
+ debugr("dispwin_get_ramdac failed on GetDeviceCaps(CM_GAMMA_RAMP)\n");
+ return NULL;
+ }
+#endif
+
+ /* Allocate a ramdac */
+ if ((r = (ramdac *)calloc(sizeof(ramdac), 1)) == NULL) {
+ debugr("dispwin_get_ramdac failed on malloc()\n");
+ return NULL;
+ }
+ r->pdepth = p->pdepth;
+ r->nent = (1 << p->pdepth);
+ r->clone = dispwin_clone_ramdac;
+ r->setlin = dispwin_setlin_ramdac;
+ r->del = dispwin_del_ramdac;
+
+ for (j = 0; j < 3; j++) {
+
+ if ((r->v[j] = (double *)calloc(sizeof(double), r->nent)) == NULL) {
+ for (j--; j >= 0; j--)
+ free(r->v[j]);
+ free(r);
+ debugr("dispwin_get_ramdac failed on malloc()\n");
+ return NULL;
+ }
+ }
+
+ /* GetDeviceGammaRamp() is hard coded for 3 x 256 entries (Quantize) */
+ if (r->nent != 256) {
+ debugr2((errout,"GetDeviceGammaRamp() is hard coded for nent == 256, and we've got nent = %d!\n",r->nent));
+ return NULL;
+ }
+
+ if (GetDeviceGammaRamp(p->hdc, vals) == 0) {
+ debugr("dispwin_get_ramdac failed on GetDeviceGammaRamp()\n");
+ return NULL;
+ }
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ r->v[j][i] = vals[j][i]/65535.0;
+ }
+ }
+#endif /* NT */
+
+#ifdef __APPLE__
+ unsigned int nent;
+ CGGammaValue vals[3][16385];
+
+ debugr("dispwin_get_ramdac called\n");
+
+ if (CGGetDisplayTransferByTable(p->ddid, 163845, vals[0], vals[1], vals[2], &nent) != 0) {
+ debugr("CGGetDisplayTransferByTable failed\n");
+ return NULL;
+ }
+
+ if (nent == 16385) { /* oops - we didn't provide enought space! */
+ debugr("CGGetDisplayTransferByTable has more entries than we can handle\n");
+ return NULL;
+ }
+
+ if (nent != (1 << p->pdepth)) {
+ debugr("CGGetDisplayTransferByTable number of entries mismatches screen depth\n");
+ return NULL;
+ }
+
+ /* Allocate a ramdac */
+ if ((r = (ramdac *)calloc(sizeof(ramdac), 1)) == NULL) {
+ debugr("dispwin_get_ramdac failed on malloc()\n");
+ return NULL;
+ }
+
+ r->pdepth = p->pdepth;
+ r->nent = (1 << p->pdepth);
+ r->clone = dispwin_clone_ramdac;
+ r->setlin = dispwin_setlin_ramdac;
+ r->del = dispwin_del_ramdac;
+ for (j = 0; j < 3; j++) {
+
+ if ((r->v[j] = (double *)calloc(sizeof(double), r->nent)) == NULL) {
+ for (j--; j >= 0; j--)
+ free(r->v[j]);
+ free(r);
+ debugr("dispwin_get_ramdac failed on malloc()\n");
+ return NULL;
+ }
+ }
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ r->v[j][i] = vals[j][i];
+ }
+ }
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11)
+ unsigned short vals[3][16384];
+ int nent = 0;
+ int evb = 0, erb = 0;
+
+ debugr("dispwin_get_ramdac called\n");
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ if (p->crtc != 0) { /* Using Xrandr 1.2 */
+ XRRCrtcGamma *crtcgam;
+ int nz = 0;
+
+ debugr("Getting gamma using Randr 1.2\n");
+
+ if ((crtcgam = XRRGetCrtcGamma(p->mydisplay, p->crtc)) == NULL) {
+ debugr("XRRGetCrtcGamma failed\n");
+ return NULL;
+ }
+
+ nent = crtcgam->size;
+
+ if (nent > 16384) {
+ debugr("XRRGetCrtcGammaSize has more entries than we can handle\n");
+ return NULL;
+ }
+
+ if (nent != (1 << p->pdepth)) {
+ debugr2((errout,"XRRGetCrtcGammaSize number of entries %d mismatches screen depth %d\n",nent,(1 << p->pdepth)));
+ return NULL;
+ }
+
+ /* Check for XRandR 1.2 startup bug */
+ for (i = 0; i < nent; i++) {
+ vals[0][i] = crtcgam->red[i];
+ vals[1][i] = crtcgam->green[i];
+ vals[2][i] = crtcgam->blue[i];
+ nz = vals[0][i] | vals[1][i] | vals[2][i];
+ }
+
+ /* Compensate for XRandR 1.2 startup bug */
+ if (nz == 0) {
+ debugr("Detected XRandR 1.2 bug ? Assuming linear ramp!\n");
+ for (i = 0; i < nent; i++) {
+ for (j = 0; j < 3; j++)
+ vals[j][i] = (int)(65535.0 * i/(nent-1.0) + 0.5);
+ }
+ }
+
+ XRRFreeGamma(crtcgam);
+
+ } else
+#endif /* randr >= V 1.2 */
+ {
+
+ if (XF86VidModeQueryExtension(p->mydisplay, &evb, &erb) == 0) {
+ debugr("XF86VidModeQueryExtension failed\n");
+ return NULL;
+ }
+ /* Some propietary multi-screen drivers (ie. TwinView & MergedFB) */
+ /* don't implement the XVidMode extenstion properly. */
+ if (XSetErrorHandler(null_error_handler) == 0) {
+ debugr("get_displays failed on XSetErrorHandler\n");
+ return NULL;
+ }
+ nent = -1;
+ if (XF86VidModeGetGammaRampSize(p->mydisplay, p->myrscreen, &nent) == 0
+ || nent == -1) {
+ XSetErrorHandler(NULL);
+ debugr("XF86VidModeGetGammaRampSize failed\n");
+ return NULL;
+ }
+ XSetErrorHandler(NULL); /* Restore handler */
+ if (nent == 0) {
+ debugr("XF86VidModeGetGammaRampSize returned 0 size\n");
+ return NULL;
+ }
+
+ if (nent > 16384) {
+ debugr("XF86VidModeGetGammaRampSize has more entries than we can handle\n");
+ return NULL;
+ }
+
+ if (XF86VidModeGetGammaRamp(p->mydisplay, p->myrscreen, nent, vals[0], vals[1], vals[2]) == 0) {
+ debugr("XF86VidModeGetGammaRamp failed\n");
+ return NULL;
+ }
+
+ if (nent != (1 << p->pdepth)) {
+ debugr2((errout,"CGGetDisplayTransferByTable number of entries %d mismatches screen depth %d\n",nent,(1 << p->pdepth)));
+ return NULL;
+ }
+ }
+
+ /* Allocate a ramdac */
+ if ((r = (ramdac *)calloc(sizeof(ramdac), 1)) == NULL) {
+ debugr("dispwin_get_ramdac failed on malloc()\n");
+ return NULL;
+ }
+
+ r->pdepth = p->pdepth;
+ r->nent = (1 << p->pdepth);
+ r->clone = dispwin_clone_ramdac;
+ r->setlin = dispwin_setlin_ramdac;
+ r->del = dispwin_del_ramdac;
+ for (j = 0; j < 3; j++) {
+
+ if ((r->v[j] = (double *)calloc(sizeof(double), r->nent)) == NULL) {
+ for (j--; j >= 0; j--)
+ free(r->v[j]);
+ free(r);
+ debugr("dispwin_get_ramdac failed on malloc()\n");
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < r->nent; i++) {
+ for (j = 0; j < 3; j++) {
+ r->v[j][i] = vals[j][i]/65535.0;
+ }
+ }
+#endif /* UNXI X11 */
+ debugr("dispwin_get_ramdac returning OK\n");
+ return r;
+}
+
+#ifdef __APPLE__
+ /* Various support functions */
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED < 1060
+
+/* Given a location, return a string for it's path */
+static char *plocpath(CMProfileLocation *ploc) {
+
+ if (ploc->locType == cmFileBasedProfile) {
+ FSRef newRef;
+ UInt8 path[256] = "";
+
+ /* Note that there is no non-deprecated equivalent to this. */
+ /* Apple need to remove the cmFileBasedProfile type from the */
+ /* CMProfileLocation to do away with it. */
+ if (FSpMakeFSRef(&ploc->u.fileLoc.spec, &newRef) == noErr) {
+ OSStatus stus;
+ if ((stus = FSRefMakePath(&newRef, path, 256)) == 0 || stus == fnfErr)
+ return strdup((char *)path);
+ return NULL;
+ }
+ } else if (ploc->locType == cmPathBasedProfile) {
+ return strdup(ploc->u.pathLoc.path);
+ }
+ return NULL;
+}
+
+/* Ugh! ColorSync doesn't take care of endian issues !! */
+static void cs_w32(unsigned long *p, unsigned long val) {
+ ((char *)p)[0] = (char)(val >> 24);
+ ((char *)p)[1] = (char)(val >> 16);
+ ((char *)p)[2] = (char)(val >> 8);
+ ((char *)p)[3] = (char)(val);
+}
+
+static void cs_w16(unsigned short *p, unsigned short val) {
+ ((char *)p)[0] = (char)(val >> 8);
+ ((char *)p)[1] = (char)(val);
+}
+
+#endif /* < 10.6 */
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+
+/* There doesn't seem to be any means of determining the locations */
+/* of profiles using current OS X API's, so we simply hard code them. */
+/* This makes the older code easier too. */
+
+#define COLORSYNC_DIR_NETWORK "/Network/Library/ColorSync/Profiles/"
+#define COLORSYNC_DIR_SYSTEM "/System/Library/ColorSync/Profiles/"
+#define COLORSYNC_DIR_LOCAL "/Library/ColorSync/Profiles/"
+#define COLORSYNC_DIR_USER "/Library/ColorSync/Profiles/"
+
+/* Given a profile name and a scope, return the path to the */
+/* installed profile. free the returned string when done. */
+/* Returns NULL on error */
+static char *iprof_path(p_scope scope, char *fname) {
+ char *home = "", *dirname, *basename, *rv = NULL;
+ int tlen = 0;
+
+ /* Locate the base filename in the fname */
+ for (basename = fname + strlen(fname); ; basename--) {
+ if (basename <= fname || basename[-1] == '/')
+ break;
+ }
+
+ /* NSFileManager's URLForDirectory: etc. doesn't have ColorSync, */
+ /* so we have no choice but to hard code the paths */
+ if (scope == p_scope_network)
+ dirname = COLORSYNC_DIR_NETWORK;
+ else if (scope == p_scope_system)
+ dirname = COLORSYNC_DIR_SYSTEM;
+ else if (scope == p_scope_local)
+ dirname = COLORSYNC_DIR_LOCAL;
+ else {
+ dirname = COLORSYNC_DIR_USER;
+ if ((home = getenv("HOME")) == NULL){
+ return NULL;
+ }
+ }
+
+ tlen = strlen(home) + strlen(dirname) + strlen(basename) + 1;
+ if ((rv = malloc(tlen)) == NULL) {
+ return NULL;
+ }
+
+ strcpy(rv, home);
+ strcat(rv, dirname);
+ strcat(rv, basename);
+
+ return rv;
+}
+
+/* Callback */
+typedef struct {
+ CFUUIDRef dispuuid; /* UUID to match */
+ CFStringRef id; /* ProfileId */
+ CFURLRef url; /* URL to return */
+} diter_cntx_t;
+
+bool diter_callback(CFDictionaryRef dict, void *cntx) {
+ diter_cntx_t *cx = (diter_cntx_t *)cntx;
+ CFStringRef str;
+ CFUUIDRef uuid;
+ CFBooleanRef iscur;
+
+ if ((str = CFDictionaryGetValue(dict, kColorSyncDeviceClass)) == NULL) {
+ debugrr("Failed to get kColorSyncDeviceClass\n");
+ return true;
+ }
+ if (!CFEqual(str, kColorSyncDisplayDeviceClass)) {
+ return true;
+ }
+ if ((uuid = CFDictionaryGetValue(dict, kColorSyncDeviceID)) == NULL) {
+ debugrr("Failed to get kColorSyncDeviceID\n");
+ return true;
+ }
+ if (!CFEqual(uuid, cx->dispuuid)) {
+ return true;
+ }
+ if ((iscur = CFDictionaryGetValue(dict, kColorSyncDeviceProfileIsCurrent)) == NULL) {
+ debugrr("Failed to get kColorSyncDeviceProfileIsCurrent\n");
+ return true;
+ }
+ if (!CFBooleanGetValue(iscur)) {
+ return true;
+ }
+
+ /* get the URL */
+ if ((cx->id = CFDictionaryGetValue(dict, kColorSyncDeviceProfileID)) == NULL) {
+ debugrr("Failed to get current profile ID\n");
+ return true;
+ }
+ if ((cx->url = CFDictionaryGetValue(dict, kColorSyncDeviceProfileURL)) == NULL) {
+ debugrr("Failed to get current profile URL\n");
+ return true;
+ }
+ CFRetain(cx->id);
+ CFRetain(cx->url);
+
+ return false;
+}
+
+/* Return the url to the given displays current profile. */
+/* Return NULL on error. CFRelease when done. */
+/* Optionally return the ProfileID string */
+CFURLRef cur_profile_url(CFStringRef *idp, dispwin *p) {
+ diter_cntx_t cx;
+
+ if ((cx.dispuuid = CGDisplayCreateUUIDFromDisplayID(p->ddid)) == NULL) {
+ debugr2((errout,"CGDisplayCreateUUIDFromDisplayID() failed\n"));
+ return NULL;
+ }
+ cx.id = NULL;
+ cx.url = NULL;
+
+ ColorSyncIterateDeviceProfiles(diter_callback, (void *)&cx);
+
+ CFRelease(cx.dispuuid);
+
+ if (idp != NULL)
+ *idp = cx.id;
+ else
+ CFRelease(cx.id);
+ return cx.url;
+}
+
+/* Convert a URL into a local POSIX path string */
+/* Return NULL on error. Free returned string when done. */
+char *url_to_path(CFURLRef url) {
+ CFStringRef urlstr;
+ CFIndex bufSize;
+ char *dpath = NULL; /* return value */
+
+ urlstr = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
+ bufSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(urlstr),
+ kCFStringEncodingUTF8) + 1;
+ if ((dpath = malloc(bufSize)) == NULL) {
+ debugrr("url_to_path: malloc failed\n");
+ CFRelease(urlstr);
+ return NULL;
+ }
+ if (!CFStringGetCString(urlstr, dpath, bufSize, kCFStringEncodingUTF8)) {
+ debugrr("url_to_path: CFStringGetCString failed\n");
+ CFRelease(urlstr);
+ return NULL;
+ }
+ CFRelease(urlstr);
+
+ return dpath;
+}
+
+/* Return information about the given displays current profile */
+/* Return NULL on error. Free returned string when done. */
+char *cur_profile(dispwin *p) {
+ CFURLRef url;
+ char *dpath = NULL; /* return value */
+
+ if ((url = cur_profile_url(NULL, p)) == NULL) {
+ debugr2((errout,"cur_profile failed to find current profile\n"));
+ return NULL;
+ }
+
+ dpath = url_to_path(url);
+
+ CFRelease(url);
+
+ return dpath;
+}
+
+#endif /* >= 10.6 */
+
+#endif /* __APPLE__ */
+
+/* Set the RAMDAC values. */
+/* Return nz if not possible */
+/* Return 2 for OS X when the current profile is a system profile */
+static int dispwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
+ int i, j;
+
+#ifdef NT
+ WORD vals[3][256]; /* 16 bit elements */
+
+ debugr("dispwin_set_ramdac called\n");
+
+#ifdef NEVER /* Doesn't seem to return correct information on win2K systems */
+ if ((GetDeviceCaps(p->hdc, COLORMGMTCAPS) & CM_GAMMA_RAMP) == 0) {
+ debugr("dispwin_set_ramdac failed on GetDeviceCaps(CM_GAMMA_RAMP)\n");
+ return 1;
+ }
+#endif
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ double vv = r->v[j][i];
+ if (vv < 0.0)
+ vv = 0.0;
+ else if (vv > 1.0)
+ vv = 1.0;
+ vals[j][i] = (int)(65535.0 * vv + 0.5);
+ }
+ }
+
+ if (SetDeviceGammaRamp(p->hdc, vals) == 0) {
+ debugr2((errout,"dispwin_set_ramdac failed on SetDeviceGammaRamp() with error %d\n",GetLastError()));
+ return 1;
+ }
+#endif /* NT */
+
+#ifdef __APPLE__
+ { /* Transient first */
+ CGGammaValue vals[3][16384];
+
+ debugr("dispwin_set_ramdac called\n");
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ double vv = r->v[j][i];
+ if (vv < 0.0)
+ vv = 0.0;
+ else if (vv > 1.0)
+ vv = 1.0;
+ vals[j][i] = vv;
+ }
+ }
+
+ if (CGSetDisplayTransferByTable(p->ddid, r->nent, vals[0], vals[1], vals[2]) != 0) {
+ debugr("CGSetDisplayTransferByTable failed\n");
+ return 1;
+ }
+
+ }
+
+ /* In theory IOFBSetGamma() might work - but maybe it needs root, and won't */
+ /* sync with OS X's view of what's loaded. */
+
+ /* By default the OSX RAMDAC access is transient, lasting only as long */
+ /* as the process setting it. To set a temporary but persistent beyond this process */
+ /* calibration, we fake up a profile and install it in such a way that it will disappear, */
+ /* restoring the previous display profile whenever the current ColorSync display profile */
+ /* is restored to the screen. NOTE that this trick will fail if it is not possible */
+ /* to rename the currently selected profile file, ie. because it is a system profile. */
+ /* [ Would a workaround be to use a link, or copy of the system file ? ] */
+ if (persist)
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ if (persist) { /* Persistent */
+ int rv = 0;
+ CFStringRef id;
+ CFURLRef url;
+ char *tpath; /* Temporary profiles/original profiles path */
+ char *ppath; /* Current/renamed profiles path */
+ icmFile *rd_fp, *wr_fp;
+ icc *icco;
+ CFUUIDRef dispuuid;
+ CFStringRef keys[1];
+ CFURLRef values[1];
+ CFDictionaryRef dict;
+
+ debugr("Set_ramdac persist\n");
+
+ /* Get the current installed profile */
+ if ((url = cur_profile_url(&id, p)) == NULL) {
+ debugr2((errout,"cur_profile_url failed for current profile\n"));
+ return 1;
+ }
+ if ((tpath = url_to_path(url)) == NULL) {
+ debugr2((errout,"url_to_path failed for current profile\n"));
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ debugr2((errout, "Current profile path = '%s'\n",tpath));
+
+ /* Create a patched version with our calibration: */
+ /* (Hmm. I think icclib will cope with V4 OK) */
+
+ /* Open up the profile for reading */
+ if ((rd_fp = new_icmFileStd_name(tpath,"r")) == NULL) {
+ debugr2((errout,"Failed to open profile '%s'\n",tpath));
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ if ((icco = new_icc()) == NULL) {
+ debugr2((errout,"Creation of ICC object failed\n"));
+ rd_fp->del(rd_fp);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ /* Read header etc. */
+ if ((rv = icco->read(icco,rd_fp,0)) != 0) {
+ debugr2((errout,"%d, %s",rv,icco->err));
+ icco->del(icco);
+ rd_fp->del(rd_fp);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+ /* Read every tag */
+ if (icco->read_all_tags(icco) != 0) {
+ debugr2((errout,"Unable to read all tags: %d, %s",icco->errc,icco->err));
+ icco->del(icco);
+ rd_fp->del(rd_fp);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ rd_fp->del(rd_fp); rd_fp = NULL;
+
+ /* Replace the description */
+ {
+ icmTextDescription *wo;
+ char *dst = "Dispwin Temp";
+
+ if (icco->find_tag(icco, icSigProfileDescriptionTag) == 0) {
+ if (icco->delete_tag(icco, icSigProfileDescriptionTag) != 0) {
+ debugr2((errout,"Unable to delete Description tag: %d, %s",icco->errc,icco->err));
+ icco->del(icco);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+ }
+
+ if ((wo = (icmTextDescription *)icco->add_tag(
+ icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL) {
+ debugr2((errout,"Unable to add Description tag: %d, %s",icco->errc,icco->err));
+ icco->del(icco);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Replace the vcgt */
+ {
+ int c,i;
+ icmVideoCardGamma *wo;
+
+ if (icco->find_tag(icco, icSigVideoCardGammaTag) == 0) {
+ if (icco->delete_tag(icco, icSigVideoCardGammaTag) != 0) {
+ debugr2((errout,"Unable to delete VideoCardGamma tag: %d, %s",icco->errc,icco->err));
+ icco->del(icco);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+ }
+
+ if ((wo = (icmVideoCardGamma *)icco->add_tag(icco, icSigVideoCardGammaTag,
+ icSigVideoCardGammaType)) == NULL) {
+ debugr2((errout,"Unable to add VideoCardGamma tag: %d, %s",icco->errc,icco->err));
+ icco->del(icco);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ wo->tagType = icmVideoCardGammaTableType;
+ wo->u.table.channels = 3; /* rgb */
+ wo->u.table.entryCount = r->nent; /* number of calibration entries */
+ wo->u.table.entrySize = 2; /* 16 bits */
+ wo->allocate((icmBase*)wo);
+
+ for (i = 0; i < r->nent; i++) {
+ for (j = 0; j < 3; j++) {
+ double vv = r->v[j][i];
+ int ivv;
+ if (vv < 0.0)
+ vv = 0.0;
+ else if (vv > 1.0)
+ vv = 1.0;
+ ((unsigned short*)wo->u.table.data)[r->nent * j + i] = (int)(vv * 65535.0 + 0.5);
+ }
+ }
+ }
+
+ if ((ppath = malloc(strlen(tpath) + 6)) == NULL) {
+ debugr2((errout,"malloc failed for display '%s'\n",p->name));
+ icco->del(icco);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+ strcpy(ppath, tpath);
+ strcat(ppath,".orig");
+
+ /* Rename the currently installed profile temporarily. */
+ /* This will fail if current profile is a system profile and not writable by the user. */
+ /* This could be worked around by cloning the system profile to the user */
+ /* area and installing it before modifiying it. */
+ if (rename(tpath, ppath) != 0) {
+ debugr2((errout,"Unable to rename '%s' to '%s'\n",tpath,ppath));
+ icco->del(icco);
+ free(ppath);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 2;
+ }
+
+ /* Rename worked */
+
+ debugr2((errout,"Renamed current profile '%s' to '%s'\n",tpath,ppath));
+
+ /* Save the modified profile to the original profile name */
+ if ((wr_fp = new_icmFileStd_name(tpath,"w")) == NULL) {
+ debugr2((errout,"Failed to open '%s' for writing\n",tpath));
+ free(ppath);
+ icco->del(icco);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ if ((rv = icco->write(icco,wr_fp,0)) != 0) {
+ debugr2((errout,"Write file: %d, %s",rv,icco->err));
+ free(ppath);
+ wr_fp->del(wr_fp);
+ icco->del(icco);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ icco->del(icco);
+ wr_fp->del(wr_fp);
+
+ /* Update to the "current" profile, which is actually the modified profile */
+ if ((dispuuid = CGDisplayCreateUUIDFromDisplayID(p->ddid)) == NULL) {
+ debugr2((errout,"CGDisplayCreateUUIDFromDisplayID() failed\n"));
+ free(ppath);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+
+ keys[0] = id;
+ values[0] = url;
+
+ if ((dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys,
+ (const void **)&values, 1, NULL, NULL)) == NULL) {
+ debugr2((errout,"CFDictionaryCreate() failed\n"));
+ CFRelease(dispuuid);
+ free(ppath);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+ if (!ColorSyncDeviceSetCustomProfiles(kColorSyncDisplayDeviceClass, dispuuid, dict)) {
+ debugr2((errout,"ColorSyncDeviceSetCustomProfiles() failed\n"));
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ free(ppath);
+ free(tpath);
+ CFRelease(id);
+ CFRelease(url);
+ return 1;
+ }
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ CFRelease(id);
+ CFRelease(url);
+
+ /* Delete the temporary profile */
+ unlink(tpath);
+
+ /* Rename the current profile back to it's correct name */
+ if (rename(ppath, tpath) != 0) {
+ debugr2((errout,"Renaming existing profile '%s' failed\n",ppath));
+ return 1;
+ }
+ debugr2((errout,"Restored '%s' back to '%s'\n",ppath,tpath));
+ free(ppath);
+ free(tpath);
+ }
+#else /* < 10.6 */
+ if (persist) { /* Persistent */
+ CMError ev;
+ CMProfileRef prof; /* Current AVID profile */
+ CMProfileLocation ploc; /* Current profile location */
+ UInt32 plocsz = sizeof(CMProfileLocation);
+ char *ppath; /* Current/renamed profiles path */
+ char *tpath; /* Temporary profiles/original profiles path */
+ CMProfileRef tprof; /* Temporary profile */
+ CMProfileLocation tploc; /* Temporary profile */
+ CMVideoCardGammaType *vcgt = NULL; /* vcgt tag */
+ int size;
+ int i, j;
+
+ debugr("Set_ramdac persist\n");
+
+ /* Get the current installed profile */
+ if ((ev = CMGetProfileByAVID((CMDisplayIDType)p->ddid, &prof)) != noErr) {
+ debugr2((errout,"CMGetProfileByAVID() failed for display '%s' with error %d\n",p->name,ev));
+ return 1;
+ }
+
+ /* Get the current installed profile's location */
+ if ((ev = NCMGetProfileLocation(prof, &ploc, &plocsz)) != noErr) {
+ debugr2((errout,"NCMGetProfileLocation() failed for display '%s' with error %d\n",p->name,ev));
+ return 1;
+ }
+
+ debugr2((errout, "Current profile path = '%s'\n",plocpath(&ploc)));
+
+ if ((tpath = plocpath(&ploc)) == NULL) {
+ debugr2((errout,"plocpath failed for display '%s'\n",p->name));
+ return 1;
+ }
+
+ if (strlen(tpath) > 255) {
+ debugr2((errout,"current profile path is too long\n"));
+ return 1;
+ }
+ if ((ppath = malloc(strlen(tpath) + 6)) == NULL) {
+ debugr2((errout,"malloc failed for display '%s'\n",p->name));
+ free(tpath);
+ return 1;
+ }
+ strcpy(ppath,tpath);
+ strcat(ppath,".orig");
+
+ /* Rename the currently installed profile temporarily */
+ if (rename(tpath, ppath) != 0) {
+ debugr2((errout,"Renaming existing profile '%s' failed\n",ppath));
+ return 2;
+ }
+ debugr2((errout,"Renamed current profile '%s' to '%s'\n",tpath,ppath));
+
+ /* Make a copy of the renamed current profile back to it's true name */
+ tploc.locType = cmPathBasedProfile;
+ strncpy(tploc.u.pathLoc.path, tpath, 255);
+ tploc.u.pathLoc.path[255] = '\000';
+
+ /* Make the temporary copy */
+ if ((ev = CMCopyProfile(&tprof, &tploc, prof)) != noErr) {
+ debugr2((errout,"CMCopyProfile() failed for display '%s' with error %d\n",p->name,ev));
+ CMCloseProfile(prof);
+ unlink(tpath);
+ rename(ppath, tpath);
+ return 1;
+ }
+ CMCloseProfile(prof);
+
+ if ((ev = CMSetProfileDescriptions(tprof, "Dispwin Temp", 13, NULL, 0, NULL, 0)) != noErr) {
+ debugr2((errout,"cmVideoCardGammaTag`() failed for display '%s' with error %d\n",p->name,ev));
+ CMCloseProfile(tprof);
+ unlink(tpath);
+ rename(ppath, tpath);
+ return 1;
+ }
+
+ /* Change the description and set the vcgt tag to the calibration */
+ if ((vcgt = malloc(size = (sizeof(CMVideoCardGammaType) - 1 + 3 * 2 * r->nent))) == NULL) {
+ debugr2((errout,"malloc of vcgt tag failed for display '%s' with error %d\n",p->name,ev));
+ CMCloseProfile(tprof);
+ unlink(tpath);
+ rename(ppath, tpath);
+ return 1;
+ }
+ cs_w32(&vcgt->typeDescriptor, cmSigVideoCardGammaType);
+ cs_w32(&vcgt->gamma.tagType, cmVideoCardGammaTableType); /* Table, not formula */
+ cs_w16(&vcgt->gamma.u.table.channels, 3);
+ cs_w16(&vcgt->gamma.u.table.entryCount, r->nent);
+ cs_w16(&vcgt->gamma.u.table.entrySize, 2);
+
+ for (i = 0; i < r->nent; i++) {
+ for (j = 0; j < 3; j++) {
+ double vv = r->v[j][i];
+ int ivv;
+ if (vv < 0.0)
+ vv = 0.0;
+ else if (vv > 1.0)
+ vv = 1.0;
+ ivv = (int)(vv * 65535.0 + 0.5);
+ cs_w16(((unsigned short *)vcgt->gamma.u.table.data) + ((j * r->nent) + i), ivv);
+ }
+ }
+
+ /* Replace or add a vcgt tag */
+ if ((ev = CMSetProfileElement(tprof, cmVideoCardGammaTag, size, vcgt)) != noErr) {
+ debugr2((errout,"CMSetProfileElement vcgt tag failed with error %d\n",ev));
+ free(vcgt);
+ CMCloseProfile(tprof);
+ unlink(tpath);
+ rename(ppath, tpath);
+ return 1;
+ }
+ free(vcgt);
+
+ if ((ev = CMUpdateProfile(tprof)) != noErr) {
+ debugr2((errout,"CMUpdateProfile failed with error %d\n",ev));
+ CMCloseProfile(tprof);
+ unlink(tpath);
+ rename(ppath, tpath);
+ return 1;
+ }
+
+ /* Make temporary file the current profile - updates LUTs */
+ if ((ev = CMSetProfileByAVID((CMDisplayIDType)p->ddid, tprof)) != noErr) {
+ debugr2((errout,"CMSetProfileByAVID() failed for display '%s' with error %d\n",p->name,ev));
+ CMCloseProfile(tprof);
+ unlink(tpath);
+ rename(ppath, tpath);
+ return 1;
+ }
+ CMCloseProfile(tprof);
+ debugr2((errout,"Set display to use temporary profile '%s'\n",tpath));
+
+ /* Delete the temporary profile */
+ unlink(tpath);
+
+ /* Rename the current profile back to it's correct name */
+ if (rename(ppath, tpath) != 0) {
+ debugr2((errout,"Renaming existing profile '%s' failed\n",ppath));
+ return 1;
+ }
+ debugr2((errout,"Restored '%s' back to '%s'\n",ppath,tpath));
+ }
+#endif /* < 10.6 */
+
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11)
+ unsigned short vals[3][16384];
+
+ debugr("dispwin_set_ramdac called\n");
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ double vv = r->v[j][i];
+ if (vv < 0.0)
+ vv = 0.0;
+ else if (vv > 1.0)
+ vv = 1.0;
+ vals[j][i] = (int)(vv * 65535.0 + 0.5);
+ }
+ }
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ if (p->crtc != 0) { /* Using Xrandr 1.2 */
+ XRRCrtcGamma *crtcgam;
+
+ debugr("Setting gamma using Randr 1.2\n");
+
+ if ((crtcgam = XRRAllocGamma(r->nent)) == NULL) {
+ debugr(" XRRAllocGamma failed\n");
+ return 1;
+ }
+
+ for (i = 0; i < r->nent; i++) {
+ crtcgam->red[i] = vals[0][i];
+ crtcgam->green[i] = vals[1][i];
+ crtcgam->blue[i] = vals[2][i];
+ }
+
+ XRRSetCrtcGamma(p->mydisplay, p->crtc, crtcgam);
+ XSync(p->mydisplay, False); /* Flush the change out */
+
+ XRRFreeGamma(crtcgam);
+
+ } else
+#endif /* randr >= V 1.2 */
+ {
+ /* Some propietary multi-screen drivers (ie. TwinView & MergedFB) */
+ /* don't implement the XVidMode extenstion properly. */
+ if (XSetErrorHandler(null_error_handler) == 0) {
+ debugr("get_displays failed on XSetErrorHandler\n");
+ return 1;
+ }
+ if (XF86VidModeSetGammaRamp(p->mydisplay, p->myrscreen, r->nent, vals[0], vals[1], vals[2]) == 0) {
+ XSetErrorHandler(NULL);
+ debugr("XF86VidModeSetGammaRamp failed\n");
+ return 1;
+ }
+ XSync(p->mydisplay, False); /* Flush the change out */
+ XSetErrorHandler(NULL);
+ }
+#endif /* UNXI X11 */
+
+ debugr("XF86VidModeSetGammaRamp returning OK\n");
+ return 0;
+}
+
+
+/* Clone ourselves */
+static ramdac *dispwin_clone_ramdac(ramdac *r) {
+ ramdac *nr;
+ int i, j;
+
+ debug("dispwin_clone_ramdac called\n");
+
+ /* Allocate a ramdac */
+ if ((nr = (ramdac *)calloc(sizeof(ramdac), 1)) == NULL) {
+ return NULL;
+ }
+
+ *nr = *r; /* Structrure copy */
+
+ for (j = 0; j < 3; j++) {
+
+ if ((nr->v[j] = (double *)calloc(sizeof(double), r->nent)) == NULL) {
+ for (j--; j >= 0; j--)
+ free(nr->v[j]);
+ free(nr);
+ return NULL;
+ }
+ }
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ nr->v[j][i] = r->v[j][i];
+ }
+ }
+
+ debug("clone is done\n");
+ return nr;
+}
+
+/* Set the ramdac values to linear */
+static void dispwin_setlin_ramdac(ramdac *r) {
+ int i, j;
+
+ debug("dispwin_setlin_ramdac called\n");
+
+ for (i = 0; i < r->nent; i++) {
+ double val = i/(r->nent - 1.0);
+ for (j = 0; j < 3; j++) {
+ r->v[j][i] = val;
+ }
+ }
+}
+
+/* We're done with a ramdac structure */
+static void dispwin_del_ramdac(ramdac *r) {
+ int j;
+
+ debug("dispwin_del_ramdac called\n");
+
+ for (j = 0; j < 3; j++) {
+ free(r->v[j]);
+ }
+
+ free(r);
+}
+
+/* ----------------------------------------------- */
+/* Useful function for X11 profie atom settings */
+
+#if defined(UNIX_X11)
+/* Return NZ on error */
+static int set_X11_atom(dispwin *p, char *fname) {
+ FILE *fp;
+ unsigned long psize, bread;
+ unsigned char *atomv;
+
+ debugr("Setting _ICC_PROFILE property\n");
+
+ /* Read in the ICC profile, then set the X11 atom value */
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(fname,"rb")) == NULL)
+#else
+ if ((fp = fopen(fname,"r")) == NULL)
+#endif
+ {
+ debugr2((errout,"Can't open file '%s'\n",fname));
+ return 1;
+ }
+
+ /* Figure out how big it is */
+ if (fseek(fp, 0, SEEK_END)) {
+ debugr2((errout,"Seek '%s' to EOF failed\n",fname));
+ return 1;
+ }
+ psize = (unsigned long)ftell(fp);
+
+ if (fseek(fp, 0, SEEK_SET)) {
+ debugr2((errout,"Seek '%s' to SOF failed\n",fname));
+ return 1;
+ }
+
+ if ((atomv = (unsigned char *)malloc(psize)) == NULL) {
+ debugr2((errout,"Failed to allocate buffer for profile '%s'\n",fname));
+ return 1;
+ }
+
+ if ((bread = fread(atomv, 1, psize, fp)) != psize) {
+ debugr2((errout,"Failed to read profile '%s' into buffer\n",fname));
+ return 1;
+ }
+
+ fclose(fp);
+
+ XChangeProperty(p->mydisplay, RootWindow(p->mydisplay, 0), p->icc_atom,
+ XA_CARDINAL, 8, PropModeReplace, atomv, psize);
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ if (p->icc_out_atom != 0) {
+ /* If Xrandr 1.2, set property on output */
+ /* This seems to fail on some servers. Ignore the error ? */
+ if (XSetErrorHandler(null_error_handler) == 0) {
+ debugr("get_displays failed on XSetErrorHandler\n");
+ return 1;
+ }
+ g_error_handler_triggered = 0;
+ XRRChangeOutputProperty(p->mydisplay, p->output, p->icc_out_atom,
+ XA_CARDINAL, 8, PropModeReplace, atomv, psize);
+ if (g_error_handler_triggered != 0) {
+ debugr("XRRChangeOutputProperty failed\n");
+ warning("Unable to set _ICC_PROFILE property on output");
+ }
+ XSync(p->mydisplay, False); /* Flush the change out */
+ XSetErrorHandler(NULL);
+ }
+#endif /* randr >= V 1.2 */
+ free(atomv);
+
+ return 0;
+}
+#endif /* UNXI X11 */
+
+/* ----------------------------------------------- */
+/* Install a display profile and make */
+/* it the default for this display. */
+/* Set the display to the calibration in the profile */
+/* (r == NULL if no calibration) */
+/* (We assume that the caller has checked that it's an ICC profile) */
+/* Return nz if failed */
+int dispwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
+#ifdef NT
+ {
+ char *fullpath;
+ char *basename;
+ char colpath[MAX_PATH];
+ unsigned long colpathlen = MAX_PATH;
+ WCS_PROFILE_MANAGEMENT_SCOPE wcssc;
+ unsigned short *wpath, *wbname, *wmonid;
+
+ debugr2((errout,"dispwin_install_profile got '%s'\n",fname));
+
+ if (GetColorDirectory(NULL, colpath, &colpathlen) == 0) {
+ debugr2((errout,"Getting color directory failed\n"));
+ return 1;
+ }
+
+ if ((fullpath = _fullpath(NULL, fname, 0)) == NULL) {
+ debugr2((errout,"_fullpath() failed\n"));
+ return 1;
+ }
+
+ if ((basename = PathFindFileName(fullpath)) == NULL) {
+ debugr2((errout,"Locating base name in '%s' failed\n",fname));
+ free(fullpath);
+ return 1;
+ }
+
+ if ((strlen(colpath) + strlen(basename) + 2) > MAX_PATH) {
+ debugr2((errout,"Installed profile path too long\n"));
+ free(fullpath);
+ return 1;
+ }
+ strcat(colpath, "\\");
+ strcat(colpath, basename);
+
+ /* Setup in case we're on Vista */
+ if (scope == p_scope_user)
+ wcssc = WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER;
+ else
+ wcssc = WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE;
+
+ if ((wpath = char2wchar(fullpath)) == NULL) {
+ debugr2((errout,"char2wchar failed\n"));
+ free(fullpath);
+ return 1;
+ }
+
+ if ((wbname = char2wchar(basename)) == NULL) {
+ debugr2((errout,"char2wchar failed\n"));
+ free(wpath);
+ free(fullpath);
+ return 1;
+ }
+
+ if ((wmonid = char2wchar(p->monid)) == NULL) {
+ debugr2((errout,"char2wchar failed\n"));
+ free(wbname);
+ free(wpath);
+ free(fullpath);
+ return 1;
+ }
+
+ debugr2((errout,"Installing '%s'\n",fname));
+
+ /* Install doesn't replace an existing installed profile, */
+ /* so we need to try and delete this profile first */
+ if (pWcsDisassociateColorProfileFromDevice != NULL) {
+ (*pWcsDisassociateColorProfileFromDevice)(wcssc, wbname, wmonid);
+ } else {
+ DisassociateColorProfileFromDevice(NULL, basename, p->monid);
+ }
+ if (UninstallColorProfile(NULL, basename, TRUE) == 0) {
+ /* UninstallColorProfile fails on Win2K */
+ _unlink(colpath);
+ }
+
+ if (InstallColorProfile(NULL, fullpath) == 0) {
+ debugr2((errout,"InstallColorProfile() failed for file '%s' with error %d\n",fname,GetLastError()));
+ free(wmonid);
+ free(wbname);
+ free(wpath);
+ free(fullpath);
+ return 1;
+ }
+
+ debugr2((errout,"Associating '%s' with '%s'\n",fullpath,p->monid));
+ if (pWcsAssociateColorProfileWithDevice != NULL) {
+ debugr("Using Vista Associate\n");
+ if ((*pWcsAssociateColorProfileWithDevice)(wcssc, wpath, wmonid) == 0) {
+ debugr2((errout,"WcsAssociateColorProfileWithDevice() failed for file '%s' with error %d\n",fullpath,GetLastError()));
+ free(wmonid);
+ free(wbname);
+ free(wpath);
+ free(fullpath);
+ return 1;
+ }
+ } else {
+ if (AssociateColorProfileWithDevice(NULL, fullpath, p->monid) == 0) {
+ debugr2((errout,"AssociateColorProfileWithDevice() failed for file '%s' with error %d\n",fullpath,GetLastError()));
+ free(wmonid);
+ free(wbname);
+ free(wpath);
+ free(fullpath);
+ return 1;
+ }
+ }
+
+ free(wmonid);
+ free(wbname);
+ free(wpath);
+ free(fullpath);
+ /* The default profile will be the last one associated */
+
+ /* MSWindows doesn't generally set the display to the current profile calibration, */
+ /* so we do it. */
+ if (p->set_ramdac(p,r,1))
+ error("Failed to set VideoLUT");
+
+ return 0;
+ }
+#endif /* NT */
+
+/* For Linux and OS X, make sure we don't create a file with the wrong owner */
+#if defined(UNIX)
+ /* If we're creating a user profile and running as root sudo */
+ if (scope == p_scope_user && geteuid() == 0) {
+ char *uids, *gids;
+ int uid, gid;
+
+ debugr("We're setting a user profile running as root - run as user\n");
+ if ((uids = getenv("SUDO_UID")) != NULL
+ && (gids = getenv("SUDO_GID")) != NULL) {
+ uid = atoi(uids);
+ gid = atoi(gids);
+ if (setegid(gid) || seteuid(uid)) {
+ debugr("seteuid or setegid failed\n");
+ }
+ debug2((errout,"Set euid %d and egid %d\n",uid,gid));
+ }
+ /* If setting local system profile and not effective root, but sudo */
+ } else if (scope != p_scope_user && getuid() == 0 && geteuid() != 0) {
+ if (getenv("SUDO_UID") != NULL
+ && getenv("SUDO_GID") != NULL) {
+
+ debugr("We're setting a system profile running as user - revert to root\n");
+ setegid(getgid());
+ seteuid(getuid());
+ }
+ }
+#endif /* OS X || Linux */
+
+#ifdef __APPLE__
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ {
+ char *dpath; /* Install file path */
+ CFUUIDRef dispuuid;
+ CFStringRef cfprofpath;
+ CFStringRef keys[1];
+ CFURLRef values[1];
+ CFDictionaryRef dict;
+
+ if ((dispuuid = CGDisplayCreateUUIDFromDisplayID(p->ddid)) == NULL) {
+ debugr2((errout,"CGDisplayCreateUUIDFromDisplayID() failed\n"));
+ return 1;
+ }
+
+ /* Determine the location the profile will be installed into */
+ if ((dpath = iprof_path(scope, fname)) == NULL) {
+ debugr2((errout,"iprof_path() failed\n"));
+ CFRelease(dispuuid);
+ return 1;
+ }
+
+ debugr2((errout,"Source profile '%s'\n",fname));
+ debugr2((errout,"Destination profile '%s'\n",dpath));
+
+ /* Copy the new profile to the destination */
+ if (copyfile(fname, dpath, NULL, COPYFILE_ALL) != 0) {
+ debugr2((errout,"copyfile failed\n"));
+ free(dpath);
+ CFRelease(dispuuid);
+ return 1;
+ }
+
+ /* Register it with the OS and make it the default */
+ if ((cfprofpath = CFStringCreateWithCString(kCFAllocatorDefault, dpath,
+ kCFStringEncodingUTF8)) == NULL) {
+ debugr2((errout,"CFStringCreateWithCString() failed\n"));
+ free(dpath);
+ CFRelease(dispuuid);
+ return 1;
+ }
+ free(dpath); dpath = NULL;
+
+ keys[0] = kColorSyncDeviceDefaultProfileID;
+ if ((values[0] = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfprofpath,
+ kCFURLPOSIXPathStyle, false)) == NULL) {
+ debugr2((errout,"CFURLCreateWithFileSystemPath() failed\n"));
+ CFRelease(cfprofpath);
+ CFRelease(dispuuid);
+ return 1;
+ }
+
+ if ((dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys,
+ (const void **)&values, 1, NULL, NULL)) == NULL) {
+ debugr2((errout,"CFDictionaryCreate() failed\n"));
+ CFRelease(values[0]);
+ CFRelease(cfprofpath);
+ CFRelease(dispuuid);
+ return 1;
+ }
+ if (!ColorSyncDeviceSetCustomProfiles(kColorSyncDisplayDeviceClass, dispuuid, dict)) {
+ debugr2((errout,"ColorSyncDeviceSetCustomProfiles() failed\n"));
+ CFRelease(dict);
+ CFRelease(values[0]);
+ CFRelease(cfprofpath);
+ CFRelease(dispuuid);
+ return 1;
+ }
+ CFRelease(dict);
+ CFRelease(values[0]);
+ CFRelease(cfprofpath);
+ CFRelease(dispuuid);
+
+ return 0;
+ }
+#else /* 10.6 and prior */
+ // Switch to using iprof_path() to simplify ?
+ {
+ CMError ev;
+ short vref;
+ FSRef dirref;
+ char dpath[FILENAME_MAX];
+ char *basename;
+
+ CMProfileLocation ploc; /* Source profile location */
+ CMProfileRef prof; /* Source profile */
+ CMProfileLocation dploc; /* Destinaion profile location */
+ CMProfileRef dprof; /* Destinaion profile */
+
+ if (scope == p_scope_network)
+ vref = kNetworkDomain;
+ else if (scope == p_scope_system)
+ vref = kSystemDomain;
+ else if (scope == p_scope_local)
+ vref = kLocalDomain;
+ else
+ vref = kUserDomain;
+
+ /* Locate the appropriate ColorSync path */
+ if ((ev = FSFindFolder(vref, kColorSyncProfilesFolderType, kCreateFolder, &dirref)) != noErr) {
+ debugr2((errout,"FSFindFolder() failed with error %d\n",ev));
+ return 1;
+ }
+
+ /* Convert to POSIX path */
+ if ((ev = FSRefMakePath(&dirref, (unsigned char *)dpath, FILENAME_MAX)) != noErr) {
+ debugr2((errout,"FSRefMakePath failed with error %d\n",ev));
+ return 1;
+ }
+
+ /* Locate the base filename in the fname */
+ for (basename = fname + strlen(fname); ; basename--) {
+ if (basename <= fname || basename[-1] == '/')
+ break;
+ }
+
+ /* Append the basename to the ColorSync directory path */
+ if ((strlen(dpath) + strlen(basename) + 2) > FILENAME_MAX
+ || (strlen(dpath) + strlen(basename) + 2) > 256) {
+ debugr2((errout,"ColorSync dir + profile name too long\n"));
+ return 1;
+ }
+ strcat(dpath, "/");
+ strcat(dpath, basename);
+
+ debugr2((errout,"Source profile '%s'\n",fname));
+ debugr2((errout,"Destination profile '%s'\n",dpath));
+
+ /* Open the profile we want to install */
+ ploc.locType = cmPathBasedProfile;
+ strncpy(ploc.u.pathLoc.path, fname, 255);
+ ploc.u.pathLoc.path[255] = '\000';
+
+ if ((ev = CMOpenProfile(&prof, &ploc)) != noErr) {
+ debugr2((errout,"CMOpenProfile() failed for file '%s' with error %d\n",fname,ev));
+ return 1;
+ }
+
+ /* Delete any current profile */
+ unlink(dpath);
+
+ /* Make a copy of it to the ColorSync directory */
+ dploc.locType = cmPathBasedProfile;
+ strncpy(dploc.u.pathLoc.path, dpath, 255);
+ dploc.u.pathLoc.path[255] = '\000';
+
+ if ((ev = CMCopyProfile(&dprof, &dploc, prof)) != noErr) {
+ debugr2((errout,"CMCopyProfile() failed for file '%s' with error %d\n",dpath,ev));
+ return 1;
+ }
+
+ /* Make it the current profile - updates LUTs */
+ if ((ev = CMSetProfileByAVID((CMDisplayIDType)p->ddid, dprof)) != noErr) {
+ debugr2((errout,"CMSetProfileByAVID() failed for file '%s' with error %d\n",fname,ev));
+ return 1;
+ }
+ CMCloseProfile(prof);
+ CMCloseProfile(dprof);
+
+ return 0;
+ }
+#endif /* 10.6 and prior */
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11) && defined(USE_UCMM)
+ {
+ ucmm_error ev;
+ ucmm_scope sc;
+ FILE *fp;
+ unsigned long psize, bread;
+ unsigned char *atomv;
+ int rv;
+
+ if (scope == p_scope_network
+ || scope == p_scope_system
+ || scope == p_scope_local)
+ sc = ucmm_local_system;
+ else
+ sc = ucmm_user;
+
+ if ((ev = ucmm_install_monitor_profile(sc, p->edid, p->edid_len, p->name, fname)) != ucmm_ok) {
+ debugr2((errout,"Installing profile '%s' failed with error %d '%s'\n",fname,ev,ucmm_error_string(ev)));
+ return 1;
+ }
+
+ if ((rv = set_X11_atom(p, fname)) != 0) {
+ debugr2((errout,"Setting X11 atom failed"));
+ return 1;
+ }
+
+ /* X11 doesn't set the display to the current profile calibration, */
+ /* so we do it. */
+ if (p->set_ramdac(p,r,1)) {
+ debugr2((errout,"Failed to set VideoLUT"));
+ return 1;
+ }
+ return 0;
+ }
+#endif /* UNXI X11 */
+
+ return 1;
+}
+
+/* Un-Install a display profile */
+/* Return nz if failed, */
+/* 1 if not sucessfully deleted */
+/* 2 if profile not found */
+int dispwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
+#ifdef NT
+ {
+ char *fullpath;
+ char *basename;
+ char colpath[MAX_PATH];
+ unsigned long colpathlen = MAX_PATH;
+ WCS_PROFILE_MANAGEMENT_SCOPE wcssc;
+ unsigned short *wbname, *wmonid;
+
+ debugr2((errout,"Uninstalling '%s'\n", fname));
+
+ if (GetColorDirectory(NULL, colpath, &colpathlen) == 0) {
+ debugr2((errout,"Getting color directory failed\n"));
+ return 1;
+ }
+
+ if ((fullpath = _fullpath(NULL, fname, 0)) == NULL) {
+ debugr2((errout,"_fullpath() failed\n"));
+ return 1;
+ }
+
+ if ((basename = PathFindFileName(fullpath)) == NULL) {
+ debugr2((errout,"Locating base name in '%s' failed\n",fname));
+ free(fullpath);
+ return 1;
+ }
+
+ if ((strlen(colpath) + strlen(basename) + 2) > MAX_PATH) {
+ debugr2((errout,"Installed profile path too long\n"));
+ free(fullpath);
+ return 1;
+ }
+ strcat(colpath, "\\");
+ strcat(colpath, basename);
+
+ /* Setup in case we're on Vista */
+ if (scope == p_scope_user)
+ wcssc = WCS_PROFILE_MANAGEMENT_SCOPE_CURRENT_USER;
+ else
+ wcssc = WCS_PROFILE_MANAGEMENT_SCOPE_SYSTEM_WIDE;
+
+ if ((wbname = char2wchar(basename)) == NULL) {
+ debugr2((errout,"char2wchar failed\n"));
+ free(fullpath);
+ return 1;
+ }
+
+ if ((wmonid = char2wchar(p->monid)) == NULL ) {
+ debugr2((errout,"char2wchar failed\n"));
+ free(wbname);
+ free(fullpath);
+ return 1;
+ }
+
+ debugr2((errout,"Disassociating '%s' from '%s'\n",basename,p->monid));
+
+ if (pWcsDisassociateColorProfileFromDevice != NULL) {
+ debugr("Using Vista Disassociate\n");
+ /* Ignore error if profile is already disasociated or doesn't exist */
+ if ((*pWcsDisassociateColorProfileFromDevice)(wcssc, wbname, wmonid) == 0
+ && GetLastError() != 2015 && GetLastError() != 2011) {
+ debugr2((errout,"WcsDisassociateColorProfileWithDevice() failed for file '%s' with error %d\n",basename,GetLastError()));
+ free(wmonid);
+ free(wbname);
+ free(fullpath);
+ return 1;
+ }
+ } else {
+ /* Ignore error if profile is already disasociated or doesn't exist */
+ if (DisassociateColorProfileFromDevice(NULL, basename, p->monid) == 0
+ && GetLastError() != 2015 && GetLastError() != 2011) {
+ debugr2((errout,"DisassociateColorProfileWithDevice() failed for file '%s' with error %d\n",basename,GetLastError()));
+ free(wmonid);
+ free(wbname);
+ free(fullpath);
+ return 1;
+ }
+ }
+
+ if (UninstallColorProfile(NULL, basename, TRUE) == 0) {
+ /* This can happen when some other program has the profile open */
+ int ev;
+ struct _stat sbuf;
+ debugr2((errout,"Warning, uninstallColorProfile() failed for file '%s' with error %d\n", basename,GetLastError()));
+ free(wmonid);
+ free(wbname);
+ free(fullpath);
+ return 2;
+ }
+
+ free(wmonid);
+ free(wbname);
+ free(fullpath);
+
+ return 0;
+ }
+#endif /* NT */
+
+/* For Linux and OS X, make sure we don't create a file with the wrong owner */
+#if defined(UNIX)
+ /* If we're creating a user profile and running as root sudo */
+ if (scope == p_scope_user && geteuid() == 0) {
+ char *uids, *gids;
+ int uid, gid;
+
+ debugr("We're setting a user profile running as root - run as user\n");
+ if ((uids = getenv("SUDO_UID")) != NULL
+ && (gids = getenv("SUDO_GID")) != NULL) {
+ uid = atoi(uids);
+ gid = atoi(gids);
+ if (setegid(gid) || seteuid(uid)) {
+ debugr("seteuid or setegid failed\n");
+ }
+ debug2((errout,"Set euid %d and egid %d\n",uid,gid));
+ }
+ /* If setting local system proile and not effective root, but sudo */
+ } else if (scope != p_scope_user && getuid() == 0 && geteuid() != 0) {
+ if (getenv("SUDO_UID") != NULL
+ && getenv("SUDO_GID") != NULL) {
+
+ debugr("We're setting a system profile running as user - revert to root\n");
+ setegid(getgid());
+ seteuid(getuid());
+ }
+ }
+#endif /* OS X || Linux */
+#ifdef __APPLE__
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+ {
+ char *dpath; /* Un-install file path */
+ struct stat sbuf;
+ int ev;
+ CFStringRef keys[1];
+ CFURLRef values[1];
+ CFDictionaryRef dict;
+ CFUUIDRef dispuuid;
+
+ /* Determine the location the profile will be installed into */
+ if ((dpath = iprof_path(scope, fname)) == NULL) {
+ debugr2((errout,"iprof_path() failed\n"));
+ return 1;
+ }
+
+ debugr2((errout,"Profile to delete '%s'\n",dpath));
+
+ if (stat(dpath, &sbuf) != 0) {
+ debugr2((errout,"delete '%s' profile doesn't exist\n",dpath));
+ return 2;
+ }
+ if ((ev = unlink(dpath)) != 0) {
+ debugr2((errout,"delete '%s' failed with %d\n",dpath,ev));
+ return 1;
+ }
+
+ free(dpath); dpath = NULL;
+
+ /* Make ColorSync notice that it's gone */
+ /* (Works on 10.7, but not 10.6 ? */
+ if ((dispuuid = CGDisplayCreateUUIDFromDisplayID(p->ddid)) == NULL) {
+ debugr2((errout,"CGDisplayCreateUUIDFromDisplayID() failed\n"));
+ return 1;
+ }
+
+ keys[0] = kColorSyncDeviceDefaultProfileID;
+ values[0] = (CFURLRef)kCFNull;
+
+ if ((dict = CFDictionaryCreate(kCFAllocatorDefault, (const void **)&keys,
+ (const void **)&values, 1, NULL, NULL)) == NULL) {
+ debugr2((errout,"CFDictionaryCreate() failed\n"));
+ CFRelease(dispuuid);
+ return 1;
+ }
+
+ if (!ColorSyncDeviceSetCustomProfiles(kColorSyncDisplayDeviceClass, dispuuid, dict)) {
+ debugr2((errout,"ColorSyncDeviceSetCustomProfiles() failed\n"));
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ return 1;
+ }
+ CFRelease(dict);
+ CFRelease(dispuuid);
+
+ return 0;
+ }
+#else /* 10.6 and prior */
+ // ~~~ can use above code
+ {
+ CMError cmev;
+ int ev;
+ short vref;
+ char dpath[FILENAME_MAX];
+ char *basename;
+ FSRef dirref;
+ struct stat sbuf;
+
+ if (scope == p_scope_network)
+ vref = kNetworkDomain;
+ else if (scope == p_scope_system)
+ vref = kSystemDomain;
+ else if (scope == p_scope_local)
+ vref = kLocalDomain;
+ else
+ vref = kUserDomain;
+
+ /* Locate the appropriate ColorSync path */
+ if ((cmev = FSFindFolder(vref, kColorSyncProfilesFolderType, kCreateFolder, &dirref)) != noErr) {
+ debugr2((errout,"FSFindFolder() failed with error %d\n",cmev));
+ return 1;
+ }
+
+ /* Convert to POSIX path */
+ if ((cmev = FSRefMakePath(&dirref, (unsigned char *)dpath, FILENAME_MAX)) != noErr) {
+ debugr2((errout,"FSRefMakePath failed with error %d\n",cmev));
+ return 1;
+ }
+
+ /* Locate the base filename in the fname */
+ for (basename = fname + strlen(fname); ; basename--) {
+ if (basename <= fname || basename[-1] == '/')
+ break;
+ }
+
+ /* Append the basename to the ColorSync directory path */
+ if ((strlen(dpath) + strlen(basename) + 2) > FILENAME_MAX
+ || (strlen(dpath) + strlen(basename) + 2) > 256) {
+ debugr2((errout,"ColorSync dir + profile name too long\n"));
+ return 1;
+ }
+ strcat(dpath, "/");
+ strcat(dpath, basename);
+ debugr2((errout,"Profile to delete '%s'\n",dpath));
+
+ if (stat(dpath, &sbuf) != 0) {
+ debugr2((errout,"delete '%s' profile doesn't exist\n",dpath));
+ return 2;
+ }
+ if ((ev = unlink(dpath)) != 0) {
+ debugr2((errout,"delete '%s' failed with %d\n",dpath,ev));
+ return 1;
+ }
+
+ return 0;
+ }
+#endif /* 10.6 and prior */
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11) && defined(USE_UCMM)
+ {
+ ucmm_error ev;
+ ucmm_scope sc;
+
+ if (scope == p_scope_network
+ || scope == p_scope_system
+ || scope == p_scope_local)
+ sc = ucmm_local_system;
+ else
+ sc = ucmm_user;
+
+ if ((ev = ucmm_uninstall_monitor_profile(sc, p->edid, p->edid_len, p->name, fname)) != ucmm_ok) {
+ debugr2((errout,"Installing profile '%s' failed with error %d '%s'\n",fname,ev,ucmm_error_string(ev)));
+ return 1;
+ }
+
+ XDeleteProperty(p->mydisplay, RootWindow(p->mydisplay, 0), p->icc_atom);
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ /* If Xrandr 1.2, set property on output */
+ if (p->icc_out_atom != 0) {
+ XRRDeleteOutputProperty(p->mydisplay, p->output, p->icc_out_atom);
+ }
+#endif /* randr >= V 1.2 */
+ return 0;
+ }
+#endif /* UNXI X11 */
+
+ return 1;
+}
+
+/* Get the currently installed display profile and return it as an icmFile. */
+/* Return the name as well, up to mxlen chars, excluding nul. */
+/* Return NULL if failed. */
+icmFile *dispwin_get_profile(dispwin *p, char *name, int mxlen) {
+ icmFile *rd_fp = NULL;
+
+#ifdef NT
+ {
+ char buf[MAX_PATH];
+ DWORD blen = MAX_PATH;
+
+ if (GetICMProfile(p->hdc, &blen, buf) == 0) {
+ debugr2((errout, "GetICMProfile failed, lasterr = %d\n",GetLastError()));
+ return NULL;
+ }
+
+ debugr2((errout,"Loading default profile '%s'\n",buf));
+ if ((rd_fp = new_icmFileStd_name(buf,"r")) == NULL)
+ debugr2((errout,"Can't open file '%s'",buf));
+
+ return rd_fp;
+ }
+#endif /* NT */
+
+#ifdef __APPLE__
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ {
+ char *dpath; /* Read file path */
+ struct stat sbuf;
+ icmAlloc *al;
+ void *buf;
+ FILE *fp;
+
+ if ((dpath = cur_profile(p)) == NULL) {
+ debugr2((errout,"cur_profile() failed\n"));
+ return NULL;
+ }
+
+ /* Get the profile size */
+ if (stat(dpath, &sbuf) != 0) {
+ debugr2((errout,"Failed to open profile '%s'\n",dpath));
+ free(dpath);
+ return NULL;
+ }
+
+ if ((al = new_icmAllocStd()) == NULL) {
+ debugr("new_icmAllocStd failed\n");
+ free(dpath);
+ return NULL;
+ }
+ if ((buf = al->malloc(al, sbuf.st_size)) == NULL) {
+ debugr("malloc of profile buffer failed\n");
+ free(dpath);
+ return NULL;
+ }
+
+ if ((fp = fopen(dpath, "r")) == NULL) {
+ debugr2((errout,"opening '%s' failed\n",dpath));
+ al->free(al, buf);
+ free(dpath);
+ return NULL;
+ }
+ if (fread(buf, 1, sbuf.st_size, fp) != sbuf.st_size) {
+ debugr2((errout,"reading '%s' failed\n",dpath));
+ al->free(al, buf);
+ fclose(fp);
+ free(dpath);
+ return NULL;
+ }
+ fclose(fp);
+ free(dpath); dpath = NULL;
+
+ /* Memory File fp that will free the buffer when deleted: */
+ if ((rd_fp = new_icmFileMem_ad(buf, sbuf.st_size, al)) == NULL) {
+ debugr("Creating memory file profile failed");
+ al->free(al, buf);
+ al->del(al);
+ return NULL;
+ }
+
+ if (name != NULL) {
+ strncpy(name, "Display", mxlen);
+ name[mxlen] = '\000';
+ }
+
+ return rd_fp;
+ }
+
+#else /* 10.5 and prior */
+ {
+ CMError ev;
+ CMProfileRef prof, dprof; /* Source profile */
+ CMProfileLocation dploc; /* Destinaion profile location */
+ CMAppleProfileHeader hdr;
+ icmAlloc *al;
+
+#ifdef NEVER
+ /* Get the current display profile */
+ if ((ev = CMGetProfileByAVID((CMDisplayIDType)p->ddid, &prof)) != noErr) {
+ debugr2((errout,"CMGetProfileByAVID() failed with error %d\n",ev));
+ return NULL;
+ }
+#else
+ CMDeviceProfileID curID; /* Current Device Default profile ID */
+ CMProfileLocation cploc; /* Current profile location */
+
+ /* Get the default ID for the display */
+ if ((ev = CMGetDeviceDefaultProfileID(cmDisplayDeviceClass, (CMDeviceID)p->ddid, &curID)) != noErr) {
+ debugr2((errout,"CMGetDeviceDefaultProfileID() failed with error %d\n",ev));
+ return NULL;
+ }
+
+ /* Get the displays profile */
+ if ((ev = CMGetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)p->ddid, curID, &cploc)) != noErr) {
+ debugr2((errout,"CMGetDeviceDefaultProfileID() failed with error %d\n",ev));
+ return NULL;
+ }
+
+ if ((ev = CMOpenProfile(&prof, &cploc)) != noErr) {
+ debugr2((errout,"CMOpenProfile() failed with error %d\n",ev));
+ return NULL;
+ }
+#endif
+
+ /* Get the profile size */
+ if ((ev = CMGetProfileHeader(prof, &hdr)) != noErr) {
+ debugr2((errout,"CMGetProfileHeader() failed with error %d\n",ev));
+ return NULL;
+ }
+
+ /* Make a copy of the profile to a memory buffer */
+ dploc.locType = cmBufferBasedProfile;
+ dploc.u.bufferLoc.size = hdr.cm1.size;
+ if ((al = new_icmAllocStd()) == NULL) {
+ debugr("new_icmAllocStd failed\n");
+ return NULL;
+ }
+ if ((dploc.u.bufferLoc.buffer = al->malloc(al, dploc.u.bufferLoc.size)) == NULL) {
+ debugr("malloc of profile buffer failed\n");
+ return NULL;
+ }
+
+ if ((ev = CMCopyProfile(&dprof, &dploc, prof)) != noErr) {
+ debugr2((errout,"CMCopyProfile() failed for AVID to buffer with error %d\n",ev));
+ return NULL;
+ }
+
+ /* Memory File fp that will free the buffer when deleted: */
+ if ((rd_fp = new_icmFileMem_ad((void *)dploc.u.bufferLoc.buffer, dploc.u.bufferLoc.size, al)) == NULL) {
+ debugr("Creating memory file from CMProfileLocation failed");
+ al->free(al, dploc.u.bufferLoc.buffer);
+ al->del(al);
+ CMCloseProfile(prof);
+ CMCloseProfile(dprof);
+ return NULL;
+ }
+
+ if (name != NULL) {
+ strncpy(name, "Display", mxlen);
+ name[mxlen] = '\000';
+ }
+
+ CMCloseProfile(prof);
+ CMCloseProfile(dprof);
+
+ return rd_fp;
+ }
+#endif /* 10.5 and prior */
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11) && defined(USE_UCMM)
+ /* Try and get the currently installed profile from ucmm */
+ {
+ ucmm_error ev;
+ char *profile = NULL;
+
+ debugr2((errout,"dispwin_get_profile called\n"));
+
+ if ((ev = ucmm_get_monitor_profile(p->edid, p->edid_len, p->name, &profile)) == ucmm_ok) {
+
+ if (name != NULL) {
+ strncpy(name, profile, mxlen);
+ name[mxlen] = '\000';
+ }
+
+ debugr2((errout,"Loading current profile '%s'\n",profile));
+ if ((rd_fp = new_icmFileStd_name(profile,"r")) == NULL) {
+ debugr2((errout,"Can't open file '%s'",profile));
+ free(profile);
+ return NULL;
+ }
+
+ /* Implicitly we set the X11 atom to be the profile we just got */
+ debugr2((errout,"Setting X11 atom to current profile '%s'\n",profile));
+ if (set_X11_atom(p, profile) != 0) {
+ debugr2((errout,"Setting X11 atom to profile '%s' failed",profile));
+ /* Hmm. We ignore this error */
+ }
+ return rd_fp;
+ }
+ if (ev != ucmm_no_profile) {
+ debugr2((errout,"Got ucmm error %d '%s'\n",ev,ucmm_error_string(ev)));
+ return NULL;
+ }
+ debugr2((errout,"Failed to get configured profile, so use X11 atom\n"));
+ /* Drop through to using the X11 root window atom */
+ }
+ {
+ Atom ret_type;
+ int ret_format;
+ long ret_len, ret_togo;
+ char aname[30];
+ unsigned char *atomv = NULL; /* Profile loaded from/to atom */
+ unsigned char *buf;
+ icmAlloc *al;
+
+ atomv = NULL;
+
+ strcpy(aname, "_ICC_PROFILE");
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ /* If Xrandr 1.2, get property on output */
+ if (p->icc_out_atom != 0) {
+
+ /* Get the ICC profile property */
+ if (XRRGetOutputProperty(p->mydisplay, p->output, p->icc_out_atom,
+ 0, 0x7ffffff, False, False, XA_CARDINAL,
+ &ret_type, &ret_format, &ret_len, &ret_togo, &atomv) != Success || ret_len == 0) {
+ debugr("Failed to read ICC_PROFILE property from Xranr output\n");
+ }
+
+ }
+#endif /* randr >= V 1.2 */
+
+ if (atomv == NULL) {
+ if (p->myuscreen != 0)
+ sprintf(aname, "_ICC_PROFILE_%d",p->myuscreen);
+
+ /* Get the ICC profile property */
+ if (XGetWindowProperty(p->mydisplay, RootWindow(p->mydisplay, 0), p->icc_atom,
+ 0, 0x7ffffff, False, XA_CARDINAL,
+ &ret_type, &ret_format, &ret_len, &ret_togo, &atomv) != Success || ret_len == 0) {
+ debugr2((errout,"Getting property '%s' from RootWindow\n", aname));
+ return NULL;
+ }
+ }
+
+ /* This is a bit of a fiddle to keep the memory allocations */
+ /* straight. (We can't assume that X11 and icc are using the */
+ /* same allocators) */
+ if ((al = new_icmAllocStd()) == NULL) {
+ debugr("new_icmAllocStd failed\n");
+ return NULL;
+ }
+ if ((buf = al->malloc(al, ret_len)) == NULL) {
+ debugr("malloc of profile buffer failed\n");
+ return NULL;
+ }
+ memmove(buf, atomv, ret_len);
+ XFree(atomv);
+
+ /* Memory File fp that will free the buffer when deleted: */
+ if ((rd_fp = new_icmFileMem_ad((void *)buf, ret_len, al)) == NULL) {
+ debugr("Creating memory file from X11 atom failed");
+ al->free(al, buf);
+ al->del(al);
+ return NULL;
+ }
+
+ if (name != NULL) {
+ strncpy(name, aname, mxlen);
+ name[mxlen] = '\000';
+ }
+ return rd_fp;
+ }
+#endif /* UNXI X11 */
+
+ return NULL;
+}
+
+/* ----------------------------------------------- */
+
+/* Restore the display state */
+static void restore_display(dispwin *p) {
+
+ /* Restore the ramdac */
+ if (p->or != NULL) {
+ p->set_ramdac(p, p->or, 0);
+ p->or->del(p->or);
+ p->or = NULL;
+ debugr("Restored original ramdac\n");
+ }
+ if (p->r != NULL) {
+ p->r->del(p->r);
+ p->r = NULL;
+ }
+
+#if defined(UNIX_X11)
+
+#if ScreenSaverMajorVersion >= 1 && ScreenSaverMinorVersion >= 1 /* X11R7.1 */
+ if (p->xsssuspend) {
+ XScreenSaverSuspend(p->mydisplay, False);
+ p->xsssuspend = 0;
+ }
+#endif
+ if (p->xssvalid) {
+ /* Restore the X11 screen saver state */
+ XSetScreenSaver(p->mydisplay, p->timeout, p->interval,
+ p->prefer_blanking, p->allow_exposures);
+ }
+
+ /* Restore the xscreensaver */
+ if (p->xssrunning) {
+ system("xscreensaver -nosplash 2>/dev/null >/dev/null&");
+ }
+
+ if (p->gnomessrunning && p->gnomepid != -1) {
+ kill(p->gnomepid, SIGKILL); /* Kill the process inhibiting the screen saver */
+ }
+
+ /* Restore the KDE screen saver state */
+ if (p->kdessrunning) {
+ system("dcop kdesktop KScreensaverIface enable true 2>&1 >/dev/null");
+ }
+
+ /* Restore DPMS */
+ if (p->dpmsenabled) {
+ DPMSEnable(p->mydisplay);
+ }
+
+ /* Flush any changes out */
+ XSync(p->mydisplay, False);
+#endif /* UNIX_X11 */
+}
+
+/* ----------------------------------------------- */
+/* On something killing our process, deal with Ramac & ScreenSaver cleanup */
+
+#ifdef NT
+void (__cdecl *dispwin_int)(int sig) = SIG_DFL;
+void (__cdecl *dispwin_term)(int sig) = SIG_DFL;
+#endif
+#ifdef UNIX
+void (*dispwin_hup)(int sig) = SIG_DFL;
+void (*dispwin_int)(int sig) = SIG_DFL;
+void (*dispwin_term)(int sig) = SIG_DFL;
+#endif
+
+/* List of dispwin's to clean up */
+static dispwin *signal_dispwin = NULL;
+
+static void dispwin_sighandler(int arg) {
+ dispwin *pp, *np;
+
+ /* Restore all dispwin's Ramdacs & screen savers */
+ for (pp = signal_dispwin; pp != NULL; pp = np) {
+ np = pp->next;
+ restore_display(pp);
+ }
+
+ /* Call through to previous handler */
+#ifdef UNIX
+ if (arg == SIGHUP && dispwin_hup != SIG_DFL && dispwin_hup != SIG_IGN)
+ dispwin_hup(arg);
+#endif
+ if (arg == SIGINT && dispwin_int != SIG_DFL && dispwin_int != SIG_IGN)
+ dispwin_int(arg);
+ if (arg == SIGTERM && dispwin_term != SIG_DFL && dispwin_term != SIG_IGN)
+ dispwin_term(arg);
+ exit(0);
+}
+
+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);
+#endif /* UNIX */
+ dispwin_int = signal(SIGINT, dispwin_sighandler);
+ dispwin_term = signal(SIGTERM, dispwin_sighandler);
+ }
+
+ /* Add this one to the list */
+ p->next = signal_dispwin;
+ signal_dispwin = p;
+}
+
+static void dispwin_uninstall_signal_handlers(dispwin *p) {
+
+ /* Find it and delete it from our static cleanup list */
+ if (signal_dispwin != NULL) {
+ if (signal_dispwin == p) {
+ signal_dispwin = p->next;
+ if (signal_dispwin == NULL) {
+#if defined(UNIX)
+ signal(SIGHUP, dispwin_hup);
+#endif /* UNIX */
+ signal(SIGINT, dispwin_int);
+ signal(SIGTERM, dispwin_term);
+ }
+ } else {
+ dispwin *pp;
+ for (pp = signal_dispwin; pp != NULL; pp = pp->next) {
+ if (pp->next == p) {
+ pp->next = p->next;
+ break;
+ }
+ }
+ }
+ }
+ p->next = NULL;
+}
+
+/* ----------------------------------------------- */
+/* Test patch window specific declarations */
+
+#ifdef __APPLE__
+
+@class DWWin;
+@class DWView;
+
+/* Our OS X window specific information */
+typedef struct {
+ dispwin *p;
+ DWWin *window; /* Our NSWindow */
+ DWView *view; /* Our NSView */
+} osx_cntx_t;
+
+static void OSX_ProcessEvents(dispwin *p);
+
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+
+@interface DWView : NSView {
+ osx_cntx_t *cntx;
+}
+- (void)setCntx:(osx_cntx_t *)cntx;
+@end
+
+@implementation DWView
+
+- (void)setCntx:(osx_cntx_t *)val {
+ cntx = val;
+}
+
+// A transparent 1x1 GIF: (43 bytes)
+unsigned char emptyCursor[43] = {
+ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b };
+
+/* Make cursor invisible over our window */
+/*
+ * This doesn't work very well. The only way to work it properly
+ * is to create a CGEventTap and do a hide/unkid cursor when
+ * the mouse enters the window. This needs the main thread
+ * to be dedicated to running the event loop.
+ */
+- (void)resetCursorRects {
+ [super resetCursorRects];
+// [self addCursorRect:[self bounds] cursor:[NSCursor crosshairCursor]];
+ NSData *idata = [NSData dataWithBytes:(void *)emptyCursor length:43];
+ NSImage *img = [NSImage alloc];
+ img = [img initWithData:idata];
+ NSCursor *curs = [NSCursor alloc];
+ curs = [curs initWithImage:img hotSpot:NSMakePoint(0,0)];
+ [self addCursorRect:[self bounds] cursor:curs];
+}
+
+- (void)drawRect:(NSRect)rect {
+ osx_cntx_t *cx = cntx;
+ dispwin *p = cx->p;
+ NSRect frect;
+ NSBezierPath* aPath = [NSBezierPath bezierPath];
+
+ frect = NSMakeRect(p->tx, p->ty, (1.0 + p->tw), (1.0 + p->th));
+
+ [[NSColor colorWithDeviceRed: p->r_rgb[0]
+ green: p->r_rgb[1]
+ blue: p->r_rgb[2]
+ alpha: 1.0] setFill];
+ [aPath appendBezierPathWithRect:frect];
+ [aPath fill];
+}
+
+@end
+
+// - - - - - - - - - - - - - - - - - - - - - - - - -
+
+@interface DWWin : NSWindow {
+ osx_cntx_t *cntx;
+}
+- (void)setCntx:(osx_cntx_t *)cntx;
+@end
+
+@implementation DWWin
+
+- (void)setCntx:(osx_cntx_t *)val {
+ cntx = val;
+}
+
+- (BOOL)canBecomeMainWindow {
+ return NO;
+}
+
+/* So that we can change the cursor on a borderless window: */
+- (BOOL)canBecomeKeyWindow {
+ return YES;
+}
+
+- (BOOL)isMoveable {
+ return NO;
+}
+
+- (BOOL)windowShouldClose:(id)sender {
+// printf("Got Window windowShouldClose\n");
+
+// [NSApp terminate: nil];
+ return YES;
+}
+
+@end
+
+/* Create our window */
+static void create_my_win(NSRect rect, osx_cntx_t *cx) {
+ dispwin *p = cx->p;
+ int i;
+
+ /* We need to locate the NSScreen that corresponds to the */
+ /* CGDirectDisplayID - look through them for a match. */
+ NSScreen *screen = nil;
+ NSArray *screenArray = [NSScreen screens];
+ for (i = 0; i < [screenArray count]; i++) {
+ NSDictionary *screenDescription = [[screenArray objectAtIndex:i] deviceDescription];
+
+ // CFShow(screenDescription); // Dump it out
+ /* Hmm. Also has "NSDeviceBitsPerSample" entry with value 8 in dict. */
+
+ NSNumber* screenID = [screenDescription objectForKey:@"NSScreenNumber"];
+ CGDirectDisplayID ddid = (CGDirectDisplayID)[screenID unsignedIntValue];
+ if (ddid == p->ddid) {
+ screen = [screenArray objectAtIndex:i];
+ break;
+ }
+ }
+
+ /* Create Window */
+ cx->window = [[DWWin alloc] initWithContentRect: rect
+ styleMask: NSBorderlessWindowMask
+ backing: NSBackingStoreBuffered
+ defer: YES
+ screen: screen];
+
+ [cx->window setLevel: NSScreenSaverWindowLevel];
+
+ [cx->window setBackgroundColor: [NSColor blackColor]];
+
+ [cx->window setTitle: @"Argyll Window"];
+
+ /* Use our view for the whole window to draw plot */
+ cx->view = [DWView new];
+ [cx->view setCntx:(void *)cx];
+ [cx->window setContentView: cx->view];
+
+ [cx->window makeKeyAndOrderFront: nil];
+}
+
+#endif /* __APPLE__ */
+
+/* ----------------------------------------------- */
+
+/* Change the window color. */
+/* Return 1 on error, 2 on window being closed */
+static int dispwin_set_color(
+dispwin *p,
+double r, double g, double b /* Color values 0.0 - 1.0 */
+) {
+ int j;
+
+ debugr("dispwin_set_color called\n");
+
+ if (p->nowin)
+ return 1;
+
+ p->rgb[0] = r;
+ p->rgb[1] = g;
+ p->rgb[2] = b;
+
+ for (j = 0; j < 3; j++) {
+ if (p->rgb[j] < 0.0)
+ p->rgb[j] = 0.0;
+ else if (p->rgb[j] > 1.0)
+ p->rgb[j] = 1.0;
+ p->r_rgb[j] = p->rgb[j];
+ }
+
+ /* Use ramdac for high precision native output. */
+ /* The ramdac is used to hold the lsb that the frame buffer */
+ /* doesn't hold. */
+ if (p->native == 1) {
+ double prange = p->r->nent - 1.0;
+
+ for (j = 0; j < 3; j++) {
+ int tt;
+
+//printf("~1 %d: in %f, ",j,p->rgb[j]);
+ tt = (int)(p->rgb[j] * prange);
+ p->r->v[j][tt] = p->rgb[j];
+ p->r_rgb[j] = (double)tt/prange; /* RAMDAC output Quantized value */
+//printf(" cell[%d], val %f, rast val %f\n",tt, p->rgb[j], p->r_rgb[j]);
+ }
+ if (p->set_ramdac(p,p->r, 0)) {
+ debugr("set_ramdac() failed\n");
+ return 1;
+ }
+ }
+
+ /* - - - - - - - - - - - - - - */
+#ifdef NT
+ {
+ MSG msg;
+ INPUT fip;
+
+ /* Stop the system going to sleep */
+
+ /* This used to work OK in reseting the screen saver, but not in Vista :-( */
+ SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
+
+ /* So we use a fake mouse non-movement reset the Vista screensaver. */
+ SystemParametersInfo(SPI_SETBLOCKSENDINPUTRESETS, FALSE, NULL, 0);
+ fip.type = INPUT_MOUSE;
+ fip.mi.dx = 0;
+ fip.mi.dy = 0;
+ fip.mi.dwFlags = MOUSEEVENTF_MOVE;
+ fip.mi.time = 0;
+ fip.mi.dwExtraInfo = 0;
+ SendInput(1, &fip, sizeof(INPUT));
+
+ p->colupd++;
+
+ /* Trigger a WM_PAINT */
+ if (!InvalidateRect(p->hwnd, NULL, FALSE)) {
+ debugr2((errout,"InvalidateRect failed, lasterr = %d\n",GetLastError()));
+ return 1;
+ }
+
+ /* Wait for WM_PAINT to be executed */
+ while (p->colupd != p->colupde) {
+ msec_sleep(20);
+ }
+ }
+#endif /* NT */
+
+ /* - - - - - - - - - - - - - - */
+
+#ifdef __APPLE__
+
+ if (p->winclose) {
+ return 2;
+ }
+
+ /* Stop the system going to sleep */
+ UpdateSystemActivity(OverallAct);
+
+ /* Make sure our window is brought to the front at least once, */
+ /* but not every time, in case the user wants to kill the application. */
+ if (p->btf == 0){
+ OSStatus stat;
+ ProcessSerialNumber cpsn;
+ if ((stat = GetCurrentProcess(&cpsn)) != noErr) {
+ debugr2((errout,"GetCurrentProcess returned error %d\n",stat));
+ } else {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1030
+ if ((stat = TransformProcessType(&cpsn, kProcessTransformToForegroundApplication)) != noErr) {
+ debugr2((errout,"TransformProcessType returned error %d\n",stat));
+ }
+#endif /* OS X 10.3 */
+ if ((stat = SetFrontProcess(&cpsn)) != noErr) {
+ debugr2((errout,"SetFrontProcess returned error %d\n",stat));
+ }
+ }
+ p->btf = 1;
+ }
+
+ /* Trigger an update that fills window with r_rgb[] */
+ [((osx_cntx_t *)(p->osx_cntx))->view setNeedsDisplay: YES ];
+
+ /* Process events */
+ OSX_ProcessEvents(p);
+
+#endif /* __APPLE__ */
+
+ /* - - - - - - - - - - - - - - */
+
+#if defined(UNIX_X11)
+ {
+ Colormap mycmap;
+ XColor col;
+ int vali[3];
+
+ /* Indicate that we've got activity to the X11 Screensaver */
+ XResetScreenSaver(p->mydisplay);
+
+ /* Quantize to 16 bit color */
+ for (j = 0; j < 3; j++)
+ vali[j] = (int)(65535.0 * p->r_rgb[j] + 0.5);
+
+ mycmap = DefaultColormap(p->mydisplay, p->myscreen);
+ col.red = vali[0];
+ col.green = vali[1];
+ col.blue = vali[2];
+ XAllocColor(p->mydisplay, mycmap, &col);
+ XSetForeground(p->mydisplay, p->mygc, col.pixel);
+
+ XFillRectangle(p->mydisplay, p->mywindow, p->mygc,
+ p->tx, p->ty, p->tw, p->th);
+
+ XSync(p->mydisplay, False); /* Make sure it happens */
+ }
+#endif /* UNXI X11 */
+
+ if (p->callout != NULL) {
+ int rv;
+ char *cmd;
+
+ if ((cmd = malloc(strlen(p->callout) + 200)) == NULL)
+ error("Malloc of command string failed");
+
+ sprintf(cmd, "%s %d %d %d %f %f %f",p->callout,
+ (int)(r * 255.0 + 0.5),(int)(g * 255.0 + 0.5),(int)(b * 255.0 + 0.5), r, g, b);
+ if ((rv = system(cmd)) != 0)
+ warning("System command '%s' failed with %d",cmd,rv);
+ free(cmd);
+ }
+
+ /* Allow some time for the display to update before */
+ /* a measurement can take place. This allows for CRT */
+ /* refresh, or LCD processing/update time, + */
+ /* display settling time (quite long for smaller LCD changes). */
+ msec_sleep(p->update_delay);
+
+ return 0;
+}
+
+/* ----------------------------------------------- */
+/* Set an update delay, and return the previous value */
+/* Value can be set to zero, but othewise will be forced */
+/* to be >= min_update_delay */
+static int dispwin_set_update_delay(
+dispwin *p,
+int update_delay) {
+ int cval = p->update_delay;
+ p->update_delay = update_delay;
+ if (update_delay != 0 && p->update_delay < p->min_update_delay)
+ p->update_delay = p->min_update_delay;
+ return cval;
+}
+
+/* ----------------------------------------------- */
+/* Set the shell set color callout */
+void dispwin_set_callout(
+dispwin *p,
+char *callout
+) {
+ debugr2((errout,"dispwin_set_callout called with '%s'\n",callout));
+
+ p->callout = strdup(callout);
+}
+
+/* ----------------------------------------------- */
+/* Destroy ourselves */
+static void dispwin_del(
+dispwin *p
+) {
+
+ debugr("dispwin_del called\n");
+
+ if (p == NULL)
+ return;
+
+ /* Restore original RAMDAC if we were in native mode, */
+ /* and restore screensaver */
+ restore_display(p);
+ dispwin_uninstall_signal_handlers(p);
+
+ /* -------------------------------------------------- */
+#ifdef NT
+
+ if (p->hwnd != NULL) {
+
+ p->quit = 1;
+ if (PostMessage(p->hwnd, WM_CLOSE, (WPARAM)NULL, (LPARAM)NULL) != 0) {
+ while(p->hwnd != NULL)
+ msec_sleep(20);
+ } else {
+ debugr2((errout, "PostMessage(WM_GETICON failed, lasterr = %d\n",GetLastError()));
+ }
+// DestroyCursor(p->curs);
+
+ if (p->mth != NULL) { /* Message thread */
+ p->mth->del(p->mth);
+ }
+ }
+
+ if (p->hdc != NULL)
+ DeleteDC(p->hdc);
+
+#endif /* NT */
+ /* -------------------------------------------------- */
+
+ /* -------------------------------------------------- */
+#ifdef __APPLE__
+ if (p->nowin == 0) { /* We have a window up */
+ restore_display(p);
+ if (p->osx_cntx != NULL) { /* And we've allocated a context */
+ osx_cntx_t *cx = (osx_cntx_t *)p->osx_cntx;
+
+ p->winclose = 1;
+
+ [cx->window release];
+ free(p->osx_cntx);
+ p->osx_cntx = NULL;
+ }
+ }
+
+// ~~
+// CGDisplayShowCursor(p->ddid);
+
+#endif /* __APPLE__ */
+ /* -------------------------------------------------- */
+
+ /* -------------------------------------------------- */
+#if defined(UNIX_X11)
+ debugr("About to close display\n");
+
+ if (p->mydisplay != NULL) {
+ if (p->nowin == 0) { /* We have a window up */
+
+ XFreeGC(p->mydisplay, p->mygc);
+ XDestroyWindow(p->mydisplay, p->mywindow);
+ }
+ XCloseDisplay(p->mydisplay);
+ }
+ debugr("finished\n");
+
+#endif /* UNXI X11 */
+ /* -------------------------------------------------- */
+
+ if (p->name != NULL)
+ free(p->name);
+ if (p->description != NULL)
+ free(p->description);
+ if (p->callout != NULL)
+ free(p->callout);
+
+ free(p);
+}
+
+/* ----------------------------------------------- */
+/* Event handler callbacks */
+
+#ifdef NT
+
+/* Undocumented flag. Set when minimized/maximized etc. */
+#ifndef SWP_STATECHANGED
+#define SWP_STATECHANGED 0x8000
+#endif
+
+static LRESULT CALLBACK MainWndProc(
+ HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+) {
+ debugrr2l(4, (stderr, "Handling message type 0x%x\n",message));
+
+ if (message >= WM_APP) {
+ debugrr2l(4, (stderr, "Message ignored\n"));
+ return 0;
+ }
+
+ switch(message) {
+ case WM_PAINT: {
+ dispwin *p = NULL;
+ int vali[3];
+ HDC hdc;
+ PAINTSTRUCT ps;
+ RECT rect;
+ HBRUSH hbr;
+ int j;
+
+#ifdef _WIN64
+ if ((p = (dispwin *)GetWindowLongPtr(hwnd, GWLP_USERDATA)) == NULL)
+#else
+ if ((p = (dispwin *)GetWindowLong(hwnd, GWL_USERDATA)) == NULL)
+#endif
+ {
+ debugrr2l(4,(stderr, "GetWindowLongPtr failed, lasterr = %d\n",GetLastError()));
+ hdc = BeginPaint(hwnd, &ps);
+ /* Don't know where to paint */
+ EndPaint(hwnd, &ps);
+ return 0;
+ }
+
+ /* Check that there is something to paint */
+ if (GetUpdateRect(hwnd, NULL, FALSE) == 0) {
+ debugrr2l(4, (stderr,"The update region was empty\n"));
+ }
+
+ /* Frame buffer Quantize 8 bit color */
+ for (j = 0; j < 3; j++) {
+ vali[j] = (int)(255.0 * p->r_rgb[j] + 0.5);
+ }
+
+ hdc = BeginPaint(hwnd, &ps);
+
+ SaveDC(hdc);
+
+ /* Try and turn ICM off */
+#ifdef ICM_DONE_OUTSIDEDC
+ if (!SetICMMode(hdc, ICM_DONE_OUTSIDEDC)) {
+ /* This seems to fail with "invalid handle" under NT4 */
+ /* Does it work under Win98 or Win2K ? */
+ printf("SetICMMode failed, lasterr = %d\n",GetLastError());
+ }
+#endif
+
+ hbr = CreateSolidBrush(RGB(vali[0],vali[1],vali[2]));
+ SelectObject(hdc,hbr);
+
+ SetRect(&rect, p->tx, p->ty, p->tx + p->tw, p->ty + p->th);
+ FillRect(hdc, &rect, hbr);
+
+ RestoreDC(hdc,-1);
+ DeleteDC(hdc);
+
+ EndPaint(hwnd, &ps);
+
+ p->colupde = p->colupd; /* We're updated to this color */
+
+ return 0;
+ }
+
+ /* Prevent any changes in position of the window */
+ case WM_WINDOWPOSCHANGING: {
+ WINDOWPOS *wpos = (WINDOWPOS *)lParam;
+ debugrr2l(4,(stderr, "It's a windowposchange, flags = 0x%x, x,y %d %d, w,h %d %d\n",wpos->flags, wpos->x, wpos->y, wpos->cx, wpos->cy));
+ wpos->flags &= ~SWP_FRAMECHANGED & ~SWP_NOREDRAW;
+ wpos->flags |= SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER
+ | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_SHOWWINDOW;
+ debugrr2l(4,(stderr, "flags now = 0x%x\n",wpos->flags));
+ return DefWindowProc(hwnd, message, wParam, lParam);
+ }
+ case WM_WINDOWPOSCHANGED: {
+ WINDOWPOS *wpos = (WINDOWPOS *)lParam;
+ debugrr2l(4,(stderr, "It's a windowposchanged, flags = 0x%x, x,y %d %d, w,h %d %d\n",wpos->flags, wpos->x, wpos->y, wpos->cx, wpos->cy));
+ debugrr2l(4,(stderr, "It's a windowposchanged, flags = 0x%x\n",wpos->flags));
+ return 0;
+ }
+ case WM_CLOSE:
+ DestroyWindow(hwnd);
+ return 0;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return 0;
+ }
+
+ debugrr2l(4,(stderr, "Handle message using DefWindowProc()\n"));
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+#endif /* NT */
+
+#ifdef __APPLE__
+
+/* Not the event handler (because events are handled by the Cocoa objects) */
+/* but a function to call to process events after an update */
+static void OSX_ProcessEvents(dispwin *p) {
+ NSEvent *event;
+ NSDate *to;
+
+ /* We're creating and draining a pool here to ensure that all the */
+ /* auto release objects get drained when we're finished (?) */
+ NSAutoreleasePool *tpool = [NSAutoreleasePool new];
+
+ /* Wait until the events are done */
+ to = [NSDate dateWithTimeIntervalSinceNow:0.01]; /* autorelease ? */
+ for (;;) {
+ /* Hmm. Assume event is autorelease */
+ if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:to inMode:NSDefaultRunLoopMode dequeue:YES]) != nil) {
+ [NSApp sendEvent:event];
+ } else {
+ break;
+ }
+ }
+ [tpool release];
+}
+
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11)
+ /* None */
+#endif /* UNXI X11 */
+
+/* ----------------------------------------------- */
+#ifdef NT
+
+/* Thread to handle message processing, so that there is no delay */
+/* when the main thread is doing other things. */
+int win_message_thread(void *pp) {
+ dispwin *p = (dispwin *)pp;
+ MSG msg;
+ WNDCLASS wc;
+
+ debugrr2l(4, (stderr, "win_message_thread started\n"));
+
+ /* Fill in window class structure with parameters that describe the */
+ /* main window. */
+ wc.style = 0 ; /* Class style(s). */
+ wc.lpfnWndProc = MainWndProc; /* Function to retrieve messages for windows of this class. */
+ wc.cbClsExtra = 0; /* No per-class extra data. */
+ wc.cbWndExtra = 0; /* No per-window extra data. */
+ wc.hInstance = NULL; /* Application that owns the class. */
+ wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wc.hCursor = LoadCursor(NULL, IDC_CROSS);
+ wc.hbrBackground = GetStockObject(BLACK_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = p->AppName;
+
+ /* Make the cursor disapear over our window */
+ /* (How does it know our window ??) */
+ ShowCursor(FALSE);
+
+ if ((p->arv = RegisterClass(&wc)) == 0) {
+ debugr2((errout, "RegisterClass failed, lasterr = %d\n",GetLastError()));
+ p->inited = 2;
+ return 0;
+ }
+
+#ifndef WS_EX_NOACTIVATE
+# define WS_EX_NOACTIVATE 0x08000000L
+#endif
+ p->hwnd = CreateWindowEx(
+ WS_EX_NOACTIVATE | WS_EX_TOPMOST,
+// 0,
+ p->AppName,
+ "Argyll Display Calibration Window",
+ WS_VISIBLE | WS_DISABLED | WS_POPUP,
+// WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+// WS_POPUPWINDOW | WS_VISIBLE,
+ p->xo, p->yo, /* Location */
+ p->wi, p->he, /* Size */
+ NULL, /* Handle to parent or owner */
+ NULL, /* Handle to menu or child window */
+ NULL, /* hInstance Handle to appication instance */
+ NULL); /* pointer to window creation data */
+
+ if (!p->hwnd) {
+ debugr2((errout, "CreateWindow failed, lasterr = %d\n",GetLastError()));
+ p->inited = 2;
+ return 0;
+ }
+
+ /* Associate the dispwin object with the window, */
+ /* so that the event callback can access it */
+#ifdef _WIN64
+ SetWindowLongPtr(p->hwnd, GWLP_USERDATA, (LONG_PTR)p);
+#else
+ SetWindowLong(p->hwnd, GWL_USERDATA, (LONG)p);
+#endif
+
+ /*
+ Should we call BOOL SystemParametersInfo()
+ to disable high contrast, powertimout and screensaver timeout ?
+
+ */
+
+ debugrr2l(4, (stderr, "win_message_thread initialized - about to process messages\n"));
+ p->inited = 1;
+
+ for (;;) {
+ if (GetMessage(&msg, NULL, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+
+ if (p->quit != 0) {
+ /* Process any pending messages */
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ break;
+ }
+ }
+ }
+
+ if (UnregisterClass(p->AppName, NULL) == 0) {
+ warning("UnregisterClass failed, lasterr = %d\n",GetLastError());
+ }
+
+ p->hwnd = NULL; /* Signal it's been deleted */
+
+ return 0;
+}
+
+#endif /* NT */
+
+/* Create a RAMDAC access and display test window, default grey */
+dispwin *new_dispwin(
+disppath *disp, /* Display to calibrate. */
+double width, double height, /* Width and height in mm */
+double hoff, double voff, /* Offset from center in fraction of screen, range -1.0 .. 1.0 */
+int nowin, /* NZ if no window should be created - RAMDAC access only */
+int native, /* 0 = use current current or given calibration curve */
+ /* 1 = use native linear out & high precision */
+int *noramdac, /* Return nz if no ramdac access. native is set to 0 */
+int blackbg, /* NZ if whole screen should be filled with black */
+int override, /* NZ if override_redirect is to be used on X11 */
+int ddebug /* >0 to print debug statements to stderr */
+) {
+ dispwin *p = NULL;
+ char *cp;
+
+ debug("new_dispwin called\n");
+
+ if ((p = (dispwin *)calloc(sizeof(dispwin), 1)) == NULL) {
+ if (ddebug) fprintf(stderr,"new_dispwin failed because malloc failed\n");
+ return NULL;
+ }
+
+ /* !!!! Make changes in webwin.c as well !!!! */
+ p->nowin = nowin;
+ p->native = native;
+ p->blackbg = blackbg;
+ p->ddebug = ddebug;
+ p->get_ramdac = dispwin_get_ramdac;
+ p->set_ramdac = dispwin_set_ramdac;
+ p->install_profile = dispwin_install_profile;
+ p->uninstall_profile = dispwin_uninstall_profile;
+ p->get_profile = dispwin_get_profile;
+ p->set_color = dispwin_set_color;
+ p->set_update_delay = dispwin_set_update_delay;
+ p->set_callout = dispwin_set_callout;
+ p->del = dispwin_del;
+
+ p->rgb[0] = p->rgb[1] = p->rgb[2] = 0.5; /* Set Grey as the initial test color */
+
+ p->min_update_delay = 20;
+
+ if ((cp = getenv("ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS")) != NULL) {
+ p->min_update_delay = atoi(cp);
+ if (p->min_update_delay < 20)
+ p->min_update_delay = 20;
+ if (p->min_update_delay > 60000)
+ p->min_update_delay = 60000;
+ debugr2((errout, "new_dispwin: Minimum display update delay set to %d msec\n",p->min_update_delay));
+ }
+
+ p->update_delay = DISPLAY_UPDATE_DELAY; /* Default update delay */
+ if (p->update_delay < p->min_update_delay)
+ p->update_delay = p->min_update_delay;
+
+ /* Basic object is initialised, so create a window */
+
+ /* -------------------------------------------------- */
+#ifdef NT
+ {
+ WNDCLASS wc;
+ int disp_hsz, disp_vsz; /* Display horizontal/vertical size in mm */
+ int disp_hrz, disp_vrz; /* Display horizontal/vertical resolution in pixels */
+ int wi, he; /* Width and height of window in pixels */
+ int xo, yo; /* Window location in pixels */
+ int bpp;
+
+ p->AppName = "Argyll Test Window";
+
+ debugr2((errout, "new_dispwin: About to open display '%s'\n",disp->name));
+
+ /* Get device context to main display */
+ /* (This is the recommended way of doing this, and works on Vista) */
+ if ((p->hdc = CreateDC(disp->name, NULL, NULL, NULL)) == NULL) {
+ debugr2((errout, "new_dispwin: CreateDC failed, lasterr = %d\n",GetLastError()));
+ dispwin_del(p);
+ return NULL;
+ }
+
+ if ((p->name = strdup(disp->name)) == NULL) {
+ debugr2((errout, "new_dispwin: Malloc failed\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ if ((p->description = strdup(disp->description)) == NULL) {
+ debugr2((errout, "new_dispwin: Malloc failed\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ strcpy(p->monid, disp->monid);
+
+ disp_hsz = GetDeviceCaps(p->hdc, HORZSIZE); /* mm */
+ disp_vsz = GetDeviceCaps(p->hdc, VERTSIZE);
+ disp_hrz = GetDeviceCaps(p->hdc, HORZRES); /* pixels */
+ disp_vrz = GetDeviceCaps(p->hdc, VERTRES);
+
+ wi = (int)(width * (double)disp_hrz/(double)disp_hsz + 0.5);
+ if (wi > disp_hrz)
+ wi = disp_hrz;
+ he = (int)(height * (double)disp_vrz/(double)disp_vsz + 0.5);
+ if (he > disp_vrz)
+ he = disp_vrz;
+
+ if (p->blackbg) { /* Window fills the screen, test area is within it */
+ p->tx = (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5);
+ p->ty = (int)((voff * 0.5 + 0.5) * (disp->sh - he) + 0.5);
+ p->tw = wi;
+ p->th = he;
+ wi = disp->sw;
+ he = disp->sh;
+ xo = disp->sx;
+ yo = disp->sy;
+ } else { /* Test area completely fills the window */
+ p->tx = 0;
+ p->ty = 0;
+ p->tw = wi;
+ p->th = he;
+ xo = disp->sx + (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5);
+ yo = disp->sy + (int)((voff * 0.5 + 0.5) * (disp->sh - he) + 0.5);
+ }
+ p->ww = wi;
+ p->wh = he;
+
+ /* It's a bit difficult to know how windows defines the display */
+ /* depth. Microsofts doco is fuzzy, and typical values */
+ /* for BITSPIXEL and PLANES are confusing (What does "32" and "1" */
+ /* mean ?) NUMCOLORS seems to be -1 on my box, and perhaps */
+ /* is only applicable to up to 256 paletized colors. The doco */
+ /* for COLORRES is also fuzzy, but it returns a meaningful number */
+ /* on my box (24) */
+ if (p->ddebug) {
+ fprintf(errout,"Windows display RASTERCAPS 0x%x, BITSPIXEL %d, PLANES %d, NUMCOLORS %d, COLORRES %d\n",
+ GetDeviceCaps(p->hdc, RASTERCAPS),
+ GetDeviceCaps(p->hdc, BITSPIXEL),GetDeviceCaps(p->hdc, PLANES),
+ GetDeviceCaps(p->hdc, NUMCOLORS),GetDeviceCaps(p->hdc, COLORRES));
+ }
+ if (GetDeviceCaps(p->hdc, RASTERCAPS) & RC_PALETTE) {
+ debugr2((errout, "new_dispwin: can't calibrate palette based device!\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ bpp = GetDeviceCaps(p->hdc, COLORRES);
+ if (bpp <= 0)
+ p->pdepth = 8; /* Assume this is so */
+ else
+ p->pdepth = bpp/3;
+
+ if (nowin == 0) {
+
+ /* We use a thread to process the window messages, so that */
+ /* Task Manager doesn't think it's not responding. */
+
+ /* Because messages only get delivered to same thread that created window, */
+ /* the thread needs to create window. :-( */
+
+ p->xo = xo; /* Pass info to thread */
+ p->yo = yo;
+ p->wi = wi;
+ p->he = he;
+
+ if ((p->mth = new_athread(win_message_thread, (void *)p)) == NULL) {
+ debugr2((errout, "new_dispwin: new_athread failed\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+
+ /* Wait for thread to run */
+ while (p->inited == 0) {
+ msec_sleep(20);
+ }
+ /* If thread errored */
+ if (p->inited != 1) { /* Error */
+ debugr2((errout, "new_dispwin: new_athread returned error\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ }
+
+ /* Install the signal handler to ensure cleanup */
+ dispwin_install_signal_handlers(p);
+ }
+
+#endif /* NT */
+ /* -------------------------------------------------- */
+
+ /* -------------------------------------------------- */
+#ifdef __APPLE__
+
+ if ((p->name = strdup(disp->name)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ p->ddid = disp->ddid; /* Display we're working on */
+
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+ {
+ CGDisplayModeRef dispmode;
+ CFStringRef pixenc;
+
+ p->pdepth = 0;
+
+ dispmode = CGDisplayCopyDisplayMode(p->ddid);
+ pixenc = CGDisplayModeCopyPixelEncoding(dispmode);
+
+ /* Hmm. Don't know what to do with kIO16BitFloatPixels or kIO32BitFloatPixels */
+ if (CFStringCompare(pixenc, CFSTR(kIO64BitDirectPixels), kCFCompareCaseInsensitive)
+ == kCFCompareEqualTo)
+ p->pdepth = 16;
+ else if (CFStringCompare(pixenc, CFSTR(kIO30BitDirectPixels), kCFCompareCaseInsensitive)
+ == kCFCompareEqualTo)
+ p->pdepth = 10;
+ else if (CFStringCompare(pixenc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive)
+ == kCFCompareEqualTo)
+ p->pdepth = 8;
+ else if (CFStringCompare(pixenc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive)
+ == kCFCompareEqualTo)
+ p->pdepth = 5;
+ CFRelease(pixenc);
+ CGDisplayModeRelease(dispmode);
+ }
+#else
+ p->pdepth = CGDisplayBitsPerSample(p->ddid);
+#endif
+
+ if (nowin == 0) { /* Create a window */
+ osx_cntx_t *cx;
+ CGSize sz; /* Display size in mm */
+ int wi, he; /* Width and height in pixels */
+ int xo, yo; /* Window location */
+ NSRect wrect;
+
+ debugr2((errout, "new_dispwin: About to open display '%s'\n",disp->name));
+
+ /* If we don't have an application object, create one. */
+ /* (This should go in a common library) */
+ /* Note that we don't actually clean this up on exit - */
+ /* possibly we can't. */
+ if (NSApp == nil) {
+ static NSAutoreleasePool *pool; /* Pool used for NSApp */
+ pool = [NSAutoreleasePool new];
+ NSApp = [NSApplication sharedApplication]; /* Creates NSApp */
+ [NSApp finishLaunching];
+ /* We seem to need this, because otherwise we don't get focus automatically */
+ [NSApp activateIgnoringOtherApps: YES];
+ }
+
+ if ((cx = (osx_cntx_t *)calloc(sizeof(osx_cntx_t), 1)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed (osx_cntx_t)\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ cx->p = p;
+ p->osx_cntx = cx;
+
+ sz = CGDisplayScreenSize(p->ddid);
+ debugr2((errout," Display size = %f x %f mm\n",sz.width,sz.height));
+
+ wi = (int)(width * disp->sw/sz.width + 0.5);
+ if (wi > disp->sw)
+ wi = disp->sw;
+ he = (int)(height * disp->sh/sz.height + 0.5);
+ if (he > disp->sh)
+ he = disp->sh;
+
+ /* (Because Cocoa origin is botton left, we flip voff) */
+ /* (Cocoa doesn't use disp->sx/sy either - each screen origin is at 0,0) */
+ if (p->blackbg) { /* Window fills the screen, test area is within it */
+ p->tx = (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5);
+ p->ty = (int)((-voff * 0.5 + 0.5) * (disp->sh - he) + 0.5);
+ p->tw = wi;
+ p->th = he;
+ wi = disp->sw;
+ he = disp->sh;
+ xo = 0;
+ yo = 0;
+ } else { /* Test area completely fills the window */
+ p->tx = 0;
+ p->ty = 0;
+ p->tw = wi;
+ p->th = he;
+ xo = (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5);
+ yo = (int)((-voff * 0.5 + 0.5) * (disp->sh - he) + 0.5);
+ }
+ p->ww = wi;
+ p->wh = he;
+
+ wrect.origin.x = xo;
+ wrect.origin.y = yo;
+ wrect.size.width = wi;
+ wrect.size.height = he;
+
+ create_my_win(wrect, cx);
+
+ OSX_ProcessEvents(p);
+
+ p->winclose = 0;
+ }
+
+ /* Install the signal handler to ensure cleanup */
+ dispwin_install_signal_handlers(p);
+#endif /* __APPLE__ */
+ /* -------------------------------------------------- */
+
+ /* -------------------------------------------------- */
+#if defined(UNIX_X11)
+ {
+ /* NOTE: That we're not doing much to detect if the display/window
+ we open is unsuitable for high quality color (ie. at least
+ 24 bit etc.
+ */
+
+#ifdef NEVER // ?? is this for a specific reason ??
+ if (signal_dispwin != NULL) {
+ debugr2((errout,"new_dispwin: Attempting to open more than one dispwin!\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+#endif
+
+ /* stuff for X windows */
+ char *pp, *bname; /* base display name */
+ Window rootwindow;
+ char *appname = "TestWin";
+ Visual *myvisual;
+ XSetWindowAttributes myattr;
+ XEvent myevent;
+ XTextProperty myappname;
+ XSizeHints mysizehints;
+ XWMHints mywmhints;
+ int evb = 0, erb = 0; /* Extension version */
+ unsigned long myforeground,mybackground;
+ int disp_hsz, disp_vsz; /* Display horizontal/vertical size in mm */
+ int disp_hrz, disp_vrz; /* Display horizontal/vertical resolution in pixels (virtual screen) */
+ int wi, he; /* Width and height of window in pixels */
+ int xo, yo; /* Window location in pixels */
+
+ /* Create the base display name (in case of Xinerama, XRandR) */
+ if ((bname = strdup(disp->name)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ if ((pp = strrchr(bname, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) != NULL) {
+ sprintf(pp,".%d",disp->screen);
+ }
+ }
+
+ /* open the display */
+ p->mydisplay = XOpenDisplay(bname);
+ if(!p->mydisplay) {
+ debugr2((errout,"new_dispwin: Unable to open display '%s'\n",bname));
+ dispwin_del(p);
+ free(bname);
+ return NULL;
+ }
+ free(bname);
+ debugr("new_dispwin: Opened display OK\n");
+
+ if ((p->name = strdup(disp->name)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ p->myscreen = disp->screen;
+ p->myuscreen = disp->uscreen;
+ p->myrscreen = disp->rscreen;
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ /* These will be NULL otherwise */
+ p->icc_atom = disp->icc_atom;
+ p->crtc = disp->crtc;
+ p->output = disp->output;
+ p->icc_out_atom = disp->icc_out_atom;
+#endif /* randr >= V 1.2 */
+
+ if (disp->edid != NULL) {
+ if ((p->edid = malloc(sizeof(unsigned char) * disp->edid_len)) == NULL) {
+ debugr2((errout,"new_dispwin: Malloc failed\n"));
+ dispwin_del(p);
+ return NULL;
+ }
+ p->edid_len = disp->edid_len;
+ memmove(p->edid, disp->edid, p->edid_len);
+ }
+
+ //p->pdepth = DefaultDepth(p->mydisplay, p->myscreen)/3;
+ myvisual = DefaultVisual(p->mydisplay, p->myscreen);
+ p->pdepth = myvisual->bits_per_rgb;
+
+ if (nowin == 0) { /* Create a window */
+ rootwindow = RootWindow(p->mydisplay, p->myscreen);
+
+ myforeground = BlackPixel(p->mydisplay, p->myscreen);
+ mybackground = BlackPixel(p->mydisplay, p->myscreen);
+
+ /* Get device context to main display */
+ disp_hsz = DisplayWidthMM(p->mydisplay, p->myscreen);
+ disp_vsz = DisplayHeightMM(p->mydisplay, p->myscreen);
+ disp_hrz = DisplayWidth(p->mydisplay, p->myscreen);
+ disp_vrz = DisplayHeight(p->mydisplay, p->myscreen);
+
+ /* Compute width and offset from overal display in case Xinerama is active */
+ wi = (int)(width * (double)disp_hrz/(double)disp_hsz + 0.5);
+ if (wi > disp_hrz)
+ wi = disp_hrz;
+ he = (int)(height * (double)disp_vrz/(double)disp_vsz + 0.5);
+ if (he > disp_vrz)
+ he = disp_vrz;
+
+ if (p->blackbg) { /* Window fills the screen, test area is within it */
+ p->tx = (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5);
+ p->ty = (int)((voff * 0.5 + 0.5) * (disp->sh - he) + 0.5);
+ p->tw = wi;
+ p->th = he;
+ wi = disp->sw;
+ he = disp->sh;
+ xo = disp->sx;
+ yo = disp->sy;
+ } else { /* Test area completely fills the window */
+ p->tx = 0;
+ p->ty = 0;
+ p->tw = wi;
+ p->th = he;
+ xo = disp->sx + (int)((hoff * 0.5 + 0.5) * (disp->sw - wi) + 0.5);
+ yo = disp->sy + (int)((voff * 0.5 + 0.5) * (disp->sh - he) + 0.5);
+ }
+ p->ww = wi;
+ p->wh = he;
+
+ /* Setup Size Hints */
+ mysizehints.flags = PPosition | USSize;
+ mysizehints.x = xo;
+ mysizehints.y = yo;
+ mysizehints.width = wi;
+ mysizehints.height = he;
+
+ /* Setup Window Manager Hints */
+ mywmhints.flags = InputHint | StateHint;
+ mywmhints.input = 0;
+ mywmhints.initial_state = NormalState;
+
+ /* Setup Window Attributes */
+ myattr.background_pixel = mybackground;
+ myattr.bit_gravity = CenterGravity;
+ myattr.win_gravity = CenterGravity;
+ myattr.backing_store = WhenMapped; /* Since we aren't listning to events */
+ if (override)
+ myattr.override_redirect = True; /* Takes the WM out of the picture */
+ else
+ myattr.override_redirect = False;
+
+ debugr("Opening window\n");
+ p->mywindow = XCreateWindow(
+ p->mydisplay, rootwindow,
+ mysizehints.x,mysizehints.y,mysizehints.width,mysizehints.height,
+ 0, /* Border width */
+ CopyFromParent, /* Depth */
+ InputOutput, /* Class */
+ CopyFromParent, /* Visual */
+ CWBackPixel | CWBitGravity /* Attributes Valumask */
+ | CWWinGravity | CWBackingStore | CWOverrideRedirect,
+ &myattr /* Attribute details */
+ );
+
+#ifdef NEVER
+ XWindowAttributes mywattributes;
+
+ /* Get the windows attributes */
+ if (XGetWindowAttributes(
+ p->mydisplay, p->mywindow,
+ &mywattributes) == 0) {
+ debugr("new_dispwin: XGetWindowAttributes failed\n");
+ dispwin_del(p);
+ return NULL;
+ }
+ p->pdepth = mywattributes.depth/3;
+#endif
+
+ /* Setup TextProperty */
+ XStringListToTextProperty(&appname, 1, &myappname);
+
+ XSetWMProperties(
+ p->mydisplay, p->mywindow,
+ &myappname, /* Window name */
+ &myappname, /* Icon name */
+ NULL, 0, /* argv, argc */
+ &mysizehints,
+ &mywmhints,
+ NULL); /* No class hints */
+
+ /* Set aditional properties */
+ {
+ Atom optat;
+ unsigned int opaque = 0xffffffff;
+ unsigned int xid = (unsigned int)rootwindow; /* Hope this is 32 bit */
+ XChangeProperty(
+ p->mydisplay, p->mywindow,
+ XA_WM_TRANSIENT_FOR, /* Property */
+ XA_WINDOW, /* Type */
+ 32, /* format = bits in type of unsigned int */
+ PropModeReplace, /* Change mode */
+ (char *)(&xid), /* Data is Root Window XID */
+ 1 /* Number of elements of data */
+ );
+
+ /* Set hint for compositing WMs that the window must be opaque */
+ if ((optat = XInternAtom(p->mydisplay, "_NET_WM_WINDOW_OPACITY", False)) != None) {
+ XChangeProperty(p->mydisplay, p->mywindow, optat,
+ XA_CARDINAL, 32, PropModeReplace, (char *)(&opaque), 1);
+ }
+ if ((optat = XInternAtom(p->mydisplay, "_NET_WM_WINDOW_OPACITY_LOCKED", False)) != None) {
+ XChangeProperty(p->mydisplay, p->mywindow, optat,
+ XA_CARDINAL, 32, PropModeReplace, (char *)(&opaque), 1);
+ }
+ }
+
+ p->mygc = XCreateGC(p->mydisplay,p->mywindow,0,0);
+ XSetBackground(p->mydisplay,p->mygc,mybackground);
+ XSetForeground(p->mydisplay,p->mygc,myforeground);
+
+ /* Create an invisible cursor over our window */
+ {
+ Cursor mycursor;
+ Pixmap mypixmap;
+ Colormap mycmap;
+ XColor col;
+ char pmdata[1] = { 0 };
+
+ col.red = col.green = col.blue = 0;
+
+ mycmap = DefaultColormap(p->mydisplay, p->myscreen);
+ XAllocColor(p->mydisplay, mycmap, &col);
+ mypixmap = XCreatePixmapFromBitmapData(p->mydisplay, p->mywindow, pmdata, 1, 1, 0, 0, 1);
+ mycursor = XCreatePixmapCursor(p->mydisplay, mypixmap, mypixmap, &col, &col, 0,0);
+ XDefineCursor(p->mydisplay, p->mywindow, mycursor);
+ }
+
+ XSelectInput(p->mydisplay,p->mywindow, ExposureMask);
+
+ XMapRaised(p->mydisplay,p->mywindow);
+ debug("Raised window\n");
+
+ /* ------------------------------------------------------- */
+ /* Suspend any screensavers if we can */
+
+ /* Install the signal handler to ensure cleanup */
+ dispwin_install_signal_handlers(p);
+
+#if ScreenSaverMajorVersion >= 1 && ScreenSaverMinorVersion >= 1 /* X11R7.1 ??? */
+
+ /* Disable any screensavers that work properly with XScreenSaverSuspend() */
+ if (XScreenSaverQueryExtension (p->mydisplay, &evb, &erb) != 0) {
+ int majv, minv;
+ XScreenSaverSuspend(p->mydisplay, True);
+ p->xsssuspend = 1;
+
+ /* Else we'd have to register as a screensaver to */
+ /* prevent another one activating ?? */
+ }
+#endif /* X11R7.1 screensaver extension */
+
+ /* Disable the native X11 screensaver */
+ if (p->xsssuspend == 0) {
+
+ /* Save the screensaver state, and then disable it */
+ XGetScreenSaver(p->mydisplay, &p->timeout, &p->interval,
+ &p->prefer_blanking, &p->allow_exposures);
+ XSetScreenSaver(p->mydisplay, 0, 0, DefaultBlanking, DefaultExposures);
+ p->xssvalid = 1;
+ }
+
+ /* Disable xscreensaver if it is running */
+ if (p->xssrunning == 0) {
+ p->xssrunning = (system("xscreensaver-command -version 2>/dev/null >/dev/null") == 0);
+ if (p->xssrunning)
+ system("xscreensaver-command -exit 2>/dev/null >/dev/null");
+ }
+
+ /* Disable gnomescreensaver if it is running */
+ if (p->gnomessrunning == 0) {
+ p->gnomessrunning = (system("gnome-screensaver-command -q "
+ "2>/dev/null >/dev/null") == 0);
+ if (p->gnomessrunning) {
+ sigset_t nsm, osm;
+ /* Ensure that other process doesn't get the signals we want to catch */
+ sigemptyset(&nsm);
+ sigaddset(&nsm,SIGHUP);
+ sigaddset(&nsm,SIGINT);
+ sigaddset(&nsm,SIGTERM);
+ sigprocmask(SIG_BLOCK, &nsm, &osm);
+
+ if ((p->gnomepid = fork()) == 0) {
+ freopen("/dev/null", "r", stdin);
+ freopen("/dev/null", "a", stdout); /* Hide output */
+ freopen("/dev/null", "a", stderr);
+ execlp("gnome-screensaver-command", "gnome-screensaver-command","-i","-n","argyll","-r","measuring screen",NULL);
+
+ _exit(0);
+ }
+ sigprocmask(SIG_SETMASK, &osm, NULL); /* restore the signals */
+ }
+ }
+
+ /* kscreensaver > 3.5.9 obeys XResetScreenSaver(), but earlier versions don't. */
+ /* Disable any KDE screen saver if it's active */
+ if (p->kdessrunning == 0) {
+ /* dcop is very slow if we're not actually running kde. */
+ /* Check that kde is running first */
+ if (system("ps -e 2>/dev/null | grep kdesktop 2>/dev/null >/dev/null") == 0) {
+ p->kdessrunning = (system("dcop kdesktop KScreensaverIface isEnabled "
+ "2>/dev/null | grep true 2>/dev/null >/dev/null") == 0);
+ }
+ if (p->kdessrunning) {
+ system("dcop kdesktop KScreensaverIface enable false 2>&1 >/dev/null");
+ }
+ }
+
+ /* If DPMS is enabled, disable it */
+ if (DPMSQueryExtension(p->mydisplay, &evb, &erb) != 0) {
+ CARD16 power_level;
+ BOOL state;
+
+ if (DPMSInfo(p->mydisplay, &power_level, &state)) {
+ if ((p->dpmsenabled = state) != 0)
+ DPMSDisable(p->mydisplay);
+ }
+ }
+
+ /* Deal with any pending events */
+ debug("About to enter main loop\n");
+ while(XPending(p->mydisplay) > 0) {
+ XNextEvent(p->mydisplay, &myevent);
+ switch(myevent.type) {
+ case Expose:
+ if(myevent.xexpose.count == 0) { /* Repare the exposed region */
+ debug("Servicing final expose\n");
+ XFillRectangle(p->mydisplay, p->mywindow, p->mygc,
+ p->tx, p->ty, p->tw, p->th);
+ debug("Finished expose\n");
+ }
+ break;
+ }
+ }
+ } else {
+ /* Install the signal handler to ensure cleanup */
+ dispwin_install_signal_handlers(p);
+ }
+ }
+#endif /* UNIX X11 */
+ /* -------------------------------------------------- */
+
+ if (!p->nowin) {
+ /* Setup for native mode */
+ if (p->native) {
+ debug("About to setup native mode\n");
+ if ((p->or = p->get_ramdac(p)) == NULL
+ || (p->r = p->or->clone(p->or)) == NULL) {
+ if (noramdac != NULL)
+ *noramdac = 1;
+ debugr("new_dispwin: Accessing VideoLUT failed, so no way to guarantee that calibration is turned off!!\n");
+ warning("new_dispwin: Accessing VideoLUT failed, so no way to guarantee that calibration is turned off!!");
+ p->native = 0;
+ } else {
+ p->r->setlin(p->r);
+ if (noramdac != NULL)
+ *noramdac = 0;
+ debug("Saved original VideoLUT\n");
+ }
+ } else {
+ if (p->get_ramdac(p) == NULL) {
+ if (noramdac != NULL)
+ *noramdac = 1;
+ }
+ }
+
+ /* Make sure initial test color is displayed */
+ dispwin_set_color(p, p->rgb[0], p->rgb[1], p->rgb[2]);
+ }
+
+ debugr("new_dispwin: return sucessfully\n");
+ return p;
+}
+
+/* ================================================================ */
+#if defined(UNIX_X11)
+/* Process to continuously monitor XRandR events, */
+/* and load the appropriate calibration and profiles */
+/* for each monitor. */
+int x11_daemon_mode(disppath *disp, int verb, int ddebug) {
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2 && !defined(DISABLE_RANDR)
+ char *dname;
+ char *pp;
+ char dnbuf[100];
+ Display *mydisplay;
+ int majv, minv; /* Version */
+ int evb = 0, erb = 0;
+ int dopoll = 1; /* Until XRandR is fixed */
+ XEvent myevent;
+ int update_profiles = 1; /* Do it on entry */
+
+ /* Open the base display */
+ strncpy(dnbuf,disp->name,99); dnbuf[99] = '\000';
+ if ((pp = strrchr(dnbuf, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) == NULL)
+ strcat(dnbuf,".0");
+ else {
+ if (pp[1] == '\000')
+ strcat(dnbuf,"0");
+ else {
+ pp[1] = '0';
+ pp[2] = '\000';
+ }
+ }
+ }
+
+ if ((mydisplay = XOpenDisplay(dnbuf)) == NULL) {
+ debug2((errout, "x11_daemon_mode: failed to open display '%s'\n",dnbuf));
+ return -1;
+ }
+
+ if (verb) printf("Opened display '%s'\n",dnbuf);
+
+ /* !!!! we want to create a test here, to see if we have to poll, */
+ /* !!!! or whether we spontainously get events when the EDID changes. */
+
+ /* Use Xrandr 1.2 if it's available and not disabled */
+ if (getenv("ARGYLL_IGNORE_XRANDR1_2") == NULL
+ && XRRQueryExtension(mydisplay, &evb, &erb) != 0
+ && XRRQueryVersion(mydisplay, &majv, &minv)
+ && majv == 1 && minv >= 2) {
+ if (verb) printf("Found XRandR 1.2 or latter\n");
+
+ XRRSelectInput(mydisplay,RootWindow(mydisplay,0),
+ RRScreenChangeNotifyMask
+ | RRCrtcChangeNotifyMask
+ | RROutputChangeNotifyMask
+ | RROutputPropertyNotifyMask
+ );
+
+ /* Deal with any pending events */
+ if (verb) printf("About to enter main loop waiting for XRandR changes\n");
+ for(;;) {
+
+ if (update_profiles == 0) {
+ if (dopoll) {
+ for (;;) {
+ XRRGetScreenResources(mydisplay, RootWindow(mydisplay,0));
+ if(XPending(mydisplay) > 0)
+ break;
+ sleep(2);
+ }
+ } else {
+ /* Sleep until there is an event */
+ XPeekEvent(mydisplay, &myevent);
+ }
+ }
+
+ /* Get all our events until we run out */
+ while (XPending(mydisplay) > 0) {
+ XNextEvent(mydisplay, &myevent);
+ if (myevent.type == evb + RRScreenChangeNotify) {
+// printf("~1 Got RRScreenChangeNotify\n");
+ update_profiles = 1;
+ } else if (myevent.type == evb + RRNotify) {
+ update_profiles = 1;
+ XRRNotifyEvent *rrne = (XRRNotifyEvent *)(&myevent);
+ if (rrne->subtype == RRNotify_CrtcChange) {
+// printf("~1 Got RRCrtcChangeNotify\n");
+ }
+ else if (rrne->subtype == RRNotify_OutputChange) {
+// printf("~1 Got RROutputChangeNotify\n");
+ }
+ else if (rrne->subtype == RRNotify_OutputProperty) {
+// printf("~1 Got RROutputPropertyNotify\n");
+ }
+ }
+ }
+
+ if (update_profiles) {
+ disppath **dp;
+ ramdac *r = NULL;
+
+ if (verb) printf("Updating profiles for display '%s'\n",dnbuf);
+
+ dp = get_displays();
+ if (dp == NULL || dp[0] == NULL) {
+ if (verb) printf("Failed to enumerate all the screens for display '%s'\n",dnbuf);
+ continue;
+ } else {
+ int i, j;
+ dispwin *dw;
+ char calname[MAXNAMEL+1] = "\000"; /* Calibration file name */
+ icmFile *rd_fp = NULL;
+ icc *icco = NULL;
+ icmVideoCardGamma *wo;
+ double iv;
+
+ for (i = 0; ; i++) {
+ if (dp[i] == NULL)
+ break;
+ if (verb) printf("Updating display %d = '%s'\n",i+1,dp[i]->description);
+
+ if ((dw = new_dispwin(dp[i], 0.0, 0.0, 0.0, 0.0, 1, 0, NULL, 0, 0, ddebug)) == NULL) {
+ if (verb) printf("Failed to access screen %d of display '%s'\n",i+1,dnbuf);
+ continue;
+ }
+ if ((r = dw->get_ramdac(dw)) == NULL) {
+ if (verb) printf("Failed to access VideoLUT of screen %d for display '%s'\n",i+1,dnbuf);
+ dw->del(dw);
+ continue;
+ }
+
+ /* Grab the installed profile from the ucmm */
+ if ((rd_fp = dw->get_profile(dw, calname, MAXNAMEL)) == NULL) {
+ if (verb) printf("Failed to find profile of screen %d for display '%s'\n",i+1,dnbuf);
+ r->del(r);
+ dw->del(dw);
+ continue;
+ }
+
+ if ((icco = new_icc()) == NULL) {
+ if (verb) printf("Failed to create profile object for screen %d for display '%s'\n",i+1,dnbuf);
+ rd_fp->del(rd_fp);
+ r->del(r);
+ dw->del(dw);
+ continue;
+ }
+
+ /* Read header etc. */
+ if (icco->read(icco, rd_fp,0) != 0) { /* Read ICC OK */
+ if (verb) printf("Failed to read profile for screen %d for display '%s'\n",i+1,dnbuf);
+ icco->del(icco);
+ rd_fp->del(rd_fp);
+ r->del(r);
+ dw->del(dw);
+ continue;
+ }
+
+ if ((wo = (icmVideoCardGamma *)icco->read_tag(icco, icSigVideoCardGammaTag)) == NULL) {
+ if (verb) printf("Failed to fined vcgt tagd in profile for screen %d for display '%s' so setting linear\n",i+1,dnbuf);
+ for (j = 0; j < r->nent; j++) {
+ iv = j/(r->nent-1.0);
+ r->v[0][j] = iv;
+ r->v[1][j] = iv;
+ r->v[2][j] = iv;
+ }
+ } else {
+ if (wo->u.table.channels == 3) {
+ for (j = 0; j < r->nent; j++) {
+ iv = j/(r->nent-1.0);
+ r->v[0][j] = wo->lookup(wo, 0, iv);
+ r->v[1][j] = wo->lookup(wo, 1, iv);
+ r->v[2][j] = wo->lookup(wo, 2, iv);
+ }
+ } else if (wo->u.table.channels == 1) {
+ for (j = 0; j < r->nent; j++) {
+ iv = j/(r->nent-1.0);
+ r->v[0][j] =
+ r->v[1][j] =
+ r->v[2][j] = wo->lookup(wo, 0, iv);
+ }
+ debug("Got monochrom vcgt calibration\n");
+ } else {
+ if (verb) printf("vcgt tag is unrecognized in profile for screen %d for display '%s'\n",i+1,dnbuf);
+ icco->del(icco);
+ rd_fp->del(rd_fp);
+ r->del(r);
+ dw->del(dw);
+ continue;
+ }
+ }
+ if (dw->set_ramdac(dw,r,1) != 0) {
+ if (verb) printf("Unable to set vcgt tag for screen %d for display '%s'\n",i+1,dnbuf);
+ icco->del(icco);
+ rd_fp->del(rd_fp);
+ r->del(r);
+ dw->del(dw);
+ continue;
+ }
+ if (verb) printf("Loaded profile and calibration for screen %d for display '%s'\n",i+1,dnbuf);
+ icco->del(icco);
+ rd_fp->del(rd_fp);
+ r->del(r);
+ dw->del(dw);
+ }
+ }
+ free_disppaths(dp);
+ update_profiles = 0;
+ }
+ }
+ } else
+#endif /* randr >= V 1.2 */
+
+ if (verb) printf("XRandR 1.2 is not available - quitting\n");
+ return -1;
+}
+
+#endif
+
+/* ================================================================ */
+#ifdef STANDALONE_TEST
+/* test/utility code */
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a ppc gcc 3.3 optimiser bug... */
+/* It seems to cause a segmentation fault instead of */
+/* converting an integer loop index into a float, */
+/* when there are sufficient variables in play. */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+#include "numlib.h"
+
+static void usage(char *diag, ...) {
+ disppath **dp;
+ fprintf(stderr,"Test display patch window, Set Video LUTs, Install profiles, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: dispwin [options] [calfile] \n");
+ fprintf(stderr," -v Verbose mode\n");
+#if defined(UNIX_X11)
+ fprintf(stderr," -display displayname Choose X11 display name\n");
+ fprintf(stderr," -d n[,m] Choose the display n from the following list (default 1)\n");
+ fprintf(stderr," Optionally choose different display m for Video LUT access\n");
+#else
+ fprintf(stderr," -d n Choose the display from the following list (default 1)\n");
+#endif
+ dp = get_displays();
+ if (dp == NULL || dp[0] == NULL) {
+ fprintf(stderr," ** No displays found **\n");
+ } else {
+ int i;
+ for (i = 0; ; i++) {
+ if (dp[i] == NULL)
+ break;
+ fprintf(stderr," %d = '%s'\n",i+1,dp[i]->description);
+ }
+ }
+ free_disppaths(dp);
+ fprintf(stderr," -dweb[:port] Display via a web server at port (default 8080)\n");
+ fprintf(stderr," -P ho,vo,ss[,vs] Position test window and scale it\n");
+ fprintf(stderr," -F Fill whole screen with black background\n");
+ fprintf(stderr," -i Run forever with random values\n");
+ fprintf(stderr," -G filename Display RGB colors from CGATS file\n");
+ fprintf(stderr," -m Manually cycle through values\n");
+ fprintf(stderr," -f Test grey ramp fade\n");
+ fprintf(stderr," -r Test just Video LUT loading & Beeps\n");
+ fprintf(stderr," -n Test native output (rather than through Video LUT)\n");
+ fprintf(stderr," -s filename Save the currently loaded Video LUT to 'filename'\n");
+ fprintf(stderr," -c Load a linear display calibration\n");
+ fprintf(stderr," -V Verify that calfile/profile cal. is currently loaded in LUT\n");
+ fprintf(stderr," -I Install profile for display and use it's calibration\n");
+ fprintf(stderr," -U Un-install profile for display\n");
+ fprintf(stderr," -S d Specify the install/uninstall scope for OS X [nlu] or X11/Vista [lu]\n");
+ fprintf(stderr," d is one of: n = network, l = local system, u = user (default)\n");
+ fprintf(stderr," -L Load installed profiles cal. into Video LUT\n");
+#if defined(UNIX_X11)
+ fprintf(stderr," -E Run in daemon loader mode for given X11 server\n");
+#endif /* X11 */
+ fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
+ fprintf(stderr," calfile Load calibration (.cal or %s) into Video LUT\n",ICC_FILE_EXT);
+ exit(1);
+}
+
+/* 32 bit pseudo random sequencer based on XOR feedback */
+/* generates number between 1 and 4294967295 */
+#define PSRAND32(S) (((S) & 0x80000000) ? (((S) << 1) ^ 0xa398655d) : ((S) << 1))
+
+int
+main(int argc, char *argv[]) {
+ int fa, nfa, mfa; /* current argument we're looking at */
+ int verb = 0; /* Verbose flag */
+ int ddebug = 0; /* debug level */
+ int webdisp = 0; /* NZ for web display, == port number */
+ disppath *disp = NULL; /* Display being used */
+ double hpatscale = 1.0, vpatscale = 1.0; /* scale factor for test patch size */
+ double ho = 0.0, vo = 0.0; /* Test window offsets, -1.0 to 1.0 */
+ int blackbg = 0; /* NZ if whole screen should be filled with black */
+ int nowin = 0; /* Don't create test window */
+ int ramd = 0; /* Just test ramdac */
+ int fade = 0; /* Test greyramp fade */
+ int native = 0; /* 0 = use current current or given calibration curve */
+ /* 1 = set native linear output and use ramdac high prec'n */
+ /* 2 = set native linear output */
+ int noramdac = 0; /* Set to nz if there is no VideoLUT access */
+ int inf = 0; /* Infnite/manual patches flag */
+ char pcname[MAXNAMEL+1] = "\000"; /* CGATS patch color name */
+ int clear = 0; /* Clear any display calibration (any calname is ignored) */
+ char sname[MAXNAMEL+1] = "\000"; /* Current cal save name */
+ int verify = 0; /* Verify that calname is currently loaded */
+ int installprofile = 0; /* Install (1) or uninstall (2) a profile for display */
+ int loadprofile = 0; /* Load displays profile calibration into LUT */
+ int loadfile = 0; /* Load given profile into LUT */
+ p_scope scope = p_scope_user; /* Scope of profile instalation/un-instalation */
+ int daemonmode = 0; /* X11 daemin loader mode */
+ char calname[MAXNAMEL+1] = "\000"; /* Calibration file name */
+ dispwin *dw;
+ unsigned int seed = 0x56781234;
+ int i, j;
+ ramdac *or = NULL, *r = NULL;
+ int is_ok_icc = 0; /* The profile is OK */
+
+ error_program = "Dispwin";
+ check_if_not_interactive();
+
+ /* Process the arguments */
+ mfa = 0; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ else if (argv[fa][1] == 'v')
+ verb = 1;
+
+ /* Debug */
+ else if (argv[fa][1] == 'D') {
+ ddebug = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ ddebug = atoi(na);
+ fa = nfa;
+ }
+ callback_ddebug = ddebug; /* dispwin global */
+ }
+
+ /* Display number */
+ else if (argv[fa][1] == 'd') {
+ if (strncmp(na,"web",3) == 0
+ || strncmp(na,"WEB",3) == 0) {
+ webdisp = 8080;
+ if (na[3] == ':') {
+ webdisp = atoi(na+4);
+ if (webdisp == 0 || webdisp > 65535)
+ usage("Web port number must be in range 1..65535");
+ }
+ fa = nfa;
+ } else {
+#if defined(UNIX_X11)
+ int ix, iv;
+
+ /* X11 type display name. */
+ if (strcmp(&argv[fa][2], "isplay") == 0 || strcmp(&argv[fa][2], "ISPLAY") == 0) {
+ if (++fa >= argc || argv[fa][0] == '-') usage("-DISPLAY parameter missing");
+ setenv("DISPLAY", argv[fa], 1);
+ } else {
+ if (na == NULL) usage("-d parameter missing");
+ fa = nfa;
+ if (sscanf(na, "%d,%d",&ix,&iv) != 2) {
+ ix = atoi(na);
+ iv = 0;
+ }
+ if (disp != NULL)
+ free_a_disppath(disp);
+ if ((disp = get_a_display(ix-1)) == NULL)
+ usage("-d parameter '%s' is out of range",na);
+ if (iv > 0)
+ disp->rscreen = iv-1;
+ }
+#else
+ int ix;
+ if (na == NULL) usage("-d parameter is missing");
+ fa = nfa;
+ ix = atoi(na);
+ if (disp != NULL)
+ free_a_disppath(disp);
+ if ((disp = get_a_display(ix-1)) == NULL)
+ usage("-d parameter '%s' is out of range",na);
+#endif
+ }
+ }
+
+ /* Test patch offset and size */
+ else if (argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage("-p parameters are missing");
+ if (sscanf(na, " %lf,%lf,%lf,%lf ", &ho, &vo, &hpatscale, &vpatscale) == 4) {
+ ;
+ } else if (sscanf(na, " %lf,%lf,%lf ", &ho, &vo, &hpatscale) == 3) {
+ vpatscale = hpatscale;
+ } else {
+ usage("-p parameters '%s' is badly formatted",na);
+ }
+ if (ho < 0.0 || ho > 1.0
+ || vo < 0.0 || vo > 1.0
+ || hpatscale <= 0.0 || hpatscale > 50.0
+ || vpatscale <= 0.0 || vpatscale > 50.0)
+ usage("-p parameters '%s' is out of range",na);
+ ho = 2.0 * ho - 1.0;
+ vo = 2.0 * vo - 1.0;
+
+ /* Black background */
+ } else if (argv[fa][1] == 'F') {
+ blackbg = 1;
+
+ } else if (argv[fa][1] == 'i')
+ inf = 1;
+
+ else if (argv[fa][1] == 'm' || argv[fa][1] == 'M')
+ inf = 2;
+
+ /* CGATS patch color file */
+ else if (argv[fa][1] == 'G') {
+ fa = nfa;
+ if (na == NULL) usage("-G parameter is missing");
+ strncpy(pcname,na,MAXNAMEL); pcname[MAXNAMEL] = '\000';
+ }
+ else if (argv[fa][1] == 'f')
+ fade = 1;
+
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R')
+ ramd = 1;
+
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ native = 1;
+ if (argv[fa][1] == 'N')
+ native = 2;
+ }
+
+ else if (argv[fa][1] == 's') {
+ fa = nfa;
+ if (na == NULL) usage("-s parameter is missing");
+ strncpy(sname,na,MAXNAMEL); sname[MAXNAMEL] = '\000';
+ }
+
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C')
+ clear = 1;
+
+ else if (argv[fa][1] == 'V')
+ verify = 1;
+
+ else if (argv[fa][1] == 'I')
+ installprofile = 1;
+
+ else if (argv[fa][1] == 'U')
+ installprofile = 2;
+
+ else if (argv[fa][1] == 'L')
+ loadprofile = 1;
+
+ else if (argv[fa][1] == 'E')
+ daemonmode = 1;
+
+ else if (argv[fa][1] == 'S') {
+ fa = nfa;
+ if (na == NULL) usage("-S parameter is missing");
+ if (na[0] == 'n' || na[0] == 'N')
+ scope = p_scope_network;
+ else if (na[0] == 'l' || na[0] == 'L')
+ scope = p_scope_local;
+ else if (na[0] == 'u' || na[0] == 'U')
+ scope = p_scope_user;
+ }
+ else
+ usage("Unknown flag '%s'",argv[fa]);
+ }
+ else
+ break;
+ }
+
+ /* No explicit display has been set */
+ if (webdisp == 0 && disp == NULL) {
+ int ix = 0;
+#if defined(UNIX_X11)
+ char *dn, *pp;
+
+ if ((dn = getenv("DISPLAY")) != NULL) {
+ if ((pp = strrchr(dn, ':')) != NULL) {
+ if ((pp = strchr(pp, '.')) != NULL) {
+ if (pp[1] != '\000')
+ ix = atoi(pp+1);
+ }
+ }
+ }
+#endif
+ if ((disp = get_a_display(ix)) == NULL)
+ error("Unable to open the default display");
+ }
+
+ /* See if there's a calibration file */
+ if (fa < argc) {
+ strncpy(calname,argv[fa++],MAXNAMEL); calname[MAXNAMEL] = '\000';
+ if (installprofile == 0 && loadprofile == 0 && verify == 0)
+ loadfile = 1; /* Load the given profile into the videoLUT */
+ }
+
+#if defined(UNIX_X11)
+ if (webdisp == 0 && daemonmode) {
+ return x11_daemon_mode(disp, verb, ddebug);
+ }
+#endif
+
+ /* Bomb on bad combinations (not all are being detected) */
+ if (installprofile && calname[0] == '\000')
+ error("Can't install or uninstall a displays profile without profile argument");
+
+ if (verify && calname[0] == '\000' && loadprofile == 0)
+ error("No calibration/profile provided to verify against");
+
+ if (verify && installprofile == 1)
+ error("Can't verify and install a displays profile at the same time");
+
+ if (verify && installprofile == 2)
+ error("Can't verify and uninstall a displays profile at the same time");
+
+ /* Don't create a window if it won't be used */
+ if (ramd != 0 || sname[0] != '\000' || clear != 0 || verify != 0 || loadfile != 0 || installprofile != 0 || loadprofile != 0)
+ nowin = 1;
+
+
+ if (webdisp != 0) {
+ if ((dw = new_webwin(webdisp, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, nowin, blackbg, verb, ddebug)) == NULL) {
+ printf("Error - new_webpwin failed!\n");
+ return -1;
+ }
+ noramdac = 1;
+
+ } else {
+ if (verb) printf("About to open dispwin object on the display\n");
+ if ((dw = new_dispwin(disp, 100.0 * hpatscale, 100.0 * vpatscale, ho, vo, nowin, native, &noramdac, blackbg, 1, ddebug)) == NULL) {
+ printf("Error - new_dispwin failed!\n");
+ return -1;
+ }
+ }
+
+ if (native != 0 && noramdac) {
+ error("We don't have access to the VideoLUT so can't display native colors\n");
+ }
+
+ /* Save the current Video LUT to the calfile */
+ if (sname[0] != '\000') {
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats_set_elem *setel; /* Array of set value elements */
+ int nsetel = 0;
+
+ if (verb)
+ printf("About to save current loaded calibration to file '%s'\n",sname);
+
+ if ((r = dw->get_ramdac(dw)) == NULL) {
+ error("We don't have access to the VideoLUT");
+ }
+
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CAL"); /* our special type is Calibration file */
+
+ ocg->add_table(ocg, tt_other, 0); /* Add a table for RAMDAC values */
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Device Calibration Curves",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll synthcal", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL);
+ ocg->add_kword(ocg, 0, "COLOR_REP", "RGB", NULL);
+
+ ocg->add_field(ocg, 0, "RGB_I", r_t);
+ ocg->add_field(ocg, 0, "RGB_R", r_t);
+ ocg->add_field(ocg, 0, "RGB_G", r_t);
+ ocg->add_field(ocg, 0, "RGB_B", r_t);
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * 4)) == NULL)
+ error("Malloc failed!");
+
+ /* Write the video lut curve values */
+ for (i = 0; i < r->nent; i++) {
+ double iv = i/(r->nent-1.0);
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ setel[0].d = iv;
+ setel[1].d = r->v[0][i];
+ setel[2].d = r->v[1][i];
+ setel[3].d = r->v[2][i];
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+
+ if (ocg->write_name(ocg, sname))
+ error("Write error to '%s' : %s",sname,ocg->err);
+
+ ocg->del(ocg); /* Clean up */
+ r->del(r);
+ r = NULL;
+
+ /* Fall through, as we may want to do other stuff too */
+ }
+
+ /* Clear the display calibration curve */
+ if (clear != 0) {
+ int rv;
+
+ if ((r = dw->get_ramdac(dw)) == NULL) {
+ error("We don't have access to the VideoLUT");
+ }
+
+ for (i = 0; i < r->nent; i++) {
+ double iv = i/(r->nent-1.0);
+ r->v[0][i] = iv;
+ r->v[1][i] = iv;
+ r->v[2][i] = iv;
+ }
+ if (verb)
+ printf("About to clear the calibration\n");
+ if ((rv = dw->set_ramdac(dw,r,1)) != 0) {
+ if (rv == 2)
+ warning("Failed to set VideoLUTs persistently because current System Profile can't be renamed");
+ else
+ error("Failed to set VideoLUTs");
+ }
+
+ r->del(r);
+ r = NULL;
+
+ /* Fall through, as we may want to do other stuff too */
+ }
+
+ /* Un-Install the profile from the display */
+ if (installprofile == 2) {
+ int rv;
+ if ((rv = dw->uninstall_profile(dw, calname, scope))) {
+ if (rv == 2)
+ warning("Profile '%s' not found to uninstall!",calname);
+ else
+ error("Error trying to uninstall profile '%s'!",calname);
+ }
+ if (verb) {
+ printf("Un-Installed '%s'\n",calname);
+ }
+ }
+
+ /* Get any calibration from the provided .cal file or .profile, */
+ /* or calibration from the current default display profile, */
+ /* and put it in r */
+ if (loadfile != 0 || verify != 0 || loadprofile != 0 || installprofile == 1) {
+ icmFile *rd_fp = NULL;
+ icc *icco = NULL;
+ cgats *ccg = NULL; /* calibration cgats structure */
+
+ /* Get a calibration that's compatible with the display. */
+ /* This can fail and return NULL - error if we later need it */
+ r = dw->get_ramdac(dw);
+
+ /* Should we load calfile instead of installed profile if it's present ??? */
+ if (loadprofile) {
+ if (calname[0] != '\000')
+ warning("Profile '%s' provided as argument is being ignored!\n",calname);
+
+ /* Get the current displays profile */
+ debug2((errout,"Loading calibration from display profile '%s'\n",dw->name));
+ if ((rd_fp = dw->get_profile(dw, calname, MAXNAMEL)) == NULL)
+ error("Failed to get the displays current ICC profile\n");
+
+ } else {
+ /* Open up the profile for reading */
+ debug2((errout,"Loading calibration from file '%s'\n",calname));
+ if ((rd_fp = new_icmFileStd_name(calname,"r")) == NULL)
+ error("Can't open file '%s'",calname);
+ }
+
+ if ((icco = new_icc()) == NULL)
+ error("Creation of ICC object failed");
+
+ /* Read header etc. */
+ if (icco->read(icco, rd_fp,0) == 0) { /* Read ICC OK */
+ icmVideoCardGamma *wo;
+ double iv;
+
+ is_ok_icc = 1; /* The profile is OK */
+
+ if ((wo = (icmVideoCardGamma *)icco->read_tag(icco, icSigVideoCardGammaTag)) == NULL) {
+ warning("No vcgt tag found in profile - assuming linear\n");
+ if (r != NULL) {
+ for (i = 0; i < r->nent; i++) {
+ iv = i/(r->nent-1.0);
+ r->v[0][i] = iv;
+ r->v[1][i] = iv;
+ r->v[2][i] = iv;
+ }
+ }
+ } else {
+
+ /* Hmm. Perhaps we should ignore this if the vcgt is linear ?? */
+ if (r == NULL)
+ error("We don't have access to the VideoLUT");
+
+ if (wo->u.table.channels == 3) {
+ for (i = 0; i < r->nent; i++) {
+ iv = i/(r->nent-1.0);
+ r->v[0][i] = wo->lookup(wo, 0, iv);
+ r->v[1][i] = wo->lookup(wo, 1, iv);
+ r->v[2][i] = wo->lookup(wo, 2, iv);
+//printf("~1 entry %d = %f %f %f\n",i,r->v[0][i],r->v[1][i],r->v[2][i]);
+ }
+ debug("Got color vcgt calibration\n");
+ } else if (wo->u.table.channels == 1) {
+ for (i = 0; i < r->nent; i++) {
+ iv = i/(r->nent-1.0);
+ r->v[0][i] =
+ r->v[1][i] =
+ r->v[2][i] = wo->lookup(wo, 0, iv);
+ }
+ debug("Got monochrom vcgt calibration\n");
+ } else {
+ r->del(r);
+ r = NULL;
+ }
+ }
+ } else { /* See if it's a .cal file */
+ int ncal;
+ int ii, fi, ri, gi, bi;
+ double cal[3][256];
+
+ icco->del(icco); /* Don't need these now */
+ icco = NULL;
+ rd_fp->del(rd_fp);
+ rd_fp = NULL;
+
+ ccg = new_cgats(); /* Create a CGATS structure */
+ ccg->add_other(ccg, "CAL"); /* our special calibration type */
+
+ if (ccg->read_name(ccg, calname)) {
+ ccg->del(ccg);
+ error("File '%s' is not a valid ICC profile or Argyll .cal file",calname);
+ }
+
+ if (ccg->ntables == 0 || ccg->t[0].tt != tt_other || ccg->t[0].oi != 0)
+ error("Calibration file isn't a CAL format file");
+ if (ccg->ntables < 1)
+ error("Calibration file '%s' doesn't contain at least one table",calname);
+
+ if ((ncal = ccg->t[0].nsets) <= 0)
+ error("No data in set of file '%s'",calname);
+
+ if (ncal != 256)
+ error("Expect 256 data sets in file '%s'",calname);
+
+ if ((fi = ccg->find_kword(ccg, 0, "DEVICE_CLASS")) < 0)
+ error("Calibration file '%s' doesn't contain keyword COLOR_REP",calname);
+ if (strcmp(ccg->t[0].kdata[fi],"DISPLAY") != 0)
+ error("Calibration file '%s' doesn't have DEVICE_CLASS of DISPLAY",calname);
+
+ if ((ii = ccg->find_field(ccg, 0, "RGB_I")) < 0)
+ error("Calibration file '%s' doesn't contain field RGB_I",calname);
+ if (ccg->t[0].ftype[ii] != r_t)
+ error("Field RGB_R in file '%s' is wrong type",calname);
+ if ((ri = ccg->find_field(ccg, 0, "RGB_R")) < 0)
+ error("Calibration file '%s' doesn't contain field RGB_R",calname);
+ if (ccg->t[0].ftype[ri] != r_t)
+ error("Field RGB_R in file '%s' is wrong type",calname);
+ if ((gi = ccg->find_field(ccg, 0, "RGB_G")) < 0)
+ error("Calibration file '%s' doesn't contain field RGB_G",calname);
+ if (ccg->t[0].ftype[gi] != r_t)
+ error("Field RGB_G in file '%s' is wrong type",calname);
+ if ((bi = ccg->find_field(ccg, 0, "RGB_B")) < 0)
+ error("Calibration file '%s' doesn't contain field RGB_B",calname);
+ if (ccg->t[0].ftype[bi] != r_t)
+ error("Field RGB_B in file '%s' is wrong type",calname);
+ for (i = 0; i < ncal; i++) {
+ cal[0][i] = *((double *)ccg->t[0].fdata[i][ri]);
+ cal[1][i] = *((double *)ccg->t[0].fdata[i][gi]);
+ cal[2][i] = *((double *)ccg->t[0].fdata[i][bi]);
+ }
+
+ if (r == NULL)
+ error("We don't have access to the VideoLUT");
+
+ /* Interpolate from cal value to RAMDAC entries */
+ for (i = 0; i < r->nent; i++) {
+ double val, w;
+ unsigned int ix;
+
+ val = (ncal-1.0) * i/(r->nent-1.0);
+ ix = (unsigned int)floor(val); /* Coordinate */
+ if (ix > (ncal-2))
+ ix = (ncal-2);
+ w = val - (double)ix; /* weight */
+ for (j = 0; j < 3; j++) {
+ val = cal[j][ix];
+ r->v[j][i] = val + w * (cal[j][ix+1] - val);
+ }
+ }
+ debug("Got cal file calibration\n");
+ }
+ if (ccg != NULL)
+ ccg->del(ccg);
+ if (icco != NULL)
+ icco->del(icco);
+ if (rd_fp != NULL)
+ rd_fp->del(rd_fp);
+ }
+
+ /* Install the profile into the display and set as the default */
+ if (installprofile == 1) {
+ if (is_ok_icc == 0)
+ error("File '%s' doesn't seem to be an ICC profile!",calname);
+
+ if (verb)
+ printf("About to install '%s' as display's default profile\n",calname);
+ if (dw->install_profile(dw, calname, r, scope)) {
+ error("Failed to install profile '%s'!",calname);
+ }
+ if (verb) {
+ printf("Installed '%s' and made it the default\n",calname);
+ }
+
+ /* load the LUT with the calibration from the given file or the current display profile. */
+ /* (But don't load profile calibration if we're verifying against it) */
+ } else if (loadfile != 0 || (loadprofile != 0 && verify == 0)) {
+ int rv;
+
+ /* r == NULL if no VideoLUT access and ICC profile without vcgt */
+ if (r == NULL) {
+ warning("No linear calibration loaded because there is no access to the VideoLUT");
+ } else {
+ if (verb)
+ printf("About to set display to given calibration\n");
+ if ((rv = dw->set_ramdac(dw,r,1)) != 0) {
+ if (rv == 2)
+ error("Failed to set VideoLUTs persistently because current System Profile can't be renamed");
+ else
+ error("Failed to set VideoLUTs");
+ }
+ if (verb)
+ printf("Calibration set\n");
+ }
+ }
+
+ if (verify != 0) {
+ int ver = 1;
+ double berr = 0.0;
+ if ((or = dw->get_ramdac(dw)) == NULL)
+ error("Unable to get current VideoLUT for verify");
+
+ if (r == NULL)
+ error("No calibration to verify against");
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ double err;
+ err = fabs(r->v[j][i] - or->v[j][i]);
+ if (err > berr)
+ berr = err;
+ if (err > VERIFY_TOL) {
+ ver = 0;
+ }
+ }
+ }
+ if (ver)
+ printf("Verify: '%s' IS loaded (discrepancy %.1f%%)\n", calname, berr * 100);
+ else
+ printf("Verify: '%s' is NOT loaded (discrepancy %.1f%%)\n", calname, berr * 100);
+ or->del(or);
+ or = NULL;
+ }
+ if (r != NULL) {
+ r->del(r);
+ r = NULL;
+ }
+
+ /* If no other command selected, do a Window or VideoLUT test */
+ if (sname[0] == '\000' && clear == 0 && installprofile == 0 && loadfile == 0 && verify == 0 && loadprofile == 0) {
+
+ if (ramd == 0) {
+
+ if (fade) {
+ int i;
+ int steps = 256;
+ for (i = 0; i < steps; i++) {
+ double tt;
+ tt = i/(steps - 1.0);
+ dw->set_color(dw, tt, tt, tt);
+ msec_sleep(20);
+ printf("Val = %f\n",tt);
+ }
+
+ /* Patch colors from a CGATS file */
+ } else if (pcname[0] != '\000') {
+ cgats *icg;
+ int i, npat;
+ int ri, gi, bi;
+ int si = -1;
+
+ if ((icg = new_cgats()) == NULL)
+ error("new_cgats() failed\n");
+ icg->add_other(icg, ""); /* Allow any signature file */
+
+ if (icg->read_name(icg, pcname))
+ error("File '%s' read error : %s",pcname, icg->err);
+
+ if (icg->ntables < 1) /* We don't use second table at the moment */
+ error ("Input file '%s' doesn't contain at least one table",pcname);
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("File '%s has no sets of data in the first table",pcname);
+
+ si = icg->find_field(icg, 0, "SAMPLE_ID");
+ if (si >= 0 && icg->t[0].ftype[si] != nqcs_t)
+ error("In file '%s' field SAMPLE_ID is wrong type",pcname);
+
+ if ((ri = icg->find_field(icg, 0, "RGB_R")) < 0)
+ error ("Input file '%s' doesn't contain field RGB_R",pcname);
+ if (icg->t[0].ftype[ri] != r_t)
+ error ("In file '%s' field RGB_R is wrong type",pcname);
+ if ((gi = icg->find_field(icg, 0, "RGB_G")) < 0)
+ error ("Input file '%s' doesn't contain field RGB_G",pcname);
+ if (icg->t[0].ftype[gi] != r_t)
+ error ("In file '%s' field RGB_G is wrong type",pcname);
+ if ((bi = icg->find_field(icg, 0, "RGB_B")) < 0)
+ error ("Input file '%s' doesn't contain field RGB_B",pcname);
+ if (icg->t[0].ftype[bi] != r_t)
+ error ("In file '%s' field RGB_B is wrong type",pcname);
+
+ if (inf == 2)
+ printf("\nHit return to advance each color\n");
+
+ if (inf == 2) {
+ printf("\nHit return to start\n");
+ getchar();
+ }
+ for (i = 0; i < npat; i++) {
+ double r, g, b;
+ r = *((double *)icg->t[0].fdata[i][ri]) / 100.0;
+ g = *((double *)icg->t[0].fdata[i][gi]) / 100.0;
+ b = *((double *)icg->t[0].fdata[i][bi]) / 100.0;
+
+ if (si >= 0)
+ printf("Patch id '%s'",((char *)icg->t[0].fdata[i][si]));
+ else
+ printf("Patch no %d",i+1);
+ printf(" color %f %f %f\n",r,g,b);
+
+ dw->set_color(dw, r, g, b);
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+ }
+ icg->del(icg);
+
+ /* Preset and random patch colors */
+ } else {
+
+ if (inf == 2)
+ printf("\nHit return to advance each color\n");
+
+ printf("Setting White\n");
+ dw->set_color(dw, 1.0, 1.0, 1.0); /* White */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting 75%% Grey\n");
+ dw->set_color(dw, 0.75, 0.75, 0.75); /* Grey */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting 50%% Grey\n");
+ dw->set_color(dw, 0.5, 0.5, 0.5); /* Grey */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting 25%% Grey\n");
+ dw->set_color(dw, 0.25, 0.25, 0.25); /* Grey */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting 12.5%% Grey\n");
+ dw->set_color(dw, 0.125, 0.125, 0.125); /* Grey */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting Black\n");
+ dw->set_color(dw, 0.0, 0.0, 0.0);
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting Red\n");
+ dw->set_color(dw, 1.0, 0.0, 0.0); /* Red */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting Green\n");
+ dw->set_color(dw, 0.0, 1.0, 0.0); /* Green */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting Blue\n");
+ dw->set_color(dw, 0.0, 0.0, 1.0); /* Blue */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting Cyan\n");
+ dw->set_color(dw, 0.0, 1.0, 1.0); /* Cyan */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting Magenta\n");
+ dw->set_color(dw, 1.0, 0.0, 1.0); /* Magenta */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting Yellow\n");
+ dw->set_color(dw, 1.0, 1.0, 0.0); /* Yellow */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting 50%% Red\n");
+ dw->set_color(dw, 0.5, 0.0, 0.0); /* Red */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting 50%% Green\n");
+ dw->set_color(dw, 0.0, 0.5, 0.0); /* Green */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ printf("Setting 50%% Blue\n");
+ dw->set_color(dw, 0.0, 0.0, 0.5); /* Blue */
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ if (inf == 1) {
+ for (;inf != 0;) {
+ double col[3];
+
+ for (i = 0; i < 3; i++) {
+ seed = PSRAND32(seed);
+ col[i] = seed/4294967295.0;
+ }
+
+ printf("Setting %f %f %f\n",col[0],col[1],col[2]);
+ dw->set_color(dw, col[0],col[1],col[2]);
+
+ if (inf == 2)
+ getchar();
+ else
+ sleep(2);
+
+ }
+ }
+ }
+ }
+
+ if (inf != 2) {
+ /* Test out the VideoLUT access */
+ if ((dw->or = dw->get_ramdac(dw)) != NULL) { /* Use dw->or so signal will restore */
+
+ r = dw->or->clone(dw->or);
+
+ /* Try darkening it */
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ r->v[j][i] = pow(dw->or->v[j][i], 2.0);
+ }
+ }
+ printf("Darkening screen\n");
+ if (dw->set_ramdac(dw,r,0)) {
+ dw->set_ramdac(dw,or,0);
+ error("Failed to set VideoLUTs");
+ }
+ sleep(1);
+
+ /* Try lightening it */
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < r->nent; i++) {
+ r->v[j][i] = pow(dw->or->v[j][i], 0.5);
+ }
+ }
+ printf("Lightening screen\n");
+ if (dw->set_ramdac(dw,r,0)) {
+ dw->set_ramdac(dw,or,0);
+ error("Failed to set VideoLUTs");
+ }
+ sleep(1);
+
+ /* restor it */
+ printf("Restoring screen\n");
+ if (dw->set_ramdac(dw,dw->or,0)) {
+ error("Failed to set VideoLUTs");
+ }
+
+ r->del(r);
+ dw->or->del(dw->or);
+ dw->or = NULL;
+
+ } else {
+ printf("We don't have access to the VideoLUT\n");
+ }
+
+ /* Test out the beeps */
+ printf("Normal beep\n");
+ normal_beep();
+
+ sleep(1);
+
+ printf("Good beep\n");
+ good_beep();
+
+ sleep(1);
+
+ printf("Bad double beep\n");
+ bad_beep();
+
+ sleep(2); /* Allow beep to complete */
+ }
+ }
+
+ if (disp != NULL)
+ free_a_disppath(disp);
+
+ if (verb)
+ printf("About to destroy dispwin object\n");
+
+ dw->del(dw);
+
+ return 0;
+}
+
+#endif /* STANDALONE_TEST */
+
+/* ================================================================ */
+/* Possible ThinkPad MSWin code to keep the main screen on */
+
+#ifdef NEVER
+
+Public Class Form1
+ Declare Sub XRCalibrationLidTurnOnNotification Lib "C:\Program Files (x86)\X-Rite\PANTONE Color Calibrator\XRLaptopIFSDK.dll" ()
+ Declare Sub XRCalibrationLidTurnOffNotification Lib "C:\Program Files (x86)\X-Rite\PANTONE Color Calibrator\XRLaptopIFSDK.dll" ()
+
+ Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
+
+ End Sub
+
+ Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
+ Call XRCalibrationLidTurnOnNotification()
+ End Sub
+
+ Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
+ Call XRCalibrationLidTurnOffNotification()
+ End Sub
+End Class
+
+#endif
+
+/* ================================================================ */
+/* Unused Apple code */
+
+#ifdef NEVER
+ /* Got displays, now have a look through them */
+ for (i = 0; i < dcount; i++) {
+ GDHandle gdh;
+ GDPtr gdp;
+
+ /* Dump display mode dictionary */
+ CFIndex nde, j;
+ CFDictionaryRef dr;
+ void **keys, **values;
+
+ dr = CGDisplayCurrentMode(dids[i]);
+ nde = CFDictionaryGetCount(dr);
+
+ printf("Dict contains %d entries \n", nde);
+ if ((keys = (void **)malloc(nde * sizeof(void *))) == NULL) {
+ debug("malloc failed for disp mode keys\n");
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+ if ((values = (void **)malloc(nde * sizeof(void *))) == NULL) {
+ debug("malloc failed for disp mode values\n");
+ free(keys);
+ free_disppaths(disps);
+ free(dids);
+ return NULL;
+ }
+ CFDictionaryGetKeysAndValues(dr, (const void **)keys, (const void **)values);
+ for (j = 0; j < nde; j++) {
+ printf("Entry %d key = %s\n", j, CFStringGetCStringPtr(keys[j], kCFStringEncodingMacRoman));
+ }
+ free(values);
+ free(keys);
+ }
+#endif
+
+
+#ifdef NEVER
+/* How to install profiles for devices. */
+
+/* Callback to locate a profile ID. */
+struct idp_rec {
+ CMDeviceID ddid; /* Device ID */
+// char *fname; /* Profile we're trying to find */
+ CMDeviceProfileID id; /* Corresponding ID */
+ CMDeviceScope dsc; /* Matching device scope */
+ int found; /* Flag indicating it's been found */
+};
+
+OSErr ItDevProfProc (
+const CMDeviceInfo *di,
+const NCMDeviceProfileInfo *pi,
+void *refCon)
+{
+ CMError ev;
+ struct idp_rec *r = (struct idp_rec *)refCon;
+ CMDeviceProfileID id;
+
+ if (di->deviceClass != cmDisplayDeviceClass
+ || di->deviceID != r->ddid) {
+ return noErr;
+ }
+
+ /* We'd qualify on the device mode too (deviceState ??), */
+ /* if we wanted to replace a profile for a particular mode. */
+
+ /* Assume this is a display with only one mode, and return */
+ /* the profile id and device scope */
+ r->id = pi->profileID;
+ r->dsc = di->deviceScope;
+ r->found = 1;
+ return noErr;
+//printf("~1 got match\n");
+
+/* Callback to locate a profile ID. */
+struct idp_rec {
+ CMDeviceID ddid; /* Device ID */
+ CMDeviceProfileID id; /* Corresponding ID */
+ CMDeviceScope dsc; /* Matching device scope */
+ int found; /* Flag indicating it's been found */
+};
+
+OSErr ItDevProfProc (
+const CMDeviceInfo *di,
+const NCMDeviceProfileInfo *pi,
+void *refCon)
+{
+ CMError ev;
+ struct idp_rec *r = (struct idp_rec *)refCon;
+ CMDeviceProfileID id;
+
+ if (di->deviceClass != cmDisplayDeviceClass
+ || di->deviceID != r->ddid) {
+ return noErr;
+ }
+
+ /* Assume this is a display with only one mode, and return */
+ /* the profile id and device scope */
+ r->id = pi->profileID;
+ r->dsc = di->deviceScope;
+ r->found = 1;
+ return noErr;
+}
+
+#ifndef NEVER
+
+/* Given a location, return a string for it's path */
+static char *plocpath(CMProfileLocation *ploc) {
+
+ if (ploc->locType == cmFileBasedProfile) {
+ FSRef newRef;
+ static UInt8 path[256] = "";
+//printf("~1 converted spec file location\n");
+
+ if (FSpMakeFSRef(&ploc->u.fileLoc.spec, &newRef) == noErr) {
+ OSStatus stus;
+ if ((stus = FSRefMakePath(&newRef, path, 256)) == 0 || stus == fnfErr) {
+ return path;
+ }
+ }
+ return strdup(path);
+ } else if (ploc->locType == cmPathBasedProfile) {
+ return strdup(ploc->u.pathLoc.path);
+ }
+ return NULL;
+}
+
+#else
+
+/* fss2path takes the FSSpec of a file, folder or volume and returns it's POSIX (?) path. */
+/* Return NULL on error. Free returned string */
+/* NOTE FSSpec is deprecated in 10.5. Replace with FSRef ?? */
+static char *fss2path(FSSpec *fss) {
+ int i, l; /* fss->name contains name of last item in path */
+ char *path;
+
+ l = fss->name[0];
+ if ((path = malloc(l + 1)) == NULL)
+ return NULL;
+ for (i = 0; i < l; i++) {
+ if (fss->name[i+1] == '/')
+ path[i] = ':';
+ else
+ path[i] = fss->name[i+1];
+ }
+ path[i] = '\000';
+//printf("~1 path = '%s', l = %d\n",path,l);
+
+ if(fss->parID != fsRtParID) { /* path is more than just a volume name */
+ FSSpec tfss;
+// CInfoPBRec pb;
+ FSRefParam pb;
+ int tl;
+ char *tpath;
+
+ memmove(&tfss, fss, sizeof(FSSpec)); /* Copy so we can modify */
+ memset(&pb, 0, sizeof(FSRefParam));
+ pb.ioNamePtr = tfss.name;
+ pb.ioVRefNum = tfss.vRefNum;
+ pb.ioDrParID = tfss.parID;
+ do {
+ pb.ioFDirIndex = -1; /* get parent directory name */
+ pb.ioDrDirID = pb.dirInfo.ioDrParID;
+ if(PBGetCatlogInfoSync(&pb) != noErr) {
+ free(path);
+ return NULL;
+ }
+
+ /* Pre-pend the directory name separated by '/' */
+ if (pb.dirInfo.ioDrDirID == fsRtDirID) {
+ tl = 0; /* Don't pre-pend volume name */
+ } else {
+ tl = tfss.name[0];
+ }
+ if ((tpath = malloc(tl + l + 1)) == NULL) {
+ free(path);
+ return NULL;
+ }
+ for (i = 0; i < tl; i++) {
+ if (tfss.name[i+1] == '/')
+ tpath[i] = ':';
+ else
+ tpath[i] = tfss.name[i+1];
+ }
+ tpath[i] = '/';
+ for (i = 0; i < l; i++)
+ tpath[tl+1+i] = path[i];
+ tpath[tl+1+i] = '\000';
+ free(path);
+ path = tpath;
+ l = tl + 1 + l;
+//printf("~1 path = '%s', l = %d\n",path,l);
+ } while(pb.dirInfo.ioDrDirID != fsRtDirID); /* while more directory levels */
+ }
+
+ return path;
+}
+
+/* Return a string containing the profiles path. */
+/* Return NULL on error. Free the string after use. */
+static char *plocpath(CMProfileLocation *ploc) {
+ if (ploc->locType == cmFileBasedProfile) {
+ return fss2path(&ploc->u.fileLoc.spec);
+ } else if (ploc->locType == cmPathBasedProfile) {
+ return strdup(ploc->u.pathLoc.path);
+ }
+ return NULL;
+}
+
+#endif
+
+/* Test code that checks what the current display default profile is, three ways */
+static void pcurpath(dispwin *p) {
+ CMProfileRef xprof; /* Current AVID profile */
+ CMProfileLocation xploc; /* Current profile location */
+ UInt32 xplocsz = sizeof(CMProfileLocation);
+ struct idp_rec cb;
+ CMError ev;
+
+ /* Get the current installed profile */
+ if ((ev = CMGetProfileByAVID((CMDisplayIDType)p->ddid, &xprof)) != noErr) {
+ debug2((errout,"CMGetProfileByAVID() failed with error %d\n",ev));
+ goto skip;
+ }
+
+ /* Get the current installed profile's location */
+ if ((ev = NCMGetProfileLocation(xprof, &xploc, &xplocsz)) != noErr) {
+ debug2((errout,"NCMGetProfileLocation() failed with error %d\n",ev));
+ goto skip;
+ }
+
+//printf("~1 Current profile by AVID = '%s'\n",plocpath(&xploc));
+
+ /* Get the current CMDeviceProfileID and device scope */
+ cb.ddid = (CMDeviceID)p->ddid; /* Display Device ID */
+ cb.found = 0;
+
+ if ((ev = CMIterateDeviceProfiles(ItDevProfProc, NULL, NULL, cmIterateAllDeviceProfiles, (void *)&cb)) != noErr) {
+ debug2((errout,"CMIterateDeviceProfiles() failed with error %d\n",ev));
+ goto skip;
+ }
+ if (cb.found == 0) {
+ debug2((errout,"Failed to find exsiting profiles ID\n"));
+ goto skip;
+ }
+ /* Got cb.id */
+
+ if ((ev = CMGetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)p->ddid, cb.id, &xploc)) != noErr) {
+ debug2((errout,"Failed to GetDeviceProfile\n"));
+ goto skip;
+ }
+//printf("~1 Current profile by Itterate = '%s'\n",plocpath(&xploc));
+
+ /* Get the default ID for the display */
+ if ((ev = CMGetDeviceDefaultProfileID(cmDisplayDeviceClass, (CMDeviceID)p->ddid, &cb.id)) != noErr) {
+ debug2((errout,"CMGetDeviceDefaultProfileID() failed with error %d\n",ev));
+ goto skip;
+ }
+
+ /* Get the displays default profile */
+ if ((ev = CMGetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)p->ddid, cb.id, &xploc)) != noErr) {
+ debug2((errout,"CMGetDeviceDefaultProfileID() failed with error %d\n",ev));
+ goto skip;
+ }
+//printf("~1 Current profile by get default = '%s'\n",plocpath(&xploc));
+
+ skip:;
+}
+ /* If we want the path to the profile, we'd do this: */
+
+ printf("id = 0x%x\n",pi->profileID);
+ if (pi->profileLoc.locType == cmFileBasedProfile) {
+ FSRef newRef;
+ UInt8 path[256] = "";
+
+ if (FSpMakeFSRef(&pi->profileLoc.u.fileLoc.spec, &newRef) == noErr) {
+ OSStatus stus;
+ if ((stus = FSRefMakePath(&newRef, path, 256)) == 0 || stus == fnfErr) {
+ printf("file = '%s'\n",path);
+ if (strcmp(r->fname, (char *)path) == 0) {
+ r->id = pi->profileID;
+ r->found = 1;
+ printf("got match\n");
+ }
+ }
+ }
+ } else if (pi->profileLoc.locType == cmPathBasedProfile) {
+ if (strcmp(r->fname, pi->profileLoc.u.pathLoc.path) == 0) {
+ r->id = pi->profileID;
+ r->dsc = di->deviceScope;
+ r->found = 1;
+ printf("got match\n");
+ }
+ }
+
+
+ {
+ struct idp_rec cb;
+
+ /* The CMDeviceProfileID wll always be 1 for a display, because displays have only one mode, */
+ /* so the Iterate could be avoided for it. */
+
+ cb.ddid = (CMDeviceID)p->ddid; /* Display Device ID */
+// cb.fname = dpath;
+ cb.found = 0;
+
+ if ((ev = CMIterateDeviceProfiles(ItDevProfProc, NULL, NULL, cmIterateAllDeviceProfiles, (void *)&cb)) != noErr) {
+ debug2((errout,"CMIterateDeviceProfiles() failed with error %d\n",dpath,ev));
+ return 1;
+ }
+ if (cb.found == 0) {
+ debug2((errout,"Failed to find exsiting profiles ID, so ca't set it as default\n"));
+ return 1;
+ }
+ if ((ev = CMSetDeviceProfile(cmDisplayDeviceClass, (CMDeviceID)p->ddid, &cb.dsc, cb.id, &dploc)) != noErr) {
+ debug2((errout,"CMSetDeviceProfile() failed for file '%s' with error %d\n",dpath,ev));
+ return 1;
+ }
+ /* There is no point in doing the following, because displays only have one mode. */
+ /* Make it the default for the display */
+ if ((ev = CMSetDeviceDefaultProfileID(cmDisplayDeviceClass, (CMDeviceID)p->ddid, cb.id)) != noErr) {
+ debug2((errout,"CMSetDeviceDefaultProfileID() failed for file '%s' with error %d\n",dpath,ev));
+ return 1;
+ }
+
+#endif /* NEVER */
+
+#ifdef NEVER
+ /* Unused 10.6+ code */
+ CFUUIDRef dispuuid;
+ CFDictionaryRef dict, sdict, pdict;
+ CFStringRef id, urlstr;
+ CFURLRef url;
+ CFIndex bufSize;
+ char *dpath = NULL; /* return value */
+
+ if ((dispuuid = CGDisplayCreateUUIDFromDisplayID(p->ddid)) == NULL) {
+ debugr2((errout,"CGDisplayCreateUUIDFromDisplayID() failed\n"));
+ return NULL;
+ }
+
+ if ((dict = ColorSyncDeviceCopyDeviceInfo(kColorSyncDisplayDeviceClass, dispuuid)) == NULL) {
+ debugr2((errout,"ColorSyncDeviceCopyDeviceInfo() failed\n"));
+ CFRelease(dispuuid);
+ return NULL;
+ }
+
+ /* Get the factory profile dictionary */
+ if ((sdict = CFDictionaryGetValue(dict, kColorSyncFactoryProfiles)) == NULL) {
+ debugrr("Failed to get kColorSyncFactoryProfiles\n");
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ return NULL;
+ }
+ /* Lookup the default profile ID */
+ if ((id = CFDictionaryGetValue(sdict, kColorSyncDeviceDefaultProfileID)) == NULL) {
+ debugrr("Failed to get kColorSyncDeviceDefaultProfileID\n");
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ return NULL;
+ }
+
+// printf("~1 got ProfileID '%s'\n",CFStringGetCStringPtr(id, kCFStringEncodingMacRoman));
+
+ /* See if this ProfileID is in the factory profile dictionary */
+ if ((pdict = CFDictionaryGetValue(sdict, id)) != NULL) {
+ } else {
+ debugrr("Failed to get factory profile with id \n");
+
+ /* Get the custom profile dictionary */
+ if ((sdict = CFDictionaryGetValue(dict, kColorSyncCustomProfiles)) == NULL) {
+ debugrr("Failed to get kColorSyncCustomProfiles\n");
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ return NULL;
+ }
+ /* See if the default id is in the custom profile dictionary */
+ if ((pdict = CFDictionaryGetValue(sdict, id)) == NULL) {
+ debugrr("Failed to locate default profile in factory or custom profile list\n");
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ return NULL;
+ }
+ }
+
+ /* get the URL */
+ if ((url = CFDictionaryGetValue(pdict, kColorSyncDeviceProfileURL)) == NULL) {
+ debugrr("Failed to get default profile URL\n");
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ return NULL;
+ }
+
+// urlstr = CFURLGetString(url);
+// printf("~1 got URL '%s'\n",CFStringGetCStringPtr(urlstr, kCFStringEncodingMacRoman));
+
+ urlstr = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
+ bufSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(urlstr),
+ kCFStringEncodingUTF8) + 1;
+ if ((dpath = malloc(bufSize)) == NULL) {
+ debugrr("cur_profile malloc failed\n");
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ return NULL;
+ }
+ if (!CFStringGetCString(urlstr, dpath, bufSize, kCFStringEncodingUTF8)) {
+ debugrr("cur_profile CFStringGetCString failed\n");
+ CFRelease(dict);
+ CFRelease(dispuuid);
+ return NULL;
+ }
+ printf("~1 got path '%s'\n",dpath);
+
+ CFRelease(dict);
+ CFRelease(dispuuid);
+
+// return dpath;
+ return NULL;
+#endif
+
diff --git a/spectro/dispwin.h b/spectro/dispwin.h
new file mode 100644
index 0000000..096547f
--- /dev/null
+++ b/spectro/dispwin.h
@@ -0,0 +1,327 @@
+
+#ifndef DISPWIN_H
+
+/*
+ * Argyll Color Correction System
+ * Display target patch window
+ *
+ * Author: Graeme W. Gill
+ * Date: 4/10/96
+ *
+ * Copyright 1998 - 2013 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.
+ */
+
+#define DISPLAY_UPDATE_DELAY 200 /* default display update delay allowance */
+
+int do_plot(double *x, double *y1, double *y2, double *y3, int n);
+
+#ifdef NT
+#define OEMRESOURCE
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
+#define _WIN32_WINNT 0x0501
+#endif
+#if !defined(WINVER) || WINVER < 0x0501
+#if defined(WINVER)
+# undef WINVER
+#endif
+#define WINVER 0x0501
+#endif
+#include <windows.h>
+#include <icm.h>
+
+#if(WINVER < 0x0500)
+#error Require WINVER >= 0x500 to compile (multi-monitor API needed)
+#endif
+
+#ifndef COLORMGMTCAPS /* In case SDK is out of date */
+
+#define COLORMGMTCAPS 121
+
+#define CM_NONE 0x00000000
+#define CM_DEVICE_ICM 0x00000001
+#define CM_GAMMA_RAMP 0x00000002
+#define CM_CMYK_COLOR 0x00000004
+
+#endif /* !COLORMGMTCAPS */
+
+/* Avoid shlwapi.h - there are problems in using it in latter SDKs */
+#ifndef WINSHLWAPI
+#define WINSHLWAPI DECLSPEC_IMPORT
+#endif
+
+WINSHLWAPI LPSTR WINAPI PathFindFileNameA(LPCSTR);
+WINSHLWAPI LPWSTR WINAPI PathFindFileNameW(LPCWSTR);
+
+#ifdef UNICODE
+#define PathFindFileName PathFindFileNameW
+#else
+#define PathFindFileName PathFindFileNameA
+#endif
+
+#endif /* NT */
+
+#ifdef __APPLE__ /* Assume OS X Cocoa */
+
+#include <Carbon/Carbon.h> /* To declare CGDirectDisplayID */
+
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11)
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/xf86vmode.h>
+#include <X11/extensions/dpms.h>
+#include <X11/extensions/Xinerama.h>
+#include <X11/extensions/Xrandr.h>
+#include <X11/extensions/scrnsaver.h>
+#include <X11/extensions/dpms.h>
+#endif /* UNIX_X11 */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Profile instalation/association scope */
+typedef enum {
+ p_scope_user = 0, /* (user profiles) Linux, OS X & Vista */
+ p_scope_local = 1, /* (local system profiles) Linux, OS X & vista */
+ p_scope_system = 2, /* (system supplied profiles) OS X. [ Linux, Vista same as local ] */
+ p_scope_network = 3 /* (shared network profiles) [ OS X. Linux, Vista same as local ] */
+} p_scope;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Enumerate and list all the available displays */
+
+/* Structure to store infomation about possible displays */
+typedef struct {
+ char *name; /* Display name */
+ char *description; /* Description of display */
+ int sx,sy; /* Displays offset in pixels */
+ int sw,sh; /* Displays width and height in pixels*/
+#ifdef NT
+ char monid[128]; /* Monitor ID */
+ int prim; /* NZ if primary display monitor */
+#endif /* NT */
+#ifdef __APPLE__
+ CGDirectDisplayID ddid;
+#endif /* __APPLE__ */
+#if defined(UNIX_X11)
+ int screen; /* Screen to select */
+ int uscreen; /* Underlying screen */
+ int rscreen; /* Underlying RAMDAC screen */
+ Atom icc_atom; /* ICC profile root atom for this display */
+ unsigned char *edid; /* 128 or 256 bytes of monitor EDID, NULL if none */
+ int edid_len; /* 128 or 256 */
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2
+ /* Xrandr stuff - output is connected 1:1 to a display */
+ RRCrtc crtc; /* Associated crtc */
+ RROutput output; /* Associated output */
+ Atom icc_out_atom; /* ICC profile atom for this output */
+#endif /* randr >= V 1.2 */
+#endif /* UNIX_X11 */
+} disppath;
+
+/* Return pointer to list of disppath. Last will be NULL. */
+/* Return NULL on failure. */
+/* Call free_disppaths() to free up allocation */
+disppath **get_displays();
+
+void free_disppaths(disppath **paths);
+
+/* Delete the display at the given index from the paths */
+void del_disppath(disppath **paths, int ix);
+
+/* Return the given display given its index 0..n-1 */
+disppath *get_a_display(int ix);
+
+void free_a_disppath(disppath *path);
+
+extern int callback_ddebug; /* Diagnostic global for get_displays() and get_a_display() */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Structure to handle RAMDAC values */
+struct _ramdac {
+ int pdepth; /* Plane depth, usually 8 */
+ int nent; /* Number of entries, = 2^pdepth */
+ double *v[3]; /* 2^pdepth entries for RGB, values 0.0 - 1.0 */
+
+ /* Clone ourselves */
+ struct _ramdac *(*clone)(struct _ramdac *p);
+
+ /* Set the curves to linear */
+ void (*setlin)(struct _ramdac *p);
+
+ /* Destroy ourselves */
+ void (*del)(struct _ramdac *p);
+}; typedef struct _ramdac ramdac;
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+/* Dispwin object */
+
+/* !!!! Make changes in dispwin.c and webwin.c !!!! */
+
+struct _dispwin {
+
+/* private: */
+ char *name; /* Display path (ie. '\\.\DISPLAY1') */
+ /* or "10.0.0.1:0.0" */
+ char *description; /* Description of display */
+
+ /* Plot instance information */
+ int sx,sy; /* Screen offset in pixels */
+ int sw,sh; /* Screen width and height in pixels*/
+ int ww,wh; /* Window width and height */
+ int tx,ty; /* Test area within window offset in pixels */
+ int tw,th; /* Test area width and height in pixels */
+
+ double rgb[3]; /* Current color (full resolution) */
+ double r_rgb[3]; /* Current color (raster value) */
+ int update_delay; /* Update delay in msec, default 200 */
+ int min_update_delay; /* Minimum update delay, default 20, overriden by EV */
+ int nowin; /* Don't create a test window */
+ int native; /* 0 = use current current or given calibration curve */
+ /* 1 = set native linear output and use ramdac high precision */
+ ramdac *or; /* Original ramdac contents, NULL if none */
+ ramdac *r; /* Ramdac in use for native mode */
+ int blackbg; /* NZ if black full screen background */
+
+ char *callout; /* if not NULL - set color Shell callout routine */
+
+ /* Linked list to automate SIGKILL cleanup */
+ struct _dispwin *next;
+
+#ifdef NT
+ char monid[128]; /* Monitor ID (ie. 'Monitor\MEA1773\{4D36E96E-E325-11CE-BFC1-08002BE10318}\0015'*/
+ HDC hdc; /* Handle to display */
+ char *AppName;
+ HWND hwnd; /* Window handle */
+ HCURSOR curs; /* Invisible cursor */
+
+ MSG msg;
+ ATOM arv;
+
+ int xo, yo, wi, he; /* Window location & size */
+ athread *mth; /* Window message thread */
+ int inited;
+ int quit; /* Request to quit */
+
+ int colupd; /* Color update count */
+ int colupde; /* Color update count echo */
+
+#endif /* NT */
+
+#ifdef __APPLE__
+ CGDirectDisplayID ddid;
+ void *osx_cntx; /* OSX specific info */
+ int btf; /* Flag, nz if window has been brought to the front once */
+ int winclose; /* Flag, set to nz if window was closed */
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11)
+ Display *mydisplay;
+ int myscreen; /* Usual or virtual screen with Xinerama */
+ int myuscreen; /* Underlying screen */
+ int myrscreen; /* Underlying RAMDAC screen */
+ Atom icc_atom; /* ICC profile root atom for this display */
+ unsigned char *edid; /* 128 or 256 bytes of monitor EDID, NULL if none */
+ int edid_len; /* 128 or 256 */
+
+#if RANDR_MAJOR == 1 && RANDR_MINOR >= 2
+ /* Xrandr stuff - output is connected 1:1 to a display */
+ RRCrtc crtc; /* Associated crtc */
+ RROutput output; /* Associated output */
+ Atom icc_out_atom; /* ICC profile atom for this output */
+#endif /* randr >= V 1.2 */
+
+ /* Test windo access */
+ Window mywindow;
+ GC mygc;
+
+ /* Screensaver state */
+ int xsssuspend; /* Was able to suspend the screensaver using XScreenSaverSuspend */
+
+ int xssvalid; /* Was able to save & disable X screensaver using XSetScreenSaver */
+ int timeout, interval;
+ int prefer_blanking;
+ int allow_exposures;
+
+ int xssrunning; /* Disabled xscreensaver */
+
+ int gnomessrunning; /* Disabled gnome screensaver and is was enabled */
+ pid_t gnomepid; /* gnome-screensaver-command -i pid */
+
+ int kdessrunning; /* Disabled kde screensaver and is was enabled */
+
+ int dpmsenabled; /* DPMS is enabled */
+
+#endif /* UNIX_X11 */
+
+ void *pcntx; /* Private context (ie., webwin) */
+ volatile unsigned int ncix, ccix; /* Counters to trigger webwin colorchange */
+ volatile int mg_stop; /* Stop flag */
+
+ int ddebug; /* >0 to print debug to stderr */
+
+/* public: */
+ int pdepth; /* Plane depth of display */
+
+ /* Get RAMDAC values. ->del() when finished. */
+ /* Return NULL if not possible */
+ ramdac *(*get_ramdac)(struct _dispwin *p);
+
+ /* Set the RAMDAC values. */
+ /* Return nz if not possible */
+ int (*set_ramdac)(struct _dispwin *p, ramdac *r, int persist);
+
+ /* Install a display profile and make */
+ /* it the defult for this display. */
+ /* Return nz if failed */
+ int (*install_profile)(struct _dispwin *p, char *fname, ramdac *r, p_scope scope);
+
+ /* Un-install a display profile. */
+ /* Return nz if failed */
+ int (*uninstall_profile)(struct _dispwin *p, char *fname, p_scope scope);
+
+ /* Get the currently installed display profile and return it as an icmFile. */
+ /* Return the name as well, up to mxlen chars, excluding nul. */
+ /* Return NULL if failed */
+ icmFile *(*get_profile)(struct _dispwin *p, char *name, int mxlen);
+
+ /* Set a color (values 0.0 - 1.0) */
+ /* Return nz on error */
+ int (*set_color)(struct _dispwin *p, double r, double g, double b);
+
+ /* Set an update delay, and return the previous value */
+ int (*set_update_delay)(struct _dispwin *p, int update_delay);
+
+ /* Set a shell set color callout command line */
+ void (*set_callout)(struct _dispwin *p, char *callout);
+
+ /* Destroy ourselves */
+ void (*del)(struct _dispwin *p);
+
+}; typedef struct _dispwin dispwin;
+
+/* Create a RAMDAC access and display test window, default white */
+dispwin *new_dispwin(
+ disppath *screen, /* Screen to calibrate. */
+ double width, double height, /* Width and height in mm */
+ double hoff, double voff, /* Offset from c. in fraction of screen, range -1.0 .. 1.0 */
+ int nowin, /* NZ if no window should be created - RAMDAC access only */
+ int native, /* 0 = use current current or given calibration curve */
+ /* 1 = use native linear out & high precision */
+ int *noramdac, /* Return nz if no ramdac access. native is set to 0 */
+ int blackbg, /* NZ if whole screen should be filled with black */
+ int override, /* NZ if override_redirect is to be used on X11 */
+ int ddebug /* >0 to print debug statements to stderr */
+);
+
+
+#define DISPWIN_H
+#endif /* DISPWIN_H */
+
diff --git a/spectro/dtp20.c b/spectro/dtp20.c
new file mode 100644
index 0000000..84c4f2b
--- /dev/null
+++ b/spectro/dtp20.c
@@ -0,0 +1,1695 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP20 related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 10/3/2001
+ *
+ * Copyright 1996 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from DTP41.c
+ *
+ * Thanks to Rolf Gierling for contributing to the devlopment of this driver.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#endif /* SALONEINSTLIB */
+#include "numsup.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "dtp20.h"
+
+static inst_code dtp20_interp_code(inst *pp, int ec);
+static inst_code activate_mode(dtp20 *p);
+
+#define MIN_MES_SIZE 10 /* Minimum normal message reply size */
+#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 100000 /* Maximum reading messagle reply size */
+
+/* Extract an error code from a reply string */
+/* Return -1 if no error code can be found */
+static int
+extract_ec(char *s) {
+ char *p;
+ char tt[3];
+ int rv;
+ p = s + strlen(s);
+ /* Find the trailing '>' */
+ for (p--; p >= s;p--) {
+ if (*p == '>')
+ break;
+ }
+ if ( (p-3) < s
+ || p[0] != '>'
+ || p[-3] != '<')
+ return -1;
+ tt[0] = p[-2];
+ tt[1] = p[-1];
+ tt[2] = '\000';
+ if (sscanf(tt,"%x",&rv) != 1)
+ return -1;
+ /* For some reason the top bit sometimes get set ? (ie. multiple errors ?)*/
+ rv &= 0x7f;
+ return rv;
+}
+
+/* Interpret an icoms error into a DTP20 error */
+static int icoms2dtp20_err(int se) {
+ if (se != ICOM_OK) {
+ if (se & ICOM_TO)
+ return DTP20_TIMEOUT;
+ return DTP20_COMS_FAIL;
+ }
+ return DTP20_OK;
+}
+
+/* Do a standard command/response echange with the dtp20 */
+/* Return the instrument error code */
+static inst_code
+dtp20_command(
+dtp20 *p,
+char *in, /* In string */
+char *out, /* Out string buffer */
+int bsize, /* Out buffer size */
+double to) { /* Timout in seconts */
+ char tc = '>'; /* Terminating character */
+ int ntc = 1; /* Number of terminating characters */
+ int rv, se, insize;
+
+ a1logd(p->log, 4, "dtp20: Sending '%s'",icoms_fix(in));
+
+ insize = strlen(in);
+ if (insize > 0) {
+ if ((se = p->icom->usb_control(p->icom, 0x41, 0x00, 0x00, 0x00, (unsigned char *)in, insize, to)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp20: send command failed ICOM err 0x%x\n",se);
+ return dtp20_interp_code((inst *)p, icoms2dtp20_err(se));
+ }
+ }
+
+ if ((se = p->icom->read(p->icom, out, bsize, tc, ntc, to)) != 0) {
+ a1logd(p->log, 1, "dtp20: read response failed ICOM err 0x%x\n",se);
+ return dtp20_interp_code((inst *)p, icoms2dtp20_err(se));
+ }
+
+ rv = DTP20_OK;
+ if (tc == '>' && ntc == 1) { /* Expecting DTP type error code */
+ rv = extract_ec(out);
+ if (rv > 0) {
+ rv &= inst_imask;
+ if (rv != DTP20_OK) { /* Clear the error */
+ char buf[MAX_MES_SIZE];
+ p->icom->usb_control(p->icom, 0x41, 0x00, 0x00, 0x00, (unsigned char *)"CE\r", 3, 0.5);
+ p->icom->read(p->icom, buf, MAX_MES_SIZE, tc, ntc, 0.5);
+ }
+ }
+ }
+
+ a1logd(p->log, 4, "dtp20: response '%s' ICOM err 0x%x\n",icoms_fix(out),rv);
+ return dtp20_interp_code((inst *)p, rv);
+}
+
+/* Do a command/binary response echange with the dtp20, */
+/* for reading binary spectral values. */
+/* This is for reading binary spectral data */
+/* Return the instrument error code */
+static inst_code
+dtp20_bin_command(
+dtp20 *p,
+char *in, /* In string */
+char *out, /* Out string buffer */
+int bsize, /* Out buffer size & bytes to read */
+double top) { /* Timout in seconds */
+ int rv, se, insize;
+ int bread = 0;
+ char *op;
+
+ a1logd(p->log, 4, "dtp20: Sending '%s'",icoms_fix(in));
+
+ insize = strlen(in);
+ if (insize > 0) {
+ if ((se = p->icom->usb_control(p->icom, 0x41, 0x00, 0x00, 0x00, (unsigned char *)in, insize, top)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp20: send failed ICOM err 0x%x\n",se);
+ return dtp20_interp_code((inst *)p, icoms2dtp20_err(se));
+ }
+ }
+
+ /* Read in 62 byte chunks */
+ for (op = out; bsize > 0;) {
+ int rsize = 62;
+
+ if (rsize > bsize)
+ rsize = bsize;
+
+ if ((se = p->icom->usb_read(p->icom, NULL, 0x81, (unsigned char *)op, rsize, &bread, top)) != ICOM_OK) {
+ if (se == ICOM_SHORT) {
+ a1logd(p->log, 1, "dtp20: response failed expected %d got %d ICOM err 0x%x\n",
+ rsize,bread,se);
+ } else {
+ a1logd(p->log, 1, "dtp20: response failed ICOM err 0x%x\n",se);
+ }
+ return dtp20_interp_code((inst *)p, icoms2dtp20_err(se));
+ }
+ bsize -= bread;
+ op += bread;
+ }
+
+ rv = DTP20_OK;
+
+ a1logd(p->log, 4, "dtp20: response '%s' ICOM err 0x%x\n",
+ icoms_tohex((unsigned char *)out, bread),rv);
+ return dtp20_interp_code((inst *)p, rv);
+}
+
+/* Establish communications with a DTP20 */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+dtp20_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ dtp20 *p = (dtp20 *)pp;
+ char buf[MAX_MES_SIZE];
+ int se;
+ inst_code ev = inst_ok;
+
+ if (p->icom->port_type(p->icom) == icomt_usb) {
+
+ a1logd(p->log, 4, "dtp20: About to init USB\n");
+
+ /* Set config, interface, write end point, read end point, read quanta */
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x81, icomuf_none, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp20: set_usbe_port failed ICOM err 0x%x\n",se);
+ return dtp20_interp_code((inst *)p, icoms2dtp20_err(se));
+ }
+
+ /* Blind reset it twice - it seems to sometimes hang up */
+ /* otherwise under OSX */
+ dtp20_command(p, "0PR\r", buf, MAX_MES_SIZE, 0.5);
+ dtp20_command(p, "0PR\r", buf, MAX_MES_SIZE, 0.5);
+
+ } else {
+ a1logd(p->log, 1, "dtp20: Failed to find connection to instrument\n");
+ return inst_coms_fail;
+ }
+
+ /* Check instrument is responding */
+ if ((ev = dtp20_command(p, "\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok) {
+ a1logd(p->log, 1, "dtp20: Failed to get a response from instrument\n");
+ return inst_coms_fail;
+ }
+
+ /* Print the general information returned by instrument */
+ if (p->log->verb) {
+ int i, j;
+ if ((ev = dtp20_command(p, "GI\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok) {
+ a1logd(p->log, 1, "dtp20: GI command failed with ICOM err 0x%x\n",ev);
+ return ev;
+ }
+ for (j = i = 0; ;i++) {
+ if (buf[i] == '<' || buf[i] == '\000')
+ break;
+ if (buf[i] == '\r') {
+ buf[i] = '\000';
+ a1logv(p->log, 1, " %s\n",&buf[j]);
+ if (buf[i+1] == '\n')
+ i++;
+ j = i+1;
+ }
+ }
+ }
+
+ a1logd(p->log, 4, "dtp20: Got coms OK\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+/* Build a strip definition as a set of passes, including DS command */
+static void
+build_strip(
+dtp20 *p,
+char *tp, /* pointer to string buffer */
+char *name, /* Strip name (7 chars) (not used) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (3 chars) (not used) */
+int sguide, /* Guide number (not used) */
+double pwid, /* Patch length in mm */
+double gwid, /* Gap length in mm */
+double twid /* Trailer length in mm (For DTP41T) */
+) {
+
+ /* Enable SID field but don't report it, */
+ /* since we expect to be reading DTP20 type charts. */
+ /* (Could set to '1' for reading DTP41 type charts) */
+ tp[0] = '0';
+
+ /* Gap width */
+ if((gwid <= 0.25))
+ tp[1] = '0';
+ else if(gwid <= 0.75)
+ tp[1] = '1';
+ else if(gwid <= 1.25)
+ tp[1] = '2';
+ else if(gwid <= 1.75)
+ tp[1] = '3';
+ else if(gwid <= 2.25)
+ tp[1] = '4';
+ else if(gwid <= 2.75)
+ tp[1] = '5';
+ else if(gwid <= 3.25)
+ tp[1] = '6';
+ else
+ tp[1] = '7';
+
+ /* Patch width in mm, dd.dd */
+ if(pwid <= 6.75)
+ tp[2] = '0';
+ else if(pwid <= 8.0)
+ tp[2] = '1';
+ else if(pwid <= 11.25)
+ tp[2] = '4';
+ else if(pwid <= 12.75)
+ tp[2] = '6';
+ else
+ tp[2] = '7';
+
+ /* Number of patches in strip */
+ tp += 3;
+ sprintf(tp, "%02d",npatch);
+ tp += 2;
+
+ *tp++ = 'D'; /* The DS command */
+ *tp++ = 'S';
+ *tp++ = '\r'; /* The CR */
+ *tp++ = '\000'; /* The end */
+
+}
+
+/* Initialise the DTP20. */
+/* return non-zero on an error, with instrument error code */
+static inst_code
+dtp20_init_inst(inst *pp) {
+ dtp20 *p = (dtp20 *)pp;
+ char buf[MAX_MES_SIZE];
+ inst_code rv = inst_ok;
+
+ a1logd(p->log, 2, "dtp20_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_no_coms; /* Must establish coms before calling init */
+
+ /* Reset it (without disconnecting USB or clearing stored data) */
+ if ((rv = dtp20_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
+ return rv;
+// if ((rv = dtp20_command(p, "RI\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
+// return rv;
+
+ /* Set Response delimeter to CR */
+ if ((rv = dtp20_command(p, "0008CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+
+ /* Get the model and version number */
+ if ((rv = dtp20_command(p, "SV\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return rv;
+
+ /* Check that it is a DTP20 */
+ if ( strlen(buf) < 12
+ || (strncmp(buf,"X-Rite DTP20",12) != 0))
+ return inst_unknown_model;
+
+// /* Set Beeper to off */
+// if ((rv = dtp20_command(p, "0001CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+// return rv;
+
+ /* Set Beeper to on */
+ if ((rv = dtp20_command(p, "0101CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+
+ /* Set Automatic Transmit off */
+ if ((rv = dtp20_command(p, "0005CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+
+ /* Set color data separator to TAB */
+ if ((rv = dtp20_command(p, "0207CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+
+ /* Set 2 decimal digit resolution */
+ if ((rv = dtp20_command(p, "020ACF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+
+ /* set default trigger mode */
+ p->trig = inst_opt_trig_user_switch;
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Setup for the type of measurements we want to do */
+ /* Set instrument to XYZ mode */
+ if ((rv = dtp20_command(p, "0518CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+
+ /* Disable multiple data output */
+ if ((rv = dtp20_command(p, "001ACF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+
+ /* Set Illuminant to D50_2 */
+ if ((rv = dtp20_command(p, "0416CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+
+ /* Reset retrieval of saved spot readings */
+ p->savix = 0;
+
+ a1logd(p->log, 2, "dtp20_init_inst: instrument inited OK\n");
+ p->inited = 1;
+
+ return inst_ok;
+}
+
+/* Read a full test chart composed of multiple sheets. */
+/* This only works if the sheets have been read off-line */
+/* DOESN'T use the trigger mode */
+/* Return the inst error code */
+static inst_code dtp20_read_chart(
+inst *pp,
+int npatch, /* Total patches/values in chart */
+int pich, /* Passes (rows) in chart */
+int sip, /* Steps in each pass (patches in each row) */
+int *pis, /* Passes in each strip (rows in each sheet) */
+int chid, /* Chart ID number */
+ipatch *vals) { /* Pointer to array of values */
+ dtp20 *p = (dtp20 *)pp;
+ inst_code ev = inst_ok;
+ char buf[MAX_RD_SIZE];
+ int cs, sl, ttlp;
+ double pw, gw;
+ int u[10];
+ int id = -1;
+ ipatch *tvals;
+ int six; /* strip index */
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (!IMODETST(p->mode,inst_mode_s_ref_chart))
+ return inst_unsupported;
+
+ /* Confirm that there is a chart ready to read */
+ if ((ev = dtp20_command(p, "CS\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf," %d ", &cs) != 1)
+ return inst_protocol_error;
+ if (cs != 3) {
+ /* Seems to be no chart saved, but double check, in case of old firmware ( < 1.03) */
+ if ((ev = dtp20_command(p, "00TS\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return inst_nonesaved;
+ if (sscanf(buf," %d ", &cs) != 1)
+ return inst_nonesaved;
+ if (cs == 0)
+ return inst_nonesaved;
+ }
+
+ /* Get the TID */
+ if ((ev = dtp20_command(p, "ST\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf,"Strip Length: %d Total Patches: %d Patch Width: %lf mm Gap Width: %lf mm"
+ " User 1: %d User 2: %d User 3: %d User 4: %d User 5: %d User 6: %d"
+ " User 7: %d User 8: %d User 9: %d User 10: %d ",
+ &sl, &ttlp, &pw, &gw, &u[0], &u[1], &u[2], &u[3], &u[4],
+ &u[5], &u[6], &u[7], &u[8], &u[9]) != 14) {
+ return inst_protocol_error;
+ }
+ /* Compute the user data/chart id */
+ if (u[0] == 0) { /* This seems to be a chart ID */
+ id = ((u[1] * 8 + u[2]) * 8 + u[3]) * 8 + u[4];
+ }
+
+ /* Check that the chart matches what we're reading */
+ /* (Should we have a way of ignoring a chart if mismatch ?) */
+ if (ttlp != npatch
+ || sl != sip
+ || (id != -1 && id != chid)) {
+ a1logd(p->log, 2, "dtp20: Got %d, xpt %d patches, got %d xpt %d strip lgth, "
+ "got %d xpt %d chart id\n",ttlp,npatch,sl,sip,id,chid);
+ return inst_nochmatch;
+ }
+
+ a1logv(p->log, 1, "Chart has %d patches, %d per strip, chart id %d\n",ttlp,sl,id);
+
+ /* Disable multiple data output */
+ if ((ev = dtp20_command(p, "001ACF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+
+ /* Read each strip's values in turn */
+ for (tvals = vals, six = 1; six <= pich; six++, tvals += sip) {
+ char *tp, cmd[10];
+ int i;
+
+ a1logv(p->log, 1, "Reading saved strip %d of %d\n",six,pich);
+
+ /* Select the strip to read */
+ sprintf(cmd, "%03d01TS\r",six);
+
+ /* Gather the results in D50_2 XYZ. This instruction seems unreliable! */
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if ((ev = dtp20_command(p, cmd, buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+
+ /* Parse the buffer */
+ /* Replace '\r' with '\000' */
+ for (tp = buf; *tp != '\000'; tp++) {
+ if (*tp == '\r')
+ *tp = '\000';
+ }
+ for (tp = buf, i = 0; i < sip; i++) {
+ if (*tp == '\000' || strlen(tp) > 40)
+ return inst_protocol_error;
+ if (sscanf(tp, " %lf %lf %lf ",
+ &tvals[i].XYZ[0], &tvals[i].XYZ[1], &tvals[i].XYZ[2]) != 3) {
+ if (sscanf(tp, " %lf %lf %lf ",
+ &tvals[i].XYZ[0], &tvals[i].XYZ[1], &tvals[i].XYZ[2]) != 3) {
+ return inst_protocol_error;
+ }
+ }
+ tvals[i].loc[0] = '\000';
+ tvals[i].mtype = inst_mrt_reflective;
+ tvals[i].XYZ_v = 1;
+ tvals[i].sp.spec_n = 0;
+ tvals[i].duration = 0.0;
+ tp += strlen(tp) + 1;
+ }
+
+ if (p->mode & inst_mode_spectral) {
+
+ /* Gather the results in Spectral reflectance */
+ if ((ev = dtp20_command(p, "0318CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Set to binary */
+ if ((ev = dtp20_command(p, "011BCF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Read the strip */
+ if ((ev = dtp20_bin_command(p, cmd, buf, 62 * sip, 5.0)) != inst_ok)
+ return ev;
+
+ /* Get each patches spectra */
+ for (tp = buf, i = 0; i < sip; i++) {
+ int j;
+
+ /* Read the spectral value */
+ for (j = 0; j < 31; j++, tp += 2) {
+ int vv;
+ vv = (unsigned char)tp[0];
+ vv = vv * 256 + (unsigned char)tp[1];
+ tvals[i].sp.spec[j] = vv * 200.0/65535.0;
+ }
+
+ tvals[i].sp.spec_n = 31;
+ tvals[i].sp.spec_wl_short = 400.0;
+ tvals[i].sp.spec_wl_long = 700.0;
+ tvals[i].sp.norm = 100.0;
+ }
+
+ /* Set to ASCII */
+ if ((ev = dtp20_command(p, "001BCF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Set back to in D50_2 XYZ. This instruction seems unreliable! */
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ }
+ }
+
+ a1logv(p->log, 1, "All saved strips read\n");
+ return inst_ok;
+}
+
+/* Read a set of strips. This only works reading on-line */
+/* Return the instrument error code */
+static inst_code
+dtp20_read_strip(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (3 chars) */
+int sguide, /* Guide number */
+double pwid, /* Patch length in mm (For DTP20/DTP41) */
+double gwid, /* Gap length in mm (For DTP20/DTP41) */
+double twid, /* Trailer length in mm (For DTP41T) */
+ipatch *vals) { /* Pointer to array of instrument patch values */
+ dtp20 *p = (dtp20 *)pp;
+ char tbuf[200], *tp;
+ char buf[MAX_RD_SIZE];
+ int i, cs, se;
+ inst_code ev = inst_ok;
+ int user_trig = 0;
+ int switch_trig = 0;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* This funtion isn't valid in saved data mode */
+ if (!IMODETST(p->mode, inst_mode_ref_strip))
+ return inst_wrong_setup;
+
+ /* Until we get the right status or give up */
+ for (i = 0;;i++) {
+ /* Confirm that we are ready to read strips */
+ if ((ev = dtp20_command(p, "CS\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf," %d ", &cs) != 1)
+ return inst_protocol_error;
+ if (cs == 1)
+ break; /* Read and empty of offline patches */
+ if (cs == 2 || cs == 3)
+ return (inst_misread | DTP20_NOT_EMPTY); /* Has onffline patches */
+ if (i < 20) {
+ if (cs == 0 || (cs >= 4 && cs <= 12)) { /* Ignore transient status */
+ msec_sleep(100);
+ continue;
+ }
+ }
+ return (inst_misread | DTP20_UNEXPECTED_STATUS);
+ }
+
+ /* Send strip definition */
+ build_strip(p, tbuf, name, npatch, pname, sguide, pwid, gwid, twid);
+
+ if ((ev = dtp20_command(p, tbuf, buf, MAX_MES_SIZE, 1.5)) != inst_ok) {
+ a1logv(p->log, 1, "Interactive strip reading won't work on Firmware earlier than V1.03 !\n");
+ return ev;
+ }
+
+ if (p->trig == inst_opt_trig_user_switch) {
+ int touts = 0;
+
+ /* Wait for a strip value to turn up, or a user command/abort */
+ for (;;) {
+
+ ev = dtp20_command(p, "CS\r", buf, MAX_MES_SIZE, 0.2);
+
+ if (ev == (inst_coms_fail | DTP20_TIMEOUT)) {
+ /* Ignore transient timeouts */
+ if (touts++ > 40)
+ return ev;
+ continue;
+
+ } else if (ev != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+ return ev; /* Error */
+ } else {
+ int stat;
+ if (sscanf(buf, " %d ", &stat) != 1)
+ stat = 6;
+
+ /* Ignore benign status */
+ if (stat != 4 && stat != 6 && stat != 7) {
+ /* Not ready - Check for user trigger or command */
+ if (p->uicallback != NULL) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort) {
+ return ev; /* Error or user abort */
+ } else if (ev == inst_user_trig) {
+ user_trig = 1; /* User trigger */
+ break;
+ }
+ }
+ }
+ /* Keep waiting */
+ msec_sleep(200);
+ continue;
+
+ } else {
+ /* Ready - continue on */
+ switch_trig = 1;
+ break;
+ }
+ }
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ } else if (p->trig == inst_opt_trig_user) {
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "dtp20: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev;
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return ev;
+ }
+
+ /* Trigger a read if the switch has not been used */
+ if (switch_trig == 0) {
+ /* Do a strip read */
+ if ((ev = dtp20_command(p, "RM\r", buf, MAX_MES_SIZE, 10.0)) != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+ return ev;
+ }
+ }
+
+ /* Disable multiple data output */
+ if ((ev = dtp20_command(p, "001ACF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Gather the results in D50_2 XYZ This instruction seems unreliable! */
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if ((ev = dtp20_command(p, "01TS\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+
+ /* Parse the buffer */
+ /* Replace '\r' with '\000' */
+ for (tp = buf; *tp != '\000'; tp++) {
+ if (*tp == '\r')
+ *tp = '\000';
+ }
+ for (tp = buf, i = 0; i < npatch; i++) {
+ if (*tp == '\000' || strlen(tp) > 40)
+ return inst_protocol_error;
+ if (sscanf(tp, " %lf %lf %lf ",
+ &vals[i].XYZ[0], &vals[i].XYZ[1], &vals[i].XYZ[2]) != 3) {
+ if (sscanf(tp, " %lf %lf %lf ",
+ &vals[i].XYZ[0], &vals[i].XYZ[1], &vals[i].XYZ[2]) != 3) {
+ return inst_protocol_error;
+ }
+ }
+ vals[i].loc[0] = '\000';
+ vals[i].mtype = inst_mrt_reflective;
+ vals[i].XYZ_v = 1;
+ vals[i].sp.spec_n = 0;
+ vals[i].duration = 0.0;
+ tp += strlen(tp) + 1;
+ }
+
+ if (p->mode & inst_mode_spectral) {
+
+ /* Gather the results in Spectral reflectance */
+ if ((ev = dtp20_command(p, "0318CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Set to binary */
+ if ((ev = dtp20_command(p, "011BCF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+
+ /* Read the strip */
+ if ((ev = dtp20_bin_command(p, "01TS\r", buf, 62 * npatch, 5.0)) != inst_ok)
+ return ev;
+
+ /* Get each patches spectra */
+ for (tp = buf, i = 0; i < npatch; i++) {
+ int j;
+
+ /* Read the spectral value */
+ for (j = 0; j < 31; j++, tp += 2) {
+ int vv;
+ vv = (unsigned char)tp[0];
+ vv = vv * 256 + (unsigned char)tp[1];
+ vals[i].sp.spec[j] = vv * 200.0/65535.0;
+ }
+
+ vals[i].sp.spec_n = 31;
+ vals[i].sp.spec_wl_short = 400.0;
+ vals[i].sp.spec_wl_long = 700.0;
+ vals[i].sp.norm = 100.0;
+ }
+
+ /* Set to ASCII */
+ if ((ev = dtp20_command(p, "001BCF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Set back to D50 2 degree */
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ }
+
+ /* Wait for status to change */
+ for (;;) {
+ if ((ev = dtp20_command(p, "CS\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok) {
+ return ev;
+ } else {
+ int stat = 4;
+ if (sscanf(buf, " %d ", &stat) != 1 || stat != 4)
+ break;
+ msec_sleep(200);
+ }
+ }
+
+ if (user_trig)
+ return inst_user_trig;
+ return inst_ok;
+}
+
+
+/* Read a single sample. */
+/* This works both on-line and off-line. */
+/* Return the instrument error code */
+static inst_code
+dtp20_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ dtp20 *p = (dtp20 *)pp;
+ char buf[MAX_MES_SIZE], *tp;
+ int se;
+ inst_code ev = inst_ok;
+ int switch_trig = 0;
+ int user_trig = 0;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* This combination doesn't make any sense... */
+ if (IMODETST(p->mode, inst_mode_s_ref_spot) && p->trig == inst_opt_trig_user_switch) {
+ return inst_wrong_setup;
+ }
+
+ if (p->trig == inst_opt_trig_user_switch) {
+ int touts = 0;
+
+ /* Wait for a sample value to turn up, or a user abort */
+ for (;;) {
+
+ /* Check for user trigger */
+ if (p->uicallback != NULL) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* User abort */
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break;
+ }
+ }
+ }
+
+ /* Check for an instrument switch trigger */
+ ev = dtp20_command(p, "CS\r", buf, MAX_MES_SIZE, 0.2);
+
+ if (ev == (inst_coms_fail | DTP20_TIMEOUT)) { /* Assume we're waiting for trigger */
+ if (touts++ > 20)
+ return ev;
+ continue;
+
+ } else if (ev != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+ return ev; /* Error */
+
+ } else { /* Got a CS response */
+ int stat;
+ if (sscanf(buf, " %d ", &stat) != 1)
+ stat = 6;
+ /* Ingnore benign status */
+ if (stat != 4 && stat != 6 && stat != 7) {
+ msec_sleep(200);
+ continue;
+ }
+ switch_trig = 1;
+ break;
+ }
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ } else if (p->trig == inst_opt_trig_user) {
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "dtp20: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* Abort */
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return ev; /* Abort */
+ }
+
+ /* Read saved spot values */
+ if (IMODETST(p->mode, inst_mode_s_ref_spot)) {
+ char cmd[10];
+ int nsr;
+
+ /* See how many saved spot readings there are */
+ if ((ev = dtp20_command(p, "00GM\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf," %d ", &nsr) != 1)
+ return inst_protocol_error;
+
+ if (nsr <= p->savix)
+ return inst_nonesaved;
+
+ p->savix++;
+ sprintf(cmd, "%03d01GM\r",p->savix);
+ /* Disable multiple data output */
+ if ((ev = dtp20_command(p, "001ACF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Gather the results in D50_2 XYZ This instruction seems unreliable! */
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if ((ev = dtp20_command(p, cmd, buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+
+ /* Read real spot values */
+ } else {
+ /* Trigger a read if the switch has not been used */
+ if (switch_trig == 0) {
+ /* Do a spot read */
+ if ((ev = dtp20_command(p, "RM\r", buf, MAX_MES_SIZE, 5.0)) != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+ return ev;
+ }
+ }
+
+ /* Disable multiple data output */
+ if ((ev = dtp20_command(p, "001ACF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Gather the results in D50_2 XYZ */
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if ((ev = dtp20_command(p, "01GM\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+
+ }
+
+ val->XYZ[0] = val->XYZ[1] = val->XYZ[2] = 0.0;
+
+ if (*buf == '\000' || strlen(buf) > 40)
+ return inst_protocol_error;
+
+ if (sscanf(buf, " %lf %lf %lf ", &val->XYZ[0], &val->XYZ[1], &val->XYZ[2]) != 3) {
+ return inst_protocol_error;
+ }
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+ val->loc[0] = '\000';
+ val->mtype = inst_mrt_reflective;
+ val->XYZ_v = 1;
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (p->mode & inst_mode_spectral) {
+ int j;
+
+ /* Set to read spectral reflectance */
+ if ((ev = dtp20_command(p, "0318CF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Set to binary */
+ if ((ev = dtp20_command(p, "011BCF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Get measurement */
+ if ((ev = dtp20_bin_command(p, "01GM\r", buf, 62, 2.0)) != inst_ok)
+ return ev;
+
+ for (j = 0; j < 31; j++)
+ val->sp.spec[j] = 0.0;
+
+ /* Read the spectral value */
+ for (tp = buf, j = 0; j < 31; j++, tp += 2) {
+ int vv;
+ vv = (unsigned char)tp[0];
+ vv = vv * 256 + (unsigned char)tp[1];
+ val->sp.spec[j] = vv * 200.0/65535.0;
+ }
+
+ val->sp.spec_n = 31;
+ val->sp.spec_wl_short = 400.0;
+ val->sp.spec_wl_long = 700.0;
+ val->sp.norm = 100.0;
+
+ /* Set to ASCII */
+ if ((ev = dtp20_command(p, "001BCF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ /* Set to D50 2 degree */
+ if ((ev = dtp20_command(p, "0518CF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ }
+
+ if (!IMODETST(p->mode, inst_mode_s_ref_spot)) {
+
+ /* Clear the spot database so our reading doesn't appear as a stored reading */
+ if ((ev = dtp20_command(p, "02CD\r", buf, MAX_MES_SIZE, 1.0)) != inst_ok)
+ return ev;
+ p->savix = 0;
+
+ /* Wait for status to change */
+ for (;;) {
+ if ((ev = dtp20_command(p, "CS\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok) {
+ return ev;
+ } else {
+ int stat = 4;
+ if (sscanf(buf, " %d ", &stat) != 1 || stat != 4)
+ break;
+ msec_sleep(200);
+ }
+ }
+ }
+
+ if (user_trig)
+ return inst_user_trig;
+ return inst_ok;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code dtp20_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ dtp20 *p = (dtp20 *)pp;
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if (p->need_cal)
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+/* This is use if the user decides they want to do a calibration, */
+/* in anticipation of a calibration (needs_calibration()) to avoid */
+/* requiring one during measurement, or in response to measuring */
+/* returning inst_needs_cal. Initially us an inst_cal_cond of inst_calc_none, */
+/* and then be prepared to setup the right conditions, or ask the */
+/* user to do so, each time the error inst_cal_setup is returned. */
+inst_code dtp20_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ dtp20 *p = (dtp20 *)pp;
+ char buf[MAX_MES_SIZE];
+ inst_code ev;
+ inst_cal_type needed, available;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ id[0] = '\000';
+
+ if ((ev = dtp20_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"dtp20_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return inst_unsupported;
+ }
+
+ if (*calt & inst_calt_ref_white) {
+
+ if (*calc != inst_calc_man_ref_white) {
+ char *cp;
+ if ((ev = dtp20_command(p, "04SN\r", buf, MAX_MES_SIZE, 4.5)) != inst_ok)
+ return ev;
+ for (cp = buf; *cp >= '0' && *cp <= '9'; cp++)
+ ;
+ *cp = '\000';
+ strcpy(id, buf);
+ *calc = inst_calc_man_ref_white;
+ return inst_cal_setup;
+ }
+
+ if ((ev = dtp20_command(p, "CR\r", buf, MAX_MES_SIZE, 4.5)) != inst_ok)
+ return ev;
+
+ p->need_cal = 0;
+ *calt &= ~inst_calt_ref_white;
+ }
+
+ return inst_ok;
+}
+
+/* Error codes interpretation */
+static char *
+dtp20_interp_error(inst *pp, int ec) {
+// dtp20 *p = (dtp20 *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+
+ case DTP20_INTERNAL_ERROR:
+ return "Internal software error";
+ case DTP20_COMS_FAIL:
+ return "Communications failure";
+ case DTP20_UNKNOWN_MODEL:
+ return "Not a DTP20";
+ case DTP20_DATA_PARSE_ERROR:
+ return "Data from DTP didn't parse as expected";
+
+ case DTP20_NOT_EMPTY:
+ return "Trying to read strips when there is already\n"
+ "an offline chart partially read. Clear the instrument and try again";
+ case DTP20_UNEXPECTED_STATUS:
+ return "Unexpected instrument status";
+
+ case DTP20_OK:
+ return "No device error";
+
+ case DTP20_MEASUREMENT_STATUS:
+ return "Measurement complete";
+
+ case DTP20_BAD_COMMAND:
+ return "Unrecognised command";
+ case DTP20_BAD_PARAMETERS:
+ return "Wrong number of parameters";
+ case DTP20_PRM_RANGE_ERROR:
+ return "One or more parameters are out of range";
+ case DTP20_BUSY:
+ return "Instrument is busy - command ignored";
+
+ case DTP20_MEASUREMENT_ERROR:
+ return "General measurement error";
+ case DTP20_TIMEOUT:
+ return "Receive timeout";
+ case DTP20_BAD_STRIP:
+ return "Bad strip";
+
+ case DTP20_NEEDS_CAL_ERROR:
+ return "Instrument needs calibration";
+ case DTP20_CAL_FAILURE_ERROR:
+ return "Calibration failed";
+
+ case DTP20_INSTRUMENT_ERROR:
+ return "General instrument error";
+ case DTP20_LAMP_ERROR:
+ return "Reflectance lamp error";
+
+ case DTP20_BAD_TID:
+ return "Invalid TID detected, Re-scan TID";
+ case DTP20_FLASH_ERASE_FAILURE:
+ return "Flash erase operation failed, Contact support";
+ case DTP20_FLASH_WRITE_FAILURE:
+ return "Flash write operation failed, Contact support";
+ case DTP20_FLASH_VERIFY_FAILURE:
+ return "Flash verify operation failed, Contact support";
+ case DTP20_MEMORY_ERROR:
+ return "Memory access failed, Contact support";
+ case DTP20_ADC_ERROR:
+ return "Analog to digital converter error, Contact support";
+ case DTP20_PROCESSOR_ERROR:
+ return "General processor error, Contact support";
+ case DTP20_BATTERY_ERROR:
+ return "General battery error occurred, Contact support";
+ case DTP20_BATTERY_LOW_ERROR:
+ return "Battery level too low to measure, Charge battery";
+ case DTP20_INPUT_POWER_ERROR:
+ return "Input power out of range, Contact support";
+
+ case DTP20_BATTERY_ABSENT_ERROR:
+ return "Battery could not be detected, Contact support";
+ case DTP20_BAD_CONFIGURATION:
+ return "Stored configuration data invalid, Set as desired";
+
+ case DTP20_BAD_SPOT:
+ return "Invalid spot reading was requested, Re-read or resend";
+ case DTP20_END_OF_DATA:
+ return "End of profile reached, None";
+ case DTP20_DBASE_PROFILE_NOT_EMPTY:
+ return "Profile database not empty, Clear profile data";
+ case DTP20_MEMORY_OVERFLOW_ERROR:
+ return "Memory overflow error, Contact support";
+ case DTP20_BAD_CALIBRATION:
+ return "Bad calibration data detected, Contact support";
+
+ case DTP20_CYAN_CAL_ERROR:
+ return "Failed cyan calibration during TID read, Re-scan TID";
+ case DTP20_MAGENTA_CAL_ERROR:
+ return "Failed magenta calibration during TID read, Re-scan TID";
+ case DTP20_YELLOW_CAL_ERROR:
+ return "Failed yellow calibration during TID read, Re-scan TID";
+ case DTP20_PATCH_SIZE_ERROR:
+ return "Invalid strip patch size was detected, Re-scan";
+ case DTP20_FAIL_PAPER_CHECK:
+ return "Failed to verify scan started/stopped on paper, Re-scan";
+ case DTP20_SHORT_SCAN_ERROR:
+ return "Less than minimum positional ticks detected, Re-scan";
+ case DTP20_STRIP_READ_ERROR:
+ return "General strip reading error, Re-scan";
+ case DTP20_SHORT_TID_ERROR:
+ return "Failed TID length verification, Re-scan TID";
+ case DTP20_SHORT_STRIP_ERROR:
+ return "Strip length invalid, Re-scan";
+ case DTP20_EDGE_COLOR_ERROR:
+ return "Strip edge color was measured invalid, Re-scan";
+ case DTP20_SPEED_ERROR:
+ return "Manual scan too fast to gather data, Re-scan";
+ case DTP20_UNDEFINED_SCAN_ERROR:
+ return "General scan error, Re-scan";
+ case DTP20_INVALID_STRIP_ID:
+ return "A strip ID field was out-of-range, Re-scan";
+ case DTP20_BAD_SERIAL_NUMBER:
+ return "A bad serial number has been detected, Contact support";
+ case DTP20_TID_ALREADY_SCANNED:
+ return "A TID has already been scanned, Scan strips";
+ case DTP20_PROFILE_DATABASE_FULL:
+ return "Profile database is full, Clear profile data";
+
+ case DTP20_SPOT_DATABASE_FULL:
+ return "Spot database is full, Clear spot data";
+ case DTP20_TID_STRIP_MIN_ERROR:
+ return "A TID was specified with fewer than 5 patches, Re-define TID";
+ case DTP20_REREAD_DATABASE_FULL:
+ return "Strip reread database is full (can't reread), Clear profile data";
+ case DTP20_STRIP_DEFINE_TOO_SHORT:
+ return "Strip definition contains too few patches, Re-define strip";
+ case DTP20_STRIP_DEFINE_TOO_LONG:
+ return "Strip definition contains too many patches, Re-define strip";
+ case DTP20_BAD_STRIP_DEFINE:
+ return "No valid strip defined, Define strip";
+
+ case DTP20_BOOTLOADER_MODE:
+ return "Instrument is in FW update mode, Reset or load FW";
+
+ default:
+ return "Unknown error code";
+ }
+}
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+dtp20_interp_code(inst *pp, int ec) {
+// dtp20 *p = (dtp20 *)pp;
+
+ switch (ec) {
+
+ case DTP20_OK:
+ return inst_ok;
+
+ case DTP20_MEASUREMENT_STATUS:
+ case DTP20_END_OF_DATA:
+ return inst_notify | ec;
+
+ case DTP20_INTERNAL_ERROR:
+ return inst_internal_error | ec;
+
+ case DTP20_TIMEOUT:
+ case DTP20_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case DTP20_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+ case DTP20_DATA_PARSE_ERROR:
+ case DTP20_BAD_COMMAND:
+ case DTP20_BAD_PARAMETERS:
+ case DTP20_PRM_RANGE_ERROR:
+ case DTP20_BUSY:
+ return inst_protocol_error | ec;
+
+ case DTP20_MEASUREMENT_ERROR:
+ case DTP20_BAD_STRIP:
+ case DTP20_BAD_SPOT:
+ case DTP20_CAL_FAILURE_ERROR:
+ case DTP20_BAD_TID:
+ case DTP20_CYAN_CAL_ERROR:
+ case DTP20_MAGENTA_CAL_ERROR:
+ case DTP20_YELLOW_CAL_ERROR:
+ case DTP20_PATCH_SIZE_ERROR:
+ case DTP20_FAIL_PAPER_CHECK:
+ case DTP20_SHORT_SCAN_ERROR:
+ case DTP20_STRIP_READ_ERROR:
+ case DTP20_SHORT_TID_ERROR:
+ case DTP20_SHORT_STRIP_ERROR:
+ case DTP20_EDGE_COLOR_ERROR:
+ case DTP20_SPEED_ERROR:
+ case DTP20_UNDEFINED_SCAN_ERROR:
+ case DTP20_INVALID_STRIP_ID:
+ case DTP20_TID_ALREADY_SCANNED:
+ case DTP20_NOT_EMPTY:
+ case DTP20_UNEXPECTED_STATUS:
+ return inst_misread | ec;
+
+ case DTP20_NEEDS_CAL_ERROR:
+ return inst_needs_cal | ec;
+
+ case DTP20_INSTRUMENT_ERROR:
+ case DTP20_LAMP_ERROR:
+ case DTP20_FLASH_ERASE_FAILURE:
+ case DTP20_FLASH_WRITE_FAILURE:
+ case DTP20_FLASH_VERIFY_FAILURE:
+ case DTP20_MEMORY_ERROR:
+ case DTP20_ADC_ERROR:
+ case DTP20_PROCESSOR_ERROR:
+ case DTP20_BATTERY_ERROR:
+ case DTP20_INPUT_POWER_ERROR:
+ case DTP20_BATTERY_LOW_ERROR:
+ case DTP20_BATTERY_ABSENT_ERROR:
+ case DTP20_MEMORY_OVERFLOW_ERROR:
+ case DTP20_BAD_CALIBRATION:
+ case DTP20_BAD_SERIAL_NUMBER:
+ return inst_hardware_fail | ec;
+
+ case DTP20_BAD_CONFIGURATION:
+ case DTP20_DBASE_PROFILE_NOT_EMPTY:
+ case DTP20_PROFILE_DATABASE_FULL:
+ case DTP20_SPOT_DATABASE_FULL:
+ case DTP20_TID_STRIP_MIN_ERROR:
+ case DTP20_REREAD_DATABASE_FULL:
+ case DTP20_STRIP_DEFINE_TOO_SHORT:
+ case DTP20_STRIP_DEFINE_TOO_LONG:
+ case DTP20_BAD_STRIP_DEFINE:
+ case DTP20_BOOTLOADER_MODE:
+ return inst_wrong_setup | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+dtp20_del(inst *pp) {
+ dtp20 *p = (dtp20 *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ free (p);
+}
+
+/* Set the instrument capabilities */
+static void set_capabilities(dtp20 *p) {
+
+ p->cap = inst_mode_ref_spot
+ | inst_mode_ref_strip
+ | inst_mode_s_ref_spot
+ | inst_mode_s_ref_chart
+ | inst_mode_colorimeter
+ | inst_mode_spectral
+ ;
+
+ p->cap2 = inst2_prog_trig
+ | inst2_user_switch_trig
+ | inst2_user_trig
+ | inst2_has_battery
+ ;
+
+ p->cap3 = inst3_none;
+}
+
+
+/* Return the instrument capabilities */
+void dtp20_capabilities(inst *pp,
+inst_mode *cap1,
+inst2_capability *cap2,
+inst3_capability *cap3) {
+ dtp20 *p = (dtp20 *)pp;
+
+ if (p->cap == inst_mode_none)
+ set_capabilities(p);
+
+ if (cap1 != NULL)
+ *cap1 = p->cap;
+ if (cap2 != NULL)
+ *cap2 = p->cap2;
+ if (cap3 != NULL)
+ *cap3 = p->cap3;
+}
+
+/*
+ * check measurement mode
+ */
+static inst_code
+dtp20_check_mode(inst *pp, inst_mode m) {
+ dtp20 *p = (dtp20 *)pp;
+ inst_mode cap;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* Check specific modes */
+ if (!IMODETST(m, inst_mode_ref_spot)
+ && !IMODETST(m, inst_mode_ref_strip)
+ && !IMODETST(m, inst_mode_s_ref_spot)
+ && !IMODETST(m, inst_mode_s_ref_chart)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * set measurement mode
+ */
+static inst_code
+dtp20_set_mode(inst *pp, inst_mode m) {
+ dtp20 *p = (dtp20 *)pp;
+ inst_code ev;
+
+ if ((ev = dtp20_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->mode = m;
+
+ return inst_ok;
+}
+
+/* Get a status or get or set an option */
+static inst_code dtp20_get_set_opt(
+inst *pp,
+inst_opt_type m, /* Requested status type */
+...) { /* Status parameters */
+ dtp20 *p = (dtp20 *)pp;
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user
+ || m == inst_opt_trig_user_switch) {
+ p->trig = m;
+
+ return inst_ok;
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (m == inst_stat_saved_readings) {
+ char buf[MAX_MES_SIZE];
+ int ev;
+ va_list args;
+ inst_stat_savdrd *fe;
+ int nsr, cs;
+
+ va_start(args, m);
+ fe = va_arg(args, inst_stat_savdrd *);
+ va_end(args);
+
+ *fe = inst_stat_savdrd_none;
+
+ /* See how many saved spot readings there are */
+ if ((ev = dtp20_command(p, "00GM\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf," %d ", &nsr) != 1)
+ return inst_protocol_error;
+ if (nsr > p->savix)
+ *fe |= inst_stat_savdrd_spot;
+
+ /* See if the instrument has read a partial or complete target */
+ if ((ev = dtp20_command(p, "CS\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf," %d ", &cs) != 1)
+ return inst_protocol_error;
+ if (0 && (cs == 2 || cs == 3)) { // ??? Is this unreliable ???
+ *fe |= inst_stat_savdrd_chart;
+ } else {
+ /* Seems to be no chart saved, but double check, in case of old firmware */
+ if ((ev = dtp20_command(p, "00TS\r", buf, MAX_MES_SIZE, 0.5)) == inst_ok) {
+ if (sscanf(buf," %d ", &cs) == 1) {
+ if (cs != 0) {
+ *fe |= inst_stat_savdrd_chart;
+ }
+ }
+ }
+ }
+ return inst_ok;
+ }
+
+ /* Return the number of saved spot readings */
+ if (m == inst_stat_s_spot) {
+ int ev;
+ char buf[MAX_MES_SIZE];
+ int *pnsr;
+ va_list args;
+
+ va_start(args, m);
+ pnsr = va_arg(args, int *);
+ va_end(args);
+
+ *pnsr = -1;
+
+ /* See how many saved spot readings there are */
+ if ((ev = dtp20_command(p, "00GM\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf," %d ", pnsr) != 1)
+ return inst_protocol_error;
+
+ if (*pnsr -= p->savix) /* ??? */
+
+ return inst_ok;
+ }
+
+ /* Return the saved chart details */
+ if (m == inst_stat_s_chart) {
+ inst_code ev = inst_ok;
+ char buf[MAX_RD_SIZE], *bp, *ep;
+ int u[10];
+ va_list args;
+ int *no_patches, *no_rows, *pat_per_row, *chart_id, *missing_row;
+ int i, cs;
+ double pw, gw;
+
+ va_start(args, m);
+ no_patches = va_arg(args, int *);
+ no_rows = va_arg(args, int *);
+ pat_per_row = va_arg(args, int *);
+ chart_id = va_arg(args, int *);
+ missing_row = va_arg(args, int *);
+ va_end(args);
+
+ *no_patches = *no_rows = *pat_per_row = *chart_id = *missing_row = -1;
+
+ /* Get the TID */
+ if ((ev = dtp20_command(p, "ST\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf,"Strip Length: %d Total Patches: %d Patch Width: %lf mm Gap Width: %lf mm"
+ " User 1: %d User 2: %d User 3: %d User 4: %d User 5: %d User 6: %d"
+ " User 7: %d User 8: %d User 9: %d User 10: %d ",
+ pat_per_row, no_patches, &pw, &gw, &u[0], &u[1], &u[2], &u[3], &u[4],
+ &u[5], &u[6], &u[7], &u[8], &u[9]) != 14) {
+ return inst_protocol_error;
+ }
+ /* Compute number of rows */
+ *no_rows = *no_patches / *pat_per_row;
+
+ /* Compute the user data/chart id */
+ if (u[0] == 0) /* This seems to be a chart ID */
+ *chart_id = ((u[1] * 8 + u[2]) * 8 + u[3]) * 8 + u[4];
+
+ /* See if any strips are missing */
+ if ((ev = dtp20_command(p, "CS\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf," %d ", &cs) != 1)
+ return inst_protocol_error;
+ if (cs == 2) {
+ if ((ev = dtp20_command(p, "01TT\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ bp = buf;
+ for (i = 1; i <= *no_rows; i++) {
+ int strno = 0;
+
+ /* Locate the next number */
+ while(*bp != '\000' && (*bp < '0' || *bp > '9'))
+ bp++;
+
+ /* Locate the end of the number */
+ ep = bp;
+ while (*ep != '\000' && *ep >= '0' && *ep <= '9')
+ ep++;
+ *ep = '\000';
+
+ if (ep > bp)
+ strno = atoi(bp);
+ if (strno != i) {
+ *missing_row = i; /* Assume no missing rows */
+ break;
+ }
+ bp = ep+1;
+ if (bp >= (buf + MAX_MES_SIZE))
+ return inst_protocol_error;
+ }
+ }
+
+ return inst_ok;
+ }
+
+ /* Return the charged status of the battery */
+ if (m == inst_stat_battery) {
+ int ev;
+ char buf[MAX_MES_SIZE];
+ double *pbchl;
+ va_list args;
+ int cs;
+
+ va_start(args, m);
+ pbchl = va_arg(args, double *);
+ va_end(args);
+
+ *pbchl = -1.0;
+
+ /* See how charged the battery is */
+ if ((ev = dtp20_command(p, "06BA\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ if (sscanf(buf," %d ", &cs) != 1)
+ return inst_protocol_error;
+
+ if (cs == 4)
+ *pbchl = 1.0;
+ else if (cs == 3)
+ *pbchl = 0.75;
+ else if (cs == 2)
+ *pbchl = 0.50;
+ else if (cs == 1)
+ *pbchl = 0.25;
+ else
+ *pbchl = 0.0;
+
+ return inst_ok;
+ }
+
+ /* !! It's not clear if there is a way of knowing */
+ /* whether the instrument has a UV filter. */
+
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
+}
+
+/* Constructor */
+extern dtp20 *new_dtp20(icoms *icom, instType itype) {
+ dtp20 *p;
+ if ((p = (dtp20 *)calloc(sizeof(dtp20),1)) == NULL) {
+ a1loge(icom->log, 1, "new_dtp20: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = dtp20_init_coms;
+ p->init_inst = dtp20_init_inst;
+ p->capabilities = dtp20_capabilities;
+ p->check_mode = dtp20_check_mode;
+ p->set_mode = dtp20_set_mode;
+ p->get_set_opt = dtp20_get_set_opt;
+ p->read_chart = dtp20_read_chart;
+ p->read_strip = dtp20_read_strip;
+ p->read_sample = dtp20_read_sample;
+ p->get_n_a_cals = dtp20_get_n_a_cals;
+ p->calibrate = dtp20_calibrate;
+ p->interp_error = dtp20_interp_error;
+ p->del = dtp20_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+ p->cap = inst_mode_none; /* Unknown until set */
+ p->mode = inst_mode_none; /* Not in a known mode yet */
+
+ return p;
+}
diff --git a/spectro/dtp20.h b/spectro/dtp20.h
new file mode 100644
index 0000000..f1e578a
--- /dev/null
+++ b/spectro/dtp20.h
@@ -0,0 +1,139 @@
+#ifndef DTP41_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP20 related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 10/1/2007
+ *
+ * Copyright 1996 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from DTP51.h
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Fake Error codes */
+#define DTP20_INTERNAL_ERROR 0x81 /* Internal software error */
+#define DTP20_COMS_FAIL 0x82 /* Communication failure */
+#define DTP20_UNKNOWN_MODEL 0x83 /* Not a DPT51 or DTP52 */
+#define DTP20_DATA_PARSE_ERROR 0x84 /* Read data parsing error */
+
+#define DTP20_NOT_EMPTY 0x89 /* Trying to read strips when not empty */
+#define DTP20_UNEXPECTED_STATUS 0x90 /* Instrument has unexpected status */
+
+/* Real error code */
+#define DTP20_OK 0x00
+
+#define DTP20_MEASUREMENT_STATUS 0x01
+
+#define DTP20_BAD_COMMAND 0x11
+#define DTP20_BAD_PARAMETERS 0x12
+#define DTP20_PRM_RANGE_ERROR 0x13
+#define DTP20_BUSY 0x14
+
+#define DTP20_MEASUREMENT_ERROR 0x20
+#define DTP20_TIMEOUT 0x21
+#define DTP20_BAD_STRIP 0x22
+
+#define DTP20_NEEDS_CAL_ERROR 0x28
+#define DTP20_CAL_FAILURE_ERROR 0x29
+
+#define DTP20_INSTRUMENT_ERROR 0x30
+#define DTP20_LAMP_ERROR 0x31
+
+#define DTP20_BAD_TID 0x33
+#define DTP20_FLASH_ERASE_FAILURE 0x34
+#define DTP20_FLASH_WRITE_FAILURE 0x35
+#define DTP20_FLASH_VERIFY_FAILURE 0x36
+#define DTP20_MEMORY_ERROR 0x37
+#define DTP20_ADC_ERROR 0x38
+#define DTP20_PROCESSOR_ERROR 0x39
+#define DTP20_BATTERY_ERROR 0x3A
+#define DTP20_BATTERY_LOW_ERROR 0x3B
+#define DTP20_INPUT_POWER_ERROR 0x3C
+
+#define DTP20_BATTERY_ABSENT_ERROR 0x3E
+#define DTP20_BAD_CONFIGURATION 0x3F
+
+#define DTP20_BAD_SPOT 0x41
+#define DTP20_END_OF_DATA 0x42
+#define DTP20_DBASE_PROFILE_NOT_EMPTY 0x43
+#define DTP20_MEMORY_OVERFLOW_ERROR 0x44
+#define DTP20_BAD_CALIBRATION 0x45
+
+#define DTP20_CYAN_CAL_ERROR 0x50
+#define DTP20_MAGENTA_CAL_ERROR 0x51
+#define DTP20_YELLOW_CAL_ERROR 0x52
+#define DTP20_PATCH_SIZE_ERROR 0x53
+#define DTP20_FAIL_PAPER_CHECK 0x54
+#define DTP20_SHORT_SCAN_ERROR 0x55
+#define DTP20_STRIP_READ_ERROR 0x56
+#define DTP20_SHORT_TID_ERROR 0x57
+#define DTP20_SHORT_STRIP_ERROR 0x58
+#define DTP20_EDGE_COLOR_ERROR 0x59
+#define DTP20_SPEED_ERROR 0x5A
+#define DTP20_UNDEFINED_SCAN_ERROR 0x5B
+#define DTP20_INVALID_STRIP_ID 0x5C
+#define DTP20_BAD_SERIAL_NUMBER 0x5D
+#define DTP20_TID_ALREADY_SCANNED 0x5E
+#define DTP20_PROFILE_DATABASE_FULL 0x5F
+
+#define DTP20_SPOT_DATABASE_FULL 0x60
+#define DTP20_TID_STRIP_MIN_ERROR 0x61
+#define DTP20_REREAD_DATABASE_FULL 0x62
+#define DTP20_STRIP_DEFINE_TOO_SHORT 0x63
+#define DTP20_STRIP_DEFINE_TOO_LONG 0x64
+#define DTP20_BAD_STRIP_DEFINE 0x65
+
+#define DTP20_BOOTLOADER_MODE 0x7F
+
+/* DTP20 communication object */
+struct _dtp20 {
+ /* **** base instrument class **** */
+ INST_OBJ_BASE
+
+ /* *** DTP20 private data **** */
+ inst_mode cap; /* Instrument mode capability */
+ inst2_capability cap2; /* Instrument capability 2 */
+ inst3_capability cap3; /* Instrument capability 3 */
+ inst_mode mode; /* Currently instrument mode */
+
+ int need_cal; /* Got a need_cal error */
+ inst_opt_type trig; /* Reading trigger mode */
+
+ int savix; /* Index of last saved spot reading read */
+
+}; typedef struct _dtp20 dtp20;
+
+/* Constructor */
+extern dtp20 *new_dtp20(icoms *icom, instType itype);
+
+
+
+#define DTP20_H
+#endif /* DTP20_H */
diff --git a/spectro/dtp22.c b/spectro/dtp22.c
new file mode 100644
index 0000000..5831a1d
--- /dev/null
+++ b/spectro/dtp22.c
@@ -0,0 +1,1110 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP22 related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/11/2006
+ *
+ * Copyright 1996 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* !SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* !SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "dtp22.h"
+
+/* Default flow control (Instrument doesn't support HW flow control) */
+#define DEFFC fc_XonXOff
+
+static inst_code dtp22_interp_code(inst *pp, int ec);
+static int comp_password(char *out, char *in, unsigned char key[4]);
+static inst_code activate_mode(dtp22 *p);
+static inst_code dtp22_get_set_opt(inst *pp, inst_opt_type m, ...);
+
+#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */
+
+/* Known DTP22 challenge/response keys for each OEM */
+/* (This is a 24 bit key - only the xor of the middle 2 bytes is significant) */
+/* The keys seem to be base 6/36, using nibbles with 2+2 bits: 3 5 6 9 A C */
+/* The last digit corresponds to the OEM serial number (ie. 6C + 9base6 = A6) */
+/* Possibly each digit is offset by the oemsn if counted in the right sequence ? - */
+/* ie. base 40 sequence or so ? Need more examples of keys to tell. */
+struct {
+ int oemsn;
+ unsigned char key[4];
+} keys[] = {
+ { 0, { 0x39, 0xa6, 0x55, 0x6c }}, /* Standard DTP22 */
+ { 9, { 0x5a, 0x66, 0xcc, 0xa6 }}, /* ColorMark calibrator - MacDermid GRAPHICARTS ColorSpan */
+ { -1, } /* End marker */
+};
+
+/* Extract an error code from a reply string */
+/* Return -1 if no error code can be found */
+static int
+extract_ec(char *s) {
+ char *p;
+ char tt[3];
+ int rv;
+ p = s + strlen(s);
+ /* Find the trailing '>' */
+ for (p--; p >= s;p--) {
+ if (*p == '>')
+ break;
+ }
+ if ( (p-3) < s
+ || p[0] != '>'
+ || p[-3] != '<')
+ return -1;
+ tt[0] = p[-2];
+ tt[1] = p[-1];
+ tt[2] = '\000';
+ if (sscanf(tt,"%x",&rv) != 1)
+ return -1;
+ /* For some reason the top bit sometimes get set ? */
+ rv &= 0x7f;
+ return rv;
+}
+
+/* Interpret an icoms error into a DTP22 error */
+static int icoms2dtp22_err(int se) {
+ if (se != ICOM_OK) {
+ if (se & ICOM_TO)
+ return DTP22_TIMEOUT;
+ return DTP22_COMS_FAIL;
+ }
+ return DTP22_OK;
+}
+
+/* Do a full featured command/response echange with the dtp22 */
+/* Return the dtp error code. End on the specified number */
+/* of specified characters, or expiry if the specified timeout */
+/* Assume standard error code if tc = '>' and ntc = 1 */
+/* Return a DTP22 error code */
+static int
+dtp22_fcommand(
+ struct _dtp22 *p,
+ char *in, /* In string */
+ char *out, /* Out string buffer */
+ int bsize, /* Out buffer size */
+ char tc, /* Terminating character */
+ int ntc, /* Number of terminating characters */
+ double to) { /* Timout in seconds */
+ int se, rv = DTP22_OK;
+
+ if ((se = p->icom->write_read(p->icom, in, out, bsize, tc, ntc, to)) != 0) {
+ a1logd(p->log, 1, "dtp22_fcommand: serial i/o failure on write_read '%s'\n",icoms_fix(in));
+ return icoms2dtp22_err(se);
+ }
+ if (tc == '>' && ntc == 1) {
+ rv = extract_ec(out);
+#ifdef NEVER /* Simulate an error ?? */
+ if (strcmp(in, "0PR\r") == 0)
+ rv = 0x1b;
+#endif /* NEVER */
+ if (rv > 0) {
+ rv &= inst_imask;
+ if (rv != DTP22_OK) { /* Clear the error */
+ char buf[MAX_MES_SIZE];
+ p->icom->write_read(p->icom, "CE\r", buf, MAX_MES_SIZE, '>', 1, 0.5);
+ }
+ }
+ }
+ a1logd(p->log, 4, "dtp22_fcommand: command '%s' returned '%s', value 0x%x\n",
+ icoms_fix(in), icoms_fix(out),rv);
+ return rv;
+}
+
+/* Do a standard command/response echange with the dtp22 */
+/* Return the dtp error code */
+static inst_code
+dtp22_command(dtp22 *p, char *in, char *out, int bsize, double to) {
+ int rv = dtp22_fcommand(p, in, out, bsize, '>', 1, to);
+ return dtp22_interp_code((inst *)p, rv);
+}
+
+/* Establish communications with a DTP22 */
+/* If it's a serial port, use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+dtp22_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ dtp22 *p = (dtp22 *) pp;
+ char buf[MAX_MES_SIZE];
+ baud_rate brt[5] = { baud_9600, baud_19200, baud_4800, baud_2400, baud_1200 };
+ char *brc[5] = { "30BR\r", "60BR\r", "18BR\r", "0CBR\r", "06BR\r" };
+ char *fcc;
+ unsigned int etime;
+ int ci, bi, i, se;
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "dtp22_init_coms: About to init Serial I/O\n");
+
+ /* Deal with flow control setting */
+ if (fc == fc_nc)
+ fc = DEFFC;
+ if (fc == fc_XonXOff) {
+ fcc = "0304CF\r";
+ } else if (fc == fc_Hardware) {
+ fcc = "0104CF\r";
+ } else {
+ fc = fc_none;
+ fcc = "0004CF\r";
+ }
+
+ /* Figure DTP22 baud rate being asked for */
+ for (bi = 0; bi < 5; bi++) {
+ if (brt[bi] == br)
+ break;
+ }
+ if (bi >= 5)
+ bi = 0;
+
+ /* Figure current icoms baud rate */
+ for (ci = 0; ci < 5; ci++) {
+ if (brt[ci] == p->icom->br)
+ break;
+ }
+ if (ci >= 5)
+ ci = bi;
+
+ /* The tick to give up on */
+ etime = msec_time() + (long)(1000.0 * tout + 0.5);
+
+ while (msec_time() < etime) {
+
+ a1logd(p->log, 4, "dtp22_init_coms: Trying different baud rates (%u msec to go)\n",
+ etime - msec_time());
+
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+
+ if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp22_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
+ }
+ if (((ev = dtp22_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail)
+ break; /* We've got coms */
+
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
+ return ev;
+ }
+ }
+ if (++i >= 5)
+ i = 0;
+ }
+ break; /* Got coms */
+ }
+
+ if (msec_time() >= etime) { /* We haven't established comms */
+ return inst_coms_fail;
+ }
+
+ /* Set the handshaking */
+ if ((ev = dtp22_command(p, fcc, buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Change the baud rate to the rate we've been told */
+ if ((se = p->icom->write_read(p->icom, brc[bi], buf, MAX_MES_SIZE, '>', 1, .2)) != 0) {
+ if (extract_ec(buf) != DTP22_OK)
+ return inst_coms_fail;
+ }
+
+ /* Configure our baud rate and handshaking as well */
+ if ((se = p->icom->set_ser_port(p->icom, fc, brt[bi], parity_none, stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp22_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
+ }
+
+ /* Loose a character (not sure why) */
+ p->icom->write_read(p->icom, "\r", buf, MAX_MES_SIZE, '>', 1, 0.1);
+
+ /* Check instrument is responding, and reset it again. */
+ if ((ev = dtp22_command(p, "\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok
+ || (ev = dtp22_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok) {
+
+ a1logd(p->log, 1, "dtp22_init_coms: failed with ICOM 0x%x\n",ev);
+
+ p->icom->del(p->icom); /* Since caller may not clean up */
+ p->icom = NULL;
+ return inst_coms_fail;
+ }
+
+ a1logd(p->log, 2, "dtp22_init_coms: init coms has suceeded\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+/* Initialise the DTP22 */
+/* return non-zero on an error, with dtp error code */
+static inst_code
+dtp22_init_inst(inst *pp) {
+ dtp22 *p = (dtp22 *)pp;
+ char buf[MAX_MES_SIZE], *bp;
+ inst_code ev = inst_ok;
+ int i;
+
+ a1logd(p->log, 2, "dtp22_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_internal_error; /* Must establish coms before calling init */
+
+ /* Warm reset it */
+ if ((ev = dtp22_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
+ return ev;
+
+ /* Get the model and version number */
+ if ((ev = dtp22_command(p, "SV\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Check that it is a DTP22 */
+ if ( strlen(buf) < 12
+ || (strncmp(buf,"X-Rite DTP22",12) != 0))
+ return inst_unknown_model;
+
+ /* Factory reset */
+// if ((ev = dtp22_command(p, "5CRI\r", buf, MAX_MES_SIZE, 10.2)) != inst_ok)
+// return ev;
+
+ /* Turn echoing of characters off */
+ if ((ev = dtp22_command(p, "0EC\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set decimal point on */
+ if ((ev = dtp22_command(p, "0106CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set color data separator to TAB */
+ if ((ev = dtp22_command(p, "0207CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set delimeter to CR */
+ if ((ev = dtp22_command(p, "0008CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set extra digit resolution (X10) */
+ if ((ev = dtp22_command(p, "010ACF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Get some information about the instrument */
+ if ((ev = dtp22_command(p, "GI\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok) {
+ a1logd(p->log, 1, "dtp22: GI command failed with ICOM err 0x%x\n",ev);
+ return ev;
+ }
+
+ /* Extract some of these */
+ if ((bp = strstr(buf, "Serial Number:")) != NULL) {
+ bp += strlen("Serial Number:");
+ p->serno = atoi(bp);
+ } else {
+ p->serno = -1;
+ }
+ if ((bp = strstr(buf, "OEM Serial #:")) != NULL) {
+ bp += strlen("OEM Serial #:");
+ p->oemsn = atoi(bp);
+ } else {
+ p->oemsn = -1;
+ }
+ if ((bp = strstr(buf, "Cal Plaque Serial #:")) != NULL) {
+ bp += strlen("Cal Plaque Serial #:");
+ p->plaqueno = atoi(bp);
+ } else {
+ p->plaqueno = -1;
+ }
+ if (p->log->verb) {
+ int i, j;
+ for (j = i = 0; ;i++) {
+ if (buf[i] == '<' || buf[i] == '\000')
+ break;
+ if (buf[i] == '\r') {
+ buf[i] = '\000';
+ a1logv(p->log, 1, " %s\n",&buf[j]);
+ if (buf[i+1] == '\n')
+ i++;
+ j = i+1;
+ }
+ }
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Setup for the default type of measurements we want to do */
+
+ /* Disable key codes */
+ if ((ev = dtp22_command(p, "0OK\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Disable the read microswitch by default */
+ if ((ev = dtp22_command(p, "0PB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ p->trig = inst_opt_trig_user;
+
+ /* Set format to colorimetric */
+ if ((ev = dtp22_command(p, "0120CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ p->mode &= ~inst_mode_spectral;
+
+ /* Set colorimetric to XYZ */
+ if ((ev = dtp22_command(p, "0221CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Disable density */
+ if ((ev = dtp22_command(p, "0022CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Enable spectral */
+ if ((ev = dtp22_command(p, "0126CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set Illuminant to D50_2 */
+ if ((ev = dtp22_command(p, "0427CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Read the current calibration values */
+// if ((ev = dtp22_command(p, "0LC\r", buf, MAX_MES_SIZE, 10.2)) != inst_ok)
+// return ev;
+
+ /* See that we have the correct challenge/response key */
+ for (i = 0; keys[i].oemsn >= 0; i++) {
+ if (keys[i].oemsn == p->oemsn) {
+ p->key[0] = keys[i].key[0];
+ p->key[1] = keys[i].key[1];
+ p->key[2] = keys[i].key[2];
+ p->key[3] = keys[i].key[3];
+ break;
+ }
+ }
+ if (keys[i].oemsn < 0)
+ return inst_unknown_model | DTP22_UNKN_OEM;
+
+ p->inited = 1;
+ a1logd(p->log, 2, "dtp22_init_inst: instrument inited OK\n");
+
+ return inst_ok;
+}
+
+/* Read a single sample */
+/* Return the instrument error code */
+static inst_code
+dtp22_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ dtp22 *p = (dtp22 *)pp;
+ char *tp;
+ char buf[MAX_RD_SIZE];
+ char buf2[50];
+ int se;
+ inst_code ev = inst_ok;
+ int switch_trig = 0;
+ int user_trig = 0;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if ((ev = activate_mode(p)) != inst_ok)
+ return ev;
+
+ /* Signal a calibration is needed */
+ if (p->need_cal && p->noutocalib == 0) {
+ return inst_needs_cal; /* Get user to calibrate */
+ }
+
+ /* Request challenge, so that we can return the response */
+ if ((ev = dtp22_command(p, "GP\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ if (comp_password(buf2, buf, p->key))
+ return inst_internal_error | DTP22_INTERNAL_ERROR;
+
+ /* Validate the password */
+ strcat(buf2, "VD\r");
+ if ((ev = dtp22_command(p, buf2, buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ if (strncmp(buf,"PASS", 4) != 0)
+ return inst_unknown_model | DTP22_BAD_PASSWORD;
+
+ if (p->trig == inst_opt_trig_user_switch) {
+
+ /* Enable the read microswitch */
+ if ((ev = dtp22_command(p, "3PB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Wait for the microswitch to be triggered, or the user to trigger */
+ for (;;) {
+ if ((se = p->icom->read(p->icom, buf, MAX_MES_SIZE, '>', 1, 1.0)) != 0) {
+ if ((se & ICOM_TO) == 0) { /* Some sort of read error */
+ /* Disable the read microswitch */
+ dtp22_command(p, "2PB\r", buf, MAX_MES_SIZE, 0.2);
+ return dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
+ }
+ /* Timed out */
+ if (p->uicallback != NULL) { /* Check for user trigger */
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort) {
+ /* Disable the read microswitch */
+ dtp22_command(p, "2PB\r", buf, MAX_MES_SIZE, 0.2);
+ return ev; /* User abort */
+ }
+ if (ev == inst_user_trig)
+ break; /* Trigger */
+ }
+ }
+ } else { /* Inst error or switch activated */
+ if (strlen(buf) >= 4
+ && buf[0] == '<' && isdigit(buf[1]) && isdigit(buf[2]) && buf[3] == '>') {
+ if ((ev = dtp22_interp_code((inst *)p, extract_ec(buf))) != inst_ok) {
+ dtp22_command(p, "CE\r", buf, MAX_MES_SIZE, 0.5);
+ dtp22_command(p, "2PB\r", buf, MAX_MES_SIZE, 0.5);
+ return ev;
+ }
+ switch_trig = 1;
+ break; /* Measure triggered via inst switch */
+ }
+ }
+ }
+ /* Disable the read microswitch */
+ if ((ev = dtp22_command(p, "2PB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ } else if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "dtp22: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+ for (;;) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* Abort */
+ if (ev == inst_user_trig)
+ break; /* Trigger */
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return ev; /* Abort */
+ }
+
+ /* Trigger a read if the switch has not been used */
+ if (switch_trig == 0) {
+ if ((ev = dtp22_command(p, "RM\r", buf, MAX_RD_SIZE, 20.0)) != inst_ok) {
+ return ev; /* Misread */
+ }
+ }
+
+ /* Gather the results in D50_2 XYZ % reflectance */
+ if ((ev = dtp22_command(p, "0SR\r", buf, MAX_RD_SIZE, 5.0)) != inst_ok)
+ return ev; /* misread */
+
+ /* Parse the buffer */
+ /* Replace '\r' with '\000' */
+ for (tp = buf; *tp != '\000'; tp++) {
+ if (*tp == '\r')
+ *tp = '\000';
+ }
+
+ if (sscanf(buf, " X %lf Y %lf Z %lf ", &val->XYZ[0], &val->XYZ[1], &val->XYZ[2]) != 3) {
+ return inst_protocol_error;
+ }
+
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+ val->loc[0] = '\000';
+ val->mtype = inst_mrt_reflective;
+ val->XYZ_v = 1;
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (p->mode & inst_mode_spectral) {
+ int j;
+ char *fmt;
+
+ /* Reset tp to point to start of spectral */
+ tp = buf + strlen(buf) + 1;
+
+ /* Different dialects spoken by DTP-22 */
+ if (strcmp(tp, "SPECTRAL DATA") == 0 ) {
+ tp += strlen(tp) + 1;
+ fmt = " w %*lf S %lf ";
+ } else {
+ fmt = " S %lf ";
+ }
+
+ /* Read the spectral value */
+ for (j = 0; j < 31; j++) {
+ if (sscanf(tp, fmt, &val->sp.spec[j]) != 1)
+ return inst_protocol_error;
+ tp += strlen(tp) + 1;
+ }
+
+ val->sp.spec_n = 31;
+ val->sp.spec_wl_short = 400.0;
+ val->sp.spec_wl_long = 700.0;
+ val->sp.norm = 100.0;
+ }
+
+ if (user_trig)
+ return inst_user_trig;
+ return inst_ok;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code dtp22_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ dtp22 *p = (dtp22 *)pp;
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if (p->need_cal && p->noutocalib == 0)
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+/* This is use if the user decides they want to do a calibration, */
+/* in anticipation of a calibration (needs_calibration()) to avoid */
+/* requiring one during measurement, or in response to measuring */
+/* returning inst_needs_cal. Initially us an inst_cal_cond of inst_calc_none, */
+/* and then be prepared to setup the right conditions, or ask the */
+/* user to do so, each time the error inst_cal_setup is returned. */
+inst_code dtp22_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ dtp22 *p = (dtp22 *)pp;
+ char buf[MAX_RD_SIZE];
+ int se;
+ inst_code tv, ev = inst_ok;
+ inst_cal_type needed, available;
+ int swen = 0;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ id[0] = '\000';
+
+ if ((ev = dtp22_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"dtp22_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return inst_unsupported;
+ }
+
+ if (*calt & inst_calt_ref_white) { /* White calibration */
+
+ sprintf(id, "Serial no. %d",p->plaqueno);
+ if (*calc != inst_calc_man_ref_whitek) {
+ *calc = inst_calc_man_ref_whitek;
+ ev = inst_cal_setup;
+ goto do_exit;
+ }
+
+ /* Calibration only works when triggered by the read switch... */
+ if (!swen) {
+ if ((ev = dtp22_command(p, "3PB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ swen = 1;
+ }
+
+ if ((ev = activate_mode(p)) != inst_ok)
+ goto do_exit;
+
+ /* Issue white calibration */
+ if ((se = p->icom->write(p->icom, "1CA\r", 0.5)) != ICOM_OK) {
+ ev = dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
+ goto do_exit;
+ }
+
+ /* Wait for the microswitch to be triggered, or a user trigger via uicallback */
+ for (;;) {
+ if ((se = p->icom->read(p->icom, buf, MAX_MES_SIZE, '>', 1, 1.0)) != 0) {
+ if ((se & ICOM_TO) == 0) { /* Some sort of read error */
+ ev = dtp22_interp_code((inst *)p, icoms2dtp22_err(se));
+ goto do_exit;
+ }
+ /* Timed out - poll user */
+ if (p->uicallback != NULL) { /* Check for user trigger */
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ goto do_exit; /* User abort */
+ if (ev == inst_user_trig)
+ break; /* User trigger */
+ }
+ }
+ } else { /* Inst error or switch activated */
+ if (strlen(buf) >= 4
+ && buf[0] == '<' && isdigit(buf[1]) && isdigit(buf[2]) && buf[3] == '>') {
+ if ((ev = dtp22_interp_code((inst *)p, extract_ec(buf))) != inst_ok) {
+ dtp22_command(p, "CE\r", buf, MAX_MES_SIZE, 0.5);
+ if (ev != inst_ok)
+ goto do_exit; /* Error */
+ }
+ break; /* Switch trigger */
+ }
+ }
+ }
+
+ if (p->uicallback) /* Notify of trigger */
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ p->need_cal = 0;
+ *calt &= ~inst_calt_ref_white;
+
+ }
+ if (*calt & inst_calt_ref_dark) { /* Black calibration */
+
+ if (*calc != inst_calc_man_ref_dark) {
+ *calc = inst_calc_man_ref_dark;
+ ev = inst_cal_setup;
+ goto do_exit;
+ }
+
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) {
+ goto do_exit;
+ }
+
+ /* Calibration only works when triggered by the read switch... */
+ if (!swen) {
+ if ((ev = dtp22_command(p, "3PB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ swen = 1;
+ }
+
+ if ((ev = activate_mode(p)) != inst_ok)
+ goto do_exit;
+
+ /* Do black calibration */
+ if ((ev = dtp22_command(p, "1CB\r", buf, MAX_RD_SIZE, 20)) != inst_ok)
+ goto do_exit;
+
+ /* Make calibration permanent */
+ if ((ev = dtp22_command(p, "MP\r", buf, MAX_RD_SIZE, 10.0)) != inst_ok)
+ goto do_exit;
+
+ *calt &= ~inst_calt_ref_dark;
+ }
+
+ do_exit:
+
+ if (swen) {
+ /* Disable the read microswitch */
+ if ((tv = dtp22_command(p, "3PB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok && ev == inst_ok)
+ return tv;
+ swen = 0;
+ }
+
+ return ev;
+}
+
+/* Error codes interpretation */
+static char *
+dtp22_interp_error(inst *pp, int ec) {
+// dtp22 *p = (dtp22 *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case DTP22_INTERNAL_ERROR:
+ return "Internal software error";
+ case DTP22_COMS_FAIL:
+ return "Communications failure";
+ case DTP22_UNKNOWN_MODEL:
+ return "Not a DTP22 or DTP52";
+ case DTP22_DATA_PARSE_ERROR:
+ return "Data from DTP didn't parse as expected";
+ case DTP22_UNKN_OEM:
+ return "Instrument is an unknown OEM version";
+ case DTP22_BAD_PASSWORD:
+ return "Instrument password was rejected";
+
+ case DTP22_OK:
+ return "No device error";
+
+ case DTP22_BAD_COMMAND:
+ return "Unrecognized command";
+ case DTP22_PRM_RANGE:
+ return "Command parameter out of range";
+ case DTP22_MEMORY_OVERFLOW:
+ return "Memory bounds error";
+ case DTP22_INVALID_BAUD_RATE:
+ return "Invalid baud rate";
+ case DTP22_TIMEOUT:
+ return "Receive timeout";
+ case DTP22_SYNTAX_ERROR:
+ return "Badly formed parameter";
+ case DTP22_INCORRECT_DATA_FORMAT:
+ return "Incorrect Data Format";
+ case DTP22_WEAK_LAMP:
+ return "Lamp is weak";
+ case DTP22_LAMP_FAILED:
+ return "Lamp has failed";
+ case DTP22_UNSTABLE_CAL:
+ return "Unstable calibration";
+ case DTP22_CAL_GAIN_ERROR:
+ return "Error setting gains during calibration";
+ case DTP22_SENSOR_FAILURE:
+ return "Sensing cell failure";
+ case DTP22_BLACK_CAL_TOO_HIGH:
+ return "Black calibration values are too high";
+ case DTP22_UNSTABLE_BLACK_CAL:
+ return "Unstable black calibration";
+ case DTP22_CAL_MEM_ERROR:
+ return "Memory error with calibration values";
+ case DTP22_FILTER_MOTOR:
+ return "Filter motor not working";
+ case DTP22_LAMP_FAILED_READING:
+ return "Lamp failed during reading";
+ case DTP22_POWER_INTR_READING:
+ return "Power failed during reading";
+ case DTP22_SIG_OFFSETS_READING:
+ return "Signal offsets exceeded limits during reading";
+ case DTP22_RD_SWITCH_TO_SOON:
+ return "Read switch released too soon";
+ case DTP22_OVERRANGE:
+ return "Overrange reading";
+ case DTP22_FILT_POS_ERROR:
+ return "Filter position sensor error";
+ case DTP22_FACT_TST_CONNECT:
+ return "Factory test connector error";
+ case DTP22_FACT_TST_LAMP_INH:
+ return "Factory test lamp inhibit error";
+
+ case DTP22_EEPROM_FAILURE:
+ return "EEprom write failure";
+ case DTP22_PROGRAM_WRITE_FAIL:
+ return "Loading new program error";
+ case DTP22_MEMORY_WRITE_FAIL:
+ return "Memory write error";
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+dtp22_interp_code(inst *pp, int ec) {
+// dtp22 *p = (dtp22 *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case DTP22_OK:
+ return inst_ok;
+
+ case DTP22_INTERNAL_ERROR:
+ return inst_internal_error | ec;
+
+ case DTP22_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case DTP22_UNKNOWN_MODEL:
+ case DTP22_UNKN_OEM:
+ case DTP22_BAD_PASSWORD:
+ return inst_unknown_model | ec;
+
+ case DTP22_DATA_PARSE_ERROR:
+ return inst_protocol_error | ec;
+
+ case DTP22_POWER_INTR_READING:
+ case DTP22_RD_SWITCH_TO_SOON:
+ case DTP22_OVERRANGE:
+ case DTP22_SIG_OFFSETS_READING:
+ case DTP22_UNSTABLE_CAL:
+ case DTP22_UNSTABLE_BLACK_CAL:
+ case DTP22_BLACK_CAL_TOO_HIGH:
+ case DTP22_CAL_GAIN_ERROR: /* Or H/W error ? */
+ return inst_misread | ec;
+
+ case DTP22_WEAK_LAMP:
+ case DTP22_LAMP_FAILED:
+ case DTP22_SENSOR_FAILURE:
+ case DTP22_CAL_MEM_ERROR:
+ case DTP22_FILTER_MOTOR:
+ case DTP22_LAMP_FAILED_READING:
+ case DTP22_FACT_TST_CONNECT:
+ case DTP22_FACT_TST_LAMP_INH:
+ case DTP22_EEPROM_FAILURE:
+ case DTP22_PROGRAM_WRITE_FAIL:
+ case DTP22_MEMORY_WRITE_FAIL:
+ case DTP22_FILT_POS_ERROR:
+ return inst_hardware_fail | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+dtp22_del(inst *pp) {
+ dtp22 *p = (dtp22 *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ free(p);
+}
+
+/* Return the instrument capabilities */
+void dtp22_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ inst_mode cap1 = 0;
+ inst2_capability cap2 = 0;
+
+ cap1 |= inst_mode_ref_spot
+ | inst_mode_colorimeter
+ | inst_mode_spectral
+ ;
+
+ cap2 |= inst2_prog_trig
+ | inst2_user_trig
+ | inst2_user_switch_trig
+ | inst2_cal_using_switch /* DTP22 special */
+ ;
+
+ if (pcap1 != NULL)
+ *pcap1 = cap1;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Activate the last set mode */
+static inst_code
+activate_mode(dtp22 *p) {
+ static char buf[MAX_MES_SIZE];
+ inst_code rv;
+
+ if (p->mode != p->lastmode) {
+
+ if ((p->lastmode & inst_mode_spectral) == inst_mode_spectral
+ && (p->mode & inst_mode_spectral) != inst_mode_spectral) {
+
+ /* Set format to colorimetric + spectral */
+ if ((rv = dtp22_command(p, "0020CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+ }
+ if ((p->lastmode & inst_mode_spectral) != inst_mode_spectral
+ && (p->mode & inst_mode_spectral) == inst_mode_spectral) {
+
+ /* Set format to just colorimetric */
+ if ((rv = dtp22_command(p, "0120CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+ }
+ p->mode = p->lastmode;
+ }
+ return inst_ok;
+}
+
+/*
+ * check measurement mode
+ */
+static inst_code
+dtp22_check_mode(inst *pp, inst_mode m) {
+ dtp22 *p = (dtp22 *)pp;
+ inst_mode cap;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* General check mode against specific capabilities logic: */
+ if (!IMODETST(m, inst_mode_ref_spot)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * set measurement mode
+ */
+static inst_code
+dtp22_set_mode(inst *pp, inst_mode m)
+{
+ dtp22 *p = (dtp22 *)pp;
+ inst_code ev;
+
+ if ((ev = dtp22_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->lastmode = m;
+
+ return inst_ok;
+}
+
+/* !! It's not clear if there is a way of knowing */
+/* whether the instrument has a UV filter. */
+
+/*
+ * set or reset an optional mode
+ *
+ * Since there is no interaction with the instrument,
+ * was assume that all of these can be done before initialisation.
+ */
+static inst_code
+dtp22_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ dtp22 *p = (dtp22 *)pp;
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user
+ || m == inst_opt_trig_user_switch) {
+ p->trig = m;
+ return inst_ok;
+ }
+
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern dtp22 *new_dtp22(icoms *icom, instType itype) {
+ dtp22 *p;
+ if ((p = (dtp22 *)calloc(sizeof(dtp22),1)) == NULL) {
+ a1loge(icom->log, 1, "new_dtp22: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = dtp22_init_coms;
+ p->init_inst = dtp22_init_inst;
+ p->capabilities = dtp22_capabilities;
+ p->check_mode = dtp22_check_mode;
+ p->set_mode = dtp22_set_mode;
+ p->get_set_opt = dtp22_get_set_opt;
+ p->read_sample = dtp22_read_sample;
+ p->get_n_a_cals = dtp22_get_n_a_cals;
+ p->calibrate = dtp22_calibrate;
+ p->interp_error = dtp22_interp_error;
+ p->del = dtp22_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+ p->mode = inst_mode_none;
+ p->need_cal = 1; /* Do a white calibration each time we open the device */
+
+ return p;
+}
+
+/* Compute the DTP22/Digital Swatchbook password response. */
+/* Return NZ if there was an error */
+static int comp_password(char *out, char *in, unsigned char key[4]) {
+ unsigned short inv[5];
+ unsigned short outv;
+
+ in[10] = '\000';
+
+ /* Convert the 10 hex chars of input to 5 unsigned chars */
+ if (sscanf(in, "%2hx%2hx%2hx%2hx%2hx", &inv[0], &inv[1], &inv[2], &inv[3], &inv[4]) != 5)
+ return 1;
+
+ /* X-Rite magic... */
+ inv[0] ^= key[0]; /* All seen to have 2 bits set in each nibble. */
+ inv[1] ^= key[1]; /* ie. taken from set 3,5,6,9,A,C ? */
+ inv[2] ^= key[2];
+ inv[4] ^= key[3];
+ outv = ((inv[0] * 256 + inv[2]) ^ (inv[4] * 256 + inv[1])) + inv[4];
+
+ sprintf(out, "%04x", outv);
+ return 0;
+}
diff --git a/spectro/dtp22.h b/spectro/dtp22.h
new file mode 100644
index 0000000..95dce16
--- /dev/null
+++ b/spectro/dtp22.h
@@ -0,0 +1,105 @@
+#ifndef DTP22_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP22 related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/11/2006
+ *
+ * Copyright 2001 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Note: update dtp22_interp_error() and dtp22_interp_code() in dtp22.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define DTP22_INTERNAL_ERROR 0x61 /* Internal software error */
+#define DTP22_COMS_FAIL 0x62 /* Communication failure */
+#define DTP22_UNKNOWN_MODEL 0x63 /* Not a DPT22 */
+#define DTP22_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+#define DTP22_UNKN_OEM 0x69 /* Unrecognized OEM */
+#define DTP22_BAD_PASSWORD 0x6A /* Password wasn't accepted */
+
+/* Real error code */
+#define DTP22_OK 0x00
+
+#define DTP22_BAD_COMMAND 0x01
+#define DTP22_PRM_RANGE 0x02
+#define DTP22_MEMORY_OVERFLOW 0x04
+#define DTP22_INVALID_BAUD_RATE 0x05
+#define DTP22_TIMEOUT 0x07
+#define DTP22_SYNTAX_ERROR 0x08
+#define DTP22_INCORRECT_DATA_FORMAT 0x09
+#define DTP22_WEAK_LAMP 0x10
+#define DTP22_LAMP_FAILED 0x11
+#define DTP22_UNSTABLE_CAL 0x12
+#define DTP22_CAL_GAIN_ERROR 0x13
+#define DTP22_SENSOR_FAILURE 0x14
+#define DTP22_BLACK_CAL_TOO_HIGH 0x15
+#define DTP22_UNSTABLE_BLACK_CAL 0x16
+#define DTP22_CAL_MEM_ERROR 0x17
+#define DTP22_FILTER_MOTOR 0x21
+#define DTP22_LAMP_FAILED_READING 0x22
+#define DTP22_POWER_INTR_READING 0x23
+#define DTP22_SIG_OFFSETS_READING 0x24
+#define DTP22_RD_SWITCH_TO_SOON 0x25
+#define DTP22_OVERRANGE 0x26
+#define DTP22_FILT_POS_ERROR 0x28
+#define DTP22_FACT_TST_CONNECT 0x2A
+#define DTP22_FACT_TST_LAMP_INH 0x2B
+
+
+#define DTP22_EEPROM_FAILURE 0x70
+#define DTP22_PROGRAM_WRITE_FAIL 0x71
+#define DTP22_MEMORY_WRITE_FAIL 0x72
+
+/* DTP22 communication object */
+struct _dtp22 {
+ INST_OBJ_BASE
+
+ /* *** DTP41 private data **** */
+ unsigned char key[4]; /* Challenge/response key */
+ int keyvalid; /* nz if key is valid */
+ int serno; /* Serial number of instrument */
+ int oemsn; /* Serial number of OEM */
+ int plaqueno; /* Serial number of calibration plaque */
+ inst_mode mode; /* Currently instrument mode */
+ inst_mode lastmode; /* Last requested mode */
+ int need_cal; /* White calibration needed flag */
+ int noutocalib; /* Don't mode change or auto calibrate */
+ inst_opt_type trig; /* Reading trigger mode */
+
+ }; typedef struct _dtp22 dtp22;
+
+/* Constructor */
+extern dtp22 *new_dtp22(icoms *icom, instType itype);
+
+
+#define DTP22_H
+#endif /* DTP22_H */
diff --git a/spectro/dtp41.c b/spectro/dtp41.c
new file mode 100644
index 0000000..4487124
--- /dev/null
+++ b/spectro/dtp41.c
@@ -0,0 +1,1292 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP41 related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 10/3/2001
+ *
+ * Copyright 1996 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from DTP51.c
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* !SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* !SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "dtp41.h"
+
+/* Default flow control */
+#define DEFFC fc_XonXOff
+
+static inst_code dtp41_interp_code(inst *pp, int ec);
+static inst_code activate_mode(dtp41 *p);
+
+#define MAX_MES_SIZE 1000 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 100000 /* Maximum reading messagle reply size */
+
+/* Extract an error code from a reply string */
+/* Return -1 if no error code can be found */
+static int
+extract_ec(char *s) {
+ char *p;
+ char tt[3];
+ int rv;
+ p = s + strlen(s);
+ /* Find the trailing '>' */
+ for (p--; p >= s;p--) {
+ if (*p == '>')
+ break;
+ }
+ if ( (p-3) < s
+ || p[0] != '>'
+ || p[-3] != '<')
+ return -1;
+ tt[0] = p[-2];
+ tt[1] = p[-1];
+ tt[2] = '\000';
+ if (sscanf(tt,"%x",&rv) != 1)
+ return -1;
+ rv &= 0x7f;
+ return rv;
+}
+
+/* Interpret an icoms error into a DTP41 error */
+static int icoms2dtp41_err(int se) {
+ if (se != ICOM_OK) {
+ if (se & ICOM_TO)
+ return DTP41_TIMEOUT;
+ return DTP41_COMS_FAIL;
+ }
+ return DTP41_OK;
+}
+
+/* Do a full featured command/response echange with the dtp41 */
+/* End on the specified number of characters, or expiry if */
+/* the specified timeout. */
+/* Assume standard error code if tc = '>' and ntc = 1 */
+/* Return a DTP41 error code */
+static int
+dtp41_fcommand(
+dtp41 *p,
+char *in, /* In string */
+char *out, /* Out string buffer */
+int bsize, /* Out buffer size */
+char tc, /* Terminating character */
+int ntc, /* Number of terminating characters */
+double to) { /* Timout in seconts */
+ int rv, se;
+
+ if ((se = p->icom->write_read(p->icom, in, out, bsize, tc, ntc, to)) != 0) {
+ a1logd(p->log, 1, "dtp41_fcommand: serial i/o failure 0x%x on write_read '%s'\n",se,icoms_fix(in));
+ return icoms2dtp41_err(se);
+ }
+ rv = DTP41_OK;
+ if (tc == '>' && ntc == 1) {
+ rv = extract_ec(out);
+ if (rv > 0) {
+ rv &= inst_imask;
+ if (rv != DTP41_OK) { /* Clear the error */
+ char buf[MAX_MES_SIZE];
+ p->icom->write_read(p->icom, "CE\r", buf, MAX_MES_SIZE, '>', 1, 0.5);
+ }
+ }
+ }
+ a1logd(p->log, 4, "dtp41_fcommand: command '%s' returned '%s', value 0x%x\n",
+ icoms_fix(in), icoms_fix(out),rv);
+ return rv;
+}
+
+/* Do a standard command/response echange with the dtp41 */
+/* Return the instrument error code */
+static inst_code
+dtp41_command(dtp41 *p, char *in, char *out, int bsize, double to) {
+ int rv = dtp41_fcommand(p, in, out, bsize, '>', 1, to);
+ return dtp41_interp_code((inst *)p, rv);
+}
+
+/* Establish communications with a DTP41 */
+/* Use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+dtp41_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ dtp41 *p = (dtp41 *)pp;
+ static char buf[MAX_MES_SIZE];
+ baud_rate brt[9] = { baud_9600, baud_19200, baud_38400, baud_57600,
+ baud_4800, baud_2400, baud_1200, baud_600, baud_300 };
+ char *brc[9] = { "9600BR\r", "19200BR\r", "38400BR\r", "57600BR\r",
+ "4800BR\r", "2400BR\r", "1200BR\r", "600BR\r", "300BR\r" };
+ char *fcc;
+ unsigned int etime;
+ int ci, bi, i, se;
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "dtp41_init_coms: About to init Serial I/O\n");
+
+ /* Deal with flow control setting */
+ if (fc == fc_nc)
+ fc = DEFFC;
+ if (fc == fc_XonXOff) {
+ fcc = "0304CF\r";
+ } else if (fc == fc_Hardware) {
+ fcc = "0104CF\r";
+ } else {
+ fc = fc_none;
+ fcc = "0004CF\r";
+ }
+
+ /* Figure DTP41 baud rate being asked for */
+ for (bi = 0; bi < 9; bi++) {
+ if (brt[bi] == br)
+ break;
+ }
+ if (bi >= 9)
+ bi = 0;
+
+ /* Figure current icoms baud rate */
+ for (ci = 0; ci < 9; ci++) {
+ if (brt[ci] == p->icom->br)
+ break;
+ }
+ if (ci >= 9)
+ ci = bi;
+
+ /* The tick to give up on */
+ etime = msec_time() + (long)(1000.0 * tout + 0.5);
+
+ while (msec_time() < etime) {
+
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp41_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp41_interp_code((inst *)p, icoms2dtp41_err(se));
+ }
+ if (((ev = dtp41_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail)
+ break; /* We've got coms */
+
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "dtp41_init_coms: user aborted\n");
+ return inst_user_abort;
+ }
+ }
+ if (++i >= 9)
+ i = 0;
+ }
+ break; /* Got coms */
+ }
+
+ if (msec_time() >= etime) { /* We haven't established comms */
+ return inst_coms_fail;
+ }
+
+ /* set the protocol to RCI */
+ if ((ev = dtp41_command(p, "0012CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set the handshaking (cope with coms breakdown) */
+ if ((se = p->icom->write_read(p->icom, fcc, buf, MAX_MES_SIZE, '>', 1, 1.5)) != 0) {
+ if (extract_ec(buf) != DTP41_OK)
+ return inst_coms_fail;
+ }
+
+ /* Change the baud rate to the rate we've been told (cope with coms breakdown) */
+ if ((se = p->icom->write_read(p->icom, brc[bi], buf, MAX_MES_SIZE, '>', 1, 1.5)) != 0) {
+ if (extract_ec(buf) != DTP41_OK)
+ return inst_coms_fail;
+ }
+
+ /* Configure our baud rate and handshaking as well */
+ if ((se = p->icom->set_ser_port(p->icom, fc, brt[bi], parity_none, stop_1, length_8))
+ != ICOM_OK) {
+ a1logd(p->log, 1, "dtp41_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp41_interp_code((inst *)p, icoms2dtp41_err(se));
+ }
+
+ /* Loose a character (not sure why) */
+ p->icom->write_read(p->icom, "\r", buf, MAX_MES_SIZE, '>', 1, 0.5);
+
+ /* Check instrument is responding */
+ if ((ev = dtp41_command(p, "\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok) {
+ a1logd(p->log, 1, "dtp41_init_coms: instrument failed to respond\n");
+ return inst_coms_fail;
+ }
+
+ a1logd(p->log, 2, "dtp41_init_coms: init coms has suceeded\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+/* Build a strip definition as a set of passes, including DS command */
+static void
+build_strip(
+dtp41 *p,
+char *tp, /* pointer to string buffer */
+char *name, /* Strip name (7 chars) (not used) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (3 chars) (not used) */
+int sguide, /* Guide number (not used) */
+double pwid, /* Patch length in mm */
+double gwid, /* Gap length in mm */
+double twid /* Trailer length in mm (DTP41T only) */
+) {
+
+ /* Number of patches in strip */
+ sprintf(tp, "%03d",npatch);
+ tp += 3;
+
+ /* Patch width in mm, dd.dd */
+ sprintf(tp, "%05.2f",pwid);
+ tp[2] = tp[3]; /* Remove point */
+ tp[3] = tp[4];
+ tp += 4;
+
+ /* Gap width in mm, dd.dd */
+ sprintf(tp, "%05.2f",gwid);
+ tp[2] = tp[3]; /* Remove point */
+ tp[3] = tp[4];
+ tp += 4;
+
+ *tp++ = '0'; /* Normal strip */
+
+ *tp++ = '8'; /* Auto type */
+
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+
+ if (twid >= 9999.5) {
+ a1logw(p->log, "DTP41 build_strip given trailer length %f > 9999 mm\n",twid);
+ twid = 9999.0;
+ }
+ /* Trailer length in mm, dddd */
+ sprintf(tp, "%04.0f",twid);
+ tp += 4;
+ }
+
+ *tp++ = 'D'; /* The DS command */
+ *tp++ = 'S';
+ *tp++ = '\r'; /* The CR */
+ *tp++ = '\000'; /* The end */
+
+}
+
+/* Initialise the DTP41. */
+/* return non-zero on an error, with instrument error code */
+static inst_code
+dtp41_init_inst(inst *pp) {
+ dtp41 *p = (dtp41 *)pp;
+ static char tbuf[100], buf[MAX_MES_SIZE];
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "dtp41_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_internal_error; /* Must establish coms before calling init */
+
+ /* Resetting instrument resets the baud rate, so do manual reset. */
+
+ /* Set emulation mode to DTP41 */
+ if ((ev = dtp41_command(p, "0010CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Turn echoing of characters off */
+ if ((ev = dtp41_command(p, "0009CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Response delimeter to CR */
+ if ((ev = dtp41_command(p, "0008CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Get the model and version number */
+ if ((ev = dtp41_command(p, "SV\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Check that it is a DTP41 */
+ if ( strlen(buf) < 12
+ || strncmp(buf,"X-Rite DTP41",11) != 0
+ || (buf[11] != '1' && buf[11] != '2'))
+ return inst_unknown_model;
+
+ /* Set Language to English */
+ if ((ev = dtp41_command(p, "0000CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Beeper to medium */
+ if ((ev = dtp41_command(p, "0201CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Automatic Transmit off */
+ if ((ev = dtp41_command(p, "0005CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set decimal point on */
+ if ((ev = dtp41_command(p, "0106CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set color data separator to TAB */
+ if ((ev = dtp41_command(p, "0207CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set 2 decimal digit resolution */
+ if ((ev = dtp41_command(p, "020ACF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Min/Max mode off */
+ if ((ev = dtp41_command(p, "000CCF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set persistent errors off */
+ if ((ev = dtp41_command(p, "000DCF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set show data labels mode off */
+ if ((ev = dtp41_command(p, "000FCF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set drive motor calibration at power up to off */
+ if ((ev = dtp41_command(p, "0011CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Reflection calibration timeout to 24 Hrs */
+ if ((ev = dtp41_command(p, "181ECF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Trailer timout to 2 seconds */
+ if ((ev = dtp41_command(p, "021FCF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Transmission calibration timeout to 24 Hrs */
+ if ((ev = dtp41_command(p, "1820CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok) {
+ /* This may fail if the firmware version is < v8212 */
+ if ((ev & inst_imask) != DTP41_PRM_RANGE_ERROR)
+ return ev;
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Setup for the type of measurements we want to do */
+ /* Enable the read microswitch */
+ if ((ev = dtp41_command(p, "01PB\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+ p->trig = inst_opt_trig_user_switch;
+
+ /* Set dynamic measurement mode */
+ if ((ev = dtp41_command(p, "0113CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set instrument to reflectance mode */
+ if ((ev = dtp41_command(p, "0019CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set data format to Reflectance, so TS can select. */
+ if ((ev = dtp41_command(p, "0318CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set density format to spectral */
+ if ((ev = dtp41_command(p, "0417CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Illuminant to D50_2 */
+ if ((ev = dtp41_command(p, "0416CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set static samples to 10 */
+ if ((ev = dtp41_command(p, "0A14CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set static readings to configured number (usually 5) */
+ sprintf(tbuf, "%02x15CF\r", p->nstaticr);
+ if ((ev = dtp41_command(p, tbuf, buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+#ifdef NEVER
+ /* See what the transmission mode is up to */
+ dtp41_command(p, "DEVELOPERPW\r", buf, MAX_MES_SIZE, 1.5);
+ dtp41_command(p, "0119CF\r", buf, MAX_MES_SIZE, 1.5);
+ dtp41_command(p, "36OD\r", buf, MAX_MES_SIZE, 1.5);
+ dtp41_command(p, "1422OD\r", buf, MAX_MES_SIZE, 1.5);
+#endif
+
+ /* We are configured in this mode now */
+ p->mode = inst_mode_ref_strip;
+
+ if (p->lastmode != p->mode) {
+ if ((ev = activate_mode(p)) != inst_ok)
+ return ev;
+ }
+
+ p->inited = 1;
+
+ a1logd(p->log, 2, "dtp41_init_inst: instrument inited OK\n");
+
+ return inst_ok;
+}
+
+/* Read a set of strips */
+/* Return the instrument error code */
+static inst_code
+dtp41_read_strip(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (3 chars) */
+int sguide, /* Guide number */
+double pwid, /* Patch length in mm (For DTP41) */
+double gwid, /* Gap length in mm (For DTP41) */
+double twid, /* Trailer length in mm (For DTP41T) */
+ipatch *vals) { /* Pointer to array of instrument patch values */
+ dtp41 *p = (dtp41 *)pp;
+ char tbuf[200], *tp;
+ static char buf[MAX_RD_SIZE];
+ int i, se;
+ inst_code ev = inst_ok;
+ int switch_trig = 0;
+ int user_trig = 0;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Configure for dynamic mode */
+ p->lastmode = (p->lastmode & ~inst_mode_sub_mask) | inst_mode_strip;
+ activate_mode(p);
+
+ build_strip(p, tbuf, name, npatch, pname, sguide, pwid, gwid, twid);
+
+ /* Send strip definition */
+ if ((ev = dtp41_command(p, tbuf, buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ if (p->trig == inst_opt_trig_user_switch) {
+
+ /* Wait for the Read status, or a user trigger/abort */
+ for (;;) {
+ if ((ev = dtp41_command(p, "", buf, MAX_MES_SIZE, 0.5)) != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+
+ if ((ev & inst_imask) != DTP41_TIMEOUT)
+ return ev; /* Instrument or comms error */
+
+ /* Timed out */
+ if (p->uicallback != NULL) { /* Check for user trigger */
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* User abort */
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break;
+ }
+ }
+ }
+
+ } else { /* Got read status - assume triggered */
+ switch_trig = 1;
+ break; /* Switch activated */
+ }
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ } else if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "dtp41: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* Abort */
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return ev; /* Abort */
+ }
+
+ /* Trigger a read if the switch has not been used */
+ if (switch_trig == 0) {
+ /* Do a strip read */
+ if ((ev = dtp41_command(p, "RM\r", buf, MAX_MES_SIZE, 30.0)) != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+ return ev;
+ }
+ }
+
+ /* Gather the results in D50_2 XYZ */
+ if ((ev = dtp41_command(p, "0405TS\r", buf, MAX_RD_SIZE, 0.5 + npatch * 0.1)) != inst_ok)
+ return ev; /* Strip misread */
+
+ /* Parse the buffer */
+ /* Replace '\r' with '\000' */
+ for (tp = buf; *tp != '\000'; tp++) {
+ if (*tp == '\r')
+ *tp = '\000';
+ }
+ for (tp = buf, i = 0; i < npatch; i++) {
+ if (*tp == '\000')
+ return inst_protocol_error;
+ if (sscanf(tp, " %lf %lf %lf ",
+ &vals[i].XYZ[0], &vals[i].XYZ[1], &vals[i].XYZ[2]) != 3) {
+ if (sscanf(tp, " %lf %lf %lf ",
+ &vals[i].XYZ[0], &vals[i].XYZ[1], &vals[i].XYZ[2]) != 3) {
+ return inst_protocol_error;
+ }
+ }
+ vals[i].loc[0] = '\000';
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission)
+ vals[i].mtype = inst_mrt_transmissive;
+ else
+ vals[i].mtype = inst_mrt_reflective;
+ vals[i].XYZ_v = 1;
+ vals[i].sp.spec_n = 0;
+ vals[i].duration = 0.0;
+ tp += strlen(tp) + 1;
+ }
+
+ if (p->mode & inst_mode_spectral) {
+
+ /* Gather the results in Spectral reflectance */
+ if ((ev = dtp41_command(p, "0403TS\r", buf, MAX_RD_SIZE, 0.5 + npatch * 0.1)) != inst_ok)
+ return ev; /* Strip misread */
+
+ /* Parse the buffer */
+ /* Replace '\r' with '\000' */
+ for (tp = buf; *tp != '\000'; tp++) {
+ if (*tp == '\r')
+ *tp = '\000';
+ }
+ /* Get each patches spetra */
+ for (tp = buf, i = 0; i < npatch; i++) {
+ int j;
+ char *tpp;
+ if (strlen(tp) < (31 * 8 - 1)) {
+ return inst_protocol_error;
+ }
+
+ /* Read the spectral value */
+ for (tpp = tp, j = 0; j < 31; j++, tpp += 8) {
+ char c;
+ c = tpp[7];
+ tpp[7] = '\000';
+ vals[i].sp.spec[j] = atof(tpp);
+ tpp[7] = c;
+ }
+
+ vals[i].sp.spec_n = 31;
+ vals[i].sp.spec_wl_short = 400.0;
+ vals[i].sp.spec_wl_long = 700.0;
+ vals[i].sp.norm = 100.0;
+ tp += strlen(tp) + 1;
+ }
+ }
+ if (user_trig)
+ return inst_user_trig;
+ return inst_ok;
+}
+
+/* Read a single sample */
+/* Return the instrument error code */
+static inst_code
+dtp41_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ dtp41 *p = (dtp41 *)pp;
+ char *tp;
+ static char buf[MAX_RD_SIZE];
+ int i, se;
+ inst_code ev = inst_ok;
+ int switch_trig = 0;
+ int user_trig = 0;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Configure for static mode */
+ p->lastmode = (p->lastmode & ~inst_mode_sub_mask) | inst_mode_spot;
+ activate_mode(p);
+
+ /* Set static measurement mode */
+ if ((ev = dtp41_command(p, "0013CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ if (p->trig == inst_opt_trig_user_switch) {
+
+ /* Wait for the Read status, or a user trigger/abort */
+ for (;;) {
+ if ((ev = dtp41_command(p, "", buf, MAX_MES_SIZE, 0.5)) != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+
+ if ((ev & inst_imask) != DTP41_TIMEOUT)
+ return ev; /* Instrument or comms error */
+
+ /* Timed out */
+ if (p->uicallback != NULL) { /* Check for user trigger */
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* User abort */
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break; /* User trigger */
+ }
+ }
+ }
+
+ } else { /* Assume read status and trigger */
+ switch_trig = 1;
+ break; /* Switch activated */
+ }
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ } else if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "dtp41: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* Abort */
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return ev; /* Abort */
+ }
+
+ /* Trigger a read if the switch has not been used */
+ if (switch_trig == 0) {
+ /* Do a read */
+ if ((ev = dtp41_command(p, "RM\r", buf, MAX_MES_SIZE, 20.0)) != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+ return ev;
+ }
+ }
+
+ /* Gather the results in D50_2 XYZ */
+ if ((ev = dtp41_command(p, "0405TS\r", buf, MAX_RD_SIZE, 0.5)) != inst_ok)
+ return ev; /* Strip misread */
+
+ /* Parse the buffer */
+ /* Replace '\r' with '\000' */
+ for (tp = buf; *tp != '\000'; tp++) {
+ if (*tp == '\r')
+ *tp = '\000';
+ }
+
+ val->XYZ[0] = val->XYZ[1] = val->XYZ[2] = 0.0;
+
+ /* for all the readings taken */
+ for (tp = buf, i = 0; i < p->nstaticr; i++) {
+ double XYZ[3];
+
+ if (*tp == '\000')
+ return inst_protocol_error;
+
+ if (sscanf(tp, " %lf %lf %lf ", &XYZ[0], &XYZ[1], &XYZ[2]) != 3) {
+ return inst_protocol_error;
+ }
+ val->XYZ[0] += XYZ[0];
+ val->XYZ[1] += XYZ[1];
+ val->XYZ[2] += XYZ[2];
+ tp += strlen(tp) + 1;
+ }
+
+ /* Average */
+ val->XYZ[0] /= (double)p->nstaticr;
+ val->XYZ[1] /= (double)p->nstaticr;
+ val->XYZ[2] /= (double)p->nstaticr;
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+ val->loc[0] = '\000';
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission)
+ val->mtype = inst_mrt_transmissive;
+ else
+ val->mtype = inst_mrt_reflective;
+ val->XYZ_v = 1;
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (p->mode & inst_mode_spectral) {
+ int j;
+
+ /* Gather the results in Spectral reflectance */
+ if ((ev = dtp41_command(p, "0403TS\r", buf, MAX_RD_SIZE, 0.5)) != DTP41_OK)
+ return ev; /* Strip misread */
+
+ /* Parse the buffer */
+ /* Replace '\r' with '\000' */
+ for (tp = buf; *tp != '\000'; tp++) {
+ if (*tp == '\r')
+ *tp = '\000';
+ }
+
+ for (j = 0; j < 31; j++)
+ val->sp.spec[j] = 0.0;
+
+ /* Get each readings spetra */
+ for (tp = buf, i = 0; i < p->nstaticr; i++) {
+ char *tpp;
+ if (strlen(tp) < (31 * 8 - 1)) {
+ return inst_protocol_error;
+ }
+
+ /* Read the spectral value */
+ for (tpp = tp, j = 0; j < 31; j++, tpp += 8) {
+ char c;
+ c = tpp[7];
+ tpp[7] = '\000';
+ val->sp.spec[j] += atof(tpp);
+ tpp[7] = c;
+ }
+
+ tp += strlen(tp) + 1;
+ }
+
+ /* Average the result */
+ for (j = 0; j < 31; j++)
+ val->sp.spec[j] /= (double)p->nstaticr;
+
+ val->sp.spec_n = 31;
+ val->sp.spec_wl_short = 400.0;
+ val->sp.spec_wl_long = 700.0;
+ val->sp.norm = 100.0;
+ }
+
+ /* Set back to dynamic measurement mode */
+ if ((ev = dtp41_command(p, "0113CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ if (user_trig)
+ return inst_user_trig;
+ return inst_ok;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code dtp41_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ dtp41 *p = (dtp41 *)pp;
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ if (p->need_cal)
+ n_cals |= inst_calt_trans_white; /* ??? */
+ a_cals |= inst_calt_trans_white;
+ } else {
+ if (p->need_cal)
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+ }
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+/* This is use if the user decides they want to do a calibration, */
+/* in anticipation of a calibration (needs_calibration()) to avoid */
+/* requiring one during measurement, or in response to measuring */
+/* returning inst_needs_cal. Initially us an inst_cal_cond of inst_calc_none, */
+/* and then be prepared to setup the right conditions, or ask the */
+/* user to do so, each time the error inst_cal_setup is returned. */
+inst_code dtp41_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ dtp41 *p = (dtp41 *)pp;
+ inst_code ev;
+ inst_cal_type needed, available;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ id[0] = '\000';
+
+ if ((ev = dtp41_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"dtp41_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return inst_unsupported;
+ }
+
+
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ if (*calt & inst_calt_trans_white) {
+
+ if (*calc != inst_calc_uop_trans_white)
+ *calc = inst_calc_uop_trans_white; /* Ask user to do calibration */
+ return inst_cal_setup;
+ }
+
+ p->need_cal = 0;
+ *calt &= ~inst_calt_trans_white;
+
+ } else {
+ if (*calt & inst_calt_ref_white) {
+
+ if (*calc != inst_calc_uop_ref_white) {
+ *calc = inst_calc_uop_ref_white; /* Ask user to do calibration */
+ return inst_cal_setup;
+ }
+
+ p->need_cal = 0;
+ *calt &= ~inst_calt_ref_white;
+ }
+ }
+
+ return inst_ok; /* Calibration done */
+}
+
+/* Error codes interpretation */
+static char *
+dtp41_interp_error(inst *pp, int ec) {
+// dtp41 *p = (dtp41 *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+
+ case DTP41_INTERNAL_ERROR:
+ return "Internal software error";
+ case DTP41_COMS_FAIL:
+ return "Communications failure";
+ case DTP41_UNKNOWN_MODEL:
+ return "Not a DTP41";
+ case DTP41_DATA_PARSE_ERROR:
+ return "Data from DTP41 didn't parse as expected";
+ case DTP41_OK:
+ return "No device error";
+ case DTP41_MEASUREMENT_STATUS:
+ return "Measurement complete";
+ case DTP41_CALIBRATION_STATUS:
+ return "Calibration complete";
+ case DTP41_KEYPRESS_STATUS:
+ return "A key was pressed";
+ case DTP41_DEFAULTS_LOADED_STATUS:
+ return "Default configuration values have been loaded";
+ case DTP41_BAD_COMMAND:
+ return "Unrecognised command";
+ case DTP41_BAD_PARAMETERS:
+ return "Wrong number of parameters";
+ case DTP41_PRM_RANGE_ERROR:
+ return "One or more parameters are out of range";
+ case DTP41_BUSY:
+ return "Instrument is busy - command ignored";
+ case DTP41_MEASUREMENT_ERROR:
+ return "General measurement error";
+ case DTP41_TIMEOUT:
+ return "Receive timeout";
+ case DTP41_BAD_STRIP:
+ return "Bad strip";
+ case DTP41_BAD_COLOR:
+ return "Bad color";
+ case DTP41_BAD_STEP:
+ return "Bad step";
+ case DTP41_BAD_PASS:
+ return "Bad pass";
+ case DTP41_BAD_PATCHES:
+ return "Bad patches";
+ case DTP41_BAD_READING:
+ return "Bad reading";
+ case DTP41_NEEDS_CAL_ERROR:
+ return "Instrument needs calibration";
+ case DTP41_CAL_FAILURE_ERROR:
+ return "Calibration failed";
+ case DTP41_INSTRUMENT_ERROR:
+ return "General instrument error";
+ case DTP41_LAMP_ERROR:
+ return "Reflectance lamp error";
+ case DTP41_FILTER_ERROR:
+ return "Filter error";
+ case DTP41_FILTER_MOTOR_ERROR:
+ return "Filter motor error";
+ case DTP41_DRIVE_MOTOR_ERROR:
+ return "Strip drive motor error";
+ case DTP41_KEYPAD_ERROR:
+ return "Keypad error";
+ case DTP41_DISPLAY_ERROR:
+ return "Display error";
+ case DTP41_MEMORY_ERROR:
+ return "Memory error";
+ case DTP41_ADC_ERROR:
+ return "ADC error";
+ case DTP41_PROCESSOR_ERROR:
+ return "Processor error";
+ case DTP41_BATTERY_ERROR:
+ return "Battery error";
+ case DTP41_BATTERY_LOW_ERROR:
+ return "Battery low error";
+ case DTP41_INPUT_POWER_ERROR:
+ return "Input power error";
+ case DTP41_TEMPERATURE_ERROR:
+ return "Temperature error";
+ case DTP41_BATTERY_ABSENT_ERROR:
+ return "Battery absent error";
+ case DTP41_TRAN_LAMP_ERROR:
+ return "Transmission lamp error";
+ case DTP41_INVALID_COMMAND_ERROR:
+ return "Invalid command";
+ default:
+ return "Unknown error code";
+ }
+}
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+dtp41_interp_code(inst *pp, int ec) {
+// dtp41 *p = (dtp41 *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case DTP41_OK:
+ return inst_ok;
+
+ case DTP41_INTERNAL_ERROR:
+ return inst_internal_error | ec;
+
+ case DTP41_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case DTP41_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+ case DTP41_DATA_PARSE_ERROR:
+ return inst_protocol_error | ec;
+
+ case DTP41_BUSY:
+ case DTP41_TIMEOUT:
+ case DTP41_BAD_READING:
+ case DTP41_INSTRUMENT_ERROR:
+ case DTP41_DRIVE_MOTOR_ERROR:
+ case DTP41_ADC_ERROR:
+ case DTP41_TRAN_LAMP_ERROR:
+ return inst_misread | ec;
+
+ case DTP41_NEEDS_CAL_ERROR:
+ return inst_needs_cal | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+dtp41_del(inst *pp) {
+ dtp41 *p = (dtp41 *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ free (p);
+}
+
+/* Interogate the device to discover its capabilities */
+/* If we haven't initilalised the instrument, we don't */
+/* know if it supports transparency. */
+static void discover_capabilities(dtp41 *p) {
+ static char buf[MAX_MES_SIZE];
+ inst_code rv = inst_ok;
+
+ p->cap = inst_mode_ref_spot
+ | inst_mode_ref_strip
+ | inst_mode_colorimeter
+ | inst_mode_spectral
+ ;
+
+ p->cap2 = inst2_prog_trig
+ | inst2_user_trig
+ | inst2_user_switch_trig
+ ;
+
+ p->cap3 = inst3_none;
+
+ if (p->inited) {
+ /* Check whether we have transmission capability */
+ if ((rv = dtp41_command(p, "0119CF\r", buf, MAX_MES_SIZE, 1.5)) == inst_ok) {
+ p->cap |= inst_mode_trans_spot
+ | inst_mode_trans_strip
+ ;
+ }
+ /* Set back to reflectance mode */
+ rv = dtp41_command(p, "0019CF\r", buf, MAX_MES_SIZE, 1.5);
+ }
+}
+
+/* Return the instrument capabilities */
+void dtp41_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ dtp41 *p = (dtp41 *)pp;
+
+ if (p->cap == inst_mode_none)
+ discover_capabilities(p);
+
+ if (pcap1 != NULL)
+ *pcap1 = p->cap;
+ if (pcap2 != NULL)
+ *pcap2 = p->cap2;
+ if (pcap3 != NULL)
+ *pcap3 = p->cap3;
+}
+
+/* Activate the last set mode */
+static inst_code
+activate_mode(dtp41 *p)
+{
+ static char buf[MAX_MES_SIZE];
+ inst_code rv;
+
+ /* Setup for transmission or reflection */
+ if ((p->lastmode & inst_mode_illum_mask) == inst_mode_reflection
+ && (p->mode & inst_mode_illum_mask) != inst_mode_reflection) {
+ if ((rv = dtp41_command(p, "0019CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return rv;
+ }
+ if ((p->lastmode & inst_mode_illum_mask) == inst_mode_transmission
+ && (p->mode & inst_mode_illum_mask) != inst_mode_transmission) {
+ if ((rv = dtp41_command(p, "0119CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return rv;
+ }
+
+ /* Setup for static or dynamic reading */
+ if ((p->lastmode & inst_mode_sub_mask) == inst_mode_spot
+ && (p->mode & inst_mode_sub_mask) != inst_mode_spot) {
+ if ((rv = dtp41_command(p, "0013CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return rv;
+ }
+ if ((p->lastmode & inst_mode_sub_mask) == inst_mode_strip
+ && (p->mode & inst_mode_sub_mask) != inst_mode_strip) {
+ if ((rv = dtp41_command(p, "0113CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return rv;
+ }
+
+ p->mode = p->lastmode;
+
+ return inst_ok;
+}
+
+/*
+ * check measurement mode
+ * We assume that the instrument has been initialised.
+ */
+static inst_code
+dtp41_check_mode(inst *pp, inst_mode m) {
+ dtp41 *p = (dtp41 *)pp;
+ inst_mode cap;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ if (m & ~cap) /* Simple elimination test */
+ return inst_unsupported;
+
+ /* Check specific modes */
+ if (!IMODETST(m, inst_mode_ref_spot)
+ && !IMODETST(m, inst_mode_ref_strip)
+ && !IMODETST2(cap, m, inst_mode_trans_spot)
+ && !IMODETST2(cap, m, inst_mode_trans_strip)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * set measurement mode
+ * We assume that the instrument has been initialised.
+ */
+static inst_code
+dtp41_set_mode(inst *pp, inst_mode m) {
+ dtp41 *p = (dtp41 *)pp;
+ inst_code ev;
+
+ if ((ev = dtp41_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->lastmode = m;
+ if (p->lastmode != p->mode) {
+ return activate_mode(p);
+ }
+
+ return inst_ok;
+}
+
+/* !! It's not clear if there is a way of knowing */
+/* whether the instrument has a UV filter. */
+
+/*
+ * set or reset an optional mode
+ *
+ * Some options talk to the instrument, and these will
+ * error if it hasn't been initialised.
+ */
+static inst_code
+dtp41_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ dtp41 *p = (dtp41 *)pp;
+ inst_code rv = inst_ok;
+ static char buf[MAX_MES_SIZE];
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Set the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user
+ || m == inst_opt_trig_user_switch) {
+ p->trig = m;
+
+ if (m == inst_opt_trig_user_switch) {
+ /* Enable the read microswitch */
+ if ((rv = dtp41_command(p, "01PB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+ } else {
+ /* Disable the read microswitch */
+ if ((rv = dtp41_command(p, "00PB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+ }
+ return inst_ok;
+ }
+
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern dtp41 *new_dtp41(icoms *icom, instType itype) {
+ dtp41 *p;
+ if ((p = (dtp41 *)calloc(sizeof(dtp41),1)) == NULL) {
+ a1loge(icom->log, 1, "new_dtp41: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log(icom->log, 0, 0, NULL, NULL, NULL, NULL);
+
+ p->init_coms = dtp41_init_coms;
+ p->init_inst = dtp41_init_inst;
+ p->capabilities = dtp41_capabilities;
+ p->check_mode = dtp41_check_mode;
+ p->set_mode = dtp41_set_mode;
+ p->get_set_opt = dtp41_get_set_opt;
+ p->read_strip = dtp41_read_strip;
+ p->read_sample = dtp41_read_sample;
+ p->get_n_a_cals = dtp41_get_n_a_cals;
+ p->calibrate = dtp41_calibrate;
+ p->interp_error = dtp41_interp_error;
+ p->del = dtp41_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+ p->cap = inst_mode_none; /* Unknown until set */
+ p->mode = inst_mode_none; /* Not in a known mode yet */
+ p->nstaticr = 5; /* Number of static readings */
+
+ return p;
+}
diff --git a/spectro/dtp41.h b/spectro/dtp41.h
new file mode 100644
index 0000000..529f94c
--- /dev/null
+++ b/spectro/dtp41.h
@@ -0,0 +1,110 @@
+#ifndef DTP41_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP41 related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 10/3/2001
+ *
+ * Copyright 1996 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from DTP51.h
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Fake Error codes */
+#define DTP41_INTERNAL_ERROR 0x61 /* Internal software error */
+#define DTP41_COMS_FAIL 0x62 /* Communication failure */
+#define DTP41_UNKNOWN_MODEL 0x63 /* Not a DPT51 or DTP52 */
+#define DTP41_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error code */
+#define DTP41_OK 0x00
+
+#define DTP41_MEASUREMENT_STATUS 0x01
+#define DTP41_CALIBRATION_STATUS 0x02
+#define DTP41_KEYPRESS_STATUS 0x03
+#define DTP41_DEFAULTS_LOADED_STATUS 0x04
+
+#define DTP41_BAD_COMMAND 0x11
+#define DTP41_BAD_PARAMETERS 0x12
+#define DTP41_PRM_RANGE_ERROR 0x13
+#define DTP41_BUSY 0x14
+
+#define DTP41_MEASUREMENT_ERROR 0x20
+#define DTP41_TIMEOUT 0x21
+#define DTP41_BAD_STRIP 0x22
+#define DTP41_BAD_COLOR 0x23
+#define DTP41_BAD_STEP 0x24
+#define DTP41_BAD_PASS 0x25
+#define DTP41_BAD_PATCHES 0x26
+#define DTP41_BAD_READING 0x27
+#define DTP41_NEEDS_CAL_ERROR 0x28
+#define DTP41_CAL_FAILURE_ERROR 0x29
+
+#define DTP41_INSTRUMENT_ERROR 0x30
+#define DTP41_LAMP_ERROR 0x31
+#define DTP41_FILTER_ERROR 0x32
+#define DTP41_FILTER_MOTOR_ERROR 0x33
+#define DTP41_DRIVE_MOTOR_ERROR 0x34
+#define DTP41_KEYPAD_ERROR 0x35
+#define DTP41_DISPLAY_ERROR 0x36
+#define DTP41_MEMORY_ERROR 0x37
+#define DTP41_ADC_ERROR 0x38
+#define DTP41_PROCESSOR_ERROR 0x39
+#define DTP41_BATTERY_ERROR 0x3A
+#define DTP41_BATTERY_LOW_ERROR 0x3B
+#define DTP41_INPUT_POWER_ERROR 0x3C
+#define DTP41_TEMPERATURE_ERROR 0x3D
+#define DTP41_BATTERY_ABSENT_ERROR 0x3E
+#define DTP41_TRAN_LAMP_ERROR 0x3F
+#define DTP41_INVALID_COMMAND_ERROR 0x40
+
+/* DTP41 communication object */
+struct _dtp41 {
+ /* **** base instrument class **** */
+ INST_OBJ_BASE
+
+ /* *** DTP41 private data **** */
+ inst_mode cap; /* Instrument mode capability */
+ inst2_capability cap2; /* Instrument capability */
+ inst3_capability cap3; /* Instrument capability 3 */
+ inst_mode mode; /* Currently instrument mode */
+ inst_mode lastmode; /* Last requested mode */
+
+ int nstaticr; /* Number of static readings */
+ int need_cal; /* needs calibration */
+ inst_opt_type trig; /* Reading trigger mode */
+
+ }; typedef struct _dtp41 dtp41;
+
+/* Constructor */
+extern dtp41 *new_dtp41(icoms *icom, instType itype);
+
+#define DTP41_H
+#endif /* DTP41_H */
diff --git a/spectro/dtp51.c b/spectro/dtp51.c
new file mode 100644
index 0000000..7e49f3e
--- /dev/null
+++ b/spectro/dtp51.c
@@ -0,0 +1,898 @@
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP51 related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 5/10/96
+ *
+ * Copyright 1996 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+/* TTBD:
+
+ Recovery from needing calibration may not work properly ?
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* !SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* !SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "dtp51.h"
+
+#undef DEBUG
+
+/* Default flow control */
+#define DEFFC fc_Hardware
+
+static inst_code dtp51_interp_code(inst *pp, int ec);
+
+#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */
+
+/* Extract an error code from a reply string */
+/* Return -1 if no error code can be found */
+static int
+extract_ec(char *s) {
+ char *p;
+ char tt[3];
+ int rv;
+ p = s + strlen(s);
+ /* Find the trailing '>' */
+ for (p--; p >= s;p--) {
+ if (*p == '>')
+ break;
+ }
+ if ( (p-3) < s
+ || p[0] != '>'
+ || p[-3] != '<')
+ return -1;
+ tt[0] = p[-2];
+ tt[1] = p[-1];
+ tt[2] = '\000';
+ if (sscanf(tt,"%x",&rv) != 1)
+ return -1;
+ return rv & 0x7f; /* Mask out MSB */
+}
+
+/* Interpret an icoms error into a DTP51 error */
+static int icoms2dtp51_err(int se) {
+ if (se != ICOM_OK) {
+ if (se & ICOM_TO)
+ return DTP51_TIMEOUT;
+ return DTP51_COMS_FAIL;
+ }
+ return DTP51_OK;
+}
+
+/* Do a full featured command/response echange with the dtp51 */
+/* Return the dtp error code. End on the specified number */
+/* of specified characters, or expiry if the specified timeout */
+/* Assume standard error code if tc = '>' and ntc = 1 */
+/* Return a DTP51 error code */
+static int
+dtp51_fcommand(
+ struct _dtp51 *p,
+ char *in, /* In string */
+ char *out, /* Out string buffer */
+ int bsize, /* Out buffer size */
+ char tc, /* Terminating character */
+ int ntc, /* Number of terminating characters */
+ double to) { /* Timout in seconts */
+ int rv, se;
+
+ if ((se = p->icom->write_read(p->icom, in, out, bsize, tc, ntc, to)) != 0) {
+ a1logd(p->log, 1, "dtp51_fcommand: serial i/o failure on write_read '%s'\n",icoms_fix(in));
+ return icoms2dtp51_err(se);
+ }
+ rv = DTP51_OK;
+ if (tc == '>' && ntc == 1) {
+ rv = extract_ec(out);
+ if (rv > 0) {
+ rv &= inst_imask;
+ if (rv != DTP51_OK) { /* Clear the error */
+ char buf[MAX_MES_SIZE];
+ p->icom->write_read(p->icom, "CE\r", buf, MAX_MES_SIZE, '>', 1, 0.5);
+ }
+ }
+ }
+ a1logd(p->log, 4, "dtp51_fcommand: command '%s' returned '%s', value 0x%x\n",
+ icoms_fix(in), icoms_fix(out),rv);
+ return rv;
+}
+
+/* Do a standard command/response echange with the dtp51 */
+/* Return the dtp error code */
+static inst_code
+dtp51_command(dtp51 *p, char *in, char *out, int bsize, double to) {
+ int rv = dtp51_fcommand(p, in, out, bsize, '>', 1, to);
+ return dtp51_interp_code((inst *)p, rv);
+}
+
+/* Just read a response from the dtp51 */
+/* Return the dtp error code. */
+static int
+dtp51_read(
+struct _dtp51 *p,
+char *out, /* Out string buffer */
+int bsize, /* Out buffer size */
+double to) { /* Timout in seconts */
+ char tc = '>'; /* Terminating character */
+ int ntc = 1; /* Number of terminating characters */
+ int rv, se;
+
+ if ((se = p->icom->read(p->icom, out, bsize, tc, ntc, to)) != 0) {
+ a1logd(p->log, 1, "dtp51_fcommand: serial i/o failure on read\n");
+ return icoms2dtp51_err(se);
+ }
+ rv = DTP51_OK;
+ if (tc == '>' && ntc == 1) {
+ rv = extract_ec(out);
+ if (rv > 0) {
+ rv &= inst_imask;
+ if (rv != DTP51_OK) { /* Clear the error */
+ char buf[MAX_MES_SIZE];
+ p->icom->write_read(p->icom, "CE\r", buf, MAX_MES_SIZE, '>', 1, 0.5);
+ }
+ }
+ }
+ a1logd(p->log, 4, "dtp51_read: returned '%s', value 0x%x\n", icoms_fix(out),rv);
+
+ return rv;
+}
+
+/* Establish communications with a DTP51 */
+/* Use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+dtp51_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ dtp51 *p = (dtp51 *)pp;
+ static char buf[MAX_MES_SIZE];
+ baud_rate brt[5] = { baud_9600, baud_19200, baud_4800, baud_2400, baud_1200 };
+ char *brc[5] = { "30BR\r", "60BR\r", "18BR\r", "0CBR\r", "06BR\r" };
+ char *fcc;
+ unsigned int etime;
+ int ci, bi, i, se;
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "dtp51_init_coms: About to init Serial I/O\n");
+
+ /* Deal with flow control setting */
+ if (fc == fc_nc)
+ fc = DEFFC;
+ if (fc == fc_XonXOff) {
+ fcc = "0304CF\r";
+ } else if (fc == fc_Hardware) {
+ fcc = "0104CF\r";
+ } else {
+ fc = fc_none;
+ fcc = "0004CF\r";
+ }
+
+ /* Figure DTP51 baud rate being asked for */
+ for (bi = 0; bi < 5; bi++) {
+ if (brt[bi] == br)
+ break;
+ }
+ if (bi >= 5)
+ bi = 0;
+
+ /* Figure current icoms baud rate */
+ for (ci = 0; ci < 5; ci++) {
+ if (brt[ci] == p->icom->br)
+ break;
+ }
+ if (ci >= 5)
+ ci = bi;
+
+ /* The tick to give up on */
+ etime = msec_time() + (long)(1000.0 * tout + 0.5);
+
+ while (msec_time() < etime) {
+
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp51_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp51_interp_code((inst *)p, icoms2dtp51_err(se));
+ }
+
+ if (((ev = dtp51_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail)
+ break; /* We've got coms */
+
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "dtp22_init_coms: user aborted\n");
+ return inst_user_abort;
+ }
+ }
+ if (++i >= 5)
+ i = 0;
+ }
+ break; /* Got coms */
+ }
+
+ if (msec_time() >= etime) { /* We haven't established comms */
+ return inst_coms_fail;
+ }
+
+ /* Set the handshaking */
+ if ((ev = dtp51_command(p, fcc, buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Change the baud rate to the rate we've been told */
+ if ((se = p->icom->write_read(p->icom, brc[bi], buf, MAX_MES_SIZE, '>', 1, 1.5)) != 0) {
+ if (extract_ec(buf) != DTP51_OK)
+ return inst_coms_fail;
+ }
+
+ /* Configure our baud rate and handshaking as well */
+ if ((se = p->icom->set_ser_port(p->icom, fc, brt[bi], parity_none, stop_1, length_8))
+ != ICOM_OK) {
+ a1logd(p->log, 1, "dtp51_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp51_interp_code((inst *)p, icoms2dtp51_err(se));
+ }
+
+ /* Loose a character (not sure why) */
+ p->icom->write_read(p->icom, "\r", buf, MAX_MES_SIZE, '>', 1, 0.5);
+
+ /* Check instrument is responding */
+ if ((ev = dtp51_command(p, "\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return inst_coms_fail;
+
+ if (p->log->verb) {
+ int i, j;
+ if ((ev = dtp51_command(p, "GI\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok
+ && (ev & inst_imask) != DTP51_BAD_COMMAND)
+ return ev;
+
+ if ((ev & inst_imask) == DTP51_BAD_COMMAND) { /* Some fimware doesn't support GI */
+ a1logv(p->log, 1, "dtp51: Firware doesn't support GI command\n");
+ } else {
+ for (j = i = 0; ;i++) {
+ if (buf[i] == '<' || buf[i] == '\000')
+ break;
+ if (buf[i] == '\r') {
+ buf[i] = '\000';
+ a1logv(p->log, 1, " %s\n",&buf[j]);
+ if (buf[i+1] == '\n')
+ i++;
+ j = i+1;
+ }
+ }
+ }
+ }
+
+ a1logd(p->log, 4, "dtp51: Got coms OK\n");
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+/* Build a strip definition as a set of passes */
+static void
+build_strip(
+char *tp, /* pointer to string buffer */
+char *name, /* Strip name (7 chars) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (3 chars) */
+int sguide) { /* Guide number */
+ int i;
+
+ /* Per strip */
+ for (i = 0; i < 7 && *name != '\000'; i++)
+ *tp++ = *name++; /* Strip name padded to 7 characters */
+ for (; i < 7; i++)
+ *tp++ = ' ';
+ *tp++ = '1'; *tp++ = '0'; *tp++ = '0'; *tp++ = '0'; /* N factor */
+ *tp++ = 'F'; /* Forward order */
+ *tp++ = '1'; /* No min/max transmitted */
+ *tp++ = '0'; /* No absolute data, no extra steps */
+ *tp++ = '0'; *tp++ = '0'; *tp++ = '0'; *tp++ = '0'; *tp++ = '0'; /* Reserved */
+
+ /* Per pass */
+ for (i = 0; i < 3 && *pname != '\000'; i++)
+ *tp++ = *pname++; /* Pass name padded to 3 characters */
+ for (; i < 3; i++)
+ *tp++ = ' ';
+ /* *tp++ = '4'; */ /* Lab data */
+ *tp++ = '5'; /* XYZ data */
+ *tp++ = '8'; /* Auto color */
+ *tp++ = '0' + (char)(npatch/10); /* Number of patches MS */
+ *tp++ = '0' + (char)(npatch%10); /* Number of patches LS */
+ *tp++ = '0' + (char)(sguide/10); /* Guide location MS */
+ *tp++ = '0' + (char)(sguide%10); /* Guide location LS */
+ *tp++ = '0'; /* (Data output type) */
+ *tp++ = '0'; /* Extra steps */
+ *tp++ = '0'; /* Reserved */
+
+ *tp++ = '\r'; /* The CR */
+ *tp++ = '\000'; /* The end */
+}
+
+/* Initialise the DTP51. The spectral flag is ignored. */
+/* return non-zero on an error, with dtp error code */
+static inst_code
+dtp51_init_inst(inst *pp) {
+ dtp51 *p = (dtp51 *)pp;
+ static char tbuf[100], buf[MAX_MES_SIZE];
+ int rv;
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "dtp51_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_internal_error; /* Must establish coms before calling init */
+
+ /* Reset it */
+ if ((ev = dtp51_command(p, "0PR\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+ sleep(2); /* Let it recover from reset */
+
+ /* Turn echoing of characters off */
+ if ((ev = dtp51_command(p, "EC\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Get the model and version number */
+ if ((ev = dtp51_command(p, "SV\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Check that it is a DTP51 or 52 */
+ if ( strlen(buf) < 12
+ || strncmp(buf,"X-Rite DTP5",11) != 0
+ || (buf[11] != '1' && buf[11] != '2'))
+ return inst_unknown_model;
+
+ /* Set the A/D Conversion rate to normal */
+ if ((ev = dtp51_command(p, "00AD\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Disable Bar code reading to save time */
+ if ((ev = dtp51_command(p, "0BC\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set the Calibration Check tolerance to default of 0.15D */
+ if ((ev = dtp51_command(p, "0FCC\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Automatic Transmit off */
+ if ((ev = dtp51_command(p, "0005CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set Read Status on */
+ if ((ev = dtp51_command(p, "1RS\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set decimal pont on */
+ if ((ev = dtp51_command(p, "0106CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set color data separator to TAB */
+ if ((ev = dtp51_command(p, "0207CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set default strip format to off */
+ if ((ev = dtp51_command(p, "0009CF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set extra digit resolution */
+ if ((ev = dtp51_command(p, "010ACF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set data after pass to off */
+ if ((ev = dtp51_command(p, "000BCF\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+#ifdef NEVER /* Doesn't seem to work on DTP51 */
+ /* Set the patch detection window to default HRW = 3, LRW 0.122% */
+ if ((ev = dtp51_command(p, "2CW\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+#endif
+
+ /* Enable the LCD display */
+ if ((ev = dtp51_command(p, "EL\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Enable the read microswitch */
+ if ((ev = dtp51_command(p, "1SM\r", buf, MAX_MES_SIZE, 1.5)) != inst_ok)
+ return ev;
+
+ /* Set a strip length of 1, to ensure parsing is invalidated */
+ build_strip(tbuf, " ", 1, " ", 30);
+
+ if ((rv = dtp51_fcommand(p, "0105DS\r", buf, MAX_MES_SIZE, '*', 1, 0.5)) != DTP51_OK)
+ return dtp51_interp_code(pp, rv);
+
+ /* Expect '*' as response */
+ if (buf[0] != '*' || buf[1] != '\000')
+ return inst_coms_fail;
+
+ /* Send strip definition */
+ if ((ev = dtp51_command(p, tbuf, buf, MAX_MES_SIZE, 4.0)) != inst_ok)
+ return ev;
+
+ /* This is the only mode supported */
+ p->trig = inst_opt_trig_switch;
+
+ p->inited = 1;
+ a1logd(p->log, 2, "dtp51_init_inst: instrument inited OK\n");
+
+ return inst_ok;
+}
+
+/* Read a set of strips */
+/* Return the dtp error code */
+static inst_code
+dtp51_read_strip(
+inst *pp,
+char *name, /* Strip name (up to first 7 chars used) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (up to first 3 chars used) */
+int sguide, /* Guide number */
+double pwid, /* Patch length in mm (For DTP41) */
+double gwid, /* Gap length in mm (For DTP41) */
+double twid, /* Trailer length in mm (For DTP41T) */
+ipatch *vals) { /* Pointer to array of instrument patch values */
+ dtp51 *p = (dtp51 *)pp;
+ char tbuf[200], *tp;
+ static char buf[MAX_RD_SIZE];
+ int i, rv;
+ inst_code ev = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ build_strip(tbuf, name, npatch, pname, sguide);
+
+ if ((rv = dtp51_fcommand(p, "0105DS\r", buf, MAX_RD_SIZE, '*', 1, 0.5)) != DTP51_OK)
+ return dtp51_interp_code(pp, rv);
+
+ /* Expect '*' as response */
+ if (buf[0] != '*' || buf[1] != '\000')
+ return inst_coms_fail;
+
+ /* Send strip definition */
+ if ((ev = dtp51_command(p, tbuf, buf, MAX_RD_SIZE, 4.0)) != inst_ok)
+ return ev;
+
+ /* Do a strip read */
+ if ((ev = dtp51_command(p, "5SW\r", buf, MAX_RD_SIZE, 1.5)) != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+ return ev;
+ }
+
+ /* Wait for the Read status, or a user abort (no user trigger!) */
+ for (;;) {
+ if ((ev = dtp51_read(p, buf, MAX_RD_SIZE, 0.5)) != inst_ok) {
+ if ((ev & inst_mask) == inst_needs_cal)
+ p->need_cal = 1;
+
+ if ((ev & inst_imask) == DTP51_TIMEOUT) { /* Timed out */
+ if (p->uicallback != NULL) { /* Check for user trigger */
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort) {
+ return ev; /* User abort */
+ }
+ }
+ } else
+ return ev; /* Instrument or comms error */
+
+ } else {
+ break; /* Switch activated */
+ }
+ }
+
+ if (p->uicallback) /* Notify of trigger */
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Gather the results */
+ if ((ev = dtp51_command(p, "TS\r", buf, MAX_RD_SIZE, 0.5 + npatch * 0.1)) != inst_ok)
+ return ev;
+
+ /* Parse the buffer */
+ /* Replace '\r' with '\000' */
+ for (tp = buf; *tp != '\000'; tp++) {
+ if (*tp == '\r')
+ *tp = '\000';
+ }
+ for (tp = buf, i = 0; i < npatch; i++) {
+ if (*tp == '\000')
+ return inst_protocol_error;
+ if (sscanf(tp, " X %lf Y %lf Z %lf ",
+ &vals[i].XYZ[0], &vals[i].XYZ[1], &vals[i].XYZ[2]) != 3) {
+ if (sscanf(tp, " x %lf y %lf z %lf ",
+ &vals[i].XYZ[0], &vals[i].XYZ[1], &vals[i].XYZ[2]) != 3) {
+ return inst_protocol_error;
+ }
+ }
+ vals[i].mtype = inst_mrt_reflective;
+ vals[i].XYZ_v = 1;
+ vals[i].sp.spec_n = 0;
+ vals[i].duration = 0.0;
+ tp += strlen(tp) + 1;
+ }
+
+#ifdef NEVER
+ /* Disable the read microswitch */
+ if ((ev = dtp51_command(p, "0SM\r", buf, MAX_RD_SIZE)) != inst_ok)
+ return ev;
+#endif
+
+ return inst_ok;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code dtp51_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ dtp51 *p = (dtp51 *)pp;
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if (p->need_cal)
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+/* This is used if the user decides they want to do a calibration, */
+/* in anticipation of a calibration (needs_calibration()) to avoid */
+/* requiring one during measurement, or in response to measuring */
+/* returning inst_needs_cal. Initially us an inst_cal_cond of inst_calc_none, */
+/* and then be prepared to setup the right conditions, or ask the */
+/* user to do so, each time the error inst_cal_setup is returned. */
+/* NOTE :- we can trigger a calibration ! */
+/* Perhaps we should do so ??? */
+inst_code dtp51_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ dtp51 *p = (dtp51 *)pp;
+ inst_code ev;
+ inst_cal_type needed, available;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ id[0] = '\000';
+
+ if ((ev = dtp51_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"dtp51_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return inst_unsupported;
+ }
+
+ if (*calt & inst_calt_ref_white) {
+
+ if (*calc != inst_calc_uop_ref_white) {
+ *calc = inst_calc_uop_ref_white; /* Ask user to do calibration */
+ return inst_cal_setup;
+ }
+ p->need_cal = 0;
+ *calt &= ~inst_calt_ref_white;
+ }
+ return inst_ok;
+}
+
+/* Error codes interpretation */
+static char *
+dtp51_interp_error(inst *pp, int ec) {
+// dtp51 *p = (dtp51 *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case DTP51_INTERNAL_ERROR:
+ return "Internal software error";
+ case DTP51_COMS_FAIL:
+ return "Communications failure";
+ case DTP51_UNKNOWN_MODEL:
+ return "Not a DTP51 or DTP52";
+ case DTP51_DATA_PARSE_ERROR:
+ return "Data from DTP didn't parse as expected";
+ case DTP51_OK:
+ return "No device error";
+ case DTP51_BAD_COMMAND:
+ return "Unrecognized command";
+ case DTP51_PRM_RANGE:
+ return "Command parameter out of range";
+ case DTP51_DISPLAY_OVERFLOW:
+ return "Display overflow";
+ case DTP51_MEMORY_OVERFLOW:
+ return "Memory bounds error";
+ case DTP51_INVALID_BAUD_RATE:
+ return "Invalid baud rate";
+ case DTP51_TIMEOUT:
+ return "Receive timeout";
+ case DTP51_INVALID_PASS:
+ return "Invalid pass";
+ case DTP51_INVALID_STEP:
+ return "Invalid step";
+ case DTP51_NO_DATA_AVAILABLE:
+ return "No data availble";
+ case DTP51_LAMP_MARGINAL:
+ return "Lamp marginal";
+ case DTP51_LAMP_FAILURE:
+ return "Lamp failure";
+ case DTP51_STRIP_RESTRAINED:
+ return "Strip was restrained";
+ case DTP51_BAD_CAL_STRIP:
+ return "Bad calibration strip";
+ case DTP51_MOTOR_ERROR:
+ return "Motor error";
+ case DTP51_BAD_BARCODE:
+ return "Bad barcode on cal strip";
+ case DTP51_INVALID_READING:
+ return "Invalid strip reading";
+ case DTP51_WRONG_COLOR:
+ return "Wrong color strip";
+ case DTP51_BATTERY_TOO_LOW:
+ return "Battery too low";
+ case DTP51_NEEDS_CALIBRATION:
+ return "Needs calibration";
+ case DTP51_COMP_TABLE_MISMATCH:
+ return "Compensation table mismatch";
+ case DTP51_BAD_COMP_TABLE:
+ return "Bad compensation table";
+ case DTP51_NO_VALID_DATA:
+ return "No valid data found";
+ case DTP51_BAD_PATCH:
+ return "Bad patch in strip";
+ case DTP51_BAD_STRING_LENGTH:
+ return "Bad strip def. string length";
+ case DTP51_BAD_CHARACTER:
+ return "Bad chareter";
+ case DTP51_BAD_MEAS_TYPE:
+ return "Bad measure type field";
+ case DTP51_BAD_COLOR:
+ return "Bad color field";
+ case DTP51_BAD_STEPS:
+ return "Bad step field";
+ case DTP51_BAD_STOP_LOCATION:
+ return "Bad guide stop field";
+ case DTP51_BAD_OUTPUT_TYPE:
+ return "Bad output type field";
+ case DTP51_MEMORY_ERROR:
+ return "Memory error (need AC supply)";
+ case DTP51_BAD_N_FACTOR:
+ return "Bad N factore";
+ case DTP51_STRIP_DOESNT_EXIST:
+ return "Strip doesn't exist";
+ case DTP51_BAD_MIN_MAX_VALUE:
+ return "Bad min/max field value";
+ case DTP51_BAD_SERIAL_NUMBER:
+ return "Bad serial number";
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+dtp51_interp_code(inst *pp, int ec) {
+// dtp51 *p = (dtp51 *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case DTP51_OK:
+ return inst_ok;
+
+ case DTP51_INTERNAL_ERROR:
+ return inst_internal_error | ec;
+
+ case DTP51_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case DTP51_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+ case DTP51_DATA_PARSE_ERROR:
+ return inst_protocol_error | ec;
+
+ case DTP51_NO_DATA_AVAILABLE:
+ case DTP51_LAMP_MARGINAL:
+ case DTP51_LAMP_FAILURE:
+ case DTP51_STRIP_RESTRAINED:
+ case DTP51_MOTOR_ERROR:
+ case DTP51_INVALID_READING:
+ case DTP51_WRONG_COLOR:
+ case DTP51_BATTERY_TOO_LOW:
+ case DTP51_COMP_TABLE_MISMATCH:
+ case DTP51_BAD_COMP_TABLE:
+ case DTP51_NO_VALID_DATA:
+ case DTP51_BAD_PATCH:
+ return inst_misread | ec;
+
+ case DTP51_NEEDS_CALIBRATION:
+ return inst_needs_cal | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+dtp51_del(inst *pp) {
+ dtp51 *p = (dtp51 *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ free(p);
+}
+
+/* Return the instrument mode capabilities */
+void dtp51_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ inst_mode cap1= 0;
+ inst2_capability cap2 = 0;
+
+ cap1 |= inst_mode_ref_strip
+ | inst_mode_colorimeter
+ ;
+
+ cap2 |= inst2_switch_trig /* Can only be triggered by microswitch */
+ ;
+
+ if (pcap1 != NULL)
+ *pcap1 = cap1;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Check device measurement mode */
+inst_code dtp51_check_mode(inst *pp, inst_mode m) {
+ inst_mode cap;
+
+ if (!pp->gotcoms)
+ return inst_no_coms;
+ if (!pp->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* only reflection strip measurement mode suported */
+ if (!IMODETST(m, inst_mode_ref_strip)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code dtp51_set_mode(inst *pp, inst_mode m) {
+ inst_code ev;
+
+ if ((ev = dtp51_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* !! It's not clear if there is a way of knowing */
+/* whether the instrument has a UV filter. */
+
+/*
+ * set or reset an optional mode
+ *
+ * Since there is no interaction with the instrument,
+ * was assume that all of these can be done before initialisation.
+ */
+static inst_code
+dtp51_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ dtp51 *p = (dtp51 *)pp;
+ static char buf[MAX_MES_SIZE];
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_switch) { /* Can only be triggered this way */
+ p->trig = m;
+ return inst_ok;
+ }
+
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern dtp51 *new_dtp51(icoms *icom, instType itype) {
+ dtp51 *p;
+ if ((p = (dtp51 *)calloc(sizeof(dtp51),1)) == NULL) {
+ a1loge(icom->log, 1, "new_dtp51: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = dtp51_init_coms;
+ p->init_inst = dtp51_init_inst;
+ p->capabilities = dtp51_capabilities;
+ p->check_mode = dtp51_check_mode;
+ p->set_mode = dtp51_set_mode;
+ p->get_set_opt = dtp51_get_set_opt;
+ p->read_strip = dtp51_read_strip;
+ p->get_n_a_cals = dtp51_get_n_a_cals;
+ p->calibrate = dtp51_calibrate;
+ p->interp_error = dtp51_interp_error;
+ p->del = dtp51_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ return p;
+}
diff --git a/spectro/dtp51.h b/spectro/dtp51.h
new file mode 100644
index 0000000..329c5d6
--- /dev/null
+++ b/spectro/dtp51.h
@@ -0,0 +1,102 @@
+#ifndef DTP51_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP51 related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 5/10/1996
+ *
+ * Copyright 1996 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Fake Error codes */
+#define DTP51_INTERNAL_ERROR 0x61 /* Internal software error */
+#define DTP51_COMS_FAIL 0x62 /* Communication failure */
+#define DTP51_UNKNOWN_MODEL 0x63 /* Not a DPT51 or DTP52 */
+#define DTP51_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error code */
+#define DTP51_OK 0x00
+
+#define DTP51_BAD_COMMAND 0x01
+#define DTP51_PRM_RANGE 0x02
+#define DTP51_DISPLAY_OVERFLOW 0x03
+#define DTP51_MEMORY_OVERFLOW 0x04
+#define DTP51_INVALID_BAUD_RATE 0x05
+#define DTP51_TIMEOUT 0x07
+#define DTP51_INVALID_PASS 0x09
+#define DTP51_INVALID_STEP 0x0A
+#define DTP51_NO_DATA_AVAILABLE 0x0B
+
+#define DTP51_LAMP_MARGINAL 0x10
+#define DTP51_LAMP_FAILURE 0x11
+#define DTP51_STRIP_RESTRAINED 0x12
+#define DTP51_BAD_CAL_STRIP 0x13
+#define DTP51_MOTOR_ERROR 0x14
+#define DTP51_BAD_BARCODE 0x15
+
+#define DTP51_INVALID_READING 0x20
+#define DTP51_WRONG_COLOR 0x21
+#define DTP51_BATTERY_TOO_LOW 0x22
+#define DTP51_NEEDS_CALIBRATION 0x23
+#define DTP51_COMP_TABLE_MISMATCH 0x24
+#define DTP51_BAD_COMP_TABLE 0x25
+#define DTP51_NO_VALID_DATA 0x26
+#define DTP51_BAD_PATCH 0x27
+
+#define DTP51_BAD_STRING_LENGTH 0x30
+#define DTP51_BAD_CHARACTER 0x31
+#define DTP51_BAD_MEAS_TYPE 0x32
+#define DTP51_BAD_COLOR 0x33
+#define DTP51_BAD_STEPS 0x34
+#define DTP51_BAD_STOP_LOCATION 0x35
+#define DTP51_BAD_OUTPUT_TYPE 0x36
+#define DTP51_MEMORY_ERROR 0x37
+#define DTP51_BAD_N_FACTOR 0x38
+#define DTP51_STRIP_DOESNT_EXIST 0x39
+#define DTP51_BAD_MIN_MAX_VALUE 0x3A
+
+#define DTP51_BAD_SERIAL_NUMBER 0x40
+
+/* DTP51 communication object */
+struct _dtp51 {
+ INST_OBJ_BASE
+
+ int need_cal; /* needs calibration */
+ inst_opt_type trig; /* Reading trigger mode */
+
+ }; typedef struct _dtp51 dtp51;
+
+/* Constructor */
+extern dtp51 *new_dtp51(icoms *icom, instType itype);
+
+
+
+#define DTP51_H
+#endif /* DTP51_H */
diff --git a/spectro/dtp92.c b/spectro/dtp92.c
new file mode 100644
index 0000000..441c0eb
--- /dev/null
+++ b/spectro/dtp92.c
@@ -0,0 +1,1325 @@
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP92/94 related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 5/10/1996
+ *
+ * Copyright 1996 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+/*
+ TTBD:
+ Should make DTP92 switch trigger a reading.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* !SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* !SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "dtp92.h"
+
+/* Default flow control */
+#define DEFFC fc_none
+
+#define IGNORE_NEEDS_OFFSET_DRIFT_CAL_ERR
+
+static inst_code dtp92_interp_code(inst *pp, int ec);
+
+#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */
+
+/* Extract an error code from a reply string */
+/* Return -1 if no error code can be found */
+static int
+extract_ec(char *s) {
+ char *p;
+ char tt[3];
+ int rv;
+ p = s + strlen(s);
+ /* Find the trailing '>' */
+ for (p--; p >= s;p--) {
+ if (*p == '>')
+ break;
+ }
+ if ( (p-3) < s
+ || p[0] != '>'
+ || p[-3] != '<')
+ return -1;
+ tt[0] = p[-2];
+ tt[1] = p[-1];
+ tt[2] = '\000';
+ if (sscanf(tt,"%x",&rv) != 1)
+ return -1;
+ return rv;
+}
+
+/* Interpret an icoms error into a DTP92 error */
+static int icoms2dtp92_err(int se) {
+ if (se != ICOM_OK) {
+ if (se & ICOM_TO)
+ return DTP92_TIMEOUT;
+ return DTP92_COMS_FAIL;
+ }
+ return DTP92_OK;
+}
+
+/* Do a full featured command/response echange with the dtp92 */
+/* Return the dtp error code. End on the specified number */
+/* of specified characters, or expiry if the specified timeout */
+/* Assume standard error code if tc = '>' and ntc = 1 */
+/* Return a DTP92 error code */
+static int
+dtp92_fcommand(
+ struct _dtp92 *p,
+ char *in, /* In string */
+ char *out, /* Out string buffer */
+ int bsize, /* Out buffer size */
+ char tc, /* Terminating character */
+ int ntc, /* Number of terminating characters */
+ double to) { /* Timout in seconds */
+ int rv, se;
+
+ if ((se = p->icom->write_read(p->icom, in, out, bsize, tc, ntc, to)) != 0) {
+ a1logd(p->log, 1, "dtp92_fcommand: serial i/o failure on write_read '%s'\n",icoms_fix(in));
+ return icoms2dtp92_err(se);
+ }
+ rv = DTP92_OK;
+ if (tc == '>' && ntc == 1) {
+ rv = extract_ec(out);
+
+#ifdef NEVER
+ if (strcmp(in, "0PR\r") == 0)
+ rv = DTP92_NEEDS_OFFSET_DRIFT_CAL; /* Emulate 1B error */
+#endif /* NEVER */
+
+ if (rv > 0) {
+ rv &= inst_imask;
+ if (rv != DTP92_OK) { /* Clear the error */
+ char buf[MAX_MES_SIZE];
+ p->icom->write_read(p->icom, "CE\r", buf, MAX_MES_SIZE, '>', 1, 0.5);
+ }
+ }
+ }
+ a1logd(p->log, 4, "dtp92_fcommand: command '%s' returned '%s', value 0x%x\n",
+ icoms_fix(in), icoms_fix(out),rv);
+
+#ifdef IGNORE_NEEDS_OFFSET_DRIFT_CAL_ERR
+ if (strcmp(in, "0PR\r") == 0 && rv == DTP92_NEEDS_OFFSET_DRIFT_CAL) {
+ static int warned = 0;
+ if (!warned) {
+ a1logw(p->log,"dtp92: Got error NEEDS_OFFSET_DRIFT_CAL on instrument reset - being ignored.");
+ warned = 1;
+ }
+ rv = 0;
+ }
+#endif
+ return rv;
+}
+
+/* Do a standard command/response echange with the dtp92 */
+/* Return the dtp error code */
+static inst_code
+dtp92_command(dtp92 *p, char *in, char *out, int bsize, double to) {
+ int rv = dtp92_fcommand(p, in, out, bsize, '>', 1, to);
+ return dtp92_interp_code((inst *)p, rv);
+}
+
+/* Establish communications with a DTP92 */
+/* If it's a serial port, use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+dtp92_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ dtp92 *p = (dtp92 *) pp;
+ static char buf[MAX_MES_SIZE];
+ baud_rate brt[5] = { baud_9600, baud_19200, baud_4800, baud_2400, baud_1200 };
+ char *brc[5] = { "30BR\r", "60BR\r", "18BR\r", "0CBR\r", "06BR\r" };
+ char *fcc;
+ unsigned int etime;
+ instType itype = pp->itype;
+ int ci, bi, i, se;
+ inst_code ev = inst_ok;
+
+ if (p->icom->port_type(p->icom) == icomt_usb) {
+#ifdef ENABLE_USB
+
+ a1logd(p->log, 2, "dtp92_init_coms: About to init USB\n");
+
+ /* Note that the 92Q and 94 have a different */
+ /* arrangement of end points: */
+ /* */
+ /* 92Q 94 */
+ /* --- -- */
+ /* */
+ /* 0x81 i Bulk 0x81 i Intr. */
+ /* 0x01 o Bulk */
+ /* 0x82 i Intr. */
+ /* 0x02 o Bulk 0x02 o Intr. */
+ /* */
+ /* Set config, interface, write end point, read end point, read quanta */
+ if (itype == instDTP94)
+ se = p->icom->set_usb_port(p->icom, 1, 0x02, 0x81, icomuf_none, 0, NULL);
+ else
+ se = p->icom->set_usb_port(p->icom, 1, 0x01, 0x81, icomuf_none, 0, NULL);
+
+ if (se != ICOM_OK) {
+ a1logd(p->log, 1, "dtp92_init_coms: set_usb_port failed ICOM err 0x%x\n",se);
+ return dtp92_interp_code((inst *)p, icoms2dtp92_err(se));
+ }
+
+ /* Blind reset it twice - it seems to sometimes hang up */
+ /* otherwise under OSX */
+ dtp92_command(p, "0PR\r", buf, MAX_MES_SIZE, 0.5);
+ dtp92_command(p, "0PR\r", buf, MAX_MES_SIZE, 0.5);
+#else /* !ENABLE_USB */
+ a1logd(p->log, 1, "dtp20: Failed to find USB connection to instrument\n");
+ return inst_coms_fail;
+#endif /* !ENABLE_USB */
+
+ } else {
+
+#ifdef ENABLE_SERIAL
+ a1logd(p->log, 2, "dtp92_init_coms: About to init Serial I/O\n");
+
+ /* Deal with flow control setting */
+ if (fc == fc_nc)
+ fc = DEFFC;
+ if (fc == fc_XonXOff) {
+ fcc = "0304CF\r";
+ } else if (fc == fc_Hardware) {
+ fcc = "0104CF\r";
+ } else {
+ fc = fc_none;
+ fcc = "0004CF\r";
+ }
+
+ /* Figure DTP92 baud rate being asked for */
+ for (bi = 0; bi < 5; bi++) {
+ if (brt[bi] == br)
+ break;
+ }
+ if (bi >= 5)
+ bi = 0;
+
+ /* Figure current icoms baud rate */
+ for (ci = 0; ci < 5; ci++) {
+ if (brt[ci] == p->icom->br)
+ break;
+ }
+ if (ci >= 5)
+ ci = bi;
+
+ /* The tick to give up on */
+ etime = msec_time() + (long)(1000.0 * tout + 0.5);
+
+ while (msec_time() < etime) {
+
+ a1logd(p->log, 4, "dtp92_init_coms: Trying different baud rates (%u msec to go)\n",
+ etime - msec_time());
+
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; msec_time() < etime;) {
+ if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp92_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp92_interp_code((inst *)p, icoms2dtp92_err(se));
+ }
+
+ if (((ev = dtp92_command(p, "\r", buf, MAX_MES_SIZE, 0.5)) & inst_mask)
+ != inst_coms_fail)
+ break; /* We've got coms or user abort */
+
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "dtp92_init_coms: user aborted\n");
+ return inst_user_abort;
+ }
+ }
+
+ if (++i >= 5)
+ i = 0;
+ }
+ break; /* Got coms */
+ }
+
+ if (msec_time() >= etime) { /* We haven't established comms */
+ return inst_coms_fail;
+ }
+
+ /* Set the handshaking */
+ if ((ev = dtp92_command(p, fcc, buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Change the baud rate to the rate we've been told */
+ if ((se = p->icom->write_read(p->icom, brc[bi], buf, MAX_MES_SIZE, '>', 1, .2)) != 0) {
+ if (extract_ec(buf) != DTP92_OK)
+ return inst_coms_fail;
+ }
+
+ /* Configure our baud rate and handshaking as well */
+ if ((se = p->icom->set_ser_port(p->icom, fc, brt[bi], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "dtp92_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ return dtp92_interp_code((inst *)p, icoms2dtp92_err(se));
+ }
+
+ /* Loose a character (not sure why) */
+ p->icom->write_read(p->icom, "\r", buf, MAX_MES_SIZE, '>', 1, 0.1);
+#else /* !ENABLE_SERIAL */
+ a1logd(p->log, 1, "dtp20: Failed to find serial connection to instrument\n");
+ return inst_coms_fail;
+#endif /* !ENABLE_SERIAL */
+ }
+
+ /* Check instrument is responding, and reset it again. */
+ if ((ev = dtp92_command(p, "\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok
+ || (ev = dtp92_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok) {
+
+ a1logd(p->log, 1, "dtp92_init_coms: failed with ICOM 0x%x\n",ev);
+
+#ifdef NEVER /* Experimental code for fixing 0x1B "Offset Drift invalid" error */
+ if ((ev & inst_mask) == inst_hardware_fail) {
+ /* Could be a checksum type error. Try resetting to factory settings */
+ warning("Got error %s (%s) on attempting to communicate with instrument.",
+ p->inst_interp_error((inst *)p, ev), p->interp_error((inst *)p, ev));
+ if ((ev & inst_imask) == DTP92_NEEDS_OFFSET_DRIFT_CAL) {
+ char tbuf[100];
+ double odv = 0.0;
+ printf("Got Offset Drift Cal error. Will try re-writing it\n");
+ if ((ev = dtp92_command(p, "SD\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
+ error("Reading current offset drift value failed");
+ if (sscanf(buf, "%lf<", &odv) != 1)
+ error("Unable to parse offset drift value");
+ printf("Read current offset drift value of %f\n", odv);
+ if (odv > 0.5 || odv < 0.05)
+ error("offset drift value seems like nonsense - aborting");
+ sprintf(tbuf,"%05dSD\r",(int)(odv * 100000));
+ printf("Command about to be sent is '%s', OK ? (Y/N)\n",icoms_fix(tbuf));
+ if (getchar() == 'Y') {
+ if ((ev = dtp92_command(p, tbuf, buf, MAX_MES_SIZE, 6.0)) != inst_ok)
+ error("Writing offset drift value failed");
+ else
+ printf("Writing offset drift value suceeded!\n");
+ } else {
+ printf("No command written\n");
+ }
+ printf("Now try re-running program\n");
+ }
+ }
+#endif /* NEVER */
+
+ p->icom->del(p->icom); /* Since caller may not clean up */
+ p->icom = NULL;
+ return inst_coms_fail;
+ }
+
+ a1logd(p->log, 2, "dtp92_init_coms: init coms has suceeded\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+static inst_code set_default_disp_type(dtp92 *p);
+
+/* Initialise the DTP92 */
+/* return non-zero on an error, with dtp error code */
+static inst_code
+dtp92_init_inst(inst *pp) {
+ dtp92 *p = (dtp92 *)pp;
+ static char buf[MAX_MES_SIZE];
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "dtp92_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_internal_error; /* Must establish coms before calling init */
+
+ /* Reset it ( without disconnecting USB or resetting baud rate etc.) */
+ if ((ev = dtp92_command(p, "0PR\r", buf, MAX_MES_SIZE, 2.0)) != inst_ok)
+ return ev;
+
+ /* Get the model and version number */
+ if ((ev = dtp92_command(p, "SV\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Check that it is a DTP92, DTP92Q or DTP94 */
+ if ( strlen(buf) < 12
+ || (strncmp(buf,"X-Rite DTP92",12) != 0
+ && strncmp(buf,"X-Rite DTP94",12) != 0))
+ return inst_unknown_model;
+
+ if (strncmp(buf,"X-Rite DTP94",12) == 0)
+ p->itype = instDTP94;
+ else
+ p->itype = instDTP92;
+
+ if (p->itype == instDTP92) {
+ /* Turn echoing of characters off */
+ if ((ev = dtp92_command(p, "DEC\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ }
+
+ if (p->itype == instDTP92) {
+ /* Set decimal point on */
+ if ((ev = dtp92_command(p, "0106CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ }
+
+ /* Set color data separator to TAB */
+ if ((ev = dtp92_command(p, "0207CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set delimeter to CR */
+ if ((ev = dtp92_command(p, "0008CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set extra digit resolution (X10) */
+ if ((ev = dtp92_command(p, "010ACF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ if (p->itype == instDTP92) {
+ /* Set absolute (luminance) calibration */
+ if ((ev = dtp92_command(p, "0118CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ }
+
+ /* Set no black point subtraction */
+ if ((ev = dtp92_command(p, "0019CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set to factory calibration */
+ if ((ev = dtp92_command(p, "EFC\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+
+ if (p->itype == instDTP94) {
+ /* Compensate for offset drift */
+ if ((ev = dtp92_command(p, "0117CF\r", buf, MAX_MES_SIZE, 0.5)) != inst_ok)
+ return ev;
+ }
+
+ if (p->itype == instDTP92) {
+ /* Enable ABS mode (in case firmware doesn't default to this after EFC) */
+ if ((ev = dtp92_command(p, "0118CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Disable -BLK mode (in case firmware doesn't default to this after EFC) */
+ if ((ev = dtp92_command(p, "0019CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set to transmit just the colorimetric data */
+ if ((ev = dtp92_command(p, "0120CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Transmit colorimetric data as XYZ */
+ if ((ev = dtp92_command(p, "0221CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Disable Luminance group */
+ if ((ev = dtp92_command(p, "0022CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Disable Frequency group */
+ if ((ev = dtp92_command(p, "0023CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Disable color temperature group */
+ if ((ev = dtp92_command(p, "0024CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Disable RGB group */
+ if ((ev = dtp92_command(p, "0025CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Disable pushbutton */
+ if ((ev = dtp92_command(p, "DPB\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+
+ /* Set sample size to 16 (default is 16) */
+ if ((ev = dtp92_command(p, "10SS\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ }
+ p->trig = inst_opt_trig_user;
+
+ /* Set the default display type */
+ if ((ev = set_default_disp_type(p)) != inst_ok)
+ return ev;
+
+ /* ??? Need to set CTYP appropriately ??? */
+
+#ifdef NEVER /* Debug code */
+ if (p->itype == instDTP94) {
+ int i, val;
+ char tb[50];
+
+ for (i = 0; i < 0x800; i++) {
+ sprintf(tb,"%04xRN\r",i);
+ if ((ev = dtp92_command(p, tb, buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ if (sscanf(buf,"%x",&val) != 1)
+ return inst_coms_fail;
+ tb[0] = val;
+ tb[1] = '\000';
+ a1logd(p->log, 0, "Mem location 0x%04x = 0x%02x '%s'\n",i,val,icoms_fix(tb));
+ }
+ }
+#endif /* NEVER */
+
+ if (p->log->verb) {
+ int i, j;
+ if ((ev = dtp92_command(p, "GI\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok) {
+ a1logd(p->log, 1, "dtp20: GI command failed with ICOM err 0x%x\n",ev);
+ return ev;
+ }
+ for (j = i = 0; ;i++) {
+ if (buf[i] == '<' || buf[i] == '\000')
+ break;
+ if (buf[i] == '\r') {
+ buf[i] = '\000';
+ a1logv(p->log, 1, " %s\n",&buf[j]);
+ if (buf[i+1] == '\n')
+ i++;
+ j = i+1;
+ }
+ }
+ }
+
+ p->inited = 1;
+ a1logd(p->log, 2, "dtp92_init_inst: instrument inited OK\n");
+
+ return inst_ok;
+}
+
+/* The DTP92 seems to have a bug whereby it adds a spurious */
+/* digit after the 'Z' of the Z value. Try and discard this. */
+
+/* Read a single sample */
+/* Return the dtp error code */
+static inst_code
+dtp92_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ dtp92 *p = (dtp92 *)pp;
+ char buf[MAX_RD_SIZE];
+ int tries;
+ int user_trig = 0;
+ inst_code rv = inst_protocol_error;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Could change SS to suite level expected. */
+#ifdef NEVER
+ if (p->itype == instDTP92) {
+ /* Set sample size to 31 (default is 16) for low level readings */
+ if ((rv = dtp92_command(p, "1fSS\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+ }
+#endif
+
+ if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "dtp92: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rv == inst_user_abort)
+ return rv; /* Abort */
+ if (rv == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return rv; /* Abort */
+ }
+
+ /* Until we get a valid return */
+ for (tries = 0; tries < 2; tries++) {
+
+ /* Take a reading */
+ /* (DTP94 has optional parameters, but the default is what we want, XYZ in cd/m^2) */
+ if ((rv = dtp92_command(p, "RM\r", buf, MAX_RD_SIZE, 10.0)) != inst_ok) {
+ if ((rv & inst_imask) == DTP92_NEEDS_OFFSET_CAL)
+ p->need_offset_cal = 1;
+ else if ((rv & inst_imask) == DTP92_NEEDS_RATIO_CAL) /* DTP92 only */
+ p->need_ratio_cal = 1;
+ return rv;
+ }
+
+ if (sscanf(buf, " X%*c %lf\t Y%*c %lf\t Z%*c %lf ",
+ &val->XYZ[0], &val->XYZ[1], &val->XYZ[2]) == 3) {
+
+ /* Apply the colorimeter correction matrix */
+ icmMulBy3x3(val->XYZ, p->ccmat, val->XYZ);
+
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+ val->loc[0] = '\000';
+ val->mtype = inst_mrt_emission;
+ val->XYZ_v = 1; /* These are absolute XYZ readings */
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+ rv = inst_ok;
+ break;
+ } else {
+ a1logd(p->log, 1, "dtp92_read_sample: failed to parse string '%s'\n",buf);
+ rv = inst_coms_fail;
+ }
+ }
+
+#ifdef NEVER
+ if (p->itype == instDTP92) {
+ /* Set sample size back to 16 */
+ if ((rv = dtp92_command(p, "10SS\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return rv;
+ }
+#endif
+
+ if (user_trig)
+ return inst_user_trig;
+ return rv;
+}
+
+/* Read an emissive refresh rate */
+static inst_code
+dtp92_read_refrate(
+inst *pp,
+double *ref_rate
+) {
+ dtp92 *p = (dtp92 *)pp;
+ char buf[MAX_RD_SIZE];
+ char buf2[MAX_RD_SIZE];
+ double refrate = 0.0;
+ inst_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Measure the refresh rate */
+ rv = dtp92_command(p, "00103RM\r", buf, MAX_RD_SIZE, 5.0);
+
+ if (rv != inst_ok) {
+ if ((rv & inst_imask) == DTP92_NO_DATA_AVAILABLE)
+ rv = inst_misread;
+ return rv;
+ }
+
+ if (sscanf(buf, "Hz %lf ", &refrate) != 1) {
+ a1logd(p->log, 1, "dtp92_read_refrate rate: failed to parse string '%s'\n",buf);
+ *ref_rate = 0.0;
+ return inst_misread;
+ }
+ if (refrate == 0.0) {
+ return inst_misread;
+ }
+ *ref_rate = refrate;
+ return inst_ok;
+}
+
+/* Insert a colorimetric correction matrix in the instrument XYZ readings */
+/* This is only valid for colorimetric instruments. */
+/* To remove the matrix, pass NULL for the filter filename */
+static inst_code dtp92_col_cor_mat(
+inst *pp,
+double mtx[3][3]
+) {
+ dtp92 *p = (dtp92 *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (mtx == NULL)
+ icmSetUnity3x3(p->ccmat);
+ else
+ icmCpy3x3(p->ccmat, mtx);
+
+ return inst_ok;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code dtp92_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ dtp92 *p = (dtp92 *)pp;
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if (p->itype == instDTP92) {
+ if (p->need_ratio_cal)
+ n_cals |= inst_calt_emis_ratio;
+ a_cals |= inst_calt_emis_ratio;
+ }
+
+ if (p->need_offset_cal)
+ n_cals |= inst_calt_emis_offset;
+ a_cals |= inst_calt_emis_offset;
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+/* This is use if the user decides they want to do a calibration */
+/* in anticipation of a calibration (needs_calibration()) to avoid */
+/* requiring one during measurement, or in response to measuring */
+/* returning inst_needs_cal. Initially use an inst_cal_cond of inst_calc_none, */
+/* and then be prepared to setup the right conditions, or ask the */
+/* user to do so, each time the error inst_cal_setup is returned. */
+static inst_code dtp92_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ dtp92 *p = (dtp92 *)pp;
+ char buf[MAX_RD_SIZE];
+ inst_code ev = inst_ok;
+ inst_cal_type needed, available;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ id[0] = '\000';
+
+ if ((ev = dtp92_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"dtp92_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return inst_unsupported;
+ }
+
+ if (*calt & inst_calt_emis_offset) { /* Dark offset calibration */
+
+ if (*calc != inst_calc_man_em_dark) {
+ *calc = inst_calc_man_em_dark;
+ return inst_cal_setup;
+ }
+
+ /* Do offset calibration */
+ if ((ev = dtp92_command(p, "CO\r", buf, MAX_RD_SIZE, 12)) != inst_ok)
+ return ev;
+
+ *calt &= inst_calt_emis_offset;
+ }
+
+ if (*calt & inst_calt_emis_ratio) { /* Cell ratio calibration */
+
+ if (*calc != inst_calc_emis_grey
+ && *calc != inst_calc_emis_grey_darker
+ && *calc != inst_calc_emis_grey_ligher) {
+ *calc = inst_calc_emis_grey;
+ return inst_cal_setup;
+ }
+
+ /* Do ratio calibration */
+ if ((ev = dtp92_command(p, "CR\r", buf, MAX_RD_SIZE, 25.0)) != inst_ok) {
+
+ if ((ev & inst_imask) == DTP92_TOO_MUCH_LIGHT) {
+ *calc = inst_calc_emis_grey_darker;
+ return inst_cal_setup;
+ } else if ((ev & inst_imask) == DTP92_NOT_ENOUGH_LIGHT) {
+ *calc = inst_calc_emis_grey_ligher;
+ return inst_cal_setup;
+ }
+ return ev; /* Error */
+ }
+ *calt &= inst_calt_emis_ratio;
+ }
+
+ return ev;
+}
+
+/* Return the last reading refresh rate in Hz. */
+static inst_code dtp92_get_refr_rate(inst *pp,
+double *ref_rate
+) {
+ dtp92 *p = (dtp92 *)pp;
+ char buf[MAX_RD_SIZE];
+ char buf2[MAX_RD_SIZE];
+ double refrate = 0.0;
+ inst_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Get the last readings refresh rate */
+ rv = dtp92_command(p, "10103RM\r", buf, MAX_RD_SIZE, 5.0);
+
+ if (rv != inst_ok) {
+ if ((rv & inst_imask) == DTP92_NO_DATA_AVAILABLE)
+ rv = inst_misread;
+ return rv;
+ }
+
+ if (sscanf(buf, "Hz %lf ", &refrate) != 1) {
+ a1logd(p->log, 1, "dtp92_read_refresh rate: failed to parse string '%s'\n",buf);
+ *ref_rate = 0.0;
+ return inst_misread;
+ }
+ if (refrate == 0.0) {
+ return inst_misread;
+ }
+ *ref_rate = refrate;
+ return inst_ok;
+}
+
+/* Set the calibrated refresh rate in Hz. */
+/* Set refresh rate to 0.0 to mark it as invalid */
+/* Rates outside the range 5.0 to 150.0 Hz will return an error */
+static inst_code dtp92_set_refr_rate(inst *pp,
+double ref_rate
+) {
+ dtp92 *p = (dtp92 *)pp;
+
+ /* The DTP92 can't have a refresh rate set */
+ return inst_unsupported;
+}
+
+/* Error codes interpretation */
+static char *
+dtp92_interp_error(inst *pp, int ec) {
+// dtp92 *p = (dtp92 *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case DTP92_INTERNAL_ERROR:
+ return "Internal software error";
+ case DTP92_COMS_FAIL:
+ return "Communications failure";
+ case DTP92_UNKNOWN_MODEL:
+ return "Not a DTP92 or DTP94";
+ case DTP92_DATA_PARSE_ERROR:
+ return "Data from DTP didn't parse as expected";
+
+ case DTP92_OK:
+ return "No device error";
+
+ case DTP92_BAD_COMMAND:
+ return "Unrecognized command";
+ case DTP92_PRM_RANGE:
+ return "Command parameter out of range";
+ case DTP92_MEMORY_OVERFLOW:
+ return "Memory bounds error";
+ case DTP92_INVALID_BAUD_RATE:
+ return "Invalid baud rate";
+ case DTP92_TIMEOUT:
+ return "Receive timeout";
+ case DTP92_SYNTAX_ERROR:
+ return "Badly formed parameter";
+ case DTP92_NO_DATA_AVAILABLE:
+ return "No data available";
+ case DTP92_MISSING_PARAMETER:
+ return "Paramter is missing";
+ case DTP92_CALIBRATION_DENIED:
+ return "Invalid calibration enable code";
+ case DTP92_NEEDS_OFFSET_CAL:
+ return "Offset calibration checksum failed";
+ case DTP92_NEEDS_RATIO_CAL:
+ return "Ratio calibration checksum failed";
+ case DTP92_NEEDS_LUMINANCE_CAL:
+ return "Luminance calibration checksum failed";
+ case DTP92_NEEDS_WHITE_POINT_CAL:
+ return "White point calibration checksum failed";
+ case DTP92_NEEDS_BLACK_POINT_CAL:
+ return "Black point calibration checksum failed";
+ case DTP92_NEEDS_OFFSET_DRIFT_CAL:
+ return "Offset drift calibration checksum failed";
+ case DTP92_INVALID_READING:
+ return "Unable to take a reading";
+ case DTP92_BAD_COMP_TABLE:
+ return "Bad compensation table";
+ case DTP92_TOO_MUCH_LIGHT:
+ return "Too much light entering instrument";
+ case DTP92_NOT_ENOUGH_LIGHT:
+ return "Not enough light to complete operation";
+
+ case DTP92_BAD_SERIAL_NUMBER:
+ return "New serial number is invalid";
+
+ case DTP92_NO_MODULATION:
+ return "No refresh modulation detected";
+
+ case DTP92_EEPROM_FAILURE:
+ return "EEprom write failure";
+ case DTP92_FLASH_WRITE_FAILURE:
+ return "Flash memory write failure";
+ case DTP92_BAD_CONFIGURATION:
+ return "Configuration data checksum failed";
+ case DTP92_INST_INTERNAL_ERROR:
+ return "Internal instrument error";
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+dtp92_interp_code(inst *pp, int ec) {
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case DTP92_OK:
+ return inst_ok;
+
+ case DTP92_INTERNAL_ERROR:
+ return inst_internal_error | ec;
+
+ case DTP92_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case DTP92_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+ case DTP92_DATA_PARSE_ERROR:
+ return inst_protocol_error | ec;
+
+ case DTP92_NO_MODULATION: /* ?? */
+ case DTP92_TOO_MUCH_LIGHT:
+ case DTP92_NOT_ENOUGH_LIGHT:
+ case DTP92_INVALID_READING:
+ return inst_misread | ec;
+
+ case DTP92_NEEDS_OFFSET_CAL:
+ return inst_needs_cal | ec;
+
+ case DTP92_NEEDS_RATIO_CAL:
+ return inst_needs_cal | ec;
+
+ case DTP92_NEEDS_LUMINANCE_CAL:
+ case DTP92_NEEDS_WHITE_POINT_CAL:
+ case DTP92_NEEDS_BLACK_POINT_CAL:
+ case DTP92_NEEDS_OFFSET_DRIFT_CAL:
+ return inst_hardware_fail | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+dtp92_del(inst *pp) {
+ dtp92 *p = (dtp92 *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ inst_del_disptype_list(p->dtlist, p->ndtlist);
+ free(p);
+}
+
+/* Return the instrument mode capabilities */
+void dtp92_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ dtp92 *p = (dtp92 *)pp;
+ inst_mode cap1 = 0;
+ inst2_capability cap2 = 0;
+
+ cap1 |= inst_mode_emis_spot
+ | inst_mode_colorimeter
+ ;
+
+ cap2 |= inst2_prog_trig
+ | inst2_user_trig
+ | inst2_ccmx
+ ; /* The '92 does have a switch, but we're not currently supporting it */
+
+ if (p->itype == instDTP94) {
+ cap2 |= inst2_disptype;
+ } else {
+ cap2 |= inst2_refresh_rate;
+ cap2 |= inst2_emis_refr_meas;
+ }
+
+ if (pcap1 != NULL)
+ *pcap1 = cap1;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Check device measurement mode */
+inst_code dtp92_check_mode(inst *pp, inst_mode m) {
+ inst_mode cap;
+
+ if (!pp->gotcoms)
+ return inst_no_coms;
+ if (!pp->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* Only display emission mode supported */
+ if (!IMODETST(m, inst_mode_emis_spot)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code dtp92_set_mode(inst *pp, inst_mode m) {
+ inst_code ev;
+
+ if ((ev = dtp92_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+inst_disptypesel dtp92_disptypesel[2] = {
+ {
+ inst_dtflags_default, /* flags */
+ 2, /* cbid */
+ "c", /* sel */
+ "CRT display", /* desc */
+ 1, /* refr */
+ 0 /* ix */
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+inst_disptypesel dtp94_disptypesel[4] = {
+ {
+ inst_dtflags_default,
+ 1,
+ "l",
+ "LCD display",
+ 0,
+ 2
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 2, /* cbid */
+ "c", /* sel */
+ "CRT display", /* desc */
+ 1, /* refr */
+ 1 /* ix */
+ },
+ {
+ inst_dtflags_none,
+ 3,
+ "g",
+ "Generic display",
+ 0, /* Might be auto refresh detect ? */
+ 0
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+static void set_base_disptype_list(dtp92 *p) {
+ if (p->itype == instDTP94) {
+ p->_dtlist = dtp94_disptypesel;
+ } else {
+ p->_dtlist = dtp92_disptypesel;
+ }
+}
+
+/* Get mode and option details */
+static inst_code dtp92_get_disptypesel(
+inst *pp,
+int *pnsels, /* Return number of display types */
+inst_disptypesel **psels, /* Return the array of display types */
+int allconfig, /* nz to return list for all configs, not just current. */
+int recreate /* nz to re-check for new ccmx & ccss files */
+) {
+ dtp92 *p = (dtp92 *)pp;
+ inst_code rv = inst_ok;
+
+ /* Create/Re-create a current list of abailable display types */
+ if (p->dtlist == NULL || recreate) {
+ if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ p->_dtlist, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return rv;
+ }
+
+ if (pnsels != NULL)
+ *pnsels = p->ndtlist;
+
+ if (psels != NULL)
+ *psels = p->dtlist;
+
+ return inst_ok;
+}
+
+/* Given a display type entry, setup for that type */
+static inst_code set_disp_type(dtp92 *p, inst_disptypesel *dentry) {
+
+ p->icx = dentry->ix;
+ p->cbid = dentry->cbid;
+ p->refrmode = dentry->refr;
+
+ if (p->itype == instDTP92) {
+ if (p->icx != 0)
+ return inst_unsupported;
+
+ } else { /* DTP94 */
+ static char buf[MAX_MES_SIZE];
+ inst_code ev;
+
+ if (p->icx == 0) { /* Generic/Non-specific */
+ if ((ev = dtp92_command(p, "0016CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ } else if (p->icx == 1) { /* CRT */
+ if ((ev = dtp92_command(p, "0116CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ } else if (p->icx == 2) { /* LCD */
+ if ((ev = dtp92_command(p, "0216CF\r", buf, MAX_MES_SIZE, 0.2)) != inst_ok)
+ return ev;
+ } else {
+ return inst_unsupported;
+ }
+ }
+
+ if (dentry->flags & inst_dtflags_ccmx) {
+ icmCpy3x3(p->ccmat, dentry->mat);
+ } else {
+ icmSetUnity3x3(p->ccmat);
+ }
+
+ return inst_ok;
+}
+
+/* Setup the default display type */
+static inst_code set_default_disp_type(dtp92 *p) {
+ inst_code ev;
+ int i;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist,
+ p->_dtlist, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) {
+ if (p->dtlist[i].flags & inst_dtflags_default)
+ break;
+ }
+ if (p->dtlist[i].flags & inst_dtflags_end) {
+ a1loge(p->log, 1, "set_default_disp_type: failed to find type!\n");
+ return inst_internal_error;
+ }
+ if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/* Set the display type */
+static inst_code dtp92_set_disptype(inst *pp, int ix) {
+ dtp92 *p = (dtp92 *)pp;
+ inst_code ev;
+ inst_disptypesel *dentry;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ p->_dtlist, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ if (ix < 0 || ix >= p->ndtlist)
+ return inst_unsupported;
+
+ dentry = &p->dtlist[ix];
+
+ if ((ev = set_disp_type(p, dentry)) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * set or reset an optional mode
+ *
+ * Some options talk to the instrument, and these will
+ * error if it hasn't been initialised.
+ */
+static inst_code
+dtp92_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ dtp92 *p = (dtp92 *)pp;
+ char buf[MAX_MES_SIZE];
+ inst_code ev = inst_ok;
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user) {
+ p->trig = m;
+ return inst_ok;
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Get the display type information */
+ if (m == inst_opt_get_dtinfo) {
+ va_list args;
+ int *refrmode, *cbid;
+
+ va_start(args, m);
+ refrmode = va_arg(args, int *);
+ cbid = va_arg(args, int *);
+ va_end(args);
+
+ if (refrmode != NULL)
+ *refrmode = p->refrmode;
+ if (cbid != NULL)
+ *cbid = p->cbid;
+
+ return inst_ok;
+ }
+
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern dtp92 *new_dtp92(icoms *icom, instType itype) {
+ dtp92 *p;
+ if ((p = (dtp92 *)calloc(sizeof(dtp92),1)) == NULL) {
+ a1loge(icom->log, 1, "new_dtp92: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = dtp92_init_coms;
+ p->init_inst = dtp92_init_inst;
+ p->capabilities = dtp92_capabilities;
+ p->check_mode = dtp92_check_mode;
+ p->set_mode = dtp92_set_mode;
+ p->get_disptypesel = dtp92_get_disptypesel;
+ p->set_disptype = dtp92_set_disptype;
+ p->get_set_opt = dtp92_get_set_opt;
+ p->read_sample = dtp92_read_sample;
+ p->read_refrate = dtp92_read_refrate;
+ p->get_n_a_cals = dtp92_get_n_a_cals;
+ p->calibrate = dtp92_calibrate;
+ p->col_cor_mat = dtp92_col_cor_mat;
+ p->get_refr_rate = dtp92_get_refr_rate;
+ p->set_refr_rate = dtp92_set_refr_rate;
+ p->interp_error = dtp92_interp_error;
+ p->del = dtp92_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */
+ set_base_disptype_list(p);
+
+ return p;
+}
+
diff --git a/spectro/dtp92.h b/spectro/dtp92.h
new file mode 100644
index 0000000..7add3e0
--- /dev/null
+++ b/spectro/dtp92.h
@@ -0,0 +1,103 @@
+#ifndef DTP92_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Xrite DTP92/94 related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 5/6/2001
+ *
+ * Copyright 2001 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Note: update dtp92_interp_error() and dtp92_interp_code() in dtp92.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define DTP92_INTERNAL_ERROR 0x61 /* Internal software error */
+#define DTP92_COMS_FAIL 0x62 /* Communication failure */
+#define DTP92_UNKNOWN_MODEL 0x63 /* Not a DPT92 */
+#define DTP92_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error code */
+#define DTP92_OK 0x00
+
+#define DTP92_BAD_COMMAND 0x01
+#define DTP92_PRM_RANGE 0x02
+#define DTP92_MEMORY_OVERFLOW 0x04
+#define DTP92_INVALID_BAUD_RATE 0x05 /* 92 only */
+#define DTP92_TIMEOUT 0x07
+#define DTP92_SYNTAX_ERROR 0x08
+#define DTP92_NO_DATA_AVAILABLE 0x0B
+#define DTP92_MISSING_PARAMETER 0x0C
+#define DTP92_CALIBRATION_DENIED 0x0D
+#define DTP92_NEEDS_OFFSET_CAL 0x16
+#define DTP92_NEEDS_RATIO_CAL 0x17 /* 92 only */
+#define DTP92_NEEDS_LUMINANCE_CAL 0x18
+#define DTP92_NEEDS_WHITE_POINT_CAL 0x19
+#define DTP92_NEEDS_BLACK_POINT_CAL 0x1A
+#define DTP92_NEEDS_OFFSET_DRIFT_CAL 0x1B /* 94 only */
+#define DTP92_INVALID_READING 0x20
+#define DTP92_BAD_COMP_TABLE 0x25
+#define DTP92_TOO_MUCH_LIGHT 0x28
+#define DTP92_NOT_ENOUGH_LIGHT 0x29
+
+#define DTP92_BAD_SERIAL_NUMBER 0x40
+
+#define DTP92_NO_MODULATION 0x50 /* 92 only */
+
+#define DTP92_EEPROM_FAILURE 0x70
+#define DTP92_FLASH_WRITE_FAILURE 0x71
+#define DTP92_BAD_CONFIGURATION 0x72 /* 94 only */
+#define DTP92_INST_INTERNAL_ERROR 0x7F /* 92 only */
+
+
+/* DTP92 communication object */
+struct _dtp92 {
+ INST_OBJ_BASE
+
+ inst_disptypesel *_dtlist; /* Base list */
+ inst_disptypesel *dtlist; /* Display Type list */
+ int ndtlist; /* Number of valid dtlist entries */
+ int icx; /* Internal calibration index, 0 = CRT, 1 = LCD */
+ int cbid; /* calibration base ID, 0 if not a base */
+ int refrmode; /* 0 for constant, 1 for refresh display */
+ double ccmat[3][3]; /* Colorimeter correction matrix */
+
+ int need_offset_cal; /* Flags to indicate type of calibration needed */
+ int need_ratio_cal;
+ inst_opt_type trig; /* Reading trigger mode */
+
+ }; typedef struct _dtp92 dtp92;
+
+/* Constructor */
+extern dtp92 *new_dtp92(icoms *icom, instType itype);
+
+
+#define DTP92_H
+#endif /* DTP92_H */
diff --git a/spectro/fakeread.c b/spectro/fakeread.c
new file mode 100644
index 0000000..df77930
--- /dev/null
+++ b/spectro/fakeread.c
@@ -0,0 +1,1025 @@
+/*
+ * Argyll Color Correction System
+ * Fake print target chart reader - use ICC or MPP profile rather than instrument
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/2/2002
+ *
+ * Copyright 2002 - 2013 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.
+ */
+
+/*
+ * TTBD:
+
+ Do we need to deterct & mark display values normalized to Y = 100 ??
+ */
+
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "icc.h"
+
+void usage(char *diag, ...) {
+ fprintf(stderr,"Fake test chart reader - lookup values in ICC/MPP profile, Version %s\n",
+ ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: fakeread [-v] [-s] [separation.icm] profile.[%s|mpp|ti3] outfile\n",ICC_FILE_EXT_ND);
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -s Lookup MPP spectral values\n");
+ fprintf(stderr," -p Use separation profile\n");
+ fprintf(stderr," -l Output Lab rather than XYZ\n");
+ fprintf(stderr," -k file.cal Apply calibration (after sep.) and include in .ti3\n");
+ fprintf(stderr," -i file.cal Include calibration in .ti3 (but don't apply it)\n");
+ fprintf(stderr," -r level Add average random deviation of <level>%% to input device values (after sep. & cal.)\n");
+ fprintf(stderr," -0 pow Apply power to input device chanel 0-9 (after sep. cal. & rand)\n");
+ fprintf(stderr," -R level Add average random deviation of <level>%% to output PCS values\n");
+ fprintf(stderr," -u Make random deviations have uniform distributions rather than normal\n");
+ fprintf(stderr," -S seed Set random seed\n");
+ fprintf(stderr," -b L,a,b Scale black point to target Lab value\n");
+ fprintf(stderr," -I intent r = relative colorimetric, a = absolute (default)\n");
+ fprintf(stderr," [separation.%s] Device link separation profile\n",ICC_FILE_EXT_ND);
+ fprintf(stderr," profile.[%s|mpp|ti3] ICC, MPP profile or TI3 to use\n",ICC_FILE_EXT_ND);
+ fprintf(stderr," outfile Base name for input[ti1]/output[ti3] file\n");
+ exit(1);
+ }
+
+int main(int argc, char *argv[])
+{
+ int j;
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0; /* Verbose flag */
+ int dosep = 0; /* Use separation before profile */
+ int dolab = 0; /* Output Lab rather than XYZ */
+ int gfudge = 0; /* Do grey fudge, 1 = W->RGB, 2 = K->xxxK */
+ double chpow[10] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };
+ double rdlevel = 0.0; /* Random device average deviation level (0.0 - 1.0) */
+ double rplevel = 0.0; /* Random PCS average deviation level (0.0 - 1.0) */
+ int unidist = 0; /* Use uniform distribution of errors */
+ unsigned int seed = time(NULL); /* Random seed value */
+ double tbp[3] = { -1.0, 0.0, 0.0 }; /* Target black point */
+ int applycal = 0; /* NZ to apply calibration */
+ static char sepname[MAXNAMEL+1] = { 0 }; /* ICC separation profile */
+ static char calname[MAXNAMEL+1] = { 0 }; /* device calibration */
+ static char profname[MAXNAMEL+1] = { 0 }; /* ICC or MPP Profile name */
+ static char inname[MAXNAMEL+1] = { 0 }; /* Input cgats file base name */
+ static char outname[MAXNAMEL+1] = { 0 }; /* Output cgats file base name */
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ int nmask = 0; /* Test chart device colorant mask */
+ int nchan = 0; /* Test chart number of device chanels */
+ int npat; /* Number of patches */
+ int si; /* Sample id index */
+ int ti; /* Temp index */
+ int fi; /* Colorspace index */
+ int inti3 = 0; /* Input is a renamed .ti3 file rather than .ti1 */
+
+ /* ICC separation device link profile */
+ icmFile *sep_fp = NULL; /* Color profile file */
+ icc *sep_icco = NULL; /* Profile object */
+ icmLuBase *sep_luo = NULL; /* Conversion object */
+ icColorSpaceSignature sep_ins, sep_outs; /* Type of input and output spaces */
+ int sep_inn; /* Number of input channels to separation */
+ inkmask sep_nmask = 0; /* Colorant mask for separation input */
+ double wp[3], bp[3]; /* ICC profile Lab white and black points */
+ double bpt[3][3]; /* Black point transform matrix (Lab->Lab) */
+
+ /* Calibration */
+ xcal *cal = NULL; /* calibration */
+
+ /* ICC profile based */
+ icRenderingIntent intent = icAbsoluteColorimetric;
+ icmFile *icc_fp = NULL; /* Color profile file */
+ icc *icc_icco = NULL; /* Profile object */
+ icmLuBase *icc_luo = NULL; /* Conversion object */
+
+ /* MPP profile based */
+ mpp *mlu = NULL; /* Conversion object */
+ instType itype = instUnknown; /* Type of instrument used */
+ int dospec = 0; /* Do spectral MPP lookup */
+ int spec_n = 0; /* Number of spectral bands */
+ double spec_wl_short;/* First reading wavelength in nm (shortest) */
+ double spec_wl_long; /* Last reading wavelength in nm (longest) */
+
+ /* TI3 based fake read */
+ cgats *ti3 = NULL; /* input cgats structure */
+ int ti3_npat = 0; /* Number of patches in reference file */
+ int ti3_chix[ICX_MXINKS]; /* Device chanel indexes */
+ int ti3_pcsix[3]; /* Device chanel indexes */
+ int ti3_spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ int ti3_isLab = 0; /* Flag indicating PCS for TI3 file */
+
+ int rv = 0;
+ int inn, outn; /* Number of channels for conversion input, output */
+ icColorSpaceSignature ins, outs; /* Type of conversion input and output spaces */
+ inkmask cnv_nmask = 0; /* Conversion input nmask */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+ char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
+
+ error_program = "Fakeread";
+ if (argc < 3)
+ usage("Too few arguments");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else
+ {
+ if ((fa+1) < argc)
+ {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ /* Verbose */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ /* Spectral MPP lookup */
+ else if (argv[fa][1] == 's')
+ dospec = 1;
+
+ /* Separation */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P')
+ dosep = 1;
+
+ /* Lab */
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L')
+ dolab = 1;
+
+ /* Uniform distrivuted errors */
+ else if (argv[fa][1] == 'u' || argv[fa][1] == 'U')
+ unidist = 1;
+
+ /* Random seed value */
+ else if (argv[fa][1] == 'S') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -S");
+ if (sscanf(na, " %u ",&seed) != 1)
+ usage("Couldn't parse argument to -S");
+ }
+
+ /* calibration to device values */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'i') {
+ if (argv[fa][1] == 'k')
+ applycal = 1;
+ else
+ applycal = 0;
+ fa = nfa;
+ if (na == NULL) usage("Expected an argument to -%c",argv[fa][1]);
+ strncpy(calname,na,MAXNAMEL); calname[MAXNAMEL] = '\000';
+ }
+
+ /* Random addition to device levels */
+ else if (argv[fa][1] == 'r') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -r");
+ rdlevel = atof(na) * 0.01;
+ }
+
+ /* Power applied to device channels */
+ else if (argv[fa][1] >= '0' && argv[fa][1] <= '9') {
+ int ch;
+ if (na == NULL) usage("Expect argument to -[0-9]");
+ ch = argv[fa][1]-'0';
+ if (ch < 0 || ch > 9)
+ usage("Channel no. %d is out of range\n",ch);
+ chpow[ch] = atof(na);
+ fa = nfa;
+ }
+
+ /* Random addition to PCS levels */
+ else if (argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -R");
+ rplevel = atof(na) * 0.01;
+ }
+
+ /* Black point scale */
+ else if (argv[fa][1] == 'b' || argv[fa][1] == 'B') {
+ if (na == NULL) usage("Expect argument to -b");
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf ",&tbp[0], &tbp[1], &tbp[2]) != 3)
+ usage("Couldn't parse argument to -b");
+ if (tbp[0] < 0.0 || tbp[0] > 100.0) usage("-b L* value out of range");
+ if (tbp[1] < -128.0 || tbp[1] > 128.0) usage("-b a* value out of range");
+ if (tbp[2] < -128.0 || tbp[2] > 128.0) usage("-b b* value out of range");
+ }
+
+ /* Intent (only applies to ICC profile) */
+ else if (argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -I");
+ switch (na[0]) {
+ case 'r':
+ intent = icRelativeColorimetric;
+ break;
+ case 'a':
+ intent = icAbsoluteColorimetric;
+ break;
+ default:
+ usage("Unexpected argument value '%c' to -I optyion",na[0]);
+ }
+ }
+
+ else
+ usage("Unrecognised flag");
+ }
+ else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (dosep) {
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing separation profile filename argument");
+ strncpy(sepname,argv[fa++],MAXNAMEL); sepname[MAXNAMEL] = '\000';
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing profile filename argument");
+ strncpy(profname,argv[fa++],MAXNAMEL); profname[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing basename argument");
+ strncpy(inname,argv[fa],MAXNAMEL-4); inname[MAXNAMEL-4] = '\000';
+ strcat(inname,".ti1");
+ strncpy(outname,argv[fa],MAXNAMEL-4); outname[MAXNAMEL-4] = '\000';
+ strcat(outname,".ti3");
+
+ rand32(seed); /* Init seed */
+ /* Deal with separation */
+ if (dosep) {
+ if ((sep_fp = new_icmFileStd_name(sepname,"r")) == NULL)
+ error ("Can't open file '%s'",sepname);
+
+ if ((sep_icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* Deal with ICC separation */
+ if ((rv = sep_icco->read(sep_icco,sep_fp,0)) == 0) {
+
+ /* Get a conversion object */
+ if ((sep_luo = sep_icco->get_luobj(sep_icco, icmFwd, icmDefaultIntent, icmSigDefaultData, icmLuOrdNorm)) == NULL) {
+ error ("%d, %s",sep_icco->errc, sep_icco->err);
+ }
+
+ /* Get details of conversion */
+ sep_luo->spaces(sep_luo, &sep_ins, &sep_inn, &sep_outs, NULL, NULL, NULL, NULL, NULL, NULL);
+ sep_nmask = icx_icc_to_colorant_comb(sep_ins, sep_icco->header->deviceClass);
+ }
+ }
+
+ /* Deal with calibration */
+ if (calname[0] != '\000') {
+ if ((cal = new_xcal()) == NULL)
+ error("new_xcal failed");
+ if ((cal->read(cal, calname)) != 0)
+ error("%s",cal->err);
+ if (verb)
+ if (applycal)
+ printf("Applying calibration curves from '%s'\n",calname);
+ else
+ printf("Embedding calibration curves from '%s' in output\n",calname);
+ }
+
+ /* Deal with ICC profile */
+ if ((icc_fp = new_icmFileStd_name(profname,"r")) == NULL)
+ error ("Can't open file '%s'",profname);
+
+ if ((icc_icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* Deal with ICC profile */
+ if ((rv = icc_icco->read(icc_icco,icc_fp,0)) == 0) {
+
+ /* Embed any calibration in the output if it's present */
+ if (cal == NULL) {
+ applycal = 0;
+ cal = xiccReadCalTag(icc_icco);
+
+ if (verb && cal != NULL)
+ printf("Embedding calibration curves from ICC profile in output\n");
+ }
+
+ /* Get a Device to PCS conversion object */
+ if ((icc_luo = icc_icco->get_luobj(icc_icco, icmFwd, intent,
+ dolab ? icSigLabData : icSigXYZData, icmLuOrdNorm)) == NULL) {
+ if ((icc_luo = icc_icco->get_luobj(icc_icco, icmFwd, icmDefaultIntent,
+ dolab ? icSigLabData : icSigXYZData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",icc_icco->errc, icc_icco->err);
+ }
+
+ /* Get details of conversion */
+ icc_luo->spaces(icc_luo, &ins, &inn, &outs, &outn, NULL, NULL, NULL, NULL, NULL);
+ cnv_nmask = icx_icc_to_colorant_comb(ins, icc_icco->header->deviceClass);
+
+ if (dospec)
+ error("Can't lookup spectral values for ICC profile");
+
+ if (tbp[0] >= 0.0) {
+ double ss[3], tt[3];
+
+ icc_luo->wh_bk_points(icc_luo, wp, bp);
+ if (dolab) {
+ icmXYZ2Lab(&icmD50, wp, wp);
+ icmXYZ2Lab(&icmD50, bp, bp);
+ } else {
+ icmLab2XYZ(&icmD50, tbp, tbp);
+ }
+
+ /* Create scaling matrix */
+ for (j = 0; j < 3; j++) {
+ tt[j] = tbp[j] - wp[j];
+ ss[j] = bp[j] - wp[j];
+ }
+ icmRotMat(bpt, ss, tt);
+
+ if (verb) {
+ printf("White point = %f %f %f (%s)\n",wp[0],wp[1],wp[2], dolab ? "Lab" : "XYZ");
+ printf("Black point = %f %f %f (%s)\n",bp[0],bp[1],bp[2], dolab ? "Lab" : "XYZ");
+ printf("Target Black point = %f %f %f (%s)\n",tbp[0],tbp[1],tbp[2], dolab ? "Lab" : "XYZ");
+ }
+ }
+
+ } else { /* Not a valid ICC */
+ /* Close out the ICC profile */
+ icc_icco->del(icc_icco);
+ icc_icco = NULL;
+ icc_fp->del(icc_fp);
+ icc_fp = NULL;
+ icc_luo = NULL;
+ }
+
+ /* If we don't have an ICC lookup object, look for an MPP */
+ if (icc_luo == NULL) {
+
+ if ((mlu = new_mpp()) == NULL)
+ error ("Creation of MPP object failed");
+
+ if ((rv = mlu->read_mpp(mlu, profname)) == 0) {
+
+ /* mlu defaults to absolute XYZ lookup */
+ if (dolab) {
+ mlu->set_ilob(mlu, icxIT_default, NULL, icxOT_default, NULL, icSigLabData, 0);
+ }
+
+ mlu->get_info(mlu, &cnv_nmask, &inn, NULL,
+ &spec_n, &spec_wl_short, &spec_wl_long, &itype, NULL);
+
+ outn = 3;
+ outs = dolab ? icSigLabData : icSigXYZData;
+
+ if ((ins = icx_colorant_comb_to_icc(cnv_nmask)) == 0)
+ error ("Couldn't match MPP mask to valid ICC colorspace");
+
+ if (dospec && spec_n <= 0)
+ error("Can't lookup spectral values for non-spectral MPP profile");
+ } else {
+ mlu->del(mlu);
+ mlu = NULL;
+ }
+ }
+
+ /* If we don't have an ICC or MPP lookup object, look for a TI3 */
+ if (icc_luo == NULL && mlu == NULL) {
+ char *rbuf, *outc;
+ char *ti3_bident;
+ int ti3_nchan;
+
+ ti3 = new_cgats(); /* Create a CGATS structure */
+ ti3->add_other(ti3, "CTI3");/* our special input type is Calibration Target Information 3 */
+
+ if (ti3->read_name(ti3, profname))
+ error("CGATS file read error : %s",ti3->err);
+
+ if (ti3->ntables == 0 || ti3->t[0].tt != tt_other || ti3->t[0].oi != 0)
+ error ("Profile file '%s' isn't a CTI3 format file",profname);
+ if (ti3->ntables != 1)
+ error ("Input file '%s' doesn't contain one table",profname);
+
+ if ((ti = ti3->find_kword(ti3, 0, "COLOR_REP")) < 0)
+ error("Input file doesn't contain keyword COLOR_REP");
+
+ if ((rbuf = strdup(ti3->t[0].kdata[ti])) == NULL)
+ error("Malloc failed");
+
+ /* Split COLOR_REP into device and PCS space */
+ if ((outc = strchr(rbuf, '_')) == NULL)
+ error("COLOR_REP '%s' invalid", ti3->t[0].kdata[ti]);
+ *outc++ = '\000';
+
+ outn = 3;
+ if (strcmp(outc, "XYZ") == 0) {
+ ti3_isLab = 0;
+ outs = icSigXYZData;
+ } else if (strcmp(outc, "LAB") == 0) {
+ ti3_isLab = 1;
+ outs = icSigLabData;
+ } else
+ error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", ti3->t[0].kdata[ti]);
+
+ if ((cnv_nmask = icx_char2inkmask(rbuf)) == 0) {
+ error ("File '%s' keyword COLOR_REP has unknown device value '%s'",profname,rbuf);
+ }
+
+ free(rbuf);
+
+ if ((ins = icx_colorant_comb_to_icc(cnv_nmask)) == 0)
+ error ("Couldn't match MPP mask to valid ICC colorspace");
+
+ if ((inn = icmCSSig2nchan(ins)) == 0)
+ error ("TI3 Colorspace with unknown number of channels");
+
+ if ((ti3_npat = ti3->t[0].nsets) <= 0)
+ error ("No sets of data in reference TI3 file");
+
+ ti3_nchan = icx_noofinks(cnv_nmask);
+ ti3_bident = icx_inkmask2char(cnv_nmask, 0);
+
+ /* Find device fields */
+ for (j = 0; j < ti3_nchan; j++) {
+ int ii, imask;
+ char fname[100];
+
+ imask = icx_index2ink(cnv_nmask, j);
+ sprintf(fname,"%s_%s",cnv_nmask == ICX_W || cnv_nmask == ICX_K ? "GRAY" : ti3_bident,
+ icx_ink2char(imask));
+
+ if ((ii = ti3->find_field(ti3, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (ti3->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+ ti3_chix[j] = ii;
+ }
+
+ /* Find PCS fields */
+ for (j = 0; j < 3; j++) {
+ int ii;
+
+ if ((ii = ti3->find_field(ti3, 0, ti3_isLab ? labfname[j] : xyzfname[j])) < 0)
+ error ("Input file doesn't contain field %s",ti3_isLab ? labfname[j] : xyzfname[j]);
+ if (ti3->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",ti3_isLab ? labfname[j] : xyzfname[j]);
+ ti3_pcsix[j] = ii;
+ }
+
+ /* Find spectral fields */
+ if ((ti = ti3->find_kword(ti3, 0, "SPECTRAL_BANDS")) >= 0) {
+ char buf[100];
+
+ spec_n = atoi(ti3->t[0].kdata[ti]);
+ if ((ti = ti3->find_kword(ti3, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ spec_wl_short = atof(ti3->t[0].kdata[ti]);
+ if ((ti = ti3->find_kword(ti3, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ spec_wl_long = atof(ti3->t[0].kdata[ti]);
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(spec_wl_short + ((double)j/(spec_n-1.0))
+ * (spec_wl_long - spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((ti3_spi[j] = ti3->find_field(ti3, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",buf);
+ }
+ }
+
+ if (dospec && spec_n <= 0)
+ error("Can't lookup spectral values for non-spectral TI3 file");
+
+ free(ti3_bident);
+ }
+
+ /* Some sanity checking */
+ if (tbp[0] >= 0.0 && icc_luo == NULL)
+ error("Black scaling only works with ICC profile");
+
+ if (verb) {
+// printf("Random seed is %u\n",seed);
+
+ if (rdlevel > 0.0)
+ printf("Adding %.3f%% average deviation %s noise to device values\n",rdlevel * 100.0,unidist ? "uniform" : "normal");
+ for (j = 0; j < inn && j < 10; j++) {
+ if (chpow[j] != 1.0)
+ printf("Applying chan %d power %f\n",j,chpow[j]);
+ }
+ if (rplevel > 0.0)
+ printf("Adding %.3f%% average deviation %s noise to %s PCS values\n",rplevel * 100.0,unidist ? "uniform" : "normal", dolab ? "L*a*b*": "XYZ");
+ fflush(stdout);
+ }
+
+ /* Deal with input CGATS files */
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI1"); /* our special input type is Calibration Target Information 1 */
+ icg->add_other(icg, "CTI3"); /* also accept renamed .ti3 file */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || (icg->t[0].oi != 0 && icg->t[0].oi != 1))
+ error ("Input file isn't a CTI1 format file");
+ if (icg->t[0].oi == 1)
+ inti3 = 1; /* It's a renamed .ti3 file */
+ if (icg->ntables != 1 && icg->ntables != 2 && icg->ntables != 3)
+ error ("Input file doesn't contain one, two or three tables");
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ /* Figure out the color space of the .ti1 */
+ if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error ("Input file doesn't contain keyword COLOR_REP");
+
+ if (inti3) {
+ char *rbuf, *outc;
+
+ if ((rbuf = strdup(icg->t[0].kdata[fi])) == NULL)
+ error("Malloc failed");
+
+ /* Split COLOR_REP into device and PCS space */
+ if ((outc = strchr(rbuf, '_')) == NULL)
+ error("Input file '%s' COLOR_REP '%s' invalid", inname, icg->t[0].kdata[fi]);
+ *outc++ = '\000';
+
+ if ((nmask = icx_char2inkmask(rbuf)) == 0) {
+ error ("Input file '%s' keyword COLOR_REP has unknown device value '%s'",inname,rbuf);
+ }
+
+ free(rbuf);
+ } else {
+ if ((nmask = icx_char2inkmask(icg->t[0].kdata[fi])) == 0)
+ error ("Input file '%s' keyword COLOR_REP has unknown value '%s'",inname, icg->t[0].kdata[fi]);
+ }
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll fakeread", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ /* What sort of device this is */
+ if (ti3 != NULL) {
+ if ((ti = ti3->find_kword(ti3, 0, "DEVICE_CLASS")) < 0)
+ error("Input TI3 doesn't contain keyword DEVICE_CLASS");
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS",ti3->t[0].kdata[ti], NULL); /* Copy */
+ } else if (mlu != NULL) {
+ /* This is a guess. It may not be correct. */
+ if ((cnv_nmask & ICX_ADDITIVE) ^ (cnv_nmask & ICX_INVERTED)) {
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL);
+ if (nmask == ICX_IRGB)
+ warning("It's unusual to have an iRGB display device !");
+ } else {
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);
+ if (nmask == ICX_RGB)
+ warning("It's unusual to have an RGB printing device !");
+ }
+ } else { /* Assume ICC */
+ if (icc_icco->header->deviceClass == icSigDisplayClass) {
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL);
+ if (nmask == ICX_IRGB)
+ warning("It's unusual to have an iRGB display device !");
+ } else {
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);
+ if (nmask == ICX_RGB)
+ warning("It's unusual to have an RGB printing device !");
+ }
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "SINGLE_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "SINGLE_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "COMP_GREY_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "COMP_GREY_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "MULTI_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "MULTI_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "FULL_SPREAD_PATCHES")) >= 0)
+ ocg->add_kword(ocg, 0, "FULL_SPREAD_PATCHES",icg->t[0].kdata[ti], NULL);
+
+ if (icc_luo == NULL) { /* If MPP profile, we know what the target instrument is */
+ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(itype) , NULL);
+ }
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+
+ if ((si = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error ("Input file doesn't contain field SAMPLE_ID");
+
+ {
+ int i, j, ii;
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ char *ident, *bident;
+ int nsetel = 0;
+ cgats_set_elem *setel; /* Array of set value elements */
+
+ nchan = icx_noofinks(nmask);
+ ident = icx_inkmask2char(nmask, 1);
+ bident = icx_inkmask2char(nmask, 0);
+
+ /* Sanity check what we're going to do */
+ if (dosep) {
+
+ /* Check if sep ICC input is compatible with .ti1 */
+ if (nmask == ICX_W && sep_ins == icSigRgbData)
+ gfudge = 1;
+ else if (nmask == ICX_K && sep_ins == icSigCmykData)
+ gfudge = 2;
+ else if (icx_colorant_comb_match_icc(nmask, sep_ins) == 0) {
+ error("Separation ICC device space '%s' dosen't match TI1 '%s'",
+ icm2str(icmColorSpaceSignature, sep_ins),
+ ident); /* Should free(). */
+ }
+
+ /* Check if separation ICC output is compatible with ICC/MPP/TI3 conversion */
+ if (icc_luo != NULL) {
+ /* Check if icc is compatible with .ti1 */
+ if (sep_outs != ins)
+ error("ICC device space '%s' dosen't match Separation ICC '%s'",
+ icm2str(icmColorSpaceSignature, ins),
+ icm2str(icmColorSpaceSignature, sep_outs));
+ } else if (mlu != NULL) {
+ /* Check if mpp is compatible with .ti1 */
+ if (icx_colorant_comb_match_icc(cnv_nmask, sep_outs) == 0)
+ error("MPP device space '%s' doesn't match Separation ICC '%s'",
+ icx_inkmask2char(cnv_nmask, 1), /* Should free(). */
+ icm2str(icmColorSpaceSignature, sep_outs));
+ } else if (ti3 != NULL) {
+ /* Check if .ti3 is compatible with .ti1 */
+ if (icx_colorant_comb_match_icc(cnv_nmask, sep_outs) == 0)
+ error("TI3 device space '%s' doesn't match Separation ICC '%s'",
+ icx_inkmask2char(cnv_nmask, 1), /* Should free(). */
+ icm2str(icmColorSpaceSignature, sep_outs));
+ }
+ } else if (icc_luo != NULL) {
+ /* Check if icc is compatible with .ti1 */
+ if (nmask == ICX_W && ins == icSigRgbData)
+ gfudge = 1;
+ else if (nmask == ICX_K && ins == icSigCmykData)
+ gfudge = 2; /* Should allow for other colorant combo's that include black */
+ else if (icx_colorant_comb_match_icc(nmask, ins) == 0) {
+ error("ICC device space '%s' dosen't match TI1 '%s'",
+ icm2str(icmColorSpaceSignature, ins),
+ ident); // Should free().
+ }
+ } else if (mlu != NULL) {
+ /* Check if mpp is compatible with .ti1 */
+ if (nmask == ICX_W && (cnv_nmask == ICX_RGB || cnv_nmask == ICX_IRGB))
+ gfudge = 1;
+ else if (nmask == ICX_K && (cnv_nmask & ICX_BLACK))
+ gfudge = 2;
+ else if (cnv_nmask != nmask)
+ error("MPP device space '%s' doesn't match TI1 '%s'",
+ icx_inkmask2char(cnv_nmask, 1), ident); // Should free().
+ } else if (ti3 != NULL) {
+ /* Check if .ti3 is compatible with .ti1 */
+ if (nmask == ICX_W && (cnv_nmask == ICX_RGB || cnv_nmask == ICX_IRGB))
+ gfudge = 1;
+ else if (nmask == ICX_K && (cnv_nmask & ICX_BLACK))
+ gfudge = 2;
+ else if (cnv_nmask != nmask)
+ error("TI3 device space '%s' doesn't match TI1 '%s'",
+ icx_inkmask2char(cnv_nmask, 1), ident); // Should free().
+ }
+
+ if ((ii = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0)
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT",icg->t[0].kdata[ii], NULL);
+
+ nsetel += 1; /* For id */
+ nsetel += nchan; /* For device values */
+ nsetel += 3; /* For XYZ/Lab */
+
+ for (j = 0; j < nchan; j++) {
+ int imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (icg->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+
+ ocg->add_field(ocg, 0, fname, r_t);
+ chix[j] = ii;
+ }
+
+ /* Add PCS fields */
+ for (j = 0; j < 3; j++) {
+ ocg->add_field(ocg, 0, dolab ? labfname[j] : xyzfname[j], r_t);
+ }
+
+ /* If we have spectral information, output it too */
+ if (dospec > 0 && spec_n > 0) {
+ char buf[100];
+
+ nsetel += spec_n; /* Spectral values */
+ sprintf(buf,"%d", spec_n);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+ sprintf(buf,"%f", spec_wl_short);
+ ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
+ sprintf(buf,"%f", spec_wl_long);
+ ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);
+
+ /* Generate fields for spectral values */
+ for (i = 0; i < spec_n; i++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(spec_wl_short + ((double)i/(spec_n-1.0))
+ * (spec_wl_long - spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+ ocg->add_field(ocg, 0, buf, r_t);
+ }
+ }
+
+ {
+ char fname[100];
+ sprintf(fname, dolab ? "%s_LAB" : "%s_XYZ", ident);
+ ocg->add_kword(ocg, 0, "COLOR_REP", fname, NULL);
+ }
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL)
+ error("Malloc failed!");
+
+ /* Read all the test patches in, convert them, */
+ /* and write them out. */
+ for (i = 0; i < npat; i++) {
+ int k = 0;
+ char *id;
+ double odev[ICX_MXINKS], dev[ICX_MXINKS], sep[ICX_MXINKS], PCS[3];
+ xspect out;
+
+ id = ((char *)icg->t[0].fdata[i][si]);
+ for (j = 0; j < nchan; j++) {
+ double dv = *((double *)icg->t[0].fdata[i][chix[j]]) / 100.0;
+ odev[j] = dev[j] = sep[j] = dv;
+ }
+
+ if (gfudge) {
+ int nch;
+
+ if (dosep) /* Figure number of channels into conversion */
+ nch = sep_inn;
+ else
+ nch = inn;
+
+ if (gfudge == 1) { /* Convert W -> RGB */
+ double wval = dev[0];
+ for (j = 0; j < nch; j++)
+ dev[j] = sep[j] = wval;
+
+ } else { /* Convert K->xxxK */
+ int kch;
+ int inmask;
+ double kval = dev[0];
+
+ if (dosep) /* Figure number of channels into conversion */
+ inmask = sep_nmask;
+ else
+ inmask = cnv_nmask;
+
+ if (inmask == 0)
+ error("Input colorspace ambiguous - can't determine if it has black");
+
+ if ((kch = icx_ink2index(inmask, ICX_BLACK)) == -1)
+ error("Can't find black colorant for K fudge");
+ for (j = 0; j < nch; j++) {
+ if (j == kch)
+ dev[j] = sep[j] = kval;
+ else
+ dev[j] = sep[j] = 0.0;
+ }
+ }
+ }
+
+ if (dosep)
+ if (sep_luo->lookup(sep_luo, sep, dev) > 1)
+ error ("%d, %s",icc_icco->errc,icc_icco->err);
+
+ /* Do calibration */
+ if (applycal && cal != NULL)
+ cal->interp(cal, sep, sep);
+
+ /* Add randomness and non-linearity to device values. */
+ /* rdlevel = avg. dev. */
+ /* Note dev/sep is 0-1.0 at this stage */
+ for (j = 0; j < inn; j++) {
+ double dv = sep[j];
+ if (rdlevel > 0.0) {
+ double rr;
+ if (unidist)
+ rr = d_rand(-2.0 * rdlevel, 2.0 * rdlevel);
+ else
+ rr = 1.2533 * rdlevel * norm_rand();
+ dv += rr;
+ if (dv < 0.0)
+ dv = 0.0;
+ else if (dv > 1.0)
+ dv = 1.0;
+ }
+ if (j < 10 && chpow[j] != 1.0) {
+ dv = pow(dv, chpow[j]);
+ }
+ sep[j] = dv;
+ }
+
+ /* Do color conversion */
+ if (icc_luo != NULL) {
+ if (icc_luo->lookup(icc_luo, PCS, sep) > 1)
+ error ("%d, %s",icc_icco->errc,icc_icco->err);
+
+ if (tbp[0] >= 0) { /* Doing black point scaling */
+
+ for (j = 0; j < 3; j++)
+ PCS[j] -= wp[j];
+ icmMulBy3x3(PCS, bpt, PCS);
+ for (j = 0; j < 3; j++)
+ PCS[j] += wp[j];
+ }
+
+ } else if (mlu != NULL) {
+ mlu->lookup(mlu, PCS, sep);
+ if (dospec && spec_n > 0) {
+ mlu->lookup_spec(mlu, &out, sep);
+ }
+ } else if (ti3 != NULL) {
+ int m;
+ double bdif = 1e6;
+ int bix = -1;
+
+ /* Search for the closest device values in TI3 file */
+ for (m = 0; m < ti3_npat; m++) {
+ double dif;
+
+ for (dif = 0.0, j = 0; j < nchan; j++) {
+ double xx;
+
+ xx = (*((double *)ti3->t[0].fdata[m][ti3_chix[j]]) / 100.0) - sep[j];
+ dif += xx * xx;
+ }
+ if (dif < bdif) {
+ bdif = dif;
+ bix = m;
+ }
+ }
+ /* Copy best value over */
+ if (!dosep) /* Doesn't make sense for separation */
+ for (j = 0; j < nchan; j++) {
+ dev[j] = *((double *)ti3->t[0].fdata[bix][ti3_chix[j]]) / 100.0;
+ }
+ for (j = 0; j < 3; j++) {
+ PCS[j] = *((double *)ti3->t[0].fdata[bix][ti3_pcsix[j]]);
+ }
+ if (ti3_isLab && !dolab) { /* Convert Lab to XYZ */
+ icmLab2XYZ(&icmD50, PCS, PCS);
+ } else if (!ti3_isLab && dolab) { /* Convert XYZ to Lab */
+ icmXYZ2Lab(&icmD50, PCS, PCS);
+ } else if (!ti3_isLab) { /* Convert XYZ100 to XYZ1 */
+ PCS[0] /= 100.0;
+ PCS[1] /= 100.0;
+ PCS[2] /= 100.0;
+ }
+ if (dospec && spec_n > 0) {
+ for (j = 0; j < spec_n; j++) {
+ out.spec[j] = *((double *)ti3->t[0].fdata[bix][ti3_spi[j]]);
+ }
+ }
+ }
+
+ setel[k++].c = id;
+
+ for (j = 0; j < nchan; j++)
+ setel[k++].d = 100.0 * odev[j];
+
+ if (dolab == 0) {
+ PCS[0] *= 100.0;
+ PCS[1] *= 100.0;
+ PCS[2] *= 100.0;
+ }
+
+ /* Add randomness. rplevel is avg. dev. */
+ /* Note PCS is 0..100 XYZ or Lab at this point */
+ if (rplevel > 0.0) {
+ double opcs[3];
+ for (j = 0; j < 3; j++) {
+ double dv = PCS[j];
+ double rr;
+ opcs[j] = dv;
+ if (unidist)
+ rr = 100.0 * d_rand(-2.0 * rplevel, 2.0 * rplevel);
+ else
+ rr = 100.0 * 1.2533 * rplevel * norm_rand();
+ dv += rr;
+
+ /* Don't let L*, X, Y or Z go negative */
+ if ((!dolab || j == 0) && dv < 0.0)
+ dv = 0.0;
+ PCS[j] = dv;
+ }
+//printf("~1 pcs %f %f %f -> %f %f %f\n", opcs[0], opcs[1], opcs[2], PCS[0], PCS[1], PCS[2]);
+ }
+
+ setel[k++].d = PCS[0];
+ setel[k++].d = PCS[1];
+ setel[k++].d = PCS[2];
+
+ if (dospec && spec_n > 0) {
+ for (j = 0; j < spec_n; j++) {
+ setel[k++].d = 100.0 * out.spec[j];
+ }
+ }
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+ free(ident);
+ free(bident);
+ }
+
+ if (sep_luo != NULL) {
+ sep_luo->del(sep_luo);
+ sep_icco->del(sep_icco);
+ sep_fp->del(sep_fp);
+ }
+
+ /* If there is a calibration, append it to the .ti3 file */
+ if (cal != NULL) {
+ if (cal->write_cgats(cal, ocg) != 0)
+ error("Writing cal error : %s",cal->err);
+ }
+
+ if (cal != NULL)
+ cal->del(cal);
+
+ if (icc_luo != NULL) {
+ /* Cleanup ICC profile */
+ icc_luo->del(icc_luo);
+ icc_icco->del(icc_icco);
+ icc_fp->del(icc_fp);
+ } else if (mlu != NULL) {
+ mlu->del(mlu);
+ } else if (ti3 != NULL) {
+ ti3->del(ti3);
+ }
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+
diff --git a/spectro/hcfr.c b/spectro/hcfr.c
new file mode 100644
index 0000000..9ec6be9
--- /dev/null
+++ b/spectro/hcfr.c
@@ -0,0 +1,878 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * HCFR Association HCFR sensor related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 20/1/2007
+ *
+ * Copyright 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "hcfr.h"
+
+static inst_code hcfr_interp_code(inst *pp, int ec);
+
+#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */
+
+/* ==================================================================== */
+
+/* Interpret an icoms error into a HCFR error */
+static int icoms2hcfr_err(int se) {
+ if (se != ICOM_OK)
+ return HCFR_COMS_FAIL;
+ return HCFR_OK;
+}
+
+/* Do a standard command/response echange with the hcfr */
+/* Return the dtp error code */
+static inst_code
+hcfr_command(
+ hcfr *p,
+ char *in, /* In string */
+ char *out, /* Out string */
+ int bsize, /* Out buffer size */
+ double to /* Timeout in seconds */
+) {
+ int rv, se;
+
+ if ((se = p->icom->write_read(p->icom, in, out, bsize, '\n', 1, to)) != 0) {
+ int ec;
+ a1logd(p->log, 1, "hcfr_command: serial i/o failure on write_read '%s'\n",icoms_fix(in));
+ return hcfr_interp_code((inst *)p, icoms2hcfr_err(se));
+ }
+ a1logd(p->log, 4, "hcfr_command: command '%s' returned '%s', value 0x%x\n",
+ icoms_fix(in), icoms_fix(out),HCFR_OK);
+ return hcfr_interp_code((inst *)p, HCFR_OK);
+}
+
+/* Do a break to check coms is working */
+inst_code
+hcfr_break(
+ hcfr *p
+) {
+ int rwbytes; /* Data bytes read or written */
+ int se, rv = inst_ok;
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_CLASS | IUSB_REQ_RECIP_INTERFACE,
+ 0x22, 0, 0, NULL, 0, 1.0);
+
+ rv = hcfr_interp_code((inst *)p, icoms2hcfr_err(se));
+
+ a1logd(p->log, 4, "hcfr_break: done, ICOM err 0x%x\n",se);
+
+ return rv;
+}
+
+/* Flush an pending messages from the device */
+inst_code
+hcfr_flush(
+ hcfr *p
+) {
+ icoms *c = p->icom;
+ char buf[MAX_MES_SIZE];
+ inst_code ev = inst_ok;
+ int rv;
+
+ for (rv = ICOM_OK;;) {
+ rv = c->read(c, buf, MAX_MES_SIZE, '\000', 100000, 0.05);
+ if (rv != ICOM_OK)
+ break; /* Expect timeout with nothing to read */
+ }
+ a1logd(p->log, 5, "hcfr_flush: done\n");
+
+ return inst_ok;
+}
+
+/* Get and check the firmware version */
+inst_code
+hcfr_get_check_version(
+ hcfr *p,
+ int *pmaj,
+ int *pmin
+) {
+ char ibuf[2];
+ char buf[MAX_MES_SIZE];
+ inst_code ev = inst_ok;
+ int maj, min;
+
+ a1logd(p->log, 4, "hcfr_get_check_version: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_internal_error;
+
+ ibuf[0] = HCFR_GET_VERS;
+ ibuf[1] = 0x00;
+
+ if ((ev = hcfr_command(p, ibuf, buf, MAX_MES_SIZE, 1.0)) != inst_ok)
+ return ev;
+
+ if (strlen(buf) < 6) {
+ a1logd(p->log, 1, "hcfr_get_check_version: version string too short\n");
+ return hcfr_interp_code((inst *)p, HCFR_BAD_FIRMWARE);
+ }
+
+ if (sscanf(buf, "v%d.%d", &maj,&min) != 2) {
+ a1logd(p->log, 1, "hcfr_get_check_version: version string doesn't match format\n");
+ return hcfr_interp_code((inst *)p, HCFR_BAD_FIRMWARE);
+ }
+
+ if (maj != HCFR_FIRMWARE_MAJOR_VERSION || min < HCFR_FIRMWARE_MINOR_VERSION) {
+ a1logd(p->log, 1, "hcfr_get_check_version: version string out of range\n");
+ return hcfr_interp_code((inst *)p, HCFR_BAD_FIRMWARE);
+ }
+
+ a1logd(p->log, 4, "hcfr_get_check_version: got firmare version %d.%d\n",maj,min);
+ if (pmaj != NULL)
+ *pmaj = maj;
+ if (pmin != NULL)
+ *pmin = min;
+
+ return inst_ok;
+}
+
+/* Get a raw measurement value */
+inst_code
+hcfr_get_rgb(
+ hcfr *p,
+ double rgb[3] /* return value */
+) {
+ char ibuf[2];
+ char buf[MAX_MES_SIZE], *bp;
+ char vbuf[4];
+ inst_code ev = inst_ok;
+ double mul, div;
+ double vals[8];
+ int onesens = 0;
+ int i;
+
+ a1logd(p->log, 3, "hcfr_get_rgb: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_internal_error;
+
+ ibuf[0] = HCFR_MEAS_RGB /* Read RGB */
+ | HCFR_MEAS_SENS0 /* Use one sensors because it's faster */
+// | HCFR_MEAS_SENS1
+ | HCFR_INTERLACE_0
+// | HCFR_FAST_MEASURE
+ ;
+
+ ibuf[1] = 0x00;
+
+ if ((ev = hcfr_command(p, ibuf, buf, MAX_MES_SIZE, 60.0)) != inst_ok) {
+ a1logd(p->log, 1, "hcfr_get_rgb: hcfr_command failed\n");
+ return ev;
+ }
+
+ if (strlen(buf) < 156) {
+ a1logd(p->log, 1, "hcfr_get_rgb: not enough bytes returned = expected %d, got %d\n",156,strlen(buf));
+ return hcfr_interp_code((inst *)p, HCFR_BAD_READING);
+ }
+
+ if (strncmp(buf, "RGB_1:", 6) == 0)
+ onesens = 1;
+ else if (strncmp(buf, "RGB_2:", 6) != 0) {
+ a1logd(p->log, 1, "hcfr_get_rgb: RGB_1 or RGB_2 not founde\n");
+ return hcfr_interp_code((inst *)p, HCFR_BAD_READING);
+ }
+
+ vbuf[3] = 0x00;
+ bp = buf + 6;
+
+ strncpy(vbuf, bp, 3); div = (double)atoi(vbuf); bp += 3;
+
+ strncpy(vbuf, bp, 3); mul = (double)atoi(vbuf); bp += 3;
+
+ /* Compute all the possible values for 4 colors and 2 sensors */
+ for (i = 0; i < 8; i++) {
+ unsigned int num, den;
+
+ strncpy(vbuf, bp, 3); den = atoi(vbuf); bp += 3;
+ strncpy(vbuf, bp, 3); den = (den << 8) + atoi(vbuf); bp += 3;
+ strncpy(vbuf, bp, 3); den = (den << 8) + atoi(vbuf); bp += 3;
+ strncpy(vbuf, bp, 3); den = (den << 8) + atoi(vbuf); bp += 3;
+
+ strncpy(vbuf, bp, 3); num = atoi(vbuf); bp += 3;
+ strncpy(vbuf, bp, 3); num = (num << 8) + atoi(vbuf); bp += 3;
+
+ if (den == 0) /* Hmm. */
+ vals[i] = -1.0;
+ else
+ vals[i] = 1e4 * (double)num * mul * div / (double)den;
+// a1logd(p->log, 6,"vals[%d] = %f = num %d * mul %f * div %f / den %d\n", i, vals[i], num,mul,div,den);
+ }
+ if (onesens) {
+ rgb[0] = vals[0];
+ rgb[1] = vals[1];
+ rgb[2] = vals[2];
+ } else {
+ rgb[0] = 0.5 * (vals[0] + vals[4]);
+ rgb[1] = 0.5 * (vals[1] + vals[5]);
+ rgb[2] = 0.5 * (vals[2] + vals[6]);
+ }
+ a1logd(p->log, 3, "hcfr_get_rgb: returning value %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ return inst_ok;
+}
+
+/* Compute the calibration matricies. */
+/* The basic calibration data is from my particular HCFR, measured */
+/* against one of my CRT and LCD displays, with the reference XYZ */
+/* derived from my i1pro. */
+inst_code
+hcfr_comp_matrix(
+ hcfr *p
+) {
+ double tmat[3][3];
+ double xmat[3][3];
+ double itmat[3][3];
+
+ /* CRT */
+
+ /* Red test patch, sensor then reference */
+ tmat[0][0] = 71.71880890;
+ tmat[1][0] = 8.53740337;
+ tmat[2][0] = 3.08216218;
+
+ xmat[0][0] = 21.988601;
+ xmat[1][0] = 12.131219;
+ xmat[2][0] = 1.312786;
+
+ /* Green test patch, sensor then reference */
+ tmat[0][1] = 6.26299108;
+ tmat[1][1] = 37.49843127;
+ tmat[2][1] = 15.91104086;
+
+ xmat[0][1] = 13.677691;
+ xmat[1][1] = 28.870823;
+ xmat[2][1] = 5.636190;
+
+ /* Blue test patch, sensor then reference */
+ tmat[0][2] = 1.30620298;
+ tmat[1][2] = 4.62894673;
+ tmat[2][2] = 27.57654019;
+
+ xmat[0][2] = 6.387302;
+ xmat[1][2] = 2.755360;
+ xmat[2][2] = 33.588242;
+
+ /* Compute the inverse */
+ if (icmInverse3x3(itmat, tmat))
+ return hcfr_interp_code((inst *)p, HCFR_CALIB_CALC);
+
+ /* Multiply by target values */
+ icmMul3x3_2(p->crt, xmat, itmat);
+
+ /* LCD */
+
+ /* Red test patch, sensor then reference */
+ tmat[0][0] = 39.94356609;
+ tmat[1][0] = 11.59679928;
+ tmat[2][0] = 8.18430397;
+
+ xmat[0][0] = 51.875052;
+ xmat[1][0] = 30.640815;
+ xmat[2][0] = 4.712397;
+
+ /* Green test patch, sensor then reference */
+ tmat[0][1] = 14.45920285;
+ tmat[1][1] = 33.82116329;
+ tmat[2][1] = 17.64558523;
+
+ xmat[0][1] = 37.482638;
+ xmat[1][1] = 64.670821;
+ xmat[2][1] = 14.554874;
+
+ /* Blue test patch, sensor then reference */
+ tmat[0][2] = 8.29727493;
+ tmat[1][2] = 17.95182031;
+ tmat[2][2] = 38.20123872;
+
+ xmat[0][2] = 25.098392;
+ xmat[1][2] = 23.719352;
+ xmat[2][2] = 108.134087;
+
+ /* Compute the inverse */
+ if (icmInverse3x3(itmat, tmat))
+ return hcfr_interp_code((inst *)p, HCFR_CALIB_CALC);
+
+ /* Multiply by target values */
+ icmMul3x3_2(p->lcd, xmat, itmat);
+
+ return inst_ok;
+}
+
+/* ==================================================================== */
+
+/* Establish communications with a HCFR */
+/* Return HCFR_COMS_FAIL on failure to establish communications */
+static inst_code
+hcfr_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ hcfr *p = (hcfr *) pp;
+ int rsize;
+ long etime;
+ int bi, i, se;
+ inst_code ev = inst_ok;
+ icomuflags usbflags = icomuf_no_open_clear | icomuf_detach;
+
+#if defined(__APPLE__) && defined(__i386__)
+ /* Except on Intel OS X 10.4/5 for some reasone. */
+ /* It would be good if the HCFR had a better USB implementation... */
+ usbflags &= ~icomuf_no_open_clear;
+#endif
+
+ a1logd(p->log, 2, "hcfr_init_coms: About to init USB\n");
+
+ if (p->icom->port_type(p->icom) != icomt_usb) {
+ a1logd(p->log, 1, "hcfr_init_coms: expect hcfr to be USB\n");
+ return hcfr_interp_code((inst *)p, HCFR_UNKNOWN_MODEL);
+ }
+
+ /* Set config, interface, "Serial" write & read end points */
+ /* Note if we clear halt the interface hangs */
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x03, 0x83, usbflags, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "hcfr_init_coms: set_usb_port failed ICOM err 0x%x\n",se);
+ return hcfr_interp_code((inst *)p, icoms2hcfr_err(se));
+ }
+
+ if ((ev = hcfr_break(p)) != inst_ok) {
+ a1logd(p->log, 1, "hcfr_init_coms: break failed\n");
+ return ev;
+ }
+ p->gotcoms = 1;
+
+ a1logd(p->log, 2, "hcfr_init_coms: inited coms OK\n");
+
+ return inst_ok;
+}
+
+static inst_code set_default_disp_type(hcfr *p);
+
+/* Initialise the HCFR */
+/* return non-zero on an error, with dtp error code */
+static inst_code
+hcfr_init_inst(inst *pp) {
+ hcfr *p = (hcfr *)pp;
+ static char buf[MAX_MES_SIZE];
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "hcfr_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_internal_error; /* Must establish coms before calling init */
+
+#ifndef NEVER /* Doesn't work with OSX ? */
+// hcfr_flush(p);
+#endif
+
+ if ((ev = hcfr_get_check_version(p, &p->maj, &p->min)) != inst_ok) {
+ a1logd(p->log, 1, "hcfr_init_inst: check_version failed\n");
+ return ev;
+ }
+
+ if ((ev = hcfr_comp_matrix(p)) != inst_ok) {
+ return ev;
+ }
+
+ p->trig = inst_opt_trig_user;
+
+ /* Setup the default display type */
+ if ((ev = set_default_disp_type(p)) != inst_ok) {
+ return ev;
+ }
+
+ p->inited = 1;
+ a1logd(p->log, 2, "hcfr_init_inst: instrument inited OK\n");
+
+ return inst_ok;
+}
+
+/* Read a single sample */
+/* Return the dtp error code */
+static inst_code
+hcfr_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ hcfr *p = (hcfr *)pp;
+ inst_code ev;
+ double rgb[3];
+ int user_trig = 0;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "hcfr: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* Abort */
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return ev; /* Abort */
+ }
+
+ if ((ev = hcfr_get_rgb(p, rgb)) != inst_ok)
+ return ev;
+
+ if (p->ix == 0) { /* LCD */
+ icmMulBy3x3(val->XYZ, p->lcd, rgb);
+
+ } else if (p->ix == 1) { /* CRT */
+ icmMulBy3x3(val->XYZ, p->crt, rgb);
+
+ } else { /* Raw */
+ val->XYZ[0] = rgb[0];
+ val->XYZ[1] = rgb[1];
+ val->XYZ[2] = rgb[2];
+ }
+
+ /* Apply the colorimeter correction matrix */
+ icmMulBy3x3(val->XYZ, p->ccmat, val->XYZ);
+
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+
+ val->loc[0] = '\000';
+ val->mtype = inst_mrt_emission;
+ val->XYZ_v = 1; /* These are absolute XYZ readings */
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (user_trig)
+ return inst_user_trig;
+ return inst_ok;
+}
+
+/* Insert a colorimetric correction matrix in the instrument XYZ readings */
+/* This is only valid for colorimetric instruments. */
+/* To remove the matrix, pass NULL for the filter filename */
+inst_code hcfr_col_cor_mat(
+inst *pp,
+double mtx[3][3]
+) {
+ hcfr *p = (hcfr *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (mtx == NULL) {
+ icmSetUnity3x3(p->ccmat);
+ } else {
+ if (p->cbid == 0) {
+ a1loge(p->log, 1, "hcfr: can't set col_cor_mat over non base display type\n");
+ inst_wrong_setup;
+ }
+ icmCpy3x3(p->ccmat, mtx);
+ }
+
+ return inst_ok;
+}
+
+/* Error codes interpretation */
+static char *
+hcfr_interp_error(inst *pp, int ec) {
+// hcfr *p = (hcfr *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case HCFR_INTERNAL_ERROR:
+ return "Internal software error";
+ case HCFR_COMS_FAIL:
+ return "Communications failure";
+ case HCFR_UNKNOWN_MODEL:
+ return "Not a HCFR or DTP52";
+ case HCFR_DATA_PARSE_ERROR:
+ return "Data from DTP didn't parse as expected";
+
+ case HCFR_OK:
+ return "No device error";
+
+ case HCFR_BAD_READING:
+ return "Invalid reading";
+
+ case HCFR_BAD_FIRMWARE:
+ return "Bad firmware version";
+
+ case HCFR_CALIB_CALC:
+ return "Error computing calibration matrix";
+
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+hcfr_interp_code(inst *pp, int ec) {
+ hcfr *p = (hcfr *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case HCFR_OK:
+ return inst_ok;
+
+ case HCFR_CALIB_CALC:
+ return inst_internal_error | ec;
+
+ case HCFR_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case HCFR_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+ case HCFR_DATA_PARSE_ERROR:
+ return inst_protocol_error | ec;
+
+ case HCFR_BAD_READING:
+ return inst_misread | ec;
+
+// case HCFR_NEEDS_OFFSET_CAL:
+// return inst_needs_cal | ec;
+
+ case HCFR_BAD_FIRMWARE:
+ return inst_hardware_fail | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+hcfr_del(inst *pp) {
+ hcfr *p = (hcfr *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ inst_del_disptype_list(p->dtlist, p->ndtlist);
+ free(p);
+}
+
+/* Return the instrument mode capabilities */
+void hcfr_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ hcfr *p = (hcfr *)pp;
+ inst_mode cap = 0;
+ inst2_capability cap2 = 0;
+
+ cap |= inst_mode_emis_spot
+ | inst_mode_colorimeter
+ ;
+
+ cap2 |= inst2_prog_trig
+ | inst2_user_trig
+ | inst2_disptype
+ | inst2_ccmx
+ ;
+
+ if (pcap1 != NULL)
+ *pcap1 = cap;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Check device measurement mode */
+inst_code hcfr_check_mode(inst *pp, inst_mode m) {
+ inst_mode cap;
+
+ if (!pp->gotcoms)
+ return inst_no_coms;
+ if (!pp->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* only display emission mode supported */
+ if (!IMODETST(m, inst_mode_emis_spot)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code hcfr_set_mode(inst *pp, inst_mode m) {
+ inst_code ev;
+
+ if ((ev = hcfr_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+inst_disptypesel hcfr_disptypesel[4] = {
+ {
+ inst_dtflags_default,
+ 0,
+ "l",
+ "LCD display",
+ 0,
+ 0
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 0, /* cbix */
+ "c", /* sel */
+ "CRT display", /* desc */
+ 0, /* refr */
+ 1 /* ix */
+ },
+ {
+ inst_dtflags_none,
+ 1,
+ "R",
+ "Raw Reading",
+ 0,
+ 2
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+/* Get mode and option details */
+static inst_code hcfr_get_disptypesel(
+inst *pp,
+int *pnsels, /* Return number of display types */
+inst_disptypesel **psels, /* Return the array of display types */
+int allconfig, /* nz to return list for all configs, not just current. */
+int recreate /* nz to re-check for new ccmx & ccss files */
+) {
+ hcfr *p = (hcfr *)pp;
+ inst_code rv = inst_ok;
+
+ /* Create/Re-create a current list of abailable display types */
+ if (p->dtlist == NULL || recreate) {
+ if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ hcfr_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return rv;
+ }
+
+ if (pnsels != NULL)
+ *pnsels = p->ndtlist;
+
+ if (psels != NULL)
+ *psels = p->dtlist;
+
+ return inst_ok;
+}
+
+/* Given a display type entry, setup for that type */
+static inst_code set_disp_type(hcfr *p, inst_disptypesel *dentry) {
+
+ p->ix = dentry->ix;
+ p->refrmode = dentry->refr;
+ p->cbid = dentry->cbid;
+
+ if (dentry->flags & inst_dtflags_ccmx) {
+ icmCpy3x3(p->ccmat, dentry->mat);
+ } else {
+ icmSetUnity3x3(p->ccmat);
+ }
+
+ return inst_ok;
+}
+
+/* Setup the default display type */
+static inst_code set_default_disp_type(hcfr *p) {
+ inst_code ev;
+ int i;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist,
+ hcfr_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) {
+ if (p->dtlist[i].flags & inst_dtflags_default)
+ break;
+ }
+ if (p->dtlist[i].flags & inst_dtflags_end) {
+ a1loge(p->log, 1, "set_default_disp_type: failed to find type!\n");
+ return inst_internal_error;
+ }
+ if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/* Set the display type */
+static inst_code hcfr_set_disptype(inst *pp, int ix) {
+ hcfr *p = (hcfr *)pp;
+ inst_code ev;
+ inst_disptypesel *dentry;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ hcfr_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ if (ix < 0 || ix >= p->ndtlist)
+ return inst_unsupported;
+
+ dentry = &p->dtlist[ix];
+
+ if ((ev = set_disp_type(p, dentry)) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * set or reset an optional mode
+ *
+ * Since there is no interaction with the instrument,
+ * was assume that all of these can be done before initialisation.
+ */
+static inst_code
+hcfr_get_set_opt(inst *pp, inst_opt_type m, ...) {
+ hcfr *p = (hcfr *)pp;
+ inst_code ev = inst_ok;
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user) {
+ p->trig = m;
+ return inst_ok;
+ }
+
+ /* Get the display type information */
+ if (m == inst_opt_get_dtinfo) {
+ va_list args;
+ int *refrmode, *cbid;
+
+ va_start(args, m);
+ refrmode = va_arg(args, int *);
+ cbid = va_arg(args, int *);
+ va_end(args);
+
+ if (refrmode != NULL)
+ *refrmode = p->refrmode;
+ if (cbid != NULL)
+ *cbid = p->cbid;
+
+ return inst_ok;
+ }
+
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern hcfr *new_hcfr(icoms *icom, instType itype) {
+ hcfr *p;
+ if ((p = (hcfr *)calloc(sizeof(hcfr),1)) == NULL) {
+ a1loge(icom->log, 1, "new_hcfr: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = hcfr_init_coms;
+ p->init_inst = hcfr_init_inst;
+ p->capabilities = hcfr_capabilities;
+ p->check_mode = hcfr_check_mode;
+ p->set_mode = hcfr_set_mode;
+ p->get_disptypesel = hcfr_get_disptypesel;
+ p->set_disptype = hcfr_set_disptype;
+ p->get_set_opt = hcfr_get_set_opt;
+ p->read_sample = hcfr_read_sample;
+ p->col_cor_mat = hcfr_col_cor_mat;
+ p->interp_error = hcfr_interp_error;
+ p->del = hcfr_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */
+
+ return p;
+}
+
+
diff --git a/spectro/hcfr.h b/spectro/hcfr.h
new file mode 100644
index 0000000..efbbd6c
--- /dev/null
+++ b/spectro/hcfr.h
@@ -0,0 +1,102 @@
+#ifndef HCFR_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Colorimtre HCFR related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 20/1/2007
+ *
+ * Copyright 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Required minimum firmware version */
+#define HCFR_FIRMWARE_MAJOR_VERSION 5
+#define HCFR_FIRMWARE_MINOR_VERSION 0
+
+
+/* Command byte contents. (A value of 0x00 won't be tranmsitted properly) */
+/* 0xff = get firmware version */
+
+
+#define HCFR_MEAS_RGB 0x01 /* Enable reading RGB sensor values */
+#define HCFR_MEAS_WHITE 0x02 /* Enable reading White values */
+#define HCFR_MEAS_SENS0 0x04 /* Read sensor 0 */
+#define HCFR_MEAS_SENS1 0x08 /* Read sensor 1 */
+#define HCFR_INTERLACE_0 0x00 /* No interlace */
+#define HCFR_INTERLACE_1 0x10 /* 2 way interlace ? */
+#define HCFR_INTERLACE_2 0x20 /* 4 way interlace ?? */
+#define HCFR_INTERLACE_3 0x30 /* ? way interlace ??? */
+#define HCFR_FAST_MEASURE 0x40 /* Fast measure */
+
+#define HCFR_GET_VERS 0xFF /* Get the firmware version number */
+
+/* Note: update hcfr_interp_error() and hcfr_interp_code() in hcfr.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define HCFR_INTERNAL_ERROR 0x61 /* Internal software error */
+#define HCFR_COMS_FAIL 0x62 /* Communication failure */
+#define HCFR_UNKNOWN_MODEL 0x63 /* Not an HCFR */
+#define HCFR_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error code */
+#define HCFR_OK 0x00
+
+#define HCFR_BAD_FIRMWARE 0x01 /* Bad firmware version */
+
+#define HCFR_BAD_READING 0x30 /* Error doing or parsing reading */
+
+#define HCFR_CALIB_CALC 0x40 /* Error computing calibration matrix */
+
+/* HCFR communication object */
+struct _hcfr {
+ INST_OBJ_BASE
+
+ int maj, min; /* Firmware version */
+
+ double lcd[3][3]; /* CRT RGB->XYZ transformation matrix */
+ double crt[3][3]; /* CRT RGB->XYZ transformation matrix */
+
+ inst_disptypesel *dtlist; /* Display Type list */
+ int ndtlist; /* Number of valid dtlist entries */
+ int ix; /* 0 = CRT, 1 = LCD, 2 = raw RGB from sensors */
+ int cbid; /* calibration base ID, 0 if not a base */
+ int refrmode; /* Refresh mode (always 0) */
+ double ccmat[3][3]; /* Colorimeter correction matrix */
+
+ inst_opt_type trig; /* Reading trigger mode */
+
+ }; typedef struct _hcfr hcfr;
+
+/* Constructor */
+extern hcfr *new_hcfr(icoms *icom, instType itype);
+
+
+#define HCFR_H
+#endif /* HCFR_H */
diff --git a/spectro/hidio.c b/spectro/hidio.c
new file mode 100644
index 0000000..595b707
--- /dev/null
+++ b/spectro/hidio.c
@@ -0,0 +1,866 @@
+
+ /* General USB HID I/O support */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2007/10/10
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * (Based on usbio.c)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ * TTBD:
+ * As usual, Apple seem to have deprecated the routines used here.
+ * See IOHIDDeviceGetReportWithCallback & IOHIDDeviceSetReportWithCallback
+ * for info on the replacements.
+ */
+
+/* These routines supliement the class code in ntio.c and unixio.c */
+/* with HID specific access routines for devices running on operating */
+/* systems where this is desirable. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <signal.h>
+#if defined(UNIX)
+#include <termios.h>
+#include <errno.h>
+#include <dirent.h>
+#endif
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#else
+#include "sa_config.h"
+#endif
+#include "numsup.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+
+#if defined(NT)
+#include <setupapi.h>
+#endif
+
+#if defined(UNIX_X11)
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <sys/types.h>
+#include <usbhid.h>
+#else /* assume Linux */
+# include <asm/types.h>
+# include <linux/hiddev.h>
+#endif
+#ifndef HID_MAX_USAGES /* Workaround Linux Bug ? */
+# define HID_MAX_USAGES 1024
+#endif
+#endif
+
+#if defined(NT)
+
+/* Declartions to enable HID access without using the DDK */
+
+typedef struct _HIDD_ATTRIBUTES {
+ ULONG Size;
+ USHORT VendorID;
+ USHORT ProductID;
+ USHORT VersionNumber;
+} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+
+void (WINAPI *pHidD_GetHidGuid)(OUT LPGUID HidGuid) = NULL;
+BOOL (WINAPI *pHidD_GetAttributes)(IN HANDLE HidDeviceObject, OUT PHIDD_ATTRIBUTES Attributes) = NULL;
+
+/* See if we can get the wanted function calls */
+/* Return nz if OK */
+static int setup_dyn_calls() {
+ static int dyn_inited = 0;
+
+ if (dyn_inited == 0) {
+ dyn_inited = 1;
+
+ pHidD_GetHidGuid = (void (WINAPI*)(LPGUID))
+ GetProcAddress(LoadLibrary("HID"), "HidD_GetHidGuid");
+ pHidD_GetAttributes = (BOOL (WINAPI*)(HANDLE, PHIDD_ATTRIBUTES))
+ GetProcAddress(LoadLibrary("HID"), "HidD_GetAttributes");
+
+ if (pHidD_GetHidGuid == NULL
+ || pHidD_GetAttributes == NULL)
+ dyn_inited = 0;
+ }
+ return dyn_inited;
+}
+
+#endif
+
+
+/* Add paths to USB connected instruments, to the existing */
+/* icompath paths in the icoms structure. */
+/* return com error */
+int hid_get_paths(icompaths *p) {
+
+ a1logd(p->log, 8, "hid_get_paths: called\n");
+
+#if defined(NT)
+ {
+ GUID HidGuid;
+ HDEVINFO hdinfo;
+ SP_DEVICE_INTERFACE_DATA did;
+#define DIDD_BUFSIZE sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + (sizeof(TCHAR)*MAX_PATH)
+ char *buf[DIDD_BUFSIZE];
+ PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)buf;
+ SP_DEVINFO_DATA dinfod;
+ int i;
+ unsigned int VendorID = 0, ProductID = 0;
+
+ /* Make sure we've dynamically linked */
+ if (setup_dyn_calls() == 0) {
+ a1loge(p->log, ICOM_SYS, "hid_get_paths() Dynamic linking to hid.dll failed\n");
+ return ICOM_SYS;
+ }
+
+ /* Get the device interface GUID for HIDClass devices */
+ (*pHidD_GetHidGuid)(&HidGuid);
+
+ /* Return device information for all devices of the HID class */
+ hdinfo = SetupDiGetClassDevs(&HidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+ if (hdinfo == INVALID_HANDLE_VALUE) {
+ a1loge(p->log, ICOM_SYS, "hid_get_paths() SetupDiGetClassDevs failed\n");
+ return ICOM_SYS;
+ }
+
+ /* Get each devices interface data in turn */
+ did.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)buf;
+ pdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+ dinfod.cbSize = sizeof(SP_DEVINFO_DATA);
+ for (i = 0; ; i++) {
+ instType itype;
+
+ if (SetupDiEnumDeviceInterfaces(hdinfo, NULL, &HidGuid, i, &did) == 0) {
+ if (GetLastError() == ERROR_NO_MORE_ITEMS) {
+ break;
+ }
+ a1loge(p->log, ICOM_SYS, "hid_get_paths() SetupDiEnumDeviceInterfaces failed\n");
+ return ICOM_SYS;
+ }
+ if (SetupDiGetDeviceInterfaceDetail(hdinfo, &did, pdidd, DIDD_BUFSIZE, NULL, &dinfod)
+ == 0) {
+ a1loge(p->log, ICOM_SYS, "hid_get_paths() SetupDiGetDeviceInterfaceDetail failed\n");
+ return ICOM_SYS;
+ }
+
+ /* Extract the vid and pid from the device path */
+ {
+ int gotid;
+ char *cp, buf[20];
+
+ for(gotid = 0;;) {
+ if ((cp = strchr(pdidd->DevicePath, 'v')) == NULL)
+ break;
+ if (strlen(cp) < 8)
+ break;
+ if (cp[1] != 'i' || cp[2] != 'd' || cp[3] != '_')
+ break;
+ memcpy(buf, cp + 4, 4);
+ buf[4] = '\000';
+ if (sscanf(buf, "%x", &VendorID) != 1)
+ break;
+ if ((cp = strchr(pdidd->DevicePath, 'p')) == NULL)
+ break;
+ if (strlen(cp) < 8)
+ break;
+ if (cp[1] != 'i' || cp[2] != 'd' || cp[3] != '_')
+ break;
+ memcpy(buf, cp + 4, 4);
+ buf[4] = '\000';
+ if (sscanf(buf, "%x", &ProductID) != 1)
+ break;
+ gotid = 1;
+ break;
+ }
+ if (!gotid) {
+ a1logd(p->log, 1, "found HID device '%s', inst %d but unable get PID and VID\n",pdidd->DevicePath, dinfod.DevInst);
+ continue;
+ }
+ }
+
+ /* If it's a device we're looking for */
+ if ((itype = inst_usb_match(VendorID, ProductID, 0)) != instUnknown) {
+ struct hid_idevice *hidd;
+ char pname[400];
+
+ /* Create human readable path/identification */
+ sprintf(pname,"hid:/%d (%s)", dinfod.DevInst, inst_name(itype));
+
+ a1logd(p->log, 2, "found HID device '%s', inst %d that we're looking for\n",pdidd->DevicePath, dinfod.DevInst);
+
+ if ((hidd = (struct hid_idevice *) calloc(sizeof(struct hid_idevice), 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "hid_get_paths() calloc failed!\n");
+ return ICOM_SYS;
+ }
+ if ((hidd->dpath = strdup(pdidd->DevicePath)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "hid_get_paths() calloc failed!\n");
+ return ICOM_SYS;
+ }
+
+ /* Add the path to the list */
+ p->add_hid(p, pname, VendorID, ProductID, 0, hidd, itype);
+
+ } else {
+ a1logd(p->log, 6, "found HID device '%s', inst %d but not one we're looking for\n",pdidd->DevicePath, dinfod.DevInst);
+ }
+ }
+
+ /* Now we're done with the hdifo */
+ if (SetupDiDestroyDeviceInfoList(hdinfo) == 0) {
+ a1loge(p->log, ICOM_SYS, "SetupDiDestroyDeviceInfoList failed\n");
+ return ICOM_SYS;
+ }
+ }
+#endif /* NT */
+
+#ifdef __APPLE__
+ {
+ kern_return_t kstat;
+ CFMutableDictionaryRef sdict; /* HID Device dictionary */
+ io_iterator_t mit; /* Matching itterator */
+
+ /* Get dictionary of HID devices */
+ if ((sdict = IOServiceMatching(kIOHIDDeviceKey)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "hid_get_paths() IOServiceMatching returned a NULL dictionary\n");
+ return ICOM_SYS;
+ }
+
+ /* Init itterator to find matching types. Consumes sdict reference */
+ if ((kstat = IOServiceGetMatchingServices(kIOMasterPortDefault, sdict, &mit))
+ != KERN_SUCCESS) {
+ a1loge(p->log, ICOM_SYS, "hid_get_paths() IOServiceGetMatchingServices returned %d\n", kstat);
+ return ICOM_SYS;
+ }
+
+ /* Find all the matching HID devices */
+ for (;;) {
+ io_object_t ioob; /* HID object found */
+ CFNumberRef vref, pref; /* HID Vendor and Product ID propeties */
+ CFNumberRef lidpref; /* Location ID properties */
+ unsigned int vid = 0, pid = 0, lid = 0;
+ instType itype;
+
+ if ((ioob = IOIteratorNext(mit)) == 0)
+ break;
+
+ /* Get the two properies we need. [ Doing IORegistryEntryCreateCFProperty() is much faster */
+ /* than IORegistryEntryCreateCFProperties() in some cases.] */
+ if ((vref = IORegistryEntryCreateCFProperty(ioob, CFSTR(kIOHIDVendorIDKey),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(vref, kCFNumberIntType, &vid);
+ CFRelease(vref);
+ }
+ if ((pref = IORegistryEntryCreateCFProperty(ioob, CFSTR(kIOHIDProductIDKey),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(pref, kCFNumberIntType, &pid);
+ CFRelease(pref);
+ }
+ if ((lidpref = IORegistryEntryCreateCFProperty(ioob, CFSTR("LocationID"),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(lidpref, kCFNumberIntType, &lid);
+ CFRelease(lidpref);
+ }
+
+ /* If it's a device we're looking for */
+ if ((itype = inst_usb_match(vid, pid, 0)) != instUnknown) {
+ struct hid_idevice *hidd;
+ char pname[400];
+
+ a1logd(p->log, 2, "found HID device '%s' lid 0x%x that we're looking for\n",inst_name(itype), lid);
+
+ /* Create human readable path/identification */
+ sprintf(pname,"hid%d: (%s)", lid >> 20, inst_name(itype));
+
+ if ((hidd = (struct hid_idevice *)calloc(sizeof(struct hid_idevice), 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "hid_get_paths calloc failed!\n");
+ return ICOM_SYS;
+ }
+ hidd->lid = lid;
+ hidd->ioob = ioob;
+ ioob = 0; /* Don't release it */
+
+ /* Add the path to the list */
+ p->add_hid(p, pname, vid, pid, 0, hidd, itype);
+ }
+ if (ioob != 0) /* If we haven't kept it */
+ IOObjectRelease(ioob); /* Release found object */
+ }
+ IOObjectRelease(mit); /* Release the itterator */
+ }
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11)
+
+ /* This is how we'd go about adding HID support for Linux, IF it */
+ /* was actually capable of communicating application composed reports - */
+ /* which it is not, so HID seems pretty busted on Linux.. */
+#ifdef NEVER
+ /* We need to scan for /dev/hiddev* or /dev/usb/hiddev* device names, */
+ /* and then read their vid & pid */
+ {
+ int i;
+ char *devds[] = { /* Typical locations hiddev will appear under */
+ "/dev",
+ "/dev/usb",
+ ""
+ };
+
+ /* For each possible device directory */
+ for (i = 0;;i++) {
+ DIR *dir;
+ struct dirent *dentry;
+
+ if (devds[i][0] == '\000')
+ break;
+ if ((dir = opendir(devds[i])) == NULL)
+ continue;
+ while ((dentry = readdir(dir)) != NULL) {
+ if (strncmp(dentry->d_name, "hiddev", 6) == 0) {
+ char dpath[PATH_MAX];
+ int fd;
+
+ strcpy(dpath, devds[i]);
+ strcat(dpath, "/");
+ strcat(dpath, dentry->d_name);
+// a1logd(p->log, 8, "found hid device '%s'\n",dpath);
+ /* Open it and see what VID and PID it is */
+ if ((fd = open(dpath, O_RDONLY)) >= 0) {
+ struct hiddev_devinfo hidinfo;
+ if (ioctl(fd, HIDIOCGDEVINFO, &hidinfo) < 0)
+ a1logd(p->log, 1, "Unable to get HID info for '%s'\n",dpath);
+ else {
+// a1logd(p->log, 8,"busnum = %d, devnum = %d, vid = 0x%x, pid = 0x%x\n",
+// hidinfo.busnum, hidinfo.devnum, hidinfo.vendor, hidinfo.product);
+ }
+ close(fd);
+ }
+// More hotplug/udev magic needed to make the device accesible !
+//else a1logd(p->log, 8,"failed to open '%s' err %d\n",dpath,fd);
+ }
+ }
+ closedir(dir);
+ }
+ }
+#endif /* NEVER */
+#endif /* UNIX_X11 */
+
+ a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+
+ return ICOM_OK;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Close an open HID port */
+/* If we don't do this, the port and/or the device may be left in an unusable state. */
+void hid_close_port(icoms *p) {
+
+ a1logd(p->log, 8, "hid_close_port: called\n");
+
+ if (p->is_open && p->hidd != NULL) {
+
+#if defined(NT)
+ CloseHandle(p->hidd->ols.hEvent);
+ CloseHandle(p->hidd->fh);
+#endif /* NT */
+
+#ifdef __APPLE__
+ IOObjectRelease(p->hidd->port);
+ p->hidd->port = 0;
+
+ if (p->hidd->evsrc != NULL)
+ CFRelease(p->hidd->evsrc);
+ p->hidd->evsrc = NULL;
+
+ p->hidd->rlr = NULL;
+
+ if ((*p->hidd->device)->close(p->hidd->device) != kIOReturnSuccess) {
+ a1loge(p->log, ICOM_SYS, "hid_close_port: closing HID port '%s' failed",p->name);
+ return;
+ }
+
+ if ((*p->hidd->device)->Release(p->hidd->device) != kIOReturnSuccess) {
+ a1loge(p->log, ICOM_SYS, "hid_close_port: Releasing HID port '%s' failed",p->name);
+ }
+ p->hidd->device = NULL;
+#endif /* __APPLE__ */
+
+ p->is_open = 0;
+ a1logd(p->log, 8, "hid_close_port: has been released and closed\n");
+ }
+
+ /* Find it and delete it from our static cleanup list */
+ usb_delete_from_cleanup_list(p);
+}
+
+
+/* Open an HID port for all our uses. */
+/* This always re-opens the port */
+/* return icom error */
+static int hid_open_port(
+icoms *p,
+icomuflags hidflags, /* Any special handling flags */
+int retries, /* > 0 if we should retry set_configuration (100msec) */
+char **pnames /* List of process names to try and kill before opening */
+) {
+ /* Make sure the port is open */
+ if (!p->is_open) {
+ a1logd(p->log, 8, "hid_open_port: about to open HID port '%s'\n",p->name);
+
+ p->uflags = hidflags;
+
+#if defined(NT)
+ {
+ int tries = 0;
+
+ for (tries = 0; retries >= 0; retries--, tries++) {
+ /* Open the device */
+ if ((p->hidd->fh = CreateFile(p->hidd->dpath, GENERIC_READ|GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL))
+ != INVALID_HANDLE_VALUE) {
+ memset(&p->hidd->ols,0,sizeof(OVERLAPPED));
+ if ((p->hidd->ols.hEvent = CreateEvent(NULL, 0, 0, NULL)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "hid_open_port: Failed to create HID "
+ "Event with %d'\n",GetLastError());
+ return ICOM_SYS;
+ }
+ break;
+ }
+ if (tries > 0 && pnames != NULL) {
+ /* Open failed. This could be the i1ProfileTray.exe */
+ kill_nprocess(pnames, p->log);
+ msec_sleep(100);
+ }
+ }
+ if (p->hidd->fh == INVALID_HANDLE_VALUE) {
+ a1loge(p->log, ICOM_SYS, "hid_open_port: Failed to open "
+ "HID '%s' with %d\n",GetLastError());
+ return ICOM_SYS;
+ }
+ }
+#endif /* NT */
+
+#ifdef __APPLE__
+ {
+ IOCFPlugInInterface **piif = NULL;
+ IOReturn result;
+ SInt32 score;
+
+ if ((result = IOCreatePlugInInterfaceForService(p->hidd->ioob, kIOHIDDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID, &piif, &score) != kIOReturnSuccess || piif == NULL)) {
+ a1loge(p->log, ICOM_SYS, "hid_open_port: Failed to get piif for "
+ "HID device '%s', result 0x%x, piif 0x%x\n",p->name,result,piif);
+ return ICOM_SYS;
+ }
+
+ p->hidd->device = NULL;
+ if ((*piif)->QueryInterface(piif,
+ CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID122), (LPVOID)&p->hidd->device)
+ != kIOReturnSuccess || p->hidd->device == NULL) {
+ a1loge(p->log, ICOM_SYS, "hid_open_port: Getting HID device '%s' failed",p->name);
+ return ICOM_SYS;
+ }
+ (*piif)->Release(piif); /* delete intermediate object */
+
+ if ((*p->hidd->device)->open(p->hidd->device, kIOHIDOptionsTypeSeizeDevice)
+ != kIOReturnSuccess) {
+ a1loge(p->log, ICOM_SYS, "hid_open_port: Opening HID device '%s' failed",p->name);
+ return ICOM_SYS;
+ }
+
+ /* Setup to handle interrupt read callbacks */
+ p->hidd->port = 0;
+ if ((*(p->hidd->device))->createAsyncPort(p->hidd->device, &p->hidd->port)
+ != kIOReturnSuccess || p->hidd->port == 0) {
+ a1loge(p->log, ICOM_SYS, "hid_open_port: Creating port on "
+ "HID device '%s' failed",p->name);
+ return ICOM_SYS;
+ }
+
+ p->hidd->evsrc = NULL;
+ if ((*(p->hidd->device))->createAsyncEventSource(p->hidd->device, &p->hidd->evsrc)
+ != kIOReturnSuccess || p->hidd->evsrc == NULL) {
+ a1loge(p->log, ICOM_SYS, "hid_open_port: Creating event source on "
+ "HID device '%s' failed",p->name);
+ return ICOM_SYS;
+ }
+
+ }
+#endif /* __APPLE__ */
+
+ p->is_open = 1;
+ a1logd(p->log, 8, "hid_open_port: HID port is now open\n");
+ }
+
+ /* Install the cleanup signal handlers, and add to our cleanup list */
+ usb_install_signal_handlers(p);
+
+ return ICOM_OK;
+}
+
+/* ========================================================= */
+
+#ifdef __APPLE__
+
+/* HID Interrupt callback for OS X */
+static void hid_read_callback(
+void *target,
+IOReturn result,
+void *refcon,
+void *sender,
+#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+uint32_t size
+#else
+UInt32 size
+#endif
+) {
+ icoms *p = (icoms *)target;
+
+ a1logd(p->log, 8, "HID callback called with size %d, result 0x%x\n",size,result);
+ p->hidd->result = result;
+ p->hidd->bread = size;
+ CFRunLoopStop(p->hidd->rlr); /* We're done */
+}
+
+#endif /* __APPLE__ */
+
+/* HID Interrupt pipe Read */
+/* Don't retry on a short read, return ICOM_SHORT. */
+/* [Probably uses the control pipe. We need a different */
+/* call for reading messages from the interrupt pipe] */
+static int
+icoms_hid_read(icoms *p,
+ unsigned char *rbuf, /* Read buffer */
+ int bsize, /* Bytes to read */
+ int *breadp, /* Bytes read */
+ double tout /* Timeout in seconds */
+) {
+ int retrv = ICOM_OK; /* Returned error value */
+ int bread = 0;
+
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_read: device not initialised\n");
+ return ICOM_SYS;
+ }
+
+#if defined(NT)
+ {
+ unsigned char *rbuf2;
+
+ /* Create a copy of the data recieved with one more byte */
+ if ((rbuf2 = malloc(bsize + 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_read: malloc failed\n");
+ return ICOM_SYS;
+ }
+ rbuf2[0] = 0;
+ if (ReadFile(p->hidd->fh, rbuf2, bsize+1, (LPDWORD)&bread, &p->hidd->ols) == 0) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ retrv = ICOM_USBR;
+ } else {
+ int res;
+ res = WaitForSingleObject(p->hidd->ols.hEvent, (int)(tout * 1000.0 + 0.5));
+ if (res == WAIT_FAILED) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_read: HID wait on read failed\n");
+ return ICOM_SYS;
+ } else if (res == WAIT_TIMEOUT) {
+ CancelIo(p->hidd->fh);
+ retrv = ICOM_TO;
+ bread = 0;
+ } else {
+ bread = p->hidd->ols.InternalHigh;
+ }
+ }
+ }
+ if (bread > 0)
+ bread--;
+ memmove(rbuf,rbuf2+1,bsize);
+ free(rbuf2);
+ }
+#endif /* NT */
+
+#ifdef __APPLE__
+#ifndef NEVER
+ {
+ IOReturn result;
+
+ /* Setup for callback */
+ p->hidd->result = -1;
+ p->hidd->bread = 0;
+
+ if ((*(p->hidd->device))->setInterruptReportHandlerCallback(p->hidd->device,
+ rbuf, bsize, hid_read_callback, (void *)p, NULL) != kIOReturnSuccess) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_read: Setting callback handler for "
+ "HID '%s' failed\n", p->name);
+ return ICOM_SYS;
+ }
+ /* Call runloop, but exit after handling one callback */
+ p->hidd->rlr = CFRunLoopGetCurrent();
+ CFRunLoopAddSource(p->hidd->rlr, p->hidd->evsrc, kCFRunLoopDefaultMode);
+
+ if ((*(p->hidd->device))->startAllQueues(p->hidd->device) != kIOReturnSuccess) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_read: Starting queues for "
+ "HID '%s' failed\n", p->name);
+ return ICOM_SYS;
+ }
+
+ result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, tout, false);
+
+ if ((*(p->hidd->device))->stopAllQueues(p->hidd->device) != kIOReturnSuccess) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_read: Stopping queues for "
+ "HID '%s' failed\n", p->name);
+ return ICOM_SYS;
+ }
+ if (result == kCFRunLoopRunTimedOut) {
+ retrv = ICOM_TO;
+ } else if (result != kCFRunLoopRunStopped) {
+ retrv = ICOM_USBR;
+ }
+ CFRunLoopRemoveSource(p->hidd->rlr, p->hidd->evsrc, kCFRunLoopDefaultMode);
+
+ if (p->hidd->result == -1) { /* Callback wasn't called */
+ retrv = ICOM_TO;
+ } else if (p->hidd->result != kIOReturnSuccess) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_read: Callback for "
+ "HID '%s' got unexpected return value\n", p->name);
+ return ICOM_SYS;
+ }
+ bread = p->hidd->bread;
+ }
+#else // NEVER
+ /* This doesn't work. Don't know why */
+ /* Returns 0xe000404f = kIOUSBPipeStalled, Pipe has stalled, error needs to be cleared */
+ {
+ IOReturn result;
+ if ((result = (*p->hidd->device)->getReport(
+ p->hidd->device,
+ kIOHIDReportTypeInput,
+ 9, /* Bulk or Interrupt transfer */
+ (void *)rbuf,
+ (UInt32 *)&bsize,
+ (unsigned int)(tout * 1000.0 + 0.5),
+ NULL, NULL, NULL)
+ ) != kIOReturnSuccess) {
+ /* (We could detect other error codes and translate them to ICOM) */
+ if (result == kIOReturnTimeout)
+ retrv = ICOM_TO;
+ else
+ retrv = ICOM_USBW;
+ } else {
+ bread = bsize;
+ }
+ }
+#endif // NEVER
+#endif /* __APPLE__ */
+
+ if (breadp != NULL)
+ *breadp = bread;
+
+ a1logd(p->log, 8, "icoms_hid_read: About to return hid read %d bytes, ICOM err 0x%x\n",
+ bread, retrv);
+
+ return retrv;
+}
+
+/* - - - - - - - - - - - - - */
+
+/* HID Command Pipe Write */
+/* Don't retry on a short read, return ICOM_SHORT. */
+static int
+icoms_hid_write(icoms *p,
+ unsigned char *wbuf, /* Write buffer */
+ int bsize, /* Bytes to write */
+ int *bwrittenp, /* Bytes written */
+ double tout /* Timeout in seconds */
+) {
+ int retrv = ICOM_OK; /* Returned error value */
+ int bwritten = 0;
+
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_write: device not initialised\n");
+ return ICOM_SYS;
+ }
+
+#if defined(NT)
+ {
+ unsigned char *wbuf2;
+
+ /* Create a copy of the data to send with one more byte */
+ if ((wbuf2 = malloc(bsize + 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_write: malloc failed\n");
+ return ICOM_SYS;
+ }
+ memmove(wbuf2+1,wbuf,bsize);
+ wbuf2[0] = 0; /* Extra report ID byte (why ?) */
+ if (WriteFile(p->hidd->fh, wbuf2, bsize+1, (LPDWORD)&bwritten, &p->hidd->ols) == 0) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ retrv = ICOM_USBW;
+ } else {
+ int res;
+ res = WaitForSingleObject(p->hidd->ols.hEvent, (int)(tout * 1000.0 + 0.5));
+ if (res == WAIT_FAILED) {
+ a1loge(p->log, ICOM_SYS, "icoms_hid_write: HID wait on write failed\n");
+ return ICOM_SYS;
+ }
+ else if (res == WAIT_TIMEOUT) {
+ CancelIo(p->hidd->fh);
+ retrv = ICOM_TO;
+ bwritten = 0;
+ } else {
+ bwritten = p->hidd->ols.InternalHigh;
+ }
+ }
+ }
+ if (bwritten > 0)
+ bwritten--;
+
+ free(wbuf2);
+ }
+#endif /* NT */
+
+#ifdef __APPLE__
+ {
+ IOReturn result;
+ if ((result = (*p->hidd->device)->setReport(
+ p->hidd->device,
+ kIOHIDReportTypeOutput,
+ 9, /* Bulk or Interrupt transfer */
+ (void *)wbuf,
+ bsize,
+ (unsigned int)(tout * 1000.0 + 0.5),
+ NULL, NULL, NULL)) != kIOReturnSuccess) {
+ /* (We could detect other error codes and translate them to ICOM) */
+ if (result == kIOReturnTimeout)
+ retrv = ICOM_TO;
+ else
+ retrv = ICOM_USBW;
+ } else {
+ bwritten = bsize;
+ }
+ }
+#endif /* __APPLE__ */
+
+ if (bwrittenp != NULL)
+ *bwrittenp = bwritten;
+
+ a1logd(p->log, 8, "icoms_hid_write: wrote %d bytes, ICOM err 0x%x\n",bwritten, retrv);
+
+ return retrv;
+}
+
+/* ------------------------------------------------- */
+/* Set the hid port number and characteristics. */
+/* This may be called to re-establish a connection that has failed */
+/* return icom error */
+static int
+icoms_set_hid_port(
+icoms *p,
+icomuflags hidflags, /* Any special handling flags */
+int retries, /* > 0 if we should retry set_configuration (100msec) */
+char **pnames /* List of process names to try and kill before opening */
+) {
+ int rv = ICOM_OK;
+
+ a1logd(p->log, 8, "icoms_set_hid_port: About to set HID port characteristics\n");
+
+ if (p->is_open)
+ p->close_port(p);
+
+ if (p->port_type(p) == icomt_hid) {
+
+ if ((rv = hid_open_port(p, hidflags, retries, pnames)) != ICOM_OK)
+ return rv;
+
+ p->write = NULL;
+ p->read = NULL;
+
+ }
+ a1logd(p->log, 8, "icoms_set_hid_port: HID port characteristics set ok\n");
+
+ return rv;
+}
+
+/* Copy hid_idevice contents from icompaths to icom */
+/* return icom error */
+int hid_copy_hid_idevice(icoms *d, icompath *s) {
+
+ if (s->hidd == NULL) {
+ d->hidd = NULL;
+ return ICOM_OK;
+ }
+
+ if ((d->hidd = calloc(sizeof(struct hid_idevice), 1)) == NULL) {
+ a1loge(d->log, ICOM_SYS, "hid_copy_hid_idevice: malloc failed\n");
+ return ICOM_SYS;
+ }
+
+#if defined(NT)
+ if ((d->hidd->dpath = strdup(s->hidd->dpath)) == NULL) {
+ a1loge(d->log, ICOM_SYS, "hid_copy_hid_idevice: malloc\n");
+ return ICOM_SYS;
+ }
+#endif
+#if defined(__APPLE__)
+ d->hidd->ioob = s->hidd->ioob;
+ IOObjectRetain(d->hidd->ioob);
+#endif
+#if defined (UNIX_X11)
+#endif
+ return ICOM_OK;
+}
+
+/* Cleanup and then free a hid_del_hid_idevice */
+void hid_del_hid_idevice(struct hid_idevice *hidd) {
+ if (hidd == NULL)
+ return;
+
+#if defined(NT)
+ if (hidd->dpath != NULL)
+ free(hidd->dpath);
+#endif
+#if defined(__APPLE__)
+ if (hidd->ioob != 0)
+ IOObjectRelease(hidd->ioob);
+#endif
+#if defined (UNIX_X11)
+#endif
+ free(hidd);
+}
+
+/* Cleanup any HID specific icoms info */
+void hid_del_hid(icoms *p) {
+ hid_del_hid_idevice(p->hidd);
+}
+
+
+/* ---------------------------------------------------------------------------------*/
+
+/* Set the HID specific icoms methods */
+void hid_set_hid_methods(
+icoms *p
+) {
+ p->set_hid_port = icoms_set_hid_port;
+ p->hid_read = icoms_hid_read;
+ p->hid_write = icoms_hid_write;
+}
+
+/* ---------------------------------------------------------------------------------*/
diff --git a/spectro/hidio.h b/spectro/hidio.h
new file mode 100644
index 0000000..b25fe03
--- /dev/null
+++ b/spectro/hidio.h
@@ -0,0 +1,87 @@
+
+#ifndef HIDIO_H
+
+ /* General USB HID I/O support */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2007/10/10
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/* These routines supliement the class code in ntio.c and unixio.c */
+
+#ifdef __APPLE__
+#include <sys/param.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/hid/IOHIDLib.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif /* __APPLE__ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Add or modify paths to USB HID connected instruments, to the existing */
+/* icompath paths in the icoms structure, if HID access is supported. */
+/* return icom error */
+int hid_get_paths(struct _icompaths *p);
+
+void hid_close_port(icoms *p);
+
+/* Set the HID specific icoms methods */
+void hid_set_hid_methods(icoms *p);
+
+/* Copy hid_idevice contents */
+/* return icom error */
+int hid_copy_hid_idevice(icoms *d, icompath *s);
+
+/* Cleanup and then free a hid_del_hid_idevice */
+void hid_del_hid_idevice(struct hid_idevice *dev);
+
+/* Cleanup any HID specific icoms info */
+void hid_del_hid(icoms *p);
+
+/* Opaque structure to hid OS dependent HID details */
+struct hid_idevice {
+#if defined(NT)
+ char *dpath; /* Device path */
+ /* Stuff setup when device is open: */
+ HANDLE fh; /* File handle for write/read */
+ OVERLAPPED ols; /* Overlapped structure for write/read */
+#endif
+#if defined(__APPLE__)
+ int lid; /* Location ID */
+ io_object_t ioob; /* Object to open */
+ /* Stuff setup when device is open: */
+ IOHIDDeviceInterface122 **device; /* OS X HID device we've opened */
+ mach_port_t port; /* Other stuff present when opened */
+ CFRunLoopSourceRef evsrc;
+ CFRunLoopRef rlr;
+ IOReturn result;
+ int bread; /* Bytes read by callback */
+#endif
+#if defined (UNIX) && !defined(__APPLE__)
+ int temp; /* Shut the compiler up */
+#endif
+};
+
+/* Cleanup and then free an hidd entry */
+void hid_del_hid_idevice(struct hid_idevice *hidd);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define HIDIO_H
+#endif /* HIDIO_H */
+
diff --git a/spectro/huey.c b/spectro/huey.c
new file mode 100644
index 0000000..f8d8308
--- /dev/null
+++ b/spectro/huey.c
@@ -0,0 +1,1663 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * GretagMacbeth Huey related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 18/10/2006
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * (Based on i1disp.c)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "huey.h"
+
+#define dbgo stderr
+
+static inst_code huey_interp_code(inst *pp, int ec);
+static inst_code huey_check_unlock(huey *p);
+
+#define CALFACTOR 3.428 /* Emissive magic calibration factor */
+#define AMB_SCALE_FACTOR 5.772e-3 /* Ambient mode scale factor */
+ /* This is only approximate, and were derived */
+ /* by matching readings from the i1pro. */
+
+/* ------------------------------------------------------------------------ */
+/* Implementation */
+
+/* Interpret an icoms error into a HUEY error */
+/* If torc is nz, then a trigger or command is OK, */
+/* othewise they are treated as an abort. */
+static int icoms2huey_err(int se, int torc) {
+ if (se != ICOM_OK)
+ return HUEY_COMS_FAIL;
+ return HUEY_OK;
+}
+
+/* i1Display command codes */
+/* B = byte (8bit), S = short (16bit), W = word (32bit), A = string */
+/* U = unused byte, - = no arguments/results */
+/* The is a 7 byte command buffer and 6 response recieve buffer. */
+/* :2 means the read is from a second 8 byte ep x81 read. */
+/* cbuf[-] is command byte */
+/* rbuf[-2] is continuation byte */
+/* rbuf[-1] is echo of command byte */
+/* rbuf2[-2] is an error byte if nz */
+typedef enum {
+ i1d_status = 0x00, /* -:A Get status string starting at 0, 1sec */
+ i1d_rd_green = 0x02, /* -:W Read the green channel, 1sec */
+ i1d_rd_blue = 0x03, /* -:W Read the blue channel, 1sec */
+ i1d_setintgt = 0x05, /* W:- Set the integration time, 1sec */
+ i1d_getintgt = 0x06, /* -:W Get the integration time, 1sec */
+ i1d_wrreg = 0x07, /* BB:? Write a register value, 1sec */
+ i1d_rdreg = 0x08, /* B:B Read a register value, 1sec */
+ i1d_unlock = 0x0e, /* BBBB:- Unlock the interface */
+ i1d_m_red_2 = 0x13, /* B:2:W Measure the red channel in freq mode, 1,10sec */
+ /* B = sync mode, typically 2 */
+ i1d_m_rgb_edge_2 = 0x16, /* SSS:2:WB Measure RGB edge/period mode, 1.70sec, ret red */
+ /* 2nd return value is not used ? */
+ i1d_rdambient = 0x17, /* BB:2:BWB Read Ambient, 1,10sec */
+ /* Returns first B param as first response */
+ /* Returns W as value read */
+ /* Returns aditional byte at end */
+
+ i1d_set_leds = 0x18, /* BB:B Set 4 LEDs state, 1sec */
+ /* 1st B is always 0 in practice */
+ /* 2nd B bits 0-4, 0 == on */
+ /* Echo's led state with returned B */
+ i1d_rgb_edge_3 = 0x19 /* SB:2:WB Unknown measurement command 1,10sec */
+ /* S is number of edges ?? */
+ /* B is the channel */
+ /* W is the reading */
+ /* B is not used ? */
+
+} i1DispCC;
+
+/* Diagnostic - return a description given the instruction code */
+static char *inst_desc(int cc) {
+ static char buf[40]; /* Fallback string */
+ switch(cc) {
+ case 0x00:
+ return "GetStatus";
+ case 0x02:
+ return "RdGreen";
+ case 0x03:
+ return "RdBlue";
+ case 0x05:
+ return "SetIntTime";
+ case 0x06:
+ return "GetIntTime";
+ case 0x07:
+ return "WrReg";
+ case 0x08:
+ return "RdReg";
+ case 0x09:
+ return "GetMeasPeriod";
+ case 0x0e:
+ return "Unlock";
+ case 0x13:
+ return "RdRedFreqMode";
+ case 0x16:
+ return "MeasRGBPeriMode";
+ case 0x17:
+ return "RdAmbient";
+ case 0x18:
+ return "SetLEDs";
+ case 0x19:
+ return "MeasRGBPeriMode2";
+ }
+ sprintf(buf,"Unknown %02x",cc);
+ return buf;
+}
+
+/* Do a command/response exchange with the huey. */
+/* Return the error code */
+/* The Huey is set up as an HID device, which can ease the need */
+/* for providing a kernel driver on MSWindows systems, */
+/* but it doesn't seem to actually be used as an HID device. */
+/* We allow for communicating via libusb, or an HID driver. */
+static inst_code
+huey_command(
+ huey *p, /* huey object */
+ i1DispCC cc, /* Command code */
+ unsigned char *in, /* 7 Command bytes to send */
+ unsigned char *out, /* 6 Response bytes returned */
+ double to, /* Timeout in seconds */
+ double to2 /* Timeout in seconds for 2nd read */
+) {
+ int i;
+ unsigned char buf[8]; /* 8 bytes to write/read */
+ int wbytes; /* bytes written */
+ int rbytes; /* bytes read from ep */
+ int se, ua = 0, rv = inst_ok;
+ int ishid = p->icom->port_type(p->icom) == icomt_hid;
+
+ a1logd(p->log,5,"huey_command: Sending '%s' args '%s'\n",inst_desc(cc), icoms_tohex(in, 7));
+
+ /* Send the command using the control interface */
+ buf[0] = cc; /* Construct the command == HID report number */
+ memmove(buf + 1, in, 7);
+
+ if (ishid) {
+ se = p->icom->hid_write(p->icom, buf, 8, &wbytes, to);
+ } else {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_CLASS | IUSB_REQ_RECIP_INTERFACE, 0x9, 0x200, 0, buf, 8, to);
+ wbytes = 8;
+ }
+ if (se != 0) {
+ a1logd(p->log,1,"huey_command: command send failed with ICOM err 0x%x\n",se);
+ return huey_interp_code((inst *)p, HUEY_COMS_FAIL);
+ }
+ rv = huey_interp_code((inst *)p, icoms2huey_err(ua, 0));
+
+ if (rv == inst_ok && wbytes != 8)
+ rv = huey_interp_code((inst *)p, HUEY_BAD_WR_LENGTH);
+
+ a1logd(p->log,6,"huey_command: get inst code\n",rv);
+
+ if (rv != inst_ok) {
+ /* Flush any response if write failed */
+ if (ishid)
+ p->icom->hid_read(p->icom, buf, 8, &rbytes, to);
+ else
+ p->icom->usb_read(p->icom, NULL, 0x81, buf, 8, &rbytes, to);
+ return rv;
+ }
+
+ /* Now fetch the response */
+ a1logd(p->log,6,"huey_command: Reading response\n");
+
+ if (ishid) {
+ se = p->icom->hid_read(p->icom, buf, 8, &rbytes, to);
+ } else {
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf, 8, &rbytes, to);
+ }
+ if (se != 0) {
+ a1logd(p->log,1,"huey_command: read failed with ICOM err 0x%x\n",se);
+ return huey_interp_code((inst *)p, HUEY_COMS_FAIL);
+ }
+ rv = huey_interp_code((inst *)p, icoms2huey_err(ua, 0));
+ if (rv == inst_ok && rbytes != 8)
+ rv = huey_interp_code((inst *)p, HUEY_BAD_RD_LENGTH);
+ if (rv == inst_ok && buf[1] != cc)
+ rv = huey_interp_code((inst *)p, HUEY_BAD_RET_CMD);
+
+ /* Some commands don't use the first response, but need to */
+ /* fetch a second response, with a longer timeout. */
+ /* This seems to be all of the measurement trigger commands */
+ if (rv == inst_ok && buf[0] == 0x90) { /* there is more */
+ a1logd(p->log,6,"huey_command: Reading extended response\n");
+
+ if (ishid) {
+ se = p->icom->hid_read(p->icom, buf, 8, &rbytes, to2);
+ } else {
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf, 8, &rbytes, to2);
+ }
+ if (se != 0) {
+ a1logd(p->log,1,"huey_command: read failed with ICOM err 0x%x\n",se);
+ return huey_interp_code((inst *)p, HUEY_COMS_FAIL);
+ }
+ rv = huey_interp_code((inst *)p, icoms2huey_err(ua, 0));
+ if (rv == inst_ok && rbytes != 8)
+ rv = huey_interp_code((inst *)p, HUEY_BAD_RD_LENGTH);
+ if (rv == inst_ok && buf[1] != cc) {
+ rv = huey_interp_code((inst *)p, HUEY_BAD_RET_CMD);
+ }
+ }
+
+ /* The first byte returned seems to be a command result error code. */
+ /* Not all codes are known, but it seems that the 6 byte payload */
+ /* is an error message, for instance 0x80 "NoCmd". */
+ /* The second byte is always the command code being echo'd back. */
+ if (rv == inst_ok && cc != 0x00 && buf[0] != 0x00) {
+ ua = HUEY_BAD_RET_STAT;
+ if (buf[0] == 0x80)
+ ua = HUEY_BAD_COMMAND;
+ rv = huey_interp_code((inst *)p, ua);
+ }
+
+ if (rv == inst_ok) {
+ memmove(out, buf + 2, 6);
+ } else {
+ memset(out, 0, 6);
+ }
+ a1logd(p->log,5,"huey_command: returning '%s' ICOM err 0x%x\n",icoms_tohex(out, 6),ua);
+
+ return rv;
+}
+
+/* Take an int, and convert it into a byte buffer */
+static void int2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 24) & 0xff;
+ buf[1] = (inv >> 16) & 0xff;
+ buf[2] = (inv >> 8) & 0xff;
+ buf[3] = (inv >> 0) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer */
+static void short2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 8) & 0xff;
+ buf[1] = (inv >> 0) & 0xff;
+}
+
+/* Take a word sized return buffer, and convert it to an int */
+static int buf2int(unsigned char *buf) {
+ int val;
+ val = buf[0];
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[3]));
+ return val;
+}
+
+/* Read a byte from a register */
+static inst_code
+huey_rdreg_byte(
+ huey *p, /* Object */
+ int *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 255 */
+) {
+ unsigned char buf[8];
+ int rsize;
+ inst_code ev;
+
+ if (addr < 0 || addr > 255)
+ return huey_interp_code((inst *)p, HUEY_BAD_REG_ADDRESS);
+
+ /* Read a byte */
+ memset(buf, 0, 7);
+ buf[0] = addr;
+ if ((ev = huey_command(p, i1d_rdreg, buf, buf, 1.0, 1.0)) != inst_ok)
+ return ev;
+
+ /* We expect the address to be returned */
+ if ((buf[0] & 0xff) != addr)
+ return huey_interp_code((inst *)p, HUEY_UNEXPECTED_RET_VAL);
+
+ *outp = (int)(buf[1] & 0xff);
+
+ return inst_ok;
+}
+
+/* Read a short from a register */
+static inst_code
+huey_rdreg_short(
+ huey *p, /* Object */
+ int *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 126 */
+) {
+ inst_code ev;
+ int v, val;
+
+ if ((ev = huey_rdreg_byte(p, &v, addr)) != inst_ok)
+ return ev;
+ val = v;
+
+ if ((ev = huey_rdreg_byte(p, &v, addr+1)) != inst_ok)
+ return ev;
+ val = ((val << 8) + (0xff & v));
+
+ *outp = val;
+
+ return inst_ok;
+}
+
+/* Read a word from a register */
+static inst_code
+huey_rdreg_word(
+ huey *p, /* Object */
+ int *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 124 */
+) {
+ inst_code ev;
+ int v, val;
+
+ if ((ev = huey_rdreg_byte(p, &v, addr)) != inst_ok)
+ return ev;
+ val = v;
+
+ if ((ev = huey_rdreg_byte(p, &v, addr+1)) != inst_ok)
+ return ev;
+ val = ((val << 8) + (0xff & v));
+
+ if ((ev = huey_rdreg_byte(p, &v, addr+2)) != inst_ok)
+ return ev;
+ val = ((val << 8) + (0xff & v));
+
+ if ((ev = huey_rdreg_byte(p, &v, addr+3)) != inst_ok)
+ return ev;
+ val = ((val << 8) + (0xff & v));
+
+ *outp = val;
+
+ return inst_ok;
+}
+
+
+/* Read a float from a register */
+/* Will return HUEY_FLOAT_NOT_SET if the float value was 0xffffffff */
+static inst_code
+huey_rdreg_float(
+ huey *p, /* Object */
+ double *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 124 */
+) {
+ inst_code ev;
+ int val;
+
+ if ((ev = huey_rdreg_word(p, &val, addr)) != inst_ok)
+ return ev;
+
+ if (ev == 0xffffffff) {
+ return inst_ok;
+ }
+
+ *outp = IEEE754todouble((unsigned int)val);
+ return inst_ok;
+}
+
+
+/* Write a byte to a register */
+static inst_code
+huey_wrreg_byte(
+ huey *p, /* Object */
+ int inv, /* Input value */
+ int addr /* Register Address, 0 - 127 */
+) {
+ int cval;
+ unsigned char ibuf[8], obuf[8];
+ int rsize;
+ inst_code ev;
+
+ ibuf[0] = addr;
+ ibuf[1] = inv;
+
+ /* Write a byte */
+ if ((ev = huey_command(p, i1d_wrreg, ibuf, obuf, 1.0, 1.0)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* Write a word to a register */
+static inst_code
+huey_wrreg_word(
+ huey *p, /* Object */
+ int inv, /* Where to write value */
+ int addr /* Register Address, 0 - 124 */
+) {
+ inst_code ev;
+ int v;
+
+ v = (inv >> 24) & 0xff;
+ if ((ev = huey_wrreg_byte(p, v, addr) ) != inst_ok)
+ return ev;
+
+ v = (inv >> 16) & 0xff;
+ if ((ev = huey_wrreg_byte(p, v, addr+1) ) != inst_ok)
+ return ev;
+
+ v = (inv >> 8) & 0xff;
+ if ((ev = huey_wrreg_byte(p, v, addr+2) ) != inst_ok)
+ return ev;
+
+ v = (inv >> 0) & 0xff;
+ if ((ev = huey_wrreg_byte(p, v, addr+3) ) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* Write a float to a register */
+static inst_code
+huey_wrreg_float(
+ huey *p, /* Object */
+ double inv, /* Value to write */
+ int addr /* Register Address, 0 - 124 */
+) {
+ inst_code ev;
+ int val;
+
+ val = (int)doubletoIEEE754(inv);
+
+ if ((ev = huey_wrreg_word(p, val, addr)) != inst_ok)
+ return ev;
+ return inst_ok;
+}
+
+/* Read the integration time */
+static inst_code
+huey_rd_int_time(
+ huey *p, /* Object */
+ int *outp /* Where to write value */
+) {
+ unsigned char buf[8];
+ int rsize;
+ inst_code ev;
+
+ if ((ev = huey_command(p, i1d_getintgt, buf, buf, 1.0, 1.0)) != inst_ok)
+ return ev;
+
+ *outp = buf2int(buf);
+
+ return inst_ok;
+}
+
+/* Set the integration time */
+/* (Not used for Huey ?) */
+static inst_code
+huey_wr_int_time(
+ huey *p, /* Object */
+ int inv /* Value to write */
+) {
+ unsigned char buf[16];
+ int rsize;
+ inst_code ev;
+
+ int2buf(buf, inv);
+ if ((ev = huey_command(p, i1d_setintgt, buf, buf, 1.0, 1.0)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Take a raw measurement using a given integration time. */
+/* The measureent is the count of (both) edges from the L2V */
+/* over the integration time */
+static inst_code
+huey_freq_measure(
+ huey *p, /* Object */
+ double rgb[3] /* Return the RGB edge count values */
+) {
+ int i;
+ unsigned char ibuf[8];
+ unsigned char obuf[8];
+ inst_code ev;
+
+ /* Do the measurement, and return the Red value */
+ ibuf[0] = 2; /* Sync mode 2 for CRT */
+ if ((ev = huey_command(p, i1d_m_red_2, ibuf, obuf, 1.0, 10.0)) != inst_ok)
+ return ev;
+ rgb[0] = (double)buf2int(obuf);
+
+ /* Get the green value */
+ if ((ev = huey_command(p, i1d_rd_green, ibuf, obuf, 1.0, 1.0)) != inst_ok)
+ return ev;
+ rgb[1] = (double)buf2int(obuf);
+
+ /* Get the blue value */
+ if ((ev = huey_command(p, i1d_rd_blue, ibuf, obuf, 1.0, 1.0)) != inst_ok)
+ return ev;
+ rgb[2] = (double)buf2int(obuf);
+
+ return inst_ok;
+}
+
+/* Take a raw measurement that returns the number of clocks */
+/* between and initial edge and edgec[] subsequent edges of the L2F. */
+/* Both edges are counted. */
+static inst_code
+huey_period_measure(
+ huey *p, /* Object */
+ int edgec[3], /* Measurement edge count for each channel */
+ double rgb[3] /* Return the RGB values */
+) {
+ int i;
+ unsigned char ibuf[16];
+ unsigned char obuf[16];
+ int rsize;
+ inst_code ev;
+
+ /* Set the edge count */
+ short2buf(ibuf + 0, edgec[0]);
+ short2buf(ibuf + 2, edgec[1]);
+ short2buf(ibuf + 4, edgec[2]);
+
+ /* Do the measurement, and return the Red value */
+ if ((ev = huey_command(p, i1d_m_rgb_edge_2, ibuf, obuf, 1.0, 70.0)) != inst_ok)
+ return ev;
+ rgb[0] = (double)buf2int(obuf);
+
+ /* Get the green value */
+ if ((ev = huey_command(p, i1d_rd_green, ibuf, obuf, 1.0, 1.0)) != inst_ok)
+ return ev;
+ rgb[1] = (double)buf2int(obuf);
+
+ /* Get the blue value */
+ if ((ev = huey_command(p, i1d_rd_blue, ibuf, obuf, 1.0, 1.0)) != inst_ok)
+ return ev;
+ rgb[2] = (double)buf2int(obuf);
+
+ return inst_ok;
+}
+
+/* Take a another mode raw mesurement from the device for */
+/* (not currently used ?) */
+static inst_code
+huey_take_raw_measurement_3(
+ huey *p, /* Object */
+ int edgec[3], /* Measurement edge count for each channel */
+ double rgb[3] /* Return the RGB values */
+) {
+ int i;
+ unsigned char ibuf[16];
+ unsigned char obuf[16];
+ int rsize;
+ inst_code ev;
+
+ /* Do the measurement, and return the Red value */
+ short2buf(ibuf + 0, edgec[0]);
+ ibuf[2] = 0; /* Channel */
+ if ((ev = huey_command(p, i1d_m_rgb_edge_2, ibuf, obuf, 1.0, 10.0)) != inst_ok)
+ return ev;
+ rgb[0] = (double)buf2int(obuf);
+
+ /* Do the measurement, and return the Green value */
+ short2buf(ibuf + 0, edgec[1]);
+ ibuf[2] = 1; /* Channel */
+ if ((ev = huey_command(p, i1d_m_rgb_edge_2, ibuf, obuf, 1.0, 10.0)) != inst_ok)
+ return ev;
+ rgb[1] = (double)buf2int(obuf);
+
+ /* Do the measurement, and return the Blue value */
+ short2buf(ibuf + 0, edgec[2]);
+ ibuf[2] = 2; /* Channel */
+ if ((ev = huey_command(p, i1d_m_rgb_edge_2, ibuf, obuf, 1.0, 10.0)) != inst_ok)
+ return ev;
+ rgb[2] = (double)buf2int(obuf);
+
+ return inst_ok;
+}
+
+/* Take a cooked measurement from the device for Huey. */
+/* The sensors are likely to be light to frequency converters */
+/* such as the TAOS TSL237, and there are only so many ways */
+/* the output can be measured. If the light level is high enough, */
+/* you could simply count the number of output transitions (edges) */
+/* in a fixed period of time. If the frequency is low though, */
+/* this limits precision due to quantization of the count. */
+/* Another way is to time how long it takes to count a certain */
+/* number of edges. This has higher precision at low frequencies, */
+/* but has the problem of having an unknown measurement duration, */
+/* and seems to be the main method chosen for the Huey. */
+static inst_code
+huey_take_measurement_2(
+ huey *p, /* Object */
+ int refr, /* nz if crt mode */
+ double rgb[3] /* Return the rgb values */
+) {
+ int i, j;
+ int edgec[3] = {1,1,1}; /* Measurement edge count for each channel */
+ int rem[3] = {1,1,1}; /* remeasure flags */
+ inst_code ev;
+
+ if (p->inited == 0)
+ return huey_interp_code((inst *)p, HUEY_NOT_INITED);
+
+ a1logd(p->log,4,"take_measurement_2 called with refr = %d\n",refr);
+
+ /* For Refresh mode, do an initial set of measurements over a fixed period */
+ if (refr) {
+
+ if ((ev = huey_freq_measure(p, rgb)) != inst_ok)
+ return ev;
+
+ a1logd(p->log,4,"Raw initial CRT RGB = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ /* Decide whether any channels need re-measuring, */
+ /* and computed cooked values. Threshold is typically 75 */
+ for (i = 0; i < 3; i++) {
+ rem[i] = (rgb[i] <= (0.75 * (double)p->sampno)) ? 1 : 0;
+ rgb[i] = 0.5 * rgb[i] * 1e6/(double)p->int_clocks;
+ }
+ a1logd(p->log,4,"Re-measure flags = %d %d %d\n",rem[0],rem[1],rem[2]);
+ }
+
+ /* If any need re-measuring */
+ if (rem[0] || rem[1] || rem[2]) {
+ double rgb2[3];
+
+ /* Do a first or second set of measurements */
+ if ((ev = huey_period_measure(p, edgec, rgb2)) != inst_ok)
+ return ev;
+ a1logd(p->log,4,"Raw initial/subsequent ecount %d %d %d RGB = %f %f %f\n",
+ edgec[0], edgec[1], edgec[2], rgb2[0], rgb2[1], rgb2[2]);
+
+ /* Compute adjusted edge count for channels we're remeasuring, */
+ /* aiming for count values of clk_freq (~1e6). */
+ for (i = 0; i < 3; i++) {
+ double ns;
+ if (rem[i]) {
+ if (p->clk_freq > ((2000.0 - 0.5) * rgb2[i]))
+ ns = 2000.0;
+ else {
+ ns = floor(p->clk_freq/rgb2[i]) + 0.5;
+ if (ns < 1.0)
+ ns = 1.0;
+ }
+ edgec[i] = (int)ns;
+ }
+ }
+
+ /* If we compute a different edge count, read again */
+ if (edgec[0] > 1 || edgec[1] > 1 || edgec[2] > 1) {
+ double rgb3[3]; /* 2nd RGB Readings */
+
+ if ((ev = huey_period_measure(p, edgec, rgb3)) != inst_ok)
+ return ev;
+
+ a1logd(p->log,4,"Raw subsequent2 ecount %d %d %d RGB = %f %f %f\n",
+ edgec[0], edgec[1], edgec[2], rgb3[0], rgb3[1], rgb3[2]);
+
+ /* Average readings if we repeated a measurement with the same threshold */
+ /* (Minor advantage, but may as well use it) */
+ for (i = 0; i < 3; i++) {
+ if (edgec[i] == 1)
+ rgb2[i] = 0.5 * (rgb2[i] + rgb3[i]);
+ else
+ rgb2[i] = rgb3[i];
+ }
+ }
+
+ /* Compute adjusted readings, ovewritting initial cooked values */
+ for (i = 0; i < 3; i++) {
+ if (rem[i]) {
+ rgb[i] = ((double)edgec[i])/(rgb2[i] * 2.0 * p->clk_prd);
+ a1logd(p->log,4,"%d after scale = %f\n",i,rgb[i]);
+
+ rgb[i] -= p->dark_cal[i]; /* Subtract black level */
+ a1logd(p->log,4,"%d after sub black = %f\n",i,rgb[i]);
+
+ if (rgb[i] < 0.0001)
+ rgb[i] = 0.0001;
+ a1logd(p->log,4,"%d after limit min = %f\n",i,rgb[i]);
+ }
+ }
+ }
+
+ a1logd(p->log,4,"Cooked RGB = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ return inst_ok;
+}
+
+/* Take a raw ambient measurement */
+static inst_code
+huey_take_amb_measurement_1(
+ huey *p, /* Object */
+ int a1, /* 8 bit argument - unknown */
+ int syncmode, /* 8 bit argument - sync mode */
+ double *amb, /* Return the raw ambient value */
+ int *rb /* Returned byte */
+) {
+ int i;
+ unsigned char ibuf[16];
+ unsigned char obuf[16];
+ int rsize;
+ inst_code ev;
+
+ a1 &= 0xff;
+ ibuf[0] = a1;
+ ibuf[1] = syncmode;
+
+ /* Do the measurement */
+ if ((ev = huey_command(p, i1d_rdambient, ibuf, obuf, 1.0, 10.0)) != inst_ok)
+ return ev;
+
+ /* Expect first argument to be returned */
+ if (obuf[0] != a1)
+ return huey_interp_code((inst *)p, HUEY_UNEXPECTED_RET_VAL);
+
+ *amb = (double)buf2int(obuf+1);
+ *rb = 0xff & obuf[5];
+
+ return inst_ok;
+}
+
+/* Take a cooked ambient measurement */
+static inst_code
+huey_take_amb_measurement(
+ huey *p, /* Object */
+ int refr, /* nz if refresh mode */
+ double *amb /* Return the ambient value */
+) {
+ int rb; /* Returned byte - not used */
+ inst_code ev;
+
+ if (p->inited == 0)
+ return huey_interp_code((inst *)p, HUEY_NOT_INITED);
+
+ a1logd(p->log,4,"take_amb_measurement_2 called with refr = %d\n",refr);
+
+ /* First param is always 3, second is sync mode */
+ if ((ev = huey_take_amb_measurement_1(p, 3, refr ? 2 : 0, amb, &rb)) != inst_ok)
+ return ev;
+ a1logd(p->log,4,"Raw ambient = %f\n",*amb);
+ return inst_ok;
+}
+
+/* Set the indicator LED's state. */
+/* The bottom 4 bits set the LED state from bottom (0) */
+/* to top (3), 0 = off, 1 = on */
+static inst_code
+huey_set_LEDs(
+ huey *p, /* Object */
+ int mask /* 8 bit LED mask */
+) {
+ int i;
+ unsigned char ibuf[8];
+ unsigned char obuf[8];
+ inst_code ev;
+
+ mask &= 0xf;
+ p->led_state = mask;
+
+ ibuf[0] = 0;
+ ibuf[1] = 0xf & (~mask);
+
+ /* Do command */
+ if ((ev = huey_command(p, i1d_set_leds, ibuf, obuf, 1.0, 1.0)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . */
+
+/* Take a XYZ measurement from the device */
+static inst_code
+huey_take_XYZ_measurement(
+ huey *p, /* Object */
+ double XYZ[3] /* Return the XYZ values */
+) {
+ int i, j;
+ double rgb[3]; /* RGB Readings */
+ inst_code ev;
+ double *mat; /* Pointer to matrix */
+
+ if (IMODETST(p->mode, inst_mode_emis_ambient)) {
+ if ((ev = huey_take_amb_measurement(p, 0, &XYZ[1])) != inst_ok)
+ return ev;
+ XYZ[1] *= AMB_SCALE_FACTOR; /* Times aproximate fudge factor */
+ XYZ[0] = icmD50.X * XYZ[1]; /* Convert to D50 neutral */
+ XYZ[2] = icmD50.Z * XYZ[1];
+ } else {
+ if ((ev = huey_take_measurement_2(p, p->refrmode, rgb)) != inst_ok)
+ return ev;
+
+ if (p->icx)
+ mat = p->CRT_cal; /* CRT/factory matrix */
+ else
+ mat = p->LCD_cal; /* LCD/user matrix */
+
+ for (i = 0; i < 3; i++) {
+ XYZ[i] = 0.0;
+ for (j = 0; j < 3; j++) {
+ XYZ[i] += mat[i * 3 + j] * rgb[j];
+ }
+ XYZ[i] *= CALFACTOR; /* Times magic scale factor */
+ }
+
+ /* Apply the colorimeter correction matrix */
+ icmMulBy3x3(XYZ, p->ccmat, XYZ);
+ }
+ a1logd(p->log,3,"huey_take_XYZ_measurement: XYZ = %f %f %f\n",XYZ[0],XYZ[1],XYZ[2]);
+ return inst_ok;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Check the device is responding, and unlock if necessary */
+static inst_code
+huey_check_unlock(
+ huey *p /* Object */
+) {
+ unsigned char buf[8];
+ int rsize;
+ inst_code ev;
+ int vv;
+ double ver;
+
+ a1logd(p->log,2,"huey_check_unlock: called\n");
+
+ /* Check the instrument status */
+ if ((ev = huey_command(p, i1d_status, buf, buf, 1.0,1.0)) != inst_ok)
+ return ev;
+
+ if (strncmp((char *)buf, "Locked", 6) == 0) {
+ if (p->lenovo)
+ strcpy((char *)buf,"huyL");
+ else
+ strcpy((char *)buf,"GrMb");
+
+ if ((ev = huey_command(p, i1d_unlock, buf, buf, 1.0,1.0)) != inst_ok)
+ return ev;
+
+ if ((ev = huey_command(p, i1d_status, buf, buf, 1.0,1.0)) != inst_ok)
+ return ev;
+ }
+
+ if (strncmp((char *)buf, "huL002", 6) != 0 /* Lenovo Huey ? */
+ && strncmp((char *)buf, "Cir001", 6) != 0) { /* Huey */
+ a1logd(p->log,1,"huey_check_unlock: unknown model '%s'\n",buf);
+ return huey_interp_code((inst *)p, HUEY_UNKNOWN_MODEL);
+ }
+
+ a1logd(p->log,2,"huey_check_unlock: instrument is responding, unlocked, and right type\n");
+
+ return inst_ok;
+}
+
+/* Read all the relevant register values */
+static inst_code
+huey_read_all_regs(
+ huey *p /* Object */
+) {
+ inst_code ev;
+ int i;
+
+ a1logd(p->log,2,"huey_check_unlock: about to read all the registers\n");
+
+ /* Serial number */
+ 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);
+
+
+ /* LCD/user calibration values */
+ for (i = 0; i < 9; i++) {
+ if ((ev = huey_rdreg_float(p, &p->LCD_cal[i], 4 + 4 * i) ) != inst_ok)
+ return ev;
+ a1logd(p->log,4,"LCD/user cal[%d] = %f\n",i,p->LCD_cal[i]);
+ }
+ /* LCD/user calibration time */
+ if ((ev = huey_rdreg_word(p, &p->LCD_caltime, 50) ) != inst_ok)
+ return ev;
+ a1logd(p->log,2,"LCD/user calibration time = 0x%x = %s\n",p->LCD_caltime, ctime_32(&p->LCD_caltime));
+
+ /* CRT/factory calibration values */
+ for (i = 0; i < 9; i++) {
+ if ((ev = huey_rdreg_float(p, &p->CRT_cal[i], 54 + 4 * i) ) != inst_ok)
+ return ev;
+ a1logd(p->log,3,"CRT/factory cal[%d] = %f\n",i,p->CRT_cal[i]);
+ }
+ /* CRT/factory calibration flag */
+ if ((ev = huey_rdreg_word(p, &p->CRT_caltime, 90) ) != inst_ok)
+ return ev;
+ a1logd(p->log,3,"CRT/factory flag = 0x%x = %s\n",p->CRT_caltime, ctime_32(&p->CRT_caltime));
+
+
+ /* Hard coded in Huey */
+ p->clk_prd = 1e-6;
+ a1logd(p->log,3,"Clock period = %f\n",p->clk_prd);
+
+ /* Dark current calibration values */
+ for (i = 0; i < 3; i++) {
+ if ((ev = huey_rdreg_float(p, &p->dark_cal[i], 103 + 4 * i)) != inst_ok) {
+ if ((ev & inst_imask) != HUEY_FLOAT_NOT_SET)
+ return ev;
+ p->dark_cal[i] = 0.0;
+ }
+ a1logd(p->log,3,"darkcal[%d] = %f\n",i,p->dark_cal[i]);
+ }
+
+ /* Ambient darkcurrent calibration value ? */
+ if ((ev = huey_rdreg_float(p, &p->amb_cal, 148)) != inst_ok) {
+ if ((ev & inst_imask) != HUEY_FLOAT_NOT_SET)
+ return ev;
+ p->amb_cal = 0.0;
+ }
+ a1logd(p->log,3,"Ambient cal = %f\n",p->amb_cal);
+
+ /* Unlock string */
+ for (i = 0; i < 4; i++) {
+ int vv;
+ if ((ev = huey_rdreg_byte(p, &vv, 122 + i) ) != inst_ok)
+ return ev;
+ p->unlk_string[i] = (char)vv;
+ }
+ p->unlk_string[i] = '\000';
+ a1logd(p->log,3,"unlock string = '%s'\n",p->unlk_string);
+
+ /* Read the integration time */
+ if ((ev = huey_rd_int_time(p, &p->int_clocks) ) != inst_ok)
+ return ev;
+ a1logd(p->log,3,"Integration time = %d\n",p->int_clocks);
+
+ a1logd(p->log,2,"huey_check_unlock: all registers read OK\n");
+
+ return inst_ok;
+}
+
+/* Compute factors that depend on the register values */
+static inst_code
+huey_compute_factors(
+ huey *p /* Object */
+) {
+ int i;
+
+ /* Check that certain value are valid */
+ if (p->ser_no == 0xffffffff) /* (It appears that some instruments have no serial number!) */
+ a1logw(p->log,"huey: bad instrument serial number\n");
+
+ if (p->LCD_caltime == 0xffffffff)
+ return huey_interp_code((inst *)p, HUEY_BAD_LCD_CALIBRATION);
+
+ if (p->CRT_caltime == 0xffffffff)
+ return huey_interp_code((inst *)p, HUEY_BAD_CRT_CALIBRATION);
+
+ /* clk_prd inversion */
+ p->clk_freq = 1.0/p->clk_prd;
+ a1logd(p->log,3,"clk_freq = %f\n",p->clk_freq);
+
+ /* Set some defaults */
+ p->sampno = 100; /* Minimum sampling count */
+
+ return inst_ok;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static inst_code set_default_disp_type(huey *p);
+
+/* Establish communications with a HUEY */
+/* If it's a serial port, use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+huey_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ huey *p = (huey *) pp;
+ unsigned char buf[8];
+ int rsize;
+ long etime;
+ int bi, i, se, rv;
+ inst_code ev = inst_ok;
+ char **pnames = NULL;
+ int retries = 0;
+
+ a1logd(p->log, 2, "huey_init_coms: About to init coms\n");
+
+ /* Open as an HID if available */
+ if (p->icom->port_type(p->icom) == icomt_hid) {
+
+ a1logd(p->log, 3, "huey_init_coms: About to init HID\n");
+
+ /* Set config, interface */
+ if ((se = p->icom->set_hid_port(p->icom, icomuf_none, retries, pnames)) != ICOM_OK) {
+ a1logd(p->log, 1, "huey_init_coms: set_hid_port failed ICOM err 0x%x\n",se);
+ return huey_interp_code((inst *)p, icoms2huey_err(se, 0));
+ }
+
+ } else if (p->icom->port_type(p->icom) == icomt_usb) {
+
+ a1logd(p->log, 3, "huey_init_coms: About to init USB\n");
+
+ /* Set config, interface, write end point, read end point */
+ /* ("serial" end points aren't used - the huey uses USB control messages) */
+ /* We need to detatch the HID driver on Linux */
+
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, icomuf_detach, 0, NULL))
+ != ICOM_OK) {
+ a1logd(p->log, 1, "huey_init_coms: set_usb_port failed ICOM err 0x%x\n",se);
+ return huey_interp_code((inst *)p, icoms2huey_err(se, 0));
+ }
+
+ } else {
+ a1logd(p->log, 1, "huey_init_coms: wrong communications type for device!\n");
+ return huey_interp_code((inst *)p, HUEY_UNKNOWN_MODEL);
+ }
+
+ if ((p->icom->vid == 0x0765 && p->icom->pid == 0x5001)
+ || (p->icom->vid == 0x0765 && p->icom->pid == 0x5010)) {
+ a1logd(p->log, 2, "huey_init_coms: Lenovo version\n");
+ p->lenovo = 1;
+ }
+
+ /* Check instrument is responding */
+ if ((ev = huey_command(p, i1d_status, buf, buf, 1.0, 1.0)) != inst_ok) {
+ a1logd(p->log, 1, "huey_init_coms: instrument didn't respond 0x%x\n",ev);
+ return ev;
+ }
+
+ /* Setup the default display type */
+ if ((ev = set_default_disp_type(p)) != inst_ok) {
+ return ev;
+ }
+
+ a1logd(p->log, 2, "huey_init_coms: inited coms OK\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+/* Initialise the HUEY */
+/* return non-zero on an error, with dtp error code */
+static inst_code
+huey_init_inst(inst *pp) {
+ huey *p = (huey *)pp;
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "huey_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return huey_interp_code((inst *)p, HUEY_NO_COMS); /* Must establish coms first */
+
+ /* Check instrument is responding, and right type */
+ if ((ev = huey_check_unlock(p)) != inst_ok)
+ return ev;
+
+ /* Turn the LEDs off */
+ if ((ev = huey_set_LEDs(p, 0x0)) != inst_ok)
+ return ev;
+
+ /* Read all the registers and store their contents */
+ if ((ev = huey_read_all_regs(p)) != inst_ok)
+ return ev;
+
+ if ((ev = huey_compute_factors(p)) != inst_ok)
+ return ev;
+
+ p->trig = inst_opt_trig_user;
+
+ p->inited = 1;
+ a1logd(p->log, 2, "huey_init_inst: inited OK\n");
+
+ /* Flash the LEDs, just cos we can! */
+ if ((ev = huey_set_LEDs(p, 0x1)) != inst_ok)
+ return ev;
+ msec_sleep(50);
+ if ((ev = huey_set_LEDs(p, 0x2)) != inst_ok)
+ return ev;
+ msec_sleep(50);
+ if ((ev = huey_set_LEDs(p, 0x4)) != inst_ok)
+ return ev;
+ msec_sleep(50);
+ if ((ev = huey_set_LEDs(p, 0x8)) != inst_ok)
+ return ev;
+ msec_sleep(50);
+ if ((ev = huey_set_LEDs(p, 0x4)) != inst_ok)
+ return ev;
+ msec_sleep(50);
+ if ((ev = huey_set_LEDs(p, 0x2)) != inst_ok)
+ return ev;
+ msec_sleep(50);
+ if ((ev = huey_set_LEDs(p, 0x1)) != inst_ok)
+ return ev;
+ msec_sleep(50);
+ if ((ev = huey_set_LEDs(p, 0x0)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* Read a single sample */
+/* Return the dtp error code */
+static inst_code
+huey_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ huey *p = (huey *)pp;
+ int user_trig = 0;
+ int rv = inst_protocol_error;
+
+a1logd(p->log, 1, "huey: huey_read_sample called\n");
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "huey: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+a1logd(p->log, 1, "huey: about to wait for user trigger\n");
+ for (;;) {
+ if ((rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rv == inst_user_abort)
+ return rv; /* Abort */
+ if (rv == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+a1logd(p->log, 1, "huey: checking for abort\n");
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return rv; /* Abort */
+ }
+
+a1logd(p->log, 1, "huey: about to call huey_take_XYZ_measurement\n");
+ /* Read the XYZ value */
+ if ((rv = huey_take_XYZ_measurement(p, val->XYZ)) != inst_ok) {
+ return rv;
+ }
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+
+ val->loc[0] = '\000';
+ if (IMODETST(p->mode, inst_mode_emis_ambient))
+ val->mtype = inst_mrt_ambient;
+ else
+ val->mtype = inst_mrt_none;
+ val->XYZ_v = 1; /* These are absolute XYZ readings ? */
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (user_trig)
+ return inst_user_trig;
+ return rv;
+}
+
+/* Insert a colorimetric correction matrix in the instrument XYZ readings */
+/* This is only valid for colorimetric instruments. */
+/* To remove the matrix, pass NULL for the filter filename */
+inst_code huey_col_cor_mat(
+inst *pp,
+double mtx[3][3]
+) {
+ huey *p = (huey *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (mtx == NULL) {
+ icmSetUnity3x3(p->ccmat);
+ } else {
+ if (p->cbid == 0) {
+ a1loge(p->log, 1, "huey: can't set col_cor_mat over non base display type\n");
+ inst_wrong_setup;
+ }
+ icmCpy3x3(p->ccmat, mtx);
+ }
+
+ return inst_ok;
+}
+
+/* Error codes interpretation */
+static char *
+huey_interp_error(inst *pp, int ec) {
+// huey *p = (huey *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case HUEY_INTERNAL_ERROR:
+ return "Internal software error";
+ case HUEY_COMS_FAIL:
+ return "Communications failure";
+ case HUEY_UNKNOWN_MODEL:
+ return "Not a known Huey Model";
+ case HUEY_DATA_PARSE_ERROR:
+ return "Data from i1 Display didn't parse as expected";
+
+ case HUEY_OK:
+ return "No device error";
+
+ case HUEY_FLOAT_NOT_SET:
+ return "Float value is not set in EEPROM";
+ case HUEY_NOT_READY:
+ return "Command didn't return command code - not ready ?";
+
+ case HUEY_BAD_SERIAL_NUMBER:
+ return "Serial number isn't set";
+ case HUEY_BAD_LCD_CALIBRATION:
+ return "LCD calibration values aren't set";
+ case HUEY_BAD_CRT_CALIBRATION:
+ return "CRT calibration values aren't set";
+ case HUEY_EEPROM_WRITE_FAIL:
+ return "Write to EEPROM failed to verify";
+
+ case HUEY_BAD_WR_LENGTH:
+ return "Unable to write full message to instrument";
+ case HUEY_BAD_RD_LENGTH:
+ return "Unable to read full message to instrument";
+ case HUEY_BAD_RET_CMD:
+ return "Message from instrument didn't echo command code";
+ case HUEY_BAD_RET_STAT:
+ return "Message from instrument had bad status code";
+ case HUEY_UNEXPECTED_RET_VAL:
+ return "Message from instrument has unexpected value";
+
+ case HUEY_BAD_STATUS:
+ return "Instrument status is unrecognised format";
+ case HUEY_UNKNOWN_VERS_ID:
+ return "Instrument version number or ID byte not recognised";
+ case HUEY_BAD_COMMAND:
+ return "Instrument didn't recognise the command";
+
+ /* Internal errors */
+ case HUEY_BAD_REG_ADDRESS:
+ return "Out of range register address";
+ case HUEY_BAD_INT_THRESH:
+ return "Out of range integration threshold";
+ case HUEY_NO_COMS:
+ return "Communications hasn't been established";
+ case HUEY_NOT_INITED:
+ return "Insrument hasn't been initialised";
+ case HUEY_CANT_BLACK_CALIB:
+ return "Device doesn't support black calibration";
+ case HUEY_CANT_MEASP_CALIB:
+ return "Device doesn't support measurment period calibration";
+ case HUEY_WRONG_DEVICE:
+ return "Wrong type of device for called function";
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+huey_interp_code(inst *pp, int ec) {
+// huey *p = (huey *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case HUEY_OK:
+ case HUEY_FLOAT_NOT_SET: /* Internal indication */
+ case HUEY_NOT_READY: /* Internal indication */
+ return inst_ok;
+
+ case HUEY_INTERNAL_ERROR:
+ case HUEY_BAD_REG_ADDRESS:
+ case HUEY_BAD_INT_THRESH:
+ case HUEY_NO_COMS:
+ case HUEY_NOT_INITED:
+ case HUEY_CANT_BLACK_CALIB:
+ case HUEY_CANT_MEASP_CALIB:
+ case HUEY_WRONG_DEVICE:
+ return inst_internal_error | ec;
+
+ case HUEY_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case HUEY_UNKNOWN_MODEL:
+ case HUEY_BAD_STATUS:
+ case HUEY_UNKNOWN_VERS_ID:
+ return inst_unknown_model | ec;
+
+ case HUEY_DATA_PARSE_ERROR:
+ case HUEY_BAD_WR_LENGTH:
+ case HUEY_BAD_RD_LENGTH:
+ case HUEY_BAD_RET_CMD:
+ case HUEY_BAD_RET_STAT:
+ case HUEY_UNEXPECTED_RET_VAL:
+ case HUEY_BAD_COMMAND:
+ return inst_protocol_error | ec;
+
+ case HUEY_BAD_SERIAL_NUMBER:
+ case HUEY_BAD_LCD_CALIBRATION:
+ case HUEY_BAD_CRT_CALIBRATION:
+ case HUEY_EEPROM_WRITE_FAIL:
+ return inst_hardware_fail | ec;
+
+ /* return inst_misread | ec; */
+ /* return inst_needs_cal_2 | ec; */
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+huey_del(inst *pp) {
+ huey *p = (huey *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ inst_del_disptype_list(p->dtlist, p->ndtlist);
+ free(p);
+}
+
+/* Return the instrument mode capabilities */
+void huey_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ huey *p = (huey *)pp;
+ inst_mode cap1 = 0;
+ inst2_capability cap2 = 0;
+
+ cap1 |= inst_mode_emis_spot
+ | inst_mode_emis_ambient
+ | inst_mode_colorimeter
+ ;
+
+ cap2 |= inst2_prog_trig
+ | inst2_user_trig
+ | inst2_has_leds
+ | inst2_disptype
+ | inst2_ambient_mono
+ | inst2_ccmx
+ ;
+
+ if (pcap1 != NULL)
+ *pcap1 = cap1;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Check device measurement mode */
+inst_code huey_check_mode(inst *pp, inst_mode m) {
+ huey *p = (huey *)pp;
+ inst_mode cap;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* only display emission mode and ambient supported */
+ if (!IMODETST(m, inst_mode_emis_spot)
+ && !IMODETST(m, inst_mode_emis_ambient)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code huey_set_mode(inst *pp, inst_mode m) {
+ huey *p = (huey *)pp;
+ inst_code ev;
+
+ if ((ev = huey_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->mode = m;
+
+ return inst_ok;
+}
+
+inst_disptypesel huey_disptypesel[3] = {
+ {
+ inst_dtflags_default,
+ 1,
+ "l",
+ "LCD display",
+ 0,
+ 0
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 2, /* cbix */
+ "c", /* sel */
+ "CRT display", /* desc */
+ 1, /* refr */
+ 1 /* ix */
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+/* Get mode and option details */
+static inst_code huey_get_disptypesel(
+inst *pp,
+int *pnsels, /* Return number of display types */
+inst_disptypesel **psels, /* Return the array of display types */
+int allconfig, /* nz to return list for all configs, not just current. */
+int recreate /* nz to re-check for new ccmx & ccss files */
+) {
+ huey *p = (huey *)pp;
+ inst_code rv = inst_ok;
+
+ /* Create/Re-create a current list of abailable display types */
+ if (p->dtlist == NULL || recreate) {
+ if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ huey_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return rv;
+ }
+
+ if (pnsels != NULL)
+ *pnsels = p->ndtlist;
+
+ if (psels != NULL)
+ *psels = p->dtlist;
+
+ return inst_ok;
+}
+
+/* Given a display type entry, setup for that type */
+static inst_code set_disp_type(huey *p, inst_disptypesel *dentry) {
+
+ p->icx = dentry->ix;
+ p->refrmode = dentry->refr;
+ p->cbid = dentry->cbid;
+
+ if (dentry->flags & inst_dtflags_ccmx) {
+ icmCpy3x3(p->ccmat, dentry->mat);
+ } else {
+ icmSetUnity3x3(p->ccmat);
+ }
+
+ return inst_ok;
+}
+
+/* Setup the default display type */
+static inst_code set_default_disp_type(huey *p) {
+ inst_code ev;
+ int i;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist,
+ huey_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) {
+ if (p->dtlist[i].flags & inst_dtflags_default)
+ break;
+ }
+ if (p->dtlist[i].flags & inst_dtflags_end) {
+ a1loge(p->log, 1, "set_default_disp_type: failed to find type!\n");
+ return inst_internal_error;
+ }
+ if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/* Set the display type */
+static inst_code huey_set_disptype(inst *pp, int ix) {
+ huey *p = (huey *)pp;
+ inst_code ev;
+ inst_disptypesel *dentry;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ huey_disptypesel, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ if (ix < 0 || ix >= p->ndtlist)
+ return inst_unsupported;
+
+ dentry = &p->dtlist[ix];
+
+ if ((ev = set_disp_type(p, dentry)) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * set or reset an optional mode
+ *
+ * Some options talk to the instrument, and these will
+ * error if it hasn't been initialised.
+ */
+static inst_code
+huey_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ huey *p = (huey *)pp;
+ inst_code ev = inst_ok;
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user) {
+ p->trig = m;
+ return inst_ok;
+ }
+
+ /* Get the display type information */
+ if (m == inst_opt_get_dtinfo) {
+ va_list args;
+ int *refrmode, *cbid;
+
+ va_start(args, m);
+ refrmode = va_arg(args, int *);
+ cbid = va_arg(args, int *);
+ va_end(args);
+
+ if (refrmode != NULL)
+ *refrmode = p->refrmode;
+ if (cbid != NULL)
+ *cbid = p->cbid;
+
+ return inst_ok;
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Operate the LEDS */
+ if (m == inst_opt_get_gen_ledmask) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = 0xf; /* Four general LEDs */
+ return inst_ok;
+ } else if (m == inst_opt_get_led_state) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = p->led_state;
+ return inst_ok;
+ } else if (m == inst_opt_set_led_state) {
+ va_list args;
+ int mask = 0;
+
+ va_start(args, m);
+ mask = va_arg(args, int);
+ va_end(args);
+ return huey_set_LEDs(p, mask);
+ }
+
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern huey *new_huey(icoms *icom, instType itype) {
+ huey *p;
+ if ((p = (huey *)calloc(sizeof(huey),1)) == NULL) {
+ a1loge(icom->log, 1, "new_huey: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = huey_init_coms;
+ p->init_inst = huey_init_inst;
+ p->capabilities = huey_capabilities;
+ p->check_mode = huey_check_mode;
+ p->set_mode = huey_set_mode;
+ p->get_disptypesel = huey_get_disptypesel;
+ p->set_disptype = huey_set_disptype;
+ p->get_set_opt = huey_get_set_opt;
+ p->read_sample = huey_read_sample;
+ p->col_cor_mat = huey_col_cor_mat;
+ p->interp_error = huey_interp_error;
+ p->del = huey_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */
+
+ return p;
+}
+
diff --git a/spectro/huey.h b/spectro/huey.h
new file mode 100644
index 0000000..6b8858a
--- /dev/null
+++ b/spectro/huey.h
@@ -0,0 +1,134 @@
+#ifndef HUEY_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * GretagMacbeth Huey related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 7/10/2007
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * (Based on i1disp.h)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Note: update huey_interp_error() and huey_interp_code() in huey.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define HUEY_INTERNAL_ERROR 0x61 /* Internal software error */
+#define HUEY_COMS_FAIL 0x62 /* Communication failure */
+#define HUEY_UNKNOWN_MODEL 0x63 /* Not an huey */
+#define HUEY_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error code */
+#define HUEY_OK 0x00
+
+/* Sub codes for device specific reasoning */
+#define HUEY_FLOAT_NOT_SET 0x01
+#define HUEY_NOT_READY 0x02
+
+#define HUEY_BAD_SERIAL_NUMBER 0x03
+#define HUEY_BAD_LCD_CALIBRATION 0x04
+#define HUEY_BAD_CRT_CALIBRATION 0x05
+#define HUEY_EEPROM_WRITE_FAIL 0x06
+
+#define HUEY_BAD_WR_LENGTH 0x07
+#define HUEY_BAD_RD_LENGTH 0x08
+#define HUEY_BAD_RET_CMD 0x09
+#define HUEY_BAD_RET_STAT 0x0A
+#define HUEY_UNEXPECTED_RET_VAL 0x0B
+
+#define HUEY_BAD_STATUS 0x0C
+#define HUEY_UNKNOWN_VERS_ID 0x0D
+
+#define HUEY_BAD_COMMAND 0x0E /* Command isn't recognised by instrument */
+
+/* Internal errors */
+#define HUEY_BAD_REG_ADDRESS 0x20
+#define HUEY_BAD_INT_THRESH 0x21
+#define HUEY_NO_COMS 0x22
+#define HUEY_NOT_INITED 0x23
+#define HUEY_CANT_BLACK_CALIB 0x24
+#define HUEY_CANT_MEASP_CALIB 0x25
+#define HUEY_WRONG_DEVICE 0x26
+
+
+/* HUEY communication object */
+struct _huey {
+ INST_OBJ_BASE
+
+ int lenovo; /* 0 = normal, 1 = 'huyL' */
+
+ inst_mode mode; /* Currently selected mode */
+
+ inst_opt_type trig; /* Reading trigger mode */
+
+ /* EEPROM registers */
+ /* Number is the register address, and B, S, W, F indicate the type/size */
+ int ser_no; /* Serial number */
+
+ double LCD_cal[9]; /* LCD 3x3 calibration matrix */
+ int LCD_caltime; /* Calibration time in secs from January 1, 1970, UTC */
+
+ double CRT_cal[9]; /* CRT 3x3 calibration matrix */
+ int CRT_caltime; /* cal valid/time flag. 0xffffffff = invalid ?, */
+ /* time in secs from January 1, 1970, UTC */
+
+ double clk_prd; /* Master clock period, hard coded to 1e-6 */
+
+ double dark_cal[3]; /* Dark current calibration values */
+
+ char unlk_string[5]; /* Unlock string */
+
+ double amb_cal; /* Ambient calibration value */
+
+ /* Computed factors and state */
+ double clk_freq; /* Inverted clk_prd, ie master clock frequency, typically apx 1e6 */
+
+ int sampno; /* Number of CRT samples we're aiming to take, def 100 */
+ int int_clocks; /* Integration time in clocks */
+
+ inst_disptypesel *dtlist; /* Display Type list */
+ int ndtlist; /* Number of valid dtlist entries */
+ int icx; /* 0 = LCD, 1 = CRT matrix */
+ int cbid; /* calibration base ID, 0 if not a base */
+ int refrmode; /* Refresh mode (always 0) */
+ double ccmat[3][3]; /* Colorimeter correction matrix */
+
+ /* Other state */
+ int led_state; /* Current LED state */
+
+}; typedef struct _huey huey;
+
+/* Constructor */
+extern huey *new_huey(icoms *icom, instType itype);
+
+
+#define HUEY_H
+#endif /* HUEY_H */
diff --git a/spectro/i1d3.c b/spectro/i1d3.c
new file mode 100644
index 0000000..53b2f0c
--- /dev/null
+++ b/spectro/i1d3.c
@@ -0,0 +1,3637 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * GretagMacbeth Huey related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/7/2011
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * (Based on huey.c)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "i1d3.h"
+
+#undef PLOT_SPECTRA /* Plot the sensor senitivity spectra */
+#undef SAVE_SPECTRA /* Save the sensor senitivity spectra to "sensors.cmf" */
+#undef PLOT_REFRESH /* Plot data used to determine refresh rate */
+
+static inst_code i1d3_interp_code(inst *pp, int ec);
+static inst_code i1d3_check_unlock(i1d3 *p);
+
+/* ------------------------------------------------------------------- */
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a PPC gcc 3.3 optimiser bug... */
+/* It seems to cause a segmentation fault instead of */
+/* converting an integer loop index into a float, */
+/* when there are sufficient variables in play. */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+/* ------------------------------------------------------------------------ */
+/* Implementation */
+
+/* Interpret an icoms error into a I1D3 error */
+/* If torc is nz, then a trigger or command is OK, */
+/* othewise they are treated as an abort. */
+static int icoms2i1d3_err(int se, int torc) {
+ if (se != ICOM_OK)
+ return I1D3_COMS_FAIL;
+ return I1D3_OK;
+}
+
+/* i1d3 command codes. */
+/* A 64 bit command/response buffer is always used, communicating */
+/* over EP 0x81 and 0x01. The command byte 0 is the major code, */
+/* and byte 1 is the sub code for command 0x00 . The response is byte 0 */
+/* error code, byte 1 echoing the major command number. */
+/* Major code 00 works when locked ? */
+typedef enum {
+ i1d3_getinfo = 0x0000, /* Product name + Firmware version + Firmware Date string */
+ i1d3_status = 0x0001, /* status number ?? */
+ i1d3_prodname = 0x0010, /* Product name string */
+ i1d3_prodtype = 0x0011, /* Product type number */
+ i1d3_firmver = 0x0012, /* Firmware version string */
+ i1d3_firmdate = 0x0013, /* Firmware date string */
+ i1d3_locked = 0x0020, /* Get locked status */
+ i1d3_measure1 = 0x0100, /* Used by all measure */
+ i1d3_measure2 = 0x0200, /* Used by all measure except ambient */
+ i1d3_readintee = 0x0800, /* Read internal EEPROM */
+ i1d3_readextee = 0x1200, /* Read external EEPROM */
+ i1d3_setled = 0x2100, /* Set the LED state */
+ i1d3_rd_sensor = 0x9300, /* Read the analog sensor */
+ i1d3_get_diff = 0x9400, /* Get the diffuser position */
+ i1d3_lockchal = 0x9900, /* Request lock challenge */
+ i1d3_lockresp = 0x9a00, /* Unlock response */
+ i1d3_relock = 0x9b00 /* Close device - relock ? */
+} i1Disp3CC;
+
+/* Diagnostic - return a description given the instruction code */
+static char *inst_desc(i1Disp3CC cc) {
+ static char buf[40]; /* Fallback string */
+ switch(cc) {
+ case i1d3_getinfo:
+ return "GetInfo";
+ case i1d3_status:
+ return "GetStatus";
+ case i1d3_prodname:
+ return "GetProductName";
+ case i1d3_prodtype:
+ return "GetProductType";
+ case i1d3_firmver:
+ return "GetFirmwareVersion";
+ case i1d3_firmdate:
+ return "GetFirmwareDate";
+ case i1d3_locked:
+ return "GetLockedStatus";
+ case i1d3_measure1:
+ return "Measure1";
+ case i1d3_measure2:
+ return "Measure2";
+ case i1d3_readintee:
+ return "ReadInternalEEPROM";
+ case i1d3_readextee:
+ return "ReadExternalEEPROM";
+ case i1d3_setled:
+ return "SetLED";
+ case i1d3_rd_sensor:
+ return "ReadAnalogSensor";
+ case i1d3_get_diff:
+ return "GetDiffuserPositio";
+ case i1d3_lockchal:
+ return "GetLockChallenge";
+ case i1d3_lockresp:
+ return "SendLockResponse";
+ case i1d3_relock:
+ return "ReLock";
+ }
+ sprintf(buf,"Unknown %04x",cc);
+ return buf;
+}
+
+/* Do a command/response exchange with the i1d3. */
+/* Return the error code */
+/* This is protected by a mutex, so it is multi-thread safe. */
+/* The i1d3 is set up as an HID device, which can ease the need */
+/* for providing a kernel driver on MSWindows systems, */
+/* but it doesn't seem to actually be used as an HID device. */
+/* We allow for communicating via libusb, or an HID driver. */
+static inst_code
+i1d3_command(
+ i1d3 *p, /* i1d3 object */
+ i1Disp3CC cc, /* Command code */
+ unsigned char *send, /* 64 Command bytes to send */
+ unsigned char *recv, /* 64 Response bytes returned */
+ double to, /* Timeout in seconds */
+ int nd /* nz to disable debug messages */
+) {
+ unsigned char cmd; /* Major command code */
+ int wbytes; /* bytes written */
+ int rbytes; /* bytes read from ep */
+ int se, ua = 0, rv = inst_ok;
+ int ishid = p->icom->port_type(p->icom) == icomt_hid;
+
+ amutex_lock(p->lock);
+
+ /* Send the command using interrupt transfer to EP 0x01 */
+ send[0] = cmd = (cc >> 8) & 0xff; /* Major command == HID report number */
+ if (cmd == 0x00)
+ send[1] = (cc & 0xff); /* Minor command */
+
+ if (!nd) a1logd(p->log, 4, "i1d3_command: Sending cmd '%s' args '%s'\n",
+ inst_desc(cc), icoms_tohex(send, 8));
+
+ if (p->icom->port_type(p->icom) == icomt_hid) {
+ se = p->icom->hid_write(p->icom, send, 64, &wbytes, to);
+ } else {
+ se = p->icom->usb_write(p->icom, NULL, 0x01, send, 64, &wbytes, to);
+ }
+ if (se != 0) {
+ if (!nd) a1logd(p->log, 1, "i1d3_command: Command send failed with ICOM err 0x%x\n",se);
+ amutex_unlock(p->lock);
+ return i1d3_interp_code((inst *)p, I1D3_COMS_FAIL);
+ }
+ rv = i1d3_interp_code((inst *)p, icoms2i1d3_err(ua, 0));
+ if (!nd) a1logd(p->log, 5, "i1d3_command: ICOM err 0x%x\n",ua);
+
+ if (rv == inst_ok && wbytes != 64) {
+ if (!nd) a1logd(p->log, 1, "i1d3_command: wbytes = %d != 64\n",wbytes);
+ rv = i1d3_interp_code((inst *)p, I1D3_BAD_WR_LENGTH);
+ }
+
+ if (rv != inst_ok) {
+ /* Flush any response */
+ if (ishid) {
+ p->icom->hid_read(p->icom, recv, 64, &rbytes, to);
+ } else {
+ p->icom->usb_read(p->icom, NULL, 0x81, recv, 64, &rbytes, to);
+ }
+ amutex_unlock(p->lock);
+ return rv;
+ }
+
+ /* Now fetch the response */
+ if (!nd) a1logd(p->log, 5, "i1d3_command: Reading response\n");
+
+ if (ishid) {
+ se = p->icom->hid_read(p->icom, recv, 64, &rbytes, to);
+ } else {
+ se = p->icom->usb_read(p->icom, NULL, 0x81, recv, 64, &rbytes, to);
+ }
+ if (se != 0) {
+ if (!nd) a1logd(p->log, 1, "i1d3_command: response read failed with ICOM err 0x%x\n",se);
+ amutex_unlock(p->lock);
+ return i1d3_interp_code((inst *)p, I1D3_COMS_FAIL);
+ }
+ if (rv == inst_ok && rbytes != 64) {
+ if (!nd) a1logd(p->log, 1, "i1d3_command: rbytes = %d != 64\n",rbytes);
+ rv = i1d3_interp_code((inst *)p, I1D3_BAD_RD_LENGTH);
+ }
+
+ /* The first byte returned seems to be a command result error code. */
+ /* The second byte is usually the command code being echo'd back, but not always. */
+ if (rv == inst_ok && recv[0] != 0x00) {
+ if (!nd) a1logd(p->log, 1, "i1d3_command: status byte != 00 = 0x%x\n",recv[0]);
+ rv = i1d3_interp_code((inst *)p, I1D3_BAD_RET_STAT);
+ }
+
+ if (rv == inst_ok) {
+ if (cc != i1d3_get_diff) {
+ if (recv[1] != cmd) {
+ if (!nd) a1logd(p->log, 1, "i1d3_command: major cmd not echo'd != 0x%02x = 0x%02x\n",
+ cmd,recv[1]);
+ rv = i1d3_interp_code((inst *)p, I1D3_BAD_RET_CMD);
+ }
+ }
+ }
+
+ if (!nd) a1logd(p->log, 4, "i1d3_command: got '%s' ICOM err 0x%x\n",icoms_tohex(recv, 14),ua);
+
+ amutex_unlock(p->lock);
+ return rv;
+}
+
+/* Read a packet and time out or throw it away */
+static inst_code
+i1d3_dummy_read(
+ i1d3 *p /* i1d3 object */
+) {
+ unsigned char buf[64];
+ int rbytes; /* bytes read from ep */
+ int se, rv = inst_ok;
+ int ishid = p->icom->port_type(p->icom) == icomt_hid;
+
+ if (ishid) {
+ se = p->icom->hid_read(p->icom, buf, 64, &rbytes, 0.1);
+ } else {
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf, 64, &rbytes, 0.1);
+ }
+
+ return rv;
+}
+
+/* Byte to int conversion. Most things seem to be little endian... */
+
+/* Take an int, and convert it into a byte buffer */
+static void int2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+ buf[2] = (inv >> 16) & 0xff;
+ buf[3] = (inv >> 24) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer */
+static void short2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer (Big Endian) */
+static void short2bufBE(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 8) & 0xff;
+ buf[1] = (inv >> 0) & 0xff;
+}
+
+
+/* Take a 64 sized return buffer, and convert it to an ORD64 */
+static ORD64 buf2ord64(unsigned char *buf) {
+ ORD64 val;
+ val = buf[7];
+ val = ((val << 8) + (0xff & buf[6]));
+ val = ((val << 8) + (0xff & buf[5]));
+ val = ((val << 8) + (0xff & buf[4]));
+ val = ((val << 8) + (0xff & buf[3]));
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a word sized return buffer, and convert it to an unsigned int */
+static unsigned int buf2uint(unsigned char *buf) {
+ unsigned int val;
+ val = buf[3];
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a word sized return buffer, and convert it to an int */
+static int buf2int(unsigned char *buf) {
+ int val;
+ val = buf[3];
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a short sized return buffer, and convert it to an int */
+static int buf2short(unsigned char *buf) {
+ int val;
+ val = buf[1];
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Get Product name + Firmware version + Firmware Date string */
+static inst_code
+i1d3_get_info(
+ i1d3 *p, /* Object */
+ char *rv /* 64 byte buffer */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if ((ev = i1d3_command(p, i1d3_getinfo, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ strncpy((char *)rv, (char *)fromdev + 2, 63);
+
+ a1logd(p->log, 3, "i1d3_get_info: got '%s'\n",rv);
+
+ return inst_ok;
+}
+
+/* Check the status. 0 = OK, 1 = BAD */
+/* Not sure what sort of status this is. The result changes some */
+/* other command parameter treatment. Could it be somthing like */
+/* "factory calibrated" status ? */
+static inst_code
+i1d3_check_status(
+ i1d3 *p, /* Object */
+ int *stat /* Status - 0 if OK, 1 if not OK */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if ((ev = i1d3_command(p, i1d3_status, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ *stat = 1; /* Bad */
+ if (fromdev[2] != 0 || (buf2short(fromdev + 3) >= 5))
+ *stat = 0; /* OK */
+
+ a1logd(p->log, 3, "i1d3_check_status: got %s\n",*stat == 0 ? "OK" : "Bad");
+
+ return inst_ok;
+}
+
+/* Get Product name */
+static inst_code
+i1d3_get_prodname(
+ i1d3 *p, /* Object */
+ char *rv /* 32 byte buffer */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if ((ev = i1d3_command(p, i1d3_prodname, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ strncpy((char *)rv, (char *)fromdev + 2, 31);
+
+ a1logd(p->log, 3, "i1d3_get_prodname: got '%s'\n",rv);
+
+ return inst_ok;
+}
+
+/* Get Product type number */
+static inst_code
+i1d3_get_prodtype(
+ i1d3 *p, /* Object */
+ int *stat /* 16 bit version number */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if ((ev = i1d3_command(p, i1d3_prodtype, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ *stat = buf2short(fromdev + 3);
+
+ a1logd(p->log, 3, "i1d3_get_prodtype: got 0x%x\n",*stat);
+
+ return inst_ok;
+}
+
+/* Get firmware version */
+static inst_code
+i1d3_get_firmver(
+ i1d3 *p, /* Object */
+ char *rv /* 32 byte buffer */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if ((ev = i1d3_command(p, i1d3_firmver, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ strncpy((char *)rv, (char *)fromdev + 2, 31);
+
+ a1logd(p->log, 3, "i1d3_get_firmver: got '%s'\n",rv);
+
+ return inst_ok;
+}
+
+/* Get firmware date name */
+static inst_code
+i1d3_get_firmdate(
+ i1d3 *p, /* Object */
+ char *rv /* 32 byte buffer */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if ((ev = i1d3_command(p, i1d3_firmdate, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ strncpy((char *)rv, (char *)fromdev + 2, 31);
+
+ a1logd(p->log, 3, "i1d3_get_firmdate: got '%s'\n",rv);
+
+ return inst_ok;
+}
+
+/* Check the lock status */
+static inst_code
+i1d3_lock_status(
+ i1d3 *p, /* Object */
+ int *stat /* Status - 0 if Unlocked, 1 if locked */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if ((ev = i1d3_command(p, i1d3_locked, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ *stat = 1; /* Locked */
+ if (fromdev[2] != 0 || fromdev[3] == 0)
+ *stat = 0; /* Not Locked */
+
+ a1logd(p->log, 3, "i1d3_lock_status: got %s\n",*stat == 1 ? "Locked" : "Unlocked");
+
+ return inst_ok;
+}
+
+static void create_unlock_response(unsigned int *k, unsigned char *c, unsigned char *r);
+
+
+/* Unlock the device */
+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 dtype; /* 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_oem },
+ { "i1Display3 ", { 0xa9119479, 0x5b168761 }, i1d3_disppro, i1d3_nec_ssp },
+ { "i1Display3 ", { 0x160eb6ae, 0x14440e70 }, i1d3_disppro, i1d3_quato_sh3 },
+ { NULL }
+ };
+ inst_code ev;
+ int ix;
+
+ a1logd(p->log, 2, "i1d3_unlock: called\n");
+
+ /* Until we give up */
+ for (ix = 0;;ix++) {
+
+ /* If we've run out of unlock keys */
+ if (codes[ix].pname == NULL) {
+ a1logd(p->log, 1, "i1d3: Unknown lock code. Please contact ArgyllCMS for help\n");
+ return i1d3_interp_code((inst *)p, I1D3_UNKNOWN_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;
+ }
+
+// a1logd(p->log, 3, "i1d3_unlock: Trying unlock key 0x%08x 0x%08x\n",
+// codes[ix].key[0], codes[ix].key[1]);
+
+ p->dtype = codes[ix].dtype;
+ p->stype = codes[ix].stype;
+
+ /* Attempt unlock */
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ /* Get a challenge */
+ if ((ev = i1d3_command(p, i1d3_lockchal, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ /* Convert challenge to response */
+ create_unlock_response(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;
+ }
+
+ a1logd(p->log, 3, "i1d3_unlock: Trying next unlock key\n");
+ /* Try the next key */
+ }
+
+ return inst_ok;
+}
+
+/* Get the ambient diffuser position */
+static inst_code
+i1d3_get_diffpos(
+ i1d3 *p, /* Object */
+ int *pos, /* 0 = display, 1 = ambient */
+ int nd /* nz = no debug message */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if ((ev = i1d3_command(p, i1d3_get_diff, todev, fromdev, 1.0, nd)) != inst_ok)
+ return ev;
+
+ *pos = fromdev[1];
+
+ if (nd == 0)
+ a1logd(p->log, 3, "i1d3_get_diffpos: got %d\n",*pos);
+
+ return inst_ok;
+}
+
+/* Read bytes from the internal EEPROM */
+static inst_code
+i1d3_read_internal_eeprom(
+ i1d3 *p, /* Object */
+ int addr, /* address, 0 .. 255 */
+ int len, /* length, 0 .. 255 */
+ unsigned char *bytes /* return bytes here */
+) {
+ inst_code ev;
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ int ll;
+
+ if (addr < 0 || addr > 255)
+ return i1d3_interp_code((inst *)p, I1D3_BAD_MEM_ADDRESS);
+
+ if (len < 0 || (addr + len) > 256)
+ return i1d3_interp_code((inst *)p, I1D3_BAD_MEM_LENGTH);
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ /* Bread read up into 60 bytes packets */
+ for (; len > 0; addr += ll, bytes += ll, len -= ll) {
+ ll = len;
+ if (ll > 60)
+ ll = 60;
+
+ /* OEM driver retries several times after a 10msec sleep on failure. */
+ /* Can a failure actually happen though ? */
+ todev[1] = (unsigned char)addr;
+ todev[2] = (unsigned char)ll;
+
+ if ((ev = i1d3_command(p, i1d3_readintee, todev, fromdev, 1.0, 0)) != inst_ok) {
+ return ev;
+ }
+
+ memmove(bytes, fromdev + 4, ll);
+ }
+
+ return inst_ok;
+}
+
+/* Read bytes from the external EEPROM */
+static inst_code
+i1d3_read_external_eeprom(
+ i1d3 *p, /* Object */
+ int addr, /* address, 0 .. 8191 */
+ int len, /* length, 0 .. 8192 */
+ unsigned char *bytes /* return bytes here */
+) {
+ inst_code ev;
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ int ll;
+ int sdebug;
+
+ if (addr < 0 || addr > 8191)
+ return i1d3_interp_code((inst *)p, I1D3_BAD_MEM_ADDRESS);
+
+ if (len < 0 || (addr + len) > 8192)
+ return i1d3_interp_code((inst *)p, I1D3_BAD_MEM_LENGTH);
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ /* Bread read up into 59 bytes packets */
+ sdebug = p->log->debug;
+ p->log->debug = p->log->debug >= 2 ? p->log->debug - 2 : 0; /* Supress command traces */
+ for (; len > 0; addr += ll, bytes += ll, len -= ll) {
+ ll = len;
+ if (ll > 59)
+ ll = 59;
+
+ /* OEM driver retries several times after a 10msec sleep on failure. */
+ /* Can a failure actually happen though ? */
+ short2bufBE(todev + 1, addr);
+ todev[3] = (unsigned char)ll;
+
+ if ((ev = i1d3_command(p, i1d3_readextee, todev, fromdev, 1.0, 0)) != inst_ok) {
+ p->log->debug = sdebug;
+ return ev;
+ }
+
+ memmove(bytes, fromdev + 5, ll);
+ }
+ p->log->debug = sdebug;
+
+ return inst_ok;
+}
+
+
+/* Take a raw measurement using a given integration time. */
+/* The measureent is the count of (both) edges from the L2V */
+/* over the integration time */
+static inst_code
+i1d3_freq_measure(
+ i1d3 *p, /* Object */
+ double *inttime, /* Integration time in seconds. (Return clock rounded) */
+ double rgb[3] /* Return the RGB values */
+) {
+ int intclks;
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ if (*inttime > 20.0) /* Hmm */
+ *inttime = 20.0;
+
+ /* Max = 357.9 seconds ? */
+ intclks = (int)(*inttime * p->clk_freq + 0.5);
+ *inttime = (double)intclks / p->clk_freq;
+
+ int2buf(todev + 1, intclks);
+
+ todev[23] = 0; /* Unknown parameter, always 0 */
+
+ if ((ev = i1d3_command(p, i1d3_measure1, todev, fromdev, 20.0, 0)) != inst_ok)
+ return ev;
+
+ rgb[0] = (double)buf2uint(fromdev + 2);
+ rgb[1] = (double)buf2uint(fromdev + 6);
+ rgb[2] = (double)buf2uint(fromdev + 10);
+
+ return inst_ok;
+}
+
+/* Take a raw measurement that returns the number of clocks */
+/* between and initial edge and edgec[] subsequent edges of the L2F. */
+/* The edge count must be between 1 and 65535 inclusive. */
+/* Both edges are counted. It's advisable to use and even edgec[], */
+/* because the L2F output may not be symetric. */
+/* If there are no edges within 10 seconds, return a count of 0 */
+static inst_code
+i1d3_period_measure(
+ i1d3 *p, /* Object */
+ int edgec[3], /* Measurement edge count for each channel */
+ int mask, /* Bit mask to enable channels */
+ double rgb[3] /* Return the RGB values */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ short2buf(todev + 1, edgec[0]);
+ short2buf(todev + 3, edgec[1]);
+ short2buf(todev + 5, edgec[2]);
+
+ todev[7] = (unsigned char)mask;
+ todev[8] = 0; /* Unknown parameter, always 0 */
+
+ if ((ev = i1d3_command(p, i1d3_measure2, todev, fromdev, 20.0, 0)) != inst_ok)
+ return ev;
+
+ rgb[0] = (double)buf2uint(fromdev + 2);
+ rgb[1] = (double)buf2uint(fromdev + 6);
+ rgb[2] = (double)buf2uint(fromdev + 10);
+
+ return inst_ok;
+}
+
+typedef enum {
+ i1d3_flash = 1,
+ i1d3_fade = 3,
+} i1d3_ledmode;
+
+static inst_code
+i1d3_set_LEDs(
+ i1d3 *p, /* Object */
+ i1d3_ledmode mode, /* 1 = off & on, 3 = off & fade on */
+ double offtime, /* Off time */
+ double ontime, /* On time. Fade is included in this */
+ int count /* Pulse count. 0x80 = infinity ? */
+) {
+ unsigned char todev[64];
+ unsigned char fromdev[64];
+ inst_code ev;
+ double mul1, mul2;
+ int ftime, ntime;
+
+ memset(todev, 0, 64);
+ memset(fromdev, 0, 64);
+
+ mul1 = p->clk_freq/(1 << 23);
+ mul2 = p->clk_freq/(1 << 19);
+
+ ftime = (int)(0.5 + offtime * mul2);
+ if (ftime < 0)
+ ftime = 0;
+ else if (ftime > 255)
+ ftime = 255;
+
+ if (mode == 1)
+ ntime = (int)(0.5 + ontime * mul2);
+ else if (mode == 3)
+ ntime = (int)(0.5 + ontime * mul1);
+ else
+ return i1d3_interp_code((inst *)p, I1D3_BAD_LED_MODE);
+
+ if (ntime < 0)
+ ntime = 0;
+ else if (ntime > 255)
+ ntime = 255;
+
+ if (count < 0)
+ count = 0;
+ else if (count > 0x80)
+ count = 0x80;
+
+ todev[1] = (unsigned char)mode;
+ todev[2] = (unsigned char)ftime;
+ todev[3] = (unsigned char)ntime;
+ todev[4] = (unsigned char)count;
+
+ if ((ev = i1d3_command(p, i1d3_setled, todev, fromdev, 1.0, 0)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - */
+/*
+
+ determining the refresh rate for a refresh type display;
+
+ Read 1300 .5 msec samples as fast as possible, and
+ timestamp them.
+ Interpolate values up to .05 msec regular samples.
+ Do an auto-correlation on the samples.
+ Pick the longest peak between 10 andf 40Hz as the best sample period,
+ 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 is no aparent refresh, or the refresh rate is not determinable,
+ return a period of 0.0 and inst_ok;
+
+ To break up the USB synchronization, the integration time
+ is randomized slightly.
+*/
+
+#ifndef PSRAND32L
+# define PSRAND32L(S) ((S) * 1664525L + 1013904223L)
+#endif
+#undef FREQ_SLOW_PRECISE /* [und] Interpolate then autocorrelate, else autc & filter */
+#define NFSAMPS 1300 /* Number of samples to read */
+#define NFMXTIME 6.0 /* Maximum time to take (2000 == 6) */
+#define PBPMS 20 /* bins per msec */
+#define PERMIN ((1000 * PBPMS)/40) /* 40 Hz */
+#define PERMAX ((1000 * PBPMS)/5) /* 5 Hz*/
+#define NPER (PERMAX - PERMIN + 1)
+//#define PWIDTH (3 * PBPMS) /* 3 msec bin spread to look for peak in */
+#define PWIDTH (8 * PBPMS) /* 3 msec bin spread to look for peak in */
+#define MAXPKS 20 /* Number of peaks to find */
+
+/* Set refperiod, refrate if possible */
+static inst_code
+i1d3_imp_measure_refresh(
+ i1d3 *p, /* Object */
+ double *prefrate, /* Return value, 0.0 if none */
+ double *ppval /* Return period value, 0.0 if none */
+) {
+ inst_code ev;
+ int i, j, k;
+ double ucalf = 1.0; /* usec_time calibration factor */
+ double inttimel = 0.0003;
+ double inttimeh = 0.0040;
+ double sutime, putime, cutime, eutime;
+ static unsigned int randn = 0x12345678;
+ struct {
+ double itime; /* Integration time */
+ double sec;
+ double rgb[3];
+ } samp[NFSAMPS];
+ int nfsamps; /* Actual samples read */
+ double maxt; /* Time range */
+ double rms[3]; /* RMS value of each channel */
+ double trms; /* Total RMS */
+ int nbins;
+ double *bins[3]; /* PBPMS sample bins */
+ double tcorr[NPER]; /* Temp for initial autocorrelation */
+ double corr[NPER]; /* Filtered correlation for each period value */
+ double mincv, maxcv; /* Max and min correlation values */
+ double crange; /* Correlation range */
+ double peaks[MAXPKS]; /* Each peak from longest to shortest */
+ int npeaks = 0; /* Number of peaks */
+ double pval; /* Period value */
+ int isdeb;
+
+ if (prefrate != NULL)
+ *prefrate = 0.0;
+ if (ppval != NULL)
+ *ppval = 0.0;
+
+ if (usec_time() < 0.0) {
+ a1loge(p->log, inst_internal_error, "i1d3_measure_refresh: No high resolution timers\n");
+ return inst_internal_error;
+ }
+
+ /* Turn debug off so that it doesn't intefere with measurement timing */
+ isdeb = p->log->debug;
+ p->icom->log->debug = 0;
+
+ /* Do some measurement and throw them away, to make sure the code is in cache. */
+ for (i = 0; i < 5; i++) {
+ if ((ev = i1d3_freq_measure(p, &inttimeh, samp[i].rgb)) != inst_ok) {
+ p->log->debug = isdeb;
+ return ev;
+ }
+ }
+
+#ifdef NEVER /* This appears to be unnecessary */
+ /* Calibrate the usec timer against the instrument */
+ {
+ double inttime1, inttime2;
+ inttime1 = 0.001;
+ inttime2 = 0.501;
+
+ sutime = usec_time();
+
+ if ((ev = i1d3_freq_measure(p, &inttime1, samp[0].rgb)) != inst_ok) {
+ p->log->debug = isdeb;
+ return ev;
+ }
+
+ putime = usec_time();
+
+ if ((ev = i1d3_freq_measure(p, &inttime2, samp[0].rgb)) != inst_ok) {
+ p->log->debug = isdeb;
+ return ev;
+ }
+
+ cutime = usec_time();
+
+ ucalf = 1000000.0 * (inttime2 - inttime1)/(cutime - 2.0 * putime + sutime);
+
+ a1logd(p->log, 3, "i1d3_measure_refresh: Clock calibration factor = %f\n",ucalf);
+ }
+#endif
+
+ /* Read the samples */
+ sutime = usec_time();
+ putime = (usec_time() - sutime) / 1000000.0;
+ for (i = 0; i < NFSAMPS; i++) {
+ double rval;
+
+ randn = PSRAND32L(randn);
+ rval = (double)randn/4294967295.0;
+ rval *= rval;
+ rval *= rval; /* Sharpen random time up */
+ samp[i].itime = (inttimeh - inttimel) * rval + inttimel;
+
+ if ((ev = i1d3_freq_measure(p, &samp[i].itime, samp[i].rgb)) != inst_ok) {
+ p->log->debug = isdeb;
+ return ev;
+ }
+ cutime = (usec_time() - sutime) / 1000000.0;
+// ~~999
+ samp[i].sec = 0.5 * (putime + cutime); /* Mean of before and after stamp */
+//samp[i].sec *= 85.0/20.0; /* Test 20 Hz */
+//samp[i].sec *= 85.0/100.0; /* Test 100 Hz */
+ putime = cutime;
+ if (cutime > NFMXTIME)
+ break;
+ }
+ p->log->debug = isdeb;
+
+ nfsamps = i;
+ if (nfsamps < 100) {
+ a1logv(p->log, 1, "No distict refresh period\n");
+ a1logd(p->log, 3, "i1d3_measure_refresh: Couldn't find a distinct refresh frequency\n");
+ return inst_ok;
+ }
+
+ a1logd(p->log, 3, "i1d3_measure_refresh: Read %d samples for refresh calibration\n",nfsamps);
+
+#ifdef NEVER
+ /* Plot the raw sensor values */
+ {
+ double xx[NFSAMPS];
+ double y1[NFSAMPS];
+ double y2[NFSAMPS];
+ double y3[NFSAMPS];
+
+ for (i = 0; i < nfsamps; i++) {
+ xx[i] = samp[i].sec;
+ y1[i] = samp[i].rgb[0];
+ y2[i] = samp[i].rgb[1];
+ y3[i] = samp[i].rgb[2];
+ //printf("%d: %f -> %f\n",i,samp[i].sec, samp[i].rgb[0]);
+ }
+ printf("Fast scan sensor values and time (sec)\n");
+ do_plot6(xx, y1, y2, y3, NULL, NULL, NULL, nfsamps);
+ }
+#endif
+
+ /* Re-zero the sample times, normalise int time, and calibrate it. */
+ maxt = -1e6;
+ rms[0] = rms[1] = rms[2] = 0.0;
+ for (i = nfsamps-1; i >= 0; i--) {
+ samp[i].sec -= samp[0].sec;
+ samp[i].sec *= ucalf;
+ if (samp[i].sec > maxt)
+ maxt = samp[i].sec;
+ for (j = 0; j < 3; j++) {
+ samp[i].rgb[j] /= samp[i].itime;
+ rms[j] += samp[i].rgb[j] * samp[i].rgb[j];
+ }
+ }
+ trms = 0.0;
+ for (j = 0; j < 3; j++) {
+ rms[j] /= (double)nfsamps;
+ trms += rms[j];
+ rms[j] = sqrt(rms[j]);
+ }
+ trms = sqrt(trms);
+ a1logd(p->log, 4, "RMS = %f %f %f, total %f\n", rms[0], rms[1], rms[2], trms);
+
+#ifdef FREQ_SLOW_PRECISE /* Interp then autocorrelate */
+
+ /* Create PBPMS bins and interpolate readings into them */
+ nbins = 1 + (int)(maxt * 1000.0 * PBPMS + 0.5);
+ for (j = 0; j < 3; j++) {
+ if ((bins[j] = (double *)calloc(sizeof(double), nbins)) == NULL) {
+ a1loge(p->log, inst_internal_error, "i1d3_measure_refresh: malloc failed\n");
+ return inst_internal_error;
+ }
+ }
+
+ /* Do the interpolation */
+ for (k = 0; k < (nfsamps-1); k++) {
+ int sbin, ebin;
+ sbin = (int)(samp[k].sec * 1000.0 * PBPMS + 0.5);
+ ebin = (int)(samp[k+1].sec * 1000.0 * PBPMS + 0.5);
+ for (i = sbin; i <= ebin; i++) {
+ double bl;
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ bl = (i - sbin)/(double)(ebin - sbin); /* 0.0 to 1.0 */
+ for (j = 0; j < 3; j++) {
+ bins[j][i] = (1.0 - bl) * samp[k].rgb[j] + bl * samp[k+1].rgb[j];
+ }
+ }
+ }
+
+#ifdef NEVER
+ /* Plot interpolated values */
+ {
+ double *xx;
+ double *y1;
+ double *y2;
+ double *y3;
+
+ xx = malloc(sizeof(double) * nbins);
+ y1 = malloc(sizeof(double) * nbins);
+ y2 = malloc(sizeof(double) * nbins);
+ y3 = malloc(sizeof(double) * nbins);
+
+ if (xx == NULL || y1 == NULL || y2 == NULL || y3 == NULL) {
+ a1loge(p->log, inst_internal_error, "i1d3_measure_refresh: malloc failed\n");
+ for (j = 0; j < 3; j++)
+ free(bins[j]);
+ return inst_internal_error;
+ }
+ for (i = 0; i < nbins; i++) {
+ xx[i] = i / (double)PBPMS; /* msec */
+ y1[i] = bins[0][i];
+ y2[i] = bins[1][i];
+ y3[i] = bins[2][i];
+ }
+ printf("Interpolated fast scan sensor values and time (msec)\n");
+ do_plot6(xx, y1, y2, y3, NULL, NULL, NULL, nbins);
+
+ free(xx);
+ free(y1);
+ free(y2);
+ free(y3);
+ }
+#endif /* PLOT_REFRESH */
+
+ /* Compute auto-correlation at 1/PBPMS msec intervals */
+ /* from 25 msec (40Hz) to 100msec (10 Hz) */
+ mincv = 1e48, maxcv = -1e48;
+ for (i = 0; i < NPER; i++) {
+ int poff = PERMIN + i; /* Offset to corresponding sample */
+ corr[i] = 0.0;
+
+ for (k = 0; (k + poff) < nbins; k++)
+ corr[i] += bins[0][k] * bins[0][k + poff];
+ for (k = 0; (k + poff) < nbins; k++)
+ corr[i] += bins[1][k] * bins[1][k + poff];
+ for (k = 0; (k + poff) < nbins; k++)
+ corr[i] += bins[2][k] * bins[2][k + poff];
+
+ corr[i] /= (double)k; /* Normalize */
+ if (corr[i] > maxcv)
+ maxcv = corr[i];
+ if (corr[i] < mincv)
+ mincv = corr[i];
+ }
+ for (j = 0; j < 3; j++)
+ free(bins[j]);
+
+#else /* !FREQ_SLOW_PRECISE Fast - autocorrellate then filter */
+
+ /* Do point by point correllation of samples */
+ for (i = 0; i < NPER; i++)
+ tcorr[i] = 0.0;
+
+ for (j = 0; j < (nfsamps-1); j++) {
+
+ for (k = j+1; k < nfsamps; k++) {
+ double del, cor;
+ int bix;
+
+ del = samp[k].sec - samp[j].sec;
+ bix = (int)(del * 1000.0 * PBPMS + 0.5);
+ if (bix < PERMIN)
+ continue;
+ if (bix > PERMAX)
+ break;
+ bix -= PERMIN;
+
+// cor = samp[j].rgb[0] * samp[k].rgb[0]
+// + samp[j].rgb[1] * samp[k].rgb[1]
+// + samp[j].rgb[2] * samp[k].rgb[2];
+
+ cor = samp[j].rgb[1] * samp[k].rgb[1];
+
+ tcorr[bix] += cor;
+ }
+ }
+
+#ifdef PLOT_REFRESH
+ /* Plot unfiltered auto correlation */
+ {
+ double xx[NPER];
+ double y1[NPER];
+
+ for (i = 0; i < NPER; i++) {
+ xx[i] = (i + PERMIN) / (double)PBPMS; /* msec */
+ y1[i] = tcorr[i];
+ }
+ printf("Unfiltered auto correlation (msec)\n");
+ do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, NPER);
+ }
+#endif /* PLOT_REFRESH */
+
+ /* Apply a 5 msec gausian filter */
+#define FWIDTH 6
+ {
+ double gaus_[2 * FWIDTH * PBPMS + 1];
+ double *gaus = &gaus_[FWIDTH * PBPMS];
+ double bb = 1.0/pow(2, 5.0);
+
+ for (j = (-FWIDTH * PBPMS); j <= (FWIDTH * PBPMS); j++) {
+ double tt;
+ tt = (double)j/(FWIDTH * PBPMS);
+ gaus[j] = 1.0/pow(2, 5.0 * tt * tt) - bb;
+ }
+ for (k = 0; k < 1; k++) {
+ for (i = 0; i < NPER; i++) {
+ double sum = 0.0;
+ double wght = 0.0;
+
+ for (j = (-FWIDTH * PBPMS); j <= (FWIDTH * PBPMS); j++) {
+ double w;
+ int ix = i + j;
+ if (ix < 0)
+ continue;
+ if (ix > (NPER-1))
+ break;
+ w = gaus[j];
+ sum += w * tcorr[ix];
+ wght += w;
+ }
+ corr[i] = sum / wght;
+ }
+ }
+ }
+
+ /* Compute min & max */
+ mincv = 1e48, maxcv = -1e48;
+ for (i = 0; i < NPER; i++) {
+ if (corr[i] > maxcv)
+ maxcv = corr[i];
+ if (corr[i] < mincv)
+ mincv = corr[i];
+ }
+
+#endif /* !FREQ_SLOW_PRECISE Fast - autocorrellate then filter */
+
+ crange = maxcv - mincv;
+ a1logd(p->log,4,"Correlation value range %f - %f = %f = %f%%\n",mincv, maxcv,crange, 100.0 * (maxcv-mincv)/maxcv);
+
+#ifdef PLOT_REFRESH
+ /* Plot auto correlation */
+ {
+ double xx[NPER];
+ double y1[NPER];
+
+ for (i = 0; i < NPER; i++) {
+ xx[i] = (i + PERMIN) / (double)PBPMS; /* msec */
+ y1[i] = corr[i];
+ }
+ printf("Auto correlation (msec)\n");
+ do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, NPER);
+ }
+#endif /* PLOT_REFRESH */
+
+ /* If there is sufficient level and distict correlations */
+ if (trms >= 1000 && (maxcv-mincv)/maxcv >= 0.10) {
+
+ /* Locate all the peaks starting at the longest correllation */
+ for (i = (NPER-1-PWIDTH); i >= 0 && npeaks < MAXPKS; i--) {
+ double v1, v2, v3;
+ v1 = corr[i];
+ v2 = corr[i + PWIDTH/2];
+ v3 = corr[i + PWIDTH];
+
+ if (fabs(v3 - v1) < (0.05 * crange)
+ && (v2 - v1) > (0.025 * crange)
+ && (v2 - v3) > (0.025 * crange)) {
+ double pkv; /* Peak value */
+ int pki; /* Peak index */
+ double ii, bl;
+
+ a1logd(p->log,4,"Max between %f and %f msec\n",
+ (i + PERMIN)/(double)PBPMS,(i + PWIDTH + PERMIN)/(double)PBPMS);
+
+ /* Locate the actual peak */
+ pkv = -1.0;
+ pki = 0;
+ for (j = i; j < (i + PWIDTH); j++) {
+ if (corr[j] > pkv) {
+ pkv = corr[j];
+ pki = j;
+ }
+ }
+ a1logd(p->log,4,"Peak is at %f msec, %f corr\n", (pki + PERMIN)/(double)PBPMS, pkv);
+
+ /* Interpolate the peak value for higher precision */
+ /* j = bigest */
+ if (corr[pki-1] > corr[pki+1]) {
+ j = pki-1;
+ k = pki+1;
+ } else {
+ j = pki+1;
+ k = pki-1;
+ }
+ bl = (corr[pki] - corr[j])/(corr[pki] - corr[k]);
+ bl = (bl + 1.0)/2.0;
+ ii = bl * pki + (1.0 - bl) * j;
+ pval = (ii + PERMIN)/(double)PBPMS;
+
+ a1logd(p->log,4,"Interpolated peak is at %f msec\n", pval);
+
+ peaks[npeaks++] = pval;
+
+ i -= PWIDTH;
+ }
+ }
+ }
+
+ a1logd(p->log,3,"Number of peaks located = %d\n",npeaks);
+ if (npeaks == 0) {
+ a1logd(p->log, 2, "i1d3: Couldn't find a distinct refresh frequency\n");
+ a1logv(p->log, 1, "No distict refresh period\n");
+ return inst_ok;
+ }
+
+ if (npeaks == 1) {
+ a1logd(p->log,3,"Only one peak\n");
+ pval = peaks[0] / 2000.0; /* Scale by half and convert to seconds */
+
+ a1logd(p->log, 1, "Quantizing to %f msec\n",pval);
+ a1logv(p->log, 1, "Quantizing to %f msec\n",pval);
+
+ if (ppval != NULL)
+ *ppval = pval;
+
+ } else {
+ int nfails;
+ double div, avg, ano;
+ /* Try and locate a common divisor amongst all the peaks. */
+ /* This is likely to be the underlying refresh rate. */
+ for (k = 0; k < npeaks; k++) {
+ for (j = 1; j < 20; j++) {
+ avg = ano = 0.0;
+ div = peaks[k]/(double)j;
+ if (div < 9.0)
+ continue; /* Skip anything over 100Hz */
+ for (nfails = i = 0; i < npeaks; i++) {
+ double rem, cnt;
+
+ rem = peaks[i]/div;
+ cnt = floor(rem + 0.5);
+ rem = fabs(rem - cnt);
+
+ a1logd(p->log, 1, "remainder for peak %d = %f\n",i,rem);
+ if (rem > 0.06) {
+ if (++nfails > 2)
+ break; /* Fail this divisor */
+ }
+ avg += peaks[i]; /* Already weighted by cnt */
+ ano += cnt;
+ }
+
+// if (i >= npeaks)
+ if (nfails == 0 || (nfails <= 2 && npeaks >= 6))
+ break; /* Sucess */
+ /* else go and try a different divisor */
+ }
+ if (j < 20)
+ break; /* Found common divisor */
+ }
+ if (k >= npeaks) {
+ a1logd(p->log,3,"Failed to locate common divisor\n");
+ pval = peaks[0] / 2000.0; /* Scale by half and convert to seconds */
+
+ if (ppval != NULL)
+ *ppval = pval;
+
+
+ a1logd(p->log, 1, "Quantizing to %f msec\n",pval);
+ a1logv(p->log, 1, "Quantizing to %f msec\n",pval);
+
+ } else {
+ int mul;
+ double refrate;
+
+ pval = avg/ano;
+ pval /= 1000.0; /* Convert to seconds */
+ refrate = 1.0/pval;
+
+ if (prefrate != NULL)
+ *prefrate = refrate; /* Save it for get_refr_rate() */
+
+ /* Error against my 85Hz CRT - GWG */
+// a1logd(p->log, 1, "Refresh rate error = %.4f%%\n",100.0 * fabs(refrate - 85.0)/(85.0));
+
+ /* Scale to just above 20 Hz */
+ mul = floor((1.0/20) / pval);
+ if (mul > 1)
+ pval *= mul;
+
+ a1logd(p->log, 1, "Refresh rate = %f Hz, quantizing to %f msec\n",refrate,pval);
+ a1logv(p->log, 1, "Refresh rate = %f Hz, quantizing to %f msec\n",refrate,pval);
+
+ if (ppval != NULL)
+ *ppval = pval;
+ }
+ }
+
+ return inst_ok;
+}
+#undef NFSAMPS
+#undef PBPMS
+#undef PERMIN
+#undef PERMAX
+#undef NPER
+#undef PWIDTH
+
+/* Measure and then set refperiod, refrate if possible */
+static inst_code
+i1d3_measure_set_refresh(
+ i1d3 *p /* Object */
+) {
+ inst_code rv;
+ double refrate = 0.0;
+ int mul;
+ double pval;
+
+ if ((rv = i1d3_imp_measure_refresh(p, &refrate, &pval)) != inst_ok) {
+ return rv;
+ }
+
+ p->refrate = refrate;
+ p->refrvalid = refrate != 0.0 ? 1 : 0;
+ p->refperiod = pval;
+ p->rrset = 1;
+
+ return inst_ok;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Take an ambient measurement and return the cooked reading */
+/* The cooked reading is the frequency of the L2V */
+static inst_code
+i1d3_take_amb_measurement(
+ i1d3 *p, /* Object */
+ double *rgb /* Return the ambient RGB values */
+) {
+ int i; /* Returned byte - not used */
+ int pos;
+ inst_code ev;
+
+ if (p->inited == 0)
+ return i1d3_interp_code((inst *)p, I1D3_NOT_INITED);
+
+ a1logd(p->log,3,"take_amb_measurement called\n");
+
+ /* Check that the ambient filter is in place */
+ if ((ev = i1d3_get_diffpos(p, &pos, 0)) != inst_ok)
+ return ev;
+
+ if (pos != 1)
+ return i1d3_interp_code((inst *)p, I1D3_SPOS_AMB);
+
+ if ((ev = i1d3_freq_measure(p, &p->inttime, rgb)) != inst_ok)
+ return ev;
+
+ /* Scale to account for counting both edges (?) over integration time */
+ /* and subtract black level */
+ for (i = 0; i < 3; i++) {
+ rgb[i] *= 0.5/p->inttime;
+ rgb[i] -= p->black[i];
+ if (rgb[i] < 0.0)
+ rgb[i] = 0.0;
+ }
+
+ a1logd(p->log,3,"take_amb_measurement returned %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ return inst_ok;
+}
+
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Take an display measurement and return the cooked reading */
+/* The cooked reading is the frequency of the L2V */
+static inst_code
+i1d3_take_emis_measurement(
+ i1d3 *p, /* Object */
+ i1d3_mmode mode, /* Measurement mode */
+ double *rgb /* Return the cooked emsissive RGB values */
+) {
+ int i, k;
+ int pos;
+ inst_code ev;
+ double rmeas[3] = { -1.0, -1.0, -1.0 }; /* raw measurement */
+ int edgec[3] = {2,2,2}; /* Measurement edge count for each channel (not counting start edge) */
+ int mask = 0x7; /* Period measure mask */
+ int msecstart = msec_time(); /* Debug */
+ double rgb2[3] = { 0.0, 0.0, 0.0 }; /* Trial measurement RGB values */
+
+ if (p->inited == 0)
+ return i1d3_interp_code((inst *)p, I1D3_NOT_INITED);
+
+ a1logd(p->log,3,"\ntake_emis_measurement called\n");
+
+ /* Check that the ambient filter is not in place */
+ if ((ev = i1d3_get_diffpos(p, &pos, 0)) != inst_ok)
+ return ev;
+
+ if (pos != 0)
+ return i1d3_interp_code((inst *)p, I1D3_SPOS_EMIS);
+
+
+ /* If we should take a frequency measurement first */
+ if (mode == i1d3_adaptive || mode == i1d3_frequency) {
+
+ /* Typically this is 200msec for non-refresh, 400msec for refresh. */
+ a1logd(p->log,3,"Doing fixed period frequency measurement over %f secs\n",p->inttime);
+
+ /* Take a frequency measurement over a fixed period */
+ if ((ev = i1d3_freq_measure(p, &p->inttime, rmeas)) != inst_ok)
+ return ev;
+
+ /* Convert to frequency (assume raw meas is both edges count over integration time) */
+ for (i = 0; i < 3; i++) {
+ rgb[i] = (0.5 * rmeas[i])/p->inttime;
+ }
+
+ a1logd(p->log,3,"Got %f %f %f raw, %f %f %f Hz\n",rmeas[0],rmeas[1],rmeas[2],rgb[0],rgb[1],rgb[2]);
+ }
+
+ /* If some period measurement will be done */
+ if (mode != i1d3_frequency) {
+
+ /* Decide if a period measurement is needed */
+ if (mode == i1d3_adaptive) {
+
+ mask = 0x0;
+
+ for (i = 0; i < 3; i++) {
+ /* Not measured or count is too small for desired precision. */
+ /* (We're being twice as critical as the OEM driver here) */
+ if (rmeas[i] < 200.0) { /* Could be 0.25% quantization error */
+ a1logd(p->log,3,"chan %d needs re-reading\n",i);
+ mask |= 1 << i;
+ } else {
+ a1logd(p->log,3,"chan %d has sufficient frequeny count\n",i);
+ }
+ }
+ }
+
+ if (mask != 0x0) { /* Some measurement wasn't accurate enough, so use period */
+ /* or longer frequency measurement */
+ int mask2 = mask;
+ double tintt[3]; /* Per channel re-measure target int. times */
+ double tinttime; /* Maximum re-measure target integration time */
+
+ /* See if we need to do some pre-measurement to compute how many */
+ /* edges to count. */
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) == 0)
+ continue;
+
+ if (rmeas[i] < 10.0
+ || (p->dtype != i1d3_munkdisp && rmeas[i] < 20.0)) {
+ a1logd(p->log,3,"chan %d needs pre-measurement\n",i);
+ mask2 |= 1 << i;
+ } else {
+ double freq;
+ mask2 &= ~(1 << i);
+ /* Convert rmeas[i] from frequency to period equivalent */
+ /* for subsequent calculations */
+ freq = (rmeas[i] * 0.5)/p->inttime;
+ rmeas[i] = (0.5 * edgec[i] * p->clk_freq)/freq;
+ a1logd(p->log,3,"chan %d has sufficient frequeny count to avoid pre-measure (rmeas_p %f)\n",i,rmeas[i]);
+ }
+ }
+ if (mask2 != 0x0) {
+ int mask3 = 0x0;
+ double rmeas2[3];
+
+ a1logd(p->log,3,"Doing 1st period pre-measurement mask 0x%x, edgec %d %d %d\n",mask2,edgec[0],edgec[1],edgec[2]);
+ /* Take an initial period pre-measurement over 2 edges */
+ if ((ev = i1d3_period_measure(p, edgec, mask2, rmeas2)) != inst_ok)
+ return ev;
+
+ a1logd(p->log,3,"Got %f %f %f raw %f %f %f Hz\n",rmeas2[0],rmeas2[1],rmeas2[2],
+ 0.5 * edgec[0] * p->clk_freq/rmeas2[0],
+ 0.5 * edgec[1] * p->clk_freq/rmeas2[1],
+ 0.5 * edgec[2] * p->clk_freq/rmeas2[2]);
+
+ /* Transfer updated counts from 1st initial measurement */
+ for (i = 0; i < 3; i++) {
+ if ((mask2 & (1 << i)) != 0) {
+ rmeas[i] = rmeas2[i];
+
+ /* Compute trial RGB in case we need it later */
+ if (rmeas[i] >= 0.5) {
+ rgb2[i] = (p->clk_freq * 0.5 * edgec[i])/rmeas[i];
+ }
+ }
+ }
+
+ /* Do 2nd initial measurement if the count is small, in case */
+ /* we are measuring a CRT with a refresh rate which adds innacuracy, */
+ /* and could result in a unecessarily long re-reading. */
+ /* Don't do this for Munki Display, because of its slow measurements. */
+ if (p->dtype != i1d3_munkdisp) {
+ for (i = 0; i < 3; i++) {
+ if ((mask2 & (1 << i)) == 0)
+ continue;
+
+ if (rmeas2[i] > 0.5) {
+ double pintt, nedgec;
+ int inedgec;
+
+ /* Compute number of edges needed for a clock count */
+ /* of 0.100 seconds */
+
+ pintt = 0.1;
+
+ if (p->refperiod > 0.0) { /* If we have a refresh period */
+ int n;
+ n = (int)ceil(pintt/p->refperiod); /* Quantize */
+ pintt = n * p->refperiod;
+ }
+
+ nedgec = edgec[i] * pintt * p->clk_freq/rmeas2[i];
+
+ a1logd(p->log,3,"chan %d target edges %f\n",i,nedgec);
+
+ /* Limit to a legal range */
+ if (nedgec > 65534.0)
+ nedgec = 65534.0;
+ else if (nedgec < 2.0)
+ nedgec = 2.0;
+
+ /* Round down to nearest even edge count */
+ inedgec = 2.0 * (int)floor(nedgec/2.0);
+
+ a1logd(p->log,3,"chan %d set edgec to %d\n",i,inedgec);
+
+ /* Don't do 2nd initial measure if we have fewer number of edges */
+ if (inedgec > edgec[i]) {
+ mask3 |= (1 << i);
+ edgec[i] = (int)inedgec;
+ }
+ } else {
+ a1logd(p->log,3,"chan %d had no reading, so skipping period measurement\n",i);
+ }
+ }
+ if (mask3 != 0x0) {
+
+ a1logd(p->log,3,"Doing 2nd initial period measurement mask 0x%x, edgec %d %d %d\n",mask2,edgec[0],edgec[1],edgec[2]);
+ /* Take a 2nd initial period measurement */
+ if ((ev = i1d3_period_measure(p, edgec, mask3, rmeas2)) != inst_ok)
+ return ev;
+
+ a1logd(p->log,3,"Got %f %f %f raw %f %f %f Hz\n",rmeas2[0],rmeas2[1],rmeas2[2],
+ 0.5 * edgec[0] * p->clk_freq/rmeas2[0],
+ 0.5 * edgec[1] * p->clk_freq/rmeas2[1],
+ 0.5 * edgec[2] * p->clk_freq/rmeas2[2]);
+
+ /* Transfer updated counts from 2nd initial measurement */
+ for (i = 0; i < 3; i++) {
+ if ((mask3 & (1 << i)) != 0)
+ rmeas[i] = rmeas2[i];
+
+ /* Compute trial RGB in case we need it later */
+ if (rmeas[i] >= 0.5) {
+ rgb2[i] = (p->clk_freq * 0.5 * edgec[i])/rmeas[i];
+ }
+ }
+ }
+ }
+ }
+
+ /* Now setup for re-measure, aiming for longer freq/full period measurement. */
+ /* Compute a target integration time for this re-measurement */
+ tinttime = tintt[0] = tintt[1] = tintt[2] = p->inttime;
+ for (i = 0; i < 3; i++) {
+ double nedgec;
+
+ if ((mask & (1 << i)) == 0 || rmeas[i] <= 0.5)
+ continue;
+
+ /* Compute number of edges needed for a clock count */
+ /* of p->inttime (0.2 secs) */
+ nedgec = edgec[i] * p->inttime * p->clk_freq/rmeas[i];
+
+ /* If we will get less than 200 edges, raise the target integration */
+ /* time in a curve to aim at a higher edge count up to 200 */
+ if (nedgec < 200.0) {
+ double bl, tedges;
+ double mint;
+
+ /* Blend down from target of 200 to minimum target of 1 edge over 8 sec. */
+ /* (Allow margine away from max integration time of 10 secs) */
+ mint = p->inttime/6.0;
+ bl = (nedgec - mint)/(200.0 - mint);
+ if (bl < 0.0)
+ bl = 0.0;
+ else {
+ /* This power sets how fast the int. time rises */
+ bl = pow(bl, 0.5); /* Use longer int. times to increase ecount */
+ }
+ tedges = bl * (200.0 - mint) + mint;
+
+ tintt[i] = tedges/(edgec[i] * p->clk_freq/rmeas[i]);
+
+ if (tintt[i] > 6.0) /* Maximum possible is 10 seconds */
+ tintt[i] = 6.0;
+
+ if (p->refperiod > 0.0) { /* If we have a refresh period */
+ int n;
+ n = (int)ceil(tintt[i]/p->refperiod); /* Quantize */
+ tintt[i] = n * p->refperiod;
+ }
+ if (tintt[i] > tinttime) /* New overal max. int. time */
+ tinttime = tintt[i];
+ }
+ }
+ a1logd(p->log,3,"target re-measure inttime %f\n",tinttime);
+
+ /* Now compute the number of edges to measure */
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) == 0)
+ continue;
+
+ if (rmeas[i] > 0.5) {
+ double nedgec, onedgec, atintt;
+
+ /* Compute number of edges needed for a clock count */
+ /* of tintt[i], the individual channels goal */
+ nedgec = edgec[i] * tintt[i] * p->clk_freq/rmeas[i];
+
+ /* Limit to a legal range */
+ if (nedgec > 65534.0)
+ nedgec = 65534.0;
+ else if (nedgec < 2.0)
+ nedgec = 2.0;
+
+ /* Round down to the nearest even edge count */
+ nedgec = 2.0 * (int)floor(nedgec/2.0);
+
+ /* Compute number of edges needed for the overall goal */
+ /* of clock count of tinttime */
+ onedgec = edgec[i] * tinttime * p->clk_freq/rmeas[i];
+
+ /* Limit to a legal range */
+ if (onedgec > 65534.0)
+ onedgec = 65534.0;
+ else if (onedgec < 2.0)
+ onedgec = 2.0;
+
+ /* Round down to nearest even edge count */
+ onedgec = 2.0 * (int)floor(onedgec/2.0);
+
+ /* Use this overall edge count goal, as long as */
+ /* it doesn't excessively increase the overall integration time */
+ atintt = onedgec * rmeas[i]/(edgec[i] * p->clk_freq);
+
+ if (atintt < (1.1 * tinttime))
+ nedgec = onedgec;
+
+ a1logd(p->log,3,"chan %d set edgec to %d\n",i,(int)nedgec);
+
+ /* Don't measure again if we have same number of edges as last time */
+ if (edgec[i] == (int)nedgec) {
+
+ /* Use previous measurement */
+ rgb[i] = (p->clk_freq * 0.5 * edgec[i])/rmeas[i];
+ mask &= ~(1 << i);
+ edgec[i] = 0;
+
+ a1logd(p->log,3,"chan %d skipping re-measure, frequency %f\n",i,rgb[i]);
+
+ } else {
+ edgec[i] = (int)nedgec;
+ }
+ } else {
+ /* Don't measure again, we failed to see any edges */
+ rgb[i] = 0.0;
+ mask &= ~(1 << i);
+ edgec[i] = 0;
+ }
+ }
+
+ if (mask != 0x0) {
+ int minedgec = 1000;
+
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) == 0)
+ continue;
+ if (edgec[i] < minedgec)
+ minedgec = edgec[i];
+ }
+ a1logd(p->log,3,"Minedgec = %d\n",minedgec);
+
+ /* Use frequency measurement over the fixed period if refresh display */
+ /* This compromises quantization error for improved stability */
+ if (p->refperiod > 0.0 /* If we have a refresh period */
+ && minedgec >= 100) { /* and the expected edge count is sufficient */
+ int n;
+
+ a1logd(p->log,3,"Doing freq re-measure inttime %f\n",tinttime);
+
+ /* Take a frequency measurement over a fixed period */
+ if ((ev = i1d3_freq_measure(p, &tinttime, rmeas)) != inst_ok)
+ return ev;
+
+ /* Convert raw measurement to frequency */
+ for (i = 0; i < 3; i++) {
+ rgb[i] = (0.5 * rmeas[i])/tinttime;
+ }
+
+ a1logd(p->log,3,"Got %f %f %f raw, %f %f %f Hz after re-measure\n",rmeas[0],rmeas[1],rmeas[2],rgb[0],rgb[1],rgb[2]);
+
+ } else {
+ /* Use period measurement of the target number of edges */
+ /* (Note that if the patch isn't constant and drops compared to */
+ /* the trial measurement used to set the target number of edges, */
+ /* that the measurement may time out and return 0. In this case */
+ /* we fall back on the trial value rather than return 0.) */
+
+ a1logd(p->log,3,"Doing period re-measure mask 0x%x, edgec %d %d %d\n",mask,edgec[0],edgec[1],edgec[2]);
+ /* Measure again with desired precision, taking up to 0.4/0.8 secs */
+ if ((ev = i1d3_period_measure(p, edgec, mask, rmeas)) != inst_ok)
+ return ev;
+
+ for (i = 0; i < 3; i++) {
+ double tt;
+ if ((mask & (1 << i)) == 0)
+ continue;
+
+ /* Compute the frequency from period measurement */
+ if (rmeas[i] < 0.5) /* Number of edges wasn't counted */
+ rgb[i] = rgb2[i]; /* Trial value, since it may be more realistic */
+ else
+ rgb[i] = (p->clk_freq * 0.5 * edgec[i])/rmeas[i];
+ a1logd(p->log,3,"chan %d raw %f frequency %f (%f Sec)\n",i,rmeas[i],rgb[i],
+ rmeas[i]/p->clk_freq);
+ }
+ a1logd(p->log,3,"Got %f %f %f Hz after period measure\n",rgb[0],rgb[1],rgb[2]);
+ }
+ }
+ }
+ }
+
+ a1logd(p->log,3,"Took %d msec to measure\n", msec_time() - msecstart);
+
+ /* Subtract black level */
+ for (i = 0; i < 3; i++) {
+ rgb[i] -= p->black[i];
+ if (rgb[i] < 0.0)
+ rgb[i] = 0.0;
+ }
+
+ a1logd(p->log,3,"Cooked RGB = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ return inst_ok;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Take a XYZ measurement from the device */
+static inst_code
+i1d3_take_XYZ_measurement(
+ i1d3 *p, /* Object */
+ double XYZ[3] /* Return the XYZ values */
+) {
+ inst_code ev;
+
+ if (IMODETST(p->mode, inst_mode_emis_ambient)) {
+ if ((ev = i1d3_take_amb_measurement(p, XYZ)) != inst_ok)
+ return ev;
+
+ /* Multiply by ambient calibration matrix */
+ icmMulBy3x3(XYZ, p->ambi_cal, XYZ);
+ icmScale3(XYZ, XYZ, 1/3.141592654); /* Convert from Lux to cd/m^2 */
+
+ } else {
+
+ /* Constant fast speed, poor accuracy for black */
+// if ((ev = i1d3_take_emis_measurement(p, i1d3_frequency, XYZ)) != inst_ok)
+// return ev;
+
+ /* Most accurate ? */
+// if ((ev = i1d3_take_emis_measurement(p, i1d3_period, XYZ)) != inst_ok)
+// return ev;
+
+ /* Best combination */
+ if ((ev = i1d3_take_emis_measurement(p, i1d3_adaptive, XYZ)) != inst_ok)
+ return ev;
+
+ /* Multiply by current emissive calibration matrix */
+ icmMulBy3x3(XYZ, p->emis_cal, XYZ);
+
+ /* Apply the (optional) colorimeter correction matrix */
+ icmMulBy3x3(XYZ, p->ccmat, XYZ);
+
+ }
+ a1logd(p->log,3,"returning XYZ = %f %f %f\n",XYZ[0],XYZ[1],XYZ[2]);
+ return inst_ok;
+}
+
+// ============================================================
+
+/* Decode the Internal EEPROM */
+static inst_code i1d3_decode_intEE(
+ i1d3 *p,
+ unsigned char *buf /* Buffer holding 256 bytes from Internal EEProm */
+) {
+ int i;
+ unsigned int t1;
+
+ /* Read the serial number */
+ strncpy(p->serial_no, (char *)buf + 0x10, 20);
+ p->serial_no[20] = '\000';
+
+ /* Read the black level offset */
+ for (i = 0; i < 3; i++) {
+ t1 = buf2uint(buf + 0x0004 + 4 * i);
+
+ if (t1 == 0xffffffff)
+ p->black[0] = 0.0;
+ else
+ p->black[0] = (double)t1/6e6;
+ }
+
+ return inst_ok;
+}
+
+/* Decode the External EEPRom */
+static inst_code i1d3_decode_extEE(
+ i1d3 *p,
+ unsigned char *buf /* Buffer holding 8192 bytes from External EEProm */
+) {
+ int i, j;
+ unsigned int off;
+ unsigned int chsum, rchsum;
+ xspect tmp;
+
+ for (chsum = 0, i = 4; i < 6042; i++)
+ chsum += buf[i];
+
+ chsum &= 0xffff; /* 16 bit sum */
+
+ rchsum = buf2short(buf + 2);
+
+ if (rchsum != chsum) {
+ a1logd(p->log, 3, "i1d3_decode_extEE: checksum failed\n");
+ return i1d3_interp_code((inst *)p, I1D3_BAD_EX_CHSUM);
+ }
+
+ /* Read 3 x sensor spectral sensitivits */
+ /* These seem to be in Hz per W/nm @ 1nm spacing, */
+ /* so convert to Hz per mW/nm which is our default assumption. */
+ p->cal_date = buf2ord64(buf + 0x001E);
+
+ for (j = 0; j < 3; j++) {
+ p->sens[j].spec_n = 351;
+ p->sens[j].spec_wl_short = 380.0;
+ p->sens[j].spec_wl_long = 730.0;
+ p->sens[j].norm = 1.0;
+ for (i = 0, off = 0x0026 + j * 351 * 4; i < 351; i++, off += 4) {
+ unsigned int val;
+ val = buf2uint(buf + off);
+ p->sens[j].spec[i] = IEEE754todouble(val);
+ p->sens[j].spec[i] /= 1000;
+ }
+ p->ambi[j] = p->sens[j]; /* Structure copy */
+ }
+
+#ifdef SAVE_SPECTRA
+ write_cmf("sensors.cmf", p->sens);
+#endif
+
+ /* Read ambient filter spectrum */
+ tmp.spec_n = 351;
+ tmp.spec_wl_short = 380.0;
+ tmp.spec_wl_long = 730.0;
+ tmp.norm = 1.0;
+ for (i = 0, off = 0x10bc; i < 351; i++, off += 4) {
+ unsigned int val;
+ val = buf2uint(buf + off);
+ tmp.spec[i] = IEEE754todouble(val);
+ }
+
+ /* Compute ambient sensor sensitivity by multiplying filter in */
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 351; i++)
+ p->ambi[j].spec[i] *= tmp.spec[i];
+ }
+#ifdef PLOT_SPECTRA
+ /* Plot the spectra */
+ {
+ double xx[351];
+ double y1[351];
+ double y2[351];
+ double y3[351];
+ double y4[351];
+ double y5[351];
+ double y6[351];
+
+ for (i = 0; i < 351; i++) {
+ xx[i] = XSPECT_XWL(&tmp, i);
+ y1[i] = p->sens[0].spec[i];
+ y2[i] = p->sens[1].spec[i];
+ y3[i] = p->sens[2].spec[i];
+ y4[i] = p->ambi[0].spec[i];
+ y5[i] = p->ambi[1].spec[i];
+ y6[i] = p->ambi[2].spec[i];
+ }
+ printf("The sensor and ambient sensor sensitivy curves\n");
+ do_plot6(xx, y1, y2, y3, y4, y5, y6, 351);
+ }
+#endif /* PLOT_SPECTRA */
+
+ // Should try and read 4 factory 3x3 matricies too,
+ // even though they are not usually set.
+
+ return inst_ok;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Calibration code */
+
+/* Maximum Ignorance by Least Squares regression (MIbLSr) Calibration. */
+/* This makes no assumption about the spectral distribution of */
+/* typical samples or their underlying dimensionality. */
+/* We use this as a default means of calibration, and as */
+/* a means of calibrating the Ambient readings. */
+/* (This matches the OEM default calibrations.) */
+/* We could weight this towards minimizing white error */
+/* by synthesizing a white patch to add to the "sample" set */
+/* (but this might make the result worse!), or we could */
+/* add or use spectral shape target (ie. analogous to */
+/* one sample per spectral wavelength, weighted by CMF's) */
+
+/* The more general calibration uses a set of spectral samples, */
+/* and a least squares matrix is computed to map the sensor RGB */
+/* to the computed XYZ values. This allows better accuracy for */
+/* a typical display that has only 3 degrees of freedom, and */
+/* allows weigting towards a distribution of actual spectral samples. */
+/* (The OEM driver supplies .edr files with this information. We use */
+/* .ccss files) */
+/* To allow less than 3 samples, extra secondary constraints could be added, */
+/* such as CMF's as pseudo-samples or a spectral shape target. */
+
+static inst_code
+i1d3_comp_calmat(
+ i1d3 *p,
+ double mat[3][3], /* Return calibration matrix from RGB to XYZ */
+ icxObserverType obType, /* XYZ Observer type */
+ xspect custObserver[3], /* Optional custom observer */ \
+ xspect *RGBcmfs, /* Array of 3 sensor CMFs, either emissive or ambient */
+ xspect *samples, /* Array of nsamp spectral samples, or RGBcmfs for MIbLSr */
+ /* (~~~ weighting array ? ~~~) */
+ int nsamp /* Number of samples */
+) {
+ int i, j, k;
+ double **sampXYZ; /* Sample XYZ values */
+ double **sampRGB; /* Sample RGB values */
+ double XYZ[3][3];
+ double RGB[3][3];
+ double iRGB[3][3];
+ xsp2cie *conv;
+
+ if (nsamp < 3)
+ return i1d3_interp_code((inst *)p, I1D3_TOO_FEW_CALIBSAMP);
+
+ sampXYZ = dmatrix(0, nsamp-1, 0, 3-1);
+ sampRGB = dmatrix(0, nsamp-1, 0, 3-1);
+
+ /* Compute XYZ of the sample array */
+ if ((conv = new_xsp2cie(icxIT_none, NULL, obType, custObserver, icSigXYZData, icxClamp)) == NULL)
+ return i1d3_interp_code((inst *)p, I1D3_INT_CIECONVFAIL);
+ for (i = 0; i < nsamp; i++) {
+ conv->convert(conv, sampXYZ[i], &samples[i]);
+ }
+ conv->del(conv);
+
+ /* Compute sensor RGB of the sample array */
+ if ((conv = new_xsp2cie(icxIT_none, NULL, icxOT_custom, RGBcmfs, icSigXYZData, icxClamp)) == NULL) {
+ free_dmatrix(sampXYZ, 0, nsamp-1, 0, 3-1);
+ free_dmatrix(sampRGB, 0, nsamp-1, 0, 3-1);
+ return i1d3_interp_code((inst *)p, I1D3_INT_CIECONVFAIL);
+ }
+ for (i = 0; i < nsamp; i++) {
+ conv->convert(conv, sampRGB[i], &samples[i]);
+ /* But we need to undo lumens scaling, because it doesn't apply to RGB sensor values */
+ for (j = 0; j < 3; j++)
+ sampRGB[i][j] /= 0.683002;
+ }
+ conv->del(conv);
+
+ /* If there are exactly 3 samples, we can directly compute the */
+ /* correction matrix, since the problem is not over-determined. */
+ if (nsamp == 3) {
+ copy_dmatrix_to3x3(XYZ, sampXYZ, 0, 2, 0, 2);
+ copy_dmatrix_to3x3(RGB, sampRGB, 0, 2, 0, 2);
+ if (icmInverse3x3(iRGB, RGB)) {
+ free_dmatrix(sampXYZ, 0, nsamp-1, 0, 3-1);
+ free_dmatrix(sampRGB, 0, nsamp-1, 0, 3-1);
+ return i1d3_interp_code((inst *)p, I1D3_TOO_FEW_CALIBSAMP);
+ }
+
+ icmMul3x3_2(mat, iRGB, XYZ);
+ icmTranspose3x3(mat, mat);
+
+ /* Otherwise we compute the least squares calibration matrix. */
+ } else {
+ /* Multiply the [3 x nsamp] XYZ matrix by the [nsamp x 3] RGB */
+ /* matrix to produce the [3 x 3] design matrix. */
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ XYZ[j][i] = 0.0;
+ for (k = 0; k < nsamp; k++)
+ XYZ[j][i] += sampXYZ[k][i] * sampRGB[k][j];
+ }
+ }
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ RGB[j][i] = 0.0;
+ for (k = 0; k < nsamp; k++)
+ RGB[j][i] += sampRGB[k][i] * sampRGB[k][j];
+ }
+ }
+ if (icmInverse3x3(iRGB, RGB)) {
+ free_dmatrix(sampXYZ, 0, nsamp-1, 0, 3-1);
+ free_dmatrix(sampRGB, 0, nsamp-1, 0, 3-1);
+ return i1d3_interp_code((inst *)p, I1D3_TOO_FEW_CALIBSAMP);
+ }
+
+ icmMul3x3_2(mat, iRGB, XYZ);
+ icmTranspose3x3(mat, mat);
+ }
+ free_dmatrix(sampXYZ, 0, nsamp-1, 0, 3-1);
+ free_dmatrix(sampRGB, 0, nsamp-1, 0, 3-1);
+
+ return inst_ok;
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+/* Establish communications with a I1D3 */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+i1d3_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ i1d3 *p = (i1d3 *) pp;
+ int stat, se;
+ inst_code ev = inst_ok;
+ icomuflags usbflags = icomuf_none;
+
+#ifdef NT
+ /* If the X-Rite software has been installed, then there may */
+ /* be a utility that has the device open. Kill that process off */
+ /* so that we can open it here. */
+ char *pnames[] = {
+ "i1ProfilerTray.exe",
+ NULL
+ };
+ int retries = 2;
+#else /* !NT */
+ char **pnames = NULL;
+ int retries = 0;
+#endif /* !NT */
+
+ a1logd(p->log, 2, "i1d3_init_coms: called\n");
+
+ /* On Linux, the i1d3 doesn't seem to close properly, and won't re-open - */
+ /* something to do with detaching the default HID driver ?? */
+#if defined(UNIX_X11)
+ usbflags |= icomuf_reset_before_close;
+#endif
+ /* Open as an HID if available */
+ if (p->icom->port_type(p->icom) == icomt_hid) {
+
+ a1logd(p->log, 2, "i1d3_init_coms: About to init HID\n");
+
+ /* Set config, interface */
+ if ((se = p->icom->set_hid_port(p->icom, icomuf_none, retries, pnames))
+ != ICOM_OK) {
+ a1logd(p->log, 1, "i1d3_init_coms: set_hid_port failed ICOM err 0x%x\n",se);
+ return i1d3_interp_code((inst *)p, icoms2i1d3_err(se, 0));
+ }
+
+ } else if (p->icom->port_type(p->icom) == icomt_usb) {
+
+ a1logd(p->log, 2, "i1d3_init_coms: About to init USB\n");
+
+ /* Set config, interface, write end point, read end point */
+ /* ("serial" end points aren't used - the i1d3 uses USB control messages) */
+ /* We need to detatch the HID driver on Linux */
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags | icomuf_detach, 0, NULL))
+ != ICOM_OK) {
+ a1logd(p->log, 1, "i1d3_init_coms: set_usb_port failed ICOM err 0x%x\n",se);
+ return i1d3_interp_code((inst *)p, icoms2i1d3_err(se, 0));
+ }
+
+ } else {
+ a1logd(p->log, 1, "i1d3_init_coms: wrong sort of coms!\n");
+ return i1d3_interp_code((inst *)p, I1D3_UNKNOWN_MODEL);
+ }
+
+#if defined(__APPLE__)
+ /* We seem to have to clear any pending messages for OS X HID */
+ i1d3_dummy_read(p);
+#endif
+
+ /* Check instrument is responding */
+ if ((ev = i1d3_check_status(p,&stat)) != inst_ok) {
+ a1logd(p->log, 1, "i1d3_init_coms: failed with rv = 0x%x\n",ev);
+ return ev;
+ }
+ a1logd(p->log, 2, "i1d3_init_coms: suceeded\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+// Print bytes as hex to debug log */
+static void dump_bytes(a1log *log, char *pfx, unsigned char *buf, int len) {
+ int i, j, ii;
+ char oline[200] = { '\000' }, *bp = oline;
+ for (i = j = 0; i < len; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp,"%s%04x:",pfx,i);
+ bp += sprintf(bp," %02x",buf[i]);
+ if ((i+1) >= len || ((i+1) % 16) == 0) {
+ for (ii = i; ((ii+1) % 16) != 0; ii++)
+ bp += sprintf(bp," ");
+ bp += sprintf(bp," ");
+ for (; j <= i; j++) {
+ if (!(buf[j] & 0x80) && isprint(buf[j]))
+ bp += sprintf(bp,"%c",buf[j]);
+ else
+ bp += sprintf(bp,".");
+ }
+ bp += sprintf(bp,"\n");
+ a1logd(log,0,oline);
+ bp = oline;
+ }
+ }
+}
+
+/* Diffuser position thread. */
+/* Poll the instrument at 100msec intervals */
+int i1d3_diff_thread(void *pp) {
+ int nfailed = 0;
+ i1d3 *p = (i1d3 *)pp;
+ inst_code rv = inst_ok;
+ a1logd(p->log,3,"Diffuser thread started\n");
+ for (nfailed = 0; nfailed < 5;) {
+ int pos;
+
+ rv = i1d3_get_diffpos(p, &pos, 1);
+ if (p->th_term) {
+ p->th_termed = 1;
+ break;
+ }
+ if (rv != inst_ok) {
+ nfailed++;
+ a1logd(p->log,3,"Diffuser thread failed with 0x%x\n",rv);
+ continue;
+ }
+ if (pos != p->dpos) {
+ p->dpos = pos;
+ if (p->eventcallback != NULL) {
+ p->eventcallback(p->event_cntx, inst_event_mconf);
+ }
+ }
+ msec_sleep(100);
+ }
+ a1logd(p->log,3,"Diffuser thread returning\n");
+ return rv;
+}
+
+static inst_code set_default_disp_type(i1d3 *p);
+
+/* Initialise the I1D3 */
+static inst_code
+i1d3_init_inst(inst *pp) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_code ev = inst_ok;
+ int i, stat;
+ unsigned char buf[8192];
+
+ a1logd(p->log, 2, "i1d3_init_inst: called\n");
+
+ p->rrset = 0;
+
+ if (p->gotcoms == 0)
+ return i1d3_interp_code((inst *)p, I1D3_NO_COMS); /* Must establish coms first */
+
+ // Get instrument information */
+ if ((ev = i1d3_check_status(p, &p->status)) != inst_ok)
+ return ev;
+ if (p->status != 0) {
+ a1logd(p->log, 1, "i1d3_init_inst: bad device status\n");
+ return i1d3_interp_code((inst *)p, I1D3_BAD_STATUS);
+ }
+
+ if ((ev = i1d3_get_prodname(p, p->prod_name)) != inst_ok)
+ return ev;
+ if ((ev = i1d3_get_prodtype(p, &p->prod_type)) != inst_ok)
+ return ev;
+ if (p->prod_type == 0x0002) { /* If ColorMunki Display */
+ /* Set this in case it doesn't need unlocking */
+ p->dtype = p->stype = i1d3_munkdisp;
+ }
+ if ((ev = i1d3_get_firmver(p, p->firm_ver)) != inst_ok)
+ return ev;
+ if ((ev = i1d3_get_firmdate(p, p->firm_date)) != inst_ok)
+ return ev;
+
+ /* Unlock instrument */
+ 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)
+ return ev;
+ if (stat != 0) {
+ a1logd(p->log, 1, "i1d3_init_inst: failed to unlock instrument\n");
+ return i1d3_interp_code((inst *)p, I1D3_UNLOCK_FAIL);
+ }
+ }
+
+ /* Read the instrument information and calibration */
+ if ((ev = i1d3_read_internal_eeprom(p,0,256,buf)) != inst_ok)
+ return ev;
+ if (p->log->debug >= 8) {
+ a1logd(p->log, 8, "Internal EEPROM:\n");
+ dump_bytes(p->log, " ", buf, 256);
+ }
+ /* Decode the Internal EEPRom */
+ if ((ev = i1d3_decode_intEE(p, buf)) != inst_ok)
+ return ev;
+
+ if ((ev = i1d3_read_external_eeprom(p,0,8192,buf)) != inst_ok)
+ return ev;
+ if (p->log->debug >= 8) {
+ a1logd(p->log, 8, "External EEPROM:\n");
+ dump_bytes(p->log, " ", buf, 8192);
+ }
+ /* Decode the External EEPRom */
+ if ((ev = i1d3_decode_extEE(p, buf)) != inst_ok)
+ return ev;
+
+ /* Set known constants */
+ p->clk_freq = 12e6; /* 12 Mhz */
+ p->dinttime = 0.2; /* 0.2 second integration time default */
+ p->inttime = p->dinttime; /* Start in non-refresh mode */
+
+ /* Create the default calibrations */
+
+ p->obType = icxOT_CIE_1931_2; /* Set the default ccss observer */
+
+ /* Setup the default display type */
+ if ((ev = set_default_disp_type(p)) != inst_ok) {
+ return ev;
+ }
+
+ p->inited = 1;
+ a1logd(p->log, 2, "i1d3_init_inst: inited OK\n");
+
+ a1logv(p->log,1,"Product Name: %s\n"
+ "Serial Number: %s\n"
+ "Firmware Version: %s\n"
+ "Firmware Date: %s\n"
+ ,p->prod_name,p->serial_no,p->firm_ver,p->firm_date);
+
+ if (p->log->debug >= 4) {
+ a1logd(p->log,4,"Default calibration:\n");
+ a1logd(p->log,4,"Ambient matrix = %f %f %f\n",
+ p->ambi_cal[0][0], p->ambi_cal[0][1], p->ambi_cal[0][2]);
+ a1logd(p->log,4," %f %f %f\n",
+ p->ambi_cal[1][0], p->ambi_cal[1][1], p->ambi_cal[1][2]);
+ a1logd(p->log,4," %f %f %f\n\n",
+ p->ambi_cal[2][0], p->ambi_cal[2][1], p->ambi_cal[2][2]);
+ a1logd(p->log,4,"Emissive matrix = %f %f %f\n",
+ p->emis_cal[0][0], p->emis_cal[0][1], p->emis_cal[0][2]);
+ a1logd(p->log,4," %f %f %f\n",
+ p->emis_cal[1][0], p->emis_cal[1][1], p->emis_cal[1][2]);
+ a1logd(p->log,4," %f %f %f\n",
+ p->emis_cal[2][0], p->emis_cal[2][1], p->emis_cal[2][2]);
+ a1logd(p->log,4,"\n");
+ }
+
+ /* Start the diffuser monitoring thread */
+ if ((p->th = new_athread(i1d3_diff_thread, (void *)p)) == NULL)
+ return I1D3_INT_THREADFAILED;
+
+ /* Flash the LED, just cos we can! */
+ if ((ev = i1d3_set_LEDs(p, i1d3_flash, 0.2, 0.05, 2)) != inst_ok)
+ return ev;
+
+ return ev;
+}
+
+/* Read a single sample */
+/* Return the dtp error code */
+static inst_code
+i1d3_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ i1d3 *p = (i1d3 *)pp;
+ int user_trig = 0;
+ int rv = inst_protocol_error;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "i1d3: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rv == inst_user_abort)
+ return rv; /* Abort */
+ if (rv == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return rv; /* Abort */
+ }
+
+ /* Attempt a refresh display frame rate calibration if needed */
+ if (p->dtype != i1d3_munkdisp && p->refrmode != 0 && p->rrset == 0) {
+ inst_code ev = inst_ok;
+
+ if ((ev = i1d3_measure_set_refresh(p)) != inst_ok)
+ return ev;
+
+ /* Quantize the sample time */
+ if (p->refperiod > 0.0) { /* If we have a refresh period */
+ int n;
+ n = (int)ceil(p->dinttime/p->refperiod);
+ p->inttime = 2.0 * n * p->refperiod;
+ a1logd(p->log, 3, "i1d3: integration time quantize to %f secs\n",p->inttime);
+
+ } else { /* We don't have a period, so simply double the default */
+ p->inttime = 2.0 * p->dinttime;
+ a1logd(p->log, 3, "i1d3: integration time integration time doubled to %f secs\n",p->inttime);
+ }
+ }
+
+ /* Read the XYZ value */
+ if ((rv = i1d3_take_XYZ_measurement(p, val->XYZ)) != inst_ok)
+ return rv;
+
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+
+ val->loc[0] = '\000';
+ if (IMODETST(p->mode, inst_mode_emis_ambient))
+ val->mtype = inst_mrt_ambient;
+ else
+ val->mtype = inst_mrt_emission;
+ val->XYZ_v = 1;
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (user_trig)
+ return inst_user_trig;
+
+ return rv;
+}
+
+/* Read an emissive refresh rate */
+static inst_code
+i1d3_read_refrate(
+inst *pp,
+double *ref_rate) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->dtype == i1d3_munkdisp)
+ return inst_unsupported;
+
+ if ((rv = i1d3_imp_measure_refresh(p, ref_rate, NULL)) != inst_ok)
+ return rv;
+
+ if (*ref_rate == 0.0)
+ return inst_misread;
+
+ return inst_ok;
+}
+
+/* Insert a colorimetric correction matrix in the instrument XYZ readings */
+/* This is only valid for colorimetric instruments. */
+/* To remove the matrix, pass NULL for the matrix. */
+inst_code i1d3_col_cor_mat(
+inst *pp,
+double mtx[3][3]
+) {
+ i1d3 *p = (i1d3 *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (mtx == NULL)
+ icmSetUnity3x3(p->ccmat);
+ else {
+ if (p->cbid == 0) {
+ a1loge(p->log, 1, "i1d3: can't set col_cor_mat over non base display type\n");
+ inst_wrong_setup;
+ }
+ icmCpy3x3(p->ccmat, mtx);
+ }
+
+ return inst_ok;
+}
+
+/* Use a Colorimeter Calibration Spectral Set to set the */
+/* instrumen calibration. */
+/* This is only valid for colorimetric instruments. */
+/* To set calibration back to default, pass NULL for sets. */
+inst_code i1d3_col_cal_spec_set(
+inst *pp,
+xspect *sets,
+int no_sets
+) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_code ev = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (sets == NULL || no_sets <= 0) {
+ if ((ev = set_default_disp_type(p)) != inst_ok) {
+ return ev;
+ }
+ } else {
+ /* Use given spectral samples */
+ if ((ev = i1d3_comp_calmat(p, p->emis_cal, p->obType, p->custObserver, p->sens,
+ sets, no_sets)) != inst_ok)
+ return ev;
+ /* Use MIbLSr */
+ if ((ev = i1d3_comp_calmat(p, p->ambi_cal, p->obType, p->custObserver, p->ambi,
+ p->ambi, 3)) != inst_ok)
+ return ev;
+ }
+ if (p->log->debug >= 4) {
+ a1logd(p->log,4,"CCSS update calibration:\n");
+ a1logd(p->log,4,"Ambient matrix = %f %f %f\n",
+ p->ambi_cal[0][0], p->ambi_cal[0][1], p->ambi_cal[0][2]);
+ a1logd(p->log,4," %f %f %f\n",
+ p->ambi_cal[1][0], p->ambi_cal[1][1], p->ambi_cal[1][2]);
+ a1logd(p->log,4," %f %f %f\n\n",
+ p->ambi_cal[2][0], p->ambi_cal[2][1], p->ambi_cal[2][2]);
+ a1logd(p->log,4,"Emissive matrix = %f %f %f\n",
+ p->emis_cal[0][0], p->emis_cal[0][1], p->emis_cal[0][2]);
+ a1logd(p->log,4," %f %f %f\n",
+ p->emis_cal[1][0], p->emis_cal[1][1], p->emis_cal[1][2]);
+ a1logd(p->log,4," %f %f %f\n",
+ p->emis_cal[2][0], p->emis_cal[2][1], p->emis_cal[2][2]);
+ a1logd(p->log,4,"\n");
+ }
+ return ev;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code i1d3_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if (p->dtype != i1d3_munkdisp && p->refrmode != 0) {
+ if (p->rrset == 0)
+ n_cals |= inst_calt_ref_freq;
+ a_cals |= inst_calt_ref_freq;
+ }
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+inst_code i1d3_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_code ev;
+ inst_cal_type needed, available;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ id[0] = '\000';
+
+ if ((ev = i1d3_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"i1d3_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return inst_unsupported;
+ }
+
+ if ((*calt & inst_calt_ref_freq) && p->dtype != i1d3_munkdisp && p->refrmode != 0) {
+ inst_code ev = inst_ok;
+
+ if (*calc != inst_calc_emis_white) {
+ *calc = inst_calc_emis_white;
+ return inst_cal_setup;
+ }
+
+ /* Do refresh display rate calibration */
+ if ((ev = i1d3_measure_set_refresh(p)) != inst_ok)
+ return ev;
+
+ /* Quantize the sample time */
+ if (p->refperiod > 0.0) {
+ int n;
+ n = (int)ceil(p->dinttime/p->refperiod);
+ p->inttime = 2.0 * n * p->refperiod;
+ a1logd(p->log, 3, "i1d3: integration time quantize to %f secs\n",p->inttime);
+ } else {
+ p->inttime = 2.0 * p->dinttime; /* Double default integration time */
+ a1logd(p->log, 3, "i1d3: integration time integration time doubled to %f secs\n",p->inttime);
+ }
+ *calt &= ~inst_calt_ref_freq;
+ }
+ return inst_ok;
+}
+
+/* Measure a display update delay. It is assumed that a */
+/* white to black change has been made to the displayed color, */
+/* and this will measure the time it took for the update to */
+/* be noticed by the instrument, up to 0.5 seconds. */
+/* inst_misread will be returned on failure to find a transition to black. */
+#define NDSAMPS 60
+#define DINTT 0.010
+#define NDMXTIME 0.6 /* Maximum time to take */
+
+inst_code i1d3_meas_delay(
+inst *pp,
+int *msecdelay) { /* Return the number of msec */
+ i1d3 *p = (i1d3 *)pp;
+ inst_code ev;
+ int i, j, k;
+ double sutime, putime, cutime, eutime;
+ struct {
+ double sec;
+ double rgb[3];
+ } samp[NDSAMPS];
+ int ndsamps;
+ double inttime = DINTT;
+ double rgb[3];
+ double etime;
+ int isdeb;
+
+ if (usec_time() < 0.0) {
+ a1loge(p->log, inst_internal_error, "i1d3_meas_delay: No high resolution timers\n");
+ return inst_internal_error;
+ }
+
+ /* Turn debug off so that it doesn't intefere with measurement timing */
+ isdeb = p->log->debug;
+ p->icom->log->debug = 0;
+
+ /* Read the samples */
+ sutime = usec_time();
+ putime = (usec_time() - sutime) / 1000000.0;
+ for (i = 0; i < NDSAMPS; i++) {
+ if ((ev = i1d3_freq_measure(p, &inttime, samp[i].rgb)) != inst_ok) {
+ a1logd(p->log, 1, "i1d3_meas_delay: measurement failed\n");
+ p->log->debug = isdeb;
+ return ev;
+ }
+ cutime = (usec_time() - sutime) / 1000000.0;
+ samp[i].sec = 0.5 * (putime + cutime); /* Mean of before and after stamp */
+ putime = cutime;
+ if (cutime > NDMXTIME)
+ break;
+ }
+ ndsamps = i;
+
+ /* Restore debugging */
+ p->log->debug = isdeb;
+
+ if (ndsamps == 0) {
+ a1logd(p->log, 1, "i1d3_meas_delay: No measurement samples returned in time\n");
+ return inst_internal_error;
+ }
+
+#ifdef NEVER
+ /* Plot the raw sensor values */
+ {
+ double xx[NDSAMPS];
+ double y1[NDSAMPS];
+ double y2[NDSAMPS];
+ double y3[NDSAMPS];
+
+ for (i = 0; i < ndsamps; i++) {
+ xx[i] = samp[i].sec;
+ y1[i] = samp[i].rgb[0];
+ y2[i] = samp[i].rgb[1];
+ y3[i] = samp[i].rgb[2];
+ //printf("%d: %f -> %f\n",i,samp[i].sec, samp[i].rgb[0]);
+ }
+ printf("Display update delay measure sensor values and time (sec)\n");
+ do_plot6(xx, y1, y2, y3, NULL, NULL, NULL, ndsamps);
+ }
+#endif
+
+ /* Over the last 100msec, locate the maximum value */
+ etime = samp[ndsamps-1].sec;
+ for (j = 0; j < 3; j++)
+ rgb[j] = 0.0;
+ for (i = ndsamps-1; i >= 0; i--) {
+ for (j = 0; j < 3; j++) {
+ if (samp[i].rgb[j] > rgb[j])
+ rgb[j] = samp[i].rgb[j];
+ }
+ if ((etime - samp[i].sec) > 0.1)
+ break;
+ }
+
+// a1logd(p->log, 3, "i1d3_meas_delay: end rgb = %f %f %f stopped at %d\n", rgb[0], rgb[1], rgb[2], i);
+
+ if (rgb[0] > 10.0 || rgb[1] > 10.0 || rgb[2] > 10.0) {
+ a1logd(p->log, 1, "i1d3_meas_delay: measurement delay doesn't seem to be black\n");
+ return inst_misread;
+ }
+
+ /* Locate the time at which the values are above this */
+ for (i = ndsamps-1; i >= 0; i--) {
+ for (j = 0; j < 3; j++) {
+ if (samp[i].rgb[j] > (1.5 * rgb[j]))
+ break;
+ }
+ if (j < 3)
+ break;
+ }
+ if (i < 0) /* Assume the update was so fast that we missed it */
+ i = 0;
+
+ a1logd(p->log, 2, "i1d3_meas_delay: stoped at sample %d time %f\n",i,samp[i].sec);
+
+ *msecdelay = (int)(samp[i].sec * 1000.0 + 0.5);
+
+ return inst_ok;
+}
+#undef NDSAMPS
+#undef DINTT
+#undef NDMXTIME
+
+/* Return the last calibrated refresh rate in Hz. Returns: */
+static inst_code i1d3_get_refr_rate(inst *pp,
+double *ref_rate
+) {
+ i1d3 *p = (i1d3 *)pp;
+ if (p->refrvalid) {
+ *ref_rate = p->refrate;
+ return inst_ok;
+ } else if (p->rrset) {
+ *ref_rate = 0.0;
+ return inst_misread;
+ }
+ return inst_needs_cal;
+}
+
+/* Set the calibrated refresh rate in Hz. */
+/* Set refresh rate to 0.0 to mark it as invalid */
+/* Rates outside the range 5.0 to 150.0 Hz will return an error */
+/* Note that it's possible to set a ColorMunki Display to use */
+/* synchronised measurement this way. */
+static inst_code i1d3_set_refr_rate(inst *pp,
+double ref_rate
+) {
+ i1d3 *p = (i1d3 *)pp;
+
+ if (ref_rate != 0.0 && (ref_rate < 5.0 || ref_rate > 150.0))
+ return inst_bad_parameter;
+
+ p->refrate = ref_rate;
+ if (ref_rate == 0.0)
+ p->refrvalid = 0;
+ else {
+ int mul;
+ double pval;
+
+ /* Scale to just above 20 Hz */
+ pval = 1.0/ref_rate;
+ mul = floor((1.0/20) / pval);
+ if (mul > 1)
+ pval *= mul;
+ p->refperiod = pval;
+
+ p->refrvalid = 1;
+ }
+ p->rrset = 1;
+
+ return inst_ok;
+}
+
+/* Error codes interpretation */
+static char *
+i1d3_interp_error(inst *pp, int ec) {
+// i1d3 *p = (i1d3 *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case I1D3_INTERNAL_ERROR:
+ return "Internal software error";
+ case I1D3_COMS_FAIL:
+ return "Communications failure";
+ case I1D3_UNKNOWN_MODEL:
+ return "Not a known Huey Model";
+ case I1D3_DATA_PARSE_ERROR:
+ return "Data from i1 Display didn't parse as expected";
+
+ case I1D3_OK:
+ return "No device error";
+
+ case I1D3_UNKNOWN_UNLOCK:
+ return "Don't know unlock code for device";
+ case I1D3_UNLOCK_FAIL:
+ return "Device unlock command failed";
+ case I1D3_BAD_EX_CHSUM:
+ return "External EEPRrom checksum doesn't match";
+
+ case I1D3_SPOS_EMIS:
+ return "Ambient filter should be removed";
+ case I1D3_SPOS_AMB:
+ return "Ambient filter should be used";
+
+ case I1D3_BAD_WR_LENGTH:
+ return "Unable to write full message to instrument";
+ case I1D3_BAD_RD_LENGTH:
+ return "Unable to read full message to instrument";
+ case I1D3_BAD_RET_STAT:
+ return "Message from instrument had bad status code";
+ case I1D3_BAD_RET_CMD:
+ return "Message from instrument didn't echo command code";
+ case I1D3_BAD_STATUS:
+ return "Instrument status is unrecognised format";
+ case I1D3_INT_THREADFAILED:
+ return "Starting diffuser position thread failed";
+
+ case I1D3_NO_COMS:
+ return "Communications hasn't been established";;
+ case I1D3_NOT_INITED:
+ return "Instrument hasn't been initialized";
+ case I1D3_BAD_MEM_ADDRESS:
+ return "Out of range EEPROM address";
+ case I1D3_BAD_MEM_LENGTH:
+ return "Out of range EEPROM length";
+ case I1D3_INT_CIECONVFAIL:
+ return "Creating spectral to CIE converted failed";
+ case I1D3_TOO_FEW_CALIBSAMP:
+ return "There are too few spectral calibration samples - need at least 3";
+ case I1D3_INT_MATINV_FAIL:
+ return "Calibration matrix inversion failed";
+ case I1D3_BAD_LED_MODE:
+ return "Parameters to set LED are incorrect";
+
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+i1d3_interp_code(inst *pp, int ec) {
+// i1d3 *p = (i1d3 *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case I1D3_OK:
+ return inst_ok;
+
+ case I1D3_BAD_MEM_ADDRESS:
+ case I1D3_BAD_MEM_LENGTH:
+ case I1D3_INT_CIECONVFAIL:
+ case I1D3_TOO_FEW_CALIBSAMP:
+ case I1D3_INT_MATINV_FAIL:
+ case I1D3_BAD_LED_MODE:
+ case I1D3_NO_COMS:
+ case I1D3_NOT_INITED:
+ case I1D3_INT_THREADFAILED:
+ return inst_internal_error | ec;
+
+ case I1D3_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case I1D3_UNKNOWN_UNLOCK:
+ case I1D3_UNLOCK_FAIL:
+ case I1D3_DATA_PARSE_ERROR:
+ case I1D3_BAD_WR_LENGTH:
+ case I1D3_BAD_RD_LENGTH:
+ case I1D3_BAD_RET_STAT:
+ case I1D3_BAD_RET_CMD:
+ case I1D3_BAD_STATUS:
+ return inst_protocol_error | ec;
+
+ case I1D3_SPOS_EMIS:
+ case I1D3_SPOS_AMB:
+ return inst_wrong_config | ec;
+
+ case I1D3_BAD_EX_CHSUM:
+ return inst_hardware_fail | ec;
+
+/* Unused:
+ inst_notify
+ inst_warning
+ inst_unknown_model
+ inst_misread
+ inst_nonesaved
+ inst_nochmatch
+ inst_needs_cal
+ inst_cal_setup
+ inst_unsupported
+ inst_unexpected_reply
+ inst_wrong_setup
+ inst_bad_parameter
+ */
+ }
+ return inst_other_error | ec;
+}
+
+/* Convert instrument specific inst_wrong_config error to inst_config enum */
+static inst_config i1d3_config_enum(inst *pp, int ec) {
+// i1d3 *p = (i1d3 *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case I1D3_SPOS_EMIS:
+ return inst_conf_emission;
+
+ case I1D3_SPOS_AMB:
+ return inst_conf_ambient;
+ }
+ return inst_conf_unknown;
+}
+
+/* Destroy ourselves */
+static void
+i1d3_del(inst *pp) {
+ if (pp != NULL) {
+ i1d3 *p = (i1d3 *)pp;
+
+ if (p->th != NULL) { /* Terminate diffuser monitor thread */
+ int i;
+ p->th_term = 1; /* Tell thread to exit on error */
+ for (i = 0; p->th_termed == 0 && i < 5; i++)
+ msec_sleep(50); /* Wait for thread to terminate */
+ if (i >= 5) {
+ a1logd(p->log,3,"i1d3 diffuser thread termination failed\n");
+ }
+ p->th->del(p->th);
+ }
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ inst_del_disptype_list(p->dtlist, p->ndtlist);
+ amutex_del(p->lock);
+ free(p);
+ }
+}
+
+/* Return the instrument capabilities */
+void i1d3_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_mode cap1 = 0;
+ inst2_capability cap2 = 0;
+
+ cap1 |= inst_mode_emis_spot
+ | inst_mode_emis_tele
+ | inst_mode_emis_ambient
+ | inst_mode_emis_refresh_ovd
+ | inst_mode_emis_norefresh_ovd
+ | inst_mode_colorimeter
+ ;
+
+ cap2 |= inst2_has_sensmode
+ | inst2_prog_trig
+ | inst2_user_trig
+ | inst2_has_leds
+ | inst2_disptype
+ | inst2_ccmx
+ | inst2_ccss
+ ;
+
+ if (p->dtype != i1d3_munkdisp) {
+ cap2 |= inst2_meas_disp_update;
+ cap2 |= inst2_refresh_rate;
+ cap2 |= inst2_emis_refr_meas;
+ }
+ if (pcap1 != NULL)
+ *pcap1 = cap1;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Return current or given configuration available measurement modes. */
+static inst_code i1d3_meas_config(
+inst *pp,
+inst_mode *mmodes,
+inst_cal_cond *cconds,
+int *conf_ix
+) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_code ev;
+ inst_mode mval;
+ int pos;
+
+ if (mmodes != NULL)
+ *mmodes = inst_mode_none;
+ if (cconds != NULL)
+ *cconds = inst_calc_unknown;
+
+ if (conf_ix == NULL
+ || *conf_ix < 0
+ || *conf_ix > 1) {
+ /* Return current configuration measrement modes */
+ if ((ev = i1d3_get_diffpos(p, &pos, 0)) != inst_ok)
+ return ev;
+ } else {
+ /* Return given configuration measurement modes */
+ pos = *conf_ix;
+ }
+
+ if (pos == 1) {
+ mval = inst_mode_emis_ambient;
+ } else {
+ mval = inst_mode_emis_spot
+ | inst_mode_emis_tele;
+ }
+
+ /* Add the extra dependent and independent modes */
+ mval |= inst_mode_emis_refresh_ovd
+ | inst_mode_emis_norefresh_ovd
+ | inst_mode_colorimeter;
+
+ if (mmodes != NULL)
+ *mmodes = mval;
+
+ /* Return configuration index returned */
+ if (conf_ix != NULL)
+ *conf_ix = pos;
+
+ return inst_ok;
+}
+
+/* Check device measurement mode */
+inst_code i1d3_check_mode(inst *pp, inst_mode m) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_mode cap;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* only display emission mode and ambient supported */
+ if (!IMODETST(m, inst_mode_emis_spot)
+ && !IMODETST(m, inst_mode_emis_tele)
+ && !IMODETST(m, inst_mode_emis_ambient)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code i1d3_set_mode(inst *pp, inst_mode m) {
+ i1d3 *p = (i1d3 *)pp;
+ int refrmode;
+ inst_code ev;
+
+ if ((ev = i1d3_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->mode = m;
+
+ /* Effective refresh mode may change */
+ refrmode = p->refrmode;
+ if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */
+ refrmode = 0;
+ } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) {
+ refrmode = 1;
+ }
+
+ if (p->refrmode != refrmode) {
+ p->rrset = 0; /* This is a hint we may have swapped displays */
+ p->refrvalid = 0;
+ }
+ p->refrmode = refrmode;
+
+ if (p->refrmode) {
+ p->inttime = 2.0 * p->dinttime; /* Double default integration time */
+ } else {
+ p->inttime = p->dinttime; /* Normal integration time */
+ }
+
+ return inst_ok;
+}
+
+inst_disptypesel i1d3_disptypesel[3] = {
+ {
+ inst_dtflags_default,
+ 1,
+ "n",
+ "Non-Refresh display",
+ 0,
+ 0
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 2, /* cbid */
+ "r", /* sel */
+ "Refresh display", /* desc */
+ 1, /* refr */
+ 1 /* ix */
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+/* Get mode and option details */
+static inst_code i1d3_get_disptypesel(
+inst *pp,
+int *pnsels, /* Return number of display types */
+inst_disptypesel **psels, /* Return the array of display types */
+int allconfig, /* nz to return list for all configs, not just current. */
+int recreate /* nz to re-check for new ccmx & ccss files */
+) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_code rv = inst_ok;
+
+ if (!allconfig && p->dpos) { /* If set to Ambient */
+
+ if (pnsels != NULL)
+ *pnsels = 0;
+
+ if (psels != NULL)
+ *psels = NULL;
+
+ return inst_ok;
+ }
+
+ /* Create/Re-create a current list of abailable display types */
+ if (p->dtlist == NULL || recreate) {
+ if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ i1d3_disptypesel, 1 /* doccss*/, 1 /* doccmx */)) != inst_ok) {
+ return rv;
+ }
+ }
+
+ if (pnsels != NULL)
+ *pnsels = p->ndtlist;
+
+ if (psels != NULL)
+ *psels = p->dtlist;
+
+ return inst_ok;
+}
+
+/* Given a display type entry, setup for that type */
+static inst_code set_disp_type(i1d3 *p, inst_disptypesel *dentry) {
+ inst_code ev;
+ int refrmode;
+
+ p->icx = dentry->ix;
+ p->cbid = dentry->cbid;
+ refrmode = dentry->refr;
+
+ if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */
+ refrmode = 0;
+ } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) {
+ refrmode = 1;
+ }
+
+ if (p->refrmode != refrmode)
+ p->rrset = 0; /* This is a hint we may have swapped displays */
+ p->refrmode = refrmode;
+
+// if (p->refrmode && p->dtype == i1d3_munkdisp) {
+ if (p->refrmode) {
+ p->inttime = 2.0 * p->dinttime; /* Double integration time */
+ } else {
+ p->inttime = p->dinttime; /* Normal integration time */
+ }
+
+ if (dentry->flags & inst_dtflags_ccss) {
+
+ if ((ev = i1d3_comp_calmat(p, p->emis_cal, p->obType, p->custObserver,
+ p->sens, dentry->sets, dentry->no_sets)) != inst_ok) {
+ a1logd(p->log, 1, "i1d3_set_disp_type: comp_calmat ccss failed with rv = 0x%x\n",ev);
+ return ev;
+ }
+ /* Use MIbLSr for ambient */
+ if ((ev = i1d3_comp_calmat(p, p->ambi_cal, p->obType, p->custObserver, p->ambi,
+ p->ambi, 3)) != inst_ok)
+ return ev;
+
+ icmSetUnity3x3(p->ccmat);
+
+ if (p->log->debug >= 4) {
+ a1logd(p->log,4,"Display type set CCSS:\n");
+ a1logd(p->log,4,"Emissive matrix = %f %f %f\n",
+ p->emis_cal[0][0], p->emis_cal[0][1], p->emis_cal[0][2]);
+ a1logd(p->log,4," %f %f %f\n",
+ p->emis_cal[1][0], p->emis_cal[1][1], p->emis_cal[1][2]);
+ a1logd(p->log,4," %f %f %f\n",
+ p->emis_cal[2][0], p->emis_cal[2][1], p->emis_cal[2][2]);
+ a1logd(p->log,4,"\n");
+ }
+
+ } else { /* Assume matrix */
+
+ /* Create the default calibration matrix */
+ if ((ev = i1d3_comp_calmat(p, p->emis_cal, p->obType, p->custObserver,
+ p->sens, p->sens, 3)) != inst_ok) {
+ a1logd(p->log, 1, "i1d3_set_disp_type: comp_calmat dflt failed with rv = 0x%x\n",ev);
+ return ev;
+ }
+ /* Use MIbLSr for ambient */
+ if ((ev = i1d3_comp_calmat(p, p->ambi_cal, p->obType, p->custObserver, p->ambi,
+ p->ambi, 3)) != inst_ok)
+ return ev;
+
+ if (dentry->flags & inst_dtflags_ccmx) {
+ icmCpy3x3(p->ccmat, dentry->mat);
+ } else {
+ icmSetUnity3x3(p->ccmat);
+ }
+ }
+
+ return inst_ok;
+}
+
+/* Setup the default display type */
+static inst_code set_default_disp_type(i1d3 *p) {
+ inst_code ev;
+ int i;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist,
+ i1d3_disptypesel, 1 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) {
+ if (p->dtlist[i].flags & inst_dtflags_default)
+ break;
+ }
+ if (p->dtlist[i].flags & inst_dtflags_end) {
+ a1loge(p->log, 1, "set_default_disp_type: failed to find type!\n");
+ return inst_internal_error;
+ }
+ if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/* Set the display type */
+static inst_code i1d3_set_disptype(inst *pp, int ix) {
+ i1d3 *p = (i1d3 *)pp;
+ inst_code ev;
+ inst_disptypesel *dentry;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ i1d3_disptypesel, 1 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ if (ix < 0 || ix >= p->ndtlist)
+ return inst_unsupported;
+
+ dentry = &p->dtlist[ix];
+
+ if ((ev = set_disp_type(p, dentry)) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+
+/*
+ * set or reset an optional mode
+ *
+ * Some options talk to the instrument, and these will
+ * error if it hasn't been initialised.
+ */
+static inst_code
+i1d3_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ i1d3 *p = (i1d3 *)pp;
+ inst_code ev;
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user) {
+ p->trig = m;
+ return inst_ok;
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Get the display type information */
+ if (m == inst_opt_get_dtinfo) {
+ va_list args;
+ int *refrmode, *cbid;
+
+ va_start(args, m);
+ refrmode = va_arg(args, int *);
+ cbid = va_arg(args, int *);
+ va_end(args);
+
+ if (refrmode != NULL)
+ *refrmode = p->refrmode;
+ if (cbid != NULL)
+ *cbid = p->cbid;
+
+ return inst_ok;
+ }
+
+ /* Set the ccss observer type */
+ if (m == inst_opt_set_ccss_obs) {
+ va_list args;
+ icxObserverType obType;
+ xspect *custObserver;
+
+ va_start(args, m);
+ obType = va_arg(args, icxObserverType);
+ custObserver = va_arg(args, xspect *);
+ va_end(args);
+
+ if (obType == icxOT_default)
+ obType = icxOT_CIE_1931_2;
+ p->obType = obType;
+ if (obType == icxOT_custom) {
+ p->custObserver[0] = custObserver[0];
+ p->custObserver[1] = custObserver[1];
+ p->custObserver[2] = custObserver[2];
+ }
+
+ return inst_ok;
+ }
+
+ /* Operate the LEDS */
+ if (m == inst_opt_get_gen_ledmask) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = 0x1; /* One general LEDs */
+ return inst_ok;
+ } else if (m == inst_opt_get_led_state) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = p->led_state;
+ return inst_ok;
+ } else if (m == inst_opt_set_led_state) {
+ va_list args;
+ int mask = 0;
+
+ va_start(args, m);
+ mask = va_arg(args, int);
+ va_end(args);
+
+ if (p->led_state & 0x1)
+ return i1d3_set_LEDs(p, i1d3_flash, 0.0, 100.0, 0x80);
+ else
+ return i1d3_set_LEDs(p, i1d3_flash, 100.0, 0.0, 0x80);
+ }
+
+ if (m == inst_opt_get_pulse_ledmask) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = 0x1; /* General LED is pulsable */
+ return inst_ok;
+ } else if (m == inst_opt_set_led_pulse_state) {
+ va_list args;
+ double period, on_time_prop, trans_time_prop;
+ double offtime, ontime;
+ i1d3_ledmode mode;
+ int nopulses;
+
+ va_start(args, m);
+ period = va_arg(args, double);
+ on_time_prop = va_arg(args, double);
+ trans_time_prop = va_arg(args, double);
+ va_end(args);
+ if (period < 0.0
+ || on_time_prop < 0.0 || on_time_prop > 1.0
+ || trans_time_prop < 0.0 || trans_time_prop > 1.0
+ || trans_time_prop > on_time_prop || trans_time_prop > (1.0 - on_time_prop))
+ return inst_bad_parameter;
+
+ p->led_period = period;
+ p->led_on_time_prop = on_time_prop;
+ p->led_trans_time_prop = trans_time_prop;
+
+ /* i1d3 doesn't have controllable fade time, so any = fade */
+ if (trans_time_prop > 0.0) {
+ mode = i1d3_fade;
+ offtime = period * (1.0 - on_time_prop - trans_time_prop);
+ ontime = period * (on_time_prop + trans_time_prop);
+ } else {
+ mode = i1d3_flash;
+ offtime = period * (1.0 - on_time_prop);
+ ontime = period * on_time_prop;
+ }
+ nopulses = 0x80;
+ if (period == 0.0 || on_time_prop == 0.0) {
+ mode = i1d3_flash;
+ offtime = 100.0;
+ ontime = 0.0;
+ p->led_state = 0;
+ } else {
+ p->led_state = 1;
+ }
+ return i1d3_set_LEDs(p, mode, offtime, ontime, nopulses);
+
+ } else if (m == inst_opt_get_led_state) {
+ va_list args;
+ double *period, *on_time_prop, *trans_time_prop;
+
+ va_start(args, m);
+ period = va_arg(args, double *);
+ on_time_prop = va_arg(args, double *);
+ trans_time_prop = va_arg(args, double *);
+ va_end(args);
+ if (period != NULL) *period = p->led_period;
+ if (on_time_prop != NULL) *on_time_prop = p->led_on_time_prop;
+ if (trans_time_prop != NULL) *trans_time_prop = p->led_trans_time_prop;
+ return inst_ok;
+ }
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern i1d3 *new_i1d3(icoms *icom, instType itype) {
+ i1d3 *p;
+
+ if ((p = (i1d3 *)calloc(sizeof(i1d3),1)) == NULL) {
+ a1loge(icom->log, 1, "new_i1d3: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = i1d3_init_coms;
+ p->init_inst = i1d3_init_inst;
+ p->capabilities = i1d3_capabilities;
+ p->meas_config = i1d3_meas_config;
+ p->check_mode = i1d3_check_mode;
+ p->set_mode = i1d3_set_mode;
+ p->get_disptypesel = i1d3_get_disptypesel;
+ p->set_disptype = i1d3_set_disptype;
+ p->get_set_opt = i1d3_get_set_opt;
+ p->read_sample = i1d3_read_sample;
+ p->read_refrate = i1d3_read_refrate;
+ p->col_cor_mat = i1d3_col_cor_mat;
+ p->col_cal_spec_set = i1d3_col_cal_spec_set;
+ p->get_n_a_cals = i1d3_get_n_a_cals;
+ p->calibrate = i1d3_calibrate;
+ p->meas_delay = i1d3_meas_delay;
+ p->get_refr_rate = i1d3_get_refr_rate;
+ p->set_refr_rate = i1d3_set_refr_rate;
+ p->interp_error = i1d3_interp_error;
+ p->config_enum = i1d3_config_enum;
+ p->del = i1d3_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ amutex_init(p->lock);
+ icmSetUnity3x3(p->ccmat);
+
+ 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;
+ unsigned char sc[8], sr[16]; /* Sub-challeng and response */
+
+ /* Only 8 bytes is used out of challenge buffer starting at */
+ /* offset 35. Bytes are decoded with xor of byte 3 value. */
+ for (i = 0; i < 8; i++)
+ sc[i] = c[3] ^ c[35 + i];
+
+ /* Combine key with 16 byte challenge to create core 16 byte response */
+ {
+ unsigned int ci[2]; /* challenge as 4 ints */
+ unsigned int co[4]; /* product, difference of 4 ints */
+ unsigned int sum; /* Sum of all input bytes */
+ unsigned char s0, s1; /* Byte components of sum. */
+
+ /* Shuffle bytes into 32 bit ints to be able to use 32 bit computation. */
+ ci[0] = (sc[3] << 24)
+ + (sc[0] << 16)
+ + (sc[4] << 8)
+ + (sc[6]);
+
+ ci[1] = (sc[1] << 24)
+ + (sc[7] << 16)
+ + (sc[2] << 8)
+ + (sc[5]);
+
+ /* Computation on the ints */
+ co[0] = -k[0] - ci[1];
+ co[1] = -k[1] - ci[0];
+ co[2] = ci[1] * -k[0];
+ co[3] = ci[0] * -k[1];
+
+ /* Sum of challenge bytes */
+ for (sum = 0, i = 0; i < 8; i++)
+ sum += sc[i];
+
+ /* Minus the two key values as bytes */
+ sum += (0xff & -k[0]) + (0xff & (-k[0] >> 8))
+ + (0xff & (-k[0] >> 16)) + (0xff & (-k[0] >> 24));
+ sum += (0xff & -k[1]) + (0xff & (-k[1] >> 8))
+ + (0xff & (-k[1] >> 16)) + (0xff & (-k[1] >> 24));
+
+ /* Convert sum to bytes. Only need 2, because sum of 16 bytes can't exceed 16 bits. */
+ s0 = sum & 0xff;
+ s1 = (sum >> 8) & 0xff;
+
+ /* Final computation of bytes from 4 ints + sum bytes */
+ sr[0] = ((co[0] >> 16) & 0xff) + s0;
+ sr[1] = ((co[2] >> 8) & 0xff) - s1;
+ sr[2] = ( co[3] & 0xff) + s1;
+ sr[3] = ((co[1] >> 16) & 0xff) + s0;
+ sr[4] = ((co[2] >> 16) & 0xff) - s1;
+ sr[5] = ((co[3] >> 16) & 0xff) - s0;
+ sr[6] = ((co[1] >> 24) & 0xff) - s0;
+ sr[7] = ( co[0] & 0xff) - s1;
+ sr[8] = ((co[3] >> 8) & 0xff) + s0;
+ sr[9] = ((co[2] >> 24) & 0xff) - s1;
+ sr[10] = ((co[0] >> 8) & 0xff) + s0;
+ sr[11] = ((co[1] >> 8) & 0xff) - s1;
+ sr[12] = ( co[1] & 0xff) + s1;
+ sr[13] = ((co[3] >> 24) & 0xff) + s1;
+ sr[14] = ( co[2] & 0xff) + s0;
+ sr[15] = ((co[0] >> 24) & 0xff) - s0;
+ }
+
+ /* The OEM driver sets the resonse to random bytes, */
+ /* but we don't need to do this, since the device doesn't */
+ /* look at them. */
+ for (i = 0; i < 64; i++)
+ r[i] = 0;
+
+ /* The actual resonse is 16 bytes at offset 24 in the response buffer. */
+ /* The OEM driver xor's challeng byte 2 with response bytes 4..63, but */
+ /* since the instrument doesn't look at them, we only do this to the actual */
+ /* response. */
+ for (i = 0; i < 16; i++)
+ r[24 + i] = c[2] ^ sr[i];
+}
diff --git a/spectro/i1d3.h b/spectro/i1d3.h
new file mode 100644
index 0000000..96de478
--- /dev/null
+++ b/spectro/i1d3.h
@@ -0,0 +1,161 @@
+#ifndef I1D3_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * X-Rite i1d3 related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 7/10/2007
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * (Based on huey.h)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Note: update huey_interp_error() and huey_interp_code() in huey.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define I1D3_INTERNAL_ERROR 0x61 /* Internal software error */
+#define I1D3_COMS_FAIL 0x62 /* Communication failure */
+#define I1D3_UNKNOWN_MODEL 0x63 /* Not an i1d3 */
+#define I1D3_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error code */
+#define I1D3_OK 0x00
+
+#define I1D3_UNKNOWN_UNLOCK 0x01
+#define I1D3_UNLOCK_FAIL 0x02
+#define I1D3_BAD_EX_CHSUM 0x03
+
+#define I1D3_SPOS_EMIS 0x05 /* Needs to be in emsissive configuration */
+#define I1D3_SPOS_AMB 0x06 /* Needs to be in ambient configuration */
+
+#define I1D3_TOO_FEW_CALIBSAMP 0x10
+
+#define I1D3_BAD_WR_LENGTH 0x11
+#define I1D3_BAD_RD_LENGTH 0x12
+#define I1D3_BAD_RET_STAT 0x13
+#define I1D3_BAD_RET_CMD 0x14
+#define I1D3_NOT_INITED 0x15
+
+/* Internal errors */
+#define I1D3_BAD_MEM_ADDRESS 0x20
+#define I1D3_BAD_MEM_LENGTH 0x21
+#define I1D3_INT_CIECONVFAIL 0x22
+#define I1D3_INT_MATINV_FAIL 0x23
+#define I1D3_BAD_LED_MODE 0x24
+#define I1D3_NO_COMS 0x25
+#define I1D3_BAD_STATUS 0x26
+#define I1D3_INT_THREADFAILED 0x27
+
+/* Sub-type of instrument */
+typedef enum {
+ i1d3_disppro = 0, /* i1 DisplayPro */
+ i1d3_munkdisp = 1, /* ColorMunki Display */
+ i1d3_oem = 2, /* OEM */
+ i1d3_nec_ssp = 3, /* NEC SpectraSensor Pro */
+ i1d3_quato_sh3 = 4 /* Quato Silver Haze 3 */
+} i1d3_dtype;
+
+/* Measurement mode */
+typedef enum {
+ i1d3_adaptive = 0, /* Frequency over fixed period then adaptive period measurement */
+ i1d3_frequency = 1, /* Frequency over fixed period measurement */
+ i1d3_period = 2 /* Adaptive period measurement */
+} i1d3_mmode;
+
+/* I1D3 communication object */
+struct _i1d3 {
+ INST_OBJ_BASE
+
+ amutex lock; /* Command lock */
+
+ /* Modes */
+ inst_mode mode; /* Currently selected mode */
+ inst_opt_type trig; /* Reading trigger mode */
+
+ /* Information and EEPROM values */
+ i1d3_dtype dtype; /* Base type of instrument, ie i1d3_disppro or i1d3_munkdisp */
+ i1d3_dtype stype; /* Sub type of instrument, ie. any of i1d3_dtype. */
+ /* (Only accurate if it needed unlocking). */
+ int status; /* 0 if status is ok (not sure what this is) */
+ char serial_no[21]; /* "I1-11.A-01.100999.02" or "CM-11.A-01.100999.02" */
+ char prod_name[32]; /* "i1Display3 " or "ColorMunki Display" */
+ int prod_type; /* 16 bit product type number. i1d3_disppro = 0x0001, */
+ /* i1d3_munkdisp = 0x0002 */
+ char firm_ver[32]; /* Firmwar version string. ie. "v1.0 " */
+ char firm_date[32]; /* Firmwar date string. ie. "11Jan11" */
+
+ /* Calibration information */
+ ORD64 cal_date; /* Calibration date */
+ xspect sens[3]; /* RGB Sensor spectral sensitivities in Hz per mW/nm */
+ xspect ambi[3]; /* RGB Sensor with ambient filter spectral sensitivities */
+
+ double black[3]; /* Black level to subtract */
+ double emis_cal[3][3]; /* Current emssion calibration matrix */
+ double ambi_cal[3][3]; /* Current ambient calibration matrix */
+
+ inst_disptypesel *dtlist; /* Display Type list */
+ int ndtlist; /* Number of valid dtlist entries */
+ int icx; /* Internal calibration matrix index, 11 = Raw */
+ int cbid; /* calibration base ID, 0 if not a base */
+ int refrmode; /* nz if in refresh display mode/double int. time */
+ double ccmat[3][3]; /* Optional colorimeter correction matrix */
+ icxObserverType obType; /* ccss observer to use */
+ xspect custObserver[3]; /* Custom ccss observer to use */
+
+ /* Computed factors and state */
+ int rrset; /* Flag, nz if the refresh rate has been determined */
+ double refperiod; /* if > 0.0 in refmode, target int time quantization */
+ double refrate; /* Measured refresh rate in Hz */
+ int refrvalid; /* nz if refrate is valid */
+ double clk_freq; /* Clock frequency (12Mhz) */
+ double dinttime; /* default integration time = 0.2 seconds */
+ double inttime; /* current integration time = 0.2 seconds */
+
+ double transblend; /* Blend between fixed and adaptive integration */
+ /* at low light levels */
+
+ /* Other state */
+ int led_state; /* : Current LED on/off state */
+ double led_period, led_on_time_prop, led_trans_time_prop; /* Pulse state */
+
+ athread *th; /* Diffuser position monitoring thread */
+ volatile int th_term; /* nz to terminate thread */
+ volatile int th_termed; /* nz when thread terminated */
+ int dpos; /* Diffuser position, 0 = display, 1 = ambient */
+
+}; typedef struct _i1d3 i1d3;
+
+/* Constructor */
+extern i1d3 *new_i1d3(icoms *icom, instType itype);
+
+
+#define I1D3_H
+#endif /* I1D3_H */
diff --git a/spectro/i1disp.c b/spectro/i1disp.c
new file mode 100644
index 0000000..b9da1e1
--- /dev/null
+++ b/spectro/i1disp.c
@@ -0,0 +1,2591 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag i1Display related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 18/10/2006
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* !SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* !SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "i1disp.h"
+
+static void dump_bytes(a1log *log, char *pfx, unsigned char *buf, int base, int len);
+static inst_code i1disp_interp_code(inst *pp, int ec);
+static inst_code i1disp_do_fcal_setit(i1disp *p);
+static inst_code i1disp_check_unlock(i1disp *p);
+
+#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */
+
+#define CALFACTOR 3.428 /* Emissive magic calibration factor */
+
+/* ------------------------------------------------------------------------ */
+/* Implementation */
+
+/* Interpret an icoms error into a I1DISP error */
+static int icoms2i1disp_err(int se) {
+ if (se != ICOM_OK)
+ return I1DISP_COMS_FAIL;
+ return I1DISP_OK;
+}
+
+/* i1Display command codes - number:X is argument count:return type */
+/* B = byte (8bit), S = short (16bit), W = word (32bit), */
+/* A = string (5 bytes total max) , - = none */
+typedef enum {
+ i1d_status = 0x00, /* -:A Get status string */
+ i1d_rd_red = 0x01, /* -:W Read the red channel clk count (and trig ?) */
+ i1d_rd_green = 0x02, /* -:W Read the green channel clk count */
+ i1d_rd_blue = 0x03, /* -:W Read the blue channel clk count */
+ i1d_getmeas_p = 0x04, /* -:W Read the measure refresh period */
+ i1d_setintgt = 0x05, /* W:- Set the integration time */
+ i1d_getintgt = 0x06, /* -:W Get the integration time */
+ i1d_wrreg = 0x07, /* BB:- Write a register value */
+ i1d_rdreg = 0x08, /* B:B Read a register value */
+ i1d_getmeas_p2 = 0x09, /* -:W Read the measure refresh period (finer ?) */
+ i1d_m_red_p = 0x0a, /* B:W Measure the red period for given edge count */
+ i1d_m_green_p = 0x0b, /* B:W Measure the green period for given edge count */
+ i1d_m_blue_p = 0x0c, /* B:W Measure the blue period for given edge count */
+ i1d_m_rgb_p = 0x0d, /* BBB:W Measure the RGB period for given edge count */
+ i1d_unlock = 0x0e, /* BBBB:- Unlock the interface */
+
+ i1d_m_red_p2 = 0x10, /* S:W Measure the red period (16 bit) */
+ i1d_m_green_p2 = 0x11, /* S:W Measure the green period (16 bit) */
+ i1d_m_blue_p2 = 0x12, /* S:W Measure the blue period (16 bit) */
+ /* S = edge count */
+
+ i1d_m_red_2 = 0x13, /* B:W Measure the red channel (16 bit) */
+ /* B = sync mode, typically 1 */
+
+ i1d_setmedges2 = 0x14, /* SB:- Set number of edges used for measurment 16 bit */
+ /* B = channel */
+ i1d_getmedges2 = 0x15, /* B:S Get number of edges used for measurment 16 bit */
+ /* B = channel */
+
+ i1d_m_rgb_edge_2 = 0x16, /* -:W Measure RGB Edge (16 bit) */
+
+ i1d_set_pll_p = 0x11, /* SS:- Set PLL period */
+ i1d_get_pll_p = 0x12, /* -:W Get PLL period */
+
+ i1d_m_rgb_edge_3 = 0x10, /* BBBB:W Measure RGB Edge & return red. */
+ /* BBBB = edge counts ??? */
+ i1d_g_green_3 = 0x11, /* -:W Get green data */
+ i1d_g_blue_3 = 0x12, /* -:W Get blue data */
+
+ i1d_wrxreg = 0x13, /* SB:- Write an extra register value */
+ i1d_rdxreg = 0x14, /* S:B Read an extra register value */
+
+ i1d_rdexreg = 0x19 /* BS:B Smile: Read an extended register value */
+ /* The address range overlapps i1d_rdreg */
+} i1DispCC;
+
+/* Do a command/response exchange with the i1disp. */
+/* Return the error code */
+/* The i1 display uses a rather convoluted means of communication (historical?). */
+/* Messages from the host are conveyed one byte per USB control message, */
+/* with the byte conveyed in bRequest, with each such control message reading */
+/* 8 bytes of data from the device. The last 8 bytes read in an overall */
+/* message contains up to 5 response bytes, the last always being nul (?). */
+/* Muti-byte quantities are transmitted in big-endian order. */
+/* (Instructions 1,2,3,8 & 9 seem to be retried up to 5 times. We're */
+/* not doing this, as it may just be historical) */
+static inst_code
+i1disp_command_1(
+ i1disp *p, /* i1display object */
+ i1DispCC cc, /* Command code */
+ unsigned char *in, int insize, /* Parameter to send */
+ unsigned char *out, int bsize, int *rsize, /* Parameter returned */
+ double to /* Timeout in seconds */
+) {
+ int requesttype; /* 8 bit request type (USB bmRequestType) */
+ int request; /* 8 bit request code (USB bRequest) */
+ int value; /* 16 bit value (USB wValue, sent little endian) */
+ int index; /* 16 bit index (USB wIndex, sent little endian) */
+ int rwsize; /* 16 bit data size (USB wLength, send little endian) */
+ int rcc = 0; /* Return cc code from instruction */
+ int i, tsize;
+ unsigned char buf[8]; /* 8 bytes to read */
+ int se, ua = 0, rv = inst_ok;
+
+ tsize = insize + 2;
+ *rsize = 0;
+
+ a1logd(p->log, 4, "i1disp: Sending cmd %02x args '%s'\n",cc, icoms_tohex(in, insize));
+
+ /* For each byte to be sent */
+ for (i = 0; i < tsize; i++) {
+ unsigned int smsec;
+
+ /* Control message to read 8 bytes */
+ requesttype = IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_ENDPOINT;
+ if (i == 0) /* Count */
+ request = insize + 1;
+ else if (i == 1) /* Command */
+ request = (int)cc;
+ else /* Data */
+ request = (int)in[i-2];
+ value = i; /* Incrementing count */
+ index = (tsize - i - 1); /* Decrementing count */
+ rwsize = 8;
+
+ smsec = msec_time();
+ if ((se = p->icom->usb_control(p->icom, requesttype, request, value, index,
+ buf, rwsize, to)) != 0) {
+ a1logd(p->log, 1, "i1disp: Message send failed with ICOM err 0x%x\n",se);
+ p->last_com_err = se;
+ return i1disp_interp_code((inst *)p, I1DISP_COMS_FAIL);
+ }
+
+ /* We could check the return data. This seems to be what we sent, */
+ /* unless it's the last exchange in the message sequence. */
+ /* I don't currently know how or if the device signals an error. */
+
+ /* If this is the last exchange, copy return value out */
+ if (i == (tsize-1)) {
+ *rsize = buf[1];
+ if (*rsize > bsize)
+ *rsize = bsize;
+ if (*rsize > 5)
+ *rsize = 5;
+ memmove(out, buf + 3, *rsize);
+
+ /* buf[2] is usually the cc, except for i1d_unlock. */
+ /* If it is not the cc, this may indicate that the command */
+ /* should be retried up to a total of 5 times, before */
+ /* assuming it has suceeded. */
+ rcc = buf[2] & 0xff;
+ }
+ }
+ rv = i1disp_interp_code((inst *)p, icoms2i1disp_err(ua));
+
+ if (rv == inst_ok && rcc != cc)
+ rv = i1disp_interp_code((inst *)p, I1DISP_NOT_READY);
+
+ /* Instrument returns "LOCK" to any instruction if it is locked */
+ if (rv == inst_ok && *rsize == 5 && strncmp((char *)out,"LOCK",4) == 0) {
+ rv = i1disp_interp_code((inst *)p, I1DISP_LOCKED);
+ }
+
+ a1logd(p->log, 4, "i1disp: response '%s' ICOM err 0x%x\n",icoms_tohex(out, *rsize),ua);
+
+ return rv;
+}
+
+/* Do a command/response exchange with the i1disp, taking care of */
+/* a LOCK error */
+static inst_code
+i1disp_command(
+ i1disp *p, /* i1display object */
+ i1DispCC cc, /* Command code */
+ unsigned char *in, int insize, /* Parameter to send */
+ unsigned char *out, int bsize, int *rsize, /* Parameter returned */
+ double to /* Timeout in seconds */
+) {
+ inst_code rv;
+
+ if ((rv = i1disp_command_1(p, cc, in, insize, out, bsize, rsize, to)) == inst_ok)
+ return rv;
+
+ /* Unlock and try again */
+ if ((rv & inst_imask) == I1DISP_LOCKED) {
+ if ((rv = i1disp_check_unlock(p)) != inst_ok)
+ return rv;
+ rv = i1disp_command_1(p, cc, in, insize, out, bsize, rsize, to);
+ }
+ return rv;
+}
+
+/* Take an int, and convert it into a byte buffer */
+static void int2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 24) & 0xff;
+ buf[1] = (inv >> 16) & 0xff;
+ buf[2] = (inv >> 8) & 0xff;
+ buf[3] = (inv >> 0) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer */
+static void short2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 8) & 0xff;
+ buf[1] = (inv >> 0) & 0xff;
+}
+
+/* Take a word sized return buffer, and convert it to an int */
+static int buf2int(unsigned char *buf) {
+ int val;
+ val = (signed char)buf[0];
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[3]));
+ return val;
+}
+
+/* Read a byte from a register */
+static inst_code
+i1disp_rdreg_byte(
+ i1disp *p, /* Object */
+ int *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 127, 159 */
+) {
+ unsigned char c, buf[16];
+ int rsize;
+ inst_code ev;
+
+ if (p->dtype == 0) {
+ if (addr < 0 || addr > 127)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_REG_ADDRESS);
+ } else {
+ if (addr < 0 || addr > 159)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_REG_ADDRESS);
+ }
+ c = (unsigned char)addr;
+
+ /* Read a byte */
+ if ((ev = i1disp_command(p, i1d_rdreg, &c, 1,
+ buf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+
+ if (rsize != 3)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+
+ if (buf[0] != c)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_VAL);
+
+ *outp = (int)buf[1];
+
+ return inst_ok;
+}
+
+/* Read a short from a register */
+static inst_code
+i1disp_rdreg_short(
+ i1disp *p, /* Object */
+ int *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 126 */
+) {
+ inst_code ev;
+ int v, val;
+
+ if ((ev = i1disp_rdreg_byte(p, &v, addr)) != inst_ok)
+ return ev;
+ val = v;
+
+ if ((ev = i1disp_rdreg_byte(p, &v, addr+1)) != inst_ok)
+ return ev;
+ val = ((val << 8) + (0xff & v));
+
+ *outp = val;
+
+ return inst_ok;
+}
+
+/* Read a word from a register */
+static inst_code
+i1disp_rdreg_word(
+ i1disp *p, /* Object */
+ int *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 124 */
+) {
+ inst_code ev;
+ int v, val;
+
+ if ((ev = i1disp_rdreg_byte(p, &v, addr)) != inst_ok)
+ return ev;
+ val = v;
+
+ if ((ev = i1disp_rdreg_byte(p, &v, addr+1)) != inst_ok)
+ return ev;
+ val = ((val << 8) + (0xff & v));
+
+ if ((ev = i1disp_rdreg_byte(p, &v, addr+2)) != inst_ok)
+ return ev;
+ val = ((val << 8) + (0xff & v));
+
+ if ((ev = i1disp_rdreg_byte(p, &v, addr+3)) != inst_ok)
+ return ev;
+ val = ((val << 8) + (0xff & v));
+
+ *outp = val;
+
+ return inst_ok;
+}
+
+
+/* Read a float from a register */
+/* Will return I1DISP_FLOAT_NOT_SET if the float value was 0xffffffff */
+static inst_code
+i1disp_rdreg_float(
+ i1disp *p, /* Object */
+ double *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 124 */
+) {
+ inst_code ev;
+ int val;
+
+ if ((ev = i1disp_rdreg_word(p, &val, addr)) != inst_ok)
+ return ev;
+
+ if (ev == 0xffffffff) {
+ return I1DISP_FLOAT_NOT_SET;
+ }
+
+ *outp = IEEE754todouble((unsigned int)val);
+ return inst_ok;
+}
+
+
+/* Write a byte to a register */
+static inst_code
+i1disp_wrreg_byte(
+ i1disp *p, /* Object */
+ int inv, /* Input value */
+ int addr /* Register Address, 0 - 127 */
+) {
+ int cval;
+ unsigned char ibuf[16], obuf[16];
+ int rsize;
+ inst_code ev;
+
+ inv &= 0xff;
+
+ /* Read it first, to see if it needs writing */
+ if ((ev = i1disp_rdreg_byte(p, &cval, addr) ) != inst_ok)
+ return ev;
+
+ if (cval == inv) /* No need to write */
+ return inst_ok;
+
+ ibuf[0] = (unsigned char)addr;
+ ibuf[1] = (unsigned char)inv;
+
+ /* Write a byte */
+ if ((ev = i1disp_command(p, i1d_wrreg, ibuf, 2,
+ obuf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+
+ if (rsize != 2)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+
+ if (obuf[0] != addr)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_VAL);
+
+ /* Check it got written properly */
+ if ((ev = i1disp_rdreg_byte(p, &cval, addr) ) != inst_ok)
+ return ev;
+
+ cval &= 0xff;
+ if (cval != inv) /* No need to write */
+ return i1disp_interp_code((inst *)p, I1DISP_EEPROM_WRITE_FAIL);
+
+ return inst_ok;
+}
+
+/* Write a word to a register */
+static inst_code
+i1disp_wrreg_word(
+ i1disp *p, /* Object */
+ int inv, /* Where to write value */
+ int addr /* Register Address, 0 - 124 */
+) {
+ inst_code ev;
+ int v;
+
+ v = (inv >> 24) & 0xff;
+ if ((ev = i1disp_wrreg_byte(p, v, addr) ) != inst_ok)
+ return ev;
+
+ v = (inv >> 16) & 0xff;
+ if ((ev = i1disp_wrreg_byte(p, v, addr+1) ) != inst_ok)
+ return ev;
+
+ v = (inv >> 8) & 0xff;
+ if ((ev = i1disp_wrreg_byte(p, v, addr+2) ) != inst_ok)
+ return ev;
+
+ v = (inv >> 0) & 0xff;
+ if ((ev = i1disp_wrreg_byte(p, v, addr+3) ) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* Write a float to a register */
+static inst_code
+i1disp_wrreg_float(
+ i1disp *p, /* Object */
+ double inv, /* Value to write */
+ int addr /* Register Address, 0 - 124 */
+) {
+ inst_code ev;
+ int val;
+
+ val = (int)doubletoIEEE754(inv);
+
+ if ((ev = i1disp_wrreg_word(p, val, addr)) != inst_ok)
+ return ev;
+ return inst_ok;
+}
+
+/* ColorMunki Smile: Read a byte from an extended register range */
+static inst_code
+i1disp_rdexreg_bytes(
+ i1disp *p, /* Object */
+ unsigned char *outp, /* Where to write values */
+ int addr, /* Register Address, 16 bit */
+ int len /* Number of bytes, 8 bits */
+) {
+ unsigned char ibuf[16];
+ unsigned char obuf[16];
+ int rsize;
+ inst_code ev;
+
+ if (p->dtype != 2) /* Only ColorMunki Smile ? */
+ return i1disp_interp_code((inst *)p, I1DISP_WRONG_DEVICE);
+
+ if (addr < 0 || addr > 0x0200)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_REG_ADDRESS);
+
+ if (len < 0 || (addr + len) > 0x0200)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_REG_ADDRESS);
+
+ for (; len > 0; ) {
+ int rlen = len;
+ if (rlen > 4)
+ rlen = 4;
+
+ /* Read up to 4 bytes at a time */
+ short2buf(ibuf+0, addr); /* Address to read from */
+ ibuf[2] = rlen; /* Number of bytes to read */
+ if ((ev = i1disp_command(p, i1d_rdexreg, ibuf, 3,
+ obuf, 16, &rsize, 0.5)) != inst_ok)
+ return ev;
+
+ if ((rsize < 4 && (rsize != (2 + rlen)))
+ || (rsize >= 4 && (rsize != (1 + rlen))))
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+
+ if (obuf[0] != rlen) /* Number of bytes returned */
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_VAL);
+
+ memcpy(outp + addr, obuf + 1, rlen);
+ addr += rlen;
+ len -= rlen;
+ }
+ return inst_ok;
+}
+
+/* Read the integration time */
+static inst_code
+i1disp_rd_int_time(
+ i1disp *p, /* Object */
+ int *outp /* Where to write value */
+) {
+ unsigned char buf[16];
+ int rsize;
+ inst_code ev;
+
+ if ((ev = i1disp_command(p, i1d_getintgt, NULL, 0,
+ buf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+
+ *outp = buf2int(buf);
+
+ return inst_ok;
+}
+
+/* Set the integration time */
+static inst_code
+i1disp_wr_int_time(
+ i1disp *p, /* Object */
+ int inv /* Value to write */
+) {
+ unsigned char buf[16];
+ int rsize;
+ inst_code ev;
+
+ int2buf(buf, inv);
+ if ((ev = i1disp_command(p, i1d_setintgt, buf, 4,
+ buf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+
+ return inst_ok;
+}
+
+/* Read the refresh period */
+static inst_code
+i1disp_rd_meas_ref_period(
+ i1disp *p, /* Object */
+ int *outp /* Where to write value */
+) {
+ unsigned char buf[16];
+ int rsize;
+ inst_code ev;
+
+ if ((ev = i1disp_command(p, i1d_getmeas_p, NULL, 0,
+ buf, 8, &rsize, 1.5)) != inst_ok)
+ return ev;
+
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+
+ *outp = buf2int(buf);
+
+ return inst_ok;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Take a raw RGB period measurement from the device for an i1d1. */
+/* The time taken to count the given number of L2F clock edges (+ve & -ve) */
+/* is measured in clk clk_freq counts. */
+static inst_code
+i1d1_period_measure(
+ i1disp *p, /* Object */
+ int edgec[3], /* Number of clock edges to count */
+ double rgb[3] /* Return the number of clk's */
+) {
+ int i;
+ unsigned char ibuf[16];
+ unsigned char obuf[16];
+ int rsize;
+ inst_code ev;
+
+ /* Sanity check the number of edges */
+ for (i = 0; i < 3; i++) {
+ if (edgec[i] < 1 || edgec[i] > 255)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_INT_THRESH);
+ ibuf[i] = (char)edgec[i];
+ }
+
+ /* Do the measurement, and return the Red value */
+ if ((ev = i1disp_command(p, i1d_m_rgb_p, ibuf, 3,
+ obuf, 8, &rsize, 60.0)) != inst_ok)
+ return ev;
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[0] = (double)buf2int(obuf);
+
+ /* Get the green value */
+ if ((ev = i1disp_command(p, i1d_rd_green, NULL, 0,
+ obuf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[1] = (double)buf2int(obuf);
+
+ /* Get the blue value */
+ if ((ev = i1disp_command(p, i1d_rd_blue, NULL, 0,
+ obuf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[2] = (double)buf2int(obuf);
+
+ return inst_ok;
+}
+
+/* Take a cooked period measurement from the device for the i1d1 */
+/* and return the frequency for each sensor. */
+static inst_code
+i1d1_take_measurement(
+ i1disp *p, /* Object */
+ int cal, /* nz if black is not to be subtracted */
+ double rgb[3] /* Return the rgb frequency values */
+) {
+ int i;
+ int edgec[3]; /* Edge count 1..255 for each channel */
+ inst_code ev;
+
+ if (p->inited == 0)
+ return i1disp_interp_code((inst *)p, I1DISP_NOT_INITED);
+
+ if (p->dtype != 0)
+ return i1disp_interp_code((inst *)p, I1DISP_WRONG_DEVICE);
+
+ /* Do an initial measurement with minimum edge count of 1 */
+ edgec[0] = edgec[1] = edgec[2] = 1;
+
+ if ((ev = i1d1_period_measure(p, edgec, rgb)) != inst_ok)
+ return ev;
+
+ a1logd(p->log, 3, "Initial RGB = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ /* Compute adjusted edge count, aiming */
+ /* for count values of clk_freq = 1 second (~1e6). */
+ for (i = 0; i < 3; i++) {
+ double ns;
+ if (p->clk_freq > ((255.0 - 0.5) * rgb[i]))
+ ns = 255.0;
+ else {
+ ns = floor(p->clk_freq/rgb[i]) + 0.5;
+ if (ns < 1.0)
+ ns = 1.0;
+ }
+ edgec[i] = (int)ns;
+ }
+
+ /* Only if we compute a different edge count, read again */
+ if (edgec[0] > 1 || edgec[1] > 1 || edgec[2] > 1) {
+ double rgb2[3]; /* 2nd RGB Readings */
+
+ if ((ev = i1d1_period_measure(p, edgec, rgb2)) != inst_ok)
+ return ev;
+
+ /* Average readings if we repeated a measurement with the same edge count */
+ /* (Minor advantage, but may as well use it) */
+ for (i = 0; i < 3; i++) {
+ if (edgec[i] == 1)
+ rgb[i] = 0.5 * (rgb[i] + rgb2[i]);
+ else
+ rgb[i] = rgb2[i];
+ }
+ }
+
+ a1logd(p->log, 3, "scaled %d %d %d gives RGB = %f %f %f\n", edgec[0],edgec[1],edgec[2], rgb[0],rgb[1],rgb[2]);
+
+ /* Compute adjusted readings as a frequency. */
+ /* We need to divide the number of edges/2 by the period in seconds */
+ for (i = 0; i < 3; i++) {
+ rgb[i] = (p->rgbadj[i] * 0.5 * (double)edgec[i] * p->clk_freq)/rgb[i];
+ a1logd(p->log, 3, "%d sensor frequency = %f\n",i,rgb[i]);
+
+ /* If we're not calibrating the black */
+ if (cal == 0) {
+ rgb[i] -= p->reg103_F[i]; /* Subtract black level */
+ a1logd(p->log, 3, "%d after sub black = %f\n",i,rgb[i]);
+
+ if (rgb[i] < 0.0001)
+ rgb[i] = 0.0001;
+ a1logd(p->log, 3, "%d after limit min = %f\n",i,rgb[i]);
+ }
+ }
+ a1logd(p->log, 3, "Adjusted RGB = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ return inst_ok;
+}
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . */
+
+/* Take a fixed period frequency measurement from the device for an i1d2. */
+/* This measures edge count over the set integration period. */
+
+/* Take a raw measurement using a given integration time. */
+/* The measureent is the count of (both) edges from the L2V */
+/* over the integration time */
+static inst_code
+i1d2_freq_measure(
+ i1disp *p, /* Object */
+ double *inttime, /* Integration time in seconds. (Return clock rounded) */
+ double rgb[3] /* Return the RGB edge count values */
+) {
+ unsigned char ibuf[16];
+ unsigned char obuf[16];
+ int intclks;
+ int rsize;
+ inst_code ev;
+
+ if (*inttime > 20.0) /* Hmm */
+ *inttime = 20.0;
+
+ intclks = (int)(*inttime * p->iclk_freq + 0.5);
+ *inttime = (double)intclks / p->iclk_freq;
+ if (intclks != p->int_clocks) {
+ if ((ev = i1disp_wr_int_time(p, intclks)) != inst_ok)
+ return ev;
+ if ((ev = i1disp_rd_int_time(p, &intclks) ) != inst_ok)
+ return ev;
+ p->int_clocks = intclks;
+ *inttime = (double)p->int_clocks/p->iclk_freq;
+ }
+
+ /* Do the measurement, and return the Red value */
+ ibuf[0] = 1; /* Sync mode 1 */
+ if ((ev = i1disp_command(p, i1d_m_red_2, ibuf, 1,
+ obuf, 8, &rsize, p->inttime + 1.0)) != inst_ok)
+ return ev;
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[0] = (double)buf2int(obuf);
+
+ /* Get the green value */
+ if ((ev = i1disp_command(p, i1d_rd_green, NULL, 0,
+ obuf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[1] = (double)buf2int(obuf);
+
+ /* Get the blue value */
+ if ((ev = i1disp_command(p, i1d_rd_blue, NULL, 0,
+ obuf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[2] = (double)buf2int(obuf);
+
+ return inst_ok;
+}
+
+/* Take a raw measurement that returns the number of clocks */
+/* between and initial edge and edgec[] subsequent edges of the L2F. */
+/* Both edges are counted. */
+static inst_code
+i1d2_period_measure(
+ i1disp *p, /* Object */
+ int edgec[3], /* Measurement edge count for each channel */
+ double rgb[3] /* Return the RGB clock count values */
+) {
+ int i;
+ unsigned char ibuf[16];
+ unsigned char obuf[16];
+ int rsize;
+ inst_code ev;
+
+ /* Set the edge count */
+ for (i = 0; i < 3; i++) {
+ short2buf(ibuf, edgec[i]); /* Edge count */
+ ibuf[2] = (unsigned char)i; /* Channel number */
+ if ((ev = i1disp_command(p, i1d_setmedges2, ibuf, 3,
+ obuf, 8, &rsize, 1.0)) != inst_ok)
+ return ev;
+ }
+
+ /* Do the measurement, and return the Red value */
+ if ((ev = i1disp_command(p, i1d_m_rgb_edge_2, ibuf, 0,
+ obuf, 8, &rsize, 120.0)) != inst_ok) {
+ return ev;
+ }
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[0] = (double)buf2int(obuf);
+
+ /* Get the green value */
+ if ((ev = i1disp_command(p, i1d_rd_green, NULL, 0,
+ obuf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[1] = (double)buf2int(obuf);
+
+ /* Get the blue value */
+ if ((ev = i1disp_command(p, i1d_rd_blue, NULL, 0,
+ obuf, 8, &rsize, 0.5)) != inst_ok)
+ return ev;
+ if (rsize != 5)
+ return i1disp_interp_code((inst *)p, I1DISP_UNEXPECTED_RET_SIZE);
+ rgb[2] = (double)buf2int(obuf);
+
+ return inst_ok;
+}
+
+#define ME 1 /* One edge initially (should this be 2 ?) */
+
+#ifndef NEVER
+
+/* ### Quick and precise for low levels, but subject to long */
+/* ### delays if the light level drops during measurement, and */
+/* ### may be less accurate at low levels due to dark noise */
+
+/* Take a cooked measurement from the device for the i1d2 */
+static inst_code
+i1d2_take_measurement(
+ i1disp *p, /* Object */
+ int refreshm, /* Measure in refresh mode flag */
+ double rgb[3] /* Return the rgb values */
+) {
+ int i;
+ double rmeas[3]; /* Raw measurement */
+ int edgec[3] = {ME,ME,ME}; /* Measurement edge count for each channel */
+ int cdgec[3] = {ME,ME,ME}; /* CRT computed edge count for re-measure */
+ int mask = 0x0; /* Period measure mask */
+ inst_code ev;
+
+ if (p->inited == 0)
+ return i1disp_interp_code((inst *)p, I1DISP_NOT_INITED);
+
+ if (p->dtype == 0)
+ return i1disp_interp_code((inst *)p, I1DISP_WRONG_DEVICE);
+
+ a1logd(p->log, 3, "i1d2_take_measurement called with refreshm = %d\n",refreshm);
+
+ /* Do refresh period measurement */
+ if (p->dtype == 1 && refreshm && p->rrset == 0) {
+ if ((ev = i1disp_do_fcal_setit(p)) != inst_ok)
+ return ev;
+
+ /* Quantize the sample time */
+ if (p->refperiod > 0.0) {
+ int n;
+ n = (int)ceil(p->dinttime/p->refperiod);
+ p->inttime = n * p->refperiod;
+ a1logd(p->log, 3, "i1disp: integration time quantize to %f secs\n",p->inttime);
+ } else {
+ p->inttime = p->dinttime;
+ a1logd(p->log, 3, "i1disp: integration time set to %f secs\n",p->inttime);
+ }
+ }
+
+// Do a frequency measurement first, to reduces chances of a light change causing delays.
+// This makes LCD same as CRT as far as quantization errors in high level readings.
+// if (refreshm) {
+ /* Do an initial fixed integration time frequency measurement. */
+ a1logd(p->log, 3, "Doing fixed period frequency measurement over %f secs\n",p->inttime);
+
+ if ((ev = i1d2_freq_measure(p, &p->inttime, rmeas)) != inst_ok)
+ return ev;
+
+ for (i = 0; i < 3; i++)
+ rgb[i] = p->rgbadj[i] * 0.5 * rmeas[i]/p->inttime;
+
+ a1logd(p->log, 3, "Got %f %f %f raw, %f %f %f Hz\n",
+ rmeas[0], rmeas[1], rmeas[2], rgb[0], rgb[1], rgb[2]);
+
+ /* Decide whether any channels need re-measuring, */
+ /* and computed cooked values. Threshold is a count of 75 */
+ for (i = 0; i < 3; i++) {
+ if (rmeas[i] <= 75.0) {
+ mask |= (1 << i); /* Yes */
+ if (rmeas[i] >= 10.0) { /* Compute target edges */
+ cdgec[i] = (int)(2.0 * rgb[i] * p->inttime + 0.5);
+ if (cdgec[i] > 2000)
+ cdgec[i] = 2000;
+ else if (cdgec[i] < ME)
+ cdgec[i] = ME;
+ }
+ }
+ }
+// } else {
+// mask = 0x7;
+// }
+ a1logd(p->log, 3, "Re-measure mask = 0x%x\n",mask);
+ a1logd(p->log, 3, "cdgec = %d %d %d\n",cdgec[0],cdgec[1],cdgec[2]);
+
+ /* If any need re-measuring */
+ if (mask != 0) {
+
+ /* See if we need to compute a target edge count */
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) && cdgec[i] == ME)
+ break;
+ }
+
+ /* Yes we do */
+ if (i < 3) {
+
+ a1logd(p->log, 3, "Doing 1st period pre-measurement mask 0x%x, edgec %d %d %d\n",
+ mask, edgec[0], edgec[1], edgec[2]);
+
+ /* Do an initial measurement of 1 edge to estimate the */
+ /* number of edges needed for the whole integration time. */
+ if ((ev = i1d2_period_measure(p, edgec, rmeas)) != inst_ok)
+ return ev;
+
+ a1logd(p->log, 3, "Got %f %f %f raw %f %f %f Hz\n",
+ rmeas[0], rmeas[1], rmeas[2],
+ (p->rgbadj[0] * 0.5 * (double)edgec[0] * p->clk_freq)/rmeas[0],
+ (p->rgbadj[1] * 0.5 * (double)edgec[1] * p->clk_freq)/rmeas[1],
+ (p->rgbadj[2] * 0.5 * (double)edgec[2] * p->clk_freq)/rmeas[2]);
+
+ /* Compute adjusted edge count for channels we're remeasuring, */
+ /* aiming for a values of int_clocks. */
+ for (i = 0; i < 3; i++) {
+ double ns;
+ if ((mask & (1 << i)) == 0)
+ continue;
+ if (p->int_clocks > ((2000.0 - 0.5) * rmeas[i]))
+ ns = 2000.0; /* Maximum edge count */
+ else {
+ ns = floor(p->inttime * edgec[i] * p->clk_freq/rmeas[i] + 0.5);
+ if (ns < ME) /* Minimum edge count */
+ ns = ME;
+ }
+ edgec[i] = (int)ns;
+ }
+ }
+
+ /* Use frequency computed edge count if available */
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) == 0)
+ continue;
+ if (cdgec[i] != ME)
+ edgec[i] = cdgec[i];
+ }
+
+ /* If we compute a different edge count, read again */
+ if (edgec[0] > ME || edgec[1] > ME || edgec[2] > ME) {
+ double rmeas2[3]; /* 2nd RGB Readings */
+
+ a1logd(p->log, 3, "Doing period re-measurement mask 0x%x, edgec %d %d %d\n",
+ mask, edgec[0], edgec[1], edgec[2]);
+
+ if ((ev = i1d2_period_measure(p, edgec, rmeas2)) != inst_ok)
+ return ev;
+
+ a1logd(p->log, 3, "Got %f %f %f raw %f %f %f Hz\n",
+ rmeas[0], rmeas[1], rmeas[2],
+ (p->rgbadj[0] * 0.5 * (double)edgec[0] * p->clk_freq)/rmeas2[0],
+ (p->rgbadj[1] * 0.5 * (double)edgec[1] * p->clk_freq)/rmeas2[1],
+ (p->rgbadj[2] * 0.5 * (double)edgec[2] * p->clk_freq)/rmeas2[2]);
+
+ a1logd(p->log, 3, "Int period %f %f %f secs\n",
+ rmeas2[0]/p->clk_freq, rmeas2[1]/p->clk_freq, rmeas2[2]/p->clk_freq);
+
+ /* Average readings if we repeated a measurement with the same count */
+ /* (Minor advantage, but may as well use it) */
+ for (i = 0; i < 3; i++) {
+ if (edgec[i] == ME)
+ rmeas[i] = 0.5 * (rmeas[i] + rmeas2[i]);
+ else
+ rmeas[i] = rmeas2[i];
+ }
+ }
+
+ /* Compute adjusted readings, ovewritting initial cooked values */
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) == 0)
+ continue;
+ rgb[i] = (p->rgbadj[i] * 0.5 * (double)edgec[i] * p->clk_freq)/rmeas[i];
+ a1logd(p->log, 3, "%d after scale = %f\n",i,rgb[i]);
+
+ rgb[i] -= p->reg103_F[i]; /* Subtract black level */
+ a1logd(p->log, 3, "%d after sub black = %f\n",i,rgb[i]);
+
+ if (rgb[i] < 0.0001)
+ rgb[i] = 0.0001;
+ a1logd(p->log, 3, "%d after limit min = %f\n",i,rgb[i]);
+ }
+ }
+
+ a1logd(p->log, 3, "Cooked RGB Hz = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ return inst_ok;
+}
+
+#else
+/* Less precise (worse quatization errors), but more robust */
+/* against excessive delays if the light level drops during measurement. */
+/* Limits period measurement to an edge count < 35, but that can */
+/* still take a long time in the dark. */
+
+/* Take a cooked measurement from the device for the i1d2 */
+static inst_code
+i1d2_take_measurement(
+ i1disp *p, /* Object */
+ int refreshm, /* Measure in crt mode flag */
+ double rgb[3] /* Return the rgb values */
+) {
+ int i;
+ double rmeas[3]; /* Raw measurement */
+ int edgec[3] = {ME,ME,ME}; /* Measurement edge count for each channel */
+ int cdgec[3] = {ME,ME,ME}; /* CRT computed edge count for re-measure */
+ int fmask = 0x0; /* Freq re-measure mask */
+ int mask = 0x0; /* Period measure mask */
+ inst_code ev;
+
+ if (p->inited == 0)
+ return i1disp_interp_code((inst *)p, I1DISP_NOT_INITED);
+
+ if (p->dtype == 0)
+ return i1disp_interp_code((inst *)p, I1DISP_WRONG_DEVICE);
+
+ a1logd(p->log, 3, "i1d2_take_measurement called with refreshm = %d\n",refreshm);
+
+ /* Do refresh period measurement */
+ if (p->dtype == 1 && refreshm && p->rrset == 0) {
+ if ((ev = i1disp_do_fcal_setit(p)) != inst_ok)
+ return ev;
+
+ /* Quantize the sample time */
+ if (p->refperiod > 0.0) {
+ int n;
+ n = (int)ceil(p->dinttime/p->refperiod);
+ p->inttime = n * p->refperiod;
+ a1logd(p->log, 3, "i1disp: integration time quantize to %f secs\n",p->inttime);
+ } else {
+ p->inttime = p->dinttime;
+ a1logd(p->log, 3, "i1disp: ntegration time set to %f secs\n",p->inttime);
+ }
+ }
+
+ /* Do an initial fixed integration time frequency measurement. */
+ a1logd(p->log, 3, "Doing fixed period frequency measurement over %f secs\n",p->inttime)
+
+ if ((ev = i1d2_freq_measure(p, &p->inttime, rmeas)) != inst_ok)
+ return ev;
+
+ for (i = 0; i < 3; i++)
+ rgb[i] = p->rgbadj[i] * 0.5 * rmeas[i]/p->inttime;
+
+ a1logd(p->log, 3, "Got %f %f %f raw, %f %f %f Hz\n",
+ rmeas[0], rmeas[1], rmeas[2], rgb[0], rgb[1], rgb[2]);
+
+ /* Decide whether any channels need re-measuring. */
+ /* Threshold is a count of 75, and switch to period */
+ /* measurement mode on count less than 37. */
+ fmask = 0x0;
+ for (i = 0; i < 3; i++) {
+
+ if (rmeas[i] <= 75.0) {
+ fmask |= (1 << i); /* Yes, do another freq re-measure */
+
+ if (rmeas[i] <= 37.5) {
+ mask |= (1 << i); /* Do a period re-measure */
+ fmask = 0; /* Don't bother with freq re-measure */
+ }
+ if (rmeas[i] >= 10.0) { /* Compute target edges */
+ cdgec[i] = (int)(2.0 * rgb[i] * p->inttime + 0.5);
+ if (cdgec[i] > 2000)
+ cdgec[i] = 2000;
+ else if (cdgec[i] < ME)
+ cdgec[i] = ME;
+ }
+ }
+ }
+ a1logd(p->log, 3, "Freq mask = 0x%x, Period mask 0x%x\n",fmask, mask);
+ a1logd(p->log, 3, "cdgec = %d %d %d\n",cdgec[0],cdgec[1],cdgec[2]);
+
+ /* If there is a frequency re-measure */
+ /* ** This doesn't actually work. The quantization error */
+ /* for each read is 0.5, but averaging 2 reads it drops */
+ /* to 0.354, not the desired 0.25 that would have been */
+ /* acheived with double the integration time. ** */
+ if (fmask != 0) {
+ a1logd(p->log, 3, "Doing frequency re-measurement over %f secs\n",p->inttime);
+ if ((ev = i1d2_freq_measure(p, &p->inttime, rmeas)) != inst_ok)
+ return ev;
+
+ for (i = 0; i < 3; i++) {
+ rgb[i] += p->rgbadj[i] * 0.5 * rmeas[i]/p->inttime;
+ rgb[i] /= 2.0;
+ }
+
+ a1logd(p->log, 3, "Got %f %f %f raw, %f %f %f Avg. Hz\n",
+ rmeas[0], rmeas[1], rmeas[2], rgb[0], rgb[1], rgb[2]);
+
+ /* If there is a period re-measure */
+ } else if (mask != 0) {
+
+ /* See if we need to compute a target edge count */
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) && cdgec[i] == ME)
+ break;
+ }
+
+ /* Yes we do */
+ if (i < 3) {
+
+ a1logd(p->log, 3, "Doing 1st period pre-measurement mask 0x%x, edgec %d %d %d\n",
+ mask, edgec[0], edgec[1], edgec[2]);
+
+ /* Do an initial measurement of 1 edge to estimate the */
+ /* number of edges needed for the whole integration time. */
+ if ((ev = i1d2_period_measure(p, edgec, rmeas)) != inst_ok)
+ return ev;
+
+ a1logd(p->log, 3, "Got %f %f %f raw %f %f %f Hz\n",
+ rmeas[0], rmeas[1], rmeas[2],
+ (p->rgbadj[0] * 0.5 * (double)edgec[0] * p->clk_freq)/rmeas[0],
+ (p->rgbadj[1] * 0.5 * (double)edgec[1] * p->clk_freq)/rmeas[1],
+ (p->rgbadj[2] * 0.5 * (double)edgec[2] * p->clk_freq)/rmeas[2]);
+
+ /* Compute adjusted edge count for channels we're remeasuring, */
+ /* aiming for a values of int_clocks. */
+ for (i = 0; i < 3; i++) {
+ double ns;
+ if ((mask & (1 << i)) == 0)
+ continue;
+ if (p->int_clocks > ((2000.0 - 0.5) * rmeas[i]))
+ ns = 2000.0; /* Maximum edge count */
+ else {
+ ns = floor(p->inttime * edgec[i] * p->clk_freq/rmeas[i] + 0.5);
+ if (ns < ME) /* Minimum edge count */
+ ns = ME;
+ }
+ edgec[i] = (int)ns;
+
+ /* Sanity check cdgec value, in case light level has changed */
+ if ((edgec[i] * 3) < (cdgec[i] * 2)) {
+ cdgec[i] = edgec[i];
+ }
+ }
+ }
+
+ /* Use frequency computed edge count if available */
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) == 0)
+ continue;
+ if (cdgec[i] != ME)
+ edgec[i] = cdgec[i];
+ }
+
+ /* If we compute a different edge count, read again */
+ if (edgec[0] > ME || edgec[1] > ME || edgec[2] > ME) {
+ double rmeas2[3]; /* 2nd RGB Readings */
+
+ a1logd(p->log, 3, "Doing period re-measurement mask 0x%x, edgec %d %d %d\n",
+ mask, edgec[0], edgec[1], edgec[2]);
+
+ if ((ev = i1d2_period_measure(p, edgec, rmeas2)) != inst_ok)
+ return ev;
+
+ a1logd(p->log, 3, "Got %f %f %f raw %f %f %f Hz\n",
+ rmeas[0], rmeas[1], rmeas[2],
+ (p->rgbadj[0] * 0.5 * (double)edgec[0] * p->clk_freq)/rmeas2[0],
+ (p->rgbadj[1] * 0.5 * (double)edgec[1] * p->clk_freq)/rmeas2[1],
+ (p->rgbadj[2] * 0.5 * (double)edgec[2] * p->clk_freq)/rmeas2[2]);
+
+ a1logd(p->log, 3, "Int period %f %f %f secs\n",
+ rmeas2[0]/p->clk_freq, rmeas2[1]/p->clk_freq, rmeas2[2]/p->clk_freq);
+
+ /* Average readings if we repeated a measurement with the same count */
+ /* (Minor advantage, but may as well use it) */
+ for (i = 0; i < 3; i++) {
+ if (edgec[i] == ME)
+ rmeas[i] = 0.5 * (rmeas[i] + rmeas2[i]);
+ else
+ rmeas[i] = rmeas2[i];
+ }
+ }
+
+ /* Compute adjusted readings, ovewritting initial cooked values */
+ for (i = 0; i < 3; i++) {
+ if ((mask & (1 << i)) == 0)
+ continue;
+ rgb[i] = (p->rgbadj[i] * 0.5 * (double)edgec[i] * p->clk_freq)/rmeas[i];
+ a1logd(p->log, 3, "%d after scale = %f\n",i,rgb[i]);
+
+ rgb[i] -= p->reg103_F[i]; /* Subtract black level */
+ a1logd(p->log, 3, "%d after sub black = %f\n",i,rgb[i]);
+
+ if (rgb[i] < 0.0001)
+ rgb[i] = 0.0001;
+ a1logd(p->log, 3, "%d after limit min = %f\n",i,rgb[i]);
+ }
+ }
+
+ a1logd(p->log, 3, "Cooked RGB Hz = %f %f %f\n",rgb[0],rgb[1],rgb[2]);
+
+ return inst_ok;
+}
+#endif
+#undef ME
+
+/* . . . . . . . . . . . . . . . . . . . . . . . . */
+
+/* Take a XYZ measurement from the device */
+static inst_code
+i1disp_take_XYZ_measurement(
+ i1disp *p, /* Object */
+ double XYZ[3] /* Return the XYZ values */
+) {
+ int i, j;
+ double rgb[3]; /* RGB Readings */
+ inst_code ev;
+ double *mat; /* Pointer to matrix */
+
+ if (p->dtype == 0) { /* i1 disp 1 */
+ if ((ev = i1d1_take_measurement(p, 0, rgb)) != inst_ok)
+ return ev;
+ } else { /* i1 disp 2 or ColorMunki Smile */
+ int refreshm = 0; /* Assume non-refresh mode */
+
+ if (p->refrmode && !IMODETST(p->mode, inst_mode_emis_ambient)) {
+ refreshm = 1;
+ }
+
+ if ((ev = i1d2_take_measurement(p, refreshm, rgb)) != inst_ok)
+ return ev;
+ }
+
+ /* Multiply by calibration matrix to arrive at XYZ */
+ if (IMODETST(p->mode, inst_mode_emis_ambient)) {
+ mat = p->amb; /* Ambient matrix */
+ } else {
+ if (p->icx)
+ mat = p->reg54_F; /* CRT/factory matrix/CCFL */
+ else
+ mat = p->reg4_F; /* LCD/user matrix/LED */
+ }
+ for (i = 0; i < 3; i++) {
+ XYZ[i] = 0.0;
+ for (j = 0; j < 3; j++) {
+ XYZ[i] += mat[i * 3 + j] * rgb[j];
+ }
+ XYZ[i] *= CALFACTOR; /* Times magic scale factor */
+
+#ifdef NEVER
+ if (p->chroma4)
+ XYZ[i] *= 4.0/3.0; /* (Not sure about this factor!) */
+#endif
+ }
+
+ if (!IMODETST(p->mode, inst_mode_emis_ambient)) {
+
+ /* Apply the colorimeter correction matrix */
+ icmMulBy3x3(XYZ, p->ccmat, XYZ);
+ }
+
+ a1logd(p->log, 3, "returning XYZ = %f %f %f\n",XYZ[0],XYZ[1],XYZ[2]);
+ return inst_ok;
+}
+
+/* Do a black calibration (i1display 1) */
+static inst_code
+i1disp_do_black_cal(
+ i1disp *p /* Object */
+) {
+ int i;
+ double rgb1[3], rgb2[3]; /* RGB Readings */
+ inst_code ev;
+
+ if (p->dtype != 0)
+ return i1disp_interp_code((inst *)p, I1DISP_CANT_BLACK_CALIB);
+
+ /* Do a couple of readings without subtracting the black */
+ if ((ev = i1d1_take_measurement(p, 1, rgb1)) != inst_ok)
+ return ev;
+ if ((ev = i1d1_take_measurement(p, 1, rgb2)) != inst_ok)
+ return ev;
+
+ /* Average the results */
+ for (i = 0; i < 3; i++) {
+ rgb1[i] = 0.5 * (rgb1[i] + rgb2[i]);
+
+ /* Since the readings are clamped to 0.0001, */
+ /* aim for a black level of 0.0001 */
+ rgb1[i] -= 0.0001;
+ }
+
+ a1logd(p->log, 3, "Black rgb = %f %f %f\n",rgb1[0],rgb1[1],rgb1[2]);
+
+ /* Save it to the EEPROM */
+ for (i = 0; i < 3; i++) {
+ if ((ev = i1disp_wrreg_float(p, rgb1[i], 103 + 4 * i)) != inst_ok)
+ return ev;
+ p->reg103_F[i] = rgb1[i];
+ }
+ return inst_ok;
+}
+
+/* Measure the refresh rate */
+static inst_code
+i1disp_read_refrate(
+ inst *pp,
+ double *ref_rate /* Return value, 0.0 if fails */
+) {
+ i1disp *p = (i1disp *)pp;
+ int i;
+ inst_code ev;
+ double measp = 0.0;
+
+ a1logd(p->log, 3, "Frequency calibration called\n");
+
+ if (p->dtype != 1)
+ return inst_unsupported;
+
+ /* Average a few refresh period readings */
+ for (i = 0; i < p->nmeasprds; i++) {
+ int mp;
+
+ /* Measures period in clocks */
+ if ((ev = i1disp_rd_meas_ref_period(p, &mp)) != inst_ok)
+ return ev;
+ if (mp == 0) {
+ measp = 0.0;
+ break; /* Too dark to measure */
+ }
+ measp += (double)mp;
+ }
+
+ /* Compute the measurement frequency */
+ if (measp != 0.0) {
+ double rrate = (p->clk_freq * (double)p->nmeasprds)/measp;
+ a1logd(p->log, 3, "Sample frequency measured = %f\n",rrate);
+ if (ref_rate != NULL)
+ *ref_rate = rrate;
+ return inst_ok;
+ } else {
+ a1logd(p->log, 3, "No discernable refresh frequency measured\n");
+ if (ref_rate != NULL)
+ *ref_rate = 0.0;
+ return inst_misread;
+ }
+}
+
+/* Do a refresh period cailbration */
+static inst_code
+i1disp_do_fcal_setit(
+ i1disp *p /* Object */
+) {
+ int i;
+ inst_code ev;
+
+ a1logd(p->log, 3, "Frequency calibration called\n");
+
+ if (p->dtype != 1)
+ return i1disp_interp_code((inst *)p, I1DISP_CANT_MEASP_CALIB);
+
+ if ((ev = i1disp_read_refrate((inst *)p, &p->refrate)) != inst_ok
+ && ev != inst_misread)
+ return ev;
+
+ if (p->refrate != 0.0) {
+ p->refperiod = 1.0/p->refrate;
+ p->refrvalid = 1;
+ } else {
+ p->refrvalid = 0;
+ }
+ p->rrset = 1;
+
+ return inst_ok;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Check the device is responding, and unlock if necessary */
+static inst_code
+i1disp_check_unlock(
+ i1disp *p /* Object */
+) {
+ unsigned char buf[16];
+ int rsize;
+ inst_code ev;
+ int i, vv;
+ double ver;
+
+ struct {
+ unsigned char code[4];
+ int *flag;
+ } codes[] = {
+ { { 'G','r','M','b' }, NULL }, /* "GrMb" i1 Display */
+ { { 'L','i','t','e' }, &p->lite }, /* "Lite" i1 Display LT */
+ { { 'M','u','n','k' }, &p->munki }, /* "Munk" ColorMunki Create */
+ { { 'O','b','i','W' }, &p->hpdream }, /* "ObiW" HP DreamColor */
+ { { 'O','b','i','w' }, &p->hpdream }, /* "Obiw" HP DreamColor */
+ { { 'C','M','X','2' }, &p->calmanx2 }, /* "CMX2" Calman X2 */
+ { { 0x24,0xb6,0xb5,0x13 }, NULL }, /* ColorMunki Smile */
+ { { 'R','G','B','c' }, NULL }, /* */
+ { { 'C','E','C','5' }, NULL }, /* */
+ { { 'C','M','C','5' }, NULL }, /* */
+ { { 'C','M','G','5' }, NULL }, /* */
+ { { 0x00,0x00,0x01,0x00 }, NULL }, /* */
+ { { 0x09,0x0b,0x0c,0x0d }, NULL }, /* */
+ { { 0x0e,0x0e,0x0e,0x0e }, NULL }, /* */
+ { { 0x11,0x02,0xde,0xf0 }, NULL }, /* Barco Chroma 5 ? */
+ { { ' ',' ',' ',' ' }, (int *)-1 }
+ };
+
+ a1logd(p->log, 3, "i1disp: about to check response and unlock instrument if needed\n");
+
+ /* Get status */
+ if ((ev = i1disp_command_1(p, i1d_status, NULL, 0,
+ buf, 8, &rsize, 0.5)) != inst_ok && (ev & inst_imask) != I1DISP_LOCKED)
+ return ev; /* An error other than being locked */
+
+ /* Try and unlock it if it is locked */
+ if ((ev & inst_imask) == I1DISP_LOCKED) {
+
+ /* Reset any flags */
+ for (i = 0; ;i++) {
+ if (codes[i].flag == (int *)-1)
+ break;
+ if (codes[i].flag != NULL)
+ *codes[i].flag = 0;
+ }
+
+ /* Try each code in turn */
+ for (i = 0; ;i++) {
+ if (codes[i].flag == (int *)-1) {
+ a1logd(p->log, 3, "Failed to find correct unlock code\n");
+ return i1disp_interp_code((inst *)p, I1DISP_UNKNOWN_MODEL);
+ }
+
+ /* Try unlock code. Ignore I1DISP_NOT_READY status. */
+ if (((ev = i1disp_command_1(p, i1d_unlock, codes[i].code, 4,
+ buf, 8, &rsize, 0.5)) & inst_mask) != inst_ok
+ && (ev & inst_imask) != I1DISP_LOCKED)
+ return ev; /* Some other sort of failure */
+
+ /* Get status */
+ if ((ev = i1disp_command_1(p, i1d_status, NULL, 0,
+ buf, 8, &rsize, 0.5)) != inst_ok
+ && (ev & inst_imask) != I1DISP_LOCKED)
+ return ev; /* An error other than being locked */
+
+ if (ev == inst_ok) { /* Correct code */
+ if (codes[i].flag != NULL)
+ *codes[i].flag = 1;
+ break;
+ }
+ }
+ }
+
+ if (rsize != 5 || !isdigit(buf[0]) || buf[1] != '.'
+ || !isdigit(buf[2]) || !isdigit(buf[3])) {
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_STATUS);
+ }
+
+ buf[4] = '\000';
+ ver = atof((char *)buf);
+ a1logd(p->log, 3, "Version string = %5.3f\n",ver);
+
+ /* Read register 0x79 for the model identifier */
+ if ((ev = i1disp_rdreg_byte(p, &vv, 121) ) != inst_ok) {
+ return ev;
+ }
+ vv &= 0xff;
+
+ a1logd(p->log, 3, "Version character = 0x%02x = '%c'\n",vv,vv);
+
+ /* Sequel Chroma 4 with vv == 0xff ? */
+ /* Barco Chroma 5 with ver = 5.01 and vv = '5' */
+ if (ver >= 4.0 && ver < 5.1
+ && (vv == 0xff || vv == 0x35)) {
+ p->dtype = 0; /* Sequel Chroma 4 ?? */
+ p->chroma4 = 1; /* Treat like an Eye-One Display 1 */
+ /* !!! Not fully tested !!! */
+ } else if (ver >= 5.1 && ver <= 5.3 && vv == 'L') {
+ p->dtype = 0; /* Eye-One Display 1 */
+ } else if (ver >= 6.0 && ver <= 6.29 && vv == 'L') {
+ p->dtype = 1; /* Eye-One Display 2 */
+
+ } else if (ver >= 6.0 && ver <= 6.29 && vv == 'M') {
+ /* ColorMunki Create ? */
+ /* ColorMunki Smile */
+ if (p->dtype == 0) /* Not sure if this is set by Create */
+ p->dtype = 1;
+ } else {
+ /* Reject any version or model we don't know about */
+ a1logv(p->log, 1, "Version string = %3.1f\nID character = 0x%02x = '%c'\n",ver,vv,vv);
+ return i1disp_interp_code((inst *)p, I1DISP_UNKNOWN_VERS_ID);
+ }
+
+ a1logd(p->log, 2, "i1disp: instrument is responding, unlocked, and right type\n");
+
+ return inst_ok;
+}
+
+/* Read all the relevant register values */
+static inst_code
+i1disp_read_all_regs(
+ i1disp *p /* Object */
+) {
+ inst_code ev;
+ int i;
+
+ a1logd(p->log, 3, "i1disp: about to read all the registers\n");
+
+ /* Serial number */
+ 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);
+
+ /* LCD/user calibration values */
+ for (i = 0; i < 9; i++) {
+ if ((ev = i1disp_rdreg_float(p, &p->reg4_F[i], 4 + 4 * i) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "LCD/user cal[%d] = %f\n",i,p->reg4_F[i]);
+ }
+ /* LCD/user calibration time */
+ if ((ev = i1disp_rdreg_word(p, &p->reg50_W, 50) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "LCD/user calibration time = 0x%x = %s\n",p->reg50_W, ctime_32(&p->reg50_W));
+
+ /* LCD/user calibration flag */
+ if ((ev = i1disp_rdreg_short(p, &p->reg126_S, 126) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "User cal flag = 0x%x\n",p->reg126_S);
+
+
+ /* CRT/factory calibration values */
+ for (i = 0; i < 9; i++) {
+ if ((ev = i1disp_rdreg_float(p, &p->reg54_F[i], 54 + 4 * i) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "CRT/factory cal[%d] = %f\n",i,p->reg54_F[i]);
+ }
+ /* CRT/factory calibration flag */
+ if ((ev = i1disp_rdreg_word(p, &p->reg90_W, 90) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "CRT/factory flag = 0x%x = %s\n",p->reg90_W, ctime_32(&p->reg90_W));
+
+
+ /* Integration clock period in nsec */
+ if ((ev = i1disp_rdreg_short(p, &p->reg40_S, 40) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "Reg40 = %d\n",p->reg40_S);
+
+ /* Calibration factor */
+ if ((ev = i1disp_rdreg_short(p, &p->reg42_S, 42) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "Reg42 = %d\n",p->reg42_S);
+
+ /* Calibration factors */
+ for (i = 0; i < 3; i++) {
+ if ((ev = i1disp_rdreg_short(p, &p->reg44_S[i], 44 + 2 * i) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "reg44[%d] = %d\n",i,p->reg44_S[i]);
+ }
+
+ /* Measurement/master clock period */
+ if ((ev = i1disp_rdreg_float(p, &p->clk_prd, 94) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "Master clock Frequency = %e\n",1/p->clk_prd);
+
+ /* unknown */
+ if ((ev = i1disp_rdreg_word(p, &p->reg98_W, 98) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "reg98 = 0x%x = %s\n",p->reg98_W,ctime_32(&p->reg98_W));
+
+ /* unknown */
+ if ((ev = i1disp_rdreg_byte(p, &p->reg102_B, 102) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "reg102 = 0x%x\n",p->reg102_B);
+
+ /* Dark current calibration values */
+ /* Should we set to a default 0.0 if reg126_S < 0xd ?? */
+ for (i = 0; i < 3; i++) {
+ if ((ev = i1disp_rdreg_float(p, &p->reg103_F[i], 103 + 4 * i)) != inst_ok) {
+ if ((ev & inst_imask) != I1DISP_FLOAT_NOT_SET)
+ return ev;
+ p->reg103_F[i] = 0.0;
+ }
+ a1logd(p->log, 3, "darkcal[%d] = %f\n",i,p->reg103_F[i]);
+ }
+
+ /* Unknown byte */
+ if ((ev = i1disp_rdreg_byte(p, &p->reg115_B, 115) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "Unknown 115 byte = 0x%x\n",p->reg115_B);
+
+ /* device ID byte */
+ if ((ev = i1disp_rdreg_byte(p, &p->reg121_B, 121) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "device type byte = 0x%x\n",p->reg121_B);
+
+ /* Unlock string */
+ for (i = 0; i < 4; i++) {
+ int vv;
+ if ((ev = i1disp_rdreg_byte(p, &vv, 122 + i) ) != inst_ok)
+ return ev;
+ p->reg122_B[i] = (char)vv;
+ }
+ p->reg122_B[i] = '\000';
+ a1logd(p->log, 3, "unlock string = '%s'\n",p->reg122_B);
+
+ p->serno[0] = '\000';
+
+ /* Read extra registers */
+ if (p->dtype == 1) {
+
+#ifdef NEVER /* Not used, so don't bother */
+ for (i = 0; i < 3; i++) {
+ if ((ev = i1disp_rdreg_float(p, &p->reg128_F[i], 128 + 4 * i) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "reg128_F[%d] = %f\n",i,p->reg128_F[i]);
+ }
+#endif /* NEVER */
+
+ for (i = 0; i < 3; i++) {
+ if ((ev = i1disp_rdreg_float(p, &p->reg144_F[i], 144 + 4 * i) ) != inst_ok) {
+ if ((ev & inst_imask) != I1DISP_FLOAT_NOT_SET)
+ return ev;
+ p->reg144_F[i] = 1.0;
+ }
+ a1logd(p->log, 3, "Ambient scale factor [%d] = %f\n",i,p->reg144_F[i]);
+ }
+
+ /* Read the integration time */
+ if ((ev = i1disp_rd_int_time(p, &p->int_clocks) ) != inst_ok)
+ return ev;
+ a1logd(p->log, 3, "Integration time = %d\n",p->int_clocks);
+
+ /* ColorMunki Smile extra information */
+ /* (Colormunki Create too ????) */
+ } else if (p->dtype == 2) {
+ int i, v;
+
+ /* Smile doesn't have ambient - reg144 seems to contain LCD cal type, */
+ /* ie. "CCFLWLED" */
+
+ /* Serial Number */
+ if ((ev = i1disp_rdexreg_bytes(p, (unsigned char *)p->serno, 0x104, 20)) != inst_ok)
+ return ev;
+ p->serno[19] = '\000';
+ }
+ a1logd(p->log, 2, "i1disp: all registers read OK\n");
+
+ return inst_ok;
+}
+
+/* Compute factors that depend on the register values */
+static inst_code
+i1disp_compute_factors(
+ i1disp *p /* Object */
+) {
+ int i;
+
+ /* Check that certain value are valid */
+ if (p->reg0_W == 0xffffffff)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_SERIAL_NUMBER);
+
+ /* LCD calibration date valid ? */
+ if (p->reg50_W == 0xffffffff)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_LCD_CALIBRATION);
+
+ /* The value stored in reg126_S ("user cal flag") seems hard to interpret. */
+ /* For the i1display 1&2, it has a value of 0x0d. */
+ /* Value 0x07 seems to be for a "user calibration" */
+ /* Values 3 & 6 seem to always "errors" as does a value */
+ /* < 7 in most circumstances. But the Heidelberg Viewmaker */
+ /* (from Sequel Imaging) and Lacie Blue Eye colorimeter seems to have a value of 2. */
+ /* The Barco sensor seems to have a value of 0x20 */
+ /* The ColorMunki Smile has a value of 0x21 */
+ if (p->reg126_S == 0xffffffff || (p->reg126_S < 7 && p->reg126_S != 2))
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_LCD_CALIBRATION);
+
+ /* Not quite sure about this, but we're assuming this */
+ /* is set to 2 or 0xd if reg4-36 hold the LCD calibration, */
+ /* and some other number if they are not set, or set */
+ /* to a custom user calibration. */
+ if (p->reg126_S != 0x02
+ && p->reg126_S != 0x0d
+ && p->reg126_S != 0x20
+ && p->reg126_S != 0x21)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_LCD_CALIBRATION);
+
+ if (p->reg90_W == 0xffffffff)
+ return i1disp_interp_code((inst *)p, I1DISP_BAD_CRT_CALIBRATION);
+
+ /* Compute ambient matrix */
+ for (i = 0; i < 9; i++)
+ p->amb[i] = p->reg144_F[i % 3] * 0.5 * (p->reg4_F[i] + p->reg54_F[i]);
+
+ /* Integration clock frequency */
+ p->iclk_freq = 1.0/(p->reg40_S * 1e-9);
+
+ /* Master/Measurement clock frequency */
+ p->clk_freq = 1.0/p->clk_prd;
+
+ /* RGB channel calibration factors */
+ for (i = 0; i < 3; i++) {
+
+ /* Individual channel calibration factors, typically 1.0 */
+ p->rgbadj[i] = (double)p->reg44_S[i] * 100.0/(double)p->reg42_S;
+ a1logd(p->log, 3, "reg44+%dcalc2 = %f\n",i,p->rgbadj[i]);
+ }
+
+ /* Set some defaults */
+ p->nmeasprds = 5; /* Number of disp refresh period measurments to average */
+ /* in doing frequency calibration */
+ p->dinttime = 1.0; /* 1.0 second integration time default */
+ p->inttime = p->dinttime; /* Current integration time */
+
+ return inst_ok;
+}
+
+/* ------------------------------------------------------------------------ */
+
+/* Establish communications with a I1DISP */
+/* If it's a serial port, use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+i1disp_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ i1disp *p = (i1disp *) pp;
+ unsigned char buf[16];
+ int rsize;
+ int se;
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "i1disp: About to init coms\n");
+
+ if (p->icom->port_type(p->icom) != icomt_usb) {
+ a1logd(p->log, 1, "i1disp_init_coms: coms is not the right type!\n");
+ return i1disp_interp_code((inst *)p, I1DISP_UNKNOWN_MODEL);
+ }
+
+ /* Set config, interface, write end point, read end point */
+ /* ("serial" end points aren't used - the i1display uses USB control messages) */
+
+ /* Set config, interface, write end point, read end point, read quanta */
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, icomuf_none, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "i1disp_init_coms: set_usbe_port failed ICOM err 0x%x\n",se);
+ return i1disp_interp_code((inst *)p, icoms2i1disp_err(se));
+ }
+
+ /* Check instrument is responding */
+ if ((ev = i1disp_command_1(p, i1d_status, NULL, 0, buf, 8, &rsize, 0.5)) != inst_ok
+ && (ev & inst_imask) != I1DISP_LOCKED) {
+ a1logd(p->log, 1, "i1disp_init_coms: failed with rv = 0x%x\n",ev);
+ return ev;
+ }
+
+ a1logd(p->log, 2, "i1disp: init coms OK\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+static inst_code set_default_disp_type(i1disp *p);
+
+/* Initialise the I1DISP */
+/* return non-zero on an error, with dtp error code */
+static inst_code
+i1disp_init_inst(inst *pp) {
+ i1disp *p = (i1disp *)pp;
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "i1disp_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return i1disp_interp_code((inst *)p, I1DISP_NO_COMS); /* Must establish coms first */
+
+ /* Check instrument is responding, and right type */
+ if ((ev = i1disp_check_unlock(p)) != inst_ok)
+ return ev;
+
+ /* Read all the registers and store their contents */
+ if ((ev = i1disp_read_all_regs(p)) != inst_ok)
+ return ev;
+
+#ifdef NEVER
+ /* Dump all the register space */
+ if (p->dtype < 2) {
+ unsigned char buf[0x200];
+ int i, len;
+
+ len = 128;
+ if (p->dtype != 0)
+ len = 160;
+
+ for (i = 0; i < len; i++) {
+ int v;
+ if ((ev = i1disp_rdreg_byte(p, &v, i)) != inst_ok) {
+ return ev;
+ }
+ buf[i] = v;
+ }
+ dump_bytes(p->log, "dump:", buf, 0, len);
+
+ /* Dump ColorMunki Smile extended range */
+ /* Main difference is Ascii serial number + other minor unknown */
+ } else {
+ unsigned char buf[0x200];
+
+
+ if ((ev = i1disp_rdexreg_bytes(p, buf, 0, 0x200)) != inst_ok) {
+ return ev;
+ }
+ dump_bytes(p->log, "dump:", buf, 0, 0x200);
+ }
+#endif /* NEVER */
+
+ if ((ev = i1disp_compute_factors(p)) != inst_ok)
+ return ev;
+
+ p->trig = inst_opt_trig_user;
+
+ /* Set a default calibration */
+ if ((ev = set_default_disp_type(p)) != inst_ok) {
+ return ev;
+ }
+
+ p->inited = 1;
+ a1logd(p->log, 2, "i1disp_init_inst: inited OK\n");
+
+ return inst_ok;
+}
+
+/* Read a single sample */
+/* Return the dtp error code */
+static inst_code
+i1disp_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ i1disp *p = (i1disp *)pp;
+ int user_trig = 0;
+ int rv = inst_protocol_error;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "i1disp: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rv == inst_user_abort)
+ return rv; /* Abort */
+ if (rv == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return rv; /* Abort */
+ }
+
+ /* Read the XYZ value */
+ if ((rv = i1disp_take_XYZ_measurement(p, val->XYZ)) != inst_ok)
+ return rv;
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+ val->loc[0] = '\000';
+ if (IMODETST(p->mode, inst_mode_emis_ambient))
+ val->mtype = inst_mrt_ambient;
+ else
+ val->mtype = inst_mrt_emission;
+ val->XYZ_v = 1; /* These are absolute XYZ readings ? */
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (user_trig)
+ return inst_user_trig;
+ return rv;
+}
+
+/* Insert a colorimetric correction matrix in the instrument XYZ readings */
+/* This is only valid for colorimetric instruments. */
+/* To remove the matrix, pass NULL for the filter filename */
+inst_code i1disp_col_cor_mat(
+inst *pp,
+double mtx[3][3]
+) {
+ i1disp *p = (i1disp *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (mtx == NULL) {
+ icmSetUnity3x3(p->ccmat);
+ } else {
+ if (p->cbid == 0) {
+ a1loge(p->log, 1, "spyd2: can't set col_cor_mat over non base display type\n");
+ inst_wrong_setup;
+ }
+ icmCpy3x3(p->ccmat, mtx);
+ }
+
+ return inst_ok;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code i1disp_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ i1disp *p = (i1disp *)pp;
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if (p->dtype == 0) { /* Eye-One Display 1 */
+ a_cals |= inst_calt_emis_offset;
+ }
+
+ if (p->dtype == 1 && p->refrmode != 0) {
+ if (p->rrset == 0)
+ n_cals |= inst_calt_ref_freq;
+ a_cals |= inst_calt_ref_freq;
+ }
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+/* This is use if the user decides they want to do a calibration, */
+/* in anticipation of a calibration (needs_calibration()) to avoid */
+/* requiring one during measurement, or in response to measuring */
+/* returning inst_needs_cal. Initially us an inst_cal_cond of inst_calc_none, */
+/* and then be prepared to setup the right conditions, or ask the */
+/* user to do so, each time the error inst_cal_setup is returned. */
+inst_code i1disp_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ i1disp *p = (i1disp *)pp;
+ inst_code ev;
+ inst_cal_type needed, available;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ id[0] = '\000';
+
+ if ((ev = i1disp_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"i1disp_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return inst_unsupported;
+ }
+
+ /* Do the appropriate calibration */
+ if (p->dtype == 0) { /* Eye-One Display 1 */
+ if (*calt & inst_calt_emis_offset) {
+
+ if (*calc != inst_calc_man_ref_dark) {
+ *calc = inst_calc_man_ref_dark;
+ return inst_cal_setup;
+ }
+
+ /* Do black offset calibration */
+ if ((ev = i1disp_do_black_cal(p)) != inst_ok)
+ return ev;
+
+ *calt &= ~inst_calt_emis_offset;
+ }
+
+ } else { /* Eye-One Display 2 */
+ if ((*calt & inst_calt_ref_freq) && p->refrmode != 0) {
+
+ if (*calc != inst_calc_emis_white) {
+ *calc = inst_calc_emis_white;
+ return inst_cal_setup;
+ }
+
+ /* Do CRT frequency calibration and set integration time */
+ if ((ev = i1disp_do_fcal_setit(p)) != inst_ok)
+ return ev;
+
+ /* Quantize the sample time */
+ if (p->refperiod > 0.0) {
+ int n;
+ n = (int)ceil(p->dinttime/p->refperiod);
+ p->inttime = n * p->refperiod;
+ a1logd(p->log, 3, "i1disp: integration time quantize to %f secs\n",p->inttime);
+ } else {
+ p->inttime = p->dinttime;
+ a1logd(p->log, 3, "i1disp: integration time set to %f secs\n",p->inttime);
+ }
+
+ *calt &= ~inst_calt_ref_freq;
+ }
+ }
+
+ return inst_ok;
+}
+
+/* Return the last calibrated refresh rate in Hz. Returns: */
+static inst_code i1disp_get_refr_rate(inst *pp,
+double *ref_rate
+) {
+ i1disp *p = (i1disp *)pp;
+ if (p->refrvalid) {
+ *ref_rate = p->refrate;
+ return inst_ok;
+ } else if (p->rrset) {
+ *ref_rate = 0.0;
+ return inst_misread;
+ }
+ return inst_needs_cal;
+}
+
+/* Set the calibrated refresh rate in Hz. */
+/* Set refresh rate to 0.0 to mark it as invalid */
+/* Rates outside the range 5.0 to 150.0 Hz will return an error */
+static inst_code i1disp_set_refr_rate(inst *pp,
+double ref_rate
+) {
+ i1disp *p = (i1disp *)pp;
+
+ if (ref_rate != 0.0 && (ref_rate < 5.0 || ref_rate > 150.0))
+ return inst_bad_parameter;
+
+ p->refrate = ref_rate;
+ if (ref_rate == 0.0)
+ p->refrvalid = 0;
+ else {
+ p->refperiod = 1.0/p->refrate;
+ p->refrvalid = 1;
+ }
+ p->rrset = 1;
+
+ return inst_ok;
+}
+
+/* Error codes interpretation */
+static char *
+i1disp_interp_error(inst *pp, int ec) {
+// i1disp *p = (i1disp *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case I1DISP_INTERNAL_ERROR:
+ return "Internal software error";
+ case I1DISP_COMS_FAIL:
+ return "Communications failure";
+ case I1DISP_UNKNOWN_MODEL:
+ return "Not a i1 Display";
+ case I1DISP_DATA_PARSE_ERROR:
+ return "Data from i1 Display didn't parse as expected";
+
+ case I1DISP_OK:
+ return "No device error";
+
+ case I1DISP_FLOAT_NOT_SET:
+ return "Float value is not set in EEPROM";
+ case I1DISP_NOT_READY:
+ return "Command didn't return command code - not ready ?";
+
+ case I1DISP_BAD_SERIAL_NUMBER:
+ return "Serial number isn't set";
+ case I1DISP_BAD_LCD_CALIBRATION:
+ return "LCD calibration values aren't set";
+ case I1DISP_BAD_CRT_CALIBRATION:
+ return "CRT calibration values aren't set";
+ case I1DISP_EEPROM_WRITE_FAIL:
+ return "Write to EEPROM failed to verify";
+
+ case I1DISP_UNEXPECTED_RET_SIZE:
+ return "Message from instrument has unexpected size";
+ case I1DISP_UNEXPECTED_RET_VAL:
+ return "Message from instrument has unexpected value";
+
+ case I1DISP_BAD_STATUS:
+ return "Instrument status is unrecognised format";
+ case I1DISP_UNKNOWN_VERS_ID:
+ return "Instrument version number or ID byte not recognised";
+
+ /* Internal errors */
+ case I1DISP_BAD_REG_ADDRESS:
+ return "Out of range register address";
+ case I1DISP_BAD_INT_THRESH:
+ return "Out of range integration threshold";
+ case I1DISP_NO_COMS:
+ return "Communications hasn't been established";
+ case I1DISP_NOT_INITED:
+ return "Insrument hasn't been initialised";
+ case I1DISP_CANT_BLACK_CALIB:
+ return "Device doesn't support black calibration";
+ case I1DISP_CANT_MEASP_CALIB:
+ return "Device doesn't support measurment period calibration";
+ case I1DISP_WRONG_DEVICE:
+ return "Wrong type of device for called function";
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+i1disp_interp_code(inst *pp, int ec) {
+// i1disp *p = (i1disp *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case I1DISP_OK:
+ case I1DISP_FLOAT_NOT_SET: /* Internal indication */
+ case I1DISP_NOT_READY: /* Internal indication */
+ return inst_ok;
+
+ case I1DISP_INTERNAL_ERROR:
+ case I1DISP_BAD_REG_ADDRESS:
+ case I1DISP_BAD_INT_THRESH:
+ case I1DISP_NO_COMS:
+ case I1DISP_NOT_INITED:
+ case I1DISP_CANT_BLACK_CALIB:
+ case I1DISP_CANT_MEASP_CALIB:
+ case I1DISP_WRONG_DEVICE:
+ case I1DISP_LOCKED:
+ return inst_internal_error | ec;
+
+ case I1DISP_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case I1DISP_UNKNOWN_MODEL:
+ case I1DISP_BAD_STATUS:
+ case I1DISP_UNKNOWN_VERS_ID:
+ return inst_unknown_model | ec;
+
+ case I1DISP_DATA_PARSE_ERROR:
+ case I1DISP_UNEXPECTED_RET_SIZE:
+ case I1DISP_UNEXPECTED_RET_VAL:
+ return inst_protocol_error | ec;
+
+ case I1DISP_BAD_SERIAL_NUMBER:
+ case I1DISP_BAD_LCD_CALIBRATION:
+ case I1DISP_BAD_CRT_CALIBRATION:
+ case I1DISP_EEPROM_WRITE_FAIL:
+ return inst_hardware_fail | ec;
+
+ /* return inst_misread | ec; */
+ /* return inst_needs_cal_2 | ec; */
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+i1disp_del(inst *pp) {
+ i1disp *p = (i1disp *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ inst_del_disptype_list(p->dtlist, p->ndtlist);
+ free(p);
+}
+
+/* Return the instrument capabilities */
+void i1disp_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ i1disp *p = (i1disp *)pp;
+ inst_mode cap1 = 0;
+ inst2_capability cap2 = 0;
+
+ cap1 |= inst_mode_emis_spot
+ | inst_mode_colorimeter
+ ;
+
+ cap2 |= inst2_prog_trig
+ | inst2_user_trig
+ | inst2_disptype
+ | inst2_ccmx
+ ;
+
+ /* i1D2 has refresh display & ambient capability */
+ /* but i1D1 & ColorMunki Smile don't */
+ if (p->dtype == 1) {
+ cap1 |= inst_mode_emis_ambient
+ | inst_mode_emis_refresh_ovd
+ | inst_mode_emis_norefresh_ovd
+ ;
+
+ cap2 |= inst2_refresh_rate
+ | inst2_emis_refr_meas
+ ;
+ }
+
+ if (pcap1 != NULL)
+ *pcap1 = cap1;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Check device measurement mode */
+inst_code i1disp_check_mode(inst *pp, inst_mode m) {
+ i1disp *p = (i1disp *)pp;
+ inst_mode cap;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple filter for most modes */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* Only display emission mode supported */
+ if (!IMODETST(m, inst_mode_emis_spot)
+ && !(p->dtype == 1 && IMODETST(m, inst_mode_emis_ambient))) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code i1disp_set_mode(inst *pp, inst_mode m) {
+ i1disp *p = (i1disp *)pp;
+ inst_code ev;
+
+ if ((ev = i1disp_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->mode = m;
+
+ if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) /* Must test this first! */
+ p->refrmode = 0;
+ else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd))
+ p->refrmode = 1;
+
+ return inst_ok;
+}
+
+inst_disptypesel i1disp_disptypesel[3] = {
+ {
+ inst_dtflags_default,
+ 1,
+ "l",
+ "LCD display",
+ 0,
+ 0
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 2, /* cbix */
+ "c", /* sel */
+ "CRT display", /* desc */
+ 1, /* refr */
+ 1 /* ix */
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+
+inst_disptypesel smile_disptypesel[3] = {
+ {
+ inst_dtflags_default, /* flags */
+ 1, /* cbix */
+ "f", /* sel */
+ "LCD with CCFL backlight", /* desc */
+ 0, /* refr */
+ 1 /* ix */
+ },
+ {
+ inst_dtflags_none,
+ 0,
+ "e",
+ "LCD with White LED backlight",
+ 0,
+ 0
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+static void set_base_disptype_list(i1disp *p) {
+ /* set the base display type list */
+ if (p->itype == instSmile) {
+ p->_dtlist = smile_disptypesel;
+ } else {
+ p->_dtlist = i1disp_disptypesel;
+ }
+}
+
+/* Get mode and option details */
+static inst_code i1disp_get_disptypesel(
+inst *pp,
+int *pnsels, /* Return number of display types */
+inst_disptypesel **psels, /* Return the array of display types */
+int allconfig, /* nz to return list for all configs, not just current. */
+int recreate /* nz to re-check for new ccmx & ccss files */
+) {
+ i1disp *p = (i1disp *)pp;
+ inst_code rv = inst_ok;
+
+ /* Create/Re-create a current list of abailable display types */
+ if (p->dtlist == NULL || recreate) {
+ if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ p->_dtlist, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return rv;
+ }
+
+ if (pnsels != NULL)
+ *pnsels = p->ndtlist;
+
+ if (psels != NULL)
+ *psels = p->dtlist;
+
+ return inst_ok;
+}
+
+/* Given a display type entry, setup for that type */
+static inst_code set_disp_type(i1disp *p, inst_disptypesel *dentry) {
+ int refrmode;
+
+ p->icx = dentry->ix;
+ p->cbid = dentry->cbid;
+ refrmode = dentry->refr;
+
+ if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */
+ refrmode = 0;
+ } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) {
+ refrmode = 1;
+ }
+
+ if (p->refrmode != refrmode) {
+ p->rrset = 0; /* This is a hint we may have swapped displays */
+ p->refrvalid = 0;
+ }
+ p->refrmode = refrmode;
+
+ if (dentry->flags & inst_dtflags_ccmx) {
+ icmCpy3x3(p->ccmat, dentry->mat);
+ } else {
+ icmSetUnity3x3(p->ccmat);
+ }
+
+ return inst_ok;
+}
+
+/* Setup the default display type */
+static inst_code set_default_disp_type(i1disp *p) {
+ inst_code ev;
+ int i;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist,
+ p->_dtlist, 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) {
+ if (p->dtlist[i].flags & inst_dtflags_default)
+ break;
+ }
+ if (p->dtlist[i].flags & inst_dtflags_end) {
+ a1loge(p->log, 1, "set_default_disp_type: failed to find type!\n");
+ return inst_internal_error;
+ }
+ if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/* Set the display type */
+static inst_code i1disp_set_disptype(inst *pp, int ix) {
+ i1disp *p = (i1disp *)pp;
+ inst_code ev;
+ inst_disptypesel *dentry;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ p->_dtlist, 1 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ if (ix < 0 || ix >= p->ndtlist)
+ return inst_unsupported;
+
+ dentry = &p->dtlist[ix];
+
+ if ((ev = set_disp_type(p, dentry)) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+
+/*
+ * set or reset an optional mode
+ *
+ * Since there is no interaction with the instrument,
+ * was assume that all of these can be done before initialisation.
+ */
+static inst_code
+i1disp_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ i1disp *p = (i1disp *)pp;
+ inst_code ev;
+
+ /* Get the display type information */
+ if (m == inst_opt_get_dtinfo) {
+ va_list args;
+ int *refrmode, *cbid;
+
+ va_start(args, m);
+ refrmode = va_arg(args, int *);
+ cbid = va_arg(args, int *);
+ va_end(args);
+
+ if (refrmode != NULL)
+ *refrmode = p->refrmode;
+ if (cbid != NULL)
+ *cbid = p->cbid;
+
+ return inst_ok;
+ }
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user) {
+ p->trig = m;
+ return inst_ok;
+ }
+
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern i1disp *new_i1disp(icoms *icom, instType itype) {
+ i1disp *p;
+ if ((p = (i1disp *)calloc(sizeof(i1disp),1)) == NULL) {
+ a1loge(icom->log, 1, "new_i1disp: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = i1disp_init_coms;
+ p->init_inst = i1disp_init_inst;
+ p->capabilities = i1disp_capabilities;
+ p->check_mode = i1disp_check_mode;
+ p->set_mode = i1disp_set_mode;
+ p->get_disptypesel = i1disp_get_disptypesel;
+ p->set_disptype = i1disp_set_disptype;
+ p->get_set_opt = i1disp_get_set_opt;
+ p->read_sample = i1disp_read_sample;
+ p->read_refrate = i1disp_read_refrate;
+ p->get_n_a_cals = i1disp_get_n_a_cals;
+ p->calibrate = i1disp_calibrate;
+ p->col_cor_mat = i1disp_col_cor_mat;
+ p->get_refr_rate = i1disp_get_refr_rate;
+ p->set_refr_rate = i1disp_set_refr_rate;
+ p->interp_error = i1disp_interp_error;
+ p->del = i1disp_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ if (p->itype == instI1Disp2)
+ p->dtype = 1; /* i1Display2 */
+
+ else if (p->itype == instSmile) {
+ p->dtype = 2; /* Smile */
+ }
+
+ icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */
+ set_base_disptype_list(p);
+
+ return p;
+}
+
+/* ---------------------------------------------------------------- */
+
+// Print bytes as hex to debug log */
+static void dump_bytes(a1log *log, char *pfx, unsigned char *buf, int base, int len) {
+ int i, j, ii;
+ char oline[200] = { '\000' }, *bp = oline;
+ for (i = j = 0; i < len; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp,"%s%04x:",pfx,base+i);
+ bp += sprintf(bp," %02x",buf[i]);
+ if ((i+1) >= len || ((i+1) % 16) == 0) {
+ for (ii = i; ((ii+1) % 16) != 0; ii++)
+ bp += sprintf(bp," ");
+ bp += sprintf(bp," ");
+ for (; j <= i; j++) {
+ if (!(buf[j] & 0x80) && isprint(buf[j]))
+ bp += sprintf(bp,"%c",buf[j]);
+ else
+ bp += sprintf(bp,".");
+ }
+ bp += sprintf(bp,"\n");
+ a1logd(log,0,oline);
+ bp = oline;
+ }
+ }
+}
+
+
+
+
diff --git a/spectro/i1disp.h b/spectro/i1disp.h
new file mode 100644
index 0000000..893cad2
--- /dev/null
+++ b/spectro/i1disp.h
@@ -0,0 +1,172 @@
+#ifndef I1DISP_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag i1Display related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 19/10/2006
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Note: update i1disp_interp_error() and i1disp_interp_code() in i1disp.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define I1DISP_INTERNAL_ERROR 0x61 /* Internal software error */
+#define I1DISP_COMS_FAIL 0x62 /* Communication failure */
+#define I1DISP_UNKNOWN_MODEL 0x63 /* Not an i1display */
+#define I1DISP_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error code */
+#define I1DISP_OK 0x00
+
+/* Sub codes for device specific reasoning */
+#define I1DISP_FLOAT_NOT_SET 0x01
+#define I1DISP_NOT_READY 0x02
+
+#define I1DISP_BAD_SERIAL_NUMBER 0x03
+#define I1DISP_BAD_LCD_CALIBRATION 0x04
+#define I1DISP_BAD_CRT_CALIBRATION 0x05
+#define I1DISP_EEPROM_WRITE_FAIL 0x06
+
+#define I1DISP_UNEXPECTED_RET_SIZE 0x07
+#define I1DISP_UNEXPECTED_RET_VAL 0x08
+
+#define I1DISP_BAD_STATUS 0x09
+#define I1DISP_UNKNOWN_VERS_ID 0x10
+
+/* Internal errors */
+#define I1DISP_BAD_REG_ADDRESS 0x20
+#define I1DISP_BAD_INT_THRESH 0x21
+#define I1DISP_NO_COMS 0x22
+#define I1DISP_NOT_INITED 0x23
+#define I1DISP_CANT_BLACK_CALIB 0x24
+#define I1DISP_CANT_MEASP_CALIB 0x25
+#define I1DISP_WRONG_DEVICE 0x26
+#define I1DISP_LOCKED 0x27
+
+
+/* I1DISP communication object */
+struct _i1disp {
+ INST_OBJ_BASE
+
+ int dtype; /* Device type: 0 = i1D1, 1 = i1D2, 2 = Smile */
+ int lite; /* i1D2: 0 = normal, 1 = "Lite" */
+ int munki; /* i1D2: 0 = normal, 1 = "Munk" */
+ int hpdream; /* i1D2: 0 = normal, 1 = "ObiW" */
+ int calmanx2; /* i1D2: 0 = normal, 1 = "CMX2" */
+ int chroma4; /* 0 = other, 1 = Sequel Chroma 4 (i1D1 based) */
+ inst_mode mode; /* Currently selected mode */
+
+ inst_opt_type trig; /* Reading trigger mode */
+
+ /* EEPROM registers */
+ /* Number is the register address, and B, S, W, F indicate the type/size */
+ int reg0_W; /* Serial number */
+
+ double reg4_F[9]; /* LCD 3x3 calibration matrix (also known as "user") */
+ /* Smile LED backlight */
+ int reg50_W; /* Calibration time in secs from January 1, 1970, UTC */
+ int reg126_S; /* LCD cal valid/state flag. For the i1disp this is 0xd, */
+ /* perhaps meaning that it is the LCD matrix. */
+ /* It's set to 7 after storing a user calibration. */
+ /* A value of 0xffff or < 7 means that it's invalid */
+ /* A value of 2 seems valid for OEM instruments */
+ /* (Heidelberg Viewmaker & Lacie Blue Eye) */
+
+ double reg54_F[9]; /* CRT 3x3 calibration matrix (also known as "factory") */
+ /* Smile CCFL backlight */
+ int reg90_W; /* CRT cal valid/time flag. 0xffffffff = invalid, */
+ /* time in secs from January 1, 1970, UTC */
+
+ int reg40_S; /* Integration clock perod in nsec reg40S, typically 1000 */
+ int reg42_S; /* Int cal. factor denominator, typically 10000 */
+ int reg44_S[3]; /* Int cal. factors numerator/100, typically 100 */
+
+ double clk_prd; /* Master clock period, reg94F, typically 1e-6 */
+
+ int reg98_W; /* A time value. Date of manufacture ? */
+ /* Reg 40-44 write date ? */
+
+ int reg102_B; /* Not used ? */
+
+ double reg103_F[3]; /* Dark current calibration values */
+ /* Not valid if reg126_S < 0xd ?? */
+
+ int reg115_B; /* Unknown */
+ int reg121_B; /* Device ID character */
+
+ char reg122_B[5]; /* Unlock string */
+
+ /* Extra registers for dtype == 1 (Eye-One Display2) */
+// double reg128_F[3]; /* Not used at all */
+ double reg144_F[3]; /* Ambient matrix adjustment values */
+ /* ??? Default to 1.0 if not set in EEPROM */
+
+ /* Computed factors and state */
+ double iclk_freq; /* Integration clock (from reg40_S), typically 1e6 */
+ double clk_freq; /* Measurement clock (from reg94_F), typically 1e6 */
+ double rgbadj[3]; /* RGB adjustment values for period meas., typically 1.0 */
+ double amb[9]; /* Ambient measurement matrix = ref144[] * average of LCD & CRT */
+
+ inst_disptypesel *_dtlist; /* Base list */
+ inst_disptypesel *dtlist; /* Display Type list */
+ int ndtlist; /* Number of valid dtlist entries */
+ int icx; /* 0 = LCD, 1 = CRT/CCFL matrix */
+ int cbid; /* calibration base ID, 0 if not a base */
+ double ccmat[3][3]; /* Colorimeter correction matrix */
+
+ /* For dtype == 1 (Eye-One Display2) */
+ int nmeasprds; /* Number of disp refresh period measurments to average, deflt 5 */
+ int refrmode; /* 0 for constant, 1 for refresh display */
+ int rrset; /* Flag, nz if the refresh rate has been determined */
+ double refperiod; /* if > 0.0 in refmode, target int time quantization */
+ double refrate; /* Measured refresh rate in Hz */
+ int refrvalid; /* nz if refrate is valid */
+
+ double dinttime; /* default integration time = 1.1 seconds */
+ double inttime; /* current integration time = 1.0 seconds */
+
+ int int_clocks; /* Currently set integration time in clocks */
+
+ /* For dtype == 2 (ColorMunki Smile) */
+ char serno[20]; /* Ascii serial number */
+
+ /* misc */
+ int last_com_err; /* Last icoms error code */
+
+}; typedef struct _i1disp i1disp;
+
+/* Constructor */
+extern i1disp *new_i1disp(icoms *icom, instType itype);
+
+
+#define I1DISP_H
+#endif /* I1DISP_H */
diff --git a/spectro/i1pro.c b/spectro/i1pro.c
new file mode 100644
index 0000000..99dd61b
--- /dev/null
+++ b/spectro/i1pro.c
@@ -0,0 +1,809 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag i1Monitor & i1Pro related functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/11/2006
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+/*
+ TTBD
+
+
+ Should add extra filter compensation support.
+
+ Should alias projector mode to display mode ??
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "rspl.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#include "rspl1.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "i1pro.h"
+#include "i1pro_imp.h"
+
+#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */
+
+/* Convert a machine specific error code into an abstract inst code */
+static inst_code i1pro_interp_code(i1pro *p, i1pro_code ec);
+
+/* ------------------------------------------------------------------------ */
+
+/* Establish communications with a I1DISP */
+/* If it's a serial port, use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+i1pro_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ i1pro *p = (i1pro *) pp;
+ int rsize, se;
+ icomuflags usbflags = icomuf_none;
+#ifdef __APPLE__
+ /* If the X-Rite software has been installed, then there may */
+ /* be a daemon process that has the device open. Kill that process off */
+ /* so that we can open it here, before it re-spawns. */
+ char *pnames[] = {
+// "i1iSisDeviceService",
+ "i1ProDeviceService",
+ NULL
+ };
+ int retries = 20;
+#else /* !__APPLE__ */
+ char **pnames = NULL;
+ int retries = 0;
+#endif /* !__APPLE__ */
+
+ a1logd(p->log, 2, "i1pro_init_coms: called\n");
+
+ if (p->icom->port_type(p->icom) != icomt_usb) {
+ a1logd(p->log, 1, "i1pro_init_coms: wrong sort of coms!\n");
+ return i1pro_interp_code(p, I1PRO_UNKNOWN_MODEL);
+ }
+
+ a1logd(p->log, 2, "i1pro_init_coms: about to init USB\n");
+
+ /* Set config, interface, write end point, read end point, read quanta */
+ /* ("serial" end points aren't used - the i1display uses USB control messages) */
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, retries, pnames))
+ != ICOM_OK) {
+ a1logd(p->log, 1, "i1pro_init_coms: failed ICOM err 0x%x\n",se);
+ return i1pro_interp_code(p, icoms2i1pro_err(se));
+ }
+
+ a1logd(p->log, 2, "i1pro_init_coms: init coms has suceeded\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+static inst_code
+i1pro_determine_capabilities(i1pro *p) {
+
+ /* Set the base Monitor/Pro capabilities mask */
+ p->cap = inst_mode_emis_spot
+ | inst_mode_emis_tele
+ | inst_mode_emis_strip /* Also likely to be light table reading */
+ | inst_mode_trans_spot /* Support this manually using a light table */
+ | inst_mode_trans_strip
+ | inst_mode_emis_nonadaptive
+ | inst_mode_colorimeter
+ | inst_mode_spectral
+ ;
+
+ /* Set the Pro capabilities mask */
+ if (p->itype == instI1Pro
+ || p->itype == instI1Pro2) {
+ p->cap |= inst_mode_ref_spot
+ | inst_mode_ref_strip
+ ;
+ }
+
+ /* Set the Pro2 capabilities mask */
+ if (p->itype == instI1Pro2) {
+ p->cap |= inst_mode_ref_uv
+ ;
+ }
+
+ if (i1pro_imp_highres(p)) /* This is static */
+ p->cap |= inst_mode_highres;
+
+ if (i1pro_imp_ambient(p)) { /* This depends on the instrument */
+ p->cap |= inst_mode_emis_ambient
+ | inst_mode_emis_ambient_flash
+ ;
+ }
+
+ p->cap2 = inst2_prog_trig
+ | inst2_user_trig
+ | inst2_user_switch_trig
+ | inst2_bidi_scan
+ | inst2_has_scan_toll
+ | inst2_no_feedback
+ ;
+
+ if (p->m != NULL) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ if (s->emiss)
+ p->cap2 |= inst2_emis_refr_meas;
+ }
+
+ p->cap3 = inst3_none;
+
+ return inst_ok;
+}
+
+/* Initialise the I1PRO */
+/* return non-zero on an error, with inst error code */
+static inst_code
+i1pro_init_inst(inst *pp) {
+ i1pro *p = (i1pro *)pp;
+ i1pro_code ev = I1PRO_OK;
+
+ a1logd(p->log, 2, "i1pro_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return i1pro_interp_code(p, I1PRO_INT_NO_COMS); /* Must establish coms before calling init */
+ if ((ev = i1pro_imp_init(p)) != I1PRO_OK) {
+ a1logd(p->log, 1, "i1pro_init_inst: failed with 0x%x\n",ev);
+ return i1pro_interp_code(p, ev);
+ }
+
+ p->inited = 1;
+ a1logd(p->log, 2, "i1pro_init_inst: instrument inited OK\n");
+
+ /* Now it's initied, we can get true capabilities */
+ i1pro_determine_capabilities(p);
+
+ return i1pro_interp_code(p, ev);
+}
+
+static char *i1pro_get_serial_no(inst *pp) {
+ i1pro *p = (i1pro *)pp;
+
+ if (!pp->gotcoms)
+ return "";
+ if (!pp->inited)
+ return "";
+
+ return i1pro_imp_get_serial_no(p);
+}
+
+/* Read a set of strips */
+static inst_code
+i1pro_read_strip(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (3 chars) */
+int sguide, /* Guide number */
+double pwid, /* Patch length in mm (DTP41) */
+double gwid, /* Gap length in mm (DTP41) */
+double twid, /* Trailer length in mm (DTP41T) */
+ipatch *vals) { /* Pointer to array of instrument patch values */
+ i1pro *p = (i1pro *)pp;
+ i1pro_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ rv = i1pro_imp_measure(p, vals, npatch, 1);
+
+ return i1pro_interp_code(p, rv);
+}
+
+/* Read a single sample */
+static inst_code
+i1pro_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* Clamp XYZ/Lab to be +ve */
+ i1pro *p = (i1pro *)pp;
+ i1pro_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ rv = i1pro_imp_measure(p, val, 1, clamp);
+
+ return i1pro_interp_code(p, rv);
+}
+
+/* Read an emissive refresh rate */
+static inst_code
+i1pro_read_refrate(
+inst *pp,
+double *ref_rate) {
+ i1pro *p = (i1pro *)pp;
+ i1pro_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ rv = i1pro_imp_meas_refrate(p, ref_rate);
+
+ return i1pro_interp_code(p, rv);
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code i1pro_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ i1pro *p = (i1pro *)pp;
+ i1pro_code rv;
+
+ rv = i1pro_imp_get_n_a_cals(p, pn_cals, pa_cals);
+ return i1pro_interp_code(p, rv);
+}
+
+/* Request an instrument calibration. */
+inst_code i1pro_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ i1pro *p = (i1pro *)pp;
+ i1pro_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ rv = i1pro_imp_calibrate(p, calt, calc, id);
+ return i1pro_interp_code(p, rv);
+}
+
+/* Instrument specific error codes interpretation */
+static char *
+i1pro_interp_error(inst *pp, i1pro_code ec) {
+// i1pro *p = (i1pro *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case I1PRO_INTERNAL_ERROR:
+ return "Internal software error";
+ case I1PRO_COMS_FAIL:
+ return "Communications failure";
+ case I1PRO_UNKNOWN_MODEL:
+ return "Not an i1 Pro";
+ case I1PRO_DATA_PARSE_ERROR:
+ return "Data from i1 Display didn't parse as expected";
+
+ case I1PRO_USER_ABORT:
+ return "User abort";
+
+ case I1PRO_USER_TRIG:
+ return "User trigger";
+
+ case I1PRO_UNSUPPORTED:
+ return "Unsupported function";
+ case I1PRO_CAL_SETUP:
+ return "Calibration retry with correct setup is needed";
+
+ case I1PRO_OK:
+ return "No device error";
+
+ case I1PRO_DATA_COUNT:
+ return "EEProm data count unexpectedly small";
+ case I1PRO_DATA_BUFSIZE:
+ return "EEProm data buffer too small";
+ case I1PRO_DATA_MAKE_KEY:
+ return "EEProm data creating key failed";
+ case I1PRO_DATA_MEMORY:
+ return "EEProm memory alloc failure";
+ case I1PRO_DATA_KEYNOTFOUND:
+ return "EEProm key value wasn't found";
+ case I1PRO_DATA_WRONGTYPE:
+ return "EEProm key is the wrong type";
+ case I1PRO_DATA_KEY_CORRUPT:
+ return "EEProm key table seems to be corrupted";
+ case I1PRO_DATA_KEY_COUNT:
+ return "EEProm key table count is too big or small";
+ case I1PRO_DATA_KEY_UNKNOWN:
+ return "EEProm unknown key type";
+ case I1PRO_DATA_KEY_MEMRANGE:
+ return "EEProm key data is out of range of EEProm";
+ case I1PRO_DATA_KEY_ENDMARK:
+ return "EEProm end section marker was missing";
+
+ case I1PRO_HW_HIGHPOWERFAIL:
+ return "Failed to switch to high power mode";
+ case I1PRO_HW_EE_SIZE:
+ return "EEProm size is too small";
+ case I1PRO_HW_EE_SHORTREAD:
+ return "Read less bytes for EEProm read than expected";
+ case I1PRO_HW_EE_SHORTWRITE:
+ return "Wrote less bytes for EEProm write than expected";
+ case I1PRO_HW_ME_SHORTREAD:
+ return "Read less bytes for measurement read than expected";
+ case I1PRO_HW_ME_ODDREAD:
+ return "Read a number of bytes not a multiple of 256";
+ case I1PRO_HW_SW_SHORTREAD:
+ return "Read less bytes for Switch read than expected";
+ case I1PRO_HW_LED_SHORTWRITE:
+ return "Wrote fewer LED sequence bytes than expected";
+ case I1PRO_HW_UNEX_SPECPARMS:
+ return "Instrument has unexpected spectral parameters";
+ case I1PRO_HW_CALIBINFO:
+ return "Instrument calibration info is missing or corrupted";
+ case I1PRO_WL_TOOLOW:
+ return "Wavelength calibration reading is too low";
+ case I1PRO_WL_SHAPE:
+ return "Wavelength calibration reading shape is incorrect";
+ case I1PRO_WL_ERR2BIG:
+ return "Wavelength calibration correction is excessive";
+
+ case I1PRO_RD_DARKREADINCONS:
+ return "Dark calibration reading is inconsistent";
+ case I1PRO_RD_SENSORSATURATED:
+ return "Sensor is saturated";
+ case I1PRO_RD_DARKNOTVALID:
+ return "Dark reading is not valid (too light)";
+ case I1PRO_RD_NEEDS_CAL:
+ return "Mode needs calibration";
+ case I1PRO_RD_WHITEREADINCONS:
+ return "White calibration reading is inconsistent";
+ case I1PRO_RD_WHITEREFERROR:
+ return "White reference reading error";
+ case I1PRO_RD_LIGHTTOOLOW:
+ return "Light level is too low";
+ case I1PRO_RD_LIGHTTOOHIGH:
+ return "Light level is too high";
+ case I1PRO_RD_SHORTMEAS:
+ return "Reading is too short";
+ case I1PRO_RD_READINCONS:
+ return "Reading is inconsistent";
+ case I1PRO_RD_TRANSWHITERANGE:
+ return "Transmission white reference is out of range";
+ case I1PRO_RD_NOTENOUGHPATCHES:
+ return "Not enough patches";
+ case I1PRO_RD_TOOMANYPATCHES:
+ return "Too many patches";
+ case I1PRO_RD_NOTENOUGHSAMPLES:
+ return "Not enough samples per patch";
+ case I1PRO_RD_NOFLASHES:
+ return "No flashes recognized";
+ case I1PRO_RD_NOAMBB4FLASHES:
+ return "No ambient found before first flash";
+ case I1PRO_RD_NOREFR_FOUND:
+ return "No refresh rate detected or failed to measure it";
+
+ case I1PRO_INT_NO_COMS:
+ return "Communications hasn't been established";
+ case I1PRO_INT_EETOOBIG:
+ return "Read of EEProm is too big (> 65536)";
+ case I1PRO_INT_ODDREADBUF:
+ return "Measurement read buffer is not a multiple of reading size";
+ case I1PRO_INT_SMALLREADBUF:
+ return "Measurement read buffer is too small for initial measurement";
+ case I1PRO_INT_INTTOOBIG:
+ return "Integration time is too big";
+ case I1PRO_INT_INTTOOSMALL:
+ return "Integration time is too small";
+ case I1PRO_INT_ILLEGALMODE:
+ return "Illegal measurement mode selected";
+ case I1PRO_INT_ZEROMEASURES:
+ return "Number of measurements requested is zero";
+ case I1PRO_INT_WRONGPATCHES:
+ return "Number of patches to match is wrong";
+ case I1PRO_INT_MEASBUFFTOOSMALL:
+ return "Measurement exceeded read buffer";
+ case I1PRO_INT_NOTIMPLEMENTED:
+ return "Support not implemented";
+ case I1PRO_INT_NOTCALIBRATED:
+ return "Unexpectedely invalid calibration";
+ case I1PRO_INT_NOINTERPDARK:
+ return "Need interpolated dark and don't have it";
+ case I1PRO_INT_THREADFAILED:
+ return "Creation of thread failed";
+ case I1PRO_INT_BUTTONTIMEOUT:
+ return "Button status read timed out";
+ case I1PRO_INT_CIECONVFAIL:
+ return "Creating spectral to CIE converted failed";
+ case I1PRO_INT_PREP_LOG_DATA:
+ return "Error in preparing log data";
+ case I1PRO_INT_MALLOC:
+ return "Error in allocating memory";
+ case I1PRO_INT_CREATE_EEPROM_STORE:
+ return "Error in creating EEProm store";
+ case I1PRO_INT_SAVE_SUBT_MODE:
+ return "Can't save calibration if in subt mode";
+ case I1PRO_INT_NO_CAL_TO_SAVE:
+ return "No calibration data to save";
+ case I1PRO_INT_EEPROM_DATA_MISSING:
+ return "EEProm data is missing";
+ case I1PRO_INT_NEW_RSPL_FAILED:
+ return "Creating RSPL object faild";
+ case I1PRO_INT_CAL_SAVE:
+ return "Unable to save calibration to file";
+ case I1PRO_INT_CAL_RESTORE:
+ return "Unable to restore calibration from file";
+ case I1PRO_INT_CAL_TOUCH:
+ return "Unable to update calibration file modification time";
+ case I1PRO_INT_ADARK_INVALID:
+ return "Adaptive dark calibration is invalid";
+ case I1PRO_INT_NO_HIGH_GAIN:
+ return "Rev E mode doesn't have a high gain mode";
+ case I1PRO_INT_ASSERT:
+ return "Assert fail";
+
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract inst code */
+static inst_code
+i1pro_interp_code(i1pro *p, i1pro_code ec) {
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case I1PRO_OK:
+
+ return inst_ok;
+
+ case I1PRO_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case I1PRO_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+ case I1PRO_DATA_PARSE_ERROR:
+ return inst_protocol_error | ec;
+
+ case I1PRO_USER_ABORT:
+ return inst_user_abort;
+
+ case I1PRO_USER_TRIG:
+ return inst_user_trig;
+
+ case I1PRO_UNSUPPORTED:
+ return inst_unsupported | ec;
+
+ case I1PRO_CAL_SETUP:
+ return inst_cal_setup | ec;
+
+ case I1PRO_HW_HIGHPOWERFAIL:
+ case I1PRO_HW_EE_SHORTREAD:
+ case I1PRO_HW_ME_SHORTREAD:
+ case I1PRO_HW_ME_ODDREAD:
+ case I1PRO_HW_CALIBINFO:
+ return inst_hardware_fail | ec;
+
+ case I1PRO_RD_DARKREADINCONS:
+ case I1PRO_RD_SENSORSATURATED:
+ case I1PRO_RD_DARKNOTVALID:
+ case I1PRO_RD_WHITEREADINCONS:
+ case I1PRO_RD_WHITEREFERROR:
+ case I1PRO_RD_LIGHTTOOLOW:
+ case I1PRO_RD_LIGHTTOOHIGH:
+ case I1PRO_RD_SHORTMEAS:
+ case I1PRO_RD_READINCONS:
+ case I1PRO_RD_TRANSWHITERANGE:
+ case I1PRO_RD_NOTENOUGHPATCHES:
+ case I1PRO_RD_TOOMANYPATCHES:
+ case I1PRO_RD_NOTENOUGHSAMPLES:
+ case I1PRO_RD_NOFLASHES:
+ case I1PRO_RD_NOAMBB4FLASHES:
+ case I1PRO_RD_NOREFR_FOUND:
+ return inst_misread | ec;
+
+ case I1PRO_RD_NEEDS_CAL:
+ return inst_needs_cal | ec;
+
+ case I1PRO_INT_NO_COMS:
+ case I1PRO_INT_EETOOBIG:
+ case I1PRO_INT_ODDREADBUF:
+ case I1PRO_INT_SMALLREADBUF:
+ case I1PRO_INT_INTTOOBIG:
+ case I1PRO_INT_INTTOOSMALL:
+ case I1PRO_INT_ILLEGALMODE:
+ case I1PRO_INT_ZEROMEASURES:
+ case I1PRO_INT_MEASBUFFTOOSMALL:
+ case I1PRO_INT_NOTIMPLEMENTED:
+ case I1PRO_INT_NOTCALIBRATED:
+ case I1PRO_INT_NOINTERPDARK:
+ case I1PRO_INT_THREADFAILED:
+ case I1PRO_INT_BUTTONTIMEOUT:
+ case I1PRO_INT_CIECONVFAIL:
+ case I1PRO_INT_PREP_LOG_DATA:
+ case I1PRO_INT_MALLOC:
+ case I1PRO_INT_CREATE_EEPROM_STORE:
+ case I1PRO_INT_SAVE_SUBT_MODE:
+ case I1PRO_INT_NO_CAL_TO_SAVE:
+ case I1PRO_INT_EEPROM_DATA_MISSING:
+ case I1PRO_INT_NEW_RSPL_FAILED:
+ case I1PRO_INT_CAL_SAVE:
+ case I1PRO_INT_CAL_RESTORE:
+ case I1PRO_INT_CAL_TOUCH:
+ case I1PRO_INT_ADARK_INVALID:
+ case I1PRO_INT_NO_HIGH_GAIN:
+ case I1PRO_INT_ASSERT:
+ return inst_internal_error | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Return the instrument capabilities */
+void i1pro_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ i1pro *p = (i1pro *)pp;
+
+ if (pcap1 != NULL)
+ *pcap1 = p->cap;
+ if (pcap2 != NULL)
+ *pcap2 = p->cap2;
+ if (pcap3 != NULL)
+ *pcap3 = p->cap3;
+}
+
+/* Return the corresponding i1pro measurement mode, */
+/* or i1p_no_modes if invalid */
+static i1p_mode i1pro_convert_mode(i1pro *p, inst_mode m) {
+ i1p_mode mmode = 0; /* Instrument measurement mode */
+
+ /* Simple test */
+ if (m & ~p->cap) {
+ return i1p_no_modes;
+ }
+
+ if (IMODETST(m, inst_mode_ref_spot)) {
+ mmode = i1p_refl_spot;
+ } else if (IMODETST(m, inst_mode_ref_strip)) {
+ mmode = i1p_refl_scan;
+ } else if (IMODETST(m, inst_mode_trans_spot)) {
+ mmode = i1p_trans_spot;
+ } else if (IMODETST(m, inst_mode_trans_strip)) {
+ mmode = i1p_trans_scan;
+ } else if (IMODETST(m, inst_mode_emis_spot)
+ || IMODETST(m, inst_mode_emis_tele)) {
+ if (IMODETST(m, inst_mode_emis_nonadaptive))
+ mmode = i1p_emiss_spot_na;
+ else
+ mmode = i1p_emiss_spot;
+ } else if (IMODETST(m, inst_mode_emis_strip)) {
+ mmode = i1p_emiss_scan;
+ } else if (IMODETST(m, inst_mode_emis_ambient)
+ && (p->cap & inst_mode_emis_ambient)) {
+ mmode = i1p_amb_spot;
+ } else if (IMODETST(m, inst_mode_emis_ambient_flash)
+ && (p->cap & inst_mode_emis_ambient_flash)) {
+ mmode = i1p_amb_flash;
+ } else {
+ return i1p_no_modes;
+ }
+
+ return mmode;
+}
+
+/* Check device measurement mode */
+inst_code i1pro_check_mode(inst *pp, inst_mode m) {
+ i1pro *p = (i1pro *)pp;
+ i1p_mode mmode = 0; /* Instrument measurement mode */
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (i1pro_convert_mode(p, m) == i1p_no_modes)
+ return inst_unsupported;
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code i1pro_set_mode(inst *pp, inst_mode m) {
+ i1pro *p = (i1pro *)pp;
+ i1p_mode mmode; /* Instrument measurement mode */
+ inst_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if ((mmode = i1pro_convert_mode(p, m)) == i1p_no_modes)
+ return inst_unsupported;
+
+ if ((rv = i1pro_interp_code(p, i1pro_imp_set_mode(p, mmode, m))) != inst_ok)
+ return rv;
+
+ i1pro_determine_capabilities(p);
+
+ return inst_ok;
+}
+
+/*
+ * set or reset an optional mode
+ *
+ * Some options talk to the instrument, and these will
+ * error if it hasn't been initialised.
+ */
+static inst_code
+i1pro_get_set_opt(inst *pp, inst_opt_type m, ...)
+{
+ i1pro *p = (i1pro *)pp;
+
+ if (m == inst_opt_noinitcalib) {
+ va_list args;
+ int losecs = 0;
+
+ va_start(args, m);
+ losecs = va_arg(args, int);
+ va_end(args);
+
+ i1pro_set_noinitcalib(p, 1, losecs);
+ return inst_ok;
+
+ } else if (m == inst_opt_initcalib) {
+ i1pro_set_noinitcalib(p, 0, 0);
+ return inst_ok;
+
+ /* Record the trigger mode */
+ } else if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user
+ || m == inst_opt_trig_user_switch) {
+ i1pro_set_trig(p, m);
+ return inst_ok;
+ }
+
+ if (m == inst_opt_scan_toll) {
+ va_list args;
+ double toll_ratio = 1.0;
+
+ va_start(args, m);
+ toll_ratio = va_arg(args, double);
+ va_end(args);
+ return i1pro_interp_code(p, i1pro_set_scan_toll(p, toll_ratio));
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Not sure if this can be set before init */
+ if (m == inst_opt_highres) {
+ return i1pro_interp_code(p, i1pro_set_highres(p));
+ } else if (m == inst_opt_stdres) {
+ return i1pro_interp_code(p, i1pro_set_stdres(p));
+ }
+
+ /* Return the filter */
+ if (m == inst_stat_get_filter) {
+ i1proimp *imp = (i1proimp *)p->m;
+ inst_opt_filter *filt;
+ va_list args;
+
+ va_start(args, m);
+ filt = va_arg(args, inst_opt_filter *);
+ va_end(args);
+
+ *filt = inst_opt_filter_none;
+
+ if (imp->physfilt == 0x82)
+ *filt = inst_opt_filter_UVCut;
+
+ return inst_ok;
+ }
+
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
+}
+
+/* Destroy ourselves */
+static void
+i1pro_del(inst *pp) {
+ i1pro *p = (i1pro *)pp;
+
+ del_i1proimp(p);
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ free(p);
+}
+
+/* Constructor */
+extern i1pro *new_i1pro(icoms *icom, instType itype) {
+ i1pro *p;
+ int rv;
+ if ((p = (i1pro *)calloc(sizeof(i1pro),1)) == NULL) {
+ a1loge(icom->log, 1, "new_i1pro: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ /* Inst methods */
+ p->init_coms = i1pro_init_coms;
+ p->init_inst = i1pro_init_inst;
+ p->capabilities = i1pro_capabilities;
+ p->get_serial_no = i1pro_get_serial_no;
+ p->check_mode = i1pro_check_mode;
+ p->set_mode = i1pro_set_mode;
+ p->get_set_opt = i1pro_get_set_opt;
+ p->read_strip = i1pro_read_strip;
+ p->read_sample = i1pro_read_sample;
+ p->read_refrate = i1pro_read_refrate;
+ p->get_n_a_cals = i1pro_get_n_a_cals;
+ p->calibrate = i1pro_calibrate;
+ p->interp_error = i1pro_interp_error;
+ p->del = i1pro_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ i1pro_determine_capabilities(p);
+
+ if ((rv = add_i1proimp(p)) != I1PRO_OK) {
+ free(p);
+ a1loge(icom->log, 1, "new_i1pro: error %d creating i1proimp\n",rv);
+ return NULL;
+ }
+
+ return p;
+}
+
diff --git a/spectro/i1pro.h b/spectro/i1pro.h
new file mode 100644
index 0000000..4366e4f
--- /dev/null
+++ b/spectro/i1pro.h
@@ -0,0 +1,56 @@
+#ifndef I1PRO_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag i1Pro related defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/11/2006
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* I1PRO communication object */
+struct _i1pro {
+ INST_OBJ_BASE
+
+ int dtype; /* Device type: 0 = ?? */
+
+ /* *** i1pro private data **** */
+ inst_mode cap; /* Instrument mode capability */
+ inst2_capability cap2; /* Instrument capability 2 */
+ inst3_capability cap3; /* Instrument capability 3 */
+
+ void *m; /* Implementation - i1proimp type */
+}; typedef struct _i1pro i1pro;
+
+/* Constructor */
+extern i1pro *new_i1pro(icoms *icom, instType itype);
+
+#define I1PRO_H
+#endif /* I1PRO_H */
diff --git a/spectro/i1pro_imp.c b/spectro/i1pro_imp.c
new file mode 100644
index 0000000..2211bd4
--- /dev/null
+++ b/spectro/i1pro_imp.c
@@ -0,0 +1,12093 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag i1Pro implementation functions
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/11/2006
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+/* TTBD:
+
+ Some things probably aren't quite correct:
+ The way the sensor saturation and optimal target is
+ computed probably doesn't account for the dark level
+ correctly, since the targets are in sensor value,
+ but the comparison is done after subtracting black ??
+ See the Munki implementation for an approach to fix this ??
+
+ It should be possible to add a refresh-display calibration
+ routine based on an emissive scan + the auto-correlation
+ (see i1d3.c). Whether this will noticably improve repeatibility
+ remains to be seen.
+*/
+
+/*
+ Notes:
+
+ Naming of spectral values:
+
+ sensor - the 16 bit values from the sensor including any dummy/shielded values
+ raw - the floating point values of the spectral section
+ absraw - raw after scaling for integration time and gain settings.
+
+ The Rev D seems to die if it is ever given a GET_STATUS. This is why
+ the WinUSB driver can't be used with it.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#if defined(UNIX)
+# include <utime.h>
+#else
+# include <sys/utime.h>
+#endif
+#include <sys/stat.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "rspl.h"
+#else /* SALONEINSTLIB */
+#include <fcntl.h>
+#include "sa_config.h"
+#include "numsup.h"
+#include "rspl1.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "sort.h"
+
+/* Configuration */
+#define ENABLE_2 /* [Def] Enable i1pro2/Rev E driver code, else treat i1pro2 as i1pro */
+#undef USE_HIGH_GAIN_MODE /* [Und] Make use of high gain mode in Rev A-D mode */
+#define USE_THREAD /* Need to use thread, or there are 1.5 second internal */
+ /* instrument delays ! */
+#undef WAIT_FOR_DELAY_TRIGGER /* [Und] Hack to diagnose threading problems */
+#undef ENABLE_WRITE /* [Und] Enable writing of calibration and log data to the EEProm */
+#define ENABLE_NONVCAL /* [Def] Enable saving calibration state between program runs in a file */
+#define ENABLE_NONLINCOR /* [Def] Enable non-linear correction */
+#define WLCALTOUT (24 * 60 * 60) /* [24 Hrs] Wavelength calibration timeout in seconds */
+#define DCALTOUT ( 60 * 60) /* [60 Minuites] Dark Calibration timeout in seconds */
+#define DCALTOUT2 ( 1 * 60 * 60) /* [1 Hr] i1pro2 Dark Calibration timeout in seconds */
+#define WCALTOUT ( 1 * 60 * 60) /* [1 Hr] White Calibration timeout in seconds */
+#define MAXSCANTIME 15.0 /* [15] Maximum scan time in seconds */
+#define SW_THREAD_TIMEOUT (10 * 60.0) /* [10 Min] Switch read thread timeout */
+
+#define SINGLE_READ /* [Def] Use a single USB read for scan to eliminate latency issues. */
+#define HIGH_RES /* [Def] Enable high resolution spectral mode code. Dissable */
+ /* to break dependency on rspl library. */
+
+/* Debug [Und] */
+#undef DEBUG /* Turn on debug printfs */
+#undef PLOT_DEBUG /* Use plot to show readings & processing */
+#undef PLOT_REFRESH /* Plot refresh rate measurement info */
+#undef DUMP_SCANV /* Dump scan readings to a file "i1pdump.txt" */
+#undef DUMP_DARKM /* Append raw dark readings to file "i1pddump.txt" */
+#undef APPEND_MEAN_EMMIS_VAL /* Append averaged uncalibrated reading to file "i1pdump.txt" */
+#undef TEST_DARK_INTERP /* Test out the dark interpolation (need DEBUG for plot) */
+#undef PATREC_DEBUG /* Print & Plot patch/flash recognition information */
+#undef PATREC_ALLBANDS /* Plot all bands of scan */
+#undef IGNORE_WHITE_INCONS /* Ignore define reference reading inconsistency */
+#undef HIGH_RES_DEBUG
+#undef HIGH_RES_PLOT
+#undef PLOT_BLACK_SUBTRACT /* Plot temperature corrected black subtraction */
+#undef FAKE_AMBIENT /* Fake the ambient mode for a Rev A */
+
+#define MATCH_SPOT_OMD /* [Def] Match Original Manufacturers Driver. Reduce */
+ /* integration time and lamp turn on time */
+
+#define DISP_INTT 2.0 /* Seconds per reading in display spot mode */
+ /* More improves repeatability in dark colors, but limits */
+ /* the maximum brightness level befor saturation. */
+ /* A value of 2.0 seconds has a limit of about 110 cd/m^2 */
+#define DISP_INTT2 0.8 /* High brightness display spot mode seconds per reading, */
+ /* Should be good up to 275 cd/m^2 */
+#define DISP_INTT3 0.3 /* High brightness display spot mode seconds per reading, */
+ /* Should be good up to 700 cd/m^2 */
+
+#define ADARKINT_MAX 2.0 /* Max cal time for adaptive dark cal */
+#define ADARKINT_MAX2 4.0 /* Max cal time for adaptive dark cal Rev E or no high gain */
+
+#define EMIS_SCALE_FACTOR 1.0 /* Emission mode scale factor */
+#define AMB_SCALE_FACTOR (1.0/3.141592654) /* Ambient mode scale factor - convert */
+ /* from Lux to Lux/PI */
+ /* These factors get the same behaviour as the GMB drivers. */
+
+#define NSEN_MAX 140 /* Maximum nsen value we can cope with */
+
+/* High res mode settings */
+#define HIGHRES_SHORT 350
+#define HIGHRES_LONG 740
+#define HIGHRES_WIDTH (10.0/3.0) /* (The 3.3333 spacing and lanczos2 seems a good combination) */
+#define HIGHRES_REF_MIN 375.0 /* Too much stray light below this in reflective mode */
+ /* (i1pro2 could go lower with different correction) */
+
+#include "i1pro.h"
+#include "i1pro_imp.h"
+
+/* - - - - - - - - - - - - - - - - - - */
+#define LAMP_OFF_TIME 1500 /* msec to make sure lamp is dark for dark measurement */
+#define PATCH_CONS_THR 0.1 /* Dark measurement consistency threshold */
+#define TRIG_DELAY 10 /* Measure trigger delay to allow pending read, msec */
+
+/* - - - - - - - - - - - - - - - - - - */
+
+#if defined(DEBUG) || defined(PLOT_DEBUG) || defined(PATREC_DEBUG)
+# include <plot.h>
+#endif
+
+
+#if defined(DEBUG) || defined(PLOT_DEBUG) || defined(HIGH_RES_PLOT) || defined(PATREC_DEBUG)
+static int disdebplot = 0;
+
+#define DISDPLOT disdebplot = 1;
+#define ENDPLOT disdebplot = 0;
+
+#else
+
+#define DISDPLOT
+#define ENDPLOT
+
+#endif /* DEBUG */
+
+#if defined(DEBUG) || defined(PLOT_DEBUG) || defined(PATREC_DEBUG)
+/* ============================================================ */
+/* Debugging support */
+
+/* Plot a CCD spectra */
+void plot_raw(double *data) {
+ int i;
+ double xx[NSEN_MAX];
+ double yy[NSEN_MAX];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < 128; i++) {
+ xx[i] = (double)i;
+ yy[i] = data[i];
+ }
+ do_plot(xx, yy, NULL, NULL, 128);
+}
+
+/* Plot two CCD spectra */
+void plot_raw2(double *data1, double *data2) {
+ int i;
+ double xx[128];
+ double y1[128];
+ double y2[128];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < 128; i++) {
+ xx[i] = (double)i;
+ y1[i] = data1[i];
+ y2[i] = data2[i];
+ }
+ do_plot(xx, y1, y2, NULL, 128);
+}
+
+/* Plot a converted spectra */
+void plot_wav(i1proimp *m, int hires, double *data) {
+ int i;
+ double xx[128];
+ double yy[128];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < m->nwav[hires]; i++) {
+ xx[i] = XSPECT_WL(m->wl_short[hires], m->wl_long[hires], m->nwav[hires], i);
+ yy[i] = data[i];
+ }
+ do_plot(xx, yy, NULL, NULL, m->nwav[hires]);
+}
+
+/* Plot two converted spectra for the current res. mode */
+void plot_wav_2(i1proimp *m, int hires, double *data1, double *data2) {
+ int i;
+ double xx[128];
+ double y1[128];
+ double y2[128];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < m->nwav[hires]; i++) {
+ xx[i] = XSPECT_WL(m->wl_short[hires], m->wl_long[hires], m->nwav[hires], i);
+ y1[i] = data1[i];
+ y2[i] = data2[i];
+ }
+ do_plot(xx, y1, y2, NULL, m->nwav[hires]);
+}
+
+#endif /* PLOT_DEBUG */
+
+/* ============================================================ */
+
+/* Implementation struct */
+
+/* Add an implementation structure */
+i1pro_code add_i1proimp(i1pro *p) {
+ i1proimp *m;
+
+ if ((m = (i1proimp *)calloc(1, sizeof(i1proimp))) == NULL) {
+ a1logd(p->log,1,"add_i1proimp malloc %ld bytes failed (1)\n",sizeof(i1proimp));
+ return I1PRO_INT_MALLOC;
+ }
+ m->p = p;
+
+ /* EEProm data store */
+ if ((m->data = new_i1data(m)) == NULL)
+ return I1PRO_INT_CREATE_EEPROM_STORE;
+
+ m->lo_secs = 2000000000; /* A very long time */
+ m->msec = msec_time();
+
+ p->m = (void *)m;
+ return I1PRO_OK;
+}
+
+/* Shutdown instrument, and then destroy */
+/* implementation structure */
+void del_i1proimp(i1pro *p) {
+
+ a1logd(p->log,5,"i1pro_del called\n");
+
+#ifdef ENABLE_NONVCAL
+ /* Touch it so that we know when the instrument was last open */
+ i1pro_touch_calibration(p);
+#endif /* ENABLE_NONVCAL */
+
+ if (p->m != NULL) {
+ int i, j;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s;
+ i1pro_code ev;
+
+ if (p->itype != instI1Pro2 && (ev = i1pro_update_log(p)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_update_log: Updating the cal and log parameters to"
+ " EEProm failed failed\n");
+ }
+
+ /* i1pro_terminate_switch() seems to fail on a rev A & Rev C ?? */
+ if (m->th != NULL) { /* Terminate switch monitor thread */
+ m->th_term = 1; /* Tell thread to exit on error */
+ i1pro_terminate_switch(p);
+
+ for (i = 0; m->th_termed == 0 && i < 5; i++)
+ msec_sleep(50); /* Wait for thread to terminate */
+ if (i >= 5) {
+ a1logd(p->log,5,"i1pro switch thread termination failed\n");
+ }
+ m->th->del(m->th);
+ usb_uninit_cancel(&m->cancelt); /* Don't need cancel token now */
+ }
+ a1logd(p->log,5,"i1pro switch thread terminated\n");
+
+ /* Free any per mode data */
+ for (i = 0; i < i1p_no_modes; i++) {
+ s = &m->ms[i];
+
+ free_dvector(s->dark_data, -1, m->nraw-1);
+ free_dvector(s->dark_data2, -1, m->nraw-1);
+ free_dvector(s->dark_data3, -1, m->nraw-1);
+ free_dvector(s->white_data, -1, m->nraw-1);
+ free_dmatrix(s->idark_data, 0, 3, -1, m->nraw-1);
+
+ free_dvector(s->cal_factor[0], 0, m->nwav[0]-1);
+ free_dvector(s->cal_factor[1], 0, m->nwav[1]-1);
+ }
+
+ /* Free EEProm key data */
+ if (m->data != NULL)
+ m->data->del(m->data);
+
+ /* Free all Rev E and high res raw2wav filters */
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 2; j++) {
+ if (m->mtx_c[i][j].index != NULL)
+ free(m->mtx_c[i][j].index);
+ if (m->mtx_c[i][j].nocoef != NULL)
+ free(m->mtx_c[i][j].nocoef);
+ if (m->mtx_c[i][j].coef != NULL)
+ free(m->mtx_c[i][j].coef);
+ }
+ }
+
+ /* Free RevE straylight arrays */
+ for (i = 0; i < 2; i++) {
+ if (m->straylight[i] != NULL)
+ free_dmatrix(m->straylight[i], 0, m->nwav[i]-1, 0, m->nwav[i]-1);
+ }
+
+ /* RevA-D high res. recal support */
+ if (m->raw2wav != NULL)
+ m->raw2wav->del(m->raw2wav);
+
+ free(m);
+ p->m = NULL;
+ }
+}
+
+/* ============================================================ */
+/* High level functions */
+
+/* Initialise our software state from the hardware */
+i1pro_code i1pro_imp_init(i1pro *p) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+ unsigned char *eeprom; /* EEProm contents, i1pro = half, i1pro2 = full */
+ int len = 8192;
+
+ a1logd(p->log,5,"i1pro_init:\n");
+
+ /* Revert to i1pro if i1pro2 driver is not enabled */
+ if (p->itype == instI1Pro2
+#ifdef ENABLE_2
+ && getenv("ARGYLL_DISABLE_I1PRO2_DRIVER") != NULL /* Disabled by environment */
+#endif
+ ) {
+ p->itype = instI1Pro;
+ }
+
+ if (p->itype != instI1Monitor
+ && p->itype != instI1Pro
+ && p->itype != instI1Pro2)
+ return I1PRO_UNKNOWN_MODEL;
+
+ m->trig = inst_opt_trig_user;
+ m->scan_toll_ratio = 1.0;
+
+ /* Take conservative approach to when the light was last on. */
+ /* Assume it might have been on right before init was called again. */
+ m->slamponoff = msec_time();
+ m->llampoffon = msec_time();
+ m->llamponoff = msec_time();
+
+ if ((ev = i1pro_reset(p, 0x1f)) != I1PRO_OK)
+ return ev;
+
+ usb_init_cancel(&m->cancelt); /* Init cancel token */
+
+#ifdef USE_THREAD
+ /* Setup the switch monitoring thread */
+ if ((m->th = new_athread(i1pro_switch_thread, (void *)p)) == NULL)
+ return I1PRO_INT_THREADFAILED;
+#endif
+
+ /* Get the current misc. status, fwrev etc */
+ if ((ev = i1pro_getmisc(p, &m->fwrev, NULL, &m->maxpve, NULL, &m->powmode)) != I1PRO_OK)
+ return ev;
+ a1logd(p->log,2,"Firmware rev = %d, max +ve value = 0x%x\n",m->fwrev, m->maxpve);
+
+ if (p->itype == instI1Pro2 && m->fwrev < 600) { /* Hmm */
+ a1logd(p->log,2, "Strange, firmware isn't up to i1pro2 but has extra pipe..revert to i1pro driver\n",m->fwrev);
+ p->itype = instI1Pro;
+ }
+
+ /* Get the EEProm size */
+ m->eesize = 8192; /* Rev A..D */
+ if (p->itype == instI1Pro2) {
+#ifdef NEVER
+// ~~99 Hmm. makes it worse. Why ???
+// /* Make sure LED sequence is finished, because it interferes with EEProm read! */
+// if ((ev = i1pro2_indLEDoff(p)) != I1PRO_OK)
+// return ev;
+#endif
+
+ if ((ev = i1pro2_geteesize(p, &m->eesize)) != I1PRO_OK) {
+ return ev;
+ }
+
+ }
+
+ if (m->eesize < 8192) {
+ a1logd(p->log,2,"Strange, EEProm size is < 8192!\n",m->fwrev);
+ return I1PRO_HW_EE_SIZE;
+ }
+
+ if ((eeprom = (unsigned char *)malloc(m->eesize)) == NULL) {
+ a1logd(p->log,1,"Malloc %d bytes for eeprom failed\n",m->eesize);
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* Read the EEProm */
+ if ((ev = i1pro_readEEProm(p, eeprom, 0, m->eesize)) != I1PRO_OK) {
+ free(eeprom);
+ return ev;
+ }
+
+ if (p->itype == instI1Pro2) {
+ /* Get the Chip ID (This doesn't work until after reading the EEProm !) */
+ if ((ev = i1pro2_getchipid(p, m->chipid)) != I1PRO_OK) {
+ free(eeprom);
+ return ev;
+ }
+ }
+
+ /* Parse the i1pro data */
+ if ((ev = m->data->parse_eeprom(m->data, eeprom, m->eesize, 0)) != I1PRO_OK) {
+ free(eeprom);
+ return ev;
+ }
+
+ /* Parse the i1pro2 extra data */
+ if (p->itype == instI1Pro2) {
+ if ((ev = m->data->parse_eeprom(m->data, eeprom, m->eesize, 1)) != I1PRO_OK) {
+ free(eeprom);
+ return ev;
+ }
+ }
+ free(eeprom); eeprom = NULL;
+
+ /* Setup various calibration parameters from the EEprom */
+ {
+ int *ip, i, xcount;
+ unsigned int count;
+ double *dp;
+
+ /* Information about the instrument */
+
+ if ((ip = m->data->get_ints(m->data, &count, key_serno)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->serno = ip[0];
+ a1logd(p->log,2,"Serial number = %d\n",m->serno);
+ sprintf(m->sserno,"%ud",m->serno);
+
+ if ((ip = m->data->get_ints(m->data, &count, key_dom)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->dom = ip[0];
+ a1logd(p->log,2, "Date of manufactur = %d-%d-%d\n",
+ m->dom/1000000, (m->dom/10000) % 100, m->dom % 10000);
+
+ if ((ip = m->data->get_ints(m->data, &count, key_cpldrev)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->cpldrev = ip[0];
+ a1logd(p->log,2,"CPLD rev = %d\n",m->cpldrev);
+
+ if ((ip = m->data->get_ints(m->data, &count, key_capabilities)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->capabilities = ip[0];
+ if (m->capabilities & 0x6000) /* Has ambient */
+ m->capabilities2 |= I1PRO_CAP2_AMBIENT; /* Mimic in capabilities2 */
+ a1logd(p->log,2,"Capabilities flag = 0x%x\n",m->capabilities);
+ if (m->capabilities & 0x6000)
+ a1logd(p->log,2," Can read ambient\n");
+
+ if ((ip = m->data->get_ints(m->data, &count, key_physfilt)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->physfilt = ip[0];
+ if (m->physfilt == 0x82)
+ m->capabilities2 |= I1PRO_CAP2_UV_FILT; /* Mimic in cap 2 */
+ a1logd(p->log,2,"Physical filter flag = 0x%x\n",m->physfilt);
+ if (m->physfilt == 0x80)
+ a1logd(p->log,2," No filter fitted\n");
+ else if (m->physfilt == 0x81)
+ a1logd(p->log,2," Emission only ??\n");
+ else if (m->physfilt == 0x82)
+ a1logd(p->log,2," Is fitted with Ultra Violet Filter\n");
+
+ /* Underlying calibration information */
+
+ m->nsen = 128;
+ m->nraw = 128;
+ if (p->itype == instI1Pro2) {
+ int clkusec, subdiv, xraw, nraw;
+ if ((ev = i1pro2_getmeaschar(p, &clkusec, &xraw, &nraw, &subdiv)) != I1PRO_OK)
+ return ev;
+ m->intclkp2 = clkusec * 1e-6; /* Rev E integration clock period, ie. 36 usec */
+ m->subclkdiv2 = subdiv; /* Rev E sub clock divider, ie. 136 */
+
+ m->nsen = nraw + xraw;
+ if (clkusec != 36 || xraw != 6 || nraw != 128 || subdiv != 136)
+ return I1PRO_HW_UNEX_SPECPARMS;
+
+ if (m->nsen > NSEN_MAX) /* Static allocation assumed */
+ return I1PRO_HW_UNEX_SPECPARMS;
+ }
+ if (m->data->get_ints(m->data, &m->nwav[0], key_mtx_index) == 0)
+ return I1PRO_HW_CALIBINFO;
+ if (m->nwav[0] != 36)
+ return I1PRO_HW_CALIBINFO;
+ m->wl_short[0] = 380.0; /* Normal res. range */
+ m->wl_long[0] = 730.0;
+
+ /* Fill high res in too */
+ m->wl_short[1] = HIGHRES_SHORT;
+ m->wl_long[1] = HIGHRES_LONG;
+ m->nwav[1] = (int)((m->wl_long[1]-m->wl_short[1])/HIGHRES_WIDTH + 0.5) + 1;
+
+ if ((dp = m->data->get_doubles(m->data, &count, key_hg_factor)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->highgain = dp[0];
+ a1logd(p->log,2,"High gain = %.10f\n",m->highgain);
+
+ if ((m->lin0 = m->data->get_doubles(m->data, &m->nlin0, key_ng_lin)) == NULL
+ || m->nlin0 < 1)
+ return I1PRO_HW_CALIBINFO;
+
+ if ((m->lin1 = m->data->get_doubles(m->data, &m->nlin1, key_hg_lin)) == NULL
+ || m->nlin1 < 1)
+ return I1PRO_HW_CALIBINFO;
+
+ if (p->log->debug >= 2) {
+ char oline[200] = { '\000' }, *bp = oline;
+
+ bp += sprintf(bp,"Normal non-lin =");
+ for(i = 0; i < m->nlin0; i++)
+ bp += sprintf(bp," %1.10f",m->lin0[i]);
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,2,oline);
+
+ bp = oline;
+ bp += sprintf(bp,"High Gain non-lin =");
+ for(i = 0; i < m->nlin1; i++)
+ bp += sprintf(bp," %1.10f",m->lin1[i]);
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,2,oline);
+ }
+
+ if ((dp = m->data->get_doubles(m->data, &count, key_min_int_time)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->min_int_time = dp[0];
+
+ /* And then override it */
+ if (p->itype == instI1Pro2) {
+ m->min_int_time = m->subclkdiv2 * m->intclkp2; /* 0.004896 */
+ } else {
+ if (m->fwrev >= 301)
+ m->min_int_time = 0.004716;
+ else
+ m->min_int_time = 0.00884; /* == 1 sub clock */
+ }
+
+ if ((dp = m->data->get_doubles(m->data, &count, key_max_int_time)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->max_int_time = dp[0];
+
+
+ if ((m->mtx_o.index = m->data->get_ints(m->data, &count, key_mtx_index)) == NULL
+ || count != m->nwav[0])
+ return I1PRO_HW_CALIBINFO;
+
+ if ((m->mtx_o.nocoef = m->data->get_ints(m->data, &count, key_mtx_nocoef)) == NULL
+ || count != m->nwav[0])
+ return I1PRO_HW_CALIBINFO;
+
+ for (xcount = i = 0; i < m->nwav[0]; i++) /* Count number expected in matrix coeffs */
+ xcount += m->mtx_o.nocoef[i];
+
+ if ((m->mtx_o.coef = m->data->get_doubles(m->data, &count, key_mtx_coef)) == NULL
+ || count != xcount)
+ return I1PRO_HW_CALIBINFO;
+
+ if ((m->white_ref[0] = m->data->get_doubles(m->data, &count, key_white_ref)) == NULL
+ || count != m->nwav[0]) {
+ if (p->itype != instI1Monitor)
+ return I1PRO_HW_CALIBINFO;
+ m->white_ref[0] = NULL;
+ }
+
+ if ((m->emis_coef[0] = m->data->get_doubles(m->data, &count, key_emis_coef)) == NULL
+ || count != m->nwav[0])
+ return I1PRO_HW_CALIBINFO;
+
+ if ((m->amb_coef[0] = m->data->get_doubles(m->data, &count, key_amb_coef)) == NULL
+ || count != m->nwav[0]) {
+ if (p->itype != instI1Monitor
+ && m->capabilities & 0x6000) /* Expect ambient calibration */
+ return I1PRO_HW_CALIBINFO;
+ m->amb_coef[0] = NULL;
+ }
+ /* Default to original EEProm raw to wav filters values*/
+ m->mtx[0][0] = m->mtx_o; /* Std res reflective */
+ m->mtx[0][1] = m->mtx_o; /* Std res emissive */
+
+ if ((ip = m->data->get_ints(m->data, &count, key_sens_target)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->sens_target = ip[0];
+
+ if ((ip = m->data->get_ints(m->data, &count, key_sens_dark)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->sens_dark = ip[0];
+
+ if ((ip = m->data->get_ints(m->data, &count, key_ng_sens_sat)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->sens_sat0 = ip[0];
+
+ if ((ip = m->data->get_ints(m->data, &count, key_hg_sens_sat)) == NULL || count < 1)
+ return I1PRO_HW_CALIBINFO;
+ m->sens_sat1 = ip[0];
+
+ a1logd(p->log,2,"sens_target %d, sens_dark %d, sens_sat0 %d, sens_sat1 %d\n",
+ m->sens_target, m->sens_dark, m->sens_sat0, m->sens_sat1);
+
+ /* Then read the log data. Don't fatal error if there is a problem with this. */
+ for (;;) {
+
+ /* Total Measure (Emis/Remis/Ambient/Trans/Cal) count */
+ if ((ip = m->data->get_ints(m->data, &count, key_meascount)) == NULL || count < 1)
+ break;
+ m->meascount = ip[0];
+
+ /* Remspotcal last calibration date */
+ if ((ip = m->data->get_ints(m->data, &count, key_caldate)) == NULL || count < 1)
+ break;
+ m->caldate = ip[0];
+
+ /* Remission spot measure count at last Remspotcal. */
+ if ((ip = m->data->get_ints(m->data, &count, key_calcount)) == NULL || count < 1)
+ break;
+ m->calcount = ip[0];
+
+ /* Last remision spot reading integration time */
+ if ((dp = m->data->get_doubles(m->data, &count, key_rpinttime)) == NULL || count < 1)
+ break;
+ m->rpinttime = dp[0];
+
+ /* Remission spot measure count */
+ if ((ip = m->data->get_ints(m->data, &count, key_rpcount)) == NULL || count < 1)
+ break;
+ m->rpcount = ip[0];
+
+ /* Remission scan measure count (??) */
+ if ((ip = m->data->get_ints(m->data, &count, key_acount)) == NULL || count < 1)
+ break;
+ m->acount = ip[0];
+
+ /* Total lamp usage time in seconds (??) */
+ if ((dp = m->data->get_doubles(m->data, &count, key_lampage)) == NULL || count < 1)
+ break;
+ m->lampage = dp[0];
+ a1logd(p->log,3,"Read log information OK\n");
+
+ break;
+ }
+ }
+
+ /* Read Rev E specific keys */
+ if (p->itype == instI1Pro2) {
+ int i, j;
+ double *dp;
+ int *sip;
+ unsigned int count;
+ int *ip;
+
+ /* Capability bits */
+ if ((ip = m->data->get_ints(m->data, &count, key2_capabilities)) == NULL
+ || count != 1)
+ return I1PRO_HW_CALIBINFO;
+ m->capabilities2 = *ip;
+ if (p->log->debug >= 2) {
+ a1logd(p->log,2,"Capabilities2 flag = 0x%x\n",m->capabilities2);
+ if (m->capabilities2 & I1PRO_CAP2_AMBIENT)
+ a1logd(p->log,2," Can read ambient\n");
+ if (m->capabilities2 & I1PRO_CAP2_WL_LED)
+ a1logd(p->log,2," Has Wavelength Calibration LED\n");
+ if (m->capabilities2 & I1PRO_CAP2_UV_LED)
+ a1logd(p->log,2," Has Ultra Violet LED\n");
+ if (m->capabilities2 & I1PRO_CAP2_ZEB_RUL)
+ a1logd(p->log,2," Has Zebra Ruler sensor\n");
+ if (m->capabilities2 & I1PRO_CAP2_IND_LED)
+ a1logd(p->log,2," Has user indicator LEDs\n");
+ if (m->capabilities2 & I1PRO_CAP2_UV_FILT)
+ a1logd(p->log,2," Is fitted with Ultra Violet Filter\n");
+ }
+
+ if (m->capabilities2 & I1PRO_CAP2_WL_LED) {
+ /* wavelength LED calibration integration time (0.56660) */
+ if ((dp = m->data->get_doubles(m->data, &count, key2_wlcal_intt)) == NULL
+ || count != 1)
+ return I1PRO_HW_CALIBINFO;
+ m->wl_cal_inttime = *dp;
+
+ /* Wavelength calibration minimum level */
+ if ((ip = m->data->get_ints(m->data, &count, key2_wlcal_minlev)) == NULL
+ || count != 1)
+ return I1PRO_HW_CALIBINFO;
+ /* Normalize it to 1.0 seconds (ie. 500/0.56660) */
+ m->wl_cal_min_level = (double)(*ip) / m->wl_cal_inttime;
+
+ /* wavelength LED measurement expected FWHM in nm */
+ if ((dp = m->data->get_doubles(m->data, &count, key2_wlcal_fwhm)) == NULL
+ || count != 1)
+ return I1PRO_HW_CALIBINFO;
+ m->wl_cal_fwhm = *dp;
+
+ /* wavelength LED measurement FWHM tollerance in nm */
+ if ((dp = m->data->get_doubles(m->data, &count, key2_wlcal_fwhm_tol)) == NULL
+ || count != 1)
+ return I1PRO_HW_CALIBINFO;
+ m->wl_cal_fwhm_tol = *dp;
+
+ /* wavelength LED reference spectrum */
+ if ((m->wl_led_spec = m->data->get_doubles(m->data, &m->wl_led_count, key2_wlcal_spec)) == NULL)
+ return I1PRO_HW_CALIBINFO;
+
+ /* wavelength LED spectraum reference offset */
+ if ((ip = m->data->get_ints(m->data, &count, key2_wlcal_ooff)) == NULL
+ || count != 1)
+ return I1PRO_HW_CALIBINFO;
+ m->wl_led_ref_off = *ip;
+ /* Hmm. this is odd, but it doesn't work correctly otherwise... */
+ m->wl_led_ref_off--;
+
+ /* wavelength calibration maximum error */
+ if ((dp = m->data->get_doubles(m->data, &count, key2_wlcal_max)) == NULL
+ || count != 1)
+ return I1PRO_HW_CALIBINFO;
+ m->wl_err_max = *dp;
+ }
+
+ /* CCD bin to wavelength polinomial */
+ if ((m->wlpoly1 = m->data->get_doubles(m->data, &count, key2_wlpoly_1)) == NULL || count != 4)
+ return I1PRO_HW_CALIBINFO;
+
+ if ((m->wlpoly2 = m->data->get_doubles(m->data, &count, key2_wlpoly_2)) == NULL || count != 4)
+ return I1PRO_HW_CALIBINFO;
+
+ /* Stray light compensation. Note that 16 bit numbers are signed. */
+ if ((sip = m->data->get_shorts(m->data, &count, key2_straylight)) == NULL
+ || count != (36 * 36))
+ return I1PRO_HW_CALIBINFO;
+
+ /* stray light scale factor */
+ if ((dp = m->data->get_doubles(m->data, &count, key2_straylight_scale)) == NULL
+ || count != 1)
+ return I1PRO_HW_CALIBINFO;
+
+ /* Convert from ints to floats */
+ m->straylight[0] = dmatrixz(0, 35, 0, 35);
+ for (i = 0; i < 36; i++) {
+ for (j = 0; j < 36; j++) {
+ m->straylight[0][i][j] = *dp * sip[i * 36 + j]/32767.0;
+ if (i == j)
+ m->straylight[0][i][j] += 1.0;
+ }
+
+ }
+
+ if (p->log->debug >= 7) {
+ a1logd(p->log,7,"Stray Light matrix:\n");
+ for(i = 0; i < 36; i++) {
+ double sum = 0.0;
+ for (j = 0; j < 36; j++) {
+ sum += m->straylight[0][i][j];
+ a1logd(p->log,7," Wt %d = %f\n",j, m->straylight[0][i][j]);
+ }
+ a1logd(p->log,7," Sum = %f\n",sum);
+ }
+ }
+
+#ifdef NEVER
+ /* Plot raw2wav polinomials for Rev E */
+ {
+ double *xx;
+ double *y1, *y2; /* Rev E poly1 and poly2 */
+ double d1, d2;
+ int i, k;
+
+ xx = dvector(0, m->nraw); /* X index = raw bin */
+ y1 = dvector(0, m->nraw); /* Y = nm */
+ y2 = dvector(0, m->nraw); /* Y = nm */
+
+ d1 = d2 = 0.0;
+ for (i = 0; i < m->nraw; i++) {
+ double iv, v1, v2;
+ xx[i] = i;
+
+ iv = (double)(128-i);
+
+ for (v1 = m->wlpoly1[4-1], k = 4-2; k >= 0; k--)
+ v1 = v1 * iv + m->wlpoly1[k];
+ y1[i] = v1;
+ d1 += fabs(y2[i] - yy[i]);
+
+ for (v2 = m->wlpoly2[4-1], k = 4-2; k >= 0; k--)
+ v2 = v2 * iv + m->wlpoly2[k];
+ y2[i] = v2;
+ d2 += fabs(y3[i] - yy[i]);
+
+// printf("ix %d, poly1 %f, poly2 %f, del12 %f\n",i, y1[i], y2[i], y2[i] - y1[i]);
+ }
+ printf("Avge del of poly1 = %f, poly2 = %f\n",d1/128.0, d2/128.0);
+
+ printf("CCD bin to wavelength mapping of RevE polinomial:\n");
+ do_plot6(xx, y1, y2, NULL, NULL, NULL, NULL, m->nraw);
+ free_dvector(xx, 0, m->nraw);
+ free_dvector(y1, 0, m->nraw);
+ free_dvector(y2, 0, m->nraw);
+ }
+#endif
+
+ }
+
+ /* Set up the current state of each mode */
+ {
+ int i, j;
+ i1pro_state *s;
+
+ /* First set state to basic configuration */
+ /* (We assume it's been zero'd) */
+ for (i = 0; i < i1p_no_modes; i++) {
+ s = &m->ms[i];
+
+ s->mode = i;
+
+ /* Default to an emissive configuration */
+ s->targoscale = 1.0; /* Default full scale */
+ s->targmaxitime = 2.0; /* Maximum integration time to aim for */
+ s->targoscale2 = 0.15; /* Proportion of targoscale to meed etargmaxitime2 (!higain) */
+ s->gainmode = 0; /* Normal gain mode */
+
+ s->inttime = 0.5; /* Integration time */
+ s->lamptime = 0.50; /* Lamp turn on time (up to 1.0 sec is better, */
+
+ s->wl_valid = 0;
+ s->wl_led_off = m->wl_led_ref_off;
+
+ s->dark_valid = 0; /* Dark cal invalid */
+ s->dark_data = dvectorz(-1, m->nraw-1);
+ s->dark_data2 = dvectorz(-1, m->nraw-1);
+ s->dark_data3 = dvectorz(-1, m->nraw-1);
+
+ s->cal_valid = 0; /* Scale cal invalid */
+ s->cal_factor[0] = dvectorz(0, m->nwav[0]-1);
+ s->cal_factor[1] = dvectorz(0, m->nwav[1]-1);
+ s->white_data = dvectorz(-1, m->nraw-1);
+
+ s->idark_valid = 0; /* Dark cal invalid */
+ s->idark_data = dmatrixz(0, 3, -1, m->nraw-1);
+
+ s->min_wl = 0.0; /* No minimum by default */
+
+ s->dark_int_time = DISP_INTT; /* 2.0 */
+ s->dark_int_time2 = DISP_INTT2; /* 0.8 */
+ s->dark_int_time3 = DISP_INTT3; /* 0.3 */
+
+ s->idark_int_time[0] = s->idark_int_time[2] = m->min_int_time;
+ if (p->itype == instI1Pro2) {
+ s->idark_int_time[1] = s->idark_int_time[3] = ADARKINT_MAX2; /* 4.0 */
+ } else {
+#ifdef USE_HIGH_GAIN_MODE
+ s->idark_int_time[1] = s->idark_int_time[3] = ADARKINT_MAX; /* 2.0 */
+#else
+ s->idark_int_time[1] = s->idark_int_time[3] = ADARKINT_MAX2; /* 4.0 */
+#endif
+ }
+
+ s->want_calib = 1; /* Do an initial calibration */
+ s->want_dcalib = 1;
+ }
+
+ /* Then add mode specific settings */
+ for (i = 0; i < i1p_no_modes; i++) {
+ s = &m->ms[i];
+ switch(i) {
+ case i1p_refl_spot:
+ s->targoscale = 1.0; /* Optimised sensor scaling to full */
+ s->reflective = 1;
+ s->adaptive = 1;
+ s->inttime = 0.02366; /* Should get this from the log ?? */
+ s->dark_int_time = s->inttime;
+
+ s->dadaptime = 0.10;
+ s->wadaptime = 0.10;
+#ifdef MATCH_SPOT_OMD
+ s->lamptime = 0.18; /* Lamp turn on time, close to OMD */
+ /* (Not ideal, but partly compensated by calib.) */
+ /* (The actual value the OMD uses is 0.20332) */
+ s->dcaltime = 0.05; /* Longer than the original driver for lower */
+ /* noise, and lamptime has been reduces to */
+ /* compensate. (OMD uses 0.014552) */
+ s->wcaltime = 0.05;
+ s->dreadtime = 0.05;
+ s->wreadtime = 0.05;
+#else
+ s->lamptime = 0.5; /* This should give better accuracy, and better */
+ s->dcaltime = 0.5; /* match the scan readings. Difference is about */
+ s->wcaltime = 0.5; /* 0.1 DE though, but would be lost in the */
+ s->dreadtime = 0.5; /* repeatability noise... */
+ s->wreadtime = 0.5;
+#endif
+ s->maxscantime = 0.0;
+ s->min_wl = HIGHRES_REF_MIN;/* Too much stray light below this */
+ /* given low illumination < 375nm */
+ break;
+ case i1p_refl_scan:
+ s->reflective = 1;
+ s->scan = 1;
+ s->adaptive = 1;
+ s->inttime = m->min_int_time; /* Maximize scan rate */
+ s->dark_int_time = s->inttime;
+ if (m->fwrev >= 301) /* (We're not using scan targoscale though) */
+ s->targoscale = 0.25;
+ else
+ s->targoscale = 0.5;
+
+ s->lamptime = 0.5; /* Lamp turn on time - lots to match scan */
+ s->dadaptime = 0.10;
+ s->wadaptime = 0.10;
+ s->dcaltime = 0.5;
+ s->wcaltime = 0.5;
+ s->dreadtime = 0.10;
+ s->wreadtime = 0.10;
+ s->maxscantime = MAXSCANTIME;
+ s->min_wl = HIGHRES_REF_MIN; /* Too much stray light below this */
+ break;
+
+ case i1p_emiss_spot_na: /* Emissive spot not adaptive */
+ s->targoscale = 0.90; /* Allow extra 10% margine for drift */
+ for (j = 0; j < m->nwav[0]; j++)
+ s->cal_factor[0][j] = EMIS_SCALE_FACTOR * m->emis_coef[0][j];
+ s->cal_valid = 1;
+ s->emiss = 1;
+ s->adaptive = 0;
+
+ s->inttime = DISP_INTT; /* Default disp integration time (ie. 2.0 sec) */
+ s->lamptime = 0.20; /* ???? */
+ s->dark_int_time = s->inttime;
+ s->dark_int_time2 = DISP_INTT2; /* Alternate disp integration time (ie. 0.8) */
+ s->dark_int_time3 = DISP_INTT3; /* Alternate disp integration time (ie. 0.3) */
+
+ s->dadaptime = 0.0;
+ s->wadaptime = 0.10;
+ s->dcaltime = DISP_INTT; /* ie. determines number of measurements */
+ s->dcaltime2 = DISP_INTT2 * 2; /* Make it 1.6 seconds (ie, 2 x 0.8 seconds) */
+ s->dcaltime3 = DISP_INTT3 * 3; /* Make it 0.9 seconds (ie, 3 x 0.3 seconds) */
+ s->wcaltime = 0.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = DISP_INTT;
+ s->maxscantime = 0.0;
+ break;
+ case i1p_emiss_spot:
+ s->targoscale = 0.90; /* Allow extra 10% margine for drift */
+ for (j = 0; j < m->nwav[0]; j++)
+ s->cal_factor[0][j] = EMIS_SCALE_FACTOR * m->emis_coef[0][j];
+ s->cal_valid = 1;
+ s->emiss = 1;
+ s->adaptive = 1;
+
+ s->lamptime = 0.20; /* ???? */
+ s->dadaptime = 0.0;
+ s->wadaptime = 0.10;
+ s->dcaltime = 1.0;
+ s->wcaltime = 0.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = 1.0;
+ s->maxscantime = 0.0;
+ break;
+ case i1p_emiss_scan:
+ for (j = 0; j < m->nwav[0]; j++)
+ s->cal_factor[0][j] = EMIS_SCALE_FACTOR * m->emis_coef[0][j];
+ s->cal_valid = 1;
+ s->emiss = 1;
+ s->scan = 1;
+ s->adaptive = 1; /* ???? */
+ s->inttime = m->min_int_time; /* Maximize scan rate */
+ s->lamptime = 0.20; /* ???? */
+ s->dark_int_time = s->inttime;
+ if (m->fwrev >= 301)
+ s->targoscale = 0.25; /* (We're not using scan targoscale though) */
+ else
+ s->targoscale = 0.5;
+
+ s->dadaptime = 0.0;
+ s->wadaptime = 0.10;
+ s->dcaltime = 1.0;
+ s->wcaltime = 0.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = 0.10;
+ s->maxscantime = MAXSCANTIME;
+ break;
+
+ case i1p_amb_spot:
+#ifdef FAKE_AMBIENT
+ for (j = 0; j < m->nwav[0]; j++)
+ s->cal_factor[0][j] = EMIS_SCALE_FACTOR * m->emis_coef[0][j];
+ s->cal_valid = 1;
+#else
+ if (m->amb_coef[0] != NULL) {
+ for (j = 0; j < m->nwav[0]; j++)
+ s->cal_factor[0][j] = AMB_SCALE_FACTOR * m->emis_coef[0][j] * m->amb_coef[0][j];
+ s->cal_valid = 1;
+ }
+#endif
+ s->emiss = 1;
+ s->ambient = 1;
+ s->adaptive = 1;
+
+ s->lamptime = 0.20; /* ???? */
+ s->dadaptime = 0.0;
+ s->wadaptime = 0.10;
+ s->dcaltime = 1.0;
+ s->wcaltime = 0.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = 1.0;
+ s->maxscantime = 0.0;
+ break;
+ case i1p_amb_flash:
+ /* This is intended for measuring flashes */
+#ifdef FAKE_AMBIENT
+ for (j = 0; j < m->nwav[0]; j++)
+ s->cal_factor[0][j] = EMIS_SCALE_FACTOR * m->emis_coef[0][j];
+ s->cal_valid = 1;
+#else
+ if (m->amb_coef[0] != NULL) {
+ for (j = 0; j < m->nwav[0]; j++)
+ s->cal_factor[0][j] = AMB_SCALE_FACTOR * m->emis_coef[0][j] * m->amb_coef[0][j];
+ s->cal_valid = 1;
+ }
+#endif
+ s->emiss = 1;
+ s->ambient = 1;
+ s->scan = 1;
+ s->adaptive = 0;
+ s->flash = 1;
+
+ s->inttime = m->min_int_time; /* Maximize scan rate */
+ s->lamptime = 0.20; /* ???? */
+ s->dark_int_time = s->inttime;
+ if (m->fwrev >= 301)
+ s->targoscale = 0.25; /* (We're not using scan targoscale though) */
+ else
+ s->targoscale = 0.5;
+
+ s->dadaptime = 0.0;
+ s->wadaptime = 0.10;
+ s->dcaltime = 1.0;
+ s->wcaltime = 0.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = 0.12;
+ s->maxscantime = MAXSCANTIME;
+ break;
+
+ case i1p_trans_spot:
+ s->trans = 1;
+ s->adaptive = 1;
+
+ s->lamptime = 0.20; /* ???? */
+ s->dadaptime = 0.10;
+ s->wadaptime = 0.10;
+ s->dcaltime = 1.0;
+ s->wcaltime = 1.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = 1.0;
+ s->maxscantime = 0.0;
+ s->min_wl = HIGHRES_REF_MIN; /* Too much stray light below this */
+ break;
+ case i1p_trans_scan:
+ s->trans = 1;
+ s->scan = 1;
+ s->adaptive = 0;
+ s->inttime = m->min_int_time; /* Maximize scan rate */
+ s->dark_int_time = s->inttime;
+ if (m->fwrev >= 301) /* (We're not using scan targoscale though) */
+ s->targoscale = 0.25;
+ else
+ s->targoscale = 0.5;
+
+ s->lamptime = 0.20; /* ???? */
+ s->dadaptime = 0.10;
+ s->wadaptime = 0.10;
+ s->dcaltime = 1.0;
+ s->wcaltime = 1.0;
+ s->dreadtime = 0.00;
+ s->wreadtime = 0.10;
+ s->maxscantime = MAXSCANTIME;
+ s->min_wl = HIGHRES_REF_MIN; /* Too much stray light below this */
+ break;
+ }
+ }
+ }
+
+ if (p->itype != instI1Monitor /* Monitor doesn't have reflective cal */
+ && p->itype != instI1Pro2) { /* Rev E mode has different calibration */
+ /* Restore the previous reflective spot calibration from the EEProm */
+ /* Get ready to operate the instrument */
+ if ((ev = i1pro_restore_refspot_cal(p)) != I1PRO_OK)
+ return ev;
+ }
+
+#ifdef ENABLE_NONVCAL
+ /* Restore the all modes calibration from the local system */
+ i1pro_restore_calibration(p);
+ /* Touch it so that we know when the instrument was last opened */
+ i1pro_touch_calibration(p);
+#endif
+
+ /* Get ready to operate the instrument */
+ if ((ev = i1pro_establish_high_power(p)) != I1PRO_OK)
+ return ev;
+
+ /* Get the current measurement parameters (why ?) */
+ if ((ev = i1pro_getmeasparams(p, &m->r_intclocks, &m->r_lampclocks, &m->r_nummeas, &m->r_measmodeflags)) != I1PRO_OK)
+ return ev;
+
+ if (p->log->verb >= 1) {
+ a1logv(p->log,1,"Instrument Type: %s\n",inst_name(p->itype));
+ a1logv(p->log,1,"Serial Number: %d\n",m->serno);
+ a1logv(p->log,1,"Firmware version: %d\n",m->fwrev);
+ a1logv(p->log,1,"CPLD version: %d\n",m->cpldrev);
+ if (p->itype == instI1Pro2)
+ a1logv(p->log,1,"Chip ID: %02x-%02x%02x%02x%02x%02x%02x%02x\n",
+ m->chipid[0], m->chipid[1], m->chipid[2], m->chipid[3],
+ m->chipid[4], m->chipid[5], m->chipid[6], m->chipid[7]);
+ a1logv(p->log,1,"Date manufactured: %d-%d-%d\n",
+ m->dom/1000000, (m->dom/10000) % 100, m->dom % 10000);
+ // Hmm. physfilt == 0x81 for instI1Monitor ???
+ a1logv(p->log,1,"U.V. filter ?: %s\n",m->physfilt == 0x82 ? "Yes" : "No");
+ a1logv(p->log,1,"Measure Ambient ?: %s\n",m->capabilities & 0x6000 ? "Yes" : "No");
+
+ a1logv(p->log,1,"Tot. Measurement Count: %d\n",m->meascount);
+ a1logv(p->log,1,"Remission Spot Count: %d\n",m->rpcount);
+ a1logv(p->log,1,"Remission Scan Count: %d\n",m->acount);
+ a1logv(p->log,1,"Date of last Remission spot cal: %s",ctime(&m->caldate));
+ a1logv(p->log,1,"Remission Spot Count at last cal: %d\n",m->calcount);
+ a1logv(p->log,1,"Total lamp usage: %f\n",m->lampage);
+ }
+
+#ifdef NEVER
+// ~~99 play with LED settings
+ if (p->itype == instI1Pro2) {
+
+ /* Makes it white */
+ unsigned char b2[] = {
+ 0x00, 0x00, 0x00, 0x02,
+
+ 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x36, 0x00,
+ 0x00, 0x00, 0x01,
+
+ 0x00, 0x00, 0x00, 0x0a,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x3f, 0x36, 0x40,
+ 0x00, 0x00, 0x01
+ };
+
+ printf("~1 send led sequence length %d\n",sizeof(b2));
+ if ((ev = i1pro2_indLEDseq(p, b2, sizeof(b2))) != I1PRO_OK)
+ return ev;
+ }
+ /* Make sure LED sequence is finished, because it interferes with EEProm read! */
+ if ((ev = i1pro2_indLEDoff(p)) != I1PRO_OK)
+ return ev;
+#endif
+
+ return ev;
+}
+
+/* Return a pointer to the serial number */
+char *i1pro_imp_get_serial_no(i1pro *p) {
+ i1proimp *m = (i1proimp *)p->m;
+
+ return m->sserno;
+}
+
+/* Return non-zero if capable of ambient mode */
+int i1pro_imp_ambient(i1pro *p) {
+
+ if (p->inited) {
+ i1proimp *m = (i1proimp *)p->m;
+ if (m->capabilities & 0x6000) /* Expect ambient calibration */
+ return 1;
+#ifdef FAKE_AMBIENT
+ return 1;
+#endif
+ return 0;
+
+ } else {
+ return 0;
+ }
+}
+
+/* Set the measurement mode. It may need calibrating */
+i1pro_code i1pro_imp_set_mode(
+ i1pro *p,
+ i1p_mode mmode, /* Operating mode */
+ inst_mode mode /* Full mode mask for options */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+
+ a1logd(p->log,2,"i1pro_imp_set_mode called with %d\n",mmode);
+ switch(mmode) {
+ case i1p_refl_spot:
+ case i1p_refl_scan:
+ if (p->itype == instI1Monitor)
+ return I1PRO_INT_ILLEGALMODE; /* i1Monitor */
+ /* Fall through */
+ case i1p_emiss_spot_na:
+ case i1p_emiss_spot:
+ case i1p_emiss_scan:
+ case i1p_amb_spot:
+ case i1p_amb_flash:
+ case i1p_trans_spot:
+ case i1p_trans_scan:
+ m->mmode = mmode;
+ break;
+ default:
+ return I1PRO_INT_ILLEGALMODE;
+ }
+ m->spec_en = (mode & inst_mode_spectral) != 0;
+ m->uv_en = 0;
+
+ if (mmode == i1p_refl_spot
+ || mmode == i1p_refl_scan)
+ m->uv_en = (mode & inst_mode_ref_uv) != 0;
+
+ return I1PRO_OK;
+}
+
+/* Return needed and available inst_cal_type's */
+i1pro_code i1pro_imp_get_n_a_cals(i1pro *p, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *cs = &m->ms[m->mmode];
+ time_t curtime = time(NULL);
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ a1logd(p->log,2,"i1pro_imp_get_n_a_cals: checking mode %d\n",m->mmode);
+
+ /* Timout calibrations that are too old */
+ if (m->capabilities2 & I1PRO_CAP2_WL_LED) {
+ if ((curtime - cs->wldate) > WLCALTOUT) {
+ a1logd(p->log,2,"Invalidating wavelength cal as %d secs from last cal\n",curtime - cs->wldate);
+ cs->wl_valid = 0;
+ }
+ }
+ if ((curtime - cs->iddate) > ((p->itype == instI1Pro) ? DCALTOUT2 : DCALTOUT)) {
+ a1logd(p->log,2,"Invalidating adaptive dark cal as %d secs from last cal\n",curtime - cs->iddate);
+ cs->idark_valid = 0;
+ }
+ if ((curtime - cs->ddate) > ((p->itype == instI1Pro) ? DCALTOUT2 : DCALTOUT)) {
+ a1logd(p->log,2,"Invalidating dark cal as %d secs from last cal\n",curtime - cs->ddate);
+ cs->dark_valid = 0;
+ }
+ if (!cs->emiss && (curtime - cs->cfdate) > WCALTOUT) {
+ a1logd(p->log,2,"Invalidating white cal as %d secs from last cal\n",curtime - cs->cfdate);
+ cs->cal_valid = 0;
+ }
+
+#ifdef NEVER
+ printf("~1 reflective = %d, adaptive = %d, emiss = %d, trans = %d, scan = %d\n",
+ cs->reflective, cs->adaptive, cs->emiss, cs->trans, cs->scan);
+ printf("~1 idark_valid = %d, dark_valid = %d, cal_valid = %d\n",
+ cs->idark_valid,cs->dark_valid,cs->cal_valid);
+ printf("~1 want_calib = %d, want_dcalib = %d, noinitcalib = %d\n",
+ cs->want_calib,cs->want_dcalib, m->noinitcalib);
+#endif /* NEVER */
+
+ if (m->capabilities2 & I1PRO_CAP2_WL_LED) {
+ if (!cs->wl_valid
+ || (cs->want_dcalib && !m->noinitcalib)) // ?? want_dcalib ??
+ n_cals |= inst_calt_wavelength;
+ a_cals |= inst_calt_wavelength;
+ }
+ if (cs->reflective) {
+ if (!cs->dark_valid
+ || (cs->want_dcalib && !m->noinitcalib))
+ n_cals |= inst_calt_ref_dark;
+ a_cals |= inst_calt_ref_dark;
+
+ if (!cs->cal_valid
+ || (cs->want_calib && !m->noinitcalib))
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+ }
+ if (cs->emiss) {
+ if ((!cs->adaptive && !cs->dark_valid)
+ || (cs->adaptive && !cs->idark_valid)
+ || (cs->want_dcalib && !m->noinitcalib))
+ n_cals |= inst_calt_em_dark;
+ a_cals |= inst_calt_em_dark;
+ }
+ if (cs->trans) {
+ if ((!cs->adaptive && !cs->dark_valid)
+ || (cs->adaptive && !cs->idark_valid)
+ || (cs->want_dcalib && !m->noinitcalib))
+ n_cals |= inst_calt_trans_dark;
+ a_cals |= inst_calt_trans_dark;
+
+ if (!cs->cal_valid
+ || (cs->want_calib && !m->noinitcalib))
+ n_cals |= inst_calt_trans_vwhite;
+ a_cals |= inst_calt_trans_vwhite;
+ }
+ if (cs->emiss && !cs->adaptive && !cs->scan) {
+ if (!cs->done_dintsel)
+ n_cals |= inst_calt_emis_int_time;
+ a_cals |= inst_calt_emis_int_time;
+ }
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ a1logd(p->log,3,"i1pro_imp_get_n_a_cals: returning n_cals 0x%x, a_cals 0x%x\n",n_cals, a_cals);
+
+ return I1PRO_OK;
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Calibrate for the current mode. */
+/* Request an instrument calibration of the current mode. */
+i1pro_code i1pro_imp_calibrate(
+ i1pro *p,
+ inst_cal_type *calt, /* Calibration type to do/remaining */
+ inst_cal_cond *calc, /* Current condition/desired condition */
+ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ int mmode = m->mmode;
+ i1pro_state *cs = &m->ms[m->mmode];
+ int sx1, sx2, sx;
+ time_t cdate = time(NULL);
+ int nummeas = 0;
+ int ltocmode = 0; /* 1 = Lamp turn on compensation mode */
+ int i, k;
+ inst_cal_type needed, available;
+
+ a1logd(p->log,2,"i1pro_imp_calibrate called with calt 0x%x, calc 0x%x\n",*calt, *calc);
+
+ if ((ev = i1pro_imp_get_n_a_cals(p, &needed, &available)) != I1PRO_OK)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"i1pro_imp_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return I1PRO_OK;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return I1PRO_UNSUPPORTED;
+ }
+
+ if (*calt & inst_calt_ap_flag) {
+ sx1 = 0; sx2 = i1p_no_modes; /* Go through all the modes */
+ } else {
+ sx1 = m->mmode; sx2 = sx1 + 1; /* Just current mode */
+ }
+
+ /* Go through the modes we are going to cover */
+ for (sx = sx1; sx < sx2; sx++) {
+ i1pro_state *s = &m->ms[sx];
+ m->mmode = sx; /* A lot of functions we call rely on this */
+
+ a1logd(p->log,2,"\nCalibrating mode %d\n", s->mode);
+
+ /* Sanity check scan mode settings, in case something strange */
+ /* has been restored from the persistence file. */
+ if (s->scan && s->inttime > (2.1 * m->min_int_time)) {
+ s->inttime = m->min_int_time; /* Maximize scan rate */
+ }
+
+ /* Wavelength calibration: */
+ if ((m->capabilities2 & I1PRO_CAP2_WL_LED)
+ && (*calt & (inst_calt_wavelength | inst_calt_ap_flag))
+ && (*calc == inst_calc_man_ref_white
+ || *calc == inst_calc_man_am_dark)) {
+ double *wlraw;
+ double optscale;
+ double *abswav;
+
+ a1logd(p->log,2,"\nDoing wavelength calibration\n");
+
+ wlraw = dvectorz(-1, m->nraw-1);
+
+ if ((ev = i1pro2_wl_measure(p, wlraw, &optscale, &m->wl_cal_inttime, 1.0)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro2_wl_measure() failed\n");
+ return ev;
+ }
+
+ /* Find the best fit of the measured values to the reference spectrum */
+ if ((ev = i1pro2_match_wl_meas(p, &cs->wl_led_off, wlraw)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro2_match_wl_meas() failed\n");
+ return ev;
+ }
+
+ free_dvector(wlraw, -1, m->nraw-1);
+
+ /* Compute normal res. reflective wavelength corrected filters */
+ if ((ev = i1pro2_compute_wav_filters(p, 1)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro2_compute_wav_filters() failed\n");
+ return ev;
+ }
+
+ /* Compute normal res. emissive/transmissive wavelength corrected filters */
+ if ((ev = i1pro2_compute_wav_filters(p, 0)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro2_compute_wav_filters() failed\n");
+ return ev;
+ }
+
+ /* Re-compute high res. wavelength corrected filters */
+ if (m->hr_inited && (ev = i1pro_create_hr(p)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_create_hr() failed\n");
+ return ev;
+ }
+
+ cs->wl_valid = 1;
+ cs->wldate = cdate;
+ *calt &= ~inst_calt_wavelength;
+
+ /* Save the calib to all modes */
+ a1logd(p->log,5,"Saving wavelength calib to similar modes\n");
+ for (i = 0; i < i1p_no_modes; i++) {
+ i1pro_state *ss = &m->ms[i];
+ if (ss == cs)
+ continue;
+ ss->wl_valid = cs->wl_valid;
+ ss->wldate = cs->wldate;
+ ss->wl_led_off = cs->wl_led_off;
+ }
+ }
+
+ /* Fixed int. time black calibration: */
+ /* Reflective uses on the fly black, even for adaptive. */
+ /* Emiss and trans can use single black ref only for non-adaptive */
+ /* using the current inttime & gainmode, while display mode */
+ /* does an extra fallback black cal for bright displays. */
+ if ((*calt & (inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark | inst_calt_ap_flag))
+ && (*calc == inst_calc_man_ref_white /* Any condition conducive to dark calib */
+ || *calc == inst_calc_man_em_dark
+ || *calc == inst_calc_man_am_dark
+ || *calc == inst_calc_man_trans_dark)
+ && ( s->reflective
+ || (s->emiss && !s->adaptive && !s->scan)
+ || (s->trans && !s->adaptive))) {
+ int stm;
+ int usesdct23 = 0; /* Is a mode that uses dcaltime2 & 3 */
+
+ if (s->emiss && !s->adaptive && !s->scan)
+ usesdct23 = 1;
+
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->inttime);
+
+ a1logd(p->log,2,"\nDoing initial black calibration with dcaltime %f, int_time %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode);
+ stm = msec_time();
+ if ((ev = i1pro_dark_measure(p, s->dark_data,
+ nummeas, &s->inttime, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,2,"Execution time of dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
+
+ /* Special display mode alternate integration time black measurement */
+ if (usesdct23) {
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime2, s->dark_int_time2);
+ a1logd(p->log,2,"Doing 2nd initial black calibration with dcaltime2 %f, dark_int_time2 %f, nummeas %d, gainmode %d\n", s->dcaltime2, s->dark_int_time2, nummeas, s->gainmode);
+ stm = msec_time();
+ if ((ev = i1pro_dark_measure(p, s->dark_data2,
+ nummeas, &s->dark_int_time2, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,2,"Execution time of 2nd dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
+
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime3, s->dark_int_time3);
+ a1logd(p->log,2,"Doing 3rd initial black calibration with dcaltime3 %f, dark_int_time3 %f, nummeas %d, gainmode %d\n", s->dcaltime3, s->dark_int_time3, nummeas, s->gainmode);
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime3, s->dark_int_time3);
+ stm = msec_time();
+ if ((ev = i1pro_dark_measure(p, s->dark_data3,
+ nummeas, &s->dark_int_time3, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,2,"Execution time of 3rd dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
+ }
+ s->dark_valid = 1;
+ s->want_dcalib = 0;
+ s->ddate = cdate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ *calt &= ~(inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark);
+
+ /* Save the calib to all similar modes */
+ for (i = 0; i < i1p_no_modes; i++) {
+ i1pro_state *ss = &m->ms[i];
+ if (ss == s || ss->ddate == cdate)
+ continue;
+ if (( s->reflective
+ || (ss->emiss && !ss->adaptive && !ss->scan)
+ || (ss->trans && !ss->adaptive))
+ && ss->dark_int_time == s->dark_int_time
+ && ss->dark_gain_mode == s->dark_gain_mode) {
+
+ ss->dark_valid = s->dark_valid;
+ ss->want_dcalib = s->want_dcalib;
+ ss->ddate = s->ddate;
+ ss->dark_int_time = s->dark_int_time;
+ ss->dark_gain_mode = s->dark_gain_mode;
+ for (k = -1; k < m->nraw; k++)
+ ss->dark_data[k] = s->dark_data[k];
+ /* If this is a mode with dark_data2/3, tranfer it too */
+ if (usesdct23 && ss->emiss && !ss->adaptive && !ss->scan) {
+ ss->dark_int_time2 = s->dark_int_time2;
+ ss->dark_int_time3 = s->dark_int_time2;
+ for (k = -1; k < m->nraw; k++) {
+ ss->dark_data2[k] = s->dark_data2[k];
+ ss->dark_data3[k] = s->dark_data3[k];
+ }
+ }
+ }
+ }
+ }
+
+ /* Emissive scan black calibration: */
+ /* Emsissive scan (flash) uses the fastest possible scan rate (??) */
+ if ((*calt & (inst_calt_em_dark | inst_calt_ap_flag))
+ && (*calc == inst_calc_man_ref_white /* Any condition conducive to dark calib */
+ || *calc == inst_calc_man_em_dark
+ || *calc == inst_calc_man_am_dark
+ || *calc == inst_calc_man_trans_dark)
+ && (s->emiss && !s->adaptive && s->scan)) {
+ int stm;
+
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->inttime);
+
+ a1logd(p->log,2,"\nDoing emissive (flash) black calibration with dcaltime %f, int_time %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode);
+ stm = msec_time();
+ if ((ev = i1pro_dark_measure(p, s->dark_data,
+ nummeas, &s->inttime, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,2,"Execution time of dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
+
+ s->dark_valid = 1;
+ s->want_dcalib = 0;
+ s->ddate = cdate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ *calt &= ~inst_calt_em_dark;
+
+ /* Save the calib to all similar modes */
+ /* We're assuming they have the same int times */
+ a1logd(p->log,5,"Saving emissive scan black calib to similar modes\n");
+ for (i = 0; i < i1p_no_modes; i++) {
+ i1pro_state *ss = &m->ms[i];
+ if (ss == s || ss->ddate == s->ddate)
+ continue;
+ if (ss->emiss && !ss->adaptive && ss->scan) {
+ ss->dark_valid = s->dark_valid;
+ ss->want_dcalib = s->want_dcalib;
+ ss->ddate = s->ddate;
+ ss->dark_int_time = s->dark_int_time;
+ ss->dark_gain_mode = s->dark_gain_mode;
+ for (k = -1; k < m->nraw; k++)
+ ss->dark_data[k] = s->dark_data[k];
+ }
+ }
+ }
+
+ /* Adaptive black calibration: */
+ /* Deal with an emmissive/transmissive black reference */
+ /* in non-scan mode, where the integration time and gain may vary. */
+ /* The black is interpolated from readings with two extreme integration times */
+ if ((*calt & (inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark | inst_calt_ap_flag))
+ && (*calc == inst_calc_man_ref_white /* Any condition conducive to dark calib */
+ || *calc == inst_calc_man_em_dark
+ || *calc == inst_calc_man_am_dark
+ || *calc == inst_calc_man_trans_dark)
+ && ((s->emiss && s->adaptive && !s->scan)
+ || (s->trans && s->adaptive && !s->scan))) {
+ int i, j, k;
+
+ a1logd(p->log,2,"\nDoing emis/trans adapative black calibration\n");
+
+ /* Adaptive where we can't measure the black reference on the fly, */
+ /* so bracket it and interpolate. */
+ /* The black reference is probably temperature dependent, but */
+ /* there's not much we can do about this. */
+
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->idark_int_time[0]);
+ a1logd(p->log,2,"\nDoing adaptive interpolated black calibration, dcaltime %f, idark_int_time[0] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[0], nummeas, 0);
+ if ((ev = i1pro_dark_measure(p, s->idark_data[0],
+ nummeas, &s->idark_int_time[0], 0)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->idark_int_time[1]);
+ a1logd(p->log,2,"Doing adaptive interpolated black calibration, dcaltime %f, idark_int_time[1] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[1], nummeas, 0);
+ if ((ev = i1pro_dark_measure(p, s->idark_data[1],
+ nummeas, &s->idark_int_time[1], 0)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+#ifdef USE_HIGH_GAIN_MODE
+ if (p->itype != instI1Pro2) { /* Rev E doesn't have high gain mode */
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->idark_int_time[2]);
+ a1logd(p->log,2,"Doing adaptive interpolated black calibration, dcaltime %f, idark_int_time[2] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[2], nummeas, 1);
+ if ((ev = i1pro_dark_measure(p, s->idark_data[2],
+ nummeas, &s->idark_int_time[2], 1)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ a1logd(p->log,2,"Doing adaptive interpolated black calibration, dcaltime %f, idark_int_time[3] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[3], nummeas, 1);
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->idark_int_time[3]);
+ if ((ev = i1pro_dark_measure(p, s->idark_data[3],
+ nummeas, &s->idark_int_time[3], 1)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ }
+#endif /* USE_HIGH_GAIN_MODE */
+
+ i1pro_prepare_idark(p);
+ s->idark_valid = 1;
+ s->iddate = cdate;
+
+ if ((ev = i1pro_interp_dark(p, s->dark_data, s->inttime, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->want_dcalib = 0;
+ s->ddate = s->iddate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ *calt &= ~(inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark);
+
+ /* Save the calib to all similar modes */
+ /* We're assuming they have the same int times */
+ a1logd(p->log,5,"Saving adaptive black calib to similar modes\n");
+ for (i = 0; i < i1p_no_modes; i++) {
+ i1pro_state *ss = &m->ms[i];
+ if (ss == s || ss->iddate == s->iddate)
+ continue;
+ if ((ss->emiss || ss->trans) && ss->adaptive && !ss->scan) {
+ ss->idark_valid = s->idark_valid;
+ ss->want_dcalib = s->want_dcalib;
+ ss->iddate = s->iddate;
+ ss->dark_int_time = s->dark_int_time;
+ ss->dark_gain_mode = s->dark_gain_mode;
+#ifdef USE_HIGH_GAIN_MODE
+ for (j = 0; j < (p->itype != instI1Pro2) ? 4 : 2; j++)
+#else
+ for (j = 0; j < 2; j++)
+#endif
+ {
+ ss->idark_int_time[j] = s->idark_int_time[j];
+ for (k = -1; k < m->nraw; k++)
+ ss->idark_data[j][k] = s->idark_data[j][k];
+ }
+ }
+ }
+
+ a1logd(p->log,5,"Done adaptive interpolated black calibration\n");
+
+ /* Test accuracy of dark level interpolation */
+#ifdef TEST_DARK_INTERP
+ {
+ double tinttime;
+ double ref[128], interp[128];
+
+ // fprintf(stderr,"Normal gain offsets:\n");
+ // plot_raw(s->idark_data[0]);
+ // fprintf(stderr,"Normal gain multiplier:\n");
+ // plot_raw(s->idark_data[1]);
+
+#ifdef DUMP_DARKM
+ extern int ddumpdarkm;
+ ddumpdarkm = 1;
+#endif
+ for (tinttime = m->min_int_time; ; tinttime *= 2.0) {
+ if (tinttime >= m->max_int_time)
+ tinttime = m->max_int_time;
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, tinttime);
+ if ((ev = i1pro_dark_measure(p, ref, nummeas, &tinttime, 0)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ i1pro_interp_dark(p, interp, tinttime, 0);
+#ifdef DEBUG
+ fprintf(stderr,"Low gain ref vs. interp dark offset for inttime %f:\n",tinttime);
+ plot_raw2(ref, interp);
+#endif
+ if ((tinttime * 1.1) > m->max_int_time)
+ break;
+ }
+#ifdef DUMP_DARKM
+ ddumpdarkm = 0;
+#endif
+
+#ifdef USE_HIGH_GAIN_MODE
+ if (p->itype != instI1Pro2) { /* Rev E doesn't have high gain mode */
+ // fprintf(stderr,"High gain offsets:\n");
+ // plot_raw(s->idark_data[2]);
+ // fprintf(stderr,"High gain multiplier:\n");
+ // plot_raw(s->idark_data[3]);
+
+ for (tinttime = m->min_int_time; ; tinttime *= 2.0) {
+ if (tinttime >= m->max_int_time)
+ tinttime = m->max_int_time;
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, tinttime);
+ if ((ev = i1pro_dark_measure(p, ref, nummeas, &tinttime, 1)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ i1pro_interp_dark(p, interp, tinttime, 1);
+#ifdef DEBUG
+ fprintf(stderr,"High gain ref vs. interp dark offset for inttime %f:\n",tinttime);
+ plot_raw2(ref, interp);
+#endif
+ if ((tinttime * 1.1) > m->max_int_time)
+ break;
+ }
+ }
+#endif /* USE_HIGH_GAIN_MODE */
+ }
+#endif /* NEVER */
+
+ }
+
+ /* Deal with an emissive/transmisive adaptive black reference */
+ /* when in scan mode. */
+ if ((*calt & (inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark | inst_calt_ap_flag))
+ && (*calc == inst_calc_man_ref_white /* Any condition conducive to dark calib */
+ || *calc == inst_calc_man_em_dark
+ || *calc == inst_calc_man_am_dark
+ || *calc == inst_calc_man_trans_dark)
+ && ((s->emiss && s->adaptive && s->scan)
+ || (s->trans && s->adaptive && s->scan))) {
+ int j;
+
+ a1logd(p->log,2,"\nDoing emis/trans adapative scan mode black calibration\n");
+
+ /* We know scan is locked to the minimum integration time, */
+ /* so we can measure the dark data at that integration time, */
+ /* but we don't know what gain mode will be used, so measure both, */
+ /* and choose the appropriate one on the fly. */
+
+ s->idark_int_time[0] = s->inttime;
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->idark_int_time[0]);
+ a1logd(p->log,2,"\nDoing adaptive scan black calibration, dcaltime %f, idark_int_time[0] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[0], nummeas, s->gainmode);
+ if ((ev = i1pro_dark_measure(p, s->idark_data[0],
+ nummeas, &s->idark_int_time[0], 0)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+#ifdef USE_HIGH_GAIN_MODE
+ if (p->itype != instI1Pro2) { /* Rev E doesn't have high gain mode */
+ s->idark_int_time[2] = s->inttime;
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->idark_int_time[2]);
+ a1logd(p->log,2,"Doing adaptive scan black calibration, dcaltime %f, idark_int_time[2] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[2], nummeas, s->gainmode);
+ if ((ev = i1pro_dark_measure(p, s->idark_data[2],
+ nummeas, &s->idark_int_time[2], 1)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ }
+#endif
+
+ s->idark_valid = 1;
+ s->iddate = cdate;
+
+#ifdef USE_HIGH_GAIN_MODE
+ if (s->gainmode) {
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data[j] = s->idark_data[2][j];
+ } else
+#endif
+ {
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data[j] = s->idark_data[0][j];
+ }
+ s->dark_valid = 1;
+ s->want_dcalib = 0;
+ s->ddate = s->iddate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ *calt &= ~(inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark);
+
+ a1logd(p->log,2,"Done adaptive scan black calibration\n");
+
+ /* Save the calib to all similar modes */
+ /* We're assuming they have the same int times */
+ a1logd(p->log,5,"Saving adaptive scan black calib to similar modes\n");
+ for (i = 0; i < i1p_no_modes; i++) {
+ i1pro_state *ss = &m->ms[i];
+ if (ss == s || ss->iddate == s->iddate)
+ continue;
+ if ((ss->emiss || ss->trans) && ss->adaptive && s->scan) {
+ ss->idark_valid = s->idark_valid;
+ ss->want_dcalib = s->want_dcalib;
+ ss->iddate = s->iddate;
+ ss->dark_int_time = s->dark_int_time;
+ ss->dark_gain_mode = s->dark_gain_mode;
+#ifdef USE_HIGH_GAIN_MODE
+ for (j = 0; j < (p->itype != instI1Pro2) ? 4 : 2; j += 2)
+#else
+ for (j = 0; j < 2; j += 2)
+#endif
+ {
+ ss->idark_int_time[j] = s->idark_int_time[j];
+ for (k = -1; k < m->nraw; k++)
+ ss->idark_data[j][k] = s->idark_data[j][k];
+ }
+ }
+ }
+ }
+
+ /* If we are doing a white reference calibrate */
+ if ((*calt & (inst_calt_ref_white
+ | inst_calt_trans_vwhite | inst_calt_ap_flag))
+ && ((*calc == inst_calc_man_ref_white && s->reflective)
+ || (*calc == inst_calc_man_trans_white && s->trans))) {
+ double scale;
+
+ a1logd(p->log,2,"\nDoing initial white calibration with current inttime %f, gainmode %d\n",
+ s->inttime, s->gainmode);
+ nummeas = i1pro_comp_nummeas(p, s->wcaltime, s->inttime);
+ ev = i1pro_whitemeasure(p, s->cal_factor[0], s->cal_factor[1], s->white_data, &scale, nummeas,
+ &s->inttime, s->gainmode, s->scan ? 1.0 : s->targoscale, 0);
+ if (ev == I1PRO_RD_SENSORSATURATED) {
+ scale = 0.0; /* Signal it this way */
+ ev = I1PRO_OK;
+ }
+ if (ev != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ /* For non-scan modes, we adjust the integration time to avoid saturation, */
+ /* and to try and match the target optimal sensor value */
+ if (!s->scan) {
+ /* If it's adaptive and not good, or if it's not adaptive and even worse, */
+ /* or if we're using lamp dynamic compensation for reflective scan, */
+ /* change the parameters until the white is optimal. */
+ if ((s->adaptive && (scale < 0.95 || scale > 1.05))
+ || (scale < 0.3 || scale > 2.0)) {
+
+ /* Need to have done adaptive black measure to change inttime/gain params */
+ if (*calc != inst_calc_man_ref_white && !s->idark_valid) {
+ m->mmode = mmode; /* Restore actual mode */
+ return I1PRO_RD_TRANSWHITERANGE;
+ }
+
+ if (scale == 0.0) { /* If sensor was saturated */
+ s->inttime = m->min_int_time;
+ s->gainmode = 0;
+ s->dark_valid = 0;
+ if (!s->emiss)
+ s->cal_valid = 0;
+
+ if (*calc == inst_calc_man_ref_white) {
+ nummeas = i1pro_comp_nummeas(p, s->dadaptime, s->inttime);
+ a1logd(p->log,2,"Doing another black calibration with dadaptime %f, min inttime %f, nummeas %d, gainmode %d\n", s->dadaptime, s->inttime, nummeas, s->gainmode);
+ if ((ev = i1pro_dark_measure(p, s->dark_data,
+ nummeas, &s->inttime, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ } else if (s->idark_valid) {
+ /* compute interpolated dark refence for chosen inttime & gainmode */
+ a1logd(p->log,2,"Interpolate dark calibration reference\n");
+ if ((ev = i1pro_interp_dark(p, s->dark_data,
+ s->inttime, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->ddate = s->iddate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ } else {
+ m->mmode = mmode; /* Restore actual mode */
+ return I1PRO_INT_NOINTERPDARK;
+ }
+ a1logd(p->log,2,"Doing another white calibration with min inttime %f, gainmode %d\n",
+ s->inttime,s->gainmode);
+ nummeas = i1pro_comp_nummeas(p, s->wadaptime, s->inttime);
+ if ((ev = i1pro_whitemeasure(p, s->cal_factor[0], s->cal_factor[1], s->white_data,
+ &scale, nummeas, &s->inttime, s->gainmode, s->targoscale, 0))
+ != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ }
+
+ /* Compute a new integration time and gain mode */
+ /* in order to optimise the sensor values. Error if can't get */
+ /* scale we want. */
+ if ((ev = i1pro_optimise_sensor(p, &s->inttime, &s->gainmode,
+ s->inttime, s->gainmode, s->trans, 0, s->targoscale, scale)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,2,"Computed optimal white inttime %f and gainmode %d\n",
+ s->inttime,s->gainmode);
+
+ if (*calc == inst_calc_man_ref_white) {
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->inttime);
+ a1logd(p->log,2,"Doing final black calibration with dcaltime %f, opt inttime %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode);
+ if ((ev = i1pro_dark_measure(p, s->dark_data,
+ nummeas, &s->inttime, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->ddate = cdate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+
+ } else if (s->idark_valid) {
+ /* compute interpolated dark refence for chosen inttime & gainmode */
+ a1logd(p->log,2,"Interpolate dark calibration reference\n");
+ if ((ev = i1pro_interp_dark(p, s->dark_data,
+ s->inttime, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->ddate = s->iddate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ } else {
+ m->mmode = mmode; /* Restore actual mode */
+ return I1PRO_INT_NOINTERPDARK;
+ }
+
+ a1logd(p->log,2,"Doing final white calibration with opt int_time %f, gainmode %d\n",
+ s->inttime,s->gainmode);
+ nummeas = i1pro_comp_nummeas(p, s->wcaltime, s->inttime);
+ if ((ev = i1pro_whitemeasure(p, s->cal_factor[0], s->cal_factor[1], s->white_data,
+ &scale, nummeas, &s->inttime, s->gainmode, s->targoscale, ltocmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ }
+
+ /* For scan we take a different approach. We try and use the minimum possible */
+ /* integration time so as to maximize sampling rate, and adjust the gain */
+ /* if necessary. */
+ } else if (s->adaptive) {
+ int j;
+ if (scale == 0.0) { /* If sensor was saturated */
+ a1logd(p->log,3,"Scan illuminant is saturating sensor\n");
+ if (s->gainmode == 0) {
+ m->mmode = mmode; /* Restore actual mode */
+ return I1PRO_RD_SENSORSATURATED; /* Nothing we can do */
+ }
+ a1logd(p->log,3,"Switching to low gain mode\n");
+ s->gainmode = 0;
+ /* Measure white again with low gain */
+ nummeas = i1pro_comp_nummeas(p, s->wcaltime, s->inttime);
+ if ((ev = i1pro_whitemeasure(p, s->cal_factor[0], s->cal_factor[1], s->white_data,
+ &scale, nummeas, &s->inttime, s->gainmode, 1.0, 0)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ } else if (p->itype != instI1Pro2 && s->gainmode == 0 && scale > m->highgain) {
+#ifdef USE_HIGH_GAIN_MODE
+ a1logd(p->log,3,"Scan signal is so low we're switching to high gain mode\n");
+ s->gainmode = 1;
+ /* Measure white again with high gain */
+ nummeas = i1pro_comp_nummeas(p, s->wcaltime, s->inttime);
+ if ((ev = i1pro_whitemeasure(p, s->cal_factor[0], s->cal_factor[1], s->white_data,
+ &scale, nummeas, &s->inttime, s->gainmode, 1.0, 0)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+#endif /* USE_HIGH_GAIN_MODE */
+ }
+
+ a1logd(p->log,2,"After scan gain adaption scale = %f\n",scale);
+ if (scale > 6.0) {
+ m->transwarn |= 2;
+ a1logd(p->log,2, "scan white reference is not bright enough by %f\n",scale);
+ }
+
+ if (*calc == inst_calc_man_ref_white) {
+ nummeas = i1pro_comp_nummeas(p, s->dcaltime, s->inttime);
+ a1logd(p->log,2,"Doing final black calibration with dcaltime %f, opt inttime %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode);
+ if ((ev = i1pro_dark_measure(p, s->dark_data,
+ nummeas, &s->inttime, s->gainmode)) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->ddate = cdate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+
+ } else if (s->idark_valid) {
+ /* compute interpolated dark refence for chosen inttime & gainmode */
+ a1logd(p->log,2,"Interpolate dark calibration reference\n");
+ if (s->gainmode) {
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data[j] = s->idark_data[2][j];
+ } else {
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data[j] = s->idark_data[0][j];
+ }
+ s->dark_valid = 1;
+ s->ddate = s->iddate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ } else {
+ m->mmode = mmode; /* Restore actual mode */
+ return I1PRO_INT_NOINTERPDARK;
+ }
+ a1logd(p->log,2,"Doing final white calibration with opt int_time %f, gainmode %d\n",
+ s->inttime,s->gainmode);
+ }
+
+ /* We've settled on the inttime and gain mode to get a good white reference. */
+ if (s->reflective) { /* We read the white reference - check it */
+ /* Check a reflective white measurement, and check that */
+ /* it seems reasonable. Return I1PRO_OK if it is, error if not. */
+ /* (Using cal_factor[] as temp.) */
+ a1logd(p->log,2,"Checking white reference\n");
+ if ((ev = i1pro_check_white_reference1(p, s->cal_factor[0])) != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ /* Compute a calibration factor given the reading of the white reference. */
+ i1pro_compute_white_cal(p, s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
+ s->cal_factor[1], m->white_ref[1], s->cal_factor[1]);
+
+ } else {
+ /* Compute a calibration factor given the reading of the white reference. */
+ m->transwarn |= i1pro_compute_white_cal(p, s->cal_factor[0], NULL, s->cal_factor[0],
+ s->cal_factor[1], NULL, s->cal_factor[1]);
+ }
+ s->cal_valid = 1;
+ s->cfdate = cdate;
+ s->want_calib = 0;
+ *calt &= ~(inst_calt_ref_white
+ | inst_calt_trans_vwhite);
+ }
+
+ /* Deal with a display integration time selection */
+ if ((*calt & (inst_calt_emis_int_time | inst_calt_ap_flag))
+ && *calc == inst_calc_emis_white
+ && (s->emiss && !s->adaptive && !s->scan)) {
+ double scale;
+ double *data;
+ double *tt, tv;
+
+ data = dvectorz(-1, m->nraw-1);
+
+ a1logd(p->log,2,"\nDoing display integration time calibration\n");
+
+ /* Undo any previous swaps */
+ if (s->dispswap == 1) {
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ } else if (s->dispswap == 2) {
+ tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
+ }
+ s->dispswap = 0;
+
+ /* Simply measure the full display white, and if it's close to */
+ /* saturation, switch to the alternate display integration time */
+ nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
+ ev = i1pro_whitemeasure(p, NULL, NULL, data , &scale, nummeas,
+ &s->inttime, s->gainmode, s->targoscale, 0);
+ /* Switch to the alternate if things are too bright */
+ /* We do this simply by swapping the alternate values in. */
+ if (ev == I1PRO_RD_SENSORSATURATED || scale < 1.0) {
+ a1logd(p->log,2,"Switching to alternate display integration time %f seconds\n",s->dark_int_time2);
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ s->dispswap = 1;
+
+ /* Do another measurement of the full display white, and if it's close to */
+ /* saturation, switch to the 3rd alternate display integration time */
+ nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
+ ev = i1pro_whitemeasure(p, NULL, NULL, data , &scale, nummeas,
+ &s->inttime, s->gainmode, s->targoscale, 0);
+ /* Switch to the 3rd alternate if things are too bright */
+ /* We do this simply by swapping the alternate values in. */
+ if (ev == I1PRO_RD_SENSORSATURATED || scale < 1.0) {
+ a1logd(p->log,2,"Switching to 3rd alternate display integration time %f seconds\n",s->dark_int_time3);
+ /* Undo previous swap */
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ /* swap in 2nd alternate */
+ tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
+ s->dispswap = 2;
+ }
+ }
+ free_dvector(data, -1, m->nraw-1);
+ if (ev != I1PRO_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->done_dintsel = 1;
+ s->diseldate = cdate;
+ *calt &= ~inst_calt_emis_int_time;
+
+ a1logd(p->log,5,"Done display integration time calibration\n");
+ }
+
+ } /* Look at next mode */
+ m->mmode = mmode; /* Restore actual mode */
+
+ /* Make sure there's the right condition for any remaining calibrations */
+ if (*calt & inst_calt_wavelength) { /* Wavelength calibration */
+ if (cs->emiss && cs->ambient) {
+ id[0] = '\000';
+ if (*calc != inst_calc_man_am_dark) {
+ *calc = inst_calc_man_am_dark; /* Calibrate using ambient adapter */
+ return I1PRO_CAL_SETUP;
+ }
+ } else {
+ sprintf(id, "Serial no. %d",m->serno);
+ if (*calc != inst_calc_man_ref_white) {
+ *calc = inst_calc_man_ref_white; /* Calibrate using white tile */
+ return I1PRO_CAL_SETUP;
+ }
+ }
+ } else if (*calt & (inst_calt_ref_dark | inst_calt_ref_white)) {
+ sprintf(id, "Serial no. %d",m->serno);
+ if (*calc != inst_calc_man_ref_white) {
+ *calc = inst_calc_man_ref_white; /* Calibrate using white tile */
+ return I1PRO_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_em_dark) { /* Emissive Dark calib */
+ id[0] = '\000';
+ if (*calc != inst_calc_man_em_dark) {
+ *calc = inst_calc_man_em_dark; /* Any sort of dark reference */
+ return I1PRO_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_trans_dark) { /* Transmissvice dark */
+ id[0] = '\000';
+ if (*calc != inst_calc_man_trans_dark) {
+ *calc = inst_calc_man_trans_dark;
+ return I1PRO_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_trans_vwhite) {/* Transmissvice white for emulated transmission */
+ id[0] = '\000';
+ if (*calc != inst_calc_man_trans_white) {
+ *calc = inst_calc_man_trans_white;
+ return I1PRO_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_emis_int_time) {
+ id[0] = '\000';
+ if (*calc != inst_calc_emis_white) {
+ *calc = inst_calc_emis_white;
+ return I1PRO_CAL_SETUP;
+ }
+ }
+
+ /* Go around again if we've still got calibrations to do */
+ if (*calt & inst_calt_all_mask) {
+ return I1PRO_CAL_SETUP;
+ }
+
+ /* We must be done */
+
+ /* Update and write the EEProm log if the is a refspot calibration */
+ if (cs->reflective && !cs->scan && cs->dark_valid && cs->cal_valid) {
+ m->calcount = m->rpcount;
+ m->caldate = cdate;
+ if ((ev = i1pro_update_log(p)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_update_log: Updating the cal and log parameters"
+ " to EEProm failed\n");
+ }
+ }
+
+#ifdef ENABLE_NONVCAL
+ /* Save the calibration to a file */
+ i1pro_save_calibration(p);
+#endif
+
+ if (m->transwarn) {
+ *calc = inst_calc_message;
+ if (m->transwarn & 2)
+ strcpy(id, "Warning: Transmission light source is too low for accuracy!");
+ else
+ strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
+ m->transwarn = 0;
+ }
+
+ a1logd(p->log,2,"Finished cal with dark_valid = %d, cal_valid = %d\n",cs->dark_valid, cs->cal_valid);
+
+ return I1PRO_OK;
+}
+
+/* Interpret an icoms error into a I1PRO error */
+int icoms2i1pro_err(int se) {
+ if (se != ICOM_OK)
+ return I1PRO_COMS_FAIL;
+ return I1PRO_OK;
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Measure a patch or strip in the current mode. */
+/* To try and speed up the reaction time between */
+/* triggering a scan measurement and being able to */
+/* start moving the instrument, we pre-allocate */
+/* all the buffers and arrays, and pospone processing */
+/* until after the scan is complete. */
+i1pro_code i1pro_imp_measure(
+ i1pro *p,
+ ipatch *vals, /* Pointer to array of instrument patch value */
+ int nvals, /* Number of values */
+ instClamping clamp /* Clamp XYZ/Lab to be +ve */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ unsigned char *buf = NULL; /* Raw USB reading buffer for reflection dark cal */
+ unsigned int bsize;
+ unsigned char *mbuf = NULL; /* Raw USB reading buffer for measurement */
+ unsigned int mbsize;
+ int nummeas = 0, maxnummeas = 0;
+ int nmeasuered = 0; /* Number actually measured */
+ double **specrd = NULL; /* Cooked spectral patch values */
+ double duration = 0.0; /* Possible flash duration value */
+ int user_trig = 0;
+
+ a1logd(p->log,2,"i1pro_imp_measure: Taking %d measurments in %s%s%s%s%s%s mode called\n", nvals,
+ s->emiss ? "Emission" : s->trans ? "Trans" : "Refl",
+ s->emiss && s->ambient ? " Ambient" : "",
+ s->scan ? " Scan" : "",
+ s->flash ? " Flash" : "",
+ s->adaptive ? " Adaptive" : "",
+ m->uv_en ? " UV" : "");
+
+
+ if ((s->emiss && s->adaptive && !s->idark_valid)
+ || ((!s->emiss || !s->adaptive) && !s->dark_valid)
+ || !s->cal_valid) {
+ a1logd(p->log,3,"emis %d, adaptive %d, idark_valid %d\n",s->emiss,s->adaptive,s->idark_valid);
+ a1logd(p->log,3,"dark_valid %d, cal_valid %d\n",s->dark_valid,s->cal_valid);
+ a1logd(p->log,3,"i1pro_imp_measure need calibration\n");
+ return I1PRO_RD_NEEDS_CAL;
+ }
+
+ if (nvals <= 0
+ || (!s->scan && nvals > 1)) {
+ a1logd(p->log,2,"i1pro_imp_measure wrong number of patches\n");
+ return I1PRO_INT_WRONGPATCHES;
+ }
+
+ /* Notional number of measurements, befor adaptive and not counting scan */
+ nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
+
+ /* Allocate buf for pre-measurement dark calibration */
+ if (s->reflective) {
+ bsize = m->nsen * 2 * nummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"i1pro_imp_measure malloc %d bytes failed (5)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+ }
+
+ /* Allocate buffer for measurement */
+ maxnummeas = i1pro_comp_nummeas(p, s->maxscantime, s->inttime);
+ if (maxnummeas < nummeas)
+ maxnummeas = nummeas;
+ mbsize = m->nsen * 2 * maxnummeas;
+ if ((mbuf = (unsigned char *)malloc(sizeof(unsigned char) * mbsize)) == NULL) {
+ if (buf != NULL)
+ free(buf);
+ a1logd(p->log,1,"i1pro_imp_measure malloc %d bytes failed (6)\n",mbsize);
+ return I1PRO_INT_MALLOC;
+ }
+ specrd = dmatrix(0, nvals-1, 0, m->nwav[m->highres]-1);
+
+ if (m->trig == inst_opt_trig_user_switch) {
+ m->hide_switch = 1; /* Supress switch events */
+
+#ifdef USE_THREAD
+ {
+ int currcount = m->switch_count; /* Variable set by thread */
+ while (currcount == m->switch_count) {
+ inst_code rc;
+ int cerr;
+
+ /* Don't trigger on user key if scan, only trigger */
+ /* on instrument switch */
+ if (p->uicallback != NULL
+ && (rc = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rc == inst_user_abort) {
+ ev = I1PRO_USER_ABORT;
+ break; /* Abort */
+ }
+ if (!s->scan && rc == inst_user_trig) {
+ ev = I1PRO_USER_TRIG;
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(100);
+ }
+ }
+#else
+ /* Throw one away in case the switch was pressed prematurely */
+ i1pro_waitfor_switch_th(p, 0.01);
+
+ for (;;) {
+ inst_code rc;
+ int cerr;
+
+ if ((ev = i1pro_waitfor_switch_th(p, 0.1)) != I1PRO_OK
+ && ev != I1PRO_INT_BUTTONTIMEOUT)
+ break; /* Error */
+
+ if (ev == I1PRO_OK)
+ break; /* switch triggered */
+
+ /* Don't trigger on user key if scan, only trigger */
+ /* on instrument switch */
+ if (p->uicallback != NULL
+ && (rc = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rc == inst_user_abort) {
+ ev = I1PRO_USER_ABORT;
+ break; /* Abort */
+ }
+ if (!s->scan && rc == inst_user_trig) {
+ ev = I1PRO_USER_TRIG;
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ }
+#endif
+ a1logd(p->log,3,"############# triggered ##############\n");
+ if (p->uicallback) /* Notify of trigger */
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ m->hide_switch = 0; /* Enable switch events again */
+
+ } else if (m->trig == inst_opt_trig_user) {
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "hcfr: inst_opt_trig_user but no uicallback function set!\n");
+ ev = I1PRO_UNSUPPORTED;
+
+ } else {
+
+ for (;;) {
+ inst_code rc;
+ if ((rc = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rc == inst_user_abort) {
+ ev = I1PRO_USER_ABORT; /* Abort */
+ break;
+ }
+ if (rc == inst_user_trig) {
+ ev = I1PRO_USER_TRIG;
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ }
+ a1logd(p->log,3,"############# triggered ##############\n");
+ if (p->uicallback) /* Notify of trigger */
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ ev = I1PRO_USER_ABORT; /* Abort */
+ }
+
+ if (ev != I1PRO_OK && ev != I1PRO_USER_TRIG) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ free(mbuf);
+ if (buf != NULL)
+ free(buf);
+ a1logd(p->log,2,"i1pro_imp_measure user aborted, terminated, command, or failure\n");
+ return ev; /* User abort, term, command or failure */
+ }
+
+ if (s->emiss && !s->scan && s->adaptive) {
+ int saturated = 0;
+ double optscale = 1.0;
+ s->inttime = 0.25;
+ s->gainmode = 0;
+ s->dark_valid = 0;
+
+ a1logd(p->log,2,"Trial measure emission with inttime %f, gainmode %d\n",s->inttime,s->gainmode);
+
+ /* Take a trial measurement reading using the current mode. */
+ /* Used to determine if sensor is saturated, or not optimal */
+// nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
+ nummeas = 1;
+ if ((ev = i1pro_trialmeasure(p, &saturated, &optscale, nummeas, &s->inttime, s->gainmode,
+ s->targoscale)) != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ free(mbuf);
+ a1logd(p->log,2,"i1pro_imp_measure trial measure failed\n");
+ return ev;
+ }
+
+ if (saturated) {
+ s->inttime = m->min_int_time;
+
+ a1logd(p->log,2,"2nd trial measure emission with inttime %f, gainmode %d\n",
+ s->inttime,s->gainmode);
+ /* Take a trial measurement reading using the current mode. */
+ /* Used to determine if sensor is saturated, or not optimal */
+ nummeas = i1pro_comp_nummeas(p, 0.25, s->inttime);
+ if ((ev = i1pro_trialmeasure(p, &saturated, &optscale, nummeas, &s->inttime,
+ s->gainmode, s->targoscale)) != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ free(mbuf);
+ a1logd(p->log,2,"i1pro_imp_measure trial measure failed\n");
+ return ev;
+ }
+ }
+
+ a1logd(p->log,2,"Compute optimal integration time\n");
+ /* For adaptive mode, compute a new integration time and gain mode */
+ /* in order to optimise the sensor values. */
+ if ((ev = i1pro_optimise_sensor(p, &s->inttime, &s->gainmode,
+ s->inttime, s->gainmode, 1, 1, s->targoscale, optscale)) != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ free(mbuf);
+ a1logd(p->log,2,"i1pro_imp_measure optimise sensor failed\n");
+ return ev;
+ }
+ a1logd(p->log,2,"Computed optimal emiss inttime %f and gainmode %d\n",s->inttime,s->gainmode);
+
+ a1logd(p->log,2,"Interpolate dark calibration reference\n");
+ if ((ev = i1pro_interp_dark(p, s->dark_data, s->inttime, s->gainmode)) != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ free(mbuf);
+ a1logd(p->log,2,"i1pro_imp_measure interplate dark ref failed\n");
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+
+ /* Recompute number of measurements and realloc measurement buffer */
+ free(mbuf);
+ nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
+ maxnummeas = i1pro_comp_nummeas(p, s->maxscantime, s->inttime);
+ if (maxnummeas < nummeas)
+ maxnummeas = nummeas;
+ mbsize = m->nsen * 2 * maxnummeas;
+ if ((mbuf = (unsigned char *)malloc(sizeof(unsigned char) * mbsize)) == NULL) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ a1logd(p->log,1,"i1pro_imp_measure malloc %d bytes failed (7)\n",mbsize);
+ return I1PRO_INT_MALLOC;
+ }
+
+ } else if (s->reflective) {
+
+ DISDPLOT
+
+ a1logd(p->log,2,"Doing on the fly black calibration_1 with nummeas %d int_time %f, gainmode %d\n",
+ nummeas, s->inttime, s->gainmode);
+
+ if ((ev = i1pro_dark_measure_1(p, nummeas, &s->inttime, s->gainmode, buf, bsize))
+ != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ free(buf);
+ free(mbuf);
+ a1logd(p->log,2,"i1pro_imp_measure dak measure 1 failed\n");
+ return ev;
+ }
+
+ ENDPLOT
+ }
+ /* Take a measurement reading using the current mode. */
+ /* Converts to completely processed output readings. */
+
+ a1logd(p->log,2,"Do main measurement reading\n");
+
+ /* Indicate to the user that they can now scan the instrument, */
+ /* after a little delay that allows for the instrument reaction time. */
+ if (s->scan) {
+ /* 500msec delay, 1KHz for 200 msec */
+ msec_beep(200 + (int)(s->lamptime * 1000.0 + 0.5), 1000, 200);
+ }
+
+ /* Retry loop for certaing cases */
+ for (;;) {
+
+ /* Trigger measure and gather raw readings */
+ if ((ev = i1pro_read_patches_1(p, nummeas, maxnummeas, &s->inttime, s->gainmode,
+ &nmeasuered, mbuf, mbsize)) != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ if (buf != NULL)
+ free(buf);
+ free(mbuf);
+ a1logd(p->log,2,"i1pro_imp_measure failed at i1pro_read_patches_1\n");
+ return ev;
+ }
+
+ /* Complete reflective black reference measurement */
+ if (s->reflective) {
+ a1logd(p->log,3,"Calling black calibration_2 calc with nummeas %d, inttime %f, gainmode %d\n", nummeas, s->inttime,s->gainmode);
+ if ((ev = i1pro_dark_measure_2(p, s->dark_data,
+ nummeas, s->inttime, s->gainmode, buf, bsize)) != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ free(buf);
+ free(mbuf);
+ a1logd(p->log,2,"i1pro_imp_measure failed at i1pro_dark_measure_2\n");
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ free(buf);
+ }
+
+ /* Process the raw measurement readings into final spectral readings */
+ ev = i1pro_read_patches_2(p, &duration, specrd, nvals, s->inttime, s->gainmode,
+ nmeasuered, mbuf, mbsize);
+ /* Special case display mode read. If the sensor is saturated, and */
+ /* we haven't already done so, switch to the alternate integration time */
+ /* and try again. */
+ if (s->emiss && !s->scan && !s->adaptive
+ && ev == I1PRO_RD_SENSORSATURATED
+ && s->dispswap < 2) {
+ double *tt, tv;
+
+ if (s->dispswap == 0) {
+ a1logd(p->log,2,"Switching to alternate display integration time %f seconds\n",s->dark_int_time2);
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ s->dispswap = 1;
+ } else if (s->dispswap == 1) {
+ a1logd(p->log,2,"Switching to 2nd alternate display integration time %f seconds\n",s->dark_int_time3);
+ /* Undo first swap */
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ /* Do 2nd swap */
+ tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
+ s->dispswap = 2;
+ }
+ /* Recompute number of measurements and realloc measurement buffer */
+ free(mbuf);
+ nummeas = i1pro_comp_nummeas(p, s->wreadtime, s->inttime);
+ maxnummeas = i1pro_comp_nummeas(p, s->maxscantime, s->inttime);
+ if (maxnummeas < nummeas)
+ maxnummeas = nummeas;
+ mbsize = m->nsen * 2 * maxnummeas;
+ if ((mbuf = (unsigned char *)malloc(sizeof(unsigned char) * mbsize)) == NULL) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ a1logd(p->log,1,"i1pro_imp_measure malloc %d bytes failed (7)\n",mbsize);
+ return I1PRO_INT_MALLOC;
+ }
+ continue; /* Do the measurement again */
+ }
+
+ if (ev != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ free(mbuf);
+ a1logd(p->log,2,"i1pro_imp_measure failed at i1pro_read_patches_2\n");
+ return ev;
+ }
+ break; /* Don't repeat */
+ }
+ free(mbuf);
+
+ /* Transfer spectral and convert to XYZ */
+ if ((ev = i1pro_conv2XYZ(p, vals, nvals, specrd, clamp)) != I1PRO_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+ a1logd(p->log,2,"i1pro_imp_measure failed at i1pro_conv2XYZ\n");
+ return ev;
+ }
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav[m->highres]-1);
+
+ if (nvals > 0)
+ vals[0].duration = duration; /* Possible flash duration */
+
+ /* Update log counters */
+ if (s->reflective) {
+ if (s->scan)
+ m->acount++;
+ else {
+ m->rpinttime = s->inttime;
+ m->rpcount++;
+ }
+ }
+
+ a1logd(p->log,3,"i1pro_imp_measure sucessful return\n");
+ if (user_trig)
+ return I1PRO_USER_TRIG;
+ return ev;
+}
+
+/* - - - - - - - - - - - - - - - - */
+/*
+
+ Determining the refresh rate for a refresh type display.
+
+ This is easy when the max sample rate of the i1 is above
+ the nyquist of the display, and will always be the case
+ for the range we are prepared to measure (up to 100Hz)
+ when using an Rev B, D or E, but is a problem for the
+ rev A and ColorMunki, which can only sample at 113Hz.
+
+ We work around this problem by detecting when
+ we are measuring an alias of the refresh rate, and
+ average the aliasing corrected measurements.
+
+ If there is no aparent refresh, or the refresh rate is not determinable,
+ return a period of 0.0 and inst_ok;
+*/
+
+i1pro_code i1pro_measure_rgb(i1pro *p, double *inttime, double *rgb);
+
+#ifndef PSRAND32L
+# define PSRAND32L(S) ((S) * 1664525L + 1013904223L)
+#endif
+#undef FREQ_SLOW_PRECISE /* [und] Interpolate then autocorrelate, else autc & filter */
+#define NFSAMPS 80 /* Number of samples to read */
+#define NFMXTIME 6.0 /* Maximum time to take (2000 == 6) */
+#define PBPMS 20 /* bins per msec */
+#define PERMIN ((1000 * PBPMS)/40) /* 40 Hz */
+#define PERMAX ((1000 * PBPMS)/4) /* 4 Hz*/
+#define NPER (PERMAX - PERMIN + 1)
+#define PWIDTH (8 * PBPMS) /* 8 msec bin spread to look for peak in */
+#define MAXPKS 20 /* Number of peaks to find */
+#define TRIES 8 /* Number of different sample rates to try */
+
+i1pro_code i1pro_imp_meas_refrate(
+ i1pro *p,
+ double *ref_rate
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ int i, j, k, mm;
+ double **multimeas; /* Spectral measurements */
+ int nummeas;
+ double rgbw[3] = { 610.0, 520.0, 460.0 };
+ double ucalf = 1.0; /* usec_time calibration factor */
+ double inttime;
+ static unsigned int randn = 0x12345678;
+ struct {
+ double sec;
+ double rgb[3];
+ } samp[NFSAMPS * 2];
+ int nfsamps; /* Actual samples read */
+ double minv[3]; /* Minimum reading */
+ double maxv[3]; /* Maximum reading */
+ double maxt; /* Time range */
+#ifdef FREQ_SLOW_PRECISE
+ int nbins;
+ double *bins[3]; /* PBPMS sample bins */
+#else
+ double tcorr[NPER]; /* Temp for initial autocorrelation */
+ int ntcorr[NPER]; /* Number accumulated */
+#endif
+ double corr[NPER]; /* Filtered correlation for each period value */
+ double mincv, maxcv; /* Max and min correlation values */
+ double crange; /* Correlation range */
+ double peaks[MAXPKS]; /* Peak wavelength */
+ double peakh[MAXPKS]; /* Peak heighheight */
+ int npeaks; /* Number of peaks */
+ double pval; /* Period value */
+ double rfreq[TRIES]; /* Computed refresh frequency for each try */
+ double rsamp[TRIES]; /* Sampling rate used to measure frequency */
+ int tix = 0; /* try index */
+
+ a1logd(p->log,2,"i1pro_imp_meas_refrate called\n");
+
+ if (!s->emiss) {
+ a1logd(p->log,2,"i1pro_imp_meas_refrate not in emissive mode\n");
+ return I1PRO_UNSUPPORTED;
+ }
+
+ for (mm = 0; mm < TRIES; mm++) {
+ rfreq[mm] = 0.0;
+ npeaks = 0; /* Number of peaks */
+ nummeas = NFSAMPS;
+ multimeas = dmatrix(0, nummeas-1, -1, m->nwav[m->highres]-1);
+
+ if (mm == 0)
+ inttime = m->min_int_time;
+ else {
+ double rval, dmm;
+ randn = PSRAND32L(randn);
+ rval = (double)randn/4294967295.0;
+ dmm = ((double)mm + rval - 0.5)/(TRIES - 0.5);
+ inttime = m->min_int_time * (1.0 + dmm * 0.80);
+ }
+
+ if ((ev = i1pro_read_patches_all(p, multimeas, nummeas, &inttime, 0)) != inst_ok) {
+ free_dmatrix(multimeas, 0, nummeas-1, 0, m->nwav[m->highres]-1);
+ return ev;
+ }
+
+ rsamp[tix] = 1.0/inttime;
+
+ /* Convert the samples to RGB */
+ for (i = 0; i < nummeas && i < NFSAMPS; i++) {
+ samp[i].sec = i * inttime;
+ samp[i].rgb[0] = samp[i].rgb[1] = samp[i].rgb[2] = 0.0;
+ for (j = 0; j < m->nwav[m->highres]; j++) {
+ double wl = XSPECT_WL(m->wl_short[m->highres], m->wl_long[m->highres], m->nwav[m->highres], j);
+
+//printf("~1 multimeas %d %d = %f\n",i, j, multimeas[i][j]);
+ for (k = 0; k < 3; k++) {
+ double tt = (double)(wl - rgbw[k]);
+ tt = (40.0 - fabs(tt))/40.0;
+ if (tt < 0.0)
+ tt = 0.0;
+ samp[i].rgb[k] += tt * multimeas[i][j];
+ }
+ }
+ }
+ nfsamps = i;
+
+ a1logd(p->log, 3, "i1pro_measure_refresh: Read %d samples for refresh calibration\n",nfsamps);
+
+#ifdef NEVER
+ /* Plot the raw sensor values */
+ {
+ double xx[NFSAMPS];
+ double y1[NFSAMPS];
+ double y2[NFSAMPS];
+ double y3[NFSAMPS];
+
+ for (i = 0; i < nfsamps; i++) {
+ xx[i] = samp[i].sec;
+ y1[i] = samp[i].rgb[0];
+ y2[i] = samp[i].rgb[1];
+ y3[i] = samp[i].rgb[2];
+// printf("%d: %f -> %f\n",i,samp[i].sec, samp[i].rgb[0]);
+ }
+ printf("Fast scan sensor values and time (sec)\n");
+ do_plot6(xx, y1, y2, y3, NULL, NULL, NULL, nfsamps);
+ }
+#endif
+
+ /* Locate the smallest values and maximum time */
+ maxt = -1e6;
+ minv[0] = minv[1] = minv[2] = 1e20;
+ maxv[0] = maxv[1] = maxv[2] = -11e20;
+ for (i = nfsamps-1; i >= 0; i--) {
+ if (samp[i].sec > maxt)
+ maxt = samp[i].sec;
+ for (j = 0; j < 3; j++) {
+ if (samp[i].rgb[j] < minv[j])
+ minv[j] = samp[i].rgb[j];
+ if (samp[i].rgb[j] > maxv[j])
+ maxv[j] = samp[i].rgb[j];
+ }
+ }
+ /* Re-zero the sample times, and normalise the readings */
+ for (i = nfsamps-1; i >= 0; i--) {
+ samp[i].sec -= samp[0].sec;
+ samp[i].sec *= ucalf;
+ if (samp[i].sec > maxt)
+ maxt = samp[i].sec;
+ for (j = 0; j < 3; j++) {
+ samp[i].rgb[j] -= minv[j];
+ }
+ }
+
+#ifdef FREQ_SLOW_PRECISE /* Interp then autocorrelate */
+
+ /* Create PBPMS bins and interpolate readings into them */
+ nbins = 1 + (int)(maxt * 1000.0 * PBPMS + 0.5);
+ for (j = 0; j < 3; j++) {
+ if ((bins[j] = (double *)calloc(sizeof(double), nbins)) == NULL) {
+ a1loge(p->log, inst_internal_error, "i1pro_measure_refresh: malloc failed\n");
+ return I1PRO_INT_MALLOC;
+ }
+ }
+
+ /* Do the interpolation */
+ for (k = 0; k < (nfsamps-1); k++) {
+ int sbin, ebin;
+ sbin = (int)(samp[k].sec * 1000.0 * PBPMS + 0.5);
+ ebin = (int)(samp[k+1].sec * 1000.0 * PBPMS + 0.5);
+ for (i = sbin; i <= ebin; i++) {
+ double bl;
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ bl = (i - sbin)/(double)(ebin - sbin); /* 0.0 to 1.0 */
+ for (j = 0; j < 3; j++) {
+ bins[j][i] = (1.0 - bl) * samp[k].rgb[j] + bl * samp[k+1].rgb[j];
+ }
+ }
+ }
+
+#ifdef NEVER
+
+ /* Plot interpolated values */
+ {
+ double *xx;
+ double *y1;
+ double *y2;
+ double *y3;
+
+ xx = malloc(sizeof(double) * nbins);
+ y1 = malloc(sizeof(double) * nbins);
+ y2 = malloc(sizeof(double) * nbins);
+ y3 = malloc(sizeof(double) * nbins);
+
+ if (xx == NULL || y1 == NULL || y2 == NULL || y3 == NULL) {
+ a1loge(p->log, inst_internal_error, "i1pro_measure_refresh: malloc failed\n");
+ for (j = 0; j < 3; j++)
+ free(bins[j]);
+ return I1PRO_INT_MALLOC;
+ }
+ for (i = 0; i < nbins; i++) {
+ xx[i] = i / (double)PBPMS; /* msec */
+ y1[i] = bins[0][i];
+ y2[i] = bins[1][i];
+ y3[i] = bins[2][i];
+ }
+ printf("Interpolated fast scan sensor values and time (msec) for inttime %f\n",inttime);
+ do_plot6(xx, y1, y2, y3, NULL, NULL, NULL, nbins);
+
+ free(xx);
+ free(y1);
+ free(y2);
+ free(y3);
+ }
+#endif /* PLOT_REFRESH */
+
+ /* Compute auto-correlation at 1/PBPMS msec intervals */
+ /* from 25 msec (40Hz) to 100msec (10 Hz) */
+ mincv = 1e48, maxcv = -1e48;
+ for (i = 0; i < NPER; i++) {
+ int poff = PERMIN + i; /* Offset to corresponding sample */
+
+ corr[i] = 0;
+ for (k = 0; (k + poff) < nbins; k++) {
+ corr[i] += bins[0][k] * bins[0][k + poff]
+ + bins[1][k] * bins[1][k + poff]
+ + bins[2][k] * bins[2][k + poff];
+ }
+ corr[i] /= (double)k; /* Normalize */
+
+ if (corr[i] > maxcv)
+ maxcv = corr[i];
+ if (corr[i] < mincv)
+ mincv = corr[i];
+ }
+ /* Free the bins */
+ for (j = 0; j < 3; j++)
+ free(bins[j]);
+
+#else /* !FREQ_SLOW_PRECISE Fast - autocorrellate then filter */
+
+ /* Upsample by a factor of 2 */
+ for (i = nfsamps-1; i >= 0; i--) {
+ j = 2 * i;
+ samp[j].sec = samp[i].sec;
+ samp[j].rgb[0] = samp[i].rgb[0];
+ samp[j].rgb[1] = samp[i].rgb[1];
+ samp[j].rgb[2] = samp[i].rgb[2];
+ if (i > 0) {
+ j--;
+ samp[j].sec = 0.5 * (samp[i].sec + samp[i-1].sec);
+ samp[j].rgb[0] = 0.5 * (samp[i].rgb[0] + samp[i-1].rgb[0]);
+ samp[j].rgb[1] = 0.5 * (samp[i].rgb[1] + samp[i-1].rgb[1]);
+ samp[j].rgb[2] = 0.5 * (samp[i].rgb[2] + samp[i-1].rgb[2]);
+ }
+ }
+ nfsamps = 2 * nfsamps - 1;
+
+ /* Do point by point correllation of samples */
+ for (i = 0; i < NPER; i++) {
+ tcorr[i] = 0.0;
+ ntcorr[i] = 0;
+ }
+
+ for (j = 0; j < (nfsamps-1); j++) {
+
+ for (k = j+1; k < nfsamps; k++) {
+ double del, cor;
+ int bix;
+
+ del = samp[k].sec - samp[j].sec;
+ bix = (int)(del * 1000.0 * PBPMS + 0.5);
+ if (bix < PERMIN)
+ continue;
+ if (bix > PERMAX)
+ break;
+ bix -= PERMIN;
+
+ cor = samp[j].rgb[0] * samp[k].rgb[0]
+ + samp[j].rgb[1] * samp[k].rgb[1]
+ + samp[j].rgb[2] * samp[k].rgb[2];
+
+//printf("~1 j %d k %d, del %f bix %d cor %f\n",j,k,del,bix,cor);
+ tcorr[bix] += cor;
+ ntcorr[bix]++;
+ }
+ }
+ /* Divide out count and linearly interpolate */
+ j = 0;
+ for (i = 0; i < NPER; i++) {
+ if (ntcorr[i] > 0) {
+ tcorr[i] /= ntcorr[i];
+ if ((i - j) > 1) {
+ if (j == 0) {
+ for (k = j; k < i; k++)
+ tcorr[k] = tcorr[i];
+
+ } else { /* Linearly interpolate from last value */
+ double ww = (double)i-j;
+ for (k = j+1; k < i; k++) {
+ double bl = (k-j)/ww;
+ tcorr[k] = (1.0 - bl) * tcorr[j] + bl * tcorr[i];
+ }
+ }
+ }
+ j = i;
+ }
+ }
+ if (j < (NPER-1)) {
+ for (k = j+1; k < NPER; k++) {
+ tcorr[k] = tcorr[j];
+ }
+ }
+
+#ifdef PLOT_REFRESH
+ /* Plot unfiltered auto correlation */
+ {
+ double xx[NPER];
+ double y1[NPER];
+
+ for (i = 0; i < NPER; i++) {
+ xx[i] = (i + PERMIN) / (double)PBPMS; /* msec */
+ y1[i] = tcorr[i];
+ }
+ printf("Unfiltered auto correlation (msec)\n");
+ do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, NPER);
+ }
+#endif /* PLOT_REFRESH */
+
+ /* Apply a gausian filter */
+#define FWIDTH 100
+ {
+ double gaus_[2 * FWIDTH * PBPMS + 1];
+ double *gaus = &gaus_[FWIDTH * PBPMS];
+ double bb = 1.0/pow(2, 5.0);
+ double fw = inttime * 1000.0;
+ int ifw;
+
+//printf("~1 sc = %f = %f msec\n",1.0/inttime, fw);
+//printf("~1 fw = %f, ifw = %d\n",fw,ifw);
+
+ fw *= 0.9;
+ ifw = (int)ceil(fw * PBPMS);
+ if (ifw > FWIDTH * PBPMS)
+ error("i1pro: Not enough space for lanczos 2 filter");
+ for (j = -ifw; j <= ifw; j++) {
+ double x, y;
+ x = j/(PBPMS * fw);
+ if (fabs(x) > 1.0)
+ y = 0.0;
+ else
+ y = 1.0/pow(2, 5.0 * x * x) - bb;
+ gaus[j] = y;
+//printf("~1 gaus[%d] = %f\n",j,y);
+ }
+
+ for (i = 0; i < NPER; i++) {
+ double sum = 0.0;
+ double wght = 0.0;
+
+ for (j = -ifw; j <= ifw; j++) {
+ double w;
+ int ix = i + j;
+ if (ix < 0)
+ ix = -ix;
+ if (ix > (NPER-1))
+ ix = 2 * NPER-1 - ix;
+ w = gaus[j];
+ sum += w * tcorr[ix];
+ wght += w;
+ }
+//printf("~1 corr[%d] wgt = %f\n",i,wght);
+ corr[i] = sum / wght;
+ }
+ }
+
+ /* Compute min & max */
+ mincv = 1e48, maxcv = -1e48;
+ for (i = 0; i < NPER; i++) {
+ if (corr[i] > maxcv)
+ maxcv = corr[i];
+ if (corr[i] < mincv)
+ mincv = corr[i];
+ }
+
+#endif /* !FREQ_SLOW_PRECISE Fast - autocorrellate then filter */
+
+ crange = maxcv - mincv;
+ a1logd(p->log,3,"Correlation value range %f - %f = %f = %f%%\n",mincv, maxcv,crange, 100.0 * (maxcv-mincv)/maxcv);
+
+#ifdef PLOT_REFRESH
+ /* Plot this measuremnts auto correlation */
+ {
+ double xx[NPER];
+ double y1[NPER];
+
+ for (i = 0; i < NPER; i++) {
+ xx[i] = (i + PERMIN) / (double)PBPMS; /* msec */
+ y1[i] = corr[i];
+ }
+ printf("Auto correlation (msec)\n");
+ do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, NPER);
+ }
+#endif /* PLOT_REFRESH */
+
+#define PFDB 4 // normally 4
+ /* If there is sufficient level and distict correlations */
+ if (crange/maxcv >= 0.1) {
+
+ a1logd(p->log,PFDB,"Searching for peaks\n");
+
+ /* Locate all the peaks starting at the longest correllation */
+ for (i = (NPER-1-PWIDTH); i >= 0 && npeaks < MAXPKS; i--) {
+ double v1, v2, v3;
+ v1 = corr[i];
+ v2 = corr[i + PWIDTH/2]; /* Peak */
+ v3 = corr[i + PWIDTH];
+
+ if (fabs(v3 - v1)/crange < 0.05
+ && (v2 - v1)/crange > 0.025
+ && (v2 - v3)/crange > 0.025
+ && (v2 - mincv)/crange > 0.5) {
+ double pkv; /* Peak value */
+ int pki; /* Peak index */
+ double ii, bl;
+
+#ifdef PLOT_REFRESH
+ a1logd(p->log,PFDB,"Max between %f and %f msec\n",
+ (i + PERMIN)/(double)PBPMS,(i + PWIDTH + PERMIN)/(double)PBPMS);
+#endif
+
+ /* Locate the actual peak */
+ pkv = -1.0;
+ pki = 0;
+ for (j = i; j < (i + PWIDTH); j++) {
+ if (corr[j] > pkv) {
+ pkv = corr[j];
+ pki = j;
+ }
+ }
+#ifdef PLOT_REFRESH
+ a1logd(p->log,PFDB,"Peak is at %f msec, %f corr\n", (pki + PERMIN)/(double)PBPMS, pkv);
+#endif
+
+ /* Interpolate the peak value for higher precision */
+ /* j = bigest */
+ if (corr[pki-1] > corr[pki+1]) {
+ j = pki-1;
+ k = pki+1;
+ } else {
+ j = pki+1;
+ k = pki-1;
+ }
+ bl = (corr[pki] - corr[j])/(corr[pki] - corr[k]);
+ bl = (bl + 1.0)/2.0;
+ ii = bl * pki + (1.0 - bl) * j;
+ pval = (ii + PERMIN)/(double)PBPMS;
+#ifdef PLOT_REFRESH
+ a1logd(p->log,PFDB,"Interpolated peak is at %f msec\n", pval);
+#endif
+ peaks[npeaks] = pval;
+ peakh[npeaks] = corr[pki];
+ npeaks++;
+
+ i -= PWIDTH;
+ }
+#ifdef NEVER
+ if (v2 > v1 && v2 > v3) {
+ printf("Peak rehjected:\n");
+ printf("(v3 - v1)/crange = %f < 0.05 ?\n",fabs(v3 - v1)/crange);
+ printf("(v2 - v1)/crange = %f > 0.025 ?\n",(v2 - v1)/crange);
+ printf("(v2 - v3)/crange = %f > 0.025 ?\n",(v2 - v3)/crange);
+ printf("(v2 - mincv)/crange = %f > 0.5 ?\n",(v2 - mincv)/crange);
+ }
+#endif
+ }
+ a1logd(p->log,3,"Number of peaks located = %d\n",npeaks);
+
+ } else {
+ a1logd(p->log,3,"All rejected, crange/maxcv = %f < 0.06\n",crange/maxcv);
+ }
+#undef PFDB
+
+ a1logd(p->log,3,"Number of peaks located = %d\n",npeaks);
+
+ if (npeaks > 1) { /* Compute aparent refresh rate */
+ int nfails;
+ double div, avg, ano;
+ /* Try and locate a common divisor amongst all the peaks. */
+ /* This is likely to be the underlying refresh rate. */
+ for (k = 0; k < npeaks; k++) {
+ for (j = 1; j < 25; j++) {
+ avg = ano = 0.0;
+ div = peaks[k]/(double)j;
+ if (div < 5.0)
+ continue; /* Skip anything higher than 200Hz */
+//printf("~1 trying %f Hz\n",1000.0/div);
+ for (nfails = i = 0; i < npeaks; i++) {
+ double rem, cnt;
+
+ rem = peaks[i]/div;
+ cnt = floor(rem + 0.5);
+ rem = fabs(rem - cnt);
+
+#ifdef PLOT_REFRESH
+ a1logd(p->log, 3, "remainder for peak %d = %f\n",i,rem);
+#endif
+ if (rem > 0.06) {
+ if (++nfails > 2)
+ break; /* Fail this divisor */
+ } else {
+ avg += peaks[i]; /* Already weighted by cnt */
+ ano += cnt;
+ }
+ }
+
+ if (nfails == 0 || (nfails <= 2 && npeaks >= 6))
+ break; /* Sucess */
+ /* else go and try a different divisor */
+ }
+ if (j < 25)
+ break; /* Success - found common divisor */
+ }
+ if (k >= npeaks) {
+ a1logd(p->log,3,"Failed to locate common divisor\n");
+
+ } else {
+ pval = 0.001 * avg/ano;
+ if (pval < inttime) {
+ a1logd(p->log,3,"Discarding frequency %f > sample rate %f\n",1.0/pval, 1.0/inttime);
+ } else {
+ pval = 1.0/pval; /* Convert to frequency */
+ rfreq[tix++] = pval;
+ a1logd(p->log,3,"Located frequency %f sum %f dif %f\n",pval, pval + 1.0/inttime, fabs(pval - 1.0/inttime));
+ }
+ }
+ }
+ }
+
+ if (tix >= 3) {
+
+ for (mm = 0; mm < tix; mm++) {
+ a1logd(p->log, 3, "Try %d, samp %f Hz, Meas %f Hz, Sum %f Hz, Dif %f Hz\n",mm,rsamp[mm],rfreq[mm], rsamp[mm] + rfreq[mm], fabs(rsamp[mm] - rfreq[mm]));
+ }
+
+ /* Decide if we are above the nyquist, or whether */
+ /* we have aliases of the fundamental */
+ {
+ double brange = 1e38;
+ double brate = 0.0;
+ int bsplit = -1;
+ double min, max, avg, range;
+ int split, mul, niia;
+
+ /* Compute fundamental and sub aliases at all possible splits. */
+ /* Skip the reading at the split. */
+ for (split = tix; split >= -1; split--) {
+ min = 1e38; max = -1e38; avg = 0.0; niia = 0;
+ for (mm = 0; mm < tix; mm++) {
+ double alias;
+
+ if (mm == split)
+ continue;
+ if (mm < split)
+ alias = rfreq[mm];
+ else
+ alias = fabs(rsamp[mm] - rfreq[mm]);
+
+ avg += alias;
+ niia++;
+
+ if (alias < min)
+ min = alias;
+ if (alias > max)
+ max = alias;
+ }
+ avg /= (double)niia;
+ range = (max - min)/(max + min);
+//printf("~1 split %d avg = %f, range = %f\n",split,avg,range);
+ if (range < brange) {
+ brange = range;
+ brate = avg;
+ bsplit = split;
+ }
+ }
+
+ /* Compute sub and add aliases at all possible splits */
+ /* Skip the reading at the split. */
+ for (split = tix; split >= -1; split--) {
+ min = 1e38; max = -1e38; avg = 0.0; niia = 0;
+ for (mm = 0; mm < tix; mm++) {
+ double alias;
+
+ if (mm == split)
+ continue;
+ if (mm < split)
+ alias = fabs(rsamp[mm] - rfreq[mm]);
+ else
+ alias = rsamp[mm] + rfreq[mm];
+
+ avg += alias;
+ niia++;
+
+ if (alias < min)
+ min = alias;
+ if (alias > max)
+ max = alias;
+ }
+ avg /= (double)niia;
+ range = (max - min)/(max + min);
+//printf("~1 split %d avg = %f, range = %f\n",100 + split,avg,range);
+ if (range < brange) {
+ brange = range;
+ brate = avg;
+ bsplit = 100 + split;
+ }
+ }
+
+ a1logd(p->log, 3, "Selected split %d range %f\n",bsplit,brange);
+
+ /* Hmm. Could reject result and re-try if brange is too large ? ( > 0.005 ?) */
+
+ if (brange > 0.05) {
+ a1logd(p->log, 3, "Readings are too inconsistent (brange %.1f%%) - should retry ?\n",brange * 100.0);
+ } else {
+ if (ref_rate != NULL)
+ *ref_rate = brate;
+
+ /* Error against my 85Hz CRT - GWG */
+// a1logd(p->log, 1, "Refresh rate %f Hz, error = %.4f%%\n",brate,100.0 * fabs(brate - 85.0)/(85.0));
+ return I1PRO_OK;
+ }
+ }
+ } else {
+ a1logd(p->log, 3, "Not enough tries suceeded to determine refresh rate\n");
+ }
+
+ if (ref_rate != NULL)
+ *ref_rate = 0.0;
+
+ return I1PRO_RD_NOREFR_FOUND;
+}
+#undef NFSAMPS
+#undef PBPMS
+#undef PERMIN
+#undef PERMAX
+#undef NPER
+#undef PWIDTH
+
+/* - - - - - - - - - - - - - - - - - - - - - - */
+/* i1 refspot calibration/log stored on instrument */
+/* RevA..D only! */
+
+/* Restore the reflective spot calibration information from the EEPRom */
+/* Always returns success, even if the restore fails, */
+/* which may happen for an instrument that's never been used or had calibration */
+/* written to its EEProm */
+/* RevA..D only! */
+i1pro_code i1pro_restore_refspot_cal(i1pro *p) {
+ int chsum1, *chsum2;
+ int *ip, i;
+ unsigned int count;
+ double *dp;
+ unsigned char buf[256];
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[i1p_refl_spot]; /* NOT current mode, refspot mode */
+ i1key offst = 0; /* Offset to copy to use */
+ i1pro_code ev = I1PRO_OK;
+ int o_nsen; /* Actual nsen data */
+
+ a1logd(p->log,2,"Doing Restoring reflective spot calibration information from the EEProm\n");
+
+ chsum1 = m->data->checksum(m->data, 0);
+ if ((chsum2 = m->data->get_int(m->data, key_checksum, 0)) == NULL || chsum1 != *chsum2) {
+ offst = key_2logoff;
+ chsum1 = m->data->checksum(m->data, key_2logoff);
+ if ((chsum2 = m->data->get_int(m->data, key_checksum + key_2logoff, 0)) == NULL
+ || chsum1 != *chsum2) {
+ a1logd(p->log,2,"Neither EEPRom checksum was valid\n");
+ return I1PRO_OK;
+ }
+ }
+
+ /* Get the calibration gain mode */
+ if ((ip = m->data->get_ints(m->data, &count, key_gainmode + offst)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to read calibration gain mode from EEPRom\n");
+ return I1PRO_OK;
+ }
+ if (ip[0] == 0) {
+#ifdef USE_HIGH_GAIN_MODE
+ s->gainmode = 1;
+#else
+ s->gainmode = 0;
+ a1logd(p->log,2,"Calibration gain mode was high, and high gain not compiled in\n");
+ return I1PRO_OK;
+#endif /* !USE_HIGH_GAIN_MODE */
+ } else
+ s->gainmode = 0;
+
+ /* Get the calibration integrattion time */
+ if ((dp = m->data->get_doubles(m->data, &count, key_inttime + offst)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to read calibration integration time from EEPRom\n");
+ return I1PRO_OK;
+ }
+ s->inttime = dp[0];
+ if (s->inttime < m->min_int_time) /* Hmm. EEprom is occasionaly screwed up */
+ s->inttime = m->min_int_time;
+
+ /* Get the dark data */
+ if ((ip = m->data->get_ints(m->data, &count, key_darkreading + offst)) == NULL
+ || count != 128) {
+ a1logv(p->log,1,"Failed to read calibration dark data from EEPRom\n");
+ return I1PRO_OK;
+ }
+
+ /* Convert back to a single raw big endian instrument readings */
+ for (i = 0; i < 128; i++) {
+ buf[i * 2 + 0] = (ip[i] >> 8) & 0xff;
+ buf[i * 2 + 1] = ip[i] & 0xff;
+ }
+
+ /* Convert to calibration data */
+ a1logd(p->log,3,"Calling black calibration_2 calc with nummeas %d, inttime %f, gainmode %d\n", 1, s->inttime,s->gainmode);
+ o_nsen = m->nsen;
+ m->nsen = 128; /* Assume EEprom cal data is <= Rev D format */
+ if ((ev = i1pro_dark_measure_2(p, s->dark_data, 1, s->inttime, s->gainmode,
+ buf, 256)) != I1PRO_OK) {
+ a1logd(p->log,2,"Failed to convert EEProm dark data to calibration\n");
+ m->nsen = o_nsen;
+ return I1PRO_OK;
+ }
+
+ /* We've sucessfully restored the dark calibration */
+ s->dark_valid = 1;
+ s->ddate = m->caldate;
+
+ /* Get the white calibration data */
+ if ((ip = m->data->get_ints(m->data, &count, key_whitereading + offst)) == NULL
+ || count != 128) {
+ a1logd(p->log,2,"Failed to read calibration white data from EEPRom\n");
+ m->nsen = o_nsen;
+ return I1PRO_OK;
+ }
+
+ /* Convert back to a single raw big endian instrument readings */
+ for (i = 0; i < 128; i++) {
+ buf[i * 2 + 0] = (ip[i] >> 8) & 0xff;
+ buf[i * 2 + 1] = ip[i] & 0xff;
+ }
+
+ /* Convert to calibration data */
+ m->nsen = 128; /* Assume EEprom cal data is <= Rev D format */
+ if ((ev = i1pro_whitemeasure_buf(p, s->cal_factor[0], s->cal_factor[1], s->white_data,
+ s->inttime, s->gainmode, buf)) != I1PRO_OK) {
+ /* This may happen for an instrument that's never been used */
+ a1logd(p->log,2,"Failed to convert EEProm white data to calibration\n");
+ m->nsen = o_nsen;
+ return I1PRO_OK;
+ }
+ m->nsen = o_nsen;
+
+ /* Check a reflective white measurement, and check that */
+ /* it seems reasonable. Return I1PRO_OK if it is, error if not. */
+ /* (Using cal_factor[] as temp.) */
+ if ((ev = i1pro_check_white_reference1(p, s->cal_factor[0])) != I1PRO_OK) {
+ /* This may happen for an instrument that's never been used */
+ a1logd(p->log,2,"Failed to convert EEProm white data to calibration\n");
+ return I1PRO_OK;
+ }
+ /* Compute a calibration factor given the reading of the white reference. */
+ i1pro_compute_white_cal(p, s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
+ s->cal_factor[1], m->white_ref[1], s->cal_factor[1]);
+
+ /* We've sucessfully restored the calibration */
+ s->cal_valid = 1;
+ s->cfdate = m->caldate;
+
+ return I1PRO_OK;
+}
+
+/* Save the reflective spot calibration information to the EEPRom data object. */
+/* Note we don't actually write to the EEProm here! */
+/* For RevA..D only! */
+static i1pro_code i1pro_set_log_data(i1pro *p) {
+ int *ip, i;
+ unsigned int count;
+ double *dp;
+ double absmeas[128];
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[i1p_refl_spot]; /* NOT current mode, refspot mode */
+ i1key offst = 0; /* Offset to copy to use */
+ i1pro_code ev = I1PRO_OK;
+
+ a1logd(p->log,3,"i1pro_set_log_data called\n");
+
+ if (s->dark_valid == 0 || s->cal_valid == 0)
+ return I1PRO_INT_NO_CAL_TO_SAVE;
+
+ /* Set the calibration gain mode */
+ if ((ip = m->data->get_ints(m->data, &count, key_gainmode + offst)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to access calibration gain mode from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ if (s->gainmode == 0)
+ ip[0] = 1;
+ else
+ ip[0] = 0;
+
+ /* Set the calibration integration time */
+ if ((dp = m->data->get_doubles(m->data, &count, key_inttime + offst)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to read calibration integration time from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ dp[0] = s->inttime;
+
+ /* Set the dark data */
+ if ((ip = m->data->get_ints(m->data, &count, key_darkreading + offst)) == NULL
+ || count != 128) {
+ a1logd(p->log,2,"Failed to access calibration dark data from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+
+ /* Convert abs dark_data to raw data */
+ if ((ev = i1pro_absraw_to_meas(p, ip, s->dark_data, s->inttime, s->gainmode)) != I1PRO_OK)
+ return ev;
+
+ /* Add back black level to white data */
+ for (i = 0; i < 128; i++)
+ absmeas[i] = s->white_data[i] + s->dark_data[i];
+
+ /* Get the white data */
+ if ((ip = m->data->get_ints(m->data, &count, key_whitereading + offst)) == NULL
+ || count != 128) {
+ a1logd(p->log,2,"Failed to access calibration white data from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+
+ /* Convert abs white_data to raw data */
+ if ((ev = i1pro_absraw_to_meas(p, ip, absmeas, s->inttime, s->gainmode)) != I1PRO_OK)
+ return ev;
+
+ /* Set all the log counters */
+
+ /* Total Measure (Emis/Remis/Ambient/Trans/Cal) count */
+ if ((ip = m->data->get_ints(m->data, &count, key_meascount)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to access meascount log counter from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ ip[0] = m->meascount;
+
+ /* Remspotcal last calibration date */
+ if ((ip = m->data->get_ints(m->data, &count, key_caldate)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to access caldate log counter from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ ip[0] = m->caldate;
+
+ /* Remission spot measure count at last Remspotcal. */
+ if ((ip = m->data->get_ints(m->data, &count, key_calcount)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to access calcount log counter from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ ip[0] = m->calcount;
+
+ /* Last remision spot reading integration time */
+ if ((dp = m->data->get_doubles(m->data, &count, key_rpinttime)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to access rpinttime log counter from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ dp[0] = m->rpinttime;
+
+ /* Remission spot measure count */
+ if ((ip = m->data->get_ints(m->data, &count, key_rpcount)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to access rpcount log counter from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ ip[0] = m->rpcount;
+
+ /* Remission scan measure count (??) */
+ if ((ip = m->data->get_ints(m->data, &count, key_acount)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to access acount log counter from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ ip[0] = m->acount;
+
+ /* Total lamp usage time in seconds (??) */
+ if ((dp = m->data->get_doubles(m->data, &count, key_lampage)) == NULL || count < 1) {
+ a1logd(p->log,2,"Failed to access lampage log counter from EEPRom\n");
+ return I1PRO_INT_EEPROM_DATA_MISSING;
+ }
+ dp[0] = m->lampage;
+
+ a1logd(p->log,5,"i1pro_set_log_data done\n");
+
+ return I1PRO_OK;
+}
+
+/* Update the single remission calibration and instrument usage log */
+/* For RevA..D only! */
+i1pro_code i1pro_update_log(i1pro *p) {
+ i1pro_code ev = I1PRO_OK;
+#ifdef ENABLE_WRITE
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char *buf; /* Buffer to write to EEProm */
+ unsigned int len;
+
+ a1logd(p->log,5,"i1pro_update_log:\n");
+
+ /* Copy refspot calibration and log data to EEProm data store */
+ if ((ev = i1pro_set_log_data(p)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_update_log i1pro_set_log_data failed\n");
+ return ev;
+ }
+
+ /* Compute checksum and serialise into buffer ready to write */
+ if ((ev = m->data->prep_section1(m->data, &buf, &len)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_update_log prep_section1 failed\n");
+ return ev;
+ }
+
+ /* First copy of log */
+ if ((ev = i1pro_writeEEProm(p, buf, 0x0000, len)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_update_log i1pro_writeEEProm 0x0000 failed\n");
+ return ev;
+ }
+ /* Second copy of log */
+ if ((ev = i1pro_writeEEProm(p, buf, 0x0800, len)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_update_log i1pro_writeEEProm 0x0800 failed\n");
+ return ev;
+ }
+ free(buf);
+
+ a1logd(p->log,5,"i1pro_update_log done\n");
+#else
+ a1logd(p->log,5,"i1pro_update_log: skipped as EPRom write is disabled\n");
+#endif
+
+ return ev;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Save the calibration for all modes, stored on local system */
+
+#ifdef ENABLE_NONVCAL
+
+/* non-volatile save/restor state */
+typedef struct {
+ int ef; /* Error flag, 1 = write failed, 2 = close failed */
+ unsigned int chsum; /* Checksum */
+ int nbytes; /* Number of bytes checksummed */
+} i1pnonv;
+
+static void update_chsum(i1pnonv *x, unsigned char *p, int nn) {
+ int i;
+ for (i = 0; i < nn; i++, p++)
+ x->chsum = ((x->chsum << 13) | (x->chsum >> (32-13))) + *p;
+ x->nbytes += nn;
+}
+
+/* Write an array of ints to the file. Set the error flag to nz on error */
+static void write_ints(i1pnonv *x, FILE *fp, int *dp, int n) {
+
+ if (fwrite((void *)dp, sizeof(int), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(int));
+ }
+}
+
+/* Write an array of doubles to the file. Set the error flag to nz on error */
+static void write_doubles(i1pnonv *x, FILE *fp, double *dp, int n) {
+
+ if (fwrite((void *)dp, sizeof(double), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(double));
+ }
+}
+
+/* Write an array of time_t's to the file. Set the error flag to nz on error */
+/* (This will cause file checksum fail if different executables on the same */
+/* system have different time_t values) */
+static void write_time_ts(i1pnonv *x, FILE *fp, time_t *dp, int n) {
+
+ if (fwrite((void *)dp, sizeof(time_t), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(time_t));
+ }
+}
+
+/* Read an array of ints from the file. Set the error flag to nz on error */
+static void read_ints(i1pnonv *x, FILE *fp, int *dp, int n) {
+
+ if (fread((void *)dp, sizeof(int), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(int));
+ }
+}
+
+/* Read an array of doubles from the file. Set the error flag to nz on error */
+static void read_doubles(i1pnonv *x, FILE *fp, double *dp, int n) {
+
+ if (fread((void *)dp, sizeof(double), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(double));
+ }
+}
+
+/* Read an array of time_t's from the file. Set the error flag to nz on error */
+/* (This will cause file checksum fail if different executables on the same */
+/* system have different time_t values) */
+static void read_time_ts(i1pnonv *x, FILE *fp, time_t *dp, int n) {
+
+ if (fread((void *)dp, sizeof(time_t), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(time_t));
+ }
+}
+
+i1pro_code i1pro_save_calibration(i1pro *p) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+ i1pro_state *s;
+ int i;
+ char nmode[10];
+ char cal_name[100]; /* Name */
+ char **cal_paths = NULL;
+ int no_paths = 0;
+ FILE *fp;
+ i1pnonv x;
+ int ss;
+ int argyllversion = ARGYLL_VERSION;
+
+ strcpy(nmode, "w");
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ strcat(nmode, "b");
+#endif
+
+ /* Create the file name */
+ sprintf(cal_name, "ArgyllCMS/.i1p_%d.cal", m->serno);
+ if ((no_paths = xdg_bds(NULL, &cal_paths, xdg_cache, xdg_write, xdg_user, cal_name)) < 1) {
+ a1logd(p->log,1,"i1pro_save_calibration xdg_bds returned no paths\n");
+ return I1PRO_INT_CAL_SAVE;
+ }
+
+ a1logd(p->log,2,"i1pro_save_calibration saving to file '%s'\n",cal_paths[0]);
+
+ if (create_parent_directories(cal_paths[0])
+ || (fp = fopen(cal_paths[0], nmode)) == NULL) {
+ a1logd(p->log,2,"i1pro_save_calibration failed to open file for writing\n");
+ xdg_free(cal_paths, no_paths);
+ return I1PRO_INT_CAL_SAVE;
+ }
+
+ x.ef = 0;
+ x.chsum = 0;
+ x.nbytes = 0;
+
+ /* A crude structure signature */
+ ss = sizeof(i1pro_state) + sizeof(i1proimp);
+
+ /* Some file identification */
+ write_ints(&x, fp, &argyllversion, 1);
+ write_ints(&x, fp, &ss, 1);
+ write_ints(&x, fp, &m->serno, 1);
+ write_ints(&x, fp, (int *)&m->nraw, 1);
+ write_ints(&x, fp, (int *)&m->nwav[0], 1);
+ write_ints(&x, fp, (int *)&m->nwav[1], 1);
+
+ /* For each mode, save the calibration if it's valid */
+ for (i = 0; i < i1p_no_modes; i++) {
+ s = &m->ms[i];
+
+ /* Mode identification */
+ write_ints(&x, fp, &s->emiss, 1);
+ write_ints(&x, fp, &s->trans, 1);
+ write_ints(&x, fp, &s->reflective, 1);
+ write_ints(&x, fp, &s->scan, 1);
+ write_ints(&x, fp, &s->flash, 1);
+ write_ints(&x, fp, &s->ambient, 1);
+ write_ints(&x, fp, &s->adaptive, 1);
+
+ /* Configuration calibration is valid for */
+ write_ints(&x, fp, &s->gainmode, 1);
+ write_doubles(&x, fp, &s->inttime, 1);
+
+ /* Calibration information */
+ write_ints(&x, fp, &s->wl_valid, 1);
+ write_time_ts(&x, fp, &s->wldate, 1);
+ write_doubles(&x, fp, &s->wl_led_off, 1);
+ write_ints(&x, fp, &s->dark_valid, 1);
+ write_time_ts(&x, fp, &s->ddate, 1);
+ write_doubles(&x, fp, &s->dark_int_time, 1);
+ write_doubles(&x, fp, s->dark_data-1, m->nraw+1);
+ write_doubles(&x, fp, &s->dark_int_time2, 1);
+ write_doubles(&x, fp, s->dark_data2-1, m->nraw+1);
+ write_doubles(&x, fp, &s->dark_int_time3, 1);
+ write_doubles(&x, fp, s->dark_data3-1, m->nraw+1);
+ write_ints(&x, fp, &s->dark_gain_mode, 1);
+
+ if (!s->emiss) {
+ write_ints(&x, fp, &s->cal_valid, 1);
+ write_time_ts(&x, fp, &s->cfdate, 1);
+ write_doubles(&x, fp, s->cal_factor[0], m->nwav[0]);
+ write_doubles(&x, fp, s->cal_factor[1], m->nwav[1]);
+ write_doubles(&x, fp, s->white_data-1, m->nraw+1);
+ }
+
+ write_ints(&x, fp, &s->idark_valid, 1);
+ write_time_ts(&x, fp, &s->iddate, 1);
+ write_doubles(&x, fp, s->idark_int_time, 4);
+ write_doubles(&x, fp, s->idark_data[0]-1, m->nraw+1);
+ write_doubles(&x, fp, s->idark_data[1]-1, m->nraw+1);
+ write_doubles(&x, fp, s->idark_data[2]-1, m->nraw+1);
+ write_doubles(&x, fp, s->idark_data[3]-1, m->nraw+1);
+ }
+
+ a1logd(p->log,3,"nbytes = %d, Checkum = 0x%x\n",x.nbytes,x.chsum);
+ write_ints(&x, fp, (int *)&x.chsum, 1);
+
+ if (fclose(fp) != 0)
+ x.ef = 2;
+
+ if (x.ef != 0) {
+ a1logd(p->log,2,"Writing calibration file failed with %d\n",x.ef);
+ delete_file(cal_paths[0]);
+ return I1PRO_INT_CAL_SAVE;
+ } else {
+ a1logd(p->log,2,"Writing calibration file succeeded\n");
+ }
+ xdg_free(cal_paths, no_paths);
+
+ return ev;
+}
+
+/* Restore the all modes calibration from the local system */
+i1pro_code i1pro_restore_calibration(i1pro *p) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+ i1pro_state *s, ts;
+ int i, j;
+ char nmode[10];
+ char cal_name[100]; /* Name */
+ char **cal_paths = NULL;
+ int no_paths = 0;
+ FILE *fp;
+ i1pnonv x;
+ int argyllversion;
+ int ss, serno, nraw, nwav0, nwav1, nbytes, chsum1, chsum2;
+
+ strcpy(nmode, "r");
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ strcat(nmode, "b");
+#endif
+ /* Create the file name */
+ sprintf(cal_name, "ArgyllCMS/.i1p_%d.cal" SSEPS "color/.i1p_%d.cal", m->serno, m->serno);
+ if ((no_paths = xdg_bds(NULL, &cal_paths, xdg_cache, xdg_read, xdg_user, cal_name)) < 1) {
+ a1logd(p->log,2,"i1pro_restore_calibration xdg_bds failed to locate file'\n");
+ return I1PRO_INT_CAL_RESTORE;
+ }
+
+ a1logd(p->log,2,"i1pro_restore_calibration restoring from file '%s'\n",cal_paths[0]);
+
+ /* Check the last modification time */
+ {
+ struct sys_stat sbuf;
+
+ if (sys_stat(cal_paths[0], &sbuf) == 0) {
+ m->lo_secs = time(NULL) - sbuf.st_mtime;
+ a1logd(p->log,2,"i1pro_restore_calibration: %d secs from instrument last open\n",m->lo_secs);
+ } else {
+ a1logd(p->log,2,"i1pro_restore_calibration: stat on file failed\n");
+ }
+ }
+
+ if ((fp = fopen(cal_paths[0], nmode)) == NULL) {
+ a1logd(p->log,2,"i1pro_restore_calibration failed to open file for reading\n");
+ xdg_free(cal_paths, no_paths);
+ return I1PRO_INT_CAL_RESTORE;
+ }
+
+ x.ef = 0;
+ x.chsum = 0;
+ x.nbytes = 0;
+
+ /* Check the file identification */
+ read_ints(&x, fp, &argyllversion, 1);
+ read_ints(&x, fp, &ss, 1);
+ read_ints(&x, fp, &serno, 1);
+ read_ints(&x, fp, &nraw, 1);
+ read_ints(&x, fp, &nwav0, 1);
+ read_ints(&x, fp, &nwav1, 1);
+ if (x.ef != 0
+ || argyllversion != ARGYLL_VERSION
+ || ss != (sizeof(i1pro_state) + sizeof(i1proimp))
+ || serno != m->serno
+ || nraw != m->nraw
+ || nwav0 != m->nwav[0]
+ || nwav1 != m->nwav[1]) {
+ a1logd(p->log,2,"Identification didn't verify\n");
+ goto reserr;
+ }
+
+ /* Do a dummy read to check the checksum */
+ for (i = 0; i < i1p_no_modes; i++) {
+ int di;
+ double dd;
+ time_t dt;
+ int emiss, trans, reflective, ambient, scan, flash, adaptive;
+
+ s = &m->ms[i];
+
+ /* Mode identification */
+ read_ints(&x, fp, &emiss, 1);
+ read_ints(&x, fp, &trans, 1);
+ read_ints(&x, fp, &reflective, 1);
+ read_ints(&x, fp, &scan, 1);
+ read_ints(&x, fp, &flash, 1);
+ read_ints(&x, fp, &ambient, 1);
+ read_ints(&x, fp, &adaptive, 1);
+
+ /* Configuration calibration is valid for */
+ read_ints(&x, fp, &di, 1);
+ read_doubles(&x, fp, &dd, 1);
+
+ /* Calibration information */
+ read_ints(&x, fp, &di, 1);
+ read_time_ts(&x, fp, &dt, 1);
+ read_doubles(&x, fp, &dd, 1);
+
+ read_ints(&x, fp, &di, 1);
+ read_time_ts(&x, fp, &dt, 1);
+ read_doubles(&x, fp, &dd, 1);
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1);
+ read_doubles(&x, fp, &dd, 1);
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1);
+ read_doubles(&x, fp, &dd, 1);
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1);
+ read_ints(&x, fp, &di, 1);
+
+ if (!s->emiss) {
+ read_ints(&x, fp, &di, 1);
+ read_time_ts(&x, fp, &dt, 1);
+ for (j = 0; j < m->nwav[0]; j++)
+ read_doubles(&x, fp, &dd, 1);
+ for (j = 0; j < m->nwav[1]; j++)
+ read_doubles(&x, fp, &dd, 1);
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1);
+ }
+
+ read_ints(&x, fp, &di, 1);
+ read_time_ts(&x, fp, &dt, 1);
+ for (j = 0; j < 4; j++)
+ read_doubles(&x, fp, &dd, 1);
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1);
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1);
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1);
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1);
+ }
+
+ chsum1 = x.chsum;
+ nbytes = x.nbytes;
+ read_ints(&x, fp, &chsum2, 1);
+
+ if (x.ef != 0
+ || chsum1 != chsum2) {
+ a1logd(p->log,2,"Checksum didn't verify, bytes %d, got 0x%x, expected 0x%x\n",nbytes,chsum1, chsum2);
+ goto reserr;
+ }
+
+ rewind(fp);
+ x.ef = 0;
+ x.chsum = 0;
+ x.nbytes = 0;
+
+ /* Allocate space in temp structure */
+
+ ts.dark_data = dvectorz(-1, m->nraw-1);
+ ts.dark_data2 = dvectorz(-1, m->nraw-1);
+ ts.dark_data3 = dvectorz(-1, m->nraw-1);
+ ts.cal_factor[0] = dvectorz(0, m->nwav[0]-1);
+ ts.cal_factor[1] = dvectorz(0, m->nwav[1]-1);
+ ts.white_data = dvectorz(-1, m->nraw-1);
+ ts.idark_data = dmatrixz(0, 3, -1, m->nraw-1);
+
+ /* Read the identification */
+ read_ints(&x, fp, &argyllversion, 1);
+ read_ints(&x, fp, &ss, 1);
+ read_ints(&x, fp, &m->serno, 1);
+ read_ints(&x, fp, (int *)&m->nraw, 1);
+ read_ints(&x, fp, (int *)&m->nwav[0], 1);
+ read_ints(&x, fp, (int *)&m->nwav[1], 1);
+
+ /* For each mode, restore the calibration if it's valid */
+ for (i = 0; i < i1p_no_modes; i++) {
+ s = &m->ms[i];
+
+ /* Mode identification */
+ read_ints(&x, fp, &ts.emiss, 1);
+ read_ints(&x, fp, &ts.trans, 1);
+ read_ints(&x, fp, &ts.reflective, 1);
+ read_ints(&x, fp, &ts.scan, 1);
+ read_ints(&x, fp, &ts.flash, 1);
+ read_ints(&x, fp, &ts.ambient, 1);
+ read_ints(&x, fp, &ts.adaptive, 1);
+
+ /* Configuration calibration is valid for */
+ read_ints(&x, fp, &ts.gainmode, 1);
+ read_doubles(&x, fp, &ts.inttime, 1);
+
+ /* Calibration information: */
+
+ /* Wavelength */
+ read_ints(&x, fp, &ts.wl_valid, 1);
+ read_time_ts(&x, fp, &ts.wldate, 1);
+ read_doubles(&x, fp, &ts.wl_led_off, 1);
+
+ /* Static Dark */
+ read_ints(&x, fp, &ts.dark_valid, 1);
+ read_time_ts(&x, fp, &ts.ddate, 1);
+ read_doubles(&x, fp, &ts.dark_int_time, 1);
+ read_doubles(&x, fp, ts.dark_data-1, m->nraw+1);
+ read_doubles(&x, fp, &ts.dark_int_time2, 1);
+ read_doubles(&x, fp, ts.dark_data2-1, m->nraw+1);
+ read_doubles(&x, fp, &ts.dark_int_time3, 1);
+ read_doubles(&x, fp, ts.dark_data3-1, m->nraw+1);
+ read_ints(&x, fp, &ts.dark_gain_mode, 1);
+
+ if (!ts.emiss) {
+ /* Reflective */
+ read_ints(&x, fp, &ts.cal_valid, 1);
+ read_time_ts(&x, fp, &ts.cfdate, 1);
+ read_doubles(&x, fp, ts.cal_factor[0], m->nwav[0]);
+ read_doubles(&x, fp, ts.cal_factor[1], m->nwav[1]);
+ read_doubles(&x, fp, ts.white_data-1, m->nraw+1);
+ }
+
+ /* Adaptive Dark */
+ read_ints(&x, fp, &ts.idark_valid, 1);
+ read_time_ts(&x, fp, &ts.iddate, 1);
+ read_doubles(&x, fp, ts.idark_int_time, 4);
+ read_doubles(&x, fp, ts.idark_data[0]-1, m->nraw+1);
+ read_doubles(&x, fp, ts.idark_data[1]-1, m->nraw+1);
+ read_doubles(&x, fp, ts.idark_data[2]-1, m->nraw+1);
+ read_doubles(&x, fp, ts.idark_data[3]-1, m->nraw+1);
+
+ /* If the configuration for this mode matches */
+ /* that of the calibration, restore the calibration */
+ /* for this mode. */
+ if (x.ef == 0 /* No read error */
+ && s->emiss == ts.emiss
+ && s->trans == ts.trans
+ && s->reflective == ts.reflective
+ && s->scan == ts.scan
+ && s->flash == ts.flash
+ && s->ambient == ts.ambient
+ && s->adaptive == ts.adaptive
+ && (s->adaptive || fabs(s->inttime - ts.inttime) < 0.01)
+ && (s->adaptive || fabs(s->dark_int_time - ts.dark_int_time) < 0.01)
+ && (s->adaptive || fabs(s->dark_int_time2 - ts.dark_int_time2) < 0.01)
+ && (s->adaptive || fabs(s->dark_int_time3 - ts.dark_int_time3) < 0.01)
+ && (!s->adaptive || fabs(s->idark_int_time[0] - ts.idark_int_time[0]) < 0.01)
+ && (!s->adaptive || fabs(s->idark_int_time[1] - ts.idark_int_time[1]) < 0.01)
+ && (!s->adaptive || fabs(s->idark_int_time[2] - ts.idark_int_time[2]) < 0.01)
+ && (!s->adaptive || fabs(s->idark_int_time[3] - ts.idark_int_time[3]) < 0.01)
+ ) {
+ /* Copy all the fields read above */
+ s->emiss = ts.emiss;
+ s->trans = ts.trans;
+ s->reflective = ts.reflective;
+ s->scan = ts.scan;
+ s->flash = ts.flash;
+ s->ambient = ts.ambient;
+ s->adaptive = ts.adaptive;
+
+ s->gainmode = ts.gainmode;
+ s->inttime = ts.inttime;
+
+ s->wl_valid = ts.wl_valid;
+ s->wldate = ts.wldate;
+ s->wl_led_off = ts.wl_led_off;
+
+ s->dark_valid = ts.dark_valid;
+ s->ddate = ts.ddate;
+ s->dark_int_time = ts.dark_int_time;
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data[j] = ts.dark_data[j];
+ s->dark_int_time2 = ts.dark_int_time2;
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data2[j] = ts.dark_data2[j];
+ s->dark_int_time3 = ts.dark_int_time3;
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data3[j] = ts.dark_data3[j];
+ s->dark_gain_mode = ts.dark_gain_mode;
+ if (!ts.emiss) {
+ s->cal_valid = ts.cal_valid;
+ s->cfdate = ts.cfdate;
+ for (j = 0; j < m->nwav[0]; j++)
+ s->cal_factor[0][j] = ts.cal_factor[0][j];
+ for (j = 0; j < m->nwav[1]; j++)
+ s->cal_factor[1][j] = ts.cal_factor[1][j];
+ for (j = -1; j < m->nraw; j++)
+ s->white_data[j] = ts.white_data[j];
+ }
+ s->idark_valid = ts.idark_valid;
+ s->iddate = ts.iddate;
+ for (j = 0; j < 4; j++)
+ s->idark_int_time[j] = ts.idark_int_time[j];
+ for (j = -1; j < m->nraw; j++)
+ s->idark_data[0][j] = ts.idark_data[0][j];
+ for (j = -1; j < m->nraw; j++)
+ s->idark_data[1][j] = ts.idark_data[1][j];
+ for (j = -1; j < m->nraw; j++)
+ s->idark_data[2][j] = ts.idark_data[2][j];
+ for (j = -1; j < m->nraw; j++)
+ s->idark_data[3][j] = ts.idark_data[3][j];
+
+ } else {
+ a1logd(p->log,2,"Not restoring cal for mode %d since params don't match:\n",i);
+ a1logd(p->log,2,"emis = %d : %d, trans = %d : %d, ref = %d : %d\n",s->emiss,ts.emiss,s->trans,ts.trans,s->reflective,ts.reflective);
+ a1logd(p->log,2,"scan = %d : %d, flash = %d : %d, ambi = %d : %d, adapt = %d : %d\n",s->scan,ts.scan,s->flash,ts.flash,s->ambient,ts.ambient,s->adaptive,ts.adaptive);
+ a1logd(p->log,2,"inttime = %f : %f\n",s->inttime,ts.inttime);
+ a1logd(p->log,2,"darkit1 = %f : %f, 2 = %f : %f, 3 = %f : %f\n",s->dark_int_time,ts.dark_int_time,s->dark_int_time2,ts.dark_int_time2,s->dark_int_time3,ts.dark_int_time3);
+ a1logd(p->log,2,"idarkit0 = %f : %f, 1 = %f : %f, 2 = %f : %f, 3 = %f : %f\n",s->idark_int_time[0],ts.idark_int_time[0],s->idark_int_time[1],ts.idark_int_time[1],s->idark_int_time[2],ts.idark_int_time[2],s->idark_int_time[3],ts.idark_int_time[3]);
+ }
+ }
+
+ /* Free up temporary space */
+ free_dvector(ts.dark_data, -1, m->nraw-1);
+ free_dvector(ts.dark_data2, -1, m->nraw-1);
+ free_dvector(ts.dark_data3, -1, m->nraw-1);
+ free_dvector(ts.white_data, -1, m->nraw-1);
+ free_dmatrix(ts.idark_data, 0, 3, -1, m->nraw-1);
+
+ free_dvector(ts.cal_factor[0], 0, m->nwav[0]-1);
+ free_dvector(ts.cal_factor[1], 0, m->nwav[1]-1);
+
+ a1logd(p->log,5,"i1pro_restore_calibration done\n");
+ reserr:;
+
+ fclose(fp);
+ xdg_free(cal_paths, no_paths);
+
+ return ev;
+}
+
+i1pro_code i1pro_touch_calibration(i1pro *p) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+ char cal_name[100]; /* Name */
+ char **cal_paths = NULL;
+ int no_paths = 0;
+ int rv;
+
+ /* Locate the file name */
+ sprintf(cal_name, "ArgyllCMS/.i1p_%d.cal" SSEPS "color/.i1p_%d.cal", m->serno, m->serno);
+ if ((no_paths = xdg_bds(NULL, &cal_paths, xdg_cache, xdg_read, xdg_user, cal_name)) < 1) {
+ a1logd(p->log,2,"i1pro_restore_calibration xdg_bds failed to locate file'\n");
+ return I1PRO_INT_CAL_TOUCH;
+ }
+
+ a1logd(p->log,2,"i1pro_touch_calibration touching file '%s'\n",cal_paths[0]);
+
+ if ((rv = sys_utime(cal_paths[0], NULL)) != 0) {
+ a1logd(p->log,2,"i1pro_touch_calibration failed with %d\n",rv);
+ xdg_free(cal_paths, no_paths);
+ return I1PRO_INT_CAL_TOUCH;
+ }
+ xdg_free(cal_paths, no_paths);
+
+ return ev;
+}
+
+#endif /* ENABLE_NONVCAL */
+
+/* ============================================================ */
+/* Intermediate routines - composite commands/processing */
+
+/* Some sort of configuration needed get instrument ready. */
+/* Does it have a sleep mode that we need to deal with ?? */
+/* Note this always does a reset. */
+i1pro_code
+i1pro_establish_high_power(i1pro *p) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ int i;
+
+ /* Get the current misc. status */
+ if ((ev = i1pro_getmisc(p, &m->fwrev, NULL, &m->maxpve, NULL, &m->powmode)) != I1PRO_OK)
+ return ev;
+
+ if (m->powmode != 8) { /* In high power mode */
+ if ((ev = i1pro_reset(p, 0x1f)) != I1PRO_OK)
+ return ev;
+
+ return I1PRO_OK;
+ }
+
+ a1logd(p->log,4,"Switching to high power mode\n");
+
+ /* Switch to high power mode */
+ if ((ev = i1pro_reset(p, 1)) != I1PRO_OK)
+ return ev;
+
+ /* Wait up to 1.5 seconds for it return high power indication */
+ for (i = 0; i < 15; i++) {
+
+ /* Get the current misc. status */
+ if ((ev = i1pro_getmisc(p, &m->fwrev, NULL, &m->maxpve, NULL, &m->powmode)) != I1PRO_OK)
+ return ev;
+
+ if (m->powmode != 8) { /* In high power mode */
+ if ((ev = i1pro_reset(p, 0x1f)) != I1PRO_OK)
+ return ev;
+
+ return I1PRO_OK;
+ }
+
+ msec_sleep(100);
+ }
+
+ /* Failed to switch into high power mode */
+ return I1PRO_HW_HIGHPOWERFAIL;
+}
+
+/* Take a dark reference measurement - part 1 */
+i1pro_code i1pro_dark_measure_1(
+ i1pro *p,
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf, /* USB reading buffer to use */
+ unsigned int bsize /* Size of buffer */
+) {
+ i1pro_code ev = I1PRO_OK;
+
+ if (nummeas <= 0)
+ return I1PRO_INT_ZEROMEASURES;
+
+ if ((ev = i1pro_trigger_one_measure(p, nummeas, inttime, gainmode, i1p_dark_cal)) != I1PRO_OK)
+ return ev;
+
+ if ((ev = i1pro_readmeasurement(p, nummeas, 0, buf, bsize, NULL, i1p_dark_cal)) != I1PRO_OK)
+ return ev;
+
+ return ev;
+}
+
+/* Take a dark reference measurement - part 2 */
+i1pro_code i1pro_dark_measure_2(
+ i1pro *p,
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ int nummeas, /* Number of readings to take */
+ double inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf, /* raw USB reading buffer to process */
+ unsigned int bsize /* Buffer size to process */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ double **multimes; /* Multiple measurement results */
+ double sensavg; /* Overall average of sensor readings */
+ double satthresh; /* Saturation threshold */
+ double darkthresh; /* Dark threshold */
+ int rv;
+
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1); /* -1 is RevE shielded cells values */
+
+ if (gainmode == 0)
+ satthresh = m->sens_sat0;
+ else
+ satthresh = m->sens_sat1;
+
+ darkthresh = m->sens_dark + inttime * 900.0;
+ if (gainmode)
+ darkthresh *= m->highgain;
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* absolute linearised sensor values. */
+ if ((ev = i1pro_sens_to_absraw(p, multimes, buf, nummeas, inttime, gainmode, &darkthresh))
+ != I1PRO_OK) {
+ return ev;
+ }
+
+ satthresh = i1pro_raw_to_absraw(p, satthresh, inttime, gainmode);
+ darkthresh = i1pro_raw_to_absraw(p, darkthresh, inttime, gainmode);
+
+ /* Average a set of measurements into one. */
+ /* Return zero if readings are consistent and not saturated. */
+ /* Return nz with bit 1 set if the readings are not consistent */
+ /* Return nz with bit 2 set if the readings are saturated */
+ /* Return the highest individual element. */
+ /* Return the overall average. */
+ rv = i1pro_average_multimeas(p, absraw, multimes, nummeas, NULL, &sensavg,
+ satthresh, darkthresh);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+
+#ifdef PLOT_DEBUG
+ printf("Average absolute sensor readings, average = %f, satthresh %f:\n",sensavg, satthresh);
+ plot_raw(absraw);
+#endif
+
+ if (rv & 1)
+ return I1PRO_RD_DARKREADINCONS;
+
+ if (rv & 2)
+ return I1PRO_RD_SENSORSATURATED;
+
+ a1logd(p->log,3,"Dark threshold = %f\n",darkthresh);
+
+ if (sensavg > (2.0 * darkthresh))
+ return I1PRO_RD_DARKNOTVALID;
+
+ return ev;
+}
+
+#ifdef DUMP_DARKM
+int ddumpdarkm = 0;
+#endif
+
+/* Take a dark reference measurement (combined parts 1 & 2) */
+i1pro_code i1pro_dark_measure(
+ i1pro *p,
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+
+ bsize = m->nsen * 2 * nummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"i1pro_dark_measure malloc %d bytes failed (8)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+
+ if ((ev = i1pro_dark_measure_1(p, nummeas, inttime, gainmode, buf, bsize)) != I1PRO_OK) {
+ free(buf);
+ return ev;
+ }
+
+ if ((ev = i1pro_dark_measure_2(p, absraw,
+ nummeas, *inttime, gainmode, buf, bsize)) != I1PRO_OK) {
+ free(buf);
+ return ev;
+ }
+ free(buf);
+
+#ifdef DUMP_DARKM
+ /* Dump raw dark readings to a file "i1pddump.txt" */
+ if (ddumpdarkm) {
+ int j;
+ FILE *fp;
+
+ if ((fp = fopen("i1pddump.txt", "a")) == NULL)
+ a1logw(p->log,"Unable to open debug file i1pddump.txt\n");
+ else {
+
+ fprintf(fp, "\nDark measure: nummeas %d, inttime %f, gainmode %d, darkcells %f\n",nummeas,*inttime,gainmode, absraw[-1]);
+ fprintf(fp,"\t\t\t{ ");
+ for (j = 0; j < (m->nraw-1); j++)
+ fprintf(fp, "%f, ",absraw[j]);
+ fprintf(fp, "%f },\n",absraw[j]);
+ fclose(fp);
+ }
+ }
+#endif
+
+ return ev;
+}
+
+
+/* Take a white reference measurement */
+/* (Subtracts black and processes into wavelenths) */
+i1pro_code i1pro_whitemeasure(
+ i1pro *p,
+ double *abswav0, /* Return array [nwav[0]] of abswav values (may be NULL) */
+ double *abswav1, /* Return array [nwav[1]] of abswav values (if hr_init, may be NULL) */
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double *optscale, /* Factor to scale gain/int time by to make optimal (may be NULL) */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale, /* Optimal reading scale factor */
+ int ltocmode /* 1 = Lamp turn on compensation mode */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ double **multimes; /* Multiple measurement results */
+ double darkthresh; /* Consitency threshold scale limit */
+ int rv;
+
+ a1logd(p->log,3,"i1pro_whitemeasure called \n");
+
+ darkthresh = m->sens_dark + *inttime * 900.0; /* Default */
+ if (gainmode)
+ darkthresh *= m->highgain;
+
+ if (nummeas <= 0)
+ return I1PRO_INT_ZEROMEASURES;
+
+ /* Allocate temporaries up front to avoid delay between trigger and read */
+ bsize = m->nsen * 2 * nummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"i1pro_whitemeasure malloc %d bytes failed (10)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1);
+
+ a1logd(p->log,3,"Triggering measurement cycle, nummeas %d, inttime %f, gainmode %d\n",
+ nummeas, *inttime, gainmode);
+
+ if ((ev = i1pro_trigger_one_measure(p, nummeas, inttime, gainmode, i1p_cal)) != I1PRO_OK) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+ a1logd(p->log,4,"Gathering readings\n");
+
+ if ((ev = i1pro_readmeasurement(p, nummeas, 0, buf, bsize, NULL, i1p_cal)) != I1PRO_OK) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* absolute linearised sensor values. */
+ if ((ev = i1pro_sens_to_absraw(p, multimes, buf, nummeas, *inttime, gainmode, &darkthresh))
+ != I1PRO_OK) {
+ return ev;
+ }
+
+#ifdef PLOT_DEBUG
+ printf("Dark data:\n");
+ plot_raw(s->dark_data);
+#endif
+
+ /* Subtract the black level */
+ i1pro_sub_absraw(p, nummeas, *inttime, gainmode, multimes, s->dark_data);
+
+ /* Convert linearised white value into output wavelength white reference */
+ ev = i1pro_whitemeasure_3(p, abswav0, abswav1, absraw, optscale, nummeas,
+ *inttime, gainmode, targoscale, multimes, darkthresh);
+
+ free(buf);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+
+ return ev;
+}
+
+/* Process a single raw white reference measurement */
+/* (Subtracts black and processes into wavelenths) */
+/* Used for restoring calibration from the EEProm */
+i1pro_code i1pro_whitemeasure_buf(
+ i1pro *p,
+ double *abswav0, /* Return array [nwav[0]] of abswav values (may be NULL) */
+ double *abswav1, /* Return array [nwav[1]] of abswav values (if hr_init, may be NULL) */
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf /* Raw buffer */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ double *meas; /* Multiple measurement results */
+ double darkthresh; /* Consitency threshold scale limit */
+
+ a1logd(p->log,3,"i1pro_whitemeasure_buf called \n");
+
+ meas = dvector(-1, m->nraw-1);
+
+ darkthresh = m->sens_dark + inttime * 900.0; /* Default */
+ if (gainmode)
+ darkthresh *= m->highgain;
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* absolute linearised sensor values. */
+ if ((ev = i1pro_sens_to_absraw(p, &meas, buf, 1, inttime, gainmode, &darkthresh))
+ != I1PRO_OK) {
+ return ev;
+ }
+
+ /* Subtract the black level */
+ i1pro_sub_absraw(p, 1, inttime, gainmode, &meas, s->dark_data);
+
+ /* Convert linearised white value into output wavelength white reference */
+ ev = i1pro_whitemeasure_3(p, abswav0, abswav1, absraw, NULL, 1, inttime, gainmode,
+ 0.0, &meas, darkthresh);
+
+ free_dvector(meas, -1, m->nraw-1);
+
+ return ev;
+}
+
+/* Take a white reference measurement - part 3 */
+/* Average, check, and convert to output wavelengths */
+i1pro_code i1pro_whitemeasure_3(
+ i1pro *p,
+ double *abswav0, /* Return array [nwav[0]] of abswav values (may be NULL) */
+ double *abswav1, /* Return array [nwav[1]] of abswav values (if hr_init, may be NULL) */
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double *optscale, /* Factor to scale gain/int time by to make optimal (may be NULL) */
+ int nummeas, /* Number of readings to take */
+ double inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale, /* Optimal reading scale factor */
+ double **multimes, /* Multiple measurement results */
+ double darkthresh /* Raw dark threshold */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ double highest; /* Highest of sensor readings */
+ double sensavg; /* Overall average of sensor readings */
+ double satthresh; /* Saturation threshold */
+ double opttarget; /* Optimal sensor target */
+ int rv;
+
+ a1logd(p->log,3,"i1pro_whitemeasure_3 called \n");
+
+ if (gainmode == 0)
+ satthresh = m->sens_sat0;
+ else
+ satthresh = m->sens_sat1;
+ satthresh = i1pro_raw_to_absraw(p, satthresh, inttime, gainmode);
+
+ darkthresh = i1pro_raw_to_absraw(p, darkthresh, inttime, gainmode);
+
+ /* Average a set of measurements into one. */
+ /* Return zero if readings are consistent and not saturated. */
+ /* Return nz with bit 1 set if the readings are not consistent */
+ /* Return nz with bit 2 set if the readings are saturated */
+ /* Return the highest individual element. */
+ /* Return the overall average. */
+ rv = i1pro_average_multimeas(p, absraw, multimes, nummeas, &highest, &sensavg,
+ satthresh, darkthresh);
+#ifdef PLOT_DEBUG
+ printf("Average absolute sensor readings, average = %f, satthresh %f:\n",sensavg, satthresh);
+ plot_raw(absraw);
+#endif
+
+#ifndef IGNORE_WHITE_INCONS
+ if (rv & 1) {
+ return I1PRO_RD_WHITEREADINCONS;
+ }
+#endif /* IGNORE_WHITE_INCONS */
+
+ if (rv & 2) {
+ return I1PRO_RD_SENSORSATURATED;
+ }
+
+ /* Convert an absraw array from raw wavelengths to output wavelenths */
+ if (abswav0 != NULL) {
+ i1pro_absraw_to_abswav(p, 0, s->reflective, 1, &abswav0, &absraw);
+
+#ifdef PLOT_DEBUG
+ printf("Converted to wavelengths std res:\n");
+ plot_wav(m, 0, abswav0);
+#endif
+ }
+
+#ifdef HIGH_RES
+ if (abswav1 != NULL && m->hr_inited) {
+ i1pro_absraw_to_abswav(p, 1, s->reflective, 1, &abswav1, &absraw);
+
+#ifdef PLOT_DEBUG
+ printf("Converted to wavelengths high res:\n");
+ plot_wav(m, 1, abswav1);
+#endif
+ }
+#endif /* HIGH_RES */
+
+ if (optscale != NULL) {
+ double lhighest = highest;
+
+ if (lhighest < 1.0)
+ lhighest = 1.0;
+
+ /* Compute correction factor to make sensor optimal */
+ opttarget = i1pro_raw_to_absraw(p, (double)m->sens_target, inttime, gainmode);
+ opttarget *= targoscale;
+
+
+ a1logd(p->log,3,"Optimal target = %f, amount to scale = %f\n",opttarget, opttarget/lhighest);
+
+ *optscale = opttarget/lhighest;
+ }
+
+ return ev;
+}
+
+/* Take a wavelength reference measurement */
+/* (Measure and subtracts black and convert to absraw) */
+i1pro_code i1pro2_wl_measure(
+ i1pro *p,
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double *optscale, /* Factor to scale gain/int time by to make optimal (may be NULL) */
+ double *inttime, /* Integration time to use/used */
+ double targoscale /* Optimal reading scale factor */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ int nummeas = 1; /* Number of measurements to take */
+ int gainmode = 0; /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ double *dark; /* Dark reading */
+ double **multimes; /* Measurement results */
+ double darkthresh; /* Consitency threshold scale limit/reading dark cell values */
+ double highest; /* Highest of sensor readings */
+ double sensavg; /* Overall average of sensor readings */
+ double satthresh; /* Saturation threshold */
+ double opttarget; /* Optimal sensor target */
+ int rv;
+
+ a1logd(p->log,3,"i1pro2_wl_measure called \n");
+
+ /* Allocate temporaries up front to avoid delay between trigger and read */
+ bsize = m->nsen * 2;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"i1pro2_wl_measure malloc %d bytes failed (10)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* Do a dark reading at our integration time */
+ dark = dvector(-1, m->nraw-1);
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1);
+
+ if ((ev = i1pro_dark_measure(p, dark, nummeas, inttime, gainmode)) != I1PRO_OK) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free_dvector(dark, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+#ifdef PLOT_DEBUG
+ printf("Absraw dark data:\n");
+ plot_raw(dark);
+#endif
+
+ a1logd(p->log,3,"Triggering wl measurement cycle, inttime %f\n", *inttime);
+
+ if ((ev = i1pro_trigger_one_measure(p, nummeas, inttime, gainmode, i1p2_wl_cal)) != I1PRO_OK) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free_dvector(dark, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+ a1logd(p->log,4,"Gathering readings\n");
+
+ if ((ev = i1pro_readmeasurement(p, nummeas, 0, buf, bsize, NULL, i1p2_wl_cal)) != I1PRO_OK) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free_dvector(dark, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* absolute linearised sensor values. */
+ if ((ev = i1pro_sens_to_absraw(p, multimes, buf, nummeas, *inttime, gainmode, &darkthresh))
+ != I1PRO_OK) {
+ return ev;
+ }
+
+ /* Convert satthresh and darkthresh/dark_cell values to abs */
+ if (gainmode == 0)
+ satthresh = m->sens_sat0;
+ else
+ satthresh = m->sens_sat1;
+ satthresh = i1pro_raw_to_absraw(p, satthresh, *inttime, gainmode);
+ darkthresh = i1pro_raw_to_absraw(p, darkthresh, *inttime, gainmode);
+
+#ifdef PLOT_DEBUG
+ printf("Absraw WL data:\n");
+ plot_raw(multimes[0]);
+#endif
+
+ /* Subtract the black level */
+ i1pro_sub_absraw(p, nummeas, *inttime, gainmode, multimes, dark);
+
+#ifdef PLOT_DEBUG
+ printf("Absraw WL - black data:\n");
+ plot_raw(multimes[0]);
+#endif
+
+ /* Average a set of measurements into one. */
+ /* Return zero if readings are consistent and not saturated. */
+ /* Return nz with bit 1 set if the readings are not consistent */
+ /* Return nz with bit 2 set if the readings are saturated */
+ /* Return the highest individual element. */
+ /* Return the overall average. */
+ rv = i1pro_average_multimeas(p, absraw, multimes, 1, &highest, &sensavg,
+ satthresh, darkthresh);
+#ifdef PLOT_DEBUG
+ printf("Average absolute sensor readings, average = %f, satthresh %f, absraw WL result:\n",sensavg, satthresh);
+ plot_raw(absraw);
+#endif
+
+#ifndef IGNORE_WHITE_INCONS
+ if (rv & 1) {
+ return I1PRO_RD_WHITEREADINCONS;
+ }
+#endif /* IGNORE_WHITE_INCONS */
+
+ if (rv & 2) {
+ return I1PRO_RD_SENSORSATURATED;
+ }
+
+ if (optscale != NULL) {
+ double lhighest = highest;
+
+ if (lhighest < 1.0)
+ lhighest = 1.0;
+
+ /* Compute correction factor to make sensor optimal */
+ opttarget = i1pro_raw_to_absraw(p, (double)m->sens_target, *inttime, gainmode);
+ opttarget *= targoscale;
+
+
+ a1logd(p->log,3,"Optimal target = %f, amount to scale = %f\n",opttarget, opttarget/lhighest);
+
+ *optscale = opttarget/lhighest;
+ }
+
+ free(buf);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free_dvector(dark, -1, m->nraw-1);
+
+ return ev;
+}
+
+/* Take a measurement reading using the current mode, part 1 */
+/* Converts to completely processed output readings. */
+/* (NOTE:- this can't be used for calibration, as it implements uv mode) */
+i1pro_code i1pro_read_patches_1(
+ i1pro *p,
+ int minnummeas, /* Minimum number of measurements to take */
+ int maxnummeas, /* Maximum number of measurements to allow for */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ int *nmeasuered, /* Number actually measured */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ i1p_mmodif mmod = i1p_norm;
+ int rv = 0;
+
+ if (minnummeas <= 0)
+ return I1PRO_INT_ZEROMEASURES;
+ if (minnummeas > maxnummeas)
+ maxnummeas = minnummeas;
+
+ if (m->uv_en)
+ mmod = i1p2_UV;
+
+ a1logd(p->log,3,"Triggering & gathering cycle, minnummeas %d, inttime %f, gainmode %d\n",
+ minnummeas, *inttime, gainmode);
+
+ if ((ev = i1pro_trigger_one_measure(p, minnummeas, inttime, gainmode, mmod)) != I1PRO_OK) {
+ return ev;
+ }
+
+ if ((ev = i1pro_readmeasurement(p, minnummeas, m->c_measmodeflags & I1PRO_MMF_SCAN,
+ buf, bsize, nmeasuered, mmod)) != I1PRO_OK) {
+ return ev;
+ }
+
+ return ev;
+}
+
+/* Take a measurement reading using the current mode, part 2 */
+/* Converts to completely processed output readings. */
+i1pro_code i1pro_read_patches_2(
+ i1pro *p,
+ double *duration, /* Return flash duration */
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of patches to return */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode useed, 0 = normal, 1 = high */
+ int nmeasuered, /* Number actually measured */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ double **multimes; /* Multiple measurement results [maxnummeas|nmeasuered][-1 nraw]*/
+ double **absraw; /* Linearsised absolute sensor raw values [numpatches][-1 nraw]*/
+ double satthresh; /* Saturation threshold */
+ double darkthresh; /* Dark threshold for consistency scaling limit */
+ int rv = 0;
+
+ if (duration != NULL)
+ *duration = 0.0; /* default value */
+
+ darkthresh = m->sens_dark + inttime * 900.0; /* Default */
+ if (gainmode)
+ darkthresh *= m->highgain;
+
+ /* Allocate temporaries */
+ multimes = dmatrix(0, nmeasuered-1, -1, m->nraw-1);
+ absraw = dmatrix(0, numpatches-1, -1, m->nraw-1);
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* absolute linearised sensor values. */
+ if ((ev = i1pro_sens_to_absraw(p, multimes, buf, nmeasuered, inttime, gainmode, &darkthresh))
+ != I1PRO_OK) {
+ return ev;
+ }
+
+ /* Subtract the black level */
+ i1pro_sub_absraw(p, nmeasuered, inttime, gainmode, multimes, s->dark_data);
+
+#ifdef DUMP_SCANV
+ /* Dump raw scan readings to a file "i1pdump.txt" */
+ {
+ int i, j;
+ FILE *fp;
+
+ if ((fp = fopen("i1pdump.txt", "w")) == NULL)
+ a1logw(p->log,"Unable to open debug file i1pdump.txt\n");
+ else {
+ for (i = 0; i < nmeasuered; i++) {
+ fprintf(fp, "%d ",i);
+ for (j = 0; j < m->nraw; j++) {
+ fprintf(fp, "%f ",multimes[i][j]);
+ }
+ fprintf(fp,"\n");
+ }
+ fclose(fp);
+ }
+ }
+#endif
+ if (gainmode == 0)
+ satthresh = m->sens_sat0;
+ else
+ satthresh = m->sens_sat1;
+ satthresh = i1pro_raw_to_absraw(p, satthresh, inttime, gainmode);
+
+ darkthresh = i1pro_raw_to_absraw(p, darkthresh, inttime, gainmode);
+
+ if (!s->scan) {
+ if (numpatches != 1) {
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nmeasuered-1, -1, m->nraw-1);
+ a1logd(p->log,2,"i1pro_read_patches_2 spot read failed because numpatches != 1\n");
+ return I1PRO_INT_WRONGPATCHES;
+ }
+
+ /* Average a set of measurements into one. */
+ /* Return zero if readings are consistent and not saturated. */
+ /* Return nz with bit 1 set if the readings are not consistent */
+ /* Return nz with bit 2 set if the readings are saturated */
+ /* Return the highest individual element. */
+ /* Return the overall average. */
+ rv = i1pro_average_multimeas(p, absraw[0], multimes, nmeasuered, NULL, NULL,
+ satthresh, darkthresh);
+ } else {
+ if (s->flash) {
+
+ if (numpatches != 1) {
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nmeasuered-1, -1, m->nraw-1);
+ a1logd(p->log,2,"i1pro_read_patches_2 spot read failed because numpatches != 1\n");
+ return I1PRO_INT_WRONGPATCHES;
+ }
+ if ((ev = i1pro_extract_patches_flash(p, &rv, duration, absraw[0], multimes,
+ nmeasuered, inttime)) != I1PRO_OK) {
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nmeasuered-1, -1, m->nraw-1);
+ a1logd(p->log,2,"i1pro_read_patches_2 spot read failed at i1pro_extract_patches_flash\n");
+ return ev;
+ }
+
+ } else {
+ a1logd(p->log,3,"Number of patches measured = %d\n",nmeasuered);
+
+ /* Recognise the required number of ref/trans patch locations, */
+ /* and average the measurements within each patch. */
+ if ((ev = i1pro_extract_patches_multimeas(p, &rv, absraw, numpatches, multimes,
+ nmeasuered, NULL, satthresh, inttime)) != I1PRO_OK) {
+ free_dmatrix(multimes, 0, nmeasuered-1, -1, m->nraw-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ a1logd(p->log,2,"i1pro_read_patches_2 spot read failed at i1pro_extract_patches_multimeas\n");
+ return ev;
+ }
+ }
+ }
+
+ if (rv & 1) {
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ a1logd(p->log,3,"i1pro_read_patches_2 spot read failed with inconsistent readings\n");
+ return I1PRO_RD_READINCONS;
+ }
+
+ if (rv & 2) {
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ a1logd(p->log,3,"i1pro_read_patches_2 spot read failed with sensor saturated\n");
+ return I1PRO_RD_SENSORSATURATED;
+ }
+
+ /* Convert an absraw array from raw wavelengths to output wavelenths */
+ i1pro_absraw_to_abswav(p, m->highres, s->reflective, numpatches, specrd, absraw);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+
+#ifdef APPEND_MEAN_EMMIS_VAL
+ /* Append averaged emission reading to file "i1pdump.txt" */
+ {
+ int i, j;
+ FILE *fp;
+
+ /* Create wavelegth label */
+ if ((fp = fopen("i1pdump.txt", "r")) == NULL) {
+ if ((fp = fopen("i1pdump.txt", "w")) == NULL)
+ a1logw(p->log,"Unable to reate debug file i1pdump.txt\n");
+ else {
+ for (j = 0; j < m->nwav[m->highres]; j++)
+ fprintf(fp,"%f ",XSPECT_WL(m->wl_short[m->highres], m->wl_long[m->highres], m->nwav[m->highres], j));
+ fprintf(fp,"\n");
+ fclose(fp);
+ }
+ }
+ if ((fp = fopen("i1pdump.txt", "a")) == NULL) {
+ a1logw(p->log,"Unable to open debug file i1pdump.txt\n");
+ else {
+ for (j = 0; j < m->nwav[m->highres]; j++)
+ fprintf(fp, "%f ",specrd[0][j] * m->emis_coef[j]);
+ fprintf(fp,"\n");
+ fclose(fp);
+ }
+ }
+#endif
+
+#ifdef PLOT_DEBUG
+ printf("Converted to wavelengths:\n");
+ plot_wav(m, m->highres, specrd[0]);
+#endif
+
+ /* Scale to the calibrated output values */
+ i1pro_scale_specrd(p, specrd, numpatches, specrd);
+
+#ifdef PLOT_DEBUG
+ printf("Calibrated measuerment spectra:\n");
+ plot_wav(m, m->highres, specrd[0]);
+#endif
+
+ return ev;
+}
+
+/* Take a measurement reading using the current mode, part 2a */
+/* Converts to completely processed output readings, */
+/* but don't average together or extract patches or flash. */
+/* (! Note that we aren't currently detecting saturation here!) */
+i1pro_code i1pro_read_patches_2a(
+ i1pro *p,
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of patches measured and to return */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode useed, 0 = normal, 1 = high */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ double **absraw; /* Linearsised absolute sensor raw values [numpatches][-1 nraw]*/
+ double satthresh; /* Saturation threshold */
+ double darkthresh; /* Dark threshold for consistency scaling limit */
+
+ darkthresh = m->sens_dark + inttime * 900.0; /* Default */
+ if (gainmode)
+ darkthresh *= m->highgain;
+
+ /* Allocate temporaries */
+ absraw = dmatrix(0, numpatches-1, -1, m->nraw-1);
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* absolute linearised sensor values. */
+ if ((ev = i1pro_sens_to_absraw(p, absraw, buf, numpatches, inttime, gainmode, &darkthresh))
+ != I1PRO_OK) {
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ return ev;
+ }
+
+ /* Subtract the black level */
+ i1pro_sub_absraw(p, numpatches, inttime, gainmode, absraw, s->dark_data);
+
+ if (gainmode == 0)
+ satthresh = m->sens_sat0;
+ else
+ satthresh = m->sens_sat1;
+ satthresh = i1pro_raw_to_absraw(p, satthresh, inttime, gainmode);
+
+ darkthresh = i1pro_raw_to_absraw(p, darkthresh, inttime, gainmode);
+
+ a1logd(p->log,3,"Number of patches measured = %d\n",numpatches);
+
+ /* Convert an absraw array from raw wavelengths to output wavelenths */
+ i1pro_absraw_to_abswav(p, m->highres, s->reflective, numpatches, specrd, absraw);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+
+#ifdef PLOT_DEBUG
+ printf("Converted to wavelengths:\n");
+ plot_wav(m, m->highres, specrd[0]);
+#endif
+
+ /* Scale to the calibrated output values */
+ i1pro_scale_specrd(p, specrd, numpatches, specrd);
+
+#ifdef PLOT_DEBUG
+ printf("Calibrated measuerment spectra:\n");
+ plot_wav(m, m->highres, specrd[0]);
+#endif
+
+ return ev;
+}
+
+/* Take a measurement reading using the current mode (combined parts 1 & 2) */
+/* Converts to completely processed output readings. */
+/* (NOTE:- this can't be used for calibration, as it implements uv mode) */
+i1pro_code i1pro_read_patches(
+ i1pro *p,
+ double *duration, /* Return flash duration */
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of patches to return */
+ int minnummeas, /* Minimum number of measurements to take */
+ int maxnummeas, /* Maximum number of measurements to allow for */
+ double *inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ int nmeasuered; /* Number actually measured */
+ int rv = 0;
+
+ if (minnummeas <= 0)
+ return I1PRO_INT_ZEROMEASURES;
+ if (minnummeas > maxnummeas)
+ maxnummeas = minnummeas;
+
+ /* Allocate temporaries */
+ bsize = m->nsen * 2 * maxnummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"i1pro_read_patches malloc %d bytes failed (11)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* Trigger measure and gather raw readings */
+ if ((ev = i1pro_read_patches_1(p, minnummeas, maxnummeas, inttime, gainmode,
+ &nmeasuered, buf, bsize)) != I1PRO_OK) {
+ free(buf);
+ return ev;
+ }
+
+ /* Process the raw readings */
+ if ((ev = i1pro_read_patches_2(p, duration, specrd, numpatches, *inttime, gainmode,
+ nmeasuered, buf, bsize)) != I1PRO_OK) {
+ free(buf);
+ return ev;
+ }
+ free(buf);
+ return ev;
+}
+
+/* Take a measurement reading using the current mode (combined parts 1 & 2a) */
+/* Converts to completely processed output readings, without averaging or extracting */
+/* sample patches. */
+/* (NOTE:- this can't be used for calibration, as it implements uv mode) */
+i1pro_code i1pro_read_patches_all(
+ i1pro *p,
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of sample to measure */
+ double *inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ int rv = 0;
+
+ bsize = m->nsen * 2 * numpatches;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"i1pro_read_patches malloc %d bytes failed (11)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* Trigger measure and gather raw readings */
+ if ((ev = i1pro_read_patches_1(p, numpatches, numpatches, inttime, gainmode,
+ NULL, buf, bsize)) != I1PRO_OK) {
+ free(buf);
+ return ev;
+ }
+
+ /* Process the raw readings without averaging or extraction */
+ if ((ev = i1pro_read_patches_2a(p, specrd, numpatches, *inttime, gainmode,
+ buf, bsize)) != I1PRO_OK) {
+ free(buf);
+ return ev;
+ }
+ free(buf);
+ return ev;
+}
+
+/* Take a trial measurement reading using the current mode. */
+/* Used to determine if sensor is saturated, or not optimal */
+/* in adaptive emission mode. */
+i1pro_code i1pro_trialmeasure(
+ i1pro *p,
+ int *saturated, /* Return nz if sensor is saturated */
+ double *optscale, /* Factor to scale gain/int time by to make optimal (may be NULL) */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale /* Optimal reading scale factor */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ double **multimes; /* Multiple measurement results */
+ double *absraw; /* Linearsised absolute sensor raw values */
+ int nmeasuered; /* Number actually measured */
+ double highest; /* Highest of sensor readings */
+ double sensavg; /* Overall average of sensor readings */
+ double satthresh; /* Saturation threshold */
+ double darkthresh; /* Dark threshold */
+ double opttarget; /* Optimal sensor target */
+ int rv;
+
+ if (nummeas <= 0)
+ return I1PRO_INT_ZEROMEASURES;
+
+ darkthresh = m->sens_dark + *inttime * 900.0;
+ if (gainmode)
+ darkthresh *= m->highgain;
+
+ /* Allocate up front to avoid delay between trigger and read */
+ bsize = m->nsen * 2 * nummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"i1pro_trialmeasure malloc %d bytes failed (12)\n",bsize);
+ return I1PRO_INT_MALLOC;
+ }
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1);
+ absraw = dvector(-1, m->nraw-1);
+
+ a1logd(p->log,3,"Triggering measurement cycle, nummeas %d, inttime %f, gainmode %d\n",
+ nummeas, *inttime, gainmode);
+
+ if ((ev = i1pro_trigger_one_measure(p, nummeas, inttime, gainmode, i1p_cal)) != I1PRO_OK) {
+ free_dvector(absraw, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+ a1logd(p->log,4,"Gathering readings\n");
+ if ((ev = i1pro_readmeasurement(p, nummeas, m->c_measmodeflags & I1PRO_MMF_SCAN,
+ buf, bsize, &nmeasuered, i1p_cal)) != I1PRO_OK) {
+ free_dvector(absraw, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* absolute linearised sensor values. */
+ if ((ev = i1pro_sens_to_absraw(p, multimes, buf, nmeasuered, *inttime, gainmode, &darkthresh))
+ != I1PRO_OK) {
+ return ev;
+ }
+
+ /* Compute dark subtraction for this trial's parameters */
+ if ((ev = i1pro_interp_dark(p, s->dark_data,
+ s->inttime, s->gainmode)) != I1PRO_OK) {
+ free_dvector(absraw, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free(buf);
+ a1logd(p->log,2,"i1pro_trialmeasure interplate dark ref failed\n");
+ return ev;
+ }
+
+ /* Subtract the black level */
+ i1pro_sub_absraw(p, nummeas, *inttime, gainmode, multimes, s->dark_data);
+
+ if (gainmode == 0)
+ satthresh = m->sens_sat0;
+ else
+ satthresh = m->sens_sat1;
+ satthresh = i1pro_raw_to_absraw(p, satthresh, *inttime, gainmode);
+
+ darkthresh = i1pro_raw_to_absraw(p, darkthresh, *inttime, gainmode);
+
+ /* Average a set of measurements into one. */
+ /* Return zero if readings are consistent and not saturated. */
+ /* Return nz with bit 1 set if the readings are not consistent */
+ /* Return nz with bit 2 set if the readings are saturated */
+ /* Return the highest individual element. */
+ /* Return the overall average. */
+ rv = i1pro_average_multimeas(p, absraw, multimes, nmeasuered, &highest, &sensavg,
+ satthresh, darkthresh);
+#ifdef PLOT_DEBUG
+ printf("Average absolute sensor readings, average = %f, satthresh %f:\n",sensavg, satthresh);
+ plot_raw(absraw);
+#endif
+
+ if (saturated != NULL) {
+ *saturated = 0;
+ if (rv & 2)
+ *saturated = 1;
+ }
+
+ /* Compute correction factor to make sensor optimal */
+ opttarget = (double)m->sens_target * targoscale;
+ opttarget = i1pro_raw_to_absraw(p, opttarget, *inttime, gainmode);
+
+ if (optscale != NULL) {
+ double lhighest = highest;
+
+ if (lhighest < 1.0)
+ lhighest = 1.0;
+
+ *optscale = opttarget/lhighest;
+ }
+
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free_dvector(absraw, -1, m->nraw-1);
+ free(buf);
+
+ return ev;
+}
+
+/* Trigger a single measurement cycle. This could be a dark calibration, */
+/* a calibration, or a real measurement. This is used to create the */
+/* higher level "calibrate" and "take reading" functions. */
+/* The setup for the operation is in the current mode state. */
+/* Call i1pro_readmeasurement() to collect the results */
+i1pro_code
+i1pro_trigger_one_measure(
+ i1pro *p,
+ int nummeas, /* Minimum number of measurements to make */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ i1p_mmodif mmodif /* Measurement modifier enum */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ unsigned int timssinceoff; /* time in msec since lamp turned off */
+ double dintclocks;
+ int intclocks; /* Number of integration clocks */
+ double dlampclocks;
+ int lampclocks; /* Number of lamp turn on sub-clocks */
+ int measmodeflags; /* Measurement mode command flags */
+ int measmodeflags2; /* Rev E Measurement mode command flags */
+
+ /* The Rev E measure mode has it's own settings */
+ if (p->itype == instI1Pro2) {
+ m->intclkp = m->intclkp2; /* From i1pro2_getmeaschar() ? */
+ m->subclkdiv = m->subclkdiv2;
+ m->subtmode = 0;
+
+ } else {
+ /* Set any special hardware up for this sort of read */
+ if (*inttime != m->c_inttime) { /* integration time is different */
+ int mcmode, maxmcmode;
+ int intclkusec;
+ int subtmodeflags;
+
+ /* Setting for fwrev < 301 */
+ /* (This is what getmcmode() returns for mcmode = 1 on fwrev >= 301) */
+ m->intclkp = 68.0e-6;
+ m->subclkdiv = 130;
+ m->subtmode = 0;
+
+ if (m->fwrev >= 301) { /* Special hardware in latter versions of instrument */
+
+#ifdef DEBUG
+ /* Show all the available clock modes */
+ for (mcmode = 1;; mcmode++) {
+ int rmcmode, subclkdiv;
+
+ if ((ev = i1pro_setmcmode(p, mcmode)) != I1PRO_OK)
+ break;
+
+ if ((ev = i1pro_getmcmode(p, &maxmcmode, &rmcmode, &subclkdiv,
+ &intclkusec, &subtmodeflags) ) != I1PRO_OK)
+ break;
+
+ fprintf(stderr,"getcmode %d: maxcmode %d, mcmode %d, subclkdif %d, intclkusec %d, subtmodeflags 0x%x\n",mcmode,maxmcmode,rmcmode,subclkdiv,intclkusec,subtmodeflags);
+ if (mcmode >= maxmcmode)
+ break;
+ }
+#endif
+ /* Configure a clock mode that gives us an optimal integration time ? */
+ for (mcmode = 1;; mcmode++) {
+ if ((ev = i1pro_setmcmode(p, mcmode)) != I1PRO_OK)
+ return ev;
+
+ if ((ev = i1pro_getmcmode(p, &maxmcmode, &mcmode, &m->subclkdiv,
+ &intclkusec, &subtmodeflags) ) != I1PRO_OK)
+ return ev;
+
+ if ((*inttime/(intclkusec * 1e-6)) > 65535.0) {
+ return I1PRO_INT_INTTOOBIG;
+ }
+
+ if (*inttime >= (intclkusec * m->subclkdiv * 1e-6 * 0.99))
+ break; /* Setting is optimal */
+
+ /* We need to go around again */
+ if (mcmode >= maxmcmode) {
+ return I1PRO_INT_INTTOOSMALL;
+ }
+ }
+ m->c_mcmode = mcmode;
+ m->intclkp = intclkusec * 1e-6;
+ a1logd(p->log,3,"Switched to perfect mode, subtmode flag = 0x%x, intclk = %f Mhz\n",subtmodeflags & 0x01, 1.0/intclkusec);
+ if (subtmodeflags & 0x01)
+ m->subtmode = 1; /* Last reading subtract mode */
+ }
+ }
+ }
+ a1logd(p->log,3,"Integration clock period = %f ussec\n",m->intclkp * 1e6);
+
+ /* Compute integration clocks */
+ dintclocks = floor(*inttime/m->intclkp + 0.5);
+ if (p->itype == instI1Pro2) {
+ if (dintclocks > 4294967296.0) /* This is probably not the actual limit */
+ return I1PRO_INT_INTTOOBIG;
+ } else {
+ if (dintclocks > 65535.0)
+ return I1PRO_INT_INTTOOBIG;
+ }
+ intclocks = (int)dintclocks;
+ *inttime = (double)intclocks * m->intclkp; /* Quantized integration time */
+
+ if (s->reflective && (mmodif & 0x10)) {
+ dlampclocks = floor(s->lamptime/(m->subclkdiv * m->intclkp) + 0.5);
+ if (dlampclocks > 256.0) /* Clip - not sure why. Silly value anyway */
+ dlampclocks = 256.0;
+ lampclocks = (int)dlampclocks;
+ s->lamptime = dlampclocks * m->subclkdiv * m->intclkp; /* Quantized lamp time */
+ } else {
+ dlampclocks = 0.0;
+ lampclocks = 0;
+ }
+
+ if (nummeas > 65535)
+ nummeas = 65535; /* Or should we error ? */
+
+ /* Create measurement mode flag values for this operation for both */
+ /* legacy and Rev E mode. Other code will examine legacy mode flags */
+ measmodeflags = 0;
+ if (s->scan && !(mmodif & 0x20)) /* Never scan on a calibration */
+ measmodeflags |= I1PRO_MMF_SCAN;
+ if (!s->reflective || !(mmodif & 0x10))
+ measmodeflags |= I1PRO_MMF_NOLAMP; /* No lamp if not reflective or dark measure */
+ if (gainmode == 0)
+ measmodeflags |= I1PRO_MMF_LOWGAIN; /* Normal gain mode */
+
+ if (p->itype == instI1Pro2) {
+ measmodeflags2 = 0;
+ if (s->scan && !(mmodif & 0x20)) /* Never scan on a calibration */
+ measmodeflags2 |= I1PRO2_MMF_SCAN;
+
+ if (mmodif == i1p2_UV)
+ measmodeflags2 |= I1PRO2_MMF_UV_LED; /* UV LED illumination measurement */
+ else if (mmodif == i1p2_wl_cal)
+ measmodeflags2 |= I1PRO2_MMF_WL_LED; /* Wavelegth illumination cal */
+ else if (s->reflective && (mmodif & 0x10))
+ measmodeflags2 |= I1PRO2_MMF_LAMP; /* lamp if reflective and mmodif possible */
+
+ if (gainmode != 0)
+ return I1PRO_INT_NO_HIGH_GAIN;
+ }
+
+ a1logd(p->log,2,"i1pro: Int time %f msec, delay %f msec, no readings %d, expect %f msec\n",
+ *inttime * 1000.0,
+ ((measmodeflags & I1PRO_MMF_NOLAMP) ? 0.0 : s->lamptime) * 1000.0,
+ nummeas,
+ (nummeas * *inttime + ((measmodeflags & I1PRO_MMF_NOLAMP) ? 0.0 : s->lamptime)) * 1000.0);
+
+ /* Do a setmeasparams */
+#ifdef NEVER
+ if (intclocks != m->c_intclocks /* If any parameters have changed */
+ || lampclocks != m->c_lampclocks
+ || nummeas != m->c_nummeas
+ || measmodeflags != m->c_measmodeflags
+ || measmodeflags2 != m->c_measmodeflags2)
+#endif /* NEVER */
+ {
+
+ if (p->itype != instI1Pro2) { /* Rev E sets the params in the measure command */
+ /* Set the hardware for measurement */
+ if ((ev = i1pro_setmeasparams(p, intclocks, lampclocks, nummeas, measmodeflags)) != I1PRO_OK)
+ return ev;
+ } else {
+ a1logd(p->log,2,"\ni1pro: SetMeasureParam2 %d, %d, %d, 0x%04x @ %d msec\n",
+ intclocks, lampclocks, nummeas, measmodeflags2,
+ msec_time() - m->msec);
+ }
+
+ m->c_intclocks = intclocks;
+ m->c_lampclocks = lampclocks;
+ m->c_nummeas = nummeas;
+ m->c_measmodeflags = measmodeflags;
+ m->c_measmodeflags2 = measmodeflags2;
+
+ m->c_inttime = *inttime; /* Special harware is configured */
+ m->c_lamptime = s->lamptime;
+ }
+
+ /* If the lamp needs to be off, make sure at least 1.5 seconds */
+ /* have elapsed since it was last on, to make sure it's dark. */
+ if ((measmodeflags & I1PRO_MMF_NOLAMP)
+ && (timssinceoff = (msec_time() - m->llamponoff)) < LAMP_OFF_TIME) {
+ a1logd(p->log,3,"Sleep %d msec for lamp cooldown\n",LAMP_OFF_TIME - timssinceoff);
+ msec_sleep(LAMP_OFF_TIME - timssinceoff); /* Make sure time adds up to 1.5 seconds */
+ }
+
+ /* Trigger a measurement */
+ if (p->itype != instI1Pro2) {
+ if ((ev = i1pro_triggermeasure(p, TRIG_DELAY)) != I1PRO_OK)
+ return ev;
+ } else {
+ if ((ev = i1pro2_triggermeasure(p, TRIG_DELAY)) != I1PRO_OK)
+ return ev;
+ }
+
+ return ev;
+}
+
+/* ============================================================ */
+/* Big endian wire format conversion routines */
+
+/* Take an int, and convert it into a byte buffer big endian */
+static void int2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 24) & 0xff;
+ buf[1] = (inv >> 16) & 0xff;
+ buf[2] = (inv >> 8) & 0xff;
+ buf[3] = (inv >> 0) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer big endian */
+static void short2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 8) & 0xff;
+ buf[1] = (inv >> 0) & 0xff;
+}
+
+/* Take a word sized buffer, and convert it to an int */
+static int buf2int(unsigned char *buf) {
+ int val;
+ val = buf[0]; /* Hmm. should this be sign extended ?? */
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[3]));
+ return val;
+}
+
+/* Take a short sized buffer, and convert it to an int */
+static int buf2short(unsigned char *buf) {
+ int val;
+ val = *((signed char *)buf); /* Sign extend */
+ val = ((val << 8) + (0xff & buf[1]));
+ return val;
+}
+
+/* Take a unsigned short sized buffer, and convert it to an int */
+static int buf2ushort(unsigned char *buf) {
+ int val;
+ val = (0xff & buf[0]);
+ val = ((val << 8) + (0xff & buf[1]));
+ return val;
+}
+
+/* ============================================================ */
+/* lower level reading processing and computation */
+
+/* Take a buffer full of sensor readings, and convert them to */
+/* absolute raw values. Linearise if Rev A..D */
+/* If RevE, fill in the [-1] value with the shielded cell values */
+/* Note the rev E darkthresh returned has NOT been converted to an absolute raw value */
+i1pro_code i1pro_sens_to_absraw(
+ i1pro *p,
+ double **absraw, /* Array of [nummeas][-1 nraw] value to return */
+ unsigned char *buf, /* Raw measurement data must be nsen * nummeas */
+ int nummeas, /* Return number of readings measured */
+ double inttime, /* Integration time used */
+ int gainmode, /* Gain mode, 0 = normal, 1 = high */
+ double *pdarkthresh /* Return a raw dark threshold value (Rev E) */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ int i, j, k;
+ unsigned char *bp;
+ unsigned int maxpve = m->maxpve; /* maximum +ve sensor value + 1 */
+ double avlastv = 0.0;
+ double darkthresh = 0.0; /* Rev E calculated values */
+ double ndarkthresh = 0.0;
+ double gain;
+ int npoly; /* Number of linearisation coefficients */
+ double *polys; /* the coeficients */
+ double scale; /* Absolute scale value */
+ int sskip = 0; /* Bytes to skip at start */
+ int eskip = 0; /* Bytes to skip at end */
+
+ if (gainmode) {
+ gain = m->highgain;
+ npoly = m->nlin1;
+ polys = m->lin1;
+ } else {
+ gain = 1.0;
+ npoly = m->nlin0;
+ polys = m->lin0;
+ }
+ scale = 1.0/(inttime * gain);
+
+ /* Now process the buffer values */
+ if (m->nsen > m->nraw) { /* It's a Rev E, so we have extra values, */
+ /* and don't linearize here. */
+ sskip = 6 * 2; /* 6 dark reading values */
+ eskip = 0 * 2; /* none to skip at end */
+
+ if ((sskip + m->nraw * 2 + eskip) != (m->nsen * 2)) {
+ a1loge(p->log,1,"i1pro Rev E - sskip %d + nraw %d + eskip %d != nsen %d\n"
+ ,sskip, m->nraw * 2, eskip, m->nsen * 2);
+ return I1PRO_INT_ASSERT;
+ }
+
+ for (bp = buf, i = 0; i < nummeas; i++, bp += eskip) {
+ unsigned int rval;
+ double fval;
+
+ /* The first 6 readings (xraw from i1pro2_getmeaschar()) are shielded cells, */
+ /* and we use them as an estimate of the dark reading consistency, as well as for */
+ /* compensating the dark level calibration for any temperature changes. */
+
+ /* raw average of all measurement shielded cell values */
+ for (k = 0; k < 6; k++) {
+ darkthresh += (double)buf2ushort(bp + k * 2);
+ ndarkthresh++;
+ }
+
+ /* absraw of shielded cells per reading */
+ absraw[i][-1] = 0.0;
+ for (k = 0; k < 6; k++) {
+ rval = buf2ushort(bp + k * 2);
+ fval = (double)(int)rval;
+
+ /* And scale to be an absolute sensor reading */
+ absraw[i][-1] += fval * scale;
+ }
+ absraw[i][-1] /= 6.0;
+
+ for (bp += sskip, j = 0; j < m->nraw; j++, bp += 2) {
+ rval = buf2ushort(bp);
+ a1logd(p->log,9,"% 3d:rval 0x%x, ",j, rval);
+ a1logd(p->log,9,"srval 0x%x, ",rval);
+ fval = (double)(int)rval;
+ a1logd(p->log,9,"fval %.0f, ",fval);
+
+ /* And scale to be an absolute sensor reading */
+ absraw[i][j] = fval * scale;
+ a1logd(p->log,9,"absval %.1f\n",fval * scale);
+ }
+ }
+ darkthresh /= ndarkthresh;
+ if (pdarkthresh != NULL)
+ *pdarkthresh = darkthresh;
+ a1logd(p->log,3,"i1pro_sens_to_absraw: Dark threshold = %f\n",darkthresh);
+
+ } else {
+ /* if subtmode is set, compute the average last reading raw value. */
+ /* Could this be some sort of temperature compensation offset ??? */
+ /* (Rev A produces a value that is quite different to a sensor value, */
+ /* ie. 1285 = 0x0505, while RevD and RevE in legacy mode have a value of 0 */
+ /* I've not seen anything actually use subtmode - maybe this is Rev B only ?) */
+ /* The 0 band seens to contain values similar to band 1, so it's not clear */
+ /* why the manufacturers driver appears to be discarding it ? */
+
+ /* (Not sure if it's reasonable to extend the sign and then do this */
+ /* computation, or whether it makes any difference, since I've never */
+ /* seen this mode triggered. */
+ if (m->subtmode) {
+ for (bp = buf + 254, i = 0; i < nummeas; i++, bp += (m->nsen * 2)) {
+ unsigned int lastv;
+ lastv = buf2ushort(bp);
+ if (lastv >= maxpve) {
+ lastv -= 0x00010000; /* Convert to -ve */
+ }
+ avlastv += (double)lastv;
+ }
+ avlastv /= (double)nummeas;
+ a1logd(p->log,3,"subtmode got avlastv = %f\n",avlastv);
+ }
+
+ for (bp = buf, i = 0; i < nummeas; i++) {
+ absraw[i][-1] = 1.0; /* Not used in RevA-D */
+
+ for (j = 0; j < 128; j++, bp += 2) {
+ unsigned int rval;
+ double fval, lval;
+
+ rval = buf2ushort(bp);
+ a1logd(p->log,9,"% 3d:rval 0x%x, ",j, rval);
+ if (rval >= maxpve)
+ rval -= 0x00010000; /* Convert to -ve */
+ a1logd(p->log,9,"srval 0x%x, ",rval);
+ fval = (double)(int)rval;
+ a1logd(p->log,9,"fval %.0f, ",fval);
+ fval -= avlastv;
+ a1logd(p->log,9,"fval-av %.0f, ",fval);
+
+#ifdef ENABLE_NONLINCOR
+ /* Linearise */
+ for (lval = polys[npoly-1], k = npoly-2; k >= 0; k--)
+ lval = lval * fval + polys[k];
+#else
+ lval = fval;
+#endif
+ a1logd(p->log,9,"lval %.1f, ",lval);
+
+ /* And scale to be an absolute sensor reading */
+ absraw[i][j] = lval * scale;
+ a1logd(p->log,9,"absval %.1f\n",lval * scale);
+ // a1logd(p->log,3,"Meas %d band %d raw = %f\n",i,j,fval);
+ }
+
+ /* Duplicate last values in buffer to make up to 128 */
+ absraw[i][0] = absraw[i][1];
+ absraw[i][127] = absraw[i][126];
+ }
+ }
+
+ return I1PRO_OK;
+}
+
+/* Take a raw value, and convert it into an absolute raw value. */
+/* Note that linearisation is ignored, since it is assumed to be insignificant */
+/* to the black threshold and saturation values. */
+double i1pro_raw_to_absraw(
+ i1pro *p,
+ double raw, /* Input value */
+ double inttime, /* Integration time used */
+ int gainmode /* Gain mode, 0 = normal, 1 = high */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ int i, j, k;
+ double gain;
+ double scale; /* Absolute scale value */
+ double fval;
+
+ if (gainmode) {
+ gain = m->highgain;
+ } else {
+ gain = 1.0;
+ }
+ scale = 1.0/(inttime * gain);
+
+ return raw * scale;
+}
+
+
+/* Invert a polinomial equation. */
+/* Since the linearisation is nearly a straight line, */
+/* a simple Newton inversion will suffice. */
+static double inv_poly(double *polys, int npoly, double inv) {
+ double outv = inv, lval, del = 100.0;
+ int i, k;
+
+ for (i = 0; i < 200 && fabs(del) > 1e-7; i++) {
+ for (lval = polys[npoly-1], k = npoly-2; k >= 0; k--) {
+ lval = lval * outv + polys[k];
+ }
+ del = (inv - lval);
+ outv += 0.99 * del;
+ }
+
+ return outv;
+}
+
+/* Take a single set of absolute linearised sensor values and */
+/* convert them back into Rev A..D raw reading values. */
+/* This is used for saving a calibration to the EEProm */
+i1pro_code i1pro_absraw_to_meas(
+ i1pro *p,
+ int *meas, /* Return raw measurement data */
+ double *absraw, /* Array of [-1 nraw] value to process */
+ double inttime, /* Integration time used */
+ int gainmode /* Gain mode, 0 = normal, 1 = high */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned int maxpve = m->maxpve; /* maximum +ve sensor value + 1 */
+ int i, j, k;
+ double avlastv = 0.0;
+ double gain;
+ int npoly; /* Number of linearisation coefficients */
+ double *polys; /* the coeficients */
+ double scale; /* Absolute scale value */
+
+ if (m->subtmode) {
+ a1logd(p->log,1,"i1pro_absraw_to_meas subtmode set\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ if (gainmode) {
+ gain = m->highgain;
+ npoly = m->nlin1;
+ polys = m->lin1;
+ } else {
+ gain = 1.0;
+ npoly = m->nlin0;
+ polys = m->lin0;
+ }
+ scale = 1.0/(inttime * gain);
+
+ for (j = 0; j < 128; j++) {
+ double fval, lval;
+ unsigned int rval;
+
+ /* Unscale from absolute sensor reading */
+ lval = absraw[j] / scale;
+
+#ifdef ENABLE_NONLINCOR
+ /* Un-linearise */
+ fval = inv_poly(polys, npoly, lval);
+#else
+ fval = lval;
+#endif
+
+ if (fval < (double)((int)maxpve-65536))
+ fval = (double)((int)maxpve-65536);
+ else if (fval > (double)(maxpve-1))
+ fval = (double)(maxpve-1);
+
+ rval = (unsigned int)(int)floor(fval + 0.5);
+ meas[j] = rval;
+ }
+ return I1PRO_OK;
+}
+
+/* Average a set of measurements into one. */
+/* Return zero if readings are consistent and not saturated. */
+/* Return nz with bit 1 set if the readings are not consistent */
+/* Return nz with bit 2 set if the readings are saturated */
+/* Return the highest individual element. */
+/* Return the overall average. */
+int i1pro_average_multimeas(
+ i1pro *p,
+ double *avg, /* return average [-1 nraw] */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to average */
+ int nummeas, /* number of readings to be averaged */
+ double *phighest, /* If not NULL, return highest value from all bands and msrmts. */
+ double *poallavg, /* If not NULL, return overall average of bands and measurements */
+ double satthresh, /* Sauration threshold, 0 for none */
+ double darkthresh /* Dark threshold (used for consistency check scaling) */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ int i, j;
+ double highest = -1e6;
+ double oallavg = 0.0;
+ double avgoverth = 0.0; /* Average over threshold */
+ double maxavg = -1e38; /* Track min and max averages of readings */
+ double minavg = 1e38;
+ double norm;
+ int rv = 0;
+
+ a1logd(p->log,3,"i1pro_average_multimeas %d readings\n",nummeas);
+
+ for (j = -1; j < 128; j++)
+ avg[j] = 0.0;
+
+ /* Now process the buffer values */
+ for (i = 0; i < nummeas; i++) {
+ double measavg = 0.0;
+ int k;
+
+ for (j = k = 0; j < m->nraw; j++) {
+ double val;
+
+ val = multimeas[i][j];
+
+ avg[j] += val; /* Per value average */
+
+ /* Skip 0 and 127 cell values for RevA-D */
+ if (m->nsen == m->nraw && (j == 0 || j == 127))
+ continue;
+
+ if (val > highest)
+ highest = val;
+ if (val > satthresh)
+ avgoverth++;
+ measavg += val;
+ k++;
+ }
+ measavg /= (double)k;
+ oallavg += measavg;
+ if (measavg < minavg)
+ minavg = measavg;
+ if (measavg > maxavg)
+ maxavg = measavg;
+
+ /* and shielded values */
+ avg[-1] += multimeas[i][-1];
+ }
+
+ for (j = -1; j < 128; j++)
+ avg[j] /= (double)nummeas;
+ oallavg /= (double)nummeas;
+ avgoverth /= (double)nummeas;
+
+ if (phighest != NULL)
+ *phighest = highest;
+
+ if (poallavg != NULL)
+ *poallavg = oallavg;
+
+ if (satthresh > 0.0 && avgoverth > 0.0)
+ rv |= 2;
+
+ norm = fabs(0.5 * (maxavg+minavg));
+ a1logd(p->log,4,"norm = %f, dark thresh = %f\n",norm,darkthresh);
+ if (norm < (2.0 * darkthresh))
+ norm = 2.0 * darkthresh;
+
+ a1logd(p->log,4,"overall avg = %f, minavg = %f, maxavg = %f, variance %f, shielded avg %f\n",
+ oallavg,minavg,maxavg,(maxavg - minavg)/norm, avg[-1]);
+ if ((maxavg - minavg)/norm > PATCH_CONS_THR) {
+ a1logd(p->log,2,"Reading is inconsistent: (maxavg %f - minavg %f)/norm %f = %f > thresh %f, darkthresh %f\n",maxavg,minavg,norm,(maxavg - minavg)/norm,PATCH_CONS_THR, darkthresh);
+ rv |= 1;
+ }
+ return rv;
+}
+
+/* Minimum number of scan samples in a patch */
+#define MIN_SAMPLES 3
+
+/* Range of bands to detect transitions */
+#define BL 5 /* Start */
+#define BH 105 /* End */
+#define BW 5 /* Width */
+
+/* Record of possible patch */
+typedef struct {
+ int ss; /* Start sample index */
+ int no; /* Number of samples */
+ int use; /* nz if patch is to be used */
+} i1pro_patch;
+
+/* Recognise the required number of ref/trans patch locations, */
+/* and average the measurements within each patch. */
+/* *flags returns zero if readings are consistent and not saturated. */
+/* *flags returns nz with bit 1 set if the readings are not consistent */
+/* *flags returns nz with bit 2 set if the readings are saturated */
+/* *phighest returns the highest individual element. */
+/* (Doesn't extract [-1] shielded values, since they have already been used) */
+i1pro_code i1pro_extract_patches_multimeas(
+ i1pro *p,
+ int *flags, /* return flags */
+ double **pavg, /* return patch average [naptch][-1 nraw] */
+ int tnpatch, /* Target number of patches to recognise */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to extract from */
+ int nummeas, /* number of readings made */
+ double *phighest, /* If not NULL, return highest value from all bands and msrmts. */
+ double satthresh, /* Sauration threshold, 0 for none */
+ double inttime /* Integration time (used to adjust consistency threshold) */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ int i, j, k, pix;
+ double **sslope; /* Signed difference between i and i+1 */
+ double *slope; /* Accumulated absolute difference between i and i+1 */
+ double *fslope; /* Filtered slope */
+ i1pro_patch *pat; /* Possible patch information */
+ int npat, apat = 0;
+ double *maxval; /* Maximum input value for each wavelength */
+ double fmaxslope = 0.0;
+ double maxslope = 0.0;
+ double minslope = 1e38;
+ double thresh = 0.4; /* Slope threshold */
+ int try; /* Thresholding try */
+ double avglegth; /* Average length of patches */
+ int *sizepop; /* Size popularity of potential patches */
+ double median; /* median potential patch width */
+ double window; /* +/- around median to accept */
+ double highest = -1e6;
+ double white_avg; /* Average of (aproximate) white data */
+ int b_lo = BL; /* Patch detection low band */
+ int b_hi = BH; /* Patch detection low band */
+ int rv = 0;
+ double patch_cons_thr = PATCH_CONS_THR * m->scan_toll_ratio;
+#ifdef PATREC_DEBUG
+ double **plot;
+#endif
+
+ a1logd(p->log,2,"i1pro_extract_patches_multimeas looking for %d patches out of %d samples\n",tnpatch,nummeas);
+
+ /* Adjust bands if UV mode */
+ /* (This is insufficient for useful patch recognition) */
+ if (m->uv_en) {
+ b_lo = 91;
+ b_hi = 117;
+ }
+
+ maxval = dvectorz(-1, m->nraw-1);
+
+ /* Loosen consistency threshold for short integation time, */
+ /* to allow for extra noise */
+ if (inttime < 0.012308) /* Smaller than Rev A minimum int. time */
+ patch_cons_thr *= sqrt(0.012308/inttime);
+
+ /* Discover the maximum input value for normalisation */
+ for (j = 0; j < m->nraw; j ++) {
+ for (i = 0; i < nummeas; i++) {
+ if (multimeas[i][j] > maxval[j])
+ maxval[j] = multimeas[i][j];
+ }
+ if (maxval[j] < 1.0)
+ maxval[j] = 1.0;
+ }
+
+#ifdef PATREC_DEBUG
+ /* Plot out 6 lots of 8 values each */
+ plot = dmatrixz(0, 8, 0, nummeas-1);
+// for (j = 45; j <= (m->nraw-8); j += 100) /* Do just one band */
+#ifdef PATREC_ALLBANDS
+ for (j = 0; j <= (m->nraw-8); j += 8) /* Plot all the bands */
+#else
+ for (j = 5; j <= (m->nraw-8); j += 30) /* Do four bands */
+#endif
+ {
+ for (k = 0; k < 8; k ++) {
+ for (i = 0; i < nummeas; i++) {
+ plot[k][i] = multimeas[i][j+k]/maxval[j+k];
+ }
+ }
+ for (i = 0; i < nummeas; i++)
+ plot[8][i] = (double)i;
+ printf("Bands %d - %d\n",j,j+7);
+ do_plot10(plot[8], plot[0], plot[1], plot[2], plot[3], plot[4], plot[5], plot[6], plot[7], NULL, NULL, nummeas, 0);
+ }
+#endif /* PATREC_DEBUG */
+
+ sslope = dmatrixz(0, nummeas-1, -1, m->nraw-1);
+ slope = dvectorz(0, nummeas-1);
+ fslope = dvectorz(0, nummeas-1);
+ sizepop = ivectorz(0, nummeas-1);
+
+#ifndef NEVER /* Good with this on */
+ /* Average bands together */
+ for (i = 0; i < nummeas; i++) {
+ for (j = b_lo + BW; j < (b_hi - BW); j++) {
+ for (k = -b_lo; k <= BW; k++) /* Box averaging filter over bands */
+ sslope[i][j] += multimeas[i][j + k]/maxval[j];
+ }
+ }
+#else
+ /* Don't average bands */
+ for (i = 0; i < nummeas; i++) {
+ for (j = 0; j < m->nraw; j++) {
+ sslope[i][j] = multimeas[i][j]/maxval[j];
+ }
+ }
+#endif
+
+ /* Compute slope result over readings and bands */
+ /* Compute signed slope result over readings and bands */
+
+#ifdef NEVER /* Works well for non-noisy readings */
+ /* Median of 5 differences from 6 points */
+ for (i = 2; i < (nummeas-3); i++) {
+ for (j = b_lo; j < b_hi; j++) {
+ double sl, asl[5];
+ int r, s;
+ asl[0] = fabs(sslope[i-2][j] - sslope[i-1][j]);
+ asl[1] = fabs(sslope[i-1][j] - sslope[i-0][j]);
+ asl[2] = fabs(sslope[i-0][j] - sslope[i+1][j]);
+ asl[3] = fabs(sslope[i+1][j] - sslope[i+2][j]);
+ asl[4] = fabs(sslope[i+2][j] - sslope[i+3][j]);
+
+ /* Sort them */
+ for (r = 0; r < (5-1); r++) {
+ for (s = r+1; s < 5; s++) {
+ if (asl[s] < asl[r]) {
+ double tt;
+ tt = asl[s];
+ asl[s] = asl[r];
+ asl[r] = tt;
+ }
+ }
+ }
+ /* Pick middle one */
+ sl = asl[2];
+ if (sl > slope[i])
+ slope[i] = sl;
+ }
+ }
+
+#else /* Works better for noisy readings */
+
+ /* Compute sliding window average and deviation that contains */
+ /* our output point, and chose the average with the minimum deviation. */
+#define FW 3 /* Number of delta's to average */
+ for (i = FW-1; i < (nummeas-FW); i++) { /* Samples */
+ double basl, bdev; /* Best average slope, Best deviation */
+ double sl[2 * FW -1];
+ double asl[FW], dev[FW];
+ int slopen = 0;
+ double slopeth = 0.0;
+ int m, pp;
+
+ for (pp = 0; pp < 2; pp++) { /* For each pass */
+
+ for (j = b_lo; j < b_hi; j++) { /* Bands */
+
+ /* Compute differences for the range of our windows */
+ for (k = 0; k < (2 * FW -1); k++)
+ sl[k] = sslope[i+k-FW+1][j] - sslope[i+k+-FW+2][j];
+
+ /* For each window offset, compute average and deviation squared */
+ bdev = 1e38;
+ for (k = 0; k < FW; k++) {
+
+ /* Compute average of this window offset */
+ asl[k] = 0.0;
+ for (m = 0; m < FW; m++) /* For slope in window */
+ asl[k] += sl[k+m];
+ asl[k] /= (double)FW;
+
+ /* Compute deviation squared */
+ dev[k] = 0.0;
+ for (m = 0; m < FW; m++) {
+ double tt;
+ tt = sl[k+m] - asl[k];
+ dev[k] += tt * tt;
+ }
+ if (dev[k] < bdev)
+ bdev = dev[k];
+ }
+
+#ifndef NEVER
+ /* Weight the deviations with a triangular weighting */
+ /* to skew slightly towards the center */
+ for (k = 0; k < FW; k++) {
+ double wt;
+
+ wt = fabs(2.0 * k - (FW -1.0))/(FW-1.0);
+ dev[k] += wt * bdev;
+ }
+#endif
+
+ /* For each window offset, choose the one to use. */
+ bdev = 1e38;
+ basl = 0.0;
+ for (k = 0; k < FW; k++) {
+
+ /* Choose window average with smallest deviation squared */
+ if (dev[k] < bdev) {
+ bdev = dev[k];
+ basl = fabs(asl[k]);
+ }
+ }
+
+ if (pp == 0) { /* First pass, compute average slope over bands */
+ slope[i] += basl;
+
+ } else { /* Second pass, average slopes of bands over threshold */
+ if (basl > slopeth) {
+ slope[i] += basl;
+ slopen++;
+ }
+ }
+ } /* Next band */
+
+ if (pp == 0) {
+ slopeth = 1.0 * slope[i]/j; /* Compute threshold */
+ slope[i] = 0.0;
+ } else {
+ if (slopen > 0)
+ slope[i] /= slopen; /* Compute average of those over threshold */
+ }
+ } /* Next pass */
+ }
+#undef FW
+#endif
+
+#ifndef NEVER /* Good with this on */
+ /* Normalise the slope values */
+ /* Locate the minumum and maximum values */
+ maxslope = 0.0;
+ minslope = 1e38;
+ for (i = 4; i < (nummeas-4); i++) {
+ double avs;
+
+ if (slope[i] > maxslope)
+ maxslope = slope[i];
+
+ /* Simple moving average for min comp. */
+ avs = 0.0;
+ for (j = -2; j <= 2; j++)
+ avs += slope[i+j];
+ avs /= 5.0;
+ if (avs < minslope)
+ minslope = avs;
+ }
+
+ /* Normalise the slope */
+ maxslope *= 0.5;
+ minslope *= 3.0;
+ for (i = 0; i < nummeas; i++) {
+ slope[i] = (slope[i] - minslope) / (maxslope - minslope);
+ if (slope[i] < 0.0)
+ slope[i] = 0.0;
+ else if (slope[i] > 1.0)
+ slope[i] = 1.0;
+ }
+
+ /* "Automatic Gain control" the raw slope information. */
+#define LFW 20 /* Half width of triangular filter */
+ for (i = 0; i < nummeas; i++) {
+ double sum, twt;
+
+ sum = twt = 0.0;
+ for (j = -LFW; j <= LFW; j++) {
+ double wt;
+ if ((i+j) < 0 || (i+j) >= nummeas)
+ continue;
+
+ wt = ((LFW-abs(j))/(double)LFW);
+
+ sum += wt * slope[i+j];
+ twt += wt;
+ }
+ fslope[i] = sum/twt;
+ if (fslope[i] > fmaxslope)
+ fmaxslope = fslope[i];
+ }
+#undef LFW
+
+#ifdef NEVER /* Better with the off, for very noisy samples */
+ /* Apply AGC with limited gain */
+ for (i = 0; i < nummeas; i++) {
+ if (fslope[i] > fmaxslope/4.0)
+ slope[i] = slope[i]/fslope[i];
+ else
+ slope[i] = slope[i] * 4.0/fmaxslope;
+ }
+#endif
+#endif /* NEVER */
+
+ /* Locate the minumum and maximum values */
+ maxslope = 0.0;
+ minslope = 1e38;
+ for (i = 4; i < (nummeas-4); i++) {
+ double avs;
+
+ if (slope[i] > maxslope)
+ maxslope = slope[i];
+
+ /* Simple moving average for min comp. */
+ avs = 0.0;
+ for (j = -2; j <= 2; j++)
+ avs += slope[i+j];
+ avs /= 5.0;
+ if (avs < minslope)
+ minslope = avs;
+ }
+
+#ifndef NEVER /* Good with this on */
+ /* Normalise the slope again */
+ maxslope *= 0.3;
+ minslope *= 3.0;
+ for (i = 0; i < nummeas; i++) {
+ slope[i] = (slope[i] - minslope) / (maxslope - minslope);
+ if (slope[i] < 0.0)
+ slope[i] = 0.0;
+ else if (slope[i] > 1.0)
+ slope[i] = 1.0;
+ }
+#endif
+
+#ifdef PATREC_DEBUG
+ printf("Slope filter output\n");
+ for (i = 0; i < nummeas; i++) {
+ int jj;
+ for (jj = 0, j = b_lo; jj < 6 && j < b_hi; jj++, j += ((b_hi-b_lo)/6)) {
+ double sum = 0.0;
+ for (k = -b_lo; k <= BW; k++) /* Box averaging filter over bands */
+ sum += multimeas[i][j + k];
+ plot[jj][i] = sum/((2.0 * b_lo + 1.0) * maxval[j+k]);
+ }
+ }
+ for (i = 0; i < nummeas; i++)
+ plot[6][i] = (double)i;
+ do_plot6(plot[6], slope, plot[0], plot[1], plot[2], plot[3], plot[4], nummeas);
+#endif /* PATREC_DEBUG */
+
+ free_dvector(fslope, 0, nummeas-1);
+ free_dmatrix(sslope, 0, nummeas-1, -1, m->nraw-1);
+
+ /* Now threshold the measurements into possible patches */
+ apat = 2 * nummeas;
+ if ((pat = (i1pro_patch *)malloc(sizeof(i1pro_patch) * apat)) == NULL) {
+ a1logd(p->log, 1, "i1pro: malloc of patch structures failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ avglegth = 0.0;
+ for (npat = i = 0; i < (nummeas-1); i++) {
+ if (slope[i] > thresh)
+ continue;
+
+ /* Start of a new patch */
+ if (npat >= apat) {
+ apat *= 2;
+ if ((pat = (i1pro_patch *)realloc(pat, sizeof(i1pro_patch) * apat)) == NULL) {
+ a1logd(p->log, 1, "i1pro: reallloc of patch structures failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+ }
+ pat[npat].ss = i;
+ pat[npat].no = 2;
+ pat[npat].use = 0;
+ for (i++; i < (nummeas-1); i++) {
+ if (slope[i] > thresh)
+ break;
+ pat[npat].no++;
+ }
+ avglegth += (double) pat[npat].no;
+ npat++;
+ }
+ a1logd(p->log,7,"Number of patches = %d\n",npat);
+
+ /* We don't count the first and last patches, as we assume they are white leader */
+ if (npat < (tnpatch + 2)) {
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,2,"Patch recog failed - unable to detect enough possible patches\n");
+ return I1PRO_RD_NOTENOUGHPATCHES;
+ } else if (npat >= (2 * tnpatch) + 2) {
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,2,"Patch recog failed - detecting too many possible patches\n");
+ return I1PRO_RD_TOOMANYPATCHES;
+ }
+ avglegth /= (double)npat;
+
+ for (i = 0; i < npat; i++) {
+ a1logd(p->log,7,"Raw patch %d, start %d, length %d\n",i, pat[i].ss, pat[i].no);
+ }
+
+ /* Accumulate popularity ccount of possible patches */
+ for (i = 1; i < (npat-1); i++)
+ sizepop[pat[i].no]++;
+
+ /* Locate the median potential patch width */
+ for (j = 0, i = 0; i < nummeas; i++) {
+ j += sizepop[i];
+ if (j >= ((npat-2)/2))
+ break;
+ }
+ median = (double)i;
+
+ a1logd(p->log,7,"Median patch width %f\n",median);
+
+ /* Now decide which patches to use. */
+ /* Try a widening window around the median. */
+ for (window = 0.2, try = 0; try < 15; window *= 1.4, try++) {
+ int bgcount = 0, bgstart = 0;
+ int gcount, gstart;
+ double wmin = median/(1.0 + window);
+ double wmax = median * (1.0 + window);
+
+ a1logd(p->log,7,"Window = %f - %f\n",wmin, wmax);
+ /* Track which is the largest contiguous group that */
+ /* is within our window */
+ gcount = gstart = 0;
+ for (i = 1; i < npat; i++) {
+ if (i < (npat-1) && pat[i].no <= wmax) { /* Small enough */
+ if (pat[i].no >= wmin) { /* And big enough */
+ if (gcount == 0) { /* Start of new group */
+ gcount++;
+ gstart = i;
+ a1logd(p->log,7,"Start group at %d\n",gstart);
+ } else {
+ gcount++; /* Continuing new group */
+ a1logd(p->log,7,"Continue group at %d, count %d\n",gstart,gcount);
+ }
+ }
+ } else { /* Too big or end of patches, end this group */
+ a1logd(p->log,7,"Terminating group group at %d, count %d\n",gstart,gcount);
+ if (gcount > bgcount) { /* New biggest group */
+ bgcount = gcount;
+ bgstart = gstart;
+ a1logd(p->log,7,"New biggest\n");
+ }
+ gcount = gstart = 0; /* End this group */
+ }
+ }
+ a1logd(p->log,7,"Biggest group is at %d, count %d\n",bgstart,bgcount);
+
+ if (bgcount == tnpatch) { /* We're done */
+ for (i = bgstart, j = 0; i < npat && j < tnpatch; i++) {
+ if (pat[i].no <= wmax && pat[i].no >= wmin) {
+ pat[i].use = 1;
+ j++;
+ if (pat[i].no < MIN_SAMPLES) {
+ a1logd(p->log,7,"Too few samples\n");
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,2,"Patch recog failed - patches sampled too sparsely\n");
+ return I1PRO_RD_NOTENOUGHSAMPLES;
+ }
+ }
+ }
+ break;
+
+ } else if (bgcount > tnpatch) {
+ a1logd(p->log,7,"Too many patches\n");
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,2,"Patch recog failed - detected too many consistent patches\n");
+ return I1PRO_RD_TOOMANYPATCHES;
+ }
+ }
+ if (try >= 15) {
+ a1logd(p->log,7,"Not enough patches\n");
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,2,"Patch recog failed - unable to find enough consistent patches\n");
+ return I1PRO_RD_NOTENOUGHPATCHES;
+ }
+
+ a1logd(p->log,7,"Got %d patches out of potential %d:\n",tnpatch, npat);
+ a1logd(p->log,7,"Average patch legth %f\n",avglegth);
+ for (i = 1; i < (npat-1); i++) {
+ if (pat[i].use == 0)
+ continue;
+ a1logd(p->log,7,"Patch %d, start %d, length %d:\n",i, pat[i].ss, pat[i].no, pat[i].use);
+ }
+
+ /* Now trim the patches simply by shrinking their windows */
+ for (k = 1; k < (npat-1); k++) {
+ int nno, trim;
+
+ if (pat[k].use == 0)
+ continue;
+
+
+ nno = (pat[k].no * 3)/4;
+ trim = (pat[k].no - nno)/2;
+
+ pat[k].ss += trim;
+ pat[k].no = nno;
+ }
+
+#ifdef PATREC_DEBUG
+ a1logd(p->log,7,"After trimming got:\n");
+ for (i = 1; i < (npat-1); i++) {
+ if (pat[i].use == 0)
+ continue;
+ printf("Patch %d, start %d, length %d:\n",i, pat[i].ss, pat[i].no, pat[i].use);
+ }
+
+ /* Create fake "slope" value that marks patches */
+ for (i = 0; i < nummeas; i++)
+ slope[i] = 1.0;
+ for (k = 1; k < (npat-1); k++) {
+ if (pat[k].use == 0)
+ continue;
+ for (i = pat[k].ss; i < (pat[k].ss + pat[k].no); i++)
+ slope[i] = 0.0;
+ }
+
+ printf("Trimmed output:\n");
+ for (i = 0; i < nummeas; i++) {
+ int jj;
+ for (jj = 0, j = b_lo; jj < 6 && j < b_hi; jj++, j += ((b_hi-b_lo)/6)) {
+ double sum = 0.0;
+ for (k = -b_lo; k <= BW; k++) /* Box averaging filter over bands */
+ sum += multimeas[i][j + k];
+ plot[jj][i] = sum/((2.0 * b_lo + 1.0) * maxval[j+k]);
+ }
+ }
+ for (i = 0; i < nummeas; i++)
+ plot[6][i] = (double)i;
+ do_plot6(plot[6], slope, plot[0], plot[1], plot[2], plot[3], plot[4], nummeas);
+#endif /* PATREC_DEBUG */
+
+#ifdef PATREC_DEBUG
+ free_dmatrix(plot, 0, 6, 0, nummeas-1);
+#endif /* PATREC_DEBUG */
+
+ /* Compute average of (aproximate) white */
+ white_avg = 0.0;
+ for (j = 1; j < (m->nraw-1); j++)
+ white_avg += maxval[j];
+ white_avg /= (m->nraw - 2.0);
+
+ /* Now process the buffer values */
+ for (i = 0; i < tnpatch; i++) {
+ for (j = 0; j < m->nraw; j++)
+ pavg[i][j] = 0.0;
+ }
+
+ for (pix = 0, k = 1; k < (npat-1); k++) {
+ double maxavg = -1e38; /* Track min and max averages of readings for consistency */
+ double minavg = 1e38;
+ double avgoverth = 0.0; /* Average over saturation threshold */
+ double cons; /* Consistency */
+
+ if (pat[k].use == 0)
+ continue;
+
+ if (pat[k].no <= MIN_SAMPLES) {
+ a1logd(p->log,7,"Too few samples (%d, need %d)\n",pat[k].no,MIN_SAMPLES);
+ free_dvector(slope, 0, nummeas-1);
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,2,"Patch recog failed - patches sampled too sparsely\n");
+ return I1PRO_RD_NOTENOUGHSAMPLES;
+ }
+
+ /* Measure samples that make up patch value */
+ for (i = pat[k].ss; i < (pat[k].ss + pat[k].no); i++) {
+ double measavg = 0.0;
+
+ for (j = 1; j < m->nraw-1; j++) {
+ double val;
+
+ val = multimeas[i][j];
+
+ if (val > highest)
+ highest = val;
+ if (val > satthresh)
+ avgoverth++;
+ measavg += val;
+ pavg[pix][j] += val;
+ }
+ measavg /= (m->nraw-2.0);
+ if (measavg < minavg)
+ minavg = measavg;
+ if (measavg > maxavg)
+ maxavg = measavg;
+
+ /* and the duplicated values at the end */
+ pavg[pix][0] += multimeas[i][0];
+ pavg[pix][127] += multimeas[i][127];
+ }
+
+ for (j = 0; j < m->nraw; j++)
+ pavg[pix][j] /= (double)pat[k].no;
+ avgoverth /= (double)pat[k].no;
+
+ if (satthresh > 0.0 && avgoverth >= 10.0)
+ rv |= 2;
+
+ cons = (maxavg - minavg)/white_avg;
+ a1logd(p->log,7,"Patch %d: consistency = %f%%, thresh = %f%%\n",pix,100.0 * cons, 100.0 * patch_cons_thr);
+ if (cons > patch_cons_thr) {
+ a1logd(p->log,2,"Patch recog failed - patch %d is inconsistent (%f%% > %f)\n",pix,cons, patch_cons_thr);
+ rv |= 1;
+ }
+ pix++;
+ }
+
+ if (phighest != NULL)
+ *phighest = highest;
+ if (flags != NULL)
+ *flags = rv;
+
+ free_dvector(slope, 0, nummeas-1);
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+
+ if (rv & 2)
+ a1logd(p->log,2,"Patch recog failed - some patches are saturated\n");
+
+ a1logd(p->log,2,"i1pro_extract_patches_multimeas done, sat = %s, inconsist = %s\n",
+ rv & 2 ? "true" : "false", rv & 1 ? "true" : "false");
+
+ return I1PRO_OK;
+}
+#undef BL
+#undef BH
+#undef BW
+
+
+/* Recognise any flashes in the readings, and */
+/* and average their values together as well as summing their duration. */
+/* Return nz on an error */
+/* (Doesn't extract [-1] shielded values, since they have already been used) */
+i1pro_code i1pro_extract_patches_flash(
+ i1pro *p,
+ int *flags, /* return flags */
+ double *duration, /* return duration */
+ double *pavg, /* return patch average [-1 nraw] */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to extract from */
+ int nummeas, /* number of readings made */
+ double inttime /* Integration time (used to compute duration) */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ int i, j, k, pix;
+ double minval, maxval; /* min and max input value at wavelength of maximum input */
+ double mean; /* Mean of the max wavelength band */
+ int maxband; /* Band of maximum value */
+ double thresh; /* Level threshold */
+ int fsampl; /* Index of the first sample over the threshold */
+ int nsampl; /* Number of samples over the threshold */
+ double *aavg; /* ambient average [-1 nraw] */
+ double finttime; /* Flash integration time */
+ int rv = 0;
+#ifdef PATREC_DEBUG
+ double **plot;
+#endif
+
+ a1logd(p->log,2,"i1pro_extract_patches_flash looking for flashes in %d measurements\n",nummeas);
+
+ /* Discover the maximum input value for flash dection */
+ maxval = -1e6;
+ maxband = 0;
+ for (j = 0; j < m->nraw; j ++) {
+ for (i = 0; i < nummeas; i++) {
+ if (multimeas[i][j] > maxval) {
+ maxval = multimeas[i][j];
+ maxband = j;
+ }
+ }
+ }
+
+ if (maxval <= 0.0) {
+ a1logd(p->log,2,"No flashes found in measurement\n");
+ return I1PRO_RD_NOFLASHES;
+ }
+
+ minval = 1e6;
+ mean = 0.0;
+ for (i = 0; i < nummeas; i++) {
+ mean += multimeas[i][maxband];
+ if (multimeas[i][maxband] < minval)
+ minval = multimeas[i][maxband];
+ }
+ mean /= (double)nummeas;
+
+ /* Set the threshold at 5% from mean towards max */
+ thresh = (3.0 * mean + maxval)/4.0;
+ a1logd(p->log,7,"i1pro_extract_patches_flash band %d minval %f maxval %f, mean = %f, thresh = %f\n",maxband,minval,maxval,mean, thresh);
+
+#ifdef PATREC_DEBUG
+ /* Plot out 6 lots of 6 values each */
+ plot = dmatrixz(0, 6, 0, nummeas-1);
+ for (j = maxband -3; j>= 0 && j < (m->nraw-6); j += 100) /* Do one set around max */
+ {
+ for (k = 0; k < 6; k ++) {
+ for (i = 0; i < nummeas; i++) {
+ plot[k][i] = multimeas[i][j+k]/maxval;
+ }
+ }
+ for (i = 0; i < nummeas; i++)
+ plot[6][i] = (double)i;
+ printf("Bands %d - %d\n",j,j+5);
+ do_plot6(plot[6], plot[0], plot[1], plot[2], plot[3], plot[4], plot[5], nummeas);
+ }
+ free_dmatrix(plot,0,6,0,nummeas-1);
+#endif /* PATREC_DEBUG */
+
+#ifdef PATREC_DEBUG
+ /* Plot just the pulses */
+ {
+ int start, end;
+
+ plot = dmatrixz(0, 6, 0, nummeas-1);
+
+ for(j = 0, start = -1, end = 0;;) {
+
+ for (start = -1, i = end; i < nummeas; i++) {
+ if (multimeas[i][maxband] >= thresh) {
+ if (start < 0)
+ start = i;
+ } else if (start >= 0) {
+ end = i;
+ break;
+ }
+ }
+ if (start < 0)
+ break;
+ start -= 3;
+ if (start < 0)
+ start = 0;
+ end += 4;
+ if (end > nummeas)
+ end = nummeas;
+
+ for (i = start; i < end; i++, j++) {
+ int q;
+
+ plot[6][j] = (double)j;
+#ifdef NEVER /* Plot +/-3 around maxband */
+ for (q = 0, k = maxband -3; k < (maxband+3) && k >= 0 && k < m->nraw; k++, q++) {
+ plot[q][j] = multimeas[i][k]/maxval;
+ }
+#else
+ /* plot max of bands in 6 segments */
+ for (q = 0; q < 6; q++) {
+ int ss, ee;
+
+ plot[q][j] = -1e60;
+ ss = q * (m->nraw/6);
+ ee = (q+1) * (m->nraw/6);
+ for (k = ss; k < ee; k++) {
+ if (multimeas[i][k]/maxval > plot[q][j])
+ plot[q][j] = multimeas[i][k]/maxval;
+ }
+ }
+#endif
+ }
+ }
+ do_plot6(plot[6], plot[0], plot[1], plot[2], plot[3], plot[4], plot[5], j);
+ free_dmatrix(plot,0,6,0,nummeas-1);
+ }
+#endif
+
+ /* Locate the first sample over the threshold, and the */
+ /* total number of samples in the pulses. */
+ fsampl = -1;
+ for (nsampl = i = 0; i < nummeas; i++) {
+ for (j = 0; j < m->nraw-1; j++) {
+ if (multimeas[i][j] >= thresh)
+ break;
+ }
+ if (j < m->nraw-1) {
+ if (fsampl < 0)
+ fsampl = i;
+ nsampl++;
+ }
+ }
+ a1logd(p->log,7,"Number of flash patches = %d\n",nsampl);
+ if (nsampl == 0)
+ return I1PRO_RD_NOFLASHES;
+
+ /* See if there are as many samples before the first flash */
+ if (nsampl < 6)
+ nsampl = 6;
+
+ /* Average nsample samples of ambient */
+ i = (fsampl-3-nsampl);
+ if (i < 0)
+ return I1PRO_RD_NOAMBB4FLASHES;
+ a1logd(p->log,7,"Ambient samples %d to %d \n",i,fsampl-3);
+ aavg = dvectorz(-1, m->nraw-1);
+ for (nsampl = 0; i < (fsampl-3); i++) {
+ for (j = 0; j < m->nraw-1; j++)
+ aavg[j] += multimeas[i][j];
+ nsampl++;
+ }
+
+ /* Average all the values over the threshold, */
+ /* and also one either side of flash */
+ for (j = 0; j < m->nraw-1; j++)
+ pavg[j] = 0.0;
+
+ for (k = 0, i = 1; i < (nummeas-1); i++) {
+ int sample = 0;
+ for (j = 0; j < m->nraw-1; j++) {
+ if (multimeas[i-1][j] >= thresh) {
+ sample = 1;
+ break;
+ }
+ if (multimeas[i][j] >= thresh) {
+ sample = 1;
+ break;
+ }
+ if (multimeas[i+1][j] >= thresh) {
+ sample = 1;
+ break;
+ }
+ }
+ if (j < m->nraw-1) {
+ a1logd(p->log,7,"Integrating flash sample no %d \n",i);
+ for (j = 0; j < m->nraw-1; j++)
+ pavg[j] += multimeas[i][j];
+ k++;
+ }
+ }
+ for (j = 0; j < m->nraw-1; j++)
+ pavg[j] = pavg[j]/(double)k - aavg[j]/(double)nsampl;
+
+ a1logd(p->log,7,"Number of flash patches integrated = %d\n",k);
+
+ finttime = inttime * (double)k;
+ if (duration != NULL)
+ *duration = finttime;
+
+ /* Convert to cd/m^2 seconds */
+ for (j = 0; j < m->nraw-1; j++)
+ pavg[j] *= finttime;
+
+ if (flags != NULL)
+ *flags = rv;
+
+ free_dvector(aavg, -1, m->nraw-1);
+
+ return I1PRO_OK;
+}
+
+
+/* Subtract the black level. */
+/* If Rev E, also adjust according to shielded cells, and linearise. */
+void i1pro_sub_absraw(
+ i1pro *p,
+ int nummeas, /* Return number of readings measured */
+ double inttime, /* Integration time used */
+ int gainmode, /* Gain mode, 0 = normal, 1 = high */
+ double **absraw, /* Source/Desination array [-1 nraw] */
+ double *sub /* Black value to subtract [-1 nraw] */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ double gain;
+ int npoly; /* Number of linearisation coefficients */
+ double *polys; /* the coeficients */
+ double scale; /* Absolute scale value */
+ double submax = -1e6; /* Subtraction value maximum */
+ int i, j;
+
+ if (gainmode) {
+ gain = m->highgain;
+ npoly = m->nlin1;
+ polys = m->lin1;
+ } else {
+ gain = 1.0;
+ npoly = m->nlin0;
+ polys = m->lin0;
+ }
+ scale = 1.0/(inttime * gain); /* To scale RevE linearity */
+
+ /* Adjust black to allow for temperature change by using the */
+ /* shielded cell values as a reference. */
+ /* We use a heuristic to compute a zero based scale for adjusting the */
+ /* black. It's not clear why it works best this way, or how */
+ /* dependent on the particular instrument the magic numbers are, */
+ /* but it reduces the black level error from over 10% to about 0.3% */
+ if (p->itype == instI1Pro2) {
+// double xx[NSEN_MAX], in[NSEN_MAX], res[NSEN_MAX];
+ double asub[NSEN_MAX];
+ double avgscell, zero;
+
+ /* Locate largest of black */
+ for (j = 0; j < m->nraw; j++) {
+ if (sub[j] > submax)
+ submax = sub[j];
+ }
+
+ /* Average the shielded cell value of all the readings */
+ avgscell = 0.0;
+ for (i = 0; i < nummeas; i++)
+ avgscell += absraw[i][-1];
+ avgscell /= (double)nummeas;
+
+ /* Compute scaling zero */
+ zero = 1.144 * 0.5 * (avgscell + sub[-1]);
+
+ /* make sure that the zero point is above any black value */
+ if (zero < (1.01 * avgscell))
+ zero = 1.01 * avgscell;
+ if (zero < (1.01 * sub[-1]))
+ zero = 1.01 * sub[-1];
+ if (zero < (1.01 * submax))
+ zero = 1.01 * submax;
+
+ a1logd(p->log,2,"Black shielded value = %f, Reading shielded value = %f\n",sub[-1], avgscell);
+ /* Compute the adjusted black */
+ for (j = 0; j < m->nraw; j++) {
+#ifdef NEVER
+ /* simple additive correction */
+# pragma message("######### i1pro2 Simple shielded cell temperature correction! ########")
+ asub[j] = sub[j] + avgscell - sub[-1];
+#else
+ /* heuristic scaled correction */
+ asub[j] = zero - (zero - sub[j]) * (zero - avgscell)/(zero - sub[-1]);
+#endif
+ }
+
+ /* Subtract the black */
+ for (i = 0; i < nummeas; i++) {
+ for (j = 0; j < m->nraw; j++) {
+// xx[j] = j, in[j] = absraw[i][j];
+
+ absraw[i][j] -= asub[j]; /* Subtract adjusted black */
+
+// res[j] = absraw[i][j] + (double)((int)(avgscell/20.0)) * 20.0;
+#ifdef ENABLE_NONLINCOR
+ /* Linearise */
+ {
+ int k;
+ double fval, lval;
+
+ fval = absraw[i][j] / scale; /* Scale back to sensor value range */
+
+ for (lval = polys[npoly-1], k = npoly-2; k >= 0; k--)
+ lval = lval * fval + polys[k];
+
+ absraw[i][j] = scale * lval; /* Rescale back to absolute range */
+ }
+#endif
+ }
+#ifdef PLOT_BLACK_SUBTRACT /* Plot black adjusted levels */
+ printf("black = meas, red = black, green = adjuste black, blue = result\n");
+ do_plot6(xx, in, sub, adjsub, res, NULL, NULL, m->nraw);
+#endif
+ }
+
+ /* Rev A-D don't have shielded reference cells */
+ } else {
+
+ /* For each measurement */
+ for (i = 0; i < nummeas; i++) {
+ for (j = -1; j < m->nraw; j++) {
+ absraw[i][j] -= sub[j];
+ }
+ }
+ }
+}
+
+/* Convert an absraw array from raw wavelengths to output wavelenths */
+/* for a given [std res, high res] and [emis/tras, reflective] mode */
+void i1pro_absraw_to_abswav(
+ i1pro *p,
+ int highres, /* 0 for std res, 1 for high res */
+ int refl, /* 0 for emis/trans, 1 for reflective */
+ int nummeas, /* Return number of readings measured */
+ double **abswav, /* Desination array [nwav] */
+ double **absraw /* Source array [-1 nraw] */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ int i, j, k, cx, sx;
+ double *tm; /* Temporary array */
+
+ tm = dvector(0, m->nwav[highres]-1);
+
+ /* For each measurement */
+ for (i = 0; i < nummeas; i++) {
+
+ /* For each output wavelength */
+ for (cx = j = 0; j < m->nwav[highres]; j++) {
+ double oval = 0.0;
+
+ /* For each matrix value */
+ sx = m->mtx[highres][refl].index[j]; /* Starting index */
+ for (k = 0; k < m->mtx[highres][refl].nocoef[j]; k++, cx++, sx++) {
+ oval += m->mtx[highres][refl].coef[cx] * absraw[i][sx];
+ }
+ abswav[i][j] = tm[j] = oval;
+ }
+
+ if (p->itype == instI1Pro2) {
+ /* Now apply stray light compensation */
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav[highres]; j++) {
+ double oval = 0.0;
+
+ /* For each matrix value */
+ for (k = 0; k < m->nwav[highres]; k++)
+ oval += m->straylight[highres][j][k] * tm[k];
+ abswav[i][j] = oval;
+ }
+#ifdef PLOT_DEBUG
+ printf("Before & after stray light correction:\n");
+ plot_wav_2(m, highres, tm, abswav[i]);
+#endif /* PLOT_DEBUG */
+ }
+ }
+ free_dvector(tm, 0, m->nwav[highres]-1);
+}
+
+/* Convert an abswav array of output wavelengths to scaled output readings. */
+void i1pro_scale_specrd(
+ i1pro *p,
+ double **outspecrd, /* Destination */
+ int numpatches, /* Number of readings/patches */
+ double **inspecrd /* Source */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ int i, j;
+
+ /* For each measurement */
+ for (i = 0; i < numpatches; i++) {
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav[m->highres]; j++) {
+ outspecrd[i][j] = inspecrd[i][j] * s->cal_factor[m->highres][j];
+ }
+ }
+}
+
+
+/* =============================================== */
+/* Rev E wavelength calibration */
+
+/*
+ The Rev E has a wavelength reference LED amd
+ stores a reference raw spectrum of it in its
+ calibrated state, together with an polinomial
+ defining the raw bin no. to wavelength conversion.
+
+ By measuring the wavelength LED and finding
+ the best positional match against the reference
+ spectrum, a CCD bin offset can be computed
+ to compensate for any shift in the optical or
+ physical alignment of spectrum against CCD.
+
+ To use the adjustment, the raw to wave subsampling
+ filters need to be regenerated, and to ensure that
+ the instrument returns readings very close to the
+ manufacturers driver, the same underlying filter
+ creation mathematics needs to be used.
+
+ The manufacturers filter weights are the accumulated
+ third order Lagrange polynomial weights of the
+ integration of a 20 nm wide triange spectrum
+ centered at each output wavelength, discretely
+ integrated between the range of the middle two points
+ of the Lagrange interpolator. The triangle response
+ being integrated has an area of exactly 1.0.
+
+ */
+
+/* Invert a raw2wavlength polinomial equation. */
+/* Use simple Newton inversion will suffice. */
+static double inv_raw2wav(double *polys, int npoly, double inv) {
+ double outv = 560.0, lval, del = 100.0;
+ int i, k;
+
+ for (i = 0; i < 200 && fabs(del) > 1e-7; i++) {
+ for (lval = polys[npoly-1], k = npoly-2; k >= 0; k--) {
+ lval = lval * outv + polys[k];
+ }
+ del = (inv - lval);
+ outv += 0.4 * del;
+ }
+
+ return 128.0 - outv;
+}
+
+/* return the uncalibrated wavelength given a raw bin value */
+/* (Always uses reflective RevE wav2cal) */
+static double i1pro_raw2wav_uncal(i1pro *p, double raw) {
+ i1proimp *m = (i1proimp *)p->m;
+ double ov;
+ int k;
+
+ if (p->itype == instI1Pro2) {
+ raw = 128.0 - raw; /* Quadratic expects +ve correlation */
+
+ /* Compute polinomial */
+ for (ov = m->wlpoly1[4-1], k = 4-2; k >= 0; k--)
+ ov = ov * raw + m->wlpoly1[k];
+ } else {
+ co pp;
+
+ if (m->raw2wav == NULL) {
+ a1loge(p->log,1,"i1pro_raw2wav_uncal called when hi-res not inited\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+ pp.p[0] = raw;
+ m->raw2wav->interp(m->raw2wav, &pp);
+ ov = pp.v[0];
+ }
+
+ return ov;
+}
+
+/* return the calibrated wavelength given a raw bin value for the given mode */
+static double i1pro_raw2wav(i1pro *p, int refl, double raw) {
+ i1proimp *m = (i1proimp *)p->m;
+ double ov;
+ int k;
+
+ if (p->itype == instI1Pro2) {
+ i1pro_state *s = &m->ms[m->mmode];
+
+ /* Correct for CCD offset and scale back to reference */
+ raw = raw - s->wl_led_off + m->wl_led_ref_off;
+
+ raw = 128.0 - raw; /* Quadratic expects +ve correlation */
+
+ /* Compute polinomial */
+ if (refl) {
+ for (ov = m->wlpoly1[4-1], k = 4-2; k >= 0; k--)
+ ov = ov * raw + m->wlpoly1[k];
+ } else {
+ for (ov = m->wlpoly2[4-1], k = 4-2; k >= 0; k--)
+ ov = ov * raw + m->wlpoly2[k];
+ }
+ } else {
+ co pp;
+
+ /* If not RevE there is no WL calibration */
+ if (m->raw2wav == NULL) {
+ a1loge(p->log,1,"i1pro_raw2wav_uncal called when hi-res not inited\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+ pp.p[0] = raw;
+ m->raw2wav->interp(m->raw2wav, &pp);
+ ov = pp.v[0];
+ }
+
+ return ov;
+}
+
+/* Powell minimisation contxt for WL calibration */
+typedef struct {
+ double ref_max; /* reference maximum level */
+ double *wl_ref; /* Wavlength reference samples */
+ int wl_ref_n; /* Number of wavelength references */
+ double *wl_meas; /* Wavelength measurement samples */
+ int wl_meas_n; /* Number of wavelength measurement samples */
+ int plot; /* Plot each try */
+} wlcal_cx;
+
+/* Powell minimisation callback function */
+/* Parameters being optimized are magnitude, offset and scale */
+static double wlcal_opt1(void *vcx, double tp[]) {
+#ifdef PLOT_DEBUG
+ int pix = 0;
+ double xx[1024];
+ double y1[1024]; /* interpolate ref */
+ double y2[1024]; /* Measurement */
+ double y3[1024]; /* Error */
+#endif
+ wlcal_cx *cx = (wlcal_cx *)vcx;
+ double vv, rv = 0.0;
+ int si, i;
+
+ si = (int)tp[1];
+
+ /* i = Measurement index */
+ for (i = si; i < cx->wl_meas_n; i++) {
+
+ double xv; /* offset & scaled measurement index */
+ int ix; /* Lagrange base offset */
+ double yv;
+
+ xv = ((double)i - tp[1]); /* fitted measurement location in reference no scale */
+
+ ix = ((int)xv) - 1; /* Reference index of Lagrange for this xv */
+ if (ix < 0)
+ continue;
+ if ((ix + 3) > cx->wl_ref_n)
+ break;
+
+ /* Compute interpolated value of reference using Lagrange: */
+ yv = cx->wl_ref[ix+0] * (xv-(ix+1)) * (xv-(ix+2)) * (xv-(ix+3))
+ /((0.0-1.0) * (0.0-2.0) * (0.0-3.0))
+ + cx->wl_ref[ix+1] * (xv-(ix+0)) * (xv-(ix+2)) * (xv-(ix+3))
+ /((1.0-0.0) * (1.0-2.0) * (1.0-3.0))
+ + cx->wl_ref[ix+2] * (xv-(ix+0)) * (xv-(ix+1)) * (xv-(ix+3))
+ /((2.0-0.0) * (2.0-1.0) * (2.0-3.0))
+ + cx->wl_ref[ix+3] * (xv-(ix+0)) * (xv-(ix+1)) * (xv-(ix+2))
+ /((3.0-0.0) * (3.0-1.0) * (3.0-2.0));
+ vv = yv - tp[0] * cx->wl_meas[i];
+
+ /* Weight error linearly with magnitude, to emphasise peak error */
+ /* rather than what's happening down in the noise */
+ vv = vv * vv * (yv + 1.0)/(cx->ref_max+1.0);
+
+#ifdef PLOT_DEBUG
+ if (cx->plot) {
+ xx[pix] = (double)i;
+ y1[pix] = yv;
+ y2[pix] = tp[0] * cx->wl_meas[i];
+// y3[pix] = 2000.0 * (0.02 + yv/cx->ref_max); /* Weighting */
+ y3[pix] = 0.5 * vv; /* Error squared */
+ pix++;
+ }
+#endif
+ rv += vv;
+ }
+#ifdef PLOT_DEBUG
+ if (cx->plot) {
+ printf("Params %f %f -> err %f\n", tp[0], tp[1], rv);
+ do_plot(xx, y1, y2, y3, pix);
+ }
+#endif
+//printf("~1 %f %f -> %f\n", tp[0], tp[1], rv);
+ return rv;
+}
+
+#ifdef SALONEINSTLIB
+/* Do a rudimetrary 2d optimization that uses exaustive */
+/* search with hierarchical step sizes */
+int wloptimize(double *cparm,
+ double *ss,
+ double tol,
+ double (*funk)(void *fdata, double tp[]),
+ void *fdata
+) {
+ double range[2][2]; /* [dim][min/max] */
+ double val[2]; /* Current test values */
+ double bfit = 1e38; /* Current best fit values */
+ int dim;
+
+ for (dim = 0; dim < 2; dim++) {
+ range[dim][0] = cparm[dim] - ss[dim];
+ range[dim][1] = cparm[dim] + ss[dim];
+ val[dim] = cparm[dim];
+ }
+
+ /* Until we reach the tollerance */
+ for (;;) {
+ double mstep = 1e38;
+
+ for (dim = 0; dim < 2; dim++) {
+ double stepsz;
+ stepsz = (range[dim][1] - range[dim][0])/10.0;
+ if (stepsz < mstep)
+ mstep = stepsz;
+
+ /* Search in this dimension */
+ for (val[dim] = range[dim][0]; val[dim] <= range[dim][1]; val[dim] += stepsz) {
+ double fit;
+ fit = funk(fdata, val);
+ if (fit < bfit) {
+ cparm[dim] = val[dim];
+ bfit = fit;
+ }
+ }
+ val[dim] = cparm[dim];
+ range[dim][0] = val[dim] - stepsz;
+ range[dim][1] = val[dim] + stepsz;
+ }
+ if (mstep <= tol)
+ break;
+ }
+ return 0;
+}
+#endif /* SALONEINSTLIB */
+
+
+/* Given a raw measurement of the wavelength LED, */
+/* Compute the base offset that best fits it to the reference */
+i1pro_code i1pro2_match_wl_meas(i1pro *p, double *pled_off, double *wlraw) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+ int i;
+ int rpoff, mpoff; /* Peak offset */
+ int roff, moff; /* Base index */
+ double lhalf, rhalf;
+ double fwhm; /* Measured half width */
+ double rmax, mmax;
+ double magscale;
+ double led_off, off_nm;
+
+ /* Do simple match first - locate maximum */
+ rmax = -1e6;
+ rpoff = -1;
+ for (i = 0; i < m->wl_led_count; i++) {
+ if (m->wl_led_spec[i] > rmax) {
+ rmax = m->wl_led_spec[i]; /* Max of reference */
+ rpoff = i;
+ }
+ }
+
+ mmax = -1e6;
+ mpoff = -1;
+ for (i = 0; i < m->nraw; i++) {
+ if (wlraw[i] > mmax) {
+ mmax = wlraw[i]; /* Max of measurement */
+ mpoff = i;
+ }
+ }
+
+ if (mpoff < 0 || mpoff >= m->nraw) {
+ a1logd(p->log,1,"Couldn't locate WL measurement peak\n");
+ return I1PRO_WL_SHAPE;
+ }
+
+ /* Check magnitude is sufficient (not sure this is right, typically 5900 > 882) */
+ a1logd(p->log,2,"Measured WL level = %f, minimum needed = %f\n",mmax, m->wl_cal_min_level);
+ if (mmax < m->wl_cal_min_level) {
+ a1logd(p->log,1,"i1pro2_match_wl_meas peak magnitude too low\n");
+ return I1PRO_WL_TOOLOW;
+ }
+
+ /* Locate the half peak values */
+ for (i = 1; i < mpoff; i++) {
+ if (wlraw[i] > (mmax/2.0)) { /* Use linear interp */
+ lhalf = (wlraw[i] - mmax/2.0)/(wlraw[i] - wlraw[i-1]);
+ lhalf = lhalf * (i-1.0) + (1.0 - lhalf) * (double)i;
+ break;
+ }
+ }
+ if (i >= mpoff) {
+ a1logd(p->log,1,"Couldn't locate WL left half level\n");
+ return I1PRO_WL_SHAPE;
+ }
+ for (; i < m->nraw; i++) {
+ if (wlraw[i] < (mmax/2.0)) { /* Use linear interp */
+ rhalf = (mmax/2.0 - wlraw[i])/(wlraw[i-1] - wlraw[i]);
+ rhalf = rhalf * (i-1.0) + (1.0 - rhalf) * (double)i;
+ break;
+ }
+ }
+ if (i >= m->nraw) {
+ a1logd(p->log,1,"Couldn't locate WL righ half level\n");
+ return I1PRO_WL_SHAPE;
+ }
+ a1logd(p->log,5,"WL half levels at %f (%f nm) and %f (%f nm)\n",lhalf, i1pro_raw2wav_uncal(p, lhalf), rhalf, i1pro_raw2wav_uncal(p, rhalf));
+ fwhm = i1pro_raw2wav_uncal(p, lhalf) - i1pro_raw2wav_uncal(p, rhalf);
+ a1logd(p->log,3, "WL spectrum fwhm = %f\n",fwhm);
+ if (fwhm < (m->wl_cal_fwhm - m->wl_cal_fwhm_tol)
+ || fwhm > (m->wl_cal_fwhm + m->wl_cal_fwhm_tol)) {
+ a1logd(p->log,1,"WL fwhm %f is out of range %f .. %f\n",fwhm,m->wl_cal_fwhm - m->wl_cal_fwhm_tol,m->wl_cal_fwhm + m->wl_cal_fwhm_tol);
+ return I1PRO_WL_SHAPE;
+ }
+
+ roff = m->wl_led_ref_off; /* reference raw offset */
+ moff = mpoff - rpoff; /* rough measured raw offset */
+
+ a1logd(p->log,3, "Preliminary WL peak match at ref base offset %d into measurement\n", moff);
+
+ magscale = rmax/mmax; /* Initial scale to make them match */
+
+#ifdef PLOT_DEBUG
+ /* Plot the match */
+ {
+ double xx[1024];
+ double y1[1024];
+ double y2[1024];
+
+ for (i = 0; i < m->nraw; i++) {
+ xx[i] = (double)i;
+ y1[i] = 0.0;
+ if (i >= moff && (i - moff) < m->wl_led_count) {
+ y1[i] = m->wl_led_spec[i- moff];
+ }
+ y2[i] = wlraw[i] * magscale;
+ }
+ printf("Simple WL match, ref = black, meas = red:\n");
+ do_plot(xx, y1, y2, NULL, m->nraw);
+ }
+#endif
+
+ /* Now do a good match */
+ /*
+ Do Lagrange interpolation on the reference curve,
+ and use a minimizer to find the best fit (minimum weighted y error)
+ by optimizing the magnitude, offset and scale.
+ */
+
+ {
+ wlcal_cx cx;
+ double cparm[2]; /* fit parameters */
+ double ss[2]; /* Search range */
+
+ cparm[0] = magscale;
+ ss[0] = 0.2;
+ cparm[1] = (double)moff;
+ ss[1] = 4.0; /* == +- 12 nm */
+
+ cx.ref_max = rmax;
+ cx.wl_ref = m->wl_led_spec;
+ cx.wl_ref_n = m->wl_led_count;
+ cx.wl_meas = wlraw;
+ cx.wl_meas_n = m->nraw;
+// cx.plot = 1; /* Plot each trial */
+
+ /* We could use the scale to adjust the whole CCD range, */
+ /* but the manufacturers driver doesn't seem to do this, */
+ /* and it may be making the calibration sensitive to any */
+ /* changes in the WL LED spectrum shape. Instead we minimize */
+ /* the error weighted for the peak of the shape. */
+
+#ifdef SALONEINSTLIB
+ if (wloptimize(cparm, ss, 1e-7, wlcal_opt1, &cx))
+ a1logw(p->log,"wlcal_opt1 failed\n");
+#else
+ if (powell(NULL, 2, cparm, ss, 1e-6, 1000, wlcal_opt1, &cx, NULL, NULL))
+ a1logw(p->log,"wlcal_opt1 failed\n");
+#endif
+ a1logd(p->log,3,"WL best fit parameters: %f %f\n", cparm[0], cparm[1]);
+
+ led_off = cparm[1];
+
+#ifdef PLOT_DEBUG
+ /* Plot the final result */
+ printf("Best WL match, ref = black, meas = red, err = green:\n");
+ cx.plot = 1;
+ wlcal_opt1(&cx, cparm);
+#endif
+
+ /* If we have calibrated on the ambient cap, correct */
+ /* for the emissive vs. reflective raw2wav scaling factor */
+ if (mmax < 2500.0) {
+ double wlraw2 = m->wl_led_ref_off + (double)rpoff;
+ double raw, wlnm, wlraw1, refnm;
+ int k;
+
+ /* Convert from raw to wavelength using poly2 (emission) */
+ raw = 128.0 - wlraw2; /* Quadratic expects +ve correlation */
+ for (wlnm = m->wlpoly2[4-1], k = 4-2; k >= 0; k--)
+ wlnm = wlnm * raw + m->wlpoly2[k];
+
+ /* Convert from wavelength to raw using poly1 (reflectance) */
+ wlraw1 = inv_raw2wav(m->wlpoly1, 4, wlnm);
+//printf("emiss raw %f -> ref raw %f\n",wlraw2, wlraw1);
+
+ /* Adjust the raw correction to account for measuring it in emissive mode */
+ led_off = led_off + wlraw2 - wlraw1;
+
+ /* Hmm. This is rather suspect. The difference between the white reference */
+ /* calibrated wavelength offset and the ambient cap one is about -0.2788 raw. */
+ /* This is not explained by the poly1 vs. poly2 difference at the WL LED peak */
+ /* at 550 nm. (see above), which amounts to about +0.026, leaving 0.2528 */
+ /* unexplained. It appears the CCD wavelength has a dependence on the */
+ /* angle that the light enters the optics ?? */
+
+ led_off += 0.2528; /* Hack to make ambient cap correction == white tile correction */
+
+ a1logd(p->log,3,"Adjusted raw correction by %f to account for measurement using ambient cap\n",wlraw2 - wlraw1 + 0.2528);
+ }
+
+ /* Check that the correction is not excessive */
+ off_nm = i1pro_raw2wav_uncal(p, led_off) - i1pro_raw2wav_uncal(p, m->wl_led_ref_off);
+ a1logd(p->log,2, "Final WL offset = %f, correction %f nm\n",led_off, off_nm);
+ if (fabs(off_nm)> m->wl_err_max) {
+ a1logd(p->log,1,"Final WL correction of %f nm is too big\n",off_nm);
+ return I1PRO_WL_ERR2BIG;
+ }
+
+ /* Do a verification plot */
+ /* Plot the measurement against calibrated wavelength, */
+ /* and reference measurement verses reference wavelength */
+
+#ifdef PLOT_DEBUG
+ {
+ double xx[1024];
+ double y1[1024]; /* interpolate ref */
+ double y2[1024]; /* Measurement */
+ int ii;
+
+ /* i = index into measurement */
+ for (ii = 0, i = m->wl_led_ref_off; i < (m->wl_led_ref_off + m->wl_led_count); i++) {
+ double raw;
+ double mwl; /* Measurment wavelength */
+ double rraw; /* Reference raw value */
+ int ix; /* Lagrange base offset */
+ int k;
+ double yv;
+
+ raw = (double)i;
+ raw = raw - led_off + m->wl_led_ref_off;
+ raw = 128.0 - raw; /* Quadratic expects +ve correlation */
+ if (mmax < 2500.0) {
+ for (mwl = m->wlpoly2[4-1], k = 4-2; k >= 0; k--)
+ mwl = mwl * raw + m->wlpoly2[k];
+ } else {
+ for (mwl = m->wlpoly1[4-1], k = 4-2; k >= 0; k--)
+ mwl = mwl * raw + m->wlpoly1[k];
+ }
+ xx[ii] = mwl;
+ y1[ii] = cparm[0] * wlraw[i];
+ y2[ii] = 0.0;
+
+ /* Compute the reference index corresponding to this wavelength */
+ rraw = inv_raw2wav(m->wlpoly1, 4, mwl) - (double)m->wl_led_ref_off;
+
+ /* Use Lagrange to interpolate the reference level for this wavelength */
+ ix = ((int)rraw) - 1; /* Reference index of Lagrange for this xv */
+ if (ix < 0)
+ continue;
+ if ((ix + 3) >= m->wl_led_count)
+ break;
+
+ /* Compute interpolated value of reference using Lagrange: */
+ yv = m->wl_led_spec[ix+0] * (rraw-(ix+1)) * (rraw-(ix+2)) * (rraw-(ix+3))
+ /((0.0-1.0) * (0.0-2.0) * (0.0-3.0))
+ + m->wl_led_spec[ix+1] * (rraw-(ix+0)) * (rraw-(ix+2)) * (rraw-(ix+3))
+ /((1.0-0.0) * (1.0-2.0) * (1.0-3.0))
+ + m->wl_led_spec[ix+2] * (rraw-(ix+0)) * (rraw-(ix+1)) * (rraw-(ix+3))
+ /((2.0-0.0) * (2.0-1.0) * (2.0-3.0))
+ + m->wl_led_spec[ix+3] * (rraw-(ix+0)) * (rraw-(ix+1)) * (rraw-(ix+2))
+ /((3.0-0.0) * (3.0-1.0) * (3.0-2.0));
+ y2[ii] = yv;
+ ii++;
+ }
+ printf("Verification fit in nm:\n");
+ do_plot(xx, y1, y2, NULL, ii);
+ }
+#endif
+
+ if (pled_off != NULL)
+ *pled_off = led_off;
+ }
+
+ return ev;
+}
+
+/* Compute standard res. downsampling filters for the given mode */
+/* given the current wl_led_off, and set them as current. */
+i1pro_code i1pro2_compute_wav_filters(i1pro *p, int refl) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ i1pro_code ev = I1PRO_OK;
+ double twidth; /* Target filter width */
+ int six, eix; /* raw starting index and one past end index */
+ int wlix; /* current wavelenght index */
+ double *wlcop; /* This wavelength base filter coefficient pointer */
+ double trh, trx; /* Triangle height and triangle equation x weighting */
+ int i, j, k;
+
+ a1logd(p->log,2,"i1pro2_compute_wav_filters called with correction %f raw\n",s->wl_led_off - m->wl_led_ref_off);
+
+ twidth = (m->wl_long[0] - m->wl_short[0])/(m->nwav[0] - 1.0); /* Filter width */
+
+ trh = 1.0/twidth; /* Triangle height */
+ trx = trh/twidth; /* Triangle equation x weighting */
+
+ /* Allocate separate space for the calibrated versions, so that the */
+ /* original eeprom values are preserved */
+ if (m->mtx_c[0][refl].index == NULL) {
+
+ if ((m->mtx_c[0][refl].index = (int *)calloc(m->nwav[0], sizeof(int))) == NULL) {
+ a1logd(p->log,1,"i1pro: malloc ndex1 failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ if ((m->mtx_c[0][refl].nocoef = (int *)calloc(m->nwav[0], sizeof(int))) == NULL) {
+ a1logd(p->log,1,"i1pro: malloc nocoef failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ if ((m->mtx_c[0][refl].coef = (double *)calloc(16 * m->nwav[0], sizeof(double)))
+ == NULL) {
+ a1logd(p->log,1,"i1pro: malloc coef failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+ }
+
+ /* For each output wavelength */
+ wlcop = m->mtx_c[0][refl].coef;
+ for (wlix = 0; wlix < m->nwav[0]; wlix++) {
+ double owl = wlix/(m->nwav[0]-1.0) * (m->wl_long[0] - m->wl_short[0]) + m->wl_short[0];
+ int lip; /* Lagrange interpolation position */
+
+// printf("Generating filter for %.1f nm width %.1f nm\n",owl, twidth);
+
+ /* The filter is based on a triangle centered at owl and extending */
+ /* from owl - twidth to owl + twidth. We therefore need to locate the */
+ /* raw values that will overlap this range */
+
+ /* Do a dumb search from high to low nm */
+ for (six = 0; six < m->nraw; six++) {
+ if (i1pro_raw2wav(p, refl, (double)six) < (owl + twidth))
+ break;
+ }
+ if (six < 2 || six >= m->nraw) {
+ a1loge(p->log,1,"i1pro: compute_wav_filters() six %d out of raw range to cover output filter %.1f nm width %.1f nm\n",six, owl, twidth);
+ return I1PRO_INT_ASSERT;
+ }
+ eix = six;
+ six -= 2; /* Outside */
+
+ for (; eix < m->nraw; eix++) {
+ if (i1pro_raw2wav(p, refl, (double)eix) <= (owl - twidth))
+ break;
+ }
+ if (eix > (m->nraw - 2) ) {
+ a1loge(p->log,1,"i1pro: compute_wav_filters() eix %d out of raw range to cover output filter %.1f nm width %.1f nm\n",eix, owl, twidth);
+ return I1PRO_INT_ASSERT;
+ }
+ eix += 2;
+
+// for (j = six; j < eix; j++)
+// printf("Using raw %d @ %.1f nm\n",j, i1pro_raw2wav(p, refl, (double)j));
+
+ /* Set start index for this wavelength */
+ m->mtx_c[0][refl].index[wlix] = six;
+
+ /* Set number of filter coefficients */
+ m->mtx_c[0][refl].nocoef[wlix] = eix - six;
+
+ if (m->mtx_c[0][refl].nocoef[wlix] > 16) {
+ a1loge(p->log,1,"i1pro: compute_wav_filters() too many filter %d\n",m->mtx_c[0][refl].nocoef[wlix]);
+ return I1PRO_INT_ASSERT;
+ }
+
+ /* Start with zero filter weightings */
+ for (i = 0; i < m->mtx_c[0][refl].nocoef[wlix]; i++)
+ wlcop[i] = 0.0;
+
+ /* for each Lagrange interpolation position */
+ for (lip = six; (lip + 3) < eix; lip++) {
+ double rwav[4]; /* Relative wavelength of these Lagrange points */
+ double den[4]; /* Denominator values for points */
+ double num[4][4]; /* Numerator polinomial components x^3, x^2, x, 1 */
+ double ilow, ihigh; /* Integration points */
+
+ /* Relative wavelengths to owl of each basis point */
+ for (i = 0; i < 4; i++)
+ rwav[i] = i1pro_raw2wav(p, refl, (double)lip + i) - owl;
+// printf("\n~1 rwav = %f %f %f %f\n", rwav[0], rwav[1], rwav[2], rwav[3]);
+
+ /* Compute each basis points Lagrange denominator values */
+ den[0] = (rwav[0]-rwav[1]) * (rwav[0]-rwav[2]) * (rwav[0]-rwav[3]);
+ den[1] = (rwav[1]-rwav[0]) * (rwav[1]-rwav[2]) * (rwav[1]-rwav[3]);
+ den[2] = (rwav[2]-rwav[0]) * (rwav[2]-rwav[1]) * (rwav[2]-rwav[3]);
+ den[3] = (rwav[3]-rwav[0]) * (rwav[3]-rwav[1]) * (rwav[3]-rwav[2]);
+// printf("~1 denominators = %f %f %f %f\n", den[0], den[1], den[2], den[3]);
+
+ /* Compute each basis points Langrange numerator components. */
+ /* We make the numerator have polinomial form, so that it is easy */
+ /* to compute the integral equation from it. */
+ num[0][0] = 1.0;
+ num[0][1] = -rwav[1] - rwav[2] - rwav[3];
+ num[0][2] = rwav[1] * rwav[2] + rwav[1] * rwav[3] + rwav[2] * rwav[3];
+ num[0][3] = -rwav[1] * rwav[2] * rwav[3];
+ num[1][0] = 1.0;
+ num[1][1] = -rwav[0] - rwav[2] - rwav[3];
+ num[1][2] = rwav[0] * rwav[2] + rwav[0] * rwav[3] + rwav[2] * rwav[3];
+ num[1][3] = -rwav[0] * rwav[2] * rwav[3];
+ num[2][0] = 1.0;
+ num[2][1] = -rwav[0] - rwav[1] - rwav[3];
+ num[2][2] = rwav[0] * rwav[1] + rwav[0] * rwav[3] + rwav[1] * rwav[3];
+ num[2][3] = -rwav[0] * rwav[1] * rwav[3];
+ num[3][0] = 1.0;
+ num[3][1] = -rwav[0] - rwav[1] - rwav[2];
+ num[3][2] = rwav[0] * rwav[1] + rwav[0] * rwav[2] + rwav[1] * rwav[2];
+ num[3][3] = -rwav[0] * rwav[1] * rwav[2];
+
+// printf("~1 num %d = %f %f %f %f\n", 0, num[0][0], num[0][1], num[0][2], num[0][3]);
+// printf("~1 num %d = %f %f %f %f\n", 1, num[1][0], num[1][1], num[1][2], num[1][3]);
+// printf("~1 num %d = %f %f %f %f\n", 2, num[2][0], num[2][1], num[2][2], num[2][3]);
+// printf("~1 num %d = %f %f %f %f\n", 3, num[3][0], num[3][1], num[3][2], num[3][3]);
+
+ /* Now compute the integral difference between the two middle points */
+ /* of the Lagrange over the triangle shape, and accumulate the resulting */
+ /* Lagrange weightings to the filter coefficients. */
+
+ /* For high and then low side of the triangle. */
+ for (k = 0; k < 2; k++) {
+
+ ihigh = rwav[1];
+ ilow = rwav[2];
+
+ if ((k == 0 && ilow <= twidth && ihigh >= 0.0) /* Portion is +ve side */
+ || (k == 1 && ilow <= 0.0 && ihigh >= -twidth)) { /* Portion is -ve side */
+
+ if (k == 0) {
+ if (ilow < 0.0)
+ ilow = 0.0;
+ if (ihigh > twidth)
+ ihigh = twidth;
+// printf("~1 doing +ve triangle between %f %f\n",ilow,ihigh);
+ } else {
+ if (ilow < -twidth)
+ ilow = -twidth;
+ if (ihigh > 0.0)
+ ihigh = 0.0;
+// printf("~1 doing -ve triangle between %f %f\n",ilow,ihigh);
+ }
+
+ /* For each Lagrange point */
+ for (i = 0; i < 4; i++) {
+ double xnum[5]; /* Expanded numerator components */
+ double nvall, nvalh; /* Numerator low and high values */
+
+ /* Because the y value is a function of x, we need to */
+ /* expand the Lagrange 3rd order polinomial into */
+ /* a 4th order polinomial using the triangle edge equation */
+ /* y = trh +- trx * x */
+ for (j = 0; j < 4; j++)
+ xnum[j] = (k == 0 ? -trx : trx) * num[i][j];
+ xnum[j] = 0.0;
+ for (j = 0; j < 4; j++)
+ xnum[j+1] += trh * num[i][j];
+
+ /* The 4th order equation becomes a 5th order one */
+ /* when we convert it to an integral, ie. x^4 becomes x^5/5 etc. */
+ for (j = 0; j < 4; j++)
+ xnum[j] /= (5.0 - (double)j); /* Integral denom. */
+
+ /* Compute ihigh integral as 5th order polynomial */
+ nvalh = xnum[0];
+ nvalh = nvalh * ihigh + xnum[1];
+ nvalh = nvalh * ihigh + xnum[2];
+ nvalh = nvalh * ihigh + xnum[3];
+ nvalh = nvalh * ihigh + xnum[4];
+ nvalh = nvalh * ihigh;
+
+ /* Compute ilow integral as 5th order polynomial */
+ nvall = xnum[0];
+ nvall = nvall * ilow + xnum[1];
+ nvall = nvall * ilow + xnum[2];
+ nvall = nvall * ilow + xnum[3];
+ nvall = nvall * ilow + xnum[4];
+ nvall = nvall * ilow;
+
+ /* Compute ihigh - ilow and add to filter weightings */
+ wlcop[lip -six + i] += (nvalh - nvall)/den[i];
+// printf("~1 k = %d, comp %d weight += %e now %e\n",k,lip-six+i,(nvalh - nvall)/den[i], wlcop[lip-six+i]);
+ }
+ }
+ }
+ }
+// printf("~1 Weightings for for %.1f nm are:\n",owl);
+// for (i = 0; i < m->mtx_c[0][refl].nocoef[wlix]; i++)
+// printf("~1 comp %d weight %e\n",i,wlcop[i]);
+
+ wlcop += m->mtx_c[0][refl].nocoef[wlix]; /* Next group of weightings */
+ }
+#ifdef DEBUG
+ /* Check against orginal filters */
+ {
+ int ix1, ix1c;
+ double aerr = 0.0;
+
+ a1logd(p->log,2,"Checking gemertated tables against EEProm table\n");
+ ix1 = ix1c = 0;
+ for (i = 0; i < m->nwav[0]; i++) {
+ double err;
+ int six, eix;
+
+ if (m->mtx_o.index[i] < m->mtx_o.index[i])
+ six = m->mtx_o.index[i];
+ else
+ six = m->mtx_o.index[i];
+
+ if ((m->mtx_o.index[i] + m->mtx_o.nocoef[i]) > (m->mtx_o.index[i] + m->mtx_o.nocoef[i]))
+ eix = m->mtx_o.index[i] + m->mtx_o.nocoef[i];
+ else
+ eix = m->mtx_o.index[i] + m->mtx_o.nocoef[i];
+// printf("~1 filter %d from %d to %d\n",i,six,eix);
+
+ err = 0.0;
+ for (j = six; j < eix; j++) {
+ double w1, w1c;
+
+ if (j < m->mtx_o.index[i] || j >= (m->mtx_o.index[i] + m->mtx_o.nocoef[i]))
+ w1 = 0.0;
+ else
+ w1 = m->mtx_o.coef[ix1 + j - m->mtx_o.index[i]];
+ if (j < m->mtx_c[0][refl].index[i]
+ || j >= (m->mtx_c[0][refl].index[i] + m->mtx_c[0][refl].nocoef[i]))
+ w1c = 0.0;
+ else
+ w1c = m->mtx_c[0][refl].coef[ix1c + j - m->mtx_c[0][refl].index[i]];
+
+ err += fabs(w1 - w1c);
+// printf("Weight %d, %e should be %e\n", j, w1c, w1);
+ }
+// printf("Filter %d average weighting error = %f\n",i, err/j);
+ aerr += err/j;
+
+ ix1 += m->mtx_o.nocoef[i];
+ ix1c += m->mtx_c[0][refl].nocoef[i];
+ }
+ a1logd(p->log,2,"Overall average filter weighting change = %f\n",aerr/m->nwav[0]);
+ }
+#endif /* DEBUG */
+
+ /* Switch normal res. to use wavelength calibrated version */
+ m->mtx[0][refl] = m->mtx_c[0][refl];
+
+ return ev;
+}
+
+
+/* =============================================== */
+#ifdef HIGH_RES
+
+#undef ANALIZE_EXISTING /* Analize the manufacturers existing filter shape */
+
+/* High res congiguration */
+/* Pick one of these: */
+#define USE_LANCZOS2 /* [def] Use lanczos2 filter shape */
+#undef USE_DECONV /* [und] Use deconvolution curve */
+#undef USE_GAUSSIAN /* [und] Use gaussian filter shape*/
+#undef USE_BLACKMAN /* [und] Use Blackman windowed sinc shape */
+#undef USE_CUBIC /* [und] Use cubic spline filter */
+
+#undef COMPUTE_DISPERSION /* Compute slit & optics dispersion from red laser data */
+
+#ifdef NEVER
+/* Plot the matrix coefficients */
+static void i1pro_debug_plot_mtx_coef(i1pro *p) {
+ i1proimp *m = (i1proimp *)p->m;
+ int i, j, k, cx, sx;
+ double *xx, *ss;
+ double **yy;
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (cx = j = 0; j < m->nwav; j++) {
+ i = j % 5;
+
+// printf("Out wave = %d\n",j);
+ /* For each matrix value */
+ sx = m->mtx_index[j]; /* Starting index */
+// printf("start index = %d, nocoef %d\n",sx,m->mtx_nocoef[j]);
+ for (k = 0; k < m->mtx_nocoef[j]; k++, cx++, sx++) {
+// printf("offset %d, coef ix %d val %f from ccd %d\n",k, cx, m->mtx_coef[cx], sx);
+ yy[5][sx] += 0.5 * m->mtx_coef[cx];
+ yy[i][sx] = m->mtx_coef[cx];
+ }
+ }
+
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+}
+#endif
+
+#ifdef COMPUTE_DISPERSION
+
+/* Gausian filter implementation */
+/* parameters are amplidude [0], center wavelength [1], std. dev. [2] */
+static double gaussf(double tp[], double x) {
+ double y;
+
+ x = (x - tp[1])/(sqrt(2.0) * tp[2]);
+ y = tp[0] * exp(-(x * x));
+
+ return y;
+}
+
+/* Gausian integral implementatation */
+/* parameters are amplidude [0], center wavelength [1], std. dev. [2] */
+/* return an aproximation to the intergral between w1 and w2 */
+static double gaussint(double tp[], double w1, double w2) {
+ int j, nn;
+ double lw, ll, vv;
+
+ /* Intergate in 0.1 nm increments */
+ nn = (int)(fabs(w2 - w1)/0.1 + 0.5);
+
+ lw = w1;
+ ll = gaussf(tp, lw);
+ vv = 0.0;
+ for (j = 0; j < nn; j++) {
+ double cw, cl;
+ cw = w1 + (j+1)/(nn +1.0) * (w2 - w1);
+ cl = gaussf(tp, cw);
+ vv += 0.5 * (cl + ll) * (lw - cw);
+ ll = cl;
+ lw = cw;
+ }
+ return fabs(vv);
+}
+
+/* Powell minimisation context */
+typedef struct {
+ double nsp; /* Number of samples of dispersion data */
+ double *llv; /* [nsamp] laser values */
+ double *lwl; /* [nsamp+1] CCD boundary wavelegths */
+} hropt_cx;
+
+/* Powell minimisation callback function */
+/* to match dispersion data */
+static double hropt_opt1(void *vcx, double tp[]) {
+ hropt_cx *cx = (hropt_cx *)vcx;
+ double rv = 0.0;
+ int i, j;
+
+ /* For each CCD sample */
+ for (i = 0; i < cx->nsp; i++) {
+ double vv;
+
+ /* Actual CCD integrated value */
+ vv = cx->llv[i] * (cx->lwl[i] - cx->lwl[i+1]);
+ /* Computed intergral with current curve */
+ vv -= gaussint(tp, cx->lwl[i], cx->lwl[i+1]);
+ rv += vv * vv;
+ }
+// printf("~1 params %f %f %f, rv = %f\n", tp[0],tp[1],tp[2],rv);
+ return rv;
+}
+
+#endif /* COMPUTE_DISPERSION */
+
+/* Filter shape point */
+typedef struct {
+ double wl, we;
+} i1pro_fs;
+
+/* Filter cooeficient values */
+typedef struct {
+ int ix; /* Raw index */
+ double we; /* Weighting */
+} i1pro_fc;
+
+/* Wavelenth calibration crossover point information */
+typedef struct {
+ double wav; /* Wavelegth of point */
+ double raw; /* Raw index of point */
+ double wei; /* Weigting of the point */
+} i1pro_xp;
+
+/* Linearly interpolate the filter shape */
+static double lin_fshape(i1pro_fs *fsh, int n, double x) {
+ int i;
+ double y;
+
+ if (x <= fsh[0].wl)
+ return fsh[0].we;
+ else if (x >= fsh[n-1].wl)
+ return fsh[n-1].we;
+
+ for (i = 0; i < (n-2); i++)
+ if (x >= fsh[i].wl && x <= fsh[i+1].wl)
+ break;
+
+ x = (x - fsh[i].wl)/(fsh[i+1].wl - fsh[i].wl);
+ y = fsh[i].we + (fsh[i+1].we - fsh[i].we) * x;
+
+ return y;
+}
+
+/* Generate a sample from a lanczos2 filter shape */
+/* wi is the width of the filter */
+static double lanczos2(double wi, double x) {
+ double y;
+
+#ifdef USE_DECONV
+ /* For 3.333, created by i1deconv.c */
+ static i1pro_fs fshape[49] = {
+ { -7.200000, 0.0 },
+ { -6.900000, 0.013546 },
+ { -6.600000, 0.035563 },
+ { -6.300000, 0.070500 },
+ { -6.000000, 0.106543 },
+ { -5.700000, 0.148088 },
+ { -5.400000, 0.180888 },
+ { -5.100000, 0.186637 },
+ { -4.800000, 0.141795 },
+ { -4.500000, 0.046101 },
+ { -4.200000, -0.089335 },
+ { -3.900000, -0.244652 },
+ { -3.600000, -0.391910 },
+ { -3.300000, -0.510480 },
+ { -3.000000, -0.573177 },
+ { -2.700000, -0.569256 },
+ { -2.400000, -0.489404 },
+ { -2.100000, -0.333957 },
+ { -1.800000, -0.116832 },
+ { -1.500000, 0.142177 },
+ { -1.200000, 0.411639 },
+ { -0.900000, 0.658382 },
+ { -0.600000, 0.851521 },
+ { -0.300000, 0.967139 },
+ { 0.000000, 1.000000 },
+ { 0.300000, 0.967139 },
+ { 0.600000, 0.851521 },
+ { 0.900000, 0.658382 },
+ { 1.200000, 0.411639 },
+ { 1.500000, 0.142177 },
+ { 1.800000, -0.116832 },
+ { 2.100000, -0.333957 },
+ { 2.400000, -0.489404 },
+ { 2.700000, -0.569256 },
+ { 3.000000, -0.573177 },
+ { 3.300000, -0.510480 },
+ { 3.600000, -0.391910 },
+ { 3.900000, -0.244652 },
+ { 4.200000, -0.089335 },
+ { 4.500000, 0.046101 },
+ { 4.800000, 0.141795 },
+ { 5.100000, 0.186637 },
+ { 5.400000, 0.180888 },
+ { 5.700000, 0.148088 },
+ { 6.000000, 0.106543 },
+ { 6.300000, 0.070500 },
+ { 6.600000, 0.035563 },
+ { 6.900000, 0.013546 },
+ { 7.200000, 0.0 }
+ };
+
+ return lin_fshape(fshape, 49, x);
+#endif
+
+#ifdef USE_GAUSSIAN
+ /* gausian */
+ wi = wi/(2.0 * sqrt(2.0 * log(2.0))); /* Convert width at half max to std. dev. */
+ x = x/(sqrt(2.0) * wi);
+// y = 1.0/(wi * sqrt(2.0 * DBL_PI)) * exp(-(x * x)); /* Unity area */
+ y = exp(-(x * x)); /* Center at 1.0 */
+#endif
+
+#ifdef USE_LANCZOS2
+ /* lanczos2 */
+ x = fabs(1.0 * x/wi);
+ if (x >= 2.0)
+ return 0.0;
+ if (x < 1e-5)
+ return 1.0;
+ y = sin(DBL_PI * x)/(DBL_PI * x) * sin(DBL_PI * x/2.0)/(DBL_PI * x/2.0);
+#endif
+
+#ifdef USE_BLACKMAN /* Use Blackman windowed sinc shape */
+ double xx = x, w;
+ double a0, a1, a2, a3;
+ double bb, cc;
+
+ xx = fabs(1.0 * x/wi);
+ if (xx >= 2.0)
+ return 0.0;
+ if (xx < 1e-5)
+ return 1.0;
+ y = sin(DBL_PI * xx)/(DBL_PI * xx); /* sinc */
+
+ /* gausian window */
+// wi *= 1.5;
+// wi = wi/(2.0 * sqrt(2.0 * log(2.0))); /* Convert width at half max to std. dev. */
+// x = x/(sqrt(2.0) * wi);
+// w = exp(-(x * x));
+
+ xx = (xx/4.0 + 0.5); /* Convert to standard window cos() range */
+
+ /* Hamming window */
+// a0 = 0.54; a1 = 0.46;
+// w = a0 - a1 * cos(2.0 * DBL_PI * xx);
+
+ /* Blackman window */
+ a0 = 7938.0/18608.0; a1 = 9240.0/18608.0; a2 = 1430.0/18608.0;
+ w = a0 - a1 * cos(2.0 * DBL_PI * xx) + a2 * cos(4.0 * DBL_PI * xx);
+
+ /* Nuttall window */
+// a0 = 0.355768; a1=0.487396; a2=0.144232; a3=0.012604;
+// w = a0 - a1 * cos(2.0 * DBL_PI * xx) + a2 * cos(4.0 * DBL_PI * xx) - a3 * cos(6.0 * DBL_PI * xx);
+
+ /* Blackman Harris window */
+// a0=0.35875; a1=0.48829; a2=0.14128; a3=0.01168;
+// w = a0 - a1 * cos(2.0 * DBL_PI * xx) + a2 * cos(4.0 * DBL_PI * xx) - a3 * cos(6.0 * DBL_PI * xx);
+
+ /* Blackman Nuttall window */
+// a0=0.3635819; a1=0.4891775; a2=0.1365995; a3=0.0106411;
+// w = a0 - a1 * cos(2.0 * DBL_PI * xx) + a2 * cos(4.0 * DBL_PI * xx) - a3 * cos(6.0 * DBL_PI * xx);
+
+ y *= w;
+#endif
+#ifdef USE_CUBIC /* Use cubic sline */
+ double xx = x;
+ double bb, cc;
+
+ xx = fabs(1.0 * x/wi);
+
+// bb = cc = 1.0/3.0; /* Mitchell */
+ bb = 0.5;
+ cc = 0.5;
+ xx *= 1.2;
+
+ if (xx < 1.0) {
+ y = ( 12.0 - 9.0 * bb - 6.0 * cc) * xx * xx * xx
+ + (-18.0 + 12.0 * bb + 6.0 * cc) * xx * xx
+ + ( 6.0 - 2.0 * bb);
+ y /= (6.0 - 2.0 * bb);
+ } else if (xx < 2.0) {
+ y = ( -1.0 * bb - 6.0 * cc) * xx * xx * xx
+ + ( 6.0 * bb + 30.0 * cc) * xx * xx
+ + (-12.0 * bb - 48.0 * cc) * xx
+ + ( 8.0 * bb + 24.0 * cc);
+ y /= (6.0 - 2.0 * bb);
+ } else {
+ y = 0.0;
+ }
+#endif
+ return y;
+}
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a ppc gcc 3.3 optimiser bug... */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+/* Create or re-create high resolution mode references */
+i1pro_code i1pro_create_hr(i1pro *p) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+ int refl;
+ int i, j, k, cx, sx;
+
+ /* If we don't have any way of converting raw2wav (ie. RevE polinomial equations), */
+ /* use the orginal filters to figure this out. */
+ if (p->itype != instI1Pro2 && m->raw2wav == NULL) {
+ i1pro_fc coeff[100][16]; /* Existing filter cooefficients */
+ i1pro_xp xp[101]; /* Crossover points each side of filter */
+ i1pro_fs fshape[100 * 16]; /* Existing filter shape */
+ int ncp = 0; /* Number of shape points */
+
+ /* Convert the native filter cooeficient representation to */
+ /* a 2D array we can randomly index. */
+ for (cx = j = 0; j < m->nwav[0]; j++) { /* For each output wavelength */
+ if (j >= 100) { /* Assert */
+ a1loge(p->log,1,"i1pro: number of output wavelenths is > 100\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+ /* For each matrix value */
+ sx = m->mtx_o.index[j]; /* Starting index */
+ for (k = 0; k < m->mtx_o.nocoef[j]; k++, cx++, sx++) {
+ if (k >= 16) { /* Assert */
+ a1loge(p->log,1,"i1pro: number of filter coeefs is > 16\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+ coeff[j][k].ix = sx;
+ coeff[j][k].we = m->mtx_o.coef[cx];
+// printf("Output %d, filter %d weight = %e\n",j,k,coeff[j][k].we);
+ }
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot original re-sampling curves */
+ {
+ double *xx, *ss;
+ double **yy;
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav[0]; j++) {
+ i = j % 5;
+
+ /* For each matrix value */
+ for (k = 0; k < m->mtx_o.nocoef[j]; k++) {
+ yy[5][coeff[j][k].ix] += 0.5 * coeff[j][k].we;
+ yy[i][coeff[j][k].ix] = coeff[j][k].we;
+ }
+ }
+
+ printf("Original wavelength sampling curves:\n");
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+ /* Compute the crossover points between each filter */
+ for (i = 0; i < (m->nwav[0]-1); i++) {
+ double den, y1, y2, y3, y4, yn, xn; /* Location of intersection */
+
+ /* between filter i and i+1, we want to find the two */
+ /* raw indexes where the weighting values cross over */
+ /* Do a brute force search to avoid making assumptions */
+ /* about the raw order */
+ for (j = 0; j < (m->mtx_o.nocoef[i]-1); j++) {
+ for (k = 0; k < (m->mtx_o.nocoef[i+1]-1); k++) {
+// printf("~1 checking %d, %d: %d = %d, %d = %d\n",j,k, coeff[i][j].ix, coeff[i+1][k].ix, coeff[i][j+1].ix, coeff[i+1][k+1].ix);
+ if (coeff[i][j].ix == coeff[i+1][k].ix
+ && coeff[i][j+1].ix == coeff[i+1][k+1].ix
+ && coeff[i][j].we > 0.0 && coeff[i][j+1].we > 0.0
+ && coeff[i][k].we > 0.0 && coeff[i][k+1].we > 0.0
+ && (( coeff[i][j].we >= coeff[i+1][k].we
+ && coeff[i][j+1].we <= coeff[i+1][k+1].we)
+ || ( coeff[i][j].we <= coeff[i+1][k].we
+ && coeff[i][j+1].we >= coeff[i+1][k+1].we))) {
+// printf("~1 got it at %d, %d: %d = %d, %d = %d\n",j,k, coeff[i][j].ix, coeff[i+1][k].ix, coeff[i][j+1].ix, coeff[i+1][k+1].ix);
+ goto gotit;
+ }
+ }
+ }
+ gotit:;
+ if (j >= m->mtx_o.nocoef[i]) { /* Assert */
+ a1loge(p->log,1,"i1pro: failed to locate crossover between resampling filters\n");
+ return I1PRO_INT_ASSERT;
+ }
+// printf("~1 %d: overlap at %d, %d: %f : %f, %f : %f\n",i, j,k, coeff[i][j].we, coeff[i+1][k].we, coeff[i][j+1].we, coeff[i+1][k+1].we);
+
+ /* Compute the intersection of the two line segments */
+ y1 = coeff[i][j].we;
+ y2 = coeff[i][j+1].we;
+ y3 = coeff[i+1][k].we;
+ y4 = coeff[i+1][k+1].we;
+ den = -y4 + y3 + y2 - y1;
+ yn = (y2 * y3 - y1 * y4)/den;
+ xn = (y3 - y1)/den;
+// printf("~1 den = %f, yn = %f, xn = %f\n",den,yn,xn);
+ xp[i+1].wav = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i + 0.5);
+ xp[i+1].raw = (1.0 - xn) * coeff[i][j].ix + xn * coeff[i][j+1].ix;
+ xp[i+1].wei = yn;
+// printf("Intersection %d: wav %f, raw %f, wei %f\n",i+1,xp[i+1].wav,xp[i+1].raw,xp[i+1].wei);
+// printf("\n");
+ }
+
+ /* Add the two points for the end filters */
+ {
+ double x5, x6, y5, y6; /* Points on intesecting line */
+ double den, y1, y2, y3, y4, yn, xn; /* Location of intersection */
+
+ x5 = xp[1].raw;
+ y5 = xp[1].wei;
+ x6 = xp[2].raw;
+ y6 = xp[2].wei;
+
+ /* Search for possible intersection point with first curve */
+ /* Create equation for line from next two intersection points */
+ for (j = 0; j < (m->mtx_o.nocoef[0]-1); j++) {
+ /* Extrapolate line to this segment */
+ y3 = y5 + (coeff[0][j].ix - x5)/(x6 - x5) * (y6 - y5);
+ y4 = y5 + (coeff[0][j+1].ix - x5)/(x6 - x5) * (y6 - y5);
+ /* This segment of curve */
+ y1 = coeff[0][j].we;
+ y2 = coeff[0][j+1].we;
+ if ( (( y1 >= y3 && y2 <= y4) /* Segments overlap */
+ || ( y1 <= y3 && y2 >= y4))
+ && (( coeff[0][j].ix < x5 && coeff[0][j].ix < x6
+ && coeff[0][j+1].ix < x5 && coeff[0][j+1].ix < x6)
+ || ( coeff[0][j+1].ix > x5 && coeff[0][j+1].ix > x6
+ && coeff[0][j].ix > x5 && coeff[0][j].ix > x6))) {
+ break;
+ }
+ }
+ if (j >= m->mtx_o.nocoef[0]) { /* Assert */
+ a1loge(p->log,1,"i1pro: failed to end crossover\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+ den = -y4 + y3 + y2 - y1;
+ yn = (y2 * y3 - y1 * y4)/den;
+ xn = (y3 - y1)/den;
+// printf("~1 den = %f, yn = %f, xn = %f\n",den,yn,xn);
+ xp[0].wav = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], -0.5);
+ xp[0].raw = (1.0 - xn) * coeff[0][j].ix + xn * coeff[0][j+1].ix;
+ xp[0].wei = yn;
+// printf("End 0 intersection %d: wav %f, raw %f, wei %f\n",0,xp[0].wav,xp[0].raw,xp[0].wei);
+// printf("\n");
+
+ x5 = xp[m->nwav[0]-2].raw;
+ y5 = xp[m->nwav[0]-2].wei;
+ x6 = xp[m->nwav[0]-1].raw;
+ y6 = xp[m->nwav[0]-1].wei;
+
+// printf("~1 x5 %f, y5 %f, x6 %f, y6 %f\n",x5,y5,x6,y6);
+ /* Search for possible intersection point with first curve */
+ /* Create equation for line from next two intersection points */
+ for (j = 0; j < (m->mtx_o.nocoef[0]-1); j++) {
+ /* Extrapolate line to this segment */
+ y3 = y5 + (coeff[m->nwav[0]-1][j].ix - x5)/(x6 - x5) * (y6 - y5);
+ y4 = y5 + (coeff[m->nwav[0]-1][j+1].ix - x5)/(x6 - x5) * (y6 - y5);
+ /* This segment of curve */
+ y1 = coeff[m->nwav[0]-1][j].we;
+ y2 = coeff[m->nwav[0]-1][j+1].we;
+ if ( (( y1 >= y3 && y2 <= y4) /* Segments overlap */
+ || ( y1 <= y3 && y2 >= y4))
+ && (( coeff[m->nwav[0]-1][j].ix < x5 && coeff[m->nwav[0]-1][j].ix < x6
+ && coeff[m->nwav[0]-1][j+1].ix < x5 && coeff[m->nwav[0]-1][j+1].ix < x6)
+ || ( coeff[m->nwav[0]-1][j+1].ix > x5 && coeff[m->nwav[0]-1][j+1].ix > x6
+ && coeff[m->nwav[0]-1][j].ix > x5 && coeff[m->nwav[0]-1][j].ix > x6))) {
+ break;
+ }
+ }
+ if (j >= m->mtx_o.nocoef[m->nwav[0]-1]) { /* Assert */
+ a1loge(p->log,1,"i1pro: failed to end crossover\n");
+ return I1PRO_INT_ASSERT;
+ }
+ den = -y4 + y3 + y2 - y1;
+ yn = (y2 * y3 - y1 * y4)/den;
+ xn = (y3 - y1)/den;
+// printf("~1 den = %f, yn = %f, xn = %f\n",den,yn,xn);
+ xp[m->nwav[0]].wav = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], m->nwav[0]-0.5);
+ xp[m->nwav[0]].raw = (1.0 - xn) * coeff[m->nwav[0]-1][j].ix + xn * coeff[m->nwav[0]-1][j+1].ix;
+ xp[m->nwav[0]].wei = yn;
+// printf("End 36 intersection %d: wav %f, raw %f, wei %f\n",m->nwav[0]+1,xp[m->nwav[0]].wav,xp[m->nwav[0]].raw,xp[m->nwav[0]].wei);
+// printf("\n");
+ }
+
+#ifdef HIGH_RES_DEBUG
+ /* Check to see if the area of each filter curve is the same */
+ /* (yep, width times 2 * xover height is close to 1.0, and the */
+ /* sum of the weightings is exactly 1.0) */
+ for (i = 0; i < m->nwav[0]; i++) {
+ double area1, area2;
+ area1 = fabs(xp[i].raw - xp[i+1].raw) * (xp[i].wei + xp[i+1].wei);
+
+ area2 = 0.0;
+ for (j = 0; j < (m->mtx_o.nocoef[i]); j++)
+ area2 += coeff[i][j].we;
+
+ printf("Area of curve %d = %f, %f\n",i,area1, area2);
+ }
+#endif /* HIGH_RES_DEBUG */
+
+ /* From our crossover data, create a rspl that maps raw CCD index */
+ /* value into wavelegth. */
+ {
+ co sd[101]; /* Scattered data points */
+ datai glow, ghigh;
+ datao vlow, vhigh;
+ int gres[1];
+ double avgdev[1];
+
+ if ((m->raw2wav = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ a1logd(p->log,1,"i1pro: creating rspl for high res conversion failed\n");
+ return I1PRO_INT_NEW_RSPL_FAILED;
+ }
+
+ vlow[0] = 1e6;
+ vhigh[0] = -1e6;
+ for (i = 0; i < (m->nwav[0]+1); i++) {
+ sd[i].p[0] = xp[i].raw;
+ sd[i].v[0] = xp[i].wav;
+
+ if (sd[i].v[0] < vlow[0])
+ vlow[0] = sd[i].v[0];
+ if (sd[i].v[0] > vhigh[0])
+ vhigh[0] = sd[i].v[0];
+ }
+ glow[0] = 0.0;
+ ghigh[0] = 127.0;
+ gres[0] = 128;
+ avgdev[0] = 0.0;
+
+ m->raw2wav->fit_rspl(m->raw2wav, 0, sd, m->nwav[0]+1, glow, ghigh, gres, vlow, vhigh, 0.5, avgdev, NULL);
+
+#ifdef HIGH_RES_PLOT
+ /* Plot raw to wav lookup */
+ {
+ double *xx, *yy, *y2;
+
+ xx = dvector(0, m->nwav[0]+1); /* X index = raw bin */
+ yy = dvector(0, m->nwav[0]+1); /* Y = nm */
+ y2 = dvector(0, m->nwav[0]+1); /* Y = nm */
+
+ for (i = 0; i < (m->nwav[0]+1); i++) {
+ co pp;
+ double iv, v1, v2;
+ xx[i] = xp[i].raw;
+ yy[i] = xp[i].wav;
+
+ pp.p[0] = xp[i].raw;
+ m->raw2wav->interp(m->raw2wav, &pp);
+ y2[i] = pp.v[0];
+ }
+
+ printf("CCD bin to wavelength mapping of original filters + rspl:\n");
+ do_plot6(xx, yy, y2, NULL, NULL, NULL, NULL, m->nwav+1);
+ free_dvector(xx, 0, m->nwav[0]+1);
+ free_dvector(yy, 0, m->nwav[0]+1);
+ free_dvector(y2, 0, m->nwav[0]+1);
+ }
+#endif /* HIGH_RES_PLOT */
+ }
+ }
+
+#ifdef ANALIZE_EXISTING
+ /* Convert each weighting curves values into normalized values and */
+ /* accumulate into a single curve. */
+ if (!m->hr_inited) {
+ for (i = 0; i < m->nwav[0]; i++) {
+ double cwl; /* center wavelegth */
+ double weight = 0.0;
+
+ for (j = 0; j < (m->mtx_o.nocoef[i]); j++) {
+ double w1, w2, cellw;
+
+ /* Translate CCD cell boundaries index to wavelength */
+ w1 = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix - 0.5);
+
+ w2 = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix + 0.5);
+
+ cellw = fabs(w2 - w1);
+
+ cwl = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i);
+
+ /* Translate CCD index to wavelength */
+ fshape[ncp].wl = i1pro_raw2wav_uncal(p, (double)coeff[i][j].ix) - cwl;
+ fshape[ncp].we = coeff[i][j].we / (0.09 * cellw);
+ ncp++;
+ }
+ }
+
+ /* Now sort by wavelength */
+#define HEAP_COMPARE(A,B) (A.wl < B.wl)
+ HEAPSORT(i1pro_fs, fshape, ncp)
+#undef HEAP_COMPARE
+
+ /* Strip out leading zero's */
+ for (i = 0; i < ncp; i++) {
+ if (fshape[i].we != 0.0)
+ break;
+ }
+ if (i > 1 && i < ncp) {
+ memmove(&fshape[0], &fshape[i-1], sizeof(i1pro_fs) * (ncp - i + 1));
+ ncp = ncp - i + 1;
+ for (i = 0; i < ncp; i++) {
+ if (fshape[i].we != 0.0)
+ break;
+ }
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot the shape of the accumulated curve */
+ {
+ double *x1 = dvectorz(0, ncp-1);
+ double *y1 = dvectorz(0, ncp-1);
+
+ for (i = 0; i < ncp; i++) {
+ double x;
+ x1[i] = fshape[i].wl;
+ y1[i] = fshape[i].we;
+ }
+ printf("Accumulated curve:\n");
+ do_plot(x1, y1, NULL, NULL, ncp);
+
+ free_dvector(x1, 0, ncp-1);
+ free_dvector(y1, 0, ncp-1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+#ifdef HIGH_RES_DEBUG
+ /* Check that the orginal filter sums to a constant */
+ {
+ double x, sum;
+
+ for (x = 0.0; x < 10.0; x += 0.2) {
+ sum = 0;
+ sum += lin_fshape(fshape, ncp, x - 30.0);
+ sum += lin_fshape(fshape, ncp, x - 20.0);
+ sum += lin_fshape(fshape, ncp, x - 10.0);
+ sum += lin_fshape(fshape, ncp, x - 0.0);
+ sum += lin_fshape(fshape, ncp, x + 10.0);
+ sum += lin_fshape(fshape, ncp, x + 20.0);
+ printf("Offset %f, sum %f\n",x, sum);
+ }
+ }
+#endif /* HIGH_RES_DEBUG */
+ }
+#endif /* ANALIZE_EXISTING */
+
+#ifdef COMPUTE_DISPERSION
+ if (!m->hr_inited) {
+ /* Fit our red laser CCD data to a slit & optics Gaussian dispersion model */
+ {
+ double spf[3]; /* Spread function parameters */
+
+ /* Measured CCD values of red laser from CCD indexes 29 to 48 inclusive */
+ /* (It would be nice to have similar data from a monochromic source */
+ /* at other wavelegths such as green and blue!) */
+ double llv[20] = {
+ 53.23,
+ 81.3,
+ 116.15,
+ 176.16,
+ 305.87,
+ 613.71,
+ 8500.52,
+ 64052.0,
+ 103134.13,
+ 89154.03,
+ 21742.89,
+ 1158.86,
+ 591.44,
+ 369.75,
+ 241.01,
+ 166.48,
+ 126.79,
+ 97.76,
+ 63.88,
+ 46.46
+ };
+ double lwl[21]; /* Wavelegth of boundary between CCD cells */
+ double ccd;
+ hropt_cx cx;
+ double ss[3];
+
+ /* Add CCD boundary wavelengths to dispersion data */
+ for (ccd = 29.0 - 0.5, i = 0; i < 21; i++, ccd += 1.0) {
+ /* Translate CCD cell boundaries index to wavelength */
+ lwl[i] = i1pro_raw2wav_uncal(p, ccd);
+ }
+
+ /* Fit a gausian to it */
+ cx.nsp = 20;
+ cx.llv = llv;
+ cx.lwl = lwl;
+
+ /* parameters are amplidude [0], center wavelength [1], std. dev. [2] */
+ spf[0] = 115248.0;
+ spf[1] = 653.78;
+ spf[2] = 3.480308;
+ ss[0] = 500.0;
+ ss[1] = 0.5;
+ ss[2] = 0.5;
+
+ if (powell(NULL, 3, spf, ss, 1e-5, 2000, hropt_opt1, &cx))
+ a1logw(p->log,"hropt_opt1 failed\n");
+
+#ifdef HIGH_RES_PLOT
+ /* Plot dispersion spectra */
+ {
+ double xx[200];
+ double y1[200];
+ double y2[200];
+ double w1, w2;
+
+ w1 = lwl[0] + 5.0;
+ w2 = lwl[20] - 5.0;
+ for (i = 0; i < 200; i++) {
+ double wl;
+ wl = w1 + (i/199.0) * (w2-w1);
+ xx[i] = wl;
+ for (j = 0; j < 20; j++) {
+ if (lwl[j] >= wl && wl >= lwl[j+1])
+ break;
+ }
+ if (j < 20)
+ y1[i] = llv[j];
+ else
+ y1[i] = 0.0;
+ y2[i] = gaussf(spf, wl);
+ }
+ printf("Gauss Parameters %f %f %f\n",spf[0],spf[1],spf[2]);
+ printf("Red laser dispersion data:\n");
+ do_plot(xx, y1, y2, NULL, 200);
+ }
+#endif /* HIGH_RES_PLOT */
+
+ /* Normalize the gausian to have an area of 1 */
+ spf[0] *= 1.0/(spf[0] * spf[2] * sqrt(2.0 * DBL_PI));
+
+// printf("~1 Normalized intergral = %f\n",gaussint(spf, spf[1] - 30.0, spf[1] + 30.0));
+// printf("~1 Half width = %f\n",2.0 * sqrt(2.0 * log(2.0)) * spf[2]);
+ }
+ }
+#endif /* COMPUTE_DISPERSION */
+
+ /* Compute the upsampled calibration references */
+ if (!m->hr_inited) {
+ rspl *trspl; /* Upsample rspl */
+ cow sd[40 * 40]; /* Scattered data points of existing references */
+ datai glow, ghigh;
+ datao vlow, vhigh;
+ int gres[2];
+ double avgdev[2];
+ int ii;
+ co pp;
+
+ if ((trspl = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ a1logd(p->log,1,"i1pro: creating rspl for high res conversion failed\n");
+ return I1PRO_INT_NEW_RSPL_FAILED;
+ }
+
+ for (ii = 0; ii < 3; ii++) {
+ double **ref2, *ref1;
+ double smooth = 1.0;
+
+ if (ii == 0) {
+ ref1 = m->white_ref[0];
+ ref2 = &m->white_ref[1];
+ smooth = 0.5;
+ } else if (ii == 1) {
+ ref1 = m->emis_coef[0];
+ ref2 = &m->emis_coef[1];
+ smooth = 500.0; /* Hmm. Lagrange may work better ?? */
+ } else {
+ if (m->amb_coef[0] == NULL)
+ break;
+ ref1 = m->amb_coef[0];
+ ref2 = &m->amb_coef[1];
+ smooth = 0.2;
+ }
+
+ if (ref1 == NULL)
+ continue; /* The instI1Monitor doesn't have a reflective cal */
+
+ vlow[0] = 1e6;
+ vhigh[0] = -1e6;
+ for (i = 0; i < m->nwav[0]; i++) {
+
+ sd[i].p[0] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i);
+ sd[i].v[0] = ref1[i];
+ sd[i].w = 1.0;
+
+ if (sd[i].v[0] < vlow[0])
+ vlow[0] = sd[i].v[0];
+ if (sd[i].v[0] > vhigh[0])
+ vhigh[0] = sd[i].v[0];
+ }
+
+ if (ii == 1) { /* fudge factors */
+
+#ifdef NEVER /* Doesn't help */
+ /* Increase boost at short wavelegths */
+ if (m->wl_short[1] < 380.0) {
+ sd[i].p[0] = m->wl_short[1];
+ sd[i].v[0] = sd[0].v[0] * (1.0 + (380.0 - m->wl_short[1])/20.0);
+ sd[i++].w = 0.6;
+ }
+#endif
+
+#ifdef NEVER /* Doesn't help */
+ /* Reduces boost at long wavelegths */
+ if (m->wl_long[1] > 730.0) {
+ sd[i].p[0] = m->wl_long[1];
+ sd[i].v[0] = sd[m->nwav[0]-1].v[0] * (1.0 + (m->wl_long[1] - 730.0)/100.0);
+ sd[i++].w = 0.3;
+ }
+#endif
+ }
+
+ glow[0] = m->wl_short[1];
+ ghigh[0] = m->wl_long[1];
+ gres[0] = m->nwav[1];
+ avgdev[0] = 0.0;
+
+ trspl->fit_rspl_w(trspl, 0, sd, i, glow, ghigh, gres, vlow, vhigh, smooth, avgdev, NULL);
+
+ if ((*ref2 = (double *)calloc(m->nwav[1], sizeof(double))) == NULL) {
+ trspl->del(trspl);
+ a1logw(p->log, "i1pro: malloc ref2 failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ for (i = 0; i < m->nwav[1]; i++) {
+ pp.p[0] = m->wl_short[1]
+ + (double)i * (m->wl_long[1] - m->wl_short[1])/(m->nwav[1]-1.0);
+ trspl->interp(trspl, &pp);
+ (*ref2)[i] = pp.v[0];
+ }
+#ifdef HIGH_RES_PLOT
+ /* Plot original and upsampled reference */
+ {
+ double *x1 = dvectorz(0, m->nwav[1]-1);
+ double *y1 = dvectorz(0, m->nwav[1]-1);
+ double *y2 = dvectorz(0, m->nwav[1]-1);
+
+ for (i = 0; i < m->nwav[1]; i++) {
+ double wl = m->wl_short[1] + (double)i * (m->wl_long[1] - m->wl_short[1])/(m->nwav[1]-1.0);
+ x1[i] = wl;
+ y1[i] = (*ref2)[i];
+ if (wl < m->wl_short[0] || wl > m->wl_long[0]) {
+ y2[i] = 0.0;
+ } else {
+ double x, wl1, wl2;
+ for (j = 0; j < (m->nwav[0]-1); j++) {
+ wl1 = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], j);
+ wl2 = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], j+1);
+ if (wl >= wl1 && wl <= wl2)
+ break;
+ }
+ x = (wl - wl1)/(wl2 - wl1);
+ y2[i] = ref1[j] + (ref1[j+1] - ref1[j]) * x;
+ }
+ }
+ printf("Original and up-sampled ");
+ if (ii == 0) {
+ printf("Reflective cal. curve:\n");
+ } else if (ii == 1) {
+ ref1 = m->emis_coef[0];
+ ref2 = &m->emis_coef[1];
+ printf("Emission cal. curve:\n");
+ } else {
+ printf("Ambient cal. curve:\n");
+ }
+ do_plot(x1, y1, y2, NULL, m->nwav[1]);
+
+ free_dvector(x1, 0, m->nwav[1]-1);
+ free_dvector(y1, 0, m->nwav[1]-1);
+ free_dvector(y2, 0, m->nwav[1]-1);
+ }
+#endif /* HIGH_RES_PLOT */
+ }
+ trspl->del(trspl);
+
+ /* Upsample stray light */
+ if (p->itype == instI1Pro2) {
+#ifdef SALONEINSTLIB
+ double **slp; /* 2D Array of stray light values */
+
+ /* Then the 2D stray light using linear interpolation */
+ slp = dmatrix(0, m->nwav[0]-1, 0, m->nwav[0]-1);
+
+ /* Set scattered points */
+ for (i = 0; i < m->nwav[0]; i++) { /* Output wavelength */
+ for (j = 0; j < m->nwav[0]; j++) { /* Input wavelength */
+
+ slp[i][j] = m->straylight[0][i][j];
+
+ /* Use interpolate/extrapolate for middle points */
+ if (j == (i-1) || j == i || j == (i+1)) {
+ int j0, j1;
+ double w0, w1;
+ if (j == (i-1)) {
+ if (j <= 0)
+ j0 = j+3, j1 = j+4;
+ else if (j >= (m->nwav[0]-3))
+ j0 = j-2, j1 = j-1;
+ else
+ j0 = j-1, j1 = j+3;
+ } else if (j == i) {
+ if (j <= 1)
+ j0 = j+2, j1 = j+3;
+ else if (j >= (m->nwav[0]-2))
+ j0 = j-3, j1 = j-2;
+ else
+ j0 = j-2, j1 = j+2;
+ } else if (j == (i+1)) {
+ if (j <= 2)
+ j0 = j+1, j1 = j+2;
+ else if (j >= (m->nwav[0]-1))
+ j0 = j-4, j1 = j-3;
+ else
+ j0 = j-3, j1 = j+1;
+ }
+ w1 = (j - j0)/(j1 - j0);
+ w0 = 1.0 - w1;
+ slp[i][j] = w0 * m->straylight[0][i][j0]
+ + w1 * m->straylight[0][i][j1];
+
+ }
+ }
+ }
+#else /* !SALONEINSTLIB */
+ /* Then setup 2D stray light using rspl */
+ if ((trspl = new_rspl(RSPL_NOFLAGS, 2, 1)) == NULL) {
+ a1logd(p->log,1,"i1pro: creating rspl for high res conversion failed\n");
+ return I1PRO_INT_NEW_RSPL_FAILED;
+ }
+
+ /* Set scattered points */
+ for (i = 0; i < m->nwav[0]; i++) { /* Output wavelength */
+ for (j = 0; j < m->nwav[0]; j++) { /* Input wavelength */
+ int ix = i * m->nwav[0] + j;
+
+ sd[ix].p[0] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], i);
+ sd[ix].p[1] = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], j);
+ sd[ix].v[0] = m->straylight[0][i][j];
+ sd[ix].w = 1.0;
+ if (j == (i-1) || j == i || j == (i+1))
+ sd[ix].w = 0.0;
+ }
+ }
+
+ glow[0] = m->wl_short[1];
+ glow[1] = m->wl_short[1];
+ ghigh[0] = m->wl_long[1];
+ ghigh[1] = m->wl_long[1];
+ gres[0] = m->nwav[1];
+ gres[1] = m->nwav[1];
+ avgdev[0] = 0.0;
+ avgdev[1] = 0.0;
+
+ trspl->fit_rspl_w(trspl, 0, sd, m->nwav[0] * m->nwav[0], glow, ghigh, gres, NULL, NULL, 0.5, avgdev, NULL);
+#endif /* !SALONEINSTLIB */
+
+ m->straylight[1] = dmatrixz(0, m->nwav[1]-1, 0, m->nwav[1]-1);
+
+ /* Create upsampled version */
+ for (i = 0; i < m->nwav[1]; i++) { /* Output wavelength */
+ for (j = 0; j < m->nwav[1]; j++) { /* Input wavelength */
+ double p0, p1;
+ p0 = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], i);
+ p1 = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], j);
+#ifdef SALONEINSTLIB
+ /* Do linear interp with clipping at ends */
+ {
+ int x0, x1, y0, y1;
+ double xx, yy, w0, w1, v0, v1;
+
+ xx = (m->nwav[0]-1.0) * (p0 - m->wl_short[0])/(m->wl_long[0] - m->wl_short[0]);
+ x0 = (int)floor(xx);
+ if (x0 <= 0)
+ x0 = 0;
+ else if (x0 >= (m->nwav[0]-2))
+ x0 = m->nwav[0]-2;
+ x1 = x0 + 1;
+ w1 = xx - (double)x0;
+ w0 = 1.0 - w1;
+
+ yy = (m->nwav[0]-1.0) * (p1 - m->wl_short[0])/(m->wl_long[0] - m->wl_short[0]);
+ y0 = (int)floor(yy);
+ if (y0 <= 0)
+ y0 = 0;
+ else if (y0 >= (m->nwav[0]-2))
+ y0 = m->nwav[0]-2;
+ y1 = y0 + 1;
+ v1 = yy - (double)y0;
+ v0 = 1.0 - v1;
+
+ pp.v[0] = w0 * v0 * slp[x0][y0]
+ + w0 * v1 * slp[x0][y1]
+ + w1 * v0 * slp[x1][y0]
+ + w1 * v1 * slp[x1][y1];
+ }
+#else /* !SALONEINSTLIB */
+ pp.p[0] = p0;
+ pp.p[1] = p1;
+ trspl->interp(trspl, &pp);
+#endif /* !SALONEINSTLIB */
+ m->straylight[1][i][j] = pp.v[0] * HIGHRES_WIDTH/10.0;
+ if (m->straylight[1][i][j] > 0.0)
+ m->straylight[1][i][j] = 0.0;
+ }
+ }
+
+ /* Fix primary wavelength weight and neighbors */
+ for (i = 0; i < m->nwav[1]; i++) { /* Output wavelength */
+ double sum;
+
+ if (i > 0)
+ m->straylight[1][i][i-1] = 0.0;
+ m->straylight[1][i][i] = 0.0;
+ if (i < (m->nwav[1]-1))
+ m->straylight[1][i][i+1] = 0.0;
+
+ for (sum = 0.0, j = 0; j < m->nwav[1]; j++)
+ sum += m->straylight[1][i][j];
+
+ m->straylight[1][i][i] = 1.0 - sum; /* Total sum should be 1.0 */
+ }
+
+#ifdef HIGH_RES_PLOT_STRAYL
+ /* Plot original and upsampled reference */
+ {
+ double *x1 = dvectorz(0, m->nwav[1]-1);
+ double *y1 = dvectorz(0, m->nwav[1]-1);
+ double *y2 = dvectorz(0, m->nwav[1]-1);
+
+ for (i = 0; i < m->nwav[1]; i++) { /* Output wavelength */
+ double wli = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], i);
+ int i1 = XSPECT_IX(m->wl_short[0], m->wl_long[0], m->nwav[0], wli);
+
+ for (j = 0; j < m->nwav[1]; j++) {
+ double wl = XSPECT_WL(m->wl_short[1], m->wl_long[1], m->nwav[1], j);
+ x1[j] = wl;
+ y1[j] = m->straylight[1][i][j];
+ if (y1[j] == 0.0)
+ y1[j] = -8.0;
+ else
+ y1[j] = log10(fabs(y1[j]));
+ if (wli < m->wl_short[0] || wli > m->wl_long[0]
+ || wl < m->wl_short[0] || wl > m->wl_long[0]) {
+ y2[j] = -8.0;
+ } else {
+ double x, wl1, wl2;
+ for (k = 0; k < (m->nwav[0]-1); k++) {
+ wl1 = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], k);
+ wl2 = XSPECT_WL(m->wl_short[0], m->wl_long[0], m->nwav[0], k+1);
+ if (wl >= wl1 && wl <= wl2)
+ break;
+ }
+ x = (wl - wl1)/(wl2 - wl1);
+ y2[j] = m->straylight[0][i1][k] + (m->straylight[0][i1][k+1]
+ - m->straylight[0][i1][k]) * x;
+ if (y2[j] == 0.0)
+ y2[j] = -8.0;
+ else
+ y2[j] = log10(fabs(y2[j]));
+ }
+ }
+ do_plot(x1, y1, y2, NULL, m->nwav[1]);
+ }
+
+ free_dvector(x1, 0, m->nwav[1]-1);
+ free_dvector(y1, 0, m->nwav[1]-1);
+ free_dvector(y2, 0, m->nwav[1]-1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+#ifdef SALONEINSTLIB
+ free_dmatrix(slp, 0, m->nwav[0]-1, 0, m->nwav[0]-1);
+#else /* !SALONEINSTLIB */
+ trspl->del(trspl);
+#endif /* !SALONEINSTLIB */
+ }
+ }
+
+ /* Create or re-create the high resolution filters */
+ for (refl = 0; refl < 2; refl++) { /* for emis/trans and reflective */
+ double fshmax; /* filter shape max wavelength from center */
+#define MXNOFC 64
+ i1pro_fc coeff2[500][MXNOFC]; /* New filter cooefficients */
+ double twidth;
+
+ /* Construct a set of filters that uses more CCD values */
+ twidth = HIGHRES_WIDTH;
+
+ if (m->nwav[1] > 500) { /* Assert */
+ a1loge(p->log,1,"High res filter has too many bands\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+ /* Use a simple means of determining width */
+ for (fshmax = 50.0; fshmax >= 0.0; fshmax -= 0.1) {
+ if (fabs(lanczos2(twidth, fshmax)) > 0.0001) {
+ fshmax += 0.1;
+ break;
+ }
+ }
+ if (fshmax <= 0.0) {
+ a1logw(p->log, "i1pro: fshmax search failed\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+// printf("~1 fshmax = %f\n",fshmax);
+
+#ifdef HIGH_RES_DEBUG
+ /* Check that the filter sums to a constant */
+ {
+ double x, sum;
+
+ for (x = 0.0; x < 5.0; x += 0.1) {
+ sum = 0;
+ sum += lin_fshape(fshape, ncp, x - 15.0);
+ sum += lin_fshape(fshape, ncp, x - 10.0);
+ sum += lin_fshape(fshape, ncp, x - 5.0);
+ sum += lin_fshape(fshape, ncp, x - 0.0);
+ sum += lin_fshape(fshape, ncp, x + 5.0);
+ sum += lin_fshape(fshape, ncp, x + 10.0);
+ printf("Offset %f, sum %f\n",x, sum);
+ }
+ }
+#endif /* HIGH_RES_DEBUG */
+
+ /* Create all the filters */
+ if (m->mtx_c[1][refl].nocoef != NULL)
+ free(m->mtx_c[1][refl].nocoef);
+ if ((m->mtx_c[1][refl].nocoef = (int *)calloc(m->nwav[1], sizeof(int))) == NULL) {
+ a1logw(p->log, "i1pro: malloc nocoef failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* For all the useful CCD bands */
+ for (i = 1; i < 127; i++) {
+ double w1, wl, w2;
+
+ /* Translate CCD center and boundaries to calibrated wavelength */
+ wl = i1pro_raw2wav(p, refl, (double)i);
+ w1 = i1pro_raw2wav(p, refl, (double)i - 0.5);
+ w2 = i1pro_raw2wav(p, refl, (double)i + 0.5);
+
+// printf("~1 CCD %d, w1 %f, wl %f, w2 %f\n",i,w1,wl,w2);
+
+ /* For each filter */
+ for (j = 0; j < m->nwav[1]; j++) {
+ double cwl, rwl; /* center, relative wavelegth */
+ double we;
+
+ cwl = m->wl_short[1] + (double)j * (m->wl_long[1] - m->wl_short[1])/(m->nwav[1]-1.0);
+ rwl = wl - cwl; /* relative wavelength to filter */
+
+ if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
+ continue; /* Doesn't fall into this filter */
+
+ /* Integrate in 0.05 nm increments from filter shape */
+ /* using triangular integration. */
+ {
+ int nn;
+ double lw, ll;
+
+ nn = (int)(fabs(w2 - w1)/0.05 + 0.5); /* Number to integrate over */
+
+ lw = w1; /* start at lower boundary of CCD cell */
+ ll = lanczos2(twidth, w1- cwl);
+ we = 0.0;
+ for (k = 0; k < nn; k++) {
+ double cw, cl;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(k);
+#endif
+ cw = w1 + (k+1.0)/(nn +1.0) * (w2 - w1); /* wl to sample */
+ cl = lanczos2(twidth, cw- cwl);
+ we += 0.5 * (cl + ll) * (lw - cw); /* Area under triangle */
+ ll = cl;
+ lw = cw;
+ }
+ }
+
+ if (m->mtx_c[1][refl].nocoef[j] >= MXNOFC) {
+ a1logw(p->log, "i1pro: run out of high res filter space\n");
+ return I1PRO_INT_ASSERT;
+ }
+
+ coeff2[j][m->mtx_c[1][refl].nocoef[j]].ix = i;
+ coeff2[j][m->mtx_c[1][refl].nocoef[j]++].we = we;
+// printf("~1 filter %d, cwl %f, rwl %f, ix %d, we %f, nocoefs %d\n",j,cwl,rwl,i,we,m->mtx_c[1][refl].nocoef[j]-1);
+ }
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot resampled curves */
+ {
+ double *xx, *ss;
+ double **yy;
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav[1]; j++) {
+ i = j % 5;
+
+ /* For each matrix value */
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++) {
+ yy[5][coeff2[j][k].ix] += 0.5 * coeff2[j][k].we;
+ yy[i][coeff2[j][k].ix] = coeff2[j][k].we;
+ }
+ }
+
+ printf("Hi-Res wavelength sampling curves:\n");
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+ /* Normalise the filters area in CCD space, while maintaining the */
+ /* total contribution of each CCD at the target too. */
+ {
+ int ii;
+ double tot = 0.0;
+ double ccdweight[128], avgw; /* Weighting determined by cell widths */
+ double ccdsum[128];
+
+ /* Normalize the overall filter weightings */
+ for (j = 0; j < m->nwav[1]; j++)
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
+ tot += coeff2[j][k].we;
+ tot /= (double)m->nwav[1];
+ for (j = 0; j < m->nwav[1]; j++)
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
+ coeff2[j][k].we /= tot;
+
+ /* Determine the relative weights for each CCD */
+ avgw = 0.0;
+ for (i = 1; i < 127; i++) {
+
+ ccdweight[i] = i1pro_raw2wav(p, refl, (double)i - 0.5)
+ - i1pro_raw2wav(p, refl, (double)i + 0.5);
+ ccdweight[i] = fabs(ccdweight[i]);
+ avgw += ccdweight[i];
+ }
+ avgw /= 126.0;
+ // ~~this isn't right because not all CCD's get used!!
+
+#ifdef NEVER
+ /* Itterate */
+ for (ii = 0; ; ii++) {
+
+ /* Normalize the individual filter weightings */
+ for (j = 0; j < m->nwav[1]; j++) {
+ double err;
+ tot = 0.0;
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
+ tot += coeff2[j][k].we;
+ err = 1.0 - tot;
+
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
+ coeff2[j][k].we += err/m->mtx_c[1][refl].nocoef[j];
+// for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
+// coeff2[j][k].we *= 1.0/tot;
+ }
+
+ /* Check CCD sums */
+ for (i = 1; i < 127; i++)
+ ccdsum[i] = 0.0;
+
+ for (j = 0; j < m->nwav[1]; j++) {
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
+ ccdsum[coeff2[j][k].ix] += coeff2[j][k].we;
+ }
+
+ if (ii >= 6)
+ break;
+
+ /* Readjust CCD sum */
+ for (i = 1; i < 127; i++) {
+ ccdsum[i] = ccdtsum[i]/ccdsum[i]; /* Amount to adjust */
+ }
+
+ for (j = 0; j < m->nwav[1]; j++) {
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++)
+ coeff2[j][k].we *= ccdsum[coeff2[j][k].ix];
+ }
+ }
+#endif /* NEVER */
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot resampled curves */
+ {
+ double *xx, *ss;
+ double **yy;
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav[1]; j++) {
+ i = j % 5;
+
+ /* For each matrix value */
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++) {
+ yy[5][coeff2[j][k].ix] += 0.5 * coeff2[j][k].we;
+ yy[i][coeff2[j][k].ix] = coeff2[j][k].we;
+ }
+ }
+
+ printf("Normalized Hi-Res wavelength sampling curves:\n");
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+ /* Convert hires filters into runtime format */
+ {
+ int xcount;
+
+ /* Allocate or reallocate high res filter tables */
+ if (m->mtx_c[1][refl].index != NULL)
+ free(m->mtx_c[1][refl].index);
+ if (m->mtx_c[1][refl].coef != NULL)
+ free(m->mtx_c[1][refl].coef);
+
+ if ((m->mtx_c[1][refl].index = (int *)calloc(m->nwav[1], sizeof(int))) == NULL) {
+ a1logw(p->log, "i1pro: malloc index failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ xcount = 0;
+ for (j = 0; j < m->nwav[1]; j++) {
+ m->mtx_c[1][refl].index[j] = coeff2[j][0].ix;
+ xcount += m->mtx_c[1][refl].nocoef[j];
+ }
+
+ if ((m->mtx_c[1][refl].coef = (double *)calloc(xcount, sizeof(double))) == NULL) {
+ a1logw(p->log, "i1pro: malloc coef failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ for (i = j = 0; j < m->nwav[1]; j++)
+ for (k = 0; k < m->mtx_c[1][refl].nocoef[j]; k++, i++)
+ m->mtx_c[1][refl].coef[i] = coeff2[j][k].we;
+
+ /* Set high res tables to new allocations */
+ m->mtx[1][refl] = m->mtx_c[1][refl];
+ }
+ }
+
+ /* Generate high res. per mode calibration factors. */
+ if (!m->hr_inited) {
+
+ m->hr_inited = 1; /* Set so that i1pro_compute_white_cal() etc. does right thing */
+
+ for (i = 0; i < i1p_no_modes; i++) {
+ i1pro_state *s = &m->ms[i];
+
+ if (s->cal_factor[1] == NULL)
+ s->cal_factor[1] = dvectorz(0, m->nwav[1]-1);
+
+ switch(i) {
+ case i1p_refl_spot:
+ case i1p_refl_scan:
+ if (s->cal_valid) {
+ /* (Using cal_factor[] as temp. for i1pro_absraw_to_abswav()) */
+#ifdef NEVER
+ printf("~1 regenerating calibration for reflection\n");
+ printf("~1 raw white data:\n");
+ plot_raw(s->white_data);
+#endif /* NEVER */
+ i1pro_absraw_to_abswav(p, 0, s->reflective, 1, &s->cal_factor[0], &s->white_data);
+#ifdef NEVER
+ printf("~1 Std res intmd. cal_factor:\n");
+ plot_wav(m, 0, s->cal_factor[0]);
+#endif /* NEVER */
+ i1pro_absraw_to_abswav(p, 1, s->reflective, 1, &s->cal_factor[1], &s->white_data);
+#ifdef NEVER
+ printf("~1 High intmd. cal_factor:\n");
+ plot_wav(m, 1, s->cal_factor[1]);
+ printf("~1 Std res white ref:\n");
+ plot_wav(m, 0, m->white_ref[0]);
+ printf("~1 High res white ref:\n");
+ plot_wav(m, 1, m->white_ref[1]);
+#endif /* NEVER */
+ i1pro_compute_white_cal(p, s->cal_factor[0], m->white_ref[0], s->cal_factor[0],
+ s->cal_factor[1], m->white_ref[1], s->cal_factor[1]);
+#ifdef NEVER
+ printf("~1 Std res final cal_factor:\n");
+ plot_wav(m, 0, s->cal_factor[0]);
+ printf("~1 High final cal_factor:\n");
+ plot_wav(m, 1, s->cal_factor[1]);
+#endif /* NEVER */
+ }
+ break;
+
+ case i1p_emiss_spot_na:
+ case i1p_emiss_spot:
+ case i1p_emiss_scan:
+ for (j = 0; j < m->nwav[1]; j++)
+ s->cal_factor[1][j] = EMIS_SCALE_FACTOR * m->emis_coef[1][j];
+ break;
+
+ case i1p_amb_spot:
+ case i1p_amb_flash:
+#ifdef FAKE_AMBIENT
+ for (j = 0; j < m->nwav[1]; j++)
+ s->cal_factor[1][j] = EMIS_SCALE_FACTOR * m->emis_coef[1][j];
+ s->cal_valid = 1;
+#else
+
+ if (m->amb_coef[0] != NULL) {
+ for (j = 0; j < m->nwav[1]; j++)
+ s->cal_factor[1][j] = AMB_SCALE_FACTOR * m->emis_coef[1][j] * m->amb_coef[1][j];
+ s->cal_valid = 1;
+ }
+#endif
+ break;
+ case i1p_trans_spot:
+ case i1p_trans_scan:
+ if (s->cal_valid) {
+ /* (Using cal_factor[] as temp. for i1pro_absraw_to_abswav()) */
+ i1pro_absraw_to_abswav(p, 0, s->reflective, 1, &s->cal_factor[0], &s->white_data);
+ i1pro_absraw_to_abswav(p, 1, s->reflective, 1, &s->cal_factor[1], &s->white_data);
+ i1pro_compute_white_cal(p, s->cal_factor[0], NULL, s->cal_factor[0],
+ s->cal_factor[1], NULL, s->cal_factor[1]);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Hires has been initialised */
+ m->hr_inited = 1;
+
+ return ev;
+}
+
+#endif /* HIGH_RES */
+
+
+/* return nz if high res is supported */
+int i1pro_imp_highres(i1pro *p) {
+#ifdef HIGH_RES
+ return 1;
+#else
+ return 0;
+#endif /* HIGH_RES */
+}
+
+/* Set to high resolution mode */
+i1pro_code i1pro_set_highres(i1pro *p) {
+ int i;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+
+#ifdef HIGH_RES
+ if (m->hr_inited == 0) {
+ if ((ev = i1pro_create_hr(p)) != I1PRO_OK)
+ return ev;
+ }
+ m->highres = 1;
+#else
+ ev = I1PRO_UNSUPPORTED;
+#endif /* HIGH_RES */
+
+ return ev;
+}
+
+/* Set to standard resolution mode */
+i1pro_code i1pro_set_stdres(i1pro *p) {
+ int i;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+
+#ifdef HIGH_RES
+ m->highres = 0;
+#else
+ ev = I1PRO_UNSUPPORTED;
+#endif /* HIGH_RES */
+
+ return ev;
+}
+
+/* =============================================== */
+
+/* Modify the scan consistency tolerance */
+i1pro_code i1pro_set_scan_toll(i1pro *p, double toll_ratio) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code ev = I1PRO_OK;
+
+ m->scan_toll_ratio = toll_ratio;
+
+ return I1PRO_OK;
+}
+
+
+/* Optics adjustment weights */
+static double opt_adj_weights[21] = {
+ 1.4944496665144658e-282, 2.0036175483913455e-070, 1.2554893022685038e+232,
+ 2.3898157055642966e+190, 1.5697625128432372e-076, 6.6912978722191457e+281,
+ 1.2369092402930559e+277, 1.4430907501246712e-153, 3.0017439193018232e+238,
+ 1.2978311824382444e+161, 5.5068703318775818e-311, 7.7791723264455314e-260,
+ 6.4560484084110176e+170, 8.9481529920968425e+165, 1.3565405878488529e-153,
+ 2.0835868791190880e-076, 5.4310198502711138e+241, 4.8689849775675438e+275,
+ 9.2709981544886391e+122, 3.7958270103353899e-153, 7.1366083837501666e-154
+};
+
+/* Convert from spectral to XYZ, and transfer to the ipatch array */
+i1pro_code i1pro_conv2XYZ(
+ i1pro *p,
+ ipatch *vals, /* Values to return */
+ int nvals, /* Number of values */
+ double **specrd, /* Spectral readings */
+ instClamping clamp /* Clamp XYZ/Lab to be +ve */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ xsp2cie *conv; /* Spectral to XYZ conversion object */
+ int i, j, k;
+ int six = 0; /* Starting index */
+ int nwl = m->nwav[m->highres]; /* Number of wavelegths */
+ double wl_short = m->wl_short[m->highres]; /* Starting wavelegth */
+ double sms; /* Weighting */
+
+ if (s->emiss)
+ conv = new_xsp2cie(icxIT_none, NULL, icxOT_CIE_1931_2, NULL, icSigXYZData, (icxClamping)clamp);
+ else
+ conv = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigXYZData, (icxClamping)clamp);
+ if (conv == NULL)
+ return I1PRO_INT_CIECONVFAIL;
+
+ /* Don't report any wavelengths below the minimum for this mode */
+ if ((s->min_wl-1e-3) > wl_short) {
+ double wl = 0.0;
+ for (j = 0; j < m->nwav[m->highres]; j++) {
+ wl = XSPECT_WL(m->wl_short[m->highres], m->wl_long[m->highres], m->nwav[m->highres], j);
+ if (wl >= (s->min_wl-1e-3))
+ break;
+ }
+ six = j;
+ wl_short = wl;
+ nwl -= six;
+ }
+
+ a1logd(p->log,5,"i1pro_conv2XYZ got wl_short %f, wl_long %f, nwav %d, min_wl %f\n",
+ m->wl_short[m->highres], m->wl_long[m->highres], m->nwav[m->highres], s->min_wl);
+ a1logd(p->log,5," after skip got wl_short %f, nwl = %d\n", wl_short, nwl);
+
+ for (sms = 0.0, i = 1; i < 21; i++)
+ sms += opt_adj_weights[i];
+ sms *= opt_adj_weights[0];
+
+ for (i = 0; i < nvals; i++) {
+
+ vals[i].loc[0] = '\000';
+ vals[i].mtype = inst_mrt_none;
+ vals[i].XYZ_v = 0;
+ vals[i].sp.spec_n = 0;
+ vals[i].duration = 0.0;
+
+ vals[i].sp.spec_n = nwl;
+ vals[i].sp.spec_wl_short = wl_short;
+ vals[i].sp.spec_wl_long = m->wl_long[m->highres];
+
+ if (s->emiss) {
+ /* Leave spectral values as mW/m^2 */
+ for (j = six, k = 0; j < m->nwav[m->highres]; j++, k++) {
+ vals[i].sp.spec[k] = specrd[i][j] * sms;
+ }
+ vals[i].sp.norm = 1.0;
+
+ /* Set the XYZ */
+ conv->convert(conv, vals[i].XYZ, &vals[i].sp);
+ vals[i].XYZ_v = 1;
+
+ if (s->ambient) {
+ if (s->flash)
+ vals[i].mtype = inst_mrt_ambient_flash;
+ else
+ vals[i].mtype = inst_mrt_ambient;
+ } else {
+ if (s->flash)
+ vals[i].mtype = inst_mrt_emission_flash;
+ else
+ vals[i].mtype = inst_mrt_emission;
+ }
+
+ } else {
+ /* Scale spectral values to percentage reflectance */
+ for (j = six, k = 0; j < m->nwav[m->highres]; j++, k++) {
+ vals[i].sp.spec[k] = 100.0 * specrd[i][j] * sms;
+ }
+ vals[i].sp.norm = 100.0;
+
+ /* Set the XYZ */
+ conv->convert(conv, vals[i].XYZ, &vals[i].sp);
+ vals[i].XYZ_v = 1;
+ vals[i].XYZ[0] *= 100.0;
+ vals[i].XYZ[1] *= 100.0;
+ vals[i].XYZ[2] *= 100.0;
+
+ if (s->trans)
+ vals[i].mtype = inst_mrt_transmissive;
+ else
+ vals[i].mtype = inst_mrt_reflective;
+ }
+
+ /* Don't return spectral if not asked for */
+ if (!m->spec_en) {
+ vals[i].sp.spec_n = 0;
+ }
+ }
+
+ conv->del(conv);
+ return I1PRO_OK;
+}
+
+/* Check a reflective white reference measurement to see if */
+/* it seems reasonable. Return I1PRO_OK if it is, error if not. */
+i1pro_code i1pro_check_white_reference1(
+ i1pro *p,
+ double *abswav /* [nwav[0]] Measurement to check */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ double *emiswav, normfac;
+ double avg01, avg2227;
+ int j;
+
+ emiswav = dvector(-1, m->nraw-1);
+
+ /* Convert from absolute wavelength converted sensor reading, */
+ /* to calibrated emission wavelength spectrum. */
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav[0]; j++) {
+ emiswav[j] = m->emis_coef[0][j] * abswav[j];
+ }
+#ifdef PLOT_DEBUG
+ printf("White ref read converted to emissive spectrum:\n");
+ plot_wav(m, 0, emiswav);
+#endif
+
+ /* Normalise the measurement to the reflectance of the 17 wavelength */
+ /* of the white reference (550nm), as well as dividing out the */
+ /* reference white. This should leave us with the iluminant spectrum, */
+ normfac = m->white_ref[0][17]/emiswav[17];
+
+ for (j = 0; j < m->nwav[0]; j++) {
+ emiswav[j] *= normfac/m->white_ref[0][j];
+ }
+
+#ifdef PLOT_DEBUG
+ printf("normalised to reference white read:\n");
+ plot_wav(m, 0, emiswav);
+#endif
+
+ /* Compute two sample averages of the illuminant spectrum. */
+ avg01 = 0.5 * (emiswav[0] + emiswav[1]);
+
+ for (avg2227 = 0, j = 22; j < 28; j++) {
+ avg2227 += emiswav[j];
+ }
+ avg2227 /= (double)(28 - 22);
+
+ free_dvector(emiswav, -1, m->nraw-1);
+
+ /* And check them against tolerance for the illuminant. */
+ if (m->physfilt == 0x82) { /* UV filter */
+ if (0.0 < avg01 && avg01 < 0.05
+ && 1.2 < avg2227 && avg2227 < 1.76) {
+ return I1PRO_OK;
+ }
+
+ } else { /* No filter */
+ if (0.11 < avg01 && avg01 < 0.22
+ && 1.35 < avg2227 && avg2227 < 1.6) {
+ return I1PRO_OK;
+ }
+ }
+ a1logd(p->log,2,"Checking white reference failed, 0.11 < avg01 %f < 0.22, 1.35 < avg2227 %f < 1.6\n",avg01,avg2227);
+ return I1PRO_RD_WHITEREFERROR;
+}
+
+/* Compute a mode calibration factor given the reading of the white reference. */
+/* Return 1 if any of the transmission wavelengths are low. */
+int i1pro_compute_white_cal(
+ i1pro *p,
+ double *cal_factor0, /* [nwav[0]] Calibration factor to compute */
+ double *white_ref0, /* [nwav[0]] White reference to aim for, NULL for 1.0 */
+ double *white_read0, /* [nwav[0]] The white that was read */
+ double *cal_factor1, /* [nwav[1]] Calibration factor to compute */
+ double *white_ref1, /* [nwav[1]] White reference to aim for, NULL for 1.0 */
+ double *white_read1 /* [nwav[1]] The white that was read */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ int j, warn = 0;;
+
+ if (white_ref0 == NULL) { /* transmission white reference */
+ double avgwh = 0.0;
+
+ /* Compute average white reference reading */
+ for (j = 0; j < m->nwav[0]; j++)
+ avgwh += white_read0[j];
+ avgwh /= (double)m->nwav[0];
+
+ /* For each wavelength */
+ for (j = 0; j < m->nwav[0]; j++) {
+ /* If reference is < 0.4% of average */
+ if (white_read0[j]/avgwh < 0.004) {
+ cal_factor0[j] = 1.0/(0.004 * avgwh);
+ warn = 1;
+ } else {
+ cal_factor0[j] = 1.0/white_read0[j];
+ }
+ }
+
+ } else { /* Reflection white reference */
+
+ /* For each wavelength */
+ for (j = 0; j < m->nwav[0]; j++) {
+ if (white_read0[j] < 1000.0)
+ cal_factor0[j] = white_ref0[j]/1000.0;
+ else
+ cal_factor0[j] = white_ref0[j]/white_read0[j];
+ }
+ }
+
+#ifdef HIGH_RES
+ if (m->hr_inited == 0)
+ return warn;
+
+ if (white_ref1 == NULL) { /* transmission white reference */
+ double avgwh = 0.0;
+
+ /* Compute average white reference reading */
+ for (j = 0; j < m->nwav[1]; j++)
+ avgwh += white_read1[j];
+ avgwh /= (double)m->nwav[1];
+
+ /* For each wavelength */
+ for (j = 0; j < m->nwav[1]; j++) {
+ /* If reference is < 0.4% of average */
+ if (white_read1[j]/avgwh < 0.004) {
+ cal_factor1[j] = 1.0/(0.004 * avgwh);
+ warn = 1;
+ } else {
+ cal_factor1[j] = 1.0/white_read1[j];
+ }
+ }
+
+ } else { /* Reflection white reference */
+
+ /* For each wavelength */
+ for (j = 0; j < m->nwav[1]; j++) {
+ if (white_read1[j] < 1000.0)
+ cal_factor1[j] = white_ref1[j]/1000.0;
+ else
+ cal_factor1[j] = white_ref1[j]/white_read1[j];
+ }
+ }
+#endif /* HIGH_RES */
+ return warn;
+}
+
+/* For adaptive mode, compute a new integration time and gain mode */
+/* in order to optimise the sensor values. Note that the Rev E doesn't have */
+/* a high gain mode. */
+i1pro_code i1pro_optimise_sensor(
+ i1pro *p,
+ double *pnew_int_time,
+ int *pnew_gain_mode,
+ double cur_int_time,
+ int cur_gain_mode,
+ int permithg, /* nz to permit switching to high gain mode */
+ int permitclip, /* nz to permit clipping out of range int_time, else error */
+ double targoscale, /* Optimising target scale ( <= 1.0) */
+ double scale /* scale needed of current int time to reach optimum */
+) {
+ i1pro_code ev = I1PRO_OK;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ double new_int_time;
+ int new_gain_mode;
+
+ a1logd(p->log,3,"i1pro_optimise_sensor called, inttime %f, gain mode %d, targ scale %f, scale %f\n",cur_int_time,cur_gain_mode, targoscale, scale);
+
+ /* Compute new normal gain integration time */
+ if (cur_gain_mode) /* If high gain */
+ new_int_time = cur_int_time * scale * m->highgain;
+ else
+ new_int_time = cur_int_time * scale;
+ new_gain_mode = 0;
+
+ a1logd(p->log,3,"target inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ /* Adjust to low light situation by increasing the integration time. */
+ if (new_int_time > s->targmaxitime) { /* Exceeding target integration time */
+ if (s->targmaxitime/new_int_time > s->targoscale2) { /* But within range */
+ /* Compromise sensor target value to maintain targmaxitime */
+ new_int_time = s->targmaxitime;
+ a1logd(p->log,3,"Using targmaxitime with compromise sensor target\n");
+ } else {
+ /* Target reduced sensor value to give improved measurement time and continuity */
+ new_int_time *= s->targoscale2;
+ a1logd(p->log,3,"Using compromse sensor target\n");
+ }
+#ifdef USE_HIGH_GAIN_MODE
+ /* !! Should change this so that it doesn't affect int. time, */
+ /* but that we simply switch to high gain mode when the */
+ /* expected level is < target_level/gain */
+ /* Hmm. It may not be a good idea to use high gain mode if it compromises */
+ /* the longer integration time which reduces noise. */
+ if (p->itype != instI1Pro2 && new_int_time > m->max_int_time && permithg) {
+ new_int_time /= m->highgain;
+ new_gain_mode = 1;
+ a1logd(p->log,3,"Switching to high gain mode\n");
+ }
+#endif
+ }
+ a1logd(p->log,3,"after low light adjust, inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ /* Deal with still low light */
+ if (new_int_time > m->max_int_time) {
+ if (permitclip)
+ new_int_time = m->max_int_time;
+ else
+ return I1PRO_RD_LIGHTTOOLOW;
+ }
+ a1logd(p->log,3,"after low light clip, inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ /* Adjust to high light situation */
+ if (new_int_time < m->min_int_time && targoscale < 1.0) {
+ new_int_time /= targoscale; /* Aim for non-scaled sensor optimum */
+ if (new_int_time > m->min_int_time) /* But scale as much as possible */
+ new_int_time = m->min_int_time;
+ }
+ a1logd(p->log,3,"after high light adjust, inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ /* Deal with still high light */
+ if (new_int_time < m->min_int_time) {
+ if (permitclip)
+ new_int_time = m->min_int_time;
+ else
+ return I1PRO_RD_LIGHTTOOHIGH;
+ }
+ a1logd(p->log,3,"after high light clip, returning inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ if (pnew_int_time != NULL)
+ *pnew_int_time = new_int_time;
+
+ if (pnew_gain_mode != NULL)
+ *pnew_gain_mode = new_gain_mode;
+
+ return I1PRO_OK;
+}
+
+/* Compute the number of measurements needed, given the target */
+/* measurement time and integration time. Will return 0 if target time is 0 */
+int i1pro_comp_nummeas(
+ i1pro *p,
+ double meas_time,
+ double int_time
+) {
+ int nmeas;
+ if (meas_time <= 0.0)
+ return 0;
+ nmeas = (int)floor(meas_time/int_time + 0.5);
+ if (nmeas < 1)
+ nmeas = 1;
+ return nmeas;
+}
+
+/* Convert the dark interpolation data to a useful state */
+/* (also allow for interpolating the shielded cell values) */
+void
+i1pro_prepare_idark(
+ i1pro *p
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ int i, j;
+
+ /* For normal and high gain */
+ for (i = 0; i < 4; i+= 2) {
+ for (j = -1; j < m->nraw; j++) {
+ double d01, d1;
+ d01 = s->idark_data[i+0][j] * s->idark_int_time[i+0];
+ d1 = s->idark_data[i+1][j] * s->idark_int_time[i+1];
+
+ /* Compute increment */
+ s->idark_data[i+1][j] = (d1 - d01)/(s->idark_int_time[i+1] - s->idark_int_time[i+0]);
+
+ /* Compute base */
+ s->idark_data[i+0][j] = d01 - s->idark_data[i+1][j] * s->idark_int_time[i+0];
+ }
+ if (p->itype == instI1Pro2) /* Rev E doesn't have high gain mode */
+ break;
+ }
+}
+
+/* Create the dark reference for the given integration time and gain */
+/* by interpolating from the 4 readings taken earlier. */
+i1pro_code
+i1pro_interp_dark(
+ i1pro *p,
+ double *result, /* Put result of interpolation here */
+ double inttime,
+ int gainmode
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_state *s = &m->ms[m->mmode];
+ int i, j;
+
+ if (!s->idark_valid)
+ return I1PRO_INT_NOTCALIBRATED;
+
+ i = 0;
+#ifdef USE_HIGH_GAIN_MODE
+ if (gainmode)
+ i = 2;
+#endif
+
+ for (j = -1; j < m->nraw; j++) {
+ double tt;
+ tt = s->idark_data[i+0][j] + inttime * s->idark_data[i+1][j];
+ tt /= inttime;
+ result[j] = tt;
+ }
+ return I1PRO_OK;
+}
+
+/* Set the noinitcalib mode */
+void i1pro_set_noinitcalib(i1pro *p, int v, int losecs) {
+ i1proimp *m = (i1proimp *)p->m;
+
+ /* Ignore disabling init calib if more than losecs since instrument was open */
+ if (v && losecs != 0 && m->lo_secs >= losecs) {
+ a1logd(p->log,3,"initcalib disable ignored because %d >= %d secs\n",m->lo_secs,losecs);
+ return;
+ }
+ m->noinitcalib = v;
+}
+
+/* Set the trigger config */
+void i1pro_set_trig(i1pro *p, inst_opt_type trig) {
+ i1proimp *m = (i1proimp *)p->m;
+ m->trig = trig;
+}
+
+/* Return the trigger config */
+inst_opt_type i1pro_get_trig(i1pro *p) {
+ i1proimp *m = (i1proimp *)p->m;
+ return m->trig;
+}
+
+/* Switch thread handler */
+int i1pro_switch_thread(void *pp) {
+ int nfailed = 0;
+ i1pro *p = (i1pro *)pp;
+ i1proimp *m = (i1proimp *)p->m;
+ i1pro_code rv = I1PRO_OK;
+ a1logd(p->log,3,"Switch thread started\n");
+ for (nfailed = 0;nfailed < 5;) {
+ rv = i1pro_waitfor_switch_th(p, SW_THREAD_TIMEOUT);
+ a1logd(p->log,8,"Switch handler triggered with rv %d, th_term %d\n",rv,m->th_term);
+ if (m->th_term) {
+ m->th_termed = 1;
+ break;
+ }
+ if (rv == I1PRO_INT_BUTTONTIMEOUT) {
+ nfailed = 0;
+ continue;
+ }
+ if (rv != I1PRO_OK) {
+ nfailed++;
+ a1logd(p->log,3,"Switch thread failed with 0x%x\n",rv);
+ continue;
+ }
+ m->switch_count++;
+ if (!m->hide_switch && p->eventcallback != NULL) {
+ p->eventcallback(p->event_cntx, inst_event_switch);
+ }
+ }
+ a1logd(p->log,3,"Switch thread returning\n");
+ return rv;
+}
+
+/* ============================================================ */
+/* Low level i1pro commands */
+
+/* USB Instrument commands */
+
+/* Reset the instrument */
+i1pro_code
+i1pro_reset(
+ i1pro *p,
+ int mask /* reset mask ?. Known values ar 0x1f, 0x07, 0x01 */
+ /* 0x1f = normal resent */
+ /* 0x01 = establish high power mode */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[2]; /* 1 or 2 bytes to write */
+ int len = 1; /* Message length */
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ a1logd(p->log,2,"i1pro_reset: reset with mask 0x%02x @ %d msec\n",
+ mask,(stime = msec_time()) - m->msec);
+
+ pbuf[0] = mask;
+
+ if (p->itype == instI1Pro2) {
+ pbuf[1] = 0; /* Not known what i1pro2 second byte is for */
+ len = 2;
+ }
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xCA, 0, 0, pbuf, len, 2.0);
+
+ rv = icoms2i1pro_err(se);
+
+ a1logd(p->log,2,"i1pro_reset: complete, ICOM err 0x%x (%d msec)\n",se,msec_time()-stime);
+
+ /* Allow time for hardware to stabalize */
+ msec_sleep(100);
+
+ /* Make sure that we re-initialize the measurement mode */
+ m->c_intclocks = 0;
+ m->c_lampclocks = 0;
+ m->c_nummeas = 0;
+ m->c_measmodeflags = 0;
+
+ return rv;
+}
+
+/* Read from the EEProm */
+i1pro_code
+i1pro_readEEProm(
+ i1pro *p,
+ unsigned char *buf, /* Where to read it to */
+ int addr, /* Address in EEprom to read from */
+ int size /* Number of bytes to read (max 65535) */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ int rwbytes; /* Data bytes read or written */
+ unsigned char pbuf[8]; /* Write EEprom parameters */
+ int len = 8; /* Message length */
+ int se, rv = I1PRO_OK;
+ int stime;
+
+ if (size >= 0x10000)
+ return I1PRO_INT_EETOOBIG;
+
+ a1logd(p->log,2,"i1pro_readEEProm: address 0x%x size 0x%x @ %d msec\n",
+ addr, size, (stime = msec_time()) - m->msec);
+
+ int2buf(&pbuf[0], addr);
+ short2buf(&pbuf[4], size);
+ pbuf[6] = pbuf[7] = 0; /* Ignored */
+
+ if (p->itype == instI1Pro2)
+ len = 6;
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC4, 0, 0, pbuf, len, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_readEEProm: read failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ /* Now read the bytes */
+ se = p->icom->usb_read(p->icom, NULL, 0x82, buf, size, &rwbytes, 5.0);
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_readEEProm: read failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ if (rwbytes != size) {
+ a1logd(p->log,1,"i1pro_readEEProm: 0x%x bytes, short read error\n",rwbytes);
+ return I1PRO_HW_EE_SHORTREAD;
+ }
+
+ if (p->log->debug >= 7) {
+ int i;
+ char oline[100], *bp = oline;
+ for (i = 0; i < size; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp," %04x:",i);
+ bp += sprintf(bp," %02x",buf[i]);
+ if ((i+1) >= size || ((i+1) % 16) == 0) {
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,7,oline);
+ bp = oline;
+ }
+ }
+ }
+
+ a1logd(p->log,2,"i1pro_readEEProm: 0x%x bytes, ICOM err 0x%x (%d msec)\n",
+ rwbytes, se, msec_time()-stime);
+
+ return rv;
+}
+
+/* Write to the EEProm */
+i1pro_code
+i1pro_writeEEProm(
+ i1pro *p,
+ unsigned char *buf, /* Where to write from */
+ int addr, /* Address in EEprom to write to */
+ int size /* Number of bytes to write (max 65535) */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ int rwbytes; /* Data bytes read or written */
+ unsigned char pbuf[8]; /* Write EEprom parameters */
+ int len = 8; /* Message length */
+ int se = 0, rv = I1PRO_OK;
+ int i;
+ int stime;
+
+ /* Don't write over fixed values, as the instrument could become unusable.. */
+ if (addr < 0 || addr > 0x1000 || (addr + size) >= 0x1000)
+ return I1PRO_INT_EETOOBIG;
+
+ a1logd(p->log,2,"i1pro_writeEEProm: address 0x%x size 0x%x @ %d msec\n",
+ addr,size, (stime = msec_time()) - m->msec);
+
+ if (p->log->debug >= 6) {
+ int i;
+ char oline[100], *bp = oline;
+ for (i = 0; i < size; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp," %04x:",i);
+ bp += sprintf(bp," %02x",buf[i]);
+ if ((i+1) >= size || ((i+1) % 16) == 0) {
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,6,oline);
+ bp = oline;
+ }
+ }
+ }
+
+#ifdef ENABLE_WRITE
+ int2buf(&pbuf[0], addr);
+ short2buf(&pbuf[4], size);
+ short2buf(&pbuf[6], 0x100); /* Might be accidental, left over from getmisc.. */
+
+ if (p->itype == instI1Pro2)
+ len = 6;
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC3, 0, 0, pbuf, len, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_writeEEProm: write failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ /* Now write the bytes */
+ se = p->icom->usb_write(p->icom, NULL, 0x03, buf, size, &rwbytes, 5.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_writeEEProm: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ if (rwbytes != size) {
+ a1logd(p->log,1,"i1pro_writeEEProm: 0x%x bytes, short write error\n",rwbytes);
+ return I1PRO_HW_EE_SHORTWRITE;
+ }
+
+ /* Now we write two separate bytes of 0 - confirm write ?? */
+ for (i = 0; i < 2; i++) {
+ pbuf[0] = 0;
+
+ /* Now write the bytes */
+ se = p->icom->usb_write(p->icom, NULL, 0x03, pbuf, 1, &rwbytes, 5.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_writeEEProm: write failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ if (rwbytes != 1) {
+ a1logd(p->log,1,"i1pro_writeEEProm: 0x%x bytes, short write error\n",rwbytes);
+ return I1PRO_HW_EE_SHORTWRITE;
+ }
+ }
+ a1logd(p->log,2,"i1pro_writeEEProm: 0x%x bytes, ICOM err 0x%x (%d msec)\n",
+ size, se, msec_time()-stime);
+
+ /* The instrument needs some recovery time after a write */
+ msec_sleep(50);
+
+#else /* ENABLE_WRITE */
+
+ a1logd(p->log,2,"i1pro_writeEEProm: (NOT) 0x%x bytes, ICOM err 0x%x\n",size, se);
+
+#endif /* ENABLE_WRITE */
+
+ return rv;
+}
+
+/* Get the miscellaneous status */
+/* return pointers may be NULL if not needed. */
+i1pro_code
+i1pro_getmisc(
+ i1pro *p,
+ int *fwrev, /* Return the hardware version number */
+ int *unkn1, /* Unknown status, set after doing a measurement */
+ int *maxpve, /* Maximum positive value in sensor readings */
+ int *unkn3, /* Unknown status, usually 1 */
+ int *powmode /* 0 = high power mode, 8 = low power mode */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[8]; /* status bytes read */
+ int _fwrev;
+ int _unkn1;
+ int _maxpve;
+ int _unkn3;
+ int _powmode;
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ a1logd(p->log,2,"i1pro_getmisc: @ %d msec\n",(stime = msec_time()) - m->msec);
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC9, 0, 0, pbuf, 8, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_getmisc: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _fwrev = buf2ushort(&pbuf[0]);
+ _unkn1 = buf2ushort(&pbuf[2]); /* Value set after each read. Average ?? */
+ _maxpve = buf2ushort(&pbuf[4]);
+ _unkn3 = pbuf[6]; /* Flag values are tested, but don't seem to be used ? */
+ _powmode = pbuf[7];
+
+ a1logd(p->log,2,"i1pro_getmisc: returning %d, 0x%04x, 0x%04x, 0x%02x, 0x%02x ICOM err 0x%x (%d msec)\n",
+ _fwrev, _unkn1, _maxpve, _unkn3, _powmode, se, msec_time()-stime);
+
+ if (fwrev != NULL) *fwrev = _fwrev;
+ if (unkn1 != NULL) *unkn1 = _unkn1;
+ if (maxpve != NULL) *maxpve = _maxpve;
+ if (unkn3 != NULL) *unkn3 = _unkn3;
+ if (powmode != NULL) *powmode = _powmode;
+
+ return rv;
+}
+
+/* Get the current measurement parameters */
+/* Return pointers may be NULL if not needed. */
+i1pro_code
+i1pro_getmeasparams(
+ i1pro *p,
+ int *intclocks, /* Number of integration clocks */
+ int *lampclocks, /* Number of lamp turn on sub-clocks */
+ int *nummeas, /* Number of measurements */
+ int *measmodeflags /* Measurement mode flags */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[8]; /* status bytes read */
+ int _intclocks;
+ int _lampclocks;
+ int _nummeas;
+ int _measmodeflags;
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ a1logd(p->log,2,"i1pro_getmeasparams: @ %d msec\n", (stime = msec_time()) - m->msec);
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC2, 0, 0, pbuf, 8, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_getmeasparams: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _intclocks = buf2ushort(&pbuf[0]);
+ _lampclocks = buf2ushort(&pbuf[2]);
+ _nummeas = buf2ushort(&pbuf[4]);
+ _measmodeflags = pbuf[6];
+
+ a1logd(p->log,2,"i1pro_getmeasparams: returning %d, %d, %d, 0x%02x ICOM err 0x%x (%d msec)\n",
+ _intclocks, _lampclocks, _nummeas, _measmodeflags, se, msec_time()-stime);
+
+ if (intclocks != NULL) *intclocks = _intclocks;
+ if (lampclocks != NULL) *lampclocks = _lampclocks;
+ if (nummeas != NULL) *nummeas = _nummeas;
+ if (measmodeflags != NULL) *measmodeflags = _measmodeflags;
+
+ return rv;
+}
+
+/* Set the current measurement parameters */
+/* Return pointers may be NULL if not needed. */
+/* Quirks:
+
+ Rev. A upgrade:
+ Rev. B:
+ Appears to have a bug where the measurement time
+ is the sum of the previous measurement plus the current measurement.
+ It doesn't seem to alter the integration time though.
+ There is no obvious way of fixing this (ie. reseting the instrument
+ doesn't work).
+
+ Rev. D:
+ It appears that setting intclocks to 0, toggles to/from
+ a half clock speed mode. (?)
+*/
+
+i1pro_code
+i1pro_setmeasparams(
+ i1pro *p,
+ int intclocks, /* Number of integration clocks */
+ int lampclocks, /* Number of lamp turn on sub-clocks */
+ int nummeas, /* Number of measurements */
+ int measmodeflags /* Measurement mode flags */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[8]; /* command bytes written */
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ a1logd(p->log,2,"i1pro_setmeasparams: %d, %d, %d, 0x%02x @ %d msec\n",
+ intclocks, lampclocks, nummeas, measmodeflags,
+ (stime = msec_time()) - m->msec);
+
+ short2buf(&pbuf[0], intclocks);
+ short2buf(&pbuf[2], lampclocks);
+ short2buf(&pbuf[4], nummeas);
+ pbuf[6] = measmodeflags;
+ pbuf[7] = 0;
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC1, 0, 0, pbuf, 8, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_setmeasparams: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ a1logd(p->log,2,"i1pro_setmeasparams: returning ICOM err 0x%x (%d msec)\n",
+ se,msec_time()-stime);
+ return rv;
+}
+
+/* Delayed trigger implementation, called from thread */
+static int
+i1pro_delayed_trigger(void *pp) {
+ i1pro *p = (i1pro *)pp;
+ i1proimp *m = (i1proimp *)p->m;
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ if ((m->c_measmodeflags & I1PRO_MMF_NOLAMP) == 0) { /* Lamp will be on for measurement */
+ m->llampoffon = msec_time(); /* Record when it turned on */
+// printf("~1 got lamp off -> on at %d (%f)\n",m->llampoffon, (m->llampoffon - m->llamponoff)/1000.0);
+
+ }
+
+ a1logd(p->log,2,"i1pro_delayed_trigger: start sleep @ %d msec\n", msec_time() - m->msec);
+
+ /* Delay the trigger */
+ msec_sleep(m->trig_delay);
+
+ m->tr_t1 = msec_time(); /* Diagnostic */
+
+ a1logd(p->log,2,"i1pro_delayed_trigger: trigger @ %d msec\n",(stime = msec_time()) - m->msec);
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC0, 0, 0, NULL, 0, 2.0);
+
+ m->tr_t2 = msec_time(); /* Diagnostic */
+
+ m->trig_se = se;
+ m->trig_rv = icoms2i1pro_err(se);
+
+ a1logd(p->log,2,"i1pro_delayed_trigger: returning ICOM err 0x%x (%d msec)\n",
+ se,msec_time()-stime);
+
+ return 0;
+}
+
+/* Trigger a measurement after the nominated delay */
+/* The actual return code will be in m->trig_rv after the delay. */
+/* This allows us to start the measurement read before the trigger, */
+/* ensuring that process scheduling latency can't cause the read to fail. */
+i1pro_code
+i1pro_triggermeasure(i1pro *p, int delay) {
+ i1proimp *m = (i1proimp *)p->m;
+ int rv = I1PRO_OK;
+
+ a1logd(p->log,2,"i1pro_triggermeasure: trigger after %dmsec delay @ %d msec\n",
+ delay, msec_time() - m->msec);
+
+ /* NOTE := would be better here to create thread once, and then trigger it */
+ /* using a condition variable. */
+ if (m->trig_thread != NULL)
+ m->trig_thread->del(m->trig_thread);
+
+ m->tr_t1 = m->tr_t2 = m->tr_t3 = m->tr_t4 = m->tr_t5 = m->tr_t6 = m->tr_t7 = 0;
+ m->trig_delay = delay;
+
+ if ((m->trig_thread = new_athread(i1pro_delayed_trigger, (void *)p)) == NULL) {
+ a1logd(p->log,1,"i1pro_triggermeasure: creating delayed trigger thread failed\n");
+ return I1PRO_INT_THREADFAILED;
+ }
+
+#ifdef WAIT_FOR_DELAY_TRIGGER /* hack to diagnose threading problems */
+ while (m->tr_t2 == 0) {
+ Sleep(1);
+ }
+#endif
+ a1logd(p->log,2,"i1pro_triggermeasure: scheduled triggering OK\n");
+
+ return rv;
+}
+
+/* Read a measurements results. */
+/* A buffer full of bytes is returned. */
+/* (This will fail on a Rev. A if there is more than about a 40 msec delay */
+/* between triggering the measurement and starting this read. */
+/* It appears though that the read can be pending before triggering though. */
+/* Scan reads will also terminate if there is too great a delay beteween each read.) */
+i1pro_code
+i1pro_readmeasurement(
+ i1pro *p,
+ int inummeas, /* Initial number of measurements to expect */
+ int scanflag, /* NZ if in scan mode to continue reading */
+ unsigned char *buf, /* Where to read it to */
+ int bsize, /* Bytes available in buffer */
+ int *nummeas, /* Return number of readings measured */
+ i1p_mmodif mmodif /* Measurement modifier enum */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char *ibuf = buf; /* Incoming buffer */
+ int nmeas; /* Number of measurements for this read */
+ double top, extra; /* Time out period */
+ int rwbytes; /* Data bytes read or written */
+ int se, rv = I1PRO_OK;
+ int treadings = 0;
+ int stime = 0;
+// int gotshort = 0; /* nz when got a previous short reading */
+
+ if ((bsize % (m->nsen * 2)) != 0) {
+ return I1PRO_INT_ODDREADBUF;
+ }
+
+ a1logd(p->log,2,"i1pro_readmeasurement: inummeas %d, scanflag %d, address %p bsize 0x%x "
+ "@ %d msec\n",inummeas, scanflag, buf, bsize, (stime = msec_time()) - m->msec);
+
+ extra = 2.0; /* Extra timeout margin */
+
+ /* Deal with Rev A+ & Rev B quirk: */
+ if ((m->fwrev >= 200 && m->fwrev < 300)
+ || (m->fwrev >= 300 && m->fwrev < 400))
+ extra += m->l_inttime;
+ m->l_inttime = m->c_inttime;
+
+#ifdef SINGLE_READ
+ if (scanflag == 0)
+ nmeas = inummeas;
+ else
+ nmeas = bsize / (m->nsen * 2); /* Use a single large read */
+#else
+ nmeas = inummeas; /* Smaller initial number of measurements */
+#endif
+
+ top = extra + m->c_inttime * nmeas;
+ if ((m->c_measmodeflags & I1PRO_MMF_NOLAMP) == 0) /* Lamp is on */
+ top += m->c_lamptime;
+
+ /* NOTE :- for a scan on Rev. A, if we don't read fast enough the Eye-One will */
+ /* assume it should stop sending, even though the user has the switch pressed. */
+ /* For the rev A, this is quite a small margin (aprox. 1 msec ?) */
+ /* The Rev D has a lot more buffering, and is quite robust. */
+ /* By using the delayed trigger and a single read, this problem is usually */
+ /* eliminated. */
+ /* An unexpected short read seems to lock the instrument up. Not currently */
+ /* sure what sequence would recover it for a retry of the read. */
+ for (;;) {
+ int size; /* number of bytes to read */
+
+ size = m->nsen * 2 * nmeas;
+
+ if (size > bsize) { /* oops, no room for read */
+ a1logd(p->log,1,"i1pro_readmeasurement: buffer was too short for scan\n");
+ return I1PRO_INT_MEASBUFFTOOSMALL;
+ }
+
+ m->tr_t6 = msec_time(); /* Diagnostic, start of subsequent reads */
+ if (m->tr_t3 == 0) m->tr_t3 = m->tr_t6; /* Diagnostic, start of first read */
+
+ se = p->icom->usb_read(p->icom, NULL, 0x82, buf, size, &rwbytes, top);
+
+ m->tr_t5 = m->tr_t7;
+ m->tr_t7 = msec_time(); /* Diagnostic, end of subsequent reads */
+ if (m->tr_t4 == 0) {
+ m->tr_t5 = m->tr_t2;
+ m->tr_t4 = m->tr_t7; /* Diagnostic, end of first read */
+ }
+
+#ifdef NEVER /* Use short + timeout to terminate scan */
+ if (gotshort != 0 && se == ICOM_TO) { /* We got a timeout after a short read. */
+ a1logd(p->log,2,"i1pro_readmeasurement: timed out in %f secs after getting short read\n",top);
+ a1logd(p->log,2,"i1pro_readmeasurement: trig & rd times %d %d %d %d)\n",
+ m->tr_t2-m->tr_t1, m->tr_t3-m->tr_t2, m->tr_t4-m->tr_t3, m->tr_t6-m->tr_t5);
+ break; /* We're done */
+ } else
+#endif
+ if (se == ICOM_SHORT) { /* Expect this to terminate scan reading */
+ a1logd(p->log,2,"i1pro_readmeasurement: short read, read %d bytes, asked for %d\n",
+ rwbytes,size);
+ a1logd(p->log,2,"i1pro_readmeasurement: trig & rd times %d %d %d %d)\n",
+ m->tr_t2-m->tr_t1, m->tr_t3-m->tr_t2, m->tr_t4-m->tr_t3, m->tr_t6-m->tr_t5);
+ } else if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ if (m->trig_rv != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_readmeasurement: trigger failed, ICOM err 0x%x\n",
+ m->trig_se);
+ return m->trig_rv;
+ }
+ if (se & ICOM_TO)
+ a1logd(p->log,1,"i1pro_readmeasurement: timed out with top = %f\n",top);
+ a1logd(p->log,1,"i1pro_readmeasurement: failed, bytes read 0x%x, ICOM err 0x%x\n",
+ rwbytes, se);
+ return rv;
+ }
+
+ /* If we didn't read a multiple of m->nsen * 2, we've got problems */
+ if ((rwbytes % (m->nsen * 2)) != 0) {
+ a1logd(p->log,1,"i1pro_readmeasurement: read 0x%x bytes, odd read error\n",rwbytes);
+ return I1PRO_HW_ME_ODDREAD;
+ }
+
+ /* Track where we're up to */
+ bsize -= rwbytes;
+ buf += rwbytes;
+ treadings += rwbytes/(m->nsen * 2);
+
+ if (scanflag == 0) { /* Not scanning */
+
+ /* Expect to read exactly what we asked for */
+ if (rwbytes != size) {
+ a1logd(p->log,1,"i1pro_readmeasurement: unexpected short read, got %d expected %d\n"
+ ,rwbytes,size);
+ return I1PRO_HW_ME_SHORTREAD;
+ }
+ break; /* And we're done */
+ }
+
+#ifdef NEVER /* Use short + timeout to terminate scan */
+ /* We expect to get a short read at the end of a scan, */
+ /* or we might have the USB transfer truncated by somethinge else. */
+ /* Note the short read, and keep reading until we get a time out */
+ if (rwbytes != size) {
+ gotshort = 1;
+ } else {
+ gotshort = 0;
+ }
+#else /* Use short to terminate scan */
+ /* We're scanning and expect to get a short read at the end of the scan. */
+ if (rwbytes != size) {
+ break;
+ }
+#endif
+
+ if (bsize == 0) { /* oops, no room for more scanning read */
+ unsigned char tbuf[NSEN_MAX * 2];
+
+ /* We need to clean up, so soak up all the data and throw it away */
+ while ((se = p->icom->usb_read(p->icom, NULL, 0x82, tbuf, m->nsen * 2, &rwbytes, top)) == ICOM_OK)
+ ;
+ a1logd(p->log,1,"i1pro_readmeasurement: buffer was too short for scan\n");
+ return I1PRO_INT_MEASBUFFTOOSMALL;
+ }
+
+ /* Read a bunch more readings until the read is short or times out */
+ nmeas = bsize / (m->nsen * 2);
+ if (nmeas > 64)
+ nmeas = 64;
+ top = extra + m->c_inttime * nmeas;
+ }
+
+ if ((m->c_measmodeflags & I1PRO_MMF_NOLAMP) == 0) { /* Lamp was on for measurement */
+ m->slamponoff = m->llamponoff; /* remember second last */
+ m->llamponoff = msec_time(); /* Record when it turned off */
+// printf("~1 got lamp on -> off at %d (%f)\n",m->llamponoff, (m->llamponoff - m->llampoffon)/1000.0);
+ m->lampage += (m->llamponoff - m->llampoffon)/1000.0; /* Time lamp was on */
+ }
+ /* Update log values */
+ if (mmodif != i1p_dark_cal)
+ m->meascount++;
+
+ /* Must have timed out in initial readings */
+ if (treadings < inummeas) {
+ a1logd(p->log,1,"i1pro_readmeasurement: read failed, bytes read 0x%x, ICOM err 0x%x\n",
+ rwbytes, se);
+ return I1PRO_RD_SHORTMEAS;
+ }
+
+ if (p->log->debug >= 6) {
+ int i, size = treadings * m->nsen * 2;
+ char oline[100], *bp = oline;
+ for (i = 0; i < size; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp," %04x:",i);
+ bp += sprintf(bp," %02x",ibuf[i]);
+ if ((i+1) >= size || ((i+1) % 16) == 0) {
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,6,oline);
+ bp = oline;
+ }
+ }
+ }
+
+ a1logd(p->log,2,"i1pro_readmeasurement: read %d readings, ICOM err 0x%x (%d msec)\n",
+ treadings, se, msec_time()-stime);
+ a1logd(p->log,2,"i1pro_readmeasurement: (trig & rd times %d %d %d %d)\n",
+ m->tr_t2-m->tr_t1, m->tr_t3-m->tr_t2, m->tr_t4-m->tr_t3, m->tr_t6-m->tr_t5);
+
+ if (nummeas != NULL) *nummeas = treadings;
+
+ return rv;
+}
+
+/* Set the measurement clock mode */
+/* Firmware Version >= 301 only */
+i1pro_code
+i1pro_setmcmode(
+ i1pro *p,
+ int mcmode /* Measurement clock mode, 1..mxmcmode */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[1]; /* 1 bytes to write */
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ a1logd(p->log,2,"i1pro_setmcmode: mode %d @ %d msec\n",
+ mcmode, (stime = msec_time()) - m->msec);
+
+ pbuf[0] = mcmode;
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xCF, 0, 0, pbuf, 1, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_setmcmode: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ a1logd(p->log,2,"i1pro_setmcmode: done, ICOM err 0x%x (%d msec)\n",
+ se, msec_time()-stime);
+ return rv;
+}
+
+/* Get the current measurement clock mode */
+/* Return pointers may be NULL if not needed. */
+/* Firmware Version >= 301 only */
+i1pro_code
+i1pro_getmcmode(
+ i1pro *p,
+ int *maxmcmode, /* mcmode must be <= maxmcmode */
+ int *mcmode, /* readback current mcmode */
+ int *subclkdiv, /* Sub clock divider ratio */
+ int *intclkusec, /* Integration clock in usec */
+ int *subtmode /* Subtract mode on read using average of value 127 */
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[8]; /* status bytes read */
+ int _maxmcmode; /* mcmode must be < maxmcmode */
+ int _mcmode; /* readback current mcmode */
+ int _unknown; /* Unknown */
+ int _subclkdiv; /* Sub clock divider ratio */
+ int _intclkusec; /* Integration clock in usec */
+ int _subtmode; /* Subtract mode on read using average of value 127 */
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ a1logd(p->log,2,"i1pro_getmcmode: called @ %d msec\n",
+ (stime = msec_time()) - m->msec);
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD1, 0, 0, pbuf, 6, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_getmcmode: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _maxmcmode = pbuf[0];
+ _mcmode = pbuf[1];
+ _unknown = pbuf[2];
+ _subclkdiv = pbuf[3];
+ _intclkusec = pbuf[4];
+ _subtmode = pbuf[5];
+
+ a1logd(p->log,2,"i1pro_getmcmode: returns %d, %d, (%d), %d, %d 0x%x ICOM err 0x%x (%d msec)\n",
+ _maxmcmode, _mcmode, _unknown, _subclkdiv, _intclkusec, _subtmode, se, msec_time()-stime);
+
+ if (maxmcmode != NULL) *maxmcmode = _maxmcmode;
+ if (mcmode != NULL) *mcmode = _mcmode;
+ if (subclkdiv != NULL) *subclkdiv = _subclkdiv;
+ if (intclkusec != NULL) *intclkusec = _intclkusec;
+ if (subtmode != NULL) *subtmode = _subtmode;
+
+ return rv;
+}
+
+
+/* Wait for a reply triggered by an instrument switch press */
+i1pro_code i1pro_waitfor_switch(i1pro *p, double top) {
+ i1proimp *m = (i1proimp *)p->m;
+ int rwbytes; /* Data bytes read */
+ unsigned char buf[8]; /* Result */
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ a1logd(p->log,2,"i1pro_waitfor_switch: read 1 byte from switch hit port @ %d msec\n",
+ (stime = msec_time()) - m->msec);
+
+ /* Now read 1 byte */
+ se = p->icom->usb_read(p->icom, NULL, 0x84, buf, 1, &rwbytes, top);
+
+ if (se & ICOM_TO) {
+ a1logd(p->log,2,"i1pro_waitfor_switch: read 0x%x bytes, timed out (%d msec)\n",
+ rwbytes,msec_time()-stime);
+ return I1PRO_INT_BUTTONTIMEOUT;
+ }
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro_waitfor_switch: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ if (rwbytes != 1) {
+ a1logd(p->log,1,"i1pro_waitfor_switch: read 0x%x bytes, short read error (%d msec)\n",
+ rwbytes,msec_time()-stime);
+ return I1PRO_HW_SW_SHORTREAD;
+ }
+
+ a1logd(p->log,2,"i1pro_waitfor_switch: read 0x%x bytes value 0x%x ICOM err 0x%x (%d msec)\n",
+ rwbytes, buf[0], se, msec_time()-stime);
+
+ return rv;
+}
+
+/* Wait for a reply triggered by a key press (thread version) */
+/* Returns I1PRO_OK if the switch has been pressed, */
+/* or I1PRO_INT_BUTTONTIMEOUT if */
+/* no switch was pressed befor the time expired, */
+/* or some other error. */
+i1pro_code i1pro_waitfor_switch_th(i1pro *p, double top) {
+ i1proimp *m = (i1proimp *)p->m;
+ int rwbytes; /* Data bytes read */
+ unsigned char buf[8]; /* Result */
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ a1logd(p->log,2,"i1pro_waitfor_switch_th: read 1 byte from switch hit port @ %d msec\n",
+ (stime = msec_time()) - m->msec);
+
+ /* Now read 1 byte */
+ se = p->icom->usb_read(p->icom, &m->cancelt, 0x84, buf, 1, &rwbytes, top);
+
+ if (se & ICOM_TO) {
+ a1logd(p->log,2,"i1pro_waitfor_switch_th: read 0x%x bytes, timed out (%d msec)\n",
+ rwbytes,msec_time()-stime);
+ return I1PRO_INT_BUTTONTIMEOUT;
+ }
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_waitfor_switch_th: failed with ICOM err 0x%x (%d msec)\n",
+ se,msec_time()-stime);
+ return rv;
+ }
+
+ if (rwbytes != 1) {
+ a1logd(p->log,2,"i1pro_waitfor_switch_th: read 0x%x bytes, short read error (%d msec)\n",
+ rwbytes,msec_time()-stime);
+ return I1PRO_HW_SW_SHORTREAD;
+ }
+
+ a1logd(p->log,2,"i1pro_waitfor_switch_th: read 0x%x bytes value 0x%x ICOM err 0x%x (%d msec)\n",
+ rwbytes, buf[0], se,msec_time()-stime);
+
+ return rv;
+}
+
+/* Terminate switch handling */
+/* This seems to always return an error ? */
+i1pro_code
+i1pro_terminate_switch(
+ i1pro *p
+) {
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[8]; /* 8 bytes to write */
+ int se, rv = I1PRO_OK;
+
+ a1logd(p->log,2,"i1pro_terminate_switch: called\n");
+
+ /* These values may not be significant */
+ pbuf[0] = pbuf[1] = pbuf[2] = pbuf[3] = 0xff;
+ pbuf[4] = 0xfc;
+ pbuf[5] = 0xee;
+ pbuf[6] = 0x12;
+ pbuf[7] = 0x00;
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD0, 3, 0, pbuf, 8, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1pro_terminate_switch: Warning: Terminate Switch Handling failed with ICOM err 0x%x\n",se);
+ } else {
+ a1logd(p->log,2,"i1pro_terminate_switch: done, ICOM err 0x%x\n",se);
+ }
+
+ /* In case the above didn't work, cancel the I/O */
+ msec_sleep(50);
+ if (m->th_termed == 0) {
+ a1logd(p->log,3,"i1pro terminate switch thread failed, canceling I/O\n");
+ p->icom->usb_cancel_io(p->icom, &m->cancelt);
+ }
+
+ return rv;
+}
+
+/* ============================================================ */
+/* Low level i1pro2 (Rev E) commands */
+
+/* Get the EEProm size */
+i1pro_code
+i1pro2_geteesize(
+ i1pro *p,
+ int *eesize
+) {
+ int se, rv = I1PRO_OK;
+ unsigned char buf[4]; /* Result */
+ int _eesize = 0;
+
+ a1logd(p->log,2,"i1pro2_geteesize: called\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD9, 0, 0, buf, 4, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro2_geteesize: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _eesize = buf2int(buf);
+
+ a1logd(p->log,2,"i1pro2_geteesize: returning %d ICOM err 0x%x\n", _eesize, se);
+
+ if (eesize != NULL)
+ *eesize = _eesize;
+
+ return rv;
+}
+
+/* Get the Chip ID */
+/* This does actually work with the Rev D. */
+/* (It returns all zero's unless you've read the EEProm first !) */
+i1pro_code
+i1pro2_getchipid(
+ i1pro *p,
+ unsigned char chipid[8]
+) {
+ int se, rv = I1PRO_OK;
+
+ a1logd(p->log,2,"i1pro2_getchipid: called\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD2, 0, 0, chipid, 8, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro2_getchipid: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ a1logd(p->log,2,"i1pro2_getchipid: returning %02X-%02X%02X%02X%02X%02X%02X%02X ICOM err 0x%x\n",
+ chipid[0], chipid[1], chipid[2], chipid[3],
+ chipid[4], chipid[5], chipid[6], chipid[7], se);
+ return rv;
+}
+
+/* Get Rev E measure characteristics. */
+i1pro_code
+i1pro2_getmeaschar(
+ i1pro *p,
+ int *clkusec, /* Return integration clock length in usec ? (ie. 36) */
+ int *xraw, /* Return number of extra non-reading (dark) raw bands ? (ie. 6) */
+ int *nraw, /* Return number of reading raw bands ? (ie. 128) */
+ int *subdiv /* Sub divider and minium integration clocks ? (ie. 136) */
+) {
+ int se, rv = I1PRO_OK;
+ unsigned char buf[16]; /* Result */
+ int _clkusec;
+ int _xraw;
+ int _nraw;
+ int _subdiv;
+
+ a1logd(p->log,2,"i1pro2_getmeaschar: called\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD5, 0, 0, buf, 16, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro2_getmeaschar: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _clkusec = buf2int(buf + 0);
+ _xraw = buf2int(buf + 4);
+ _nraw = buf2int(buf + 8);
+ _subdiv = buf2int(buf + 12);
+
+ a1logd(p->log,2,"i1pro2_getmeaschar: returning clkusec %d, xraw %d, nraw %d, subdiv %d ICOM err 0x%x\n", _clkusec, _xraw, _nraw, _subdiv, se);
+
+ if (clkusec != NULL)
+ *clkusec = _clkusec;
+ if (xraw != NULL)
+ *xraw = _xraw;
+ if (nraw != NULL)
+ *nraw = _nraw;
+ if (subdiv != NULL)
+ *subdiv = _subdiv;
+
+ return rv;
+}
+
+/* Delayed trigger implementation, called from thread */
+/* We assume that the Rev E measurement parameters have been set in */
+/* the i1proimp structure c_* values */
+static int
+i1pro2_delayed_trigger(void *pp) {
+ i1pro *p = (i1pro *)pp;
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[14]; /* 14 bytes to write */
+ int se, rv = I1PRO_OK;
+ int stime = 0;
+
+ int2buf(pbuf + 0, m->c_intclocks);
+ int2buf(pbuf + 4, m->c_lampclocks);
+ int2buf(pbuf + 8, m->c_nummeas);
+ short2buf(pbuf + 12, m->c_measmodeflags2);
+
+ if ((m->c_measmodeflags & I1PRO_MMF_NOLAMP) == 0) { /* Lamp will be on for measurement */
+ m->llampoffon = msec_time(); /* Record when it turned on */
+ }
+
+ a1logd(p->log,2,"i1pro2_delayed_trigger: Rev E start sleep @ %d msec\n",
+ msec_time() - m->msec);
+
+ /* Delay the trigger */
+ msec_sleep(m->trig_delay);
+
+ m->tr_t1 = msec_time(); /* Diagnostic */
+
+ a1logd(p->log,2,"i1pro2_delayed_trigger: trigger Rev E @ %d msec\n",
+ (stime = msec_time()) - m->msec);
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD4, 0, 0, pbuf, 14, 2.0);
+
+ m->tr_t2 = msec_time(); /* Diagnostic */
+
+ m->trig_se = se;
+ m->trig_rv = icoms2i1pro_err(se);
+
+ a1logd(p->log,2,"i1pro2_delayed_trigger: done ICOM err 0x%x (%d msec)\n",
+ se,msec_time()-stime);
+ return 0;
+}
+
+/* Trigger a measurement after the nominated delay */
+/* The actual return code will be in m->trig_rv after the delay. */
+/* This allows us to start the measurement read before the trigger, */
+/* ensuring that process scheduling latency can't cause the read to fail. */
+i1pro_code
+i1pro2_triggermeasure(i1pro *p, int delay) {
+ i1proimp *m = (i1proimp *)p->m;
+ int rv = I1PRO_OK;
+
+ a1logd(p->log,2,"i1pro2_triggermeasure: triggering Rev Emeasurement after %dmsec "
+ "delay @ %d msec\n", delay, msec_time() - m->msec);
+
+ /* NOTE := would be better here to create thread once, and then trigger it */
+ /* using a condition variable. */
+ if (m->trig_thread != NULL)
+ m->trig_thread->del(m->trig_thread);
+
+ m->tr_t1 = m->tr_t2 = m->tr_t3 = m->tr_t4 = m->tr_t5 = m->tr_t6 = m->tr_t7 = 0;
+ m->trig_delay = delay;
+
+ if ((m->trig_thread = new_athread(i1pro2_delayed_trigger, (void *)p)) == NULL) {
+ a1logd(p->log,1,"i1pro2_triggermeasure: creating delayed trigger Rev E thread failed\n");
+ return I1PRO_INT_THREADFAILED;
+ }
+
+#ifdef WAIT_FOR_DELAY_TRIGGER /* hack to diagnose threading problems */
+ while (m->tr_t2 == 0) {
+ Sleep(1);
+ }
+#endif
+ a1logd(p->log,2,"i1pro2_triggermeasure: scheduled triggering Rev E OK\n");
+
+ return rv;
+}
+
+/* Get the UV before and after measurement voltage drop */
+i1pro_code
+i1pro2_getUVvolts(
+ i1pro *p,
+ int *before,
+ int *after
+) {
+ int se, rv = I1PRO_OK;
+ unsigned char buf[4]; /* Result */
+ int _before = 0;
+ int _after = 0;
+
+ a1logd(p->log,2,"i1pro2_getUVvolts: called\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD8, 0, 0, buf, 4, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro2_getUVvolts: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _before = buf2ushort(buf);
+ _after = buf2ushort(buf+2);
+
+ a1logd(p->log,2,"i1pro2_getUVvolts: returning %d, %d ICOM err 0x%x\n", _before, _after, se);
+
+ if (before != NULL)
+ *before = _before;
+
+ if (after != NULL)
+ *after = _after;
+
+ return rv;
+}
+
+/* Terminate Ruler tracking (???) */
+/* The parameter seems to be always 0 ? */
+static int
+i1pro2_stop_ruler(void *pp, int parm) {
+ i1pro *p = (i1pro *)pp;
+ i1proimp *m = (i1proimp *)p->m;
+ unsigned char pbuf[2]; /* 2 bytes to write */
+ int se, rv = I1PRO_OK;
+
+ short2buf(pbuf, parm);
+
+ a1logd(p->log,2,"i1pro2_stop_ruler: called with 0x%x\n", parm);
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD7, 0, 0, pbuf, 2, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro2_stop_ruler: failed with ICOM err 0x%x\n",rv);
+ return rv;
+ }
+
+ a1logd(p->log,2,"i1pro2_stop_ruler: returning ICOM err 0x%x\n",rv);
+
+ return rv;
+}
+
+ /* Send a raw indicator LED sequence. */
+/*
+ The byte sequence has the following format:
+ (all values are big endian)
+
+ XXXX Number of following blocks, BE.
+
+ Blocks are:
+
+ YYYY Number of bytes in the block
+ RRRR Number of repeats of the block, FFFFFFFF = infinite
+
+ A sequence of codes:
+
+ LL TTTT
+ L = Led mask:
+ 01 = Red Right
+ 02 = Green Right
+ 04 = Blue Right
+ 08 = Red Left
+ 10 = Green Left
+ 20 = Blue Left
+ TTT = clock count for this mask (ie. aprox. 73 usec clock period)
+ PWM typically alternates between on & off state with a period total of
+ 0x50 clocks = 170 Hz. 255 clocks would be 54 Hz.
+
+ */
+
+static int
+i1pro2_indLEDseq(void *pp, unsigned char *buf, int size) {
+ i1pro *p = (i1pro *)pp;
+ i1proimp *m = (i1proimp *)p->m;
+ int rwbytes; /* Data bytes written */
+ unsigned char pbuf[4]; /* Number of bytes being send */
+ int se, rv = I1PRO_OK;
+
+ int2buf(pbuf, size);
+
+ a1logd(p->log,2,"i1pro2_indLEDseq: length %d bytes\n", size);
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xD6, 0, 0, pbuf, 4, 2.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro2_indLEDseq: failed with ICOM err 0x%x\n",rv);
+ return rv;
+ }
+
+ a1logd(p->log,2,"i1pro2_geteesize: command got ICOM err 0x%x\n", se);
+
+ /* Now write the bytes */
+ se = p->icom->usb_write(p->icom, NULL, 0x03, buf, size, &rwbytes, 5.0);
+
+ if ((rv = icoms2i1pro_err(se)) != I1PRO_OK) {
+ a1logd(p->log,1,"i1pro2_indLEDseq: data write failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ if (rwbytes != size) {
+ a1logd(p->log,1,"i1pro2_indLEDseq: wrote 0x%x bytes, short write error\n",rwbytes);
+ return I1PRO_HW_LED_SHORTWRITE;
+ }
+
+ a1logd(p->log,2,"i1pro2_indLEDseq: wrote 0x%x bytes LED sequence, ICOM err 0x%x\n", size, rv);
+
+ return rv;
+}
+
+/* Turn indicator LEDs off */
+static int
+i1pro2_indLEDoff(void *pp) {
+ i1pro *p = (i1pro *)pp;
+ int rv = I1PRO_OK;
+ unsigned char seq[] = {
+ 0x00, 0x00, 0x00, 0x01,
+
+ 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x10
+ };
+
+ a1logd(p->log,2,"i1pro2_indLEDoff: called\n");
+ rv = i1pro2_indLEDseq(p, seq, sizeof(seq));
+ a1logd(p->log,2,"i1pro2_indLEDoff: returning ICOM err 0x%x\n",rv);
+
+ return rv;
+}
+
+#ifdef NEVER
+
+ // ~~99 play with LED settings
+ if (p->itype == instI1Pro2) {
+
+ // LED is capable of white and red
+
+ /* Turns it off */
+ unsigned char b1[] = {
+ 0x00, 0x00, 0x00, 0x01,
+
+ 0x00, 0x00, 0x00, 0x07,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x01
+ };
+
+ /* Makes it white */
+ unsigned char b2[] = {
+ 0x00, 0x00, 0x00, 0x02,
+
+ 0x00, 0x00, 0x00, 0x0a,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x36, 0x00,
+ 0x00, 0x00, 0x01,
+
+ 0x00, 0x00, 0x00, 0x0a,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x3f, 0x36, 0x40,
+ 0x00, 0x00, 0x01
+ };
+
+ /* Makes it pulsing white */
+ unsigned char b3[] = {
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x36, 0x40, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x08, 0xec, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x03, 0x00, 0x00, 0x50, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x50, 0x3f, 0x00, 0x03, 0x00,
+ 0x00, 0x4d, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x49, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x45, 0x3f, 0x00,
+ 0x03, 0x00, 0x00, 0x42, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x42, 0x3f, 0x00, 0x04, 0x00, 0x00, 0x4f,
+ 0x3f, 0x00, 0x04, 0x00, 0x00, 0x4d, 0x3f, 0x00, 0x04, 0x00, 0x00, 0x49, 0x3f, 0x00, 0x04, 0x00,
+ 0x00, 0x46, 0x3f, 0x00, 0x04, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x04, 0x00, 0x00, 0x41, 0x3f, 0x00,
+ 0x05, 0x00, 0x00, 0x4d, 0x3f, 0x00, 0x05, 0x00, 0x00, 0x49, 0x3f, 0x00, 0x05, 0x00, 0x00, 0x46,
+ 0x3f, 0x00, 0x05, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x06, 0x00, 0x00, 0x4d, 0x3f, 0x00, 0x06, 0x00,
+ 0x00, 0x4a, 0x3f, 0x00, 0x06, 0x00, 0x00, 0x47, 0x3f, 0x00, 0x06, 0x00, 0x00, 0x44, 0x3f, 0x00,
+ 0x06, 0x00, 0x00, 0x41, 0x3f, 0x00, 0x07, 0x00, 0x00, 0x49, 0x3f, 0x00, 0x07, 0x00, 0x00, 0x46,
+ 0x3f, 0x00, 0x07, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x3f, 0x00, 0x07, 0x00,
+ 0x00, 0x3e, 0x3f, 0x00, 0x08, 0x00, 0x00, 0x44, 0x3f, 0x00, 0x09, 0x00, 0x00, 0x4a, 0x3f, 0x00,
+ 0x09, 0x00, 0x00, 0x47, 0x3f, 0x00, 0x09, 0x00, 0x00, 0x44, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x49,
+ 0x3f, 0x00, 0x09, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x09, 0x00, 0x00, 0x3d, 0x3f, 0x00, 0x0b, 0x00,
+ 0x00, 0x48, 0x3f, 0x00, 0x0b, 0x00, 0x00, 0x45, 0x3f, 0x00, 0x0a, 0x00, 0x00, 0x3c, 0x3f, 0x00,
+ 0x0c, 0x00, 0x00, 0x46, 0x3f, 0x00, 0x0c, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x0d, 0x00, 0x00, 0x46,
+ 0x3f, 0x00, 0x0c, 0x00, 0x00, 0x3e, 0x3f, 0x00, 0x0c, 0x00, 0x00, 0x3c, 0x3f, 0x00, 0x0d, 0x00,
+ 0x00, 0x3f, 0x3f, 0x00, 0x0d, 0x00, 0x00, 0x3d, 0x3f, 0x00, 0x0e, 0x00, 0x00, 0x3f, 0x3f, 0x00,
+ 0x0e, 0x00, 0x00, 0x3d, 0x3f, 0x00, 0x0e, 0x00, 0x00, 0x3b, 0x3f, 0x00, 0x0f, 0x00, 0x00, 0x3d,
+ 0x3f, 0x00, 0x0e, 0x00, 0x00, 0x37, 0x3f, 0x00, 0x0f, 0x00, 0x00, 0x39, 0x3f, 0x00, 0x10, 0x00,
+ 0x00, 0x3b, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x40, 0x3f, 0x00, 0x10, 0x00, 0x00, 0x37, 0x3f, 0x00,
+ 0x13, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x13, 0x00, 0x00, 0x3d, 0x3f, 0x00, 0x11, 0x00, 0x00, 0x34,
+ 0x3f, 0x00, 0x12, 0x00, 0x00, 0x36, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x34, 0x3f, 0x00, 0x14, 0x00,
+ 0x00, 0x38, 0x3f, 0x00, 0x14, 0x00, 0x00, 0x36, 0x3f, 0x00, 0x17, 0x00, 0x00, 0x3c, 0x3f, 0x00,
+ 0x17, 0x00, 0x00, 0x3a, 0x3f, 0x00, 0x18, 0x00, 0x00, 0x3a, 0x3f, 0x00, 0x15, 0x00, 0x00, 0x31,
+ 0x3f, 0x00, 0x17, 0x00, 0x00, 0x34, 0x3f, 0x00, 0x16, 0x00, 0x00, 0x30, 0x3f, 0x00, 0x1a, 0x00,
+ 0x00, 0x37, 0x3f, 0x00, 0x1b, 0x00, 0x00, 0x37, 0x3f, 0x00, 0x18, 0x00, 0x00, 0x2f, 0x3f, 0x00,
+ 0x1c, 0x00, 0x00, 0x35, 0x3f, 0x00, 0x1c, 0x00, 0x00, 0x33, 0x3f, 0x00, 0x1c, 0x00, 0x00, 0x31,
+ 0x3f, 0x00, 0x1d, 0x00, 0x00, 0x31, 0x3f, 0x00, 0x1b, 0x00, 0x00, 0x2c, 0x3f, 0x00, 0x1c, 0x00,
+ 0x00, 0x2c, 0x3f, 0x00, 0x1d, 0x00, 0x00, 0x2c, 0x3f, 0x00, 0x1e, 0x00, 0x00, 0x2c, 0x3f, 0x00,
+ 0x1d, 0x00, 0x00, 0x29, 0x3f, 0x00, 0x1e, 0x00, 0x00, 0x29, 0x3f, 0x00, 0x23, 0x00, 0x00, 0x2e,
+ 0x3f, 0x00, 0x22, 0x00, 0x00, 0x2b, 0x3f, 0x00, 0x25, 0x00, 0x00, 0x2d, 0x3f, 0x00, 0x24, 0x00,
+ 0x00, 0x2a, 0x3f, 0x00, 0x22, 0x00, 0x00, 0x26, 0x3f, 0x00, 0x27, 0x00, 0x00, 0x2a, 0x3f, 0x00,
+ 0x22, 0x00, 0x00, 0x23, 0x3f, 0x00, 0x23, 0x00, 0x00, 0x23, 0x3f, 0x00, 0x2a, 0x00, 0x00, 0x28,
+ 0x3f, 0x00, 0x24, 0x00, 0x00, 0x21, 0x3f, 0x00, 0x29, 0x00, 0x00, 0x24, 0x3f, 0x00, 0x2c, 0x00,
+ 0x00, 0x25, 0x3f, 0x00, 0x28, 0x00, 0x00, 0x20, 0x3f, 0x00, 0x2b, 0x00, 0x00, 0x21, 0x3f, 0x00,
+ 0x2d, 0x00, 0x00, 0x21, 0x3f, 0x00, 0x2b, 0x00, 0x00, 0x1e, 0x3f, 0x00, 0x2a, 0x00, 0x00, 0x1c,
+ 0x3f, 0x00, 0x2f, 0x00, 0x00, 0x1e, 0x3f, 0x00, 0x2b, 0x00, 0x00, 0x1a, 0x3f, 0x00, 0x2d, 0x00,
+ 0x00, 0x1a, 0x3f, 0x00, 0x31, 0x00, 0x00, 0x1b, 0x3f, 0x00, 0x2e, 0x00, 0x00, 0x18, 0x3f, 0x00,
+ 0x37, 0x00, 0x00, 0x1b, 0x3f, 0x00, 0x38, 0x00, 0x00, 0x1a, 0x3f, 0x00, 0x37, 0x00, 0x00, 0x18,
+ 0x3f, 0x00, 0x31, 0x00, 0x00, 0x14, 0x3f, 0x00, 0x39, 0x00, 0x00, 0x16, 0x3f, 0x00, 0x3d, 0x00,
+ 0x00, 0x16, 0x3f, 0x00, 0x36, 0x00, 0x00, 0x12, 0x3f, 0x00, 0x3a, 0x00, 0x00, 0x12, 0x3f, 0x00,
+ 0x3b, 0x00, 0x00, 0x11, 0x3f, 0x00, 0x40, 0x00, 0x00, 0x11, 0x3f, 0x00, 0x3a, 0x00, 0x00, 0x0e,
+ 0x3f, 0x00, 0x3b, 0x00, 0x00, 0x0d, 0x3f, 0x00, 0x3c, 0x00, 0x00, 0x0c, 0x3f, 0x00, 0x3d, 0x00,
+ 0x00, 0x0b, 0x3f, 0x00, 0x3e, 0x00, 0x00, 0x0a, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x09, 0x3f, 0x00,
+ 0x40, 0x00, 0x00, 0x08, 0x3f, 0x00, 0x42, 0x00, 0x00, 0x07, 0x3f, 0x00, 0x44, 0x00, 0x00, 0x06,
+ 0x3f, 0x00, 0x47, 0x00, 0x00, 0x05, 0x3f, 0x00, 0x4b, 0x00, 0x00, 0x04, 0x3f, 0x00, 0x50, 0x00,
+ 0x00, 0x03, 0x3f, 0x00, 0x44, 0x00, 0x00, 0x01, 0x3f, 0x00, 0x45, 0x3f, 0x00, 0x45, 0x3f, 0x00,
+ 0x45, 0x3f, 0x00, 0x45, 0x3f, 0x00, 0x44, 0x00, 0x00, 0x01, 0x3f, 0x00, 0x50, 0x00, 0x00, 0x03,
+ 0x3f, 0x00, 0x4b, 0x00, 0x00, 0x04, 0x3f, 0x00, 0x47, 0x00, 0x00, 0x05, 0x3f, 0x00, 0x44, 0x00,
+ 0x00, 0x06, 0x3f, 0x00, 0x42, 0x00, 0x00, 0x07, 0x3f, 0x00, 0x40, 0x00, 0x00, 0x08, 0x3f, 0x00,
+ 0x3f, 0x00, 0x00, 0x09, 0x3f, 0x00, 0x3e, 0x00, 0x00, 0x0a, 0x3f, 0x00, 0x3d, 0x00, 0x00, 0x0b,
+ 0x3f, 0x00, 0x3c, 0x00, 0x00, 0x0c, 0x3f, 0x00, 0x3b, 0x00, 0x00, 0x0d, 0x3f, 0x00, 0x3a, 0x00,
+ 0x00, 0x0e, 0x3f, 0x00, 0x40, 0x00, 0x00, 0x11, 0x3f, 0x00, 0x3b, 0x00, 0x00, 0x11, 0x3f, 0x00,
+ 0x3a, 0x00, 0x00, 0x12, 0x3f, 0x00, 0x36, 0x00, 0x00, 0x12, 0x3f, 0x00, 0x3d, 0x00, 0x00, 0x16,
+ 0x3f, 0x00, 0x39, 0x00, 0x00, 0x16, 0x3f, 0x00, 0x31, 0x00, 0x00, 0x14, 0x3f, 0x00, 0x37, 0x00,
+ 0x00, 0x18, 0x3f, 0x00, 0x38, 0x00, 0x00, 0x1a, 0x3f, 0x00, 0x37, 0x00, 0x00, 0x1b, 0x3f, 0x00,
+ 0x2e, 0x00, 0x00, 0x18, 0x3f, 0x00, 0x31, 0x00, 0x00, 0x1b, 0x3f, 0x00, 0x2d, 0x00, 0x00, 0x1a,
+ 0x3f, 0x00, 0x2b, 0x00, 0x00, 0x1a, 0x3f, 0x00, 0x2f, 0x00, 0x00, 0x1e, 0x3f, 0x00, 0x2a, 0x00,
+ 0x00, 0x1c, 0x3f, 0x00, 0x2b, 0x00, 0x00, 0x1e, 0x3f, 0x00, 0x2d, 0x00, 0x00, 0x21, 0x3f, 0x00,
+ 0x2b, 0x00, 0x00, 0x21, 0x3f, 0x00, 0x28, 0x00, 0x00, 0x20, 0x3f, 0x00, 0x2c, 0x00, 0x00, 0x25,
+ 0x3f, 0x00, 0x29, 0x00, 0x00, 0x24, 0x3f, 0x00, 0x24, 0x00, 0x00, 0x21, 0x3f, 0x00, 0x2a, 0x00,
+ 0x00, 0x28, 0x3f, 0x00, 0x23, 0x00, 0x00, 0x23, 0x3f, 0x00, 0x22, 0x00, 0x00, 0x23, 0x3f, 0x00,
+ 0x27, 0x00, 0x00, 0x2a, 0x3f, 0x00, 0x22, 0x00, 0x00, 0x26, 0x3f, 0x00, 0x24, 0x00, 0x00, 0x2a,
+ 0x3f, 0x00, 0x25, 0x00, 0x00, 0x2d, 0x3f, 0x00, 0x22, 0x00, 0x00, 0x2b, 0x3f, 0x00, 0x23, 0x00,
+ 0x00, 0x2e, 0x3f, 0x00, 0x1e, 0x00, 0x00, 0x29, 0x3f, 0x00, 0x1d, 0x00, 0x00, 0x29, 0x3f, 0x00,
+ 0x1e, 0x00, 0x00, 0x2c, 0x3f, 0x00, 0x1d, 0x00, 0x00, 0x2c, 0x3f, 0x00, 0x1c, 0x00, 0x00, 0x2c,
+ 0x3f, 0x00, 0x1b, 0x00, 0x00, 0x2c, 0x3f, 0x00, 0x1d, 0x00, 0x00, 0x31, 0x3f, 0x00, 0x1c, 0x00,
+ 0x00, 0x31, 0x3f, 0x00, 0x1c, 0x00, 0x00, 0x33, 0x3f, 0x00, 0x1c, 0x00, 0x00, 0x35, 0x3f, 0x00,
+ 0x18, 0x00, 0x00, 0x2f, 0x3f, 0x00, 0x1b, 0x00, 0x00, 0x37, 0x3f, 0x00, 0x1a, 0x00, 0x00, 0x37,
+ 0x3f, 0x00, 0x16, 0x00, 0x00, 0x30, 0x3f, 0x00, 0x17, 0x00, 0x00, 0x34, 0x3f, 0x00, 0x15, 0x00,
+ 0x00, 0x31, 0x3f, 0x00, 0x18, 0x00, 0x00, 0x3a, 0x3f, 0x00, 0x17, 0x00, 0x00, 0x3a, 0x3f, 0x00,
+ 0x17, 0x00, 0x00, 0x3c, 0x3f, 0x00, 0x14, 0x00, 0x00, 0x36, 0x3f, 0x00, 0x14, 0x00, 0x00, 0x38,
+ 0x3f, 0x00, 0x12, 0x00, 0x00, 0x34, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x36, 0x3f, 0x00, 0x11, 0x00,
+ 0x00, 0x34, 0x3f, 0x00, 0x13, 0x00, 0x00, 0x3d, 0x3f, 0x00, 0x13, 0x00, 0x00, 0x3f, 0x3f, 0x00,
+ 0x10, 0x00, 0x00, 0x37, 0x3f, 0x00, 0x12, 0x00, 0x00, 0x40, 0x3f, 0x00, 0x10, 0x00, 0x00, 0x3b,
+ 0x3f, 0x00, 0x0f, 0x00, 0x00, 0x39, 0x3f, 0x00, 0x0e, 0x00, 0x00, 0x37, 0x3f, 0x00, 0x0f, 0x00,
+ 0x00, 0x3d, 0x3f, 0x00, 0x0e, 0x00, 0x00, 0x3b, 0x3f, 0x00, 0x0e, 0x00, 0x00, 0x3d, 0x3f, 0x00,
+ 0x0e, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x0d, 0x00, 0x00, 0x3d, 0x3f, 0x00, 0x0d, 0x00, 0x00, 0x3f,
+ 0x3f, 0x00, 0x0c, 0x00, 0x00, 0x3c, 0x3f, 0x00, 0x0c, 0x00, 0x00, 0x3e, 0x3f, 0x00, 0x0d, 0x00,
+ 0x00, 0x46, 0x3f, 0x00, 0x0c, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x0c, 0x00, 0x00, 0x46, 0x3f, 0x00,
+ 0x0a, 0x00, 0x00, 0x3c, 0x3f, 0x00, 0x0b, 0x00, 0x00, 0x45, 0x3f, 0x00, 0x0b, 0x00, 0x00, 0x48,
+ 0x3f, 0x00, 0x09, 0x00, 0x00, 0x3d, 0x3f, 0x00, 0x09, 0x00, 0x00, 0x3f, 0x3f, 0x00, 0x0a, 0x00,
+ 0x00, 0x49, 0x3f, 0x00, 0x09, 0x00, 0x00, 0x44, 0x3f, 0x00, 0x09, 0x00, 0x00, 0x47, 0x3f, 0x00,
+ 0x09, 0x00, 0x00, 0x4a, 0x3f, 0x00, 0x08, 0x00, 0x00, 0x44, 0x3f, 0x00, 0x07, 0x00, 0x00, 0x3e,
+ 0x3f, 0x00, 0x08, 0x00, 0x00, 0x4a, 0x3f, 0x00, 0x07, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x07, 0x00,
+ 0x00, 0x46, 0x3f, 0x00, 0x07, 0x00, 0x00, 0x49, 0x3f, 0x00, 0x06, 0x00, 0x00, 0x41, 0x3f, 0x00,
+ 0x06, 0x00, 0x00, 0x44, 0x3f, 0x00, 0x06, 0x00, 0x00, 0x47, 0x3f, 0x00, 0x06, 0x00, 0x00, 0x4a,
+ 0x3f, 0x00, 0x06, 0x00, 0x00, 0x4d, 0x3f, 0x00, 0x05, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x05, 0x00,
+ 0x00, 0x46, 0x3f, 0x00, 0x05, 0x00, 0x00, 0x49, 0x3f, 0x00, 0x05, 0x00, 0x00, 0x4d, 0x3f, 0x00,
+ 0x04, 0x00, 0x00, 0x41, 0x3f, 0x00, 0x04, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x04, 0x00, 0x00, 0x46,
+ 0x3f, 0x00, 0x04, 0x00, 0x00, 0x49, 0x3f, 0x00, 0x04, 0x00, 0x00, 0x4d, 0x3f, 0x00, 0x04, 0x00,
+ 0x00, 0x4f, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x42, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x42, 0x3f, 0x00,
+ 0x03, 0x00, 0x00, 0x45, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x49, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x4d,
+ 0x3f, 0x00, 0x03, 0x00, 0x00, 0x50, 0x3f, 0x00, 0x03, 0x00, 0x00, 0x50, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00,
+ 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43,
+ 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00, 0x00, 0x43, 0x3f, 0x00, 0x02, 0x00,
+ 0x00, 0x43
+ };
+
+ unsigned char b4[] = {
+ 0x00, 0x00, 0x00, 0x01, // blocks
+
+ 0x00, 0x00, 0x00, 0x0a, // bytes
+ 0x00, 0x00, 0x00, 0x04, // repeat
+// 0xff, 0xff, 0xff, 0xff, // repeat
+// 0x3f, 0x00, 0x04, // Level ????
+// 0x00, 0x00, 0x3c // msec ????
+ 0x3f, 0x20, 0x00, // "
+ 0x00, 0x20, 0x00 // LED mask + clocks
+ };
+
+ printf("~1 send led sequence length %d\n",sizeof(b4));
+ if ((ev = i1pro2_indLEDseq(p, b4, sizeof(b4))) != I1PRO_OK)
+ return ev;
+ }
+#endif /* NEVER */
+
+/* ============================================================ */
+/* key/value dictionary support for EEProm contents */
+
+/* Search the linked list for the given key */
+/* Return NULL if not found */
+static i1keyv *i1data_find_key(i1data *d, i1key key) {
+ i1keyv *k;
+
+ for (k = d->head; k != NULL; k = k->next) {
+ if (k->key == key)
+ return k;
+ }
+ return NULL;
+}
+
+/* Search the linked list for the given key and */
+/* return it, or add it to the list if it doesn't exist. */
+/* Return NULL on error */
+static i1keyv *i1data_make_key(i1data *d, i1key key) {
+ i1keyv *k;
+
+ for (k = d->head; k != NULL; k = k->next)
+ if (k->key == key)
+ return k;
+
+ if ((k = (i1keyv *)calloc(1, sizeof(i1keyv))) == NULL) {
+ a1logw(d->log, "i1data: malloc failed!\n");
+ return NULL;
+ }
+
+ k->key = key;
+ k->next = NULL;
+ if (d->last == NULL) {
+ d->head = d->last = k;
+ } else {
+ d->last->next = k;
+ d->last = k;
+ }
+ return k;
+}
+
+/* Return type of data associated with key. Return i1_dtype_unknown if not found */
+static i1_dtype i1data_get_type(i1data *d, i1key key) {
+ i1keyv *k;
+
+ if ((k = d->find_key(d, key)) != NULL)
+ return k->type;
+ return i1_dtype_unknown;
+}
+
+/* Return the number of data items in a keyv. Return 0 if not found */
+static unsigned int i1data_get_count(i1data *d, i1key key) {
+ i1keyv *k;
+
+ if ((k = d->find_key(d, key)) != NULL)
+ return k->count;
+ return 0;
+}
+
+/* Return a pointer to the short data for the key. */
+/* Return NULL if not found or wrong type */
+static int *i1data_get_shorts(i1data *d, unsigned int *count, i1key key) {
+ i1keyv *k;
+
+ if ((k = d->find_key(d, key)) == NULL)
+ return NULL;
+
+ if (k->type != i1_dtype_short)
+ return NULL;
+
+ if (count != NULL)
+ *count = k->count;
+
+ return (int *)k->data;
+}
+
+/* Return a pointer to the int data for the key. */
+/* Return NULL if not found or wrong type */
+static int *i1data_get_ints(i1data *d, unsigned int *count, i1key key) {
+ i1keyv *k;
+
+ if ((k = d->find_key(d, key)) == NULL)
+ return NULL;
+
+ if (k->type != i1_dtype_int)
+ return NULL;
+
+ if (count != NULL)
+ *count = k->count;
+
+ return (int *)k->data;
+}
+
+/* Return a pointer to the double data for the key. */
+/* Return NULL if not found or wrong type */
+static double *i1data_get_doubles(i1data *d, unsigned int *count, i1key key) {
+ i1keyv *k;
+
+ if ((k = d->find_key(d, key)) == NULL)
+ return NULL;
+
+ if (k->type != i1_dtype_double)
+ return NULL;
+
+ if (count != NULL)
+ *count = k->count;
+
+ return (double *)k->data;
+}
+
+
+/* Return pointer to one of the int data for the key. */
+/* Return NULL if not found or wrong type or out of range index. */
+static int *i1data_get_int(i1data *d, i1key key, unsigned int index) {
+ i1keyv *k;
+
+ if ((k = d->find_key(d, key)) == NULL)
+ return NULL;
+
+ if (k->type != i1_dtype_int)
+ return NULL;
+
+ if (index >= k->count)
+ return NULL;
+
+ return ((int *)k->data) + index;
+}
+
+/* Return pointer to one of the double data for the key. */
+/* Return NULL if not found or wrong type or out of range index. */
+static double *i1data_get_double(i1data *d, i1key key, double *data, unsigned int index) {
+ i1keyv *k;
+
+ if ((k = d->find_key(d, key)) == NULL)
+ return NULL;
+
+ if (k->type != i1_dtype_double)
+ return NULL;
+
+ if (index >= k->count)
+ return NULL;
+
+ return ((double *)k->data) + index;
+}
+
+/* Un-serialize a char buffer into an i1key keyv */
+static i1pro_code i1data_unser_shorts(
+ i1data *d,
+ i1key key,
+ int addr,
+ unsigned char *buf,
+ unsigned int size
+) {
+ i1keyv *k;
+ int i, count;
+
+ count = size/2;
+
+ if (count == 0)
+ return I1PRO_DATA_COUNT;
+
+ if ((k = d->make_key(d, key)) == NULL)
+ return I1PRO_DATA_MAKE_KEY;
+
+ if (k->data != NULL)
+ free(k->data);
+
+ if ((k->data = (void *)malloc(sizeof(int) * count)) == NULL)
+ return I1PRO_DATA_MEMORY;
+
+ for (i = 0; i < count; i++, buf += 2) {
+ ((int *)k->data)[i] = buf2short(buf);
+ }
+
+ k->count = count;
+ k->size = size;
+ k->type = i1_dtype_short;
+ if (addr != -1)
+ k->addr = addr;
+
+ return I1PRO_OK;
+}
+
+/* Un-serialize a char buffer into an i1key keyv */
+static i1pro_code i1data_unser_ints(
+ i1data *d,
+ i1key key,
+ int addr,
+ unsigned char *buf,
+ unsigned int size
+) {
+ i1keyv *k;
+ int i, count;
+
+ count = size/4;
+
+ if (count == 0)
+ return I1PRO_DATA_COUNT;
+
+ if ((k = d->make_key(d, key)) == NULL)
+ return I1PRO_DATA_MAKE_KEY;
+
+ if (k->data != NULL)
+ free(k->data);
+
+ if ((k->data = (void *)malloc(sizeof(int) * count)) == NULL)
+ return I1PRO_DATA_MEMORY;
+
+ for (i = 0; i < count; i++, buf += 4) {
+ ((int *)k->data)[i] = buf2int(buf);
+ }
+
+ k->count = count;
+ k->size = size;
+ k->type = i1_dtype_int;
+ if (addr != -1)
+ k->addr = addr;
+
+ return I1PRO_OK;
+}
+
+/* Create an entry for an end of section marker */
+static i1pro_code i1data_add_eosmarker(
+ i1data *d,
+ i1key key, /* section number */
+ int addr
+) {
+ i1keyv *k;
+
+ if ((k = d->make_key(d, key)) == NULL)
+ return I1PRO_DATA_MAKE_KEY;
+
+ if (k->data != NULL) {
+ free(k->data);
+ k->data = NULL;
+ }
+
+ k->count = 0;
+ k->size = 0;
+ k->type = i1_dtype_section;
+ if (addr != -1)
+ k->addr = addr;
+
+ return I1PRO_OK;
+}
+
+/* Un-serialize a char buffer of floats into a double keyv */
+static i1pro_code i1data_unser_doubles(
+ i1data *d,
+ i1key key,
+ int addr,
+ unsigned char *buf,
+ unsigned int size
+) {
+ i1keyv *k;
+ int i, count;
+
+ count = size/4;
+
+ if (count == 0)
+ return I1PRO_DATA_COUNT;
+
+ if ((k = d->make_key(d, key)) == NULL)
+ return I1PRO_DATA_MAKE_KEY;
+
+ if (k->data != NULL)
+ free(k->data);
+
+ if ((k->data = (void *)malloc(sizeof(double) * count)) == NULL)
+ return I1PRO_DATA_MEMORY;
+
+ for (i = 0; i < count; i++, buf += 4) {
+ int val;
+ val = buf2int(buf);
+ ((double *)k->data)[i] = IEEE754todouble((unsigned int)val);
+ }
+
+ k->count = count;
+ k->size = size;
+ k->type = i1_dtype_double;
+ if (addr != -1)
+ k->addr = addr;
+
+ return I1PRO_OK;
+}
+
+
+/* Serialize an i1key keyv into a char buffer. Error if it is outside the buffer */
+static i1pro_code i1data_ser_ints(
+ i1data *d,
+ i1keyv *k,
+ unsigned char *buf,
+ unsigned int size
+) {
+ i1pro *p = d->p;
+ int i, len;
+
+ if (k->type != i1_dtype_int)
+ return I1PRO_DATA_WRONGTYPE;
+
+ len = k->count * 4;
+ if (len > k->size)
+ return I1PRO_DATA_BUFSIZE;
+
+ if (k->addr < 0 || k->addr >= size || (k->addr + k->size) > size)
+ return I1PRO_DATA_BUFSIZE;
+
+ buf += k->addr;
+ for (i = 0; i < k->count; i++, buf += 4) {
+ int2buf(buf, ((int *)k->data)[i]);
+ }
+
+ return I1PRO_OK;
+}
+
+/* Serialize a double keyv as floats into a char buffer. Error if the buf is not big enough */
+static i1pro_code i1data_ser_doubles(
+ i1data *d,
+ i1keyv *k,
+ unsigned char *buf,
+ unsigned int size
+) {
+ i1pro *p = d->p;
+ int i, len;
+
+ if (k->type != i1_dtype_double)
+ return I1PRO_DATA_WRONGTYPE;
+
+ len = k->count * 4;
+ if (len > k->size)
+ return I1PRO_DATA_BUFSIZE;
+
+ if (k->addr < 0 || k->addr >= size || (k->addr + k->size) > size)
+ return I1PRO_DATA_BUFSIZE;
+
+ buf += k->addr;
+ for (i = 0; i < k->count; i++, buf += 4) {
+ int2buf(buf, doubletoIEEE754(((double *)k->data)[i]));
+ }
+
+ return I1PRO_OK;
+}
+
+/* Copy an array full of ints to the key */
+/* Note the count must be the same as the existing key value, */
+/* since we are not prepared to re-allocate key/values within */
+/* the EEProm, or re-write the directory. */
+static i1pro_code i1data_add_ints(i1data *d, i1key key, int *data, unsigned int count) {
+ i1keyv *k;
+ int i;
+
+ if ((k = d->make_key(d, key)) == NULL)
+ return I1PRO_DATA_MAKE_KEY;
+
+ if (count != k->count)
+ return I1PRO_DATA_COUNT;
+
+ if (k->data != NULL)
+ free(k->data);
+
+ if ((k->data = (void *)malloc(sizeof(int) * count)) == NULL)
+ return I1PRO_DATA_MEMORY;
+
+ for (i = 0; i < count; i++) {
+ ((int *)k->data)[i] = data[i];
+ }
+
+ k->count = count;
+ k->type = i1_dtype_int;
+
+ return I1PRO_OK;
+}
+
+/* Copy an array full of doubles to the key */
+/* Note the count must be the same as the existing key value, */
+/* since we are not prepared to re-allocate key/values within */
+/* the EEProm, or re-write the directory. */
+static i1pro_code i1data_add_doubles(i1data *d, i1key key, double *data, unsigned int count) {
+ i1keyv *k;
+ int i;
+
+ if ((k = d->make_key(d, key)) == NULL)
+ return I1PRO_DATA_MAKE_KEY;
+
+ if (count != k->count)
+ return I1PRO_DATA_COUNT;
+
+ if (k->data != NULL)
+ free(k->data);
+
+ if ((k->data = (void *)malloc(sizeof(double) * count)) == NULL)
+ return I1PRO_DATA_MEMORY;
+
+ for (i = 0; i < count; i++) {
+ ((double *)k->data)[i] = data[i];
+ }
+
+ k->count = count;
+ k->type = i1_dtype_double;
+
+ return I1PRO_OK;
+}
+
+/* Initialise the data from the EEProm contents */
+static i1pro_code i1data_parse_eeprom(i1data *d, unsigned char *buf, unsigned int len, int extra) {
+ i1pro *p = d->p;
+ int rv = I1PRO_OK;
+ int dir = 0x1000; /* Location of key directory */
+ int block_id; /* Block id */
+ int nokeys;
+ i1key key, off, nkey = 0, noff = 0;
+ int size; /* size of key in bytes */
+ unsigned char *bp;
+ int i;
+
+ if (extra)
+ dir = 0x2000; /* Directory is at half way in i1pro2 2nd table */
+
+ a1logd(p->log,3,"i1pro_parse_eeprom called with %d bytes\n",len);
+
+ /* Room for minimum number of keys ? */
+ if ((dir + 300) > len)
+ return I1PRO_DATA_KEY_COUNT;
+
+ block_id = buf2ushort(buf + dir);
+ if ((extra == 0 && block_id != 1) /* Must be 1 for base data */
+ || (extra == 1 && block_id != 2)) /* Must be 2 for i1pro2 extra data*/
+ return I1PRO_DATA_KEY_CORRUPT;
+
+ nokeys = buf2ushort(buf + dir + 2); /* Bytes in key table */
+ if (nokeys < 300 || nokeys > 512)
+ return I1PRO_DATA_KEY_COUNT;
+
+ nokeys = (nokeys - 4)/6; /* Number of 6 byte entries */
+
+ a1logd(p->log,3,"%d key/values in EEProm table %d\n",nokeys, extra);
+
+ /* We need current and next value to figure data size out */
+ bp = buf + dir + 4;
+ key = buf2ushort(bp);
+ off = buf2int(bp+2);
+ bp += 6;
+ for (i = 0; i < nokeys; i++, bp += 6, key = nkey, off = noff) {
+ i1_dtype type;
+
+ if (i < (nokeys-1)) {
+ nkey = buf2ushort(bp);
+ noff = buf2int(bp+2);
+ }
+ size = noff - off;
+ if (size < 0)
+ size = 0;
+ type = d->det_type(d, key);
+
+ a1logd(p->log,3,"Table entry %d is Key 0x%04x, type %d addr 0x%x, size %d\n",
+ i,key,type,off,size);
+
+ /* Check data is within range */
+ if (off >= len || noff < off || noff > len) {
+ a1logd(p->log,3,"Key 0x%04x offset %d and length %d out of range\n",key,off,noff);
+ return I1PRO_DATA_KEY_MEMRANGE;
+ }
+
+ if (type == i1_dtype_unknown) {
+ if (d->log->debug >= 7) {
+ int i;
+ char oline[100], *bp = oline;
+ bp = oline;
+ a1logd(d->log,7,"Key 0x%04x is unknown type\n",key);
+ for (i = 0; i < size; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp," %04x:",i);
+ bp += sprintf(bp," %02x",buf[off + i]);
+ if ((i+1) >= size || ((i+1) % 16) == 0) {
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,7,oline);
+ bp = oline;
+ }
+ }
+ }
+ if (type == i1_dtype_unknown)
+ continue; /* Ignore it */
+ }
+ if (type == i1_dtype_section) {
+ if ((rv = i1data_add_eosmarker(d, key, off)) != I1PRO_OK) {
+ a1logd(p->log,3,"Key 0x%04x section marker failed with 0x%x\n",key,rv);
+ return rv;
+ }
+ continue;
+ }
+ if (i >= nokeys) {
+ a1logd(p->log,3,"Last key wasn't a section marker!\n");
+ return I1PRO_DATA_KEY_ENDMARK;
+ }
+ if (type == i1_dtype_short) {
+ if ((rv = i1data_unser_shorts(d, key, off, buf + off, size)) != I1PRO_OK) {
+ a1logd(p->log,3,"Key 0x%04x short unserialise failed with 0x%x\n",key,rv);
+ return rv;
+ }
+ } else if (type == i1_dtype_int) {
+ if ((rv = i1data_unser_ints(d, key, off, buf + off, size)) != I1PRO_OK) {
+ a1logd(p->log,3,"Key 0x%04x int unserialise failed with 0x%x\n",key,rv);
+ return rv;
+ }
+ } else if (type == i1_dtype_double) {
+ if ((rv = i1data_unser_doubles(d, key, off, buf + off, size)) != I1PRO_OK) {
+ a1logd(p->log,3,"Key 0x%04x double unserialise failed with 0x%x\n",key,rv);
+ return rv;
+ }
+ } else {
+ a1logd(p->log,3,"Key 0x%04x has type we can't handle!\n",key);
+ }
+ }
+
+ return I1PRO_OK;
+}
+
+/* Compute and set the checksum, then serialise all the keys up */
+/* to the first marker into a buffer, ready for writing back to */
+/* the EEProm. It is an error if this buffer is not located at */
+/* zero in the EEProm */
+static i1pro_code i1data_prep_section1(
+i1data *d,
+unsigned char **buf, /* return allocated buffer */
+unsigned int *len
+) {
+ i1pro *p = d->p;
+ i1proimp *m = d->m;
+ int chsum1, *chsum2;
+ i1keyv *k, *sk, *j;
+ i1pro_code ev = I1PRO_OK;
+
+ a1logd(p->log,5,"i1data_prep_section1 called\n");
+
+ /* Compute the checksum for the first copy of the log data */
+ chsum1 = m->data->checksum(m->data, 0);
+
+ /* Locate and then set the checksum */
+ if ((chsum2 = m->data->get_int(m->data, key_checksum, 0)) == NULL) {
+ a1logd(p->log,2,"i1data_prep_section1 failed to locate checksum\n");
+ return I1PRO_INT_PREP_LOG_DATA;
+ }
+ *chsum2 = chsum1;
+
+ /* Locate the first section marker */
+ for (sk = d->head; sk != NULL; sk = sk->next) {
+ if (sk->type == i1_dtype_section)
+ break;
+ }
+ if (sk == NULL) {
+ a1logd(p->log,2,"i1data_prep_section1 failed to find section marker\n");
+ return I1PRO_INT_PREP_LOG_DATA;
+ }
+
+ /* for each key up to the first section marker */
+ /* check it resides within that section, and doesn't */
+ /* overlap any other key. */
+ for (k = d->head; k != NULL; k = k->next) {
+ if (k->type == i1_dtype_section)
+ break;
+ if (k->addr < 0 || k->addr >= sk->addr || (k->addr + k->size) > sk->addr) {
+ a1logd(p->log,2,"i1data_prep_section1 found key outside section\n");
+ return I1PRO_INT_PREP_LOG_DATA;
+ }
+ for (j = k->next; j != NULL; j = j->next) {
+ if (j->type == i1_dtype_section)
+ break;
+ if ((j->addr >= k->addr && j->addr < (k->addr + k->size))
+ || ((j->addr + j->size) > k->addr && (j->addr + j->size) <= (k->addr + k->size))) {
+ a1logd(p->log,2,"i1data_prep_section1 found key overlap section, 0x%x %d and 0x%x %d\n",
+ k->addr, k->size, j->addr, j->size);
+ return I1PRO_INT_PREP_LOG_DATA;
+ }
+ }
+ }
+
+ /* Allocate the buffer for the data */
+ *len = sk->addr;
+ if ((*buf = (unsigned char *)calloc(sk->addr, sizeof(unsigned char))) == NULL) {
+ a1logw(p->log, "i1data: malloc failed!\n");
+ return I1PRO_INT_MALLOC;
+ }
+
+ /* Serialise it into the buffer */
+ for (k = d->head; k != NULL; k = k->next) {
+ if (k->type == i1_dtype_section)
+ break;
+ else if (k->type == i1_dtype_int) {
+ if ((ev = m->data->ser_ints(m->data, k, *buf, *len)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1data_prep_section1 serializing ints failed\n");
+ return ev;
+ }
+ } else if (k->type == i1_dtype_double) {
+ if ((ev = m->data->ser_doubles(m->data, k, *buf, *len)) != I1PRO_OK) {
+ a1logd(p->log,2,"i1data_prep_section1 serializing doubles failed\n");
+ return ev;
+ }
+ } else {
+ a1logd(p->log,2,"i1data_prep_section1 tried to serialise unknown type\n");
+ return I1PRO_INT_PREP_LOG_DATA;
+ }
+ }
+ a1logd(p->log,5,"a_prep_section1 done\n");
+ return ev;
+}
+
+
+/* Return the data type for the given key identifier */
+static i1_dtype i1data_det_type(i1data *d, i1key key) {
+
+ if (key < 0x100)
+ return i1_dtype_section;
+
+ switch(key) {
+ /* Log keys */
+ case key_meascount:
+ case key_meascount + 1000:
+ return i1_dtype_int;
+ case key_darkreading:
+ case key_darkreading + 1000:
+ return i1_dtype_int;
+ case key_whitereading:
+ case key_whitereading + 1000:
+ return i1_dtype_int;
+ case key_gainmode:
+ case key_gainmode + 1000:
+ return i1_dtype_int;
+ case key_inttime:
+ case key_inttime + 1000:
+ return i1_dtype_double;
+ case key_caldate:
+ case key_caldate + 1000:
+ return i1_dtype_int;
+ case key_calcount:
+ case key_calcount + 1000:
+ return i1_dtype_int;
+ case key_checksum:
+ case key_checksum + 1000:
+ return i1_dtype_int;
+ case key_rpinttime:
+ case key_rpinttime + 1000:
+ return i1_dtype_double;
+ case key_rpcount:
+ case key_rpcount + 1000:
+ return i1_dtype_int;
+ case key_acount:
+ case key_acount + 1000:
+ return i1_dtype_int;
+ case key_lampage:
+ case key_lampage + 1000:
+ return i1_dtype_double;
+
+
+ /* Intstrument calibration keys */
+ case key_ng_lin:
+ return i1_dtype_double;
+ case key_hg_lin:
+ return i1_dtype_double;
+ case key_min_int_time:
+ return i1_dtype_double;
+ case key_max_int_time:
+ return i1_dtype_double;
+ case key_mtx_index:
+ return i1_dtype_int;
+ case key_mtx_nocoef:
+ return i1_dtype_int;
+ case key_mtx_coef:
+ return i1_dtype_double;
+ case key_0bb9:
+ return i1_dtype_int;
+ case key_0bba:
+ return i1_dtype_int;
+ case key_white_ref:
+ return i1_dtype_double;
+ case key_emis_coef:
+ return i1_dtype_double;
+ case key_amb_coef:
+ return i1_dtype_double;
+ case key_0fa0:
+ return i1_dtype_int;
+ case key_0bbf:
+ return i1_dtype_int;
+ case key_cpldrev:
+ return i1_dtype_int;
+ case key_0bc1:
+ return i1_dtype_int;
+ case key_capabilities:
+ return i1_dtype_int;
+ case key_0bc3:
+ return i1_dtype_int;
+ case key_physfilt:
+ return i1_dtype_int;
+ case key_0bc5:
+ return i1_dtype_int;
+ case key_0bc6:
+ return i1_dtype_double;
+ case key_sens_target:
+ return i1_dtype_int;
+ case key_sens_dark:
+ return i1_dtype_int;
+ case key_ng_sens_sat:
+ return i1_dtype_int;
+ case key_hg_sens_sat:
+ return i1_dtype_int;
+ case key_serno:
+ return i1_dtype_int;
+ case key_dom:
+ return i1_dtype_int;
+ case key_hg_factor:
+ return i1_dtype_double;
+ default:
+ return i1_dtype_unknown;
+
+ /* i1pro2 keys */
+ case 0x2ee0:
+ return i1_dtype_unknown; // ~~
+ case 0x2ee1:
+ return i1_dtype_char;
+ case 0x2ee2:
+ return i1_dtype_int;
+ case 0x2ee3:
+ return i1_dtype_int;
+ case 0x2ee4:
+ return i1_dtype_unknown; // ~~
+
+ case 0x2eea:
+ return i1_dtype_int;
+ case 0x2eeb:
+ return i1_dtype_int;
+ case 0x2eec:
+ return i1_dtype_int;
+
+ case 0x2ef4:
+ return i1_dtype_double;
+ case 0x2ef5:
+ return i1_dtype_double;
+ case 0x2ef6:
+ return i1_dtype_double;
+ case 0x2ef9:
+ return i1_dtype_double;
+ case 0x2efa:
+ return i1_dtype_double;
+ case 0x2efe:
+ return i1_dtype_int;
+ case 0x2eff:
+ return i1_dtype_int;
+
+ case 0x2f08:
+ return i1_dtype_double;
+ case 0x2f09:
+ return i1_dtype_double;
+ case 0x2f12:
+ return i1_dtype_double;
+ case 0x2f13:
+ return i1_dtype_double;
+ case 0x2f14:
+ return i1_dtype_double;
+ case 0x2f15:
+ return i1_dtype_double;
+
+ case 0x2f44: /* Wavelength LED reference shape ? */
+ return i1_dtype_double;
+ case 0x2f45:
+ return i1_dtype_int;
+ case 0x2f46:
+ return i1_dtype_double;
+ case 0x2f4e:
+ return i1_dtype_double;
+ case 0x2f4f:
+ return i1_dtype_double;
+ case 0x2f50:
+ return i1_dtype_double;
+ case 0x2f58:
+ return i1_dtype_short; /* Stray light compensation table */
+ case 0x2f59:
+ return i1_dtype_double; /* Stray light scale factor ? */
+ case 0x2f62:
+ return i1_dtype_double;
+ case 0x2f63:
+ return i1_dtype_double;
+ case 0x2f6c:
+ return i1_dtype_double;
+ case 0x2f6d:
+ return i1_dtype_double;
+ case 0x2f6e:
+ return i1_dtype_double;
+ case 0x2f76:
+ return i1_dtype_double;
+ case 0x2f77:
+ return i1_dtype_double;
+
+ case 0x32c8:
+ return i1_dtype_int; // Date
+ case 0x32c9:
+ return i1_dtype_int; // Date
+ case 0x32ca:
+ return i1_dtype_unknown; // ~~
+
+ case 0x36b0:
+ return i1_dtype_int; // Date
+ case 0x36b1:
+ return i1_dtype_int; // Date
+ case 0x36b2:
+ return i1_dtype_unknown; // ~~
+
+ case 0x3a99:
+ return i1_dtype_unknown; // ~~
+ case 0x3a9a:
+ return i1_dtype_unknown; // ~~
+ case 0x3a9b:
+ return i1_dtype_unknown; // ~~
+ case 0x3a9c:
+ return i1_dtype_unknown; // ~~
+ case 0x3a9d:
+ return i1_dtype_unknown; // ~~
+
+ case 0x3e81:
+ return i1_dtype_char; // "X-Rite"
+ case 0x3e82:
+ return i1_dtype_unknown; // ~~
+ case 0x3e8a:
+ return i1_dtype_unknown; // ~~
+
+ case 0x3e94:
+ return i1_dtype_unknown; // ~~
+
+ }
+ return i1_dtype_unknown;
+}
+
+/* Given an index starting at 0, return the matching key code */
+/* for keys that get checksummed. Return 0 if outside range. */
+static i1key i1data_chsum_keys(
+ i1data *d,
+ int index
+) {
+ switch(index) {
+ case 0:
+ return key_meascount;
+ case 1:
+ return key_darkreading;
+ case 2:
+ return key_whitereading;
+ case 3:
+ return key_gainmode;
+ case 4:
+ return key_inttime;
+ case 5:
+ return key_caldate;
+ case 6:
+ return key_calcount;
+ case 7:
+ return key_rpinttime;
+ case 8:
+ return key_rpcount;
+ case 9:
+ return key_acount;
+ case 10:
+ return key_lampage;
+ }
+ return 0;
+}
+
+/* Compute a checksum. */
+static int i1data_checksum(
+ i1data *d,
+ i1key keyoffset /* Offset to apply to keys */
+) {
+ int i, n, j;
+ int chsum = 0;
+
+ for (i = 0; ; i++) {
+ i1key key;
+ i1keyv *k;
+
+ if ((key = d->chsum_keys(d, i)) == 0)
+ break; /* we're done */
+
+ key += keyoffset;
+
+ if ((k = d->find_key(d, key)) == NULL)
+ continue; /* Hmm */
+
+ if (k->type == i1_dtype_int) {
+ for (j = 0; j < k->count; j++)
+ chsum += ((int *)k->data)[j];
+ } else if (k->type == i1_dtype_double) {
+ for (j = 0; j < k->count; j++)
+ chsum += doubletoIEEE754(((double *)k->data)[j]);
+ }
+ }
+
+ return chsum;
+}
+
+/* Destroy ourselves */
+static void i1data_del(i1data *d) {
+ i1keyv *k, *nk;
+
+ del_a1log(d->log); /* Unref it */
+
+ /* Free all the keys and their data */
+ for (k = d->head; k != NULL; k = nk) {
+ nk = k->next;
+ if (k->data != NULL)
+ free(k->data);
+ free(k);
+ }
+ free(d);
+}
+
+/* Constructor for i1data */
+i1data *new_i1data(i1proimp *m) {
+ i1data *d;
+ if ((d = (i1data *)calloc(1, sizeof(i1data))) == NULL) {
+ a1loge(m->p->log, 1, "new_i1data: malloc failed!\n");
+ return NULL;
+ }
+
+ d->p = m->p;
+ d->m = m;
+
+ d->log = new_a1log_d(m->p->log); /* Take reference */
+
+ d->find_key = i1data_find_key;
+ d->make_key = i1data_make_key;
+ d->get_type = i1data_get_type;
+ d->get_count = i1data_get_count;
+ d->get_shorts = i1data_get_shorts;
+ d->get_ints = i1data_get_ints;
+ d->get_doubles = i1data_get_doubles;
+ d->get_int = i1data_get_int;
+ d->get_double = i1data_get_double;
+ d->unser_ints = i1data_unser_ints;
+ d->unser_doubles = i1data_unser_doubles;
+ d->ser_ints = i1data_ser_ints;
+ d->ser_doubles = i1data_ser_doubles;
+ d->parse_eeprom = i1data_parse_eeprom;
+ d->prep_section1 = i1data_prep_section1;
+ d->add_ints = i1data_add_ints;
+ d->add_doubles = i1data_add_doubles;
+ d->del = i1data_del;
+
+ d->det_type = i1data_det_type;
+ d->chsum_keys = i1data_chsum_keys;
+ d->checksum = i1data_checksum;
+
+ return d;
+}
+
+/* ----------------------------------------------------------------- */
diff --git a/spectro/i1pro_imp.h b/spectro/i1pro_imp.h
new file mode 100644
index 0000000..64296b2
--- /dev/null
+++ b/spectro/i1pro_imp.h
@@ -0,0 +1,1376 @@
+#ifndef I1PRO_IMP_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag i1Pro implementation defines
+ *
+ * Author: Graeme W. Gill
+ * Date: 20/12/2006
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+/* Implementation resources for i1pro driver */
+
+/* -------------------------------------------------- */
+/* Implementation class */
+
+typedef int i1pro_code; /* Type to use for error codes */
+
+/* I1PRO mode state. This is implementation data that */
+/* depends on the mode the instrument is in. */
+/* Each mode has a separate calibration, and configured instrument state. */
+
+typedef enum {
+ i1p_refl_spot = 0,
+ i1p_refl_scan = 1,
+ i1p_emiss_spot_na = 2,
+ i1p_emiss_spot = 3,
+ i1p_emiss_scan = 4,
+ i1p_amb_spot = 5,
+ i1p_amb_flash = 6,
+ i1p_trans_spot = 7,
+ i1p_trans_scan = 8,
+ i1p_no_modes = 9 /* Number of modes */
+} i1p_mode;
+
+struct _i1pro_state {
+ i1p_mode mode; /* Mode number */
+
+ /* Just one of the following 3 must always be set */
+ int emiss; /* flag - Emissive mode */
+ int trans; /* flag - Transmissive mode */
+ int reflective; /* flag - Reflective mode */
+
+ /* The following can be added to emiss */
+ int ambient; /* flag - Ambient mode */
+
+ /* The following can be added to any of the 3: */
+ int scan; /* flag - Scanning mode */
+ int adaptive; /* flag - adaptive mode */
+
+ /* The following can be added to scan: */
+ int flash; /* flag - Flash detection from scan mode */
+
+ /* Configuration & state information */
+ double targoscale; /* Optimal reading scale factor <= 1.0 */
+ /* Would determine scan sample rate, except we're not doing it that way! */
+ double targmaxitime;/* maximum integration time to aim for (ie. 2.0 sec) */
+ double targoscale2;/* Proportion of targoscale allowed to meed targmaxitime */
+ int gainmode; /* Gain mode, 0 = normal, 1 = high */
+ double inttime; /* Integration time */
+ double lamptime; /* Lamp turn on time */
+
+ double dadaptime; /* Target adaptive dark read time - sets number of readings */
+ double wadaptime; /* Target adaptive white/sample read time - sets number of readings */
+
+ double dcaltime; /* Target dark calibration time - sets number of readings */
+ double wcaltime; /* Target white calibration time - sets number of readings */
+
+ double dreadtime; /* Target dark on-the-fly cal time - sets number of readings */
+ double wreadtime; /* Target white/sample reading time - sets number of readings */
+
+ double maxscantime; /* Maximum scan time sets buffer size allocated */
+
+ double min_wl; /* Minimum wavelegth to report for this mode */
+
+ /* calibration information for this mode */
+ int wl_valid; /* wavelength calibration factor valid */
+ time_t wldate; /* Date/time of last wavelength calibration */
+ double wl_led_off; /* Wavelength LED reference spectrum current offset */
+
+ int dark_valid; /* dark calibration factor valid */
+ time_t ddate; /* Date/time of last dark calibration */
+ double dark_int_time; /* Integration time used for dark data */
+ double *dark_data; /* [-1 nraw] of dark level to subtract. Note that the dark value */
+ /* depends on integration time. */
+ int dark_gain_mode; /* Gain mode used for dark data */
+
+ int cal_valid; /* calibration factor valid */
+ time_t cfdate; /* Date/time of last cal factor calibration */
+ double *cal_factor[2]; /* [low res, high res][nwav] calibration scale factor for this mode */
+ double *white_data; /* [-1 nraw] linear absolute dark subtracted white data */
+ /* used to compute cal_factor */
+// double *cal_factor1, *cal_factor2; /* (Underlying tables for two resolutions) */
+
+ /* Adaptive emission/transparency black data */
+ int idark_valid; /* idark calibration factors valid */
+ time_t iddate; /* Date/time of last dark idark calibration */
+ double idark_int_time[4];
+ double **idark_data; /* [4][-1 nraw] of dark level for inttime/gains of : */
+ /* 0.01 norm, 4.0 norm, 0.01 high, 2.0 high */
+
+ int want_calib; /* Want White calibration at start */
+ int want_dcalib; /* Want Dark Calibration at start */
+
+ /* Display mode calibration state (emmis && !scan && !adaptive) */
+ int dispswap; /* 0 = default time, 1 = dark_int_time2, 2 = dark_int_time3 */
+ double done_dintsel; /* A display integration time selection has been done */
+ time_t diseldate; /* Date/time of last display integration time selection */
+ double dcaltime2; /* Target dark calibration time - sets number of readings */
+ double dark_int_time2; /* Integration time used for dark data 2 */
+ double *dark_data2; /* [-1 nraw] of dark level to subtract for dark_int_time2. */
+ double dcaltime3; /* Target dark calibration time - sets number of readings */
+ double dark_int_time3; /* Integration time used for dark data 3 */
+ double *dark_data3; /* [-1 nraw] of dark level to subtract for dark_int_time3. */
+
+}; typedef struct _i1pro_state i1pro_state;
+
+/* Pointers to the three tables that allow a raw to wave filter conversion */
+typedef struct {
+ int *index; /* [nwav] Matrix CCD sample starting index for each out wavelength */
+ int *nocoef; /* [nwav] Number of matrix cooeficients for each out wavelength */
+ double *coef; /* [nwav * mtx_nocoef] Matrix cooeficients to compute each wavelength */
+} i1pro_r2wtab;
+
+/* RevE capability bits */
+#define I1PRO_CAP2_AMBIENT 0x01 /* Has ambient measurement capability */
+#define I1PRO_CAP2_WL_LED 0x02 /* Has wavelenght LED */
+#define I1PRO_CAP2_UV_LED 0x04 /* Has Ultra Violet LED */
+#define I1PRO_CAP2_ZEB_RUL 0x08 /* Has zerbra ruler sensor */
+#define I1PRO_CAP2_IND_LED 0x10 /* Has indicator LEDs */
+#define I1PRO_CAP2_UV_FILT 0x20 /* Has Ultra Violet Filter */
+
+/* I1PRO implementation class */
+struct _i1proimp {
+ i1pro *p;
+
+ /* Misc. and top level */
+ struct _i1data *data; /* EEProm data container */
+ athread *th; /* Switch monitoring thread (NULL if not used) */
+ volatile int switch_count; /* Incremented in thread */
+ volatile int hide_switch; /* Set to supress switch event during read */
+ usb_cancelt cancelt; /* Token to allow cancelling an outstanding I/O */
+ volatile int th_term; /* Terminate thread on next return */
+ volatile int th_termed; /* Thread has terminated */
+ inst_opt_type trig; /* Reading trigger mode */
+ int noinitcalib; /* Disable initial calibration if not essential */
+ int highres; /* High resolution mode */
+ int hr_inited; /* High resolution has been initialized */
+
+ /* Current settings */
+ i1p_mode mmode; /* Current measurement mode selected */
+ i1pro_state ms[i1p_no_modes]; /* Mode state */
+ int spec_en; /* NZ to enable reporting of spectral data */
+ int uv_en; /* NZ to do UV reflective measurement */
+ /* ~~ change this to uv_mode of none, uv, strip1, 2pass */
+
+ double intclkp; /* Integration clock period (typically 68 usec) */
+ int subclkdiv; /* Sub clock divider ratio */
+ int subtmode; /* Reading 127 subtract mode (version 301 or greater) */
+
+ /* Current state of hardware, to avoid uncessary operations */
+ double c_inttime; /* Integration time */
+ double l_inttime; /* Last Integration time (for Rev A+/B quirk fix) */
+ double c_lamptime; /* Lamp turn on time */
+ int c_mcmode; /* special clock mode we're in (if rev >= 301) */
+ int c_intclocks; /* Number of integration clocks (set using setmeasparams() */
+ int c_lampclocks; /* Number of integration clocks (set using setmeasparams() */
+ int c_nummeas; /* Number of measurements (set using setmeasparams() */
+ int c_measmodeflags; /* Measurement mode flags (set using setmeasparams() */
+ int c_measmodeflags2; /* Measurement mode flags Rev E (set using setmeasparams() */
+ unsigned int slamponoff; /* The second last time the lamp was switched from on to off */
+ unsigned int llampoffon; /* The last time the lamp was switched from off to on, in msec */
+ unsigned int llamponoff; /* The last time the lamp was switched from on to off, in msec */
+
+
+ /* Values read from GetMisc() */
+ int fwrev; /* int - Firmware revision number, from getmisc() */
+ /* Used for internal switching ?? */
+ /* 101 = Rev A, 202 = Rev A update, 302 = Rev B, 502 = Rev D */
+ /* 629 = Rev E (i1pro2) */
+
+ int cpldrev; /* int - CPLD revision number in EEProm */
+ /* Not used internaly ???? */
+ /* 101 = Rev A, 2 = Rev A update, 301 = Rev B, 999 = Rev D */
+
+ unsigned char chipid[8]; /* HW serial number - Rev E */
+
+ int eesize; /* EEProm size in bytes */
+ int maxpve; /* Maximum +ve value of Sensor Data + 1 */
+ int powmode; /* Power mode status, 0 = high, 8 = low */
+
+ /* Values from i1pro2_getmeaschar() */
+ double intclkp2; /* Rev E Integration clock period (typically 36 usec) */
+ int subclkdiv2; /* Sub clock divider ratio (typically 136) */
+
+ /* Values read from GetMeasureParameters() - are these needed ? */
+ int r_intclocks; /* Number of integration clocks (read from instrument) */
+ int r_lampclocks; /* Number of lamp turn on sub-clocks (read from instrument) */
+ int r_nummeas; /* Number of measurements (read from instrument) */
+ int r_measmodeflags; /* Measurement mode flags (read from instrument) */
+
+
+ /* Information about the instrument from the EEprom */
+ int serno; /* serial number */
+ char sserno[14]; /* serial number as string */
+ int dom; /* Date of manufacture DDMMYYYY ? */
+ int capabilities; /* Capabilities flag */
+ /* Ambient capability if val & 0x6000 != 0 */
+ int physfilt; /* int - physical filter */
+ /* 0x80 == no filter */
+ /* 0x81 == emission only ?? */
+ /* 0x82 == UV filter */
+ int capabilities2; /* Rev E capabilities - set #defines above */
+ /* Also set for RevA-D */
+
+ /* Underlying calibration information */
+ int nsen; /* Raw + extra sample bands read = 128 for i1pro, 136 for Rev E */
+ /* Rev <= D have exactly 128 */
+ /* Rev E has 134, of which 128 are measurements. */
+ /* 5 are skipped at the start, and 1 at the end */
+ /* The first 4 are used as a dark consistency check. */
+ /* ie. 4 + 1 + 128 + 1 */
+ int nraw; /* Raw sample bands stored = 128 (Must be signed!) */
+ unsigned int nwav[2]; /* [low res, high res] cooked spectrum bands stored, ie = 36 */
+ double wl_short[2]; /* [low res, high res] cooked spectrum bands short wavelength, ie 380 */
+ double wl_long[2]; /* [low res, high res] cooked spectrum bands short wavelength, ie 730 */
+
+ unsigned int nlin0; /* Number in array */
+ double *lin0; /* Array of linearisation polinomial factors, normal gain. */
+
+ unsigned int nlin1; /* Number in array */
+ double *lin1; /* Array of linearisation polinomial factors, high gain. */
+
+ double min_int_time; /* Minimum integration time (secs) */
+ double max_int_time; /* Maximum integration time (secs) */
+
+ i1pro_r2wtab mtx[2][2]; /* Raw to wav filters [normal res, high res][emis/trans, reflective] */
+ /* These are all pointers to tables allocated below */
+
+ i1pro_r2wtab mtx_o; /* Underlying original filters from EEProm calibration info. */
+ i1pro_r2wtab mtx_c[2][2]; /* Underlying allocated for RevE wavelength and hi-res calibrated */
+
+ double *white_ref[2]; /* [low res, high res][nwav] White cal tile reflectance values */
+ double *emis_coef[2]; /* [low res, high res][nwav] Emission cal coefficients */
+ double *amb_coef[2]; /* [low res, high res][nwav] Ambient light cal values */
+ /* (compound with Emission), NULL if ambient not supported */
+
+ double **straylight[2]; /* [nwav][nwav] Stray light convolution matrix (Rev E) */
+
+ double highgain; /* High gain mode gain */
+ double scan_toll_ratio; /* Modifier of scan tollerance */
+
+ int sens_target; /* sensor optimal target value */
+ int sens_dark; /* sensor dark reference threshold */
+ int sens_sat0; /* Normal gain sensor saturated threshold */
+ int sens_sat1; /* High gain sensor saturated threshold */
+
+ /* RevA-D alternative to RevE calibration information */
+ rspl *raw2wav; /* Lookup from CCD index to wavelength, NULL until highres inited */
+
+ /* Rev E calibration information */
+ double wl_cal_inttime; /* Wavelength calibration integration time */
+ double wl_cal_min_level; /* Normalized wavelength calibration minumum peak level */
+ double wl_cal_fwhm; /* Wavelength cal expected FWHM (nm) */
+ double wl_cal_fwhm_tol; /* Wavelength cal expected FWHM tollerance (nm) */
+ double *wl_led_spec; /* Wavelength LED reference spectrum */
+ unsigned int wl_led_count; /* Wavelength LED reference spectrum number of entries */
+ double wl_led_ref_off; /* Wavelength LED reference spectrum ref. offset */
+ double wl_err_max; /* Wavelength error maximum value (ie. 5.0) */
+ double *wlpoly1, *wlpoly2; /* CCD bin to wavelength polinomial equations */
+ /* for reflective and emissive/transmissuce modes respectively. */
+
+ /* log variables */
+ int meascount; /* Total Measure (Emis/Remis/Ambient/Trans/Cal) count */
+ /* but not the pre-Remission dark calibration. */
+ time_t caldate; /* Remspotcal last calibration date */
+ int calcount; /* Remission spot measure count at last Remspotcal. */
+ double rpinttime; /* Last remision spot reading integration time */
+ int rpcount; /* Remission spot measure count */
+ int acount; /* Remission scan measure count (Or all scan ??) */
+ double lampage; /* Total lamp usage time in seconds (??) */
+
+ /* Trigger houskeeping & diagnostics */
+ int transwarn; /* Transmission calibration warning state */
+ int lo_secs; /* Seconds since last opened (from calibration file mod time) */
+ int msec; /* msec_time() at creation */
+ athread *trig_thread; /* Delayed trigger thread */
+ int trig_delay; /* Trigger delay in msec */
+ int tr_t1, tr_t2, tr_t3, tr_t4, tr_t5, tr_t6, tr_t7; /* Trigger/read timing diagnostics */
+ /* 1->2 = time to execute trigger */
+ /* 2->3 = time to between end trigger and start of first read */
+ /* 3->4 = time to exectute first read */
+ /* 6->5 = time between end of second last read and start of last read */
+ int trig_se; /* Delayed trigger icoms error */
+ i1pro_code trig_rv; /* Delayed trigger result */
+
+}; typedef struct _i1proimp i1proimp;
+
+/* Add an implementation structure */
+i1pro_code add_i1proimp(i1pro *p);
+
+/* Destroy implementation structure */
+void del_i1proimp(i1pro *p);
+
+/* ============================================================ */
+/* Error codes returned from i1pro_imp */
+
+/* Note: update i1pro_interp_error() and i1pro_interp_code() in i1pro.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define I1PRO_INTERNAL_ERROR 0x71 /* Internal software error */
+#define I1PRO_COMS_FAIL 0x72 /* Communication failure */
+#define I1PRO_UNKNOWN_MODEL 0x73 /* Not an i1pro */
+#define I1PRO_DATA_PARSE_ERROR 0x74 /* Read data parsing error */
+
+#define I1PRO_USER_ABORT 0x75 /* uicallback returned abort */
+#define I1PRO_USER_TRIG 0x76 /* uicallback retuned trigger */
+
+#define I1PRO_UNSUPPORTED 0x79 /* Unsupported function */
+#define I1PRO_CAL_SETUP 0x7A /* Cal. retry with correct setup is needed */
+
+/* Real error code */
+#define I1PRO_OK 0x00
+
+#define I1PRO_DATA_COUNT 0x01 /* count unexpectedly small */
+#define I1PRO_DATA_BUFSIZE 0x02 /* buffer too small */
+#define I1PRO_DATA_MAKE_KEY 0x03 /* creating key failed */
+#define I1PRO_DATA_MEMORY 0x04 /* memory alloc failure */
+#define I1PRO_DATA_KEYNOTFOUND 0x05 /* a key value wasn't found */
+#define I1PRO_DATA_WRONGTYPE 0x06 /* a key is the wrong type */
+#define I1PRO_DATA_KEY_CORRUPT 0x07 /* key table seems to be corrupted */
+#define I1PRO_DATA_KEY_COUNT 0x08 /* key table count is too big or small */
+#define I1PRO_DATA_KEY_UNKNOWN 0x09 /* unknown key type */
+#define I1PRO_DATA_KEY_MEMRANGE 0x0a /* key data is out of range of EEProm */
+#define I1PRO_DATA_KEY_ENDMARK 0x0b /* And end section marker was missing */
+
+/* HW errors */
+#define I1PRO_HW_HIGHPOWERFAIL 0x10 /* Switch to high power mode failed */
+#define I1PRO_HW_EE_SIZE 0x11 /* EEProm is too small */
+#define I1PRO_HW_EE_SHORTREAD 0x12 /* Read fewer EEProm bytes than expected */
+#define I1PRO_HW_EE_SHORTWRITE 0x13 /* Read fewer EEProm bytes than expected */
+#define I1PRO_HW_ME_SHORTREAD 0x14 /* Read measurement bytes than expected */
+#define I1PRO_HW_ME_ODDREAD 0x15 /* Read measurement bytes was not mult 256 */
+#define I1PRO_HW_SW_SHORTREAD 0x16 /* Read less bytes for Switch read than expected */
+#define I1PRO_HW_LED_SHORTWRITE 0x17 /* Wrote fewer LED sequence bytes than expected */
+#define I1PRO_HW_UNEX_SPECPARMS 0x18 /* Unexpacted spectral parameter values */
+#define I1PRO_HW_CALIBINFO 0x19 /* calibration info is missing or corrupted */
+#define I1PRO_WL_TOOLOW 0x1A /* WL calibration measurement too low */
+#define I1PRO_WL_SHAPE 0x1B /* WL calibration measurement shape is wrong */
+#define I1PRO_WL_ERR2BIG 0x1C /* WL calibration correction is too big */
+
+/* Sample read operation errors */
+#define I1PRO_RD_DARKREADINCONS 0x30 /* Dark calibration reading inconsistent */
+#define I1PRO_RD_SENSORSATURATED 0x31 /* Sensor is saturated */
+#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_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 */
+#define I1PRO_RD_READINCONS 0x39 /* Reading is inconsistent */
+#define I1PRO_RD_TRANSWHITERANGE 0x3A /* Transmission white reference is out of range */
+#define I1PRO_RD_NOTENOUGHPATCHES 0x3B /* Not enough patches */
+#define I1PRO_RD_TOOMANYPATCHES 0x3C /* Too many patches */
+#define I1PRO_RD_NOTENOUGHSAMPLES 0x3D /* Not enough samples per patch */
+#define I1PRO_RD_NOFLASHES 0x3E /* No flashes recognized */
+#define I1PRO_RD_NOAMBB4FLASHES 0x3F /* No ambient before flashes found */
+#define I1PRO_RD_NOREFR_FOUND 0x40 /* Unable to measure refresh rate */
+
+/* Internal errors */
+#define I1PRO_INT_NO_COMS 0x50
+#define I1PRO_INT_EETOOBIG 0x51 /* EEProm read size is too big */
+#define I1PRO_INT_ODDREADBUF 0x52 /* Measurment read buffer is not mult 256 */
+#define I1PRO_INT_SMALLREADBUF 0x53 /* Measurment read buffer too small */
+#define I1PRO_INT_INTTOOBIG 0x55 /* Integration time is too big */
+#define I1PRO_INT_INTTOOSMALL 0x56 /* Integration time is too small */
+#define I1PRO_INT_ILLEGALMODE 0x57 /* Illegal measurement mode selected */
+#define I1PRO_INT_WRONGMODE 0x58 /* In wrong mode for request */
+#define I1PRO_INT_ZEROMEASURES 0x59 /* Number of measurements requested is zero */
+#define I1PRO_INT_WRONGPATCHES 0x5A /* Number of patches to match is wrong */
+#define I1PRO_INT_MEASBUFFTOOSMALL 0x5B /* Measurement read buffer is too small */
+#define I1PRO_INT_NOTIMPLEMENTED 0x5C /* Support not implemented */
+#define I1PRO_INT_NOTCALIBRATED 0x5D /* Unexpectedely invalid calibration */
+#define I1PRO_INT_NOINTERPDARK 0x5E /* Need interpolated dark and don't have it */
+#define I1PRO_INT_THREADFAILED 0x5F /* Creation of thread failed */
+#define I1PRO_INT_BUTTONTIMEOUT 0x60 /* Switch status read timed out */
+#define I1PRO_INT_CIECONVFAIL 0x61 /* Creating spectral to CIE converted failed */
+#define I1PRO_INT_PREP_LOG_DATA 0x62 /* Error in preparing log data */
+#define I1PRO_INT_MALLOC 0x63 /* Error in mallocing memory */
+#define I1PRO_INT_CREATE_EEPROM_STORE 0x64 /* Error in creating EEProm store */
+#define I1PRO_INT_SAVE_SUBT_MODE 0x65 /* Can't save calibration if in subt mode */
+#define I1PRO_INT_NO_CAL_TO_SAVE 0x66 /* No calibration data to save */
+#define I1PRO_INT_EEPROM_DATA_MISSING 0x67 /* EEProm data is missing */
+#define I1PRO_INT_NEW_RSPL_FAILED 0x68 /* Creating RSPL object faild */
+#define I1PRO_INT_CAL_SAVE 0x69 /* Unable to save calibration to file */
+#define I1PRO_INT_CAL_RESTORE 0x6A /* Unable to restore calibration from file */
+#define I1PRO_INT_CAL_TOUCH 0x6B /* Unable to touch calibration file */
+#define I1PRO_INT_ADARK_INVALID 0x6C /* Adaptive dark calibration is invalid */
+#define I1PRO_INT_NO_HIGH_GAIN 0x6D /* Rev E mode doesn't support high gain mode */
+#define I1PRO_INT_ASSERT 0x6F /* Internal assert */
+
+int icoms2i1pro_err(int se);
+
+/* ============================================================ */
+/* High level implementatation */
+
+/* Initialise our software state from the hardware */
+i1pro_code i1pro_imp_init(i1pro *p);
+
+/* Return a pointer to the serial number */
+char *i1pro_imp_get_serial_no(i1pro *p);
+
+/* Return non-zero if capable of ambient mode */
+int i1pro_imp_ambient(i1pro *p);
+
+/* Set the measurement mode. It may need calibrating */
+i1pro_code i1pro_imp_set_mode(
+ i1pro *p,
+ i1p_mode mmode, /* i1pro mode to use */
+ inst_mode m); /* full mode mask */
+
+/* Implement get_n_a_cals */
+i1pro_code i1pro_imp_get_n_a_cals(i1pro *p, inst_cal_type *pn_cals, inst_cal_type *pa_cals);
+
+/* Calibrate for the current mode. */
+/* Request an instrument calibration of the current mode. */
+i1pro_code i1pro_imp_calibrate(
+ i1pro *p,
+ inst_cal_type *calt, /* Calibration type to do/remaining */
+ inst_cal_cond *calc, /* Current condition/desired condition */
+ char id[100] /* Condition identifier (ie. white reference ID) */
+);
+
+/* Measure a patch or strip in the current mode. */
+i1pro_code i1pro_imp_measure(
+ i1pro *p,
+ ipatch *val, /* Pointer to array of instrument patch value */
+ int nvals, /* Number of values */
+ instClamping clamp /* Clamp XYZ/Lab to be +ve */
+);
+
+/* Measure the emissive refresh rate */
+i1pro_code i1pro_imp_meas_refrate(
+ i1pro *p,
+ double *ref_rate
+);
+
+/* Given a raw measurement of the wavelength LED, */
+/* Compute the base offset that best fits it to the reference */
+i1pro_code i1pro2_match_wl_meas(i1pro *p, double *pled_off, double *wlraw);
+
+/* Compute standard res downsampling filters */
+/* mtx_index1, mtx_nocoef1, mtx_coef1 given the */
+/* current wl_led_off */
+i1pro_code i1pro2_compute_wav_filters(i1pro *p, int reflective);
+
+/* return nz if high res is supported */
+int i1pro_imp_highres(i1pro *p);
+
+/* Set to high resolution mode */
+i1pro_code i1pro_set_highres(i1pro *p);
+
+/* Set to standard resolution mode */
+i1pro_code i1pro_set_stdres(i1pro *p);
+
+/* Modify the scan consistency tollerance */
+i1pro_code i1pro_set_scan_toll(i1pro *p, double toll_ratio);
+
+
+/* Update the single remission calibration and instrument usage log */
+i1pro_code i1pro_update_log(i1pro *p);
+
+/* Save the reflective spot calibration information to the EEPRom data object. */
+/* Note we don't actually write to the EEProm here! */
+static i1pro_code i1pro_set_log_data(i1pro *p);
+
+/* Restore the reflective spot calibration information from the EEPRom */
+/* Always returns success, even if the restore fails */
+i1pro_code i1pro_restore_refspot_cal(i1pro *p);
+
+
+/* Save the calibration for all modes, stored on local system */
+i1pro_code i1pro_save_calibration(i1pro *p);
+
+/* Restore the all modes calibration from the local system */
+i1pro_code i1pro_restore_calibration(i1pro *p);
+
+/* Update the modification time on the file, so we can */
+/* track when the instrument was last open. */
+i1pro_code i1pro_touch_calibration(i1pro *p);
+
+/* ============================================================ */
+/* Intermediate routines - composite commands/processing */
+
+i1pro_code i1pro_establish_high_power(i1pro *p);
+
+/* Take a dark reference measurement - part 1 */
+i1pro_code i1pro_dark_measure_1(
+ i1pro *p,
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf, /* USB reading buffer to use */
+ unsigned int bsize /* Size of buffer */
+);
+
+/* Take a dark reference measurement - part 2 */
+i1pro_code i1pro_dark_measure_2(
+ i1pro *p,
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ int nummeas, /* Number of readings to take */
+ double inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf, /* raw USB reading buffer to process */
+ unsigned int bsize /* Buffer size to process */
+);
+
+/* Take a dark measurement */
+i1pro_code i1pro_dark_measure(
+ i1pro *p,
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+);
+
+/* Take a white reference measurement - part 3 */
+/* Average, check, and convert to output wavelengths */
+i1pro_code i1pro_whitemeasure_3(
+ i1pro *p,
+ double *abswav1, /* Return array [nwav1] of abswav values (may be NULL) */
+ double *abswav2, /* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double *optscale, /* Factor to scale gain/int time by to make optimal (may be NULL) */
+ int nummeas, /* Number of readings to take */
+ double inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale, /* Optimal reading target scale factor */
+ double **multimes, /* Multiple measurement results */
+ double darkthresh /* Raw dark threshold */
+);
+
+/* Take a white reference measurement */
+/* (Subtracts black and processes into wavelenths) */
+i1pro_code i1pro_whitemeasure(
+ i1pro *p,
+ double *abswav1, /* Return array [nwav1] of abswav values (may be NULL) */
+ double *abswav2, /* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double *optscale, /* Factor to scale gain/int time by to make optimal (may be NULL) */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale, /* Optimal reading scale factor */
+ int ltocmode /* 1 = Lamp turn on compensation mode */
+);
+
+/* Process a single raw white reference measurement */
+/* (Subtracts black and processes into wavelenths) */
+i1pro_code i1pro_whitemeasure_buf(
+ i1pro *p,
+ double *abswav1, /* Return array [nwav1] of abswav values (may be NULL) */
+ double *abswav2, /* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf /* Raw buffer */
+);
+
+/* Take a wavelength reference measurement */
+/* (Measure and subtracts black and convert to absraw) */
+i1pro_code i1pro2_wl_measure(
+ i1pro *p,
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double *optscale, /* Factor to scale gain/int time by to make optimal (may be NULL) */
+ double *inttime, /* Integration time to use/used */
+ double targoscale /* Optimal reading scale factor */
+);
+
+/* Take a measurement reading using the current mode, part 1 */
+/* Converts to completely processed output readings. */
+i1pro_code i1pro_read_patches_1(
+ i1pro *p,
+ int minnummeas, /* Minimum number of measurements to take */
+ int maxnummeas, /* Maximum number of measurements to allow for */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ int *nmeasuered, /* Number actually measured */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+);
+
+/* Take a measurement reading using the current mode, part 2 */
+/* Converts to completely processed output readings. */
+i1pro_code i1pro_read_patches_2(
+ i1pro *p,
+ double *duration, /* return flash duration (secs) */
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of patches to return */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode useed, 0 = normal, 1 = high */
+ int nmeasuered, /* Number actually measured */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+);
+
+/* Take a measurement reading using the current mode. */
+/* Converts to completely processed output readings. */
+i1pro_code i1pro_read_patches(
+ i1pro *p,
+ double *duration, /* Return flash duration */
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of patches to return */
+ int minnummeas, /* Minimum number of measurements to take */
+ int maxnummeas, /* Maximum number of measurements to allow for */
+ double *inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+);
+
+/* Take a trial measurement reading using the current mode. */
+/* Used to determine if sensor is saturated, or not optimal */
+i1pro_code i1pro_trialmeasure(
+ i1pro *p,
+ int *saturated, /* Return nz if sensor is saturated */
+ double *optscale, /* Factor to scale gain/int time by to make optimal */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale /* Optimal reading scale factor */
+);
+
+/* Measurement modifier. Modifes the default current measurement mode */
+/* for the measurement. Bit 0x10 indicates that incandescent illumination */
+/* is possible, bit 0x20 indicates that any scan mode is to be ignored */
+typedef enum {
+ i1p_norm = 0x10, /* Normal measurement for current mode */
+ i1p2_UV = 0x01, /* Measurement using UV LED instead of incandescent (Rev E) */
+ i1p_cal = 0x32, /* No scan, with current mode illumination */
+ i1p_dark_cal = 0x23, /* No scan, no illumination */
+ i1p2_wl_cal = 0x24 /* No scan, wavelength reference LED illumination (Rev E) */
+} i1p_mmodif;
+
+/* Trigger a single measurement cycle. This could be a dark calibration, */
+/* a calibration, or a real measurement. Used to create the higher */
+/* level "calibrate" and "take reading" functions. */
+/* The setup for the operation is in the current mode state. */
+/* The called then needs to call i1pro_readmeasurement() */
+i1pro_code
+i1pro_trigger_one_measure(
+ i1pro *p,
+ int nummeas, /* Number of measurements to make */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ i1p_mmodif mmodif /* Measurement modifier enum */
+);
+
+/* ============================================================ */
+/* lower level reading processing */
+
+/* Take a buffer full of sensor readings, and convert them to */
+/* absolute raw values. Linearise if Rev A..D */
+/* Note the rev E darkthresh returned has NOT been converted to an absolute raw value */
+i1pro_code i1pro_sens_to_absraw(
+ i1pro *p,
+ double **absraw, /* Array of [nummeas][-1 nraw] value to return */
+ unsigned char *buf, /* Raw measurement data must be 256 * nummeas */
+ int nummeas, /* Return number of readings measured */
+ double inttime, /* Integration time used */
+ int gainmode, /* Gain mode, 0 = normal, 1 = high */
+ double *pdarkthresh /* Return a dark threshold value (Rev E) */
+);
+
+/* Take a raw value, and convert it into an absolute raw value. */
+/* Note that linearisation is ignored, since it is assumed to be insignificant */
+/* to the black threshold and saturation values. */
+double i1pro_raw_to_absraw(
+ i1pro *p,
+ double raw, /* Input value */
+ double inttime, /* Integration time used */
+ int gainmode /* Gain mode, 0 = normal, 1 = high */
+);
+
+/* Take a single set of absolute linearised sensor values and */
+/* convert them back into i1pro Rev A..D raw reading values. */
+i1pro_code i1pro_absraw_to_meas(
+ i1pro *p,
+ int *meas, /* Return raw measurement data */
+ double *absraw, /* Array of [-1 nraw] value to process */
+ double inttime, /* Integration time used */
+ int gainmode /* Gain mode, 0 = normal, 1 = high */
+);
+
+/* Average a set of measurements into one. */
+/* Return zero if readings are consistent and not saturated. */
+/* Return nz with bit 1 set if the readings are not consistent */
+/* Return nz with bit 2 set if the readings are saturated */
+/* Return the highest individual element. */
+/* Return the overall average. */
+int i1pro_average_multimeas(
+ i1pro *p,
+ double *avg, /* return average [-1 nraw] */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to average */
+ int nummeas, /* Return number of readings measured */
+ double *phighest, /* If not NULL, return highest value from all bands and msrmts. */
+ double *poallavg, /* If not NULL, return overall average of bands and measurements */
+ double satthresh, /* Sauration threshold, 0 for none */
+ double darkthresh /* Dark threshold (used for consistency check scaling) */
+);
+
+/* Recognise the required number of ref/trans patch locations, */
+/* and average the measurements within each patch. */
+/* Return flags zero if readings are consistent and not saturated. */
+/* Return flags nz with bit 1 set if the readings are not consistent */
+/* Return flags nz with bit 2 set if the readings are saturated */
+/* Return the highest individual element. */
+i1pro_code i1pro_extract_patches_multimeas(
+ i1pro *p,
+ int *flags, /* return flags */
+ double **pavg, /* return patch average [naptch][-1 nraw] */
+ int npatch, /* number of patches to recognise */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to extract from */
+ int nummeas, /* number of readings to recognise them from */
+ double *phighest, /* If not NULL, return highest value from all bands and msrmts. */
+ double satthresh, /* Sauration threshold, 0 for none */
+ double inttime /* Integration time (used to adjust consistency threshold) */
+);
+
+/* Recognise any flashes in the readings, and */
+/* and average their values together as well as summing their duration. */
+/* Return nz on an error */
+i1pro_code i1pro_extract_patches_flash(
+ i1pro *p,
+ int *flags, /* return flags */
+ double *duration, /* return duration */
+ double *pavg, /* return patch average [-1 nraw] */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to extract from */
+ int nummeas, /* number of readings made */
+ double inttime /* Integration time (used to compute duration) */
+);
+
+/* Subtract one absraw array from another */
+/* If Rev E, also adjust according to shielded cells, and linearise. */
+void i1pro_sub_absraw(
+ i1pro *p,
+ int nummeas, /* Return number of readings measured */
+ double inttime, /* Integration time used */
+ int gainmode, /* Gain mode, 0 = normal, 1 = high */
+ double **absraw, /* Source/Desination array [-1 nraw] */
+ double *sub /* Black value to subtract [-1 nraw] */
+);
+
+/* Convert an absraw array from raw wavelengths to output wavelenths */
+/* for the current resolution */
+void i1pro_absraw_to_abswav(
+ i1pro *p,
+ int highres,
+ int reflective,
+ int nummeas, /* Return number of readings measured */
+ double **abswav, /* Desination array [nwav] */
+ double **absraw /* Source array [-1 nraw] */
+);
+
+/* Convert an abswav array of output wavelengths to scaled output readings. */
+void i1pro_scale_specrd(
+ i1pro *p,
+ double **outspecrd, /* Destination */
+ int numpatches, /* Number of readings/patches */
+ double **inspecrd /* Source */
+);
+
+/* Convert from spectral to XYZ, and transfer to the ipatch array */
+i1pro_code i1pro_conv2XYZ(
+ i1pro *p,
+ ipatch *vals, /* Values to return */
+ int nvals, /* Number of values */
+ double **specrd, /* Spectral readings */
+ instClamping clamp /* Clamp XYZ/Lab to be +ve */
+);
+
+/* Check a reflective white measurement, and check that */
+/* it seems reasonable. Return inst_ok if it is, error if not. */
+i1pro_code i1pro_check_white_reference1(
+ i1pro *p,
+ double *abswav /* Measurement to check */
+);
+
+/* Compute a calibration factor given the reading of the white reference. */
+/* Return nz if any of the transmission wavelengths are low */
+int i1pro_compute_white_cal(
+ i1pro *p,
+ double *cal_factor0, /* [nwav0] Calibration factor to compute */
+ double *white_ref0, /* [nwav0] White reference to aim for, NULL for 1.0 */
+ double *white_read0, /* [nwav0] The white that was read */
+ double *cal_factor1, /* [nwav1] Calibration factor to compute */
+ double *white_ref1, /* [nwav1] White reference to aim for, NULL for 1.0 */
+ double *white_read1 /* [nwav1] The white that was read */
+);
+
+/* For adaptive mode, compute a new integration time and gain mode */
+/* in order to optimise the sensor values. */
+i1pro_code i1pro_optimise_sensor(
+ i1pro *p,
+ double *pnew_int_time,
+ int *pnew_gain_mode,
+ double cur_int_time,
+ int cur_gain_mode,
+ int permithg, /* nz to permit switching to high gain mode */
+ int permitclip, /* nz to permit clipping out of range int_time, else error */
+ double targoscale, /* Optimising target scale ( <= 1.0) */
+ double scale /* scale needed of current int time to reach optimum */
+);
+
+/* Compute the number of measurements needed, given the target */
+/* time and integration time. Will return 0 if target time is 0 */
+int i1pro_comp_nummeas(
+ i1pro *p,
+ double meas_time,
+ double int_time
+);
+
+/* Convert the dark interpolation data to a useful state */
+void i1pro_prepare_idark(i1pro *p);
+
+/* Create the dark reference for the given integration time and gain */
+/* by interpolating from the 4 readings taken earlier. */
+i1pro_code i1pro_interp_dark(
+ i1pro *p,
+ double *result, /* Put result of interpolation here */
+ double inttime,
+ int gainmode
+);
+
+/* Create or re-create high resolution mode references */
+i1pro_code i1pro_create_hr(i1pro *p);
+
+/* Set the noinitcalib mode */
+void i1pro_set_noinitcalib(i1pro *p, int v, int losecs);
+
+/* Set the trigger config */
+void i1pro_set_trig(i1pro *p, inst_opt_type trig);
+
+/* Return the trigger config */
+inst_opt_type i1pro_get_trig(i1pro *p);
+
+/* Set the trigger return */
+void i1pro_set_trigret(i1pro *p, int val);
+
+/* Switch thread handler */
+int i1pro_switch_thread(void *pp);
+
+/* ============================================================ */
+/* Low level i1pro commands */
+
+/* USB Commands */
+
+/* Reset the instrument */
+i1pro_code
+i1pro_reset(
+ struct _i1pro *p,
+ int mask /* reset mask ?. Known values ar 0x1f, 0x07, 0x01 */
+);
+
+/* Read from the EEProm */
+i1pro_code
+i1pro_readEEProm(
+ struct _i1pro *p,
+ unsigned char *buf, /* Where to read it to */
+ int addr, /* Address in EEprom to read from */
+ int size /* Number of bytes to read (max 65535) */
+);
+
+/* Write to the EEProm */
+i1pro_code
+i1pro_writeEEProm(
+ i1pro *p,
+ unsigned char *buf, /* Where to write from */
+ int addr, /* Address in EEprom to write to */
+ int size /* Number of bytes to write (max 65535) */
+);
+
+/* Get the miscelanious status */
+/* return pointers may be NULL if not needed. */
+i1pro_code
+i1pro_getmisc(
+ i1pro *p,
+ int *fwrev, /* Return the hardware version number */
+ int *unkn1, /* Unknown status, set after doing a measurement */
+ int *maxpve, /* Maximum positive value in sensor readings */
+ int *unkn3, /* Unknown status, usually 1 */
+ int *powmode /* 0 = high power mode, 8 = low power mode */
+);
+
+/* Get the current measurement parameters */
+/* return pointers may be NULL if not needed. */
+i1pro_code
+i1pro_getmeasparams(
+ i1pro *p,
+ int *intclocks, /* Number of integration clocks (Up to 65535) */
+ int *lampclocks, /* Number of lamp turn on sub-clocks (Up to 65535) */
+ int *nummeas, /* Number of measurements (Up to 65535) */
+ int *measmodeflags /* Measurement mode flags (4 bits, see below) */
+);
+
+/* These bits correspond with the instruction flags */
+#define I1PRO_MMF_SCAN 0x01 /* Scan mode bit, else spot mode */
+#define I1PRO_MMF_NOLAMP 0x02 /* No lamp mode, else use illumination lamp */
+#define I1PRO_MMF_LOWGAIN 0x04 /* Normal gain mode, else high gain */
+#define I1PRO_MMF_UNKN 0x08 /* Unknown. Not usually set */
+
+/* Scan mode continues measuring until the user releases the button. */
+/* (Does scan mode do the given number of readings as a minimum ???) */
+/* Spot mode does the given number of readings. */
+
+/* Set the measurement parameters */
+i1pro_code
+i1pro_setmeasparams(
+ i1pro *p,
+ int intclocks, /* Number of integration clocks */
+ int lampclocks, /* Number of lamp turn on sub-clocks */
+ int nummeas, /* Number of measurements to make */
+ int measmodeflags /* Measurement mode flags */
+);
+
+/* Trigger a measurement after the delay in msec. */
+/* The actual return code will be in m->trig_rv after the delay */
+i1pro_code
+i1pro_triggermeasure(i1pro *p, int delay);
+
+
+/* Read a measurements results */
+i1pro_code
+i1pro_readmeasurement(
+ i1pro *p,
+ int inummeas, /* Initial number of measurements to expect */
+ int scanflag, /* NZ if in scan mode to continue reading */
+ unsigned char *buf, /* Where to read it to */
+ int bsize, /* Bytes available in buffer */
+ int *nummeas, /* Return number of readings measured */
+ i1p_mmodif mmodif /* Measurement modifier enum */
+);
+
+
+/* Set the measurement clock mode */
+/* Version >= 301 only */
+i1pro_code
+i1pro_setmcmode(
+ i1pro *p,
+ int mcmode /* Measurement clock mode, 1..mxmcmode */
+);
+
+
+/* Get the current measurement clock mode */
+/* Return pointers may be NULL if not needed. */
+/* Version >= 301 only */
+i1pro_code
+i1pro_getmcmode(
+ i1pro *p,
+ int *maxmcmode, /* mcmode must be < maxmcmode */
+ int *mcmode, /* readback current mcmode */
+ int *subclkdiv, /* Sub clock divider ratio */
+ int *intclkusec, /* Integration clock in usec */
+ int *subtmode /* Subtract mode on read using average of value 127 */
+);
+
+/* ============================================================ */
+/* Low level Rev E commands */
+
+/* Get the EEProm size */
+i1pro_code
+i1pro2_geteesize(
+ i1pro *p,
+ int *eesize
+);
+
+/* Get the Chip ID (Also valid for Rev D) */
+/* Only returns a valid result after reading the EEProm ! */
+i1pro_code
+i1pro2_getchipid(
+ i1pro *p,
+ unsigned char chipid[8]
+);
+
+/* Get Extra Parameters */
+i1pro_code
+i1pro2_getmeaschar(
+ i1pro *p,
+ int *clkusec,
+ int *xraw,
+ int *nraw,
+ int *subdiv
+);
+
+/* These bits correspond with the instruction flags */
+#define I1PRO2_MMF_LAMP 0x0100 /* Use the Incandescent Lamp as the illuminant */
+#define I1PRO2_MMF_UV_LED 0x0200 /* Use the Ultra Violet LED as the illuminant */
+#define I1PRO2_MMF_WL_LED 0x0300 /* Use the Wavelength Reference LED as the illuminant */
+//#define I1PRO2_MMF_HIGHGAIN 0x0000 /* Rev E mode has no high gain mode ? */
+#define I1PRO2_MMF_SCAN 0x0001 /* Scan mode bit, else spot mode */
+#define I1PRO2_MMF_RULER_START 0x0004 /* Start ruler tracking in scan mode */
+#define I1PRO2_MMF_RULER_END 0x0008 /* End ruler tracking in scan mode */
+
+/* Delayed trigger implementation, called from thread */
+/* We assume that the Rev E measurement parameters have been set in */
+/* the i1proimp structure c_* values */
+static int
+i1pro2_delayed_trigger(void *pp);
+
+/* Trigger a measurement after the nominated delay */
+/* The actual return code will be in m->trig_rv after the delay. */
+/* This allows us to start the measurement read before the trigger, */
+/* ensuring that process scheduling latency can't cause the read to fail. */
+i1pro_code
+i1pro2_triggermeasure(i1pro *p, int delay);
+
+
+/* Get the UV before and after measurement voltage drop */
+i1pro_code
+i1pro2_getUVvolts(
+ i1pro *p,
+ int *before,
+ int *after
+);
+
+/* Terminate Ruler tracking (???) */
+/* The parameter seems to be always 0 ? */
+static int
+i1pro2_stop_ruler(void *pp, int parm);
+
+
+/* Send a LED sequence */
+static int
+i1pro2_indLEDseq(void *pp, unsigned char *buf, int size);
+
+/* Turn indicator LEDs off */
+static int
+i1pro2_indLEDoff(void *pp);
+
+// ~~~~9999
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Wait for a reply triggered by a button press */
+i1pro_code i1pro_waitfor_switch(i1pro *p, double top);
+
+/* Wait for a reply triggered by a button press (thread version) */
+i1pro_code i1pro_waitfor_switch_th(i1pro *p, double top);
+
+/* Terminate button handling ? */
+i1pro_code i1pro_terminate_switch(i1pro *p);
+
+/* -------------------------------------------------- */
+/* Key/Value storage */
+
+/* Calibration data storage class */
+/* The i1pro stores all it's calibration information */
+/* using a key/values arrangement. */
+/* We provide a place to store and retrieve that information here. */
+
+/* We haven't implemented a full set of functions - it's not possible */
+/* to create the store from scratch, re-allocate key/value entries, */
+/* resize entries or anything else of this sort. */
+
+
+/* Data Key identifiers */
+
+/* Note that array sizes are nominal. They could change with */
+/* driver and instrument changes. */
+
+/* "Log" data is keys 2710-2715, 271a-271d, 2724-2725 */
+
+/* The log data seems largly devoted to the last remission spot calibration */
+/* or reading, and some general statistics. */
+
+typedef enum {
+
+// Note 0x2710 = 10000
+ key_meascount = 0x2715, /* int, Total Measure (Emis/Remis/Ambient/Trans/Cal) count */
+ /* but not the pre-Remission dark calibration. */
+ key_darkreading = 0x271a, /* int[128] Remspotcal Dark data */
+ key_whitereading= 0x271b, /* int[128] Remspotcal White data */
+ key_gainmode = 0x271c, /* int - Remspotcal gain mode, Values 1 (normal) or 0 (high) */
+ key_inttime = 0x271d, /* double - Remspotcal integration time */
+ key_caldate = 0x2724, /* int date - Remspotcal last calibration date */
+ key_calcount = 0x2725, /* int - Remission spot measure Count at last Remspotcal. */
+ key_checksum = 0x2710, /* int - Log checksum */
+ key_rpinttime = 0x2711, /* double - Last remision spot reading integration time */
+ key_rpcount = 0x2712, /* int - Remission spot measure Count */
+ key_acount = 0x2713, /* int - Remission scan measure Count (??) */
+ key_lampage = 0x2714, /* double - Total lamp usage time (??) */
+
+/* Duplicate of above, keys += 0x3E8 (+1000) */
+// (0x2af8 = 11000)
+
+ key_2logoff = 0x03e8, /* Offset from first to second copy of log keys */
+
+
+/* Calibration parameters are 3e8-3ec, 44c-44e, 4b4-4b5, 4b7-4b8, 4bb-4bd, */
+/* 4c5-4c6, bb9-bba, bbf-bc6, fa0 */
+
+// Note 0x3e8 = 1000
+// 0x44c = 1100
+// 0x4b0 = 1200
+// 0xbb8 = 3000
+// 0xfa0 = 4000
+
+/* Linearisation uses Polinomial equation, ie: y = c0 + c1 * x + c2 * x^2 + c3 * x^3 etc. */
+/* and is applied to the raw (integer) sensor data. */
+
+ key_ng_lin = 0x03e8, /* double[4] */
+ /* Normal gain polinomial linearisation coefficients */
+
+ key_hg_lin = 0x03e9, /* double[4] */
+ /* High gain polinomial linearisation coefficients */
+
+ key_min_int_time= 0x04c5, /* double - Minumum integration time */
+ /* default 8.84000025689601900e-003 in EEProm */
+ /* Overwritten in MinilinoLowLevelDriver constructor: */
+ /* Default to 8.84000025689601900e-003 if cpldrev == 101 Ver A */
+ /* Default to 4.71600005403161050e-003 if cpldrev == 301 Ver B+ */
+
+ key_max_int_time= 0x04c6, /* double - Maximum integration time */
+ /* Typically 4.4563798904418945 */
+
+ key_mtx_index = 0x03ea, /* int[36] */
+ /* Matrix CCD sample index for each out wavelength */
+ /* 380 - 730nm */
+
+ key_mtx_nocoef = 0x03eb, /* int[36] */
+ /* Number of matrix cooeficients for each out wavelength */
+
+ key_mtx_coef = 0x03ec, /* double[36 x 16] */
+ /* Matrix cooeficients to compute each wavelength */
+
+ key_0bb9 = 0x0bb9, /* int - value typically -1*/
+ key_0bba = 0x0bba, /* int - value typically -1 */
+
+ key_white_ref = 0x044c, /* double[36] */
+ /* White calibration tile reflectance values */
+
+ key_emis_coef = 0x044d, /* double[36] */
+ /* Emission calibration coefficients */
+
+ key_amb_coef = 0x044e, /* double[36] */
+ /* Ambient light calibration values (compound with Emission) */
+ /* May be < 36, values -1.0 if Ambient is not supported */
+
+ key_0fa0 = 0x0fa0, /* int */
+ key_0bbf = 0x0bbf, /* int */
+
+ key_cpldrev = 0x0bc0, /* int - Firmware revision number */
+
+ key_0bc1 = 0x0bc1, /* int[5] */
+
+ key_capabilities= 0x0bc2, /* int */
+ /* Capabilities flag ? */
+ /* ie. has Ambient capability if val & 0x6000 != 0 */
+
+ key_0bc3 = 0x0bc3, /* int */
+
+ key_physfilt = 0x0bc4, /* int - physical filter */
+ /* 0x80 == no filter */
+ /* 0x82 == UV filter */
+
+ key_0bc5 = 0x0bc5, /* int */
+
+ key_0bc6 = 0x0bc6, /* double */
+
+ key_sens_target = 0x04b4, /* int - sensor optimal target value */
+ /* typical value 37000 */
+
+ key_sens_dark = 0x04b5, /* int - sensor dark reference threshold */
+ /* typically value 150 */
+
+ key_ng_sens_sat = 0x04b7, /* int */
+ /* Normal gain sensor saturated threshold */
+ /* typically value 45000 */
+
+ key_hg_sens_sat = 0x04b8, /* int */
+ /* High gain sensor saturated threshold */
+ /* typically value 45000 */
+
+ key_serno = 0x04bb, /* int - serial number */
+
+ key_dom = 0x04bc, /* int - unknown */
+ /* Possibly date of manufacture DDMMYYYY ? */
+ /* ie., decimal 10072002 would be 10/7/2002 ? */
+
+ key_hg_factor = 0x04bd, /* double */
+ /* High gain mode gain factor, ie 9.5572.. */
+
+
+ key2_chip_id = 0x2ee1, /* uchar[8], chip id */
+
+ key2_capabilities = 0x2ee2, /* int, capabilities bits */
+
+ key2_sens_target = 0x2eeb, /* int - sensor optimal target value ? */
+ /* typical value 30000 */
+
+ key2_sens_sat = 0x2eec, /* int - sensor saturation value ? */
+ /* typical value 55000 */
+
+ key2_uvcal_intt = 0x2ef9, /* double, UV calibration initial integration time */
+
+ key2_wlcal_intt = 0x2efa, /* double, wavelength calibration initial integration time */
+
+ key2_wlcal_minlev = 0x2efe, /* int, wavelength calibration normalized minimum peak level */
+
+ key2_wlcal_spec = 0x2f44, /* double[50], wavelength calibration reference spectrum */
+
+ key2_wlcal_ooff = 0x2f45, /* int, Reference WL Led spectral offset */
+
+ key2_wlcal_fwhm = 0x2f4e, /* double, wavelength calibration nominal fwhm (nm) */
+ key2_wlcal_fwhm_tol = 0x2f4f, /* double, wavelength calibration fwhm tollerance (nm) */
+
+ key2_wlcal_max = 0x2f46, /* double, wavelength calibration error limit, ie. 5.0 */
+
+ key2_wlpoly_1 = 0x2f62, /* double[4], CCD bin to wavelength polinomial #1 (normal) */
+ key2_wlpoly_2 = 0x2f63, /* double[4], CCD bin to wavelength polinomial #2 ??? */
+
+ key2_straylight = 0x2f58, /* int16[36][6] signed stray light values */
+ key2_straylight_scale = 0x2f59 /* double stray light scale factor */
+
+} i1key;
+
+
+/* Data type */
+typedef enum {
+ i1_dtype_unknown = 0,
+ i1_dtype_char = 1, /* Array of bytes */
+ i1_dtype_short = 2, /* 16 bit int, date */
+ i1_dtype_int = 3, /* 32 bit int, date */
+ i1_dtype_double = 4, /* 64 bit double, serialized as 32 bit float */
+ i1_dtype_section = 5 /* End of section marker */
+} i1_dtype;
+
+/* A key/value entry */
+struct _i1keyv {
+ void *data; /* Array of data */
+ unsigned int count; /* Count of data */
+ i1_dtype type; /* Type of data */
+ int addr; /* EEProm address */
+ int size; /* Size in bytes */
+ int key; /* 16 bit key */
+ struct _i1keyv *next; /* Link to next keyv */
+}; typedef struct _i1keyv i1keyv;
+
+struct _i1data {
+ /* private: */
+ i1pro *p;
+ i1proimp *m;
+
+ a1log *log; /* reference to instrument log */
+ i1keyv *head; /* Pointer to first in chain of keyv */
+ i1keyv *last; /* Pointer to last in chain of keyv */
+
+ /* public: */
+
+ /* Search the linked list for the given key */
+ /* Return NULL if not found */
+ i1keyv *(* find_key)(struct _i1data *d, i1key key);
+
+ /* Search the linked list for the given key and */
+ /* return it, or create the key if it doesn't exist. */
+ /* Return NULL on error */
+ i1keyv *(* make_key)(struct _i1data *d, i1key key);
+
+ /* Return type of data associated with key. Return i1_dtype_unknown if not found */
+ i1_dtype (*get_type)(struct _i1data *d, i1key key);
+
+ /* Return the number of data items in a keyv. Return 0 if not found */
+ unsigned int (*get_count)(struct _i1data *d, i1key key);
+
+ /* Return a int pointer to the 16 bit int data for the key. */
+ /* Optionally return the number of items too. */
+ /* Return NULL if not found or wrong type */
+ int *(*get_shorts)(struct _i1data *d, unsigned int *count, i1key key);
+
+ /* Return a pointer to the 32 bit int data for the key. */
+ /* Optionally return the number of items too. */
+ /* Return NULL if not found or wrong type */
+ int *(*get_ints)(struct _i1data *d, unsigned int *count, i1key key);
+
+ /* Return a pointer to the double data for the key. */
+ /* Optionally return the number of items too. */
+ /* Return NULL if not found or wrong type */
+ double *(*get_doubles)(struct _i1data *d, unsigned int *count, i1key key);
+
+
+ /* Return pointer to one of the int data for the key. */
+ /* Return NULL if not found or wrong type or out of range index. */
+ int *(*get_int)(struct _i1data *d, i1key key, unsigned int index);
+
+ /* Return pointer to one of the double data for the key. */
+ /* Return NULL if not found or wrong type or out of range index. */
+ double *(*get_double)(struct _i1data *d, i1key key, double *data, unsigned int index);
+
+
+ /* Un-serialize a char buffer into an i1key keyv */
+ /* (Don't change addr if its is -1) */
+ i1pro_code (*unser_ints)(struct _i1data *d, i1key key, int addr,
+ unsigned char *buf, unsigned int size);
+
+ /* Un-serialize a char buffer of floats into a double keyv */
+ /* (Don't change addr if its is -1) */
+ i1pro_code (*unser_doubles)(struct _i1data *d, i1key key, int addr,
+ unsigned char *buf, unsigned int size);
+
+
+ /* Serialize an i1key keyv into a char buffer. Error if it is outside the buffer */
+ i1pro_code (*ser_ints)(struct _i1data *d, i1keyv *k, unsigned char *buf, unsigned int size);
+
+ /* Serialize a double keyv as floats into a char buffer. Error if the buf is not big enough */
+ i1pro_code (*ser_doubles)(struct _i1data *d, i1keyv *k, unsigned char *buf, unsigned int size);
+
+ /* Initialise the data from the EEprom contents */
+ i1pro_code (*parse_eeprom)(struct _i1data *d, unsigned char *buf, unsigned int len, int extra);
+
+
+ /* Serialise all the keys up to the first marker into a buffer. */
+ i1pro_code (*prep_section1)(struct _i1data *d, unsigned char **buf, unsigned int *len);
+
+ /* Copy an array full of ints to the key (must be same size as existing) */
+ i1pro_code (*add_ints)(struct _i1data *d, i1key key, int *data, unsigned int count);
+
+ /* Copy an array full of doubles to the key (must be same size as existing) */
+ i1pro_code (*add_doubles)(struct _i1data *d, i1key key, double *data, unsigned int count);
+
+
+ /* Destroy ourselves */
+ void (*del)(struct _i1data *d);
+
+ /* Other utility methods */
+
+ /* Return the data type for the given key identifier */
+ i1_dtype (*det_type)(struct _i1data *d, i1key key);
+
+ /* Given an index starting at 0, return the matching key code */
+ /* for keys that get checksummed. Return 0 if outside range. */
+ i1key (*chsum_keys)(struct _i1data *d, int index);
+
+ /* Compute a checksum. */
+ int (*checksum)(struct _i1data *d, i1key keyoffset);
+
+}; typedef struct _i1data i1data;
+
+/* Constructor. Construct from the EEprom contents */
+extern i1data *new_i1data(i1proimp *m);
+
+#define I1PRO_IMP
+#endif /* I1PRO_IMP */
diff --git a/spectro/icoms.c b/spectro/icoms.c
new file mode 100644
index 0000000..0dc815c
--- /dev/null
+++ b/spectro/icoms.c
@@ -0,0 +1,484 @@
+
+ /* General instrument + serial I/O support */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/97
+ *
+ * Copyright 1997 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/* These routines supliement the class code in ntio.c and unixio.c */
+/* with common and USB specific routines */
+/* Rename to icoms.c ?? */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+#include <signal.h>
+#if defined(UNIX)
+#include <termios.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#else
+#include "sa_config.h"
+#endif
+#include "numsup.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+
+
+/* ----------------------------------------------------- */
+
+/* Fake device */
+icompath icomFakeDevice = { "Fake Display Device" };
+
+/* Return the path corresponding to the port number, or NULL if out of range */
+static icompath *icompaths_get_path(
+ icompaths *p,
+ int port /* Enumerated port number, 1..n */
+) {
+ if (port == -99)
+ return &icomFakeDevice;
+
+ if (port <= 0 || port > p->npaths)
+ return NULL;
+
+ return p->paths[port-1];
+}
+
+static void icompaths_clear(icompaths *p) {
+
+ /* Free any old list */
+ if (p->paths != NULL) {
+ int i;
+ for (i = 0; i < p->npaths; i++) {
+ if (p->paths[i]->name != NULL)
+ free(p->paths[i]->name);
+#ifdef ENABLE_SERIAL
+ if (p->paths[i]->spath != NULL)
+ free(p->paths[i]->spath);
+#endif /* ENABLE_SERIAL */
+#ifdef ENABLE_USB
+ usb_del_usb_idevice(p->paths[i]->usbd);
+ hid_del_hid_idevice(p->paths[i]->hidd);
+#endif /* ENABLE_USB */
+ free(p->paths[i]);
+ }
+ free(p->paths);
+ p->npaths = 0;
+ p->paths = NULL;
+ }
+}
+
+/* Add an empty new path. */
+/* Return icom error */
+static int icompaths_add_path(icompaths *p) {
+ if (p->paths == NULL) {
+ if ((p->paths = (icompath **)calloc(sizeof(icompath *), 1 + 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icompaths: calloc failed!\n");
+ return ICOM_SYS;
+ }
+ } else {
+ icompath **npaths;
+ if ((npaths = (icompath **)realloc(p->paths,
+ sizeof(icompath *) * (p->npaths + 2))) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icompaths: realloc failed!\n");
+ return ICOM_SYS;
+ }
+ p->paths = npaths;
+ p->paths[p->npaths+1] = NULL;
+ }
+ if ((p->paths[p->npaths] = calloc(sizeof(icompath), 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icompaths: malloc failed!\n");
+ return ICOM_SYS;
+ }
+ p->npaths++;
+ p->paths[p->npaths] = NULL;
+ return ICOM_OK;
+}
+
+#ifdef ENABLE_SERIAL
+
+/* Add a serial path */
+/* return icom error */
+static int icompaths_add_serial(icompaths *p, char *name, char *spath) {
+ int rv;
+
+ if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ return rv;
+
+ if ((p->paths[p->npaths-1]->name = strdup(name)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
+ return ICOM_SYS;
+ }
+ if ((p->paths[p->npaths-1]->spath = strdup(spath)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
+ return ICOM_SYS;
+ }
+ return ICOM_OK;
+}
+
+#endif /* ENABLE_SERIAL */
+
+#ifdef ENABLE_USB
+
+/* Set an icompath details */
+/* return icom error */
+int icompath_set_usb(a1log *log, icompath *p, char *name, unsigned int vid, unsigned int pid,
+ int nep, struct usb_idevice *usbd, instType itype) {
+ int rv;
+
+ if ((p->name = strdup(name)) == NULL) {
+ a1loge(log, ICOM_SYS, "icompath: strdup failed!\n");
+ return ICOM_SYS;
+ }
+
+ p->nep = nep;
+ p->vid = vid;
+ p->pid = pid;
+ p->usbd = usbd;
+ p->itype = itype;
+
+ return ICOM_OK;
+}
+
+/* Add a usb path. usbd is taken, others are copied. */
+/* return icom error */
+static int icompaths_add_usb(icompaths *p, char *name, unsigned int vid, unsigned int pid,
+ int nep, struct usb_idevice *usbd, instType itype) {
+ int rv;
+
+ if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ return rv;
+
+ return icompath_set_usb(p->log, p->paths[p->npaths-1], name, vid, pid, nep, usbd, itype);
+
+ return ICOM_OK;
+}
+
+/* Add an hid path. hidd is taken, others are copied. */
+/* return icom error */
+static int icompaths_add_hid(icompaths *p, char *name, unsigned int vid, unsigned int pid,
+ int nep, struct hid_idevice *hidd, instType itype) {
+ int rv;
+
+ if ((rv = icompaths_add_path(p)) != ICOM_OK)
+ return rv;
+
+ if ((p->paths[p->npaths-1]->name = strdup(name)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icompaths: strdup failed!\n");
+ return ICOM_SYS;
+ }
+
+ p->paths[p->npaths-1]->nep = nep;
+ p->paths[p->npaths-1]->vid = vid;
+ p->paths[p->npaths-1]->pid = pid;
+ p->paths[p->npaths-1]->hidd = hidd;
+ p->paths[p->npaths-1]->itype = itype;
+
+ return ICOM_OK;
+}
+#endif /* ENABLE_USB */
+
+static void icompaths_del(icompaths *p) {
+ icompaths_clear(p);
+
+ p->log = del_a1log(p->log); /* Unreference it */
+ free(p);
+}
+
+int icompaths_refresh_paths(icompaths *p); /* Defined in platform specific */
+
+/* Allocate an icom paths and set it to the list of available devices */
+/* Return NULL on error */
+icompaths *new_icompaths(a1log *log) {
+ icompaths *p;
+ if ((p = (icompaths *)calloc(sizeof(icompaths), 1)) == NULL) {
+ a1loge(log, ICOM_SYS, "new_icompath: calloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(log);
+
+ p->clear = icompaths_clear;
+ p->refresh = icompaths_refresh_paths;
+ p->get_path = icompaths_get_path;
+#ifdef ENABLE_SERIAL
+ p->add_serial = icompaths_add_serial;
+#endif /* ENABLE_SERIAL */
+#ifdef ENABLE_USB
+ p->add_usb = icompaths_add_usb;
+ p->add_hid = icompaths_add_hid;
+#endif /* ENABLE_USB */
+ p->del = icompaths_del;
+
+ if (icompaths_refresh_paths(p)) {
+ a1loge(log, ICOM_SYS, "new_icompaths: icompaths_refresh_paths failed!\n");
+ return NULL;
+ }
+
+ return p;
+}
+
+
+/* ----------------------------------------------------- */
+
+/* Copy an icompath into an icom */
+/* return icom error */
+static int icom_copy_path_to_icom(icoms *p, icompath *pp) {
+ int rv;
+
+ if ((p->name = strdup(pp->name)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "copy_path_to_icom: malloc name failed\n");
+ return ICOM_SYS;
+ }
+#ifdef ENABLE_SERIAL
+ if (pp->spath != NULL) {
+ if ((p->spath = strdup(pp->spath)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "copy_path_to_icom: malloc spath failed\n");
+ return ICOM_SYS;
+ }
+ } else {
+ p->spath = NULL;
+ }
+#endif /* ENABLE_SERIAL */
+#ifdef ENABLE_USB
+ p->nep = pp->nep;
+ p->vid = pp->vid;
+ p->pid = pp->pid;
+ if ((rv = usb_copy_usb_idevice(p, pp)) != ICOM_OK)
+ return rv;
+ if ((rv = hid_copy_hid_idevice(p, pp)) != ICOM_OK)
+ return rv;
+#endif
+ p->itype = pp->itype;
+
+ return ICOM_OK;
+}
+
+/* Return the port type */
+static icom_type icoms_port_type(
+icoms *p
+) {
+#ifdef ENABLE_USB
+ if (p->hidd != NULL)
+ return icomt_hid;
+ if (p->usbd != NULL)
+ return icomt_usb;
+#endif
+ return icomt_serial;
+}
+
+/* ----------------------------------------------------- */
+
+/* Include the icoms implementation dependent function implementations */
+#ifdef NT
+# include "icoms_nt.c"
+#endif
+#if defined(UNIX)
+# include "icoms_ux.c"
+#endif
+
+/* write and read convenience function */
+/* return icom error */
+static int
+icoms_write_read(
+icoms *p,
+char *wbuf, /* Write puffer */
+char *rbuf, /* Read buffer */
+int bsize, /* Buffer size */
+char tc, /* Terminating characer */
+int ntc, /* Number of terminating characters */
+double tout
+) {
+ int rv = ICOM_OK;
+
+ a1logd(p->log, 8, "icoms_write_read: called with '%s'\n",icoms_fix(wbuf));
+
+ if (p->write == NULL || p->read == NULL) { /* Neither serial nor USB ? */
+ a1loge(p->log, ICOM_NOTS, "icoms_write_read: Neither serial nor USB device!\n");
+ return ICOM_NOTS;
+ }
+
+#ifdef ENABLE_SERIAL
+ /* Flush any stray chars if serial */
+ if (p->usbd == NULL && p->hidd == NULL) {
+ int debug = p->log->debug;
+ if (debug < 8)
+ p->log->debug = 0;
+ for (; rv == ICOM_OK;) /* Until we get a timeout */
+ rv = p->read(p, rbuf, bsize, '\000', 100000, 0.01);
+ p->log->debug = debug;
+ rv = ICOM_OK;
+ }
+#endif
+
+ /* Write the write data */
+ rv = p->write(p, wbuf, tout);
+
+ /* Return error if coms */
+ if (rv != ICOM_OK) {
+ a1logd(p->log, 8, "icoms_write_read: failed - returning 0x%x\n",rv);
+ return rv;
+ }
+
+ /* Read response */
+ rv = p->read(p, rbuf, bsize, tc, ntc, tout);
+
+ a1logd(p->log, 8, "icoms_write_read: returning 0x%x\n",rv);
+
+ return rv;
+}
+
+/* icoms Constructor */
+/* Return NULL on error */
+icoms *new_icoms(
+ icompath *ipath, /* instrument to open */
+ a1log *log /* log to take reference from, NULL for default */
+) {
+ icoms *p;
+ if ((p = (icoms *)calloc(sizeof(icoms), 1)) == NULL) {
+ a1loge(log, ICOM_SYS, "new_icoms: calloc failed!\n");
+ return NULL;
+ }
+
+ if ((p->name = strdup(ipath->name)) == NULL) {
+ a1loge(log, ICOM_SYS, "new_icoms: strdup failed!\n");
+ return NULL;
+ }
+ p->itype = ipath->itype;
+
+ /* Copy ipath info to this icoms */
+ if (icom_copy_path_to_icom(p, ipath)) {
+ free(p);
+ return NULL;
+ }
+
+#ifdef ENABLE_SERIAL
+#ifdef NT
+ p->phandle = NULL;
+#endif
+#ifdef UNIX
+ p->fd = -1;
+#endif
+ p->fc = fc_nc;
+ p->br = baud_nc;
+ p->py = parity_nc;
+ p->sb = stop_nc;
+ p->wl = length_nc;
+#endif /* ENABLE_SERIAL */
+
+ p->lserr = 0;
+ p->tc = -1;
+
+ p->log = new_a1log_d(log);
+ p->debug = p->log->debug; /* Legacy code */
+
+ p->close_port = icoms_close_port;
+
+ p->port_type = icoms_port_type;
+#ifdef ENABLE_SERIAL
+ p->set_ser_port = icoms_set_ser_port;
+#endif /* ENABLE_SERIAL */
+
+ p->write = NULL; /* Serial open or set_methods will set */
+ p->read = NULL;
+ p->write_read = icoms_write_read;
+
+ p->del = icoms_del;
+
+#ifdef ENABLE_USB
+ usb_set_usb_methods(p);
+ hid_set_hid_methods(p);
+#endif /* ENABLE_USB */
+
+ return p;
+}
+
+/* ---------------------------------------------------------------------------------*/
+/* utilities */
+
+/* Emit a "normal" beep */
+void normal_beep() {
+ /* 0msec delay, 1.0KHz for 200 msec */
+ msec_beep(0, 1000, 200);
+}
+
+/* Emit a "good" beep */
+void good_beep() {
+ /* 0msec delay, 1.2KHz for 200 msec */
+ msec_beep(0, 1200, 200);
+}
+
+/* Emit a "bad" double beep */
+void bad_beep() {
+ /* 0msec delay, 800Hz for 200 msec */
+ msec_beep(0, 800, 200);
+ /* 500msec delay, 800Hz for 200 msec */
+ msec_beep(350, 800, 200);
+}
+
+/* Convert control chars to ^[A-Z] notation in a string */
+/* Can be called 5 times without reusing the static buffer */
+char *
+icoms_fix(char *ss) {
+ static unsigned char buf[5][1005];
+ static int ix = 0;
+ unsigned char *d;
+ unsigned char *s = (unsigned char *)ss;
+ if (++ix >= 5)
+ ix = 0;
+ for(d = buf[ix]; (d - buf[ix]) < 1000;) {
+ if (*s < ' ' && *s > '\000') {
+ *d++ = '^';
+ *d++ = *s++ + '@';
+ } else if (*s >= 0x80) {
+ *d++ = '\\';
+ *d++ = '0' + ((*s >> 6) & 0x3);
+ *d++ = '0' + ((*s >> 3) & 0x7);
+ *d++ = '0' + ((*s++ >> 0) & 0x7);
+ } else {
+ *d++ = *s++;
+ }
+ if (s[-1] == '\000')
+ break;
+ }
+ *d++ = '.';
+ *d++ = '.';
+ *d++ = '.';
+ *d++ = '\000';
+ return (char *)buf[ix];
+}
+
+/* Convert a limited binary buffer to a list of hex */
+char *
+icoms_tohex(unsigned char *s, int len) {
+ static char buf[64 * 3 + 10];
+ int i;
+ char *d;
+
+ buf[0] = '\000';
+ for(i = 0, d = buf; i < 64 && i < len; i++, s++) {
+ sprintf(d, "%s%02x", i > 0 ? " " : "", *s);
+ d += strlen(d);
+ }
+ if (i < len)
+ sprintf(d, " ...");
+
+ return buf;
+}
+
diff --git a/spectro/icoms.h b/spectro/icoms.h
new file mode 100644
index 0000000..aac351a
--- /dev/null
+++ b/spectro/icoms.h
@@ -0,0 +1,484 @@
+
+#ifndef ICOMS_H
+
+ /* An abstracted instrument serial and USB communication class. */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/4/20
+ *
+ * Copyright 1996 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from serio.h
+ */
+
+/*
+
+ Notes: The user keyboard/interrupt handling is really broken.
+ It's not noticed most of the time because mostly keys are only
+ hit at the expected times. Serial instruments (X-Rite) are more
+ forgiving in interrupting coms to/from the instrument, as well
+ as being long winded and needing abort. For USB insruments it's
+ not necessarily robust to interrupt or terminate after a give
+ USB transaction. The handling of user commands and aborts
+ is not consistent either, possibly leaving some instruments
+ suseptable to bodgy results due to an unrecognised aborted
+ command. Really, the instrument driver should deterimine
+ at what points an operation can be aborted, and how to recover.
+
+ Because the instrument itself can be a source of commands,
+ some way of waiting for instrument or user input is needed.
+ Could a threaded approach with instrument abort work ?
+
+*/
+
+/* Some MSWin specific stuff is in icoms, and used by usbio & hidio */
+#if defined (NT)
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0501
+# if defined(_WIN32_WINNT)
+# undef _WIN32_WINNT
+# endif
+# define _WIN32_WINNT 0x0501
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#if defined(__APPLE__)
+#include <IOKit/usb/IOUSBLib.h>
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#undef QUIET_MEMCHECKERS /* #define to memset coms read buffers before reading */
+
+typedef struct _icompath icompath;
+typedef struct _icompaths icompaths;
+typedef struct _icoms icoms;
+
+#ifdef ENABLE_USB
+
+struct usb_idevice; /* Forward declarations */
+struct hid_idevice;
+
+/* Information about each end point */
+typedef struct {
+ int valid; /* Flag, nz if this endpoint is valid */
+ int addr; /* Address of end point */
+ int packetsize; /* The max packet size */
+ int type; /* 2 = bulk, 3 = interrupt */
+ int interface; /* interface number */
+ int pipe; /* pipe number (1..N, OS X only) */
+} usb_ep;
+
+#define ICOM_EP_TYPE_BULK 2
+#define ICOM_EP_TYPE_INTERRUPT 3
+
+#include "usbio.h"
+#include "hidio.h"
+
+#endif /* ENABLE_USB */
+
+/* - - - - - - - - - - - - - - - - - - - - */
+
+/* Store information about a possible instrument communication path */
+/* (Note a path doesn't have a reference to icompaths or its' log) */
+struct _icompath{
+ char *name; /* instance description */
+#ifdef ENABLE_SERIAL
+ char *spath; /* Serial device path */
+#endif
+#ifdef ENABLE_USB
+ int nep; /* Number of end points */
+ unsigned int vid, pid; /* USB vendor and product id's */
+ struct usb_idevice *usbd; /* USB port, NULL if not USB */
+ struct hid_idevice *hidd; /* HID port, NULL if not HID */
+#endif /* ENABLE_USB */
+ instType itype; /* Type of instrument if known */
+};
+
+extern icompath icomFakeDevice; /* Declare fake device */
+
+/* The available instrument communication paths */
+struct _icompaths {
+ int npaths; /* Number of paths */
+ icompath **paths; /* Paths if any */
+ a1log *log; /* Verbose, debuge & error logging */
+
+ /* Re-populate the available instrument list */
+ /* return icom error */
+ int (*refresh)(struct _icompaths *p);
+
+#ifdef ENABLE_SERIAL
+ /* Add a serial path. path is copied. Return icom error */
+ int (*add_serial)(struct _icompaths *p, char *name, char *spath);
+#endif /* ENABLE_SERIAL */
+
+#ifdef ENABLE_USB
+ /* Add a usb path. usbd is taken, others are copied. Return icom error */
+ int (*add_usb)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
+ int nep, struct usb_idevice *usbd, instType itype);
+
+ /* Add an hid path. hidd is taken, others are copied. Return icom error */
+ int (*add_hid)(struct _icompaths *p, char *name, unsigned int vid, unsigned int pid,
+ int nep, struct hid_idevice *hidd, instType itype);
+#endif /* ENABLE_USB */
+
+ /* Return the path corresponding to the port number, or NULL if out of range */
+ icompath *(*get_path)(
+ struct _icompaths *p,
+ int port); /* Enumerated port number, 1..n */
+
+ /* Clear all the paths */
+ void (*clear)(struct _icompaths *p);
+
+ /* We're done */
+ void (*del)(struct _icompaths *p);
+
+};
+
+/* Allocate an icom paths and set it to the list of available devices */
+/* Return NULL on error */
+icompaths *new_icompaths(a1log *log);
+
+
+/* - - - - - - - - - - - */
+/* Serial related stuff */
+
+/* Flow control */
+typedef enum {
+ fc_nc = 0, /* not configured/default */
+ fc_none,
+ fc_XonXOff,
+ fc_Hardware
+} flow_control;
+
+/* baud rate available on all systems */
+typedef enum {
+ baud_nc = 0, /* Not Configured */
+ baud_110 = 1,
+ baud_300 = 2,
+ baud_600 = 3,
+ baud_1200 = 4,
+ baud_2400 = 5,
+ baud_4800 = 6,
+ baud_9600 = 7,
+ baud_14400 = 8,
+ baud_19200 = 9,
+ baud_38400 = 10,
+ baud_57600 = 11,
+ baud_115200 = 12
+} baud_rate;
+
+/* Possible parity */
+typedef enum {
+ parity_nc,
+ parity_none,
+ parity_odd,
+ parity_even
+} parity;
+
+/* Possible stop bits */
+typedef enum {
+ stop_nc,
+ stop_1,
+ stop_2
+} stop_bits;
+
+/* Possible word length */
+typedef enum {
+ length_nc,
+ length_5,
+ length_6,
+ length_7,
+ length_8
+} word_length;
+
+/* USB open/handling/buf workaround flags */
+typedef enum {
+ icomuf_none = 0x0000,
+ icomuf_detach = 0x0001, /* Attempt to detach from system driver */
+ icomuf_no_open_clear = 0x0001, /* Don't send a clear_halt after opening the port */
+ icomuf_reset_before_close = 0x0004, /* Reset port before closing it */
+ icomuf_resetep_before_read = 0x0008 /* Do a usb_resetep before each ep read */
+} icomuflags;
+
+/* Type of port */
+typedef enum {
+ icomt_serial, /* Serial port */
+ icomt_usb, /* USB port */
+ icomt_hid /* HID (USB) port */
+} icom_type;
+
+/* Status bits/return values */
+#define ICOM_OK 0x000000 /* No error */
+
+#define ICOM_NOTS 0x001000 /* Not supported */
+#define ICOM_SIZE 0x002000 /* Request/response size exceeded limits */
+#define ICOM_TO 0x004000 /* Timed out */
+#define ICOM_SHORT 0x008000 /* Number of bytes wasn't read/written */
+#define ICOM_CANC 0x010000 /* Was cancelled */
+#define ICOM_SYS 0x020000 /* System error (ie. malloc, system call fail) */
+#define ICOM_VER 0x040000 /* Version error - need up to date kernel driver */
+
+#define ICOM_USBR 0x000100 /* Unspecified USB read error */
+#define ICOM_USBW 0x000200 /* Unspecified USB write error */
+#define ICOM_SERR 0x000400 /* Unspecified Serial read error */
+#define ICOM_SERW 0x000800 /* Unspecified Serial write error */
+
+#define ICOM_XRE 0x000040 /* Xmit shift reg empty */
+#define ICOM_XHE 0x000020 /* Xmit hold reg empty */
+#define ICOM_BRK 0x000010 /* Break detected */
+#define ICOM_FER 0x000008 /* Framing error */
+#define ICOM_PER 0x000004 /* Parity error */
+#define ICOM_OER 0x000002 /* Overun error */
+#define ICOM_DRY 0x000001 /* Recv data ready */
+
+
+
+/* Cancelation token. */
+typedef struct _usb_cancelt usb_cancelt;
+
+#ifdef ENABLE_USB
+void usb_init_cancel(usb_cancelt *p);
+void usb_uninit_cancel(usb_cancelt *p);
+
+#endif
+
+struct _icoms {
+ /* Private: */
+
+ /* Copy of some of icompath contents: */
+ char *name; /* Device description */
+ instType itype; /* Type of instrument if known */
+
+ int is_open; /* Flag, NZ if this port is open */
+
+#ifdef ENABLE_SERIAL
+
+ /* Serial port parameters */
+ char *spath; /* Serial port path */
+#if defined (MSDOS)
+ unsigned short porta; /* Hardware port address */
+#endif
+#if defined (NT)
+ HANDLE phandle; /* NT handle */
+#endif
+#if defined (UNIX) || defined(__APPLE__)
+ int fd; /* Unix file descriptor */
+#endif
+ flow_control fc;
+ baud_rate br;
+ parity py;
+ stop_bits sb;
+ word_length wl;
+
+#endif /* ENABLE_SERIAL */
+
+#ifdef ENABLE_USB
+
+ /* USB port parameters */
+ struct usb_idevice *usbd; /* USB port - copy of ppath->usbd */
+#ifndef NATIVE_USB /* Hmm. could put all this within usb_idevice if not #defined ? */
+# ifdef USE_LIBUSB1
+ libusb_device_handle *usbh;
+# else
+ struct usb_dev_handle *usbh;
+# endif
+#endif
+ icomuflags uflags; /* Bug workaround flags */
+
+ unsigned int vid, pid; /* USB vendor and product id's, used to distiguish instruments */
+ int nconfig; /* Number of configurations */
+ int config; /* Config this info applies to (always 1 ?) */
+ int cconfig; /* Current configuration (0 or 1 ?) */
+ int nifce; /* Number of interfaces */
+ int nep; /* Number of end points */
+ int wr_ep, rd_ep; /* Default end points to use for "serial" read/write */
+ int rd_qa; /* Read quanta size */
+
+ usb_ep ep[32]; /* Information about each end point for general usb i/o */
+
+/* Macro to access end point information */
+#define EPINFO(addr) ep[((addr >> 3) & 0x10) + (addr & 0x0f)]
+
+ /* HID port parameters */
+ struct hid_idevice *hidd; /* HID port - copy of ppath->hidd */
+
+#endif /* ENABLE_USB */
+
+ /* General parameters */
+ int lserr; /* Last serial communication error code */
+ int tc; /* Current serial parser termination character (-1 if not set) */
+ a1log *log; /* Debug & Error log */
+ int debug; /* legacy - Flag, nz to print instrument io info to stderr */
+
+ /* Linked list to automate SIGKILL cleanup */
+ struct _icoms *next;
+
+ /* Public: */
+
+ /* Return the port type */
+ icom_type (*port_type)(struct _icoms *p);
+
+#ifdef ENABLE_SERIAL
+ /* Select the serial communications port and characteristics */
+ /* return icom error */
+ int (*set_ser_port)(
+ struct _icoms *p,
+ flow_control fc, /* Flow control */
+ baud_rate baud,
+ parity parity,
+ stop_bits stop_bits,
+ word_length word_length);
+#endif /* ENABLE_SERIAL */
+
+#ifdef ENABLE_USB
+ /* Select the USB communications port and characteristics */
+ /* return icom error */
+ int (*set_usb_port)(
+ struct _icoms *p,
+ int config, /* Configuration */
+ int wr_ep, /* "serial" write end point */
+ int rd_ep, /* "serial" read end point */
+ icomuflags usbflags, /* Any special handling flags */
+ int retries, /* > 0 if we should retry set_configuration (100msec) */
+ char **pnames /* List of process names to try and kill before opening */
+ );
+
+ /* Select the HID communications port and characteristics */
+ /* return icom error */
+ int (*set_hid_port)(
+ struct _icoms *p,
+ icomuflags usbflags, /* Any special handling flags */
+ int retries, /* > 0 if we should retry set_configuration (100msec) */
+ char **pnames /* List of process names to try and kill before opening */
+ );
+#endif /* ENABLE_USB */
+
+ /* Close the port */
+ void (*close_port)(struct _icoms *p);
+
+ /* "Serial" write the characters in the buffer out */
+ /* Data will be written up to the terminating nul. */
+ /* return icom error */
+ int (*write)(
+ struct _icoms *p,
+ char *buf,
+ double tout); /* Timeout in seconds */
+
+ /* "Serial" read characters into the buffer */
+ /* The returned data will be terminated by a nul. */
+ /* return icom error */
+ int (*read)(
+ struct _icoms *p,
+ char *buf, /* Buffer to store characters read */
+ int bsize, /* Buffer size */
+ char tc, /* Terminating character */
+ int ntc, /* Number of terminating characters */
+ double tout); /* Timeout in seconds */
+
+ /* "Serial" write and read */
+ /* return icom error */
+ int (*write_read)(
+ struct _icoms *p,
+ char *wbuf, /* Write puffer */
+ char *rbuf, /* Read buffer */
+ int bsize, /* Buffer size */
+ char tc, /* Terminating characer */
+ int ntc, /* Number of terminating characters */
+ double tout); /* Timeout in seconds */
+
+ /* For a USB device, do a control message */
+ /* return icom error */
+ int (*usb_control)(struct _icoms *p,
+ int requesttype, /* 8 bit request type (USB bmRequestType) */
+ int request, /* 8 bit request code (USB bRequest) */
+ int value, /* 16 bit value (USB wValue, sent little endian) */
+ int index, /* 16 bit index (USB wIndex, sent little endian) */
+ unsigned char *rwbuf, /* Read or write buffer */
+ int rwsize, /* Bytes to read or write */
+ double tout); /* Timeout in seconds */
+
+ /* For a USB device, do a bulk or interrupt read from an end point */
+ /* return icom error */
+ int (*usb_read)(struct _icoms *p,
+ usb_cancelt *cancelt, /* Optionaly tokem that can be used to cancel */
+ int ep, /* End point address */
+ unsigned char *buf, /* Read buffer */
+ int bsize, /* Bytes to read or write */
+ int *bread, /* Bytes read */
+ double tout); /* Timeout in seconds */
+
+ /* For a USB device, do a bulk or interrupt write to an end point */
+ /* return icom error */
+ int (*usb_write)(struct _icoms *p,
+ usb_cancelt *cancelt, /* Optionaly tokem that can be used to cancel */
+ int ep, /* End point address */
+ unsigned char *wbuf, /* Write buffer */
+ int wsize, /* Bytes to or write */
+ int *bwritten, /* Bytes written */
+ double tout); /* Timeout in seconds */
+
+ /* Cancel a read/write in another thread */
+ /* return icom error */
+ int (*usb_cancel_io)(struct _icoms *p,
+ usb_cancelt *cantelt); /* Cancel handle */
+
+ /* Reset and end point toggle state to 0 */
+ /* return icom error */
+ int (*usb_resetep)(struct _icoms *p,
+ int ep); /* End point address */
+
+ /* Clear an end point halt */
+ /* return icom error */
+ int (*usb_clearhalt)(struct _icoms *p,
+ int ep); /* End point address */
+
+ /* For an HID device, read a message from the device. */
+ /* return icom error */
+ int (*hid_read)(struct _icoms *p,
+ unsigned char *buf, /* Read buffer */
+ int bsize, /* Bytes to read or write */
+ int *bread, /* Bytes read */
+ double tout); /* Timeout in seconds */
+
+ /* For an HID device, write a message to the device */
+ /* return icom error */
+ int (*hid_write)(struct _icoms *p,
+ unsigned char *wbuf, /* Write buffer */
+ int wsize, /* Bytes to or write */
+ int *bwritten, /* Bytes written */
+ double tout); /* Timeout in seconds */
+
+ /* Destroy ourselves */
+ void (*del)(struct _icoms *p);
+
+};
+
+/* Constructor */
+extern icoms *new_icoms(icompath *ipath, a1log *log);
+
+/* - - - - - - - - - - - - - - - - - - -- */
+/* Utilities */
+
+/* Convert control chars to ^[A-Z] notation in a string */
+char *icoms_fix(char *s);
+
+/* Convert a limited binary buffer to a list of hex */
+char *icoms_tohex(unsigned char *s, int len);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define ICOMS_H
+#endif /* ICOMS_H */
diff --git a/spectro/icoms_nt.c b/spectro/icoms_nt.c
new file mode 100644
index 0000000..ef364c4
--- /dev/null
+++ b/spectro/icoms_nt.c
@@ -0,0 +1,563 @@
+
+ /* Windows NT serial I/O class */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/97
+ *
+ * Copyright 1997 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <conio.h>
+
+/* Create and return a list of available serial ports or USB instruments for this system. */
+/* We look at the registry key "HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM" */
+/* to determine serial ports, and use libusb to discover USB instruments. */
+/* Create and return a list of available serial ports or USB instruments for this system */
+/* return icom error */
+int icompaths_refresh_paths(icompaths *p) {
+ int rv, usbend = 0;
+ int i,j;
+ LONG stat;
+ HKEY sch; /* Serial coms handle */
+
+ a1logd(p->log, 8, "icoms_get_paths: called\n");
+
+ /* Clear any existing paths */
+ p->clear(p);
+
+#ifdef ENABLE_USB
+ if ((rv = hid_get_paths(p)) != ICOM_OK)
+ return rv;
+ if ((rv = usb_get_paths(p)) != ICOM_OK)
+ return rv;
+#endif /* ENABLE_USB */
+ usbend = p->npaths;
+
+ a1logd(p->log, 6, "icoms_get_paths: got %d paths, looking up the registry for serial ports\n",p->npaths);
+
+#ifdef ENABLE_SERIAL
+ /* Look in the registry for serial ports */
+ if ((stat = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM",
+ 0, KEY_READ, &sch)) != ERROR_SUCCESS) {
+ a1logd(p->log, 1, "icoms_get_paths: There don't appear to be any serial ports\n");
+ return ICOM_OK; /* Maybe they have USB ports */
+ }
+
+ /* Look at all the values in this key */
+ a1logd(p->log, 8, "icoms_get_paths: looking through all the values in the SERIALCOMM key\n");
+
+ for (i = 0; ; i++) {
+ char valname[500];
+ DWORD vnsize = 500;
+ DWORD vtype;
+ char value[500];
+ DWORD vsize = 500;
+
+ stat = RegEnumValue(
+ sch, /* handle to key to enumerate */
+ i, /* index of subkey to enumerate */
+ valname, /* address of buffer for value name */
+ &vnsize, /* address for size of value name buffer */
+ NULL, /* reserved */
+ &vtype, /* Address of value type */
+ value, /* Address of value buffer */
+ &vsize /* Address of value buffer size */
+ );
+ if (stat == ERROR_NO_MORE_ITEMS) {
+ a1logd(p->log, 8, "icoms_get_paths: got ERROR_NO_MORE_ITEMS\n");
+ break;
+ }
+ if (stat == ERROR_MORE_DATA /* Hmm. Should expand buffer size */
+ || stat != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: RegEnumValue failed with %d\n",stat);
+ break;
+ }
+ valname[500-1] = '\000';
+ value[500-1] = '\000';
+
+ if (vtype != REG_SZ) {
+ a1logw(p->log, "icoms_get_paths: RegEnumValue didn't return stringz type\n");
+ continue;
+ }
+
+ /* Add the port to the list */
+ p->add_serial(p, value, value);
+ a1logd(p->log, 8, "icoms_get_paths: Added path '%s'\n",value);
+ }
+ if ((stat = RegCloseKey(sch)) != ERROR_SUCCESS) {
+ a1logw(p->log, "icoms_get_paths: RegCloseKey failed with %d\n",stat);
+ }
+#endif /* ENABLE_SERIAL */
+
+ /* Sort the COM keys so people don't get confused... */
+ a1logd(p->log, 6, "icoms_get_paths: we now have %d entries and are about to sort them\n",p->npaths);
+ for (i = usbend; i < (p->npaths-1); i++) {
+ for (j = i+1; j < p->npaths; j++) {
+ if (strcmp(p->paths[i]->name, p->paths[j]->name) > 0) {
+ icompath *tt = p->paths[i];
+ p->paths[i] = p->paths[j];
+ p->paths[j] = tt;
+ }
+ }
+ }
+
+ a1logd(p->log, 8, "icoms_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+
+ return ICOM_OK;
+}
+
+
+/* Close the port */
+static void icoms_close_port(icoms *p) {
+ if (p->is_open) {
+#ifdef ENABLE_USB
+ if (p->usbd) {
+ usb_close_port(p);
+ } else if (p->hidd) {
+ hid_close_port(p);
+ }
+#endif
+#ifdef ENABLE_SERIAL
+ if (p->phandle != NULL) {
+ CloseHandle(p->phandle);
+ }
+#endif /* ENABLE_SERIAL */
+ p->is_open = 0;
+ }
+}
+
+#ifdef ENABLE_SERIAL
+
+static int icoms_ser_write(icoms *p, char *wbuf, double tout);
+static int icoms_ser_read(icoms *p, char *rbuf, int bsize, char tc, int ntc, double tout);
+
+/* Set the serial port characteristics */
+/* This always re-opens the port */
+/* return an icom error */
+static int
+icoms_set_ser_port(
+icoms *p,
+flow_control fc,
+baud_rate baud,
+parity parity,
+stop_bits stop,
+word_length word)
+{
+ a1logd(p->log, 8, "icoms_set_ser_port: About to set port characteristics:\n"
+ " Port name = %s\n"
+ " Flow control = %d\n"
+ " Baud Rate = %d\n"
+ " Parity = %d\n"
+ " Stop bits = %d\n"
+ " Word length = %d\n"
+ ,p->name ,fc ,baud ,parity ,stop ,word);
+
+ if (p->is_open)
+ p->close_port(p);
+
+ if (p->port_type(p) == icomt_serial) {
+ DCB dcb;
+
+ a1logd(p->log, 8, "icoms_set_ser_port: Make sure serial port is open\n");
+
+ if (fc != fc_nc)
+ p->fc = fc;
+ if (baud != baud_nc)
+ p->br = baud;
+ if (parity != parity_nc)
+ p->py = parity;
+ if (stop != stop_nc)
+ p->sb = stop;
+ if (word != length_nc)
+ p->wl = word;
+
+ /* Make sure the port is open */
+ if (!p->is_open) {
+ a1logd(p->log, 8, "icoms_set_ser_port: about to open serial port '%s'\n",p->spath);
+
+ if ((p->phandle = CreateFile(
+ p->spath,
+ GENERIC_READ|GENERIC_WRITE,
+ 0, /* Exclusive access */
+ NULL, /* No security */
+ OPEN_EXISTING, /* Does not make sense to create */
+ 0, /* No overlapped I/O */
+ NULL) /* NULL template */
+ ) == INVALID_HANDLE_VALUE) {
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: open port '%s' failed with LastError %d\n",p->spath,GetLastError());
+ return ICOM_SYS;
+ }
+ p->is_open = 1;
+ }
+
+ if (GetCommState(p->phandle, &dcb) == FALSE) {
+ CloseHandle(p->phandle);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: reading state '%s' failed with LastError %d\n",p->spath,GetLastError());
+ return ICOM_SYS;
+ }
+
+ /* Set misc stuff to default */
+ dcb.fBinary = TRUE; /* Binary mode is only one that works */
+ dcb.fOutxCtsFlow = FALSE; /* Not using Cts flow control */
+ dcb.fOutxDsrFlow = FALSE; /* Not using Dsr Flow control */
+ dcb.fDtrControl = DTR_CONTROL_ENABLE; /* Enable DTR during connection */
+ dcb.fDsrSensitivity = FALSE; /* Not using Dsr Flow control */
+ dcb.fTXContinueOnXoff = TRUE; /* */
+ dcb.fOutX = FALSE; /* No default Xon/Xoff flow control */
+ dcb.fInX = FALSE; /* No default Xon/Xoff flow control */
+ dcb.fErrorChar = FALSE;
+ dcb.fNull = FALSE;
+ dcb.fRtsControl = RTS_CONTROL_ENABLE; /* Turn RTS on during connection */
+ dcb.fAbortOnError = TRUE;
+
+ switch (p->fc) {
+ case fc_nc:
+ CloseHandle(p->phandle);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal flow control %d\n",p->fc);
+ return ICOM_SYS;
+ case fc_XonXOff:
+ /* Use Xon/Xoff bi-directional flow control */
+ dcb.fOutX = TRUE;
+ dcb.fInX = TRUE;
+ dcb.XonChar = 0x11; /* ^Q */
+ dcb.XoffChar = 0x13; /* ^S */
+ // dcb.fTXContinueOnXoff = FALSE; /* Stop transmitting if input is full */
+ break;
+ case fc_Hardware:
+ /* Use RTS/CTS bi-directional flow control */
+ dcb.fOutxCtsFlow = TRUE;
+ dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
+ break;
+ default:
+ break;
+ }
+
+ switch (p->py) {
+ case parity_nc:
+ CloseHandle(p->phandle);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal parity setting %d\n",p->py);
+ return ICOM_SYS;
+ case parity_none:
+ dcb.fParity = FALSE;
+ dcb.Parity = NOPARITY;
+ break;
+ case parity_odd:
+ dcb.fParity = TRUE;
+ dcb.Parity = ODDPARITY;
+ break;
+ case parity_even:
+ dcb.fParity = TRUE;
+ dcb.Parity = EVENPARITY;
+ break;
+ default:
+ break;
+ }
+
+ switch (p->sb) {
+ case stop_nc:
+ CloseHandle(p->phandle);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal stop bits %d\n",p->sb);
+ return ICOM_SYS;
+ case stop_1:
+ dcb.StopBits = ONESTOPBIT;
+ break;
+ case stop_2:
+ dcb.StopBits = TWOSTOPBITS;
+ break;
+ }
+
+ switch (p->wl) {
+ case length_nc:
+ CloseHandle(p->phandle);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal word length %d\n",p->wl);
+ return ICOM_SYS;
+ case length_5:
+ dcb.ByteSize = 5;
+ break;
+ case length_6:
+ dcb.ByteSize = 6;
+ break;
+ case length_7:
+ dcb.ByteSize = 7;
+ break;
+ case length_8:
+ dcb.ByteSize = 8;
+ break;
+ }
+
+ switch (p->br) {
+ case baud_110:
+ dcb.BaudRate = CBR_110;
+ break;
+ case baud_300:
+ dcb.BaudRate = CBR_300;
+ break;
+ case baud_600:
+ dcb.BaudRate = CBR_600;
+ break;
+ case baud_1200:
+ dcb.BaudRate = CBR_1200;
+ break;
+ case baud_2400:
+ dcb.BaudRate = CBR_2400;
+ break;
+ case baud_4800:
+ dcb.BaudRate = CBR_4800;
+ break;
+ case baud_9600:
+ dcb.BaudRate = CBR_9600;
+ break;
+ case baud_14400:
+ dcb.BaudRate = CBR_14400;
+ break;
+ case baud_19200:
+ dcb.BaudRate = CBR_19200;
+ break;
+ case baud_38400:
+ dcb.BaudRate = CBR_38400;
+ break;
+ case baud_57600:
+ dcb.BaudRate = CBR_57600;
+ break;
+ case baud_115200:
+ dcb.BaudRate = CBR_115200;
+ break;
+ default:
+ CloseHandle(p->phandle);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal baud rate! (0x%x)\n",p->br);
+ return ICOM_SYS;
+ }
+
+ PurgeComm(p->phandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
+
+ if (!SetCommState(p->phandle, &dcb)) {
+ CloseHandle(p->phandle);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: SetCommState failed with LastError %d\n",
+ GetLastError());
+ return ICOM_SYS;
+ }
+
+ PurgeComm(p->phandle, PURGE_TXCLEAR | PURGE_RXCLEAR);
+
+ p->write = icoms_ser_write;
+ p->read = icoms_ser_read;
+
+ }
+ a1logd(p->log, 8, "icoms_set_ser_port: port characteristics set ok\n");
+
+ return ICOM_OK;
+}
+
+/* ---------------------------------------------------------------------------------*/
+/* Serial write/read */
+
+/* Write the characters in the buffer out */
+/* Data will be written up to the terminating nul */
+/* Return relevant error status bits */
+/* Set the icoms lserr value */
+static int
+icoms_ser_write(
+icoms *p,
+char *wbuf,
+double tout)
+{
+ COMMTIMEOUTS tmo;
+ DWORD wbytes;
+ int c, len;
+ long toc, i, top; /* Timout count, counter, timeout period */
+ int rv = ICOM_OK;
+
+ a1logd(p->log, 8, "icoms_ser_write: About to write '%s' ",icoms_fix(wbuf));
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_write: device not initialised\n");
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ len = strlen(wbuf);
+ tout *= 1000.0; /* Timout in msec */
+
+ top = 100; /* Timeout period in msecs */
+ toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */
+ if (toc < 1)
+ toc = 1;
+
+ /* Set the timout value */
+ tmo.ReadIntervalTimeout = top;
+ tmo.ReadTotalTimeoutMultiplier = 0;
+ tmo.ReadTotalTimeoutConstant = top;
+ tmo.WriteTotalTimeoutMultiplier = top;
+ tmo.WriteTotalTimeoutConstant = 0;
+ if (!SetCommTimeouts(p->phandle, &tmo)) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_write: SetCommTimeouts failed with %d\n",GetLastError());
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ /* Until data is all written or we time out */
+ for (i = toc; i > 0 && len > 0;) {
+ if (!WriteFile(p->phandle, wbuf, len, &wbytes, NULL)) {
+ DWORD errs;
+ if (!ClearCommError(p->phandle,&errs,NULL))
+ error("Write to COM port failed, and Clear error failed");
+ if (errs & CE_BREAK)
+ rv |= ICOM_BRK;
+ if (errs & CE_FRAME)
+ rv |= ICOM_FER;
+ if (errs & CE_RXPARITY)
+ rv |= ICOM_PER;
+ if (errs & CE_RXOVER)
+ rv |= ICOM_OER;
+ break;
+ } else if (wbytes == 0) {
+ i--; /* Timeout */
+ } else if (wbytes > 0) { /* Account for bytes done */
+ i = toc;
+ len -= wbytes;
+ wbuf += len;
+ }
+ }
+ if (i <= 0) { /* Timed out */
+ rv |= ICOM_TO;
+ }
+ a1logd(p->log, 8, "icoms_ser_write: returning ICOM err 0x%x\n",rv);
+
+ p->lserr = rv;
+ return rv;
+}
+
+
+/* Read characters into the buffer */
+/* Return string will be terminated with a nul */
+static int
+icoms_ser_read(
+icoms *p,
+char *rbuf, /* Buffer to store characters read */
+int bsize, /* Buffer size */
+char tc, /* Terminating characer */
+int ntc, /* Number of terminating characters */
+double tout /* Time out in seconds */
+) {
+ COMMTIMEOUTS tmo;
+ DWORD rbytes;
+ int c, j;
+ long toc, i, top; /* Timout count, counter, timeout period */
+ char *rrbuf = rbuf; /* Start of return buffer */
+ DCB dcb;
+ int rv = ICOM_OK;
+
+ if (p->phandle == NULL) {
+ a1loge(p->log, ICOM_SYS, "icoms_read: device not initialised\n");
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ if (bsize < 3) {
+ a1loge(p->log, ICOM_SYS, "icoms_read: given too small a buffer\n");
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+#ifdef NEVER
+ /* The Prolific 2303 USB<->serial seems to choke on this, */
+ /* so we just put up with a 100msec delay at the end of each */
+ /* reply. */
+ if (GetCommState(p->phandle, &dcb) == FALSE) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_read: GetCommState failed with %d\n",GetLastError());
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ dcb.EofChar = tc;
+
+ if (!SetCommState(p->phandle, &dcb)) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_read: SetCommState failed %d\n",GetLastError());
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+#endif
+ p->tc = tc;
+
+ tout *= 1000.0; /* Timout in msec */
+ bsize--; /* Allow space for null */
+
+ top = 100; /* Timeout period in msecs */
+ toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */
+ if (toc < 1)
+ toc = 1;
+
+ /* Set the timout value */
+ tmo.ReadIntervalTimeout = top;
+ tmo.ReadTotalTimeoutMultiplier = 0;
+ tmo.ReadTotalTimeoutConstant = top;
+ tmo.WriteTotalTimeoutMultiplier = top;
+ tmo.WriteTotalTimeoutConstant = 0;
+ if (!SetCommTimeouts(p->phandle, &tmo)) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_read: SetCommTimeouts failed with %d\n",GetLastError());
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ /* Until data is all read or we time out */
+ for (i = toc, j = 0; i > 0 && bsize > 1 && j < ntc ;) {
+ if (!ReadFile(p->phandle, rbuf, bsize, &rbytes, NULL)) {
+ DWORD errs;
+ if (!ClearCommError(p->phandle,&errs,NULL))
+ error("Read from COM port failed, and Clear error failed");
+ if (errs & CE_BREAK)
+ rv |= ICOM_BRK;
+ if (errs & CE_FRAME)
+ rv |= ICOM_FER;
+ if (errs & CE_RXPARITY)
+ rv |= ICOM_PER;
+ if (errs & CE_RXOVER)
+ rv |= ICOM_OER;
+ break;
+ } else if (rbytes == 0) {
+ i--; /* Timeout */
+ } else if (rbytes > 0) { /* Account for bytes done */
+ i = toc;
+ bsize -= rbytes;
+ while(rbytes--) { /* Count termination characters */
+ if (*rbuf++ == tc)
+ j++;
+ }
+ }
+ }
+ if (i <= 0) { /* timed out */
+ rv |= ICOM_TO;
+ }
+ *rbuf = '\000';
+ a1logd(p->log, 8, "icoms_ser_read: returning '%s' ICOM err 0x%x\n",icoms_fix(rrbuf),rv);
+
+ p->lserr = rv;
+ return rv;
+}
+
+#endif /* ENABLE_SERIAL */
+/* ---------------------------------------------------------------------------------*/
+
+
+/* Destroy ourselves */
+static void
+icoms_del(icoms *p) {
+ a1logd(p->log, 8, "icoms_del: called\n");
+ if (p->is_open) {
+ a1logd(p->log, 8, "icoms_del: closing port\n");
+ p->close_port(p);
+ }
+#ifdef ENABLE_USB
+ usb_del_usb(p);
+ hid_del_hid(p);
+#endif
+ p->log = del_a1log(p->log); /* unref */
+ free (p);
+}
+
diff --git a/spectro/icoms_ux.c b/spectro/icoms_ux.c
new file mode 100644
index 0000000..722492e
--- /dev/null
+++ b/spectro/icoms_ux.c
@@ -0,0 +1,739 @@
+
+ /* Unix icoms and serial I/O class */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 18/11/2000
+ *
+ * Copyright 1997 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ TTBD:
+ */
+
+#include <sys/types.h> /* Include sys/select.h ? */
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <dirent.h>
+#include <string.h>
+
+/* select() defined, but not poll(), so emulate poll() */
+#if defined(FD_CLR) && !defined(POLLIN)
+#include "pollem.h"
+#define poll_x pollem
+#else
+#include <sys/poll.h> /* Else assume poll() is native */
+#define poll_x poll
+#endif
+
+#ifdef __APPLE__
+//#include <stdbool.h>
+#include <sys/sysctl.h>
+#include <sys/param.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/serial/IOSerialKeys.h>
+#include <IOKit/IOBSD.h>
+#include <mach/mach_init.h>
+#include <mach/task_policy.h>
+#endif /* __APPLE__ */
+
+/* Create and return a list of available serial ports or USB instruments for this system */
+/* return icom error */
+int icompaths_refresh_paths(icompaths *p) {
+ int rv, usbend = 0;
+ int i,j;
+
+ a1logd(p->log, 8, "icoms_get_paths: called\n");
+
+ /* Clear any existing paths */
+ p->clear(p);
+
+#ifdef ENABLE_USB
+ if ((rv = hid_get_paths(p)) != ICOM_OK)
+ return rv;
+ if ((rv = usb_get_paths(p)) != ICOM_OK)
+ return rv;
+#endif /* ENABLE_USB */
+ usbend = p->npaths;
+
+#ifdef ENABLE_SERIAL
+#ifdef __APPLE__
+ /* Search the OSX registry for serial ports */
+ {
+ kern_return_t kstat;
+ mach_port_t mp; /* Master IO port */
+ CFMutableDictionaryRef sdict; /* Serial Port dictionary */
+ io_iterator_t mit; /* Matching itterator */
+ io_object_t ioob; /* Serial object found */
+
+ /* Get dictionary of serial ports */
+ if ((sdict = IOServiceMatching(kIOSerialBSDServiceValue)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "IOServiceMatching returned a NULL dictionary\n");
+ return ICOM_OK;
+ }
+
+ /* Set value to match to RS232 type serial */
+ CFDictionarySetValue(sdict, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDRS232Type));
+
+ /* Init itterator to find matching types. Consumes sdict reference */
+ if ((kstat = IOServiceGetMatchingServices(kIOMasterPortDefault, sdict, &mit))
+ != KERN_SUCCESS) {
+ a1loge(p->log, ICOM_SYS, "IOServiceGetMatchingServices returned %d\n", kstat);
+ return ICOM_SYS;
+ }
+
+ /* Find all the matching serial ports */
+ for (;;) {
+ char pname[100];
+
+ CFTypeRef dfp; /* Device file path */
+
+ if ((ioob = IOIteratorNext(mit)) == 0)
+ break;
+
+ /* Get the callout device's path (/dev/cu.xxxxx). */
+ if ((dfp = IORegistryEntryCreateCFProperty(ioob, CFSTR(kIOCalloutDeviceKey),
+ kCFAllocatorDefault, 0)) == NULL)
+ goto continue1;
+
+ /* Convert from CF string to C string */
+ if (!CFStringGetCString(dfp, pname, 100, kCFStringEncodingASCII))
+ goto continue2;
+
+ /* Ignore infra red port or Bluetooth, or any other noise */
+ if (strstr(pname, "IrDA") != NULL
+ || strstr(pname, "Dialup") != NULL
+ || strstr(pname, "Bluetooth") != NULL)
+ goto continue2;
+
+ /* Add the port to the list */
+ p->add_serial(p, pname, pname);
+ a1logd(p->log, 8, "icoms_get_paths: Added path '%s'\n",pname);
+
+ continue2:
+ CFRelease(dfp);
+ continue1:
+ IOObjectRelease(ioob); /* Release found object */
+ }
+ IOObjectRelease(mit); /* Release the itterator */
+ }
+#else
+ /* Other UNIX like systems */
+ /* Many are crude and list every available device name, whether */
+ /* it's usable or not. Do any UNIX systems have a mechanism for listing */
+ /* serial ports ?? */
+
+ /* On Linux, the list in /proc/tty/driver/serial may indicate */
+ /* which are real or not (if "uart:unknown" then not real) */
+ /* e.g.:
+
+ 0: uart:16550A port:000003F8 irq:4 tx:3 rx:1755 brk:1 RTS|DTR
+ 1: uart:16550A port:000002F8 irq:3 tx:11 rx:3 brk:3
+ 2: uart:unknown port:000003E8 irq:4
+ 3: uart:unknown port:000002E8 irq:3
+ 4: uart:unknown port:00000000 irq:0
+ 5: uart:unknown port:00000000 irq:0
+ 6: uart:unknown port:00000000 irq:0
+ 7: uart:unknown port:00000000 irq:0
+
+ but the permissions don't allow looking at this.
+ */
+ /* (This info is similar to what is returned by "setserial -g /dev/ttyS*", */
+ /* and "setserial -gb /dev/ttyS*" returns just the real ports.) */
+ /* None of this can distinguish if one is the mouse. */
+
+ /* From "QTSerialPort": */
+ /*
+ Constant Used By Naming Convention
+ ---------- ------------- ------------------------
+ _TTY_WIN_ Windows COM1, COM2
+ _TTY_IRIX_ SGI/IRIX /dev/ttyf1, /dev/ttyf2
+ _TTY_HPUX_ HP-UX /dev/tty1p0, /dev/tty2p0
+ _TTY_SUN_ SunOS/Solaris /dev/ttya, /dev/ttyb
+ _TTY_DIGITAL_ Digital UNIX /dev/tty01, /dev/tty02
+ _TTY_FREEBSD_ FreeBSD /dev/ttyd0, /dev/ttyd1
+ _TTY_LINUX_ Linux /dev/ttyS0, /dev/ttyS1
+ <none> Linux /dev/ttyS0, /dev/ttyS1
+ Linux /dev/ttyUSB0, /dev/ttyUSB1
+ */
+
+ /*
+ "Most program set a lock in /var/lock/LCK..tty<XX> on Linux ?
+ <http://sunsite.ualberta.ca/LDP/LDP/nag2/x-087-2-serial.devices.html>
+ <http://docs.freebsd.org/info/uucp/uucp.info.UUCP_Lock_Files.html>
+
+ We should really use the lock files to avoid treading on
+ other programs toes. We assume at the moment that the user
+ only picks a serial port with an instrument on it.
+ */
+
+ /* Search for devices that match the pattern /dev/ttyS[0-9]* and /dev/ttyUSB* */
+ {
+ DIR *dd;
+ struct dirent *de;
+ char *dirn = "/dev/";
+
+ if ((dd = opendir(dirn)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "failed to open directory \"%s\"\n",dirn);
+ return ICOM_OK;
+ }
+
+ for (;;) {
+ int fd;
+ char *dpath;
+
+ if ((de = readdir(dd)) == NULL)
+ break;
+
+ if (!(
+#ifdef __FreeBSD__
+ /* This should match uart & USB devs. */
+ ( strncmp (de->d_name, "cua", 3) == 0
+ && strlen (de->d_name) < 7)
+#else
+ /* Presumably Linux.. */
+ ( strncmp(de->d_name, "ttyS", 4) == 0
+ && de->d_name[4] >= '0' && de->d_name[4] <= '9')
+ || ( strncmp(de->d_name, "ttyUSB", 5) == 0)
+#endif
+ ))
+ continue;
+
+ if ((dpath = (char *)malloc(strlen(dirn) + strlen(de->d_name) + 1)) == NULL) {
+ closedir(dd);
+ a1loge(p->log, ICOM_SYS, "icompaths_refresh_paths() malloc failed!\n");
+ return ICOM_SYS;
+ }
+ strcpy(dpath, dirn);
+ strcat(dpath, de->d_name);
+
+ /* See if the serial port is real */
+ if (strncmp(de->d_name, "ttyUSB", 5) != 0) {
+
+ /* Hmm. This is probably a bad idea - it can upset other */
+ /* programs that use the serial ports ? */
+ if ((fd = open(dpath, O_RDONLY | O_NOCTTY | O_NONBLOCK)) < 0) {
+ a1logd(p->log, 8, "icoms_get_paths: failed to open serial \"%s\" - not real\n",dpath);
+ free(dpath);
+ continue;
+ }
+ /* On linux we could do a
+ struct serial_struct serinfo;
+
+ serinfo.reserved_char[0] = 0;
+
+ if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0
+ || serinfo.type == PORT_UNKNOWN) {
+ free(dpath);
+ continue;
+ }
+
+ */
+ close(fd);
+ }
+ a1logd(p->log, 8, "icoms_get_paths: open'd serial \"%s\" - assume real\n",dpath);
+
+ /* Add the path to the list */
+ p->add_serial(p, dpath, dpath);
+ a1logd(p->log, 8, "icoms_get_paths: Added path '%s'\n",dpath);
+ }
+ closedir(dd);
+ }
+#endif /* ! __APPLE__ */
+#endif /* ENABLE_SERIAL */
+
+ /* Sort the serial /dev keys so people don't get confused... */
+ /* Sort USB serial ports ahead of normal serial ports. */
+ for (i = usbend; i < (p->npaths-1); i++) {
+ for (j = i+1; j < p->npaths; j++) {
+ if ((strncmp(p->paths[i]->name, "/dev/ttyUSB", 11) ||
+ strncmp(p->paths[j]->name, "/dev/ttyS", 9)) &&
+ strcmp(p->paths[i]->name, p->paths[j]->name) > 0) {
+ icompath *tt = p->paths[i];
+ p->paths[i] = p->paths[j];
+ p->paths[j] = tt;
+ }
+ }
+ }
+ return ICOM_OK;
+}
+
+/* -------------------------------------------------------------------- */
+
+/* Close the port */
+static void icoms_close_port(icoms *p) {
+ if (p->is_open) {
+#ifdef ENABLE_USB
+ if (p->usbd) {
+ usb_close_port(p);
+ } else if (p->hidd) {
+ hid_close_port(p);
+ }
+#endif
+#ifdef ENABLE_SERIAL
+ if (p->fd != -1) {
+ close(p->fd);
+ p->fd = -1;
+ }
+#endif /* ENABLE_SERIAL */
+ p->is_open = 0;
+ }
+}
+
+#ifdef ENABLE_SERIAL
+
+static int icoms_ser_write(icoms *p, char *wbuf, double tout);
+static int icoms_ser_read(icoms *p, char *rbuf, int bsize, char tc, int ntc, double tout);
+
+/* Set the serial port number and characteristics */
+/* This always re-opens the port */
+/* return icom error */
+static int
+icoms_set_ser_port(
+icoms *p,
+flow_control fc,
+baud_rate baud,
+parity parity,
+stop_bits stop,
+word_length word
+) {
+ int rv;
+ struct termios tio;
+ speed_t speed = 0;
+
+ a1logd(p->log, 8, "icoms_set_ser_port: About to set port characteristics:\n"
+ " Port name = %s\n"
+ " Flow control = %d\n"
+ " Baud Rate = %d\n"
+ " Parity = %d\n"
+ " Stop bits = %d\n"
+ " Word length = %d\n"
+ ,p->name ,fc ,baud ,parity ,stop ,word);
+
+
+ if (p->is_open) /* Close it and re-open it */
+ p->close_port(p);
+
+ if (p->port_type(p) == icomt_serial) {
+
+ a1logd(p->log, 8, "icoms_set_ser_port: Make sure serial port is open\n");
+
+ if (fc != fc_nc)
+ p->fc = fc;
+ if (baud != baud_nc)
+ p->br = baud;
+ if (parity != parity_nc)
+ p->py = parity;
+ if (stop != stop_nc)
+ p->sb = stop;
+ if (word != length_nc)
+ p->wl = word;
+
+ /* Make sure the port is open */
+ if (!p->is_open) {
+
+ a1logd(p->log, 8, "icoms_set_ser_port: about to open serial port '%s'\n",p->spath);
+
+ if ((p->fd = open(p->spath, O_RDWR | O_NOCTTY )) < 0) {
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: open port '%s' failed with %d (%s)\n",p->spath,p->fd,strerror(errno));
+ return ICOM_SYS;
+ }
+ /* O_NONBLOCK O_SYNC */
+ p->is_open = 1;
+ }
+
+ if ((rv = tcgetattr(p->fd, &tio)) < 0) {
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: tcgetattr on '%s' failed with %d (%s)\n",p->spath,p->fd,strerror(errno));
+ return ICOM_SYS;
+ }
+
+ /* Clear everything in the tio, and just set what we want */
+ memset(&tio, 0, sizeof(struct termios));
+
+ /* Turn on basic configuration: */
+ tio.c_iflag |= (
+ IGNBRK /* Ignore Break */
+ );
+
+ tio.c_oflag |= ( 0 );
+
+ tio.c_cflag |= (
+ CREAD /* Enable the receiver */
+ | CLOCAL /* Ignore modem control lines */
+ );
+
+ tio.c_lflag |= (
+ 0 /* Non-canonical input mode */
+ );
+
+ /* And configure: */
+ tio.c_cc[VTIME] = 1; /* 0.1 second timeout */
+ tio.c_cc[VMIN] = 64; /* Comfortably less than _PF_MAX_INPUT */
+
+ switch (p->fc) {
+ case fc_nc:
+ close(p->fd);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal flow control %d\n",p->fc);
+ return ICOM_SYS;
+ case fc_XonXOff:
+ /* Use Xon/Xoff bi-directional flow control */
+ tio.c_iflag |= IXON; /* Enable XON/XOFF flow control on output */
+ tio.c_iflag |= IXOFF; /* Enable XON/XOFF flow control on input */
+ tio.c_cc[VSTART] = 0x11; /* ^Q */
+ tio.c_cc[VSTOP] = 0x13; /* ^S */
+ break;
+ case fc_Hardware:
+ /* Use RTS/CTS bi-directional flow control */
+#ifdef __APPLE__
+ tio.c_cflag |= CCTS_OFLOW;
+ tio.c_cflag |= CRTS_IFLOW;
+#else
+ tio.c_cflag |= CRTSCTS;
+#endif
+ break;
+ default:
+ break;
+ }
+
+ switch (p->py) {
+ case parity_nc:
+ close(p->fd);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal parity setting %d\n",p->py);
+ return ICOM_SYS;
+ break;
+ case parity_none:
+ tio.c_iflag &= ~INPCK; /* Disable input parity checking */
+ break;
+ case parity_odd:
+ tio.c_iflag |= INPCK; /* Enable input parity checking */
+ tio.c_cflag |= PARENB; /* Enable input and output parity checking */
+ tio.c_cflag |= PARODD; /* Input and output parity is odd */
+ break;
+ case parity_even:
+ tio.c_iflag |= INPCK; /* Enable input parity checking */
+ tio.c_cflag |= PARENB; /* Enable input and output parity checking */
+ break;
+ }
+
+ switch (p->sb) {
+ case stop_nc:
+ close(p->fd);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal stop bits %d\n",p->sb);
+ return ICOM_SYS;
+ case stop_1:
+ break; /* defaults to 1 */
+ case stop_2:
+ tio.c_cflag |= CSTOPB;
+ break;
+ }
+
+ switch (p->wl) {
+ case length_nc:
+ close(p->fd);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal word length %d\n",p->wl);
+ return ICOM_SYS;
+ case length_5:
+ tio.c_cflag |= CS5;
+ break;
+ case length_6:
+ tio.c_cflag |= CS6;
+ break;
+ case length_7:
+ tio.c_cflag |= CS7;
+ break;
+ case length_8:
+ tio.c_cflag |= CS8;
+ break;
+ }
+
+ /* Set the baud rate */
+ switch (p->br) {
+ case baud_110:
+ speed = B110;
+ break;
+ case baud_300:
+ speed = B300;
+ break;
+ case baud_600:
+ speed = B600;
+ break;
+ case baud_1200:
+ speed = B1200;
+ break;
+ case baud_2400:
+ speed = B2400;
+ break;
+ case baud_4800:
+ speed = B4800;
+ break;
+ case baud_9600:
+ speed = B9600;
+ break;
+ case baud_19200:
+ speed = B19200;
+ break;
+ case baud_38400:
+ speed = B38400;
+ break;
+ case baud_57600:
+ speed = B57600;
+ break;
+ case baud_115200:
+ speed = B115200;
+ break;
+ default:
+ close(p->fd);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: illegal baud rate! (0x%x)\n",p->br);
+ return ICOM_SYS;
+ }
+
+ tcflush(p->fd, TCIOFLUSH); /* Discard any current in/out data */
+
+ if ((rv = cfsetispeed(&tio, speed)) < 0) {
+ close(p->fd);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: cfsetispeed failed with '%s'\n", strerror(errno));
+ return ICOM_SYS;
+ }
+ if ((rv = cfsetospeed(&tio, speed)) < 0) {
+ close(p->fd);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: cfsetospeed failed with '%s'\n", strerror(errno));
+ return ICOM_SYS;
+ }
+
+ /* Make change immediately */
+ if ((rv = tcsetattr(p->fd, TCSANOW, &tio)) < 0) {
+ close(p->fd);
+ a1loge(p->log, ICOM_SYS, "icoms_set_ser_port: tcsetattr failed with '%s'\n", strerror(errno));
+ return ICOM_SYS;
+ }
+
+ tcflush(p->fd, TCIOFLUSH); /* Discard any current in/out data */
+
+ p->write = icoms_ser_write;
+ p->read = icoms_ser_read;
+
+ }
+ a1logd(p->log, 8, "icoms_set_ser_port: port characteristics set ok\n");
+
+ return ICOM_OK;
+}
+
+/* ---------------------------------------------------------------------------------*/
+/* Serial write/read */
+
+/* Write the characters in the buffer out */
+/* Data will be written up to the terminating nul */
+/* Return relevant error status bits */
+/* Set the icoms lserr value */
+static int
+icoms_ser_write(
+icoms *p,
+char *wbuf,
+double tout
+) {
+ int rv, retrv = ICOM_OK;
+ int len, wbytes;
+ long toc, i, top; /* Timout count, counter, timeout period */
+ struct pollfd pa[1]; /* Poll array to monitor serial write and stdin */
+ int nfd = 1; /* Number of fd's to poll */
+ struct termios origs, news;
+
+ a1logd(p->log, 8, "icoms_ser_write: About to write '%s' ",icoms_fix(wbuf));
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_write: device not initialised\n");
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ /* Setup to wait for serial output not block */
+ pa[0].fd = p->fd;
+ pa[0].events = POLLOUT;
+ pa[0].revents = 0;
+
+ /* Until timed out, aborted, or transmitted */
+ len = strlen(wbuf);
+ tout *= 1000.0; /* Timout in msec */
+
+ top = 100; /* Timeout period in msecs */
+ toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */
+ if (toc < 1)
+ toc = 1;
+
+ /* Until data is all written, we time out, or the user aborts */
+ for(i = toc; i > 0 && len > 0;) {
+ if (poll_x(pa, nfd, top) > 0) {
+ if (pa[0].revents != 0) {
+ if (pa[0].revents != POLLOUT) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_write: poll returned "
+ "unexpected value 0x%x",pa[0].revents);
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ /* We can write it without blocking */
+ if ((wbytes = write(p->fd, wbuf, len)) < 0) {
+ retrv |= ICOM_SERW;
+ break;
+ } else if (wbytes > 0) {
+ i = toc;
+ len -= wbytes;
+ wbuf += wbytes;
+ }
+ }
+ } else {
+ i--; /* timeout (or error!) */
+ }
+ }
+ if (i <= 0) { /* Timed out */
+ retrv |= ICOM_TO;
+ }
+
+ a1logd(p->log, 8, "icoms_ser_write: returning ICOM err 0x%x\n",retrv);
+
+ p->lserr = retrv;
+ return retrv;
+}
+
+/* Read characters into the buffer */
+/* Return string will be terminated with a nul */
+/* return icom error */
+static int
+icoms_ser_read(
+icoms *p,
+char *rbuf, /* Buffer to store characters read */
+int bsize, /* Buffer size */
+char tc, /* Terminating characer */
+int ntc, /* Number of terminating characters */
+double tout /* Time out in seconds */
+) {
+ int rv, retrv = ICOM_OK;
+ int rbytes;
+ long j, toc, i, top; /* Timout count, counter, timeout period */
+ struct pollfd pa[1]; /* Poll array to monitor serial read and stdin */
+ int nfd = 1; /* Number of fd's to poll */
+ struct termios origs, news;
+ char *rrbuf = rbuf; /* Start of return buffer */
+
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_read: device not initialised\n");
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ if (bsize < 3) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_read: given too small a buffer\n");
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+#ifdef NEVER
+ /* The Prolific 2303 USB<->serial seems to choke on this, */
+ /* so we just put up with the 100msec delay at the end of each reply. */
+ if (tc != p->tc) { /* Set the termination char */
+ struct termios tio;
+
+ if (tcgetattr(p->fd, &tio) < 0) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_read: tcgetattr failed with '%s' on '%s'\n",
+ strerror(errno),p->spath);
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ tio.c_cc[VEOL] = tc;
+
+ /* Make change immediately */
+ tcflush(p->fd, TCIFLUSH);
+ if (tcsetattr(p->fd, TCSANOW, &tio) < 0) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_read: tcsetattr failed with '%s' on '%s'\n",
+ strerror(errno),p->spath);
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ p->tc = tc;
+ }
+#endif
+
+ /* Wait for serial input to have data */
+ pa[0].fd = p->fd;
+ pa[0].events = POLLIN | POLLPRI;
+ pa[0].revents = 0;
+
+ bsize--; /* Allow space for null */
+ tout *= 1000.0; /* Timout in msec */
+
+ top = 100; /* Timeout period in msecs */
+ toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */
+ if (toc < 1)
+ toc = 1;
+
+ /* Until data is all read, we time out, or the user aborts */
+ for(i = toc, j = 0; i > 0 && bsize > 1 && j < ntc ;) {
+
+ if (poll_x(pa, nfd, top) > 0) {
+ if (pa[0].revents != 0) {
+ if (pa[0].revents != POLLIN && pa[0].revents != POLLPRI) {
+ a1loge(p->log, ICOM_SYS, "icoms_ser_read: poll on serin returned "
+ "unexpected value 0x%x",pa[0].revents);
+ p->lserr = rv = ICOM_SYS;
+ return rv;
+ }
+
+ /* We have data to read from input */
+ if ((rbytes = read(p->fd, rbuf, bsize)) < 0) {
+ retrv |= ICOM_SERR;
+ break;
+ } else if (rbytes > 0) {
+ i = toc; /* Reset time */
+ bsize -= rbytes;
+ while(rbytes--) { /* Count termination characters */
+ if (*rbuf++ == tc)
+ j++;
+ }
+ }
+ }
+ } else {
+ i--; /* We timed out (or error!) */
+ }
+ }
+
+ *rbuf = '\000';
+ if (i <= 0) { /* timed out */
+ retrv |= ICOM_TO;
+ }
+
+ a1logd(p->log, 8, "icoms_ser_read: returning '%s' ICOM err 0x%x\n",icoms_fix(rrbuf),retrv);
+
+ p->lserr = retrv;
+ return retrv;
+}
+
+#endif /* ENABLE_SERIAL */
+
+/* ---------------------------------------------------------------------------------*/
+
+/* Destroy ourselves */
+static void
+icoms_del(icoms *p) {
+ a1logd(p->log, 8, "icoms_del: called\n");
+ if (p->is_open) {
+ a1logd(p->log, 8, "icoms_del: closing port\n");
+ p->close_port(p);
+ }
+#ifdef ENABLE_USB
+ usb_del_usb(p);
+ hid_del_hid(p);
+#endif
+ p->log = del_a1log(p->log);
+ free (p);
+}
+
diff --git a/spectro/ifiles b/spectro/ifiles
new file mode 100644
index 0000000..6e73997
--- /dev/null
+++ b/spectro/ifiles
@@ -0,0 +1,14 @@
+dtp20.c
+dtp22.c
+dtp41.c
+dtp51.c
+dtp92.c
+i1disp.c
+huey.c
+i1d3.c
+spyd2.c
+ss.c
+i1pro.c
+munki.c
+hcfr.c
+colorhug.c
diff --git a/spectro/illumread.c b/spectro/illumread.c
new file mode 100644
index 0000000..282ec2f
--- /dev/null
+++ b/spectro/illumread.c
@@ -0,0 +1,1232 @@
+
+ /* Illuminant measurement utility */
+
+/*
+ * Argyll Color Correction System
+ * Author: Graeme W. Gill
+ * Date: 3/10/2001
+ *
+ * Derived from printread.c/chartread.c
+ * Was called printspot.
+ *
+ * Copyright 2001 - 2013 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.
+ */
+
+/* This program uses an instrument capable of spectral illuminant/emissive */
+/* and reflective (non-UV filtered) measurement, to measure an illuminant */
+/* spectrum that includes a UV estimate. */
+
+/* Based on spotread.c */
+
+/*
+ TTBD:
+
+ Should add support for converting Spyder correction readings to ccmx.
+ (see SpyderDeviceCorrections.txt)
+
+ */
+
+#undef DEBUG /* Save measurements and restore them to outname_X.sp */
+ /*
+
+ outname_i.sp Illuminant spectrum
+ outname_r.sp Illuminant off paper spectrum
+ outname_p.sp Instrument measured paper reflectance spectrum
+ outname_mpir.sp Measured paper under illuminant spectrum
+ outname_cpir.sp Computed paper under illuminant spectrum
+
+ */
+
+#define SHOWDXX /* Plot the best matched daylight as well */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "conv.h"
+#include "inst.h"
+#include "icoms.h"
+#include "instappsup.h"
+#include "plot.h"
+#include "spyd2setup.h" /* Enable Spyder 2 access */
+
+#include <stdarg.h>
+
+#if defined (NT)
+#include <conio.h>
+#endif
+
+/* Deal with an instrument error. */
+/* Return 0 to retry, 1 to abort */
+static int ierror(inst *it, inst_code ic) {
+ int ch;
+ empty_con_chars();
+ printf("Got '%s' (%s) error.\nHit Esc or Q to give up, any other key to retry:",
+ it->inst_interp_error(it, ic), it->interp_error(it, ic));
+ fflush(stdout);
+ ch = next_con_char();
+ printf("\n");
+ if (ch == 0x03 || ch == 0x1b || ch == 'q' || ch == 'Q') /* Escape, ^C or Q */
+ return 1;
+ return 0;
+}
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a ppc gcc 3.3 optimiser bug... */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+
+#define GCC_BUGFIX(XX) gcc_bug_fix(XX);
+#else /* !APPLE */
+#define GCC_BUGFIX(XX)
+#endif /* !APPLE */
+
+
+/* ============================================================== */
+/* optimizer callback */
+
+/* Structure to hold optimisation information */
+typedef struct {
+ xspect *i_sp; /* Illuminiant measurement */
+ xspect *r_sp; /* Illuminant off paper measurement */
+ xspect *p_sp; /* Paper reflectance measurement */
+
+ xsp2cie *pap; /* Estimated illuminant + UV on paper lookup inc FWA */
+ xsp2cie *ref; /* Measured illuminant on paper lookup */
+
+ xspect ill; /* Illuminant with UV added */
+ xspect cpsp; /* FWA corrected calculated paper reflectance */
+ xspect srop; /* Scaled measured paper reflectance */
+
+ double lab0[3], lab1[3]; /* Conversion of calculated vs. measured */
+} bfinds;
+
+/* Optimize the UV content that minimizes the (weighted) Delta E */
+static double bfindfunc(void *adata, double pv[]) {
+ bfinds *b = (bfinds *)adata;
+ int i;
+ double rv = 0.0;
+
+ /* Add UV level to illuminant */
+ b->ill = *b->i_sp;
+ xsp_setUV(&b->ill, b->i_sp, pv[0]);
+
+ /* Update the conversion */
+ if (b->pap->update_fwa_custillum(b->pap, NULL, &b->ill) != 0)
+ error ("Updating FWA compensation failed");
+
+ /* Apply FWA compensation to the paper reflectance */
+ b->pap->sconvert(b->pap, &b->cpsp, b->lab0, b->p_sp);
+
+ /* Adjust gain factor of measured illuminant off paper */
+ /* and divide by illuminant measurement to give reflectance */
+ b->srop = *b->r_sp;
+ for (i = 0; i < b->r_sp->spec_n; i++) {
+ double ww = XSPECT_XWL(b->r_sp, i);
+ double ival = value_xspect(b->i_sp, ww);
+ if (ival < 0.05) /* Stop noise sending it wild */
+ ival = 0.05;
+ b->srop.spec[i] *= pv[1]/ival;
+ if (b->srop.spec[i] < 0.0)
+ b->srop.spec[i] = 0.0;
+ }
+
+ /* Compute Lab of the computed reflectance under flat spectrum */
+ b->ref->convert(b->ref, b->lab0, &b->cpsp);
+
+ /* Compute Lab value of illuminant measured reflectance */
+ b->ref->convert(b->ref, b->lab1, &b->srop);
+
+ /* Weighted Delta E (low weight on a* error) */
+ rv = sqrt( (b->lab0[0] - b->lab1[0]) * (b->lab0[0] - b->lab1[0])
+ + 0.1 * (b->lab0[1] - b->lab1[1]) * (b->lab0[1] - b->lab1[1])
+ + (b->lab0[2] - b->lab1[2]) * (b->lab0[2] - b->lab1[2]));
+
+ /* Add a slight weight of the UV level, to minimize it */
+ /* if the case is unconstrained. */
+ rv += 0.1 * fabs(pv[0]);
+
+//printf("~1 rev = %f (%f %f %f - %f %f %f) from %f %f\n",rv, b->lab0[0], b->lab0[1], b->lab0[2], b->lab1[0], b->lab1[1], b->lab1[2], pv[0], pv[1]);
+ return rv;
+}
+
+/* ============================================================== */
+#ifdef SHOWDXX /* Plot the best matched daylight as well */
+
+/* optimizer callback for computing daylight match */
+
+/* Structure to hold optimisation information */
+typedef struct {
+ xspect ill; /* Illuminant with UV added - target */
+ xspect dxx; /* Daylight spectrum */
+
+ xsp2cie *ref; /* reference Lab conversion */
+
+ double lab0[3], lab1[3]; /* Conversion of target vs. Daylight */
+} cfinds;
+
+/* Optimize the daylight color temperature and level to minimizes the Delta E */
+static double cfindfunc(void *adata, double pv[]) {
+ cfinds *b = (cfinds *)adata;
+ int i;
+ double rv = 0.0;
+
+ /* Compute daylight with the given color temperature */
+ standardIlluminant( &b->dxx, icxIT_Dtemp, pv[0]);
+ b->dxx.norm = 1.0;
+
+ /* Adjust the level of daylight spectra */
+ for (i = 0; i < b->dxx.spec_n; i++) {
+ b->dxx.spec[i] *= pv[1];
+ }
+
+ /* Compute Lab of target */
+ b->ref->convert(b->ref, b->lab0, &b->ill);
+
+ /* Compute Lab of Dxx */
+ b->ref->convert(b->ref, b->lab1, &b->dxx);
+
+ /* Weighted Delta E (low weight on a* error) */
+ rv = icmLabDEsq(b->lab0, b->lab1);
+
+//printf("~1 rev = %f (%f %f %f - %f %f %f) from %f %f\n",rv, b->lab0[0], b->lab0[1], b->lab0[2], b->lab1[0], b->lab1[1], b->lab1[2], pv[0], pv[1]);
+ return rv;
+}
+
+#endif /* SHOWDXX */
+
+/* ============================================================== */
+void
+usage() {
+ icompaths *icmps;
+ fprintf(stderr,"Measure an illuminant, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (setup_spyd2() == 2)
+ fprintf(stderr,"WARNING: This file contains a proprietary firmware image, and may not be freely distributed !\n");
+ fprintf(stderr,"usage: illumread [-options] output.sp\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -S Plot spectrum for each reading\n");
+ fprintf(stderr," -c listno Choose instrument from the following list (default 1)\n");
+ if ((icmps = new_icompaths(g_log)) != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ if (paths[i]->itype == instSpyder2 && setup_spyd2() == 0)
+ fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
+ else
+ fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
+ }
+ } else
+ fprintf(stderr," ** No ports found **\n");
+ }
+ fprintf(stderr," -N Disable initial calibration of instrument if possible\n");
+ fprintf(stderr," -H Use high resolution spectrum mode (if available)\n");
+ fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
+ fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
+ fprintf(stderr," illuminant.sp File to save measurement to\n");
+
+ if (icmps != NULL)
+ icmps->del(icmps);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int i,j;
+ int fa, nfa, mfa; /* current argument we're looking at */
+ int verb = 0;
+ int debug = 0;
+ int nocal = 0; /* Disable initial calibration */
+ int pspec = 0; /* 2 = Plot out the spectrum for each reading */
+ int highres = 0; /* Use high res mode if available */
+ char outname[MAXNAMEL+1] = "\000"; /* Spectral output file name */
+#ifdef DEBUG
+ char tname[MAXNAMEL+11] = "\000", *tnp;
+ int rd_i = 0, rd_r = 0, rd_p = 0;
+#endif
+
+ icompaths *icmps = NULL; /* Ports to choose from */
+ int comno = 1; /* Specific port suggested by user */
+ inst *it = NULL; /* Instrument object, NULL if none */
+ inst_mode mode = 0; /* Instrument reading mode */
+ inst_opt_type trigmode = inst_opt_unknown; /* Chosen trigger mode */
+ instType itype = instUnknown; /* No default target instrument */
+ inst_mode cap = inst_mode_none; /* Instrument mode capabilities */
+ inst2_capability cap2 = inst2_none; /* Instrument capabilities 2 */
+ inst3_capability cap3 = inst3_none; /* Instrument capabilities 3 */
+ baud_rate br = baud_38400; /* Target baud rate */
+ flow_control fc = fc_nc; /* Default flow control */
+
+ inst_code rv;
+ int uswitch = 0; /* Instrument switch is enabled */
+ xspect i_sp; /* Illuminant emsission spectrum */
+ xspect r_sp; /* Illuminant reflected from paper emission spectrum */
+ xspect p_sp; /* Paper reflectance spectrum */
+ xspect insp; /* Instrument illuminant (for FWA) */
+ xspect ill; /* Estimated illuminant */
+ xspect aill; /* Accumulated result */
+ int nacc = 0; /* Number accumulated */
+ ipatch val; /* Value read */
+
+ set_exe_path(argv[0]); /* Set global exe_path and error_program */
+ check_if_not_interactive();
+ setup_spyd2(); /* Load firware if available */
+
+ i_sp.spec_n = 0;
+ r_sp.spec_n = 0;
+ p_sp.spec_n = 0;
+ insp.spec_n = 0;
+ ill.spec_n = 0;
+ aill.spec_n = 0;
+
+ /* Process the arguments */
+ mfa = 0; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?') {
+ usage();
+
+ } else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ g_log->verb = verb;
+
+ } else if (argv[fa][1] == 'S') {
+ pspec = 2;
+
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+ if (na == NULL) usage();
+ comno = atoi(na);
+ if (comno < 1 || comno > 99) usage();
+
+ /* No initial calibration */
+ } else if (argv[fa][1] == 'N') {
+ nocal = 1;
+
+ /* High res mode */
+ } else if (argv[fa][1] == 'H') {
+ highres = 1;
+
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (na[0] == 'n' || na[0] == 'N')
+ fc = fc_none;
+ else if (na[0] == 'h' || na[0] == 'H')
+ fc = fc_Hardware;
+ else if (na[0] == 'x' || na[0] == 'X')
+ fc = fc_XonXOff;
+ else
+ usage();
+
+ } else if (argv[fa][1] == 'D') {
+ debug = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ debug = atoi(na);
+ fa = nfa;
+ }
+ g_log->debug = debug;
+ } else
+ usage();
+ }
+ else
+ break;
+ }
+
+ /* Get the output spectrum file name argument */
+ if (fa >= argc)
+ usage();
+
+ strncpy(outname,argv[fa++],MAXNAMEL-1); outname[MAXNAMEL-1] = '\000';
+
+#ifdef DEBUG
+ strcpy(tname, outname);
+ if ((tnp = strrchr(tname, '.')) == NULL)
+ tnp = tname + strlen(tname);
+
+ /* Special debug */
+ strcpy(tnp, "_i.sp");
+ if (read_xspect(&i_sp, tname) == 0) {
+ rd_i = 1;
+ printf("(Found '%s' file and loaded it)\n",tname);
+ }
+ strcpy(tnp, "_r.sp");
+ if (read_xspect(&r_sp, tname) == 0) {
+ rd_r = 1;
+ printf("(Found '%s' file and loaded it)\n",tname);
+ }
+ strcpy(tnp, "_p.sp");
+ if (read_xspect(&p_sp, tname) == 0) {
+ rd_p = 1;
+ /* Should read instrument type from debug_p.sp !! */
+ if (inst_illuminant(&insp, instI1Pro) != 0) /* Hack !! */
+ error ("Instrument doesn't have an FWA illuminent");
+ printf("(Found '%s' file and loaded it)\n",tname);
+ }
+#endif /* DEBUG */
+
+ /* Until the measurements are done, or we give up */
+ for (;;) {
+ int c;
+
+ /* Print the menue of adjustments */
+ printf("\nPress 1 .. 7\n");
+ printf("1) Measure direct illuminant%s\n",i_sp.spec_n != 0 ? " (measured)":"");
+ printf("2) Measure illuminant reflected from paper%s\n", r_sp.spec_n != 0 ? " (measured)":"");
+ printf("3) Measure paper%s\n", p_sp.spec_n != 0 ? " (measured)":"");
+ if (it == NULL) {
+ printf("4) Select another instrument, Currently %d (", comno);
+ if (icmps == NULL)
+ icmps = new_icompaths(g_log);
+ else
+ icmps->refresh(icmps);
+ if (icmps != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ if ((i+1) == comno) {
+ printf(" '%s'",paths[i]->name);
+ break;
+ }
+ }
+ }
+ }
+ printf(")\n");
+ } else
+ printf("4) Select another instrument, Currently %s\n", inst_name(itype));
+ printf("5) Compute illuminant spectrum, average result with %d previous readings & save it\n",nacc);
+ printf("6) Compute illuminant spectrum from this reading & save result\n");
+ printf("7) Exit\n");
+
+ empty_con_chars();
+ c = next_con_char();
+ printf("'%c'\n",c);
+
+ /* Deal with doing a measurement */
+ if (c == '1' || c == '2' || c == '3') {
+ int ch;
+
+ if (it == NULL) {
+ if (icmps == NULL)
+ icmps = new_icompaths(g_log);
+
+ /* Open the instrument */
+ if ((it = new_inst(icmps->get_path(icmps, comno), 0, g_log, DUIH_FUNC_AND_CONTEXT)) == NULL) {
+ printf("!!! Unknown, inappropriate or no instrument detected !!!\n");
+ continue;
+ }
+
+ if (verb)
+ printf("Connecting to the instrument ..\n");
+
+#ifdef DEBUG
+ printf("About to init the comms\n");
+#endif
+
+ /* Establish communications */
+ if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
+ printf("!!! Failed to initialise communications with instrument\n"
+ " or wrong instrument or bad configuration !!!\n"
+ " ('%s' + '%s')\n", it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ it = NULL;
+ itype = instUnknown;
+ continue;
+ }
+
+#ifdef DEBUG
+ printf("Established comms & initing the instrument\n");
+#endif
+
+ /* Initialise the instrument */
+ if ((rv = it->init_inst(it)) != inst_ok) {
+ printf("!!! Instrument initialisation failed with '%s' (%s) !!!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ it = NULL;
+ itype = instUnknown;
+ continue;
+ }
+
+ itype = it->get_itype(it); /* get actual type of instrument */
+
+ /* Check the instrument has the necessary capabilities */
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ /* Need spectral */
+ if (!IMODETST(cap, inst_mode_spectral)) {
+ printf("Instrument lacks spectral measurement capability");
+ }
+
+ /* Disable iniial calibration of machine if selected */
+ if (nocal != 0){
+ if ((rv = it->get_set_opt(it,inst_opt_noinitcalib, 0)) != inst_ok) {
+ printf("Setting no-initial calibrate failed failed with '%s' (%s) !!!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ printf("Disable initial-calibrate not supported\n");
+ }
+ }
+ if (highres) {
+ if (IMODETST(cap, inst_mode_highres)) {
+ inst_code ev;
+ if ((ev = it->get_set_opt(it, inst_opt_highres)) != inst_ok) {
+ printf("!!! Setting high res mode failed with error :'%s' (%s) !!!\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ }
+ } else if (verb) {
+ printf("!!! High resolution ignored - instrument doesn't support it !!!\n");
+ }
+ }
+ }
+
+ /* Check the instrument has the necessary capabilities for this measurement */
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ if (c == '1') {
+ if (IMODETST(cap, inst_mode_emis_ambient)) {
+ mode = inst_mode_emis_ambient;
+ } else if (IMODETST(cap, inst_mode_emis_spot)) {
+ mode = inst_mode_emis_spot;
+ } else {
+ printf("!!! Instrument doesn't have ambient or emissive capability !!!\n");
+ continue;
+ }
+ }
+ if (c == '2') {
+ if (IMODETST(cap, inst_mode_emis_tele)) {
+ mode = inst_mode_emis_tele;
+ } else if (IMODETST(cap, inst_mode_emis_spot)) {
+ mode = inst_mode_emis_spot;
+ } else {
+ printf("!!! Instrument doesn't have telephoto or emissive capability !!!\n");
+ continue;
+ }
+ }
+ if (c == '3') {
+ inst_opt_filter filt;
+
+ if (IMODETST(cap, inst_mode_ref_spot)) {
+ mode = inst_mode_ref_spot;
+ } else {
+ printf("!!! Instrument lacks reflective spot measurement capability !!!\n");
+ continue;
+ }
+
+ if ((rv = it->get_set_opt(it, inst_stat_get_filter, &filt)) == inst_ok) {
+ if (filt & inst_opt_filter_UVCut) {
+ printf("!!! Instrument has UV filter - can't measure FWA !!!\n");
+ continue;
+ }
+ }
+ }
+ mode |= inst_mode_spectral;
+
+ if ((rv = it->set_mode(it, mode)) != inst_ok) {
+ printf("!!! Setting instrument mode failed with error :'%s' (%s) !!!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ continue;
+ }
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ /* If it batter powered, show the status of the battery */
+ if ((cap2 & inst2_has_battery)) {
+ double batstat = 0.0;
+ if ((rv = it->get_set_opt(it, inst_stat_battery, &batstat)) == inst_ok)
+ printf("The battery charged level is %.0f%%\n",batstat * 100.0);
+ }
+
+ /* If it's an instrument that need positioning do trigger using user via uicallback */
+ /* in illumread, else enable switch or keyboard trigger if possible. */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ trigmode = inst_opt_trig_prog;
+
+ } else if (cap2 & inst2_user_switch_trig) {
+ trigmode = inst_opt_trig_user_switch;
+ uswitch = 1;
+
+ /* Or go for user via uicallback trigger */
+ } else if (cap2 & inst2_user_trig) {
+ trigmode = inst_opt_trig_user;
+
+ /* Or something is wrong with instrument capabilities */
+ } else {
+ printf("!!! No reasonable trigger mode avilable for this instrument !!!\n");
+ continue;
+ }
+ if ((rv = it->get_set_opt(it, trigmode)) != inst_ok) {
+ printf("!!! Setting trigger mode failed with error :'%s' (%s) !!!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ continue;
+ }
+
+ /* Setup the keyboard trigger to return our commands */
+ inst_set_uih(0x0, 0xff, DUIH_TRIG);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
+ inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
+
+ /* Hold table */
+ if (cap2 & inst2_xy_holdrel) {
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_sheet_hold(it)) == inst_ok)
+ break;
+
+ if (ierror(it, rv)) {
+ printf("!!! Setting paper hold failed with error :'%s' (%s) !!!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->xy_clear(it);
+ continue;
+ }
+ }
+ }
+
+ /* Do any needed calibration before the user places the instrument on a desired spot */
+ if (it->needs_calibration(it) != inst_calt_none) {
+ double lx, ly;
+ inst_code ev;
+
+ printf("\nInstrument needs a calibration before continuing\n");
+
+ /* save current location */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ for (;;) { /* retry loop */
+ if ((ev = it->xy_get_location(it, &lx, &ly)) == inst_ok)
+ break;
+ if (ierror(it, ev) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (ev != inst_ok) {
+ printf("!!! Setting calibration location failed with error :'%s' (%s) !!!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ continue;
+ }
+ }
+
+ ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ printf("!!! Calibration failed with error :'%s' (%s) !!!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ continue;
+ }
+
+ /* restore location */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ for (;;) { /* retry loop */
+ if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
+ break;
+ if (ierror(it, ev) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (ev != inst_ok) {
+ printf("!!! Restoring location failed with error :'%s' (%s) !!!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ continue;
+ }
+ }
+ }
+
+ /* Now do the measurement: */
+
+ /* If this is an xy instrument: */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+
+ /* Allow the user to position the instrument */
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_locate_start(it)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok)
+ break; /* Abort */
+
+ if (c != 3) {
+ printf("!!! Unexpected: XY instrument used for emissive measurements !!!\n");
+ continue;
+ }
+
+ printf("Using the XY table controls, position the instrument sight\n");
+ printf("so as to read the paper,\n");
+
+ /* Purely manual instrument */
+ } else {
+
+ if (c == '1') {
+ if (IMODETST(cap, inst_mode_emis_ambient)) {
+ printf("\n(If applicable) set instrument to ambient measurenent mode, or place\n");
+ printf("ambient adapter on it, and position it so as to measure the illuminant directly.\n");
+ } else {
+ printf("\n(If applicable) set instrument to emissive measurenent mode,\n");
+ printf("and position it so as to measure the illuminant directly.\n");
+ }
+ } else if (c == '2') {
+ if (IMODETST(cap, inst_mode_emis_tele)) {
+ printf("\n(If applicable) set instrument to telephoto measurenent mode,\n");
+ printf("position it so as to measure the illuminant reflected from the paper.\n");
+ } else {
+ printf("\n(If applicable) set instrument to emsissive measurenent mode,\n");
+ printf("position it so as to measure the illuminant reflected from the paper.\n");
+ }
+ } else if (c == '3') {
+ printf("\n(If applicable) set instrument to reflective measurenent mode,\n");
+ printf("position it so as to measure the paper.");
+ } else
+ error("Unexpected choice");
+ }
+ if (uswitch)
+ printf("Hit ESC or Q to abort, or instrument switch or any other key to take a reading: ");
+ else
+ printf("Hit ESC or Q to abort, any any other key to take a reading: ");
+ fflush(stdout);
+
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+
+ /* Wait for the user to hit a key */
+ for (;;) {
+ if ((rv = inst_get_uicallback()(inst_get_uicontext(), inst_armed)) != inst_ok)
+ break;
+ }
+
+ if (rv == inst_user_abort) {
+ break; /* Abort */
+
+ } else if (rv == inst_user_trig) {
+ double lx, ly;
+ inst_code ev;
+
+ /* Take the location set on the sight, and move the instrument */
+ /* to take the measurement there. */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_get_location(it, &lx, &ly)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok)
+ break; /* Abort */
+
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_locate_end(it)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok)
+ break; /* Abort */
+
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_position(it, 1, lx, ly)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok)
+ break; /* Abort */
+ }
+ rv = it->read_sample(it, "SPOT", &val, 1);
+
+ /* Restore the location the instrument to have the location */
+ /* sight over the selected patch. */
+ for (;;) { /* retry loop */
+ if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
+ break;
+ if (ierror(it, ev) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (ev != inst_ok)
+ break; /* Abort */
+ }
+ /* else what ? */
+
+ /* Not an XY instrument */
+ } else {
+ rv = it->read_sample(it, "SPOT", &val, 1);
+ }
+
+ /* Release paper */
+ if (cap2 & inst2_xy_holdrel) {
+ it->xy_clear(it);
+ }
+
+#ifdef DEBUG
+ printf("read_sample returned '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+#endif /* DEBUG */
+
+ /* Deal with a trigger or command */
+ if ((rv & inst_mask) == inst_user_trig) {
+ ch = inst_get_uih_char() & 0xff;
+
+ /* Deal with a command or abort */
+ } else if ((rv & inst_mask) == inst_user_abort) {
+ ch = inst_get_uih_char();
+
+ if (ch & DUIH_CMND) {
+ ch &= 0xff;
+ } else if (ch & DUIH_ABORT) {
+ printf("\nIlluminant measure aborted at user request!\n");
+ continue;
+ }
+
+ /* Deal with a needs calibration */
+ } else if ((rv & inst_mask) == inst_needs_cal) {
+ inst_code ev;
+ printf("\nIlluminant measure failed because instruments needs calibration.\n");
+ ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL);
+ continue;
+
+ /* Deal with a bad sensor position */
+ } else if ((rv & inst_mask) == inst_wrong_config) {
+ printf("\nIlluminant measure failed due to the sensor being in the wrong position\n(%s)\n",it->interp_error(it, rv));
+ continue;
+
+ /* Deal with a misread */
+ } else if ((rv & inst_mask) == inst_misread) {
+ printf("\nIlluminant measure failed due to misread (%s)\n",it->interp_error(it, rv));
+ continue;
+
+ /* Deal with a communications error */
+ } else if ((rv & inst_mask) == inst_coms_fail) {
+ empty_con_chars();
+ printf("\nIlluminant measure failed due to communication problem.\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ continue;
+
+ /* Some other fatal error */
+ } else if (rv != inst_ok) {
+ printf("\nGot fatal error '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ continue;
+ }
+
+ if (c == '1') {
+ i_sp = val.sp;
+#ifdef DEBUG
+ if (rd_i == 0) {
+ strcpy(tnp, "_i.sp");
+ write_xspect(tname,&i_sp);
+ }
+#endif
+ } else if (c == '2') {
+ r_sp = val.sp;
+#ifdef DEBUG
+ if (rd_r == 0) {
+ strcpy(tnp, "_r.sp");
+ write_xspect(tname,&r_sp);
+ }
+#endif
+ } else if (c == '3') {
+ p_sp = val.sp;
+
+ /* Get the illuminant spectrum too */
+ if (inst_illuminant(&insp, itype) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+
+#ifdef DEBUG
+ if (rd_p == 0) {
+ /* Should save instrument type/instrument illuminant spectrum !!! */
+ strcpy(tnp, "_p.sp");
+ write_xspect(tname,&p_sp);
+ }
+#endif
+ }
+
+ if (pspec) {
+ double xx[XSPECT_MAX_BANDS];
+ double y1[XSPECT_MAX_BANDS];
+ double xmin, xmax, ymin, ymax;
+ int nn;
+
+ if (val.sp.spec_n <= 0)
+ error("Instrument didn't return spectral data");
+
+ printf("Spectrum from %f to %f nm in %d steps\n",
+ val.sp.spec_wl_short, val.sp.spec_wl_long, val.sp.spec_n);
+
+ if (val.sp.spec_n > XSPECT_MAX_BANDS)
+ error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,val.sp.spec_n);
+
+ for (j = 0; j < val.sp.spec_n; j++) {
+ GCC_BUGFIX(j)
+ xx[j] = val.sp.spec_wl_short
+ + j * (val.sp.spec_wl_long - val.sp.spec_wl_short)/(val.sp.spec_n-1);
+
+ y1[j] = value_xspect(&val.sp, xx[j]);
+ }
+
+ xmax = val.sp.spec_wl_long;
+ xmin = val.sp.spec_wl_short;
+ ymin = ymax = 0.0; /* let it scale */
+ do_plot_x(xx, y1, NULL, NULL, val.sp.spec_n, 1,
+ xmin, xmax, ymin, ymax, 2.0);
+ }
+
+ continue;
+ } /* End of take a measurement */
+
+ /* Deal with selecting the instrument */
+ if (c == '4') {
+
+ if (it != NULL)
+ it->del(it);
+ it = NULL;
+ itype = instUnknown;
+
+ if (icmps == NULL)
+ icmps = new_icompaths(g_log);
+ else
+ icmps->refresh(icmps);
+ if (icmps != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ if (paths[i]->itype == instSpyder2 && setup_spyd2() == 0)
+ fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
+ else
+ fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
+ }
+ printf("Select device 1 - %d: \n",i);
+ empty_con_chars();
+ c = next_con_char();
+
+ if (c < '1' || c > ('0' + i)) {
+ printf("'%c' is out of range - ignored !\n",c);
+ } else {
+ comno = c - '0';
+ }
+
+ } else {
+ fprintf(stderr,"No ports to select from!\n");
+ }
+ }
+ continue;
+ }
+ if (c == '5' || c == '6') { /* Compute result */
+ xspect cpisp; /* FWA corrected calculated initial paper reflectance */
+ double gain;
+ bfinds bf; /* Optimization context */
+ double xyz0[3], xyz1[3];
+ double tt[2], sr[2];
+ double rv;
+
+ if (i_sp.spec_n == 0) {
+ printf("Need to measure the direct illuminant\n");
+ continue;
+ }
+ if (r_sp.spec_n == 0) {
+ printf("Need to measure the illuminant reflected off paper\n");
+ continue;
+ }
+ if (p_sp.spec_n == 0) {
+ printf("Need to measure the paper\n");
+ continue;
+ }
+
+ /* Normalize direct illumination */
+ for (gain = 0.0, i = 0; i < i_sp.spec_n; i++)
+ gain += i_sp.spec[i];
+ gain /= i_sp.spec_n;
+ for (i = 0; i < i_sp.spec_n; i++)
+ i_sp.spec[i] /= gain;
+
+ /* Normalize indirect illumination */
+ for (gain = 0.0, i = 0; i < r_sp.spec_n; i++)
+ gain += r_sp.spec[i];
+ gain /= r_sp.spec_n;
+ for (i = 0; i < r_sp.spec_n; i++)
+ r_sp.spec[i] /= gain;
+
+ /* Normalize paper reflectance to 1.0 */
+ xspect_denorm(&p_sp);
+
+ bf.i_sp = &i_sp;
+ bf.r_sp = &r_sp;
+ bf.p_sp = &p_sp;
+
+ if ((bf.pap = new_xsp2cie(icxIT_custom, &i_sp, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
+ error("new_xsp2cie pap failed");
+
+ if (bf.pap->set_fwa(bf.pap, &insp, NULL, &p_sp) != 0)
+ error ("Setting FWA compensation failed");
+
+ /* Setup the equal energy to Lab conversion */
+ if ((bf.ref = new_xsp2cie(icxIT_E, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
+ error("new_xsp2cie ref failed");
+
+ /* Estimate an initial gain match */
+ tt[0] = 0.0;
+ tt[1] = 1.0;
+ bfindfunc((void *)&bf, tt);
+ icmLab2XYZ(&icmD50, xyz0, bf.lab0);
+ icmLab2XYZ(&icmD50, xyz1, bf.lab1);
+
+ gain = xyz0[1] / xyz1[1];
+//printf("~1 Target XYZ %f %f %f, is %f %f %f, gain needed = %f\n",xyz0[0],xyz0[1],xyz0[2],xyz1[0],xyz1[1],xyz1[2],gain);
+
+ for (i = 0; i < r_sp.spec_n; i++)
+ r_sp.spec[i] *= gain;
+
+ /* Check initial gain match is OK */
+ bfindfunc((void *)&bf, tt);
+ cpisp = bf.cpsp; /* Copy initial match */
+ icmLab2XYZ(&icmD50, xyz0, bf.lab0);
+ icmLab2XYZ(&icmD50, xyz1, bf.lab1);
+#ifdef NEVER
+ printf("~1 Target XYZ %f %f %f, now %f %f %f\n",xyz0[0],xyz0[1],xyz0[2],xyz1[0],xyz1[1],xyz1[2]);
+#endif
+
+ tt[0] = 0.1, tt[1] = 1.0; /* Search parameter starting values */
+ sr[0] = sr[1] = 0.1; /* Search parameter search radiuses */
+
+ if (powell(&rv, 2, tt, sr, 0.0001, 1000,
+ bfindfunc, (void *)&bf, NULL, NULL) != 0) {
+ printf("Optimization search failed\n");
+ continue;
+ }
+ printf("(Best match DE %f, UV content = %f (gain match %f))\n", rv, tt[0], tt[1]);
+
+ /* Compute the result */
+ bfindfunc((void *)&bf, tt);
+ ill = bf.ill;
+
+ if (c == '5' && nacc > 0) {
+ for (i = 0; i < ill.spec_n; i++)
+ aill.spec[i] += ill.spec[i];
+ nacc++;
+ } else {
+ aill = ill;
+ nacc = 1;
+ }
+
+ /* Save the result */
+ if (aill.spec_n == 0) {
+ printf("Nothing to save!\n");
+ } else {
+ for (i = 0; i < ill.spec_n; i++)
+ ill.spec[i] = aill.spec[i]/nacc;
+
+ if(write_xspect(outname, &ill))
+ printf("\nWriting file '%s' failed\n",outname);
+ else
+ printf("\nWriting file '%s' succeeded\n",outname);
+#ifdef DEBUG
+ strcpy(tnp, "_mpir.sp"); // Measured paper under illuminant spectrum
+ write_xspect(tname,&bf.srop);
+ strcpy(tnp, "_cpir.sp"); // Computed paper under illuminant spectrum
+ write_xspect(tname,&bf.cpsp);
+#endif
+ }
+
+ /* Plot the result */
+ if (pspec) {
+ double xx[XSPECT_MAX_BANDS];
+ double y1[XSPECT_MAX_BANDS];
+ double y2[XSPECT_MAX_BANDS];
+ double y3[XSPECT_MAX_BANDS];
+ double xmin, xmax, ymin, ymax;
+ int nn;
+
+#ifdef SHOWDXX
+ cfinds cf; /* Optimization context */
+ double tt[2], sr[2];
+ double rv;
+ xspect cpdsp; /* FWA corrected calculated daylight paper reflectance */
+
+ /* Setup the referencec comversion */
+ if ((cf.ref = new_xsp2cie(icxIT_E, NULL, icxOT_CIE_1931_2, NULL, icSigLabData, icxClamp)) == NULL)
+ error("new_xsp2cie ref failed");
+
+ cf.ill = bf.ill;
+
+ /* Set starting values */
+ tt[0] = 5000.0; /* degrees */
+ tt[1] = 1.0;
+ cfindfunc((void *)&cf, tt);
+ icmLab2XYZ(&icmD50, xyz0, cf.lab0);
+ icmLab2XYZ(&icmD50, xyz1, cf.lab1);
+
+ tt[1] = xyz0[1] / xyz1[1];
+
+ sr[0] = 10.0;
+ sr[1] = 0.1; /* Search parameter search radiuses */
+
+ if (powell(&rv, 2, tt, sr, 0.0001, 1000,
+ cfindfunc, (void *)&cf, NULL, NULL) != 0) {
+ error("Optimization search failed\n");
+ }
+ printf("(Best daylight match DE %f, temp = %f (gain match %f))\n", rv, tt[0], tt[1]);
+
+ /* Compute the result */
+ cfindfunc((void *)&cf, tt);
+
+ printf("Illuminant: Black - Measured, Red - with estimated UV, Green - daylight\n");
+
+ if (bf.ill.spec_n > XSPECT_MAX_BANDS)
+ error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,bf.ill.spec_n);
+
+ for (j = 0; j < bf.ill.spec_n; j++) {
+ GCC_BUGFIX(j)
+ xx[j] = XSPECT_XWL(&bf.ill, j);
+ y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
+ y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
+ y3[j] = value_xspect(&cf.dxx, xx[j]); /* Daylight match (green)*/
+ }
+
+ xmax = bf.ill.spec_wl_long;
+ xmin = bf.ill.spec_wl_short;
+ ymin = ymax = 0.0; /* let it scale */
+ do_plot_x(xx, y1, y2, y3, bf.ill.spec_n, 1,
+ xmin, xmax, ymin, ymax, 2.0);
+
+ /* Update the conversion to the matched Dayligh */
+ if (bf.pap->update_fwa_custillum(bf.pap, NULL, &cf.dxx) != 0)
+ error ("Updating FWA compensation to daylight failed");
+
+ /* Apply FWA compensation to the paper reflectance */
+ bf.pap->sconvert(bf.pap, &cpdsp, NULL, bf.p_sp);
+
+ printf("Paper Reflectance: Black - Measured, Red - Initial FWA model, Green - FWA Final FWA model\n");
+// printf("Paper Reflectance: Black - Measured, Red - FWA Modelled, Green - Daylight modelled\n");
+
+ for (j = 0; j < bf.cpsp.spec_n; j++) {
+ GCC_BUGFIX(j)
+ xx[j] = XSPECT_XWL(&bf.cpsp, j);
+ y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
+ y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
+ y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
+// y3[j] = value_xspect(&cpdsp, xx[j]); /* Computed daylight reflectance (green) */
+ }
+
+ xmax = bf.cpsp.spec_wl_long;
+ xmin = bf.cpsp.spec_wl_short;
+ ymin = ymax = 0.0; /* let it scale */
+ do_plot_x(xx, y1, y2, y3, bf.cpsp.spec_n, 1,
+ xmin, xmax, ymin, ymax, 2.0);
+
+#else // !SHOWDXX
+ printf("Illuminant: Black - Measured, Red - with estimated UV\n");
+
+ if (bf.ill.spec_n > XSPECT_MAX_BANDS)
+ error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,bf.ill.spec_n);
+
+ for (j = 0; j < bf.ill.spec_n; j++) {
+ GCC_BUGFIX(j)
+ xx[j] = XSPECT_XWL(&bf.ill, j);
+ y1[j] = value_xspect(bf.i_sp, xx[j]); /* Measured (black) */
+ y2[j] = value_xspect(&bf.ill, xx[j]); /* Computed (red)*/
+ }
+
+ xmax = bf.ill.spec_wl_long;
+ xmin = bf.ill.spec_wl_short;
+ ymin = ymax = 0.0; /* let it scale */
+ do_plot_x(xx, y1, y2, NULL, bf.ill.spec_n, 1,
+ xmin, xmax, ymin, ymax, 2.0);
+
+ printf("Paper Reflectance: Black - Measured, Red - Initial FWA model, Green - FWA Final FWA model\n");
+
+ for (j = 0; j < bf.cpsp.spec_n; j++) {
+ GCC_BUGFIX(j)
+ xx[j] = XSPECT_XWL(&bf.cpsp, j);
+ y1[j] = value_xspect(&bf.srop, xx[j]); /* Measured reflectance (black) */
+ y2[j] = value_xspect(&cpisp, xx[j]); /* Computed initial reflectance (red) */
+ y3[j] = value_xspect(&bf.cpsp, xx[j]); /* Computed final reflectance (green) */
+ }
+
+ xmax = bf.cpsp.spec_wl_long;
+ xmin = bf.cpsp.spec_wl_short;
+ ymin = ymax = 0.0; /* let it scale */
+ do_plot_x(xx, y1, y2, y3, bf.cpsp.spec_n, 1,
+ xmin, xmax, ymin, ymax, 2.0);
+
+#endif // !SHOWDXX
+ printf("%s illuminant with UV:\n",c == '5' ? "Averaged" : "Computed");
+
+ for (j = 0; j < ill.spec_n; j++) {
+ GCC_BUGFIX(j)
+ xx[j] = XSPECT_XWL(&ill, j);
+ y1[j] = value_xspect(&ill, xx[j]);
+ }
+
+ xmax = ill.spec_wl_long;
+ xmin = ill.spec_wl_short;
+ ymin = ymax = 0.0; /* let it scale */
+ do_plot_x(xx, y1, NULL, NULL, ill.spec_n, 1,
+ xmin, xmax, ymin, ymax, 2.0);
+ }
+
+ /* Make sure that the illuminant is re-measured for another reading */
+ i_sp.spec_n = 0;
+ r_sp.spec_n = 0;
+
+ continue;
+ }
+
+ if (c == '7' || c == 0x3) { /* Exit */
+ break;
+ }
+
+ } /* Next command */
+
+#ifdef DEBUG
+ printf("About to exit\n");
+#endif
+
+ /* Free instrument */
+ if (it != NULL)
+ it->del(it);
+
+ return 0;
+}
+
+
+
+
diff --git a/spectro/inflate.c b/spectro/inflate.c
new file mode 100644
index 0000000..55d8e65
--- /dev/null
+++ b/spectro/inflate.c
@@ -0,0 +1,922 @@
+
+/*
+ inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993
+
+ Copied from gzip version 1.2.4 source.
+
+ Adapted for use in i1d3ccss
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include <fcntl.h>
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+
+#undef PKZIP_BUG_WORKAROUND
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(text) printf text ;
+#else
+#define DBG(text)
+#endif
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned int ulg;
+
+#define memzero(s, n) memset((void *)(s), 0, (n))
+
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+/* Interface to i1d3ccss.c */
+extern unsigned int inflate_get_byte();
+extern void inflate_unget_byte();
+extern int inflate_write_output(unsigned char *buf, unsigned int len);
+
+
+/* Function prototypes */
+static int huft_build(unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *);
+static int huft_free(struct huft *);
+static int inflate_codes(struct huft *, struct huft *, int, int);
+static int inflate_stored(void);
+static int inflate_fixed(void);
+static int inflate_dynamic(void);
+static int inflate_block(int *);
+int inflate(void);
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+/* unsigned wp; current position in slide */
+
+#define WSIZE 0x8000
+unsigned int wp; /* current position in slide */
+uch slide[32768];
+
+static int flush_output(unsigned int w) {
+ wp = w;
+
+ if (wp == 0)
+ return 0;
+ if (inflate_write_output(slide, wp))
+ return 1;
+ wp = 0;
+ return 0;
+}
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* note: see note #13 above about the 258 in this list. */
+
+static ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+
+static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+
+static ush cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & mask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+ulg bb; /* bit buffer */
+unsigned bk; /* bits in bit buffer */
+
+ush mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#define NEXTBYTE() (uch)inflate_get_byte()
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+int lbits = 9; /* bits in base literal/length lookup table */
+int dbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+unsigned hufts; /* track memory usage */
+
+
+static int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+ush *d; /* list of base values for non-simple codes */
+ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+ p = b; i = n;
+ do {
+// Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"), n-i, *p));
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0) {
+ DBG(("huft_buildd, bad input: more codes than bits\n"))
+ return 2; /* bad input: more codes than bits */
+ }
+ if ((y -= c[i]) < 0) {
+ DBG(("huft_buildd, less than zero\n"))
+ return 2;
+ }
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+ (struct huft *)NULL)
+ {
+ if (h)
+ huft_free(u[0]);
+ DBG(("huft_buildd, not enough memory\n"))
+ return 3; /* not enough memory */
+ }
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch)l; /* bits to dump before this table */
+ r.e = (uch)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush)(*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ }
+ else
+ {
+ r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+
+static int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ free((char*)p);
+ p = q;
+ }
+ return 0;
+}
+
+
+static int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl)
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch)t->v.n;
+// Tracevv((stderr, "%c", slide[w-1]));
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e)
+// Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) /* (this test assumes unsigned comparison) */
+ {
+ memcpy(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+// Tracevv((stderr, "%c", slide[w-1]));
+ } while (--e);
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+
+
+static int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+
+ /* go to byte boundary */
+ n = k & 7;
+ DUMPBITS(n);
+
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff)) {
+ DBG(("stored, error in compressed data\n"))
+ return 1; /* error in compressed data */
+ }
+ DUMPBITS(16)
+
+
+ /* read and output the compressed data */
+ while (n--)
+ {
+ NEEDBITS(8)
+ slide[w++] = (uch)b;
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+ return 0;
+}
+
+
+
+static int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
+ DBG(("fixed, huft_build return nz\n"))
+ return i;
+ }
+
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ huft_free(tl);
+ DBG(("fixed, huft_build return > 1\n"))
+ return i;
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd)) {
+ DBG(("fixed, inflate_codes return nz\n"))
+ return 1;
+ }
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+static int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30)
+#endif
+ {
+ DBG(("dynamic, bad length\n"))
+ return 1; /* bad lengths */
+ }
+
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if (i == 1)
+ huft_free(tl);
+ DBG(("dynamic, huft_build failed\n"))
+ return i; /* incomplete code set */
+ }
+
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl)
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n) {
+ DBG(("dynamic, i + j > n\n"))
+ return 1;
+ }
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n) {
+ DBG(("dynamic, i + j > n\n"))
+ return 1;
+ } while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n) {
+ DBG(("dynamic, i + j > n\n"))
+ return 1;
+ }
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+ if (i == 1) {
+ fprintf(stderr, " incomplete literal tree\n");
+ huft_free(tl);
+ }
+ DBG(("dynamic, incomplete code set\n"))
+ return i; /* incomplete code set */
+ }
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+ if (i == 1) {
+ fprintf(stderr, " incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ DBG(("dynamic, incomplete distance tree\n"))
+ return i; /* incomplete code set */
+#endif
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd)) {
+ DBG(("dynamic, an end-of-block code\n"))
+ return 1;
+ }
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+static int inflate_block(e)
+int *e; /* last block flag */
+/* decompress an inflated block */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ *e = (int)b & 1;
+ DUMPBITS(1)
+
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* inflate that block type */
+ if (t == 2)
+ return inflate_dynamic();
+ if (t == 0)
+ return inflate_stored();
+ if (t == 1)
+ return inflate_fixed();
+
+
+ /* bad block type */
+ return 2;
+}
+
+
+
+int inflate()
+/* decompress an inflated entry */
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ if ((r = inflate_block(&e)) != 0)
+ return r;
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 8) {
+ bk -= 8;
+ inflate_unget_byte();
+ }
+
+ /* flush out slide */
+ flush_output(wp);
+
+
+ /* return success */
+#ifdef DEBUG
+ fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+ return 0;
+}
diff --git a/spectro/inst.c b/spectro/inst.c
new file mode 100644
index 0000000..d57a84a
--- /dev/null
+++ b/spectro/inst.c
@@ -0,0 +1,1359 @@
+
+ /* Abstract instrument class implemenation */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 10/3/2001
+ *
+ * Copyright 2001 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#else
+#include "sa_config.h"
+#endif /* !SALONEINSTLIB */
+#include "numsup.h"
+#include "xspect.h"
+#include "ccmx.h"
+#include "ccss.h"
+#include "conv.h"
+#include "insttypes.h"
+
+#include "icoms.h"
+#include "inst.h"
+#include "insttypeinst.h"
+
+#include "sort.h"
+
+#ifdef ENABLE_SERIAL
+static instType ser_inst_type(icoms *p,
+inst_code (*uicallback)(void *cntx, inst_ui_purp purp), void *cntx);
+#endif /* ENABLE_SERIAL */
+
+/* ------------------------------------ */
+/* Default methods for instrument class */
+
+/* Establish communications at the indicated baud rate. */
+/* Timout in to seconds, and return non-zero error code */
+static inst_code init_coms(
+inst *p,
+baud_rate br, /* Baud rate */
+flow_control fc, /* Flow control */
+double tout) { /* Timeout */
+ return inst_unsupported;
+}
+
+/* Initialise or re-initialise the INST */
+/* return non-zero on an error, with inst error code */
+static inst_code init_inst(
+inst *p) {
+ return inst_unsupported;
+}
+
+/* Return the instrument type */
+static instType get_itype(inst *p) {
+ if (p != NULL)
+ return p->itype;
+ return instUnknown;
+}
+
+/* Return the instrument serial number. */
+/* (This will be an empty string if there is no serial no) */
+static char *get_serial_no(inst *p) {
+ return "";
+}
+
+/* Return the instrument mode capabilities */
+static void capabilities(inst *p, inst_mode *cap1,
+ inst2_capability *cap2, inst3_capability *cap3) {
+ if (cap1 != NULL)
+ *cap1 = inst_mode_none;
+ if (cap2 != NULL)
+ *cap2 = inst2_none;
+ if (cap3 != NULL)
+ *cap3 = inst3_none;
+}
+
+/* Return current or given configuration available measurement modes. */
+/* This default routine assumed one confiration which will be */
+/* all the measurement modes returned by capabilities(). */
+static inst_code meas_config(inst *p,
+inst_mode *mmodes, /* Return all the valid measurement modes */
+ /* for the current configuration */
+inst_cal_cond *cconds, /* Return the valid calibration conditions */
+int *conf_ix) { /* Request mode for given configuration, and */
+ /* return the index of the configuration returned */
+ if (mmodes != NULL) {
+ *mmodes = inst_mode_none;
+
+ /* Available measurement modes is current capabilities */
+ p->capabilities(p, mmodes, NULL, NULL);
+ }
+
+ if (cconds != NULL)
+ *cconds = inst_calc_unknown;
+
+ if (conf_ix != NULL)
+ *conf_ix = 0;
+
+ return inst_ok;
+}
+
+/* Check the device measurement mode */
+static inst_code check_mode(
+inst *p,
+inst_mode m) { /* Requested mode */
+ return inst_unsupported;
+}
+
+/* Set the device measurement mode */
+static inst_code set_mode(
+inst *p,
+inst_mode m) { /* Requested mode */
+ return inst_unsupported;
+}
+
+/* Return array of display type selectors */
+static inst_code get_disptypesel(
+inst *pp,
+int *pnsels, /* Return number of display types */
+inst_disptypesel **psels, /* Return the array of display types */
+int allconfig, /* nz to return list for all configs, not just current. */
+int recreate /* nz to re-check for new ccmx & ccss files */
+) {
+ return inst_unsupported;
+}
+
+/* Set the display type */
+static inst_code set_disptype(
+inst *pp,
+int ix /* index into the inst_disptypesel[] */
+) {
+ return inst_unsupported;
+}
+
+/* Get a status or set or get an option (default implementation) */
+inst_code inst_get_set_opt_def(
+inst *p,
+inst_opt_type m, /* Requested option type */
+va_list args) { /* Option parameters */
+
+ return inst_unsupported;
+}
+
+/* Get a status or set or get an option */
+static inst_code get_set_opt(
+inst *p,
+inst_opt_type m, /* Requested status type */
+...) { /* Status parameters */
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(p, m, args); /* Call the above */
+ va_end(args);
+
+ return rv;
+}
+
+/* Read a full test chart composed of multiple sheets */
+/* DOESN'T use the trigger mode */
+/* Return the inst error code */
+static inst_code read_chart(
+inst *p,
+int npatch, /* Total patches/values in chart */
+int pich, /* Passes (rows) in chart */
+int sip, /* Steps in each pass (patches in each row) */
+int *pis, /* Passes in each strip (rows in each sheet) */
+int chid, /* Chart ID number */
+ipatch *vals) { /* Pointer to array of values */
+
+ return inst_unsupported;
+}
+
+/* For an xy instrument, release the paper */
+/* (if cap has inst_xy_holdrel) */
+/* Return the inst error code */
+static inst_code xy_sheet_release(
+inst *p) {
+ return inst_unsupported;
+}
+
+/* For an xy instrument, hold the paper */
+/* (if cap has inst_xy_holdrel) */
+/* Return the inst error code */
+static inst_code xy_sheet_hold(
+inst *p) {
+ return inst_unsupported;
+}
+
+/* For an xy instrument, allow the user to locate a point */
+/* (if cap has inst_xy_locate) */
+/* Return the inst error code */
+static inst_code xy_locate_start(
+inst *p) {
+ return inst_unsupported;
+}
+
+/* For an xy instrument, read back the location */
+/* (if cap has inst_xy_locate) */
+/* Return the inst error code */
+static inst_code xy_get_location(
+inst *p,
+double *x, double *y) {
+ return inst_unsupported;
+}
+
+/* For an xy instrument, end allowing the user to locate a point */
+/* (if cap has inst_xy_locate) */
+/* Return the inst error code */
+static inst_code xy_locate_end(
+inst *p) {
+ return inst_unsupported;
+}
+
+/* For an xy instrument, move the measurement point */
+/* (if cap has inst_xy_position) */
+/* Return the inst error code */
+static inst_code xy_position(
+inst *p,
+int measure, /* nz for measure point, z for locate point */
+double x, double y) {
+ return inst_unsupported;
+}
+
+/* For an xy instrument, try and clear the table after an abort */
+/* Return the inst error code */
+static inst_code xy_clear(
+inst *p) {
+ return inst_unsupported;
+}
+
+/* Read a sheet full of patches using xy mode */
+/* DOESN'T use the trigger mode */
+/* Return the inst error code */
+static inst_code read_xy(
+inst *p,
+int pis, /* Passes in strips (letters in sheet) */
+int sip, /* Steps in pass (numbers in sheet) */
+int npatch, /* Total patches in strip (skip in last pass) */
+char *pname, /* Starting pass name (' A' to 'ZZ') */
+char *sname, /* Starting step name (' 1' to '99') */
+double ox, double oy, /* Origin of first patch */
+double ax, double ay, /* pass increment */
+double aax, double aay, /* pass offset for odd patches */
+double px, double py, /* step/patch increment */
+ipatch *vals) { /* Pointer to array of values */
+ return inst_unsupported;
+}
+
+/* Read a set of strips (applicable to strip reader) */
+/* Obeys the trigger mode set */
+/* Return the inst error code */
+static inst_code read_strip(
+inst *p,
+char *name, /* Strip name (up to 7 chars) */
+int npatch, /* Number of patches in each pass */
+char *pname, /* Pass name (3 chars) */
+int sguide, /* Guide number (decrements by 5) */
+double pwid, /* Patch width in mm (For DTP20/DTP41) */
+double gwid, /* Gap width in mm (For DTP20/DTP41) */
+double twid, /* Trailer width in mm (For DTP41T) */
+ipatch *vals) { /* Pointer to array of values */
+ return inst_unsupported;
+}
+
+/* Read a single sample (applicable to spot instruments) */
+/* Obeys the trigger mode set */
+/* Return the inst error code */
+static inst_code read_sample(
+inst *p,
+char *name, /* Patch identifier (up to 7 chars) */
+ipatch *val, /* Pointer to value to be returned */
+instClamping clamp) { /* NZ to clamp XYZ to be +ve */
+ return inst_unsupported;
+}
+
+/* Measure the emissive refresh rate in Hz. */
+static inst_code read_refrate(
+inst *p,
+double *ref_rate) {
+ if (ref_rate != NULL)
+ *ref_rate = 0.0;
+ return inst_unsupported;
+}
+
+/* Determine if a calibration is needed. Returns inst_calt_none if not */
+/* or unknown, or a mask of the needed calibrations. */
+/* Default implementation - call through to get_n_a_cals() */
+static inst_cal_type needs_calibration(
+inst *p) {
+ inst_cal_type n_cals;
+
+ if (p->get_n_a_cals(p, &n_cals, NULL) != inst_ok)
+ return inst_calt_none;
+
+ return n_cals;
+}
+
+/* Return combined mask of of needed or available inst_cal_type's */
+/* for the current mode. */
+inst_code inst_get_n_a_cals(
+struct _inst *p,
+inst_cal_type *n_cals,
+inst_cal_type *a_cals) {
+
+ if (n_cals != NULL)
+ *n_cals = inst_calc_none;
+
+ if (a_cals != NULL)
+ *a_cals = inst_mode_none;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+/* DOESN'T use the trigger mode */
+/* Return inst_unsupported if calibration type is not appropriate. */
+static inst_code calibrate(
+inst *p,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN]) { /* Condition identifier (ie. white reference ID, filter ID) */
+ return inst_unsupported;
+}
+
+/* Measure a display update delay. It is assumed that a */
+/* White to black change has been made to the displayed color, */
+/* and this will measure the time it took for the update to */
+/* be noticed by the instrument, up to 1.0 seconds. */
+/* inst_misread will be returned on failure to find a transition. */
+static inst_code meas_delay(
+inst *p,
+int *msecdelay) { /* Return the number of msec */
+ return inst_unsupported;
+}
+
+/* Return the last calibrated refresh rate in Hz. Returns: */
+/* inst_unsupported - if this instrument doesn't suport a refresh mode */
+/* or is unable to retrieve the refresh rate */
+/* inst_needs_cal - if the refresh rate value is not valid */
+/* inst_misread - if no refresh rate could be determined */
+/* inst_ok - on returning a valid reading */
+static inst_code get_refr_rate(
+struct _inst *p,
+double *ref_rate) {
+ if (ref_rate != NULL)
+ *ref_rate = 0.0;
+ return inst_unsupported;
+}
+
+/* Set the calibrated refresh rate in Hz. */
+/* Set refresh rate to 0.0 to mark it as invalid */
+/* Rates outside the range 5.0 to 150.0 Hz will return an error */
+static inst_code set_refr_rate(
+struct _inst *p,
+double ref_rate) {
+ return inst_unsupported;
+}
+
+/* Insert a compensation filter in the instrument readings */
+/* This is typically needed if an adapter is being used, that alters */
+/* the spectrum of the light reaching the instrument */
+/* To remove the filter, pass NULL for the filter filename */
+static inst_code comp_filter(
+inst *p,
+char *filtername) { /* File containing compensating filter */
+ return inst_unsupported;
+}
+
+/* Insert a colorimetric correction matrix in the instrument XYZ readings */
+/* This is only valid for colorimetric instruments. */
+/* To remove the matrix, pass NULL for the matrix */
+static inst_code col_cor_mat(
+struct _inst *p,
+double mtx[3][3]) { /* XYZ matrix */
+ return inst_unsupported;
+}
+
+/* Use a Colorimeter Calibration Spectral Set to set the */
+/* instrumen calibration. */
+/* This is only valid for colorimetric instruments. */
+/* To set calibration back to default, pass NULL for ccss. */
+static inst_code col_cal_spec_set(
+inst *pp,
+xspect *sets,
+int no_sets) {
+ return inst_unsupported;
+}
+
+/* Supply a user interaction callback function. */
+static void set_uicallback(
+inst *pp,
+inst_code (*uicallback)(void *cntx, inst_ui_purp purp),
+void *cntx) {
+ pp->uicallback = uicallback;
+ pp->uic_cntx = cntx;
+}
+
+/* Supply an asynchronous event callback function. */
+static void set_event_callback(
+inst *pp,
+void (*eventcallback)(void *cntx, inst_event_type event),
+void *cntx) {
+ pp->eventcallback = eventcallback;
+ pp->event_cntx = cntx;
+}
+
+/* Generic inst error codes interpretation */
+static char *inst_interp_error(inst *p, inst_code ec) {
+ switch(ec & inst_mask) {
+ case inst_ok:
+ return "No error";
+ case inst_notify:
+ return "Notification";
+ case inst_warning:
+ return "Warning";
+ case inst_no_coms:
+ return "Internal error - communications needed but not established";
+ case inst_no_init:
+ return "Internal error - initialisation needed but not done";
+ case inst_internal_error:
+ return "Internal software error";
+ case inst_coms_fail:
+ return "Communications failure";
+ case inst_unknown_model:
+ return "Not expected instrument model";
+ case inst_protocol_error:
+ return "Communication protocol breakdown";
+ case inst_user_abort:
+ return "User hit Abort Key";
+ case inst_user_trig:
+ return "User hit Trigger Key";
+ case inst_misread:
+ return "Measurement misread";
+ case inst_nonesaved:
+ return "No saved data to read";
+ case inst_nochmatch:
+ return "Chart being read doesn't match chart expected";
+ case inst_needs_cal:
+ return "Instrument needs calibration";
+ case inst_cal_setup:
+ return "Instrument needs to be setup for calibration";
+ case inst_unsupported:
+ return "Unsupported function";
+ case inst_unexpected_reply:
+ return "Unexpected Reply";
+ case inst_wrong_config:
+ return "Wrong Sensor Position";
+ case inst_wrong_setup:
+ return "Wrong or conflicting setup";
+ case inst_bad_parameter:
+ return "Bad Parameter Value";
+ case inst_hardware_fail:
+ return "Hardware Failure";
+ case inst_other_error:
+ return "Non-specific error";
+ }
+ return "Unknown inst error code";
+}
+
+/* Instrument specific error codes interpretation */
+static char *interp_error(inst *p, int ec) {
+ return "interp_error is uninplemented in base class!";
+}
+
+/* Return the last serial communication error code */
+/* (This is used for deciding fallback/retry strategies) */
+static int last_scomerr(inst *p) {
+ return p->icom->lserr;
+}
+
+/* Convert instrument specific inst_wrong_config error to inst_config enum */
+static inst_config config_enum(inst *p, int ec) {
+ return inst_conf_unknown;
+}
+
+/* ---------------------------------------------- */
+/* Virtual constructor. */
+/* Return NULL for unknown instrument, */
+/* or serial instrument if nocoms == 0. */
+extern inst *new_inst(
+icompath *path, /* Device path to instrument */
+int nocoms, /* Don't open if communications are needed to establish inst type */
+a1log *log, /* log to use */
+inst_code (*uicallback)(void *cntx, inst_ui_purp purp), /* optional uicallback */
+void *cntx /* Context for callback */
+) {
+ instType itype = instUnknown; /* Actual type */
+ icoms *icom;
+ inst *p = NULL;
+
+ if ((icom = new_icoms(path, log)) == NULL) {
+ return NULL;
+ }
+
+ /* Set instrument type from USB port, if not specified */
+ itype = icom->itype; /* Instrument type if its known from usb/hid */
+#ifdef ENABLE_SERIAL
+ if (itype == instUnknown && !nocoms)
+ itype = ser_inst_type(icom, uicallback, cntx); /* Else type from serial */
+#endif /* ENABLE_SERIAL */
+
+
+#ifdef ENABLE_SERIAL
+ if (itype == instDTP22)
+ p = (inst *)new_dtp22(icom, itype);
+ else if (itype == instDTP41)
+ p = (inst *)new_dtp41(icom, itype);
+ else if (itype == instDTP51)
+ p = (inst *)new_dtp51(icom, itype);
+ else if (itype == instDTP92)
+ p = (inst *)new_dtp92(icom, itype);
+ else if ((itype == instSpectrolino ) ||
+ (itype == instSpectroScan ) ||
+ (itype == instSpectroScanT))
+ p = (inst *)new_ss(icom, itype);
+/* NYI
+ else if (itype == instSpectrocam)
+ p = (inst *)new_spc(icom, itype);
+*/
+#endif /* ENABLE_SERIAL */
+
+#ifdef ENABLE_USB
+ if (itype == instDTP94)
+ p = (inst *)new_dtp92(icom, itype);
+ else if (itype == instDTP20)
+ p = (inst *)new_dtp20(icom, itype);
+ else if (itype == instI1Disp1 ||
+ itype == instI1Disp2)
+ p = (inst *)new_i1disp(icom, itype);
+ else if (itype == instI1Disp3)
+ p = (inst *)new_i1d3(icom, itype);
+ else if (itype == instI1Monitor)
+ p = (inst *)new_i1pro(icom, itype);
+ else if ((itype == instI1Pro) ||
+ (itype == instI1Pro2))
+ p = (inst *)new_i1pro(icom, itype);
+ else if (itype == instColorMunki)
+ p = (inst *)new_munki(icom, itype);
+ else if (itype == instHCFR)
+ p = (inst *)new_hcfr(icom, itype);
+ else if (itype == instSpyder2)
+ p = (inst *)new_spyd2(icom, itype);
+ else if (itype == instSpyder3)
+ p = (inst *)new_spyd2(icom, itype);
+ else if (itype == instSpyder4)
+ p = (inst *)new_spyd2(icom, itype);
+ else if (itype == instHuey)
+ p = (inst *)new_huey(icom, itype);
+ else if (itype == instSmile)
+ p = (inst *)new_i1disp(icom, itype);
+ else if (itype == instColorHug)
+ p = (inst *)new_colorhug(icom, itype);
+#endif /* ENABLE_USB */
+
+ /* Nothing matched */
+ if (p == NULL)
+ return NULL;
+
+ /* Add default methods if constructor did not supply them */
+ if (p->init_coms == NULL)
+ p->init_coms = init_coms;
+ if (p->init_inst == NULL)
+ p->init_inst = init_inst;
+ if (p->get_itype == NULL)
+ p->get_itype = get_itype;
+ if (p->get_serial_no == NULL)
+ p->get_serial_no = get_serial_no;
+ if (p->capabilities == NULL)
+ p->capabilities = capabilities;
+ if (p->meas_config == NULL)
+ p->meas_config = meas_config;
+ if (p->set_mode == NULL)
+ p->set_mode = set_mode;
+ if (p->get_disptypesel == NULL)
+ p->get_disptypesel = get_disptypesel;
+ if (p->set_disptype == NULL)
+ p->set_disptype = set_disptype;
+ if (p->get_set_opt == NULL)
+ p->get_set_opt = get_set_opt;
+ if (p->read_chart == NULL)
+ p->read_chart = read_chart;
+ if (p->xy_sheet_release == NULL)
+ p->xy_sheet_release = xy_sheet_release;
+ if (p->xy_sheet_hold == NULL)
+ p->xy_sheet_hold = xy_sheet_hold;
+ if (p->xy_locate_start == NULL)
+ p->xy_locate_start = xy_locate_start;
+ if (p->xy_get_location == NULL)
+ p->xy_get_location = xy_get_location;
+ if (p->xy_locate_end == NULL)
+ p->xy_locate_end = xy_locate_end;
+ if (p->xy_position == NULL)
+ p->xy_position = xy_position;
+ if (p->xy_clear == NULL)
+ p->xy_clear = xy_clear;
+ if (p->read_xy == NULL)
+ p->read_xy = read_xy;
+ if (p->read_strip == NULL)
+ p->read_strip = read_strip;
+ if (p->read_sample == NULL)
+ p->read_sample = read_sample;
+ if (p->read_refrate == NULL)
+ p->read_refrate = read_refrate;
+ if (p->needs_calibration == NULL)
+ p->needs_calibration = needs_calibration;
+ if (p->get_n_a_cals == NULL)
+ p->get_n_a_cals = inst_get_n_a_cals;
+ if (p->calibrate == NULL)
+ p->calibrate = calibrate;
+ if (p->meas_delay == NULL)
+ p->meas_delay = meas_delay;
+ if (p->get_refr_rate == NULL)
+ p->get_refr_rate = get_refr_rate;
+ if (p->set_refr_rate == NULL)
+ p->set_refr_rate = set_refr_rate;
+ if (p->comp_filter == NULL)
+ p->comp_filter = comp_filter;
+ if (p->col_cor_mat == NULL)
+ p->col_cor_mat = col_cor_mat;
+ if (p->col_cal_spec_set == NULL)
+ p->col_cal_spec_set = col_cal_spec_set;
+ if (p->set_uicallback == NULL)
+ p->set_uicallback = set_uicallback;
+ if (p->set_event_callback == NULL)
+ p->set_event_callback = set_event_callback;
+ if (p->inst_interp_error == NULL)
+ p->inst_interp_error = inst_interp_error;
+ if (p->interp_error == NULL)
+ p->interp_error = interp_error;
+ if (p->last_scomerr == NULL)
+ p->last_scomerr = last_scomerr;
+ if (p->config_enum == NULL)
+ p->config_enum = config_enum;
+
+ /* Set the provided user interaction callback */
+ p->set_uicallback(p, uicallback, cntx);
+
+ return p;
+}
+
+/* --------------------------------------------------- */
+/* Display type list support */
+
+/* Default display type UI selector characters:
+
+ g Generic
+ n Non-refresh (Generic)
+ r Refresh (Generic)
+
+ c CRT
+ l LCD (Generic or CCFL Backlight)
+ f LCD, CCFL Backlight
+ b LCD, RGB LED Backlight
+ L LCD, Wide Gamut, CCFL Backlight
+ B LCD, Wide Gamut, RGB LED Backlight
+ e LCD, White LED Backlight
+ o OLED
+ a AMOLED
+ p Projector (Generic)
+ m Plasma
+
+ F Factory base calibration
+ R Raw sensor values
+ */
+
+
+/* Free a display type list */
+void inst_del_disptype_list(inst_disptypesel *list, int no) {
+
+ if (list != NULL) {
+ int i;
+ for (i = 0; i < no; i++) {
+ if (list[i].path != NULL)
+ free(list[i].path);
+ if (list[i].sets != NULL)
+ free(list[i].sets);
+ }
+ free(list);
+ }
+}
+
+/* Ensure that the list is large enough for n+1 entries (+1 == end marker) */
+/* Return NULL on malloc error */
+static inst_disptypesel *expand_dlist(inst_disptypesel *list, int nlist, int *nalist) {
+
+ if ((nlist+1) > *nalist) {
+ int xnalist = (2 * nlist + 6);
+ inst_disptypesel *xlist;
+
+ if ((xlist = realloc(list, xnalist * sizeof(inst_disptypesel))) == NULL) {
+ inst_del_disptype_list(list, nlist);
+ *nalist = 0;
+ return NULL;
+ }
+ *nalist = xnalist;
+ list = xlist;
+ }
+
+ /* Set end marker */
+ list[nlist].flags = inst_dtflags_end;
+ list[nlist].cbid = 0;
+ list[nlist].sel[0] = '\000';
+ list[nlist].desc[0] = '\000';
+ list[nlist].refr = 0;
+ list[nlist].ix = 0;
+ list[nlist].path = NULL;
+ list[nlist].sets = NULL;
+ list[nlist].no_sets = 0;
+
+ return list;
+}
+
+/* For each selector we need to:
+
+ check each selector char
+ if already used,
+ remove it.
+ if no selector remain,
+ allocate a free one.
+ mark all used selectors
+*/
+
+/* Set the selection characters */
+/* return NZ if we have run out */
+static int set_sel(char *sel, char *usels, int *k, char *asels) {
+ char *d, *s;
+
+ /* First remove any used chars from selector */
+ for (d = s = sel; *s != '\000'; s++) {
+ if (usels[*s] == 0)
+ *d++ = *s;
+ }
+ *d = '\000';
+
+ /* Add a selector if we need one */
+ if (sel[0] == '\000') {
+
+ /* Locate the next unused selector */
+ for (;;) {
+ if (asels[*k] == '\000') /* Run out of selectors */
+ return 1;
+ if (usels[*k] == 0)
+ break;
+ (*k)++;
+ }
+ sel[0] = asels[*k];
+ sel[1] = '\000';
+ usels[sel[0]] = 1;
+ (*k)++;
+ }
+
+ return 0;
+}
+
+/* Create the display type list */
+inst_code inst_creat_disptype_list(inst *p,
+int *pndtlist, /* Number in returned list */
+inst_disptypesel **pdtlist, /* Returned list */
+inst_disptypesel *sdtlist, /* Static list */
+int doccss, /* Add installed ccss files */
+int doccmx /* Add matching installed ccmx files */
+) {
+ inst_disptypesel *list = NULL;
+ int i, j, k, nlist = 0, nalist = 0;
+ char usels[256]; /* Used selectors */
+ static char *asels = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ /* free the old list */
+ inst_del_disptype_list(*pdtlist, *pndtlist);
+ *pdtlist = NULL;
+ *pndtlist = 0;
+
+ for (i = 0; i < 256; i++)
+ usels[i] = 0;
+ k = 0;
+
+ /* Add entries from the static list */
+ /* Count the number in the static list */
+ for (i = 0; !(sdtlist[i].flags & inst_dtflags_end); i++) {
+
+ if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL)
+ return inst_internal_error;
+
+ list[nlist-1] = sdtlist[i]; /* Struct copy */
+
+ if (set_sel(list[nlist-1].sel, usels, &k, asels)) {
+ a1loge(p->log, 1, "inst_creat_disptype_list run out of selectors\n");
+ break;
+ }
+ }
+
+ k = 0; /* Next selector index */
+
+ /* Add any ccss's */
+ if (doccss) {
+ iccss *ss_list;
+ if ((ss_list = list_iccss(NULL)) == NULL) {
+ free(list);
+ return inst_internal_error;
+ }
+
+ for (i = 0; ss_list[i].path != NULL; i++) {
+
+ if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL)
+ return inst_internal_error;
+
+ list[nlist-1].flags = inst_dtflags_ccss;
+
+ if (ss_list[i].sel != NULL) {
+ strncpy(list[nlist-1].sel, ss_list[i].sel, INST_DTYPE_SEL_LEN);
+ list[nlist-1].sel[INST_DTYPE_SEL_LEN-1] = '\000';
+ }
+ if (set_sel(list[nlist-1].sel, usels, &k, asels)) {
+ a1loge(p->log, 1, "inst_creat_disptype_list run out of selectors\n");
+ break;
+ }
+
+ strncpy(list[nlist-1].desc, ss_list[i].desc, INST_DTYPE_DESC_LEN);
+ list[nlist-1].desc[INST_DTYPE_DESC_LEN-1] = '\000';
+ list[nlist-1].refr = ss_list[i].refr;
+ list[nlist-1].ix = 0;
+ list[nlist-1].path = ss_list[i].path; ss_list[i].path = NULL;
+ list[nlist-1].sets = ss_list[i].sets; ss_list[i].sets = NULL;
+ list[nlist-1].no_sets = ss_list[i].no_sets; ss_list[i].no_sets = 0;
+ }
+ }
+
+ /* Add any ccmx's */
+ if (doccmx) {
+ iccmx *ss_list;
+
+ /* Just ccmx's for this instrument */
+ if ((ss_list = list_iccmx(inst_name(p->itype), NULL)) == NULL) {
+ free(list);
+ return inst_internal_error;
+ }
+
+ for (i = 0; ss_list[i].path != NULL; i++) {
+
+ /* Check that we can find the matching base calibation */
+ for (j = 0; j < nlist; j++) {
+ if (list[j].cbid == ss_list[i].cbid)
+ break;
+ }
+ if (j >= nlist) {
+ a1loge(p->log, 1, "inst_creat_disptype_list can't find cbid %d for '%s'\n",list[j].cbid, list[j].path);
+ continue;
+ }
+
+ if ((list = expand_dlist(list, ++nlist, &nalist)) == NULL)
+ return inst_internal_error;
+
+ list[nlist-1].flags = inst_dtflags_ccmx;
+
+ if (ss_list[i].sel != NULL) {
+ strncpy(list[nlist-1].sel, ss_list[i].sel, INST_DTYPE_SEL_LEN);
+ list[nlist-1].sel[INST_DTYPE_SEL_LEN-1] = '\000';
+ }
+ if (set_sel(list[nlist-1].sel, usels, &k, asels)) {
+ a1loge(p->log, 1, "inst_creat_disptype_list run out of selectors\n");
+ break;
+ }
+ strncpy(list[nlist-1].desc, ss_list[i].desc, INST_DTYPE_DESC_LEN);
+ list[nlist-1].desc[INST_DTYPE_DESC_LEN-1] = '\000';
+ list[nlist-1].refr = ss_list[i].refr;
+ list[nlist-1].ix = list[j].ix; /* Copy underlying cal selection from base */
+ list[nlist-1].path = ss_list[i].path; ss_list[i].path = NULL;
+ icmCpy3x3(list[nlist-1].mat, ss_list[i].mat);
+ }
+ }
+
+ if (pndtlist != NULL)
+ *pndtlist = nlist;
+ if (pdtlist != NULL)
+ *pdtlist = list;
+
+ return inst_ok;
+}
+
+/* ============================================================= */
+/* CCMX location support */
+
+/* return a list of installed ccmx files. */
+/* if inst != NULL, return those that match the given instrument. */
+/* The list is sorted by description and terminated by a NULL entry. */
+/* If no is != NULL, return the number in the list */
+/* Return NULL and -1 if there is a malloc error */
+iccmx *list_iccmx(char *inst, int *no) {
+ int i, j;
+ iccmx *rv;
+
+ char **paths = NULL;
+ int npaths = 0;
+
+
+ npaths = xdg_bds(NULL, &paths, xdg_data, xdg_read, xdg_user,
+ "ArgyllCMS/\052.ccmx" XDG_FUDGE "color/\052.ccmx"
+ );
+
+ if ((rv = malloc(sizeof(iccmx) * (npaths + 1))) == NULL) {
+ a1loge(g_log, 1, "list_iccmx: malloc of paths failed\n");
+ xdg_free(paths, npaths);
+ if (no != NULL) *no = -1;
+ return NULL;
+ }
+
+ for (i = j = 0; i < npaths; i++) {
+ ccmx *cs;
+ int len;
+ char *pp;
+ char *tech, *disp;
+ int cbid, refr;
+
+ if ((cs = new_ccmx()) == NULL) {
+ a1loge(g_log, 1, "list_iccmx: new_ccmx failed\n");
+ for (--j; j>= 0; j--) {
+ free(rv[j].path);
+ free(rv[j].desc);
+ }
+ xdg_free(paths, npaths);
+ if (no != NULL) *no = -1;
+ return NULL;
+ }
+ if (cs->read_ccmx(cs, paths[i])) {
+ cs->del(cs);
+ continue; /* Skip any unreadable ccmx's */
+ }
+
+ /* Skip any that don't match */
+ if (inst != NULL && cs->inst != NULL && strcmp(inst, cs->inst) != 0)
+ continue;
+
+ if ((tech = cs->tech) == NULL)
+ tech = "";
+ if ((disp = cs->disp) == NULL)
+ disp = "";
+ cbid = cs->cbid;
+ refr = cs->refrmode;
+ len = strlen(tech) + strlen(disp) + 4;
+ if ((pp = malloc(len)) == NULL) {
+ a1loge(g_log, 1, "list_iccmx: malloc failed\n");
+ for (--j; j >= 0; j--) {
+ free(rv[j].path);
+ free(rv[j].desc);
+ }
+ cs->del(cs);
+ free(rv);
+ xdg_free(paths, npaths);
+ if (no != NULL) *no = -1;
+ return NULL;
+ }
+ if ((rv[j].path = strdup(paths[i])) == NULL) {
+ a1loge(g_log, 1, "list_iccmx: strdup failed\n");
+ for (--j; j >= 0; j--) {
+ free(rv[j].path);
+ free(rv[j].desc);
+ }
+ cs->del(cs);
+ free(rv);
+ free(pp);
+ xdg_free(paths, npaths);
+ if (no != NULL) *no = -1;
+ return NULL;
+ }
+ strcpy(pp, tech);
+ strcat(pp, " (");
+ strcat(pp, disp);
+ strcat(pp, ")");
+ rv[j].desc = pp;
+ rv[j].cbid = cbid;
+ rv[j].refr = refr;
+ rv[j].sel = cs->sel; cs->sel = NULL;
+ icmCpy3x3(rv[j].mat, cs->matrix);
+ cs->del(cs);
+ j++;
+ }
+ xdg_free(paths, npaths);
+ rv[j].path = NULL;
+ rv[j].desc = NULL;
+ rv[j].cbid = 0;
+ rv[j].refr = -1;
+ rv[j].sel = NULL;
+ if (no != NULL)
+ *no = j;
+
+ /* Sort the list */
+#define HEAP_COMPARE(A,B) (strcmp(A.desc, B.desc) < 0)
+ HEAPSORT(iccmx, rv, j)
+#undef HEAP_COMPARE
+
+ return rv;
+}
+
+/* Free up a iccmx list */
+void free_iccmx(iccmx *list) {
+ int i;
+
+ if (list != NULL) {
+ for (i = 0; list[i].path != NULL || list[i].desc != NULL; i++) {
+ if (list[i].path != NULL)
+ free(list[i].path);
+ if (list[i].desc != NULL)
+ free(list[i].desc);
+ if (list[i].sel != NULL)
+ free(list[i].sel);
+ }
+ free(list);
+ }
+}
+
+/* ============================================================= */
+/* CCSS location support */
+
+/* return a list of installed ccss files. */
+/* The list is sorted by description and terminated by a NULL entry. */
+/* If no is != NULL, return the number in the list */
+/* Return NULL and -1 if there is a malloc error */
+iccss *list_iccss(int *no) {
+ int i, j;
+ iccss *rv;
+
+ char **paths = NULL;
+ int npaths = 0;
+
+
+ npaths = xdg_bds(NULL, &paths, xdg_data, xdg_read, xdg_user,
+ "ArgyllCMS/\052.ccss" XDG_FUDGE "color/\052.ccss"
+ );
+
+ if ((rv = malloc(sizeof(iccss) * (npaths + 1))) == NULL) {
+ a1loge(g_log, 1, "list_iccss: malloc of paths failed\n");
+ xdg_free(paths, npaths);
+ if (no != NULL) *no = -1;
+ return NULL;
+ }
+
+ for (i = j = 0; i < npaths; i++) {
+ ccss *cs;
+ int len;
+ char *pp;
+ char *tech, *disp;
+ int refr;
+
+ if ((cs = new_ccss()) == NULL) {
+ a1loge(g_log, 1, "list_iccss: new_ccss failed\n");
+ for (--j; j>= 0; j--) {
+ free(rv[j].path);
+ free(rv[j].desc);
+ }
+ xdg_free(paths, npaths);
+ if (no != NULL) *no = -1;
+ return NULL;
+ }
+ if (cs->read_ccss(cs, paths[i])) {
+ cs->del(cs);
+ continue; /* Skip any unreadable ccss's */
+ }
+
+ if ((tech = cs->tech) == NULL)
+ tech = "";
+ if ((disp = cs->disp) == NULL)
+ disp = "";
+ refr = cs->refrmode;
+ len = strlen(tech) + strlen(disp) + 4;
+ if ((pp = malloc(len)) == NULL) {
+ a1loge(g_log, 1, "list_iccss: malloc failed\n");
+ for (--j; j >= 0; j--) {
+ free(rv[j].path);
+ free(rv[j].desc);
+ }
+ cs->del(cs);
+ free(rv);
+ xdg_free(paths, npaths);
+ if (no != NULL) *no = -1;
+ return NULL;
+ }
+ if ((rv[j].path = strdup(paths[i])) == NULL) {
+ a1loge(g_log, 1, "list_iccss: strdup failed\n");
+ for (--j; j >= 0; j--) {
+ free(rv[j].path);
+ free(rv[j].desc);
+ }
+ cs->del(cs);
+ free(rv);
+ free(pp);
+ xdg_free(paths, npaths);
+ if (no != NULL) *no = -1;
+ return NULL;
+ }
+ strcpy(pp, tech);
+ strcat(pp, " (");
+ strcat(pp, disp);
+ strcat(pp, ")");
+ rv[j].desc = pp;
+ rv[j].refr = refr;
+ rv[j].sel = cs->sel; cs->sel = NULL;
+ rv[j].sets = cs->samples; cs->samples = NULL;
+ rv[j].no_sets = cs->no_samp; cs->no_samp = 0;
+ cs->del(cs);
+ j++;
+ }
+ xdg_free(paths, npaths);
+ rv[j].path = NULL;
+ rv[j].desc = NULL;
+ rv[j].refr = -1;
+ rv[j].sel = NULL;
+ rv[j].sets = NULL;
+ rv[j].no_sets = 0;
+ if (no != NULL)
+ *no = j;
+
+ /* Sort the list */
+#define HEAP_COMPARE(A,B) (strcmp(A.desc, B.desc) < 0)
+ HEAPSORT(iccss, rv, j)
+#undef HEAP_COMPARE
+
+ return rv;
+}
+
+/* Free up a iccss list */
+void free_iccss(iccss *list) {
+ int i;
+
+ if (list != NULL) {
+ for (i = 0; list[i].path != NULL || list[i].desc != NULL; i++) {
+ if (list[i].path != NULL)
+ free(list[i].path);
+ if (list[i].desc != NULL)
+ free(list[i].desc);
+ if (list[i].sel != NULL)
+ free(list[i].sel);
+ if (list[i].sets != NULL)
+ free(list[i].sets);
+ }
+ free(list);
+ }
+}
+
+/* ============================================================= */
+
+#ifdef ENABLE_SERIAL
+static void hex2bin(char *buf, int len);
+
+/* Heuristicly determine the instrument type for */
+/* a serial connection, and instUnknown if not serial. */
+/* Set it in icoms and also return it. */
+static instType ser_inst_type(
+ icoms *p,
+ inst_code (*uicallback)(void *cntx, inst_ui_purp purp), /* optional uicallback */
+ void *cntx /* Context for callback */
+) {
+ instType rv = instUnknown;
+ char buf[100];
+ baud_rate brt[] = { baud_9600, baud_19200, baud_4800, baud_2400,
+ baud_1200, baud_38400, baud_57600, baud_115200,
+ baud_600, baud_300, baud_110, baud_nc };
+ unsigned int etime;
+ unsigned int bi, i;
+ int se, len;
+ int xrite = 0;
+ int ss = 0;
+ int so = 0;
+
+#ifdef ENABLE_USB
+ if (p->usbd != NULL || p->hidd != NULL)
+ return p->itype;
+#endif /* ENABLE_USB */
+
+ bi = 0;
+
+ /* The tick to give up on */
+ etime = msec_time() + (long)(1000.0 * 20.0 + 0.5);
+
+ a1logd(p->log, 1, "ser_inst_type: Trying different baud rates (%u msec to go)\n",etime - msec_time());
+
+ /* Until we time out, find the correct baud rate */
+ for (i = bi; msec_time() < etime; i++) {
+ if (brt[i] == baud_nc)
+ i = 0;
+ if ((se = p->set_ser_port(p, fc_none, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 5, "ser_inst_type: set_ser_port failed with 0x%x\n",se);
+ return instUnknown; /* Give up */
+ }
+
+// a1logd(p->log, 5, "brt = %d\n",brt[i]);
+ if ((se = p->write_read(p, ";D024\r\n", buf, 100, '\r', 1, 0.5)) != inst_ok) {
+ /* Check for user abort */
+ if (uicallback != NULL) {
+ inst_code ev;
+ if ((ev = uicallback(cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 5, "ser_inst_type: User aborted\n");
+ return instUnknown;
+ }
+ }
+ }
+ len = strlen(buf);
+
+// a1logd(p->log, 5, "len = %d\n",len);
+ if (len < 4)
+ continue;
+
+ /* Is this an X-Rite error value such as "<01>" ? */
+ if (buf[0] == '<' && isdigit(buf[1]) && isdigit(buf[2]) && buf[3] == '>') {
+// a1logd(p->log, 5, "xrite\n");
+ xrite = 1;
+ break;
+ }
+
+ /* Is this a Spectrolino error resonse ? */
+ if (len >= 5 && strncmp(buf, ":26", 3) == 0) {
+// a1logd(p->log, 5, "spectrolino\n");
+ so = 1;
+ break;
+ }
+ /* Is this a SpectroScan response ? */
+ if (len >= 7 && strncmp(buf, ":D183", 5) == 0) {
+// a1logd(p->log, 5, "spectroscan\n");
+ ss = 1;
+ break;
+ }
+ }
+
+ if (msec_time() >= etime) { /* We haven't established comms */
+ a1logd(p->log, 5, "ser_inst_type: Failed to establish coms\n");
+ return instUnknown;
+ }
+
+ a1logd(p->log, 5, "ser_inst_type: Got coms with instrument\n");
+
+ /* Spectrolino */
+ if (so) {
+ rv = instSpectrolino;
+ }
+
+ /* SpectroScan */
+ if (ss) {
+ rv = instSpectroScan;
+ if ((se = p->write_read(p, ";D030\r\n", buf, 100, '\n', 1, 1.5)) == 0) {
+ if (strlen(buf) >= 41) {
+ hex2bin(&buf[5], 12);
+// a1logd(p->log, 5, "spectroscan type = '%s'\n",buf);
+ if (strncmp(buf, ":D190SpectroScanT", 17) == 0)
+ rv = instSpectroScanT;
+ }
+ }
+ }
+ if (xrite) {
+
+ /* Get the X-Rite model and version number */
+ if ((se = p->write_read(p, "SV\r\n", buf, 100, '>', 1, 2.5)) != 0)
+ return instUnknown;
+
+ if (strlen(buf) >= 12) {
+ if (strncmp(buf,"X-Rite DTP22",12) == 0)
+ rv = instDTP22;
+ if (strncmp(buf,"X-Rite DTP41",12) == 0)
+ rv = instDTP41;
+ if (strncmp(buf,"X-Rite DTP42",12) == 0)
+ rv = instDTP41;
+ if (strncmp(buf,"X-Rite DTP51",12) == 0)
+ rv = instDTP51;
+ if (strncmp(buf,"X-Rite DTP52",12) == 0)
+ rv = instDTP51;
+ if (strncmp(buf,"X-Rite DTP92",12) == 0)
+ rv = instDTP92;
+ if (strncmp(buf,"X-Rite DTP94",12) == 0)
+ rv = instDTP94;
+ }
+ }
+
+ a1logd(p->log, 5, "ser_inst_type: Instrument type is '%s'\n", inst_name(rv));
+
+ p->close_port(p); /* Or should we leave it open ?? */
+
+ p->itype = rv;
+
+ return rv;
+}
+
+/* Convert an ASCII Hex character to an integer. */
+static int h2b(char c) {
+ if (c >= '0' && c <= '9')
+ return (c-(int)'0');
+ if (c >= 'A' && c <= 'F')
+ return (10 + c-(int)'A');
+ if (c >= 'a' && c <= 'f')
+ return (10 + c-(int)'a');
+ return 0;
+}
+
+/* Convert a Hex encoded buffer into binary. */
+/* len is number of bytes out */
+static void hex2bin(char *buf, int len) {
+ int i;
+
+ for (i = 0; i < len; i++) {
+ buf[i] = (char)((h2b(buf[2 * i + 0]) << 4)
+ | (h2b(buf[2 * i + 1]) << 0));
+ }
+}
+
+#endif /* ENABLE_SERIAL */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spectro/inst.h b/spectro/inst.h
new file mode 100644
index 0000000..5b5d710
--- /dev/null
+++ b/spectro/inst.h
@@ -0,0 +1,999 @@
+
+#ifndef INST_H
+
+ /* instlib API definition. */
+
+ /* See spotread.c, chartread.c, illumread.c & ccxxmake.c for examples of */
+ /* the API usage. */
+
+ /* Abstract base class for common color instrument interface */
+ /* and other common instrument stuff. */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 15/3/2001
+ *
+ * Copyright 2001 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "insttypes.h" /* libinst Includes this functionality */
+#include "icoms.h" /* libinst Includes this functionality */
+#include "conv.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* ------------------------------------------------- */
+/* aprox. debug level guide:
+
+ 1,2 Applications, internal errors
+ 2,3 High level instrument drivers
+ 4,5 High level instrument communications
+ 6,7 High level serial/USB communications
+ 8,9 Low level serial/USB communications
+
+*/
+
+/* ------------------------------------------------- */
+/* Structure for holding an instrument patch reading */
+
+#define ICOM_MAX_LOC_LEN 10
+
+/* Type of measurement result */
+typedef enum { /* XYZ units, spectral units */
+ inst_mrt_none = 0, /* Not set */
+ inst_mrt_emission = 1, /* cd/m^2, mW/m^2/nm */
+ inst_mrt_ambient = 2, /* Lux/3.1415926 ?? */
+ inst_mrt_emission_flash = 3, /* cd/m^2.s, mW/m^2/nm.s*/
+ inst_mrt_ambient_flash = 4, /* Lux/3.1415926/s ?? */
+ inst_mrt_reflective = 5, /* %, %/nm */
+ inst_mrt_transmissive = 6 /* %, %/nm */
+} inst_meas_type;
+
+struct _ipatch {
+ char loc[ICOM_MAX_LOC_LEN]; /* patch location */
+
+ inst_meas_type mtype; /* Measurement type */
+
+ int XYZ_v; /* XYZ valid */
+ double XYZ[3]; /* XYZ values */
+
+ xspect sp; /* Spectrum. sp.spec_n > 0 if valid */
+ /* Reflectance/Transmittance 0.0 .. 100.0%, norm = 100.0 */
+ /* or mW/nm/m^2, norm = 1.0, etc. */
+
+ double duration; /* Apparent total duration in seconds (flash measurement) */
+ /* Typicall limited to sampling rate of instrument. */
+
+}; typedef struct _ipatch ipatch;
+
+/* ---------------------------------------- */
+/* Instrument interface abstract base class */
+
+/* Abstract return codes in ms byte. */
+/* Instrument dependant codes in ls byte. */
+/* Note :- update inst_interp_error() in inst.c if anything here is changed. */
+/* and also check all the instrument specific XXX_interp_code() routines too. */
+typedef enum {
+ inst_ok = 0x0000,
+ inst_notify = 0x0100, /* A Notification */
+ inst_warning = 0x0200, /* A Warning */
+ inst_no_coms = 0x0300, /* init_coms() hasn't been called yet */
+ inst_no_init = 0x0400, /* init_inst() hasn't been called yet */
+ inst_unsupported = 0x0500, /* Unsupported function */
+ inst_internal_error = 0x0600, /* Internal software error */
+ inst_coms_fail = 0x0700, /* Communication failure */
+ inst_unknown_model = 0x0800, /* Not the expected instrument */
+ inst_protocol_error = 0x0900, /* Read or Write protocol error */
+ inst_user_abort = 0x0A00, /* User hit escape */
+ inst_user_trig = 0x0C00, /* User hit trigger key */
+ inst_misread = 0x0E00, /* Bad reading, or strip misread */
+ inst_nonesaved = 0x0F00, /* No saved data to read */
+ inst_nochmatch = 0x1000, /* Chart doesn't match */
+ inst_needs_cal = 0x1100, /* Instrument needs calibration, and read retried */
+ inst_cal_setup = 0x1200, /* Calibration retry with correct setup is needed */
+ inst_wrong_config = 0x1300, /* Retry with correct inst. config./sensor posn. needed */
+ inst_unexpected_reply = 0x1400, /* Unexpected Reply */
+ inst_wrong_setup = 0x1500, /* Setup is wrong or conflicting */
+ inst_hardware_fail = 0x1600, /* Hardware failure */
+ inst_bad_parameter = 0x1700, /* Bad parameter value */
+ inst_other_error = 0x1800, /* Some other error */
+ inst_mask = 0xff00, /* inst_code mask value */
+ inst_imask = 0x00ff /* instrument specific mask value */
+} inst_code;
+
+/* Instrument capabilities & modes */
+/* Note that due to the binary combinations, capabilities is not definititive */
+/* as to valid modes. check_mode() is definitive. */
+typedef enum {
+ inst_mode_none = 0x00000000, /* No capability or mode */
+
+ /* Mode of light measurement */
+ inst_mode_reflection = 0x00000001, /* General reflection mode */
+ inst_mode_s_reflection = 0x00000002, /* General saved reflection mode */
+ inst_mode_transmission = 0x00000004, /* General transmission mode */
+ inst_mode_emission = 0x00000008, /* General emission mode */
+ inst_mode_illum_mask = 0x0000000f, /* Mask of sample illumination sub mode */
+
+ /* Access mode of measurement */
+ inst_mode_spot = 0x00000010, /* General spot measurement mode */
+ inst_mode_strip = 0x00000020, /* General strip measurement mode */
+ inst_mode_xy = 0x00000040, /* General X-Y measurement mode */
+ inst_mode_chart = 0x00000080, /* General chart measurement mode */
+ inst_mode_ambient = 0x00000100, /* General ambient measurement mode */
+ inst_mode_ambient_flash = 0x00000200, /* General ambient flash measurement mode */
+ inst_mode_tele = 0x00000400, /* General telephoto measurement mode */
+ // Hmm. Should there be a tele_flash mode ????
+ inst_mode_sub_mask = 0x000007f0, /* Mask of sub-mode */
+
+ /* Basic mode */
+ inst_mode_basic_mask = inst_mode_illum_mask | inst_mode_sub_mask,
+
+/*
+ possible UV modes:
+
+ Do the reflective measurement with UV rather than normal illuminant
+ [ Should this be reflectivity against 'A', or absolute ?? ]
+ (ie. spot, strip, xy or chart). inst_mode_ref_uv
+
+ Do a white & UV measurement at the start of each strip reading.
+ Return result with special call after each strip read.
+ inst_mode_ref_uv_strip_1
+
+ Do a dual white & UV measurement
+ [ Can do in one hit for spot, but how should two strip passes be handled ?
+ ie. two separate strip reads of phase 1 & then 2 ? ]
+ (ie. spot, strip, xy or chart). inst_mode_ref_uv_2pass
+
+ Get normal illuminant spectrum.
+
+ Get UV spectrum.
+
+ get_meas_illum_spectrum(mode);
+ */
+
+ /* Extra dependent modes */
+ inst_mode_emis_nonadaptive = 0x00000800, /* Emissom Non-adaptive mode */
+ inst_mode_ref_uv = 0x00001000, /* Ultra Violet measurement mode */
+ inst_mode_emis_refresh_ovd = 0x00002000, /* Emissom Refresh mode override */
+ inst_mode_emis_norefresh_ovd = 0x00006000, /* Emissom Non-refresh mode override */
+ inst_mode_dep_extra_mask = 0x00007800, /* Mask of measurement modifiers */
+
+ /* Extra independent modes */
+ inst_mode_colorimeter = 0x00004000, /* Colorimetric mode */
+ inst_mode_spectral = 0x00008000, /* Spectral mode */
+ inst_mode_highres = 0x00010000, /* High Resolution Spectral mode */
+ inst_mode_extra_mask = 0x0001c000, /* Mask of extra modes */
+
+ /* Configured for calibration & capable of returning it from inst_mode_calibration */
+ inst_mode_calibration = 0x80000000, /* Configured for calibration */
+
+ /* Combined operating modes (from above): */
+ /* These mode capabilities are also use to set the mode */
+ /* Test for a mode should be IMODETST(flags, mode) */
+ inst_mode_ref_spot = inst_mode_spot /* Reflection spot measurement mode */
+ | inst_mode_reflection,
+ inst_mode_ref_strip = inst_mode_strip /* Reflection strip measurement mode */
+ | inst_mode_reflection,
+ inst_mode_ref_xy = inst_mode_xy /* Reflection X-Y measurement mode */
+ | inst_mode_reflection,
+ inst_mode_ref_chart = inst_mode_chart /* Reflection Chart measurement mode */
+ | inst_mode_reflection,
+
+ inst_mode_s_ref_spot = inst_mode_spot /* Saved reflection spot measurement mode */
+ | inst_mode_s_reflection,
+ inst_mode_s_ref_strip = inst_mode_strip /* Saved reflection strip measurement mode */
+ | inst_mode_s_reflection,
+ inst_mode_s_ref_xy = inst_mode_xy /* Saved reflection X-Y measurement mode */
+ | inst_mode_s_reflection,
+ inst_mode_s_ref_chart = inst_mode_chart /* Saved reflection Chart measurement mode */
+ | inst_mode_s_reflection,
+
+ inst_mode_trans_spot = inst_mode_spot /* Transmission spot measurement mode */
+ | inst_mode_transmission,
+ inst_mode_trans_strip = inst_mode_strip /* Transmission strip measurement mode */
+ | inst_mode_transmission,
+ inst_mode_trans_xy = inst_mode_xy /* Transmission X-Y measurement mode */
+ | inst_mode_transmission,
+ inst_mode_trans_chart = inst_mode_chart /* Transmission chart measurement mode */
+ | inst_mode_transmission,
+
+ inst_mode_emis_spot = inst_mode_spot /* Spot emission measurement mode */
+ | inst_mode_emission,
+ inst_mode_emis_tele = inst_mode_tele /* Telephoto emission measurement mode */
+ | inst_mode_emission,
+ inst_mode_emis_ambient = inst_mode_ambient /* Ambient emission measurement mode */
+ | inst_mode_emission,
+ inst_mode_emis_ambient_flash = inst_mode_ambient_flash /* Ambient emission flash measurement */
+ | inst_mode_emission,
+
+ inst_mode_emis_strip = inst_mode_strip /* Strip emission measurement mode */
+ | inst_mode_emission,
+
+ inst_mode_measurement_mask = inst_mode_illum_mask /* Mask of exclusive measurement modes */
+ | inst_mode_sub_mask
+ | inst_mode_dep_extra_mask
+} inst_mode;
+
+/* Test for a specific mode */
+#define IMODETST(mbits, mode) (((mbits) & (mode)) == (mode))
+
+/* Test for a specific mode in capability and mode */
+#define IMODETST2(mcap, mbits, mode) (IMODETST(mcap, mode) && IMODETST(mbits, mode))
+
+/* Instrument capabilities 2 */
+/* (Available capabilities may be mode dependent) */
+typedef enum {
+ inst2_none = 0x00000000, /* No capabilities */
+
+ inst2_xy_holdrel = 0x00000001, /* Needs paper hold/release between each sheet */
+ inst2_xy_locate = 0x00000002, /* Needs user to locate patch locations */
+ inst2_xy_position = 0x00000004, /* Can be positioned at a given location */
+
+ inst2_meas_disp_update = 0x00000010, /* Is able to measure display update delay */
+ inst2_refresh_rate = 0x00000020, /* Is able to retrieve the calibrated refresh rate */
+
+ inst2_prog_trig = 0x00000100, /* Progromatic trigger measure capability */
+ inst2_user_trig = 0x00000200, /* User trigger measure capability */
+ inst2_switch_trig = 0x00000400, /* Inst. switch trigger measure capability */
+ inst2_user_switch_trig = 0x00000800, /* User or switch trigger measure capability */
+
+ inst2_bidi_scan = 0x00001000, /* Try and recognise patches scanned from either dir. */
+ inst2_cal_using_switch = 0x00002000, /* DTP22 special - use switch triggered calibration */
+ inst2_has_scan_toll = 0x00004000, /* Instrument will honour modified scan tollerance */
+ inst2_no_feedback = 0x00008000, /* Instrument doesn't give any user feedback */
+
+ inst2_has_leds = 0x00200000, /* Instrument has some user viewable indicator LEDs */
+ inst2_has_sensmode = 0x00400000, /* Instrument can report it's sensors mode */
+
+ inst2_has_battery = 0x00800000, /* Instrument is battery powered */
+
+ inst2_disptype = 0x01000000, /* Has a display type selector */
+ inst2_ccmx = 0x02000000, /* Colorimeter Correction Matrix capability */
+ inst2_ccss = 0x04000000, /* Colorimeter Cal. Spectral Set capability */
+
+ inst2_ambient_mono = 0x08000000, /* The ambient measurement is monochrome */
+
+ inst2_emis_refr_meas = 0x10000000, /* Has an emissive refresh rate measurement func. */
+
+} inst2_capability;
+
+/* Instrument capabilities 3 (room for expansion) */
+/* (Available capabilities may be mode dependent) */
+typedef enum {
+ inst3_none = 0x00000000, /* No capabilities */
+
+} inst3_capability;
+
+typedef enum {
+ inst_dtflags_none = 0x0000, /* no flags */
+ inst_dtflags_default = 0x0001, /* default display type */
+ inst_dtflags_ccss = 0x0002, /* ccss */
+ inst_dtflags_ccmx = 0x0004, /* ccmx */
+ inst_dtflags_end = 0x8000 /* end marker */
+
+} inst_dtflags;
+
+#define INST_DTYPE_SEL_LEN 10
+#define INST_DTYPE_DESC_LEN 100
+
+/* Structure used to return display type selection information */
+typedef struct _inst_disptypesel {
+
+ /* Public: */
+ inst_dtflags flags; /* Attribute flags */
+ int cbid; /* Calibration base ID. NZ if valid ccmx calibration base. */
+ /* Should remain constant between releases */
+ char sel[INST_DTYPE_SEL_LEN]; /* String of selector characters */
+ char desc[INST_DTYPE_DESC_LEN]; /* Textural description */
+ int refr; /* Refresh mode flag */
+
+ /* Private: */
+ int ix; /* Internal index, */
+
+ // Stuff for ccss & ccmx
+ char *path; /* Path to ccss or ccmx */
+ double mat[3][3]; /* ccmx matrix */
+ xspect *sets; /* ccss set of sample spectra */
+ int no_sets; /* ccs number of sets */
+
+} inst_disptypesel;
+
+/* Instrument options for get_set_opt() */
+typedef enum {
+ inst_opt_unknown = 0x0000, /* Option not specified */
+
+ inst_stat_saved_readings = 0x0001, /* Return status of saved reading values */
+ /* [1 argument type *inst_stat_savdrd] */
+ inst_stat_s_spot = 0x0002, /* Return number of saved spot readings */
+ /* [1 argument type *int] */
+ inst_stat_s_strip = 0x0003, /* Return saved strip details */
+ /* [args: int *no_patches, int *no_rows */
+ /* int *pat_per_row] */
+ inst_stat_s_xy = 0x0004, /* Return saved strip details */
+ /* [args: int *no_sheets, int *no_patches, */
+ /* int *no_rows, int *pat_per_row] */
+ inst_stat_s_chart = 0x0005, /* Return number saved chart details */
+ /* [args: int *no_patches, int *no_rows */
+ /* int *pat_per_row, int *chart_id, */
+ /* int *missing_row ] */
+
+ inst_stat_battery = 0x0006, /* Return charged status of battery */
+ /* [1 argument type *double : range 0.0 - 1.0 ] */
+
+ inst_stat_get_filter = 0x0007, /* Get a filter configuration */
+ /* [1 argument type *inst_opt_filter ] */
+
+ inst_opt_initcalib = 0x0008, /* Enable initial calibration (default) [No args] */
+ inst_opt_noinitcalib = 0x0009, /* Disable initial calibration if < losecs since last */ /* opened, or losecs == 0 [int losecs] */
+
+ inst_opt_set_ccss_obs = 0x000A, /* Set the observer used with ccss device types */
+ /* Only takes effect after inst_opt_set_disp_type */
+ /* or col_cal_spec_set() */
+ /* [args: icxObserverType obType,*/
+ /* xspect custObserver[3] */
+
+ inst_opt_get_dtinfo = 0x000C, /* Get current display type information */
+ /* [args: int *refrmode,*/
+ /* int *cbid] */
+
+ inst_opt_set_filter = 0x000D, /* Set a filter configuration */
+ /* [1 argument type inst_opt_filter] */
+
+ inst_opt_trig_prog = 0x000E, /* Trigger progromatically [No args] */
+ inst_opt_trig_user = 0x000F, /* Trigger from user via uicallback [No args] */
+ inst_opt_trig_switch = 0x0010, /* Trigger using instrument switch [No args] */
+ inst_opt_trig_user_switch = 0x0011, /* Trigger from user via uicallback or switch (def) [No args] */
+
+ inst_opt_highres = 0x0012, /* Enable high resolution spectral mode */
+ inst_opt_stdres = 0x0013, /* Revert to standard resolution spectral mode */
+
+ inst_opt_scan_toll = 0x0014, /* Modify the patch scan recognition tollnce [double] */
+
+ inst_opt_get_gen_ledmask = 0x0015, /* Get the bitmask for general indication LEDs [*int] */
+ /* (More specialized indicator masks go here) */
+ inst_opt_set_led_state = 0x0016, /* Set the current LED state. 0 = off, 1 == on [int] */
+ inst_opt_get_led_state = 0x0017, /* Get the current LED state. 0 = off, 1 == on [*int] */
+ inst_opt_get_pulse_ledmask = 0x0018, /* Get the bitmask for pulseable ind. LEDs [*int] */
+ inst_opt_set_led_pulse_state= 0x0019, /* Set the current LED state. [double period_in_secs, */
+ /* double on_time_prop, double trans_time_prop] */
+ inst_opt_get_led_pulse_state= 0x001A /* Get the current pulse LED state. [*double period, */
+
+} inst_opt_type;
+
+/* Optional filter fitted to instrument (for inst_opt_set_filter) */
+typedef enum {
+ inst_opt_filter_unknown = 0xffff, /* Unspecified filter */
+ inst_opt_filter_none = 0x0000, /* No filters fitted */
+ inst_opt_filter_pol = 0x0001, /* Polarising filter */
+ inst_opt_filter_D65 = 0x0002, /* D65 Illuminant filter */
+ inst_opt_filter_UVCut = 0x0004, /* U.V. Cut filter */
+ inst_opt_filter_Custom = 0x0008 /* Custom Filter */
+} inst_opt_filter;
+
+/* Off-line pending readings available (status) */
+typedef enum {
+ inst_stat_savdrd_none = 0x00, /* No saved readings */
+ inst_stat_savdrd_spot = 0x01, /* There are saved spot readings available */
+ inst_stat_savdrd_strip = 0x02, /* There are saved strip readings available */
+ inst_stat_savdrd_xy = 0x04, /* There are saved page readings available */
+ inst_stat_savdrd_chart = 0x08 /* There are saved chart readings available */
+} inst_stat_savdrd;
+
+/* Type of calibration needed/available/requested - corresponds to capabilities */
+/* [ inst_calt_trans_vwhite is "variable" white transmission calibration, needed */
+/* where transmission mode is being emulated. ] */
+typedef enum {
+ /* Response to needs_calibration() */
+ inst_calt_none = 0x00000000, /* No calibration or unknown */
+
+ /* Psudo-calibration types */
+ inst_calt_all = 0x00000001, /* Do required non-deferable cals for mode, but also */
+ /* do all possible calibrations for all other modes */
+ /* using the calibration conditions. This may be slow */
+ /* Hmm. We don't have an "calt_all_needed" - do all needed cals of all possible modes. */
+ /* This might be more useful than inst_calt_all ? */
+ inst_calt_needed = 0x00000002, /* Do all required non-deferable cals for c.m. */
+ inst_calt_available = 0x00000003, /* Do all available non-deferable cals for c.m. */
+
+ /* Specific type of calibration - corresponds to capabilities */
+ inst_calt_wavelength = 0x00000010, /* Wavelength calibration using refl. cal. surface */
+ inst_calt_ref_white = 0x00000020, /* Reflective white/emissive dark calibration */
+ inst_calt_ref_dark = 0x00000040, /* Reflective dark calibration (in dark) */
+ inst_calt_emis_offset = 0x00000080, /* Emissive offset/black calibration (dark surface) */
+ inst_calt_emis_ratio = 0x00000100, /* Emissive ratio calibration */
+ inst_calt_em_dark = 0x00000200, /* Emissive dark calibration (in dark) */
+ inst_calt_trans_white = 0x00000400, /* Transmissive white reference calibration */
+ inst_calt_trans_vwhite = 0x00000800, /* Transmissive variable white reference calibration */
+ inst_calt_trans_dark = 0x00001000, /* Transmissive dark reference calibration */
+
+ inst_calt_n_dfrble_mask = 0x0000fff0, /* Mask of non-deferrable calibrations */
+
+ /* Calibrations that might be deferred until measurement */
+ inst_calt_emis_int_time = 0x00100000, /* Emissive measurement range (integration time) */
+ inst_calt_ref_freq = 0x00200000, /* Display refresh frequency calibration */
+
+ inst_calt_dfrble_mask = 0x00f00000, /* Mask of deferrable calibrations */
+
+ inst_calt_all_mask = 0x00f0fff0, /* Mask of all specific calibrations */
+
+ inst_calt_ap_flag = 0x80000000 /* Implementation flag indicating do all possible */
+
+} inst_cal_type;
+
+/* Calibration conditions. */
+/* This is how the instrument communicates to the calling program */
+/* about how to facilitate a calibration, or what it's current measurement */
+/* configuration provides. */
+/* [There is no provission for explictly indicating calibrations that can be */
+/* performed automatically and transparently by the instrument - for instance */
+/* in the case of the spectroscan, since the required condition can be obtained */
+/* without the users interaction. ] */
+typedef enum {
+ inst_calc_none = 0x00000000, /* Not suitable for calibration */
+ inst_calc_unknown = 0xffffffff, /* Unknown calibration setup */
+
+ /* uop means that user has to trigger the within instrument */
+ /* calibration using its "front panel" or other direct keys */
+ inst_calc_uop_ref_white = 0x00000001, /* user operated reflective white calibration */
+ inst_calc_uop_trans_white = 0x00000002, /* user operated tranmissive white calibration */
+ inst_calc_uop_trans_dark = 0x00000003, /* user operated tranmissive dark calibration */
+ inst_calc_uop_mask = 0x0000000F, /* user operated calibration mask */
+
+ /* Man means that the user has to manualy configure the instrument */
+ /* to be on the correct reference for the software triggered cal. */
+ inst_calc_man_ref_white = 0x00000010, /* place instrument on reflective white reference */
+ inst_calc_man_ref_whitek = 0x00000020, /* click instrument on reflective white reference */
+ inst_calc_man_ref_dark = 0x00000030, /* place instrument in dark, not close to anything */
+ inst_calc_man_em_dark = 0x00000040, /* place cap on instrument, put on dark surface or white ref. */
+ inst_calc_man_am_dark = 0x00000050, /* Place cap over ambient sensor (wl calib capable) */
+ inst_calc_man_cal_smode = 0x00000060, /* Put instrument sensor in calibration position */
+
+ inst_calc_man_trans_white = 0x00000070, /* place instrument on transmissive white reference */
+ inst_calc_man_trans_dark = 0x00000080, /* place instrument on transmissive dark reference */
+ inst_calc_man_man_mask = 0x000000F0, /* user configured calibration mask */
+
+ inst_calc_emis_white = 0x00000100, /* Provide a white test patch */
+ inst_calc_emis_grey = 0x00000200, /* Provide a grey test patch */
+ inst_calc_emis_grey_darker = 0x00000300, /* Provide a darker grey test patch */
+ inst_calc_emis_grey_ligher = 0x00000400, /* Provide a darker grey test patch */
+ inst_calc_emis_mask = 0x00000F00, /* Emmissive/display provided reference patch */
+
+ inst_calc_change_filter = 0x00010000, /* Filter needs changing on device - see id[] */
+ inst_calc_message = 0x00020000 /* Issue a message. - see id[] */
+} inst_cal_cond;
+
+/* Clamping state */
+typedef enum {
+ instNoClamp = 0, /* Don't clamp XYZ/Lab to +ve */
+ instClamp = 1, /* Clamp XYZ/Lab to +ve */
+} instClamping;
+
+/* User interaction callback function purpose */
+typedef enum {
+ inst_negcoms, /* Negotiating communications */
+ inst_triggered, /* Measurement has been triggered by switch or user (not progromatic) */
+ inst_armed, /* Armed and waiting for a measurement trigger */
+ inst_measuring /* Busy measuring */
+} inst_ui_purp;
+
+/* Asynchronous event callback type */
+typedef enum {
+ inst_event_switch, /* Instrument measure/calibrate switch pressed */
+ inst_event_mconf /* Change in measurement configuration (ie. sensor position) */
+} inst_event_type;
+
+/* Instrument configuration/sensor position*/
+typedef enum {
+ inst_conf_unknown,
+ inst_conf_projector,
+ inst_conf_surface,
+ inst_conf_emission,
+ inst_conf_calibration,
+ inst_conf_ambient
+} inst_config;
+
+/* Off-line pending readings available (status) */
+#define CALIDLEN 200 /* Maxumum length of calibration tile ID string */
+
+/* Color instrument interface base object */
+/* Note that some methods work after creation, while many */
+/* will return an error if communications hasn't been established and */
+/* the instrument initialised. Some may change their response before and */
+/* after initialisation. */
+#define INST_OBJ_BASE \
+ \
+ a1log *log; /* Pointer to debug & error logging class */ \
+ instType itype; /* Instrument type determined by driver */ \
+ icoms *icom; /* Instrument coms object */ \
+ int gotcoms; /* Coms established flag */ \
+ int inited; /* Instrument open and initialized flag */ \
+ double cal_gy_level; /* Display calibration test window state */ \
+ int cal_gy_count; /* Display calibration test window state */ \
+ inst_code (*uicallback)(void *cntx, inst_ui_purp purp); \
+ void *uic_cntx; /* User interaction callback function */ \
+ void (*eventcallback)(void *cntx, inst_event_type event); \
+ void *event_cntx; /* Event callback function */ \
+ \
+ /* Establish communications at the indicated baud rate. */ \
+ /* (Serial parameters are ignored for USB instrument) */ \
+ /* Timout in to seconds, and return non-zero error code */ \
+ inst_code (*init_coms)( \
+ struct _inst *p, \
+ baud_rate br, /* Baud rate */ \
+ flow_control fc, /* Flow control */ \
+ double tout); /* Timeout */ \
+ \
+ /* Initialise or re-initialise the INST */ \
+ /* return non-zero on an error, with inst error code */ \
+ inst_code (*init_inst)( \
+ struct _inst *p); \
+ \
+ /* Return the instrument type */ \
+ /* (this could concievably change after init_inst()) */ \
+ /* Can be called before init */ \
+ instType (*get_itype)( \
+ struct _inst *p); \
+ \
+ /* Return the instrument serial number. */ \
+ /* (This will be an empty string if there is no serial no) */ \
+ char *(*get_serial_no)( \
+ struct _inst *p); \
+ \
+ /* Return the avilable instrument modes and capabilities. */ \
+ /* Can be called before init, but may be different to */ \
+ /* what's returned after initilisation. */ \
+ /* Note that these may change with the mode. */ \
+ /* Arguments may be NULL */ \
+ void (*capabilities)(struct _inst *p, \
+ inst_mode *cap1, \
+ inst2_capability *cap2, \
+ inst3_capability *cap3); \
+ \
+ /* Return current or given configuration available measurement modes. */ \
+ /* Most instruments have only one detectable configuration. */ \
+ /* If conf_ix == NULL or *conf_ix is an invalid configuration index, */ \
+ /* then the current configuration modes are returned. */ \
+ /* Otherwise the given configuration index is returned. */ \
+ /* The i1d3 has 2, the Munki has 4, one being calibration. */ \
+ /* *cconds is valid if *mmodes = inst_mode_calibration */ \
+ inst_code (*meas_config)(struct _inst *p, \
+ inst_mode *mmodes, /* Return all the valid measurement modes */ \
+ /* for the current configuration */ \
+ inst_cal_cond *cconds, /* Return the valid calibration conditions */ \
+ int *conf_ix); /* Request mode for given configuration, and */ \
+ /* return the index of the configuration returned */ \
+ \
+ /* Check that the particular device measurement mode is valid, */ \
+ /* since it's not possible to be 100% sure from capabilities */ \
+ inst_code (*check_mode)( \
+ struct _inst *p, \
+ inst_mode m); /* Requested mode */ \
+ \
+ /* Set the device measurement mode */ \
+ /* Note that this may change the capabilities. */ \
+ inst_code (*set_mode)( \
+ struct _inst *p, \
+ inst_mode m); /* Requested mode */ \
+ \
+ /* Return array of display type selectors */ \
+ inst_code (*get_disptypesel)( \
+ struct _inst *p, \
+ int *no_selectors, /* Return number of display types */ \
+ inst_disptypesel **sels,/* Return the array of display types */ \
+ int allconfig, /* nz to return list for all configs, not just current. */ \
+ int recreate); /* nz to re-check for new ccmx & ccss files */ \
+ \
+ /* Set the display type. index is into the inst_disptypesel[] returned */ \
+ /* returned by get_disptypesel(). clears col_cor_mat() */ \
+ inst_code (*set_disptype)( \
+ struct _inst *p, \
+ int index); \
+ \
+ /* Get a status or get or set an option */ \
+ /* option state. */ \
+ /* Some options can be set before init */ \
+ /* See inst_opt_type typedef for list of mode types */ \
+ inst_code (*get_set_opt)( \
+ struct _inst *p, \
+ inst_opt_type m, /* Requested option mode */ \
+ ...); /* Option parameters */ \
+ \
+ /* Read a full test chart composed of multiple sheets */ \
+ /* DOESN'T use the trigger mode */ \
+ /* Return the inst error code */ \
+ inst_code (*read_chart)( \
+ struct _inst *p, \
+ int npatch, /* Total patches/values in chart */ \
+ int pich, /* Passes (rows) in chart */ \
+ int sip, /* Steps in each pass (patches in each row) */ \
+ int *pis, /* Passes in each strip (rows in each sheet) */ \
+ int chid, /* Chart ID number */ \
+ ipatch *vals); /* Pointer to array of values */ \
+ \
+ \
+ /* For an xy instrument, release the paper */ \
+ /* (if cap has inst_xy_holdrel) */ \
+ /* Return the inst error code */ \
+ inst_code (*xy_sheet_release)( \
+ struct _inst *p); \
+ \
+ /* For an xy instrument, hold the paper */ \
+ /* (if cap has inst_xy_holdrel) */ \
+ /* Return the inst error code */ \
+ inst_code (*xy_sheet_hold)( \
+ struct _inst *p); \
+ \
+ /* For an xy instrument, allow the user to locate a point */ \
+ /* (if cap has inst_xy_locate) */ \
+ /* Return the inst error code */ \
+ inst_code (*xy_locate_start)( \
+ struct _inst *p); \
+ \
+ /* For an xy instrument, read back the location */ \
+ /* (if cap has inst_xy_locate) */ \
+ /* Return the inst error code */ \
+ inst_code (*xy_get_location)( \
+ struct _inst *p, \
+ double *x, double *y); \
+ \
+ /* For an xy instrument, end allowing the user to locate a point */ \
+ /* (if cap has inst_xy_locate) */ \
+ /* Return the inst error code */ \
+ inst_code (*xy_locate_end)( \
+ struct _inst *p); \
+ \
+ /* For an xy instrument, move the measurement point */ \
+ /* (if cap has inst_xy_position) */ \
+ /* Return the inst error code */ \
+ inst_code (*xy_position)( \
+ struct _inst *p, \
+ int measure, /* nz for measure point, z for locate point */ \
+ double x, double y); \
+ \
+ /* For an xy instrument, try and clear the table after an abort */ \
+ /* Return the inst error code */ \
+ inst_code (*xy_clear)( \
+ struct _inst *p); \
+ \
+ /* Read a sheet full of patches using xy mode */ \
+ /* DOESN'T use the trigger mode */ \
+ /* Return the inst error code */ \
+ inst_code (*read_xy)( \
+ struct _inst *p, \
+ int pis, /* Passes in strips (letters in sheet) */ \
+ int sip, /* Steps in pass (numbers in sheet) */ \
+ int npatch, /* Total patches in strip (skip in last pass) */ \
+ char *pname, /* Starting pass name (' A' to 'ZZ') */ \
+ char *sname, /* Starting step name (' 1' to '99') */ \
+ double ox, double oy, /* Origin of first patch */ \
+ double ax, double ay, /* pass increment */ \
+ double aax, double aay, /* pass offset for odd patches */ \
+ double px, double py, /* step/patch increment */ \
+ ipatch *vals); /* Pointer to array of values */ \
+ \
+ \
+ /* Read a set of strips (applicable to strip reader) */ \
+ /* Obeys the trigger mode set, and may return user trigger code */ \
+ /* (to hint that a user command may be available) */ \
+ /* Return the inst error code */ \
+ inst_code (*read_strip)( \
+ struct _inst *p, \
+ char *name, /* Strip name (up to 7 chars) */ \
+ int npatch, /* Number of patches in each pass */ \
+ char *pname, /* Pass name (3 chars) */ \
+ int sguide, /* Guide number (decrements by 5) */ \
+ double pwid, /* Patch width in mm (For DTP20/DTP41) */ \
+ double gwid, /* Gap width in mm (For DTP20/DTP41) */ \
+ double twid, /* Trailer width in mm (For DTP41T) */ \
+ ipatch *vals); /* Pointer to array of values */ \
+ \
+ \
+ /* Read a single sample (applicable to spot instruments) */ \
+ /* Obeys the trigger mode set, and may return user trigger code */ \
+ /* Values are in XYZ 0..100 for reflective transmissive, */ \
+ /* aXYZ in cd/m^2 for emissive, amd Lux/3.1415926 for ambient. */ \
+ /* Spectral will be analogous to the XYZ. */ \
+ /* By default values may be -ve due to noise (depending on instrument) */ \
+ /* Return the inst error code */ \
+ inst_code (*read_sample)( \
+ struct _inst *p, \
+ char *name, /* Patch identifier (up to 7 chars) */ \
+ ipatch *val, /* Pointer to value to be returned */ \
+ instClamping clamp); /* NZ to clamp XYZ to be +ve */ \
+ \
+ /* Measure the emissive refresh rate in Hz. */ \
+ /* (Available if cap2 & inst2_emis_refr_meas) */ \
+ /* Returns: */ \
+ /* inst_unsupported - if this instrument doesn't suport this measuremet */ \
+ /* or not in an emissive measurement mode */ \
+ /* inst_misread - if no refresh rate could be determined */ \
+ /* inst_ok - on returning a valid reading */ \
+ inst_code (*read_refrate)( \
+ struct _inst *p, \
+ double *ref_rate); /* Return the Hz */ \
+ \
+ /* Determine if a calibration is needed. Returns inst_calt_none if not */ \
+ /* or unknown, or a mask of the needed calibrations. */ \
+ /* This call checks if calibrations are invalid or have timed out. */ \
+ /* With the exception of instruments with automated calibration */ \
+ /* (ie. SpectroScan), an instrument will typically */ \
+ /* not check for calibration timout any other way. */ \
+ /* [What's returned is the same as get_n_a_cals() [ needed_calibrations.] */\
+ inst_cal_type (*needs_calibration)( \
+ struct _inst *p); \
+ \
+ /* Return combined mask of needed and available inst_cal_type's */ \
+ /* for the current mode. */ \
+ inst_code (*get_n_a_cals)( \
+ struct _inst *p, \
+ inst_cal_type *needed_calibrations, \
+ inst_cal_type *available_calibrations); \
+ \
+ /* Request an instrument calibration. */ \
+ /* This is use if the user decides they want to do a calibration */ \
+ /* in anticipation of a calibration (needs_calibration()) to avoid */ \
+ /* requiring one during measurement, or in response to measuring */ \
+ /* returning inst_needs_cal before retrying the measurement, */ \
+ /* or to do one or more re-calibrations. */ \
+ \
+ /* *calt should contain the mask of calibrations to be performed, */ \
+ /* with *calc set to the current calibration condition. */ \
+ /* Alternately, one of the psudo-calibration types inst_calt_all, */ \
+ /* inst_calt_needed or inst_calt_available can be used, */ \
+ /* and/or the *calc of inst_calc_none to get calibrate() */ \
+ /* to determine the required calibration types and conditions. */ \
+ /* (The corresponding calibration types will be used & returned. */ \
+ \
+ /* If no error is returned to the first call to calibrate() with */ \
+ /* then the instrument was capable of calibrating without user or */ \
+ /* application intervention. If on the other hand calibrate() returns */ \
+ /* inst_cal_setup, then the appropriate action indicated by the value */ \
+ /* returned in *calc should be taken by the user or application, */ \
+ /* before retrying calibration() with the current setup indicated */ \
+ /* by *calc. If more than one calibration type is requested, then */ \
+ /* several retries may be needed with different calibration conditions. */ \
+ /* Each call to calibrate() will update *calt to reflect the remaining */ \
+ /* calibration to be performed. calibrate() returns inst_ok when no */ \
+ /* more calibrations remain. */ \
+ \
+ /* DOESN'T use the trigger mode */ \
+ /* Return inst_unsupported if *calt is not appropriate, */ \
+ /* inst_cal_setup if *calc is not appropriate. */ \
+ inst_code (*calibrate)( \
+ struct _inst *p, \
+ inst_cal_type *calt, /* Calibration type to do/remaining */ \
+ inst_cal_cond *calc, /* Current condition/desired condition */ \
+ char id[CALIDLEN]); /* Condition identifier (ie. white */ \
+ /* reference ID, filter ID) */ \
+ \
+ /* Measure a display update delay. It is assumed that a */ \
+ /* White to black change has been made to the displayed color, */ \
+ /* and this will measure the time it took for the update to */ \
+ /* be noticed by the instrument, up to 1.0 seconds. */ \
+ /* inst_misread will be returned on failure to find a transition to black. */ \
+ inst_code (*meas_delay)( \
+ struct _inst *p, \
+ int *msecdelay); /* Return the number of msec */ \
+ \
+ /* Return the last calibrated refresh rate in Hz. Returns: */ \
+ /* inst_unsupported - if this instrument doesn't suport a refresh mode */ \
+ /* or is unable to retrieve the refresh rate */ \
+ /* inst_needs_cal - if the refresh rate value is not valid */ \
+ /* inst_misread - if no refresh rate could be determined */ \
+ /* inst_ok - on returning a valid reading */ \
+ inst_code (*get_refr_rate)( \
+ struct _inst *p, \
+ double *ref_rate); /* Return the Hz */ \
+ \
+ /* Set the calibrated refresh rate in Hz. */ \
+ /* Set refresh rate to 0.0 to mark it as invalid */ \
+ /* Rates outside the range 5.0 to 150.0 Hz will return an error */ \
+ /* Note that not all instruments that can return a refresh rate, */ \
+ /* will permit one to be set (ie., DTP92) */ \
+ inst_code (*set_refr_rate)( \
+ struct _inst *p, \
+ double ref_rate); /* Rate in Hz */ \
+ \
+ /* Insert a compensation filter in the instrument readings */ \
+ /* This is typically needed if an adapter is being used, that alters */ \
+ /* the spectrum of the light reaching the instrument */ \
+ /* To remove the filter, pass NULL for the filter filename */ \
+ inst_code (*comp_filter)( \
+ struct _inst *p, \
+ char *filtername); /* File containing compensating filter */ \
+ \
+ /* Insert a colorimetric correction matrix in the instrument XYZ readings */ \
+ /* This is only valid for colorimetric instruments, and can only be */ \
+ /* applied over a base calibration display type. Setting a display */ \
+ /* type will clear the matrix. */ \
+ /* To clear the matrix, pass NULL for the matrix */ \
+ inst_code (*col_cor_mat)( \
+ struct _inst *p, \
+ double mtx[3][3]); /* XYZ matrix */ \
+ \
+ /* Use a Colorimeter Calibration Spectral Set (ccss) to set the */ \
+ /* instrumen calibration. This will affect emissive readings. */ \
+ /* An alternate observer may also be set, and this will affect both */ \
+ /* emissive and ambient readings. */ \
+ /* This is only valid for colorimetric instruments. */ \
+ /* To set calibration back to default, pass NULL for sets, and */ \
+ /* icxOT_default for the observer. */ \
+ inst_code (*col_cal_spec_set)( \
+ struct _inst *p, \
+ xspect *sets, /* Set of sample spectra */ \
+ int no_sets); /* Number on set */ \
+ \
+ /* Supply a user interaction callback function. \
+ * This is called for one of three different purposes: \
+ * To signal that the instrument measurement has been triggered. \
+ * To poll for a abort while waiting to trigger. \
+ * To poll for a user abort during measurement. \
+ * \
+ * The callback function will have the purpose paramater appropriately. \
+ * \
+ * For inst_negcoms, the return value of inst_user_abort \
+ * will abort the communication negotiation \
+ * \
+ * For inst_triggered, the return value of the callback is ignored. \
+ * \
+ * For inst_armed return value should be one of: \
+ * inst_ok to do nothing, inst_user_abort to abort the measurement, \
+ * or inst_user_trig to trigger the measurement. \
+ * \
+ * For inst_measuring the return value should be one of: \
+ * inst_ok to do nothing, inst_user_abort to abort the measurement. \
+ * \
+ * NULL can be set to disable the callback. \
+ */ \
+ void (*set_uicallback)(struct _inst *p, \
+ inst_code (*uicallback)(void *cntx, inst_ui_purp purp), \
+ void *cntx); \
+ \
+ /* Supply an aynchronous event callback function. \
+ * This is called from a thread with the following possible events: \
+ * \
+ * inst_event_switch: Instrument measure/calibrate switch pressed \
+ * inst_event_mconf: The measurement configuration has changed (ie. sensor position) \
+ * \
+ * NULL can be set to disable the callback. \
+ */ \
+ void (*set_event_callback)(struct _inst *p, \
+ void (*eventcallback)(void *cntx, inst_event_type event), \
+ void *cntx); \
+ \
+ /* Generic inst error codes interpretation */ \
+ char * (*inst_interp_error)(struct _inst *p, inst_code ec); \
+ \
+ /* Instrument specific error codes interpretation */ \
+ char * (*interp_error)(struct _inst *p, int ec); \
+ \
+ /* Convert instrument specific inst_wrong_config error to inst_config enum */ \
+ inst_config (*config_enum)(struct _inst *p, int ec); \
+ \
+ /* Return the last serial communication error code */ \
+ /* (This is used for deciding fallback/retry strategies) */ \
+ int (*last_scomerr)(struct _inst *p); \
+ \
+ /* Destroy ourselves */ \
+ void (*del)(struct _inst *p); \
+
+/* The base object type */
+struct _inst {
+ INST_OBJ_BASE
+ }; typedef struct _inst inst;
+
+/* Virtual constructor. */
+/* Return NULL for unknown instrument, */
+/* or serial instrument if nocoms == 0. */
+/* (Doesn't copy icompaths log!) */
+/* If uicallback is provided, it will be set in the resulting inst */
+extern inst *new_inst(
+ icompath *path, /* Device path this instrument */
+ int nocoms, /* Don't open if communications are needed to establish inst type */
+ a1log *log, /* Log to use */
+ inst_code (*uicallback)(void *cntx, inst_ui_purp purp), /* optional uicallback */
+ void *cntx /* Context for callback */
+);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Implementation functions used by drivers */
+
+/* Get a status or set or get an option (default implementation) */
+inst_code inst_get_set_opt_def(
+inst *p,
+inst_opt_type m, /* Option type */
+va_list args); /* Option parameters */
+
+/* - - - - - - - - - - - - - - - - - - -- */
+
+/* Create the display type list */
+inst_code inst_creat_disptype_list(inst *p,
+int *pndtlist, /* Number in returned list */
+inst_disptypesel **pdtlist, /* Returned list */
+inst_disptypesel *sdtlist, /* Static list */
+int doccss, /* Add installed ccss files */
+int doccmx /* Add matching installed ccmx files */
+);
+
+/* Free a display type list */
+void inst_del_disptype_list(inst_disptypesel *list, int no);
+
+
+/* - - - - - - - - - - - - - - - - - - -- */
+/* CCMX support */
+
+typedef struct {
+ char *path; /* Path to the file */
+ char *desc; /* Technology + display description */
+ int cbid; /* Calibration display type base ID */
+ int refr; /* Refresh mode flag */
+ char *sel; /* UI selector characters (may be NULL) */
+ double mat[3][3]; /* The matrix values */
+} iccmx;
+
+/* return a list of installed ccmx files. */
+/* if inst != NULL, return those that match the given instrument. */
+/* The list is sorted by description and terminated by a NULL entry. */
+/* If no is != NULL, return the number in the list */
+/* Return NULL and -1 if there is a malloc error */
+iccmx *list_iccmx(char *inst, int *no);
+
+/* Free up a iccmx list */
+void free_iccmx(iccmx *list);
+
+/* - - - - - - - - - - - - - - - - - - -- */
+/* CCSS support */
+
+typedef struct {
+ char *path; /* Path to the file */
+ char *desc; /* Technology + display description */
+ int refr; /* Refresh mode flag */
+ char *sel; /* UI selector characters (may be NULL) */
+ xspect *sets; /* Set of sample spectra */
+ int no_sets; /* Number on set */
+} iccss;
+
+/* return a list of installed ccss files. */
+/* The list is sorted by description and terminated by a NULL entry. */
+/* If no is != NULL, return the number in the list */
+/* Return NULL and -1 if there is a malloc error */
+iccss *list_iccss(int *no);
+
+/* Free up a iccss list */
+void free_iccss(iccss *list);
+
+/* - - - - - - - - - - - - - - - - - - -- */
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define INST_H
+#endif /* INST_H */
diff --git a/spectro/instappsup.c b/spectro/instappsup.c
new file mode 100644
index 0000000..67849c7
--- /dev/null
+++ b/spectro/instappsup.c
@@ -0,0 +1,556 @@
+
+ /* Instrument command line application support functions */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 10/3/2001
+ *
+ * Copyright 2001 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#else
+#include "sa_config.h"
+#endif /* !SALONEINSTLIB */
+#include "numsup.h"
+#include "xspect.h"
+#include "conv.h"
+#include "insttypes.h"
+
+#include "icoms.h"
+#include "inst.h"
+#include "insttypeinst.h"
+#include "instappsup.h"
+
+/* ================================================================= */
+/* a default user interaction handler */
+
+typedef struct _uicontext {
+ int emit_ret; /* Emit \n on inst_triggered */
+ int cut; /* The character that caused the termination */
+ int uih[256]; /* User interrupt handling key table. Value can be: */
+ /* DUIH_OK, DUIH_ABORT, DUIH_TERM, DUIH_TRIG, DUIH_CMND */
+} uicontext;
+
+static uicontext def_uicntx = { 1, 0, { 0 } };
+
+static inst_code def_uicallback(void *cntx, inst_ui_purp purp) {
+ uicontext *p = (uicontext *)cntx;
+
+ if (purp == inst_triggered) {
+ if (p->emit_ret)
+ printf("\n");
+ return inst_ok;
+
+ } else if (purp == inst_negcoms
+ || purp == inst_armed
+ || purp == inst_measuring) {
+ int c;
+
+ c = poll_con_char();
+ if (c != 0) {
+ p->cut = c;
+ c = p->uih[c];
+ if (c & (DUIH_ABORT | DUIH_TERM | DUIH_CMND))
+ return inst_user_abort;
+ if (c & DUIH_TRIG)
+ return inst_user_trig;
+ }
+
+ /* Change in measurement configuration */
+ } else if (purp == inst_measuring) {
+ return inst_ok;
+ }
+ return inst_ok;
+}
+
+/* Return the default uicallback function */
+inst_code (*inst_get_uicallback())(void *, inst_ui_purp) {
+ return &def_uicallback;
+}
+
+/* Return the default uicallback context */
+void *inst_get_uicontext() {
+ return (void *)&def_uicntx;
+}
+
+/* Install the default uicallback function in the given inst */
+void inst_set_uicallback(inst *p) {
+ p->set_uicallback(p, def_uicallback, (void *)&def_uicntx);
+}
+
+/* Set the return on trigger to true or false */
+void inst_set_uicb_trigret(int set) {
+ uicontext *p = &def_uicntx;
+ p->emit_ret = set;
+}
+
+/* Reset user interaction handling to default (Esc, ^C, q or 'Q' = Abort) */
+void inst_reset_uih() {
+ uicontext *p = &def_uicntx;
+ int i;
+
+ for (i = 0; i < 255; i++)
+ p->uih[i] = DUIH_NONE;
+
+ p->uih[0x1b] = DUIH_ABORT; /* Escape */
+ p->uih['q'] = DUIH_ABORT; /* q */
+ p->uih['Q'] = DUIH_ABORT; /* Q */
+ p->uih[0x03] = DUIH_ABORT; /* ^C */
+}
+
+/* Set a key range to the given handling type */
+/* min & max are between 0 and 255, status is one of */
+/* DUIH_OK, DUIH_USER, DUIH_TERM, DUIH_TRIG, DUIH_CMND */
+void inst_set_uih(
+int min, /* Start key code */
+int max, /* End key code (inclusive) */
+int status /* ICOM_OK, ICOM_USER, ICOM_TERM, ICOM_TRIG, ICOM_CMND */
+) {
+ uicontext *p = &def_uicntx;
+ int i;
+
+ if (min < 0)
+ min = 0;
+ else if (min > 255)
+ min = 255;
+ if (max < 0)
+ max = 0;
+ else if (max > 255)
+ max = 255;
+
+ if (status != DUIH_NONE
+ && status != DUIH_ABORT
+ && status != DUIH_TERM
+ && status != DUIH_CMND
+ && status != DUIH_TRIG)
+ status = DUIH_NONE;
+
+ for (i = min; i <= max; i++) {
+ p->uih[i] = status;
+ }
+}
+
+/* Get the character that caused the user interrupt */
+/* + its key type in the upper 8 bits. */
+/* Clear it to 0x00 after reading it. */
+int inst_get_uih_char() {
+ uicontext *p = &def_uicntx;
+ int c = p->cut;
+ c |= p->uih[c];
+ p->cut = 0;
+ return c;
+}
+
+/* ================================================================= */
+
+/* A default calibration user interaction handler using the console. */
+/* This handles both normal and display based calibration interaction */
+/* with the instrument, if a disp_setup function and pointer to disp_win_info */
+/* is provided. */
+inst_code inst_handle_calibrate(
+ inst *p,
+ inst_cal_type calt, /* Calibration type to do */
+ inst_cal_cond calc, /* Current current condition */
+ inst_code (*disp_setup) (inst *p,inst_cal_cond calc, disp_win_info *dwi),
+ /* Callback for handling a display calibration - May be NULL */
+ disp_win_info *dwi /* Information to be able to open a display test patch - May be NULL */
+) {
+ inst_code rv = inst_ok, ev;
+ int usermes = 0; /* User was given a message */
+ char id[200]; /* Condition identifier */
+ int ch;
+
+ a1logd(p->log,1,"inst_handle_calibrate called\n");
+
+ /* Untill we're done with the calibration */
+ for (;;) {
+
+ a1logd(p->log,1,"About to call calibrate at top of loop\n");
+ ev = p->calibrate(p, &calt, &calc, id);
+ a1logd(p->log,1,"Calibrate returned calt 0x%x, calc 0x%x, ev 0x%x\n",calt,calc,ev);
+
+ /* We're done */
+ if ((ev & inst_mask) == inst_ok) {
+ if (calc == inst_calc_message)
+ printf("%s\n",id);
+ if (usermes)
+ printf("Calibration complete\n");
+ fflush(stdout);
+ a1logd(p->log,1,"inst_handle_calibrate done 0x%x\n",ev);
+ return ev;
+ }
+
+ /* User aborted */
+ if ((ev & inst_mask) == inst_user_abort) {
+ a1logd(p->log,1,"inst_handle_calibrate user aborted 0x%x\n",ev);
+ return ev;
+ }
+
+ /* Retry on an error */
+ if ((ev & inst_mask) != inst_cal_setup) {
+ if ((ev & inst_mask) == inst_unsupported) {
+ a1logd(p->log,1,"inst_handle_calibrate err 0x%x, calibration type 0x%x not supported\n",ev, calt);
+ return inst_unsupported;
+ }
+
+ printf("Calibration failed with '%s' (%s)\n",
+ p->inst_interp_error(p, ev), p->interp_error(p, ev));
+ printf("Hit any key to retry, or Esc or Q to abort:\n");
+
+ empty_con_chars();
+ ch = next_con_char();
+ printf("\n");
+ if (ch == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ a1logd(p->log,1,"inst_handle_calibrate user aborted 0x%x\n",inst_user_abort);
+ fflush(stdout);
+ return inst_user_abort;
+ }
+
+ /* Get user to do/setup calibration */
+ } else {
+
+ switch (calc) {
+ case inst_calc_uop_ref_white:
+ printf("Do a reflective white calibration,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_uop_trans_white:
+ printf("Do a transmissive white calibration,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_uop_trans_dark:
+ printf("Do a transmissive dark calibration,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_man_ref_white:
+ printf("Place the instrument on its reflective white reference %s,\n",id);
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_man_ref_whitek:
+ printf("Click the instrument on its reflective white reference %s,\n",id);
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_man_ref_dark:
+ printf("Place the instrument in the dark, not in contact with any surface,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_man_em_dark:
+ printf("Place cap on the instrument, or place on a dark surface,\n");
+ printf("or place on the white calibration reference,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_man_am_dark:
+ printf("Place ambient adapter and cap on the instrument,\n");
+ printf("or place on the white calibration reference,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_man_cal_smode:
+ printf("Set instrument sensor to calibration position,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_man_trans_white:
+ printf("Place the instrument on its transmissive white source,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_man_trans_dark:
+ printf("Use the appropriate tramissive blocking to block the transmission path,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_change_filter:
+ printf("Change filter on instrument to %s,\n",id);
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_message:
+ printf("%s\n",id);
+ printf(" Hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ break;
+
+ case inst_calc_emis_white:
+ if (disp_setup == NULL || dwi == NULL) { /* No way of creating a test window */
+ printf("Place the instrument on a 100%% white test patch,\n");
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ } else {
+ /* We need to display a 100% white patch to proceed with this */
+ /* type of calibration */
+ if ((rv = disp_setup(p, calc, dwi)) != inst_ok)
+ return rv;
+ }
+ break;
+
+ case inst_calc_emis_grey:
+ case inst_calc_emis_grey_darker:
+ case inst_calc_emis_grey_ligher:
+ if (dwi == NULL) { /* No way of creating a test window */
+ if (calc == inst_calc_emis_grey) {
+ p->cal_gy_level = 0.6;
+ p->cal_gy_count = 0;
+ } else if (calc == inst_calc_emis_grey_darker) {
+ p->cal_gy_level *= 0.7;
+ p->cal_gy_count++;
+ } else if (calc == inst_calc_emis_grey_ligher) {
+ p->cal_gy_level *= 1.4;
+ if (p->cal_gy_level > 1.0)
+ p->cal_gy_level = 1.0;
+ p->cal_gy_count++;
+ }
+ if (p->cal_gy_count > 4) {
+ printf("Cell ratio calibration failed - too many tries at setting grey level.\n");
+ a1logd(p->log,1,"inst_handle_calibrate too many tries at setting grey level 0x%x\n",inst_internal_error);
+ return inst_internal_error;
+ } else {
+ printf("Place the instrument on a %d%% white test patch,\n", (int)(p->cal_gy_level * 100.0 + 0.5));
+ printf(" and then hit any key to continue,\n");
+ printf(" or hit Esc or Q to abort: ");
+ }
+ } else {
+
+ /* We need to display a test patch to proceed with this
+ * type of calibration. Typically this will be:
+ *
+ * inst_calc_xxxx_grey:
+ * set p->cal_gy_level = 0.6
+ * set p->cal_gy_count = 0;
+ *
+ * inst_calc_xxxx_grey_darker:
+ * set p->cal_gy_level *= 0.7
+ * set p->cal_gy_count++
+ *
+ * inst_calc_xxxx_grey_ligher:
+ * set p->cal_gy_level *= 1.4
+ * set p->cal_gy_count++
+ *
+ * and return failure if p->cal_gy_count > 4
+ */
+
+ if ((rv = disp_setup(p, calc, dwi)) != inst_ok)
+ return rv;
+ }
+ break;
+
+ default:
+ /* Something isn't being handled */
+ a1logd(p->log,1,"inst_handle_calibrate unhandled calc case 0x%x, err 0x%x\n",calc,inst_internal_error);
+ return inst_internal_error;
+ }
+ fflush(stdout);
+
+ usermes = 1;
+
+ if (calc != inst_calc_man_ref_whitek) {
+ empty_con_chars();
+ ch = next_con_char();
+ printf("\n");
+ if (ch == 0x1b || ch == 0x3 || ch == 'q' || ch == 'Q') {
+ a1logd(p->log,1,"inst_handle_calibrate user aborted 0x%x\n",inst_user_abort);
+ return inst_user_abort;
+ }
+ }
+ }
+ }
+}
+
+/* ============================================================================= */
+
+/* A helper function to display -y flag usage for each instrument type available */
+/* 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) {
+ int i, j;
+ char buf[200], *bp;
+ char extra[40];
+ int olen, pstart;
+ int notall = 0; /* Not all instruments are USB */
+ int gotone = 0; /* Found at least one USB instrument */
+ inst2_capability acap = 0; /* Accumulate capabilities */
+
+ if (icmps == NULL)
+ return 0;
+
+ /* Locate the end of the option */
+ for (bp = oline; *bp != '\000' && *bp == ' '; bp++)
+ ;
+ for (; *bp != '\000' && *bp != ' '; bp++)
+ ;
+ pstart = bp - oline;
+ if (pstart > 10)
+ pstart = 10;
+ strncpy(buf, oline, pstart);
+ buf[pstart++] = ' ';
+
+ olen = strlen(oline); /* lenth of option part of line */
+
+ for (i = 0; icmps != NULL && i < icmps->npaths; i++) {
+ inst *it;
+ inst2_capability cap;
+ int k;
+
+ if ((it = new_inst(icmps->paths[i], 1, g_log, NULL, NULL)) == NULL) {
+ notall = 1;
+ continue;
+ }
+ gotone = 1;
+
+ it->capabilities(it, NULL, &cap, NULL);
+ acap |= cap;
+
+ if (cap & inst2_disptype) {
+ int nsel;
+ inst_disptypesel *sels;
+
+ if (it->get_disptypesel(it, &nsel, &sels, 1, 0) != inst_ok) {
+ it->del(it);
+ continue;
+ }
+ for (j = 0; j < nsel; j++) {
+ int m;
+
+ if (docbib && sels[j].cbid == 0)
+ continue; /* Skip non cbid type */
+
+ m = pstart;
+ for (k = 0; k < (INST_DTYPE_SEL_LEN-1); k++) {
+ if (sels[j].sel[k] == '\000')
+ break;
+ if (m > pstart)
+ buf[m++] = '|';
+ buf[m++] = sels[j].sel[k];
+ }
+ while (m < (olen+1)) /* Indent it by 1 */
+ buf[m++] = ' ';
+ buf[m++] = '\000';
+
+ extra[0] = '\000';
+ if ((sels[j].flags & inst_dtflags_default) || sels[j].cbid != 0) {
+ strcat(extra, " [");
+ if (sels[j].flags & inst_dtflags_default) {
+ strcat(extra, "Default");
+ if (sels[j].cbid != 0)
+ strcat(extra, ",");
+ }
+ if (sels[j].cbid != 0) {
+ sprintf(extra + strlen(extra), "CB%d",sels[j].cbid);
+ }
+ strcat(extra, "]");
+ }
+
+ fprintf(fp, "%s%s: %s%s\n",buf, inst_sname(it->itype), sels[j].desc, extra);
+
+ if (j == 0) {
+ for (m = 0; m < pstart; m++)
+ buf[m] = ' ';
+ }
+ }
+ }
+ it->del(it);
+ }
+ /* Output a default desciption if not all instruments are USB */
+ if (notall) {
+ int m = pstart;
+ buf[m++] = 'l';
+ buf[m++] = '|';
+ buf[m++] = 'c';
+ while (m < olen)
+ buf[m++] = ' ';
+ buf[m++] = '\000';
+ fprintf(fp, "%s%s\n",buf, " Other: l = LCD, c = CRT");
+ }
+ if (!gotone)
+ acap = ~0;
+
+ return acap;
+}
+
+/* A helper function to turn a -y flag into a selection index */
+/* If docbib is nz, then only allow base calibration display types */
+/* Return -1 on error */
+int inst_get_disptype_index(inst *it, int c, int docbib) {
+ inst2_capability cap;
+ int j, k;
+
+ it->capabilities(it, NULL, &cap, NULL);
+
+ if (cap & inst2_disptype) {
+ int nsel;
+ inst_disptypesel *sels;
+
+ if (it->get_disptypesel(it, &nsel, &sels, 1, 0) != inst_ok) {
+ return -1;
+ }
+ for (j = 0; j < nsel; j++) {
+ if (docbib && sels[j].cbid == 0)
+ continue; /* Skip non cbid type */
+
+ for (k = 0; k < (INST_DTYPE_SEL_LEN-1); k++) {
+ if (sels[j].sel[k] == '\000')
+ break;
+ if (sels[j].sel[k] == c) {
+ return j;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+/* ================================================================= */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spectro/instappsup.h b/spectro/instappsup.h
new file mode 100644
index 0000000..24da6db
--- /dev/null
+++ b/spectro/instappsup.h
@@ -0,0 +1,100 @@
+
+#ifndef INSTAPPSUP_H
+
+/* Instrument command line application support functions */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 15/3/2001
+ *
+ * Copyright 2001 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ */
+
+//#include "insttypes.h" /* libinst Includes this functionality */
+//#include "icoms.h"
+//#include "conv.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* ============================================================================= */
+/* a default user interaction callback handler */
+
+/* User key types */
+#define DUIH_NONE 0x0000 /* No meaning */
+#define DUIH_ABORT 0x0100 /* User abort operation */
+#define DUIH_TERM 0x0200 /* User terminated operation */
+#define DUIH_CMND 0x0400 /* User command */
+#define DUIH_TRIG 0x0800 /* User trigger */
+
+/* The default uicallback function and context. resets uih too. */
+#define DUIH_FUNC_AND_CONTEXT (inst_reset_uih(), inst_get_uicallback()), inst_get_uicontext()
+
+/* Return the default uicallback function */
+inst_code (*inst_get_uicallback())(void *, inst_ui_purp);
+
+/* Return the default uicallback context */
+void *inst_get_uicontext();
+
+/* Install the default uicallback function in the given inst */
+void inst_set_uicallback(inst *p);
+
+/* Reset user interaction handling to default (Esc, ^C, q or 'Q' = Abort) */
+void inst_reset_uih();
+
+/* Set a key range to the given handling type */
+/* min & max are between 0 and 255, status is one of */
+/* DUIH_OK, DUIH_USER, DUIH_TERM, DUIH_TRIG, DUIH_CMND */
+void inst_set_uih(int min, int max, int status);
+
+/* Get the character that caused the user trigger or abort */
+/* + its key type in the upper 8 bits. */
+/* Clear it to 0x00 after reading it. */
+int inst_get_uih_char();
+
+/* ============================================================================= */
+
+#ifndef DISPSUP_H
+/* Opaque type as far as inst.h is concerned. */
+typedef struct _disp_win_info disp_win_info;
+#endif
+
+/* A default calibration user interaction handler using the console. */
+/* This handles both normal and display based calibration interaction */
+/* with the instrument, if a disp_setup function and pointer to disp_win_info */
+/* is provided. */
+inst_code inst_handle_calibrate(
+ inst *p,
+ inst_cal_type calt, /* Calibration type to do */
+ inst_cal_cond calc, /* Current calibration condition */
+ inst_code (*disp_setup) (inst *p, inst_cal_cond calc, disp_win_info *dwi),
+ /* Callback for handling a display calibration - May be NULL */
+ disp_win_info *dwi /* Information to be able to open a display test patch - May be NULL */
+);
+
+/* ============================================================================= */
+
+/* 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);
+
+/* A helper function to turn a -y flag into a list index */
+/* If docbib is nz, then only allow base calibration display types */
+/* Return 0 on error */
+int inst_get_disptype_index(inst *it, int c, int docbib);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define INSTAPPSUP_H
+#endif /* INSTAPPSUP_H */
diff --git a/spectro/instlib.ksh b/spectro/instlib.ksh
new file mode 100644
index 0000000..88fcba5
--- /dev/null
+++ b/spectro/instlib.ksh
@@ -0,0 +1,191 @@
+#!/bin/sh
+
+# Package up the source and other files for the standalone GPLv2 Instrument library.
+
+# Copyright 2007 - 2013 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.
+
+echo "Making standalone GPLv2 instrument archive instlib.zip "
+
+H_FILES="
+ ../h/sort.h
+ "
+
+NUMLIB_FILES="
+ ../numlib/numsup.h
+ ../numlib/numsup.c
+ "
+
+CGATS_FILES="
+ ../cgats/pars.h
+ ../cgats/pars.c
+ ../cgats/parsstd.c
+ ../cgats/cgats.h
+ ../cgats/cgats.c
+ ../cgats/cgatsstd.c
+ "
+
+XICC_FILES="
+ ../xicc/xspect.h
+ ../xicc/xspect.c
+ ../xicc/ccss.h
+ ../xicc/ccss.c
+ ../xicc/ccmx.h
+ ../xicc/ccmx.c
+ "
+
+RSPL_FILES="
+ ../rspl/rspl1.h
+ ../rspl/rspl1.c
+ "
+
+SPECTRO_FILES="
+ License2.txt
+ Makefile.OSX
+ Makefile.UNIX
+ Makefile.WNT
+ pollem.h
+ pollem.c
+ conv.h
+ conv.c
+ aglob.c
+ aglob.h
+ hidio.h
+ hidio.c
+ icoms.h
+ inst.h
+ inst.c
+ insttypes.c
+ insttypes.h
+ insttypeinst.h
+ instappsup.c
+ instappsup.h
+ dtp20.c
+ dtp20.h
+ dtp22.c
+ dtp22.h
+ dtp41.c
+ dtp41.h
+ dtp51.c
+ dtp51.h
+ dtp92.c
+ dtp92.h
+ ss.h
+ ss.c
+ ss_imp.h
+ ss_imp.c
+ i1disp.c
+ i1disp.h
+ i1d3.h
+ i1d3.c
+ i1pro.h
+ i1pro.c
+ i1pro_imp.h
+ i1pro_imp.c
+ munki.h
+ munki.c
+ munki_imp.h
+ munki_imp.c
+ hcfr.c
+ hcfr.h
+ huey.c
+ huey.h
+ colorhug.c
+ colorhug.h
+ spyd2.c
+ spyd2.h
+ spyd2setup.h
+ spyd2PLD.h
+ oemarch.c
+ oemarch.h
+ oeminst.c
+ vinflate.c
+ inflate.c
+ LzmaDec.c
+ LzmaDec.h
+ LzmaTypes.h
+ icoms.c
+ icoms_nt.c
+ icoms_ux.c
+ iusb.h
+ usbio.h
+ usbio.c
+ usbio_lusb.c
+ usbio_nt.c
+ usbio_ox.c
+ usbio_lx.c
+ xdg_bds.c
+ xdg_bds.h
+ spotread.c
+ "
+
+FILES=" $H_FILES $CGATS_FILES $NUMLIB_FILES $RSPL_FILES $XICC_FILES $SPECTRO_FILES "
+
+rm -f instlib.zip
+rm -rf _zipdir
+rm -f _ziplist
+mkdir _zipdir
+mkdir _zipdir/instlib
+
+
+# Archive the Argyll files needed
+for j in $FILES
+do
+ if [ ! -e ${j} ] ; then
+ echo "!!!!!!!!!!!!!!!!!!!!!!!!!!! Can't find file ${j} !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+ NOTFOUND="$NOTFOUND ${tt}"
+ else
+ cp ${j} _zipdir/instlib/${j##*/}
+ echo instlib/${j##*/} >> _ziplist
+ fi
+done
+
+# Plus renamed files
+cp IntsLib_Readme.txt _zipdir/instlib/Readme.txt
+echo instlib/Readme.txt >> _ziplist
+cp Makefile.SA _zipdir/instlib/Makefile
+echo instlib/Makefile >> _ziplist
+cp ../h/aconfig.h _zipdir/instlib/sa_config.h
+echo instlib/sa_config.h >> _ziplist
+
+# Create usb archive
+
+for j in `cat ../usb/afiles | grep -E -v 'afiles|binfiles.msw|binfiles.osx|binfiles.lx|Jamfile|ArgyllCMS.inf.t|ArgyllCMS.inf.d'`
+do
+ echo "File ${j}"
+
+ # Create any needed temporary directories
+
+ tt=usb/${j}
+ path=${tt%/*} # extract path without filename
+
+ echo "path ${path}"
+
+ if [ ! -e _zipdir/instlib/${path} ] ; then # if not been created
+ echo "Creating directory _zipdir/instlib/${path}"
+ mkdir -p _zipdir/instlib/${path}
+ fi
+
+ tt=../${tt}
+
+ if [ ! -e ${tt} ] ; then
+ echo "!!!!!!!!!!!!!!!!!!!!!!!!!!! Can't find file ${tt} !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+ NOTFOUND="$NOTFOUND ${tt}"
+ else
+ cp ${tt} _zipdir/instlib/usb/${j}
+ echo instlib/usb/${j} >> _ziplist
+ fi
+done
+
+cd _zipdir
+zip -9 -m ../instlib.zip `cat ../_ziplist`
+cd ..
+rm -rf _zipdir
+rm -f _ziplist
+
+if [ "X$NOTFOUND" != "X" ] ; then
+ echo "!!!!!! Didn't find $NOTFOUND !!!!!!"
+fi
+
+echo "Created instlib.zip"
diff --git a/spectro/instlib.txt b/spectro/instlib.txt
new file mode 100644
index 0000000..661584d
--- /dev/null
+++ b/spectro/instlib.txt
@@ -0,0 +1,11 @@
+
+To create a standalone instrument library, you need a subset of
+files from this directory and other selected files from Argyll.
+
+If you are on MSWin you need to build argyll first using Jam.
+
+You can run the instlib.ksh script which will copy the necessary
+files into the file instlib.zip.
+
+This can be extracted, the Makefile modified to suite the system,
+and then built. (See the Readme.txt within instlib.zip file)
diff --git a/spectro/insttypeinst.h b/spectro/insttypeinst.h
new file mode 100644
index 0000000..c61a5c4
--- /dev/null
+++ b/spectro/insttypeinst.h
@@ -0,0 +1,25 @@
+
+/* Add instrument instance headers here */
+
+/*
+ * Copyright 2001 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include "dtp20.h"
+#include "dtp22.h"
+#include "dtp41.h"
+#include "dtp51.h"
+#include "dtp92.h"
+#include "ss.h"
+#include "i1disp.h"
+#include "i1d3.h"
+#include "i1pro.h"
+#include "munki.h"
+#include "hcfr.h"
+#include "spyd2.h"
+#include "huey.h"
+#include "colorhug.h"
diff --git a/spectro/insttypes.c b/spectro/insttypes.c
new file mode 100644
index 0000000..e0863d0
--- /dev/null
+++ b/spectro/insttypes.c
@@ -0,0 +1,384 @@
+
+ /* Instrument supported types utilities */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 10/3/2001
+ *
+ * Copyright 2001 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#else
+#include "sa_config.h"
+#endif /* !SALONEINSTLIB */
+#include "numsup.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+
+/* NOTE NOTE NOTE: */
+/* Need to add a new instrument to new_inst() in */
+/* inst.c as well !!! */
+
+/* Utility functions */
+
+/* Return the short instrument identification name (static string) */
+char *inst_sname(instType itype) {
+ switch (itype) {
+ case instDTP20:
+ return "DTP20";
+ case instDTP22:
+ return "DTP22";
+ case instDTP41:
+ return "DTP41";
+ case instDTP51:
+ return "DTP51";
+ case instDTP92:
+ return "DTP92";
+ case instDTP94:
+ return "DTP94";
+ case instSpectrolino:
+ return "Spectrolino";
+ case instSpectroScan:
+ return "SpectroScan";
+ case instSpectroScanT:
+ return "SpectroScanT";
+ case instSpectrocam:
+ return "Spectrocam";
+ case instI1Disp1:
+ return "i1D1";
+ case instI1Disp2:
+ return "i1D2";
+ case instI1Disp3:
+ return "i1D3";
+ case instI1Monitor:
+ return "i1 Monitor";
+ case instI1Pro:
+ return "i1 Pro";
+ case instI1Pro2:
+ return "i1 Pro 2";
+ case instColorMunki:
+ return "ColorMunki";
+ case instHCFR:
+ return "HCFR";
+ case instSpyder2:
+ return "Spyder2";
+ case instSpyder3:
+ return "Spyder3";
+ case instSpyder4:
+ return "Spyder4";
+ case instHuey:
+ return "Huey";
+ case instSmile:
+ return "Smile";
+ case instColorHug:
+ return "ColorHug";
+ default:
+ break;
+ }
+ return "Unknown";
+}
+
+/* Return the long instrument identification name (static string) */
+char *inst_name(instType itype) {
+ switch (itype) {
+ case instDTP20:
+ return "Xrite DTP20";
+ case instDTP22:
+ return "Xrite DTP22";
+ case instDTP41:
+ return "Xrite DTP41";
+ case instDTP51:
+ return "Xrite DTP51";
+ case instDTP92:
+ return "Xrite DTP92";
+ case instDTP94:
+ return "Xrite DTP94";
+ case instSpectrolino:
+ return "GretagMacbeth Spectrolino";
+ case instSpectroScan:
+ return "GretagMacbeth SpectroScan";
+ case instSpectroScanT:
+ return "GretagMacbeth SpectroScanT";
+ case instSpectrocam:
+ return "Spectrocam";
+ case instI1Disp1:
+ return "GretagMacbeth i1 Display 1";
+ case instI1Disp2:
+ return "GretagMacbeth i1 Display 2";
+ case instI1Disp3:
+ return "Xrite i1 DisplayPro, ColorMunki Display";
+ case instI1Monitor:
+ return "GretagMacbeth i1 Monitor";
+ case instI1Pro:
+ return "GretagMacbeth i1 Pro";
+ case instI1Pro2:
+ return "X-Rite i1 Pro 2";
+ case instColorMunki:
+ return "X-Rite ColorMunki";
+ case instHCFR:
+ return "Colorimtre HCFR";
+ case instSpyder2:
+ return "ColorVision Spyder2";
+ case instSpyder3:
+ return "Datacolor Spyder3";
+ case instSpyder4:
+ return "Datacolor Spyder4";
+ case instHuey:
+ return "GretagMacbeth Huey";
+ case instSmile:
+ return "ColorMunki Smile";
+ case instColorHug:
+ return "Hughski ColorHug";
+ default:
+ break;
+ }
+ return "Unknown Instrument";
+}
+
+/* Given a long instrument identification name, return the matching */
+/* instType, or instUnknown if not matched */
+instType inst_enum(char *name) {
+
+ if (strcmp(name, "Xrite DTP20") == 0)
+ return instDTP20;
+ else if (strcmp(name, "Xrite DTP22") == 0)
+ return instDTP22;
+ else if (strcmp(name, "Xrite DTP41") == 0)
+ return instDTP41;
+ else if (strcmp(name, "Xrite DTP51") == 0)
+ return instDTP51;
+ else if (strcmp(name, "Xrite DTP92") == 0)
+ return instDTP92;
+ else if (strcmp(name, "Xrite DTP94") == 0)
+ return instDTP94;
+ else if (strcmp(name, "GretagMacbeth Spectrolino") == 0)
+ return instSpectrolino;
+ else if (strcmp(name, "GretagMacbeth SpectroScan") == 0)
+ return instSpectroScan;
+ else if (strcmp(name, "GretagMacbeth SpectroScanT") == 0)
+ return instSpectroScanT;
+ else if (strcmp(name, "Spectrocam") == 0)
+ return instSpectrocam;
+ else if (strcmp(name, "GretagMacbeth i1 Display 1") == 0)
+ return instI1Disp1;
+ else if (strcmp(name, "GretagMacbeth i1 Display 2") == 0
+ || strcmp(name, "GretagMacbeth i1 Display") == 0
+ || strcmp(name, "Xrite i1 Display") == 0)
+ return instI1Disp2;
+ else if (strcmp(name, "Xrite i1 DisplayPro") == 0
+ || strcmp(name, "ColorMunki Display") == 0)
+ return instI1Disp3;
+ else if (strcmp(name, "GretagMacbeth i1 Monitor") == 0)
+ return instI1Monitor;
+ else if (strcmp(name, "GretagMacbeth i1 Pro") == 0
+ || strcmp(name, "Xrite i1 Pro") == 0)
+ return instI1Pro;
+ else if (strcmp(name, "Xrite i1 Pro 2") == 0)
+ return instI1Pro2;
+ else if (strcmp(name, "X-Rite ColorMunki") == 0)
+ return instColorMunki;
+ else if (strcmp(name, "Colorimtre HCFR") == 0)
+ return instHCFR;
+ else if (strcmp(name, "ColorVision Spyder2") == 0)
+ return instSpyder2;
+ else if (strcmp(name, "Datacolor Spyder3") == 0)
+ return instSpyder3;
+ else if (strcmp(name, "Datacolor Spyder4") == 0)
+ return instSpyder4;
+ else if (strcmp(name, "GretagMacbeth Huey") == 0)
+ return instHuey;
+ else if (strcmp(name, "ColorMunki Smile") == 0)
+ return instSmile;
+ else if (strcmp(name, "Hughski ColorHug") == 0)
+ return instColorHug;
+
+ return instUnknown;
+}
+
+#ifdef ENABLE_USB
+
+/* Given a USB vendor and product ID, */
+/* return the matching instrument type, or */
+/* instUnknown if none match. */
+/* If nep == 0, do preliminary match just on vid & pid */
+instType inst_usb_match(
+unsigned int idVendor,
+unsigned int idProduct,
+int nep) { /* Number of end points */
+
+ if (idVendor == 0x04DB) {
+ if (idProduct == 0x005B) /* Colorimtre HCFR */
+ return instHCFR;
+ }
+
+ if (idVendor == 0x0670) { /* Sequel Imaging */
+ if (idProduct == 0x0001) /* Monaco Optix / i1 Display 1 */
+ /* Sequel Chroma 4 / i1 Display 1 */
+ return instI1Disp1;
+ }
+
+ if (idVendor == 0x0765) { /* X-Rite */
+ if (idProduct == 0x5001) /* HueyL (Lenovo W70DS Laptop ?) */
+ return instHuey;
+ if (idProduct == 0x5010) /* HueyL (Lenovo W530 Laptop ?) */
+ return instHuey;
+ if (idProduct == 0x5020) /* i1DisplayPro, ColorMunki Display (HID) */
+ return instI1Disp3;
+ if (idProduct == 0x6003) /* ColorMinki Smile (aka. ColorMunki Display Lite) */
+ return instSmile;
+ if (idProduct == 0xD020) /* DTP20 */
+ return instDTP20;
+ if (idProduct == 0xD092) /* DTP92Q */
+ return instDTP92;
+ if (idProduct == 0xD094) /* DTP94 */
+ return instDTP94;
+ }
+
+ if (idVendor == 0x085C) { /* ColorVision */
+ if (idProduct == 0x0100) /* ColorVision Spyder1 */
+ return instSpyder2; /* Alias to Spyder 2 */
+ if (idProduct == 0x0200) /* ColorVision Spyder2 */
+ return instSpyder2;
+ if (idProduct == 0x0300) /* ColorVision Spyder3 */
+ return instSpyder3;
+ if (idProduct == 0x0400) /* ColorVision Spyder4 */
+ return instSpyder4;
+ }
+
+ if (idVendor == 0x0971) { /* Gretag Macbeth */
+ if (idProduct == 0x2000) { /* i1 Pro or i1 Pro 2*/
+
+ /* The i1pro2/rev E has 5 pipes - it has EP 85 */
+ if (nep >= 5)
+ return instI1Pro2;
+ else
+ return instI1Pro;
+ }
+ if (idProduct == 0x2001) /* i1 Monitor */
+ return instI1Monitor;
+ if (idProduct == 0x2003) /* i1 Display 2 */
+ return instI1Disp2;
+ if (idProduct == 0x2005) /* Huey (HID) */
+ return instHuey;
+ if (idProduct == 0x2007) /* ColorMunki */
+ return instColorMunki;
+ }
+
+ if ((idVendor == 0x04d8 && idProduct == 0xf8da) /* Microchip & Hughski ColorHug (old) */
+ || (idVendor == 0x273f && idProduct == 0x1001)) { /* Hughski & ColorHug Fmw. >= 0.1.20 */
+ return instColorHug;
+ }
+ /* Add other instruments here */
+
+ return instUnknown;
+}
+
+#endif /* ENABLE_USB */
+
+/* Should deprecate the following. It should be replaced with a */
+/* method in the instrument class that returns its configured spectrum, */
+/* and the spectrum should be embedded in the .ti3 file, not the instrument */
+/* name. */
+
+/* Fill in an instruments illuminant spectrum. */
+/* Return 0 on sucess, 1 if not not applicable. */
+int inst_illuminant(xspect *sp, instType itype) {
+
+ switch (itype) {
+ case instDTP20:
+ return standardIlluminant(sp, icxIT_A, 0); /* 2850K */
+
+ case instDTP22:
+ return standardIlluminant(sp, icxIT_A, 0); /* 2850K */
+
+ case instDTP41:
+ return standardIlluminant(sp, icxIT_A, 0); /* 2850K */
+
+ case instDTP51:
+ return standardIlluminant(sp, icxIT_A, 0); /* 2850K */
+
+ case instDTP92:
+ case instDTP94:
+ return 1; /* Not applicable */
+
+ /* Strictly the Spectrolino could have the UV or D65 filter on, */
+ /* but since we're not currently passing this inform through, we */
+ /* are simply assuming the default A type illuminant. */
+
+ case instSpectrolino:
+ return standardIlluminant(sp, icxIT_A, 0); /* Standard A type assumed */
+
+ case instSpectroScan:
+ return standardIlluminant(sp, icxIT_A, 0); /* Standard A type assumed */
+
+ case instSpectroScanT:
+ return standardIlluminant(sp, icxIT_A, 0); /* Standard A type assumed */
+
+#ifndef SALONEINSTLIB
+ case instSpectrocam:
+ return standardIlluminant(sp, icxIT_Spectrocam, 0); /* Spectrocam Xenon Lamp */
+#endif
+ case instI1Disp1:
+ return 1; /* Not applicable */
+
+ case instI1Disp2:
+ return 1; /* Not applicable */
+
+ case instI1Disp3:
+ return 1; /* Not applicable */
+
+ case instI1Monitor:
+ return 1; /* Not applicable */
+
+ case instI1Pro:
+ case instI1Pro2:
+ return standardIlluminant(sp, icxIT_A, 0); /* Standard A type assumed */
+
+ case instColorMunki:
+ return 1; /* No U.V. */
+
+ case instHCFR:
+ return 1; /* Not applicable */
+
+ case instSpyder2:
+ return 1; /* Not applicable */
+
+ case instSpyder3:
+ return 1; /* Not applicable */
+
+ case instSpyder4:
+ return 1; /* Not applicable */
+
+ case instHuey:
+ return 1; /* Not applicable */
+
+ case instSmile:
+ return 1; /* Not applicable */
+
+ case instColorHug:
+ return 1; /* Not applicable */
+
+
+ default:
+ break;
+ }
+ return 1;
+}
+
+
diff --git a/spectro/insttypes.h b/spectro/insttypes.h
new file mode 100644
index 0000000..88e800b
--- /dev/null
+++ b/spectro/insttypes.h
@@ -0,0 +1,100 @@
+
+#ifndef INSTTYPES_H
+
+ /* Instrument suported types utilities. */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 15/3/2001
+ *
+ * Copyright 2001 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* ----------------------------- */
+/* Possible types of instruments */
+typedef enum {
+ instUnknown = 0, /* Undefined Instrument */
+ instDTP20, /* Xrite DTP20 (Pulse) */
+ instDTP22, /* Xrite DTP22 (Digital Swatchbook) */
+ instDTP41, /* Xrite DTP41 */
+ instDTP51, /* Xrite DTP51 */
+ instDTP92, /* Xrite DTP92 */
+ instDTP94, /* Xrite DTP94 (Optix) */
+ instSpectrolino, /* GretagMacbeth Spectrolino */
+ instSpectroScan, /* GretagMacbeth SpectroScan */
+ instSpectroScanT, /* GretagMacbeth SpectroScanT */
+ instSpectrocam, /* Avantes Spectrocam */
+ instI1Disp1, /* GretagMacbeth i1 Display 1 */
+ instI1Disp2, /* GretagMacbeth i1 Display 2 */
+ instI1Disp3, /* Xrite i1 DisplayPro, ColorMunki Display */
+ instI1Monitor, /* GretagMacbeth i1 Monitor */
+ instI1Pro, /* GretagMacbeth i1 Pro */
+ instI1Pro2, /* X-Rite i1 Pro2 */
+ instColorMunki, /* X-Rite ColorMunki */
+ instHCFR, /* Colorimtre HCFR */
+ instSpyder2, /* Datacolor/ColorVision Spyder2 */
+ instSpyder3, /* Datacolor Spyder3 */
+ instSpyder4, /* Datacolor Spyder4 */
+ instHuey, /* GretagMacbeth Huey */
+ instSmile, /* X-rite Colormunki Smile */
+ instColorHug, /* Hughski ColorHug */
+
+} instType;
+
+struct _icoms; /* Forward declaration */
+
+/* Utility functions in libinsttypes */
+
+/* Given its instrument type, return the matching */
+/* short instrument name (static string), */
+extern char *inst_sname(instType itype);
+
+/* Given its instrument type, return the matching */
+/* long instrument identification name (static string), */
+extern char *inst_name(instType itype);
+
+
+/* Given an instrument long identification name, return the matching */
+/* instType, or instUnknown if not matched */
+extern instType inst_enum(char *name);
+
+
+#ifdef ENABLE_USB
+/* Given a USB vendor and product ID, */
+/* return the matching instrument type, or */
+/* instUnknown if none match. */
+extern instType inst_usb_match(
+unsigned int idVendor,
+unsigned int idProduct,
+int nep); /* Number of end points (0 for prelim match) */
+#endif /* ENABLE_USB */
+
+
+/* Should deprecate the following. It should be replaced with a */
+/* method in the instrument class that returns its configured spectrum, */
+/* and the spectrum should be embedded in the .ti3 file, not the instrument */
+/* name. */
+
+/* Fill in an instruments illuminant spectrum. */
+/* Return 0 on sucess, 1 if not not applicable. */
+extern int inst_illuminant(xspect *sp, instType itype);
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define INSTTYPES_H
+#endif /* INSTTYPES_H */
+
diff --git a/spectro/iusb.h b/spectro/iusb.h
new file mode 100644
index 0000000..a254ec0
--- /dev/null
+++ b/spectro/iusb.h
@@ -0,0 +1,131 @@
+#ifndef _IUSB_H_
+
+/* Standard USB protocol defines */
+
+/*
+ * Copyright 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/* Device and/or Interface Class codes */
+#define IUSB_CLASS_PER_INTERFACE 0x00 /* for DeviceClass */
+#define IUSB_CLASS_AUDIO 0x01
+#define IUSB_CLASS_COMM 0x02
+#define IUSB_CLASS_HID 0x03
+#define IUSB_CLASS_PHYSICAL 0x05
+#define IUSB_CLASS_STILL_IMAGE 0x06
+#define IUSB_CLASS_PRINTER 0x07
+#define IUSB_CLASS_MASS_STORAGE 0x08
+#define IUSB_CLASS_HUB 0x09
+#define IUSB_CLASS_CDC_DATA 0x0a
+#define IUSB_CLASS_SMART_CARD 0x0b
+#define IUSB_CLASS_CONT_SECURITY 0x0d
+#define IUSB_CLASS_VIDEO 0x0e
+#define IUSB_CLASS_DIAGNOSTIC 0xdc
+#define IUSB_CLASS_WIRELESS 0xe0
+#define IUSB_CLASS_MISC 0xef
+#define IUSB_CLASS_APP_SPEC 0xfe
+#define IUSB_CLASS_VENDOR_SPEC 0xff
+
+
+/* Standard Descriptor types */
+#define IUSB_DESC_TYPE_DEVICE 0x01
+#define IUSB_DESC_TYPE_CONFIG 0x02
+#define IUSB_DESC_TYPE_STRING 0x03
+#define IUSB_DESC_TYPE_INTERFACE 0x04
+#define IUSB_DESC_TYPE_ENDPOINT 0x05
+#define IUSB_DESC_TYPE_DEVICE_QUALIFIER 0x06
+#define IUSB_DESC_TYPE_OTHER_SPEED_CONFIG 0x07
+#define IUSB_DESC_TYPE_INTERFACE_POWER 0x08
+#define IUSB_DESC_TYPE_OTG 0x09
+#define IUSB_DESC_TYPE_DEBUG 0x0a
+#define IUSB_DESC_TYPE_INTERFACE_ASSOCIATION 0x0b
+
+/* Descriptor sizes per descriptor type */
+#define IUSB_DESC_TYPE_DEVICE_SIZE 18
+#define IUSB_DESC_TYPE_CONFIG_SIZE 9
+#define IUSB_DESC_TYPE_INTERFACE_SIZE 9
+#define IUSB_DESC_TYPE_ENDPOINT_SIZE 7
+
+/* Endpoint descriptor bEndpointAddress */
+#define IUSB_ENDPOINT_NUM_MASK 0x0f
+#define IUSB_ENDPOINT_DIR_MASK 0x80
+#define IUSB_ENDPOINT_DIR_SHIFT 7
+#define IUSB_ENDPOINT_IN 0x80
+#define IUSB_ENDPOINT_OUT 0x00
+
+/* Endpoint descriptor bmAttributes */
+#define IUSB_ENDPOINT_TYPE_MASK 0x03
+#define IUSB_ENDPOINT_TYPE_CONTROL 0x00
+#define IUSB_ENDPOINT_TYPE_ISOCHRONOUS 0x01
+#define IUSB_ENDPOINT_TYPE_BULK 0x02
+#define IUSB_ENDPOINT_TYPE_INTERRUPT 0x03
+
+#define IUSB_ENDPOINT_SYNC_MASK 0x0c
+#define IUSB_ENDPOINT_SYNC_NONE 0x00
+#define IUSB_ENDPOINT_SYNC_ASYNC 0x04
+#define IUSB_ENDPOINT_SYNC_ADPT 0x08
+#define IUSB_ENDPOINT_SYNC_SYNC 0x0c
+
+#define IUSB_ENDPOINT_USAGE_MASK 0x30
+#define IUSB_ENDPOINT_USAGE_DATA 0x00
+#define IUSB_ENDPOINT_USAGE_FEED 0x10
+#define IUSB_ENDPOINT_USAGE_IMPL_FEED 0x20
+
+/* Endpoint descriptor wMaxPacketSize */
+#define IUSB_ENDPOINT_MAX_PKTSZ_MASK 0x03ff
+#define IUSB_ENDPOINT_MAX_XACTS_MASK 0x0c00
+#define IUSB_ENDPOINT_MAX_XACTS_SHIFT 11
+
+/* OTG descriptor bmAttributes */
+#define IUSB_OTG_SRP 0x00
+#define IUSB_OTG_HNP 0x01
+
+/* Control request */
+#define IUSB_REQ_HEADER_SIZE 8
+
+/* Request bmRequestType */
+#define IUSB_REQ_HOST_TO_DEV 0x00
+#define IUSB_REQ_DEV_TO_HOST 0x80
+#define IUSB_REQ_DIR_MASK 0x80
+
+#define IUSB_REQ_TYPE_SHIFT 5
+#define IUSB_REQ_TYPE_STANDARD (0x00 << IUSB_REQ_TYPE_SHIFT)
+#define IUSB_REQ_TYPE_CLASS (0x01 << IUSB_REQ_TYPE_SHIFT)
+#define IUSB_REQ_TYPE_VENDOR (0x02 << IUSB_REQ_TYPE_SHIFT)
+#define IUSB_REQ_TYPE_RESERVED (0x03 << IUSB_REQ_TYPE_SHIFT)
+#define IUSB_REQ_TYPE_MASK (0x03 << IUSB_REQ_TYPE_SHIFT)
+
+#define IUSB_REQ_RECIP_DEVICE 0x00
+#define IUSB_REQ_RECIP_INTERFACE 0x01
+#define IUSB_REQ_RECIP_ENDPOINT 0x02
+#define IUSB_REQ_RECIP_OTHER 0x03
+#define IUSB_REQ_RECIP_MASK 0x1f
+
+/* Standard bRequest values */
+#define IUSB_REQ_GET_STATUS 0x00
+#define IUSB_REQ_CLEAR_FEATURE 0x01
+#define IUSB_REQ_SET_FEATURE 0x03
+#define IUSB_REQ_SET_ADDRESS 0x05
+#define IUSB_REQ_GET_DESCRIPTOR 0x06
+#define IUSB_REQ_SET_DESCRIPTOR 0x07
+#define IUSB_REQ_GET_CONFIGURATION 0x08
+#define IUSB_REQ_SET_CONFIGURATION 0x09
+#define IUSB_REQ_GET_INTERFACE 0x0a
+#define IUSB_REQ_SET_INTERFACE 0x0b
+#define IUSB_REQ_SYNCH_FRAME 0x0c
+
+/* Feature selector */
+#define IUSB_FEATURE_EP_HALT 0
+#define IUSB_FEATURE_DEV_REMOTE_WAKEUP 1
+
+/* REQ_GET_STATUS return values */
+#define IUSB_DEVICE_STATUS_SELFPWR 0x0001
+#define IUSB_DEVICE_STATUS_REMOTE_WAKEUP 0x0002
+#define IUSB_ENDPOINT_STATUS_HALT 0x0001
+
+#define _IUSB_H_
+#endif /* _IUSB_H_ */
diff --git a/spectro/linear.cal b/spectro/linear.cal
new file mode 100644
index 0000000..30da145
--- /dev/null
+++ b/spectro/linear.cal
@@ -0,0 +1,275 @@
+CAL
+
+DESCRIPTOR "Argyll Device Calibration Curves"
+ORIGINATOR "Argyll synthcal"
+CREATED "Sat Mar 09 18:33:22 2013"
+KEYWORD "DEVICE_CLASS"
+DEVICE_CLASS "DISPLAY"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+
+KEYWORD "RGB_I"
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+RGB_I RGB_R RGB_G RGB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 256
+BEGIN_DATA
+0.0000 0.0000 0.0000 0.0000
+3.9216e-003 3.9216e-003 3.9216e-003 3.9216e-003
+7.8431e-003 7.8431e-003 7.8431e-003 7.8431e-003
+0.011765 0.011765 0.011765 0.011765
+0.015686 0.015686 0.015686 0.015686
+0.019608 0.019608 0.019608 0.019608
+0.023529 0.023529 0.023529 0.023529
+0.027451 0.027451 0.027451 0.027451
+0.031373 0.031373 0.031373 0.031373
+0.035294 0.035294 0.035294 0.035294
+0.039216 0.039216 0.039216 0.039216
+0.043137 0.043137 0.043137 0.043137
+0.047059 0.047059 0.047059 0.047059
+0.050980 0.050980 0.050980 0.050980
+0.054902 0.054902 0.054902 0.054902
+0.058824 0.058824 0.058824 0.058824
+0.062745 0.062745 0.062745 0.062745
+0.066667 0.066667 0.066667 0.066667
+0.070588 0.070588 0.070588 0.070588
+0.074510 0.074510 0.074510 0.074510
+0.078431 0.078431 0.078431 0.078431
+0.082353 0.082353 0.082353 0.082353
+0.086275 0.086275 0.086275 0.086275
+0.090196 0.090196 0.090196 0.090196
+0.094118 0.094118 0.094118 0.094118
+0.098039 0.098039 0.098039 0.098039
+0.10196 0.10196 0.10196 0.10196
+0.10588 0.10588 0.10588 0.10588
+0.10980 0.10980 0.10980 0.10980
+0.11373 0.11373 0.11373 0.11373
+0.11765 0.11765 0.11765 0.11765
+0.12157 0.12157 0.12157 0.12157
+0.12549 0.12549 0.12549 0.12549
+0.12941 0.12941 0.12941 0.12941
+0.13333 0.13333 0.13333 0.13333
+0.13725 0.13725 0.13725 0.13725
+0.14118 0.14118 0.14118 0.14118
+0.14510 0.14510 0.14510 0.14510
+0.14902 0.14902 0.14902 0.14902
+0.15294 0.15294 0.15294 0.15294
+0.15686 0.15686 0.15686 0.15686
+0.16078 0.16078 0.16078 0.16078
+0.16471 0.16471 0.16471 0.16471
+0.16863 0.16863 0.16863 0.16863
+0.17255 0.17255 0.17255 0.17255
+0.17647 0.17647 0.17647 0.17647
+0.18039 0.18039 0.18039 0.18039
+0.18431 0.18431 0.18431 0.18431
+0.18824 0.18824 0.18824 0.18824
+0.19216 0.19216 0.19216 0.19216
+0.19608 0.19608 0.19608 0.19608
+0.20000 0.20000 0.20000 0.20000
+0.20392 0.20392 0.20392 0.20392
+0.20784 0.20784 0.20784 0.20784
+0.21176 0.21176 0.21176 0.21176
+0.21569 0.21569 0.21569 0.21569
+0.21961 0.21961 0.21961 0.21961
+0.22353 0.22353 0.22353 0.22353
+0.22745 0.22745 0.22745 0.22745
+0.23137 0.23137 0.23137 0.23137
+0.23529 0.23529 0.23529 0.23529
+0.23922 0.23922 0.23922 0.23922
+0.24314 0.24314 0.24314 0.24314
+0.24706 0.24706 0.24706 0.24706
+0.25098 0.25098 0.25098 0.25098
+0.25490 0.25490 0.25490 0.25490
+0.25882 0.25882 0.25882 0.25882
+0.26275 0.26275 0.26275 0.26275
+0.26667 0.26667 0.26667 0.26667
+0.27059 0.27059 0.27059 0.27059
+0.27451 0.27451 0.27451 0.27451
+0.27843 0.27843 0.27843 0.27843
+0.28235 0.28235 0.28235 0.28235
+0.28627 0.28627 0.28627 0.28627
+0.29020 0.29020 0.29020 0.29020
+0.29412 0.29412 0.29412 0.29412
+0.29804 0.29804 0.29804 0.29804
+0.30196 0.30196 0.30196 0.30196
+0.30588 0.30588 0.30588 0.30588
+0.30980 0.30980 0.30980 0.30980
+0.31373 0.31373 0.31373 0.31373
+0.31765 0.31765 0.31765 0.31765
+0.32157 0.32157 0.32157 0.32157
+0.32549 0.32549 0.32549 0.32549
+0.32941 0.32941 0.32941 0.32941
+0.33333 0.33333 0.33333 0.33333
+0.33725 0.33725 0.33725 0.33725
+0.34118 0.34118 0.34118 0.34118
+0.34510 0.34510 0.34510 0.34510
+0.34902 0.34902 0.34902 0.34902
+0.35294 0.35294 0.35294 0.35294
+0.35686 0.35686 0.35686 0.35686
+0.36078 0.36078 0.36078 0.36078
+0.36471 0.36471 0.36471 0.36471
+0.36863 0.36863 0.36863 0.36863
+0.37255 0.37255 0.37255 0.37255
+0.37647 0.37647 0.37647 0.37647
+0.38039 0.38039 0.38039 0.38039
+0.38431 0.38431 0.38431 0.38431
+0.38824 0.38824 0.38824 0.38824
+0.39216 0.39216 0.39216 0.39216
+0.39608 0.39608 0.39608 0.39608
+0.40000 0.40000 0.40000 0.40000
+0.40392 0.40392 0.40392 0.40392
+0.40784 0.40784 0.40784 0.40784
+0.41176 0.41176 0.41176 0.41176
+0.41569 0.41569 0.41569 0.41569
+0.41961 0.41961 0.41961 0.41961
+0.42353 0.42353 0.42353 0.42353
+0.42745 0.42745 0.42745 0.42745
+0.43137 0.43137 0.43137 0.43137
+0.43529 0.43529 0.43529 0.43529
+0.43922 0.43922 0.43922 0.43922
+0.44314 0.44314 0.44314 0.44314
+0.44706 0.44706 0.44706 0.44706
+0.45098 0.45098 0.45098 0.45098
+0.45490 0.45490 0.45490 0.45490
+0.45882 0.45882 0.45882 0.45882
+0.46275 0.46275 0.46275 0.46275
+0.46667 0.46667 0.46667 0.46667
+0.47059 0.47059 0.47059 0.47059
+0.47451 0.47451 0.47451 0.47451
+0.47843 0.47843 0.47843 0.47843
+0.48235 0.48235 0.48235 0.48235
+0.48627 0.48627 0.48627 0.48627
+0.49020 0.49020 0.49020 0.49020
+0.49412 0.49412 0.49412 0.49412
+0.49804 0.49804 0.49804 0.49804
+0.50196 0.50196 0.50196 0.50196
+0.50588 0.50588 0.50588 0.50588
+0.50980 0.50980 0.50980 0.50980
+0.51373 0.51373 0.51373 0.51373
+0.51765 0.51765 0.51765 0.51765
+0.52157 0.52157 0.52157 0.52157
+0.52549 0.52549 0.52549 0.52549
+0.52941 0.52941 0.52941 0.52941
+0.53333 0.53333 0.53333 0.53333
+0.53725 0.53725 0.53725 0.53725
+0.54118 0.54118 0.54118 0.54118
+0.54510 0.54510 0.54510 0.54510
+0.54902 0.54902 0.54902 0.54902
+0.55294 0.55294 0.55294 0.55294
+0.55686 0.55686 0.55686 0.55686
+0.56078 0.56078 0.56078 0.56078
+0.56471 0.56471 0.56471 0.56471
+0.56863 0.56863 0.56863 0.56863
+0.57255 0.57255 0.57255 0.57255
+0.57647 0.57647 0.57647 0.57647
+0.58039 0.58039 0.58039 0.58039
+0.58431 0.58431 0.58431 0.58431
+0.58824 0.58824 0.58824 0.58824
+0.59216 0.59216 0.59216 0.59216
+0.59608 0.59608 0.59608 0.59608
+0.60000 0.60000 0.60000 0.60000
+0.60392 0.60392 0.60392 0.60392
+0.60784 0.60784 0.60784 0.60784
+0.61176 0.61176 0.61176 0.61176
+0.61569 0.61569 0.61569 0.61569
+0.61961 0.61961 0.61961 0.61961
+0.62353 0.62353 0.62353 0.62353
+0.62745 0.62745 0.62745 0.62745
+0.63137 0.63137 0.63137 0.63137
+0.63529 0.63529 0.63529 0.63529
+0.63922 0.63922 0.63922 0.63922
+0.64314 0.64314 0.64314 0.64314
+0.64706 0.64706 0.64706 0.64706
+0.65098 0.65098 0.65098 0.65098
+0.65490 0.65490 0.65490 0.65490
+0.65882 0.65882 0.65882 0.65882
+0.66275 0.66275 0.66275 0.66275
+0.66667 0.66667 0.66667 0.66667
+0.67059 0.67059 0.67059 0.67059
+0.67451 0.67451 0.67451 0.67451
+0.67843 0.67843 0.67843 0.67843
+0.68235 0.68235 0.68235 0.68235
+0.68627 0.68627 0.68627 0.68627
+0.69020 0.69020 0.69020 0.69020
+0.69412 0.69412 0.69412 0.69412
+0.69804 0.69804 0.69804 0.69804
+0.70196 0.70196 0.70196 0.70196
+0.70588 0.70588 0.70588 0.70588
+0.70980 0.70980 0.70980 0.70980
+0.71373 0.71373 0.71373 0.71373
+0.71765 0.71765 0.71765 0.71765
+0.72157 0.72157 0.72157 0.72157
+0.72549 0.72549 0.72549 0.72549
+0.72941 0.72941 0.72941 0.72941
+0.73333 0.73333 0.73333 0.73333
+0.73725 0.73725 0.73725 0.73725
+0.74118 0.74118 0.74118 0.74118
+0.74510 0.74510 0.74510 0.74510
+0.74902 0.74902 0.74902 0.74902
+0.75294 0.75294 0.75294 0.75294
+0.75686 0.75686 0.75686 0.75686
+0.76078 0.76078 0.76078 0.76078
+0.76471 0.76471 0.76471 0.76471
+0.76863 0.76863 0.76863 0.76863
+0.77255 0.77255 0.77255 0.77255
+0.77647 0.77647 0.77647 0.77647
+0.78039 0.78039 0.78039 0.78039
+0.78431 0.78431 0.78431 0.78431
+0.78824 0.78824 0.78824 0.78824
+0.79216 0.79216 0.79216 0.79216
+0.79608 0.79608 0.79608 0.79608
+0.80000 0.80000 0.80000 0.80000
+0.80392 0.80392 0.80392 0.80392
+0.80784 0.80784 0.80784 0.80784
+0.81176 0.81176 0.81176 0.81176
+0.81569 0.81569 0.81569 0.81569
+0.81961 0.81961 0.81961 0.81961
+0.82353 0.82353 0.82353 0.82353
+0.82745 0.82745 0.82745 0.82745
+0.83137 0.83137 0.83137 0.83137
+0.83529 0.83529 0.83529 0.83529
+0.83922 0.83922 0.83922 0.83922
+0.84314 0.84314 0.84314 0.84314
+0.84706 0.84706 0.84706 0.84706
+0.85098 0.85098 0.85098 0.85098
+0.85490 0.85490 0.85490 0.85490
+0.85882 0.85882 0.85882 0.85882
+0.86275 0.86275 0.86275 0.86275
+0.86667 0.86667 0.86667 0.86667
+0.87059 0.87059 0.87059 0.87059
+0.87451 0.87451 0.87451 0.87451
+0.87843 0.87843 0.87843 0.87843
+0.88235 0.88235 0.88235 0.88235
+0.88627 0.88627 0.88627 0.88627
+0.89020 0.89020 0.89020 0.89020
+0.89412 0.89412 0.89412 0.89412
+0.89804 0.89804 0.89804 0.89804
+0.90196 0.90196 0.90196 0.90196
+0.90588 0.90588 0.90588 0.90588
+0.90980 0.90980 0.90980 0.90980
+0.91373 0.91373 0.91373 0.91373
+0.91765 0.91765 0.91765 0.91765
+0.92157 0.92157 0.92157 0.92157
+0.92549 0.92549 0.92549 0.92549
+0.92941 0.92941 0.92941 0.92941
+0.93333 0.93333 0.93333 0.93333
+0.93725 0.93725 0.93725 0.93725
+0.94118 0.94118 0.94118 0.94118
+0.94510 0.94510 0.94510 0.94510
+0.94902 0.94902 0.94902 0.94902
+0.95294 0.95294 0.95294 0.95294
+0.95686 0.95686 0.95686 0.95686
+0.96078 0.96078 0.96078 0.96078
+0.96471 0.96471 0.96471 0.96471
+0.96863 0.96863 0.96863 0.96863
+0.97255 0.97255 0.97255 0.97255
+0.97647 0.97647 0.97647 0.97647
+0.98039 0.98039 0.98039 0.98039
+0.98431 0.98431 0.98431 0.98431
+0.98824 0.98824 0.98824 0.98824
+0.99216 0.99216 0.99216 0.99216
+0.99608 0.99608 0.99608 0.99608
+1.0000 1.0000 1.0000 1.0000
+END_DATA
diff --git a/spectro/linear.sp b/spectro/linear.sp
new file mode 100644
index 0000000..8851462
--- /dev/null
+++ b/spectro/linear.sp
@@ -0,0 +1,23 @@
+SPECT
+
+DESCRIPTOR "Argyll Spectrolino tele adapter compensation filter - linear version"
+ORIGINATOR "Argyll CMS"
+CREATED "Wed Jun 21 17:49:57 2006"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "36"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "380.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "730.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "1.000000"
+
+NUMBER_OF_FIELDS 36
+BEGIN_DATA_FORMAT
+SPEC_380 SPEC_390 SPEC_400 SPEC_410 SPEC_420 SPEC_430 SPEC_440 SPEC_450 SPEC_460 SPEC_470 SPEC_480 SPEC_490 SPEC_500 SPEC_510 SPEC_520 SPEC_530 SPEC_540 SPEC_550 SPEC_560 SPEC_570 SPEC_580 SPEC_590 SPEC_600 SPEC_610 SPEC_620 SPEC_630 SPEC_640 SPEC_650 SPEC_660 SPEC_670 SPEC_680 SPEC_690 SPEC_700 SPEC_710 SPEC_720 SPEC_730
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
+END_DATA
diff --git a/spectro/mongoose.c b/spectro/mongoose.c
new file mode 100644
index 0000000..e1df94a
--- /dev/null
+++ b/spectro/mongoose.c
@@ -0,0 +1,4819 @@
+// Copyright (c) 2004-2012 Sergey Lyubka
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#if defined(_WIN32)
+#define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005
+#else
+#ifdef __linux__
+#define _XOPEN_SOURCE 600 // For flockfile() on Linux
+#endif
+#define _LARGEFILE_SOURCE // Enable 64-bit file offsets
+#define __STDC_FORMAT_MACROS // <inttypes.h> wants this for C++
+#define __STDC_LIMIT_MACROS // C++ wants that for INT64_MAX
+#endif
+
+//#ifdef WIN32_LEAN_AND_MEAN
+//#undef WIN32_LEAN_AND_MEAN // Disable WIN32_LEAN_AND_MEAN, if necessary
+//#endif
+
+#define WIN32_LEAN_AND_MEAN // Set WIN32_LEAN_AND_MEAN to prevent winsock2.h problem
+
+#if defined(__SYMBIAN32__)
+#define NO_SSL // SSL is not supported
+#define NO_CGI // CGI is not supported
+#define PATH_MAX FILENAME_MAX
+#endif // __SYMBIAN32__
+
+#ifndef _WIN32_WCE // Some ANSI #includes are not available on Windows CE
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#endif // !_WIN32_WCE
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__) // Windows specific
+#if _WIN32_WINNT < 0x0400
+# define _WIN32_WINNT 0x0400 // To make it link in VS2005
+#endif
+#ifndef WIN32
+# define WIN32
+#endif
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+
+#ifndef PATH_MAX
+# define PATH_MAX MAX_PATH
+#endif
+
+#ifndef _WIN32_WCE
+# include <process.h>
+# include <direct.h>
+# include <io.h>
+#else // _WIN32_WCE
+# define NO_CGI // WinCE has no pipes
+
+typedef long off_t;
+
+# define errno GetLastError()
+# define strerror(x) _ultoa(x, (char *) _alloca(sizeof(x) *3 ), 10)
+#endif // _WIN32_WCE
+
+#define MAKEUQUAD(lo, hi) ((uint64_t)(((uint32_t)(lo)) | \
+ ((uint64_t)((uint32_t)(hi))) << 32))
+#define RATE_DIFF 10000000 // 100 nsecs
+#define EPOCH_DIFF MAKEUQUAD(0xd53e8000, 0x019db1de)
+#define SYS2UNIX_TIME(lo, hi) \
+ (time_t) ((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF)
+
+// Visual Studio 6 does not know __func__ or __FUNCTION__
+// The rest of MS compilers use __FUNCTION__, not C99 __func__
+// Also use _strtoui64 on modern M$ compilers
+#if defined(_MSC_VER) && _MSC_VER < 1300
+# define STRX(x) #x
+# define STR(x) STRX(x)
+# define __func__ "line " STR(__LINE__)
+# define strtoull(x, y, z) strtoul(x, y, z)
+# define strtoll(x, y, z) strtol(x, y, z)
+#else
+# define __func__ __FUNCTION__
+# define strtoull(x, y, z) _strtoui64(x, y, z)
+# define strtoll(x, y, z) _strtoi64(x, y, z)
+#endif // _MSC_VER
+
+#define ERRNO GetLastError()
+#define NO_SOCKLEN_T
+#define SSL_LIB "ssleay32.dll"
+#define CRYPTO_LIB "libeay32.dll"
+#define O_NONBLOCK 0
+#if !defined(EWOULDBLOCK)
+# define EWOULDBLOCK WSAEWOULDBLOCK
+#endif // !EWOULDBLOCK
+#define _POSIX_
+#define INT64_FMT "I64d"
+
+#define WINCDECL __cdecl
+#define SHUT_WR 1
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#define mg_sleep(x) Sleep(x)
+
+#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
+#ifndef popen
+# define popen(x, y) _popen(x, y)
+# define pclose(x) _pclose(x)
+#endif
+#define close(x) _close(x)
+#define dlsym(x,y) GetProcAddress((HINSTANCE) (x), (y))
+#define RTLD_LAZY 0
+#define fseeko(x, y, z) _lseeki64(_fileno(x), (y), (z))
+#define fdopen(x, y) _fdopen((x), (y))
+#define write(x, y, z) _write((x), (y), (unsigned) z)
+#define read(x, y, z) _read((x), (y), (unsigned) z)
+#define flockfile(x) EnterCriticalSection(&global_log_file_lock)
+#define funlockfile(x) LeaveCriticalSection(&global_log_file_lock)
+#define sleep(x) Sleep((x) * 1000)
+
+#if !defined(fileno)
+#define fileno(x) _fileno(x)
+#endif // !fileno MINGW #defines fileno
+
+typedef HANDLE pthread_mutex_t;
+typedef struct {HANDLE signal, broadcast;} pthread_cond_t;
+typedef DWORD pthread_t;
+#define pid_t HANDLE // MINGW typedefs pid_t to int. Using #define here.
+
+static int pthread_mutex_lock(pthread_mutex_t *);
+static int pthread_mutex_unlock(pthread_mutex_t *);
+static FILE *mg_fopen(const char *path, const char *mode);
+
+#if defined(HAVE_STDINT) || defined(INT64_MAX)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
+#define INT64_MAX 9223372036854775807
+#endif // HAVE_STDINT
+
+// POSIX dirent interface
+struct dirent {
+ char d_name[PATH_MAX];
+};
+
+typedef struct DIR {
+ HANDLE handle;
+ WIN32_FIND_DATAW info;
+ struct dirent result;
+} DIR;
+
+// Mark required libraries
+#pragma comment(lib, "Ws2_32.lib")
+
+#else // UNIX specific
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <netdb.h>
+
+#include <pwd.h>
+#include <unistd.h>
+#include <dirent.h>
+#if !defined(NO_SSL_DL) && !defined(NO_SSL)
+#include <dlfcn.h>
+#endif
+#include <pthread.h>
+#if defined(__MACH__)
+#define SSL_LIB "libssl.dylib"
+#define CRYPTO_LIB "libcrypto.dylib"
+#else
+#if !defined(SSL_LIB)
+#define SSL_LIB "libssl.so"
+#endif
+#if !defined(CRYPTO_LIB)
+#define CRYPTO_LIB "libcrypto.so"
+#endif
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif // O_BINARY
+#define closesocket(a) close(a)
+#define mg_fopen(x, y) fopen(x, y)
+#define mg_mkdir(x, y) mkdir(x, y)
+#define mg_remove(x) remove(x)
+#define mg_rename(x, y) rename(x, y)
+#define mg_sleep(x) usleep((x) * 1000)
+#define ERRNO errno
+#define INVALID_SOCKET (-1)
+#define INT64_FMT PRId64
+typedef int SOCKET;
+#define WINCDECL
+
+#endif // End of Windows and UNIX specific includes
+
+#include "mongoose.h"
+
+#define MONGOOSE_VERSION "3.3"
+#define PASSWORDS_FILE_NAME ".htpasswd"
+#define CGI_ENVIRONMENT_SIZE 4096
+#define MAX_CGI_ENVIR_VARS 64
+#define MG_BUF_LEN 8192
+#define MAX_REQUEST_SIZE 16384
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+
+#ifdef _WIN32
+static CRITICAL_SECTION global_log_file_lock;
+static pthread_t pthread_self(void) {
+ return GetCurrentThreadId();
+}
+#endif // _WIN32
+
+#ifdef DEBUG_TRACE
+#undef DEBUG_TRACE
+#define DEBUG_TRACE(x)
+#else
+#if defined(DEBUG)
+#define DEBUG_TRACE(x) do { \
+ flockfile(stdout); \
+ printf("*** %lu.%p.%s.%d: ", \
+ (unsigned long) time(NULL), (void *) pthread_self(), \
+ __func__, __LINE__); \
+ printf x; \
+ putchar('\n'); \
+ fflush(stdout); \
+ funlockfile(stdout); \
+} while (0)
+#else
+#define DEBUG_TRACE(x)
+#endif // DEBUG
+#endif // DEBUG_TRACE
+
+// Darwin prior to 7.0 and Win32 do not have socklen_t
+#ifdef NO_SOCKLEN_T
+typedef int socklen_t;
+#endif // NO_SOCKLEN_T
+#define _DARWIN_UNLIMITED_SELECT
+
+#if !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL 0
+#endif
+
+#if !defined(SOMAXCONN)
+#define SOMAXCONN 100
+#endif
+
+#if !defined(PATH_MAX)
+#define PATH_MAX 4096
+#endif
+
+static const char *http_500_error = "Internal Server Error";
+
+// Snatched from OpenSSL includes. I put the prototypes here to be independent
+// from the OpenSSL source installation. Having this, mongoose + SSL can be
+// built on any system with binary SSL libraries installed.
+typedef struct ssl_st SSL;
+typedef struct ssl_method_st SSL_METHOD;
+typedef struct ssl_ctx_st SSL_CTX;
+
+#define SSL_ERROR_WANT_READ 2
+#define SSL_ERROR_WANT_WRITE 3
+#define SSL_FILETYPE_PEM 1
+#define CRYPTO_LOCK 1
+
+#if defined(NO_SSL_DL)
+extern void SSL_free(SSL *);
+extern int SSL_accept(SSL *);
+extern int SSL_connect(SSL *);
+extern int SSL_read(SSL *, void *, int);
+extern int SSL_write(SSL *, const void *, int);
+extern int SSL_get_error(const SSL *, int);
+extern int SSL_set_fd(SSL *, int);
+extern SSL *SSL_new(SSL_CTX *);
+extern SSL_CTX *SSL_CTX_new(SSL_METHOD *);
+extern SSL_METHOD *SSLv23_server_method(void);
+extern SSL_METHOD *SSLv23_client_method(void);
+extern int SSL_library_init(void);
+extern void SSL_load_error_strings(void);
+extern int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
+extern int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
+extern int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
+extern void SSL_CTX_set_default_passwd_cb(SSL_CTX *, mg_callback_t);
+extern void SSL_CTX_free(SSL_CTX *);
+extern unsigned long ERR_get_error(void);
+extern char *ERR_error_string(unsigned long, char *);
+extern int CRYPTO_num_locks(void);
+extern void CRYPTO_set_locking_callback(void (*)(int, int, const char *, int));
+extern void CRYPTO_set_id_callback(unsigned long (*)(void));
+#else
+// Dynamically loaded SSL functionality
+struct ssl_func {
+ const char *name; // SSL function name
+ void (*ptr)(void); // Function pointer
+};
+
+#define SSL_free (* (void (*)(SSL *)) ssl_sw[0].ptr)
+#define SSL_accept (* (int (*)(SSL *)) ssl_sw[1].ptr)
+#define SSL_connect (* (int (*)(SSL *)) ssl_sw[2].ptr)
+#define SSL_read (* (int (*)(SSL *, void *, int)) ssl_sw[3].ptr)
+#define SSL_write (* (int (*)(SSL *, const void *,int)) ssl_sw[4].ptr)
+#define SSL_get_error (* (int (*)(SSL *, int)) ssl_sw[5].ptr)
+#define SSL_set_fd (* (int (*)(SSL *, SOCKET)) ssl_sw[6].ptr)
+#define SSL_new (* (SSL * (*)(SSL_CTX *)) ssl_sw[7].ptr)
+#define SSL_CTX_new (* (SSL_CTX * (*)(SSL_METHOD *)) ssl_sw[8].ptr)
+#define SSLv23_server_method (* (SSL_METHOD * (*)(void)) ssl_sw[9].ptr)
+#define SSL_library_init (* (int (*)(void)) ssl_sw[10].ptr)
+#define SSL_CTX_use_PrivateKey_file (* (int (*)(SSL_CTX *, \
+ const char *, int)) ssl_sw[11].ptr)
+#define SSL_CTX_use_certificate_file (* (int (*)(SSL_CTX *, \
+ const char *, int)) ssl_sw[12].ptr)
+#define SSL_CTX_set_default_passwd_cb \
+ (* (void (*)(SSL_CTX *, mg_callback_t)) ssl_sw[13].ptr)
+#define SSL_CTX_free (* (void (*)(SSL_CTX *)) ssl_sw[14].ptr)
+#define SSL_load_error_strings (* (void (*)(void)) ssl_sw[15].ptr)
+#define SSL_CTX_use_certificate_chain_file \
+ (* (int (*)(SSL_CTX *, const char *)) ssl_sw[16].ptr)
+#define SSLv23_client_method (* (SSL_METHOD * (*)(void)) ssl_sw[17].ptr)
+
+#define CRYPTO_num_locks (* (int (*)(void)) crypto_sw[0].ptr)
+#define CRYPTO_set_locking_callback \
+ (* (void (*)(void (*)(int, int, const char *, int))) crypto_sw[1].ptr)
+#define CRYPTO_set_id_callback \
+ (* (void (*)(unsigned long (*)(void))) crypto_sw[2].ptr)
+#define ERR_get_error (* (unsigned long (*)(void)) crypto_sw[3].ptr)
+#define ERR_error_string (* (char * (*)(unsigned long,char *)) crypto_sw[4].ptr)
+
+// set_ssl_option() function updates this array.
+// It loads SSL library dynamically and changes NULLs to the actual addresses
+// of respective functions. The macros above (like SSL_connect()) are really
+// just calling these functions indirectly via the pointer.
+static struct ssl_func ssl_sw[] = {
+ {"SSL_free", NULL},
+ {"SSL_accept", NULL},
+ {"SSL_connect", NULL},
+ {"SSL_read", NULL},
+ {"SSL_write", NULL},
+ {"SSL_get_error", NULL},
+ {"SSL_set_fd", NULL},
+ {"SSL_new", NULL},
+ {"SSL_CTX_new", NULL},
+ {"SSLv23_server_method", NULL},
+ {"SSL_library_init", NULL},
+ {"SSL_CTX_use_PrivateKey_file", NULL},
+ {"SSL_CTX_use_certificate_file",NULL},
+ {"SSL_CTX_set_default_passwd_cb",NULL},
+ {"SSL_CTX_free", NULL},
+ {"SSL_load_error_strings", NULL},
+ {"SSL_CTX_use_certificate_chain_file", NULL},
+ {"SSLv23_client_method", NULL},
+ {NULL, NULL}
+};
+
+// Similar array as ssl_sw. These functions could be located in different lib.
+#if !defined(NO_SSL)
+static struct ssl_func crypto_sw[] = {
+ {"CRYPTO_num_locks", NULL},
+ {"CRYPTO_set_locking_callback", NULL},
+ {"CRYPTO_set_id_callback", NULL},
+ {"ERR_get_error", NULL},
+ {"ERR_error_string", NULL},
+ {NULL, NULL}
+};
+#endif // NO_SSL
+#endif // NO_SSL_DL
+
+static const char *month_names[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+// Unified socket address. For IPv6 support, add IPv6 address structure
+// in the union u.
+union usa {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#if defined(USE_IPV6)
+ struct sockaddr_in6 sin6;
+#endif
+};
+
+// Describes a string (chunk of memory).
+struct vec {
+ const char *ptr;
+ size_t len;
+};
+
+// Structure used by mg_stat() function. Uses 64 bit file length.
+struct mgstat {
+ int is_directory; // Directory marker
+ int64_t size; // File size
+ time_t mtime; // Modification time
+};
+
+// Describes listening socket, or socket which was accept()-ed by the master
+// thread and queued for future handling by the worker thread.
+struct socket {
+ struct socket *next; // Linkage
+ SOCKET sock; // Listening socket
+ union usa lsa; // Local socket address
+ union usa rsa; // Remote socket address
+ int is_ssl; // Is socket SSL-ed
+};
+
+// NOTE(lsm): this enum shoulds be in sync with the config_options below.
+enum {
+ CGI_EXTENSIONS, CGI_ENVIRONMENT, PUT_DELETE_PASSWORDS_FILE, CGI_INTERPRETER,
+ PROTECT_URI, AUTHENTICATION_DOMAIN, SSI_EXTENSIONS, THROTTLE,
+ ACCESS_LOG_FILE, ENABLE_DIRECTORY_LISTING, ERROR_LOG_FILE,
+ GLOBAL_PASSWORDS_FILE, INDEX_FILES, ENABLE_KEEP_ALIVE, ACCESS_CONTROL_LIST,
+ EXTRA_MIME_TYPES, LISTENING_PORTS, DOCUMENT_ROOT, SSL_CERTIFICATE,
+ NUM_THREADS, RUN_AS_USER, REWRITE, HIDE_FILES,
+ NUM_OPTIONS
+};
+
+static const char *config_options[] = {
+ "C", "cgi_pattern", "**.cgi$|**.pl$|**.php$",
+ "E", "cgi_environment", NULL,
+ "G", "put_delete_passwords_file", NULL,
+ "I", "cgi_interpreter", NULL,
+ "P", "protect_uri", NULL,
+ "R", "authentication_domain", "mydomain.com",
+ "S", "ssi_pattern", "**.shtml$|**.shtm$",
+ "T", "throttle", NULL,
+ "a", "access_log_file", NULL,
+ "d", "enable_directory_listing", "yes",
+ "e", "error_log_file", NULL,
+ "g", "global_passwords_file", NULL,
+ "i", "index_files", "index.html,index.htm,index.cgi,index.shtml,index.php",
+ "k", "enable_keep_alive", "no",
+ "l", "access_control_list", NULL,
+ "m", "extra_mime_types", NULL,
+ "p", "listening_ports", "8080",
+ "r", "document_root", ".",
+ "s", "ssl_certificate", NULL,
+ "t", "num_threads", "20",
+ "u", "run_as_user", NULL,
+ "w", "url_rewrite_patterns", NULL,
+ "x", "hide_files_patterns", NULL,
+ NULL
+};
+#define ENTRIES_PER_CONFIG_OPTION 3
+
+struct mg_context {
+ volatile int stop_flag; // Should we stop event loop
+ SSL_CTX *ssl_ctx; // SSL context
+ SSL_CTX *client_ssl_ctx; // Client SSL context
+ char *config[NUM_OPTIONS]; // Mongoose configuration parameters
+ mg_callback_t user_callback; // User-defined callback function
+ void *user_data; // User-defined data
+
+ struct socket *listening_sockets;
+
+ volatile int num_threads; // Number of threads
+ pthread_mutex_t mutex; // Protects (max|num)_threads
+ pthread_cond_t cond; // Condvar for tracking workers terminations
+
+ struct socket queue[20]; // Accepted sockets
+ volatile int sq_head; // Head of the socket queue
+ volatile int sq_tail; // Tail of the socket queue
+ pthread_cond_t sq_full; // Signaled when socket is produced
+ pthread_cond_t sq_empty; // Signaled when socket is consumed
+};
+
+struct mg_connection {
+ struct mg_request_info request_info;
+ struct mg_context *ctx;
+ SSL *ssl; // SSL descriptor
+ struct socket client; // Connected client
+ time_t birth_time; // Time when request was received
+ int64_t num_bytes_sent; // Total bytes sent to client
+ int64_t content_len; // Content-Length header value
+ int64_t consumed_content; // How many bytes of content have been read
+ char *buf; // Buffer for received data
+ char *path_info; // PATH_INFO part of the URL
+ char *log_message; // Placeholder for the mongoose error log message
+ int must_close; // 1 if connection must be closed
+ int buf_size; // Buffer size
+ int request_len; // Size of the request + headers in a buffer
+ int data_len; // Total size of data in a buffer
+ int status_code; // HTTP reply status code, e.g. 200
+ int throttle; // Throttling, bytes/sec. <= 0 means no throttle
+ time_t last_throttle_time; // Last time throttled data was sent
+ int64_t last_throttle_bytes;// Bytes sent this second
+};
+
+const char **mg_get_valid_option_names(void) {
+ return config_options;
+}
+
+static void *call_user(struct mg_connection *conn, enum mg_event event) {
+ return conn == NULL || conn->ctx == NULL || conn->ctx->user_callback == NULL ?
+ NULL : conn->ctx->user_callback(event, conn);
+}
+
+void *mg_get_user_data(struct mg_connection *conn) {
+ return conn != NULL && conn->ctx != NULL ? conn->ctx->user_data : NULL;
+}
+
+const char *mg_get_log_message(const struct mg_connection *conn) {
+ return conn == NULL ? NULL : conn->log_message;
+}
+
+int mg_get_reply_status_code(const struct mg_connection *conn) {
+ return conn == NULL ? -1 : conn->status_code;
+}
+
+void *mg_get_ssl_context(const struct mg_connection *conn) {
+ return conn == NULL || conn->ctx == NULL ? NULL : conn->ctx->ssl_ctx;
+}
+
+static int get_option_index(const char *name) {
+ int i;
+
+ for (i = 0; config_options[i] != NULL; i += ENTRIES_PER_CONFIG_OPTION) {
+ if (strcmp(config_options[i], name) == 0 ||
+ strcmp(config_options[i + 1], name) == 0) {
+ return i / ENTRIES_PER_CONFIG_OPTION;
+ }
+ }
+ return -1;
+}
+
+const char *mg_get_option(const struct mg_context *ctx, const char *name) {
+ int i;
+ if ((i = get_option_index(name)) == -1) {
+ return NULL;
+ } else if (ctx->config[i] == NULL) {
+ return "";
+ } else {
+ return ctx->config[i];
+ }
+}
+
+static void sockaddr_to_string(char *buf, size_t len,
+ const union usa *usa) {
+ buf[0] = '\0';
+#if defined(USE_IPV6)
+ inet_ntop(usa->sa.sa_family, usa->sa.sa_family == AF_INET ?
+ (void *) &usa->sin.sin_addr :
+ (void *) &usa->sin6.sin6_addr, buf, len);
+#elif defined(_WIN32)
+ // Only Windoze Vista (and newer) have inet_ntop()
+ strncpy(buf, inet_ntoa(usa->sin.sin_addr), len);
+#else
+ inet_ntop(usa->sa.sa_family, (void *) &usa->sin.sin_addr, buf, len);
+#endif
+}
+
+static void cry(struct mg_connection *conn,
+ PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
+
+// Print error message to the opened error log stream.
+static void cry(struct mg_connection *conn, const char *fmt, ...) {
+ char buf[MG_BUF_LEN], src_addr[20];
+ va_list ap;
+ FILE *fp;
+ time_t timestamp;
+
+ va_start(ap, fmt);
+ (void) vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ // Do not lock when getting the callback value, here and below.
+ // I suppose this is fine, since function cannot disappear in the
+ // same way string option can.
+ conn->log_message = buf;
+ if (call_user(conn, MG_EVENT_LOG) == NULL) {
+ fp = conn->ctx == NULL || conn->ctx->config[ERROR_LOG_FILE] == NULL ? NULL :
+ mg_fopen(conn->ctx->config[ERROR_LOG_FILE], "a+");
+
+ if (fp != NULL) {
+ flockfile(fp);
+ timestamp = time(NULL);
+
+ sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+ fprintf(fp, "[%010lu] [error] [client %s] ", (unsigned long) timestamp,
+ src_addr);
+
+ if (conn->request_info.request_method != NULL) {
+ fprintf(fp, "%s %s: ", conn->request_info.request_method,
+ conn->request_info.uri);
+ }
+
+ (void) fprintf(fp, "%s", buf);
+ fputc('\n', fp);
+ funlockfile(fp);
+ if (fp != stderr) {
+ fclose(fp);
+ }
+ }
+ }
+ conn->log_message = NULL;
+}
+
+// Return fake connection structure. Used for logging, if connection
+// is not applicable at the moment of logging.
+static struct mg_connection *fc(struct mg_context *ctx) {
+ static struct mg_connection fake_connection;
+ fake_connection.ctx = ctx;
+ return &fake_connection;
+}
+
+const char *mg_version(void) {
+ return MONGOOSE_VERSION;
+}
+
+const struct mg_request_info *
+mg_get_request_info(const struct mg_connection *conn) {
+ return &conn->request_info;
+}
+
+static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
+ for (; *src != '\0' && n > 1; n--) {
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+}
+
+static int lowercase(const char *s) {
+ return tolower(* (const unsigned char *) s);
+}
+
+static int mg_strncasecmp(const char *s1, const char *s2, size_t len) {
+ int diff = 0;
+
+ if (len > 0)
+ do {
+ diff = lowercase(s1++) - lowercase(s2++);
+ } while (diff == 0 && s1[-1] != '\0' && --len > 0);
+
+ return diff;
+}
+
+static int mg_strcasecmp(const char *s1, const char *s2) {
+ int diff;
+
+ do {
+ diff = lowercase(s1++) - lowercase(s2++);
+ } while (diff == 0 && s1[-1] != '\0');
+
+ return diff;
+}
+
+static char * mg_strndup(const char *ptr, size_t len) {
+ char *p;
+
+ if ((p = (char *) malloc(len + 1)) != NULL) {
+ mg_strlcpy(p, ptr, len + 1);
+ }
+
+ return p;
+}
+
+static char * mg_strdup(const char *str) {
+ return mg_strndup(str, strlen(str));
+}
+
+// Like snprintf(), but never returns negative value, or a value
+// that is larger than a supplied buffer.
+// Thanks to Adam Zeldis to pointing snprintf()-caused vulnerability
+// in his audit report.
+static int mg_vsnprintf(struct mg_connection *conn, char *buf, size_t buflen,
+ const char *fmt, va_list ap) {
+ int n;
+
+ if (buflen == 0)
+ return 0;
+
+ n = vsnprintf(buf, buflen, fmt, ap);
+
+ if (n < 0) {
+ cry(conn, "vsnprintf error");
+ n = 0;
+ } else if (n >= (int) buflen) {
+ cry(conn, "truncating vsnprintf buffer: [%.*s]",
+ n > 200 ? 200 : n, buf);
+ n = (int) buflen - 1;
+ }
+ buf[n] = '\0';
+
+ return n;
+}
+
+static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
+ PRINTF_FORMAT_STRING(const char *fmt), ...)
+ PRINTF_ARGS(4, 5);
+
+static int mg_snprintf(struct mg_connection *conn, char *buf, size_t buflen,
+ const char *fmt, ...) {
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = mg_vsnprintf(conn, buf, buflen, fmt, ap);
+ va_end(ap);
+
+ return n;
+}
+
+// Skip the characters until one of the delimiters characters found.
+// 0-terminate resulting word. Skip the delimiter and following whitespaces if any.
+// Advance pointer to buffer to the next word. Return found 0-terminated word.
+// Delimiters can be quoted with quotechar.
+static char *skip_quoted(char **buf, const char *delimiters,
+ const char *whitespace, char quotechar) {
+ char *p, *begin_word, *end_word, *end_whitespace;
+
+ begin_word = *buf;
+ end_word = begin_word + strcspn(begin_word, delimiters);
+
+ // Check for quotechar
+ if (end_word > begin_word) {
+ p = end_word - 1;
+ while (*p == quotechar) {
+ // If there is anything beyond end_word, copy it
+ if (*end_word == '\0') {
+ *p = '\0';
+ break;
+ } else {
+ size_t end_off = strcspn(end_word + 1, delimiters);
+ memmove (p, end_word, end_off + 1);
+ p += end_off; // p must correspond to end_word - 1
+ end_word += end_off + 1;
+ }
+ }
+ for (p++; p < end_word; p++) {
+ *p = '\0';
+ }
+ }
+
+ if (*end_word == '\0') {
+ *buf = end_word;
+ } else {
+ end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
+
+ for (p = end_word; p < end_whitespace; p++) {
+ *p = '\0';
+ }
+
+ *buf = end_whitespace;
+ }
+
+ return begin_word;
+}
+
+// Simplified version of skip_quoted without quote char
+// and whitespace == delimiters
+static char *skip(char **buf, const char *delimiters) {
+ return skip_quoted(buf, delimiters, delimiters, 0);
+}
+
+
+// Return HTTP header value, or NULL if not found.
+static const char *get_header(const struct mg_request_info *ri,
+ const char *name) {
+ int i;
+
+ for (i = 0; i < ri->num_headers; i++)
+ if (!mg_strcasecmp(name, ri->http_headers[i].name))
+ return ri->http_headers[i].value;
+
+ return NULL;
+}
+
+const char *mg_get_header(const struct mg_connection *conn, const char *name) {
+ return get_header(&conn->request_info, name);
+}
+
+// A helper function for traversing a comma separated list of values.
+// It returns a list pointer shifted to the next value, or NULL if the end
+// of the list found.
+// Value is stored in val vector. If value has form "x=y", then eq_val
+// vector is initialized to point to the "y" part, and val vector length
+// is adjusted to point only to "x".
+static const char *next_option(const char *list, struct vec *val,
+ struct vec *eq_val) {
+ if (list == NULL || *list == '\0') {
+ // End of the list
+ list = NULL;
+ } else {
+ val->ptr = list;
+ if ((list = strchr(val->ptr, ',')) != NULL) {
+ // Comma found. Store length and shift the list ptr
+ val->len = list - val->ptr;
+ list++;
+ } else {
+ // This value is the last one
+ list = val->ptr + strlen(val->ptr);
+ val->len = list - val->ptr;
+ }
+
+ if (eq_val != NULL) {
+ // Value has form "x=y", adjust pointers and lengths
+ // so that val points to "x", and eq_val points to "y".
+ eq_val->len = 0;
+ eq_val->ptr = (const char *) memchr(val->ptr, '=', val->len);
+ if (eq_val->ptr != NULL) {
+ eq_val->ptr++; // Skip over '=' character
+ eq_val->len = val->ptr + val->len - eq_val->ptr;
+ val->len = (eq_val->ptr - val->ptr) - 1;
+ }
+ }
+ }
+
+ return list;
+}
+
+static int match_prefix(const char *pattern, int pattern_len, const char *str) {
+ const char *or_str;
+ int i, j, len, res;
+
+ if ((or_str = (const char *) memchr(pattern, '|', pattern_len)) != NULL) {
+ res = match_prefix(pattern, or_str - pattern, str);
+ return res > 0 ? res :
+ match_prefix(or_str + 1, (pattern + pattern_len) - (or_str + 1), str);
+ }
+
+ i = j = 0;
+ res = -1;
+ for (; i < pattern_len; i++, j++) {
+ if (pattern[i] == '?' && str[j] != '\0') {
+ continue;
+ } else if (pattern[i] == '$') {
+ return str[j] == '\0' ? j : -1;
+ } else if (pattern[i] == '*') {
+ i++;
+ if (pattern[i] == '*') {
+ i++;
+ len = (int) strlen(str + j);
+ } else {
+ len = (int) strcspn(str + j, "/");
+ }
+ if (i == pattern_len) {
+ return j + len;
+ }
+ do {
+ res = match_prefix(pattern + i, pattern_len - i, str + j + len);
+ } while (res == -1 && len-- > 0);
+ return res == -1 ? -1 : j + res + len;
+ } else if (pattern[i] != str[j]) {
+ return -1;
+ }
+ }
+ return j;
+}
+
+// HTTP 1.1 assumes keep alive if "Connection:" header is not set
+// This function must tolerate situations when connection info is not
+// set up, for example if request parsing failed.
+static int should_keep_alive(const struct mg_connection *conn) {
+ const char *http_version = conn->request_info.http_version;
+ const char *header = mg_get_header(conn, "Connection");
+ if (conn->must_close ||
+ conn->status_code == 401 ||
+ mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0 ||
+ (header != NULL && mg_strcasecmp(header, "keep-alive") != 0) ||
+ (header == NULL && http_version && strcmp(http_version, "1.1"))) {
+ return 0;
+ }
+ return 1;
+}
+
+static const char *suggest_connection_header(const struct mg_connection *conn) {
+ return should_keep_alive(conn) ? "keep-alive" : "close";
+}
+
+static void send_http_error(struct mg_connection *, int, const char *,
+ PRINTF_FORMAT_STRING(const char *fmt), ...)
+ PRINTF_ARGS(4, 5);
+
+
+static void send_http_error(struct mg_connection *conn, int status,
+ const char *reason, const char *fmt, ...) {
+ char buf[MG_BUF_LEN];
+ va_list ap;
+ int len;
+
+ conn->status_code = status;
+ if (call_user(conn, MG_HTTP_ERROR) == NULL) {
+ buf[0] = '\0';
+ len = 0;
+
+ // Errors 1xx, 204 and 304 MUST NOT send a body
+ if (status > 199 && status != 204 && status != 304) {
+ len = mg_snprintf(conn, buf, sizeof(buf), "Error %d: %s", status, reason);
+ buf[len++] = '\n';
+
+ va_start(ap, fmt);
+ len += mg_vsnprintf(conn, buf + len, sizeof(buf) - len, fmt, ap);
+ va_end(ap);
+ }
+ DEBUG_TRACE(("[%s]", buf));
+
+ mg_printf(conn, "HTTP/1.1 %d %s\r\n"
+ "Content-Length: %d\r\n"
+ "Connection: %s\r\n\r\n", status, reason, len,
+ suggest_connection_header(conn));
+ conn->num_bytes_sent += mg_printf(conn, "%s", buf);
+ }
+}
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+static int pthread_mutex_init(pthread_mutex_t *mutex, void *unused) {
+ unused = NULL;
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ return *mutex == NULL ? -1 : 0;
+}
+
+static int pthread_mutex_destroy(pthread_mutex_t *mutex) {
+ return CloseHandle(*mutex) == 0 ? -1 : 0;
+}
+
+static int pthread_mutex_lock(pthread_mutex_t *mutex) {
+ return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
+}
+
+static int pthread_mutex_unlock(pthread_mutex_t *mutex) {
+ return ReleaseMutex(*mutex) == 0 ? -1 : 0;
+}
+
+static int pthread_cond_init(pthread_cond_t *cv, const void *unused) {
+ unused = NULL;
+ cv->signal = CreateEvent(NULL, FALSE, FALSE, NULL);
+ cv->broadcast = CreateEvent(NULL, TRUE, FALSE, NULL);
+ return cv->signal != NULL && cv->broadcast != NULL ? 0 : -1;
+}
+
+static int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex) {
+ HANDLE handles[] = {cv->signal, cv->broadcast};
+ ReleaseMutex(*mutex);
+ WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+ return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0? 0 : -1;
+}
+
+static int pthread_cond_signal(pthread_cond_t *cv) {
+ return SetEvent(cv->signal) == 0 ? -1 : 0;
+}
+
+static int pthread_cond_broadcast(pthread_cond_t *cv) {
+ // Implementation with PulseEvent() has race condition, see
+ // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ return PulseEvent(cv->broadcast) == 0 ? -1 : 0;
+}
+
+static int pthread_cond_destroy(pthread_cond_t *cv) {
+ return CloseHandle(cv->signal) && CloseHandle(cv->broadcast) ? 0 : -1;
+}
+
+// For Windows, change all slashes to backslashes in path names.
+static void change_slashes_to_backslashes(char *path) {
+ int i;
+
+ for (i = 0; path[i] != '\0'; i++) {
+ if (path[i] == '/')
+ path[i] = '\\';
+ // i > 0 check is to preserve UNC paths, like \\server\file.txt
+ if (path[i] == '\\' && i > 0)
+ while (path[i + 1] == '\\' || path[i + 1] == '/')
+ (void) memmove(path + i + 1,
+ path + i + 2, strlen(path + i + 1));
+ }
+}
+
+// Encode 'path' which is assumed UTF-8 string, into UNICODE string.
+// wbuf and wbuf_len is a target buffer and its length.
+static void to_unicode(const char *path, wchar_t *wbuf, size_t wbuf_len) {
+ char buf[PATH_MAX], buf2[PATH_MAX], *p;
+
+ mg_strlcpy(buf, path, sizeof(buf));
+ change_slashes_to_backslashes(buf);
+
+ // Point p to the end of the file name
+ p = buf + strlen(buf) - 1;
+
+ // Trim trailing backslash character
+ while (p > buf && *p == '\\' && p[-1] != ':') {
+ *p-- = '\0';
+ }
+
+ // Protect from CGI code disclosure.
+ // This is very nasty hole. Windows happily opens files with
+ // some garbage in the end of file name. So fopen("a.cgi ", "r")
+ // actually opens "a.cgi", and does not return an error!
+ if (*p == 0x20 || // No space at the end
+ (*p == 0x2e && p > buf) || // No '.' but allow '.' as full path
+ *p == 0x2b || // No '+'
+ (*p & ~0x7f)) { // And generally no non-ASCII chars
+ (void) fprintf(stderr, "Rejecting suspicious path: [%s]", buf);
+ wbuf[0] = L'\0';
+ } else {
+ // Convert to Unicode and back. If doubly-converted string does not
+ // match the original, something is fishy, reject.
+ memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int) wbuf_len);
+ WideCharToMultiByte(CP_UTF8, 0, wbuf, (int) wbuf_len, buf2, sizeof(buf2),
+ NULL, NULL);
+ if (strcmp(buf, buf2) != 0) {
+ wbuf[0] = L'\0';
+ }
+ }
+}
+
+#if defined(_WIN32_WCE)
+static time_t time(time_t *ptime) {
+ time_t t;
+ SYSTEMTIME st;
+ FILETIME ft;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+ t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
+
+ if (ptime != NULL) {
+ *ptime = t;
+ }
+
+ return t;
+}
+
+static struct tm *localtime(const time_t *ptime, struct tm *ptm) {
+ int64_t t = ((int64_t) *ptime) * RATE_DIFF + EPOCH_DIFF;
+ FILETIME ft, lft;
+ SYSTEMTIME st;
+ TIME_ZONE_INFORMATION tzinfo;
+
+ if (ptm == NULL) {
+ return NULL;
+ }
+
+ * (int64_t *) &ft = t;
+ FileTimeToLocalFileTime(&ft, &lft);
+ FileTimeToSystemTime(&lft, &st);
+ ptm->tm_year = st.wYear - 1900;
+ ptm->tm_mon = st.wMonth - 1;
+ ptm->tm_wday = st.wDayOfWeek;
+ ptm->tm_mday = st.wDay;
+ ptm->tm_hour = st.wHour;
+ ptm->tm_min = st.wMinute;
+ ptm->tm_sec = st.wSecond;
+ ptm->tm_yday = 0; // hope nobody uses this
+ ptm->tm_isdst =
+ GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
+
+ return ptm;
+}
+
+static struct tm *gmtime(const time_t *ptime, struct tm *ptm) {
+ // FIXME(lsm): fix this.
+ return localtime(ptime, ptm);
+}
+
+static size_t strftime(char *dst, size_t dst_size, const char *fmt,
+ const struct tm *tm) {
+ (void) snprintf(dst, dst_size, "implement strftime() for WinCE");
+ return 0;
+}
+#endif
+
+static int mg_rename(const char* oldname, const char* newname) {
+ wchar_t woldbuf[PATH_MAX];
+ wchar_t wnewbuf[PATH_MAX];
+
+ to_unicode(oldname, woldbuf, ARRAY_SIZE(woldbuf));
+ to_unicode(newname, wnewbuf, ARRAY_SIZE(wnewbuf));
+
+ return MoveFileW(woldbuf, wnewbuf) ? 0 : -1;
+}
+
+
+static FILE *mg_fopen(const char *path, const char *mode) {
+ wchar_t wbuf[PATH_MAX], wmode[20];
+
+ to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
+ MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
+
+ return _wfopen(wbuf, wmode);
+}
+
+static int mg_stat(const char *path, struct mgstat *stp) {
+ int ok = -1; // Error
+ wchar_t wbuf[PATH_MAX];
+ WIN32_FILE_ATTRIBUTE_DATA info;
+
+ to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
+
+ if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
+ stp->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
+ stp->mtime = SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
+ info.ftLastWriteTime.dwHighDateTime);
+ stp->is_directory =
+ info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ ok = 0; // Success
+ }
+
+ return ok;
+}
+
+static int mg_remove(const char *path) {
+ wchar_t wbuf[PATH_MAX];
+ to_unicode(path, wbuf, ARRAY_SIZE(wbuf));
+ return DeleteFileW(wbuf) ? 0 : -1;
+}
+
+static int mg_mkdir(const char *path, int mode) {
+ char buf[PATH_MAX];
+ wchar_t wbuf[PATH_MAX];
+
+ mode = 0; // Unused
+ mg_strlcpy(buf, path, sizeof(buf));
+ change_slashes_to_backslashes(buf);
+
+ (void) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, sizeof(wbuf));
+
+ return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
+}
+
+// Implementation of POSIX opendir/closedir/readdir for Windows.
+static DIR * opendir(const char *name) {
+ DIR *dir = NULL;
+ wchar_t wpath[PATH_MAX];
+ DWORD attrs;
+
+ if (name == NULL) {
+ SetLastError(ERROR_BAD_ARGUMENTS);
+ } else if ((dir = (DIR *) malloc(sizeof(*dir))) == NULL) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ } else {
+ to_unicode(name, wpath, ARRAY_SIZE(wpath));
+ attrs = GetFileAttributesW(wpath);
+ if (attrs != 0xFFFFFFFF &&
+ ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)) {
+ (void) wcscat(wpath, L"\\*");
+ dir->handle = FindFirstFileW(wpath, &dir->info);
+ dir->result.d_name[0] = '\0';
+ } else {
+ free(dir);
+ dir = NULL;
+ }
+ }
+
+ return dir;
+}
+
+static int closedir(DIR *dir) {
+ int result = 0;
+
+ if (dir != NULL) {
+ if (dir->handle != INVALID_HANDLE_VALUE)
+ result = FindClose(dir->handle) ? 0 : -1;
+
+ free(dir);
+ } else {
+ result = -1;
+ SetLastError(ERROR_BAD_ARGUMENTS);
+ }
+
+ return result;
+}
+
+static struct dirent *readdir(DIR *dir) {
+ struct dirent *result = 0;
+
+ if (dir) {
+ if (dir->handle != INVALID_HANDLE_VALUE) {
+ result = &dir->result;
+ (void) WideCharToMultiByte(CP_UTF8, 0,
+ dir->info.cFileName, -1, result->d_name,
+ sizeof(result->d_name), NULL, NULL);
+
+ if (!FindNextFileW(dir->handle, &dir->info)) {
+ (void) FindClose(dir->handle);
+ dir->handle = INVALID_HANDLE_VALUE;
+ }
+
+ } else {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+ } else {
+ SetLastError(ERROR_BAD_ARGUMENTS);
+ }
+
+ return result;
+}
+
+#define set_close_on_exec(fd) // No FD_CLOEXEC on Windows
+
+int mg_start_thread(mg_thread_func_t f, void *p) {
+ return _beginthread((void (__cdecl *)(void *)) f, 0, p) == -1L ? -1 : 0;
+}
+
+static HANDLE dlopen(const char *dll_name, int flags) {
+ wchar_t wbuf[PATH_MAX];
+ flags = 0; // Unused
+ to_unicode(dll_name, wbuf, ARRAY_SIZE(wbuf));
+ return LoadLibraryW(wbuf);
+}
+
+#if !defined(NO_CGI)
+#define SIGKILL 0
+static int kill(pid_t pid, int sig_num) {
+ (void) TerminateProcess(pid, sig_num);
+ (void) CloseHandle(pid);
+ return 0;
+}
+
+static pid_t spawn_process(struct mg_connection *conn, const char *prog,
+ char *envblk, char *envp[], int fd_stdin,
+ int fd_stdout, const char *dir) {
+ HANDLE me;
+ char *p, *interp, full_interp[PATH_MAX], cmdline[PATH_MAX], buf[PATH_MAX];
+ FILE *fp;
+ STARTUPINFOA si = { sizeof(si) };
+ PROCESS_INFORMATION pi = { 0 };
+
+ envp = NULL; // Unused
+
+ // TODO(lsm): redirect CGI errors to the error log file
+ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ me = GetCurrentProcess();
+ DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdin), me,
+ &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS);
+ DuplicateHandle(me, (HANDLE) _get_osfhandle(fd_stdout), me,
+ &si.hStdOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);
+
+ // If CGI file is a script, try to read the interpreter line
+ interp = conn->ctx->config[CGI_INTERPRETER];
+ if (interp == NULL) {
+ buf[0] = buf[2] = '\0';
+
+ // Read the first line of the script into the buffer
+ snprintf(cmdline, sizeof(cmdline), "%s%c%s", dir, '/', prog);
+ if ((fp = mg_fopen(cmdline, "r")) != NULL) {
+ fgets(buf, sizeof(buf), fp);
+ fclose(fp);
+ buf[sizeof(buf) - 1] = '\0';
+ }
+
+ if (buf[0] == '#' && buf[1] == '!') {
+ // Trim whitespace in interpreter name
+ for (p = buf + 2; *p != '\0' && isspace(* (unsigned char *) p); )
+ p++;
+ *p = '\0';
+ }
+ interp = buf + 2;
+ }
+
+ if (interp[0] != '\0') {
+ GetFullPathName(interp, sizeof(full_interp), full_interp, NULL);
+ interp = full_interp;
+ }
+
+ mg_snprintf(conn, cmdline, sizeof(cmdline), "%s%s%s",
+ interp, interp[0] == '\0' ? "" : " ", prog);
+
+ DEBUG_TRACE(("Running [%s]", cmdline));
+ if (CreateProcessA(NULL, cmdline, NULL, NULL, TRUE,
+ CREATE_NEW_PROCESS_GROUP, envblk, dir, &si, &pi) == 0) {
+ cry(conn, "%s: CreateProcess(%s): %d",
+ __func__, cmdline, ERRNO);
+ pi.hProcess = (pid_t) -1;
+ }
+
+ // Always close these to prevent handle leakage.
+ (void) close(fd_stdin);
+ (void) close(fd_stdout);
+
+ (void) CloseHandle(si.hStdOutput);
+ (void) CloseHandle(si.hStdInput);
+ (void) CloseHandle(pi.hThread);
+
+ return (pid_t) pi.hProcess;
+}
+#endif // !NO_CGI
+
+static int set_non_blocking_mode(SOCKET sock) {
+ unsigned long on = 1;
+ return ioctlsocket(sock, FIONBIO, &on);
+}
+
+#else
+static int mg_stat(const char *path, struct mgstat *stp) {
+ struct stat st;
+ int ok;
+
+ if (stat(path, &st) == 0) {
+ ok = 0;
+ stp->size = st.st_size;
+ stp->mtime = st.st_mtime;
+ stp->is_directory = S_ISDIR(st.st_mode);
+ } else {
+ ok = -1;
+ }
+
+ return ok;
+}
+
+static void set_close_on_exec(int fd) {
+ (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+}
+
+int mg_start_thread(mg_thread_func_t func, void *param) {
+ pthread_t thread_id;
+ pthread_attr_t attr;
+
+ (void) pthread_attr_init(&attr);
+ (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ // TODO(lsm): figure out why mongoose dies on Linux if next line is enabled
+ // (void) pthread_attr_setstacksize(&attr, sizeof(struct mg_connection) * 5);
+
+ return pthread_create(&thread_id, &attr, func, param);
+}
+
+#ifndef NO_CGI
+static pid_t spawn_process(struct mg_connection *conn, const char *prog,
+ char *envblk, char *envp[], int fd_stdin,
+ int fd_stdout, const char *dir) {
+ pid_t pid;
+ const char *interp;
+
+ envblk = NULL; // Unused
+
+ if ((pid = fork()) == -1) {
+ // Parent
+ send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO));
+ } else if (pid == 0) {
+ // Child
+ if (chdir(dir) != 0) {
+ cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
+ } else if (dup2(fd_stdin, 0) == -1) {
+ cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO));
+ } else if (dup2(fd_stdout, 1) == -1) {
+ cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO));
+ } else {
+ (void) dup2(fd_stdout, 2);
+ (void) close(fd_stdin);
+ (void) close(fd_stdout);
+
+ interp = conn->ctx->config[CGI_INTERPRETER];
+ if (interp == NULL) {
+ (void) execle(prog, prog, NULL, envp);
+ cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO));
+ } else {
+ (void) execle(interp, interp, prog, NULL, envp);
+ cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog,
+ strerror(ERRNO));
+ }
+ }
+ exit(EXIT_FAILURE);
+ }
+
+ // Parent. Close stdio descriptors
+ (void) close(fd_stdin);
+ (void) close(fd_stdout);
+
+ return pid;
+}
+#endif // !NO_CGI
+
+static int set_non_blocking_mode(SOCKET sock) {
+ int flags;
+
+ flags = fcntl(sock, F_GETFL, 0);
+ (void) fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+
+ return 0;
+}
+#endif // _WIN32
+
+// Write data to the IO channel - opened file descriptor, socket or SSL
+// descriptor. Return number of bytes written.
+static int64_t push(FILE *fp, SOCKET sock, SSL *ssl, const char *buf,
+ int64_t len) {
+ int64_t sent;
+ int n, k;
+
+ sent = 0;
+ while (sent < len) {
+
+ // How many bytes we send in this iteration
+ k = len - sent > INT_MAX ? INT_MAX : (int) (len - sent);
+
+ if (ssl != NULL) {
+ n = SSL_write(ssl, buf + sent, k);
+ } else if (fp != NULL) {
+ n = (int) fwrite(buf + sent, 1, (size_t) k, fp);
+ if (ferror(fp))
+ n = -1;
+ } else {
+ n = send(sock, buf + sent, (size_t) k, MSG_NOSIGNAL);
+ }
+
+ if (n < 0)
+ break;
+
+ sent += n;
+ }
+
+ return sent;
+}
+
+// This function is needed to prevent Mongoose to be stuck in a blocking
+// socket read when user requested exit. To do that, we sleep in select
+// with a timeout, and when returned, check the context for the stop flag.
+// If it is set, we return 0, and this means that we must not continue
+// reading, must give up and close the connection and exit serving thread.
+static int wait_until_socket_is_readable(struct mg_connection *conn) {
+ int result;
+ struct timeval tv;
+ fd_set set;
+
+ do {
+ tv.tv_sec = 0;
+ tv.tv_usec = 300 * 1000;
+ FD_ZERO(&set);
+ FD_SET(conn->client.sock, &set);
+ result = select(conn->client.sock + 1, &set, NULL, NULL, &tv);
+ } while ((result == 0 || (result < 0 && ERRNO == EINTR)) &&
+ conn->ctx->stop_flag == 0);
+
+ return conn->ctx->stop_flag || result < 0 ? 0 : 1;
+}
+
+// Read from IO channel - opened file descriptor, socket, or SSL descriptor.
+// Return negative value on error, or number of bytes read on success.
+static int pull(FILE *fp, struct mg_connection *conn, char *buf, int len) {
+ int nread;
+
+ if (fp != NULL) {
+ // Use read() instead of fread(), because if we're reading from the CGI
+ // pipe, fread() may block until IO buffer is filled up. We cannot afford
+ // to block and must pass all read bytes immediately to the client.
+ nread = read(fileno(fp), buf, (size_t) len);
+ } else if (!wait_until_socket_is_readable(conn)) {
+ nread = -1;
+ } else if (conn->ssl != NULL) {
+ nread = SSL_read(conn->ssl, buf, len);
+ } else {
+ nread = recv(conn->client.sock, buf, (size_t) len, 0);
+ }
+
+ return conn->ctx->stop_flag ? -1 : nread;
+}
+
+int mg_read(struct mg_connection *conn, void *buf, size_t len) {
+ int n, buffered_len, nread;
+ const char *body;
+
+ nread = 0;
+ if (conn->consumed_content < conn->content_len) {
+ // Adjust number of bytes to read.
+ int64_t to_read = conn->content_len - conn->consumed_content;
+ if (to_read < (int64_t) len) {
+ len = (size_t) to_read;
+ }
+
+ // Return buffered data
+ body = conn->buf + conn->request_len + conn->consumed_content;
+ buffered_len = &conn->buf[conn->data_len] - body;
+ if (buffered_len > 0) {
+ if (len < (size_t) buffered_len) {
+ buffered_len = (int) len;
+ }
+ memcpy(buf, body, (size_t) buffered_len);
+ len -= buffered_len;
+ conn->consumed_content += buffered_len;
+ nread += buffered_len;
+ buf = (char *) buf + buffered_len;
+ }
+
+ // We have returned all buffered data. Read new data from the remote socket.
+ while (len > 0) {
+ n = pull(NULL, conn, (char *) buf, (int) len);
+ if (n < 0) {
+ nread = n; // Propagate the error
+ break;
+ } else if (n == 0) {
+ break; // No more data to read
+ } else {
+ buf = (char *) buf + n;
+ conn->consumed_content += n;
+ nread += n;
+ len -= n;
+ }
+ }
+ }
+ return nread;
+}
+
+int mg_write(struct mg_connection *conn, const void *buf, size_t len) {
+ time_t now;
+ int64_t n, total, allowed;
+
+ if (conn->throttle > 0) {
+ if ((now = time(NULL)) != conn->last_throttle_time) {
+ conn->last_throttle_time = now;
+ conn->last_throttle_bytes = 0;
+ }
+ allowed = conn->throttle - conn->last_throttle_bytes;
+ if (allowed > (int64_t) len) {
+ allowed = len;
+ }
+ if ((total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
+ (int64_t) allowed)) == allowed) {
+ buf = (char *) buf + total;
+ conn->last_throttle_bytes += total;
+ while (total < (int64_t) len && conn->ctx->stop_flag == 0) {
+ allowed = conn->throttle > (int64_t) len - total ?
+ len - total : conn->throttle;
+ if ((n = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
+ (int64_t) allowed)) != allowed) {
+ break;
+ }
+ sleep(1);
+ conn->last_throttle_bytes = allowed;
+ conn->last_throttle_time = time(NULL);
+ buf = (char *) buf + n;
+ total += n;
+ }
+ }
+ } else {
+ total = push(NULL, conn->client.sock, conn->ssl, (const char *) buf,
+ (int64_t) len);
+ }
+ return (int) total;
+}
+
+int mg_printf(struct mg_connection *conn, const char *fmt, ...) {
+ char mem[MG_BUF_LEN], *buf = mem;
+ int len;
+ va_list ap;
+
+ // Print in a local buffer first, hoping that it is large enough to
+ // hold the whole message
+ va_start(ap, fmt);
+ len = vsnprintf(mem, sizeof(mem), fmt, ap);
+ va_end(ap);
+
+ if (len == 0) {
+ // Do nothing. mg_printf(conn, "%s", "") was called.
+ } else if (len < 0) {
+ // vsnprintf() error, give up
+ len = -1;
+ cry(conn, "%s(%s, ...): vsnprintf() error", __func__, fmt);
+ } else if (len > (int) sizeof(mem) && (buf = (char *) malloc(len + 1)) != NULL) {
+ // Local buffer is not large enough, allocate big buffer on heap
+ va_start(ap, fmt);
+ vsnprintf(buf, len + 1, fmt, ap);
+ va_end(ap);
+ len = mg_write(conn, buf, (size_t) len);
+ free(buf);
+ } else if (len > (int) sizeof(mem)) {
+ // Failed to allocate large enough buffer, give up
+ cry(conn, "%s(%s, ...): Can't allocate %d bytes, not printing anything",
+ __func__, fmt, len);
+ len = -1;
+ } else {
+ // Copy to the local buffer succeeded
+ len = mg_write(conn, buf, (size_t) len);
+ }
+
+ return len;
+}
+
+// URL-decode input buffer into destination buffer.
+// 0-terminate the destination buffer. Return the length of decoded data.
+// form-url-encoded data differs from URI encoding in a way that it
+// uses '+' as character for space, see RFC 1866 section 8.2.1
+// http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
+static size_t url_decode(const char *src, size_t src_len, char *dst,
+ size_t dst_len, int is_form_url_encoded) {
+ size_t i, j;
+ int a, b;
+#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
+
+ for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
+ if (src[i] == '%' &&
+ isxdigit(* (const unsigned char *) (src + i + 1)) &&
+ isxdigit(* (const unsigned char *) (src + i + 2))) {
+ a = tolower(* (const unsigned char *) (src + i + 1));
+ b = tolower(* (const unsigned char *) (src + i + 2));
+ dst[j] = (char) ((HEXTOI(a) << 4) | HEXTOI(b));
+ i += 2;
+ } else if (is_form_url_encoded && src[i] == '+') {
+ dst[j] = ' ';
+ } else {
+ dst[j] = src[i];
+ }
+ }
+
+ dst[j] = '\0'; // Null-terminate the destination
+
+ return j;
+}
+
+// Scan given buffer and fetch the value of the given variable.
+// It can be specified in query string, or in the POST data.
+// Return -1 if the variable not found, or length of the URL-decoded value
+// stored in dst. The dst buffer is guaranteed to be NUL-terminated if it
+// is not NULL or zero-length. If dst is NULL or zero-length, then
+// -2 is returned.
+int mg_get_var(const char *buf, size_t buf_len, const char *name,
+ char *dst, size_t dst_len) {
+ const char *p, *e, *s;
+ size_t name_len;
+ int len;
+
+ if (dst == NULL || dst_len == 0) {
+ len = -2;
+ } else if (buf == NULL || name == NULL || buf_len == 0) {
+ len = -1;
+ dst[0] = '\0';
+ } else {
+ name_len = strlen(name);
+ e = buf + buf_len;
+ len = -1;
+ dst[0] = '\0';
+
+ // buf is "var1=val1&var2=val2...". Find variable first
+ for (p = buf; p + name_len < e; p++) {
+ if ((p == buf || p[-1] == '&') && p[name_len] == '=' &&
+ !mg_strncasecmp(name, p, name_len)) {
+
+ // Point p to variable value
+ p += name_len + 1;
+
+ // Point s to the end of the value
+ s = (const char *) memchr(p, '&', (size_t)(e - p));
+ if (s == NULL) {
+ s = e;
+ }
+ assert(s >= p);
+
+ // Decode variable into destination buffer
+ if ((size_t) (s - p) < dst_len) {
+ len = (int) url_decode(p, (size_t)(s - p), dst, dst_len, 1);
+ }
+ break;
+ }
+ }
+ }
+
+ return len;
+}
+
+int mg_get_cookie(const struct mg_connection *conn, const char *cookie_name,
+ char *dst, size_t dst_size) {
+ const char *s, *p, *end;
+ int name_len, len = -1;
+
+ dst[0] = '\0';
+ if ((s = mg_get_header(conn, "Cookie")) == NULL) {
+ return -1;
+ }
+
+ name_len = (int) strlen(cookie_name);
+ end = s + strlen(s);
+
+ for (; (s = strstr(s, cookie_name)) != NULL; s += name_len)
+ if (s[name_len] == '=') {
+ s += name_len + 1;
+ if ((p = strchr(s, ' ')) == NULL)
+ p = end;
+ if (p[-1] == ';')
+ p--;
+ if (*s == '"' && p[-1] == '"' && p > s + 1) {
+ s++;
+ p--;
+ }
+ if ((size_t) (p - s) < dst_size) {
+ len = p - s;
+ mg_strlcpy(dst, s, (size_t) len + 1);
+ }
+ break;
+ }
+
+ return len;
+}
+
+static int convert_uri_to_file_name(struct mg_connection *conn, char *buf,
+ size_t buf_len, struct mgstat *st) {
+ struct vec a, b;
+ const char *rewrite, *uri = conn->request_info.uri;
+ char *p;
+ int match_len, stat_result;
+
+ buf_len--; // This is because memmove() for PATH_INFO may shift part
+ // of the path one byte on the right.
+ mg_snprintf(conn, buf, buf_len, "%s%s", conn->ctx->config[DOCUMENT_ROOT],
+ uri);
+
+ rewrite = conn->ctx->config[REWRITE];
+ while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
+ if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
+ mg_snprintf(conn, buf, buf_len, "%.*s%s", (int) b.len, b.ptr,
+ uri + match_len);
+ break;
+ }
+ }
+
+ if ((stat_result = mg_stat(buf, st)) != 0) {
+ // Support PATH_INFO for CGI scripts.
+ for (p = buf + strlen(buf); p > buf + 1; p--) {
+ if (*p == '/') {
+ *p = '\0';
+ if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
+ strlen(conn->ctx->config[CGI_EXTENSIONS]), buf) > 0 &&
+ (stat_result = mg_stat(buf, st)) == 0) {
+ // Shift PATH_INFO block one character right, e.g.
+ // "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
+ // conn->path_info is pointing to the local variable "path" declared
+ // in handle_request(), so PATH_INFO is not valid after
+ // handle_request returns.
+ conn->path_info = p + 1;
+ memmove(p + 2, p + 1, strlen(p + 1) + 1); // +1 is for trailing \0
+ p[1] = '/';
+ break;
+ } else {
+ *p = '/';
+ stat_result = -1;
+ }
+ }
+ }
+ }
+
+ return stat_result;
+}
+
+static int sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *)) {
+ return (conn->ssl = SSL_new(s)) != NULL &&
+ SSL_set_fd(conn->ssl, conn->client.sock) == 1 &&
+ func(conn->ssl) == 1;
+}
+
+// Check whether full request is buffered. Return:
+// -1 if request is malformed
+// 0 if request is not yet fully buffered
+// >0 actual request length, including last \r\n\r\n
+static int get_request_len(const char *buf, int buflen) {
+ const char *s, *e;
+ int len = 0;
+
+ for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
+ // Control characters are not allowed but >=128 is.
+ if (!isprint(* (const unsigned char *) s) && *s != '\r' &&
+ *s != '\n' && * (const unsigned char *) s < 128) {
+ len = -1;
+ break; // [i_a] abort scan as soon as one malformed character is found; don't let subsequent \r\n\r\n win us over anyhow
+ } else if (s[0] == '\n' && s[1] == '\n') {
+ len = (int) (s - buf) + 2;
+ } else if (s[0] == '\n' && &s[1] < e &&
+ s[1] == '\r' && s[2] == '\n') {
+ len = (int) (s - buf) + 3;
+ }
+
+ return len;
+}
+
+// Convert month to the month number. Return -1 on error, or month number
+static int get_month_index(const char *s) {
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(month_names); i++)
+ if (!strcmp(s, month_names[i]))
+ return (int) i;
+
+ return -1;
+}
+
+static int num_leap_years(int year) {
+ return year / 4 - year / 100 + year / 400;
+}
+
+// Parse UTC date-time string, and return the corresponding time_t value.
+static time_t parse_date_string(const char *datetime) {
+ static const unsigned short days_before_month[] = {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+ };
+ char month_str[32];
+ int second, minute, hour, day, month, year, leap_days, days;
+ time_t result = (time_t) 0;
+
+ if (((sscanf(datetime, "%d/%3s/%d %d:%d:%d",
+ &day, month_str, &year, &hour, &minute, &second) == 6) ||
+ (sscanf(datetime, "%d %3s %d %d:%d:%d",
+ &day, month_str, &year, &hour, &minute, &second) == 6) ||
+ (sscanf(datetime, "%*3s, %d %3s %d %d:%d:%d",
+ &day, month_str, &year, &hour, &minute, &second) == 6) ||
+ (sscanf(datetime, "%d-%3s-%d %d:%d:%d",
+ &day, month_str, &year, &hour, &minute, &second) == 6)) &&
+ year > 1970 &&
+ (month = get_month_index(month_str)) != -1) {
+ leap_days = num_leap_years(year) - num_leap_years(1970);
+ year -= 1970;
+ days = year * 365 + days_before_month[month] + (day - 1) + leap_days;
+ result = days * 24 * 3600 + hour * 3600 + minute * 60 + second;
+ }
+
+ return result;
+}
+
+// Protect against directory disclosure attack by removing '..',
+// excessive '/' and '\' characters
+static void remove_double_dots_and_double_slashes(char *s) {
+ char *p = s;
+
+ while (*s != '\0') {
+ *p++ = *s++;
+ if (s[-1] == '/' || s[-1] == '\\') {
+ // Skip all following slashes, backslashes and double-dots
+ while (s[0] != '\0') {
+ if (s[0] == '/' || s[0] == '\\') {
+ s++;
+ } else if (s[0] == '.' && s[1] == '.') {
+ s += 2;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ *p = '\0';
+}
+
+static const struct {
+ const char *extension;
+ size_t ext_len;
+ const char *mime_type;
+} builtin_mime_types[] = {
+ {".html", 5, "text/html"},
+ {".htm", 4, "text/html"},
+ {".shtm", 5, "text/html"},
+ {".shtml", 6, "text/html"},
+ {".css", 4, "text/css"},
+ {".js", 3, "application/x-javascript"},
+ {".ico", 4, "image/x-icon"},
+ {".gif", 4, "image/gif"},
+ {".jpg", 4, "image/jpeg"},
+ {".jpeg", 5, "image/jpeg"},
+ {".png", 4, "image/png"},
+ {".svg", 4, "image/svg+xml"},
+ {".txt", 4, "text/plain"},
+ {".torrent", 8, "application/x-bittorrent"},
+ {".wav", 4, "audio/x-wav"},
+ {".mp3", 4, "audio/x-mp3"},
+ {".mid", 4, "audio/mid"},
+ {".m3u", 4, "audio/x-mpegurl"},
+ {".ram", 4, "audio/x-pn-realaudio"},
+ {".xml", 4, "text/xml"},
+ {".json", 5, "text/json"},
+ {".xslt", 5, "application/xml"},
+ {".ra", 3, "audio/x-pn-realaudio"},
+ {".doc", 4, "application/msword"},
+ {".exe", 4, "application/octet-stream"},
+ {".zip", 4, "application/x-zip-compressed"},
+ {".xls", 4, "application/excel"},
+ {".tgz", 4, "application/x-tar-gz"},
+ {".tar", 4, "application/x-tar"},
+ {".gz", 3, "application/x-gunzip"},
+ {".arj", 4, "application/x-arj-compressed"},
+ {".rar", 4, "application/x-arj-compressed"},
+ {".rtf", 4, "application/rtf"},
+ {".pdf", 4, "application/pdf"},
+ {".swf", 4, "application/x-shockwave-flash"},
+ {".mpg", 4, "video/mpeg"},
+ {".webm", 5, "video/webm"},
+ {".mpeg", 5, "video/mpeg"},
+ {".mp4", 4, "video/mp4"},
+ {".m4v", 4, "video/x-m4v"},
+ {".asf", 4, "video/x-ms-asf"},
+ {".avi", 4, "video/x-msvideo"},
+ {".bmp", 4, "image/bmp"},
+ {NULL, 0, NULL}
+};
+
+const char *mg_get_builtin_mime_type(const char *path) {
+ const char *ext;
+ size_t i, path_len;
+
+ path_len = strlen(path);
+
+ for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
+ ext = path + (path_len - builtin_mime_types[i].ext_len);
+ if (path_len > builtin_mime_types[i].ext_len &&
+ mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
+ return builtin_mime_types[i].mime_type;
+ }
+ }
+
+ return "text/plain";
+}
+
+// Look at the "path" extension and figure what mime type it has.
+// Store mime type in the vector.
+static void get_mime_type(struct mg_context *ctx, const char *path,
+ struct vec *vec) {
+ struct vec ext_vec, mime_vec;
+ const char *list, *ext;
+ size_t path_len;
+
+ path_len = strlen(path);
+
+ // Scan user-defined mime types first, in case user wants to
+ // override default mime types.
+ list = ctx->config[EXTRA_MIME_TYPES];
+ while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
+ // ext now points to the path suffix
+ ext = path + path_len - ext_vec.len;
+ if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
+ *vec = mime_vec;
+ return;
+ }
+ }
+
+ vec->ptr = mg_get_builtin_mime_type(path);
+ vec->len = strlen(vec->ptr);
+}
+
+#ifndef HAVE_MD5
+typedef struct MD5Context {
+ uint32_t buf[4];
+ uint32_t bits[2];
+ unsigned char in[64];
+} MD5_CTX;
+
+#if defined(__BYTE_ORDER) && (__BYTE_ORDER == 1234)
+#define byteReverse(buf, len) // Do nothing
+#else
+static void byteReverse(unsigned char *buf, unsigned longs) {
+ uint32_t t;
+ do {
+ t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32_t *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+// initialization constants.
+static void MD5Init(MD5_CTX *ctx) {
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+static void MD5Transform(uint32_t buf[4], uint32_t const in[16]) {
+ register uint32_t a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+static void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len) {
+ uint32_t t;
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+ ctx->bits[1]++;
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f;
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ memcpy(ctx->in, buf, len);
+}
+
+static void MD5Final(unsigned char digest[16], MD5_CTX *ctx) {
+ unsigned count;
+ unsigned char *p;
+
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ p = ctx->in + count;
+ *p++ = 0x80;
+ count = 64 - 1 - count;
+ if (count < 8) {
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ memset(ctx->in, 0, 56);
+ } else {
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+ ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+ MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset((char *) ctx, 0, sizeof(*ctx));
+}
+#endif // !HAVE_MD5
+
+// Stringify binary data. Output buffer must be twice as big as input,
+// because each byte takes 2 bytes in string representation
+static void bin2str(char *to, const unsigned char *p, size_t len) {
+ static const char *hex = "0123456789abcdef";
+
+ for (; len--; p++) {
+ *to++ = hex[p[0] >> 4];
+ *to++ = hex[p[0] & 0x0f];
+ }
+ *to = '\0';
+}
+
+// Return stringified MD5 hash for list of strings. Buffer must be 33 bytes.
+void mg_md5(char buf[33], ...) {
+ unsigned char hash[16];
+ const char *p;
+ va_list ap;
+ MD5_CTX ctx;
+
+ MD5Init(&ctx);
+
+ va_start(ap, buf);
+ while ((p = va_arg(ap, const char *)) != NULL) {
+ MD5Update(&ctx, (const unsigned char *) p, (unsigned) strlen(p));
+ }
+ va_end(ap);
+
+ MD5Final(hash, &ctx);
+ bin2str(buf, hash, sizeof(hash));
+}
+
+// Check the user's password, return 1 if OK
+static int check_password(const char *method, const char *ha1, const char *uri,
+ const char *nonce, const char *nc, const char *cnonce,
+ const char *qop, const char *response) {
+ char ha2[32 + 1], expected_response[32 + 1];
+
+ // Some of the parameters may be NULL
+ if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL ||
+ qop == NULL || response == NULL) {
+ return 0;
+ }
+
+ // NOTE(lsm): due to a bug in MSIE, we do not compare the URI
+ // TODO(lsm): check for authentication timeout
+ if (// strcmp(dig->uri, c->ouri) != 0 ||
+ strlen(response) != 32
+ // || now - strtoul(dig->nonce, NULL, 10) > 3600
+ ) {
+ return 0;
+ }
+
+ mg_md5(ha2, method, ":", uri, NULL);
+ mg_md5(expected_response, ha1, ":", nonce, ":", nc,
+ ":", cnonce, ":", qop, ":", ha2, NULL);
+
+ return mg_strcasecmp(response, expected_response) == 0;
+}
+
+// Use the global passwords file, if specified by auth_gpass option,
+// or search for .htpasswd in the requested directory.
+static FILE *open_auth_file(struct mg_connection *conn, const char *path) {
+ struct mg_context *ctx = conn->ctx;
+ char name[PATH_MAX];
+ const char *p, *e;
+ struct mgstat st;
+ FILE *fp;
+
+ if (ctx->config[GLOBAL_PASSWORDS_FILE] != NULL) {
+ // Use global passwords file
+ fp = mg_fopen(ctx->config[GLOBAL_PASSWORDS_FILE], "r");
+ if (fp == NULL)
+ cry(fc(ctx), "fopen(%s): %s",
+ ctx->config[GLOBAL_PASSWORDS_FILE], strerror(ERRNO));
+ } else if (!mg_stat(path, &st) && st.is_directory) {
+ (void) mg_snprintf(conn, name, sizeof(name), "%s%c%s",
+ path, '/', PASSWORDS_FILE_NAME);
+ fp = mg_fopen(name, "r");
+ } else {
+ // Try to find .htpasswd in requested directory.
+ for (p = path, e = p + strlen(p) - 1; e > p; e--)
+ if (e[0] == '/')
+ break;
+ (void) mg_snprintf(conn, name, sizeof(name), "%.*s%c%s",
+ (int) (e - p), p, '/', PASSWORDS_FILE_NAME);
+ fp = mg_fopen(name, "r");
+ }
+
+ return fp;
+}
+
+// Parsed Authorization header
+struct ah {
+ char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
+};
+
+// Return 1 on success. Always initializes the ah structure.
+static int parse_auth_header(struct mg_connection *conn, char *buf,
+ size_t buf_size, struct ah *ah) {
+ char *name, *value, *s;
+ const char *auth_header;
+
+ (void) memset(ah, 0, sizeof(*ah));
+ if ((auth_header = mg_get_header(conn, "Authorization")) == NULL ||
+ mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
+ return 0;
+ }
+
+ // Make modifiable copy of the auth header
+ (void) mg_strlcpy(buf, auth_header + 7, buf_size);
+ s = buf;
+
+ // Parse authorization header
+ for (;;) {
+ // Gobble initial spaces
+ while (isspace(* (unsigned char *) s)) {
+ s++;
+ }
+ name = skip_quoted(&s, "=", " ", 0);
+ // Value is either quote-delimited, or ends at first comma or space.
+ if (s[0] == '\"') {
+ s++;
+ value = skip_quoted(&s, "\"", " ", '\\');
+ if (s[0] == ',') {
+ s++;
+ }
+ } else {
+ value = skip_quoted(&s, ", ", " ", 0); // IE uses commas, FF uses spaces
+ }
+ if (*name == '\0') {
+ break;
+ }
+
+ if (!strcmp(name, "username")) {
+ ah->user = value;
+ } else if (!strcmp(name, "cnonce")) {
+ ah->cnonce = value;
+ } else if (!strcmp(name, "response")) {
+ ah->response = value;
+ } else if (!strcmp(name, "uri")) {
+ ah->uri = value;
+ } else if (!strcmp(name, "qop")) {
+ ah->qop = value;
+ } else if (!strcmp(name, "nc")) {
+ ah->nc = value;
+ } else if (!strcmp(name, "nonce")) {
+ ah->nonce = value;
+ }
+ }
+
+ // CGI needs it as REMOTE_USER
+ if (ah->user != NULL) {
+ conn->request_info.remote_user = mg_strdup(ah->user);
+ } else {
+ return 0;
+ }
+
+ return 1;
+}
+
+// Authorize against the opened passwords file. Return 1 if authorized.
+static int authorize(struct mg_connection *conn, FILE *fp) {
+ struct ah ah;
+ char line[256], f_user[256], ha1[256], f_domain[256], buf[MG_BUF_LEN];
+
+ if (!parse_auth_header(conn, buf, sizeof(buf), &ah)) {
+ return 0;
+ }
+
+ // Loop over passwords file
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ if (sscanf(line, "%[^:]:%[^:]:%s", f_user, f_domain, ha1) != 3) {
+ continue;
+ }
+
+ if (!strcmp(ah.user, f_user) &&
+ !strcmp(conn->ctx->config[AUTHENTICATION_DOMAIN], f_domain))
+ return check_password(
+ conn->request_info.request_method,
+ ha1, ah.uri, ah.nonce, ah.nc, ah.cnonce, ah.qop,
+ ah.response);
+ }
+
+ return 0;
+}
+
+// Return 1 if request is authorised, 0 otherwise.
+static int check_authorization(struct mg_connection *conn, const char *path) {
+ FILE *fp;
+ char fname[PATH_MAX];
+ struct vec uri_vec, filename_vec;
+ const char *list;
+ int authorized;
+
+ fp = NULL;
+ authorized = 1;
+
+ list = conn->ctx->config[PROTECT_URI];
+ while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
+ if (!memcmp(conn->request_info.uri, uri_vec.ptr, uri_vec.len)) {
+ mg_snprintf(conn, fname, sizeof(fname), "%.*s",
+ (int) filename_vec.len, filename_vec.ptr);
+ if ((fp = mg_fopen(fname, "r")) == NULL) {
+ cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
+ }
+ break;
+ }
+ }
+
+ if (fp == NULL) {
+ fp = open_auth_file(conn, path);
+ }
+
+ if (fp != NULL) {
+ authorized = authorize(conn, fp);
+ (void) fclose(fp);
+ }
+
+ return authorized;
+}
+
+static void send_authorization_request(struct mg_connection *conn) {
+ conn->status_code = 401;
+ (void) mg_printf(conn,
+ "HTTP/1.1 401 Unauthorized\r\n"
+ "Content-Length: 0\r\n"
+ "WWW-Authenticate: Digest qop=\"auth\", "
+ "realm=\"%s\", nonce=\"%lu\"\r\n\r\n",
+ conn->ctx->config[AUTHENTICATION_DOMAIN],
+ (unsigned long) time(NULL));
+}
+
+static int is_authorized_for_put(struct mg_connection *conn) {
+ FILE *fp;
+ int ret = 0;
+
+ fp = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ? NULL :
+ mg_fopen(conn->ctx->config[PUT_DELETE_PASSWORDS_FILE], "r");
+
+ if (fp != NULL) {
+ ret = authorize(conn, fp);
+ (void) fclose(fp);
+ }
+
+ return ret;
+}
+
+int mg_modify_passwords_file(const char *fname, const char *domain,
+ const char *user, const char *pass) {
+ int found;
+ char line[512], u[512], d[512], ha1[33], tmp[PATH_MAX];
+ FILE *fp, *fp2;
+
+ found = 0;
+ fp = fp2 = NULL;
+
+ // Regard empty password as no password - remove user record.
+ if (pass != NULL && pass[0] == '\0') {
+ pass = NULL;
+ }
+
+ (void) snprintf(tmp, sizeof(tmp), "%s.tmp", fname);
+
+ // Create the file if does not exist
+ if ((fp = mg_fopen(fname, "a+")) != NULL) {
+ (void) fclose(fp);
+ }
+
+ // Open the given file and temporary file
+ if ((fp = mg_fopen(fname, "r")) == NULL) {
+ return 0;
+ } else if ((fp2 = mg_fopen(tmp, "w+")) == NULL) {
+ fclose(fp);
+ return 0;
+ }
+
+ // Copy the stuff to temporary file
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ if (sscanf(line, "%[^:]:%[^:]:%*s", u, d) != 2) {
+ continue;
+ }
+
+ if (!strcmp(u, user) && !strcmp(d, domain)) {
+ found++;
+ if (pass != NULL) {
+ mg_md5(ha1, user, ":", domain, ":", pass, NULL);
+ fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
+ }
+ } else {
+ (void) fprintf(fp2, "%s", line);
+ }
+ }
+
+ // If new user, just add it
+ if (!found && pass != NULL) {
+ mg_md5(ha1, user, ":", domain, ":", pass, NULL);
+ (void) fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
+ }
+
+ // Close files
+ (void) fclose(fp);
+ (void) fclose(fp2);
+
+ // Put the temp file in place of real file
+ (void) mg_remove(fname);
+ (void) mg_rename(tmp, fname);
+
+ return 1;
+}
+
+struct de {
+ struct mg_connection *conn;
+ char *file_name;
+ struct mgstat st;
+};
+
+static void url_encode(const char *src, char *dst, size_t dst_len) {
+ static const char *dont_escape = "._-$,;~()";
+ static const char *hex = "0123456789abcdef";
+ const char *end = dst + dst_len - 1;
+
+ for (; *src != '\0' && dst < end; src++, dst++) {
+ if (isalnum(*(const unsigned char *) src) ||
+ strchr(dont_escape, * (const unsigned char *) src) != NULL) {
+ *dst = *src;
+ } else if (dst + 2 < end) {
+ dst[0] = '%';
+ dst[1] = hex[(* (const unsigned char *) src) >> 4];
+ dst[2] = hex[(* (const unsigned char *) src) & 0xf];
+ dst += 2;
+ }
+ }
+
+ *dst = '\0';
+}
+
+static void print_dir_entry(struct de *de) {
+ char size[64], mod[64], href[PATH_MAX];
+
+ if (de->st.is_directory) {
+ (void) mg_snprintf(de->conn, size, sizeof(size), "%s", "[DIRECTORY]");
+ } else {
+ // We use (signed) cast below because MSVC 6 compiler cannot
+ // convert unsigned __int64 to double. Sigh.
+ if (de->st.size < 1024) {
+ (void) mg_snprintf(de->conn, size, sizeof(size),
+ "%lu", (unsigned long) de->st.size);
+ } else if (de->st.size < 0x100000) {
+ (void) mg_snprintf(de->conn, size, sizeof(size),
+ "%.1fk", (double) de->st.size / 1024.0);
+ } else if (de->st.size < 0x40000000) {
+ (void) mg_snprintf(de->conn, size, sizeof(size),
+ "%.1fM", (double) de->st.size / 1048576);
+ } else {
+ (void) mg_snprintf(de->conn, size, sizeof(size),
+ "%.1fG", (double) de->st.size / 1073741824);
+ }
+ }
+ (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", localtime(&de->st.mtime));
+ url_encode(de->file_name, href, sizeof(href));
+ de->conn->num_bytes_sent += mg_printf(de->conn,
+ "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
+ "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
+ de->conn->request_info.uri, href, de->st.is_directory ? "/" : "",
+ de->file_name, de->st.is_directory ? "/" : "", mod, size);
+}
+
+// This function is called from send_directory() and used for
+// sorting directory entries by size, or name, or modification time.
+// On windows, __cdecl specification is needed in case if project is built
+// with __stdcall convention. qsort always requires __cdels callback.
+static int WINCDECL compare_dir_entries(const void *p1, const void *p2) {
+ const struct de *a = (const struct de *) p1, *b = (const struct de *) p2;
+ const char *query_string = a->conn->request_info.query_string;
+ int cmp_result = 0;
+
+ if (query_string == NULL) {
+ query_string = "na";
+ }
+
+ if (a->st.is_directory && !b->st.is_directory) {
+ return -1; // Always put directories on top
+ } else if (!a->st.is_directory && b->st.is_directory) {
+ return 1; // Always put directories on top
+ } else if (*query_string == 'n') {
+ cmp_result = strcmp(a->file_name, b->file_name);
+ } else if (*query_string == 's') {
+ cmp_result = a->st.size == b->st.size ? 0 :
+ a->st.size > b->st.size ? 1 : -1;
+ } else if (*query_string == 'd') {
+ cmp_result = a->st.mtime == b->st.mtime ? 0 :
+ a->st.mtime > b->st.mtime ? 1 : -1;
+ }
+
+ return query_string[1] == 'd' ? -cmp_result : cmp_result;
+}
+
+static int must_hide_file(struct mg_connection *conn, const char *path) {
+ const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
+ const char *pattern = conn->ctx->config[HIDE_FILES];
+ return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0 ||
+ (pattern != NULL && match_prefix(pattern, strlen(pattern), path) > 0);
+}
+
+static int scan_directory(struct mg_connection *conn, const char *dir,
+ void *data, void (*cb)(struct de *, void *)) {
+ char path[PATH_MAX];
+ struct dirent *dp;
+ DIR *dirp;
+ struct de de;
+
+ if ((dirp = opendir(dir)) == NULL) {
+ return 0;
+ } else {
+ de.conn = conn;
+
+ while ((dp = readdir(dirp)) != NULL) {
+ // Do not show current dir and hidden files
+ if (!strcmp(dp->d_name, ".") ||
+ !strcmp(dp->d_name, "..") ||
+ must_hide_file(conn, dp->d_name)) {
+ continue;
+ }
+
+ mg_snprintf(conn, path, sizeof(path), "%s%c%s", dir, '/', dp->d_name);
+
+ // If we don't memset stat structure to zero, mtime will have
+ // garbage and strftime() will segfault later on in
+ // print_dir_entry(). memset is required only if mg_stat()
+ // fails. For more details, see
+ // http://code.google.com/p/mongoose/issues/detail?id=79
+ if (mg_stat(path, &de.st) != 0) {
+ memset(&de.st, 0, sizeof(de.st));
+ }
+ de.file_name = dp->d_name;
+
+ cb(&de, data);
+ }
+ (void) closedir(dirp);
+ }
+ return 1;
+}
+
+struct dir_scan_data {
+ struct de *entries;
+ int num_entries;
+ int arr_size;
+};
+
+static void dir_scan_callback(struct de *de, void *data) {
+ struct dir_scan_data *dsd = (struct dir_scan_data *) data;
+
+ if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
+ dsd->arr_size *= 2;
+ dsd->entries = (struct de *) realloc(dsd->entries, dsd->arr_size *
+ sizeof(dsd->entries[0]));
+ }
+ if (dsd->entries == NULL) {
+ // TODO(lsm): propagate an error to the caller
+ dsd->num_entries = 0;
+ } else {
+ dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
+ dsd->entries[dsd->num_entries].st = de->st;
+ dsd->entries[dsd->num_entries].conn = de->conn;
+ dsd->num_entries++;
+ }
+}
+
+static void handle_directory_request(struct mg_connection *conn,
+ const char *dir) {
+ int i, sort_direction;
+ struct dir_scan_data data = { NULL, 0, 128 };
+
+ if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
+ send_http_error(conn, 500, "Cannot open directory",
+ "Error: opendir(%s): %s", dir, strerror(ERRNO));
+ return;
+ }
+
+ sort_direction = conn->request_info.query_string != NULL &&
+ conn->request_info.query_string[1] == 'd' ? 'a' : 'd';
+
+ conn->must_close = 1;
+ mg_printf(conn, "%s",
+ "HTTP/1.1 200 OK\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n\r\n");
+
+ conn->num_bytes_sent += mg_printf(conn,
+ "<html><head><title>Index of %s</title>"
+ "<style>th {text-align: left;}</style></head>"
+ "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
+ "<tr><th><a href=\"?n%c\">Name</a></th>"
+ "<th><a href=\"?d%c\">Modified</a></th>"
+ "<th><a href=\"?s%c\">Size</a></th></tr>"
+ "<tr><td colspan=\"3\"><hr></td></tr>",
+ conn->request_info.uri, conn->request_info.uri,
+ sort_direction, sort_direction, sort_direction);
+
+ // Print first entry - link to a parent directory
+ conn->num_bytes_sent += mg_printf(conn,
+ "<tr><td><a href=\"%s%s\">%s</a></td>"
+ "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
+ conn->request_info.uri, "..", "Parent directory", "-", "-");
+
+ // Sort and print directory entries
+ qsort(data.entries, (size_t) data.num_entries, sizeof(data.entries[0]),
+ compare_dir_entries);
+ for (i = 0; i < data.num_entries; i++) {
+ print_dir_entry(&data.entries[i]);
+ free(data.entries[i].file_name);
+ }
+ free(data.entries);
+
+ conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
+ conn->status_code = 200;
+}
+
+// Send len bytes from the opened file to the client.
+static void send_file_data(struct mg_connection *conn, FILE *fp, int64_t len) {
+ char buf[MG_BUF_LEN];
+ int to_read, num_read, num_written;
+
+ while (len > 0) {
+ // Calculate how much to read from the file in the buffer
+ to_read = sizeof(buf);
+ if ((int64_t) to_read > len) {
+ to_read = (int) len;
+ }
+
+ // Read from file, exit the loop on error
+ if ((num_read = fread(buf, 1, (size_t)to_read, fp)) <= 0) {
+ break;
+ }
+
+ // Send read bytes to the client, exit the loop on error
+ if ((num_written = mg_write(conn, buf, (size_t)num_read)) != num_read) {
+ break;
+ }
+
+ // Both read and were successful, adjust counters
+ conn->num_bytes_sent += num_written;
+ len -= num_written;
+ }
+}
+
+static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
+ return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
+}
+
+static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
+ strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", gmtime(t));
+}
+
+static void construct_etag(char *buf, size_t buf_len,
+ const struct mgstat *stp) {
+ snprintf(buf, buf_len, "\"%lx.%" INT64_FMT "\"",
+ (unsigned long) stp->mtime, stp->size);
+}
+
+static void handle_file_request(struct mg_connection *conn, const char *path,
+ struct mgstat *stp) {
+ char date[64], lm[64], etag[64], range[64];
+ const char *msg = "OK", *hdr;
+ time_t curtime = time(NULL);
+ int64_t cl, r1, r2;
+ struct vec mime_vec;
+ FILE *fp;
+ int n;
+
+ get_mime_type(conn->ctx, path, &mime_vec);
+ cl = stp->size;
+ conn->status_code = 200;
+ range[0] = '\0';
+
+ if ((fp = mg_fopen(path, "rb")) == NULL) {
+ send_http_error(conn, 500, http_500_error,
+ "fopen(%s): %s", path, strerror(ERRNO));
+ return;
+ }
+ set_close_on_exec(fileno(fp));
+
+ // If Range: header specified, act accordingly
+ r1 = r2 = 0;
+ hdr = mg_get_header(conn, "Range");
+ if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0) {
+ conn->status_code = 206;
+ (void) fseeko(fp, r1, SEEK_SET);
+ cl = n == 2 ? r2 - r1 + 1: cl - r1;
+ (void) mg_snprintf(conn, range, sizeof(range),
+ "Content-Range: bytes "
+ "%" INT64_FMT "-%"
+ INT64_FMT "/%" INT64_FMT "\r\n",
+ r1, r1 + cl - 1, stp->size);
+ msg = "Partial Content";
+ }
+
+ // Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
+ // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3
+ gmt_time_string(date, sizeof(date), &curtime);
+ gmt_time_string(lm, sizeof(lm), &stp->mtime);
+ construct_etag(etag, sizeof(etag), stp);
+
+ (void) mg_printf(conn,
+ "HTTP/1.1 %d %s\r\n"
+ "Date: %s\r\n"
+ "Last-Modified: %s\r\n"
+ "Etag: %s\r\n"
+ "Content-Type: %.*s\r\n"
+ "Content-Length: %" INT64_FMT "\r\n"
+ "Connection: %s\r\n"
+ "Accept-Ranges: bytes\r\n"
+ "%s\r\n",
+ conn->status_code, msg, date, lm, etag, (int) mime_vec.len,
+ mime_vec.ptr, cl, suggest_connection_header(conn), range);
+
+ if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
+ send_file_data(conn, fp, cl);
+ }
+ (void) fclose(fp);
+}
+
+void mg_send_file(struct mg_connection *conn, const char *path) {
+ struct mgstat st;
+ if (mg_stat(path, &st) == 0) {
+ handle_file_request(conn, path, &st);
+ } else {
+ send_http_error(conn, 404, "Not Found", "%s", "File not found");
+ }
+}
+
+
+// Parse HTTP headers from the given buffer, advance buffer to the point
+// where parsing stopped.
+static void parse_http_headers(char **buf, struct mg_request_info *ri) {
+ int i;
+
+ for (i = 0; i < (int) ARRAY_SIZE(ri->http_headers); i++) {
+ ri->http_headers[i].name = skip_quoted(buf, ":", " ", 0);
+ ri->http_headers[i].value = skip(buf, "\r\n");
+ if (ri->http_headers[i].name[0] == '\0')
+ break;
+ ri->num_headers = i + 1;
+ }
+}
+
+static int is_valid_http_method(const char *method) {
+ return !strcmp(method, "GET") || !strcmp(method, "POST") ||
+ !strcmp(method, "HEAD") || !strcmp(method, "CONNECT") ||
+ !strcmp(method, "PUT") || !strcmp(method, "DELETE") ||
+ !strcmp(method, "OPTIONS") || !strcmp(method, "PROPFIND");
+}
+
+// Parse HTTP request, fill in mg_request_info structure.
+// This function modifies the buffer by NUL-terminating
+// HTTP request components, header names and header values.
+static int parse_http_message(char *buf, int len, struct mg_request_info *ri) {
+ int request_length = get_request_len(buf, len);
+ if (request_length > 0) {
+ // Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_port
+ ri->remote_user = ri->request_method = ri->uri = ri->http_version = NULL;
+ ri->num_headers = 0;
+
+ buf[request_length - 1] = '\0';
+
+ // RFC says that all initial whitespaces should be ingored
+ while (*buf != '\0' && isspace(* (unsigned char *) buf)) {
+ buf++;
+ }
+ ri->request_method = skip(&buf, " ");
+ ri->uri = skip(&buf, " ");
+ ri->http_version = skip(&buf, "\r\n");
+ parse_http_headers(&buf, ri);
+ }
+ return request_length;
+}
+
+static int parse_http_request(char *buf, int len, struct mg_request_info *ri) {
+ int result = parse_http_message(buf, len, ri);
+ if (result > 0 &&
+ is_valid_http_method(ri->request_method) &&
+ !strncmp(ri->http_version, "HTTP/", 5)) {
+ ri->http_version += 5; // Skip "HTTP/"
+ } else {
+ result = -1;
+ }
+ return result;
+}
+
+static int parse_http_response(char *buf, int len, struct mg_request_info *ri) {
+ int result = parse_http_message(buf, len, ri);
+ return result > 0 && !strncmp(ri->request_method, "HTTP/", 5) ? result : -1;
+}
+
+// Keep reading the input (either opened file descriptor fd, or socket sock,
+// or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
+// buffer (which marks the end of HTTP request). Buffer buf may already
+// have some data. The length of the data is stored in nread.
+// Upon every read operation, increase nread by the number of bytes read.
+static int read_request(FILE *fp, struct mg_connection *conn,
+ char *buf, int bufsiz, int *nread) {
+ int request_len, n = 1;
+
+ request_len = get_request_len(buf, *nread);
+ while (*nread < bufsiz && request_len == 0 && n > 0) {
+ n = pull(fp, conn, buf + *nread, bufsiz - *nread);
+ if (n > 0) {
+ *nread += n;
+ request_len = get_request_len(buf, *nread);
+ }
+ }
+
+ if (n < 0) {
+ // recv() error -> propagate error; do not process a b0rked-with-very-high-probability request
+ return -1;
+ }
+ return request_len;
+}
+
+// For given directory path, substitute it to valid index file.
+// Return 0 if index file has been found, -1 if not found.
+// If the file is found, it's stats is returned in stp.
+static int substitute_index_file(struct mg_connection *conn, char *path,
+ size_t path_len, struct mgstat *stp) {
+ const char *list = conn->ctx->config[INDEX_FILES];
+ struct mgstat st;
+ struct vec filename_vec;
+ size_t n = strlen(path);
+ int found = 0;
+
+ // The 'path' given to us points to the directory. Remove all trailing
+ // directory separator characters from the end of the path, and
+ // then append single directory separator character.
+ while (n > 0 && path[n - 1] == '/') {
+ n--;
+ }
+ path[n] = '/';
+
+ // Traverse index files list. For each entry, append it to the given
+ // path and see if the file exists. If it exists, break the loop
+ while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
+
+ // Ignore too long entries that may overflow path buffer
+ if (filename_vec.len > path_len - (n + 2))
+ continue;
+
+ // Prepare full path to the index file
+ (void) mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
+
+ // Does it exist?
+ if (mg_stat(path, &st) == 0) {
+ // Yes it does, break the loop
+ *stp = st;
+ found = 1;
+ break;
+ }
+ }
+
+ // If no index file exists, restore directory path
+ if (!found) {
+ path[n] = '\0';
+ }
+
+ return found;
+}
+
+// Return True if we should reply 304 Not Modified.
+static int is_not_modified(const struct mg_connection *conn,
+ const struct mgstat *stp) {
+ char etag[64];
+ const char *ims = mg_get_header(conn, "If-Modified-Since");
+ const char *inm = mg_get_header(conn, "If-None-Match");
+ construct_etag(etag, sizeof(etag), stp);
+ return (inm != NULL && !mg_strcasecmp(etag, inm)) ||
+ (ims != NULL && stp->mtime <= parse_date_string(ims));
+}
+
+static int forward_body_data(struct mg_connection *conn, FILE *fp,
+ SOCKET sock, SSL *ssl) {
+ const char *expect, *body;
+ char buf[MG_BUF_LEN];
+ int to_read, nread, buffered_len, success = 0;
+
+ expect = mg_get_header(conn, "Expect");
+ assert(fp != NULL);
+
+ if (conn->content_len == -1) {
+ send_http_error(conn, 411, "Length Required", "%s", "");
+ } else if (expect != NULL && mg_strcasecmp(expect, "100-continue")) {
+ send_http_error(conn, 417, "Expectation Failed", "%s", "");
+ } else {
+ if (expect != NULL) {
+ (void) mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
+ }
+
+ body = conn->buf + conn->request_len + conn->consumed_content;
+ buffered_len = &conn->buf[conn->data_len] - body;
+ assert(buffered_len >= 0);
+ assert(conn->consumed_content == 0);
+
+ if (buffered_len > 0) {
+ if ((int64_t) buffered_len > conn->content_len) {
+ buffered_len = (int) conn->content_len;
+ }
+ push(fp, sock, ssl, body, (int64_t) buffered_len);
+ conn->consumed_content += buffered_len;
+ }
+
+ nread = 0;
+ while (conn->consumed_content < conn->content_len) {
+ to_read = sizeof(buf);
+ if ((int64_t) to_read > conn->content_len - conn->consumed_content) {
+ to_read = (int) (conn->content_len - conn->consumed_content);
+ }
+ nread = pull(NULL, conn, buf, to_read);
+ if (nread <= 0 || push(fp, sock, ssl, buf, nread) != nread) {
+ break;
+ }
+ conn->consumed_content += nread;
+ }
+
+ if (conn->consumed_content == conn->content_len) {
+ success = nread >= 0;
+ }
+
+ // Each error code path in this function must send an error
+ if (!success) {
+ send_http_error(conn, 577, http_500_error, "%s", "");
+ }
+ }
+
+ return success;
+}
+
+#if !defined(NO_CGI)
+// This structure helps to create an environment for the spawned CGI program.
+// Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
+// last element must be NULL.
+// However, on Windows there is a requirement that all these VARIABLE=VALUE\0
+// strings must reside in a contiguous buffer. The end of the buffer is
+// marked by two '\0' characters.
+// We satisfy both worlds: we create an envp array (which is vars), all
+// entries are actually pointers inside buf.
+struct cgi_env_block {
+ struct mg_connection *conn;
+ char buf[CGI_ENVIRONMENT_SIZE]; // Environment buffer
+ int len; // Space taken
+ char *vars[MAX_CGI_ENVIR_VARS]; // char **envp
+ int nvars; // Number of variables
+};
+
+static char *addenv(struct cgi_env_block *block,
+ PRINTF_FORMAT_STRING(const char *fmt), ...)
+ PRINTF_ARGS(2, 3);
+
+// Append VARIABLE=VALUE\0 string to the buffer, and add a respective
+// pointer into the vars array.
+static char *addenv(struct cgi_env_block *block, const char *fmt, ...) {
+ int n, space;
+ char *added;
+ va_list ap;
+
+ // Calculate how much space is left in the buffer
+ space = sizeof(block->buf) - block->len - 2;
+ assert(space >= 0);
+
+ // Make a pointer to the free space int the buffer
+ added = block->buf + block->len;
+
+ // Copy VARIABLE=VALUE\0 string into the free space
+ va_start(ap, fmt);
+ n = mg_vsnprintf(block->conn, added, (size_t) space, fmt, ap);
+ va_end(ap);
+
+ // Make sure we do not overflow buffer and the envp array
+ if (n > 0 && n + 1 < space &&
+ block->nvars < (int) ARRAY_SIZE(block->vars) - 2) {
+ // Append a pointer to the added string into the envp array
+ block->vars[block->nvars++] = added;
+ // Bump up used length counter. Include \0 terminator
+ block->len += n + 1;
+ } else {
+ cry(block->conn, "%s: CGI env buffer truncated for [%s]", __func__, fmt);
+ }
+
+ return added;
+}
+
+static void prepare_cgi_environment(struct mg_connection *conn,
+ const char *prog,
+ struct cgi_env_block *blk) {
+ const char *s, *slash;
+ struct vec var_vec;
+ char *p, src_addr[20];
+ int i;
+
+ blk->len = blk->nvars = 0;
+ blk->conn = conn;
+ sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+
+ addenv(blk, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
+ addenv(blk, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
+ addenv(blk, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
+
+ // Prepare the environment block
+ addenv(blk, "%s", "GATEWAY_INTERFACE=CGI/1.1");
+ addenv(blk, "%s", "SERVER_PROTOCOL=HTTP/1.1");
+ addenv(blk, "%s", "REDIRECT_STATUS=200"); // For PHP
+
+ // TODO(lsm): fix this for IPv6 case
+ addenv(blk, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
+
+ addenv(blk, "REQUEST_METHOD=%s", conn->request_info.request_method);
+ addenv(blk, "REMOTE_ADDR=%s", src_addr);
+ addenv(blk, "REMOTE_PORT=%d", conn->request_info.remote_port);
+ addenv(blk, "REQUEST_URI=%s", conn->request_info.uri);
+
+ // SCRIPT_NAME
+ assert(conn->request_info.uri[0] == '/');
+ slash = strrchr(conn->request_info.uri, '/');
+ if ((s = strrchr(prog, '/')) == NULL)
+ s = prog;
+ addenv(blk, "SCRIPT_NAME=%.*s%s", (int) (slash - conn->request_info.uri),
+ conn->request_info.uri, s);
+
+ addenv(blk, "SCRIPT_FILENAME=%s", prog);
+ addenv(blk, "PATH_TRANSLATED=%s", prog);
+ addenv(blk, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
+
+ if ((s = mg_get_header(conn, "Content-Type")) != NULL)
+ addenv(blk, "CONTENT_TYPE=%s", s);
+
+ if (conn->request_info.query_string != NULL)
+ addenv(blk, "QUERY_STRING=%s", conn->request_info.query_string);
+
+ if ((s = mg_get_header(conn, "Content-Length")) != NULL)
+ addenv(blk, "CONTENT_LENGTH=%s", s);
+
+ if ((s = getenv("PATH")) != NULL)
+ addenv(blk, "PATH=%s", s);
+
+ if (conn->path_info != NULL) {
+ addenv(blk, "PATH_INFO=%s", conn->path_info);
+ }
+
+#if defined(_WIN32)
+ if ((s = getenv("COMSPEC")) != NULL) {
+ addenv(blk, "COMSPEC=%s", s);
+ }
+ if ((s = getenv("SYSTEMROOT")) != NULL) {
+ addenv(blk, "SYSTEMROOT=%s", s);
+ }
+ if ((s = getenv("SystemDrive")) != NULL) {
+ addenv(blk, "SystemDrive=%s", s);
+ }
+#else
+ if ((s = getenv("LD_LIBRARY_PATH")) != NULL)
+ addenv(blk, "LD_LIBRARY_PATH=%s", s);
+#endif // _WIN32
+
+ if ((s = getenv("PERLLIB")) != NULL)
+ addenv(blk, "PERLLIB=%s", s);
+
+ if (conn->request_info.remote_user != NULL) {
+ addenv(blk, "REMOTE_USER=%s", conn->request_info.remote_user);
+ addenv(blk, "%s", "AUTH_TYPE=Digest");
+ }
+
+ // Add all headers as HTTP_* variables
+ for (i = 0; i < conn->request_info.num_headers; i++) {
+ p = addenv(blk, "HTTP_%s=%s",
+ conn->request_info.http_headers[i].name,
+ conn->request_info.http_headers[i].value);
+
+ // Convert variable name into uppercase, and change - to _
+ for (; *p != '=' && *p != '\0'; p++) {
+ if (*p == '-')
+ *p = '_';
+ *p = (char) toupper(* (unsigned char *) p);
+ }
+ }
+
+ // Add user-specified variables
+ s = conn->ctx->config[CGI_ENVIRONMENT];
+ while ((s = next_option(s, &var_vec, NULL)) != NULL) {
+ addenv(blk, "%.*s", (int) var_vec.len, var_vec.ptr);
+ }
+
+ blk->vars[blk->nvars++] = NULL;
+ blk->buf[blk->len++] = '\0';
+
+ assert(blk->nvars < (int) ARRAY_SIZE(blk->vars));
+ assert(blk->len > 0);
+ assert(blk->len < (int) sizeof(blk->buf));
+}
+
+static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
+ int headers_len, data_len, i, fd_stdin[2], fd_stdout[2];
+ const char *status, *status_text;
+ char buf[16384], *pbuf, dir[PATH_MAX], *p;
+ struct mg_request_info ri;
+ struct cgi_env_block blk;
+ FILE *in, *out;
+ pid_t pid;
+
+ prepare_cgi_environment(conn, prog, &blk);
+
+ // CGI must be executed in its own directory. 'dir' must point to the
+ // directory containing executable program, 'p' must point to the
+ // executable program name relative to 'dir'.
+ (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog);
+ if ((p = strrchr(dir, '/')) != NULL) {
+ *p++ = '\0';
+ } else {
+ dir[0] = '.', dir[1] = '\0';
+ p = (char *) prog;
+ }
+
+ pid = (pid_t) -1;
+ fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
+ in = out = NULL;
+
+ if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
+ send_http_error(conn, 500, http_500_error,
+ "Cannot create CGI pipe: %s", strerror(ERRNO));
+ goto done;
+ } else if ((pid = spawn_process(conn, p, blk.buf, blk.vars,
+ fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) {
+ send_http_error(conn, 500, http_500_error,
+ "Cannot spawn CGI process [%s]: %s", prog, strerror(ERRNO));
+ goto done;
+ }
+
+ // spawn_process() must close those!
+ // If we don't mark them as closed, close() attempt before
+ // return from this function throws an exception on Windows.
+ // Windows does not like when closed descriptor is closed again.
+ fd_stdin[0] = fd_stdout[1] = -1;
+
+ if ((in = fdopen(fd_stdin[1], "wb")) == NULL ||
+ (out = fdopen(fd_stdout[0], "rb")) == NULL) {
+ send_http_error(conn, 500, http_500_error,
+ "fopen: %s", strerror(ERRNO));
+ goto done;
+ }
+
+ setbuf(in, NULL);
+ setbuf(out, NULL);
+
+ // Send POST data to the CGI process if needed
+ if (!strcmp(conn->request_info.request_method, "POST") &&
+ !forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
+ goto done;
+ }
+
+ // Close so child gets an EOF.
+ fclose(in);
+ in = NULL;
+ fd_stdin[1] = -1;
+
+ // Now read CGI reply into a buffer. We need to set correct
+ // status code, thus we need to see all HTTP headers first.
+ // Do not send anything back to client, until we buffer in all
+ // HTTP headers.
+ data_len = 0;
+ headers_len = read_request(out, conn, buf, sizeof(buf), &data_len);
+ if (headers_len <= 0) {
+ send_http_error(conn, 500, http_500_error,
+ "CGI program sent malformed or too big (>%u bytes) "
+ "HTTP headers: [%.*s]",
+ (unsigned) sizeof(buf), data_len, buf);
+ goto done;
+ }
+ pbuf = buf;
+ buf[headers_len - 1] = '\0';
+ parse_http_headers(&pbuf, &ri);
+
+ // Make up and send the status line
+ status_text = "OK";
+ if ((status = get_header(&ri, "Status")) != NULL) {
+ conn->status_code = atoi(status);
+ status_text = status;
+ while (isdigit(* (unsigned char *) status_text) || *status_text == ' ') {
+ status_text++;
+ }
+ } else if (get_header(&ri, "Location") != NULL) {
+ conn->status_code = 302;
+ } else {
+ conn->status_code = 200;
+ }
+ if (get_header(&ri, "Connection") != NULL &&
+ !mg_strcasecmp(get_header(&ri, "Connection"), "keep-alive")) {
+ conn->must_close = 1;
+ }
+ (void) mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code,
+ status_text);
+
+ // Send headers
+ for (i = 0; i < ri.num_headers; i++) {
+ mg_printf(conn, "%s: %s\r\n",
+ ri.http_headers[i].name, ri.http_headers[i].value);
+ }
+ (void) mg_write(conn, "\r\n", 2);
+
+ // Send chunk of data that may have been read after the headers
+ conn->num_bytes_sent += mg_write(conn, buf + headers_len,
+ (size_t)(data_len - headers_len));
+
+ // Read the rest of CGI output and send to the client
+ send_file_data(conn, out, INT64_MAX);
+
+done:
+ if (pid != (pid_t) -1) {
+ kill(pid, SIGKILL);
+ }
+ if (fd_stdin[0] != -1) {
+ (void) close(fd_stdin[0]);
+ }
+ if (fd_stdout[1] != -1) {
+ (void) close(fd_stdout[1]);
+ }
+
+ if (in != NULL) {
+ (void) fclose(in);
+ } else if (fd_stdin[1] != -1) {
+ (void) close(fd_stdin[1]);
+ }
+
+ if (out != NULL) {
+ (void) fclose(out);
+ } else if (fd_stdout[0] != -1) {
+ (void) close(fd_stdout[0]);
+ }
+}
+#endif // !NO_CGI
+
+// For a given PUT path, create all intermediate subdirectories
+// for given path. Return 0 if the path itself is a directory,
+// or -1 on error, 1 if OK.
+static int put_dir(const char *path) {
+ char buf[PATH_MAX];
+ const char *s, *p;
+ struct mgstat st;
+ int len, res = 1;
+
+ for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
+ len = p - path;
+ if (len >= (int) sizeof(buf)) {
+ res = -1;
+ break;
+ }
+ memcpy(buf, path, len);
+ buf[len] = '\0';
+
+ // Try to create intermediate directory
+ DEBUG_TRACE(("mkdir(%s)", buf));
+ if (mg_stat(buf, &st) == -1 && mg_mkdir(buf, 0755) != 0) {
+ res = -1;
+ break;
+ }
+
+ // Is path itself a directory?
+ if (p[1] == '\0') {
+ res = 0;
+ }
+ }
+
+ return res;
+}
+
+static void put_file(struct mg_connection *conn, const char *path) {
+ struct mgstat st;
+ const char *range;
+ int64_t r1, r2;
+ FILE *fp;
+ int rc;
+
+ conn->status_code = mg_stat(path, &st) == 0 ? 200 : 201;
+
+ if ((rc = put_dir(path)) == 0) {
+ mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->status_code);
+ } else if (rc == -1) {
+ send_http_error(conn, 500, http_500_error,
+ "put_dir(%s): %s", path, strerror(ERRNO));
+ } else if ((fp = mg_fopen(path, "wb+")) == NULL) {
+ send_http_error(conn, 500, http_500_error,
+ "fopen(%s): %s", path, strerror(ERRNO));
+ } else {
+ set_close_on_exec(fileno(fp));
+ range = mg_get_header(conn, "Content-Range");
+ r1 = r2 = 0;
+ if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
+ conn->status_code = 206;
+ // TODO(lsm): handle seek error
+ (void) fseeko(fp, r1, SEEK_SET);
+ }
+ if (forward_body_data(conn, fp, INVALID_SOCKET, NULL)) {
+ (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n\r\n", conn->status_code);
+ }
+ (void) fclose(fp);
+ }
+}
+
+static void send_ssi_file(struct mg_connection *, const char *, FILE *, int);
+
+static void do_ssi_include(struct mg_connection *conn, const char *ssi,
+ char *tag, int include_level) {
+ char file_name[MG_BUF_LEN], path[PATH_MAX], *p;
+ FILE *fp;
+
+ // sscanf() is safe here, since send_ssi_file() also uses buffer
+ // of size MG_BUF_LEN to get the tag. So strlen(tag) is always < MG_BUF_LEN.
+ if (sscanf(tag, " virtual=\"%[^\"]\"", file_name) == 1) {
+ // File name is relative to the webserver root
+ (void) mg_snprintf(conn, path, sizeof(path), "%s%c%s",
+ conn->ctx->config[DOCUMENT_ROOT], '/', file_name);
+ } else if (sscanf(tag, " file=\"%[^\"]\"", file_name) == 1) {
+ // File name is relative to the webserver working directory
+ // or it is absolute system path
+ (void) mg_snprintf(conn, path, sizeof(path), "%s", file_name);
+ } else if (sscanf(tag, " \"%[^\"]\"", file_name) == 1) {
+ // File name is relative to the currect document
+ (void) mg_snprintf(conn, path, sizeof(path), "%s", ssi);
+ if ((p = strrchr(path, '/')) != NULL) {
+ p[1] = '\0';
+ }
+ (void) mg_snprintf(conn, path + strlen(path),
+ sizeof(path) - strlen(path), "%s", file_name);
+ } else {
+ cry(conn, "Bad SSI #include: [%s]", tag);
+ return;
+ }
+
+ if ((fp = mg_fopen(path, "rb")) == NULL) {
+ cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s",
+ tag, path, strerror(ERRNO));
+ } else {
+ set_close_on_exec(fileno(fp));
+ if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
+ strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) {
+ send_ssi_file(conn, path, fp, include_level + 1);
+ } else {
+ send_file_data(conn, fp, INT64_MAX);
+ }
+ (void) fclose(fp);
+ }
+}
+
+#if !defined(NO_POPEN)
+static void do_ssi_exec(struct mg_connection *conn, char *tag) {
+ char cmd[MG_BUF_LEN];
+ FILE *fp;
+
+ if (sscanf(tag, " \"%[^\"]\"", cmd) != 1) {
+ cry(conn, "Bad SSI #exec: [%s]", tag);
+ } else if ((fp = popen(cmd, "r")) == NULL) {
+ cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
+ } else {
+ send_file_data(conn, fp, INT64_MAX);
+ (void) pclose(fp);
+ }
+}
+#endif // !NO_POPEN
+
+static void send_ssi_file(struct mg_connection *conn, const char *path,
+ FILE *fp, int include_level) {
+ char buf[MG_BUF_LEN];
+ int ch, len, in_ssi_tag;
+
+ if (include_level > 10) {
+ cry(conn, "SSI #include level is too deep (%s)", path);
+ return;
+ }
+
+ in_ssi_tag = 0;
+ len = 0;
+
+ while ((ch = fgetc(fp)) != EOF) {
+ if (in_ssi_tag && ch == '>') {
+ in_ssi_tag = 0;
+ buf[len++] = (char) ch;
+ buf[len] = '\0';
+ assert(len <= (int) sizeof(buf));
+ if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
+ // Not an SSI tag, pass it
+ (void) mg_write(conn, buf, (size_t)len);
+ } else {
+ if (!memcmp(buf + 5, "include", 7)) {
+ do_ssi_include(conn, path, buf + 12, include_level);
+#if !defined(NO_POPEN)
+ } else if (!memcmp(buf + 5, "exec", 4)) {
+ do_ssi_exec(conn, buf + 9);
+#endif // !NO_POPEN
+ } else {
+ cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
+ }
+ }
+ len = 0;
+ } else if (in_ssi_tag) {
+ if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
+ // Not an SSI tag
+ in_ssi_tag = 0;
+ } else if (len == (int) sizeof(buf) - 2) {
+ cry(conn, "%s: SSI tag is too large", path);
+ len = 0;
+ }
+ buf[len++] = ch & 0xff;
+ } else if (ch == '<') {
+ in_ssi_tag = 1;
+ if (len > 0) {
+ (void) mg_write(conn, buf, (size_t)len);
+ }
+ len = 0;
+ buf[len++] = ch & 0xff;
+ } else {
+ buf[len++] = ch & 0xff;
+ if (len == (int) sizeof(buf)) {
+ (void) mg_write(conn, buf, (size_t)len);
+ len = 0;
+ }
+ }
+ }
+
+ // Send the rest of buffered data
+ if (len > 0) {
+ (void) mg_write(conn, buf, (size_t)len);
+ }
+}
+
+static void handle_ssi_file_request(struct mg_connection *conn,
+ const char *path) {
+ FILE *fp;
+
+ if ((fp = mg_fopen(path, "rb")) == NULL) {
+ send_http_error(conn, 500, http_500_error, "fopen(%s): %s", path,
+ strerror(ERRNO));
+ } else {
+ conn->must_close = 1;
+ set_close_on_exec(fileno(fp));
+ mg_printf(conn, "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\nConnection: %s\r\n\r\n",
+ suggest_connection_header(conn));
+ send_ssi_file(conn, path, fp, 0);
+ (void) fclose(fp);
+ }
+}
+
+static void send_options(struct mg_connection *conn) {
+ conn->status_code = 200;
+
+ (void) mg_printf(conn,
+ "HTTP/1.1 200 OK\r\n"
+ "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS\r\n"
+ "DAV: 1\r\n\r\n");
+}
+
+// Writes PROPFIND properties for a collection element
+static void print_props(struct mg_connection *conn, const char* uri,
+ struct mgstat* st) {
+ char mtime[64];
+ gmt_time_string(mtime, sizeof(mtime), &st->mtime);
+ conn->num_bytes_sent += mg_printf(conn,
+ "<d:response>"
+ "<d:href>%s</d:href>"
+ "<d:propstat>"
+ "<d:prop>"
+ "<d:resourcetype>%s</d:resourcetype>"
+ "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
+ "<d:getlastmodified>%s</d:getlastmodified>"
+ "</d:prop>"
+ "<d:status>HTTP/1.1 200 OK</d:status>"
+ "</d:propstat>"
+ "</d:response>\n",
+ uri,
+ st->is_directory ? "<d:collection/>" : "",
+ st->size,
+ mtime);
+}
+
+static void print_dav_dir_entry(struct de *de, void *data) {
+ char href[PATH_MAX];
+ struct mg_connection *conn = (struct mg_connection *) data;
+ mg_snprintf(conn, href, sizeof(href), "%s%s",
+ conn->request_info.uri, de->file_name);
+ print_props(conn, href, &de->st);
+}
+
+static void handle_propfind(struct mg_connection *conn, const char* path,
+ struct mgstat* st) {
+ const char *depth = mg_get_header(conn, "Depth");
+
+ conn->must_close = 1;
+ conn->status_code = 207;
+ mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/xml; charset=utf-8\r\n\r\n");
+
+ conn->num_bytes_sent += mg_printf(conn,
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<d:multistatus xmlns:d='DAV:'>\n");
+
+ // Print properties for the requested resource itself
+ print_props(conn, conn->request_info.uri, st);
+
+ // If it is a directory, print directory entries too if Depth is not 0
+ if (st->is_directory &&
+ !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") &&
+ (depth == NULL || strcmp(depth, "0") != 0)) {
+ scan_directory(conn, path, conn, &print_dav_dir_entry);
+ }
+
+ conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
+}
+
+#if defined(USE_WEBSOCKET)
+
+// START OF SHA-1 code
+// Copyright(c) By Steve Reid <steve@edmweb.com>
+#define SHA1HANDSOFF
+#if defined(__sun)
+#include "solarisfixes.h"
+#endif
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+ |(rol(block->l[i],8)&0x00FF00FF))
+#elif BYTE_ORDER == BIG_ENDIAN
+#define blk0(i) block->l[i]
+#else
+#error "Endianness not defined!"
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+static void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]) {
+ uint32_t a, b, c, d, e;
+ typedef union { unsigned char c[64]; uint32_t l[16]; } CHAR64LONG16;
+
+ CHAR64LONG16 block[1];
+ memcpy(block, buffer, 64);
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ a = b = c = d = e = 0;
+ memset(block, '\0', sizeof(block));
+}
+
+static void SHA1Init(SHA1_CTX* context) {
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+static void SHA1Update(SHA1_CTX* context, const unsigned char* data,
+ uint32_t len) {
+ uint32_t i, j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j)
+ context->count[1]++;
+ context->count[1] += (len>>29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64-j));
+ SHA1Transform(context->state, context->buffer);
+ for ( ; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ }
+ else i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+static void SHA1Final(unsigned char digest[20], SHA1_CTX* context) {
+ unsigned i;
+ unsigned char finalcount[8], c;
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ c = 0200;
+ SHA1Update(context, &c, 1);
+ while ((context->count[0] & 504) != 448) {
+ c = 0000;
+ SHA1Update(context, &c, 1);
+ }
+ SHA1Update(context, finalcount, 8);
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+ }
+ memset(context, '\0', sizeof(*context));
+ memset(&finalcount, '\0', sizeof(finalcount));
+}
+// END OF SHA1 CODE
+
+static void base64_encode(const unsigned char *src, int src_len, char *dst) {
+ static const char *b64 =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int i, j, a, b, c;
+
+ for (i = j = 0; i < src_len; i += 3) {
+ a = src[i];
+ b = i + 1 >= src_len ? 0 : src[i + 1];
+ c = i + 2 >= src_len ? 0 : src[i + 2];
+
+ dst[j++] = b64[a >> 2];
+ dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
+ if (i + 1 < src_len) {
+ dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
+ }
+ if (i + 2 < src_len) {
+ dst[j++] = b64[c & 63];
+ }
+ }
+ while (j % 4 != 0) {
+ dst[j++] = '=';
+ }
+ dst[j++] = '\0';
+}
+
+static void send_websocket_handshake(struct mg_connection *conn) {
+ static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
+ SHA1_CTX sha_ctx;
+
+ mg_snprintf(conn, buf, sizeof(buf), "%s%s",
+ mg_get_header(conn, "Sec-WebSocket-Key"), magic);
+ SHA1Init(&sha_ctx);
+ SHA1Update(&sha_ctx, (unsigned char *) buf, strlen(buf));
+ SHA1Final((unsigned char *) sha, &sha_ctx);
+ base64_encode((unsigned char *) sha, sizeof(sha), b64_sha);
+ mg_printf(conn, "%s%s%s",
+ "HTTP/1.1 101 Switching Protocols\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
+}
+
+static void read_websocket(struct mg_connection *conn) {
+ unsigned char *mask, *buf = (unsigned char *) conn->buf + conn->request_len;
+ int n, len, mask_len, body_len, discard_len;
+
+ for (;;) {
+ if ((body_len = conn->data_len - conn->request_len) >= 2) {
+ len = buf[1] & 127;
+ mask_len = buf[1] & 128 ? 4 : 0;
+ if (len < 126) {
+ conn->content_len = 2 + mask_len + len;
+ mask = buf + 2;
+ } else if (len == 126 && body_len >= 4) {
+ conn->content_len = 2 + mask_len + ((((int) buf[2]) << 8) + buf[3]);
+ mask = buf + 4;
+ } else if (body_len >= 10) {
+ conn->content_len = 2 + mask_len +
+ ((uint64_t) htonl(* (uint32_t *) &buf[2])) << 32 |
+ htonl(* (uint32_t *) &buf[6]);
+ mask = buf + 10;
+ }
+ }
+
+ if (conn->content_len > 0) {
+ if (call_user(conn, MG_WEBSOCKET_MESSAGE) != NULL) {
+ break; // Callback signalled to exit
+ }
+ discard_len = conn->content_len > body_len ? body_len : conn->content_len;
+ memmove(buf, buf + discard_len, conn->data_len - discard_len);
+ conn->data_len -= discard_len;
+ conn->content_len = conn->consumed_content = 0;
+ } else {
+ if (wait_until_socket_is_readable(conn) == 0) {
+ break;
+ }
+ n = pull(NULL, conn, conn->buf + conn->data_len,
+ conn->buf_size - conn->data_len);
+ if (n <= 0) {
+ break;
+ }
+ conn->data_len += n;
+ }
+ }
+}
+
+static void handle_websocket_request(struct mg_connection *conn) {
+ if (strcmp(mg_get_header(conn, "Sec-WebSocket-Version"), "13") != 0) {
+ send_http_error(conn, 426, "Upgrade Required", "%s", "Upgrade Required");
+ } else if (call_user(conn, MG_WEBSOCKET_CONNECT) != NULL) {
+ // Callback has returned non-NULL, do not proceed with handshake
+ } else {
+ send_websocket_handshake(conn);
+ call_user(conn, MG_WEBSOCKET_READY);
+ read_websocket(conn);
+ call_user(conn, MG_WEBSOCKET_CLOSE);
+ }
+}
+
+static int is_websocket_request(const struct mg_connection *conn) {
+ const char *host, *upgrade, *connection, *version, *key;
+
+ host = mg_get_header(conn, "Host");
+ upgrade = mg_get_header(conn, "Upgrade");
+ connection = mg_get_header(conn, "Connection");
+ key = mg_get_header(conn, "Sec-WebSocket-Key");
+ version = mg_get_header(conn, "Sec-WebSocket-Version");
+
+ return host != NULL && upgrade != NULL && connection != NULL &&
+ key != NULL && version != NULL &&
+ !mg_strcasecmp(upgrade, "websocket") &&
+ !mg_strcasecmp(connection, "Upgrade");
+}
+#endif // !USE_WEBSOCKET
+
+static int isbyte(int n) {
+ return n >= 0 && n <= 255;
+}
+
+static int parse_net(const char *spec, uint32_t *net, uint32_t *mask) {
+ int n, a, b, c, d, slash = 32, len = 0;
+
+ if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5 ||
+ sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) &&
+ isbyte(a) && isbyte(b) && isbyte(c) && isbyte(d) &&
+ slash >= 0 && slash < 33) {
+ len = n;
+ *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | d;
+ *mask = slash ? 0xffffffffU << (32 - slash) : 0;
+ }
+
+ return len;
+}
+
+static int set_throttle(const char *spec, uint32_t remote_ip, const char *uri) {
+ int throttle = 0;
+ struct vec vec, val;
+ uint32_t net, mask;
+ char mult;
+ double v;
+
+ while ((spec = next_option(spec, &vec, &val)) != NULL) {
+ mult = ',';
+ if (sscanf(val.ptr, "%lf%c", &v, &mult) < 1 || v < 0 ||
+ (lowercase(&mult) != 'k' && lowercase(&mult) != 'm' && mult != ',')) {
+ continue;
+ }
+ v *= lowercase(&mult) == 'k' ? 1024 : lowercase(&mult) == 'm' ? 1048576 : 1;
+ if (vec.len == 1 && vec.ptr[0] == '*') {
+ throttle = (int) v;
+ } else if (parse_net(vec.ptr, &net, &mask) > 0) {
+ if ((remote_ip & mask) == net) {
+ throttle = (int) v;
+ }
+ } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
+ throttle = (int) v;
+ }
+ }
+
+ return throttle;
+}
+
+static uint32_t get_remote_ip(const struct mg_connection *conn) {
+ return ntohl(* (uint32_t *) &conn->client.rsa.sin.sin_addr);
+}
+
+// This is the heart of the Mongoose's logic.
+// This function is called when the request is read, parsed and validated,
+// and Mongoose must decide what action to take: serve a file, or
+// a directory, or call embedded function, etcetera.
+static void handle_request(struct mg_connection *conn) {
+ struct mg_request_info *ri = &conn->request_info;
+ char path[PATH_MAX];
+ int stat_result, uri_len;
+ struct mgstat st;
+
+ if ((conn->request_info.query_string = strchr(ri->uri, '?')) != NULL) {
+ *conn->request_info.query_string++ = '\0';
+ }
+ uri_len = (int) strlen(ri->uri);
+ url_decode(ri->uri, (size_t)uri_len, ri->uri, (size_t)(uri_len + 1), 0);
+ remove_double_dots_and_double_slashes(ri->uri);
+ stat_result = convert_uri_to_file_name(conn, path, sizeof(path), &st);
+ conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
+ get_remote_ip(conn), ri->uri);
+
+ DEBUG_TRACE(("%s", ri->uri));
+ if (!check_authorization(conn, path)) {
+ send_authorization_request(conn);
+#if defined(USE_WEBSOCKET)
+ } else if (is_websocket_request(conn)) {
+ handle_websocket_request(conn);
+#endif
+ } else if (call_user(conn, MG_NEW_REQUEST) != NULL) {
+ // Do nothing, callback has served the request
+ } else if (!strcmp(ri->request_method, "OPTIONS")) {
+ send_options(conn);
+ } else if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
+ send_http_error(conn, 404, "Not Found", "Not Found");
+ } else if ((!strcmp(ri->request_method, "PUT") ||
+ !strcmp(ri->request_method, "DELETE")) &&
+ (conn->ctx->config[PUT_DELETE_PASSWORDS_FILE] == NULL ||
+ is_authorized_for_put(conn) != 1)) {
+ send_authorization_request(conn);
+ } else if (!strcmp(ri->request_method, "PUT")) {
+ put_file(conn, path);
+ } else if (!strcmp(ri->request_method, "DELETE")) {
+ if (mg_remove(path) == 0) {
+ send_http_error(conn, 200, "OK", "%s", "");
+ } else {
+ send_http_error(conn, 500, http_500_error, "remove(%s): %s", path,
+ strerror(ERRNO));
+ }
+ } else if (stat_result != 0 || must_hide_file(conn, path)) {
+ send_http_error(conn, 404, "Not Found", "%s", "File not found");
+ } else if (st.is_directory && ri->uri[uri_len - 1] != '/') {
+ (void) mg_printf(conn, "HTTP/1.1 301 Moved Permanently\r\n"
+ "Location: %s/\r\n\r\n", ri->uri);
+ } else if (!strcmp(ri->request_method, "PROPFIND")) {
+ handle_propfind(conn, path, &st);
+ } else if (st.is_directory &&
+ !substitute_index_file(conn, path, sizeof(path), &st)) {
+ if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")) {
+ handle_directory_request(conn, path);
+ } else {
+ send_http_error(conn, 403, "Directory Listing Denied",
+ "Directory listing denied");
+ }
+#if !defined(NO_CGI)
+ } else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
+ strlen(conn->ctx->config[CGI_EXTENSIONS]),
+ path) > 0) {
+ if (strcmp(ri->request_method, "POST") &&
+ strcmp(ri->request_method, "GET")) {
+ send_http_error(conn, 501, "Not Implemented",
+ "Method %s is not implemented", ri->request_method);
+ } else {
+ handle_cgi_request(conn, path);
+ }
+#endif // !NO_CGI
+ } else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
+ strlen(conn->ctx->config[SSI_EXTENSIONS]),
+ path) > 0) {
+ handle_ssi_file_request(conn, path);
+ } else if (is_not_modified(conn, &st)) {
+ send_http_error(conn, 304, "Not Modified", "%s", "");
+ } else {
+ handle_file_request(conn, path, &st);
+ }
+}
+
+static void close_all_listening_sockets(struct mg_context *ctx) {
+ struct socket *sp, *tmp;
+ for (sp = ctx->listening_sockets; sp != NULL; sp = tmp) {
+ tmp = sp->next;
+ (void) closesocket(sp->sock);
+ free(sp);
+ }
+}
+
+// Valid listening port specification is: [ip_address:]port[s]
+// Examples: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
+// TODO(lsm): add parsing of the IPv6 address
+static int parse_port_string(const struct vec *vec, struct socket *so) {
+ int a, b, c, d, port, len;
+
+ // MacOS needs that. If we do not zero it, subsequent bind() will fail.
+ // Also, all-zeroes in the socket address means binding to all addresses
+ // for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
+ memset(so, 0, sizeof(*so));
+
+ if (sscanf(vec->ptr, "%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) {
+ // Bind to a specific IPv4 address
+ so->lsa.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
+ } else if (sscanf(vec->ptr, "%d%n", &port, &len) != 1 ||
+ len <= 0 ||
+ len > (int) vec->len ||
+ (vec->ptr[len] && vec->ptr[len] != 's' && vec->ptr[len] != ',')) {
+ return 0;
+ }
+
+ so->is_ssl = vec->ptr[len] == 's';
+#if defined(USE_IPV6)
+ so->lsa.sin6.sin6_family = AF_INET6;
+ so->lsa.sin6.sin6_port = htons((uint16_t) port);
+#else
+ so->lsa.sin.sin_family = AF_INET;
+ so->lsa.sin.sin_port = htons((uint16_t) port);
+#endif
+
+ return 1;
+}
+
+static int set_ports_option(struct mg_context *ctx) {
+ const char *list = ctx->config[LISTENING_PORTS];
+ int on = 1, success = 1;
+ SOCKET sock;
+ struct vec vec;
+ struct socket so, *listener;
+
+ while (success && (list = next_option(list, &vec, NULL)) != NULL) {
+ if (!parse_port_string(&vec, &so)) {
+ cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s",
+ __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|p]");
+ success = 0;
+ } else if (so.is_ssl &&
+ (ctx->ssl_ctx == NULL || ctx->config[SSL_CERTIFICATE] == NULL)) {
+ cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?");
+ success = 0;
+ } else if ((sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6)) ==
+ INVALID_SOCKET ||
+ // On Windows, SO_REUSEADDR is recommended only for
+ // broadcast UDP sockets
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &on,
+ sizeof(on)) != 0 ||
+ // Set TCP keep-alive. This is needed because if HTTP-level
+ // keep-alive is enabled, and client resets the connection,
+ // server won't get TCP FIN or RST and will keep the connection
+ // open forever. With TCP keep-alive, next keep-alive
+ // handshake will figure out that the client is down and
+ // will close the server end.
+ // Thanks to Igor Klopov who suggested the patch.
+ setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &on,
+ sizeof(on)) != 0 ||
+ bind(sock, &so.lsa.sa, sizeof(so.lsa)) != 0 ||
+ listen(sock, SOMAXCONN) != 0) {
+ closesocket(sock);
+ cry(fc(ctx), "%s: cannot bind to %.*s: %s", __func__,
+ (int) vec.len, vec.ptr, strerror(ERRNO));
+ success = 0;
+ } else if ((listener = (struct socket *)
+ calloc(1, sizeof(*listener))) == NULL) {
+ // NOTE(lsm): order is important: call cry before closesocket(),
+ // cause closesocket() alters the errno.
+ cry(fc(ctx), "%s: %s", __func__, strerror(ERRNO));
+ closesocket(sock);
+ success = 0;
+ } else {
+ *listener = so;
+ listener->sock = sock;
+ set_close_on_exec(listener->sock);
+ listener->next = ctx->listening_sockets;
+ ctx->listening_sockets = listener;
+ }
+ }
+
+ if (!success) {
+ close_all_listening_sockets(ctx);
+ }
+
+ return success;
+}
+
+static void log_header(const struct mg_connection *conn, const char *header,
+ FILE *fp) {
+ const char *header_value;
+
+ if ((header_value = mg_get_header(conn, header)) == NULL) {
+ (void) fprintf(fp, "%s", " -");
+ } else {
+ (void) fprintf(fp, " \"%s\"", header_value);
+ }
+}
+
+static void log_access(const struct mg_connection *conn) {
+ const struct mg_request_info *ri;
+ FILE *fp;
+ char date[64], src_addr[20];
+
+ fp = conn->ctx->config[ACCESS_LOG_FILE] == NULL ? NULL :
+ mg_fopen(conn->ctx->config[ACCESS_LOG_FILE], "a+");
+
+ if (fp == NULL)
+ return;
+
+ strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z",
+ localtime(&conn->birth_time));
+
+ ri = &conn->request_info;
+ flockfile(fp);
+
+ sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+ fprintf(fp, "%s - %s [%s] \"%s %s HTTP/%s\" %d %" INT64_FMT,
+ src_addr, ri->remote_user == NULL ? "-" : ri->remote_user, date,
+ ri->request_method ? ri->request_method : "-",
+ ri->uri ? ri->uri : "-", ri->http_version,
+ conn->status_code, conn->num_bytes_sent);
+ log_header(conn, "Referer", fp);
+ log_header(conn, "User-Agent", fp);
+ fputc('\n', fp);
+ fflush(fp);
+
+ funlockfile(fp);
+ fclose(fp);
+}
+
+// Verify given socket address against the ACL.
+// Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
+static int check_acl(struct mg_context *ctx, uint32_t remote_ip) {
+ int allowed, flag;
+ uint32_t net, mask;
+ struct vec vec;
+ const char *list = ctx->config[ACCESS_CONTROL_LIST];
+
+ // If any ACL is set, deny by default
+ allowed = list == NULL ? '+' : '-';
+
+ while ((list = next_option(list, &vec, NULL)) != NULL) {
+ flag = vec.ptr[0];
+ if ((flag != '+' && flag != '-') ||
+ parse_net(&vec.ptr[1], &net, &mask) == 0) {
+ cry(fc(ctx), "%s: subnet must be [+|-]x.x.x.x[/x]", __func__);
+ return -1;
+ }
+
+ if (net == (remote_ip & mask)) {
+ allowed = flag;
+ }
+ }
+
+ return allowed == '+';
+}
+
+static void add_to_set(SOCKET fd, fd_set *set, int *max_fd) {
+ FD_SET(fd, set);
+ if (fd > (SOCKET) *max_fd) {
+ *max_fd = (int) fd;
+ }
+}
+
+#if !defined(_WIN32)
+static int set_uid_option(struct mg_context *ctx) {
+ struct passwd *pw;
+ const char *uid = ctx->config[RUN_AS_USER];
+ int success = 0;
+
+ if (uid == NULL) {
+ success = 1;
+ } else {
+ if ((pw = getpwnam(uid)) == NULL) {
+ cry(fc(ctx), "%s: unknown user [%s]", __func__, uid);
+ } else if (setgid(pw->pw_gid) == -1) {
+ cry(fc(ctx), "%s: setgid(%s): %s", __func__, uid, strerror(errno));
+ } else if (setuid(pw->pw_uid) == -1) {
+ cry(fc(ctx), "%s: setuid(%s): %s", __func__, uid, strerror(errno));
+ } else {
+ success = 1;
+ }
+ }
+
+ return success;
+}
+#endif // !_WIN32
+
+#if !defined(NO_SSL)
+static pthread_mutex_t *ssl_mutexes;
+
+// Return OpenSSL error message
+static const char *ssl_error(void) {
+ unsigned long err;
+ err = ERR_get_error();
+ return err == 0 ? "" : ERR_error_string(err, NULL);
+}
+
+static void ssl_locking_callback(int mode, int mutex_num, const char *file,
+ int line) {
+ line = 0; // Unused
+ file = NULL; // Unused
+
+ if (mode & CRYPTO_LOCK) {
+ (void) pthread_mutex_lock(&ssl_mutexes[mutex_num]);
+ } else {
+ (void) pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
+ }
+}
+
+static unsigned long ssl_id_callback(void) {
+ return (unsigned long) pthread_self();
+}
+
+#if !defined(NO_SSL_DL)
+static int load_dll(struct mg_context *ctx, const char *dll_name,
+ struct ssl_func *sw) {
+ union {void *p; void (*fp)(void);} u;
+ void *dll_handle;
+ struct ssl_func *fp;
+
+ if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
+ cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
+ return 0;
+ }
+
+ for (fp = sw; fp->name != NULL; fp++) {
+#ifdef _WIN32
+ // GetProcAddress() returns pointer to function
+ u.fp = (void (*)(void)) dlsym(dll_handle, fp->name);
+#else
+ // dlsym() on UNIX returns void *. ISO C forbids casts of data pointers to
+ // function pointers. We need to use a union to make a cast.
+ u.p = dlsym(dll_handle, fp->name);
+#endif // _WIN32
+ if (u.fp == NULL) {
+ cry(fc(ctx), "%s: %s: cannot find %s", __func__, dll_name, fp->name);
+ return 0;
+ } else {
+ fp->ptr = u.fp;
+ }
+ }
+
+ return 1;
+}
+#endif // NO_SSL_DL
+
+// Dynamically load SSL library. Set up ctx->ssl_ctx pointer.
+static int set_ssl_option(struct mg_context *ctx) {
+ int i, size;
+ const char *pem;
+
+ // If PEM file is not specified, skip SSL initialization.
+ if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL) {
+ return 1;
+ }
+
+#if !defined(NO_SSL_DL)
+ if (!load_dll(ctx, SSL_LIB, ssl_sw) ||
+ !load_dll(ctx, CRYPTO_LIB, crypto_sw)) {
+ return 0;
+ }
+#endif // NO_SSL_DL
+
+ // Initialize SSL crap
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ if ((ctx->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
+ cry(fc(ctx), "SSL_CTX_new (client) error: %s", ssl_error());
+ }
+
+ if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
+ cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
+ return 0;
+ }
+
+ // If user callback returned non-NULL, that means that user callback has
+ // set up certificate itself. In this case, skip sertificate setting.
+ if (call_user(fc(ctx), MG_INIT_SSL) == NULL &&
+ (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, SSL_FILETYPE_PEM) == 0 ||
+ SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, SSL_FILETYPE_PEM) == 0)) {
+ cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error());
+ return 0;
+ }
+
+ if (pem != NULL) {
+ (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
+ }
+
+ // Initialize locking callbacks, needed for thread safety.
+ // http://www.openssl.org/support/faq.html#PROG1
+ size = sizeof(pthread_mutex_t) * CRYPTO_num_locks();
+ if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) {
+ cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error());
+ return 0;
+ }
+
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_init(&ssl_mutexes[i], NULL);
+ }
+
+ CRYPTO_set_locking_callback(&ssl_locking_callback);
+ CRYPTO_set_id_callback(&ssl_id_callback);
+
+ return 1;
+}
+
+static void uninitialize_ssl(struct mg_context *ctx) {
+ int i;
+ if (ctx->ssl_ctx != NULL) {
+ CRYPTO_set_locking_callback(NULL);
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_destroy(&ssl_mutexes[i]);
+ }
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_id_callback(NULL);
+ }
+}
+#endif // !NO_SSL
+
+static int set_gpass_option(struct mg_context *ctx) {
+ struct mgstat mgstat;
+ const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
+ return path == NULL || mg_stat(path, &mgstat) == 0;
+}
+
+static int set_acl_option(struct mg_context *ctx) {
+ return check_acl(ctx, (uint32_t) 0x7f000001UL) != -1;
+}
+
+static void reset_per_request_attributes(struct mg_connection *conn) {
+ conn->path_info = conn->log_message = NULL;
+ conn->num_bytes_sent = conn->consumed_content = 0;
+ conn->status_code = -1;
+ conn->must_close = conn->request_len = conn->throttle = 0;
+}
+
+static void close_socket_gracefully(struct mg_connection *conn) {
+ char buf[MG_BUF_LEN];
+ struct linger linger;
+ int n, sock = conn->client.sock;
+
+ // Set linger option to avoid socket hanging out after close. This prevent
+ // ephemeral port exhaust problem under high QPS.
+ linger.l_onoff = 1;
+ linger.l_linger = 1;
+ setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof(linger));
+
+ // Send FIN to the client
+ (void) shutdown(sock, SHUT_WR);
+ set_non_blocking_mode(sock);
+
+ // Read and discard pending incoming data. If we do not do that and close the
+ // socket, the data in the send buffer may be discarded. This
+ // behaviour is seen on Windows, when client keeps sending data
+ // when server decides to close the connection; then when client
+ // does recv() it gets no data back.
+ do {
+ n = pull(NULL, conn, buf, sizeof(buf));
+ } while (n > 0);
+
+ // Now we know that our FIN is ACK-ed, safe to close
+ (void) closesocket(sock);
+}
+
+static void close_connection(struct mg_connection *conn) {
+ if (conn->ssl) {
+ SSL_free(conn->ssl);
+ conn->ssl = NULL;
+ }
+
+ if (conn->client.sock != INVALID_SOCKET) {
+ close_socket_gracefully(conn);
+ }
+}
+
+void mg_close_connection(struct mg_connection *conn) {
+ close_connection(conn);
+ free(conn);
+}
+
+struct mg_connection *mg_connect(struct mg_context *ctx,
+ const char *host, int port, int use_ssl) {
+ struct mg_connection *newconn = NULL;
+ struct sockaddr_in sin;
+ struct hostent *he;
+ int sock;
+
+ if (use_ssl && (ctx == NULL || ctx->client_ssl_ctx == NULL)) {
+ cry(fc(ctx), "%s: SSL is not initialized", __func__);
+ } else if ((he = gethostbyname(host)) == NULL) {
+ cry(fc(ctx), "%s: gethostbyname(%s): %s", __func__, host, strerror(ERRNO));
+ } else if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
+ cry(fc(ctx), "%s: socket: %s", __func__, strerror(ERRNO));
+ } else {
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons((uint16_t) port);
+ sin.sin_addr = * (struct in_addr *) he->h_addr_list[0];
+ if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) != 0) {
+ cry(fc(ctx), "%s: connect(%s:%d): %s", __func__, host, port,
+ strerror(ERRNO));
+ closesocket(sock);
+ } else if ((newconn = (struct mg_connection *)
+ calloc(1, sizeof(*newconn))) == NULL) {
+ cry(fc(ctx), "%s: calloc: %s", __func__, strerror(ERRNO));
+ closesocket(sock);
+ } else {
+ newconn->ctx = ctx;
+ newconn->client.sock = sock;
+ newconn->client.rsa.sin = sin;
+ newconn->client.is_ssl = use_ssl;
+ if (use_ssl) {
+ sslize(newconn, ctx->client_ssl_ctx, SSL_connect);
+ }
+ }
+ }
+
+ return newconn;
+}
+
+FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path,
+ char *buf, size_t buf_len, struct mg_request_info *ri) {
+ struct mg_connection *newconn;
+ int n, req_length, data_length, port;
+ char host[1025], proto[10], buf2[MG_BUF_LEN];
+ FILE *fp = NULL;
+
+ if (sscanf(url, "%9[htps]://%1024[^:]:%d/%n", proto, host, &port, &n) == 3) {
+ } else if (sscanf(url, "%9[htps]://%1024[^/]/%n", proto, host, &n) == 2) {
+ port = mg_strcasecmp(proto, "https") == 0 ? 443 : 80;
+ } else {
+ cry(fc(ctx), "%s: invalid URL: [%s]", __func__, url);
+ return NULL;
+ }
+
+ if ((newconn = mg_connect(ctx, host, port,
+ !strcmp(proto, "https"))) == NULL) {
+ cry(fc(ctx), "%s: mg_connect(%s): %s", __func__, url, strerror(ERRNO));
+ } else {
+ mg_printf(newconn, "GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", url + n, host);
+ data_length = 0;
+ req_length = read_request(NULL, newconn, buf, buf_len, &data_length);
+ if (req_length <= 0) {
+ cry(fc(ctx), "%s(%s): invalid HTTP reply", __func__, url);
+ } else if (parse_http_response(buf, req_length, ri) <= 0) {
+ cry(fc(ctx), "%s(%s): cannot parse HTTP headers", __func__, url);
+ } else if ((fp = fopen(path, "w+b")) == NULL) {
+ cry(fc(ctx), "%s: fopen(%s): %s", __func__, path, strerror(ERRNO));
+ } else {
+ // Write chunk of data that may be in the user's buffer
+ data_length -= req_length;
+ if (data_length > 0 &&
+ fwrite(buf + req_length, 1, data_length, fp) != (size_t) data_length) {
+ cry(fc(ctx), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO));
+ fclose(fp);
+ fp = NULL;
+ }
+ // Read the rest of the response and write it to the file. Do not use
+ // mg_read() cause we didn't set newconn->content_len properly.
+ while (fp && (data_length = pull(0, newconn, buf2, sizeof(buf2))) > 0) {
+ if (fwrite(buf2, 1, data_length, fp) != (size_t) data_length) {
+ cry(fc(ctx), "%s: fwrite(%s): %s", __func__, path, strerror(ERRNO));
+ fclose(fp);
+ fp = NULL;
+ break;
+ }
+ }
+ }
+ mg_close_connection(newconn);
+ }
+
+ return fp;
+}
+
+static int is_valid_uri(const char *uri) {
+ // Conform to http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
+ // URI can be an asterisk (*) or should start with slash.
+ return uri[0] == '/' || (uri[0] == '*' && uri[1] == '\0');
+}
+
+static void process_new_connection(struct mg_connection *conn) {
+ struct mg_request_info *ri = &conn->request_info;
+ int keep_alive_enabled, discard_len;
+ const char *cl;
+
+ keep_alive_enabled = !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
+
+ do {
+ reset_per_request_attributes(conn);
+ conn->request_len = read_request(NULL, conn, conn->buf, conn->buf_size,
+ &conn->data_len);
+ assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
+ if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
+ send_http_error(conn, 413, "Request Too Large", "%s", "");
+ return;
+ } if (conn->request_len <= 0) {
+ return; // Remote end closed the connection
+ }
+ if (parse_http_request(conn->buf, conn->buf_size, ri) <= 0 ||
+ !is_valid_uri(ri->uri)) {
+ // Do not put garbage in the access log, just send it back to the client
+ send_http_error(conn, 400, "Bad Request",
+ "Cannot parse HTTP request: [%.*s]", conn->data_len, conn->buf);
+ conn->must_close = 1;
+ } else if (strcmp(ri->http_version, "1.0") &&
+ strcmp(ri->http_version, "1.1")) {
+ // Request seems valid, but HTTP version is strange
+ send_http_error(conn, 505, "HTTP version not supported", "%s", "");
+ log_access(conn);
+ } else {
+ // Request is valid, handle it
+ if ((cl = get_header(ri, "Content-Length")) != NULL) {
+ conn->content_len = strtoll(cl, NULL, 10);
+ } else if (!mg_strcasecmp(ri->request_method, "POST") ||
+ !mg_strcasecmp(ri->request_method, "PUT")) {
+ conn->content_len = -1;
+ } else {
+ conn->content_len = 0;
+ }
+ conn->birth_time = time(NULL);
+ handle_request(conn);
+ call_user(conn, MG_REQUEST_COMPLETE);
+ log_access(conn);
+ }
+ if (ri->remote_user != NULL) {
+ free((void *) ri->remote_user);
+ }
+
+ // Discard all buffered data for this request
+ discard_len = conn->content_len >= 0 &&
+ conn->request_len + conn->content_len < (int64_t) conn->data_len ?
+ (int) (conn->request_len + conn->content_len) : conn->data_len;
+ memmove(conn->buf, conn->buf + discard_len, conn->data_len - discard_len);
+ conn->data_len -= discard_len;
+ assert(conn->data_len >= 0);
+ assert(conn->data_len <= conn->buf_size);
+
+ } while (conn->ctx->stop_flag == 0 &&
+ keep_alive_enabled &&
+ conn->content_len >= 0 &&
+ should_keep_alive(conn));
+}
+
+// Worker threads take accepted socket from the queue
+static int consume_socket(struct mg_context *ctx, struct socket *sp) {
+ (void) pthread_mutex_lock(&ctx->mutex);
+ DEBUG_TRACE(("going idle"));
+
+ // If the queue is empty, wait. We're idle at this point.
+ while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) {
+ pthread_cond_wait(&ctx->sq_full, &ctx->mutex);
+ }
+
+ // If we're stopping, sq_head may be equal to sq_tail.
+ if (ctx->sq_head > ctx->sq_tail) {
+ // Copy socket from the queue and increment tail
+ *sp = ctx->queue[ctx->sq_tail % ARRAY_SIZE(ctx->queue)];
+ ctx->sq_tail++;
+ DEBUG_TRACE(("grabbed socket %d, going busy", sp->sock));
+
+ // Wrap pointers if needed
+ while (ctx->sq_tail > (int) ARRAY_SIZE(ctx->queue)) {
+ ctx->sq_tail -= ARRAY_SIZE(ctx->queue);
+ ctx->sq_head -= ARRAY_SIZE(ctx->queue);
+ }
+ }
+
+ (void) pthread_cond_signal(&ctx->sq_empty);
+ (void) pthread_mutex_unlock(&ctx->mutex);
+
+ return !ctx->stop_flag;
+}
+
+static void worker_thread(struct mg_context *ctx) {
+ struct mg_connection *conn;
+
+ conn = (struct mg_connection *) calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
+ if (conn == NULL) {
+ cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
+ } else {
+ conn->buf_size = MAX_REQUEST_SIZE;
+ conn->buf = (char *) (conn + 1);
+
+ // Call consume_socket() even when ctx->stop_flag > 0, to let it signal
+ // sq_empty condvar to wake up the master waiting in produce_socket()
+ while (consume_socket(ctx, &conn->client)) {
+ conn->birth_time = time(NULL);
+ conn->ctx = ctx;
+
+ // Fill in IP, port info early so even if SSL setup below fails,
+ // error handler would have the corresponding info.
+ // Thanks to Johannes Winkelmann for the patch.
+ // TODO(lsm): Fix IPv6 case
+ conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
+ memcpy(&conn->request_info.remote_ip,
+ &conn->client.rsa.sin.sin_addr.s_addr, 4);
+ conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
+ conn->request_info.is_ssl = conn->client.is_ssl;
+
+ if (!conn->client.is_ssl ||
+ (conn->client.is_ssl &&
+ sslize(conn, conn->ctx->ssl_ctx, SSL_accept))) {
+ process_new_connection(conn);
+ }
+
+ close_connection(conn);
+ }
+ free(conn);
+ }
+
+ // Signal master that we're done with connection and exiting
+ (void) pthread_mutex_lock(&ctx->mutex);
+ ctx->num_threads--;
+ (void) pthread_cond_signal(&ctx->cond);
+ assert(ctx->num_threads >= 0);
+ (void) pthread_mutex_unlock(&ctx->mutex);
+
+ DEBUG_TRACE(("exiting"));
+}
+
+// Master thread adds accepted socket to a queue
+static void produce_socket(struct mg_context *ctx, const struct socket *sp) {
+ (void) pthread_mutex_lock(&ctx->mutex);
+
+ // If the queue is full, wait
+ while (ctx->stop_flag == 0 &&
+ ctx->sq_head - ctx->sq_tail >= (int) ARRAY_SIZE(ctx->queue)) {
+ (void) pthread_cond_wait(&ctx->sq_empty, &ctx->mutex);
+ }
+
+ if (ctx->sq_head - ctx->sq_tail < (int) ARRAY_SIZE(ctx->queue)) {
+ // Copy socket to the queue and increment head
+ ctx->queue[ctx->sq_head % ARRAY_SIZE(ctx->queue)] = *sp;
+ ctx->sq_head++;
+ DEBUG_TRACE(("queued socket %d", sp->sock));
+ }
+
+ (void) pthread_cond_signal(&ctx->sq_full);
+ (void) pthread_mutex_unlock(&ctx->mutex);
+}
+
+static void accept_new_connection(const struct socket *listener,
+ struct mg_context *ctx) {
+ struct socket accepted;
+ char src_addr[20];
+ socklen_t len;
+ int allowed;
+
+ len = sizeof(accepted.rsa);
+ accepted.lsa = listener->lsa;
+ accepted.sock = accept(listener->sock, &accepted.rsa.sa, &len);
+ if (accepted.sock != INVALID_SOCKET) {
+ allowed = check_acl(ctx, ntohl(* (uint32_t *) &accepted.rsa.sin.sin_addr));
+ if (allowed) {
+ // Put accepted socket structure into the queue
+ DEBUG_TRACE(("accepted socket %d", accepted.sock));
+ accepted.is_ssl = listener->is_ssl;
+ produce_socket(ctx, &accepted);
+ } else {
+ sockaddr_to_string(src_addr, sizeof(src_addr), &accepted.rsa);
+ cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
+ (void) closesocket(accepted.sock);
+ }
+ }
+}
+
+static void master_thread(struct mg_context *ctx) {
+ fd_set read_set;
+ struct timeval tv;
+ struct socket *sp;
+ int max_fd;
+
+ // Increase priority of the master thread
+#if defined(_WIN32)
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
+#endif
+
+#if defined(ISSUE_317)
+ struct sched_param sched_param;
+ sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
+ pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
+#endif
+
+ while (ctx->stop_flag == 0) {
+ FD_ZERO(&read_set);
+ max_fd = -1;
+
+ // Add listening sockets to the read set
+ for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) {
+ add_to_set(sp->sock, &read_set, &max_fd);
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 200 * 1000;
+
+ if (select(max_fd + 1, &read_set, NULL, NULL, &tv) < 0) {
+#ifdef _WIN32
+ // On windows, if read_set and write_set are empty,
+ // select() returns "Invalid parameter" error
+ // (at least on my Windows XP Pro). So in this case, we sleep here.
+ mg_sleep(1000);
+#endif // _WIN32
+ } else {
+ for (sp = ctx->listening_sockets; sp != NULL; sp = sp->next) {
+ if (ctx->stop_flag == 0 && FD_ISSET(sp->sock, &read_set)) {
+ accept_new_connection(sp, ctx);
+ }
+ }
+ }
+ }
+ DEBUG_TRACE(("stopping workers"));
+
+ // Stop signal received: somebody called mg_stop. Quit.
+ close_all_listening_sockets(ctx);
+
+ // Wakeup workers that are waiting for connections to handle.
+ pthread_cond_broadcast(&ctx->sq_full);
+
+ // Wait until all threads finish
+ (void) pthread_mutex_lock(&ctx->mutex);
+ while (ctx->num_threads > 0) {
+ (void) pthread_cond_wait(&ctx->cond, &ctx->mutex);
+ }
+ (void) pthread_mutex_unlock(&ctx->mutex);
+
+ // All threads exited, no sync is needed. Destroy mutex and condvars
+ (void) pthread_mutex_destroy(&ctx->mutex);
+ (void) pthread_cond_destroy(&ctx->cond);
+ (void) pthread_cond_destroy(&ctx->sq_empty);
+ (void) pthread_cond_destroy(&ctx->sq_full);
+
+#if !defined(NO_SSL)
+ uninitialize_ssl(ctx);
+#endif
+ DEBUG_TRACE(("exiting"));
+
+ // Signal mg_stop() that we're done.
+ // WARNING: This must be the very last thing this
+ // thread does, as ctx becomes invalid after this line.
+ ctx->stop_flag = 2;
+}
+
+static void free_context(struct mg_context *ctx) {
+ int i;
+
+ // Deallocate config parameters
+ for (i = 0; i < NUM_OPTIONS; i++) {
+ if (ctx->config[i] != NULL)
+ free(ctx->config[i]);
+ }
+
+ // Deallocate SSL context
+ if (ctx->ssl_ctx != NULL) {
+ SSL_CTX_free(ctx->ssl_ctx);
+ }
+ if (ctx->client_ssl_ctx != NULL) {
+ SSL_CTX_free(ctx->client_ssl_ctx);
+ }
+#ifndef NO_SSL
+ if (ssl_mutexes != NULL) {
+ free(ssl_mutexes);
+ ssl_mutexes = NULL;
+ }
+#endif // !NO_SSL
+
+ // Deallocate context itself
+ free(ctx);
+}
+
+void mg_stop(struct mg_context *ctx) {
+ ctx->stop_flag = 1;
+
+ // Wait until mg_fini() stops
+ while (ctx->stop_flag != 2) {
+ (void) mg_sleep(10);
+ }
+ free_context(ctx);
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ (void) WSACleanup();
+#endif // _WIN32
+}
+
+struct mg_context *mg_start(mg_callback_t user_callback, void *user_data,
+ const char **options) {
+ struct mg_context *ctx;
+ const char *name, *value, *default_value;
+ int i;
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ WSADATA data;
+ WSAStartup(MAKEWORD(2,2), &data);
+ InitializeCriticalSection(&global_log_file_lock);
+#endif // _WIN32
+
+ // Allocate context and initialize reasonable general case defaults.
+ // TODO(lsm): do proper error handling here.
+ if ((ctx = (struct mg_context *) calloc(1, sizeof(*ctx))) == NULL) {
+ return NULL;
+ }
+ ctx->user_callback = user_callback;
+ ctx->user_data = user_data;
+
+ while (options && (name = *options++) != NULL) {
+ if ((i = get_option_index(name)) == -1) {
+ cry(fc(ctx), "Invalid option: %s", name);
+ free_context(ctx);
+ return NULL;
+ } else if ((value = *options++) == NULL) {
+ cry(fc(ctx), "%s: option value cannot be NULL", name);
+ free_context(ctx);
+ return NULL;
+ }
+ if (ctx->config[i] != NULL) {
+ cry(fc(ctx), "warning: %s: duplicate option", name);
+ }
+ ctx->config[i] = mg_strdup(value);
+ DEBUG_TRACE(("[%s] -> [%s]", name, value));
+ }
+
+ // Set default value if needed
+ for (i = 0; config_options[i * ENTRIES_PER_CONFIG_OPTION] != NULL; i++) {
+ default_value = config_options[i * ENTRIES_PER_CONFIG_OPTION + 2];
+ if (ctx->config[i] == NULL && default_value != NULL) {
+ ctx->config[i] = mg_strdup(default_value);
+ DEBUG_TRACE(("Setting default: [%s] -> [%s]",
+ config_options[i * ENTRIES_PER_CONFIG_OPTION + 1],
+ default_value));
+ }
+ }
+
+ // NOTE(lsm): order is important here. SSL certificates must
+ // be initialized before listening ports. UID must be set last.
+ if (!set_gpass_option(ctx) ||
+#if !defined(NO_SSL)
+ !set_ssl_option(ctx) ||
+#endif
+ !set_ports_option(ctx) ||
+#if !defined(_WIN32)
+ !set_uid_option(ctx) ||
+#endif
+ !set_acl_option(ctx)) {
+ free_context(ctx);
+ return NULL;
+ }
+
+#if !defined(_WIN32) && !defined(__SYMBIAN32__)
+ // Ignore SIGPIPE signal, so if browser cancels the request, it
+ // won't kill the whole process.
+ (void) signal(SIGPIPE, SIG_IGN);
+ // Also ignoring SIGCHLD to let the OS to reap zombies properly.
+ (void) signal(SIGCHLD, SIG_IGN);
+#endif // !_WIN32
+
+ (void) pthread_mutex_init(&ctx->mutex, NULL);
+ (void) pthread_cond_init(&ctx->cond, NULL);
+ (void) pthread_cond_init(&ctx->sq_empty, NULL);
+ (void) pthread_cond_init(&ctx->sq_full, NULL);
+
+ // Start master (listening) thread
+ mg_start_thread((mg_thread_func_t) master_thread, ctx);
+
+ // Start worker threads
+ for (i = 0; i < atoi(ctx->config[NUM_THREADS]); i++) {
+ if (mg_start_thread((mg_thread_func_t) worker_thread, ctx) != 0) {
+ cry(fc(ctx), "Cannot start worker thread: %d", ERRNO);
+ } else {
+ ctx->num_threads++;
+ }
+ }
+
+ return ctx;
+}
diff --git a/spectro/mongoose.h b/spectro/mongoose.h
new file mode 100644
index 0000000..708cf73
--- /dev/null
+++ b/spectro/mongoose.h
@@ -0,0 +1,308 @@
+// Copyright (c) 2004-2012 Sergey Lyubka
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#ifndef MONGOOSE_HEADER_INCLUDED
+#define MONGOOSE_HEADER_INCLUDED
+
+#include <stdio.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+struct mg_context; // Handle for the HTTP service itself
+struct mg_connection; // Handle for the individual connection
+
+
+// This structure contains information about the HTTP request.
+struct mg_request_info {
+ char *request_method; // "GET", "POST", etc
+ char *uri; // URL-decoded URI
+ char *http_version; // E.g. "1.0", "1.1"
+ char *query_string; // URL part after '?' (not including '?') or NULL
+ char *remote_user; // Authenticated user, or NULL if no auth used
+ long remote_ip; // Client's IP address
+ int remote_port; // Client's port
+ int is_ssl; // 1 if SSL-ed, 0 if not
+ int num_headers; // Number of headers
+ struct mg_header {
+ char *name; // HTTP header name
+ char *value; // HTTP header value
+ } http_headers[64]; // Maximum 64 headers
+};
+
+
+// Various events on which user-defined function is called by Mongoose.
+enum mg_event {
+ MG_NEW_REQUEST, // New HTTP request has arrived from the client
+ MG_REQUEST_COMPLETE, // Mongoose has finished handling the request
+ MG_HTTP_ERROR, // HTTP error must be returned to the client
+ MG_EVENT_LOG, // Mongoose logs an event, request_info.log_message
+ MG_INIT_SSL, // SSL initialization, sent before certificate setup
+ MG_WEBSOCKET_CONNECT, // Sent on HTTP connect, before websocket handshake.
+ // If user callback returns NULL, then mongoose proceeds
+ // with handshake, otherwise it closes the connection.
+ MG_WEBSOCKET_READY, // Handshake has been successfully completed.
+ MG_WEBSOCKET_MESSAGE, // Incoming message from the client
+ MG_WEBSOCKET_CLOSE, // Client has closed the connection
+};
+
+
+// Prototype for the user-defined function. Mongoose calls this function
+// on every MG_* event.
+//
+// Parameters:
+// event: which event has been triggered.
+// conn: opaque connection handler. Could be used to read, write data to the
+// client, etc. See functions below that have "mg_connection *" arg.
+//
+// Return:
+// If handler returns non-NULL, that means that handler has processed the
+// request by sending appropriate HTTP reply to the client. Mongoose treats
+// the request as served.
+// If handler returns NULL, that means that handler has not processed
+// the request. Handler must not send any data to the client in this case.
+// Mongoose proceeds with request handling as if nothing happened.
+typedef void *(*mg_callback_t)(enum mg_event event, struct mg_connection *conn);
+
+
+// Start web server.
+//
+// Parameters:
+// callback: user defined event handling function or NULL.
+// options: NULL terminated list of option_name, option_value pairs that
+// specify Mongoose configuration parameters.
+//
+// Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom
+// processing is required for these, signal handlers must be set up
+// after calling mg_start().
+//
+//
+// Example:
+// const char *options[] = {
+// "document_root", "/var/www",
+// "listening_ports", "80,443s",
+// NULL
+// };
+// struct mg_context *ctx = mg_start(&my_func, NULL, options);
+//
+// Please refer to http://code.google.com/p/mongoose/wiki/MongooseManual
+// for the list of valid option and their possible values.
+//
+// Return:
+// web server context, or NULL on error.
+struct mg_context *mg_start(mg_callback_t callback, void *user_data,
+ const char **options);
+
+
+// Stop the web server.
+//
+// Must be called last, when an application wants to stop the web server and
+// release all associated resources. This function blocks until all Mongoose
+// threads are stopped. Context pointer becomes invalid.
+void mg_stop(struct mg_context *);
+
+
+// Get the value of particular configuration parameter.
+// The value returned is read-only. Mongoose does not allow changing
+// configuration at run time.
+// If given parameter name is not valid, NULL is returned. For valid
+// names, return value is guaranteed to be non-NULL. If parameter is not
+// set, zero-length string is returned.
+const char *mg_get_option(const struct mg_context *ctx, const char *name);
+
+
+// Return array of strings that represent valid configuration options.
+// For each option, a short name, long name, and default value is returned.
+// Array is NULL terminated.
+const char **mg_get_valid_option_names(void);
+
+
+// Add, edit or delete the entry in the passwords file.
+//
+// This function allows an application to manipulate .htpasswd files on the
+// fly by adding, deleting and changing user records. This is one of the
+// several ways of implementing authentication on the server side. For another,
+// cookie-based way please refer to the examples/chat.c in the source tree.
+//
+// If password is not NULL, entry is added (or modified if already exists).
+// If password is NULL, entry is deleted.
+//
+// Return:
+// 1 on success, 0 on error.
+int mg_modify_passwords_file(const char *passwords_file_name,
+ const char *domain,
+ const char *user,
+ const char *password);
+
+
+// Return information associated with the request.
+// These functions always succeed.
+const struct mg_request_info *mg_get_request_info(const struct mg_connection *);
+void *mg_get_user_data(struct mg_connection *);
+const char *mg_get_log_message(const struct mg_connection *);
+int mg_get_reply_status_code(const struct mg_connection *);
+void *mg_get_ssl_context(const struct mg_connection *);
+
+
+// Send data to the client.
+// Return:
+// 0 when the connection has been closed
+// -1 on error
+// number of bytes written on success
+int mg_write(struct mg_connection *, const void *buf, size_t len);
+
+
+// Send data to the browser using printf() semantics.
+//
+// Works exactly like mg_write(), but allows to do message formatting.
+// Below are the macros for enabling compiler-specific checks for
+// printf-like arguments.
+
+#undef PRINTF_FORMAT_STRING
+#if _MSC_VER >= 1400
+#include <sal.h>
+#if _MSC_VER > 1400
+#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
+#else
+#define PRINTF_FORMAT_STRING(s) __format_string s
+#endif
+#else
+#define PRINTF_FORMAT_STRING(s) s
+#endif
+
+#ifdef __GNUC__
+#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
+#else
+#define PRINTF_ARGS(x, y)
+#endif
+
+int mg_printf(struct mg_connection *,
+ PRINTF_FORMAT_STRING(const char *fmt), ...) PRINTF_ARGS(2, 3);
+
+
+// Send contents of the entire file together with HTTP headers.
+void mg_send_file(struct mg_connection *conn, const char *path);
+
+
+// Read data from the remote end, return number of bytes read.
+int mg_read(struct mg_connection *, void *buf, size_t len);
+
+
+// Get the value of particular HTTP header.
+//
+// This is a helper function. It traverses request_info->http_headers array,
+// and if the header is present in the array, returns its value. If it is
+// not present, NULL is returned.
+const char *mg_get_header(const struct mg_connection *, const char *name);
+
+
+// Get a value of particular form variable.
+//
+// Parameters:
+// data: pointer to form-uri-encoded buffer. This could be either POST data,
+// or request_info.query_string.
+// data_len: length of the encoded data.
+// var_name: variable name to decode from the buffer
+// buf: destination buffer for the decoded variable
+// buf_len: length of the destination buffer
+//
+// Return:
+// On success, length of the decoded variable.
+// On error:
+// -1 (variable not found, or destination buffer is too small).
+// -2 (destination buffer is NULL or zero length).
+//
+// Destination buffer is guaranteed to be '\0' - terminated if it is not
+// NULL or zero length. In case of failure, dst[0] == '\0'.
+int mg_get_var(const char *data, size_t data_len,
+ const char *var_name, char *buf, size_t buf_len);
+
+// Fetch value of certain cookie variable into the destination buffer.
+//
+// Destination buffer is guaranteed to be '\0' - terminated. In case of
+// failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
+// parameter. This function returns only first occurrence.
+//
+// Return:
+// On success, value length.
+// On error, -1 (either "Cookie:" header is not present at all, or the
+// requested parameter is not found, or destination buffer is too small
+// to hold the value).
+int mg_get_cookie(const struct mg_connection *,
+ const char *cookie_name, char *buf, size_t buf_len);
+
+
+// Connect to the remote web server.
+// Return:
+// On success, valid pointer to the new connection
+// On error, NULL
+struct mg_connection *mg_connect(struct mg_context *ctx,
+ const char *host, int port, int use_ssl);
+
+
+// Close the connection opened by mg_connect().
+void mg_close_connection(struct mg_connection *conn);
+
+
+// Download given URL to a given file.
+// url: URL to download
+// path: file name where to save the data
+// request_info: pointer to a structure that will hold parsed reply headers
+// buf, bul_len: a buffer for the reply headers
+// Return:
+// On error, NULL
+// On success, opened file stream to the downloaded contents. The stream
+// is positioned to the end of the file. It is the user's responsibility
+// to fclose() the opened file stream.
+FILE *mg_fetch(struct mg_context *ctx, const char *url, const char *path,
+ char *buf, size_t buf_len, struct mg_request_info *request_info);
+
+
+// Convenience function -- create detached thread.
+// Return: 0 on success, non-0 on error.
+typedef void * (*mg_thread_func_t)(void *);
+int mg_start_thread(mg_thread_func_t f, void *p);
+
+
+// Return builtin mime type for the given file name.
+// For unrecognized extensions, "text/plain" is returned.
+const char *mg_get_builtin_mime_type(const char *file_name);
+
+
+// Return Mongoose version.
+const char *mg_version(void);
+
+
+// MD5 hash given strings.
+// Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
+// ASCIIz strings. When function returns, buf will contain human-readable
+// MD5 hash. Example:
+// char buf[33];
+// mg_md5(buf, "aa", "bb", NULL);
+void mg_md5(char buf[33], ...);
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // MONGOOSE_HEADER_INCLUDED
diff --git a/spectro/munki.c b/spectro/munki.c
new file mode 100644
index 0000000..6fa898e
--- /dev/null
+++ b/spectro/munki.c
@@ -0,0 +1,940 @@
+
+ /* X-Rite ColorMunki related functions */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/1/2009
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * (Based on i1pro.c)
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "munki.h"
+#include "munki_imp.h"
+
+#define MAX_MES_SIZE 500 /* Maximum normal message reply size */
+#define MAX_RD_SIZE 5000 /* Maximum reading messagle reply size */
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code munki_interp_code(munki *p, munki_code ec);
+
+/* ------------------------------------------------------------------------ */
+
+/* Establish communications with a Munki */
+/* If it's a serial port, use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+munki_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ munki *p = (munki *) pp;
+ int se;
+ icomuflags usbflags = icomuf_none;
+#ifdef __APPLE__
+ /* If the ColorMunki software has been installed, then there will */
+ /* be a daemon process that has the device open. Kill that process off */
+ /* so that we can open it here, before it re-spawns. */
+ char *pnames[] = {
+ "ninjad",
+ "ColorMunkiDeviceService",
+ NULL
+ };
+ int retries = 20;
+#else /* !__APPLE__ */
+ char **pnames = NULL;
+ int retries = 0;
+#endif /* !__APPLE__ */
+
+ a1logd(p->log, 2, "munki_init_coms: called\n");
+
+ if (p->icom->port_type(p->icom) != icomt_usb) {
+ a1logd(p->log, 1, "munki_init_coms: wrong sort of coms!\n");
+ return munki_interp_code(p, MUNKI_UNKNOWN_MODEL);
+ }
+
+ a1logd(p->log, 2, "munki_init_coms: about to init USB\n");
+
+ /* Set config, interface, write end point, read end point, read quanta */
+ /* ("serial" end points aren't used - the Munki uses USB control messages) */
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, retries, pnames))
+ != ICOM_OK) {
+ a1logd(p->log, 1, "munki_init_coms: failed ICOM err 0x%x\n",se);
+ return munki_interp_code(p, icoms2munki_err(se));
+ }
+
+ a1logd(p->log, 2, "munki_init_coms: init coms has suceeded\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+static inst_code
+munki_determine_capabilities(munki *p) {
+
+ /* Set the Munki capabilities mask */
+ p->cap = inst_mode_ref_spot
+ | inst_mode_ref_strip
+ | inst_mode_emis_spot
+ | inst_mode_emis_tele
+ | inst_mode_trans_spot /* Support this manually using a light table */
+ | inst_mode_trans_strip
+ | inst_mode_emis_strip /* Also likely to be light table reading */
+ | inst_mode_emis_ambient
+ | inst_mode_emis_ambient_flash
+ | inst_mode_emis_nonadaptive
+ | inst_mode_colorimeter
+ | inst_mode_spectral
+ | inst_mode_calibration /* Can indicate cal configuration */
+ ;
+
+ if (munki_imp_highres(p)) /* Static */
+ p->cap |= inst_mode_highres;
+
+ p->cap2 = inst2_prog_trig
+ | inst2_user_trig
+ | inst2_user_switch_trig
+ | inst2_bidi_scan
+ | inst2_has_scan_toll
+ | inst2_no_feedback
+ | inst2_has_leds
+ | inst2_has_sensmode
+ ;
+
+ if (p->m != NULL) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ if (s->emiss)
+ p->cap2 |= inst2_emis_refr_meas;
+ }
+
+ p->cap3 = inst3_none;
+
+ return inst_ok;
+}
+
+/* Return current or given configuration available measurement modes. */
+static inst_code munki_meas_config(
+inst *pp,
+inst_mode *mmodes,
+inst_cal_cond *cconds,
+int *conf_ix
+) {
+ munki *p = (munki *)pp;
+ munki_code ev;
+ mk_spos spos;
+
+ if (mmodes != NULL)
+ *mmodes = inst_mode_none;
+ if (cconds != NULL)
+ *cconds = inst_calc_none;
+
+ if (conf_ix == NULL
+ || *conf_ix < mk_spos_proj
+ || *conf_ix > mk_spos_amb) {
+ /* Return current configuration measrement modes */
+ ev = munki_getstatus(p, &spos, NULL);
+ if (ev != MUNKI_OK)
+ return munki_interp_code(p, ev);
+ } else {
+ /* Return given configuration measurement modes */
+ spos = *conf_ix;
+ }
+
+ if (spos == mk_spos_proj) {
+ if (mmodes != NULL)
+ *mmodes = inst_mode_emis_tele;
+ } else if (spos == mk_spos_surf) {
+ if (mmodes != NULL)
+ *mmodes = inst_mode_ref_spot
+ | inst_mode_ref_strip
+ | inst_mode_emis_spot
+ | inst_mode_trans_spot
+ | inst_mode_trans_strip;
+ } else if (spos == mk_spos_calib) {
+ if (cconds != NULL)
+ *cconds = inst_calc_man_cal_smode;
+ if (mmodes != NULL)
+ *mmodes = inst_mode_calibration;
+ } else if (spos == mk_spos_amb) {
+ if (mmodes != NULL)
+ *mmodes = inst_mode_emis_ambient
+ | inst_mode_emis_ambient_flash;
+ }
+
+ /* Return configuration index returned */
+ if (conf_ix != NULL)
+ *conf_ix = (int)spos;
+
+ /* Add the extra dependent and independent modes */
+ if (mmodes != NULL)
+ *mmodes |= inst_mode_emis_nonadaptive
+ | inst_mode_colorimeter
+ | inst_mode_spectral;
+
+ return inst_ok;
+}
+
+
+/* Initialise the MUNKI */
+/* return non-zero on an error, with dtp error code */
+static inst_code
+munki_init_inst(inst *pp) {
+ munki *p = (munki *)pp;
+ munki_code ev = MUNKI_OK;
+
+ a1logd(p->log, 2, "munki_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return munki_interp_code(p, MUNKI_INT_NO_COMS); /* Must establish coms before calling init */
+ if ((ev = munki_imp_init(p)) != MUNKI_OK) {
+ a1logd(p->log, 1, "munki_init_inst: failed with 0x%x\n",ev);
+ return munki_interp_code(p, ev);
+ }
+
+ p->inited = 1;
+ a1logd(p->log, 2, "munki_init_inst: instrument inited OK\n");
+
+ munki_determine_capabilities(p);
+
+ return munki_interp_code(p, ev);
+}
+
+static char *munki_get_serial_no(inst *pp) {
+ munki *p = (munki *)pp;
+
+ if (!p->gotcoms)
+ return "";
+ if (!p->inited)
+ return "";
+
+ return munki_imp_get_serial_no(p);
+}
+
+/* Read a set of strips */
+/* Return the dtp error code */
+static inst_code
+munki_read_strip(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (3 chars) */
+int sguide, /* Guide number */
+double pwid, /* Patch length in mm (DTP41) */
+double gwid, /* Gap length in mm (DTP41) */
+double twid, /* Trailer length in mm (DTP41T) */
+ipatch *vals) { /* Pointer to array of instrument patch values */
+ munki *p = (munki *)pp;
+ munki_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ rv = munki_imp_measure(p, vals, npatch, 1);
+
+ return munki_interp_code(p, rv);
+}
+
+/* Read a single sample */
+/* Return the dtp error code */
+static inst_code
+munki_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* Clamp XYZ/Lab to be +ve */
+ munki *p = (munki *)pp;
+ munki_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ rv = munki_imp_measure(p, val, 1, clamp);
+
+ return munki_interp_code(p, rv);
+}
+
+/* Read an emissive refresh rate */
+static inst_code
+munki_read_refrate(
+inst *pp,
+double *ref_rate) {
+ munki *p = (munki *)pp;
+ munki_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ rv = munki_imp_meas_refrate(p, ref_rate);
+
+ return munki_interp_code(p, rv);
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code munki_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ munki *p = (munki *)pp;
+ munki_code rv;
+
+ rv = munki_imp_get_n_a_cals(p, pn_cals, pa_cals);
+ return munki_interp_code(p, rv);
+}
+
+/* Request an instrument calibration. */
+inst_code munki_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ munki *p = (munki *)pp;
+ munki_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ rv = munki_imp_calibrate(p, calt, calc, id);
+
+ return munki_interp_code(p, rv);
+}
+
+/* Instrument specific error codes interpretation */
+static char *
+munki_interp_error(inst *pp, munki_code ec) {
+// munki *p = (munki *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case MUNKI_INTERNAL_ERROR:
+ return "Internal software error";
+ case MUNKI_COMS_FAIL:
+ return "Communications failure";
+ case MUNKI_UNKNOWN_MODEL:
+ return "Not an i1 Pro";
+ case MUNKI_DATA_PARSE_ERROR:
+ return "Data from i1 Display didn't parse as expected";
+
+ case MUNKI_USER_ABORT:
+ return "User abort";
+
+ case MUNKI_USER_TRIG:
+ return "User trigger";
+
+ case MUNKI_UNSUPPORTED:
+ return "Unsupported function";
+ case MUNKI_CAL_SETUP:
+ return "Calibration retry with correct setup is needed";
+
+ case MUNKI_OK:
+ return "No device error";
+
+ case MUNKI_DATA_RANGE:
+ return "EEProm data count location out of range";
+ case MUNKI_DATA_MEMORY:
+ return "EEProm memory alloc failure";
+
+ case MUNKI_HW_EE_SHORTREAD:
+ return "Read less bytes for EEProm read than expected";
+ case MUNKI_HW_ME_SHORTREAD:
+ return "Read less bytes for measurement read than expected";
+ case MUNKI_HW_ME_ODDREAD:
+ return "Read a number of bytes not a multiple of 274";
+ case MUNKI_HW_CALIBVERSION:
+ return "Instrument calibration version is unknown";
+ case MUNKI_HW_CALIBMATCH:
+ return "Calibration doesn't match device";
+
+ case MUNKI_RD_DARKREADINCONS:
+ return "Dark calibration reading is inconsistent";
+ case MUNKI_RD_SENSORSATURATED:
+ return "Sensor is saturated";
+ case MUNKI_RD_DARKNOTVALID:
+ return "Dark reading is not valid (too light)";
+ case MUNKI_RD_NEEDS_CAL:
+ return "Mode needs calibration";
+ case MUNKI_RD_WHITEREADINCONS:
+ return "White calibration reading is inconsistent";
+ case MUNKI_RD_WHITEREFERROR:
+ return "White reference reading error";
+ case MUNKI_RD_LIGHTTOOLOW:
+ return "Light level is too low";
+ case MUNKI_RD_LIGHTTOOHIGH:
+ return "Light level is too high";
+ case MUNKI_RD_SHORTMEAS:
+ return "Reading is too short";
+ case MUNKI_RD_READINCONS:
+ return "Reading is inconsistent";
+ case MUNKI_RD_REFWHITENOCONV:
+ return "White reference calibration didn't converge";
+ case MUNKI_RD_NOTENOUGHPATCHES:
+ return "Not enough patches";
+ case MUNKI_RD_TOOMANYPATCHES:
+ return "Too many patches";
+ case MUNKI_RD_NOTENOUGHSAMPLES:
+ return "Not enough samples per patch";
+ case MUNKI_RD_NOFLASHES:
+ return "No flashes recognized";
+ case MUNKI_RD_NOAMBB4FLASHES:
+ return "No ambient found before first flash";
+ case MUNKI_RD_NOREFR_FOUND:
+ return "No refresh rate detected or failed to measure it";
+
+ case MUNKI_SPOS_PROJ:
+ return "Sensor should be in projector position";
+ case MUNKI_SPOS_SURF:
+ return "Sensor should be in surface position";
+ case MUNKI_SPOS_CALIB:
+ return "Sensor should be in calibration position";
+ case MUNKI_SPOS_AMB:
+ return "Sensor should be in ambient position";
+
+ case MUNKI_INT_NO_COMS:
+ return "Communications hasn't been established";
+ case MUNKI_INT_EESIZE:
+ return "EEProm is not the expected size";
+ case MUNKI_INT_EEOUTOFRANGE:
+ return "EEProm access is out of range";
+ case MUNKI_INT_CALTOOSMALL:
+ return "EEProm calibration data is too short";
+ case MUNKI_INT_CALTOOBIG:
+ return "EEProm calibration data is too long";
+ case MUNKI_INT_CALBADCHSUM:
+ return "Calibration data has a bad checksum";
+ case MUNKI_INT_ODDREADBUF:
+ return "Measurement read buffer is not a multiple of 274";
+ case MUNKI_INT_INTTOOBIG:
+ return "Integration time is too big";
+ case MUNKI_INT_INTTOOSMALL:
+ return "Integration time is too small";
+ case MUNKI_INT_ILLEGALMODE:
+ return "Illegal measurement mode selected";
+ case MUNKI_INT_ZEROMEASURES:
+ return "Number of measurements requested is zero";
+ case MUNKI_INT_WRONGPATCHES:
+ return "Number of patches to match is wrong";
+ case MUNKI_INT_MEASBUFFTOOSMALL:
+ return "Measurement exceeded read buffer";
+ case MUNKI_INT_NOTIMPLEMENTED:
+ return "Support not implemented";
+ case MUNKI_INT_NOTCALIBRATED:
+ return "Unexpectedely invalid calibration";
+ case MUNKI_INT_THREADFAILED:
+ return "Creation of thread failed";
+ case MUNKI_INT_BUTTONTIMEOUT:
+ return "Button status read timed out";
+ case MUNKI_INT_CIECONVFAIL:
+ return "Creating spectral to CIE converted failed";
+ case MUNKI_INT_MALLOC:
+ return "Error in allocating memory";
+ case MUNKI_INT_CREATE_EEPROM_STORE:
+ return "Error in creating EEProm store";
+ case MUNKI_INT_NEW_RSPL_FAILED:
+ return "Creating RSPL object faild";
+ case MUNKI_INT_CAL_SAVE:
+ return "Unable to save calibration to file";
+ case MUNKI_INT_CAL_RESTORE:
+ return "Unable to restore calibration from file";
+ case MUNKI_INT_CAL_TOUCH:
+ return "Unable to update calibration file modification time";
+ case MUNKI_INT_ASSERT:
+ return "Assert fail";
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+munki_interp_code(munki *p, munki_code ec) {
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case MUNKI_OK:
+
+ return inst_ok;
+
+ case MUNKI_COMS_FAIL:
+ return inst_coms_fail | ec;
+
+ case MUNKI_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+ case MUNKI_DATA_PARSE_ERROR:
+ return inst_protocol_error | ec;
+
+ case MUNKI_USER_ABORT:
+ return inst_user_abort;
+
+ case MUNKI_USER_TRIG:
+ return inst_user_trig;
+
+ case MUNKI_UNSUPPORTED:
+ return inst_unsupported | ec;
+
+ case MUNKI_RD_NEEDS_CAL:
+ return inst_needs_cal | ec;
+
+ case MUNKI_CAL_SETUP:
+ case MUNKI_SPOS_CALIB:
+ return inst_cal_setup | ec;
+
+ case MUNKI_SPOS_PROJ:
+ case MUNKI_SPOS_SURF:
+ case MUNKI_SPOS_AMB:
+ return inst_wrong_config | ec;
+
+ case MUNKI_DATA_RANGE:
+ case MUNKI_DATA_MEMORY:
+ case MUNKI_HW_EE_SHORTREAD:
+ case MUNKI_HW_ME_SHORTREAD:
+ case MUNKI_HW_ME_ODDREAD:
+ case MUNKI_HW_CALIBVERSION:
+ case MUNKI_HW_CALIBMATCH:
+ return inst_hardware_fail | ec;
+
+ case MUNKI_RD_DARKREADINCONS:
+ case MUNKI_RD_SENSORSATURATED:
+ case MUNKI_RD_DARKNOTVALID:
+ case MUNKI_RD_WHITEREADINCONS:
+ case MUNKI_RD_WHITEREFERROR:
+ case MUNKI_RD_LIGHTTOOLOW:
+ case MUNKI_RD_LIGHTTOOHIGH:
+ case MUNKI_RD_SHORTMEAS:
+ case MUNKI_RD_READINCONS:
+ case MUNKI_RD_REFWHITENOCONV:
+ case MUNKI_RD_NOTENOUGHPATCHES:
+ case MUNKI_RD_TOOMANYPATCHES:
+ case MUNKI_RD_NOTENOUGHSAMPLES:
+ case MUNKI_RD_NOFLASHES:
+ case MUNKI_RD_NOAMBB4FLASHES:
+ case MUNKI_RD_NOREFR_FOUND:
+ return inst_misread | ec;
+
+ case MUNKI_INTERNAL_ERROR:
+ case MUNKI_INT_NO_COMS:
+ case MUNKI_INT_EESIZE:
+ case MUNKI_INT_EEOUTOFRANGE:
+ case MUNKI_INT_CALTOOSMALL:
+ case MUNKI_INT_CALTOOBIG:
+ case MUNKI_INT_CALBADCHSUM:
+ case MUNKI_INT_ODDREADBUF:
+ case MUNKI_INT_INTTOOBIG:
+ case MUNKI_INT_INTTOOSMALL:
+ case MUNKI_INT_ILLEGALMODE:
+ case MUNKI_INT_ZEROMEASURES:
+ case MUNKI_INT_MEASBUFFTOOSMALL:
+ case MUNKI_INT_NOTIMPLEMENTED:
+ case MUNKI_INT_NOTCALIBRATED:
+ case MUNKI_INT_THREADFAILED:
+ case MUNKI_INT_BUTTONTIMEOUT:
+ case MUNKI_INT_CIECONVFAIL:
+ case MUNKI_INT_MALLOC:
+ case MUNKI_INT_CREATE_EEPROM_STORE:
+ case MUNKI_INT_NEW_RSPL_FAILED:
+ case MUNKI_INT_CAL_SAVE:
+ case MUNKI_INT_CAL_RESTORE:
+ case MUNKI_INT_CAL_TOUCH:
+ case MUNKI_INT_WRONGPATCHES:
+ case MUNKI_INT_ASSERT:
+ return inst_internal_error | ec;
+ }
+ return inst_other_error | ec;
+}
+
+/* Convert instrument specific inst_wrong_config error to inst_config enum */
+static inst_config munki_config_enum(inst *pp, int ec) {
+// munki *p = (munki *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case MUNKI_SPOS_PROJ:
+ return inst_conf_projector;
+
+ case MUNKI_SPOS_SURF:
+ return inst_conf_surface;
+
+ case MUNKI_SPOS_AMB:
+ return inst_conf_ambient;
+
+ case MUNKI_SPOS_CALIB:
+ return inst_conf_calibration;
+ }
+ return inst_conf_unknown;
+}
+
+/* Return the instrument capabilities */
+void munki_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ munki *p = (munki *)pp;
+
+ if (pcap1 != NULL)
+ *pcap1 = p->cap;
+ if (pcap2 != NULL)
+ *pcap2 = p->cap2;
+ if (pcap3 != NULL)
+ *pcap3 = p->cap3;
+
+ return;
+}
+
+/* Return the corresponding munki measurement mode, */
+/* or mk_no_modes if invalid */
+static mk_mode munki_convert_mode(munki *p, inst_mode m) {
+ mk_mode mmode = 0;
+
+ /* Simple test */
+ if (m & ~p->cap)
+ return mk_no_modes;
+
+ if (IMODETST(m, inst_mode_ref_spot)) {
+ mmode = mk_refl_spot;
+ } else if (IMODETST(m, inst_mode_ref_strip)) {
+ mmode = mk_refl_scan;
+ } else if (IMODETST(m, inst_mode_trans_spot)) {
+ mmode = mk_trans_spot;
+ } else if (IMODETST(m, inst_mode_trans_strip)) {
+ mmode = mk_trans_scan;
+ } else if (IMODETST(m, inst_mode_emis_spot)) {
+ if (IMODETST(m, inst_mode_emis_nonadaptive))
+ mmode = mk_emiss_spot_na;
+ else
+ mmode = mk_emiss_spot;
+ } else if (IMODETST(m, inst_mode_emis_tele)) {
+ if (IMODETST(m, inst_mode_emis_nonadaptive))
+ mmode = mk_tele_spot_na;
+ else
+ mmode = mk_tele_spot;
+ } else if (IMODETST(m, inst_mode_emis_strip)) {
+ mmode = mk_emiss_scan;
+ } else if (IMODETST(m, inst_mode_emis_ambient)) {
+ mmode = mk_amb_spot;
+ } else if (IMODETST(m, inst_mode_emis_ambient_flash)) {
+ mmode = mk_amb_flash;
+ } else {
+ return mk_no_modes;
+ }
+
+ return mmode;
+}
+
+/* Check device measurement mode */
+inst_code munki_check_mode(inst *pp, inst_mode m) {
+ munki *p = (munki *)pp;
+ mk_mode mmode = 0;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (munki_convert_mode(p, m) == mk_no_modes)
+ return inst_unsupported;
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code munki_set_mode(inst *pp, inst_mode m) {
+ munki *p = (munki *)pp;
+ mk_mode mmode = 0;
+ inst_mode cap = p->cap;
+ inst_code rv;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if ((mmode = munki_convert_mode(p, m)) == mk_no_modes)
+ return inst_unsupported;
+
+ if ((rv = munki_interp_code(p, munki_imp_set_mode(p, mmode, m & inst_mode_spectral)))
+ != inst_ok)
+ return rv;
+
+ munki_determine_capabilities(p);
+
+ return inst_ok;
+}
+
+/*
+ * set or reset an optional mode
+ *
+ * Some options talk to the instrument, and these will
+ * error if it hasn't been initialised.
+ */
+static inst_code
+munki_get_set_opt(inst *pp, inst_opt_type m, ...) {
+ munki *p = (munki *)pp;
+
+ if (m == inst_opt_noinitcalib) {
+ va_list args;
+ int losecs = 0;
+
+ va_start(args, m);
+ losecs = va_arg(args, int);
+ va_end(args);
+
+ munki_set_noinitcalib(p, 1, losecs);
+ return inst_ok;
+
+ } else if (m == inst_opt_initcalib) {
+ munki_set_noinitcalib(p, 0, 0);
+ return inst_ok;
+
+ /* Record the trigger mode */
+ } else if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user
+ || m == inst_opt_trig_user_switch) {
+ munki_set_trig(p, m);
+ return inst_ok;
+ }
+
+ if (m == inst_opt_scan_toll) {
+ va_list args;
+ double toll_ratio = 1.0;
+
+ va_start(args, m);
+ toll_ratio = va_arg(args, double);
+ va_end(args);
+ return munki_interp_code(p, munki_set_scan_toll(p, toll_ratio));
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Not sure if hires can be set before init */
+ if (m == inst_opt_highres) {
+ return munki_interp_code(p, munki_set_highres(p));
+ } else if (m == inst_opt_stdres) {
+ return munki_interp_code(p, munki_set_stdres(p));
+ }
+
+ if (m == inst_opt_get_gen_ledmask) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = 0x1; /* One general LED */
+ return inst_ok;
+ } else if (m == inst_opt_set_led_state) {
+ va_list args;
+ int mask = 0;
+
+ va_start(args, m);
+ mask = 1 & va_arg(args, int);
+ va_end(args);
+ if (mask & 1) {
+ p->led_period = 1.0;
+ p->led_on_time_prop = 1.0;
+ p->led_trans_time_prop = 0.0;
+ return munki_interp_code(p, munki_setindled(p, 1000,0,0,-1,0));
+ } else {
+ p->led_period = 0.0;
+ p->led_on_time_prop = 0.0;
+ p->led_trans_time_prop = 0.0;
+ return munki_interp_code(p, munki_setindled(p, 0,0,0,0,0));
+ }
+ } else if (m == inst_opt_get_led_state) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ if (mask != NULL) *mask = p->led_state;
+ return inst_ok;
+ }
+
+ if (m == inst_opt_get_pulse_ledmask) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = 0x1; /* General LED is pulsable */
+ return inst_ok;
+ } else if (m == inst_opt_set_led_pulse_state) {
+ va_list args;
+ double period, on_time_prop, trans_time_prop;
+ int ontime, offtime, transtime, nopulses;
+
+ va_start(args, m);
+ period = va_arg(args, double);
+ on_time_prop = va_arg(args, double);
+ trans_time_prop = va_arg(args, double);
+ va_end(args);
+ if (period < 0.0
+ || on_time_prop < 0.0 || on_time_prop > 1.0
+ || trans_time_prop < 0.0 || trans_time_prop > 1.0
+ || trans_time_prop > on_time_prop || trans_time_prop > (1.0 - on_time_prop))
+ return inst_bad_parameter;
+ ontime = (int)(1000.0 * period * (on_time_prop - trans_time_prop) + 0.5);
+ offtime = (int)(1000.0 * period * (1.0 - on_time_prop - trans_time_prop) + 0.5);
+ transtime = (int)(1000.0 * period * trans_time_prop + 0.5);
+ nopulses = -1;
+ if (period == 0.0 || on_time_prop == 0.0) {
+ ontime = offtime = transtime = nopulses = 0;
+ p->led_state = 0;
+ } else {
+ p->led_state = 1;
+ }
+ p->led_period = period;
+ p->led_on_time_prop = on_time_prop;
+ p->led_trans_time_prop = trans_time_prop;
+ return munki_interp_code(p, munki_setindled(p, ontime,offtime,transtime,nopulses,0));
+ } else if (m == inst_opt_get_led_state) {
+ va_list args;
+ double *period, *on_time_prop, *trans_time_prop;
+
+ va_start(args, m);
+ period = va_arg(args, double *);
+ on_time_prop = va_arg(args, double *);
+ trans_time_prop = va_arg(args, double *);
+ va_end(args);
+ if (period != NULL) *period = p->led_period;
+ if (on_time_prop != NULL) *on_time_prop = p->led_on_time_prop;
+ if (trans_time_prop != NULL) *trans_time_prop = p->led_trans_time_prop;
+ return inst_ok;
+ }
+
+ /* Return the filter */
+ if (m == inst_stat_get_filter) {
+ inst_opt_filter *filt;
+ va_list args;
+
+ va_start(args, m);
+ filt = va_arg(args, inst_opt_filter *);
+ va_end(args);
+
+ /* The ColorMunki is always UV cut */
+ *filt = inst_opt_filter_UVCut;
+
+ return inst_ok;
+ }
+
+ /* Use default implementation of other inst_opt_type's */
+ {
+ inst_code rv;
+ va_list args;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
+ return inst_unsupported;
+}
+
+/* Destroy ourselves */
+static void
+munki_del(inst *pp) {
+ munki *p = (munki *)pp;
+
+ del_munkiimp(p);
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ free(p);
+}
+
+/* Constructor */
+extern munki *new_munki(icoms *icom, instType itype) {
+ munki *p;
+ int rv;
+ if ((p = (munki *)calloc(sizeof(munki),1)) == NULL) {
+ a1loge(icom->log, 1, "new_munki: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ /* Inst methods */
+ p->init_coms = munki_init_coms;
+ p->init_inst = munki_init_inst;
+ p->capabilities = munki_capabilities;
+ p->meas_config = munki_meas_config;
+ p->get_serial_no = munki_get_serial_no;
+ p->check_mode = munki_check_mode;
+ p->set_mode = munki_set_mode;
+ p->get_set_opt = munki_get_set_opt;
+ p->read_strip = munki_read_strip;
+ p->read_sample = munki_read_sample;
+ p->read_refrate = munki_read_refrate;
+ p->get_n_a_cals = munki_get_n_a_cals;
+ p->calibrate = munki_calibrate;
+ p->interp_error = munki_interp_error;
+ p->config_enum = munki_config_enum;
+ p->del = munki_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ /* Preliminary capabilities */
+ munki_determine_capabilities(p);
+
+ if ((rv = add_munkiimp(p) != MUNKI_OK)) {
+ free(p);
+ a1loge(icom->log, 1, "new_munki: error %d creating munkiimp\n",rv);
+ }
+
+ return p;
+}
+
diff --git a/spectro/munki.h b/spectro/munki.h
new file mode 100644
index 0000000..01eda29
--- /dev/null
+++ b/spectro/munki.h
@@ -0,0 +1,72 @@
+
+#ifndef MUNKI_H
+
+ /* X-Rite ColorMunki related defines */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/1/2009
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * (Based on i1pro.h)
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* MUNKI communication object */
+struct _munki {
+ INST_OBJ_BASE
+
+ int dtype; /* Device type: 0 = ?? */
+
+ /* *** munki private data **** */
+ inst_mode cap; /* Instrument mode capability */
+ inst2_capability cap2; /* Instrument capability 2 */
+ inst3_capability cap3; /* Instrument capability 3 */
+
+ void *m; /* Implementation - munkiimp type */
+
+ /* Other state */
+ int led_state; /* : Current LED on/off state */
+ double led_period, led_on_time_prop, led_trans_time_prop; /* Pulse state */
+
+}; typedef struct _munki munki;
+
+/* Constructor */
+extern munki *new_munki(icoms *icom, instType itype);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define MUNKI_H
+#endif /* MUNKI_H */
diff --git a/spectro/munki_imp.c b/spectro/munki_imp.c
new file mode 100644
index 0000000..c76e9bc
--- /dev/null
+++ b/spectro/munki_imp.c
@@ -0,0 +1,9103 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/1/2009
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * (Base on i1pro_imp.c)
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+/* TTBD:
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#if defined(UNIX)
+# include <utime.h>
+#else
+# include <sys/utime.h>
+#endif
+#include <sys/stat.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "rspl.h"
+#else /* SALONEINSTLIB */
+#include <fcntl.h>
+#include "sa_config.h"
+#include "numsup.h"
+#include "rspl1.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "sort.h"
+
+/* Configuration */
+#undef USE_HIGH_GAIN_MODE /* [Und] Make use of high gain mode */
+#define USE_THREAD /* [Def] Need to use thread, or there are 1.5 second internal */
+ /* instrument delays ! */
+#define ENABLE_NONVCAL /* [Def] Enable saving calibration state between program runs in a file */
+#define ENABLE_NONLINCOR /* [Def] Enable non-linear correction */
+ /* NOTE :- high gain scaling will be stuffed if disabled! */
+#define ENABLE_LEDTEMPC /* [Def] Enable LED temperature compensation */
+#define ENABLE_SPOS_CHECK /* [Def] Chech the sensor position is reasonable for measurement */
+#define DCALTOUT (1 * 60 * 60) /* [1 Hrs] Dark Calibration timeout in seconds */
+#define WCALTOUT (24 * 60 * 60) /* [24 Hrs] White Calibration timeout in seconds */
+#define MAXSCANTIME 20.0 /* [20 Sec] Maximum scan time in seconds */
+#define SW_THREAD_TIMEOUT (10 * 60.0) /* [10 Min] Switch read thread timeout */
+
+#define SINGLE_READ /* [Def] Use a single USB read for scan to eliminate latency issues. */
+#define HIGH_RES /* [Def] Enable high resolution spectral mode code. Disable */
+ /* to break dependency on rspl library. */
+
+/* Debug [Und] */
+#undef DEBUG /* Turn on extra messages & plots */
+#undef PLOT_DEBUG /* Use plot to show readings & processing */
+#undef PLOT_REFRESH /* Plot refresh rate measurement info */
+#undef RAWR_DEBUG /* Print out raw reading processing values */
+#undef DUMP_SCANV /* Dump scan readings to a file "mkdump.txt" */
+#undef DUMP_DARKM /* Append raw dark readings to file "mkddump.txt" */
+#undef APPEND_MEAN_EMMIS_VAL /* Append averaged uncalibrated reading to file "mkdump.txt" */
+#undef IGNORE_WHITE_INCONS /* Ignore define reference reading inconsistency */
+#undef TEST_DARK_INTERP /* Test out the dark interpolation (need DEBUG for plot) */
+#undef PLOT_RCALCURVE /* Plot the reflection reference curve */
+#undef PLOT_ECALCURVES /* Plot the emission reference curves */
+#undef PLOT_TEMPCOMP /* Plot before and after temp. compensation */
+#undef PATREC_DEBUG /* Print & Plot patch/flash recognition information */
+#undef HIGH_RES_DEBUG
+#undef HIGH_RES_PLOT
+#undef HIGH_RES_PLOT_STRAYL /* Plot strat light upsample */
+
+
+#define DISP_INTT 0.7 /* Seconds per reading in display spot mode */
+ /* More improves repeatability in dark colors, but limits */
+ /* the maximum brightness level befor saturation. */
+ /* A value of 2.0 seconds has a limit of about 110 cd/m^2 */
+#define DISP_INTT2 0.3 /* High brightness display spot mode seconds per reading, */
+ /* Should be good up to 275 cd/m^2 */
+#define DISP_INTT3 0.1 /* High brightness display spot mode seconds per reading, */
+ /* Should be good up to 700 cd/m^2 */
+
+#define ADARKINT_MIN 0.01 /* Min cal time for adaptive dark cal */
+#define ADARKINT_MAX 2.0 /* Max cal time for adaptive dark cal with high gain mode */
+#define ADARKINT_MAX2 4.0 /* Max cal time for adaptive dark for no high gain */
+
+#define SCAN_OP_LEV 0.10 /* Degree of optimimum sensor value to aim for */
+ /* Make it scan as fast as possible */
+
+#define RDEAD_TIME 0.004432 /* Fudge figure to make reflecting intn. time scale linearly */
+
+#define EMIS_SCALE_FACTOR 1.0 /* Emission mode scale factor */
+#define AMB_SCALE_FACTOR (1.0/3.141592654) /* Ambient mode scale factor - convert */
+ /* from Lux to Lux/PI */
+ /* These factors get the same behaviour as the GMB drivers. */
+
+#define NSEN_MAX 140 /* Maximum nsen/raw value we can cope with */
+
+/* High res mode settings */
+#define HIGHRES_SHORT 360 /* Wavelength to calculate */
+#define HIGHRES_LONG 740
+#define HIGHRES_WIDTH (10.0/3.0) /* (The 3.3333 spacing and lanczos2 seems a good combination) */
+#define HIGHRES_REF_MIN 410.0 /* Too much stray light below this in reflective mode */
+#define HIGHRES_TRANS_MIN 380.0 /* Too much stray light below this in reflective mode */
+
+#include "munki.h"
+#include "munki_imp.h"
+
+/* - - - - - - - - - - - - - - - - - - */
+
+#define PATCH_CONS_THR 0.05 /* Dark measurement consistency threshold */
+#define DARKTHSCAMIN 5000.0 /* Dark threshold scaled/offset minimum */
+
+/* - - - - - - - - - - - - - - - - - - */
+
+/* Three levels of runtime debugging messages:
+
+ ~~~ this is no longer accurate. a1logd calls
+ ~~~ probably need to be tweaked.
+ 1 = default, typical I/O messages etc.
+ 2 = more internal operation messages
+ 3 = dump extra detailes
+ 4 = dump EEPROM data
+ 5 = dump tables etc
+*/
+
+/* ============================================================ */
+
+// Print bytes as hex to debug log */
+static void dump_bytes(a1log *log, char *pfx, unsigned char *buf, int base, int len) {
+ int i, j, ii;
+ char oline[200] = { '\000' }, *bp = oline;
+ for (i = j = 0; i < len; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp,"%s%04x:",pfx,base+i);
+ bp += sprintf(bp," %02x",buf[i]);
+ if ((i+1) >= len || ((i+1) % 16) == 0) {
+ for (ii = i; ((ii+1) % 16) != 0; ii++)
+ bp += sprintf(bp," ");
+ bp += sprintf(bp," ");
+ for (; j <= i; j++) {
+ if (!(buf[j] & 0x80) && isprint(buf[j]))
+ bp += sprintf(bp,"%c",buf[j]);
+ else
+ bp += sprintf(bp,".");
+ }
+ bp += sprintf(bp,"\n");
+ a1logd(log,0,oline);
+ bp = oline;
+ }
+ }
+}
+
+/* ============================================================ */
+/* Debugging plot support */
+
+#if defined(DEBUG) || defined(PLOT_DEBUG) || defined(PATREC_DEBUG) || defined(HIGH_RES_PLOT) || defined(HIGH_RES_PLOT_STRAYL)
+
+# include <plot.h>
+
+static int disdebplot = 0;
+
+# define DISDPLOT disdebplot = 1;
+# define ENDPLOT disdebplot = 0;
+
+/* Plot a CCD spectra */
+void plot_raw(double *data) {
+ int i;
+ double xx[NSEN_MAX];
+ double yy[NSEN_MAX];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < 128; i++) {
+ xx[i] = (double)i;
+ yy[i] = data[i];
+ }
+ do_plot(xx, yy, NULL, NULL, 128);
+}
+
+/* Plot two CCD spectra */
+void plot_raw2(double *data1, double *data2) {
+ int i;
+ double xx[NSEN_MAX];
+ double y1[NSEN_MAX];
+ double y2[NSEN_MAX];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < 128; i++) {
+ xx[i] = (double)i;
+ y1[i] = data1[i];
+ y2[i] = data2[i];
+ }
+ do_plot(xx, y1, y2, NULL, 128);
+}
+
+/* Plot a converted spectra */
+void plot_wav(munkiimp *m, double *data) {
+ int i;
+ double xx[NSEN_MAX];
+ double yy[NSEN_MAX];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < m->nwav; i++) {
+ xx[i] = XSPECT_WL(m->wl_short, m->wl_long, m->nwav, i);
+ yy[i] = data[i];
+ }
+ do_plot(xx, yy, NULL, NULL, m->nwav);
+}
+
+/* Plot a standard res spectra */
+void plot_wav1(munkiimp *m, double *data) {
+ int i;
+ double xx[36];
+ double yy[36];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < m->nwav1; i++) {
+ xx[i] = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, i);
+ yy[i] = data[i];
+ }
+ do_plot(xx, yy, NULL, NULL, m->nwav1);
+}
+
+/* Plot a high res spectra */
+void plot_wav2(munkiimp *m, double *data) {
+ int i;
+ double xx[NSEN_MAX];
+ double yy[NSEN_MAX];
+
+ if (disdebplot)
+ return;
+
+ for (i = 0; i < m->nwav2; i++) {
+ xx[i] = XSPECT_WL(m->wl_short2, m->wl_long2, m->nwav2, i);
+ yy[i] = data[i];
+ }
+ do_plot(xx, yy, NULL, NULL, m->nwav2);
+}
+
+#else /* !PLOT_DEBUG */
+
+# define DISDPLOT
+# define ENDPLOT
+
+#endif /* !PLOT_DEBUG */
+
+/* ============================================================ */
+
+munki_code munki_touch_calibration(munki *p);
+
+/* Implementation struct */
+
+/* Add an implementation structure */
+munki_code add_munkiimp(munki *p) {
+ munkiimp *m;
+
+ if ((m = (munkiimp *)calloc(1, sizeof(munkiimp))) == NULL) {
+ a1logd(p->log,3,"add_munkiimp malloc %lu bytes failed (1)\n",sizeof(munkiimp));
+ return MUNKI_INT_MALLOC;
+ }
+ m->p = p;
+
+ m->lo_secs = 2000000000; /* A very long time */
+
+ p->m = (void *)m;
+ return MUNKI_OK;
+}
+
+/* Shutdown instrument, and then destroy */
+/* implementation structure */
+void del_munkiimp(munki *p) {
+
+ a1logd(p->log,3,"munki_del called\n");
+
+#ifdef ENABLE_NONVCAL
+ /* Touch it so that we know when the instrument was last open */
+ munki_touch_calibration(p);
+#endif /* ENABLE_NONVCAL */
+
+ if (p->m != NULL) {
+ int i;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s;
+
+ if (m->th != NULL) { /* Terminate switch monitor thread by simulating an event */
+ m->th_term = 1; /* Tell thread to exit on error */
+ munki_simulate_event(p, mk_eve_spos_change, 0);
+ for (i = 0; m->th_termed == 0 && i < 5; i++)
+ msec_sleep(50); /* Wait for thread to terminate */
+ if (i >= 5) {
+ a1logd(p->log,3,"Munki switch thread termination failed\n");
+ }
+ m->th->del(m->th);
+ usb_uninit_cancel(&m->cancelt); /* Don't need cancel token now */
+ }
+
+ /* Free any per mode data */
+ for (i = 0; i < mk_no_modes; i++) {
+ s = &m->ms[i];
+
+ free_dvector(s->dark_data, -1, m->nraw-1);
+ free_dvector(s->dark_data2, -1, m->nraw-1);
+ free_dvector(s->dark_data3, -1, m->nraw-1);
+ free_dvector(s->white_data, -1, m->nraw-1);
+ free_dmatrix(s->iwhite_data, 0, 1, -1, m->nraw-1);
+ free_dmatrix(s->idark_data, 0, 3, -1, m->nraw-1);
+
+ free_dvector(s->cal_factor1, 0, m->nwav1-1);
+ free_dvector(s->cal_factor2, 0, m->nwav2-1);
+ }
+
+ /* Free EEProm key data */
+ if (m->data != NULL)
+ m->data->del(m->data);
+
+ /* Free arrays */
+
+ if (m->lin0 != NULL)
+ free(m->lin0);
+ if (m->lin1 != NULL)
+ free(m->lin1);
+
+ if (m->white_ref1 != NULL)
+ free(m->white_ref1);
+ if (m->emis_coef1 != NULL)
+ free(m->emis_coef1);
+ if (m->amb_coef1 != NULL)
+ free(m->amb_coef1);
+ if (m->proj_coef1 != NULL)
+ free(m->proj_coef1);
+
+ if (m->white_ref2 != NULL)
+ free(m->white_ref2);
+ if (m->emis_coef2 != NULL)
+ free(m->emis_coef2);
+ if (m->amb_coef2 != NULL)
+ free(m->amb_coef2);
+ if (m->proj_coef2 != NULL)
+ free(m->proj_coef2);
+
+ if (m->straylight1 != NULL)
+ free_dmatrix(m->straylight1, 0, m->nwav1-1, 0, m->nwav1-1);
+
+ if (m->straylight2 != NULL)
+ free_dmatrix(m->straylight2, 0, m->nwav1-2, 0, m->nwav1-2);
+
+ if (m->rmtx_index1 != NULL)
+ free(m->rmtx_index1);
+ if (m->rmtx_nocoef1 != NULL)
+ free(m->rmtx_nocoef1);
+ if (m->rmtx_coef1 != NULL)
+ free(m->rmtx_coef1);
+
+ if (m->rmtx_index2 != NULL)
+ free(m->rmtx_index2);
+ if (m->rmtx_nocoef2 != NULL)
+ free(m->rmtx_nocoef2);
+ if (m->rmtx_coef2 != NULL)
+ free(m->rmtx_coef2);
+
+ if (m->emtx_index1 != NULL)
+ free(m->emtx_index1);
+ if (m->emtx_nocoef1 != NULL)
+ free(m->emtx_nocoef1);
+ if (m->emtx_coef1 != NULL)
+ free(m->emtx_coef1);
+
+ if (m->emtx_index2 != NULL)
+ free(m->emtx_index2);
+ if (m->emtx_nocoef2 != NULL)
+ free(m->emtx_nocoef2);
+ if (m->emtx_coef2 != NULL)
+ free(m->emtx_coef2);
+
+ free(m);
+ p->m = NULL;
+ }
+}
+
+/* ============================================================ */
+/* Little endian wire format conversion routines */
+
+/* Take an int, and convert it into a byte buffer little endian */
+static void int2buf(unsigned char *buf, int inv) {
+ buf[3] = (inv >> 24) & 0xff;
+ buf[2] = (inv >> 16) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+ buf[0] = (inv >> 0) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer little endian */
+static void short2buf(unsigned char *buf, int inv) {
+ buf[1] = (inv >> 8) & 0xff;
+ buf[0] = (inv >> 0) & 0xff;
+}
+
+/* Take a word sized buffer, and convert it to an int */
+static int buf2int(unsigned char *buf) {
+ int val;
+ val = ((signed char *)buf)[3];
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a word sized buffer, and convert it to an unsigned int */
+static unsigned int buf2uint(unsigned char *buf) {
+ unsigned int val;
+ val = (0xff & buf[3]);
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a short sized buffer, and convert it to an int */
+static int buf2short(unsigned char *buf) {
+ int val;
+ val = ((signed char *)buf)[1];
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a unsigned short sized buffer, and convert it to an int */
+static int buf2ushort(unsigned char *buf) {
+ int val;
+ val = (0xff & buf[1]);
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* ============================================================ */
+/* High level functions */
+
+/* Initialise our software state from the hardware */
+munki_code munki_imp_init(munki *p) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code ev = MUNKI_OK;
+ unsigned char buf[4];
+ int calsize = 0, rucalsize;
+ unsigned char *calbuf; /* EEProm contents */
+
+ a1logd(p->log,2,"munki_init:\n");
+
+ if (p->itype != instColorMunki)
+ return MUNKI_UNKNOWN_MODEL;
+
+#ifdef ENABLE_SPOS_CHECK
+ m->nosposcheck = 0;
+#else
+# pragma message("####### ColorMunki Sensor Position Check is OFF! ########")
+ m->nosposcheck = 1;
+#endif
+
+ m->trig = inst_opt_trig_user;
+ m->scan_toll_ratio = 1.0;
+
+ /* Get the firmware parameters so that we can check eeprom range. */
+ if ((ev = munki_getfirm(p, &m->fwrev, &m->tickdur, &m->minintcount, &m->noeeblocks, &m->eeblocksize)) != MUNKI_OK)
+ return ev;
+ a1logd(p->log,2,"Firmware rev = %d.%d\n",m->fwrev/256, m->fwrev % 256);
+
+ /* Check the EEProm */
+ if (m->noeeblocks != 2 || m->eeblocksize != 8192) {
+ a1logw(p->log,"EEProm is unexpected size\n");
+ return MUNKI_INT_ASSERT;
+ }
+
+ /* Dump the eeprom contents as a block */
+ if (p->log->debug >= 7) {
+ int base, size;
+
+ a1logd(p->log,7, "EEPROM contents:\n");
+
+ size = 8192;
+ for (base = 0; base < (2 * 8192); base += 8192) {
+ unsigned char eeprom[8192];
+
+ if ((ev = munki_readEEProm(p, eeprom, base, size)) != MUNKI_OK)
+ return ev;
+
+ dump_bytes(p->log, " ", eeprom, base, size);
+ }
+ }
+
+ /* Tick in seconds */
+ m->intclkp = (double)m->tickdur * 1e-6;
+
+ /* Set these to reasonable values */
+ m->min_int_time = m->intclkp * (double)m->minintcount;
+ m->max_int_time = 4.5;
+
+ a1logd(p->log,3, "minintcount %d, min_int_time = %f\n", m->minintcount, m->min_int_time);
+
+ /* Get the Chip ID */
+ if ((ev = munki_getchipid(p, m->chipid)) != MUNKI_OK)
+ return ev;
+
+ /* Get the Version String */
+ if ((ev = munki_getversionstring(p, m->vstring)) != MUNKI_OK)
+ return ev;
+
+ /* Read the calibration size */
+ if ((ev = munki_readEEProm(p, buf, 4, 4)) != MUNKI_OK)
+ return ev;
+ calsize = buf2int(buf);
+ rucalsize = (calsize + 3) & ~3; /* Round up to next 32 bits */
+
+ if (calsize < 12)
+ return MUNKI_INT_CALTOOSMALL;
+ if (calsize > (m->noeeblocks * m->eeblocksize))
+ return MUNKI_INT_CALTOOBIG;
+
+ /* Read the calibration raw data from the EEProm */
+ if ((calbuf = (unsigned char *)calloc(rucalsize, sizeof(unsigned char))) == NULL) {
+ a1logd(p->log,3,"munki_imp_init malloc %d bytes failed\n",rucalsize);
+ return MUNKI_INT_MALLOC;
+ }
+ if ((ev = munki_readEEProm(p, calbuf, 0, calsize)) != MUNKI_OK)
+ return ev;
+
+ if ((ev = munki_parse_eeprom(p, calbuf, rucalsize)) != MUNKI_OK)
+ return ev;
+
+ free(calbuf);
+ calbuf = NULL;
+
+#ifdef USE_THREAD
+ /* Setup the switch monitoring thread */
+ usb_init_cancel(&m->cancelt); /* Get cancel token ready */
+ if ((m->th = new_athread(munki_switch_thread, (void *)p)) == NULL)
+ return MUNKI_INT_THREADFAILED;
+#endif
+
+ /* Set up the current state of each mode */
+ {
+ int i, j;
+ munki_state *s;
+
+ /* First set state to basic configuration */
+ for (i = 0; i < mk_no_modes; i++) {
+ s = &m->ms[i];
+
+ s->mode = i;
+
+ /* Default to an emissive configuration */
+ s->targoscale = 0.90; /* Allow extra 10% margine by default */
+ s->targmaxitime = 2.0; /* Maximum integration time to aim for */
+ s->targoscale2 = 0.15; /* Proportion of targoscale to meed targmaxitime */
+
+ s->gainmode = 0; /* Normal gain mode */
+ s->inttime = 0.5; /* Initial integration time */
+
+
+ s->dark_valid = 0; /* Dark cal invalid */
+ s->dark_data = dvectorz(-1, m->nraw-1);
+ s->dark_data2 = dvectorz(-1, m->nraw-1);
+ s->dark_data3 = dvectorz(-1, m->nraw-1);
+
+ s->cal_valid = 0; /* Scale cal invalid */
+ s->cal_factor1 = dvectorz(0, m->nwav1-1);
+ s->cal_factor2 = dvectorz(0, m->nwav2-1);
+ s->cal_factor = s->cal_factor1; /* Default to standard resolution */
+ s->white_data = dvectorz(-1, m->nraw-1);
+ s->iwhite_data = dmatrixz(0, 1, -1, m->nraw-1);
+
+ s->idark_valid = 0; /* Interpolatable Dark cal invalid */
+ s->idark_data = dmatrixz(0, 3, -1, m->nraw-1);
+
+ s->min_wl = 0.0; /* Default minimum to report */
+
+ s->dark_int_time = DISP_INTT; /* 0.7 */
+ s->dark_int_time2 = DISP_INTT2; /* 0.3 */
+ s->dark_int_time3 = DISP_INTT3; /* 0.1 */
+
+ s->idark_int_time[0] = s->idark_int_time[2] = m->min_int_time;
+#ifdef USE_HIGH_GAIN_MODE
+ s->idark_int_time[1] = s->idark_int_time[3] = ADARKINT_MAX; /* 2.0 */
+#else
+ s->idark_int_time[1] = s->idark_int_time[3] = ADARKINT_MAX2; /* 4.0 */
+#endif
+ s->want_calib = 1; /* By default want an initial calibration */
+ s->want_dcalib = 1;
+ }
+
+ /* Then add mode specific settings */
+ for (i = 0; i < mk_no_modes; i++) {
+ s = &m->ms[i];
+ switch(i) {
+ case mk_refl_spot:
+ s->targoscale = 1.0; /* Optimised sensor scaling to full */
+ s->reflective = 1;
+ s->adaptive = 0;
+ s->inttime = s->targoscale * m->cal_int_time;
+ s->dark_int_time = s->inttime;
+
+ s->dpretime = 0.20; /* Pre-measure time */
+ s->wpretime = 0.20;
+ s->dcaltime = 0.5; /* same as reading */
+ s->wcaltime = 0.5; /* same as reading */
+ s->dreadtime = 0.5; /* same as reading */
+ s->wreadtime = 0.5;
+ s->maxscantime = 0.0;
+ s->min_wl = HIGHRES_REF_MIN; /* Not enogh illumination to go below this */
+ break;
+
+ case mk_refl_scan:
+ s->targoscale = SCAN_OP_LEV; /* Maximize scan rate */
+ s->reflective = 1;
+ s->scan = 1;
+ s->adaptive = 0;
+ s->inttime = (s->targoscale * m->cal_int_time - RDEAD_TIME) + RDEAD_TIME;
+ if (s->inttime < m->min_int_time)
+ s->inttime = m->min_int_time;
+ s->dark_int_time = s->inttime;
+
+ s->dpretime = 0.20; /* Pre-measure time */
+ s->wpretime = 0.20;
+ s->dcaltime = 0.5;
+ s->wcaltime = 0.5;
+ s->dreadtime = 0.10;
+ s->wreadtime = 0.10;
+ s->maxscantime = MAXSCANTIME;
+ s->min_wl = HIGHRES_REF_MIN; /* Not enogh illumination to go below this */
+ break;
+
+ case mk_emiss_spot_na: /* Emissive spot not adaptive */
+ case mk_tele_spot_na: /* Tele spot not adaptive */
+ s->targoscale = 0.90; /* Allow extra 10% margine */
+ if (i == mk_emiss_spot_na) {
+ for (j = 0; j < m->nwav1; j++)
+ s->cal_factor1[j] = EMIS_SCALE_FACTOR * m->emis_coef1[j];
+ } else {
+ for (j = 0; j < m->nwav1; j++)
+ s->cal_factor1[j] = EMIS_SCALE_FACTOR * m->proj_coef1[j];
+ s->projector = 1;
+ }
+ s->cal_valid = 1;
+ s->emiss = 1;
+ s->adaptive = 0;
+
+ s->inttime = DISP_INTT; /* Default disp integration time (ie. 0.7 sec) */
+ s->dark_int_time = s->inttime;
+ s->dark_int_time2 = DISP_INTT2; /* Alternate disp integration time (ie. 0.3) */
+ s->dark_int_time3 = DISP_INTT3; /* Alternate disp integration time (ie. 0.1) */
+
+ s->dpretime = 0.0;
+ s->wpretime = 0.20;
+ s->dcaltime = 1.0; /* ie. determines number of measurements */
+ s->dcaltime2 = 1.0;
+ s->dcaltime3 = 1.0;
+ s->wcaltime = 0.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = DISP_INTT;
+ s->maxscantime = 0.0;
+ break;
+
+ case mk_emiss_spot:
+ case mk_amb_spot:
+ case mk_tele_spot: /* Adaptive projector */
+ s->targoscale = 0.90; /* Allow extra 5% margine */
+ if (i == mk_emiss_spot) {
+ for (j = 0; j < m->nwav1; j++)
+ s->cal_factor1[j] = EMIS_SCALE_FACTOR * m->emis_coef1[j];
+ } else if (i == mk_amb_spot) {
+ for (j = 0; j < m->nwav1; j++)
+ s->cal_factor1[j] = AMB_SCALE_FACTOR * m->amb_coef1[j];
+ s->ambient = 1;
+ } else {
+ for (j = 0; j < m->nwav1; j++)
+ s->cal_factor1[j] = EMIS_SCALE_FACTOR * m->proj_coef1[j];
+ s->projector = 1;
+ }
+
+ s->cal_valid = 1;
+ s->emiss = 1;
+ s->adaptive = 1;
+
+ s->dpretime = 0.0;
+ s->wpretime = 0.10;
+ s->dcaltime = 1.0;
+ s->wcaltime = 0.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = 1.0;
+ s->maxscantime = 0.0;
+ break;
+
+ case mk_emiss_scan:
+ case mk_amb_flash:
+ s->targoscale = 0.90; /* Allow extra 10% margine */
+ if (i == mk_emiss_scan) {
+ for (j = 0; j < m->nwav1; j++)
+ s->cal_factor1[j] = EMIS_SCALE_FACTOR * m->emis_coef1[j];
+ } else {
+ for (j = 0; j < m->nwav1; j++)
+ s->cal_factor1[j] = AMB_SCALE_FACTOR * m->amb_coef1[j];
+ s->ambient = 1;
+ s->flash = 1;
+ }
+ s->cal_valid = 1;
+ s->emiss = 1;
+ s->scan = 1;
+ s->adaptive = 0;
+ s->inttime = m->min_int_time;
+ s->dark_int_time = s->inttime;
+
+ s->dpretime = 0.0;
+ s->wpretime = 0.10;
+ s->dcaltime = 1.0;
+ s->wcaltime = 0.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = 0.10;
+ s->maxscantime = MAXSCANTIME;
+ break;
+
+ /* Transparency has a white reference, and interpolated dark ref. */
+ case mk_trans_spot:
+ s->targoscale = 0.90; /* Allow extra 10% margine */
+ s->trans = 1;
+ s->adaptive = 1;
+
+ s->dpretime = 0.20;
+ s->wpretime = 0.20;
+ s->dcaltime = 1.0;
+ s->wcaltime = 1.0;
+ s->dreadtime = 0.0;
+ s->wreadtime = 1.0;
+ s->maxscantime = 0.0;
+ s->min_wl = HIGHRES_TRANS_MIN; /* Too much stray light below this ? */
+ break;
+
+ case mk_trans_scan:
+ s->targoscale = 0.90; /* Allow extra 10% margine */
+ s->trans = 1;
+ s->scan = 1;
+ s->targoscale = SCAN_OP_LEV;
+ s->inttime = s->targoscale * m->cal_int_time;
+ if (s->inttime < m->min_int_time)
+ s->inttime = m->min_int_time;
+ s->dark_int_time = s->inttime;
+ s->adaptive = 0;
+
+ s->dpretime = 0.20;
+ s->wpretime = 0.20;
+ s->dcaltime = 1.0;
+ s->wcaltime = 1.0;
+ s->dreadtime = 0.00;
+ s->wreadtime = 0.10;
+ s->maxscantime = MAXSCANTIME;
+ s->min_wl = HIGHRES_TRANS_MIN; /* Too much stray light below this ? */
+ break;
+ }
+ }
+ }
+
+#ifdef ENABLE_NONVCAL
+ /* Restore the all modes calibration from the local system */
+ munki_restore_calibration(p);
+ /* Touch it so that we know when the instrument was last opened */
+ munki_touch_calibration(p);
+#endif
+
+ a1logv(p->log, 1,
+ "Instrument Type: ColorMunki\n" // ~~ should get this from version string ?
+ "Serial Number: %s\n"
+ "Firmware version: %d\n"
+ "Chip ID: %02X-%02X%02X%02X%02X%02X%02X%02X\n"
+ "Version string: '%s'\n"
+ "Calibration Ver.: %d\n"
+ "Production No.: %d\n",
+ m->serno,
+ m->fwrev,
+ m->chipid[0], m->chipid[1], m->chipid[2], m->chipid[3],
+ m->chipid[4], m->chipid[5], m->chipid[6], m->chipid[7],
+ m->vstring,
+ m->calver,
+ m->prodno);
+
+ /* Flash the LED, just cos we can! */
+ if ((ev = munki_setindled(p, 1000,0,0,-1,0)) != MUNKI_OK)
+ return ev;
+ msec_sleep(200);
+ if ((ev = munki_setindled(p, 0,0,0,0,0)) != MUNKI_OK)
+ return ev;
+
+ return ev;
+}
+
+/* Return a pointer to the serial number */
+char *munki_imp_get_serial_no(munki *p) {
+ munkiimp *m = (munkiimp *)p->m;
+
+ return m->serno;
+}
+
+/* Set the measurement mode. It may need calibrating */
+munki_code munki_imp_set_mode(
+ munki *p,
+ mk_mode mmode,
+ int spec_en /* nz to enable reporting spectral */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+
+ a1logd(p->log,3,"munki_imp_set_mode called with %d\n",mmode);
+ switch(mmode) {
+ case mk_refl_spot:
+ case mk_refl_scan:
+ case mk_emiss_spot_na:
+ case mk_tele_spot_na:
+ case mk_emiss_spot:
+ case mk_tele_spot:
+ case mk_emiss_scan:
+ case mk_amb_spot:
+ case mk_amb_flash:
+ case mk_trans_spot:
+ case mk_trans_scan:
+ m->mmode = mmode;
+ m->spec_en = spec_en ? 1 : 0;
+ return MUNKI_OK;
+ default:
+ break;
+ }
+ return MUNKI_INT_ILLEGALMODE;
+}
+
+/* Return needed and available inst_cal_type's */
+munki_code munki_imp_get_n_a_cals(munki *p, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *cs = &m->ms[m->mmode];
+ time_t curtime = time(NULL);
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ a1logd(p->log,3,"munki_imp_get_n_a_cals: checking mode %d\n",m->mmode);
+
+ /* Timout calibrations that are too old */
+ a1logd(p->log,4,"curtime = %u, iddate = %u\n",curtime,cs->iddate);
+ if ((curtime - cs->iddate) > DCALTOUT) {
+ a1logd(p->log,3,"Invalidating adaptive dark cal as %d secs from last cal\n",curtime - cs->iddate);
+ cs->idark_valid = 0;
+ }
+ if ((curtime - cs->ddate) > DCALTOUT) {
+ a1logd(p->log,3,"Invalidating dark cal as %d secs from last cal\n",curtime - cs->ddate);
+ cs->dark_valid = 0;
+ }
+ if (!cs->emiss && (curtime - cs->cfdate) > WCALTOUT) {
+ a1logd(p->log,3,"Invalidating white cal as %d secs from last cal\n",curtime - cs->cfdate);
+ cs->cal_valid = 0;
+ }
+
+ if (cs->reflective) {
+ if (!cs->dark_valid
+ || (cs->want_dcalib && !m->noinitcalib))
+ n_cals |= inst_calt_ref_dark;
+ a_cals |= inst_calt_ref_dark;
+
+ if (!cs->cal_valid
+ || (cs->want_calib && !m->noinitcalib))
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+ }
+ if (cs->emiss) {
+ if ((!cs->adaptive && !cs->dark_valid)
+ || (cs->adaptive && !cs->idark_valid)
+ || (cs->want_dcalib && !m->noinitcalib))
+ n_cals |= inst_calt_em_dark;
+ a_cals |= inst_calt_em_dark;
+ }
+ if (cs->trans) {
+ if ((!cs->adaptive && !cs->dark_valid)
+ || (cs->adaptive && !cs->idark_valid)
+ || (cs->want_dcalib && !m->noinitcalib))
+ n_cals |= inst_calt_trans_dark;
+ a_cals |= inst_calt_trans_dark;
+
+ if (!cs->cal_valid
+ || (cs->want_calib && !m->noinitcalib))
+ n_cals |= inst_calt_trans_vwhite;
+ a_cals |= inst_calt_trans_vwhite;
+ }
+ if (cs->emiss && !cs->scan && !cs->adaptive) {
+ if (!cs->done_dintsel)
+ n_cals |= inst_calt_emis_int_time;
+ a_cals |= inst_calt_emis_int_time;
+ }
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ a1logd(p->log,3,"munki_imp_get_n_a_cals: returning n_cals 0x%x, a_cals 0x%x\n",n_cals, a_cals);
+
+ return MUNKI_OK;
+}
+
+/* - - - - - - - - - - - - - - - - */
+/* Calibrate for the current mode. */
+/* Request an instrument calibration of the current mode. */
+munki_code munki_imp_calibrate(
+ munki *p,
+ inst_cal_type *calt, /* Calibration type to do/remaining */
+ inst_cal_cond *calc, /* Current condition/desired condition */
+ char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ int mmode = m->mmode; /* Current actual mode */
+ munki_state *cs = &m->ms[m->mmode];
+ int sx1, sx2, sx;
+ time_t cdate = time(NULL);
+ int nummeas = 0;
+ mk_spos spos;
+ int i, j, k;
+ inst_cal_type needed, available;
+
+ a1logd(p->log,3,"munki_imp_calibrate called with calt 0x%x, calc 0x%x\n",*calt, *calc);
+
+ if ((ev = munki_imp_get_n_a_cals(p, &needed, &available)) != MUNKI_OK)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"munki_imp_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return MUNKI_OK;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return MUNKI_UNSUPPORTED;
+ }
+
+ /* Get current sensor position */
+ if ((ev = munki_getstatus(p, &spos, NULL)) != MUNKI_OK) {
+ return ev;
+ }
+ a1logd(p->log,4,"munki sensor position = 0x%x\n",spos);
+
+ /* Make sure that the instrument configuration matches the */
+ /* conditions */
+ if (*calc == inst_calc_man_cal_smode) {
+ if (!m->nosposcheck && spos != mk_spos_calib) {
+ return MUNKI_SPOS_CALIB;
+ }
+ } else if (*calc == inst_calc_man_trans_white) {
+ if (!m->nosposcheck && spos != mk_spos_surf) {
+ return MUNKI_SPOS_SURF;
+ }
+ }
+
+ /* If the instrument is in the calibration position, */
+ /* we know what the conditions are. */
+ if (!m->nosposcheck && spos == mk_spos_calib) {
+ *calc = inst_calc_man_cal_smode;
+ a1logd(p->log,4,"munki set calc to cal conditions\n",spos);
+ }
+
+ a1logd(p->log,4,"munki_imp_calibrate has right conditions\n");
+
+ if (*calt & inst_calt_ap_flag) {
+ sx1 = 0; sx2 = mk_no_modes; /* Go through all the modes */
+ } else {
+ sx1 = m->mmode; sx2 = sx1 + 1; /* Just current mode */
+ }
+
+ /* Go through the modes we are going to cover */
+ for (sx = sx1; sx < sx2; sx++) {
+ munki_state *s = &m->ms[sx];
+ m->mmode = sx; /* A lot of functions we call rely on this */
+
+ a1logd(p->log,3,"\nCalibrating mode %d\n", s->mode);
+
+ /* Sanity check scan mode settings, in case something strange */
+ /* has been restored from the persistence file. */
+ if (s->scan && s->inttime > (2.1 * m->min_int_time)) {
+ s->inttime = m->min_int_time; /* Maximize scan rate */
+ }
+
+ /* We are now either in inst_calc_man_cal_smode, */
+ /* inst_calc_man_trans_white, inst_calc_disp_white or inst_calc_proj_white */
+ /* sequenced in that order, and in the appropriate condition for it. */
+
+ /* Fixed int. time black calibration: */
+ /* Reflective uses on the fly black, even for adaptive. */
+ /* Emiss and trans can use single black ref only for non-adaptive */
+ /* using the current inttime & gainmode, while display mode */
+ /* does an extra fallback black cal for bright displays. */
+ if ((*calt & (inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark | inst_calt_ap_flag))
+ && *calc == inst_calc_man_cal_smode
+ && ( s->reflective
+ || (s->emiss && !s->adaptive && !s->scan)
+ || (s->trans && !s->adaptive))) {
+ int stm;
+ int usesdct23 = 0; /* Is a mode that uses dcaltime2 & 3 */
+
+ if (s->emiss && !s->adaptive && !s->scan)
+ usesdct23 = 1;
+
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->inttime);
+
+ a1logd(p->log,3,"\nDoing initial display black calibration with dcaltime %f, int_time %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode);
+ stm = msec_time();
+ if ((ev = munki_dark_measure(p, s->dark_data, nummeas, &s->inttime, s->gainmode))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,4,"Execution time of dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
+
+ /* Special display mode alternate integration time black measurement */
+ if (usesdct23) {
+ nummeas = munki_comp_nummeas(p, s->dcaltime2, s->dark_int_time2);
+ a1logd(p->log,3,"Doing 2nd initial black calibration with dcaltime2 %f, dark_int_time2 %f, nummeas %d, gainmode %d\n", s->dcaltime2, s->dark_int_time2, nummeas, s->gainmode);
+ stm = msec_time();
+ if ((ev = munki_dark_measure(p, s->dark_data2, nummeas, &s->dark_int_time2,
+ s->gainmode)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,4,"Execution time of 2nd dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
+
+ nummeas = munki_comp_nummeas(p, s->dcaltime3, s->dark_int_time3);
+ a1logd(p->log,3,"Doing 3rd initial black calibration with dcaltime3 %f, dark_int_time3 %f, nummeas %d, gainmode %d\n", s->dcaltime3, s->dark_int_time3, nummeas, s->gainmode);
+ nummeas = munki_comp_nummeas(p, s->dcaltime3, s->dark_int_time3);
+ stm = msec_time();
+ if ((ev = munki_dark_measure(p, s->dark_data3, nummeas, &s->dark_int_time3,
+ s->gainmode)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,4,"Execution time of 3rd dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
+
+ }
+ s->dark_valid = 1;
+ s->want_dcalib = 0;
+ s->ddate = cdate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ *calt &= ~(inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark);
+
+ /* Save the calib to all similar modes */
+ for (i = 0; i < mk_no_modes; i++) {
+ munki_state *ss = &m->ms[i];
+ if (ss == s || ss->ddate == cdate)
+ continue;
+ if ( (s->reflective
+ || (ss->emiss && !ss->adaptive && !ss->scan)
+ || (ss->trans && !ss->adaptive))
+ && ss->dark_int_time == s->dark_int_time
+ && ss->dark_gain_mode == s->dark_gain_mode) {
+
+ ss->dark_valid = s->dark_valid;
+ ss->want_dcalib = s->want_dcalib;
+ ss->ddate = s->ddate;
+ ss->dark_int_time = s->dark_int_time;
+ ss->dark_gain_mode = s->dark_gain_mode;
+ for (k = -1; k < m->nraw; k++)
+ ss->dark_data[k] = s->dark_data[k];
+ /* If this is a mode with dark_data2/3, tranfer it too */
+ if (usesdct23 && ss->emiss && !ss->adaptive && !ss->scan) {
+ ss->dark_int_time2 = s->dark_int_time2;
+#ifndef NEVER // ~~99
+if (ss->dark_int_time2 != s->dark_int_time2
+ || ss->dark_int_time3 != s->dark_int_time3)
+ a1logd(p->log,1,"copying cal to mode with different cal/gain mode: %d -> %d\n",s->mode, ss->mode);
+#endif
+ ss->dark_int_time3 = s->dark_int_time2;
+ for (k = -1; k < m->nraw; k++) {
+ ss->dark_data2[k] = s->dark_data2[k];
+ ss->dark_data3[k] = s->dark_data3[k];
+ }
+ }
+ }
+ }
+ }
+
+ /* Emissive scan black calibration: */
+ /* Emsissive scan (flash) uses the fastest possible scan rate (??) */
+ if ((*calt & (inst_calt_em_dark | inst_calt_ap_flag))
+ && *calc == inst_calc_man_cal_smode
+ && (s->emiss && !s->adaptive && s->scan)) {
+ int stm;
+
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->inttime);
+
+ a1logd(p->log,3,"\nDoing emissive (flash) black calibration with dcaltime %f, int_time %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode);
+ stm = msec_time();
+ if ((ev = munki_dark_measure(p, s->dark_data, nummeas, &s->inttime, s->gainmode))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ a1logd(p->log,4,"Execution time of dark calib time %f sec = %d msec\n",s->inttime,msec_time() - stm);
+
+ s->dark_valid = 1;
+ s->want_dcalib = 0;
+ s->ddate = cdate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ *calt &= ~inst_calt_em_dark;
+
+ /* Save the calib to all similar modes */
+ for (i = 0; i < mk_no_modes; i++) {
+ munki_state *ss = &m->ms[i];
+ if (ss == s || ss->ddate == cdate)
+ continue;
+ if ((ss->emiss && !ss->adaptive && ss->scan)
+ && ss->dark_int_time == s->dark_int_time
+ && ss->dark_gain_mode == s->dark_gain_mode) {
+ ss->dark_valid = s->dark_valid;
+ ss->want_dcalib = s->want_dcalib;
+ ss->ddate = s->ddate;
+ ss->dark_int_time = s->dark_int_time;
+ ss->dark_gain_mode = s->dark_gain_mode;
+ for (k = -1; k < m->nraw; k++) {
+ ss->dark_data[k] = s->dark_data[k];
+ }
+ }
+ }
+ }
+
+ /* Adaptive black calibration: */
+ /* Emmissive adaptive and transmissive black reference. */
+ /* in non-scan mode, where the integration time and gain may vary. */
+ if ((*calt & (inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark | inst_calt_ap_flag))
+ && *calc == inst_calc_man_cal_smode
+ && ((s->emiss && s->adaptive && !s->scan)
+ || (s->trans && s->adaptive && !s->scan))) {
+ /* Adaptive where we can't measure the black reference on the fly, */
+ /* so bracket it and interpolate. */
+ /* The black reference is probably temperature dependent, but */
+ /* there's not much we can do about this. */
+
+ s->idark_int_time[0] = m->min_int_time;
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->idark_int_time[0]);
+ a1logd(p->log,3,"\nDoing adaptive interpolated black calibration, dcaltime %f, idark_int_time[0] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[0], nummeas, 0);
+ if ((ev = munki_dark_measure(p, s->idark_data[0], nummeas, &s->idark_int_time[0], 0))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->idark_int_time[1]);
+ a1logd(p->log,3,"Doing adaptive interpolated black calibration, dcaltime %f, idark_int_time[1] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[1], nummeas, 0);
+ if ((ev = munki_dark_measure(p, s->idark_data[1], nummeas, &s->idark_int_time[1], 0))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+#ifdef USE_HIGH_GAIN_MODE
+ s->idark_int_time[2] = m->min_int_time; /* 0.01 */
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->idark_int_time[2]);
+ a1logd(p->log,3,"Doing adaptive interpolated black calibration, dcaltime %f, idark_int_time[2] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[2], nummeas, 1);
+ if ((ev = munki_dark_measure(p, s->idark_data[2], nummeas, &s->idark_int_time[2], 1))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ s->idark_int_time[3] = ADARKINT_MAX; /* 2.0 */
+ a1logd(p->log,3,"Doing adaptive interpolated black calibration, dcaltime %f, idark_int_time[3] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[3], nummeas, 1);
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->idark_int_time[3]);
+ if ((ev = munki_dark_measure(p, s->idark_data[3], nummeas, &s->idark_int_time[3], 1))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+#endif /* USE_HIGH_GAIN_MODE */
+
+ munki_prepare_idark(p);
+
+ s->idark_valid = 1;
+ s->iddate = cdate;
+
+ if ((ev = munki_interp_dark(p, s->dark_data, s->inttime, s->gainmode)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->want_dcalib = 0;
+ s->ddate = s->iddate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ *calt &= ~(inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark);
+
+ /* Save the calib to all similar modes */
+ /* We're assuming they have the same int times */
+ a1logd(p->log,3,"Saving adaptive black calib to similar modes\n");
+ for (i = 0; i < mk_no_modes; i++) {
+ munki_state *ss = &m->ms[i];
+ if (ss == s || ss->iddate == cdate)
+ continue;
+ if ((ss->emiss || ss->trans) && ss->adaptive && !ss->scan) {
+ ss->idark_valid = s->idark_valid;
+ ss->want_dcalib = s->want_dcalib;
+ ss->iddate = s->iddate;
+ ss->dark_int_time = s->dark_int_time;
+ ss->dark_gain_mode = s->dark_gain_mode;
+#ifndef NEVER // ~~99
+if (ss->dark_int_time != s->dark_int_time
+ || ss->dark_gain_mode != s->dark_gain_mode)
+ a1logd(p->log,1,"copying cal to mode with different cal/gain mode: %d -> %d\n",s->mode, ss->mode);
+#endif
+#ifdef USE_HIGH_GAIN_MODE
+ for (j = 0; j < 4; j++)
+#else
+ for (j = 0; j < 2; j++)
+#endif
+ {
+ ss->idark_int_time[j] = s->idark_int_time[j];
+#ifndef NEVER // ~~99
+if (ss->idark_int_time[j] != s->idark_int_time[j])
+ a1logd(p->log,1,"copying cal to mode with different cal/gain mode: %d -> %d\n",s->mode, ss->mode);
+#endif
+ for (k = -1; k < m->nraw; k++)
+ ss->idark_data[j][k] = s->idark_data[j][k];
+ }
+ }
+ }
+
+ a1logd(p->log,3,"Done adaptive interpolated black calibration\n");
+
+ /* Test accuracy of dark level interpolation */
+#ifdef TEST_DARK_INTERP
+ {
+ double tinttime;
+ double ref[NSEN_MAX], interp[NSEN_MAX];
+
+ // fprintf(stderr,"Normal gain offsets, base:\n");
+ // plot_raw(s->idark_data[0]);
+ // fprintf(stderr,"Normal gain offsets, multiplier:\n");
+ // plot_raw(s->idark_data[1]);
+
+#ifdef DUMP_DARKM
+ extern int ddumpdarkm;
+ ddumpdarkm = 1;
+#endif
+ for (tinttime = m->min_int_time; ; tinttime *= 2.0) {
+ if (tinttime >= m->max_int_time)
+ tinttime = m->max_int_time;
+
+ nummeas = munki_comp_nummeas(p, s->dcaltime, tinttime);
+ if ((ev = munki_dark_measure(p, ref, nummeas, &tinttime, 0)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ munki_interp_dark(p, interp, tinttime, 0);
+#ifdef DEBUG
+ fprintf(stderr,"Normal gain, int time %f:\n",tinttime);
+ plot_raw2(ref, interp);
+#endif
+ if ((tinttime * 1.1) > m->max_int_time)
+ break;
+ }
+#ifdef DUMP_DARKM
+ ddumpdarkm = 0;
+#endif
+
+#ifdef USE_HIGH_GAIN_MODE
+ // fprintf(stderr,"High gain offsets, base:\n");
+ // plot_raw(s->idark_data[2]);
+ // fprintf(stderr,"High gain offsets, multiplier:\n");
+ // plot_raw(s->idark_data[3]);
+
+ for (tinttime = m->min_int_time; ; tinttime *= 2.0) {
+ if (tinttime >= m->max_int_time)
+ tinttime = m->max_int_time;
+
+ nummeas = munki_comp_nummeas(p, s->dcaltime, tinttime);
+ if ((ev = munki_dark_measure(p, ref, nummeas, &tinttime, 1)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ munki_interp_dark(p, interp, tinttime, 1);
+#ifdef DEBUG
+ printf("High gain, int time %f:\n",tinttime);
+ plot_raw2(ref, interp);
+#endif
+ if ((tinttime * 1.1) > m->max_int_time)
+ break;
+ }
+#endif /* USE_HIGH_GAIN_MODE */
+ }
+#endif /* TEST_DARK_INTERP */
+
+ }
+
+ /* Deal with an emissive/transmisive adaptive black reference */
+ /* when in scan mode. */
+ if ((*calt & (inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark | inst_calt_ap_flag))
+ && *calc == inst_calc_man_cal_smode
+ && ((s->emiss && s->adaptive && s->scan)
+ || (s->trans && s->adaptive && s->scan))) {
+ int j;
+ /* We know scan is locked to the minimum integration time, */
+ /* so we can measure the dark data at that integration time, */
+ /* but we don't know what gain mode will be used, so measure both, */
+ /* and choose the appropriate one on the fly. */
+
+ s->idark_int_time[0] = s->inttime;
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->idark_int_time[0]);
+ a1logd(p->log,3,"\nDoing adaptive scan black calibration, dcaltime %f, idark_int_time[0] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[0], nummeas, s->gainmode);
+ if ((ev = munki_dark_measure(p, s->idark_data[0], nummeas, &s->idark_int_time[0], 0))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+#ifdef USE_HIGH_GAIN_MODE
+ s->idark_int_time[2] = s->inttime;
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->idark_int_time[2]);
+ a1logd(p->log,3,"Doing adaptive scan black calibration, dcaltime %f, idark_int_time[2] %f, nummeas %d, gainmode %d\n", s->dcaltime, s->idark_int_time[2], nummeas, s->gainmode);
+ if ((ev = munki_dark_measure(p, s->idark_data[2], nummeas, &s->idark_int_time[2], 1))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+#endif
+
+ s->idark_valid = 1;
+ s->iddate = cdate;
+
+#ifdef USE_HIGH_GAIN_MODE
+ if (s->gainmode) {
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data[j] = s->idark_data[2][j];
+ } else
+#endif
+ {
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data[j] = s->idark_data[0][j];
+ }
+ s->dark_valid = 1;
+ s->want_dcalib = 0;
+ s->ddate = s->iddate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ *calt &= ~(inst_calt_ref_dark
+ | inst_calt_em_dark
+ | inst_calt_trans_dark);
+
+ a1logd(p->log,3,"Done adaptive scan black calibration\n");
+
+ /* Save the calib to all similar modes */
+ /* We're assuming they have the same int times */
+ a1logd(p->log,3,"Saving adaptive scan black calib to similar modes\n");
+ for (i = 0; i < mk_no_modes; i++) {
+ munki_state *ss = &m->ms[i];
+ if (ss == s || s->iddate == cdate)
+ continue;
+ if ((ss->emiss || ss->trans) && ss->adaptive && s->scan) {
+ ss->idark_valid = s->idark_valid;
+ ss->want_dcalib = s->want_dcalib;
+ ss->iddate = s->iddate;
+ ss->dark_int_time = s->dark_int_time;
+ ss->dark_gain_mode = s->dark_gain_mode;
+#ifdef USE_HIGH_GAIN_MODE
+ for (j = 0; j < 4; j += 2)
+#else
+ for (j = 0; j < 2; j += 2)
+#endif
+ {
+ ss->idark_int_time[j] = s->idark_int_time[j];
+ for (k = -1; k < m->nraw; k++)
+ ss->idark_data[j][k] = s->idark_data[j][k];
+ }
+ }
+ }
+ }
+
+ /* Now deal with white calibrations */
+
+ /* If we are doing a reflective white reference calibrate */
+ /* or a we are doing a tranmisive white reference calibrate */
+ if ((*calt & (inst_calt_ref_white
+ | inst_calt_trans_vwhite | inst_calt_ap_flag))
+ && ((*calc == inst_calc_man_cal_smode && s->reflective)
+ || (*calc == inst_calc_man_trans_white && s->trans))) {
+// && s->cfdate < cdate)
+ double dead_time = 0.0; /* Dead integration time */
+ double scale;
+ int i;
+ double ulimit = m->optsval / m->minsval; /* Upper scale needed limit */
+ double fulimit = sqrt(ulimit); /* Fast exit limit */
+ double llimit = m->optsval / m->maxsval; /* Lower scale needed limit */
+ double fllimit = sqrt(llimit); /* Fast exit limit */
+
+ a1logd(p->log,3,"\nDoing initial white calibration with current inttime %f, gainmode %d\n",
+ s->inttime, s->gainmode);
+ a1logd(p->log,3,"ulimit %f, llimit %f\n",ulimit,llimit);
+ a1logd(p->log,3,"fulimit %f, fllimit %f\n",fulimit,fllimit);
+ if (s->reflective) {
+ dead_time = RDEAD_TIME; /* Fudge value that makes int time calcs work */
+ /* Heat up the LED to put in in a nominal state for int time adjustment */
+ munki_heatLED(p, m->ledpreheattime);
+ }
+
+ /* Until we're done */
+ for (i = 0; i < 6; i++) {
+
+ a1logd(p->log,3,"Doing a white calibration with trial int_time %f, gainmode %d\n",
+ s->inttime,s->gainmode);
+
+ if (s->trans && s->adaptive) {
+ /* compute interpolated dark refence for chosen inttime & gainmode */
+ a1logd(p->log,3,"Interpolate dark calibration reference\n");
+ if ((ev = munki_interp_dark(p, s->dark_data, s->inttime, s->gainmode))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->ddate = s->iddate;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ }
+ nummeas = munki_comp_nummeas(p, s->wcaltime, s->inttime);
+ ev = munki_whitemeasure(p, s->white_data, &scale, nummeas, &s->inttime, s->gainmode,
+ s->targoscale);
+ a1logd(p->log,3,"Needed scale is %f\n",scale);
+
+ if (ev == MUNKI_RD_SENSORSATURATED) {
+ scale = 0.0; /* Signal it this way */
+ ev = MUNKI_OK;
+ }
+ if (ev != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ if (scale >= fllimit && scale <= fulimit) {
+ a1logd(p->log,3,"Close enough for early exit\n");
+ break; /* OK, we can stop straight away */
+ }
+
+ if (scale == 0.0) { /* If sensor was saturated */
+ s->inttime = m->min_int_time;
+ s->gainmode = 0;
+ s->dark_valid = 0;
+ } else {
+ double ninttime;
+
+ /* Compute a new integration time and gain mode */
+ /* in order to optimise the sensor values. Error if can't get */
+ /* scale we want. */
+ if ((ev = munki_optimise_sensor(p, &ninttime, &s->gainmode, s->inttime,
+ s->gainmode, s->trans, 0, &s->targoscale, scale, dead_time)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->inttime = ninttime;
+ a1logd(p->log,3,"New inttime = %f\n",s->inttime);
+ }
+ }
+ if (i >= 6) {
+ if (scale == 0.0) { /* If sensor was saturated */
+ a1logd(p->log,1, "White calibration failed - sensor is saturated\n");
+ m->mmode = mmode; /* Restore actual mode */
+ return MUNKI_RD_SENSORSATURATED;
+ }
+ if (scale > ulimit || scale < llimit) {
+ a1logd(p->log,1,"White calibration failed - didn't converge (%f %f %f)\n",llimit,scale,ulimit);
+ m->mmode = mmode; /* Restore actual mode */
+ return MUNKI_RD_REFWHITENOCONV;
+ }
+ }
+
+ /* We've settled on the inttime and gain mode to get a good white reference. */
+ if (s->reflective) { /* We read the write reference - check it */
+
+ /* Let the LED cool down */
+ a1logd(p->log,3,"Waiting %f secs for LED to cool\n",m->ledwaittime);
+ msec_sleep((int)(m->ledwaittime * 1000.0 + 0.5));
+
+ /* Re-calibrate the black with the given integration time */
+ nummeas = munki_comp_nummeas(p, s->dcaltime, s->inttime);
+
+ a1logd(p->log,3,"Doing another reflective black calibration with dcaltime %f, int_time %f, nummeas %d, gainmode %d\n", s->dcaltime, s->inttime, nummeas, s->gainmode);
+ if ((ev = munki_dark_measure(p, s->dark_data, nummeas, &s->inttime, s->gainmode))
+ != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ /* Take a reflective white reference measurement, */
+ /* subtracts black and decompose into base + LED temperature components, */
+ /* and compute reftemp white reference. */
+ nummeas = munki_comp_nummeas(p, m->calscantime, s->inttime);
+ if ((ev = munki_ledtemp_whitemeasure(p, s->white_data, s->iwhite_data, &s->reftemp,
+ nummeas, s->inttime, s->gainmode)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ /* Compute wavelength white readings from ref temp sensor reading */
+ if ((ev = munki_compute_wav_whitemeas(p, s->cal_factor1, s->cal_factor2,
+ s->white_data)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ /* We don't seem to sanity check the white reference. Presumably */
+ /* this is because a LED isn't going to burn out... */
+
+ /* Compute a calibration factor given the reading of the white reference. */
+ munki_compute_white_cal(p, s->cal_factor1, m->white_ref1, s->cal_factor1,
+ s->cal_factor2, m->white_ref2, s->cal_factor2);
+
+ } else {
+ /* Compute wavelength white readings from sensor */
+ if ((ev = munki_compute_wav_whitemeas(p, s->cal_factor1, s->cal_factor2,
+ s->white_data)) != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+
+ /* Compute a calibration factor given the reading of the white reference. */
+ m->transwarn |= munki_compute_white_cal(p, s->cal_factor1, NULL, s->cal_factor1,
+ s->cal_factor2, NULL, s->cal_factor2);
+ }
+ s->cal_valid = 1;
+ s->cfdate = cdate;
+ s->want_calib = 0;
+ *calt &= ~(inst_calt_ref_white
+ | inst_calt_trans_vwhite);
+ }
+
+ /* Deal with a display integration time selection */
+ if ((*calt & (inst_calt_emis_int_time | inst_calt_ap_flag))
+ && *calc == inst_calc_emis_white
+// && s->cfdate < cdate
+ && (s->emiss && !s->adaptive && !s->scan)) {
+ double scale;
+ double *data;
+ double *tt, tv;
+
+ data = dvectorz(-1, m->nraw-1);
+
+ a1logd(p->log,3,"\nDoing display integration time calibration\n");
+
+ /* Undo any previous swaps */
+ if (s->dispswap == 1) {
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ } else if (s->dispswap == 2) {
+ tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
+ }
+ s->dispswap = 0;
+
+ /* Simply measure the full display white, and if it's close to */
+ /* saturation, switch to the alternate display integration time */
+ nummeas = munki_comp_nummeas(p, s->wreadtime, s->inttime);
+ ev = munki_whitemeasure(p, data , &scale, nummeas,
+ &s->inttime, s->gainmode, s->targoscale);
+ /* Switch to the alternate if things are too bright */
+ /* We do this simply by swapping the alternate values in. */
+ if (ev == MUNKI_RD_SENSORSATURATED || scale < 1.0) {
+ a1logd(p->log,3,"Switching to alternate display integration time %f seconds\n",s->dark_int_time2);
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ s->dispswap = 1;
+
+ /* Do another measurement of the full display white, and if it's close to */
+ /* saturation, switch to the 3rd alternate display integration time */
+ nummeas = munki_comp_nummeas(p, s->wreadtime, s->inttime);
+ ev = munki_whitemeasure(p, data , &scale, nummeas,
+ &s->inttime, s->gainmode, s->targoscale);
+ /* Switch to the 3rd alternate if things are too bright */
+ /* We do this simply by swapping the alternate values in. */
+ if (ev == MUNKI_RD_SENSORSATURATED || scale < 1.0) {
+ a1logd(p->log,3,"Switching to 3rd alternate display integration time %f seconds\n",s->dark_int_time3);
+ /* Undo previous swap */
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ /* swap in 2nd alternate */
+ tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
+ s->dispswap = 2;
+ }
+ }
+ free_dvector(data, -1, m->nraw-1);
+ if (ev != MUNKI_OK) {
+ m->mmode = mmode; /* Restore actual mode */
+ return ev;
+ }
+ s->done_dintsel = 1;
+ s->diseldate = cdate;
+ *calt &= ~inst_calt_emis_int_time;
+
+ a1logd(p->log,3,"Done display integration time selection\n");
+ }
+
+ } /* Look at next mode */
+ m->mmode = mmode; /* Restore actual mode */
+
+ /* Make sure there's the right condition for the calibration */
+ if (*calt & (inst_calt_ref_dark | inst_calt_ref_white)) { /* Reflective calib */
+ if (*calc != inst_calc_man_cal_smode) {
+ *calc = inst_calc_man_cal_smode;
+ return MUNKI_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_em_dark) { /* Emissive Dark calib */
+ id[0] = '\000';
+ if (*calc != inst_calc_man_cal_smode) {
+ *calc = inst_calc_man_cal_smode;
+ return MUNKI_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_trans_dark) { /* Transmissive dark */
+ id[0] = '\000';
+ if (*calc != inst_calc_man_cal_smode) {
+ *calc = inst_calc_man_cal_smode;
+ return MUNKI_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_trans_vwhite) { /* Transmissive white for emulated trans. */
+ id[0] = '\000';
+ if (*calc != inst_calc_man_trans_white) {
+ *calc = inst_calc_man_trans_white;
+ return MUNKI_CAL_SETUP;
+ }
+ } else if (*calt & inst_calt_emis_int_time) {
+ id[0] = '\000';
+ if (*calc != inst_calc_emis_white) {
+ *calc = inst_calc_emis_white;
+ return MUNKI_CAL_SETUP;
+ }
+ }
+
+ /* Go around again if we've still got calibrations to do */
+ if (*calt & inst_calt_all_mask) {
+ return MUNKI_CAL_SETUP;
+ }
+
+ /* We must be done */
+
+#ifdef ENABLE_NONVCAL
+ /* Save the calibration to a file */
+ munki_save_calibration(p);
+#endif
+
+ if (m->transwarn) {
+ *calc = inst_calc_message;
+ if (m->transwarn & 2)
+ strcpy(id, "Warning: Transmission light source is too low for accuracy!");
+ else
+ strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
+ m->transwarn = 0;
+ return MUNKI_OK;
+ }
+
+ a1logd(p->log,3,"Finished cal with dark_valid = %d, cal_valid = %d\n",cs->dark_valid, cs->cal_valid);
+
+ return ev;
+}
+
+/* Interpret an icoms error into a MUNKI error */
+int icoms2munki_err(int se) {
+ if (se != ICOM_OK)
+ return MUNKI_COMS_FAIL;
+ return MUNKI_OK;
+}
+
+
+/* - - - - - - - - - - - - - - - - */
+/* Measure a patch or strip or flash in the current mode. */
+/* To try and speed up the reaction time between */
+/* triggering a scan measurement and being able to */
+/* start moving the instrument, we pre-allocate */
+/* all the buffers and arrays, and pospone processing */
+/* until after the scan is complete. */
+munki_code munki_imp_measure(
+ munki *p,
+ ipatch *vals, /* Pointer to array of instrument patch value */
+ int nvals, /* Number of values */
+ instClamping clamp /* Clamp XYZ/Lab to be +ve */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ unsigned char *buf = NULL; /* Raw USB reading buffer for reflection dark cal */
+ unsigned int bsize;
+ unsigned char *mbuf = NULL; /* Raw USB reading buffer for measurement */
+ unsigned int mbsize;
+ int nummeas = 0, maxnummeas = 0;
+ int nmeasuered = 0; /* Number actually measured */
+ double invsampt = 0.0; /* Invalid sample time */
+ int ninvmeas = 0; /* Number of invalid measurements */
+ double **specrd = NULL; /* Cooked spectral patch values */
+ double duration = 0.0; /* Possible flash duration value */
+ mk_spos spos;
+ int user_trig = 0;
+
+ a1logd(p->log,2,"munki_imp_measure called\n");
+ a1logd(p->log,3,"Taking %d measurments in %s%s%s%s%s mode called\n", nvals,
+ s->emiss ? "Emission" : s->trans ? "Trans" : "Refl",
+ s->emiss && s->ambient ? " Ambient" : "",
+ s->scan ? " Scan" : "",
+ s->flash ? " Flash" : "",
+ s->adaptive ? " Adaptive" : "");
+
+
+ if ((s->emiss && s->adaptive && !s->idark_valid)
+ || ((!s->emiss || !s->adaptive) && !s->dark_valid)
+ || !s->cal_valid) {
+ a1logd(p->log,3,"emis %d, adaptive %d, idark_valid %d\n",s->emiss,s->adaptive,s->idark_valid);
+ a1logd(p->log,3,"dark_valid %d, cal_valid %d\n",s->dark_valid,s->cal_valid);
+ a1logd(p->log,3,"munki_imp_measure need calibration\n");
+ return MUNKI_RD_NEEDS_CAL;
+ }
+
+ if (nvals <= 0
+ || (!s->scan && nvals > 1)) {
+ a1logd(p->log,3,"munki_imp_measure wrong number of patches\n");
+ return MUNKI_INT_WRONGPATCHES;
+ }
+
+ if (s->reflective) {
+ /* Number of invalid samples to allow for LED warmup */
+ invsampt = m->refinvalidsampt;
+ ninvmeas = munki_comp_ru_nummeas(p, invsampt, s->inttime);
+ }
+
+ /* Notional number of measurements, befor adaptive and not counting scan */
+ nummeas = munki_comp_nummeas(p, s->wreadtime, s->inttime);
+
+ /* Allocate buffer for dark measurement */
+ if (s->reflective) {
+ bsize = m->nsen * 2 * nummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"munki_imp_measure malloc %d bytes failed (5)\n",bsize);
+ return MUNKI_INT_MALLOC;
+ }
+ }
+
+ /* Allocate buffer for measurement */
+ maxnummeas = munki_comp_nummeas(p, s->maxscantime, s->inttime);
+ if (maxnummeas < (ninvmeas + nummeas))
+ maxnummeas = (ninvmeas + nummeas);
+ mbsize = m->nsen * 2 * maxnummeas;
+ if ((mbuf = (unsigned char *)malloc(sizeof(unsigned char) * mbsize)) == NULL) {
+ if (buf != NULL)
+ free(buf);
+ a1logd(p->log,1,"munki_imp_measure malloc %d bytes failed (6)\n",mbsize);
+ return MUNKI_INT_MALLOC;
+ }
+ specrd = dmatrix(0, nvals-1, 0, m->nwav-1);
+
+ if (m->trig == inst_opt_trig_user_switch) {
+ m->hide_switch = 1; /* Supress switch events */
+
+#ifdef USE_THREAD
+ {
+ int currcount = m->switch_count; /* Variable set by thread */
+ while (currcount == m->switch_count) {
+ inst_code rc;
+ int cerr;
+
+ /* Don't trigger on user key if scan, only trigger */
+ /* on instrument switch */
+ if (p->uicallback != NULL
+ && (rc = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rc == inst_user_abort) {
+ ev = MUNKI_USER_ABORT;
+ break; /* Abort */
+ }
+ if (!s->scan && rc == inst_user_trig) {
+ ev = MUNKI_USER_TRIG;
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(100);
+ }
+ }
+#else
+ /* Throw one away in case the switch was pressed prematurely */
+ munki_waitfor_switch_th(p, NULL, NULL, 0.01);
+
+ for (;;) {
+ mk_eve ecode;
+ int cerr;
+
+ if ((ev = munki_waitfor_switch_th(p, &ecode, NULL, 0.1)) != MUNKI_OK
+ && ev != MUNKI_INT_BUTTONTIMEOUT)
+ break; /* Error */
+
+ if (ev == MUNKI_OK && ecode == mk_eve_switch_press)
+ break; /* switch triggered */
+
+ /* Don't trigger on user key if scan, only trigger */
+ /* on instrument switch */
+ if (p->uicallback != NULL
+ && (rc = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rc == inst_user_abort) {
+ ev = MUNKI_USER_ABORT;
+ break; /* Abort */
+ }
+ if (!s->scan && rc == inst_user_trig) {
+ ev = MUNKI_USER_TRIG;
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ }
+#endif
+ a1logd(p->log,3,"############# triggered ##############\n");
+ if (p->uicallback) /* Notify of trigger */
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ m->hide_switch = 0; /* Enable switch events again */
+
+ } else if (m->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "hcfr: inst_opt_trig_user but no uicallback function set!\n");
+ ev = MUNKI_UNSUPPORTED;
+
+ } else {
+
+ for (;;) {
+ inst_code rc;
+ if ((rc = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rc == inst_user_abort) {
+ ev = MUNKI_USER_ABORT; /* Abort */
+ break;
+ }
+ if (rc == inst_user_trig) {
+ ev = MUNKI_USER_TRIG;
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ }
+ a1logd(p->log,3,"############# triggered ##############\n");
+ if (p->uicallback) /* Notify of trigger */
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ ev = MUNKI_USER_ABORT; /* Abort */
+ }
+
+ if (ev != MUNKI_OK && ev != MUNKI_USER_TRIG) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(mbuf);
+ if (buf != NULL)
+ free(buf);
+ a1logd(p->log,3,"munki_imp_measure user aborted, terminated, command, or failure\n");
+ return ev; /* User abort, term, command or failure */
+ }
+
+ /* Get current sensor position */
+ if ((ev = munki_getstatus(p, &spos, NULL)) != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(mbuf);
+ if (buf != NULL)
+ free(buf);
+ a1logd(p->log,3,"munki_imp_measure getstatus failed\n");
+ return ev;
+ }
+
+ /* Check the current sensor position */
+ if (!m->nosposcheck) {
+ if (s->emiss) {
+ if (s->ambient) {
+ if (spos != mk_spos_amb)
+ ev = MUNKI_SPOS_AMB;
+ } else if (s->projector) {
+ if (spos != mk_spos_proj)
+ ev = MUNKI_SPOS_PROJ;
+ } else { /* Display */
+ if (spos != mk_spos_surf)
+ ev = MUNKI_SPOS_SURF;
+ }
+ } else { /* Reflective or transmissive */
+ if (spos != mk_spos_surf)
+ ev = MUNKI_SPOS_SURF;
+ }
+ if (ev != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(mbuf);
+ if (buf != NULL)
+ free(buf);
+ a1logd(p->log,3,"munki_imp_measure: Sensor in wrong position\n");
+ return ev;
+ }
+ }
+
+ /* Emissive adaptive, non-scan */
+ if (s->emiss && !s->scan && s->adaptive) {
+ int saturated = 0;
+ double optscale = 1.0;
+ s->inttime = 0.25;
+ s->gainmode = 0;
+ s->dark_valid = 0;
+
+ a1logd(p->log,3,"Trial measure emission with inttime %f, gainmode %d\n",s->inttime,s->gainmode);
+
+ /* Take a trial measurement reading using the current mode. */
+ /* Used to determine if sensor is saturated, or not optimal */
+ nummeas = munki_comp_nummeas(p, s->wreadtime, s->inttime);
+ if ((ev = munki_trialmeasure(p, &saturated, &optscale, nummeas, &s->inttime, s->gainmode,
+ s->targoscale)) != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(mbuf);
+ a1logd(p->log,3,"munki_imp_measure trial measure failed\n");
+ return ev;
+ }
+
+ if (saturated) {
+ s->inttime = m->min_int_time;
+
+ a1logd(p->log,3,"2nd trial measure emission with inttime %f, gainmode %d\n",
+ s->inttime,s->gainmode);
+ /* Take a trial measurement reading using the current mode. */
+ /* Used to determine if sensor is saturated, or not optimal */
+ nummeas = munki_comp_nummeas(p, s->wreadtime, s->inttime);
+ if ((ev = munki_trialmeasure(p, &saturated, &optscale, nummeas, &s->inttime,
+ s->gainmode, s->targoscale)) != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(mbuf);
+ a1logd(p->log,3,"munki_imp_measure trial measure failed\n");
+ return ev;
+ }
+ }
+
+ a1logd(p->log,3,"Compute optimal integration time\n");
+ /* For adaptive mode, compute a new integration time and gain mode */
+ /* in order to optimise the sensor values. */
+ if ((ev = munki_optimise_sensor(p, &s->inttime, &s->gainmode,
+ s->inttime, s->gainmode, 1, 1, &s->targoscale, optscale, 0.0)) != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(mbuf);
+ a1logd(p->log,3,"munki_imp_measure optimise sensor failed\n");
+ return ev;
+ }
+ a1logd(p->log,3,"Computed optimal emiss inttime %f and gainmode %d\n",s->inttime,s->gainmode);
+
+ a1logd(p->log,3,"Interpolate dark calibration reference\n");
+ if ((ev = munki_interp_dark(p, s->dark_data, s->inttime, s->gainmode)) != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(mbuf);
+ a1logd(p->log,3,"munki_imp_measure interplate dark ref failed\n");
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+
+ /* Recompute number of measurements and realloc measurement buffer */
+ free(mbuf);
+ nummeas = munki_comp_nummeas(p, s->wreadtime, s->inttime);
+ maxnummeas = munki_comp_nummeas(p, s->maxscantime, s->inttime);
+ if (maxnummeas < nummeas)
+ maxnummeas = nummeas;
+ mbsize = m->nsen * 2 * maxnummeas;
+ if ((mbuf = (unsigned char *)malloc(sizeof(unsigned char) * mbsize)) == NULL) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ a1logd(p->log,1,"munki_imp_measure malloc %d bytes failed (7)\n",mbsize);
+ return MUNKI_INT_MALLOC;
+ }
+
+ } else if (s->reflective) {
+
+ DISDPLOT
+
+ a1logd(p->log,3,"Doing on the fly black calibration_1 with nummeas %d int_time %f, gainmode %d\n",
+ nummeas, s->inttime, s->gainmode);
+
+ if ((ev = munki_dark_measure_1(p, nummeas, &s->inttime, s->gainmode, buf, bsize))
+ != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(buf);
+ free(mbuf);
+ a1logd(p->log,3,"munki_imp_measure dak measure 1 failed\n");
+ return ev;
+ }
+
+ ENDPLOT
+ }
+ /* Take a measurement reading using the current mode. */
+ /* Converts to completely processed output readings. */
+
+ a1logd(p->log,3,"Do main measurement reading\n");
+
+ /* Indicate to the user that they can now scan the instrument, */
+ /* after a little delay that allows for the instrument reaction time. */
+ if (s->scan) {
+ /* 100msec delay, 1KHz for 200 msec */
+ msec_beep(0 + (int)(invsampt * 1000.0 + 0.9), 1000, 200);
+ }
+
+ /* Retry loop in case a display read is saturated */
+ for (;;) {
+
+ /* Trigger measure and gather raw readings */
+ if ((ev = munki_read_patches_1(p, ninvmeas, nummeas, maxnummeas, &s->inttime, s->gainmode,
+ &nmeasuered, mbuf, mbsize)) != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ if (buf != NULL)
+ free(buf);
+ free(mbuf);
+ a1logd(p->log,3,"munki_imp_measure failed at munki_read_patches_1\n");
+ return ev;
+ }
+
+ /* Complete processing of dark readings now that main measurement has been taken */
+ if (s->reflective) {
+ a1logd(p->log,3,"Calling black calibration_2 calc with nummeas %d, inttime %f, gainmode %d\n", nummeas, s->inttime,s->gainmode);
+ if ((ev = munki_dark_measure_2(p, s->dark_data, nummeas, s->inttime,
+ s->gainmode, buf, bsize)) != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(buf);
+ free(mbuf);
+ a1logd(p->log,3,"munki_imp_measure failed at munki_dark_measure_2\n");
+ return ev;
+ }
+ s->dark_valid = 1;
+ s->dark_int_time = s->inttime;
+ s->dark_gain_mode = s->gainmode;
+ free(buf);
+ }
+
+ /* Process the raw measurement readings into final spectral readings */
+ ev = munki_read_patches_2(p, &duration, specrd, nvals, s->inttime, s->gainmode,
+ ninvmeas, nmeasuered, mbuf, mbsize);
+ /* Special case display mode read. If the sensor is saturated, and */
+ /* we haven't already done so, switch to the alternate integration time */
+ /* and try again. */
+ if (s->emiss && !s->scan && !s->adaptive
+ && ev == MUNKI_RD_SENSORSATURATED
+ && s->dispswap < 2) {
+ double *tt, tv;
+
+ if (s->dispswap == 0) {
+ a1logd(p->log,3,"Switching to alternate display integration time %f seconds\n",s->dark_int_time2);
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ s->dispswap = 1;
+ } else if (s->dispswap == 1) {
+ a1logd(p->log,3,"Switching to 2nd alternate display integration time %f seconds\n",s->dark_int_time3);
+ /* Undo first swap */
+ tv = s->inttime; s->inttime = s->dark_int_time2; s->dark_int_time2 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data2; s->dark_data2 = tt;
+ /* Do 2nd swap */
+ tv = s->inttime; s->inttime = s->dark_int_time3; s->dark_int_time3 = tv;
+ tt = s->dark_data; s->dark_data = s->dark_data3; s->dark_data3 = tt;
+ s->dispswap = 2;
+ }
+ /* Recompute number of measurements and realloc measurement buffer */
+ free(mbuf);
+ nummeas = munki_comp_nummeas(p, s->wreadtime, s->inttime);
+ maxnummeas = munki_comp_nummeas(p, s->maxscantime, s->inttime);
+ if (maxnummeas < nummeas)
+ maxnummeas = nummeas;
+ mbsize = m->nsen * 2 * maxnummeas;
+ if ((mbuf = (unsigned char *)malloc(sizeof(unsigned char) * mbsize)) == NULL) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ a1logd(p->log,1,"munki_imp_measure malloc %d bytes failed (7)\n",mbsize);
+ return MUNKI_INT_MALLOC;
+ }
+ continue; /* Do the measurement again */
+ }
+
+ if (ev != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ free(mbuf);
+ a1logd(p->log,3,"munki_imp_measure failed at munki_read_patches_2\n");
+ return ev;
+ }
+ break; /* Don't repeat */
+ }
+ free(mbuf);
+
+ /* Transfer spectral and convert to XYZ */
+ if ((ev = munki_conv2XYZ(p, vals, nvals, specrd, clamp)) != MUNKI_OK) {
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+ a1logd(p->log,3,"munki_imp_measure failed at munki_conv2XYZ\n");
+ return ev;
+ }
+ free_dmatrix(specrd, 0, nvals-1, 0, m->nwav-1);
+
+ if (nvals > 0)
+ vals[0].duration = duration; /* Possible flash duration */
+
+ a1logd(p->log,3,"munki_imp_measure sucessful return\n");
+ if (user_trig)
+ return MUNKI_USER_TRIG;
+ return ev;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/*
+
+ Determining the refresh rate for a refresh type display.
+
+ This is easy when the max sample rate of the i1 is above
+ the nyquist of the display, and will always be the case
+ for the range we are prepared to measure (up to 100Hz)
+ when using an Rev B, D or E, but is a problem for the
+ rev A and ColorMunki, which can only sample at 113Hz.
+
+ We work around this problem by detecting when
+ we are measuring an alias of the refresh rate, and
+ average the aliasing corrected measurements.
+
+ If there is no aparent refresh, or the refresh rate is not determinable,
+ return a period of 0.0 and inst_ok;
+*/
+
+munki_code munki_measure_rgb(munki *p, double *inttime, double *rgb);
+
+#ifndef PSRAND32L
+# define PSRAND32L(S) ((S) * 1664525L + 1013904223L)
+#endif
+#undef FREQ_SLOW_PRECISE /* [und] Interpolate then autocorrelate, else autc & filter */
+#define NFSAMPS 80 /* Number of samples to read */
+#define NFMXTIME 6.0 /* Maximum time to take (2000 == 6) */
+#define PBPMS 20 /* bins per msec */
+#define PERMIN ((1000 * PBPMS)/40) /* 40 Hz */
+#define PERMAX ((1000 * PBPMS)/4) /* 4 Hz*/
+#define NPER (PERMAX - PERMIN + 1)
+#define PWIDTH (8 * PBPMS) /* 8 msec bin spread to look for peak in */
+#define MAXPKS 20 /* Number of peaks to find */
+#define TRIES 8 /* Number of different sample rates to try */
+
+munki_code munki_imp_meas_refrate(
+ munki *p,
+ double *ref_rate
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ int i, j, k, mm;
+ double **multimeas; /* Spectral measurements */
+ int nummeas;
+ double rgbw[3] = { 610.0, 520.0, 460.0 };
+ double ucalf = 1.0; /* usec_time calibration factor */
+ double inttime;
+ static unsigned int randn = 0x12345678;
+ struct {
+ double sec;
+ double rgb[3];
+ } samp[NFSAMPS * 2];
+ int nfsamps; /* Actual samples read */
+ double minv[3]; /* Minimum reading */
+ double maxv[3]; /* Maximum reading */
+ double maxt; /* Time range */
+#ifdef FREQ_SLOW_PRECISE
+ int nbins;
+ double *bins[3]; /* PBPMS sample bins */
+#else
+ double tcorr[NPER]; /* Temp for initial autocorrelation */
+ int ntcorr[NPER]; /* Number accumulated */
+#endif
+ double corr[NPER]; /* Filtered correlation for each period value */
+ double mincv, maxcv; /* Max and min correlation values */
+ double crange; /* Correlation range */
+ double peaks[MAXPKS]; /* Peak wavelength */
+ double peakh[MAXPKS]; /* Peak heighheight */
+ int npeaks; /* Number of peaks */
+ double pval; /* Period value */
+ double rfreq[TRIES]; /* Computed refresh frequency for each try */
+ double rsamp[TRIES]; /* Sampling rate used to measure frequency */
+ int tix = 0; /* try index */
+
+ a1logd(p->log,2,"munki_imp_meas_refrate called\n");
+
+ if (!s->emiss) {
+ a1logd(p->log,2,"munki_imp_meas_refrate not in emissive mode\n");
+ return MUNKI_UNSUPPORTED;
+ }
+
+ for (mm = 0; mm < TRIES; mm++) {
+ rfreq[mm] = 0.0;
+ npeaks = 0; /* Number of peaks */
+ nummeas = NFSAMPS;
+ multimeas = dmatrix(0, nummeas-1, -1, m->nwav-1);
+
+ if (mm == 0)
+ inttime = m->min_int_time;
+ else {
+ double rval, dmm;
+ randn = PSRAND32L(randn);
+ rval = (double)randn/4294967295.0;
+ dmm = ((double)mm + rval - 0.5)/(TRIES - 0.5);
+ inttime = m->min_int_time * (1.0 + dmm * 0.80);
+ }
+
+ if ((ev = munki_read_patches_all(p, multimeas, nummeas, &inttime, 0)) != inst_ok) {
+ free_dmatrix(multimeas, 0, nummeas-1, 0, m->nwav-1);
+ return ev;
+ }
+
+ rsamp[tix] = 1.0/inttime;
+
+ /* Convert the samples to RGB */
+ for (i = 0; i < nummeas && i < NFSAMPS; i++) {
+ samp[i].sec = i * inttime;
+ samp[i].rgb[0] = samp[i].rgb[1] = samp[i].rgb[2] = 0.0;
+ for (j = 0; j < m->nwav; j++) {
+ double wl = XSPECT_WL(m->wl_short, m->wl_long, m->nwav, j);
+
+//printf("~1 multimeas %d %d = %f\n",i, j, multimeas[i][j]);
+ for (k = 0; k < 3; k++) {
+ double tt = (double)(wl - rgbw[k]);
+ tt = (40.0 - fabs(tt))/40.0;
+ if (tt < 0.0)
+ tt = 0.0;
+ samp[i].rgb[k] += tt * multimeas[i][j];
+ }
+ }
+ }
+ nfsamps = i;
+
+ a1logd(p->log, 3, "munki_measure_refresh: Read %d samples for refresh calibration\n",nfsamps);
+
+#ifdef NEVER
+ /* Plot the raw sensor values */
+ {
+ double xx[NFSAMPS];
+ double y1[NFSAMPS];
+ double y2[NFSAMPS];
+ double y3[NFSAMPS];
+
+ for (i = 0; i < nfsamps; i++) {
+ xx[i] = samp[i].sec;
+ y1[i] = samp[i].rgb[0];
+ y2[i] = samp[i].rgb[1];
+ y3[i] = samp[i].rgb[2];
+// printf("%d: %f -> %f\n",i,samp[i].sec, samp[i].rgb[0]);
+ }
+ printf("Fast scan sensor values and time (sec)\n");
+ do_plot6(xx, y1, y2, y3, NULL, NULL, NULL, nfsamps);
+ }
+#endif
+
+ /* Locate the smallest values and maximum time */
+ maxt = -1e6;
+ minv[0] = minv[1] = minv[2] = 1e20;
+ maxv[0] = maxv[1] = maxv[2] = -11e20;
+ for (i = nfsamps-1; i >= 0; i--) {
+ if (samp[i].sec > maxt)
+ maxt = samp[i].sec;
+ for (j = 0; j < 3; j++) {
+ if (samp[i].rgb[j] < minv[j])
+ minv[j] = samp[i].rgb[j];
+ if (samp[i].rgb[j] > maxv[j])
+ maxv[j] = samp[i].rgb[j];
+ }
+ }
+ /* Re-zero the sample times, and normalise the readings */
+ for (i = nfsamps-1; i >= 0; i--) {
+ samp[i].sec -= samp[0].sec;
+ samp[i].sec *= ucalf;
+ if (samp[i].sec > maxt)
+ maxt = samp[i].sec;
+ for (j = 0; j < 3; j++) {
+ samp[i].rgb[j] -= minv[j];
+ }
+ }
+
+#ifdef FREQ_SLOW_PRECISE /* Interpolate then autocorrelate */
+
+ /* Create PBPMS bins and interpolate readings into them */
+ nbins = 1 + (int)(maxt * 1000.0 * PBPMS + 0.5);
+ for (j = 0; j < 3; j++) {
+ if ((bins[j] = (double *)calloc(sizeof(double), nbins)) == NULL) {
+ a1loge(p->log, inst_internal_error, "munki_measure_refresh: malloc failed\n");
+ return MUNKI_INT_MALLOC;
+ }
+ }
+
+ /* Do the interpolation */
+ for (k = 0; k < (nfsamps-1); k++) {
+ int sbin, ebin;
+ sbin = (int)(samp[k].sec * 1000.0 * PBPMS + 0.5);
+ ebin = (int)(samp[k+1].sec * 1000.0 * PBPMS + 0.5);
+ for (i = sbin; i <= ebin; i++) {
+ double bl;
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ bl = (i - sbin)/(double)(ebin - sbin); /* 0.0 to 1.0 */
+ for (j = 0; j < 3; j++) {
+ bins[j][i] = (1.0 - bl) * samp[k].rgb[j] + bl * samp[k+1].rgb[j];
+ }
+ }
+ }
+
+#ifdef NEVER
+ /* Plot interpolated values */
+ {
+ double *xx;
+ double *y1;
+ double *y2;
+ double *y3;
+
+ xx = malloc(sizeof(double) * nbins);
+ y1 = malloc(sizeof(double) * nbins);
+ y2 = malloc(sizeof(double) * nbins);
+ y3 = malloc(sizeof(double) * nbins);
+
+ if (xx == NULL || y1 == NULL || y2 == NULL || y3 == NULL) {
+ a1loge(p->log, inst_internal_error, "munki_measure_refresh: malloc failed\n");
+ for (j = 0; j < 3; j++)
+ free(bins[j]);
+ return MUNKI_INT_MALLOC;
+ }
+ for (i = 0; i < nbins; i++) {
+ xx[i] = i / (double)PBPMS; /* msec */
+ y1[i] = bins[0][i];
+ y2[i] = bins[1][i];
+ y3[i] = bins[2][i];
+ }
+ printf("Interpolated fast scan sensor values and time (msec) for inttime %f\n",inttime);
+ do_plot6(xx, y1, y2, y3, NULL, NULL, NULL, nbins);
+
+ free(xx);
+ free(y1);
+ free(y2);
+ free(y3);
+ }
+#endif /* PLOT_REFRESH */
+
+ /* Compute auto-correlation at 1/PBPMS msec intervals */
+ /* from 25 msec (40Hz) to 100msec (10 Hz) */
+ mincv = 1e48, maxcv = -1e48;
+ for (i = 0; i < NPER; i++) {
+ int poff = PERMIN + i; /* Offset to corresponding sample */
+
+ corr[i] = 0;
+ for (k = 0; (k + poff) < nbins; k++) {
+ corr[i] += bins[0][k] * bins[0][k + poff]
+ + bins[1][k] * bins[1][k + poff]
+ + bins[2][k] * bins[2][k + poff];
+ }
+ corr[i] /= (double)k; /* Normalize */
+
+ if (corr[i] > maxcv)
+ maxcv = corr[i];
+ if (corr[i] < mincv)
+ mincv = corr[i];
+ }
+ /* Free the bins */
+ for (j = 0; j < 3; j++)
+ free(bins[j]);
+
+#else /* !FREQ_SLOW_PRECISE Fast - autocorrellate then filter */
+
+ /* Upsample by a factor of 2 */
+ for (i = nfsamps-1; i >= 0; i--) {
+ j = 2 * i;
+ samp[j].sec = samp[i].sec;
+ samp[j].rgb[0] = samp[i].rgb[0];
+ samp[j].rgb[1] = samp[i].rgb[1];
+ samp[j].rgb[2] = samp[i].rgb[2];
+ if (i > 0) {
+ j--;
+ samp[j].sec = 0.5 * (samp[i].sec + samp[i-1].sec);
+ samp[j].rgb[0] = 0.5 * (samp[i].rgb[0] + samp[i-1].rgb[0]);
+ samp[j].rgb[1] = 0.5 * (samp[i].rgb[1] + samp[i-1].rgb[1]);
+ samp[j].rgb[2] = 0.5 * (samp[i].rgb[2] + samp[i-1].rgb[2]);
+ }
+ }
+ nfsamps = 2 * nfsamps - 1;
+
+ /* Do point by point correllation of samples */
+ for (i = 0; i < NPER; i++) {
+ tcorr[i] = 0.0;
+ ntcorr[i] = 0;
+ }
+
+ for (j = 0; j < (nfsamps-1); j++) {
+
+ for (k = j+1; k < nfsamps; k++) {
+ double del, cor;
+ int bix;
+
+ del = samp[k].sec - samp[j].sec;
+ bix = (int)(del * 1000.0 * PBPMS + 0.5);
+ if (bix < PERMIN)
+ continue;
+ if (bix > PERMAX)
+ break;
+ bix -= PERMIN;
+
+ cor = samp[j].rgb[0] * samp[k].rgb[0]
+ + samp[j].rgb[1] * samp[k].rgb[1]
+ + samp[j].rgb[2] * samp[k].rgb[2];
+
+//printf("~1 j %d k %d, del %f bix %d cor %f\n",j,k,del,bix,cor);
+ tcorr[bix] += cor;
+ ntcorr[bix]++;
+ }
+ }
+ /* Divide out count and linearly interpolate */
+ j = 0;
+ for (i = 0; i < NPER; i++) {
+ if (ntcorr[i] > 0) {
+ tcorr[i] /= ntcorr[i];
+ if ((i - j) > 1) {
+ if (j == 0) {
+ for (k = j; k < i; k++)
+ tcorr[k] = tcorr[i];
+
+ } else { /* Linearly interpolate from last value */
+ double ww = (double)i-j;
+ for (k = j+1; k < i; k++) {
+ double bl = (k-j)/ww;
+ tcorr[k] = (1.0 - bl) * tcorr[j] + bl * tcorr[i];
+ }
+ }
+ }
+ j = i;
+ }
+ }
+ if (j < (NPER-1)) {
+ for (k = j+1; k < NPER; k++) {
+ tcorr[k] = tcorr[j];
+ }
+ }
+
+#ifdef PLOT_REFRESH
+ /* Plot unfiltered auto correlation */
+ {
+ double xx[NPER];
+ double y1[NPER];
+
+ for (i = 0; i < NPER; i++) {
+ xx[i] = (i + PERMIN) / (double)PBPMS; /* msec */
+ y1[i] = tcorr[i];
+ }
+ printf("Unfiltered auto correlation (msec)\n");
+ do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, NPER);
+ }
+#endif /* PLOT_REFRESH */
+
+ /* Apply a gausian filter */
+#define FWIDTH 100
+ {
+ double gaus_[2 * FWIDTH * PBPMS + 1];
+ double *gaus = &gaus_[FWIDTH * PBPMS];
+ double bb = 1.0/pow(2, 5.0);
+ double fw = inttime * 1000.0;
+ int ifw;
+
+//printf("~1 sc = %f = %f msec\n",1.0/inttime, fw);
+//printf("~1 fw = %f, ifw = %d\n",fw,ifw);
+
+ fw *= 0.9;
+ ifw = (int)ceil(fw * PBPMS);
+ if (ifw > FWIDTH * PBPMS)
+ error("munki: Not enough space for lanczos 2 filter");
+ for (j = -ifw; j <= ifw; j++) {
+ double x, y;
+ x = j/(PBPMS * fw);
+ if (fabs(x) > 1.0)
+ y = 0.0;
+ else
+ y = 1.0/pow(2, 5.0 * x * x) - bb;
+ gaus[j] = y;
+//printf("~1 gaus[%d] = %f\n",j,y);
+ }
+
+ for (i = 0; i < NPER; i++) {
+ double sum = 0.0;
+ double wght = 0.0;
+
+ for (j = -ifw; j <= ifw; j++) {
+ double w;
+ int ix = i + j;
+ if (ix < 0)
+ ix = -ix;
+ if (ix > (NPER-1))
+ ix = 2 * NPER-1 - ix;
+ w = gaus[j];
+ sum += w * tcorr[ix];
+ wght += w;
+ }
+//printf("~1 corr[%d] wgt = %f\n",i,wght);
+ corr[i] = sum / wght;
+ }
+ }
+
+ /* Compute min & max */
+ mincv = 1e48, maxcv = -1e48;
+ for (i = 0; i < NPER; i++) {
+ if (corr[i] > maxcv)
+ maxcv = corr[i];
+ if (corr[i] < mincv)
+ mincv = corr[i];
+ }
+
+#endif /* !FREQ_SLOW_PRECISE Fast - autocorrellate then filter */
+
+ crange = maxcv - mincv;
+ a1logd(p->log,3,"Correlation value range %f - %f = %f = %f%%\n",mincv, maxcv,crange, 100.0 * (maxcv-mincv)/maxcv);
+
+#ifdef PLOT_REFRESH
+ /* Plot this measuremnts auto correlation */
+ {
+ double xx[NPER];
+ double y1[NPER];
+
+ for (i = 0; i < NPER; i++) {
+ xx[i] = (i + PERMIN) / (double)PBPMS; /* msec */
+ y1[i] = corr[i];
+ }
+ printf("Auto correlation (msec)\n");
+ do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, NPER);
+ }
+#endif /* PLOT_REFRESH */
+
+#define PFDB 4 // normally 4
+ /* If there is sufficient level and distict correlations */
+ if (crange/maxcv >= 0.1) {
+
+ a1logd(p->log,PFDB,"Searching for peaks\n");
+
+ /* Locate all the peaks starting at the longest correllation */
+ for (i = (NPER-1-PWIDTH); i >= 0 && npeaks < MAXPKS; i--) {
+ double v1, v2, v3;
+ v1 = corr[i];
+ v2 = corr[i + PWIDTH/2]; /* Peak */
+ v3 = corr[i + PWIDTH];
+
+ if (fabs(v3 - v1)/crange < 0.05
+ && (v2 - v1)/crange > 0.025
+ && (v2 - v3)/crange > 0.025
+ && (v2 - mincv)/crange > 0.5) {
+ double pkv; /* Peak value */
+ int pki; /* Peak index */
+ double ii, bl;
+
+#ifdef PLOT_REFRESH
+ a1logd(p->log,PFDB,"Max between %f and %f msec\n",
+ (i + PERMIN)/(double)PBPMS,(i + PWIDTH + PERMIN)/(double)PBPMS);
+#endif
+
+ /* Locate the actual peak */
+ pkv = -1.0;
+ pki = 0;
+ for (j = i; j < (i + PWIDTH); j++) {
+ if (corr[j] > pkv) {
+ pkv = corr[j];
+ pki = j;
+ }
+ }
+#ifdef PLOT_REFRESH
+ a1logd(p->log,PFDB,"Peak is at %f msec, %f corr\n", (pki + PERMIN)/(double)PBPMS, pkv);
+#endif
+
+ /* Interpolate the peak value for higher precision */
+ /* j = bigest */
+ if (corr[pki-1] > corr[pki+1]) {
+ j = pki-1;
+ k = pki+1;
+ } else {
+ j = pki+1;
+ k = pki-1;
+ }
+ bl = (corr[pki] - corr[j])/(corr[pki] - corr[k]);
+ bl = (bl + 1.0)/2.0;
+ ii = bl * pki + (1.0 - bl) * j;
+ pval = (ii + PERMIN)/(double)PBPMS;
+#ifdef PLOT_REFRESH
+ a1logd(p->log,PFDB,"Interpolated peak is at %f msec\n", pval);
+#endif
+ peaks[npeaks] = pval;
+ peakh[npeaks] = corr[pki];
+ npeaks++;
+
+ i -= PWIDTH;
+ }
+#ifdef NEVER
+ if (v2 > v1 && v2 > v3) {
+ printf("Peak rehjected:\n");
+ printf("(v3 - v1)/crange = %f < 0.05 ?\n",fabs(v3 - v1)/crange);
+ printf("(v2 - v1)/crange = %f > 0.025 ?\n",(v2 - v1)/crange);
+ printf("(v2 - v3)/crange = %f > 0.025 ?\n",(v2 - v3)/crange);
+ printf("(v2 - mincv)/crange = %f > 0.5 ?\n",(v2 - mincv)/crange);
+ }
+#endif
+ }
+ a1logd(p->log,3,"Number of peaks located = %d\n",npeaks);
+
+ } else {
+ a1logd(p->log,3,"All rejected, crange/maxcv = %f < 0.06\n",crange/maxcv);
+ }
+#undef PFDB
+
+ a1logd(p->log,3,"Number of peaks located = %d\n",npeaks);
+
+ if (npeaks > 1) { /* Compute aparent refresh rate */
+ int nfails;
+ double div, avg, ano;
+ /* Try and locate a common divisor amongst all the peaks. */
+ /* This is likely to be the underlying refresh rate. */
+ for (k = 0; k < npeaks; k++) {
+ for (j = 1; j < 25; j++) {
+ avg = ano = 0.0;
+ div = peaks[k]/(double)j;
+ if (div < 5.0)
+ continue; /* Skip anything higher than 200Hz */
+//printf("~1 trying %f Hz\n",1000.0/div);
+ for (nfails = i = 0; i < npeaks; i++) {
+ double rem, cnt;
+
+ rem = peaks[i]/div;
+ cnt = floor(rem + 0.5);
+ rem = fabs(rem - cnt);
+
+#ifdef PLOT_REFRESH
+ a1logd(p->log, 3, "remainder for peak %d = %f\n",i,rem);
+#endif
+ if (rem > 0.06) {
+ if (++nfails > 2)
+ break; /* Fail this divisor */
+ } else {
+ avg += peaks[i]; /* Already weighted by cnt */
+ ano += cnt;
+ }
+ }
+
+ if (nfails == 0 || (nfails <= 2 && npeaks >= 6))
+ break; /* Sucess */
+ /* else go and try a different divisor */
+ }
+ if (j < 25)
+ break; /* Success - found common divisor */
+ }
+ if (k >= npeaks) {
+ a1logd(p->log,3,"Failed to locate common divisor\n");
+
+ } else {
+ pval = 0.001 * avg/ano;
+ if (pval < inttime) {
+ a1logd(p->log,3,"Discarding frequency %f > sample rate %f\n",1.0/pval, 1.0/inttime);
+ } else {
+ pval = 1.0/pval; /* Convert to frequency */
+ rfreq[tix++] = pval;
+ a1logd(p->log,3,"Located frequency %f sum %f dif %f\n",pval, pval + 1.0/inttime, fabs(pval - 1.0/inttime));
+ }
+ }
+ }
+ }
+
+ if (tix >= 3) {
+
+ for (mm = 0; mm < tix; mm++) {
+ a1logd(p->log, 3, "Try %d, samp %f Hz, Meas %f Hz, Sum %f Hz, Dif %f Hz\n",mm,rsamp[mm],rfreq[mm], rsamp[mm] + rfreq[mm], fabs(rsamp[mm] - rfreq[mm]));
+ }
+
+ /* Decide if we are above the nyquist, or whether */
+ /* we have aliases of the fundamental */
+ {
+ double brange = 1e38;
+ double brate = 0.0;
+ int bsplit = -1;
+ double min, max, avg, range;
+ int split, mul, niia;
+
+ /* Compute fundamental and sub aliases at all possible splits. */
+ /* Skip the reading at the split. */
+ for (split = tix; split >= -1; split--) {
+ min = 1e38; max = -1e38; avg = 0.0; niia = 0;
+ for (mm = 0; mm < tix; mm++) {
+ double alias;
+
+ if (mm == split)
+ continue;
+ if (mm < split)
+ alias = rfreq[mm];
+ else
+ alias = fabs(rsamp[mm] - rfreq[mm]);
+
+ avg += alias;
+ niia++;
+
+ if (alias < min)
+ min = alias;
+ if (alias > max)
+ max = alias;
+ }
+ avg /= (double)niia;
+ range = (max - min)/(max + min);
+//printf("~1 split %d avg = %f, range = %f\n",split,avg,range);
+ if (range < brange) {
+ brange = range;
+ brate = avg;
+ bsplit = split;
+ }
+ }
+
+ /* Compute sub and add aliases at all possible splits */
+ /* Skip the reading at the split. */
+ for (split = tix; split >= -1; split--) {
+ min = 1e38; max = -1e38; avg = 0.0; niia = 0;
+ for (mm = 0; mm < tix; mm++) {
+ double alias;
+
+ if (mm == split)
+ continue;
+ if (mm < split)
+ alias = fabs(rsamp[mm] - rfreq[mm]);
+ else
+ alias = rsamp[mm] + rfreq[mm];
+
+ avg += alias;
+ niia++;
+
+ if (alias < min)
+ min = alias;
+ if (alias > max)
+ max = alias;
+ }
+ avg /= (double)niia;
+ range = (max - min)/(max + min);
+//printf("~1 split %d avg = %f, range = %f\n",100 + split,avg,range);
+ if (range < brange) {
+ brange = range;
+ brate = avg;
+ bsplit = 100 + split;
+ }
+ }
+
+ a1logd(p->log, 3, "Selected split %d range %f\n",bsplit,brange);
+
+ /* Hmm. Could reject result and re-try if brange is too large ? ( > 0.005 ?) */
+
+ if (brange > 0.05) {
+ a1logd(p->log, 3, "Readings are too inconsistent (brange %.1f%%) - should retry ?\n",brange * 100.0);
+ } else {
+ if (ref_rate != NULL)
+ *ref_rate = brate;
+
+ /* Error against my 85Hz CRT - GWG */
+// a1logd(p->log, 1, "Refresh rate %f Hz, error = %.4f%%\n",brate,100.0 * fabs(brate - 85.0)/(85.0));
+ return MUNKI_OK;
+ }
+ }
+ } else {
+ a1logd(p->log, 3, "Not enough tries suceeded to determine refresh rate\n");
+ }
+
+ if (ref_rate != NULL)
+ *ref_rate = 0.0;
+
+ return MUNKI_RD_NOREFR_FOUND;
+}
+#undef NFSAMPS
+#undef PBPMS
+#undef PERMIN
+#undef PERMAX
+#undef NPER
+#undef PWIDTH
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Save the calibration for all modes, stored on local system */
+
+#ifdef ENABLE_NONVCAL
+
+/* non-volatile save/restor state to/from a file */
+typedef struct {
+ int ef; /* Error flag, 1 = write failed, 2 = close failed */
+ unsigned int chsum; /* Checksum */
+} mknonv;
+
+static void update_chsum(mknonv *x, unsigned char *p, int nn) {
+ int i;
+ for (i = 0; i < nn; i++, p++)
+ x->chsum = ((x->chsum << 13) | (x->chsum >> (32-13))) + *p;
+}
+
+/* Write an array of chars to the file. Set the error flag to nz on error */
+static void write_chars(mknonv *x, FILE *fp, char *dp, int n) {
+
+ if (fwrite((void *)dp, sizeof(char), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(char));
+ }
+}
+
+/* Write an array of ints to the file. Set the error flag to nz on error */
+static void write_ints(mknonv *x, FILE *fp, int *dp, int n) {
+
+ if (fwrite((void *)dp, sizeof(int), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(int));
+ }
+}
+
+/* Write an array of doubles to the file. Set the error flag to nz on error */
+static void write_doubles(mknonv *x, FILE *fp, double *dp, int n) {
+
+ if (fwrite((void *)dp, sizeof(double), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(double));
+ }
+}
+
+/* Write an array of time_t's to the file. Set the error flag to nz on error */
+/* (This will cause file checksum fail if different executables on the same */
+/* system have different time_t values) */
+static void write_time_ts(mknonv *x, FILE *fp, time_t *dp, int n) {
+
+ if (fwrite((void *)dp, sizeof(time_t), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(time_t));
+ }
+}
+
+/* Read an array of ints from the file. Set the error flag to nz on error */
+static void read_ints(mknonv *x, FILE *fp, int *dp, int n) {
+
+ if (fread((void *)dp, sizeof(int), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(int));
+ }
+}
+
+/* Read an array of chars from the file. Set the error flag to nz on error */
+static void read_chars(mknonv *x, FILE *fp, char *dp, int n) {
+
+ if (fread((void *)dp, sizeof(char), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(char));
+ }
+}
+
+
+/* Read an array of doubles from the file. Set the error flag to nz on error */
+static void read_doubles(mknonv *x, FILE *fp, double *dp, int n) {
+
+ if (fread((void *)dp, sizeof(double), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(double));
+ }
+}
+
+/* Read an array of time_t's from the file. Set the error flag to nz on error */
+/* (This will cause file checksum fail if different executables on the same */
+/* system have different time_t values) */
+static void read_time_ts(mknonv *x, FILE *fp, time_t *dp, int n) {
+
+ if (fread((void *)dp, sizeof(time_t), n, fp) != n) {
+ x->ef = 1;
+ } else {
+ update_chsum(x, (unsigned char *)dp, n * sizeof(time_t));
+ }
+}
+
+munki_code munki_save_calibration(munki *p) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code ev = MUNKI_OK;
+ munki_state *s;
+ int i;
+ char nmode[10];
+ char cal_name[100]; /* Name */
+ char **cal_paths = NULL;
+ int no_paths = 0;
+ FILE *fp;
+ mknonv x;
+ int ss;
+ int argyllversion = ARGYLL_VERSION;
+
+ strcpy(nmode, "w");
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ strcat(nmode, "b");
+#endif
+
+ sprintf(cal_name, "ArgyllCMS/.mk_%s.cal", m->serno);
+ if ((no_paths = xdg_bds(NULL, &cal_paths, xdg_cache, xdg_write, xdg_user, cal_name)) < 1) {
+ a1logd(p->log,1,"munki_save_calibration xdg_bds returned no paths\n");
+ return MUNKI_INT_CAL_SAVE;
+ }
+
+ a1logd(p->log,3,"munki_save_calibration saving to file '%s'\n",cal_paths[0]);
+
+ if (create_parent_directories(cal_paths[0])
+ || (fp = fopen(cal_paths[0], nmode)) == NULL) {
+ a1logd(p->log,3,"munki_save_calibration failed to open file for writing\n");
+ xdg_free(cal_paths, no_paths);
+ return MUNKI_INT_CAL_SAVE;
+ }
+
+ x.ef = 0;
+ x.chsum = 0;
+
+ /* A crude structure signature */
+ ss = sizeof(munki_state) + sizeof(munkiimp);
+
+ /* Some file identification */
+ write_ints(&x, fp, &argyllversion, 1);
+ write_ints(&x, fp, &ss, 1);
+ write_chars(&x, fp, m->serno, 17);
+ write_ints(&x, fp, &m->nraw, 1);
+ write_ints(&x, fp, (int *)&m->nwav1, 1);
+ write_ints(&x, fp, (int *)&m->nwav2, 1);
+
+ /* For each mode, save the calibration if it's valid */
+ for (i = 0; i < mk_no_modes; i++) {
+ s = &m->ms[i];
+
+ /* Mode identification */
+ write_ints(&x, fp, &s->emiss, 1);
+ write_ints(&x, fp, &s->trans, 1);
+ write_ints(&x, fp, &s->reflective, 1);
+ write_ints(&x, fp, &s->scan, 1);
+ write_ints(&x, fp, &s->flash, 1);
+ write_ints(&x, fp, &s->ambient, 1);
+ write_ints(&x, fp, &s->projector, 1);
+ write_ints(&x, fp, &s->adaptive, 1);
+
+ /* Configuration calibration is valid for */
+ write_ints(&x, fp, &s->gainmode, 1);
+ write_doubles(&x, fp, &s->inttime, 1);
+
+ /* Calibration information */
+ write_ints(&x, fp, &s->dark_valid, 1);
+ write_time_ts(&x, fp, &s->ddate, 1);
+ write_doubles(&x, fp, &s->dark_int_time, 1);
+ write_doubles(&x, fp, s->dark_data-1, m->nraw+1);
+ write_doubles(&x, fp, &s->dark_int_time2, 1);
+ write_doubles(&x, fp, s->dark_data2-1, m->nraw+1);
+ write_doubles(&x, fp, &s->dark_int_time3, 1);
+ write_doubles(&x, fp, s->dark_data3-1, m->nraw+1);
+ write_ints(&x, fp, &s->dark_gain_mode, 1);
+
+ if (!s->emiss) {
+ write_ints(&x, fp, &s->cal_valid, 1);
+ write_time_ts(&x, fp, &s->cfdate, 1);
+ write_doubles(&x, fp, s->cal_factor1, m->nwav1);
+ write_doubles(&x, fp, s->cal_factor2, m->nwav2);
+ write_doubles(&x, fp, s->white_data-1, m->nraw+1);
+ write_doubles(&x, fp, &s->reftemp, 1);
+ write_doubles(&x, fp, s->iwhite_data[0]-1, m->nraw+1);
+ write_doubles(&x, fp, s->iwhite_data[1]-1, m->nraw+1);
+ }
+
+ write_ints(&x, fp, &s->idark_valid, 1);
+ write_time_ts(&x, fp, &s->iddate, 1);
+ write_doubles(&x, fp, s->idark_int_time, 4);
+ write_doubles(&x, fp, s->idark_data[0]-1, m->nraw+1);
+ write_doubles(&x, fp, s->idark_data[1]-1, m->nraw+1);
+ write_doubles(&x, fp, s->idark_data[2]-1, m->nraw+1);
+ write_doubles(&x, fp, s->idark_data[3]-1, m->nraw+1);
+ }
+
+ a1logd(p->log,3,"Checkum = 0x%x\n",x.chsum);
+ write_ints(&x, fp, (int *)&x.chsum, 1);
+
+ if (fclose(fp) != 0)
+ x.ef = 2;
+
+ if (x.ef != 0) {
+ a1logd(p->log,3,"Writing calibration file failed with %d\n",x.ef);
+ delete_file(cal_paths[0]);
+ } else {
+ a1logd(p->log,3,"Writing calibration file succeeded\n");
+ }
+ xdg_free(cal_paths, no_paths);
+
+ return ev;
+}
+
+/* Restore the all modes calibration from the local system */
+munki_code munki_restore_calibration(munki *p) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code ev = MUNKI_OK;
+ munki_state *s, ts;
+ int i, j;
+ char nmode[10];
+ char cal_name[100]; /* Name */
+ char **cal_paths = NULL;
+ int no_paths = 0;
+ FILE *fp;
+ mknonv x;
+ int argyllversion;
+ int ss, nraw, nwav1, nwav2, chsum1, chsum2;
+ char serno[17];
+
+ strcpy(nmode, "r");
+#if defined(O_BINARY) || defined(_O_BINARY)
+ strcat(nmode, "b");
+#endif
+
+ sprintf(cal_name, "ArgyllCMS/.mk_%s.cal" SSEPS "color/.mk_%s.cal", m->serno, m->serno);
+ if ((no_paths = xdg_bds(NULL, &cal_paths, xdg_cache, xdg_read, xdg_user, cal_name)) < 1) {
+ a1logd(p->log,1,"munki_restore_calibration xdg_bds returned no paths\n");
+ return MUNKI_INT_CAL_RESTORE;
+ }
+
+ a1logd(p->log,2,"munki_restore_calibration restoring from file '%s'\n",cal_paths[0]);
+
+ /* Check the last modification time */
+ {
+ struct sys_stat sbuf;
+
+ if (sys_stat(cal_paths[0], &sbuf) == 0) {
+ m->lo_secs = time(NULL) - sbuf.st_mtime;
+ a1logd(p->log,2,"munki_restore_calibration: %d secs from instrument last open\n",m->lo_secs);
+ } else {
+ a1logd(p->log,2,"munki_restore_calibration: stat on file failed\n");
+ }
+ }
+
+ if ((fp = fopen(cal_paths[0], nmode)) == NULL) {
+ a1logd(p->log,2,"munki_restore_calibration failed to open file for reading\n");
+ xdg_free(cal_paths, no_paths);
+ return MUNKI_INT_CAL_RESTORE;
+ }
+ xdg_free(cal_paths, no_paths);
+
+ x.ef = 0;
+ x.chsum = 0;
+
+ /* Check the file identification */
+ read_ints(&x, fp, &argyllversion, 1);
+ read_ints(&x, fp, &ss, 1);
+ read_chars(&x, fp, serno, 17);
+ read_ints(&x, fp, &nraw, 1);
+ read_ints(&x, fp, &nwav1, 1);
+ read_ints(&x, fp, &nwav2, 1);
+ if (x.ef != 0
+ || argyllversion != ARGYLL_VERSION
+ || ss != (sizeof(munki_state) + sizeof(munkiimp))
+ || strcmp(serno, m->serno) != 0
+ || nraw != m->nraw
+ || nwav1 != m->nwav1
+ || nwav2 != m->nwav2) {
+ a1logd(p->log,3,"Identification didn't verify\n");
+ goto reserr;
+ }
+
+ /* Do a dummy read to check the checksum */
+ for (i = 0; i < mk_no_modes; i++) {
+ int di;
+ double dd;
+ time_t dt;
+ int emiss, trans, reflective, ambient, projector, scan, flash, adaptive;
+
+ s = &m->ms[i];
+
+ /* Mode identification */
+ read_ints(&x, fp, &emiss, 1);
+ read_ints(&x, fp, &trans, 1);
+ read_ints(&x, fp, &reflective, 1);
+ read_ints(&x, fp, &scan, 1);
+ read_ints(&x, fp, &flash, 1);
+ read_ints(&x, fp, &ambient, 1);
+ read_ints(&x, fp, &projector, 1);
+ read_ints(&x, fp, &adaptive, 1);
+
+ /* Configuration calibration is valid for */
+ read_ints(&x, fp, &di, 1); /* gainmode */
+ read_doubles(&x, fp, &dd, 1); /* inttime */
+
+ /* Calibration information */
+ read_ints(&x, fp, &di, 1); /* dark_valid */
+ read_time_ts(&x, fp, &dt, 1); /* ddate */
+ read_doubles(&x, fp, &dd, 1); /* dark_int_time */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* dark_data */
+ read_doubles(&x, fp, &dd, 1); /* dark_int_time2 */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* dark_data2 */
+ read_doubles(&x, fp, &dd, 1); /* dark_int_time3 */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* dark_data3 */
+ read_ints(&x, fp, &di, 1); /* dark_gain_mode */
+
+ if (!s->emiss) {
+ read_ints(&x, fp, &di, 1); /* cal_valid */
+ read_time_ts(&x, fp, &dt, 1); /* cfdate */
+ for (j = 0; j < m->nwav1; j++)
+ read_doubles(&x, fp, &dd, 1); /* cal_factor1 */
+ for (j = 0; j < m->nwav2; j++)
+ read_doubles(&x, fp, &dd, 1); /* cal_factor2 */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* white_data */
+ read_doubles(&x, fp, &dd, 1); /* reftemp */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* iwhite_data[0] */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* iwhite_data[1] */
+ }
+
+ read_ints(&x, fp, &di, 1); /* idark_valid */
+ read_time_ts(&x, fp, &dt, 1); /* iddate */
+ for (j = 0; j < 4; j++)
+ read_doubles(&x, fp, &dd, 1); /* idark_int_time */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* idark_data[0] */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* idark_data[1] */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* idark_data[2] */
+ for (j = -1; j < m->nraw; j++)
+ read_doubles(&x, fp, &dd, 1); /* idark_data[3] */
+ }
+
+ chsum1 = x.chsum;
+ read_ints(&x, fp, &chsum2, 1);
+
+ if (x.ef != 0
+ || chsum1 != chsum2) {
+ a1logd(p->log,3,"Checksum didn't verify, got 0x%x, expected 0x%x\n",chsum1, chsum2);
+ goto reserr;
+ }
+
+ rewind(fp);
+
+ /* Allocate space in temp structure */
+
+ ts.dark_data = dvectorz(-1, m->nraw-1);
+ ts.dark_data2 = dvectorz(-1, m->nraw-1);
+ ts.dark_data3 = dvectorz(-1, m->nraw-1);
+ ts.cal_factor1 = dvectorz(0, m->nwav1-1);
+ ts.cal_factor2 = dvectorz(0, m->nwav2-1);
+ ts.white_data = dvectorz(-1, m->nraw-1);
+ ts.iwhite_data = dmatrixz(0, 2, -1, m->nraw-1);
+ ts.idark_data = dmatrixz(0, 3, -1, m->nraw-1);
+
+ /* Read the identification */
+ read_ints(&x, fp, &argyllversion, 1);
+ read_ints(&x, fp, &ss, 1);
+ read_chars(&x, fp, m->serno, 17);
+ read_ints(&x, fp, &m->nraw, 1);
+ read_ints(&x, fp, (int *)&m->nwav1, 1);
+ read_ints(&x, fp, (int *)&m->nwav2, 1);
+
+ /* For each mode, save the calibration if it's valid */
+ for (i = 0; i < mk_no_modes; i++) {
+ s = &m->ms[i];
+
+ /* Mode identification */
+ read_ints(&x, fp, &ts.emiss, 1);
+ read_ints(&x, fp, &ts.trans, 1);
+ read_ints(&x, fp, &ts.reflective, 1);
+ read_ints(&x, fp, &ts.scan, 1);
+ read_ints(&x, fp, &ts.flash, 1);
+ read_ints(&x, fp, &ts.ambient, 1);
+ read_ints(&x, fp, &ts.projector, 1);
+ read_ints(&x, fp, &ts.adaptive, 1);
+
+ /* Configuration calibration is valid for */
+ read_ints(&x, fp, &ts.gainmode, 1);
+ read_doubles(&x, fp, &ts.inttime, 1);
+
+ /* Calibration information: */
+
+ /* Static Dark */
+ read_ints(&x, fp, &ts.dark_valid, 1);
+ read_time_ts(&x, fp, &ts.ddate, 1);
+ read_doubles(&x, fp, &ts.dark_int_time, 1);
+ read_doubles(&x, fp, ts.dark_data-1, m->nraw+1);
+ read_doubles(&x, fp, &ts.dark_int_time2, 1);
+ read_doubles(&x, fp, ts.dark_data2-1, m->nraw+1);
+ read_doubles(&x, fp, &ts.dark_int_time3, 1);
+ read_doubles(&x, fp, ts.dark_data3-1, m->nraw+1);
+ read_ints(&x, fp, &ts.dark_gain_mode, 1);
+
+ if (!ts.emiss) {
+ /* Reflective */
+ read_ints(&x, fp, &ts.cal_valid, 1);
+ read_time_ts(&x, fp, &ts.cfdate, 1);
+ read_doubles(&x, fp, ts.cal_factor1, m->nwav1);
+ read_doubles(&x, fp, ts.cal_factor2, m->nwav2);
+ read_doubles(&x, fp, ts.white_data-1, m->nraw+1);
+ read_doubles(&x, fp, &ts.reftemp, 1);
+ read_doubles(&x, fp, ts.iwhite_data[0]-1, m->nraw+1);
+ read_doubles(&x, fp, ts.iwhite_data[1]-1, m->nraw+1);
+ }
+
+ /* Adaptive Dark */
+ read_ints(&x, fp, &ts.idark_valid, 1);
+ read_time_ts(&x, fp, &ts.iddate, 1);
+ read_doubles(&x, fp, ts.idark_int_time, 4);
+ read_doubles(&x, fp, ts.idark_data[0]-1, m->nraw+1);
+ read_doubles(&x, fp, ts.idark_data[1]-1, m->nraw+1);
+ read_doubles(&x, fp, ts.idark_data[2]-1, m->nraw+1);
+ read_doubles(&x, fp, ts.idark_data[3]-1, m->nraw+1);
+
+ /* If the configuration for this mode matches */
+ /* that of the calibration, restore the calibration */
+ /* for this mode. */
+ if (x.ef == 0 /* No read error */
+ && s->emiss == ts.emiss
+ && s->trans == ts.trans
+ && s->reflective == ts.reflective
+ && s->scan == ts.scan
+ && s->flash == ts.flash
+ && s->ambient == ts.ambient
+ && s->projector == ts.projector
+ && s->adaptive == ts.adaptive
+ && (s->adaptive || fabs(s->inttime - ts.inttime) < 0.01)
+ && (s->adaptive || fabs(s->dark_int_time - ts.dark_int_time) < 0.01)
+ && (s->adaptive || fabs(s->dark_int_time2 - ts.dark_int_time2) < 0.01)
+ && (s->adaptive || fabs(s->dark_int_time3 - ts.dark_int_time3) < 0.01)
+ && (!s->adaptive || fabs(s->idark_int_time[0] - ts.idark_int_time[0]) < 0.01)
+ && (!s->adaptive || fabs(s->idark_int_time[1] - ts.idark_int_time[1]) < 0.01)
+ && (!s->adaptive || fabs(s->idark_int_time[2] - ts.idark_int_time[2]) < 0.01)
+ && (!s->adaptive || fabs(s->idark_int_time[3] - ts.idark_int_time[3]) < 0.01)
+ ) {
+ /* Copy all the fields read above */
+ s->emiss = ts.emiss;
+ s->trans = ts.trans;
+ s->reflective = ts.reflective;
+ s->scan = ts.scan;
+ s->flash = ts.flash;
+ s->ambient = ts.ambient;
+ s->projector = ts.projector;
+ s->adaptive = ts.adaptive;
+
+ s->gainmode = ts.gainmode;
+ s->inttime = ts.inttime;
+ s->dark_valid = ts.dark_valid;
+ s->ddate = ts.ddate;
+ s->dark_int_time = ts.dark_int_time;
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data[j] = ts.dark_data[j];
+ s->dark_int_time2 = ts.dark_int_time2;
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data2[j] = ts.dark_data2[j];
+ s->dark_int_time3 = ts.dark_int_time3;
+ for (j = -1; j < m->nraw; j++)
+ s->dark_data3[j] = ts.dark_data3[j];
+ s->dark_gain_mode = ts.dark_gain_mode;
+ if (!ts.emiss) {
+ s->cal_valid = ts.cal_valid;
+ s->cfdate = ts.cfdate;
+ for (j = 0; j < m->nwav1; j++)
+ s->cal_factor1[j] = ts.cal_factor1[j];
+ for (j = 0; j < m->nwav2; j++)
+ s->cal_factor2[j] = ts.cal_factor2[j];
+ for (j = -1; j < m->nraw; j++)
+ s->white_data[j] = ts.white_data[j];
+ s->reftemp = ts.reftemp;
+ for (j = -1; j < m->nraw; j++)
+ s->iwhite_data[0][j] = ts.iwhite_data[0][j];
+ for (j = -1; j < m->nraw; j++)
+ s->iwhite_data[1][j] = ts.iwhite_data[1][j];
+ }
+ s->idark_valid = ts.idark_valid;
+ s->iddate = ts.iddate;
+ for (j = 0; j < 4; j++)
+ s->idark_int_time[j] = ts.idark_int_time[j];
+ for (j = -1; j < m->nraw; j++)
+ s->idark_data[0][j] = ts.idark_data[0][j];
+ for (j = -1; j < m->nraw; j++)
+ s->idark_data[1][j] = ts.idark_data[1][j];
+ for (j = -1; j < m->nraw; j++)
+ s->idark_data[2][j] = ts.idark_data[2][j];
+ for (j = -1; j < m->nraw; j++)
+ s->idark_data[3][j] = ts.idark_data[3][j];
+
+ } else {
+//printf("~1 mode %d\n",i);
+//printf("~1 adaptive = %d\n",s->adaptive);
+//printf("~1 innttime %f %f\n",s->inttime, ts.inttime);
+//printf("~1 dark_int_time %f %f\n",s->dark_int_time,ts.dark_int_time);
+//printf("~1 dark_int_time2 %f %f\n",s->dark_int_time2,ts.dark_int_time2);
+//printf("~1 dark_int_time3 %f %f\n",s->dark_int_time3,ts.dark_int_time3);
+//printf("~1 idark_int_time0 %f %f\n",s->idark_int_time[0],ts.idark_int_time[0]);
+//printf("~1 idark_int_time1 %f %f\n",s->idark_int_time[1],ts.idark_int_time[1]);
+//printf("~1 idark_int_time2 %f %f\n",s->idark_int_time[2],ts.idark_int_time[2]);
+//printf("~1 idark_int_time3 %f %f\n",s->idark_int_time[3],ts.idark_int_time[3]);
+ a1logd(p->log,4,"Not restoring cal for mode %d since params don't match:\n",i);
+ a1logd(p->log,4,"emis = %d : %d, trans = %d : %d, ref = %d : %d\n",s->emiss,ts.emiss,s->trans,ts.trans,s->reflective,ts.reflective);
+ a1logd(p->log,4,"scan = %d : %d, flash = %d : %d, ambi = %d : %d, proj = %d : %d, adapt = %d : %d\n",s->scan,ts.scan,s->flash,ts.flash,s->ambient,ts.ambient,s->projector,ts.projector,s->adaptive,ts.adaptive);
+ a1logd(p->log,4,"inttime = %f : %f\n",s->inttime,ts.inttime);
+ a1logd(p->log,4,"darkit1 = %f : %f, 2 = %f : %f, 3 = %f : %f\n",s->dark_int_time,ts.dark_int_time,s->dark_int_time2,ts.dark_int_time2,s->dark_int_time3,ts.dark_int_time3);
+ a1logd(p->log,4,"idarkit0 = %f : %f, 1 = %f : %f, 2 = %f : %f, 3 = %f : %f\n",s->idark_int_time[0],ts.idark_int_time[0],s->idark_int_time[1],ts.idark_int_time[1],s->idark_int_time[2],ts.idark_int_time[2],s->idark_int_time[3],ts.idark_int_time[3]);
+ }
+ }
+
+ /* Free up temporary space */
+ free_dvector(ts.dark_data, -1, m->nraw-1);
+ free_dvector(ts.dark_data2, -1, m->nraw-1);
+ free_dvector(ts.dark_data3, -1, m->nraw-1);
+ free_dvector(ts.white_data, -1, m->nraw-1);
+ free_dmatrix(ts.iwhite_data, 0, 1, -1, m->nraw-1);
+ free_dmatrix(ts.idark_data, 0, 3, -1, m->nraw-1);
+
+ free_dvector(ts.cal_factor1, 0, m->nwav1-1);
+ free_dvector(ts.cal_factor2, 0, m->nwav2-1);
+
+ a1logd(p->log,3,"munki_restore_calibration done\n");
+ reserr:;
+
+ fclose(fp);
+
+ return ev;
+}
+
+munki_code munki_touch_calibration(munki *p) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code ev = MUNKI_OK;
+ char cal_name[100]; /* Name */
+ char **cal_paths = NULL;
+ int no_paths = 0;
+ int rv;
+
+ sprintf(cal_name, "ArgyllCMS/.mk_%s.cal" SSEPS "color/.mk_%s.cal", m->serno, m->serno);
+ if ((no_paths = xdg_bds(NULL, &cal_paths, xdg_cache, xdg_read, xdg_user, cal_name)) < 1)
+ return MUNKI_INT_CAL_TOUCH;
+
+ a1logd(p->log,2,"munki_touch_calibration touching file '%s'\n",cal_paths[0]);
+
+ if ((rv = sys_utime(cal_paths[0], NULL)) != 0) {
+ a1logd(p->log,2,"munki_touch_calibration failed with %d\n",rv);
+ xdg_free(cal_paths, no_paths);
+ return MUNKI_INT_CAL_TOUCH;
+ }
+ xdg_free(cal_paths, no_paths);
+
+ return ev;
+}
+
+#endif /* ENABLE_NONVCAL */
+
+
+/* ============================================================ */
+/* Intermediate routines - composite commands/processing */
+
+/* Take a dark reference measurement - part 1 */
+munki_code munki_dark_measure_1(
+ munki *p,
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf, /* USB reading buffer to use */
+ unsigned int bsize /* Size of buffer */
+) {
+ munki_code ev = MUNKI_OK;
+
+ if (nummeas <= 0)
+ return MUNKI_INT_ZEROMEASURES;
+
+ if ((ev = munki_trigger_one_measure(p, nummeas, inttime, gainmode, 1, 1)) != MUNKI_OK)
+ return ev;
+
+ if ((ev = munki_readmeasurement(p, nummeas, 0, buf, bsize, NULL, 1, 1)) != MUNKI_OK)
+ return ev;
+
+ return ev;
+}
+
+/* Take a dark reference measurement - part 2 */
+munki_code munki_dark_measure_2(
+ munki *p,
+ double *sens, /* Return array [-1 nraw] of sens values */
+ int nummeas, /* Number of readings to take */
+ double inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf, /* raw USB reading buffer to process */
+ unsigned int bsize /* Buffer size to process */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ double **multimes; /* Multiple measurement results */
+ double darkthresh; /* Dark threshold */
+ double sensavg; /* Overall average of sensor readings */
+ int rv;
+
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1);
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* floating point sensor readings. Check for saturation */
+ if ((rv = munki_sens_to_raw(p, multimes, NULL, buf, 0, nummeas, m->satlimit, &darkthresh))
+ != MUNKI_OK) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ return rv;
+ }
+
+ /* Average a set of measurements into one. */
+ /* Return nz if the readings are not consistent */
+ /* Return the overall average. */
+ rv = munki_average_multimeas(p, sens, multimes, nummeas, &sensavg, darkthresh);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+
+#ifdef PLOT_DEBUG
+ printf("Average absolute sensor readings, average = %f, darkthresh %f\n",sensavg,darkthresh);
+ plot_raw(sens);
+#endif
+
+ if (rv) {
+ a1logd(p->log,3,"munki_dark_measure_2: readings are inconsistent\n");
+ return MUNKI_RD_DARKREADINCONS;
+ }
+
+ if (sensavg > (2.0 * darkthresh)) {
+ a1logd(p->log,3,"munki_dark_measure_2: Average %f is > 2 * darkthresh %f\n",sensavg,darkthresh);
+ return MUNKI_RD_DARKNOTVALID;
+ }
+ return ev;
+}
+
+#ifdef DUMP_DARKM
+int ddumpdarkm = 0;
+#endif
+
+/* Take a dark reference measurement (combined parts 1 & 2) */
+munki_code munki_dark_measure(
+ munki *p,
+ double *raw, /* Return array [-1 nraw] of raw values */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code ev = MUNKI_OK;
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+
+ a1logd(p->log,3, "munki_dark_measure with inttime %f\n",*inttime);
+ bsize = m->nsen * 2 * nummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"munki_dark_measure malloc %d bytes failed (8)\n",bsize);
+ return MUNKI_INT_MALLOC;
+ }
+
+ if ((ev = munki_dark_measure_1(p, nummeas, inttime, gainmode, buf, bsize)) != MUNKI_OK) {
+ free(buf);
+ return ev;
+ }
+
+ if ((ev = munki_dark_measure_2(p, raw, nummeas, *inttime, gainmode, buf, bsize))
+ != MUNKI_OK) {
+ free(buf);
+ return ev;
+ }
+ free(buf);
+
+#ifdef DUMP_DARKM
+ /* Dump raw dark readings to a file "mkddump.txt" */
+ if (ddumpdarkm) {
+ int j;
+ FILE *fp;
+
+ if ((fp = fopen("mkddump.txt", "a")) == NULL)
+ a1logw(p->log,"Unable to open debug file mkddump.txt\n");
+ else {
+ fprintf(fp, "\nDark measure: nummeas %d, inttime %f, gainmode %d, darkcells %f\n",nummeas,*inttime,gainmode, raw[-1]);
+ fprintf(fp,"\t\t\t{ ");
+ for (j = 0; j < (m->nraw-1); j++)
+ fprintf(fp, "%f, ",raw[j]);
+ fprintf(fp, "%f },\n",raw[j]);
+ fclose(fp);
+ }
+ }
+#endif
+ return ev;
+}
+
+/* Heat the LED up for given number of seconds by taking a reading */
+munki_code munki_heatLED(
+ munki *p,
+ double htime /* Heat up time */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ double inttime = m->cal_int_time; /* Integration time to use/used */
+ int nummeas;
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ int rv;
+
+ a1logd(p->log,3,"munki_heatLED called \n");
+
+ nummeas = munki_comp_ru_nummeas(p, htime, inttime);
+
+ if (nummeas <= 0)
+ return MUNKI_OK;
+
+ /* Allocate temporaries */
+ bsize = m->nsen * 2 * nummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"munki_heatLED malloc %d bytes failed (10)\n",bsize);
+ return MUNKI_INT_MALLOC;
+ }
+
+ a1logd(p->log,3,"Triggering measurement cycle, nummeas %d, inttime %f\n", nummeas, inttime);
+
+ if ((rv = munki_trigger_one_measure(p, nummeas, &inttime, 0, 1, 0))
+ != MUNKI_OK) {
+ free(buf);
+ return rv;
+ }
+
+ a1logd(p->log,3,"Gathering readings\n");
+
+ rv = munki_readmeasurement(p, nummeas, 0, buf, bsize, NULL, 1, 0);
+
+ free(buf);
+
+ return rv;
+}
+
+
+/* Take a reflective or emissive white reference sens measurement, */
+/* subtracts black and processes into wavelenths. */
+/* (absraw is usually ->white_data) */
+munki_code munki_whitemeasure(
+ munki *p,
+ double *absraw, /* Return array [-1 nraw] of absraw values (may be NULL) */
+ double *optscale, /* Return scale for gain/int time to make optimal (may be NULL) */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale /* Ratio of optimal sensor value to aim for */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ int ninvmeas = 0; /* Number of invalid measurements */
+ double **multimes; /* Multiple measurement results */
+ double sensavg; /* Overall average of sensor readings */
+ double darkthresh; /* Dark threshold */
+ double trackmax[3]; /* Track optimum target & darkthresh */
+ double maxval; /* Maximum multimeas value */
+ int rv;
+
+ a1logd(p->log,3,"munki_whitemeasure called \n");
+
+ if (s->reflective) {
+ /* Compute invalid samples to allow for LED warmup */
+ ninvmeas = munki_comp_ru_nummeas(p, m->refinvalidsampt, *inttime);
+ }
+
+ if (nummeas <= 0)
+ return MUNKI_INT_ZEROMEASURES;
+
+ /* Allocate temporaries */
+ bsize = m->nsen * 2 * (ninvmeas + nummeas);
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"munki_whitemeasure malloc %d bytes failed (10)\n",bsize);
+ return MUNKI_INT_MALLOC;
+ }
+
+ a1logd(p->log,3,"Triggering measurement cycle, ninvmeas %d, nummeas %d, inttime %f, gainmode %d\n",
+ ninvmeas, nummeas, *inttime, gainmode);
+
+ if ((ev = munki_trigger_one_measure(p, ninvmeas + nummeas, inttime, gainmode, 1, 0))
+ != MUNKI_OK) {
+ free(buf);
+ return ev;
+ }
+
+ a1logd(p->log,3,"Gathering readings\n");
+
+ if ((ev = munki_readmeasurement(p, ninvmeas + nummeas, 0, buf, bsize, NULL, 1, 0))
+ != MUNKI_OK) {
+ free(buf);
+ return ev;
+ }
+
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1);
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* floating point sensor readings. Check for saturation */
+ if ((rv = munki_sens_to_raw(p, multimes, NULL, buf, ninvmeas, nummeas, m->satlimit,
+ &darkthresh)) != MUNKI_OK) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ return rv;
+ }
+
+#ifdef PLOT_DEBUG
+ printf("Dark data:\n");
+ plot_raw(s->dark_data);
+#endif
+
+ trackmax[0] = darkthresh; /* Track the dark threshold value */
+ trackmax[1] = m->optsval; /* Track the optimal sensor target value */
+ trackmax[2] = m->satlimit; /* For debugging */
+
+ /* Subtract the black from sensor values and convert to */
+ /* absolute (integration & gain scaled), zero offset based, */
+ /* linearized sensor values. */
+ /* Return the highest individual element. */
+ munki_sub_raw_to_absraw(p, nummeas, *inttime, gainmode, multimes, s->dark_data,
+ trackmax, 3, &maxval);
+ darkthresh = trackmax[0];
+ free(buf);
+
+ if (absraw != NULL) {
+ /* Average a set of measurements into one. */
+ /* Return nz if the readings are not consistent */
+ /* Return the overall average. */
+ rv = munki_average_multimeas(p, absraw, multimes, nummeas, &sensavg, darkthresh);
+
+#ifndef IGNORE_WHITE_INCONS
+ if (rv) {
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ return MUNKI_RD_WHITEREADINCONS;
+ }
+#endif /* IGNORE_WHITE_INCONS */
+
+ a1logd(p->log,3,"Average absolute sensor readings, avg %f, max %f, darkth %f satth %f\n",
+ sensavg,maxval,darkthresh,trackmax[2]);
+#ifdef PLOT_DEBUG
+ plot_raw(absraw);
+#endif
+ }
+
+ if (optscale != NULL) {
+ double opttarget; /* Optimal reading scale target value */
+
+ opttarget = targoscale * trackmax[1];
+ if (maxval < 0.01) /* Could go -ve */
+ maxval = 0.01;
+ *optscale = opttarget/maxval;
+
+ a1logd(p->log,3,"Targscale %f, maxval %f, optimal target = %f, amount to scale = %f\n",
+ targoscale, maxval, opttarget, *optscale);
+ }
+
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1); /* Free after using *pmax */
+
+ return ev;
+}
+
+/* Given an absraw white reference measurement, */
+/* compute the wavelength equivalents. */
+/* (absraw is usually ->white_data) */
+/* (abswav1 is usually ->cal_factor1) */
+/* (abswav2 is usually ->cal_factor2) */
+munki_code munki_compute_wav_whitemeas(
+ munki *p,
+ double *abswav1, /* Return array [nwav1] of abswav values (may be NULL) */
+ double *abswav2, /* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
+ double *absraw /* Given array [-1 nraw] of absraw values */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+
+ /* Convert an absraw array from raw wavelengths to output wavelenths */
+ if (abswav1 != NULL) {
+ munki_absraw_to_abswav1(p, 1, &abswav1, &absraw);
+
+#ifdef PLOT_DEBUG
+ printf("Converted to wavelengths std res:\n");
+ plot_wav1(m, abswav1);
+#endif
+ }
+
+#ifdef HIGH_RES
+ if (abswav2 != NULL && m->hr_inited == 2) {
+ munki_absraw_to_abswav2(p, 1, &abswav2, &absraw);
+
+#ifdef PLOT_DEBUG
+ printf("Converted to wavelengths high res:\n");
+ plot_wav2(m, abswav2);
+#endif
+ }
+#endif /* HIGH_RES */
+
+ return MUNKI_OK;
+}
+
+/* Take a reflective white reference measurement, */
+/* subtracts black and decompose into base + LED temperature components */
+munki_code munki_ledtemp_whitemeasure(
+ munki *p,
+ double *white, /* Return [-1 nraw] of temperature compensated white reference */
+ double **iwhite, /* Return array [-1 nraw][2] of absraw base and scale values */
+ double *reftemp, /* Return a reference temperature to normalize to */
+ int nummeas, /* Number of readings to take */
+ double inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ int ninvmeas = 0; /* Number of invalid measurements */
+ double **multimes; /* Multiple measurement results */
+ double *ledtemp; /* LED temperature for each measurement */
+ double darkthresh; /* Dark threshold */
+ int rv;
+
+ a1logd(p->log,3,"munki_ledtemp_whitemeasure called \n");
+
+ /* Compute invalid samples to allow for LED warmup */
+ ninvmeas = munki_comp_ru_nummeas(p, m->refinvalidsampt, inttime);
+
+ if (nummeas <= 0) {
+ return MUNKI_INT_ZEROMEASURES;
+ }
+
+ /* Allocate temporaries */
+ bsize = m->nsen * 2 * (ninvmeas + nummeas);
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"munki_whitemeasure malloc %d bytes failed (10)\n",bsize);
+ return MUNKI_INT_MALLOC;
+ }
+
+ a1logd(p->log,3,"Triggering measurement cycle, ninvmeas %d, nummeas %d, inttime %f, gainmode %d\n",
+ ninvmeas, nummeas, inttime, gainmode);
+
+ if ((ev = munki_trigger_one_measure(p, ninvmeas + nummeas, &inttime, gainmode, 1, 0))
+ != MUNKI_OK) {
+ free(buf);
+ return ev;
+ }
+
+ a1logd(p->log,3,"Gathering readings\n");
+
+ if ((ev = munki_readmeasurement(p, ninvmeas + nummeas, 0, buf, bsize, NULL, 1, 0))
+ != MUNKI_OK) {
+ free(buf);
+ return ev;
+ }
+
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1);
+ ledtemp = dvector(0, nummeas-1);
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* floating point sensor readings. Check for saturation */
+ if ((ev = munki_sens_to_raw(p, multimes, ledtemp, buf, ninvmeas, nummeas, m->satlimit,
+ &darkthresh)) != MUNKI_OK) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ return ev;
+ }
+
+ /* Make the reference temperature nominal */
+ *reftemp = 0.5 * (ledtemp[0] + ledtemp[nummeas-1]);
+
+#ifdef PLOT_DEBUG
+ printf("Dark data:\n");
+ plot_raw(s->dark_data);
+#endif
+
+ /* Subtract the black from sensor values and convert to */
+ /* absolute (integration & gain scaled), zero offset based, */
+ /* linearized sensor values. */
+ munki_sub_raw_to_absraw(p, nummeas, inttime, gainmode, multimes, s->dark_data,
+ &darkthresh, 1, NULL);
+
+ free(buf);
+
+ /* For each raw wavelength, compute a linear regression */
+ {
+ int i, w;
+ double tt, ss, sx, sy, sxdss, stt, b;
+
+ ss = (double)nummeas;
+ for (sx = 0.0, i = 0; i < nummeas; i++)
+ sx += ledtemp[i];
+ sxdss = sx/ss;
+
+ for (w = -1; w < m->nraw; w++) {
+ for (sy = 0.0, i = 0; i < nummeas; i++)
+ sy += multimes[i][w];
+
+ for (stt = b = 0.0, i = 0; i < nummeas; i++) {
+ tt = ledtemp[i] - sxdss;
+ stt += tt * tt;
+ b += tt * multimes[i][w];
+ }
+ b /= stt;
+
+ iwhite[0][w] = (sy - sx * b)/ss;
+ iwhite[1][w] = b;
+ }
+ }
+#ifdef DEBUG
+ { /* Verify the linear regression */
+ int i, w;
+ double x, terr = 0.0, errc = 0.0;
+
+ for (w = -1; w < m->nraw; w++) {
+ for (i = 0; i < nummeas; i++) {
+ x = iwhite[0][w] + ledtemp[i] * iwhite[1][w];
+ terr += fabs(x - multimes[i][w]);
+ errc++;
+ }
+ }
+ terr /= errc;
+ printf("Linear regression average error = %f\n",terr);
+ }
+#endif
+
+#ifdef PLOT_TEMPCOMP
+ /* Plot the raw spectra and model, 3 at a time */
+ {
+ int i, j, k;
+ double *indx;
+ double **mod;
+ indx = dvectorz(0, nummeas-1);
+ mod = dmatrix(0, 5, 0, nummeas-1);
+ for (i = 0; i < nummeas; i++)
+ indx[i] = 3.0 * i/(nummeas-1.0);
+
+ for (j = 0; (j+2) < (m->nraw-1); j += 3) {
+ for (i = 0; i < nummeas; i++) {
+ for (k = j; k < (j + 3); k++) {
+ mod[k-j][i] = iwhite[0][k] + ledtemp[i] * iwhite[1][k];
+ }
+ for (k = j; k < (j + 3); k++) {
+ mod[k-j+3][i] = multimes[i][k];
+ }
+ }
+
+ printf("Bands %d - %d\n",j, j+2);
+ do_plot6(indx, mod[0], mod[1], mod[2], mod[3], mod[4], mod[5], nummeas);
+ }
+ free_dvector(indx, 0, nummeas-1);
+ free_dmatrix(mod, 0, 5, 0, nummeas-1);
+ }
+#endif
+
+ a1logd(p->log,3,"Computed linear regression\n");
+
+#ifdef ENABLE_LEDTEMPC
+ /* Compute a temerature compensated set of white readings */
+ if ((ev = munki_ledtemp_comp(p, multimes, ledtemp, nummeas, *reftemp, iwhite)) != MUNKI_OK) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ return ev;
+ }
+#endif /* ENABLE_LEDTEMPC */
+
+ /* Average a set of measurements into one. */
+ if ((rv = munki_average_multimeas(p, white, multimes, nummeas, NULL, darkthresh)) != 0) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ a1logd(p->log,3,"munki_ledtemp_whitemeasure: readings are inconsistent\n");
+ return MUNKI_RD_DARKREADINCONS;
+ }
+
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+
+ return ev;
+}
+
+/* Given the ledtemp base and scale values, */
+/* return an absraw reflective white reference for the */
+/* given temperature */
+munki_code munki_ledtemp_white(
+ munki *p,
+ double *absraw, /* Return array [-1 nraw] of absraw base and scale values */
+ double **iwhite, /* ledtemp base and scale */
+ double ledtemp /* LED temperature value */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ int w;
+
+ for (w = -1; w < m->nraw; w++)
+ absraw[w] = iwhite[0][w] + ledtemp * iwhite[1][w];
+
+ return MUNKI_OK;
+}
+
+/* Given a set of absraw sensor readings and the corresponding temperature, */
+/* compensate the readings to be at the nominated temperature. */
+munki_code munki_ledtemp_comp(
+ munki *p,
+ double **absraw, /* [nummeas][raw] measurements to compensate */
+ double *ledtemp, /* LED temperature for each measurement */
+ int nummeas, /* Number of measurements */
+ double reftemp, /* LED reference temperature to compensate to */
+ double **iwhite /* ledtemp base and scale information */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ int i, w;
+
+ for (i = 0; i < nummeas; i++) {
+ for (w = 0; w < m->nraw; w++) { /* Don't try and compensate shielded values */
+ double targ, attemp;
+ targ = iwhite[0][w] + reftemp * iwhite[1][w];
+ attemp = iwhite[0][w] + ledtemp[i] * iwhite[1][w];
+
+ absraw[i][w] *= targ/attemp;
+ }
+ }
+ return MUNKI_OK;
+}
+
+/* Take a measurement reading using the current mode, part 1 */
+/* Converts to completely processed output readings. */
+munki_code munki_read_patches_1(
+ munki *p,
+ int ninvmeas, /* Number of extra invalid measurements at start */
+ int minnummeas, /* Minimum number of measurements to take */
+ int maxnummeas, /* Maximum number of measurements to allow for */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ int *nmeasuered, /* Number actually measured (excluding ninvmeas) */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+
+ if ((ninvmeas + minnummeas) <= 0)
+ return MUNKI_INT_ZEROMEASURES;
+
+ if ((minnummeas + ninvmeas) > maxnummeas)
+ maxnummeas = (minnummeas - ninvmeas);
+
+ a1logd(p->log,3,"Triggering & gathering cycle, ninvmeas %d, minnummeas %d, inttime %f, gainmode %d\n",
+ ninvmeas, minnummeas, *inttime, gainmode);
+
+ if ((ev = munki_trigger_one_measure(p, ninvmeas + minnummeas, inttime, gainmode, 0, 0))
+ != MUNKI_OK) {
+ return ev;
+ }
+
+ if ((ev = munki_readmeasurement(p, ninvmeas + minnummeas, m->c_measmodeflags & MUNKI_MMF_SCAN,
+ buf, bsize, nmeasuered, 0, 0)) != MUNKI_OK) {
+ return ev;
+ }
+
+ if (nmeasuered != NULL)
+ *nmeasuered -= ninvmeas; /* Correct for invalid number */
+
+ return ev;
+}
+
+/* Take a measurement reading using the current mode, part 2 */
+/* Converts to completely processed output readings. */
+munki_code munki_read_patches_2(
+ munki *p,
+ double *duration, /* Return flash duration in seconds */
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of patches to return */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode useed, 0 = normal, 1 = high */
+ int ninvmeas, /* Number of extra invalid measurements at start */
+ int nummeas, /* Number of actual measurements */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ double **multimes; /* Multiple measurement results [maxnummeas|nummeas][-1 nraw]*/
+ double **absraw; /* Linearsised absolute sensor raw values [numpatches][-1 nraw]*/
+ double *ledtemp; /* LED temperature values */
+ double darkthresh; /* Dark threshold (for consistency checking) */
+ int rv = 0;
+
+ if (duration != NULL)
+ *duration = 0.0; /* default value */
+
+ /* Allocate temporaries */
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1);
+ ledtemp = dvector(0, nummeas-1);
+ absraw = dmatrix(0, numpatches-1, -1, m->nraw-1);
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* floating point sensor readings. Check for saturation */
+ if ((rv = munki_sens_to_raw(p, multimes, ledtemp, buf, ninvmeas, nummeas,
+ m->satlimit, &darkthresh)) != MUNKI_OK) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ return rv;
+ }
+
+ /* Subtract the black from sensor values and convert to */
+ /* absolute (integration & gain scaled), zero offset based, */
+ /* linearized sensor values. */
+ munki_sub_raw_to_absraw(p, nummeas, inttime, gainmode, multimes, s->dark_data,
+ &darkthresh, 1, NULL);
+
+#ifdef PLOT_TEMPCOMP
+ /* Plot the raw spectra, 6 at a time */
+ if (s->reflective) {
+ int i, j, k;
+ double *indx;
+ double **mod;
+ indx = dvectorz(0, nummeas-1);
+ mod = dmatrix(0, 5, 0, nummeas-1);
+ for (i = 0; i < nummeas; i++)
+ indx[i] = (double)i;
+
+// for (j = 0; (j+5) < m->nraw; j += 6) {
+ for (j = 50; (j+5) < 56; j += 6) {
+ for (i = 0; i < nummeas; i++) {
+ for (k = j; k < (j + 6); k++) {
+ mod[k-j][i] = multimes[i][k];
+ }
+ }
+
+ printf("Before temp comp, bands %d - %d\n",j, j+5);
+ do_plot6(indx, mod[0], mod[1], mod[2], mod[3], mod[4], mod[5], nummeas);
+ }
+ free_dvector(indx, 0, nummeas-1);
+ free_dmatrix(mod, 0, 5, 0, nummeas-1);
+ }
+#endif
+#ifdef DUMP_SCANV
+ /* Dump raw scan readings to a file "mkdump.txt" */
+ {
+ int i, j;
+ FILE *fp;
+
+ if ((fp = fopen("mkdump.txt", "w")) == NULL)
+ a1logw(p->log,"Unable to open debug file mkdump.txt\n");
+ else {
+ for (i = 0; i < nummeas; i++) {
+ fprintf(fp, "%d ",i);
+ for (j = 0; j < m->nraw; j++) {
+ fprintf(fp, "%f ",multimes[i][j]);
+ }
+ fprintf(fp,"\n");
+ }
+ fclose(fp);
+ }
+ }
+#endif
+
+#ifdef ENABLE_LEDTEMPC
+ /* Do LED temperature compensation of absraw values */
+ if (s->reflective) {
+ if ((ev = munki_ledtemp_comp(p, multimes, ledtemp, nummeas, s->reftemp, s->iwhite_data))
+ != MUNKI_OK) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ a1logd(p->log,3,"munki_read_patches_2 ledtemp comp failed\n");
+ return ev;
+ }
+#ifdef PLOT_TEMPCOMP
+ /* Plot the raw spectra, 6 at a time */
+ {
+ int i, j, k;
+ double *indx;
+ double **mod;
+ indx = dvectorz(0, nummeas-1);
+ mod = dmatrix(0, 5, 0, nummeas-1);
+ for (i = 0; i < nummeas; i++)
+ indx[i] = (double)i;
+
+// for (j = 0; (j+5) < m->nraw; j += 6) {
+ for (j = 50; (j+5) < 56; j += 6) {
+ for (i = 0; i < nummeas; i++) {
+ for (k = j; k < (j + 6); k++) {
+ mod[k-j][i] = multimes[i][k];
+ }
+ }
+
+ printf("After temp comp, bands %d - %d\n",j, j+5);
+ do_plot6(indx, mod[0], mod[1], mod[2], mod[3], mod[4], mod[5], nummeas);
+ }
+ free_dvector(indx, 0, nummeas-1);
+ free_dmatrix(mod, 0, 5, 0, nummeas-1);
+ }
+#endif
+ }
+#endif /* ENABLE_LEDTEMPC */
+
+
+ if (!s->scan) {
+ if (numpatches != 1) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ a1logd(p->log,3,"munki_read_patches_2 spot read failed because numpatches != 1\n");
+ return MUNKI_INT_WRONGPATCHES;
+ }
+
+ /* Average a set of measurements into one. */
+ /* Return zero if readings are consistent. */
+ /* Return nz if the readings are not consistent */
+ /* Return the overall average. */
+ rv = munki_average_multimeas(p, absraw[0], multimes, nummeas, NULL, darkthresh);
+ } else {
+
+ if (s->flash) {
+
+ if (numpatches != 1) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ a1logd(p->log,3,"munki_read_patches_2 spot read failed because numpatches != 1\n");
+ return MUNKI_INT_WRONGPATCHES;
+ }
+ if ((ev = munki_extract_patches_flash(p, &rv, duration, absraw[0], multimes,
+ nummeas, inttime)) != MUNKI_OK) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ a1logd(p->log,3,"munki_read_patches_2 spot read failed at munki_extract_patches_flash\n");
+ return ev;
+ }
+
+ } else {
+ a1logd(p->log,3,"Number of patches to be measured = %d\n",nummeas);
+
+ /* Recognise the required number of ref/trans patch locations, */
+ /* and average the measurements within each patch. */
+ if ((ev = munki_extract_patches_multimeas(p, &rv, absraw, numpatches, multimes,
+ nummeas, inttime)) != MUNKI_OK) {
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ a1logd(p->log,3,"munki_read_patches_2 spot read failed at munki_extract_patches_multimeas\n");
+ return ev;
+ }
+ }
+ }
+ free_dvector(ledtemp, 0, nummeas-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+
+ if (rv) {
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ a1logd(p->log,3,"munki_read_patches_2 spot read failed with inconsistent readings\n");
+ return MUNKI_RD_READINCONS;
+ }
+
+ /* Convert an absraw array from raw wavelengths to output wavelenths */
+ munki_absraw_to_abswav(p, numpatches, specrd, absraw);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+
+#ifdef APPEND_MEAN_EMMIS_VAL
+ /* Append averaged emission reading to file "mkdump.txt" */
+ {
+ int i, j;
+ FILE *fp;
+
+ /* Create wavelegth label */
+ if ((fp = fopen("mkdump.txt", "r")) == NULL) {
+ if ((fp = fopen("mkdump.txt", "w")) == NULL)
+ a1logw(p->log,"Unable to reate debug file mkdump.txt\n");
+ else {
+ for (j = 0; j < m->nwav; j++)
+ fprintf(fp,"%f ",XSPECT_WL(m->wl_short, m->wl_long, m->nwav, j));
+ fprintf(fp,"\n");
+ fclose(fp);
+ }
+ }
+ if ((fp = fopen("mkdump.txt", "a")) == NULL)
+ a1logw(p->log,"Unable to open debug file mkdump.txt\n");
+ else {
+ for (j = 0; j < m->nwav; j++)
+ fprintf(fp, "%f ",specrd[0][j] * m->emis_coef[j]);
+ fprintf(fp,"\n");
+ fclose(fp);
+ }
+ }
+#endif
+
+#ifdef PLOT_DEBUG
+ printf("Converted to wavelengths:\n");
+ plot_wav(m, specrd[0]);
+#endif
+
+ /* Scale to the calibrated output values */
+ munki_scale_specrd(p, specrd, numpatches, specrd);
+
+#ifdef PLOT_DEBUG
+ printf("Calibrated measuerment spectra:\n");
+ plot_wav(m, specrd[0]);
+#endif
+
+ return ev;
+}
+
+/* Take a measurement reading using the current mode, part 2a */
+/* Converts to completely processed output readings, */
+/* but don't average together or extract patches or flash. */
+/* (! Note that we aren't currently detecting saturation here!) */
+munki_code munki_read_patches_2a(
+ munki *p,
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of patches measured and to return */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode useed, 0 = normal, 1 = high */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ double **absraw; /* Linearsised absolute sensor raw values [numpatches][-1 nraw]*/
+ double *ledtemp; /* LED temperature values */
+ double satthresh; /* Saturation threshold */
+ double darkthresh; /* Dark threshold for consistency scaling limit */
+
+ /* Allocate temporaries */
+ absraw = dmatrix(0, numpatches-1, -1, m->nraw-1);
+ ledtemp = dvector(0, numpatches-1);
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* floating point sensor readings. Check for saturation */
+ if ((ev = munki_sens_to_raw(p, absraw, ledtemp, buf, 0, numpatches,
+ m->satlimit, &darkthresh)) != MUNKI_OK) {
+ free_dvector(ledtemp, 0, numpatches-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+ return ev;
+ }
+
+ /* Subtract the black from sensor values and convert to */
+ /* absolute (integration & gain scaled), zero offset based, */
+ /* linearized sensor values. */
+ munki_sub_raw_to_absraw(p, numpatches, inttime, gainmode, absraw, s->dark_data,
+ &darkthresh, 1, NULL);
+
+ a1logd(p->log,3,"Number of patches measured = %d\n",numpatches);
+
+ /* Convert an absraw array from raw wavelengths to output wavelenths */
+ munki_absraw_to_abswav(p, numpatches, specrd, absraw);
+
+ free_dvector(ledtemp, 0, numpatches-1);
+ free_dmatrix(absraw, 0, numpatches-1, -1, m->nraw-1);
+
+#ifdef PLOT_DEBUG
+ printf("Converted to wavelengths:\n");
+ plot_wav(m, specrd[0]);
+#endif
+
+ /* Scale to the calibrated output values */
+ munki_scale_specrd(p, specrd, numpatches, specrd);
+
+#ifdef PLOT_DEBUG
+ printf("Calibrated measuerment spectra:\n");
+ plot_wav(m, specrd[0]);
+#endif
+
+ return ev;
+}
+
+/* Take a measurement reading using the current mode (combined parts 1 & 2a) */
+/* Converts to completely processed output readings, without averaging or extracting */
+/* sample patches. */
+munki_code munki_read_patches_all(
+ munki *p,
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of sample to measure */
+ double *inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ int rv = 0;
+
+ bsize = m->nsen * 2 * numpatches;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"munki_read_patches malloc %d bytes failed (11)\n",bsize);
+ return MUNKI_INT_MALLOC;
+ }
+
+ /* Trigger measure and gather raw readings */
+ if ((ev = munki_read_patches_1(p, 0, numpatches, numpatches, inttime, gainmode,
+ NULL, buf, bsize)) != MUNKI_OK) {
+ free(buf);
+ return ev;
+ }
+
+ /* Process the raw readings without averaging or extraction */
+ if ((ev = munki_read_patches_2a(p, specrd, numpatches, *inttime, gainmode,
+ buf, bsize)) != MUNKI_OK) {
+ free(buf);
+ return ev;
+ }
+ free(buf);
+ return ev;
+}
+
+/* Take a trial emission measurement reading using the current mode. */
+/* Used to determine if sensor is saturated, or not optimal */
+/* in adaptive emission mode. */
+munki_code munki_trialmeasure(
+ munki *p,
+ int *saturated, /* Return nz if sensor is saturated */
+ double *optscale, /* Return scale for gain/int time to make optimal (may be NULL) */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale /* Ratio of optimal sensor value to aim for */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ unsigned char *buf; /* Raw USB reading buffer */
+ unsigned int bsize;
+ double **multimes; /* Multiple measurement results */
+ double *absraw; /* Linearsised absolute sensor raw values */
+ int nmeasuered; /* Number actually measured */
+ double sensavg; /* Overall average of sensor readings */
+ double darkthresh; /* Dark threshold */
+ double trackmax[2]; /* Track optimum target */
+ double maxval; /* Maximum multimeas value */
+ int rv;
+
+ if (s->reflective) {
+ a1logw(p->log, "munki_trialmeasure: Assert - not meant to be used for reflective read!\n");
+ return MUNKI_INT_ASSERT;
+ }
+
+ if (nummeas <= 0)
+ return MUNKI_INT_ZEROMEASURES;
+
+ /* Allocate up front to avoid delay between trigger and read */
+ bsize = m->nsen * 2 * nummeas;
+ if ((buf = (unsigned char *)malloc(sizeof(unsigned char) * bsize)) == NULL) {
+ a1logd(p->log,1,"munki_trialmeasure malloc %d bytes failed (12)\n",bsize);
+ return MUNKI_INT_MALLOC;
+ }
+ multimes = dmatrix(0, nummeas-1, -1, m->nraw-1);
+ absraw = dvector(-1, m->nraw-1);
+
+ a1logd(p->log,3,"Triggering measurement cycle, nummeas %d, inttime %f, gainmode %d\n",
+ nummeas, *inttime, gainmode);
+
+ if ((ev = munki_trigger_one_measure(p, nummeas, inttime, gainmode, 1, 0)) != MUNKI_OK) {
+ free_dvector(absraw, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+ a1logd(p->log,3,"Gathering readings\n");
+ if ((ev = munki_readmeasurement(p, nummeas, m->c_measmodeflags & MUNKI_MMF_SCAN,
+ buf, bsize, &nmeasuered, 1, 0)) != MUNKI_OK) {
+ free_dvector(absraw, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ free(buf);
+ return ev;
+ }
+
+ if (saturated != NULL) /* Initialize return flag */
+ *saturated = 0;
+
+ /* Take a buffer full of raw readings, and convert them to */
+ /* floating point sensor readings. Check for saturation */
+ if ((rv = munki_sens_to_raw(p, multimes, NULL, buf, 0, nmeasuered, m->satlimit,
+ &darkthresh)) != MUNKI_OK) {
+ if (rv != MUNKI_RD_SENSORSATURATED) {
+ free(buf);
+ return rv;
+ }
+ if (saturated != NULL)
+ *saturated = 1;
+ }
+ free(buf);
+
+ /* Comute dark subtraction for this trial's parameters */
+ if ((ev = munki_interp_dark(p, s->dark_data, *inttime, gainmode)) != MUNKI_OK) {
+ free_dvector(absraw, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1);
+ a1logd(p->log,3,"munki_imp_measure interplate dark ref failed\n");
+ return ev;
+ }
+
+ trackmax[0] = darkthresh; /* Track dark threshold */
+ trackmax[1] = m->optsval; /* Track the optimal sensor target value */
+
+ /* Subtract the black from sensor values and convert to */
+ /* absolute (integration & gain scaled), zero offset based, */
+ /* linearized sensor values. */
+ /* Return the highest individual element. */
+ munki_sub_raw_to_absraw(p, nmeasuered, *inttime, gainmode, multimes, s->dark_data,
+ trackmax, 2, &maxval);
+ darkthresh = trackmax[0];
+
+ /* Average a set of measurements into one. */
+ /* Return nz if the readings are not consistent */
+ /* Return the overall average. */
+ rv = munki_average_multimeas(p, absraw, multimes, nmeasuered, &sensavg, darkthresh);
+
+ /* Ignore iconsistent readings ?? */
+
+#ifdef PLOT_DEBUG
+ printf("Average absolute sensor readings, average = %f, max %f\n",sensavg,maxval);
+ plot_raw(absraw);
+#endif
+
+ if (optscale != NULL) {
+ double opttarget; /* Optimal sensor target */
+
+ opttarget = targoscale * trackmax[1];
+ if (maxval < 0.01) /* Could go -ve */
+ maxval = 0.01;
+ *optscale = opttarget/ maxval;
+ a1logd(p->log,4,"Targscale %f, maxval %f, optimal target = %f, amount to scale = %f\n",
+ targoscale, maxval, opttarget, *optscale);
+ }
+
+ free_dvector(absraw, -1, m->nraw-1);
+ free_dmatrix(multimes, 0, nummeas-1, -1, m->nraw-1); /* Free after using *pmax */
+
+ return ev;
+}
+
+/* Trigger a single measurement cycle. This could be a dark calibration, */
+/* a calibration, or a real measurement. This is used to create the */
+/* higher level "calibrate" and "take reading" functions. */
+/* The setup for the operation is in the current mode state. */
+/* Call munki_readmeasurement() to collect the results */
+munki_code
+munki_trigger_one_measure(
+ munki *p,
+ int nummeas, /* Minimum number of measurements to make */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ int calib_measure, /* flag - nz if this is a calibration measurement */
+ int dark_measure /* flag - nz if this is a dark measurement */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ double dintclocks;
+ int intclocks; /* Number of integration clocks */
+ int measmodeflags; /* Measurement mode command flags */
+ int holdtempduty; /* Hold temperature duty cycle */
+
+ /* Compute integration clocks. Take account of (seeming) dead integration time */
+ dintclocks = floor((*inttime)/m->intclkp + 0.5);
+ intclocks = (int)dintclocks;
+ *inttime = (double)intclocks * m->intclkp; /* Quantized integration time */
+
+ /* Create measurement mode flag byte for this operation */
+ measmodeflags = 0;
+ if (s->scan && !calib_measure)
+ measmodeflags |= MUNKI_MMF_SCAN; /* Never scan on a calibration */
+ if (s->reflective && !dark_measure)
+ measmodeflags |= MUNKI_MMF_LAMP; /* Need lamp if reflective and not dark measure */
+ if (gainmode == 1)
+ measmodeflags |= MUNKI_MMF_HIGHGAIN; /* High gain mode */
+ holdtempduty = m->ledholdtempdc; /* From the EEProm value */
+
+ /* Trigger a measurement */
+ if ((ev = munki_triggermeasure(p, intclocks, nummeas, measmodeflags, holdtempduty)) != MUNKI_OK)
+ return ev;
+
+ m->c_measmodeflags = measmodeflags;
+
+ m->c_inttime = *inttime;
+
+ return ev;
+}
+
+/* ============================================================ */
+/* lower level reading processing and computation */
+
+/* Take a buffer full of raw readings, and convert them to */
+/* directly to floating point raw values. Return MUNKI_RD_SENSORSATURATED if any is saturated */
+/* (No black subtraction or linearization is performed) */
+munki_code munki_sens_to_raw(
+ munki *p,
+ double **raw, /* Array of [nummeas-ninvalid][-1 nraw] value to return */
+ double *ledtemp, /* Optional array [nummeas-ninvalid] LED temperature values to return */
+ unsigned char *buf, /* Raw measurement data must be 274 * nummeas */
+ int ninvalid, /* Number of initial invalid readings to skip */
+ int nummeas, /* Number of readings measured */
+ double satthresh, /* Saturation threshold to trigger error in raw units (if > 0.0) */
+ double *pdarkthresh /* Return a dark threshold value */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ int i, j, k;
+ unsigned char *bp;
+ double maxval = -1e38;
+ double darkthresh = 0.0;
+ double ndarkthresh = 0.0;
+ int sskip = 2 * 6; /* Bytes to skip at start */
+ int eskip = 2 * 3; /* Bytes to skip at end */
+
+ if ((m->nraw * 2 + sskip + eskip) != (m->nsen * 2)) {
+ a1logw(p->log,"NRAW %d and NRAWB %d don't match!\n",m->nraw,m->nsen * 2);
+ return MUNKI_INT_ASSERT;
+ }
+
+ if (ninvalid >= nummeas) {
+ a1logw(p->log,"ninvalid %d is >= nummeas %d!\n",ninvalid,nummeas);
+ return MUNKI_INT_ASSERT;
+ }
+
+ if (ninvalid > 0)
+ a1logd(p->log, 4, "munki_sens_to_raw: Skipping %d invalid readings\n",ninvalid);
+
+ /* Now process the buffer values */
+ for (bp = buf + ninvalid * m->nsen * 2, i = 0; i < nummeas; i++, bp += eskip) {
+
+ /* The first 4 readings are shielded cells, and we use them as an */ /* estimate of the dark reading consistency, as well as for */
+ /* compensating the dark level calibration for any temperature changes. */
+
+ /* raw average of all measurement shielded cell values */
+ for (k = 0; k < 4; k++) {
+ darkthresh += (double)buf2ushort(bp + k * 2);
+ ndarkthresh++;
+ }
+
+ /* raw of shielded cells per reading */
+ raw[i][-1] = 0.0;
+ for (k = 0; k < 4; k++) {
+ raw[i][-1] += (double)buf2ushort(bp + k * 2);
+ }
+ raw[i][-1] /= 4.0;
+
+ /* The LED voltage drop is the last 16 bits in each reading */
+ if (ledtemp != NULL)
+ ledtemp[i] = (double)buf2ushort(bp + (m->nsen * 2) - 2);
+
+ /* The 128 raw spectral values */
+ for (bp += sskip, j = 0; j < m->nraw; j++, bp += 2) {
+ unsigned int rval;
+ double fval;
+
+ rval = buf2ushort(bp);
+ fval = (double)rval;
+ raw[i][j] = fval;
+// printf("~1 i = %d, j = %d, addr % 274 = %d, val = %f\n",i,j,(bp - buf) % 274, fval);
+
+ if (fval > maxval)
+ maxval = fval;
+ }
+ }
+
+ /* Check if any are over saturation threshold */
+ if (satthresh > 0.0) {
+ if (maxval > satthresh) {
+ a1logd(p->log,4,"munki_sens_to_raw: Max sens %f > satthresh %f\n",maxval,satthresh);
+ return MUNKI_RD_SENSORSATURATED;
+ }
+ a1logd(p->log,4,"munki_sens_to_raw: Max sens %f < satthresh %f\n",maxval,satthresh);
+ }
+
+ darkthresh /= ndarkthresh;
+ if (pdarkthresh != NULL)
+ *pdarkthresh = darkthresh;
+ a1logd(p->log,3,"munki_sens_to_raw: Dark thrheshold = %f\n",darkthresh);
+
+ return MUNKI_OK;
+}
+
+/* Subtract the black from raw values and convert to */
+/* absolute (integration & gain scaled), zero offset based, */
+/* linearized raw values. */
+/* Return the highest individual element. */
+void munki_sub_raw_to_absraw(
+ munki *p,
+ int nummeas, /* Return number of readings measured */
+ double inttime, /* Integration time used */
+ int gainmode, /* Gain mode, 0 = normal, 1 = high */
+ double **absraw, /* Source/Desination array [-1 nraw] */
+ double *sub, /* Value to subtract [-1 nraw] */
+ double *trackmax, /* absraw values that should be offset the same as max */
+ int ntrackmax, /* Number of trackmax values */
+ double *maxv /* If not NULL, return the maximum value */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ int npoly; /* Number of linearisation coefficients */
+ double *polys; /* the coeficients */
+ double scale; /* Absolute scale value */
+ double submax = -1e6; /* Subtraction value maximum */
+ double asub[NSEN_MAX];
+ double avgscell, zero;
+ double rawmax, maxval = -1e38;
+ double maxzero = 0.0;
+ int i, j, k;
+
+ if (gainmode) { /* High gain */
+ npoly = m->nlin1; /* Encodes gain too */
+ polys = m->lin1;
+ } else { /* Low gain */
+ npoly = m->nlin0;
+ polys = m->lin0;
+ }
+ scale = 1.0/inttime;
+
+ /* Adjust black to allow for temperature change by using the */
+ /* shielded cell values as a reference. */
+ /* We use a heuristic to compute a zero based scale for adjusting the */
+ /* black. It's not clear why it works best this way, or how */
+ /* dependent on the particular instrument the magic numbers are, */
+ /* but it reduces the black level error from over 10% to about 0.3% */
+
+ /* Locate largest of black */
+ for (j = 0; j < m->nraw; j++) {
+ if (sub[j] > submax)
+ submax = sub[j];
+ }
+
+ /* Average the shielded cell value of all the readings */
+ avgscell = 0.0;
+ for (i = 0; i < nummeas; i++)
+ avgscell += absraw[i][-1];
+ avgscell /= (double)nummeas;
+
+ /* Compute scaling zero */
+ zero = 1.08 * 0.5 * (avgscell + sub[-1]);
+
+ /* make sure that the zero point is above any black value */
+ if (zero < (1.005 * avgscell))
+ zero = 1.005 * avgscell;
+ if (zero < (1.005 * sub[-1]))
+ zero = 1.005 * sub[-1];
+ if (zero < (1.005 * submax))
+ zero = 1.005 * submax;
+
+ a1logd(p->log,4,"Black shielded value = %f, Reading shielded value = %f\n",sub[-1], avgscell);
+
+ /* Compute the adjusted black */
+ for (j = 0; j < m->nraw; j++) {
+#ifdef NEVER
+ /* simple additive correction */
+# pragma message("######### munki Simple shielded cell temperature correction! ########")
+ asub[j] = sub[j] + avgscell - sub[-1];
+#else
+ /* heuristic scaled correction */
+ asub[j] = zero - (zero - sub[j]) * (zero - avgscell)/(zero - sub[-1]);
+#endif
+ }
+
+
+ /* For each measurement */
+ for (i = 0; i < nummeas; i++) {
+ double rval, sval, lval;
+
+ for (j = 0; j < m->nraw; j++) {
+
+ rval = absraw[i][j];
+ sval = rval - asub[j]; /* Make zero based */
+
+#ifdef ENABLE_NONLINCOR
+ /* Linearise */
+ for (lval = polys[npoly-1], k = npoly-2; k >= 0; k--)
+ lval = lval * sval + polys[k];
+#else
+ lval = sval;
+#endif
+ lval *= scale;
+ absraw[i][j] = lval;
+
+ /* Track the maximum value and the black that was subtracted from it */
+ if (lval > maxval) {
+ maxval = lval;
+ rawmax = rval;
+ maxzero = asub[j];
+ if (maxv != NULL)
+ *maxv = absraw[i][j];
+ }
+ }
+ }
+
+ /* Process the "tracked to max" values too */
+ if (ntrackmax > 0 && trackmax != NULL) {
+ for (i = 0; i < ntrackmax; i++) {
+ double rval, fval, lval;
+
+ rval = trackmax[i];
+ fval = rval - maxzero;
+
+#ifdef ENABLE_NONLINCOR
+ /* Linearise */
+ for (lval = polys[npoly-1], k = npoly-2; k >= 0; k--)
+ lval = lval * fval + polys[k];
+#else
+ lval = fval;
+#endif
+ lval *= scale;
+ trackmax[i] = lval;
+// printf("~1 trackmax[%d] = %f, maxzero = %f\n",i,lval,maxzero);
+ }
+ }
+}
+
+/* Average a set of sens or absens measurements into one. */
+/* (Make sure darkthresh is tracked if absens is being averaged!) */
+/* Return zero if readings are consistent and not saturated. */
+/* Return nz if the readings are not consistent */
+/* Return the overall average. */
+int munki_average_multimeas(
+ munki *p,
+ double *avg, /* return average [-1 nraw] */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to average */
+ int nummeas, /* number of readings to be averaged */
+ double *poallavg, /* If not NULL, return overall average of bands and measurements */
+ double darkthresh /* Dark threshold (used for consistency check scaling) */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ int i, j;
+ double oallavg = 0.0;
+ double maxavg = -1e38; /* Track min and max averages of readings */
+ double minavg = 1e38;
+ double norm;
+ int rv = 0;
+
+ a1logd(p->log,3,"munki_average_multimeas %d readings (darkthresh %f)\n",nummeas,darkthresh);
+
+ for (j = -1; j < m->nraw; j++)
+ avg[j] = 0.0;
+
+ /* Now process the buffer values */
+ for (i = 0; i < nummeas; i++) {
+ double measavg = 0.0;
+
+ avg[-1] += multimeas[i][-1]; /* shielded cell value */
+
+ for (j = 0; j < m->nraw; j++) {
+ double val;
+
+ val = multimeas[i][j];
+
+ measavg += val;
+ avg[j] += val;
+ }
+ measavg /= (double)m->nraw;
+ oallavg += measavg;
+ if (measavg < minavg)
+ minavg = measavg;
+ if (measavg > maxavg)
+ maxavg = measavg;
+ }
+
+ for (j = -1; j < m->nraw; j++)
+ avg[j] /= (double)nummeas;
+ oallavg /= (double)nummeas;
+
+ if (poallavg != NULL)
+ *poallavg = oallavg;
+
+ norm = fabs(0.5 * (maxavg+minavg));
+ darkthresh = fabs(darkthresh);
+ if (darkthresh < DARKTHSCAMIN)
+ darkthresh = DARKTHSCAMIN;
+ a1logd(p->log,3,"norm = %f, dark thresh = %f\n",norm,darkthresh);
+ if (norm < (2.0 * darkthresh))
+ norm = 2.0 * darkthresh;
+
+ a1logd(p->log,4,"avg_multi: overall avg = %f, minavg = %f, maxavg = %f, variance %f, THR %f (darkth %f)\n",
+ oallavg,minavg,maxavg,(maxavg - minavg)/norm, PATCH_CONS_THR,darkthresh);
+ if ((maxavg - minavg)/norm > PATCH_CONS_THR) {
+ rv |= 1;
+ }
+ return rv;
+}
+
+/* Minimum number of scan samples in a patch */
+#define MIN_SAMPLES 2
+
+/* Range of bands to detect transitions */
+#define BL 5 /* Start */
+#define BH 105 /* End */
+#define BW 5 /* Width */
+
+/* Record of possible patch */
+typedef struct {
+ int ss; /* Start sample index */
+ int no; /* Number of samples */
+ int use; /* nz if patch is to be used */
+} munki_patch;
+
+/* Recognise the required number of ref/trans patch locations, */
+/* and average the measurements within each patch. */
+/* *flags returns zero if readings are consistent. */
+/* *flags returns nz if the readings are not consistent */
+/* (Doesn't extract [-1] shielded values, since they have already been used) */
+munki_code munki_extract_patches_multimeas(
+ munki *p,
+ int *flags, /* return flags */
+ double **pavg, /* return patch average [naptch][-1 nraw] */
+ int tnpatch, /* Target number of patches to recognise */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to extract from */
+ int nummeas, /* number of readings made */
+ double inttime /* Integration time (used to adjust consistency threshold) */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ int i, j, k, pix;
+ double **sslope; /* Signed difference between i and i+1 */
+ double *slope; /* Accumulated absolute difference between i and i+1 */
+ double *fslope; /* Filtered slope */
+ munki_patch *pat; /* Possible patch information */
+ int npat, apat = 0;
+ double *maxval; /* Maximum input value for each wavelength */
+ double fmaxslope = 0.0;
+ double maxslope = 0.0;
+ double minslope = 1e38;
+ double thresh = 0.4; /* Slope threshold */
+ int try; /* Thresholding try */
+ double avglegth; /* Average length of patches */
+ int *sizepop; /* Size popularity of potential patches */
+ double median; /* median potential patch width */
+ double window; /* +/- around median to accept */
+ double white_avg; /* Average of (aproximate) white data */
+ int rv = 0;
+ double patch_cons_thr = PATCH_CONS_THR * m->scan_toll_ratio;
+#ifdef PATREC_DEBUG
+ double **plot;
+#endif
+
+ a1logd(p->log,3,"munki_extract_patches_multimeas: looking for %d patches out of %d samples\n",tnpatch,nummeas);
+
+ maxval = dvectorz(-1, m->nraw-1);
+
+ /* Loosen consistency threshold for short intergation time */
+ if (inttime < 0.012308) /* Smaller than Rev A minimum int. time */
+ patch_cons_thr *= sqrt(0.012308/inttime);
+
+ /* Discover the maximum input value for normalisation */
+ for (j = 0; j < m->nraw; j ++) {
+ for (i = 0; i < nummeas; i++) {
+ if (multimeas[i][j] > maxval[j])
+ maxval[j] = multimeas[i][j];
+ }
+ if (maxval[j] < 1.0)
+ maxval[j] = 1.0;
+ }
+
+#ifdef PATREC_DEBUG
+ /* Plot out 6 lots of 6 values each */
+ plot = dmatrixz(0, 6, 0, nummeas-1);
+// for (j = 1; j < (m->nraw-6); j += 6) /* Plot all the bands */
+// for (j = 45; j < (m->nraw-6); j += 100) /* Do just one band */
+ for (j = 5; j < (m->nraw-6); j += 30) { /* Do four bands */
+ for (k = 0; k < 6; k ++) {
+ for (i = 0; i < nummeas; i++) {
+ plot[k][i] = multimeas[i][j+k]/maxval[j+k];
+ }
+ }
+ for (i = 0; i < nummeas; i++)
+ plot[6][i] = (double)i;
+ printf("Bands %d - %d\n",j,j+5);
+ do_plot6(plot[6], plot[0], plot[1], plot[2], plot[3], plot[4], plot[5], nummeas);
+ }
+#endif
+
+ sslope = dmatrixz(0, nummeas-1, -1, m->nraw-1);
+ slope = dvectorz(0, nummeas-1);
+ fslope = dvectorz(0, nummeas-1);
+ sizepop = ivectorz(0, nummeas-1);
+
+#ifndef NEVER /* Good with this on */
+ /* Average bands together */
+ for (i = 0; i < nummeas; i++) {
+ for (j = BL + BW; j < (BH - BW); j++) {
+ for (k = -BL; k <= BW; k++) /* Box averaging filter over bands */
+ sslope[i][j] += multimeas[i][j + k]/maxval[j];
+ }
+ }
+#else
+ /* Don't average bands */
+ for (i = 0; i < nummeas; i++) {
+ for (j = 0; j < m->nraw; j++) {
+ sslope[i][j] = multimeas[i][j]/maxval[j];
+ }
+ }
+#endif
+
+ /* Compute slope result over readings and bands */
+ /* Compute signed slope result over readings and bands */
+
+#ifdef NEVER /* Works well for non-noisy readings */
+ /* Median of 5 differences from 6 points */
+ for (i = 2; i < (nummeas-3); i++) {
+ for (j = BL; j < BH; j++) {
+ double sl, asl[5];
+ int r, s;
+ asl[0] = fabs(sslope[i-2][j] - sslope[i-1][j]);
+ asl[1] = fabs(sslope[i-1][j] - sslope[i-0][j]);
+ asl[2] = fabs(sslope[i-0][j] - sslope[i+1][j]);
+ asl[3] = fabs(sslope[i+1][j] - sslope[i+2][j]);
+ asl[4] = fabs(sslope[i+2][j] - sslope[i+3][j]);
+
+ /* Sort them */
+ for (r = 0; r < (5-1); r++) {
+ for (s = r+1; s < 5; s++) {
+ if (asl[s] < asl[r]) {
+ double tt;
+ tt = asl[s];
+ asl[s] = asl[r];
+ asl[r] = tt;
+ }
+ }
+ }
+ /* Pick middle one */
+ sl = asl[2];
+ if (sl > slope[i])
+ slope[i] = sl;
+ }
+ }
+
+#else /* Works better for noisy readings */
+
+ /* Compute sliding window average and deviation that contains */
+ /* our output point, and chose the average with the minimum deviation. */
+#define FW 3 /* Number of delta's to average */
+ for (i = FW-1; i < (nummeas-FW); i++) { /* Samples */
+ double basl, bdev; /* Best average slope, Best deviation */
+ double sl[2 * FW -1];
+ double asl[FW], dev[FW];
+ int slopen = 0;
+ double slopeth = 0.0;
+ int m, pp;
+
+ for (pp = 0; pp < 2; pp++) { /* For each pass */
+
+ for (j = BL; j < BH; j++) { /* Bands */
+
+ /* Compute differences for the range of our windows */
+ for (k = 0; k < (2 * FW -1); k++)
+ sl[k] = sslope[i+k-FW+1][j] - sslope[i+k+-FW+2][j];
+
+ /* For each window offset, compute average and deviation squared */
+ bdev = 1e38;
+ for (k = 0; k < FW; k++) {
+
+ /* Compute average of this window offset */
+ asl[k] = 0.0;
+ for (m = 0; m < FW; m++) /* For slope in window */
+ asl[k] += sl[k+m];
+ asl[k] /= (double)FW;
+
+ /* Compute deviation squared */
+ dev[k] = 0.0;
+ for (m = 0; m < FW; m++) {
+ double tt;
+ tt = sl[k+m] - asl[k];
+ dev[k] += tt * tt;
+ }
+ if (dev[k] < bdev)
+ bdev = dev[k];
+ }
+
+#ifndef NEVER
+ /* Weight the deviations with a triangular weighting */
+ /* to skew slightly towards the center */
+ for (k = 0; k < FW; k++) {
+ double wt;
+
+ wt = fabs(2.0 * k - (FW -1.0))/(FW-1.0);
+ dev[k] += wt * bdev;
+ }
+#endif
+
+ /* For each window offset, choose the one to use. */
+ bdev = 1e38;
+ basl = 0.0;
+ for (k = 0; k < FW; k++) {
+
+ /* Choose window average with smallest deviation squared */
+ if (dev[k] < bdev) {
+ bdev = dev[k];
+ basl = fabs(asl[k]);
+ }
+ }
+
+ if (pp == 0) { /* First pass, compute average slope over bands */
+ slope[i] += basl;
+
+ } else { /* Second pass, average slopes of bands over threshold */
+ if (basl > slopeth) {
+ slope[i] += basl;
+ slopen++;
+ }
+ }
+ } /* Next band */
+
+ if (pp == 0) {
+ slopeth = 1.0 * slope[i]/j; /* Compute threshold */
+ slope[i] = 0.0;
+ } else {
+ if (slopen > 0)
+ slope[i] /= slopen; /* Compute average of those over threshold */
+ }
+ } /* Next pass */
+ }
+#undef FW
+#endif
+
+#ifndef NEVER /* Good with this on */
+ /* Normalise the slope values */
+ /* Locate the minumum and maximum values */
+ maxslope = 0.0;
+ minslope = 1e38;
+ for (i = 4; i < (nummeas-4); i++) {
+ double avs;
+
+ if (slope[i] > maxslope)
+ maxslope = slope[i];
+
+ /* Simple moving average for min comp. */
+ avs = 0.0;
+ for (j = -2; j <= 2; j++)
+ avs += slope[i+j];
+ avs /= 5.0;
+ if (avs < minslope)
+ minslope = avs;
+ }
+
+ /* Normalise the slope */
+ maxslope *= 0.5;
+ minslope *= 3.0;
+ for (i = 0; i < nummeas; i++) {
+ slope[i] = (slope[i] - minslope) / (maxslope - minslope);
+ if (slope[i] < 0.0)
+ slope[i] = 0.0;
+ else if (slope[i] > 1.0)
+ slope[i] = 1.0;
+ }
+
+ /* "Automatic Gain control" the raw slope information. */
+#define LFW 20 /* Half width of triangular filter */
+ for (i = 0; i < nummeas; i++) {
+ double sum, twt;
+
+ sum = twt = 0.0;
+ for (j = -LFW; j <= LFW; j++) {
+ double wt;
+ if ((i+j) < 0 || (i+j) >= nummeas)
+ continue;
+
+ wt = ((LFW-abs(j))/(double)LFW);
+
+ sum += wt * slope[i+j];
+ twt += wt;
+ }
+ fslope[i] = sum/twt;
+ if (fslope[i] > fmaxslope)
+ fmaxslope = fslope[i];
+ }
+#undef LFW
+
+#ifdef NEVER /* Better with the off, for very noisy samples */
+ /* Apply AGC with limited gain */
+ for (i = 0; i < nummeas; i++) {
+ if (fslope[i] > fmaxslope/4.0)
+ slope[i] = slope[i]/fslope[i];
+ else
+ slope[i] = slope[i] * 4.0/fmaxslope;
+ }
+#endif
+#endif /* NEVER */
+
+ /* Locate the minumum and maximum values */
+ maxslope = 0.0;
+ minslope = 1e38;
+ for (i = 4; i < (nummeas-4); i++) {
+ double avs;
+
+ if (slope[i] > maxslope)
+ maxslope = slope[i];
+
+ /* Simple moving average for min comp. */
+ avs = 0.0;
+ for (j = -2; j <= 2; j++)
+ avs += slope[i+j];
+ avs /= 5.0;
+ if (avs < minslope)
+ minslope = avs;
+ }
+
+#ifndef NEVER /* Good with this on */
+ /* Normalise the slope again */
+ maxslope *= 0.3;
+ minslope *= 3.0;
+ for (i = 0; i < nummeas; i++) {
+ slope[i] = (slope[i] - minslope) / (maxslope - minslope);
+ if (slope[i] < 0.0)
+ slope[i] = 0.0;
+ else if (slope[i] > 1.0)
+ slope[i] = 1.0;
+ }
+#endif
+
+#ifdef PATREC_DEBUG
+ printf("Slope filter output\n");
+ for (i = 0; i < nummeas; i++) {
+ int jj;
+ for (jj = 0, j = BL; jj < 6 && j < BH; jj++, j += ((BH-BL)/6)) {
+ double sum = 0.0;
+ for (k = -BL; k <= BW; k++) /* Box averaging filter over bands */
+ sum += multimeas[i][j + k];
+ plot[jj][i] = sum/((2.0 * BL + 1.0) * maxval[j+k]);
+ }
+ }
+ for (i = 0; i < nummeas; i++)
+ plot[6][i] = (double)i;
+ do_plot6(plot[6], slope, plot[0], plot[1], plot[2], plot[3], plot[4], nummeas);
+#endif
+
+ free_dvector(fslope, 0, nummeas-1);
+ free_dmatrix(sslope, 0, nummeas-1, -1, m->nraw-1);
+
+ /* Now threshold the measurements into possible patches */
+ apat = 2 * nummeas;
+ if ((pat = (munki_patch *)malloc(sizeof(munki_patch) * apat)) == NULL) {
+ a1logd(p->log,1,"munki: malloc of patch structures failed!\n");
+ return MUNKI_INT_MALLOC;
+ }
+
+ avglegth = 0.0;
+ for (npat = i = 0; i < (nummeas-1); i++) {
+ if (slope[i] > thresh)
+ continue;
+
+ /* Start of a new patch */
+ if (npat >= apat) {
+ apat *= 2;
+ if ((pat = (munki_patch *)realloc(pat, sizeof(munki_patch) * apat)) == NULL) {
+ a1logd(p->log,1,"munki: reallloc of patch structures failed!\n");
+ return MUNKI_INT_MALLOC;
+ }
+ }
+ pat[npat].ss = i;
+ pat[npat].no = 2;
+ pat[npat].use = 0;
+ for (i++; i < (nummeas-1); i++) {
+ if (slope[i] > thresh)
+ break;
+ pat[npat].no++;
+ }
+ avglegth += (double) pat[npat].no;
+ npat++;
+ }
+ a1logd(p->log,7,"Number of patches = %d\n",npat);
+
+ /* We don't count the first and last patches, as we assume they are white leader */
+ if (npat < (tnpatch + 2)) {
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,1,"Patch recog failed - unable to detect enough possible patches\n");
+ return MUNKI_RD_NOTENOUGHPATCHES;
+ } else if (npat >= (2 * tnpatch) + 2) {
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,1,"Patch recog failed - detecting too many possible patches\n");
+ return MUNKI_RD_TOOMANYPATCHES;
+ }
+ avglegth /= (double)npat;
+
+#ifdef PATREC_DEBUG
+ for (i = 0; i < npat; i++) {
+ printf("Raw patch %d, start %d, length %d\n",i, pat[i].ss, pat[i].no);
+ }
+#endif
+
+ /* Accumulate popularity ccount of possible patches */
+ for (i = 1; i < (npat-1); i++)
+ sizepop[pat[i].no]++;
+
+ /* Locate the median potential patch width */
+ for (j = 0, i = 0; i < nummeas; i++) {
+ j += sizepop[i];
+ if (j >= ((npat-2)/2))
+ break;
+ }
+ median = (double)i;
+
+ a1logd(p->log,7,"Median patch width %f\n",median);
+
+ /* Now decide which patches to use. */
+ /* Try a widening window around the median. */
+ for (window = 0.2, try = 0; try < 15; window *= 1.4, try++) {
+ int bgcount = 0, bgstart = 0;
+ int gcount, gstart;
+ double wmin = median/(1.0 + window);
+ double wmax = median * (1.0 + window);
+
+ a1logd(p->log,7,"Window = %f - %f\n",wmin, wmax);
+ /* Track which is the largest contiguous group that */
+ /* is within our window */
+ gcount = gstart = 0;
+ for (i = 1; i < npat; i++) {
+ if (i < (npat-1) && pat[i].no <= wmax) { /* Small enough */
+ if (pat[i].no >= wmin) { /* And big enough */
+ if (gcount == 0) { /* Start of new group */
+ gcount++;
+ gstart = i;
+ a1logd(p->log,7,"Start group at %d\n",gstart);
+ } else {
+ gcount++; /* Continuing new group */
+ a1logd(p->log,7,"Continue group at %d, count %d\n",gstart,gcount);
+ }
+ }
+ } else { /* Too big or end of patches, end this group */
+ a1logd(p->log,7,"Terminating group group at %d, count %d\n",gstart,gcount);
+ if (gcount > bgcount) { /* New biggest group */
+ bgcount = gcount;
+ bgstart = gstart;
+ a1logd(p->log,7,"New biggest\n");
+ }
+ gcount = gstart = 0; /* End this group */
+ }
+ }
+ a1logd(p->log,7,"Biggest group is at %d, count %d\n",bgstart,bgcount);
+
+ if (bgcount == tnpatch) { /* We're done */
+ for (i = bgstart, j = 0; i < npat && j < tnpatch; i++) {
+ if (pat[i].no <= wmax && pat[i].no >= wmin) {
+ pat[i].use = 1;
+ j++;
+ if (pat[i].no < MIN_SAMPLES) {
+ a1logd(p->log,7,"Too few samples\n");
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,1,"Patch recog failed - patches sampled too sparsely\n");
+ return MUNKI_RD_NOTENOUGHSAMPLES;
+ }
+ }
+ }
+ break;
+
+ } else if (bgcount > tnpatch) {
+ a1logd(p->log,7,"Too many patches\n");
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,1,"Patch recog failed - detected too many consistent patches\n");
+ return MUNKI_RD_TOOMANYPATCHES;
+ }
+ }
+ if (try >= 15) {
+ a1logd(p->log,7,"Not enough patches\n");
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(slope, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,1,"Patch recog failed - unable to find enough consistent patches\n");
+ return MUNKI_RD_NOTENOUGHPATCHES;
+ }
+
+#ifdef PATREC_DEBUG
+ printf("Got %d patches out of potentional %d:\n",tnpatch, npat);
+ printf("Average patch legth %f\n",avglegth);
+ for (i = 1; i < (npat-1); i++) {
+ if (pat[i].use == 0)
+ continue;
+ printf("Patch %d, start %d, length %d:\n",i, pat[i].ss, pat[i].no, pat[i].use);
+ }
+#endif
+
+ /* Now trim the patches simply by shrinking their windows */
+ for (k = 1; k < (npat-1); k++) {
+ int nno, trim;
+
+ if (pat[k].use == 0)
+ continue;
+
+
+ nno = (pat[k].no * 3)/4;
+ trim = (pat[k].no - nno)/2;
+
+ pat[k].ss += trim;
+ pat[k].no = nno;
+ }
+
+#ifdef PATREC_DEBUG
+ printf("After trimming got:\n");
+ for (i = 1; i < (npat-1); i++) {
+ if (pat[i].use == 0)
+ continue;
+ printf("Patch %d, start %d, length %d:\n",i, pat[i].ss, pat[i].no, pat[i].use);
+ }
+
+ /* Create fake "slope" value that marks patches */
+ for (i = 0; i < nummeas; i++)
+ slope[i] = 1.0;
+ for (k = 1; k < (npat-1); k++) {
+ if (pat[k].use == 0)
+ continue;
+ for (i = pat[k].ss; i < (pat[k].ss + pat[k].no); i++)
+ slope[i] = 0.0;
+ }
+
+ printf("Trimmed output:\n");
+ for (i = 0; i < nummeas; i++) {
+ int jj;
+ for (jj = 0, j = BL; jj < 6 && j < BH; jj++, j += ((BH-BL)/6)) {
+ double sum = 0.0;
+ for (k = -BL; k <= BW; k++) /* Box averaging filter over bands */
+ sum += multimeas[i][j + k];
+ plot[jj][i] = sum/((2.0 * BL + 1.0) * maxval[j+k]);
+ }
+ }
+ for (i = 0; i < nummeas; i++)
+ plot[6][i] = (double)i;
+ do_plot6(plot[6], slope, plot[0], plot[1], plot[2], plot[3], plot[4], nummeas);
+#endif
+
+ /* Compute average of (aproximate) white */
+ white_avg = 0.0;
+ for (j = 1; j < (m->nraw-1); j++)
+ white_avg += maxval[j];
+ white_avg /= (m->nraw - 2.0);
+
+ /* Now process the buffer values */
+ for (i = 0; i < tnpatch; i++)
+ for (j = 0; j < m->nraw; j++)
+ pavg[i][j] = 0.0;
+
+ for (pix = 0, k = 1; k < (npat-1); k++) {
+ double maxavg = -1e38; /* Track min and max averages of readings for consistency */
+ double minavg = 1e38;
+ double cons; /* Consistency */
+
+ if (pat[k].use == 0)
+ continue;
+
+ if (pat[k].no <= MIN_SAMPLES) {
+ a1logd(p->log,7,"Too few samples\n");
+ free_dvector(slope, 0, nummeas-1);
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+ a1logd(p->log,1,"Patch recog failed - patches sampled too sparsely\n");
+ return MUNKI_RD_NOTENOUGHSAMPLES;
+ }
+
+ /* Measure samples that make up patch value */
+ for (i = pat[k].ss; i < (pat[k].ss + pat[k].no); i++) {
+ double measavg = 0.0;
+
+ for (j = 0; j < m->nraw; j++) {
+ double val;
+
+ val = multimeas[i][j];
+
+ measavg += val;
+ pavg[pix][j] += val;
+ }
+ measavg /= (m->nraw-2.0);
+ if (measavg < minavg)
+ minavg = measavg;
+ if (measavg > maxavg)
+ maxavg = measavg;
+ }
+
+ for (j = 0; j < m->nraw; j++)
+ pavg[pix][j] /= (double)pat[k].no;
+
+ cons = (maxavg - minavg)/white_avg;
+ a1logd(p->log,7,"Patch %d: consistency = %f%%, thresh = %f%%\n",pix,100.0 * cons, 100.0 * patch_cons_thr);
+ if (cons > patch_cons_thr) {
+ a1logd(p->log,1,"Patch recog failed - patch %d is inconsistent (%f%%)\n",pix, cons);
+ rv |= 1;
+ }
+ pix++;
+ }
+
+ if (flags != NULL)
+ *flags = rv;
+
+#ifdef PATREC_DEBUG
+ free_dmatrix(plot, 0, 6, 0, nummeas-1);
+#endif
+
+ free_dvector(slope, 0, nummeas-1);
+ free_ivector(sizepop, 0, nummeas-1);
+ free_dvector(maxval, -1, m->nraw-1);
+ free(pat);
+
+ a1logd(p->log,3,"munki_extract_patches_multimeas done, sat = %s, inconsist = %s\n",
+ rv & 2 ? "true" : "false", rv & 1 ? "true" : "false");
+
+ a1logd(p->log,2,"Patch recognition returning OK\n");
+
+ return MUNKI_OK;
+}
+
+#undef BL
+#undef BH
+#undef BW
+
+/* Recognise any flashes in the readings, and */
+/* and average their values together as well as summing their duration. */
+/* The readings are integrated, so the the units are cd/m^2 seconds. */
+/* Return nz on an error */
+/* (Doesn't extract [-1] shielded values, since they have already been used) */
+munki_code munki_extract_patches_flash(
+ munki *p,
+ int *flags, /* return flags */
+ double *duration, /* return duration */
+ double *pavg, /* return patch average [-1 nraw] */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to extract from */
+ int nummeas, /* number of readings made */
+ double inttime /* Integration time (used to compute duration) */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ int i, j, k;
+ double minval, maxval; /* min and max input value at wavelength of maximum input */
+ double mean; /* Mean of the max wavelength band */
+ int maxband; /* Band of maximum value */
+ double thresh; /* Level threshold */
+ int fsampl; /* Index of the first sample over the threshold */
+ int nsampl; /* Number of samples over the threshold */
+ double *aavg; /* ambient average [-1 nraw] */
+ double finttime; /* Flash integration time */
+ int rv = 0;
+#ifdef PATREC_DEBUG
+ double **plot;
+#endif
+
+ a1logd(p->log,3,"munki_extract_patches_flash: %d measurements\n",nummeas);
+
+ /* Discover the maximum input value for flash dection */
+ maxval = -1e6;
+ maxband = 0;
+ for (j = 0; j < m->nraw; j ++) {
+ for (i = 0; i < nummeas; i++) {
+ if (multimeas[i][j] > maxval) {
+ maxval = multimeas[i][j];
+ maxband = j;
+ }
+ }
+ }
+
+ if (maxval <= 0.0) {
+ a1logd(p->log,1,"No flashes found in measurement\n");
+ return MUNKI_RD_NOFLASHES;
+ }
+
+ minval = 1e6;
+ mean = 0.0;
+ for (i = 0; i < nummeas; i++) {
+ mean += multimeas[i][maxband];
+ if (multimeas[i][maxband] < minval)
+ minval = multimeas[i][maxband];
+ }
+ mean /= (double)nummeas;
+
+ /* Set the threshold at 5% from mean towards max */
+ thresh = (3.0 * mean + maxval)/4.0;
+ a1logd(p->log,7,"munki_extract_patches_flash band %d minval %f maxval %f, mean = %f, thresh = %f\n",maxband,minval,maxval,mean, thresh);
+
+#ifdef PATREC_DEBUG
+ /* Plot out 6 lots of 6 values each */
+ plot = dmatrixz(0, 6, 0, nummeas-1);
+ for (j = maxband -3; j>= 0 && j < (m->nraw-6); j += 100) /* Do one set around max */
+ {
+ for (k = 0; k < 6; k ++) {
+ for (i = 0; i < nummeas; i++) {
+ plot[k][i] = multimeas[i][j+k]/maxval;
+ }
+ }
+ for (i = 0; i < nummeas; i++)
+ plot[6][i] = (double)i;
+ printf("Bands %d - %d\n",j,j+5);
+ do_plot6(plot[6], plot[0], plot[1], plot[2], plot[3], plot[4], plot[5], nummeas);
+ }
+ free_dmatrix(plot,0,6,0,nummeas-1);
+#endif
+
+#ifdef PATREC_DEBUG
+ /* Plot just the pulses */
+ {
+ int start, end;
+
+ plot = dmatrixz(0, 6, 0, nummeas-1);
+
+ for(j = 0, start = -1, end = 0;;) {
+
+ for (start = -1, i = end; i < nummeas; i++) {
+ if (multimeas[i][maxband] >= thresh) {
+ if (start < 0)
+ start = i;
+ } else if (start >= 0) {
+ end = i;
+ break;
+ }
+ }
+ if (start < 0)
+ break;
+ start -= 3;
+ if (start < 0)
+ start = 0;
+ end += 4;
+ if (end > nummeas)
+ end = nummeas;
+
+ for (i = start; i < end; i++, j++) {
+ int q;
+
+ plot[6][j] = (double)j;
+#ifdef NEVER /* Plot +/-3 around maxband */
+ for (q = 0, k = maxband -3; k < (maxband+3) && k >= 0 && k < m->nraw; k++, q++) {
+ plot[q][j] = multimeas[i][k]/maxval;
+ }
+#else
+ /* plot max of bands in 6 segments */
+ for (q = 0; q < 6; q++) {
+ int ss, ee;
+
+ plot[q][j] = -1e60;
+ ss = q * (m->nraw/6);
+ ee = (q+1) * (m->nraw/6);
+ for (k = ss; k < ee; k++) {
+ if (multimeas[i][k]/maxval > plot[q][j])
+ plot[q][j] = multimeas[i][k]/maxval;
+ }
+ }
+#endif
+ }
+ }
+ do_plot6(plot[6], plot[0], plot[1], plot[2], plot[3], plot[4], plot[5], j);
+ free_dmatrix(plot,0,6,0,nummeas-1);
+ }
+#endif
+
+ /* Locate the first sample over the threshold, and the */
+ /* total number of samples in the pulses. */
+ fsampl = -1;
+ for (nsampl = i = 0; i < nummeas; i++) {
+ for (j = 0; j < m->nraw-1; j++) {
+ if (multimeas[i][j] >= thresh)
+ break;
+ }
+ if (j < m->nraw-1) {
+ if (fsampl < 0)
+ fsampl = i;
+ nsampl++;
+ }
+ }
+ a1logd(p->log,7,"Number of flash patches = %d\n",nsampl);
+ if (nsampl == 0)
+ return MUNKI_RD_NOFLASHES;
+
+ /* See if there are as many samples before the first flash */
+ if (nsampl < 6)
+ nsampl = 6;
+
+ /* Average nsample samples of ambient */
+ i = (fsampl-3-nsampl);
+ if (i < 0)
+ return MUNKI_RD_NOAMBB4FLASHES;
+ a1logd(p->log,7,"Ambient samples %d to %d \n",i,fsampl-3);
+ aavg = dvectorz(-1, m->nraw-1);
+ for (nsampl = 0; i < (fsampl-3); i++) {
+ for (j = 0; j < m->nraw-1; j++)
+ aavg[j] += multimeas[i][j];
+ nsampl++;
+ }
+
+ /* Average all the values over the threshold, */
+ /* and also one either side of flash */
+ for (j = 0; j < m->nraw-1; j++)
+ pavg[j] = 0.0;
+
+ for (k = 0, i = 1; i < (nummeas-1); i++) {
+ int sample = 0;
+ for (j = 0; j < m->nraw-1; j++) {
+ if (multimeas[i-1][j] >= thresh) {
+ sample = 1;
+ break;
+ }
+ if (multimeas[i][j] >= thresh) {
+ sample = 1;
+ break;
+ }
+ if (multimeas[i+1][j] >= thresh) {
+ sample = 1;
+ break;
+ }
+ }
+ if (j < m->nraw-1) {
+ a1logd(p->log,7,"Integrating flash sample no %d \n",i);
+ for (j = 0; j < m->nraw-1; j++)
+ pavg[j] += multimeas[i][j];
+ k++;
+ }
+ }
+ for (j = 0; j < m->nraw-1; j++)
+ pavg[j] = pavg[j]/(double)k - aavg[j]/(double)nsampl;
+
+ a1logd(p->log,7,"Number of flash patches integrated = %d\n",k);
+
+ finttime = inttime * (double)k;
+ if (duration != NULL)
+ *duration = finttime;
+
+ /* Convert to cd/m^2 seconds */
+ for (j = 0; j < m->nraw-1; j++)
+ pavg[j] *= finttime;
+
+ if (flags != NULL)
+ *flags = rv;
+
+ free_dvector(aavg, -1, m->nraw-1);
+
+ return MUNKI_OK;
+}
+
+/* Convert an absraw array from raw wavelengths to output wavelenths */
+/* for the current resolution. Apply stray light compensation too. */
+void munki_absraw_to_abswav(
+ munki *p,
+ int nummeas, /* Return number of readings measured */
+ double **abswav, /* Desination array [nwav] */
+ double **absraw /* Source array [-1 nraw] */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ double *tm; /* Temporary array */
+ int i, j, k, cx, sx;
+
+ tm = dvector(0, m->nwav-1);
+
+ /* For each measurement */
+ for (i = 0; i < nummeas; i++) {
+
+ /* For each output wavelength */
+ for (cx = j = 0; j < m->nwav; j++) {
+ double oval = 0.0;
+
+ /* For each matrix value */
+ if (s->reflective) {
+ sx = m->rmtx_index[j]; /* Starting index */
+ for (k = 0; k < m->rmtx_nocoef[j]; k++, cx++, sx++)
+ oval += m->rmtx_coef[cx] * absraw[i][sx];
+ } else {
+ sx = m->emtx_index[j]; /* Starting index */
+ for (k = 0; k < m->emtx_nocoef[j]; k++, cx++, sx++)
+ oval += m->emtx_coef[cx] * absraw[i][sx];
+ }
+ tm[j] = oval;
+ }
+
+ /* Now apply stray light compensation */
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav; j++) {
+ double oval = 0.0;
+
+ /* For each matrix value */
+ for (k = 0; k < m->nwav; k++)
+ oval += m->straylight[j][k] * tm[k];
+ abswav[i][j] = oval;
+ }
+ }
+ free_dvector(tm, 0, m->nwav-1);
+}
+
+/* Convert an absraw array from raw wavelengths to output wavelenths */
+/* for the standard resolution. Apply stray light compensation too. */
+void munki_absraw_to_abswav1(
+ munki *p,
+ int nummeas, /* Return number of readings measured */
+ double **abswav, /* Desination array [nwav1] */
+ double **absraw /* Source array [-1 nraw] */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ double *tm; /* Temporary array */
+ int i, j, k, cx, sx;
+
+ tm = dvector(0, m->nwav1-1);
+
+ /* For each measurement */
+ for (i = 0; i < nummeas; i++) {
+
+ /* For each output wavelength */
+ for (cx = j = 0; j < m->nwav1; j++) {
+ double oval = 0.0;
+
+ /* For each matrix value */
+ if (s->reflective) {
+ sx = m->rmtx_index1[j]; /* Starting index */
+ for (k = 0; k < m->rmtx_nocoef1[j]; k++, cx++, sx++)
+ oval += m->rmtx_coef1[cx] * absraw[i][sx];
+ } else {
+ sx = m->emtx_index1[j]; /* Starting index */
+ for (k = 0; k < m->emtx_nocoef1[j]; k++, cx++, sx++)
+ oval += m->emtx_coef1[cx] * absraw[i][sx];
+ }
+ tm[j] = oval;
+ }
+
+ /* Now apply stray light compensation */
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav1; j++) {
+ double oval = 0.0;
+
+ /* For each matrix value */
+ for (k = 0; k < m->nwav1; k++)
+ oval += m->straylight1[j][k] * tm[k];
+ abswav[i][j] = oval;
+ }
+ }
+ free_dvector(tm, 0, m->nwav1-1);
+}
+
+/* Convert an absraw array from raw wavelengths to output wavelenths */
+/* for the high resolution. Apply light compensation too. */
+void munki_absraw_to_abswav2(
+ munki *p,
+ int nummeas, /* Return number of readings measured */
+ double **abswav, /* Desination array [nwav2] */
+ double **absraw /* Source array [-1 nraw] */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ double *tm; /* Temporary array */
+ int i, j, k, cx, sx;
+
+ tm = dvector(0, m->nwav2-1);
+
+ /* For each measurement */
+ for (i = 0; i < nummeas; i++) {
+
+ /* For each output wavelength */
+ for (cx = j = 0; j < m->nwav2; j++) {
+ double oval = 0.0;
+
+ /* For each matrix value */
+ if (s->reflective) {
+ sx = m->rmtx_index2[j]; /* Starting index */
+ for (k = 0; k < m->rmtx_nocoef2[j]; k++, cx++, sx++)
+ oval += m->rmtx_coef2[cx] * absraw[i][sx];
+ } else {
+ sx = m->emtx_index2[j]; /* Starting index */
+ for (k = 0; k < m->emtx_nocoef2[j]; k++, cx++, sx++)
+ oval += m->emtx_coef2[cx] * absraw[i][sx];
+ }
+ tm[j] = oval;
+ }
+
+ /* Now apply stray light compensation */
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav2; j++) {
+ double oval = 0.0;
+
+ /* For each matrix value */
+ for (k = 0; k < m->nwav2; k++)
+ oval += m->straylight2[j][k] * tm[k];
+ abswav[i][j] = oval;
+ }
+ }
+ free_dvector(tm, 0, m->nwav2-1);
+}
+
+/* Convert an abswav array of output wavelengths to scaled output readings. */
+void munki_scale_specrd(
+ munki *p,
+ double **outspecrd, /* Destination */
+ int numpatches, /* Number of readings/patches */
+ double **inspecrd /* Source */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ int i, j;
+
+ /* For each measurement */
+ for (i = 0; i < numpatches; i++) {
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav; j++) {
+ outspecrd[i][j] = inspecrd[i][j] * s->cal_factor[j];
+ }
+ }
+}
+
+
+/* =============================================== */
+#ifdef HIGH_RES
+
+/* High res congiguration */
+#undef EXISTING_SHAPE /* Else generate filter shape */
+#undef USE_GAUSSIAN /* Use gaussian filter shape, else lanczos2 */
+
+#ifdef NEVER
+/* Plot the matrix coefficients */
+void munki_debug_plot_mtx_coef(munki *p, int ref) {
+ munkiimp *m = (munkiimp *)p->m;
+ int i, j, k, cx, sx;
+ double *xx, *ss;
+ double **yy;
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (cx = j = 0; j < m->nwav; j++) {
+ i = j % 5;
+
+// printf("Out wave = %d\n",j);
+ /* For each matrix value */
+ if (ref) {
+ sx = m->rmtx_index[j]; /* Starting index */
+// printf("start index = %d, nocoef %d\n",sx,m->rmtx_nocoef[j]);
+ for (k = 0; k < m->rmtx_nocoef[j]; k++, cx++, sx++) {
+// printf("offset %d, coef ix %d val %f from ccd %d\n",k, cx, m->rmtx_coef[cx], sx);
+ yy[5][sx] += 0.5 * m->rmtx_coef[cx];
+ yy[i][sx] = m->rmtx_coef[cx];
+ }
+ } else {
+ sx = m->emtx_index[j]; /* Starting index */
+// printf("start index = %d, nocoef %d\n",sx,m->emtx_nocoef[j]);
+ for (k = 0; k < m->emtx_nocoef[j]; k++, cx++, sx++) {
+// printf("offset %d, coef ix %d val %f from ccd %d\n",k, cx, m->emtx_coef[cx], sx);
+ yy[5][sx] += 0.5 * m->emtx_coef[cx];
+ yy[i][sx] = m->emtx_coef[cx];
+ }
+ }
+ }
+
+ if (ref)
+ printf("Reflective cooeficients\n");
+ else
+ printf("Emissive cooeficients\n");
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+}
+#endif
+
+/* Filter shape point */
+typedef struct {
+ double wl, we;
+} munki_fs;
+
+/* Filter cooeficient values */
+typedef struct {
+ int ix; /* Raw index */
+ double we; /* Weighting */
+} munki_fc;
+
+/* Wavelenth calibration crossover point information */
+typedef struct {
+ double wav; /* Wavelegth of point */
+ double raw; /* Raw index of point */
+ double wei; /* Weigting of the point */
+} munki_xp;
+
+/* Linearly interpolate the filter shape */
+static double lin_fshape(munki_fs *fsh, int n, double x) {
+ int i;
+ double y;
+
+ if (x <= fsh[0].wl)
+ return fsh[0].we;
+ else if (x >= fsh[n-1].wl)
+ return fsh[n-1].we;
+
+ for (i = 0; i < (n-1); i++)
+ if (x >= fsh[i].wl && x <= fsh[i+1].wl)
+ break;
+
+ x = (x - fsh[i].wl)/(fsh[i+1].wl - fsh[i].wl);
+ y = fsh[i].we + (fsh[i+1].we - fsh[i].we) * x;
+
+ return y;
+}
+
+/* Generate a sample from a lanczos2 filter shape */
+/* wi is the width of the filter */
+static double lanczos2(double wi, double x) {
+ double y;
+
+#ifdef USE_GAUSSIAN
+ /* gausian */
+ wi = wi/(2.0 * sqrt(2.0 * log(2.0))); /* Convert width at half max to std. dev. */
+ x = x/(sqrt(2.0) * wi);
+ y = 1.0/(wi * sqrt(2.0 * DBL_PI)) * exp(-(x * x));
+#else
+
+ /* lanczos2 */
+ x = fabs(1.0 * x/wi);
+ if (x >= 2.0)
+ return 0.0;
+ if (x < 1e-5)
+ return 1.0;
+ y = sin(DBL_PI * x)/(DBL_PI * x) * sin(DBL_PI * x/2.0)/(DBL_PI * x/2.0);
+#endif
+ return y;
+}
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a ppc gcc 3.3 optimiser bug... */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+/* Create high resolution mode references, */
+/* Create Reflective if ref nz, else create Emissive */
+/* We expect this to be called twice, once for each. */
+munki_code munki_create_hr(munki *p, int ref) {
+ munkiimp *m = (munkiimp *)p->m;
+ int i, j, jj, k, cx, sx;
+ munki_fc coeff[40][16]; /* Existing filter cooefficients */
+ int nwav1; /* Number of filters */
+ double wl_short1, wl_long1; /* Ouput wavelength of first and last filters */
+ double wl_step1;
+ munki_xp xp[41]; /* Crossover points each side of filter */
+ munki_code ev = MUNKI_OK;
+ rspl *raw2wav; /* Lookup from CCD index to wavelength */
+ munki_fs fshape[40 * 16]; /* Existing filter shape */
+ int ncp = 0; /* Number of shape points */
+ int *mtx_index1, **pmtx_index2, *mtx_index2;
+ int *mtx_nocoef1, **pmtx_nocoef2, *mtx_nocoef2;
+ double *mtx_coef1, **pmtx_coef2, *mtx_coef2;
+
+ /* Start with nominal values. May alter these if filters are not unique */
+ nwav1 = m->nwav1;
+ wl_short1 = m->wl_short1;
+ wl_long1 = m->wl_long1;
+ wl_step1 = (wl_long1 - m->wl_short1)/(m->nwav1-1.0);
+
+ if (ref) {
+ mtx_index1 = m->rmtx_index1;
+ mtx_nocoef1 = m->rmtx_nocoef1;
+ mtx_coef1 = m->rmtx_coef1;
+ mtx_index2 = mtx_nocoef2 = NULL;
+ mtx_coef2 = NULL;
+ pmtx_index2 = &m->rmtx_index2;
+ pmtx_nocoef2 = &m->rmtx_nocoef2;
+ pmtx_coef2 = &m->rmtx_coef2;
+ } else {
+ mtx_index1 = m->emtx_index1;
+ mtx_nocoef1 = m->emtx_nocoef1;
+ mtx_coef1 = m->emtx_coef1;
+ mtx_index2 = mtx_nocoef2 = NULL;
+ mtx_coef2 = NULL;
+ pmtx_index2 = &m->emtx_index2;
+ pmtx_nocoef2 = &m->emtx_nocoef2;
+ pmtx_coef2 = &m->emtx_coef2;
+ }
+
+ /* Convert the native filter cooeficient representation to */
+ /* a 2D array we can randomly index. Skip any duplicated */
+ /* filter cooeficients. */
+ for (cx = j = jj = 0; j < m->nwav1; j++) { /* For each output wavelength */
+ if (j >= 40) { /* Assert */
+ a1logw(p->log,"munki: number of output wavelenths is > 40\n");
+ return MUNKI_INT_ASSERT;
+ }
+
+ /* For each matrix value */
+ sx = mtx_index1[j]; /* Starting index */
+ if (jj == 0 && (j+1) < m->nwav1 && sx == mtx_index1[j+1]) { /* Same index */
+// printf("~1 skipping %d\n",j);
+ wl_short1 += wl_step1;
+ nwav1--;
+ cx += mtx_nocoef1[j];
+ continue;
+ }
+ for (k = 0; k < mtx_nocoef1[j]; k++, cx++, sx++) {
+ if (k >= 16) { /* Assert */
+ a1logw(p->log,"munki: number of filter coeefs is > 16\n");
+ return MUNKI_INT_ASSERT;
+ }
+
+ coeff[jj][k].ix = sx;
+ coeff[jj][k].we = mtx_coef1[cx];
+ }
+ jj++;
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot original re-sampling curves */
+ {
+ double *xx, *ss;
+ double **yy;
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (j = 0; j < nwav1; j++) {
+ i = j % 5;
+
+ /* For each matrix value */
+ for (k = 0; k < mtx_nocoef1[j]; k++) {
+ yy[5][coeff[j][k].ix] += 0.5 * coeff[j][k].we;
+ yy[i][coeff[j][k].ix] = coeff[j][k].we;
+ }
+ }
+
+ if (ref)
+ printf("Original reflection wavelength sampling curves:\n");
+ else
+ printf("Original emission wavelength sampling curves:\n");
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+// a1logd(p->log,3,"computing crossover points\n");
+ /* Compute the crossover points between each filter */
+ for (i = 0; i < (nwav1-1); i++) {
+ double den, y1, y2, y3, y4, yn, xn; /* Location of intersection */
+ double besty = -1e6;
+
+ /* between filter i and i+1, we want to find the two */
+ /* raw indexes where the weighting values cross over */
+ /* Do a brute force search to avoid making assumptions */
+ /* about the raw order. */
+ for (j = 0; j < (mtx_nocoef1[i]-1); j++) {
+ for (k = 0; k < (mtx_nocoef1[i+1]-1); k++) {
+ if (coeff[i][j].ix == coeff[i+1][k].ix
+ && coeff[i][j+1].ix == coeff[i+1][k+1].ix
+ && coeff[i][j].we > 0.0 && coeff[i][j+1].we > 0.0
+ && coeff[i+1][k].we > 0.0 && coeff[i+1][k+1].we > 0.0
+ && (( coeff[i][j].we >= coeff[i+1][k].we
+ && coeff[i][j+1].we <= coeff[i+1][k+1].we)
+ || ( coeff[i][j].we <= coeff[i+1][k].we
+ && coeff[i][j+1].we >= coeff[i+1][k+1].we))) {
+// a1logd(p->log,3,"got it at %d, %d: %d = %d, %d = %d\n",j,k, coeff[i][j].ix, coeff[i+1][k].ix, coeff[i][j+1].ix, coeff[i+1][k+1].ix);
+
+ /* Compute the intersection of the two line segments */
+ y1 = coeff[i][j].we;
+ y2 = coeff[i][j+1].we;
+ y3 = coeff[i+1][k].we;
+ y4 = coeff[i+1][k+1].we;
+ den = -y4 + y3 + y2 - y1;
+ yn = (y2 * y3 - y1 * y4)/den;
+ xn = (y3 - y1)/den;
+// a1logd(p->log,3,"den = %f, yn = %f, xn = %f\n",den,yn,xn);
+// a1logd(p->log,3,"Intersection %d: wav %f, raw %f, wei %f\n",i+1,xp[i+1].wav,xp[i+1].raw,xp[i+1].wei);
+ if (yn > besty) {
+ xp[i+1].wav = XSPECT_WL(wl_short1, wl_long1, nwav1, i + 0.5);
+ xp[i+1].raw = (1.0 - xn) * coeff[i][j].ix + xn * coeff[i][j+1].ix;
+ xp[i+1].wei = yn;
+ besty = yn;
+// a1logd(p->log,3,"Found new best y\n");
+ }
+// a1logd(p->log,3,"\n");
+ }
+ }
+ }
+ if (besty < 0.0) { /* Assert */
+ a1logw(p->log,"munki: failed to locate crossover between resampling filters\n");
+ return MUNKI_INT_ASSERT;
+ }
+// a1logd(p->log,3,"\n");
+ }
+
+ /* Add the two points for the end filters */
+ {
+ double x5, x6, y5, y6; /* Points on intesecting line */
+ double den, y1, y2, y3, y4, yn, xn; /* Location of intersection */
+
+ x5 = xp[1].raw;
+ y5 = xp[1].wei;
+ x6 = xp[2].raw;
+ y6 = xp[2].wei;
+
+ /* Search for possible intersection point with first curve */
+ /* Create equation for line from next two intersection points */
+ for (j = 0; j < (mtx_nocoef1[0]-1); j++) {
+ /* Extrapolate line to this segment */
+ y3 = y5 + (coeff[0][j].ix - x5)/(x6 - x5) * (y6 - y5);
+ y4 = y5 + (coeff[0][j+1].ix - x5)/(x6 - x5) * (y6 - y5);
+ /* This segment of curve */
+ y1 = coeff[0][j].we;
+ y2 = coeff[0][j+1].we;
+ if ( (( y1 >= y3 && y2 <= y4) /* Segments overlap */
+ || ( y1 <= y3 && y2 >= y4))
+ && (( coeff[0][j].ix < x5 && coeff[0][j].ix < x6
+ && coeff[0][j+1].ix < x5 && coeff[0][j+1].ix < x6)
+ || ( coeff[0][j+1].ix > x5 && coeff[0][j+1].ix > x6
+ && coeff[0][j].ix > x5 && coeff[0][j].ix > x6))) {
+ break;
+ }
+ }
+ if (j >= mtx_nocoef1[0]) { /* Assert */
+ a1logw(p->log,"munki: failed to end crossover\n");
+ return MUNKI_INT_ASSERT;
+ }
+ den = -y4 + y3 + y2 - y1;
+ yn = (y2 * y3 - y1 * y4)/den;
+ xn = (y3 - y1)/den;
+// a1logd(p->log,3,"den = %f, yn = %f, xn = %f\n",den,yn,xn);
+ xp[0].wav = XSPECT_WL(wl_short1, wl_long1, nwav1, -0.5);
+ xp[0].raw = (1.0 - xn) * coeff[0][j].ix + xn * coeff[0][j+1].ix;
+ xp[0].wei = yn;
+// a1logd(p->log,3,"End 0 intersection %d: wav %f, raw %f, wei %f\n",0,xp[0].wav,xp[0].raw,xp[0].wei);
+// a1logd(p->log,3,"\n");
+
+ x5 = xp[nwav1-2].raw;
+ y5 = xp[nwav1-2].wei;
+ x6 = xp[nwav1-1].raw;
+ y6 = xp[nwav1-1].wei;
+
+// a1logd(p->log,3,"x5 %f, y5 %f, x6 %f, y6 %f\n",x5,y5,x6,y6);
+ /* Search for possible intersection point with first curve */
+ /* Create equation for line from next two intersection points */
+ for (j = 0; j < (mtx_nocoef1[0]-1); j++) {
+ /* Extrapolate line to this segment */
+ y3 = y5 + (coeff[nwav1-1][j].ix - x5)/(x6 - x5) * (y6 - y5);
+ y4 = y5 + (coeff[nwav1-1][j+1].ix - x5)/(x6 - x5) * (y6 - y5);
+ /* This segment of curve */
+ y1 = coeff[nwav1-1][j].we;
+ y2 = coeff[nwav1-1][j+1].we;
+ if ( (( y1 >= y3 && y2 <= y4) /* Segments overlap */
+ || ( y1 <= y3 && y2 >= y4))
+ && (( coeff[nwav1-1][j].ix < x5 && coeff[nwav1-1][j].ix < x6
+ && coeff[nwav1-1][j+1].ix < x5 && coeff[nwav1-1][j+1].ix < x6)
+ || ( coeff[nwav1-1][j+1].ix > x5 && coeff[nwav1-1][j+1].ix > x6
+ && coeff[nwav1-1][j].ix > x5 && coeff[nwav1-1][j].ix > x6))) {
+ break;
+ }
+ }
+ if (j >= mtx_nocoef1[nwav1-1]) { /* Assert */
+ a1logw(p->log, "munki: failed to end crossover\n");
+ return MUNKI_INT_ASSERT;
+ }
+ den = -y4 + y3 + y2 - y1;
+ yn = (y2 * y3 - y1 * y4)/den;
+ xn = (y3 - y1)/den;
+// a1logd(p->log,3,"den = %f, yn = %f, xn = %f\n",den,yn,xn);
+ xp[nwav1].wav = XSPECT_WL(wl_short1, wl_long1, nwav1, nwav1-0.5);
+ xp[nwav1].raw = (1.0 - xn) * coeff[nwav1-1][j].ix + xn * coeff[nwav1-1][j+1].ix;
+ xp[nwav1].wei = yn;
+// a1logd(p->log,3,"End 36 intersection %d: wav %f, raw %f, wei %f\n",nwav1+1,xp[nwav1].wav,xp[nwav1].raw,xp[nwav1].wei);
+// a1logd(p->log,3,"\n");
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot original re-sampling curves + crossing points */
+ {
+ double *xx, *ss;
+ double **yy;
+ double *xc, *yc;
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+ xc = dvectorz(0, nwav1); /* Crossover X */
+ yc = dvectorz(0, nwav1); /* Crossover Y */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (j = 0; j < nwav1; j++) {
+ i = j % 5;
+
+ /* For each matrix value */
+ for (k = 0; k < mtx_nocoef1[j]; k++) {
+ yy[5][coeff[j][k].ix] += 0.5 * coeff[j][k].we;
+ yy[i][coeff[j][k].ix] = coeff[j][k].we;
+ }
+ }
+
+ /* Crosses at intersection points */
+ for (i = 0; i <= nwav1; i++) {
+ xc[i] = xp[i].raw;
+ yc[i] = xp[i].wei;
+ }
+
+ if (ref)
+ printf("Original reflection sampling curves + crossover points\n");
+ else
+ printf("Original emsission sampling curves + crossover points\n");
+ do_plot6p(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw, xc, yc, nwav1+1);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+ free_dvector(xc, 0, nwav1);
+ free_dvector(yc, 0, nwav1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+#ifdef HIGH_RES_DEBUG
+ /* Check to see if the area of each filter curve is the same */
+ /* (yep, width times 2 * xover height is close to 1.0, and the */
+ /* sum of the weightings is exactly 1.0) */
+ for (i = 0; i < nwav1; i++) {
+ double area1, area2;
+ area1 = fabs(xp[i].raw - xp[i+1].raw) * (xp[i].wei + xp[i+1].wei);
+
+ area2 = 0.0;
+ for (j = 0; j < (mtx_nocoef1[i]); j++)
+ area2 += coeff[i][j].we;
+
+ printf("Area of curve %d = %f, %f\n",i,area1, area2);
+ }
+#endif /* HIGH_RES_DEBUG */
+
+ /* From our crossover data, create a rspl that maps raw CCD index */
+ /* value into wavelegth. */
+ {
+ co sd[101]; /* Scattered data points */
+ datai glow, ghigh;
+ datao vlow, vhigh;
+ int gres[1];
+ double avgdev[1];
+
+ if ((raw2wav = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ a1logd(p->log,3,"munki: creating rspl for high res conversion failed\n");
+ return MUNKI_INT_NEW_RSPL_FAILED;
+ }
+
+ vlow[0] = 1e6;
+ vhigh[0] = -1e6;
+
+ for (i = 0; i < (nwav1+1); i++) {
+ sd[i].p[0] = xp[i].raw;
+ sd[i].v[0] = xp[i].wav;
+
+ if (sd[i].v[0] < vlow[0])
+ vlow[0] = sd[i].v[0];
+ if (sd[i].v[0] > vhigh[0])
+ vhigh[0] = sd[i].v[0];
+ }
+ glow[0] = 0.0;
+ ghigh[0] = (double)(m->nraw-1);
+ gres[0] = m->nraw;
+ avgdev[0] = 0.0;
+
+ raw2wav->fit_rspl(raw2wav, 0, sd, nwav1+1, glow, ghigh, gres, vlow, vhigh, 1.0, avgdev, NULL);
+ }
+
+#ifdef EXISTING_SHAPE
+ /* Convert each weighting curves values into normalized values and */
+ /* accumulate into a single curve. */
+ /* This probably isn't quite correct - we really need to remove */
+ /* the effects of the convolution with the CCD cell widths. */
+ /* perhaps it's closer to a lanczos2 if this were done ? */
+ {
+ for (i = 0; i < nwav1; i++) {
+ double cwl; /* center wavelegth */
+ double weight = 0.0;
+
+ for (j = 0; j < (mtx_nocoef1[i]); j++) {
+ double w1, w2, cellw;
+ co pp;
+
+ /* Translate CCD cell boundaries index to wavelength */
+ pp.p[0] = (double)coeff[i][j].ix - 0.5;
+ raw2wav->interp(raw2wav, &pp);
+ w1 = pp.v[0];
+
+ pp.p[0] = (double)coeff[i][j].ix + 0.5;
+ raw2wav->interp(raw2wav, &pp);
+ w2 = pp.v[0];
+
+ cellw = fabs(w2 - w1);
+
+ cwl = XSPECT_WL(wl_short1, wl_long1, nwav1, i);
+
+ /* Translate CCD index to wavelength */
+ pp.p[0] = (double)coeff[i][j].ix;
+ raw2wav->interp(raw2wav, &pp);
+ fshape[ncp].wl = pp.v[0] - cwl;
+ fshape[ncp].we = coeff[i][j].we / (0.09 * cellw);
+ ncp++;
+ }
+ }
+
+ /* Now sort by wavelength */
+#define HEAP_COMPARE(A,B) (A.wl < B.wl)
+ HEAPSORT(munki_fs, fshape, ncp)
+#undef HEAP_COMPARE
+
+ /* Strip out leading zero's */
+ for (i = 0; i < ncp; i++) {
+ if (fshape[i].we != 0.0)
+ break;
+ }
+ if (i > 1 && i < ncp) {
+ memmove(&fshape[0], &fshape[i-1], sizeof(munki_fs) * (ncp - i + 1));
+ ncp = ncp - i + 1;
+ for (i = 0; i < ncp; i++) {
+ if (fshape[i].we != 0.0)
+ break;
+ }
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot the shape of the accumulated curve */
+ {
+ double *x1 = dvectorz(0, ncp-1);
+ double *y1 = dvectorz(0, ncp-1);
+
+ for (i = 0; i < ncp; i++) {
+ double x;
+ x1[i] = fshape[i].wl;
+ y1[i] = fshape[i].we;
+ }
+ if (ref)
+ printf("Shape of existing reflection sampling curve:\n");
+ else
+ printf("Shape of existing emission sampling curve:\n");
+ do_plot(x1, y1, NULL, NULL, ncp);
+
+ free_dvector(x1, 0, ncp-1);
+ free_dvector(y1, 0, ncp-1);
+ }
+#endif /* HIGH_RES_PLOT */
+ }
+#endif /* EXISTING_SHAPE */
+
+#ifdef HIGH_RES_DEBUG
+ /* Check that the filter sums to a constant */
+ {
+ double x, sum;
+
+ for (x = 0.0; x < 10.0; x += 0.2) {
+ sum = 0;
+ sum += lin_fshape(fshape, ncp, x - 30.0);
+ sum += lin_fshape(fshape, ncp, x - 20.0);
+ sum += lin_fshape(fshape, ncp, x - 10.0);
+ sum += lin_fshape(fshape, ncp, x - 0.0);
+ sum += lin_fshape(fshape, ncp, x + 10.0);
+ sum += lin_fshape(fshape, ncp, x + 20.0);
+ printf("Offset %f, sum %f\n",x, sum);
+ }
+ }
+#endif /* HIGH_RES_DEBUG */
+
+ {
+ double fshmax; /* filter shape max wavelength from center */
+#define MXNOFC 64
+ munki_fc coeff2[500][MXNOFC]; /* New filter cooefficients */
+ double twidth;
+
+ /* Construct a set of filters that uses more CCD values */
+ twidth = HIGHRES_WIDTH;
+
+ if (m->nwav2 > 500) { /* Assert */
+ a1logw(p->log,"High res filter has too many bands\n");
+ return MUNKI_INT_ASSERT;
+ }
+
+#ifdef EXISTING_SHAPE /* Else generate filter shape */
+ /* Cut the filter width by half, to conver from 10nm to 5nm spacing */
+ for (i = 0; i < ncp; i++)
+ fshape[i].wl *= twidth/10.0;
+ fshmax = -fshape[0].wl; /* aximum extent needed around zero */
+ if (fshape[ncp-1].wl > fshmax)
+ fshmax = fshape[ncp-1].wl;
+#else
+ /* Use a crude means of determining width */
+ for (fshmax = 50.0; fshmax >= 0.0; fshmax -= 0.1) {
+ if (fabs(lanczos2(twidth, fshmax)) > 0.001) {
+ fshmax += 0.1;
+ break;
+ }
+ }
+ if (fshmax <= 0.0) {
+ a1logw(p->log,"munki: fshmax search failed\n");
+ return MUNKI_INT_ASSERT;
+ }
+#endif
+// a1logd(p->log,1,"fshmax = %f\n",fshmax);
+
+#ifdef HIGH_RES_DEBUG
+ /* Check that the filter sums to a constant */
+ {
+ double x, sum;
+
+ for (x = 0.0; x < 5.0; x += 0.1) {
+ sum = 0;
+ sum += lin_fshape(fshape, ncp, x - 15.0);
+ sum += lin_fshape(fshape, ncp, x - 10.0);
+ sum += lin_fshape(fshape, ncp, x - 5.0);
+ sum += lin_fshape(fshape, ncp, x - 0.0);
+ sum += lin_fshape(fshape, ncp, x + 5.0);
+ sum += lin_fshape(fshape, ncp, x + 10.0);
+ printf("Offset %f, sum %f\n",x, sum);
+ }
+ }
+#endif /* HIGH_RES_DEBUG */
+
+ /* Create all the filters */
+ if ((*pmtx_nocoef2 = mtx_nocoef2 = (int *)calloc(m->nwav2, sizeof(int))) == NULL) {
+ a1logd(p->log,1,"munki: malloc mtx_nocoef2 failed!\n");
+ return MUNKI_INT_MALLOC;
+ }
+
+ /* For all the useful CCD bands */
+ for (i = 0; i < m->nraw; i++) {
+ co pp;
+ double w1, wl, w2;
+
+ /* Translate CCD center to to wavelength */
+ pp.p[0] = (double)i;
+ raw2wav->interp(raw2wav, &pp);
+ wl = pp.v[0];
+
+ /* Translate CCD cell boundaries index to wavelength */
+ pp.p[0] = i - 0.5;
+ raw2wav->interp(raw2wav, &pp);
+ w1 = pp.v[0];
+
+ pp.p[0] = i + 0.5;
+ raw2wav->interp(raw2wav, &pp);
+ w2 = pp.v[0];
+
+// a1logd(p->log,1,"CCD %d, wl %f\n",i,wl);
+
+ /* For each filter */
+ for (j = 0; j < m->nwav2; j++) {
+ double cwl, rwl; /* center, relative wavelegth */
+ double we;
+
+ cwl = m->wl_short2 + (double)j * (m->wl_long2 - m->wl_short2)/(m->nwav2-1.0);
+ rwl = wl - cwl; /* relative wavelgth to filter */
+
+ if (fabs(w1 - cwl) > fshmax && fabs(w2 - cwl) > fshmax)
+ continue; /* Doesn't fall into this filter */
+
+#ifndef NEVER
+ /* Integrate in 0.05 nm increments from filter shape */
+ {
+ int nn;
+ double lw, ll;
+
+ nn = (int)(fabs(w2 - w1)/0.05 + 0.5);
+
+ lw = w1;
+#ifdef EXISTING_SHAPE
+ ll = lin_fshape(fshape, ncp, w1- cwl);
+#else
+ ll = lanczos2(twidth, w1- cwl);
+#endif
+ we = 0.0;
+ for (k = 0; k < nn; k++) {
+ double cw, cl;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(k);
+#endif
+ cw = w1 + (k+1.0)/(nn +1.0) * (w2 - w1);
+#ifdef EXISTING_SHAPE
+ cl = lin_fshape(fshape, ncp, cw - cwl);
+#else
+ cl = lanczos2(twidth, cw- cwl);
+#endif
+ we += 0.5 * (cl + ll) * (lw - cw);
+ ll = cl;
+ lw = cw;
+ }
+ }
+
+
+#else /* Point sample with weighting */
+
+#ifdef EXISTING_SHAPE
+ we = fabs(w2 - w1) * lin_fshape(fshape, ncp, rwl);
+#else
+ we = fabs(w2 - w1) * lanczos2(twidth, rwl);
+#endif
+
+#endif /* Integrate/Point sample */
+
+ if (mtx_nocoef2[j] >= MXNOFC) {
+ a1logw(p->log,"munki: run out of high res filter space\n");
+ return MUNKI_INT_ASSERT;
+ }
+
+ coeff2[j][mtx_nocoef2[j]].ix = i;
+ coeff2[j][mtx_nocoef2[j]++].we = we;
+// a1logd(p->log,1,"filter %d, cwl %f, rwl %f, ix %d, we %f\n",j,cwl,rwl,i,we);
+ }
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot resampled curves */
+ {
+ double *xx, *ss;
+ double **yy;
+
+ xx = dvectorz(0, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, 0, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav2; j++) {
+ i = j % 5;
+
+ /* For each matrix value */
+ for (k = 0; k < mtx_nocoef2[j]; k++) {
+ yy[5][coeff2[j][k].ix] += 0.5 * coeff2[j][k].we;
+ yy[i][coeff2[j][k].ix] = coeff2[j][k].we;
+ }
+ }
+
+ if (ref)
+ printf("Hi-Res reflection wavelength sampling curves:\n");
+ else
+ printf("Hi-Res emission wavelength sampling curves:\n");
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, 0, m->nraw-1);
+ free_dmatrix(yy, 0, 2, 0, m->nraw-1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+ /* Normalise the filters area in CCD space, while maintaining the */
+ /* total contribution of each CCD at the target too. */
+ {
+ int ii;
+ double tot = 0.0;
+ double ccdweight[NSEN_MAX], avgw; /* Weighting determined by cell widths */
+ double ccdsum[NSEN_MAX];
+
+ /* Normalize the overall filter weightings */
+ for (j = 0; j < m->nwav2; j++)
+ for (k = 0; k < mtx_nocoef2[j]; k++)
+ tot += coeff2[j][k].we;
+ tot /= (double)m->nwav2;
+ for (j = 0; j < m->nwav2; j++)
+ for (k = 0; k < mtx_nocoef2[j]; k++)
+ coeff2[j][k].we /= tot;
+
+ /* Determine the relative weights for each CCD */
+ avgw = 0.0;
+ for (i = 0; i < m->nraw; i++) {
+ co pp;
+
+ pp.p[0] = i - 0.5;
+ raw2wav->interp(raw2wav, &pp);
+ ccdweight[i] = pp.v[0];
+
+ pp.p[0] = i + 0.5;
+ raw2wav->interp(raw2wav, &pp);
+ ccdweight[i] = fabs(ccdweight[i] - pp.v[0]);
+ avgw += ccdweight[i];
+ }
+ avgw /= 126.0;
+ // ~~this isn't right because not all CCD's get used!!
+
+#ifdef NEVER
+ /* Itterate */
+ for (ii = 0; ; ii++) {
+
+ /* Normalize the individual filter weightings */
+ for (j = 0; j < m->nwav2; j++) {
+ double err;
+ tot = 0.0;
+ for (k = 0; k < mtx_nocoef2[j]; k++)
+ tot += coeff2[j][k].we;
+ err = 1.0 - tot;
+
+ for (k = 0; k < mtx_nocoef2[j]; k++)
+ coeff2[j][k].we += err/mtx_nocoef2[j];
+// for (k = 0; k < mtx_nocoef2[j]; k++)
+// coeff2[j][k].we *= 1.0/tot;
+ }
+
+ /* Check CCD sums */
+ for (i = 0; i < nraw; i++)
+ ccdsum[i] = 0.0;
+
+ for (j = 0; j < m->nwav2; j++) {
+ for (k = 0; k < mtx_nocoef2[j]; k++)
+ ccdsum[coeff2[j][k].ix] += coeff2[j][k].we;
+ }
+
+ if (ii >= 6)
+ break;
+
+ /* Readjust CCD sum */
+ for (i = 0; i < nraw; i++) {
+ ccdsum[i] = ccdtsum[i]/ccdsum[i]; /* Amount to adjust */
+ }
+
+ for (j = 0; j < m->nwav2; j++) {
+ for (k = 0; k < mtx_nocoef2[j]; k++)
+ coeff2[j][k].we *= ccdsum[coeff2[j][k].ix];
+ }
+ }
+#endif /* NEVER */
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot resampled curves */
+ {
+ double *xx, *ss;
+ double **yy;
+
+ xx = dvectorz(-1, m->nraw-1); /* X index */
+ yy = dmatrixz(0, 5, -1, m->nraw-1); /* Curves distributed amongst 5 graphs */
+
+ for (i = 0; i < m->nraw; i++)
+ xx[i] = i;
+
+ /* For each output wavelength */
+ for (j = 0; j < m->nwav2; j++) {
+ i = j % 5;
+
+ /* For each matrix value */
+ for (k = 0; k < mtx_nocoef2[j]; k++) {
+ yy[5][coeff2[j][k].ix] += 0.5 * coeff2[j][k].we;
+ yy[i][coeff2[j][k].ix] = coeff2[j][k].we;
+ }
+ }
+
+ printf("Normalized Hi-Res wavelength sampling curves:\n");
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], m->nraw);
+ free_dvector(xx, -1, m->nraw-1);
+ free_dmatrix(yy, 0, 2, -1, m->nraw-1);
+ }
+#endif /* HIGH_RES_PLOT */
+ /* Convert into runtime format */
+ {
+ int xcount;
+
+ if ((*pmtx_index2 = mtx_index2 = (int *)calloc(m->nwav2, sizeof(int))) == NULL) {
+ a1logd(p->log,1,"munki: malloc mtx_index2 failed!\n");
+ return MUNKI_INT_MALLOC;
+ }
+
+ xcount = 0;
+ for (j = 0; j < m->nwav2; j++) {
+ mtx_index2[j] = coeff2[j][0].ix;
+ xcount += mtx_nocoef2[j];
+ }
+
+ if ((*pmtx_coef2 = mtx_coef2 = (double *)calloc(xcount, sizeof(double))) == NULL) {
+ a1logd(p->log,1,"munki: malloc mtx_coef2 failed!\n");
+ return MUNKI_INT_MALLOC;
+ }
+
+ for (i = j = 0; j < m->nwav2; j++)
+ for (k = 0; k < mtx_nocoef2[j]; k++, i++)
+ mtx_coef2[i] = coeff2[j][k].we;
+ }
+
+ /* Basic capability is initialised */
+ m->hr_inited++;
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* If both reflective and emissive samplings have been created, */
+ /* deal with upsampling the references and calibrations */
+ if (m->hr_inited == 2) {
+#ifdef SALONEINSTLIB
+ double **slp; /* 2D Array of stray light values */
+#endif /* !SALONEINSTLIB */
+ rspl *trspl; /* Upsample rspl */
+ cow sd[40 * 40]; /* Scattered data points of existing references */
+ datai glow, ghigh;
+ datao vlow, vhigh;
+ int gres[2];
+ double avgdev[2];
+ int ii, jj;
+ co pp;
+
+ /* First the 1D references */
+ if ((trspl = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ a1logd(p->log,3,"munki: creating rspl for high res conversion failed\n");
+ raw2wav->del(raw2wav);
+ return MUNKI_INT_NEW_RSPL_FAILED;
+ }
+
+ for (ii = 0; ii < 4; ii++) {
+ double **ref2, *ref1;
+
+ if (ii == 0) {
+ ref1 = m->white_ref1;
+ ref2 = &m->white_ref2;
+ } else if (ii == 1) {
+ ref1 = m->emis_coef1;
+ ref2 = &m->emis_coef2;
+ } else if (ii == 2) {
+ ref1 = m->amb_coef1;
+ ref2 = &m->amb_coef2;
+ } else {
+ ref1 = m->proj_coef1;
+ ref2 = &m->proj_coef2;
+ }
+
+ vlow[0] = 1e6;
+ vhigh[0] = -1e6;
+
+ /* Set scattered points */
+ for (i = 0; i < m->nwav1; i++) {
+
+ sd[i].p[0] = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, i);
+ sd[i].v[0] = ref1[i];
+ sd[i].w = 1.0;
+
+ if (sd[i].v[0] < vlow[0])
+ vlow[0] = sd[i].v[0];
+ if (sd[i].v[0] > vhigh[0])
+ vhigh[0] = sd[i].v[0];
+ }
+
+ /* Add some corrections at short wavelengths */
+ /* (The combination of the diffraction grating and */
+ /* LED light source doesn't give us much to work with here.) */
+ if (ii == 1) { /* Emission */
+ sd[0].v[0] *= 10.0; /* 380 */
+ sd[1].v[0] *= 3.0; /* 390 */
+ sd[2].v[0] *= 1.0; /* 400 */
+ }
+
+ if (ii == 2) { /* Ambient */
+ sd[0].v[0] *= 5.0; /* 380 */ /* Doesn't help much, because */
+ sd[1].v[0] *= 2.0; /* 390 */ /* the diffuser absorbs short WL */
+ sd[2].v[0] *= 1.0; /* 400 */
+ }
+
+ if (ii == 3) { /* Projector */
+ sd[0].v[0] *= 0.1; /* 380 */
+ sd[1].v[0] *= 1.0; /* 390 */
+
+ sd[i].p[0] = 350.0; /* 350 */
+ sd[i].v[0] = 0.2 * sd[0].v[0];
+ sd[i++].w = 1.0;
+ }
+
+ glow[0] = m->wl_short2;
+ ghigh[0] = m->wl_long2;
+ gres[0] = m->nwav2;
+ avgdev[0] = 0.0;
+
+ trspl->fit_rspl_w(trspl, 0, sd, i, glow, ghigh, gres, vlow, vhigh, 0.5, avgdev, NULL);
+
+ if ((*ref2 = (double *)calloc(m->nwav2, sizeof(double))) == NULL) {
+ raw2wav->del(raw2wav);
+ trspl->del(trspl);
+ a1logd(p->log,1,"munki: malloc mtx_coef2 failed!\n");
+ return MUNKI_INT_MALLOC;
+ }
+
+ /* Create upsampled version */
+ for (i = 0; i < m->nwav2; i++) {
+ pp.p[0] = XSPECT_WL(m->wl_short2, m->wl_long2, m->nwav2, i);
+ trspl->interp(trspl, &pp);
+ if (pp.v[0] < 0.0)
+ pp.v[0] = 0.0;
+ (*ref2)[i] = pp.v[0];
+ }
+
+
+ /* Add some corrections at short wavelengths */
+ if (ii == 0) {
+ /* 376.67 - 470 */
+ double corr[5][29] = {
+ { 4.2413, 4.0654, 3.6425, 3.2194, 2.8692, 2.3964,
+ 1.9678, 1.3527, 0.7978, 0.7823, 0.8474, 0.9227,
+ 0.9833, 1.0164, 1.0270, 1.0241, 1.0157, 1.0096,
+ 1.0060, 1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0 },
+
+ };
+
+ for (i = 0; i < m->nwav2; i++) {
+ double wl;
+ int ix;
+ wl = XSPECT_WL(m->wl_short2, m->wl_long2, m->nwav2, i);
+ ix = XSPECT_IX(376.6666667, 470.0, 29, wl);
+
+ if (ix < 0)
+ ix = 0;
+ else if (ix >= 29)
+ ix = 28;
+ (*ref2)[i] *= corr[ii][ix];
+ }
+
+ }
+
+#ifdef HIGH_RES_PLOT
+ /* Plot original and upsampled reference */
+ {
+ double *x1 = dvectorz(0, m->nwav2-1);
+ double *y1 = dvectorz(0, m->nwav2-1);
+ double *y2 = dvectorz(0, m->nwav2-1);
+
+ for (i = 0; i < m->nwav2; i++) {
+ double wl = m->wl_short2 + (double)i * (m->wl_long2 - m->wl_short2)/(m->nwav2-1.0);
+ x1[i] = wl;
+ y1[i] = (*ref2)[i];
+ if (wl < m->wl_short1 || wl > m->wl_long1) {
+ y2[i] = 0.0;
+ } else {
+ double x, wl1, wl2;
+ for (j = 0; j < (m->nwav1-1); j++) {
+ wl1 = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, j);
+ wl2 = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, j+1);
+ if (wl >= wl1 && wl <= wl2)
+ break;
+ }
+ x = (wl - wl1)/(wl2 - wl1);
+ y2[i] = ref1[j] + (ref1[j+1] - ref1[j]) * x;
+ }
+ }
+ printf("Original and up-sampled ");
+ if (ii == 0) {
+ printf("Reflective cal. curve:\n");
+ } else if (ii == 1) {
+ printf("Emission cal. curve:\n");
+ } else if (ii == 2) {
+ printf("Ambient cal. curve:\n");
+ } else {
+ printf("Projector cal. curve:\n");
+ }
+ do_plot(x1, y1, y2, NULL, m->nwav2);
+
+ free_dvector(x1, 0, m->nwav2-1);
+ free_dvector(y1, 0, m->nwav2-1);
+ free_dvector(y2, 0, m->nwav2-1);
+ }
+#endif /* HIGH_RES_PLOT */
+ }
+ trspl->del(trspl);
+
+#ifdef SALONEINSTLIB
+ /* Then the 2D stray light using linear interpolation */
+ slp = dmatrix(0, m->nwav1-1, 0, m->nwav1-1);
+
+ /* Set scattered points */
+ for (i = 0; i < m->nwav1; i++) { /* Output wavelength */
+ for (j = 0; j < m->nwav1; j++) { /* Input wavelength */
+
+ slp[i][j] = m->straylight1[i][j];
+
+ /* Use interpolate/extrapolate for middle points */
+ if (j == (i-1) || j == i || j == (i+1)) {
+ int j0, j1;
+ double w0, w1;
+ if (j == (i-1)) {
+ if (j <= 0)
+ j0 = j+3, j1 = j+4;
+ else if (j >= (m->nwav1-3))
+ j0 = j-2, j1 = j-1;
+ else
+ j0 = j-1, j1 = j+3;
+ } else if (j == i) {
+ if (j <= 1)
+ j0 = j+2, j1 = j+3;
+ else if (j >= (m->nwav1-2))
+ j0 = j-3, j1 = j-2;
+ else
+ j0 = j-2, j1 = j+2;
+ } else if (j == (i+1)) {
+ if (j <= 2)
+ j0 = j+1, j1 = j+2;
+ else if (j >= (m->nwav1-1))
+ j0 = j-4, j1 = j-3;
+ else
+ j0 = j-3, j1 = j+1;
+ }
+ w1 = (j - j0)/(j1 - j0);
+ w0 = 1.0 - w1;
+ slp[i][j] = w0 * m->straylight1[i][j0]
+ + w1 * m->straylight1[i][j1];
+
+ }
+ }
+ }
+#else /* !SALONEINSTLIB */
+ /* Then setup 2D stray light using rspl */
+ if ((trspl = new_rspl(RSPL_NOFLAGS, 2, 1)) == NULL) {
+ a1logd(p->log,3,"munki: creating rspl for high res conversion failed\n");
+ raw2wav->del(raw2wav);
+ return MUNKI_INT_NEW_RSPL_FAILED;
+ }
+
+ /* Set scattered points */
+ for (i = 0; i < m->nwav1; i++) { /* Output wavelength */
+ for (j = 0; j < m->nwav1; j++) { /* Input wavelength */
+ int ix = i * m->nwav1 + j;
+
+ sd[ix].p[0] = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, i);
+ sd[ix].p[1] = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, j);
+ sd[ix].v[0] = m->straylight1[i][j];
+ sd[ix].w = 1.0;
+ if (j == (i-1) || j == i || j == (i+1))
+ sd[ix].w = 0.0;
+ }
+ }
+
+ glow[0] = m->wl_short2;
+ glow[1] = m->wl_short2;
+ ghigh[0] = m->wl_long2;
+ ghigh[1] = m->wl_long2;
+ gres[0] = m->nwav2;
+ gres[1] = m->nwav2;
+ avgdev[0] = 0.0;
+ avgdev[1] = 0.0;
+
+ trspl->fit_rspl_w(trspl, 0, sd, m->nwav1 * m->nwav1, glow, ghigh, gres, NULL, NULL, 0.5, avgdev, NULL);
+#endif /* !SALONEINSTLIB */
+
+ m->straylight2 = dmatrixz(0, m->nwav2-1, 0, m->nwav2-1);
+
+ /* Create upsampled version */
+ for (i = 0; i < m->nwav2; i++) { /* Output wavelength */
+ for (j = 0; j < m->nwav2; j++) { /* Input wavelength */
+ double p0, p1;
+ p0 = XSPECT_WL(m->wl_short2, m->wl_long2, m->nwav2, i);
+ p1 = XSPECT_WL(m->wl_short2, m->wl_long2, m->nwav2, j);
+#ifdef SALONEINSTLIB
+ /* Do linear interp with clipping at ends */
+ {
+ int x0, x1, y0, y1;
+ double xx, yy, w0, w1, v0, v1;
+
+ xx = (m->nwav1-1.0) * (p0 - m->wl_short1)/(m->wl_long1 - m->wl_short1);
+ x0 = (int)floor(xx);
+ if (x0 <= 0)
+ x0 = 0;
+ else if (x0 >= (m->nwav1-2))
+ x0 = m->nwav1-2;
+ x1 = x0 + 1;
+ w1 = xx - (double)x0;
+ w0 = 1.0 - w1;
+
+ yy = (m->nwav1-1.0) * (p1 - m->wl_short1)/(m->wl_long1 - m->wl_short1);
+ y0 = (int)floor(yy);
+ if (y0 <= 0)
+ y0 = 0;
+ else if (y0 >= (m->nwav1-2))
+ y0 = m->nwav1-2;
+ y1 = y0 + 1;
+ v1 = yy - (double)y0;
+ v0 = 1.0 - v1;
+
+ pp.v[0] = w0 * v0 * slp[x0][y0]
+ + w0 * v1 * slp[x0][y1]
+ + w1 * v0 * slp[x1][y0]
+ + w1 * v1 * slp[x1][y1];
+ }
+#else /* !SALONEINSTLIB */
+ pp.p[0] = p0;
+ pp.p[1] = p1;
+ trspl->interp(trspl, &pp);
+#endif /* !SALONEINSTLIB */
+ m->straylight2[i][j] = pp.v[0] * HIGHRES_WIDTH/10.0;
+ if (m->straylight2[i][j] > 0.0)
+ m->straylight2[i][j] = 0.0;
+ }
+ }
+
+ /* Fix primary wavelength weight and neighbors */
+ for (i = 0; i < m->nwav2; i++) { /* Output wavelength */
+ double sum;
+
+ if (i > 0)
+ m->straylight2[i][i-1] = 0.0;
+ m->straylight2[i][i] = 0.0;
+ if (i < (m->nwav2-1))
+ m->straylight2[i][i+1] = 0.0;
+
+ for (sum = 0.0, j = 0; j < m->nwav2; j++)
+ sum += m->straylight2[i][j];
+
+ m->straylight2[i][i] = 1.0 - sum; /* Total sum should be 1.0 */
+ }
+
+#ifdef HIGH_RES_PLOT_STRAYL
+ /* Plot original and upsampled reference */
+ {
+ double *x1 = dvectorz(0, m->nwav2-1);
+ double *y1 = dvectorz(0, m->nwav2-1);
+ double *y2 = dvectorz(0, m->nwav2-1);
+
+ for (i = 0; i < m->nwav2; i++) { /* Output wavelength */
+ double wli = XSPECT_WL(m->wl_short2, m->wl_long2, m->nwav2, i);
+ int i1 = XSPECT_IX(m->wl_short1, m->wl_long1, m->nwav1, wli);
+
+ for (j = 0; j < m->nwav2; j++) {
+ double wl = XSPECT_WL(m->wl_short2, m->wl_long2, m->nwav2, j);
+ x1[j] = wl;
+ y1[j] = m->straylight2[i][j];
+ if (y1[j] == 0.0)
+ y1[j] = -8.0;
+ else
+ y1[j] = log10(fabs(y1[j]));
+ if (wli < m->wl_short1 || wli > m->wl_long1
+ || wl < m->wl_short1 || wl > m->wl_long1) {
+ y2[j] = -8.0;
+ } else {
+ double x, wl1, wl2;
+ for (k = 0; k < (m->nwav1-1); k++) {
+ wl1 = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, k);
+ wl2 = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, k+1);
+ if (wl >= wl1 && wl <= wl2)
+ break;
+ }
+ x = (wl - wl1)/(wl2 - wl1);
+ y2[j] = m->straylight1[i1][k] + (m->straylight1[i1][k+1]
+ - m->straylight1[i1][k]) * x;
+ if (y2[j] == 0.0)
+ y2[j] = -8.0;
+ else
+ y2[j] = log10(fabs(y2[j]));
+ }
+ }
+ do_plot(x1, y1, y2, NULL, m->nwav2);
+ }
+
+ free_dvector(x1, 0, m->nwav2-1);
+ free_dvector(y1, 0, m->nwav2-1);
+ free_dvector(y2, 0, m->nwav2-1);
+ }
+#endif /* HIGH_RES_PLOT */
+
+#ifdef SALONEINSTLIB
+ free_dmatrix(slp, 0, m->nwav1-1, 0, m->nwav1-1);
+#else /* !SALONEINSTLIB */
+ trspl->del(trspl);
+#endif /* !SALONEINSTLIB */
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /* Allocate space for per mode calibration reference */
+ /* and bring high res calibration factors into line */
+ /* with current standard res. ones */
+ for (i = 0; i < mk_no_modes; i++) {
+ munki_state *s = &m->ms[i];
+
+ s->cal_factor2 = dvectorz(0, m->nwav2-1);
+
+ switch(i) {
+ case mk_refl_spot:
+ case mk_refl_scan:
+ if (s->cal_valid) {
+ munki_absraw_to_abswav1(p, 1, &s->cal_factor1, &s->white_data);
+ munki_absraw_to_abswav2(p, 1, &s->cal_factor2, &s->white_data);
+ munki_compute_white_cal(p, s->cal_factor1, m->white_ref1, s->cal_factor1,
+ s->cal_factor2, m->white_ref2, s->cal_factor2);
+ }
+ break;
+
+ case mk_emiss_spot_na:
+ case mk_emiss_spot:
+ case mk_emiss_scan:
+ for (j = 0; j < m->nwav2; j++)
+ s->cal_factor2[j] = EMIS_SCALE_FACTOR * m->emis_coef2[j];
+ break;
+
+ case mk_tele_spot_na:
+ case mk_tele_spot:
+ for (j = 0; j < m->nwav2; j++)
+ s->cal_factor2[j] = EMIS_SCALE_FACTOR * m->proj_coef2[j];
+ break;
+
+ case mk_amb_spot:
+ case mk_amb_flash:
+ if (m->amb_coef1 != NULL) {
+ for (j = 0; j < m->nwav2; j++)
+ s->cal_factor2[j] = AMB_SCALE_FACTOR * m->amb_coef2[j];
+ s->cal_valid = 1;
+ }
+ break;
+ case mk_trans_spot:
+ case mk_trans_scan:
+ if (s->cal_valid) {
+ munki_absraw_to_abswav1(p, 1, &s->cal_factor1, &s->white_data);
+ munki_absraw_to_abswav2(p, 1, &s->cal_factor2, &s->white_data);
+ munki_compute_white_cal(p, s->cal_factor1, NULL, s->cal_factor1,
+ s->cal_factor2, NULL, s->cal_factor2);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ raw2wav->del(raw2wav);
+
+ return ev;
+}
+
+#endif /* HIGH_RES */
+
+
+/* return nz if high res is supported */
+int munki_imp_highres(munki *p) {
+#ifdef HIGH_RES
+ return 1;
+#else
+ return 0;
+#endif /* HIGH_RES */
+}
+
+/* Set to high resolution mode */
+munki_code munki_set_highres(munki *p) {
+ int i;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code ev = MUNKI_OK;
+
+#ifdef HIGH_RES
+ if (m->hr_inited == 0) {
+ if ((ev = munki_create_hr(p, 1)) != MUNKI_OK) /* Reflective */
+ return ev;
+ if ((ev = munki_create_hr(p, 0)) != MUNKI_OK) /* Emissive */
+ return ev;
+ }
+
+ m->nwav = m->nwav2;
+ m->wl_short = m->wl_short2;
+ m->wl_long = m->wl_long2;
+
+ m->rmtx_index = m->rmtx_index2;
+ m->rmtx_nocoef = m->rmtx_nocoef2;
+ m->rmtx_coef = m->rmtx_coef2;
+ m->emtx_index = m->emtx_index2;
+ m->emtx_nocoef = m->emtx_nocoef2;
+ m->emtx_coef = m->emtx_coef2;
+ m->white_ref = m->white_ref2;
+ m->emis_coef = m->emis_coef2;
+ m->amb_coef = m->amb_coef2;
+ m->proj_coef = m->proj_coef2;
+ m->straylight = m->straylight2;
+
+ for (i = 0; i < mk_no_modes; i++) {
+ munki_state *s = &m->ms[i];
+ s->cal_factor = s->cal_factor2;
+ }
+ m->highres = 1;
+#else
+ ev = MUNKI_UNSUPPORTED;
+#endif /* HIGH_RES */
+
+ return ev;
+}
+
+/* Set to standard resolution mode */
+munki_code munki_set_stdres(munki *p) {
+ int i;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code ev = MUNKI_OK;
+
+#ifdef HIGH_RES
+ m->nwav = m->nwav1;
+ m->wl_short = m->wl_short1;
+ m->wl_long = m->wl_long1;
+
+ m->rmtx_index = m->rmtx_index1;
+ m->rmtx_nocoef = m->rmtx_nocoef1;
+ m->rmtx_coef = m->rmtx_coef1;
+ m->emtx_index = m->emtx_index1;
+ m->emtx_nocoef = m->emtx_nocoef1;
+ m->emtx_coef = m->emtx_coef1;
+ m->white_ref = m->white_ref1;
+ m->emis_coef = m->emis_coef1;
+ m->amb_coef = m->amb_coef1;
+ m->proj_coef = m->proj_coef1;
+ m->straylight = m->straylight1;
+
+ for (i = 0; i < mk_no_modes; i++) {
+ munki_state *s = &m->ms[i];
+ s->cal_factor = s->cal_factor1;
+ }
+ m->highres = 0;
+
+#else
+ ev = MUNKI_UNSUPPORTED;
+#endif /* HIGH_RES */
+
+ return ev;
+}
+
+/* Modify the scan consistency tolerance */
+munki_code munki_set_scan_toll(munki *p, double toll_ratio) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code ev = MUNKI_OK;
+
+ m->scan_toll_ratio = toll_ratio;
+
+ return MUNKI_OK;
+}
+
+/* Optical adjustment weights */
+static double opt_adj_weights[21] = {
+ 1.4944496665144658e-282, 2.0036175483913455e-070, 1.2554893022685038e+232,
+ 2.3898157055642966e+190, 1.5697625128432372e-076, 6.6912978722191457e+281,
+ 1.2369092402930559e+277, 1.4430907501246712e-153, 3.0017439193018232e+238,
+ 1.2978311824382444e+161, 5.5068703318775818e-311, 7.7791723264455314e-260,
+ 6.4560484084110176e+170, 8.9481529920968425e+165, 1.3565405878488529e-153,
+ 2.0835868791190880e-076, 5.4310198502711138e+241, 4.8689849775675438e+275,
+ 9.2709981544886391e+122, 3.7958270103353899e-153, 7.1366083837501666e-154
+};
+
+/* Convert from spectral to XYZ, and transfer to the ipatch array */
+munki_code munki_conv2XYZ(
+ munki *p,
+ ipatch *vals, /* Values to return */
+ int nvals, /* Number of values */
+ double **specrd, /* Spectral readings */
+ instClamping clamp /* Clamp XYZ/Lab to be +ve */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ xsp2cie *conv; /* Spectral to XYZ conversion object */
+ int i, j, k;
+ int six = 0; /* Starting index */
+ int nwl = m->nwav; /* Number of wavelegths */
+ double wl_short = m->wl_short; /* Starting wavelegth */
+ double sms; /* Weighting */
+
+ if (s->emiss)
+ conv = new_xsp2cie(icxIT_none, NULL, icxOT_CIE_1931_2, NULL, icSigXYZData, (icxClamping)clamp);
+ else
+ conv = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2, NULL, icSigXYZData, (icxClamping)clamp);
+ if (conv == NULL)
+ return MUNKI_INT_CIECONVFAIL;
+
+ /* Don't report any wavelengths below the minimum for this mode */
+ if ((s->min_wl-1e-3) > wl_short) {
+ double wl;
+ for (j = 0; j < m->nwav; j++) {
+ wl = XSPECT_WL(m->wl_short, m->wl_long, m->nwav, j);
+ if (wl >= (s->min_wl-1e-3))
+ break;
+ }
+ six = j;
+ wl_short = wl;
+ nwl -= six;
+ }
+
+ a1logd(p->log,3,"munki_conv2XYZ got wl_short %f, wl_long %f, nwav %d, min_wl %f\n"
+ " after skip got wl_short %f, nwl = %d\n",
+ m->wl_short, m->wl_long, m->nwav, s->min_wl, wl_short, nwl);
+
+ for (sms = 0.0, i = 1; i < 21; i++)
+ sms += opt_adj_weights[i];
+ sms *= opt_adj_weights[0];
+
+ for (i = 0; i < nvals; i++) {
+
+ vals[i].loc[0] = '\000';
+ vals[i].mtype = inst_mrt_none;
+ vals[i].XYZ_v = 0;
+ vals[i].sp.spec_n = 0;
+ vals[i].duration = 0.0;
+
+ vals[i].sp.spec_n = nwl;
+ vals[i].sp.spec_wl_short = wl_short;
+ vals[i].sp.spec_wl_long = m->wl_long;
+
+ if (s->emiss) {
+ for (j = six, k = 0; j < m->nwav; j++, k++) {
+ vals[i].sp.spec[k] = specrd[i][j] * sms;
+ }
+ vals[i].sp.norm = 1.0;
+
+ /* Set the XYZ */
+ conv->convert(conv, vals[i].XYZ, &vals[i].sp);
+ vals[i].XYZ_v = 1;
+
+ if (s->ambient) {
+ if (s->flash)
+ vals[i].mtype = inst_mrt_ambient_flash;
+ else
+ vals[i].mtype = inst_mrt_ambient;
+ } else {
+ if (s->flash)
+ vals[i].mtype = inst_mrt_emission_flash;
+ else
+ vals[i].mtype = inst_mrt_emission;
+ }
+
+ } else {
+ for (j = six, k = 0; j < m->nwav; j++, k++) {
+ vals[i].sp.spec[k] = 100.0 * specrd[i][j] * sms;
+ }
+ vals[i].sp.norm = 100.0;
+
+ /* Set the XYZ */
+ conv->convert(conv, vals[i].XYZ, &vals[i].sp);
+ vals[i].XYZ_v = 1;
+ vals[i].XYZ[0] *= 100.0;
+ vals[i].XYZ[1] *= 100.0;
+ vals[i].XYZ[2] *= 100.0;
+
+ if (s->trans)
+ vals[i].mtype = inst_mrt_transmissive;
+ else
+ vals[i].mtype = inst_mrt_reflective;
+ }
+
+ /* Don't return spectral if not asked for */
+ if (!m->spec_en) {
+ vals[i].sp.spec_n = 0;
+ }
+ }
+
+ conv->del(conv);
+ return MUNKI_OK;
+}
+
+/* Compute a mode calibration factor given the reading of the white reference. */
+/* Return 1 if any of the transmission wavelengths are low. */
+int munki_compute_white_cal(
+ munki *p,
+ double *cal_factor1, /* [nwav1] Calibration factor to compute */
+ double *white_ref1, /* [nwav1] White reference to aim for, NULL for 1.0 */
+ double *white_read1, /* [nwav1] The white that was read */
+ double *cal_factor2, /* [nwav2] Calibration factor to compute */
+ double *white_ref2, /* [nwav2] White reference to aim for, NULL for 1.0 */
+ double *white_read2 /* [nwav2] The white that was read */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ int j, warn = 0;
+
+ a1logd(p->log,3,"munki_compute_white_cal called\n");
+
+ if (white_ref1 == NULL) { /* transmission white reference */
+ double avgwh = 0.0;
+
+ /* Compute average white reference reading */
+ for (j = 0; j < m->nwav1; j++)
+ avgwh += white_read1[j];
+ avgwh /= (double)m->nwav1;
+
+ /* For each wavelength */
+ for (j = 0; j < m->nwav1; j++) {
+ /* If reference is < 0.4% of average */
+ if (white_read1[j]/avgwh < 0.004) {
+ cal_factor1[j] = 1.0/(0.004 * avgwh);
+ warn = 1;
+ } else {
+ cal_factor1[j] = 1.0/white_read1[j];
+ }
+ }
+
+ } else { /* Reflection white reference */
+
+ /* For each wavelength */
+ for (j = 0; j < m->nwav1; j++) {
+ if (white_read1[j] < 1000.0)
+ cal_factor1[j] = white_ref1[j]/1000.0;
+ else
+ cal_factor1[j] = white_ref1[j]/white_read1[j];
+ }
+ }
+
+#ifdef HIGH_RES
+ if (m->hr_inited == 0)
+ return warn;
+
+ if (white_ref2 == NULL) { /* transmission white reference */
+ double avgwh = 0.0;
+
+ /* Compute average white reference reading */
+ for (j = 0; j < m->nwav2; j++)
+ avgwh += white_read2[j];
+ avgwh /= (double)m->nwav2;
+
+ /* For each wavelength */
+ for (j = 0; j < m->nwav2; j++) {
+ /* If reference is < 0.4% of average */
+ if (white_read2[j]/avgwh < 0.004) {
+ cal_factor2[j] = 1.0/(0.004 * avgwh);
+ warn = 1;
+ } else {
+ cal_factor2[j] = 1.0/white_read2[j];
+ }
+ }
+
+ } else { /* Reflection white reference */
+
+ /* For each wavelength */
+ for (j = 0; j < m->nwav2; j++) {
+ if (white_read2[j] < 1000.0)
+ cal_factor2[j] = white_ref2[j]/1000.0;
+ else
+ cal_factor2[j] = white_ref2[j]/white_read2[j];
+ }
+ }
+#endif /* HIGH_RES */
+ return warn;
+}
+
+/* For adaptive mode, compute a new integration time and gain mode */
+/* in order to optimise the sensor values. */
+munki_code munki_optimise_sensor(
+ munki *p,
+ double *pnew_int_time,
+ int *pnew_gain_mode,
+ double cur_int_time, /* Current intergration time */
+ int cur_gain_mode, /* nz if currently high gain */
+ int permithg, /* nz to permit switching to high gain mode */
+ int permitclip, /* nz to permit clipping out of range int_time, else error */
+ double *targoscale, /* Optimising target scale ( <= 1.0) */
+ /* (May be altered if integration time isn't possible) */
+ double scale, /* scale needed of current int time to reach optimum */
+ double deadtime /* Dead integration time (if any) */
+) {
+ munki_code ev = MUNKI_OK;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ double new_int_time;
+ double min_int_time; /* Adjusted min_int_time */
+ int new_gain_mode;
+
+ a1logd(p->log,3,"munki_optimise_sensor called, inttime %f, gain mode %d, scale %f\n",cur_int_time,cur_gain_mode, scale);
+
+ min_int_time = m->min_int_time - deadtime;
+ cur_int_time -= deadtime;
+
+ /* Compute new normal gain integration time */
+ if (cur_gain_mode)
+ new_int_time = cur_int_time * scale * m->highgain;
+ else
+ new_int_time = cur_int_time * scale;
+ new_gain_mode = 0;
+
+ a1logd(p->log,3,"target inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ /* Adjust to low light situation by increasing the integration time. */
+ if (new_int_time > s->targmaxitime) { /* Exceeding target integration time */
+ if (s->targmaxitime/new_int_time > s->targoscale2) { /* But within range */
+ /* Compromise sensor target value to maintain targmaxitime */
+ new_int_time = s->targmaxitime;
+ a1logd(p->log,3,"Using targmaxitime with compromise sensor target\n");
+ } else {
+ /* Target reduced sensor value to give improved measurement time and continuity */
+ new_int_time *= s->targoscale2;
+ a1logd(p->log,3,"Using compromse sensor target\n");
+ }
+#ifdef USE_HIGH_GAIN_MODE
+ /* Hmm. It may not be a good idea to use high gain mode if it compromises */
+ /* the longer integration time which reduces noise. */
+ if (new_int_time > m->max_int_time && permithg) {
+ new_int_time /= m->highgain;
+ new_gain_mode = 1;
+ a1logd(p->log,3,"Switching to high gain mode\n");
+ }
+#endif
+ }
+ a1logd(p->log,3,"after low light adjust, inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ /* Deal with still low light */
+ if (new_int_time > m->max_int_time) {
+ if (permitclip)
+ new_int_time = m->max_int_time;
+ else
+ return MUNKI_RD_LIGHTTOOLOW;
+ }
+ a1logd(p->log,3,"after low light clip, inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ /* Adjust to high light situation */
+ if (new_int_time < min_int_time && *targoscale < 1.0) {
+ *targoscale *= min_int_time/new_int_time;
+ new_int_time = min_int_time;
+ }
+ a1logd(p->log,3,"after high light adjust, targoscale %f, inttime %f, gain mode %d\n",*targoscale, new_int_time,new_gain_mode);
+
+ /* Deal with still high light */
+ if (new_int_time < min_int_time) {
+ if (permitclip)
+ new_int_time = min_int_time;
+ else
+ return MUNKI_RD_LIGHTTOOHIGH;
+ }
+ a1logd(p->log,3,"after high light clip, returning inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+
+ new_int_time += deadtime;
+
+ a1logd(p->log,3,"munki_optimise_sensor returning inttime %f, gain mode %d\n",new_int_time,new_gain_mode);
+ if (pnew_int_time != NULL)
+ *pnew_int_time = new_int_time;
+
+ if (pnew_gain_mode != NULL)
+ *pnew_gain_mode = new_gain_mode;
+
+ return MUNKI_OK;
+}
+
+/* Compute the number of measurements needed, given the target */
+/* time and integration time. Will return 0 if target time is 0 */
+int munki_comp_nummeas(
+ munki *p,
+ double meas_time,
+ double int_time
+) {
+ int nmeas;
+ if (meas_time <= 0.0)
+ return 0;
+ nmeas = (int)floor(meas_time/int_time + 0.5);
+ if (nmeas < 1)
+ nmeas = 1;
+ return nmeas;
+}
+
+/* Compute the rounded up number of measurements needed, */
+/* given the target time and integration time. */
+/* Will return 0 if target time is 0 */
+int munki_comp_ru_nummeas(
+ munki *p,
+ double meas_time,
+ double int_time
+) {
+ int nmeas;
+ if (meas_time <= 0.0)
+ return 0;
+ nmeas = (int)ceil(meas_time/int_time);
+ return nmeas;
+}
+
+/* Convert the dark interpolation data to a useful state */
+/* (also allow for interpolating the shielded cell values) */
+void
+munki_prepare_idark(
+ munki *p
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ int i, j;
+
+ /* For normal and high gain */
+ for (i = 0; i < 4; i+=2) {
+ for (j = -1; j < m->nraw; j++) {
+ double d01, d1;
+ d01 = s->idark_data[i+0][j];
+ d1 = s->idark_data[i+1][j];
+
+ /* Compute increment proportional to time */
+ s->idark_data[i+1][j] = (d1 - d01)/(s->idark_int_time[i+1] - s->idark_int_time[i+0]);
+
+ /* Compute base */
+ s->idark_data[i+0][j] = d01 - s->idark_data[i+1][j] * s->idark_int_time[i+0];;
+ }
+ }
+}
+
+/* Create the dark reference for the given integration time and gain */
+/* by interpolating from the 4 readings prepared earlier */
+munki_code
+munki_interp_dark(
+ munki *p,
+ double *result, /* Put result of interpolation here */
+ double inttime,
+ int gainmode
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ munki_state *s = &m->ms[m->mmode];
+ int i, j;
+
+ if (!s->idark_valid)
+ return MUNKI_INT_NOTCALIBRATED;
+
+ i = 0;
+#ifdef USE_HIGH_GAIN_MODE
+ if (gainmode)
+ i = 2;
+#endif
+
+ for (j = -1; j < m->nraw; j++) {
+ double tt;
+ tt = s->idark_data[i+0][j] + inttime * s->idark_data[i+1][j];
+ result[j] = tt;
+ }
+ return MUNKI_OK;
+}
+
+/* Set the noinitcalib mode */
+void munki_set_noinitcalib(munki *p, int v, int losecs) {
+ munkiimp *m = (munkiimp *)p->m;
+ /* Ignore disabling init calib if more than losecs since instrument was open */
+a1logd(p->log,3,"set_noinitcalib v = %d, ->lo_secs %d, losecs %d secs\n",v, m->lo_secs,losecs);
+ if (v && losecs != 0 && m->lo_secs >= losecs) {
+ a1logd(p->log,3,"initcalib disable ignored because %d >= %d secs\n",m->lo_secs,losecs);
+ return;
+ }
+ m->noinitcalib = v;
+}
+
+/* Set the trigger config */
+void munki_set_trig(munki *p, inst_opt_type trig) {
+ munkiimp *m = (munkiimp *)p->m;
+ m->trig = trig;
+}
+
+/* Return the trigger config */
+inst_opt_type munki_get_trig(munki *p) {
+ munkiimp *m = (munkiimp *)p->m;
+ return m->trig;
+}
+
+/* Switch thread handler */
+int munki_switch_thread(void *pp) {
+ int nfailed = 0;
+ munki *p = (munki *)pp;
+ munkiimp *m = (munkiimp *)p->m;
+ munki_code rv = MUNKI_OK;
+ a1logd(p->log,3,"Switch thread started\n");
+ for (nfailed = 0;nfailed < 5;) {
+ mk_eve ecode;
+
+ rv = munki_waitfor_switch_th(p, &ecode, NULL, SW_THREAD_TIMEOUT);
+ if (m->th_term) {
+ m->th_termed = 1;
+ break;
+ }
+ if (rv == MUNKI_INT_BUTTONTIMEOUT) {
+ nfailed = 0;
+ continue;
+ }
+ if (rv != MUNKI_OK) {
+ nfailed++;
+ a1logd(p->log,3,"Switch thread failed with 0x%x\n",rv);
+ continue;
+ }
+ if (ecode == mk_eve_switch_press) {
+ m->switch_count++;
+ if (!m->hide_switch && p->eventcallback != NULL) {
+ p->eventcallback(p->event_cntx, inst_event_switch);
+ }
+ } else if (ecode == mk_eve_spos_change) {
+ if (p->eventcallback != NULL) {
+ p->eventcallback(p->event_cntx, inst_event_mconf);
+ }
+ }
+ }
+ a1logd(p->log,3,"Switch thread returning\n");
+ return rv;
+}
+
+/* ============================================================ */
+/* Low level commands */
+
+/* USB Instrument commands */
+
+/* Read from the EEProm */
+munki_code
+munki_readEEProm(
+ munki *p,
+ unsigned char *buf, /* Where to read it to */
+ int addr, /* Address in EEprom to read from */
+ int size /* Number of bytes to read (max 65535) */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ int rwbytes; /* Data bytes read or written */
+ unsigned char pbuf[8]; /* Write EEprom parameters */
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_readEEProm: address 0x%x size 0x%x\n",addr,size);
+
+ if (size < 0 || addr < 0 || (addr + size) > (m->noeeblocks * m->eeblocksize))
+ return MUNKI_INT_EEOUTOFRANGE;
+
+ int2buf(&pbuf[0], addr);
+ int2buf(&pbuf[4], size);
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x81, 0, 0, pbuf, 8, 2.0);
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_readEEProm: read failed (1) with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ /* Now read the bytes */
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf, size, &rwbytes, 5.0);
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_readEEProm: read failed (2) with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ if (rwbytes != size) {
+ a1logd(p->log,1,"munki_readEEProm: 0x%x bytes, short read error\n",rwbytes);
+ return MUNKI_HW_EE_SHORTREAD;
+ }
+
+ if (p->log->debug >= 5) {
+ int i;
+ char oline[100] = { '\000' }, *bp = oline;
+ for (i = 0; i < size; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp," %04x:",i);
+ bp += sprintf(bp," %02x",buf[i]);
+ if ((i+1) >= size || ((i+1) % 16) == 0) {
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,5,oline);
+ bp = oline;
+ }
+ }
+ }
+
+ a1logd(p->log,2,"munki_readEEProm: got 0x%x bytes, ICOM err 0x%x\n",rwbytes, se);
+
+ return rv;
+}
+
+
+
+/* Get the firmware parameters */
+/* return pointers may be NULL if not needed. */
+munki_code
+munki_getfirm(
+ munki *p,
+ int *fwrev, /* Return the formware version number as 8.8 */
+ int *tickdur, /* Tick duration */
+ int *minintcount, /* Minimum integration tick count */
+ int *noeeblocks, /* Number of EEPROM blocks */
+ int *eeblocksize /* Size of each block */
+) {
+ unsigned char pbuf[24]; /* status bytes read */
+ int _fwrev_maj, _fwrev_min;
+ int _tickdur;
+ int _minintcount;
+ int _noeeblocks;
+ int _eeblocksize;
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_getfirm:\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x86, 0, 0, pbuf, 24, 2.0);
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_getfirm: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _fwrev_maj = buf2int(&pbuf[0]);
+ _fwrev_min = buf2int(&pbuf[4]);
+ _tickdur = buf2int(&pbuf[8]);
+ _minintcount = buf2int(&pbuf[12]);
+ _noeeblocks = buf2int(&pbuf[16]);
+ _eeblocksize = buf2int(&pbuf[20]);
+
+ a1logd(p->log,2,"munki_getfirm: returning fwrev %d.%d, tickdur %d, minint %d, eeblks %d, "
+ "eeblksz %d ICOM err 0x%x\n", _fwrev_maj, _fwrev_min, _tickdur, _minintcount,
+ _noeeblocks, _eeblocksize, se);
+
+ if (fwrev != NULL) *fwrev = _fwrev_maj * 256 + _fwrev_min ;
+ if (tickdur != NULL) *tickdur = _tickdur;
+ if (minintcount != NULL) *minintcount = _minintcount;
+ if (noeeblocks != NULL) *noeeblocks = _noeeblocks;
+ if (eeblocksize != NULL) *eeblocksize = _eeblocksize;
+
+ return rv;
+}
+
+/* Get the Chip ID */
+munki_code
+munki_getchipid(
+ munki *p,
+ unsigned char chipid[8]
+) {
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_getchipid: called\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x8A, 0, 0, chipid, 8, 2.0);
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_getchipid: GetChipID failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ a1logd(p->log,2," GetChipID returns %02X-%02X%02X%02X%02X%02X%02X%02X ICOM err 0x%x\n",
+ chipid[0], chipid[1], chipid[2], chipid[3],
+ chipid[4], chipid[5], chipid[6], chipid[7], se);
+ return rv;
+}
+
+/* Get the Version String */
+munki_code
+munki_getversionstring(
+ munki *p,
+ char vstring[37]
+) {
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_getversionstring: called\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x85, 0, 0, (unsigned char *)vstring, 36, 2.0);
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_getversionstring: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ vstring[36] = '\000';
+
+ a1logd(p->log,2,"munki_getversionstring: returning '%s' ICOM err 0x%x\n", vstring, se);
+
+ return rv;
+}
+
+/* Get the measurement state */
+/* return pointers may be NULL if not needed. */
+munki_code
+munki_getmeasstate(
+ munki *p,
+ int *ledtrange, /* LED temperature range */
+ int *ledtemp, /* LED temperature */
+ int *dutycycle, /* Duty Cycle */
+ int *ADfeedback /* A/D converter feedback */
+) {
+ unsigned char pbuf[16]; /* values read */
+ int _ledtrange;
+ int _ledtemp;
+ int _dutycycle;
+ int _ADfeedback;
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_getmeasstate: called\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x8F, 0, 0, pbuf, 16, 2.0);
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_getmeasstate: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _ledtrange = buf2int(&pbuf[0]);
+ _ledtemp = buf2int(&pbuf[4]);
+ _dutycycle = buf2int(&pbuf[8]);
+ _ADfeedback = buf2int(&pbuf[12]);
+
+ a1logd(p->log,2,"munki_getmeasstate: returning LED temp range %d, LED temp %d, "
+ "Duty Cycle %d, ADFeefback %d, ICOM err 0x%x\n",
+ _ledtrange, _ledtemp, _dutycycle, _ADfeedback, se);
+
+ if (ledtrange != NULL) *ledtrange = _ledtrange;
+ if (ledtemp != NULL) *ledtemp = _ledtemp;
+ if (dutycycle != NULL) *dutycycle = _dutycycle;
+ if (ADfeedback != NULL) *ADfeedback = _ADfeedback;
+
+ return rv;
+}
+
+/* Get the device status */
+/* return pointers may be NULL if not needed. */
+munki_code
+munki_getstatus(
+ munki *p,
+ mk_spos *spos, /* Return the sensor position */
+ mk_but *but /* Return Button state */
+) {
+ unsigned char pbuf[2]; /* status bytes read */
+ mk_spos _spos;
+ mk_but _but;
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_getstatus: called\n");
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x87, 0, 0, pbuf, 2, 2.0);
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_getstatus: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ _spos = (mk_spos)pbuf[0];
+ _but = (mk_but)pbuf[1];
+
+ if (p->log->debug >= 3) {
+ char sb1[50], sb2[50];
+ if (_spos == mk_spos_proj)
+ strcpy(sb1, "Projector");
+ else if (_spos == mk_spos_surf)
+ strcpy(sb1, "Surface");
+ else if (_spos == mk_spos_calib)
+ strcpy(sb1, "Calibration");
+ else if (_spos == mk_spos_amb)
+ strcpy(sb1, "Ambient");
+ else
+ sprintf(sb1,"Unknown 0x%x",_spos);
+ if (_but == mk_but_switch_release)
+ strcpy(sb2, "Released");
+ else if (_but == mk_but_switch_press)
+ strcpy(sb2, "Pressed");
+ else
+ sprintf(sb2,"Unknown 0x%x",_but);
+
+ a1logd(p->log,3,"munki_getstatus: Sensor pos. %s, Button state %s, ICOM err 0x%x\n",
+ sb1, sb2, se);
+ }
+
+ if (spos != NULL) *spos = _spos;
+ if (but != NULL) *but = _but;
+
+ return rv;
+}
+
+/* Set the indicator LED state (advanced) */
+/* NOTE that the instrument seems to turn it off */
+/* whenever any other sort of operation occurs. */
+munki_code
+munki_setindled(
+ munki *p,
+ int p1, /* On time (msec) */
+ int p2, /* Off time (msec) */
+ int p3, /* Transition time (msec) */
+ int p4, /* Number of pulses, -1 = max */
+ int p5 /* Ignored ? */
+) {
+ unsigned char pbuf[20]; /* command bytes written */
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_setindled: %d, %d, %d, %d, %d\n",
+ p1, p2, p3, p4, p5);
+
+ int2buf(&pbuf[0], p1); /* On time (msec) */
+ int2buf(&pbuf[4], p2); /* Off time (msec) */
+ int2buf(&pbuf[8], p3); /* Transition time (msec) */
+ int2buf(&pbuf[12], p4); /* Number of pulses, -1 = max */
+ int2buf(&pbuf[16], p5); /* Unknown */
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x92, 0, 0, pbuf, 20, 2.0);
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_setindled: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ a1logd(p->log,2,"munki_setindled: OK ICOM err 0x%x\n",se);
+
+ return rv;
+}
+
+/* Trigger a measurement with the given measurement parameters */
+munki_code
+munki_triggermeasure(
+ munki *p,
+ int intclocks, /* Number of integration clocks */
+ int nummeas, /* Number of measurements to make */
+ int measmodeflags, /* Measurement mode flags */
+ int holdtempduty /* Hold temperature duty cycle */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ unsigned char pbuf[12]; /* command bytes written */
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_triggermeasure: lamp %d, scan %d, gain %d, intclks %d, nummeas %d\n",
+ (measmodeflags & MUNKI_MMF_LAMP) ? 1 : 0,
+ (measmodeflags & MUNKI_MMF_SCAN) ? 1 : 0,
+ (measmodeflags & MUNKI_MMF_HIGHGAIN) ? 1 : 0,
+ intclocks, nummeas);
+
+ pbuf[0] = (measmodeflags & MUNKI_MMF_LAMP) ? 1 : 0;
+ pbuf[1] = (measmodeflags & MUNKI_MMF_SCAN) ? 1 : 0;
+ pbuf[2] = (measmodeflags & MUNKI_MMF_HIGHGAIN) ? 1 : 0;
+ pbuf[3] = holdtempduty;
+ int2buf(&pbuf[4], intclocks);
+ int2buf(&pbuf[8], nummeas);
+
+ m->tr_t1 = m->tr_t2 = m->tr_t3 = m->tr_t4 = m->tr_t5 = m->tr_t6 = m->tr_t7 = 0;
+ m->tr_t1 = msec_time(); /* Diagnostic */
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x80, 0, 0, pbuf, 12, 2.0);
+
+ m->tr_t2 = msec_time(); /* Diagnostic */
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,1,"munki_triggermeasure: failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ a1logd(p->log,2,"munki_triggermeasure: OK ICOM err 0x%x\n",se);
+
+ return rv;
+}
+
+/* Read a measurements results. */
+/* A buffer full of bytes is returned. */
+munki_code
+munki_readmeasurement(
+ munki *p,
+ int inummeas, /* Initial number of measurements to expect */
+ int scanflag, /* NZ if in scan mode to continue reading */
+ unsigned char *buf, /* Where to read it to */
+ int bsize, /* Bytes available in buffer */
+ int *nummeas, /* Return number of readings measured */
+ int calib_measure, /* flag - nz if this is a calibration measurement */
+ int dark_measure /* flag - nz if this is a dark measurement */
+) {
+ munkiimp *m = (munkiimp *)p->m;
+ unsigned char *ibuf = buf; /* Incoming buffer */
+ int nmeas; /* Number of measurements for this read */
+ double top, extra; /* Time out period */
+ int rwbytes; /* Data bytes read or written */
+ int se, rv = MUNKI_OK;
+ int treadings = 0;
+// int gotshort = 0; /* nz when got a previous short reading */
+
+ if ((bsize % (m->nsen * 2)) != 0) {
+ a1logd(p->log,1,"munki_readmeasurement: got %d bytes, nsen = %d\n",bsize,m->nsen);
+ return MUNKI_INT_ODDREADBUF;
+ }
+
+ extra = 1.0; /* Extra timeout margin */
+
+#ifdef SINGLE_READ
+ if (scanflag == 0)
+ nmeas = inummeas;
+ else
+ nmeas = bsize / (m->nsen * 2); /* Use a single large read */
+#else
+ nmeas = inummeas; /* Smaller initial number of measurements */
+#endif
+
+ top = extra + m->c_inttime * nmeas;
+
+ a1logd(p->log,2,"munki_readmeasurement: inummeas %d, scanflag %d, address %p bsize 0x%x, timout %f\n",inummeas, scanflag, buf, bsize, top);
+
+ for (;;) {
+ int size; /* number of bytes to read */
+
+ size = (m->nsen * 2) * nmeas;
+
+ if (size > bsize) { /* oops, no room for read */
+ a1logd(p->log,1,"munki_readmeasurement: Buffer was too short for scan\n");
+ return MUNKI_INT_MEASBUFFTOOSMALL;
+ }
+
+ m->tr_t6 = msec_time(); /* Diagnostic, start of subsequent reads */
+ if (m->tr_t3 == 0) m->tr_t3 = m->tr_t6; /* Diagnostic, start of first read */
+
+ a1logd(p->log,5,"about to call usb_read with %d bytes\n",size);
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf, size, &rwbytes, top);
+
+ m->tr_t5 = m->tr_t7;
+ m->tr_t7 = msec_time(); /* Diagnostic, end of subsequent reads */
+ if (m->tr_t4 == 0) {
+ m->tr_t5 = m->tr_t2;
+ m->tr_t4 = m->tr_t7; /* Diagnostic, end of first read */
+ }
+
+#ifdef NEVER /* Use short + timeout to terminate scan */
+ if (gotshort != 0 && se == ICOM_TO) { /* We got a timeout after a short read. */
+ a1logd(p->log,1,"Read timed out in %f secs after getting short read\n"
+ "(Trig & rd times %d %d %d %d)\n",
+ top,
+ m->tr_t2-m->tr_t1, m->tr_t3-m->tr_t2, m->tr_t4-m->tr_t3, m->tr_t6-m->tr_t5);
+ break; /* We're done */
+ } else
+#endif
+ if (se == ICOM_SHORT) { /* Expect this to terminate scan reading */
+ a1logd(p->log,5,"Short read, read %d bytes, asked for %d\n"
+ "(Trig & rd times %d %d %d %d)\n",
+ rwbytes,size,
+ m->tr_t2-m->tr_t1, m->tr_t3-m->tr_t2, m->tr_t4-m->tr_t3, m->tr_t6-m->tr_t5);
+ } else if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ if (m->trig_rv != MUNKI_OK) {
+ a1logd(p->log,1,"munki_readmeasurement: trigger failed, ICOM err 0x%x\n",m->trig_se);
+ return m->trig_rv;
+ }
+ if (se & ICOM_TO)
+ a1logd(p->log,1,"munki_readmeasurement: read timed out with top = %f\n",top);
+
+ a1logd(p->log,1,"munki_readmeasurement: read failed, bytes read 0x%x, ICOM err 0x%x\n",rwbytes, se);
+ return rv;
+ }
+
+ /* If we didn't read a multiple of m->nsen * 2, we've got problems */
+ if ((rwbytes % (m->nsen * 2)) != 0) {
+ a1logd(p->log,1,"munki_readmeasurement: read %d bytes, nsen %d, odd read error\n",rwbytes, m->nsen);
+ return MUNKI_HW_ME_ODDREAD;
+ }
+
+ /* Track where we're up to */
+ bsize -= rwbytes;
+ buf += rwbytes;
+ treadings += rwbytes/(m->nsen * 2);
+
+ if (scanflag == 0) { /* Not scanning */
+
+ /* Expect to read exactly what we asked for */
+ if (rwbytes != size) {
+ a1logd(p->log,1,"munki_readmeasurement: unexpected short read, got %d expected %d\n",rwbytes,size);
+ return MUNKI_HW_ME_SHORTREAD;
+ }
+ break; /* And we're done */
+ }
+
+#ifdef NEVER /* Use short + timeout to terminate scan */
+ /* We expect to get a short read at the end of a scan, */
+ /* or we might have the USB transfer truncated by somethinge else. */
+ /* Note the short read, and keep reading until we get a time out */
+ if (rwbytes != size) {
+ gotshort = 1;
+ } else {
+ gotshort = 0;
+ }
+#else /* Use short to terminate scan */
+ /* We're scanning and expect to get a short read at the end of the scan. */
+ if (rwbytes != size) {
+ a1logd(p->log,5,"done because read %d bytes != %d\n",rwbytes,size);
+ break;
+ }
+#endif
+
+ if (bsize == 0) { /* oops, no room for more scanning read */
+ unsigned char tbuf[NSEN_MAX * 2];
+
+ /* We need to clean up, so soak up all the data and throw it away */
+ while ((se = p->icom->usb_read(p->icom, NULL, 0x81, tbuf, m->nsen * 2, &rwbytes, top)) == ICOM_OK)
+ ;
+ a1logd(p->log,1,"munki_readmeasurement: buffer was too short for scan\n");
+ return MUNKI_INT_MEASBUFFTOOSMALL;
+ }
+
+ /* Read a bunch more readings until the read is short or times out */
+ nmeas = bsize / (m->nsen * 2);
+ if (nmeas > 64)
+ nmeas = 64;
+ top = extra + m->c_inttime * nmeas;
+ }
+
+ /* Must have timed out in initial readings */
+ if (treadings < inummeas) {
+ a1logd(p->log,1,"munki_readmeasurement: read failed, bytes read 0x%x, ICOM err 0x%x\n",rwbytes, se);
+ return MUNKI_RD_SHORTMEAS;
+ }
+
+ if (p->log->debug >= 5) {
+ int i, size = treadings * m->nsen * 2;
+ char oline[100] = { '\000' }, *bp = oline;
+ for (i = 0; i < size; i++) {
+ if ((i % 16) == 0)
+ bp += sprintf(bp," %04x:",i);
+ bp += sprintf(bp," %02x",ibuf[i]);
+ if ((i+1) >= size || ((i+1) % 16) == 0) {
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,5,oline);
+ bp = oline;
+ }
+ }
+ }
+
+ a1logd(p->log,2,"munki_readmeasurement: Read %d readings, ICOM err 0x%x\n"
+ "(Trig & rd times %d %d %d %d)\n",
+ treadings, se,
+ m->tr_t2-m->tr_t1, m->tr_t3-m->tr_t2, m->tr_t4-m->tr_t3, m->tr_t6-m->tr_t5);
+
+ if (nummeas != NULL) *nummeas = treadings;
+
+ return rv;
+}
+
+/* Simulating an event */
+munki_code munki_simulate_event(munki *p, mk_eve ecode, int timestamp) {
+ munkiimp *m = (munkiimp *)p->m;
+ unsigned char pbuf[8]; /* 8 bytes to write */
+ int se, rv = MUNKI_OK;
+
+ a1logd(p->log,2,"munki_simulate_event: 0x%x\n",ecode);
+
+ int2buf(&pbuf[0], ecode);
+ int2buf(&pbuf[4], timestamp); /* msec since munki power up */
+
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0x8E, 0, 0, pbuf, 8, 2.0);
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK)
+ a1logd(p->log,1,"munki_simulate_event: event 0x%x failed with ICOM err 0x%x\n",ecode,se);
+ else
+ a1logd(p->log,2,"munki_simulate_event: 0x%x done, ICOM err 0x%x\n",ecode,se);
+
+ /* Cancel the I/O in case there is no response*/
+ msec_sleep(50);
+ if (m->th_termed == 0) {
+ a1logd(p->log,1,"munki_simulate_event: terminate switch thread failed, canceling I/O\n");
+ p->icom->usb_cancel_io(p->icom, &m->cancelt);
+ }
+
+ return rv;
+}
+
+/* Wait for a reply triggered by an event */
+munki_code munki_waitfor_switch(munki *p, mk_eve *ecode, int *timest, double top) {
+ int rwbytes; /* Data bytes read */
+ unsigned char buf[8]; /* Result */
+ int se, rv = MUNKI_OK;
+ mk_eve _ecode;
+ int _timest;
+
+ a1logd(p->log,2,"munki_waitfor_switch: Read 8 bytes from switch hit port\n");
+
+ /* Now read 8 bytes */
+ se = p->icom->usb_read(p->icom, NULL, 0x83, buf, 8, &rwbytes, top);
+
+ if (se & ICOM_TO) {
+ a1logd(p->log,1,"munki_waitfor_switch: read 0x%x bytes, timed out\n",rwbytes);
+ return MUNKI_INT_BUTTONTIMEOUT;
+ }
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,2,"munki_waitfor_switch: read failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ if (rwbytes != 8) {
+ a1logd(p->log,1,"munki_waitfor_switch: read %d bytes, short read error\n",rwbytes);
+ return MUNKI_HW_EE_SHORTREAD;
+ }
+
+ _ecode = (mk_eve) buf2int(&buf[0]);
+ _timest = buf2int(&buf[4]);
+
+ if (p->log->debug >= 3) {
+ char sbuf[100];
+ if (_ecode == mk_eve_none)
+ strcpy(sbuf, "None");
+ else if (_ecode == mk_eve_switch_press)
+ strcpy(sbuf, "Button press");
+ else if (_ecode == mk_eve_switch_release)
+ strcpy(sbuf, "Button release");
+ else if (_ecode == mk_eve_spos_change)
+ strcpy(sbuf, "Sensor position change");
+ else
+ sprintf(sbuf,"Unknown 0x%x",_ecode);
+
+ a1logd(p->log,3,"munki_waitfor_switch: Event %s, timestamp %d ICOM err 0x%x\n", sbuf, _timest, se);
+ }
+
+ a1logd(p->log,2,"munki_waitfor_switch: read %d bytes OK\n",rwbytes);
+
+ if (ecode != NULL) *ecode = _ecode;
+ if (timest != NULL) *timest = _timest;
+
+ return rv;
+}
+
+/* Wait for a reply triggered by a key press or config change (thread version) */
+/* Returns MUNKI_OK if the switch has been pressed, */
+/* or MUNKI_INT_BUTTONTIMEOUT if */
+/* no switch was pressed befor the time expired, */
+/* or some other error. */
+munki_code munki_waitfor_switch_th(munki *p, mk_eve *ecode, int *timest, double top) {
+ munkiimp *m = (munkiimp *)p->m;
+ int rwbytes; /* Data bytes read */
+ unsigned char buf[8]; /* Result */
+ int se, rv = MUNKI_OK;
+ mk_eve _ecode;
+ int _timest;
+
+ a1logd(p->log,2,"munki_waitfor_switch_th: Read 8 bytes from switch hit port\n");
+
+ /* Now read 8 bytes */
+ se = p->icom->usb_read(p->icom, &m->cancelt, 0x83, buf, 8, &rwbytes, top);
+
+ if (se & ICOM_TO) {
+ a1logd(p->log,1,"munki_waitfor_switch_th: read 0x%x bytes, timed out\n",rwbytes);
+ return MUNKI_INT_BUTTONTIMEOUT;
+ }
+
+ if ((rv = icoms2munki_err(se)) != MUNKI_OK) {
+ a1logd(p->log,2,"munki_waitfor_switch_th: read failed with ICOM err 0x%x\n",se);
+ return rv;
+ }
+
+ if (rwbytes != 8) {
+ a1logd(p->log,1,"munki_waitfor_switch_th: read %d bytes, short read error\n",rwbytes);
+ return MUNKI_HW_EE_SHORTREAD;
+ }
+
+ _ecode = (mk_eve) buf2int(&buf[0]);
+ _timest = buf2int(&buf[4]); /* msec since munki power up */
+
+ if (p->log->debug >= 3) {
+ char sbuf[100];
+ if (_ecode == mk_eve_none)
+ strcpy(sbuf, "None");
+ else if (_ecode == mk_eve_switch_press)
+ strcpy(sbuf, "Button press");
+ else if (_ecode == mk_eve_switch_release)
+ strcpy(sbuf, "Button release");
+ else if (_ecode == mk_eve_spos_change)
+ strcpy(sbuf, "Sensor position change");
+ else
+ sprintf(sbuf,"Unknown 0x%x",_ecode);
+
+ a1logd(p->log,3,"munki_waitfor_switch_th: Event %s, timestamp %d ICOM err 0x%x\n", sbuf, _timest, se);
+ }
+
+ a1logd(p->log,2,"munki_waitfor_switch_th: read %d bytes OK\n",rwbytes);
+
+ if (ecode != NULL) *ecode = _ecode;
+ if (timest != NULL) *timest = _timest;
+
+ return rv;
+}
+
+
+/* ============================================================ */
+/* key/value dictionary support for EEProm contents */
+
+/* Fixup values for the window reference */
+
+/* Check values */
+static double proj_check[36] = {
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.827859997749328610,
+ 0.849550008773803710,
+ 0.855490028858184810,
+ 0.858709990978240970,
+ 0.861010015010833740,
+ 0.862879991531372070,
+ 0.864109992980957030,
+ 0.864619970321655270,
+ 0.865379989147186280,
+ 0.865629971027374270,
+ 0.865689992904663090,
+ 0.865499973297119140,
+ 0.865499973297119140,
+ 0.865760028362274170,
+ 0.866209983825683590,
+ 0.866630017757415770,
+ 0.867579996585845950,
+ 0.868969976902008060,
+ 0.870270013809204100,
+ 0.871270000934600830,
+ 0.872340023517608640,
+ 0.873269975185394290,
+ 0.873669981956481930,
+ 0.873640000820159910,
+ 0.874390006065368650,
+ 0.873179972171783450,
+ 0.872720003128051760,
+ 0.872640013694763180,
+ 0.873160004615783690,
+ 0.873440027236938480
+};
+
+
+/* Correction values to emission ref. */
+static double proj_fix[36] = {
+ 0.639684915542602540,
+ 0.639684915542602540,
+ 0.639684915542602540,
+ 0.812916100025177000,
+ 0.846581041812896730,
+ 0.854855418205261230,
+ 0.859299719333648680,
+ 0.861804306507110600,
+ 0.863713920116424560,
+ 0.865424513816833500,
+ 0.866307735443115230,
+ 0.867028772830963130,
+ 0.867631316184997560,
+ 0.868214190006256100,
+ 0.868206322193145750,
+ 0.868299305438995360,
+ 0.867988884449005130,
+ 0.868103504180908200,
+ 0.868657410144805910,
+ 0.869595944881439210,
+ 0.870542407035827640,
+ 0.871895790100097660,
+ 0.873195052146911620,
+ 0.874702811241149900,
+ 0.876054167747497560,
+ 0.877129673957824710,
+ 0.877931654453277590,
+ 0.877546310424804690,
+ 0.876341819763183590,
+ 0.875181615352630620,
+ 0.875020027160644530,
+ 0.875684559345245360,
+ 0.876559674739837650,
+ 0.876724362373352050,
+ 0.876553714275360110,
+ 0.875786423683166500
+};
+
+/* Initialise the calibration from the EEProm contents. */
+/* (We're handed a buffer that's been rounded up to an even 32 bits by */
+/* padding with zero's) */
+munki_code munki_parse_eeprom(munki *p, unsigned char *buf, unsigned int len) {
+ munkiimp *m = (munkiimp *)p->m;
+ mkdata *d;
+ int rv = MUNKI_OK;
+ unsigned int chsum, sum;
+ int calver, compver; /* Calibration version and compatiblity version */
+ unsigned char chipid[8]; /* Calibration chip id */
+ int tint, *tinta; /* Temporary */
+ double tdouble; /* Temporary */
+ int i, j;
+
+ a1logd(p->log,2,"munki_parse_eeprom: called with %d bytes\n",len);
+
+ /* Check the checksum */
+ chsum = buf2uint(buf+8);
+ int2buf(buf+8, 0); /* Zero it out */
+
+ for (sum = 0, i = 0; i < (len-3); i += 4) {
+ sum += buf2uint(buf + i);
+ }
+
+
+
+ a1logd(p->log,3,"munki_parse_eeprom: cal chsum = 0x%x, should be 0x%x - %s\n",sum,chsum, sum == chsum ? "OK": "BAD");
+ if (sum != chsum)
+ return MUNKI_INT_CALBADCHSUM;
+
+
+ /* Create class to handle EEProm parsing */
+ if ((d = m->data = new_mkdata(p, buf, len)) == NULL)
+ return MUNKI_INT_CREATE_EEPROM_STORE;
+
+ /* Check out the version */
+ if (d->get_u16_ints(d, &calver, 0, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ if (d->get_u16_ints(d, &compver, 2, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ a1logd(p->log,4,"cal version = %d, compatible with %d\n",calver,compver);
+
+ /* We understand versions 3 to 6 */
+
+ if (calver < 3 || compver < 3 || compver > 6)
+ return MUNKI_HW_CALIBVERSION;
+
+ /* Choose the version we will treat it as */
+ if (calver > 6 && compver <= 6)
+ m->calver = 6;
+ else
+ m->calver = calver;
+ a1logd(p->log,4,"Treating as cal version = %d\n",m->calver);
+
+ /* Parse all the calibration info common for vers 3 - 6 */
+
+ /* Production number */
+ if (d->get_32_ints(d, &m->prodno, 12, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ a1logd(p->log,4,"Produnction no = %d\n",m->prodno);
+
+ /* Chip HW ID */
+ if (d->get_8_char(d, (unsigned char *)chipid, 16, 8) == NULL)
+ return MUNKI_DATA_RANGE;
+ a1logd(p->log,4,"HW Id = %02x-%02x%02x%02x%02x%02x%02x%02x\n",
+ chipid[0], chipid[1], chipid[2], chipid[3],
+ chipid[4], chipid[5], chipid[6], chipid[7]);
+
+ /* Check that the chipid matches the calibration */
+ for (i = 0; i < 8; i++) {
+ if (chipid[i] != m->chipid[i])
+ return MUNKI_HW_CALIBMATCH;
+ }
+
+ /* Serial number */
+ if (d->get_8_asciiz(d, m->serno, 24, 16) == NULL)
+ return MUNKI_DATA_RANGE;
+ a1logd(p->log,4,"serial number '%s'\n",m->serno);
+
+ /* Underlying calibration information */
+
+ m->nsen = 137; /* Sensor bands stored */
+ m->nraw = 128; /* Raw bands stored */
+ m->nwav1 = 36; /* Standard res number of cooked spectrum band */
+ m->wl_short1 = 380.0; /* Standard res short and long wavelengths */
+ m->wl_long1 = 730.0;
+
+ /* Fill this in here too */
+ m->wl_short2 = HIGHRES_SHORT;
+ m->wl_long2 = HIGHRES_LONG;
+ m->nwav2 = (int)((m->wl_long2-m->wl_short2)/HIGHRES_WIDTH + 0.5) + 1;
+
+ /* Reflection wavelength calibration information */
+ /* This is setup assuming 128 raw bands, starting */
+ /* at offset 6 from the values returned by the hardware. */
+ if ((m->rmtx_index1 = d->get_32_ints(d, NULL, 40, 36)) == NULL)
+ return MUNKI_DATA_RANGE;
+
+ /* Fake the number of matrix cooeficients for each out wavelength */
+ if ((m->rmtx_nocoef1 = (int *)malloc(sizeof(int) * 36)) == NULL)
+ return MUNKI_DATA_MEMORY;
+ for (i = 0; i < 36; i++)
+ m->rmtx_nocoef1[i] = 16;
+
+ if ((m->rmtx_coef1 = d->get_32_doubles(d, NULL, 184, 36 * 16)) == NULL)
+ return MUNKI_DATA_RANGE;
+
+#ifdef NEVER
+// ~~~ hack !!!
+m->rmtx_index1[4] = m->rmtx_index1[5] + 3;
+m->rmtx_index1[3] = m->rmtx_index1[4] + 3;
+m->rmtx_index1[2] = m->rmtx_index1[3] + 3;
+m->rmtx_index1[1] = m->rmtx_index1[2] + 3;
+m->rmtx_index1[0] = m->rmtx_index1[1] + 3;
+
+for(i = 0; i < 5; i++) {
+ for (j = 0; j < 16; j++) {
+ m->rmtx_coef1[i * 16 + j] = m->rmtx_coef1[5 * 16 + j];
+ }
+}
+#endif
+
+ if (p->log->debug >= 7) {
+ a1logd(p->log,7,"Reflectance matrix:\n");
+ for(i = 0; i < 36; i++) {
+ a1logd(p->log,7," Wave %d, index %d\n",i, m->rmtx_index1[i]);
+ for (j = 0; j < 16; j++) {
+ if (m->rmtx_coef1[i * 16 + j] != 0.0)
+ a1logd(p->log,7," Wt %d = %f\n",j, m->rmtx_coef1[i * 16 + j]);
+ }
+ }
+ }
+
+ /* Emission wavelength calibration information */
+ if ((m->emtx_index1 = d->get_32_ints(d, NULL, 2488, 36)) == NULL)
+ return MUNKI_DATA_RANGE;
+
+ /* Fake the number of matrix cooeficients for each out wavelength */
+ if ((m->emtx_nocoef1 = (int *)malloc(sizeof(int) * 36)) == NULL)
+ return MUNKI_DATA_MEMORY;
+ for (i = 0; i < 36; i++)
+ m->emtx_nocoef1[i] = 16;
+
+ if ((m->emtx_coef1 = d->get_32_doubles(d, NULL, 2632, 36 * 16)) == NULL)
+ return MUNKI_DATA_RANGE;
+
+ if (p->log->debug >= 7) {
+ a1logd(p->log,5,"Emmission matrix:\n");
+ for(i = 0; i < 36; i++) {
+ a1logd(p->log,7," Wave %d, index %d\n",i, m->emtx_index1[i]);
+ for (j = 0; j < 16; j++) {
+ if (m->emtx_coef1[i * 16 + j] != 0.0)
+ a1logd(p->log,7," Wt %d = %f\n",j, m->emtx_coef1[i * 16 + j]);
+ }
+ }
+ }
+
+ /* Linearization */
+ if ((m->lin0 = d->rget_32_doubles(d, NULL, 4936, 4)) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->nlin0 = 4;
+
+ if ((m->lin1 = d->rget_32_doubles(d, NULL, 4952, 4)) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->nlin1 = 4;
+
+ if (p->log->debug >= 3) {
+ char oline[200] = { '\000' }, *bp = oline;
+
+ bp += sprintf(bp,"Normal non-lin =");
+ for(i = 0; i < m->nlin0; i++)
+ bp += sprintf(bp," %1.10f",m->lin0[i]);
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,2,oline);
+
+ bp = oline;
+ bp += sprintf(bp,"High Gain non-lin =");
+ for(i = 0; i < m->nlin1; i++)
+ bp += sprintf(bp," %1.10f",m->lin1[i]);
+ bp += sprintf(bp,"\n");
+ a1logd(p->log,2,oline);
+ }
+
+ /* Reflectance reference */
+ if ((m->white_ref1 = d->get_32_doubles(d, NULL, 4968, 36)) == NULL)
+ return MUNKI_DATA_RANGE;
+
+ /* Emission reference */
+ if ((m->emis_coef1 = d->get_32_doubles(d, NULL, 5112, 36)) == NULL)
+ return MUNKI_DATA_RANGE;
+
+ /* Ambient reference */
+ if ((m->amb_coef1 = d->get_32_doubles(d, NULL, 5256, 36)) == NULL)
+ return MUNKI_DATA_RANGE;
+
+ /* Sensor target values */
+ if (d->get_u16_ints(d, &tint, 5400, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->minsval = (double)tint;
+ if (d->get_u16_ints(d, &tint, 5402, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->optsval = (double)tint;
+ if (d->get_u16_ints(d, &tint, 5404, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->maxsval = (double)tint;
+ if (d->get_u16_ints(d, &tint, 5406, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->satlimit = (double)tint;
+
+ a1logd(p->log,4,"Sensor targmin %.0f, opt %.0f, max %.0f, sat %.0f\n",
+ m->minsval,m->optsval,m->maxsval,m->satlimit);
+
+ if (d->get_32_doubles(d, &m->cal_int_time, 5408, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->cal_int_time *= 1e-3; /* Convert to seconds */
+
+ if (d->get_32_ints(d, &tint, 5412, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->ledpreheattime = tint * 1e-3; /* Convert to seconds */
+
+ if (d->get_32_ints(d, &tint, 5416, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->ledwaittime = tint * 1e-3; /* Convert to seconds */
+
+ if (d->get_u16_ints(d, &m->ledholdtempdc, 5420, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+
+ a1logd(p->log,4,"Cal int time %f, LED pre-heat %f, Led wait %f, LED hold temp duty cycle %d\n", m->cal_int_time, m->ledpreheattime, m->ledwaittime, m->ledholdtempdc);
+
+ if (d->get_u16_ints(d, &tint, 5422, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->refinvalidsampt = tint * 1e-3; /* Convert to seconds */
+
+ if (d->get_32_ints(d, &tint, 5424, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ m->calscantime = tint * 1e-3; /* Convert to seconds */
+
+ a1logd(p->log,4,"Invalid sample time %f, Cal scan time %f\n",
+ m->refinvalidsampt, m->calscantime);
+
+ /* Stray light compensation. Note that 16 bit numbers are signed. */
+ if ((tinta = d->get_16_ints(d, NULL, 5428, 36 * 36)) == NULL)
+ return MUNKI_DATA_RANGE;
+ if (m->calver >= 4) {
+ if (d->get_32_doubles(d, &tdouble, 8020, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ } else {
+ tdouble = 0.001; /* Hmm. this is quite different to EEProm value */
+ }
+ /* Convert from ints to floats */
+ m->straylight1 = dmatrixz(0, 35, 0, 35);
+ for (i = 0; i < 36; i++) {
+ for (j = 0; j < 36; j++) {
+ m->straylight1[i][j] = tdouble * tinta[i * 36 + j];
+ if (i == j)
+ m->straylight1[i][j] += 1.0;
+ }
+ }
+ free(tinta);
+
+ if (p->log->debug >= 7) {
+ a1logd(p->log,7,"Stray Light matrix:\n");
+ for(i = 0; i < 36; i++) {
+ double sum = 0.0;
+ a1logd(p->log,7," Wave %d, index %d\n",i, m->rmtx_index1[i]);
+ for (j = 0; j < 36; j++) {
+ sum += m->straylight1[i][j];
+ a1logd(p->log,7," Wt %d = %f\n",j, m->straylight1[i][j]);
+ }
+ a1logd(p->log,7," Sum = %f\n",sum);
+ }
+ }
+
+ if (m->calver >= 5) {
+ /* Projector reference */
+ if ((m->proj_coef1 = d->get_32_doubles(d, NULL, 8024, 36)) == NULL)
+ return MUNKI_DATA_RANGE;
+
+ /* Apparently this can be faulty though. Check if it is */
+ for (i = 0; i < 6; i++) {
+ if (m->proj_coef1[i] != m->proj_coef1[i])
+ break; /* Not Nan */
+ }
+ if (i == 6) { /* First 6 are Nan's */
+ for (; i < 36; i++) {
+ if ((m->emis_coef1[i]/m->proj_coef1[i] - proj_check[i]) > 0.001)
+ break; /* Not less than 0.001 */
+ }
+ }
+ if (i == 36) { /* It's faulty */
+ free(m->proj_coef1);
+ m->proj_coef1 = NULL; /* Fall through to fakeup */
+ }
+ }
+
+ if (m->proj_coef1 == NULL) { /* Fake up a projector reference */
+ if ((m->proj_coef1 = (double *)malloc(sizeof(double) * 36)) == NULL)
+ return MUNKI_DATA_MEMORY;
+ for (i = 0; i < 36; i++) {
+ m->proj_coef1[i] = m->emis_coef1[i]/proj_fix[i];
+ }
+ a1logd(p->log,4,"Faked up projector cal reference\n");
+ }
+
+ if (m->calver >= 6) {
+ if (d->get_8_ints(d, &m->adctype, 8168, 1) == NULL)
+ return MUNKI_DATA_RANGE;
+ } else {
+ m->adctype = 0;
+ }
+
+ if (p->log->debug >= 7) {
+ a1logd(p->log,4,"White ref, emission cal, ambient cal, proj cal:\n");
+ for(i = 0; i < 36; i++) {
+ a1logd(p->log,7," %d: %f, %f, %f, %f\n",i, m->white_ref1[i], m->emis_coef1[i],
+ m->amb_coef1[i], m->proj_coef1[i]);
+ }
+ }
+
+#ifdef PLOT_RCALCURVE
+ /* Plot the reflection reference curve */
+ {
+ int i;
+ double xx[36];
+ double y1[36];
+
+ for (i = 0; i < m->nwav1; i++) {
+ xx[i] = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, i);
+ y1[i] = m->white_ref1[i];
+ }
+ printf("Reflection Reference (Black)\n");
+ do_plot(xx, y1, NULL, NULL, 36);
+ }
+#endif /* PLOT_RCALCURVE */
+
+#ifdef PLOT_ECALCURVES
+ /* Plot the emission reference curves */
+ {
+ int i;
+ double xx[36];
+ double y1[36], y2[36], y3[36];
+
+ printf("Emission Reference (Black), Ambient (Red), Projector (Green)\n");
+ for (i = 0; i < m->nwav1; i++) {
+ xx[i] = XSPECT_WL(m->wl_short1, m->wl_long1, m->nwav1, i);
+ y1[i] = m->emis_coef1[i];
+ y2[i] = m->amb_coef1[i];
+ y3[i] = m->proj_coef1[i];
+ if (y3[i] > 0.02)
+ y3[i] = 0.02;
+ }
+ do_plot(xx, y1, y2, y3, 36);
+ }
+#endif /* PLOT_ECALCURVES */
+
+ /* Default to standard resolution */
+ m->nwav = m->nwav1;
+ m->wl_short = m->wl_short1;
+ m->wl_long = m->wl_long1;
+
+ m->rmtx_index = m->rmtx_index1;
+ m->rmtx_nocoef = m->rmtx_nocoef1;
+ m->rmtx_coef = m->rmtx_coef1;
+ m->emtx_index = m->emtx_index1;
+ m->emtx_nocoef = m->emtx_nocoef1;
+ m->emtx_coef = m->emtx_coef1;
+
+ m->white_ref = m->white_ref1;
+ m->emis_coef = m->emis_coef1;
+ m->amb_coef = m->amb_coef1;
+ m->proj_coef = m->proj_coef1;
+ m->straylight = m->straylight1;
+
+ m->highgain = 1.0/m->lin1[1]; /* Gain is encoded in linearity */
+ a1logd(p->log,3, "highgain = %f\n",m->highgain);
+
+ return rv;
+}
+
+
+/* Return a pointer to an array of chars containing data from 8 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range. */
+static unsigned char *mkdata_get_8_char(struct _mkdata *d, unsigned char *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 1) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (unsigned char *)malloc(sizeof(int) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 1) {
+ rv[i] = d->buf[off];
+ }
+ return rv;
+}
+
+/* Return a pointer to an nul terminated string containing data from 8 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range. */
+/* An extra space and a nul terminator will be added to the eeprom data */
+static char *mkdata_get_8_asciiz(struct _mkdata *d, char *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 1) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (char *)malloc(sizeof(int) * (count + 1))) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 1) {
+ rv[i] = (char)d->buf[off];
+ }
+ rv[i] = '\000';
+
+ return rv;
+}
+
+/* Return a pointer to an array of ints containing data from 8 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range. */
+static int *mkdata_get_8_ints(struct _mkdata *d, int *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 1) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (int *)malloc(sizeof(int) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 1) {
+ rv[i] = ((signed char *)d->buf)[off];
+ }
+ return rv;
+}
+
+/* Return a pointer to an array of ints containing data from unsigned 8 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range. */
+static int *mkdata_get_u8_ints(struct _mkdata *d, int *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 1) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (int *)malloc(sizeof(int) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 1) {
+ rv[i] = d->buf[off];
+ }
+ return rv;
+}
+
+/* Return a pointer to an array of ints containing data from 16 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range. */
+static int *mkdata_get_16_ints(struct _mkdata *d, int *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 2) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (int *)malloc(sizeof(int) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 2) {
+ rv[i] = buf2short(d->buf + off);
+ }
+ return rv;
+}
+
+/* Return a pointer to an array of ints containing data from unsigned 16 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range. */
+static int *mkdata_get_u16_ints(struct _mkdata *d, int *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 2) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (int *)malloc(sizeof(int) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 2) {
+ rv[i] = buf2ushort(d->buf + off);
+ }
+ return rv;
+}
+
+/* Return a pointer to an array of ints containing data from 32 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range. */
+static int *mkdata_get_32_ints(struct _mkdata *d, int *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 4) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (int *)malloc(sizeof(int) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 4) {
+ rv[i] = buf2int(d->buf + off);
+ }
+ return rv;
+}
+
+/* Return a pointer to an array of unsigned ints containing data from unsigned 32 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range. */
+static unsigned int *mkdata_get_u32_uints(struct _mkdata *d, unsigned int *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 4) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (unsigned int *)malloc(sizeof(unsigned int) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 4) {
+ rv[i] = buf2uint(d->buf + off);
+ }
+ return rv;
+}
+
+/* Return a pointer to an array of doubles containing data from 32 bits. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range or malloc failure. */
+static double *mkdata_get_32_doubles(struct _mkdata *d, double *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 4) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (double *)malloc(sizeof(double) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = 0; i < count; i++, off += 4) {
+ unsigned int val;
+ val = buf2uint(d->buf + off);
+ rv[i] = IEEE754todouble(val);
+ }
+ return rv;
+}
+
+/* Return a pointer to an array of doubles containing data from 32 bits, */
+/* with the array filled in reverse order. */
+/* If rv is NULL, the returned value will have been allocated, othewise */
+/* the rv will be returned. Return NULL if out of range or malloc failure. */
+static double *mkdata_rget_32_doubles(struct _mkdata *d, double *rv, int off, int count) {
+ int i;
+
+ if (count <= 0
+ || off < 0
+ || (off + count * 4) > d->len)
+ return NULL;
+
+ if (rv == NULL) {
+ if ((rv = (double *)malloc(sizeof(double) * count)) == NULL)
+ return NULL;
+ }
+
+ for (i = count-1; i >= 0; i--, off += 4) {
+ unsigned int val;
+ val = buf2uint(d->buf + off);
+ rv[i] = IEEE754todouble(val);
+ }
+ return rv;
+}
+
+
+/* Destroy ourselves */
+static void mkdata_del(mkdata *d) {
+ del_a1log(d->log); /* Unref it */
+ free(d);
+}
+
+/* Constructor for mkdata */
+mkdata *new_mkdata(munki *p, unsigned char *buf, int len) {
+ mkdata *d;
+ if ((d = (mkdata *)calloc(1, sizeof(mkdata))) == NULL) {
+ a1loge(p->log, 1, "new_mkdata: malloc failed!\n");
+ return NULL;
+ }
+
+ d->p = p;
+
+ d->log = new_a1log_d(p->log); /* Take reference */
+
+ d->buf = buf;
+ d->len = len;
+
+ d->get_8_char = mkdata_get_8_char;
+ d->get_8_asciiz = mkdata_get_8_asciiz;
+ d->get_8_ints = mkdata_get_8_ints;
+ d->get_u8_ints = mkdata_get_u8_ints;
+ d->get_16_ints = mkdata_get_16_ints;
+ d->get_u16_ints = mkdata_get_u16_ints;
+ d->get_32_ints = mkdata_get_32_ints;
+ d->get_u32_uints = mkdata_get_u32_uints;
+ d->get_32_doubles = mkdata_get_32_doubles;
+ d->rget_32_doubles = mkdata_rget_32_doubles;
+
+ d->del = mkdata_del;
+
+ return d;
+}
+
+/* ----------------------------------------------------------------- */
diff --git a/spectro/munki_imp.h b/spectro/munki_imp.h
new file mode 100644
index 0000000..a9af3a9
--- /dev/null
+++ b/spectro/munki_imp.h
@@ -0,0 +1,1029 @@
+
+#ifndef MUNKI_IMP_H
+
+ /* X-Rite ColorMunki related defines */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/1/2009
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * (Base on i1pro_imp.h)
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Implementation resources for munki driver */
+
+/* -------------------------------------------------- */
+/* Implementation class */
+
+typedef int munki_code; /* Type to use for error codes */
+
+/* MUNKI mode state. This is implementation data that */
+/* depends on the mode the instrument is in. */
+/* Each mode has a separate calibration, and configured instrument state. */
+
+typedef enum {
+ mk_refl_spot = 0,
+ mk_refl_scan = 1,
+ mk_emiss_spot_na = 2,
+ mk_tele_spot_na = 3,
+ mk_emiss_spot = 4,
+ mk_tele_spot = 5,
+ mk_emiss_scan = 6,
+ mk_amb_spot = 7,
+ mk_amb_flash = 8,
+ mk_trans_spot = 9,
+ mk_trans_scan = 10,
+ mk_no_modes = 11
+} mk_mode;
+
+struct _munki_state {
+ mk_mode mode; /* Mode number */
+
+ /* Just one of the following 3 must always be set */
+ int emiss; /* flag - Emissive mode */
+ int trans; /* flag - Transmissive mode */
+ int reflective; /* flag - Reflective mode */
+
+ /* The following modify emiss */
+ int ambient; /* flag - Ambient position mode */
+ int projector; /* flag - Projector position (tele) mode */
+
+ /* The following can be added to any of the 3: */
+ int scan; /* flag - Scanning mode */
+ int adaptive; /* flag - adaptive mode (emiss - adapt for each measurement) */
+
+ /* The following can be added to scan: */
+ int flash; /* flag - Flash detection from scan mode */
+
+ /* Configuration & state information */
+ double targoscale; /* Optimal reading scale factor <= 1.0 */
+ double targmaxitime;/* maximum integration time to aim for (ie. 2.0 sec) */
+ double targoscale2; /* Proportion of targoscale allowed to meed targmaxitime */
+ int gainmode; /* Gain mode, 0 = normal, 1 = high */
+ double inttime; /* Integration time */
+ double invsampt; /* Invalid sample time */
+
+ double dpretime; /* Target pre-read dark read time - sets no. of readings */
+ double wpretime; /* Target pre-read white/sample read time - sets no. of readings */
+
+ double dcaltime; /* Target dark calibration time - sets number of readings */
+ double wcaltime; /* Target white calibration time - sets number of readings (not used?) */
+
+ double dreadtime; /* Target dark on-the-fly cal time - sets number of readings */
+ double wreadtime; /* Target white/sample reading time - sets number of readings */
+
+ double maxscantime; /* Maximum scan time sets buffer size allocated */
+
+ double min_wl; /* Minimum wavelegth to report for this mode */
+
+ /* calibration information for this mode */
+ int dark_valid; /* dark calibration factor valid */
+ time_t ddate; /* Date/time of last dark calibration */
+ double dark_int_time; /* Integration time used for dark data */
+ double *dark_data; /* [-1 nraw] of dark level to subtract. Note that the dark value */
+ /* depends on integration time and gain mode. */
+ int dark_gain_mode; /* Gain mode used for dark data */
+
+ int cal_valid; /* calibration factor valid */
+ time_t cfdate; /* Date/time of last cal factor calibration */
+ double *cal_factor; /* [nwav] of calibration scale factor for this mode */
+ double *cal_factor1, *cal_factor2; /* (Underlying tables for two resolutions) */
+ double *white_data; /* [-1 nraw] linear absolute dark subtracted white data */
+ /* used to compute cal_factors (at reftemp) */
+ double **iwhite_data; /* [-1 nraw][2] LED temperature data to interpolate white_data from */
+ double reftemp; /* Reference temperature to correct to */
+
+ /* Adaptive emission/transparency black data */
+ int idark_valid; /* idark calibration factors valid */
+ time_t iddate; /* Date/time of last dark idark calibration */
+ double idark_int_time[4];
+ double **idark_data; /* [4][-1 nraw] of dark level for inttime/gains of : */
+ /* 0.01 norm, 1.0 norm, 0.01 high, 1.0 high */
+ /* then it's converted to base + increment with inttime */
+
+ int want_calib; /* Initial White calibration wanted */
+ int want_dcalib; /* Initial Dark Calibration wanted */
+
+ /* Display mode calibration state (emmis && !scan && !adaptive) */
+ int dispswap; /* 0 = default time, 1 = dark_int_time2, 2 = dark_int_time3 */
+ double done_dintsel; /* A display integration time selection has been done */
+ time_t diseldate; /* Date/time of last display integration time selection */
+ double dcaltime2; /* Target dark calibration time - sets number of readings */
+ double dark_int_time2; /* Integration time used for dark data 2 */
+ double *dark_data2; /* [-1 nraw] of dark level to subtract for dark_int_time2. */
+ double dcaltime3; /* Target dark calibration time - sets number of readings */
+ double dark_int_time3; /* Integration time used for dark data 3 */
+ double *dark_data3; /* [-1 nraw] of dark level to subtract for dark_int_time3. */
+
+}; typedef struct _munki_state munki_state;
+
+
+
+/* MUNKI implementation class */
+struct _munkiimp {
+ munki *p;
+
+ /* Misc. and top level */
+ struct _mkdata *data; /* EEProm data container */
+ athread *th; /* Switch monitoring thread (NULL if not used) */
+ volatile int switch_count; /* Incremented in thread */
+ volatile int hide_switch; /* Set to supress switch event during read */
+ usb_cancelt cancelt; /* Token to allow cancelling an outstanding I/O */
+ volatile int th_term; /* Thread terminate on error rather than retry */
+ volatile int th_termed; /* Thread has terminated */
+ inst_opt_type trig; /* Reading trigger mode */
+ int noinitcalib; /* Disable initial calibration if not essential */
+ int nosposcheck; /* Disable checking the sensor position */
+ int highres; /* High resolution mode */
+ int hr_inited; /* High resolution has been initialized */
+
+ /* Current settings */
+ mk_mode mmode; /* Current measurement mode selected */
+ munki_state ms[mk_no_modes]; /* Mode state */
+ int spec_en; /* Enable reporting of spectral data */
+
+ double intclkp; /* Integration clock period (computed from tickdur) */
+
+ /* Current state of hardware (~~99 are all these used ??) */
+ double c_inttime; /* Integration period (=inttime + deadtime) */
+ int c_measmodeflags; /* Measurement mode flags (set by trigger() */
+
+ /* Information from the HW */
+ int fwrev; /* int - Firmware revision number, from getfirm() */
+ /* Typically 0120 = V1.32 */
+ unsigned char chipid[8]; /* HW serial number */
+ char vstring[37]; /* Asciiz version string */
+ int tickdur; /* Tick duration (usec, converted to intclkp) */
+ int minintcount; /* Minimum integration tick count */
+ int noeeblocks; /* Number of EEPROM blocks */
+ int eeblocksize; /* Size of each block */
+
+ /* Information from the EEProm */
+ int calver; /* Effective calibration version number */
+ int prodno; /* Production number */
+ char serno[17]; /* serial number string */
+ int adctype; /* A/D converter type */
+
+ double minsval; /* Minimum sensor value target */
+ double optsval; /* Optimal sensor value target */
+ double maxsval; /* Maximum sensor value target */
+ double satlimit; /* Saturation limit */
+
+ int ledholdtempdc; /* LED Hold temparature duty cycle */
+ /* Parameter used in measure instruction. [0] */
+ double ledpreheattime; /* LED Pre-heat time, Seconds [1.0] */
+ /* Time to turn LED on before determining */
+ /* integration time that achieves optimal sensor value. */
+ double cal_int_time; /* Calibration integration time in seconds. [0.018208] */
+ /* Starting integration time use for achieving */
+ /* the optimal sensor value. */
+ double ledwaittime; /* LED Wait time, Seconds [1.0] */
+ /* Time to wait for LED to cool down */
+ /* before determining temperature/output characteristic. */
+ double calscantime; /* Calibration scan time used for determining temp/output */
+ /* characteristic of LED, Seconds. [3.0] */
+ double refinvalidsampt; /* Reflection invalid sample time in seconds. [0.1] */
+ /* This sets the number of extra samples to add to a */
+ /* reflective read, and then to discard from */
+ /* the start of the measurements. This allows for LED */
+ /* thermal warmup. */
+
+ double min_int_time; /* Minimum integration time (secs) (set from minintcount) */
+ /* (Typical value is 0.007168 = 139.5 times/sec) */
+ double max_int_time; /* Maximum integration time (secs) (fixed in sw) */
+
+ /* Underlying calibration information */
+ int nsen; /* There are 137 provided from the device, with */
+ /* 6 skipped at the start, and 3 at the end. */
+ /* The first 4 are photo shielded. */
+ /* The last reading is the LED voltage drop */
+ /* 2 at the start and 2 at the end are unused. */
+ int nraw; /* Raw sample bands stored = 128 (Must be signed!) */
+ int nwav; /* Current cooked spectrum bands stored, usually = 36 */
+ double wl_short; /* Cooked spectrum bands short wavelength, usually 380 */
+ double wl_long; /* Cooked spectrum bands short wavelength, usually 730 */
+
+ unsigned int nwav1, nwav2; /* Available bands for standard and high-res modes */
+ double wl_short1, wl_short2, wl_long1, wl_long2;
+
+ /* Reflection */
+ int *rmtx_index; /* [nwav] Matrix CCD sample starting index for each out wavelength */
+ int *rmtx_nocoef; /* [nwav] Number of matrix cooeficients for each out wavelength */
+ double *rmtx_coef; /* [nwav * rmtx_nocoef] Matrix coeef's to compute each wavelength */
+ int *rmtx_index1, *rmtx_index2; /* Underlying arrays for the two resolutions */
+ int *rmtx_nocoef1, *rmtx_nocoef2; /* first [nwav1], second [nwav2] */
+ double *rmtx_coef1, *rmtx_coef2;
+
+ /* Emission */
+ int *emtx_index; /* [nwav] Matrix CCD sample starting index for each out wavelength */
+ int *emtx_nocoef; /* [nwav] Number of matrix cooeficients for each out wavelength */
+ double *emtx_coef; /* [nwav * emtx_nocoef] Matrix coeef's to compute each wavelength */
+ int *emtx_index1, *emtx_index2; /* Underlying arrays for the two resolutions */
+ int *emtx_nocoef1, *emtx_nocoef2; /* first [nwav1], second [nwav2] */
+ double *emtx_coef1, *emtx_coef2;
+
+ unsigned int nlin0; /* Number in array */
+ double *lin0; /* Array of linearisation polinomial factors, normal gain. */
+
+ unsigned int nlin1; /* Number in array */
+ double *lin1; /* Array of linearisation polinomial factors, high gain. */
+
+ double *white_ref; /* [nwav] White calibration tile reflectance values */
+ double *emis_coef; /* [nwav] Emission calibration coefficients */
+ double *amb_coef; /* [nwav] Ambient light cal values (compound with Emission) */
+ double *proj_coef; /* [nwav] Projector light cal values (compound with Emission) */
+ double *white_ref1, *white_ref2; /* Underlying tables for normal/high res modes */
+ double *emis_coef1, *emis_coef2;
+ double *amb_coef1, *amb_coef2;
+ double *proj_coef1, *proj_coef2;
+
+ double **straylight; /* [nwav][nwav] Stray light convolution matrix */
+ double **straylight1, **straylight2; /* Underlying tables for normal/high res modes */
+
+ double highgain; /* High gain mode gain */
+ double scan_toll_ratio; /* Modifier of scan tollerance */
+
+ /* Trigger houskeeping & diagnostics */
+ int transwarn; /* Transmission calibration warning state */
+ int lo_secs; /* Seconds since last opened (from calibration file mod time) */
+ int tr_t1, tr_t2, tr_t3, tr_t4, tr_t5, tr_t6, tr_t7; /* Trigger/read timing diagnostics */
+ /* 1->2 = time to execute trigger */
+ /* 2->3 = time to between end trigger and start of first read */
+ /* 3->4 = time to exectute first read */
+ /* 6->5 = time between end of second last read and start of last read */
+ int trig_se; /* Delayed trigger icoms error */
+ munki_code trig_rv; /* Delayed trigger result */
+
+}; typedef struct _munkiimp munkiimp;
+
+/* Add an implementation structure */
+munki_code add_munkiimp(munki *p);
+
+/* Destroy implementation structure */
+void del_munkiimp(munki *p);
+
+/* ============================================================ */
+/* Error codes returned from munki_imp */
+
+/* Note: update munki_interp_error() and munki_interp_code() in munki.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define MUNKI_INTERNAL_ERROR 0x71 /* Internal software error */
+#define MUNKI_COMS_FAIL 0x72 /* Communication failure */
+#define MUNKI_UNKNOWN_MODEL 0x73 /* Not an munki */
+#define MUNKI_DATA_PARSE_ERROR 0x74 /* Read data parsing error */
+
+#define MUNKI_USER_ABORT 0x75 /* uicallback returned abort */
+#define MUNKI_USER_TRIG 0x76 /* uicallback retuned trigger */
+
+#define MUNKI_UNSUPPORTED 0x79 /* Unsupported function */
+#define MUNKI_CAL_SETUP 0x7A /* Cal. retry with correct setup is needed */
+
+/* Real error code */
+#define MUNKI_OK 0x00
+
+/* EEprop parsing errors */
+#define MUNKI_DATA_RANGE 0x02 /* out of range of buffer */
+#define MUNKI_DATA_MEMORY 0x03 /* memory alloc failure */
+
+/* HW errors */
+#define MUNKI_HW_EE_SHORTREAD 0x21 /* Read fewer EEProm bytes than expected */
+#define MUNKI_HW_ME_SHORTREAD 0x22 /* Read measurement bytes than expected */
+#define MUNKI_HW_ME_ODDREAD 0x23 /* Read measurement bytes was not mult 274 */
+#define MUNKI_HW_CALIBVERSION 0x24 /* calibration version is unknown */
+#define MUNKI_HW_CALIBMATCH 0x25 /* calibration doesn't match device */
+
+/* Sample read operation errors */
+#define MUNKI_RD_DARKREADINCONS 0x30 /* Dark calibration reading inconsistent */
+#define MUNKI_RD_SENSORSATURATED 0x31 /* Sensor is saturated */
+#define MUNKI_RD_DARKNOTVALID 0x32 /* Dark reading is not valid (too light) */
+#define MUNKI_RD_NEEDS_CAL 0x33 /* Mode needs calibration */
+#define MUNKI_RD_WHITEREADINCONS 0x34 /* White reference readings are inconsistent */
+#define MUNKI_RD_WHITEREFERROR 0x35 /* White reference reading error */
+#define MUNKI_RD_LIGHTTOOLOW 0x36 /* Light level is too low */
+#define MUNKI_RD_LIGHTTOOHIGH 0x37 /* Light level is too high */
+#define MUNKI_RD_SHORTMEAS 0x38 /* Measurment was too short */
+#define MUNKI_RD_READINCONS 0x39 /* Reading is inconsistent */
+#define MUNKI_RD_REFWHITENOCONV 0x3A /* White calibration didn't converge */
+#define MUNKI_RD_NOTENOUGHPATCHES 0x3B /* Not enough patches */
+#define MUNKI_RD_TOOMANYPATCHES 0x3C /* Too many patches */
+#define MUNKI_RD_NOTENOUGHSAMPLES 0x3D /* Not enough samples per patch */
+#define MUNKI_RD_NOFLASHES 0x3E /* No flashes recognized */
+#define MUNKI_RD_NOAMBB4FLASHES 0x3F /* No ambient before flashes found */
+#define MUNKI_RD_NOREFR_FOUND 0x40 /* Unable to measure refresh rate */
+
+#define MUNKI_SPOS_PROJ 0x48 /* Sensor needs to be in projector position */
+#define MUNKI_SPOS_SURF 0x49 /* Sensor needs to be in surface position */
+#define MUNKI_SPOS_CALIB 0x4A /* Sensor needs to be in calibration position */
+#define MUNKI_SPOS_AMB 0x4B /* Sensor needs to be in ambient position */
+
+/* Internal errors */
+#define MUNKI_INT_NO_COMS 0x50
+#define MUNKI_INT_EESIZE 0x51 /* EEProm read size is too big */
+#define MUNKI_INT_EEOUTOFRANGE 0x52 /* EEProm size is unexpected */
+#define MUNKI_INT_CALTOOSMALL 0x53 /* Calibration EEProm size is too small */
+#define MUNKI_INT_CALTOOBIG 0x54 /* Calibration EEProm size is too big */
+#define MUNKI_INT_CALBADCHSUM 0x55 /* Calibration has a bad checksum */
+#define MUNKI_INT_ODDREADBUF 0x56 /* Measurment read buffer is not mult 274 */
+#define MUNKI_INT_INTTOOBIG 0x57 /* Integration time is too big */
+#define MUNKI_INT_INTTOOSMALL 0x58 /* Integration time is too small */
+#define MUNKI_INT_ILLEGALMODE 0x59 /* Illegal measurement mode selected */
+#define MUNKI_INT_ZEROMEASURES 0x5A /* Number of measurements requested is zero */
+#define MUNKI_INT_WRONGPATCHES 0x5B /* Number of patches to match is wrong */
+#define MUNKI_INT_MEASBUFFTOOSMALL 0x5C /* Measurement read buffer is too small */
+#define MUNKI_INT_NOTIMPLEMENTED 0x5D /* Support not implemented */
+#define MUNKI_INT_NOTCALIBRATED 0x5E /* Unexpectedely invalid calibration */
+#define MUNKI_INT_THREADFAILED 0x5F /* Creation of thread failed */
+#define MUNKI_INT_BUTTONTIMEOUT 0x60 /* Switch status read timed out */
+#define MUNKI_INT_CIECONVFAIL 0x61 /* Creating spectral to CIE converted failed */
+#define MUNKI_INT_MALLOC 0x62 /* Error in mallocing memory */
+#define MUNKI_INT_CREATE_EEPROM_STORE 0x63 /* Error in creating EEProm store */
+#define MUNKI_INT_NEW_RSPL_FAILED 0x64 /* Creating RSPL object faild */
+#define MUNKI_INT_CAL_SAVE 0x65 /* Unable to save calibration to file */
+#define MUNKI_INT_CAL_RESTORE 0x66 /* Unable to restore calibration from file */
+#define MUNKI_INT_CAL_TOUCH 0x67 /* Unable to touch calibration file */
+
+
+#define MUNKI_INT_ASSERT 0x6F /* Internal assert */
+
+
+int icoms2munki_err(int se);
+
+/* ============================================================ */
+/* High level implementatation */
+
+/* Initialise our software state from the hardware */
+munki_code munki_imp_init(munki *p);
+
+/* Return a pointer to the serial number */
+char *munki_imp_get_serial_no(munki *p);
+
+/* Set the measurement mode. It may need calibrating */
+munki_code munki_imp_set_mode(
+ munki *p,
+ mk_mode mmode, /* munki mode to use */
+ int spec_en); /* nz to enable reporting spectral */
+
+/* Implement get_n_a_cals */
+munki_code munki_imp_get_n_a_cals(munki *p, inst_cal_type *pn_cals, inst_cal_type *pa_cals);
+
+/* Calibrate for the current mode. */
+/* Request an instrument calibration of the current mode. */
+munki_code munki_imp_calibrate(
+munki *p,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[100] /* Condition identifier (ie. white reference ID) */
+);
+
+/* Measure a patch or strip in the current mode. */
+munki_code munki_imp_measure(
+ munki *p,
+ ipatch *val, /* Pointer to array of instrument patch value */
+ int nvals, /* Number of values */
+ instClamping clamp /* Clamp XYZ/Lab to be +ve */
+);
+
+/* Measure the emissive refresh rate */
+munki_code munki_imp_meas_refrate(
+ munki *p,
+ double *ref_rate
+);
+
+/* return nz if high res is supported */
+int munki_imp_highres(munki *p);
+
+/* Set to high resolution mode */
+munki_code munki_set_highres(munki *p);
+
+/* Set to standard resolution mode */
+munki_code munki_set_stdres(munki *p);
+
+/* Modify the scan consistency tollerance */
+munki_code munki_set_scan_toll(munki *p, double toll_ratio);
+
+
+/* Save the calibration for all modes, stored on local system */
+munki_code munki_save_calibration(munki *p);
+
+/* Restore the all modes calibration from the local system */
+munki_code munki_restore_calibration(munki *p);
+
+
+/* ============================================================ */
+/* Intermediate routines - composite commands/processing */
+
+/* Take a dark reference measurement - part 1 */
+munki_code munki_dark_measure_1(
+ munki *p,
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf, /* USB reading buffer to use */
+ unsigned int bsize /* Size of buffer */
+);
+
+/* Take a dark reference measurement - part 2 */
+munki_code munki_dark_measure_2(
+ munki *p,
+ double *sens, /* Return array [-1 nraw] of sens values */
+ int nummeas, /* Number of readings to take */
+ double inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf, /* raw USB reading buffer to process */
+ unsigned int bsize /* Buffer size to process */
+);
+
+/* Take a dark measurement */
+munki_code munki_dark_measure(
+ munki *p,
+ double *sens, /* Return array [-1 nraw] of sens values */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+);
+
+/* Take a white reference measurement */
+/* (Subtracts black and processes into wavelenths) */
+munki_code munki_whitemeasure(
+ munki *p,
+ double *absraw, /* Return array [-1 nraw] of absraw values (may be NULL) */
+ double *optscale, /* Factor to scale gain/int time by to make optimal (may be NULL) */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale /* Optimal reading scale factor */
+);
+
+/* Given an absraw white reference measurement, */
+/* compute the wavelength equivalents. */
+/* (absraw is usually ->white_data) */
+/* (abswav1 is usually ->cal_factor1) */
+/* (abswav2 is usually ->cal_factor2) */
+munki_code munki_compute_wav_whitemeas(
+ munki *p,
+ double *abswav1, /* Return array [nwav1] of abswav values (may be NULL) */
+ double *abswav2, /* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
+ double *absraw /* Given array [-1 nraw] of absraw values */
+);
+
+/* Take a reflective white reference measurement, */
+/* subtracts black and decompose into base + LED temperature components */
+munki_code munki_ledtemp_whitemeasure(
+ munki *p,
+ double *white, /* Return [-1 nraw] of temperature compensated white reference */
+ double **iwhite, /* Return array [-1 nraw][2] of absraw base and scale values */
+ double *reftemp, /* Return a reference temperature to normalize to */
+ int nummeas, /* Number of readings to take */
+ double inttime, /* Integration time to use */
+ int gainmode /* Gain mode to use, 0 = normal, 1 = high */
+);
+
+/* Given the ledtemp base and scale values, */
+/* return a raw reflective white reference for the */
+/* given temperature */
+munki_code munki_ledtemp_white(
+ munki *p,
+ double *absraw, /* Return array [-1 nraw] of absraw base and scale values */
+ double **iwhite, /* ledtemp base and scale */
+ double ledtemp /* LED temperature value */
+);
+
+/* Given a set of absraw sensor readings and the corresponding temperature, */
+/* compensate the readings to be at the nominated temperature. */
+munki_code munki_ledtemp_comp(
+ munki *p,
+ double **absraw, /* [nummeas][raw] measurements to compensate */
+ double *ledtemp, /* LED temperature for each measurement */
+ int nummeas, /* Number of measurements */
+ double reftemp, /* LED reference temperature to compensate to */
+ double **iwhite /* ledtemp base and scale information */
+);
+
+/* Heat the LED up for given number of seconds by taking a reading */
+munki_code munki_heatLED(
+ munki *p,
+ double htime /* Heat up time */
+);
+
+/* Process a single raw white reference measurement */
+/* (Subtracts black and processes into wavelenths) */
+munki_code munki_whitemeasure_buf(
+ munki *p,
+ double *abswav1, /* Return array [nwav1] of abswav values (may be NULL) */
+ double *abswav2, /* Return array [nwav2] of abswav values (if hr_init, may be NULL) */
+ double *absraw, /* Return array [-1 nraw] of absraw values */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ unsigned char *buf /* Raw buffer */
+);
+
+/* Take a measurement reading using the current mode, part 1 */
+/* Converts to completely processed output readings. */
+munki_code munki_read_patches_1(
+ munki *p,
+ int ninvmeas, /* Number of extra invalid measurements at start */
+ int minnummeas, /* Minimum number of measurements to take */
+ int maxnummeas, /* Maximum number of measurements to allow for */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ int *nmeasuered, /* Number actually measured (excluding ninvmeas) */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+);
+
+/* Take a measurement reading using the current mode, part 2 */
+/* Converts to completely processed output readings. */
+munki_code munki_read_patches_2(
+ munki *p,
+ double *duration, /* return flash duration (secs) */
+ double **specrd, /* Return array [numpatches][nwav] of spectral reading values */
+ int numpatches, /* Number of patches to return */
+ double inttime, /* Integration time to used */
+ int gainmode, /* Gain mode useed, 0 = normal, 1 = high */
+ int ninvmeas, /* Number of extra invalid measurements at start */
+ int nmeasuered, /* Number actually measured */
+ unsigned char *buf, /* Raw USB reading buffer */
+ unsigned int bsize
+);
+
+/* Take a trial measurement reading using the current mode. */
+/* Used to determine if sensor is saturated, or not optimal */
+munki_code munki_trialmeasure(
+ munki *p,
+ int *saturated, /* Return nz if sensor is saturated */
+ double *optscale, /* Factor to scale gain/int time by to make optimal */
+ int nummeas, /* Number of readings to take */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ double targoscale /* Optimal reading scale factor */
+);
+
+/* Trigger a single measurement cycle. This could be a dark calibration, */
+/* a calibration, or a real measurement. Used to create the higher */
+/* level "calibrate" and "take reading" functions. */
+/* The setup for the operation is in the current mode state. */
+/* The called then needs to call munki_readmeasurement() */
+munki_code
+munki_trigger_one_measure(
+ munki *p,
+ int nummeas, /* Number of measurements to make */
+ double *inttime, /* Integration time to use/used */
+ int gainmode, /* Gain mode to use, 0 = normal, 1 = high */
+ int calib_measure, /* flag - nz if this is a calibration measurement */
+ int dark_measure /* flag - nz if this is a dark measurement */
+);
+
+/* ============================================================ */
+/* lower level reading processing */
+
+/* Take a buffer full of sensor readings, and convert them to */
+/* directly to floating point raw values. */
+/* Return MUNKI_RD_SENSORSATURATED if any is saturated */
+munki_code munki_sens_to_raw(
+ munki *p,
+ double **raw, /* Array of [nummeas-ninvalid][-1 nraw] value to return */
+ double *ledtemp, /* Optional array [nummeas-ninvalid] LED temperature values to return */
+ unsigned char *buf, /* Sensor measurement data must be 274 * nummeas */
+ int nummeas, /* Number of readings measured */
+ int ninvalid, /* Number of initial invalid readings to skip */
+ double satthresh, /* Sauration threshold in raw units */
+ double *darkthresh /* Return a dark threshold value */
+);
+
+/* Subtract the black from raw values and convert to */
+/* absolute (integration & gain scaled), zero offset based, */
+/* linearized sensor values. */
+void munki_sub_raw_to_absraw(
+ munki *p,
+ int nummeas, /* Return number of readings measured */
+ double inttime, /* Integration time used */
+ int gainmode, /* Gain mode, 0 = normal, 1 = high */
+ double **absraw, /* Source/Desination array [-1 nraw] */
+ double *sub, /* Value to subtract [-1 nraw] */
+ double *trackmax, /* absraw values that should be offset the same as max */
+ int ntrackmax, /* Number of trackmax values */
+ double *maxv /* If not NULL, return the maximum value */
+);
+
+/* Average a set of sens or absens measurements into one. */
+/* (Make sure darkthresh is tracked if absens is being averaged!) */
+/* Return zero if readings are consistent and not saturated. */
+/* Return nz if the readings are not consistent */
+/* Return the overall average. */
+int munki_average_multimeas(
+ munki *p,
+ double *avg, /* return average [-1 nraw] */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to average */
+ int nummeas, /* number of readings to be averaged */
+ double *poallavg, /* If not NULL, return overall average of bands and measurements */
+ double darkthresh /* Dark threshold (used for consistency check scaling) */
+);
+
+/* Recognise the required number of ref/trans patch locations, */
+/* and average the measurements within each patch. */
+/* Return flags zero if readings are consistent. */
+/* Return flags nz if the readings are not consistent */
+munki_code munki_extract_patches_multimeas(
+ munki *p,
+ int *flags, /* return flags */
+ double **pavg, /* return patch average [naptch][-1 nraw] */
+ int npatch, /* number of patches to recognise */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to extract from */
+ int nummeas, /* number of readings to recognise them from */
+ double inttime /* Integration time (used to adjust consistency threshold) */
+);
+
+/* Recognise any flashes in the readings, and */
+/* and average their values together as well as summing their duration. */
+/* Return nz on an error */
+munki_code munki_extract_patches_flash(
+ munki *p,
+ int *flags, /* return flags */
+ double *duration, /* return duration */
+ double *pavg, /* return patch average [-1 nraw] */
+ double **multimeas, /* Array of [nummeas][-1 nraw] value to extract from */
+ int nummeas, /* number of readings made */
+ double inttime /* Integration time (used to compute duration) */
+);
+
+/* Convert an absraw array from raw wavelengths to output wavelenths */
+/* for the current resolution */
+void munki_absraw_to_abswav(
+ munki *p,
+ int nummeas, /* Return number of readings measured */
+ double **abswav, /* Desination array [nwav] */
+ double **absraw /* Source array [-1 nraw] */
+);
+
+/* Convert an absraw array from raw wavelengths to output wavelenths */
+/* for the standard resolution */
+void munki_absraw_to_abswav1(
+ munki *p,
+ int nummeas, /* Return number of readings measured */
+ double **abswav, /* Desination array [nwav1] */
+ double **absraw /* Source array [-1 nraw] */
+);
+
+/* Convert an absraw array from raw wavelengths to output wavelenths */
+/* for the high resolution */
+void munki_absraw_to_abswav2(
+ munki *p,
+ int nummeas, /* Return number of readings measured */
+ double **abswav, /* Desination array [nwav2] */
+ double **absraw /* Source array [-1 nraw] */
+);
+
+/* Convert an abswav array of output wavelengths to scaled output readings. */
+void munki_scale_specrd(
+ munki *p,
+ double **outspecrd, /* Destination */
+ int numpatches, /* Number of readings/patches */
+ double **inspecrd /* Source */
+);
+
+/* Convert from spectral to XYZ, and transfer to the ipatch array */
+munki_code munki_conv2XYZ(
+ munki *p,
+ ipatch *vals, /* Values to return */
+ int nvals, /* Number of values */
+ double **specrd, /* Spectral readings */
+ instClamping clamp /* Clamp XYZ/Lab to be +ve */
+);
+
+/* Compute a calibration factor given the reading of the white reference. */
+/* Return nz if any of the transmission wavelengths are low */
+int munki_compute_white_cal(
+ munki *p,
+ double *cal_factor1, /* [nwav1] Calibration factor to compute */
+ double *white_ref1, /* [nwav1] White reference to aim for, NULL for 1.0 */
+ double *white_read1, /* [nwav1] The white that was read */
+ double *cal_factor2, /* [nwav2] Calibration factor to compute */
+ double *white_ref2, /* [nwav2] White reference to aim for, NULL for 1.0 */
+ double *white_read2 /* [nwav2] The white that was read */
+);
+
+/* For adaptive mode, compute a new integration time and gain mode */
+/* in order to optimise the sensor values. */
+munki_code munki_optimise_sensor(
+ munki *p,
+ double *pnew_int_time,
+ int *pnew_gain_mode,
+ double cur_int_time,
+ int cur_gain_mode,
+ int permithg, /* nz to permit switching to high gain mode */
+ int permitclip, /* nz to permit clipping out of range int_time, else error */
+ double *targoscale, /* Optimising target scale ( <= 1.0) */
+ /* (May be altered if integration time isn't possible) */
+ double scale, /* scale needed of current int time to reach optimum */
+ double deadtime /* Dead integration time (if any) */
+);
+
+/* Compute the number of measurements needed, given the target */
+/* time and integration time. Will return 0 if target time is 0 */
+int munki_comp_nummeas(
+ munki *p,
+ double meas_time,
+ double int_time
+);
+
+/* Compute the rounded up number of measurements needed, */
+/* given the target time and integration time. */
+/* Will return 0 if target time is 0 */
+int munki_comp_ru_nummeas(
+ munki *p,
+ double meas_time,
+ double int_time
+);
+
+/* Convert the dark interpolation data to a useful state */
+void munki_prepare_idark(munki *p);
+
+/* Create the dark reference for the given integration time and gain */
+/* by interpolating from the 4 readings taken earlier. */
+munki_code munki_interp_dark(
+ munki *p,
+ double *result, /* Put result of interpolation here */
+ double inttime,
+ int gainmode
+);
+
+/* Create high resolution mode references. */
+/* Create Reflective if ref nz, else create Emissive */
+munki_code munki_create_hr(munki *p, int ref);
+
+/* Set the noinitcalib mode */
+void munki_set_noinitcalib(munki *p, int v, int losecs);
+
+/* Set the trigger config */
+void munki_set_trig(munki *p, inst_opt_type trig);
+
+/* Return the trigger config */
+inst_opt_type munki_get_trig(munki *p);
+
+/* Set the trigger return */
+void munki_set_trigret(munki *p, int val);
+
+/* Switch thread handler */
+int munki_switch_thread(void *pp);
+
+/* ============================================================ */
+/* Low level commands */
+
+/* USB Commands */
+
+/* Read from the EEProm */
+munki_code
+munki_readEEProm(
+ struct _munki *p,
+ unsigned char *buf, /* Where to read it to */
+ int addr, /* Address in EEprom to read from */
+ int size /* Number of bytes to read (max 65535) */
+);
+
+
+/* Get the firmware parameters */
+/* return pointers may be NULL if not needed. */
+munki_code
+munki_getfirm(
+ munki *p,
+ int *fwrev, /* Return the formware version number as 8.8 */
+ int *tickdur, /* Tick duration */
+ int *minintcount, /* Minimum integration tick count */
+ int *noeeblocks, /* Number of EEPROM blocks */
+ int *eeblocksize /* Size of each block */
+);
+
+/* Get the Chip ID */
+munki_code
+munki_getchipid(
+ munki *p,
+ unsigned char chipid[8]
+);
+
+/* Get the Version String */
+munki_code
+munki_getversionstring(
+ munki *p,
+ char vstring[37]
+);
+
+/* Get the measurement state */
+/* return pointers may be NULL if not needed. */
+munki_code
+munki_getmeasstate(
+ munki *p,
+ int *ledtrange, /* LED temperature range */
+ int *ledtemp, /* LED temperature */
+ int *dutycycle, /* Duty Cycle */
+ int *ADfeedback /* A/D converter feedback */
+);
+
+/* Munki sensor positions */
+typedef enum {
+ mk_spos_proj = 0x00, /* Projector/Between detents */
+ mk_spos_surf = 0x01, /* Surface */
+ mk_spos_calib = 0x02, /* Calibration tile */
+ mk_spos_amb = 0x03 /* Ambient */
+} mk_spos;
+
+/* Munki switch state */
+typedef enum {
+ mk_but_switch_release = 0x00, /* Button is released */
+ mk_but_switch_press = 0x01 /* Button is pressed */
+} mk_but;
+
+/* Get the device status */
+/* return pointers may be NULL if not needed. */
+munki_code
+munki_getstatus(
+ munki *p,
+ mk_spos *spos, /* Return the sensor position */
+ mk_but *but /* Return Button state */
+);
+
+/* Set the indicator LED state */
+munki_code
+munki_setindled(
+ munki *p,
+ int ontime, /* On time (msec) */
+ int offtrime, /* Off time (msec) */
+ int transtime, /* Transition time (msec) */
+ int nopulses, /* Number of pulses, -1 = max */
+ int p5 /* Ignored ? */
+);
+
+/* Measuremend mode flags */
+#define MUNKI_MMF_LAMP 0x01 /* Lamp mode, else no illumination of sample */
+#define MUNKI_MMF_SCAN 0x02 /* Scan mode bit, else spot mode */
+#define MUNKI_MMF_HIGHGAIN 0x04 /* High gain, else normal gain. */
+
+/* Trigger a measurement with the given measurement parameters */
+munki_code
+munki_triggermeasure(
+ munki *p,
+ int intclocks, /* Number of integration clocks */
+ int nummeas, /* Number of measurements to make */
+ int measmodeflags, /* Measurement mode flags */
+ int holdtempduty /* Hold temperature duty cycle */
+);
+
+/* Read a measurements results */
+munki_code
+munki_readmeasurement(
+ munki *p,
+ int inummeas, /* Initial number of measurements to expect */
+ int scanflag, /* NZ if in scan mode to continue reading */
+ unsigned char *buf, /* Where to read it to */
+ int bsize, /* Bytes available in buffer */
+ int *nummeas, /* Return number of readings measured */
+ int calib_measure, /* flag - nz if this is a calibration measurement */
+ int dark_measure /* flag - nz if this is a dark measurement */
+);
+
+/* Set the measurement clock mode */
+/* Version >= 301 only */
+munki_code
+munki_setmcmode(
+ munki *p,
+ int mcmode /* Measurement clock mode, 1..mxmcmode */
+);
+
+/* Munki event values, returned by event pipe, or */
+/* parameter to simulate event */
+typedef enum {
+ mk_eve_none = 0x0000, /* No event */
+ mk_eve_switch_press = 0x0001, /* Button has been pressed */
+ mk_eve_switch_release = 0x0002, /* Button has been released */
+ mk_eve_spos_change = 0x0100 /* Sensor position is being changed */
+} mk_eve;
+
+/* Simulating an event (use to terminate event thread) */
+/* timestamp is msec since munki power up */
+munki_code munki_simulate_event(munki *p, mk_eve ecode, int timestamp);
+
+/* Wait for a reply triggered by a key press */
+munki_code munki_waitfor_switch(munki *p, mk_eve *ecode, int *timest, double top);
+
+/* Wait for a reply triggered by a key press (thread version) */
+munki_code munki_waitfor_switch_th(munki *p, mk_eve *ecode, int *timest, double top);
+
+/* -------------------------------------------------- */
+/* EEProm parsing support. */
+
+/* Initialise the calibration from the EEProm contents. */
+/* (We're handed a buffer that's been rounded up to an even 32 bits by */
+/* padding with zero's) */
+munki_code munki_parse_eeprom(munki *p, unsigned char *buf, unsigned int len);
+
+struct _mkdata {
+ /* private: */
+ munki *p;
+
+ a1log *log;
+ unsigned char *buf; /* Buffer to parse */
+ int len; /* Length of buffer */
+
+ /* public: */
+
+ /* Return a pointer to an array of chars containing data from 8 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ unsigned char *(*get_8_char)(struct _mkdata *d, unsigned char *rv, int offset, int count);
+
+ /* Return a pointer to an nul terminated string containing data from 8 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ /* An extra space and a nul terminator will be added to the eeprom data */
+ char *(*get_8_asciiz)(struct _mkdata *d, char *rv, int offset, int count);
+
+
+ /* Return a pointer to an array of ints containing data from 8 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ int *(*get_8_ints)(struct _mkdata *d, int *rv, int offset, int count);
+
+ /* Return a pointer to an array of ints containing data from unsigned 8 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ int *(*get_u8_ints)(struct _mkdata *d, int *rv, int offset, int count);
+
+
+ /* Return a pointer to an array of ints containing data from 16 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ int *(*get_16_ints)(struct _mkdata *d, int *rv, int offset, int count);
+
+ /* Return a pointer to an array of ints containing data from unsigned 16 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ int *(*get_u16_ints)(struct _mkdata *d, int *rv, int offset, int count);
+
+
+ /* Return a pointer to an array of ints containing data from 32 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ int *(*get_32_ints)(struct _mkdata *d, int *rv, int offset, int count);
+
+ /* Return a pointer to an array of unsigned ints containing data from 32 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ unsigned int *(*get_u32_uints)(struct _mkdata *d, unsigned int *rv, int offset, int count);
+
+
+ /* Return a pointer to an array of doubles containing data from 32 bits. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ double *(*get_32_doubles)(struct _mkdata *d, double *rv, int offset, int count);
+
+ /* Return a pointer to an array of doubles containing data from 32 bits, */
+ /* with the array filled in reverse order. */
+ /* If rv is NULL, the returned value will have been allocated, othewise */
+ /* the rv will be returned. Return NULL if out of range. */
+ double *(*rget_32_doubles)(struct _mkdata *d, double *rv, int offset, int count);
+
+ /* Destroy ourselves */
+ void (*del)(struct _mkdata *d);
+
+}; typedef struct _mkdata mkdata;
+
+/* Constructor. Construct from the EEprom calibration contents */
+extern mkdata *new_mkdata(munki *p, unsigned char *buf, int len);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define MUNKI_IMP
+#endif /* MUNKI_IMP */
diff --git a/spectro/oemarch.c b/spectro/oemarch.c
new file mode 100644
index 0000000..733156e
--- /dev/null
+++ b/spectro/oemarch.c
@@ -0,0 +1,2610 @@
+
+ /* OEM archive access library. */
+ /* This supports installing OEM data files */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 13/11/2012
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#if defined (NT)
+#define WIN32_LEAN_AND_MEAN
+#include <io.h>
+#include <windows.h>
+#endif
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <ctype.h>
+#endif /* UNIX */
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include <fcntl.h>
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xdg_bds.h"
+#include "xspect.h"
+#include "conv.h"
+#include "aglob.h"
+#include "ccss.h"
+#include "LzmaDec.h"
+#include "oemarch.h"
+
+#undef DEBUG
+#undef PLOT_SAMPLES /* Plot spectral samples */
+
+/* Configured target information */
+oem_target oemtargs = {
+#ifdef NT
+ { /* Installed files */
+ { "/ColorVision/Spyder2express/CVSpyder.dll", targ_spyd_pld, file_dllcab },
+ { "/ColorVision/Spyder2pro/CVSpyder.dll", targ_spyd_pld, file_dllcab },
+ { "/PANTONE COLORVISION/ColorPlus/CVSpyder.dll", targ_spyd_pld, file_dllcab },
+ { "/Datacolor/Spyder4Express/dccmtr.dll", targ_spyd_cal, file_dllcab },
+ { "/Datacolor/Spyder4Pro/dccmtr.dll", targ_spyd_cal, file_dllcab },
+ { "/Datacolor/Spyder4Elite/dccmtr.dll", targ_spyd_cal, file_dllcab },
+ { "/Datacolor/Spyder4TV HD/dccmtr.dll", targ_spyd_cal, file_dllcab },
+ { "/X-Rite/Devices/i1d3/Calibrations/*.edr", targ_i1d3_edr, file_data },
+ { NULL }
+ },
+ { /* Volume names */
+ { "ColorVision", targ_spyd_pld | targ_spyd_cal },
+ { "Datacolor", targ_spyd_pld | targ_spyd_cal },
+ { "i1Profiler", targ_i1d3_edr },
+ { "ColorMunki Displ", targ_i1d3_edr },
+ { NULL }
+ },
+ { /* Archive names */
+ { "/setup/setup.exe", targ_spyd_pld },
+ { "/Data/setup.exe", targ_spyd_cal },
+ { "/Installer/Setup.exe", targ_i1d3_edr },
+ { "/Installer/ColorMunkiDisplaySetup.exe", targ_i1d3_edr },
+ { NULL }
+ }
+#endif /* NT */
+#ifdef __APPLE__
+ { /* Installed files */
+ { "/Applications/Spyder2express 2.2/Spyder2express.app/Contents/MacOSClassic/Spyder.lib", targ_spyd_pld },
+ { "/Applications/Spyder2pro 2.2/Spyder2pro.app/Contents/MacOSClassic/Spyder.lib", targ_spyd_pld },
+
+ { "/Library/Application Support/X-Rite/Devices/i1d3xrdevice/Contents/Resources/Calibrations/*.edr", targ_i1d3_edr },
+ { NULL }
+ },
+ { /* Volume names */
+ { "/Volumes/ColorVision", targ_spyd_pld | targ_spyd_cal },
+ { "/Volumes/Datacolor", targ_spyd_pld | targ_spyd_cal },
+ { "/Volumes/i1Profiler", targ_i1d3_edr },
+ { "/Volumes/ColorMunki Display", targ_i1d3_edr },
+ { NULL }
+ },
+ { /* Archive names */
+ { "/setup/setup.exe", targ_spyd_pld },
+ { "/Data/setup.exe", targ_spyd_cal },
+ { "/Installer/Setup.exe", targ_i1d3_edr },
+ { "/Installer/ColorMunkiDisplaySetup.exe", targ_i1d3_edr },
+ { NULL }
+ }
+#endif /* __APPLE__ */
+#ifdef UNIX_X11
+ { /* Installed files */
+ { NULL }
+ },
+ { /* Volume names the CDROM may have */
+ { "/media/ColorVision", targ_spyd_pld | targ_spyd_cal },
+ { "/media/Datacolor", targ_spyd_pld | targ_spyd_cal },
+ { "/media/i1Profiler", targ_i1d3_edr },
+ { "/media/ColorMunki Displ", targ_i1d3_edr },
+ { "/mnt/cdrom", targ_spyd_pld | targ_spyd_cal | targ_i1d3_edr },
+ { "/mnt/cdrecorder", targ_spyd_pld | targ_spyd_cal | targ_i1d3_edr },
+ { "/media/cdrom", targ_spyd_pld | targ_spyd_cal | targ_i1d3_edr },
+ { "/media/cdrecorder", targ_spyd_pld | targ_spyd_cal | targ_i1d3_edr },
+ { "/cdrom", targ_spyd_pld | targ_spyd_cal | targ_i1d3_edr },
+ { "/cdrecorder", targ_spyd_pld | targ_spyd_cal | targ_i1d3_edr },
+ { NULL }
+ },
+ { /* Archive names */
+ { "/setup/setup.exe", targ_spyd_pld },
+ { "/Data/setup.exe", targ_spyd_cal },
+ { "/Installer/Setup.exe", targ_i1d3_edr },
+ { "/Installer/ColorMunkiDisplaySetup.exe", targ_i1d3_edr },
+ { NULL }
+ }
+#endif /* UNIX_X11 */
+};
+
+#if defined(__APPLE__)
+/* Global: */
+char *oemamount_path = NULL;
+#endif
+
+/* Cleanup function for transfer on Apple OS X */
+void oem_umiso() {
+#if defined(__APPLE__)
+ if (oemamount_path != NULL) {
+ char sbuf[MAXNAMEL+1 + 100];
+ sprintf(sbuf, "umount \"%s\"",oemamount_path);
+ system(sbuf);
+ sprintf(sbuf, "rmdir \"%s\"",oemamount_path);
+ system(sbuf);
+ }
+#endif /* __APPLE__ */
+}
+
+static xfile *locate_volume(int verb);
+static xfile *locate_read_archive(xfile *vol, int verb);
+static xfile *locate_read_oeminstall(xfile **pxf, int verb);
+
+void classify_file(xfile *xf, int verb);
+
+/* Spyder related archive functions */
+int is_vise(xfile *xf);
+int is_dll(xfile *xf);
+static xfile *vise_extract(xfile **pxf, xfile *xi, char *tfilename, int verb);
+static xfile *spyd2pld_extract(xfile **pxf, xfile *dll, int verb);
+static xfile *spyd4cal_extract(xfile **pxf, xfile *dll, int verb);
+int is_s2pld(xfile *xf);
+int is_s4cal(xfile *xf);
+
+/* i1d3 archive related functions */
+int is_inno(xfile *xf);
+int is_cab(xfile *xf);
+static xfile *inno_extract(xfile *xi, char *tfilename, int verb);
+static xfile *msi_extract(xfile **pxf, xfile *xi, char *tname, int verb);
+static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb);
+
+/* edr to ccss functions */
+int is_edr(xfile *xf);
+static xfile *edr_convert(xfile **pxf, xfile *xi, int verb);
+int is_ccss(xfile *xf);
+
+/* ccmx functions */
+int is_ccmx(xfile *xf);
+
+#ifdef DEBUG
+static void list_files(char *s, xfile *xf) {
+ int i;
+
+ if (xf == NULL)
+ printf("%s: no files\n",s);
+ else {
+ printf("%s:\n",s);
+ for (i = 0; xf[i].name != NULL; i++) {
+ printf("Got '%s' size %d ftype 0x%x ttype 0x%x\n",xf[i].name,xf[i].len,xf[i].ftype,xf[i].ttype);
+// save_xfile(&xf[i], NULL, "oem/", 1);
+ }
+ }
+}
+#endif
+
+/* Given a list of source archives or files, convert them to a list of install files, */
+/* or if no files are given look for installed files or files from a CD. */
+/* Return NULL if none found. files is deleted. */
+xfile *oemarch_get_ifiles(xfile *files, int verb) {
+ int i;
+ xfile *ofiles, *nfiles = NULL; /* Ping pong */
+
+#ifdef DEBUG
+ list_files("On entry", files);
+#endif
+
+ /* Classify the files we've been given */
+ if (files != NULL) {
+ for (i = 0; files[i].name != NULL; i++) {
+ classify_file(&files[i], verb);
+ }
+#ifdef DEBUG
+ list_files("After classification",files);
+#endif
+ }
+
+
+ /* See if there are any OEM files installed */
+ if (files == NULL) {
+
+ locate_read_oeminstall(&files, verb);
+
+#ifdef DEBUG
+ list_files("OEM Installed files", files);
+#endif
+ }
+
+ if (files == NULL) {
+ /* Look for files on a CD */
+ xfile *vol; /* CD volume located */
+
+ if ((vol = locate_volume(verb)) == NULL) {
+ return NULL;
+ }
+
+ if ((files = locate_read_archive(vol, verb)) == NULL) {
+ oem_umiso();
+ return NULL;
+ }
+ oem_umiso();
+ del_xf(vol); vol = NULL;
+
+#ifdef DEBUG
+ list_files("CD files", files);
+#endif
+ }
+
+ if (files == NULL)
+ return NULL;
+
+ /* Now process any archives - extract dll & cab's */
+ for (i = 0; files[i].name != NULL; i++) {
+ xfile *arch = files + i;
+
+ /* Preserve & skip non-archives */
+ if (files[i].ftype != file_arch) {
+ new_add_xf(&nfiles, files[i].name, files[i].buf, files[i].len,
+ files[i].ftype, files[i].ttype);
+ files[i].buf = NULL; /* We've taken these */
+ files[i].len = 0;
+ continue;
+ }
+
+ /* If this could be spyder 2 PLD pattern: */
+ if (arch->ttype & targ_spyd_pld) {
+ xfile *dll = NULL; /* dccmtr.dll */
+
+ if (vise_extract(&nfiles, arch, "CVSpyder.dll", verb) != NULL)
+ continue;
+ }
+
+ /* If this could be spyder 4 calibration file: */
+ if (arch->ttype & targ_spyd_cal) {
+ xfile *dll = NULL; /* dccmtr.dll */
+
+ if (vise_extract(&nfiles, arch, "dccmtr.dll", verb) != NULL)
+ continue;
+ }
+
+ /* If this could be i1d3 .edr files: */
+ if (arch->ttype & targ_i1d3_edr) {
+ xfile *msi = NULL; /* .msi */
+
+#ifdef NEVER /* Don't have to do it this way */
+ /* Extract .msi from it */
+ if ((msi = inno_extract(arch, "{tmp}\\XRD i1d3.msi", verb)) != NULL) {
+
+ /* Extract the .cab from it */
+ if (msi_extract(&nfiles, msi, "XRD_i1d3.cab", verb) != NULL) {
+ del_xf(msi);
+ continue;
+ }
+ del_xf(msi);
+ }
+#else
+ /* Extract the .cab directly from Setup.exe */
+ if (msi_extract(&nfiles, arch, "XRD_i1d3.cab", verb) != NULL)
+ continue;
+ if (msi_extract(&nfiles, arch, "XRD_Manager.cab", verb) != NULL)
+ continue;
+#endif
+ }
+ if (verb) printf("Warning: unhandled '%s' discarded\n",arch->name);
+ }
+ ofiles = files; /* Swap to new list */
+ files = nfiles;
+ del_xf(ofiles);
+ nfiles = NULL;
+
+#ifdef DEBUG
+ list_files("After de-archive", files);
+#endif
+
+ if (files == NULL)
+ return NULL;
+
+ /* Process any dll & cab files - extract individual files */
+ for (i = 0; files[i].name != NULL; i++) {
+ xfile *dllcab = files + i;
+
+ /* Preserve non-dll/cab */
+ if (files[i].ftype != file_dllcab) {
+ new_add_xf(&nfiles, files[i].name, files[i].buf, files[i].len,
+ files[i].ftype, files[i].ttype);
+ files[i].buf = NULL; /* We've taken these */
+ files[i].len = 0;
+ continue;
+ }
+
+ /* If this could be spyder 2 PLD pattern: */
+ if (dllcab->ttype & targ_spyd_pld) {
+
+ if (spyd2pld_extract(&nfiles, dllcab, verb) != NULL)
+ continue;
+ }
+
+ /* If this could be spyder 4 calibration file: */
+ if (dllcab->ttype & targ_spyd_cal) {
+
+ if (spyd4cal_extract(&nfiles, dllcab, verb) != NULL)
+ continue;
+ }
+
+ /* If this could be i1d3 .edr files: */
+ if (dllcab->ttype & targ_i1d3_edr) {
+
+ /* Extract the .edr's from it */
+ if (cab_extract(&nfiles, dllcab, ".edr", verb) != NULL)
+ continue;
+ }
+ if (verb) printf("Warning: unhandled '%s' discarded\n",dllcab->name);
+ }
+ ofiles = files; /* Swap to new list */
+ files = nfiles;
+ del_xf(ofiles);
+ nfiles = NULL;
+
+#ifdef DEBUG
+ list_files("After file extract", files);
+#endif
+
+ if (files == NULL)
+ return NULL;
+
+ /* Process any .edr files - convert to ccss */
+ for (i = 0; files[i].name != NULL; i++) {
+
+ /* Preserve non-edr */
+ if (files[i].ftype != file_data
+ || (files[i].ttype & targ_i1d3_edr) == 0
+ || !is_edr(&files[i])
+ ) {
+ new_add_xf(&nfiles, files[i].name, files[i].buf, files[i].len,
+ files[i].ftype, files[i].ttype);
+ files[i].buf = NULL; /* We've taken these */
+ files[i].len = 0;
+ continue;
+ }
+ if (edr_convert(&nfiles, files + i, verb) != NULL)
+ continue;
+
+ if (verb) printf("Warning: unhandled '%s' discarded\n",files[i].name);
+ }
+ ofiles = files; /* Swap to new list */
+ files = nfiles;
+ del_xf(ofiles);
+ nfiles = NULL;
+
+#ifdef DEBUG
+ list_files("Returning", files);
+ printf("\n");
+#endif
+
+ return files;
+}
+
+/* -------------------------------------------- */
+/* Determine a file type */
+
+void classify_file(xfile *xf, int verb) {
+ if (is_dll(xf)) {
+ xf->ftype = file_dllcab;
+ xf->ttype &= (targ_spyd_pld | targ_spyd_cal);
+ if (verb) printf("'%s' seems to be a .dll file\n",xf->name);
+ return;
+ }
+ if (is_vise(xf)) {
+ xf->ftype = file_arch;
+ xf->ttype &= (targ_spyd_pld | targ_spyd_cal);
+ if (verb) printf("'%s' seems to be a VISE archive\n",xf->name);
+ return;
+ }
+ if (is_inno(xf)) {
+ xf->ftype = file_arch;
+ xf->ttype &= targ_i1d3_edr;
+ if (verb) printf("'%s' seems to be an Inno archive\n",xf->name);
+ return;
+ }
+ if (is_cab(xf)) {
+ xf->ftype = file_dllcab;
+ xf->ttype &= targ_i1d3_edr;
+ if (verb) printf("'%s' seems to be a .cab file\n",xf->name);
+ return;
+ }
+ if (is_edr(xf) || is_ccss(xf)) {
+ xf->ftype = file_data;
+ xf->ttype &= targ_i1d3_edr;
+ if (verb) printf("'%s' seems to be a i1d3 calibration file or .ccss\n",xf->name);
+ return;
+ }
+ if (is_ccmx(xf)) {
+ xf->ftype = file_data;
+ xf->ttype &= targ_ccmx;
+ if (verb) printf("'%s' seems to be a .ccmx\n",xf->name);
+ return;
+ }
+ if (is_s2pld(xf)) {
+ xf->ftype = file_data;
+ xf->ttype &= targ_spyd_pld;
+ if (verb) printf("'%s' seems to be a Spyder 2 PLD file\n",xf->name);
+ return;
+ }
+ if (is_s4cal(xf)) {
+ xf->ftype = file_data;
+ xf->ttype &= targ_spyd_cal;
+ if (verb) printf("'%s' seems to be a Spyder 4 calibration file\n",xf->name);
+ return;
+ }
+ /* Hmm. */
+ if (verb) printf("'%s' is unknown\n",xf->name);
+ xf->ftype = file_arch | file_dllcab | file_data;
+}
+
+/* ============================================================================= */
+
+/* Locate a CD volume. Return NULL if no CD found */
+/* free when done */
+static xfile *locate_volume(int verb) {
+ xfile *xf = NULL; /* return value */
+
+ if (verb) { printf("Looking for CDROM to install from .. \n"); fflush(stdout); }
+
+#ifdef NT
+ {
+ char buf[1000];
+ char vol_name[MAXNAMEL+1] = { '\000' };
+ char drive[50];
+ int len, i, j;
+
+ len = GetLogicalDriveStrings(1000, buf);
+ if (len > 1000)
+ error("GetLogicalDriveStrings too large");
+ for (i = 0; ;) { /* For all drives */
+ if (buf[i] == '\000')
+ break;
+ if (GetDriveType(buf+i) == DRIVE_CDROM) {
+ DWORD maxvoll, fsflags;
+ if (GetVolumeInformation(buf + i, vol_name, MAXNAMEL,
+ NULL, &maxvoll, &fsflags, NULL, 0) != 0) {
+ for (j = 0;;j++) { /* For all volume names */
+ if (oemtargs.volnames[j].path == NULL)
+ break;
+ if (strcmp(vol_name, oemtargs.volnames[j].path) == 0) {
+ strcpy(drive, buf+i);
+ drive[2] = '\000'; /* Remove '\' */
+ /* Found the instalation CDROM volume name */
+ new_add_xf(&xf, drive, NULL, 0, file_vol, oemtargs.volnames[j].ttype);
+ if (verb)
+ printf("Found Volume '%s' on drive '%s'\n",vol_name,drive);
+ break;
+ }
+ }
+ if (oemtargs.volnames[j].path != NULL) /* Found a match */
+ break;
+ }
+ }
+ i += strlen(buf + i) + 1;
+ }
+ }
+#endif /* NT */
+
+#if defined(__APPLE__)
+ {
+ int j;
+ char tname[MAXNAMEL+1] = { '\000' };
+
+ for (j = 0; ; j++) {
+ if (oemtargs.volnames[j].path == NULL)
+ break;
+
+ /* In case it's already mounted (previously aborted ?) */
+ strcpy(tname, oemtargs.volnames[j].path);
+ strcat(tname, "_ISO");
+ if (oemamount_path == NULL) { /* Remember to unmount it */
+ if ((oemamount_path = strdup(tname)) == NULL)
+ error("Malloc of amount_path failed");
+ }
+ if (verb) { printf("Checking if '%s' is already mounted .. ",tname); fflush(stdout); }
+ if (access(tname, 0) == 0) {
+ if (verb) printf("yes\n");
+ new_add_xf(&xf, tname, NULL, 0, file_vol, oemtargs.volnames[j].ttype);
+ break;
+ } else if (verb)
+ printf("no\n");
+
+ /* Not already mounted. */
+ if (access(oemtargs.volnames[j].path, 0) == 0) {
+ struct statfs buf;
+ char sbuf[MAXNAMEL+1 + 100];
+ int sl, rv;
+ if (verb) { printf("Mounting ISO partition .. "); fflush(stdout); }
+
+ /* but we need the ISO partition */
+ /* Locate the mount point */
+ if (statfs(oemtargs.volnames[j].path, &buf) != 0)
+ error("\nUnable to locate mount point for '%s' of install CDROM",oemtargs.volnames[j].path);
+ if ((sl = strlen(buf.f_mntfromname)) > 3
+ && buf.f_mntfromname[sl-2] == 's'
+ && buf.f_mntfromname[sl-1] >= '1'
+ && buf.f_mntfromname[sl-1] <= '9')
+ buf.f_mntfromname[sl-2] = '\000';
+ else
+ error("\nUnable to determine CDROM mount point from '%s'",buf.f_mntfromname);
+
+ strcpy(tname, oemtargs.volnames[j].path);
+ strcat(tname, "_ISO");
+ sprintf(sbuf, "mkdir \"%s\"", tname);
+ if ((rv = system(sbuf)) != 0)
+ error("\nCreating ISO9660 volume of CDROM failed with %d",rv);
+ sprintf(sbuf, "mount_cd9660 %s \"%s\"", buf.f_mntfromname,tname);
+ if ((rv = system(sbuf)) != 0) {
+ sprintf(sbuf, "rmdir \"%s\"", tname);
+ system(sbuf);
+ error("\nMounting ISO9660 volume of CDROM failed with %d",rv);
+ }
+ if (verb)
+ printf("done\n");
+ if ((oemamount_path = strdup(tname)) == NULL) {
+ oem_umiso();
+ error("Malloc of amount_path failed");
+ }
+ new_add_xf(&xf, tname, NULL, 0, file_vol, oemtargs.volnames[j].ttype);
+ break;
+ }
+ }
+ }
+#endif /* __APPLE__ */
+
+#if defined(UNIX_X11)
+ {
+ int j;
+
+ /* See if we can see what we're looking for on one of the volumes */
+ /* It would be nice to be able to read the volume name ! */
+ for (j = 0;;j++) {
+ if (oemtargs.volnames[j].path == NULL)
+ break;
+
+ if (access(oemtargs.volnames[j].path, 0) == 0) {
+ if (verb) printf("found '%s'\n",oemtargs.volnames[j].path);
+ new_add_xf(&xf, oemtargs.volnames[j].path, NULL, 0,
+ file_vol, oemtargs.volnames[j].ttype);
+ break;
+ }
+ }
+ }
+#endif /* UNIX */
+
+ return xf;
+}
+
+/* Locate and read the archive on the given volume. */
+/* Return NULL if not found */
+static xfile *locate_read_archive(xfile *vol, int verb) {
+ int j;
+ char buf[1000], *ap;
+ xfile *xf = NULL; /* return value */
+
+ if (verb) { printf("Looking for archive on volume '%s' .. ",vol->name); fflush(stdout); }
+
+ strcpy(buf, vol->name);
+ ap = buf + strlen(buf);
+
+ for (j = 0; oemtargs.archnames[j].path != NULL; j++) {
+ targ_type ttype = vol->ttype & oemtargs.archnames[j].ttype;
+
+ if (ttype == targ_none) {
+ continue;
+ }
+
+ strcpy(ap, oemtargs.archnames[j].path);
+ if (sys_access(buf, 0) == 0) {
+ if (verb) printf("found\n");
+ new_add_xf(&xf, buf, NULL, 0, file_arch, ttype);
+ if (load_xfile(xf, verb))
+ error("Failed to load file '%s'",xf->name);
+ xf->ftype = file_arch;
+ xf->ttype = oemtargs.archnames[j].ttype & vol->ttype;
+ break;
+ }
+ }
+ if (verb && oemtargs.archnames[j].path == NULL)
+ printf("not found\n");
+
+ return xf;
+}
+
+/* Locate and read any OEM install files. */
+/* Return NULL if not found */
+static xfile *locate_read_oeminstall(xfile **pxf, int verb) {
+ int j;
+ char tname[1000], *pf, *ap;
+ xfile *xf = NULL; /* return value */
+ aglob ag;
+
+ if (verb) { printf("Looking for OEM install files .. \n"); fflush(stdout); }
+
+ tname[0] = '\000';
+
+#ifdef NT
+ /* Where the normal instalation goes */
+ if ((pf = getenv("PROGRAMFILES")) != NULL)
+ strcpy(tname, pf);
+ else
+ strcpy(tname, "C:/Program Files");
+#endif /* NT */
+
+ ap = tname + strlen(tname);
+
+ for (j = 0; oemtargs.instpaths[j].path != NULL; j++) {
+
+ strcpy(ap, oemtargs.instpaths[j].path);
+
+ if (verb) printf("Looking for '%s'\n",tname);
+
+ if (aglob_create(&ag, tname))
+ error("Searching for '%s' malloc error",oemtargs.instpaths[j].path);
+
+ for (;;) {
+ char *pp;
+ if ((pp = aglob_next(&ag)) == NULL)
+ break;
+ xf = new_add_xf(&xf, pp, NULL, 0, oemtargs.archnames[j].ftype,
+ oemtargs.archnames[j].ttype);
+ if (load_xfile(xf, verb))
+ error("Failed to load file '%s'",xf->name);
+ }
+ aglob_cleanup(&ag);
+ }
+ return xf;
+}
+
+/* ============================================================================= */
+/* A list of files stored in memory. The last entry of the list has name == NULL */
+
+/* return a list with the given number of available entries */
+xfile *new_xf(int n) {
+ xfile *l;
+
+ if ((l = (xfile *)calloc((n + 1), sizeof(xfile))) == NULL)
+ error("new_xf: Failed to allocate xfile structure");
+
+ return l;
+}
+
+/* Add an entry to the list. Create the list if it is NULL */
+/* Return point to that entry */
+xfile *add_xf(xfile **l) {
+ int n;
+ xfile *ll;
+
+ if (*l == NULL)
+ *l = new_xf(0);
+
+ /* Count number of existing entries */
+ for (ll = *l, n = 0; ll->name != NULL; ll++, n++)
+ ;
+
+ if ((*l = (xfile *)realloc(*l, (n+2) * sizeof(xfile))) == NULL)
+ error("new_xf: Failed to realloc xfile structure");
+ (*l)[n+1].name = NULL; /* End marker */
+ (*l)[n+1].buf = NULL;
+ (*l)[n+1].len = 0;
+ (*l)[n+1].ftype = 0;
+ (*l)[n+1].ttype = 0;
+
+ return &(*l)[n];
+}
+
+/* Add an entry and copy details to the list. Create the list if it is NULL */
+/* Return point to that entry */
+xfile *new_add_xf(xfile **pxf, char *name, unsigned char *buf, unsigned long len,
+ file_type ftype, targ_type ttype) {
+ xfile *xf;
+ xf = add_xf(pxf);
+ if ((xf->name = strdup(name)) == NULL)
+ error("new_add_xf: strdup failed");
+ xf->buf = buf;
+ xf->len = len;
+ xf->ftype = ftype;
+ xf->ttype = ttype;
+ return xf;
+}
+
+/* Free up a whole list */
+void del_xf(xfile *l) {
+ int n;
+
+ if (l != NULL) {
+ for (n = 0; l[n].name != NULL; n++) {
+ if (l[n].name != NULL)
+ free(l[n].name);
+ if (l[n].buf != NULL)
+ free(l[n].buf);
+ }
+ free(l);
+ }
+}
+
+/* Allocate and load the given entry. */
+/* Return NZ on error */
+int load_xfile(xfile *xf, int verb) {
+ FILE *fp;
+ int i, nfiles;
+ unsigned char *ibuf;
+ unsigned long ilen, bread;
+
+ if (verb) { printf("Loading file '%s'..",xf->name); fflush(stdout); }
+
+ /* Open up the file for reading */
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(xf->name,"rb")) == NULL)
+#else
+ if ((fp = fopen(xf->name,"r")) == NULL)
+#endif
+ {
+ if (verb) printf("fopen '%s' failed\n",xf->name);
+ return 1;
+ }
+
+ /* Figure out how big it is */
+ if (fseek(fp, 0, SEEK_END)) {
+ if (verb) printf("fseek to EOF of '%s' failed\n",xf->name);
+ return 1;
+ }
+
+ ilen = (unsigned long)ftell(fp);
+
+ if (verb > 1) printf("Size of file '%s' is %ld bytes\n",xf->name, ilen);
+
+ if (fseek(fp, 0, SEEK_SET)) {
+ if (verb) printf("fseek to SOF of file '%s' failed\n",xf->name);
+ return 1;
+ }
+
+ if ((ibuf = (unsigned char *)malloc(ilen)) == NULL)
+ error("\nmalloc buffer for file '%s' failed",xf->name);
+
+ if (verb > 1) printf("(Reading file '%s')\n",xf->name);
+
+ if ((bread = fread(ibuf, 1, ilen, fp)) != ilen) {
+ if (verb) printf("Failed to read file '%s', read %ld out of %ld bytes\n",xf->name,bread,ilen);
+ return 1;
+ }
+
+ fclose(fp);
+
+ if (xf->buf != NULL)
+ free(xf->buf);
+ xf->buf = ibuf;
+ xf->len = ilen;
+
+ if (verb) printf("done\n");
+
+ return 0;
+}
+
+/* Save a file to the given sname, or of it is NULL, */
+/* to prefix + xf-file name (path is ignored) */
+/* Error on failure */
+void save_xfile(xfile *xf, char *sname, char *pfx, int verb) {
+ FILE *fp;
+ char *cp, *fname;
+ size_t len;
+
+ if (sname != NULL) {
+ fname = sname;
+ } else {
+ if ((cp = strrchr(xf->name, '/')) == NULL
+ && (cp = strrchr(xf->name, '\\')) == NULL)
+ cp = xf->name;
+ else
+ cp++;
+
+ len = strlen(pfx) + strlen(cp) + 1;
+ if ((fname = malloc(len)) == NULL)
+ error("malloc fname %d bytes failed",len);
+ strcpy(fname, pfx);
+ strcat(fname, cp);
+ }
+
+ /* Open up the file for writing */
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(fname,"wb")) == NULL)
+#else
+ if ((fp = fopen(fname,"w")) == NULL)
+#endif
+ error("Can't open file '%s' for writing",fname);
+
+ if ((fwrite(xf->buf, 1, xf->len, fp)) != xf->len)
+ error("Failed to write file '%s'",fname);
+
+ if (fclose(fp))
+ error("Failed to close file '%s' after writing",fname);
+
+ if (verb) printf("Wrote '%s' %ld bytes\n",fname, xf->len);
+
+ if (sname == NULL)
+ free(fname);
+}
+
+/* ============================================================================= */
+/* VISE archive file extraction */
+
+/* structure holding the VISE archive information */
+struct _visearch {
+ int verb;
+ int isvise; /* Is this an archive ? */
+ unsigned int vbase; /* Base address of archive */
+ unsigned char *abuf; /* Buffer holding archive file */
+ unsigned int asize; /* Nuber of bytes in file */
+ unsigned int off; /* Current offset */
+ unsigned char *dbuf; /* Room for decompressed driver file */
+ unsigned int dsize; /* current write location/size of decompressed file */
+ unsigned int dasize; /* current allocated size of dbuf */
+
+ /* Locate the given name, and set the offset */
+ /* to the locatation the compressed data is at */
+ /* return nz if not located */
+ int (*locate_file)(struct _visearch *p, char *name);
+
+ /* Set the current file offset */
+ void (*setoff)(struct _visearch *p, unsigned int off);
+
+ /* Get the next (big endian) 16 bits from the archive */
+ /* return 0 if past the end of the file */
+ unsigned int (*get16)(struct _visearch *p);
+
+ /* Unget 16 bytes */
+ void (*unget16)(struct _visearch *p);
+
+ /* Destroy ourselves */
+ void (*del)(struct _visearch *p);
+
+}; typedef struct _visearch visearch;
+
+static void del_arch(visearch *p) {
+ if (p->dbuf != NULL)
+ free(p->dbuf);
+ free(p);
+}
+
+/* Set the current file offset */
+static void setoff_arch(visearch *p, unsigned int off) {
+ if (off >= p->asize)
+ off = p->asize-1;
+ p->off = off;
+}
+
+/* Locate the given name, and set the offset */
+/* to the locatation the compressed data is at */
+/* return nz if not located */
+static int locate_file_arch(visearch *p, char *name) {
+ int i, sl;
+
+ sl = strlen(name); /* length excluding null */
+
+ if (sl == 0)
+ return 1;
+
+ /* Locate the filname with a search */
+ for (i = 0x10000; i < (p->asize - sl); i++) {
+ if (p->abuf[i] == name[0]) {
+ if (strncmp((char *)&p->abuf[i], name, sl) == 0) {
+ int sto;
+ /* Found it */
+ if (p->verb)
+ printf("Located driver entry '%s' at offset 0x%x\n",name,i);
+ i += sl;
+ if (i >= (p->asize - 1))
+ return 1;
+ sto = p->abuf[i];
+ i += (4 + sto) * 4; /* This is a complete hack. */
+ if (i >= (p->asize - 4))
+ return 1;
+ p->off = p->abuf[i + 0];
+ p->off += (p->abuf[i + 1] << 8);
+ p->off += (p->abuf[i + 2] << 16);
+ p->off += (p->abuf[i + 3] << 24);
+ p->off += p->vbase;
+ if (p->off >= p->asize - 10)
+ return 1;
+ if (p->verb)
+ printf("Located driver file '%s' at offset 0x%x\n",name,p->off);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+/* Get the next (big endian) 16 bits from the archive */
+/* return 0 if past the end of the file */
+static unsigned int get16_arch(visearch *p) {
+ unsigned int val;
+
+ if (p->off >= (p->asize-1)) {
+ error("Went past end of archive");
+ }
+
+ val = (0xff & p->abuf[p->off]);
+ val = ((val << 8) + (0xff & p->abuf[p->off+1]));
+ p->off += 2;
+ return val;
+}
+
+/* Unget the 16 bits from the archive. */
+static void unget16_arch(visearch *p) {
+
+ if (p->off > 1)
+ p->off -= 2;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Interface with vinflate.c */
+
+int vinflate(void);
+
+visearch *g_va = NULL;
+
+/* fetch the next 16 bits, big endian */
+/* if we get 0xffffffff, we are at EOF */
+unsigned int vget_16bits() {
+ return get16_arch(g_va);
+}
+
+/* unget 16 bits */
+void vunget_16bits() {
+ unget16_arch(g_va);
+}
+
+/* Save the decompressed file to the buffer */
+int vwrite_output(unsigned char *buf, unsigned int len) {
+
+ /* If run out of space */
+ if ((g_va->dsize + len) >= g_va->dasize) {
+ size_t nlen = g_va->dsize + len;
+
+ /* Round up allocation */
+ if (nlen <= 1024)
+ nlen += 1024;
+ else
+ nlen += 4096;
+
+ if ((g_va->dbuf = realloc(g_va->dbuf, nlen)) == NULL)
+ error("realloc failed on VISE decompress buffer (%d bytes)",nlen);
+
+ g_va->dasize = nlen;
+ }
+ memmove(g_va->dbuf + g_va->dsize, buf, len);
+ g_va->dsize += len;
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return NZ if the file appears to be a VISE archive */
+int is_vise(xfile *xf) {
+ int i;
+
+ /* See if it looks like a VIZE archive */
+ for (i = 0x10000; i < 0x11000 && i < (xf->len-4); i++) {
+ if (xf->buf[i + 3] == 'V'
+ && xf->buf[i + 2] == 'I'
+ && xf->buf[i + 1] == 'S'
+ && xf->buf[i + 0] == 'E') {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* create an archive from given memory data */
+/* Return NULL if it is not a VISE archive */
+visearch *new_arch(unsigned char *abuf, unsigned int asize, int verb) {
+ int i, rv = 0;
+ visearch *p;
+
+ if ((p = (visearch *)calloc(sizeof(visearch),1)) == NULL)
+ error("Malloc failed!");
+
+ p->locate_file = locate_file_arch;
+ p->setoff = setoff_arch;
+ p->verb = verb;
+ p->get16 = get16_arch;
+ p->unget16 = unget16_arch;
+ p->del = del_arch;
+ p->abuf = abuf;
+ p->asize = asize;
+
+ /* See if it looks like a VIZE archive */
+ for (i = 0x10000; i < 0x11000 && i < (p->asize-4); i++) {
+ if (p->abuf[i + 3] == 'V'
+ && p->abuf[i + 2] == 'I'
+ && p->abuf[i + 1] == 'S'
+ && p->abuf[i + 0] == 'E') {
+ p->isvise = 1;
+ p->vbase = i;
+ }
+ }
+
+ if (!p->isvise) {
+ free(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+/* Extract a VISE file */
+/* Return NULL if not found */
+static xfile *vise_extract(xfile **pxf, xfile *arch, char *tfilename, int verb) {
+ visearch *vi;
+ char *cp;
+ xfile *xf = NULL;
+
+ if ((vi = new_arch(arch->buf, arch->len, verb)) == NULL) {
+ return NULL;
+ }
+
+ if (verb)
+ printf("Input file '%s' is a VISE archive file base 0x%x\n",arch->name,vi->vbase);
+
+ if (vi->locate_file(vi, tfilename)) {
+ if (verb) printf("Failed to locate file '%s' in VISE archive",tfilename);
+ return NULL;
+ }
+
+ g_va = vi;
+ if (vinflate()) {
+ if (verb) printf("Inflating file '%s' failed",tfilename);
+ return NULL;
+ }
+ g_va = NULL;
+
+ if (verb)
+ printf("Located and decompressed file '%s' from VISE archive\n",tfilename);
+
+ xf = add_xf(pxf);
+
+ /* Just return base filename */
+ if ((cp = strrchr(tfilename, '/')) == NULL
+ && (cp = strrchr(tfilename, '\\')) == NULL)
+ cp = tfilename;
+ else
+ cp++;
+
+ if ((xf->name = strdup(cp)) == NULL) {
+ fprintf(stderr,"strdup failed on filename\n");
+ exit(-1);
+ }
+ xf->buf = vi->dbuf;
+ xf->len = vi->dsize;
+ xf->ftype = file_dllcab;
+ xf->ttype = arch->ttype;
+
+ vi->dbuf = NULL; /* We've taken buffer */
+ vi->dsize = vi->dasize = 0;
+ vi->del(vi);
+
+ if (verb) printf("Returning '%s' length %ld from '%s'\n",xf->name, xf->len, arch[0].name);
+
+
+ return xf;
+}
+
+/* ============================================================================= */
+/* Spyder 2 PLD pattern extraction */
+
+int is_s2pld(xfile *xf) {
+
+ if (xf->len != 6817)
+ return 0;
+
+ if (xf->buf[0] == 0xff
+ && xf->buf[1] == 0x04
+ && xf->buf[2] == 0xb0
+ && xf->buf[3] == 0x0a)
+ return 1;
+ return 0;
+}
+
+static xfile *spyd2pld_extract(xfile **pxf, xfile *dll, int verb) {
+ unsigned char *buf;
+ unsigned int size;
+ unsigned int i, j;
+ unsigned int rfsize;
+ unsigned char *firmware;
+ unsigned int firmwaresize;
+ /* First few bytes of the standard Xilinx XCS05XL PLD pattern */
+ unsigned char magic[4] = { 0xff, 0x04, 0xb0, 0x0a };
+ xfile *xf = NULL;
+
+ buf = dll->buf;
+ size = dll->len;
+
+ firmwaresize = 6817;
+ rfsize = (firmwaresize + 7) & ~7;
+
+ /* Search for start of PLD pattern */
+ for(i = 0; (i + rfsize) < size ;i++) {
+ if (buf[i] == magic[0]) {
+ for (j = 0; j < 4; j++) {
+ if (buf[i + j] != magic[j])
+ break;
+ }
+ if (j >= 4)
+ break; /* found it */
+ }
+ }
+ if ((i + rfsize) >= size) {
+ if (verb) printf("Failed to locate Spyder 2 firmware in '%s'\n",dll->name);
+ return NULL;
+ }
+
+ firmware = buf + i;
+
+ xf = add_xf(pxf);
+
+ if ((xf->name = strdup("spyd2PLD.bin")) == NULL) {
+ fprintf(stderr,"strdup failed on filename\n");
+ exit(-1);
+ }
+ if ((xf->buf = malloc(firmwaresize)) == NULL) {
+ fprintf(stderr,"malloc failed for Spyder 2 PLD pattern (%d bytes)\n",firmwaresize);
+ exit(-1);
+ }
+ memcpy(xf->buf, firmware, firmwaresize);
+ xf->len = firmwaresize;
+ xf->ftype = file_data;
+ xf->ttype = targ_spyd_pld;
+
+ if (verb) printf("Returning '%s' length %ld from '%s'\n",xf->name, xf->len, dll->name);
+
+ return xf;
+}
+
+/* ============================================================================= */
+/* Spyder 4 calibration table extraction */
+
+int is_s4cal(xfile *xf) {
+ int i;
+ unsigned char cal2vals[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f };
+
+ if (xf->len < 8)
+ return 0;
+
+ for (i = 0; i < 8 ; i++) {
+ if (xf->buf[i] != cal2vals[i])
+ return 0;
+ }
+ return 1;
+}
+
+/* Extract the spyder 4 calibration table from the .dll */
+/* Return NULL if not found */
+static xfile *spyd4cal_extract(xfile **pxf, xfile *dll, int verb) {
+ unsigned char *buf, *caldata;
+ unsigned int size;
+ unsigned int i, j;
+ int nocals;
+ unsigned int rfsize;
+ /* First 41 x 8 bytes are the following pattern: */
+ unsigned char cal2vals[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3f };
+ unsigned char cal2evals[7] = { '3', '3', '3', '7', '1', '0', '-' };
+ xfile *xf = NULL;
+
+ buf = dll->buf;
+ size = dll->len;
+
+ /* Search for start of the calibration data */
+ for(i = 0; i < (size - 41 * 8 - 7) ;i++) {
+ if (buf[i] == cal2vals[0]) {
+ for (j = 0; j < (41 * 8); j++) {
+ if (buf[i + j] != cal2vals[j % 8])
+ break;
+ }
+ if (j >= (41 * 8))
+ break; /* found first set of doubles */
+ }
+ }
+ if (i >= (size - 41 * 8 - 7)) {
+ if (verb) printf("Failed to locate Spyder 4 calibration data in '%s'\n",dll->name);
+ return NULL;
+ }
+
+ caldata = buf + i;
+
+ /* Search for end of the calibration data */
+ for(i += (41 * 8); i < (size-7) ;i++) {
+ if (buf[i] == cal2evals[0]) {
+ for (j = 0; j < 7; j++) {
+ if (buf[i + j] != cal2evals[j])
+ break;
+ }
+ if (j >= 7)
+ break; /* found string after calibration data */
+ }
+ }
+ if (i >= (size-7)) {
+ if (verb) printf("Failed to locate end of Spyder 4 calibration data in '%s'\n",dll->name);
+ return NULL;
+ }
+
+ rfsize = buf + i - caldata;
+
+ nocals = rfsize / (41 * 8);
+ if (rfsize != (nocals * 41 * 8)) {
+ if (verb) printf("Spyder 4 calibration data is not a multiple of %d bytes\n",41 * 8);
+ return NULL;
+ }
+
+ if (nocals != 6) {
+ if (verb) printf("Spyder 4 calibration data has an unexpected number of entries (%d)\n",nocals);
+ return NULL;
+ }
+
+ xf = add_xf(pxf);
+
+ if ((xf->name = strdup("spyd4cal.bin")) == NULL) {
+ fprintf(stderr,"strdup failed on filename\n");
+ exit(-1);
+ }
+ if ((xf->buf = malloc(rfsize)) == NULL) {
+ fprintf(stderr,"malloc failed for Spyder 4 calibration data (%d bytes)\n",rfsize);
+ exit(-1);
+ }
+ memcpy(xf->buf, caldata, rfsize);
+ xf->len = rfsize;
+ xf->ftype = file_data;
+ xf->ttype = targ_spyd_cal;
+
+ if (verb) printf("Returning '%s' length %ld from '%s'\n",xf->name, xf->len, dll[0].name);
+
+ return xf;
+}
+
+/* ============================================================================= */
+/* EDR to CCSS */
+
+static ccss *parse_EDR(unsigned char *buf, unsigned long len, char *name, int verb);
+static ccss *read_EDR_file(char *name, int verb);
+
+/* Do conversion. Return NZ on sucess */
+static xfile *edr_convert(xfile **pxf, xfile *xi, int verb) {
+ xfile *xf = NULL;
+ ccss *c;
+
+ if (verb) printf("Translating '%s' (%d bytes)\n",xi->name, xi->len);
+
+ if ((c = parse_EDR(xi->buf, xi->len, xi->name, verb)) == NULL) {
+ if (verb) printf("Failed to parse EDR '%s'\n",xi->name);
+ return NULL;
+ } else {
+ char *ccssname;
+ char *edrname;
+ unsigned char *buf;
+ int len;
+ if (c->buf_write_ccss(c, &buf, &len)) {
+ error("Failed to create ccss for '%s'",xi->name);
+ }
+ /* Convert .edr file name to .ccss */
+
+ /* Get basename of file */
+ if ((edrname = strrchr(xi->name, '/')) == NULL)
+ edrname = xi->name;
+ else
+ edrname++;
+
+ if ((ccssname = malloc(strlen(edrname) + 10)) == NULL)
+ error("Malloc failed on ccssname");
+
+ strcpy(ccssname, edrname);
+
+ /* Fix extension */
+ if (strlen(ccssname) > 4
+ && (strncmp(ccssname + strlen(ccssname) -4, ".edr", 4) == 0
+ || strncmp(ccssname + strlen(ccssname) -4, ".EDR", 4) == 0))
+ strcpy(ccssname + strlen(ccssname) -4, ".ccss");
+ xf = new_add_xf(pxf, ccssname, buf, len, file_data, targ_i1d3_edr);
+ free(ccssname);
+ }
+ return xf;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+/* Lower level */
+
+// Print bytes as hex to fp
+static void dump_bytes(FILE *fp, char *pfx, unsigned char *buf, int len) {
+ int i, j, ii;
+ for (i = j = 0; i < len; i++) {
+ if ((i % 16) == 0)
+ fprintf(fp,"%s%04x:",pfx,i);
+ fprintf(fp," %02x",buf[i]);
+ if ((i+1) >= len || ((i+1) % 16) == 0) {
+ for (ii = i; ((ii+1) % 16) != 0; ii++)
+ fprintf(fp," ");
+ fprintf(fp," ");
+ for (; j <= i; j++) {
+ if (isprint(buf[j]))
+ fprintf(fp,"%c",buf[j]);
+ else
+ fprintf(fp,".");
+ }
+ fprintf(fp,"\n");
+ }
+ }
+}
+
+/* Take a 64 sized return buffer, and convert it to an ORD64 */
+static ORD64 buf2ord64(unsigned char *buf) {
+ ORD64 val;
+ val = buf[7];
+ val = ((val << 8) + (0xff & buf[6]));
+ val = ((val << 8) + (0xff & buf[5]));
+ val = ((val << 8) + (0xff & buf[4]));
+ val = ((val << 8) + (0xff & buf[3]));
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a word sized return buffer, and convert it to an unsigned int */
+static unsigned int buf2uint(unsigned char *buf) {
+ unsigned int val;
+ val = buf[3];
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a word sized return buffer, and convert it to an int */
+static int buf2int(unsigned char *buf) {
+ int val;
+ val = buf[3];
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a short sized return buffer, and convert it to an int */
+static int buf2short(unsigned char *buf) {
+ int val;
+ val = buf[1];
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Detect this file as an EDR file */
+int is_edr(xfile *xf) {
+
+ if (xf->len < 16)
+ return 0;
+
+ /* See if it has the right file ID */
+ if (strncmp("EDR DATA1", (char *)xf->buf, 16) == 0)
+ return 1;
+ return 0;
+}
+
+/* Given a buffer holding and EDR file, parse it and return a ccss */
+/* Return NULL on error */
+static ccss *parse_EDR(
+ unsigned char *buf,
+ unsigned long len,
+ char *name, /* Name of the file */
+ int verb /* Verbose flag */
+) {
+ int i, j;
+ FILE *fp;
+ unsigned char *nbuf;
+ unsigned long nlen;
+ unsigned int off;
+ unsigned char *dbuf = NULL; /* Buffer for spectral samples */
+ INR64 edrdate;
+ char creatdate[30];
+ char dispdesc[256];
+ int ttmin, ttmax; /* Min & max technology strings (inclusive) */
+ int *trefmodes; /* Corresponding refresh mode for tecnology */
+ char **tsels; /* Corresponding UI selection chars */
+ char **ttstrings; /* Corresponding technology strings */
+ int ttype; /* Technology type idex */
+ int nsets, set;
+ xspect *samples = NULL, sp;
+ int hasspec;
+ double nmstart, nmend, nmspace;
+ int nsamples;
+ ccss *rv;
+
+ /* We hard code the Technology strings for now. In theory we could */
+ /* read them from the TechnologyStrings.txt file that comes with the .edr's */
+ {
+ ttmin = 0;
+ ttmax = 22;
+ if ((ttstrings = (char **)malloc(sizeof(char *) * (ttmax - ttmin + 2))) == NULL) {
+ if (verb) printf("Malloc failed\n");
+ return NULL;
+ }
+ if ((trefmodes = (int *)malloc(sizeof(int) * (ttmax - ttmin + 2))) == NULL) {
+ free(ttstrings);
+ if (verb) printf("Malloc failed\n");
+ return NULL;
+ }
+ if ((tsels = (char **)malloc(sizeof(char *) * (ttmax - ttmin + 2))) == NULL) {
+ free(trefmodes);
+ free(ttstrings);
+ if (verb) printf("Malloc failed\n");
+ return NULL;
+ }
+
+ trefmodes[0] = 0; tsels[0] = NULL; ttstrings[0] = "Color Matching Function";
+ trefmodes[1] = 0; tsels[1] = NULL; ttstrings[1] = "Custom";
+ trefmodes[2] = 1; tsels[2] = "c"; ttstrings[2] = "CRT";
+ trefmodes[3] = 0; tsels[3] = "l"; ttstrings[3] = "LCD CCFL IPS";
+ trefmodes[4] = 0; tsels[4] = NULL; ttstrings[4] = "LCD CCFL VPA";
+ trefmodes[5] = 0; tsels[5] = NULL; ttstrings[5] = "LCD CCFL TFT";
+ trefmodes[6] = 0; tsels[6] = "L"; ttstrings[6] = "LCD CCFL Wide Gamut IPS";
+ trefmodes[7] = 0; tsels[7] = NULL; ttstrings[7] = "LCD CCFL Wide Gamut VPA";
+ trefmodes[8] = 0; tsels[8] = NULL; ttstrings[8] = "LCD CCFL Wide Gamut TFT";
+ trefmodes[9] = 0; tsels[9] = "e"; ttstrings[9] = "LCD White LED IPS";
+ trefmodes[10] = 0; tsels[10] = NULL; ttstrings[10] = "LCD White LED VPA";
+ trefmodes[11] = 0; tsels[11] = NULL; ttstrings[11] = "LCD White LED TFT";
+ trefmodes[12] = 0; tsels[12] = "b"; ttstrings[12] = "LCD RGB LED IPS";
+ trefmodes[13] = 0; tsels[13] = NULL; ttstrings[13] = "LCD RGB LED VPA";
+ trefmodes[14] = 0; tsels[14] = NULL; ttstrings[14] = "LCD RGB LED TFT";
+ trefmodes[15] = 0; tsels[15] = "o"; ttstrings[15] = "LED OLED";
+ trefmodes[16] = 0; tsels[16] = "a"; ttstrings[16] = "LED AMOLED";
+ trefmodes[17] = 1; tsels[17] = "m"; ttstrings[17] = "Plasma";
+ trefmodes[18] = 0; tsels[18] = NULL; ttstrings[18] = "LCD RG Phosphor"; // is this LCD ??
+ trefmodes[19] = 1; tsels[19] = NULL; ttstrings[19] = "Projector RGB Filter Wheel";
+ trefmodes[20] = 1; tsels[10] = NULL; ttstrings[20] = "Projector RGBW Filter Wheel";
+ trefmodes[21] = 1; tsels[21] = NULL; ttstrings[21] = "Projector RGBCMY Filter Wheel";
+ trefmodes[22] = 0; tsels[22] = "p"; ttstrings[22] = "Projector";
+ trefmodes[23] = 0; tsels[23] = NULL; ttstrings[23] = "Unknown";
+ }
+
+ if (len < 600) {
+ if (verb) printf("Unable to read '%s' header\n",name);
+ return NULL;
+ }
+ nbuf = buf + 600; /* Next time we "read" the file */
+ nlen = len - 600;
+
+ /* See if it has the right file ID */
+ if (strncmp("EDR DATA1", (char *)buf, 16) != 0) {
+ if (verb) printf("File '%s' isn't an EDR\n",name);
+ return NULL;
+ }
+
+ /* Creation Date&time of EDR */
+ edrdate = buf2ord64(buf + 0x0018);
+ strcpy(creatdate, ctime_64(&edrdate));
+
+ /* Creation tool string @ 0x0020 */
+
+ /* Display description */
+ strncpy(dispdesc, (char *)buf + 0x0060, 255); dispdesc[255] = '\000';
+
+ /* Technology type index. */
+ ttype = buf2int(buf + 0x0160);
+
+ /* Number of data sets */
+ nsets = buf2int(buf + 0x0164);
+
+ if (nsets < 3 || nsets > 100) {
+ if (verb) printf("File '%s' number of data sets %d out of range\n",name,nsets);
+ return NULL;
+ }
+
+ /* Model number string @ 0x0168 ? */
+ /* Part code string @ 0x01a8 ? */
+ /* Another number string @ 0x01e8 ? */
+
+ /* Unknown Flag/number = 1 @ 0x022c */
+
+ /* "has spectral data" flag ? */
+ hasspec = buf2short(buf + 0x022E);
+ if (hasspec != 1) {
+ if (verb) printf("Has Data flag != 1 in EDR file '%s'\n",name);
+ return NULL;
+ }
+
+ /* The spectral sample characteristics */
+ nmstart = IEEE754_64todouble(buf2ord64(buf + 0x0230));
+ nmend = IEEE754_64todouble(buf2ord64(buf + 0x0238));
+ nmspace = IEEE754_64todouble(buf2ord64(buf + 0x0240));
+
+ /* Setup prototype spectral values */
+ sp.spec_wl_short = nmstart;
+ sp.spec_wl_long = nmend;
+ sp.spec_n = (int)(1.0 + (nmend - nmstart)/nmspace + 0.5);
+ sp.norm = 1.0;
+
+ /* Unknown Flag/number = 0 @ 0x0248 */
+ /* Error if not 0 ??? */
+
+ if (hasspec) {
+ /* Allocate space for the sets */
+ if ((samples = (xspect *)malloc(sizeof(xspect) * nsets)) == NULL) {
+ if (verb) printf("Malloc of spectral samples failed\n");
+ return NULL;
+ }
+ }
+
+ /* Read the sets of data */
+ for (set = 0; set < nsets; set++) {
+
+ /* "Read" in the 128 byte data set header */
+ buf = nbuf;
+ len = nlen;
+ if (len < 128) {
+ if (verb) printf("Unable to read file '%s' set %d data header\n",name,set);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+ nbuf = buf + 128; /* Next time we "read" the file */
+ nlen = len - 128;
+
+ /* See if it has the right ID */
+ if (strncmp("DISPLAY DATA", (char *)buf, 16) != 0) {
+ if (verb) printf("File '%s' set %d data header has unknown identifier\n",name,set);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+
+ /* double Yxy(z) of sample at +0x0058 in data header ? */
+
+ if (hasspec == 0) /* No spectral data, so skip it */
+ continue;
+
+ /* Read in the 28 byte data set header */
+ buf = nbuf;
+ len = nlen;
+ if (len < 28) {
+ if (verb) printf("Unable to read file '%s' set %d spectral data header\n",name,set);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+ nbuf = buf + 28; /* Next time we "read" the file */
+ nlen = len - 28;
+
+ /* See if it has the right ID */
+ if (strncmp("SPECTRAL DATA", (char *)buf, 16) != 0) {
+ if (verb) printf("File '%s' set %d data header has unknown identifier\n",name,set);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+
+ /* Number of doubles in set */
+ nsamples = buf2int(buf + 0x0010);
+
+ if (nsamples != sp.spec_n) {
+ if (verb) printf("File '%s' set %d number of samles %d doesn't match wavelengths %d\n",name,set,nsamples,sp.spec_n);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+
+ /* Read in the spectral values */
+ buf = nbuf;
+ len = nlen;
+ if (len < 8 * sp.spec_n) {
+ if (verb) printf("Unable to read file '%s' set %d spectral data\n",name,set);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+ nbuf = buf + 8 * sp.spec_n; /* Next time we "read" the file */
+ nlen = len - 8 * sp.spec_n;
+
+ XSPECT_COPY_INFO(&samples[set], &sp);
+
+ /* Read the spectral values for this sample, */
+ /* and convert it from W/nm/m^2 to mW/nm/m^2 */
+ for (j = 0; j < sp.spec_n; j++) {
+ samples[set].spec[j] = IEEE754_64todouble(buf2ord64(buf + j * 8));
+ samples[set].spec[j] *= 1000.0;
+ }
+#ifdef PLOT_SAMPLES
+ /* Plot the spectra */
+ {
+ double xx[500];
+ double y1[500];
+
+ for (j = 0; j < samples[set].spec_n; j++) {
+ xx[j] = XSPECT_XWL(&sp, j);
+ y1[j] = samples[set].spec[j];
+ }
+ printf("EDR sample %d (uncorrected)\n",set+1);
+ do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, samples[set].spec_n);
+ }
+#endif /* PLOT_SAMPLES */
+
+ }
+
+ /* After the spectral data comes the "correction" data. This seems to be */
+ /* related to the measurement instrument (typically a Minolta CS1000). */
+ /* It's not obvious why this isn't already applied to the spectral data, */
+ /* and doesn't cover the same wavelength range as the samples. */
+
+ /* Try and read in the 92 byte correction header */
+ buf = nbuf;
+ len = nlen;
+ if (len >= 92) {
+ nbuf = buf + 92; /* Next time we "read" the file */
+ nlen = len - 92;
+
+ /* See if it has the right ID */
+ if (strncmp("CORRECTION DATA", (char *)buf, 16) != 0) {
+ if (verb) printf("File '%s' correction data header has unknown identifier\n",name);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+
+ /* Number of doubles in set */
+ nsamples = buf2int(buf + 0x0050);
+
+ if (nsamples == 351) {
+ sp.spec_wl_short = 380.0;
+ sp.spec_wl_long = 730.0;
+ sp.spec_n = nsamples;
+ sp.norm = 1.0;
+ } else if (nsamples == 401) {
+ sp.spec_wl_short = 380.0;
+ sp.spec_wl_long = 780.0;
+ sp.spec_n = nsamples;
+ sp.norm = 1.0;
+ } else {
+ if (verb) printf("File '%s' correction data has unknown range %d\n\n",name,nsamples);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+
+ /* Read in the spectral values */
+ buf = nbuf;
+ len = nlen;
+ if (len < 8 * sp.spec_n) {
+ if (verb) printf("Unable to read file '%s' correction spectral data\n",name);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+ nbuf = buf + 8 * sp.spec_n; /* Next time we "read" the file */
+ nlen = len - 8 * sp.spec_n;
+
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = IEEE754_64todouble(buf2ord64(buf + j * 8));
+ }
+
+#ifdef PLOT_SAMPLES
+ /* Plot the spectra */
+ {
+ double xx[500];
+ double y1[500];
+
+ for (j = 0; j < sp.spec_n; j++) {
+ xx[j] = XSPECT_XWL(&sp, j);
+ y1[j] = sp.spec[j];
+ }
+ printf("Correction data\n");
+ do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, sp.spec_n);
+ }
+#endif /* PLOT_SAMPLES */
+
+ /* Apply the correction to all the spectral samples */
+ for (set = 0; set < nsets; set++) {
+ for (j = 0; j < samples[set].spec_n; j++)
+ samples[set].spec[j] *= value_xspect(&sp, XSPECT_XWL(&samples[set], j));
+ }
+ }
+
+ /* Creat a ccss */
+ if ((rv = new_ccss()) == NULL) {
+ if (verb) printf("Unable to read file '%s' correction spectral data\n",name);
+ if (samples != NULL) free(samples);
+ return NULL;
+ }
+
+ if (ttype < ttmin || ttype > ttmax) {
+ ttype = ttmax + 1; /* Set to Unknown */
+ }
+
+ /* Set it's values */
+ rv->set_ccss(rv, "X-Rite", creatdate, NULL, dispdesc, ttstrings[ttype], trefmodes[ttype], tsels[ttype], "CS1000", samples, nsets);
+
+ free(tsels);
+ free(trefmodes);
+ free(ttstrings);
+ free(samples);
+
+ return rv;
+}
+
+/* Return nz if this looks like a .ccss */
+int is_ccss(xfile *xf) {
+ if (xf->len < 7)
+ return 0;
+
+ /* See if it has the right file ID */
+ if (strncmp("CCSS ", (char *)xf->buf, 7) == 0)
+ return 1;
+ return 0;
+}
+
+/* Read am EDR file and return a ccss class */
+/* Return NULL on error */
+static ccss *read_EDR_file(
+ char *name, /* File to read */
+ int verb /* Verbose flag */
+) {
+ FILE *fp;
+ unsigned char *ibuf;
+ unsigned long ilen, bread;
+ ccss *rv;
+
+ /* Open up the file for reading */
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(name,"rb")) == NULL)
+#else
+ if ((fp = fopen(name,"r")) == NULL)
+#endif
+ {
+ if (verb) printf("Unable to open file file '%s'\n",name);
+ return NULL;
+ }
+
+ /* Figure out how big it is */
+ if (fseek(fp, 0, SEEK_END)) {
+ if (verb) printf("Seek to EOF '%s' failed'\n",name);
+ return NULL;
+ }
+ ilen = (unsigned long)ftell(fp);
+
+ if (fseek(fp, 0, SEEK_SET)) {
+ if (verb) printf("Seek to SOF '%s' failed'\n",name);
+ return NULL;
+ }
+
+ if ((ibuf = (unsigned char *)malloc(ilen)) == NULL) {
+ if (verb) printf("Malloc of buffer for file '%s' failed\n",name);
+ return NULL;
+ }
+
+ if ((bread = fread(ibuf, 1, ilen, fp)) != ilen) {
+ if (verb) printf("Failed to read file '%s', read %ld out of %ld bytes\n",name,bread,ilen);
+ free(ibuf);
+ return NULL;
+ }
+ fclose(fp);
+
+ rv = parse_EDR(ibuf, ilen, name, verb);
+
+ free(ibuf);
+
+ return rv;
+}
+
+/* ========================================================= */
+
+/* Return nz if this looks like a .ccmx */
+int is_ccmx(xfile *xf) {
+ if (xf->len < 7)
+ return 0;
+
+ /* See if it has the right file ID */
+ if (strncmp("CCMX ", (char *)xf->buf, 7) == 0)
+ return 1;
+ return 0;
+}
+
+/* ========================================================= */
+/* i1d3 Archive support */
+/* Extract a file from an inno archive. */
+
+/* (It turns out we don't actually need this inno parsing code, */
+/* since the .cab file is uncompressed and contiguous, so */
+/* we can locate and save it directly from Setup.exe.) */
+
+/* Function callbacks for LzmaDec */
+static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
+static void SzFree(void *p, void *address) { p = p; free(address); }
+ISzAlloc alloc = { SzAlloc, SzFree };
+
+
+/* Version of lzma decode that skips the 4 byte CRC before each 4096 byte block */
+static SRes LzmaDecodeX(
+Byte *dest, unsigned long *destLen, const Byte *src, unsigned long *srcLen,
+ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) {
+ SRes res;
+ CLzmaDec state;
+ SizeT slen = *srcLen;
+ SizeT dlen = *destLen;
+ SizeT len;
+ int doneheader = 0;
+
+ if (slen < (4 + 5))
+ return SZ_ERROR_INPUT_EOF;
+
+ LzmaDec_Construct(&state);
+ res = LzmaDec_Allocate(&state, src + 4, LZMA_PROPS_SIZE, alloc);
+ if (res != SZ_OK)
+ return res;
+
+ *srcLen = 0;
+ *destLen = 0;
+ LzmaDec_Init(&state);
+
+ for (;slen > 0 && dlen > 0;) {
+ SizeT ddlen;
+
+ if (slen < 4)
+ return SZ_ERROR_INPUT_EOF;
+ if (dlen == 0)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ /* Skip the CRC */
+ src += 4;
+ slen -= 4;
+ *srcLen += 4;
+
+ len = 4096; /* Bytes to next CRC */
+
+ if (doneheader == 0) { /* Skip the 5 + 8 byte header */
+ int inc = 5;
+ len -= inc;
+ src += inc;
+ slen -= inc;
+ *srcLen += inc;
+ doneheader = 1;
+ }
+
+ if (len > slen)
+ len = slen;
+ ddlen = dlen;
+
+ res = LzmaDec_DecodeToBuf(&state, dest, &ddlen, src, &len, finishMode, status);
+ if (res != SZ_OK) {
+ LzmaDec_Free(&state, alloc);
+ return res;
+ }
+
+ src += len;
+ slen -= len;
+ *srcLen += len;
+
+ dest += ddlen;
+ dlen -= ddlen;
+ *destLen += ddlen;
+
+ if (*status == LZMA_STATUS_FINISHED_WITH_MARK
+ || *status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) {
+ break;
+ }
+ }
+ LzmaDec_Free(&state, alloc);
+
+ return res;
+}
+
+/* extract the given file from Setup.exe */
+
+/* Return a list of xfiles, with one entry if successful */
+/* Return NULL if not found or not inno file */
+static xfile *inno_extract(xfile *xi, char *tfilename, int verb) {
+ int i, j, k;
+ unsigned char *ibuf;
+ unsigned long ilen;
+ char *headerid = "Inno Setup Setup Data (5.3.10)";
+ int headerlen = strlen(headerid);
+ unsigned int ldrbase = 0;
+ unsigned long haddr, srclen;
+ unsigned char *d1buf, *d2buf; /* Decompress buffer */
+ unsigned long d1sz, d2sz;
+ unsigned char *msibuf;
+ unsigned long msisz;
+ unsigned long cblocklen;
+ SRes rv;
+ ELzmaStatus dstat;
+ unsigned long ix;
+ int filelen = strlen(tfilename);
+ unsigned long fileso, filesz;
+ char *cp;
+ xfile *xf = NULL;
+
+ ibuf = xi->buf;
+ ilen = xi->len;
+
+ /* Search for the start of the loader. All the file offsets */
+ /* are relative to this */
+ for (i = 0; i < (ilen - 4); i++) {
+ if (ibuf[i + 0] == 0x4d
+ && ibuf[i + 1] == 0x5a
+ && ibuf[i + 2] == 0x90
+ && ibuf[i + 3] == 0x00) {
+ if (verb > 1) printf("Found archive base 0x%x\n",i);
+ ldrbase = i;
+ break;
+ }
+ }
+ if (i >= (ilen - 4)) {
+ if (verb) printf("Failed to locate loader base\n");
+ return NULL;
+ }
+
+ /* Search for inno header pattern. */
+ for (i = 0; i < (ilen - 64 - 4 - 5 - 4); i++) {
+ if (ibuf[i] == headerid[0]
+ && strncmp((char *)ibuf + i, headerid, headerlen) == 0
+ && ibuf[i + 64] != 'I'
+ && ibuf[i + 65] != 'n'
+ && ibuf[i + 66] != 'n'
+ && ibuf[i + 67] != 'o') {
+ haddr = i;
+ }
+ }
+ if (i >= (ilen - 64 - 4 - 5 - 4)) {
+ if (verb) printf("Failed to locate header pattern\n");
+ return NULL;
+ }
+
+ if (verb > 1) printf("Found header at 0x%x\n",i);
+
+ /* Use the last header found (or cound search all found ?) */
+ haddr += 64; /* Skip Inno header */
+
+ /* Next 9 bytes are the compression header */
+ haddr += 4; /* Skip Inno header CRC */
+ cblocklen = buf2uint(ibuf + haddr); /* Compressed block length */
+
+ if (verb > 1) printf("Header compression block length = %ld\n",cblocklen);
+
+ if ((haddr + cblocklen) > ilen) {
+ if (verb) printf("Compression block is longer than setup.exe\n");
+ return NULL;
+ }
+
+ if (ibuf[haddr + 4] != 1) {
+ if (verb) printf("Inno header is expected to be compressed\n");
+ return NULL;
+ }
+ haddr += 5; /* Skip compression header */
+
+ /* We'r now at the start of the compressed data */
+
+ d1sz = cblocklen * 30;
+ if ((d1buf = (unsigned char *)malloc(d1sz)) == NULL) {
+ fprintf(stderr,"Failed to allocate decompression buffer\n");
+ exit(-1);
+ }
+
+ // if (verb) printf("CRC + lzma at %d\n",haddr);
+
+ srclen = ilen - haddr;
+
+ /* Decode using CRC + 4096 byte blocks */
+ rv = LzmaDecodeX(d1buf, &d1sz, ibuf + haddr, &srclen, LZMA_FINISH_END, &dstat, &alloc);
+
+ if (rv != SZ_OK) {
+ if (verb) printf("lzma decode failed with rv %d and status %d\n",rv, dstat);
+ free(d1buf);
+ return NULL;
+ }
+ if (verb > 1) printf("Decoded %ld bytes to created %ld bytes of Header output (ratio %.1f)\n",srclen,d1sz,(double)d1sz/srclen);
+
+// dump_bytes(stdout, " ", d1buf, d1sz);
+
+ /* - - - - - - - - - - - - - - - - -*/
+
+ /* Skip to the start of the next compression block header */
+ haddr += cblocklen;
+
+ if (verb > 1) printf("Expect File Location compressed block to be at 0x%lx\n",haddr);
+ if ((haddr + 20) > ilen) {
+ if (verb) printf("Setup.exe too short for 2nd header block\n");
+ free(d1buf);
+ return NULL;
+ }
+
+ /* Next 9 bytes are the compression header */
+ haddr += 4; /* Skip Inno header CRC */
+ cblocklen = buf2uint(ibuf + haddr); /* Compressed block length */
+
+ if (verb > 1) printf("File Location compression block length = %ld\n",cblocklen);
+
+ if ((haddr + cblocklen) > ilen) {
+ if (verb) printf("2nd compression block is longer than setup.exe\n");
+ free(d1buf);
+ return NULL;
+ }
+
+ if (ibuf[haddr + 4] != 1) {
+ if (verb) printf("Inno 2nd header is expected to be compressed\n");
+ free(d1buf);
+ return NULL;
+ }
+ haddr += 5; /* Skip compression header */
+
+ /* We're now at the start of the compressed data */
+
+ d2sz = cblocklen * 10;
+ if ((d2buf = (unsigned char *)malloc(d2sz)) == NULL) {
+ if (verb) printf("Failed to allocate 2nd block decompression buffer\n");
+ free(d1buf);
+ free(d2buf);
+ return NULL;
+ }
+
+ //if (verb) printf("CRC + lzma at %d\n",haddr);
+ srclen = ilen - haddr;
+
+ /* Decode using CRC + 4096 byte blocks */
+ rv = LzmaDecodeX(d2buf, &d2sz, ibuf + haddr, &srclen, LZMA_FINISH_END, &dstat, &alloc);
+
+ if (rv != SZ_OK) {
+ if (verb) printf("lzma decode of 2nd block failed with rv %d and status %d\n",rv, dstat);
+ free(d1buf);
+ free(d2buf);
+ return NULL;
+ }
+ if (verb > 1) printf("Decoded %ld bytes to created %ld bytes of File Location output (ratio %.1f)\n",srclen,d1sz,(double)d1sz/srclen);
+
+// dump_bytes(stdout, " ", d2buf, d2sz);
+
+ if (verb > 1) printf("Searching for file '%s' in Header\n",tfilename);
+ for (i = 0; i < (d1sz - 101); i++) {
+ if (d1buf[i+4] == tfilename[0]
+ && strncmp((char *)d1buf + 4 + i, tfilename, filelen) == 0
+ && d1buf[i+0] == filelen
+ && d1buf[i+1] == 0
+ && d1buf[i+2] == 0
+ && d1buf[i+3] == 0) {
+ if (verb > 1) printf("Found it at 0x%x\n",i);
+ break;
+ }
+ }
+ if (i >= (d1sz - 101)) {
+ if (verb) printf("Failed to find file '%s'\n",tfilename);
+ free(d1buf);
+ free(d2buf);
+ return NULL;
+ }
+
+ /* Need to skip 8 more strings */
+ i += 4 + filelen;
+ for (j = 0; j < 8; j++) {
+ unsigned long len;
+ len = buf2uint(d1buf + i);
+ i += 4 + len;
+ }
+ /* Skip another 40 bytes to location entry index */
+ i += 20;
+
+ ix = buf2uint(d1buf + i);
+
+ if (verb > 1) printf("Got file location index %ld at 0x%x\n",ix,i);
+
+
+ /* Now get the ix file entry information. */
+ /* They are in 74 byte structures */
+ i = ix * 74;
+
+ if ((i + 74) > d2sz) {
+ if (verb) printf("File location structure is out of range\n");
+ free(d1buf);
+ free(d2buf);
+ return NULL;
+ }
+
+ /* The start offset is at 8 */
+ fileso = buf2uint(d2buf + i + 8);
+
+ /* The original and compresses sizes are at 20 and 28 */
+ filesz = buf2uint(d2buf + i + 20); /* Actually 64 bit, but we don't need it */
+ if (filesz != buf2uint(d2buf + i + 28)) {
+ if (verb) printf("Can't handle compressed '%s'\n",tfilename);
+ free(d1buf);
+ free(d2buf);
+ return NULL;
+ }
+
+ if (verb > 1) printf("File '%s' is at offset 0x%lx, length %ld\n",tfilename,fileso,filesz);
+
+ if ((fileso + ldrbase) > ilen
+ || (fileso + ldrbase + filesz-1) > ilen) {
+ if (verb) printf("File '%s' is outsize file '%s' range \n",tfilename,xi->name);
+ free(d1buf);
+ free(d2buf);
+ return NULL;
+ }
+ /* Sanity check */
+ if (ibuf[ldrbase + fileso + 0] != 0xd0
+ || ibuf[ldrbase + fileso + 1] != 0xcf
+ || ibuf[ldrbase + fileso + 2] != 0x11
+ || ibuf[ldrbase + fileso + 3] != 0xe0) {
+ if (verb) printf("File '%s' doesn't seem to be at location\n",tfilename);
+ free(d1buf);
+ free(d2buf);
+ return NULL;
+ }
+
+ /* Copy to new buffer and free everything */
+ msisz = filesz;
+ if ((msibuf = (unsigned char *)malloc(msisz)) == NULL) {
+ fprintf(stderr,"Failed to allocate file '%s' buffer\n",tfilename);
+ free(d1buf);
+ free(d2buf);
+ exit(-1);
+ }
+ memmove(msibuf, ibuf + ldrbase + fileso, filesz);
+
+ free(d1buf);
+ free(d2buf);
+
+ xf = new_xf(1);
+
+ /* Just return base filename */
+ if ((cp = strrchr(tfilename, '/')) == NULL
+ && (cp = strrchr(tfilename, '\\')) == NULL)
+ cp = tfilename;
+ else
+ cp++;
+
+ if ((xf->name = strdup(cp)) == NULL) {
+ fprintf(stderr,"strdup failed on filename\n");
+ exit(-1);
+ }
+ xf->buf = msibuf;
+ xf->len = filesz;
+
+ if (verb) printf("Returning '%s' length %ld from '%s'\n",xf->name,xf->len, xi->name);
+
+ return xf;
+}
+
+/* ====================================================== */
+/* i1d3 Archive support */
+
+int is_inno(xfile *xf) {
+ int i;
+
+ /* Search for the start of the loader. All the file offsets */
+ /* are relative to this */
+ for (i = 0; i < (xf->len - 4); i++) {
+ if (xf->buf[i + 0] == 0x4d
+ && xf->buf[i + 1] == 0x5a
+ && xf->buf[i + 2] == 0x90
+ && xf->buf[i + 3] == 0x00) {
+ break;
+ }
+ }
+ if (i >= (xf->len - 4)) {
+ return 0;
+ }
+
+ /* Search for an Inno header pattern. */
+ for (i = 0; i < (xf->len - 64 - 4 - 5 - 4); i++) {
+ if (xf->buf[i + 0] == 'I'
+ && xf->buf[i + 1] == 'n'
+ && xf->buf[i + 2] == 'n'
+ && xf->buf[i + 3] == 'o') {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Return NZ if this is .cab file */
+int is_cab(xfile *xf) {
+
+ if (xf->len < 8)
+ return 0;
+
+ if (xf->buf[0] == 0x4d
+ && xf->buf[1] == 0x53
+ && xf->buf[2] == 0x43
+ && xf->buf[3] == 0x46
+ && xf->buf[4] == 0x00
+ && xf->buf[5] == 0x00
+ && xf->buf[6] == 0x00
+ && xf->buf[7] == 0x00)
+ return 1;
+ return 0;
+}
+
+/* Return NZ if this seems to be a .dll */
+int is_dll(xfile *xf) {
+ int off;
+ int chars;
+
+ if (xf->len < 0x40
+ || xf->buf[0] != 0x4d /* "MZ" */
+ || xf->buf[1] != 0x5a)
+ return 0;
+
+ off = xf->buf[0x3c] /* Offset to PE header */
+ + (xf->buf[0x3d] << 8)
+ + (xf->buf[0x3e] << 16)
+ + (xf->buf[0x3f] << 24);
+
+ if (xf->len < off + 0x18)
+ return 0;
+
+ if (xf->buf[off + 0] != 0x50 /* "PE" */
+ || xf->buf[off + 1] != 0x45
+ || xf->buf[off + 2] != 0x00
+ || xf->buf[off + 3] != 0x00)
+ return 0;
+
+ chars = xf->buf[off + 0x16] /* PE Characteristics */
+ + (xf->buf[off + 0x17] << 8);
+
+ /*
+ 0x0002 = executable (no unresolved refs)
+ 0x1000 = .sys driver
+ */
+
+ if (chars & 0x2000) /* It is a DLL */
+ return 1;
+
+ return 0;
+}
+
+/* Extract the .cab file from another file. */
+/* It's stored in the .msi uncompressed and contiguous, so we */
+/* just need to identify where it is and its length. */
+/* (This will work on any file that has the .cab file uncompressed and contiguous) */
+/* Return NULL if not found */
+static xfile *msi_extract(xfile **pxf, xfile *xi, char *tname, int verb) {
+ int i, j, k;
+ xfile *xf = NULL;
+ char *fid = "i1d3.xrdevice"; /* File in .cab to look for */
+ unsigned long fle = strlen(fid);
+ unsigned long cabo, cabsz;
+ size_t len;
+
+ if (verb) printf("Attempting to extract '%s' from '%s'\n",tname,xi->name);
+
+ /* Search for a filename in the .cab */
+ for (i = 0; i < (xi->len - fle - 2); i++) {
+ if (xi->buf[i + 0] == 0x00
+ && xi->buf[i + 1] == fid[0]
+ && strncmp((char *)xi->buf + i + 1, fid, fle) == 0) {
+ if (verb > 1) printf("Found file name '%s' in '%s' at 0x%x\n",fid,xi->name,i);
+ break;
+ }
+ }
+ if (i >= (xi->len - fle - 2)) {
+ if (verb) printf(".cab not found\n");
+ return NULL;
+ }
+
+ /* Search backwards for .cab signature */
+ for (; i >= 0; i--) {
+ if (xi->buf[i + 0] == 0x4d
+ && xi->buf[i + 1] == 0x53
+ && xi->buf[i + 2] == 0x43
+ && xi->buf[i + 3] == 0x46
+ && xi->buf[i + 4] == 0x00
+ && xi->buf[i + 5] == 0x00
+ && xi->buf[i + 6] == 0x00
+ && xi->buf[i + 7] == 0x00) {
+ if (verb > 1) printf("Found '%s' at 0x%x\n",tname,i);
+ break;
+ }
+ }
+ if (i < 0) {
+ if (verb) printf(".cab not found\n");
+ return NULL;
+ }
+
+ /* Lookup the .cab size (really 64 bit, but we don't care) */
+ len = buf2uint(xi->buf + i + 8);
+
+ if (verb > 1) printf("'%s' is length %ld\n",tname,len);
+
+ if ((xi->len - i) < len) {
+ if (verb) printf("Not enough room for .cab file in source\n");
+ return NULL;
+ }
+
+ xf = add_xf(pxf);
+ xf->len = len;
+
+ if ((xf->buf = malloc(xf->len)) == NULL) {
+ fprintf(stderr,"maloc of .cab buffer failed\n");
+ exit(-1);
+ }
+ memmove(xf->buf, xi->buf + i ,xf->len);
+
+ if ((xf->name = strdup(tname)) == NULL) {
+ fprintf(stderr,"maloc of .cab name failed\n");
+ exit(-1);
+ }
+
+ xf->ftype = file_dllcab;
+ xf->ttype = xi->ttype;
+
+ if (verb) printf("Extacted '%s' length %ld\n",xf->name,xf->len);
+
+ return xf;
+}
+
+
+/* ================================================================ */
+/* Extract files of a given type from a .cab file */
+
+/* Interface with inflate.c */
+/* We use globals for this */
+
+unsigned char *i_buf = NULL;
+unsigned long i_len = 0;
+unsigned long i_ix = 0;
+
+unsigned char *o_buf = NULL;
+unsigned long o_len = 0;
+unsigned long o_ix = 0;
+
+/* Interface to inflate */
+
+int inflate(void);
+
+/* fetch the next 8 bits */
+/* if we get 0xffffffff, we are at EOF */
+unsigned int inflate_get_byte() {
+ if (i_ix < i_len)
+ return i_buf[i_ix++];
+ return 0xff;
+}
+
+/* unget 8 bits */
+void inflate_unget_byte() {
+ if (i_ix > 0)
+ i_ix--;
+}
+
+/* Save the decompressed file to the buffer */
+int inflate_write_output(unsigned char *buf, unsigned int len) {
+ if ((o_ix + len) > o_len) {
+ fprintf(stderr,"Uncompressed buffer is unexpectedly large (%ld > %ld)!\n", o_ix + len, o_len);
+ return 1;
+ }
+ memmove(o_buf + o_ix, buf, len);
+ o_ix += len;
+ return 0;
+}
+
+/* Extract all the .edr files from the .cab */
+/* Returns the last file extracted, or NULL if none found */
+static xfile *cab_extract(xfile **pxf, xfile *xi, char *text, int verb) {
+ int i, j, k;
+ xfile *xf = NULL;
+ unsigned char *buf = xi->buf;
+ unsigned long len = xi->len;
+ unsigned long off;
+ unsigned long filesize, headeroffset, datastart;
+ int nofolders, nofiles, flags, comptype;
+ unsigned int totubytes;
+ int ufiles = 0;
+ unsigned char *obuf;
+ unsigned long olen;
+
+ if (verb) printf("Attempting to extract '*%s' from '%s'\n",text, xi->name);
+
+ /* Check it is a .cab file */
+ if (len < 0x2c
+ || buf[0] != 0x4d
+ || buf[1] != 0x53
+ || buf[2] != 0x43
+ || buf[3] != 0x46
+ || buf[4] != 0x00
+ || buf[5] != 0x00
+ || buf[6] != 0x00
+ || buf[7] != 0x00) {
+ fprintf(stderr,"'%s' is not a .cab file\n",xi->name);
+ exit(-1);
+ }
+
+ filesize = buf2uint(buf + 0x08);
+ headeroffset = buf2uint(buf + 0x10);
+ nofolders = buf2short(buf + 0x1a);
+ nofiles = buf2short(buf + 0x1c);
+ flags = buf2short(buf + 0x1e);
+
+ if (filesize != len) {
+ fprintf(stderr,"'%s' filesize desn't match\n",xi->name);
+ exit(-1);
+ }
+ if (nofolders != 1) {
+ fprintf(stderr,"'%s' has more than one folder\n",xi->name);
+ exit(-1);
+ }
+ if (flags != 0) {
+ fprintf(stderr,"'%s' has non-zero flags\n",xi->name);
+ exit(-1);
+ }
+
+ /* Read the first folders info (assumed flags == 0) */
+ datastart = buf2uint(buf + 0x24);
+ comptype = buf[0x2a];
+ if (comptype!= 1) {
+ fprintf(stderr,"'%s' doesn't use MSZip compression\n",xi->name);
+ exit(-1);
+ }
+
+ if (verb > 1) printf(".cab headeroffset = 0x%lx, datastart = 0x%lx, nofiles = %d\n",headeroffset,datastart,nofiles);
+
+ /* Look at each file */
+ for (off = headeroffset, k = 0; k < nofiles; k++) {
+ unsigned long fsize; /* Uncompressed size */
+ unsigned long foff;
+ short ffix;
+ char fname[95];
+
+ if (off > (len - 80)) {
+ fprintf(stderr,"'%s' too short for directory\n",xi->name);
+ exit(-1);
+ }
+
+ fsize = buf2uint(buf + off + 0x00);
+ foff = buf2uint(buf + off + 0x04);
+ ffix = buf2short(buf + off + 0x08);
+
+ strncpy(fname, (char *)buf + off + 0x10, 94);
+ fname[94] = '\000';
+
+ if (verb > 1) printf("file %d is '%s' at 0x%lx length %ld\n",k,fname, foff,fsize);
+
+ off += 0x10 + strlen(fname) + 1; /* Next entry */
+ }
+
+ /* Now come the data blocks */
+ totubytes = 0;
+ for (off = datastart, j = 0; ; j++) {
+ unsigned long chsum;
+ unsigned long cbytes;
+ unsigned long ubytes;
+
+ if (off > (len - 8)) {
+ if (verb > 1) printf("Got to end of data blocks at 0x%lx\n",off);
+ break;
+ }
+
+ chsum = buf2uint(buf + off + 0x00);
+ cbytes = buf2short(buf + off + 0x04);
+ ubytes = buf2short(buf + off + 0x06);
+
+ if (verb > 1) printf("Compression block %d, cbytes %ld, ubytes %ld\n",j,cbytes,ubytes);
+
+ totubytes += ubytes;
+
+ off += 8 + cbytes;
+ }
+
+
+ if (verb > 1) printf("Total uncompressed bytes = %d\n",totubytes);
+
+ olen = totubytes;
+ if ((obuf = malloc(olen)) == NULL) {
+ fprintf(stderr,"maloc of uncompressed output buffer failed\n");
+ exit(-1);
+ }
+
+ o_buf = obuf;
+ o_len = olen;
+ o_ix = 0;
+
+ for (off = datastart, j = 0; ; j++) {
+ unsigned long chsum;
+ unsigned long cbytes;
+ unsigned long ubytes;
+
+ if (off > (len - 8))
+ break;
+
+ chsum = buf2uint(buf + off + 0x00);
+ cbytes = buf2short(buf + off + 0x04);
+ ubytes = buf2short(buf + off + 0x06);
+
+ i_buf = buf + off + 8;
+ i_len = cbytes;
+ i_ix = 0;
+
+ /* MSZIP has a two byte signature at the start of each block */
+ if (inflate_get_byte() != 0x43 || inflate_get_byte() != 0x4B) {
+ printf(".cab block doesn't start with 2 byte MSZIP signature\n");
+ exit (-1);
+ }
+
+ if (inflate()) {
+ fprintf(stderr, "inflate of '%s' failed at i_ix 0x%lx, o_ix 0x%lx\n",xi->name,i_ix,o_ix);
+ exit (-1);
+ }
+
+ /* The history buffer is meant to survive from one block to the next. */
+ /* Not sure what that means, as it seems to work as is... */
+
+ off += 8 + cbytes;
+ }
+
+ xf = add_xf(pxf);
+
+ /* Create a buffer for each file */
+ for (ufiles = 0, off = headeroffset, k = 0; k < nofiles; k++) {
+ unsigned long fsize; /* Uncompressed size */
+ unsigned long foff;
+ short ffix;
+ char fname[95], *cp;
+ int namelen;
+
+ fsize = buf2uint(buf + off + 0x00);
+ foff = buf2uint(buf + off + 0x04);
+ ffix = buf2short(buf + off + 0x08);
+
+ strncpy(fname, (char *)buf + off + 0x10, 94);
+ fname[94] = '\000';
+ namelen = strlen(fname);
+
+ /* Lop of the junk in the filename */
+ if ((cp = strrchr(fname, '.')) != NULL)
+ *cp = '\000';
+
+ /* See if it's the type of file we want */
+ if ((cp = strrchr(fname, '.')) != NULL
+ && strcmp(cp, text) == 0) {
+ xfile *xx;
+
+ xf = xx = add_xf(pxf);
+
+ if (foff >= olen || (foff + fsize) > olen) {
+ fprintf(stderr,"file '%s' doesn't fit in decomressed buffer\n",fname);
+ exit(-1);
+ }
+ if ((xx->buf = malloc(fsize)) == NULL) {
+ fprintf(stderr,"maloc of file '%s' buffer len %ld failed\n",fname,fsize);
+ exit(-1);
+ }
+ xx->len = fsize;
+ memmove(xx->buf, obuf + foff, fsize);
+
+ if ((xx->name = strdup(fname)) == NULL) {
+ fprintf(stderr,"maloc of .edr name failed\n");
+ exit(-1);
+ }
+ xx->ftype = file_data;
+ xx->ttype = targ_i1d3_edr;
+ ufiles++;
+ }
+ off += 0x10 + namelen + 1; /* Next entry */
+ }
+
+ if (verb) printf("Found %d %s files out of %d files in .cab\n",ufiles, text, nofiles);
+
+ return xf;
+}
+
+
diff --git a/spectro/oemarch.h b/spectro/oemarch.h
new file mode 100644
index 0000000..72a3bb6
--- /dev/null
+++ b/spectro/oemarch.h
@@ -0,0 +1,102 @@
+
+#ifndef OEMARCH_H
+
+ /* OEM archive access library.
+ /* This supports installing OEM data files */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 13/11/2012
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define MAX_ARCH_LISTS 40
+
+/* Possible type of files/stage of processing */
+typedef enum {
+ file_none = 0x0000, /* None */
+ file_vol = 0x0001, /* Volume name */
+ file_arch = 0x0002, /* Archive file */
+ file_dllcab = 0x0004, /* .dll or .cab */
+ file_data = 0x0008 /* final data file */
+} file_type;
+
+/* Possible type of target */
+typedef enum {
+ targ_none = 0x0000, /* None */
+ targ_spyd_pld = 0x0001, /* Spyder PLD pattern */
+ targ_spyd_cal = 0x0002, /* Spyder spectral calibration */
+ targ_i1d3_edr = 0x0004, /* i1d3 .edr or .ccss */
+ targ_ccmx = 0x0008 /* .ccmx */
+} targ_type;
+
+/* An install path, volume name or archive name */
+typedef struct {
+ char *path;
+ targ_type ttype; /* Hint to target type */
+ file_type ftype; /* Hint to file type (instpaths only) */
+} oem_source;
+
+/* A definition of an install target */
+typedef struct {
+ oem_source instpaths[MAX_ARCH_LISTS]; /* Possible archive install paths, NULL terminated */
+ oem_source volnames[MAX_ARCH_LISTS]; /* Possible volume names, NULL terminated */
+ oem_source archnames[MAX_ARCH_LISTS]; /* Possible archive file names, NULL terminated */
+} oem_target;
+
+/* A list of files stored in memory. */
+typedef struct {
+ char *name; /* Name of file, NULL for last entry */
+ unsigned char *buf; /* It's contents */
+ size_t len; /* The length of the contents */
+ file_type ftype; /* Hint to file type */
+ targ_type ttype; /* Target type */
+} xfile;
+
+/* return a list with the given number of available entries */
+xfile *new_xf(int n);
+
+/* Add an entry to the list. Create the list if it is NULL */
+/* Return point to that entry */
+xfile *add_xf(xfile **l);
+
+/* Append an entry and copy details to the list. Create the list if it is NULL */
+/* Return point to that entry */
+xfile *new_add_xf(xfile **l, char *name, unsigned char *buf, unsigned long len,
+ file_type ftype, targ_type ttype);
+
+/* Free up a whole list */
+void del_xf(xfile *l);
+
+/* Allocate and load the given entry. */
+/* Return NZ on error */
+int load_xfile(xfile *xf, int verb);
+
+/* Save a file to the given sname, or of it is NULL, */
+/* to prefix + file name (path is ignored) */
+/* Error on failure */
+void save_xfile(xfile *xf, char *sname, char *pfx, int verb);
+
+/* Given a list of source archives or files, convert them to a list of install files, */
+/* or if no files are given look for installed files or files from a CD. */
+/* Return NULL if none found. files is deleted. */
+xfile *oemarch_get_ifiles(xfile *files, int verb);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define OEMARCH_H
+#endif /* OEMARCH_H */
diff --git a/spectro/oeminst.c b/spectro/oeminst.c
new file mode 100644
index 0000000..88efae0
--- /dev/null
+++ b/spectro/oeminst.c
@@ -0,0 +1,276 @@
+/*
+ * Argyll Color Correction System
+ *
+ * OEM data file installer.
+ *
+ * Author: Graeme W. Gill
+ * Date: 13/11/2012
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include <fcntl.h>
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xdg_bds.h"
+#include "conv.h"
+#include "aglob.h"
+#include "oemarch.h"
+#include "xspect.h"
+#include "ccmx.h"
+#include "ccss.h"
+
+void usage(void) {
+ fprintf(stderr,"Install OEM data files, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the GPL Version 2 or later\n");
+ fprintf(stderr,"usage: oeminst [-options] [infile(s)]\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -n Don't install, show where files would be installed\n");
+ fprintf(stderr," -c Don't install, save files to current directory\n");
+ fprintf(stderr," -S d Specify the install scope u = user (def.), l = local system]\n");
+ fprintf(stderr," infile setup.exe CD install file(s) or .dll(s) containing install files\n");
+ fprintf(stderr," infile.[edr|ccss|ccmx] EDR file(s) to translate and install or CCSS or CCMX files to install\n");
+ fprintf(stderr," If no file is provided, oeminst will look for the install CD.\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ xdg_scope scope = xdg_user;
+ int verb = 0;
+ int install = 1;
+ int local = 0;
+ int has_ccss = 0;
+ char *install_dir = "";
+ int i;
+ xfile *files = NULL;
+ int rv = 0;
+
+ set_exe_path(argv[0]); /* Set global exe_path and error_program */
+
+ if (argc < 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ /* No install */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ install = 0;
+ }
+
+ /* Save to current directory */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ local = 1;
+ }
+
+ /* Install scope */
+ else if (argv[fa][1] == 'S') {
+ fa = nfa;
+ if (na == NULL) usage();
+ else if (na[0] == 'l' || na[0] == 'L')
+ scope = xdg_local;
+ else if (na[0] == 'u' || na[0] == 'U')
+ scope = xdg_user;
+ }
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa > argc || (fa < argc && argv[fa][0] == '-')) usage();
+
+ /* If filename(s) are provided, load the files up. */
+ /* We don't know what they are, but oemarch_get_ifiles() will figure it out */
+ for (; fa < argc; fa++) {
+ xfile *xf;
+ xf = new_add_xf(&files, argv[fa], NULL, 0, file_arch | file_dllcab | file_data,
+ targ_spyd_pld | targ_spyd_cal
+ | targ_i1d3_edr | targ_ccmx);
+ if (load_xfile(xf, verb))
+ error("Unable to load file '%s'",xf->name);
+ }
+
+ /* Turn files into installables */
+ if ((files = oemarch_get_ifiles(files, verb)) == NULL)
+ error("Didn't locate any files to install - no CD present ?\n");
+
+ /* If there are any ccss files to install, supliment with any found in ../ref */
+ for (i = 0; files[i].name != NULL; i++) {
+ if (files[i].ftype == file_data
+ && files[i].ttype == targ_i1d3_edr)
+ has_ccss = 1;
+ }
+ if (has_ccss) {
+ int len;
+ char *pp;
+ char tname[MAXNAMEL+1] = { '\000' };
+ aglob ag;
+
+ strcpy(tname, exe_path);
+
+ len = strlen(tname);
+ if ((pp = strrchr(tname, '/')) != NULL)
+ *pp = '\000';
+ if ((pp = strrchr(tname, '/')) != NULL) {
+ strcpy(pp, "/ref/*.ccss");
+
+ if (aglob_create(&ag, tname))
+ error("Searching for '%s' malloc error",tname);
+
+ for (;;) {
+ char *cp;
+ xfile *xf;
+ if ((pp = aglob_next(&ag)) == NULL)
+ break;
+
+ /* Leave just base filename */
+ if ((cp = strrchr(pp, '/')) == NULL
+ && (cp = strrchr(pp, '\\')) == NULL)
+ cp = pp;
+ else
+ cp++;
+
+ xf = new_add_xf(&files, pp, NULL, 0, file_data, targ_i1d3_edr);
+ if (load_xfile(xf, verb))
+ error("Unable to load file '%s'",xf->name);
+ free(xf->name);
+ if ((xf->name = strdup(cp)) == NULL)
+ error("strdup failed");
+ }
+ aglob_cleanup(&ag);
+ }
+ }
+
+#ifdef NEVER
+ for (i = 0; files[i].name != NULL; i++) {
+ printf("Got '%s' size %d ftype 0x%x ttype 0x%x to install\n",files[i].name,files[i].len,files[i].ftype,files[i].ttype);
+ }
+#endif
+
+ /* Do a special check of ccmx and ccss files, to warn if there will be problems with them */
+ for (i = 0; files[i].name != NULL; i++) {
+ xfile *xf = &files[i];
+
+ if (xf->ttype & targ_ccmx) {
+ ccmx *cx;
+ if ((cx = new_ccmx()) == NULL)
+ error("new_ccmx failed");
+ if (cx->buf_read_ccmx(cx, xf->buf, xf->len)) {
+ error("Reading '%s' failed with '%s'\n",xf->name,cx->err);
+ }
+ if (cx->cbid <= 0)
+ error("'%s' doesn't contain DISPLAY_TYPE_BASE_ID field :- it can't be installed without this!",xf->name);
+ if (cx->refrmode < 0)
+ warning("'%s' doesn't contain DISPLAY_TYPE_REFRESH field :- non-refresh will be assumed!",xf->name);
+ cx->del(cx);
+ } else if (xf->ttype & targ_i1d3_edr) {
+ ccss *ss;
+ if ((ss = new_ccss()) == NULL)
+ error("new_ccss failed");
+ if (ss->buf_read_ccss(ss, xf->buf, xf->len)) {
+ error("Reading '%s' failed with '%s'\n",xf->name,ss->err);
+ }
+ if (ss->refrmode < 0)
+ warning("'%s' doesn't contain DISPLAY_TYPE_REFRESH field :- non-refresh will be assumed!",xf->name);
+ ss->del(ss);
+ }
+ }
+
+ /* We now have all the install files loaded into files. Save or install them all */
+
+ if (!local) /* Install them in ArgyllCMS sub-directory */
+ install_dir = "ArgyllCMS/";
+
+ /* Save all the install file */
+ for (i = 0; files[i].name != NULL; i++) {
+ xfile *xf = &files[i];
+ size_t len;
+ char *install_name = NULL, *cp;
+
+ if (xf->ftype != file_data) {
+ if (verb) printf("Skipping '%s' as its type is unknown\n",xf->name);
+ continue;
+ }
+
+ /* Create install path and name */
+ len = strlen(install_dir) + strlen(xf->name);
+ if ((install_name = malloc(len)) == NULL)
+ error("malloc install_name %d bytes failed",len);
+
+ strcpy(install_name, install_dir);
+
+ /* Append just the basename of the xf */
+ if ((cp = strrchr(xf->name, '/')) == NULL
+ && (cp = strrchr(xf->name, '\\')) == NULL)
+ cp = xf->name;
+ else
+ cp++;
+
+ strcat(install_name, cp);
+
+ if (!local) {
+ char **paths = NULL;
+ int npaths = 0;
+
+ /* Get destination path. This may drop uid/gid if we are su */
+ if ((npaths = xdg_bds(NULL, &paths, xdg_data, xdg_write, scope, install_name)) < 1) {
+ error("Failed to find/create XDG_DATA path '%s'",install_name);
+ }
+ if (install)
+ save_xfile(xf, paths[0], NULL, verb);
+ else
+ printf("Would install '%s'\n",paths[0]);
+ xdg_free(paths, npaths);
+
+ } else {
+ if (install)
+ save_xfile(xf, install_name, NULL, verb);
+ else
+ printf("Would save '%s'\n",install_name);
+ }
+ free(install_name);
+ }
+
+ del_xf(files);
+
+ return 0;
+}
diff --git a/spectro/pollem.c b/spectro/pollem.c
new file mode 100644
index 0000000..f7578c8
--- /dev/null
+++ b/spectro/pollem.c
@@ -0,0 +1,111 @@
+
+ /* Unix serial I/O class poll() emulation. */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/9/2004
+ *
+ * Copyright 2004, 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#ifdef UNIX
+
+/* Fake up poll() support on systems that only support select() */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <memory.h>
+
+/* select() defined, but not poll(), so emulate poll() */
+#if defined(FD_CLR) && !defined(POLLIN)
+
+#include <sys/time.h>
+
+#include "pollem.h"
+
+int pollem(struct pollfd *fds, unsigned long nfds, int timeout) {
+ int i, nfd;
+ fd_set rd_ary; /* Select array for read file descriptors */
+ fd_set wr_ary; /* Select array for write file descriptors */
+ fd_set ex_ary; /* Select array for exception file descriptors */
+ struct timeval tv; /* Timeout value */
+ struct timeval *ptv = &tv; /* Pointer to above */
+ int result; /* Select return value */
+
+ /* Translate files and events */
+ FD_ZERO(&rd_ary);
+ FD_ZERO(&wr_ary);
+ FD_ZERO(&ex_ary);
+
+ for (i = nfd = 0; i < nfds; i++) {
+ fds[i].revents = 0;
+
+ if (fds[i].events & POLLIN) {
+ FD_SET(fds[i].fd, &rd_ary);
+ if (fds[i].fd > nfd)
+ nfd = fds[i].fd;
+ }
+
+ if (fds[i].events & POLLPRI) {
+ FD_SET(fds[i].fd, &ex_ary);
+ if (fds[i].fd > nfd)
+ nfd = fds[i].fd;
+ }
+
+ if (fds[i].events & POLLOUT) {
+ FD_SET(fds[i].fd, &wr_ary);
+ if (fds[i].fd > nfd)
+ nfd = fds[i].fd;
+ }
+ }
+ nfd++; /* Maximum file desciptor index + 1 */
+
+ /* Translate timeout */
+ if (timeout == -1) {
+ ptv = NULL; /* Wait forever */
+
+ } else if (timeout == 0) {
+ tv.tv_sec = 0; /* Return imediately */
+ tv.tv_usec = 0;
+
+ } else { /* Convert milliseconds to seconds and useconds */
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000;
+ }
+
+ /* Do the select */
+ if ((result = select(nfd, &rd_ary, &wr_ary, &ex_ary, ptv)) > 0) {
+
+ for (i = 0; i < nfds; i++) {
+ fds[i].revents = 0;
+
+ if (FD_ISSET(fds[i].fd, &ex_ary))
+ fds[i].revents |= POLLPRI;
+
+ if (FD_ISSET(fds[i].fd, &rd_ary))
+ fds[i].revents |= POLLIN;
+
+ if (FD_ISSET(fds[i].fd, &wr_ary))
+ fds[i].revents |= POLLOUT;
+ }
+ }
+
+ return result;
+}
+
+#endif /* FD_CLR */
+
+#endif /* UNIX */
diff --git a/spectro/pollem.h b/spectro/pollem.h
new file mode 100644
index 0000000..f8a86ee
--- /dev/null
+++ b/spectro/pollem.h
@@ -0,0 +1,50 @@
+
+#ifndef POLLEN_H
+
+ /* Unix serial I/O class poll() emulation. */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/9/2004
+ *
+ * Copyright 2004, 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#ifdef UNIX
+
+/* Fake up poll() support on systems that only support select() */
+
+/* Fake poll array structure */
+struct pollfd {
+ int fd; /* File descriptor */
+ short events; /* Requested events */
+ short revents; /* Returned events */
+};
+
+/* Fake Poll flag values supported */
+#define POLLIN 0x01
+#define POLLPRI 0x02
+#define POLLOUT 0x04
+
+/* Timeout is in milliseconds, -1 == wait forever */
+int pollem(struct pollfd fds[], unsigned long nfds, int timeout);
+
+#define POLLEN_H
+#endif /* POLLEN_H */
+
+#endif /* UNIX */
+
+#ifdef __cplusplus
+ }
+#endif
+
diff --git a/spectro/spec2cie.c b/spectro/spec2cie.c
new file mode 100644
index 0000000..99fe898
--- /dev/null
+++ b/spectro/spec2cie.c
@@ -0,0 +1,831 @@
+
+/*
+ * Argyll Color Correction System
+ * Spectral .ti3 file converter
+ *
+ * Copyright 2005 Gerhard Fuernkranz
+ * All rights reserved.
+ *
+ * Copyright 2006, 2007 Graeme Gill.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * See the License2.txt file for details.
+ *
+ * Pursuant to the above, this file is licenced in ArgyllCMS
+ * under the GNU GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ *
+ * This program takes the spectral data in a .ti3 file, converts them
+ * to XYZ and Lab and fills the XYZ_[XYZ] and LAB_[LAB] columns in the
+ * output .ti3 file with the computed XYZ and Lab values. If the columns
+ * XYZ_[XYZ] and/or LAB_[LAB] are missing in the input file, they are
+ * added to the output file.
+ *
+ * All other colums are copied from the input to the output .ti3 file.
+ *
+ * If the -f option is used, the FWA corrected spectral reflectances
+ * are written to the output .ti3 file, instead of simply copying the
+ * spectral reflectances from the input .ti3 file. In this case, the
+ * XYZ_[XYZ] and LAB_[LAB] values are computed from the FWA corrected
+ * reflectances as well.
+ */
+
+/*
+ NOTE this uses hard coded space signatures, and should be converted
+ to use xcolorants instead.
+
+ This doesn't handle display .ti3's properly, as the resulting CIE values
+ need to be normalised to Y=100 or marked as not normalised.
+
+ Calibration tables aren't being passed through either ??
+ */
+
+#define ALLOW_PLOT
+#define XRES 200
+
+
+#include <stdio.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "inst.h"
+#ifdef ALLOW_PLOT
+#include "plot.h"
+#endif
+
+
+void
+usage (void)
+{
+ fprintf (stderr, "Convert spectral .ti3 file, Version %s\n", ARGYLL_VERSION_STR);
+ fprintf (stderr, "Author: Gerhard Fuernkranz, licensed under the AGPL Version 3\n");
+ fprintf (stderr, "\n");
+ fprintf (stderr, "Usage: spec2cie [options] input.ti3 output.ti3\n");
+ fprintf (stderr, " -v Verbose mode\n");
+ fprintf (stderr, " -I illum Override actual instrument illuminant in .ti3 file:\n");
+ fprintf (stderr, " A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf (stderr, " (only used in conjunction with -f)\n");
+ fprintf (stderr, " -f [illum] Use Fluorescent Whitening Agent compensation [simulated inst. illum.:\n");
+ fprintf (stderr, " M0, M1, M2, A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp]\n");
+ fprintf (stderr, " -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n");
+ fprintf (stderr, " A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf (stderr, " -o observ Choose CIE Observer for spectral data:\n");
+ fprintf (stderr, " 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
+ fprintf (stderr, " -n Don't output spectral values\n");
+#ifdef ALLOW_PLOT
+ fprintf (stderr, " -p Plot each values spectrum\n");
+#endif
+ fprintf (stderr, " input.ti3 Measurement file\n");
+ fprintf (stderr, " output.ti3 Converted measurement file\n");
+ exit (1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int fa, nfa; /* current argument we're looking at */
+ int verb = 0;
+ int nospec = 0; /* NZ if not to output spectral values */
+ char *in_ti3_name;
+ char *out_ti3_name;
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ cgats_set_elem *elems;
+
+ int isdisp = 0; /* nz if this is a display device */
+ int isdnormed = 0; /* Has display data been normalised to 100 ? */
+ icColorSpaceSignature devspace = icmSigDefaultData; /* The device colorspace */
+ int isAdditive = 0; /* 0 if subtractive, 1 if additive colorspace */
+ int isInverted = 0; /* nz if inverted real device */
+ int ci, mi, yi, ki; /* Indexes of device values */
+ int fwacomp = 0; /* FWA compensation */
+ int doplot = 0; /* Plot each patches spectrum */
+ char* illum_str = "D50";
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */
+ icxIllumeType illum = icxIT_D50; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxIllumeType inst_illum = icxIT_none; /* Spectral defaults */
+ xspect inst_cust_illum; /* Custom illumination spectrum */
+ icxObserverType observ = icxOT_CIE_1931_2;
+
+ int npat; /* Number of patches */
+ char *kw;
+ int i, j, jj, k;
+
+#if defined(__IBMC__)
+ _control87 (EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87 (EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ if (argc < 3)
+ usage ();
+
+ /* Process the arguments */
+ for (fa = 1; fa < argc; fa++) {
+
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa + 1) < argc) {
+ if (argv[fa + 1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage ();
+
+ /* Verbose */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ /* Don't output spectral */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N')
+ nospec = 1;
+
+ /* Plot each patch spectral value */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P')
+ doplot = 1;
+
+ /* Instrument Illuminant type */
+ else if (argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL)
+ usage ();
+ if (strcmp (na, "A") == 0) {
+ inst_illum = icxIT_A;
+ }
+ else if (strcmp (na, "C") == 0) {
+ inst_illum = icxIT_C;
+ }
+ else if (strcmp (na, "D50") == 0) {
+ inst_illum = icxIT_D50;
+ }
+ else if (strcmp (na, "D50M2") == 0) {
+ inst_illum = icxIT_D50M2;
+ }
+ else if (strcmp (na, "D65") == 0) {
+ inst_illum = icxIT_D65;
+ }
+ else if (strcmp (na, "F5") == 0) {
+ inst_illum = icxIT_F5;
+ }
+ else if (strcmp (na, "F8") == 0) {
+ inst_illum = icxIT_F8;
+ }
+ else if (strcmp (na, "F10") == 0) {
+ inst_illum = icxIT_F10;
+ }
+ else { /* Assume it's a filename */
+ inst_illum = icxIT_custom;
+ if (read_xspect (&inst_cust_illum, na) != 0)
+ usage ();
+ }
+ }
+
+ /* FWA comp & simulated instrument illuminant */
+ else if (argv[fa][1] == 'f') {
+ fwacomp = 1;
+
+ if (na != NULL) { /* Argument is present - target/simulated instr. illum. */
+ fa = nfa;
+ if (strcmp(na, "A") == 0
+ || strcmp(na, "M0") == 0) {
+ tillum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ tillum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0
+ || strcmp(na, "M1") == 0) {
+ tillum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0
+ || strcmp(na, "M2") == 0) {
+ tillum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ tillum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ tillum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ tillum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ tillum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ tillum = icxIT_custom;
+ if (read_xspect(&cust_tillum, na) != 0)
+ usage();
+ }
+ }
+ }
+
+ /* CIE tristimulous spectral Illuminant type */
+ else if (argv[fa][1] == 'i') {
+ fa = nfa;
+ if (na == NULL)
+ usage ();
+ illum_str = na;
+ if (strcmp (na, "A") == 0) {
+ illum = icxIT_A;
+ }
+ else if (strcmp (na, "C") == 0) {
+ illum = icxIT_C;
+ }
+ else if (strcmp (na, "D50") == 0) {
+ illum = icxIT_D50;
+ }
+ else if (strcmp (na, "D50M2") == 0) {
+ illum = icxIT_D50M2;
+ }
+ else if (strcmp (na, "D65") == 0) {
+ illum = icxIT_D65;
+ }
+ else if (strcmp (na, "F5") == 0) {
+ illum = icxIT_F5;
+ }
+ else if (strcmp (na, "F8") == 0) {
+ illum = icxIT_F8;
+ }
+ else if (strcmp (na, "F10") == 0) {
+ illum = icxIT_F10;
+ }
+ else { /* Assume it's a filename */
+ illum = icxIT_custom;
+ if (read_xspect (&cust_illum, na) != 0)
+ usage ();
+ }
+ }
+
+ /* Spectral Observer type */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL)
+ usage ();
+ if (strcmp (na, "1931_2") == 0) { /* Classic 2 degree */
+ observ = icxOT_CIE_1931_2;
+ }
+ else if (strcmp (na, "1964_10") == 0) { /* Classic 10 degree */
+ observ = icxOT_CIE_1964_10;
+ }
+ else if (strcmp (na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ observ = icxOT_Stiles_Burch_2;
+ }
+ else if (strcmp (na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ observ = icxOT_Judd_Voss_2;
+ }
+ else if (strcmp (na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ observ = icxOT_Shaw_Fairchild_2;
+ }
+ else
+ usage ();
+ }
+
+ else
+ usage ();
+ }
+ else
+ break;
+ }
+
+ /* Get the file name arguments */
+ if (fa >= argc || argv[fa][0] == '-')
+ usage ();
+
+ in_ti3_name = argv[fa++];
+
+ if (fa >= argc || argv[fa][0] == '-')
+ usage ();
+
+ out_ti3_name = argv[fa++];
+
+ /* Open and look at the .ti3 profile patches file */
+
+ icg = new_cgats (); /* Create a CGATS structure */
+ icg->add_other (icg, "CTI3"); /* Calibration Target Information 3 */
+
+ ocg = new_cgats (); /* Create a CGATS structure */
+ ocg->add_other (ocg, "CTI3"); /* Calibration Target Information 3 */
+
+ if (icg->read_name (icg, in_ti3_name))
+ error ("CGATS file read error: %s", icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI3 format file");
+ if (icg->ntables < 1)
+ error ("Input file doesn't contain at least one table");
+
+ /* add table to output file */
+
+ ocg->add_table(ocg, tt_other, 0);
+
+ /* copy keywords */
+
+ for (i = 0; i < icg->t[0].nkwords; i++) {
+ kw = icg->t[0].ksym[i];
+ if (fwacomp && strcmp(kw, "TARGET_INSTRUMENT") == 0) {
+ /*
+ * overwrite TARGET_INSTRUMENT with the new illuminant,
+ * since the FWA corrected spectral data are no longer
+ * valid for the original instrument's illuminant
+ */
+ ocg->add_kword (ocg, 0, kw, illum_str, NULL);
+ }
+ else {
+ ocg->add_kword (ocg, 0, kw,
+ icg->t[0].kdata[i], icg->t[0].kcom[i]);
+ }
+ }
+
+ /* Figure out what sort of device it is */
+
+ {
+ int ti;
+
+ if ((ti = icg->find_kword (icg, 0, "DEVICE_CLASS")) < 0)
+ error ("Input file doesn't contain keyword DEVICE_CLASS");
+
+ if (strcmp (icg->t[0].kdata[ti], "DISPLAY") == 0) {
+ isdisp = 1;
+ }
+
+ /* See if the display CIE data has been normalised to Y = 100 */
+ if ((ti = icg->find_kword(icg, 0, "NORMALIZED_TO_Y_100")) < 0
+ || strcmp(icg->t[0].kdata[ti],"NO") == 0) {
+ isdnormed = 0;
+ } else {
+ isdnormed = 1;
+ }
+
+ if (isdisp && fwacomp) {
+ error ("FWA compensation cannot be used for DISPLAY devices");
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error("Input file doesn't contain keyword COLOR_REP");
+
+ if (strncmp(icg->t[0].kdata[ti],"CMYK_",5) == 0)
+ devspace = icSigCmykData;
+ else if (strncmp(icg->t[0].kdata[ti],"CMY_",4) == 0)
+ devspace = icSigCmyData;
+ else if (strncmp(icg->t[0].kdata[ti],"RGB_",4) == 0)
+ devspace = icSigRgbData;
+ else if (strncmp(icg->t[0].kdata[ti],"iRGB_",4) == 0) {
+ devspace = icSigRgbData;
+ isInverted = 1;
+ } else if (strncmp(icg->t[0].kdata[ti],"K_",2) == 0) {
+ devspace = icSigGrayData;
+ isAdditive = 0;
+ } else if (strncmp(icg->t[0].kdata[ti],"W_",2) == 0) {
+ devspace = icSigGrayData;
+ isAdditive = 1;
+ } else
+ error("Device has unhandled color representation '%s'",icg->t[0].kdata[ti]);
+
+ if (devspace == icSigGrayData) {
+
+ if (isAdditive) {
+ if ((ci = icg->find_field(icg, 0, "GRAY_W")) < 0)
+ error("Input file doesn't contain field GRAY_W");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field GRAY_W is wrong type - corrupted file ?");
+ } else {
+ if ((ci = icg->find_field(icg, 0, "GRAY_K")) < 0)
+ error("Input file doesn't contain field GRAY_K");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field GRAY_K is wrong type - corrupted file ?");
+ }
+ mi = yi = ki = ci;
+
+ } else if (devspace == icSigRgbData) {
+
+ if ((ci = icg->find_field(icg, 0, "RGB_R")) < 0)
+ error("Input file doesn't contain field RGB_R");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field RGB_R is wrong type - corrupted file ?");
+ if ((mi = icg->find_field(icg, 0, "RGB_G")) < 0)
+ error("Input file doesn't contain field RGB_G");
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Field RGB_G is wrong type - corrupted file ?");
+ if ((yi = icg->find_field(icg, 0, "RGB_B")) < 0)
+ error("Input file doesn't contain field RGB_B");
+ if (icg->t[0].ftype[yi] != r_t)
+ error("Field RGB_B is wrong type - corrupted file ?");
+ ki = yi;
+
+ } else if (devspace == icSigCmyData) {
+
+ if ((ci = icg->find_field(icg, 0, "CMY_C")) < 0)
+ error("Input file doesn't contain field CMY_C");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field CMY_C is wrong type - corrupted file ?");
+ if ((mi = icg->find_field(icg, 0, "CMY_M")) < 0)
+ error("Input file doesn't contain field CMY_M");
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Field CMY_M is wrong type - corrupted file ?");
+ if ((yi = icg->find_field(icg, 0, "CMY_Y")) < 0)
+ error("Input file doesn't contain field CMY_Y");
+ if (icg->t[0].ftype[yi] != r_t)
+ error("Field CMY_Y is wrong type - corrupted file ?");
+ ki = yi;
+
+ } else { /* Assume CMYK */
+
+ if ((ci = icg->find_field(icg, 0, "CMYK_C")) < 0)
+ error("Input file doesn't contain field CMYK_C");
+ if (icg->t[0].ftype[ci] != r_t)
+ error("Field CMYK_C is wrong type - corrupted file ?",icg->t[0].ftype[ci],r_t);
+ if ((mi = icg->find_field(icg, 0, "CMYK_M")) < 0)
+ error("Input file doesn't contain field CMYK_M");
+ if (icg->t[0].ftype[mi] != r_t)
+ error("Field CMYK_M is wrong type - corrupted file ?");
+ if ((yi = icg->find_field(icg, 0, "CMYK_Y")) < 0)
+ error("Input file doesn't contain field CMYK_Y");
+ if (icg->t[0].ftype[yi] != r_t)
+ error("Field CMYK_Y is wrong type - corrupted file ?");
+ if ((ki = icg->find_field(icg, 0, "CMYK_K")) < 0)
+ error("Input file doesn't contain field CMYK_K");
+ if (icg->t[0].ftype[ki] != r_t)
+ error("Field CMYK_K is wrong type - corrupted file ?");
+ }
+ }
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ /* Read in the CGATs fields */
+
+ {
+ int sidx; /* Sample ID index */
+ int ti, ii, Xi, Yi, Zi, Li, ai, bi;
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xsp2cie *sp2cie; /* Spectral conversion object */
+ xspect sp;
+ double XYZ[3];
+ double Lab[3];
+ char buf[100];
+ /* These are only set if fwa is needed */
+ xspect rmwsp; /* Raw medium white spectrum */
+ xspect mwsp; /* FWA compensated medium white spectrum */
+ double mwXYZ[3]; /* Media white XYZ */
+
+ if ((sidx = icg->find_field (icg, 0, "SAMPLE_ID")) < 0)
+ error ("Input file doesn't contain field SAMPLE_ID");
+ if (icg->t[0].ftype[sidx] != nqcs_t)
+ error ("Field SAMPLE_ID is wrong type");
+
+ /* Using spectral data */
+
+ if ((ii = icg->find_kword (icg, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ sp.spec_n = atoi (icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword (icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ sp.spec_wl_short = atof (icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword (icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ sp.spec_wl_long = atof (icg->t[0].kdata[ii]);
+ if (!isdisp || isdnormed != 0)
+ sp.norm = 100.0;
+ else
+ sp.norm = 1.0;
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int) (sp.spec_wl_short +
+ ((double) j / (sp.spec_n - 1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf (buf, "SPEC_%03d", nm);
+
+ if ((spi[j] = icg->find_field (icg, 0, buf)) < 0)
+ error ("Input file doesn't contain field %s", buf);
+ }
+
+ if (isdisp) {
+ illum = icxIT_none; /* Displays are assumed to be self luminous */
+ }
+
+ /* copy fields to output file (except spectral if nospec) */
+ for (i = 0; i < icg->t[0].nfields; i++) {
+ /* See if this is a input spectral field */
+ for (j = 0; nospec && j < sp.spec_n; j++) {
+ if (spi[j] == i)
+ break; /* Yes it is */
+ }
+ if (nospec == 0 || j >= sp.spec_n)
+ ocg->add_field (ocg, 0, icg->t[0].fsym[i], icg->t[0].ftype[i]);
+ }
+
+ /* create field for XYZ and Lab if not present */
+
+ if ((Xi = icg->find_field(icg, 0, "XYZ_X")) < 0)
+ if ((Xi = ocg->add_field(ocg, 0, "XYZ_X", r_t)) < 0)
+ error ("Cannot add field to table");
+
+ if ((Yi = icg->find_field(icg, 0, "XYZ_Y")) < 0)
+ if ((Yi = ocg->add_field(ocg, 0, "XYZ_Y", r_t)) < 0)
+ error ("Cannot add field to table");
+
+ if ((Zi = icg->find_field(icg, 0, "XYZ_Z")) < 0)
+ if ((Zi = ocg->add_field(ocg, 0, "XYZ_Z", r_t)) < 0)
+ error ("Cannot add field to table");
+
+ if ((Li = icg->find_field(icg, 0, "LAB_L")) < 0)
+ if ((Li = ocg->add_field(ocg, 0, "LAB_L", r_t)) < 0)
+ error ("Cannot add field to table");
+
+ if ((ai = icg->find_field(icg, 0, "LAB_A")) < 0)
+ if ((ai = ocg->add_field(ocg, 0, "LAB_A", r_t)) < 0)
+ error ("Cannot add field to table");
+
+ if ((bi = icg->find_field(icg, 0, "LAB_B")) < 0)
+ if ((bi = ocg->add_field(ocg, 0, "LAB_B", r_t)) < 0)
+ error ("Cannot add field to table");
+
+ /* allocate elements */
+
+ if ((elems = (cgats_set_elem *)
+ calloc(ocg->t[0].nfields, sizeof(cgats_set_elem))) == NULL)
+ {
+ error("Out of memory");
+ }
+
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie (illum,
+ illum == icxIT_none ? NULL : &cust_illum,
+ observ, NULL, icSigXYZData, icxClamp)) == NULL)
+ {
+ error ("Creation of spectral conversion object failed");
+ }
+
+ if (fwacomp) {
+ double nw = 0.0; /* Number of media white patches */
+
+ rmwsp = sp; /* Initial Struct copy */
+
+ /* Find the media white spectral reflectance */
+ for (j = 0; j < rmwsp.spec_n; j++)
+ rmwsp.spec[j] = 0.0;
+
+ /* Compute the mean of all the media white patches */
+ for (i = 0; i < npat; i++) {
+ int use = 0;
+
+ if (devspace == icSigGrayData) {
+ if (isAdditive) {
+ if (*((double *)icg->t[0].fdata[i][ci]) > (100.0 - 0.1))
+ use = 1;
+ } else {
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1)
+ use = 1;
+ }
+ } else if (devspace == icSigRgbData) {
+ if (*((double *)icg->t[0].fdata[i][ci]) > (100.0 - 0.1)
+ && *((double *)icg->t[0].fdata[i][mi]) > (100.0 - 0.1)
+ && *((double *)icg->t[0].fdata[i][yi]) > (100.0 - 0.1))
+ use = 1;
+ } else if (devspace == icSigCmyData) {
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1
+ && *((double *)icg->t[0].fdata[i][mi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][yi]) < 0.1)
+ use = 1;
+ } else { /* Assume CMYK */
+
+ if (*((double *)icg->t[0].fdata[i][ci]) < 0.1
+ && *((double *)icg->t[0].fdata[i][mi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][yi]) < 0.1
+ && *((double *)icg->t[0].fdata[i][ki]) < 0.1) {
+ use = 1;
+ }
+ }
+
+ if (use) {
+ /* Read the spectral values for this patch */
+ for (j = 0; j < rmwsp.spec_n; j++) {
+ rmwsp.spec[j] += *((double *)icg->t[0].fdata[i][spi[j]]);
+ }
+ nw++;
+ }
+ }
+
+ if (nw == 0.0) {
+ warning("Can't find a media white patch to compute white reference");
+ warning("Using maximum of all spectral readings instead");
+
+ /* Track the maximum reflectance for any band to determine white. */
+ /* This might give bogus results if there is no white patch... */
+ for (i = 0; i < npat; i++) {
+ for (j = 0; j < rmwsp.spec_n; j++) {
+ double rv = *((double *)icg->t[0].fdata[i][spi[j]]);
+ if (rv > rmwsp.spec[j])
+ rmwsp.spec[j] = rv;
+ }
+ }
+ nw++;
+ }
+ for (j = 0; j < rmwsp.spec_n; j++) {
+ rmwsp.spec[j] /= nw; /* Compute average */
+ }
+ mwsp = rmwsp; /* Structure copy */
+ }
+
+ if (fwacomp) {
+ instType itype; /* Spectral instrument type */
+ xspect insp; /* Instrument illuminant */
+
+ if (inst_illum == icxIT_none) {
+ /* try to get from .ti3 file */
+ if ((ti = icg->find_kword (icg, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Can't find target instrument needed for FWA compensation");
+
+ if ((itype = inst_enum (icg->t[0].kdata[ti])) == instUnknown)
+ error ("Unrecognised target instrument '%s'",
+ icg->t[0].kdata[ti]);
+
+ if (inst_illuminant (&insp, itype) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+ }
+ else if (inst_illum == icxIT_custom) {
+ insp = inst_cust_illum; /* Structure copy */
+ }
+ else {
+ if (standardIlluminant(&insp, inst_illum, 0) != 0)
+ error ("Failed to find standard illuminant");
+ }
+
+ /* If we are setting a specific simulated instrument illuminant */
+ if (tillum != icxIT_none) {
+ tillump = &cust_tillum;
+ if (tillum != icxIT_custom) {
+ if (standardIlluminant(tillump, tillum, 0.0)) {
+ error("simulated inst. illum. not recognised");
+ }
+ }
+ }
+
+ /* (Note that sp and mwsp.norm is set to 100.0) */
+ if (sp2cie->set_fwa(sp2cie, &insp, tillump, &mwsp))
+ error ("Set FWA on sp2cie failed");
+
+ if (verb) {
+ double FWAc;
+ sp2cie->get_fwa_info(sp2cie, &FWAc);
+ printf("FWA content = %f\n",FWAc);
+ }
+
+ /* Create an FWA compensated white spectrum and XYZ value */
+ sp2cie->sconvert (sp2cie, &rmwsp, mwXYZ, &mwsp);
+ }
+
+ for (i = 0; i < npat; i++) {
+
+ xspect corr_sp;
+
+ /* copy all input colums to output (except spectral if nospec) */
+
+ for (jj = j = 0; j < icg->t[0].nfields; j++) {
+ for (k = 0; nospec && k < sp.spec_n; k++) {
+ if (spi[k] == j)
+ break;
+ }
+ if (nospec == 0 || k >= sp.spec_n) {
+ switch (icg->t[0].ftype[j]) {
+ case r_t:
+ elems[jj].d = *((double *) icg->t[0].fdata[i][j]);
+ break;
+ case i_t:
+ elems[jj].i = *((int *) icg->t[0].fdata[i][j]);
+ break;
+ default:
+ elems[jj].c = (char *) icg->t[0].fdata[i][j];
+ }
+ jj++;
+ }
+ }
+
+ /* Read the spectral values for this patch */
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+ }
+
+ if (fwacomp) {
+ corr_sp = sp;
+
+ /* Convert it to CIE space */
+ sp2cie->sconvert (sp2cie, &corr_sp, XYZ, &sp);
+
+ /* Write the corrected spectral values for this patch */
+ if (nospec == 0) {
+ for (j = 0; j < sp.spec_n; j++) {
+ elems[spi[j]].d = corr_sp.spec[j];
+ }
+ }
+#ifdef ALLOW_PLOT
+ if (doplot) {
+ int ii;
+ double xx[XRES];
+ double y1[XRES];
+ double y2[XRES];
+ double lab[3];
+
+ icmXYZ2Lab(&icmD50, lab, XYZ);
+ printf("Patch %d, XYZ = %f %f %f, Lab = %f %f %f\n",i,
+ XYZ[0], XYZ[1], XYZ[2], lab[0], lab[1], lab[2]);
+
+ /* Plot spectrum out */
+ for (ii = 0; ii < XRES; ii++) {
+ double ww;
+
+ ww = (sp.spec_wl_long - sp.spec_wl_short)
+ * ((double)ii/(XRES-1.0)) + sp.spec_wl_short;
+
+ xx[ii] = ww;
+ y1[ii] = value_xspect(&sp, ww);
+ y2[ii] = 100.0 * value_xspect(&corr_sp, ww);
+ }
+ do_plot(xx,y1,y2,NULL,ii);
+ }
+#endif
+ }
+ else {
+ /* Convert it to CIE space */
+ sp2cie->convert (sp2cie, XYZ, &sp);
+#ifdef ALLOW_PLOT
+ if (doplot) {
+ int ii;
+ double xx[XRES];
+ double y1[XRES];
+ double lab[3];
+
+ icmXYZ2Lab(&icmD50, lab, XYZ);
+ printf("Patch %d, XYZ = %f %f %f, Lab = %f %f %f\n",i,
+ XYZ[0], XYZ[1], XYZ[2], lab[0], lab[1], lab[2]);
+
+ /* Plot spectrum out */
+ for (ii = 0; ii < XRES; ii++) {
+ double ww;
+
+ ww = (sp.spec_wl_long - sp.spec_wl_short)
+ * ((double)ii/(XRES-1.0)) + sp.spec_wl_short;
+
+ xx[ii] = ww;
+ y1[ii] = value_xspect(&sp, ww);
+ }
+ do_plot(xx,y1,NULL,NULL,ii);
+ }
+#endif
+ }
+
+ icmXYZ2Lab(&icmD50, Lab, XYZ);
+
+ elems[Xi].d = XYZ[0] * 100.0;
+ elems[Yi].d = XYZ[1] * 100.0;
+ elems[Zi].d = XYZ[2] * 100.0;
+
+ elems[Li].d = Lab[0];
+ elems[ai].d = Lab[1];
+ elems[bi].d = Lab[2];
+
+ ocg->add_setarr(ocg, 0, elems);
+ }
+
+ if (ocg->write_name(ocg, out_ti3_name)) {
+ error ("Write error: %s", ocg->err);
+ }
+
+ sp2cie->del (sp2cie); /* Done with this */
+
+ ocg->del (ocg); /* Clean up */
+ icg->del (icg); /* Clean up */
+
+ free (elems);
+ }
+
+ return 0;
+}
+
diff --git a/spectro/spotread.c b/spectro/spotread.c
new file mode 100644
index 0000000..3218243
--- /dev/null
+++ b/spectro/spotread.c
@@ -0,0 +1,2271 @@
+
+ /* Spectrometer/Colorimeter color spot reader utility */
+
+/*
+ * Argyll Color Correction System
+ * Author: Graeme W. Gill
+ * Date: 3/10/2001
+ *
+ * Derived from printread.c/chartread.c
+ * Was called printspot.
+ *
+ * Copyright 2001 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/* This program reads a spot reflection/transmission/emission value using */
+/* a spectrometer or colorimeter. */
+
+/* TTBD
+ *
+ * Should fix plot so that it is a separate object running its own thread,
+ * so that it can be sent a graph without needing to be clicked in all the time.
+ *
+ * Should add option to show reflective/tranmsission density values.
+ *
+ * Should add option for Y u' v' values.
+ */
+
+#undef DEBUG
+#undef TEST_EVENT_CALLBACK /* Report async event callbacks */
+
+#define COMPORT 1 /* Default com port 1..4 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "conv.h"
+#include "plot.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#include "xspect.h"
+#include "conv.h"
+#endif /* SALONEINSTLIB */
+#include "ccss.h"
+#include "ccmx.h"
+#include "inst.h"
+#include "icoms.h"
+#include "instappsup.h"
+#include "spyd2setup.h"
+#ifdef EN_SPYD2
+#include "spyd2setup.h"
+#endif
+
+#if defined (NT)
+#include <conio.h>
+#endif
+
+#ifdef NEVER /* Not currently used */
+/* Convert control chars to ^[A-Z] notation in a string */
+static char *
+fix_asciiz(char *s) {
+ static char buf [200];
+ char *d;
+ for(d = buf; ;) {
+ if (*s < ' ' && *s > '\000') {
+ *d++ = '^';
+ *d++ = *s++ + '@';
+ } else
+ *d++ = *s++;
+ if (s[-1] == '\000')
+ break;
+ }
+ return buf;
+}
+#endif
+
+#ifdef SALONEINSTLIB
+
+#define D50_X_100 96.42
+#define D50_Y_100 100.00
+#define D50_Z_100 82.49
+
+/* CIE XYZ 0..100 to perceptual D50 CIE 1976 L*a*b* */
+static void
+XYZ2Lab(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/D50_X_100;
+ y = Y/D50_Y_100;
+ z = Z/D50_Z_100;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+/* Return the normal Delta E given two Lab values */
+static double LabDE(double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ rv += tt * tt;
+
+ return sqrt(rv);
+}
+
+/* Lab to LCh */
+void Lab2LCh(double *out, double *in) {
+ double C, h;
+
+ C = sqrt(in[1] * in[1] + in[2] * in[2]);
+
+ h = (180.0/3.14159265359) * atan2(in[2], in[1]);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ out[0] = in[0];
+ out[1] = C;
+ out[2] = h;
+}
+
+/* XYZ to Yxy */
+static void XYZ2Yxy(double *out, double *in) {
+ double sum = in[0] + in[1] + in[2];
+ double Y, x, y;
+
+ if (sum < 1e-9) {
+ Y = 0.0;
+ y = 0.0;
+ x = 0.0;
+ } else {
+ Y = in[1];
+ x = in[0]/sum;
+ y = in[1]/sum;
+ }
+ out[0] = Y;
+ out[1] = x;
+ out[2] = y;
+}
+
+#endif /* SALONEINSTLIB */
+
+/* Replacement for gets */
+char *getns(char *buf, int len) {
+ int i;
+ if (fgets(buf, len, stdin) == NULL)
+ return NULL;
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '\n') {
+ buf[i] = '\000';
+ return buf;
+ }
+ }
+ buf[len-1] = '\000';
+ return buf;
+}
+
+/* Deal with an instrument error. */
+/* Return 0 to retry, 1 to abort */
+static int ierror(inst *it, inst_code ic) {
+ int ch;
+ empty_con_chars();
+ printf("Got '%s' (%s) error.\nHit Esc or Q to give up, any other key to retry:",
+ it->inst_interp_error(it, ic), it->interp_error(it, ic));
+ fflush(stdout);
+ ch = next_con_char();
+ printf("\n");
+ if (ch == 0x03 || ch == 0x1b || ch == 'q' || ch == 'Q') /* Escape, ^C or Q */
+ return 1;
+ return 0;
+}
+
+/* A color structure */
+/* This can hold all representations simultaniously */
+typedef struct {
+ double gy;
+ double r,g,b;
+ double cmyk[4];
+ double XYZ[4]; /* Colorimeter readings */
+ double eXYZ[4]; /* Expected XYZ values */
+ xspect sp; /* Spectral reading */
+
+ char *id; /* Id string */
+ char *loc; /* Location string */
+ int loci; /* Location integer = pass * 256 + step */
+} col;
+
+#ifdef TEST_EVENT_CALLBACK
+ void test_event_callback(void *cntx, inst_event_type event) {
+ a1logd(g_log,0,"Got event_callback with 0x%x\n",event);
+ }
+#endif
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a ppc gcc 3.3 optimiser bug... */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+/*
+
+ Flags used:
+
+ ABCDEFGHIJKLMNOPQRSTUVWXYZ
+ upper ... . . . . .. ...
+ lower . .... .. . .. . ..
+
+*/
+
+void
+usage(char *diag, ...) {
+ int i;
+ icompaths *icmps;
+ inst2_capability cap2 = 0;
+ fprintf(stderr,"Measure spot values, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the GPL Version 2 or later\n");
+ if (setup_spyd2() == 2)
+ fprintf(stderr,"WARNING: This file contains a proprietary firmware image, and may not be freely distributed !\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: spotread [-options] [logfile]\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -s Print spectrum for each reading\n");
+#ifndef SALONEINSTLIB
+ fprintf(stderr," -S Plot spectrum for each reading\n");
+#endif /* !SALONEINSTLIB */
+ fprintf(stderr," -c listno Set communication port from the following list (default %d)\n",COMPORT);
+ if ((icmps = new_icompaths(g_log)) != NULL) {
+ icompath **paths;
+ if ((paths = icmps->paths) != NULL) {
+ int i;
+ for (i = 0; ; i++) {
+ if (paths[i] == NULL)
+ break;
+ if (paths[i]->itype == instSpyder2 && setup_spyd2() == 0)
+ fprintf(stderr," %d = '%s' !! Disabled - no firmware !!\n",i+1,paths[i]->name);
+ else
+ fprintf(stderr," %d = '%s'\n",i+1,paths[i]->name);
+ }
+ } else
+ fprintf(stderr," ** No ports found **\n");
+ }
+ fprintf(stderr," -t Use transmission measurement mode\n");
+ fprintf(stderr," -e Use emissive measurement mode (absolute results)\n");
+ fprintf(stderr," -eb Use display white brightness relative measurement mode\n");
+ fprintf(stderr," -ew Use display white relative measurement mode\n");
+ fprintf(stderr," -p Use telephoto measurement mode (absolute results)\n");
+ fprintf(stderr," -pb Use projector white brightness relative measurement mode\n");
+ fprintf(stderr," -pw Use projector white relative measurement mode\n");
+ fprintf(stderr," -a Use ambient measurement mode (absolute results)\n");
+ fprintf(stderr," -f Use ambient flash measurement mode (absolute results)\n");
+ cap2 = inst_show_disptype_options(stderr, " -y ", icmps, 0);
+#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");
+#endif
+ fprintf(stderr," -i illum Choose illuminant for computation of CIE XYZ from spectral data & FWA:\n");
+#ifndef SALONEINSTLIB
+ fprintf(stderr," A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
+#else
+ fprintf(stderr," A, C, D50 (def.), D65\n");
+#endif
+ fprintf(stderr," -Q observ Choose CIE Observer for spectral data or CCSS instrument:\n");
+#ifndef SALONEINSTLIB
+ fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
+#else
+ fprintf(stderr," 1931_2 (def), 1964_10\n");
+#endif
+#ifndef SALONEINSTLIB
+ fprintf(stderr," (Choose FWA during operation)\n");
+#endif
+ fprintf(stderr," -F filter Set filter configuration (if aplicable):\n");
+ fprintf(stderr," n None\n");
+ fprintf(stderr," p Polarising filter\n");
+ fprintf(stderr," 6 D65\n");
+ fprintf(stderr," u U.V. Cut\n");
+ fprintf(stderr," -E extrafilterfile Apply extra filter compensation file\n");
+ fprintf(stderr," -x Display Yxy instead of Lab\n");
+ fprintf(stderr," -h Display LCh instead of Lab\n");
+ fprintf(stderr," -V Show running average and std. devation from ref.\n");
+#ifndef SALONEINSTLIB
+ fprintf(stderr," -T Display correlated color temperatures and CRI\n");
+#endif /* !SALONEINSTLIB */
+// fprintf(stderr," -K type Run instrument calibration first\n");
+ fprintf(stderr," -N Disable auto calibration of instrument\n");
+ fprintf(stderr," -H Start in high resolution spectrum mode (if available)\n");
+ if (cap2 & inst2_ccmx)
+ fprintf(stderr," -X file.ccmx Apply Colorimeter Correction Matrix\n");
+ if (cap2 & inst2_ccss) {
+ fprintf(stderr," -X file.ccss Use Colorimeter Calibration Spectral Samples for calibration\n");
+ }
+ fprintf(stderr," -Y r|n Override refresh, non-refresh display mode\n");
+ fprintf(stderr," -Y A Use non-adaptive integration time mode (if available).\n");
+// fprintf(stderr," -Y U Test i1pro2 UV measurement mode\n");
+ fprintf(stderr," -W n|h|x Override serial port flow control: n = none, h = HW, x = Xon/Xoff\n");
+ fprintf(stderr," -D [level] Print debug diagnostics to stderr\n");
+ fprintf(stderr," logfile Optional file to save reading results as text\n");
+
+ if (icmps != NULL)
+ icmps->del(icmps);
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ int i, j;
+ int fa, nfa, mfa; /* current argument we're looking at */
+ int verb = 0;
+ int debug = 0;
+ int docalib = 0; /* Do a manual instrument calibration */
+ int nocal = 0; /* Disable auto calibration */
+ int pspec = 0; /* 1 = Print out the spectrum for each reading */
+ /* 2 = Plot out the spectrum for each reading */
+ int trans = 0; /* Use transmissioin mode */
+ int emiss = 0; /* 1 = Use emissive mode, 2 = display bright rel. */
+ /* 3 = display white rel. */
+ int tele = 0; /* 1 = Use telephoto emissive sub-mode. */
+ int ambient = 0; /* 1 = Use ambient emissive mode, 2 = ambient flash mode */
+ int highres = 0; /* Use high res mode if available */
+ int uvmode = 0; /* ~~~ i1pro2 test mode ~~~ */
+ int refrmode = -1; /* -1 = default, 0 = non-refresh mode, 1 = non-refresh mode */
+ int nadaptive = 0; /* Use non-apative mode if available */
+ int doYxy= 0; /* Display Yxy instead of Lab */
+ int doLCh= 0; /* Display LCh instead of Lab */
+ int doCCT= 0; /* Display correlated color temperatures */
+ inst_mode mode = 0, smode = 0; /* Normal mode and saved readings mode */
+ inst_opt_type trigmode = inst_opt_unknown; /* Chosen trigger mode */
+ inst_opt_filter fe = inst_opt_filter_unknown;
+ /* Filter configuration */
+ char outname[MAXNAMEL+1] = "\000"; /* Output logfile name */
+ char ccxxname[MAXNAMEL+1] = "\000"; /* Colorimeter Correction/Colorimeter Calibration name */
+ char filtername[MAXNAMEL+1] = "\000"; /* Filter compensation */
+ FILE *fp = NULL; /* Logfile */
+ icompaths *icmps = NULL;
+ int comport = COMPORT; /* COM port used */
+ icompath *ipath = NULL;
+ int dtype = 0; /* Display type selection charater */
+ inst_mode cap = inst_mode_none; /* Instrument mode capabilities */
+ inst2_capability cap2 = inst2_none; /* Instrument capabilities 2 */
+ inst3_capability cap3 = inst3_none; /* Instrument capabilities 3 */
+ double lx, ly; /* Read location on xy table */
+ baud_rate br = baud_38400; /* Target baud rate */
+ flow_control fc = fc_nc; /* Default flow control */
+ inst *it; /* Instrument object */
+ inst_code rv;
+ int uswitch = 0; /* Instrument switch is enabled */
+ int spec = 0; /* Need spectral data for observer/illuminant flag */
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */
+ icxIllumeType illum = icxIT_D50; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxObserverType obType = icxOT_default;
+ xspect sp; /* Last spectrum read */
+ xspect rsp; /* Reference spectrum */
+ xsp2cie *sp2cie = NULL; /* default conversion */
+ xsp2cie *sp2cief[26]; /* FWA corrected conversions */
+ double wXYZ[3] = { -10.0, 0, 0 };/* White XYZ for display white relative */
+ double Lab[3] = { -10.0, 0, 0}; /* Last Lab */
+ double rXYZ[3] = { 0.0, -10.0, 0}; /* Reference XYZ */
+ double rLab[3] = { -10.0, 0, 0}; /* Reference Lab */
+ double Yxy[3] = { 0.0, 0, 0}; /* Yxy value */
+ double LCh[3] = { 0.0, 0, 0}; /* LCh value */
+ double refstats = 0; /* Print running avg & stddev against ref */
+ double rstat_n; /* Stats N */
+ double rstat_XYZ[3]; /* Stats sum of XYZ's */
+ double rstat_XYZsq[3]; /* Stats sum of XYZ's squared */
+ double rstat_Lab[3]; /* Stats sum of Lab's */
+ double rstat_Labsq[3]; /* Stats sum of Lab's squared */
+ int savdrd = 0; /* At least one saved reading is available */
+ int ix; /* Reading index number */
+ int loghead = 0; /* NZ if log file heading has been printed */
+
+ set_exe_path(argv[0]); /* Set global exe_path and error_program */
+ check_if_not_interactive();
+ setup_spyd2(); /* Load firware if available */
+
+ for (i = 0; i < 26; i++)
+ sp2cief[i] = NULL;
+
+ sp.spec_n = 0;
+ rsp.spec_n = 0;
+
+ /* Process the arguments */
+ mfa = 0; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == 'D') {
+ debug = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ debug = atoi(na);
+ fa = nfa;
+ }
+ g_log->debug = debug;
+ } else if (argv[fa][1] == '?') {
+ usage("Usage requested");
+
+ } else if (argv[fa][1] == 'v') {
+ verb = 1;
+ g_log->verb = verb;
+
+ } else if (argv[fa][1] == 's') {
+ pspec = 1;
+
+#ifndef SALONEINSTLIB
+ } else if (argv[fa][1] == 'S') {
+ pspec = 2;
+#endif /* !SALONEINSTLIB */
+
+ /* COM port */
+ } else if (argv[fa][1] == 'c') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -c");
+ comport = atoi(na);
+ if (comport < 1 || comport > 40) usage("-c parameter %d out of range",comport);
+
+ /* Display type */
+ } else if (argv[fa][1] == 'y') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -y");
+ dtype = na[0];
+
+#ifndef SALONEINSTLIB
+ /* Simulated instrument illumination (FWA) */
+ } else if (argv[fa][1] == 'I') {
+
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -I");
+ if (strcmp(na, "A") == 0
+ || strcmp(na, "M0") == 0) {
+ spec = 1;
+ tillum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ tillum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0
+ || strcmp(na, "M1") == 0) {
+ spec = 1;
+ tillum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0
+ || strcmp(na, "M2") == 0) {
+ spec = 1;
+ tillum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ tillum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ tillum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ tillum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ tillum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ tillum = icxIT_custom;
+ if (read_xspect(&cust_tillum, na) != 0)
+ usage("Failed to read custom target illuminant spectrum in file '%s'",na);
+ }
+#endif /* SALONEINSTLIB */
+
+ /* Spectral Illuminant type for XYZ computation */
+ } else if (argv[fa][1] == 'i') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -i");
+ if (strcmp(na, "A") == 0) {
+ spec = 1;
+ illum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ illum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0) {
+ spec = 1;
+ illum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0) {
+ spec = 1;
+ illum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ illum = icxIT_D65;
+#ifndef SALONEINSTLIB
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ illum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ illum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ illum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ illum = icxIT_custom;
+ if (read_xspect(&cust_illum, na) != 0)
+ usage("Unable to read custom illuminant file '%s'",na);
+ }
+#else /* SALONEINSTLIB */
+ } else
+ usage("Unrecognised illuminant '%s'",na);
+#endif /* SALONEINSTLIB */
+
+ /* Spectral Observer type */
+ } else if (argv[fa][1] == 'Q') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -Q");
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ obType = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ obType = icxOT_CIE_1964_10;
+#ifndef SALONEINSTLIB
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ obType = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ obType = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ obType = icxOT_Shaw_Fairchild_2;
+#endif /* !SALONEINSTLIB */
+ } else
+ usage("Spectral observer type '%s' not recognised",na);
+
+ /* Request transmission measurement */
+ } else if (argv[fa][1] == 't') {
+ emiss = 0;
+ trans = 1;
+ tele = 0;
+ ambient = 0;
+
+ /* Request emissive measurement */
+ } else if (argv[fa][1] == 'e' || argv[fa][1] == 'd') {
+
+ if (argv[fa][1] == 'd')
+ warning("spotread -d flag is deprecated");
+
+ emiss = 1;
+ trans = 0;
+ tele = 0;
+ ambient = 0;
+
+ if (argv[fa][2] != '\000') {
+ if (argv[fa][2] == 'b' || argv[fa][2] == 'B')
+ emiss = 2;
+ else if (argv[fa][2] == 'w' || argv[fa][2] == 'W')
+ emiss = 3;
+ else
+ usage("-d modifier '%c' not recognised",argv[fa][2]);
+ }
+
+ /* Request telephoto measurement */
+ } else if (argv[fa][1] == 'p') {
+
+ emiss = 1;
+ trans = 0;
+ tele = 1;
+ ambient = 0;
+
+ if (argv[fa][2] != '\000') {
+ fa = nfa;
+ if (argv[fa][2] == 'b' || argv[fa][2] == 'B')
+ emiss = 2;
+ else if (argv[fa][2] == 'w' || argv[fa][2] == 'W')
+ emiss = 3;
+ else
+ usage("-p modifier '%c' not recognised",argv[fa][2]);
+ }
+
+ /* Request ambient measurement */
+ } else if (argv[fa][1] == 'a') {
+ emiss = 1;
+ trans = 0;
+ tele = 0;
+ ambient = 1;
+
+ /* Request ambient flash measurement */
+ } else if (argv[fa][1] == 'f') {
+ emiss = 1;
+ trans = 0;
+ tele = 0;
+ ambient = 2;
+
+ /* Filter configuration */
+ } else if (argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -F");
+ if (na[0] == 'n' || na[0] == 'N')
+ fe = inst_opt_filter_none;
+ else if (na[0] == 'p' || na[0] == 'P')
+ fe = inst_opt_filter_pol;
+ else if (na[0] == '6')
+ fe = inst_opt_filter_D65;
+ else if (na[0] == 'u' || na[0] == 'U')
+ fe = inst_opt_filter_UVCut;
+ else
+ usage("-F type '%c' not recognised",na[0]);
+
+ /* Extra filter compensation file */
+ } else if (argv[fa][1] == 'E') {
+ fa = nfa;
+ if (na == NULL) usage("Paramater expected following -E");
+ strncpy(filtername,na,MAXNAMEL-1); filtername[MAXNAMEL-1] = '\000';
+
+ /* Show Yxy */
+ } else if (argv[fa][1] == 'x') {
+ doYxy = 1;
+ doLCh = 0;
+
+ /* Show LCh */
+ } else if (argv[fa][1] == 'h') {
+ doYxy = 0;
+ doLCh = 1;
+
+ /* Compute running average and standard deviation from ref. */
+ /* Also turns off clamping */
+ } else if (argv[fa][1] == 'V') {
+ refstats = 1;
+#ifndef SALONEINSTLIB
+
+ /* Show CCT etc. */
+ } else if (argv[fa][1] == 'T') {
+ doCCT = 1;
+#endif /* !SALONEINSTLIB */
+
+ /* Manual calibration */
+ } else if (argv[fa][1] == 'K') {
+
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ docalib = atoi(na);
+ fa = nfa;
+ } else
+ usage("-K parameter '%c' not recognised",na[0]);
+
+ /* No auto calibration */
+ } else if (argv[fa][1] == 'N') {
+ nocal = 1;
+
+ /* High res mode */
+ } else if (argv[fa][1] == 'H') {
+ highres = 1;
+
+ /* Colorimeter Correction Matrix or */
+ /* Colorimeter Calibration Spectral Samples */
+ } else if (argv[fa][1] == 'X') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -K");
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+
+ /* Serial port flow control */
+ } else if (argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage("Parameter expected after -W");
+ if (na[0] == 'n' || na[0] == 'N')
+ fc = fc_none;
+ else if (na[0] == 'h' || na[0] == 'H')
+ fc = fc_Hardware;
+ else if (na[0] == 'x' || na[0] == 'X')
+ fc = fc_XonXOff;
+ else
+ usage("-W parameter '%c' not recognised",na[0]);
+
+ /* Extra flags */
+ } else if (argv[fa][1] == 'Y') {
+ if (na == NULL)
+ usage("Parameter expected after -Y");
+
+ if (na[0] == 'A') {
+ nadaptive = 1;
+ } else if (na[0] == 'r') {
+ refrmode = 1;
+ } else if (na[0] == 'n') {
+ refrmode = 0;
+ /* ~~~ i1pro2 test code ~~~ */
+ } else if (na[0] == 'U') {
+ uvmode = 1;
+ } else {
+ usage("-Y parameter '%c' not recognised",na[0]);
+ }
+
+ } else
+ usage("Flag -%c not recognised",argv[fa][1]);
+ }
+ else
+ break;
+ }
+
+ /* Get the optional file name argument */
+ if (fa < argc) {
+ strncpy(outname,argv[fa++],MAXNAMEL-1); outname[MAXNAMEL-1] = '\000';
+ if ((fp = fopen(outname, "w")) == NULL)
+ error("Unable to open logfile '%s' for writing\n",outname);
+ }
+
+
+ /* See if there is an environment variable ccxx */
+ if (ccxxname[0] == '\000') {
+ char *na;
+ if ((na = getenv("ARGYLL_COLMTER_CAL_SPEC_SET")) != NULL) {
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+
+ } else if ((na = getenv("ARGYLL_COLMTER_COR_MATRIX")) != NULL) {
+ strncpy(ccxxname,na,MAXNAMEL-1); ccxxname[MAXNAMEL-1] = '\000';
+ }
+ }
+
+ /* - - - - - - - - - - - - - - - - - - - */
+ if ((icmps = new_icompaths(g_log)) == NULL)
+ error("Finding instrument paths failed");
+ if ((ipath = icmps->get_path(icmps, comport)) == NULL)
+ error("No instrument at port %d",comport);
+
+
+ /* Setup the instrument ready to do reads */
+ if ((it = new_inst(ipath, 0, g_log, DUIH_FUNC_AND_CONTEXT)) == NULL) {
+ usage("Unknown, inappropriate or no instrument detected");
+ }
+
+#ifdef TEST_EVENT_CALLBACK
+ it->set_event_callback(it, test_event_callback, (void *)it);
+#endif
+
+ if (verb)
+ printf("Connecting to the instrument ..\n");
+
+#ifdef DEBUG
+ printf("About to init the comms\n");
+#endif
+
+ /* Establish communications */
+ if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
+ printf("Failed to initialise communications with instrument\n"
+ "or wrong instrument or bad configuration!\n"
+ "('%s' + '%s')\n", it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+#ifdef DEBUG
+ printf("Established comms\n");
+#endif
+
+#ifdef DEBUG
+ printf("About to init the instrument\n");
+#endif
+
+ /* set filter configuration before initialising/calibrating */
+ if (fe != inst_opt_filter_unknown) {
+ if ((rv = it->get_set_opt(it, inst_opt_set_filter, fe)) != inst_ok) {
+ printf("Setting filter configuration not supported by instrument\n");
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* Initialise the instrument */
+ if ((rv = it->init_inst(it)) != inst_ok) {
+ printf("Instrument initialisation failed with '%s' (%s)!\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ /* Configure the instrument mode */
+ {
+ int ccssset = 0;
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ /* Don't fail if the instrument has only one mode, and */
+ /* it's not been selected */
+
+ if (trans == 0 && emiss == 0 && !IMODETST(cap, inst_mode_reflection)) {
+ /* This will fail. Switch to a mode the instrument has */
+ if (IMODETST(cap, inst_mode_emission)) {
+ if (verb)
+ printf("Defaulting to emission measurement\n");
+ emiss = 1;
+
+ } else if (IMODETST(cap, inst_mode_transmission)) {
+ if (verb)
+ printf("Defaulting to transmission measurement\n");
+ trans = 1;
+ }
+ }
+
+ if (trans) {
+ if (!IMODETST(cap, inst_mode_trans_spot)
+ || it->check_mode(it, inst_mode_trans_spot) != inst_ok) {
+ printf("Need transmission spot capability,\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+
+ } else if (ambient == 1) {
+ if (!IMODETST(cap, inst_mode_emis_ambient)
+ || it->check_mode(it, inst_mode_emis_ambient) != inst_ok) {
+ printf("Requested ambient light capability,\n");
+ printf("and instrument doesn't support it.\n");
+ if (!IMODETST(cap, inst_mode_emis_spot)) {
+ it->del(it);
+ return -1;
+ } else {
+ printf("Will use emissive mode instead,\n");
+ printf("but note that light level readings may be wrong!\n");
+
+ }
+ } else {
+ if (verb) {
+ printf("Please make sure the instrument is fitted with\n");
+ printf("the appropriate ambient light measuring head\n");
+ }
+ }
+
+ } else if (ambient == 2) {
+ if (!IMODETST(cap, inst_mode_emis_ambient_flash)
+ || it->check_mode(it, inst_mode_emis_ambient_flash) != inst_ok) {
+ printf("Requested ambient flash capability,\n");
+ printf("and instrument doesn't support it.\n");
+ it->del(it);
+ return -1;
+ } else {
+ if (verb) {
+ printf("Please make sure the instrument is fitted with\n");
+ printf("the appropriate ambient light measuring head, and that\n");
+ printf("you are ready to trigger the flash.\n");
+ }
+ }
+
+ } else if (emiss || tele) {
+
+ if (tele) {
+ if (!IMODETST(cap, inst_mode_emis_tele)
+ || it->check_mode(it, inst_mode_emis_tele) != inst_ok) {
+ printf("Need telephoto spot capability\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+ } else {
+ if (!IMODETST(cap, inst_mode_emis_spot)
+ || it->check_mode(it, inst_mode_emis_spot) != inst_ok) {
+ printf("Need emissive spot capability\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+ }
+
+ if (nadaptive && !IMODETST(cap, inst_mode_emis_nonadaptive)) {
+ if (verb) {
+ printf("Requested non-adaptive mode and instrument doesn't support it (ignored)\n");
+ nadaptive = 0;
+ }
+ }
+ if (refrmode >= 0 && !IMODETST(cap, inst_mode_emis_refresh_ovd)
+ && !IMODETST(cap, inst_mode_emis_norefresh_ovd)) {
+ if (verb) {
+ printf("Requested refresh mode override and instrument doesn't support it (ignored)\n");
+ refrmode = -1;
+ }
+ }
+
+ /* Set display type */
+ if (dtype != 0) {
+
+ if (cap2 & inst2_disptype) {
+ int ix;
+ if ((ix = inst_get_disptype_index(it, dtype, 0)) < 0) {
+ it->del(it);
+ usage("Failed to locate display type matching '%c'",dtype);
+ }
+
+ if ((rv = it->set_disptype(it, ix)) != inst_ok) {
+ printf("Setting display type ix %d not supported by instrument\n",ix);
+ it->del(it);
+ return -1;
+ }
+ } else
+ printf("Display type ignored - instrument doesn't support display type\n");
+ }
+
+ } else {
+ if (!IMODETST(cap, inst_mode_ref_spot)
+ || it->check_mode(it, inst_mode_ref_spot) != inst_ok) {
+ printf("Need reflection spot reading capability,\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* If we have non-standard observer we need spectral or CCSS */
+ if (obType != icxOT_default && !IMODETST(cap, inst_mode_spectral) && !(cap2 & inst2_ccss)) {
+ printf("Non standard observer needs spectral information or CCSS capability\n");
+ printf("and instrument doesn't support either.\n");
+ it->del(it);
+ return -1;
+ }
+
+ /* If we don't have CCSS then we need spectral for non-standard observer */
+ if (obType != icxOT_default && (cap2 & inst2_ccss) == 0) {
+ spec = 1;
+ }
+
+ if ((spec || pspec) && !IMODETST(cap, inst_mode_spectral)) {
+ printf("Need spectral information for custom illuminant or observer\n");
+ printf("and instrument doesn't support it\n");
+ it->del(it);
+ return -1;
+ }
+
+ /* Disable initial calibration of machine if selected */
+ if (nocal != 0) {
+ if ((rv = it->get_set_opt(it,inst_opt_noinitcalib, 0)) != inst_ok) {
+ printf("Setting no-initial calibrate failed with '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ printf("Disable initial-calibrate not supported\n");
+ }
+ }
+ if (highres) {
+ if (IMODETST(cap, inst_mode_highres)) {
+ inst_code ev;
+ if ((ev = it->get_set_opt(it, inst_opt_highres)) != inst_ok) {
+ printf("\nSetting high res mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+ highres = 1;
+ } else if (verb) {
+ printf("high resolution ignored - instrument doesn't support high res. mode\n");
+ }
+ }
+
+ /* Set it to the appropriate mode */
+
+ /* Should look at instrument type & user spec ??? */
+ if (trans)
+ smode = mode = inst_mode_trans_spot;
+ else if (ambient == 1 && IMODETST(cap, inst_mode_emis_ambient)
+ && it->check_mode(it, inst_mode_emis_ambient) == inst_ok)
+ smode = mode = inst_mode_emis_ambient;
+ else if (ambient == 2 && IMODETST(cap, inst_mode_emis_ambient_flash)
+ && it->check_mode(it, inst_mode_emis_ambient_flash) == inst_ok)
+ smode = mode = inst_mode_emis_ambient_flash;
+ else if (tele) // Hmm. What about tele flash ?
+ smode = mode = inst_mode_emis_tele;
+ else if (emiss || ambient)
+ smode = mode = inst_mode_emis_spot;
+ else {
+ smode = mode = inst_mode_ref_spot;
+ if (IMODETST(cap, inst_mode_s_ref_spot)
+ && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok)
+ smode = inst_mode_s_ref_spot;
+ }
+
+ /* Mode dependent extra modes */
+ if (emiss || tele) {
+ if (nadaptive) {
+ mode |= inst_mode_emis_nonadaptive;
+ smode |= inst_mode_emis_nonadaptive;
+ }
+ if (refrmode == 0) {
+ mode |= inst_mode_emis_norefresh_ovd;
+ smode |= inst_mode_emis_norefresh_ovd;
+ }
+ else if (refrmode == 1) {
+ mode |= inst_mode_emis_refresh_ovd;
+ smode |= inst_mode_emis_refresh_ovd;
+ }
+ }
+
+ /* Use spec if requested or if available in case of CRI or FWA */
+ if (spec || pspec || IMODETST(cap, inst_mode_spectral)) {
+ mode |= inst_mode_spectral;
+ smode |= inst_mode_spectral;
+ }
+
+ // ~~~ i1pro2 test code ~~~ */
+ if (uvmode) {
+ if (!IMODETST(cap, inst_mode_ref_uv)) {
+ printf("UV measurement mode requested, but instrument doesn't support this mode\n");
+ it->del(it);
+ return -1;
+ }
+ mode |= inst_mode_ref_uv;
+ smode |= inst_mode_ref_uv;
+ }
+
+ if ((rv = it->set_mode(it, mode)) != inst_ok) {
+ printf("\nSetting instrument mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ /* Apply Extra filter compensation */
+ if (filtername[0] != '\000') {
+ if ((rv = it->comp_filter(it, filtername)) != inst_ok) {
+ printf("\nSetting filter compensation failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* Colorimeter Correction Matrix */
+ if (ccxxname[0] != '\000') {
+ ccss *cs = NULL;
+ ccmx *cx = NULL;
+
+ if ((cx = new_ccmx()) == NULL) {
+ printf("\nnew_ccmx failed\n");
+ it->del(it);
+ return -1;
+ }
+ if (cx->read_ccmx(cx,ccxxname) == 0) {
+ if ((cap2 & inst2_ccmx) == 0) {
+ printf("\nInstrument doesn't have Colorimeter Correction Matrix capability\n");
+ it->del(it);
+ return -1;
+ }
+ if ((rv = it->col_cor_mat(it, cx->matrix)) != inst_ok) {
+ printf("\nSetting Colorimeter Correction Matrix failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ cx->del(cx);
+ it->del(it);
+ return -1;
+ }
+ cx->del(cx);
+
+ } else {
+ cx->del(cx);
+ cx = NULL;
+
+ /* CCMX failed, try CCSS */
+ if ((cs = new_ccss()) == NULL) {
+ printf("\nnew_ccss failed\n");
+ it->del(it);
+ return -1;
+ }
+ if (cs->read_ccss(cs,ccxxname)) {
+ printf("\nReading CCMX/CCSS File '%s' failed with error %d:'%s'\n",
+ ccxxname, cs->errc, cs->err);
+ cs->del(cs);
+ it->del(it);
+ return -1;
+ }
+ if ((cap2 & inst2_ccss) == 0) {
+ printf("\nInstrument doesn't have Colorimeter Calibration Spectral Sample capability\n");
+ cs->del(cs);
+ it->del(it);
+ return -1;
+ }
+ if ((rv = it->get_set_opt(it, inst_opt_set_ccss_obs, obType, NULL)) != inst_ok) {
+ printf("\nSetting CCS Observer failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ cs->del(cs);
+ it->del(it);
+ return -1;
+ }
+ if ((rv = it->col_cal_spec_set(it, cs->samples, cs->no_samp)) != inst_ok) {
+ printf("\nSetting Colorimeter Calibration Spectral Samples failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ cs->del(cs);
+ it->del(it);
+ return -1;
+ }
+ ccssset = 1;
+ cs->del(cs);
+ }
+ }
+
+ /* If non-standard observer wasn't set by a CCSS file above */
+ if (obType != icxOT_default && (cap2 & inst2_ccss) && ccssset == 0) {
+ if ((rv = it->get_set_opt(it, inst_opt_set_ccss_obs, obType, 0)) != inst_ok) {
+ printf("\nSetting CCSS Observer failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ }
+
+ /* If it batter powered, show the status of the battery */
+ if ((cap2 & inst2_has_battery)) {
+ double batstat = 0.0;
+ if ((rv = it->get_set_opt(it, inst_stat_battery, &batstat)) != inst_ok) {
+ printf("\nGetting instrument battery status failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ printf("The battery charged level is %.0f%%\n",batstat * 100.0);
+ }
+
+ /* If it's an instrument that need positioning let user trigger via uicallback */
+ /* in spotread, else enable switch or user via uicallback trigger if possible. */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ trigmode = inst_opt_trig_prog;
+
+ } else if (cap2 & inst2_user_switch_trig) {
+ trigmode = inst_opt_trig_user_switch;
+ uswitch = 1;
+
+ /* Or go for keyboard trigger */
+ } else if (cap2 & inst2_user_trig) {
+ trigmode = inst_opt_trig_user;
+
+ /* Or something is wrong with instrument capabilities */
+ } else {
+ printf("\nNo reasonable trigger mode avilable for this instrument\n");
+ it->del(it);
+ return -1;
+ }
+ if ((rv = it->get_set_opt(it, trigmode)) != inst_ok) {
+ printf("\nSetting trigger mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+
+ /* Setup the keyboard trigger to return our commands */
+ inst_set_uih(0x0, 0xff, DUIH_TRIG);
+ inst_set_uih('r', 'r', DUIH_CMND);
+ inst_set_uih('R', 'R', DUIH_CMND);
+ inst_set_uih('h', 'h', DUIH_CMND);
+ inst_set_uih('H', 'H', DUIH_CMND);
+ inst_set_uih('k', 'k', DUIH_CMND);
+ inst_set_uih('K', 'K', DUIH_CMND);
+ inst_set_uih('s', 's', DUIH_CMND);
+ inst_set_uih('S', 'S', DUIH_CMND);
+ inst_set_uih('f', 'f', DUIH_CMND);
+ inst_set_uih('F', 'F', DUIH_CMND);
+ inst_set_uih('q', 'q', DUIH_ABORT);
+ inst_set_uih('Q', 'Q', DUIH_ABORT);
+ inst_set_uih(0x03, 0x03, DUIH_ABORT); /* ^c */
+ inst_set_uih(0x1b, 0x1b, DUIH_ABORT); /* Esc */
+ }
+
+#ifdef DEBUG
+ printf("About to enter read loop\n");
+#endif
+
+ if (verb)
+ printf("Init instrument success !\n");
+
+ if (spec) {
+ /* Any non-illuminated mode has no illuminant */
+ if (emiss || tele || ambient)
+ illum = icxIT_none;
+
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie(illum, &cust_illum, obType, NULL, icSigXYZData,
+ refstats ? icxNoClamp : icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+
+ /* If we are setting a specific simulated instrument illuminant */
+ if (tillum != icxIT_none) {
+ tillump = &cust_tillum;
+ if (tillum != icxIT_custom) {
+ if (standardIlluminant(tillump, tillum, 0.0)) {
+ error("simulated inst. illum. not recognised");
+ }
+ }
+ }
+ }
+
+ /* Hold table */
+ if (cap2 & inst2_xy_holdrel) {
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_sheet_hold(it)) == inst_ok)
+ break;
+
+ if (ierror(it, rv)) {
+ it->xy_clear(it);
+ it->del(it);
+ return -1;
+ }
+ }
+ }
+
+ /* Read spots until the user quits */
+ for (ix = 1;; ix++) {
+ ipatch val;
+ double XYZ[3]; /* XYZ scaled 0..100 or absolute */
+ double tXYZ[3];
+#ifndef SALONEINSTLIB
+ double cct, vct, vdt;
+ double cct_de, vct_de, vdt_de;
+#endif /* !SALONEINSTLIB */
+ int ch = '0'; /* Character */
+ int sufwa = 0; /* Setup for FWA compensation */
+ int dofwa = 0; /* Do FWA compensation */
+ int fidx = -1; /* FWA compensated index, default = none */
+
+ if (savdrd != -1 && IMODETST(cap, inst_mode_s_ref_spot)
+ && it->check_mode(it, inst_mode_s_ref_spot) == inst_ok) {
+ inst_stat_savdrd sv;
+
+ savdrd = 0;
+ if ((rv = it->get_set_opt(it, inst_stat_saved_readings, &sv)) != inst_ok) {
+ printf("\nGetting saved reading status failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ it->del(it);
+ return -1;
+ }
+ if (sv & inst_stat_savdrd_spot)
+ savdrd = 1;
+ }
+
+ /* Read a stored value */
+ if (savdrd == 1) {
+ inst_code ev;
+
+ /* Set to saved spot mode */
+ if ((ev = it->set_mode(it, smode)) != inst_ok) {
+ printf("\nSetting instrument mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ /* Set N and n to be a command */
+ inst_set_uih('N', 'N', DUIH_CMND);
+ inst_set_uih('n', 'n', DUIH_CMND);
+
+ /* Set to keyboard only trigger */
+ if ((ev = it->get_set_opt(it, inst_opt_trig_user)) != inst_ok) {
+ printf("\nSetting trigger mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+
+ printf("\nThere are saved spot readings in the instrument.\n");
+#ifndef SALONEINSTLIB
+ printf("Hit [A-Z] to use reading for white and setup FWA compensation (keyed to letter)\n");
+ printf("[a-z] to use reading for FWA compensated value from keyed reference\n");
+ printf("'r' to set reference, 's' to save spectrum,\n");
+#else /* SALONEINSTLIB */
+ printf("Hit 'r' to set reference\n");
+#endif /* SALONEINSTLIB */
+ printf("Hit ESC or Q to exit, N to not read saved reading,\n");
+ printf("any other key to use reading: ");
+ fflush(stdout);
+
+ /* Read the sample or get a command */
+ rv = it->read_sample(it, "SPOT", &val, refstats ? instNoClamp : instClamp);
+
+ ch = inst_get_uih_char();
+
+ /* Restore the trigger mode */
+ if ((ev = it->get_set_opt(it, trigmode)) != inst_ok) {
+ printf("\nSetting trigger mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+
+ /* Set N and n to be a trigger */
+ inst_set_uih('N', 'N', DUIH_TRIG);
+ inst_set_uih('n', 'n', DUIH_TRIG);
+
+ /* Set back to read spot mode */
+ if ((ev = it->set_mode(it, mode)) != inst_ok) {
+ printf("\nSetting instrument mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+ it->capabilities(it, &cap, &cap2, &cap3);
+
+ /* If user said no to reading stored values */
+ if ((rv & inst_mask) == inst_user_abort
+ && (ch & DUIH_CMND) && ((ch & 0xff) == 'N' || (ch & 0xff) == 'n')) {
+ printf("\n");
+ savdrd = -1;
+ continue;
+ }
+
+ /* Do a normal read */
+ } else {
+
+ /* Do any needed calibration before the user places the instrument on a desired spot */
+ if (it->needs_calibration(it) & inst_calt_n_dfrble_mask) {
+ inst_code ev;
+
+ printf("\nSpot read needs a calibration before continuing\n");
+
+ /* save current location */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ for (;;) { /* retry loop */
+ if ((ev = it->xy_get_location(it, &lx, &ly)) == inst_ok)
+ break;
+ if (ierror(it, ev) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (ev != inst_ok) {
+ printf("\nSpot read got abort or error from xy_get_location\n");
+ break; /* Abort */
+ }
+ }
+
+ ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ printf("\nSpot read got abort or error from calibration\n");
+ break;
+ }
+
+ /* restore location */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ for (;;) { /* retry loop */
+ if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
+ break;
+ if (ierror(it, ev) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (ev != inst_ok) {
+ printf("\nSpot read got abort or error from xy_get_location\n");
+ break; /* Abort */
+ }
+ }
+ }
+
+ if (ambient == 2) { /* Flash ambient */
+ printf("\nConfigure for ambient, press and hold button, trigger flash then release button,\n");
+#ifndef SALONEINSTLIB
+ printf("or hit 'r' to set reference, 's' to save spectrum,\n");
+#else /* SALONEINSTLIB */
+ printf("or hit 'r' to set reference\n");
+#endif /* SALONEINSTLIB */
+ printf("'h' to toggle high res., 'k' to do a calibration\n");
+
+ } else {
+ /* If this is an xy instrument: */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+
+ /* Allow the user to position the instrument */
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_locate_start(it)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ printf("\nSpot read got abort or error from xy_locate_start\n");
+ break; /* Abort */
+ }
+
+ printf("\nUsing the XY table controls, locate the point to measure with the sight,\n");
+
+ /* Purely manual instrument */
+ } else {
+
+ /* If this is display white brightness relative, read the white */
+ if ((emiss > 1 || tele > 1) && wXYZ[0] < 0.0)
+ printf("\nPlace instrument on white reference spot,\n");
+ else {
+ printf("\nPlace instrument on spot to be measured,\n");
+ }
+ }
+#ifndef SALONEINSTLIB
+ printf("and hit [A-Z] to read white and setup FWA compensation (keyed to letter)\n");
+ printf("[a-z] to read and make FWA compensated reading from keyed reference\n");
+ printf("'r' to set reference, 's' to save spectrum,\n");
+ printf("'f' to report cal. refresh rate, 'F' to measure refresh rate\n");
+#else /* SALONEINSTLIB */
+ printf("Hit 'r' to set reference\n");
+#endif /* SALONEINSTLIB */
+ printf("'h' to toggle high res., 'k' to do a calibration\n");
+ }
+ if (uswitch)
+ printf("Hit ESC or Q to exit, instrument switch or any other key to take a reading: ");
+ else
+ printf("Hit ESC or Q to exit, any other key to take a reading: ");
+ fflush(stdout);
+
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ /* Wait for the user to hit a key */
+ for (;;) {
+ if ((rv = inst_get_uicallback()(inst_get_uicontext(), inst_armed)) != inst_ok)
+ break;
+ }
+
+ if (rv == inst_user_abort) {
+ break; /* Abort */
+
+ } else if (rv == inst_user_trig) {
+ inst_code ev;
+
+ /* Take the location set on the sight, and move the instrument */
+ /* to take the measurement there. */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_get_location(it, &lx, &ly)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ printf("\nSpot read got abort or error from xy_get_location\n");
+ break; /* Abort */
+ }
+
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_locate_end(it)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ printf("\nSpot read got abort or error from xy_locate_end\n");
+ break; /* Abort */
+ }
+
+ for (;;) { /* retry loop */
+ if ((rv = it->xy_position(it, 1, lx, ly)) == inst_ok)
+ break;
+ if (ierror(it, rv) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (rv != inst_ok) {
+ printf("\nSpot read got abort or error from xy_position\n");
+ break; /* Abort */
+ }
+ }
+ rv = it->read_sample(it, "SPOT", &val, refstats ? instNoClamp : instClamp);
+
+ /* Restore the location the instrument to have the location */
+ /* sight over the selected patch. */
+ for (;;) { /* retry loop */
+ if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
+ break;
+ if (ierror(it, ev) == 0) /* Ignore */
+ continue;
+ break; /* Abort */
+ }
+ if (ev != inst_ok) {
+ printf("\nSpot read got abort or error from xy_position\n");
+ break; /* Abort */
+ }
+ }
+ /* else what ? */
+ } else {
+ rv = it->read_sample(it, "SPOT", &val, refstats ? instNoClamp : instClamp);
+ }
+ }
+
+#ifdef DEBUG
+ printf("read_sample returned '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+#endif /* DEBUG */
+
+ /* Get any command or trigger character */
+ if ((rv & inst_mask) == inst_user_trig
+ || (rv & inst_mask) == inst_user_abort)
+ ch = inst_get_uih_char();
+ else
+ ch = '0';
+
+ /* Do return after command */
+ if ((rv & inst_mask) == inst_user_abort && (ch & DUIH_CMND))
+ printf("\n");
+
+ /* Deal with a user abort */
+ if ((rv & inst_mask) == inst_user_abort && (ch & DUIH_ABORT)) {
+ printf("\n\nSpot read stopped at user request!\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ ch = next_con_char();
+ if (ch == 0x1b || ch == 0x03 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ break;
+ }
+ printf("\n");
+ continue;
+
+ /* Deal with a needs calibration */
+ } else if ((rv & inst_mask) == inst_needs_cal) {
+ inst_code ev;
+ printf("\n\nSpot read failed because instruments needs calibration.\n");
+ ev = inst_handle_calibrate(it, inst_calt_needed, inst_calc_none, NULL, NULL);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ printf("\nSpot read got abort or error from calibrate\n");
+ break;
+ }
+ continue;
+
+ /* Deal with a bad sensor position */
+ } else if ((rv & inst_mask) == inst_wrong_config) {
+ printf("\n\nSpot read failed due to the sensor being in the wrong position\n(%s)\n",it->interp_error(it, rv));
+ continue;
+
+ /* Deal with a misread */
+ } else if ((rv & inst_mask) == inst_misread) {
+ empty_con_chars();
+ printf("\n\nSpot read failed due to misread (%s)\n",it->interp_error(it, rv));
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ ch = next_con_char();
+ printf("\n");
+ if (ch == 0x1b || ch == 0x03 || ch == 'q' || ch == 'Q') {
+ break;
+ }
+ continue;
+
+ /* Deal with a communications error */
+ } else if ((rv & inst_mask) == inst_coms_fail) {
+ empty_con_chars();
+ printf("\n\nSpot read failed due to communication problem.\n");
+ printf("Hit Esc or Q to give up, any other key to retry:"); fflush(stdout);
+ ch = next_con_char();
+ if (ch == 0x1b || ch == 0x03 || ch == 'q' || ch == 'Q') {
+ printf("\n");
+ break;
+ }
+ printf("\n");
+ if (it->icom->port_type(it->icom) == icomt_serial) {
+ /* Allow retrying at a lower baud rate */
+ int tt = it->last_scomerr(it);
+ if (tt & (ICOM_BRK | ICOM_FER | ICOM_PER | ICOM_OER)) {
+ if (br == baud_57600) br = baud_38400;
+ else if (br == baud_38400) br = baud_9600;
+ else if (br == baud_9600) br = baud_4800;
+ else if (br == baud_9600) br = baud_4800;
+ else if (br == baud_2400) br = baud_1200;
+ else br = baud_1200;
+ }
+ if ((rv = it->init_coms(it, br, fc, 15.0)) != inst_ok) {
+ printf("init_coms returned '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ break;
+ }
+ }
+ continue;
+
+ /* Some fatal error */
+ } else if ((rv & inst_mask) != inst_ok
+ && (rv & inst_mask) != inst_user_trig
+ && (rv & inst_mask) != inst_user_abort) {
+ printf("\n\nGot fatal error '%s' (%s)\n",
+ it->inst_interp_error(it, rv), it->interp_error(it, rv));
+ break;
+ }
+
+ /* Process command or reading */
+ ch &= 0xff;
+ if (ch == 0x1b || ch == 0x03 || ch == 'q' || ch == 'Q') { /* Or ^C */
+ break;
+ }
+ if (ch == 'H' || ch == 'h') { /* Toggle high res mode */
+ if (IMODETST(cap, inst_mode_highres)) {
+ inst_code ev;
+ if (highres) {
+ if ((ev = it->get_set_opt(it, inst_opt_stdres)) != inst_ok) {
+ printf("\nSetting std res mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+ highres = 0;
+ if (pspec)
+ loghead = 0;
+ printf("\n Instrument set to standard resolution spectrum mode\n");
+ } else {
+ if ((ev = it->get_set_opt(it, inst_opt_highres)) != inst_ok) {
+ printf("\nSetting high res mode failed with error :'%s' (%s)\n",
+ it->inst_interp_error(it, ev), it->interp_error(it, ev));
+ it->del(it);
+ return -1;
+ }
+ highres = 1;
+ if (pspec)
+ loghead = 0;
+ printf("\n Instrument set to high resolution spectrum mode\n");
+ }
+ } else {
+ printf("\n 'H' Command ignored - instrument doesn't support high res. mode\n");
+ }
+ --ix;
+ continue;
+ }
+ if (ch == 'R' || ch == 'r') { /* Make last reading the reference */
+ if (Lab[0] >= -9.0) {
+ rXYZ[0] = XYZ[0];
+ rXYZ[1] = XYZ[1];
+ rXYZ[2] = XYZ[2];
+ rLab[0] = Lab[0];
+ rLab[1] = Lab[1];
+ rLab[2] = Lab[2];
+ if (pspec) {
+ rsp = sp; /* Save spectral reference too */
+ }
+ if (refstats) {
+ rstat_n = 1;
+ for (j = 0; j < 3; j++) {
+ rstat_XYZ[j] = XYZ[j];
+ rstat_XYZsq[j] = XYZ[j] * XYZ[j];
+ rstat_Lab[j] = Lab[j];
+ rstat_Labsq[j] = Lab[j] * Lab[j];
+ }
+ }
+ printf("\n Reference is now XYZ: %f %f %f Lab: %f %f %f\n", rXYZ[0], rXYZ[1], rXYZ[2],rLab[0], rLab[1], rLab[2]);
+ } else {
+ printf("\n No previous reading to use as reference\n");
+ }
+ --ix;
+ continue;
+ }
+#ifndef SALONEINSTLIB
+ if (ch == 'S' || ch == 's') { /* Save last spectral into file */
+ if (sp.spec_n > 0) {
+ char buf[500];
+ printf("\nEnter filename (ie. xxxx.sp): "); fflush(stdout);
+ if (getns(buf, 500) != NULL && strlen(buf) > 0) {
+ if(write_xspect(buf, &sp))
+ printf("\nWriting file '%s' failed\n",buf);
+ else
+ printf("\nWriting file '%s' succeeded\n",buf);
+ } else {
+ printf("\nNo filename, nothing saved\n");
+ }
+ } else {
+ printf("\nNo previous spectral reading to save to file (Use -s flag ?)\n");
+ }
+ --ix;
+ continue;
+ }
+#endif /* !SALONEINSTLIB */
+ if (ch == 'K' || ch == 'k') { /* Do a calibration */
+ inst_code ev;
+
+ printf("\nDoing a calibration\n");
+
+ /* save current location */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ for (;;) { /* retry loop */
+ if ((ev = it->xy_get_location(it, &lx, &ly)) == inst_ok)
+ break;
+ if (ierror(it, ev) == 0) { /* Ignore */
+ --ix;
+ continue;
+ }
+ break; /* Abort */
+ }
+ if (ev != inst_ok) {
+ printf("\nSpot read got abort or error from xy_get_location\n");
+ break; /* Abort */
+ }
+ }
+
+ ev = inst_handle_calibrate(it, inst_calt_available, inst_calc_none, NULL, NULL);
+ if (ev != inst_ok) { /* Abort or fatal error */
+ printf("\nSpot read got abort or error from calibrate\n");
+ break;
+ }
+
+ /* restore location */
+ if ((cap2 & inst2_xy_locate) && (cap2 & inst2_xy_position)) {
+ for (;;) { /* retry loop */
+ if ((ev = it->xy_position(it, 0, lx, ly)) == inst_ok)
+ break;
+ if (ierror(it, ev) == 0) { /* Ignore */
+ --ix;
+ continue;
+ }
+ break; /* Abort */
+ }
+ if (ev != inst_ok) {
+ printf("\nSpot read got abort or error from xy_position");
+ break; /* Abort */
+ }
+ }
+ --ix;
+ continue;
+ }
+
+ /* Measure refresh rate */
+ if (ch == 'F') {
+ double refr;
+ inst_code ev;
+
+ if (!(cap2 & inst2_emis_refr_meas)) {
+ printf("\nInstrument isn't capable of refresh rate measurement in current mode\n");
+ --ix;
+ continue;
+ }
+
+ ev = it->read_refrate(it, &refr);
+ if (ev == inst_unsupported) {
+ printf("\nInstrument isn't capable of refresh rate measurement in current mode\n");
+ --ix;
+ continue;
+ }
+
+ if (ev == inst_misread) {
+ printf("\nNo refresh detectable, or measurement failed\n");
+ --ix;
+ continue;
+
+ } else if (ev != inst_ok) {
+ if (ierror(it, ev) == 0) { /* Ignore */
+ --ix;
+ continue;
+ }
+ break; /* Abort */
+ } else {
+ printf("\nRefresh rate = %f Hz\n",refr);
+ }
+ --ix;
+ continue;
+ }
+
+ /* Report calibrated refresh rate */
+ if (ch == 'f') {
+ double refr;
+ inst_code ev;
+
+ if (!(cap2 & inst2_refresh_rate)) {
+ printf("\nInstrument isn't capable of refresh rate calibration\n");
+ --ix;
+ continue;
+ }
+
+ ev = it->get_refr_rate(it, &refr);
+ if (ev == inst_unsupported) {
+ printf("\nInstrument isn't capable of refresh rate calibration\n");
+ --ix;
+ continue;
+
+ } else if (ev == inst_needs_cal) {
+ int refrmode;
+
+ printf("\nRefresh rate hasn't been calibrated\n");
+
+ if ((ev = it->get_set_opt(it, inst_opt_get_dtinfo, &refrmode, NULL)) != inst_ok) {
+ printf("Can't get curretn refresh mode from instrument\n");
+ --ix;
+ continue;
+ }
+ if (!refrmode) {
+ printf("Instrument isn't set to a refresh display type\n");
+ --ix;
+ continue;
+ }
+
+ ev = inst_handle_calibrate(it, inst_calt_ref_freq, inst_calc_none, NULL, NULL);
+
+ if (ev != inst_ok) { /* Abort or fatal error */
+ printf("\nSpot read got abort or error from calibrate\n");
+ if (ierror(it, ev) == 0) { /* Ignore */
+ --ix;
+ continue;
+ }
+ break;
+ }
+ ev = it->get_refr_rate(it, &refr);
+ }
+
+ if (ev == inst_misread) {
+ printf("\nNo refresh, or wasn't able to measure one\n");
+ --ix;
+ continue;
+
+ } else if (ev != inst_ok) {
+ if (ierror(it, ev) == 0) { /* Ignore */
+ --ix;
+ continue;
+ }
+ break; /* Abort */
+ } else {
+ printf("\nRefresh rate = %f Hz\n",refr);
+ }
+ --ix;
+ continue;
+ }
+
+#ifndef SALONEINSTLIB
+ if (ch >= 'A' && ch <= 'Z') {
+ printf("\nMeasured media to setup FWA compensation slot '%c'\n",ch);
+ sufwa = 1;
+ fidx = ch - 'A';
+ }
+ if (ch >= 'a' && ch <= 'z') {
+ fidx = ch - 'a';
+ if (fidx < 0 || sp2cief[fidx] == NULL) {
+ printf("\nUnable to apply FWA compensation because it wasn't set up\n");
+ fidx = -1;
+ } else {
+ dofwa = 1;
+ }
+
+ }
+
+ /* Setup FWA compensation */
+ if (sufwa) {
+ double FWAc;
+ xspect insp; /* Instrument illuminant */
+
+ if (val.sp.spec_n <= 0) {
+ error("Instrument didn't return spectral data");
+ }
+
+ if (inst_illuminant(&insp, it->get_itype(it)) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+
+ /* Creat the base conversion object */
+ if (sp2cief[fidx] == NULL) {
+ if ((sp2cief[fidx] = new_xsp2cie(illum, &cust_illum, obType,
+ NULL, icSigXYZData, refstats ? icxNoClamp : icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+ }
+
+ if (sp2cief[fidx]->set_fwa(sp2cief[fidx], &insp, tillump, &val.sp))
+ error ("Set FWA on sp2cie failed");
+
+ sp2cief[fidx]->get_fwa_info(sp2cief[fidx], &FWAc);
+ printf("FWA content = %f\n",FWAc);
+ }
+#else /* !SALONEINSTLIB */
+ if (sufwa) {
+ error ("FWA compensation not supported in this version");
+ }
+#endif /* !SALONEINSTLIB */
+
+ /* Print and/or plot out spectrum, */
+ /* even if it's an FWA setup */
+ if (pspec) {
+ xspect tsp;
+
+ if (val.sp.spec_n <= 0)
+ error("Instrument didn't return spectral data");
+
+ tsp = val.sp; /* Temp. save spectral reading */
+
+ /* Compute FWA corrected spectrum */
+ if (dofwa != 0) {
+ sp2cief[fidx]->sconvert(sp2cief[fidx], &tsp, NULL, &tsp);
+ }
+
+ printf("Spectrum from %f to %f nm in %d steps\n",
+ tsp.spec_wl_short, tsp.spec_wl_long, tsp.spec_n);
+
+ for (j = 0; j < tsp.spec_n; j++)
+ printf("%s%8.3f",j > 0 ? ", " : "", tsp.spec[j]);
+ printf("\n");
+
+#ifndef SALONEINSTLIB
+ /* Plot the spectrum */
+ if (pspec == 2) {
+ double xx[XSPECT_MAX_BANDS];
+ double yy[XSPECT_MAX_BANDS];
+ double yr[XSPECT_MAX_BANDS];
+ double xmin, xmax, ymin, ymax;
+ xspect *ss; /* Spectrum range to use */
+ int nn;
+
+ if (rsp.spec_n > 0) {
+ if ((tsp.spec_wl_long - tsp.spec_wl_short) >
+ (rsp.spec_wl_long - rsp.spec_wl_short))
+ ss = &tsp;
+ else
+ ss = &rsp;
+ } else
+ ss = &tsp;
+
+ if (tsp.spec_n > rsp.spec_n)
+ nn = tsp.spec_n;
+ else
+ nn = rsp.spec_n;
+
+ if (nn > XSPECT_MAX_BANDS)
+ error("Got > %d spectral values (%d)",XSPECT_MAX_BANDS,nn);
+
+ for (j = 0; j < nn; j++) {
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(j);
+#endif
+ xx[j] = ss->spec_wl_short
+ + j * (ss->spec_wl_long - ss->spec_wl_short)/(nn-1);
+
+ yy[j] = value_xspect(&tsp, xx[j]);
+
+ if (rLab[0] >= -1.0) { /* If there is a reference */
+ yr[j] = value_xspect(&rsp, xx[j]);
+ }
+ }
+
+ xmax = ss->spec_wl_long;
+ xmin = ss->spec_wl_short;
+ if (emiss || uvmode) {
+ ymin = ymax = 0.0; /* let it scale */
+ } else {
+ ymin = 0.0;
+ ymax = 120.0;
+ }
+ do_plot_x(xx, yy, rLab[0] >= -1.0 ? yr : NULL, NULL, nn, 1,
+ xmin, xmax, ymin, ymax, 2.0);
+ }
+#endif /* !SALONEINSTLIB */
+ }
+
+ if (sufwa == 0) { /* Not setting up fwa, so show reading */
+
+ sp = val.sp; /* Save as last spectral reading */
+
+ /* Compute the XYZ & Lab */
+ if (dofwa == 0 && spec == 0) {
+ if (val.XYZ_v == 0)
+ error("Instrument didn't return XYZ value");
+
+ for (j = 0; j < 3; j++)
+ XYZ[j] = val.XYZ[j];
+
+ } else {
+ /* Compute XYZ given spectral */
+
+ if (sp.spec_n <= 0) {
+ error("Instrument didn't return spectral data");
+ }
+
+ if (dofwa == 0) {
+ /* Convert it to XYZ space using uncompensated */
+ sp2cie->convert(sp2cie, XYZ, &sp);
+ } else {
+ /* Convert using compensated conversion */
+ sp2cief[fidx]->sconvert(sp2cief[fidx], &sp, XYZ, &sp);
+ }
+ if (!(emiss || tele || ambient)) {
+ for (j = 0; j < 3; j++)
+ XYZ[j] *= 100.0; /* 0..100 scale */
+ }
+ }
+
+ /* XYZ is 0 .. 100 for reflective/transmissive, and absolute for emissibe here */
+ /* XYZ is 0 .. 1 for reflective/transmissive, and absolute for emissibe here */
+
+#ifndef SALONEINSTLIB
+ /* Compute color temperatures */
+ if (ambient || doCCT) {
+ icmXYZNumber wp;
+ double nxyz[3], axyz[3];
+ double lab[3], alab[3];
+
+ nxyz[0] = XYZ[0] / XYZ[1];
+ nxyz[2] = XYZ[2] / XYZ[1];
+ nxyz[1] = XYZ[1] / XYZ[1];
+
+ /* Compute CCT */
+ if ((cct = icx_XYZ2ill_ct(axyz, icxIT_Ptemp, obType, NULL, XYZ, NULL, 0)) < 0)
+ error ("Got bad cct\n");
+ axyz[0] /= axyz[1];
+ axyz[2] /= axyz[1];
+ axyz[1] /= axyz[1];
+ icmAry2XYZ(wp, axyz);
+ icmXYZ2Lab(&wp, lab, nxyz);
+ icmXYZ2Lab(&wp, alab, axyz);
+ cct_de = icmLabDE(lab, alab);
+
+ /* Compute VCT */
+ if ((vct = icx_XYZ2ill_ct(axyz, icxIT_Ptemp, obType, NULL, XYZ, NULL, 1)) < 0)
+ error ("Got bad vct\n");
+ axyz[0] /= axyz[1];
+ axyz[2] /= axyz[1];
+ axyz[1] /= axyz[1];
+ icmAry2XYZ(wp, axyz);
+ icmXYZ2Lab(&wp, lab, nxyz);
+ icmXYZ2Lab(&wp, alab, axyz);
+ vct_de = icmLabDE(lab, alab);
+
+ /* Compute VDT */
+ if ((vdt = icx_XYZ2ill_ct(axyz, icxIT_Dtemp, obType, NULL, XYZ, NULL, 1)) < 0)
+ error ("Got bad vct\n");
+ axyz[0] /= axyz[1];
+ axyz[2] /= axyz[1];
+ axyz[1] /= axyz[1];
+ icmAry2XYZ(wp, axyz);
+ icmXYZ2Lab(&wp, lab, nxyz);
+ icmXYZ2Lab(&wp, alab, axyz);
+ vdt_de = icmLabDE(lab, alab);
+ }
+
+ /* Compute D50 Lab from XYZ */
+ icmXYZ2Lab(&icmD50_100, Lab, XYZ);
+
+ /* Compute Yxy from XYZ */
+ icmXYZ2Yxy(Yxy, XYZ);
+
+ /* Compute LCh from Lab */
+ icmLab2LCh(LCh, Lab);
+
+#else /* SALONEINSTLIB */
+ /* Compute D50 Lab from XYZ */
+ XYZ2Lab(Lab, XYZ);
+
+ /* Compute Yxy from XYZ */
+ XYZ2Yxy(Yxy, XYZ);
+
+ /* Compute LCh from Lab */
+ Lab2LCh(LCh, Lab);
+#endif /* SALONEINSTLIB */
+
+ if (emiss > 1 || tele > 1) {
+ if (wXYZ[0] < 0.0) {
+ if (XYZ[1] < 10.0)
+ error ("White of XYZ %f %f %f doesn't seem reasonable",XYZ[0], XYZ[1], XYZ[2]);
+ printf("\n Making result XYZ: %f %f %f, D50 Lab: %f %f %f white reference.\n",
+ XYZ[0], XYZ[1], XYZ[2], Lab[0], Lab[1], Lab[2]);
+ wXYZ[0] = XYZ[0];
+ wXYZ[1] = XYZ[1];
+ wXYZ[2] = XYZ[2];
+ continue;
+ }
+ if (emiss == 2 || tele == 2) {
+ /* Normalize to white Y value and scale to 0..100 */
+ XYZ[0] = 100.0 * XYZ[0] / wXYZ[1];
+ XYZ[1] = 100.0 * XYZ[1] / wXYZ[1];
+ XYZ[2] = 100.0 * XYZ[2] / wXYZ[1];
+ }
+#ifndef SALONEINSTLIB
+ else {
+
+ /* Normalize to white and scale to 0..100 */
+ XYZ[0] = XYZ[0] * icmD50_100.X / wXYZ[0];
+ XYZ[1] = XYZ[1] * icmD50_100.Y / wXYZ[1];
+ XYZ[2] = XYZ[2] * icmD50_100.Z / wXYZ[2];
+ }
+
+ /* recompute Lab */
+ icmXYZ2Lab(&icmD50_100, Lab, XYZ);
+
+ /* recompute Yxy from XYZ */
+ icmXYZ2Yxy(Yxy, XYZ);
+
+ /* recompute LCh from Lab */
+ icmLab2LCh(LCh, Lab);
+#else /* SALONEINSTLIB */
+ else {
+
+ /* Normalize to white */
+ XYZ[0] = XYZ[0] * D50_X_100 / wXYZ[0];
+ XYZ[1] = XYZ[1] * D50_Y_100 / wXYZ[1];
+ XYZ[2] = XYZ[2] * D50_Z_100 / wXYZ[2];
+ }
+
+ /* recompute Lab */
+ XYZ2Lab(Lab, XYZ);
+
+ /* recompute Yxy from XYZ */
+ XYZ2Yxy(Yxy, XYZ);
+
+ /* recompute LCh from Lab */
+ Lab2LCh(LCh, Lab);
+#endif /* SALONEINSTLIB */
+ }
+
+ if (ambient && (cap2 & inst2_ambient_mono)) {
+ printf("\n Result is Y: %f, L*: %f\n",XYZ[1], Lab[0]);
+ } else {
+ if (doYxy) {
+ /* Print out the XYZ and Yxy */
+ printf("\n Result is XYZ: %f %f %f, Yxy: %f %f %f\n",
+ XYZ[0], XYZ[1], XYZ[2], Yxy[0], Yxy[1], Yxy[2]);
+ } else if (doLCh) {
+ /* Print out the XYZ and LCh */
+ printf("\n Result is XYZ: %f %f %f, LCh: %f %f %f\n",
+ XYZ[0], XYZ[1], XYZ[2], LCh[0], LCh[1], LCh[2]);
+ } else {
+ /* Print out the XYZ and Lab */
+ printf("\n Result is XYZ: %f %f %f, D50 Lab: %f %f %f\n",
+ XYZ[0], XYZ[1], XYZ[2], Lab[0], Lab[1], Lab[2]);
+ }
+ }
+
+ if (rLab[0] >= -9.0) {
+ if (refstats) {
+ double avg[3], sdev[3];
+ rstat_n++;
+
+ for (j = 0; j < 3; j++) {
+ rstat_XYZ[j] += XYZ[j];
+ rstat_XYZsq[j] += XYZ[j] * XYZ[j];
+
+ avg[j] = rstat_XYZ[j]/rstat_n;
+ sdev[j] = sqrt(rstat_n * rstat_XYZsq[j] - rstat_XYZ[j] * rstat_XYZ[j])/rstat_n;
+ }
+ printf(" XYZ stats %.0f: Avg %f %f %f, S.Dev %f %f %f\n",
+ rstat_n, avg[0], avg[1], avg[2], sdev[0], sdev[1], sdev[2]);
+
+ for (j = 0; j < 3; j++) {
+ rstat_Lab[j] += Lab[j];
+ rstat_Labsq[j] += Lab[j] * Lab[j];
+
+ avg[j] = rstat_Lab[j]/rstat_n;
+ sdev[j] = sqrt(rstat_n * rstat_Labsq[j] - rstat_Lab[j] * rstat_Lab[j])/rstat_n;
+ }
+ printf(" Lab stats %.0f: Avg %f %f %f, S.Dev %f %f %f\n",
+ rstat_n, avg[0], avg[1], avg[2], sdev[0], sdev[1], sdev[2]);
+ }
+#ifndef SALONEINSTLIB
+ printf(" Delta E to reference is %f %f %f (%f, CIE94 %f)\n",
+ Lab[0] - rLab[0], Lab[1] - rLab[1], Lab[2] - rLab[2],
+ icmLabDE(Lab, rLab), icmCIE94(Lab, rLab));
+#else
+ printf(" Delta E to reference is %f %f %f (%f)\n",
+ Lab[0] - rLab[0], Lab[1] - rLab[1], Lab[2] - rLab[2],
+ LabDE(Lab, rLab));
+#endif
+ }
+ if (ambient) {
+ if (ambient == 2)
+ printf(" Apparent flash duration = %f seconds\n",val.duration);
+ if (cap2 & inst2_ambient_mono) {
+ printf(" Ambient = %.1f Lux%s\n",
+ 3.141592658 * XYZ[1], ambient == 2 ? "-Seconds" : "");
+ if (ambient != 2)
+ printf(" Suggested EV @ ISO100 for %.1f Lux incident light = %.1f\n",
+ 3.141592658 * XYZ[1],
+ log(3.141592658 * XYZ[1]/2.5)/log(2.0));
+ } else {
+#ifndef SALONEINSTLIB
+ printf(" Ambient = %.1f Lux%s, CCT = %.0fK (Delta E %f)\n",
+ 3.1415926 * XYZ[1], ambient == 2 ? "-Seconds" : "",
+ cct, cct_de);
+ if (ambient != 2)
+ printf(" Suggested EV @ ISO100 for %.1f Lux incident light = %.1f\n",
+ 3.141592658 * XYZ[1],
+ log(3.141592658 * XYZ[1]/2.5)/log(2.0));
+ printf(" Closest Planckian temperature = %.0fK (Delta E %f)\n",vct, vct_de);
+ printf(" Closest Daylight temperature = %.0fK (Delta E %f)\n",vdt, vdt_de);
+#else /* SALONEINSTLIB */
+ printf(" Ambient = %.1f Lux%s\n",
+ 3.1415926 * XYZ[1], ambient == 2 ? "-Seconds" : "");
+#endif /* SALONEINSTLIB */
+ }
+#ifndef SALONEINSTLIB
+ } else if (doCCT) {
+ printf(" CCT = %.0fK (Delta E %f)\n",cct, cct_de);
+ printf(" Closest Planckian temperature = %.0fK (Delta E %f)\n",vct, vct_de);
+ printf(" Closest Daylight temperature = %.0fK (Delta E %f)\n",vdt, vdt_de);
+#endif
+ }
+#ifndef SALONEINSTLIB
+ if (val.sp.spec_n > 0 && (ambient || doCCT)) {
+ int invalid = 0;
+ double cri;
+ cri = icx_CIE1995_CRI(&invalid, &sp);
+ printf(" Color Rendering Index (Ra) = %.1f%s\n",cri,invalid ? " (Invalid)" : "");
+ }
+#endif
+
+ /* Save reading to the log file */
+ if (fp != NULL) {
+ /* Print some column titles */
+ if (loghead == 0) {
+ fprintf(fp,"Reading\tX\tY\tZ\tL*\ta*\tb*");
+ if (pspec) { /* Print or plot out spectrum */
+ for (j = 0; j < sp.spec_n; j++) {
+ double wvl = sp.spec_wl_short
+ + j * (sp.spec_wl_long - sp.spec_wl_short)/(sp.spec_n-1);
+ fprintf(fp,"\t%3f",wvl);
+ }
+ }
+ fprintf(fp,"\n");
+ loghead = 1;
+ }
+
+ /* Print results */
+ fprintf(fp,"%d\t%f\t%f\t%f\t%f\t%f\t%f",
+ ix, XYZ[0], XYZ[1], XYZ[2], Lab[0], Lab[1], Lab[2]);
+
+ if (pspec != 0) {
+ for (j = 0; j < sp.spec_n; j++)
+ fprintf(fp,"\t%8.3f",sp.spec[j]);
+ }
+ fprintf(fp,"\n");
+ }
+ }
+ } /* Next reading */
+
+ /* Release paper */
+ if (cap2 & inst2_xy_holdrel) {
+ it->xy_clear(it);
+ }
+
+#ifdef DEBUG
+ printf("About to exit\n");
+#endif
+
+ if (sp2cie != NULL)
+ sp2cie->del(sp2cie);
+ for (i = 0; i < 26; i++)
+ if (sp2cief[i] != NULL)
+ sp2cief[i]->del(sp2cief[i]);
+
+ /* Free instrument */
+ it->del(it);
+
+ icmps->del(icmps);
+
+ if (fp != NULL)
+ fclose(fp);
+
+ return 0;
+}
+
+
+
+
diff --git a/spectro/spyd2.c b/spectro/spyd2.c
new file mode 100644
index 0000000..f8f9bac
--- /dev/null
+++ b/spectro/spyd2.c
@@ -0,0 +1,3808 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Datacolor/ColorVision Spyder 2/3/4 related software.
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/9/2007
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * (Based initially on i1disp.c)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ IMPORTANT NOTES:
+
+ The Spyder 2 instrument cannot function without the driver software
+ having access to the vendor supplied PLD firmware pattern for it.
+ This firmware is not provided with Argyll, since it is not available
+ under a compatible license.
+
+ The purchaser of a Spyder 2 instrument should have received a copy
+ of this firmware along with their instrument, and should therefore be able to
+ enable the Argyll driver for this instrument by using the spyd2en utility
+ to create a spyd2PLD.bin file.
+
+ [ The Spyder 3 & 4 don't need a PLD firmware file. ]
+
+
+ The Spyder 4 instrument will not have the full range of manufacturer
+ calibration settings available without the vendor calibration data.
+ This calibration day is not provided with Argyll, since it is not
+ available under a compatible license.
+
+ The purchaser of a Spyder 4 instrument should have received a copy
+ of this calibration data along with their instrument, and should therefore
+ be able to enable the use of the full range of calibration settings
+ by using the spyd4en utility to create a spyd4cal.bin file.
+
+ Alternatively, you can use Argyll .ccss files to set a Spyder 4
+ calibration.
+
+ [ The Spyder 2 & 3 don't need a calibration data file. ]
+
+ The hwver == 5 code is not fully implemented.
+ It's not possible to get it going without an instrument to verify on.
+ (Perhaps it has only 4 sensors ?)
+
+ The frequency measurement is not very accurate, particularly for
+ the Spyder 3 & 4, being too low by about 3.5%.
+
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+/* TTBD:
+
+ Would be good to add read/write data values if debug >= 3
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <math.h>
+#include <fcntl.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "spyd2.h"
+
+#undef PLOT_SPECTRA /* Plot the sensor senitivity spectra */
+#undef PLOT_SPECTRA_EXTRA /* Plot the sensor senitivity spectra extra values */
+#undef SAVE_SPECTRA /* Save the sensor senitivity spectra to "sensors.sp" */
+#undef SAVE_XYZSPECTRA /* Save the XYZ senitivity spectra to "sensorsxyz.sp" (scale 1.4) */
+#undef SAVE_STDXYZ /* save 1931 2 degree to stdobsxyz.sp */
+
+
+#define DO_RESETEP /* Do the miscelanous resetep()'s */
+#define CLKRATE 1000000 /* Clockrate the Spyder 2 hardware runs at */
+#define MSECDIV (CLKRATE/1000) /* Divider to turn clocks into msec */
+#define DEFRRATE 50 /* Default display refresh rate */
+#define DO_ADAPTIVE /* Adapt the integration time to the light level */
+ /* This helps repeatability at low levels A LOT */
+
+#define LEVEL2 /* Second level (nonliniarity) calibration */
+#define RETRIES 4 /* usb_reads are unreliable - bug in spyder H/W ?*/
+
+#ifdef DO_ADAPTIVE
+# define RINTTIME 2.0 /* Base time to integrate reading over - refresh display */
+# define NINTTIME 2.0 /* Base time to integrate reading over - non-refresh display */
+#else /* !DO_ADAPTIVE */
+# define RINTTIME 5.0 /* Integrate over fixed longer time (manufacturers default) */
+# define NINTTIME 5.0 /* Integrate over fixed longer time (manufacturers default) */
+#endif /* !DO_ADAPTIVE */
+
+static inst_code spyd2_interp_code(inst *pp, int ec);
+
+/* ------------------------------------------------------------------------ */
+/* Implementation */
+
+/* Interpret an icoms error into a SPYD2 error */
+static int icoms2spyd2_err(int se) {
+ if (se != ICOM_OK)
+ return SPYD2_COMS_FAIL;
+ return SPYD2_OK;
+}
+
+/* ----------------------------------------------------- */
+/* Big endian wire format conversion routines */
+
+/* Take an int, and convert it into a byte buffer big endian */
+static void int2buf(unsigned char *buf, int inv) {
+ buf[0] = (unsigned char)(inv >> 24) & 0xff;
+ buf[1] = (unsigned char)(inv >> 16) & 0xff;
+ buf[2] = (unsigned char)(inv >> 8) & 0xff;
+ buf[3] = (unsigned char)(inv >> 0) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer big endian */
+static void short2buf(unsigned char *buf, int inv) {
+ buf[0] = (unsigned char)(inv >> 8) & 0xff;
+ buf[1] = (unsigned char)(inv >> 0) & 0xff;
+}
+
+/* Take a short sized buffer, and convert it to an int big endian */
+static int buf2short(unsigned char *buf) {
+ int val;
+ val = buf[0];
+ val = ((val << 8) + (0xff & buf[1]));
+ return val;
+}
+
+/* Take a unsigned short sized buffer, and convert it to an int big endian */
+static int buf2ushort(unsigned char *buf) {
+ int val;
+ val = (0xff & buf[0]);
+ val = ((val << 8) + (0xff & buf[1]));
+ return val;
+}
+
+/* Take a word sized buffer, and convert it to an int big endian. */
+static int buf2int(unsigned char *buf) {
+ int val;
+ val = buf[0];
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[3]));
+ return val;
+}
+
+/* Take a word sized buffer, and convert it to an unsigned int big endian. */
+static unsigned int buf2uint(unsigned char *buf) {
+ unsigned int val;
+ val = buf[0];
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[3]));
+ return val;
+}
+
+
+/* Take a 3 byte buffer, and convert it to an unsigned int big endian. */
+static unsigned int buf2uint24(unsigned char *buf) {
+ unsigned int val;
+ val = buf[0];
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[2]));
+ return val;
+}
+
+/* Take a 24 bit unsigned sized buffer in little endian */
+/* format, and return an int */
+static unsigned int buf2uint24le(unsigned char *buf) {
+ unsigned int val;
+ val = (0xff & buf[2]);
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a 24 bit unsigned sized buffer in little endian */
+/* nibble swapped format, and return an int */
+static unsigned int buf2uint24lens(unsigned char *buf) {
+ unsigned int val;
+ val = (0xf & buf[2]);
+ val = (val << 4) + (0xf & (buf[2] >> 4));
+ val = (val << 4) + (0xf & buf[1]);
+ val = (val << 4) + (0xf & (buf[1] >> 4));
+ val = (val << 4) + (0xf & buf[0]);
+ val = (val << 4) + (0xf & (buf[0] >> 4));
+ return val;
+}
+
+/* Take a 64 sized return buffer, and convert it to a ORD64 */
+static ORD64 buf2ord64(unsigned char *buf) {
+ ORD64 val;
+ val = buf[7];
+ val = ((val << 8) + (0xff & buf[6]));
+ val = ((val << 8) + (0xff & buf[5]));
+ val = ((val << 8) + (0xff & buf[4]));
+ val = ((val << 8) + (0xff & buf[3]));
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* ============================================================ */
+/* Low level commands */
+
+
+/* USB Instrument commands */
+
+/* Spyder 2: Reset the instrument */
+static inst_code
+spyd2_reset(
+ spyd2 *p
+) {
+ int se;
+ int retr;
+ inst_code rv = inst_ok;
+
+ a1logd(p->log, 3, "spyd2_reset: called\n");
+
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC7, 0, 0, NULL, 0, 5.0);
+
+ if (se == ICOM_OK) {
+ a1logd(p->log, 6, "spyd2_reset: complete, ICOM code 0x%x\n",se);
+ break;
+ }
+ if (retr >= RETRIES ) {
+ a1logd(p->log, 1, "spyd2_reset: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_reset: reset retry with ICOM err 0x%x\n",se);
+ }
+
+ return rv;
+}
+
+/* Spyder 2: Get status */
+/* return pointer may be NULL if not needed. */
+static inst_code
+spyd2_getstatus(
+ spyd2 *p,
+ int *stat /* Return the 1 byte status code */
+) {
+ unsigned char pbuf[8]; /* status bytes read */
+ int _stat;
+ int se;
+ int retr;
+ inst_code rv = inst_ok;
+
+ a1logd(p->log, 3, "spyd2_getstatus: called\n");
+
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC6, 0, 0, pbuf, 8, 5.0);
+
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES ) {
+ a1logd(p->log, 1, "spyd2_getstatus: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_getstatus: retry with ICOM err 0x%x\n",se);
+ }
+ msec_sleep(100); /* Limit rate status commands can be given */
+
+ _stat = pbuf[0]; /* Only the first byte is examined. */
+ /* Other bytes have information, but SW ignores them */
+
+ a1logd(p->log, 3, "spyd2_getstatus: returns %d ICOM err 0x%x\n", _stat, se);
+
+ if (stat != NULL) *stat = _stat;
+
+ return rv;
+}
+
+/* Read Serial EEProm bytes (implementation) */
+/* Can't read more than 256 in one go */
+static inst_code
+spyd2_readEEProm_imp(
+ spyd2 *p,
+ unsigned char *buf, /* Buffer to return bytes in */
+ int addr, /* Serial EEprom address, 0 - 1023 */
+ int size /* Number of bytes to read, 0 - 128 (ie. max of bank) */
+) {
+ int se;
+ int retr;
+ inst_code rv = inst_ok;
+
+ a1logd(p->log, 3, "spyd2_readEEProm_imp: addr %d, bytes %d\n",addr,size);
+
+ if (addr < 0
+ || (p->hwver < 7 && (addr + size) > 512)
+ || (p->hwver == 7 && (addr + size) > 1024))
+ return spyd2_interp_code((inst *)p, SPYD2_BAD_EE_ADDRESS);
+
+ if (size >= 256)
+ return spyd2_interp_code((inst *)p, SPYD2_BAD_EE_SIZE);
+
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC4, addr, size, buf, size, 5.0);
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES) {
+ a1logd(p->log, 1, "spyd2_readEEProm_imp: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_readEEProm_imp: retry with ICOM err 0x%x\n",se);
+ }
+
+
+ a1logd(p->log, 3, "spyd2_readEEProm_imp: returning ICOM err 0x%x\n", se);
+
+ return rv;
+}
+
+/* Read Serial EEProm bytes */
+/* (Handles reads > 256 bytes) */
+static inst_code
+spyd2_readEEProm(
+ spyd2 *p,
+ unsigned char *buf, /* Buffer to return bytes in */
+ int addr, /* Serial EEprom address, 0 - 511 */
+ int size /* Number of bytes to read, 0 - 511 */
+) {
+
+ if (addr < 0
+ || (p->hwver < 7 && (addr + size) > 512)
+ || (p->hwver == 7 && (addr + size) > 1024))
+ return spyd2_interp_code((inst *)p, SPYD2_BAD_EE_ADDRESS);
+
+ while (size > 255) { /* Single read is too big */
+ inst_code rv;
+ if ((rv = spyd2_readEEProm_imp(p, buf, addr, 255)) != inst_ok)
+ return rv;
+ size -= 255;
+ buf += 255;
+ addr += 255;
+ }
+ return spyd2_readEEProm_imp(p, buf, addr, size);
+}
+
+/* Spyder 2: Download PLD pattern */
+static inst_code
+spyd2_loadPLD(
+ spyd2 *p,
+ unsigned char *buf, /* Bytes to download */
+ int size /* Number of bytes */
+) {
+ int se;
+ int retr;
+ inst_code rv = inst_ok;
+
+ a1logd(p->log, 6, "spyd2_loadPLD: Load PLD %d bytes\n",size);
+
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC0, 0, 0, buf, size, 5.0);
+
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES ) {
+ a1logd(p->log, 1, "spyd2_loadPLD: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_loadPLD: retry with ICOM err 0x%x\n",se);
+ }
+
+ a1logd(p->log, 6, "spyd2_loadPLD: returns ICOM err 0x%x\n", se);
+
+ return rv;
+}
+
+/* Get minmax command. */
+/* Figures out the current minimum and maximum frequency periods */
+/* so as to be able to set a frame detect threshold. */
+/* Note it returns 0,0 if there is not enough light. */
+/* (The light to frequency output period size is inversly */
+/* related to the lightness level) */
+/* (This isn't used by the manufacturers Spyder3/4 driver, */
+/* but the instrument seems to impliment it.) */
+static inst_code
+spyd2_GetMinMax(
+ spyd2 *p,
+ int *clocks, /* Number of clocks to use (may get limited) */
+ int *min, /* Return min and max light->frequency periods */
+ int *max
+) {
+ int rwbytes; /* Data bytes read or written */
+ int se;
+ inst_code rv = inst_ok;
+ int value;
+ int index;
+ int retr;
+ unsigned char buf[8]; /* return bytes read */
+
+ a1logd(p->log, 2, "spyd2_GetMinMax: %d clocks\n",*clocks);
+
+ /* Issue the triggering command */
+ if (*clocks > 0xffffff)
+ *clocks = 0xffffff; /* Maximum count hardware will take ? */
+ value = *clocks >> 8;
+ value = (value >> 8) | ((value << 8) & 0xff00); /* Convert to big endian */
+ index = (*clocks << 8) & 0xffff;
+ index = (index >> 8) | ((index << 8) & 0xff00); /* Convert to big endian */
+
+ for (retr = 0; ; retr++) {
+ /* Issue the trigger command */
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC2, value, index, NULL, 0, 5.0);
+
+ if ((se != ICOM_OK && retr >= RETRIES)) {
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ msec_sleep(*clocks/MSECDIV);
+ p->icom->usb_read(p->icom, NULL, 0x81, buf, 8, &rwbytes, 1.0);
+
+ a1logd(p->log, 1, "spyd2_GetMinMax: trig failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ if (se != ICOM_OK) {
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ msec_sleep(*clocks/MSECDIV);
+ p->icom->usb_read(p->icom, NULL, 0x81, buf, 8, &rwbytes, 1.0);
+
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_GetMinMax: trig retry with ICOM err 0x%x\n",se);
+ continue;
+ }
+
+ a1logd(p->log, 3, "spyd2_GetMinMax: trig returns ICOM err 0x%x\n", se);
+
+ /* Allow some time for the instrument to respond */
+ msec_sleep(*clocks/MSECDIV);
+
+ /* Now read the bytes */
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf, 8, &rwbytes, 5.0);
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES) {
+ a1logd(p->log, 1, "spyd2_GetMinMax: get failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_GetMinMax: get retry with ICOM err 0x%x\n",se);
+ }
+
+ if (rwbytes != 8) {
+ a1logd(p->log, 1, "spyd2_GetMinMax: got short data read %d",rwbytes);
+ return spyd2_interp_code((inst *)p, SPYD2_BADREADSIZE);
+ }
+
+ *min = buf2ushort(&buf[0]);
+ *max = buf2ushort(&buf[2]);
+
+ a1logd(p->log, 3, "spyd2_GetMinMax: got %d/%d returns ICOM err 0x%x\n", *min, *max, se);
+
+ return rv;
+}
+
+/* Get refresh rate (low level) command */
+/* (This isn't used by the manufacturers Spyder3 driver, */
+/* but the instrument seems to implement it.) */
+static inst_code
+spyd2_GetRefRate_ll(
+ spyd2 *p,
+ int *clocks, /* Maximum number of clocks to use */
+ int nframes, /* Number of frames to count */
+ int thresh, /* Frame detection threshold */
+ int *minfclks, /* Minimum number of clocks per frame */
+ int *maxfclks, /* Maximum number of clocks per frame */
+ int *clkcnt /* Return number of clocks for nframes frames */
+) {
+ int rwbytes; /* Data bytes read or written */
+ int se;
+ inst_code rv = inst_ok;
+ int value;
+ int index;
+ int flag;
+ int retr;
+ unsigned char buf1[8]; /* send bytes */
+ unsigned char buf2[8]; /* return bytes read */
+
+ a1logd(p->log, 3, "spyd2_GetRefRate_ll: %d clocks\n",*clocks);
+
+ /* Setup the triggering parameters */
+ if (*clocks > 0xffffff) /* Enforce hardware limits */
+ *clocks = 0xffffff;
+ if (*minfclks > 0x7fff)
+ *minfclks = 0x7fff;
+ if (*maxfclks > 0x7fff)
+ *maxfclks = 0x7fff;
+ value = *clocks >> 8;
+ value = (value >> 8) | ((value << 8) & 0xff00); /* Convert to big endian */
+ index = (*clocks << 8) & 0xffff;
+ index = (index >> 8) | ((index << 8) & 0xff00); /* Convert to big endian */
+
+ /* Setup parameters in send buffer */
+ short2buf(&buf1[0], thresh);
+ short2buf(&buf1[2], nframes);
+ short2buf(&buf1[4], *minfclks);
+ short2buf(&buf1[6], *maxfclks);
+
+ /* Issue the triggering command */
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC3, value, index, buf1, 8, 5.0);
+
+ if (se != ICOM_OK && retr >= RETRIES) {
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ msec_sleep(*clocks/MSECDIV);
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 1.0);
+
+ a1logd(p->log, 1, "spyd2_GetRefRate_ll: trig failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ if (se != ICOM_OK) {
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ msec_sleep(*clocks/MSECDIV);
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 1.0);
+
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_GetRefRate_ll: trig retry with ICOM err 0x%x\n",se);
+ continue;
+ }
+
+ a1logd(p->log, 3, "spyd2_GetRefRate_ll: trig returns ICOM err 0x%x\n", se);
+
+ /* Allow some time for the instrument to respond */
+ msec_sleep(*clocks/MSECDIV);
+
+ /* Now read the bytes */
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 5.0);
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES) {
+ a1logd(p->log, 3, "spyd2_GetRefRate_ll: get failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_GetRefRate_ll: get retry with ICOM err 0x%x\n",se);
+ }
+
+ if (rwbytes != 8) {
+ a1logd(p->log, 1, "spyd2_GetRefRate_ll: got short data read %d",rwbytes);
+ return spyd2_interp_code((inst *)p, SPYD2_BADREADSIZE);
+ }
+
+ flag = buf2[0];
+ *clkcnt = buf2uint24(&buf2[1]);
+
+ /* Spyder2 */
+ if (p->hwver < 4 && flag == 1) {
+ a1logd(p->log, 1, "spyd2_GetRefRate_ll: got trigger timeout");
+ return spyd2_interp_code((inst *)p, SPYD2_TRIGTIMEOUT);
+ }
+
+ /* Spyder2 */
+ if (p->hwver < 4 && flag == 2) {
+ a1logd(p->log, 1, "spyd2_GetRefRate_ll: got overall timeout");
+ return spyd2_interp_code((inst *)p, SPYD2_OVERALLTIMEOUT);
+ }
+
+ a1logd(p->log, 3, "spyd2_GetRefRate_ll: result %d, returns ICOM err 0x%x\n", *clkcnt, se);
+
+ return rv;
+}
+
+/* Get a reading (low level) command */
+static inst_code
+spyd2_GetReading_ll(
+ spyd2 *p,
+ int *clocks, /* Nominal/Maximum number of integration clocks to use */
+ int nframes, /* Number of refresh frames being measured (not used ?) */
+ int thresh, /* Frame detection threshold */
+ int *minfclks, /* Minimum number of clocks per frame */
+ int *maxfclks, /* Maximum number of clocks per frame */
+ double *sensv, /* Return the 8 sensor readings (may be NULL) */
+ int *maxtcnt, /* Return the maximum transition count (may be NULL) */
+ int *mintcnt /* Return the minimum transition count (may be NULL) */
+) {
+ int rwbytes; /* Data bytes read or written */
+ int se;
+ inst_code rv = inst_ok;
+ int value;
+ int index;
+ int flag;
+ int nords, retr;
+ unsigned char buf1[8]; /* send bytes */
+ unsigned char buf2[9 * 8]; /* return bytes read */
+ int rvals[3][8]; /* Raw values */
+ int _maxtcnt = 0; /* Maximum transition count */
+ int _mintcnt = 0x7fffffff; /* Minumum transition count */
+ int i, j, k;
+
+ a1logd(p->log, 3, "spyd2_GetReading_ll: clocks = %d, minfc = %d, maxfc = %d\n",*clocks,*minfclks,*maxfclks);
+
+ /* Setup the triggering parameters */
+ if (*clocks > 0xffffff)
+ *clocks = 0xffffff;
+ if (*minfclks > 0x7fff)
+ *minfclks = 0x7fff;
+ if (*maxfclks > 0x7fff)
+ *maxfclks = 0x7fff;
+ value = *clocks >> 8;
+ if (p->hwver == 5) { /* Hmm. not sure if this is right */
+ value /= 1000;
+ }
+ value = (value >> 8) | ((value << 8) & 0xff00); /* Convert to big endian */
+ index = (*clocks << 8) & 0xffff;
+ index = (index >> 8) | ((index << 8) & 0xff00); /* Convert to big endian */
+
+ /* Setup parameters in send buffer */
+ /* (Spyder3 doesn't seem to use these. Perhaps it does its */
+ /* own internal refresh detection and syncronization ?) */
+ thresh *= 256;
+ int2buf(&buf1[0], thresh);
+ short2buf(&buf1[4], *minfclks);
+ short2buf(&buf1[6], *maxfclks);
+
+ /* If we aborted a read, the prevraw values are now invalid. */
+ /* We fix it by doing a dumy reading. */
+ if (p->hwver < 4 && p->prevrawinv) {
+ int clocks = 500;
+ int minfclks = 0;
+ int maxfclks = 0;
+ p->prevrawinv = 0;
+ a1logd(p->log, 3, "spyd2_GetReading_ll: doing dummy read to get prevraw\n");
+ if ((rv = spyd2_GetReading_ll(p, &clocks, 10, 0, &minfclks, &maxfclks, NULL, NULL, NULL)) != inst_ok) {
+ a1logd(p->log, 1, "spyd2_GetReading_ll: dummy read failed\n");
+ p->prevrawinv = 1;
+ return rv;
+ }
+ }
+
+ /* The Spyder comms seems especially flakey... */
+ for (retr = 0, nords = 1; ; retr++, nords++) {
+
+//int start = msec_time();
+
+ /* Issue the triggering command */
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xC1, value, index, buf1, 8, 5.0);
+
+ if (se != ICOM_OK && retr >= RETRIES) {
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ msec_sleep(*clocks/MSECDIV);
+ for (i = 0; i < (1+9); i++)
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 1.0);
+ p->prevrawinv = 1; /* prevraw are now invalid */
+
+ a1logd(p->log, 1, "spyd2_GetReading_ll: trig failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ if (se != ICOM_OK) {
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ msec_sleep(*clocks/MSECDIV);
+ for (i = 0; i < (1+9); i++)
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 1.0);
+ p->prevrawinv = 1; /* prevraw are now invalid */
+
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_GetReading_ll: trig retry with ICOM err 0x%x\n",se);
+ continue;
+ }
+
+ a1logd(p->log, 3, "spyd2_GetReading_ll: reading returns ICOM code 0x%x\n", se);
+
+ /* Allow some time for the instrument to respond */
+ msec_sleep(*clocks/MSECDIV);
+
+ /* Now read the first 8 bytes (status etc.) */
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 5.0);
+ if (se != ICOM_OK && retr >= RETRIES) {
+ a1logd(p->log, 1, "spyd2_GetReading_ll: read stat failed with ICOM err 0x%x\n",se);
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ for (i = 0; i < (1+9); i++)
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 0.5);
+ p->prevrawinv = 1; /* prevraw are now invalid */
+ msec_sleep(500);
+
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+//printf("~1 trig -> read = %d msec\n",msec_time() - start);
+
+ if (se != ICOM_OK) {
+ a1logd(p->log, 1, "spyd2_GetReading_ll: read stat retry with ICOM err 0x%x\n", se);
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ for (i = 0; i < (1+9); i++)
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 0.5);
+ p->prevrawinv = 1; /* prevraw are now invalid */
+ msec_sleep(500);
+ continue; /* Retry the whole command */
+ }
+
+ if (rwbytes != 8) {
+ a1logd(p->log, 1, "spyd2_GetReading_ll: read stat got short data read %d",rwbytes);
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ for (i = 0; i < (1+9); i++)
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2, 8, &rwbytes, 0.5);
+ p->prevrawinv = 1; /* prevraw are now invalid */
+ msec_sleep(500);
+
+ return spyd2_interp_code((inst *)p, SPYD2_BADREADSIZE);
+ }
+
+ flag = buf2[0];
+
+ /* Spyder2 */
+ if (p->hwver < 4 && flag == 1) {
+ a1logd(p->log, 1, "spyd2_GetReading_ll: read stat is trigger timeout");
+ return spyd2_interp_code((inst *)p, SPYD2_TRIGTIMEOUT);
+ }
+
+ /* Spyder2 */
+ if (p->hwver < 4 && flag == 2) {
+ a1logd(p->log, 1, "spyd2_GetReading_ll: read stat is overall timeout");
+ return spyd2_interp_code((inst *)p, SPYD2_OVERALLTIMEOUT);
+ }
+
+ /* Now read the following 9 x 8 bytes of sensor data */
+ for (i = 0; i < 9; i++) {
+
+ se = p->icom->usb_read(p->icom, NULL, 0x81, buf2 + i * 8, 8, &rwbytes, 5.0);
+ if (se != ICOM_OK && retr >= RETRIES) {
+ int ii = i;
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ for (; ii < (1+9); ii++)
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2 + i * 8, 8, &rwbytes, 0.5);
+ p->prevrawinv = 1; /* prevraw are now invalid */
+
+ a1logd(p->log, 1, "spyd2_GetReading_ll: get reading failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ if (se != ICOM_OK) {
+ int ii = i;
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ for (; ii < (1+9); ii++)
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2 + i * 8, 8, &rwbytes, 0.5);
+ p->prevrawinv = 1; /* prevraw are now invalid */
+
+ break;
+ }
+ if (rwbytes != 8) {
+ int ii = i;
+ a1logd(p->log, 1, "spyd2_GetReading_ll: got short data read %d",rwbytes);
+
+ /* Complete the operation so as not to leave the instrument in a hung state */
+ for (; ii < (1+9); ii++)
+ p->icom->usb_read(p->icom, NULL, 0x81, buf2 + i * 8, 8, &rwbytes, 0.5);
+ p->prevrawinv = 1; /* prevraw are now invalid */
+
+ return spyd2_interp_code((inst *)p, SPYD2_BADREADSIZE);
+ }
+ }
+
+ if (i >= 9)
+ break; /* We're done */
+
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_GetReading_ll: reading retry with ICOM err 0x%x\n",se);
+
+#ifdef DO_RESETEP /* Do the miscelanous resetep()'s */
+ a1logd(p->log, 1, "spyd2_GetReading_ll: resetting end point\n");
+ p->icom->usb_resetep(p->icom, 0x81);
+ msec_sleep(1); /* Let device recover ? */
+#endif /* DO_RESETEP */
+ } /* End of whole command retries */
+
+ if (p->log->debug >= 5) {
+ a1logd(p->log, 5, "spyd2_GetReading_ll: got bytes:\n");
+ for (i = 0; i < 9; i++) {
+ a1logd(p->log, 5, " %d: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",i * 8,
+ buf2[i * 8 + 0], buf2[i * 8 + 1], buf2[i * 8 + 2], buf2[i * 8 + 3],
+ buf2[i * 8 + 4], buf2[i * 8 + 5], buf2[i * 8 + 6], buf2[i * 8 + 7]);
+ }
+ }
+
+ /* Spyder 2 decoding */
+ /* Spyder2 */
+ if (p->hwver < 4) {
+ /* Convert the raw buffer readings into 3 groups of 8 integers. */
+ /* At the start of each reading, the HW starts counting master */
+ /* (1MHz) clocks. When the first transition after the start of */
+ /* the reading is received from a light->frequency sensor (TAOS TSL237), */
+ /* the clock count is recorded, and returned as the second of the three */
+ /* numbers returned for each sensor. */
+ /* When the last transition before the end of the reading period is */
+ /* received, the clock count is recorded, and returned as the first */
+ /* of the three numbers. The integration period is therefore */
+ /* the first number minus the second. */
+ /* The third number is the number of transitions from the sensor */
+ /* counted during the integration period. Since this 24 bit counter is */
+ /* not reset between readings, the previous count is recorded (prevraw[]), */
+ /* and subtracted (modulo 24 bits) from the current value. */
+ /* The light level is directly proportional to the frequency, */
+ /* hence the transitions-1 counted. */
+ /* In the case of a CRT, the total number of clocks is assumed to be */
+ /* set to an integer number of refresh cycles, and the total transitions */
+ /* over that period are counted. */
+ for (i = j = 0; j < 3; j++) {
+ for (k = 0; k < 8; k++, i += 3) {
+ rvals[j][k] = buf2uint24lens(buf2 + i);
+// a1logd(p->log, 1, "got rvals[%d][%d] = 0x%x\n",j,k,rvals[j][k]);
+ }
+ }
+
+ /* And convert 3 values per sensor into sensor values */
+ for (k = 0; k < 8; k++) {
+ int transcnt, intclks;
+
+ /* Compute difference of L2F count to previous value */
+ /* read, modulo 24 bits */
+ a1logd(p->log, 5, "%d: transcnt %d, previous %d\n", k,rvals[2][k],p->prevraw[k]);
+ if (p->prevraw[k] <= rvals[2][k]) {
+ transcnt = rvals[2][k] - p->prevraw[k];
+ } else {
+ transcnt = rvals[2][k] + 0x1000000 - p->prevraw[k];
+ }
+
+ p->prevraw[k] = rvals[2][k]; /* New previuos value */
+
+ /* Compute difference of 1MHz clock count of first to second value */
+ intclks = rvals[0][k] - rvals[1][k];
+
+ if (transcnt == 0 || intclks <= 0) { /* It's too dark ... */
+ if (sensv != NULL)
+ sensv[k] = 0.0;
+ _mintcnt = 0;
+ } else { /* We discard 0'th L2F transion to give transitions */
+ /* over the time period. */
+ if (sensv != NULL)
+ sensv[k] = ((double)transcnt - 1.0) * (double)CLKRATE
+ / ((double)nords * (double)intclks);
+ if (transcnt > _maxtcnt)
+ _maxtcnt = transcnt;
+ if (transcnt < _mintcnt)
+ _mintcnt = transcnt;
+ }
+ if (p->log->debug >= 4 && sensv != NULL)
+ a1logd(p->log, 4, "%d: initial senv %f from transcnt %d and intclls %d\n",
+ k,sensv[k],transcnt,intclks);
+
+#ifdef NEVER /* This seems to make repeatability worse ??? */
+ /* If CRT and bright enough */
+ if (sensv != NULL && sensv[k] > 1.5 && p->refrmode != 0) {
+ sensv[k] = ((double)transcnt) * (double)p->refrate/(double)nframes;
+ }
+#endif
+ }
+
+ /* Spyder 3/4 decoding */
+ } else {
+ /* Convert the raw buffer readings into 3 groups of 8 integers. */
+ /* At the start of each reading, the HW starts counting master */
+ /* (1MHz) clocks. When the first transition after the start of */
+ /* the reading is received from a light->frequency sensor (TAOS TSL238T), */
+ /* the clock count is recorded, and returned as the second of the three */
+ /* numbers returned for each sensor. */
+ /* When the last transition before the end of the reading period is */
+ /* received, the clock count is recorded, and returned as the first */
+ /* of the three numbers. The integration period is therefore */
+ /* the first number minus the second. */
+ /* The third number is the number of transitions from the sensor */
+ /* counted during the integration period. */
+ /* The light level is directly proportional to the frequency, */
+ /* hence the transitions-1 counted. */
+
+ int map[8] = { 0,0,1,2,5,6,7,4 }; /* Map sensors into Spyder 2 order */
+
+ for (j = 0; j < 3; j++) {
+ for (k = 0; k < 8; k++) {
+ rvals[j][k] = buf2uint24le(buf2 + (j * 24 + map[k] * 3));
+// a1logd(p->log, 1, "got rvals[%d][%d] = 0x%x\n",j,k,rvals[j][k]);
+ }
+ }
+
+ /* And convert 3 integers per sensor into sensor values */
+ for (k = 0; k < 8; k++) {
+ int transcnt, intclks;
+
+ /* Number of sensor transitions */
+ transcnt = rvals[2][k];
+
+ /* Compute difference of first integer to second */
+ intclks = rvals[0][k] - rvals[1][k];
+
+ if (transcnt == 0 || intclks <= 0) { /* It's too dark ... */
+ if (sensv != NULL)
+ sensv[k] = 0.0;
+ _mintcnt = 0;
+ } else { /* Transitions within integration period */
+ /* hence one is discarded ? */
+ if (sensv != NULL)
+ sensv[k] = ((double)transcnt - 1.0) * (double)CLKRATE
+ / ((double)intclks * 8.125);
+ if (transcnt > _maxtcnt)
+ _maxtcnt = transcnt;
+ if (transcnt < _mintcnt)
+ _mintcnt = transcnt;
+ }
+ if (p->log->debug >= 4 && sensv != NULL)
+ a1logd(p->log, 4, "%d: initial senv %f from transcnt %d and intclls %d\n",
+ k,sensv[k],transcnt,intclks);
+ }
+ }
+
+ if (maxtcnt != NULL)
+ *maxtcnt = _maxtcnt;
+ if (mintcnt != NULL)
+ *mintcnt = _mintcnt;
+
+ return rv;
+}
+
+/* Spyder 3: Set the LED */
+static inst_code
+spyd2_setLED(
+ spyd2 *p,
+ int mode, /* LED mode: 0 = off, 1 = pulse, 2 = on */
+ double period /* Pulse period in seconds */
+) {
+ int se;
+ inst_code rv = inst_ok;
+ int value;
+ int index;
+ int retr;
+ int ptime; /* Pulse time, 1 - 255 x 20 msec */
+
+ if (mode < 0)
+ mode = 0;
+ else if (mode > 2)
+ mode = 2;
+ ptime = (int)(period/0.02 + 0.5);
+ if (ptime < 0)
+ ptime = 0;
+ else if (ptime > 255)
+ ptime = 255;
+
+ if (p->log->debug >= 2) {
+ if (mode == 1)
+ a1logd(p->log, 3, "spyd2_setLED: set to pulse, %f secs\n",ptime * 0.02);
+ else
+ a1logd(p->log, 3, "spyd2_setLED: set to %s\n",mode == 0 ? "off" : "on");
+ }
+
+ value = mode; /* Leave little endian */
+ index = ptime;
+
+ for (retr = 0; ; retr++) {
+ /* Issue the trigger command */
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xF6, value, index, NULL, 0, 5.0);
+
+ if (se == ICOM_OK) {
+ a1logd(p->log, 5, "spyd2_setLED: OK, ICOM code 0x%x\n",se);
+ break;
+ }
+ if (retr >= RETRIES) {
+ a1logd(p->log, 1, "spyd2_setLED: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_setLED: retry with ICOM err 0x%x\n",se);
+ }
+
+ return rv;
+}
+
+
+/* Spyder 3: Set the ambient control register */
+static inst_code
+spyd2_SetAmbReg(
+ spyd2 *p,
+ int val /* 8 bit ambient config register value */
+) {
+ int se;
+ inst_code rv = inst_ok;
+ int value;
+ int retr;
+
+ a1logd(p->log, 3, "spyd2_SetAmbReg: control register to %d\n",val);
+
+ if (val < 0)
+ val = 0;
+ else if (val > 255)
+ val = 255;
+ value = val; /* Leave little endian */
+
+ for (retr = 0; ; retr++) {
+ /* Issue the trigger command */
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xF3, value, 0, NULL, 0, 5.0);
+
+ if (se == ICOM_OK) {
+ a1logd(p->log, 5, "spyd2_SetAmbReg: OK, ICOM code 0x%x\n",se);
+ break;
+ }
+ if (retr >= RETRIES) {
+ a1logd(p->log, 1, "spyd2_SetAmbReg: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_SetAmbReg: retry with ICOM err 0x%x\n",se);
+ }
+
+ return rv;
+}
+
+/* Spyder3/4: Read ambient light timing */
+/* The byte value seems to be composed of:
+ bits 0,1
+ bits 4
+*/
+static inst_code
+spyd2_ReadAmbTiming(
+ spyd2 *p,
+ int *val /* Return the 8 bit timing value */
+) {
+ unsigned char pbuf[1]; /* Timing value read */
+ int _val;
+ int se;
+ int retr;
+ inst_code rv = inst_ok;
+
+ a1logd(p->log, 3, "spyd2_ReadAmbTiming: called\n");
+
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xF4, 0, 0, pbuf, 1, 5.0);
+
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES) {
+ a1logd(p->log, 1, "spyd2_ReadAmbTiming: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_ReadAmbTiming: retry with ICOM err 0x%x\n",se);
+ }
+
+ _val = pbuf[0];
+
+ a1logd(p->log, 5, "spyd2_ReadAmbTiming: returning val %d ICOM err 0x%x\n",_val, se);
+
+ if (val != NULL) *val = _val;
+
+ return rv;
+}
+
+
+/* Spyder3/4: Read ambient light channel 0 or 1 */
+static inst_code
+spyd2_ReadAmbChan(
+ spyd2 *p,
+ int chan, /* Ambient channel, 0 or 1 */
+ int *val /* Return the 16 bit channel value */
+) {
+ unsigned char pbuf[2]; /* Channel value read */
+ int _val;
+ int se;
+ int retr;
+ inst_code rv = inst_ok;
+
+ chan &= 1;
+
+ a1logd(p->log, 3, "spyd2_ReadAmbChan: channel %d\n",chan);
+
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xF0 + chan, 0, 0, pbuf, 2, 5.0);
+
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES) {
+ a1logd(p->log, 2, "spyd2_ReadAmbChan: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 2, "spyd2_ReadAmbChan: retry with ICOM err 0x%x\n",se);
+ }
+
+ _val = buf2ushort(pbuf);
+
+ a1logd(p->log, 3, "spyd2_ReadAmbChan: chan %d returning %d ICOM err 0x%x\n", chan, _val, se);
+
+ if (val != NULL) *val = _val;
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Spyder3/4: Read temperature config */
+static inst_code
+spyd2_ReadTempConfig(
+ spyd2 *p,
+ int *val /* Return the 8 bit config value */
+) {
+ unsigned char pbuf[1]; /* Config value read */
+ int _val;
+ int se;
+ int retr;
+ inst_code rv = inst_ok;
+
+ a1logd(p->log, 3, "spyd2_ReadTempConfig: called\n");
+
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xE1, 0, 0, pbuf, 1, 5.0);
+
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES) {
+ a1logd(p->log, 1, "spyd2_ReadTempConfig: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_ReadTempConfig: retry with ICOM err 0x%x\n",se);
+ }
+
+ _val = pbuf[0];
+
+ a1logd(p->log, 3, "spyd2_ReadTempConfig: returning %d ICOM err 0x%x\n", _val, se);
+
+ if (val != NULL) *val = _val;
+
+ return rv;
+}
+
+/* Spyder 3/4: Write Register */
+static inst_code
+spyd2_WriteReg(
+ spyd2 *p,
+ int reg,
+ int val /* 8 bit temp config register value */
+) {
+ int se;
+ inst_code rv = inst_ok;
+ int value;
+ int retr;
+
+ a1logd(p->log, 3, "spyd2_WriteReg: val %d to register %d\n",reg, val);
+
+ if (val < 0)
+ val = 0;
+ else if (val > 255)
+ val = 255;
+ value = val; /* Leave little endian */
+
+ reg &= 0xff;
+ value |= (reg << 8);
+
+ for (retr = 0; ; retr++) {
+ /* Issue the trigger command */
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_OUT | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xE2, value, 0, NULL, 0, 5.0);
+
+ if (se == ICOM_OK) {
+ a1logd(p->log, 5, "spyd2_WriteReg: OK, ICOM code 0x%x\n",se);
+ break;
+ }
+ if (retr >= RETRIES) {
+ a1logd(p->log, 5, "spyd2_WriteReg: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 5, "spyd2_WriteReg: retry with ICOM err 0x%x\n",se);
+ }
+
+ return rv;
+}
+
+
+/* Spyder3/4: Read Register */
+static inst_code
+spyd2_ReadRegister(
+ spyd2 *p,
+ int reg,
+ int *pval /* Return the register value */
+) {
+ unsigned char pbuf[2]; /* Temp value read */
+ int ival;
+// double _val;
+ int se;
+ int retr;
+ inst_code rv = inst_ok;
+
+ reg &= 0xff;
+
+ a1logd(p->log, 3, "spyd2_ReadRegister: register %d\n",reg);
+
+ for (retr = 0; ; retr++) {
+ se = p->icom->usb_control(p->icom,
+ IUSB_ENDPOINT_IN | IUSB_REQ_TYPE_VENDOR | IUSB_REQ_RECIP_DEVICE,
+ 0xE0, reg, 0, pbuf, 2, 5.0);
+
+ if (se == ICOM_OK)
+ break;
+ if (retr >= RETRIES) {
+ a1logd(p->log, 1, "spyd2_ReadRegister: failed with ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+ msec_sleep(500);
+ a1logd(p->log, 1, "spyd2_ReadRegister: retry with ICOM err 0x%x\n",se);
+ }
+
+ ival = buf2ushort(&pbuf[0]);
+// _val = (double)ival * 12.5; /* Read temperature */
+
+ a1logd(p->log, 1, "spyd2_ReadRegister: reg %d returning %d ICOM err 0x%x\n", ival, rv, se);
+
+ if (pval != NULL) *pval = ival;
+
+ return rv;
+}
+
+
+/* hwver == 5, set gain */
+/* Valid gain values 1, 4, 16, 64 */
+static inst_code
+spyd2_SetGain(
+ spyd2 *p,
+ int gain
+) {
+ int gv = 0;
+
+ p->gain = (double)gain;
+
+ switch (gain) {
+ case 1:
+ gv = 0;
+ break;
+ case 4:
+ gv = 16;
+ break;
+ case 16:
+ gv = 32;
+ break;
+ case 64:
+ gv = 48;
+ break;
+ }
+ return spyd2_WriteReg(p, 7, gv);
+}
+
+/* ============================================================ */
+/* Medium level commands */
+
+/* Read a 8 bits from the EEProm */
+static inst_code
+spyd2_rd_ee_uchar(
+ spyd2 *p, /* Object */
+ unsigned int *outp, /* Where to write value */
+ int addr /* EEprom Address, 0 - 510 */
+) {
+ inst_code ev;
+ unsigned char buf[1];
+
+ if ((ev = spyd2_readEEProm(p, buf, addr, 1)) != inst_ok)
+ return ev;
+
+ *outp = buf[0];
+
+ return inst_ok;
+}
+
+/* Read a 16 bit word from the EEProm */
+static inst_code
+spyd2_rd_ee_ushort(
+ spyd2 *p, /* Object */
+ unsigned int *outp, /* Where to write value */
+ int addr /* EEprom Address, 0 - 510 */
+) {
+ inst_code ev;
+ unsigned char buf[2];
+
+ if ((ev = spyd2_readEEProm(p, buf, addr, 2)) != inst_ok)
+ return ev;
+
+ *outp = buf2ushort(buf);
+
+ return inst_ok;
+}
+
+/* Read a 32 bit word from the EEProm */
+static inst_code
+spyd2_rd_ee_int(
+ spyd2 *p, /* Object */
+ int *outp, /* Where to write value */
+ int addr /* EEprom Address, 0 - 508 */
+) {
+ inst_code ev;
+ unsigned char buf[4];
+
+ if ((ev = spyd2_readEEProm(p, buf, addr, 4)) != inst_ok)
+ return ev;
+
+ *outp = buf2int(buf);
+
+ return inst_ok;
+}
+
+/* Read a float from the EEProm */
+static inst_code
+spyd2_rdreg_float(
+ spyd2 *p, /* Object */
+ double *outp, /* Where to write value */
+ int addr /* Register Address, 0 - 508 */
+) {
+ inst_code ev;
+ int val;
+
+ if ((ev = spyd2_rd_ee_int(p, &val, addr)) != inst_ok)
+ return ev;
+
+ *outp = IEEE754todouble((unsigned int)val);
+ return inst_ok;
+}
+
+unsigned int spyd4_crctab[256];
+
+static void spyd4_crc32_init(void) {
+ int i, j;
+
+ unsigned int crc;
+
+ for (i = 0; i < 256; i++) {
+ crc = i;
+ for (j = 0; j < 8; j++) {
+ if (crc & 1)
+ crc = (crc >> 1) ^ 0xedb88320;
+ else
+ crc = crc >> 1;
+ }
+ spyd4_crctab[i] = crc;
+// a1logd(p->log, 1, "spyd4_crc32_init: crctab[%d] = 0x%08x\n",i,crctab[i]);
+ }
+}
+
+static unsigned int spyd4_crc32(unsigned char *data, int len) {
+ unsigned int crc;
+ int i;
+
+ crc = ~0;
+ for (i = 0; i < len; i++)
+ crc = spyd4_crctab[(crc ^ *data++) & 0xff] ^ (crc >> 8);
+ return ~crc;
+}
+
+/* For HWV 7, check the EEPRom CRC */
+static inst_code
+spyd2_checkEECRC(
+ spyd2 *p /* Object */
+) {
+ inst_code ev;
+ unsigned char buf[1024], *bp;
+ unsigned int crct, crc; /* Target value, computed value */
+ int i;
+
+ spyd4_crc32_init();
+
+ if ((ev = spyd2_readEEProm(p, buf, 0, 1024)) != inst_ok)
+ return ev;
+
+ /* Target value */
+ crct = buf2uint(buf + 1024 - 4);
+
+ bp = buf;
+ crc = ~0;
+ for (i = 0; i < (1024 - 4); i++, bp++)
+ crc = spyd4_crctab[(crc ^ *bp) & 0xff] ^ (crc >> 8);
+ crc = ~crc;
+
+ a1logd(p->log, 4, "spyd2_checkEECRC: EEProm CRC is 0x%x, should be 0x%x\n",crc,crct);
+
+ if (crc != crct)
+ return spyd2_interp_code((inst *)p, SPYD2_BAD_EE_CRC);
+
+ return inst_ok;
+}
+
+/* Special purpose float read, */
+/* Read three 9 vectors of floats from the EEprom */
+static inst_code
+spyd2_rdreg_3x9xfloat(
+ spyd2 *p, /* Object */
+ double *out0, /* Where to write first 9 doubles */
+ double *out1, /* Where to write second 9 doubles */
+ double *out2, /* Where to write third 9 doubles */
+ int addr /* Register Address, 0 - 1023 */
+) {
+ inst_code ev;
+ unsigned char buf[3 * 9 * 4], *bp;
+ int i;
+
+ if ((ev = spyd2_readEEProm(p, buf, addr, 3 * 9 * 4)) != inst_ok)
+ return ev;
+
+ bp = buf;
+ for (i = 0; i < 9; i++, bp +=4, out0++) {
+ int val;
+ val = buf2int(bp);
+ *out0 = IEEE754todouble((unsigned int)val);
+ }
+
+ for (i = 0; i < 9; i++, bp +=4, out1++) {
+ int val;
+ val = buf2int(bp);
+ *out1 = IEEE754todouble((unsigned int)val);
+ }
+
+ for (i = 0; i < 9; i++, bp +=4, out2++) {
+ int val;
+ val = buf2int(bp);
+ *out2 = IEEE754todouble((unsigned int)val);
+ }
+
+ return inst_ok;
+}
+
+/* Special purpose short read, */
+/* Read 7 x 41 vectors of ints from the EEprom */
+static inst_code
+spyd2_rdreg_7x41xshort(
+ spyd2 *p, /* Object */
+ double sens[7][41], /* Destination */
+ int addr /* Register Address, 0 - 1023 */
+) {
+ inst_code ev;
+ unsigned char buf[7 * 41 * 2], *bp;
+ int i, j;
+
+ if ((ev = spyd2_readEEProm(p, buf, addr, 7 * 41 * 2)) != inst_ok)
+ return ev;
+
+ bp = buf;
+ for (i = 0; i < 7; i++) {
+ for (j = 0; j < 41; j++, bp += 2) {
+ int val;
+ val = buf2ushort(bp);
+ sens[i][j] = val / 100.0;
+ }
+ }
+
+ return inst_ok;
+}
+
+/* Get refresh rate command. Set it to DEFRRATE if not detectable */
+/* if no refresh rate can be established */
+/* (This isn't used by the manufacturers Spyder3/4 driver, */
+/* but the instrument seems to impliment it.) */
+static inst_code
+spyd2_read_refrate(
+ inst *pp,
+ double *ref_rate
+) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_code ev;
+ int clocks; /* Clocks to run commands */
+ int min, max; /* min and max light intensity frequency periods */
+
+ a1logd(p->log, 3, "spyd2_read_refrate: called\n");
+
+ /* Establish the frame rate detect threshold level */
+ clocks = (10 * CLKRATE)/DEFRRATE;
+
+ if ((ev = spyd2_GetMinMax(p, &clocks, &min, &max)) != inst_ok)
+ return ev;
+
+ if (min == 0 || max < (5 * min)) {
+ a1logd(p->log, 3, "spyd2_read_refrate: no refresh rate detectable\n");
+ if (ref_rate != NULL)
+ *ref_rate = 0.0;
+ return inst_ok;
+ } else {
+ int frclocks; /* notional clocks per frame */
+ int nframes; /* Number of frames to count */
+ int thresh; /* Frame detection threshold */
+ int minfclks; /* Minimum number of clocks per frame */
+ int maxfclks; /* Maximum number of clocks per frame */
+ int clkcnt; /* Return number of clocks for nframes frames */
+
+ frclocks = CLKRATE/DEFRRATE;
+ nframes = 50;
+ thresh = (max - min)/5 + min; /* Threshold is at 80% of max brightness */
+ minfclks = frclocks/3; /* Allow for 180 Hz */
+ maxfclks = (frclocks * 5)/2; /* Allow for 24 Hz */
+ clocks = nframes * frclocks * 2; /* Allow for 120 Hz */
+
+ if ((ev = spyd2_GetRefRate_ll(p, &clocks, nframes, thresh, &minfclks, &maxfclks,
+ &clkcnt)) != inst_ok)
+ return ev;
+
+ /* Compute the refresh rate */
+ if (ref_rate != NULL)
+ *ref_rate = ((double)nframes * (double)CLKRATE)/(double)clkcnt;
+ return inst_ok;
+ }
+}
+
+/* Get refresh rate command. Set it to DEFRRATE if not detectable */
+/* if no refresh rate can be established */
+/* (This isn't used by the manufacturers Spyder3/4 driver, */
+/* but the instrument seems to impliment it.) */
+static inst_code
+spyd2_GetRefRate(
+ spyd2 *p
+) {
+ int i;
+ inst_code ev;
+
+ a1logd(p->log, 3, "Frequency calibration called\n");
+
+ if ((ev = spyd2_read_refrate((inst *)p, &p->refrate)) != inst_ok) {
+ return ev;
+ }
+ if (p->refrate != 0.0) {
+ a1logd(p->log, 3, "spyd2_GetRefRate: refresh rate is %f Hz\n",p->refrate);
+ p->refrvalid = 1;
+ } else {
+ a1logd(p->log, 3, "spyd2_GetRefRate: no refresh rate detectable\n");
+ p->refrate = DEFRRATE;
+ p->refrvalid = 0;
+ }
+ p->rrset = 1;
+
+ return inst_ok;
+}
+
+/* Do a reading. */
+/* Note that the Spyder 3 seems to give USB errors on the data */
+/* read if the measurement time is too small (ie. 0.2 seconds) */
+/* when reading dark values. */
+static inst_code
+spyd2_GetReading(
+ spyd2 *p,
+ double *XYZ /* return the XYZ values */
+) {
+ inst_code ev;
+ int clocks1, clocks2; /* Clocks to run commands */
+ int min, max; /* min and max light intensity frequency periods */
+ int frclocks; /* notional clocks per frame */
+ int nframes; /* Number of frames to measure over */
+ int thresh; /* Frame detection threshold */
+ int minfclks; /* Minimum number of clocks per frame */
+ int maxfclks; /* Maximum number of clocks per frame */
+ double sensv[8]; /* The 8 final sensor value readings */
+ int maxtcnt; /* The maximum transition count measured */
+ int mintcnt; /* The minumum transition count measured */
+ double a_sensv[8]; /* Accumulated sensor value readings */
+ double a_w[8]; /* Accumulated sensor value weight */
+ double pows[9]; /* Power combinations of initial XYZ */
+ int i, j, k;
+ double inttime = 0.0;
+
+ a1logd(p->log, 3, "spyd2_GetReading: called\n");
+
+ if (p->refrmode)
+ inttime = RINTTIME; /* ie. 1 second */
+ else
+ inttime = NINTTIME; /* ie. 1 second */
+
+ /* Compute number of frames for desired base read time */
+ nframes = (int)(inttime * p->refrate + 0.5);
+
+ /* Establish the frame rate detect threshold level */
+ /* (The Spyder 3 doesn't use this ?) */
+ clocks1 = (int)((nframes * CLKRATE)/(10 * p->refrate) + 0.5); /* Use 10% of measurement clocks */
+
+ if ((ev = spyd2_GetMinMax(p, &clocks1, &min, &max)) != inst_ok)
+ return ev;
+
+ /* Setup for measurement */
+ thresh = (max - min)/5 + min; /* Threshold is at 80% of max brightness */
+ if (thresh == 0)
+ thresh = 65535; /* Set to max, otherwise reading will be 0 */
+ frclocks = (int)(CLKRATE/p->refrate + 0.5); /* Nominal clocks per frame */
+ minfclks = frclocks/3; /* Allow for 180 Hz */
+ maxfclks = (frclocks * 5)/2; /* Allow for 24 Hz */
+
+ if (p->hwver < 7) {
+ /* Check calibration is valid */
+ if ((p->icx & 1) == 0 && (p->fbits & 1) == 0) {
+// return spyd2_interp_code((inst *)p, SPYD2_NOCRTCAL);
+ a1logd(p->log, 1, "spyd2_GetReading: instrument appears to have no CRT calibration "
+ "table! Proceeding anyway..\n");
+ }
+
+ if ((p->icx & 1) == 1 && (p->fbits & 2) == 0) {
+// return spyd2_interp_code((inst *)p, SPYD2_NOLCDCAL);
+ a1logd(p->log, 1, "spyd2_GetReading: instrument appears to have no LCD calibration "
+ "table! Proceeding anyway..\n");
+ }
+ }
+
+ a1logd(p->log, 3, "spyd2_GetReading: Using cal table %d\n",(p->icx & 1));
+ if (p->hwver)
+ a1logd(p->log, 3, "spyd2_GetReading: using spectral cal table %d\n",p->icx >> 1);
+
+ for (k = 0; k < 8; k++) /* Zero weighted average */
+ a_sensv[k] = a_w[k] = 0.0;
+
+ /* For initial and possible adaptive readings */
+ for (i = 0;; i++) {
+ double itime; /* Integration time */
+
+ clocks2 = (int)((double)nframes/p->refrate * (double)CLKRATE + 0.5);
+
+ if ((ev = spyd2_GetReading_ll(p, &clocks2, nframes, thresh, &minfclks, &maxfclks,
+ sensv, &maxtcnt, &mintcnt)) != inst_ok)
+ return ev;
+// a1logd(p->log, 3, "spyd2_GetReading: returned number of clocks = %d\n",clocks2);
+
+ if (p->log->debug >= 3) {
+ for (k = 0; k < 8; k++)
+ a1logd(p->log, 3, "Sensor %d value = %f\n",k,sensv[k]);
+ }
+
+ itime = (double)clocks2 / (double)CLKRATE;
+// a1logd(p->log, 3, "spyd2_GetReading: reading %d was %f secs\n",i,itime);
+
+ /* Accumulate it for weighted average */
+ for (k = 0; k < 8; k++) {
+ if (sensv[k] != 0.0) { /* Skip value where we didn't get any transitions */
+ a_sensv[k] += sensv[k] * itime;
+ a_w[k] += itime;
+ }
+ }
+
+#ifdef DO_ADAPTIVE
+ a1logd(p->log, 3, "spyd2_GetReading: Maxtcnt = %d, Mintcnt = %d\n",maxtcnt,mintcnt);
+ if (i > 0)
+ break; /* Done adaptive */
+
+ /* Decide whether to go around again */
+
+ if (maxtcnt <= (100/16)) {
+ nframes *= 16; /* Typically 16 seconds */
+ a1logd(p->log, 3, "spyd2_GetReading: using maximum integration time\n");
+ } else if (maxtcnt < 100) {
+ double mulf;
+ mulf = 100.0/maxtcnt;
+ mulf -= 0.8; /* Just want to accumulate up to target, not re-do it */
+ nframes = (int)(nframes * mulf + 0.5);
+ a1logd(p->log, 3, "spyd2_GetReading: increasing total integration time "
+ "by %.1f times\n",1+mulf);
+ } else {
+ break; /* No need for another reading */
+ }
+#else /* !DO_ADAPTIVE */
+ a1logw(p->log, "!!!! Spyder 2 DO_ADAPTIVE is off !!!!\n");
+ break;
+#endif /* !DO_ADAPTIVE */
+ }
+
+ /* Compute weighted average and guard against silliness */
+ for (k = 0; k < 8; k++) {
+ if (a_w[k] > 0.0) {
+ a_sensv[k] /= a_w[k];
+ }
+ }
+
+ if (p->hwver == 5) {
+ double gainscale = 1.0;
+ unsigned int v381;
+
+ if ((ev = spyd2_rd_ee_uchar(p, &v381, 381)) != inst_ok)
+ return ev;
+
+ gainscale = (double)v381/p->gain;
+ a1logd(p->log, 3, "spyd2_GetReading: hwver5 v381 = %d, gain = %f, gainscale = %f\n",
+ v381,p->gain,gainscale);
+ /* Convert sensor readings to XYZ value */
+ for (j = 0; j < 3; j++) {
+ XYZ[j] = p->cal_A[p->icx & 1][j][0]; /* First entry is a constant */
+ for (k = 1; k < 8; k++)
+ XYZ[j] += a_sensv[k] * p->cal_A[p->icx & 1][j][k+2] * gainscale;
+ }
+
+ } else {
+ /* Convert sensor readings to XYZ value */
+ for (j = 0; j < 3; j++) {
+ XYZ[j] = p->cal_A[p->icx & 1][j][0]; /* First entry is a constant */
+ for (k = 1; k < 8; k++)
+ XYZ[j] += a_sensv[k] * p->cal_A[p->icx & 1][j][k+1];
+ }
+ }
+
+// a1logd(p->log, 3, "spyd2_GetReading: real Y = %f\n",XYZ[1]);
+ a1logd(p->log, 3, "spyd2_GetReading: initial XYZ reading %f %f %f\n",XYZ[0], XYZ[1], XYZ[2]);
+
+#ifdef LEVEL2
+ /* Add "level 2" correction factors */
+ pows[0] = XYZ[0];
+ pows[1] = XYZ[1];
+ pows[2] = XYZ[2];
+ pows[3] = XYZ[0] * XYZ[1];
+ pows[4] = XYZ[0] * XYZ[2];
+ pows[5] = XYZ[1] * XYZ[2];
+ pows[6] = XYZ[0] * XYZ[0];
+ pows[7] = XYZ[1] * XYZ[1];
+ pows[8] = XYZ[2] * XYZ[2];
+
+
+ for (j = 0; j < 3; j++) {
+ XYZ[j] = 0.0;
+
+ for (k = 0; k < 9; k++) {
+ XYZ[j] += pows[k] * p->cal_B[p->icx & 1][j][k];
+ }
+ }
+ a1logd(p->log, 3, "spyd2_GetReading: 2nd level XYZ reading %f %f %f\n",XYZ[0], XYZ[1], XYZ[2]);
+#endif
+
+ /* Protect against silliness (This may stuff up averages though!) */
+ for (j = 0; j < 3; j++) {
+ if (XYZ[j] < 0.0)
+ XYZ[j] = 0.0;
+ }
+ a1logd(p->log, 3, "spyd2_GetReading: final XYZ reading %f %f %f\n",XYZ[0], XYZ[1], XYZ[2]);
+
+ return ev;
+}
+
+/* Spyder3/4: Do an ambient reading */
+
+/* NOTE :- the ambient sensor is something like a TAOS TLS 2562CS. */
+/* It has two sensors, one wide band and the other infra-red, */
+/* the idea being to subtract them to get a rough human response. */
+/* The reading is 16 bits, and the 8 bit conrol register */
+/* controls gain and integration time: */
+
+/* Bits 0,1 inttime, 0 = scale 0.034, 1 = scale 0.252. 2 = scale 1, 3 = manual */
+/* Bit 2, manual, 0 = stop int, 1 = start int */
+/* Bit 4, gain, 0 = gain 1, 1 = gain 16 */
+
+
+static inst_code
+spyd2_GetAmbientReading(
+ spyd2 *p,
+ double *XYZ /* return the ambient XYZ values */
+) {
+ inst_code ev = inst_ok;
+ int tconf; /* Ambient timing config */
+ int iamb0, iamb1;
+ double amb0, amb1; /* The two ambient values */
+ double trv; /* Trial value */
+ double thr[8] = { 64/512.0, 128/512.0, 192/512.0, 256/512.0, /* Magic tables */
+ 312/512.0, 410/512.0, 666/512.0, 0 };
+ double s0[8] = { 498/128.0, 532/128.0, 575/128.0, 624/128.0,
+ 367/128.0, 210/128.0, 24/128.0, 0 };
+ double s1[8] = { 446/128.0, 721/128.0, 891/128.0, 1022/128.0,
+ 508/128.0, 251/128.0, 18/128.0, 0 };
+ double amb; /* Combined ambient value */
+ double sfact;
+ int i;
+
+ a1logd(p->log, 3, "spyd2_GetAmbientReading: called\n");
+
+ /* Set the ambient control register to 3 */
+ if ((ev = spyd2_SetAmbReg(p, 3)) != inst_ok)
+ return ev;
+
+ /* Wait one second */
+ msec_sleep(1000);
+
+ /* Read the ambient timing config value */
+ if ((ev = spyd2_ReadAmbTiming(p, &tconf)) != inst_ok)
+ return ev;
+// a1logd(p->log, 4, "spyd2_GetAmbientReading: timing = %d\n",tconf);
+
+ /* Read the ambient values */
+ if ((ev = spyd2_ReadAmbChan(p, 0, &iamb0)) != inst_ok)
+ return ev;
+ if ((ev = spyd2_ReadAmbChan(p, 1, &iamb1)) != inst_ok)
+ return ev;
+
+// a1logd(p->log, 4, "spyd2_GetAmbientReading: values = %d, %d\n",iamb0,iamb1);
+ amb0 = iamb0/128.0;
+ amb1 = iamb1/128.0;
+
+ /* Set the ambient control register to 0 */
+ if ((ev = spyd2_SetAmbReg(p, 0)) != inst_ok)
+ return ev;
+
+ /* Compute the scale factor from the timing config value */
+ if ((tconf & 3) == 0)
+ sfact = 1.0/0.034;
+ else if ((tconf & 3) == 1)
+ sfact = 1.0/0.252;
+ else
+ sfact = 1.0;
+
+ if ((tconf & 0x10) == 0)
+ sfact *= 16.0;
+
+ amb0 *= sfact;
+ amb1 *= sfact;
+
+ if (amb0 > 0.0)
+ trv = amb1/amb0;
+ else
+ trv = 0.0;
+
+ for (i = 0; i < 7; i++) {
+ if (trv <= thr[i])
+ break;
+ }
+// a1logd(p->log, 4, "spyd2_GetAmbientReading: trv = %f, s0 = %f, s1 = %f\n",trv, s0[i],s1[i]);
+ /* Compute ambient in Lux */
+ amb = s0[i] * amb0 - s1[i] * amb1;
+
+// a1logd(p->log, 4, "spyd2_GetAmbientReading: combined ambient = %f Lux\n",amb);
+ /* Compute the Y value */
+
+ XYZ[1] = amb; /* cd/m^2 ??? - not very accurate, due to */
+ /* spectral response and/or integration angle. */
+ XYZ[0] = icmD50.X * XYZ[1]; /* Convert to D50 neutral */
+ XYZ[2] = icmD50.Z * XYZ[1];
+
+ a1logd(p->log, 3, "spyd2_GetAmbientReading: returning %f %f %f\n",XYZ[0],XYZ[1],XYZ[2]);
+
+ return ev;
+}
+
+/* ------------------------------------------------------------ */
+/* Spyder 4 manufacturer calibration data */
+int spyd4_nocals = 0; /* Number of calibrations */
+xspect *spyd4_cals = NULL; /* [nocals] Device spectrum */
+
+/* ------------------------------------------------------------ */
+/* Spyder4: Create a calibration matrix using the manufacturers */
+/* calibration data. */
+
+static inst_code
+spyd4_set_cal(
+ spyd2 *p, /* Object */
+ int ix /* Selection, 0 .. spyd4_nocals-1 */
+) {
+ int i, j, k;
+ xspect *oc[3]; /* The XYZ observer curves */
+
+ if (ix < 0 || ix >= spyd4_nocals) {
+ return spyd2_interp_code((inst *)p, SPYD2_DISP_SEL_RANGE) ;
+ }
+
+ /* The Manufacturers calibration routine computes a least squares */
+ /* spectral fit of the sensor spectral sensitivities to the */
+ /* standard observer curves, weighted by the white illuminant */
+ /* of the display technology. We use the same approach for the */
+ /* default calibration selections, to be faithful to the Manufacturers */
+ /* intentions. */
+
+ if (standardObserver(oc, icxOT_CIE_1931_2)) {
+ return spyd2_interp_code((inst *)p, SPYD2_DISP_SEL_RANGE) ;
+ }
+
+ /* We compute X,Y & Z independently. */
+ for (k = 0; k < 3; k++) {
+ double target[81]; /* Spectral target @ 5nm spacing */
+ double **wsens; /* Weighted sensor sensitivities */
+ double **psisens; /* Pseudo inverse of sensitivies */
+
+ /* Load up the observer curve and weight it by the display spectrum */
+ /* and mW Lumoinance efficiency factor. */
+ for (i = 0; i < 81; i++) {
+ double nm = 380.0 + i * 5.0;
+ target[i] = value_xspect(&spyd4_cals[ix], nm) * value_xspect(oc[k], nm) * 0.683002;
+ }
+
+ /* Load up the sensor curves and weight by the display spectrum */
+ wsens = dmatrix(0, 6, 0, 80);
+ psisens = dmatrix(0, 80, 0, 6);
+ for (j = 0; j < 7; j++) {
+ for (i = 0; i < 81; i++) {
+ double nm = 380.0 + i * 5.0;
+ wsens[j][i] = value_xspect(&spyd4_cals[ix], nm) * value_xspect(&p->sens[j], nm);
+ }
+ }
+
+ /* Compute the pseudo-inverse matrix */
+ if (lu_psinvert(psisens, wsens, 7, 81) != 0) {
+ free_dmatrix(wsens, 0, 6, 0, 80);
+ free_dmatrix(psisens, 0, 80, 0, 6);
+ return spyd2_interp_code((inst *)p, SPYD2_CAL_FAIL) ;
+ }
+
+ {
+ double *cc, *tt;
+ p->cal_A[1][k][0] = 0.0; /* Offset is zero */
+ p->cal_A[1][k][1] = 0.0; /* Unused is zero */
+ cc = &p->cal_A[1][k][2]; /* 7 cal values go here */
+ tt = target;
+
+ /* Multiply inverse by target to get calibration matrix */
+ if (matrix_mult(&cc, 1, 7, &tt, 1, 81, psisens, 81, 7))
+ return spyd2_interp_code((inst *)p, SPYD2_CAL_FAIL) ;
+ }
+// a1logd(p->log, 3, "Cal %d = %f %f %f %f %f %f %f\n", k, p->cal_A[1][k][2], p->cal_A[1][k][3], p->cal_A[1][k][4], p->cal_A[1][k][5], p->cal_A[1][k][6], p->cal_A[1][k][7], p->cal_A[1][k][8]);
+ }
+
+#ifdef PLOT_SPECTRA
+ /* Plot the calibrated sensor spectra */
+ {
+ int i, j, k;
+ double xx[81];
+ double yy[10][81], *yp[10];
+
+ for (i = 0; i < 81; i++)
+ xx[i] = 380.0 + i * 5.0;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 81; i++) {
+ yy[j][i] = 0.0;
+ for (k = 0; k < 7; k++) {
+ yy[j][i] += p->cal_A[1][j][k+2] * value_xspect(&p->sens[k], xx[i]);
+ }
+ }
+ yp[j] = yy[j];
+ }
+ for (; j < 10; j++)
+ yp[j] = NULL;
+
+ printf("The calibrated sensor sensitivities\n");
+ do_plot10(xx, yp[0], yp[1], yp[2], yp[3], yp[4], yp[5], yp[6], yp[7], yp[8], yp[9], 81, 0);
+ }
+#endif /* PLOT_SPECTRA */
+
+#ifdef SAVE_XYZSPECTRA /* Save the default XYZ senitivity spectra to "sensorsxyz.sp" */
+ {
+ int i, j, k;
+ xspect xyz[3];
+ double wl;
+
+ for (j = 0; j < 3; j++) {
+ xyz[j].spec_n = 81;
+ xyz[j].spec_wl_short = 380;
+ xyz[j].spec_wl_long = 780;
+ xyz[j].norm = 1.0;
+ for (i = 0; i < 81; i++) {
+ wl = 380.0 + i * 5.0;
+ xyz[j].spec[i] = 0.0;
+ for (k = 0; k < 7; k++)
+ xyz[j].spec[i] += p->cal_A[1][j][k+2] * value_xspect(&p->sens[k], wl);
+ xyz[j].spec[i] *= 1.4; /* Align with std XYZ */
+ }
+ }
+ write_nxspect("sensorsxyz.sp", xyz, 3, 0);
+ }
+#endif
+#ifdef SAVE_STDXYZ
+ {
+ xspect xyz[3];
+ standardObserver(&xyz[0], &xyz[1], &xyz[2],icxOT_CIE_1931_2);
+ write_nxspect("stdobsxyz.sp", xyz, 3, 0);
+ }
+#endif /* SAVE_STDXYZ */
+
+ return inst_ok;
+}
+
+
+/* The CCSS calibration uses a set of spectral samples, */
+/* and a least squares matrix is computed to map the sensor RGB */
+/* to the computed XYZ values. This allows better accuracy for */
+/* a typical display that has only 3 degrees of freedom, and */
+/* allows weigting towards a distribution of actual spectral samples. */
+/* Because the typical display has only three degrees of freedom, */
+/* while the instrument has 7 sensors, some extra dummy spectral */
+/* samples are added to the list to provide some slight extra goal. */
+
+/* [ Given the poor curve shapes that can come out of this, it's not */
+/* clear that it wouldn't be better using the default flat-spetrum */
+/* calibration and computing a 3x3 calibration matrix over the top of it. ] */
+static inst_code
+spyd4_comp_calmat(
+ spyd2 *p,
+ icxObserverType obType, /* XYZ Observer type */
+ xspect custObserver[3], /* Optional custom observer */ \
+ xspect *samples, /* Array of nsamp spectral samples */
+ int nsamp /* Number of real samples */
+) {
+ int i, j;
+ int nasamp = nsamp + 81; /* Number of real + augmented samples */
+ double exwt = 1.0; /* Extra spectral point weight */
+ double **sampXYZ; /* Sample XYZ values */
+ double **sampSENS; /* Sample Sensor values */
+ double **isampSENS; /* Pseudo-inverse of sensor values */
+ double **calm; /* Calibration matrix */
+ xsp2cie *conv;
+ double wl;
+ xspect white;
+
+ if (nsamp < 3)
+ return spyd2_interp_code((inst *)p, SPYD2_TOO_FEW_CALIBSAMP);
+
+ /* Create white spectrum samples */
+ XSPECT_COPY_INFO(&white, &samples[0]);
+ for (j = 0; j < white.spec_n; j++)
+ white.spec[j] = 0.0;
+ for (i = 0; i < nsamp; i++) {
+ for (j = 0; j < white.spec_n; j++)
+ if (samples[i].spec[j] > white.spec[j])
+ white.spec[j] = samples[i].spec[j];
+ }
+
+ /* Compute XYZ of the real sample array. */
+ if ((conv = new_xsp2cie(icxIT_none, NULL, obType, custObserver, icSigXYZData, icxClamp)) == NULL)
+ return spyd2_interp_code((inst *)p, SPYD2_INT_CIECONVFAIL);
+ sampXYZ = dmatrix(0, nasamp-1, 0, 3-1);
+ for (i = 0; i < nsamp; i++) {
+ conv->convert(conv, sampXYZ[i], &samples[i]);
+// a1logd(p->log, 3, "asamp[%d] XYZ = %f %f %f\n", i,sampXYZ[nsamp+i][0],sampXYZ[nsamp+i][1], sampXYZ[nsamp+i][2]);
+ }
+
+ /* Create extra spectral samples */
+ for (i = 0; i < 81; i++) {
+ for (j = 0; j < 3; j++) {
+ wl = 380.0 + i * 5;
+ sampXYZ[nsamp+i][j] = exwt * value_xspect(&white, wl)
+ * value_xspect(&conv->observer[j], wl) * 0.683002;
+ }
+// a1logd(p->log, 3, "asamp[%d] XYZ = %f %f %f\n", i,sampXYZ[nsamp+i][0],sampXYZ[nsamp+i][1], sampXYZ[nsamp+i][2]);
+ }
+ conv->del(conv);
+
+ sampSENS = dmatrix(0, nasamp-1, 0, 7-1);
+
+ /* Compute sensor values of the sample array */
+ for (i = 0; i < nsamp; i++) {
+ for (j = 0; j < 7; j++) {
+ sampSENS[i][j] = 0.0;
+ for (wl = p->sens[0].spec_wl_short; wl <= p->sens[0].spec_wl_long; wl += 1.0) {
+ sampSENS[i][j] += value_xspect(&samples[i], wl) * value_xspect(&p->sens[j], wl);
+ }
+ }
+ }
+ /* Create sensor values of the extra sample array */
+ for (i = 0; i < 81; i++) {
+ for (j = 0; j < 7; j++) {
+ wl = 380.0 + i * 5;
+ sampSENS[nsamp+i][j] = exwt * value_xspect(&white, wl) * value_xspect(&p->sens[j], wl);
+ }
+// a1logd(p->log, 3, "asamp[%d] Sens = %f %f %f %f %f %f %f\n", i,
+// sampSENS[nsamp+i][0],sampSENS[nsamp+i][1], sampSENS[nsamp+i][2],
+// sampSENS[nsamp+i][3],sampSENS[nsamp+i][4], sampSENS[nsamp+i][5],
+// sampSENS[nsamp+i][6]);
+ }
+#if defined(PLOT_SPECTRA_EXTRA)
+ /* Plot the target extra values */
+ {
+ int i, j, k;
+ double xx[81];
+ double yy[10][81], *yp[10];
+
+ for (i = 0; i < 81; i++)
+ xx[i] = 380.0 + i * 5;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 81; i++) {
+ yy[j][i] = sampXYZ[nsamp+i][j];
+ }
+ yp[j] = yy[j];
+ }
+ for (; j < 10; j++)
+ yp[j] = NULL;
+
+ printf("The target extra XYZ values\n");
+ do_plot10(xx, yp[0], yp[1], yp[2], yp[3], yp[4], yp[5], yp[6], yp[7], yp[8], yp[9], 81, 0);
+
+ for (j = 0; j < 7; j++) {
+ for (i = 0; i < 81; i++) {
+ yy[j][i] = sampSENS[nsamp+i][j];
+ }
+ yp[j] = yy[j];
+ }
+ for (; j < 10; j++)
+ yp[j] = NULL;
+
+ printf("The given extra sensor values\n");
+ do_plot10(xx, yp[0], yp[1], yp[2], yp[3], yp[4], yp[5], yp[6], yp[7], yp[8], yp[9], 81, 0);
+ }
+#endif /* PLOT_SPECTRA_EXTRA */
+
+
+ isampSENS = dmatrix(0, 7-1, 0, nasamp-1);
+
+ /* Compute the pseudo inverse of sampSENS */
+ if (lu_psinvert(isampSENS, sampSENS, nasamp, 7) != 0) {
+ free_dmatrix(sampXYZ, 0, nasamp-1, 0, 3-1);
+ free_dmatrix(sampSENS, 0, nasamp-1, 0, 7-1);
+ free_dmatrix(isampSENS, 0, 7-1, 0, nasamp-1);
+ return spyd2_interp_code((inst *)p, SPYD2_CAL_FAIL) ;
+ }
+
+ calm = dmatrix(0, 7-1, 0, 3-1);
+
+ /* Multiply inverse by target to get calibration matrix */
+ if (matrix_mult(calm, 7, 3, isampSENS, 7, nasamp, sampXYZ, nasamp, 3)) {
+ free_dmatrix(sampXYZ, 0, nasamp-1, 0, 3-1);
+ free_dmatrix(sampSENS, 0, nasamp-1, 0, 7-1);
+ free_dmatrix(isampSENS, 0, 7-1, 0, nasamp-1);
+ free_dmatrix(calm, 0, 7-1, 0, 3-1);
+ return spyd2_interp_code((inst *)p, SPYD2_CAL_FAIL);
+ }
+
+ /* Copy the matrix into place */
+ for (i = 0; i < 7; i++) {
+ for (j = 0; j < 3; j++) {
+//calm[i][j] = 0.5;
+ p->cal_A[1][j][2+i] = calm[i][j];
+ }
+ }
+
+ free_dmatrix(calm, 0, 7-1, 0, 3-1);
+
+#ifdef NEVER
+
+ /* Compute the residuals */
+ {
+ double **refXYZ;
+ double t1, t2;
+
+ refXYZ = dmatrix(0, nasamp-1, 0, 3-1);
+
+ if (matrix_mult(refXYZ, nasamp, 3, sampSENS, nasamp, 7, calm, 7, 3)) {
+ printf("Residual matrix mult failed\n");
+ } else {
+ t1 = 0.0;
+ for (i = 0; i < nsamp; i++) {
+ t1 += icmLabDE(refXYZ[i],sampXYZ[i]);
+ }
+ t1 /= nsamp;
+ printf("Average error for sample points = %f\n",t1);
+ t2 = 0.0;
+ for (i = nsamp; i < (nsamp + 81); i++) {
+ t2 += icmLabDE(refXYZ[i],sampXYZ[i]);
+// printf("Resid %d error = %f, %f %f %f, %f %f %f\n",
+// i, icmLabDE(refXYZ[i],sampXYZ[i]), sampXYZ[i][0], sampXYZ[i][1],
+// sampXYZ[i][2], refXYZ[i][0], refXYZ[i][1], refXYZ[i][2]);
+ }
+ t2 /= 81;
+ printf("Average error for extra points = %f\n",t2);
+ }
+ }
+#endif
+
+#ifdef PLOT_SPECTRA
+ /* Plot the calibrated sensor spectra */
+ {
+ int i, j, k;
+ double xx[81];
+ double yy[10][81], *yp[10];
+
+ for (i = 0; i < 81; i++)
+ xx[i] = 380.0 + i * 5.0;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 81; i++) {
+ yy[j][i] = 0.0;
+ for (k = 0; k < 7; k++) {
+ yy[j][i] += p->cal_A[1][j][k+2] * value_xspect(&p->sens[k], xx[i]);
+ }
+ }
+ yp[j] = yy[j];
+ }
+ for (; j < 10; j++)
+ yp[j] = NULL;
+
+ printf("The calibrated sensor sensitivities\n");
+ do_plot10(xx, yp[0], yp[1], yp[2], yp[3], yp[4], yp[5], yp[6], yp[7], yp[8], yp[9], 81, 0);
+ }
+#endif /* PLOT_SPECTRA */
+
+ free_dmatrix(sampXYZ, 0, nasamp-1, 0, 3-1);
+ free_dmatrix(sampSENS, 0, nasamp-1, 0, 7-1);
+ free_dmatrix(isampSENS, 0, 7-1, 0, nasamp-1);
+
+ return inst_ok;
+}
+
+
+/* ------------------------------------------------------------ */
+
+/* Read all the relevant register values */
+static inst_code
+spyd2_read_all_regs(
+ spyd2 *p /* Object */
+) {
+ inst_code ev;
+
+ a1logd(p->log, 3, "spyd2_read_all_regs: about to read all the EEProm values\n");
+
+ /* HW version */
+ if ((ev = spyd2_rd_ee_uchar(p, &p->hwver, 5)) != inst_ok)
+ return ev;
+
+ /* Feature bits */
+ if ((ev = spyd2_rd_ee_uchar(p, &p->fbits, 6)) != inst_ok)
+ return ev;
+
+ a1logd(p->log, 3, "spyd2_read_all_regs: hwver = 0x%02x%02x\n",p->hwver,p->fbits);
+
+ /* Check the EEProm checksum */
+ if (p->hwver == 7) {
+ if ((ev = spyd2_checkEECRC(p)) != inst_ok)
+ return ev;
+ }
+
+ /* Serial number */
+ if ((ev = spyd2_readEEProm(p, (unsigned char *)p->serno, 8, 8)) != inst_ok)
+ return ev;
+ p->serno[8] = '\000';
+ a1logd(p->log, 3, "spyd2_read_all_regs: serno = '%s'\n",p->serno);
+
+ if (p->hwver < 7) {
+
+ /* Hmm. We deliberately ignore the fbits 0, 1 & 2 here, in case they are faulty */
+ /* (Not sure if we should look at fbits 1 or not) */
+
+ /* Spyde2: CRT calibration values */
+ /* Spyde3: Unknown calibration values */
+ if ((ev = spyd2_rdreg_3x9xfloat(p, p->cal_A[0][0], p->cal_A[0][1], p->cal_A[0][2], 16))
+ != inst_ok)
+ return ev;
+ if ((ev = spyd2_rdreg_3x9xfloat(p, p->cal_B[0][0], p->cal_B[0][1], p->cal_B[0][2], 128))
+ != inst_ok)
+ return ev;
+
+
+ /* Hmm. The 0 table seems to sometimes be scaled. Is this a bug ? */
+ /* (might be gain factor ?) */
+ /* The spyder 3/4 doesn't use this anyway. */
+ if (p->hwver >= 4) {
+ int j, k, i;
+ double avgmag = 0.0;
+
+ for (i = j = 0; j < 3; j++) {
+ for (k = 0; k < 9; k++) {
+ if (p->cal_A[0][j][k] != 0.0) {
+ avgmag += fabs(p->cal_A[0][j][k]);
+ i++;
+ }
+ }
+ }
+ avgmag /= (double)(i);
+ a1logd(p->log, 4, "spyd2_read_all_regs: Cal_A avgmag = %f\n",avgmag);
+
+ if (avgmag < 0.05) {
+ a1logd(p->log, 5, "spyd2_read_all_regs: Scaling Cal_A by 16\n");
+ for (j = 0; j < 3; j++) {
+ for (k = 0; k < 9; k++) {
+ p->cal_A[0][j][k] *= 16.0;
+ }
+ }
+ }
+ }
+
+ /* Spyder2: LCD calibration values */
+ /* Spyder3: Normal CRT/LCD calibration values */
+ if ((ev = spyd2_rdreg_3x9xfloat(p, p->cal_A[1][0], p->cal_A[1][1], p->cal_A[1][2], 256))
+ != inst_ok)
+ return ev;
+ if ((ev = spyd2_rdreg_3x9xfloat(p, p->cal_B[1][0], p->cal_B[1][1], p->cal_B[1][2], 384))
+ != inst_ok)
+ return ev;
+
+ /* The monochrome "TOKIOBLUE" calibration */
+ /* (Not sure if this is fbits 2 and 4 or not) */
+
+ /* Luminence only calibration values ??? */
+ if ((ev = spyd2_rdreg_float(p, &p->cal_F[0], 240)) != inst_ok)
+ return ev;
+ if ((ev = spyd2_rdreg_float(p, &p->cal_F[1], 244)) != inst_ok)
+ return ev;
+ if ((ev = spyd2_rdreg_float(p, &p->cal_F[2], 248)) != inst_ok)
+ return ev;
+ if ((ev = spyd2_rdreg_float(p, &p->cal_F[3], 252)) != inst_ok)
+ return ev;
+ if ((ev = spyd2_rdreg_float(p, &p->cal_F[4], 364)) != inst_ok)
+ return ev;
+ if ((ev = spyd2_rdreg_float(p, &p->cal_F[5], 368)) != inst_ok)
+ return ev;
+ if ((ev = spyd2_rdreg_float(p, &p->cal_F[6], 372)) != inst_ok)
+ return ev;
+
+ if (p->log->debug >= 4) {
+ int i, j, k;
+
+ a1logd(p->log, 4, "Cal_A:\n");
+ for (i = 0; i < 2;i++) {
+ for (j = 0; j < 3; j++) {
+ for (k = 0; k < 9; k++) {
+ a1logd(p->log, 4, "Cal_A [%d][%d][%d] = %f\n",i,j,k,p->cal_A[i][j][k]);
+ }
+ }
+ }
+ a1logd(p->log, 4, "\nCal_B:\n");
+ for (i = 0; i < 2;i++) {
+ for (j = 0; j < 3; j++) {
+ for (k = 0; k < 9; k++) {
+ a1logd(p->log, 4, "Cal_B [%d][%d][%d] = %f\n",i,j,k,p->cal_B[i][j][k]);
+ }
+ }
+ }
+ a1logd(p->log, 4, "\nCal_F:\n");
+ for (i = 0; i < 7;i++) {
+ a1logd(p->log, 4, "Cal_F [%d] = %f\n",i,p->cal_F[i]);
+ }
+ a1logd(p->log, 4, "\n");
+ }
+
+ } else if (p->hwver == 7) {
+ int i, j;
+ unsigned int sscal;
+ double tsens[7][41];
+
+ /* Read sensor sensitivity spectral data */
+ if ((ev = spyd2_rdreg_7x41xshort(p, tsens, 170)) != inst_ok)
+ return ev;
+
+ /* Sensor scale factor */
+ if ((ev = spyd2_rd_ee_ushort(p, &sscal, 21)) != inst_ok)
+ return ev;
+
+ /* And apply it to the sensor data */
+ for (j = 0; j < 7; j++) {
+ for (i = 0; i < 41; i++) {
+ tsens[j][i] /= 1000; /* Convert to Hz per mW/nm/m^2 */
+ tsens[j][i] /= sscal/1e5; /* Sensitivity scale value */
+ }
+ }
+
+ /* Convert sensor values to xspect's */
+ for (i = 0; i < 7; i++) {
+ p->sens[i].spec_n = 41;
+ p->sens[i].spec_wl_short = 380;
+ p->sens[i].spec_wl_long = 780;
+ p->sens[i].norm = 1.0;
+ for (j = 0; j < 41; j++) {
+ p->sens[i].spec[j] = tsens[i][j];
+ }
+ }
+#ifdef SAVE_SPECTRA
+ write_nxspect("sensors.sp", p->sens, 7, 0);
+#endif
+
+ /* Linearization */
+ if ((ev = spyd2_rdreg_3x9xfloat(p, p->cal_B[1][0], p->cal_B[1][1], p->cal_B[1][2], 60))
+ != inst_ok)
+ return ev;
+
+#ifdef PLOT_SPECTRA
+ /* Plot the sensor spectra */
+ {
+ int i, j;
+ double xx[81];
+ double yy[10][81], *yp[10];
+
+ for (i = 0; i < 81; i++)
+ xx[i] = 380.0 + i * 5.0;
+
+ for (j = 0; j < 7; j++) {
+ for (i = 0; i < 81; i++)
+ yy[j][i] = value_xspect(&p->sens[j], xx[i]);
+ yp[j] = yy[j];
+ }
+ for (; j < 10; j++)
+ yp[j] = NULL;
+
+ printf("The sensor and ambient sensor sensitivy curves\n");
+ do_plot10(xx, yp[0], yp[1], yp[2], yp[3], yp[4], yp[5], yp[6], yp[7], yp[8], yp[9], 81, 0);
+
+
+ for (j = 0; j < spyd4_nocals; j++) {
+ double max = 0;
+ for (i = 0; i < 81; i++) {
+ if (yy[j][i] = value_xspect(&spyd4_cals[j], xx[i]) > max)
+ max = value_xspect(&spyd4_cals[j], xx[i]);
+ }
+ for (i = 0; i < 81; i++)
+ yy[j][i] = value_xspect(&spyd4_cals[j], xx[i])/max;
+ yp[j] = yy[j];
+ }
+ for (; j < 10; j++)
+ yp[j] = NULL;
+
+ printf("The display spectra\n");
+ do_plot10(xx, yp[0], yp[1], yp[2], yp[3], yp[4], yp[5], yp[6], yp[7], yp[8], yp[9], 81, 0);
+ }
+#endif /* PLOT_SPECTRA */
+
+ }
+
+ a1logd(p->log, 3, "spyd2_read_all_regs: all EEProm read OK\n");
+
+ return inst_ok;
+}
+
+/* ------------------------------------------------------------ */
+
+/* Table to hold Spyder 2 Firmware, if it's installed */
+unsigned int _spyder2_pld_size = 0; /* Number of bytes to download */
+unsigned int *spyder2_pld_size = &_spyder2_pld_size;
+unsigned char *spyder2_pld_bytes = NULL;
+
+/* Spyder 2: Download the PLD if it is available, and check status */
+static inst_code
+spyd2_download_pld(
+ spyd2 *p /* Object */
+) {
+ inst_code ev;
+ int stat;
+ int i;
+
+ a1logd(p->log, 2, "spyd2_download_pld: called\n");
+
+ if (*spyder2_pld_size == 0 || *spyder2_pld_size == 0x11223344) {
+ a1logd(p->log, 1, "spyd2_download_pld: No PLD pattern available! (have you run spyd2en ?)\n");
+ return spyd2_interp_code((inst *)p, SPYD2_NO_PLD_PATTERN) ;
+ }
+
+ for (i = 0; i < *spyder2_pld_size; i += 8) {
+ if ((ev = spyd2_loadPLD(p, spyder2_pld_bytes + i, 8)) != inst_ok)
+ return ev;
+ }
+
+ /* Let the PLD initialize */
+ msec_sleep(500);
+
+#ifdef DO_RESETEP /* Do the miscelanous resetep()'s */
+ /* Reset the coms */
+ p->icom->usb_resetep(p->icom, 0x81);
+ msec_sleep(1); /* Let device recover ? */
+#endif /* DO_RESETEP */
+
+ /* Check the status */
+ if ((ev = spyd2_getstatus(p, &stat)) != inst_ok)
+ return ev;
+
+ if (stat != 0) {
+ a1logd(p->log, 1, "spyd2_download_pld: PLD download failed!\n");
+ return spyd2_interp_code((inst *)p, SPYD2_PLDLOAD_FAILED);
+ }
+
+ a1logd(p->log, 2, "spyd2_download_pld: PLD download OK\n");
+
+ msec_sleep(500);
+#ifdef DO_RESETEP /* Do the miscelanous resetep()'s */
+ p->icom->usb_resetep(p->icom, 0x81);
+ msec_sleep(1); /* Let device recover ? */
+#endif /* DO_RESETEP */
+
+ return inst_ok;
+}
+
+
+/* ------------------------------------------------------------ */
+/* Setup Spyder4 native calibrations */
+
+/* Load the manufacturers Spyder4 calibration data */
+/* Return a SPYD2_ error value */
+static int
+spyd4_load_cal(spyd2 *p) {
+ char **bin_paths = NULL;
+ int no_paths = 0;
+ unsigned int size;
+ unsigned char *buf = NULL;
+ FILE *fp = NULL;
+ int nocals = 0;
+ int i, j;
+
+ /* If already loaded */
+ if (spyd4_nocals != 0)
+ return SPYD2_OK;
+
+
+ for (;;) { /* So we can break */
+ if ((no_paths = xdg_bds(NULL, &bin_paths, xdg_data, xdg_read, xdg_user,
+ "ArgyllCMS/spyd4cal.bin" XDG_FUDGE "color/spyd4cal.bin"
+ )) < 1)
+ break;
+
+ /* open binary file */
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(bin_paths[0],"rb")) == NULL)
+#else
+ if ((fp = fopen(bin_paths[0],"r")) == NULL)
+#endif
+ break;
+ xdg_free(bin_paths, no_paths);
+
+ /* Figure out how big file it is */
+ if (fseek(fp, 0, SEEK_END)) {
+ fclose(fp);
+ break;
+ }
+ size = (unsigned long)ftell(fp);
+
+ if ((size % (41 * 8)) != 0) {
+ fclose(fp);
+ a1logd(p->log, 1, "spyd4_load_cal: calibration file '%s' is unexpected size\n",bin_paths[0]);
+ break;
+ }
+
+ nocals = size/(41 * 8);
+ if (nocals != 6) {
+ fclose(fp);
+ a1logd(p->log, 1, "spyd4_load_cal: calibration file '%s' is unexpected number of calibrations (%d)\n",bin_paths[0],nocals);
+ break;
+ }
+
+ if (fseek(fp, 0, SEEK_SET)) {
+ fclose(fp);
+ break;
+ }
+
+ if ((buf = (unsigned char *)calloc(nocals * 41, 8)) == NULL) {
+ fclose(fp);
+ return SPYD2_MALLOC;
+ }
+
+ if (fread(buf, 1, size, fp) != size) {
+ free(buf);
+ fclose(fp);
+ break;
+ }
+ fclose(fp);
+ break;
+ }
+
+ if (buf == NULL)
+ nocals = 1;
+
+ if ((spyd4_cals = (xspect *)calloc(nocals, sizeof(xspect))) == NULL) {
+ if (buf != NULL)
+ free(buf);
+ return SPYD2_MALLOC;
+ }
+
+ /* If we have calibrations */
+ if (buf != NULL) {
+ unsigned char *bp;
+
+ for (i = 0; i < nocals; i++) {
+ bp = buf + 41 * 8 * i;
+
+ spyd4_cals[i].spec_n = 41;
+ spyd4_cals[i].spec_wl_short = 380;
+ spyd4_cals[i].spec_wl_long = 780;
+ spyd4_cals[i].norm = 1.0;
+
+ for (j = 0; j < 41; j++, bp += 8) {
+ ORD64 val;
+
+ val = buf2ord64(bp);
+ spyd4_cals[i].spec[j] = IEEE754_64todouble(val);
+// a1logd(p->log, 3, "cal[%d][%d] = %f\n",i,j,spyd4_cals[i].spec[j]);
+ }
+ }
+
+ } else {
+
+ /* Create a default calibration */
+ for (j = 0; j < 41; j++)
+ spyd4_cals[0].spec_n = 41;
+ spyd4_cals[0].spec_wl_short = 380;
+ spyd4_cals[0].spec_wl_long = 780;
+ spyd4_cals[0].norm = 1.0;
+
+ for (j = 0; j < 41; j++) {
+ spyd4_cals[0].spec[j] = 1.0;
+ }
+ }
+
+ spyd4_nocals = nocals;
+
+ return SPYD2_OK;
+}
+
+/* ============================================================ */
+
+
+/* Establish communications with a SPYD2 */
+/* If it's a serial port, use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+spyd2_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ spyd2 *p = (spyd2 *) pp;
+ int se;
+ icomuflags usbflags = icomuf_none;
+
+ a1logd(p->log, 2, "spyd2_init_coms: about to init coms\n");
+
+ if (p->icom->port_type(p->icom) != icomt_usb) {
+ a1logd(p->log, 1, "spyd2_init_coms: coms is not the right type!\n");
+ return spyd2_interp_code((inst *)p, SPYD2_UNKNOWN_MODEL);
+ }
+
+ a1logd(p->log, 2, "spyd2_init_coms: about to init USB\n");
+
+ /* On MSWindows the Spyder 3 doesn't work reliably unless each */
+ /* read is preceeded by a reset endpoint. */
+ /* (!!! This needs checking to see if it's still true. */
+ /* Should switch back to libusb0.sys and re-test.) */
+ /* (and Spyder 2 hangs if a reset ep is done on MSWin.) */
+ /* The spyder 2 doesn't work well with the winusb driver either, */
+ /* it needs icomuf_resetep_before_read to work at all, and */
+ /* gets retries anyway. So we use the libusb0 driver for it. */
+#if defined(NT)
+ if (p->itype == instSpyder3) {
+ usbflags |= icomuf_resetep_before_read; /* The spyder USB is buggy ? */
+ }
+#endif
+
+ /* On OS X the Spyder 2 can't close properly */
+#if defined(__APPLE__) /* OS X*/
+ if (p->itype == instSpyder2) {
+ usbflags |= icomuf_reset_before_close; /* The spyder 2 USB is buggy ? */
+ }
+#endif
+
+#ifdef NEVER /* Don't want this now that we avoid 2nd set_config on Linux */
+#if defined(UNIX_X11) /* Linux*/
+ /* On Linux the Spyder 2 doesn't work reliably unless each */
+ /* read is preceeded by a reset endpoint. */
+ if (p->itype == instSpyder2) {
+ usbflags |= icomuf_resetep_before_read; /* The spyder USB is buggy ? */
+ }
+#endif
+#endif
+
+ /* Set config, interface, write end point, read end point */
+ /* ("serial" end points aren't used - the spyd2lay uses USB control messages) */
+ if ((se = p->icom->set_usb_port(p->icom, 1, 0x00, 0x00, usbflags, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "spyd2_init_coms: failed ICOM err 0x%x\n",se);
+ return spyd2_interp_code((inst *)p, icoms2spyd2_err(se));
+ }
+
+ a1logd(p->log, 2, "spyd2_init_coms: suceeded\n");
+
+ p->gotcoms = 1;
+ return inst_ok;
+}
+
+static inst_code set_default_disp_type(spyd2 *p);
+
+/* Initialise the SPYD2 */
+/* return non-zero on an error, with an inst_code */
+static inst_code
+spyd2_init_inst(inst *pp) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_code ev = inst_ok;
+ int stat;
+ int i;
+
+ a1logd(p->log, 2, "spyd2_init_inst: called\n");
+
+ if (p->gotcoms == 0) /* Must establish coms before calling init */
+ return spyd2_interp_code((inst *)p, SPYD2_NO_COMS);
+
+ if (p->itype != instSpyder2
+ && p->itype != instSpyder3
+ && p->itype != instSpyder4)
+ return spyd2_interp_code((inst *)p, SPYD2_UNKNOWN_MODEL);
+
+ p->refrate = DEFRRATE;
+ for (i = 0; i < 8; i++)
+ p->prevraw[i] = 0; /* Internal counters will be reset */
+ p->prevrawinv = 0; /* prevraw is valid */
+
+ /* For Spyder 1 & 2, reset the hardware and wait for it to become ready. */
+ if (p->itype != instSpyder3
+ && p->itype != instSpyder4) {
+
+ /* Reset the instrument */
+ if ((ev = spyd2_reset(p)) != inst_ok)
+ return ev;
+
+ /* Fetch status until we get a status = 1 */
+ for (i = 0; i < 50; i++) {
+ if ((ev = spyd2_getstatus(p, &stat)) != inst_ok)
+ return ev;
+
+ if (stat == 1)
+ break;
+ }
+ if (i >= 50)
+ return spyd2_interp_code((inst *)p, SPYD2_BADSTATUS);
+
+ } else {
+ /* Because the Spyder 3/4 doesn't have a reset command, */
+ /* it may be left in a borked state if the driver is aborted. */
+ /* Make sure there's no old read data hanging around. */
+ /* Sometimes it takes a little while for the old data to */
+ /* turn up, so try at least for 1 second. */
+ /* This won't always work if the driver is re-started */
+ /* quickly after aborting a long integration read. */
+
+ unsigned char buf[8]; /* return bytes read */
+ int rwbytes; /* Data bytes read or written */
+
+
+ for (i = 0; i < 10; i++) {
+ if ((p->icom->usb_read(p->icom, NULL, 0x81, buf, 8, &rwbytes, 0.1) & ICOM_TO)
+ && i > 9)
+ break; /* Done when read times out */
+ }
+ }
+
+ /* Read the Serial EEProm contents */
+ if ((ev = spyd2_read_all_regs(p)) != inst_ok)
+ return ev;
+
+ /* Spyder 2 */
+ if (p->hwver < 4) {
+ /* Download the PLD pattern and check the status */
+ if ((ev = spyd2_download_pld(p)) != inst_ok)
+ return ev;
+ }
+
+ p->gain = 1.0;
+ if (p->hwver == 5) {
+ if ((ev = spyd2_SetGain(p, 4)) != inst_ok)
+ return ev;
+ }
+
+ /* Set a default calibration */
+ if ((ev = set_default_disp_type(p)) != inst_ok) {
+ return ev;
+ }
+
+ /* Do a dumy sensor read. This will set prevraw[] values. */
+ {
+ int clocks = 500;
+ int minfclks = 0;
+ int maxfclks = 0;
+ msec_sleep(100);
+ if ((ev = spyd2_GetReading_ll(p, &clocks, 10, 0, &minfclks, &maxfclks, NULL, NULL, NULL)) != inst_ok)
+ return ev;
+ }
+
+ p->trig = inst_opt_trig_user; /* default trigger mode */
+
+ p->inited = 1;
+ a1logd(p->log, 2, "spyd2_init_inst: inited OK\n");
+
+ if (p->hwver >= 4) {
+ /* Flash the LED, just cos we can! */
+ if ((ev = spyd2_setLED(p, 2, 0.0)) != inst_ok)
+ return ev;
+ msec_sleep(200);
+ if ((ev = spyd2_setLED(p, 0, 0.0)) != inst_ok)
+ return ev;
+ }
+
+ a1logv(p->log, 1, "Instrument Type: %s\n"
+ "Serial Number: %s\n"
+ "Hardware version: 0x%02x%02x\n"
+ ,inst_name(p->itype) ,p->serno ,p->hwver,p->fbits);
+
+ return inst_ok;
+}
+
+/* Read a single sample */
+/* Return the dtp error code */
+static inst_code
+spyd2_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ spyd2 *p = (spyd2 *)pp;
+ int user_trig = 0;
+ inst_code ev = inst_protocol_error;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->trig == inst_opt_trig_user) {
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "sptyd2: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((ev = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (ev == inst_user_abort)
+ return ev; /* Abort */
+ if (ev == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (ev = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_trig)
+ return ev; /* Abort */
+ }
+
+ if (IMODETST(p->mode, inst_mode_emis_ambient)) {
+ if ((ev = spyd2_GetAmbientReading(p, val->XYZ)) != inst_ok)
+ return ev;
+
+ } else {
+
+ /* Attempt a CRT frame rate calibration if needed */
+ if (p->refrmode != 0 && p->rrset == 0) {
+ if ((ev = spyd2_GetRefRate(p)) != inst_ok)
+ return ev;
+ }
+
+ /* Read the XYZ value */
+ if ((ev = spyd2_GetReading(p, val->XYZ)) != inst_ok)
+ return ev;
+
+ /* Apply the colorimeter correction matrix */
+ icmMulBy3x3(val->XYZ, p->ccmat, val->XYZ);
+ }
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+
+ val->loc[0] = '\000';
+ if (IMODETST(p->mode, inst_mode_emis_ambient))
+ val->mtype = inst_mrt_ambient;
+ else
+ val->mtype = inst_mrt_emission;
+ val->XYZ_v = 1; /* These are absolute XYZ readings ? */
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ if (user_trig)
+ return inst_user_trig;
+ return ev;
+}
+
+/* Insert a colorimetric correction matrix in the instrument XYZ readings */
+/* This is only valid for colorimetric instruments. */
+/* To remove the matrix, pass NULL for the filter filename */
+inst_code spyd2_col_cor_mat(
+inst *pp,
+double mtx[3][3]
+) {
+ spyd2 *p = (spyd2 *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (mtx == NULL) {
+ icmSetUnity3x3(p->ccmat);
+ } else {
+ if (p->cbid == 0) {
+ a1loge(p->log, 1, "spyd2: can't set col_cor_mat over non base display type\n");
+ inst_wrong_setup;
+ }
+ icmCpy3x3(p->ccmat, mtx);
+ }
+
+ return inst_ok;
+}
+
+/* Use a Colorimeter Calibration Spectral Set to set the */
+/* instrumen calibration. */
+/* This is only valid for colorimetric instruments. */
+/* To set calibration back to default, pass NULL for sets. */
+inst_code spyd2_col_cal_spec_set(
+inst *pp,
+xspect *sets,
+int no_sets
+) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_code ev = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+ if (p->hwver < 7)
+ return inst_unsupported;
+
+ if (sets == NULL || no_sets <= 0) {
+ if ((ev = set_default_disp_type(p)) != inst_ok)
+ return ev;
+ } else {
+ /* Use given spectral samples */
+ if ((ev = spyd4_comp_calmat(p, p->obType, p->custObserver, sets, no_sets)) != inst_ok)
+ return ev;
+ p->icx = (99 << 1) | 1; /* Out of range index */
+ }
+ return ev;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code spyd2_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ spyd2 *p = (spyd2 *)pp;
+
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if (p->refrmode != 0) {
+ if (p->rrset == 0)
+ n_cals |= inst_calt_ref_freq;
+ a_cals |= inst_calt_ref_freq;
+ }
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Request an instrument calibration. */
+/* This is use if the user decides they want to do a calibration, */
+/* in anticipation of a calibration (needs_calibration()) to avoid */
+/* requiring one during measurement, or in response to measuring */
+/* returning inst_needs_cal. Initially us an inst_cal_cond of inst_calc_none, */
+/* and then be prepared to setup the right conditions, or ask the */
+/* user to do so, each time the error inst_cal_setup is returned. */
+inst_code spyd2_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_code ev = inst_ok;
+ inst_cal_type needed, available;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ id[0] = '\000';
+
+ if ((ev = spyd2_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return ev;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"spyd2_calibrate: doing calt 0x%x\n",calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ if ((*calt & inst_calt_ref_freq) && p->refrmode != 0) {
+
+ if (*calc != inst_calc_emis_white) {
+ *calc = inst_calc_emis_white;
+ return inst_cal_setup;
+ }
+
+ /* Do CRT frame rate calibration */
+ if ((ev = spyd2_GetRefRate(p)) != inst_ok)
+ return ev;
+
+ *calt &= ~inst_calt_ref_freq;
+ }
+
+ return inst_ok;
+}
+
+/* Return the last calibrated refresh rate in Hz. Returns: */
+static inst_code spyd2_get_refr_rate(inst *pp,
+double *ref_rate
+) {
+ spyd2 *p = (spyd2 *)pp;
+ if (p->refrvalid) {
+ *ref_rate = p->refrate;
+ return inst_ok;
+ } else if (p->rrset) {
+ *ref_rate = 0.0;
+ return inst_misread;
+ }
+ return inst_needs_cal;
+}
+
+/* Set the calibrated refresh rate in Hz. */
+/* Set refresh rate to 0.0 to mark it as invalid */
+/* Rates outside the range 5.0 to 150.0 Hz will return an error */
+static inst_code spyd2_set_refr_rate(inst *pp,
+double ref_rate
+) {
+ spyd2 *p = (spyd2 *)pp;
+
+ if (ref_rate != 0.0 && (ref_rate < 5.0 || ref_rate > 150.0))
+ return inst_bad_parameter;
+
+ p->refrate = ref_rate;
+ if (ref_rate == 0.0)
+ p->refrate = DEFRRATE;
+ else
+ p->refrvalid = 1;
+ p->rrset = 1;
+
+ return inst_ok;
+}
+
+/* Error codes interpretation */
+static char *
+spyd2_interp_error(inst *pp, int ec) {
+// spyd2 *p = (spyd2 *)pp;
+ ec &= inst_imask;
+ switch (ec) {
+ case SPYD2_INTERNAL_ERROR:
+ return "Non-specific software internal software error";
+ case SPYD2_COMS_FAIL:
+ return "Communications failure";
+ case SPYD2_UNKNOWN_MODEL:
+ return "Not a Spyder 2 or 3";
+ case SPYD2_DATA_PARSE_ERROR:
+ return "Data from i1 Display didn't parse as expected";
+
+ case SPYD2_OK:
+ return "No device error";
+
+ /* device specific errors */
+ case SPYD2_BADSTATUS:
+ return "Too many retries waiting for status to come good";
+ case SPYD2_PLDLOAD_FAILED:
+ return "Wrong status after download of PLD";
+ case SPYD2_BADREADSIZE:
+ return "Didn't read expected amount of data";
+ case SPYD2_TRIGTIMEOUT:
+ return "Trigger timout";
+ case SPYD2_OVERALLTIMEOUT:
+ return "Overall timout";
+ case SPYD2_BAD_EE_CRC:
+ return "Serial EEProm CRC failed";
+
+ /* Internal errors */
+ case SPYD2_BAD_EE_ADDRESS:
+ return "Serial EEProm read is out of range";
+ case SPYD2_BAD_EE_SIZE:
+ return "Serial EEProm read size > 256";
+ case SPYD2_NO_PLD_PATTERN:
+ return "No PLD firmware pattern is available (have you run spyd2en ?)";
+ case SPYD2_NO_COMS:
+ return "Communications hasn't been established";
+ case SPYD2_NOT_INITED:
+ return "Insrument hasn't been initialised";
+ case SPYD2_NOCRTCAL:
+ return "Insrument is missing the CRT calibration table";
+ case SPYD2_NOLCDCAL:
+ return "Insrument is missing the Normal or LCD calibration table";
+ case SPYD2_MALLOC:
+ return "Memory allocation failure";
+ case SPYD2_OBS_SELECT:
+ return "Failed to set observer type";
+ case SPYD2_CAL_FAIL:
+ return "Calibration calculation failed";
+ case SPYD2_INT_CIECONVFAIL:
+ return "Creating spectral to CIE converted failed";
+ case SPYD2_TOO_FEW_CALIBSAMP:
+ return "There are too few spectral calibration samples - need at least 3";
+
+ /* Configuration */
+ case SPYD2_DISP_SEL_RANGE:
+ return "Display device selection out of range";
+
+ default:
+ return "Unknown error code";
+ }
+}
+
+
+/* Convert a machine specific error code into an abstract dtp code */
+static inst_code
+spyd2_interp_code(inst *pp, int ec) {
+// spyd2 *p = (spyd2 *)pp;
+
+ ec &= inst_imask;
+ switch (ec) {
+
+ case SPYD2_OK:
+ return inst_ok;
+
+ case SPYD2_INTERNAL_ERROR:
+ case SPYD2_NO_COMS:
+ case SPYD2_NOT_INITED:
+ case SPYD2_BAD_EE_ADDRESS:
+ case SPYD2_BAD_EE_SIZE:
+ case SPYD2_NO_PLD_PATTERN:
+ case SPYD2_MALLOC:
+ case SPYD2_OBS_SELECT:
+ case SPYD2_CAL_FAIL:
+ case SPYD2_INT_CIECONVFAIL:
+ case SPYD2_TOO_FEW_CALIBSAMP:
+ return inst_internal_error | ec;
+
+ case SPYD2_COMS_FAIL:
+ case SPYD2_BADREADSIZE:
+ case SPYD2_TRIGTIMEOUT:
+ case SPYD2_BADSTATUS:
+ case SPYD2_OVERALLTIMEOUT:
+ return inst_coms_fail | ec;
+
+ case SPYD2_UNKNOWN_MODEL:
+ return inst_unknown_model | ec;
+
+// return inst_protocol_error | ec;
+
+ case SPYD2_NOCRTCAL:
+ case SPYD2_NOLCDCAL:
+ case SPYD2_PLDLOAD_FAILED:
+ case SPYD2_BAD_EE_CRC:
+ return inst_hardware_fail | ec;
+
+ case SPYD2_DISP_SEL_RANGE:
+ return inst_wrong_setup | ec;
+
+ }
+ return inst_other_error | ec;
+}
+
+/* Destroy ourselves */
+static void
+spyd2_del(inst *pp) {
+ spyd2 *p = (spyd2 *)pp;
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ inst_del_disptype_list(p->dtlist, p->ndtlist);
+ free(p);
+}
+
+/* Return the instrument mode capabilities */
+void spyd2_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_mode cap1= 0;
+ inst2_capability cap2 = 0;
+
+ cap1 |= inst_mode_emis_spot
+ | inst_mode_emis_refresh_ovd
+ | inst_mode_emis_norefresh_ovd
+ | inst_mode_colorimeter
+ ;
+
+ /* We don't seem to have a way of detecting the lack */
+ /* of ambinent capability, short of doing a read */
+ /* and noticing the result is zero. */
+ if (p->itype == instSpyder3
+ || p->itype == instSpyder4) {
+ cap1 |= inst_mode_emis_ambient;
+ }
+
+ cap2 |= inst2_prog_trig
+ | inst2_user_trig
+ | inst2_ccmx
+ | inst2_refresh_rate
+ | inst2_emis_refr_meas
+ ;
+
+ if (p->itype == instSpyder3
+ || p->itype == instSpyder4) {
+ cap2 |= inst2_disptype;
+ cap2 |= inst2_has_leds;
+ cap2 |= inst2_ambient_mono;
+ } else {
+ cap2 |= inst2_disptype;
+ }
+
+ if (p->itype == instSpyder4)
+ cap2 |= inst2_ccss; /* Spyder4 has spectral sensiivities */
+
+ if (pcap1 != NULL)
+ *pcap1 = cap1;
+ if (pcap2 != NULL)
+ *pcap2 = cap2;
+ if (pcap3 != NULL)
+ *pcap3 = inst3_none;
+}
+
+/* Check device measurement mode */
+inst_code spyd2_check_mode(inst *pp, inst_mode m) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_mode cap;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ if (!IMODETST(m, inst_mode_emis_spot)
+ && !IMODETST(m, inst_mode_emis_ambient)) {
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/* Set device measurement mode */
+inst_code spyd2_set_mode(inst *pp, inst_mode m) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_code ev;
+
+ if ((ev = spyd2_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->mode = m;
+
+ if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) /* Must test this first! */
+ p->refrmode = 0;
+ else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd))
+ p->refrmode = 1;
+
+ return inst_ok;
+}
+
+inst_disptypesel spyd2_disptypesel[3] = {
+ {
+ inst_dtflags_default,
+ 1,
+ "l",
+ "LCD display",
+ 0,
+ 1
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 2, /* cbid */
+ "c", /* sel */
+ "CRT display", /* desc */
+ 1, /* refr */
+ 0 /* ix */
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+inst_disptypesel spyd3_disptypesel[3] = {
+ {
+ inst_dtflags_default,
+ 1,
+ "nl",
+ "Non-Refresh display",
+ 0,
+ 1
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 2, /* cbid */
+ "rc", /* sel */
+ "Refresh display", /* desc */
+ 1, /* refr */
+ 1 /* ix */
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+inst_disptypesel spyd4_disptypesel_1[8] = {
+ {
+ inst_dtflags_default,
+ 1,
+ "nl",
+ "Generic Non-Refresh Display",
+ 0,
+ 1
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 2, /* cbid */
+ "rc", /* sel */
+ "Generic Refresh Display", /* desc */
+ 1, /* refr */
+ 1 /* ix */
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+inst_disptypesel spyd4_disptypesel[8] = {
+ {
+ inst_dtflags_default,
+ 1,
+ "n",
+ "Generic Non-Refresh Display",
+ 0,
+ 1
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 2, /* cbid */
+ "r", /* sel */
+ "Generic Refresh Display", /* desc */
+ 1, /* refr */
+ 1 /* ix = hw bit + spec table << 1 */
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 0,
+ "f",
+ "LCD, CCFL Backlight",
+ 0,
+ (1 << 1) | 1
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 0,
+ "L",
+ "Wide Gamut LCD, CCFL Backlight",
+ 0,
+ (2 << 1) | 1
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 0,
+ "e",
+ "LCD, White LED Backlight",
+ 0,
+ (3 << 1) | 1
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 0,
+ "B",
+ "Wide Gamut LCD, RGB LED Backlight",
+ 0,
+ (4 << 1) | 1
+ },
+ {
+ inst_dtflags_none, /* flags */
+ 0,
+ "x",
+ "LCD, CCFL Backlight (Laptop ?)",
+ 0,
+ (5 << 1) | 1
+ },
+ {
+ inst_dtflags_end,
+ 0,
+ "",
+ "",
+ 0,
+ 0
+ }
+};
+
+static void set_base_disptype_list(spyd2 *p) {
+ /* set the base display type list */
+ if (p->itype == instSpyder4) {
+ if (spyd4_nocals <= 1) {
+ p->_dtlist = spyd4_disptypesel_1;
+ } else {
+ p->_dtlist = spyd4_disptypesel;
+ }
+ } else if (p->itype == instSpyder3) {
+ p->_dtlist = spyd3_disptypesel;
+ } else {
+ p->_dtlist = spyd2_disptypesel;
+ }
+}
+
+/* Get mode and option details */
+static inst_code spyd2_get_disptypesel(
+inst *pp,
+int *pnsels, /* Return number of display types */
+inst_disptypesel **psels, /* Return the array of display types */
+int allconfig, /* nz to return list for all configs, not just current. */
+int recreate /* nz to re-check for new ccmx & ccss files */
+) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_code rv = inst_ok;
+
+ /* Create/Re-create a current list of abailable display types */
+ if (p->dtlist == NULL || recreate) {
+ if ((rv = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ p->_dtlist, p->hwver >= 7 ? 1 : 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return rv;
+ }
+
+ if (pnsels != NULL)
+ *pnsels = p->ndtlist;
+
+ if (psels != NULL)
+ *psels = p->dtlist;
+
+ return inst_ok;
+}
+
+/* Given a display type entry, setup for that type */
+static inst_code set_disp_type(spyd2 *p, inst_disptypesel *dentry) {
+ inst_code ev;
+ int refrmode;
+
+ p->icx = dentry->ix;
+ p->cbid = dentry->cbid;
+ refrmode = dentry->refr;
+
+ if ( IMODETST(p->mode, inst_mode_emis_norefresh_ovd)) { /* Must test this first! */
+ refrmode = 0;
+ } else if (IMODETST(p->mode, inst_mode_emis_refresh_ovd)) {
+ refrmode = 1;
+ }
+
+ if (p->refrmode != refrmode) {
+ p->rrset = 0; /* This is a hint we may have swapped displays */
+ p->refrvalid = 0;
+ }
+ p->refrmode = refrmode;
+
+ if (dentry->flags & inst_dtflags_ccss) {
+
+ if ((ev = spyd4_comp_calmat(p, p->obType, p->custObserver, dentry->sets, dentry->no_sets))
+ != inst_ok) {
+ a1logd(p->log, 1, "spyd4_set_disp_type: comp_calmat ccss failed with rv = 0x%x\n",ev);
+ return ev;
+ }
+ p->icx = (99 << 1) | 1; /* Out of range index */
+ icmSetUnity3x3(p->ccmat);
+
+ } else {
+
+ if (p->hwver >= 7) {
+ if ((p->icx >> 1) > spyd4_nocals)
+ return inst_unsupported;
+
+ /* Create the calibration matrix */
+ if ((ev = spyd4_set_cal(p, p->icx >> 1)) != inst_ok)
+ return ev;
+ }
+
+ if (dentry->flags & inst_dtflags_ccmx) {
+ icmCpy3x3(p->ccmat, dentry->mat);
+ } else {
+ icmSetUnity3x3(p->ccmat);
+ }
+ }
+
+ return inst_ok;
+}
+
+
+/* Setup the default display type */
+static inst_code set_default_disp_type(spyd2 *p) {
+ inst_code ev;
+ int i;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list((inst *)p, &p->ndtlist, &p->dtlist,
+ p->_dtlist, p->hwver >= 7 ? 1 : 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ for (i = 0; !(p->dtlist[i].flags & inst_dtflags_end); i++) {
+ if (p->dtlist[i].flags & inst_dtflags_default)
+ break;
+ }
+ if (p->dtlist[i].flags & inst_dtflags_end) {
+ a1loge(p->log, 1, "set_default_disp_type: failed to find type!\n");
+ return inst_internal_error;
+ }
+ if ((ev = set_disp_type(p, &p->dtlist[i])) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/* Set the display type */
+static inst_code spyd2_set_disptype(inst *pp, int ix) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_code ev;
+ inst_disptypesel *dentry;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->dtlist == NULL) {
+ if ((ev = inst_creat_disptype_list(pp, &p->ndtlist, &p->dtlist,
+ p->_dtlist, p->hwver >= 7 ? 1 : 0 /* doccss*/, 1 /* doccmx */)) != inst_ok)
+ return ev;
+ }
+
+ if (ix < 0 || ix >= p->ndtlist)
+ return inst_unsupported;
+
+ dentry = &p->dtlist[ix];
+
+ if ((ev = set_disp_type(p, dentry)) != inst_ok) {
+ return ev;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * set or reset an optional mode
+ *
+ * Some options talk to the instrument, and these will
+ * error if it hasn't been initialised.
+ * [We could fix this by setting a flag and adding
+ * some extra logic in init()]
+ */
+static inst_code
+spyd2_get_set_opt(inst *pp, inst_opt_type m, ...) {
+ spyd2 *p = (spyd2 *)pp;
+ inst_code ev = inst_ok;
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user) {
+ p->trig = m;
+ return inst_ok;
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Get the display type information */
+ if (m == inst_opt_get_dtinfo) {
+ va_list args;
+ int *refrmode, *cbid;
+
+ va_start(args, m);
+ refrmode = va_arg(args, int *);
+ cbid = va_arg(args, int *);
+ va_end(args);
+
+ if (refrmode != NULL)
+ *refrmode = p->refrmode;
+ if (cbid != NULL)
+ *cbid = p->cbid;
+
+ return inst_ok;
+ }
+
+ /* Set the ccss observer type */
+ if (m == inst_opt_set_ccss_obs) {
+ va_list args;
+ icxObserverType obType;
+ xspect *custObserver;
+
+ va_start(args, m);
+ obType = va_arg(args, icxObserverType);
+ custObserver = va_arg(args, xspect *);
+ va_end(args);
+
+ if (obType == icxOT_default)
+ obType = icxOT_CIE_1931_2;
+ p->obType = obType;
+ if (obType == icxOT_custom) {
+ p->custObserver[0] = custObserver[0];
+ p->custObserver[1] = custObserver[1];
+ p->custObserver[2] = custObserver[2];
+ }
+
+ return inst_ok;
+ }
+
+ /* Operate the LED */
+ if (p->hwver >= 4) {
+ if (m == inst_opt_get_gen_ledmask) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = 0x1; /* One general LED */
+ return inst_ok;
+ } else if (m == inst_opt_get_led_state) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = p->led_state;
+ return inst_ok;
+ } else if (m == inst_opt_set_led_state) {
+ va_list args;
+ int mask = 0;
+
+ va_start(args, m);
+ mask = 1 & va_arg(args, int);
+ va_end(args);
+ if ((ev = spyd2_setLED(p, mask & 1 ? 2 : 0, 0.0)) == inst_ok) {
+ p->led_state = mask;
+ }
+ return ev;
+ }
+ }
+
+ if (m == inst_opt_get_pulse_ledmask) {
+ va_list args;
+ int *mask = NULL;
+
+ va_start(args, m);
+ mask = va_arg(args, int *);
+ va_end(args);
+ *mask = 0x1; /* General LED is pulsable */
+ return inst_ok;
+ } else if (m == inst_opt_set_led_pulse_state) {
+ va_list args;
+ double period, on_time_prop, trans_time_prop;
+ int mode;
+
+ va_start(args, m);
+ period = va_arg(args, double);
+ on_time_prop = va_arg(args, double);
+ trans_time_prop = va_arg(args, double);
+ va_end(args);
+ if (period < 0.0
+ || on_time_prop < 0.0 || on_time_prop > 1.0
+ || trans_time_prop < 0.0 || trans_time_prop > 1.0
+ || trans_time_prop > on_time_prop || trans_time_prop > (1.0 - on_time_prop))
+ return inst_bad_parameter;
+ if (period == 0.0 || on_time_prop == 0.0) {
+ period = 0.0;
+ mode = 0;
+ p->led_state = 0;
+ } else {
+ mode = 1;
+ p->led_state = 1;
+ }
+ p->led_period = period;
+ p->led_on_time_prop = on_time_prop;
+ p->led_trans_time_prop = trans_time_prop;
+ return spyd2_setLED(p, mode, period);
+ } else if (m == inst_opt_get_led_state) {
+ va_list args;
+ double *period, *on_time_prop, *trans_time_prop;
+
+ va_start(args, m);
+ period = va_arg(args, double *);
+ on_time_prop = va_arg(args, double *);
+ trans_time_prop = va_arg(args, double *);
+ va_end(args);
+ if (period != NULL) *period = p->led_period;
+ if (on_time_prop != NULL) *on_time_prop = p->led_on_time_prop;
+ if (trans_time_prop != NULL) *trans_time_prop = p->led_trans_time_prop;
+ return inst_ok;
+ }
+ return inst_unsupported;
+}
+
+/* Constructor */
+extern spyd2 *new_spyd2(icoms *icom, instType itype) {
+ spyd2 *p;
+ if ((p = (spyd2 *)calloc(sizeof(spyd2),1)) == NULL) {
+ a1loge(icom->log, 1, "new_spyd2: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ p->init_coms = spyd2_init_coms;
+ p->init_inst = spyd2_init_inst;
+ p->capabilities = spyd2_capabilities;
+ p->check_mode = spyd2_check_mode;
+ p->set_mode = spyd2_set_mode;
+ p->get_disptypesel = spyd2_get_disptypesel;
+ p->set_disptype = spyd2_set_disptype;
+ p->get_set_opt = spyd2_get_set_opt;
+ p->read_sample = spyd2_read_sample;
+ p->read_refrate = spyd2_read_refrate;
+ p->get_n_a_cals = spyd2_get_n_a_cals;
+ p->calibrate = spyd2_calibrate;
+ p->col_cor_mat = spyd2_col_cor_mat;
+ p->col_cal_spec_set = spyd2_col_cal_spec_set;
+ p->get_refr_rate = spyd2_get_refr_rate;
+ p->set_refr_rate = spyd2_set_refr_rate;
+ p->interp_error = spyd2_interp_error;
+ p->del = spyd2_del;
+
+ p->icom = icom;
+ p->itype = icom->itype;
+
+ /* Load manufacturers Spyder4 calibrations */
+ if (itype == instSpyder4) {
+ int rv;
+ p->hwver = 7; /* Set preliminary version */
+ if ((rv = spyd4_load_cal(p)) != SPYD2_OK)
+ a1logd(p->log, 1, "Loading Spyder4 calibrations failed with '%s'\n",p->interp_error((inst *)p, rv));
+ if (spyd4_nocals < 1)
+ a1logd(p->log, 1, "Spyder4 choice of calibrations not available\n");
+ }
+ if (itype == instSpyder3) {
+ p->hwver = 4; /* Set preliminary version */
+ }
+ if (itype == instSpyder2) {
+ p->hwver = 3; /* Set preliminary version */
+ }
+
+ icmSetUnity3x3(p->ccmat); /* Set the colorimeter correction matrix to do nothing */
+ set_base_disptype_list(p);
+
+ return p;
+}
+
diff --git a/spectro/spyd2.h b/spectro/spyd2.h
new file mode 100644
index 0000000..d3a208c
--- /dev/null
+++ b/spectro/spyd2.h
@@ -0,0 +1,168 @@
+#ifndef SPYD2_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * ColorVision Spyder 2 & 3 related software.
+ *
+ * Author: Graeme W. Gill
+ * Date: 19/10/2006
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * (Based on i1disp.c)
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include "inst.h"
+
+/* Note: update spyd2_interp_error() and spyd2_interp_code() in spyd2.c */
+/* if anything of these #defines are added or subtracted */
+
+/* Fake Error codes */
+#define SPYD2_INTERNAL_ERROR 0x61 /* Internal software error */
+#define SPYD2_COMS_FAIL 0x62 /* Communication failure */
+#define SPYD2_UNKNOWN_MODEL 0x63 /* Not an spyd2lay */
+#define SPYD2_DATA_PARSE_ERROR 0x64 /* Read data parsing error */
+
+/* Real error code */
+#define SPYD2_OK 0x00
+
+/* Sub codes for device specific reasoning */
+#define SPYD2_BADSTATUS 0x01
+#define SPYD2_PLDLOAD_FAILED 0x02
+#define SPYD2_BADREADSIZE 0x03
+#define SPYD2_TRIGTIMEOUT 0x04
+#define SPYD2_OVERALLTIMEOUT 0x05
+#define SPYD2_BAD_EE_CRC 0x06
+
+/* Internal software errors */
+#define SPYD2_BAD_EE_ADDRESS 0x21
+#define SPYD2_BAD_EE_SIZE 0x22
+#define SPYD2_NO_PLD_PATTERN 0x23
+#define SPYD2_NO_COMS 0x24
+#define SPYD2_NOT_INITED 0x25
+#define SPYD2_NOCRTCAL 0x26 /* No CRT calibration data */
+#define SPYD2_NOLCDCAL 0x27 /* No LCD calibration data */
+#define SPYD2_MALLOC 0x28
+#define SPYD2_OBS_SELECT 0x29 /* Observer */
+#define SPYD2_CAL_FAIL 0x2A
+#define SPYD2_TOO_FEW_CALIBSAMP 0x2B
+#define SPYD2_INT_CIECONVFAIL 0x2C
+
+/* Configuration */
+#define SPYD2_DISP_SEL_RANGE 0x40 /* Calibration selection is out of range */
+
+/* SPYD2/3 communication object */
+struct _spyd2 {
+ INST_OBJ_BASE
+
+ inst_mode mode; /* Currently selected mode (emis/ambient/etc.) */
+
+ inst_opt_type trig; /* Reading trigger mode */
+
+ /* Serial EEPROM registers */
+ /* versioni & feature bits */
+ /* Spyder2 = 0x0307 */
+ /* Spyder3 Express = 0x040f */
+ /* Spyder3 Pro = 0x0407 */
+ /* Spyder3 Elite = 0x0407 */
+ /* Spyder4 Pro = 0x070F */
+
+ unsigned int hwver; /* 5:B Harware version number */
+ /* Spyder2 = 3 */
+ /* Spyder3 = 4 */
+ /* Spyder4 = 7 */
+
+ unsigned int fbits; /* 6:B Feature bits 0,1,2,3 correspond to calibration types */
+ /* CRT/UNK, LCD/NORM, TOK, CRT/UNK */
+
+ char serno[9]; /* 8:8xB Serial number as zero terminated string */
+
+ /* Spyder2: [0][][] = CRT, [1][][] = LCD */
+ /* Spyder3: [0][][] = UNK, [1][][] = CRT & LCD */
+
+ /* hwver 3..6 uses these calibrations */
+ double cal_A[2][3][9]; /* HW3..6: 16, 256 CRT/LCD A calibration matrix */
+ double cal_B[2][3][9]; /* HW3..6: 128, 384 CRT/LCD B calibration matrix */
+
+ /* HW3 [0] = CRT/UNK, [1] = LCD/NORM */
+ /* HW4..6 [0] = not used, [1] = LCD */
+
+ /* HW7 [0] = No used */
+ /* HW7: cal_A[1] computed from sensor spectral data. */
+ /* HWy: cal_B[1] 60, 384 Linearity correction */
+
+ /* The first (A) 3x9 is a sensor to XYZ transform. */
+ /* cal[0] is an offset value, while the */
+ /* remaining 8 entries are the sensor weightings. */
+ /* Because there are only 7 real sensors, cal[1] */
+ /* and sensor[0] are skipped. */
+
+ /* The second (B) 3x9 is an additional non-linearity */
+ /* correction matrix, applied to the XYZ created */
+ /* from the first 3x9. The cooeficients consist */
+ /* of the weights for each product, ie: */
+ /* X, Y, Z, X*X, X*Z, Y*Z, X*X, Y*Y, Z*Z */
+ /* for each corrected output XYZ */
+
+ double cal_F[7]; /* 240:4, 364:3 F calibration vector */
+ /* This might be Y only weightings for the 7 sensor values, */
+ /* with no offset value (TOK type ?). */
+
+ /* hwver 7 (Spyder 4) uses computed calibrations */
+ xspect sens[7]; /* Sensor sensitivity curves in Hz per mW/nm/m^2 */
+
+ /* Computed factors and state */
+ inst_disptypesel *_dtlist; /* Base list */
+ inst_disptypesel *dtlist; /* Display Type list */
+ int ndtlist; /* Number of valid dtlist entries */
+
+ int refrmode; /* 0 for constant, 1 for refresh display */
+ int cbid; /* calibration base ID, 0 if not a base */
+ int icx; /* Bit 0: Cal table index, 0 = CRT, 1 = LCD/normal */
+ /* Bits 31-1: Spyder 4 spectral cal index, 0..spyd4_nocals-1 */
+ int rrset; /* Flag, nz if the refresh rate has been determined */
+ double refrate; /* Current refresh rate. Set to DEFREFR if not measurable */
+ int refrvalid; /* nz if refrate was measured */
+ double gain; /* hwver == 5 gain value (default 4) */
+ double ccmat[3][3]; /* Colorimeter correction matrix */
+ icxObserverType obType; /* ccss observer to use */
+ xspect custObserver[3]; /* Custom ccss observer to use */
+
+ int prevraw[8]; /* Previous raw reading values */
+ int prevrawinv; /* Previous raw readings invalid flag - after an abort */
+
+ /* Other state */
+ int led_state; /* Spyder 3: Current LED state */
+ double led_period, led_on_time_prop, led_trans_time_prop; /* Spyder 3: Pulse state */
+
+}; typedef struct _spyd2 spyd2;
+
+/* Constructor */
+extern spyd2 *new_spyd2(icoms *icom, instType itype);
+
+
+#define SPYD2_H
+#endif /* SPYD2_H */
diff --git a/spectro/spyd2PLD.h b/spectro/spyd2PLD.h
new file mode 100644
index 0000000..4a71cd8
--- /dev/null
+++ b/spectro/spyd2PLD.h
@@ -0,0 +1,10 @@
+
+/* Spyder 2 Colorimeter Xilinx XCS05XL firmware pattern */
+/* needs to be transfered here for the instrument to work. */
+
+/* The end user should see the spyd2en utility.*/
+
+static unsigned int pld_size = 0x11223344; /* Endian indicator */
+static unsigned int pld_space = 6824;
+static unsigned char pld_bytes[6824] = "XCS05XL firmware pattern"; /* Magic number */
+
diff --git a/spectro/spyd2setup.h b/spectro/spyd2setup.h
new file mode 100644
index 0000000..def83b6
--- /dev/null
+++ b/spectro/spyd2setup.h
@@ -0,0 +1,119 @@
+#ifndef SPYD2SETUP_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * ColorVision Spyder 2 related software.
+ *
+ * Author: Graeme W. Gill
+ * Date: 19/10/2006
+ *
+ * Copyright 2006 - 2013, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/* This file is only included in top utilities that need to */
+/* be able to access the Spyder 2 colorimeter. This provides */
+/* a mechanism for ensuring that only such utilities load the */
+/* proprietary Spyder firmware, as well as providing a means to */
+/* detect if the spyder driver is going to be funcional. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned int *spyder2_pld_size; /* in spyd2.c */
+extern unsigned char *spyder2_pld_bytes;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Return 0 if Spyder 2 firmware is not available */
+/* Return 1 if Spyder 2 firmware is available from an external file */
+/* Return 2 if Spyder 2 firmware is part of this executable */
+int setup_spyd2() {
+#ifdef ENABLE_USB
+ static int loaded = 0; /* Was loaded from a file */
+ char **bin_paths = NULL;
+ int no_paths = 0;
+ unsigned int size, rsize;
+ FILE *fp;
+ int i;
+
+ /* Spyder 2 Colorimeter Xilinx XCS05XL firmware pattern. */
+ /* This is a placeholder in the distributed files. */
+ /* It could be replaced with the actual end users firmware */
+ /* by using the spyd2trans utility, but normally the spyd2PLD.bin */
+ /* file is loaded instead. */
+
+#include "spyd2PLD.h"
+
+ spyder2_pld_size = &pld_size;
+ spyder2_pld_bytes = pld_bytes;
+
+ /* If no firmware compiled in, see if there is a file to load from. */
+ if ((pld_size == 0 || pld_size == 0x11223344) && loaded == 0) {
+
+
+ for (;;) { /* So we can break out */
+ if ((no_paths = xdg_bds(NULL, &bin_paths, xdg_data, xdg_read, xdg_user,
+ "ArgyllCMS/spyd2PLD.bin" XDG_FUDGE "color/spyd2PLD.bin"
+)) < 1) {
+ a1logd(g_log, 1, "etup_spyd2: failed to find PLD file\n");
+ break;
+ }
+
+ /* open binary file */
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(bin_paths[0],"rb")) == NULL)
+#else
+ if ((fp = fopen(bin_paths[0],"r")) == NULL)
+#endif
+ break;
+ xdg_free(bin_paths, no_paths);
+
+ /* Figure out how file it is */
+ if (fseek(fp, 0, SEEK_END)) {
+ fclose(fp);
+ break;
+ }
+ size = (unsigned long)ftell(fp);
+
+ if (size > pld_space)
+ size = pld_space;
+
+ if (fseek(fp, 0, SEEK_SET)) {
+ fclose(fp);
+ break;
+ }
+
+ if (fread(pld_bytes, 1, size, fp) != size) {
+ fclose(fp);
+ break;
+ }
+ pld_size = size;
+ loaded = 1; /* We've loaded it from a file */
+// a1logd(g_log,0,"Spyder2 pld bytes = 0x%x 0x%x 0x%x 0x%x\n",pld_bytes[0], pld_bytes[1], pld_bytes[2], pld_bytes[3]);
+ fclose(fp);
+ break;
+ }
+ }
+
+ if (pld_size != 0 && pld_size != 0x11223344) {
+ if (loaded)
+ return 1; /* Was loaded from a file */
+ return 2; /* Was compiled in */
+ }
+#endif /* ENABLE_USB */
+ return 0; /* Not available */
+}
+
+#define SPYD2SETUP_H
+#endif /* SPYD2SETUP_H */
diff --git a/spectro/ss.c b/spectro/ss.c
new file mode 100644
index 0000000..c72e189
--- /dev/null
+++ b/spectro/ss.c
@@ -0,0 +1,2109 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag Spectrolino and Spectroscan related
+ * defines and declarations.
+ *
+ * Author: Graeme W. Gill
+ * Date: 13/7/2005
+ *
+ * Copyright 2005 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from DTP41.h
+ *
+ * This is an alternative driver to spm/gretag.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+/*
+ TTBD:
+
+ There is a bug or limitation with using -N to skip the calibration
+ when using any of the emissive modes - the readings end up being nearly zero.
+
+ We aren't saving the spectrolino fake tranmission white reference in
+ a calibration file, so -N doesn't work with it.
+
+ You can't trigger a calibration reading using the instrument switch.
+
+ You should be able to do use the table enter key anywhere the user
+ is asked to hit a key.
+
+ The corner positioning could be smarter.
+
+ The SpectroscanT transmission cal. merely reminds the user (vie verbose)
+ that it is assuming the correct apatture, rather than given them
+ a chance to change it.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "ss.h"
+
+/* Default flow control */
+#define DEFFC fc_Hardware
+
+#include <stdarg.h>
+
+/* Some tables to convert between emums and text descriptions */
+
+/* Filter type */
+char* filter_desc[] = {
+ "Filter not defined",
+ "No Filter (U)",
+ "Polarizing Filter",
+ "D65 Filter",
+ "(Unknown Filter)",
+ "UV cut Filter",
+ "Custon Filter"
+};
+
+#define SS_REF_CAL_COUNT 50
+#define SS_TRANS_CAL_COUNT 10
+
+/* Track the number of measurements taken */
+static void inc_calcount(ss *p) {
+ p->calcount++;
+}
+
+/* Check if a calibration should be done, and set flags appropriately. */
+/* (atstart should be nz at start of serpentine) */
+static void check_calcount(ss *p, int atstart) {
+ a1logd(p->log, 4, "ss check_calcount: atstart %d, calcount %d, pisrow %d\n",
+ atstart,p->calcount,p->pisrow);
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_reflection) {
+ /* If forced or out and back will cross count, do cal now. */
+ if (p->forcecalib /* Forced */
+ || p->calcount >= SS_REF_CAL_COUNT /* Needs cal now */
+ || ( atstart /* At start of up & back */
+ && p->pisrow < SS_REF_CAL_COUNT /* possible not to cross */
+ && (p->calcount + p->pisrow) > SS_REF_CAL_COUNT)) { /* and will cross */
+ p->need_wd_cal = 1;
+ p->forcecalib = 0;
+ a1logd(p->log, 4, "ss check_calcount: need_wd_cal set\n");
+ }
+ } else if (((p->mode & inst_mode_illum_mask) == inst_mode_transmission
+ && (p->calcount >= SS_TRANS_CAL_COUNT || p->forcecalib))) {
+ p->forcecalib = 0;
+ p->need_t_cal = 2;
+ a1logd(p->log, 4, "ss check_calcount: need_t_cal set\n");
+ }
+}
+
+/* Establish communications with a Spectrolino/Spectroscan */
+/* Use the baud rate given, and timeout in to secs */
+/* Return DTP_COMS_FAIL on failure to establish communications */
+static inst_code
+ss_init_coms(inst *pp, baud_rate br, flow_control fc, double tout) {
+ ss *p = (ss *)pp;
+ /* We're a bit stuffed if the Specrolino/scan is set to 28800, since */
+ /* this rate isn't universally supported by computer systems. */
+ baud_rate brt[7] = { baud_9600, baud_19200, baud_57600,
+ baud_2400, baud_1200, baud_600,
+ baud_300 };
+ ss_bt ssbrc[7] = { ss_bt_9600, ss_bt_19200, ss_bt_57600,
+ ss_bt_2400, ss_bt_1200, ss_bt_600,
+ ss_bt_300 };
+ ss_ctt sobrc[7] = { ss_ctt_SetBaud9600, ss_ctt_SetBaud19200, ss_ctt_SetBaud57600,
+ ss_ctt_SetBaud2400, ss_ctt_SetBaud1200, ss_ctt_SetBaud600,
+ ss_ctt_SetBaud300 };
+ ss_ctt fcc1;
+ ss_hst fcc2;
+ long etime;
+ int ci, bi, i, se;
+ inst_code ev = inst_ok;
+
+ a1logd(p->log, 2, "ss_init_coms: About to init Serial I/O\n");
+
+ /* Deal with flow control setting */
+ if (fc == fc_nc)
+ fc = DEFFC;
+
+ if (fc == fc_XonXOff) {
+ fcc1 = ss_ctt_ProtokolWithXonXoff;
+ fcc2 = ss_hst_XonXOff;
+ } else if (fc == fc_Hardware) {
+ fcc1 = ss_ctt_ProtokolWithHardwareHS;
+ fcc2 = ss_hst_Hardware;
+ } else {
+ fc = fc_none;
+ fcc1 = ss_ctt_ProtokolWithoutXonXoff;
+ fcc2 = ss_hst_None;
+ }
+
+ /* Figure Spectrolino baud rate being asked for */
+ for (bi = 0; bi < 7; bi++) {
+ if (brt[bi] == br)
+ break;
+ }
+ if (bi >= 7)
+ bi = 0;
+
+ /* Figure current icoms baud rate */
+ for (ci = 0; ci < 7; ci++) {
+ if (brt[ci] == p->icom->br)
+ break;
+ }
+ if (ci >= 7)
+ ci = bi;
+
+ /* The tick to give up on */
+ etime = clock() + (long)(CLOCKS_PER_SEC * tout + 0.5);
+
+ /* Until we establish comms or give up */
+ while (clock() < etime) {
+
+ /* Until we time out, find the correct baud rate */
+ for (i = ci; clock() < etime;) {
+ a1logd(p->log, 4, "ss_init_coms: trying baud rate %d\n",i);
+ if ((se = p->icom->set_ser_port(p->icom, fc_none, brt[i], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "ss_init_coms: set_ser_port failed ICOM err 0x%x\n",se);
+ p->snerr = icoms2ss_err(se);
+ return ss_inst_err(p);
+ }
+
+ /* Try a SpectroScan Output Status */
+ ss_init_send(p);
+ ss_add_ssreq(p, ss_OutputStatus);
+ ss_command(p, SH_TMO);
+
+ if (ss_sub_1(p) == ss_AnsPFX) { /* Got comms */
+ p->itype = instSpectroScan; /* Preliminary */
+ break;
+ }
+
+ /* Try a Spectrolino Parameter Request */
+ ss_init_send(p);
+ ss_add_soreq(p, ss_ParameterRequest);
+ ss_command(p, SH_TMO);
+
+ if (ss_sub_1(p) == ss_ParameterAnswer) { /* Got comms */
+ p->itype = instSpectrolino;
+ break;
+ }
+
+ /* Check for user abort */
+ if (p->uicallback != NULL) {
+ inst_code ev;
+ if ((ev = p->uicallback(p->uic_cntx, inst_negcoms)) == inst_user_abort) {
+ a1logd(p->log, 1, "ss_init_coms: user aborted\n");
+ return inst_user_abort;
+ }
+ }
+
+ if (++i >= 7)
+ i = 0;
+ }
+ break; /* Got coms */
+ }
+
+ if (clock() >= etime) { /* We haven't established comms */
+ return inst_coms_fail;
+ }
+
+ a1logd(p->log, 4, "ss_init_coms: got basic communications\n");
+
+ /* Finalise the communications */
+ if (p->itype == instSpectrolino) {
+
+ if ((ev = so_do_MeasControlDownload(p, fcc1)) != inst_ok)
+ return ev;
+
+ /* Do baudrate change without checking results */
+ so_do_MeasControlDownload(p, sobrc[bi]);
+ if ((se = p->icom->set_ser_port(p->icom, fc, brt[bi], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "ss_init_coms: spectrolino set_ser_port failed ICOM err 0x%x\n",se);
+ p->snerr = icoms2ss_err(se);
+ return ss_inst_err(p);
+ }
+
+ } else { /* Spectroscan */
+
+ ss_do_SetDeviceOnline(p); /* Put the device online */
+
+ /* Make sure other communication parameters are right */
+ if ((ev = ss_do_ChangeHandshake(p, fcc2)) != inst_ok)
+ return ev;
+
+ /* Do baudrate change without checking results */
+ ss_do_ChangeBaudRate(p, ssbrc[bi]);
+ if ((se = p->icom->set_ser_port(p->icom, fc, brt[bi], parity_none,
+ stop_1, length_8)) != ICOM_OK) {
+ a1logd(p->log, 1, "ss_init_coms: spectroscan set_ser_port failed ICOM err 0x%x\n",se);
+ p->snerr = icoms2ss_err(se);
+ return ss_inst_err(p);
+ }
+
+ /* Make sure the Spectrolino is talking to us. */
+ if ((ev = ss_do_ScanSpectrolino(p)) != inst_ok) {
+ a1logd(p->log, 1, "ss_init_coms: spectroscan, instrument isn't communicating ICOM err 0x%x\n",se);
+ return ev;
+ }
+ }
+
+ a1logd(p->log, 4, "ss_init_coms: establish communications\n");
+
+ /* See if we have a Spectroscan or SpectroscanT, and get other details */
+ p->itype = instUnknown;
+ {
+ char devn[19];
+
+ ev = ss_do_OutputType(p, devn);
+
+ if (ev == inst_ok) {
+ a1logd(p->log, 5, "ss_init_coms: got device name '%s'\n",devn);
+ if (strncmp(devn, "SpectroScanT",12) == 0) {
+ p->itype = instSpectroScanT;
+ } else if (strncmp(devn, "SpectroScan",11) == 0) {
+ p->itype = instSpectroScan;
+ }
+ }
+ }
+ /* Check if there's a Spectrolino */
+ {
+ char devn[19];
+ int sn, sr, yp, mp, dp, hp, np; /* Date & Time of production */
+ int fswl, nosw, dsw; /* Wavelengths sampled */
+ ss_ttt tt; /* Target Type */
+
+ ev = so_do_TargetIdRequest(p, devn, &sn, &sr, &yp, &mp, &dp, &hp, &np,
+ &tt, &fswl, &nosw, &dsw);
+
+ if (ev == inst_ok) {
+
+ a1logd(p->log, 4, "ss_init_coms:\n"
+ " Got device name '%s'\n"
+ " Got target type '%d'\n"
+ " Start wl %d, no wl %d, wl space %d\n", devn ,tt, fswl, nosw, dsw);
+
+ /* "Spectrolino" and "Spectrolino 8mm" are known */
+ if (tt != ss_ttt_Spectrolino
+ || strncmp(devn, "Spectrolino",11) != 0)
+ return inst_unknown_model;
+
+ if (p->itype == instUnknown) /* No SpectrScan */
+ p->itype = instSpectrolino;
+ }
+ }
+
+#ifdef EMSST
+ a1logv(p->log, 0, "DEBUG: Emulating SpectroScanT with SpectroScan!\n");
+#endif
+
+ p->gotcoms = 1;
+
+ a1logd(p->log, 2, "ss_init_coms: init coms has suceeded\n");
+
+ return inst_ok;
+}
+
+/* Set the capabilities values for the type of instrument */
+static void ss_determine_capabilities(ss *p) {
+
+ /* Set the capabilities mask */
+ p->cap = inst_mode_ref_spot
+ | inst_mode_emis_spot
+ | inst_mode_emis_tele
+ | inst_mode_colorimeter
+ | inst_mode_spectral
+ ;
+
+ if (p->itype == instSpectrolino) {
+ p->cap |= inst_mode_trans_spot; /* Support this manually using a light table */
+ }
+
+ if (p->itype == instSpectroScan
+ || p->itype == instSpectroScanT) /* Only in reflective mode */
+ p->cap |= inst_mode_ref_xy;
+
+ if (p->itype == instSpectroScanT) {
+ p->cap |= inst_mode_trans_spot;
+ }
+
+ /* Set the capabilities mask 2 */
+ p->cap2 = inst2_prog_trig
+ | inst2_user_trig
+ | inst2_user_switch_trig
+ ;
+
+ if (p->itype == instSpectroScan
+ || p->itype == instSpectroScanT) {
+ /* These are not available in transmission mode */
+ if ((p->mode & inst_mode_illum_mask) != inst_mode_transmission) {
+ p->cap2 |= inst2_xy_holdrel
+ | inst2_xy_locate
+ | inst2_xy_position
+ ;
+ }
+ }
+
+ p->cap3 = inst3_none;
+
+ a1logd(p->log, 4, "ss_determine_capabilities got cap1 0x%x cap2 0x%x\n",p->cap,p->cap2);
+}
+
+/* Initialise the Spectrolino/SpectroScan. */
+/* return non-zero on an error, with dtp error code */
+static inst_code
+ss_init_inst(inst *pp) {
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+
+ a1logd(p->log, 2, "ss_init_inst: called\n");
+
+ if (p->gotcoms == 0)
+ return inst_internal_error; /* Must establish coms before calling init */
+
+ /* Reset the instrument to a known state */
+ if (p->itype != instSpectrolino) {
+
+ /* Initialise the device without resetting the baud rate */
+ if (p->itype == instSpectroScanT) {
+ if ((rv = ss_do_SetTableMode(p, ss_tmt_Reflectance)) != inst_ok)
+ return rv;
+ }
+ if ((rv = ss_do_SetDeviceOnline(p)) != inst_ok)
+ return rv;
+ if ((rv = ss_do_ResetKeyAcknowlge(p)) != inst_ok)
+ return rv;
+ if ((rv = ss_do_ReleasePaper(p)) != inst_ok)
+ return rv;
+ if ((rv = ss_do_InitMotorPosition(p)) != inst_ok)
+ return rv;
+
+ if (p->log->verb) {
+ char dn[19]; /* Device name */
+ unsigned int sn; /* Serial number */
+ char pn[9]; /* Part number */
+ int yp; /* Year of production (e.g. 1996) */
+ int mp; /* Month of production (1-12) */
+ int dp; /* Day of production (1-31) */
+ char sv[13]; /* Software version */
+
+ if ((rv = ss_do_OutputType(p, dn)) != inst_ok)
+ return rv;
+ if ((rv = ss_do_OutputSerialNumber(p, &sn)) != inst_ok)
+ return rv;
+ if ((rv = ss_do_OutputArticleNumber(p, pn)) != inst_ok)
+ return rv;
+ if ((rv = ss_do_OutputProductionDate(p, &yp, &mp, &dp)) != inst_ok)
+ return rv;
+ if ((rv = ss_do_OutputSoftwareVersion(p, sv)) != inst_ok)
+ return rv;
+
+ 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);
+ }
+ }
+ /* Do Spectrolino stuff */
+ if ((rv = so_do_ResetStatusDownload(p, ss_smt_InitWithoutRemote)) != inst_ok)
+ return rv;
+ 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 */
+ unsigned int sn; /* serial number */
+ char sv[13]; /* software release */
+ int yp; /* Year of production (e.g. 1996) */
+ int mp; /* Month of production (1-12) */
+ int dp; /* Day of production (1-31) */
+ char devn[19];
+ int sn2, sr, hp, np; /* Date & Time of production */
+ int fswl, nosw, dsw; /* Wavelengths sampled */
+ ss_ttt tt; /* Target Type */
+
+ if ((rv = so_do_DeviceDataRequest(p, dn, &dno, pn, &sn, sv)) != inst_ok)
+ return rv;
+
+ if ((rv = so_do_TargetIdRequest(p, devn, &sn2, &sr, &yp, &mp, &dp, &hp, &np,
+ &tt, &fswl, &nosw, &dsw)) != inst_ok)
+ return rv;
+
+ 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 */
+ if ((rv = so_do_ParameterDownload(p, p->dstd, p->wbase, p->illum, p->obsv)) != inst_ok)
+ return rv;
+
+ /* Set the capabilities masks */
+ ss_determine_capabilities(p);
+
+ /* Deactivate measurement switch */
+ if ((rv = so_do_TargetOnOffStDownload(p,ss_toost_Deactivated)) != inst_ok)
+ return rv;
+ p->trig = inst_opt_trig_user;
+
+ p->inited = 1;
+ a1logd(p->log, 2, "ss_init_inst: instrument inited OK\n");
+
+ return inst_ok;
+}
+
+/* For an xy instrument, release the paper */
+/* Return the inst error code */
+static inst_code
+ss_xy_sheet_release(
+struct _inst *pp) {
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->cap2 & inst2_xy_holdrel)
+ rv = ss_do_ReleasePaper(p);
+ return rv;
+}
+
+/* For an xy instrument, hold the paper */
+/* Return the inst error code */
+static inst_code
+ss_xy_sheet_hold(
+struct _inst *pp) {
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->cap2 & inst2_xy_holdrel)
+ rv = ss_do_HoldPaper(p);
+ return rv;
+}
+
+/* For an xy instrument, allow the user to locate a point */
+/* Return the inst error code */
+static inst_code
+ss_xy_locate_start(
+struct _inst *pp) {
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->cap2 & inst2_xy_locate) {
+ rv = ss_do_SetDeviceOffline(p);
+ p->offline = 1;
+ }
+ return rv;
+}
+
+/* For an xy instrument, position the reading point */
+/* Return the inst error code */
+static inst_code ss_xy_position(
+struct _inst *pp,
+int measure, /* nz if position measure point, z if locate point */
+double x, double y
+) {
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->cap2 & inst2_xy_position)
+ if ((rv = ss_do_MoveAbsolut(p, measure ? ss_rt_SensorRef : ss_rt_SightRef, x, y)) != inst_ok)
+ return rv;
+
+ return rv;
+}
+
+/* For an xy instrument, read back the location */
+/* Return the inst error code */
+static inst_code
+ss_xy_get_location(
+struct _inst *pp,
+double *x, double *y) {
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+ ss_rt rr;
+ ss_zkt zk;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->cap2 & inst2_xy_position)
+ if ((rv = ss_do_OutputActualPosition(p, ss_rt_SightRef, &rr, x, y, &zk)) != inst_ok)
+ return rv;
+
+ return rv;
+}
+
+/* For an xy instrument, ends allowing the user to locate a point */
+/* Return the inst error code */
+static inst_code
+ss_xy_locate_end(
+struct _inst *pp) {
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->cap2 & inst2_xy_position) {
+ rv = ss_do_SetDeviceOnline(p);
+ p->offline = 0;
+ }
+ return rv;
+}
+
+/* For an xy instrument, try and clear the table after an abort */
+/* Return the inst error code */
+static inst_code
+ss_xy_clear(
+struct _inst *pp) {
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->cap2 & inst2_xy_position) {
+ ss_do_SetDeviceOnline(p); /* Put the device online */
+ ss_do_MoveUp(p); /* Raise the sensor */
+ ss_do_ReleasePaper(p); /* Release the paper */
+ ss_do_MoveHome(p); /* Move to the home position */
+ }
+
+ return rv;
+}
+
+static inst_code ss_calibrate_imp(ss *p, inst_cal_type *calt, inst_cal_cond *calc, char id[CALIDLEN]);
+
+/* Read a sheet full of patches using xy mode */
+/* Return the inst error code */
+static inst_code
+ss_read_xy(
+inst *pp,
+int pis, /* Passes in strip (letters in sheet) */
+int sip, /* Steps in pass (numbers in sheet) */
+int npatch, /* Total patches in strip (skip in last pass) */
+char *pname, /* Starting pass name (' A' to 'ZZ') */
+char *sname, /* Starting step name (' 1' to '99') */
+double ox, double oy, /* Origin of first patch */
+double ax, double ay, /* pass increment */
+double aax, double aay, /* pass offset for odd patches */
+double px, double py, /* step/patch increment */
+ipatch *vals) { /* Pointer to array of values */
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+ int pass, step, patch;
+ int tries, tc; /* Total read tries */
+ int fstep = 0; /* NZ if step is fast & quiet direction */
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (p->itype != instSpectroScan
+ && p->itype != instSpectroScanT)
+ return inst_unsupported;
+
+ /* Move quickest in X direction to minimise noise, */
+ /* and maximise speed. This means we either increment the step or */
+ /* the pass fastest, depending on fstep. */
+ if (fabs(px) > fabs(ax)) {
+ fstep = 1;
+ p->pisrow = 2 * sip;
+ } else {
+ p->pisrow = 2 * pis;
+ }
+
+ tries = sip * pis; /* Total grid patch count. Not all may have real patches. */
+
+ /* Read all the patches */
+ for (step = pass = tc = 0; tc < tries; tc++) {
+ int astep, apass; /* Actual step and pass to use */
+ double ix, iy;
+
+ /* Move in serpentine order */
+ if (fstep) {
+ astep = (pass & 1) ? sip - 1 - step : step;
+ apass = pass;
+ } else {
+ astep = step;
+ apass = (step & 1) ? pis - 1 - pass : pass;
+ }
+
+ patch = apass * sip + astep;
+
+ if (patch < npatch) { /* Over a valid patch */
+ int try, notries = 5;
+
+ ix = ox + apass * ax + astep * px;
+ iy = oy + apass * ay + astep * py;
+
+ if ((step & 1) == 1) { /* Offset for odd hex patches */
+ ix += aax;
+ iy += aay;
+ }
+
+ /* Retry a reading if it fails. */
+ /* (Note that we actually check if retries have failed within the loop) */
+ for (try = 0; try < notries; try++) {
+
+ a1logd(p->log, 3, "ss_read_xy: fstep %d, astep/pass %d\n",
+ fstep, fstep ? astep : apass);
+ /* Do calibration if it is absolutely needed, or when it would */
+ /* avoid a long move. */
+ check_calcount(p, fstep ? (pass & 1) == 0 && step == 0 : (step & 1) == 0 && pass == 0);
+ if ( (p->need_wd_cal || p->need_t_cal) && p->noinitcalib == 0) {
+ inst_cal_type calt = inst_calt_needed;
+ inst_cal_cond calc = inst_calc_none;
+ char id[CALIDLEN];
+
+ /* We expect this to be automatic, but handle as if it mightn't be */
+ if ((rv = ss_calibrate_imp(p, &calt, &calc, id)) != inst_ok) {
+ if (rv == inst_cal_setup)
+ return inst_needs_cal; /* Not automatic, needs a manual setup */
+ if (try < notries) {
+ p->forcecalib = 1; /* Force a calibration */
+ inc_calcount(p); /* Set correct type of calib */
+ a1logv(p->log, 1, "Calibration failed, retrying...\n");
+ continue; /* Retry */
+ }
+ return rv; /* Error */
+ }
+ }
+
+ {
+ ss_rvt refvalid;
+ double col[3], spec[36];
+ int i;
+
+ vals[patch].loc[0] = '\000';
+ vals[patch].mtype = inst_mrt_none;
+ vals[patch].XYZ_v = 0;
+ vals[patch].sp.spec_n = 0;
+ vals[patch].duration = 0.0;
+
+ /* move and measure gives us spectrum data anyway */
+ if ((rv = ss_do_MoveAndMeasure(p, ix, iy, spec, &refvalid)) != inst_ok) {
+ if (try < notries) {
+ p->forcecalib = 1; /* Force a calibration */
+ inc_calcount(p); /* Set correct type of calib */
+ a1logv(p->log, 1, "Measurement failed, retrying...\n");
+ continue; /* Retry */
+ }
+ return rv; /* Error */
+ }
+
+ vals[patch].sp.spec_n = 36;
+ vals[patch].sp.spec_wl_short = 380;
+ vals[patch].sp.spec_wl_long = 730;
+ vals[patch].sp.norm = 100.0;
+
+ for (i = 0; i < vals[patch].sp.spec_n; i++)
+ vals[patch].sp.spec[i] = 100.0 * (double)spec[i];
+
+ /* Get the XYZ */
+ {
+ ss_cst rct;
+ ss_rvt rvf;
+ ss_aft af;
+ ss_wbt wb;
+ ss_ilt it;
+ ss_ot ot;
+
+ if ((rv = so_do_CParameterRequest(p, ss_cst_XYZ, &rct, col, &rvf,
+ &af, &wb, &it, &ot)) != inst_ok
+ || rvf != ss_rvt_True) {
+ if (try < notries) {
+ p->forcecalib = 1; /* Force a calibration */
+ inc_calcount(p); /* Set correct type of calib */
+ a1logv(p->log, 1, "XYZ reading failed, retrying...\n");
+ continue; /* Retry */
+ }
+ return rv; /* Error */
+ }
+ }
+ vals[patch].XYZ_v = 1;
+ vals[patch].XYZ[0] = col[0];
+ vals[patch].XYZ[1] = col[1];
+ vals[patch].XYZ[2] = col[2];
+
+ /* Track the need for a calibration */
+ inc_calcount(p);
+
+ break; /* Don't need to retry */
+ }
+ } /* Retry */
+ }
+
+ /* Move on to the next patch */
+ if (fstep) {
+ if (++step >= sip) {
+ step = 0;
+ pass++;
+ }
+ } else {
+ if (++pass >= pis) {
+ pass = 0;
+ step++;
+ }
+ }
+ }
+
+ return rv;
+}
+
+/* Read a set of strips */
+/* Return the inst error code */
+static inst_code
+ss_read_strip(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+int npatch, /* Number of patches in the pass */
+char *pname, /* Pass name (3 chars) */
+int sguide, /* Guide number */
+double pwid, /* Patch length in mm (For DTP41) */
+double gwid, /* Gap length in mm (For DTP41) */
+double twid, /* Trailer length in mm (For DTP41T) */
+ipatch *vals) { /* Pointer to array of instrument patch values */
+// ss *p = (ss *)pp;
+ inst_code rv = inst_unsupported;
+ return rv;
+}
+
+
+/* Observer weightings for Spectrolino spectrum, 380 .. 730 nm in 10nm steps */
+/* 1931 2 degree/10 degree, X, Y, Z */
+/* Derived from the 1mm CIE data by integrating over +/- 5nm */
+double obsv[2][3][36] = {
+ {
+ {
+ 0.001393497640, 0.004448031900, 0.014518206300, 0.045720800000, 0.138923633000,
+ 0.279645970000, 0.344841960000, 0.335387990000, 0.288918940000, 0.196038970000,
+ 0.097089264500, 0.033433134500, 0.006117900200, 0.011512466000, 0.065321232000,
+ 0.166161125000, 0.291199155000, 0.434290495000, 0.594727005000, 0.761531500000,
+ 0.914317000000, 1.023460340000, 1.058604000000, 0.999075000000, 0.851037990000,
+ 0.644076660000, 0.449047000000, 0.285682340000, 0.166610680000, 0.089139475000,
+ 0.047203532000, 0.023272100000, 0.011556993000, 0.005897781550, 0.002960988050,
+ 0.001468472565
+ },
+ {
+ 0.000040014416, 0.000126320071, 0.000402526680, 0.001272963400, 0.004268400000,
+ 0.011759799700, 0.023092867000, 0.038306468000, 0.060303866000, 0.091762739000,
+ 0.139594730000, 0.210065540000, 0.326613130000, 0.504776000000, 0.706552500000,
+ 0.859214005000, 0.951809665000, 0.993340440000, 0.993019710000, 0.950281660000,
+ 0.868557660000, 0.756550000000, 0.630964340000, 0.503366340000, 0.380962000000,
+ 0.266444660000, 0.175871340000, 0.108002605000, 0.061709066000, 0.032657466000,
+ 0.017165009000, 0.008419183400, 0.004173919800, 0.002129796800, 0.001069267000,
+ 0.000530292340
+ },
+ {
+ 0.006568973000, 0.021026087500, 0.068865635000, 0.218090190000, 0.668415545000,
+ 1.366703205000, 1.731816230000, 1.769890130000, 1.658588340000, 1.288104470000,
+ 0.818359800000, 0.471791600000, 0.275824200000, 0.159485840000, 0.080436864500,
+ 0.042599734500, 0.020750932000, 0.009028633450, 0.004015999900, 0.002160166550,
+ 0.001629500100, 0.001143333400, 0.000804400000, 0.000372600000, 0.000180700000,
+ 0.000054966665, 0.000019933332, 0.000002266667, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000
+ }
+ },
+ {
+ {
+ 0.000221161200, 0.002892312000, 0.021223545000, 0.087243800000, 0.203891450000,
+ 0.313689500000, 0.379737550000, 0.368800750000, 0.301126300000, 0.194835400000,
+ 0.082524250000, 0.018557800000, 0.006085000000, 0.039474500000, 0.119180250000,
+ 0.237142500000, 0.377122750000, 0.531279950000, 0.705108350000, 0.876453800000,
+ 1.013894200000, 1.113552000000, 1.119829000000, 1.026837000000, 0.855199200000,
+ 0.646495700000, 0.434312700000, 0.270230400000, 0.154505300000, 0.082548760000,
+ 0.041674230000, 0.020379080000, 0.009795728000, 0.004661858000, 0.002225776000,
+ 0.001069074500
+ },
+ {
+ 0.000023956650, 0.000309054000, 0.002220395000, 0.009005150000, 0.021600050000,
+ 0.038992450000, 0.062072600000, 0.089764700000, 0.128515350000, 0.185550850000,
+ 0.255690850000, 0.342051100000, 0.461805650000, 0.607378100000, 0.759122200000,
+ 0.874795100000, 0.958787300000, 0.991541600000, 0.995046500000, 0.953158750000,
+ 0.869616900000, 0.775837500000, 0.657942650000, 0.527902700000, 0.399013000000,
+ 0.283553200000, 0.181354350000, 0.108672400000, 0.061082550000, 0.032323865000,
+ 0.016231270000, 0.007919470000, 0.003803046000, 0.001810832500, 0.000865886500,
+ 0.000416835450
+ },
+ {
+ 0.000975787600, 0.012867500000, 0.095777190000, 0.402301600000, 0.971629200000,
+ 1.549938000000, 1.948388000000, 1.984670000000, 1.739857000000, 1.308151000000,
+ 0.781796500000, 0.422593900000, 0.222878650000, 0.115174050000, 0.061302800000,
+ 0.030879300000, 0.013841200000, 0.004144350000, 0.000189450000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000
+ }
+ }
+};
+
+/* Read a single sample */
+/* Return the dtp error code */
+static inst_code
+ss_read_sample(
+inst *pp,
+char *name, /* Strip name (7 chars) */
+ipatch *val, /* Pointer to instrument patch value */
+instClamping clamp) { /* NZ if clamp XYZ/Lab to be +ve */
+ ss *p = (ss *)pp;
+ inst_code rv = inst_ok;
+ int switch_trig = 0;
+ int user_trig = 0;
+ double col[3], spec[36];
+ int i;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ if (!val)
+ return inst_internal_error;
+
+ a1logd(p->log, 4, "ss_read_sample()\n");
+
+ val->loc[0] = '\000';
+ val->XYZ_v = 0;
+ val->sp.spec_n = 0;
+ val->duration = 0.0;
+
+ /* Do calibration if it is needed */
+ if ((p->need_wd_cal || p->need_t_cal) && p->noinitcalib == 0) {
+ inst_cal_type calt = inst_calt_needed;
+ inst_cal_cond calc = inst_calc_none;
+ char id[CALIDLEN];
+
+ /* This could be automatic or need manual intervention */
+ if ((rv = ss_calibrate_imp(p, &calt, &calc, id)) != inst_ok) {
+ if (rv == inst_cal_setup) {
+ return inst_needs_cal; /* Not automatic, needs a manual setup */
+ }
+ return rv; /* Error */
+ }
+ }
+
+ if (p->trig == inst_opt_trig_user_switch) {
+
+ a1logd(p->log, 4, "inst_opt_trig_user_switch\n");
+
+ /* We're assuming that switch trigger won't be selected */
+ /* for spot measurement on the spectroscan, so we don't lower the head. */
+
+ /* Activate measurement switch */
+ if ((rv = so_do_TargetOnOffStDownload(p,ss_toost_Activated)) != inst_ok) {
+ return rv;
+ }
+
+ /* Wait for a measurement or for the user to hit a key */
+ for (;;) {
+ ss_nmt nm;
+
+ /* Query whether a new measurement was performed since the last */
+ if ((rv = so_do_NewMeasureRequest(p, &nm)) != inst_ok) {
+ return rv; /* Error */
+ }
+ if (nm == ss_nmt_NewMeas) {
+ switch_trig = 1;
+ break;
+ }
+ /* If SpectroScanT transmission, poll the enter key */
+ if (p->itype == instSpectroScanT
+ && (p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ ss_sks sk;
+ ss_ptt pt;
+ if ((rv = ss_do_OutputActualKey(p, &sk, &pt)) == inst_ok
+ && sk == ss_sks_EnterKey) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+
+ if (p->uicallback != NULL) { /* Check for user trigger */
+ if ((rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rv == inst_user_abort)
+ return rv; /* Abort */
+ if (rv == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ }
+ }
+
+ /* Deactivate measurement switch */
+ if ((rv = so_do_TargetOnOffStDownload(p,ss_toost_Deactivated)) != inst_ok)
+ return rv;
+
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ } else if (p->trig == inst_opt_trig_user) {
+
+ a1logd(p->log, 4, "inst_opt_trig_user\n");
+
+ if (p->uicallback == NULL) {
+ a1logd(p->log, 1, "ss: inst_opt_trig_user but no uicallback function set!\n");
+ return inst_unsupported;
+ }
+
+ for (;;) {
+ if ((rv = p->uicallback(p->uic_cntx, inst_armed)) != inst_ok) {
+ if (rv == inst_user_abort)
+ return rv; /* Abort */
+ if (rv == inst_user_trig) {
+ user_trig = 1;
+ break; /* Trigger */
+ }
+ }
+ msec_sleep(200);
+ }
+ /* Notify of trigger */
+ if (p->uicallback)
+ p->uicallback(p->uic_cntx, inst_triggered);
+
+ /* Progromatic Trigger */
+ } else {
+ a1logd(p->log, 4, "program trigger\n");
+
+ /* Check for abort */
+ if (p->uicallback != NULL
+ && (rv = p->uicallback(p->uic_cntx, inst_armed)) == inst_user_abort)
+ return rv; /* Abort */
+ }
+
+ /* Trigger a read if the switch has not been used */
+ if (switch_trig == 0) {
+ ss_nmt nm;
+
+ a1logd(p->log, 4, "starting a read because switch wasn't used\n");
+
+ /* For the spectroscan, make sure the instrument is on line, */
+ /* since it may be off line to allow the user to position it. */
+ if (p->itype != instSpectrolino && p->offline) {
+ if ((rv = p->xy_locate_end((inst *)p)) != inst_ok)
+ return rv;
+ }
+
+ /* For reflection spot mode on a SpectroScan, lower the head. */
+ /* (A SpectroScanT in transmission will position automatically) */
+ if (p->itype != instSpectrolino
+ && (p->mode & inst_mode_illum_mask) != inst_mode_transmission) {
+ if ((rv = ss_do_MoveDown(p)) != inst_ok)
+ return rv;
+ }
+
+ /* trigger it in software */
+ if ((rv = so_do_ExecMeasurement(p)) != inst_ok)
+ return rv;
+ /* Query measurement to reset count */
+ if ((rv = so_do_NewMeasureRequest(p, &nm)) != inst_ok)
+ return rv;
+
+ /* For reflection spot mode on a SpectroScan, raise the head. */
+ /* (A SpectroScanT in transmission will position automatically) */
+ if (p->itype != instSpectrolino
+ && (p->mode & inst_mode_illum_mask) != inst_mode_transmission) {
+ if ((rv = ss_do_MoveUp(p)) != inst_ok)
+ return rv;
+ }
+ }
+
+ /* Track the need for a calibration */
+ inc_calcount(p);
+
+ /* Get the XYZ: */
+
+ /* Emulated spot transmission mode: */
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission
+ && p->itype == instSpectrolino) {
+ ss_st rst; /* Return Spectrum Type (Reflectance/Density) */
+ ss_rvt rvf; /* Return Reference Valid Flag */
+ ss_aft af; /* Return filter being used (None/Pol/D65/UV/custom */
+ ss_wbt wb; /* Return white base (Paper/Absolute) */
+ double norm; /* Y normalisation factor */
+ int j, tix = 0; /* Default 2 degree */
+
+ /* Get the spectrum */
+ if ((rv = so_do_SpecParameterRequest(p, ss_st_LinearSpectrum,
+ &rst, spec, &rvf, &af, &wb)) != inst_ok)
+ return rv;
+
+ /* Divide by transmission white reference to get transmission level. */
+ for (i = 0; i < 36; i++) {
+ if (p->tref[i] >= 0.0001)
+ spec[i] = spec[i]/p->tref[i];
+ else
+ spec[i] = 0.0;
+ }
+
+ if (p->mode & inst_mode_spectral) {
+ val->sp.spec_n = 36;
+ val->sp.spec_wl_short = 380;
+ val->sp.spec_wl_long = 730;
+ val->sp.norm = 100.0;
+ for (i = 0; i < val->sp.spec_n; i++)
+ val->sp.spec[i] = 100.0 * (double)spec[i];
+ }
+
+ /* Convert to desired illuminant XYZ */
+ val->XYZ[0] = 0.0;
+ val->XYZ[1] = 0.0;
+ val->XYZ[2] = 0.0;
+ if (p->obsv == ss_ot_TenDeg)
+ tix = 1;
+
+ /* Compute normalisation factor */
+ for (norm = 0.0, i = 0; i < 36; i++) {
+ if (p->tref[i] >= 0.0001)
+ norm += obsv[tix][1][i] * p->cill[i];
+ }
+ norm = 100.0/norm;
+
+ /* Compute XYZ */
+ for (i = 0; i < 36; i++) {
+ if (p->tref[i] >= 0.0001) {
+ for (j = 0; j < 3; j++)
+ val->XYZ[j] += obsv[tix][j][i] * p->cill[i] * spec[i];
+ }
+ }
+ for (j = 0; j < 3; j++)
+ val->XYZ[j] *= norm;
+
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(val->XYZ, val->XYZ);
+
+ val->XYZ_v = 1;
+ val->mtype = inst_mrt_transmissive;
+
+
+ /* Using filter compensation */
+ /* This isn't applicable to emulated transmission mode, because */
+ /* the filter will be calibrated out in the illuminant measurement. */
+ } else if (p->compen != 0) {
+ ss_cst rct;
+ ss_st rst; /* Return Spectrum Type (Reflectance/Density) */
+ ss_rvt rvf; /* Return Reference Valid Flag */
+ ss_aft af; /* Return filter being used (None/Pol/D65/UV/custom */
+ ss_ilt it;
+ ss_ot ot;
+ ss_wbt wb; /* Return white base (Paper/Absolute) */
+#ifdef NEVER
+ double norm; /* Y normalisation factor */
+#endif
+ double XYZ[3];
+ int j, tix = 0; /* Default 2 degree */
+
+ /* Get the XYZ */
+ if ((rv = so_do_CParameterRequest(p, ss_cst_XYZ, &rct, col, &rvf,
+ &af, &wb, &it, &ot)) != inst_ok)
+ return rv;
+
+ /* Get the spectrum */
+ if ((rv = so_do_SpecParameterRequest(p, ss_st_LinearSpectrum,
+ &rst, spec, &rvf, &af, &wb)) != inst_ok)
+ return rv;
+
+ /* Multiply by the filter compensation values to do correction */
+ for (i = 0; i < 36; i++) {
+ spec[i] *= p->comp[i];
+ }
+
+ /* Return the results */
+ if (p->mode & inst_mode_spectral) {
+ val->sp.spec_n = 36;
+ val->sp.spec_wl_short = 380;
+ val->sp.spec_wl_long = 730;
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_emission) {
+ val->sp.norm = 1.0;
+ for (i = 0; i < val->sp.spec_n; i++)
+ val->sp.spec[i] = (double)spec[i];
+ } else {
+ val->sp.norm = 100.0;
+ for (i = 0; i < val->sp.spec_n; i++)
+ val->sp.spec[i] = 100.0 * (double)spec[i];
+ }
+ }
+
+ /* Convert to desired illuminant XYZ */
+ if (p->obsv == ss_ot_TenDeg)
+ tix = 1;
+
+ /* Compute XYZ */
+ for (j = 0; j < 3; j++)
+ XYZ[j] = 0.0;
+ for (i = 0; i < 36; i++)
+ for (j = 0; j < 3; j++)
+ XYZ[j] += obsv[tix][j][i] * spec[i];
+
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(XYZ, XYZ);
+
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_emission) {
+ /* Emission XYZ seems to be Luminous Watts, so */
+ /* convert to cd/m^2 */
+ val->XYZ_v = 1;
+ val->XYZ[0] = XYZ[0] * 683.002;
+ val->XYZ[1] = XYZ[1] * 683.002;
+ val->XYZ[2] = XYZ[2] * 683.002;
+ val->mtype = inst_mrt_emission;
+ } else {
+ val->XYZ_v = 1;
+ val->XYZ[0] = XYZ[0];
+ val->XYZ[1] = XYZ[1];
+ val->XYZ[2] = XYZ[2];
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission)
+ val->mtype = inst_mrt_transmissive;
+ else
+ val->mtype = inst_mrt_reflective;
+ }
+
+ /* Normal instrument values */
+ } else {
+ ss_cst rct;
+ ss_rvt rvf;
+ ss_aft af;
+ ss_wbt wb;
+ ss_ilt it;
+ ss_ot ot;
+
+ if ((rv = so_do_CParameterRequest(p, ss_cst_XYZ, &rct, col, &rvf,
+ &af, &wb, &it, &ot)) != inst_ok)
+ return rv;
+
+ /* This may not change anything since instrument may clamp */
+ if (clamp)
+ icmClamp3(col, col);
+
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_emission) {
+ val->XYZ_v = 1;
+ val->XYZ[0] = col[0];
+ val->XYZ[1] = col[1];
+ val->XYZ[2] = col[2];
+ val->mtype = inst_mrt_emission;
+ } else {
+ val->XYZ_v = 1;
+ val->XYZ[0] = col[0];
+ val->XYZ[1] = col[1];
+ val->XYZ[2] = col[2];
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission)
+ val->mtype = inst_mrt_transmissive;
+ else
+ val->mtype = inst_mrt_reflective;
+ }
+
+ /* spectrum data is returned only if requested */
+ if (p->mode & inst_mode_spectral) {
+ ss_st rst; /* Return Spectrum Type (Reflectance/Density) */
+ ss_rvt rvf; /* Return Reference Valid Flag */
+ ss_aft af; /* Return filter being used (None/Pol/D65/UV/custom */
+ ss_wbt wb; /* Return white base (Paper/Absolute) */
+
+ if ((rv = so_do_SpecParameterRequest(p, ss_st_LinearSpectrum,
+ &rst, spec, &rvf, &af, &wb)) != inst_ok)
+ return rv;
+
+ val->sp.spec_n = 36;
+ val->sp.spec_wl_short = 380;
+ val->sp.spec_wl_long = 730;
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_emission) {
+ /* Spectral data is in mW/nm/m^2 interpolated to 10nm spacing */
+ val->sp.norm = 1.0;
+ for (i = 0; i < val->sp.spec_n; i++)
+ val->sp.spec[i] = (double)spec[i];
+ } else {
+ val->sp.norm = 100.0;
+ for (i = 0; i < val->sp.spec_n; i++)
+ val->sp.spec[i] = 100.0 * (double)spec[i];
+ }
+ }
+ }
+ if (user_trig)
+ return inst_user_trig;
+ return rv;
+}
+
+/* Return needed and available inst_cal_type's */
+static inst_code ss_get_n_a_cals(inst *pp, inst_cal_type *pn_cals, inst_cal_type *pa_cals) {
+ ss *p = (ss *)pp;
+ inst_cal_type n_cals = inst_calt_none;
+ inst_cal_type a_cals = inst_calt_none;
+
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ if (p->itype == instSpectrolino) { /* Emulated transmission */
+ if (p->need_wd_cal && p->noinitcalib == 0)
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+ if (p->need_t_cal) /* We aren't saving trans white ref */
+ n_cals |= inst_calt_trans_vwhite;
+ a_cals |= inst_calt_trans_vwhite;
+ } else { /* SpectroscanT */
+ if (p->need_wd_cal && p->noinitcalib == 0)
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+ if (p->need_t_cal && p->noinitcalib == 0)
+ n_cals |= inst_calt_trans_white;
+ a_cals |= inst_calt_trans_white;
+ }
+
+ } else {
+ if (p->need_wd_cal && p->noinitcalib == 0)
+ n_cals |= inst_calt_ref_white;
+ a_cals |= inst_calt_ref_white;
+ }
+
+ if (pn_cals != NULL)
+ *pn_cals = n_cals;
+
+ if (pa_cals != NULL)
+ *pa_cals = a_cals;
+
+ return inst_ok;
+}
+
+/* Perform an instrument calibration (implementation). */
+static inst_code ss_calibrate_imp(
+ss *p,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ inst_code rv = inst_ok;
+ ss_aft afilt; /* Actual filter */
+ double sp[36]; /* Spectral values of filter */
+ ss_owrt owr; /* Original white reference */
+ inst_cal_type needed, available;
+
+ id[0] = '\000';
+
+ a1logd(p->log, 3, "ss calibrate called with calt = 0x%x, condition 0x%x, need w %d, t %d\n", *calt, *calc, p->need_wd_cal, p->need_t_cal);
+
+ if ((rv = ss_get_n_a_cals((inst *)p, &needed, &available)) != inst_ok)
+ return rv;
+
+ /* Translate inst_calt_all/needed into something specific */
+ if (*calt == inst_calt_all
+ || *calt == inst_calt_needed
+ || *calt == inst_calt_available) {
+ if (*calt == inst_calt_all)
+ *calt = (needed & inst_calt_n_dfrble_mask) | inst_calt_ap_flag;
+ else if (*calt == inst_calt_needed)
+ *calt = needed & inst_calt_n_dfrble_mask;
+ else if (*calt == inst_calt_available)
+ *calt = available & inst_calt_n_dfrble_mask;
+
+ a1logd(p->log,4,"ss_imp_calibrate: doing calt 0x%x\n",*calt);
+
+ if ((*calt & inst_calt_n_dfrble_mask) == 0) /* Nothing todo */
+ return inst_ok;
+ }
+
+ /* See if it's a calibration we understand */
+ if (*calt & ~available & inst_calt_all_mask) {
+ return inst_unsupported;
+ }
+
+ /* There are different procedures depending on the intended mode, */
+ /* whether this is a Spectrolino or SpectrScan, and whether just a white, */
+ /* or a transmission calibration are needed or both. */
+
+ /* All first time calibrations do an initial reflective white calibration. */
+ if (*calt & inst_calt_ref_white) {
+
+ a1logd(p->log, 3, "ss cal dealing with being on ref_white\n");
+
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_emission)
+ p->filt = ss_aft_NoFilter; /* Need no filter for emission */
+
+ /* Set mode to reflection as a default for calibration */
+ if (p->itype == instSpectroScanT) {
+ if ((rv = ss_do_SetTableMode(p, ss_tmt_Reflectance)) != inst_ok)
+ return rv;
+ } else {
+ if ((rv = so_do_MeasControlDownload(p, ss_ctt_RemissionMeas)) != inst_ok)
+ return rv;
+ }
+
+ /* Set the desired colorimetric parameters + absolute white base */
+ if ((rv = so_do_ParameterDownload(p, p->dstd, ss_wbt_Abs, p->illum, p->obsv)) != inst_ok)
+ return rv;
+
+ /* Get the name of the expected white reference */
+ if ((rv = so_do_WhiteReferenceRequest(p, p->filt, &afilt, sp, &owr, id)) != inst_ok)
+ return rv;
+
+ if (p->noinitcalib == 0) {
+
+ /* Make sure we're in a condition to do the calibration */
+ if (p->itype == instSpectrolino && *calc != inst_calc_man_ref_white) {
+ *calc = inst_calc_man_ref_white;
+ a1logd(p->log, 3, "ss cal need cond. inst_calc_man_ref_white and haven't got it\n");
+ return inst_cal_setup;
+ }
+
+ /* Do the white calibration */
+ for (;;) { /* Untill everything is OK */
+
+ a1logd(p->log, 3, "ss cal doing white reflective cal\n");
+ /* For SpectroScan, move to the white reference in slot 1 and lower */
+ if (p->itype != instSpectrolino) {
+ if ((rv = ss_do_MoveToWhiteRefPos(p, ss_wrpt_RefTile1)) != inst_ok)
+ return rv;
+ if ((rv = ss_do_MoveDown(p)) != inst_ok)
+ return rv;
+ }
+
+ /* Calibrate */
+ if ((rv = so_do_ExecRefMeasurement(p, ss_mmt_WhiteCalWithWarn))
+ != (inst_notify | ss_et_WhiteMeasOK))
+ return rv;
+ rv = inst_ok;
+
+ /* For SpectroScan, raise */
+ if (p->itype != instSpectrolino) {
+ if ((rv = ss_do_MoveUp(p)) != inst_ok)
+ return rv;
+ }
+
+ /* Verify the filter. */
+ {
+ ss_dst ds;
+ ss_wbt wb;
+ ss_ilt it;
+ ss_ot ot;
+ ss_aft af;
+
+ if ((rv = so_do_ParameterRequest(p, &ds, &wb, &it, &ot, &af)) != inst_ok)
+ return rv;
+ if (af == p->filt)
+ break;
+
+ a1logd(p->log, 3, "got filt %d, want %d\n",af,p->filt);
+
+ strcpy(id, filter_desc[p->filt]);
+ *calc = inst_calc_change_filter;
+ return inst_cal_setup;
+ }
+ }
+ a1logd(p->log, 3, "reflection calibration and filter verify is complete\n");
+
+ /* Emission or spot transmission mode, dark calibration. */
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_emission
+ || ((p->mode & inst_mode_illum_mask) == inst_mode_transmission
+ && p->itype == instSpectrolino)) {
+ a1logd(p->log, 3, "emmission/transmission dark calibration:\n");
+ /* Set emission mode */
+ if ((rv = so_do_MeasControlDownload(p, ss_ctt_EmissionMeas)) != inst_ok)
+ return rv;
+ if (p->noinitcalib == 0) {
+ /* Do dark calibration (Assume we're still on white reference) */
+ if ((rv = so_do_ExecRefMeasurement(p, ss_mmt_EmissionCal))
+ != (inst_notify | ss_et_EmissionCalOK))
+ return rv;
+ }
+ rv = inst_ok;
+ a1logd(p->log, 3, "emmission/transmisson dark calibration done\n");
+ }
+
+ p->calcount = 0;
+ p->need_wd_cal = 0;
+ }
+
+ /* Restore the instrument to the desired mode */
+ /* SpectroScanT - Transmission mode, set transmission mode. */
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission
+ && p->itype == instSpectroScanT) {
+
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ if ((rv = ss_do_SetTableMode(p, ss_tmt_Transmission)) != inst_ok)
+ return rv;
+ }
+ }
+ *calt &= ~inst_calt_ref_white;
+ }
+
+ /* ??? If White Base Type is not Absolute, where is Paper type set, */
+ /* and how is it calibrated ????? */
+
+ /* For non-reflective measurement, do the recalibration or 2nd part of calibration. */
+
+ /* Transmission mode calibration: */
+ if ((*calt & (inst_calt_trans_vwhite | inst_calt_trans_white))
+ && (p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+
+ a1logd(p->log, 3, "ss cal need trans with calt = trans_white\n");
+ /* Emulated spot transmission using spectrolino */
+ if ((*calt & inst_calt_trans_vwhite) && p->itype == instSpectrolino) {
+ ss_st rst; /* Return Spectrum Type (Reflectance/Density) */
+ ss_rvt rvf; /* Return Reference Valid Flag */
+ ss_aft af; /* Return filter being used (None/Pol/D65/UV/custom */
+ ss_wbt wb; /* Return white base (Paper/Absolute) */
+ ss_ilt it; /* Return illuminant type */
+ int i;
+
+ a1logd(p->log, 3, "ss cal need trans, spectrolino\n");
+ /* Make sure we're in a condition to do the calibration */
+ if (*calc != inst_calc_man_trans_white) {
+ *calc = inst_calc_man_trans_white;
+ a1logd(p->log, 3, "ss cal need cond. inst_calc_man_trans_white and haven't got it\n");
+ return inst_cal_setup;
+ }
+
+ /* Measure white reference spectrum */
+ if ((rv = so_do_ExecMeasurement(p)) != inst_ok)
+ return rv;
+ if ((rv = so_do_SpecParameterRequest(p, ss_st_LinearSpectrum,
+ &rst, p->tref, &rvf, &af, &wb)) != inst_ok)
+ return rv;
+
+ so_do_NewMeasureRequest(p, NULL); /* flush pending measurement */
+
+ /* See how good a source it is */
+ for (i = 0; i < 36; i++) {
+ if (p->tref[i] < 0.0001)
+ break;
+ }
+
+ if (i < 36) {
+ *calc = inst_calc_message;
+ strcpy(id, "Warning: Transmission light source is low at some wavelengths!");
+ rv = inst_ok;
+ }
+
+ /* Get the instrument illuminant */
+ if ((rv = so_do_IllumTabRequest(p, p->illum, &it, p->cill)) != inst_ok)
+ return rv;
+
+ p->calcount = 0;
+ p->need_t_cal = 0;
+ a1logd(p->log, 3, "transmission lino cal done\n");
+
+ /* SpectroScanT */
+ } else if ((*calt & inst_calt_trans_white) && p->itype != instSpectrolino) {
+ /* Hmm. Should we really return a message and resume somehow, */
+ /* rather than communicating directly with the user... */
+
+ a1logd(p->log, 3, "transmission scan cal being done\n");
+#ifdef NEVER
+ /* Advise user to change aperture before switching to transmission mode. */
+ p->message_user((inst *)p, "\nEnsure that desired transmission aperture is fitted,\n"
+ "and press space to continue:\n");
+ p->poll_user((inst *)p, 1);
+#else
+ a1logv(p->log,1,"It is assumed that the desired transmission aperture is fitted\n");
+#endif
+ /* Presuming this is the right return code */
+ if ((rv = so_do_ExecRefMeasurement(p, ss_mmt_WhiteCalWithWarn))
+ != (inst_notify | ss_et_WhiteMeasOK))
+ return rv;
+ rv = inst_ok;
+ p->calcount = 0;
+ p->need_t_cal = 0;
+ a1logd(p->log, 3, "transmission scan cal done\n");
+ }
+ *calt &= ~(inst_calt_trans_vwhite | inst_calt_trans_white);
+ }
+
+ a1logd(p->log, 3, "calibration completed\n");
+ return rv;
+}
+
+/* Request an instrument calibration. */
+/* This is use if the user decides they want to do a calibration, */
+/* in anticipation of a calibration (needs_calibration()) to avoid */
+/* requiring one during measurement, or in response to measuring */
+/* returning inst_needs_cal. Initially use an inst_cal_cond of inst_calc_none, */
+/* and then be prepared to setup the right conditions, or ask the */
+/* user to do so, each time the error inst_cal_setup is returned. */
+inst_code ss_calibrate(
+inst *pp,
+inst_cal_type *calt, /* Calibration type to do/remaining */
+inst_cal_cond *calc, /* Current condition/desired condition */
+char id[CALIDLEN] /* Condition identifier (ie. white reference ID) */
+) {
+ ss *p = (ss *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ return ss_calibrate_imp(p, calt, calc, id);
+}
+
+/* Insert a compensation filter in the instrument readings */
+/* This is typically needed if an adapter is being used, that alters */
+/* the spectrum of the light reaching the instrument */
+/* To remove the filter, pass NULL for the filter filename */
+inst_code ss_comp_filter(
+struct _inst *pp,
+char *filtername
+) {
+ ss *p = (ss *)pp;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+#ifndef SALONEINSTLIB
+ if (filtername == NULL) {
+ p->compen = 0;
+ } else {
+ xspect sp;
+ int i;
+ if (read_xspect(&sp, filtername) != 0) {
+ return inst_wrong_setup;
+ }
+ if (sp.spec_n != 36 || sp.spec_wl_short != 380.0 || sp.spec_wl_long != 730.0) {
+ return inst_wrong_setup;
+ }
+ for (i = 0; i < 36; i++)
+ p->comp[i] = sp.spec[i];
+ p->compen = 1;
+ }
+ return inst_ok;
+#else /* SALONEINSTLIB */
+ return inst_unsupported;
+#endif /* SALONEINSTLIB */
+}
+
+/* Instrument specific error codes interpretation */
+static char *
+ss_interp_error(inst *pp, int ec) {
+// ss *p = (ss *)pp;
+ ec &= inst_imask;
+
+ switch (ec) {
+
+ /* Device errors */
+ case ss_et_NoError:
+ return "No device error";
+ case ss_et_MemoryFailure:
+ return "Memory failure";
+ case ss_et_PowerFailure:
+ return "Power failure";
+ case ss_et_LampFailure:
+ return "Lamp failure";
+ case ss_et_HardwareFailure:
+ return "Hardware failure";
+ case ss_et_FilterOutOfPos:
+ return "Filter wheel out of position";
+ case ss_et_SendTimeout:
+ return "Data transmission timout";
+ case ss_et_DriveError:
+ return "Data drive defect";
+ case ss_et_MeasDisabled:
+ return "Measuring disabled";
+ case ss_et_DensCalError:
+ return "Incorrect input during densitometric calibration";
+ case ss_et_EPROMFailure:
+ return "Defective EPROM";
+ case ss_et_RemOverFlow:
+ return "Too much light or wrong white calibration";
+ case ss_et_MemoryError:
+ return "Checksum error in memory";
+ case ss_et_FullMemory:
+ return "Memory is full";
+ case ss_et_WhiteMeasOK:
+ return "White measurement is OK";
+ case ss_et_NotReady:
+ return "Instrument is not ready - please wait";
+ case ss_et_WhiteMeasWarn:
+ return "White measurement warning";
+ case ss_et_ResetDone:
+ return "Reset is done";
+ case ss_et_EmissionCalOK:
+ return "Emission calibration is OK";
+ case ss_et_OnlyEmission:
+ return "Only for emission (not reflection)";
+ case ss_et_CheckSumWrong:
+ return "Wrong checksum";
+ case ss_et_NoValidMeas:
+ return "No valid measurement (e.g. no white measurement)";
+ case ss_et_BackupError:
+ return "Error in backing up values";
+ case ss_et_ProgramROMError:
+ return "Errors in programming ROM";
+
+ /* Incorporate remote error set codes thus: */
+ case ss_et_NoValidDStd:
+ return "No valid Density standard set";
+ case ss_et_NoValidWhite:
+ return "No valid White standard set";
+ case ss_et_NoValidIllum:
+ return "No valid Illumination set";
+ case ss_et_NoValidObserver:
+ return "No valid Observer set";
+ case ss_et_NoValidMaxLambda:
+ return "No valid maximum Lambda set";
+ case ss_et_NoValidSpect:
+ return "No valid spectrum";
+ case ss_et_NoValidColSysOrIndex:
+ return "No valid color system or index";
+ case ss_et_NoValidChar:
+ return "No valid character";
+ case ss_et_DorlOutOfRange:
+ return "Density is out of range";
+ case ss_et_ReflectanceOutOfRange:
+ return "Reflectance is out of range";
+ case ss_et_Color1OutOfRange:
+ return "Color 1 is out of range";
+ case ss_et_Color2OutOfRange:
+ return "Color 2 is out of range";
+ case ss_et_Color3OutOfRange:
+ return "Color 3 is out of range";
+ case ss_et_NotAnSROrBoolean:
+ return "Not an SR or Boolean";
+ case ss_et_NoValidValOrRef:
+ return "No valid value or reference";
+
+ /* Translated scan error codes thus: */
+ case ss_et_DeviceIsOffline:
+ return "Device has been set offline";
+ case ss_et_OutOfRange:
+ return "A parameter of the command is out of range";
+ case ss_et_ProgrammingError:
+ return "Error writing to Flash-EPROM";
+ case ss_et_NoUserAccess:
+ return "No access to internal function";
+ case ss_et_NoValidCommand:
+ return "Unknown command sent";
+ case ss_et_NoDeviceFound:
+ return "Spectrolino can't be found";
+ case ss_et_MeasurementError:
+ return "Measurement error";
+ case ss_et_NoTransmTable:
+ return "SpectroScanT command when no tansmission table";
+ case ss_et_NotInTransmMode:
+ return "SpectroScanT transmission command in reflection mode";
+ case ss_et_NotInReflectMode:
+ return "SpectroScanT reflection command in transmission mode";
+
+ /* Translated device communication errors */
+ case ss_et_StopButNoStart:
+ return "No start character received by instrument";
+ case ss_et_IllegalCharInRec:
+ return "Invalid character received by instrument";
+ case ss_et_IncorrectRecLen:
+ return "Record length received by instrument incorrect";
+ case ss_et_IllegalRecType:
+ return "Invalid message number receivec by instrument";
+ case ss_et_NoTagField:
+ return "No message number received by instrument";
+ case ss_et_ConvError:
+ return "Received data couldn't be converted by instrument";
+ case ss_et_InvalidForEmission:
+ return "Invalid message number for emission instrument";
+ case ss_et_NoAccess:
+ return "Failure in user identification by instrument";
+
+ /* Our own communication errors here too. */
+ case ss_et_SerialFail:
+ return "Serial communications failure";
+
+ case ss_et_SendBufferFull:
+ return "Message send buffer is full";
+ case ss_et_RecBufferEmpty:
+ return "Message receive buffer is full";
+ case ss_et_BadAnsFormat:
+ return "Message received from instrument is badly formatted";
+ case ss_et_BadHexEncoding:
+ return "Message received from instrument has bad Hex encoding";
+ case ss_et_RecBufferOverun:
+ return "Message received from instrument would overflow recieve buffer";
+ default:
+ return "Unknown error code";
+ }
+}
+
+/* Return the instrument mode capabilities */
+void ss_capabilities(inst *pp,
+inst_mode *pcap1,
+inst2_capability *pcap2,
+inst3_capability *pcap3) {
+ ss *p = (ss *)pp;
+
+ if (p->cap == inst_mode_none)
+ ss_determine_capabilities(p);
+
+ if (pcap1 != NULL)
+ *pcap1 = p->cap;
+ if (pcap2 != NULL)
+ *pcap2 = p->cap2;
+ if (pcap3 != NULL)
+ *pcap3 = p->cap3;
+}
+
+/*
+ * Check measurement mode
+ * We assume that the instrument has been initialised.
+ */
+static inst_code
+ss_check_mode(inst *pp, inst_mode m) {
+ ss *p = (ss *)pp;
+ inst_mode cap;
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ pp->capabilities(pp, &cap, NULL, NULL);
+
+ a1logd(p->log, 4, "check_mode 0x%x with cap 0x%x\n",m, cap);
+
+ /* Simple test */
+ if (m & ~cap)
+ return inst_unsupported;
+
+ /* Check specific modes */
+ if (!IMODETST(m, inst_mode_ref_spot)
+ && !IMODETST(m, inst_mode_emis_spot)
+ && !IMODETST(m, inst_mode_emis_tele)
+ && !IMODETST2(cap, m, inst_mode_ref_xy)
+ && !IMODETST2(cap, m, inst_mode_trans_spot)) { /* Fake or SpectroScanT */
+ return inst_unsupported;
+ }
+
+ return inst_ok;
+}
+
+/*
+ * set measurement mode
+ * We assume that the instrument has been initialised.
+ * The measurement mode is activated.
+ */
+static inst_code
+ss_set_mode(inst *pp, inst_mode m) {
+ ss *p = (ss *)pp;
+ inst_code ev;
+
+ if ((ev = ss_check_mode(pp, m)) != inst_ok)
+ return ev;
+
+ p->nextmode = m;
+
+ /* Now activate the next mode */
+ if (((p->nextmode & inst_mode_illum_mask) == inst_mode_reflection
+ && (p->mode & inst_mode_illum_mask) != inst_mode_reflection)
+ || ((p->nextmode & inst_mode_illum_mask) == inst_mode_emission
+ && (p->mode & inst_mode_illum_mask) != inst_mode_emission)
+ || ((p->nextmode & inst_mode_illum_mask) == inst_mode_transmission
+ && (p->mode & inst_mode_illum_mask) != inst_mode_transmission)) {
+
+ /* Mode has changed */
+ p->mode = p->nextmode;
+
+ /* Capabilities may have changed */
+ ss_determine_capabilities(p);
+
+ /* So we need calibration (do we, if this mode has been calibrated before ?) */
+ p->need_wd_cal = 1;
+ if ((p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ p->need_t_cal = 1;
+ }
+ }
+ return inst_ok;
+}
+
+/*
+ * Get a status or get or set an option
+ * Since there is no interaction with the instrument,
+ * was assume that all of these can be done before initialisation.
+ */
+static inst_code
+ss_get_set_opt(inst *pp, inst_opt_type m, ...) {
+ ss *p = (ss *)pp;
+
+ if (m == inst_opt_noinitcalib) {
+ va_list args;
+ int losecs = 0;
+
+ va_start(args, m);
+ losecs = va_arg(args, int);
+ va_end(args);
+
+ /* Note that we're not implementing support for losecs at the moment. */
+ /* We would have to save a dummy calibration file to track the last time */
+ /* the instrument was opened. */
+
+ if (losecs == 0) /* If losecs != 0, then don't disable init calib */
+ p->noinitcalib = 1;
+
+ return inst_ok;
+
+ } else if (m == inst_opt_initcalib) {
+ p->noinitcalib = 0;
+ return inst_ok;
+
+ } else if (m == inst_opt_set_filter) {
+ va_list args;
+ inst_opt_filter fe = inst_opt_filter_unknown;
+
+ va_start(args, m);
+
+ fe = va_arg(args, inst_opt_filter);
+
+ va_end(args);
+
+ switch(fe) {
+
+ case inst_opt_filter_none:
+ p->filt = ss_aft_NoFilter;
+ return inst_ok;
+ case inst_opt_filter_pol:
+ p->filt = ss_aft_PolFilter;
+ return inst_ok;
+ case inst_opt_filter_D65:
+ p->filt = ss_aft_D65Filter;
+ return inst_ok;
+ case inst_opt_filter_UVCut:
+ p->filt = ss_aft_UVCutFilter;
+ return inst_ok;
+ case inst_opt_filter_Custom:
+ p->filt = ss_aft_CustomFilter;
+ return inst_ok;
+ default:
+ break;
+ }
+ return inst_unsupported;
+ }
+
+ /* Record the trigger mode */
+ if (m == inst_opt_trig_prog
+ || m == inst_opt_trig_user
+ || m == inst_opt_trig_user_switch) {
+
+ p->trig = m;
+ return inst_ok;
+ }
+
+ if (!p->gotcoms)
+ return inst_no_coms;
+ if (!p->inited)
+ return inst_no_init;
+
+ /* Return the filter */
+ if (m == inst_stat_get_filter) {
+ inst_opt_filter *filt;
+ inst_code rv;
+ va_list args;
+ ss_dst ds;
+ ss_wbt wb;
+ ss_ilt it;
+ ss_ot ot;
+ ss_aft af;
+
+ va_start(args, m);
+ filt = va_arg(args, inst_opt_filter *);
+ va_end(args);
+
+ /* Get the filter. */
+ if ((rv = so_do_ParameterRequest(p, &ds, &wb, &it, &ot, &af)) != inst_ok)
+ return rv;
+
+ switch (af) {
+ case ss_aft_NoFilter:
+ *filt = inst_opt_filter_none;
+ break;
+ case ss_aft_PolFilter:
+ *filt = inst_opt_filter_pol;
+ break;
+ case ss_aft_D65Filter:
+ *filt = inst_opt_filter_D65 ;
+ break;
+ case ss_aft_UVCutFilter:
+ *filt = inst_opt_filter_UVCut;
+ break;
+ case ss_aft_CustomFilter:
+ *filt = inst_opt_filter_Custom;
+ break;
+ default:
+ *filt = inst_opt_filter_unknown;
+ break;
+ }
+ return inst_ok;
+ }
+
+ /* Use default implementation of other inst_opt_type's */
+ {
+ va_list args;
+ inst_code rv;
+
+ va_start(args, m);
+ rv = inst_get_set_opt_def(pp, m, args);
+ va_end(args);
+
+ return rv;
+ }
+}
+
+/* Destroy ourselves */
+static void
+ss_del(inst *pp) {
+ ss *p = (ss *)pp;
+
+ if (p->inited
+ && p->itype == instSpectroScanT
+ && (p->mode & inst_mode_illum_mask) == inst_mode_transmission) {
+ ss_do_SetDeviceOnline(p);
+ ss_do_SetTableMode(p, ss_tmt_Reflectance);
+ ss_do_MoveUp(p); /* Raise the sensor */
+ ss_do_ReleasePaper(p); /* Release the paper */
+ ss_do_MoveHome(p); /* Move to the home position */
+ }
+
+ if (p->inited
+ && (p->mode & inst_mode_illum_mask) != inst_mode_transmission) {
+ ss_xy_clear(pp);
+ }
+
+ if (p->icom != NULL)
+ p->icom->del(p->icom);
+ free (p);
+}
+
+/* Constructor */
+extern ss *new_ss(icoms *icom, instType itype) {
+ ss *p;
+ if ((p = (ss *)calloc(sizeof(ss),1)) == NULL) {
+ a1loge(icom->log, 1, "new_ss: malloc failed!\n");
+ return NULL;
+ }
+
+ p->log = new_a1log_d(icom->log);
+
+ /* Init public methods */
+ p->init_coms = ss_init_coms;
+ p->init_inst = ss_init_inst;
+ p->capabilities = ss_capabilities;
+ p->check_mode = ss_check_mode;
+ p->set_mode = ss_set_mode;
+ p->get_set_opt = ss_get_set_opt;
+ p->xy_sheet_release = ss_xy_sheet_release;
+ p->xy_sheet_hold = ss_xy_sheet_hold;
+ p->xy_locate_start = ss_xy_locate_start;
+ p->xy_get_location = ss_xy_get_location;
+ p->xy_locate_end = ss_xy_locate_end;
+ p->xy_position = ss_xy_position;
+ p->xy_clear = ss_xy_clear;
+ p->read_xy = ss_read_xy;
+ p->read_strip = ss_read_strip;
+ p->read_sample = ss_read_sample;
+ p->get_n_a_cals = ss_get_n_a_cals;
+ p->calibrate = ss_calibrate;
+ p->comp_filter = ss_comp_filter;
+ p->interp_error = ss_interp_error;
+ p->del = ss_del;
+
+ /* Init state */
+ p->icom = icom;
+ p->itype = icom->itype;
+ p->cap = inst_mode_none; /* Unknown until initialised */
+ p->mode = inst_mode_none; /* Not in a known mode yet */
+ p->nextmode = inst_mode_none; /* Not in a known mode yet */
+
+ /* Set default measurement configuration */
+ p->filt = ss_aft_NoFilter;
+ p->dstd = ss_dst_ANSIT;
+ p->illum = ss_ilt_D50;
+ p->obsv = ss_ot_TwoDeg;
+ p->wbase = ss_wbt_Abs;
+ p->phmode = ss_ctt_PhotometricAbsolute;
+ p->phref = 1.0;
+
+ /* Init serialisation stuff */
+ p->sbuf = &p->_sbuf[0];
+ p->sbufe = &p->_sbuf[SS_MAX_WR_SIZE-2]; /* Allow one byte for nul */
+ p->rbuf = &p->_rbuf[0];
+ p->rbufe = &p->_rbuf[0]; /* Initialy empty */
+ p->snerr = ss_et_NoError; /* COMs error */
+
+#ifdef EMSST
+ p->tmode = 0; /* Reflection mode */
+ p->sbr = ss_rt_SensorRef;
+ p->sbx = 100.0;
+ p->sby = 200.0;
+#endif
+
+ ss_determine_capabilities(p);
+
+ return p;
+}
diff --git a/spectro/ss.h b/spectro/ss.h
new file mode 100644
index 0000000..bff0846
--- /dev/null
+++ b/spectro/ss.h
@@ -0,0 +1,115 @@
+
+#ifndef SS_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag Spectrolino and Spectroscan related
+ * defines and declarations.
+ *
+ * Author: Graeme W. Gill
+ * Date: 13/7/2005
+ *
+ * Copyright 2005 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Derived from DTP41.h
+ *
+ * This is an alternative driver to spm/gretag.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#undef EMSST /* Debug - emulate a SpectroScanT with a SpectroScan */
+
+#include "inst.h"
+#include "ss_imp.h"
+
+#define SS_MAX_WR_SIZE 1000 /* Assumed maximum normal message query size */
+#define SS_MAX_RD_SIZE 1000 /* Assumed maximum normal messagle answer size */
+
+/* Gretag Spectrolino/Spectroscan communication object */
+struct _ss {
+ /* **** base instrument class **** */
+ INST_OBJ_BASE
+
+ /* *** Spectroscan/lino private data **** */
+ inst_mode cap; /* Instrument mode capability */
+ inst2_capability cap2; /* Instrument capability 2 */
+ inst3_capability cap3; /* Instrument capability 3 */
+ inst_mode nextmode; /* Next requested mode */
+ inst_mode mode; /* Currently instrument mode */
+
+ /* Desired measurement configuration */
+ ss_aft filt; /* Filter type (None/UV/D65 etc.) */
+ ss_dst dstd; /* Density standard (ANSI A/ANSI T/DIN etc.) */
+ ss_ilt illum; /* Illuminant type (A/C/D50 etc.) */
+ ss_ot obsv; /* Observer type (2deg/10deg) */
+ ss_wbt wbase; /* White base type (Paper/Abs>) */
+ ss_ctt phmode; /* Photometric mode (Absolute/Relative) */
+ double phref; /* Photometric reference (cd/m^2) */
+
+ int calcount; /* Calibration needed counter */
+ int pisrow; /* patches in a reading direction serpentine rows */
+ int need_wd_cal; /* White/dark calibration needed flag */
+ int need_t_cal; /* Transmission calibration needed flag */
+ int noinitcalib; /* Don't mode change or do initilal calibrate */
+ int forcecalib; /* Force a calibration even if not near white tile */
+ inst_opt_type trig; /* Reading trigger mode */
+ int offline; /* nz if we're off line */
+
+ /* Emulated manual transmission mode support */
+ double tref[36]; /* White reference spectrum */
+ double cill[36]; /* Colorimetry illuminant */
+
+ /* telescopic adapter compensation */
+ int compen; /* Compensation filter enabled */
+ double comp[36]; /* Compensation filter */
+
+#ifdef EMSST
+ int tmode; /* Transmission mode */
+ ss_rt sbr; /* Standby reference */
+ double sbx, sby; /* Standby location */
+#endif
+
+ /* Serialisation support: */
+
+ /* Send buffer */
+ char _sbuf[SS_MAX_WR_SIZE]; /* Buffer allocation */
+ char *sbufe; /* Pointer to last valid location in _sbuf[] */
+ char *sbuf; /* Next character output */
+
+ /* Receive buffer */
+ char _rbuf[SS_MAX_RD_SIZE]; /* Buffer allocation */
+ char *rbufe; /* Pointer to last valid location in _rbuf[] */
+ char *rbuf; /* Next character output */
+
+ /* Accumulated device error */
+ ss_et snerr;
+
+ }; typedef struct _ss ss;
+
+/* Constructor */
+extern ss *new_ss(icoms *icom, instType itype);
+
+#define SS_H
+#endif /* SS_H */
diff --git a/spectro/ss_imp.c b/spectro/ss_imp.c
new file mode 100644
index 0000000..b4c5d8a
--- /dev/null
+++ b/spectro/ss_imp.c
@@ -0,0 +1,1943 @@
+
+#ifndef SS_IMP_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag Spectrolino and Spectroscan related
+ * defines and declarations - implementation.
+ *
+ * Author: Graeme W. Gill
+ * Date: 14/7/2005
+ *
+ * Copyright 2005 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * This is an alternative driver to spm/gretag.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+#include "ss.h"
+
+/* ------------------------------------------- */
+/* Serialisation for different types functions */
+
+/* QUERY: */
+
+/* These add characters to the current send buffer, */
+/* And set the status appropriately */
+
+/* 4 bits to hex character conversion table */
+static char b2h[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+/* Check that there is enough space to write size more characters */
+#define CHWSPACE(size) \
+ if (p->snerr == ss_et_NoError \
+ && (p->sbufe - p->sbuf) < (size)) { \
+ p->snerr = ss_et_SendBufferFull; \
+ } \
+ if (p->snerr != ss_et_NoError) \
+ return;
+
+/* Reset send buffer, and init with start character */
+void ss_init_send(ss *p) {
+ p->snerr = ss_et_NoError;
+ p->sbuf = p->_sbuf;
+ CHWSPACE(1);
+ p->sbuf[0] = ';';
+ p->sbuf += 1;
+}
+
+/* Reset send buffer, and add an Spectrolino Request enum */
+void ss_add_soreq(ss *p, int rq) {
+ ss_init_send(p);
+ CHWSPACE(2);
+ p->sbuf[0] = b2h[(rq >> 4) & 0xf];
+ p->sbuf[1] = b2h[(rq >> 0) & 0xf];
+ p->sbuf += 2;
+}
+
+/* Reset send buffer, and add an SpectroScan Request enum */
+void ss_add_ssreq(ss *p, int rq) {
+ ss_init_send(p);
+ CHWSPACE(4);
+ p->sbuf[0] = b2h[((int)ss_ReqPFX >> 4) & 0xf]; /* Prefix */
+ p->sbuf[1] = b2h[((int)ss_ReqPFX >> 0) & 0xf]; /* Prefix */
+ p->sbuf[2] = b2h[(rq >> 4) & 0xf];
+ p->sbuf[3] = b2h[(rq >> 0) & 0xf];
+ p->sbuf += 4;
+}
+
+/* Add an int/enum/char into one byte type */
+void ss_add_1(ss *p, int c) {
+ CHWSPACE(2);
+ p->sbuf[0] = b2h[(c >> 4) & 0xf];
+ p->sbuf[1] = b2h[(c >> 0) & 0xf];
+ p->sbuf += 2;
+}
+
+/* Add an int/enum into two byte type */
+void ss_add_2(ss *p, int s) {
+ CHWSPACE(4);
+ p->sbuf[0] = b2h[(s >> 4) & 0xf]; /* LSB */
+ p->sbuf[1] = b2h[(s >> 0) & 0xf];
+ p->sbuf[2] = b2h[(s >> 12) & 0xf]; /* MSB */
+ p->sbuf[3] = b2h[(s >> 8) & 0xf];
+ p->sbuf += 4;
+}
+
+/* Add an int/enum into four byte type */
+void ss_add_4(ss *p, int i) {
+ CHWSPACE(8);
+ p->sbuf[0] = b2h[(i >> 4) & 0xf]; /* LSB */
+ p->sbuf[1] = b2h[(i >> 0) & 0xf];
+ p->sbuf[2] = b2h[(i >> 12) & 0xf];
+ p->sbuf[3] = b2h[(i >> 8) & 0xf];
+ p->sbuf[4] = b2h[(i >> 20) & 0xf];
+ p->sbuf[5] = b2h[(i >> 16) & 0xf];
+ p->sbuf[6] = b2h[(i >> 28) & 0xf]; /* MSB */
+ p->sbuf[7] = b2h[(i >> 24) & 0xf];
+ p->sbuf += 8;
+}
+
+/* Add a double into four byte type */
+void ss_add_double(ss *p, double d) {
+ unsigned int id;
+
+ id = doubletoIEEE754(d);
+
+ ss_add_4(p, id);
+}
+
+/* Add an ASCII string into the send buffer. */
+/* The string will be padded with nul's up to len. */
+void ss_add_string(ss *p, char *t, int len) {
+ int i;
+
+ CHWSPACE(2 * len);
+ for (i = 0; i < len; i++) {
+ p->sbuf[2 * i + 0] = b2h[(t[i] >> 4) & 0xf];
+ p->sbuf[2 * i + 1] = b2h[(t[i] >> 0) & 0xf];
+ if (t[i] == '\000')
+ break;
+ }
+ for (; i < len; i++) {
+ p->sbuf[2 * i + 0] = '0';
+ p->sbuf[2 * i + 1] = '0';
+ }
+ p->sbuf += 2 * len;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* ANSWER: */
+
+/* Check that there is not already an error, */
+/* and that there is enough space to read size more characters. */
+/* Return nz if not. */
+static int chrspace(ss *p, int size) {
+
+ if (p->snerr != ss_et_NoError) /* Problem assembling request */
+ return 1;
+
+ if ((p->rbufe - p->rbuf) < (size)) {
+ p->snerr = ss_et_RecBufferEmpty;
+ return 1;
+ }
+ {
+ char *rr = p->rbuf, *re = p->rbuf + size;
+ while (rr < re && *rr != '\000')
+ rr++;
+ if (rr < re) {
+ p->snerr = ss_et_RecBufferEmpty;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Check that the read buffer is fully consumed. */
+static void chended(ss *p) {
+ if (p->snerr == ss_et_NoError /* Don't overrite any existing error */
+ && p->rbufe != p->rbuf) {
+ p->snerr = ss_et_BadAnsFormat;
+ }
+}
+
+/* Convert an ASCII Hex character to an integer. */
+static int h2b(ss *p, char c) {
+ if (c >= '0' && c <= '9')
+ return (c-(int)'0');
+ if (c >= 'A' && c <= 'F')
+ return (10 + c-(int)'A');
+ if (c >= 'a' && c <= 'f')
+ return (10 + c-(int)'a');
+ if (p->snerr == ss_et_NoError) /* Don't overrite any existing error */
+ p->snerr = ss_et_BadHexEncoding;
+ return 0;
+}
+
+/* Return the first enum from the recieve buffer without removing it. */
+int ss_peek_ans(ss *p) {
+ int rv;
+
+ if (chrspace(p, 2))
+ return 0;
+ rv = (h2b(p, p->rbuf[0]) << 4)
+ | (h2b(p, p->rbuf[1]) << 0);
+
+ return rv;
+}
+
+/* Remove a Spectrolino answer enum from the revieve buffer, */
+/* and check it is correct. */
+void ss_sub_soans(ss *p, int cv) {
+ int rv;
+
+ if (chrspace(p, 2))
+ return;
+ rv = (h2b(p, p->rbuf[0]) << 4)
+ | (h2b(p, p->rbuf[1]) << 0);
+ p->rbuf += 2;
+ if (rv != cv) {
+ if (p->snerr == ss_et_NoError) /* Don't overrite any existing error */
+ p->snerr = ss_et_BadAnsFormat;
+ return;
+ }
+ return;
+}
+
+/* Remove a SpectroScan Prefix and answer enum from the revieve buffer, */
+/* and check it is correct. */
+void ss_sub_ssans(ss *p, int cv) {
+ int rv;
+
+ if (chrspace(p, 4))
+ return;
+ if (p->rbuf[0] != 'D'
+ || p->rbuf[1] != '1') {
+ if (p->snerr == ss_et_NoError) /* Don't overrite any existing error */
+ p->snerr = ss_et_BadAnsFormat;
+ return;
+ }
+ rv = (h2b(p, p->rbuf[2]) << 4)
+ | (h2b(p, p->rbuf[3]) << 0);
+ p->rbuf += 4;
+ if (rv != cv) {
+ if (p->snerr == ss_et_NoError) /* Don't overrite any existing error */
+ p->snerr = ss_et_BadAnsFormat;
+ return;
+ }
+ return;
+}
+
+/* Remove an int/enum/char into one byte type */
+int ss_sub_1(ss *p) {
+ int rv;
+
+ if (chrspace(p, 2))
+ return 0;
+ rv = (h2b(p, p->rbuf[0]) << 4)
+ | (h2b(p, p->rbuf[1]) << 0);
+ p->rbuf += 2;
+
+ return rv;
+}
+
+/* Remove an int/enum into two byte type */
+int ss_sub_2(ss *p) {
+ int rv;
+
+ if (chrspace(p, 4))
+ return 0;
+ rv = (h2b(p, p->rbuf[0]) << 4)
+ | (h2b(p, p->rbuf[1]) << 0)
+ | (h2b(p, p->rbuf[2]) << 12)
+ | (h2b(p, p->rbuf[3]) << 8);
+ p->rbuf += 4;
+
+ return rv;
+}
+
+/* Remove an int/enum into four byte type */
+int ss_sub_4(ss *p) {
+ int rv;
+
+ if (chrspace(p, 8))
+ return 0;
+ rv = (h2b(p, p->rbuf[0]) << 4)
+ | (h2b(p, p->rbuf[1]) << 0)
+ | (h2b(p, p->rbuf[2]) << 12)
+ | (h2b(p, p->rbuf[3]) << 8)
+ | (h2b(p, p->rbuf[4]) << 20)
+ | (h2b(p, p->rbuf[5]) << 16)
+ | (h2b(p, p->rbuf[6]) << 28)
+ | (h2b(p, p->rbuf[7]) << 24);
+ p->rbuf += 8;
+
+ return rv;
+}
+
+/* Remove a double into four byte type */
+double ss_sub_double(ss *p) {
+ unsigned int ip;
+ double op;
+
+ ip = (unsigned int)ss_sub_4(p);
+
+ op = IEEE754todouble(ip);
+
+ return op;
+}
+
+/* Remove an ASCII string from the receive buffer. */
+/* The string will be terminated with a nul, so a buffer */
+/* of len+1 should be provided to return the string in. */
+void ss_sub_string(ss *p, char *t, int len) {
+ int i;
+
+ if (chrspace(p, 2 * len))
+ return;
+ for (i = 0; i < len; i++) {
+ t[i] = (char)((h2b(p, p->rbuf[2 * i + 0]) << 4)
+ | (h2b(p, p->rbuf[2 * i + 1]) << 0));
+ }
+ t[i] = '\000';
+ p->rbuf += 2 * len;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* ERROR CODES: */
+
+/* Convert an ss error into an inst_error */
+inst_code ss_inst_err(ss *p) {
+ ss_et ec = p->snerr;
+
+ switch(ec) {
+ case ss_et_NoError:
+ return inst_ok;
+
+ case ss_et_WhiteMeasOK:
+ case ss_et_ResetDone:
+ case ss_et_EmissionCalOK:
+ return inst_notify | ec;
+
+ case ss_et_WhiteMeasWarn:
+ return inst_warning | ec;
+
+ case ss_et_SendTimeout:
+ case ss_et_SerialFail:
+ return inst_coms_fail | ec;
+
+ case ss_et_StopButNoStart:
+ case ss_et_IllegalCharInRec:
+ case ss_et_IncorrectRecLen:
+ case ss_et_IllegalRecType:
+ case ss_et_NoTagField:
+ case ss_et_ConvError:
+ case ss_et_RecBufferEmpty:
+ case ss_et_BadAnsFormat:
+ case ss_et_BadHexEncoding:
+ case ss_et_RecBufferOverun:
+ case ss_et_OutOfRange:
+ case ss_et_NotAnSROrBoolean:
+ return inst_protocol_error | ec;
+
+ case ss_et_RemOverFlow:
+ case ss_et_MeasDisabled:
+ case ss_et_MeasurementError:
+ case ss_et_DorlOutOfRange:
+ case ss_et_ReflectanceOutOfRange:
+ case ss_et_Color1OutOfRange:
+ case ss_et_Color2OutOfRange:
+ case ss_et_Color3OutOfRange:
+ return inst_misread | ec;
+
+ case ss_et_NoValidCommand:
+ case ss_et_NoUserAccess:
+ return inst_unsupported | ec;
+
+ case ss_et_NotReady:
+ case ss_et_NoAccess:
+ return inst_other_error | ec;
+ break;
+
+ case ss_et_SendBufferFull:
+ return inst_internal_error | ec;
+
+ case ss_et_NoValidMeas:
+ case ss_et_OnlyEmission:
+ case ss_et_DensCalError:
+ case ss_et_NoTransmTable:
+ case ss_et_InvalidForEmission:
+ case ss_et_NotInTransmMode:
+ case ss_et_NotInReflectMode:
+ case ss_et_NoValidDStd:
+ case ss_et_NoValidWhite:
+ case ss_et_NoValidIllum:
+ case ss_et_NoValidObserver:
+ case ss_et_NoValidMaxLambda:
+ case ss_et_NoValidSpect:
+ case ss_et_NoValidColSysOrIndex:
+ case ss_et_NoValidChar:
+ case ss_et_NoValidValOrRef:
+ case ss_et_DeviceIsOffline:
+ case ss_et_NoDeviceFound:
+ return inst_wrong_setup | ec;
+
+ case ss_et_BackupError:
+ case ss_et_ProgramROMError:
+ case ss_et_CheckSumWrong:
+ case ss_et_MemoryError:
+ case ss_et_FullMemory:
+ case ss_et_EPROMFailure:
+ case ss_et_MemoryFailure:
+ case ss_et_PowerFailure:
+ case ss_et_LampFailure:
+ case ss_et_HardwareFailure:
+ case ss_et_DriveError:
+ case ss_et_FilterOutOfPos:
+ case ss_et_ProgrammingError:
+ return inst_hardware_fail | ec;
+
+ }
+ return inst_other_error | ec;
+}
+
+/* Incorporate a error into the snerr value */
+void ss_incorp_err(ss *p, ss_et se) {
+ if (p->snerr != ss_et_NoError) /* Don't overrite any existing error */
+ return;
+ if (se == ss_set_NoError)
+ return;
+
+ p->snerr = se;
+}
+
+/* Incororate Remote Error Set values into snerr value */
+/* Since ss_res is a bit mask, we just prioritize the errors. */
+void ss_incorp_remerrset(ss *p, ss_res es) {
+ int i, ii;
+ if (p->snerr != ss_et_NoError) /* Don't overrite any existing error */
+ return;
+ if (es == ss_res_NoError)
+ return;
+
+ for (i = ss_et_NoValidDStd, ii = 0x0001; ii < 0x10000; i++, ii <<= 1) {
+ if ((ii & es) != 0) {
+ break;
+ }
+ }
+ p->snerr = i;
+}
+
+/* Incorporate a scan error into the snerr value */
+void ss_incorp_scanerr(ss *p, ss_set se) {
+ if (p->snerr != ss_et_NoError) /* Don't overrite any existing error */
+ return;
+ if (se == ss_set_NoError)
+ return;
+
+ p->snerr = se + ss_et_DeviceIsOffline - 1;
+}
+
+/* Incorporate a device communication error into the snerr value */
+void ss_incorp_comerr(ss *p, ss_cet se) {
+ if (p->snerr != ss_et_NoError) /* Don't overrite any existing error */
+ return;
+ if (se == ss_cet_NoError)
+ return;
+
+ p->snerr = se + ss_et_StopButNoStart - 1;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* EXECUTION: */
+
+/* Interpret an icoms error into a SS error */
+int icoms2ss_err(int se) {
+ if (se != ICOM_OK)
+ return ss_et_SerialFail;
+ return ss_et_NoError;
+}
+
+/* Terminate the send buffer, and then do a */
+/* send/receieve to the device. */
+/* Leave any error in p->snerr */
+void ss_command(ss *p, double tmo) {
+ int se;
+
+ CHWSPACE(3);
+ p->sbuf[0] = '\r';
+ p->sbuf[1] = '\n';
+ p->sbuf[2] = '\00'; /* write_read terminates on nul */
+
+ p->rbuf = p->_rbuf; /* Reset read pointer */
+ if ((se = p->icom->write_read(p->icom, p->_sbuf, p->_rbuf, SS_MAX_RD_SIZE, '\n', 1, tmo)) != 0) {
+ p->snerr = icoms2ss_err(se);
+ return;
+ }
+
+ /* Figure out receive size, and clean up termination. */
+ p->rbufe = p->_rbuf + strlen(p->_rbuf);
+ if ((p->rbufe - p->rbuf) >= 1 && p->rbufe[-1] == '\n') {
+ --p->rbufe;
+ *p->rbufe = '\000';
+ }
+ if ((p->rbufe - p->rbuf) >= 1 && p->rbufe[-1] == '\r') {
+ --p->rbufe;
+ *p->rbufe = '\000';
+ }
+
+ /* Check receive format and look for a COM error */
+ if ((p->rbufe - p->rbuf) < 1 || p->rbuf[0] != ':') {
+ p->snerr = ss_et_BadAnsFormat;
+ return;
+ }
+ p->rbuf++;
+
+ /* See if this is a Spectroscan COM error */
+ if ((p->rbufe - p->rbuf) >= 2
+ && p->rbuf[0] == 'D'
+ && p->rbuf[1] == '1') {
+
+ if ((p->rbufe - p->rbuf) >= 4
+ && p->rbuf[0] == 'A'
+ && p->rbuf[1] == '0') { /* COMM Error */
+ p->rbuf += 4;
+ ss_incorp_comerr(p, (ss_cet)ss_sub_1(p));
+ return;
+ }
+ }
+
+ /* See if it is a Spectrolino COMM error */
+ if ((p->rbufe - p->rbuf) >= 2
+ && p->rbuf[0] == '2'
+ && p->rbuf[1] == '6') { /* COMM Error */
+ p->rbuf += 2;
+ ss_incorp_comerr(p, (ss_cet)ss_sub_1(p));
+ return;
+ }
+ return;
+}
+
+/* =================================================================== */
+/* Complete Spectrolino instructions. */
+/* [This is less elegant than Neil Okamoto's */
+/* table approach, but is more flexible, */
+/* and it does the job.] */
+
+/* - - - - - - - - - - - - - - - - - - - - */
+/* Device Initialisation and configuration */
+
+/* Reset instrument */
+inst_code so_do_ResetStatusDownload(
+ss *p,
+ss_smt sm /* Init all or all except communications */
+) {
+ ss_add_soreq(p, ss_ResetStatusDownload);
+ ss_add_1(p, 0x01);
+ ss_add_1(p, 0x04);
+ ss_add_1(p, sm);
+ ss_command(p, IT_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Load various parameters, such as: */
+/* comm flow control, baud rate, speaker, */
+/* reflective/tranmission/emmission mode, */
+/* custom filter on/off */
+inst_code so_do_MeasControlDownload(
+ss *p,
+ss_ctt ct /* Control */
+) {
+ ss_add_soreq(p, ss_MeasControlDownload);
+ ss_add_1(p, ct);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+
+ return ss_inst_err(p);
+}
+
+/* Query various current parameters, such as: */
+/* comm flow control, baud rate, speaker, */
+/* reflective/tranmission/emmission mode, */
+/* custom filter on/off. */
+inst_code so_do_MeasControlRequest(
+ss *p,
+ss_ctt ct, /* Control to query */
+ss_ctt *rct /* Return current state */
+) {
+ ss_add_soreq(p, ss_MeasControlRequest);
+ ss_add_1(p, ct);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_MeasControlAnswer);
+ ss_sub_1(p); /* Should be the same as ct */
+ *rct = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Queries specific device data */
+inst_code so_do_DeviceDataRequest(
+ss *p,
+char dn[19], /* Return the device name */
+ss_dnot *dno, /* Return device number */
+char pn[9], /* Return the part number */
+unsigned int *sn, /* Return serial number */
+char sv[13] /* Return software version */
+) {
+ char rsv[17]; /* Space for resered field */
+ ss_add_soreq(p, ss_DeviceDataRequest);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DeviceDataAnswer);
+ ss_sub_string(p, dn, 18);
+ *dno = ss_sub_1(p);
+ ss_sub_string(p, pn, 8);
+ *sn = (unsigned int)ss_sub_4(p);
+ ss_sub_string(p, sv, 12);
+ ss_sub_string(p, rsv, 16);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query special device data */
+inst_code so_do_TargetIdRequest(
+ss *p,
+char dn[19], /* Return Device Name */
+int *sn, /* Return Serial Number (1-65535) */
+int *sr, /* Return Software Release */
+int *yp, /* Return Year of production (e.g. 1996) */
+int *mp, /* Return Month of production (1-12) */
+int *dp, /* Return Day of production (1-31) */
+int *hp, /* Return Hour of production (0-23) */
+int *np, /* Return Minuite of production (0-59) */
+ss_ttt *tt, /* Return Target Tech Type (SPM/Spectrolino etc.) */
+int *fswl, /* Return First spectral wavelength (nm) */
+int *nosw, /* Return Number of spectral wavelengths */
+int *dpsw /* Return Distance between spectral wavelengths (nm) */
+) {
+ ss_add_soreq(p, ss_TargetIdRequest);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_TargetIdAnswer);
+ ss_sub_string(p, dn, 18);
+ *sn = ss_sub_2(p);
+ *sr = ss_sub_2(p);
+ *yp = ss_sub_2(p);
+ *mp = ss_sub_2(p);
+ *dp = ss_sub_2(p);
+ *hp = ss_sub_2(p);
+ *np = ss_sub_2(p);
+ *tt = ss_sub_1(p);
+ *fswl = ss_sub_2(p);
+ *nosw = ss_sub_2(p);
+ *dpsw = ss_sub_2(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - - - - - - - - */
+/* Measurement configuration */
+
+/* Query the standard or user definable densitometric tables */
+inst_code so_do_DensTabRequest(
+ss *p,
+ss_dst ds, /* Density standard (ANSI/DIN/User etc.) */
+ss_dst *rds, /* Return Density standard (ANSI/DIN/User etc.) */
+double sp[4][36] /* Return 4 * 36 spectral weighting values */
+) {
+ int n,i;
+ ss_add_soreq(p, ss_DensTabRequest);
+ ss_add_1(p, 0x00);
+ ss_add_1(p, ds);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DensTabAnswer);
+ ss_sub_soans(p, 0x00);
+ *rds = ss_sub_1(p);
+ for (n = 0; n < 4; n++)
+ for (i = 0; i < 36; i++)
+ sp[n][i] = ss_sub_double(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Download user definable densitometric tables */
+inst_code so_do_DensTabDownload(
+ss *p,
+double sp[4][36] /* 4 * 36 spectral weighting values */
+) {
+ int i, n;
+ ss_add_soreq(p, ss_DensTabDownload);
+ ss_add_1(p, 0x08);
+ for (n = 0; n < 4; n++)
+ for (i = 0; i < 36; i++)
+ ss_add_double(p, sp[n][i]);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Set slope values for densitometry */
+inst_code so_do_SlopeDownload(
+ss *p,
+double dv[4] /* Db Dc Dm Dy density values */
+) {
+ int i;
+ ss_add_soreq(p, ss_SlopeDownload);
+ for (i = 0; i < 4; i++)
+ ss_add_double(p, dv[i]);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query slope values of densitometry */
+inst_code so_do_SlopeRequest(
+ss *p,
+double dv[4] /* Return Db Dc Dm Dy density values */
+) {
+ int i;
+ ss_add_soreq(p, ss_SlopeRequest);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_SlopeAnswer);
+ for (i = 0; i < 4; i++)
+ dv[i] = ss_sub_double(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Set the colorimetric parameters */
+inst_code so_do_ParameterDownload(
+ss *p,
+ss_dst ds, /* Density standard (ANSI/DIN etc.) */
+ss_wbt wb, /* White base (Paper/Absolute) */
+ss_ilt it, /* Illuminant type (A/C/D65 etc.) */
+ss_ot ot /* Observer type (2deg/10deg) */
+) {
+ ss_add_soreq(p, ss_ParameterDownload);
+ ss_add_1(p, ds);
+ ss_add_1(p, wb);
+ ss_add_1(p, it);
+ ss_add_1(p, ot);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query colorimetric parameters */
+inst_code so_do_ParameterRequest(
+ss *p,
+ss_dst *ds, /* Return Density Standard */
+ss_wbt *wb, /* Return White Base */
+ss_ilt *it, /* Return Illuminant type (A/C/D65/User etc.) */
+ss_ot *ot, /* Return Observer type (2deg/10deg) */
+ss_aft *af /* Return Filter being used (None/Pol/D65/UV/custom */
+) {
+ ss_add_soreq(p, ss_ParameterRequest);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_ParameterAnswer);
+ *ds = ss_sub_1(p);
+ *wb = ss_sub_1(p);
+ *it = ss_sub_1(p);
+ *ot = ss_sub_1(p);
+ *af = ss_sub_1(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the standard or user defined illuminant tables (Colorimetry) */
+inst_code so_do_IllumTabRequest(
+ss *p,
+ss_ilt it, /* Illuminant type (A/C/D65/User etc.) */
+ss_ilt *rit, /* Return Illuminant type (A/C/D65/User etc.) */
+double sp[36] /* Return 36 spectral values */
+) {
+ int i;
+ ss_add_soreq(p, ss_IllumTabRequest);
+ ss_add_1(p, 0x00);
+ ss_add_1(p, it);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_IllumTabAnswer);
+ ss_sub_soans(p, 0x00);
+ *rit = ss_sub_1(p);
+ for (i = 0; i < 36; i++)
+ sp[i] = ss_sub_double(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Download user definable illuminant tables (Colorimetry) */
+inst_code so_do_IllumTabDownload(
+ss *p,
+double sp[36] /* 36 spectral values to set */
+) {
+ int i;
+ ss_add_soreq(p, ss_IllumTabDownload);
+ ss_add_1(p, 0x08);
+ for (i = 0; i < 36; i++)
+ ss_add_double(p, sp[i]);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query for the color temperature of daylight illuminant Dxx */
+inst_code so_do_GetValNr(
+ss *p,
+int *ct /* Return color temperature in deg K/100 */
+) {
+ ss_add_soreq(p, ss_GetValNr);
+ ss_add_1(p, 0x60);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_ValNrAnswer);
+ ss_sub_soans(p, 0x60);
+ *ct = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Download user definable illuminant tables (Colorimetry) */
+inst_code so_do_SetValNr(
+ss *p,
+int ct /* Color temperature to set for illuminant Dxx in deg K/100 */
+) {
+ ss_add_soreq(p, ss_IllumTabDownload);
+ ss_add_1(p, 0x60);
+ ss_add_2(p, ct);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Queries the spectra of the white reference for the desired filter */
+inst_code so_do_WhiteReferenceRequest(
+ss *p,
+ss_aft af, /* Filter being queried (None/Pol/D65/UV/custom */
+ss_aft *raf, /* Return filter being queried (None/Pol/D65/UV/custom */
+double sp[36], /* Return 36 spectral values */
+ss_owrt *owr, /* Return original white reference */
+char dtn[19] /* Return name of data table */
+) {
+ int i;
+ ss_add_soreq(p, ss_WhiteReferenceRequest);
+ ss_add_1(p, af);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_WhiteReferenceAnswer);
+ *raf = ss_sub_1(p);
+ for (i = 0; i < 36; i++)
+ sp[i] = ss_sub_double(p);
+ *owr = ss_sub_1(p);
+ ss_sub_string(p, dtn, 18);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Load spectra of a user defined white reference for the desired filter. */
+/* A name can be given to the white reference. */
+inst_code so_do_WhiteReferenceDownld(
+ss *p,
+ss_aft af, /* Filter being set (None/Pol/D65/UV/custom */
+double sp[36], /* 36 spectral values being set */
+char dtn[19] /* Name for data table */
+) {
+ int i;
+ ss_add_soreq(p, ss_WhiteReferenceDownld);
+ ss_add_1(p, af);
+ for (i = 0; i < 36; i++)
+ ss_add_double(p, sp[i]);
+ ss_add_string(p, dtn, 18);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the reference value for the relative photometric (emission) reference value */
+inst_code so_do_FloatRequest(
+ss *p,
+ss_comft comf, /* Choose common float type (PhotometricYRef) */
+ss_comft *rcomf, /* Return common float type (PhotometricYRef) */
+double *comfv /* Return the reference value */
+) {
+ ss_add_soreq(p, ss_FloatRequest);
+ ss_add_1(p, comf);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_FloatAnswer);
+ *rcomf = ss_sub_1(p);
+ *comfv = ss_sub_double(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Set the reference value for the relative photometric (emission) reference value */
+inst_code so_do_FloatDownload(
+ss *p,
+ss_comft comf, /* Choose common float type (PhotometricYRef) */
+double comfv /* The reference value */
+) {
+ ss_add_soreq(p, ss_FloatDownload);
+ ss_add_1(p, comf);
+ ss_add_double(p, comfv);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - */
+/* Calibration */
+
+/* Reset the spectra of the respective white reference to the original data */
+inst_code so_do_ExecWhiteRefToOrigDat(
+ss *p
+) {
+ ss_add_soreq(p, ss_ExecWhiteRefToOrigDat);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError); /* Instrument behavour doesn't match doco. */
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+
+/* Perform a Reference Measurement */
+inst_code so_do_ExecRefMeasurement(
+ss *p,
+ss_mmt mm /* Measurement Mode (Meas/Cal etc.) */
+) {
+#ifdef EMSST
+ if (p->tmode != 0) {
+ ss_rvt rv;
+ double sp[36];
+ ss_nmt nm;
+ p->tmode = 0;
+ ss_do_MoveAndMeasure(p, 155.0, 230.0, sp, &rv);
+ so_do_NewMeasureRequest(p, &nm);
+ ss_do_MoveAbsolut(p, p->sbr, p->sbx, p->sby);
+ p->tmode = 1;
+ return (inst_notify | ss_et_WhiteMeasOK);
+ }
+#endif
+ ss_add_soreq(p, ss_ExecRefMeasurement);
+ ss_add_1(p, 0x09);
+ ss_add_1(p, mm);
+ ss_command(p, 2.0 * DF_TMO);
+ ss_sub_soans(p, ss_ExecError);
+ ss_incorp_err(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Perform a White Measurement - not recommended */
+/* (ExecRefMeasuremen is preferred instead) */
+inst_code so_do_ExecWhiteMeasurement(
+ss *p
+) {
+ ss_add_soreq(p, ss_ExecWhiteMeasurement);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_ExecError);
+ ss_incorp_err(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - - - - - - - */
+/* Performing measurements */
+
+
+/* Perform a Measurement */
+inst_code so_do_ExecMeasurement(
+ss *p
+) {
+#ifdef EMSST
+ if (p->tmode != 0) {
+ inst_code rc;
+ p->tmode = 0;
+ ss_do_MoveAbsolut(p, ss_rt_SensorRef, 155.0, 230.0);
+ ss_do_MoveDown(p);
+ rc = so_do_ExecMeasurement(p);
+ ss_do_MoveUp(p);
+ ss_do_MoveAbsolut(p, p->sbr, p->sbx, p->sby);
+ p->tmode = 1;
+ return rc;
+ }
+#endif
+ ss_add_soreq(p, ss_ExecMeasurement);
+ ss_command(p, 2.0 * DF_TMO);
+ ss_sub_soans(p, ss_ExecError);
+ ss_incorp_err(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Define automatic output after each measurement */
+/* [Note that dealing with the resulting measurement replies */
+/* isn't directly supported, currently.] */
+inst_code so_do_SetMeasurementOutput(
+ss *p,
+ss_ost os, /* Type of output to request */
+ss_os o /* bitmask of output */
+) {
+ ss_add_soreq(p, ss_SetMeasurementOutput);
+ ss_add_1(p, os);
+ ss_add_1(p, o.i);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+
+ return ss_inst_err(p);
+}
+
+/* - - - - - - - - */
+/* Getting results */
+
+/* so_do_Printout isn't currently defined. */
+/* It needs to cope with the expected number of values that */
+/* will be returned. This could probably be figured out from */
+/* the string itself ? */
+
+/* Query Density measurement results and associated parameters */
+inst_code so_do_DensityParameterRequest(
+ss *p,
+ss_cst *rct, /* Return Color Type (Lab/XYZ etc.) */
+double dv[4], /* Return Db Dc Dm Dy density values */
+ss_sdft *sdf, /* Return Standard Density Filter (Db/Dc/Dm/Dy) */
+ss_rvt *rv, /* Return Reference Valid Flag */
+ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom */
+ss_wbt *wb, /* Return white base (Paper/Absolute) */
+ss_dst *ds, /* Return Density standard (ANSI/DIN/User etc.) */
+ss_ilt *rit, /* Return Illuminant type (A/C/D65/User etc.) */
+ss_ot *ot /* Return Observer type (2deg/10deg) */
+) {
+ int i;
+ ss_add_soreq(p, ss_DensityParameterRequest);
+ ss_add_1(p, 0x09);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DensityParameterAnswer);
+ ss_sub_soans(p, 0x09);
+ for (i = 0; i < 4; i++)
+ dv[i] = ss_sub_double(p);
+ *sdf = ss_sub_1(p);
+ *rv = ss_sub_1(p);
+ *af = ss_sub_1(p);
+ *wb = ss_sub_1(p);
+ ss_sub_soans(p, 0x02);
+ *ds = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query Densitometric measurement values - not recommended */
+/* (DensityParameterRequest is preferred instead) */
+inst_code so_do_DensityRequest(
+ss *p,
+double dv[4], /* Return Db Dc Dm Dy density values */
+ss_sdft *sdf, /* Return Standard Density Filter (Db/Dc/Dm/Dy) */
+ss_rvt *rv /* Return Reference Valid */
+) {
+ int i;
+ ss_add_soreq(p, ss_DensityRequest);
+ ss_add_1(p, 0x09);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DensityAnswer);
+ ss_sub_soans(p, 0x09);
+ for (i = 0; i < 4; i++)
+ dv[i] = ss_sub_double(p);
+ *sdf = ss_sub_1(p);
+ *rv = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query maximum density reading */
+inst_code so_do_DmaxRequest(
+ss *p,
+double *Dmax, /* Return Value of Maximum Density */
+int *lambda, /* Return wavelength where maximum density was found */
+ss_dmot *dmo, /* Return Dmax OK flag. */
+ss_rvt *rv /* Return Reference Valid Flag */
+) {
+ ss_add_soreq(p, ss_DmaxRequest);
+ ss_add_1(p, 0x09);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DmaxAnswer);
+ ss_sub_soans(p, 0x09);
+ *Dmax = ss_sub_double(p);
+ *lambda = ss_sub_2(p);
+ *dmo = ss_sub_1(p);
+ *rv = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query Color measurement results and associated parameters */
+inst_code so_do_CParameterRequest(
+ss *p,
+ss_cst ct, /* Choose Color Type (Lab/XYZ etc.) */
+ss_cst *rct, /* Return Color Type (Lab/XYZ etc.) */
+double cv[3], /* Return 3 color values */
+ss_rvt *rv, /* Return Reference Valid Flag */
+ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom) */
+ss_wbt *wb, /* Return white base (Paper/Absolute) */
+ss_ilt *it, /* Return Illuminant type (A/C/D65/User etc.) */
+ss_ot *ot /* Return Observer type (2deg/10deg) */
+) {
+ int i;
+ ss_add_soreq(p, ss_CParameterRequest);
+ ss_add_1(p, 0x09);
+ ss_add_1(p,ct);
+ ss_command(p, DF_TMO);
+
+ ss_sub_soans(p, ss_CParameterAnswer);
+ ss_sub_soans(p, 0x09);
+ *rct = ss_sub_1(p);
+ for (i = 0; i < 3; i++)
+ cv[i] = ss_sub_double(p);
+ *rv = ss_sub_1(p);
+ *af = ss_sub_1(p);
+ *wb = ss_sub_1(p);
+ ss_sub_soans(p, 0x02);
+ *it = ss_sub_1(p);
+ *ot = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query Colorimetric measurement results - not recommended */
+/* (CParameterRequest is prefered instead) */
+inst_code so_do_CRequest(
+ss *p,
+ss_cst *ct, /* Return Color Type (Lab/XYZ etc.) */
+double *cv[3], /* Return 3 color values */
+ss_rvt *rv /* Return Reference Valid Flag */
+) {
+ int i;
+ ss_add_soreq(p, ss_CRequest);
+ ss_add_1(p, 0x09);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_CAnswer);
+ ss_sub_soans(p, 0x09);
+ *ct = ss_sub_1(p);
+ for (i = 0; i < 3; i++)
+ *cv[i] = ss_sub_double(p);
+ *rv = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query Spectral measurement results and associated parameters */
+inst_code so_do_SpecParameterRequest(
+ss *p,
+ss_st st, /* Choose Spectrum Type (Reflectance/Density) */
+ss_st *rst, /* Return Spectrum Type (Reflectance/Density) */
+double sp[36], /* Return 36 spectral values */
+ss_rvt *rv, /* Return Reference Valid Flag */
+ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom */
+ss_wbt *wb /* Return white base (Paper/Absolute) */
+) {
+ int i;
+ ss_add_soreq(p, ss_SpecParameterRequest);
+ ss_add_1(p, 0x09);
+ ss_add_1(p,st);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_SpecParameterAnswer);
+ ss_sub_soans(p, 0x09);
+ *rst = ss_sub_1(p);
+ for (i = 0; i < 36; i++)
+ sp[i] = ss_sub_double(p);
+ *rv = ss_sub_1(p);
+ *af = ss_sub_1(p);
+ *wb = ss_sub_1(p);
+ ss_sub_soans(p, 0x02);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query Spectral measurement results - not recommended */
+/* (SpecParameterRequest is preferred instead) */
+inst_code so_do_SpectrumRequest(
+ss *p,
+ss_st *st, /* Return Spectrum Type (Reflectance/Density) */
+double sp[36], /* Return 36 spectral values */
+ss_rvt *rv /* Return Reference Valid Flag */
+) {
+ int i;
+ ss_add_soreq(p, ss_SpectrumRequest);
+ ss_add_1(p, 0x09);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_SpectrumAnswer);
+ ss_sub_soans(p, 0x09);
+ *st = ss_sub_1(p);
+ for (i = 0; i < 36; i++)
+ sp[i] = ss_sub_double(p);
+ *rv = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - */
+/* Miscelanious */
+
+/* Query whether a new measurement was performed since the last access */
+inst_code so_do_NewMeasureRequest(
+ss *p,
+ss_nmt *nm /* Return New Measurement (None/Meas/White etc.) */
+) {
+ ss_add_soreq(p, ss_NewMeasureRequest);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_NewMeasureAnswer);
+ if (nm != NULL)
+ *nm = ss_sub_1(p);
+ ss_sub_soans(p, 0x09);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query whether a key was pressed since the last access */
+inst_code so_do_NewKeyRequest(
+ss *p,
+ss_nkt *nk, /* Return whether a new key was pressed */
+ss_ks *k /* Return the key that was pressed (none/meas) */
+) {
+ ss_add_soreq(p, ss_NewKeyRequest);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_NewKeyAnswer);
+ *nk = ss_sub_1(p);
+ *k = ss_sub_2(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query for the general error status */
+inst_code so_do_ActErrorRequest(
+ss *p
+) {
+ ss_add_soreq(p, ss_ActErrorRequest);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_ActErrorAnswer);
+ ss_incorp_err(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Set Target On/Off status (locks key function of device?) */
+inst_code so_do_TargetOnOffStDownload(
+ss *p,
+ss_toost oo /* Activated/Deactivated */
+) {
+ ss_add_soreq(p, ss_TargetOnOffStDownload);
+ ss_add_1(p, 0x00);
+ ss_add_1(p, oo);
+ ss_add_1(p, 0x00);
+ ss_command(p, DF_TMO);
+ ss_sub_soans(p, ss_DownloadError);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* =========================================== */
+/* SpectroScan/T specific commands and queries */
+
+/* - - - - - - - - - - - - - - - - - - - - */
+/* Device Initialisation and configuration */
+
+/* Initialise the device. Scans the Spectrolino */
+/* (Doesn't work when device is offline ) */
+inst_code ss_do_ScanInitializeDevice(ss *p) {
+ ss_add_ssreq(p, ss_InitializeDevice);
+ ss_command(p, IT_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Establish communications between the SpectroScan and Spectrolino */
+/* at the highest possible baud rate. */
+/* (Doesn't work when device is offline ) */
+inst_code ss_do_ScanSpectrolino(ss *p) {
+ ss_add_ssreq(p, ss_ScanSpectrolino);
+ ss_command(p, IT_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Establish the zero position of the motors and set the position to 0,0 */
+/* (Doesn't work when device is offline ) */
+inst_code ss_do_InitMotorPosition(ss *p) {
+ ss_add_ssreq(p, ss_InitMotorPosition);
+ ss_command(p, MV_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Change the SpectroScan baud rate */
+inst_code ss_do_ChangeBaudRate(
+ss *p,
+ss_bt br /* Baud rate (110 - 57600) */
+) {
+ ss_add_ssreq(p, ss_ChangeBaudRate);
+ ss_add_1(p, br);
+ ss_command(p, SH_TMO); /* Don't really expect an answer */
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p); /* Will probably bomb because comms will break down */
+}
+
+/* Change the SpectroScan handshaking mode. */
+inst_code ss_do_ChangeHandshake(
+ss *p,
+ss_hst hs /* Handshake type (None/XonXoff/HW) */
+) {
+ ss_add_ssreq(p, ss_ChangeHandshake);
+ ss_add_1(p, hs);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the type of XY table */
+inst_code ss_do_OutputType(
+ss *p,
+char dt[19] /* Return Device Type ("SpectroScan", "SpectroScan " or "SpectroScanT") */
+) {
+ ss_add_ssreq(p, ss_OutputType);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_TypeAnswer);
+ ss_sub_string(p, dt, 18);
+ chended(p);
+#ifdef EMSST
+ if (strcmp(dt,"SpectroScan ") == 0
+ || strcmp(dt,"SpectroScan") == 0)
+ sprintf(dt,"SpectroScanT");
+#endif
+ return ss_inst_err(p);
+}
+
+/* Query the serial number of the XY table */
+inst_code ss_do_OutputSerialNumber(
+ss *p,
+unsigned int *sn /* Return serial number */
+) {
+ ss_add_ssreq(p, ss_OutputSerialNumber);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_SerialNumberAnswer);
+ *sn = (unsigned int)ss_sub_4(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the part number of the XY table */
+inst_code ss_do_OutputArticleNumber(
+ss *p,
+char pn[9] /* Return Part Number */
+) {
+ ss_add_ssreq(p, ss_OutputArticleNumber);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ArticleNumberAnswer);
+ ss_sub_string(p, pn, 8);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the production date of the XY table */
+inst_code ss_do_OutputProductionDate(
+ss *p,
+int *yp, /* Return Year of production (e.g. 1996) */
+int *mp, /* Return Month of production (1-12) */
+int *dp /* Return Day of production (1-31) */
+) {
+ ss_add_ssreq(p, ss_OutputProductionDate);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ProductionDateAnswer);
+ *dp = ss_sub_2(p);
+ *mp = ss_sub_2(p);
+ *yp = ss_sub_2(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the Software Version of the XY table */
+inst_code ss_do_OutputSoftwareVersion(
+ss *p,
+char sv[13] /* Return Software Version */
+) {
+ ss_add_ssreq(p, ss_OutputSoftwareVersion);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_SoftwareVersionAnswer);
+ ss_sub_string(p, sv, 12);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - - - - - - - - */
+/* Measurement configuration */
+
+/* Set the SpectroScanT to reflectance or transmission. */
+/* The Spectrolino is also automatically set to the corresponding mode. */
+/* (Doesn't work when device is offline ) */
+inst_code ss_do_SetTableMode(
+ss *p,
+ss_tmt tm /* Table mode (Reflectance/Transmission) */
+) {
+#ifdef EMSST
+ if (tm == ss_tmt_Transmission) {
+ if (p->tmode == 0) {
+ ss_do_MoveAbsolut(p, p->sbr, p->sbx, p->sby); /* ?? */
+ }
+ p->tmode = 1;
+ } else {
+ if (p->tmode != 0) {
+ p->tmode = 0;
+ ss_do_MoveHome(p);
+ }
+ p->tmode = 0;
+ }
+ return inst_ok;
+#endif
+ ss_add_ssreq(p, ss_SetTableMode);
+ ss_add_1(p, tm);
+ ss_command(p, IT_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - - - - - - - - */
+/* Table operation */
+
+/* Set the SpectrScan to online. All moving keys are disabled. */
+/* (Only valid when device is in reflectance mode.) */
+inst_code ss_do_SetDeviceOnline(ss *p) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+// return inst_unsupported;
+#endif
+ ss_add_ssreq(p, ss_SetDeviceOnline);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Set the SpectrScan to offline. All moving keys are enabled. */
+/* (Only valid when device is in reflectance mode.) */
+/* (All remote commands to move the device will be ignored.) */
+inst_code ss_do_SetDeviceOffline(ss *p) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_SetDeviceOffline);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Enable electrostatic paper hold. */
+/* (Not valid when device is offline) */
+inst_code ss_do_HoldPaper(ss *p) {
+ ss_add_ssreq(p, ss_HoldPaper);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Disable electrostatic paper hold. */
+/* (Not valid when device is offline) */
+inst_code ss_do_ReleasePaper(ss *p) {
+ ss_add_ssreq(p, ss_ReleasePaper);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - */
+/* Positioning */
+
+/* Move either the sight or sensor to an absolute position. */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveAbsolut(
+ss *p,
+ss_rt r, /* Reference (Sensor/Sight) */
+double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
+double y /* Y coord in mm, 0-230.0, accurate to 0.1mm */
+) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_MoveAbsolut);
+ ss_add_1(p, r);
+ ss_add_2(p, (int)(x * 10 + 0.5));
+ ss_add_2(p, (int)(y * 10 + 0.5));
+ ss_command(p, MV_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Move relative to current position. */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveRelative(
+ss *p,
+double x, /* X distance in mm, 0-310.0, accurate to 0.1mm */
+double y /* Y distance in mm, 0-230.0, accurate to 0.1mm */
+) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_MoveRelative);
+ ss_add_2(p, (int)(x * 10 + 0.5));
+ ss_add_2(p, (int)(y * 10 + 0.5));
+ ss_command(p, MV_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Move to the home position (== 0,0). */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveHome(
+ss *p
+) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_MoveHome);
+ ss_command(p, MV_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Move to the sensor up. */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveUp(
+ss *p
+) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_MoveUp);
+ ss_command(p, MV_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Move to the sensor down. */
+/* (Doesn't work when device is offline or transmission mode.) */
+inst_code ss_do_MoveDown(
+ss *p
+) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_MoveDown);
+ ss_command(p, MV_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the current absolute position of the sensor or sight. */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_OutputActualPosition(
+ss *p,
+ss_rt r, /* Reference (Sensor/Sight) */
+ss_rt *rr, /* Return reference (Sensor/Sight) */
+double *x, /* Return the X coord in mm, 0-310.0, accurate to 0.1mm */
+double *y, /* Return the Y coord in mm, 0-230.0, accurate to 0.1mm */
+ss_zkt *zk /* Return the Z coordinate (Up/Down) */
+) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_OutputActualPosition);
+ ss_add_1(p, r);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_PositionAnswer);
+ *rr = ss_sub_1(p);
+ ss_sub_soans(p, 0x00);
+ ss_sub_soans(p, 0x00);
+ *x = ss_sub_2(p)/10.0;
+ *y = ss_sub_2(p)/10.0;
+ *zk = ss_sub_1(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Move to the white reference position */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveToWhiteRefPos(
+ss *p,
+ss_wrpt wrp /* White Reference Position (Tile1/Tile2) */
+) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_MoveToWhiteRefPos);
+ ss_add_1(p, wrp);
+ ss_command(p, MV_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - - - - - - - */
+/* Performing measurements */
+
+/* Move the sensor to an absolute position, move the */
+/* sensor down, execute a measurement, move the head up, */
+/* and return spectral measuring results. */
+inst_code ss_do_MoveAndMeasure(
+ss *p,
+double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
+double y, /* Y coord in mm, 0-230.0, accurate to 0.1mm */
+double sp[36], /* Return 36 spectral values */
+ss_rvt *rv /* Return Reference Valid Flag */
+) {
+#ifdef EMSST
+ /* Not sure if this is valid on the SpectroScanT in trans mode ? */
+ if (p->tmode != 0) {
+ inst_code rc;
+ p->tmode = 0;
+ rc = ss_do_MoveAndMeasure(p, 155.0, 230.0, sp, rv);
+ ss_do_MoveAbsolut(p, p->sbr, p->sbx, p->sby);
+ p->tmode = 1;
+ return rc;
+ }
+#endif
+ ss_add_ssreq(p, ss_MoveAndMeasure);
+ ss_add_2(p, (int)(x * 10 + 0.5));
+ ss_add_2(p, (int)(y * 10 + 0.5));
+ ss_command(p, MV_TMO);
+ if (ss_peek_ans(p) == ss_SpectrumAnswer) {
+ int i;
+ ss_sub_soans(p, ss_SpectrumAnswer);
+ ss_sub_soans(p, 0x09);
+ ss_sub_soans(p, 0x00);
+ for (i = 0; i < 36; i++)
+ sp[i] = ss_sub_double(p);
+ *rv = ss_sub_1(p);
+ ss_incorp_remerrset(p, ss_sub_2(p));
+ } else {
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ }
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* - - - - - - */
+/* Miscelanious */
+
+/* Set the SpectroScanT transmission light level during standby. */
+/* (Only valid on SpectroScanT in transmission mode) */
+inst_code ss_do_SetLightLevel(
+ss *p,
+ss_llt ll /* Transmission light level (Off/Surround/Low) */
+) {
+#ifdef EMSST
+ if (p->tmode != 0)
+ return inst_ok;
+ else
+ *((char *)0) = 55;
+#endif
+ ss_add_ssreq(p, ss_SetLightLevel);
+ ss_add_1(p, ll);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Set tranmission standby position. */
+/* (Only valid on SpectroScanT in transmission mode) */
+inst_code ss_do_SetTransmStandbyPos(
+ss *p,
+ss_rt r, /* Reference (Sensor/Sight) */
+double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
+double y /* Y coord in mm, 0-230.0, accurate to 0.1mm */
+) {
+#ifdef EMSST
+ if (p->tmode != 0) {
+ p->sbr = r;
+ p->sbx = x;
+ p->sby = y;
+ return inst_ok;
+ } else {
+ *((char *)0) = 55;
+ }
+#endif
+ ss_add_ssreq(p, ss_SetTransmStandbyPos);
+ ss_add_1(p, r);
+ ss_add_2(p, (int)(x * 10 + 0.5));
+ ss_add_2(p, (int)(y * 10 + 0.5));
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Set digitizing mode. Clears digitizing buffer, */
+/* and puts the device offline. The user can move */
+/* and enter positions. */
+inst_code ss_do_SetDigitizingMode(ss *p) {
+ ss_add_ssreq(p, ss_SetDigitizingMode);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Get last digitized position from memory. */
+inst_code ss_do_OutputDigitizingValues(
+ss *p,
+ss_rt r, /* Reference (Sensor/Sight) */
+ss_rt *rr, /* Return reference (Sensor/Sight) */
+int *nrp,/* Return the number of remaining positions in memory. */
+double *x, /* Return the X coord in mm, 0-310.0, accurate to 0.1mm */
+double *y, /* Return the Y coord in mm, 0-230.0, accurate to 0.1mm */
+ss_zkt *zk /* Return the Z coordinate (Up/Down) */
+) {
+ ss_add_ssreq(p, ss_OutputDigitizingValues);
+ ss_add_1(p, r);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_PositionAnswer);
+ *rr = ss_sub_1(p);
+ *nrp = ss_sub_2(p); /* Should be unsigned ?? */
+ *x = ss_sub_2(p)/10.0;
+ *y = ss_sub_2(p)/10.0;
+ *zk = ss_sub_1(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Turn on key aknowledge mode. Causes a KeyAnswer message */
+/* to be generated whenever a key is pressed. */
+/* (KetAnswer isn't well supported here ?) */
+inst_code ss_do_SetKeyAcknowlge(ss *p) {
+ ss_add_ssreq(p, ss_SetKeyAcknowlge);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Turn off key aknowledge mode. */
+inst_code ss_do_ResetKeyAcknowlge(ss *p) {
+ ss_add_ssreq(p, ss_ResetKeyAcknowlge);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the keys that are currently pressed */
+inst_code ss_do_OutputActualKey(
+ss *p,
+ss_sks *sk, /* Return Scan Key Set (Key bitmask) */
+ss_ptt *pt /* Return press time (Short/Long) */
+) {
+ ss_add_ssreq(p, ss_OutputActualKey);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_KeyAnswer);
+ *sk = ss_sub_1(p);
+ *pt = ss_sub_1(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the keys that were last pressed */
+inst_code ss_do_OutputLastKey(
+ss *p,
+ss_sks *sk, /* Return Scan Key bitmask (Keys) */
+ss_ptt *pt /* Return press time (Short/Long) */
+) {
+ ss_add_ssreq(p, ss_OutputLastKey);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_KeyAnswer);
+ *sk = ss_sub_1(p);
+ *pt = ss_sub_1(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the status register */
+inst_code ss_do_OutputStatus(
+ss *p,
+ss_sts *st /* Return status bitmask (Enter key/Online/Digitize/KeyAck/Paper) */
+) {
+ ss_add_ssreq(p, ss_OutputStatus);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_StatusAnswer);
+ *st = ss_sub_1(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Clear the status register */
+inst_code ss_do_ClearStatus(
+ss *p,
+ss_sts st /* Status to reset (Enter key/Online/Digitize/KeyAck/Paper) */
+) {
+ ss_add_ssreq(p, ss_ClearStatus);
+ ss_add_1(p, st);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Set the special status register */
+/* (Set to all 0 on reset) */
+inst_code ss_do_SetSpecialStatus(
+ss *p,
+ss_sss sss /* Status bits to set (HeadDwnOnMv/TableInTransMode/AllLightsOn) */
+) {
+ ss_add_ssreq(p, ss_SetSpecialStatus);
+ ss_add_1(p, sss);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Clear the special status register */
+inst_code ss_do_ClearSpecialStatus(
+ss *p,
+ss_sss sss /* Status bits to clear (HeadDwnOnMv/TableInTransMode/AllLightsOn) */
+) {
+ ss_add_ssreq(p, ss_ClearSpecialStatus);
+ ss_add_1(p, sss);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_ErrorAnswer);
+ ss_incorp_scanerr(p, ss_sub_1(p));
+ chended(p);
+ return ss_inst_err(p);
+}
+
+/* Query the special status register */
+inst_code ss_do_OutputSpecialStatus(
+ss *p,
+ss_sss *sss /* Return Special Status bits */
+) {
+ ss_add_ssreq(p, ss_OutputSpecialStatus);
+ ss_command(p, DF_TMO);
+ ss_sub_ssans(p, ss_StatusAnswer);
+ *sss = ss_sub_1(p);
+ chended(p);
+ return ss_inst_err(p);
+}
+
+
+#define SS_IMP_H
+#endif /* SS_IMP_H */
+
+
diff --git a/spectro/ss_imp.h b/spectro/ss_imp.h
new file mode 100644
index 0000000..c298e80
--- /dev/null
+++ b/spectro/ss_imp.h
@@ -0,0 +1,1335 @@
+
+#ifndef SS_IMP_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Gretag Spectrolino and Spectroscan related
+ * defines and declarations - implementation.
+ *
+ * Author: Graeme W. Gill
+ * Date: 13/7/2005
+ *
+ * Copyright 2005 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * This is an alternative driver to spm/gretag.
+ */
+
+/*
+ If you make use of the instrument driver code here, please note
+ that it is the author(s) of the code who take responsibility
+ for its operation. Any problems or queries regarding driving
+ instruments with the Argyll drivers, should be directed to
+ the Argyll's author(s), and not to any other party.
+
+ If there is some instrument feature or function that you
+ would like supported here, it is recommended that you
+ contact Argyll's author(s) first, rather than attempt to
+ modify the software yourself, if you don't have firm knowledge
+ of the instrument communicate protocols. There is a chance
+ that an instrument could be damaged by an incautious command
+ sequence, and the instrument companies generally cannot and
+ will not support developers that they have not qualified
+ and agreed to support.
+ */
+
+
+/* Communication symbol definitions */
+/* From the Gretag Spectrolino/Spectroscan */
+/* Serial Interface manual. */
+/* We are using the Hex communication method */
+
+/* Timout values for commands */
+#define SH_TMO 0.5 /* Short timout for establishing communications */
+#define IT_TMO 18.0 /* Initialisation commands */
+#define MV_TMO 10.0 /* Move commands */
+#define DF_TMO 6.0 /* Other commands */
+
+/* Actual Filter Type */
+typedef enum {
+ ss_aft_NoDefined = 0x00,
+ ss_aft_NoFilter = 0x01,
+ ss_aft_PolFilter = 0x02,
+ ss_aft_D65Filter = 0x03,
+ ss_aft_UVCutFilter = 0x05,
+ ss_aft_CustomFilter = 0x06
+} ss_aft;
+
+/* Article Number Type */
+
+/* Baudrate Type */
+typedef enum {
+ ss_bt_110 = 0x00,
+ ss_bt_150 = 0x01,
+ ss_bt_300 = 0x02,
+ ss_bt_600 = 0x03,
+ ss_bt_1200 = 0x04,
+ ss_bt_2400 = 0x05,
+ ss_bt_4800 = 0x06,
+ ss_bt_9600 = 0x07,
+ ss_bt_19200 = 0x08,
+ ss_bt_28080 = 0x09,
+ ss_bt_57600 = 0x0A
+} ss_bt;
+
+/* Color Type */
+
+/* COM Float Type */
+typedef enum {
+ ss_comft_vPhotometricYRef = 0x01 /* cd/m^2 */
+} ss_comft;
+
+/* Control Type */
+typedef enum {
+ ss_ctt_ProtokolWithXonXoff = 0x1E,
+ ss_ctt_ProtokolWithoutXonXoff = 0x1F,
+ ss_ctt_ProtokolWithHardwareHS = 0xCF,
+ ss_ctt_SetBaud110 = 0x20,
+ ss_ctt_SetBaud150 = 0x21,
+ ss_ctt_SetBaud300 = 0x22,
+ ss_ctt_SetBaud600 = 0x23,
+ ss_ctt_SetBaud1200 = 0x24,
+ ss_ctt_SetBaud2400 = 0x25,
+ ss_ctt_SetBaud4800 = 0x26,
+ ss_ctt_SetBaud9600 = 0x27,
+ ss_ctt_SetBaud19200 = 0x28,
+ ss_ctt_SetBaud28800 = 0x98,
+ ss_ctt_SetBaud57600 = 0x99,
+ ss_ctt_SpeakerON = 0x54,
+ ss_ctt_SpeakerOFF = 0x55,
+ ss_ctt_RemissionMeas = 0x9B,
+ ss_ctt_TransmissionMeas = 0x9C,
+ ss_ctt_EmissionMeas = 0x9D,
+ ss_ctt_PhotometricAbsolute = 0x9E,
+ ss_ctt_PhotometricRelative = 0x9F,
+ ss_ctt_SetCustomFilter = 0xA0,
+ ss_ctt_ReleaseCustomFilter = 0xA1
+} ss_ctt;
+
+/* Color Space Type */
+typedef enum {
+ ss_cst_XyY = 0x00,
+ ss_cst_Lab = 0x01,
+ ss_cst_LChab = 0x02,
+ ss_cst_Luv = 0x03,
+ ss_cst_XYZ = 0x04,
+ ss_cst_RxRyRz = 0x05,
+ ss_cst_HLab = 0x06,
+ ss_cst_LABmg = 0x0B,
+ ss_cst_LCHmg = 0x0C,
+ ss_cst_LCHuv = 0x0D
+} ss_cst;
+
+/* Date Type */
+
+/* Density Filter Spectral Array Type */
+
+/* Density Filter Array Type */
+
+/* Density Filter Type */
+typedef enum {
+ ss_dft_Db = 0x00,
+ ss_dft_Dc = 0x01,
+ ss_dft_Dm = 0x02,
+ ss_dft_Dy = 0x03,
+ ss_dft_Dmax = 0x04,
+ ss_dft_Dauto = 0x05
+} ss_dft;
+
+/* Device Name Type */
+
+/* Device Number Type */
+typedef enum {
+ ss_dnot_SPM10 = 0x00,
+ ss_dnot_SPM50 = 0x01,
+ ss_dnot_SPM55 = 0x02,
+ ss_dnot_SPM60 = 0x03,
+ ss_dnot_SPM100 = 0x04,
+ ss_dnot_SPM100IInl = 0x05,
+ ss_dnot_SPM100II = 0x06,
+ ss_dnot_D196 = 0x10,
+ ss_dnot_D19C = 0x11,
+ ss_dnot_D118C = 0x12,
+ ss_dnot_DM620 = 0x13,
+ ss_dnot_SPECTROLINO = 0x20,
+ ss_dnot_VIDEOLINO = 0x30,
+ ss_dnot_SPECTROSCAN = 0x40
+} ss_dnot;
+
+/* Dmax OK Type */
+typedef enum {
+ ss_dmot_FALSE = 0x00,
+ ss_dmot_TRUE = 0x01
+} ss_dmot;
+
+/* Dmax Type */
+
+/* Density Standard Type */
+typedef enum {
+ ss_dst_ANSIA = 0x00,
+ ss_dst_ANSIT = 0x01,
+ ss_dst_DIN = 0x02,
+ ss_dst_DINNB = 0x03,
+ ss_dst_DS1 = 0x08 /* User defined */
+} ss_dst;
+
+/* Communication Error Type */
+typedef enum {
+ ss_cet_NoError = 0x00,
+ ss_cet_StopButNoStart = 0x01,
+ ss_cet_IllegalCharInRec = 0x02,
+ ss_cet_IncorrectRecLen = 0x03,
+ ss_cet_IllegalRecType = 0x04,
+ ss_cet_NoTagField = 0x06,
+ ss_cet_ConvError = 0x07,
+ ss_cet_InvalidForEmission = 0x08,
+ ss_cet_NoAccess = 0x10,
+} ss_cet;
+
+/* Daylight Color Temperature Type */
+
+/* Error Type + augmentation */
+typedef enum {
+ ss_et_NoError = 0x00,
+ ss_et_MemoryFailure = 0x01,
+ ss_et_PowerFailure = 0x02,
+ ss_et_LampFailure = 0x04,
+ ss_et_HardwareFailure = 0x05,
+ ss_et_FilterOutOfPos = 0x06,
+ ss_et_SendTimeout = 0x07,
+ ss_et_DriveError = 0x08,
+ ss_et_MeasDisabled = 0x09,
+ ss_et_DensCalError = 0x0A,
+ ss_et_EPROMFailure = 0x0D,
+ ss_et_RemOverFlow = 0x0E,
+ ss_et_MemoryError = 0x10,
+ ss_et_FullMemory = 0x11,
+ ss_et_WhiteMeasOK = 0x13,
+ ss_et_NotReady = 0x15,
+ ss_et_WhiteMeasWarn = 0x32,
+ ss_et_ResetDone = 0x33,
+ ss_et_EmissionCalOK = 0x34,
+ ss_et_OnlyEmission = 0x35,
+ ss_et_CheckSumWrong = 0x36,
+ ss_et_NoValidMeas = 0x37,
+ ss_et_BackupError = 0x38,
+ ss_et_ProgramROMError = 0x3C,
+
+ /* Incororate Remote Error Set values into snerr value */
+ /* Since ss_res is a bit mask, we just prioritize the errors: */
+ ss_et_NoValidDStd = 0x41,
+ ss_et_NoValidWhite = 0x42,
+ ss_et_NoValidIllum = 0x43,
+ ss_et_NoValidObserver = 0x44,
+ ss_et_NoValidMaxLambda = 0x45,
+ ss_et_NoValidSpect = 0x46,
+ ss_et_NoValidColSysOrIndex = 0x47,
+ ss_et_NoValidChar = 0x48,
+ ss_et_DorlOutOfRange = 0x49,
+ ss_et_ReflectanceOutOfRange = 0x4A,
+ ss_et_Color1OutOfRange = 0x4B,
+ ss_et_Color2OutOfRange = 0x4C,
+ ss_et_Color3OutOfRange = 0x4D,
+ ss_et_NotAnSROrBoolean = 0x4E,
+ ss_et_NoValidValOrRef = 0x4F,
+
+ /* Incorporate scan error codes thus: */
+ ss_et_DeviceIsOffline = 0x61,
+ ss_et_OutOfRange = 0x62,
+ ss_et_ProgrammingError = 0x63,
+ ss_et_NoUserAccess = 0x64,
+ ss_et_NoValidCommand = 0x65,
+ ss_et_NoDeviceFound = 0x66,
+ ss_et_MeasurementError = 0x67,
+ ss_et_NoTransmTable = 0x68,
+ ss_et_NotInTransmMode = 0x69,
+ ss_et_NotInReflectMode = 0x6A,
+
+ /* Incorporate communication errors thus: */
+ ss_et_StopButNoStart = 0x81,
+ ss_et_IllegalCharInRec = 0x82,
+ ss_et_IncorrectRecLen = 0x83,
+ ss_et_IllegalRecType = 0x84,
+ ss_et_NoTagField = 0x86,
+ ss_et_ConvError = 0x87,
+ ss_et_InvalidForEmission = 0x88,
+ ss_et_NoAccess = 0x90,
+
+ /* Add our own communication errors here too. */
+ ss_et_SerialFail = 0xF0,
+ ss_et_SendBufferFull = 0xF5,
+ ss_et_RecBufferEmpty = 0xF6,
+ ss_et_BadAnsFormat = 0xF7,
+ ss_et_BadHexEncoding = 0xF8,
+ ss_et_RecBufferOverun = 0xF9
+} ss_et;
+
+/* Handshake Type */
+typedef enum {
+ ss_hst_None = 0x00,
+ ss_hst_XonXOff = 0x01,
+ ss_hst_Hardware = 0x02,
+} ss_hst;
+
+/* Illuminant Type */
+typedef enum {
+ ss_ilt_A = 0x00,
+ ss_ilt_C = 0x01,
+ ss_ilt_D65 = 0x02,
+ ss_ilt_D50 = 0x03,
+ ss_ilt_1 = 0x08, /* User defined */
+ ss_ilt_Dxx = 0x10, /* Variable daylight table */
+ ss_ilt_F1 = 0x18,
+ ss_ilt_F2 = 0x19,
+ ss_ilt_F3 = 0x1A,
+ ss_ilt_F4 = 0x1B,
+ ss_ilt_F5 = 0x1C,
+ ss_ilt_F6 = 0x1D,
+ ss_ilt_F7 = 0x1E,
+ ss_ilt_F8 = 0x1F,
+ ss_ilt_F9 = 0x20,
+ ss_ilt_F10 = 0x21,
+ ss_ilt_F11 = 0x22,
+ ss_ilt_F12 = 0x23
+} ss_ilt;
+
+/* Keyset - treat as cardinal */
+typedef enum {
+ ss_ks_NoKey = 0x0000,
+ ss_ks_MeasurementKey = 0x0080
+} ss_ks;
+
+/* Lambda Type */
+
+/* Light Level Type */
+typedef enum {
+ ss_llt_AllOff = 0x00, /* All lights off during standby */
+ ss_llt_Standby1 = 0x01, /* Surround is on but measurement lamp is off */
+ ss_llt_Standby2 = 0x02, /* Surround is on and measurement lamp is on low */
+} ss_llt;
+
+/* Measurement Mode Type */
+typedef enum {
+ ss_mmt_NormalMeas = 0x00,
+ ss_mmt_WhiteCalibration = 0x01,
+ ss_mmt_WhiteCalWithWarn = 0x07,
+ ss_mmt_EmissionCal = 0x08
+} ss_mmt;
+
+/* New Key Type */
+typedef enum {
+ ss_nkt_False = 0x00,
+ ss_nkt_True = 0x01
+} ss_nkt;
+
+/* New Measurement Type */
+typedef enum {
+ ss_nmt_NoNewMeas = 0x00,
+ ss_nmt_NewMeas = 0x01,
+ ss_nmt_NewWhiteCal = 0x02,
+ ss_nmt_NewWhiteCalWW = 0x03,
+ ss_nmt_NewEmissionCal = 0x04
+} ss_nmt;
+
+/* Observer Type */
+typedef enum {
+ ss_ot_TwoDeg = 0x00,
+ ss_ot_TenDeg = 0x01
+} ss_ot;
+
+/* Original White Reference Type */
+typedef enum {
+ ss_owrt_OriginalWhiteRef = 0x00,
+ ss_owrt_OriginalUserWhiteRef = 0x01,
+ ss_owrt_NotDefWhiteRef = 0x02
+} ss_owrt;
+
+
+/* Output Set Type */
+typedef enum {
+ ss_ost_ParameterSet = 0x00, /* To define measurement of parameters for output */
+ ss_ost_SpectrumSet = 0x01, /* To define spectra for output */
+ ss_ost_CMetry1Set = 0x02, /* To define colorimetry values for output */
+ ss_ost_CMetry2Set = 0x03, /* To define colorimetry values for output */
+ ss_ost_DensitySet = 0x04, /* To define densitometry values for output */
+ ss_ost_ErrorType = 0xFF /* To get the error of the measurement */
+} ss_ost;
+
+/* Output Parameter Set - bit masks */
+typedef enum {
+ ss_ops_None = 0x00,
+ ss_ops_DStdType = 0x01,
+ ss_ops_WBase = 0x02,
+ ss_ops_Illuminant = 0x04,
+ ss_ops_Observer = 0x08,
+ ss_ops_ActualFilter = 0x10
+} ss_ops;
+
+/* Output Spectrum Set - bit masks */
+typedef enum {
+ ss_oss_None = 0x00,
+ ss_oss_Spectrum = 0x01,
+ ss_oss_Density = 0x02
+} ss_oss;
+
+/* Output Colorimetry 1 Set - bit masks */
+typedef enum {
+ ss_oc1s_None = 0x00,
+ ss_oc1s_xyY = 0x01,
+ ss_oc1s_Lab = 0x02,
+ ss_oc1s_LChab = 0x04,
+ ss_oc1s_Luv = 0x08,
+ ss_oc1s_XYZ = 0x10,
+ ss_oc1s_RxRyRz = 0x20,
+ ss_oc1s_HLab = 0x40
+} ss_oc1s;
+
+/* Output Colorimetry 2 Set - bit masks */
+typedef enum {
+ ss_oc2s_None = 0x00,
+ ss_oc2s_LABmg = 0x01,
+ ss_oc2s_LCHmg = 0x02,
+ ss_oc2s_LChuv = 0x04
+} ss_oc2s;
+
+/* Output Density Set - bit masks */
+typedef enum {
+ ss_ods_None = 0x00,
+ ss_ods_Black = 0x01,
+ ss_ods_Cyan = 0x02,
+ ss_ods_Magenta = 0x04,
+ ss_ods_Yellow = 0x08,
+ ss_ods_Max = 0x10,
+ ss_ods_Auto = 0x20
+} ss_ods;
+
+/* Type that is one of the above, depending on what ss_ost is selected */
+typedef union {
+ ss_ods od;
+ ss_oss os;
+ ss_oc1s oc1;
+ ss_oc2s oc2;
+ ss_ops op;
+ int i;
+} ss_os;
+
+
+/* Press Time Type */
+typedef enum {
+ ss_ptt_Short = 0x00,
+ ss_ptt_Long = 0x01
+} ss_ptt;
+
+/* Reference Type */
+typedef enum {
+ ss_rt_SensorRef = 0x00,
+ ss_rt_SightRef = 0x01
+} ss_rt;
+
+/* Reference Valid Type */
+typedef enum {
+ ss_rvt_False = 0x00,
+ ss_rvt_True = 0x01
+} ss_rvt;
+
+/* Remaining Positions Type */
+
+/* Remote Error Set - bit mask - treat as cardinal */
+typedef enum {
+ ss_res_NoError = 0x0000,
+ ss_res_NoValidDStd = 0x0001,
+ ss_res_NoValidWhite = 0x0002,
+ ss_res_NoValidIllum = 0x0004,
+ ss_res_NoValidObserver = 0x0008,
+ ss_res_NoValidMaxLambda = 0x0010,
+ ss_res_NoValidSpect = 0x0020,
+ ss_res_NoValidColSysOrIndex = 0x0040,
+ ss_res_NoValidChar = 0x0080,
+ ss_res_SlopeOutOfRange = 0x0100,
+ ss_res_DorlOutOfRange = 0x0200,
+ ss_res_ReflectanceOutOfRange = 0x0400,
+ ss_res_Color1OutOfRange = 0x0800,
+ ss_res_Color2OutOfRange = 0x1000,
+ ss_res_Color3OutOfRange = 0x2000,
+ ss_res_NotAnSROrBoolean = 0x4000,
+ ss_res_NoValidValOrRef = 0x8000,
+} ss_res;
+
+/* Scan Error Type */
+typedef enum {
+ ss_set_NoError = 0x00,
+ ss_set_DeviceIsOffline = 0x01,
+ ss_set_OutOfRange = 0x02,
+ ss_set_ProgrammingError = 0x03,
+ ss_set_NoUserAccess = 0x04,
+ ss_set_NoValidCommand = 0x05,
+ ss_set_NoDeviceFound = 0x06,
+ ss_set_MeasurementError = 0x07,
+ ss_set_NoTransmTable = 0x08,
+ ss_set_NotInTransmMode = 0x09,
+ ss_set_NotInReflectMode = 0x0A
+} ss_set;
+
+/* Scan Key Set - bit mask */
+typedef enum {
+ ss_sks_EnterKey = 0x01,
+ ss_sks_PaperKey = 0x02,
+ ss_sks_OnlineKey = 0x04,
+ ss_sks_UpDownKey = 0x08,
+ ss_sks_MoveRightKey = 0x10,
+ ss_sks_MoveLeftKey = 0x20,
+ ss_sks_MoveDownKey = 0x40,
+ ss_sks_MoveUpKey = 0x80
+} ss_sks;
+
+/* Serial Number Type */
+
+/* Special Status Set - bit mask */
+typedef enum {
+ ss_sss_HeadDwnOnMove = 0x01, /* Don't lift the head when moving */
+ ss_sss_TableInTransMode = 0x10, /* Table is set to transmission mode */
+ ss_sss_AllLightsOn = 0x20 /* Surround light on + low measure light */
+} ss_sss;
+
+/* Spect. Type */
+typedef enum {
+ ss_st_LinearSpectrum = 0x00,
+ ss_st_DensitySpectrum = 0x01
+} ss_st;
+
+/* Status Mode Type */
+typedef enum {
+ ss_smt_InitAll = 0x01,
+ ss_smt_InitWithoutRemote = 0x05
+} ss_smt;
+
+/* Status Set - bit mask */
+typedef enum {
+ ss_sts_EnterKeyPressed = 0x01,
+ ss_sts_DeviceIsOnline = 0x10,
+ ss_sts_DigitizingModeOn = 0x20,
+ ss_sts_KeyAckModeOn = 0x40,
+ ss_sts_PaperIsHeld = 0x80
+} ss_sts;
+
+/* Standard Density Filter Type */
+typedef enum {
+ ss_sdft_Db = 0x00,
+ ss_sdft_Dc = 0x01,
+ ss_sdft_Dm = 0x02,
+ ss_sdft_Dy = 0x03
+} ss_sdft;
+
+/* Table Mode Type */
+typedef enum {
+ ss_tmt_Reflectance = 0x00,
+ ss_tmt_Transmission = 0x01
+} ss_tmt;
+
+/* Table Value Type */
+typedef enum {
+ ss_tvt_vDxx1 = 0x60
+} ss_tvt;
+
+/* Target On Off Status Type (Enables/Disables measurement key ?) */
+typedef enum {
+ ss_toost_Activated = 0x00,
+ ss_toost_Deactivated = 0x01
+} ss_toost;
+
+/* Target Tech Type */
+typedef enum {
+ ss_ttt_SPM = 0x00,
+ ss_ttt_D190 = 0x01,
+ ss_ttt_Spectrolino = 0x02,
+ ss_ttt_Videolino = 0x03,
+ ss_ttt_SpectroScan = 0x04
+} ss_ttt;
+
+/* White Base Type */
+typedef enum {
+ ss_wbt_Pap = 0x00,
+ ss_wbt_Abs = 0x01
+} ss_wbt;
+
+/* White Reference Position Type */
+typedef enum {
+ ss_wrpt_RefTile1 = 0x00,
+ ss_wrpt_RefTile2 = 0x01
+} ss_wrpt;
+
+/* Zed Koordinate Type Type */
+typedef enum {
+ ss_zkt_SensorUp = 0x00,
+ ss_zkt_SensorDown = 0x01
+} ss_zkt;
+
+/* Spectrolino request and answer types */
+typedef enum {
+ ss_ParameterRequest = 0x00,
+ ss_ParameterAnswer = 0x0B,
+ ss_SlopeRequest = 0x01,
+ ss_SlopeAnswer = 0x0C,
+ ss_DensityRequest = 0x03,
+ ss_DensityAnswer = 0x0E,
+ ss_DmaxRequest = 0x04,
+ ss_DmaxAnswer = 0x0F,
+ ss_SpectrumRequest = 0x05,
+ ss_SpectrumAnswer = 0x10,
+ ss_CRequest = 0x06,
+ ss_CAnswer = 0x11,
+ ss_NewMeasureRequest = 0x07,
+ ss_NewMeasureAnswer = 0x12,
+ ss_NewKeyRequest = 0x08,
+ ss_NewKeyAnswer = 0x13,
+ ss_ParameterDownload = 0x16,
+ ss_SlopeDownload = 0x17,
+ ss_DownloadError = 0x1F,
+ ss_ExecMeasurement = 0x20,
+ ss_ExecWhiteMeasurement = 0x21,
+ ss_ExecRefMeasurement = 0x22,
+ ss_ExecError = 0x25,
+ ss_ActErrorRequest = 0x29,
+ ss_ActErrorAnswer = 0x2F,
+ ss_TargetIdRequest = 0x2B,
+ ss_TargetIdAnswer = 0x31,
+ ss_TargetOnOffStDownload = 0x33,
+ ss_IllumTabRequest = 0x38,
+ ss_IllumTabAnswer = 0x39,
+ ss_IllumTabDownload = 0x3A,
+ ss_DensTabRequest = 0x3B,
+ ss_DensTabAnswer = 0x3C,
+ ss_DensTabDownload = 0x3D,
+ ss_GetValNr = 0x47,
+ ss_ValNrAnswer = 0x48,
+ ss_SetValNr = 0x49,
+ ss_ExecWhiteRefToOrigDat = 0x4A,
+ ss_MeasControlDownload = 0x4D,
+ ss_ResetStatusDownload = 0x5A,
+ ss_MeasControlRequest = 0x5B,
+ ss_MeasControlAnswer = 0x5C,
+ ss_SetMeasurementOutput = 0xB1,
+ ss_WhiteReferenceRequest = 0xB3,
+ ss_WhiteReferenceAnswer = 0xB4,
+ ss_DeviceDataRequest = 0xB5,
+ ss_DeviceDataAnswer = 0xB6,
+ ss_WhiteReferenceDownld = 0xB7,
+ ss_SpecParameterRequest = 0xB8,
+ ss_SpecParameterAnswer = 0xB9,
+ ss_CParameterRequest = 0xBA,
+ ss_CParameterAnswer = 0xBB,
+ ss_DensityParameterAnswer = 0xBC,
+ ss_DensityParameterRequest = 0xBD,
+ ss_Printout = 0xBE,
+ ss_FloatRequest = 0xC0,
+ ss_FloatAnswer = 0xC1,
+ ss_FloatDownload = 0xC2,
+ ss_COMErr = 0x26
+} ss_so_cat;
+
+/* Spectroscan request and answer types */
+typedef enum {
+ ss_ReqPFX = 0xD0, /* Prefix */
+ ss_AnsPFX = 0xD1, /* Prefix */
+ ss_MoveAbsolut = 0x00,
+ ss_MoveRelative = 0x01,
+ ss_MoveHome = 0x02,
+ ss_MoveUp = 0x03,
+ ss_MoveDown = 0x04,
+ ss_OutputActualPosition = 0x05,
+ ss_MoveToWhiteRefPos = 0x06,
+ ss_MoveAndMeasure = 0x07,
+ ss_InitializeDevice = 0x0A,
+ ss_ScanSpectrolino = 0x0B,
+ ss_InitMotorPosition = 0x0C,
+ ss_SetTableMode = 0x0D,
+ ss_SetLightLevel = 0x0E,
+ ss_SetTransmStandbyPos = 0x0F,
+ ss_SetDeviceOnline = 0x10,
+ ss_SetDeviceOffline = 0x11,
+ ss_HoldPaper = 0x12,
+ ss_ReleasePaper = 0x13,
+ ss_SetDigitizingMode = 0x14,
+ ss_OutputDigitizingValues = 0x15,
+ ss_SetKeyAcknowlge = 0x16,
+ ss_ResetKeyAcknowlge = 0x17,
+ ss_ChangeBaudRate = 0x20,
+ ss_ChangeHandshake = 0x21,
+ ss_OutputActualKey = 0x22,
+ ss_OutputLastKey = 0x23,
+ ss_OutputStatus = 0x24,
+ ss_ClearStatus = 0x25,
+ ss_SetSpecialStatus = 0x26,
+ ss_ClearSpecialStatus = 0x27,
+ ss_OutputSpecialStatus = 0x28,
+ ss_OutputType = 0x30,
+ ss_OutputSerialNumber = 0x31,
+ ss_OutputArticleNumber = 0x32,
+ ss_OutputProductionDate = 0x33,
+ ss_OutputSoftwareVersion = 0x34,
+ ss_ErrorAnswer = 0x80,
+ ss_PositionAnswer = 0x81,
+ ss_KeyAnswer = 0x82,
+ ss_StatusAnswer = 0x83,
+ ss_TypeAnswer = 0x90,
+ ss_SerialNumberAnswer = 0x91,
+ ss_ArticleNumberAnswer = 0x92,
+ ss_ProductionDateAnswer = 0x93,
+ ss_SoftwareVersionAnswer = 0x94,
+ ss_SSCOMErr = 0xA0
+} ss_ss_cat;
+
+/* -------------------------- */
+/* Interface declarations */
+
+struct _ss;
+
+/* ------------------------------------------- */
+/* Serialisation for different types functions */
+
+/* QUERY: */
+/* Reset send buffer, and init with start character */
+void ss_init_send(struct _ss *p);
+
+/* Reset send buffer, and add an Spectrolino Request enum */
+void ss_add_soreq(struct _ss *p, int rq);
+
+/* Reset send buffer, and add an SpectroScan Request enum */
+void ss_add_ssreq(struct _ss *p, int rq);
+
+/* Add an int/enum/char into one byte type */
+void ss_add_1(struct _ss *p, int c);
+
+/* Add an int/enum into two byte type */
+void ss_add_2(struct _ss *p, int s);
+
+/* Add an int/enum into four byte type */
+void ss_add_4(struct _ss *p, int i);
+
+/* Add a double into four byte type */
+void ss_add_double(struct _ss *p, double d);
+
+/* Add an ASCII string into the send buffer. */
+/* The string will be padded with nul's up to len. */
+void ss_add_string(struct _ss *p, char *t, int len);
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* ANSWER: */
+
+/* Return the first enum from the recieve buffer without removing it. */
+int ss_peek_ans(struct _ss *p);
+
+/* Remove a Spectrolino answer enum from the revieve buffer, */
+/* and check it is correct. */
+void ss_sub_soans(struct _ss *p, int cv);
+
+/* Remove a SpectroScan Prefix and answer enum from the revieve buffer, */
+/* and check it is correct. */
+void ss_sub_ssans(struct _ss *p, int cv);
+
+/* Remove an int/enum/char into one byte type */
+int ss_sub_1(struct _ss *p);
+
+/* Remove an int/enum into two byte type */
+int ss_sub_2(struct _ss *p);
+
+/* Remove an int/enum into four byte type */
+int ss_sub_4(struct _ss *p);
+
+/* Remove a double into four byte type */
+double ss_sub_double(struct _ss *p);
+
+/* Remove an ASCII string from the receive buffer. */
+/* The string will be terminated with a nul, so a buffer */
+/* of len+1 should be provided to return the string in. */
+void ss_sub_string(struct _ss *p, char *t, int len);
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* ERROR CODES: */
+
+/* Convert an ss error into an inst_error */
+inst_code ss_inst_err(struct _ss *p);
+
+/* Incorporate a error into the snerr value */
+void ss_incorp_err(struct _ss *p, ss_et se);
+
+/* Incororate Remote Error Set values into snerr value */
+/* Since ss_res is a bit mask, we just prioritize the errors. */
+void ss_incorp_remerrset(struct _ss *p, ss_res es);
+
+/* Incorporate a scan error into the snerr value */
+void ss_incorp_scanerr(struct _ss *p, ss_set se);
+
+/* Incorporate a device communication error into the snerr value */
+void ss_incorp_comerr(struct _ss *p, ss_cet se);
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* EXECUTION: */
+
+/* Interpret an icoms error into a SS error */
+int icoms2ss_err(int se);
+
+/* Terminate the send buffer, and then do a */
+/* send/receieve to the device. */
+/* Leave any error in p->snerr */
+void ss_command(struct _ss *p, double tmo);
+
+/* - - - - - - - - - - - - - - - - - - - - */
+/* Device Initialisation and configuration */
+
+/* Reset instrument */
+inst_code so_do_ResetStatusDownload(
+struct _ss *p,
+ss_smt sm /* Init all or all except communications */
+);
+
+/* Load various parameters, such as: */
+/* comm flow control, baud rate, speaker, */
+/* reflective/tranmission/emmission mode, */
+/* custom filter on/off */
+inst_code so_do_MeasControlDownload(
+struct _ss *p,
+ss_ctt ct /* Control */
+);
+
+/* Query various current parameters, such as: */
+/* comm flow control, baud rate, speaker, */
+/* reflective/tranmission/emmission mode, */
+/* custom filter on/off. */
+inst_code so_do_MeasControlRequest(
+struct _ss *p,
+ss_ctt ct, /* Control to query */
+ss_ctt *rct /* Return current state */
+);
+
+/* Queries specific device data */
+inst_code so_do_DeviceDataRequest(
+struct _ss *p,
+char dn[19], /* Return the device name */
+ss_dnot *dno, /* Return device number */
+char pn[9], /* Return the part number */
+unsigned int *sn, /* Return serial number */
+char sv[13] /* Return software version */
+);
+
+/* Query special device data */
+inst_code so_do_TargetIdRequest(
+struct _ss *p,
+char dn[19], /* Return Device Name */
+int *sn, /* Return Serial Number (1-65535) */
+int *sr, /* Return Software Release */
+int *yp, /* Return Year of production (e.g. 1996) */
+int *mp, /* Return Month of production (1-12) */
+int *dp, /* Return Day of production (1-31) */
+int *hp, /* Return Hour of production (0-23) */
+int *np, /* Return Minuite of production (0-59) */
+ss_ttt *tt, /* Return Target Tech Type (SPM/Spectrolino etc.) */
+int *fswl, /* Return First spectral wavelength (nm) */
+int *nosw, /* Return Number of spectral wavelengths */
+int *dpsw /* Return Distance between spectral wavelengths (nm) */
+);
+
+/* - - - - - - - - - - - - - */
+/* Measurement configuration */
+
+/* Query the standard or user definable densitometric tables */
+inst_code so_do_DensTabRequest(
+struct _ss *p,
+ss_dst ds, /* Density standard (ANSI/DIN/User etc.) */
+ss_dst *rds, /* Return Density standard (ANSI/DIN/User etc.) */
+double sp[4][36] /* Return 4 * 36 spectral weighting values */
+);
+
+/* Download user definable densitometric tables */
+inst_code so_do_DensTabDownload(
+struct _ss *p,
+double sp[4][36] /* 4 * 36 spectral weighting values */
+);
+
+/* Set slope values for densitometry */
+inst_code so_do_SlopeDownload(
+struct _ss *p,
+double dv[4] /* Db Dc Dm Dy density values */
+);
+
+/* Query slope values of densitometry */
+inst_code so_do_SlopeRequest(
+struct _ss *p,
+double dv[4] /* Return Db Dc Dm Dy density values */
+);
+
+/* Set the colorimetric parameters */
+inst_code so_do_ParameterDownload(
+struct _ss *p,
+ss_dst ds, /* Density standard (ANSI/DIN etc.) */
+ss_wbt wb, /* White base (Paper/Absolute) */
+ss_ilt it, /* Illuminant type (A/C/D65 etc.) */
+ss_ot ot /* Observer type (2deg/10deg) */
+);
+
+/* Query colorimetric parameters */
+inst_code so_do_ParameterRequest(
+struct _ss *p,
+ss_dst *ds, /* Return Density Standard */
+ss_wbt *wb, /* Return White Base */
+ss_ilt *it, /* Return Illuminant type (A/C/D65/User etc.) */
+ss_ot *ot, /* Return Observer type (2deg/10deg) */
+ss_aft *af /* Return Filter being used (None/Pol/D65/UV/custom */
+);
+
+/* Query the standard or user defined illuminant tables (Colorimetry) */
+inst_code so_do_IllumTabRequest(
+struct _ss *p,
+ss_ilt it, /* Illuminant type (A/C/D65/User etc.) */
+ss_ilt *rit, /* Return Illuminant type (A/C/D65/User etc.) */
+double sp[36] /* Return 36 spectral values */
+);
+
+/* Download user definable illuminant tables (Colorimetry) */
+inst_code so_do_IllumTabDownload(
+struct _ss *p,
+double sp[36] /* 36 spectral values to set */
+);
+
+/* Query for the color temperature of daylight illuminant Dxx */
+inst_code so_do_GetValNr(
+struct _ss *p,
+int *ct /* Return color temperature in deg K/100 */
+);
+
+/* Download user definable illuminant tables (Colorimetry) */
+inst_code so_do_SetValNr(
+struct _ss *p,
+int ct /* Color temperature to set for illuminant Dxx in deg K/100 */
+);
+
+/* Queries the spectra of the white reference for the desired filter */
+inst_code so_do_WhiteReferenceRequest(
+struct _ss *p,
+ss_aft af, /* Filter being queried (None/Pol/D65/UV/custom */
+ss_aft *raf, /* Return filter being queried (None/Pol/D65/UV/custom */
+double sp[36], /* Return 36 spectral values */
+ss_owrt *owr, /* Return original white reference */
+char dtn[19] /* Return name of data table */
+);
+
+/* Load spectra of a user defined white reference for the desired filter. */
+/* A name can be given to the white reference. */
+inst_code so_do_WhiteReferenceDownld(
+struct _ss *p,
+ss_aft af, /* Filter being set (None/Pol/D65/UV/custom */
+double sp[36], /* 36 spectral values being set */
+char dtn[19] /* Name for data table */
+);
+
+/* Query the reference value for the relative photometric (emission) reference value */
+inst_code so_do_FloatRequest(
+struct _ss *p,
+ss_comft comf, /* Choose common float type (PhotometricYRef) */
+ss_comft *rcomf, /* Return common float type (PhotometricYRef) */
+double *comfv /* Return the reference value */
+);
+
+/* Set the reference value for the relative photometric (emission) reference value */
+inst_code so_do_FloatDownload(
+struct _ss *p,
+ss_comft comf, /* Choose common float type (PhotometricYRef) */
+double comfv /* The reference value */
+);
+
+/* - - - - - - */
+/* Calibration */
+
+/* Reset the spectra of the respective white reference to the original data */
+inst_code so_do_ExecWhiteRefToOrigDat(
+struct _ss *p
+);
+
+
+/* Perform a Reference Measurement */
+inst_code so_do_ExecRefMeasurement(
+struct _ss *p,
+ss_mmt mm /* Measurement Mode (Meas/Cal etc.) */
+);
+
+/* Perform a White Measurement - not recommended */
+/* (ExecRefMeasuremen is preferred instead) */
+inst_code so_do_ExecWhiteMeasurement(struct _ss *p);
+
+/* - - - - - - - - - - - - */
+/* Performing measurements */
+
+/* Perform a Measurement */
+inst_code so_do_ExecMeasurement(struct _ss *p);
+
+/* Define automatic output after each measurement */
+/* [Note that dealing with the resulting measurement replies */
+/* isn't directly supported, currently.] */
+inst_code so_do_SetMeasurementOutput(
+struct _ss *p,
+ss_ost os, /* Type of output to request */
+ss_os o /* bitmask of output */
+);
+
+/* - - - - - - - - */
+/* Getting results */
+
+/* Query Density measurement results and associated parameters */
+inst_code so_do_DensityParameterRequest(
+struct _ss *p,
+ss_cst *rct, /* Return Color Type (Lab/XYZ etc.) */
+double dv[4], /* Return Db Dc Dm Dy density values */
+ss_sdft *sdf, /* Return Standard Density Filter (Db/Dc/Dm/Dy) */
+ss_rvt *rv, /* Return Reference Valid Flag */
+ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom */
+ss_wbt *wb, /* Return white base (Paper/Absolute) */
+ss_dst *ds, /* Return Density standard (ANSI/DIN/User etc.) */
+ss_ilt *rit, /* Return Illuminant type (A/C/D65/User etc.) */
+ss_ot *ot /* Return Observer type (2deg/10deg) */
+);
+
+/* Query Densitometric measurement values - not recommended */
+/* (DensityParameterRequest is preferred instead) */
+inst_code so_do_DensityRequest(
+struct _ss *p,
+double dv[4], /* Return Db Dc Dm Dy density values */
+ss_sdft *sdf, /* Return Standard Density Filter (Db/Dc/Dm/Dy) */
+ss_rvt *rv /* Return Reference Valid */
+);
+
+/* Query maximum density reading */
+inst_code so_do_DmaxRequest(
+struct _ss *p,
+double *Dmax, /* Return Value of Maximum Density */
+int *lambda, /* Return wavelength where maximum density was found */
+ss_dmot *dmo, /* Return Dmax OK flag. */
+ss_rvt *rv /* Return Reference Valid Flag */
+);
+
+/* Query Color measurement results and associated parameters */
+inst_code so_do_CParameterRequest(
+struct _ss *p,
+ss_cst ct, /* Choose Color Type (Lab/XYZ etc.) */
+ss_cst *rct, /* Return Color Type (Lab/XYZ etc.) */
+double cv[3], /* Return 3 color values */
+ss_rvt *rv, /* Return Reference Valid Flag */
+ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom) */
+ss_wbt *wb, /* Return white base (Paper/Absolute) */
+ss_ilt *it, /* Return Illuminant type (A/C/D65/User etc.) */
+ss_ot *ot /* Return Observer type (2deg/10deg) */
+);
+
+/* Query Colorimetric measurement results - not recommended */
+/* (CParameterRequest is prefered instead) */
+inst_code so_do_CRequest(
+struct _ss *p,
+ss_cst *ct, /* Return Color Type (Lab/XYZ etc.) */
+double *cv[3], /* Return 3 color values */
+ss_rvt *rv /* Return Reference Valid Flag */
+);
+
+/* Query Spectral measurement results and associated parameters */
+inst_code so_do_SpecParameterRequest(
+struct _ss *p,
+ss_st st, /* Choose Spectrum Type (Reflectance/Density) */
+ss_st *rst, /* Return Spectrum Type (Reflectance/Density) */
+double sp[36], /* Return 36 spectral values */
+ss_rvt *rv, /* Return Reference Valid Flag */
+ss_aft *af, /* Return filter being used (None/Pol/D65/UV/custom */
+ss_wbt *wb /* Return white base (Paper/Absolute) */
+);
+
+/* Query Spectral measurement results - not recommended */
+/* (SpecParameterRequest is preferred instead) */
+inst_code so_do_SpectrumRequest(
+struct _ss *p,
+ss_st *st, /* Return Spectrum Type (Reflectance/Density) */
+double sp[36], /* Return 36 spectral values */
+ss_rvt *rv /* Return Reference Valid Flag */
+);
+
+/* - - - - - - */
+/* Miscelanious */
+
+/* Query whether a new measurement was performed since the last accestruct _ss */
+inst_code so_do_NewMeasureRequest(
+struct _ss *p,
+ss_nmt *nm /* Return New Measurement (None/Meas/White etc.) */
+);
+
+/* Query whether a key was pressed since the last accestruct _ss */
+inst_code so_do_NewKeyRequest(
+struct _ss *p,
+ss_nkt *nk, /* Return whether a new key was pressed */
+ss_ks *k /* Return the key that was pressed (none/meas) */
+);
+
+/* Query for the general error status */
+inst_code so_do_ActErrorRequest(
+struct _ss *p
+);
+
+/* Set Target On/Off status (Enables/Disables measurement key ?) */
+inst_code so_do_TargetOnOffStDownload(
+struct _ss *p,
+ss_toost oo /* Activated/Deactivated */
+);
+
+/* =========================================== */
+/* SpectroScan/T specific commands and queries */
+
+/* - - - - - - - - - - - - - - - - - - - - */
+/* Device Initialisation and configuration */
+
+/* Initialise the device. Scans the Spectrolino */
+/* (Doesn't work when device is offline ) */
+inst_code ss_do_ScanInitializeDevice(struct _ss *p);
+
+/* Establish communications between the SpectroScan and Spectrolino */
+/* at the highest possible baud rate. */
+/* (Doesn't work when device is offline ) */
+inst_code ss_do_ScanSpectrolino(struct _ss *p);
+
+/* Establish the zero position of the motors and set the position to 0,0 */
+/* (Doesn't work when device is offline ) */
+inst_code ss_do_InitMotorPosition(struct _ss *p);
+
+/* Change the SpectroScan baud rate */
+inst_code ss_do_ChangeBaudRate(
+struct _ss *p,
+ss_bt br /* Baud rate (110 - 57600) */
+);
+
+/* Change the SpectroScan handshaking mode. */
+inst_code ss_do_ChangeHandshake(
+struct _ss *p,
+ss_hst hs /* Handshake type (None/XonXoff/HW) */
+);
+
+/* Query the type of XY table */
+inst_code ss_do_OutputType(
+struct _ss *p,
+char dt[19] /* Return Device Type ("SpectroScan " or "SpectroScanT") */
+);
+
+/* Query the serial number of the XY table */
+inst_code ss_do_OutputSerialNumber(
+struct _ss *p,
+unsigned int *sn /* Return serial number */
+);
+
+/* Query the part number of the XY table */
+inst_code ss_do_OutputArticleNumber(
+struct _ss *p,
+char pn[9] /* Return Part Number */
+);
+
+/* Query the production date of the XY table */
+inst_code ss_do_OutputProductionDate(
+struct _ss *p,
+int *yp, /* Return Year of production (e.g. 1996) */
+int *mp, /* Return Month of production (1-12) */
+int *dp /* Return Day of production (1-31) */
+);
+
+/* Query the Software Version of the XY table */
+inst_code ss_do_OutputSoftwareVersion(
+struct _ss *p,
+char sv[13] /* Return Software Version */
+);
+
+/* - - - - - - - - - - - - - */
+/* Measurement configuration */
+
+/* Set the SpectroScanT to reflectance or transmission. */
+/* The Spectrolino is also automatically set to the corresponding mode. */
+/* (Doesn't work when device is offline ) */
+inst_code ss_do_SetTableMode(
+struct _ss *p,
+ss_tmt tm /* Table mode (Reflectance/Transmission) */
+);
+
+/* - - - - - - - - - - - - - */
+/* Table operation */
+
+/* Set the SpectrScan to online. All moving keys are disabled. */
+/* (Only valid when device is in reflectance mode.) */
+inst_code ss_do_SetDeviceOnline(struct _ss *p);
+
+/* Set the SpectrScan to offline. All moving keys are enabled. */
+/* (Only valid when device is in reflectance mode.) */
+/* (All remote commands to move the device will be ignored.) */
+inst_code ss_do_SetDeviceOffline(struct _ss *p);
+
+/* Enable electrostatic paper hold. */
+/* (Not valid when device is offline) */
+inst_code ss_do_HoldPaper(struct _ss *p);
+
+/* Disable electrostatic paper hold. */
+/* (Not valid when device is offline) */
+inst_code ss_do_ReleasePaper(struct _ss *p);
+
+/* - - - - - - */
+/* Positioning */
+
+/* Move either the sight or sensor to an absolute position. */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveAbsolut(
+struct _ss *p,
+ss_rt r, /* Reference (Sensor/Sight) */
+double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
+double y /* Y coord in mm, 0-230.0, accurate to 0.1mm */
+);
+
+/* Move relative to current position. */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveRelative(
+struct _ss *p,
+double x, /* X distance in mm, 0-310.0, accurate to 0.1mm */
+double y /* Y distance in mm, 0-230.0, accurate to 0.1mm */
+);
+
+/* Move to the home position (== 0,0). */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveHome(
+struct _ss *p
+);
+
+/* Move to the sensor up. */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveUp(
+struct _ss *p
+);
+
+/* Move to the sensor down. */
+/* (Doesn't work when device is offline or transmission mode.) */
+inst_code ss_do_MoveDown(
+struct _ss *p
+);
+
+/* Query the current absolute position of the sensor or sight. */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_OutputActualPosition(
+struct _ss *p,
+ss_rt r, /* Reference (Sensor/Sight) */
+ss_rt *rr, /* Return reference (Sensor/Sight) */
+double *x, /* Return the X coord in mm, 0-310.0, accurate to 0.1mm */
+double *y, /* Return the Y coord in mm, 0-230.0, accurate to 0.1mm */
+ss_zkt *zk /* Return the Z coordinate (Up/Down) */
+);
+
+/* Move to the white reference position */
+/* (Doesn't work when device is offline or transmissioin mode.) */
+inst_code ss_do_MoveToWhiteRefPos(
+struct _ss *p,
+ss_wrpt wrp /* White Reference Position (Tile1/Tile2) */
+);
+
+/* - - - - - - - - - - - - */
+/* Performing measurements */
+
+/* Move the sensor to an absolute position, move the */
+/* sensor down, execute a measurement, move the head up, */
+/* and return spectral measuring results. */
+inst_code ss_do_MoveAndMeasure(
+struct _ss *p,
+double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
+double y, /* Y coord in mm, 0-230.0, accurate to 0.1mm */
+double sp[36], /* Return 36 spectral values */
+ss_rvt *rv /* Return Reference Valid Flag */
+);
+
+/* - - - - - - */
+/* Miscelanious */
+
+/* Set the SpectroScanT transmission light level during standby. */
+/* (Only valid on SpectroScanT in transmission mode) */
+inst_code ss_do_SetLightLevel(
+struct _ss *p,
+ss_llt ll /* Transmission light level (Off/Surround/Low) */
+);
+
+/* Set tranmission standby position. */
+/* (Only valid on SpectroScanT in transmission mode) */
+inst_code ss_do_SetTransmStandbyPos(
+struct _ss *p,
+ss_rt r, /* Reference (Sensor/Sight) */
+double x, /* X coord in mm, 0-310.0, accurate to 0.1mm */
+double y /* Y coord in mm, 0-230.0, accurate to 0.1mm */
+);
+
+/* Set digitizing mode. Clears digitizing buffer, */
+/* and puts the device offline. The user can move */
+/* and enter positions. */
+inst_code ss_do_SetDigitizingMode(struct _ss *p);
+
+/* Get last digitized position from memory. */
+inst_code ss_do_OutputDigitizingValues(
+struct _ss *p,
+ss_rt r, /* Reference (Sensor/Sight) */
+ss_rt *rr, /* Return reference (Sensor/Sight) */
+int *nrp,/* Return the number of remaining positions in memory. */
+double *x, /* Return the X coord in mm, 0-310.0, accurate to 0.1mm */
+double *y, /* Return the Y coord in mm, 0-230.0, accurate to 0.1mm */
+ss_zkt *zk /* Return the Z coordinate (Up/Down) */
+);
+
+/* Turn on key aknowledge mode. Causes a KeyAnswer message */
+/* to be generated whenever a key is pressed. */
+/* (KetAnswer isn't well supported here ?) */
+inst_code ss_do_SetKeyAcknowlge(struct _ss *p);
+
+/* Turn off key aknowledge mode. */
+inst_code ss_do_ResetKeyAcknowlge(struct _ss *p);
+
+/* Query the keys that are currently pressed */
+inst_code ss_do_OutputActualKey(
+struct _ss *p,
+ss_sks *sk, /* Return Scan Key Set (Key bitmask) */
+ss_ptt *pt /* Return press time (Short/Long) */
+);
+
+/* Query the keys that were last pressed */
+inst_code ss_do_OutputLastKey(
+struct _ss *p,
+ss_sks *sk, /* Return Scan Key bitmask (Keys) */
+ss_ptt *pt /* Return press time (Short/Long) */
+);
+
+/* Query the status register */
+inst_code ss_do_OutputStatus(
+struct _ss *p,
+ss_sts *st /* Return status bitmask (Enter key/Online/Digitize/KeyAck/Paper) */
+);
+
+/* Clear the status register */
+inst_code ss_do_ClearStatus(
+struct _ss *p,
+ss_sts st /* Status to reset (Enter key/Online/Digitize/KeyAck/Paper) */
+);
+
+/* Set the special status register */
+/* (Set to all 0 on reset) */
+inst_code ss_do_SetSpecialStatus(
+struct _ss *p,
+ss_sss sss /* Status bits to set (HeadDwnOnMv/TableInTransMode/AllLightsOn) */
+);
+
+/* Clear the special status register */
+inst_code ss_do_ClearSpecialStatus(
+struct _ss *p,
+ss_sss sss /* Status bits to clear (HeadDwnOnMv/TableInTransMode/AllLightsOn) */
+);
+
+/* Query the special status register */
+inst_code ss_do_OutputSpecialStatus(
+struct _ss *p,
+ss_sss *sss /* Return Special Status bits */
+);
+
+#define SS_IMP_H
+#endif /* SS_IMP_H */
diff --git a/spectro/strange.cal b/spectro/strange.cal
new file mode 100644
index 0000000..23c1e87
--- /dev/null
+++ b/spectro/strange.cal
@@ -0,0 +1,275 @@
+CAL
+
+DESCRIPTOR "Argyll Device Calibration Curves"
+ORIGINATOR "Argyll synthcal"
+CREATED "Sat Mar 09 18:33:22 2013"
+KEYWORD "DEVICE_CLASS"
+DEVICE_CLASS "DISPLAY"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+
+KEYWORD "RGB_I"
+NUMBER_OF_FIELDS 4
+BEGIN_DATA_FORMAT
+RGB_I RGB_R RGB_G RGB_B
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 256
+BEGIN_DATA
+0.0000 0.0000 0.0000 0.0000
+3.9216e-003 5.6752e-005 0.011879 0.018606
+7.8431e-003 1.8439e-004 0.020682 0.030226
+0.011765 3.6735e-004 0.028607 0.040147
+0.015686 5.9908e-004 0.036009 0.049103
+0.019608 8.7544e-004 0.043047 0.057404
+0.023529 1.1935e-003 0.049807 0.065218
+0.027451 1.5511e-003 0.056344 0.072650
+0.031373 1.9464e-003 0.062696 0.079768
+0.035294 2.3779e-003 0.068891 0.086623
+0.039216 2.8443e-003 0.074949 0.093253
+0.043137 3.3446e-003 0.080888 0.099687
+0.047059 3.8778e-003 0.086719 0.10595
+0.050980 4.4431e-003 0.092453 0.11205
+0.054902 5.0396e-003 0.098100 0.11802
+0.058824 5.6668e-003 0.10367 0.12386
+0.062745 6.3239e-003 0.10916 0.12958
+0.066667 7.0104e-003 0.11458 0.13520
+0.070588 7.7258e-003 0.11995 0.14072
+0.074510 8.4696e-003 0.12525 0.14615
+0.078431 9.2413e-003 0.13049 0.15149
+0.082353 0.010040 0.13569 0.15675
+0.086275 0.010867 0.14083 0.16194
+0.090196 0.011720 0.14593 0.16706
+0.094118 0.012599 0.15099 0.17211
+0.098039 0.013504 0.15600 0.17710
+0.10196 0.014436 0.16097 0.18203
+0.10588 0.015392 0.16590 0.18690
+0.10980 0.016374 0.17080 0.19172
+0.11373 0.017380 0.17567 0.19649
+0.11765 0.018411 0.18049 0.20121
+0.12157 0.019467 0.18529 0.20588
+0.12549 0.020546 0.19006 0.21051
+0.12941 0.021650 0.19480 0.21509
+0.13333 0.022777 0.19950 0.21963
+0.13725 0.023927 0.20418 0.22414
+0.14118 0.025101 0.20884 0.22860
+0.14510 0.026298 0.21347 0.23303
+0.14902 0.027518 0.21807 0.23742
+0.15294 0.028760 0.22265 0.24177
+0.15686 0.030025 0.22720 0.24610
+0.16078 0.031312 0.23174 0.25039
+0.16471 0.032621 0.23625 0.25465
+0.16863 0.033953 0.24074 0.25888
+0.17255 0.035306 0.24521 0.26308
+0.17647 0.036681 0.24965 0.26725
+0.18039 0.038077 0.25408 0.27139
+0.18431 0.039495 0.25849 0.27551
+0.18824 0.040935 0.26288 0.27960
+0.19216 0.042395 0.26725 0.28366
+0.19608 0.043876 0.27161 0.28770
+0.20000 0.045378 0.27595 0.29172
+0.20392 0.046901 0.28027 0.29571
+0.20784 0.048445 0.28457 0.29968
+0.21176 0.050009 0.28886 0.30363
+0.21569 0.051594 0.29313 0.30755
+0.21961 0.053198 0.29738 0.31146
+0.22353 0.054824 0.30163 0.31534
+0.22745 0.056469 0.30585 0.31920
+0.23137 0.058134 0.31006 0.32304
+0.23529 0.059819 0.31426 0.32687
+0.23922 0.061523 0.31844 0.33067
+0.24314 0.063248 0.32261 0.33446
+0.24706 0.064992 0.32677 0.33822
+0.25098 0.066755 0.33091 0.34197
+0.25490 0.068538 0.33504 0.34570
+0.25882 0.070340 0.33916 0.34942
+0.26275 0.072162 0.34326 0.35312
+0.26667 0.074002 0.34736 0.35680
+0.27059 0.075862 0.35144 0.36046
+0.27451 0.077740 0.35551 0.36411
+0.27843 0.079638 0.35956 0.36774
+0.28235 0.081554 0.36361 0.37136
+0.28627 0.083489 0.36764 0.37496
+0.29020 0.085442 0.37167 0.37855
+0.29412 0.087415 0.37568 0.38213
+0.29804 0.089405 0.37968 0.38569
+0.30196 0.091414 0.38367 0.38923
+0.30588 0.093442 0.38765 0.39276
+0.30980 0.095487 0.39162 0.39628
+0.31373 0.097551 0.39559 0.39979
+0.31765 0.099633 0.39954 0.40328
+0.32157 0.10173 0.40348 0.40676
+0.32549 0.10385 0.40741 0.41022
+0.32941 0.10599 0.41133 0.41368
+0.33333 0.10814 0.41524 0.41712
+0.33725 0.11031 0.41915 0.42055
+0.34118 0.11250 0.42304 0.42396
+0.34510 0.11471 0.42693 0.42737
+0.34902 0.11693 0.43080 0.43076
+0.35294 0.11918 0.43467 0.43414
+0.35686 0.12144 0.43853 0.43752
+0.36078 0.12371 0.44238 0.44088
+0.36471 0.12601 0.44623 0.44422
+0.36863 0.12832 0.45006 0.44756
+0.37255 0.13065 0.45389 0.45089
+0.37647 0.13300 0.45770 0.45421
+0.38039 0.13536 0.46151 0.45751
+0.38431 0.13774 0.46532 0.46081
+0.38824 0.14014 0.46911 0.46410
+0.39216 0.14255 0.47290 0.46737
+0.39608 0.14499 0.47668 0.47064
+0.40000 0.14743 0.48045 0.47390
+0.40392 0.14990 0.48421 0.47715
+0.40784 0.15238 0.48797 0.48038
+0.41176 0.15488 0.49172 0.48361
+0.41569 0.15740 0.49546 0.48683
+0.41961 0.15993 0.49920 0.49004
+0.42353 0.16248 0.50293 0.49324
+0.42745 0.16505 0.50665 0.49644
+0.43137 0.16763 0.51037 0.49962
+0.43529 0.17023 0.51407 0.50279
+0.43922 0.17284 0.51778 0.50596
+0.44314 0.17547 0.52147 0.50912
+0.44706 0.17812 0.52516 0.51227
+0.45098 0.18079 0.52884 0.51541
+0.45490 0.18347 0.53252 0.51854
+0.45882 0.18616 0.53619 0.52167
+0.46275 0.18888 0.53985 0.52479
+0.46667 0.19161 0.54351 0.52789
+0.47059 0.19435 0.54716 0.53100
+0.47451 0.19711 0.55080 0.53409
+0.47843 0.19989 0.55444 0.53718
+0.48235 0.20268 0.55807 0.54025
+0.48627 0.20549 0.56170 0.54332
+0.49020 0.20832 0.56532 0.54639
+0.49412 0.21116 0.56894 0.54944
+0.49804 0.21402 0.57255 0.55249
+0.50196 0.21689 0.57615 0.55553
+0.50588 0.21978 0.57975 0.55857
+0.50980 0.22268 0.58334 0.56160
+0.51373 0.22560 0.58693 0.56462
+0.51765 0.22854 0.59051 0.56763
+0.52157 0.23149 0.59409 0.57064
+0.52549 0.23445 0.59766 0.57364
+0.52941 0.23744 0.60122 0.57663
+0.53333 0.24043 0.60478 0.57962
+0.53725 0.24345 0.60834 0.58260
+0.54118 0.24648 0.61189 0.58557
+0.54510 0.24952 0.61543 0.58854
+0.54902 0.25258 0.61897 0.59150
+0.55294 0.25565 0.62251 0.59445
+0.55686 0.25874 0.62603 0.59740
+0.56078 0.26185 0.62956 0.60034
+0.56471 0.26497 0.63308 0.60328
+0.56863 0.26811 0.63659 0.60621
+0.57255 0.27126 0.64010 0.60913
+0.57647 0.27442 0.64361 0.61205
+0.58039 0.27760 0.64711 0.61496
+0.58431 0.28080 0.65060 0.61787
+0.58824 0.28401 0.65410 0.62077
+0.59216 0.28724 0.65758 0.62366
+0.59608 0.29048 0.66106 0.62655
+0.60000 0.29373 0.66454 0.62943
+0.60392 0.29701 0.66801 0.63231
+0.60784 0.30029 0.67148 0.63518
+0.61176 0.30359 0.67494 0.63805
+0.61569 0.30691 0.67840 0.64091
+0.61961 0.31024 0.68186 0.64376
+0.62353 0.31358 0.68531 0.64661
+0.62745 0.31694 0.68875 0.64945
+0.63137 0.32032 0.69220 0.65229
+0.63529 0.32371 0.69563 0.65513
+0.63922 0.32711 0.69907 0.65795
+0.64314 0.33053 0.70249 0.66078
+0.64706 0.33397 0.70592 0.66360
+0.65098 0.33741 0.70934 0.66641
+0.65490 0.34088 0.71276 0.66922
+0.65882 0.34435 0.71617 0.67202
+0.66275 0.34785 0.71958 0.67482
+0.66667 0.35135 0.72298 0.67761
+0.67059 0.35487 0.72638 0.68040
+0.67451 0.35841 0.72978 0.68318
+0.67843 0.36196 0.73317 0.68596
+0.68235 0.36552 0.73656 0.68873
+0.68627 0.36910 0.73994 0.69150
+0.69020 0.37269 0.74332 0.69426
+0.69412 0.37630 0.74670 0.69702
+0.69804 0.37992 0.75007 0.69977
+0.70196 0.38356 0.75344 0.70252
+0.70588 0.38721 0.75681 0.70527
+0.70980 0.39087 0.76017 0.70801
+0.71373 0.39455 0.76353 0.71075
+0.71765 0.39824 0.76688 0.71348
+0.72157 0.40195 0.77023 0.71620
+0.72549 0.40567 0.77358 0.71893
+0.72941 0.40940 0.77692 0.72164
+0.73333 0.41315 0.78026 0.72436
+0.73725 0.41692 0.78360 0.72707
+0.74118 0.42069 0.78693 0.72977
+0.74510 0.42448 0.79026 0.73247
+0.74902 0.42829 0.79359 0.73517
+0.75294 0.43211 0.79691 0.73786
+0.75686 0.43594 0.80023 0.74055
+0.76078 0.43979 0.80354 0.74323
+0.76471 0.44365 0.80686 0.74591
+0.76863 0.44752 0.81016 0.74859
+0.77255 0.45141 0.81347 0.75126
+0.77647 0.45531 0.81677 0.75393
+0.78039 0.45923 0.82007 0.75659
+0.78431 0.46316 0.82336 0.75925
+0.78824 0.46710 0.82666 0.76191
+0.79216 0.47106 0.82994 0.76456
+0.79608 0.47503 0.83323 0.76721
+0.80000 0.47902 0.83651 0.76985
+0.80392 0.48302 0.83979 0.77249
+0.80784 0.48703 0.84307 0.77512
+0.81176 0.49105 0.84634 0.77776
+0.81569 0.49509 0.84961 0.78038
+0.81961 0.49915 0.85287 0.78301
+0.82353 0.50321 0.85614 0.78563
+0.82745 0.50729 0.85940 0.78825
+0.83137 0.51139 0.86265 0.79086
+0.83529 0.51550 0.86591 0.79347
+0.83922 0.51962 0.86916 0.79608
+0.84314 0.52375 0.87241 0.79868
+0.84706 0.52790 0.87565 0.80128
+0.85098 0.53206 0.87889 0.80387
+0.85490 0.53624 0.88213 0.80646
+0.85882 0.54042 0.88537 0.80905
+0.86275 0.54463 0.88860 0.81163
+0.86667 0.54884 0.89183 0.81421
+0.87059 0.55307 0.89506 0.81679
+0.87451 0.55731 0.89828 0.81937
+0.87843 0.56157 0.90150 0.82194
+0.88235 0.56584 0.90472 0.82450
+0.88627 0.57012 0.90793 0.82707
+0.89020 0.57441 0.91115 0.82963
+0.89412 0.57872 0.91436 0.83218
+0.89804 0.58304 0.91756 0.83474
+0.90196 0.58738 0.92077 0.83729
+0.90588 0.59173 0.92397 0.83983
+0.90980 0.59609 0.92717 0.84238
+0.91373 0.60046 0.93036 0.84492
+0.91765 0.60485 0.93356 0.84745
+0.92157 0.60925 0.93675 0.84999
+0.92549 0.61366 0.93993 0.85252
+0.92941 0.61809 0.94312 0.85504
+0.93333 0.62253 0.94630 0.85757
+0.93725 0.62698 0.94948 0.86009
+0.94118 0.63145 0.95266 0.86261
+0.94510 0.63593 0.95583 0.86512
+0.94902 0.64042 0.95900 0.86763
+0.95294 0.64493 0.96217 0.87014
+0.95686 0.64945 0.96534 0.87264
+0.96078 0.65398 0.96850 0.87515
+0.96471 0.65852 0.97166 0.87765
+0.96863 0.66308 0.97482 0.88014
+0.97255 0.66765 0.97798 0.88263
+0.97647 0.67223 0.98113 0.88512
+0.98039 0.67683 0.98428 0.88761
+0.98431 0.68144 0.98743 0.89009
+0.98824 0.68606 0.99058 0.89258
+0.99216 0.69069 0.99372 0.89505
+0.99608 0.69534 0.99686 0.89753
+1.0000 0.70000 1.0000 0.90000
+END_DATA
diff --git a/spectro/synthcal.c b/spectro/synthcal.c
new file mode 100644
index 0000000..75d18be
--- /dev/null
+++ b/spectro/synthcal.c
@@ -0,0 +1,350 @@
+
+/*
+ * Argyll Color Correction System
+ * Create a linear display calibration file.
+ *
+ * Author: Graeme W. Gill
+ * Date: 15/11/2005
+ *
+ * Copyright 1996 - 2007 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.
+ */
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+
+#include "sort.h"
+
+#include <stdarg.h>
+
+#if defined (NT)
+#include <conio.h>
+#endif
+
+void
+usage(int level) {
+ int i;
+ fprintf(stderr,"Create a synthetic calibration file, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: synthcal [-options] outfile\n");
+ fprintf(stderr," -t N i = input, o = output, d = display (default)\n");
+ fprintf(stderr," -d col_comb choose colorant combination from the following (default 3):\n");
+ for (i = 0; ; i++) {
+ char *desc;
+ if (icx_enum_colorant_comb(i, &desc) == 0)
+ break;
+ fprintf(stderr," %d: %s\n",i,desc);
+ }
+ fprintf(stderr," -D colorant Add or delete colorant from combination:\n");
+ if (level == 0)
+ fprintf(stderr," (Use -?? to list known colorants)\n");
+ else {
+ fprintf(stderr," %d: %s\n",0,"Additive");
+ for (i = 0; ; i++) {
+ char *desc;
+ if (icx_enum_colorant(i, &desc) == 0)
+ break;
+ fprintf(stderr," %d: %s\n",i+1,desc);
+ }
+ }
+ fprintf(stderr," -o o1,o2,o3, Set non-linear curve offset (default 0.0)\n");
+ fprintf(stderr," -s s1,s2,s3, Set non-linear curve scale (default 1.0)\n");
+ fprintf(stderr," -p p1,p2,p3, Set non-linear curve powers (default 1.0)\n");
+ fprintf(stderr," -E description Set the profile dEscription string\n");
+ fprintf(stderr," outfile Base name for output .cal file\n");
+ exit(1);
+ }
+
+int main(int argc, char *argv[])
+{
+ int fa,nfa; /* current argument we're looking at */
+ int j;
+ int verb = 0;
+ char outname[MAXNAMEL+1] = { 0 }; /* Output cgats file base name */
+ char *profDesc = NULL; /* Description */
+ int devtype = 2; /* debice type, 0 = in, 1 = out, 2 = display */
+ inkmask devmask = 0; /* ICX ink mask of device space */
+ int devchan; /* Number of chanels in device space */
+ char *ident; /* Ink combination identifier (includes possible leading 'i') */
+ char *bident; /* Base ink combination identifier */
+ double off[MAX_CHAN]; /* Output offset */
+ double sca[MAX_CHAN]; /* Output scale */
+ double gam[MAX_CHAN]; /* Gamma applied */
+
+ for (j = 0; j < MAX_CHAN; j++)
+ off[j] = 0.0, sca[j] = gam[j] = 1.0;
+
+ error_program = "synthcal";
+ if (argc <= 1)
+ usage(0);
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') /* Look for any flags */
+ {
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?' || argv[fa][1] == '-') {
+ if (argv[fa][2] == '?' || argv[fa][2] == '-')
+ usage(1);
+ usage(0);
+ }
+
+ else if (argv[fa][1] == 'v')
+ verb = 1;
+
+ /* Select the device type */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage(0);
+ if (na[0] == 'i' || na[0] == 'I')
+ devtype = 0;
+ else if (na[0] == 'o' || na[0] == 'O')
+ devtype = 1;
+ else if (na[0] == 'd' || na[0] == 'D')
+ devtype = 2;
+ else
+ usage(0);
+ }
+
+ /* Select the ink enumeration */
+ else if (argv[fa][1] == 'd') {
+ int ix;
+ fa = nfa;
+ if (na == NULL) usage(0);
+ ix = atoi(na);
+ if (ix == 0 && na[0] != '0')
+ usage(0);
+ if ((devmask = icx_enum_colorant_comb(ix, NULL)) == 0)
+ usage(0);
+ }
+
+ /* Toggle the colorant in ink combination */
+ else if (argv[fa][1] == 'D') {
+ int ix, tmask;
+ fa = nfa;
+ if (na == NULL) usage(0);
+ ix = atoi(na);
+ if (ix == 0 && na[0] != '0')
+ usage(0);
+ if (ix == 0)
+ tmask = ICX_ADDITIVE;
+ else
+ if ((tmask = icx_enum_colorant(ix-1, NULL)) == 0)
+ usage(0);
+ devmask ^= tmask;
+ }
+
+ /* curve offset */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage(0);
+ for (j = 0; j < MAX_CHAN; j++) {
+ int i;
+ for (i = 0; ; i++) {
+ if (na[i] == ','){
+ na[i] = '\000';
+ break;
+ }
+ if (na[i] == '\000') {
+ i = 0;
+ break;
+ }
+ }
+ off[j] = atof(na);
+ if (i == 0)
+ break;
+ na += i+1;
+ }
+ }
+
+ /* curve scale */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ fa = nfa;
+ if (na == NULL) usage(0);
+ for (j = 0; j < MAX_CHAN; j++) {
+ int i;
+ for (i = 0; ; i++) {
+ if (na[i] == ','){
+ na[i] = '\000';
+ break;
+ }
+ if (na[i] == '\000') {
+ i = 0;
+ break;
+ }
+ }
+ sca[j] = atof(na);
+ if (i == 0)
+ break;
+ na += i+1;
+ }
+ }
+
+ /* curve power */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage(0);
+ for (j = 0; j < MAX_CHAN; j++) {
+ int i;
+ for (i = 0; ; i++) {
+ if (na[i] == ','){
+ na[i] = '\000';
+ break;
+ }
+ if (na[i] == '\000') {
+ i = 0;
+ break;
+ }
+ }
+ gam[j] = atof(na);
+ if (i == 0)
+ break;
+ na += i+1;
+ }
+ }
+
+ /* Profile Description */
+ else if (argv[fa][1] == 'E') {
+ fa = nfa;
+ if (na == NULL) usage(0);
+ profDesc = na;
+ }
+
+
+ else
+ usage(0);
+ } else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage(0);
+ strcpy(outname,argv[fa]);
+ if (strlen(outname) < 4 || strcmp(".cal",outname + strlen(outname)-4) != 0)
+ strcat(outname,".cal");
+
+ /* Implement defaults */
+ if (devmask == 0) {
+ if (devtype == 0 || devtype == 2)
+ devmask = ICX_RGB;
+ else
+ devmask = ICX_CMYK;
+ }
+
+ ident = icx_inkmask2char(devmask, 1);
+ bident = icx_inkmask2char(devmask, 0);
+ devchan = icx_noofinks(devmask);
+
+ if (verb) {
+ if (devtype == 0)
+ printf("Device type: input\n");
+ else if (devtype == 1)
+ printf("Device type: output\n");
+ else
+ printf("Device type: display\n");
+
+ printf("Colorspace: %s\n", ident);
+
+ printf("Curve parameters:\n");
+ for (j = 0; j < devchan; j++)
+ printf("off[%d] = %f, sca[%d] = %f, gam[%d] = %f\n",j,off[j],j,sca[j],j, gam[j]);
+ }
+
+ /* Write out the resulting calibration file */
+ {
+ int i, j, calres = 256; /* 256 steps in calibration */
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats_set_elem *setel; /* Array of set value elements */
+ int nsetel = 0;
+ char buf[200];
+
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CAL"); /* our special type is Calibration file */
+
+ ocg->add_table(ocg, tt_other, 0); /* Add a table for RAMDAC values */
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Device Calibration Curves",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll synthcal", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ if (devtype == 0)
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","INPUT", NULL);
+ else if (devtype == 1)
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);
+ else
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL);
+
+ ocg->add_kword(ocg, 0, "COLOR_REP", ident, NULL);
+
+ if (profDesc != NULL)
+ ocg->add_kword(ocg, 0, "DESCRIPTION", profDesc, NULL);
+
+ sprintf(buf, "%s_I",bident);
+ ocg->add_field(ocg, 0, buf, r_t);
+ nsetel++;
+ for (j = 0; j < devchan; j++) {
+ inkmask imask = icx_index2ink(devmask, j);
+ sprintf(buf, "%s_%s",bident,icx_ink2char(imask));
+ ocg->add_field(ocg, 0, buf, r_t);
+ nsetel++;
+ }
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL)
+ error("Malloc failed!");
+
+ for (i = 0; i < calres; i++) {
+ double vv = i/(calres-1.0);
+
+ setel[0].d = vv;
+ for (j = 0; j < devchan; j++) {
+ setel[j+1].d = off[j] + sca[j] * pow(vv, gam[j]);
+ if (setel[j+1].d < 0.0)
+ setel[j+1].d = 0.0;
+ else if (setel[j+1].d > 1.0)
+ setel[j+1].d = 1.0;
+ }
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ ocg->del(ocg); /* Clean up */
+ }
+ return 0;
+}
+
+
diff --git a/spectro/synthread.c b/spectro/synthread.c
new file mode 100644
index 0000000..c4312f1
--- /dev/null
+++ b/spectro/synthread.c
@@ -0,0 +1,691 @@
+
+/*
+ * Argyll Color Correction System
+ * Synthetic device target chart reader
+ *
+ * Author: Graeme W. Gill
+ * Date: 10/7/2007
+ *
+ * Copyright 2002 - 2007 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.
+ *
+ * Based on fakeread.c
+ */
+
+/*
+ Implements a synthetic RGB device response based on sRGB like
+ primaries.
+
+ */
+
+/*
+ * TTBD:
+ *
+ * Add non-linear mixing model
+ *
+ */
+
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "xicc.h"
+#include "icc.h"
+
+void
+usage(char *mes) {
+ fprintf(stderr,"Synthetic device model test chart reader - Version %s\n",
+ ARGYLL_VERSION_STR);
+ 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: synthread [-v] [-s] [separation.icm] profile.[icc|mpp|ti3] outfile\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -p Use separation profile\n");
+ fprintf(stderr," -l Construct and output in Lab rather than XYZ\n");
+ fprintf(stderr," -i p1,p2,p3, Set input channel curve powers (default 1.0)\n");
+ fprintf(stderr," -k x1:y1,x2:y2,x3:y2 Set input channel inflection points (default 0.5,0.5)\n");
+ fprintf(stderr," -o p1,p2,p3, Set output channel curve powers (default 1.0)\n");
+ fprintf(stderr," -r level Add average random deviation of <level>%% to input device values (after sep.)\n");
+ fprintf(stderr," -R level Add average random deviation of <level>%% to output PCS values\n");
+ fprintf(stderr," -u Make random deviations have uniform distributions rather than normal\n");
+ fprintf(stderr," -b L,a,b Scale black point to target Lab value\n");
+ fprintf(stderr," [separation.icm] Device link separation profile\n");
+ fprintf(stderr," profile.[icc|mpp|ti3] ICC, MPP profile or TI3 to use\n");
+ fprintf(stderr," outfile Base name for input[ti1]/output[ti3] file\n");
+ exit(1);
+ }
+
+
+typedef struct {
+ int dolab; /* Combine and output in Lab space */
+ double ipow[3]; /* Input power applied */
+ double ibpp[3]; /* Input breakpoint location, -ve if none */
+ double ibpv[3]; /* Input breakpoint value, -ve if none */
+ double col[3][3]; /* sRGB additive colorant values in XYZ :- [out][in] */
+ double wnf[3]; /* White normalization factor */
+ double opow[3]; /* Output power */
+ double omax[3]; /* Output maximum that power operates into */
+} synthmodel;
+
+/* Symetrical power function */
+double spow(double val, double pp) {
+ if (val < 0.0)
+ return -pow(-val, pp);
+ else
+ return pow(val, pp);
+}
+
+/* Execute the device model */
+static void domodel(synthmodel *p, double *out, double *in) {
+ double tmp[3];
+ int i, j;
+
+ /* Input power */
+ for (j = 0; j < 3; j++)
+ tmp[j] = pow(in[j], p->ipow[j]);
+
+ /* Input breakpoint */
+ for (j = 0; j < 3; j++) {
+ if (p->ibpp[j] >= 0.0 && p->ibpv[j] >= 0.0) {
+ double b;
+ if (tmp[j] <= p->ibpp[j]) {
+ b = (tmp[j] - 0.0)/(p->ibpp[j] - 0.0);
+ tmp[j] = b * p->ibpv[j] + (1.0 - b) * 0.0;
+ } else {
+ b = (tmp[j] - p->ibpp[j])/(1.0 - p->ibpp[j]);
+ tmp[j] = b * 1.0 + (1.0 - b) * p->ibpv[j];
+ }
+ }
+ }
+
+ /* Lookup primary values, sum them, and then */
+ /* apply output power */
+ /* (We're not allowing for non-linear mixing yet) */
+ for (j = 0; j < 3; j++) {
+ out[j] = 0.0;
+ for (i = 0; i < 3; i++)
+ out[j] += p->col[j][i] * tmp[i];
+ out[j] = spow(out[j]/p->omax[j], p->opow[j]) * p->omax[j];
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i, j, rv = 0;
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0; /* Verbose flag */
+ int dosep = 0; /* Use separation before profile */
+ int gfudge = 0; /* Do grey fudge, 1 = W->RGB, 2 = K->xxxK */
+ double rdlevel = 0.0; /* Random device average deviation level (0.0 - 1.0) */
+ double rplevel = 0.0; /* Random PCS average deviatio level (0.0 - 1.0) */
+ int unidist = 0; /* Use uniform distribution of errors */
+ double tbp[3] = { -1.0, 0.0, 0.0 }; /* Target black point */
+ static char sepname[500] = { 0 }; /* ICC separation profile */
+ static char inname[500] = { 0 }; /* Input cgats file base name */
+ static char outname[500] = { 0 }; /* Output cgats file base name */
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ int nmask = 0; /* Test chart device colorant mask */
+ int nchan = 0; /* Test chart number of device chanels */
+ int npat; /* Number of patches */
+ int si; /* Sample id index */
+ int ti; /* Temp index */
+ int fi; /* Colorspace index */
+
+ synthmodel md; /* Synthetic model */
+
+ /* ICC separation device link profile */
+ icmFile *sep_fp = NULL; /* Color profile file */
+ icc *sep_icco = NULL; /* Profile object */
+ icmLuBase *sep_luo = NULL; /* Conversion object */
+ icColorSpaceSignature sep_ins, sep_outs; /* Type of input and output spaces */
+ int sep_inn; /* Number of input channels to separation */
+ inkmask sep_nmask = 0; /* Colorant mask for separation input */
+ double wp[3], bp[3]; /* ICC profile Lab white and black points */
+ double bpt[3][3]; /* Black point transform matrix (Lab->Lab) */
+
+
+ int inn, outn; /* Number of channels for conversion input, output */
+ icColorSpaceSignature ins, outs; /* Type of conversion input and output spaces */
+ int cnv_nmask = 0; /* Conversion input nmask */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+ char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
+
+ error_program = "Synthread";
+ if (argc < 1)
+ usage("Too few arguments");
+
+ /* Initialise the default model */
+ inn = 3;
+ ins = icSigRgbData;
+ outn = 3;
+ outs = icSigXYZData;
+
+ md.dolab = 0;
+
+ md.ipow[0] = 1.0;
+ md.ipow[1] = 1.0;
+ md.ipow[2] = 1.0;
+
+ md.ibpp[0] = -1.0;
+ md.ibpv[0] = -1.0;
+ md.ibpp[1] = -1.0;
+ md.ibpv[1] = -1.0;
+ md.ibpp[2] = -1.0;
+ md.ibpv[2] = -1.0;
+
+ md.col[0][0] = 0.412424; /* X from R */
+ md.col[0][1] = 0.357579; /* X from G */
+ md.col[0][2] = 0.180464; /* X from B */
+ md.col[1][0] = 0.212656; /* Y from R */
+ md.col[1][1] = 0.715158; /* Y from G */
+ md.col[1][2] = 0.0721856; /* Y from B */
+ md.col[2][0] = 0.0193324; /* Z from R */
+ md.col[2][1] = 0.119193; /* Z from G */
+ md.col[2][2] = 0.950444; /* Z from B */
+
+ md.opow[0] = 1.0;
+ md.opow[1] = 1.0;
+ md.opow[2] = 1.0;
+
+ md.omax[0] = 1.0;
+ md.omax[1] = 1.0;
+ md.omax[2] = 1.0;
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else
+ {
+ if ((fa+1) < argc)
+ {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ /* Verbose */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ /* Separation */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P')
+ dosep = 1;
+
+ /* Lab */
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L')
+ md.dolab = 1;
+
+ /* Input curve power */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -i");
+ if (sscanf(na, " %lf,%lf,%lf ", &md.ipow[0], &md.ipow[1], &md.ipow[2]) != 3)
+ usage("Argument to -i does not parse");
+ }
+
+ /* Input curve inflexction point */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -k");
+ if (sscanf(na, " %lf:%lf,%lf:%lf,%lf:%lf ",
+ &md.ibpp[0], &md.ibpv[0], &md.ibpp[1],
+ &md.ibpv[1], &md.ibpp[2], &md.ibpv[2]) != 6)
+ usage("Argument to -k does not parse");
+ }
+
+ /* Output curve power */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -o");
+ if (sscanf(na, " %lf,%lf,%lf ", &md.opow[0], &md.opow[1], &md.opow[2]) != 3)
+ usage("Argument to -o does not parse");
+ }
+
+ /* Uniform distrivuted errors */
+ else if (argv[fa][1] == 'u' || argv[fa][1] == 'U')
+ unidist = 1;
+
+ /* Random addition to device levels */
+ else if (argv[fa][1] == 'r') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -r");
+ rdlevel = 0.01 * atof(na);
+ rand32(time(NULL)); /* Init seed randomly */
+ }
+
+ /* Random addition to PCS levels */
+ else if (argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -R");
+ rplevel = 0.01 * atof(na);
+ rand32(time(NULL)); /* Init seed randomly */
+ }
+
+ /* Black point scale */
+ else if (argv[fa][1] == 'b' || argv[fa][1] == 'B') {
+ if (na == NULL) usage("Expect argument to -b");
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf ",&tbp[0], &tbp[1], &tbp[2]) != 3)
+ usage("Couldn't parse argument to -b");
+ if (tbp[0] < 0.0 || tbp[0] > 100.0) usage("-b L* value out of range");
+ if (tbp[1] < -128.0 || tbp[1] > 128.0) usage("-b a* value out of range");
+ if (tbp[2] < -128.0 || tbp[2] > 128.0) usage("-b b* value out of range");
+ }
+
+ else
+ usage("Unrecognised flag");
+ }
+ else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (dosep) {
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing separation profile filename argument");
+ strcpy(sepname,argv[fa++]);
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing basename argument");
+ strcpy(inname,argv[fa]);
+ strcat(inname,".ti1");
+ strcpy(outname,argv[fa]);
+ strcat(outname,".ti3");
+
+ /* Convert colorants to Lab, and scale white point */
+ if (md.dolab) {
+ double white[3] = { 100.0, 0, 0 };
+ double rot[3][3];
+
+printf("~1 switching to Lab\n");
+
+ for (i = 0; i < 3; i++) {
+ double val[3];
+
+ val[0] = md.col[0][i];
+ val[1] = md.col[1][i];
+ val[2] = md.col[2][i];
+printf("~1 prim XYZ %f %f %f -> ", val[0], val[1], val[2]);
+ icmXYZ2Lab(&icmD50, val, val);
+printf("Lab %f %f %f\n", val[0], val[1], val[2]);
+ md.col[0][i] = val[0];
+ md.col[1][i] = val[1];
+ md.col[2][i] = val[2];
+ }
+
+ /* Compute white sum */
+ for (i = 0; i < 3; i++) {
+ md.omax[i] = 0.0;
+ for (j = 0; j < 3; j++)
+ md.omax[i] += md.col[i][j];
+ }
+printf("~1 sum = %f %f %f\n", md.omax[0], md.omax[1], md.omax[2]);
+
+ /* Compute rotate and scale to map to white target */
+ icmRotMat(rot, md.omax, white);
+
+ /* Rotate and primaries to sum to white */
+ for (i = 0; i < 3; i++) {
+ double val[3];
+
+ val[0] = md.col[0][i];
+ val[1] = md.col[1][i];
+ val[2] = md.col[2][i];
+ icmMulBy3x3(val, rot, val);
+printf("~1 Scaled primary %f %f %f\n", val[0], val[1], val[2]);
+ md.col[0][i] = val[0];
+ md.col[1][i] = val[1];
+ md.col[2][i] = val[2];
+ }
+
+ /* Compute output maximum factors to set out power range */
+ for (i = 0; i < 3; i++) {
+ md.omax[i] = 0.0;
+ for (j = 0; j < 3; j++) {
+ if (i == 0)
+ md.omax[i] += md.col[i][j];
+ else {
+ if (fabs(md.col[i][j]) > md.omax[i])
+ md.omax[i] = fabs(md.col[i][j]);
+
+ }
+ }
+ }
+ } else {
+
+ /* Compute output maximum factors to set out power range */
+ for (i = 0; i < 3; i++) {
+ md.omax[i] = 0.0;
+ for (j = 0; j < 3; j++)
+ md.omax[i] += md.col[i][j];
+ }
+ }
+printf("~1 omax = %f %f %f\n", md.omax[0], md.omax[1], md.omax[2]);
+
+ /* Deal with separation */
+ if (dosep) {
+ if ((sep_fp = new_icmFileStd_name(sepname,"r")) == NULL)
+ error ("Can't open file '%s'",sepname);
+
+ if ((sep_icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* Deal with ICC separation */
+ if ((rv = sep_icco->read(sep_icco,sep_fp,0)) == 0) {
+
+ /* Get a conversion object */
+ if ((sep_luo = sep_icco->get_luobj(sep_icco, icmFwd, icmDefaultIntent, icmSigDefaultData, icmLuOrdNorm)) == NULL) {
+ error ("%d, %s",sep_icco->errc, sep_icco->err);
+ }
+
+ /* Get details of conversion */
+ sep_luo->spaces(sep_luo, &sep_ins, &sep_inn, &sep_outs, NULL, NULL, NULL, NULL, NULL, NULL);
+ sep_nmask = icx_icc_to_colorant_comb(sep_ins, sep_icco->header->deviceClass);
+ }
+ }
+
+ /* Deal with input CGATS files */
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI1"); /* our special input type is Calibration Target Information 1 */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI1 format file");
+ if (icg->ntables != 1 && icg->ntables != 2 && icg->ntables != 3)
+ error ("Input file doesn't contain one, two or three tables");
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll synthread", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ /* Assume a general output type device */
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "SINGLE_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "SINGLE_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "COMP_GREY_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "COMP_GREY_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "MULTI_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "MULTI_DIM_STEPS",icg->t[0].kdata[ti], NULL);
+
+ if ((ti = icg->find_kword(icg, 0, "FULL_SPREAD_PATCHES")) >= 0)
+ ocg->add_kword(ocg, 0, "FULL_SPREAD_PATCHES",icg->t[0].kdata[ti], NULL);
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+
+ if ((si = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error ("Input file doesn't contain field SAMPLE_ID");
+
+ /* Figure out the color space */
+ if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error ("Input file doesn't contain keyword COLOR_REP");
+
+ if ((nmask = icx_char2inkmask(icg->t[0].kdata[fi])) == 0)
+ error ("Input file keyword COLOR_REP has unknown value");
+
+ {
+ int i, j, ii;
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ char *ident, *bident;
+ int nsetel = 0;
+ cgats_set_elem *setel; /* Array of set value elements */
+
+ nchan = icx_noofinks(nmask);
+ ident = icx_inkmask2char(nmask, 1);
+ bident = icx_inkmask2char(nmask, 0);
+
+ /* Sanity check what we're going to do */
+ if (dosep) {
+
+ /* Check if sep ICC input is compatible with .ti1 */
+ if (nmask == ICX_W && sep_ins == icSigRgbData)
+ gfudge = 1;
+ else if (nmask == ICX_K && sep_ins == icSigCmykData)
+ gfudge = 2;
+ else if (icx_colorant_comb_match_icc(nmask, sep_ins) == 0) {
+ error("Separation ICC device space '%s' dosen't match TI1 '%s'",
+ icm2str(icmColorSpaceSignature, sep_ins),
+ ident); /* Should free(). */
+ }
+
+ /* Check if separation ICC output is compatible with ICC/MPP/TI3 conversion */
+ if (sep_outs != ins)
+ error("Synthetic device space '%s' dosen't match Separation ICC '%s'",
+ icm2str(icmColorSpaceSignature, ins),
+ icm2str(icmColorSpaceSignature, sep_outs));
+ } else {
+ /* Check if synthetic device is compatible with .ti1 */
+ if (nmask == ICX_W && ins == icSigRgbData)
+ gfudge = 1;
+ else if (nmask == ICX_K && ins == icSigCmykData)
+ gfudge = 2; /* Should allow for other colorant combo's that include black */
+ else if (icx_colorant_comb_match_icc(nmask, ins) == 0) {
+ error("Synthetic device space '%s' dosen't match TI1 '%s'",
+ icm2str(icmColorSpaceSignature, ins),
+ ident); // Should free().
+ }
+ }
+
+ if ((ii = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0)
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT",icg->t[0].kdata[ii], NULL);
+
+ nsetel += 1; /* For id */
+ nsetel += nchan; /* For device values */
+ nsetel += 3; /* For XYZ/Lab */
+
+ for (j = 0; j < nchan; j++) {
+ int imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (icg->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+
+ ocg->add_field(ocg, 0, fname, r_t);
+ chix[j] = ii;
+ }
+
+ /* Add PCS fields */
+ for (j = 0; j < 3; j++) {
+ ocg->add_field(ocg, 0, md.dolab ? labfname[j] : xyzfname[j], r_t);
+ }
+
+ {
+ char fname[100];
+ sprintf(fname, md.dolab ? "%s_LAB" : "%s_XYZ", ident);
+ ocg->add_kword(ocg, 0, "COLOR_REP", fname, NULL);
+ }
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL)
+ error("Malloc failed!");
+
+ /* Read all the test patches in, convert them, */
+ /* and write them out. */
+ for (i = 0; i < npat; i++) {
+ int k = 0;
+ char *id;
+ double odev[ICX_MXINKS], dev[ICX_MXINKS], sep[ICX_MXINKS], PCS[3];
+ xspect out;
+
+ id = ((char *)icg->t[0].fdata[i][si]);
+ for (j = 0; j < nchan; j++) {
+ double dv = *((double *)icg->t[0].fdata[i][chix[j]]) / 100.0;
+ odev[j] = dev[j] = sep[j] = dv;
+ }
+
+ if (gfudge) {
+ int nch;
+
+ if (dosep) /* Figure number of channels into conversion */
+ nch = sep_inn;
+ else
+ nch = inn;
+
+ if (gfudge == 1) { /* Convert W -> RGB */
+ double wval = dev[0];
+ for (j = 0; j < nch; j++)
+ dev[j] = sep[j] = wval;
+
+ } else { /* Convert K->xxxK */
+ int kch;
+ int inmask;
+ double kval = dev[0];
+
+ if (dosep) /* Figure number of channels into conversion */
+ inmask = sep_nmask;
+ else
+ inmask = cnv_nmask;
+
+ if (inmask == 0)
+ error("Input colorspace ambiguous - can't determine if it has black");
+
+ if ((kch = icx_ink2index(inmask, ICX_BLACK)) == -1)
+ error("Can't find black colorant for K fudge");
+ for (j = 0; j < nch; j++) {
+ if (j == kch)
+ dev[j] = sep[j] = kval;
+ else
+ dev[j] = sep[j] = 0.0;
+ }
+ }
+ }
+
+ if (dosep)
+ if (sep_luo->lookup(sep_luo, sep, dev) > 1)
+ error ("%d, %s",sep_icco->errc,sep_icco->err);
+
+ /* Add randomness and non-linearity (rdlevel is avg. dev.) */
+ /* Note dev/sep is 0-1.0 at this stage */
+ for (j = 0; j < inn; j++) {
+ double dv = sep[j];
+ if (rdlevel > 0.0) {
+ double rr;
+ if (unidist)
+ rr = d_rand(-2.0 * rdlevel, 2.0 * rdlevel);
+ else
+ rr = 1.2533 * rdlevel * norm_rand();
+ dv += rr;
+ if (dv < 0.0)
+ dv = 0.0;
+ else if (dv > 1.0)
+ dv = 1.0;
+ }
+ sep[j] = dv;
+ }
+
+ /* Do color conversion */
+ domodel(&md, PCS, sep);
+
+ if (tbp[0] >= 0) { /* Doing black point scaling */
+
+ for (j = 0; j < 3; j++)
+ PCS[j] -= wp[j];
+ icmMulBy3x3(PCS, bpt, PCS);
+ for (j = 0; j < 3; j++)
+ PCS[j] += wp[j];
+ }
+
+ setel[k++].c = id;
+
+ for (j = 0; j < nchan; j++)
+ setel[k++].d = 100.0 * odev[j];
+
+ if (md.dolab == 0) {
+ PCS[0] *= 100.0;
+ PCS[1] *= 100.0;
+ PCS[2] *= 100.0;
+ }
+
+ /* Add randomness (rplevel is avg. dev.) */
+ /* Note PCS is 0..100 XYZ or Lab at this point */
+ if (rplevel > 0.0) {
+ for (j = 0; j < 3; j++) {
+ double dv = PCS[j];
+ double rr;
+ if (unidist)
+ rr = 100.0 * d_rand(-2.0 * rplevel, 2.0 * rplevel);
+ else
+ rr = 100.0 * 1.2533 * rplevel * norm_rand();
+ dv += rr;
+
+ /* Don't let L*, X, Y or Z go negative */
+ if ((!md.dolab || j == 0) && dv < 0.0)
+ dv = 0.0;
+ PCS[j] = dv;
+ }
+ }
+
+ setel[k++].d = PCS[0];
+ setel[k++].d = PCS[1];
+ setel[k++].d = PCS[2];
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+ free(ident);
+ free(bident);
+ }
+
+ if (sep_luo != NULL) {
+ sep_luo->del(sep_luo);
+ sep_icco->del(sep_icco);
+ sep_fp->del(sep_fp);
+ }
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+
diff --git a/spectro/usbio.c b/spectro/usbio.c
new file mode 100644
index 0000000..3db1535
--- /dev/null
+++ b/spectro/usbio.c
@@ -0,0 +1,585 @@
+
+ /* General USB I/O support */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/22/4
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/* These routines supliement the class code in ntio.c and unixio.c */
+/* with common and USB specific routines */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <signal.h>
+#if defined(UNIX)
+#include <termios.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#else
+#include "sa_config.h"
+#endif
+#include "numsup.h"
+#include "xspect.h"
+#include "insttypes.h"
+#include "conv.h"
+#include "icoms.h"
+
+#ifdef ENABLE_USB
+
+/* Counter set when we're in a USB read or write */
+/* Note - this isn't perfectly thread safe */
+int in_usb_rw = 0;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Cancel token utility functions */
+
+/* Used by caller of icoms to init and uninit token */
+void usb_init_cancel(usb_cancelt *p) {
+
+ amutex_init(p->cmtx);
+
+#ifdef NATIVE_USB
+ p->hcancel = NULL;
+#else
+# ifdef USE_LIBUSB1
+ p->hcancel = NULL;
+# else
+ p->hcancel = (void *)-1;
+# endif
+#endif
+}
+
+void usb_uninit_cancel(usb_cancelt *p) {
+ amutex_del(p->cmtx);
+}
+
+/* Used by implementation */
+static void usb_lock_cancel(usb_cancelt *p) {
+ amutex_lock(p->cmtx);
+}
+
+static void usb_unlock_cancel(usb_cancelt *p) {
+ amutex_unlock(p->cmtx);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Include the USB implementation dependent function implementations */
+#ifdef NATIVE_USB
+# ifdef NT
+# include "usbio_nt.c"
+# endif
+# if defined(__APPLE__)
+# include "usbio_ox.c"
+# endif
+# if defined(UNIX_X11)
+# include "usbio_lx.c"
+# endif
+#else /* Using libusb */
+# include "usbio_lusb.c"
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* I/O routines supported by icoms - uses platform independent */
+/* USB routines implemented by code in usbio_*.c above */
+
+/* USB control message */
+static int
+icoms_usb_control(
+icoms *p,
+int requesttype, /* 8 bit request type (USB bmRequestType) */
+int request, /* 8 bit request code (USB bRequest) */
+int value, /* 16 bit value (USB wValue) */
+int index, /* 16 bit index (USB wIndex) */
+unsigned char *rwbuf, /* Write or read buffer */
+int rwsize, /* Bytes to read or write */
+double tout /* Timeout in seconds */
+) {
+ int rv = 0; /* Return value */
+ int c, rwbytes; /* Data bytes read or written */
+ long top; /* timeout in msec */
+
+ if (p->log->debug >= 8) {
+ a1logd(p->log, 8, "icoms_usb_control: message %02x, %02x %04x %04x %04x\n",
+ requesttype, request, value, index, rwsize);
+ if ((requesttype & IUSB_ENDPOINT_IN) == 0)
+ a1logd(p->log, 8, " writing data %s\n",icoms_tohex(rwbuf, rwsize));
+ }
+
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_control: device not open\n");
+ return ICOM_SYS;
+ }
+
+ top = (int)(tout * 1000.0 + 0.5); /* Timout in msec */
+
+#ifdef QUIET_MEMCHECKERS
+ if (requesttype & IUSB_ENDPOINT_IN)
+ memset(rwbuf, 0, rwsize);
+#endif
+
+ /* Call back end implementation */
+ rv = icoms_usb_control_msg(p, &rwbytes, requesttype, request, value, index,
+ rwbuf, rwsize, top);
+ a1logd(p->log, 8, "icoms_usb_control: returning ICOM err 0x%x\n",rv);
+
+ if (p->log->debug >= 8 && (requesttype & IUSB_ENDPOINT_IN))
+ a1logd(p->log, 8, " read data %s\n",icoms_tohex(rwbuf, rwsize));
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - */
+/* USB Read/Write. Direction is set by ep. */
+/* Don't retry on a short read, return ICOM_SHORT. */
+static int
+icoms_usb_rw(icoms *p,
+ usb_cancelt *cancelt, /* Cancel handle */
+ int ep, /* End point address */
+ unsigned char *rbuf, /* Read/Write buffer */
+ int bsize, /* Bytes to read */
+ int *breadp, /* Bytes read/written */
+ double tout /* Timeout in seconds */
+) {
+ int lerr; /* Last error */
+ int bread, qa;
+ long top; /* Timeout period */
+ icom_usb_trantype type; /* bulk or interrupt */
+
+#ifdef QUIET_MEMCHECKERS
+ memset(rbuf, 0, bsize);
+#endif
+
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_rw: device not initialised\n");
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).valid == 0) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_rw: invalid end point 0x%02x\n",ep);
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).type != ICOM_EP_TYPE_BULK
+ && p->EPINFO(ep).type != ICOM_EP_TYPE_INTERRUPT) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_rw: unhandled end point type %d\n",p->EPINFO(ep).type);
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).type == ICOM_EP_TYPE_BULK)
+ type = icom_usb_trantype_bulk;
+ else
+ type = icom_usb_trantype_interrutpt;
+
+ qa = bsize; /* For simpler tracing */
+
+ lerr = 0;
+ bread = 0;
+
+ top = (int)(tout * 1000 + 0.5); /* Timeout period in msecs */
+
+ /* Bug workaround - on some OS's for some devices */
+ if (p->uflags & icomuf_resetep_before_read
+ && (ep & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_IN) {
+ msec_sleep(1); /* Let device recover ? */
+ p->usb_resetep(p, ep);
+ msec_sleep(1); /* Let device recover (ie. Spyder 3) */
+ }
+
+ /* Until data is all read/written, we get a short read/write, we time out, or the user aborts */
+// a1logd(p->log, 8, "icoms_usb_rw: read/write of %d bytes, timout %f\n",bsize,tout);
+ while (bsize > 0) {
+ int rv, rbytes;
+ int rsize = bsize > qa ? qa : bsize;
+
+// a1logd(p->log, 8, "icoms_usb_rw: read/write %d bytes this time\n",rsize);
+ rv = icoms_usb_transaction(p, cancelt, &rbytes, type, (unsigned char)ep, rbuf, rsize, top);
+ if (rv != 0 && rv != ICOM_SHORT) {
+ lerr = rv;
+ break;
+ } else { /* Account for bytes read/written */
+ bsize -= rbytes;
+ rbuf += rbytes;
+ bread += rbytes;
+ }
+ if (rbytes != rsize) {
+ lerr |= ICOM_SHORT;
+ break;
+ }
+ }
+
+ if (breadp != NULL)
+ *breadp = bread;
+
+ a1logd(p->log, 8, "icoms_usb_rw: returning %d bytes, ICOM err 0x%x\n",bread, lerr);
+
+ return lerr;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Static list so that all open USB/HID connections can be closed on a SIGKILL */
+static icoms *icoms_list = NULL;
+
+/* Clean up any open USB ports ready for exit on signal */
+static void icoms_cleanup() {
+ icoms *pp, *np;
+
+#if defined(UNIX)
+ /* This is a bit of a hack to compensate for the fact */
+ /* that a ^C will kill the program while ICANON is off. */
+ /* It's really better to restore the original attributes, */
+ /* even when USB is not compiled in. */
+ struct termios news;
+ if (tcgetattr(STDIN_FILENO, &news) >= 0) {
+ news.c_lflag |= (ICANON | ECHO);
+ tcsetattr(STDIN_FILENO,TCSANOW, &news);
+ }
+#endif
+
+ for (pp = icoms_list; pp != NULL; pp = np) {
+ np = pp->next;
+ a1logd(pp->log, 6, "icoms_cleanup: closing usb port 0x%x\n",pp);
+ /* There's a problem here if have more than one USB port */
+ /* open - win32 doesn't return from the system call. */
+ /* Should we depend on usb read/write routines to call cleanup ? */
+ pp->close_port(pp);
+ }
+}
+
+#ifdef NT
+void (__cdecl *usbio_int)(int sig) = SIG_DFL;
+void (__cdecl *usbio_term)(int sig) = SIG_DFL;
+#endif
+#ifdef UNIX
+void (*usbio_hup)(int sig) = SIG_DFL;
+void (*usbio_int)(int sig) = SIG_DFL;
+void (*usbio_term)(int sig) = SIG_DFL;
+#endif
+
+/* On something killing our process, deal with USB cleanup */
+static void icoms_sighandler(int arg) {
+ a1logd(g_log, 6, "icoms_sighandler: invoked with arg = %d\n",arg);
+ if (in_usb_rw != 0)
+ in_usb_rw = -1;
+ icoms_cleanup();
+ /* Call the existing handlers */
+#ifdef UNIX
+ if (arg == SIGHUP && usbio_hup != SIG_DFL && usbio_hup != SIG_IGN)
+ usbio_hup(arg);
+#endif /* UNIX */
+ if (arg == SIGINT && usbio_int != SIG_DFL && usbio_int != SIG_IGN)
+ usbio_int(arg);
+ if (arg == SIGTERM && usbio_term != SIG_DFL && usbio_term != SIG_IGN)
+ usbio_term(arg);
+
+ a1logd(g_log, 6, "icoms_sighandler: calling exit()\n");
+ exit(0);
+}
+
+/* - - - - - - - - - - - - - - - - - - - */
+
+/* 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);
+#endif /* UNIX */
+ usbio_int = signal(SIGINT, icoms_sighandler);
+ usbio_term = signal(SIGTERM, icoms_sighandler);
+ }
+
+ /* Add it to our static list, to allow automatic cleanup on signal */
+ p->next = icoms_list;
+ icoms_list = p;
+ a1logd(g_log, 6, "usb_install_signal_handlers: done\n");
+}
+
+/* Delete an icoms from our static signal cleanup list */
+void usb_delete_from_cleanup_list(icoms *p) {
+
+ /* Find it and delete it from our static cleanup list */
+ if (icoms_list != NULL) {
+ if (icoms_list == p) {
+ icoms_list = p->next;
+ if (icoms_list == NULL) {
+#if defined(UNIX)
+ signal(SIGHUP, usbio_hup);
+#endif /* UNIX */
+ signal(SIGINT, usbio_int);
+ signal(SIGTERM, usbio_term);
+ }
+ } else {
+ icoms *pp;
+ for (pp = icoms_list; pp != NULL; pp = pp->next) {
+ if (pp->next == p) {
+ pp->next = p->next;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* ========================================================= */
+/* USB write/read "serial" imitation */
+
+/* Write the characters in the buffer out */
+/* Data will be written up to the terminating nul */
+/* Return relevant error status bits */
+static int
+icoms_usb_ser_write(
+icoms *p,
+char *wbuf,
+double tout)
+{
+ int len, wbytes;
+ long toc, i, top; /* Timout count, counter, timeout period */
+ int ep = p->wr_ep; /* End point */
+ icom_usb_trantype type; /* bulk or interrupt */
+ int retrv = ICOM_OK;
+
+ a1logd(p->log, 8, "\nicoms_usb_ser_write: writing '%s'\n",icoms_fix(wbuf));
+
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_ser_write: device is not open\n");
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).valid == 0) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_ser_write: invalid end point 0x%02x\n",ep);
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).type != ICOM_EP_TYPE_BULK
+ && p->EPINFO(ep).type != ICOM_EP_TYPE_INTERRUPT) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_ser_write: unhandled end point type %d",p->EPINFO(ep).type);
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).type == ICOM_EP_TYPE_BULK)
+ type = icom_usb_trantype_bulk;
+ else
+ type = icom_usb_trantype_interrutpt;
+
+ len = strlen(wbuf);
+ tout *= 1000.0; /* Timout in msec */
+
+ top = (int)(tout + 0.5); /* Timeout period in msecs */
+ toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */
+ if (toc < 1)
+ toc = 1;
+
+ /* Until data is all written, we time out, or the user aborts */
+ for (i = toc; i > 0 && len > 0;) {
+ int c, rv;
+ a1logd(p->log, 8, "icoms_usb_ser_write: attempting to write %d bytes to usb top = %d, i = %d\n",len,top,i);
+
+ rv = icoms_usb_transaction(p, NULL, &wbytes, type, (unsigned char)ep, (unsigned char *)wbuf, len, top);
+ if (rv != ICOM_OK) {
+ if (rv != ICOM_TO) {
+ retrv |= rv;
+ break;
+ }
+ i--; /* timeout */
+ } else { /* Account for bytes written */
+ a1logd(p->log, 8, "icoms_usb_ser_write: wrote %d bytes\n",wbytes);
+ i = toc;
+ wbuf += wbytes;
+ len -= wbytes;
+ }
+ }
+ if (i <= 0) /* Must have timed out */
+ retrv |= ICOM_TO;
+
+ a1logd(p->log, 8, "icoms_usb_ser_write: returning ICOM err 0x%x\n",retrv);
+
+ return retrv;
+}
+
+
+/* Read characters into the buffer */
+/* Return string will be terminated with a nul */
+/* Read only in paket sized chunks, and retry if */
+/* the bytes requested aren'r read, untill we get a */
+/* timeout or a terminating char is read */
+static int
+icoms_usb_ser_read(icoms *p,
+char *rbuf, /* Buffer to store characters read */
+int bsize, /* Buffer size */
+char tc, /* Terminating characer */
+int ntc, /* Number of terminating characters */
+double tout) /* Time out in seconds */
+{
+ int j, rbytes;
+ long toc, i, top; /* Timout count, counter, timeout period */
+ char *rrbuf = rbuf; /* Start of return buffer */
+ int ep = p->rd_ep; /* End point */
+ icom_usb_trantype type; /* bulk or interrupt */
+ int retrv = ICOM_OK;
+
+#ifdef QUIET_MEMCHECKERS
+ memset(rbuf, 0, bsize);
+#endif
+
+ if (!p->is_open) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_ser_read: device is not open\n");
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).valid == 0) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_ser_read: invalid end point 0x%02x\n",ep);
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).type != ICOM_EP_TYPE_BULK
+ && p->EPINFO(ep).type != ICOM_EP_TYPE_INTERRUPT) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_ser_read: unhandled end point type %d",p->EPINFO(ep).type);
+ return ICOM_SYS;
+ }
+
+ if (p->EPINFO(ep).type == ICOM_EP_TYPE_BULK)
+ type = icom_usb_trantype_bulk;
+ else
+ type = icom_usb_trantype_interrutpt;
+
+ if (bsize < 3) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_ser_read given too small a buffer (%d)", bsize);
+ return ICOM_SYS;
+ }
+
+ for (i = 0; i < bsize; i++) rbuf[i] = 0;
+
+ tout *= 1000.0; /* Timout in msec */
+ bsize--; /* Allow space for null */
+
+ /* Have to do this in one go, because libusb has no way */
+ /* of timing out and returning the number of characters read */
+ /* up to the timeout, and it looses characters. */
+ top = (int)(tout + 0.5); /* Timeout period in msecs */
+ toc = (int)(tout/top + 0.5); /* Number of timout periods in timeout */
+ if (toc < 1)
+ toc = 1;
+
+ a1logd(p->log, 8, "\nicoms_usb_ser_read: end point 0x%x, read quanta %d\n",p->rd_ep,p->rd_qa);
+ /* Until data is all read, we time out, or the user aborts */
+ for (i = toc, j = 0; i > 0 && bsize > 1 && j < ntc ;) {
+ int c, rv;
+ int rsize = p->rd_qa < bsize ? p->rd_qa : bsize;
+
+ a1logd(p->log, 8, "icoms_usb_ser_read: attempting to read %d bytes from usb, top = %d, i = %d, j = %d\n",bsize > p->rd_qa ? p->rd_qa : bsize,top,i,j);
+ /* We read one read quanta at a time (usually 8 bytes), to avoid */
+ /* problems with libusb loosing characters whenever it times out. */
+ rv = icoms_usb_transaction(p, NULL, &rbytes, type, (unsigned char)ep, (unsigned char *)rbuf, rsize, top);
+ if (rv != 0 && rv != ICOM_SHORT) {
+ a1logd(p->log, 8, "icoms_usb_ser_read: read failed with 0x%x, rbuf = '%s'\n",rv,icoms_fix(rrbuf));
+ if (rv != ICOM_TO) {
+ retrv |= rv;
+ break;
+ }
+ i--; /* Timeout */
+ } else { /* Account for bytes read */
+ a1logd(p->log, 8, "icoms_usb_ser_read: read read %d bytes, rbuf = '%s'\n",rbytes,icoms_fix(rrbuf));
+ i = toc;
+ bsize -= rbytes;
+ while(rbytes) { /* Count termination characters */
+ if (*rbuf++ == tc)
+ j++;
+ rbytes--;
+ }
+ }
+ }
+
+ if (i <= 0) /* Must have timed out */
+ retrv |= ICOM_TO;
+
+ *rbuf = '\000';
+
+ a1logd(p->log, 8, "icoms_usb_ser_read: returning '%s' ICOM err 0x%x\n",icoms_fix(rrbuf),retrv);
+
+ return retrv;
+}
+
+
+/* ------------------------------------------------- */
+
+/* Set the usb port number and characteristics. */
+/* This may be called to re-establish a connection that has failed */
+/* return an icom error */
+static int
+icoms_set_usb_port(
+icoms *p,
+int config, /* Configuration */
+int wr_ep, /* "Serial" Write end point */
+int rd_ep, /* "Serial" Read end point */
+icomuflags usbflags, /* Any special handling flags */
+int retries, /* > 0 if we should retry set_configuration (100msec) */
+char **pnames /* List of process names to try and kill before opening */
+) {
+ a1logd(p->log, 8, "icoms_set_usb_port: About to set usb port characteristics\n");
+
+ if (p->port_type(p) == icomt_usb) {
+ int rv;
+
+ if (p->is_open)
+ p->close_port(p);
+
+ if ((rv = usb_open_port(p, config, wr_ep, rd_ep, usbflags, retries, pnames)) != ICOM_OK) {
+ return rv;
+ }
+
+ p->write = icoms_usb_ser_write;
+ p->read = icoms_usb_ser_read;
+
+ }
+ a1logd(p->log, 6, "icoms_set_usb_port: usb port characteristics set ok\n");
+
+#ifndef NATIVE_USB
+ /* libusb doesn't have any facility for re-directing its */
+ /* debug messages. Since we're moving away from it, */
+ /* ignore the problem. */
+ if (p->log->debug >= 8) { /* Could this go inside usb_open_port ? */
+# ifdef USE_LIBUSB1
+ libusb_set_debug(NULL, p->log->debug);
+# else
+ usb_set_debug(p->debug);
+# endif
+ }
+#endif /* NATIVE_USB */
+
+ return ICOM_OK;
+}
+
+/* ---------------------------------------------------------------------------------*/
+
+/* Set the USB specific icoms methods */
+void usb_set_usb_methods(
+icoms *p
+) {
+ p->set_usb_port = icoms_set_usb_port;
+ p->usb_control = icoms_usb_control;
+ p->usb_read = icoms_usb_rw;
+ p->usb_write = icoms_usb_rw;
+ p->usb_cancel_io = icoms_usb_cancel_io;
+ p->usb_resetep = icoms_usb_resetep;
+ p->usb_clearhalt = icoms_usb_clearhalt;
+}
+
+/* ---------------------------------------------------------------------------------*/
+
+#endif /* ENABLE_USB */
diff --git a/spectro/usbio.h b/spectro/usbio.h
new file mode 100644
index 0000000..5c982ae
--- /dev/null
+++ b/spectro/usbio.h
@@ -0,0 +1,247 @@
+
+#ifndef USBIO_H
+
+ /* General USB I/O support */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/22/4
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#ifdef ENABLE_USB
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+
+#ifdef NATIVE_USB
+
+/* Standard USB protocol defines */
+# include "iusb.h"
+
+/* Opaque structure to hide implementation details in icoms */
+
+# ifdef NT
+
+/* MSWin native USB context */
+struct usb_idevice {
+ /* icompath stuff: */
+ char *dpath; /* Device path */
+ int nconfig; /* Number of configurations */
+ int config; /* This config (always 1) */
+ int nifce; /* Number of interfaces */
+ usb_ep ep[32]; /* Information about each end point for general usb i/o */
+ /* Stuff setup when device is open: */
+ HANDLE handle;
+};
+
+# endif /* NT */
+
+# if defined(UNIX) && defined(__APPLE__)
+
+/* OS X structure version wrangling */
+
+/* usb_device_t - for communicating with the device. */
+#if defined (kIOUSBDeviceInterfaceID320)
+# define usb_device_t IOUSBDeviceInterface320
+# define DeviceInterfaceID kIOUSBDeviceInterfaceID320
+# define DeviceVersion 320
+#elif defined (kIOUSBDeviceInterfaceID300)
+# define usb_device_t IOUSBDeviceInterface300
+# define DeviceInterfaceID kIOUSBDeviceInterfaceID300
+# define DeviceVersion 300
+#elif defined (kIOUSBDeviceInterfaceID245)
+# define usb_device_t IOUSBDeviceInterface245
+# define DeviceInterfaceID kIOUSBDeviceInterfaceID245
+# define DeviceVersion 245
+#elif defined (kIOUSBDeviceInterfaceID197)
+# define usb_device_t IOUSBDeviceInterface197
+# define DeviceInterfaceID kIOUSBDeviceInterfaceID197
+# define DeviceVersion 197
+#elif defined (kIOUSBDeviceInterfaceID187)
+# define usb_device_t IOUSBDeviceInterface187
+# define DeviceInterfaceID kIOUSBDeviceInterfaceID187
+# define DeviceVersion 187
+#elif defined (kIOUSBDeviceInterfaceID182)
+# define usb_device_t IOUSBDeviceInterface182
+# define DeviceInterfaceID kIOUSBDeviceInterfaceID182
+# define DeviceVersion 182
+#else
+# error "Unknown kIOUSBDeviceInterface version"
+#endif
+
+/* usb_interface_t - for communicating with an interface in the device */
+#if defined (kIOUSBInterfaceInterfaceID300)
+# define usb_interface_t IOUSBInterfaceInterface300
+# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID300
+# define InterfaceVersion 300
+#elif defined (kIOUSBInterfaceInterfaceID245)
+# define usb_interface_t IOUSBInterfaceInterface245
+# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID245
+# define InterfaceVersion 245
+#elif defined (kIOUSBInterfaceInterfaceID220)
+# define usb_interface_t IOUSBInterfaceInterface220
+# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID220
+# define InterfaceVersion 220
+#elif defined (kIOUSBInterfaceInterfaceID197)
+# define usb_interface_t IOUSBInterfaceInterface197
+# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID197
+# define InterfaceVersion 197
+#elif defined (kIOUSBInterfaceInterfaceID190)
+# define usb_interface_t IOUSBInterfaceInterface190
+# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID190
+# define InterfaceVersion 190
+#elif defined (kIOUSBInterfaceInterfaceID182)
+# define usb_interface_t IOUSBInterfaceInterface182
+# define InterfaceInterfaceID kIOUSBInterfaceInterfaceID182
+# define InterfaceVersion 182
+#else
+# error "Unknown kIOUSBInterfaceInterfaceID"
+#endif
+
+/* OS X native USB context */
+struct usb_idevice {
+ /* icompath stuff: */
+ int lid; /* Location ID */
+ io_object_t ioob; /* USB io registry object */
+ int nconfig; /* Number of configurations */
+ int config; /* This config (always 1) */
+ int nifce; /* Number of interfaces */
+ /* Stuff setup when device is open: */
+ usb_device_t **device; /* OS X USB device we've opened */
+ usb_interface_t **interfaces[32]; /* nifce interfaces */
+ CFRunLoopSourceRef cfsources[32]; /* Corresponding event sources */
+ pthread_t thread; /* RunLoop thread */
+ pthread_mutex_t lock; /* Protect cfrunloop and cond */
+ pthread_cond_t cond; /* Signal from thread that it's started */
+ IOReturn thrv; /* Thread return value */
+ CFRunLoopRef cfrunloop; /* RunLoop */
+ CFRunLoopSourceRef cfsource;/* Device event sources */
+};
+# endif /* OS X */
+
+# if defined(UNIX) && !defined(__APPLE__)
+
+/* Linux USB context */
+struct usb_idevice {
+ /* icompath stuff: */
+ char *dpath; /* Device path */
+ int nconfig; /* Number of configurations */
+ int config; /* This config (always 1) */
+ int nifce; /* Number of interfaces */
+ usb_ep ep[32]; /* Information about each end point for general usb i/o */
+ /* Stuff setup when device is open: */
+ int fd; /* Device file descriptor */
+ pthread_t thread; /* Reaper thread */
+ volatile int shutdown; /* Flag to tell reaper that we're closing the fd */
+ int sd_pipe[2]; /* pipe to signal sutdown */
+
+ /* These are simply to deal with the device going away: */
+ volatile int running; /* Reaper thread is running. Set to 0 on reap failure */
+ pthread_mutex_t lock; /* Protect reqs list */
+ struct _usbio_req *reqs; /* linked list of current reqs */
+};
+
+# endif /* Linux */
+
+#else /* !NATIVE_USB - Using libusb */
+
+# ifdef USE_LIBUSB1
+
+# include "libusb.h"
+# define usb_idevice libusb_device
+# define IUSB_ENDPOINT_DIR_MASK LIBUSB_ENDPOINT_DIR_MASK
+# define IUSB_ENDPOINT_IN LIBUSB_ENDPOINT_IN
+# define IUSB_ENDPOINT_OUT LIBUSB_ENDPOINT_OUT
+# define IUSB_REQ_RECIP_DEVICE LIBUSB_RECIPIENT_DEVICE
+# define IUSB_REQ_RECIP_INTERFACE LIBUSB_RECIPIENT_INTERFACE
+# define IUSB_REQ_RECIP_ENDPOINT LIBUSB_RECIPIENT_ENDPOINT
+# define IUSB_REQ_TYPE_STANDARD LIBUSB_REQUEST_TYPE_STANDARD
+# define IUSB_REQ_TYPE_CLASS LIBUSB_REQUEST_TYPE_CLASS
+# define IUSB_REQ_TYPE_VENDOR LIBUSB_REQUEST_TYPE_VENDOR
+# define IUSB_ENDPOINT_TYPE_MASK LIBUSB_TRANSFER_TYPE_MASK
+
+# else
+
+# include "usb.h"
+# define usb_idevice usb_device
+# define IUSB_ENDPOINT_DIR_MASK USB_ENDPOINT_DIR_MASK
+# define IUSB_ENDPOINT_IN USB_ENDPOINT_IN
+# define IUSB_ENDPOINT_OUT USB_ENDPOINT_OUT
+# define IUSB_REQ_RECIP_DEVICE USB_RECIP_DEVICE
+# define IUSB_REQ_RECIP_INTERFACE USB_RECIP_INTERFACE
+# define IUSB_REQ_RECIP_ENDPOINT USB_RECIP_ENDPOINT
+# define IUSB_REQ_TYPE_STANDARD USB_TYPE_STANDARD
+# define IUSB_REQ_TYPE_CLASS USB_TYPE_CLASS
+# define IUSB_REQ_TYPE_VENDOR USB_TYPE_VENDOR
+# define IUSB_ENDPOINT_TYPE_MASK USB_ENDPOINT_TYPE_MASK
+
+# endif
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Transfer types for communicating to usb implementation */
+typedef enum {
+ icom_usb_trantype_command = 0,
+ icom_usb_trantype_interrutpt = 1,
+ icom_usb_trantype_bulk = 2
+} icom_usb_trantype;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Cancelation token. */
+struct _usb_cancelt {
+ amutex cmtx;
+ void *hcancel; /* Pointer to implementation cancel handle */
+};
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* These routines suplement the class code in icoms_nt.c and icoms_ux.c */
+
+/* Add paths to USB connected instruments, to the existing */
+/* icompath paths in the icoms structure. */
+/* return icom error */
+int usb_get_paths(struct _icompaths *p);
+
+void usb_close_port(icoms *p);
+
+/* Set the USB specific icoms methods */
+void usb_set_usb_methods(icoms *p);
+
+/* Copy usb_idevice contents from icompaths to icom */
+/* return icom error */
+int usb_copy_usb_idevice(icoms *d, icompath *s);
+
+/* Cleanup and then free a usb_del_usb_idevice */
+void usb_del_usb_idevice(struct usb_idevice *dev);
+
+/* Cleanup any USB specific icoms info */
+void usb_del_usb(icoms *p);
+
+/* Install the cleanup signal handlers */
+/* (used inside usb_open_port(), hid_open_port() */
+void usb_install_signal_handlers(icoms *p);
+
+/* Delete an icoms from our static signal cleanup list */
+/* (used inside usb_close_port(), hid_close_port() */
+void usb_delete_from_cleanup_list(icoms *p);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* ENABLE_USB */
+
+#define USBIO_H
+#endif /* USBIO_H */
diff --git a/spectro/usbio_lusb.c b/spectro/usbio_lusb.c
new file mode 100644
index 0000000..f78bcca
--- /dev/null
+++ b/spectro/usbio_lusb.c
@@ -0,0 +1,897 @@
+
+/* General USB I/O support, legacy Libusb 0.1/1.0 implementation, no longer */
+/* used by default, but can be configured in the Jamfile. */
+/* The corresponding libusb code is not distributed with the current source */
+/* though, and would have to be copied from ArgyllCMS V1.4.0 */
+
+/* This file is conditionaly #included into usbio.c */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/22/4
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/* To simplify error messages: */
+#ifdef USE_LIBUSB1
+# define USB_STRERROR(RV) libusb_strerror(RV)
+#else
+# define USB_STRERROR(RV) usb_strerror()
+#endif
+
+#ifdef USE_LIBUSB1
+# define usb_device libusb_device
+# define usb_device_descriptor libusb_device_descriptor
+# define usb_dev_handle libusb_device_handle
+# define usb_config_descriptor libusb_config_descriptor
+# define usb_strerror libusb_strerror
+#endif
+
+#if defined(__FreeBSD__) /* Shut spurious warnings up */
+# define CASTFIX (intptr_t)
+#else
+# define CASTFIX
+#endif
+
+/* Check a USB Vendor and product ID, and add the device */
+/* to the icoms path if it is supported. */
+/* (this is used to help implement usb_get_paths) */
+/* return icom error */
+static int usb_check_and_add(
+icompaths *p,
+struct usb_device *usbd
+) {
+ instType itype;
+ int nep; /* Number of end points */
+
+ struct usb_device_descriptor descriptor;
+
+#ifdef USE_LIBUSB1
+ enum libusb_error rv;
+
+ if ((rv = libusb_get_device_descriptor(usbd, &descriptor)) != LIBUSB_SUCCESS) {
+ a1loge(p->log, ICOM_SYS, "usb_check_and_add: failed with %d (%s)\n",
+ rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+#else
+ descriptor = usbd->descriptor; /* Copy */
+#endif
+ a1logd(p->log, 6, "usb_check_and_add: called with VID 0x%x, PID 0x%x\n",descriptor.idVendor, descriptor.idProduct);
+
+#ifdef USE_LIBUSB1
+#if defined(NT) || defined(__APPLE__)
+ /* Ignore libusb1 HID driver capability */
+ {
+ struct libusb_config_descriptor *confdesc = NULL;
+
+ /* If not obviously HID, we need to fetch the config descriptor */
+ if (descriptor.bDeviceClass != LIBUSB_CLASS_HID
+ && (rv = libusb_get_config_descriptor(usbd, 0, &confdesc)) != LIBUSB_SUCCESS) {
+ /* This seems to happen for hubs etc., so ignore it */
+ a1logd(p->log, 6 , "usb_check_and_add: get conf desc. failed - device not reconized\n");
+ return ICOM_OK;
+ }
+
+ if (descriptor.bDeviceClass == LIBUSB_CLASS_HID
+ || (confdesc->bNumInterfaces > 0
+ && confdesc->interface[0]. num_altsetting > 0
+ && confdesc->interface[0].altsetting[0].bInterfaceClass == LIBUSB_CLASS_HID)) {
+ int i;
+ /* See if this devices is already in the list via the HID interface */
+ /* (This may not be 100% correct in the face of multiple instances
+ of the same device, if Windows allows different drivers for different
+ instances of the same device type.) */
+ for (i = 0; i < p->npaths; i++) {
+ if (p->paths[i]->vid == descriptor.idVendor
+ && p->paths[i]->pid == descriptor.idProduct)
+ break; /* Yes */
+ }
+ if (i < p->npaths) {
+ a1logd(p->log, 6, "Is an HID device and already added\n");
+ if (confdesc != NULL)
+ libusb_free_config_descriptor(confdesc);
+ return ICOM_OK;
+ }
+ }
+ if (confdesc != NULL)
+ libusb_free_config_descriptor(confdesc);
+ }
+#endif
+#endif
+
+ /* The i1pro2 is detected by checking the number of end points, */
+ /* so set this value in icom now by looking at the descriptor */
+ {
+#ifdef USE_LIBUSB1
+ struct libusb_config_descriptor *confdesc;
+ const struct libusb_interface_descriptor *ifd;
+
+ if (libusb_get_config_descriptor(usbd, 0, &confdesc) != LIBUSB_SUCCESS) {
+ /* This seems to happen for hubs etc., so ignore it */
+ a1logd(p->log, 6 , "usb_check_and_add: get conf desc. failed - device not reconized\n");
+ return ICOM_OK;
+ }
+
+ ifd = &confdesc->interface[0].altsetting[0];
+ nep = ifd->bNumEndpoints;
+ if (confdesc != NULL)
+ libusb_free_config_descriptor(confdesc);
+#else
+ struct usb_interface_descriptor *ifd;
+ ifd = &usbd->config[0].interface[0].altsetting[0];
+ nep = ifd->bNumEndpoints;
+#endif
+ }
+
+ if ((itype = inst_usb_match((unsigned int)descriptor.idVendor,
+ (unsigned int)descriptor.idProduct, nep)) != instUnknown) {
+ char pname[400];
+
+ a1logd(p->log, 2, "usb_check_and_add: found known instrument VID 0x%x, PID 0x%x\n",
+ descriptor.idVendor, descriptor.idProduct);
+
+ /* Create a path/identification */
+ /* (devnum doesn't seem valid ?) */
+#ifdef USE_LIBUSB1
+ libusb_ref_device(usbd); /* Keep it */
+ sprintf(pname,"usb:/bus%d/dev%d/ (%s)",libusb_get_bus_number(usbd),libusb_get_device_address(usbd), inst_name(itype));
+#else
+# if defined(UNIX)
+ sprintf(pname,"usb:/bus%d/dev%d (%s)",usbd->bus->location >> 24, usbd->devnum, inst_name(itype));
+# else
+ sprintf(pname,"usb:/bus%lu/dev%d (%s)",usbd->bus->location, usbd->devnum, inst_name(itype));
+# endif
+#endif
+
+ /* Add the path to the list */
+ p->add_usb(p, pname, descriptor.idVendor, descriptor.idProduct, nep, usbd, itype);
+ return ICOM_OK;
+ }
+ a1logd(p->log, 6 , "usb_check_and_add: device not reconized\n");
+
+ return ICOM_OK;
+}
+
+#ifdef USE_LIBUSB1
+
+/* Add paths of USB connected instruments */
+/* return icom error */
+int usb_get_paths(
+icompaths *p
+) {
+ ssize_t i, nlist;
+ struct libusb_device **list;
+
+ /* Scan the USB busses for instruments we recognise */
+ /* We're not expecting any of our instruments to be an interface on a device. */
+
+ /* Use the default context to avoid worying about versions */
+ /* of libusb1 that don't reference count them. (ie. would need */
+ /* copies in both icompaths and icoms) */
+
+ libusb_init(NULL); /* Use default context */
+
+ /* Enable lower level debugging of device finding */
+ if (p->log->debug >= 8)
+ libusb_set_debug(NULL, p->log->debug);
+
+ if ((nlist = libusb_get_device_list(NULL, &list)) < 0) {
+ a1loge(p->log, ICOM_SYS, "usb_get_paths: get_device_list failed with %d (%s)\n",
+ nlist,USB_STRERROR(nlist));
+ return ICOM_SYS;
+ }
+
+ a1logd(p->log, 6, "usb_get_paths: about to look through devices:\n");
+
+ for (i = 0; i < nlist; i++) {
+ usb_check_and_add(p, list[i]);
+ }
+
+ libusb_free_device_list(list, 1);
+
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ return ICOM_OK;
+}
+
+#else /* !USE_LIBUSB1 */
+
+/* Add paths of USB connected instruments */
+/* return icom error */
+int usb_get_paths(
+icompaths *p
+) {
+ struct usb_bus *bus;
+ int rv;
+
+ /* Enable lower level debugging of device finding */
+ if (p->log->debug >= 8)
+ usb_set_debug(p->log->debug);
+
+ /* Scan the USB busses for instruments we recognise */
+ /* We're not expecting any of our instruments to be an interface on a device. */
+
+ usb_init();
+ if ((rv = usb_find_busses()) < 0) {
+ a1loge(p->log, ICOM_SYS, "usb_get_paths: find_busses failed with %d (%s)\n",
+ rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+ if ((rv = usb_find_devices()) < 0) {
+ a1loge(p->log, ICOM_SYS, "usb_get_paths: usb_find_devices failed with %d (%s)\n",
+ rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+
+ a1logd(p->log, 6, "usb_get_paths: about to look through busses:\n");
+
+ for (bus = usb_get_busses(); bus != NULL; bus = bus->next) {
+ struct usb_device *dev;
+ a1logd(p->log, 6, "usb_get_paths: about to look through devices:\n");
+ for (dev = bus->devices; dev != NULL; dev = dev->next) {
+ if ((rv = usb_check_and_add(p, dev)) != ICOM_OK)
+ return rv;
+ }
+ }
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ return ICOM_OK;
+}
+#endif /* !USE_LIBUSB1 */
+
+/* Copy usb_idevice contents from icompaths to icom */
+/* return icom error */
+int usb_copy_usb_idevice(icoms *d, icompath *s) {
+ if (s->usbd == NULL) {
+ d->usbd = NULL;
+ return ICOM_OK;
+ }
+
+ d->usbd = s->usbd; /* Copy pointer */
+#ifdef USE_LIBUSB1
+ libusb_ref_device(d->usbd);
+#endif
+ return ICOM_OK;
+}
+
+/* Cleanup and then free a usb dev entry */
+void usb_del_usb_idevice(struct usb_idevice *usbd) {
+
+ if (usbd == NULL)
+ return;
+
+#ifdef USE_LIBUSB1
+ libusb_unref_device(usbd);
+#endif
+}
+
+/* Cleanup any USB specific icoms state */
+void usb_del_usb(icoms *p) {
+
+#ifdef USE_LIBUSB1
+ usb_del_usb_idevice(p->usbd);
+#endif /* USE_LIBUSB1 */
+}
+
+/* Close an open USB port */
+/* If we don't do this, the port and/or the device may be left in an unusable state. */
+void usb_close_port(icoms *p) {
+
+ a1logd(p->log, 8, "usb_close_port: called\n");
+
+ if (p->is_open && p->usbh != NULL) {
+ int iface;
+
+ for (iface = 0; iface < p->nifce; iface++) {
+#ifdef USE_LIBUSB1
+ libusb_release_interface(p->usbh, iface);
+#else
+ usb_release_interface(p->usbh, iface);
+#endif
+ }
+
+ /* Workaround for some bugs */
+ if (p->uflags & icomuf_reset_before_close) {
+#ifdef USE_LIBUSB1
+ libusb_reset_device(p->usbh);
+#else
+ usb_reset(p->usbh);
+#endif
+ }
+
+ /* Close as well, othewise we can't re-open */
+ {
+#ifdef USE_LIBUSB1
+ libusb_close(p->usbh);
+#else
+ usb_close(p->usbh);
+#endif
+ }
+ p->usbh = NULL;
+
+ a1logd(p->log, 8, "usb_close_port: port has been released and closed\n");
+ }
+ p->is_open = 0;
+
+ /* Find it and delete it from our static cleanup list */
+ usb_delete_from_cleanup_list(p);
+
+}
+
+/* Open a USB port for all our uses. */
+/* This always re-opens the port */
+/* return icom error */
+static int usb_open_port(
+icoms *p,
+int config, /* Configuration number */
+int wr_ep, /* Write end point */
+int rd_ep, /* Read end point */
+icomuflags usbflags,/* Any special handling flags */
+int retries, /* > 0 if we should retry set_configuration (100msec) */
+char **pnames /* List of process names to try and kill before opening */
+) {
+ int tries = 0;
+ a1logd(p->log, 8, "usb_open_port: Make sure USB port is open, tries %d\n",retries);
+
+ if (p->is_open)
+ p->close_port(p);
+
+ /* Make sure the port is open */
+ if (!p->is_open) {
+ struct usb_device_descriptor descriptor;
+#ifdef USE_LIBUSB1
+ const struct libusb_interface_descriptor *ifd;
+ struct libusb_config_descriptor *confdesc;
+#else
+ struct usb_interface_descriptor *ifd;
+#endif
+ int rv, i, iface;
+ kkill_nproc_ctx *kpc = NULL;
+
+ /* Do open retries */
+ for (tries = 0; retries >= 0; retries--, tries++) {
+
+ a1logd(p->log, 8, "usb_open_port: About to open USB port '%s'\n",p->name);
+
+ if (tries > 0) {
+ //msec_sleep(i_rand(50,100));
+ msec_sleep(77);
+ }
+ if (tries > 0 && pnames != NULL && kpc == NULL) {
+#if defined(__APPLE__) || defined(NT)
+ if ((kpc = kkill_nprocess(pnames, p->log)) == NULL)
+ a1logd(p->log, 1, "usb_open_port: kkill_nprocess returned error!\n");
+#endif /* __APPLE__ */
+ }
+
+#ifdef USE_LIBUSB1
+ if ((rv = libusb_open(p->usbd, &p->usbh)) != LIBUSB_SUCCESS)
+#else
+ if ((p->usbh = usb_open(p->usbd)) == NULL)
+#endif
+ {
+ a1logd(p->log, 8, "usb_open_port: open '%s' config %d failed (%s) (Permissions ?)\n",p->name,config,USB_STRERROR(rv));
+ if (retries <= 0) {
+ if (kpc != NULL)
+ kpc->del(kpc);
+ a1loge(p->log, ICOM_SYS, "usb_open_port: open '%s' config %d failed (%s) (Permissions ?)\n",p->name,config,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+ continue;
+ } else if (p->debug)
+ a1logd(p->log, 2, "usb_open_port: open port '%s' succeeded\n",p->name);
+
+ /* Get a copy of the device descriptor so we can see device params */
+#ifdef USE_LIBUSB1
+ if (libusb_get_device_descriptor(p->usbd, &descriptor) != LIBUSB_SUCCESS) {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: get device descriptor on '%s' failed with %d (%s)\n",p->name,rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+#else
+ descriptor = p->usbd->descriptor; /* Copy */
+#endif
+
+ p->uflags = usbflags;
+
+ a1logd(p->log, 8, "usb_open_port: Number of configurations = %d\n",
+ descriptor.bNumConfigurations);
+ p->nconfig = descriptor.bNumConfigurations;
+ p->config = config;
+
+#if defined(UNIX_X11)
+ /* only call set_configuration on Linux if the device has more than one */
+ /* possible configuration, because Linux does a set_configuration by default, */
+ /* and two of them mess up instruments like the Spyder2 */
+
+ if (descriptor.bNumConfigurations > 1) {
+#endif
+
+ /* Can't skip this, as it is needed to setup the interface and end points on OS X */
+#ifdef USE_LIBUSB1
+ if ((rv = libusb_set_configuration(p->usbh, config)) < 0)
+#else
+ if ((rv = usb_set_configuration(p->usbh, config)) < 0)
+#endif
+ {
+ a1logd(p->log, 8, "usb_open_port: configuring '%s' to %d failed with %d (%s)\n",p->name,config,rv,USB_STRERROR(rv));
+ if (retries <= 0) {
+ if (kpc != NULL)
+ kpc->del(kpc);
+ a1loge(p->log, ICOM_SYS, "usb_open_port: configuring '%s' to %d failed with %d (%s)\n",p->name,config,rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+ /* reset the port and retry */
+#ifdef USE_LIBUSB1
+ libusb_reset_device(p->usbh); // ~~999 ?????
+ libusb_close(p->usbh);
+#else
+ usb_reset(p->usbh);
+ usb_close(p->usbh);
+#endif
+ continue;
+ }
+#if defined(UNIX_X11)
+ } /* End of if bNumConfigurations > 1 */
+#endif
+
+ /* We're done */
+ break;
+ }
+
+ if (kpc != NULL)
+ kpc->del(kpc);
+
+ /* Claim all interfaces of this configuration */
+#ifdef USE_LIBUSB1
+ if ((rv = libusb_get_active_config_descriptor(p->usbd, &confdesc)) != LIBUSB_SUCCESS) {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: get config desc. for '%s' failed with %d (%s)\n",p->name,rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+ p->nifce = confdesc->bNumInterfaces;
+#else
+ p->nifce = p->usbd->config->bNumInterfaces;
+#endif
+
+// a1logv(p->log, 8, "usb_open_port: Number of interfaces = %d\n",p->nifce);
+
+ /* Claim all the interfaces */
+ for (iface = 0; iface < p->nifce; iface++) {
+ /* (Second parameter is bInterfaceNumber) */
+
+#ifdef USE_LIBUSB1
+ if ((rv = libusb_claim_interface(p->usbh, iface)) < 0) {
+ /* Detatch the existing interface if kernel driver is active. */
+ if (p->uflags & icomuf_detach
+ && libusb_kernel_driver_active(p->usbh, iface) == 1) {
+ libusb_detach_kernel_driver (p->usbh, iface);
+ if ((rv = libusb_claim_interface(p->usbh, iface)) < 0) {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: Claiming USB port '%s' interface %d failed after detach with %d (%s)\n",p->name,iface,rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+ } else {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: Claiming USB port '%s' interface %d failed with %d (%s)\n",p->name,iface,rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+ }
+#else
+ if ((rv = usb_claim_interface(p->usbh, iface)) < 0) {
+# if LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP == 1
+ /* Detatch the existing interface. */
+ if (p->uflags & icomuf_detach) {
+ usb_detach_kernel_driver_np(p->usbh, iface);
+ if ((rv = usb_claim_interface(p->usbh, iface)) < 0) {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: Claiming USB port '%s' interface %d failed after detach with %d (%s)\n",p->name,iface,rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+ }
+# else
+ a1loge(p->log, ICOM_SYS, "usb_open_port: Claiming USB port '%s' interface %d failed with %d (%s)\n",p->name,iface,rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+# endif
+ }
+#endif
+
+ /* Fill in the end point details */
+#ifdef USE_LIBUSB1
+ ifd = &confdesc->interface[iface].altsetting[0];
+#else
+ ifd = &p->usbd->config[p->config-1].interface[iface].altsetting[0];
+#endif
+// a1logv(p->log, 8, "usb_open_port: Number of endpoints on iface %d = %d\n",iface, ifd->bNumEndpoints);
+ p->nep = ifd->bNumEndpoints;
+ for (i = 0; i < ifd->bNumEndpoints; i++) {
+ int ad = ifd->endpoint[i].bEndpointAddress;
+ p->EPINFO(ad).valid = 1;
+ p->EPINFO(ad).addr = ad;
+ p->EPINFO(ad).packetsize = ifd->endpoint[i].wMaxPacketSize;
+ p->EPINFO(ad).type = ifd->endpoint[i].bmAttributes & IUSB_ENDPOINT_TYPE_MASK;
+ /* Some I/F seem to hang if we do this, some seem to hang if we don't ! */
+ if (!(p->uflags & icomuf_no_open_clear))
+#ifdef USE_LIBUSB1
+ libusb_clear_halt(p->usbh, (unsigned char)ad);
+#else
+ usb_clear_halt(p->usbh, ad);
+#endif
+// a1logv(p->log, 8, "usb_open_port: ep %d: endpoint addr %02x pktsze %d, type %d\n",i,ad,ifd->endpoint[i].wMaxPacketSize,p->EPINFO(ad).type);
+ }
+
+#ifdef NEVER
+ /* Get the serial number */
+ {
+ int rv;
+ struct usb_device_descriptor descriptor;
+
+ a1logd(p->log, 8, "usb_open_port: About to get device serial number\n");
+# ifdef USE_LIBUSB1
+ if ((rv = libusb_get_device_descriptor(p->usbd, &descriptor)) != LIBUSB_SUCCESS) {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: get_device_descriptor failed with %d USB port '%s'\n",rv,p->name);
+ return ICOM_SYS;
+ }
+# else
+ descriptor = dev->descriptor; /* Copy */
+# endif
+ if ((rv = libusb_get_string_descriptor_ascii(p->usbh, descriptor.iSerialNumber, p->serialno, 32)) <= 0) {
+ a1logd(p->log, 1, "usb_open_port: Failed to get device serial number %d (%s)\n",rv,USB_STRERROR(rv));
+ p->serialno[0] = '\000';
+ } else {
+ a1logd(p->log, 1, "usb_open_port: Device serial number = '%s'\n",p->serialno);
+ }
+ }
+#endif /* NEVER */
+ }
+
+ /* Set "serial" coms values */
+ p->wr_ep = wr_ep;
+ p->rd_ep = rd_ep;
+ p->rd_qa = p->EPINFO(rd_ep).packetsize;
+ if (p->rd_qa == 0)
+ p->rd_qa = 8;
+ a1logd(p->log, 8, "usb_open_port: 'serial' read quanta = packet size = %d\n",p->rd_qa);
+
+#ifdef USE_LIBUSB1
+ if (confdesc != NULL)
+ libusb_free_config_descriptor(confdesc);
+#endif
+
+ p->is_open = 1;
+ a1logd(p->log, 8, "usb_open_port: USB port is now open\n");
+ }
+
+ /* Install the cleanup signal handlers, and add to our cleanup list */
+ usb_install_signal_handlers(p);
+
+ return ICOM_OK;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Time out error return value */
+
+#ifdef USE_LIBUSB1
+#define USBIO_ERROR_TIMEOUT LIBUSB_ERROR_TIMEOUT
+#else
+# if defined(UNIX)
+#define USBIO_ERROR_TIMEOUT -ETIMEDOUT
+# else
+#define USBIO_ERROR_TIMEOUT -116 /* libusb-win32 code */
+# endif /* UNIX */
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef USE_LIBUSB1
+
+/* Callback functions */
+static void bulk_transfer_cb(struct libusb_transfer *transfer)
+{
+ int *completed = transfer->user_data;
+ *completed = 1;
+ /* caller interprets results and frees transfer */
+}
+
+/* Version of libusb1 sync to async code that returns the pointer */
+/* to the transfer structure so that the transfer can be cancelled */
+/* by another thread. */
+/* Return an icoms error code */
+static int do_sync_usb_transfer(
+ icoms *p,
+ struct libusb_device_handle *dev_handle,
+ usb_cancelt *cancelt,
+ int *transferred,
+ icom_usb_trantype ttype,
+ unsigned char endpoint,
+ unsigned char *buffer,
+ int length,
+ unsigned int timeout
+) {
+ enum libusb_transfer_type type;
+ struct libusb_transfer *transfer = libusb_alloc_transfer(0);
+ int completed = 0;
+ int rv;
+
+ if (!transfer) {
+ a1logd(p->log, 1, "do_sync_usb_transfer: transfer is NULL!\n");
+ return ICOM_SYS;
+ }
+
+ /* Translate icoms transfer type of libusb1 */
+ switch (ttype) {
+ case icom_usb_trantype_command:
+ type = LIBUSB_TRANSFER_TYPE_CONTROL;
+ break;
+ case icom_usb_trantype_interrutpt:
+ type = LIBUSB_TRANSFER_TYPE_INTERRUPT;
+ break;
+ case icom_usb_trantype_bulk:
+ type = LIBUSB_TRANSFER_TYPE_BULK;
+ break;
+ }
+
+ libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
+ bulk_transfer_cb, &completed, timeout);
+ transfer->type = type;
+
+ if ((rv = libusb_submit_transfer(transfer)) < 0) {
+ libusb_free_transfer(transfer);
+ a1logd(p->log, 1, "do_sync_usb_transfer: Submitting transfer failed with %d (%s)\n",rv,USB_STRERROR(rv));
+ if ((endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT)
+ return ICOM_USBW;
+ else
+ return ICOM_USBR;
+ }
+
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *)transfer;
+ usb_unlock_cancel(cancelt);
+ }
+
+ while (!completed) {
+ if ((rv = libusb_handle_events_check(NULL, &completed)) < 0) {
+ if (rv == LIBUSB_ERROR_INTERRUPTED)
+ continue; /* Retry */
+ /* Give up - cancel transfer and wait until complete */
+ libusb_cancel_transfer(transfer);
+ while (!completed) {
+ if (libusb_handle_events_check(NULL, &completed) < 0)
+ break;
+ }
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = NULL;
+ usb_unlock_cancel(cancelt);
+ }
+ libusb_free_transfer(transfer);
+ a1loge(p->log, ICOM_SYS, "do_sync_usb_transfer: handle_events failed with %d (%s)\n",rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+ }
+ }
+
+ *transferred = transfer->actual_length;
+ switch (transfer->status) {
+ case LIBUSB_TRANSFER_COMPLETED:
+ rv = ICOM_OK;
+ break;
+ case LIBUSB_TRANSFER_TIMED_OUT:
+ rv = ICOM_TO;
+ break;
+ case LIBUSB_TRANSFER_STALL:
+ case LIBUSB_TRANSFER_OVERFLOW:
+ case LIBUSB_TRANSFER_NO_DEVICE:
+ if ((endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT)
+ rv = ICOM_USBW;
+ else
+ rv = ICOM_USBR;
+ break;
+ case LIBUSB_TRANSFER_CANCELLED:
+ rv = ICOM_CANC;
+ break;
+ default:
+ a1loge(p->log, ICOM_SYS, "do_sync_usb_transfer: transfer faile with %d (%s)\n",rv,USB_STRERROR(rv));
+ rv = ICOM_SYS;
+ }
+
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = NULL;
+ usb_unlock_cancel(cancelt);
+ }
+ libusb_free_transfer(transfer);
+
+ /* requested size wasn't transferred */
+ if (rv == ICOM_OK && *transferred != length)
+ rv = ICOM_SHORT;
+
+ return rv;
+}
+#endif /* USE_LIBUSB1 */
+
+/* Return icom error code */
+static int icoms_usb_control_msg(
+icoms *p,
+int *transferred,
+int requesttype, int request,
+int value, int index, unsigned char *bytes, int size,
+int timeout) {
+ int rv;
+
+ in_usb_rw++;
+ a1logd(p->log, 8, "icoms_usb_control_msg: type 0x%x, req 0x%x, size %d\n",requesttype,request,size);
+
+ if (transferred != NULL)
+ *transferred = 0;
+#ifdef USE_LIBUSB1
+ rv = libusb_control_transfer(p->usbh, (uint8_t)requesttype, (uint8_t)request,
+ (uint16_t)value, (uint16_t)index, bytes, (uint16_t)size, timeout);
+#else
+ rv = usb_control_msg(p->usbh, requesttype, request, value, index, (char *)bytes, size, timeout);
+#endif
+ if (in_usb_rw < 0) /* interrupt recurssion */
+ exit(0);
+
+ in_usb_rw--;
+
+ if (rv < 0) {
+ if (rv == USBIO_ERROR_TIMEOUT) { /* Not a timeout */
+ rv = ICOM_TO;
+ } else {
+ if (requesttype & IUSB_ENDPOINT_IN) /* Device to host */
+ rv = ICOM_USBR; /* Read error */
+ else
+ rv = ICOM_USBW; /* Write error */
+ }
+ } else {
+ if (transferred != NULL)
+ *transferred = rv;
+ if (rv != size) {
+ rv = ICOM_SHORT;
+ } else
+ rv = ICOM_OK;
+ }
+ a1logd(p->log, 8, "icoms_usb_control_msg: returning err 0x%x and %d bytes\n",rv, *transferred);
+ return rv;
+}
+
+/* Our versions of usblib read/write, that exit if a signal was caught */
+/* This is so that MSWindows works properly */
+/* return an icom error */
+static int icoms_usb_transaction(icoms *p, usb_cancelt *cancelt, int *xbytes,
+ icom_usb_trantype type, int ep, unsigned char *bytes, int size, int timeout) {
+ int rv;
+
+ in_usb_rw++;
+
+ a1logd(p->log, 8, "coms_usb_transaction: req type 0x%x ep 0x%x size %d\n",type,ep,size);
+#ifdef USE_LIBUSB1
+ rv = do_sync_usb_transfer(p, p->usbh, cancelt, xbytes, type,
+ (unsigned char)ep, bytes, size, timeout);
+#else
+ if (xbytes != NULL)
+ *xbytes = 0;
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *) CASTFIX ep;
+ usb_lock_cancel(cancelt);
+ }
+ if (type == icom_usb_trantype_interrutpt) {
+ if ((ep & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT)
+ rv = usb_interrupt_write(p->usbh, ep, (char *)bytes, size, timeout);
+ else
+ rv = usb_interrupt_read(p->usbh, ep, (char *)bytes, size, timeout);
+ } else { /* bulk */
+ if ((ep & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT)
+ rv = usb_bulk_write(p->usbh, ep, (char *)bytes, size, timeout);
+ else
+ rv = usb_bulk_read(p->usbh, ep, (char *)bytes, size, timeout);
+ }
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *)-1;
+ usb_lock_cancel(cancelt);
+ }
+ if (rv < 0) {
+ if (rv == USBIO_ERROR_TIMEOUT)
+ rv = ICOM_TO;
+ else {
+ if ((ep & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT)
+ rv = ICOM_USBW;
+ else
+ rv = ICOM_USBR;
+ }
+ } else {
+ if (xbytes != NULL)
+ *xbytes = rv;
+ if (rv != *xbytes)
+ rv = ICOM_SHORT;
+ else
+ rv = ICOM_OK;
+ }
+#endif
+ if (in_usb_rw < 0) /* Signal handler recursion error */
+ exit(0);
+
+ in_usb_rw--;
+
+ a1logd(p->log, 8, "coms_usb_transaction: returning err 0x%x and %d bytes\n",rv, *xbytes);
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Cancel i/o in another thread */
+int icoms_usb_cancel_io(
+ icoms *p,
+ usb_cancelt *cancelt
+) {
+ int rv = 0;
+ usb_lock_cancel(cancelt);
+#ifdef USE_LIBUSB1
+ if (cancelt->hcancel != NULL) {
+ rv = libusb_cancel_transfer((struct libusb_transfer *)cancelt->hcancel);
+ if (rv == LIBUSB_ERROR_NOT_FOUND)
+ rv = 0;
+ }
+#else
+ if ((int) CASTFIX cancelt->hcancel >= 0) {
+// msec_sleep(1); /* Let device recover ? */
+ rv = usb_resetep(p->usbh, (int) CASTFIX cancelt->hcancel); /* Not reliable ? */
+// msec_sleep(1); /* Let device recover ? */
+ }
+#endif
+ usb_unlock_cancel(cancelt);
+
+ if (rv == 0)
+ return ICOM_OK;
+
+ a1logd(p->log, 1, "icoms_usb_cancel_io: failed with %d (%s)\n", rv,USB_STRERROR(rv));
+ return ICOM_SYS;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Reset and end point data toggle to 0 */
+int icoms_usb_resetep(
+ icoms *p,
+ int ep /* End point address */
+) {
+ int rv;
+#ifdef USE_LIBUSB1
+ rv = libusb_resetep(p->usbh, (unsigned char)ep); /* Is this the same though ? */
+#else
+ rv = usb_resetep(p->usbh, ep); /* Not reliable ? */
+#endif
+
+ if (rv == 0)
+ return ICOM_OK;
+
+ a1logd(p->log, 1, "icoms_usb_resetep: failed with %d (%s)\n", rv,USB_STRERROR(rv));
+ return ICOM_USBW;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Clear a halt on an end point */
+int icoms_usb_clearhalt(
+ icoms *p,
+ int ep /* End point address */
+) {
+ int rv;
+#ifdef USE_LIBUSB1
+ rv = libusb_clear_halt(p->usbh, (unsigned char)ep);
+#else
+ rv = usb_clear_halt(p->usbh, ep);
+#endif
+
+ if (rv == 0)
+ return ICOM_OK;
+
+ a1logd(p->log, 1, "icoms_usb_clearhalt: failed with %d (%s)\n", rv,USB_STRERROR(rv));
+ return ICOM_USBW;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+
diff --git a/spectro/usbio_lx.c b/spectro/usbio_lx.c
new file mode 100644
index 0000000..359f483
--- /dev/null
+++ b/spectro/usbio_lx.c
@@ -0,0 +1,1069 @@
+
+/* General USB I/O support, Linux native implementation. */
+/* ("libusbx ? We don't need no stinking libusbx..." :-) */
+/* This file is conditionaly #included into usbio.c */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/22/4
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/usbdevice_fs.h>
+
+/* select() defined, but not poll(), so emulate poll() */
+#if defined(FD_CLR) && !defined(POLLIN)
+#include "pollem.h"
+#define poll_x pollem
+#else
+#include <sys/poll.h> /* Else assume poll() is native */
+#define poll_x poll
+#endif
+
+/* USB descriptors are little endian */
+
+/* Take a word sized return buffer, and convert it to an unsigned int */
+static unsigned int buf2uint(unsigned char *buf) {
+ unsigned int val;
+ val = buf[3];
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a short sized return buffer, and convert it to an int */
+static unsigned int buf2ushort(unsigned char *buf) {
+ unsigned int val;
+ val = buf[1];
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take an int, and convert it into a byte buffer */
+static void int2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+ buf[2] = (inv >> 16) & 0xff;
+ buf[3] = (inv >> 24) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer */
+static void short2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+}
+
+
+/* Check a USB Vendor and product ID by reading the device descriptors, */
+/* and add the device to the icoms path if it is supported. */
+/* Return icom nz error code on fatal error */
+int usb_check_and_add_fd(
+a1log *log,
+icompaths *pp, /* icompaths to add to, or if NULL */
+icompath *p, /* icompath to set. */
+char *dpath, /* path to device - may be NULL */
+int fd /* device file descriptor */
+) {
+ int rv;
+ unsigned char buf[IUSB_DESC_TYPE_DEVICE_SIZE];
+ unsigned vid, pid, nep10 = 0xffff;
+ unsigned int configix, nconfig, totlen;
+ instType itype;
+ struct usb_idevice *usbd = NULL;
+
+ a1logd(log, 6, "usb_check_and_add_fd: with fd %d\n",fd);
+
+ /* Read the device descriptor */
+ if ((rv = read(fd, buf, IUSB_DESC_TYPE_DEVICE_SIZE)) < 0
+ || rv != IUSB_DESC_TYPE_DEVICE_SIZE
+ || buf[0] != IUSB_DESC_TYPE_DEVICE_SIZE
+ || buf[1] != IUSB_DESC_TYPE_DEVICE) {
+ a1logd(log, 1, "usb_check_and_add: failed to read device descriptor\n");
+ return ICOM_OK;
+ }
+
+ /* Extract the vid and pid */
+ vid = buf2ushort(buf + 8);
+ pid = buf2ushort(buf + 10);
+ nconfig = buf[17];
+
+ a1logd(log, 6, "usb_check_and_add: checking vid 0x%04x, pid 0x%04x\n",vid,pid);
+
+ /* Do a preliminary match */
+ if ((itype = inst_usb_match(vid, pid, 0)) == instUnknown) {
+ a1logd(log, 6 , "usb_check_and_add: instrument not reconized\n");
+ return ICOM_OK;
+ }
+
+ /* Allocate an idevice so that we can fill in the end point information */
+ if ((usbd = (struct usb_idevice *) calloc(sizeof(struct usb_idevice), 1)) == NULL) {
+ a1loge(log, ICOM_SYS, "icoms: calloc failed!\n");
+ return ICOM_SYS;
+ }
+
+ usbd->nconfig = nconfig;
+
+ /* Read the configuration descriptors looking for the first configuration, first interface, */
+ /* and extract the number of end points */
+ for (configix = 0; configix < nconfig; configix++) {
+ int configno;
+ unsigned int ninfaces, inface, nep;
+ unsigned char *buf2, *bp, *zp;
+
+ /* Read the first 4 bytes to get the type and size */
+ if ((rv = read(fd, buf, 4)) < 0
+ || rv != 4
+ || buf[1] != IUSB_DESC_TYPE_CONFIG) {
+ a1logd(log, 1, "usb_check_and_add: failed to read device config\n");
+ free(usbd);
+ return ICOM_OK;
+ }
+
+ if ((totlen = buf2ushort(buf + 2)) < 6) {
+ a1logd(log, 1, "usb_check_and_add: config desc size strange\n");
+ free(usbd);
+ return ICOM_OK;;
+ }
+ if ((buf2 = calloc(1, totlen)) == NULL) {
+ a1loge(log, ICOM_SYS, "usb_check_and_add: calloc of descriptor failed!\n");
+ return ICOM_SYS;
+ }
+
+ memcpy(buf2, buf, 4); /* First 4 bytes read */
+ if ((rv = read(fd, buf2 + 4, totlen - 4)) < 0 /* Read the remainder */
+ || rv != (totlen - 4)) {
+ a1logd(log, 1, "usb_check_and_add: failed to read device config details\n");
+ free(buf2);
+ free(usbd);
+ return ICOM_SYS;
+ }
+
+ bp = buf2 + buf2[0]; /* Skip coniguration tag */
+ zp = buf2 + totlen; /* Past last bytes */
+
+ /* We are at the first configuration. */
+ /* Just read tags and keep track of where we are */
+ ninfaces = 0;
+ nep = 0;
+ usbd->nifce = buf2[4]; /* number of interfaces */
+ usbd->config = configno = buf2[5]; /* current configuration */
+ for (;bp < zp; bp += bp[0]) {
+ int ifaceno;
+ if ((bp + 1) >= zp)
+ break; /* Hmm - bodgy, give up */
+ if (bp[1] == IUSB_DESC_TYPE_INTERFACE) {
+ ninfaces++;
+ if ((bp + 2) >= zp)
+ break; /* Hmm - bodgy, give up */
+ ifaceno = bp[2]; /* Get bInterfaceNumber */
+ } else if (bp[1] == IUSB_DESC_TYPE_ENDPOINT) {
+ nep++;
+ if ((bp + 5) >= zp)
+ break; /* Hmm - bodgy */
+ /* At first config - */
+ /* record current nep and end point details */
+ if (configno == 1) {
+ int ad = bp[2];
+ nep10 = nep;
+ usbd->EPINFO(ad).valid = 1;
+ usbd->EPINFO(ad).addr = ad;
+ usbd->EPINFO(ad).packetsize = buf2ushort(bp + 4);
+ usbd->EPINFO(ad).type = bp[3] & IUSB_ENDPOINT_TYPE_MASK;
+ usbd->EPINFO(ad).interface = ifaceno;
+ a1logd(log, 6, "set ep ad 0x%x packetsize %d type %d\n",ad,usbd->EPINFO(ad).packetsize,usbd->EPINFO(ad).type);
+ }
+ }
+ /* Ignore other tags */
+ }
+ free(buf2);
+ }
+ if (nep10 == 0xffff) { /* Hmm. Failed to find number of end points */
+ a1logd(log, 1, "usb_check_and_add: failed to find number of end points\n");
+ free(usbd);
+ return ICOM_SYS;
+ }
+
+ a1logd(log, 6, "usb_check_and_add: found nep10 %d\n",nep10);
+
+ /* Found a known instrument ? */
+ if ((itype = inst_usb_match(vid, pid, nep10)) != instUnknown) {
+ char pname[400];
+
+ a1logd(log, 2, "usb_check_and_add: found instrument vid 0x%04x, pid 0x%04x\n",vid,pid);
+
+ /* Create a path/identification */
+ /* (devnum doesn't seem valid ?) */
+ if (dpath == NULL) {
+ sprintf(pname,"%s", inst_name(itype));
+ if ((usbd->dpath = strdup("no_path")) == NULL) {
+ a1loge(log, ICOM_SYS, "usb_check_and_add: strdup path failed!\n");
+ free(usbd);
+ return ICOM_SYS;
+ }
+ } else {
+ sprintf(pname,"%s (%s)", dpath, inst_name(itype));
+ if ((usbd->dpath = strdup(dpath)) == NULL) {
+ a1loge(log, ICOM_SYS, "usb_check_and_add: strdup path failed!\n");
+ free(usbd);
+ return ICOM_SYS;
+ }
+ }
+
+ /* Add the path and ep info to the list */
+ if (pp != NULL) {
+ if ((rv = pp->add_usb(pp, pname, vid, pid, nep10, usbd, itype)) != ICOM_OK)
+ return rv;
+ } else {
+ usbd->fd = fd;
+ if ((rv = icompath_set_usb(log, p, pname, vid, pid, nep10, usbd, itype)) != ICOM_OK)
+ return rv;
+ }
+ } else {
+ free(usbd);
+ }
+ return ICOM_OK;
+}
+
+/* Same as above, starting with the path */
+static int usb_check_and_add(
+icompaths *p,
+char *dpath
+) {
+ int fd;
+ int rv;
+
+ a1logd(p->log, 6, "usb_check_and_add: givem '%s'\n",dpath);
+
+ /* Open the device so that we can read it */
+ if ((fd = open(dpath, O_RDONLY)) < 0) {
+ a1logd(p->log, 1, "usb_check_and_add: failed to open '%s'\n",dpath);
+ return ICOM_OK;
+ }
+
+ rv = usb_check_and_add_fd(p->log, p, NULL, dpath, fd);
+
+ close(fd);
+ return rv;
+}
+
+/* Add paths to USB connected instruments */
+/* Return an icom error */
+int usb_get_paths(
+icompaths *p
+) {
+ int vid, pid;
+
+ a1logd(p->log, 6, "usb_get_paths: about to look through buses:\n");
+
+ {
+ int j;
+ char *paths[3] = { "/dev/bus/usb", /* current, from udev */
+ "/proc/bus/usb", /* old, deprecated */
+ "/dev" }; /* CONFIG_USB_DEVICE_CLASS, embeded, deprecated ? */
+
+ /* See what device names to look for */
+ for (j = 0; j < 3; j++) {
+ DIR *d1;
+ struct dirent *e1;
+ int rv, found = 0;
+
+ if ((d1 = opendir(paths[j])) == NULL)
+ continue;
+
+ while ((e1 = readdir(d1)) != NULL) {
+ if (e1->d_name[0] == '.')
+ continue;
+ found = 1;
+ if (j < 2) { /* Directory structure */
+ char path1[PATH_MAX];
+ char path2[PATH_MAX];
+ DIR *d2;
+ struct dirent *e2;
+ struct stat statbuf;
+
+ snprintf(path1, PATH_MAX, "%s/%s", paths[j], e1->d_name);
+
+ if ((d2 = opendir(path1)) == NULL)
+ continue;
+ while ((e2 = readdir(d2)) != NULL) {
+ if (e2->d_name[0] == '.')
+ continue;
+
+ snprintf(path2, PATH_MAX, "%s/%s/%s", paths[j], e1->d_name, e2->d_name);
+ a1logd(p->log, 8, "usb_get_paths: about to stat %s\n",path2);
+ if (stat(path2, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
+ found = 1;
+ if ((rv = usb_check_and_add(p, path2)) != ICOM_OK) {
+ closedir(d1);
+ return rv;
+ }
+ }
+ }
+ closedir(d2);
+ } else { /* Flat */
+ char path2[PATH_MAX];
+ struct stat statbuf;
+
+ /* Hmm. This will go badly wrong if this is a /dev/usbdev%d.%d_ep%d, */
+ /* since we're not expecting the end points to be separate devices. */
+ /* Maybe that's deprectated though... */
+ snprintf(path2, PATH_MAX, "%s/%s", paths[j], e1->d_name);
+ a1logd(p->log, 8, "usb_get_paths: about to stat %s\n",path2);
+ if (stat(path2, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
+ found = 1;
+ if ((rv = usb_check_and_add(p, path2)) != ICOM_OK) {
+ closedir(d1);
+ return rv;
+ }
+ }
+ }
+ }
+ closedir(d1);
+ if (found)
+ break;
+ }
+ }
+
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ return ICOM_OK;
+}
+
+
+/* Copy usb_idevice contents from icompaths to icom */
+/* return icom error */
+int usb_copy_usb_idevice(icoms *d, icompath *s) {
+ int i;
+ if (s->usbd == NULL) {
+ d->usbd = NULL;
+ return ICOM_OK;
+ }
+ if ((d->usbd = calloc(sizeof(struct usb_idevice), 1)) == NULL) {
+ a1loge(d->log, ICOM_SYS, "usb_copy_usb_idevice: malloc\n");
+ return ICOM_SYS;
+ }
+ if ((d->usbd->dpath = strdup(s->usbd->dpath)) == NULL) {
+ a1loge(d->log, ICOM_SYS, "usb_copy_usb_idevice: malloc\n");
+ return ICOM_SYS;
+ }
+ /* Copy the ep info */
+ d->nconfig = s->usbd->nconfig;
+ d->nifce = s->usbd->nifce;
+ d->config = s->usbd->config;
+ for (i = 0; i < 32; i++)
+ d->ep[i] = s->usbd->ep[i]; /* Struct copy */
+ return ICOM_OK;
+}
+
+/* Cleanup and then free a usb dev entry */
+void usb_del_usb_idevice(struct usb_idevice *usbd) {
+
+ if (usbd == NULL)
+ return;
+
+ if (usbd->dpath != NULL)
+ free(usbd->dpath);
+ free(usbd);
+}
+
+/* Cleanup any USB specific icoms state */
+void usb_del_usb(icoms *p) {
+
+ usb_del_usb_idevice(p->usbd);
+}
+
+/* Close an open USB port */
+/* If we don't do this, the port and/or the device may be left in an unusable state. */
+void usb_close_port(icoms *p) {
+
+ a1logd(p->log, 6, "usb_close_port: called\n");
+
+ if (p->is_open && p->usbd != NULL) {
+ struct usbdevfs_urb urb;
+ unsigned char buf[8+IUSB_DESC_TYPE_DEVICE_SIZE];
+ int iface, rv;
+
+ /* Release all the interfaces */
+ for (iface = 0; iface < p->nifce; iface++)
+ ioctl(p->usbd->fd, USBDEVFS_RELEASEINTERFACE, &iface);
+
+ /* Workaround for some bugs - reset device on close */
+ if (p->uflags & icomuf_reset_before_close) {
+ if ((rv = ioctl(p->usbd->fd, USBDEVFS_RESET, NULL)) != 0) {
+ a1logd(p->log, 1, "usb_close_port: reset returned %d\n",rv);
+ }
+ }
+
+ if (p->usbd->running) { /* If reaper is still running */
+ unsigned char buf[1] = { 0 };
+
+ a1logd(p->log, 6, "usb_close_port: waking reaper thread to trigger exit\n");
+ p->usbd->shutdown = 1;
+
+ if (write(p->usbd->sd_pipe[1], buf, 1) < 1) {
+ a1logd(p->log, 1, "usb_close_port: writing to sd_pipe failed with '%s'\n", strerror(errno));
+ /* Hmm. We could be in trouble ? */
+ }
+ }
+ a1logd(p->log, 6, "usb_close_port: waiting for reaper thread\n");
+ pthread_join(p->usbd->thread, NULL); /* Wait for urb reaper thread to exit */
+ close(p->usbd->fd);
+ pthread_mutex_destroy(&p->usbd->lock);
+ close(p->usbd->sd_pipe[0]);
+ close(p->usbd->sd_pipe[1]);
+ free(p->usbd->dpath);
+ free(p->usbd);
+ p->usbd = NULL;
+
+ a1logd(p->log, 6, "usb_close_port: usb port has been released and closed\n");
+ }
+ p->is_open = 0;
+
+ /* Find it and delete it from our static cleanup list */
+ usb_delete_from_cleanup_list(p);
+}
+
+static void *urb_reaper(void *context); /* Declare */
+
+/* Open a USB port for all our uses. */
+/* This always re-opens the port */
+/* return icom error */
+static int usb_open_port(
+icoms *p,
+int config, /* Configuration number */
+int wr_ep, /* Write end point */
+int rd_ep, /* Read end point */
+icomuflags usbflags,/* Any special handling flags */
+int retries, /* > 0 if we should retry set_configuration (100msec) */
+char **pnames /* List of process names to try and kill before opening */
+) {
+ int rv, tries = 0;
+ a1logd(p->log, 8, "usb_open_port: Make sure USB port is open, tries %d\n",retries);
+
+ if (p->is_open)
+ p->close_port(p);
+
+ /* Make sure the port is open */
+ if (!p->is_open) {
+ int rv, i, iface;
+ kkill_nproc_ctx *kpc = NULL;
+
+ if (config != 1) {
+ /* Nothing currently needs it, so we haven't implemented it yet... */
+ a1loge(p->log, ICOM_NOTS, "usb_open_port: native driver cant handle config %d\n",config);
+ return ICOM_NOTS;
+ }
+
+ /* Do open retries */
+ for (tries = 0; retries >= 0; retries--, tries++) {
+
+ a1logd(p->log, 8, "usb_open_port: About to open USB port '%s'\n",p->usbd->dpath);
+
+ if (tries > 0) {
+ //msec_sleep(i_rand(50,100));
+ msec_sleep(77);
+ }
+
+ if ((rv = p->usbd->fd = open(p->usbd->dpath, O_RDWR)) < 0) {
+ a1logd(p->log, 8, "usb_open_port: open '%s' config %d failed (%d) (Permissions ?)\n",p->usbd->dpath,config,rv);
+ if (retries <= 0) {
+ if (kpc != NULL)
+ kpc->del(kpc);
+ a1loge(p->log, ICOM_SYS, "usb_open_port: open '%s' config %d failed (%d) (Permissions ?)\n",p->usbd->dpath,config,rv);
+ return ICOM_SYS;
+ }
+ continue;
+ } else if (p->debug)
+ a1logd(p->log, 2, "usb_open_port: open port '%s' succeeded\n",p->usbd->dpath);
+
+ p->uflags = usbflags;
+
+ /* We should only do a set configuration if the device has more than one */
+ /* possible configuration and it is currently not the desired configuration, */
+ /* but we should avoid doing a set configuration if the OS has already */
+ /* selected the configuration we want, since two set configs seem to */
+ /* mess up the Spyder2, BUT we can't do a get config because this */
+ /* messes up the i1pro-D. */
+
+ /* Linux set_configuration(1) by default, so we don't need to do anything */
+ p->cconfig = 1;
+
+ if (p->cconfig != config) {
+ if ((rv = ioctl(p->usbd->fd, USBDEVFS_SETCONFIGURATION, &config)) != 0) {
+ a1logd(p->log, 1, "icoms_usb_setconfig failed with %d\n",rv);
+ return ICOM_SYS;
+ }
+ p->cconfig = config;
+ a1logd(p->log, 6, "usb_open_port: set config %d OK\n",config);
+ }
+
+ /* We're done */
+ break;
+ }
+
+ if (kpc != NULL)
+ kpc->del(kpc);
+
+ /* Claim all the interfaces */
+ for (iface = 0; iface < p->nifce; iface++) {
+
+ if ((rv = ioctl(p->usbd->fd, USBDEVFS_CLAIMINTERFACE, &iface)) < 0) {
+ struct usbdevfs_getdriver getd;
+ getd.interface = iface;
+
+ a1logd(p->log, 1, "usb_open_port: Claiming USB port '%s' interface %d initally failed with %d\n",p->usbd->dpath,iface,rv);
+
+ /* Detatch the existing interface if kernel driver is active. */
+ if (p->uflags & icomuf_detach
+ && ioctl(p->usbd->fd, USBDEVFS_GETDRIVER, &getd) == 0) {
+ struct usbdevfs_ioctl cmd;
+ a1logd(p->log, 1, "usb_open_port: Attempting kernel detach\n");
+ cmd.ifno = iface;
+ cmd.ioctl_code = USBDEVFS_DISCONNECT;
+ cmd.data = NULL;
+ ioctl(p->usbd->fd, USBDEVFS_IOCTL, &cmd);
+ if ((rv = ioctl(p->usbd->fd, USBDEVFS_CLAIMINTERFACE, &iface)) < 0) {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: Claiming USB port '%s' interface %d failed after detach with %d\n",p->usbd->dpath,iface,rv);
+ return ICOM_SYS;
+ }
+ } else {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: Claiming USB port '%s' interface %d failed with %d\n",p->usbd->dpath,iface,rv);
+ return ICOM_SYS;
+ }
+ }
+ }
+
+ /* Clear any errors. */
+ /* (Some I/F seem to hang if we do this, some seem to hang if we don't !) */
+ /* The ColorMunki on Linux only starts every second time if we don't do this. */
+ if (!(p->uflags & icomuf_no_open_clear)) {
+ for (i = 0; i < 32; i++) {
+ if (!p->ep[i].valid)
+ continue;
+ p->usb_clearhalt(p, p->ep[i].addr);
+ }
+ }
+
+ /* Set "serial" coms values */
+ p->wr_ep = wr_ep;
+ p->rd_ep = rd_ep;
+ p->rd_qa = p->EPINFO(rd_ep).packetsize;
+ if (p->rd_qa == 0)
+ p->rd_qa = 8;
+ a1logd(p->log, 8, "usb_open_port: 'serial' read quanta = packet size = %d\n",p->rd_qa);
+
+ /* Start the reaper thread to handle URB completions */
+ if ((rv = pipe(p->usbd->sd_pipe)) < 0) {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: creat pipe failed with %d\n",rv);
+ return ICOM_SYS;
+ }
+ pthread_mutex_init(&p->usbd->lock, NULL);
+
+ p->usbd->running = 1;
+ if ((rv = pthread_create(&p->usbd->thread, NULL, urb_reaper, (void*)p)) < 0) {
+ p->usbd->running = 0;
+ a1loge(p->log, ICOM_SYS, "usb_open_port: creating urb reaper thread failed with %s\n",rv);
+ return ICOM_SYS;
+ }
+
+ p->is_open = 1;
+ a1logd(p->log, 8, "usb_open_port: USB port is now open\n");
+ }
+
+ /* Install the cleanup signal handlers, and add to our cleanup list */
+ usb_install_signal_handlers(p);
+
+ return ICOM_OK;
+}
+
+/* -------------------------------------------------------------- */
+/* I/O structures */
+
+/* an icoms urb */
+typedef struct {
+ struct _usbio_req *req; /* Request we're part of */
+ int urbno; /* urb index within request */
+ struct usbdevfs_urb urb; /* Linux urb */
+} usbio_urb;
+
+/* an i/o request */
+typedef struct _usbio_req {
+
+ int nurbs; /* Number of urbs in urbs[] */
+ usbio_urb *urbs; /* Allocated */
+ volatile int nourbs; /* Number of outstanding urbs, 0 when done */
+ int cancelled; /* All the URB's have been cancelled */
+
+ pthread_mutex_t lock; /* Protect req & reaper access */
+ pthread_cond_t cond; /* Signal to thread waiting on req */
+
+ struct _usbio_req *next; /* Link to next in list */
+} usbio_req;
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+
+/* Cancel a req's urbs from the last down to but not including thisurb. */
+/* return icom error */
+static int cancel_req(icoms *p, usbio_req *req, int thisurb) {
+ int i, rv = ICOM_OK;
+ for (i = req->nurbs-1; i > thisurb; i--) {
+ int ev;
+ // ~~99 can we skip done, errored or cancelled urbs ?
+ // Does it matter if there is a race between cancellers ? */
+ a1logd(p->log, 7, "cancel_req %d\n",i);
+ 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);
+ rv = ICOM_SYS;
+ }
+ req->urbs[i].urb.status = -ECONNRESET;
+ }
+ req->cancelled = 1; /* Don't cancel it again */
+ return ICOM_OK;
+}
+
+/* The reaper thread */
+static void *urb_reaper(void *context) {
+ icoms *p = (icoms *)context;
+ struct usbdevfs_urb *out = NULL;
+ int errc = 0;
+ int rv;
+ struct pollfd pa[2]; /* Poll array to monitor urb result or shutdown */
+
+ a1logd(p->log, 6, "urb_reaper: reap starting\n");
+
+ /* Wait for a URB, and signal the requester */
+ for (;;) {
+ usbio_urb *iurb;
+ usbio_req *req;
+
+ /* Setup to wait for serial output not block */
+ pa[0].fd = p->usbd->fd;
+ pa[0].events = POLLIN | POLLOUT;
+ pa[0].revents = 0;
+
+ pa[1].fd = p->usbd->sd_pipe[0];
+ pa[1].events = POLLIN;
+ pa[1].revents = 0;
+
+ /* Wait for fd to become ready or shutdown */
+ if ((rv = poll_x(pa, 2, -1)) < 0 || pa[1].revents || pa[0].revents == 0) {
+ a1logd(p->log, 6, "urb_reaper: poll returned %d and events %d %d\n",rv,pa[0].revents,pa[1].revents);
+ p->usbd->shutdown = 1;
+ break;
+ }
+
+ /* Not sure what this returns if there is nothing there */
+ rv = ioctl(p->usbd->fd, USBDEVFS_REAPURBNDELAY, &out);
+
+ if (rv < 0) {
+ a1logd(p->log, 2, "urb_reaper: reap failed with %d\n",rv);
+ if (errc++ < 5) {
+ continue;
+ }
+ p->usbd->shutdown = 1;
+ break;
+ }
+
+ errc = 0;
+
+ if (out == NULL) {
+ a1logd(p->log, 2, "urb_reaper: reap returned NULL URB\n");
+ continue;
+ }
+
+ /* Normal reap */
+ iurb = (usbio_urb *)out->usercontext;
+ req = iurb->req;
+
+ a1logd(p->log, 8, "urb_reaper: urb reap URB %d with status %d bytes %d, usrbs left %d\n",iurb->urbno, out->status, out->actual_length, req->nourbs-1);
+
+ pthread_mutex_lock(&req->lock); /* Stop requester from missing reap */
+ req->nourbs--; /* We're reaped one */
+
+ /* 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->status < 0 && out->status != -ECONNRESET))) {
+ a1logd(p->log, 6, "urb_reaper: reaper canceling failed or done urb's\n",rv);
+ if (cancel_req(p, req, iurb->urbno) != ICOM_OK) {
+ pthread_mutex_unlock(&req->lock);
+ /* Is this fatal ? Assume so for the moment ... */
+ break;
+ }
+ }
+ if (req->nourbs <= 0) /* Signal the requesting thread that we're done */
+ pthread_cond_signal(&req->cond);
+ pthread_mutex_unlock(&req->lock);
+ }
+
+ /* Clean up */
+ if (p->usbd->shutdown) {
+ usbio_req *req;
+
+ a1logd(p->log, 8, "urb_reaper: shutdown or too many failure\n");
+
+ /* Signal that any request should give up, and that the */
+ /* reaper thread is going to exit */
+ p->usbd->running = 0;
+
+ /* Go through the outstanding request list, and */
+ /* mark them as failed and signal them all */
+ pthread_mutex_lock(&p->usbd->lock);
+ req = p->usbd->reqs;
+ while(req != NULL) {
+ int i;
+
+ pthread_mutex_lock(&req->lock);
+ for (i = req->nourbs-1; i >= 0; i--) {
+ req->urbs[i].urb.status = ICOM_SYS;
+ }
+ req->nourbs = 0;
+ pthread_cond_signal(&req->cond);
+ pthread_mutex_unlock(&req->lock);
+ req = req->next;
+ }
+ pthread_mutex_unlock(&p->usbd->lock);
+ a1logd(p->log, 1, "urb_reaper: cleared requests\n");
+ }
+ p->usbd->running = 0;
+
+ a1logd(p->log, 6, "urb_reaper: thread done\n");
+ return NULL;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Our universal USB transfer function */
+static int icoms_usb_transaction(
+ icoms *p,
+ usb_cancelt *cancelt,
+ int *transferred,
+ icom_usb_trantype ttype, /* transfer type */
+ unsigned char endpoint, /* 0x80 for control write, 0x00 for control read */
+ unsigned char *buffer,
+ int length,
+ unsigned int timeout /* In msec */
+) {
+ int reqrv = ICOM_OK, rv = 0;
+ usbio_req req, **preq;
+ int type;
+ int remlen;
+ unsigned char *bp;
+ int xlength = 0;
+ int i;
+
+ in_usb_rw++;
+ a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d\n",ttype,endpoint,length);
+
+ if (!p->usbd->running) {
+ in_usb_rw--;
+ a1logv(p->log, 1, "icoms_usb_transaction: reaper thread is not running\n");
+ return ICOM_SYS;
+ }
+
+ /* Translate icoms transfer type of Linux */
+ switch (ttype) {
+ case icom_usb_trantype_command:
+ type = USBDEVFS_URB_TYPE_CONTROL;
+ break;
+ case icom_usb_trantype_interrutpt:
+ type = USBDEVFS_URB_TYPE_INTERRUPT;
+ break;
+ case icom_usb_trantype_bulk:
+ type = USBDEVFS_URB_TYPE_BULK;
+ break;
+ }
+
+ /* Setup the icom req and urbs */
+ req.urbs = NULL;
+ pthread_mutex_init(&req.lock, NULL);
+ pthread_cond_init(&req.cond, NULL);
+
+ /* Linux historically only copes with 16384 length urbs, */
+ /* so break up longer requests into multiple urbs */
+
+ req.cancelled = 0;
+ req.nourbs = req.nurbs = (length + (1 << 14)-1) >> 14;
+ if ((req.urbs = (usbio_urb *)calloc(sizeof(usbio_urb), req.nourbs)) == NULL) {
+ in_usb_rw--;
+ a1loge(p->log, ICOM_SYS, "icoms_usb_transaction: control transfer too big! (%d)\n",length);
+ return ICOM_SYS;
+ }
+
+ bp = buffer;
+ remlen = length;
+ for (i = 0; i < req.nurbs; i++) {
+ req.urbs[i].req = &req;
+ req.urbs[i].urbno = i;
+ /* Setup Linux URB */
+ req.urbs[i].urb.usercontext = &req.urbs[i];
+ req.urbs[i].urb.type = type;
+ if (type != USBDEVFS_URB_TYPE_CONTROL)
+ req.urbs[i].urb.endpoint = endpoint;
+ if (remlen > 16384)
+ req.urbs[i].urb.buffer_length = 16384;
+ else
+ req.urbs[i].urb.buffer_length = remlen;
+ req.urbs[i].urb.buffer = (void *)bp;
+ remlen -= req.urbs[i].urb.buffer_length;
+ bp += req.urbs[i].urb.buffer_length;
+ req.urbs[i].urb.status = -EINPROGRESS;
+ }
+a1logd(p->log, 8, "icoms_usb_transaction: reset req 0x%p nourbs to %d\n",&req,req.nourbs);
+
+ /* Add our request to the req list so that it can be cancelled on reap failure */
+ pthread_mutex_lock(&p->usbd->lock);
+ req.next = p->usbd->reqs;
+ p->usbd->reqs = &req;
+ pthread_mutex_unlock(&p->usbd->lock);
+
+ /* submit the URBs */
+ for (i = 0; i < req.nurbs; i++) {
+ if ((rv = ioctl(p->usbd->fd, USBDEVFS_SUBMITURB, &req.urbs[i].urb)) < 0) {
+ a1logd(p->log, 1, "coms_usb_transaction: Submitting urb to fd %d failed with %d\n",p->usbd->fd, rv);
+ req.urbs[i].urb.status = ICOM_SYS; /* Mark it as failed to submit */
+ req.nourbs--;
+ }
+ }
+
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *)&req;
+ usb_unlock_cancel(cancelt);
+ }
+
+ /* Wait for the reaper to wake us, or for a timeout, */
+ /* or for the reaper to die. */
+ pthread_mutex_lock(&req.lock);
+ if (req.nourbs > 0) {
+ struct timeval tv;
+ struct timespec ts;
+
+ // this is unduly complicated...
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec + timeout/1000;
+ ts.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000L;
+ if (ts.tv_nsec > 1000000000L) {
+ ts.tv_nsec -= 1000000000L;
+ ts.tv_sec++;
+ }
+
+ for(;;) { /* Ignore spurious wakeups */
+ if ((rv = pthread_cond_timedwait(&req.cond, &req.lock, &ts)) != 0) {
+ if (rv != ETIMEDOUT) {
+ pthread_mutex_unlock(&req.lock);
+ a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_timedwait failed with %d\n",rv);
+ rv = ICOM_SYS;
+ goto done;
+ }
+
+ /* Timed out - cancel the remaining URB's */
+ a1logd(p->log, 8, "coms_usb_transaction: time out - cancel remaining URB's\n");
+ reqrv = ICOM_TO;
+ if (!req.cancelled && (rv = cancel_req(p, &req, -1)) != ICOM_OK) {
+ pthread_mutex_unlock(&req.lock);
+ reqrv = ICOM_SYS;
+ /* Since cancelling failed, we can't wait for them to be reaped */
+ goto done;
+ }
+
+ /* Wait for the cancelled URB's to be reaped */
+ for (;req.nourbs > 0;) { /* Ignore spurious wakeups */
+ if ((rv = pthread_cond_wait(&req.cond, &req.lock)) != 0) {
+ pthread_mutex_unlock(&req.lock);
+ a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_wait failed with %d\n",rv);
+ reqrv = ICOM_SYS;
+ /* Waiting for reap failed, so give up */
+ goto done;
+ }
+ }
+ } else {
+ a1logd(p->log, 8, "coms_usb_transaction: reap - %d left\n",req.nourbs);
+ }
+ if (req.nourbs <= 0)
+ break; /* All urbs's are done */
+ }
+ }
+ pthread_mutex_unlock(&req.lock);
+
+ /* Compute the overall result by going through the urbs. */
+ for (i = 0; i < req.nurbs; i++) {
+ int stat = req.urbs[i].urb.status;
+ xlength += req.urbs[i].urb.actual_length;
+
+ if (stat == ICOM_SYS) { /* Submit or cancel failed */
+ reqrv = ICOM_SYS;
+ } else if (reqrv == ICOM_OK && stat < 0 && stat != -ECONNRESET) { /* Error result */
+ if ((endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT)
+ reqrv = ICOM_USBW;
+ else
+ reqrv = ICOM_USBR;
+ } else if (reqrv == ICOM_OK && stat == -ECONNRESET) { /* Cancelled */
+ reqrv = ICOM_CANC;
+ } else if (reqrv == ICOM_OK
+ && req.urbs[i].urb.actual_length < req.urbs[i].urb.buffer_length) {
+ /* Disregard any following urb's status - they are probably cancelled */
+ break;
+ }
+ /* reqrv == ICOM_TO will ignore urb status */
+ }
+
+ if (ttype == icom_usb_trantype_command)
+ xlength += IUSB_REQ_HEADER_SIZE; /* Account for header - linux doesn't */
+
+ /* requested size wasn't transferred ? */
+ if (reqrv == ICOM_OK && xlength != length)
+ reqrv = ICOM_SHORT;
+
+ if (transferred != NULL)
+ *transferred = xlength;
+
+done:;
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *)NULL;
+ usb_unlock_cancel(cancelt);
+ }
+
+ /* Remove our request from the list */
+ pthread_mutex_lock(&p->usbd->lock);
+ preq = &p->usbd->reqs;
+ while (*preq != &req && *preq != NULL) /* Find it */
+ preq = &((*preq)->next);
+ if (*preq != NULL)
+ *preq = (*preq)->next;
+ pthread_mutex_unlock(&p->usbd->lock);
+
+ if (req.urbs != NULL)
+ free(req.urbs);
+ pthread_cond_destroy(&req.cond);
+ pthread_mutex_destroy(&req.lock);
+
+ if (in_usb_rw < 0)
+ exit(0);
+
+ in_usb_rw--;
+
+ a1logd(p->log, 8, "coms_usb_transaction: returning err 0x%x and %d bytes\n",reqrv, xlength);
+
+ return reqrv;
+}
+
+
+/* Return error icom error code */
+static int icoms_usb_control_msg(
+icoms *p,
+int *transferred,
+int requesttype, int request,
+int value, int index, unsigned char *bytes, int size,
+int timeout) {
+ int reqrv = ICOM_OK;
+ int dirw = (requesttype & IUSB_REQ_DIR_MASK) == IUSB_REQ_HOST_TO_DEV ? 1 : 0;
+ unsigned char *buf;
+
+ a1logd(p->log, 8, "icoms_usb_control_msg: type 0x%x req 0x%x size %d\n",requesttype,request,size);
+
+ /* Allocate a buffer for the ctrl header + payload */
+ if ((buf = calloc(1, IUSB_REQ_HEADER_SIZE + size)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_control_msg: calloc failed\n");
+ return ICOM_SYS;
+ }
+
+ /* Setup the control header */
+ buf[0] = requesttype;
+ buf[1] = request;
+ short2buf(buf + 2, value);
+ short2buf(buf + 4, index);
+ short2buf(buf + 6, size);
+
+ /* If it's a write, copy the write data into the buffer */
+ if (dirw)
+ memcpy(buf + IUSB_REQ_HEADER_SIZE, bytes, size);
+
+ reqrv = icoms_usb_transaction(p, NULL, transferred, icom_usb_trantype_command,
+ dirw ? 0x80 : 0x00, buf, IUSB_REQ_HEADER_SIZE + size, timeout);
+
+ /* If read, copy the data back */
+ if (!dirw)
+ memcpy(bytes, buf + IUSB_REQ_HEADER_SIZE, size);
+
+ if (transferred != NULL) /* Adjust for header size requested */
+ *transferred -= IUSB_REQ_HEADER_SIZE;
+
+ free(buf);
+
+ a1logd(p->log, 8, "icoms_usb_control_msg: returning err 0x%x and %d bytes\n",reqrv, *transferred);
+ return reqrv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Time out error return value */
+
+#define USBIO_ERROR_TIMEOUT -ETIMEDOUT
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Cancel i/o in another thread */
+int icoms_usb_cancel_io(
+ icoms *p,
+ usb_cancelt *cancelt
+) {
+ int rv = ICOM_OK;
+ a1logd(p->log, 8, "icoms_usb_cancel_io called\n");
+ usb_lock_cancel(cancelt);
+ if (cancelt->hcancel != NULL)
+ rv = cancel_req(p, (usbio_req *)cancelt->hcancel, -1);
+ usb_unlock_cancel(cancelt);
+
+ if (rv != ICOM_OK) /* Assume this could be because of faulty device */
+ rv = ICOM_USBW;
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Reset and end point data toggle to 0 */
+int icoms_usb_resetep(
+ icoms *p,
+ int ep /* End point address */
+) {
+ int rv = ICOM_OK;
+
+ if ((rv = ioctl(p->usbd->fd, USBDEVFS_RESETEP, &ep)) != 0) {
+ a1logd(p->log, 1, "icoms_usb_resetep failed with %d\n",rv);
+ rv = ICOM_USBW;
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Clear a halt on an end point */
+int icoms_usb_clearhalt(
+ icoms *p,
+ int ep /* End point address */
+) {
+ int rv = ICOM_OK;
+
+ if ((rv = ioctl(p->usbd->fd, USBDEVFS_CLEAR_HALT, &ep)) != 0) {
+ a1logd(p->log, 1, "icoms_usb_clearhalt failed with %d\n",rv);
+ rv = ICOM_USBW;
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+
diff --git a/spectro/usbio_nt.c b/spectro/usbio_nt.c
new file mode 100644
index 0000000..1711f0d
--- /dev/null
+++ b/spectro/usbio_nt.c
@@ -0,0 +1,898 @@
+
+/* General USB I/O support, MSWin native libusb0.sys implementation. */
+/* This file is conditionaly #included into usbio.c */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/22/4
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <windows.h>
+#include <winioctl.h>
+#include <setupapi.h>
+#include <driver_api.h>
+
+#define DEBUG /* Turn on debug messages */
+
+#define LIBUSBW1_MAX_DEVICES 255
+#define LIBUSBW1_PATH_MAX 512
+#define LIBUSBW1_DEFAULT_TIMEOUT 5000
+
+/* USB descriptors are little endian */
+
+/* Take a word sized return buffer, and convert it to an unsigned int */
+static unsigned int buf2uint(unsigned char *buf) {
+ unsigned int val;
+ val = buf[3];
+ val = ((val << 8) + (0xff & buf[2]));
+ val = ((val << 8) + (0xff & buf[1]));
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take a short sized return buffer, and convert it to an int */
+static unsigned int buf2ushort(unsigned char *buf) {
+ unsigned int val;
+ val = buf[1];
+ val = ((val << 8) + (0xff & buf[0]));
+ return val;
+}
+
+/* Take an int, and convert it into a byte buffer */
+static void int2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+ buf[2] = (inv >> 16) & 0xff;
+ buf[3] = (inv >> 24) & 0xff;
+}
+
+/* Take a short, and convert it into a byte buffer */
+static void short2buf(unsigned char *buf, int inv) {
+ buf[0] = (inv >> 0) & 0xff;
+ buf[1] = (inv >> 8) & 0xff;
+}
+
+/* Do a synchronous request. Return an ICOM error */
+static int do_sync_io(
+HANDLE handle,
+unsigned int ioctl,
+void *out, int outsz,
+void *in, int insz,
+int *retsz) {
+ OVERLAPPED olaps;
+ DWORD xlength;
+
+ memset(&olaps, 0, sizeof(OVERLAPPED));
+ if (retsz != NULL)
+ *retsz = 0;
+
+ if ((olaps.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
+ return ICOM_SYS;
+
+ if (!DeviceIoControl(handle, ioctl, out, outsz, in, insz, &xlength, &olaps)) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ CloseHandle(olaps.hEvent);
+ return ICOM_USBW;
+ }
+ if (!GetOverlappedResult(handle, &olaps, &xlength, TRUE)) {
+ CloseHandle(olaps.hEvent);
+ return ICOM_USBR;
+ }
+ }
+ CloseHandle(olaps.hEvent);
+ if (retsz != NULL)
+ *retsz = (int)xlength;
+
+ return ICOM_OK;
+}
+
+/* Add paths to USB connected instruments */
+/* Return an icom error */
+int usb_get_paths(
+icompaths *p
+) {
+ unsigned int vid, pid, nep10 = 0xffff;
+ unsigned int configix, nconfig, nifce;
+ instType itype;
+ struct usb_idevice *usbd = NULL;
+ int rv, retsz, i;
+
+ for (i = 0; i < LIBUSBW1_MAX_DEVICES; i++) {
+ libusb_request req;
+ char dpath[LIBUSBW1_PATH_MAX];
+ HANDLE handle;
+ unsigned char buf[IUSB_DESC_TYPE_DEVICE_SIZE];
+
+ _snprintf(dpath, LIBUSBW1_PATH_MAX - 1,"\\\\.\\libusb0-%04d", i+1);
+ a1logd(p->log, 6, "usb_get_paths opening device '%s'\n",dpath);
+
+ if ((handle = CreateFile(dpath, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
+ NULL)) == INVALID_HANDLE_VALUE) {
+#ifdef DEBUG
+ a1logd(p->log, 8, "usb_get_paths failed to open device '%s'\n",dpath);
+#endif
+ continue;
+ }
+
+ /* Set kernel message debug */
+ if (p->log->debug >= 6) {
+ req.debug.level = LIBUSB_DEBUG_MAX;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+ if (do_sync_io(handle, LIBUSB_IOCTL_SET_DEBUG_LEVEL,
+ &req, sizeof(libusb_request), NULL, 0, NULL)) {
+ a1logd(p->log, 1, "usb_get_paths: failed to set driver log leve\n");
+ } else {
+ a1logd(p->log, 1, "usb_get_paths: turned on kernel debug messages\n");
+ }
+ }
+
+ /* Read the device descriptor */
+ req.descriptor.type = IUSB_DESC_TYPE_DEVICE;
+ req.descriptor.recipient = IUSB_REQ_RECIP_DEVICE;
+ req.descriptor.index = 0;
+ req.descriptor.language_id = 0;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if (do_sync_io(handle, LIBUSB_IOCTL_GET_DESCRIPTOR,
+ &req, sizeof(libusb_request),
+ buf, IUSB_DESC_TYPE_DEVICE_SIZE, &retsz) != ICOM_OK
+ || retsz != IUSB_DESC_TYPE_DEVICE_SIZE) {
+ a1logd(p->log, 1, "usb_get_paths: failed to read device descriptor '%s'\n",dpath);
+ CloseHandle(handle);
+ continue;
+ }
+
+ /* Extract the vid and pid */
+ vid = buf2ushort(buf + 8);
+ pid = buf2ushort(buf + 10);
+ nconfig = buf[17];
+
+ a1logd(p->log, 6, "usb_get_paths: checking vid 0x%04x, pid 0x%04x\n",vid,pid);
+
+ /* Do a preliminary match */
+ if ((itype = inst_usb_match(vid, pid, 0)) == instUnknown) {
+ a1logd(p->log, 6 , "usb_get_paths: instrument not reconized\n");
+ CloseHandle(handle);
+ continue;
+ }
+
+ /* Allocate an idevice so that we can fill in the end point information */
+ if ((usbd = (struct usb_idevice *) calloc(sizeof(struct usb_idevice), 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "usb_get_paths: calloc failed!\n");
+ CloseHandle(handle);
+ return ICOM_SYS;
+ }
+
+ usbd->nconfig = nconfig;
+
+ /* Read the configuration descriptors looking for the first configuration, first interface, */
+ /* and extract the number of end points for each configuration */
+ for (configix = 0; configix < nconfig; configix++) {
+ int configno, totlen;
+ unsigned char *buf2, *bp, *zp;
+ unsigned int ninfaces, inface, nep;
+
+ /* Read the configuration descriptor */
+ req.descriptor.type = IUSB_DESC_TYPE_CONFIG;
+ req.descriptor.recipient = IUSB_REQ_RECIP_DEVICE;
+ req.descriptor.index = configix;
+ req.descriptor.language_id = 0;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if ((rv = do_sync_io(handle, LIBUSB_IOCTL_GET_DESCRIPTOR,
+ &req, sizeof(libusb_request),
+ buf, IUSB_DESC_TYPE_CONFIG_SIZE, &retsz)) != ICOM_OK
+ || retsz != IUSB_DESC_TYPE_CONFIG_SIZE) {
+ a1logd(p->log, 1, "usb_get_paths: failed to read configix %d descriptor\n",configix);
+ free(usbd);
+ CloseHandle(handle);
+ break;
+ }
+ nifce = buf[4]; /* number of interfaces */
+ configno = buf[5]; /* Configuration number */
+
+ if (configno != 1)
+ continue;
+
+ if ((totlen = buf2ushort(buf + 2)) < 6) {
+ a1logd(p->log, 1, "usb_get_paths: '%s' config desc size strange\n",dpath);
+ free(usbd);
+ CloseHandle(handle);
+ break;
+ }
+ if ((buf2 = calloc(1, totlen)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "usb_get_paths: calloc of descriptor failed!\n");
+ free(usbd);
+ CloseHandle(handle);
+ return ICOM_SYS;
+ }
+
+ /* Read the whole configuration descriptor */
+ req.descriptor.type = IUSB_DESC_TYPE_CONFIG;
+ req.descriptor.recipient = IUSB_REQ_RECIP_DEVICE;
+ req.descriptor.index = configix;
+ req.descriptor.language_id = 0;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if (do_sync_io(handle, LIBUSB_IOCTL_GET_DESCRIPTOR,
+ &req, sizeof(libusb_request),
+ buf2, totlen, &retsz) != ICOM_OK
+ || retsz != totlen) {
+ a1logd(p->log, 1, "usb_get_paths: failed to read all configix %d descriptor\n",configix);
+ free(buf2);
+ free(usbd);
+ CloseHandle(handle);
+ break;
+ }
+
+ bp = buf2 + buf2[0]; /* Skip coniguration tag */
+ zp = buf2 + totlen; /* Past last bytes */
+
+ /* We are at the first configuration. */
+ /* Just read tags and keep track of where we are */
+ ninfaces = 0;
+ nep = 0;
+ usbd->nifce = buf2[4]; /* number of interfaces */
+ usbd->config = configno = buf2[5]; /* this configuration */
+ for (;bp < zp; bp += bp[0]) {
+ int ifaceno;
+ if ((bp + 1) >= zp)
+ break; /* Hmm - bodgy, give up */
+ if (bp[1] == IUSB_DESC_TYPE_INTERFACE) {
+ ninfaces++;
+ if ((bp + 2) >= zp)
+ break; /* Hmm - bodgy, give up */
+ ifaceno = bp[2]; /* Get bInterfaceNumber */
+ } else if (bp[1] == IUSB_DESC_TYPE_ENDPOINT) {
+ nep++;
+ if ((bp + 5) >= zp)
+ break; /* Hmm - bodgy */
+ /* At first config - */
+ /* record current nep and end point details */
+ if (configno == 1) {
+ int ad = bp[2];
+ nep10 = nep;
+ usbd->EPINFO(ad).valid = 1;
+ usbd->EPINFO(ad).addr = ad;
+ usbd->EPINFO(ad).packetsize = buf2ushort(bp + 4);
+ usbd->EPINFO(ad).type = bp[3] & IUSB_ENDPOINT_TYPE_MASK;
+ usbd->EPINFO(ad).interface = ifaceno;
+ a1logd(p->log, 6, "set ep ad 0x%x packetsize %d type %d\n",ad,usbd->EPINFO(ad).packetsize,usbd->EPINFO(ad).type);
+ }
+ }
+ /* Ignore other tags */
+ }
+ free(buf2);
+ }
+ if (nep10 == 0xffff) { /* Hmm. Failed to find number of end points */
+ a1logd(p->log, 1, "usb_get_paths: failed to find number of end points\n");
+ free(usbd);
+ CloseHandle(handle);
+ continue;
+ }
+
+ /* Check that we have an up to date kernel driver */
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+ if (do_sync_io(handle, LIBUSB_IOCTL_GET_VERSION,
+ &req, sizeof(libusb_request),
+ &req, sizeof(libusb_request), &retsz) != ICOM_OK
+ || retsz != sizeof(libusb_request)) {
+ a1logd(p->log, 1, "usb_get_paths: failed to read driver version info\n");
+ free(usbd);
+ CloseHandle(handle);
+ continue;
+ }
+ if (req.version.major < 1
+ || req.version.major == 1 && (req.version.minor < 2
+ || req.version.minor == 2 && req.version.micro < 6)) {
+ a1loge(p->log, ICOM_VER, "usb_get_paths: Must update %s System Driver to latest version!\n",inst_name(itype));
+ free(usbd);
+ CloseHandle(handle);
+ return ICOM_VER;
+ }
+ CloseHandle(handle);
+
+ /* Found a known instrument ? */
+ if ((itype = inst_usb_match(vid, pid, nep10)) != instUnknown) {
+ char pname[400];
+
+ a1logd(p->log, 1, "usb_get_paths: found instrument vid 0x%04x, pid 0x%04x\n",vid,pid);
+
+ /* Create a path/identification */
+ sprintf(pname,"%s (%s)", dpath + 4, inst_name(itype));
+
+ if ((usbd->dpath = strdup(dpath)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "usb_check_and_add: strdup path failed!\n");
+ free(usbd);
+ return ICOM_SYS;
+ }
+
+ /* Add the path and ep info to the list */
+ if ((rv = p->add_usb(p, pname, vid, pid, nep10, usbd, itype)) != ICOM_OK)
+ return rv;
+ } else {
+ free(usbd);
+ }
+ }
+
+ return ICOM_OK;
+}
+
+
+/* Copy usb_idevice contents from icompaths to icom */
+/* return icom error */
+int usb_copy_usb_idevice(icoms *d, icompath *s) {
+ int i;
+ if (s->usbd == NULL) {
+ d->usbd = NULL;
+ return ICOM_OK;
+ }
+ if ((d->usbd = calloc(sizeof(struct usb_idevice), 1)) == NULL) {
+ a1loge(d->log, ICOM_SYS, "usb_copy_usb_idevice: malloc\n");
+ return ICOM_SYS;
+ }
+ if ((d->usbd->dpath = strdup(s->usbd->dpath)) == NULL) {
+ a1loge(d->log, ICOM_SYS, "usb_copy_usb_idevice: malloc\n");
+ return ICOM_SYS;
+ }
+ /* Copy the current state & ep info */
+ d->nconfig = s->usbd->nconfig;
+ d->config = s->usbd->config;
+ d->nifce = s->usbd->nifce;
+ for (i = 0; i < 32; i++)
+ d->ep[i] = s->usbd->ep[i]; /* Struct copy */
+ return ICOM_OK;
+}
+
+/* Cleanup and then free a usb dev entry */
+void usb_del_usb_idevice(struct usb_idevice *usbd) {
+
+ if (usbd == NULL)
+ return;
+
+ if (usbd->dpath != NULL)
+ free(usbd->dpath);
+ free(usbd);
+}
+
+/* Cleanup any USB specific icoms state */
+void usb_del_usb(icoms *p) {
+
+ usb_del_usb_idevice(p->usbd);
+}
+
+/* Close an open USB port */
+/* If we don't do this, the port and/or the device may be left in an unusable state. */
+void usb_close_port(icoms *p) {
+
+ a1logd(p->log, 6, "usb_close_port: called\n");
+
+ if (p->is_open && p->usbd != NULL) {
+ int iface, rv;
+
+ /* Release all the interfaces */
+ for (iface = 0; iface < p->nifce; iface++) {
+ libusb_request req;
+
+ memset(&req, 0, sizeof(req));
+ req.intf.interface_number = iface;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ do_sync_io(p->usbd->handle, LIBUSB_IOCTL_RELEASE_INTERFACE,
+ &req, sizeof(libusb_request), NULL, 0, NULL);
+ }
+
+ /* Workaround for some bugs - reset device on close */
+ if (p->uflags & icomuf_reset_before_close) {
+ libusb_request req;
+
+ memset(&req, 0, sizeof(req));
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_RESET_DEVICE,
+ &req, sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "usb_close_port: reset returned %d\n",rv);
+ }
+ }
+ CloseHandle(p->usbd->handle);
+
+ free(p->usbd->dpath);
+ free(p->usbd);
+ p->usbd = NULL;
+
+ a1logd(p->log, 6, "usb_close_port: usb port has been released and closed\n");
+ }
+ p->is_open = 0;
+
+ /* Find it and delete it from our static cleanup list */
+ usb_delete_from_cleanup_list(p);
+}
+
+static void *urb_reaper(void *context); /* Declare */
+
+/* Open a USB port for all our uses. */
+/* This always re-opens the port */
+/* return icom error */
+static int usb_open_port(
+icoms *p,
+int config, /* Configuration number */
+int wr_ep, /* Write end point */
+int rd_ep, /* Read end point */
+icomuflags usbflags,/* Any special handling flags */
+int retries, /* > 0 if we should retry set_configuration (100msec) */
+char **pnames /* List of process names to try and kill before opening */
+) {
+ int rv, tries = 0;
+ a1logd(p->log, 8, "usb_open_port: Make sure USB port is open, tries %d\n",retries);
+
+ if (p->is_open)
+ p->close_port(p);
+
+ /* Make sure the port is open */
+ if (!p->is_open) {
+ int rv, i, iface;
+ kkill_nproc_ctx *kpc = NULL;
+ OSVERSIONINFO osver;
+
+ if (config != 1) {
+ /* Nothing currently needs it, so we haven't implemented it yet... */
+ a1loge(p->log, ICOM_NOTS, "usb_open_port: native driver cant handle config %d\n",config);
+ return ICOM_NOTS;
+ }
+
+ /* Do open retries */
+ for (tries = 0; retries >= 0; retries--, tries++) {
+
+ a1logd(p->log, 8, "usb_open_port: About to open USB port '%s'\n",p->usbd->dpath);
+
+ if (tries > 0) {
+ //msec_sleep(i_rand(50,100));
+ msec_sleep(77);
+ }
+
+ if ((p->usbd->handle = CreateFile(p->usbd->dpath, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED, NULL)) == INVALID_HANDLE_VALUE) {
+ a1logd(p->log, 8, "usb_open_port: open '%s' config %d failed (%d) (Device being used ?)\n",p->usbd->dpath,config,GetLastError());
+ if (retries <= 0) {
+ if (kpc != NULL)
+ kpc->del(kpc);
+ a1loge(p->log, ICOM_SYS, "usb_open_port: open '%s' config %d failed (%d) (Device being used ?)\n",p->usbd->dpath,config,GetLastError());
+ return ICOM_SYS;
+ }
+ continue;
+ } else if (p->debug)
+ a1logd(p->log, 2, "usb_open_port: open port '%s' succeeded\n",p->usbd->dpath);
+
+ p->uflags = usbflags;
+
+ /* We're done */
+ break;
+ }
+
+ if (kpc != NULL)
+ kpc->del(kpc);
+
+ /* We should only do a set configuration if the device has more than one */
+ /* possible configuration and it is currently not the desired configuration, */
+ /* but we should avoid doing a set configuration if the OS has already */
+ /* selected the configuration we want, since two set configs seem to */
+ /* mess up the Spyder2, BUT we can't do a get config because this */
+ /* messes up the i1pro-D. */
+
+ osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ osver.dwMajorVersion = 5;
+ GetVersionEx(&osver);
+ if (osver.dwMajorVersion >= 6 && osver.dwMinorVersion >= 2) {
+ p->cconfig = 0; /* Need to do set_congfig(1) on Win8 */
+ } else {
+ p->cconfig = 1; /* Set by default to config 1 */
+ }
+
+ if (p->cconfig != config) {
+ libusb_request req;
+
+ memset(&req, 0, sizeof(libusb_request));
+ req.configuration.configuration = config;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_SET_CONFIGURATION,
+ &req, sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
+
+ a1loge(p->log, rv, "usb_open_port: Setting port '%s' to config %d failed with %d\n",p->usbd->dpath,config,rv);
+ return ICOM_SYS;
+ }
+ p->cconfig = config;
+ a1logd(p->log, 6, "usb_open_port: set config %d OK\n",config);
+ }
+
+ /* Claim all the interfaces */
+ for (iface = 0; iface < p->nifce; iface++) {
+ libusb_request req;
+
+ memset(&req, 0, sizeof(libusb_request));
+ req.intf.interface_number = iface;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_CLAIM_INTERFACE,
+ &req, sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
+
+ a1loge(p->log, rv, "usb_open_port: Claiming USB port '%s' interface %d failed with %d\n",p->usbd->dpath,iface,rv);
+ return ICOM_SYS;
+ }
+ }
+
+ /* Clear any errors */
+ /* (Some I/F seem to hang if we do this, some seem to hang if we don't !) */
+ if (!(p->uflags & icomuf_no_open_clear)) {
+ for (i = 0; i < 32; i++) {
+ if (!p->ep[i].valid)
+ continue;
+ p->usb_clearhalt(p, p->ep[i].addr);
+ }
+ }
+
+ /* Set "serial" coms values */
+ p->wr_ep = wr_ep;
+ p->rd_ep = rd_ep;
+ p->rd_qa = p->EPINFO(rd_ep).packetsize;
+ if (p->rd_qa == 0)
+ p->rd_qa = 8;
+ a1logd(p->log, 8, "usb_open_port: 'serial' read quanta = packet size = %d\n",p->rd_qa);
+
+ p->is_open = 1;
+ a1logd(p->log, 8, "usb_open_port: USB port is now open\n");
+ }
+
+ /* Install the cleanup signal handlers, and add to our cleanup list */
+ usb_install_signal_handlers(p);
+
+ return ICOM_OK;
+}
+
+/* -------------------------------------------------------------- */
+
+/* Our universal USB transfer function */
+static int icoms_usb_transaction(
+ icoms *p,
+ usb_cancelt *cancelt,
+ int *transferred,
+ icom_usb_trantype ttype, /* transfer type */
+ unsigned char endpoint, /* 0x80 for control write, 0x00 for control read */
+ unsigned char *buffer,
+ int length,
+ unsigned int timeout /* In msec */
+) {
+ int rv = ICOM_OK;
+ int dirw = (endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT ? 1 : 0;
+ libusb_request req;
+ OVERLAPPED olaps;
+ DWORD xlength = 0;
+
+ in_usb_rw++;
+
+ a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d\n",ttype,endpoint,length);
+
+ if (ttype != icom_usb_trantype_interrutpt
+ && ttype != icom_usb_trantype_bulk) {
+ /* We only handle interrupt & bulk, not control */
+ return ICOM_SYS;
+ }
+
+ memset(&olaps, 0, sizeof(olaps));
+
+ if ((olaps.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
+ return ICOM_SYS;
+
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *)&endpoint;
+ usb_unlock_cancel(cancelt);
+ }
+
+ memset(&req, 0, sizeof(libusb_request));
+ req.endpoint.endpoint = endpoint;
+
+ if (!DeviceIoControl(p->usbd->handle,
+ dirw ? LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE
+ : LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ,
+ &req, sizeof(libusb_request),
+ buffer,
+ length, &xlength, &olaps)) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ rv = dirw ? ICOM_USBW : ICOM_USBR;
+ goto done;
+ }
+
+ if (WaitForSingleObject(olaps.hEvent, timeout) == WAIT_TIMEOUT) {
+
+ /* Cancel the operation */
+ memset(&req, 0, sizeof(libusb_request));
+ req.endpoint.endpoint = endpoint;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+ do_sync_io(p->usbd->handle, LIBUSB_IOCTL_ABORT_ENDPOINT,
+ &req, sizeof(libusb_request), NULL, 0, NULL);
+ rv = ICOM_TO;
+ }
+
+ if (!GetOverlappedResult(p->usbd->handle, &olaps, &xlength, TRUE)) {
+ if (rv == ICOM_OK) {
+ if (GetLastError() == ERROR_OPERATION_ABORTED)
+ rv = ICOM_CANC;
+ else
+ rv = dirw ? ICOM_USBW : ICOM_USBR;
+ }
+ }
+ }
+done:;
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *)NULL;
+ usb_unlock_cancel(cancelt);
+ }
+
+ CloseHandle(olaps.hEvent);
+
+ if (transferred != NULL)
+ *transferred = (int)xlength;
+
+ /* The requested size wasn't transferred */
+ if (rv == ICOM_OK && xlength != length)
+ rv = ICOM_SHORT;
+
+ if (in_usb_rw < 0)
+ exit(0);
+
+ in_usb_rw--;
+
+ a1logd(p->log, 8, "coms_usb_transaction: returning err 0x%x and %d bytes\n",rv, xlength);
+
+ return rv;
+}
+
+
+/* Our control message routine */
+/* Return error icom error code */
+static int icoms_usb_control_msg(
+icoms *p,
+int *transferred,
+int requesttype, int request,
+int value, int index, unsigned char *bytes, int size,
+int timeout) {
+ int rv = ICOM_OK;
+ int dirw = (requesttype & IUSB_REQ_DIR_MASK) == IUSB_REQ_HOST_TO_DEV ? 1 : 0;
+ libusb_request req;
+ unsigned char *obuf = (unsigned char *)&req;
+ int osize = sizeof(libusb_request);
+ unsigned char *ibuf = bytes;
+ int isize = size;
+ int ioctl = 0;
+ int retsz = 0;
+
+ a1logd(p->log, 8, "icoms_usb_control_msg: type 0x%x req 0x%x size %d\n",requesttype,request,size);
+
+ memset(&req, 0, sizeof(libusb_request));
+ req.timeout = timeout;
+
+ /* We need to treat each request type as a different IOCTL */
+ switch (requesttype & IUSB_REQ_TYPE_MASK) {
+
+ case IUSB_REQ_TYPE_STANDARD:
+
+ switch (request) {
+ case IUSB_REQ_GET_STATUS:
+ req.status.recipient = requesttype & IUSB_REQ_RECIP_MASK;
+ req.status.index = index;
+ ioctl = LIBUSB_IOCTL_GET_STATUS;
+ break;
+
+ case IUSB_REQ_CLEAR_FEATURE:
+ req.feature.recipient = requesttype & IUSB_REQ_RECIP_MASK;
+ req.feature.feature = value;
+ req.feature.index = index;
+ ioctl = LIBUSB_IOCTL_CLEAR_FEATURE;
+ break;
+
+ case IUSB_REQ_SET_FEATURE:
+ req.feature.recipient = requesttype & IUSB_REQ_RECIP_MASK;
+ req.feature.feature = value;
+ req.feature.index = index;
+ ioctl = LIBUSB_IOCTL_SET_FEATURE;
+ break;
+
+ case IUSB_REQ_GET_DESCRIPTOR:
+ req.descriptor.recipient = requesttype & IUSB_REQ_RECIP_MASK;
+ req.descriptor.type = (value >> 8) & 0xFF;
+ req.descriptor.index = value & 0xFF;
+ req.descriptor.language_id = index;
+ ioctl = LIBUSB_IOCTL_GET_DESCRIPTOR;
+ break;
+
+ case IUSB_REQ_SET_DESCRIPTOR:
+ req.descriptor.recipient = requesttype & IUSB_REQ_RECIP_MASK;
+ req.descriptor.type = (value >> 8) & 0xFF;
+ req.descriptor.index = value & 0xFF;
+ req.descriptor.language_id = index;
+ ioctl = LIBUSB_IOCTL_SET_DESCRIPTOR;
+ break;
+
+ case IUSB_REQ_GET_CONFIGURATION:
+ ioctl = LIBUSB_IOCTL_GET_CONFIGURATION;
+ break;
+
+ case IUSB_REQ_SET_CONFIGURATION:
+ req.configuration.configuration = value;
+ ioctl = LIBUSB_IOCTL_SET_CONFIGURATION;
+ break;
+
+ case IUSB_REQ_GET_INTERFACE:
+ req.intf.interface_number = index;
+ ioctl = LIBUSB_IOCTL_GET_INTERFACE;
+ break;
+
+ case IUSB_REQ_SET_INTERFACE:
+ req.intf.interface_number = index;
+ req.intf.altsetting_number = value;
+ ioctl = LIBUSB_IOCTL_SET_INTERFACE;
+ break;
+
+ default:
+ return ICOM_SYS;
+ }
+ break;
+
+ case IUSB_REQ_TYPE_VENDOR:
+ case IUSB_REQ_TYPE_CLASS:
+
+ req.vendor.type = (requesttype & IUSB_REQ_TYPE_MASK) >> IUSB_REQ_TYPE_SHIFT;
+ req.vendor.recipient = requesttype & IUSB_REQ_RECIP_MASK;
+ req.vendor.request = request;
+ req.vendor.value = value;
+ req.vendor.index = index;
+
+ if (dirw)
+ ioctl = LIBUSB_IOCTL_VENDOR_WRITE;
+ else
+ ioctl = LIBUSB_IOCTL_VENDOR_READ;
+ break;
+
+ case IUSB_REQ_TYPE_RESERVED:
+ default:
+ return ICOM_SYS;
+ }
+
+ /* If we're writing the data, append it to the req */
+ if (dirw) {
+ osize = sizeof(libusb_request) + size;
+ if ((obuf = calloc(1, osize)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_control_msg: calloc failed\n");
+ return ICOM_SYS;
+ }
+
+ memcpy(obuf, &req, sizeof(libusb_request));
+ memcpy(obuf + sizeof(libusb_request), bytes, size);
+ ibuf = NULL;
+ isize = 0;
+ }
+
+ if ((rv = do_sync_io(p->usbd->handle, ioctl, obuf, osize, ibuf, isize, &retsz))
+ != ICOM_OK) {
+ if (dirw)
+ free(obuf);
+ return rv;
+ }
+
+ if (dirw) {
+ free(obuf);
+ retsz = size;
+ }
+
+ if (transferred != NULL) /* Adjust for header size requested */
+ *transferred = retsz;
+
+ a1logd(p->log, 8, "icoms_usb_control_msg: returning err 0x%x and %d bytes\n",rv, *transferred);
+ return rv;
+}
+
+/* Cancel i/o operation in another thread. */
+/* Only Vista has CancelIoEx that can cancel a single operation, */
+/* so we cancel the io to the end point, which will */
+/* acheive what we want. */
+int icoms_usb_cancel_io(
+ icoms *p,
+ usb_cancelt *cancelt
+) {
+ int rv = ICOM_OK;
+ usb_lock_cancel(cancelt);
+ if (cancelt->hcancel != NULL) {
+ libusb_request req;
+
+ memset(&req, 0, sizeof(libusb_request));
+ req.endpoint.endpoint = *((unsigned char *)cancelt->hcancel);
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_ABORT_ENDPOINT,
+ &req, sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "icoms_usb_cancel_io: failed with 0x%x\n",rv);
+ }
+ }
+ usb_unlock_cancel(cancelt);
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Reset and end point data toggle to 0 */
+int icoms_usb_resetep(
+ icoms *p,
+ int ep /* End point address */
+) {
+ libusb_request req;
+ int rv = ICOM_OK;
+
+ memset(&req, 0, sizeof(libusb_request));
+ req.endpoint.endpoint = ep;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_RESET_ENDPOINT, &req,
+ sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "icoms_usb_resetep failed with %d\n",rv);
+ return rv;
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Clear a halt on an end point */
+/* (Actually does a resetep) */
+int icoms_usb_clearhalt(
+ icoms *p,
+ int ep /* End point address */
+) {
+ libusb_request req;
+ int rv = ICOM_OK;
+
+ memset(&req, 0, sizeof(libusb_request));
+ req.endpoint.endpoint = ep;
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_RESET_ENDPOINT, &req,
+ sizeof(libusb_request), NULL, 0, NULL)) != ICOM_OK) {
+ a1logd(p->log, 1, "icoms_usb_resetep failed with %d\n",rv);
+ return rv;
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef NEVER
+ libusb_request req;
+ unsigned char buf[1] = { 0xff };
+
+ memset(&req, 0, sizeof(libusb_request));
+ req.timeout = LIBUSBW1_DEFAULT_TIMEOUT;
+
+ if ((rv = do_sync_io(p->usbd->handle, LIBUSB_IOCTL_GET_CONFIGURATION,
+ &req, sizeof(libusb_request), buf, 1, NULL)) != ICOM_OK) {
+
+ a1logd(p->log, 1, "usb_open_port: Getting port '%s' configuration failed with %d\n",p->usbd->dpath,rv);
+ /* Ignore error */
+ } else {
+ a1logd(p->log, 1, "usb_open_port: current config = %d\n",(int)buf[0]);
+ }
+ config = buf[0];
+#endif // NEVER
+
diff --git a/spectro/usbio_ox.c b/spectro/usbio_ox.c
new file mode 100644
index 0000000..24498fb
--- /dev/null
+++ b/spectro/usbio_ox.c
@@ -0,0 +1,986 @@
+
+/* General USB I/O support, OS X native implementation. */
+/* This file is conditionaly #included into usbio.c */
+
+/*
+ * Argyll Color Correction System
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/22/4
+ *
+ * Copyright 2006 - 2013 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+#include <sys/time.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOTypes.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/usb/IOUSBLib.h>
+#include <IOKit/IOCFPlugIn.h>
+//#include <IOKit/IOCFBundle.h>
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+# include <objc/objc-auto.h>
+#endif
+
+/* Add paths to USB connected instruments */
+/* Return an icom error */
+int usb_get_paths(
+icompaths *p
+) {
+ kern_return_t kstat;
+ CFMutableDictionaryRef sdict; /* USB Device dictionary */
+ io_iterator_t mit; /* Matching itterator */
+ int vid, pid;
+ struct usb_idevice *usbd = NULL;
+
+ a1logd(p->log, 6, "usb_get_paths: about to look through devices:\n");
+
+ /* Get dictionary of USB devices */
+ if ((sdict = IOServiceMatching(kIOUSBDeviceClassName)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "usb_get_paths() IOServiceMatching returned a NULL dictionary\n");
+ return ICOM_SYS;
+ }
+
+ /* Init itterator to find matching types. Consumes sdict reference */
+ if ((kstat = IOServiceGetMatchingServices(kIOMasterPortDefault, sdict, &mit))
+ != KERN_SUCCESS) {
+ a1loge(p->log, ICOM_SYS, "usb_get_paths() IOServiceGetMatchingServices returned %d\n", kstat);
+ return ICOM_SYS;
+ }
+
+ /* Find all the matching USB devices */
+ for (;;) {
+ io_object_t ioob; /* USB object found */
+ io_iterator_t it1; /* Child level 1 */
+ CFMutableDictionaryRef usbprops = 0; /* USB Device properties */
+ CFNumberRef vref, pref; /* USB Vendor and Product ID propeties */
+ CFNumberRef nconfref; /* No configurations */
+ CFNumberRef nepref, lidpref; /* No ep's, Location ID properties */
+ unsigned int vid = 0, pid = 0, nep, tnep, nconfig = 0, lid = 0;
+ instType itype;
+
+ if ((ioob = IOIteratorNext(mit)) == 0)
+ break;
+
+ /* Get the two properies we need. */
+ if ((vref = IORegistryEntryCreateCFProperty(ioob, CFSTR(kUSBVendorID),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(vref, kCFNumberIntType, &vid);
+ CFRelease(vref);
+ }
+ if ((pref = IORegistryEntryCreateCFProperty(ioob, CFSTR(kUSBProductID),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(pref, kCFNumberIntType, &pid);
+ CFRelease(pref);
+ }
+
+ if ((nconfref = IORegistryEntryCreateCFProperty(ioob, CFSTR("bNumConfigurations"),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(nconfref, kCFNumberIntType, &nconfig);
+ CFRelease(nconfref);
+ }
+
+ if ((lidpref = IORegistryEntryCreateCFProperty(ioob, CFSTR("locationID"),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(lidpref, kCFNumberIntType, &lid);
+ CFRelease(lidpref);
+ }
+
+ a1logd(p->log, 6, "usb_check_and_add: checking vid 0x%04x, pid 0x%04x, lid 0x%x\n",vid,pid,lid);
+
+ /* Do a preliminary match */
+ if ((itype = inst_usb_match(vid, pid, 0)) == instUnknown) {
+ a1logd(p->log, 6 , "usb_check_and_add: 0x%04x 0x%04x not reconized\n",vid,pid);
+ IOObjectRelease(ioob); /* Release found object */
+ continue;
+ }
+
+ /* Allocate an idevice so that we can fill in the end point information */
+ if ((usbd = (struct usb_idevice *) calloc(sizeof(struct usb_idevice), 1)) == NULL) {
+ a1loge(p->log, ICOM_SYS, "icoms: calloc failed!\n");
+ return ICOM_SYS;
+ }
+
+ usbd->nconfig = nconfig;
+ usbd->config = 1; /* We are only interested in config 1 */
+
+ /* Go through all the Interfaces, adding up the number of end points */
+ tnep = 0;
+ if ((kstat = IORegistryEntryCreateIterator(ioob, kIOServicePlane,
+ kIORegistryIterateRecursively, &it1)) != KERN_SUCCESS) {
+ IOObjectRelease(ioob);
+ IOObjectRelease(mit);
+ a1loge(p->log, kstat, "usb_check_and_add: IORegistryEntryCreateIterator() with %d\n",kstat);
+ return ICOM_SYS;
+ }
+ usbd->nifce = 0;
+ for (;;) {
+ io_object_t ch1; /* Child object 1 */
+ if ((ch1 = IOIteratorNext(it1)) == 0)
+ break;
+ if (IOObjectConformsTo(ch1, "IOUSBInterface")) {
+ unsigned int config = 0;
+
+ /* Get the configuration number */
+ if ((nconfref = IORegistryEntryCreateCFProperty(ch1, CFSTR(kUSBNumEndpoints),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(nconfref, kCFNumberIntType, &config);
+ CFRelease(nconfref);
+ }
+
+ if (config != 1)
+ continue;
+
+ usbd->nifce++;
+
+ /* Get the number of end points */
+ if ((nepref = IORegistryEntryCreateCFProperty(ch1, CFSTR(kUSBNumEndpoints),
+ kCFAllocatorDefault,kNilOptions)) != 0) {
+ CFNumberGetValue(nepref, kCFNumberIntType, &nep);
+ CFRelease(nepref);
+ tnep += nep;
+ }
+ IOObjectRelease(ch1);
+ }
+ }
+ IOObjectRelease(it1);
+
+ if ((itype = inst_usb_match(vid, pid, tnep)) != instUnknown) {
+ int i;
+ char pname[400];
+ int rv;
+
+ /* If this device is HID, it will have already added to the paths list, */
+ /* so check for this and skip this device if it is already there. */
+ for (i = 0; i < p->npaths; i++) {
+ if (p->paths[i]->vid == vid
+ && p->paths[i]->pid == pid
+ && p->paths[i]->hidd != NULL
+ && p->paths[i]->hidd->lid == lid) {
+ a1logd(p->log, 1, "usb_check_and_add: Ignoring device because it is already in list as HID\n");
+ break;
+ }
+ }
+ if (i < p->npaths) {
+ IOObjectRelease(ioob); /* Release found object */
+ free(usbd);
+
+ } else {
+
+ a1logd(p->log, 1, "usb_check_and_add: found instrument vid 0x%04x, pid 0x%04x\n",vid,pid);
+ usbd->lid = lid;
+ usbd->ioob = ioob;
+
+ /* Create a path/identification */
+ sprintf(pname,"usb%d: (%s)", lid >> 20, inst_name(itype));
+
+ /* Add the path and ep info to the list */
+ if ((rv = p->add_usb(p, pname, vid, pid, tnep, usbd, itype)) != ICOM_OK) {
+ IOObjectRelease(ioob); /* Release found object */
+ free(usbd);
+ IOObjectRelease(mit); /* Release the itterator */
+ return rv;
+ }
+ }
+ } else {
+ IOObjectRelease(ioob); /* Release found object */
+ free(usbd);
+ }
+ }
+ IOObjectRelease(mit); /* Release the itterator */
+
+ a1logd(p->log, 8, "usb_get_paths: returning %d paths and ICOM_OK\n",p->npaths);
+ return ICOM_OK;
+}
+
+/* Copy usb_idevice contents from icompaths to icom */
+/* return icom error */
+int usb_copy_usb_idevice(icoms *d, icompath *s) {
+ int i;
+ if (s->usbd == NULL) {
+ d->usbd = NULL;
+ return ICOM_OK;
+ }
+ if ((d->usbd = calloc(sizeof(struct usb_idevice), 1)) == NULL) {
+ a1loge(d->log, ICOM_SYS, "usb_copy_usb_idevice: malloc\n");
+ return ICOM_SYS;
+ }
+ d->nconfig = s->usbd->nconfig;
+ d->config = s->usbd->config;
+ d->nifce = s->usbd->nifce;
+ d->usbd->ioob = s->usbd->ioob;
+ IOObjectRetain(d->usbd->ioob);
+ return ICOM_OK;
+}
+
+/* Cleanup and then free a usb dev entry */
+void usb_del_usb_idevice(struct usb_idevice *usbd) {
+
+ if (usbd == NULL)
+ return;
+
+ if (usbd->ioob != 0)
+ IOObjectRelease(usbd->ioob);
+
+ free(usbd);
+}
+
+/* Cleanup any USB specific icoms state */
+void usb_del_usb(icoms *p) {
+
+ usb_del_usb_idevice(p->usbd);
+}
+
+/* Clean up anything allocated/created in p->usbd, but don't free p->usbd itself */
+static void cleanup_device(icoms *p) {
+
+ if (p->usbd != NULL) {
+ if (p->usbd->device != NULL) { /* device is open */
+ int i;
+
+ /* Stop the RunLoop and wait for it */
+ if (p->usbd->cfrunloop != NULL) {
+
+ a1logd(p->log, 6, "usb_close_port: waiting for RunLoop thread to exit\n");
+ CFRunLoopStop(p->usbd->cfrunloop);
+ CFRelease(p->usbd->cfrunloop);
+ if (p->usbd->thread != NULL)
+ pthread_join(p->usbd->thread, NULL);
+ }
+
+ /* Release all the interfaces */
+ for (i = 0; i < p->usbd->nifce; i++) {
+ if (p->usbd->interfaces[i] != NULL) {
+ (*p->usbd->interfaces[i])->USBInterfaceClose(p->usbd->interfaces[i]);
+ (*p->usbd->interfaces[i])->Release(p->usbd->interfaces[i]);
+ }
+ }
+
+ /* Close the device */
+ (*(p->usbd->device))->USBDeviceClose(p->usbd->device);
+ (*(p->usbd->device))->Release(p->usbd->device);
+ }
+ pthread_cond_destroy(&p->usbd->cond);
+ pthread_mutex_destroy(&p->usbd->lock);
+
+ memset(p->usbd, 0, sizeof(struct usb_idevice));
+ }
+}
+
+/* Close an open USB port */
+/* If we don't do this, the port and/or the device may be left in an unusable state. */
+void usb_close_port(icoms *p) {
+
+ a1logd(p->log, 6, "usb_close_port: called\n");
+
+ if (p->is_open && p->usbd != NULL) {
+
+ /* Workaround for some bugs - reset device on close */
+ if (p->uflags & icomuf_reset_before_close) {
+ IOReturn rv;
+ if ((rv = (*(p->usbd->device))->ResetDevice(p->usbd->device)) != kIOReturnSuccess) {
+ a1logd(p->log, 1, "usb_close_port: ResetDevice failed with 0x%x\n",rv);
+ }
+ }
+
+ /* Close down and free everything in p->usbd */
+ cleanup_device(p);
+ if (p->usbd != NULL) {
+ free(p->usbd);
+ p->usbd = NULL;
+ }
+ a1logd(p->log, 6, "usb_close_port: usb port has been released and closed\n");
+ }
+ p->is_open = 0;
+
+ /* Find it and delete it from our static cleanup list */
+ usb_delete_from_cleanup_list(p);
+}
+
+static int icoms_usb_control_msg(icoms *p, int *transferred, int requesttype, int request,
+ int value, int index, unsigned char *bytes, int size, int timeout);
+static void *io_runloop(void *context);
+
+/* Open a USB port for all our uses. */
+/* This always re-opens the port */
+/* return icom error */
+static int usb_open_port(
+icoms *p,
+int config, /* Configuration number, (1 based) */
+int wr_ep, /* Write end point */
+int rd_ep, /* Read end point */
+icomuflags usbflags,/* Any special handling flags */
+int retries, /* > 0 if we should retry set_configuration (100msec) */
+char **pnames /* List of process names to try and kill before opening */
+) {
+ IOReturn rv;
+ int tries = 0;
+ a1logd(p->log, 8, "usb_open_port: Make sure USB port is open, tries %d\n",retries);
+
+ if (p->is_open)
+ p->close_port(p);
+
+ /* Make sure the port is open */
+ if (!p->is_open) {
+ kkill_nproc_ctx *kpc = NULL;
+
+ if (config != 1) {
+ /* Nothing currently needs it, so we haven't implemented it yet... */
+ a1loge(p->log, ICOM_NOTS, "usb_open_port: native driver cant handle config %d\n",config);
+ return ICOM_NOTS;
+ }
+
+ pthread_mutex_init(&p->usbd->lock, NULL);
+ pthread_cond_init(&p->usbd->cond, NULL);
+
+ /* Do open retries */
+ for (tries = 0; retries >= 0; retries--, tries++) {
+ IOCFPlugInInterface **piif = NULL;
+ SInt32 score;
+
+ a1logd(p->log, 8, "usb_open_port: About to open USB port '%s'\n",p->name);
+
+ if (tries > 0) {
+ //msec_sleep(i_rand(50,100));
+ msec_sleep(77);
+ }
+ if (tries > 0 && pnames != NULL && kpc == NULL) {
+ if ((kpc = kkill_nprocess(pnames, p->log)) == NULL) {
+ a1logd(p->log, 1, "kkill_nprocess returned error!\n");
+ }
+ }
+
+ if ((rv = IOCreatePlugInInterfaceForService(p->usbd->ioob,
+ kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
+ &piif, &score)) != kIOReturnSuccess || piif == NULL) {
+ a1loge(p->log, rv, "usb_open_port: Failed to get piif for "
+ "USB device '%s', result 0x%x, piif 0x%x\n",p->name,rv,piif);
+ return ICOM_SYS;
+ }
+
+ p->usbd->device = NULL;
+ if ((rv = (*piif)->QueryInterface(piif,
+ CFUUIDGetUUIDBytes(DeviceInterfaceID), (void *)&p->usbd->device))
+ != kIOReturnSuccess || p->usbd->device == NULL) {
+ a1loge(p->log, rv, "usb_open_port: QueryInterface '%s' failed with 0%x\n",p->name, rv);
+ (*piif)->Release(piif);
+ return ICOM_SYS;
+ }
+ (*piif)->Release(piif); /* delete intermediate object */
+
+ if ((rv = (*p->usbd->device)->USBDeviceOpenSeize(p->usbd->device)) != kIOReturnSuccess) {
+ a1logd(p->log, 8, "usb_open_port: open '%s' config %d failed (0x%x) (Device being used ?)\n",p->name,config,rv);
+ if (retries <= 0) {
+ if (kpc != NULL)
+ kpc->del(kpc);
+ a1loge(p->log, rv, "usb_open_port: open '%s' config %d failed (0x%x) (Device being used ?)\n",p->name, config, rv);
+ (*p->usbd->device)->Release(p->usbd->device);
+ return ICOM_SYS;
+ }
+ continue;
+ } else if (p->debug)
+ a1logd(p->log, 1, "usb_open_port: open port '%s' succeeded\n",p->name);
+
+ p->uflags = usbflags;
+
+ /* We're done retries */
+ break;
+ }
+
+ if (kpc != NULL)
+ kpc->del(kpc);
+
+ /* We should only do a set configuration if the device has more than one */
+ /* possible configuration and it is currently not the desired configuration, */
+ /* but we should avoid doing a set configuration if the OS has already */
+ /* selected the configuration we want, since two set configs seem to */
+ /* mess up the Spyder2, BUT we can't do a get config because this */
+ /* messes up the i1pro-D. */
+
+ /* OS X doesn't do a set_configuration() by default */
+ p->cconfig = 0;
+
+ if (p->cconfig != config) {
+ if ((rv = (*(p->usbd->device))->SetConfiguration(
+ p->usbd->device, config)) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: SetConfiguration failed with 0x%x\n",rv);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ p->cconfig = config;
+ a1logd(p->log, 6, "usb_open_port: SetConfiguration %d OK\n",config);
+ }
+
+ /* Get interfaces */
+ {
+ int i, j;
+ IOUSBFindInterfaceRequest req;
+ io_iterator_t ioit;
+ io_service_t iface;
+ IOCFPlugInInterface **pluginref = NULL;
+ SInt32 score;
+
+ req.bInterfaceClass =
+ req.bInterfaceSubClass =
+ req.bInterfaceProtocol =
+ req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ if ((rv = (*(p->usbd->device))->CreateInterfaceIterator(
+ p->usbd->device, &req, &ioit)) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: CreateInterfaceIterator failed with 0x%x\n",rv);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ iface = IOIteratorNext(ioit);
+ for (i = 0; iface != 0; i++, iface = IOIteratorNext(ioit)) {
+ u_int8_t nep;
+
+ if ((rv = IOCreatePlugInInterfaceForService(iface,
+ kIOUSBInterfaceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &pluginref, &score)) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: IOCreatePlugInInterfaceForService failed with 0x%x\n",rv);
+ IOObjectRelease(iface);
+ IOObjectRelease(ioit);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ IOObjectRelease(iface);
+ if ((rv = (*pluginref)->QueryInterface(pluginref,
+ CFUUIDGetUUIDBytes(InterfaceInterfaceID),
+ (void *)&p->usbd->interfaces[i])) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: QueryInterface failed with 0x%x\n",rv);
+ (*pluginref)->Stop(pluginref);
+ IODestroyPlugInInterface(pluginref);
+ IOObjectRelease(ioit);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ (*pluginref)->Stop(pluginref);
+ IODestroyPlugInInterface(pluginref);
+
+ if ((rv = (*(p->usbd->interfaces[i]))->USBInterfaceOpen(
+ p->usbd->interfaces[i])) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: USBInterfaceOpen failed with 0x%x\n",rv);
+ IOObjectRelease(ioit);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+
+ /* Get the end point details, and set reference to pipe no and interfece ix */
+ if ((rv = (*(p->usbd->interfaces[i]))->GetNumEndpoints(
+ p->usbd->interfaces[i], &nep)) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: GetNumEndpoints failed with 0x%x\n",rv);
+ IOObjectRelease(ioit);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ for (j = 0; j < nep; j++) {
+ UInt8 direction, pnumber, transferType, interval;
+ UInt16 maxPacketSize;
+ int ad;
+ if ((rv = (*(p->usbd->interfaces[i]))->GetPipeProperties(
+ p->usbd->interfaces[i], (UInt8)(j+1), &direction, &pnumber,
+ &transferType, &maxPacketSize, &interval)) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: GetPipeProperties failed with 0x%x\n",rv);
+ IOObjectRelease(ioit);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ ad = ((direction << IUSB_ENDPOINT_DIR_SHIFT) & IUSB_ENDPOINT_DIR_MASK)
+ | (pnumber & IUSB_ENDPOINT_NUM_MASK);
+ p->EPINFO(ad).valid = 1;
+ p->EPINFO(ad).addr = ad;
+ p->EPINFO(ad).packetsize = maxPacketSize;
+ p->EPINFO(ad).type = transferType & IUSB_ENDPOINT_TYPE_MASK;
+ p->EPINFO(ad).interface = i;
+ p->EPINFO(ad).pipe = j+1;
+ a1logd(p->log, 6, "set ep ad 0x%x packetsize %d type %d, if %d, pipe %d\n",ad,maxPacketSize,transferType & IUSB_ENDPOINT_TYPE_MASK,i,j);
+ }
+ }
+ p->usbd->nifce = i; /* Just in case.. */
+
+ IOObjectRelease(ioit);
+ }
+ {
+ /* Setup the RunLoop thread */
+ a1logd(p->log, 6, "usb_open_port: Starting RunLoop thread\n");
+ if ((rv = pthread_create(&p->usbd->thread, NULL, io_runloop, (void*)p)) < 0) {
+ a1loge(p->log, ICOM_SYS, "usb_open_port: creating RunLoop thread failed with %s\n",rv);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+
+ /* Wait for the runloop thread to start and create a cfrunloop */
+ pthread_mutex_lock(&p->usbd->lock);
+ while (p->usbd->cfrunloop == NULL)
+ pthread_cond_wait(&p->usbd->cond, &p->usbd->lock);
+ pthread_mutex_unlock(&p->usbd->lock);
+ if (p->usbd->thrv != kIOReturnSuccess) { /* Thread failed */
+ pthread_join(p->usbd->thread, NULL);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ CFRetain(p->usbd->cfrunloop);
+ a1logd(p->log, 6, "usb_open_port: RunLoop thread started\n");
+ }
+
+ /* Clear any errors */
+ /* (Some I/F seem to hang if we do this, some seem to hang if we don't !) */
+ if (!(p->uflags & icomuf_no_open_clear)) {
+ int i;
+ for (i = 0; i < 32; i++) {
+ if (!p->ep[i].valid)
+ continue;
+ p->usb_clearhalt(p, p->ep[i].addr);
+ }
+ }
+
+ /* Set "serial" coms values */
+ p->wr_ep = wr_ep;
+ p->rd_ep = rd_ep;
+ p->rd_qa = p->EPINFO(rd_ep).packetsize;
+ if (p->rd_qa == 0)
+ p->rd_qa = 8;
+ a1logd(p->log, 8, "usb_open_port: 'serial' read quanta = packet size = %d\n",p->rd_qa);
+
+ p->is_open = 1;
+ a1logd(p->log, 8, "usb_open_port: USB port is now open\n");
+ }
+
+ /* Install the cleanup signal handlers, and add to our cleanup list */
+ usb_install_signal_handlers(p);
+
+ return ICOM_OK;
+}
+
+/* -------------------------------------------------------------- */
+
+/* The run loop thread */
+static void *io_runloop(void *context) {
+ icoms *p = (icoms *)context;
+ int i;
+
+ /* Register this thread with the Objective-C garbage collector */
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+ objc_registerThreadWithCollector();
+#endif
+
+ a1logd(p->log, 6, "io_runloop: thread started\n");
+
+ p->usbd->cfrunloop = CFRunLoopGetCurrent(); /* Get this threads RunLoop */
+ CFRetain(p->usbd->cfrunloop);
+
+ /* Add a device event source */
+ if ((p->usbd->thrv = (*(p->usbd->device))->CreateDeviceAsyncEventSource(
+ p->usbd->device, &p->usbd->cfsource)) != kIOReturnSuccess) {
+ a1loge(p->log, p->usbd->thrv, "io_runloop: CreateDeviceAsyncEventSource failed with 0x%x\n",p->usbd->thrv);
+ } else {
+ CFRunLoopAddSource(p->usbd->cfrunloop, p->usbd->cfsource, kCFRunLoopDefaultMode);
+ }
+
+ /* Create an async event source for the interfaces */
+ for (i = 0; p->usbd->thrv == kIOReturnSuccess && i < p->usbd->nifce; i++) {
+ if ((p->usbd->thrv = (*(p->usbd->interfaces[i]))->CreateInterfaceAsyncEventSource(
+ p->usbd->interfaces[i], &p->usbd->cfsources[i])) != kIOReturnSuccess) {
+ a1loge(p->log, p->usbd->thrv, "io_runloop: CreateInterfaceAsyncEventSource failed with 0x%x\n",p->usbd->thrv);
+ } else {
+ /* Add it to the RunLoop */
+ CFRunLoopAddSource(p->usbd->cfrunloop, p->usbd->cfsources[i], kCFRunLoopDefaultMode);
+ }
+ }
+
+ /* Signal main thread that we've started */
+ pthread_mutex_lock(&p->usbd->lock);
+ pthread_cond_signal(&p->usbd->cond);
+ pthread_mutex_unlock(&p->usbd->lock);
+
+ /* Run the loop, or exit on error */
+ if (p->usbd->thrv == kIOReturnSuccess) {
+ CFRunLoopRun(); /* Run the loop and deliver events */
+ }
+
+ /* Delete the interfaces async event sources */
+ for (i = 0; i < p->usbd->nifce; i++) {
+ if (p->usbd->cfsources[i] != NULL) {
+ CFRunLoopRemoveSource(p->usbd->cfrunloop, p->usbd->cfsources[i], kCFRunLoopDefaultMode);
+ CFRelease(p->usbd->cfsources[i]);
+ }
+ }
+
+ /* Delete the devices event sources */
+ if (p->usbd->cfsource != NULL) {
+ CFRunLoopRemoveSource(p->usbd->cfrunloop, p->usbd->cfsource, kCFRunLoopDefaultMode);
+ CFRelease(p->usbd->cfsource);
+ }
+
+ CFRelease(p->usbd->cfrunloop);
+
+ a1logd(p->log, 6, "io_runloop: thread done\n");
+ return NULL;
+}
+
+/* I/O structures */
+
+typedef struct _usbio_req {
+ icoms *p;
+ int iix; /* Interface index */
+ UInt8 pno; /* pipe index */
+ volatile int done; /* Done flag */
+ pthread_mutex_t lock; /* Protect req & callback access */
+ pthread_cond_t cond; /* Signal to thread waiting on req */
+ int xlength; /* Bytes transferred */
+ IOReturn result; /* Result of transaction */
+} usbio_req;
+
+
+/* Async completion callback - called by RunLoop thread */
+static void io_callback(void *refcon, IOReturn result, void *arg0) {
+ usbio_req *req = (usbio_req *)refcon;
+
+ a1logd(req->p->log, 1, "io_callback: result 0x%x, length %d\n",result,(int)(long)arg0);
+
+ req->xlength = (int)(long)arg0;
+ req->result = result;
+ req->done = 1;
+ pthread_mutex_lock(&req->lock);
+ pthread_cond_signal(&req->cond);
+ pthread_mutex_unlock(&req->lock);
+}
+
+/* Our universal USB transfer function */
+static int icoms_usb_transaction(
+ icoms *p,
+ usb_cancelt *cancelt,
+ int *transferred,
+ icom_usb_trantype ttype, /* transfer type */
+ unsigned char endpoint, /* 0x80 for control write, 0x00 for control read */
+ unsigned char *buffer,
+ int length,
+ unsigned int timeout /* In msec */
+) {
+ int reqrv = ICOM_OK, rv = 0;
+ int dirw = (endpoint & IUSB_ENDPOINT_DIR_MASK) == IUSB_ENDPOINT_OUT ? 1 : 0;
+ usbio_req req;
+ IOReturn result;
+ int iix = p->EPINFO(endpoint).interface;
+ UInt8 pno = (UInt8)p->EPINFO(endpoint).pipe;
+
+ in_usb_rw++;
+
+ a1logd(p->log, 8, "icoms_usb_transaction: req type 0x%x ep 0x%x size %d\n",ttype,endpoint,length);
+
+ if (ttype != icom_usb_trantype_interrutpt
+ && ttype != icom_usb_trantype_bulk) {
+ /* We only handle interrupt & bulk, not control */
+ return ICOM_SYS;
+ }
+
+ req.p = p;
+ req.iix = iix;
+ req.pno = pno;
+ req.xlength = 0;
+ req.done = 0;
+ pthread_mutex_init(&req.lock, NULL);
+ pthread_cond_init(&req.cond, NULL);
+
+ if (dirw)
+ result = (*p->usbd->interfaces[iix])->WritePipeAsync(p->usbd->interfaces[iix],
+ pno, buffer, length, io_callback, &req);
+ else
+ result = (*p->usbd->interfaces[iix])->ReadPipeAsync(p->usbd->interfaces[iix],
+ pno, buffer, length, io_callback, &req);
+
+ if (result != kIOReturnSuccess) {
+ a1loge(p->log, ICOM_SYS, "icoms_usb_transaction: %sPipeAsync failed with 0x%x\n",dirw ? "Write" : "Read", result);
+ reqrv = ICOM_SYS;
+ goto done;
+ }
+
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *)&req;
+ usb_unlock_cancel(cancelt);
+ }
+
+ /* Wait for the callback to complete */
+ pthread_mutex_lock(&req.lock);
+ if (!req.done) {
+ struct timeval tv;
+ struct timespec ts;
+
+ // this is unduly complicated...
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec + timeout/1000;
+ ts.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000L;
+ if (ts.tv_nsec > 1000000000L) {
+ ts.tv_nsec -= 1000000000L;
+ ts.tv_sec++;
+ }
+
+ for(;;) { /* Ignore spurious wakeups */
+ if ((rv = pthread_cond_timedwait(&req.cond, &req.lock, &ts)) != 0) {
+ if (rv != ETIMEDOUT) {
+ a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_timedwait failed with %d\n",rv);
+ (*p->usbd->interfaces[iix])->AbortPipe(p->usbd->interfaces[iix], pno);
+ req.result = kIOReturnAborted;
+ reqrv = ICOM_SYS;
+ break;
+ }
+
+ /* Timed out */
+ a1logd(p->log, 8, "coms_usb_transaction: time out - aborting io\n");
+ (*p->usbd->interfaces[iix])->AbortPipe(p->usbd->interfaces[iix], pno);
+ reqrv = ICOM_TO;
+ /* Wait for the cancelled io to be signalled */
+ if ((rv = pthread_cond_wait(&req.cond, &req.lock)) != 0) {
+ pthread_mutex_unlock(&req.lock);
+ a1logd(p->log, 1, "coms_usb_transaction: pthread_cond_wait failed with %d\n",rv);
+ req.result = kIOReturnAborted;
+ reqrv = ICOM_SYS;
+ break;
+ }
+ break;
+ }
+ if (req.done) /* Ignore spurious wakeups */
+ break;
+ }
+ }
+ pthread_mutex_unlock(&req.lock);
+
+ a1logd(p->log, 8, "coms_usb_transaction: completed with reqrv 0x%x and xlength %d\n",req.result,req.xlength);
+
+ /* If io was aborted, ClearPipeStall */
+ if (req.result == kIOReturnAborted) {
+#if defined(NEVER) && (InterfaceVersion > 182)
+ (*p->usbd->interfaces[iix])->ClearPipeStallBothEnds(p->usbd->interfaces[iix], pno);
+#else
+ (*p->usbd->interfaces[iix])->ClearPipeStall(p->usbd->interfaces[iix], pno);
+ icoms_usb_control_msg(p, NULL, IUSB_REQ_HOST_TO_DEV | IUSB_REQ_TYPE_STANDARD
+ | IUSB_REQ_RECIP_ENDPOINT, IUSB_REQ_CLEAR_FEATURE,
+ IUSB_FEATURE_EP_HALT, endpoint, NULL, 0, 200);
+#endif
+ if (reqrv == ICOM_OK) /* If not aborted for a known reason, must be cancelled */
+ reqrv = ICOM_CANC;
+ }
+
+ /* If normal completion - not timed out or aborted */
+ if (reqrv == ICOM_OK) { /* Completed OK */
+ if (req.result == kIOReturnSuccess) {
+ if (req.xlength != length)
+ reqrv = ICOM_SHORT;
+ } else {
+ if (dirw)
+ reqrv = ICOM_USBW;
+ else
+ reqrv = ICOM_USBR;
+ }
+ }
+
+ if (transferred != NULL)
+ *transferred = req.xlength;
+
+done:;
+ if (cancelt != NULL) {
+ usb_lock_cancel(cancelt);
+ cancelt->hcancel = (void *)NULL;
+ usb_unlock_cancel(cancelt);
+ }
+
+ pthread_cond_destroy(&req.cond);
+ pthread_mutex_destroy(&req.lock);
+
+ if (in_usb_rw < 0)
+ exit(0);
+
+ in_usb_rw--;
+
+ a1logd(p->log, 8, "coms_usb_transaction: returning err 0x%x and %d bytes\n",reqrv, req.xlength);
+
+ return reqrv;
+}
+
+
+/* Our control message routine */
+/* Return error icom error code */
+static int icoms_usb_control_msg(
+icoms *p,
+int *transferred,
+int requesttype, int request,
+int value, int index, unsigned char *bytes, int size,
+int timeout) {
+ int reqrv = ICOM_OK;
+ int dirw = (requesttype & IUSB_REQ_DIR_MASK) == IUSB_REQ_HOST_TO_DEV ? 1 : 0;
+ IOReturn rv;
+ IOUSBDevRequestTO req;
+
+ a1logd(p->log, 8, "icoms_usb_control_msg: type 0x%x req 0x%x size %d\n",requesttype,request,size);
+ bzero(&req, sizeof(req));
+ req.bmRequestType = requesttype;
+ req.bRequest = request;
+ req.wValue = value;
+ req.wIndex = index;
+ req.wLength = size;
+ req.pData = bytes;
+ req.completionTimeout = timeout;
+ req.noDataTimeout = timeout;
+
+ if (transferred != NULL)
+ *transferred = 0;
+
+ if ((rv = (*(p->usbd->device))->DeviceRequestTO(p->usbd->device, &req)) != kIOReturnSuccess) {
+ if (rv == kIOUSBTransactionTimeout) {
+ reqrv = ICOM_TO;
+ } else {
+ if (dirw)
+ reqrv = ICOM_USBW;
+ else
+ reqrv = ICOM_USBR;
+ }
+ } else {
+ if (transferred != NULL)
+ *transferred = req.wLenDone;
+ }
+
+ a1logd(p->log, 8, "icoms_usb_control_msg: returning err 0x%x and %d bytes\n",reqrv, transferred != NULL ? *transferred : -1);
+ return reqrv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Time out error return value */
+
+//#define USBIO_ERROR_TIMEOUT -ETIMEDOUT
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Cancel i/o in another thread */
+int icoms_usb_cancel_io(
+ icoms *p,
+ usb_cancelt *cancelt
+) {
+ int reqrv = ICOM_OK;
+
+ usb_lock_cancel(cancelt);
+ usbio_req *req = (usbio_req *)cancelt->hcancel;
+ if (req != NULL) {
+ IOReturn rv;
+
+ if ((rv = (*p->usbd->interfaces[req->iix])->AbortPipe(
+ p->usbd->interfaces[req->iix], req->pno)) != kIOReturnSuccess) {
+ reqrv = ICOM_USBW;
+ }
+ }
+ usb_unlock_cancel(cancelt);
+
+ return reqrv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Reset and end point data toggle to 0 */
+int icoms_usb_resetep(
+ icoms *p,
+ int ep /* End point address */
+) {
+ int reqrv = ICOM_OK;
+ int iix = p->EPINFO(ep).interface;
+ UInt8 pno = (UInt8)p->EPINFO(ep).pipe;
+ IOReturn rv;
+
+ if ((rv = (*p->usbd->interfaces[iix])->ResetPipe(
+ p->usbd->interfaces[iix], pno)) != kIOReturnSuccess) {
+ a1logd(p->log, 1, "icoms_usb_resetep failed with 0x%x\n",rv);
+ reqrv = ICOM_USBW;
+ }
+ return reqrv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Clear a halt on an end point */
+int icoms_usb_clearhalt(
+ icoms *p,
+ int ep /* End point address */
+) {
+ int reqrv = ICOM_OK;
+ int iix = p->EPINFO(ep).interface;
+ UInt8 pno = (UInt8)p->EPINFO(ep).pipe;
+ IOReturn rv;
+ int irv;
+
+#if defined(NEVER) && (InterfaceVersion > 182)
+ if ((rv = (*p->usbd->interfaces[iix])->ClearPipeStallBothEnds(
+ p->usbd->interfaces[iix], pno)) != kIOReturnSuccess) {
+ a1logd(p->log, 1, "icoms_usb_clearhalt failed with 0x%x\n",rv);
+ reqrv = ICOM_USBW;
+ }
+#else
+ if ((rv = (*p->usbd->interfaces[iix])->ClearPipeStall(
+ p->usbd->interfaces[iix], pno)) != kIOReturnSuccess) {
+ a1logd(p->log, 1, "icoms_usb_clearhalt failed with 0x%x\n",rv);
+ reqrv = ICOM_USBW;
+ }
+ if ((irv = icoms_usb_control_msg(p, NULL, IUSB_REQ_HOST_TO_DEV | IUSB_REQ_TYPE_STANDARD
+ | IUSB_REQ_RECIP_ENDPOINT, IUSB_REQ_CLEAR_FEATURE,
+ IUSB_FEATURE_EP_HALT, ep, NULL, 0, 200)) != ICOM_OK) {
+ a1logd(p->log, 1, "icoms_usb_clearhalt far end failed with 0x%x\n",irv);
+ reqrv = ICOM_USBW;
+ }
+#endif
+ return reqrv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#ifdef NEVER
+ {
+ IOUSBFindInterfaceRequest req;
+ io_iterator_t ioit;
+
+ /* See if we can find any interfaces */
+ req.bInterfaceClass =
+ req.bInterfaceSubClass =
+ req.bInterfaceProtocol =
+ req.bAlternateSetting = kIOUSBFindInterfaceDontCare;
+
+ if ((rv = (*(p->usbd->device))->CreateInterfaceIterator(
+ p->usbd->device, &req, &ioit)) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: CreateInterfaceIterator failed with 0x%x\n",rv);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ if (IOIteratorNext(ioit) == 0) { /* Configure the device */
+ IOUSBConfigurationDescriptorPtr confdesc;
+
+ if ((rv = (*(p->usbd->device))->GetConfigurationDescriptorPtr(
+ p->usbd->device, config-1, &confdesc)) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: GetConfigurationDescriptorPtr failed with 0x%x\n",rv);
+ IOObjectRelease(ioit);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ if ((rv = (*(p->usbd->device))->SetConfiguration(
+ p->usbd->device, confdesc->bConfigurationValue)) != kIOReturnSuccess) {
+ a1loge(p->log, rv, "usb_open_port: SetConfiguration failed with 0x%x\n",rv);
+ IOObjectRelease(ioit);
+ cleanup_device(p);
+ return ICOM_SYS;
+ }
+ a1logd(p->log, 6, "usb_open_port: SetConfiguration %d OK\n",confdesc->bConfigurationValue);
+
+ } else { /* Some diagnostics */
+ UInt8 confno;
+ if ((rv = (*(p->usbd->device))->GetConfiguration(
+ p->usbd->device, &confno)) != kIOReturnSuccess) {
+ a1logd(p->log, 6, "usb_open_port: GetConfiguration failed with 0x%x\n",rv);
+ } else {
+ a1logd(p->log, 6, "usb_open_port: Device didn't need configuring - currently %d\n",confno);
+ }
+ }
+ IOObjectRelease(ioit);
+
+ }
+#endif /* NEVER */
diff --git a/spectro/vinflate.c b/spectro/vinflate.c
new file mode 100644
index 0000000..847fa28
--- /dev/null
+++ b/spectro/vinflate.c
@@ -0,0 +1,972 @@
+
+/*
+ inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993
+
+ Copied from gzip version 1.2.4 source, and modifed to work with
+ the VIZE installer flavour of DEFLATE by Graeme Gill, October 2007,
+ calling it vinflate.c to distinguish from the original.
+
+ The modifications include reading data 16 bits at a time, big endian,
+ aligning to 16 bits before a stored block, and backing out 16
+ bits at a time at the end of a block.
+
+ (Note that this fails on the latest Spyder2 setup.exe, while
+ the vinflate inside InstExpl.exe works. See
+ http://www.totalcmd.net/plugring/InstallExplorer.html
+ Or does this work now ?)
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef SALONEINSTLIB
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#else /* SALONEINSTLIB */
+#include <fcntl.h>
+#include "sa_config.h"
+#include "numsup.h"
+#endif /* SALONEINSTLIB */
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(text) printf text ;
+#else
+#define DBG(text)
+#endif
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned int ulg;
+
+#define memzero(s, n) memset((void *)(s), 0, (n))
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ unsigned char e; /* number of extra bits or operation */
+ unsigned char b; /* number of bits in this code or subcode */
+ union {
+ unsigned short n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+/* Interface to visetest.c */
+extern unsigned int vget_16bits();
+extern void vunget_16bits();
+extern int vwrite_output(unsigned char *buf, unsigned int len);
+
+/* Function prototypes */
+static int huft_build(unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *);
+static int huft_free(struct huft *);
+static int vinflate_codes(struct huft *, struct huft *, int, int);
+static int vinflate_stored(void);
+static int vinflate_fixed(void);
+static int vinflate_dynamic(void);
+static int vinflate_block(int *);
+int vinflate(void);
+
+/*
+ The inflate algorithm uses a sliding 32K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ and'ing with 0x7fff (32K-1).
+ It is left to other modules to supply the 32K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case.
+*/
+
+#define WSIZE 0x8000
+unsigned int wp; /* current position in slide */
+uch slide[32768];
+
+static int vflush_output(unsigned int w) {
+ wp = w;
+
+ if (wp == 0)
+ return 0;
+ if (vwrite_output(slide, wp))
+ return 1;
+ DBG(("Flushed %d byte sof ouput\n",wp))
+ wp = 0;
+
+ return 0;
+}
+
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+static ush cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & vmask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+ulg bb; /* bit buffer */
+unsigned bk; /* bits in bit buffer */
+
+ush vmask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#ifdef NEVER
+#define NEEDBITS(n) { \
+ while(k < (n)) { \
+ unsigned int nv; \
+ nv = vget_16bits(); \
+ if (nv == 0x11111111) { \
+ printf("\nnoticed end\n"); \
+ /* return 2; */ \
+ } \
+ b |= ((ulg)nv) << k; \
+ k += 16; \
+ } \
+}
+#else
+#define NEXTBYTE() (uch)vget_16bits()
+//#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=16;}}
+#define NEEDBITS(n) { \
+ while(k < (n)) { \
+ unsigned int ttt; \
+ ttt = (ulg) (0xffff & vget_16bits()); \
+ b |= ttt << k; \
+ k += 16; \
+ } \
+}
+#endif
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables vlbits and vdbits
+ below. vlbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and vdbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so vlbits is 8+1 and vdbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+int vlbits = 9; /* bits in base literal/length lookup table */
+int vdbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+unsigned hufts; /* track memory usage */
+
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+/* return nz (2 ?) on error */
+static int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+ush *d; /* list of base values for non-simple codes */
+ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+
+ for (i = 0; i < BMAX; i++) {
+ u[i] = NULL;
+ x[i] = c[i] = 0;
+ }
+ x[i] = c[i] = 0;
+
+ for (i = 0; i < N_MAX; i++)
+ v[i] = 0;
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+ p = b; i = n;
+ do {
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0) {
+ return 2; /* bad input: more codes than bits */
+ }
+ if ((y -= c[i]) < 0) {
+ return 2;
+ }
+ c[i] += y;
+
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+ a = c[k];
+ while (a--)
+ {
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+ (struct huft *)NULL)
+ {
+ if (h)
+ huft_free(u[0]);
+ return 3; /* not enough memory */
+ }
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch)l; /* bits to dump before this table */
+ r.e = (uch)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+ }
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush)(*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ }
+ else
+ {
+ if (e == NULL) {
+ return 2; /* Some sort of error */
+ }
+ r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+ }
+ }
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+
+static int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ free((char*)p);
+ p = q;
+ }
+ return 0;
+}
+
+
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+static int vinflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = vmask_bits[bl]; /* precompute masks for speed */
+ md = vmask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl)
+ if (tl == NULL) {
+ DBG(("Huffman table is NULL\n"))
+ return 2;
+ }
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99) {
+ DBG(("Huffman table returned 99\n"))
+ return 1;
+ }
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & vmask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch)t->v.n;
+ if (w == WSIZE)
+ {
+ if (vflush_output(w)) {
+ DBG(("Buffer was unexpectedly large\n"))
+ return 1;
+ }
+ w = 0;
+ }
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & vmask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99) {
+ DBG(("Huffman table returned 99\n"))
+ return 1;
+ }
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & vmask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & vmask_bits[e]);
+ DUMPBITS(e)
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) /* (this test assumes unsigned comparison) */
+ {
+ memmove(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+ } while (--e);
+ if (w == WSIZE)
+ {
+ if (vflush_output(w)) {
+ DBG(("Buffer was unexpectedly large\n"))
+ return 1;
+ }
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+
+
+static int vinflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+
+ /* go to 16 byte boundary */
+ n = k & 15;
+ DUMPBITS(n);
+
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff)) {
+ DBG(("Stored block length comlpement doesn't match\n"))
+ return 1; /* error in compressed data */
+ }
+ DUMPBITS(16)
+
+
+ /* read and output the compressed data */
+ while (n--)
+ {
+ NEEDBITS(8)
+ slide[w++] = (uch)b;
+ if (w == WSIZE)
+ {
+ if (vflush_output(w)) {
+ DBG(("Buffer was unexpectedly large\n"))
+ return 1;
+ }
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+ return 0;
+}
+
+
+
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+static int vinflate_fixed()
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ return i;
+
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ huft_free(tl);
+ return i;
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (vinflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+static int vinflate_dynamic()
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30) {
+#endif
+ DBG(("Bad block type nl = %d, nd = %d\n",nl,nd))
+ return 1; /* bad lengths */
+ }
+
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if (i == 1)
+ huft_free(tl);
+ DBG(("Incomplete code set\n"))
+ return i; /* incomplete code set */
+ }
+
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = vmask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl)
+ if (tl == NULL) {
+ DBG(("Huffman table is NULL\n"))
+ return 2;
+ }
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n) {
+ DBG(("Repeat length %d is bad\n",i))
+ return 1;
+ }
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n) {
+ DBG(("Repeat length %d is bad\n",i))
+ return 1;
+ }
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n) {
+ DBG(("Repeat length %d is bad\n",i))
+ return 1;
+ }
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = vlbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+ if (i == 1) {
+ huft_free(tl);
+ }
+ DBG(("Incomplete litteral tree\n"))
+ return i; /* incomplete code set */
+ }
+ bd = vdbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+ if (i == 1) {
+// fprintf(stderr, " incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ DBG(("Incomplete code set\n"))
+ return i; /* incomplete code set */
+#endif
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (vinflate_codes(tl, td, bl, bd)) {
+ DBG(("vinflate_codes failed\n"))
+ return 1;
+ }
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+/* decompress an inflated block */
+static int vinflate_block(e)
+int *e; /* last block flag */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ *e = (int)b & 1;
+ DUMPBITS(1)
+
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+
+ /* inflate that block type */
+ if (t == 2)
+ return vinflate_dynamic();
+ if (t == 0)
+ return vinflate_stored();
+
+#ifdef NEVER
+ /* Apparently VISE doesn't use this */
+ if (t == 1) {
+ printf("WARNING: vinflate fixed found\n");
+ return vinflate_fixed();
+ }
+#endif
+
+ /* bad block type */
+ DBG(("Bad block type %d\n",t))
+ return 2;
+}
+
+/* decompress an inflated entry */
+/* return nz on error */
+int vinflate()
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ if ((r = vinflate_block(&e)) != 0)
+ return r;
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 16) {
+ bk -= 16;
+ vunget_16bits();
+ }
+
+ /* flush out slide */
+ if (vflush_output(wp)) {
+ DBG(("Buffer was unexpectedly large\n"))
+ return 1;
+ }
+
+ /* return success */
+ return 0;
+}
diff --git a/spectro/webwin.c b/spectro/webwin.c
new file mode 100644
index 0000000..d90239a
--- /dev/null
+++ b/spectro/webwin.c
@@ -0,0 +1,455 @@
+
+
+/*
+ * Argyll Color Correction System
+ * Web Display target patch window
+ *
+ * Author: Graeme W. Gill
+ * Date: 3/4/12
+ *
+ * Copyright 2013 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#ifdef NT
+# include <winsock2.h>
+#endif
+#ifdef UNIX
+# include <sys/types.h>
+# include <ifaddrs.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# ifdef __FreeBSD__
+# include <sys/socket.h>
+# endif /* __FreeBSD__ */
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "icc.h"
+#include "numsup.h"
+#include "cgats.h"
+#include "conv.h"
+#include "dispwin.h"
+#include "conv.h"
+#include "mongoose.h"
+
+#undef DEBUG
+//#define STANDALONE_TEST
+
+#ifdef DEBUG
+#define errout stderr
+# define debug(xx) fprintf(errout, xx )
+# define debug2(xx) fprintf xx
+# define debugr(xx) fprintf(errout, xx )
+# define debugr2(xx) fprintf xx
+# define debugrr(xx) fprintf(errout, xx )
+# define debugrr2(xx) fprintf xx
+# define debugrr2l(lev, xx) fprintf xx
+#else
+#define errout stderr
+# define debug(xx)
+# define debug2(xx)
+# define debugr(xx) if (p->ddebug) fprintf(errout, xx )
+# define debugr2(xx) if (p->ddebug) fprintf xx
+# define debugrr(xx) if (callback_ddebug) fprintf(errout, xx )
+# define debugrr2(xx) if (callback_ddebug) fprintf xx
+# define debugrr2l(lev, xx) if (callback_ddebug >= lev) fprintf xx
+#endif
+
+// A handler for the /ajax/get_messages endpoint.
+// Return a list of messages with ID greater than requested.
+static void ajax_get_messages(struct mg_connection *conn,
+ const struct mg_request_info *request_info) {
+char src_addr[20];
+
+// dispwin *p = (dispwin *)(request_info->user_data);
+ dispwin *p = (dispwin *)mg_get_user_data(conn);
+
+//sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+
+// printf("ajax_messages query_string '%s'\n",request_info->query_string);
+
+ p->ccix++;
+
+ while(p->ncix == p->ccix && p->mg_stop == 0) {
+ msec_sleep(50);
+ }
+
+ mg_printf(conn,
+ "\r\n#%02X%02X%02X",
+ (int)(p->r_rgb[0] * 255.0 + 0.5),
+ (int)(p->r_rgb[1] * 255.0 + 0.5),
+ (int)(p->r_rgb[2] * 255.0 + 0.5));
+}
+
+/* Event handler */
+static void *webwin_ehandler(enum mg_event event,
+ struct mg_connection *conn) {
+// const struct mg_request_info *request_info) {
+ const struct mg_request_info *request_info = mg_get_request_info(conn);
+
+ if (event != MG_NEW_REQUEST) {
+ return NULL;
+ }
+#ifdef DEBUG
+ printf("Got event with uri = '%s'\n",request_info->uri);
+#endif
+ if (strcmp(request_info->uri, "/ajax/messages") == 0) {
+ ajax_get_messages(conn, request_info);
+ } else if (strcmp(request_info->uri, "/webdisp.js") == 0) {
+#ifndef NEVER
+ char *webdisp_js =
+ "\r\n"
+ "if (typeof XMLHttpRequest == \"undefined\") {\r\n"
+ " XMLHttpRequest = function () {\r\n"
+ " try { return new ActiveXObject(\"Msxml2.XMLHTTP.6.0\"); }\r\n"
+ " catch (e) {}\r\n"
+ " try { return new ActiveXObject(\"Msxml2.XMLHTTP.3.0\"); }\r\n"
+ " catch (e) {}\r\n"
+ " try { return new ActiveXObject(\"Microsoft.XMLHTTP\"); }\r\n"
+ " catch (e) {}\r\n"
+ " throw new Error(\"This browser does not support XMLHttpRequest.\");\r\n"
+ " };\r\n"
+ "}\r\n"
+ "\r\n"
+ "var ccolor = \"\";\r\n"
+ "var oXHR;\r\n"
+ "\r\n"
+ "function XHR_response() {\r\n"
+ " if (oXHR.readyState != 4)\r\n"
+ " return;\r\n"
+ "\r\n"
+ " if (oXHR.status != 200) {\r\n"
+ " return;\r\n"
+ " }\r\n"
+ " var rt = oXHR.responseText;\r\n"
+ " if (rt.charAt(0) == '\\r' && rt.charAt(1) == '\\n')\r\n"
+ " rt = rt.slice(2);\r\n"
+ " if (ccolor != rt) {\r\n"
+ " ccolor = rt;\r\n"
+ " document.body.style.background = ccolor;\r\n"
+ " }\r\n"
+ " oXHR.open(\"GET\", \"/ajax/messages?\" + document.body.style.background + \" \" + Math.random(), true);\r\n"
+ " oXHR.onreadystatechange = XHR_response;\r\n"
+ " oXHR.send();\r\n"
+ "}\r\n"
+ "\r\n"
+ "window.onload = function() {\r\n"
+ " ccolor = \"#808080\";\r\n"
+ " document.body.style.background = ccolor;\r\n"
+ "\r\n"
+ " oXHR = new XMLHttpRequest();\r\n"
+ " oXHR.open(\"GET\", \"/ajax/messages?\" + document.body.style.background, true);\r\n"
+ " oXHR.onreadystatechange = XHR_response;\r\n"
+ " oXHR.send();\r\n"
+ "};\r\n";
+ mg_write(conn, webdisp_js, strlen(webdisp_js));
+#else
+ return NULL; /* Read webdisp.js */
+#endif
+ } else {
+ mg_printf(conn, "HTTP/1.1 200 OK\r\n"
+ "Cache-Control: no-cache\r\n"
+ "Content-Type: text/html\r\n\r\n"
+ "<html>\r\n"
+ "<head>\r\n"
+ "<title>ArgyllCMS Web Display</title>\r\n"
+ "<script src=\"webdisp.js\"></script>\r\n"
+ "</head>\r\n"
+ "</html>\r\n"
+ );
+ }
+
+// "<script type=\"text/javascript\"src=\"webdisp.js\"></script>"
+ return "yes";
+}
+
+/* ----------------------------------------------- */
+
+/* Get RAMDAC values. ->del() when finished. */
+/* Return NULL if not possible */
+static ramdac *webwin_get_ramdac(dispwin *p) {
+ debugr("webdisp doesn't have a RAMDAC\n");
+ return NULL;
+}
+
+/* Set the RAMDAC values. */
+/* Return nz if not possible */
+static int webwin_set_ramdac(dispwin *p, ramdac *r, int persist) {
+ debugr("webdisp doesn't have a RAMDAC\n");
+ return 1;
+}
+
+/* ----------------------------------------------- */
+/* Install a display profile and make */
+/* it the default for this display. */
+/* Return nz if failed */
+int webwin_install_profile(dispwin *p, char *fname, ramdac *r, p_scope scope) {
+ debugr("webdisp doesn't support installing profiles\n");
+ return 1;
+}
+
+/* Un-Install a display profile */
+/* Return nz if failed, */
+int webwin_uninstall_profile(dispwin *p, char *fname, p_scope scope) {
+ debugr("webdisp doesn't support uninstalling profiles\n");
+ return 1;
+}
+
+/* Get the currently installed display profile. */
+/* Return NULL if failed. */
+icmFile *webwin_get_profile(dispwin *p, char *name, int mxlen) {
+ debugr("webdisp doesn't support getting the current profile\n");
+ return NULL;
+}
+
+/* ----------------------------------------------- */
+
+/* Change the window color. */
+/* Return 1 on error, 2 on window being closed */
+static int webwin_set_color(
+dispwin *p,
+double r, double g, double b /* Color values 0.0 - 1.0 */
+) {
+ int j;
+
+ debugr("webwin_set_color called\n");
+
+ if (p->nowin)
+ return 1;
+
+ p->rgb[0] = r;
+ p->rgb[1] = g;
+ p->rgb[2] = b;
+
+ for (j = 0; j < 3; j++) {
+ if (p->rgb[j] < 0.0)
+ p->rgb[j] = 0.0;
+ else if (p->rgb[j] > 1.0)
+ p->rgb[j] = 1.0;
+ p->r_rgb[j] = p->rgb[j];
+ }
+
+ /* This is probably not actually thread safe... */
+ p->ncix++;
+
+ while(p->ncix != p->ccix) {
+ msec_sleep(50);
+ }
+
+ /* Allow some time for the display to update before */
+ /* a measurement can take place. This allows time for */
+ /* the browser to update the background color, the CRT */
+ /* refresh or LCD processing/update time, + */
+ /* display settling time (quite long for smaller LCD changes). */
+ msec_sleep(200);
+
+ return 0;
+}
+
+/* ----------------------------------------------- */
+/* Set an update delay, and return the previous value */
+/* Value can be set to zero, but othewise will be forced */
+/* to be >= min_update_delay */
+static int webwin_set_update_delay(
+dispwin *p,
+int update_delay) {
+ int cval = p->update_delay;
+ p->update_delay = update_delay;
+ if (update_delay != 0 && p->update_delay < p->min_update_delay)
+ p->update_delay = p->min_update_delay;
+ return cval;
+}
+
+/* ----------------------------------------------- */
+/* Set the shell set color callout */
+void webwin_set_callout(
+dispwin *p,
+char *callout
+) {
+ debugr2((errout,"webwin_set_callout called with '%s'\n",callout));
+
+ p->callout = strdup(callout);
+}
+
+/* ----------------------------------------------- */
+/* Destroy ourselves */
+static void webwin_del(
+dispwin *p
+) {
+
+ debugr("webwin_del called\n");
+
+ if (p == NULL)
+ return;
+
+ p->mg_stop = 1;
+ mg_stop((struct mg_context *)p->pcntx);
+
+ if (p->name != NULL)
+ free(p->name);
+ if (p->description != NULL)
+ free(p->description);
+ if (p->callout != NULL)
+ free(p->callout);
+
+ free(p);
+}
+
+/* ----------------------------------------------- */
+
+/* Create a web display test window, default grey */
+dispwin *new_webwin(
+int webdisp, /* Port number */
+double width, double height, /* Width and height in mm */
+double hoff, double voff, /* Offset from center in fraction of screen, range -1.0 .. 1.0 */
+int nowin, /* NZ if no window should be created - RAMDAC access only */
+int blackbg, /* NZ if whole screen should be filled with black */
+int verb, /* NZ for verbose prompts */
+int ddebug /* >0 to print debug statements to stderr */
+) {
+ dispwin *p = NULL;
+ char *cp;
+ struct mg_context *mg;
+ const char *options[3];
+ char port[50];
+
+ debug("new_webwin called\n");
+
+ if ((p = (dispwin *)calloc(sizeof(dispwin), 1)) == NULL) {
+ if (ddebug) fprintf(stderr,"new_webwin failed because malloc failed\n");
+ return NULL;
+ }
+
+ /* !!!! Make changes in dispwin.c as well !!!! */
+ p->name = strdup("Web Window");
+ p->nowin = nowin;
+ p->native = 0;
+ p->blackbg = blackbg;
+ p->ddebug = ddebug;
+ p->get_ramdac = webwin_get_ramdac;
+ p->set_ramdac = webwin_set_ramdac;
+ p->install_profile = webwin_install_profile;
+ p->uninstall_profile = webwin_uninstall_profile;
+ p->get_profile = webwin_get_profile;
+ p->set_color = webwin_set_color;
+ p->set_update_delay = webwin_set_update_delay;
+ p->set_callout = webwin_set_callout;
+ p->del = webwin_del;
+
+ p->rgb[0] = p->rgb[1] = p->rgb[2] = 0.5; /* Set Grey as the initial test color */
+
+ p->min_update_delay = 20;
+
+ if ((cp = getenv("ARGYLL_MIN_DISPLAY_UPDATE_DELAY_MS")) != NULL) {
+ p->min_update_delay = atoi(cp);
+ if (p->min_update_delay < 20)
+ p->min_update_delay = 20;
+ if (p->min_update_delay > 60000)
+ p->min_update_delay = 60000;
+ debugr2((errout, "new_webwin: Minimum display update delay set to %d msec\n",p->min_update_delay));
+ }
+
+ p->update_delay = DISPLAY_UPDATE_DELAY; /* Default update delay */
+ if (p->update_delay < p->min_update_delay)
+ p->update_delay = p->min_update_delay;
+
+ p->ncix = 1;
+
+ /* Basic object is initialised, so create a web server */
+
+ options[0] = "listening_ports";
+ sprintf(port,"%d", webdisp);
+ options[1] = port;
+ options[2] = NULL;
+
+ mg = mg_start(&webwin_ehandler, (void *)p, options);
+ p->pcntx = (void *)mg;
+
+//printf("Domain = %s'\n",mg_get_option(mg, "authentication_domain"));
+
+ /* Create a suitable description */
+#if NT
+ {
+ char szHostName[255];
+ struct hostent *host_entry;
+ char *localIP;
+ char buf[1000];
+
+ /* We assume WinSock has been started by mongoose */
+
+ // Get the local hostname
+ gethostname(szHostName, 255);
+ host_entry=gethostbyname(szHostName);
+ /* Get first entry */
+ localIP = inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list);
+
+ sprintf(buf,"Web Window at http://%s:%d",localIP,webdisp);
+ p->description = strdup(buf);
+
+ if (verb)
+ printf("Created web server at 'http://%s:%d', now waiting for browser to connect\n",localIP,webdisp);
+ }
+#else
+ {
+ struct ifaddrs * ifAddrStruct=NULL;
+ struct ifaddrs * ifa=NULL;
+ void *tmpAddrPtr=NULL;
+ char abuf[INET_ADDRSTRLEN] = "";
+ char abuf6[INET6_ADDRSTRLEN] = "";
+ char *addr = abuf;
+ char buf[1000];
+
+ getifaddrs(&ifAddrStruct);
+
+ /* Stop at the first non local adderss */
+ for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
+#ifdef AF_INET6
+ if (ifa->ifa_addr->sa_family==AF_INET) { /* IP4 ? */
+#endif
+ if (strncmp(ifa->ifa_name, "lo",2) == 0 || abuf[0] != '\000')
+ continue;
+ tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+ inet_ntop(AF_INET, tmpAddrPtr, abuf, INET_ADDRSTRLEN);
+// printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
+#ifdef AF_INET6
+ } else if (ifa->ifa_addr->sa_family==AF_INET6) { /* IP6 ? */
+ if (strncmp(ifa->ifa_name, "lo",2) == 0 || abuf6[0] != '\000')
+ continue;
+ tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+ inet_ntop(AF_INET6, tmpAddrPtr, abuf6, INET6_ADDRSTRLEN);
+// printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
+ }
+#endif
+ }
+ if (ifAddrStruct!=NULL)
+ freeifaddrs(ifAddrStruct);
+ if (addr[0] == '\000')
+ addr = abuf6;
+ if (addr[0] == '\000')
+ addr = "Unknown";
+
+ sprintf(buf,"Web Window at http://%s:%d",addr,webdisp);
+ p->description = strdup(buf);
+
+ if (verb)
+ printf("Created web server at 'http://%s:%d', now waiting for browser to connect\n",addr,webdisp);
+ }
+#endif
+
+ /* Wait for the web server to connect */
+ debugr("new_webwin: waiting for web browser to connect\n");
+ while(p->ccix == 0) {
+ msec_sleep(50);
+ }
+
+ debugr("new_webwin: return sucessfully\n");
+
+ return p;
+}
+
diff --git a/spectro/webwin.h b/spectro/webwin.h
new file mode 100644
index 0000000..b298397
--- /dev/null
+++ b/spectro/webwin.h
@@ -0,0 +1,31 @@
+
+#ifndef WEBWIN_H
+
+/*
+ * Argyll Color Correction System
+ * Web Display target patch window
+ *
+ * Author: Graeme W. Gill
+ * Date: 3/4/12
+ *
+ * Copyright 2013 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.
+ */
+
+
+/* Create a web display test window, default grey */
+dispwin *new_webwin(
+int webdisp, /* Port number */
+double width, double height, /* Width and height in mm */
+double hoff, double voff, /* Offset from center in fraction of screen, range -1.0 .. 1.0 */
+int nowin, /* NZ if no window should be created - RAMDAC access only */
+int blackbg, /* NZ if whole screen should be filled with black */
+int verb, /* NZ for verbose prompts */
+int ddebug /* >0 to print debug statements to stderr */
+);
+
+#define WEBWIN_H
+#endif /* WEBWIN_H */
diff --git a/spectro/xdg_bds.c b/spectro/xdg_bds.c
new file mode 100644
index 0000000..9d81291
--- /dev/null
+++ b/spectro/xdg_bds.c
@@ -0,0 +1,1088 @@
+
+ /* XDG Base Directory Specifications support library. */
+ /* Implements equivalent cross platform functionality too. */
+
+/*************************************************************************
+ Copyright 2011, 2013 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+/*
+ This function provides support for the XDG Base Directory Specifications
+ in a cross platform compatible way.
+
+ [ Note that for MSWin each path in a set is separated by a ';' character.
+ and that DATA and CONF will be in the same directory. ]
+
+ The following paths are used for each of the 5 XDG concepts, listed in order
+ of priority:
+
+ Per user application related data.
+
+ Per user application configuration settings.
+
+ Per user application cache storage area.
+
+ Local system wide application related data.
+
+ Local system wide application configuration settings.
+
+ Unix:
+ $XDG_DATA_HOME
+ $HOME/.local/share
+
+ $XDG_CONF_HOME
+ $HOME/.config
+
+ $XDG_CACHE_HOME
+ $HOME/.cache
+
+ $XDG_DATA_DIRS
+ /usr/local/share:/usr/share
+
+ $XDG_CONF_DIRS
+ /etc/xdg
+
+ OS X:
+ $XDG_DATA_HOME
+ $HOME/Library/Application Support
+
+ $XDG_CONF_HOME
+ $HOME/Library/Preferences
+
+ $XDG_CACHE_HOME
+ $HOME/Library/Caches
+
+ $XDG_DATA_DIRS
+ /Library/Application Support
+
+ $XDG_CONF_DIRS
+ /Library/Preferences
+
+ MSWin:
+ $XDG_DATA_HOME
+ $APPDATA
+ $HOME/.local/share
+
+ $XDG_CONF_HOME
+ $APPDATA
+ $HOME/.config
+
+ $XDG_CACHE_HOME
+ $APPDATA/Cache
+ $HOME/.cache
+
+ $XDG_DATA_DIRS
+ $ALLUSERSPROFILE
+
+ $XDG_CONF_DIRS
+ $ALLUSERSPROFILE
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <signal.h>
+#ifndef NT
+# include <unistd.h>
+# include <glob.h>
+#else
+# include <io.h>
+# include <direct.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "numsup.h"
+#include "conv.h"
+#include "aglob.h"
+#include "xdg_bds.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBGA g_log, 0
+#define DBG(xxx) a1logd xxx ;
+#else
+#define DBG(xxx)
+#endif /* DEBUG */
+
+#ifdef NT
+# define stat _stat
+# define mode_t int
+# define mkdir(A,B) _mkdir(A)
+# define mputenv _putenv
+# define unlink _unlink
+# define rmdir _rmdir
+#else
+/* UNIX putenv is a pain.. */
+static void mputenv(char *ss) {
+ int ll = strlen(ss);
+ ss = strdup(ss);
+ if (ll > 0 && ss[ll-1]== '=') {
+ ss[ll-1] = '\000';
+ unsetenv(ss);
+ } else {
+ putenv(ss);
+ }
+}
+#endif
+
+/* Allocate a copy of the string, and normalize the */
+/* path separator to '/' */
+
+/* Append a string. Free in. Return NULL on error. */
+static char *append(char *in, char *app) {
+ char *rv;
+
+ if ((rv = malloc(strlen(in) + strlen(app) + 1)) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: append malloc failed\n");
+ free(in);
+ return NULL;
+ }
+ strcpy(rv, in);
+ strcat(rv, app);
+ free(in);
+
+ return rv;
+}
+
+/* Append a ':' or ';' then a string. Free in. Return NULL on error. */
+static char *cappend(char *in, char *app) {
+ int inlen;
+ char *rv;
+
+ inlen = strlen(in);
+
+ if ((rv = malloc(inlen + 1 + strlen(app) + 1)) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: cappend malloc failed\n");
+ free(in);
+ return NULL;
+ }
+ strcpy(rv, in);
+ if (inlen > 1)
+ strcat(rv, SSEPS);
+ strcat(rv, app);
+ free(in);
+
+ return rv;
+}
+
+/* Append a '/' then a string. Free in. Return NULL on error. */
+static char *dappend(char *in, char *app) {
+ int inlen;
+ char *rv;
+
+ inlen = strlen(in);
+
+ if ((rv = malloc(inlen + 1 + strlen(app) + 1)) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: dappend malloc failed\n");
+ free(in);
+ return NULL;
+ }
+ strcpy(rv, in);
+ if (inlen > 1 && in[inlen-1] != '/')
+ strcat(rv, "/");
+ strcat(rv, app);
+ free(in);
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Do internal cleanup */
+static void xdg_ifree(char ***paths, char **fnames, int nopaths) {
+ int i;
+
+ if (paths != NULL) {
+ if (*paths != NULL) {
+ for (i = 0; i < nopaths; i++) {
+ if ((*paths)[i] != NULL)
+ free ((*paths)[i]);
+ }
+ }
+ free(*paths);
+ *paths = NULL;
+ }
+ if (fnames != NULL) {
+ for (i = 0; i < nopaths; i++) {
+ if (fnames[i] != NULL)
+ free (fnames[i]);
+ }
+ free(fnames);
+ }
+}
+
+/* Free a return value */
+void xdg_free(char **paths, int nopaths) {
+ int i;
+
+ if (paths != NULL) {
+ for (i = 0; i < nopaths; i++) {
+ if (paths[i] != NULL)
+ free (paths[i]);
+ }
+ free(paths);
+ }
+}
+
+/* Return the number of matching full paths to the given subpath for the */
+/* type of storage and access required. Return 0 if there is an error. */
+/* The files are always unique (ie. the first match to a given filename */
+/* in the possible XDG list of directories is returned, and files with */
+/* the same name in other XDG directories are ignored) */
+/* Wildcards should not be used for xdg_write. */
+/* The list should be free'd using xdg_free() after use. */
+/* XDG environment variables and the subpath are assumed to be using */
+/* the '/' path separator. Multiple read paths are separated by SSEP */
+/* When "xdg_write", the necessary path to the file will be created. */
+/* If we're running as sudo and are creating a user dir/file, */
+/* we drop to using the underlying SUDO_UID/GID. If we are creating a */
+/* local system dir/file as sudo and have dropped to the SUDO_UID/GID, */
+/* then revert back to root uid/gid. */
+int xdg_bds(
+ xdg_error *er, /* Return an error code */
+ char ***paths, /* Retun array pointers to paths */
+ xdg_storage_type st, /* Specify the storage type */
+ xdg_op_type op, /* Operation type */
+ xdg_scope sc, /* Scope if write */
+ char *pfname /* Sub-path and file name(s) */
+) {
+ char *path = NULL; /* Directory paths to search, separated by ':' or ';' */
+ char **fnames = NULL; /* Filename component of each path being returned */
+ int npaths = 0; /* Number of paths being returned */
+ int napaths = 0; /* Number of paths allocated */
+
+ DBG((DBGA,"xdg_bds called with st %s, op %s, sc %s, pfnames '%s'\n",
+ st == xdg_data ? "data" : st == xdg_conf ? "config" : st == xdg_cache ? "cache" : "unknown",
+ op == xdg_write ? "write" : op == xdg_read ? "read" : "unknown",
+ sc == xdg_user ? "user" : sc == xdg_local ? "local" : "unknown",
+ pfname))
+
+ *paths = NULL;
+
+ /* Initial, empty path */
+ if ((path = strdup("")) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+
+ /* Create a set of ':'/';' separated search paths */
+
+ /* User scope */
+ if (op == xdg_read || sc == xdg_user) {
+ if (st == xdg_data) {
+ char *xdg, *home;
+ if ((xdg = getenv("XDG_DATA_HOME")) != NULL) {
+ if ((path = cappend(path, xdg)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#ifdef NT
+ } else if (getenv("HOME") == NULL && (xdg = getenv("APPDATA")) != NULL) {
+ if ((path = cappend(path, xdg)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#endif
+ } else {
+ if ((home = getenv("HOME")) == NULL
+#ifdef NT
+ && (home = getenv("APPDATA")) == NULL
+#endif
+ ) {
+ if (er != NULL) *er = xdg_nohome;
+ free(path);
+ DBG((DBGA,"no $HOME\n"))
+ return 0;
+ }
+ if ((path = cappend(path, home)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#ifdef NT
+ if (getenv("HOME") != NULL)
+ path = dappend(path, ".local/share");
+#else
+#ifdef __APPLE__
+ path = dappend(path, "Library/Application Support");
+#else /* Unix, Default */
+ path = dappend(path, ".local/share");
+#endif
+#endif
+ if (path == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+ }
+ } else if (st == xdg_conf) {
+ char *xdg, *home;
+ if ((xdg = getenv("XDG_CONF_HOME")) != NULL) {
+ if ((path = cappend(path, xdg)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#ifdef NT
+ } else if (getenv("HOME") == NULL && (xdg = getenv("APPDATA")) != NULL) {
+ if ((path = cappend(path, xdg)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#endif
+ } else {
+ if ((home = getenv("HOME")) == NULL
+#ifdef NT
+ && (home = getenv("APPDATA")) == NULL
+#endif
+ ) {
+ if (er != NULL) *er = xdg_nohome;
+ free(path);
+ DBG((DBGA,"no $HOME\n"))
+ return 0;
+ }
+ if ((path = cappend(path, home)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#ifdef NT
+ if (getenv("HOME") != NULL)
+ path = dappend(path, ".config");
+#else
+#ifdef __APPLE__
+ path = dappend(path, "Library/Preferences");
+#else /* Unix, Default */
+ path = dappend(path, ".config");
+#endif
+#endif
+ if (path == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+ }
+ } else if (st == xdg_cache) {
+ char *xdg, *home;
+ if ((xdg = getenv("XDG_CACHE_HOME")) != NULL) {
+ if ((path = cappend(path, xdg)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#ifdef NT
+ } else if (getenv("HOME") == NULL && (xdg = getenv("APPDATA")) != NULL) {
+ if ((path = cappend(path, xdg)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+ if ((path = dappend(path, "Cache")) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#endif
+ } else {
+ if ((home = getenv("HOME")) == NULL
+#ifdef NT
+ && (home = getenv("APPDATA")) == NULL
+#endif
+ ) {
+ if (er != NULL) *er = xdg_nohome;
+ free(path);
+ DBG((DBGA,"no $HOME\n"))
+ return 0;
+ }
+ if ((path = cappend(path, home)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+#ifdef NT
+ if (getenv("HOME") != NULL)
+ path = dappend(path, ".cache");
+ else
+ path = dappend(path, "Cache");
+#else
+#ifdef __APPLE__
+ path = dappend(path, "Library/Caches");
+#else /* Unix, Default */
+ path = dappend(path, ".cache");
+#endif
+#endif
+ if (path == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+ }
+ }
+ }
+ /* Local system scope */
+ if (op == xdg_read || sc == xdg_local) {
+ char *xdg;
+ if (st == xdg_data) {
+ if ((xdg = getenv("XDG_DATA_DIRS")) != NULL) {
+ if ((path = cappend(path, xdg)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+ } else {
+#ifdef NT
+ /*
+ QT uses $COMMON_APPDATA expected to be
+ C:\Documents and Settings\All Users\Application Data\
+ while others use $CommonAppData.
+ Both seem poorly supported,
+ */
+ char *home;
+ if ((home = getenv("ALLUSERSPROFILE")) == NULL
+ ) {
+ if (er != NULL) *er = xdg_noalluserprofile;
+ free(path);
+ DBG((DBGA,"no $ALLUSERSPROFILE\n"))
+ return 0;
+ }
+ path = cappend(path, home);
+#else
+#ifdef __APPLE__
+ path = cappend(path, "/Library");
+#else
+ path = cappend(path, "/usr/local/share:/usr/share");
+#endif
+#endif
+ if (path == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+ }
+ } else if (st == xdg_conf) {
+ if ((xdg = getenv("XDG_CONF_DIRS")) != NULL) {
+ if ((path = cappend(path, xdg)) == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+ } else {
+#ifdef NT
+ char *home;
+ if ((home = getenv("ALLUSERSPROFILE")) == NULL
+ ) {
+ if (er != NULL) *er = xdg_noalluserprofile;
+ free(path);
+ DBG((DBGA,"no $ALLUSERSPROFILE\n"))
+ return 0;
+ }
+ path = cappend(path, home);
+#else
+#ifdef __APPLE__
+ path = cappend(path, "/Library/Preferences");
+#else
+ path = cappend(path, "/etc/xdg");
+#endif
+#endif
+ if (path == NULL) {
+ if (er != NULL) *er = xdg_alloc;
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ return 0;
+ }
+ }
+ }
+ }
+
+#ifdef NT
+ /* Replace all backslashes with forward slashes */
+ {
+ char *cp;
+ for (cp = path; *cp != '\000'; cp++) {
+ if (*cp == '\\')
+ *cp = '/';
+ }
+ }
+#endif
+
+ DBG((DBGA,"Paths to search '%s'\n",path));
+
+ /* Hmm. */
+ if (strlen(path) == 0) {
+ free(path);
+ if (er != NULL) *er = xdg_nopath;
+ *paths = NULL;
+ return 0;
+ }
+
+ {
+ char *spath = NULL; /* sub path out of paths */
+ char *cp, *ep;
+
+ /* For each search path */
+ for (cp = path; *cp != '\000';) {
+ char *sname = NULL; /* sub name out of pfnames */
+ char *ncp, *nep;
+
+ /* Copy search path */
+ if ((ep = strchr(cp, SSEP)) == NULL)
+ ep = cp + strlen(cp);
+ if ((ep - cp) == 0) {
+ free(path);
+ if (er != NULL) *er = xdg_mallformed;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ if ((spath = (char *)malloc(ep - cp + 1)) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ free(path);
+ if (er != NULL) *er = xdg_alloc;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ memmove(spath, cp, ep - cp);
+ spath[ep - cp] = '\000';
+
+ /* For each filename part */
+ for (ncp = pfname; *ncp != '\000';) {
+ int rlen = 0; /* Number of chars of search path up to subpath & filename */
+ char *pp;
+ char *schpath; /* Path to search */
+
+ /* Copy filename path */
+ if ((nep = strchr(ncp, SSEP)) == NULL)
+ nep = ncp + strlen(ncp);
+ if ((nep - ncp) == 0) {
+ free(spath);
+ free(path);
+ if (er != NULL) *er = xdg_mallformed;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ if ((sname = (char *)malloc(nep - ncp + 1)) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ free(spath);
+ free(path);
+ if (er != NULL) *er = xdg_alloc;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ memmove(sname, ncp, nep - ncp);
+ sname[nep - ncp] = '\000';
+
+ /* append subpath & subname */
+ if ((schpath = strdup(spath)) == NULL
+ || (schpath = dappend(schpath, sname)) == NULL) {
+ free(sname);
+ free(spath);
+ free(path);
+ if (er != NULL) *er = xdg_alloc;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ DBG((DBGA,"Full path to check '%s'\n",schpath));
+
+ /* Figure out where the filename starts */
+ if ((pp = strrchr(schpath, '/')) == NULL)
+ rlen = 0;
+ else
+ rlen = pp - schpath + 1;
+
+ if (op == xdg_read) {
+ char *fpath; /* Full path of matched */
+ aglob gg; /* Glob structure */
+
+ /* Setup the file glob */
+ if (aglob_create(&gg, schpath)) {
+ free(schpath);
+ free(sname);
+ free(spath);
+ free(path);
+ if (er != NULL) *er = xdg_alloc;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+
+ /* While we have matching filenames */
+ DBG((DBGA,"Getting glob results for '%s'\n",schpath))
+ free(schpath);
+ for (;;) {
+ int i;
+
+ if ((fpath = aglob_next(&gg)) == NULL) {
+ if (gg.merr) { /* Malloc error */
+ free(sname);
+ free(spath);
+ free(path);
+ aglob_cleanup(&gg);
+ if (er != NULL) *er = xdg_alloc;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ break; /* No more matches */
+ }
+ DBG((DBGA,"Found match with '%s'\n",fpath))
+
+ /* Check that this one hasn't already been found */
+ /* in a different search directory */
+ for (i = 0; i < npaths; i++) {
+ if (strcmp(fpath + rlen, fnames[i]) == 0) {
+ /* Already been found earlier - ignore it */
+ break;
+ }
+ }
+ if (i < npaths) {
+ free(fpath);
+ DBG((DBGA,"Ignoring it because it's already in list\n"))
+ continue; /* Ignore it */
+ }
+
+ /* Found a file, so append it to the list */
+ if (npaths >= napaths) { /* Need more space in arrays */
+ napaths = napaths * 2 + 1;
+ if ((*paths = realloc(*paths, sizeof(char *) * napaths)) == NULL
+ || (fnames = realloc(fnames, sizeof(char *) * napaths)) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: realloc failed\n");
+ free(fpath);
+ free(sname);
+ free(spath);
+ free(path);
+ aglob_cleanup(&gg);
+ if (er != NULL) *er = xdg_alloc;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ }
+ if (((*paths)[npaths] = strdup(fpath)) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: strdup failed\n");
+ free(fpath);
+ free(sname);
+ free(spath);
+ free(path);
+ aglob_cleanup(&gg);
+ if (er != NULL) *er = xdg_alloc;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ /* The non-searchpath part of the name found */
+ if ((fnames[npaths] = strdup(fpath + rlen)) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: strdup failed\n");
+ free((*paths)[npaths]);
+ free(fpath);
+ free(sname);
+ free(spath);
+ free(path);
+ aglob_cleanup(&gg);
+ if (er != NULL) *er = xdg_alloc;
+ xdg_ifree(paths, fnames, npaths);
+ return 0;
+ }
+ free(fpath);
+ fpath = NULL;
+ npaths++;
+ }
+ aglob_cleanup(&gg);
+
+ /* Fall through to next search path */
+
+ } else { /* op == xdg_write */
+ char *pp = schpath;
+ struct stat sbuf;
+ mode_t mode = 0700; /* Default directory mode */
+
+ if (sc == xdg_user)
+ mode = 0700; /* Default directory mode for user */
+ else
+ mode = 0755; /* Default directory mode local system shared */
+#ifndef NT
+ /* If we're creating a user dir/file and running as root sudo */
+ if (sc == xdg_user && geteuid() == 0) {
+ char *uids, *gids;
+ int uid, gid;
+ DBG((DBGA,"We're setting a user dir/file running as root\n"))
+
+ if ((uids = getenv("SUDO_UID")) != NULL
+ && (gids = getenv("SUDO_GID")) != NULL) {
+ uid = atoi(uids);
+ gid = atoi(gids);
+ if (setegid(gid) || seteuid(uid)) {
+ DBG((DBGA,"seteuid or setegid failed\n"))
+ } else {
+ DBG((DBGA,"Set euid %d and egid %d\n",uid,gid))
+ }
+ }
+ /* If setting local system dir/file and not effective root, but sudo */
+ } else if (sc == xdg_local && getuid() == 0 && geteuid() != 0) {
+ if (getenv("SUDO_UID") != NULL
+ && getenv("SUDO_GID") != NULL) {
+ DBG((DBGA,"We're setting a local system dir/file with uid = 0 && euid != 0\n"))
+ setegid(getgid());
+ seteuid(getuid());
+ DBG((DBGA,"Set euid %d, egid %d\n",geteuid(),getegid()))
+ }
+ }
+#endif /* !NT */
+
+#ifdef NT
+ if (*pp != '\000' /* Skip drive number */
+ && ((*pp >= 'a' && *pp <= 'z') || (*pp >= 'A' && *pp <= 'Z'))
+ && pp[1] == ':')
+ pp += 2;
+#endif
+ if (*pp == '/')
+ pp++; /* Skip root directory */
+
+ /* Check each directory in hierarchy, and */
+ /* create it if it doesn't exist. */
+ DBG((DBGA,"About to check & create whole path '%s'\n",schpath))
+ for (;pp != NULL && *pp != '\000';) {
+ if ((pp = strchr(pp, '/')) != NULL) {
+ *pp = '\000';
+ DBG((DBGA,"Checking path '%s'\n",schpath))
+ if (stat(schpath,&sbuf) != 0) {
+ /* Doesn't exist */
+ DBG((DBGA,"Path '%s' doesn't exist - creating it\n",schpath))
+ if (mkdir(schpath, mode) != 0) {
+ DBG((DBGA,"mkdir failed - giving up on this one\n"))
+ break;
+ }
+ } else {
+ mode = sbuf.st_mode;
+ }
+ *pp = '/';
+ pp++;
+ }
+ }
+
+ /* If we got to the end of the hierarchy, */
+ /* then the path looks good to write to, */
+ /* so create a list of one and we're done */
+ if (pp == NULL || *pp == '\000') {
+
+ if ((*paths = malloc(sizeof(char *))) == NULL) {
+ a1loge(g_log, 1, "xdg_bds: malloc failed\n");
+ free(schpath);
+ free(sname);
+ free(spath);
+ free(path);
+ if (er != NULL) *er = xdg_alloc;
+ return 0;
+ }
+ if (((*paths)[npaths] = schpath) == NULL) {
+ free(sname);
+ free(spath);
+ free(path);
+ if (er != NULL) *er = xdg_alloc;
+ free(*paths);
+ return 0;
+ }
+ npaths++;
+ DBG((DBGA,"Returning 0: '%s'\n",(*paths)[0]))
+ free(sname);
+ free(spath);
+ free(path);
+ return npaths;
+ }
+ }
+
+ /* Move on to the next name part */
+ free(sname); sname = NULL;
+ if (*nep == SSEP)
+ ncp = nep+1;
+ else
+ ncp = nep;
+ }
+
+ /* Move on to the next search path */
+ free(spath); spath = NULL;
+ if (*ep == SSEP)
+ cp = ep+1;
+ else
+ cp = ep;
+ }
+ }
+
+ /* We're done looking through search paths */
+ free(path);
+
+ if (npaths == 0) { /* Didn't find anything */
+ if (er != NULL) *er = xdg_nopath;
+ xdg_ifree(paths, fnames, npaths);
+ } else {
+ xdg_ifree(NULL, fnames, npaths);
+#ifdef DEBUG
+ {
+ int i;
+ a1logd(DBGA,"Returning list\n");
+ for (i = 0; i < npaths; i++)
+ a1logd(DBGA," %d: '%s'\n",i,(*paths)[i]);
+ }
+#endif
+ }
+ return npaths;
+}
+
+/* Return a string corresponding to the error value */
+char *xdg_errstr(xdg_error er) {
+ switch (er) {
+ case xdg_ok:
+ return "OK";
+ case xdg_alloc:
+ return "memory allocation failed";
+ case xdg_nohome:
+ return "There is no $HOME";
+ case xdg_noalluserprofile:
+ return "Theres no $ALLUSERSPROFILE is no $ALLUSERSPROFILE";
+ case xdg_nopath:
+ return "There is no resulting path";
+ case xdg_mallformed:
+ return "Malfomed path fount";
+ default:
+ return "unknown";
+ }
+}
+
+
+/* ---------------------------------------------------------------- */
+#ifdef STANDALONE_TEST
+/* test code */
+
+/* Return nz on error */
+static int touch(char *name) {
+ FILE *fp;
+
+ if ((fp = fopen(name,"w")) == NULL)
+ return 1;
+
+ if (fclose(fp))
+ return 1;
+
+ return 0;
+}
+
+/* Check a file can be opened */
+/* Return nz on error */
+static int check(char *name) {
+ FILE *fp;
+
+ if ((fp = fopen(name,"r")) == NULL)
+ return 1;
+
+ if (fclose(fp))
+ return 1;
+
+ return 0;
+}
+
+/* Delete a path and a file */
+/* Return nz on error */
+static int delpath(char *path, int depth) {
+ int i;
+ char *pp;
+
+ for (i = 0; i < depth;) {
+// a1logd(DBGA,"deleting '%s'\n",path);
+ if (i == 0) {
+ if (unlink(path)) {
+// a1logd(DBGA,"unlink '%s' failed\n",path);
+ return 1;
+ }
+ } else {
+ if (rmdir(path)) {
+// a1logd(DBGA,"rmdir '%s' failed\n",path);
+ return 1;
+ }
+ }
+ i++;
+ if (i == depth)
+ return 0;
+
+ if ((pp = strrchr(path, '/')) == NULL)
+ return 0;
+ *pp = '\000';
+ }
+ return 0;
+}
+
+/* Run a test */
+static int runtest(
+ xdg_storage_type st, /* Specify the storage type */
+ xdg_scope sc, /* Scope if write */
+ char *pfname, /* Sub-path and file name */
+ char *env, /* Environment variable being set */
+ char *envv, /* Value to set it to */
+ char *defv, /* default variable needed for read */
+ int depth /* Cleanup depth */
+) {
+ xdg_error er;
+ char *xval;
+ char **paths;
+ int nopaths;
+ char buf[200];
+
+ if ((xval = getenv(env)) != NULL) /* Save value before mods */
+ xval = strdup(xval);
+ if (*env != '\000') { /* If it is to be set */
+ sprintf(buf, "%s=%s",env,envv);
+ mputenv(buf);
+ }
+
+ printf("\nTesting Variable %s\n",env);
+ if ((nopaths = xdg_bds(&er, &paths, st, xdg_write, sc, pfname)) == 0) {
+ printf("Write test failed with %s\n",xdg_errstr(er));
+ return 1;
+ }
+ printf("Create %s %s returned '%s'\n",
+ st == xdg_data ? "Data" : st == xdg_data ? "Conf" : "Cache",
+ sc == xdg_data ? "User" : "Local", paths[0]);
+ if (touch(paths[0])) {
+ printf("Creating file %s failed\n",paths[0]);
+ return 1;
+ }
+ if (check(paths[0])) {
+ printf("Checking file %s failed\n",paths[0]);
+ return 1;
+ }
+
+ if (sc == xdg_local && *env != '\000') { /* Add another path */
+ sprintf(buf, "%s=xdgtestXXX%c%s",env,SSEP,envv);
+ mputenv(buf);
+ }
+
+ if (defv != NULL) {
+ sprintf(buf, "%s=xdg_NOT_%s",defv,defv);
+ mputenv(buf);
+ }
+ xdg_free(paths, nopaths);
+
+ if ((nopaths = xdg_bds(&er, &paths, st, xdg_read, sc, pfname)) < 1) {
+ printf("Read test failed with %s\n",xdg_errstr(er));
+ return 1;
+ }
+ printf(" Read %s %s returned '%s'\n",
+ st == xdg_data ? "Data" : st == xdg_data ? "Conf" : "Cache",
+ sc == xdg_data ? "User" : "Local",paths[0]);
+ if (check(paths[0])) {
+ printf("Checking file %s failed\n",paths[0]);
+ return 1;
+ }
+ if (delpath(paths[0], depth)) {
+ printf("Warning: Deleting file %s failed\n",paths[0]);
+ }
+ xdg_free(paths, nopaths);
+
+ /* Restore variables value */
+ if (xval == NULL)
+ sprintf(buf, "%s=",env);
+ else
+ sprintf(buf, "%s=%s",env,xval);
+ mputenv(buf);
+
+ if (defv != NULL) {
+ sprintf(buf, "%s=",defv);
+ mputenv(buf);
+ }
+
+ return 0;
+}
+
+typedef struct {
+ xdg_storage_type st; /* Storage type */
+ xdg_scope sc; /* Scope if write */
+ char *defv[2]; /* Default variables needed for user & local tests on read */
+ char *envn[10]; /* Environment variable name to set */
+} testcase;
+
+int
+main() {
+ char buf1[200], buf2[200];
+ int i, j;
+
+#ifdef NT
+ testcase cases[5] = {
+ { xdg_data, xdg_user, {"ALLUSERSPROFILE", NULL},
+ { "XDG_DATA_HOME", "APPDATA", "HOME", "APPDATA", NULL } },
+ { xdg_conf, xdg_user, {"ALLUSERSPROFILE", NULL},
+ { "XDG_CONF_HOME", "APPDATA", "HOME", "APPDATA", NULL } },
+ { xdg_cache, xdg_user, {NULL, NULL},
+ { "XDG_CACHE_HOME", "APPDATA", "HOME", "APPDATA", NULL } },
+ { xdg_data, xdg_local, {NULL, "HOME"},
+ { "XDG_DATA_DIRS", "ALLUSERSPROFILE", NULL } },
+ { xdg_conf, xdg_local, {NULL, "HOME"},
+ { "XDG_CONF_DIRS", "ALLUSERSPROFILE", NULL } }
+ };
+#else /* Apple, Unix, Default */
+ testcase cases[5] = {
+ { xdg_data, xdg_user, {NULL, NULL},
+ { "XDG_DATA_HOME", "HOME", NULL } },
+ { xdg_conf, xdg_user, {NULL, NULL},
+ { "XDG_CONF_HOME", "HOME", NULL } },
+ { xdg_cache, xdg_user, {NULL, NULL},
+ { "XDG_CACHE_HOME", "HOME", NULL } },
+ { xdg_data, xdg_local, {NULL, "HOME"},
+ { "XDG_DATA_DIRS", "", NULL } },
+ { xdg_conf, xdg_local, {NULL, "HOME"},
+ { "XDG_CONF_DIRS", "", NULL } }
+ };
+#endif
+
+ /* First clear all the environment variables */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; ;j++) {
+ if (cases[i].envn[j] == NULL)
+ break;
+ sprintf(buf1, "%s=",cases[i].envn[j]);
+ mputenv(buf1);
+ }
+ }
+
+ /* Then run all the tests */
+ for (i = 0; i < 5; i++) {
+ for (j = 0; ;j++) {
+ if (cases[i].envn[j] == NULL)
+ break;
+ sprintf(buf1, "xdgtest%d",i);
+ sprintf(buf2, "application/%s",cases[i].st == xdg_data ? "data" :
+ cases[i].st == xdg_conf ? "config" : "cache");
+ if (runtest(cases[i].st, cases[i].sc, buf2, cases[i].envn[j],buf1,
+ cases[i].defv[cases[i].sc == xdg_user ? 0 : 1],9))
+ exit(1);
+ }
+ }
+
+ printf("Test completed OK\n");
+
+ return 0;
+}
+
+#endif /* STANDALONE_TEST */
+
+
diff --git a/spectro/xdg_bds.h b/spectro/xdg_bds.h
new file mode 100644
index 0000000..5c29790
--- /dev/null
+++ b/spectro/xdg_bds.h
@@ -0,0 +1,115 @@
+
+#ifndef XDG_BDS_H
+
+ /* XDG Base Directory Specifications support library */
+
+/*************************************************************************
+ Copyright 2011, 2013 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* Which type of storage */
+typedef enum {
+ xdg_data,
+ xdg_conf,
+ xdg_cache /* Note there is no xdg_local cache */
+} xdg_storage_type;
+
+/* What operation is being performed */
+typedef enum {
+ xdg_write, /* Create or write */
+ xdg_read /* Read */
+} xdg_op_type;
+
+/* What scope to write to */
+/* (For write only. Read always searches */
+/* the user context then the local system context.) */
+typedef enum {
+ xdg_user, /* User context */
+ xdg_local /* Local system wide context */
+} xdg_scope;
+
+/* An error code */
+typedef enum {
+ xdg_ok = 0,
+ xdg_alloc, /* A memory allocation failed */
+ xdg_nohome, /* There is no $HOME */
+ xdg_noalluserprofile, /* There is no $ALLUSERSPROFILE */
+ xdg_nopath, /* There is no resulting path */
+ xdg_mallformed /* Malfomed path */
+} xdg_error;
+
+#ifdef NT
+#define SSEP ';' /* Since ':' is used for drive letter */
+#define SSEPS ";"
+#else
+#define SSEP ':'
+#define SSEPS ":"
+#endif
+
+ /* ONLY use this for xdg_data type */
+#ifdef __APPLE__ /* fudge to assist OS X migration from */
+#define XDG_FUDGE SSEPS "../" /* Library/color to Library/Application Support/ArgyllCMS */
+#else
+#define XDG_FUDGE SSEPS
+#endif
+
+/* Return the number of matching full paths to the given subpath for the */
+/* type of storage and access required. Return 0 if there is an error. */
+/* The files are always unique (ie. the first match to a given filename */
+/* in the possible XDG list of directories is returned, and files with */
+/* the same name in other XDG directories are ignored) */
+/* Wildcards should only be for the filename portion, and not be used for xdg_write. */
+/* The list should be free'd using xdg_free() after use. */
+/* XDG environment variables and the subpath are assumed to be using */
+/* the '/' path separator. Multiple read paths are separated by SSEP */
+/* When "xdg_write", the necessary path to the file will be created. */
+/* If we're running as sudo and are creating a user dir/file, */
+/* we drop to using the underlying SUDO_UID/GID. If we are creating a */
+/* local system dir/file as sudo and have dropped to the SUDO_UID/GID, */
+/* then revert back to root uid/gid. */
+int xdg_bds(
+ xdg_error *er, /* Return an error code */
+ char ***paths, /* Return array of pointers to paths */
+ xdg_storage_type st, /* Specify the storage type */
+ xdg_op_type op, /* Operation type */
+ xdg_scope sc, /* Scope if write */
+ char *spath /* Sub-path and file name or file pattern */
+);
+
+/* Free the list */
+void xdg_free(char **paths, int nopaths);
+
+/* Return a string corresponding to the error value */
+char *xdg_errstr(xdg_error er);
+
+
+#define XDG_BDS_H
+#endif /* XDG_BDS_H */
+
+#ifdef __cplusplus
+ }
+#endif
+
diff --git a/target/ColorChecker.ti2 b/target/ColorChecker.ti2
new file mode 100644
index 0000000..6ede47a
--- /dev/null
+++ b/target/ColorChecker.ti2
@@ -0,0 +1,54 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+# Standard Macbeth ColorChecker 6x4 chart, read patch by patch
+ORIGINATOR "Argyll printtarg"
+CREATED "Wed Apr 11 22:19:15 2007"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "86.776 90.361 70.642"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "6"
+KEYWORD "PASSES_IN_STRIPS2"
+PASSES_IN_STRIPS2 "4"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "A-Z, 2-9;A-X,2A-9Z"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 24
+BEGIN_DATA
+1 "A1" 0 0 0 11.773 10.213 4.9219
+2 "A2" 0 0 0 40.174 36.201 20.217
+3 "A3" 0 0 0 17.675 19.409 26.983
+4 "A4" 0 0 0 11.121 13.530 5.5615
+5 "A5" 0 0 0 25.551 24.404 34.847
+6 "A6" 0 0 0 31.744 43.164 35.249
+7 "B1" 0 0 0 40.056 30.947 4.8180
+8 "B2" 0 0 0 12.544 11.700 28.648
+9 "B3" 0 0 0 30.675 20.352 10.837
+10 "B4" 0 0 0 8.3961 6.5047 10.849
+11 "B5" 0 0 0 36.036 44.991 8.9494
+12 "B6" 0 0 0 50.203 44.570 6.2773
+13 "C1" 0 0 0 7.4590 6.0952 23.518
+14 "C2" 0 0 0 15.439 23.986 7.7482
+15 "C3" 0 0 0 22.850 13.022 4.1188
+16 "C4" 0 0 0 59.637 60.332 7.3520
+17 "C5" 0 0 0 30.450 20.015 22.947
+18 "C6" 0 0 0 13.591 19.466 30.479
+19 "D1" 0 0 0 86.776 90.361 70.642
+20 "D2" 0 0 0 56.865 59.038 48.218
+21 "D3" 0 0 0 34.763 36.036 29.378
+22 "D4" 0 0 0 18.884 19.603 16.309
+23 "D5" 0 0 0 8.4332 8.7464 7.1022
+24 "D6" 0 0 0 3.0110 3.0971 2.5475
+END_DATA
diff --git a/target/ECI2002.ti2 b/target/ECI2002.ti2
new file mode 100644
index 0000000..0ab3095
--- /dev/null
+++ b/target/ECI2002.ti2
@@ -0,0 +1,1578 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+ORIGINATOR "Argyll printtarg"
+CREATED "Mon Oct 11 11:50:06 2010"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "Xrite DTP41"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "86.886812 89.830019 77.951670"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+KEYWORD "RANDOM_START"
+RANDOM_START "1251"
+KEYWORD "PATCH_LENGTH"
+PATCH_LENGTH "7.366000"
+KEYWORD "GAP_LENGTH"
+GAP_LENGTH "2.032000"
+KEYWORD "TRAILER_LENGTH"
+TRAILER_LENGTH "18.796000"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "57"
+KEYWORD "PASSES_IN_STRIPS2"
+PASSES_IN_STRIPS2 "8,8,8,3"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "A-Z, A-Z"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+KEYWORD "INDEX_ORDER"
+INDEX_ORDER "STRIP_THEN_PATCH"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1539
+BEGIN_DATA
+1 "K18" 0.0000 0.0000 0.0000 0.0000 82.670 85.770 75.100
+2 "C42" 0.0000 10.196 0.0000 0.0000 75.440 75.210 67.360
+3 "H41" 0.0000 20.000 0.0000 0.0000 68.390 65.250 59.520
+4 "J28" 0.0000 29.804 0.0000 0.0000 61.730 55.910 51.990
+5 "P43" 0.0000 40.000 0.0000 0.0000 55.570 47.360 44.900
+6 "P52" 0.0000 54.902 0.0000 0.0000 47.430 36.190 34.970
+7 "Q3" 0.0000 70.196 0.0000 0.0000 40.640 27.330 26.760
+8 "C3" 0.0000 85.098 0.0000 0.0000 36.010 21.120 20.750
+9 "O41" 0.0000 100.00 0.0000 0.0000 32.280 16.480 15.950
+10 "R55" 10.196 0.0000 0.0000 0.0000 74.060 78.380 73.130
+11 "V5" 10.196 10.196 0.0000 0.0000 67.440 68.580 65.650
+12 "R5" 10.196 20.000 0.0000 0.0000 61.180 59.530 58.060
+13 "L34" 10.196 29.804 0.0000 0.0000 55.110 50.870 50.710
+14 "G34" 10.196 40.000 0.0000 0.0000 49.460 42.920 43.790
+15 "B38" 10.196 54.902 0.0000 0.0000 42.150 32.700 34.170
+16 "A44" 10.196 70.196 0.0000 0.0000 36.060 24.630 26.220
+17 "S11" 10.196 85.098 0.0000 0.0000 31.880 18.960 20.420
+18 "X39" 10.196 100.00 0.0000 0.0000 28.510 14.710 15.790
+19 "R40" 20.000 0.0000 0.0000 0.0000 65.080 70.510 71.060
+20 "R31" 20.000 10.196 0.0000 0.0000 59.420 61.860 63.940
+21 "S5" 20.000 20.000 0.0000 0.0000 54.000 53.760 56.770
+22 "N37" 20.000 29.804 0.0000 0.0000 48.570 45.890 49.620
+23 "X57" 20.000 40.000 0.0000 0.0000 43.490 38.650 42.860
+24 "Y52" 20.000 54.902 0.0000 0.0000 36.980 29.400 33.560
+25 "D13" 20.000 70.196 0.0000 0.0000 31.560 22.080 25.870
+26 "Q15" 20.000 85.098 0.0000 0.0000 27.790 16.870 20.230
+27 "A15" 20.000 100.00 0.0000 0.0000 24.730 12.950 15.700
+28 "W20" 29.804 0.0000 0.0000 0.0000 56.270 62.660 68.950
+29 "AA44" 29.804 10.196 0.0000 0.0000 51.330 54.930 61.980
+30 "A43" 29.804 20.000 0.0000 0.0000 46.640 47.710 55.080
+31 "C45" 29.804 29.804 0.0000 0.0000 41.990 40.770 48.310
+32 "Z39" 29.804 40.000 0.0000 0.0000 37.620 34.380 41.870
+33 "V30" 29.804 54.902 0.0000 0.0000 31.960 26.120 32.880
+34 "H33" 29.804 70.196 0.0000 0.0000 27.230 19.560 25.440
+35 "C23" 29.804 85.098 0.0000 0.0000 23.930 14.880 20.050
+36 "Y49" 29.804 100.00 0.0000 0.0000 21.240 11.340 15.730
+37 "Z50" 40.000 0.0000 0.0000 0.0000 48.240 55.380 66.850
+38 "L20" 40.000 10.196 0.0000 0.0000 43.880 48.440 60.010
+39 "K41" 40.000 20.000 0.0000 0.0000 39.840 42.020 53.330
+40 "F1" 40.000 29.804 0.0000 0.0000 35.910 35.950 46.930
+41 "S55" 40.000 40.000 0.0000 0.0000 32.220 30.360 40.840
+42 "B10" 40.000 54.902 0.0000 0.0000 27.350 23.050 32.190
+43 "N30" 40.000 70.196 0.0000 0.0000 23.270 17.220 25.020
+44 "T4" 40.000 85.098 0.0000 0.0000 20.410 13.050 19.880
+45 "I25" 40.000 100.00 0.0000 0.0000 18.080 9.9000 15.760
+46 "G17" 54.902 0.0000 0.0000 0.0000 38.030 45.930 63.790
+47 "D2" 54.902 10.196 0.0000 0.0000 34.510 40.110 57.320
+48 "B52" 54.902 20.000 0.0000 0.0000 31.280 34.770 51.060
+49 "K1" 54.902 29.804 0.0000 0.0000 28.140 29.700 44.980
+50 "O42" 54.902 40.000 0.0000 0.0000 25.220 25.070 39.230
+51 "Z36" 54.902 54.902 0.0000 0.0000 21.420 19.070 31.290
+52 "F13" 54.902 70.196 0.0000 0.0000 18.220 14.260 24.660
+53 "P32" 54.902 85.098 0.0000 0.0000 15.880 10.710 19.720
+54 "Y57" 54.902 100.00 0.0000 0.0000 13.940 7.9900 15.690
+55 "K51" 70.196 0.0000 0.0000 0.0000 29.450 37.760 60.910
+56 "T57" 70.196 10.196 0.0000 0.0000 26.690 32.940 54.840
+57 "L28" 70.196 20.000 0.0000 0.0000 24.150 28.550 48.990
+58 "Y13" 70.196 29.804 0.0000 0.0000 21.690 24.370 43.210
+59 "K47" 70.196 40.000 0.0000 0.0000 19.410 20.550 37.770
+60 "O23" 70.196 54.902 0.0000 0.0000 16.490 15.670 30.460
+61 "B18" 70.196 70.196 0.0000 0.0000 14.010 11.710 24.300
+62 "S3" 70.196 85.098 0.0000 0.0000 12.120 8.7200 19.550
+63 "A9" 70.196 100.00 0.0000 0.0000 10.540 6.3900 15.630
+64 "R7" 85.098 0.0000 0.0000 0.0000 22.360 31.030 58.510
+65 "P51" 85.098 10.196 0.0000 0.0000 20.260 27.090 52.840
+66 "G55" 85.098 20.000 0.0000 0.0000 18.350 23.520 47.310
+67 "F25" 85.098 29.804 0.0000 0.0000 16.510 20.140 41.930
+68 "X30" 85.098 40.000 0.0000 0.0000 14.790 17.020 36.840
+69 "AA48" 85.098 54.902 0.0000 0.0000 12.500 12.920 29.790
+70 "AA46" 85.098 70.196 0.0000 0.0000 10.560 9.6000 23.840
+71 "Z23" 85.098 85.098 0.0000 0.0000 9.0900 7.1100 19.350
+72 "I55" 85.098 100.00 0.0000 0.0000 7.8700 5.1700 15.670
+73 "M27" 100.00 0.0000 0.0000 0.0000 16.720 25.290 56.260
+74 "X34" 100.00 10.196 0.0000 0.0000 15.170 22.120 51.000
+75 "A3" 100.00 20.000 0.0000 0.0000 13.770 19.260 45.750
+76 "Y30" 100.00 29.804 0.0000 0.0000 12.430 16.590 40.800
+77 "X4" 100.00 40.000 0.0000 0.0000 11.160 14.070 36.080
+78 "A8" 100.00 54.902 0.0000 0.0000 9.3600 10.620 29.150
+79 "Y39" 100.00 70.196 0.0000 0.0000 7.8300 7.8300 23.340
+80 "L44" 100.00 85.098 0.0000 0.0000 6.7100 5.7800 19.130
+81 "D52" 100.00 100.00 0.0000 0.0000 5.7900 4.2100 15.750
+82 "D3" 0.0000 0.0000 10.196 0.0000 80.380 84.000 64.370
+83 "O17" 0.0000 10.196 10.196 0.0000 73.240 73.550 57.600
+84 "H11" 0.0000 20.000 10.196 0.0000 66.560 63.900 51.070
+85 "C48" 0.0000 29.804 10.196 0.0000 60.220 54.850 44.770
+86 "O25" 0.0000 40.000 10.196 0.0000 54.320 46.530 38.760
+87 "C56" 0.0000 54.902 10.196 0.0000 46.490 35.580 30.230
+88 "E57" 0.0000 70.196 10.196 0.0000 39.940 26.920 23.160
+89 "AA55" 0.0000 85.098 10.196 0.0000 35.480 20.900 18.000
+90 "Z21" 0.0000 100.00 10.196 0.0000 31.910 16.410 13.900
+91 "G7" 10.196 0.0000 10.196 0.0000 71.850 76.680 62.750
+92 "H25" 10.196 10.196 10.196 0.0000 65.560 67.260 56.410
+93 "W51" 10.196 20.000 10.196 0.0000 59.560 58.430 50.060
+94 "F6" 10.196 29.804 10.196 0.0000 53.740 50.010 43.840
+95 "R50" 10.196 40.000 10.196 0.0000 48.340 42.280 37.940
+96 "K45" 10.196 54.902 10.196 0.0000 41.320 32.260 29.640
+97 "G23" 10.196 70.196 10.196 0.0000 35.490 24.370 22.790
+98 "A55" 10.196 85.098 10.196 0.0000 31.500 18.860 17.820
+99 "D5" 10.196 100.00 10.196 0.0000 28.300 14.750 13.870
+100 "N50" 20.000 0.0000 10.196 0.0000 63.190 69.190 61.080
+101 "G47" 20.000 10.196 10.196 0.0000 57.650 60.620 54.910
+102 "T27" 20.000 20.000 10.196 0.0000 52.360 52.680 48.710
+103 "J23" 20.000 29.804 10.196 0.0000 47.190 45.010 42.630
+104 "N57" 20.000 40.000 10.196 0.0000 42.370 37.990 36.900
+105 "B21" 20.000 54.902 10.196 0.0000 36.180 28.990 28.990
+106 "E7" 20.000 70.196 10.196 0.0000 31.020 21.860 22.440
+107 "E12" 20.000 85.098 10.196 0.0000 27.440 16.800 17.600
+108 "B42" 20.000 100.00 10.196 0.0000 24.540 12.990 13.700
+109 "Q43" 29.804 0.0000 10.196 0.0000 54.560 61.520 59.050
+110 "O44" 29.804 10.196 10.196 0.0000 49.750 53.870 53.150
+111 "C52" 29.804 20.000 10.196 0.0000 45.200 46.820 47.200
+112 "V1" 29.804 29.804 10.196 0.0000 40.730 40.020 41.410
+113 "F26" 29.804 40.000 10.196 0.0000 36.560 33.770 35.950
+114 "J37" 29.804 54.902 10.196 0.0000 31.180 25.750 28.380
+115 "I38" 29.804 70.196 10.196 0.0000 26.680 19.370 22.070
+116 "F23" 29.804 85.098 10.196 0.0000 23.510 14.790 17.380
+117 "AA15" 29.804 100.00 10.196 0.0000 20.920 11.310 13.590
+118 "Y54" 40.000 0.0000 10.196 0.0000 46.600 54.310 57.010
+119 "G19" 40.000 10.196 10.196 0.0000 42.470 47.550 51.400
+120 "O47" 40.000 20.000 10.196 0.0000 38.590 41.330 45.720
+121 "U42" 40.000 29.804 10.196 0.0000 34.790 35.350 40.250
+122 "F39" 40.000 40.000 10.196 0.0000 31.230 29.850 35.070
+123 "K23" 40.000 54.902 10.196 0.0000 26.600 22.740 27.800
+124 "Z18" 40.000 70.196 10.196 0.0000 22.720 17.060 21.720
+125 "G49" 40.000 85.098 10.196 0.0000 19.950 12.940 17.190
+126 "V56" 40.000 100.00 10.196 0.0000 17.670 9.8000 13.520
+127 "L47" 54.902 0.0000 10.196 0.0000 36.470 44.940 54.360
+128 "AA56" 54.902 10.196 10.196 0.0000 33.150 39.300 49.040
+129 "N49" 54.902 20.000 10.196 0.0000 30.120 34.180 43.840
+130 "H23" 54.902 29.804 10.196 0.0000 27.160 29.250 38.710
+131 "G25" 54.902 40.000 10.196 0.0000 24.390 24.710 33.830
+132 "K4" 54.902 54.902 10.196 0.0000 20.750 18.820 27.020
+133 "N17" 54.902 70.196 10.196 0.0000 17.690 14.080 21.310
+134 "M43" 54.902 85.098 10.196 0.0000 15.470 10.610 17.020
+135 "Q42" 54.902 100.00 10.196 0.0000 13.640 7.9500 13.520
+136 "K55" 70.196 0.0000 10.196 0.0000 27.940 36.820 51.930
+137 "E45" 70.196 10.196 10.196 0.0000 25.360 32.200 46.890
+138 "J26" 70.196 20.000 10.196 0.0000 23.020 28.000 42.110
+139 "H45" 70.196 29.804 10.196 0.0000 20.770 23.990 37.280
+140 "Q41" 70.196 40.000 10.196 0.0000 18.660 20.280 32.670
+141 "C2" 70.196 54.902 10.196 0.0000 15.860 15.440 26.300
+142 "AA18" 70.196 70.196 10.196 0.0000 13.490 11.540 20.940
+143 "N2" 70.196 85.098 10.196 0.0000 11.760 8.6500 16.890
+144 "P16" 70.196 100.00 10.196 0.0000 10.320 6.4100 13.560
+145 "X52" 85.098 0.0000 10.196 0.0000 20.880 30.120 49.870
+146 "R42" 85.098 10.196 10.196 0.0000 19.000 26.420 45.220
+147 "Y2" 85.098 20.000 10.196 0.0000 17.220 22.970 40.630
+148 "H21" 85.098 29.804 10.196 0.0000 15.530 19.690 36.070
+149 "Q45" 85.098 40.000 10.196 0.0000 13.960 16.660 31.740
+150 "D22" 85.098 54.902 10.196 0.0000 11.860 12.690 25.740
+151 "C22" 85.098 70.196 10.196 0.0000 10.070 9.4700 20.670
+152 "U35" 85.098 85.098 10.196 0.0000 8.7400 7.0600 16.830
+153 "J53" 85.098 100.00 10.196 0.0000 7.6400 5.2000 13.660
+154 "L12" 100.00 0.0000 10.196 0.0000 15.280 24.400 47.930
+155 "T16" 100.00 10.196 10.196 0.0000 13.990 21.530 43.690
+156 "L23" 100.00 20.000 10.196 0.0000 12.640 18.700 39.220
+157 "C44" 100.00 29.804 10.196 0.0000 11.390 16.040 34.910
+158 "S44" 100.00 40.000 10.196 0.0000 10.230 13.600 30.870
+159 "T14" 100.00 54.902 10.196 0.0000 8.6900 10.360 25.210
+160 "S9" 100.00 70.196 10.196 0.0000 7.3700 7.7300 20.420
+161 "G24" 100.00 85.098 10.196 0.0000 6.3600 5.7600 16.780
+162 "B53" 100.00 100.00 10.196 0.0000 5.5300 4.2200 13.770
+163 "H37" 0.0000 0.0000 20.000 0.0000 78.300 82.380 54.640
+164 "R37" 0.0000 10.196 20.000 0.0000 71.360 72.100 48.880
+165 "AA22" 0.0000 20.000 20.000 0.0000 65.060 62.860 43.680
+166 "V10" 0.0000 29.804 20.000 0.0000 58.960 54.020 38.370
+167 "T22" 0.0000 40.000 20.000 0.0000 53.250 45.860 33.210
+168 "O39" 0.0000 54.902 20.000 0.0000 45.770 35.240 25.990
+169 "V49" 0.0000 70.196 20.000 0.0000 39.500 26.800 19.980
+170 "Z56" 0.0000 85.098 20.000 0.0000 35.160 20.850 15.510
+171 "B39" 0.0000 100.00 20.000 0.0000 31.650 16.380 11.930
+172 "A50" 10.196 0.0000 20.000 0.0000 69.820 75.120 53.140
+173 "M39" 10.196 10.196 20.000 0.0000 63.810 65.980 47.900
+174 "U2" 10.196 20.000 20.000 0.0000 58.190 57.500 42.860
+175 "K15" 10.196 29.804 20.000 0.0000 52.650 49.350 37.630
+176 "I1" 10.196 40.000 20.000 0.0000 47.450 41.810 32.570
+177 "C32" 10.196 54.902 20.000 0.0000 40.640 31.960 25.540
+178 "Q29" 10.196 70.196 20.000 0.0000 34.960 24.170 19.690
+179 "W19" 10.196 85.098 20.000 0.0000 31.090 18.740 15.360
+180 "P41" 10.196 100.00 20.000 0.0000 27.980 14.690 11.890
+181 "B51" 20.000 0.0000 20.000 0.0000 61.330 67.780 51.660
+182 "E37" 20.000 10.196 20.000 0.0000 56.030 59.460 46.530
+183 "B31" 20.000 20.000 20.000 0.0000 51.100 51.890 41.660
+184 "U39" 20.000 29.804 20.000 0.0000 46.130 44.410 36.510
+185 "T47" 20.000 40.000 20.000 0.0000 41.450 37.500 31.540
+186 "I29" 20.000 54.902 20.000 0.0000 35.490 28.670 24.840
+187 "Y40" 20.000 70.196 20.000 0.0000 30.520 21.670 19.280
+188 "N25" 20.000 85.098 20.000 0.0000 27.040 16.700 15.120
+189 "J11" 20.000 100.00 20.000 0.0000 24.220 12.950 11.750
+190 "S22" 29.804 0.0000 20.000 0.0000 52.750 60.170 49.770
+191 "V9" 29.804 10.196 20.000 0.0000 48.210 52.780 44.850
+192 "B45" 29.804 20.000 20.000 0.0000 43.950 46.030 40.170
+193 "I49" 29.804 29.804 20.000 0.0000 39.710 39.450 35.370
+194 "B4" 29.804 40.000 20.000 0.0000 35.720 33.350 30.730
+195 "S52" 29.804 54.902 20.000 0.0000 30.520 25.450 24.250
+196 "A36" 29.804 70.196 20.000 0.0000 26.170 19.160 18.850
+197 "A27" 29.804 85.098 20.000 0.0000 23.120 14.680 14.860
+198 "U32" 29.804 100.00 20.000 0.0000 20.640 11.290 11.640
+199 "A17" 40.000 0.0000 20.000 0.0000 44.870 53.030 47.880
+200 "K30" 40.000 10.196 20.000 0.0000 41.020 46.530 43.230
+201 "M48" 40.000 20.000 20.000 0.0000 37.380 40.550 38.740
+202 "W53" 40.000 29.804 20.000 0.0000 33.840 34.820 34.310
+203 "V54" 40.000 40.000 20.000 0.0000 30.490 29.510 30.000
+204 "M56" 40.000 54.902 20.000 0.0000 26.000 22.460 23.730
+205 "N4" 40.000 70.196 20.000 0.0000 22.210 16.840 18.480
+206 "M12" 40.000 85.098 20.000 0.0000 19.560 12.830 14.660
+207 "F18" 40.000 100.00 20.000 0.0000 17.420 9.7900 11.580
+208 "A22" 54.902 0.0000 20.000 0.0000 35.030 43.940 45.670
+209 "F46" 54.902 10.196 20.000 0.0000 31.970 38.520 41.340
+210 "G53" 54.902 20.000 20.000 0.0000 29.140 33.620 37.240
+211 "Y11" 54.902 29.804 20.000 0.0000 26.340 28.850 32.990
+212 "B49" 54.902 40.000 20.000 0.0000 23.700 24.410 28.850
+213 "Z11" 54.902 54.902 20.000 0.0000 20.220 18.600 23.080
+214 "N55" 54.902 70.196 20.000 0.0000 17.280 13.940 18.230
+215 "G38" 54.902 85.098 20.000 0.0000 15.130 10.540 14.610
+216 "K9" 54.902 100.00 20.000 0.0000 13.360 7.9400 11.670
+217 "H43" 70.196 0.0000 20.000 0.0000 26.700 36.030 43.670
+218 "H17" 70.196 10.196 20.000 0.0000 24.320 31.560 39.620
+219 "O30" 70.196 20.000 20.000 0.0000 22.190 27.590 35.870
+220 "O12" 70.196 29.804 20.000 0.0000 20.010 23.650 31.770
+221 "R46" 70.196 40.000 20.000 0.0000 17.960 19.980 27.790
+222 "AA13" 70.196 54.902 20.000 0.0000 15.350 15.250 22.490
+223 "W13" 70.196 70.196 20.000 0.0000 13.140 11.440 18.030
+224 "M7" 70.196 85.098 20.000 0.0000 11.450 8.6000 14.610
+225 "AA1" 70.196 100.00 20.000 0.0000 10.020 6.4000 11.780
+226 "V43" 85.098 0.0000 20.000 0.0000 19.660 29.370 41.960
+227 "D30" 85.098 10.196 20.000 0.0000 17.910 25.760 38.150
+228 "R53" 85.098 20.000 20.000 0.0000 16.330 22.510 34.520
+229 "D50" 85.098 29.804 20.000 0.0000 14.730 19.300 30.700
+230 "Z45" 85.098 40.000 20.000 0.0000 13.230 16.320 27.010
+231 "C20" 85.098 54.902 20.000 0.0000 11.300 12.470 22.050
+232 "F21" 85.098 70.196 20.000 0.0000 9.6700 9.3500 17.840
+233 "U45" 85.098 85.098 20.000 0.0000 8.4000 7.0000 14.550
+234 "Y10" 85.098 100.00 20.000 0.0000 7.3300 5.1800 11.820
+235 "T48" 100.00 0.0000 20.000 0.0000 14.050 23.630 40.330
+236 "D53" 100.00 10.196 20.000 0.0000 12.830 20.790 36.740
+237 "E20" 100.00 20.000 20.000 0.0000 11.670 18.130 33.170
+238 "M13" 100.00 29.804 20.000 0.0000 10.550 15.580 29.660
+239 "M40" 100.00 40.000 20.000 0.0000 9.5000 13.210 26.320
+240 "Z31" 100.00 54.902 20.000 0.0000 8.1000 10.100 21.640
+241 "L6" 100.00 70.196 20.000 0.0000 6.9000 7.5700 17.620
+242 "E16" 100.00 85.098 20.000 0.0000 5.9800 5.6700 14.470
+243 "X9" 100.00 100.00 20.000 0.0000 5.2200 4.2000 11.840
+244 "I19" 0.0000 0.0000 29.804 0.0000 76.290 80.780 45.490
+245 "U18" 0.0000 10.196 29.804 0.0000 69.640 70.770 40.820
+246 "A21" 0.0000 20.000 29.804 0.0000 63.470 61.670 36.480
+247 "E5" 0.0000 29.804 29.804 0.0000 57.610 53.040 32.110
+248 "E2" 0.0000 40.000 29.804 0.0000 52.150 45.090 27.870
+249 "X7" 0.0000 54.902 29.804 0.0000 44.940 34.710 21.850
+250 "A49" 0.0000 70.196 29.804 0.0000 38.900 26.490 16.830
+251 "T51" 0.0000 85.098 29.804 0.0000 34.770 20.740 13.120
+252 "B44" 0.0000 100.00 29.804 0.0000 31.460 16.430 10.140
+253 "Y21" 10.196 0.0000 29.804 0.0000 67.860 73.560 44.410
+254 "Y18" 10.196 10.196 29.804 0.0000 62.090 64.640 40.170
+255 "R57" 10.196 20.000 29.804 0.0000 56.730 56.440 35.980
+256 "Q4" 10.196 29.804 29.804 0.0000 51.390 48.450 31.590
+257 "O35" 10.196 40.000 29.804 0.0000 46.360 41.070 27.340
+258 "N51" 10.196 54.902 29.804 0.0000 39.850 31.530 21.510
+259 "T2" 10.196 70.196 29.804 0.0000 34.420 23.980 16.660
+260 "C28" 10.196 85.098 29.804 0.0000 30.730 18.690 13.060
+261 "D18" 10.196 100.00 29.804 0.0000 27.770 14.730 10.160
+262 "D45" 20.000 0.0000 29.804 0.0000 59.420 66.240 43.090
+263 "P26" 20.000 10.196 29.804 0.0000 54.410 58.230 39.030
+264 "M51" 20.000 20.000 29.804 0.0000 49.760 50.910 34.960
+265 "R43" 20.000 29.804 29.804 0.0000 44.940 43.580 30.610
+266 "E49" 20.000 40.000 29.804 0.0000 40.420 36.810 26.440
+267 "Q19" 20.000 54.902 29.804 0.0000 34.740 28.280 20.900
+268 "AA26" 20.000 70.196 29.804 0.0000 30.020 21.510 16.310
+269 "L50" 20.000 85.098 29.804 0.0000 26.700 16.660 12.870
+270 "L48" 20.000 100.00 29.804 0.0000 23.990 12.980 10.080
+271 "F22" 29.804 0.0000 29.804 0.0000 51.100 58.890 41.600
+272 "S31" 29.804 10.196 29.804 0.0000 46.760 51.710 37.680
+273 "AA4" 29.804 20.000 29.804 0.0000 42.790 45.230 33.780
+274 "Q50" 29.804 29.804 29.804 0.0000 38.690 38.760 29.720
+275 "I11" 29.804 40.000 29.804 0.0000 34.810 32.760 25.820
+276 "X24" 29.804 54.902 29.804 0.0000 29.830 25.090 20.450
+277 "R24" 29.804 70.196 29.804 0.0000 25.670 19.000 15.980
+278 "V15" 29.804 85.098 29.804 0.0000 22.780 14.630 12.670
+279 "M52" 29.804 100.00 29.804 0.0000 20.420 11.310 9.9900
+280 "U48" 40.000 0.0000 29.804 0.0000 43.450 52.000 40.160
+281 "O5" 40.000 10.196 29.804 0.0000 39.710 45.600 36.380
+282 "Y16" 40.000 20.000 29.804 0.0000 36.340 39.880 32.650
+283 "U57" 40.000 29.804 29.804 0.0000 32.920 34.240 28.910
+284 "I3" 40.000 40.000 29.804 0.0000 29.650 28.990 25.280
+285 "E47" 40.000 54.902 29.804 0.0000 25.340 22.140 20.070
+286 "V36" 40.000 70.196 29.804 0.0000 21.730 16.690 15.720
+287 "I54" 40.000 85.098 29.804 0.0000 19.230 12.780 12.520
+288 "O15" 40.000 100.00 29.804 0.0000 17.200 9.8200 9.9400
+289 "J51" 54.902 0.0000 29.804 0.0000 33.680 42.990 38.300
+290 "C39" 54.902 10.196 29.804 0.0000 30.740 37.650 34.740
+291 "D25" 54.902 20.000 29.804 0.0000 28.090 32.910 31.290
+292 "M36" 54.902 29.804 29.804 0.0000 25.370 28.210 27.700
+293 "H29" 54.902 40.000 29.804 0.0000 22.800 23.860 24.250
+294 "W44" 54.902 54.902 29.804 0.0000 19.570 18.300 19.520
+295 "M10" 54.902 70.196 29.804 0.0000 16.850 13.830 15.540
+296 "S7" 54.902 85.098 29.804 0.0000 14.830 10.510 12.520
+297 "T31" 54.902 100.00 29.804 0.0000 13.130 7.9500 10.040
+298 "O48" 70.196 0.0000 29.804 0.0000 25.400 35.120 36.620
+299 "W33" 70.196 10.196 29.804 0.0000 23.170 30.740 33.270
+300 "U22" 70.196 20.000 29.804 0.0000 21.120 26.850 30.070
+301 "Y24" 70.196 29.804 29.804 0.0000 19.020 22.990 26.610
+302 "U55" 70.196 40.000 29.804 0.0000 17.060 19.420 23.300
+303 "I21" 70.196 54.902 29.804 0.0000 14.730 14.970 19.020
+304 "R3" 70.196 70.196 29.804 0.0000 12.750 11.360 15.400
+305 "I16" 70.196 85.098 29.804 0.0000 11.160 8.5800 12.540
+306 "A34" 70.196 100.00 29.804 0.0000 9.7800 6.4000 10.150
+307 "B54" 85.098 0.0000 29.804 0.0000 18.470 28.540 35.270
+308 "A5" 85.098 10.196 29.804 0.0000 16.860 25.020 32.140
+309 "R14" 85.098 20.000 29.804 0.0000 15.370 21.850 29.080
+310 "C34" 85.098 29.804 29.804 0.0000 13.860 18.740 25.870
+311 "J31" 85.098 40.000 29.804 0.0000 12.450 15.870 22.800
+312 "N45" 85.098 54.902 29.804 0.0000 10.740 12.230 18.720
+313 "E41" 85.098 70.196 29.804 0.0000 9.2800 9.2700 15.250
+314 "I9" 85.098 85.098 29.804 0.0000 8.1000 6.9800 12.500
+315 "S39" 85.098 100.00 29.804 0.0000 7.0900 5.1700 10.190
+316 "P6" 100.00 0.0000 29.804 0.0000 12.990 22.890 34.020
+317 "N31" 100.00 10.196 29.804 0.0000 11.870 20.140 31.110
+318 "P4" 100.00 20.000 29.804 0.0000 10.830 17.600 28.160
+319 "T37" 100.00 29.804 29.804 0.0000 9.8200 15.150 25.230
+320 "S40" 100.00 40.000 29.804 0.0000 8.8600 12.890 22.430
+321 "K27" 100.00 54.902 29.804 0.0000 7.5900 9.9100 18.480
+322 "T26" 100.00 70.196 29.804 0.0000 6.5100 7.4800 15.080
+323 "H32" 100.00 85.098 29.804 0.0000 5.6700 5.6300 12.430
+324 "O46" 100.00 100.00 29.804 0.0000 4.9700 4.1800 10.210
+325 "P49" 0.0000 0.0000 40.000 0.0000 74.390 79.200 36.970
+326 "P5" 0.0000 10.196 40.000 0.0000 67.990 69.470 33.260
+327 "H20" 0.0000 20.000 40.000 0.0000 61.920 60.440 29.670
+328 "S24" 0.0000 29.804 40.000 0.0000 56.270 52.000 26.160
+329 "S21" 0.0000 40.000 40.000 0.0000 51.050 44.280 22.780
+330 "P44" 0.0000 54.902 40.000 0.0000 44.100 34.130 17.920
+331 "X56" 0.0000 70.196 40.000 0.0000 38.280 26.120 13.860
+332 "C4" 0.0000 85.098 40.000 0.0000 34.370 20.590 10.880
+333 "O34" 0.0000 100.00 40.000 0.0000 31.270 16.470 8.4900
+334 "E31" 10.196 0.0000 40.000 0.0000 66.000 72.030 36.270
+335 "H57" 10.196 10.196 40.000 0.0000 60.440 63.300 32.890
+336 "O20" 10.196 20.000 40.000 0.0000 55.270 55.310 29.430
+337 "B40" 10.196 29.804 40.000 0.0000 50.100 47.480 25.830
+338 "X49" 10.196 40.000 40.000 0.0000 45.250 40.270 22.370
+339 "V34" 10.196 54.902 40.000 0.0000 39.050 31.050 17.670
+340 "Q1" 10.196 70.196 40.000 0.0000 33.900 23.770 13.770
+341 "C6" 10.196 85.098 40.000 0.0000 30.390 18.640 10.880
+342 "A46" 10.196 100.00 40.000 0.0000 27.580 14.780 8.5600
+343 "Y15" 20.000 0.0000 40.000 0.0000 57.590 64.730 35.140
+344 "N53" 20.000 10.196 40.000 0.0000 52.850 56.990 32.000
+345 "AA23" 20.000 20.000 40.000 0.0000 48.380 49.850 28.590
+346 "Y35" 20.000 29.804 40.000 0.0000 43.740 42.660 25.010
+347 "C9" 20.000 40.000 40.000 0.0000 39.390 36.060 21.630
+348 "Y46" 20.000 54.902 40.000 0.0000 34.000 27.850 17.190
+349 "L22" 20.000 70.196 40.000 0.0000 29.520 21.330 13.510
+350 "C36" 20.000 85.098 40.000 0.0000 26.380 16.620 10.760
+351 "M34" 20.000 100.00 40.000 0.0000 23.800 13.020 8.5200
+352 "S4" 29.804 0.0000 40.000 0.0000 49.550 57.650 34.070
+353 "Z33" 29.804 10.196 40.000 0.0000 45.360 50.640 31.000
+354 "Q46" 29.804 20.000 40.000 0.0000 41.620 44.370 27.750
+355 "A18" 29.804 29.804 40.000 0.0000 37.650 38.000 24.370
+356 "M23" 29.804 40.000 40.000 0.0000 33.870 32.100 21.180
+357 "L43" 29.804 54.902 40.000 0.0000 29.130 24.710 16.880
+358 "T40" 29.804 70.196 40.000 0.0000 25.190 18.840 13.300
+359 "G3" 29.804 85.098 40.000 0.0000 22.450 14.590 10.630
+360 "P8" 29.804 100.00 40.000 0.0000 20.210 11.340 8.4500
+361 "K34" 40.000 0.0000 40.000 0.0000 42.140 51.000 33.060
+362 "P30" 40.000 10.196 40.000 0.0000 38.440 44.670 30.030
+363 "O45" 40.000 20.000 40.000 0.0000 35.330 39.180 26.960
+364 "R6" 40.000 29.804 40.000 0.0000 31.990 33.600 23.810
+365 "L41" 40.000 40.000 40.000 0.0000 28.770 28.400 20.790
+366 "M18" 40.000 54.902 40.000 0.0000 24.680 21.800 16.630
+367 "K32" 40.000 70.196 40.000 0.0000 21.270 16.540 13.140
+368 "S50" 40.000 85.098 40.000 0.0000 18.910 12.740 10.540
+369 "G39" 40.000 100.00 40.000 0.0000 16.990 9.8300 8.4100
+370 "G20" 54.902 0.0000 40.000 0.0000 32.390 42.020 31.550
+371 "P34" 54.902 10.196 40.000 0.0000 29.520 36.740 28.640
+372 "P50" 54.902 20.000 40.000 0.0000 27.010 32.130 25.760
+373 "H9" 54.902 29.804 40.000 0.0000 24.380 27.510 22.780
+374 "Z7" 54.902 40.000 40.000 0.0000 21.910 23.260 19.950
+375 "V32" 54.902 54.902 40.000 0.0000 18.920 17.960 16.180
+376 "S34" 54.902 70.196 40.000 0.0000 16.410 13.690 13.000
+377 "C29" 54.902 85.098 40.000 0.0000 14.520 10.470 10.540
+378 "X42" 54.902 100.00 40.000 0.0000 12.920 7.9500 8.4900
+379 "Y20" 70.196 0.0000 40.000 0.0000 24.130 34.160 30.170
+380 "A42" 70.196 10.196 40.000 0.0000 22.000 29.870 27.400
+381 "V6" 70.196 20.000 40.000 0.0000 20.030 26.030 24.680
+382 "A47" 70.196 29.804 40.000 0.0000 18.020 22.270 21.860
+383 "I57" 70.196 40.000 40.000 0.0000 16.190 18.840 19.200
+384 "C25" 70.196 54.902 40.000 0.0000 14.100 14.650 15.780
+385 "Q57" 70.196 70.196 40.000 0.0000 12.330 11.240 12.880
+386 "E25" 70.196 85.098 40.000 0.0000 10.860 8.5400 10.550
+387 "U36" 70.196 100.00 40.000 0.0000 9.5600 6.3900 8.5800
+388 "F17" 85.098 0.0000 40.000 0.0000 17.320 27.680 29.170
+389 "C8" 85.098 10.196 40.000 0.0000 15.830 24.270 26.620
+390 "F36" 85.098 20.000 40.000 0.0000 14.420 21.160 24.040
+391 "D7" 85.098 29.804 40.000 0.0000 13.000 18.150 21.410
+392 "AA27" 85.098 40.000 40.000 0.0000 11.710 15.410 18.910
+393 "T19" 85.098 54.902 40.000 0.0000 10.180 11.970 15.610
+394 "G56" 85.098 70.196 40.000 0.0000 8.8800 9.1500 12.790
+395 "Z19" 85.098 85.098 40.000 0.0000 7.8000 6.9300 10.540
+396 "J44" 85.098 100.00 40.000 0.0000 6.8600 5.1600 8.6400
+397 "E23" 100.00 0.0000 40.000 0.0000 11.990 22.160 28.290
+398 "X25" 100.00 10.196 40.000 0.0000 10.980 19.510 25.970
+399 "F4" 100.00 20.000 40.000 0.0000 10.040 17.070 23.530
+400 "V41" 100.00 29.804 40.000 0.0000 9.1100 14.730 21.100
+401 "X48" 100.00 40.000 40.000 0.0000 8.2400 12.570 18.770
+402 "W42" 100.00 54.902 40.000 0.0000 7.1100 9.7100 15.500
+403 "W9" 100.00 70.196 40.000 0.0000 6.1400 7.3700 12.690
+404 "M35" 100.00 85.098 40.000 0.0000 5.3800 5.5800 10.500
+405 "I4" 100.00 100.00 40.000 0.0000 4.7300 4.1600 8.6800
+406 "M15" 0.0000 0.0000 54.902 0.0000 71.850 76.950 25.370
+407 "L46" 0.0000 10.196 54.902 0.0000 65.680 67.470 22.770
+408 "D21" 0.0000 20.000 54.902 0.0000 59.880 58.740 20.360
+409 "AA6" 0.0000 29.804 54.902 0.0000 54.450 50.550 17.950
+410 "Z55" 0.0000 40.000 54.902 0.0000 49.460 43.080 15.630
+411 "L35" 0.0000 54.902 54.902 0.0000 42.980 33.400 12.470
+412 "O33" 0.0000 70.196 54.902 0.0000 37.560 25.750 9.8100
+413 "X31" 0.0000 85.098 54.902 0.0000 33.860 20.410 7.7800
+414 "Q8" 0.0000 100.00 54.902 0.0000 30.910 16.400 6.1200
+415 "U43" 10.196 0.0000 54.902 0.0000 63.580 69.930 24.890
+416 "C55" 10.196 10.196 54.902 0.0000 58.240 61.470 22.580
+417 "A48" 10.196 20.000 54.902 0.0000 53.250 53.660 20.240
+418 "R39" 10.196 29.804 54.902 0.0000 48.380 46.160 17.810
+419 "D49" 10.196 40.000 54.902 0.0000 43.840 39.280 15.490
+420 "J30" 10.196 54.902 54.902 0.0000 38.020 30.410 12.360
+421 "I48" 10.196 70.196 54.902 0.0000 33.160 23.390 9.7500
+422 "L31" 10.196 85.098 54.902 0.0000 29.860 18.460 7.7800
+423 "Q54" 10.196 100.00 54.902 0.0000 27.220 14.740 6.1800
+424 "I5" 20.000 0.0000 54.902 0.0000 55.290 62.740 24.130
+425 "Z30" 20.000 10.196 54.902 0.0000 50.730 55.220 22.030
+426 "W18" 20.000 20.000 54.902 0.0000 46.420 48.250 19.660
+427 "K29" 20.000 29.804 54.902 0.0000 42.090 41.390 17.270
+428 "S43" 20.000 40.000 54.902 0.0000 38.060 35.130 15.040
+429 "T6" 20.000 54.902 54.902 0.0000 33.020 27.230 12.030
+430 "F20" 20.000 70.196 54.902 0.0000 28.810 20.960 9.5300
+431 "P22" 20.000 85.098 54.902 0.0000 25.880 16.440 7.6700
+432 "F37" 20.000 100.00 54.902 0.0000 23.490 12.990 6.1500
+433 "E36" 29.804 0.0000 54.902 0.0000 47.380 55.770 23.500
+434 "J42" 29.804 10.196 54.902 0.0000 43.320 48.960 21.370
+435 "R16" 29.804 20.000 54.902 0.0000 39.750 42.870 19.180
+436 "D57" 29.804 29.804 54.902 0.0000 36.070 36.810 16.890
+437 "J17" 29.804 40.000 54.902 0.0000 32.590 31.210 14.710
+438 "A39" 29.804 54.902 54.902 0.0000 28.190 24.120 11.810
+439 "I23" 29.804 70.196 54.902 0.0000 24.530 18.480 9.3900
+440 "G31" 29.804 85.098 54.902 0.0000 22.000 14.420 7.5900
+441 "O18" 29.804 100.00 54.902 0.0000 19.930 11.320 6.1100
+442 "L19" 40.000 0.0000 54.902 0.0000 40.090 49.230 22.920
+443 "U13" 40.000 10.196 54.902 0.0000 36.510 43.100 20.740
+444 "U20" 40.000 20.000 54.902 0.0000 33.580 37.810 18.740
+445 "U26" 40.000 29.804 54.902 0.0000 30.510 32.510 16.560
+446 "AA51" 40.000 40.000 54.902 0.0000 27.550 27.560 14.450
+447 "Y3" 40.000 54.902 54.902 0.0000 23.780 21.240 11.650
+448 "E42" 40.000 70.196 54.902 0.0000 20.630 16.200 9.3100
+449 "F33" 40.000 85.098 54.902 0.0000 18.460 12.570 7.5500
+450 "U19" 40.000 100.00 54.902 0.0000 16.710 9.8100 6.1000
+451 "I45" 54.902 0.0000 54.902 0.0000 30.490 40.400 21.940
+452 "D44" 54.902 10.196 54.902 0.0000 27.770 35.360 19.870
+453 "W41" 54.902 20.000 54.902 0.0000 25.450 30.940 18.010
+454 "X14" 54.902 29.804 54.902 0.0000 23.100 26.600 16.000
+455 "S16" 54.902 40.000 54.902 0.0000 20.880 22.580 14.040
+456 "E21" 54.902 54.902 54.902 0.0000 18.070 17.450 11.410
+457 "R29" 54.902 70.196 54.902 0.0000 15.710 13.320 9.2100
+458 "D4" 54.902 85.098 54.902 0.0000 14.010 10.270 7.5500
+459 "N47" 54.902 100.00 54.902 0.0000 12.590 7.9000 6.1800
+460 "W49" 70.196 0.0000 54.902 0.0000 22.390 32.710 21.050
+461 "E50" 70.196 10.196 54.902 0.0000 20.430 28.660 19.130
+462 "P15" 70.196 20.000 54.902 0.0000 18.630 25.000 17.350
+463 "T34" 70.196 29.804 54.902 0.0000 16.890 21.490 15.480
+464 "G29" 70.196 40.000 54.902 0.0000 15.290 18.280 13.670
+465 "Q21" 70.196 54.902 54.902 0.0000 13.300 14.180 11.210
+466 "C12" 70.196 70.196 54.902 0.0000 11.600 10.850 9.1300
+467 "E44" 70.196 85.098 54.902 0.0000 10.300 8.3100 7.5600
+468 "G41" 70.196 100.00 54.902 0.0000 9.1900 6.3100 6.2600
+469 "S25" 85.098 0.0000 54.902 0.0000 15.750 26.400 20.560
+470 "N44" 85.098 10.196 54.902 0.0000 14.390 23.190 18.740
+471 "V48" 85.098 20.000 54.902 0.0000 13.140 20.250 16.990
+472 "R51" 85.098 29.804 54.902 0.0000 11.930 17.440 15.210
+473 "I47" 85.098 40.000 54.902 0.0000 10.800 14.850 13.490
+474 "I39" 85.098 54.902 54.902 0.0000 9.4100 11.510 11.140
+475 "I36" 85.098 70.196 54.902 0.0000 8.2100 8.8000 9.1400
+476 "L10" 85.098 85.098 54.902 0.0000 7.2700 6.7200 7.5900
+477 "O11" 85.098 100.00 54.902 0.0000 6.4700 5.0700 6.3100
+478 "T55" 100.00 0.0000 54.902 0.0000 10.570 21.060 20.180
+479 "Y53" 100.00 10.196 54.902 0.0000 9.6800 18.550 18.440
+480 "N16" 100.00 20.000 54.902 0.0000 8.8700 16.280 16.720
+481 "W55" 100.00 29.804 54.902 0.0000 8.0700 14.050 15.000
+482 "Q35" 100.00 40.000 54.902 0.0000 7.3200 11.980 13.370
+483 "S10" 100.00 54.902 54.902 0.0000 6.3600 9.2700 11.100
+484 "S53" 100.00 70.196 54.902 0.0000 5.5400 7.0700 9.1600
+485 "R15" 100.00 85.098 54.902 0.0000 4.8900 5.3900 7.6300
+486 "H44" 100.00 100.00 54.902 0.0000 4.3500 4.0800 6.3500
+487 "H14" 0.0000 0.0000 70.196 0.0000 69.800 74.880 16.470
+488 "B12" 0.0000 10.196 70.196 0.0000 63.780 65.610 14.710
+489 "R17" 0.0000 20.000 70.196 0.0000 58.230 57.180 13.230
+490 "T13" 0.0000 29.804 70.196 0.0000 52.990 49.220 11.670
+491 "AA21" 0.0000 40.000 70.196 0.0000 48.170 41.980 10.170
+492 "K46" 0.0000 54.902 70.196 0.0000 42.070 32.730 8.2600
+493 "S29" 0.0000 70.196 70.196 0.0000 36.970 25.400 6.6500
+494 "C40" 0.0000 85.098 70.196 0.0000 33.440 20.220 5.3500
+495 "Q6" 0.0000 100.00 70.196 0.0000 30.600 16.310 4.2700
+496 "F34" 10.196 0.0000 70.196 0.0000 61.650 68.010 16.120
+497 "I7" 10.196 10.196 70.196 0.0000 56.470 59.790 14.610
+498 "P27" 10.196 20.000 70.196 0.0000 51.630 52.160 13.150
+499 "Z2" 10.196 29.804 70.196 0.0000 47.010 44.970 11.630
+500 "AA33" 10.196 40.000 70.196 0.0000 42.730 38.390 10.180
+501 "C38" 10.196 54.902 70.196 0.0000 37.200 29.830 8.2300
+502 "J14" 10.196 70.196 70.196 0.0000 32.570 23.030 6.6000
+503 "S38" 10.196 85.098 70.196 0.0000 29.430 18.250 5.3400
+504 "E26" 10.196 100.00 70.196 0.0000 26.920 14.660 4.3100
+505 "G6" 20.000 0.0000 70.196 0.0000 53.480 60.950 15.650
+506 "E55" 20.000 10.196 70.196 0.0000 49.030 53.620 14.290
+507 "N14" 20.000 20.000 70.196 0.0000 44.850 46.800 12.780
+508 "P37" 20.000 29.804 70.196 0.0000 40.780 40.270 11.310
+509 "Z24" 20.000 40.000 70.196 0.0000 37.020 34.300 9.9300
+510 "J34" 20.000 54.902 70.196 0.0000 32.230 26.660 8.0300
+511 "W52" 20.000 70.196 70.196 0.0000 28.240 20.580 6.4300
+512 "I13" 20.000 85.098 70.196 0.0000 25.470 16.240 5.2400
+513 "V52" 20.000 100.00 70.196 0.0000 23.240 12.930 4.2800
+514 "J54" 29.804 0.0000 70.196 0.0000 45.620 54.040 15.320
+515 "D31" 29.804 10.196 70.196 0.0000 41.700 47.430 13.880
+516 "V16" 29.804 20.000 70.196 0.0000 38.240 41.500 12.520
+517 "J2" 29.804 29.804 70.196 0.0000 34.800 35.730 11.090
+518 "Z13" 29.804 40.000 70.196 0.0000 31.560 30.400 9.7100
+519 "B19" 29.804 54.902 70.196 0.0000 27.450 23.570 7.8800
+520 "G10" 29.804 70.196 70.196 0.0000 24.000 18.130 6.3400
+521 "X12" 29.804 85.098 70.196 0.0000 21.630 14.240 5.2000
+522 "U10" 29.804 100.00 70.196 0.0000 19.700 11.270 4.2700
+523 "Y14" 40.000 0.0000 70.196 0.0000 38.400 47.570 15.020
+524 "E24" 40.000 10.196 70.196 0.0000 34.980 41.670 13.500
+525 "S8" 40.000 20.000 70.196 0.0000 32.150 36.540 12.320
+526 "D36" 40.000 29.804 70.196 0.0000 29.300 31.490 10.920
+527 "P9" 40.000 40.000 70.196 0.0000 26.580 26.800 9.5400
+528 "T36" 40.000 54.902 70.196 0.0000 23.070 20.720 7.7800
+529 "C19" 40.000 70.196 70.196 0.0000 20.120 15.860 6.3000
+530 "J46" 40.000 85.098 70.196 0.0000 18.100 12.400 5.1900
+531 "Q44" 40.000 100.00 70.196 0.0000 16.480 9.7600 4.2800
+532 "J12" 54.902 0.0000 70.196 0.0000 28.990 38.930 14.450
+533 "V12" 54.902 10.196 70.196 0.0000 26.430 34.130 13.060
+534 "F7" 54.902 20.000 70.196 0.0000 24.220 29.870 11.960
+535 "R35" 54.902 29.804 70.196 0.0000 22.100 25.790 10.700
+536 "Q16" 54.902 40.000 70.196 0.0000 20.110 22.000 9.4300
+537 "D11" 54.902 54.902 70.196 0.0000 17.420 16.980 7.7000
+538 "L39" 54.902 70.196 70.196 0.0000 15.150 12.950 6.2500
+539 "Y44" 54.902 85.098 70.196 0.0000 13.580 10.050 5.2000
+540 "A4" 54.902 100.00 70.196 0.0000 12.310 7.8300 4.3500
+541 "E30" 70.196 0.0000 70.196 0.0000 21.040 31.420 13.950
+542 "O51" 70.196 10.196 70.196 0.0000 19.240 27.610 12.700
+543 "W30" 70.196 20.000 70.196 0.0000 17.560 24.110 11.650
+544 "V51" 70.196 29.804 70.196 0.0000 16.050 20.840 10.500
+545 "J39" 70.196 40.000 70.196 0.0000 14.640 17.820 9.3400
+546 "L29" 70.196 54.902 70.196 0.0000 12.690 13.760 7.6500
+547 "X1" 70.196 70.196 70.196 0.0000 11.020 10.470 6.2200
+548 "T7" 70.196 85.098 70.196 0.0000 9.8400 8.0700 5.2200
+549 "U46" 70.196 100.00 70.196 0.0000 8.8800 6.2200 4.4200
+550 "T12" 85.098 0.0000 70.196 0.0000 14.510 25.260 13.810
+551 "I6" 85.098 10.196 70.196 0.0000 13.280 22.230 12.580
+552 "S46" 85.098 20.000 70.196 0.0000 12.150 19.450 11.490
+553 "H55" 85.098 29.804 70.196 0.0000 11.100 16.810 10.370
+554 "B36" 85.098 40.000 70.196 0.0000 10.120 14.360 9.2600
+555 "E34" 85.098 54.902 70.196 0.0000 8.8000 11.100 7.6600
+556 "N1" 85.098 70.196 70.196 0.0000 7.6600 8.4500 6.3000
+557 "A12" 85.098 85.098 70.196 0.0000 6.8300 6.4900 5.2900
+558 "N5" 85.098 100.00 70.196 0.0000 6.1500 4.9800 4.4600
+559 "T25" 100.00 0.0000 70.196 0.0000 9.4400 20.050 13.750
+560 "R49" 100.00 10.196 70.196 0.0000 8.6300 17.670 12.510
+561 "K35" 100.00 20.000 70.196 0.0000 7.9400 15.540 11.370
+562 "W17" 100.00 29.804 70.196 0.0000 7.2400 13.420 10.240
+563 "M32" 100.00 40.000 70.196 0.0000 6.5800 11.440 9.1600
+564 "Z16" 100.00 54.902 70.196 0.0000 5.7500 8.8500 7.6900
+565 "O32" 100.00 70.196 70.196 0.0000 5.0400 6.7700 6.4100
+566 "E3" 100.00 85.098 70.196 0.0000 4.4900 5.2000 5.3600
+567 "H16" 100.00 100.00 70.196 0.0000 4.0200 3.9800 4.4800
+568 "J8" 0.0000 0.0000 85.098 0.0000 68.430 73.430 10.410
+569 "Q51" 0.0000 10.196 85.098 0.0000 62.490 64.260 9.2600
+570 "L51" 0.0000 20.000 85.098 0.0000 57.100 56.050 8.3900
+571 "Z26" 0.0000 29.804 85.098 0.0000 52.030 48.310 7.4600
+572 "G8" 0.0000 40.000 85.098 0.0000 47.370 41.250 6.5500
+573 "S56" 0.0000 54.902 85.098 0.0000 41.420 32.200 5.4000
+574 "AA30" 0.0000 70.196 85.098 0.0000 36.460 25.040 4.4200
+575 "E18" 0.0000 85.098 85.098 0.0000 33.070 20.020 3.6500
+576 "K48" 0.0000 100.00 85.098 0.0000 30.360 16.240 3.0200
+577 "B2" 10.196 0.0000 85.098 0.0000 60.350 66.640 10.190
+578 "T35" 10.196 10.196 85.098 0.0000 55.320 58.620 9.2000
+579 "V8" 10.196 20.000 85.098 0.0000 50.600 51.150 8.3400
+580 "T41" 10.196 29.804 85.098 0.0000 46.130 44.150 7.4400
+581 "H24" 10.196 40.000 85.098 0.0000 42.000 37.750 6.5500
+582 "C46" 10.196 54.902 85.098 0.0000 36.660 29.410 5.3900
+583 "C1" 10.196 70.196 85.098 0.0000 32.180 22.780 4.4100
+584 "D19" 10.196 85.098 85.098 0.0000 29.130 18.110 3.6700
+585 "P20" 10.196 100.00 85.098 0.0000 26.690 14.580 3.0600
+586 "U9" 20.000 0.0000 85.098 0.0000 52.310 59.720 9.9000
+587 "Y5" 20.000 10.196 85.098 0.0000 47.960 52.550 9.0200
+588 "C13" 20.000 20.000 85.098 0.0000 43.970 45.950 8.1400
+589 "Y51" 20.000 29.804 85.098 0.0000 40.050 39.610 7.2600
+590 "AA10" 20.000 40.000 85.098 0.0000 36.390 33.790 6.4300
+591 "A29" 20.000 54.902 85.098 0.0000 31.730 26.280 5.2800
+592 "AA19" 20.000 70.196 85.098 0.0000 27.830 20.300 4.3100
+593 "C53" 20.000 85.098 85.098 0.0000 25.180 16.080 3.6100
+594 "U28" 20.000 100.00 85.098 0.0000 23.040 12.880 3.0500
+595 "A13" 29.804 0.0000 85.098 0.0000 44.520 52.890 9.7300
+596 "U23" 29.804 10.196 85.098 0.0000 40.790 46.510 8.8100
+597 "U21" 29.804 20.000 85.098 0.0000 37.450 40.750 8.0000
+598 "I52" 29.804 29.804 85.098 0.0000 34.100 35.100 7.1400
+599 "M53" 29.804 40.000 85.098 0.0000 30.950 29.880 6.3100
+600 "T20" 29.804 54.902 85.098 0.0000 26.950 23.190 5.2100
+601 "G18" 29.804 70.196 85.098 0.0000 23.610 17.870 4.2800
+602 "E27" 29.804 85.098 85.098 0.0000 21.330 14.090 3.6000
+603 "M11" 29.804 100.00 85.098 0.0000 19.500 11.220 3.0500
+604 "A35" 40.000 0.0000 85.098 0.0000 37.360 46.510 9.5900
+605 "Q5" 40.000 10.196 85.098 0.0000 34.210 40.890 8.6200
+606 "N56" 40.000 20.000 85.098 0.0000 31.430 35.860 7.9100
+607 "E52" 40.000 29.804 85.098 0.0000 28.620 30.880 7.0700
+608 "D29" 40.000 40.000 85.098 0.0000 25.980 26.280 6.2400
+609 "R4" 40.000 54.902 85.098 0.0000 22.590 20.350 5.1700
+610 "J27" 40.000 70.196 85.098 0.0000 19.760 15.630 4.2800
+611 "K56" 40.000 85.098 85.098 0.0000 17.820 12.260 3.6200
+612 "D20" 40.000 100.00 85.098 0.0000 16.260 9.7000 3.0700
+613 "I14" 54.902 0.0000 85.098 0.0000 28.140 38.070 9.3200
+614 "R33" 54.902 10.196 85.098 0.0000 25.790 33.510 8.4400
+615 "I24" 54.902 20.000 85.098 0.0000 23.570 29.290 7.7800
+616 "Y29" 54.902 29.804 85.098 0.0000 21.530 25.290 7.0200
+617 "V3" 54.902 40.000 85.098 0.0000 19.630 21.590 6.2400
+618 "L26" 54.902 54.902 85.098 0.0000 17.020 16.690 5.1800
+619 "I53" 54.902 70.196 85.098 0.0000 14.810 12.750 4.2900
+620 "Z17" 54.902 85.098 85.098 0.0000 13.300 9.9200 3.6500
+621 "O10" 54.902 100.00 85.098 0.0000 12.080 7.7600 3.1300
+622 "A24" 70.196 0.0000 85.098 0.0000 20.310 30.710 9.0900
+623 "I33" 70.196 10.196 85.098 0.0000 18.650 27.080 8.3300
+624 "K49" 70.196 20.000 85.098 0.0000 16.970 23.600 7.6800
+625 "N8" 70.196 29.804 85.098 0.0000 15.540 20.420 6.9800
+626 "A10" 70.196 40.000 85.098 0.0000 14.240 17.500 6.2700
+627 "J4" 70.196 54.902 85.098 0.0000 12.330 13.510 5.2100
+628 "M29" 70.196 70.196 85.098 0.0000 10.690 10.280 4.3200
+629 "N34" 70.196 85.098 85.098 0.0000 9.5500 7.9500 3.6900
+630 "Q10" 70.196 100.00 85.098 0.0000 8.6400 6.1600 3.1800
+631 "O6" 85.098 0.0000 85.098 0.0000 13.780 24.590 9.1200
+632 "Q53" 85.098 10.196 85.098 0.0000 12.670 21.710 8.3700
+633 "AA24" 85.098 20.000 85.098 0.0000 11.550 18.950 7.7100
+634 "G43" 85.098 29.804 85.098 0.0000 10.580 16.400 7.0200
+635 "P38" 85.098 40.000 85.098 0.0000 9.6900 14.050 6.3400
+636 "D12" 85.098 54.902 85.098 0.0000 8.4200 10.860 5.3200
+637 "H2" 85.098 70.196 85.098 0.0000 7.3300 8.2700 4.4400
+638 "Q12" 85.098 85.098 85.098 0.0000 6.5500 6.3700 3.7700
+639 "E35" 85.098 100.00 85.098 0.0000 5.9100 4.9100 3.2100
+640 "U1" 100.00 0.0000 85.098 0.0000 8.6800 19.390 9.2000
+641 "F53" 100.00 10.196 85.098 0.0000 7.9800 17.120 8.4600
+642 "L25" 100.00 20.000 85.098 0.0000 7.3400 15.040 7.7500
+643 "U15" 100.00 29.804 85.098 0.0000 6.7100 13.000 7.0600
+644 "W11" 100.00 40.000 85.098 0.0000 6.1100 11.110 6.4000
+645 "X6" 100.00 54.902 85.098 0.0000 5.3500 8.6100 5.4400
+646 "L40" 100.00 70.196 85.098 0.0000 4.7100 6.5900 4.5900
+647 "M37" 100.00 85.098 85.098 0.0000 4.2100 5.0800 3.8600
+648 "S33" 100.00 100.00 85.098 0.0000 3.8000 3.9100 3.2300
+649 "A2" 0.0000 0.0000 100.00 0.0000 67.430 72.230 6.1400
+650 "H56" 0.0000 10.196 100.00 0.0000 61.540 63.120 5.4400
+651 "G2" 0.0000 20.000 100.00 0.0000 56.250 55.090 4.9800
+652 "O22" 0.0000 29.804 100.00 0.0000 51.340 47.560 4.5000
+653 "X37" 0.0000 40.000 100.00 0.0000 46.820 40.680 4.0200
+654 "M16" 0.0000 54.902 100.00 0.0000 40.930 31.740 3.3500
+655 "N24" 0.0000 70.196 100.00 0.0000 36.020 24.690 2.7900
+656 "P2" 0.0000 85.098 100.00 0.0000 32.750 19.830 2.4100
+657 "G42" 0.0000 100.00 100.00 0.0000 30.180 16.190 2.1100
+658 "B3" 10.196 0.0000 100.00 0.0000 59.400 65.500 6.0300
+659 "K14" 10.196 10.196 100.00 0.0000 54.490 57.660 5.4100
+660 "Z43" 10.196 20.000 100.00 0.0000 49.880 50.340 4.9600
+661 "Z48" 10.196 29.804 100.00 0.0000 45.510 43.480 4.4700
+662 "Q40" 10.196 40.000 100.00 0.0000 41.480 37.210 3.9800
+663 "D10" 10.196 54.902 100.00 0.0000 36.280 29.070 3.3500
+664 "B48" 10.196 70.196 100.00 0.0000 31.910 22.580 2.8200
+665 "Q20" 10.196 85.098 100.00 0.0000 28.920 17.990 2.4500
+666 "C31" 10.196 100.00 100.00 0.0000 26.500 14.500 2.1500
+667 "W14" 20.000 0.0000 100.00 0.0000 51.490 58.710 5.8500
+668 "A31" 20.000 10.196 100.00 0.0000 47.230 51.690 5.3000
+669 "C7" 20.000 20.000 100.00 0.0000 43.430 45.310 4.8600
+670 "X50" 20.000 29.804 100.00 0.0000 39.600 39.120 4.3900
+671 "A6" 20.000 40.000 100.00 0.0000 35.980 33.390 3.9300
+672 "L17" 20.000 54.902 100.00 0.0000 31.380 25.970 3.3100
+673 "U47" 20.000 70.196 100.00 0.0000 27.540 20.080 2.7900
+674 "N40" 20.000 85.098 100.00 0.0000 24.950 15.950 2.4400
+675 "S57" 20.000 100.00 100.00 0.0000 22.890 12.830 2.1600
+676 "T46" 29.804 0.0000 100.00 0.0000 43.750 51.970 5.7800
+677 "F56" 29.804 10.196 100.00 0.0000 40.230 45.810 5.2200
+678 "F15" 29.804 20.000 100.00 0.0000 37.010 40.220 4.8000
+679 "P29" 29.804 29.804 100.00 0.0000 33.680 34.640 4.3400
+680 "H40" 29.804 40.000 100.00 0.0000 30.540 29.480 3.9000
+681 "P57" 29.804 54.902 100.00 0.0000 26.590 22.880 3.3000
+682 "E39" 29.804 70.196 100.00 0.0000 23.310 17.660 2.8000
+683 "Z10" 29.804 85.098 100.00 0.0000 21.090 13.970 2.4500
+684 "Q32" 29.804 100.00 100.00 0.0000 19.320 11.170 2.1700
+685 "Q31" 40.000 0.0000 100.00 0.0000 36.650 45.670 5.7400
+686 "W47" 40.000 10.196 100.00 0.0000 33.800 40.340 5.1800
+687 "T39" 40.000 20.000 100.00 0.0000 31.030 35.390 4.7700
+688 "B24" 40.000 29.804 100.00 0.0000 28.210 30.420 4.3300
+689 "S36" 40.000 40.000 100.00 0.0000 25.560 25.850 3.8900
+690 "D23" 40.000 54.902 100.00 0.0000 22.240 20.050 3.3200
+691 "W1" 40.000 70.196 100.00 0.0000 19.480 15.450 2.8300
+692 "K52" 40.000 85.098 100.00 0.0000 17.580 12.160 2.4800
+693 "I37" 40.000 100.00 100.00 0.0000 16.060 9.6400 2.1900
+694 "G27" 54.902 0.0000 100.00 0.0000 27.620 37.430 5.6700
+695 "B9" 54.902 10.196 100.00 0.0000 25.500 33.120 5.1700
+696 "F40" 54.902 20.000 100.00 0.0000 23.220 28.890 4.7800
+697 "G16" 54.902 29.804 100.00 0.0000 21.180 24.900 4.3600
+698 "L9" 54.902 40.000 100.00 0.0000 19.320 21.260 3.9400
+699 "S37" 54.902 54.902 100.00 0.0000 16.760 16.460 3.3700
+700 "L56" 54.902 70.196 100.00 0.0000 14.590 12.610 2.8900
+701 "H47" 54.902 85.098 100.00 0.0000 13.090 9.8300 2.5300
+702 "Y56" 54.902 100.00 100.00 0.0000 11.880 7.7100 2.2400
+703 "S26" 70.196 0.0000 100.00 0.0000 19.890 30.210 5.6200
+704 "E9" 70.196 10.196 100.00 0.0000 18.370 26.750 5.2000
+705 "R11" 70.196 20.000 100.00 0.0000 16.620 23.220 4.8300
+706 "T30" 70.196 29.804 100.00 0.0000 15.220 20.080 4.4200
+707 "X40" 70.196 40.000 100.00 0.0000 13.980 17.240 4.0200
+708 "O31" 70.196 54.902 100.00 0.0000 12.100 13.330 3.4500
+709 "Y6" 70.196 70.196 100.00 0.0000 10.490 10.160 2.9600
+710 "G26" 70.196 85.098 100.00 0.0000 9.3600 7.8700 2.5900
+711 "A52" 70.196 100.00 100.00 0.0000 8.4500 6.1000 2.2800
+712 "B56" 85.098 0.0000 100.00 0.0000 13.310 24.080 5.7300
+713 "F48" 85.098 10.196 100.00 0.0000 12.310 21.330 5.3500
+714 "Y28" 85.098 20.000 100.00 0.0000 11.170 18.560 4.9800
+715 "K13" 85.098 29.804 100.00 0.0000 10.230 16.070 4.5900
+716 "U17" 85.098 40.000 100.00 0.0000 9.4000 13.810 4.2100
+717 "L55" 85.098 54.902 100.00 0.0000 8.1700 10.690 3.6300
+718 "F8" 85.098 70.196 100.00 0.0000 7.1000 8.1500 3.1100
+719 "D37" 85.098 85.098 100.00 0.0000 6.3500 6.2900 2.6800
+720 "K44" 85.098 100.00 100.00 0.0000 5.7300 4.8500 2.3000
+721 "D56" 100.00 0.0000 100.00 0.0000 8.1500 18.840 5.8600
+722 "J41" 100.00 10.196 100.00 0.0000 7.5400 16.690 5.5300
+723 "Z46" 100.00 20.000 100.00 0.0000 6.9300 14.620 5.1500
+724 "L36" 100.00 29.804 100.00 0.0000 6.3300 12.660 4.7900
+725 "M20" 100.00 40.000 100.00 0.0000 5.7800 10.860 4.4300
+726 "E1" 100.00 54.902 100.00 0.0000 5.0700 8.4400 3.8400
+727 "R1" 100.00 70.196 100.00 0.0000 4.4600 6.4700 3.2900
+728 "N48" 100.00 85.098 100.00 0.0000 4.0000 5.0000 2.7700
+729 "K6" 100.00 100.00 100.00 0.0000 3.6300 3.8400 2.3100
+730 "AA40" 0.0000 0.0000 0.0000 20.000 58.360 60.610 53.170
+731 "D43" 0.0000 10.196 0.0000 20.000 53.610 53.700 48.160
+732 "E29" 0.0000 20.000 0.0000 20.000 48.890 47.040 42.950
+733 "D54" 0.0000 40.000 0.0000 20.000 40.030 34.580 32.840
+734 "F49" 0.0000 70.196 0.0000 20.000 29.450 20.200 19.890
+735 "B5" 0.0000 100.00 0.0000 20.000 23.380 12.170 11.950
+736 "U31" 10.196 0.0000 0.0000 20.000 52.670 55.730 51.910
+737 "V38" 10.196 10.196 0.0000 20.000 48.300 49.300 47.050
+738 "P46" 10.196 20.000 0.0000 20.000 44.110 43.230 41.990
+739 "X29" 10.196 40.000 0.0000 20.000 36.000 31.630 32.080
+740 "J7" 10.196 70.196 0.0000 20.000 26.440 18.410 19.540
+741 "M31" 10.196 100.00 0.0000 20.000 20.820 10.960 11.830
+742 "P35" 20.000 0.0000 0.0000 20.000 46.630 50.470 50.570
+743 "B25" 20.000 10.196 0.0000 20.000 42.900 44.780 45.930
+744 "U25" 20.000 20.000 0.0000 20.000 39.260 39.330 41.130
+745 "N32" 20.000 40.000 0.0000 20.000 31.990 28.770 31.460
+746 "H39" 20.000 70.196 0.0000 20.000 23.430 16.720 19.310
+747 "Z22" 20.000 100.00 0.0000 20.000 18.200 9.7200 11.760
+748 "Q7" 40.000 0.0000 0.0000 20.000 34.990 40.080 47.760
+749 "L37" 40.000 10.196 0.0000 20.000 32.140 35.530 43.290
+750 "S28" 40.000 20.000 0.0000 20.000 29.450 31.220 38.810
+751 "T9" 40.000 40.000 0.0000 20.000 24.220 23.070 30.090
+752 "F16" 40.000 70.196 0.0000 20.000 17.690 13.370 18.770
+753 "M5" 40.000 100.00 0.0000 20.000 13.490 7.5300 11.800
+754 "S47" 70.196 0.0000 0.0000 20.000 21.560 27.570 43.680
+755 "M49" 70.196 10.196 0.0000 20.000 19.770 24.420 39.700
+756 "Z20" 70.196 20.000 0.0000 20.000 18.090 21.460 35.760
+757 "T23" 70.196 40.000 0.0000 20.000 14.830 15.810 27.910
+758 "H38" 70.196 70.196 0.0000 20.000 10.900 9.2900 18.290
+759 "X22" 70.196 100.00 0.0000 20.000 8.1500 5.0700 11.840
+760 "C5" 100.00 0.0000 0.0000 20.000 12.040 18.260 40.230
+761 "X23" 100.00 10.196 0.0000 20.000 11.030 16.160 36.800
+762 "F12" 100.00 20.000 0.0000 20.000 10.110 14.230 33.300
+763 "F2" 100.00 40.000 0.0000 20.000 8.3400 10.560 26.580
+764 "J38" 100.00 70.196 0.0000 20.000 6.0600 6.1100 17.550
+765 "P17" 100.00 100.00 0.0000 20.000 4.6900 3.5400 12.120
+766 "H19" 0.0000 0.0000 10.196 20.000 56.880 59.490 46.150
+767 "E33" 0.0000 10.196 10.196 20.000 52.190 52.650 41.710
+768 "P3" 0.0000 20.000 10.196 20.000 47.710 46.180 37.310
+769 "X18" 0.0000 40.000 10.196 20.000 39.230 34.050 28.660
+770 "M25" 0.0000 70.196 10.196 20.000 29.010 19.950 17.420
+771 "R52" 0.0000 100.00 10.196 20.000 23.130 12.140 10.560
+772 "Q47" 10.196 0.0000 10.196 20.000 51.250 54.670 45.100
+773 "H26" 10.196 10.196 10.196 20.000 47.100 48.480 40.930
+774 "K26" 10.196 20.000 10.196 20.000 43.060 42.530 36.640
+775 "AA42" 10.196 40.000 10.196 20.000 35.260 31.210 28.100
+776 "B6" 10.196 70.196 10.196 20.000 26.070 18.250 17.170
+777 "X33" 10.196 100.00 10.196 20.000 20.700 11.000 10.520
+778 "Q28" 20.000 0.0000 10.196 20.000 45.440 49.660 44.000
+779 "R13" 20.000 10.196 10.196 20.000 41.760 44.000 39.930
+780 "F35" 20.000 20.000 10.196 20.000 38.190 38.630 35.730
+781 "L4" 20.000 40.000 10.196 20.000 31.230 28.300 27.390
+782 "AA8" 20.000 70.196 10.196 20.000 23.050 16.570 16.940
+783 "S32" 20.000 100.00 10.196 20.000 18.110 9.7800 10.400
+784 "N6" 40.000 0.0000 10.196 20.000 34.000 39.460 41.260
+785 "J19" 40.000 10.196 10.196 20.000 31.250 34.980 37.540
+786 "T38" 40.000 20.000 10.196 20.000 28.630 30.760 33.670
+787 "X54" 40.000 40.000 10.196 20.000 23.490 22.650 26.130
+788 "W27" 40.000 70.196 10.196 20.000 17.270 13.220 16.460
+789 "V47" 40.000 100.00 10.196 20.000 13.270 7.5000 10.250
+790 "R36" 70.196 0.0000 10.196 20.000 20.640 27.060 37.720
+791 "E43" 70.196 10.196 10.196 20.000 18.930 23.970 34.350
+792 "B46" 70.196 20.000 10.196 20.000 17.350 21.100 31.070
+793 "G22" 70.196 40.000 10.196 20.000 14.290 15.580 24.370
+794 "T52" 70.196 70.196 10.196 20.000 10.520 9.1300 15.900
+795 "V17" 70.196 100.00 10.196 20.000 8.0400 5.1100 10.360
+796 "V55" 100.00 0.0000 10.196 20.000 11.150 17.780 34.660
+797 "I31" 100.00 10.196 10.196 20.000 10.300 15.850 31.840
+798 "Y27" 100.00 20.000 10.196 20.000 9.3900 13.900 28.800
+799 "C10" 100.00 40.000 10.196 20.000 7.7200 10.240 22.890
+800 "D17" 100.00 70.196 10.196 20.000 5.7400 6.0400 15.400
+801 "S2" 100.00 100.00 10.196 20.000 4.5000 3.5400 10.610
+802 "E10" 0.0000 0.0000 20.000 20.000 55.510 58.460 39.620
+803 "Z41" 0.0000 10.196 20.000 20.000 50.960 51.730 35.790
+804 "M33" 0.0000 20.000 20.000 20.000 46.740 45.520 32.240
+805 "H7" 0.0000 40.000 20.000 20.000 38.550 33.640 24.800
+806 "Z49" 0.0000 70.196 20.000 20.000 28.750 19.910 15.170
+807 "Y34" 0.0000 100.00 20.000 20.000 22.950 12.130 9.1700
+808 "F50" 10.196 0.0000 20.000 20.000 49.930 53.690 38.630
+809 "T50" 10.196 10.196 20.000 20.000 45.960 47.660 35.140
+810 "B15" 10.196 20.000 20.000 20.000 42.160 41.940 31.690
+811 "T15" 10.196 40.000 20.000 20.000 34.670 30.910 24.370
+812 "M14" 10.196 70.196 20.000 20.000 25.720 18.140 14.980
+813 "G28" 10.196 100.00 20.000 20.000 20.500 10.980 9.1400
+814 "F54" 20.000 0.0000 20.000 20.000 44.240 48.780 37.640
+815 "J57" 20.000 10.196 20.000 20.000 40.710 43.270 34.210
+816 "L45" 20.000 20.000 20.000 20.000 37.360 38.130 30.870
+817 "V19" 20.000 40.000 20.000 20.000 30.580 27.960 23.650
+818 "Y31" 20.000 70.196 20.000 20.000 22.700 16.440 14.690
+819 "D15" 20.000 100.00 20.000 20.000 17.930 9.7800 9.0200
+820 "I8" 40.000 0.0000 20.000 20.000 32.900 38.690 35.070
+821 "A30" 40.000 10.196 20.000 20.000 30.310 34.340 31.940
+822 "M46" 40.000 20.000 20.000 20.000 27.800 30.230 28.830
+823 "L14" 40.000 40.000 20.000 20.000 22.920 22.350 22.560
+824 "U16" 40.000 70.196 20.000 20.000 16.870 13.030 14.140
+825 "J9" 40.000 100.00 20.000 20.000 13.160 7.5500 8.8800
+826 "G40" 70.196 0.0000 20.000 20.000 19.890 26.630 32.070
+827 "B26" 70.196 10.196 20.000 20.000 18.280 23.600 29.330
+828 "Z34" 70.196 20.000 20.000 20.000 16.800 20.840 26.720
+829 "X2" 70.196 40.000 20.000 20.000 13.770 15.330 20.890
+830 "F52" 70.196 70.196 20.000 20.000 10.250 9.0300 13.770
+831 "C30" 70.196 100.00 20.000 20.000 7.8800 5.1400 9.0600
+832 "W6" 100.00 0.0000 20.000 20.000 10.390 17.380 29.450
+833 "I28" 100.00 10.196 20.000 20.000 9.5600 15.440 27.010
+834 "U40" 100.00 20.000 20.000 20.000 8.7700 13.580 24.530
+835 "N15" 100.00 40.000 20.000 20.000 7.2200 9.9900 19.600
+836 "T3" 100.00 70.196 20.000 20.000 5.4100 5.9200 13.300
+837 "Y4" 100.00 100.00 20.000 20.000 4.2800 3.5200 9.1000
+838 "I46" 0.0000 0.0000 40.000 20.000 52.880 56.400 27.260
+839 "D16" 0.0000 10.196 40.000 20.000 48.700 50.030 24.750
+840 "L1" 0.0000 20.000 40.000 20.000 44.640 43.970 22.250
+841 "AA38" 0.0000 40.000 40.000 20.000 37.100 32.640 17.260
+842 "U51" 0.0000 70.196 40.000 20.000 27.990 19.520 10.690
+843 "X15" 0.0000 100.00 40.000 20.000 22.690 12.240 6.6600
+844 "F44" 10.196 0.0000 40.000 20.000 47.390 51.700 26.810
+845 "L49" 10.196 10.196 40.000 20.000 43.700 45.940 24.510
+846 "G45" 10.196 20.000 40.000 20.000 40.200 40.510 22.100
+847 "D51" 10.196 40.000 40.000 20.000 33.150 29.870 16.970
+848 "B8" 10.196 70.196 40.000 20.000 25.010 17.910 10.620
+849 "Z51" 10.196 100.00 40.000 20.000 20.260 11.120 6.6900
+850 "H18" 20.000 0.0000 40.000 20.000 41.770 46.840 26.030
+851 "J52" 20.000 10.196 40.000 20.000 38.570 41.670 23.900
+852 "R48" 20.000 20.000 40.000 20.000 35.500 36.770 21.500
+853 "X47" 20.000 40.000 40.000 20.000 29.090 26.920 16.440
+854 "R22" 20.000 70.196 40.000 20.000 21.980 16.200 10.430
+855 "X3" 20.000 100.00 40.000 20.000 17.710 9.9100 6.6500
+856 "F42" 40.000 0.0000 40.000 20.000 31.120 37.440 24.580
+857 "M38" 40.000 10.196 40.000 20.000 28.550 33.110 22.510
+858 "E14" 40.000 20.000 40.000 20.000 26.350 29.270 20.340
+859 "O57" 40.000 40.000 40.000 20.000 21.530 21.410 15.830
+860 "K43" 40.000 70.196 40.000 20.000 16.100 12.750 10.160
+861 "Z29" 40.000 100.00 40.000 20.000 12.980 7.6800 6.5500
+862 "U12" 70.196 0.0000 40.000 20.000 18.220 25.500 22.460
+863 "X8" 70.196 10.196 40.000 20.000 16.710 22.500 20.530
+864 "C54" 70.196 20.000 40.000 20.000 15.280 19.750 18.590
+865 "A45" 70.196 40.000 40.000 20.000 12.400 14.380 14.520
+866 "D33" 70.196 70.196 40.000 20.000 9.6100 8.8200 9.8600
+867 "T11" 70.196 100.00 40.000 20.000 7.6300 5.2000 6.6300
+868 "R10" 100.00 0.0000 40.000 20.000 9.0700 16.580 20.850
+869 "N36" 100.00 10.196 40.000 20.000 8.3600 14.700 19.230
+870 "R23" 100.00 20.000 40.000 20.000 7.6900 12.940 17.480
+871 "E32" 100.00 40.000 40.000 20.000 6.3600 9.5600 13.950
+872 "K11" 100.00 70.196 40.000 20.000 4.8700 5.7800 9.4800
+873 "D9" 100.00 100.00 40.000 20.000 3.9100 3.4700 6.5600
+874 "P33" 0.0000 0.0000 70.196 20.000 49.570 53.360 12.660
+875 "AA2" 0.0000 10.196 70.196 20.000 45.630 47.300 11.410
+876 "A41" 0.0000 20.000 70.196 20.000 41.930 41.640 10.340
+877 "T29" 0.0000 40.000 70.196 20.000 34.960 30.980 8.0400
+878 "I26" 0.0000 70.196 70.196 20.000 26.980 19.010 5.3600
+879 "H54" 0.0000 100.00 70.196 20.000 22.180 12.160 3.5200
+880 "O49" 10.196 0.0000 70.196 20.000 44.230 48.860 12.400
+881 "B16" 10.196 10.196 70.196 20.000 40.810 43.440 11.330
+882 "E38" 10.196 20.000 70.196 20.000 37.540 38.270 10.270
+883 "I50" 10.196 40.000 70.196 20.000 31.320 28.550 8.0400
+884 "P10" 10.196 70.196 70.196 20.000 24.050 17.420 5.3200
+885 "I43" 10.196 100.00 70.196 20.000 19.800 11.070 3.5500
+886 "W57" 20.000 0.0000 70.196 20.000 38.780 44.170 12.050
+887 "W50" 20.000 10.196 70.196 20.000 35.800 39.280 11.080
+888 "AA57" 20.000 20.000 70.196 20.000 32.940 34.620 9.9900
+889 "N35" 20.000 40.000 70.196 20.000 27.400 25.720 7.8500
+890 "H15" 20.000 70.196 70.196 20.000 21.110 15.740 5.1900
+891 "F28" 20.000 100.00 70.196 20.000 17.340 9.9100 3.5300
+892 "W22" 40.000 0.0000 70.196 20.000 28.430 35.030 11.550
+893 "O29" 40.000 10.196 70.196 20.000 26.060 31.010 10.480
+894 "D55" 40.000 20.000 70.196 20.000 24.080 27.430 9.6200
+895 "F31" 40.000 40.000 70.196 20.000 20.060 20.410 7.5400
+896 "Y50" 40.000 70.196 70.196 20.000 15.440 12.420 5.1000
+897 "N20" 40.000 100.00 70.196 20.000 12.700 7.6900 3.5200
+898 "X19" 70.196 0.0000 70.196 20.000 16.050 23.620 10.700
+899 "Q48" 70.196 10.196 70.196 20.000 14.770 20.950 9.8000
+900 "M6" 70.196 20.000 70.196 20.000 13.560 18.450 9.0300
+901 "B27" 70.196 40.000 70.196 20.000 11.410 13.790 7.2800
+902 "H51" 70.196 70.196 70.196 20.000 8.8300 8.4300 4.9700
+903 "Y32" 70.196 100.00 70.196 20.000 7.2300 5.1400 3.6000
+904 "V20" 100.00 0.0000 70.196 20.000 7.3300 15.200 10.370
+905 "AA11" 100.00 10.196 70.196 20.000 6.7500 13.480 9.4800
+906 "J16" 100.00 20.000 70.196 20.000 6.2500 11.920 8.6400
+907 "P36" 100.00 40.000 70.196 20.000 5.2300 8.8200 6.9600
+908 "E6" 100.00 70.196 70.196 20.000 4.1700 5.4400 4.9700
+909 "S49" 100.00 100.00 70.196 20.000 3.4700 3.4000 3.6200
+910 "O27" 0.0000 0.0000 100.00 20.000 47.580 51.210 4.9300
+911 "V14" 0.0000 10.196 100.00 20.000 43.710 45.260 4.4100
+912 "X41" 0.0000 20.000 100.00 20.000 40.190 39.890 4.0700
+913 "M9" 0.0000 40.000 100.00 20.000 33.690 29.870 3.3200
+914 "D41" 0.0000 70.196 100.00 20.000 26.080 18.400 2.3900
+915 "Q17" 0.0000 100.00 100.00 20.000 21.830 12.070 1.8800
+916 "X35" 10.196 0.0000 100.00 20.000 42.290 46.780 4.8300
+917 "K40" 10.196 10.196 100.00 20.000 39.070 41.650 4.3700
+918 "W54" 10.196 20.000 100.00 20.000 36.010 36.770 4.0400
+919 "R12" 10.196 40.000 100.00 20.000 30.270 27.640 3.2800
+920 "Y22" 10.196 70.196 100.00 20.000 23.500 17.090 2.4000
+921 "AA17" 10.196 100.00 100.00 20.000 19.450 10.960 1.9100
+922 "I22" 20.000 0.0000 100.00 20.000 37.000 42.250 4.6800
+923 "L3" 20.000 10.196 100.00 20.000 34.220 37.660 4.2800
+924 "O54" 20.000 20.000 100.00 20.000 31.710 33.400 3.9500
+925 "K10" 20.000 40.000 100.00 20.000 26.660 25.130 3.2300
+926 "F11" 20.000 70.196 100.00 20.000 20.670 15.470 2.3800
+927 "S30" 20.000 100.00 100.00 20.000 17.060 9.8400 1.9200
+928 "B32" 40.000 0.0000 100.00 20.000 26.840 33.370 4.5700
+929 "P19" 40.000 10.196 100.00 20.000 25.020 29.910 4.1600
+930 "B28" 40.000 20.000 100.00 20.000 23.240 26.630 3.8600
+931 "D14" 40.000 40.000 100.00 20.000 19.630 20.050 3.1900
+932 "P55" 40.000 70.196 100.00 20.000 15.250 12.380 2.4100
+933 "Q25" 40.000 100.00 100.00 20.000 12.380 7.6200 1.9400
+934 "V29" 70.196 0.0000 100.00 20.000 15.020 22.560 4.4700
+935 "X36" 70.196 10.196 100.00 20.000 14.080 20.300 4.1600
+936 "C47" 70.196 20.000 100.00 20.000 12.930 17.920 3.8800
+937 "P40" 70.196 40.000 100.00 20.000 11.220 13.740 3.2600
+938 "K53" 70.196 70.196 100.00 20.000 8.6700 8.4500 2.4900
+939 "X20" 70.196 100.00 100.00 20.000 6.9400 5.0900 2.0100
+940 "H10" 100.00 0.0000 100.00 20.000 6.2800 14.140 4.6600
+941 "G33" 100.00 10.196 100.00 20.000 5.8900 12.680 4.4000
+942 "Y23" 100.00 20.000 100.00 20.000 5.4800 11.230 4.1000
+943 "X45" 100.00 40.000 100.00 20.000 4.6900 8.4700 3.5000
+944 "P24" 100.00 70.196 100.00 20.000 3.8000 5.3200 2.6800
+945 "O4" 100.00 100.00 100.00 20.000 3.2300 3.3700 2.0200
+946 "I18" 0.0000 0.0000 0.0000 40.000 35.870 37.330 32.950
+947 "Y26" 0.0000 20.000 0.0000 40.000 30.230 29.160 26.800
+948 "V25" 0.0000 40.000 0.0000 40.000 25.150 21.930 20.960
+949 "AA36" 0.0000 70.196 0.0000 40.000 18.700 13.060 12.860
+950 "U27" 0.0000 100.00 0.0000 40.000 14.740 7.8300 7.6100
+951 "D35" 20.000 0.0000 0.0000 40.000 28.670 31.130 31.220
+952 "V45" 20.000 20.000 0.0000 40.000 24.270 24.370 25.550
+953 "W35" 20.000 40.000 0.0000 40.000 20.090 18.170 19.960
+954 "O53" 20.000 70.196 0.0000 40.000 14.900 10.780 12.360
+955 "AA49" 20.000 100.00 0.0000 40.000 11.690 6.3800 7.4900
+956 "P42" 40.000 0.0000 0.0000 40.000 21.620 24.850 29.390
+957 "M1" 40.000 20.000 0.0000 40.000 18.280 19.370 23.990
+958 "K21" 40.000 40.000 0.0000 40.000 15.230 14.510 18.930
+959 "K7" 40.000 70.196 0.0000 40.000 11.320 8.6100 11.900
+960 "T24" 40.000 100.00 0.0000 40.000 8.9100 5.1000 7.5200
+961 "C16" 70.196 0.0000 0.0000 40.000 13.500 17.280 26.810
+962 "E56" 70.196 20.000 0.0000 40.000 11.420 13.450 22.040
+963 "D32" 70.196 40.000 0.0000 40.000 9.5400 10.080 17.500
+964 "L21" 70.196 70.196 0.0000 40.000 7.2400 6.1400 11.590
+965 "AA7" 70.196 100.00 0.0000 40.000 5.6800 3.6200 7.5800
+966 "M22" 100.00 0.0000 0.0000 40.000 7.6800 11.640 24.760
+967 "I2" 100.00 20.000 0.0000 40.000 6.5800 9.1700 20.590
+968 "N9" 100.00 40.000 0.0000 40.000 5.6100 7.0000 16.710
+969 "V24" 100.00 70.196 0.0000 40.000 4.3200 4.3200 11.260
+970 "Z9" 100.00 100.00 0.0000 40.000 3.4900 2.6700 7.8400
+971 "I32" 0.0000 0.0000 20.000 40.000 34.040 35.930 24.620
+972 "V40" 0.0000 20.000 20.000 40.000 28.830 28.170 20.180
+973 "V27" 0.0000 40.000 20.000 40.000 24.160 21.290 15.890
+974 "C43" 0.0000 70.196 20.000 40.000 18.230 12.870 9.8700
+975 "G21" 0.0000 100.00 20.000 40.000 14.540 7.8700 5.9600
+976 "K36" 20.000 0.0000 20.000 40.000 27.120 30.010 23.330
+977 "V23" 20.000 20.000 20.000 40.000 23.040 23.560 19.260
+978 "Z5" 20.000 40.000 20.000 40.000 19.150 17.630 15.090
+979 "Z44" 20.000 70.196 20.000 40.000 14.420 10.600 9.4800
+980 "Q27" 20.000 100.00 20.000 40.000 11.510 6.4500 5.8500
+981 "E4" 40.000 0.0000 20.000 40.000 20.240 23.890 21.670
+982 "H5" 40.000 20.000 20.000 40.000 17.200 18.700 17.940
+983 "R8" 40.000 40.000 20.000 40.000 14.380 14.040 14.320
+984 "G5" 40.000 70.196 20.000 40.000 10.790 8.4100 9.0500
+985 "R2" 40.000 100.00 20.000 40.000 8.6400 5.1000 5.7400
+986 "C49" 70.196 0.0000 20.000 40.000 12.450 16.670 19.850
+987 "W4" 70.196 20.000 20.000 40.000 10.620 13.080 16.640
+988 "U37" 70.196 40.000 20.000 40.000 8.8900 9.8000 13.270
+989 "S45" 70.196 70.196 20.000 40.000 6.8300 6.0200 8.8200
+990 "C27" 70.196 100.00 20.000 40.000 5.4700 3.6600 5.8600
+991 "L5" 100.00 0.0000 20.000 40.000 6.7400 11.210 18.420
+992 "P1" 100.00 20.000 20.000 40.000 5.8200 8.8600 15.430
+993 "O13" 100.00 40.000 20.000 40.000 4.9700 6.7300 12.540
+994 "W28" 100.00 70.196 20.000 40.000 3.9300 4.2600 8.6600
+995 "V28" 100.00 100.00 20.000 40.000 3.2600 2.7100 5.9900
+996 "M41" 0.0000 0.0000 40.000 40.000 32.280 34.540 16.750
+997 "P7" 0.0000 20.000 40.000 40.000 27.410 27.100 13.780
+998 "W3" 0.0000 40.000 40.000 40.000 23.150 20.570 10.940
+999 "W8" 0.0000 70.196 40.000 40.000 17.680 12.600 6.9200
+1000 "AA47" 0.0000 100.00 40.000 40.000 14.440 8.0200 4.3800
+1001 "M21" 20.000 0.0000 40.000 40.000 25.450 28.700 15.960
+1002 "S1" 20.000 20.000 40.000 40.000 21.770 22.640 13.300
+1003 "O2" 20.000 40.000 40.000 40.000 18.130 16.910 10.410
+1004 "Q11" 20.000 70.196 40.000 40.000 13.910 10.440 6.7100
+1005 "G46" 20.000 100.00 40.000 40.000 11.360 6.5700 4.3400
+1006 "N11" 40.000 0.0000 40.000 40.000 19.000 23.010 15.060
+1007 "K17" 40.000 20.000 40.000 40.000 16.200 18.030 12.580
+1008 "C14" 40.000 40.000 40.000 40.000 13.450 13.420 10.020
+1009 "F14" 40.000 70.196 40.000 40.000 10.260 8.2300 6.4900
+1010 "Z57" 40.000 100.00 40.000 40.000 8.4500 5.1800 4.2300
+1011 "R56" 70.196 0.0000 40.000 40.000 11.350 15.930 13.860
+1012 "M4" 70.196 20.000 40.000 40.000 9.6500 12.410 11.580
+1013 "W26" 70.196 40.000 40.000 40.000 8.0300 9.2500 9.2600
+1014 "B20" 70.196 70.196 40.000 40.000 6.4100 5.9200 6.3300
+1015 "E53" 70.196 100.00 40.000 40.000 5.2600 3.7100 4.2900
+1016 "G37" 100.00 0.0000 40.000 40.000 5.9700 10.810 13.150
+1017 "V22" 100.00 20.000 40.000 40.000 5.1800 8.5500 11.090
+1018 "I44" 100.00 40.000 40.000 40.000 4.4400 6.5300 9.0000
+1019 "L11" 100.00 70.196 40.000 40.000 3.6000 4.2200 6.2100
+1020 "T28" 100.00 100.00 40.000 40.000 3.0500 2.7500 4.3500
+1021 "Y17" 0.0000 0.0000 70.196 40.000 30.110 32.530 7.8400
+1022 "X43" 0.0000 20.000 70.196 40.000 25.640 25.540 6.4900
+1023 "G1" 0.0000 40.000 70.196 40.000 21.710 19.410 5.2000
+1024 "H34" 0.0000 70.196 70.196 40.000 17.020 12.270 3.6000
+1025 "S12" 0.0000 100.00 70.196 40.000 14.160 8.0600 2.4500
+1026 "Y37" 20.000 0.0000 70.196 40.000 23.490 26.940 7.4500
+1027 "W5" 20.000 20.000 70.196 40.000 20.010 21.120 6.2700
+1028 "P11" 20.000 40.000 70.196 40.000 16.810 15.890 5.0900
+1029 "B43" 20.000 70.196 70.196 40.000 13.190 10.030 3.4900
+1030 "K31" 20.000 100.00 70.196 40.000 11.110 6.6100 2.4300
+1031 "R20" 40.000 0.0000 70.196 40.000 17.210 21.410 7.1200
+1032 "F24" 40.000 20.000 70.196 40.000 14.550 16.640 6.0500
+1033 "Q9" 40.000 40.000 70.196 40.000 12.140 12.370 4.9300
+1034 "B11" 40.000 70.196 70.196 40.000 9.5800 7.8100 3.4200
+1035 "N3" 40.000 100.00 70.196 40.000 8.2200 5.2100 2.4000
+1036 "C21" 70.196 0.0000 70.196 40.000 9.9300 14.690 6.6700
+1037 "N18" 70.196 20.000 70.196 40.000 8.4300 11.430 5.7400
+1038 "Y7" 70.196 40.000 70.196 40.000 7.1600 8.5900 4.7900
+1039 "AA25" 70.196 70.196 70.196 40.000 5.7600 5.5200 3.3600
+1040 "J24" 70.196 100.00 70.196 40.000 4.9800 3.6900 2.4600
+1041 "L8" 100.00 0.0000 70.196 40.000 4.9200 10.010 6.6400
+1042 "J45" 100.00 20.000 70.196 40.000 4.2900 7.9400 5.6100
+1043 "AA12" 100.00 40.000 70.196 40.000 3.7200 6.0500 4.6300
+1044 "N21" 100.00 70.196 70.196 40.000 3.1500 3.9800 3.4100
+1045 "M17" 100.00 100.00 70.196 40.000 2.7800 2.7200 2.5600
+1046 "R44" 0.0000 0.0000 100.00 40.000 28.850 31.210 3.3700
+1047 "F45" 0.0000 20.000 100.00 40.000 24.550 24.460 2.8400
+1048 "S54" 0.0000 40.000 100.00 40.000 20.890 18.660 2.4100
+1049 "R26" 0.0000 70.196 100.00 40.000 16.460 11.890 1.8600
+1050 "K57" 0.0000 100.00 100.00 40.000 13.900 8.0200 1.5400
+1051 "L54" 20.000 0.0000 100.00 40.000 22.420 25.850 3.2100
+1052 "M30" 20.000 20.000 100.00 40.000 19.130 20.270 2.7800
+1053 "H49" 20.000 40.000 100.00 40.000 16.050 15.200 2.3700
+1054 "V57" 20.000 70.196 100.00 40.000 12.710 9.6900 1.8500
+1055 "J35" 20.000 100.00 100.00 40.000 10.910 6.5800 1.5400
+1056 "O14" 40.000 0.0000 100.00 40.000 16.250 20.490 3.1400
+1057 "S41" 40.000 20.000 100.00 40.000 13.770 15.900 2.7300
+1058 "U50" 40.000 40.000 100.00 40.000 11.340 11.590 2.3700
+1059 "J36" 40.000 70.196 100.00 40.000 9.1100 7.4700 1.8700
+1060 "M45" 40.000 100.00 100.00 40.000 8.0200 5.1700 1.5300
+1061 "K3" 70.196 0.0000 100.00 40.000 9.2500 13.990 3.1100
+1062 "D28" 70.196 20.000 100.00 40.000 7.8100 10.790 2.7700
+1063 "F38" 70.196 40.000 100.00 40.000 6.6300 8.0500 2.4100
+1064 "Y25" 70.196 70.196 100.00 40.000 5.4400 5.2900 1.9100
+1065 "H4" 70.196 100.00 100.00 40.000 4.8200 3.6700 1.5700
+1066 "C57" 100.00 0.0000 100.00 40.000 4.2300 9.1900 3.3200
+1067 "AA35" 100.00 20.000 100.00 40.000 3.7700 7.3600 2.9300
+1068 "X21" 100.00 40.000 100.00 40.000 3.3300 5.7000 2.5400
+1069 "S15" 100.00 70.196 100.00 40.000 2.8800 3.8500 2.0300
+1070 "P28" 100.00 100.00 100.00 40.000 2.6300 2.7000 1.6000
+1071 "P13" 0.0000 0.0000 0.0000 60.000 18.920 19.770 17.150
+1072 "A32" 0.0000 20.000 0.0000 60.000 16.340 15.770 14.120
+1073 "V42" 0.0000 40.000 0.0000 60.000 14.000 12.220 11.280
+1074 "P21" 0.0000 70.196 0.0000 60.000 10.700 7.6400 7.1400
+1075 "Y47" 0.0000 100.00 0.0000 60.000 8.5700 4.8000 4.3800
+1076 "U6" 20.000 0.0000 0.0000 60.000 15.460 16.840 16.420
+1077 "J33" 20.000 20.000 0.0000 60.000 13.250 13.290 13.530
+1078 "Q39" 20.000 40.000 0.0000 60.000 11.130 10.030 10.730
+1079 "T49" 20.000 70.196 0.0000 60.000 8.5400 6.2900 6.8500
+1080 "F27" 20.000 100.00 0.0000 60.000 7.0000 4.0600 4.3400
+1081 "B13" 40.000 0.0000 0.0000 60.000 11.910 13.740 15.620
+1082 "A40" 40.000 20.000 0.0000 60.000 10.010 10.570 12.760
+1083 "Q55" 40.000 40.000 0.0000 60.000 8.2800 7.8100 10.130
+1084 "N52" 40.000 70.196 0.0000 60.000 6.4600 4.9900 6.5800
+1085 "G35" 40.000 100.00 0.0000 60.000 5.5100 3.3800 4.3900
+1086 "K28" 70.196 0.0000 0.0000 60.000 7.7000 9.8600 14.380
+1087 "D27" 70.196 20.000 0.0000 60.000 6.4400 7.5200 11.770
+1088 "W7" 70.196 40.000 0.0000 60.000 5.3600 5.5600 9.3700
+1089 "X11" 70.196 70.196 0.0000 60.000 4.3900 3.7500 6.4300
+1090 "U56" 70.196 100.00 0.0000 60.000 3.8400 2.6400 4.4700
+1091 "M19" 100.00 0.0000 0.0000 60.000 4.5500 6.8200 13.210
+1092 "U53" 100.00 20.000 0.0000 60.000 3.9900 5.4500 11.020
+1093 "L24" 100.00 40.000 0.0000 60.000 3.5100 4.2900 9.0400
+1094 "V33" 100.00 70.196 0.0000 60.000 3.0100 3.0000 6.3500
+1095 "T1" 100.00 100.00 0.0000 60.000 2.7600 2.2300 4.6700
+1096 "Z52" 0.0000 0.0000 20.000 60.000 17.650 18.660 13.040
+1097 "A57" 0.0000 20.000 20.000 60.000 15.210 14.850 10.820
+1098 "B33" 0.0000 40.000 20.000 60.000 13.040 11.490 8.7000
+1099 "V4" 0.0000 70.196 20.000 60.000 10.150 7.3400 5.6000
+1100 "W34" 0.0000 100.00 20.000 60.000 8.3400 4.8000 3.5600
+1101 "X51" 20.000 0.0000 20.000 60.000 14.260 15.790 12.420
+1102 "AA20" 20.000 20.000 20.000 60.000 12.250 12.490 10.350
+1103 "B23" 20.000 40.000 20.000 60.000 10.350 9.4800 8.2400
+1104 "N46" 20.000 70.196 20.000 60.000 8.1000 6.0800 5.3800
+1105 "J10" 20.000 100.00 20.000 60.000 6.8100 4.0700 3.5100
+1106 "C18" 40.000 0.0000 20.000 60.000 10.760 12.700 11.610
+1107 "X26" 40.000 20.000 20.000 60.000 9.1600 9.9100 9.6500
+1108 "D1" 40.000 40.000 20.000 60.000 7.7100 7.4500 7.8000
+1109 "N29" 40.000 70.196 20.000 60.000 6.1100 4.8400 5.1200
+1110 "AA16" 40.000 100.00 20.000 60.000 5.2900 3.3500 3.4600
+1111 "M24" 70.196 0.0000 20.000 60.000 6.8300 9.0700 10.680
+1112 "V53" 70.196 20.000 20.000 60.000 5.8600 7.0900 8.9800
+1113 "O8" 70.196 40.000 20.000 60.000 4.9700 5.3400 7.2400
+1114 "J6" 70.196 70.196 20.000 60.000 4.1400 3.6600 5.0200
+1115 "N26" 70.196 100.00 20.000 60.000 3.6600 2.6300 3.5500
+1116 "K22" 100.00 0.0000 20.000 60.000 3.9700 6.3600 9.9000
+1117 "Z28" 100.00 20.000 20.000 60.000 3.5300 5.1400 8.3700
+1118 "V35" 100.00 40.000 20.000 60.000 3.1500 4.0600 6.9300
+1119 "E48" 100.00 70.196 20.000 60.000 2.7900 2.9300 5.0100
+1120 "E46" 100.00 100.00 20.000 60.000 2.5900 2.2200 3.6500
+1121 "O16" 0.0000 0.0000 40.000 60.000 16.280 17.460 8.9900
+1122 "D8" 0.0000 20.000 40.000 60.000 13.940 13.790 7.4700
+1123 "F32" 0.0000 40.000 40.000 60.000 11.950 10.650 6.0700
+1124 "T17" 0.0000 70.196 40.000 60.000 9.4900 6.9600 4.0200
+1125 "O52" 0.0000 100.00 40.000 60.000 8.1200 4.8400 2.7200
+1126 "B17" 20.000 0.0000 40.000 60.000 12.910 14.570 8.5600
+1127 "I27" 20.000 20.000 40.000 60.000 11.160 11.580 7.2100
+1128 "Y41" 20.000 40.000 40.000 60.000 9.4600 8.8000 5.7600
+1129 "Y19" 20.000 70.196 40.000 60.000 7.6000 5.8500 3.8800
+1130 "U38" 20.000 100.00 40.000 60.000 6.5900 4.1000 2.6900
+1131 "A53" 40.000 0.0000 40.000 60.000 9.6500 11.690 8.0600
+1132 "K33" 40.000 20.000 40.000 60.000 8.3300 9.2300 6.8000
+1133 "U44" 40.000 40.000 40.000 60.000 7.0700 6.9900 5.5300
+1134 "H35" 40.000 70.196 40.000 60.000 5.7300 4.6900 3.7500
+1135 "AA14" 40.000 100.00 40.000 60.000 5.0800 3.3600 2.6300
+1136 "S35" 70.196 0.0000 40.000 60.000 5.9400 8.2400 7.4200
+1137 "H8" 70.196 20.000 40.000 60.000 5.1800 6.5200 6.2800
+1138 "O1" 70.196 40.000 40.000 60.000 4.4900 5.0100 5.1400
+1139 "AA39" 70.196 70.196 40.000 60.000 3.8800 3.5800 3.6700
+1140 "AA54" 70.196 100.00 40.000 60.000 3.4600 2.6100 2.6500
+1141 "F30" 100.00 0.0000 40.000 60.000 3.4600 5.9400 7.0600
+1142 "S51" 100.00 20.000 40.000 60.000 3.1400 4.8400 6.0700
+1143 "T8" 100.00 40.000 40.000 60.000 2.8500 3.8800 5.0700
+1144 "L2" 100.00 70.196 40.000 60.000 2.5700 2.8600 3.6700
+1145 "L13" 100.00 100.00 40.000 60.000 2.4100 2.1900 2.7000
+1146 "Y43" 0.0000 0.0000 70.196 60.000 14.740 16.020 4.3100
+1147 "C41" 0.0000 20.000 70.196 60.000 12.580 12.610 3.6000
+1148 "O7" 0.0000 40.000 70.196 60.000 10.780 9.7300 2.9400
+1149 "K24" 0.0000 70.196 70.196 60.000 8.8400 6.6200 2.1600
+1150 "A51" 0.0000 100.00 70.196 60.000 7.7800 4.8100 1.6200
+1151 "P54" 20.000 0.0000 70.196 60.000 11.480 13.230 4.0400
+1152 "J15" 20.000 20.000 70.196 60.000 9.9000 10.490 3.4500
+1153 "A20" 20.000 40.000 70.196 60.000 8.5200 8.1000 2.8800
+1154 "K54" 20.000 70.196 70.196 60.000 7.0800 5.5800 2.1200
+1155 "E22" 20.000 100.00 70.196 60.000 6.3200 4.0900 1.6000
+1156 "Z37" 40.000 0.0000 70.196 60.000 8.3300 10.440 3.7900
+1157 "T21" 40.000 20.000 70.196 60.000 7.2400 8.3100 3.3000
+1158 "A28" 40.000 40.000 70.196 60.000 6.3100 6.4500 2.8100
+1159 "L27" 40.000 70.196 70.196 60.000 5.3400 4.5000 2.0900
+1160 "W29" 40.000 100.00 70.196 60.000 4.8800 3.3700 1.5800
+1161 "L30" 70.196 0.0000 70.196 60.000 4.9400 7.2800 3.5100
+1162 "J18" 70.196 20.000 70.196 60.000 4.4400 5.9200 3.1400
+1163 "F9" 70.196 40.000 70.196 60.000 4.0200 4.7200 2.7600
+1164 "P45" 70.196 70.196 70.196 60.000 3.5400 3.4200 2.0700
+1165 "D40" 70.196 100.00 70.196 60.000 3.2700 2.6000 1.6200
+1166 "J1" 100.00 0.0000 70.196 60.000 2.8100 5.3600 3.5000
+1167 "W12" 100.00 20.000 70.196 60.000 2.6300 4.4700 3.1000
+1168 "Q30" 100.00 40.000 70.196 60.000 2.4600 3.6400 2.7100
+1169 "X53" 100.00 70.196 70.196 60.000 2.3200 2.7500 2.1300
+1170 "F19" 100.00 100.00 70.196 60.000 2.2400 2.1800 1.7000
+1171 "R45" 0.0000 0.0000 100.00 60.000 14.580 15.940 2.3100
+1172 "I51" 0.0000 20.000 100.00 60.000 12.630 12.710 1.9300
+1173 "N7" 0.0000 40.000 100.00 60.000 10.990 9.9500 1.6300
+1174 "W48" 0.0000 70.196 100.00 60.000 8.9400 6.7100 1.3300
+1175 "P14" 0.0000 100.00 100.00 60.000 7.7500 4.7900 1.1900
+1176 "K8" 20.000 0.0000 100.00 60.000 11.610 13.460 2.1900
+1177 "H53" 20.000 20.000 100.00 60.000 10.060 10.730 1.9000
+1178 "T10" 20.000 40.000 100.00 60.000 8.6300 8.2800 1.6400
+1179 "T42" 20.000 70.196 100.00 60.000 7.1200 5.6500 1.3600
+1180 "F43" 20.000 100.00 100.00 60.000 6.3400 4.1200 1.2000
+1181 "X10" 40.000 0.0000 100.00 60.000 8.6200 10.880 2.1300
+1182 "U11" 40.000 20.000 100.00 60.000 7.4100 8.5900 1.8900
+1183 "N41" 40.000 40.000 100.00 60.000 6.2300 6.4500 1.6800
+1184 "O36" 40.000 70.196 100.00 60.000 5.3000 4.5300 1.4100
+1185 "Z6" 40.000 100.00 100.00 60.000 4.9100 3.4400 1.2200
+1186 "C26" 70.196 0.0000 100.00 60.000 5.1600 7.7100 2.1000
+1187 "W45" 70.196 20.000 100.00 60.000 4.4600 6.0900 1.9200
+1188 "Z8" 70.196 40.000 100.00 60.000 3.9000 4.7000 1.7400
+1189 "W23" 70.196 70.196 100.00 60.000 3.4800 3.4600 1.4500
+1190 "Q22" 70.196 100.00 100.00 60.000 3.3000 2.7100 1.2600
+1191 "C24" 100.00 0.0000 100.00 60.000 2.6900 5.4400 2.2300
+1192 "Z53" 100.00 20.000 100.00 60.000 2.5100 4.5200 2.0100
+1193 "H22" 100.00 40.000 100.00 60.000 2.3600 3.6900 1.7900
+1194 "W39" 100.00 70.196 100.00 60.000 2.2400 2.8000 1.5100
+1195 "O19" 100.00 100.00 100.00 60.000 2.2100 2.2400 1.2900
+1196 "L38" 0.0000 0.0000 0.0000 80.000 7.9300 8.2700 6.9600
+1197 "M44" 0.0000 40.000 0.0000 80.000 6.2500 5.4900 4.7900
+1198 "E13" 0.0000 70.196 0.0000 80.000 5.2700 3.9500 3.3700
+1199 "V7" 0.0000 100.00 0.0000 80.000 4.4200 2.7100 2.1800
+1200 "Y36" 40.000 0.0000 0.0000 80.000 5.3400 6.1300 6.6800
+1201 "X28" 40.000 40.000 0.0000 80.000 4.2900 4.1000 4.6400
+1202 "J21" 40.000 70.196 0.0000 80.000 3.7200 3.0200 3.3100
+1203 "F55" 40.000 100.00 0.0000 80.000 3.3100 2.2400 2.3200
+1204 "L42" 70.196 0.0000 0.0000 80.000 3.7700 4.7400 6.4100
+1205 "C15" 70.196 40.000 0.0000 80.000 3.1200 3.2300 4.4800
+1206 "B7" 70.196 70.196 0.0000 80.000 2.8100 2.4700 3.3100
+1207 "W43" 70.196 100.00 0.0000 80.000 2.5900 1.9300 2.4000
+1208 "N54" 100.00 0.0000 0.0000 80.000 2.4000 3.4600 6.0000
+1209 "D38" 100.00 40.000 0.0000 80.000 2.2300 2.5700 4.3900
+1210 "B1" 100.00 70.196 0.0000 80.000 2.1300 2.0600 3.2900
+1211 "R21" 100.00 100.00 0.0000 80.000 2.0000 1.6500 2.4400
+1212 "Z15" 0.0000 0.0000 40.000 80.000 7.3700 7.9100 4.1700
+1213 "I12" 0.0000 40.000 40.000 80.000 5.8100 5.2700 2.9500
+1214 "Z25" 0.0000 70.196 40.000 80.000 5.0300 3.9300 2.1900
+1215 "Z27" 0.0000 100.00 40.000 80.000 4.5400 3.0400 1.6100
+1216 "E11" 40.000 0.0000 40.000 80.000 4.7700 5.7300 3.9000
+1217 "G14" 40.000 40.000 40.000 80.000 3.9100 3.9200 2.8200
+1218 "G54" 40.000 70.196 40.000 80.000 3.4900 3.0100 2.1300
+1219 "F51" 40.000 100.00 40.000 80.000 3.2900 2.4500 1.6500
+1220 "Z4" 70.196 0.0000 40.000 80.000 3.2800 4.4100 3.7300
+1221 "AA5" 70.196 40.000 40.000 80.000 2.8200 3.1100 2.7300
+1222 "W38" 70.196 70.196 40.000 80.000 2.6600 2.5200 2.1400
+1223 "O56" 70.196 100.00 40.000 80.000 2.5900 2.1300 1.7100
+1224 "P39" 100.00 0.0000 40.000 80.000 2.1600 3.4200 3.6700
+1225 "J49" 100.00 40.000 40.000 80.000 2.0800 2.6000 2.8000
+1226 "V31" 100.00 70.196 40.000 80.000 2.0700 2.1800 2.2100
+1227 "F47" 100.00 100.00 40.000 80.000 2.0700 1.9000 1.7500
+1228 "D42" 0.0000 0.0000 70.196 80.000 7.0600 7.6700 2.5600
+1229 "R19" 0.0000 40.000 70.196 80.000 5.5800 5.1500 1.8900
+1230 "J32" 0.0000 70.196 70.196 80.000 4.9200 3.9400 1.5400
+1231 "I42" 0.0000 100.00 70.196 80.000 4.5200 3.1700 1.2700
+1232 "A11" 40.000 0.0000 70.196 80.000 4.4800 5.5000 2.4100
+1233 "M57" 40.000 40.000 70.196 80.000 3.7400 3.8500 1.8300
+1234 "D34" 40.000 70.196 70.196 80.000 3.4000 3.0300 1.5000
+1235 "J56" 40.000 100.00 70.196 80.000 3.2800 2.5500 1.2900
+1236 "R18" 70.196 0.0000 70.196 80.000 3.0400 4.2200 2.3300
+1237 "B14" 70.196 40.000 70.196 80.000 2.7000 3.0800 1.8300
+1238 "L7" 70.196 70.196 70.196 80.000 2.5600 2.5100 1.5000
+1239 "P56" 70.196 100.00 70.196 80.000 2.5600 2.2100 1.3100
+1240 "Y42" 100.00 0.0000 70.196 80.000 2.0000 3.3300 2.3600
+1241 "G30" 100.00 40.000 70.196 80.000 1.9700 2.5800 1.8800
+1242 "N23" 100.00 70.196 70.196 80.000 1.9900 2.1900 1.5500
+1243 "R30" 100.00 100.00 70.196 80.000 2.0100 1.9400 1.3000
+1244 "N39" 0.0000 0.0000 100.00 80.000 7.0200 7.6900 1.6400
+1245 "W40" 0.0000 40.000 100.00 80.000 5.6300 5.2600 1.3400
+1246 "L15" 0.0000 70.196 100.00 80.000 4.9500 4.0400 1.1900
+1247 "D47" 0.0000 100.00 100.00 80.000 4.4900 3.2300 1.1000
+1248 "O9" 40.000 0.0000 100.00 80.000 4.5100 5.6100 1.6000
+1249 "K2" 40.000 40.000 100.00 80.000 3.7700 3.9500 1.3300
+1250 "W25" 40.000 70.196 100.00 80.000 3.4400 3.1300 1.1900
+1251 "D39" 40.000 100.00 100.00 80.000 3.2800 2.6300 1.1300
+1252 "Q24" 70.196 0.0000 100.00 80.000 3.0600 4.3200 1.5900
+1253 "J3" 70.196 40.000 100.00 80.000 2.7200 3.1700 1.3400
+1254 "Q14" 70.196 70.196 100.00 80.000 2.5800 2.6000 1.2000
+1255 "R34" 70.196 100.00 100.00 80.000 2.5500 2.2800 1.1300
+1256 "G50" 100.00 0.0000 100.00 80.000 1.9100 3.3100 1.6000
+1257 "T43" 100.00 40.000 100.00 80.000 1.9300 2.6100 1.3900
+1258 "M50" 100.00 70.196 100.00 80.000 1.9600 2.2400 1.2300
+1259 "T18" 100.00 100.00 100.00 80.000 1.9600 1.9800 1.0600
+1260 "Q13" 0.0000 0.0000 0.0000 100.00 2.6900 2.8000 2.1600
+1261 "N33" 0.0000 40.000 0.0000 100.00 2.4700 2.3000 1.6700
+1262 "B50" 0.0000 100.00 0.0000 100.00 2.3200 1.6600 1.0100
+1263 "N43" 40.000 0.0000 0.0000 100.00 1.9700 2.2000 2.1200
+1264 "C11" 40.000 40.000 0.0000 100.00 1.9300 1.8900 1.6800
+1265 "Z35" 40.000 100.00 0.0000 100.00 1.9800 1.4700 1.0700
+1266 "K5" 100.00 0.0000 0.0000 100.00 1.2300 1.6300 2.2800
+1267 "AA52" 100.00 40.000 0.0000 100.00 1.3300 1.4900 1.8100
+1268 "S17" 100.00 100.00 0.0000 100.00 1.5800 1.3300 1.2300
+1269 "S18" 0.0000 0.0000 40.000 100.00 2.6600 2.7900 1.6200
+1270 "G52" 0.0000 40.000 40.000 100.00 2.4800 2.3600 1.3200
+1271 "O21" 0.0000 100.00 40.000 100.00 2.4000 1.8300 0.92000
+1272 "I30" 40.000 0.0000 40.000 100.00 1.9700 2.2300 1.5800
+1273 "O38" 40.000 40.000 40.000 100.00 1.9500 1.9600 1.3100
+1274 "Q18" 40.000 100.00 40.000 100.00 2.0500 1.6300 0.94000
+1275 "H28" 100.00 0.0000 40.000 100.00 1.2300 1.6600 1.6700
+1276 "O43" 100.00 40.000 40.000 100.00 1.3500 1.5600 1.3900
+1277 "A19" 100.00 100.00 40.000 100.00 1.6300 1.4600 1.0400
+1278 "S20" 0.0000 0.0000 100.00 100.00 2.5600 2.8300 0.98000
+1279 "A56" 0.0000 40.000 100.00 100.00 2.4600 2.4900 0.89000
+1280 "U5" 0.0000 100.00 100.00 100.00 2.4600 2.0800 0.85000
+1281 "AA28" 40.000 0.0000 100.00 100.00 1.9200 2.3000 0.93000
+1282 "H6" 40.000 40.000 100.00 100.00 1.9500 2.1100 0.85000
+1283 "S42" 40.000 100.00 100.00 100.00 2.1100 1.8700 0.81000
+1284 "P12" 100.00 0.0000 100.00 100.00 1.2000 1.7500 0.98000
+1285 "C35" 100.00 40.000 100.00 100.00 1.3600 1.6900 0.90000
+1286 "U3" 100.00 100.00 100.00 100.00 1.6800 1.6600 0.83000
+1287 "Y48" 100.00 0.0000 0.0000 0.0000 16.720 25.290 56.260
+1288 "J29" 98.039 0.0000 0.0000 0.0000 17.390 26.000 56.550
+1289 "A33" 94.902 0.0000 0.0000 0.0000 18.440 27.100 57.000
+1290 "V2" 90.196 0.0000 0.0000 0.0000 20.310 29.010 57.740
+1291 "A37" 85.098 0.0000 0.0000 0.0000 22.360 31.030 58.510
+1292 "N12" 80.000 0.0000 0.0000 0.0000 24.560 33.150 59.270
+1293 "J47" 74.902 0.0000 0.0000 0.0000 26.920 35.350 60.050
+1294 "O3" 70.196 0.0000 0.0000 0.0000 29.450 37.760 60.910
+1295 "N19" 60.000 0.0000 0.0000 0.0000 35.020 43.070 62.800
+1296 "H50" 50.196 0.0000 0.0000 0.0000 41.200 48.900 64.790
+1297 "D48" 40.000 0.0000 0.0000 0.0000 48.240 55.380 66.850
+1298 "K12" 29.804 0.0000 0.0000 0.0000 56.270 62.660 68.950
+1299 "H52" 25.098 0.0000 0.0000 0.0000 60.620 66.560 70.010
+1300 "H13" 20.000 0.0000 0.0000 0.0000 65.080 70.510 71.060
+1301 "Y8" 14.902 0.0000 0.0000 0.0000 69.620 74.500 72.110
+1302 "A54" 10.196 0.0000 0.0000 0.0000 74.060 78.380 73.130
+1303 "I17" 7.0588 0.0000 0.0000 0.0000 76.690 80.650 73.730
+1304 "O50" 5.0980 0.0000 0.0000 0.0000 78.370 82.090 74.120
+1305 "H30" 3.1373 0.0000 0.0000 0.0000 80.070 83.550 74.510
+1306 "Y45" 1.9608 0.0000 0.0000 0.0000 80.930 84.290 74.710
+1307 "U49" 0.0000 100.00 0.0000 0.0000 32.280 16.480 15.950
+1308 "U41" 0.0000 98.039 0.0000 0.0000 32.750 17.030 16.530
+1309 "Q56" 0.0000 94.902 0.0000 0.0000 33.460 17.900 17.440
+1310 "M3" 0.0000 90.196 0.0000 0.0000 34.690 19.430 19.040
+1311 "S27" 0.0000 85.098 0.0000 0.0000 36.010 21.120 20.750
+1312 "R27" 0.0000 80.000 0.0000 0.0000 37.400 22.980 22.580
+1313 "F41" 0.0000 74.902 0.0000 0.0000 38.840 24.970 24.520
+1314 "T44" 0.0000 70.196 0.0000 0.0000 40.640 27.330 26.760
+1315 "L18" 0.0000 60.000 0.0000 0.0000 44.970 32.940 32.000
+1316 "E17" 0.0000 50.196 0.0000 0.0000 50.010 39.680 38.140
+1317 "D6" 0.0000 40.000 0.0000 0.0000 55.570 47.360 44.900
+1318 "M47" 0.0000 29.804 0.0000 0.0000 61.730 55.910 51.990
+1319 "X27" 0.0000 25.098 0.0000 0.0000 64.990 60.480 55.690
+1320 "AA50" 0.0000 20.000 0.0000 0.0000 68.390 65.250 59.520
+1321 "Z47" 0.0000 14.902 0.0000 0.0000 71.880 70.190 63.430
+1322 "U24" 0.0000 10.196 0.0000 0.0000 75.440 75.210 67.360
+1323 "T5" 0.0000 7.0588 0.0000 0.0000 77.590 78.300 69.700
+1324 "Y55" 0.0000 5.0980 0.0000 0.0000 79.020 80.390 71.220
+1325 "L52" 0.0000 3.1373 0.0000 0.0000 80.470 82.520 72.750
+1326 "A26" 0.0000 1.9608 0.0000 0.0000 81.200 83.590 73.530
+1327 "Z40" 0.0000 0.0000 100.00 0.0000 67.430 72.230 6.1400
+1328 "A38" 0.0000 0.0000 98.039 0.0000 67.550 72.380 6.6300
+1329 "P53" 0.0000 0.0000 94.902 0.0000 67.740 72.610 7.4100
+1330 "K37" 0.0000 0.0000 90.196 0.0000 68.070 73.010 8.8300
+1331 "R54" 0.0000 0.0000 85.098 0.0000 68.430 73.430 10.410
+1332 "D24" 0.0000 0.0000 80.000 0.0000 68.840 73.870 12.190
+1333 "D26" 0.0000 0.0000 74.902 0.0000 69.260 74.310 14.170
+1334 "P47" 0.0000 0.0000 70.196 0.0000 69.800 74.880 16.470
+1335 "S13" 0.0000 0.0000 60.000 0.0000 71.090 76.210 22.050
+1336 "E15" 0.0000 0.0000 50.196 0.0000 72.640 77.690 29.020
+1337 "M2" 0.0000 0.0000 40.000 0.0000 74.390 79.200 36.970
+1338 "AA3" 0.0000 0.0000 29.804 0.0000 76.290 80.780 45.490
+1339 "R25" 0.0000 0.0000 25.098 0.0000 77.270 81.580 50.000
+1340 "Q49" 0.0000 0.0000 20.000 0.0000 78.300 82.380 54.640
+1341 "AA31" 0.0000 0.0000 14.902 0.0000 79.330 83.180 59.470
+1342 "B35" 0.0000 0.0000 10.196 0.0000 80.380 84.000 64.370
+1343 "K16" 0.0000 0.0000 7.0588 0.0000 81.040 84.510 67.460
+1344 "X17" 0.0000 0.0000 5.0980 0.0000 81.510 84.870 69.580
+1345 "AA53" 0.0000 0.0000 3.1373 0.0000 81.970 85.230 71.760
+1346 "X16" 0.0000 0.0000 1.9608 0.0000 82.200 85.410 72.860
+1347 "Z12" 0.0000 0.0000 0.0000 100.00 2.6900 2.8000 2.1600
+1348 "AA32" 0.0000 0.0000 0.0000 98.039 3.0500 3.1800 2.4900
+1349 "P25" 0.0000 0.0000 0.0000 94.902 3.6700 3.8200 3.0400
+1350 "I34" 0.0000 0.0000 0.0000 90.196 4.8400 5.0500 4.1200
+1351 "T53" 0.0000 0.0000 0.0000 85.098 6.2100 6.4700 5.3700
+1352 "R41" 0.0000 0.0000 0.0000 80.000 7.9300 8.2700 6.9600
+1353 "O55" 0.0000 0.0000 0.0000 74.902 10.010 10.450 8.8900
+1354 "Q2" 0.0000 0.0000 0.0000 70.196 12.600 13.150 11.280
+1355 "I41" 0.0000 0.0000 0.0000 60.000 18.920 19.770 17.150
+1356 "W16" 0.0000 0.0000 0.0000 50.196 26.590 27.730 24.310
+1357 "L32" 0.0000 0.0000 0.0000 40.000 35.870 37.330 32.950
+1358 "S19" 0.0000 0.0000 0.0000 29.804 46.510 48.340 42.550
+1359 "E40" 0.0000 0.0000 0.0000 25.098 52.470 54.520 47.890
+1360 "X13" 0.0000 0.0000 0.0000 20.000 58.360 60.610 53.170
+1361 "R47" 0.0000 0.0000 0.0000 14.902 64.370 66.830 58.570
+1362 "AA9" 0.0000 0.0000 0.0000 10.196 70.130 72.800 63.780
+1363 "AA37" 0.0000 0.0000 0.0000 7.0588 73.750 76.540 67.050
+1364 "I15" 0.0000 0.0000 0.0000 5.0980 76.230 79.110 69.290
+1365 "G32" 0.0000 0.0000 0.0000 3.1373 78.770 81.730 71.570
+1366 "E54" 0.0000 0.0000 0.0000 1.9608 80.050 83.060 72.740
+1367 "G48" 0.0000 0.0000 0.0000 0.0000 82.670 85.770 75.100
+1368 "C51" 100.00 85.098 85.098 0.0000 4.2100 5.0800 3.8600
+1369 "F29" 80.000 65.098 65.098 0.0000 9.2500 10.040 7.5600
+1370 "U4" 60.000 45.098 45.098 0.0000 18.590 19.740 16.510
+1371 "AA34" 40.000 27.059 27.059 0.0000 34.220 36.090 31.630
+1372 "E51" 20.000 12.157 12.157 0.0000 56.270 58.800 51.990
+1373 "J43" 10.196 5.8824 5.8824 0.0000 68.820 71.500 62.730
+1374 "N10" 5.0980 3.1373 3.1373 0.0000 75.560 78.420 68.630
+1375 "A25" 40.000 27.059 27.059 10.196 29.920 31.630 27.750
+1376 "G9" 20.000 12.157 12.157 10.196 48.460 50.700 44.880
+1377 "H42" 10.196 5.8824 5.8824 10.196 58.810 61.160 53.730
+1378 "J48" 60.000 45.098 45.098 20.000 14.020 14.930 12.540
+1379 "X5" 40.000 27.059 27.059 20.000 25.580 27.090 23.790
+1380 "Q36" 20.000 12.157 12.157 20.000 40.850 42.790 37.950
+1381 "W56" 10.196 5.8824 5.8824 20.000 49.240 51.260 45.120
+1382 "V46" 80.000 65.098 65.098 40.000 5.0200 5.3800 3.9000
+1383 "W2" 60.000 45.098 45.098 40.000 8.9700 9.5400 7.9900
+1384 "O37" 40.000 27.059 27.059 40.000 15.850 16.790 14.880
+1385 "W37" 20.000 12.157 12.157 40.000 25.140 26.400 23.570
+1386 "W10" 10.196 5.8824 5.8824 40.000 30.280 31.590 27.990
+1387 "C33" 100.00 85.098 85.098 60.000 2.2400 2.4600 1.6300
+1388 "H1" 80.000 65.098 65.098 60.000 3.1800 3.3500 2.3200
+1389 "AA41" 60.000 45.098 45.098 60.000 4.8500 5.0700 4.4500
+1390 "Y38" 40.000 27.059 27.059 60.000 8.3800 8.8100 8.0600
+1391 "F57" 20.000 12.157 12.157 60.000 13.460 14.110 12.550
+1392 "G51" 10.196 5.8824 5.8824 60.000 16.140 16.860 14.740
+1393 "K39" 100.00 85.098 85.098 80.000 1.9600 2.0600 1.2500
+1394 "X55" 80.000 65.098 65.098 80.000 2.3600 2.4500 1.6300
+1395 "W36" 60.000 45.098 45.098 80.000 3.0700 3.2100 2.4800
+1396 "V50" 40.000 27.059 27.059 80.000 4.2700 4.4900 3.7200
+1397 "K42" 20.000 12.157 12.157 80.000 5.9400 6.2300 5.2700
+1398 "H46" 10.196 5.8824 5.8824 80.000 6.8900 7.1900 6.0600
+1399 "K20" 100.00 85.098 85.098 100.00 1.6000 1.6200 0.88000
+1400 "O28" 80.000 65.098 65.098 100.00 1.6500 1.6700 1.0000
+1401 "M55" 60.000 45.098 45.098 100.00 1.7400 1.7900 1.2400
+1402 "Q33" 40.000 27.059 27.059 100.00 1.9500 2.0300 1.5400
+1403 "G11" 20.000 12.157 12.157 100.00 2.2800 2.3700 1.8500
+1404 "O24" 10.196 5.8824 5.8824 100.00 2.4700 2.5700 1.9900
+1405 "I40" 100.00 0.0000 0.0000 70.196 3.3500 4.9400 9.1000
+1406 "V26" 0.0000 100.00 0.0000 70.196 6.2200 3.6300 3.1400
+1407 "P23" 0.0000 0.0000 100.00 70.196 10.310 11.280 1.9600
+1408 "Z38" 100.00 100.00 0.0000 70.196 2.3500 1.9200 3.4300
+1409 "I20" 100.00 0.0000 100.00 70.196 2.2700 4.2800 1.9000
+1410 "V18" 0.0000 100.00 100.00 70.196 5.9200 3.9200 1.1400
+1411 "U33" 40.000 40.000 0.0000 70.196 6.0400 5.7300 7.0200
+1412 "V37" 40.000 0.0000 40.000 70.196 6.8800 8.3200 5.7100
+1413 "A23" 0.0000 40.000 40.000 70.196 8.4500 7.5800 4.3000
+1414 "U54" 3.1373 3.1373 0.0000 0.0000 77.910 80.350 72.190
+1415 "Y1" 3.1373 0.0000 3.1373 0.0000 79.370 83.010 71.210
+1416 "M8" 0.0000 3.1373 3.1373 0.0000 79.770 81.980 69.490
+1417 "J50" 3.1373 3.1373 3.1373 0.0000 77.230 79.830 68.970
+1418 "J55" 3.1373 0.0000 0.0000 3.1373 76.310 79.640 71.020
+1419 "M42" 0.0000 3.1373 0.0000 3.1373 76.690 78.660 69.370
+1420 "A14" 3.1373 3.1373 0.0000 3.1373 74.280 76.630 68.840
+1421 "Y9" 0.0000 0.0000 3.1373 3.1373 78.110 81.220 68.430
+1422 "S14" 3.1373 0.0000 3.1373 3.1373 75.660 79.130 67.910
+1423 "G15" 0.0000 3.1373 3.1373 3.1373 76.030 78.160 66.300
+1424 "H48" 3.1373 3.1373 3.1373 3.1373 73.640 76.140 65.810
+1425 "B30" 7.0588 7.0588 0.0000 0.0000 71.830 73.480 68.450
+1426 "G36" 7.0588 0.0000 7.0588 0.0000 75.070 79.390 66.280
+1427 "G44" 0.0000 7.0588 7.0588 0.0000 75.980 77.080 62.510
+1428 "Q52" 7.0588 7.0588 7.0588 0.0000 70.400 72.440 61.560
+1429 "C50" 7.0588 0.0000 0.0000 7.0588 68.550 72.090 65.870
+1430 "D46" 0.0000 7.0588 0.0000 7.0588 69.340 70.070 62.380
+1431 "M28" 7.0588 7.0588 0.0000 7.0588 64.320 65.870 61.300
+1432 "K19" 0.0000 0.0000 7.0588 7.0588 72.350 75.460 60.420
+1433 "I56" 7.0588 0.0000 7.0588 7.0588 67.150 71.010 59.410
+1434 "S23" 0.0000 7.0588 7.0588 7.0588 67.940 69.020 56.130
+1435 "I35" 7.0588 7.0588 7.0588 7.0588 63.090 64.980 55.310
+1436 "F10" 40.000 3.1373 0.0000 0.0000 46.900 53.230 64.760
+1437 "W32" 3.1373 40.000 0.0000 0.0000 53.700 46.000 44.550
+1438 "K38" 40.000 0.0000 3.1373 0.0000 47.760 55.080 63.820
+1439 "B41" 40.000 3.1373 3.1373 0.0000 46.430 52.940 61.850
+1440 "B55" 0.0000 40.000 3.1373 0.0000 55.180 47.100 42.990
+1441 "H3" 3.1373 40.000 3.1373 0.0000 53.320 45.760 42.680
+1442 "F3" 40.000 40.000 3.1373 0.0000 31.900 30.200 39.030
+1443 "N27" 3.1373 0.0000 40.000 0.0000 71.840 77.030 36.790
+1444 "U30" 0.0000 3.1373 40.000 0.0000 72.430 76.190 35.830
+1445 "T32" 3.1373 3.1373 40.000 0.0000 69.950 74.110 35.680
+1446 "A1" 40.000 3.1373 40.000 0.0000 40.970 49.010 32.140
+1447 "H12" 3.1373 40.000 40.000 0.0000 49.290 43.080 22.680
+1448 "A7" 40.000 0.0000 0.0000 3.1373 46.150 52.970 63.810
+1449 "N28" 40.000 3.1373 0.0000 3.1373 44.890 50.940 61.840
+1450 "T33" 0.0000 40.000 0.0000 3.1373 53.090 45.340 42.990
+1451 "G57" 3.1373 40.000 0.0000 3.1373 51.330 44.050 42.660
+1452 "AA29" 40.000 40.000 0.0000 3.1373 30.990 29.250 39.160
+1453 "Z54" 40.000 0.0000 3.1373 3.1373 45.700 52.680 60.950
+1454 "B57" 40.000 3.1373 3.1373 3.1373 44.460 50.670 59.100
+1455 "E19" 0.0000 40.000 3.1373 3.1373 52.730 45.090 41.180
+1456 "W24" 3.1373 40.000 3.1373 3.1373 50.980 43.830 40.890
+1457 "L16" 40.000 40.000 3.1373 3.1373 30.680 29.090 37.450
+1458 "Q38" 0.0000 0.0000 40.000 3.1373 70.950 75.570 35.460
+1459 "E28" 3.1373 0.0000 40.000 3.1373 68.550 73.520 35.290
+1460 "J25" 40.000 0.0000 40.000 3.1373 40.440 48.890 31.760
+1461 "Z42" 0.0000 3.1373 40.000 3.1373 69.110 72.730 34.390
+1462 "O40" 3.1373 3.1373 40.000 3.1373 66.780 70.770 34.250
+1463 "P48" 40.000 3.1373 40.000 3.1373 39.330 47.000 30.880
+1464 "S48" 0.0000 40.000 40.000 3.1373 48.850 42.450 21.930
+1465 "T54" 3.1373 40.000 40.000 3.1373 47.180 41.310 21.840
+1466 "V21" 40.000 40.000 40.000 3.1373 27.660 27.330 20.040
+1467 "X32" 3.1373 0.0000 0.0000 40.000 34.810 36.430 32.700
+1468 "M54" 0.0000 3.1373 0.0000 40.000 35.000 36.040 32.030
+1469 "P18" 3.1373 3.1373 0.0000 40.000 33.960 35.170 31.790
+1470 "B29" 40.000 3.1373 0.0000 40.000 21.090 23.970 28.560
+1471 "N42" 3.1373 40.000 0.0000 40.000 24.370 21.350 20.800
+1472 "H36" 0.0000 0.0000 3.1373 40.000 35.580 37.110 31.630
+1473 "Y33" 3.1373 0.0000 3.1373 40.000 34.530 36.220 31.390
+1474 "X38" 40.000 0.0000 3.1373 40.000 21.430 24.730 28.190
+1475 "W46" 0.0000 3.1373 3.1373 40.000 34.710 35.820 30.740
+1476 "Q34" 3.1373 3.1373 3.1373 40.000 33.680 34.950 30.510
+1477 "L53" 40.000 3.1373 3.1373 40.000 20.900 23.850 27.410
+1478 "Q23" 0.0000 40.000 3.1373 40.000 24.990 21.820 20.150
+1479 "N22" 3.1373 40.000 3.1373 40.000 24.220 21.240 20.010
+1480 "L57" 40.000 40.000 3.1373 40.000 15.080 14.420 18.190
+1481 "F5" 3.1373 0.0000 40.000 40.000 31.250 33.670 16.670
+1482 "J22" 0.0000 3.1373 40.000 40.000 31.520 33.360 16.290
+1483 "H27" 3.1373 3.1373 40.000 40.000 30.520 32.520 16.230
+1484 "U29" 40.000 3.1373 40.000 40.000 18.520 22.170 14.690
+1485 "U34" 3.1373 40.000 40.000 40.000 22.390 20.040 10.900
+0 "R9" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "R38" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "T45" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "G12" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Q37" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "G4" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Z32" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "S6" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "V39" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "V44" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Q26" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Z3" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "N38" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "B22" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "W21" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "B47" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "AA45" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Z1" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "R32" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "V11" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "P31" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "W31" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "N13" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "H31" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "K50" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "M26" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "J40" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "B34" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "T56" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "K25" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "W15" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "E8" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "G13" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "C17" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "U14" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Y12" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "J20" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "A16" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "B37" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "U7" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "X44" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "U8" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "AA43" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "U52" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "J13" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "J5" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "I10" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "O26" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "Z14" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "V13" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "C37" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "X46" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "L33" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+0 "R28" 0.0000 0.0000 0.0000 0.0000 86.887 89.830 77.952
+END_DATA
diff --git a/target/ECI2002R.ti2 b/target/ECI2002R.ti2
new file mode 100644
index 0000000..d3f2d8b
--- /dev/null
+++ b/target/ECI2002R.ti2
@@ -0,0 +1,1517 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+# ECI2002 Random CMYK chart, 1485 patches.
+ORIGINATOR "Argyll printtarg"
+CREATED "Thu Aug 11 22:19:15 2005"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
+KEYWORD "MULTI_DIM_STEPS"
+MULTI_DIM_STEPS "2"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "96.420000 100.000000 82.490000"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "33"
+KEYWORD "PASSES_IN_STRIPS"
+PASSES_IN_STRIPS "j"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "A-Z, 2-9;A-X,2A-9Z"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1485
+BEGIN_DATA
+810 "A1" 10 20 20 20 42.793 42.608 32.296
+1369 "A2" 80 65 65 0 9.5005 10.178 7.8087
+1393 "A3" 100 85 85 80 1.9086 2.003 1.1906
+1427 "A4" 0 7 7 0 76.857 77.978 63.869
+1387 "A5" 100 85 85 60 2.2422 2.4721 1.6188
+1377 "A6" 10 6 6 10 60.778 63.216 55.806
+558 "A7" 85 100 70 0 6.1175 5.0394 4.4819
+1381 "A8" 10 6 6 20 50.129 52.184 46.198
+1394 "A9" 80 65 65 80 2.3235 2.4083 1.599
+1434 "A10" 0 7 7 7 69.874 71.047 58.514
+1388 "A11" 80 65 65 60 3.437 3.6144 2.5883
+1392 "A12" 10 6 6 60 16.236 16.953 14.978
+1382 "A13" 80 65 65 40 5.2618 5.5902 4.1157
+93 "A14" 10 20 10 0 60.498 59.465 51.051
+230 "A15" 85 40 20 0 13.639 16.589 27.468
+1430 "A16" 0 7 0 7 71.224 72.097 64.03
+1395 "A17" 60 45 45 80 3.041 3.1902 2.4497
+1376 "A18" 20 12 12 10 49.823 52.06 45.983
+1389 "A19" 60 45 45 60 5.2975 5.5898 4.7403
+1380 "A20" 20 12 12 20 41.45 43.378 38.352
+1424 "A21" 3 3 3 3 75.838 78.392 68.023
+1385 "A22" 20 12 12 40 25.493 26.703 23.726
+1378 "A23" 60 45 45 20 14.211 15.169 12.762
+1391 "A24" 20 12 12 60 13.215 13.844 12.297
+1420 "A25" 3 3 0 3 76.251 78.631 70.15
+1397 "A26" 20 12 12 80 5.8519 6.1281 5.184
+210 "A27" 55 20 20 0 29.639 34.115 38.205
+101 "A28" 20 10 10 0 58.653 61.601 55.595
+1432 "A29" 0 0 7 7 74.374 77.494 62.933
+1375 "A30" 40 27 27 10 30.415 32.13 28.372
+1384 "A31" 40 27 27 40 16.266 17.237 15.144
+1379 "A32" 40 27 27 20 25.674 27.176 23.921
+1 "A33" 0 0 0 0 83.532 86.556 75.658
+970 "B1" 100 100 0 40 3.6335 2.7779 7.9686
+1049 "B2" 0 70 100 40 16.486 12.087 1.9347
+968 "B3" 100 40 0 40 5.7755 7.1079 16.701
+336 "B4" 10 20 40 0 55.595 55.81 29.655
+479 "B5" 100 10 55 0 9.9812 18.831 18.457
+560 "B6" 100 10 70 0 8.8992 17.985 12.749
+328 "B7" 0 30 40 0 56.678 52.472 26.359
+564 "B8" 100 55 70 0 5.8864 8.9485 7.8006
+974 "B9" 0 70 20 40 18.626 13.239 10.215
+1045 "B10" 100 100 70 40 2.8294 2.7651 2.6045
+234 "B11" 85 100 20 0 7.5253 5.3012 12.047
+999 "B12" 0 70 40 40 17.721 12.765 7.0851
+1018 "B13" 100 40 40 40 4.5218 6.511 8.8453
+997 "B14" 0 20 40 40 27.374 27.152 13.911
+641 "B15" 100 10 85 0 8.1959 17.374 8.6931
+849 "B16" 10 100 40 20 20.419 11.252 6.8398
+433 "B17" 30 0 55 0 47.637 56.166 23.691
+279 "B18" 30 100 30 0 20.49 11.372 10.058
+469 "B19" 85 0 55 0 16.124 26.789 20.762
+315 "B20" 85 100 30 0 7.2433 5.2818 10.282
+1046 "B21" 0 0 100 40 28.466 31.033 3.3861
+955 "B22" 20 100 0 40 11.794 6.4646 7.5603
+1056 "B23" 40 0 100 40 16.346 20.623 3.1537
+965 "B24" 70 100 0 40 5.7639 3.7213 7.6967
+1066 "B25" 100 0 100 40 4.1162 8.961 3.2855
+422 "B26" 10 85 55 0 30.135 18.78 7.901
+887 "B27" 20 10 70 20 36.357 39.95 11.445
+458 "B28" 55 85 55 0 14.013 10.389 7.6421
+899 "B29" 70 10 70 20 14.937 21.331 10.227
+740 "B30" 10 70 0 20 26.948 18.819 20.02
+911 "B31" 0 10 100 20 43.802 45.594 4.5306
+1265 "B32" 40 100 0 100 2.0055 1.5286 1.1038
+905 "B33" 100 10 70 20 6.9562 13.709 9.7649
+1061 "C1" 70 0 100 40 9.2036 14.115 3.1614
+952 "C2" 20 20 0 40 24.491 24.553 25.45
+1063 "C3" 70 40 100 40 6.7295 8.3357 2.4606
+358 "C4" 30 70 40 0 25.322 19.034 13.417
+720 "C5" 85 100 100 0 5.6081 4.8531 2.2834
+135 "C6" 55 100 10 0 13.763 8.0611 13.747
+350 "C7" 20 85 40 0 26.724 17.011 10.976
+384 "C8" 70 55 40 0 14.077 14.733 15.901
+1027 "C9" 20 20 70 40 20.476 21.648 6.6864
+986 "C10" 70 0 20 40 12.854 17.116 20.559
+389 "C11" 85 10 40 0 16.298 24.777 26.866
+1002 "C12" 20 20 40 40 21.604 22.456 13.304
+1013 "C13" 70 40 40 40 7.9577 9.151 9.2125
+1004 "C14" 20 70 40 40 13.987 10.47 6.8252
+216 "C15" 55 100 20 0 13.4 7.9938 11.912
+728 "C16" 100 85 100 0 4.0841 5.1036 2.7965
+471 "C17" 85 20 55 0 13.49 20.624 17.26
+457 "C18" 55 70 55 0 15.752 13.406 9.2268
+435 "C19" 30 20 55 0 40.149 43.322 19.482
+421 "C20" 10 70 55 0 33.517 23.678 9.8153
+400 "C21" 100 30 40 0 9.4072 14.991 21.358
+186 "C22" 20 55 20 0 35.935 29.1 25.365
+616 "C23" 55 30 85 0 21.553 25.496 7.2393
+222 "C24" 70 55 20 0 15.6 15.466 23.084
+580 "C25" 10 30 85 0 46.288 44.489 7.4927
+1267 "C26" 100 40 0 100 1.3818 1.5205 1.8283
+935 "C27" 70 10 100 20 13.917 20.374 4.265
+1261 "C28" 0 40 0 100 2.8301 2.5695 1.9105
+918 "C29" 10 20 100 20 36.334 37.277 4.1001
+474 "C30" 85 55 55 0 9.5771 11.612 11.315
+452 "C31" 55 10 55 0 28.107 35.803 20.187
+438 "C32" 30 55 55 0 28.453 24.407 11.952
+416 "C33" 10 10 55 0 58.641 61.983 22.575
+960 "D1" 40 100 0 40 8.982 5.1483 7.5676
+1059 "D2" 40 70 100 40 9.3594 7.7211 1.9254
+958 "D3" 40 40 0 40 15.606 14.83 19.238
+372 "D4" 55 20 40 0 27.182 32.439 26.236
+370 "D5" 55 0 40 0 32.564 42.302 31.907
+362 "D6" 40 10 40 0 39.04 45.288 30.422
+364 "D7" 40 30 40 0 32.681 34.373 24.474
+366 "D8" 40 55 40 0 24.752 21.975 16.766
+984 "D9" 40 70 20 40 11.209 8.7933 9.4358
+1035 "D10" 40 100 70 40 8.2908 5.2998 2.5581
+198 "D11" 30 100 20 0 20.728 11.36 11.887
+1009 "D12" 40 70 40 40 10.342 8.24 6.5236
+1008 "D13" 40 40 40 40 13.263 13.221 9.9237
+1007 "D14" 40 20 40 40 15.983 17.734 12.478
+371 "D15" 55 10 40 0 29.797 37.094 29.054
+419 "D16" 10 40 55 0 44.092 39.582 15.619
+437 "D17" 30 40 55 0 32.767 31.468 14.757
+455 "D18" 55 40 55 0 21.173 22.9 14.519
+473 "D19" 85 40 55 0 10.975 15.009 13.636
+150 "D20" 85 55 10 0 12.293 12.909 26.065
+1048 "D21" 0 40 100 40 20.719 18.667 2.3797
+953 "D22" 20 40 0 40 20.382 18.42 20.1
+1058 "D23" 40 40 100 40 11.607 11.948 2.4183
+963 "D24" 70 40 0 40 9.8391 10.374 17.803
+1068 "D25" 100 40 100 40 3.3945 5.7942 2.5531
+418 "D26" 10 30 55 0 48.669 46.539 17.988
+436 "D27" 30 30 55 0 36.428 37.272 17.106
+454 "D28" 55 30 55 0 23.62 27.183 16.565
+76 "D29" 100 30 0 0 13.039 16.997 41.354
+738 "D30" 10 20 0 20 44.794 43.834 42.663
+1278 "D31" 0 0 100 100 2.572 2.8437 0.98565
+1263 "D32" 40 0 0 100 3.6855 4.1078 4.037
+1284 "D33" 100 0 100 100 1.2048 1.7593 0.98423
+1051 "E1" 20 0 100 40 22.537 26.074 3.287
+962 "E2" 70 20 0 40 11.811 13.835 22.408
+1053 "E3" 20 40 100 40 16.09 15.286 2.4195
+394 "E4" 85 70 40 0 9.0571 9.2955 12.883
+684 "E5" 30 100 100 0 19.136 11.158 2.267
+99 "E6" 10 100 10 0 28.387 14.824 13.952
+386 "E7" 70 85 40 0 10.927 8.6924 10.65
+348 "E8" 20 55 40 0 34.295 28.185 17.407
+1037 "E9" 70 20 70 40 8.742 11.892 6.0601
+976 "E10" 20 0 20 40 27.708 30.572 23.903
+353 "E11" 30 10 40 0 45.851 51.24 31.303
+1012 "E12" 70 20 40 40 9.5758 12.338 11.494
+1003 "E13" 20 40 40 40 17.982 16.763 10.473
+1014 "E14" 70 70 40 40 6.3807 5.873 6.3043
+180 "E15" 10 100 20 0 28.092 14.8 12.13
+1042 "E16" 100 20 70 40 4.4208 8.0398 5.8433
+989 "E17" 70 70 20 40 7.153 6.3562 9.1678
+1032 "E18" 40 20 70 40 15.006 17.115 6.3506
+979 "E19" 20 70 20 40 14.885 11.021 9.8194
+1022 "E20" 0 20 70 40 26.023 26.124 6.893
+465 "E21" 70 55 55 0 13.34 14.247 11.521
+443 "E22" 40 10 55 0 37.025 43.64 20.961
+429 "E23" 20 55 55 0 33.356 27.593 12.197
+407 "E24" 0 10 55 0 66.105 68.086 22.708
+847 "E25" 10 40 40 20 33.266 30.041 17.13
+791 "E26" 70 10 10 20 19.449 24.461 34.957
+1282 "E27" 40 40 100 100 2.0252 2.1915 0.93621
+779 "E28" 20 10 10 20 42.453 44.687 40.368
+920 "E29" 10 70 100 20 23.705 17.325 2.4843
+470 "E30" 85 10 55 0 14.757 23.58 19.012
+456 "E31" 55 55 55 0 18.248 17.687 11.697
+434 "E32" 30 10 55 0 43.729 49.397 21.567
+420 "E33" 10 55 55 0 38.378 30.8 12.538
+950 "F1" 0 100 0 40 14.72 7.8407 7.6846
+1069 "F2" 100 70 100 40 2.9619 3.9055 2.0486
+948 "F3" 0 40 0 40 25.204 21.959 20.959
+481 "F4" 100 30 55 0 8.3475 14.293 15.071
+334 "F5" 10 0 40 0 66.412 72.64 36.369
+326 "F6" 0 10 40 0 68.338 69.993 33.426
+562 "F7" 100 30 70 0 7.442 13.62 10.455
+330 "F8" 0 55 40 0 44.42 34.552 18.22
+994 "F9" 100 70 20 40 4.1074 4.3786 8.8089
+1025 "F10" 0 100 70 40 14.075 8.072 2.5768
+813 "F11" 10 100 20 20 20.591 11.076 9.279
+1019 "F12" 100 70 40 40 3.6876 4.2309 6.2137
+998 "F13" 0 40 40 40 23.042 20.474 11.041
+1017 "F14" 100 20 40 40 5.3212 8.6332 11.014
+335 "F15" 10 10 40 0 61.004 64.009 33.147
+971 "F16" 0 0 20 40 34.702 36.66 25.315
+1030 "F17" 20 100 70 40 11.115 6.6577 2.5397
+981 "F18" 40 0 20 40 20.866 24.502 22.417
+1040 "F19" 70 100 70 40 5.0452 3.8003 2.5712
+991 "F20" 100 0 20 40 7.0357 11.405 18.83
+848 "F21" 10 70 40 20 25.346 18.217 10.84
+851 "F22" 20 10 40 20 39.003 42.17 24.128
+431 "F23" 20 85 55 0 26.099 16.712 7.7591
+863 "F24" 70 10 40 20 16.884 22.769 20.63
+467 "F25" 70 85 55 0 10.306 8.4104 7.6211
+875 "F26" 0 10 70 20 46.193 47.991 11.698
+440 "F27" 30 85 55 0 22.165 14.664 7.6754
+893 "F28" 40 10 70 20 26.604 31.587 10.802
+476 "F29" 85 85 55 0 7.4139 6.8546 7.6769
+731 "F30" 0 10 0 20 54.196 54.229 48.696
+1280 "F31" 0 100 100 100 2.4602 2.0877 0.85588
+749 "F32" 40 10 0 20 32.888 36.102 43.757
+1286 "F33" 100 100 100 100 1.6821 1.6669 0.84474
+91 "G1" 10 0 10 0 72.655 77.501 63.478
+151 "G2" 85 70 10 0 10.431 9.6758 21.099
+127 "G3" 55 0 10 0 36.695 45.049 54.358
+115 "G4" 30 70 10 0 27.027 19.626 22.285
+74 "G5" 100 10 0 0 15.768 22.473 51.333
+799 "G6" 100 40 10 20 8.0418 10.464 23.122
+901 "G7" 70 40 70 20 11.548 14.047 7.522
+787 "G8" 40 40 10 20 24.018 23.121 26.467
+889 "G9" 20 40 70 20 27.785 26.194 8.1213
+769 "G10" 0 40 10 20 39.7 34.449 29.069
+92 "G11" 10 10 10 0 66.392 68.104 57.186
+152 "G12" 85 85 10 0 9.0576 7.294 17.214
+128 "G13" 55 10 10 0 33.535 39.592 49.444
+116 "G14" 30 85 10 0 23.803 15.085 17.589
+236 "G15" 100 10 20 0 13.328 21.135 37.261
+323 "G16" 100 85 30 0 5.8909 5.7585 12.626
+587 "G17" 20 10 85 0 48.263 52.997 9.1566
+214 "G18" 55 70 20 0 17.587 14.191 18.765
+623 "G19" 70 10 85 0 18.622 27.328 8.567
+178 "G20" 10 70 20 0 35.423 24.586 20.135
+164 "G21" 0 10 20 0 72.096 72.884 50.177
+224 "G22" 70 85 20 0 11.621 8.7959 15.019
+200 "G23" 40 10 20 0 41.66 47.104 43.962
+188 "G24" 20 85 20 0 27.325 17.019 15.415
+398 "G25" 100 10 40 0 11.311 19.793 26.198
+1277 "G26" 100 100 40 100 1.6231 1.463 1.0683
+815 "G27" 20 10 20 20 41.466 44.041 34.957
+1271 "G28" 0 100 40 100 2.3835 1.8323 0.95284
+827 "G29" 70 10 20 20 18.625 23.963 30.049
+233 "G30" 85 85 20 0 8.7078 7.2232 14.921
+596 "G31" 30 10 85 0 41.074 46.949 8.98
+197 "G32" 30 85 20 0 23.387 14.972 15.204
+632 "G33" 85 10 85 0 12.726 21.931 8.5728
+873 "H1" 100 100 40 20 4.0344 3.542 6.6923
+826 "H2" 70 0 20 20 20.193 26.962 32.911
+861 "H3" 40 100 40 20 13.132 7.8145 6.7117
+814 "H4" 20 0 20 20 45.011 49.644 38.435
+843 "H5" 0 100 40 20 22.911 12.431 6.8012
+87 "H6" 0 55 10 0 46.808 35.876 30.627
+139 "H7" 70 30 10 0 21.203 24.321 37.669
+123 "H8" 40 55 10 0 27.068 23.111 28.104
+103 "H9" 20 30 10 0 47.872 45.713 43.191
+159 "H10" 100 55 10 0 9.06 10.557 25.56
+734 "H11" 0 70 0 20 30.09 20.627 20.392
+924 "H12" 20 20 100 20 31.964 33.847 4.0427
+752 "H13" 40 70 0 20 17.978 13.534 19.055
+936 "H14" 70 20 100 20 12.98 18.161 3.9702
+764 "H15" 100 70 0 20 6.3548 6.3278 17.789
+176 "H16" 10 40 20 0 47.705 42.092 33.062
+228 "H17" 85 20 20 0 16.859 22.879 35.148
+212 "H18" 55 40 20 0 23.936 24.63 29.499
+192 "H19" 30 20 20 0 44.961 47.088 41.589
+321 "H20" 100 55 30 0 7.8525 10.036 18.64
+967 "H21" 100 20 0 40 6.8416 9.3463 20.683
+1064 "H22" 70 70 100 40 5.5461 5.4696 1.964
+957 "H23" 40 20 0 40 18.62 19.639 24.192
+1054 "H24" 20 70 100 40 12.884 9.8577 1.9285
+947 "H25" 0 20 0 40 30.469 29.407 26.979
+177 "H26" 10 55 20 0 41.029 32.359 25.991
+211 "H27" 55 30 20 0 26.724 29.193 33.776
+213 "H28" 55 55 20 0 20.573 18.917 23.762
+175 "H29" 10 30 20 0 53.082 49.78 38.239
+775 "H30" 10 40 10 20 35.701 31.677 28.433
+1272 "H31" 40 0 40 100 3.1261 3.5912 2.1998
+1273 "H32" 40 40 40 100 1.9912 2.0029 1.3252
+774 "H33" 10 20 10 20 43.922 43.41 37.409
+95 "I1" 10 40 10 0 48.895 42.882 38.427
+147 "I2" 85 20 10 0 17.934 23.473 41.104
+131 "I3" 55 40 10 0 24.753 25.048 34.193
+111 "I4" 30 20 10 0 45.998 47.606 47.873
+78 "I5" 100 55 0 0 9.7782 10.862 29.546
+800 "I6" 100 70 10 20 6.0042 6.2242 15.688
+900 "I7" 70 20 70 20 13.87 18.947 9.4115
+788 "I8" 40 70 10 20 17.773 13.576 16.768
+888 "I9" 20 20 70 20 33.503 35.29 10.418
+770 "I10" 0 70 10 20 29.596 20.42 17.817
+96 "I11" 10 55 10 0 41.647 32.596 29.968
+148 "I12" 85 30 10 0 16.114 20.056 36.433
+132 "I13" 55 55 10 0 21.206 19.17 27.442
+112 "I14" 30 30 10 0 41.422 40.699 42.001
+240 "I15" 100 55 20 0 8.4259 10.278 22.043
+319 "I16" 100 30 30 0 10.129 15.397 25.408
+591 "I17" 20 55 85 0 32 26.649 5.4117
+1396 "I18" 40 27 27 80 4.0894 4.3142 3.5719
+627 "I19" 70 55 85 0 12.285 13.572 5.4121
+174 "I20" 10 20 20 0 58.796 58.174 43.686
+168 "I21" 0 55 20 0 46.124 35.582 26.484
+220 "I22" 70 30 20 0 20.264 23.866 32.415
+204 "I23" 40 55 20 0 26.384 22.796 24.217
+184 "I24" 20 30 20 0 46.704 44.962 37.252
+402 "I25" 100 55 40 0 7.331 9.8658 15.652
+1275 "I26" 100 0 40 100 1.2309 1.6899 1.6818
+1270 "I27" 0 40 40 100 3.2681 3.0735 1.5546
+1269 "I28" 0 0 40 100 2.9669 3.1625 1.83
+1276 "I29" 100 40 40 100 1.4023 1.624 1.4424
+229 "I30" 85 30 20 0 15.201 19.611 31.303
+600 "I31" 30 55 85 0 27.177 23.519 5.3512
+193 "I32" 30 30 20 0 40.3 40.044 36.324
+636 "I33" 85 55 85 0 8.5285 11.006 5.5658
+944 "J1" 100 70 100 20 3.8385 5.3703 2.7357
+756 "J2" 70 20 0 20 18.512 21.78 36.238
+932 "J3" 40 70 100 20 15.288 12.495 2.4705
+744 "J4" 20 20 0 20 39.781 39.757 41.498
+914 "J5" 0 70 100 20 26.393 18.799 2.4983
+83 "J6" 0 10 10 0 73.893 74.191 58.471
+143 "J7" 70 85 10 0 11.962 8.8492 17.294
+119 "J8" 40 10 10 0 43.033 47.993 51.622
+107 "J9" 20 85 10 0 27.765 17.167 17.844
+155 "J10" 100 10 10 0 14.44 21.781 43.785
+805 "J11" 0 40 20 20 38.936 33.996 25.233
+853 "J12" 20 40 40 20 29.539 27.398 16.776
+823 "J13" 40 40 20 20 23.556 22.971 23.03
+865 "J14" 70 40 40 20 12.596 14.604 14.68
+835 "J15" 100 40 20 20 7.5128 10.212 20.015
+172 "J16" 10 0 20 0 70.716 76.081 54.653
+232 "J17" 85 70 20 0 9.9958 9.5404 18.27
+208 "J18" 55 0 20 0 35.457 44.307 46.319
+196 "J19" 30 70 20 0 26.484 19.44 19.264
+317 "J20" 100 10 30 0 12.264 20.462 31.235
+404 "J21" 100 85 40 0 5.5846 5.711 10.662
+182 "J22" 20 10 20 0 56.852 60.272 47.551
+620 "J23" 55 85 85 0 13.193 10.033 3.8012
+218 "J24" 70 10 20 0 24.73 31.961 40.398
+584 "J25" 10 85 85 0 29.365 18.455 3.8402
+173 "J26" 10 10 20 0 64.663 66.846 49.307
+215 "J27" 55 85 20 0 15.327 10.768 15.072
+209 "J28" 55 10 20 0 32.457 38.971 42.15
+179 "J29" 10 85 20 0 31.401 19.157 15.756
+803 "J30" 0 10 20 20 51.767 52.562 36.611
+1274 "J31" 40 100 40 100 2.0691 1.6856 1.0061
+821 "J32" 40 10 20 20 31.147 35.136 32.826
+776 "J33" 10 70 10 20 26.657 18.779 17.602
+1120 "K1" 100 100 20 60 2.7153 2.3352 3.7231
+1161 "K2" 70 0 70 60 5.2448 7.7346 3.9283
+1110 "K3" 40 100 20 60 5.3374 3.4243 3.4798
+1151 "K4" 20 0 70 60 11.544 13.308 4.2438
+1100 "K5" 0 100 20 60 8.2906 4.8151 3.5443
+721 "K6" 100 0 100 0 8.1076 18.912 5.7582
+63 "K7" 70 100 0 0 10.674 6.4968 15.82
+685 "K8" 40 0 100 0 36.515 45.894 5.8715
+27 "K9" 20 100 0 0 25.023 13.172 15.983
+649 "K10" 0 0 100 0 67.831 73.183 6.3566
+397 "K11" 100 0 40 0 12.306 22.492 28.548
+387 "K12" 70 100 40 0 9.5791 6.4536 8.6392
+361 "K13" 40 0 40 0 42.364 51.362 33.35
+351 "K14" 20 100 40 0 23.924 13.131 8.6622
+325 "K15" 0 0 40 0 74.951 79.955 36.787
+73 "K16" 100 0 0 0 17.316 25.666 56.941
+711 "K17" 70 100 100 0 8.1065 6.0234 2.3028
+37 "K18" 40 0 0 0 48.74 55.767 67.464
+675 "K19" 20 100 100 0 22.791 12.85 2.2624
+1367 "K20" 0 0 0 0 83.532 86.556 75.658
+1170 "K21" 100 100 70 60 2.2415 2.1937 1.767
+1111 "K22" 70 0 20 60 6.7365 8.9202 10.488
+1160 "K23" 40 100 70 60 4.9604 3.4503 1.6823
+1101 "K24" 20 0 20 60 13.925 15.376 12.153
+1150 "K25" 0 100 70 60 7.7356 4.82 1.7333
+1268 "K26" 100 100 0 100 1.586 1.3361 1.2371
+929 "K27" 40 10 100 20 25.041 30.091 4.2447
+1262 "K28" 0 100 0 100 2.3217 1.6655 1.0172
+916 "K29" 10 0 100 20 42.296 47.086 4.8745
+54 "K30" 55 100 0 0 14.16 8.1322 15.9
+614 "K31" 55 10 85 0 25.842 33.805 8.7239
+18 "K32" 10 100 0 0 28.671 14.852 16.045
+578 "K33" 10 10 85 0 55.572 59.114 9.4388
+3 "L1" 0 20 0 0 69.597 66.565 60.838
+673 "L2" 20 70 100 0 27.825 20.432 2.9018
+39 "L3" 40 20 0 0 40.572 42.615 53.944
+709 "L4" 70 70 100 0 10.2 10.073 3.0376
+75 "L5" 100 20 0 0 14.395 19.681 46.296
+1149 "L6" 0 70 70 60 8.9749 6.7909 2.3081
+1102 "L7" 20 20 20 60 12.058 12.309 10.166
+1159 "L8" 40 70 70 60 5.4431 4.5543 2.1995
+1112 "L9" 70 20 20 60 5.7816 6.99 8.7996
+1169 "L10" 100 70 70 60 2.3761 2.8104 2.2458
+327 "L11" 0 20 40 0 62.366 61.062 29.931
+349 "L12" 20 70 40 0 29.877 21.69 13.737
+363 "L13" 40 20 40 0 35.967 39.85 27.525
+385 "L14" 70 70 40 0 12.394 11.372 12.969
+399 "L15" 100 20 40 0 10.365 17.364 23.838
+1099 "L16" 0 70 20 60 10.103 7.3489 5.5678
+1152 "L17" 20 20 70 60 10.044 10.668 3.7279
+1109 "L18" 40 70 20 60 6.1706 4.8349 5.1079
+1162 "L19" 70 20 70 60 4.6655 6.2353 3.4497
+1119 "L20" 100 70 20 60 2.8528 2.9433 4.9122
+651 "L21" 0 20 100 0 56.365 55.495 5.0428
+25 "L22" 20 70 0 0 31.967 22.387 26.188
+687 "L23" 40 20 100 0 31.007 35.545 4.8234
+61 "L24" 70 70 0 0 14.307 11.92 24.622
+723 "L25" 100 20 100 0 6.9585 14.721 5.1854
+170 "L26" 0 85 20 0 35.618 21.393 16.061
+598 "L27" 30 30 85 0 34.305 35.444 7.2538
+206 "L28" 40 85 20 0 19.826 13.094 15.005
+634 "L29" 85 30 85 0 10.637 16.574 7.1922
+739 "L30" 10 40 0 20 36.361 31.929 32.553
+923 "L31" 20 10 100 20 34.532 38.16 4.3913
+1264 "L32" 40 40 0 100 3.025 2.9233 2.7653
+941 "L33" 100 10 100 20 5.8796 12.705 4.4488
+725 "M1" 100 40 100 0 5.6657 10.768 4.437
+59 "M2" 70 40 0 0 19.82 20.835 38.153
+689 "M3" 40 40 100 0 25.449 25.81 3.9199
+23 "M4" 20 40 0 0 43.988 39.086 43.242
+653 "M5" 0 40 100 0 46.826 40.833 4.0776
+401 "M6" 100 40 40 0 8.508 12.792 19.04
+383 "M7" 70 40 40 0 15.911 18.715 19.337
+365 "M8" 40 40 40 0 28.9 28.624 21.058
+347 "M9" 20 40 40 0 39.477 36.198 21.787
+329 "M10" 0 40 40 0 51.464 44.787 23.357
+1118 "M11" 100 40 20 60 3.2583 4.1229 6.8222
+1163 "M12" 70 40 70 60 4.1138 4.892 2.905
+1108 "M13" 40 40 20 60 7.7936 7.5097 7.7076
+1153 "M14" 20 40 70 60 8.5393 8.172 3.0297
+1098 "M15" 0 40 20 60 12.826 11.415 8.5245
+77 "M16" 100 40 0 0 11.697 14.469 36.691
+707 "M17" 70 40 100 0 13.879 17.302 4.1153
+41 "M18" 40 40 0 0 32.737 30.791 41.385
+671 "M19" 20 40 100 0 36.014 33.591 3.9651
+5 "M20" 0 40 0 0 56.387 48.115 45.856
+1168 "M21" 100 40 70 60 2.5594 3.7583 2.8973
+1113 "M22" 70 40 20 60 4.8984 5.29 7.0265
+1158 "M23" 40 40 70 60 6.4157 6.5513 2.9637
+1103 "M24" 20 40 20 60 10.233 9.4169 8.1469
+1148 "M25" 0 40 70 60 10.845 9.911 3.1434
+1266 "M26" 100 0 0 100 1.2487 1.6429 2.2918
+1281 "M27" 40 0 100 100 1.9438 2.3714 0.98627
+1260 "M28" 0 0 0 100 2.6842 2.7971 2.1442
+919 "M29" 10 40 100 20 30.294 27.803 3.3279
+231 "M30" 85 55 20 0 11.711 12.702 22.558
+618 "M31" 55 55 85 0 17.046 16.86 5.3492
+195 "M32" 30 55 20 0 30.939 25.813 24.749
+582 "M33" 10 55 85 0 36.867 29.737 5.4828
+7 "N1" 0 70 0 0 41.064 27.7 27.285
+669 "N2" 20 20 100 0 43.633 45.789 4.9326
+43 "N3" 40 70 0 0 23.633 17.469 25.317
+705 "N4" 70 20 100 0 16.392 23.335 4.9379
+79 "N5" 100 70 0 0 8.126 7.9858 23.641
+1147 "N6" 0 20 70 60 12.587 12.713 3.8151
+1104 "N7" 20 70 20 60 8.0904 6.0557 5.3789
+1157 "N8" 40 20 70 60 7.5476 8.6054 3.5775
+1114 "N9" 70 70 20 60 4.1371 3.6437 4.9376
+1167 "N10" 100 20 70 60 2.7694 4.6386 3.3816
+331 "N11" 0 70 40 0 38.555 26.426 14.048
+345 "N12" 20 20 40 0 48.9 50.47 29.029
+367 "N13" 40 70 40 0 21.346 16.675 13.201
+381 "N14" 70 20 40 0 20.214 26.349 24.972
+403 "N15" 100 70 40 0 6.3393 7.4821 12.814
+1097 "N16" 0 20 20 60 15.268 14.982 10.814
+1154 "N17" 20 70 70 60 7.1701 5.6409 2.2541
+1107 "N18" 40 20 20 60 9.4122 10.149 9.7345
+1164 "N19" 70 70 70 60 3.633 3.517 2.2485
+1117 "N20" 100 20 20 60 3.6367 5.1854 8.293
+655 "N21" 0 70 100 0 36.241 25.005 2.8668
+21 "N22" 20 20 0 0 54.93 54.652 57.434
+691 "N23" 40 70 100 0 19.499 15.579 2.9145
+57 "N24" 70 20 0 0 24.704 28.996 49.5
+727 "N25" 100 70 100 0 4.5299 6.5549 3.3469
+166 "N26" 0 30 20 0 59.495 54.521 39.124
+602 "N27" 30 85 85 0 21.419 14.317 3.7354
+202 "N28" 40 30 20 0 34.441 35.391 35.145
+638 "N29" 85 85 85 0 6.544 6.5053 3.8482
+767 "N30" 0 10 10 20 52.858 53.287 42.421
+1279 "N31" 0 40 100 100 2.5356 2.5301 0.93376
+785 "N32" 40 10 10 20 32.161 35.818 38.145
+1285 "N33" 100 40 100 100 1.3834 1.7214 0.9272
+1116 "O1" 100 0 20 60 4.0233 6.3135 9.7349
+1165 "O2" 70 100 70 60 3.3702 2.7166 1.7203
+1106 "O3" 40 0 20 60 10.885 12.753 11.594
+1155 "O4" 20 100 70 60 6.3144 4.1045 1.6767
+1096 "O5" 0 0 20 60 17.552 18.567 13.037
+729 "O6" 100 100 100 0 3.664 3.8734 2.2561
+55 "O7" 70 0 0 0 30.004 38.132 61.496
+693 "O8" 40 100 100 0 15.807 9.6095 2.2784
+19 "O9" 20 0 0 0 66.155 71.475 71.889
+657 "O10" 0 100 100 0 30.384 16.417 2.1357
+1166 "O11" 100 0 70 60 2.9468 5.4992 3.8083
+1115 "O12" 70 100 20 60 3.6881 2.6925 3.5312
+1156 "O13" 40 0 70 60 8.7063 10.81 4.1087
+1105 "O14" 20 100 20 60 6.8185 4.1293 3.5251
+1146 "O15" 0 0 70 60 14.463 15.773 4.3803
+405 "O16" 100 100 40 0 4.8934 4.227 8.7463
+379 "O17" 70 0 40 0 24.306 34.442 30.471
+369 "O18" 40 100 40 0 17.036 9.9095 8.4951
+343 "O19" 20 0 40 0 57.937 65.282 35.342
+333 "O20" 0 100 40 0 31.525 16.713 8.6926
+81 "O21" 100 100 0 0 5.9847 4.2869 15.899
+703 "O22" 70 0 100 0 19.672 30.335 5.7155
+45 "O23" 40 100 0 0 18.459 10.135 16.046
+667 "O24" 20 0 100 0 51.529 59.137 6.0021
+9 "O25" 0 100 0 0 32.54 16.641 16.24
+755 "O26" 70 10 0 20 20.246 24.805 40.149
+1283 "O27" 40 100 100 100 2.1248 1.9121 0.8517
+743 "O28" 20 10 0 20 43.426 45.187 46.138
+921 "O29" 10 100 100 20 19.493 11.05 1.9553
+227 "O30" 85 10 20 0 18.576 26.246 38.785
+702 "O31" 55 100 100 0 11.506 7.6255 2.2956
+191 "O32" 30 10 20 0 49.042 53.595 46.035
+666 "O33" 10 100 100 0 26.519 14.59 2.2261
+72 "P1" 85 100 0 0 8.1029 5.2979 15.827
+340 "P2" 10 70 40 0 34.272 24.137 13.968
+483 "P3" 100 55 55 0 6.5506 9.3542 11.193
+1047 "P4" 0 20 100 40 24.607 24.742 2.8903
+966 "P5" 100 0 0 40 7.8864 11.734 24.621
+1041 "P6" 100 0 70 40 4.9885 9.9939 6.791
+972 "P7" 0 20 20 40 29.603 28.971 20.875
+1043 "P8" 100 40 70 40 3.8205 6.1544 4.8109
+332 "P9" 0 85 40 0 34.717 21.033 11.097
+153 "P10" 85 100 10 0 7.7939 5.3137 13.803
+1020 "P11" 100 100 40 40 3.1018 2.7833 4.3737
+341 "P12" 10 85 40 0 30.755 19.063 11.102
+645 "P13" 100 55 85 0 5.452 8.6712 5.5797
+337 "P14" 10 30 40 0 50.294 47.764 25.922
+1016 "P15" 100 0 40 40 6.031 10.716 12.899
+975 "P16" 0 100 20 40 14.692 8.0191 6.1097
+1026 "P17" 20 0 70 40 23.972 27.505 7.9233
+985 "P18" 40 100 20 40 8.8642 5.2767 5.9276
+1036 "P19" 70 0 70 40 10.213 15.128 7.1568
+995 "P20" 100 100 20 40 3.4196 2.8206 6.1531
+839 "P21" 0 10 40 20 48.941 50.379 24.983
+413 "P22" 0 85 55 0 34.221 20.855 7.9812
+857 "P23" 40 10 40 20 28.681 33.245 22.467
+449 "P24" 40 85 55 0 18.641 12.797 7.6507
+869 "P25" 100 10 40 20 8.6715 14.974 19.269
+504 "P26" 10 100 70 0 27.004 14.761 4.3751
+1403 "P27" 20 12 12 100 2.3544 2.4509 1.8872
+540 "P28" 55 100 70 0 12.158 7.8497 4.4409
+137 "P29" 70 10 10 0 25.806 32.587 47.472
+585 "P30" 10 100 85 0 26.788 14.692 3.1709
+190 "P31" 30 0 20 0 53.459 60.877 50.898
+621 "P32" 55 100 85 0 11.844 7.745 3.2349
+226 "P33" 85 0 20 0 20.45 29.973 42.588
+388 "Q1" 85 0 40 0 17.714 28.071 29.4
+354 "Q2" 30 20 40 0 42.187 45.057 28.305
+392 "Q3" 85 40 40 0 11.752 15.464 19.015
+954 "Q4" 20 70 0 40 15.189 11.028 12.597
+1065 "Q5" 70 100 100 40 4.8713 3.7963 1.602
+990 "Q6" 70 100 20 40 5.5746 3.7845 5.993
+1029 "Q7" 20 70 70 40 13.561 10.362 3.7644
+988 "Q8" 70 40 20 40 9.1547 10.107 13.621
+346 "Q9" 20 30 40 0 44.17 43.164 25.365
+380 "Q10" 70 10 40 0 22.221 30.224 27.687
+1011 "Q11" 70 0 40 40 11.281 15.853 13.82
+355 "Q12" 30 30 40 0 38.083 38.522 24.763
+393 "Q13" 85 55 40 0 10.347 12.121 15.787
+359 "Q14" 30 85 40 0 22.653 14.886 10.796
+1015 "Q15" 70 100 40 40 5.2597 3.798 4.3099
+1044 "Q16" 100 70 70 40 3.254 4.0928 3.564
+987 "Q17" 70 20 20 40 11.085 13.59 17.234
+1034 "Q18" 40 70 70 40 9.9768 8.179 3.6375
+977 "Q19" 20 20 20 40 23.514 24.033 19.687
+1024 "Q20" 0 70 70 40 17.151 12.502 3.8006
+461 "Q21" 70 10 55 0 20.669 29.041 19.486
+447 "Q22" 40 55 55 0 24.03 21.485 11.773
+425 "Q23" 20 10 55 0 51.206 55.742 22.11
+411 "Q24" 0 55 55 0 43.461 33.955 12.825
+844 "Q25" 10 0 40 20 47.596 52.102 27.007
+637 "Q26" 85 70 85 0 7.3644 8.3584 4.5689
+129 "Q27" 55 20 10 0 30.721 34.726 44.429
+601 "Q28" 30 70 85 0 23.755 18.069 4.3796
+1398 "Q29" 10 6 6 80 7.0105 7.296 6.1388
+629 "Q30" 70 85 85 0 9.3822 8 3.8025
+130 "Q31" 55 30 10 0 27.711 29.708 39.164
+593 "Q32" 20 85 85 0 25.359 16.384 3.7822
+94 "Q33" 10 30 10 0 54.468 50.787 44.521
+36 "R1" 30 100 0 0 21.556 11.576 16.017
+376 "R2" 55 70 40 0 16.504 13.853 13.09
+374 "R3" 55 40 40 0 22.024 23.501 20.533
+1057 "R4" 40 20 100 40 13.816 15.962 2.8108
+956 "R5" 40 0 0 40 22.126 25.279 29.614
+1031 "R6" 40 0 70 40 17.712 21.988 7.536
+982 "R7" 40 20 20 40 17.794 19.295 18.567
+1033 "R8" 40 40 70 40 12.562 12.837 5.1282
+368 "R9" 40 85 40 0 19.001 12.943 10.645
+603 "R10" 30 100 85 0 19.457 11.28 3.1632
+1010 "R11" 40 100 40 40 8.5279 5.2899 4.3262
+377 "R12" 55 85 40 0 14.612 10.65 10.619
+375 "R13" 55 55 40 0 18.962 18.108 16.309
+373 "R14" 55 30 40 0 24.694 27.954 23.328
+1006 "R15" 40 0 40 40 18.948 22.947 15.201
+973 "R16" 0 40 20 40 24.664 21.767 16.297
+1028 "R17" 20 40 70 40 17.171 16.287 5.3583
+983 "R18" 40 40 20 40 14.701 14.35 14.562
+1038 "R19" 70 40 70 40 7.3528 8.9015 4.9868
+993 "R20" 100 40 20 40 5.1831 6.9074 12.774
+846 "R21" 10 20 40 20 40.547 40.963 22.243
+409 "R22" 0 30 55 0 54.926 51.085 18.191
+427 "R23" 20 30 55 0 42.488 41.9 17.571
+445 "R24" 40 30 55 0 31.051 33.066 16.879
+463 "R25" 70 30 55 0 17.193 21.865 15.919
+581 "R26" 10 40 85 0 42.195 38.09 6.6443
+105 "R27" 20 55 10 0 36.68 29.43 29.303
+617 "R28" 55 40 85 0 19.79 21.875 6.4114
+141 "R29" 70 55 10 0 16.099 15.606 26.608
+573 "R30" 0 55 85 0 41.699 32.615 5.5737
+194 "R31" 30 40 20 0 36.038 33.681 31.325
+609 "R32" 40 55 85 0 22.77 20.607 5.3262
+1401 "R33" 60 45 45 100 1.7812 1.8318 1.268
+352 "S1" 30 0 40 0 49.662 57.958 34.147
+390 "S2" 85 20 40 0 14.827 21.597 24.334
+356 "S3" 30 40 40 0 33.95 32.236 21.274
+964 "S4" 70 70 0 40 7.5493 6.3917 11.819
+1055 "S5" 20 100 100 40 10.959 6.6601 1.5403
+980 "S6" 20 100 20 40 11.707 6.6171 6.0027
+1039 "S7" 70 70 70 40 6.0395 5.8289 3.6118
+978 "S8" 20 40 20 40 19.514 17.974 15.42
+382 "S9" 70 30 40 0 18.083 22.458 22.119
+344 "S10" 20 10 40 0 53.406 57.674 32.389
+1001 "S11" 20 0 40 40 25.382 28.644 16.04
+391 "S12" 85 30 40 0 13.302 18.459 21.66
+357 "S13" 30 55 40 0 29.224 24.877 17.005
+395 "S14" 85 85 40 0 7.9931 7.0878 10.595
+1005 "S15" 20 100 40 40 11.468 6.6943 4.4176
+724 "S16" 100 30 100 0 6.3165 12.701 4.8035
+475 "S17" 85 70 55 0 8.3754 8.8787 9.2435
+453 "S18" 55 20 55 0 25.734 31.381 18.381
+439 "S19" 30 70 55 0 24.743 18.69 9.4446
+417 "S20" 10 20 55 0 53.632 54.204 20.345
+969 "S21" 100 70 0 40 4.4711 4.4108 11.353
+1062 "S22" 70 20 100 40 7.8759 11.047 2.8479
+959 "S23" 40 70 0 40 11.581 8.7901 12.166
+1052 "S24" 20 20 100 40 19.245 20.452 2.8827
+949 "S25" 0 70 0 40 18.935 13.249 13.033
+633 "S26" 85 20 85 0 11.655 19.202 7.8973
+133 "S27" 55 70 10 0 17.99 14.262 21.622
+597 "S28" 30 20 85 0 37.726 41.19 8.1607
+97 "S29" 10 70 10 0 35.88 24.704 23.163
+625 "S30" 70 30 85 0 15.417 20.507 7.1937
+134 "S31" 55 85 10 0 15.742 10.852 17.356
+589 "S32" 20 30 85 0 40.348 40.08 7.3947
+98 "S33" 10 85 10 0 31.817 19.291 18.193
+741 "T1" 10 100 0 20 20.92 11.046 11.999
+485 "T2" 100 85 55 0 5.0324 5.4618 7.6477
+338 "T3" 10 40 40 0 45.243 40.342 22.51
+1067 "T4" 100 20 100 40 3.8495 7.4907 2.9603
+946 "T5" 0 0 0 40 36.398 37.862 33.394
+1021 "T6" 0 0 70 40 30.347 32.944 8.1709
+992 "T7" 100 20 20 40 6.1477 9.1347 15.967
+1023 "T8" 0 40 70 40 21.896 19.753 5.4679
+566 "T9" 100 85 70 0 4.5612 5.2604 5.3847
+777 "T10" 10 100 10 20 20.725 11.051 10.533
+1000 "T11" 0 100 40 40 14.375 8.0539 4.4273
+647 "T12" 100 85 85 0 4.2488 5.1601 3.9195
+339 "T13" 10 55 40 0 39.423 31.475 17.861
+643 "T14" 100 30 85 0 6.846 13.168 7.2542
+996 "T15" 0 0 40 40 31.718 34.029 16.657
+415 "T16" 10 0 55 0 63.997 70.524 24.637
+261 "T17" 10 100 30 0 27.879 14.844 10.292
+451 "T18" 55 0 55 0 30.669 40.701 22.033
+297 "T19" 55 100 30 0 13.148 8 10.121
+146 "T20" 85 10 10 0 19.783 26.989 45.684
+1050 "T21" 0 100 100 40 13.872 8.1063 1.6531
+951 "T22" 20 0 0 40 29.196 31.595 31.502
+1060 "T23" 40 100 100 40 8.0648 5.252 1.5254
+961 "T24" 70 0 0 40 13.926 17.677 27.023
+1070 "T25" 100 100 100 40 2.6364 2.7274 1.6146
+577 "T26" 10 0 85 0 60.79 67.419 10.52
+522 "T27" 30 100 70 0 19.696 11.34 4.3352
+613 "T28" 55 0 85 0 28.109 38.325 9.5404
+1400 "T29" 80 65 65 100 1.6643 1.6892 1.0143
+569 "T30" 0 10 85 0 62.99 65.129 9.7311
+117 "T31" 30 100 10 0 21.029 11.408 13.717
+605 "T32" 40 10 85 0 34.556 41.383 8.8728
+80 "T33" 100 85 0 0 6.9675 5.9349 19.448
+772 "U1" 10 0 10 20 52.057 55.554 45.831
+773 "U2" 10 10 10 20 47.759 49.162 41.538
+1399 "U3" 100 85 85 100 1.6187 1.6394 0.89845
+737 "U4" 10 10 0 20 48.784 49.713 47.296
+1408 "U5" 100 100 0 70 2.3691 1.9568 3.3718
+1409 "U6" 100 0 100 70 2.199 4.0799 1.855
+1410 "U7" 0 100 100 70 5.5848 3.7343 1.077
+1411 "U8" 40 40 0 70 5.7934 5.5192 6.6041
+1412 "U9" 40 0 40 70 6.7115 8.06 5.5183
+1413 "U10" 0 40 40 70 7.6432 6.9353 3.875
+940 "U11" 100 0 100 20 6.04 13.773 4.7479
+759 "U12" 70 100 0 20 8.2981 5.199 11.988
+928 "U13" 40 0 100 20 26.943 33.718 4.5748
+747 "U14" 20 100 0 20 18.477 9.8932 11.977
+910 "U15" 0 0 100 20 47.123 51.088 4.9814
+917 "U16" 10 10 100 20 39.259 42.042 4.485
+881 "U17" 10 10 70 20 41.368 44.128 11.608
+1211 "U18" 100 100 0 80 2.0214 1.6659 2.424
+672 "U19" 20 55 100 0 31.603 26.297 3.3949
+26 "U20" 20 85 0 0 28.234 17.308 20.611
+717 "U21" 85 55 100 0 8.0848 10.71 3.7004
+1227 "U22" 100 100 40 80 2.0471 1.8756 1.7224
+510 "U23" 20 55 70 0 32.554 27.054 8.1303
+269 "U24" 20 85 30 0 26.943 16.945 13.047
+555 "U25" 85 55 70 0 9.0366 11.316 7.9158
+396 "U26" 85 100 40 0 7.0104 5.2661 8.714
+290 "U27" 55 10 30 0 31.15 38.101 34.962
+360 "U28" 30 100 40 0 20.282 11.426 8.5811
+254 "U29" 10 10 30 0 62.704 65.312 40.658
+477 "U30" 85 100 55 0 6.5143 5.1384 6.2913
+47 "U31" 55 10 0 0 34.846 40.287 57.695
+441 "U32" 30 100 55 0 20.015 11.407 6.151
+11 "U33" 10 10 0 0 68.278 69.374 66.073
+1429 "V1" 7 0 0 7 70.46 73.92 67.261
+1404 "V2" 10 6 6 100 2.5919 2.6833 2.038
+1431 "V3" 7 7 0 7 66.447 68.034 62.702
+1390 "V4" 40 27 27 60 8.7749 9.2534 8.0212
+1433 "V5" 7 0 7 7 69.32 73.145 61.541
+1386 "V6" 10 6 6 40 30.82 32.145 28.568
+1435 "V7" 7 7 7 7 65.491 67.488 57.736
+1405 "V8" 100 0 0 70 3.3139 4.757 8.8718
+1406 "V9" 0 100 0 70 5.8208 3.4664 3.0148
+1407 "V10" 0 0 100 70 9.7971 10.768 1.8949
+732 "V11" 0 20 0 20 49.803 47.82 43.811
+926 "V12" 20 70 100 20 20.873 15.756 2.4785
+750 "V13" 40 20 0 20 30.145 31.768 39.381
+938 "V14" 70 70 100 20 8.5654 8.4502 2.5669
+762 "V15" 100 20 0 20 10.566 14.545 33.543
+736 "V16" 10 0 0 20 53.253 56.303 52.493
+811 "V17" 10 40 20 20 35.05 31.312 24.766
+14 "V18" 10 40 0 0 50.032 43.488 44.395
+688 "V19" 40 30 100 0 28.329 30.701 4.3862
+1206 "V20" 70 70 0 80 2.8994 2.5411 3.343
+1245 "V21" 0 40 100 80 5.6651 5.3425 1.396
+257 "V22" 10 40 30 0 46.555 41.32 27.521
+526 "V23" 40 30 70 0 29.655 31.955 11.194
+1222 "V24" 70 70 40 80 2.7614 2.6125 2.2024
+1229 "V25" 0 40 70 80 5.6798 5.2963 1.9558
+503 "V26" 10 85 70 0 29.757 18.637 5.4744
+274 "V27" 30 30 30 0 39.358 39.499 30.446
+1239 "V28" 70 100 70 80 2.5641 2.2416 1.3396
+1225 "V29" 100 40 40 80 2.1514 2.6607 2.8621
+665 "V30" 10 85 100 0 29.156 18.326 2.5466
+31 "V31" 30 30 0 0 42.828 41.521 48.982
+1255 "V32" 70 100 100 80 2.6193 2.3714 1.1818
+1209 "V33" 100 40 0 80 2.2087 2.5172 4.2884
+1480 "W1" 40 40 3 40 15.491 14.783 18.578
+1481 "W2" 3 0 40 40 30.835 33.282 16.572
+1482 "W3" 0 3 40 40 31.096 33.009 16.254
+1483 "W4" 3 3 40 40 30.215 32.277 16.188
+1484 "W5" 40 3 40 40 18.485 22.123 14.796
+1485 "W6" 3 40 40 40 22.306 19.937 10.964
+1425 "W7" 7 7 0 0 72.916 74.562 68.933
+1426 "W8" 7 0 7 0 76.125 80.385 67.437
+1368 "W9" 100 85 85 0 4.2488 5.1601 3.9195
+1428 "W10" 7 7 7 0 71.61 73.677 62.845
+943 "W11" 100 40 100 20 4.7403 8.5831 3.5312
+757 "W12" 70 40 0 20 15.154 16.041 28.325
+931 "W13" 40 40 100 20 19.538 20.131 3.252
+745 "W14" 20 40 0 20 32.397 29.093 31.919
+913 "W15" 0 40 100 20 33.852 30.15 3.3353
+882 "W16" 10 20 70 20 38.037 38.894 10.534
+880 "W17" 10 0 70 20 44.871 49.726 12.722
+67 "W18" 85 30 0 0 17.178 20.552 42.38
+1248 "W19" 40 0 100 80 4.5413 5.658 1.6254
+30 "W20" 30 20 0 0 47.48 48.506 55.784
+713 "W21" 85 10 100 0 12.311 21.57 5.442
+310 "W22" 85 30 30 0 14.221 19.029 26.141
+1232 "W23" 40 0 70 80 4.7088 5.7638 2.5301
+273 "W24" 30 20 30 0 43.523 46.036 34.48
+551 "W25" 85 10 70 0 13.518 22.62 12.816
+1226 "W26" 100 70 40 80 2.1369 2.2414 2.227
+517 "W27" 30 30 70 0 35.091 36.183 11.185
+276 "W28" 30 55 30 0 30.089 25.385 20.636
+1241 "W29" 100 40 70 80 2.0726 2.6889 1.9514
+1210 "W30" 100 70 0 80 2.1361 2.0453 3.268
+679 "W31" 30 30 100 0 33.743 34.869 4.3993
+33 "W32" 30 55 0 0 32.472 26.538 33.225
+1257 "W33" 100 40 100 80 2.0186 2.7006 1.4305
+1418 "X1" 3 0 0 3 78.087 81.304 72.192
+1471 "X2" 3 40 0 40 24.528 21.469 20.832
+1416 "X3" 0 3 3 0 80.718 82.931 70.76
+1473 "X4" 3 0 3 40 35.081 36.717 31.93
+1474 "X5" 40 0 3 40 21.975 25.198 28.589
+1450 "X6" 0 40 0 3 54.231 46.336 44.17
+1402 "X7" 40 27 27 100 1.9928 2.0843 1.578
+1451 "X8" 3 40 0 3 52.764 45.324 43.924
+1478 "X9" 0 40 3 40 25.167 21.969 20.329
+1479 "X10" 3 40 3 40 24.43 21.434 20.192
+238 "X11" 100 30 20 0 10.953 15.845 30.175
+114 "X12" 30 55 10 0 31.677 26.184 28.689
+607 "X13" 40 30 85 0 28.89 31.247 7.2553
+726 "X14" 100 55 100 0 5.0689 8.4682 3.8849
+571 "X15" 0 30 85 0 52.284 48.719 7.5835
+797 "X16" 100 10 10 20 10.649 16.035 32.114
+885 "X17" 10 100 70 20 19.827 11.129 3.648
+10 "X18" 10 0 0 0 75.117 79.325 73.888
+296 "X19" 55 85 30 0 14.958 10.704 12.697
+38 "X20" 40 10 0 0 44.525 48.85 60.426
+259 "X21" 10 70 30 0 34.846 24.357 16.865
+496 "X22" 10 0 70 0 61.985 68.656 16.253
+701 "X23" 55 85 100 0 12.855 9.8743 2.6087
+524 "X24" 40 10 70 0 35.387 42.195 13.842
+664 "X25" 10 70 100 0 32.058 22.77 2.9035
+499 "X26" 10 30 70 0 47.31 45.407 11.733
+278 "X27" 30 85 30 0 22.93 14.868 12.814
+535 "X28" 55 30 70 0 22.277 26.128 10.97
+314 "X29" 85 85 30 0 8.3629 7.174 12.667
+661 "X30" 10 30 100 0 45.626 43.799 4.5115
+35 "X31" 30 85 0 0 24.287 15.231 20.388
+697 "X32" 55 30 100 0 20.902 24.885 4.4299
+71 "X33" 85 85 0 0 9.4362 7.3338 19.684
+1455 "2A1" 0 40 3 3 53.993 46.223 42.661
+1461 "2A2" 0 3 40 3 70.383 74.295 34.724
+1448 "2A3" 40 0 0 3 47.195 53.953 64.998
+1449 "2A4" 40 3 0 3 46.112 52.161 63.209
+1464 "2A5" 0 40 40 3 49.506 43.168 22.613
+1465 "2A6" 3 40 40 3 48.143 42.244 22.502
+1419 "2A7" 0 3 0 3 78.35 80.439 70.76
+1467 "2A8" 3 0 0 40 35.38 36.979 33.117
+1468 "2A9" 0 3 0 40 35.504 36.593 32.45
+1469 "2A10" 3 3 0 40 34.505 35.714 32.02
+945 "2A11" 100 100 100 20 3.2509 3.4049 2.0486
+754 "2A12" 70 0 0 20 22.089 28.05 44.087
+933 "2A13" 40 100 100 20 12.377 7.6664 1.9719
+742 "2A14" 20 0 0 20 47.424 51.241 51.225
+915 "2A15" 0 100 100 20 21.691 12.124 1.9921
+884 "2A16" 10 70 70 20 24.384 17.733 5.538
+833 "2A17" 100 10 20 20 9.9756 15.72 27.732
+1259 "2A18" 100 100 100 80 2.113 2.1285 1.1794
+1200 "2A19" 40 0 0 80 5.5174 6.2971 6.7766
+674 "2A20" 20 85 100 0 25.196 16.32 2.5594
+65 "2A21" 85 10 0 0 21.358 27.932 53.463
+1243 "2A22" 100 100 70 80 2.0847 2.0389 1.3911
+1216 "2A23" 40 0 40 80 4.9677 5.9205 3.9901
+512 "2A24" 20 85 70 0 25.681 16.532 5.3409
+308 "2A25" 85 10 30 0 17.37 25.474 32.287
+1224 "2A26" 100 0 40 80 2.1836 3.3985 3.6401
+521 "2A27" 30 85 70 0 21.75 14.466 5.2726
+272 "2A28" 30 10 30 0 47.416 52.397 38.143
+557 "2A29" 85 85 70 0 6.8894 6.6312 5.3769
+1208 "2A30" 100 0 0 80 2.454 3.4793 5.9636
+683 "2A31" 30 85 100 0 21.18 14.225 2.5591
+29 "2A32" 30 10 0 0 52.057 55.456 62.416
+719 "2A33" 85 85 100 0 6.2798 6.3626 2.7033
+730 "2B1" 0 0 0 20 58.945 61.186 53.819
+927 "2B2" 20 100 100 20 17.147 9.9331 1.9505
+748 "2B3" 40 0 0 20 35.871 40.917 48.425
+939 "2B4" 70 100 100 20 6.9229 5.146 2.0433
+760 "2B5" 100 0 0 20 12.282 18.294 40.046
+879 "2B6" 0 100 70 20 22.293 12.288 3.6598
+778 "2B7" 20 0 10 20 46.281 50.535 44.514
+897 "2B8" 40 100 70 20 12.747 7.7894 3.6629
+790 "2B9" 70 0 10 20 21.117 27.534 38.328
+909 "2B10" 100 100 70 20 3.5374 3.4661 3.6518
+802 "2B11" 0 0 20 20 56.601 59.66 40.624
+855 "2B12" 20 100 40 20 17.914 10.071 6.8185
+820 "2B13" 40 0 20 20 33.673 39.499 36.055
+867 "2B14" 70 100 40 20 7.6254 5.2461 6.6314
+832 "2B15" 100 0 20 20 10.812 17.701 30.133
+808 "2B16" 10 0 20 20 50.801 54.679 39.587
+809 "2B17" 10 10 20 20 46.797 48.543 36.027
+662 "2B18" 10 40 100 0 41.429 37.335 4.0161
+40 "2B19" 40 30 0 0 36.619 36.559 47.537
+1254 "2B20" 70 70 100 80 2.5715 2.5962 1.2142
+1197 "2B21" 0 40 0 80 6.4426 5.6762 4.9924
+500 "2B22" 10 40 70 0 42.89 38.711 10.283
+283 "2B23" 40 30 30 0 33.8 35.223 30.04
+1238 "2B24" 70 70 70 80 2.634 2.5979 1.5788
+1213 "2B25" 0 40 40 80 5.8329 5.3275 2.9845
+494 "2B26" 0 85 70 0 33.767 20.676 5.531
+1220 "2B27" 70 0 40 80 3.3832 4.5369 3.8556
+530 "2B28" 40 85 70 0 18.281 12.652 5.3328
+245 "2B29" 0 10 30 0 70.09 71.322 41.218
+656 "2B30" 0 85 100 0 33.072 20.292 2.4698
+1204 "2B31" 70 0 0 80 3.7611 4.7312 6.4057
+692 "2B32" 40 85 100 0 17.532 12.31 2.5727
+2 "2B33" 0 10 0 0 76.386 76.234 68.218
+942 "2C1" 100 20 100 20 5.5861 11.454 4.1569
+758 "2C2" 70 70 0 20 11.215 9.5001 18.543
+930 "2C3" 40 20 100 20 23.258 26.76 3.9332
+746 "2C4" 20 70 0 20 23.84 17.025 19.697
+912 "2C5" 0 20 100 20 40.492 40.409 4.1293
+157 "2C6" 100 30 10 0 11.881 16.348 35.184
+599 "2C7" 30 40 85 0 31.083 30.156 6.447
+121 "2C8" 40 30 10 0 35.412 35.905 40.726
+635 "2C9" 85 40 85 0 9.8396 14.293 6.4971
+85 "2C10" 0 30 10 0 60.945 55.586 45.669
+870 "2C11" 100 20 40 20 7.9757 13.201 17.586
+830 "2C12" 70 70 20 20 10.44 9.2485 14.123
+858 "2C13" 40 20 40 20 26.608 29.542 20.401
+818 "2C14" 20 70 20 20 23.192 16.881 15.065
+840 "2C15" 0 20 40 20 44.975 44.4 22.596
+883 "2C16" 10 40 70 20 31.53 28.832 8.2102
+761 "2C17" 100 10 0 20 11.442 16.401 36.797
+715 "2C18" 85 30 100 0 10.092 16.111 4.6429
+24 "2C19" 20 55 0 0 37.446 29.749 33.815
+678 "2C20" 30 20 100 0 37.103 40.577 4.8694
+69 "2C21" 85 55 0 0 12.993 13.191 30.047
+553 "2C22" 85 30 70 0 11.284 17.084 10.6
+267 "2C23" 20 55 30 0 35.127 28.689 21.218
+516 "2C24" 30 20 70 0 38.702 42.133 12.782
+312 "2C25" 85 55 30 0 11.038 12.408 18.913
+303 "2C26" 70 55 30 0 14.846 15.086 19.26
+508 "2C27" 20 30 70 0 41.217 40.898 11.519
+1218 "2C28" 40 70 40 80 3.6659 3.1681 2.2246
+544 "2C29" 70 30 70 0 16.099 21.105 10.782
+60 "2C30" 70 55 0 0 16.76 15.817 30.664
+670 "2C31" 20 30 100 0 39.738 39.469 4.4475
+1202 "2C32" 40 70 0 80 3.7763 3.0477 3.2991
+706 "2C33" 70 30 100 0 14.854 19.997 4.5073
+733 "2D1" 0 40 0 20 40.233 34.647 33.129
+925 "2D2" 20 40 100 20 26.655 25.285 3.2995
+751 "2D3" 40 40 0 20 24.262 23.011 30.235
+937 "2D4" 70 40 100 20 11.121 13.778 3.3001
+763 "2D5" 100 40 0 20 8.6134 10.69 26.448
+877 "2D6" 0 40 70 20 35.215 31.352 8.2469
+781 "2D7" 20 40 10 20 31.798 28.893 27.848
+895 "2D8" 40 40 70 20 20.565 20.969 7.8714
+793 "2D9" 70 40 10 20 14.627 15.876 24.736
+907 "2D10" 100 40 70 20 5.376 8.9832 7.2014
+242 "2D11" 100 85 20 0 6.248 5.8322 14.826
+110 "2D12" 30 10 10 0 50.445 54.511 53.557
+611 "2D13" 40 85 85 0 17.915 12.48 3.772
+722 "2D14" 100 10 100 0 7.5407 16.73 5.5048
+575 "2D15" 0 85 85 0 33.454 20.538 3.8382
+845 "2D16" 10 10 40 20 44.143 46.488 24.678
+812 "2D17" 10 70 20 20 26.183 18.591 15.339
+658 "2D18" 10 0 100 0 59.555 66.059 6.1393
+539 "2D19" 55 85 70 0 13.564 10.195 5.3184
+686 "2D20" 40 10 100 0 33.715 40.512 5.2951
+502 "2D21" 10 70 70 0 32.955 23.401 6.7685
+253 "2D22" 10 0 30 0 68.467 74.301 44.913
+53 "2D23" 55 85 0 0 16.201 10.972 20.026
+281 "2D24" 40 10 30 0 40.297 46.19 36.753
+16 "2D25" 10 70 0 0 36.4 24.93 26.624
+490 "2D26" 0 30 70 0 53.301 49.669 11.829
+285 "2D27" 40 55 30 0 25.601 22.406 20.218
+1237 "2D28" 70 40 70 80 2.7354 3.1541 1.8793
+249 "2D29" 0 55 30 0 45.291 35.118 22.117
+652 "2D30" 0 30 100 0 51.46 47.868 4.5834
+42 "2D31" 40 55 0 0 27.794 23.398 32.575
+1253 "2D32" 70 40 100 80 2.6706 3.1448 1.3783
+6 "2D33" 0 55 0 0 47.429 36.04 35.201
+639 "2E1" 85 100 85 0 5.8308 4.9409 3.2424
+109 "2E2" 30 0 10 0 55.088 61.998 59.12
+619 "2E3" 55 70 85 0 14.749 12.807 4.4093
+145 "2E4" 85 0 10 0 21.862 30.879 50.22
+583 "2E5" 10 70 85 0 32.511 23.105 4.5305
+798 "2E6" 100 20 10 20 9.8389 14.217 29.27
+902 "2E7" 70 70 70 20 9.0284 8.6722 5.2487
+786 "2E8" 40 20 10 20 29.549 31.581 34.307
+890 "2E9" 20 70 70 20 21.516 16.127 5.5174
+768 "2E10" 0 20 10 20 48.723 47.131 38.268
+872 "2E11" 100 70 40 20 5.0542 5.875 9.601
+828 "2E12" 70 20 20 20 17.147 21.19 27.273
+860 "2E13" 40 70 40 20 16.588 13.074 10.285
+816 "2E14" 20 20 20 20 38.01 38.793 31.561
+842 "2E15" 0 70 40 20 28.249 19.899 10.893
+868 "2E16" 100 0 40 20 9.4045 16.878 20.882
+831 "2E17" 70 100 20 20 7.8989 5.178 9.1518
+856 "2E18" 40 0 40 20 30.615 36.969 24.493
+819 "2E19" 20 100 20 20 18.113 9.908 9.1732
+838 "2E20" 0 0 40 20 53.014 56.721 27.364
+801 "2E21" 100 100 10 20 4.5969 3.5817 10.626
+898 "2E22" 70 0 70 20 16.054 23.845 11.028
+789 "2E23" 40 100 10 20 13.563 7.6862 10.405
+886 "2E24" 20 0 70 20 39.398 45.005 12.506
+771 "2E25" 0 100 10 20 23.23 12.237 10.633
+299 "2E26" 70 10 30 0 23.504 31.165 33.504
+1235 "2E27" 40 100 70 80 3.3405 2.6353 1.3536
+263 "2E28" 20 10 30 0 55.035 58.89 39.483
+548 "2E29" 70 85 70 0 9.7363 8.1738 5.3342
+56 "2E30" 70 10 0 0 27.178 33.283 55.276
+1251 "2E31" 40 100 100 80 3.2688 2.647 1.118
+20 "2E32" 20 10 0 0 60.381 62.688 64.424
+710 "2E33" 70 85 100 0 9.063 7.8401 2.6433
+735 "2F1" 0 100 0 20 23.313 12.186 12.03
+922 "2F2" 20 0 100 20 37.207 42.764 4.7618
+753 "2F3" 40 100 0 20 13.706 7.6698 11.934
+934 "2F4" 70 0 100 20 14.805 22.592 4.5557
+765 "2F5" 100 100 0 20 4.7688 3.5633 11.941
+874 "2F6" 0 0 70 20 50.178 54.221 12.859
+783 "2F7" 20 100 10 20 18.29 9.8994 10.499
+892 "2F8" 40 0 70 20 28.936 35.683 11.763
+795 "2F9" 70 100 10 20 8.091 5.1913 10.527
+904 "2F10" 100 0 70 20 7.4692 15.345 10.452
+807 "2F11" 0 100 20 20 23.058 12.245 9.3329
+850 "2F12" 20 0 40 20 41.953 47.187 26.39
+825 "2F13" 40 100 20 20 13.401 7.6934 9.073
+862 "2F14" 70 0 40 20 18.366 25.704 22.551
+837 "2F15" 100 100 20 20 4.4115 3.5814 9.3364
+804 "2F16" 0 20 20 20 47.421 46.184 32.872
+854 "2F17" 20 70 40 20 22.348 16.488 10.687
+822 "2F18" 40 20 20 20 28.605 31.013 29.77
+866 "2F19" 70 70 40 20 9.6063 8.8285 9.7922
+834 "2F20" 100 20 20 20 9.1624 13.858 25.265
+878 "2F21" 0 70 70 20 27.083 19.177 5.4949
+780 "2F22" 20 20 10 20 39 39.419 36.308
+896 "2F23" 40 70 70 20 15.843 12.812 5.3519
+792 "2F24" 70 20 10 20 17.857 21.566 31.645
+908 "2F25" 100 70 70 20 4.2637 5.5352 5.0322
+1231 "2F26" 0 100 70 80 4.3827 3.0922 1.2778
+289 "2F27" 55 0 30 0 33.975 43.311 38.423
+538 "2F28" 55 70 70 0 15.19 13.094 6.4213
+1212 "2F29" 0 0 40 80 7.2398 7.7736 4.0923
+1247 "2F30" 0 100 100 80 4.4779 3.2461 1.1384
+46 "2F31" 55 0 0 0 37.906 45.689 64.134
+700 "2F32" 55 70 100 0 14.382 12.584 2.9632
+1196 "2F33" 0 0 0 80 7.5688 7.8937 6.6402
+495 "2G1" 0 100 70 0 30.696 16.461 4.3649
+241 "2G2" 100 70 20 0 7.204 7.7121 18.004
+491 "2G3" 0 40 70 0 48.486 42.462 10.329
+237 "2G4" 100 20 20 0 12.139 18.465 33.814
+487 "2G5" 0 0 70 0 70.296 75.801 16.829
+162 "2G6" 100 100 10 0 5.6757 4.2905 13.782
+622 "2G7" 70 0 85 0 20.256 30.935 9.2353
+126 "2G8" 40 100 10 0 17.864 9.9327 13.659
+586 "2G9" 20 0 85 0 52.677 60.378 10.16
+90 "2G10" 0 100 10 0 32.128 16.573 14.095
+1175 "2G11" 0 100 100 60 7.7461 4.8491 1.2043
+1094 "2G12" 100 70 0 60 3.1519 3.0872 6.637
+1173 "2G13" 0 40 100 60 11.279 10.35 1.7059
+1092 "2G14" 100 20 0 60 4.2429 5.682 11.587
+1171 "2G15" 0 0 100 60 14.598 16.021 2.3931
+871 "2G16" 100 40 40 20 6.5827 9.7411 14.016
+829 "2G17" 70 40 20 20 14.093 15.634 21.374
+859 "2G18" 40 40 40 20 21.865 21.791 15.941
+817 "2G19" 20 40 20 20 31.09 28.498 24.183
+841 "2G20" 0 40 40 20 36.833 32.49 17.453
+161 "2G21" 100 85 10 0 6.6047 5.9016 16.991
+595 "2G22" 30 0 85 0 44.655 53.316 9.9579
+125 "2G23" 40 85 10 0 20.256 13.207 17.412
+631 "2G24" 85 0 85 0 13.875 24.876 9.1828
+89 "2G25" 0 85 10 0 36.074 21.585 18.626
+311 "2G26" 85 40 30 0 12.707 16.067 22.975
+1233 "2G27" 40 40 70 80 3.8288 3.958 1.903
+275 "2G28" 30 40 30 0 34.956 32.941 26.009
+552 "2G29" 85 20 70 0 12.404 19.831 11.757
+68 "2G30" 85 40 0 0 15.401 17.409 37.286
+1249 "2G31" 40 40 100 80 3.7464 3.9131 1.3253
+32 "2G32" 30 40 0 0 38.119 34.792 42.301
+714 "2G33" 85 20 100 0 11.174 18.801 5.061
+181 "2H1" 20 0 20 0 62.098 68.564 52.696
+543 "2H2" 70 20 70 0 17.657 24.48 11.96
+185 "2H3" 20 40 20 0 41.807 37.848 32.114
+547 "2H4" 70 70 70 0 10.995 10.582 6.3901
+189 "2H5" 20 100 20 0 24.389 13.068 11.973
+574 "2H6" 0 70 85 0 36.78 25.432 4.5745
+102 "2H7" 20 20 10 0 53.225 53.555 49.466
+610 "2H8" 40 70 85 0 19.945 15.86 4.4212
+138 "2H9" 70 20 10 0 23.543 28.475 42.67
+646 "2H10" 100 70 85 0 4.7922 6.658 4.6939
+1076 "2H11" 20 0 0 60 16.12 17.453 17.095
+1187 "2H12" 70 20 100 60 4.5975 6.3578 1.9865
+1078 "2H13" 20 40 0 60 11.246 10.181 10.973
+1189 "2H14" 70 70 100 60 3.5687 3.5704 1.4992
+1080 "2H15" 20 100 0 60 7.0775 4.127 4.4583
+806 "2H16" 0 70 20 20 29.112 20.241 15.526
+852 "2H17" 20 20 40 20 35.941 37.258 21.792
+824 "2H18" 40 70 20 20 17.483 13.512 14.633
+864 "2H19" 70 20 40 20 15.463 19.996 18.676
+836 "2H20" 100 70 20 20 5.6528 6.1009 13.653
+876 "2H21" 0 20 70 20 42.359 42.186 10.58
+782 "2H22" 20 70 10 20 23.594 17.029 17.321
+894 "2H23" 40 20 70 20 24.554 27.936 9.8858
+794 "2H24" 70 70 10 20 10.82 9.3917 16.304
+906 "2H25" 100 20 70 20 6.4375 12.12 9.0207
+498 "2H26" 10 20 70 0 52.093 52.845 13.265
+293 "2H27" 55 40 30 0 23.034 24.103 24.689
+534 "2H28" 55 20 70 0 24.425 30.317 12.235
+1214 "2H29" 0 70 40 80 4.9538 3.8773 2.1287
+660 "2H30" 10 20 100 0 50.036 50.783 4.986
+50 "2H31" 55 40 0 0 25.599 25.355 39.62
+696 "2H32" 55 20 100 0 23.048 29.043 4.8772
+1198 "2H33" 0 70 0 80 5.2316 3.8927 3.3515
+531 "2I1" 40 100 70 0 16.461 9.8123 4.3821
+205 "2I2" 40 70 20 0 22.514 17.107 18.902
+527 "2I3" 40 40 70 0 26.802 27.163 9.6925
+201 "2I4" 40 20 20 0 38.27 41.405 39.909
+523 "2I5" 40 0 70 0 38.624 48.002 15.263
+158 "2I6" 100 40 10 0 10.662 13.88 31.163
+626 "2I7" 70 40 85 0 14.365 17.774 6.4865
+122 "2I8" 40 40 10 0 31.718 30.304 35.442
+590 "2I9" 20 40 85 0 36.646 34.206 6.581
+86 "2I10" 0 40 10 0 54.892 47.114 39.437
+1185 "2I11" 40 100 100 60 5.0017 3.5415 1.2204
+1084 "2I12" 40 70 0 60 6.8268 5.2535 6.9461
+1183 "2I13" 40 40 100 60 6.4525 6.7027 1.7087
+1082 "2I14" 40 20 0 60 10.544 11.081 13.353
+1181 "2I15" 40 0 100 60 8.7155 10.991 2.1626
+472 "2I16" 85 30 55 0 12.234 17.741 15.442
+113 "2I17" 30 40 10 0 37.004 34.223 36.327
+615 "2I18" 55 20 85 0 23.49 29.472 7.9889
+149 "2I19" 85 40 10 0 14.438 16.952 32.008
+579 "2I20" 10 20 85 0 50.831 51.658 8.4306
+796 "2I21" 100 0 10 20 11.565 18.075 34.978
+903 "2I22" 70 100 70 20 7.2197 5.2296 3.6755
+784 "2I23" 40 0 10 20 34.823 40.299 41.81
+891 "2I24" 20 100 70 20 17.351 9.9665 3.658
+766 "2I25" 0 0 10 20 57.939 60.619 47.246
+307 "2I26" 85 0 30 0 19.008 28.996 35.395
+520 "2I27" 30 70 70 0 24.172 18.332 6.4687
+271 "2I28" 30 0 30 0 51.632 59.517 42.064
+556 "2I29" 85 70 70 0 7.8131 8.5513 6.5836
+64 "2I30" 85 0 0 0 23.365 31.716 59.171
+682 "2I31" 30 70 100 0 23.425 17.869 2.8932
+28 "2I32" 30 0 0 0 56.939 63.231 69.655
+718 "2I33" 85 70 100 0 7.0792 8.2175 3.1644
+217 "2J1" 70 0 20 0 27.125 36.402 44.283
+507 "2J2" 20 20 70 0 45.39 47.549 12.999
+221 "2J3" 70 40 20 0 18.121 20.121 28.272
+511 "2J4" 20 70 70 0 28.512 20.854 6.5761
+225 "2J5" 70 100 20 0 10.071 6.4693 12.011
+570 "2J6" 0 20 85 0 57.496 56.756 8.6102
+106 "2J7" 20 70 10 0 31.445 22.187 22.731
+606 "2J8" 40 20 85 0 31.7 36.246 8.065
+142 "2J9" 70 70 10 0 13.821 11.77 21.436
+642 "2J10" 100 20 85 0 7.5282 15.276 7.9873
+1086 "2J11" 70 0 0 60 8.0007 10.124 14.828
+1177 "2J12" 20 20 100 60 10.17 10.9 1.9567
+1088 "2J13" 70 40 0 60 5.7691 6.0384 10.009
+1179 "2J14" 20 70 100 60 7.236 5.7348 1.4263
+1090 "2J15" 70 100 0 60 3.9422 2.7307 4.5882
+1441 "2J16" 3 40 3 0 54.293 46.676 43.807
+1442 "2J17" 40 40 3 0 32.465 30.677 39.82
+1445 "2J18" 3 3 40 0 70.851 75.213 35.788
+1452 "2J19" 40 40 0 3 31.687 29.834 39.954
+1475 "2J20" 0 3 3 40 35.382 36.528 31.537
+1460 "2J21" 40 0 40 3 40.881 49.515 32.217
+1439 "2J22" 40 3 3 0 47.181 53.597 62.936
+1470 "2J23" 40 3 0 40 21.586 24.396 28.773
+1458 "2J24" 0 0 40 3 71.989 76.822 35.593
+1459 "2J25" 3 0 40 3 69.942 75.071 35.529
+17 "2J26" 10 85 0 0 32.373 19.535 21.02
+695 "2J27" 55 10 100 0 25.223 33.197 5.3016
+1207 "2J28" 70 100 0 80 2.5582 1.9132 2.3762
+659 "2J29" 10 10 100 0 54.751 58.224 5.5591
+260 "2J30" 10 85 30 0 31 19.053 13.235
+533 "2J31" 55 10 70 0 26.597 34.52 13.332
+1223 "2J32" 70 100 40 80 2.5976 2.1507 1.738
+497 "2J33" 10 10 70 0 56.943 60.473 14.751
+567 "2K1" 100 100 70 0 4.0646 4.0207 4.4248
+169 "2K2" 0 70 20 0 39.926 27.209 20.466
+563 "2K3" 100 40 70 0 6.7195 11.55 9.3203
+165 "2K4" 0 20 20 0 65.698 63.533 44.561
+559 "2K5" 100 0 70 0 9.7118 20.377 13.922
+154 "2K6" 100 0 10 0 15.883 24.856 47.995
+630 "2K7" 70 100 85 0 8.3698 6.119 3.2589
+118 "2K8" 40 0 10 0 47.027 54.654 56.844
+594 "2K9" 20 100 85 0 23.133 12.999 3.1718
+82 "2K10" 0 0 10 0 81.546 85.184 66.064
+1195 "2K11" 100 100 100 60 2.1724 2.2263 1.2824
+1074 "2K12" 0 70 0 60 10.685 7.6357 7.2649
+1193 "2K13" 100 40 100 60 2.3928 3.7472 1.7985
+1072 "2K14" 0 20 0 60 16.905 16.358 14.823
+1191 "2K15" 100 0 100 60 2.6759 5.3706 2.2135
+1456 "2K16" 3 40 3 3 52.498 45.211 42.458
+1457 "2K17" 40 40 3 3 31.539 29.824 38.593
+1462 "2K18" 3 3 40 3 68.523 72.789 34.704
+1466 "2K19" 40 40 40 3 27.973 27.724 20.342
+1476 "2K20" 3 3 3 40 34.365 35.654 31.211
+1463 "2K21" 40 3 40 3 40.141 48.066 31.487
+1454 "2K22" 40 3 3 3 45.786 52.01 61.036
+1477 "2K23" 40 3 3 40 21.485 24.371 27.892
+1383 "2K24" 60 45 45 40 9.0665 9.6529 8.1931
+1421 "2K25" 0 0 3 3 79.789 82.854 70.456
+1258 "2K26" 100 70 100 80 2.0133 2.2902 1.2531
+51 "2K27" 55 55 0 0 21.878 19.422 31.73
+681 "2K28" 30 55 100 0 26.716 23.115 3.3808
+15 "2K29" 10 55 0 0 42.403 32.903 34.48
+1242 "2K30" 100 70 70 80 2.0233 2.2352 1.5758
+294 "2K31" 55 55 30 0 19.917 18.657 19.916
+519 "2K32" 30 55 70 0 27.687 23.883 8.0068
+258 "2K33" 10 55 30 0 40.235 31.957 21.726
+244 "2L1" 0 0 30 0 77.08 81.697 45.873
+432 "2L2" 20 100 55 0 23.639 13.11 6.1943
+280 "2L3" 40 0 30 0 43.854 52.447 40.404
+468 "2L4" 70 100 55 0 9.0996 6.3346 6.2835
+316 "2L5" 100 0 30 0 13.442 23.318 34.159
+1141 "2L6" 100 0 40 60 3.6644 6.2207 7.1392
+1122 "2L7" 0 20 40 60 14.806 14.748 7.7643
+1143 "2L8" 100 40 40 60 2.9983 4.0964 5.1669
+1124 "2L9" 0 70 40 60 10.133 7.5047 4.2491
+1145 "2L10" 100 100 40 60 2.4113 2.1836 2.7443
+406 "2L11" 0 0 55 0 72.272 77.656 24.988
+270 "2L12" 20 100 30 0 24.153 13.087 10.191
+442 "2L13" 40 0 55 0 40.203 49.451 22.945
+306 "2L14" 70 100 30 0 9.7975 6.4564 10.228
+478 "2L15" 100 0 55 0 10.877 21.35 20.18
+1316 "2L16" 0 50 0 0 50.062 39.535 38.4
+1317 "2L17" 0 40 0 0 56.387 48.115 45.856
+1336 "2L18" 0 0 50 0 73.074 78.372 28.447
+1337 "2L19" 0 0 40 0 74.951 79.955 36.787
+1356 "2L20" 0 0 0 50 27.113 28.23 24.861
+1357 "2L21" 0 0 0 40 36.398 37.862 33.394
+1296 "2L22" 50 0 0 0 41.037 48.639 65.176
+1297 "2L23" 40 0 0 0 48.74 55.767 67.464
+1423 "2L24" 0 3 3 3 77.783 79.99 68.416
+1446 "2L25" 40 3 40 0 41.382 49.573 32.515
+13 "2L26" 10 30 0 0 55.886 51.656 51.481
+699 "2L27" 55 55 100 0 16.597 16.464 3.4464
+49 "2L28" 55 30 0 0 28.708 30.127 45.424
+663 "2L29" 10 55 100 0 36.425 29.327 3.4137
+256 "2L30" 10 30 30 0 51.713 48.832 31.807
+537 "2L31" 55 55 70 0 17.549 17.239 7.7907
+292 "2L32" 55 30 30 0 25.976 28.883 28.527
+501 "2L33" 10 55 70 0 37.489 30.199 8.313
+480 "2M1" 100 20 55 0 9.1693 16.548 16.803
+304 "2M2" 70 70 30 0 12.946 11.538 15.631
+444 "2M3" 40 20 55 0 34.071 38.341 19.01
+268 "2M4" 20 70 30 0 30.376 21.828 16.549
+408 "2M5" 0 20 55 0 60.429 59.474 20.497
+1140 "2M6" 70 100 40 60 3.6536 2.8129 2.798
+1129 "2M7" 20 70 40 60 8.0524 6.1717 4.0654
+1138 "2M8" 70 40 40 60 4.681 5.3026 5.3278
+1127 "2M9" 20 20 40 60 11.795 12.27 7.4165
+1136 "2M10" 70 0 40 60 6.2776 8.7036 7.5706
+318 "2M11" 100 20 30 0 11.189 17.899 28.374
+466 "2M12" 70 70 55 0 11.666 10.941 9.1914
+282 "2M13" 40 20 30 0 37.116 40.692 33.418
+430 "2M14" 20 70 55 0 29.124 21.215 9.6145
+246 "2M15" 0 20 30 0 63.958 62.225 36.837
+1335 "2M16" 0 0 60 0 71.538 76.972 21.903
+1338 "2M17" 0 0 30 0 77.08 81.697 45.873
+1071 "2M18" 0 0 0 60 18.722 19.509 17.095
+1358 "2M19" 0 0 0 30 47.08 48.926 43.146
+1295 "2M20" 60 0 0 0 34.932 42.867 63.187
+1298 "2M21" 30 0 0 0 56.939 63.231 69.655
+1315 "2M22" 0 60 0 0 44.984 32.815 32.205
+4 "2M23" 0 30 0 0 62.701 56.901 53.098
+1443 "2M24" 3 0 40 0 72.542 77.891 36.699
+1444 "2M25" 0 3 40 0 73.042 77.009 35.813
+1256 "2M26" 100 0 100 80 1.893 3.2487 1.582
+459 "2M27" 55 100 55 0 12.532 7.9279 6.2308
+677 "2M28" 30 10 100 0 40.279 46.151 5.3443
+423 "2M29" 10 100 55 0 27.329 14.831 6.2413
+1240 "2M30" 100 0 70 80 2.053 3.3808 2.4352
+378 "2M31" 55 100 40 0 12.95 8.0267 8.5395
+515 "2M32" 30 10 70 0 42.101 47.999 14.089
+342 "2M33" 10 100 40 0 27.652 14.886 8.7057
+248 "2N1" 0 40 30 0 52.528 45.525 28.318
+428 "2N2" 20 40 55 0 38.41 35.546 15.198
+284 "2N3" 40 40 30 0 29.939 29.326 25.645
+464 "2N4" 70 40 55 0 15.489 18.523 14.18
+320 "2N5" 100 40 30 0 9.1277 13.089 22.599
+1131 "2N6" 40 0 40 60 10.19 12.289 8.225
+1132 "2N7" 40 20 40 60 8.8102 9.7595 6.9608
+1133 "2N8" 40 40 40 60 7.5029 7.4316 5.702
+1134 "2N9" 40 70 40 60 6.1031 4.9339 3.8811
+1135 "2N10" 40 100 40 60 5.4052 3.6322 2.7892
+410 "2N11" 0 40 55 0 49.848 43.529 15.896
+266 "2N12" 20 40 30 0 40.719 37.127 26.715
+446 "2N13" 40 40 55 0 27.771 27.816 14.545
+302 "2N14" 70 40 30 0 17.16 19.561 23.614
+482 "2N15" 100 40 55 0 7.5448 12.159 13.409
+1334 "2N16" 0 0 70 0 70.296 75.801 16.829
+1339 "2N17" 0 0 25 0 78.242 82.636 50.981
+1354 "2N18" 0 0 0 70 12.207 12.724 11
+1359 "2N19" 0 0 0 25 52.793 54.831 48.289
+1294 "2N20" 70 0 0 0 30.004 38.132 61.496
+1299 "2N21" 25 0 0 0 61.333 67.185 70.784
+1314 "2N22" 0 70 0 0 41.064 27.7 27.285
+1319 "2N23" 0 25 0 0 65.984 61.496 56.807
+1422 "2N24" 3 0 3 3 77.603 80.974 69.8
+1453 "2N25" 40 0 3 3 46.789 53.696 62.519
+8 "2N26" 0 85 0 0 36.321 21.541 21.27
+1252 "2N27" 70 0 100 80 3.0822 4.3835 1.6602
+44 "2N28" 40 85 0 0 20.804 13.409 20.271
+650 "2N29" 0 10 100 0 61.675 63.625 5.5889
+251 "2N30" 0 85 30 0 35.13 21.185 13.353
+1236 "2N31" 70 0 70 80 3.1049 4.3664 2.4244
+287 "2N32" 40 85 30 0 19.397 12.989 12.646
+488 "2N33" 0 10 70 0 64.187 66.282 14.983
+484 "2O1" 100 70 55 0 5.6991 7.1059 9.2396
+300 "2O2" 70 20 30 0 21.43 27.247 30.357
+448 "2O3" 40 70 55 0 20.835 16.388 9.392
+264 "2O4" 20 20 30 0 50.349 51.559 35.476
+412 "2O5" 0 70 55 0 37.905 26.101 9.9968
+1130 "2O6" 20 100 40 60 6.858 4.3108 2.799
+1139 "2O7" 70 70 40 60 3.9719 3.6823 3.7647
+1128 "2O8" 20 40 40 60 10.011 9.377 5.9896
+1137 "2O9" 70 20 40 60 5.3796 6.8306 6.3741
+1126 "2O10" 20 0 40 60 13.55 15.296 8.8402
+322 "2O11" 100 70 30 0 6.7492 7.5725 15.244
+462 "2O12" 70 20 55 0 18.9 25.419 17.746
+286 "2O13" 40 70 30 0 21.943 16.881 15.824
+426 "2O14" 20 20 55 0 46.818 48.738 19.917
+250 "2O15" 0 70 30 0 39.264 26.87 17.027
+1333 "2O16" 0 0 75 0 69.765 75.294 14.738
+163 "2O17" 0 0 20 0 79.484 83.639 56.44
+1353 "2O18" 0 0 0 75 9.6965 10.11 8.6337
+1360 "2O19" 0 0 0 20 58.945 61.186 53.819
+1293 "2O20" 75 0 0 0 27.91 36.096 60.764
+1300 "2O21" 20 0 0 0 66.155 71.475 71.889
+1313 "2O22" 0 75 0 0 39.448 25.605 25.236
+1320 "2O23" 0 20 0 0 69.597 66.565 60.838
+1447 "2O24" 3 40 40 0 49.709 43.549 23.144
+1440 "2O25" 0 40 3 0 56.018 47.878 44.066
+708 "2O26" 70 55 100 0 11.905 13.313 3.5428
+22 "2O27" 20 30 0 0 49.337 46.598 50.167
+1250 "2O28" 40 70 100 80 3.5096 3.1916 1.2656
+58 "2O29" 70 30 0 0 22.184 24.711 43.62
+546 "2O30" 70 55 70 0 12.724 13.885 7.8103
+265 "2O31" 20 30 30 0 45.493 44.156 31.065
+1234 "2O32" 40 70 70 80 3.5287 3.1386 1.5764
+301 "2O33" 70 30 30 0 19.263 23.285 27.099
+252 "2P1" 0 100 30 0 31.693 16.659 10.363
+424 "2P2" 20 0 55 0 55.813 63.395 24.202
+288 "2P3" 40 100 30 0 17.259 9.8599 10.01
+460 "2P4" 70 0 55 0 22.568 32.996 21.23
+324 "2P5" 100 100 30 0 5.115 4.2399 10.227
+1121 "2P6" 0 0 40 60 17.271 18.552 9.4611
+1142 "2P7" 100 20 40 60 3.3494 5.165 6.2004
+1123 "2P8" 0 40 40 60 12.404 11.185 6.1411
+1144 "2P9" 100 70 40 60 2.6547 2.9252 3.7357
+1125 "2P10" 0 100 40 60 8.4247 5.0487 2.8149
+414 "2P11" 0 100 55 0 31.062 16.556 6.234
+262 "2P12" 20 0 30 0 59.989 66.929 43.563
+450 "2P13" 40 100 55 0 16.719 9.8527 6.1702
+298 "2P14" 70 0 30 0 25.698 35.448 36.711
+486 "2P15" 100 100 55 0 4.4375 4.1148 6.2786
+1352 "2P16" 0 0 0 80 7.5688 7.8937 6.6402
+1361 "2P17" 0 0 0 15 64.939 67.375 59.178
+1292 "2P18" 80 0 0 0 25.861 34.122 60.042
+1301 "2P19" 15 0 0 0 70.678 75.488 73.034
+1312 "2P20" 0 80 0 0 37.947 23.655 23.333
+1321 "2P21" 0 15 0 0 73.058 71.373 64.646
+1332 "2P22" 0 0 80 0 69.318 74.851 12.828
+1341 "2P23" 0 0 15 0 80.55 84.499 61.058
+1472 "2P24" 0 0 3 40 36.184 37.715 32.352
+1417 "2P25" 3 3 3 0 78.484 81.076 70.262
+1318 "2P26" 0 30 0 0 62.701 56.901 53.098
+690 "2P27" 40 55 100 0 22.27 20.208 3.3847
+1205 "2P28" 70 40 0 80 3.1799 3.3106 4.5548
+654 "2P29" 0 55 100 0 41.058 32.033 3.4188
+247 "2P30" 0 30 30 0 58.153 53.602 32.559
+528 "2P31" 40 55 70 0 23.312 21.036 7.9337
+1221 "2P32" 70 40 40 80 2.8916 3.2153 2.8407
+492 "2P33" 0 55 70 0 42.45 33.253 8.4795
+1075 "2Q1" 0 100 0 60 8.4242 4.7581 4.4183
+1194 "2Q2" 100 70 100 60 2.2826 2.8028 1.5269
+1073 "2Q3" 0 40 0 60 14.133 12.396 11.625
+1192 "2Q4" 100 20 100 60 2.5815 4.6387 2.025
+1355 "2Q5" 0 0 0 60 18.722 19.509 17.095
+648 "2Q6" 100 100 85 0 3.8434 3.9547 3.2222
+136 "2Q7" 70 0 10 0 28.399 37.168 52.105
+612 "2Q8" 40 100 85 0 16.149 9.722 3.1901
+100 "2Q9" 20 0 10 0 64.122 70.064 61.644
+576 "2Q10" 0 100 85 0 30.497 16.411 3.101
+171 "2Q11" 0 100 20 0 31.855 16.576 12.252
+565 "2Q12" 100 70 70 0 5.126 6.7822 6.4772
+167 "2Q13" 0 40 20 0 53.653 46.279 33.894
+561 "2Q14" 100 20 70 0 8.1739 15.8 11.648
+1340 "2Q15" 0 0 20 0 79.484 83.639 56.44
+1351 "2Q16" 0 0 0 85 5.8783 6.1325 5.0453
+1362 "2Q17" 0 0 0 10 71.324 73.964 64.846
+1291 "2Q18" 85 0 0 0 23.365 31.716 59.171
+1302 "2Q19" 10 0 0 0 75.117 79.325 73.888
+1311 "2Q20" 0 85 0 0 36.321 21.541 21.27
+1322 "2Q21" 0 10 0 0 76.386 76.234 68.218
+568 "2Q22" 0 0 85 0 68.847 74.374 10.815
+1342 "2Q23" 0 0 10 0 81.546 85.184 66.064
+1374 "2Q24" 5 3 3 0 76.898 79.714 69.893
+1438 "2Q25" 40 0 3 0 48.364 55.548 64.6
+704 "2Q26" 70 10 100 0 17.965 26.694 5.3452
+1203 "2Q27" 40 100 0 80 3.2852 2.2379 2.2698
+668 "2Q28" 20 10 100 0 47.476 52.192 5.4187
+62 "2Q29" 70 85 0 0 12.341 8.8945 19.81
+542 "2Q30" 70 10 70 0 19.275 27.93 13.002
+1219 "2Q31" 40 100 40 80 3.3941 2.569 1.7401
+506 "2Q32" 20 10 70 0 49.495 54.282 14.405
+305 "2Q33" 70 85 30 0 11.307 8.7763 12.758
+1176 "2R1" 20 0 100 60 11.693 13.6 2.2243
+1087 "2R2" 70 20 0 60 6.8485 7.9614 12.462
+1178 "2R3" 20 40 100 60 8.7383 8.4322 1.6864
+1089 "2R4" 70 70 0 60 4.667 3.981 6.7619
+1180 "2R5" 20 100 100 60 6.4005 4.2183 1.2148
+88 "2R6" 0 70 10 0 40.436 27.379 23.635
+588 "2R7" 20 20 85 0 44.346 46.526 8.2869
+124 "2R8" 40 70 10 0 23.071 17.287 21.894
+624 "2R9" 70 20 85 0 16.961 23.857 7.9109
+160 "2R10" 100 70 10 0 7.664 7.8564 20.701
+505 "2R11" 20 0 70 0 53.84 61.587 15.853
+219 "2R12" 70 20 20 0 22.509 27.914 36.573
+509 "2R13" 20 40 70 0 37.308 34.783 10.114
+223 "2R14" 70 70 20 0 13.409 11.668 18.565
+513 "2R15" 20 100 70 0 23.329 13.052 4.3523
+1350 "2R16" 0 0 0 90 4.4602 4.6549 3.7277
+1363 "2R17" 0 0 0 7 75.254 78.018 68.33
+1290 "2R18" 90 0 0 0 21.073 29.468 58.368
+1303 "2R19" 7 0 0 0 77.791 81.624 74.41
+1310 "2R20" 0 90 0 0 34.862 19.646 19.365
+1323 "2R21" 0 7 0 0 78.538 79.375 70.488
+1330 "2R22" 0 0 90 0 68.433 73.929 9.0439
+1343 "2R23" 0 0 7 0 82.212 85.642 69.346
+1373 "2R24" 10 6 6 0 70.016 72.69 64.029
+1415 "2R25" 3 0 3 0 80.483 84.013 72.319
+1199 "2R26" 0 100 0 80 4.3725 2.7121 2.1754
+694 "2R27" 55 0 100 0 27.395 37.577 5.7703
+52 "2R28" 55 70 0 0 18.521 14.442 24.918
+1244 "2R29" 0 0 100 80 6.9069 7.584 1.6615
+1215 "2R30" 0 100 40 80 4.3481 2.9399 1.5795
+532 "2R31" 55 0 70 0 29.025 39.214 14.527
+295 "2R32" 55 70 30 0 17.073 14.022 15.756
+1228 "2R33" 0 0 70 80 7.1318 7.7751 2.585
+1085 "2S1" 40 100 0 60 5.6385 3.4701 4.5217
+1184 "2S2" 40 70 100 60 5.472 4.6439 1.431
+1083 "2S3" 40 40 0 60 8.6745 8.2231 10.527
+1182 "2S4" 40 20 100 60 7.5389 8.7392 1.9446
+1081 "2S5" 40 0 0 60 12.481 14.256 16.248
+644 "2S6" 100 40 85 0 6.1465 11.136 6.5358
+140 "2S7" 70 40 10 0 18.977 20.519 32.887
+608 "2S8" 40 40 85 0 26.102 26.494 6.3489
+104 "2S9" 20 40 10 0 42.831 38.473 37.277
+572 "2S10" 0 40 85 0 47.559 41.579 6.6855
+207 "2S11" 40 100 20 0 17.46 9.8331 11.75
+529 "2S12" 40 70 70 0 20.353 16.119 6.5305
+203 "2S13" 40 40 20 0 30.828 29.84 30.465
+525 "2S14" 40 20 70 0 32.496 37.003 12.595
+199 "2S15" 40 0 20 0 45.428 53.565 48.478
+1289 "2S16" 95 0 0 0 19.138 27.524 57.623
+1304 "2S17" 5 0 0 0 79.535 83.122 74.775
+1309 "2S18" 0 95 0 0 33.67 18.103 17.756
+1324 "2S19" 0 5 0 0 79.986 81.472 72
+1329 "2S20" 0 0 95 0 68.131 73.555 7.6466
+1344 "2S21" 0 0 5 0 82.632 85.932 71.387
+1349 "2S22" 0 0 0 95 3.4906 3.6405 2.8571
+1364 "2S23" 0 0 0 5 77.813 80.658 70.597
+1372 "2S24" 20 12 12 0 57.127 59.628 52.649
+1437 "2S25" 3 40 0 0 54.609 46.838 45.445
+716 "2S26" 85 40 100 0 9.3486 13.878 4.257
+1201 "2S27" 40 40 0 80 4.4886 4.319 4.7764
+680 "2S28" 30 40 100 0 30.501 29.579 3.9312
+66 "2S29" 85 20 0 0 19.214 24.141 47.91
+554 "2S30" 85 40 70 0 10.365 14.666 9.5341
+1217 "2S31" 40 40 40 80 4.1433 4.1667 2.9522
+518 "2S32" 30 40 70 0 31.79 30.79 9.8645
+309 "2S33" 85 20 30 0 15.812 22.227 29.309
+1186 "2T1" 70 0 100 60 5.2037 7.8436 2.1627
+1077 "2T2" 20 20 0 60 13.375 13.41 13.73
+1188 "2T3" 70 40 100 60 4.0032 4.9322 1.7678
+1079 "2T4" 20 70 0 60 8.7529 6.4523 7.1492
+1190 "2T5" 70 100 100 60 3.3628 2.8119 1.2912
+84 "2T6" 0 20 10 0 67.502 64.907 52.292
+592 "2T7" 20 70 85 0 28.108 20.596 4.4394
+120 "2T8" 40 20 10 0 39.229 41.854 46.166
+628 "2T9" 70 70 85 0 10.587 10.344 4.467
+156 "2T10" 100 20 10 0 13.142 19.002 39.45
+541 "2T11" 70 0 70 0 21.057 31.724 14.068
+183 "2T12" 20 20 20 0 51.957 52.761 42.696
+545 "2T13" 70 40 70 0 14.902 18.186 9.7369
+187 "2T14" 20 70 20 0 30.915 22.015 19.669
+549 "2T15" 70 100 70 0 8.6643 6.2153 4.4865
+1288 "2T16" 98 0 0 0 18.031 26.399 57.207
+1305 "2T17" 3 0 0 0 81.162 84.519 75.123
+1308 "2T18" 0 98 0 0 32.984 17.216 16.835
+1325 "2T19" 0 3 0 0 81.401 83.509 73.467
+1328 "2T20" 0 0 98 0 67.951 73.331 6.8597
+1345 "2T21" 0 0 3 0 83.005 86.19 73.174
+1348 "2T22" 0 0 0 98 2.99 3.117 2.4132
+1365 "2T23" 0 0 0 3 80.153 83.071 72.668
+1371 "2T24" 40 27 27 0 35.147 37.025 32.701
+1436 "2T25" 40 3 0 0 47.607 53.841 65.458
+12 "2T26" 10 20 0 0 62.169 60.553 58.992
+698 "2T27" 55 40 100 0 19.251 21.319 3.9971
+48 "2T28" 55 20 0 0 31.849 35.245 51.635
+1246 "2T29" 0 70 100 80 4.9126 4.0355 1.2344
+255 "2T30" 10 20 30 0 57.101 56.911 36.24
+536 "2T31" 55 40 70 0 20.38 22.356 9.6853
+291 "2T32" 55 20 30 0 28.488 33.387 31.708
+1230 "2T33" 0 70 70 80 4.9638 4.0166 1.6192
+1095 "2U1" 100 100 0 60 2.7618 2.2108 4.6888
+1174 "2U2" 0 70 100 60 9.0728 6.8758 1.3976
+1093 "2U3" 100 40 0 60 3.7545 4.5005 9.551
+1172 "2U4" 0 20 100 60 12.964 13.182 1.9982
+1091 "2U5" 100 0 0 60 4.728 6.906 13.457
+640 "2U6" 100 0 85 0 8.8403 19.595 9.2829
+144 "2U7" 70 100 10 0 10.353 6.489 13.819
+604 "2U8" 40 0 85 0 37.463 46.861 9.8419
+108 "2U9" 20 100 10 0 24.631 13.078 13.805
+1331 "2U10" 0 0 85 0 68.847 74.374 10.815
+243 "2U11" 100 100 20 0 5.3982 4.2754 11.983
+493 "2U12" 0 70 70 0 37.425 25.929 6.9599
+239 "2U13" 100 40 20 0 9.8374 13.434 26.709
+489 "2U14" 0 20 70 0 58.624 57.821 13.421
+235 "2U15" 100 0 20 0 14.646 24.111 40.809
+1287 "2U16" 100 0 0 0 17.316 25.666 56.941
+1306 "2U17" 2 0 0 0 81.949 85.195 75.296
+1307 "2U18" 0 100 0 0 32.54 16.641 16.24
+1326 "2U19" 0 2 0 0 82.103 84.515 74.191
+1327 "2U20" 0 0 100 0 67.831 73.183 6.3566
+1346 "2U21" 0 0 2 0 83.181 86.312 74.008
+1347 "2U22" 0 0 0 100 2.6842 2.7971 2.1442
+1366 "2U23" 0 0 0 2 81.269 84.221 73.655
+1370 "2U24" 60 45 45 0 18.648 19.88 16.953
+1414 "2U25" 3 3 0 0 79.032 81.452 72.778
+712 "2U26" 85 0 100 0 13.275 24.297 5.716
+34 "2U27" 30 70 0 0 27.569 19.811 25.728
+676 "2U28" 30 0 100 0 43.65 52.263 5.9337
+70 "2U29" 85 70 0 0 10.922 9.7865 24.082
+550 "2U30" 85 0 70 0 14.772 25.647 13.911
+277 "2U31" 30 70 30 0 25.866 19.213 16.143
+514 "2U32" 30 0 70 0 45.856 54.52 15.521
+313 "2U33" 85 70 30 0 9.539 9.4096 15.441
+END_DATA
diff --git a/target/FograStrip2.ti1 b/target/FograStrip2.ti1
new file mode 100644
index 0000000..f8abae7
--- /dev/null
+++ b/target/FograStrip2.ti1
@@ -0,0 +1,120 @@
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Manualy created for FOGRA strip #2 "
+CREATED "Wed Jun 1 15:06:24 2004"
+KEYWORD "DEFAULT_EXPECTED_VALUES"
+DEFAULT_EXPECTED_VALUES "true"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "83.77 87.26 66.79"
+KEYWORD "TOTAL_INK_LIMIT"
+TOTAL_INK_LIMIT "270.0"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 46
+BEGIN_DATA
+1 100 0 0 0 19.21 25.37 45.6
+2 70 0 0 0 28.25 35.4 51.26
+3 40 0 0 0 45.2 52.51 58.34
+4 0 100 0 0 35.66 21.75 16.18
+5 0 70 0 0 41.16 28.04 22.51
+6 0 40 0 0 54.44 44.85 37.56
+7 0 0 100 0 70.46 73.51 10.34
+8 0 0 70 0 72.54 76.67 16.6
+9 0 0 40 0 76.58 81.29 31.57
+10 20 70 70 0 26.84 20.24 9.68
+11 40 70 70 20 15.21 13.33 8.47
+12 40 100 100 20 13.26 10.8 6.56
+13 40 100 40 20 15.41 12.16 10.32
+14 40 40 100 20 17.64 18.07 7.7
+15 100 40 100 20 8.74 11.04 7.8
+16 100 40 40 20 10.64 12.84 14.75
+17 100 100 40 20 8.44 8.45 10.12
+18 0 0 0 10 69.21 72.04 55.31
+19 0 0 0 20 57.67 59.99 46.27
+20 0 0 0 40 37.79 39.2 30.25
+21 0 0 0 60 22.87 23.62 18.11
+22 0 0 0 80 12.52 12.83 9.74
+23 0 0 0 100 7.34 7.42 5.6
+24 100 100 0 0 10.64 10.02 15.7
+25 70 70 0 0 15.73 14.48 21.18
+26 40 40 0 0 31.46 29.92 34.72
+27 0 100 100 0 32.06 19.73 6.79
+28 0 70 70 0 37.86 26.24 10.23
+29 0 40 40 0 50.42 41.91 21.32
+30 100 0 100 0 11.84 18.76 9.74
+31 70 0 70 0 20.00 28.29 14.84
+32 40 0 40 0 37.71 46.37 28.51
+33 10 40 40 0 44.02 38.09 21.16
+34 0 40 100 0 46.00 37.51 8.7
+35 0 100 40 0 34.28 21.23 12.07
+36 40 100 0 0 20.58 15.09 16.73
+37 40 0 100 0 32.29 40.42 10.44
+38 100 0 40 0 15.35 22.58 24.53
+39 100 40 0 0 14.68 16.88 29.74
+40 0 0 0 0 83.77 87.26 66.79
+41 10 6 6 0 69.49 73.01 57.1
+42 20 12 12 0 53.95 56.73 46.26
+43 40 27 27 0 31.75 33.56 28.39
+44 60 45 45 0 18.83 20.03 17.45
+45 80 65 65 0 11.98 12.82 11.37
+46 100 85 85 0 8.30 8.90 8.39
+END_DATA
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Argyll targen"
+KEYWORD "DENSITY_EXTREME_VALUES"
+DENSITY_EXTREME_VALUES "8"
+CREATED "April 22, 2008"
+
+KEYWORD "INDEX"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+INDEX CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 8
+BEGIN_DATA
+0 0.0000 0.0000 0.0000 0.0000 96.420 100.00 82.490
+1 100.00 0.0000 0.0000 0.0000 12.000 18.000 48.000
+2 0.0000 100.00 0.0000 0.0000 38.000 19.000 20.000
+3 100.00 0.0000 0.0000 45.486 3.2503 4.8706 13.063
+4 0.0000 17.988 100.00 0.0000 59.720 57.803 8.0538
+5 100.00 0.0000 100.00 40.023 3.1381 4.8335 2.1311
+6 0.0000 100.00 100.00 18.089 19.420 9.9765 1.7309
+7 0.0000 31.327 0.0000 100.00 0.65916 0.54433 0.57384
+END_DATA
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Argyll targen"
+KEYWORD "DEVICE_COMBINATION_VALUES"
+DEVICE_COMBINATION_VALUES "9"
+CREATED "April 22, 2008"
+
+KEYWORD "INDEX"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+INDEX CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 9
+BEGIN_DATA
+0 0.0000 0.0000 0.0000 0.0000 96.420 100.00 82.490
+1 100.00 0.0000 0.0000 0.0000 12.000 18.000 48.000
+2 0.0000 100.00 0.0000 0.0000 38.000 19.000 20.000
+3 100.00 100.00 0.0000 0.0000 4.7293 3.4200 11.638
+4 0.0000 0.0000 100.00 0.0000 76.000 81.000 11.000
+5 100.00 0.0000 100.00 0.0000 9.4586 14.580 6.4008
+6 0.0000 100.00 100.00 0.0000 29.952 15.390 2.6670
+7 100.00 100.00 100.00 100.00 0.038661 0.027702 0.018813
+8 40.000 40.000 40.000 0.0000 19.978 17.645 12.009
+END_DATA
diff --git a/target/FograStrip2_2.ti2 b/target/FograStrip2_2.ti2
new file mode 100644
index 0000000..b84cb9d
--- /dev/null
+++ b/target/FograStrip2_2.ti2
@@ -0,0 +1,75 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+ORIGINATOR "Manualy created for FOGRA strip #2 in 2 strip layout"
+CREATED "Wed Jun 1 15:06:24 2004"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "83.77 87.26 66.79"
+KEYWORD "TOTAL_INK_LIMIT"
+TOTAL_INK_LIMIT "270.0"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "23"
+KEYWORD "PASSES_IN_STRIPS"
+PASSES_IN_STRIPS "2"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 46
+BEGIN_DATA
+1 "A1" 100 0 0 0 19.21 25.37 45.6
+2 "A2" 70 0 0 0 28.25 35.4 51.26
+3 "A3" 40 0 0 0 45.2 52.51 58.34
+4 "A4" 0 100 0 0 35.66 21.75 16.18
+5 "A5" 0 70 0 0 41.16 28.04 22.51
+6 "A6" 0 40 0 0 54.44 44.85 37.56
+7 "A7" 0 0 100 0 70.46 73.51 10.34
+8 "A8" 0 0 70 0 72.54 76.67 16.6
+9 "A9" 0 0 40 0 76.58 81.29 31.57
+10 "A10" 20 70 70 0 26.84 20.24 9.68
+11 "A11" 40 70 70 20 15.21 13.33 8.47
+12 "A12" 40 100 100 20 13.26 10.8 6.56
+13 "A13" 40 100 40 20 15.41 12.16 10.32
+14 "A14" 40 40 100 20 17.64 18.07 7.7
+15 "A15" 100 40 100 20 8.74 11.04 7.8
+16 "A16" 100 40 40 20 10.64 12.84 14.75
+17 "A17" 100 100 40 20 8.44 8.45 10.12
+18 "A18" 0 0 0 10 69.21 72.04 55.31
+19 "A19" 0 0 0 20 57.67 59.99 46.27
+20 "A20" 0 0 0 40 37.79 39.2 30.25
+21 "A21" 0 0 0 60 22.87 23.62 18.11
+22 "A22" 0 0 0 80 12.52 12.83 9.74
+23 "A23" 0 0 0 100 7.34 7.42 5.6
+24 "B1" 100 100 0 0 10.64 10.02 15.7
+25 "B2" 70 70 0 0 15.73 14.48 21.18
+26 "B3" 40 40 0 0 31.46 29.92 34.72
+27 "B4" 0 100 100 0 32.06 19.73 6.79
+28 "B5" 0 70 70 0 37.86 26.24 10.23
+29 "B6" 0 40 40 0 50.42 41.91 21.32
+30 "B7" 100 0 100 0 11.84 18.76 9.74
+31 "B8" 70 0 70 0 20.00 28.29 14.84
+32 "B9" 40 0 40 0 37.71 46.37 28.51
+33 "B10" 10 40 40 0 44.02 38.09 21.16
+34 "B11" 0 40 100 0 46.00 37.51 8.7
+35 "B12" 0 100 40 0 34.28 21.23 12.07
+36 "B13" 40 100 0 0 20.58 15.09 16.73
+37 "B14" 40 0 100 0 32.29 40.42 10.44
+38 "B15" 100 0 40 0 15.35 22.58 24.53
+39 "B16" 100 40 0 0 14.68 16.88 29.74
+40 "B17" 0 0 0 0 83.77 87.26 66.79
+41 "B18" 10 6 6 0 69.49 73.01 57.1
+42 "B19" 20 12 12 0 53.95 56.73 46.26
+43 "B20" 40 27 27 0 31.75 33.56 28.39
+44 "B21" 60 45 45 0 18.83 20.03 17.45
+45 "B22" 80 65 65 0 11.98 12.82 11.37
+46 "B23" 100 85 85 0 8.30 8.90 8.39
+END_DATA
+
+
diff --git a/target/FograStrip3.ti1 b/target/FograStrip3.ti1
new file mode 100644
index 0000000..4cf126f
--- /dev/null
+++ b/target/FograStrip3.ti1
@@ -0,0 +1,146 @@
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Manualy created for FOGRA strip #3 "
+CREATED "Thu Jan 12 15:06:24 2011"
+KEYWORD "DEFAULT_EXPECTED_VALUES"
+DEFAULT_EXPECTED_VALUES "true"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "87.38 90.38 75.45"
+KEYWORD "TOTAL_INK_LIMIT"
+TOTAL_INK_LIMIT "270.0"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 72
+BEGIN_DATA
+1 100 0 0 0 14.91 22.41 53.72
+2 70 0 0 0 24.6 32.11 56.56
+3 40 0 0 0 41.86 48.84 63.97
+4 20 0 0 0 59.49 65.47 69.4
+5 10 0 0 0 71.85 76.74 72.45
+6 0 100 0 0 35.87 18.39 16.7
+7 0 70 0 0 42.6 27.5 24.95
+8 0 40 0 0 56.48 44.98 40.26
+9 0 20 0 0 69.77 63.34 55.08
+10 0 10 0 0 79.71 77.36 66.28
+11 0 0 100 0 74.36 78.79 7.06
+12 0 0 70 0 75.77 80.62 16.06
+13 0 0 40 0 78.94 83.73 32.04
+14 0 0 20 0 82.9 87.23 49.82
+15 0 0 10 0 85.2 88.98 61.85
+16 0 0 0 10 67.91 70.15 58.39
+17 0 0 0 20 49.47 51.05 42.55
+18 0 0 0 40 30.07 30.99 26.02
+19 0 0 0 60 15.9 16.31 13.78
+20 0 0 0 80 7.04 7.13 6.22
+21 0 0 0 100 1.69 1.61 1.67
+22 0 100 0 100 1.41 1.14 1.48
+23 0 70 70 60 9.68 7.17 3.38
+24 0 0 70 80 7.27 7.64 3.38
+25 100 100 0 0 4.35 2.81 13.31
+26 70 70 0 0 12.04 10.07 21.64
+27 40 40 0 0 28.32 26.36 35.63
+28 20 20 0 0 47.53 46.5 50.03
+29 10 10 0 0 64.23 64.56 61.64
+30 0 100 100 0 32.69 17.25 2.74
+31 0 70 70 0 39.4 25.83 7.73
+32 0 40 40 0 52.14 42.32 20.67
+33 0 20 20 0 66.2 60.84 38.79
+34 0 10 10 0 77.01 75.27 54.63
+35 100 0 100 0 6.66 16.31 5.63
+36 70 0 70 0 16.97 26.86 13.73
+37 40 0 40 0 35.31 44.25 29.06
+38 20 0 20 0 55.17 62.38 46.73
+39 10 0 10 0 69.88 75.46 59.92
+40 10 6 6 0 66.27 68.73 60.0
+41 20 12 12 0 48.71 50.74 45.17
+42 40 27 27 0 28.15 29.54 26.91
+43 60 45 45 0 15.65 16.58 15.62
+44 80 65 65 0 7.41 7.92 7.94
+45 100 85 85 0 3.11 3.51 4.29
+46 100 0 0 100 1.00 1.07 1.42
+47 20 100 70 60 6.34 3.91 2.68
+48 70 0 70 80 3.22 4.15 3.04
+49 100 100 100 0 2.42 2.16 2.69
+50 70 70 70 0 8.92 8.36 6.83
+51 40 40 40 0 24.72 24.12 18.8
+52 20 20 20 0 44.17 44.18 35.62
+53 10 10 10 0 61.84 62.76 51.51
+54 20 70 70 0 26.95 19.18 7.57
+55 40 70 70 20 13.71 10.9 5.89
+56 40 100 100 20 10.62 6.33 2.41
+57 40 100 40 20 11.7 6.77 7.24
+58 40 40 100 20 16.45 16.81 3.73
+59 100 40 100 20 3.62 6.84 3.5
+60 100 40 40 20 5.33 8.00 12.8
+61 100 100 40 20 2.75 2.07 6.41
+62 10 40 40 0 43.46 36.9 20.39
+63 0 40 100 0 49.78 40.72 4.88
+64 0 100 40 0 34.02 17.62 9.73
+65 40 100 0 0 16.66 9.11 14.75
+66 40 0 100 0 31.1 40.61 6.39
+67 100 0 40 0 9.99 19.02 25.24
+68 100 40 0 0 9.18 11.79 30.55
+69 0 0 0 0 87.38 90.38 75.45
+70 0 0 100 100 1.57 1.54 1.33
+71 0 70 0 60 10.61 7.67 7.74
+72 70 0 0 80 3.84 4.59 6.23
+END_DATA
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Argyll targen"
+KEYWORD "DENSITY_EXTREME_VALUES"
+DENSITY_EXTREME_VALUES "8"
+CREATED "April 22, 2008"
+
+KEYWORD "INDEX"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+INDEX CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 8
+BEGIN_DATA
+0 0.0000 0.0000 0.0000 0.0000 96.420 100.00 82.490
+1 100.00 0.0000 0.0000 0.0000 12.000 18.000 48.000
+2 0.0000 100.00 0.0000 0.0000 38.000 19.000 20.000
+3 100.00 0.0000 0.0000 45.486 3.2503 4.8706 13.063
+4 0.0000 17.988 100.00 0.0000 59.720 57.803 8.0538
+5 100.00 0.0000 100.00 40.023 3.1381 4.8335 2.1311
+6 0.0000 100.00 100.00 18.089 19.420 9.9765 1.7309
+7 0.0000 31.327 0.0000 100.00 0.65916 0.54433 0.57384
+END_DATA
+CTI1
+
+DESCRIPTOR "Argyll Calibration Target chart information 1"
+ORIGINATOR "Argyll targen"
+KEYWORD "DEVICE_COMBINATION_VALUES"
+DEVICE_COMBINATION_VALUES "9"
+CREATED "April 22, 2008"
+
+KEYWORD "INDEX"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+INDEX CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 9
+BEGIN_DATA
+0 0.0000 0.0000 0.0000 0.0000 96.420 100.00 82.490
+1 100.00 0.0000 0.0000 0.0000 12.000 18.000 48.000
+2 0.0000 100.00 0.0000 0.0000 38.000 19.000 20.000
+3 100.00 100.00 0.0000 0.0000 4.7293 3.4200 11.638
+4 0.0000 0.0000 100.00 0.0000 76.000 81.000 11.000
+5 100.00 0.0000 100.00 0.0000 9.4586 14.580 6.4008
+6 0.0000 100.00 100.00 0.0000 29.952 15.390 2.6670
+7 100.00 100.00 100.00 100.00 0.038661 0.027702 0.018813
+8 40.000 40.000 40.000 0.0000 19.978 17.645 12.009
+END_DATA
diff --git a/target/FograStrip3_3.ti2 b/target/FograStrip3_3.ti2
new file mode 100644
index 0000000..8f9822e
--- /dev/null
+++ b/target/FograStrip3_3.ti2
@@ -0,0 +1,101 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2"
+ORIGINATOR "Manualy created for FOGRA strip #3 in 3 strip layout (E3Z)"
+CREATED "Thu Jan 12 15:06:24 2011"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth SpectroScan"
+KEYWORD "APPROX_WHITE_POINT"
+APPROX_WHITE_POINT "83.77 87.26 66.79"
+KEYWORD "TOTAL_INK_LIMIT"
+TOTAL_INK_LIMIT "270.0"
+KEYWORD "COLOR_REP"
+COLOR_REP "CMYK"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "24"
+KEYWORD "PASSES_IN_STRIPS"
+PASSES_IN_STRIPS "3"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 9
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC CMYK_C CMYK_M CMYK_Y CMYK_K XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 72
+BEGIN_DATA
+1 "A1" 100 0 0 0 14.91 22.41 53.72
+2 "A2" 70 0 0 0 24.6 32.11 56.56
+3 "A3" 40 0 0 0 41.86 48.84 63.97
+4 "A4" 20 0 0 0 59.49 65.47 69.4
+5 "A5" 10 0 0 0 71.85 76.74 72.45
+6 "A6" 0 100 0 0 35.87 18.39 16.7
+7 "A7" 0 70 0 0 42.6 27.5 24.95
+8 "A8" 0 40 0 0 56.48 44.98 40.26
+9 "A9" 0 20 0 0 69.77 63.34 55.08
+10 "A10" 0 10 0 0 79.71 77.36 66.28
+11 "A11" 0 0 100 0 74.36 78.79 7.06
+12 "A12" 0 0 70 0 75.77 80.62 16.06
+13 "A13" 0 0 40 0 78.94 83.73 32.04
+14 "A14" 0 0 20 0 82.9 87.23 49.82
+15 "A15" 0 0 10 0 85.2 88.98 61.85
+16 "A16" 0 0 0 10 67.91 70.15 58.39
+17 "A17" 0 0 0 20 49.47 51.05 42.55
+18 "A18" 0 0 0 40 30.07 30.99 26.02
+19 "A19" 0 0 0 60 15.9 16.31 13.78
+20 "A20" 0 0 0 80 7.04 7.13 6.22
+21 "A21" 0 0 0 100 1.69 1.61 1.67
+22 "A22" 0 100 0 100 1.41 1.14 1.48
+23 "A23" 0 70 70 60 9.68 7.17 3.38
+24 "A24" 0 0 70 80 7.27 7.64 3.38
+25 "B1" 100 100 0 0 4.35 2.81 13.31
+26 "B2" 70 70 0 0 12.04 10.07 21.64
+27 "B3" 40 40 0 0 28.32 26.36 35.63
+28 "B4" 20 20 0 0 47.53 46.5 50.03
+29 "B5" 10 10 0 0 64.23 64.56 61.64
+30 "B6" 0 100 100 0 32.69 17.25 2.74
+31 "B7" 0 70 70 0 39.4 25.83 7.73
+32 "B8" 0 40 40 0 52.14 42.32 20.67
+33 "B9" 0 20 20 0 66.2 60.84 38.79
+34 "B10" 0 10 10 0 77.01 75.27 54.63
+35 "B11" 100 0 100 0 6.66 16.31 5.63
+36 "B12" 70 0 70 0 16.97 26.86 13.73
+37 "B13" 40 0 40 0 35.31 44.25 29.06
+38 "B14" 20 0 20 0 55.17 62.38 46.73
+39 "B15" 10 0 10 0 69.88 75.46 59.92
+40 "B16" 10 6 6 0 66.27 68.73 60.0
+41 "B17" 20 12 12 0 48.71 50.74 45.17
+42 "B18" 40 27 27 0 28.15 29.54 26.91
+43 "B19" 60 45 45 0 15.65 16.58 15.62
+44 "B20" 80 65 65 0 7.41 7.92 7.94
+45 "B21" 100 85 85 0 3.11 3.51 4.29
+46 "B22" 100 0 0 100 1.00 1.07 1.42
+47 "B23" 20 100 70 60 6.34 3.91 2.68
+48 "B24" 70 0 70 80 3.22 4.15 3.04
+49 "C1" 100 100 100 0 2.42 2.16 2.69
+50 "C2" 70 70 70 0 8.92 8.36 6.83
+51 "C3" 40 40 40 0 24.72 24.12 18.8
+52 "C4" 20 20 20 0 44.17 44.18 35.62
+53 "C5" 10 10 10 0 61.84 62.76 51.51
+54 "C6" 20 70 70 0 26.95 19.18 7.57
+55 "C7" 40 70 70 20 13.71 10.9 5.89
+56 "C8" 40 100 100 20 10.62 6.33 2.41
+57 "C9" 40 100 40 20 11.7 6.77 7.24
+58 "C10" 40 40 100 20 16.45 16.81 3.73
+59 "C11" 100 40 100 20 3.62 6.84 3.5
+60 "C12" 100 40 40 20 5.33 8.00 12.8
+61 "C13" 100 100 40 20 2.75 2.07 6.41
+62 "C14" 10 40 40 0 43.46 36.9 20.39
+63 "C15" 0 40 100 0 49.78 40.72 4.88
+64 "C16" 0 100 40 0 34.02 17.62 9.73
+65 "C17" 40 100 0 0 16.66 9.11 14.75
+66 "C18" 40 0 100 0 31.1 40.61 6.39
+67 "C19" 100 0 40 0 9.99 19.02 25.24
+68 "C20" 100 40 0 0 9.18 11.79 30.55
+69 "C21" 0 0 0 0 87.38 90.38 75.45
+70 "C22" 0 0 100 100 1.57 1.54 1.33
+71 "C23" 0 70 0 60 10.61 7.67 7.74
+72 "C24" 70 0 0 80 3.84 4.59 6.23
+END_DATA
+
+
diff --git a/target/Jamfile b/target/Jamfile
new file mode 100644
index 0000000..3a3ef28
--- /dev/null
+++ b/target/Jamfile
@@ -0,0 +1,74 @@
+
+# Print Calibration Target Data File generator
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Link debugging flags
+#PREF_CCFLAGS += $(CCPROFFLAG) ; # Profile flags
+#PREF_LINKFLAGS += $(LINKPROFFLAG) ; # Profile link flags
+
+#Products
+Executables = targen printtarg ;
+Samples = ECI2002.ti2
+ ECI2002R.ti2
+ ColorChecker.ti2
+ FograStrip2.ti1 FograStrip2_2.ti2
+ FograStrip3.ti1 FograStrip3_3.ti2
+ i1_RGB_Scan_1.4.ti2 ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+InstallFile $(DESTDIR)$(PREFIX)/$(REFSUBDIR) : $(Samples) ;
+
+HDRS = ../h ../numlib ;
+
+Objects alphix.c randix.c ;
+
+HDRS += ../plot ../rspl ../cgats ../icc ../gamut ../xicc ../spectro ../render $(TIFFINC) ;
+
+LINKLIBS = ../xicc/libxcolorants ../spectro/libconv ../xicc/libxicc ../spectro/libinsttypes
+ ../gamut/libgamut ../rspl/librspl ../render/librender ../cgats/libcgats
+ ../plot/libplot ../plot/libvrml ../icc/libicc ../numlib/libnum
+ $(TIFFLIB) $(JPEGLIB) $(LibWin) ;
+
+
+#target generator
+Main targen : targen.c ofps.c ifarp.c simplat.c simdlat.c prand.c ;
+
+# Film Calibration Target File generator
+Main filmtarg : filmtarg.c : : : $(TIFFINC) : alphix randix : $(TIFFLIB) $(JPEGLIB) ;
+
+# Print Calibration Target Postscript File generator
+Main printtarg : printtarg.c : : : : alphix randix : ;
+
+# Individual stand alone test of sample point classes
+
+# Percepttual point distribution
+#MainVariant ppoint : ppoint.c : : STANDALONE_TEST ;
+
+# Optimised farthest point sampling class
+MainVariant ofps : ofps.c : : STANDALONE_TEST ;
+
+# Incremental far point class
+MainVariant ifarp : ifarp.c : : STANDALONE_TEST ;
+
+# Perceptual space simplex lattice
+MainVariant ifarp : ifarp.c : : STANDALONE_TEST ;
+
+MainVariant simplat : simplat.c : : STANDALONE_TEST ;
+
+# Device space simplex lattice
+MainVariant simdlat : simdlat.c : : STANDALONE_TEST ;
+
+if $(BUILD_JUNK) {
+
+ # Test program
+ Main test : test.c : : : : alphix ;
+
+ # Test program
+ Main temp : temp.c ;
+
+ # Test lmean experiment
+ Main lmean : lmean.c ;
+}
diff --git a/target/License.txt b/target/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/target/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/target/Makefile.am b/target/Makefile.am
new file mode 100644
index 0000000..d9f050b
--- /dev/null
+++ b/target/Makefile.am
@@ -0,0 +1,28 @@
+include $(top_srcdir)/Makefile.shared
+
+CPPFLAGS+=-D_FORTIFY_SOURCE=2
+
+privatelib_LTLIBRARIES = libtarget.la
+privatelibdir = $(pkglibdir)
+
+libtarget_la_SOURCES = alphix.c alphix.h randix.c randix.h
+
+LDADD = ./libtarget.la ../rspl/librspl.la ../plot/libvrml.la \
+ $(ICC_LIBS) ../render/librender.la ../cgats/libcgats.la \
+ ../xicc/libxicc.la ../gamut/libgamut.la \
+ ../spectro/libinsttypes.la ../spectro/libconv.la \
+ ../numlib/libargyllnum.la ../libargyll.la $(TIFF_LIBS)
+
+bin_PROGRAMS = targen printtarg
+
+targen_DEPENDENCIES = ../spectro/libinsttypes.la
+targen_SOURCES = targen.c targen.h ofps.c ofps.h ifarp.c ifarp.h \
+ simplat.c simplat.h simdlat.c simdlat.h prand.c prand.h
+
+printtarg_SOURCES = printtarg.c
+
+refdir = $(datadir)/color/argyll/ref
+
+ref_DATA = $(wildcard *.ti2)
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/target/Readme.txt b/target/Readme.txt
new file mode 100644
index 0000000..99a8317
--- /dev/null
+++ b/target/Readme.txt
@@ -0,0 +1,13 @@
+This directory containts routines that generate print or
+film calibration test charts, based on perceptually evenly
+distributed, random sequence points, suitable for reading
+using an Xrite DTP51 coloromiter or Xrite DTP41 spectromter
+(print) or Gretag Spectrolino (film). The generated print
+file is a PostScript file, while the film recorder file is
+a TIFF file.
+
+targen Is used to generate the test point values.
+
+target Is used to generate a PostScript file from those values.
+
+
diff --git a/target/afiles b/target/afiles
new file mode 100644
index 0000000..4b06b9f
--- /dev/null
+++ b/target/afiles
@@ -0,0 +1,32 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+randix.c
+randix.h
+alphix.c
+alphix.h
+targen.c
+targen.h
+printtarg.c
+filmtarg.c
+ppoint.c
+ppoint.h
+ofps.h
+ofps.c
+simplat.h
+simplat.c
+simdlat.h
+simdlat.c
+ifarp.h
+ifarp.c
+prand.h
+prand.c
+ColorChecker.ti2
+FograStrip2.ti1
+FograStrip2_2.ti2
+FograStrip3.ti1
+FograStrip3_3.ti2
+i1_RGB_Scan_1.4.ti2
+ECI2002.ti2
+ECI2002R.ti2
diff --git a/target/alphix.c b/target/alphix.c
new file mode 100644
index 0000000..68dfd48
--- /dev/null
+++ b/target/alphix.c
@@ -0,0 +1,468 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Alphabetic index class.
+ *
+ * Author: Graeme W. Gill
+ * Date: 22/8/2005
+ *
+ * Copyright 2005, 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.
+ */
+
+/* TTBD:
+ It would be nice if it was possible to add a delimeter between
+ the X and Y identifiers so that number + number or alpha + alpha
+ identification was possible.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "numsup.h"
+#include "alphix.h"
+
+/* Return the alpha index for the given raw index number */
+/* Return NULL on error */
+static char *torawix(alphix *p, int ix) {
+ int i, j, n;
+ int z = 0;
+ char *rv, *v;
+
+ if (ix < 0 || ix >= p->rmct)
+ return NULL; /* Index range error */
+
+ if ((rv = malloc((p->nd+1) * sizeof(char))) == NULL)
+ return NULL;
+
+ for (v = rv, j = 0, i = p->nd-1; i >= 0; j++, i--) {
+ char c;
+ n = ix / p->ds[i].b;
+ ix -= n * p->ds[i].b;
+ c = p->ds[i].seq[n];
+ if (p->ds[i].z && z == 0 && c == '0')
+ c = ' ';
+ if (z != 0 || c != ' ') {
+ *v++ = p->ds[i].seq[n];
+ z = 1;
+ }
+ }
+ *v = '\000';
+
+ return rv;
+}
+
+/* Return the the raw index number given the alpha index */
+/* return -1 on error */
+static int fromanat(alphix *p, char *ax) {
+ char *v, *tb, _tb[11];
+ int cl;
+ int i, k, rv = 0;
+
+ if (p->nd > 10) {
+ if ((tb = malloc((p->nd+1) * sizeof(char))) == NULL)
+ return -1; /* Malloc error */
+ } else
+ tb = _tb;
+
+ /* Pack the string out to the right number of digits with spaces. */
+ cl = strlen(ax);
+ for (v = tb; cl < p->nd; v++, cl++)
+ *v = ' ';
+ strcpy(v, ax);
+
+ /* For each digit, convert to numerical and accumulate */
+ for (v = tb, i = p->nd-1; i >= 0; v++, i--) {
+ for (k = 0; k < p->ds[i].n; k++) {
+ if (*v == p->ds[i].seq[k]
+ || (p->ds[i].z && *v == ' ' && p->ds[i].seq[k] == '0')) {
+ rv += k * p->ds[i].b;
+ break;
+ }
+ }
+ if (k >= p->ds[i].n) {
+ if (tb != _tb)
+ free(tb);
+ return -1; /* Unknown digit */
+ }
+ }
+
+ if (tb != _tb)
+ free(tb);
+
+ return rv;
+}
+
+/* Working from the end of the string, */
+/* return a pointer to the maximum number of characters */
+/* that are legaly part of this alpha index. */
+static char *find_start(alphix *p, char *ax) {
+ int i, k;
+ char *v;
+
+ v = ax + strlen(ax) - 1; /* start at last character */
+ for (i = 0; v >= ax && i < p->nd; v--, i++) { /* working backwards */
+ for (k = 0; k < p->ds[i].n; k++) { /* Locate */
+ if (*v == p->ds[i].seq[k])
+ break; /* Found */
+ }
+ if (k >= p->ds[i].n) /* Not found */
+ break;
+ }
+ return v+1;
+}
+
+/* Convert from cooked index to raw index. */
+/* Return -1 if out of range */
+static int cookedtoraw(alphix *p, int ix) {
+ int i;
+
+ if (p->nr == 0)
+ return ix;
+
+ for (i = 0; i < p->nr; i++) {
+ if (ix >= p->rs[i].c0 && ix <= p->rs[i].c1) {
+ ix = ix - p->rs[i].c0 + p->rs[i].r0;
+ return ix;
+ }
+ }
+ return -1;
+}
+
+/* Convert from raw index to cooked index. */
+/* Return -1 if out of range */
+static int rawtocooked(alphix *p, int ix) {
+ int i;
+
+ if (p->nr == 0)
+ return ix;
+
+ for (i = 0; i < p->nr; i++) {
+ if (ix >= p->rs[i].r0 && ix <= p->rs[i].r1) {
+ ix = ix - p->rs[i].r0 + p->rs[i].c0;
+ return ix;
+ }
+ }
+ return -1;
+}
+
+/* Return the maximum possible length of count */
+static int alphix_maxlen(alphix *p) {
+ return p->cmct;
+}
+
+/* Return the alpha index for the given index number (0 based) */
+/* Return NULL on error */
+/* (Free after use) */
+static char *alphix_aix(alphix *p, int ix) {
+ if ((ix = cookedtoraw(p, ix)) < 0)
+ return NULL;
+ return torawix(p, ix);
+}
+
+/* Return the index number for the given alpha index */
+int alphix_nix(alphix *p, char *ax) {
+ int rv;
+ if ((rv = fromanat(p, ax)) < 0)
+ return -1;
+ return rawtocooked(p, rv);
+}
+
+/* Destroy ourselves */
+static void
+alphix_del(alphix *p) {
+ int i;
+ for (i = 0; i < p->nd; i++)
+ free(p->ds[i].seq);
+ free (p->ds);
+ free (p->rs);
+ free (p);
+}
+
+/* Constructor: */
+alphix *new_alphix(char *pattern) {
+ alphix *p;
+ char *pp = pattern;
+ int i;
+
+ if ((p = (alphix *)calloc(1,sizeof(alphix))) == NULL)
+ error("alphix: malloc failed");
+
+ p->maxlen = alphix_maxlen;
+ p->aix = alphix_aix;
+ p->nix = alphix_nix;
+ p->del = alphix_del;
+
+ /* We now need to parse the pattern to setup our index sequence: */
+ /* For all digits */
+ for (p->nd = 0; ; p->nd++) {
+
+ if (*pp == '\000' || *pp == ';') {
+ break;
+ }
+
+ /* We are starting a new digit sequence */
+ if (p->nd >= p->_nd) { /* Allocate space for current digit */
+ p->_nd = 2 + p->_nd;
+ if ((p->ds = (dig *)realloc(p->ds, p->_nd * sizeof(dig))) == NULL)
+ error ("alphix: realloc failed");
+ }
+
+ p->ds[p->nd].n = 0;
+ p->ds[p->nd].seq = NULL;
+ p->ds[p->nd]._n = 0;
+ p->ds[p->nd].z = 0;
+
+ /* For all symbols in this digit */
+ for (p->ds[p->nd].n = 0; ;) {
+ char c, c1, c2;
+
+ /* We are adding another character to the sequence */
+ if (*pp == '\000' || *pp == ';' || *pp == ',')
+ break; /* Done this digit */
+ if (pp[1] == '-' && pp[2] != '\000' && pp[2] != ';' && pp[2] != ',') {
+ c1 = pp[0];
+ c2 = pp[2];
+ pp += 3;
+ } else {
+ c1 = c2 = *pp;
+ pp++;
+ }
+ if (c1 == '@') {
+ c1 = '0';
+ p->ds[p->nd].z = 1;
+ }
+ if (c2 == '@') {
+ c2 = '0';
+ p->ds[p->nd].z = 1;
+ }
+
+ /* Expand digit sequence */
+ for (c = c1; c <= c2; c++) {
+
+ if (p->ds[p->nd].n >= p->ds[p->nd]._n) { /* Allocate space for next character */
+ p->ds[p->nd]._n = 20 + p->ds[p->nd]._n;
+ if ((p->ds[p->nd].seq = (char *)realloc(p->ds[p->nd].seq, p->ds[p->nd]._n * sizeof(char))) == NULL)
+ error ("alphix: realloc failed");
+ }
+ p->ds[p->nd].seq[p->ds[p->nd].n++] = c;
+ }
+ }
+ if (*pp == '\000' || *pp == ';')
+ continue;
+ pp++;
+
+ }
+
+ /* Compute the native maximum index count */
+ for (p->rmct = 1, i = 0; i < p->nd; i++) {
+ p->ds[i].b = p->rmct;
+ p->rmct *= p->ds[i].n;
+ }
+
+ /* Search for valid ranges */
+ if (*pp == ';') {
+ char *v, *tb, _tb[11];
+
+ pp++;
+ if (p->nd > 10) {
+ if ((tb = malloc((p->nd+1) * sizeof(char))) == NULL)
+ error ("alphix: malloc failed");
+ } else
+ tb = _tb;
+
+ /* For each range */
+ for (p->nr = 0; ; p->nr++) {
+
+ if (*pp == '\000' || *pp == ';')
+ break;
+
+ /* We are adding a new range */
+ if (p->nr >= p->_nr) { /* Allocate space for current range */
+ p->_nr = 2 + p->_nr;
+ if ((p->rs = (rngsq *)realloc(p->rs, p->_nr * sizeof(rngsq))) == NULL)
+ error ("alphix: realloc failed");
+ }
+
+ /* Locate the end of the range start */
+ for(v = tb; *pp != '\000' && *pp != '-' && *pp != ','; v++, pp++)
+ *v = *pp;
+ *v = '\000';
+ p->rs[p->nr].r0 = p->rs[p->nr].r1 = fromanat(p, tb);
+ if (p->rs[p->nr].r0 < 0)
+ error("alphix: range start definition error on '%s'",tb);
+
+
+ if (*pp != '-') { /* oops - bad definition */
+ error("alphix: range definition error - missing '-'");
+ }
+
+ /* Locate the end of the range end */
+ for(v = tb, pp++; *pp != '\000' && *pp != ','; v++, pp++)
+ *v = *pp;
+ *v = '\000';
+ p->rs[p->nr].r1 = fromanat(p, tb);
+ if (p->rs[p->nr].r1 < 0)
+ error("alphix: range end definition error on '%s'",tb);
+
+ if (p->rs[p->nr].r1 < p->rs[p->nr].r0) /* Hmm */
+ error("alphix: range definition error, end < start ");
+
+ /* Compute cooked index range */
+ p->rs[p->nr].c0 = 0;
+ p->rs[p->nr].c1 = p->rs[p->nr].r1 - p->rs[p->nr].r0;
+ if (p->nr > 0) {
+ int ofs = p->rs[p->nr-1].c1+1;
+ p->rs[p->nr].c0 += ofs;
+ p->rs[p->nr].c1 += ofs;
+ }
+
+ if (*pp == '\000' || *pp == ';')
+ continue;
+ pp++;
+ }
+
+ if (tb != _tb)
+ free(tb);
+ }
+
+ /* Compute cooked actual range */
+ p->cmct = p->rmct;
+ if (p->nr > 0) {
+ p->cmct = p->rs[p->nr-1].c1+1;
+ }
+
+#ifdef NEVER
+ // ###########################################################
+ /* Debug stuff */
+ printf("~1 There are %d digits, %d ranges, raw max = %d, cooked max = %d\n",
+ p->nd,p->nr,p->rmct, p->maxlen(p));
+
+ /* Digit sequences */
+ for (i = 0; i < p->nd; i++) {
+ printf(" ~1 Digit %d has %d symbols\n",i,p->ds[i].n);
+ for (j = 0; j < p->ds[i].n; j++)
+ printf(" ~1 symbol %d = '%c'\n",j,p->ds[i].seq[j]);
+ }
+
+ /* Ranges */
+ for (i = 0; i < p->nr; i++) {
+ printf(" ~1 Range %d is raw %d - %d, cooked %d - %d\n",
+ i,p->rs[i].r0, p->rs[i].r1, p->rs[i].c0, p->rs[i].c1);
+ }
+
+ /* Itterate the sequence */
+ for (i = 0; i < p->cmct; i++) {
+ char *v;
+ v = p->aix(p, i);
+ printf("ix %d -> '%s'\n",i,v);
+ free(v);
+ }
+ // ###########################################################
+#endif /* NEVER */
+
+ return p;
+}
+
+
+/* ==================================================================== */
+/* Utility function: */
+/* Given the strip and patch alphix objects, and order flag, */
+/* Return a patch location. Free the returned string after use. */
+/* Return NULL on error */
+char *patch_location(
+ alphix *saix, /* Strip alpha index object */
+ alphix *paix, /* Patch alpha index object */
+ int ixord, /* Index order, 0 = strip then patch */
+ int six, /* Strip index */
+ int pix /* Patch index */
+) {
+ char *sl, *pl, *rv;
+ int ll;
+
+ if ((sl = saix->aix(saix, six)) == NULL)
+ return NULL;
+
+ if ((pl = paix->aix(paix, pix)) == NULL) {
+ free (sl);
+ return NULL;
+ }
+ ll = strlen(sl) + strlen(pl) + 1;
+ if ((rv = malloc(ll * sizeof(char))) == NULL) {
+ free (pl);
+ free (sl);
+ return NULL;
+ }
+
+ if (ixord == 0) {
+ strcpy (rv, sl);
+ strcat (rv, pl);
+ } else {
+ strcpy (rv, pl);
+ strcat (rv, sl);
+ }
+ return rv;
+}
+
+/* ==================================================================== */
+/* Utility function: */
+/* Given the strip and patch alphix objects, and order flag, */
+/* and a corresonding patch location string, return an index */
+/* number suitable for sorting location strings. */
+/* The sort order is in order of strips, then patches within each strip */
+/* Return -1 on error */
+int patch_location_order(
+ alphix *saix, /* Strip alpha index object */
+ alphix *paix, /* Patch alpha index object */
+ int ixord, /* Index order, 0 = strip then patch */
+ char *_ax /* Patch location string */
+) {
+ char *ax; /* Copy of input string */
+ char *v;
+ alphix *rh; /* Least significant, right hand alphix */
+ alphix *lh; /* Most significant, left hand alphix */
+ int ri, li; /* Right hand and left hand index numbers */
+
+ if ((ax = malloc(strlen(_ax)+1)) == NULL)
+ return -1;
+ strcpy(ax,_ax);
+
+ if (ixord == 0) {
+ lh = saix; /* Strip is left hand */
+ rh = paix; /* Patch is right hand */
+ } else {
+ rh = saix; /* Strip is right hand */
+ lh = paix; /* Patch is left hand */
+ }
+
+ /* We need to identify the boundary between */
+ /* the right hand and left hand indexes. */
+ /* We assume that the sequences are distinguishable ... */
+ v = find_start(rh, ax);
+
+ ri = rh->nix(rh, v);
+ *v = '\000';
+ li = lh->nix(lh, ax);
+ free(ax);
+ if (ri < 0 || li < 0)
+ return -1;
+
+ if (ixord == 0) /* Strip is left hand */
+ return li * rh->cmct + ri;
+ else
+ return ri * lh->cmct + li;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/target/alphix.h b/target/alphix.h
new file mode 100644
index 0000000..091c191
--- /dev/null
+++ b/target/alphix.h
@@ -0,0 +1,118 @@
+
+#ifndef ALPHIX_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Alphabetic indexing class
+ *
+ * Author: Graeme W. Gill
+ * Date: 22/8/2005
+ *
+ * Copyright 2005, 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.
+ */
+
+/*
+ *
+ * Syntax of alphix pattern:
+ *
+ * First comes the definition of the symbols for each digit
+ * location, LS to MS. The number of definitions declares the
+ * maximum number of digits. For example, for a normal 2 digit numerical
+ * sequence: "0123456789, 123456789" (note the space is significant)
+ * would define 0..99 with the MS digit supressed when it is 0.
+ * Ranges can be used for brevity: * "0-9, 1-9".
+ * As a special case, the '@' character can be used
+ * instead of '0' to indicate suppression of the leading zero.
+ * Leading ' ' characters in a generated sequence are omitted.
+ *
+ * Optional, and delimited by a ';' character, valid segments of the
+ * index sequence can be defined. For instance, to define the index
+ * range to be 1..49 one could use the pattern "0-9, 1-9;1-49"
+ *
+ * Of course the main reason for using alphix is to allow letter index
+ * sequences. For a sequence A, B, C .. AA, AB, AC etc. (the default
+ * used in Argyll), the following pattern would be used: "A-Z, A-Z"
+ *
+ * For a some ECI2002R charts that skip columns Y and Z, the following
+ * might be used: "A-Z, 2-9;A-X,2A-9Z"
+ */
+
+#define ALPHIX_MAX 4 /* Maximum digits allowed */
+
+/* Definition for each digit sequence */
+typedef struct {
+ int n; /* Number of characters in sequence */
+ char *seq; /* Sequence of characters */
+ int _n; /* Allocation size of seq */
+ int b; /* Base of this digit */
+ int z; /* NZ if leading zero is to be supressed */
+} dig;
+
+/* Definition for each range sequence */
+typedef struct {
+ int r0,r1; /* Raw index start and end of range */
+ int c0,c1; /* Cooked index start and end of range */
+} rngsq;
+
+struct _alphix {
+/* private: */
+ int nd; /* Number of digits */
+ dig *ds; /* Digit sequences */
+ int _nd; /* Allocation size of ds */
+ int rmct; /* Raw maximum count */
+ int cmct; /* Cooked maximum count */
+
+ int nr; /* Number of ranges */
+ rngsq *rs; /* Digit sequences */
+ int _nr; /* Allocation size of rs */
+
+/* public: */
+ /* Return the maximum possible length of count */
+ int (*maxlen)(struct _alphix *p);
+
+ /* Return the alpha index for the given index number (0 based) */
+ /* Return NULL on error */
+ char *(*aix)(struct _alphix *p, int ix);
+
+ /* Return the index number for the given alpha index */
+ /* Return -1 on error */
+ int (*nix)(struct _alphix *p, char *ax);
+
+ /* Destroy ourselves */
+ void (*del)(struct _alphix *p);
+
+}; typedef struct _alphix alphix;
+
+/* Constructor: */
+extern alphix *new_alphix(char *pattern);
+
+
+/* Utility function: */
+/* Given the strip and patch alhix objects, and order flag, */
+/* Return a patch location. */
+/* Return NULL on error */
+char *patch_location(
+ alphix *saix, /* Strip alpha index object */
+ alphix *paix, /* Patch alpha index object */
+ int ixord, /* Index order, 0 = strip then patch */
+ int six, /* Strip index (from 0) */
+ int pix); /* Patch index (from 0) */
+
+/* Utility function: */
+/* Given the strip and patch alphix objects, and order flag, */
+/* and a coresonding patch location string, return an index */
+/* number suitable for sorting location strings. */
+/* Return -1 on error */
+int patch_location_order(
+ alphix *saix, /* Strip alpha index object */
+ alphix *paix, /* Patch alpha index object */
+ int ixord, /* Index order, 0 = strip then patch */
+ char *_ax); /* Patch location string */
+
+#define ALPHIX_H
+#endif /* ALPHIX_H */
diff --git a/target/filmtarg.c b/target/filmtarg.c
new file mode 100644
index 0000000..af341dd
--- /dev/null
+++ b/target/filmtarg.c
@@ -0,0 +1,458 @@
+/*
+ * Argyll Color Correction System
+ * Film recorder chart generator module.
+ *
+ * Author: Neil Okamoto
+ * Date: 1/3/2001
+ *
+ * Copyright 2001, DreamWorks LLC
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 :-
+ * see the License2.txt file for licencing details.
+ */
+
+/* This program generates a set of TIFF images containing color test patches,
+ * given the .ti1 file specifying what the colors are.
+ *
+ * The output is designed to facilitate output on a 35mm motion picture film
+ * recorder such as those manufactured by Cineon, Celco, MGI, ARRI, etc. */
+
+/* Description:
+ *
+ */
+
+/* TTBD:
+ *
+ * - eliminate gamma hack -- do it correctly in targen.
+ * - write a proper description
+ * - multi-patch mosaics on a single tiff image
+ * - render text labels into images
+ */
+
+#undef DEBUG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <ctype.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "cgats.h"
+#include "randix.h"
+#include "tiffio.h"
+
+#include <stdarg.h>
+void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...);
+
+/* A color structure */
+/* This can hold all representations simultaniously */
+typedef struct {
+ int t; /* Tag */
+#define T_W 0x1
+#define T_RGB 0x2
+#define T_CMYK 0x4
+ double gy;
+ double r,g,b;
+ double c,m,y,k;
+ char *id; /* Id string */
+ char loc[5]; /* Location ID string */
+} col;
+
+
+void
+generate_tiffs(
+char *basename, /* Base file name for output tiffs */
+col *cols, /* Array of colors to be put on target chart */
+int npat, /* Number of test targets needed */
+char *label, /* Per set label */
+int pw, int ph, /* Patch width and height */
+int rand, /* Randomise flag */
+int rstart, /* Starting index for random */
+int verb) /* Verbose flag */
+{
+ randix *r = NULL; /* Random index order object */
+ int ix; /* Patch index in target list */
+ int i; /* Logical patch in target list */
+ char slab[6]; /* Strip label */
+ char fname[200]; /* File name */
+ TIFF *tiff; /* TIFF file handle */
+ unsigned short* scanline; /* scanline buffer */
+ int x,y; /* position in TIFF image */
+
+ if (rand)
+ r = new_randix(npat, rstart);
+
+ i = 0;
+ while (i < npat) {
+
+ if (rand)
+ ix = r->next(r); /* Next pseudo random index */
+ else
+ ix = i;
+
+ sprintf(slab, "P%04d",i+1);
+ strcpy(cols[ix].loc, slab);
+ sprintf(fname, "%s.%04d.tiff", basename, i+1);
+
+ if ((tiff = TIFFOpen(fname, "w")) == NULL) {
+ fprintf(stderr,"Failed to open output %s\n", fname);
+ exit(-1);
+ }
+
+ if (!(scanline = (unsigned short*)malloc(3*sizeof(short)*pw))) {
+ fprintf(stderr,"Failed to malloc a scanline buffer\n");
+ exit(-1);
+ }
+
+ TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, pw);
+ TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, ph);
+ TIFFSetField(tiff, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 16);
+ TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
+
+ if (verb) {
+ printf("writing patch %4d (%4.2f %4.2f %4.2f) to %s\n",
+ ix, cols[ix].r, cols[ix].g, cols[ix].b, fname);
+ }
+
+ /* fill scanline */
+ for (x=0; x<pw; x++) {
+ int xx = 3*x;
+ scanline[xx++] = (unsigned short)((cols[ix].r * 65535.0) + 0.5);
+ scanline[xx++] = (unsigned short)((cols[ix].g * 65535.0) + 0.5);
+ scanline[xx] = (unsigned short)((cols[ix].b * 65535.0) + 0.5);
+ }
+ for (y=0; y<ph; y++) {
+ if (TIFFWriteScanline(tiff, (tdata_t)scanline, y, 0) < 0) {
+ fprintf(stderr,"WriteScanline Failed at line %d\n",y);
+ exit (-1);
+ }
+ }
+ TIFFClose(tiff);
+ free(scanline);
+
+ i++;
+ }
+
+ if (rand)
+ r->del(r);
+
+}
+
+/* film size structure */
+typedef struct {
+ char *name; /* User name (lower case) */
+ int w,h; /* Width and height in pixels */
+} film;
+
+static film filmsizes[] = {
+ { "Acad_Full", 3656, 2664 },
+ { "Acad_Half", 1828, 1332 },
+ { "Cscope_Full", 3656, 3112 },
+ { "Cscope_Half", 1828, 1556 },
+ { "FullAp_Full", 4096, 3112 },
+ { "FullAp_Half", 2048, 1556 },
+ { "Vista_Full", 4096, 6144 },
+ { "Vista_Half", 2048, 3072 },
+ { NULL, 0, 0 }
+};
+
+/* Case independent string compare */
+int
+cistrcmp(char *s1, char *s2) {
+ for (;;s1++, s2++) {
+ if (tolower(*s1) != tolower(*s2))
+ return 1;
+ if (*s1 == '\000')
+ return 0;
+ }
+}
+
+void
+usage(void) {
+ film *ff;
+ fprintf(stderr,"Generate Film Target image sequence, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Licensed under the GPL\n");
+ fprintf(stderr,"usage: filmtarg [-v] [-r] [-g gamma] [-f format] basename\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -r Don't randomise patch location\n");
+ fprintf(stderr," -g gamma Gamma correction / linearization\n");
+ fprintf(stderr," -f format Select format from:\n");
+ for (ff = filmsizes; ff->name != NULL; ff++)
+ fprintf(stderr," \t%s\t[%d x %d]\n", ff->name, ff->w, ff->h);
+ fprintf(stderr," basename Base name for input(.ti1)/output(.ti2)\n");
+ exit(1);
+}
+
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int fa,nfa; /* current argument we're looking at */
+ int verb = 0;
+ int rand = 1;
+ double gamma = 1.0;
+ static char inname[200] = { 0 }; /* Input cgats file base name */
+ static char outname[200] = { 0 }; /* Output cgats file base name */
+ static char tiffname[200] = { 0 }; /* Output postscrip file base name */
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ int i;
+ int si, fi, wi; /* sample id index, field index, keyWord index */
+ char *label = "Argyll Color Correction System - Development chart";
+ film *flm = &filmsizes[1]; /* Default film format = Academy Half */
+ col *cols;
+ int npat; /* Number of patches */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ char buf[100]; /* general sprintf buffer */
+ int rstart = 0; /* Random sequence start value */
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ if (argc <= 1)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++)
+ {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') /* Look for any flags */
+ {
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else
+ {
+ if ((fa+1) < argc)
+ {
+ if (argv[fa+1][0] != '-')
+ {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+ /* Randomisation */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R')
+ rand = 0;
+ /* Gamma */
+ else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') {
+ fa = nfa;
+ if (na == NULL) usage();
+ gamma = atof(na);
+ }
+ /* Image format */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage();
+ for (flm = filmsizes; flm->name != NULL; flm++) {
+ if (cistrcmp(na, flm->name) == 0)
+ break;
+ }
+ if (flm->name == NULL)
+ usage();
+ } else
+ usage();
+ }
+ else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(inname,argv[fa]);
+ strcat(inname,".ti1");
+ strcpy(outname,argv[fa]);
+ strcat(outname,".ti2");
+ strcpy(tiffname,argv[fa]);
+
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI1"); /* our special input type is Calibration Target Information 1 */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI1 format file");
+ if (icg->ntables < 1)
+ error ("Input file doesn't contain at least one table");
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ if ((cols = (col *)malloc(sizeof(col) * npat)) == NULL)
+ error("Malloc failed!");
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI2"); /* our special type is Calibration Target Information 2 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 2",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll filmtarg", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ /* Note what instrument this chart is setup for */
+ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", "GretagMacbeth SpectroScanT", NULL);
+
+ /* Copy various parameters through */
+ if ((wi = icg->find_kword(icg, 0, "SINGLE_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "SINGLE_DIM_STEPS",icg->t[0].kdata[wi], NULL);
+
+ if ((wi = icg->find_kword(icg, 0, "COMP_GREY_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "COMP_GREY_STEPS",icg->t[0].kdata[wi], NULL);
+
+ if ((wi = icg->find_kword(icg, 0, "MULTI_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "MULTI_DIM_STEPS",icg->t[0].kdata[wi], NULL);
+
+ if ((wi = icg->find_kword(icg, 0, "FULL_SPREAD_PATCHES")) >= 0)
+ ocg->add_kword(ocg, 0, "FULL_SPREAD_PATCHES",icg->t[0].kdata[wi], NULL);
+
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+ ocg->add_field(ocg, 0, "SAMPLE_LOC", cs_t);
+
+ if ((si = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error ("Input file doesn't contain field SAMPLE_ID");
+ if (icg->t[0].ftype[si] != nqcs_t)
+ error ("Field SAMPLE_ID is wrong type");
+
+ /* Figure out the color space */
+ if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error ("Input file doesn't contain keyword COLOR_REPS");
+ if (strcmp(icg->t[0].kdata[fi],"CMYK") == 0) {
+ error ("We don't support CMYK yet");
+ } else if (strcmp(icg->t[0].kdata[fi],"RGB") == 0) {
+ int ri, gi, bi;
+ if ((ri = icg->find_field(icg, 0, "RGB_R")) < 0)
+ error ("Input file doesn't contain field RGB_R");
+ if (icg->t[0].ftype[ri] != r_t)
+ error ("Field RGB_R is wrong type");
+ if ((gi = icg->find_field(icg, 0, "RGB_G")) < 0)
+ error ("Input file doesn't contain field RGB_G");
+ if (icg->t[0].ftype[gi] != r_t)
+ error ("Field RGB_G is wrong type");
+ if ((bi = icg->find_field(icg, 0, "RGB_B")) < 0)
+ error ("Input file doesn't contain field RGB_B");
+ if (icg->t[0].ftype[bi] != r_t)
+ error ("Field RGB_B is wrong type");
+ ocg->add_field(ocg, 0, "RGB_R", r_t);
+ ocg->add_field(ocg, 0, "RGB_G", r_t);
+ ocg->add_field(ocg, 0, "RGB_B", r_t);
+ ocg->add_kword(ocg, 0, "COLOR_REP","RGB", NULL);
+ if (gamma != 1.0) {
+ sprintf(buf, "%6.4f", gamma);
+ ocg->add_kword(ocg, 0, "GAMMA", buf, NULL);
+ }
+ for (i = 0; i < npat; i++) {
+ cols[i].t = T_RGB;
+ cols[i].id = ((char *)icg->t[0].fdata[i][si]);
+ /* normalized and possibly gamma corrected */
+ cols[i].r = pow(*((double *)icg->t[0].fdata[i][ri]) / 100.0, gamma);
+ cols[i].g = pow(*((double *)icg->t[0].fdata[i][gi]) / 100.0, gamma);
+ cols[i].b = pow(*((double *)icg->t[0].fdata[i][bi]) / 100.0, gamma);
+ }
+ } else if (strcmp(icg->t[0].kdata[fi],"W") == 0) {
+ error ("We don't support GRAY yet");
+ } else
+ error ("Input file keyword COLOR_REPS has unknown value");
+
+
+ if (verb)
+ printf("Film format chosen is %s [%d x %d]\n", flm->name, flm->w, flm->h);
+
+ if (rand) {
+ rstart = clk % npat;
+ sprintf(buf,"%d",rstart);
+ ocg->add_kword(ocg, 0, "RANDOM_START", buf, NULL);
+ }
+
+ generate_tiffs(tiffname, cols, npat, label, flm->w, flm->h, rand, rstart, verb);
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < npat; i++) {
+ if (cols[i].t & T_CMYK)
+ ocg->add_set(ocg, 0, cols[i].id, cols[i].loc, 100.0 * cols[i].c, 100.0 * cols[i].m,
+ 100.0 * cols[i].y, 100.0 * cols[i].k);
+ else if (cols[i].t & T_RGB)
+ ocg->add_set(ocg, 0, cols[i].id, cols[i].loc, 100.0 * cols[i].r,
+ 100.0 * cols[i].g, 100.0 * cols[i].b);
+ else if (cols[i].t & T_W)
+ ocg->add_set(ocg, 0, cols[i].id, cols[i].loc, 100.0 * cols[i].gy);
+ }
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ free(cols);
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"filmtarg: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"filmtarg: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+
+
+
+
+
+
diff --git a/target/i1_RGB_Scan_1.4.ti2 b/target/i1_RGB_Scan_1.4.ti2
new file mode 100644
index 0000000..8aaf081
--- /dev/null
+++ b/target/i1_RGB_Scan_1.4.ti2
@@ -0,0 +1,319 @@
+CTI2
+
+DESCRIPTOR "Argyll Calibration Target chart information 2 for Eye-One Scan Target 1.4"
+ORIGINATOR "Argyll printtarg"
+CREATED "Wed Sep 12 00:02:26 2007"
+KEYWORD "TARGET_INSTRUMENT"
+TARGET_INSTRUMENT "GretagMacbeth i1 Pro"
+KEYWORD "ACCURATE_EXPECTED_VALUES"
+ACCURATE_EXPECTED_VALUES "true"
+KEYWORD "COLOR_REP"
+COLOR_REP "RGB"
+KEYWORD "STEPS_IN_PASS"
+STEPS_IN_PASS "18"
+KEYWORD "PASSES_IN_STRIPS2"
+PASSES_IN_STRIPS2 "16"
+KEYWORD "STRIP_INDEX_PATTERN"
+STRIP_INDEX_PATTERN "0-9,@-9,@-9;1-999"
+KEYWORD "PATCH_INDEX_PATTERN"
+PATCH_INDEX_PATTERN "A-Z, A-Z"
+KEYWORD "INDEX_ORDER"
+INDEX_ORDER "PATCH_THEN_STRIP"
+
+KEYWORD "SAMPLE_LOC"
+NUMBER_OF_FIELDS 8
+BEGIN_DATA_FORMAT
+SAMPLE_ID SAMPLE_LOC RGB_R RGB_G RGB_B XYZ_X XYZ_Y XYZ_Z
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 288
+BEGIN_DATA
+1 "A1" 0 0 0 0.52 0.59 0.56
+2 "A2" 20 40 100 10.27 10 32.62
+3 "A3" 80 0 20 13.89 7.3 2.84
+4 "A4" 100 40 20 33.34 23.69 4.75
+5 "A5" 69.8 69.8 69.8 31.79 33.22 28.61
+6 "A6" 46.67 46.67 46.67 13.85 14.51 12.72
+7 "A7" 100 40 40 35.52 25.53 10.91
+8 "A8" 66.67 60 66.67 27.16 27.04 25.26
+9 "A9" 29.8 29.8 29.8 6.12 6.42 5.76
+10 "A10" 26.67 33.33 33.33 6.04 6.8 6.75
+11 "A11" 0 20 100 4.4 3.47 20.55
+12 "A12" 40 0 60 6.34 3.41 11.34
+13 "A13" 40 20 60 9.03 7.05 14.88
+14 "A14" 40 20 40 7.91 6.52 8.41
+15 "A15" 60 20 80 16.18 10.77 24.37
+16 "A16" 0 0 60 1.97 1.1 8.66
+17 "B1" 60 100 20 27.55 34.83 6.23
+18 "B2" 80 20 0 17.94 11.4 1.02
+19 "B3" 80 80 20 34.87 35.19 5.79
+20 "B4" 20 80 80 13.05 19.54 29.87
+21 "B5" 0 60 100 6.88 9.15 27.74
+22 "B6" 100 100 80 70.59 73.69 44.02
+23 "B7" 13.33 13.33 6.67 2.04 2.19 1.41
+24 "B8" 0 40 0 1.35 2.84 0.94
+25 "B9" 100 60 80 49.51 40.62 36.32
+26 "B10" 100 60 40 43.26 35.61 12.01
+27 "B11" 13.33 20 20 2.65 3.13 3.25
+28 "B12" 40 80 60 17.77 24.45 21.08
+29 "B13" 0 100 100 8.51 14.13 31.85
+30 "B14" 0 80 100 7.84 11.93 30.12
+31 "B15" 0 100 60 5.81 12.04 16.38
+32 "B16" 60 20 0 11.49 8.06 0.99
+33 "C1" 100 20 100 34.5 19.81 37.1
+34 "C2" 80 80 73.33 42.27 43.99 33.47
+35 "C3" 0 60 60 4.36 7.54 14.12
+36 "C4" 100 100 20 58.73 57.76 6.5
+37 "C5" 60 0 80 11.22 5.5 17.82
+38 "C6" 6.67 13.33 13.33 1.55 1.89 2.09
+39 "C7" 74.9 74.9 74.9 37.5 39.03 33.61
+40 "C8" 80 40 20 23.67 18.54 4.44
+41 "C9" 20 80 20 8.12 14.07 4.81
+42 "C10" 0 100 0 2.9 7.38 1.41
+43 "C11" 73.33 73.33 66.67 34.09 35.82 26.91
+44 "C12" 40 33.33 40 9.45 9.34 9.05
+45 "C13" 100 60 20 41.11 33.34 5.29
+46 "C14" 80 40 60 27.38 21.65 19.2
+47 "C15" 64.71 64.71 64.71 27.38 28.66 24.61
+48 "C16" 80 80 100 48.58 49.16 58.53
+49 "D1" 20 80 0 7.47 12.02 1.86
+50 "D2" 80 0 80 17.27 8.47 18.91
+51 "D3" 100 20 0 24.86 14.78 0.99
+52 "D4" 60 0 20 8.61 4.81 2.74
+53 "D5" 80 60 20 28.85 26.03 5.07
+54 "D6" 40 80 80 20.34 26.75 33.64
+55 "D7" 40 0 40 5.39 3.09 6.34
+56 "D8" 40 0 80 7.42 3.7 17.12
+57 "D9" 86.67 100 100 60.57 66.88 64.61
+58 "D10" 26.67 20 26.67 4.42 4.33 4.38
+59 "D11" 0 20 60 2.63 2.73 10.91
+60 "D12" 80 100 60 46.48 54.19 25.5
+61 "D13" 0 20 20 1.24 2.02 2.92
+62 "D14" 0 60 20 2.43 5.58 3.81
+63 "D15" 40 0 0 4.46 2.69 0.72
+64 "D16" 100 0 80 23.58 11.3 19.67
+65 "E1" 60 40 60 18.33 16.26 18.07
+66 "E2" 40 80 0 13.25 17.2 1.73
+67 "E3" 40 80 40 16.1 22.52 11.75
+68 "E4" 86.67 86.67 80 50.7 52.96 40.49
+69 "E5" 4.71 4.71 4.71 0.93 1.03 0.98
+70 "E6" 0 0 80 2.58 1.28 12.24
+71 "E7" 93.33 93.33 86.67 61.11 63.67 49.46
+72 "E8" 20 80 40 9.69 16.36 11.19
+73 "E9" 60 60 20 19.64 20.4 5.14
+74 "E10" 100 100 69.8 68.63 71.55 34.47
+75 "E11" 73.33 66.67 73.33 33.86 33.75 30.83
+76 "E12" 100 0 0 18.65 9.44 0.83
+77 "E13" 20 100 60 12.88 22.5 20.49
+78 "E14" 80 60 100 40.57 35.97 51.8
+79 "E15" 60 60 80 25.89 26.22 33.39
+80 "E16" 60 100 40 30.29 39.21 13.78
+81 "F1" 0 80 20 3.2 7.65 4.38
+82 "F2" 0 20 80 3.71 3.35 16.24
+83 "F3" 80 20 80 23.31 14.61 25.55
+84 "F4" 80 20 40 20.14 13.3 9.05
+85 "F5" 53.33 60 60 19.65 21.55 20.22
+86 "F6" 6.67 6.67 0 1.21 1.33 0.75
+87 "F7" 0 60 80 5.8 8.65 21.51
+88 "F8" 100 0 40 20.82 10.37 7.25
+89 "F9" 60 0 100 12.98 6.05 24.77
+90 "F10" 60 40 20 15.96 14.23 4.62
+91 "F11" 100 100 0 54.03 50.45 2.31
+92 "F12" 60 60 60 23.38 24.4 20.86
+93 "F13" 20 40 0 4.42 5.8 1.14
+94 "F14" 40 100 20 17.42 25.87 5.81
+95 "F15" 0 40 20 1.8 3.63 3.4
+96 "F16" 60 20 20 12.33 9.08 3.65
+97 "G1" 100 40 80 41.01 28.98 32.18
+98 "G2" 20 100 80 14.7 24.18 31.92
+99 "G3" 0 40 80 4.63 5.68 19.04
+100 "G4" 100 100 93.33 73.8 76.63 58.3
+101 "G5" 100 0 100 25.16 11.63 27.13
+102 "G6" 60 80 20 23.64 27.52 5.74
+103 "G7" 80 80 60 40.74 42.65 24.74
+104 "G8" 20 40 20 5.04 6.8 4
+105 "G9" 20 80 100 15.6 21.51 42.53
+106 "G10" 80 86.67 86.67 47.5 50.89 46.6
+107 "G11" 40 46.67 46.67 11.95 13.23 12.63
+108 "G12" 0 0 20 0.74 0.68 2.21
+109 "G13" 60 40 80 20.56 17.42 28.91
+110 "G14" 20 20 13.33 3.34 3.61 2.24
+111 "G15" 80 0 60 15.88 7.93 12.58
+112 "G16" 60 100 60 32.76 42.79 24.95
+113 "H1" 13.33 6.67 13.33 1.99 1.85 1.96
+114 "H2" 20 20 60 5.23 4.73 13.17
+115 "H3" 60 100 80 35.1 45.5 39.54
+116 "H4" 49.8 49.8 49.8 15.44 16.22 14.02
+117 "H5" 54.9 54.9 54.9 18.85 19.72 16.96
+118 "H6" 100 0 20 19.88 10.01 3.06
+119 "H7" 40 20 100 12.31 8.36 31.05
+120 "H8" 80 60 80 37.11 33.66 35.77
+121 "H9" 80 60 40 31.4 29.01 12.25
+122 "H10" 20 40 40 5.92 7.65 8.81
+123 "H11" 94.9 94.9 94.9 65.82 68.12 58.73
+124 "H12" 40 60 60 15.16 18.34 19.38
+125 "H13" 60 40 0 14.99 12.73 1.65
+126 "H14" 86.67 93.33 93.33 56.71 60.58 54.75
+127 "H15" 20 60 60 9.34 13.22 17.86
+128 "H16" 80 0 40 14.91 7.72 6.98
+129 "I1" 80 40 40 25.37 20.12 10.52
+130 "I2" 84.71 84.71 84.71 49.34 51.3 44.11
+131 "I3" 33.33 26.67 33.33 6.63 6.47 6.58
+132 "I4" 6.67 0 6.67 1.07 0.94 1.24
+133 "I5" 60 0 0 8.34 4.69 0.92
+134 "I6" 60 40 100 23.16 18.65 41.02
+135 "I7" 20 60 20 6.72 10.56 4.53
+136 "I8" 80 60 0 27.97 23.98 1.71
+137 "I9" 0 0 100 3.27 1.46 15.75
+138 "I10" 100 80 60 55.74 51.88 24.53
+139 "I11" 20 60 40 7.7 11.77 9.88
+140 "I12" 9.8 9.8 9.8 1.57 1.7 1.49
+141 "I13" 60 60 100 28.92 28.09 47.66
+142 "I14" 100 20 40 28.27 17.22 9.16
+143 "I15" 100 100 86.67 72.13 75.17 50.99
+144 "I16" 0 40 60 3.58 5.09 12.93
+145 "J1" 20 60 100 13.14 15.8 38.03
+146 "J2" 20 100 20 9.81 17.93 5.25
+147 "J3" 100 86.67 100 68.6 65.82 63.75
+148 "J4" 100 40 100 43.83 30.19 45.87
+149 "J5" 80 0 100 18.39 8.6 26.07
+150 "J6" 0 80 60 5.36 10.17 15.84
+151 "J7" 86.67 86.67 100 55.67 57.15 61.71
+152 "J8" 40 60 80 17.35 19.86 30.55
+153 "J9" 60 0 40 9.34 5.12 6.56
+154 "J10" 20 26.67 26.67 4.06 4.65 4.46
+155 "J11" 100 80 80 59.67 55.56 40.66
+156 "J12" 86.67 80 86.67 49.63 49.42 45.4
+157 "J13" 80 100 20 41.62 45.81 6.35
+158 "J14" 20 20 40 4.44 4.57 7.21
+159 "J15" 46.67 40 46.67 12.73 12.57 11.83
+160 "J16" 80 60 60 33.9 31.33 21.78
+161 "K1" 80 100 0 39.02 40.41 2.14
+162 "K2" 20 20 80 6.59 5.47 20
+163 "K3" 20 60 80 11 14.42 27.43
+164 "K4" 0 20 40 1.86 2.4 6.45
+165 "K5" 40 100 40 18.68 28.5 12.59
+166 "K6" 100 100 100 75.76 78.23 67.4
+167 "K7" 33.33 33.33 26.67 7.32 7.87 5.36
+168 "K8" 60 60 0 18.49 18.14 1.64
+169 "K9" 80 80 40 37.54 38.95 13.07
+170 "K10" 80 100 100 55.35 62.8 63.8
+171 "K11" 33.33 40 40 8.76 9.83 9.34
+172 "K12" 34.9 34.9 34.9 8.38 8.86 7.56
+173 "K13" 80 20 60 21.69 14.04 16.27
+174 "K14" 40 100 0 16.19 22.43 2.19
+175 "K15" 100 100 40 62.66 63.7 14.84
+176 "K16" 0 100 80 7.22 13.33 24.18
+177 "L1" 40 0 20 4.75 2.89 2.62
+178 "L2" 60 100 100 38.93 48.68 58.9
+179 "L3" 93.33 100 93.33 65.92 71 57.4
+180 "L4" 100 100 60 66.52 69 26.91
+181 "L5" 40 40 100 15.55 13.99 36.92
+182 "L6" 60 40 40 17.18 15.48 10.42
+183 "L7" 80 100 80 51.65 59.75 43.16
+184 "L8" 60 20 100 18.25 11.8 33.47
+185 "L9" 20 20 20 3.47 3.71 3.23
+186 "L10" 60 20 40 12.9 9.35 8.48
+187 "L11" 100 80 100 64.65 59.55 61.46
+188 "L12" 100 80 0 45.13 38.69 1.96
+189 "L13" 0 80 80 6.43 10.92 22.75
+190 "L14" 60 53.33 60 21.35 21.35 19.83
+191 "L15" 80 40 100 33.05 24.65 43.94
+192 "L16" 60 60 53.33 22.66 23.84 17.58
+193 "M1" 100 86.67 86.67 65.11 63.01 48.58
+194 "M2" 20 0 0 1.94 1.46 0.65
+195 "M3" 80 40 0 22.58 16.86 1.28
+196 "M4" 60 0 60 10.28 5.41 11.55
+197 "M5" 20 100 40 11.02 20.07 11.6
+198 "M6" 93.33 86.67 93.33 59.78 59.84 54.76
+199 "M7" 0 40 40 2.71 4.6 7.83
+200 "M8" 40 100 80 23.91 34.53 36.93
+201 "M9" 100 20 60 30.27 18.26 16.91
+202 "M10" 40 100 100 26.5 36.45 52.65
+203 "M11" 40 60 40 13.33 16.63 10.94
+204 "M12" 0 80 40 4.04 8.83 9.08
+205 "M13" 26.67 26.67 26.67 5.17 5.59 5.05
+206 "M14" 0 100 20 3.61 9.2 4.51
+207 "M15" 40 40 33.33 10.14 10.8 7.78
+208 "M16" 20 20 0 3.13 3.26 0.84
+209 "N1" 0 60 40 3.29 6.6 8.25
+210 "N2" 0 100 40 4.65 10.78 9.31
+211 "N3" 66.67 73.33 73.33 30.72 33.49 30.48
+212 "N4" 40 60 0 10.72 12.58 1.45
+213 "N5" 40 20 80 10.17 7.54 21.82
+214 "N6" 20 80 60 11.18 18 19.3
+215 "N7" 100 80 40 53.3 49.34 13.79
+216 "N8" 40 20 20 7.14 6.18 3.7
+217 "N9" 20 40 60 7.18 8.54 15.43
+218 "N10" 40 40 40 10.26 10.86 9.44
+219 "N11" 93.33 93.33 100 64.17 66.15 63.94
+220 "N12" 80 40 80 29.82 22.94 30.75
+221 "N13" 80 73.33 80 41.27 41.14 38.01
+222 "N14" 40 40 80 13.72 13.09 26.73
+223 "N15" 93.33 100 100 67.54 72.16 65.85
+224 "N16" 100 69.8 100 59.57 51.66 57.98
+225 "O1" 80 0 0 13.5 7.07 0.76
+226 "O2" 100 80 20 49.21 44.05 5.87
+227 "O3" 80 20 20 18.71 12.3 3.74
+228 "O4" 73.33 80 80 38.42 41.38 37.84
+229 "O5" 40 80 20 14.29 19.83 5.34
+230 "O6" 100 40 60 38.12 27.36 19.84
+231 "O7" 0 20 0 0.82 1.5 0.8
+232 "O8" 86.67 100 86.67 58.19 65.09 49.46
+233 "O9" 60 80 0 22.03 24.06 1.89
+234 "O10" 100 60 100 54.38 44.04 54.64
+235 "O11" 53.33 53.33 46.67 17.33 18.31 13.39
+236 "O12" 20 13.33 20 3.07 2.92 2.94
+237 "O13" 40 40 0 8.57 8.65 1.33
+238 "O14" 0 60 0 2.04 4.54 1.45
+239 "O15" 20 0 100 5.58 2.53 20.51
+240 "O16" 40 40 20 9.55 10.01 4.38
+241 "P1" 60 80 60 27.28 32.46 22.7
+242 "P2" 0 0 40 1.26 0.88 4.93
+243 "P3" 60 80 100 33.17 37.11 53.34
+244 "P4" 40 0 100 8.31 3.84 22.57
+245 "P5" 0 6.67 6.67 0.65 0.9 1.06
+246 "P6" 20 0 60 3.58 1.97 10.4
+247 "P7" 20 100 100 17.53 26.57 45.79
+248 "P8" 100 60 0 38.54 30.11 1.74
+249 "P9" 100 93.33 93.33 70.01 70.01 56.41
+250 "P10" 69.8 100 100 45.98 54.96 61.34
+251 "P11" 0 40 100 5.76 6.4 24.4
+252 "P12" 66.67 66.67 60 27.4 28.95 21.64
+253 "P13" 20 40 80 8.91 9.56 24.29
+254 "P14" 60 20 60 14.32 10.16 15.55
+255 "P15" 80 100 40 44.13 50.38 14.14
+256 "P16" 80 20 100 25.91 15.77 35.63
+257 "Q1" 20 20 100 7.89 5.75 27.26
+258 "Q2" 40 60 100 19.45 21.15 43.11
+259 "Q3" 20 0 20 2.18 1.59 2.48
+260 "Q4" 14.9 14.9 14.9 2.47 2.57 2.36
+261 "Q5" 100 93.33 100 71.98 71.6 65.38
+262 "Q6" 60 66.67 66.67 25.4 27.72 25.57
+263 "Q7" 100 60 60 46.78 38.92 22.52
+264 "Q8" 60 80 80 30.85 35.91 37
+265 "Q9" 20 100 0 9.11 15.52 1.94
+266 "Q10" 40 40 60 11.65 11.86 16.65
+267 "Q11" 60 60 40 20.6 21.96 11.36
+268 "Q12" 0 80 0 2.49 6.09 1.38
+269 "Q13" 80 80 80 43.66 45.37 39.11
+270 "Q14" 89.8 89.8 89.8 56.73 58.92 50.71
+271 "Q15" 46.67 46.67 40 13.37 14.14 10.18
+272 "Q16" 60 80 40 25.67 30.42 12.63
+273 "R1" 40 60 20 11.96 14.98 5.06
+274 "R2" 60 100 0 25.55 30.36 2.16
+275 "R3" 40 100 60 20.96 31.53 22.46
+276 "R4" 100 20 20 26.63 16.16 3.75
+277 "R5" 46.67 53.33 53.33 15.45 17.15 15.99
+278 "R6" 20 0 40 2.87 1.83 5.87
+279 "R7" 20 60 0 5.94 8.9 1.32
+280 "R8" 100 0 60 22.2 10.8 12.85
+281 "R9" 100 20 80 32.45 19.2 26.87
+282 "R10" 100 40 0 31.17 21.44 1.48
+283 "R11" 20 0 80 4.71 2.36 15.65
+284 "R12" 53.33 46.67 53.33 16.81 16.68 15.67
+285 "R13" 80 80 0 33.39 31.69 1.87
+286 "R14" 40 20 0 6.67 5.46 0.93
+287 "R15" 40 80 100 23.87 29.65 49.1
+288 "R16" 26.67 26.67 20 5.1 5.43 3.45
+END_DATA
diff --git a/target/ifarp.c b/target/ifarp.c
new file mode 100644
index 0000000..7e1117e
--- /dev/null
+++ b/target/ifarp.c
@@ -0,0 +1,946 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Incremental far point class
+ *
+ * Author: Graeme W. Gill
+ * Date: 6/11/2002
+ *
+ * Copyright 2002 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.
+ */
+
+/*
+ Algorithm:
+
+ Starting with a previous test point as a seed, use a random starte point
+ and minimisation algorithm to locate another point that is as far as
+ possible from the nearest existing test point in perceptual space,
+ while remaining in gamut at all tines. This means that ideally each
+ point "fills in" the gaps in the existing distribution, while starting
+ from an existing point.
+
+ The performance is still not very good, as the inner loop involves
+ locating the nearest existing point, as well as converting from
+ device coordinates to perceptual space. If the powell search radius
+ is reduced too much the uniformity of the distribution suffers.
+
+ */
+
+/* TTBD:
+
+ It would probably help the uniformity of distribution if we could
+ aproximately locate the next seed point as the one with the
+ biggest adjoing "gap", and this may speed things up by allowing us
+ to reduce the powel search radius.
+
+ Perhaps switching to a balltree indexing structure would speed up
+ nearest ppoint finding as well as providing a mechanism to quickly
+ locate the nearest "void".
+
+ Subsequent experience indicates that furthest distance in perceptual
+ space may not be the best strategy, but furthest distance in device
+ space may be. Add #define allowing this to be tested ??
+
+ */
+
+#undef DEBUG
+#define PERC_PLOT 1 /* Emit perceptive space plots (if DEBUG) */
+#define DO_WAIT 1 /* Wait for user key after each plot */
+
+#define ASSERTS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#ifdef DEBUG
+#include "plot.h"
+#endif
+#include "numlib.h"
+#include "sort.h"
+#include "plot.h"
+#include "icc.h"
+#include "xcolorants.h"
+#include "targen.h"
+#include "ifarp.h"
+#include "../h/sort.h" /* Heap sort */
+
+#ifdef DEBUG
+static void dump_image(ifarp *s, int pcp);
+static void dump_image_final(ifarp *s, int pcp);
+#endif
+
+#define MAX_TRIES 30 /* Maximum itterations */
+
+
+/* nn functions */
+static double nearest(ifarp *s, double *q);
+static void init_nn(ifarp *s);
+static void add_nn(ifarp *s);
+static void del_nn(ifarp *s);
+
+/* ----------------------------------------------------- */
+/* Default convert the nodes device coordinates into approximate perceptual coordinates */
+static void
+ifarp_to_percept(void *od, double *p, double *d) {
+ ifarp *s = (ifarp *)od;
+ int e;
+
+ /* Do nothing - copy device to perceptual. */
+ for (e = 0; e < s->di; e++) {
+ p[e] = d[e] * 100.0;
+ }
+}
+
+
+/* Return the largest distance of the point outside the device gamut. */
+/* This will be 0 if inside the gamut, and > 0 if outside. */
+static double
+ifarp_in_dev_gamut(ifarp *s, double *d) {
+ int e;
+ int di = s->di;
+ double tt, dd = 0.0;
+ double ss = 0.0;
+
+ for (e = 0; e < di; e++) {
+ ss += d[e];
+
+ tt = 0.0 - d[e];
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ tt = d[e] - 1.0;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ }
+ tt = ss - s->ilimit;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ return dd;
+}
+
+/* Snap a point to the device gamut boundary. */
+/* Return nz if it has been snapped. */
+static int snap_to_gamut(ifarp *s, double *d) {
+ int e;
+ int di = s->di;
+ double dd; /* Smallest distance */
+ double ss; /* Sum */
+ int rv = 0;
+
+ /* Snap to ink limit first */
+ for (ss = 0.0, e = 0; e < di; e++)
+ ss += d[e];
+ dd = fabs(ss - s->ilimit);
+
+ if (dd < 0.0) {
+ int j;
+ for (j = 0; j < di; j++)
+ d[j] *= s->ilimit/ss; /* Snap to ink limit */
+ rv = 1;
+ }
+
+ /* Now snap to any other dimension */
+ for (e = 0; e < di; e++) {
+
+ dd = fabs(d[e] - 0.0);
+ if (dd < 0.0) {
+ d[e] = 0.0; /* Snap to orthogonal boundary */
+ rv = 1;
+ }
+ dd = fabs(1.0 - d[e]);
+ if (dd < 0.0) {
+ d[e] = 1.0; /* Snap to orthogonal boundary */
+ rv = 1;
+ }
+ }
+
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Reverse lookup function :- perceptual to device coordinates */
+
+/* Definition of the optimization functions handed to powell() */
+
+/* Return metric to be minimised, and */
+/* an error >= 50000 on being out of device gamut */
+static double efunc(void *edata, double p[]) {
+ ifarp *s = (ifarp *)edata;
+ double rv;
+ if ((rv = (ifarp_in_dev_gamut(s, p))) > 0.0) {
+ rv = rv * 500.0 + 500.0; /* Discourage being out of gamut */
+ } else {
+ double v[MXTD];
+ s->percept(s->od, v, p);
+ rv = 500.0 - nearest(s, v);
+ }
+//printf("~1 rv = %f from %f %f\n",rv,p[0],p[1]);
+ return rv;
+}
+
+/* Given a point in device space, optimise it to be */
+/* within the device gamut, as well as being as far as */
+/* possible from the nearest point in perceptual space. */
+/* return nz if powell failed */
+static int
+optimise_point(
+ifarp *s,
+double *d /* starting and returned device position */
+) {
+ int e, di = s->di;
+ double sr[MXTD]; /* Search radius in each device dimension */
+ double drad = 1.0; /* Search Radius (affects fill evenness) */
+ double ptol = 0.001; /* Tolerance */
+ double tt;
+
+// ~~99
+ for (e = 0; e < di; e++)
+ sr[e] = drad; /* Device space search radius */
+ if (powell(&tt, di, d, sr, ptol, 500, efunc, (void *)s, NULL, NULL) != 0 || tt >= 50000.0) {
+#ifdef DEBUG
+ warning("ifarp: powell failed, tt = %f",tt);
+#endif
+ return 1;
+ }
+ snap_to_gamut(s, d);
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Create a new node. */
+/* Return current number of nodes */
+static int new_node(
+ifarp *s,
+int ix /* Index of point to start from */
+) {
+ int di = s->di;
+ int e;
+
+// ~~99
+ /* Retry if powell failes */
+ for (;;) {
+
+ /* Create the new point by cloning the existing point */
+ s->nodes[s->np].fx = 0; /* Not a fixed/pre-existing node */
+ for (e = 0; e < di; e++) {
+ s->nodes[s->np].p[e] = s->nodes[ix].p[e];
+ }
+ /* Compute new point location that is farthest from nearest existing point */
+ if (optimise_point(s, s->nodes[s->np].p) == 0)
+ break;
+ }
+
+ /* compute perceptual location */
+ s->percept(s->od, s->nodes[s->np].v, s->nodes[s->np].p);
+
+#ifdef DEBUG
+printf("Added node %d at perc %f %f, dev %f %f\n",
+s->np,
+s->nodes[s->np].v[0],
+s->nodes[s->np].v[1],
+s->nodes[s->np].p[0],
+s->nodes[s->np].p[1]);
+#endif
+
+ /* Add the node to our current list */
+ s->nodes[s->np].touch = s->tbase;
+ s->np++;
+ add_nn(s);
+
+ return s->np;
+}
+
+/* ============================================= */
+/* Main object functions */
+
+/* Initialise, ready to read out all the points */
+static void ifarp_reset(ifarp *s) {
+ s->rix = 0;
+}
+
+/* Read the next set of non-fixed points values */
+/* return non-zero when no more points */
+static int ifarp_read(
+ifarp *s,
+double *d, /* Device position */
+double *p /* Perceptual value */
+) {
+ int j;
+
+ for (; s->rix < s->np; s->rix++) {
+
+ if (s->nodes[s->rix].fx == 0) {
+ for (j = 0; j < s->di; j++) {
+ if (d != NULL)
+ d[j] = s->nodes[s->rix].p[j];
+ if (p != NULL)
+ p[j] = s->nodes[s->rix].v[j];
+ }
+ s->rix++;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Destroy ourselves */
+static void
+ifarp_del(ifarp *s) {
+
+ if (s->nodes != NULL)
+ free(s->nodes);
+
+ free (s);
+}
+
+/* Constructor */
+ifarp *new_ifarp(
+int di, /* Dimensionality of device space */
+double ilimit, /* Ink limit (sum of device coords max) */
+int inp, /* Number of points to generate */
+fxpos *fxlist, /* List of existing fixed points (may be NULL) */
+int fxno, /* Number of existing fixes points */
+void (*percept)(void *od, double *out, double *in), /* Perceptual lookup func. */
+void *od /* context for Perceptual function */
+) {
+ ifarp *s;
+ int e, i;
+ int verb = 1;
+
+#ifdef DEBUG
+ printf("new_ifarp called with di %d, inp %d, fxno = %d\n",di,inp,fxno);
+#endif
+
+ if ((s = (ifarp *)calloc(sizeof(ifarp), 1)) == NULL)
+ error ("ifarp: ifarp malloc failed");
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ s->reset = ifarp_reset;
+ s->read = ifarp_read;
+ s->del = ifarp_del;
+
+ /* If no perceptual function given, use default */
+ if (percept == NULL) {
+ s->percept = ifarp_to_percept;
+ s->od = s;
+ } else {
+ s->percept = percept;
+ s->od = od;
+ }
+
+ s->ilimit = ilimit;
+
+ s->inp = inp; /* Intended number of points */
+ s->np = 0;
+
+ if (di > MXTD)
+ error ("ifarp: Can't handle di %d",di);
+ s->di = di;
+ s->tbase = 0;
+
+ /* Initial alloc of nodes */
+ if ((s->nodes = (ifpnode *)malloc(s->inp * sizeof(ifpnode))) == NULL)
+ error ("ifarp: nodes malloc failed");
+
+ /* Copy fixed nodes */
+ for (i = 0; (i < fxno) && (s->np < s->inp); i++) {
+ s->nodes[s->np].fx = 1;
+ for (e = 0; e < di; e++)
+ s->nodes[s->np].p[e] = fxlist[i].p[e];
+ s->percept(s->od, s->nodes[i].v, s->nodes[i].p);
+ s->nodes[s->np].touch = s->tbase;
+ s->np++;
+ }
+
+ /* Create at least one seed point */
+ if (s->np == 0) {
+ s->nodes[s->np].fx = 0;
+
+ for (e = 0; e < di; e++)
+ s->nodes[s->np].p[e] = 0.0; /* This is assumed to be in gamut */
+ s->percept(s->od, s->nodes[i].v, s->nodes[i].p);
+ s->nodes[s->np].touch = s->tbase;
+ s->np++;
+ }
+
+ /* Setup initial nearest point acceleration structure */
+ init_nn(s);
+
+ /* Create initial patches */
+// ~~99
+
+ if (verb)
+ printf("Full points:\n");
+
+ for (i = 0; s->np < s->inp; i += 17) {
+ i %= s->np;
+ new_node(s, i);
+ if (verb) {
+ int pc = (int)(100.0 * s->np/s->inp + 0.5);
+ printf(" % 3d%%%c",pc,cr_char); fflush(stdout);
+ }
+ }
+
+ if (verb)
+ printf("\n");
+
+ /* We're done with acceleration structure */
+ del_nn(s);
+
+ return s;
+}
+
+/* --------------------------------------------------- */
+/* (This code is has been copied from gamut/gamut.c) */
+
+#ifdef DEBUG
+#define NN_INF 100000.0
+#else
+#define NN_INF 1e307
+#endif
+
+/* Given a point, */
+/* return the nearest existint test point. */
+static double
+nearest(
+ifarp *s,
+double *q /* Target point location */
+) {
+ int e, i, k;
+ int di = s->di;
+ int wex[MXTD * 2]; /* Current window edge indexes */
+ double wed[MXTD * 2]; /* Current window edge distances */
+ /* Indexes are axis * 2 +0 for lower edge, */
+ /* +1 for upper edge of search box. */
+ /* We are comparing lower edge of search box */
+ /* with upper edge of bounding box etc. */
+
+//printf("~1 nearest called\n");
+
+ /* We have to find out which existing point the point will be nearest */
+
+ if ((s->tbase + di) < s->tbase) { /* Overflow of touch count */
+ for (i = 0; i < s->np; i++)
+ s->sax[0][i]->touch = 0; /* reset it in all the objects */
+ s->tbase = 0;
+ }
+ s->ttarget = s->tbase + di; /* Target touch value */
+
+//printf("\n");
+//printf("Query point is %f %f\n",q[0], q[1]);
+
+ /* Find starting indexes within axis arrays */
+ for (e = 0; e < (2 * di); e++) { /* For all axes min & max */
+ int f = e/2; /* Axis */
+ int i0, i1, i2; /* Search indexes */
+ double v0, v1, v2; /* Box */
+ double qf, ww;
+
+ /* Binary search this edge */
+ qf = q[f]; /* strength reduced q[f] */
+
+//printf("\n");
+//printf("isearching axis %d %s for %f\n",f, e & 1 ? "max" : "min", qf);
+ i0 = 0;
+ i2 = s->np - 1;
+ v0 = s->sax[f][i0]->v[f];
+ v2 = s->sax[f][i2]->v[f];
+//printf("start points %d - %d, bound %f - %f\n",i0, i2, v0, v2);
+
+ if (qf <= v0) {
+ i2 = i0;
+ v2 = v0;
+ } else if (qf >= v2) {
+ i0 = i2;
+ v0 = v2;
+ } else {
+ do {
+ i1 = (i2 + i0)/2; /* Trial point */
+ v1 = s->sax[f][i1]->v[f]; /* Value at trial */
+ if (v1 < qf) {
+ i0 = i1; /* Take top half */
+ v0 = v1;
+ } else {
+ i2 = i1; /* Take bottom half */
+ v2 = v1;
+ }
+//printf("current point %d - %d, bound %f - %f\n",i0, i2, v0, v2);
+ } while ((i2 - i0) > 1);
+ }
+
+ if (e & 1) { /* Max side of window */
+ int tc; /* total object count */
+
+ ww = v2 - qf;
+ wed[e] = fabs(ww) * ww;
+ wex[e] = i2;
+
+ /* Check that min and max together will cover at least s->np objects */
+ tc = s->np - i2 + wex[e ^ 1] + 1;
+//printf("got %d, expected %d\n",tc, s->np);
+
+ /* (I don't really understand why this works!) */
+ if (tc < s->np) { /* We haven't accounted for all the objects */
+ int el = e ^ 1; /* Low side sax */
+ int ti0, ti2;
+ double tv0, tv2;
+
+ ti0 = wex[el];
+ ti2 = i2;
+//printf("We have straddling objects, initial indexes are %d - %d\n",ti0, ti2);
+
+ /* While straddling objects remain undiscovered: */
+ while (tc < s->np) {
+ tv0 = NN_INF; /* Guard values */
+ tv2 = -NN_INF;
+
+ /* Increment low side until we find a straddler */
+ while (ti0 < (s->np-1)) {
+ ww = s->sax[f][++ti0]->v[f]; /* Position of the other end */
+ if (ww < qf) {
+//printf("found low object %d at index %d that straddles\n",s->sax[f][ti0]-s->nodes,ti0);
+ tv0 = qf - s->sax[f][ti0]->v[f];
+ break;
+ }
+ }
+
+ /* Decrement high side until we find a straddler */
+ while (ti2 > 0) {
+ ww = s->sax[f][--ti2]->v[f]; /* Position of the other end */
+ if (ww > qf) {
+//printf("found high object %d at index %d that straddles\n",s->sax[f][ti2]-s->nodes,ti2);
+ tv2 = s->sax[f][ti2]->v[f] - qf;
+ break;
+ }
+ }
+ /* Choose the closest */
+ if (tv0 > tv2) {
+ wed[el] = fabs(tv0) * tv0;
+ wex[el] = ti0;
+ tc++;
+ } else {
+ wed[e] = fabs(tv2) * tv2;
+ wex[e] = ti2;
+ tc++;
+ }
+ }
+//printf("After correction we have %d - %d\n",wex[e^1], wex[e]);
+ }
+ } else { /* Min side of window */
+ ww = q[f] - v0;
+ wed[e] = fabs(ww) * ww;
+ wex[e] = i0;
+ }
+ }
+
+ /* Expand a di dimenstional cube centered on the target point, */
+ /* jumping to the next nearest point on any axis, discovering */
+ /* any bounding boxes that are within the expanding window */
+ /* by checking their touch count. */
+
+ /* The first point found establishes the initial best distance. */
+ /* When the window expands beyond the point where it can improve */
+ /* the best distance, stop */
+
+ {
+ double bw = 0.0; /* Current window distance */
+ double bdist = NN_INF; /* Best possible distance to an object outside the window */
+ int bix; /* Index of best point */
+
+ /* Until we're done */
+ for (;;) {
+ int ee; /* Axis & expanding box edge */
+ int ff; /* Axis */
+ int ii; /* Index of chosen point */
+ ifpnode *ob; /* Current object */
+ unsigned int ctv; /* Current touch value */
+//printf("\n");
+//printf("wwidth = %f, bdist = %f, window = %d-%d, %d-%d\n",
+//bw, bdist, wex[0], wex[1], wex[2], wex[3]);
+//printf("window edge distances are = %f-%f, %f-%f\n",
+//wed[0], wed[1], wed[2], wed[3]);
+
+ /* find next (smallest) window increment axis and direction */
+ ee = 0;
+ ii = wex[ee];
+ bw = wed[ee];
+ for (e = 1; e < (2 * di); e++) {
+ if (wed[e] < bw) {
+ ee = e;
+ ii = wex[e];
+ bw = wed[e];
+ }
+ }
+//printf("Next best is axisdir %d, object %d, axis index %d, best possible dist %f\n",
+//ee, s->sax[ee/2][ii] - s->nodes, ii, bw);
+
+ if (bw == NN_INF || bw > bdist) {
+ break; /* Can't go any further, or further points will be worse */
+ }
+
+#ifdef ASSERTS
+if (ii < 0 || ii >= s->np) {
+printf("Assert: went out of bounds of sorted axis array\n");
+exit(0);
+}
+#endif
+ /* Chosen point on ee axis/direction, index ii */
+ ff = ee / 2; /* Axis only */
+
+ ob = s->sax[ff][ii];
+
+ /* Touch value of current object */
+ ctv = ob->touch;
+
+ if (ctv < s->ttarget) { /* Not been dealt with before */
+
+ /* Touch this new window boundary point */
+ ob->touch = ctv = ((ctv < s->tbase) ? s->tbase : ctv) + 1;
+
+//printf("New touch count on %d is %d, target %d\n",
+//ob - s->nodes, s->sax[ff][ii]->touch, s->ttarget);
+
+ /* Check the point out */
+ if (ctv == (s->tbase + di)) { /* Is within window on all axes */
+ double tdist = 0.0;
+
+ /* Compute distance from query point to this object */
+ for (k = 0; k < di; k++) {
+ double tt = ob->v[k] - q[k];
+ tdist += tt * tt;
+ }
+
+//printf("Got new best point %d, dist %f\n",ob-s->nodes,sqrt(tdist));
+ if (tdist < bdist) { /* New closest distance */
+ bdist = tdist;
+ bix = ob - s->nodes;
+ }
+ }
+ }
+
+ /* Increment next window edge candidate, and figure new edge distance */
+ if (ee & 1) { /* Top */
+ if (++wex[ee] >= s->np) {
+ wed[ee] = NN_INF;
+ wex[ee]--;
+ } else {
+ double ww = s->sax[ff][wex[ee]]->v[ff] - q[ff];
+ wed[ee] = fabs(ww) * ww;
+ }
+ } else {
+ if (--wex[ee] < 0) {
+ wed[ee] = NN_INF;
+ wex[ee]++;
+ } else {
+ double ww = q[ff] - s->sax[ff][wex[ee]]->v[ff];
+ wed[ee] = fabs(ww) * ww;
+ }
+ }
+ }
+
+ s->tbase += di; /* Next touch */
+
+//printf("~1 returning closest to node %d distance %f\n",bix,sqrt(bdist));
+ return sqrt(bdist); /* Return nearest distance */
+ }
+}
+
+
+/* Setup the nearest function acceleration structure */
+/* with the existing points */
+static void
+init_nn(
+ifarp *s
+) {
+ int di = s->di;
+ int i, k;
+ int np = s->np; /* Existing number of points */
+
+//printf("~9 init_nn called\n");
+
+ s->tbase = 0; /* Initialse touch flag */
+
+ /* Allocate the arrays spaces for intended number of points */
+ for (k = 0; k < di; k++) {
+ if ((s->sax[k] = (ifpnode **)malloc(sizeof(ifpnode *) * s->inp)) == NULL)
+ error("Failed to allocate sorted index array");
+ }
+
+ /* Add each existing test point to the axis lists. */
+ for (i = 0; i < np; i++) {
+ for (k = 0; k < di; k++)
+ s->sax[k][i] = &s->nodes[i];
+ }
+
+ /* Sort the axis arrays */
+ for (k = 0; k < di; k++) {
+ /* Sort nodes edge list */
+#define HEAP_COMPARE(A,B) (A->v[k] < B->v[k])
+ HEAPSORT(ifpnode *, &s->sax[k][0], np)
+#undef HEAP_COMPARE
+ }
+//printf("~9 init_nn done\n");
+}
+
+
+#ifdef NEVER /* Slower but simpler version */
+
+/* Add the last point to the acceleration structure */
+static void
+add_nn(
+ifarp *s
+) {
+ int di = s->di;
+ int i, k;
+ int np = s->np; /* Existing number of points */
+ int ap = np - 1; /* Index of point ot add */
+
+//printf("~9 add_nn called with point ix %d, pos %f %f\n",ap, s->nodes[ap].v[0],s->nodes[ap].v[1]);
+
+ for (k = 0; k < di; k++) {
+ s->sax[k][ap] = &s->nodes[ap];
+ }
+
+ /* Sort the axis arrays */
+ for (k = 0; k < di; k++) {
+ /* Sort nodes edge list */
+#define HEAP_COMPARE(A,B) (A->v[k] < B->v[k])
+ HEAPSORT(ifpnode *, &s->sax[k][0], np)
+#undef HEAP_COMPARE
+ }
+}
+
+#else
+
+/* Add the last point to the acceleration structure */
+static void
+add_nn(
+ifarp *s
+) {
+ int di = s->di;
+ int e;
+ int np = s->np; /* Existing number of points */
+ int ap = np - 1; /* Index of point to add */
+
+//printf("~9 add_nn called with point ix %d, pos %f %f\n",ap, s->nodes[ap].v[0],s->nodes[ap].v[1]);
+
+ for (e = 0; e < di; e++) { /* For all axes */
+ int i0, i1, i2; /* Search indexes */
+ double v0, v1, v2; /* Box */
+ double qf;
+
+ qf = s->nodes[ap].v[e]; /* value to be insertion sorted */
+
+//printf("isearching axis %d for %f\n",e, qf);
+
+ /* Find index of lowest value that is greater than target */
+ i0 = 0;
+ i2 = ap - 1;
+ v0 = s->sax[e][i0]->v[e];
+ v2 = s->sax[e][i2]->v[e];
+//printf("start points %d - %d, bound %f - %f\n",i0, i2, v0, v2);
+
+ if (qf <= v0) {
+ i1 = i0;
+ } else if (qf >= v2) {
+ i1 = ap;
+ } else {
+ do {
+ i1 = (i2 + i0)/2; /* Trial point */
+ v1 = s->sax[e][i1]->v[e]; /* Value at trial */
+
+ if (qf > v1) {
+ i0 = i1; /* Take top half */
+ v0 = v1;
+ } else { /* qf <= v1 */
+ i2 = i1; /* Take bottom half */
+ v2 = v1;
+ }
+//printf("current point %d - %d, bound %f - %f\n",i0, i2, v0, v2);
+ } while ((i2 - i0) > 1);
+
+ i1 = i0;
+ v1 = s->sax[e][i1]->v[e];
+
+ /* Ensure we're > than target */
+ while (v1 <= qf) {
+ i1++;
+ if (i1 < ap)
+ v1 = s->sax[e][i1]->v[e];
+ else
+ break;
+ }
+ }
+
+ /* Make room */
+ if (i1 < ap) {
+ memmove((void *)&s->sax[e][i1+1], (void *)&s->sax[e][i1], (ap - i1) * sizeof(ifpnode *));
+ }
+ /* Insert */
+ s->sax[e][i1] = &s->nodes[ap];
+ }
+}
+
+#endif
+
+/* Free everything to do with the nn */
+static void del_nn(ifarp *s) {
+ int di = s->di;
+ int k;
+
+ for (k = 0; k < di; k++) {
+ free (s->sax[k]);
+ }
+}
+
+/* =================================================== */
+
+#ifdef STANDALONE_TEST
+
+icxColorantLu *clu;
+
+void sa_percept(void *od, double *out, double *in) {
+
+#ifdef NEVER
+ double lab[3];
+ clu->dev_to_rLab(clu, lab, in);
+
+ out[0] = lab[0];
+// out[1] = (lab[1]+100.0)/2.0;
+ out[1] = (lab[2]+100.0)/2.0;
+#else
+
+ out[0] = in[0] * 100.0;
+ out[1] = in[1] * 100.0;
+
+#endif
+}
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int npoints = 500;
+ ifarp *s;
+ int mask = ICX_BLACK | ICX_GREEN;
+ int di = 2;
+
+ error_program = argv[0];
+ check_if_not_interactive();
+
+ if (argc > 1)
+ npoints = atoi(argv[1]);
+
+ if ((clu = new_icxColorantLu(mask)) == NULL)
+ error ("Creation of xcolorant lu object failed");
+
+ /* Create the required points */
+ s = new_ifarp(di, 1.5, npoints, NULL, 0, sa_percept, (void *)NULL);
+
+#ifdef DEBUG
+ /* Dump perceptual map */
+ dump_image(s, PERC_PLOT);
+#endif /* DEBUG */
+
+ s->del(s);
+
+ return 0;
+}
+
+#endif /* STANDALONE_TEST */
+
+
+
+#ifdef DEBUG
+
+/* Dump the current point positions to a plot window file */
+static void
+dump_image(ifarp *s, int pcp) {
+ double minx, miny, maxx, maxy;
+ double *x1a = NULL;
+ double *y1a = NULL;
+ double *x2a = NULL;
+ double *y2a = NULL;
+ double *x3a = NULL;
+ double *y3a = NULL;
+
+ int i, nu;
+ ifpnode *p;
+
+ if (s->np == 0)
+ return;
+
+ if (pcp) { /* Perceptual range */
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 100.0;
+ maxy = 100.0;
+ } else {
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 1.0;
+ maxy = 1.0;
+ }
+
+ if ((x1a = (double *)malloc(s->np * sizeof(double))) == NULL)
+ error ("ifarp: plot malloc failed %d",s->np);
+ if ((y1a = (double *)malloc(s->np * sizeof(double))) == NULL)
+ error ("ifarp: plot malloc failed %d",s->np);
+ if ((x2a = (double *)malloc(s->np * sizeof(double))) == NULL)
+ error ("ifarp: plot malloc failed %d",s->np);
+ if ((y2a = (double *)malloc(s->np * sizeof(double))) == NULL)
+ error ("ifarp: plot malloc failed %d",s->np);
+
+ for (nu = i = 0; i < s->np; i++) {
+ p = &s->nodes[i];
+
+ if (pcp) {
+ x1a[nu] = p->v[0];
+ y1a[nu] = p->v[1];
+ x2a[nu] = p->v[0];
+ y2a[nu] = p->v[1];
+ } else {
+ x1a[nu] = p->p[0];
+ y1a[nu] = p->p[1];
+ x2a[nu] = p->p[0];
+ y2a[nu] = p->p[1];
+ }
+ nu++;
+ }
+
+ /* Plot the vectors */
+ do_plot_vec(minx, maxx, miny, maxy,
+ x1a, y1a, x2a, y2a, nu, DO_WAIT, x3a, y3a, 0);
+
+ free(x1a);
+ free(y1a);
+ free(x2a);
+ free(y2a);
+}
+
+#endif /* DEBUG */
+
+
+
+
+
diff --git a/target/ifarp.h b/target/ifarp.h
new file mode 100644
index 0000000..083411b
--- /dev/null
+++ b/target/ifarp.h
@@ -0,0 +1,67 @@
+
+#ifndef IFARP_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Incremental far point class
+ *
+ * Author: Graeme W. Gill
+ * Date: 6/11/2002
+ *
+ * Copyright 2002 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.
+ */
+
+/* A sample point node */
+struct _ifpnode {
+ int fx; /* nz if point is fixed (existing) */
+ double p[MXTD]; /* Device coordinate position */
+ double v[MXTD]; /* Subjective value (Labnnn..) */
+
+ unsigned int touch; /* nn: Per value touch count */
+}; typedef struct _ifpnode ifpnode;
+
+
+/* Main simplex latice object */
+struct _ifarp {
+/* private: */
+ int di; /* Point dimensionality */
+ double ilimit; /* Ink limit - limit on sum of p[] */
+ int inp; /* Intended number of points in list */
+ int np; /* Number of point nodes in list */
+ ifpnode *nodes; /* Current array of nodes */
+ int rix; /* Next read index */
+
+ /* Perceptual function */
+ void (*percept)(void *od, double *out, double *in);
+ void *od; /* Opaque data for perceptual point */
+
+ /* nn support */
+ ifpnode **sax[MXTD]; /* Sorted axis pointers, one for each direction */
+ unsigned int tbase; /* Touch base value for this pass */
+ unsigned int ttarget; /* Touch target value for this pass */
+
+/* public: */
+ /* Initialise, ready to read out all the points */
+ void (*reset)(struct _ifarp *s);
+
+ /* Read the next set of non-fixed points values */
+ /* return non-zero when no more points */
+ int (*read)(struct _ifarp *s, double *d, double *p);
+
+ /* Destroy ourselves */
+ void (*del)(struct _ifarp *s);
+
+}; typedef struct _ifarp ifarp;
+
+/* Constructor */
+extern ifarp *new_ifarp(int di, double ilimit, int npoints,
+ fxpos *fxlist, int fxno,
+ void (*percept)(void *od, double *out, double *in), void *od);
+
+#define IFARP_H
+#endif /* IFARP_H */
diff --git a/target/ofps.c b/target/ofps.c
new file mode 100644
index 0000000..fdea8cb
--- /dev/null
+++ b/target/ofps.c
@@ -0,0 +1,10222 @@
+
+/*
+ * ArgyllCMS Color Correction System
+ *
+ * Optimised Farthest Point Sampling - NN
+ *
+ * Author: Graeme W. Gill
+ * Date: 6/9/2004
+ *
+ * Copyright 2004, 2009 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.
+ */
+
+/* Latest version using vertex nets to reduce internal accounting overhead, */
+/* in an attempt to improve performance scaling with larger numbers of points. */
+
+/* TTBD:
+
+ This code shouldn't exit on an error - this causes an unnecessary failure
+ when ofps is used to evaluate the point distribution of other
+ distribution algorithms.
+
+ There is a bug when the ink limit == dimensions-1 (200% for CMYY), and
+ the number of bit mask then exceeds > 32. This is not so +/- 0.2% either side
+ of 200%.
+
+ One way of addressing the performance issues would be to use multiple
+ threads to call dnsq. A pool could be setup, one for each CPU.
+
+ Some profiles are too rough, and slow/stall vertex placement.
+ Reducing the cache grid and/or smoothing the rspl values
+ ay mitigate this to some degree, and make this more robust ??
+
+ */
+
+/*
+ Description:
+
+ We create a function that estimates the sample positioning error at
+ any location based on a weighted combination of perceptual and device distance,
+ and perceptual function curvature.
+
+ We then initially add sampling points at the largest estimated error
+ verticies of the veronoi natural neighbourhood.
+ This gives us an optimal distribution measuring in mestimated position
+ error within a tollerance of 2:1
+
+ We then iteratively improve the distribution of point nodes by
+ moving them in the direction of the adjacent vertex with the
+ largest estimated sampling error, so that the errors are equally
+ distributed.
+
+ To ensure that there is a good distribution of sampling
+ points on the edges and faces of the gamut, the initial
+ points are given a slighte weighting towards these
+ elements, and then fastened to them. The points on
+ each lower dimensional element (edge, face) is then
+ optimized only amongst themselves, while higher
+ dimension points are aware of the lower dimension
+ ones. In this way the distribution of points on
+ lower dimensional surfaces is well spread, while
+ the higher dimension points take thier positions into account.
+ */
+
+/*
+ Failings:
+
+ The initial allocation of points to lower dimension surfaces
+ is a bit haphazard. It would be nice to have some mechanism
+ to add or subtract points to/from lower dimensional surfaces
+ if they were over or under sampled compared to everything else.
+
+ While the current algorithm meets many goals, such as minimizing the
+ maximum estimated error from any point in the space to the nearest
+ node, and placing nodes on sub dimensional surfaces with distributions
+ optimal within that sub dimensions, it has one obvious failing, and
+ that is that it fails to stratify the samples.
+
+ So if a device is dominantly channel indepenedent, it doesn't
+ take advantage of the number of samples used to fully explore
+ all possible device channel values. This also applies at
+ higher dimensions (ie. the CMYK values exploring response
+ to different K values doesn't spread the CMY values
+ evenly appart.)
+
+ Stratification seems to be somewhat at odds with the primary goal
+ of minimizing the maximum estimated error from any point in the
+ space to the nearest node, but it would be good if there were
+ some way of setting this balance.
+
+ How could stratification be added to the current approach ?
+
+ In general there are many sub-dimensions views, not all of
+ which would probably be regarded as important.
+
+ To measure spread, independent voronoi tesselations of
+ these sub dimensions would be neededi, and they could be
+ used partly driver optimization (??).
+
+ For 1D device channels this wouldn't be so hard to
+ add, although it's hard to know how effective it would
+ be, or whether it would wreck the ND optimization. It
+ might also be unecessary if per channel calibration
+ has been applied.
+
+ For CMY this would need a 3D shadow veronoi.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#include "numlib.h"
+#include "sort.h"
+#include "counters.h"
+#include "plot.h"
+#include "icc.h"
+#include "xicc.h"
+#include "xcolorants.h"
+#include "targen.h"
+#include "rspl.h"
+#include "conv.h"
+#include "ofps.h"
+
+//#include <iperf.h>
+
+#undef DEBUG
+#undef WARNINGS /* Print warnings within DEBUG */
+#undef STATS /* Show function stats */
+
+ /* Optimal fully adapted weightings : */
+#define ADAPT_PERCWGHT 0.65 /* Degree of perceptual adaptation */
+#define ADAPT_CURVWGHT 1.0 /* Degree of curvature */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#ifndef STANDALONE_TEST // targen settings
+
+# define DOOPT /* Do optimization */
+# define INDEP_SURFACE /* Make surface point distribution and optimization independent */
+# undef MAXINDEP_2D /* Limit independent surfaces to 2D */
+ /* Seems to be best for ink limited devices to #undef ? */
+# define KEEP_SURFACE /* Keep surface points on the surface during opt. */
+# define INITIAL_SURFACE_PREF 1.50 /* Extra weighting for surface points at start of seeding */
+# define FINAL_SURFACE_PREF 0.80 /* Extra weighting for surface points by end of seeding */
+
+# define SURFTOL 0.0001 /* Proportion of average spacing to force to gamut boundary */
+# define RANDOM_PERTERB /* Perpterb initial placement to break up patterns */
+
+/* Good mode */
+# define PERTERB_AMOUNT 0.5 /* and to aid surface point distribution with INDEP_SURFACE */
+# define OPT_MAXITS 20 /* Number of optimisation itterations (0 to disable optimisation) */
+# define OPT_TRANS_ITTERS 18 /* Numbers of itterations to transition overshoot and sepw */
+# define OPT_TRANS_POW 1.6 /* Power curve to blend along */
+# define OPT_INITIAL_OVERSHOOT 1.9 /* Optimisation movement initial overshoot */
+# define OPT_FINAL_OVERSHOOT 0.1 /* Optimisation movement final overshoot */
+# define OPT_INITIAL_SEP_WEIGHT 0.7 /* Weight to give separation of nodes during opt */
+# define OPT_FINAL_SEP_WEIGHT 0.3 /* Weight to give separation of nodes during opt */
+# define OPT_STOP_TOL 0.0005 /* Stopping tollerance */
+
+/* Fast mode */
+# define PERTERB_AMOUNT_2 0.1 /* and to aid surface point distribution with INDEP_SURFACE */
+# define OPT_MAXITS_2 6 /* Number of optimisation itterations (0 to disable optimisation) */
+# define OPT_TRANS_ITTERS_2 5 /* Numbers of itterations to transition overshoot and sepw */
+# define OPT_TRANS_POW_2 1.7 /* Power curve to blend along */
+# define OPT_INITIAL_OVERSHOOT_2 1.6 /* Optimisation movement initial overshoot */
+# define OPT_FINAL_OVERSHOOT_2 0.05 /* Optimisation movement final overshoot */
+# define OPT_INITIAL_SEP_WEIGHT_2 0.8 /* Weight to give separation of nodes during opt */
+# define OPT_FINAL_SEP_WEIGHT_2 0.3 /* Weight to give separation of nodes during opt */
+# define OPT_STOP_TOL_2 0.001 /* Stopping tollerance */
+
+/* Diagnostic settings */
+# undef DUMP_STRUCTURE /* Dump internal node & vertex structure */
+# undef DUMP_PLOT_SEED /* Show on screen plot for each initial seed point */
+# undef DUMP_PLOT /* Show on screen plot after each itteration */
+# define DUMP_VTX 1 /* Display the vertex locations too */
+# define DUMP_PLA 1 /* Display the node planes too */
+# define PERC_PLOT 0 /* Emit perceptive space plots */
+# define DO_WAIT 1 /* Wait for user key after each plot */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#else /* ofps standalone test settings */
+
+# define DOOPT /* Do optimization */
+# define INDEP_SURFACE /* Make surface point distribution and optimization independent */
+# define MAXINDEP_2D /* Limit independent surfaces to 2D */
+# define KEEP_SURFACE /* Keep surface points on the surface during opt. */
+# define INITIAL_SURFACE_PREF 1.60 /* Extra weighting for surface points at start of seeding */
+# define FINAL_SURFACE_PREF 0.80 /* Extra weighting for surface points by end of seeding */
+
+# define SURFTOL 0.0001 /* Proportion of averag spacing to force to gamut boundary */
+# define RANDOM_PERTERB /* Perpterb initial placement to break up patterns, */
+# define PERTERB_AMOUNT 0.5
+
+# define OPT_MAXITS 20 /* Number of optimisation itterations (0 to disable optimisation) */
+# define OPT_TRANS_ITTERS 18 /* Numbers of itterations to transition overshoot and sepw */
+# define OPT_TRANS_POW 2.5 /* Power curve to blend along */
+# define OPT_INITIAL_OVERSHOOT 0.8 /* Optimisation movement initial overshoot */
+# define OPT_FINAL_OVERSHOOT 0.1 /* Optimisation movement final overshoot */
+# define OPT_INITIAL_SEP_WEIGHT 0.9 /* Weight to give separation of nodes during opt */
+# define OPT_FINAL_SEP_WEIGHT 0.3 /* Weight to give separation of nodes during opt */
+# define OPT_STOP_TOL 0.0005 /* Device stopping tollerance */
+
+/* Diagnostic settings */
+# undef DUMP_STRUCTURE /* Dump internal node & vertex structure */
+# undef DUMP_PLOT_SEED /* Show on screen plot for each initial seed point */
+# undef DUMP_PLOT_NCOL /* Show on screen plot after adding neighbours, before collecting */
+# define DUMP_PLOT /* Show on screen plot after each itteration */
+# undef DUMP_PLOT_RESEED /* Show on screen plot for each re-seed point */
+# undef DUMP_OPT_PLOT /* Show on screen plot for each optimization pass */
+# undef DUMP_PLOT_BEFORFIXUP /* Show plot after reposition but before fixups */
+# undef DUMP_PLOT_EACHFIXUP /* Show each node fixup */
+# define DUMP_VTX 1 /* Display the vertex locations too */
+# define DUMP_PLA 1 /* Display the node planes too */
+# define PERC_PLOT 0 /* Emit perceptive space plots */
+# define DO_WAIT 1 /* Wait for user key after each plot */
+# undef DUMP_EPERR /* Create .tiff of eperr */
+# undef DUMP_FERR /* 10000 */ /* Create .tiff of function error >= 20 and stop. */
+//# define SA_ADAPT 0.001 /* Standalone test, adaptation level */
+
+# define SA_ADAPT -1.0 /* Standalone test, adaptation level (< 0.0, use individual) */
+# define SA_DEVD_MULT 1.0 /* Delta E for each percent of device space distance */
+# define SA_PERC_MULT 0.0 /* Delta E for each delta E of perceptual space distance */
+# define SA_INTERP_MULT 0.0 /* Delta E for each delta E of estimated interpolation error */
+
+#endif /* NEVER */
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Overall algorithm */
+
+#define NINSERTTRIES 100 /* Number of seedin insert tries befor failing with error() */
+
+#define NUMTOL 1e-16 /* Numerical tollerance */
+#define FTOL 1e-8 /* dnsqe function tollerance */
+#define FGPMUL 5.0 /* Weighting of gamut plane error into dnsqe function */
+#define COINTOL 1e-8 /* Tollerance for point cooincidence */
+#define ILIMITEPS 1e-6 /* imin, imax and ilimit clip test margine */
+
+#define FASTREJMULT1 20.5 /* Fast reject layer distance fudge factor */
+#define FASTREJECTMULT 0.08 /* Fast reject cell skip threshold fudge factor */
+
+#define CELLMAXEPERRFF 2.2 /* Cell worst case eperr from center fudge factor */
+
+#define TNPAGRID 0.8 /* Target nodes per accelleration & peceptual cache grid cell */
+#define TNPAGRIDMINRES 7 /* Perceptual cache grid min resolution */
+#define TNPAGRIDMAXRES 33 /* Perceptual cache grid max resolution */
+#undef FORCE_INCREMENTAL /* Force incremental update after itteration */
+#undef FORCE_RESEED /* Force reseed after itteration */
+#define MAXTRIES 41 /* Maximum dnsq tries before giving up */
+#define CACHE_PERCEPTUAL /* Cache the perceptual lookup function */
+#define USE_DISJOINT_SETMASKS /* Reduce INDEP_SURFACE setmask size */
+
+/* Sanity checks (slow) */
+#undef SANITY_CHECK_SEED /* Sanity check the selection of the bigest eperr seed vertex */
+#undef SANITY_CHECK_HIT /* Sanity check the hit detection */
+#undef SANITY_CHECK_HIT_FATAL /* throw fatal error in sanity check */
+#undef SANITY_CHECK_FIXUP /* Check that fixup was sucessful */
+#undef SANITY_CHECK_FIXUP_FATAL /* throw fatal if it wasn't */
+#undef SANITY_CHECK_CLOSEST /* Check that ofps_findclosest_xx() returns correct result */
+#undef SANITY_CHECK_CLOSEST_FATAL /* throw fatal error on sanity fail */
+#undef SANITY_CHECK_CONSISTENCY /* Check internal consistency at each itteration */
+#undef SANITY_CHECK_CONSISTENCY_FATAL /* Throw a fatal if it wasn't */
+
+#undef SANITY_RESEED_AFTER_FIXUPS /* Re-create veronoi from scratch after incremental update. */
+#undef SANITY_CHECK_EXAUSTIVE_SEARCH_FOR_VERTEXES /* Do very, vert slow search for all vertexes */
+
+#define ALWAYS
+#undef NEVER
+
+#ifdef STATS
+# include "conv.h" /* System dependent convenience functions */
+#endif
+
+#if defined(DUMP_EPERR) || defined(DUMP_FERR)
+#include "tiffio.h"
+struct _vopt_cx;
+static void dump_dnsqe(ofps *s, char *fname, int *nix, struct _vopt_cx *cx);
+#endif
+
+#if defined(DEBUG) || defined(DUMP_PLOT_SEED) || defined(DUMP_PLOT)
+static void dump_image(ofps *s, int pcp, int dwt, int vtx, int dpla, int ferr, int noi);
+#endif
+#if defined(DEBUG) || defined (SANITY_CHECK_CONSISTENCY)
+static void sanity_check(ofps *s, int check_nodelists);
+#endif
+#if defined(DEBUG) || defined(DUMP_STRUCTURE)
+static void dump_node_vtxs(ofps *s, int check_nodelists);
+//static void dump_node_vtxs2(ofps *s, char *cc);
+#endif
+
+static void ofps_binit(ofps *s);
+static void ofps_stats(ofps *s);
+static int ofps_point2cell(ofps *s, double *v, double *p);
+static void ofps_gridcoords(ofps *s, int *c, double *v, double *p);
+static void ofps_add_nacc(ofps *s, node *n);
+static void ofps_rem_nacc(ofps *s, node *n);
+static void ofps_add_vacc(ofps *s, vtx *vx);
+static void ofps_rem_vacc(ofps *s, vtx *vx);
+static void ofps_add_vseed(ofps *s, vtx *vx);
+static void ofps_rem_vseed(ofps *s, vtx *vx);
+static void ofps_re_create_node_node_vtx_lists(ofps *s);
+static void do_batch_update1(ofps *s, int fixup);
+static void do_batch_update2(ofps *s, int fixup);
+
+static node *ofps_findclosest_node(ofps *s, double *ceperr, vtx *vx);
+//static vtx *ofps_findclosest_vtx(ofps *s, double *ceperr, node *nn);
+static int ofps_findhit_vtxs(ofps *s, node *nn);
+
+static char *pco(int di, int *co);
+static char *ppos(int di, double *p);
+static char *pcomb(int di, int *n);
+static char *peperr(double eperr);
+static char *psm(ofps *s, setmask *sm);
+
+/* Check the incremental vertexes against the re-seeded vertexes */
+static void save_ivertexes(ofps *s);
+static int check_vertexes(ofps *s);
+
+/* Check that no node is closer to a vertex than its parent */
+static int check_vertex_closest_node(ofps *s);
+
+/* Do an exaustive check for missing vertexes */
+static void check_for_missing_vertexes(ofps *s);
+
+/* --------------------------------------------------- */
+/* Setmask manipulation functions */
+
+#ifdef USE_DISJOINT_SETMASKS
+ /* We assume the number of words is <= 1, */
+ /* and we can use macros */
+
+/* Signal this is a single word mask by using -ve no. of bits */
+#define sm_init(s, nbits) _sm_init(s, -(nbits))
+
+#define sm_cp(s, sm_B, sm_A) \
+ ((sm_B)->m[0] = (sm_A)->m[0])
+
+#define sm_or(s, sm_C, sm_A, sm_B) \
+ ((sm_C)->m[0] = (sm_A)->m[0] | (sm_B)->m[0])
+
+#define sm_orand(s, sm_D, sm_A, sm_B, sm_C) \
+ ((sm_D)->m[0] = (sm_A)->m[0] | ((sm_B)->m[0] & (sm_C)->m[0]))
+
+#define sm_and(s, sm_C, sm_A, sm_B) \
+ ((sm_C)->m[0] = (sm_A)->m[0] & (sm_B)->m[0])
+
+#define sm_andnot(s, sm_C, sm_A, sm_B) \
+ ((sm_C)->m[0] = (sm_A)->m[0] & (s->lwmask ^ (sm_B)->m[0]))
+
+#define sm_andand(s, sm_D, sm_A, sm_B, sm_C) \
+ ((sm_D)->m[0] = (sm_A)->m[0] & (sm_B)->m[0] & (sm_C)->m[0])
+
+#define sm_test(s, sm_A) \
+ ((sm_A)->m[0] & s->lwmask)
+
+#define sm_equal(s, sm_A, sm_B) \
+ (((sm_A)->m[0] & s->lwmask) == ((sm_B)->m[0] & s->lwmask))
+
+#define sm_andtest(s, sm_A, sm_B) \
+ ((sm_A)->m[0] & (sm_B)->m[0])
+
+#define sm_andnottest(s, sm_A, sm_B) \
+ ((sm_A)->m[0] & (s->lwmask ^ (sm_B)->m[0]))
+
+#define sm_vtx_vtx(s, v1, v2) \
+ ((v1)->vm.m[0] & (v2)->vm.m[0] & s->sc[(v1)->cmask & (v2)->cmask].a_sm.m[0])
+
+#define sm_vtx_node(s, vx, nn) \
+ ((vx)->vm.m[0] & s->sc[(nn)->pmask].a_sm.m[0] & s->sc[(vx)->cmask & (nn)->pmask].a_sm.m[0])
+
+#else
+
+#define sm_init(s, nbits) _sm_init(s, nbits)
+#define sm_cp(s, sm_B, sm_A) _sm_cp(s, sm_B, sm_A)
+#define sm_or(s, sm_C, sm_A, sm_B) _sm_or(s, sm_C, sm_A, sm_B)
+#define sm_orand(s, sm_D, sm_A, sm_B, sm_C) _sm_orand(s, sm_D, sm_A, sm_B, sm_C)
+#define sm_and(s, sm_C, sm_A, sm_B) _sm_and(s, sm_C, sm_A, sm_B)
+#define sm_andnot(s, sm_C, sm_A, sm_B) _sm_andnot(s, sm_C, sm_A, sm_B)
+#define sm_andand(s, sm_D, sm_A, sm_B, sm_C) _sm_andand(s, sm_D, sm_A, sm_B, sm_C)
+#define sm_test(s, sm_A) _sm_test(s, sm_A)
+#define sm_equal(s, sm_A, sm_B) _sm_equal(s, sm_A, sm_B)
+#define sm_andtest(s, sm_A, sm_B) _sm_andtest(s, sm_A, sm_B)
+#define sm_andnottest(s, sm_A, sm_B) _sm_andnottest(s, sm_A, sm_B)
+#define sm_vtx_node(s, vx, nn) _sm_vtx_node(s, vx, nn)
+#define sm_vtx_vtx(s, v1, v2) _sm_vtx_vtx(s, v1, v2)
+
+#endif
+
+/* Compute set mask parameters */
+static void _sm_init(ofps *s, int nbits) {
+
+//printf("~1 _sm_init with %d bits\n",nbits);
+ s->bpsmw = sizeof(unsigned int) * 8;
+
+ if (nbits < 0) { /* Macro initialisation */
+#ifdef DEBUG
+ printf("Disjoint sets being used\n");
+#endif
+ nbits = -nbits;
+ if (nbits > s->bpsmw)
+ error("Attempt to use macro setmasks when nbits %d > a words bits %d",nbits,s->bpsmw);
+ }
+
+ s->smbits = nbits;
+ s->nsmw = (s->smbits + s->bpsmw - 1)/s->bpsmw;
+ s->lwmask = ~0;
+ s->lwmask >>= s->nsmw * s->bpsmw - s->smbits; /* Number of unused bits */
+ if (s->nsmw > MXSMASKW)
+ error("Not enough words for %d setmask bits, got %d need %d\n",s->smbits,MXSMASKW,s->nsmw);
+}
+
+/* Copy a setmask */
+static void _sm_cp(ofps *s, setmask *sm_B, setmask *sm_A) {
+ int i;
+
+ for (i = 0; i < s->nsmw; i++)
+ sm_B->m[i] = sm_A->m[i];
+}
+
+/* Set the whole mask to zero or one */
+static void sm_set(ofps *s, setmask *sm, int val) {
+ int i;
+ unsigned int vv = 0;
+
+ if (val & 1)
+ vv = ~0;
+ for (i = 0; i < s->nsmw; i++)
+ sm->m[i] = vv;
+ sm->m[i-1] &= s->lwmask;
+}
+
+/* Set the given bit to zero or one */
+static void sm_setbit(ofps *s, setmask *sm, int bit, int val) {
+ int i;
+ unsigned int vv = 0;
+
+ if (bit > s->smbits)
+ error("assert, trying to set bit %d outside setmask size %d",bit,s->smbits);
+ i = bit / s->bpsmw;
+ vv = 1 << bit % s->bpsmw;
+ if (val & 1)
+ sm->m[i] |= vv;
+ else
+ sm->m[i] &= ~vv;
+}
+
+/* C = A | B */
+static void _sm_or(ofps *s, setmask *sm_C, setmask *sm_A, setmask *sm_B) {
+ int i;
+
+ for (i = 0; i < s->nsmw; i++)
+ sm_C->m[i] = sm_A->m[i] | sm_B->m[i];
+}
+
+/* D = A | (B & C) */
+static void _sm_orand(ofps *s, setmask *sm_D, setmask *sm_A, setmask *sm_B, setmask *sm_C) {
+ int i;
+
+ for (i = 0; i < s->nsmw; i++)
+ sm_D->m[i] = sm_A->m[i] | (sm_B->m[i] & sm_C->m[i]);
+}
+
+/* C = A & B */
+/* Return zero if result is zero */
+static unsigned int _sm_and(ofps *s, setmask *sm_C, setmask *sm_A, setmask *sm_B) {
+ unsigned int vv = 0;
+ int i;
+
+ for (i = 0; i < s->nsmw; i++)
+ vv |= sm_C->m[i] = sm_A->m[i] & sm_B->m[i];
+ return vv;
+}
+
+/* C = A & ~B */
+/* Return zero if result is zero */
+static unsigned int _sm_andnot(ofps *s, setmask *sm_C, setmask *sm_A, setmask *sm_B) {
+ unsigned int vv = 0;
+ int i;
+
+ for (i = 0; i < s->nsmw; i++) {
+ if (i < (s->nsmw-1))
+ vv |= sm_C->m[i] = sm_A->m[i] & ~sm_B->m[i];
+ else
+ vv |= sm_C->m[i] = sm_A->m[i] & (s->lwmask ^ sm_B->m[i]);
+ }
+ return vv;
+}
+
+/* D = A & B & C */
+/* Return zero if result is zero */
+static unsigned int _sm_andand(ofps *s, setmask *sm_D, setmask *sm_A, setmask *sm_B, setmask *sm_C) {
+ unsigned int vv = 0;
+ int i;
+
+ for (i = 0; i < s->nsmw; i++)
+ vv |= sm_D->m[i] = sm_A->m[i] & sm_B->m[i] & sm_C->m[i];
+ return vv;
+}
+
+/* Return zero if result is zero */
+static unsigned int _sm_test(ofps *s, setmask *sm_A) {
+ unsigned int vv = 0;
+ int i;
+
+ for (i = 0; i < s->nsmw; i++) {
+ if (i < (s->nsmw-1))
+ vv |= sm_A->m[i];
+ else
+ vv |= sm_A->m[i] & s->lwmask;
+ }
+ return vv;
+}
+
+/* Return nz if the two are equal */
+static unsigned int _sm_equal(ofps *s, setmask *sm_A, setmask *sm_B) {
+ int i;
+
+ for (i = 0; i < s->nsmw; i++) {
+ if (i < (s->nsmw-1)) {
+ if (sm_A->m[i] != sm_B->m[i])
+ return 0;
+ } else {
+ if ((sm_A->m[i] & s->lwmask) != (sm_B->m[i] & s->lwmask))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* A & B and return zero if the result was zero. */
+static unsigned int _sm_andtest(ofps *s, setmask *sm_A, setmask *sm_B) {
+ unsigned int vv = 0;
+ int i;
+
+ for (i = 0; i < s->nsmw; i++)
+ vv |= sm_A->m[i] & sm_B->m[i];
+
+ return vv;
+}
+
+/* A & ~B and return zero if result is zero */
+static unsigned int _sm_andnottest(ofps *s, setmask *sm_A, setmask *sm_B) {
+ unsigned int vv = 0;
+ int i;
+
+ for (i = 0; i < s->nsmw; i++) {
+ if (i < (s->nsmw-1))
+ vv |= sm_A->m[i] & ~sm_B->m[i];
+ else
+ vv |= sm_A->m[i] & (s->lwmask ^ sm_B->m[i]);
+ }
+ return vv;
+}
+
+/* Test if two vertexes interact */
+/* return nz if they do */
+static unsigned int _sm_vtx_vtx(ofps *s, vtx *v1, vtx *v2) {
+ unsigned int vv = 0;
+ int i;
+
+#ifdef USE_DISJOINT_SETMASKS
+ /* Because the mask bits are re-used across disjoint sets, */
+ /* we have to discount any intersection that occurs where */
+ /* the two items are disjoint, with the exception of the full-d set. */
+ for (i = 0; i < s->nsmw; i++)
+ vv |= v1->vm.m[i] & v2->vm.m[i] & s->sc[v1->cmask & v2->cmask].a_sm.m[i];
+#else
+ for (i = 0; i < s->nsmw; i++)
+ vv |= v1->vm.m[i] & v2->vm.m[i];
+# endif
+ return vv;
+}
+
+/* Test if a vertex and node interact */
+static unsigned int _sm_vtx_node(ofps *s, vtx *vx, node *nn) {
+ unsigned int vv = 0;
+ int i;
+
+ /* Because the mask bits are re-used across disjoint sets, */
+ /* we have to discount any intersection that occurs where */
+ /* the two items are disjoint, with the exception of the full-d set. */
+#ifdef USE_DISJOINT_SETMASKS
+ for (i = 0; i < s->nsmw; i++)
+ vv |= vx->vm.m[i] & s->sc[nn->pmask].a_sm.m[i] & s->sc[vx->cmask & nn->pmask].a_sm.m[i];
+#else
+ for (i = 0; i < s->nsmw; i++)
+ vv |= vx->vm.m[i] & s->sc[nn->pmask].a_sm.m[i];
+# endif
+ return vv;
+}
+
+/* Utility - return a string containing the mask in hex */
+static char *psm(ofps *s, setmask *sm) {
+ static char buf[5][200];
+ static int ix = 0;
+ int e, f;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ sprintf(bp, "0x"); bp += strlen(bp);
+ for (f = 0, e = s->nsmw-1; e >= 0; e--) {
+ if (f || e == 0 || sm->m[e] != 0) {
+ if (f) {
+ sprintf(bp, "%08x", sm->m[e]); bp += strlen(bp);
+ } else {
+ sprintf(bp, "%x", sm->m[e]); bp += strlen(bp);
+ f = 1;
+ }
+ }
+ }
+ return buf[ix];
+}
+
+/* --------------------------------------------------- */
+/* Swap the location of a node in s->n[]. This is assumed to */
+/* be done _before_ a node is added to the veroni */
+static void swap_nodes(ofps *s, int i, int j) {
+ node *n;
+ int xx;
+
+ n = s->n[i];
+ s->n[i] = s->n[j];
+ s->n[j] = n;
+
+ /* fix index number */
+ xx = s->n[i]->ix;
+ s->n[i]->ix = s->n[j]->ix;
+ s->n[j]->ix = xx;
+
+ xx = s->n[i]->ixm;
+ s->n[i]->ixm = s->n[j]->ixm;
+ s->n[j]->ixm = xx;
+}
+
+/* Shuffle all the nodes in the list along to put */
+/* the given node at the start. */
+static void move_node_to_front(ofps *s, int i) {
+ node *n;
+ int j;
+
+ n = s->n[i];
+
+ for (j = 1; j <= i; j++)
+ s->n[j] = s->n[j-1];
+
+ s->n[0] = n;
+
+ /* Fix ->ix and ixm */
+ for (j = 0; j <= i; j++) {
+ int bitp;
+ s->n[j]->ix = i;
+
+ bitp = 31 & (j + (j >> 4) + (j >> 8) + (j >> 12));
+ s->n[j]->ixm = (1 << bitp);
+ }
+}
+
+/* Randomly shuffle all the nodes */
+static void shuffle_node_order(ofps *s) {
+ int i;
+
+ for (i = 0; i < s->tinp; i++) {
+ swap_nodes(s, i, i_rand(0, s->tinp-1));
+ }
+}
+
+/* Reverse the nodes order */
+static void reverse_node_order(ofps *s) {
+ int i, j;
+
+ for (i = 0, j = s->tinp-1; i < j; i++, j--) {
+ swap_nodes(s, i, j);
+ }
+}
+
+/* --------------------------------------------------- */
+/* Default convert the nodes device coordinates into approximate perceptual coordinates */
+/* (usually overriden by caller supplied function) */
+static void
+default_ofps_to_percept(void *od, double *p, double *d) {
+ ofps *s = (ofps *)od;
+ int e;
+
+ /* Default Do nothing - copy device to perceptual. */
+ for (e = 0; e < s->di; e++) {
+ double tt = d[e];
+ p[e] = tt * 100.0;
+ }
+}
+
+/* Cached perceptual lookup */
+static void
+ofps_cache_percept(void *od, double *p, double *d) {
+ int e;
+ co tp;
+ rspl *pc = (rspl *)od;
+
+ for (e = 0; e < pc->di; e++)
+ tp.p[e] = d[e];
+ pc->interp(pc, &tp);
+ for (e = 0; e < pc->fdi; e++)
+ p[e] = tp.v[e];
+}
+
+/* Return the distance of the device value from the device gamut */
+/* This will be -ve if the point is outside */
+/* If bvp is non-null, the index of the closest dim times 2 */
+/* will be returned for the 0.0 boundary, dim * 2 + 1 for the 1.0 */
+/* boundary, and di * 2 for the ink limit boundary. */
+static double
+ofps_in_dev_gamut(ofps *s, double *d, int *bvp) {
+ int e, di = s->di;
+ double tt;
+ double dd = 100.0; /* Worst distance outside */
+ double ss = 0.0; /* Sum of values */
+ int bv = di;
+ for (e = 0; e < di; e++) {
+ tt = d[e] - s->imin[e];
+ if (tt < dd) {
+ dd = tt;
+ bv = e * 2;
+ }
+ tt = s->imax[e] - d[e];
+ if (tt < dd) {
+ dd = tt;
+ bv = e * 2 + 1;
+ }
+ ss += d[e]; /* Track sum */
+ }
+ ss = (s->ilimit - ss)/di; /* Axis aligned distance to ink limit */
+ tt = sqrt((double)di) * ss; /* Diagonal distance to ink limit */
+ if (tt < dd) {
+ dd = tt;
+ bv = di * 2;
+ }
+ if (bvp != NULL)
+ *bvp = bv;
+ return dd;
+}
+
+#ifdef NEVER /* Allow performance trace on ofps_clip_point usage */
+static int ofps_clip_point(ofps *s, double *cd, double *d);
+
+static int ofps_clip_point1(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point2(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point3(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point4(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point5(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point6(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point7(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point8(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point9(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+static int ofps_clip_point10(ofps *s, double *cd, double *d) {
+ return ofps_clip_point(s, cd, d); }
+
+#else /* Production code */
+#define ofps_clip_point1 ofps_clip_point
+#define ofps_clip_point2 ofps_clip_point
+#define ofps_clip_point3 ofps_clip_point
+#define ofps_clip_point4 ofps_clip_point
+#define ofps_clip_point5 ofps_clip_point
+#define ofps_clip_point6 ofps_clip_point
+#define ofps_clip_point7 ofps_clip_point
+#define ofps_clip_point8 ofps_clip_point
+#define ofps_clip_point9 ofps_clip_point
+#define ofps_clip_point10 ofps_clip_point
+#endif
+
+/* Given the new intended device coordinates, */
+/* clip the new position to the device gamut edge */
+/* return non-zero if the point was clipped */
+static int
+ofps_clip_point(ofps *s, double *cd, double *d) {
+ int di = s->di;
+ double ss = 0.0;
+ int rv = 0;
+
+#define STEP(IX) \
+ cd[IX] = d[IX]; \
+ if (cd[IX] < s->imin[IX]) { \
+ cd[IX] = s->imin[IX]; \
+ if (cd[IX] < (s->imin[IX] - ILIMITEPS)) \
+ rv |= 1; \
+ } else if (cd[IX] > s->imax[IX]) { \
+ cd[IX] = s->imax[IX]; \
+ if (cd[IX] > (s->imax[IX] + ILIMITEPS)) \
+ rv |= 1; \
+ } \
+ ss += cd[IX];
+
+ switch (di) {
+ case 4:
+ STEP(3)
+ case 3:
+ STEP(2)
+ case 2:
+ STEP(1)
+ case 1:
+ STEP(0)
+ }
+#undef STEP
+ if (ss > s->ilimit) {
+ if (ss > (s->ilimit + ILIMITEPS))
+ rv |= 1;
+ ss = (ss - s->ilimit)/s->di;
+ switch (di) {
+ case 4:
+ cd[3] -= ss;
+ case 3:
+ cd[2] -= ss;
+ case 2:
+ cd[1] -= ss;
+ case 1:
+ cd[0] -= ss;
+ }
+ }
+ return rv;
+}
+
+/* Given the new intended device coordinates, */
+/* return non-zero if the point would be clipped. */
+static int
+ofps_would_clip_point(ofps *s, double *d) {
+ int e;
+ double ss;
+ for (ss = 0.0, e = 0; e < s->di; e++) {
+ if (d[e] < (s->imin[e] - ILIMITEPS))
+ return 1;
+ else if (d[e] > (s->imax[e] + ILIMITEPS))
+ return 1;
+ ss += d[e];
+ }
+ if (ss > (s->ilimit + ILIMITEPS))
+ return 1;
+ return 0;
+}
+
+/* Return a out of gamut value. */
+/* 0.0 is returned if the posistion is in gamut */
+static double ofps_oog(ofps *s, double *p) {
+ int e, di = s->di;
+ double ss, oog = 0.0;
+
+ for (ss = 0.0, e = 0; e < di; e++) {
+ if (p[e] < (s->imin[e])) {
+ double tt = s->imin[e] - p[e];
+ if (tt > oog) oog = tt;
+ } else if (p[e] > (s->imax[e])) {
+ double tt = p[e] - s->imax[e];
+ if (tt > oog) oog = tt;
+ }
+ ss += p[e];
+ }
+ if (ss > s->ilimit) {
+ double tt;
+ ss = (ss - s->ilimit)/di; /* Axis aligned distance to ink limit */
+ tt = sqrt((double)di) * ss; /* Diagonal distance to ink limit */
+ if (tt > oog)
+ oog = tt;
+ }
+ return oog;
+}
+
+/* Unbounded perceptual lookup. */
+/* return nz if it was actually clipped and extended */
+static int ofps_cc_percept(ofps *s, double *v, double *p) {
+ co cp;
+ int clip;
+
+ clip = ofps_clip_point(s, cp.p, p);
+
+ if (s->pcache) { /* In line this for speed */
+ int e, di = s->di;
+
+ s->pcache->interp(s->pcache, &cp);
+ for (e = 0; e < di; e++)
+ v[e] = cp.v[e];
+
+ } else {
+ s->percept(s->od, v, cp.p);
+ }
+
+ /* Extend perceptual value using matrix model */
+ if (clip) {
+ int e, di = s->di;
+ double mcv[MXPD], zv[MXPD];
+
+#ifdef DEBUG
+ if (s->pmod_init == 0)
+ error("ofps_cc_percept() called before pmod has been inited");
+#endif
+ /* Lookup matrix mode of perceptual at clipped device */
+ icxCubeInterp(s->pmod, di, di, mcv, cp.p);
+
+ /* Compute a correction factor to add to the matrix model to */
+ /* give the actual perceptual value at the clipped location */
+ for (e = 0; e < di; e++)
+ zv[e] = v[e] - mcv[e];
+
+ /* Compute the unclipped matrix model perceptual value */
+ icxCubeInterp(s->pmod, di, di, v, p);
+
+ /* Add the correction value to it */
+ for (e = 0; e < di; e++)
+ v[e] += zv[e];
+ }
+ return clip;
+}
+
+/* --------------------------------------------------- */
+/* Vertex alloc/free support */
+
+/* Check if a vertex is in the cache index, */
+/* and return it if it is. Return NULL otherwise */
+static vtx *vtx_cache_get(ofps *s, int *nix) {
+ int e, di = s->di;
+ unsigned int hash;
+ vtx *vx;
+
+ hash = (unsigned int)nix[MXPD+1]; /* We assume it was put there by sort */
+
+ for (vx = s->vch[hash]; vx != NULL; vx = vx->chn) {
+ for (e = 0; e <= di; e++) { /* See if it is a match */
+ if (nix[e] != vx->nix[e])
+ break;
+ }
+ if (e > di) { /* It is */
+ return vx;
+ }
+ }
+ return vx;
+}
+
+/* Add a vertex to the cache index */
+static void vtx_cache_add(ofps *s, vtx *vv) {
+ int e, di = s->di;
+ unsigned int hash;
+
+ hash = (unsigned int)vv->nix[MXPD+1];
+
+ /* Add it to the list */
+ vv->chn = s->vch[hash];
+ if (s->vch[hash] != NULL)
+ s->vch[hash]->pchn = &vv->chn;
+ s->vch[hash] = vv;
+ vv->pchn = &s->vch[hash];
+}
+
+/* Remove a vertex from the cache index */
+static void vtx_cache_rem(ofps *s, vtx *vv) {
+ int e, di = s->di;
+ unsigned int hash;
+ vtx *vx;
+
+ hash = (unsigned int)vv->nix[MXPD+1];
+
+ for (vx = s->vch[hash]; vx != NULL; vx = vx->chn) {
+ if (vx == vv) {
+ if (vx->pchn != NULL) {
+ *vx->pchn = vx->chn;
+ if (vx->chn != NULL)
+ vx->chn->pchn = vx->pchn;
+ }
+ return;
+ }
+ }
+ /* Hmm. not in cache */
+}
+
+/* Each vtx returned gets a unique serial number */
+static vtx *new_vtx(ofps *s) {
+ vtx *vv;
+
+ if (s->fvtx != NULL) { /* re-use one we've got */
+ vv = s->fvtx;
+ s->fvtx = vv->link;
+ memset((void *)vv, 0, sizeof(vtx));
+
+ } else {
+ if ((vv = (vtx *)calloc(sizeof(vtx), 1)) == NULL)
+ error("ofps: malloc failed on new vertex");
+ }
+
+ /* Link vertex to currently used list */
+ vv->link = s->uvtx;
+ if (s->uvtx != NULL)
+ s->uvtx->plp = &vv->link;
+ s->uvtx = vv;
+ vv->plp = &s->uvtx;
+ vv->no = s->nxvno++;
+ s->nv++;
+
+ s->nvtxcreated++;
+
+ vv->fuptol = NUMTOL;
+
+ return vv;
+}
+
+/* Remove a vertx from the used list, and put it on the hidden list. */
+/* (Used for making inside and outside vertexes unavailabe) */
+static void remu_vtx(ofps *s, vtx *v) {
+//printf("~1 remu_vtx called on no %d\n",v->no);
+
+ /* Remove it from the used list */
+ if (v->plp != NULL) { /* If is on used list, remove it */
+ *v->plp = v->link;
+ if (v->link != NULL)
+ v->link->plp = v->plp;
+ }
+ v->plp = NULL;
+ v->link = NULL;
+
+ /* Add it to the hidden list */
+ v->link = s->hvtx;
+ if (s->hvtx != NULL)
+ s->hvtx->plp = &v->link;
+ s->hvtx = v;
+ v->plp = &s->hvtx;
+
+ s->nv--; /* Don't count hidden verts */
+}
+
+/* Remove a vertex from the cache and spatial accelleration grid, */
+/* and and the used list. */
+static void del_vtx1(ofps *s, vtx *vx) {
+ node *nn, *nnn;
+
+ if (vx->plp != NULL) { /* If is on used list, remove it */
+ *vx->plp = vx->link;
+ if (vx->link != NULL)
+ vx->link->plp = vx->plp;
+ s->nv--;
+ }
+
+ if (vx->pfchl != NULL) { /* If is on fixup check list, remove it */
+ *vx->pfchl = vx->fchl;
+ if (vx->fchl != NULL)
+ vx->fchl->pfchl = vx->pfchl;
+ }
+ vx->pfchl = NULL;
+ vx->fchl = NULL;
+
+ if (vx->ofake == 0) {
+
+ /* Remove it from cache */
+ vtx_cache_rem(s, vx);
+
+ /* Remove it from spatial accelleration grid */
+ ofps_rem_vacc(s, vx);
+
+ /* Remove it from seeding group */
+ ofps_rem_vseed(s, vx);
+ }
+
+ /* Remove vertex from the s->svtxs[] list */
+ /* so that it doesn't get used in fixups. */
+ if (vx->psvtxs != NULL) {
+ *vx->psvtxs = NULL;
+ vx->psvtxs = NULL;
+ }
+}
+
+/* Delete a vertex by removing it from the cache and spatial accelleration grid, */
+/* and then moving it to the free list */
+/* (It's assumed that it's been removed from all other */
+/* structures by the caller) */
+static void del_vtx(ofps *s, vtx *vx) {
+
+//printf("~1 del_vtx called on no %d\n",vx->no);
+
+ /* Remove it from various lists */
+ del_vtx1(s, vx);
+
+ /* Free vertex net neighbours list */
+ if (vx->nv != NULL) {
+/* !!!! if we need this, we're referencing deleted vertexes !!!! */
+/* vx->nnv = vx->_nnv = 0; */
+ free(vx->nv);
+/* vx->nv = NULL; */
+ }
+
+ /* Add to free list */
+ vx->link = s->fvtx;
+ vx->plp = NULL;
+ s->fvtx = vx;
+
+ s->nvtxdeleted++;
+}
+
+/* Add a vertex to a vertex's net */
+static void vtx_add_vertex(ofps *s, vtx *vv, vtx *vx) {
+ int i;
+
+//printf("~1 Adding vertex no %d comb %s vm %s to vtx %d\n",vx->no,pcomb(s->di,vx->nix),psm(s,&vx->vm),vv->no);
+//printf("~1 Adding vertex no %d to vtx no %d\n",vx->no,vv->no);
+//printf("~1 Before add, no %d list is :",vv->no); for (i = 0; i < vv->nnv; i++) printf(" %d",vv->nv[i]->no); printf("\n");
+ if (vv->_nnv == 0) {
+ vv->_nnv = 4; /* Initial allocation */
+ if ((vv->nv = (vtx **)malloc(sizeof(vtx *) * vv->_nnv)) == NULL)
+ error("ofps: malloc failed on node vertex pointers");
+ } else if (vv->nnv >= vv->_nnv) {
+ vv->_nnv *= 2; /* Double allocation */
+ if ((vv->nv = (vtx **)realloc(vv->nv, sizeof(vtx *) * vv->_nnv)) == NULL)
+ error("ofps: realloc failed on node vertex pointers");
+ }
+#ifdef DEBUG
+{
+ int i;
+
+ /* Check that we're not adding ourself */
+ if (vx == vv) {
+ printf("Adding vtx no %d comb %s to itself!\n",vx->no,pcomb(s->di,vx->nix)); fflush(stdout);
+ error("Adding vtx no %d comb %s to itself!\n",vx->no,pcomb(s->di,vx->nix));
+ }
+
+ /* Check that the vertex is not already here */
+ for (i = 0; i < vv->nnv; i++) {
+ if (vx == vv->nv[i]) {
+ printf("Adding vtx no %d comb %s to vtx %d when already there!\n",vx->no,pcomb(s->di,vx->nix),vv->no); fflush(stdout);
+ fprintf(stderr,"Adding vtx no %d comb %s to vtx %d when already there!\n",vx->no,pcomb(s->di,vx->nix),vv->no); fflush(stdout);
+//*((char *)0) = 55;
+ return;
+ }
+ }
+}
+#endif /* DEBUG */
+
+ vv->nv[vv->nnv++] = vx;
+
+//printf("~1 After add, no %d list is :",vv->no); for (i = 0; i < vv->nnv; i++) printf(" %d",vv->nv[i]->no); printf("\n");
+}
+
+/* Delete a vertex to a vertex's net */
+static void vtx_rem_vertex(ofps *s, vtx *vv, vtx *vx) {
+ int i, j;
+
+//printf("~1 Removing vertex no %d comb %s vm %s from vtx %d\n",vx->no,pcomb(s->di,vx->nix),psm(s,&vx->vm),vv->no);
+//printf("~1 Before delete, no %d list is :",vv->no); for (i = 0; i < vv->nnv; i++) printf(" %d",vv->nv[i]->no); printf("\n");
+
+ for (i = j = 0; i < vv->nnv; i++) {
+ if (vv->nv[i] != vx) {
+ vv->nv[j] = vv->nv[i];
+ j++;
+ }
+ }
+ vv->nnv = j;
+//printf("~1 After delete, no %d list is :",vv->no); for (i = 0; i < vv->nnv; i++) printf(" %d",vv->nv[i]->no); printf("\n");
+}
+
+/* Given two vertexes, check if they are neighbours, and if they are, */
+/* add them to each others neighbourhood. */
+/* If fixup is set, first check that they arn't already neighbours */
+/* Return nz if ther were added to each other */
+static int vtx_cnd_biadd_vtx(ofps *s, vtx *vx1, vtx *vx2, int fixup) {
+ int f, ff, e, di = s->di;
+ int aa, bb, cc; /* Probable hit check */
+ int nnm, nmix;
+
+ if (vx1 == vx2)
+ return 0;
+
+#ifdef NEVER /* vertex net needs all neighbours ? */
+#ifdef INDEP_SURFACE
+ /* Can only have a net between them if they are visible to each other */
+ if (sm_vtx_vtx(s, vx1, vx2) == 0)
+ return 0;
+#endif
+#endif
+
+ /* Use the nixm to quickly check if all but one parent node matches */
+ aa = vx1->nix[MXPD+2]; /* nixm */
+ bb = vx2->nix[MXPD+2]; /* nixm */
+ if ((aa & bb) == 0 || (cc = aa & ~bb, (cc & (cc-1)) != 0)) {
+ return 0; /* It's certainly not */
+ }
+
+ /* Do an exact check of all except one node match */
+ for (nnm = ff = e = 0; e <= di; e++) {
+ for (f = ff; f <= di; f++) {
+ if (vx1->nix[e] == vx2->nix[f]) {
+ ff = f; /* Start from here next time */
+ break;
+ }
+ if (vx1->nix[e] > vx2->nix[f]) /* No point in looking further */
+ f = di;
+ }
+ if (f > di) { /* Didn't match */
+ if (++nnm > 1)
+ break;
+ nmix = e;
+ }
+ }
+ if (e <= di) {
+ return 0; /* No match */
+ }
+
+ if (nnm == 0) {
+ fflush(stdout);
+ error("ofps: two vertexes have the same nodes !\n"
+ "no %d at %s nix %s\nno %d at %s nix %s",
+ vx1->no,ppos(di,vx1->p),pcomb(di,vx1->nix),
+ vx2->no,ppos(di,vx2->p),pcomb(di,vx2->nix));
+ }
+
+ /* If fixup or not INDEP_SURFACE, check that the vertex */
+ /* is not already here */
+#ifndef INDEP_SURFACE
+ if (fixup)
+#endif
+ {
+ int i;
+ vtx *va = vx1, *vb = vx2;
+
+ if (vx1->nnv > vx2->nnv) { /* Search the shortest list */
+ va = vx2;
+ vb = vx1;
+ }
+ for (i = 0; i < va->nnv; i++) {
+ if (vb == va->nv[i]) {
+ return 0;
+ }
+ }
+ }
+
+//printf("~1 Adding net between vtx no %d and no %d\n",vx1->no,vx2->no);
+ /* vx2 is a neighbour, so add it to the vtx net */
+ vtx_add_vertex(s, vx1, vx2);
+
+ /* The reverse must apply too */
+ vtx_add_vertex(s, vx2, vx1);
+
+ return 1;
+}
+
+#ifdef NEVER /* Not used */
+
+/* Clear any veroinoi content of a vertex, but not the vertex itself. */
+static void vtx_clear(ofps *s, vtx *v) {
+
+ /* Clear the list of vertex net neighbours */
+ v->nnv = 0;
+}
+
+/* Free any allocated content of a vertex, but not the vertex itself. */
+static void vtx_free(ofps *s, vtx *v) {
+
+//printf("~1 freeing node ix %d and all contents\n",v->ix);
+
+ /* Free up list of Vertex net neighbours */
+ if (v->nv != NULL) {
+ v->nnv = v->_nnv = 0;
+ free(v->nv);
+ v->nv = NULL;
+ }
+}
+#endif /* NEVER */
+
+/* vertex binary tree support */
+
+static int vtx_aat_cmp_eperr(const void *p1, const void *p2) {
+ return ((vtx *)p1)->eperr == ((vtx *)p2)->eperr ? 0 :
+ (((vtx *)p1)->eperr < ((vtx *)p2)->eperr ? -1 : 1);
+}
+
+static int vtx_aat_cmp_eserr(const void *p1, const void *p2) {
+ return ((vtx *)p1)->eserr == ((vtx *)p2)->eserr ? 0 :
+ (((vtx *)p1)->eserr < ((vtx *)p2)->eserr ? -1 : 1);
+}
+
+
+/* --------------------------------------------------- */
+/* Midpoint alloc/free support */
+
+/* Each mid returned gets a unique serial number */
+/* and a refc or 0 */
+static mid *new_mid(ofps *s) {
+ mid *p;
+
+ if (s->fmid != NULL) { /* re-use one we've got */
+ p = s->fmid;
+ s->fmid = p->link;
+ memset((void *)p, 0, sizeof(mid));
+
+ } else {
+ if ((p = (mid *)calloc(sizeof(mid), 1)) == NULL)
+ error("ofps: malloc failed on new midpoint");
+ }
+
+ /* Link midpoint to currently used list */
+ p->link = s->umid;
+ if (s->umid != NULL)
+ s->umid->plp = &p->link;
+ s->umid = p;
+ p->plp = &s->umid;
+ p->no = s->nxmno++;
+
+ return p;
+}
+
+/* Decrement reference count, and midpoint to the free list */
+static void del_mid(ofps *s, mid *p) {
+//printf("~1 del_mid called on no %d, refc = %d\n",p->no,p->refc);
+ if (--p->refc <= 0) {
+
+ if (p->plp != NULL) { /* If is on used list, remove it */
+ *p->plp = p->link;
+ if (p->link != NULL)
+ p->link->plp = p->plp;
+ }
+
+ p->link = s->fmid; /* Add to free list */
+ p->plp = NULL;
+ s->fmid = p;
+ p->refc = 0;
+ }
+}
+
+/* --------------------------------------------------- */
+/* Node basic support functions */
+
+/* Clear any veroinoi content of a node, but not the node itself. */
+static void node_clear(ofps *s, node *p) {
+
+ /* Clear the list of Voronoi verticies */
+ p->nvv = 0;
+
+ /* Clear any midpoints and nodes */
+ while (p->nvn > 0) {
+ if (p->mm[--p->nvn] != NULL)
+ del_mid(s, p->mm[p->nvn]);
+ }
+}
+
+/* Free any allocated content of a node, but not the node itself. */
+static void node_free(ofps *s, node *p) {
+
+//printf("~1 freeing node ix %d and all contents\n",p->ix);
+
+ /* Free up list of Voronoi verticies */
+ if (p->vv != NULL) {
+ free(p->vv);
+ p->vv = NULL;
+ p->nvv = p->_nvv = 0;
+ }
+
+ /* Free up list of voronoi node indexes */
+ if (p->vn != NULL) {
+ while (p->nvn > 0) {
+ if (p->mm[--p->nvn] != NULL)
+ del_mid(s, p->mm[p->nvn]);
+ }
+ p->nvn = p->_nvn = 0;
+ free(p->vn);
+ free(p->mm);
+ p->vn = NULL;
+ p->mm = NULL;
+ }
+
+ p->nsp = 0; /* No list of surface planes */
+}
+
+/* Add a vertex to the node vertex list */
+static void node_add_vertex(ofps *s, node *pp, vtx *vx) {
+
+//printf("~1 Adding vertex no %d comb %s vm %s to node %d\n",vx->no,pcomb(s->di,vx->nix),psm(s,&vx->vm),pp->ix);
+#ifdef DEBUG
+ if (vx->del)
+ warning("!!!!! adding vertex no %d with delete flag set!!!",vx->no);
+#endif
+
+ if (pp->_nvv == 0) {
+ pp->_nvv = 4; /* Initial allocation */
+ if ((pp->vv = (vtx **)malloc(sizeof(vtx *) * pp->_nvv)) == NULL)
+ error("ofps: malloc failed on node vertex pointers");
+ } else if (pp->nvv >= pp->_nvv) {
+ pp->_nvv *= 2; /* Double allocation */
+ if ((pp->vv = (vtx **)realloc(pp->vv, sizeof(vtx *) * pp->_nvv)) == NULL)
+ error("ofps: realloc failed on node vertex pointers");
+ }
+
+#ifdef DEBUG
+{
+ int i;
+
+ /* Check that the vertex is not already here */
+ for (i = 0; i < pp->nvv; i++) {
+ if (vx == pp->vv[i]) {
+ printf("Adding vtx no %d comb %s when already there!\n",vx->no,pcomb(s->di,vx->nix)); fflush(stdout);
+ error("Adding vtx no %d comb %s when already there!",vx->no,pcomb(s->di,vx->nix)); fflush(stdout);
+ }
+ }
+}
+#endif /* DEBUG */
+
+ pp->vv[pp->nvv++] = vx;
+
+#ifdef NEVER
+#ifdef DEBUG
+ {
+ int e, di = s->di;
+ printf("~1 +++ Node ix %d add vtx no %d pos %s err %f @ %d:",pp->ix,vx->no,ppos(di,vx->p),vx->eperr,pp->nvv);
+ for (e = 0; e < pp->nvv; e++)
+ printf("%d ",pp->vv[e]->no);
+ printf("\n");
+ }
+#endif
+#endif
+}
+
+/* Remove a vertex from the node vertex list */
+static void node_rem_vertex(ofps *s, node *pp, vtx *vx) {
+ int i, j;
+
+//printf("~1 Removing vertex no %d comb %s vm %s from node ix %d\n",vx->no,pcomb(s->di,vx->nix),psm(s,&vx->vm),pp->ix);
+//printf("~1 Before delete, no %d list is :",vv->no); for (i = 0; i < vv->nnv; i++) printf(" %d",vv->nv[i]->no); printf("\n");
+
+ for (i = j = 0; i < pp->nvv; i++) {
+ if (pp->vv[i] != vx) {
+ pp->vv[j] = pp->vv[i];
+ j++;
+ }
+ }
+ pp->nvv = j;
+}
+
+/* Add a node index to the node */
+static void node_add_nix(ofps *s, node *pp, int ix) {
+
+ if (pp->_nvn == 0) {
+ pp->_nvn = 4; /* Initial allocation */
+ if ((pp->vn = (int *)malloc(sizeof(int) * pp->_nvn)) == NULL)
+ error("ofps: malloc failed on node index list");
+ if ((pp->mm = (mid **)malloc(sizeof(mid *) * pp->_nvn)) == NULL)
+ error("ofps: malloc failed on midpoint pointer list");
+ } else if (pp->nvn >= pp->_nvn) {
+ pp->_nvn *= 2; /* Double allocation */
+ if ((pp->vn = (int *)realloc(pp->vn, sizeof(int) * pp->_nvn)) == NULL)
+ error("ofps: realloc failed on node index list");
+ if ((pp->mm = (mid **)realloc(pp->mm, sizeof(mid *) * pp->_nvn)) == NULL)
+ error("ofps: realloc failed on midpoint pointer list");
+ }
+ pp->vn[pp->nvn] = ix;
+ pp->mm[pp->nvn++] = NULL;
+
+#ifdef NEVER
+#ifdef DEBUG
+ {
+ int e, di = s->di;
+ printf("~1 +++ Node ix %d add node ix %d at %s @ %d: ",pp->ix,ix,ppos(di,pp->p),pp->nvn);
+ for (e = 0; e < pp->nvn; e++)
+ printf("%d ",pp->vn[e]);
+ printf("\n");
+ }
+#endif
+#endif
+}
+
+/* Recompute a nodes neighborhood nodes. */
+/* (Invalidates and deletes any midpoints) */
+static void node_recomp_nvn(
+ ofps *s,
+ node *pp
+) {
+ int e, di = s->di;
+ int i, j, k;
+
+#ifdef DEBUG
+ printf("node_recomp_nvn for node ix %d\n",pp->ix);
+#endif
+ /* Clear any midpoints and nodes */
+ while (pp->nvn > 0) {
+ if (pp->mm[--pp->nvn] != NULL)
+ del_mid(s, pp->mm[pp->nvn]);
+ }
+ s->nvnflag++; /* Make sure each node is only added once */
+ pp->nvnflag = s->nvnflag; /* Don't put self in list */
+
+ for (i = 0; i < pp->nvv; i++) { /* For each vertex */
+ double rads;
+ vtx *vv = pp->vv[i];
+
+ for (j = 0; j <= di; j++) { /* For each node in vertex */
+ int ix = vv->nix[j];
+ node *ap = s->n[ix];
+
+ if (ap->nvnflag == s->nvnflag)
+ continue; /* Already done that node */
+
+ node_add_nix(s, pp, ix);
+ ap->nvnflag = s->nvnflag; /* Don't worry about it again */
+ }
+ }
+}
+
+/* Sort a vertex node index array of di+1 nodes, */
+/* and add a hash at MXDP+1, and nixm at MXDP+2 */
+/* This is to speed up searching for a match */
+/* Sort largest to smallest (so fake gamut nodes are last) */
+static void sort_nix(ofps *s, int *nix) {
+ int i, j, t;
+ int di = s->di; /* There are di+1 nodes */
+ unsigned int hash = 0;
+ int nixm = 0;
+
+ /* Do a really simple exchange sort */
+ for (i = 0; i < di; i++) {
+ for (j = i+1; j <= di; j++) {
+ if (nix[i] < nix[j]) {
+ t = nix[j];
+ nix[j] = nix[i];
+ nix[i] = t;
+ }
+ }
+ }
+
+ /* And then compute the hash and nixm */
+ for (i = 0; i <= di; i++) {
+ int bitp, ix = nix[i];
+ hash = hash * 17 + nix[i];
+ bitp = 31 & (ix + (ix >> 4) + (ix >> 8) + (ix >> 12));
+ nixm |= (1 << bitp);
+ }
+ hash %= VTXCHSIZE;
+
+ nix[MXPD+1] = (int)hash;
+ nix[MXPD+2] = nixm;
+}
+
+/* Check if the given locate is on the gamut boundary surface, */
+/* and return the corresponding plane mask */
+static unsigned int check_pos_gsurf(ofps *s, double *p) {
+ int i, e, di = s->di;
+ unsigned int pmask = 0;
+
+ /* For all the gamut boundary planes */
+ for (i = 0; i < s->nbp; i++) {
+ pleq *vp = &s->gpeqs[i];
+ double v;
+
+ for (v = vp->pe[di], e = 0; e < di; e++) /* Compute relation to plane equation */
+ v += vp->pe[e] * p[e];
+ /* See if this location close to, or outside boundary plane */
+ if (v > -s->surftol)
+ pmask |= (1 << i);
+ }
+#ifdef MAXINDEP_2D
+ if (s->sc[pmask].valid == 0)
+ pmask = 0;
+#endif
+ return pmask;
+}
+
+/* Check if the given node is on the gamut boundary surface, */
+/* and record the number of surfaces it is on. */
+/* Return nz if the node is on one or more gamut boundaries. */
+/* Set the state of the node clip flag too. */
+static int det_node_gsurf(ofps *s, node *n, double *p) {
+ int i, e, di = s->di;
+ double ss;
+
+ n->nsp = 0;
+ n->pmask = 0;
+
+ /* For all the gamut boundary planes */
+ for (i = 0; i < s->nbp; i++) {
+ pleq *vp = &s->gpeqs[i];
+ double v;
+
+ for (v = vp->pe[di], e = 0; e < di; e++) /* Compute relation to plane equation */
+ v += vp->pe[e] * p[e];
+
+ /* See if this location close to, or outside boundary plane */
+ if (v > -s->surftol) {
+ /* Add pointer to plane it falls on */
+ n->sp[n->nsp++] = vp;
+ n->pmask |= (1 << i);
+ if (n->nsp > MXPD+1)
+ error("Assert in ofps det_node_gsurf : nsp %d > MXPD +1 %d",n->nsp, MXPD+1);
+ }
+ }
+
+#ifdef MAXINDEP_2D
+ if (s->sc[n->pmask].valid == 0) {
+ n->pmask = 0;
+ n->nsp = 0;
+ }
+#endif
+//printf("~1 node pmask = 0x%x\n",n->pmask);
+
+ return (n->nsp > 0);
+}
+
+/* Compute a cmask from an nix */
+static unsigned int comp_cmask(ofps *s, int *nix) {
+ unsigned int smask = 0, cmask = ~0;
+ int i, e, di = s->di;
+
+ /* The composition mask indicates all the common surface planes */
+ /* that a vertexes parent nodes lie on. Given this, one expects */
+ /* the resulting location to be the same of within this. */
+ for (e = 0; e <= di; e++) {
+ int ix = nix[e];
+ if (ix < 0 && ix >= -s->nbp) { /* If fake surface node */
+ smask |= 1 << -ix-1;
+ } else if (ix >= 0) { /* If real node */
+ cmask &= s->n[ix]->pmask;
+ }
+ }
+ if (smask != 0)
+ cmask &= smask;
+
+#ifdef MAXINDEP_2D
+ if (s->sc[cmask].valid == 0)
+ cmask = 0;
+#endif
+
+ return cmask;
+}
+
+/* Check if the given vertex is on the gamut boundary surface, */
+/* and record the number of surfaces it is on. */
+/* Also compute its cmask based on its parent nodes. */
+/* Set the state of the clip flag too. */
+static void det_vtx_gsurf(ofps *s, vtx *vx) {
+ int i, e, di = s->di;
+ unsigned int smask = 0;
+
+ vx->nsp = 0;
+
+ /* The composition mask indicates all the common surface planes */
+ /* that a vertexes parent nodes lie on. Given this, one expects */
+ /* the resulting location to be the same of within this. */
+ vx->cmask = ~0;
+ for (e = 0; e <= di; e++) {
+ int ix = vx->nix[e];
+ if (ix < 0 && ix >= -s->nbp) { /* If fake surface node */
+ smask |= 1 << -ix-1;
+ } else if (ix >= 0) {
+ vx->cmask &= s->n[ix]->pmask;
+ }
+ }
+ if (smask != 0)
+ vx->cmask &= smask;
+
+#ifdef MAXINDEP_2D
+ if (s->sc[vx->cmask].valid == 0)
+ vx->cmask = 0;
+#endif
+
+ /* For all the gamut boundary planes */
+ for (i = 0; i < s->nbp; i++) {
+ pleq *vp = &s->gpeqs[i];
+ double v;
+
+ for (v = vp->pe[di], e = 0; e < di; e++) /* Compute relation to plane equation */
+ v += vp->pe[e] * vx->p[e];
+
+ /* See if this location close to, or outside boundary plane */
+ if (v > -s->surftol) {
+ vx->sp[vx->nsp++] = vp;
+ vx->pmask |= (1 << i);
+ if (vx->nsp > di+1)
+ error("Assert in ofps det_vtx_gsurf : nsp %d > di+1 %d",vx->nsp, di+1);
+ }
+ }
+#ifdef MAXINDEP_2D
+ if (s->sc[vx->pmask].valid == 0) {
+ vx->pmask = 0;
+ vx->nsp = 0;
+ }
+#endif
+
+//printf("~1 vertex pmask = 0x%x, cmask = 0x%x\n",vx->pmask,vx->cmask);
+}
+
+/* Given a device position and a list of surface planes, */
+/* move the position to lie on the closest location */
+/* on those planes. */
+static void confineto_gsurf(ofps *s, double *p, pleq **psp, int nsp) {
+
+ if (nsp > 0) { /* It's a surface point, so keep it on the surface */
+ int i, j, e, di = s->di;
+ double nn, np, q;
+
+ /* Special case the common situation for speed. */
+ if (nsp == 1) {
+ pleq *sp = psp[0];
+
+ /* Compute the dot product of the plane equation normal */
+ for (nn = 0.0, e = 0; e < di; e++)
+ nn += sp->pe[e] * sp->pe[e];
+
+ /* Compute the dot product of the plane equation and the point */
+ for (np = 0.0, e = 0; e < di; e++)
+ np += sp->pe[e] * p[e];
+
+ /* Compute the parameter */
+ q = (sp->pe[di] + np)/nn;
+
+ /* Compute the closest point */
+ for (e = 0; e < di; e++)
+ p[e] -= q * sp->pe[e];
+
+ /* General case using matrix solution. */
+ /* We compute the proportion of each plane normal vector to add to point */
+ /* to map it onto all planes simultaniously (ie. to map the point to */
+ /* the intersection of all the planes). */
+ } else if (nsp > 1) {
+ double **ta, *TTA[MXPD + 1], TA[MXPD+1][MXPD + 1];
+ double *tb, TB[MXPD + 1];
+
+ for (e = 0; e < nsp; e++)
+ TTA[e] = TA[e];
+ ta = TTA;
+ tb = TB;
+
+ /* For each combination of planes */
+ for (i = 0; i < nsp; i++) {
+ pleq *spi = psp[i];
+ for (j = i; j < nsp; j++) {
+ pleq *spj = psp[j];
+ double vv;
+
+ /* Compute dot product of the two normals */
+ for (vv = 0.0, e = 0; e < di; e++)
+ vv += spi->pe[e] * spj->pe[e];
+ ta[j][i] = ta[i][j] = vv; /* Use symetry too */
+ }
+
+ /* Compute right hand side */
+ for (tb[i] = 0.0, e = 0; e < di; e++)
+ tb[i] += spi->pe[e] * p[e]; /* Dot prod of plane normal and point */
+ tb[i] += spi->pe[di]; /* plus plane constant */
+ }
+ /* Solve the simultaneous linear equations A.x = B */
+ /* Return 1 if the matrix is singular, 0 if OK */
+ if (solve_se(ta, tb, nsp) == 0) {
+ /* Compute the closest point */
+ for (i = 0; i < nsp; i++) {
+ pleq *spi = psp[i];
+ for (e = 0; e < di; e++)
+ p[e] -= tb[i] * spi->pe[e];
+ }
+ }
+ }
+ /* The mapping may leave it out of gamut */
+ ofps_clip_point2(s, p, p);
+ }
+}
+
+/* Given a device position and a list of surface planes, */
+/* check that the point lies on all the planes. */
+/* Return NZ if it does, Z if it doesn't */
+static int checkon_gsurf(ofps *s, double *p, pleq **psp, int nsp) {
+ int i, e, di = s->di;
+ double nn, np, q;
+
+ if (nsp == 0)
+ return 1;
+
+ for (i = 0; i < nsp; i++) {
+ pleq *vp = psp[i];
+ double v;
+
+ for (v = vp->pe[di], e = 0; e < di; e++) /* Compute relation to plane equation */
+ v += vp->pe[e] * p[e];
+
+ /* See if this location close to, or outside boundary plane */
+ if (fabs(v) > s->surftol) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Compute the estimated positioning error given two locations. */
+/* [ This seems to be the critical inner loop in regard to */
+/* overall speed. The dominant callers are dnsq_solver() 10%, */
+/* followed by add_node2voronoi() 5%, others <= 1% ] */
+
+#ifdef NEVER /* Allow performance trace on eperr usage */
+static double ofps_comp_eperr(ofps *s, double *pddist, double *v, double *p, double *nv, double *np);
+static double ofps_comp_eperr1(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+static double ofps_comp_eperr2(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+static double ofps_comp_eperr3(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+static double ofps_comp_eperr4(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+static double ofps_comp_eperr5(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+static double ofps_comp_eperr6(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+static double ofps_comp_eperr7(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+static double ofps_comp_eperr8(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+static double ofps_comp_eperr9(ofps *s, double *pddist, double *v, double *p, double *nv, double *np) {
+ return ofps_comp_eperr(s, pddist, v, p, nv, np); }
+#else /* Production code */
+#define ofps_comp_eperr1 ofps_comp_eperr
+#define ofps_comp_eperr2 ofps_comp_eperr
+#define ofps_comp_eperr3 ofps_comp_eperr
+#define ofps_comp_eperr4 ofps_comp_eperr
+#define ofps_comp_eperr5 ofps_comp_eperr
+#define ofps_comp_eperr6 ofps_comp_eperr
+#define ofps_comp_eperr7 ofps_comp_eperr
+#define ofps_comp_eperr8 ofps_comp_eperr
+#define ofps_comp_eperr9 ofps_comp_eperr
+#endif
+
+static double ofps_comp_eperr(
+ ofps *s,
+ double *pddist, /* If not NULL, return the device distance */
+ double *v, /* Device perceptual value */
+ double *p, /* Device sample location to be evaluated */
+ double *nv, /* Other perceptual value */
+ double *np /* Other perceptual value */
+) {
+ int ii, e, f, di = s->di;
+ int isc;
+ double tt, ddist, pdist;
+ double eperr;
+
+ /* Uncertaintly error computed from device and perceptual distance */
+
+#ifndef NEVER /* unrolled code */
+
+#if MXPD > 4
+# error "ofps.c: Need to expand switch code for MXPD > 4"
+#endif
+ /* Unrole the loop */
+ pdist = ddist = 0.0;
+ switch (di) {
+ case 4:
+ tt = (p[3] - np[3]); /* Device distance */
+ ddist += tt * tt;
+ tt = (v[3] - nv[3]); /* Perceptual distance */
+ pdist += tt * tt;
+ case 3:
+ tt = (p[2] - np[2]); /* Device distance */
+ ddist += tt * tt;
+ tt = (v[2] - nv[2]); /* Perceptual distance */
+ pdist += tt * tt;
+ case 2:
+ tt = (p[1] - np[1]); /* Device distance */
+ ddist += tt * tt;
+ tt = (v[1] - nv[1]); /* Perceptual distance */
+ pdist += tt * tt;
+ case 1:
+ tt = (p[0] - np[0]); /* Device distance */
+ ddist += tt * tt;
+ tt = (v[0] - nv[0]); /* Perceptual distance */
+ pdist += tt * tt;
+ }
+#else
+ /* General code */
+ for (pdist = ddist = 0.0, e = 0; e < di; e++) {
+
+ /* Compute the device distance */
+ tt = (p[e] - np[e]);
+ ddist += tt * tt;
+
+ /* Compute the perceptual distance */
+ tt = (v[e] - nv[e]);
+ pdist += tt * tt;
+ }
+#endif
+
+ if (pddist != NULL)
+ *pddist = ddist;
+
+ ddist *= 100.0 * 100.0;
+
+//printf("~1 Device distance = %f, dev error = %f\n",ddist,s->devd_wght * ddist);
+
+ ddist = sqrt(ddist);
+ pdist = sqrt(pdist);
+ eperr = s->devd_wght * ddist + s->perc_wght * pdist;
+
+//printf("~1 Percept distance = %f, perc error = %f\n",pdist,s->perc_wght * pdist);
+ return eperr;
+}
+
+/* Compute the per node estimated position and interpolation errors */
+/* given a location and a list of up to di+1 neighborhood measurement nodes. */
+static void ofps_pn_eperr(
+ ofps *s,
+ double *ce, /* return the curvature/interpolation error for each node (may be NULL) */
+ double *ee, /* return the uncertaintly error for each node */
+ double *sv, /* Perceptual value if known, othewise NULL */
+ double *sp, /* Device sample location to be evaluated */
+ node **nds, /* Array of pointers to measurement nodes */
+ int nnds /* Number of measurement nodes (>= 1) */
+) {
+ int ii, e, di = s->di;
+ node *np;
+ double _sv[MXPD]; /* Sample perceptual value */
+ double iv[MXPD]; /* Interpolated perceptual value */
+
+ /* Lookup perceptual value at sample point location */
+ if (sv == NULL) {
+ sv = _sv;
+ ofps_cc_percept(s, sv, sp);
+ }
+
+ /* Uncertaintly error computed from device and perceptual distance */
+ for (ii = 0; ii < nnds; ii++) {
+ ee[ii] = ofps_comp_eperr1(s, NULL, sv, sp, nds[ii]->v, nds[ii]->p);
+ }
+
+ if (ce == NULL)
+ return;
+
+ /* This could be made more efficient by only computing it for every */
+ /* vertex during the initial seeding, and then on subsequent */
+ /* passes only computing it once the re-seed/fixups are done. */
+ if (s->curv_wght != 0.0) { /* Don't waste the time unless it's used */
+
+ /* Compute an error estimate that's related to curvature */
+ for (ii = 0; ii < nnds; ii++) {
+ double cp[MXPD]; /* Midway points location */
+ double civ[MXPD]; /* Midway points interpolated perceptual value */
+ double cv[MXPD]; /* Midway points actual perceptual value */
+
+ /* Compute a point midway between the sample location and the node */
+ for (e = 0; e < di; e++) {
+ cp[e] = 0.5 * (sp[e] + nds[ii]->p[e]);
+ civ[e] = 0.5 * (sv[e] + nds[ii]->v[e]);
+ }
+
+ /* Look the actual perceptual value */
+ /* (Computing this for each vertex consumes about 8% of execution time) */
+ ofps_cc_percept(s, cv, cp);
+
+ /* Compute the difference between the interpolated and actual perceptual values */
+ for (ce[ii] = 0.0, e = 0; e < di; e++) {
+ double tt;
+ tt = civ[e] - cv[e];
+ ce[ii] += tt * tt;
+ }
+ ce[ii] = s->curv_wght * sqrt(ce[ii]);
+ }
+ } else {
+ for (ii = 0; ii < nnds; ii++)
+ ce[ii] = 0.0;
+ }
+}
+
+/* Compute the estimated position error given the results */
+/* of ofps_pn_eperr() */
+static double ofps_eperr2(
+ double *ee, /* Uncertainty error for each node */
+ int nnds /* Number of measurement nodes */
+) {
+ double eperr;
+ int ii;
+
+ for (eperr = 1e80, ii = 0; ii < nnds; ii++) {
+ if (ee[ii] < eperr)
+ eperr = ee[ii];
+ }
+
+//printf("~1 ofps_eperr returning %f\n",eperr);
+ return eperr;
+}
+
+/* Compute the estimated sampling error of a location given */
+/* the results of ofps_pn_eperr() */
+static double ofps_eserr2(
+ double *ce, /* The estimated curvature/interpolation error for each node */
+ double *ee, /* Uncertainty error for each node */
+ int nnds /* Number of measurement nodes */
+) {
+ int ii;
+ double eserr;
+ double mxce;
+
+#ifdef NEVER
+ /* We assume errors are inverse probabilities, */
+ /* and sum inverse squares. */
+ for (mxce = 0.0, eserr = 0.0, ii = 0; ii < nnds; ii++) {
+ double tt;
+
+ tt = ee[ii] * ee[ii];
+ if (tt > NUMTOL)
+ eserr += 1.0/tt;
+ else { /* One error is close to zero */
+ eserr = 0.0;
+ break;
+ }
+ if (ce[ii] > mxce)
+ mxce = ce[ii];
+ }
+ if (ii >= nnds)
+ eserr = 1.0/sqrt(eserr);
+ eserr += mxce;
+
+#else /* This seems best ? */
+ /* Return nearest neighbor error metric for the moment, */
+ /* with the ce being the maximum of the surrounders. */
+ for (mxce = 0.0, eserr = 1e80, ii = 0; ii < nnds; ii++) {
+ if (ee[ii] < eserr)
+ eserr = ee[ii];
+ if (ce[ii] > mxce)
+ mxce = ce[ii];
+ }
+ eserr += mxce;
+#endif
+
+//printf("~1 ofps_eserr returning %f\n",eserr);
+ return eserr;
+}
+
+/* - - - - - - - - - -- - - - - - - - - - - - - - - - - - - - */
+/* Finding vertex location code using dnsqe() */
+
+typedef struct {
+ double p[MXPD];
+} loc;
+
+/* Context for callback */
+struct _vopt_cx {
+ ofps *s;
+ node *nds[MXPD+1]; /* List of real nodes */
+ int nn; /* Number of real nodes */
+ int on; /* Index of odd node */
+
+ pleq *sp[MXPD+1]; /* List of touched gamut surface planes */
+ int nsp; /* Number of touched gamut surface planes */
+
+ double srad; /* Search radius used */
+ double stp[MXPD]; /* Starting point used */
+
+#ifdef DUMP_FERR
+ /* Debug: */
+ int debug; /* nz to trace search path */
+ loc *clist; /* List of points sampled */
+ int _nl; /* Allocated size */
+ int nl; /* Number of points */
+#endif
+
+}; typedef struct _vopt_cx vopt_cx;
+
+/* calculate the functions at x[] */
+int dnsq_solver( /* Return < 0 on abort */
+ void *fdata, /* Opaque data pointer */
+ int n, /* Dimenstionality */
+ double *x, /* Multivariate input values */
+ double *fvec, /* Multivariate output values */
+ int iflag /* Flag set to 0 to trigger debug output */
+) {
+ vopt_cx *cx = (vopt_cx *)fdata;
+ ofps *s = cx->s;
+ int k, e, di = s->di;
+ int nn_1 = cx->nn-1;
+ double sv[MXPD];
+ double cee[MXPD+1], teperr;
+
+#ifdef DUMP_FERR
+ /* record the points we visited */
+ if (cx->debug) {
+ if (cx->nl >= cx->_nl) {
+ cx->_nl = 2 * cx->_nl + 5;
+ if ((cx->clist = (loc *)realloc(cx->clist, sizeof(loc) * cx->_nl)) == NULL)
+ error("ofps: malloc failed on debug location array %d", cx->_nl);
+ }
+ for (e = 0; e < di; e++)
+ cx->clist[cx->nl].p[e] = x[e];
+ cx->nl++;
+ }
+#endif
+//printf("~1 dnsq_solver got %d nodes and %d planes\n",cx->nn,cx->nsp);
+
+ /* Get eperr at each real node */
+ ofps_cc_percept(s, sv, x); /* We have to compute it */
+ for (k = 0; k < cx->nn; k++)
+ cee[k] = ofps_comp_eperr2(s, NULL, sv, x, cx->nds[k]->v, cx->nds[k]->p);
+
+//fprintf(stderr,"~1 maxeperr = %f\n",cmax);
+
+//printf("~1 error =");
+//for (k = 0; k < cx->nn; k++)
+// printf(" %f",cee[k]);
+//printf("\n");
+
+ /* We need to create nn-1 output values from nn eperr's */
+ /* cx->on is the odd one out. */
+ /* Difference to average (best) */
+ for (teperr = 0.0, k = 0; k < cx->nn; k++)
+ teperr += cee[k];
+ teperr /= (double)cx->nn;
+
+ for (k = e = 0; k < cx->nn; k++) {
+ if (k != cx->on) {
+ fvec[e++] = (teperr - cee[k]);
+ }
+ }
+
+ /* Compute plane errors */
+ for (k = 0; k < cx->nsp; k++) {
+ pleq *pl = cx->sp[k];
+ double v;
+
+ for (v = pl->pe[di], e = 0; e < di; e++) /* Compute relation to plane equation */
+ v += pl->pe[e] * x[e];
+ fvec[nn_1 + k] = FGPMUL * v;
+ }
+
+ s->funccount++;
+
+//for (k = 0; k < nn_1; k++)
+//printf("~1 fvec[%d] = %f\n",k,fvec[k]);
+//printf("dnsq_solver returning %s from %s\n",ppos(di,fvec),ppos(di,x));
+//fprintf(stderr,"dnsq_solver returning %s from %s\n",ppos(di,fvec),ppos(di,x));
+
+ return 0;
+}
+
+/* Locate a vertex position that has the eperr from all the real nodes */
+/* being equal. Set eperr, eserr and subjective value v[] too. */
+/* vv->ceperr contains the current eperr that must be bettered. */
+/* Return 0 if suceeded, 1 if best result is out of tollerance, 2 if failed. */
+static int position_vtx(
+ ofps *s,
+ nodecomb *vv, /* Return the location and its error */
+ int startex, /* nz if current position is to be used as initial start point */
+ int repos, /* nz after an itteration and we expect out of gamut */
+ int fixup /* nz if doing fixups after itteration and expect out of gamut ??? */
+) {
+ int e, di = s->di;
+ int k, ii;
+ double tw;
+ double atp[MXPD], mct[MXPD]; /* Average node position, middle of closest 2 nodes */
+ double osp[MXPD]; /* Original start position, start position */
+ double cdist, fdist; /* Closest/furthest two points distance apart */
+ double bsrad; /* Basic search radius, search radius */
+ double ftol = FTOL; /* Final eperr tolerance */
+ int tfev = 0, tcalls = 0; /* Track average successful fevs */
+ int maxfev = 50; /* Maximum function evaluations */
+ int tries, notries = MAXTRIES; /* Point to give up on. Giving up will error. */
+ vopt_cx cx, pcx; /* dnsq context + previous context */
+
+#ifdef DEBUG
+ printf("Position_vtx called for comb %s\n",pcomb(di,vv->nix));
+#endif
+
+ s->positions++;
+ s->sob->reset(s->sob);
+
+#ifdef DUMP_FERR
+ cx.debug = 0;
+#endif
+
+ /* Setup for dnsq to optimize for equal eperr */
+ cx.s = s;
+
+ /* Pointers to real nodes. Although we allow for the */
+ /* fake inner/outer nodes, eperr() will fail them later. */
+ for (ii = e = 0; e <= di; e++) {
+ if (vv->nix[e] >= 0 || vv->nix[e] < -s->nbp)
+ cx.nds[ii++] = s->n[vv->nix[e]];
+ }
+ cx.nn = ii;
+
+ if (ii == 0) {
+ fflush(stdout);
+ error("ofps: unexpectedely got no real nodes in vertex position %s",pcomb(di,vv->nix));
+ }
+
+#ifdef DEBUG
+ printf("%d real nodes\n",ii);
+ for (k = 0; k < ii; k++)
+ printf("Node ix %d at %s\n",cx.nds[k]->ix,ppos(di,cx.nds[k]->p));
+#endif
+
+ /* Setup gamut suface planes */
+ cx.nsp = 0;
+ if (ii < (di+1)) {
+ /* Create list of pointers to the gamut surface planes involved */
+ for (e = 0, k = ii; k <= di; e++, k++) {
+#ifdef DEBUG
+ printf("Adding plane for node ix %d\n",vv->nix[k]);
+#endif
+ cx.sp[e] = &s->gpeqs[-1 - vv->nix[k]];
+ }
+ cx.nsp = e;
+ }
+
+ /* If there is only one node, map it to the planes */
+ /* and we're done. */
+ if (ii == 1) {
+ double ee[MXPD+1];
+
+ for (e = 0; e < di; e++)
+ vv->p[e] = cx.nds[0]->p[e];
+
+ confineto_gsurf(s, vv->p, cx.sp, cx.nsp);
+
+ if (checkon_gsurf(s, vv->p, cx.sp, cx.nsp) == 0) {
+#ifdef DEBUG
+ printf("Single node comb %s failed to confine to gamut surface\n",pcomb(di,vv->nix));
+#endif
+ return 2;
+ }
+
+ /* Compute perceptual (can't clip because of confine) */
+ s->percept(s->od, vv->v, vv->p);
+
+ /* Compute the eperr's for each node. */
+ ofps_pn_eperr(s, vv->ce, ee, vv->v, vv->p, cx.nds, cx.nn);
+
+ /* Compute errors at returned location */
+ vv->eperr = ofps_eperr2(ee, cx.nn);
+ vv->eserr = ofps_eserr2(vv->ce, ee, cx.nn);
+
+#ifdef DEBUG
+ printf("Single node, returning comb %s opt pos = %s, eperr = %f, eserr = %f\n",pcomb(di,vv->nix),ppos(di,vv->p),vv->eperr,vv->eserr);
+#endif
+ return 0;
+ }
+ {
+ /* Compute average of real nodes */
+ for (e = 0; e < di; e++)
+ atp[e] = 0.0;
+ for (tw = 0.0, k = 0; k < ii; k++) {
+ double w = 1.0;
+
+ for (e = 0; e < di; e++)
+ atp[e] += cx.nds[k]->p[e];
+ tw += w;
+ }
+ for (e = 0; e < di; e++)
+ atp[e] /= tw;
+
+#ifdef DEBUG
+ printf("Average of %d real node start pos = %s\n",ii,ppos(di,atp));
+#endif
+ }
+
+ /* Locate the closest and furthest two nodes */
+ {
+ double ceperr = 1e200;
+ int i, j, bi = 0, bj = 0;
+
+ /* Find the two vectors that have the closest eperr. Brute force search */
+ /* and track the device position for the two points involved. */
+ /* Also locate the smallest device distance. */
+ cdist = 1e200;
+ fdist = -1.0;
+ for (i = 0; i < (ii-1); i++) {
+ for (j = i+1; j < ii; j++) {
+ double dist;
+ dist = ofps_comp_eperr3(s, NULL, cx.nds[i]->v, cx.nds[i]->p, cx.nds[j]->v, cx.nds[j]->p);
+ if (dist < ceperr) {
+ ceperr = dist;
+ bi = i;
+ bj = j;
+ }
+ for (dist = 0.0, e = 0; e < di; e++) {
+ double tt = cx.nds[i]->p[e] - cx.nds[j]->p[e];
+ dist += tt * tt;
+ }
+ if (dist < cdist)
+ cdist = dist;
+ if (dist > fdist)
+ fdist = dist;
+ }
+ }
+
+ fdist = sqrt(fdist);
+ cdist = sqrt(cdist);
+
+ /* Compute the middle of the two closest eperr nodes */
+ for (e = 0; e < di; e++)
+ mct[e] = 0.5 * (cx.nds[bi]->p[e] + cx.nds[bj]->p[e]);
+
+ /* Set a step/search radius based on the distance */
+ /* between the two closest device distance nodes. */
+ if (cdist < COINTOL) {
+#ifdef DEBUG
+ printf("Two nodes are cooincident! - dnsq will fail!\n");
+#endif
+ if (s->verb > 1)
+ warning("Two nodes are cooincident! ix %d, pos %s and ix %d pos %s",cx.nds[bi]->ix,ppos(di,cx.nds[bi]->p),cx.nds[bj]->ix,ppos(di,cx.nds[bj]->p));
+ }
+ bsrad = 0.2 * cdist;
+ if (bsrad < 1e-5)
+ bsrad = 1e-5;
+ }
+
+ /* Set initial starting position */
+// if (startex && ! ofps_would_clip_point(s, vv->p)) { }
+ if (startex) {
+
+ for (e = 0; e < di; e++)
+ osp[e] = vv->p[e];
+
+// ofps_clip_point(s, vv->p, vv->p);
+#ifdef DEBUG
+ printf("Startex startposition = %s\n",ppos(di,atp));
+#endif
+ } else {
+ double mwt = 0.3;
+ /* Start at equalateral point between two closest */
+ /* nodes towards average. */
+ for (e = 0; e < di; e++) {
+// osp[e] = mct[e]; /* Best for 2D ? */
+// osp[e] = atp[e]; /* best for 3D/4D ? */
+ osp[e] = mwt * mct[e] + (1.0 - mwt) * atp[e]; /* Good compromize */
+ }
+ }
+
+ /* Try our computed starting position first, and if that fails, */
+ /* retry with a random offset starting location. */
+ cx.srad = bsrad;
+ for (e = 0; e < di; e++)
+ cx.stp[e] = osp[e];
+ cx.on = 0;
+
+ for (tries = 0; tries < notries; tries++) {
+ int rv;
+ double fvec[MXPD]; /* Return function value at solution */
+ int cfunccount;
+
+ if (tries > 0) { /* Determine a starting point */
+
+ /* Try all possible odd one outs */
+ cx.on++;
+
+ /* On carry, use a random start offset */
+ /* (Tried culling random starts and odd one outs */
+ /* by picking one with a low norm, but */
+ /* while this reduced the number of small */
+ /* retries, it worsened the number of failures */
+ /* and sucesses after a large number of retries.) */
+ if (cx.on >= cx.nn) {
+ double rscale = 1.0; /* Random scale */
+ double fval[MXPD];
+ int nc;
+
+ s->sob->next(s->sob, cx.stp);
+
+ /* Scale random value around original starting point */
+ for (e = 0; e < di; e++) {
+ cx.stp[e] = cx.stp[e] * 2.0 - 1.0; /* Make -1.0 to 1.0 range */
+ if (cx.stp[e] < 0.0) {
+ cx.stp[e] *= rscale * (osp[e] - s->imin[e]);
+ } else {
+ cx.stp[e] *= rscale * (s->imax[e] - osp[e]);
+ }
+ cx.stp[e] += atp[e];
+ }
+ ofps_clip_point4(s, cx.stp, cx.stp);
+ cx.on = 0;
+ }
+ }
+
+ /* Set start position */
+ for (e = 0; e < di; e++)
+ vv->p[e] = cx.stp[e];
+
+#ifdef DEBUG
+ printf("Starting location = %s, srad = %f, on = %d\n",ppos(di,cx.stp),cx.srad,cx.on);
+#endif
+
+//printf("\nStarting location = %s, srad = %f\n",ppos(di,cx.stp),cx.srad);
+ /* Locate vertex */
+ cfunccount = s->funccount;
+ s->dnsqs++;
+ if (tcalls == 0)
+ maxfev = 500;
+ else
+ maxfev = 2 * tfev/tcalls;
+ rv = dnsqe((void *)&cx, dnsq_solver, NULL, di, vv->p, cx.srad, fvec, 0.0, ftol, maxfev, 0);
+ if ((s->funccount - cfunccount) > 20) {
+//printf("More than 20: %d\n",s->funccount - cfunccount);
+ }
+ if ((s->funccount - cfunccount) > s->maxfunc) {
+ s->maxfunc = (s->funccount - cfunccount);
+//printf("New maximum %d\n",s->maxfunc);
+ }
+
+ if (rv != 1 && rv != 3) {
+ /* Fail to converge */
+#ifdef DEBUG
+ printf("dnsqe fail to converge, retuned %d\n",rv);
+#endif
+ } else {
+ double ee[MXPD+1];
+ double max, min;
+ double ple = 0.0; /* Gamut plane error */
+
+ /* Evaluate the result */
+
+ /* Update average function evaluations */
+ tcalls++;
+ tfev += s->funccount - cfunccount;
+
+#ifdef DEBUG
+ printf("dnsq pos %s\n",ppos(di,vv->p));
+ if (rv == 3)
+ printf("dnsq returned 3 - dtol too small\n");
+#endif
+
+ /* Compute perceptual */
+ ofps_cc_percept(s, vv->v, vv->p);
+
+ /* Compute the eperr's for each node. */
+ ofps_pn_eperr(s, vv->ce, ee, vv->v, vv->p, cx.nds, cx.nn);
+
+ min = 1e80, max = -1e80;
+ for (e = 0; e < cx.nn; e++) {
+ if (min > ee[e])
+ min = ee[e];
+ if (max < ee[e])
+ max = ee[e];
+ }
+
+ /* Compute the worst plane equation error */
+ for (k = 0; k < cx.nsp; k++) {
+ double v;
+ for (v = cx.sp[k]->pe[di], e = 0; e < di; e++) /* Compute relation to plane equation */
+ v += cx.sp[k]->pe[e] * vv->p[e];
+ v = fabs(v * FGPMUL);
+//printf("~1 gamut plane %d err = %f\n",k,v);
+ if (v > ple)
+ ple = v;
+ }
+
+#ifdef DEBUG
+ printf("new vertex pos %s has eperrs match by %f & gamut plane %f\n",ppos(di,vv->p),max-min,ple);
+#endif
+ /* If not dtol too large, Check that the balance is acceptable */
+ if (/* rv != 3 && */
+ (((cx.nn > 1) && (max - min) > (ftol * 2.0))
+ || ((cx.nsp > 0) && ple > (ftol * 2.0)))) {
+ /* Don't use this */
+#ifdef DEBUG
+ printf("new vertex pos %s doesn't have sufficient matching eperrs and on gamut plane\n",ppos(di,vv->p),max-min,ple);
+#endif
+ } else {
+ /* eperr balance is acceptable, so further */
+ /* evaluate the location found. */
+ double ss;
+
+ s->sucfunc += (s->funccount - cfunccount);
+ s->sucdnsq++;
+
+ /* Compute how much the result is out of gamut */
+ vv->oog = ofps_oog(s, vv->p);
+#ifdef DEBUG
+ if (vv->oog > 0.01)
+ printf("dnsq returned out of gamut result by %e\n", vv->oog);
+#endif
+
+ /* Compute errors at returned location */
+ vv->eperr = ofps_eperr2(ee, cx.nn);
+ vv->eserr = ofps_eserr2(vv->ce, ee, cx.nn);
+
+ /* Decide whether a vertex location is acceptable */
+ /* We accept a point that has an acceptable error balance */
+ /* and improves the eperr, and is in gamut if this is not a repos. */
+ /* (There's some mystery stuff in here for fixups) */
+ if ((cx.nn <= 1) || ((max - min) <= (ftol * 2.0)
+ && ((!repos && vv->oog <= 0.01 && vv->eperr < (vv->ceperr + 0.1))
+ || ( repos && vv->oog <= 0.01 && vv->eperr < (5.0 * vv->ceperr + 20.0))
+ || ( repos && vv->oog > 0.0 && vv->eperr < 1000.0)
+ || ( fixup && vv->oog < 20.0 && vv->eperr < (vv->ceperr + 0.01))
+ ))) {
+
+ if (tries > s->maxretries)
+ s->maxretries = tries;
+#ifdef DEBUG
+ printf(" - comb %s suceeded on retry %d (max %d)\n",pcomb(di,vv->nix),tries,s->maxretries);
+ printf(" oog = %f, eperr = %f, ceperr = %f\n",vv->oog,vv->eperr,vv->ceperr);
+#endif
+//if (tries > 10)
+// printf(" - comb %s suceeded on retry %d (max %d)\n",pcomb(di,vv->nix),tries,s->maxretries);
+//
+//printf("Solution for comb %s has eperr %f < ceperr %f and not out of gamut by %f, retry %d\n",pcomb(di,vv->nix),vv->eperr,vv->ceperr,vv->oog,tries+1);
+//printf("Solution is at %s (%s)\n",ppos(di,vv->p),ppos(di,vv->v));
+
+//
+//if (repos) printf("~1 vtx no %d dtav = %f, fdist = %f\n",vv->dtav,fdist);
+//if (repos && vv->vv->no == 889) printf("~1 vtx no %d dtav = %f, fdist = %f\n",vv->vv->no,vv->dtav,fdist);
+
+#ifdef DUMP_FERR /* Create .tiff of dnsq function error */
+ if (tries >= DUMP_FERR) {
+ printf("Suceeded on retry %d, dumping debug rasters\n",tries);
+
+ /* Re-run the last unsucessful dnsq, to trace the path */
+ pcx.debug = 1;
+ pcx.clist = NULL;
+ pcx._nl = 0;
+ pcx.nl = 0;
+ dnsqe((void *)&pcx, dnsq_solver, NULL, di, pcx.stp, pcx.srad, fvec, 0.0, ftol, maxfev, 0);
+ pcx.debug = 0;
+ dump_dnsqe(s, "dnsq_fail2.tif", vv->nix, &pcx);
+ free(pcx.clist);
+
+ /* Re-run the first unsucessful dnsq, to trace the path */
+ pcx.debug = 1;
+ pcx.clist = NULL;
+ pcx._nl = 0;
+ pcx.nl = 0;
+ pcx.on = 0; /* First odd one out */
+ for (e = 0; e < di; e++)
+ pcx.stp[e] = atp[e]; /* best start ? */
+ dnsqe((void *)&pcx, dnsq_solver, NULL, di, pcx.stp, pcx.srad, fvec, 0.0, ftol, maxfev, 0);
+ pcx.debug = 0;
+ dump_dnsqe(s, "dnsq_fail1.tif", vv->nix, &pcx);
+ free(pcx.clist);
+
+ /* Re-run the sucessful dnsq, to trace the path */
+ cx.debug = 1;
+ cx.clist = NULL;
+ cx._nl = 0;
+ cx.nl = 0;
+ dnsqe((void *)&cx, dnsq_solver, NULL, di, cx.stp, cx.srad, fvec, 0.0, ftol, maxfev, 0);
+ cx.debug = 0;
+ dump_dnsqe(s, "dnsq_suc.tif", vv->nix, &cx);
+ free(cx.clist);
+ exit(0);
+ }
+#endif
+
+ break; /* Use the result now */
+ }
+#ifdef DEBUG
+ printf("Solution for comb %s has eperr %f > ceperr %f or out of gamut by %f, retry %d\n",pcomb(di,vv->nix),vv->eperr,vv->ceperr,vv->oog,tries+1);
+#endif
+ }
+ }
+ pcx = cx; /* Save unsucessful context for debug */
+ } /* Retry */
+
+ /* If we've run out of tries, return the best solution we found */
+ if (tries >= notries) {
+
+ /* Show up if this ever gets used */
+ for (e = 0; e < di; e++)
+ vv->p[e] = -0.1;
+ ofps_cc_percept(s, vv->v, vv->p);
+#ifdef DEBUG
+ printf("vertex location solving failed after %d tries\n",tries);
+#endif
+ if (s->verb > 1)
+ warning("vertex location solving failed after %d tries",tries);
+ return 2; /* Don't use this vertex */
+ }
+
+#ifdef DEBUG
+ printf("Returning comb %s opt pos = %s val = %s, eperr = %f, eserr = %f\n",pcomb(di,vv->nix),ppos(di,vv->p),ppos(di,vv->v),vv->eperr,vv->eserr);
+#endif
+
+ return 0;
+}
+
+/* --------------------------------------------------------- */
+/* Deal with creating a dummy vertex to represent one that */
+/* can't be positioned. We simply locate the best point we can. */
+
+/* calculate the functions at x[] */
+double powell_solver( /* Return < 0 on abort */
+ void *fdata, /* Opaque data pointer */
+ double *x /* Multivariate input values */
+) {
+ vopt_cx *cx = (vopt_cx *)fdata;
+ ofps *s = cx->s;
+ int k, e, di = s->di;
+ int nn_1 = cx->nn-1;
+ double sv[MXPD];
+ double cee[MXPD+1], teperr;
+ double ss, oog;
+ double rv = 0.0;
+
+//printf("~1 powell_solver got %d nodes and %d planes\n",cx->nn,cx->nsp);
+
+ /* Get eperr at each real node */
+ ofps_cc_percept(s, sv, x); /* We have to compute it */
+ for (k = 0; k < cx->nn; k++)
+ cee[k] = ofps_comp_eperr2(s, NULL, sv, x, cx->nds[k]->v, cx->nds[k]->p);
+
+//fprintf(stderr,"~1 maxeperr = %f\n",cmax);
+
+//printf("~1 eprror =");
+//for (k = 0; k < cx->nn; k++)
+// printf(" %f",cee[k]);
+//printf("\n");
+
+ /* The error is zero if the input value */
+ /* is within gamut, all the real node eperr's are */
+ /* the same, and the ditance to gamut planes is zero. */
+
+ /* Compute average eperr */
+ for (teperr = 0.0, k = 0; k < cx->nn; k++)
+ teperr += cee[k];
+ teperr /= (double)cx->nn;
+
+//printf("~1 average = %f\n", teperr);
+
+ /* Add diference to average */
+ for (k = e = 0; k < cx->nn; k++) {
+ if (k != cx->on) {
+ double tt;
+ tt = teperr - cee[k];
+ rv += tt * tt;
+ }
+ }
+//printf("~1 after diff to avg rv = %f\n", rv);
+
+ /* Compute distances to planes */
+ for (k = 0; k < cx->nsp; k++) {
+ pleq *pl = cx->sp[k];
+ double v;
+
+ for (v = pl->pe[di], e = 0; e < di; e++) /* Compute relation to plane equation */
+ v += pl->pe[e] * x[e];
+ v *= FGPMUL;
+ rv += v * v;
+ }
+//printf("~1 after diff to planes rv = %f\n", rv);
+
+ /* Compute distance out of gamut */
+
+ for (ss = oog = 0.0, e = 0; e < di; e++) {
+ if (x[e] < (s->imin[e])) {
+ double tt = s->imin[e] - x[e];
+ if (tt > oog) oog = tt;
+ } else if (x[e] > (s->imax[e])) {
+ double tt = x[e] - s->imax[e];
+ if (tt > oog) oog = tt;
+ }
+ ss += x[e];
+ }
+ if (ss > s->ilimit) {
+ double tt;
+ ss = (ss - s->ilimit)/di; /* Axis aligned distance to ink limit */
+ tt = sqrt((double)di) * ss; /* Diagonal distance to ink limit */
+ if (tt > oog)
+ oog = tt;
+ }
+
+ rv += 1000.0 * oog * oog;
+//printf("~1 after oog rv = %f\n", rv);
+
+//printf("powell_solver returning %f from %s\n",rv, ppos(di,x));
+//fprintf(stderr,"powell_solver returning %f from %s\n",rv, ppos(di,x));
+
+ return 0;
+}
+
+/* Fake up a vertex position when position_vtx() has failed. */
+static void dummy_vtx_position(
+ ofps *s,
+ vtx *ev1, vtx *ev2, /* Deleted and non-deleted vertexes */
+ nodecomb *vv /* Return the location and its error */
+) {
+ int e, di = s->di;
+ int k, ii;
+ vopt_cx cx; /* dnsq context */
+ double ss[MXPD];
+ double bl; /* Location on path between del and !del vertexes */
+ double ee[MXPD+1];
+
+#ifdef DEBUG
+ printf("dummy_vtx_position called for comb %s\n",pcomb(di,vv->nix));
+#endif
+
+#ifdef DUMP_FERR
+ cx.debug = 0;
+#endif
+
+ /* Setup for dnsq to optimize for equal eperr */
+ cx.s = s;
+
+ /* Pointers to real nodes. Although we allow for the */
+ /* fake inner/outer nodes, eperr() will fail them later. */
+ for (ii = e = 0; e <= di; e++) {
+ if (vv->nix[e] >= 0 || vv->nix[e] < -s->nbp)
+ cx.nds[ii++] = s->n[vv->nix[e]];
+ }
+ cx.nn = ii;
+
+ if (ii == 0) {
+ fflush(stdout);
+ error("ofps: unexpectedely got no real nodes in vertex position %s",pcomb(di,vv->nix));
+ }
+
+#ifdef DEBUG
+ printf("%d real nodes\n",ii);
+ for (k = 0; k < ii; k++)
+ printf("Node ix %d at %s (%s)\n",cx.nds[k]->ix,ppos(di,cx.nds[k]->p),ppos(di,cx.nds[k]->v));
+#endif
+
+ /* Setup gamut suface planes */
+ cx.nsp = 0;
+ if (ii < (di+1)) {
+ /* Create list of pointers to the gamut surface planes involved */
+ for (e = 0, k = ii; k <= di; e++, k++) {
+#ifdef DEBUG
+ printf("Adding plane for node ix %d\n",vv->nix[k]);
+#endif
+ cx.sp[e] = &s->gpeqs[-1 - vv->nix[k]];
+ }
+ cx.nsp = e;
+ }
+
+ /* Set search area */
+ for (e = 0; e < di; e++)
+ ss[e] = 0.001;
+
+ /* Compute a position on the locus between the del and !del vertexes */
+ bl = (ev1->nba_eperr - ev2->eperr)/(ev1->eperr - ev2->eperr);
+ if (bl < 0.0)
+ bl = 0.0;
+ else if (bl > 1.0)
+ bl = 1.0;
+ for (e = 0; e < di; e++) {
+ vv->p[e] = bl * vv->v1[0]->p[e] + (1.0 - bl) * vv->v2[0]->p[e];
+ }
+
+ ofps_clip_point5(s, vv->p, vv->p);
+
+#ifndef NEVER
+ /* Seem to often fail due to pathalogical condition for max type eperr() */
+ if (powell(NULL, di, vv->p, ss, 1e-5, 1000, powell_solver, &cx, NULL, NULL)) {
+ warning("dummy_vtx_position powell failed");
+ }
+#endif
+
+ ofps_clip_point5(s, vv->p, vv->p);
+
+ /* Compute perceptual (was clipped above) */
+ s->percept(s->od, vv->v, vv->p);
+
+ /* Compute the eperr's for each node. */
+ ofps_pn_eperr(s, vv->ce, ee, vv->v, vv->p, cx.nds, cx.nn);
+
+ /* Compute errors at returned location */
+ vv->eperr = ofps_eperr2(ee, cx.nn);
+ vv->eserr = ofps_eserr2(vv->ce, ee, cx.nn);
+
+#ifdef DEBUG
+ printf("Returning comb %s opt pos = %s val = %s, eperr = %f, eserr = %f\n",pcomb(di,vv->nix),ppos(di,vv->p),ppos(di,vv->v),vv->eperr,vv->eserr);
+#endif
+}
+
+/* --------------------------------------------------- */
+/* Vertex add routines */
+
+/* Comlete adding a node to a Voronoi surface. */
+/* It's assumed that the hit nodes have been added to the s->nxh list */
+/* and the s->nvcheckhits set to the number of hit vertexes. */
+/* The nodes may be fake gamut boundary nodes, but must have */
+/* real vertexes. Vertexes that are marked for deletion or new ones */
+/* will be added to the batch update list for later execution. */
+/* Nodes that have had vertexes added to them will added to the node 'to be updated' list */
+/* and then a batch update will be executed. */
+/* Return 0 if it wasn't added, */
+/* Return 1 if it was added */
+static int add_to_vsurf(
+ofps *s,
+node *nn, /* Node to add */
+int fixup, /* 0 = seed, 1 = fixup ?? */
+int abortonfail /* 0 = ignore position failures, 1 = abort add if there are any failures */
+) {
+ int e, ff, f, di = s->di;
+ int i, j, k, ndi;
+ vtx *tev;
+ vtx *ev1, *ev2; /* Deleted and non-deleted vertexes */
+ int ndelvtx; /* Number of vertexes to delete */
+ int nncombs; /* Number of node combinations generated, allocated. */
+
+#ifdef DEBUG
+ printf("\nAdd_to_vsurf node ix %d (p %s), i_sm %s, a_sm %s\n",nn->ix, ppos(di,nn->p),psm(s,&s->sc[nn->pmask].i_sm),psm(s,&s->sc[nn->pmask].a_sm));
+#endif
+
+#ifdef DEBUG
+ if (nn->ix < -s->nbp) {
+ printf("Fake node involved\n");
+ }
+#endif
+
+ /* Update stats for the hit vertexes */
+ s->nsurfadds++;
+ s->nhitv += s->nvcheckhits;
+ if (s->nvcheckhits > s->maxhitv)
+ s->maxhitv = s->nvcheckhits;
+
+ if (s->nvcheckhits == 0) { /* Node doesn't improve any vertex eperrs */
+#ifdef DEBUG
+ printf("Add_to_vsurf done - not better, not added\n");
+#endif
+ return 0;
+ }
+
+#ifdef DEBUG
+ printf("There are %d vertexes to replace, and %d potential replacement vertexes\n",s->nvcheckhits, di * s->nvcheckhits);
+ printf("Vertexes marked for deletion are:\n");
+ for (ev1 = s->nxh; ev1 != NULL; ev1 = ev1->nxh)
+ printf(" vtx no %d nix %s\n",ev1->no,pcomb(di,ev1->nix));
+#endif
+
+ /* Generate all the potential new node combinations/replacement verticies. */
+ /* We check each deleted vertex against its non-deleted neighbours. */
+ /* The same replacement combination may be generated more than once. */
+ for (nncombs = 0, ev1 = s->nxh; ev1 != NULL; ev1 = ev1->nxh) {
+
+ for (ndi = 0; ndi < ev1->nnv; ndi++) {
+ int nix[MXNIX];
+#ifdef INDEP_SURFACE
+ setmask cvm; /* visibility setmask for each vertex combination */
+#endif
+ ev2 = ev1->nv[ndi];
+
+ if (ev2->del != 0)
+ continue; /* Can't pair with another deleted vertex */
+
+#ifdef DEBUG
+ printf("\nDealing with vertex pair del no %d nix %s, and !del no %d nix %s\n",ev1->no,pcomb(di,ev1->nix),ev2->no,pcomb(di,ev2->nix));
+#endif
+
+#ifdef DEBUG
+ {
+ int aa, bb, cc; /* Probable hit check */
+ int nnm, nmix;
+
+ /* Use the nixm to quickly check if all but one parent node matches */
+ aa = ev1->nix[MXPD+2]; /* nixm */
+ bb = ev2->nix[MXPD+2]; /* nixm */
+ if ((aa & bb) == 0 || (cc = aa & ~bb, (cc & (cc-1)) != 0)) {
+ error("Vertexes %d comb %s and %d comb %s are vn neighbours that shouldn't be!", ev1->no,pcomb(di,ev1->nix),ev2->no,pcomb(di,ev2->nix));
+ }
+
+ /* Do an exact check of all except one node match */
+ for (nnm = ff = e = 0; e <= di; e++) {
+ for (f = ff; f <= di; f++) {
+ if (ev1->nix[e] == ev2->nix[f]) {
+ ff = f; /* Start from here next time */
+ break;
+ }
+ if (ev1->nix[e] > ev2->nix[f]) /* No point in looking further */
+ f = di;
+ }
+ if (f > di) { /* Didn't match */
+ if (++nnm > 1)
+ break;
+ nmix = e;
+ }
+ }
+ if (e <= di) {
+ error("Vertexes %d comb %s and %d comb %s are vn neighbours that shouldn't be!", ev1->no,pcomb(di,ev1->nix),ev2->no,pcomb(di,ev2->nix));
+ }
+ }
+#endif /* DEBUG */
+ /* Create the node combination */
+ for (e = 0; e <= di; e++) {
+ nix[e] = ev1->nix[e];
+ for (f = 0; f <= di; f++) {
+ if (nix[e] == ev2->nix[f])
+ break;
+ }
+ if (f > di) /* Found one different */
+ nix[e] = nn->ix;
+ }
+ sort_nix(s, nix);
+
+ /* Check that the same node doesn't appear twice */
+ /* (~~99 Why do we need this - does it ever happen ??) */
+ for (e = 0; e < di; e++) {
+ for (k = e+1; k <= di; k++) {
+ if (nix[e] == nix[k]) {
+#ifdef DEBUG
+ printf("New vertex with duplicate nodes %s from vertexes %d comb %s and %d comb %s ignored\n",pcomb(di,nix),ev1->no,pcomb(di,ev1->nix),ev2->no,pcomb(di,ev2->nix));
+ if (s->verb > 1)
+ warning("New vertex with duplicate nodes %s from vertexes %d comb %s and %d comb %s ignored",pcomb(di,nix),ev1->no,pcomb(di,ev1->nix),ev2->no,pcomb(di,ev2->nix));
+#endif
+ break;
+ }
+ }
+ if (k <= di)
+ break;
+ }
+ if (e < di)
+ continue;
+
+ /* See if the combination has at least one real node, */
+ /* and none of the inner or outer fake nodes. */
+ /* (~~99 Do we need this - does it ever happen ??) */
+ k = 0;
+ for (e = 0; e <= di; e++) {
+ if (nix[e] >= 0)
+ k |= 1; /* Found one real node */
+ else if (nix[e] < -s->nbp)
+ break; /* There's a fake inner or outer node though */
+ }
+ if (e <= di || k == 0) {
+#ifdef DEBUG
+ printf("Combination ix: %s, skipped because it has no real nodes\n",pcomb(di,nix));
+ if (s->verb > 1)
+ warning("Combination ix: %s, skipped because it has no real nodes",pcomb(di,nix));
+#endif
+ continue;
+ }
+
+#ifdef INDEP_SURFACE
+ /* Compute the pertinent visibility mask for this vertex creation. */
+ /* Note that we keep pairs of vertexes that aren't visible to each other */
+ /* so that we can add them to the vertex net. */
+ sm_andand(s, &cvm, &ev1->vm, &ev2->vm, &s->sc[comp_cmask(s, nix)].a_sm);
+#ifdef DEBUG
+ printf("Combination ix: %s, vm %s, eperrs %f to %f\n",pcomb(di,nix),psm(s,&cvm),ev1->eperr,ev2->eperr);
+#endif
+#else /* !INDEP_SURFACE */
+#ifdef DEBUG
+ printf("Combination ix: %s, eperrs %f to %f\n",pcomb(di,nix),ev1->eperr,ev2->eperr);
+#endif
+#endif /* !INDEP_SURFACE */
+
+ /* See if this combination is already in the list */
+ /* due to a pair having the same common nodes. */
+ for (k = 0; k < nncombs; k++) {
+
+ if (s->combs[k].nix[MXPD+1] != nix[MXPD+1]) /* Hashes don't match */
+ continue;
+
+ for (e = 0; e <= di; e++) { /* Do full check */
+ if (s->combs[k].nix[e] != nix[e]) {
+ break; /* No match */
+ }
+ }
+ if (e > di) { /* Match */
+ double ceperr;
+ if (s->combs[k].count >= s->combs[k]._count) {
+ s->combs[k]._count = 2 * s->combs[k]._count + 5;
+ if ((s->combs[k].v1 = (vtx **)realloc(s->combs[k].v1,
+ sizeof(vtx *) * s->combs[k]._count)) == NULL)
+ error ("ofps: malloc failed on node combination vertex list %d",
+ s->combs[k]._count);
+ if ((s->combs[k].v2 = (vtx **)realloc(s->combs[k].v2,
+ sizeof(vtx *) * s->combs[k]._count)) == NULL)
+ error ("ofps: malloc failed on node combination vertex list %d",
+ s->combs[k]._count);
+ }
+ s->combs[k].v1[s->combs[k].count] = ev1;
+ s->combs[k].v2[s->combs[k].count] = ev2;
+ s->combs[k].count++;
+
+ /* Update ceperr if this is higher */
+ ceperr = ev1->eperr > ev2->eperr ? ev1->eperr : ev2->eperr;
+ if (ceperr > s->combs[k].ceperr)
+ s->combs[k].ceperr = ceperr;
+#ifdef DEBUG
+ printf("Vertex generation count now %d with ceperr %f\n",s->combs[k].count,s->combs[k].ceperr);
+#endif
+#ifdef INDEP_SURFACE
+ sm_or(s, &s->combs[k].vm, &s->combs[k].vm, &cvm);
+#ifdef DEBUG
+ printf("Vertex combination vm now %s\n",psm(s,&s->combs[k].vm));
+#endif
+#endif
+ break;
+ }
+ }
+ if (k < nncombs)
+ continue; /* Already on list */
+
+ /* Add this combination to the list as a new entry */
+ if (nncombs >= s->_ncombs) {
+ int o_ncombs = s->_ncombs;
+ s->_ncombs = 2 * s->_ncombs + 5;
+ if ((s->combs = (nodecomb *)realloc(s->combs, sizeof(nodecomb) * s->_ncombs)) == NULL)
+ error ("ofps: malloc failed on node combination array length %d", s->_ncombs);
+ memset((void *)(s->combs + o_ncombs), 0,
+ (s->_ncombs - o_ncombs) * sizeof(nodecomb));
+ }
+
+ if (1 >= s->combs[nncombs]._count) {
+ s->combs[nncombs]._count = 2 * s->combs[nncombs]._count + 5;
+ if ((s->combs[nncombs].v1 = (vtx **)realloc(s->combs[nncombs].v1,
+ sizeof(vtx *) * s->combs[nncombs]._count)) == NULL)
+ error ("ofps: malloc failed on node combination vertex list %d",
+ s->combs[nncombs]._count);
+ if ((s->combs[nncombs].v2 = (vtx **)realloc(s->combs[nncombs].v2,
+ sizeof(vtx *) * s->combs[nncombs]._count)) == NULL)
+ error ("ofps: malloc failed on node combination vertex list %d",
+ s->combs[nncombs]._count);
+ }
+ s->combs[nncombs].v1[0] = ev1;
+ s->combs[nncombs].v2[0] = ev2;
+ s->combs[nncombs].count = 1;
+ for (e = 0; e <= di; e++)
+ s->combs[nncombs].nix[e] = nix[e];
+ s->combs[nncombs].nix[MXPD+1] = nix[MXPD+1]; /* Copy Hash */
+ s->combs[nncombs].nix[MXPD+2] = nix[MXPD+2]; /* Copy nixm */
+ s->combs[nncombs].ceperr = ev1->eperr > ev2->eperr ? ev1->eperr : ev2->eperr;
+ s->combs[nncombs].startex = 0;
+ s->combs[nncombs].pvalid = 0;
+ s->combs[nncombs].vv = NULL;
+#ifdef INDEP_SURFACE
+ sm_cp(s, &s->combs[nncombs].vm, &cvm);
+#else /* !INDEP_SURFACE */
+ sm_set(s, &s->combs[nncombs].vm, 0); /* Not used */
+#endif /* !INDEP_SURFACE */
+
+ nncombs++;
+
+#ifdef DEBUG
+ printf("Adding combination to list with ceperr %f, vm %s, list size %d\n",s->combs[nncombs-1].ceperr,psm(s,&s->combs[nncombs-1].vm), nncombs);
+#endif
+ }
+ }
+
+#ifdef DEBUG
+ printf("\nThere are %d unique node combinations in list, locating combs. in list:\n",nncombs);
+#endif
+
+ /* Locate the replacement vertex positions */
+ for (i = 0; i < nncombs; i++) {
+
+ ev1 = s->combs[i].v1[0];
+ ev2 = s->combs[i].v2[0];
+
+#ifdef INDEP_SURFACE
+ /* Ignore pairs of vertexes that don't form a visible new combination */
+ if (sm_test(s, &s->combs[i].vm) == 0) {
+#ifdef DEBUG
+ printf("Combination ix: %s, skipped because vm %s == 0x0\n",pcomb(di,s->combs[i].nix),psm(s,&s->combs[i].vm));
+#endif
+ continue;
+ }
+#endif /* INDEP_SURFACE */
+
+#ifdef DEBUG
+ printf("\nNode combination ix: %s\n",pcomb(di,s->combs[i].nix));
+#endif
+ /* Try and locate existing vertex that is due to the same nodes */
+ if ((s->combs[i].vv = vtx_cache_get(s, s->combs[i].nix)) != NULL) {
+#ifdef DEBUG
+ printf("Vertex is same as existing no %d\n",s->combs[i].vv->no);
+#endif
+
+ s->combs[i].vv->add = 2; /* Updated vertex */
+
+ /* If a new vertex is not the same as the two nodes it's being created */
+ /* from yet has been marked for deletion, reprieve it. */
+ if (s->combs[i].vv->del) {
+
+ s->combs[i].vv->del = 0;
+#ifdef DEBUG
+ printf("New existing vertex no %d is deleted vertex - reprieve it\n",s->combs[i].vv->no);
+#endif
+ }
+ }
+
+ /* We need to create a replacement vertex, locate position for it */
+ if (s->combs[i].vv == NULL) {
+#ifdef DEBUG
+ printf("About to locate comb ix: %s, ceperr %f\n",pcomb(di,s->combs[i].nix),s->combs[i].ceperr);
+#endif
+//printf("~1 About to locate comb ix: %s, ceperr %f\n",pcomb(di,s->combs[i].nix),s->combs[i].ceperr);
+ /* Compute a starting position between the deleted/not deleted pair */
+ /* This seems very slightly better than the default mct[] + atp[] scheme. */
+ if (nn->ix >= 0) { /* If not boundary */
+ double bl;
+ bl = (ev1->nba_eperr - ev2->eperr)/(ev1->eperr - ev2->eperr);
+ if (bl < 0.0)
+ bl = 0.0;
+ else if (bl > 1.0)
+ bl = 1.0;
+ for (e = 0; e < di; e++) {
+ s->combs[i].p[e] = bl * s->combs[i].v1[0]->p[e] + (1.0 - bl) * s->combs[i].v2[0]->p[e];
+ }
+ ofps_clip_point5(s, s->combs[i].p, s->combs[i].p);
+//printf("Startex is %s\n",ppos(di,s->combs[i].p));
+ s->combs[i].startex = 1;
+ }
+ /* find vertex position of max eperr */
+ if (position_vtx(s, &s->combs[i], s->combs[i].startex, 0, fixup) != 0) {
+ if (s->verb > 1)
+ warning("Unable to locate vertex at node comb %s\n",pcomb(di,s->combs[i].nix));
+ s->posfails++;
+ s->posfailstp++;
+ if (abortonfail)
+ break;
+
+ } else {
+ s->combs[i].pvalid = 1;
+ }
+ }
+ } /* Next replacement vertex */
+
+ /* If we aborted because abortonfail is set and we failed to place a new node, */
+ /* erase our tracks and return failure. */
+ if (i < nncombs) {
+ for (i = 0; i < nncombs; i++) {
+ if (s->combs[i].vv != NULL) {
+ s->combs[i].vv->add = 0;
+ s->combs[i].vv->del = 0;
+ }
+ }
+ return 0;
+ }
+
+#ifdef DEBUG
+ printf("\nNow converting positioned combinations to vertexes\n");
+#endif
+ /* Convert from computed position to vertexes */
+ for (i = 0; i < nncombs; i++) {
+
+#ifdef INDEP_SURFACE
+ /* Ignore combo that doesn't form a visible new vertex */
+ if (sm_test(s, &s->combs[i].vm) == 0)
+ continue;
+#endif /* INDEP_SURFACE */
+
+ if (s->combs[i].vv == NULL) { /* Not an existing vertex */
+
+ if (s->combs[i].pvalid == 0) { /* No valid vertex found */
+
+ /* [ If a valid vertex location was not found we tried */
+ /* using the deleted vertex's location instead, and */
+ /* relying on it getting deleted at some later stage. */
+ /* This seems to stuff the incremental fixup code up */
+ /* completely, so we create a summy vertex position instead. ] */
+
+ /* Fake up a vertex position when position_vtx() has failed. */
+ dummy_vtx_position(s, ev1, ev2, &s->combs[i]);
+ goto lnew_vtx;
+
+ } else {
+
+ lnew_vtx:;
+ /* Allocate space for new vertex, and create it from location */
+ s->combs[i].vv = new_vtx(s);
+
+#ifdef DEBUG
+ printf("Converting comb %s to from del %d !del %d to vtx no %d vm %s\n",pcomb(di,s->combs[i].nix),s->combs[i].v1[0]->no, s->combs[i].v2[0]->no, s->combs[i].vv->no,psm(s,&s->combs[i].vm));
+#endif
+
+ for (e = 0; e < di; e++) {
+ s->combs[i].vv->nix[e] = s->combs[i].nix[e];
+ s->combs[i].vv->ce[e] = s->combs[i].ce[e];
+ s->combs[i].vv->p[e] = s->combs[i].p[e];
+ s->combs[i].vv->v[e] = s->combs[i].v[e];
+ }
+ s->combs[i].vv->nix[e] = s->combs[i].nix[e];
+ s->combs[i].vv->nix[MXPD+1] = s->combs[i].nix[MXPD+1]; /* Copy Hash */
+ s->combs[i].vv->nix[MXPD+2] = s->combs[i].nix[MXPD+2]; /* Copy nixm */
+
+ s->combs[i].vv->eperr = s->combs[i].eperr;
+ s->combs[i].vv->eserr = s->combs[i].eserr;
+
+ /* Count the number of gamut surfaces the vertex falls on */
+ det_vtx_gsurf(s, s->combs[i].vv);
+
+ /* Check if the node and vertex cooincide, and aren't going to move */
+ if (nn->nsp == di && s->combs[i].vv->nsp == di
+ && nn->pmask == s->combs[i].vv->pmask) {
+//printf("~1 Trapped node and vertex coincide - mark vertex as ghost\n");
+ s->combs[i].vv->ghost = 1;
+ }
+ s->combs[i].vv->del = 0;
+ s->combs[i].vv->add = 1; /* New vertex */
+ }
+ }
+
+ if (s->combs[i].vv != NULL) { /* There is a new or updated vertex */
+#ifdef DEBUG
+ printf("Vertex no %d pmask 0x%x cmask 0x%x vm %s at %s being added to batch list\n",s->combs[i].vv->no, s->combs[i].vv->pmask, s->combs[i].vv->cmask, psm(s,&s->combs[i].vm),ppos(di,s->combs[i].vv->p));
+#endif
+ /* Add to batch update list if it is not already there */
+ if (s->combs[i].vv->bch == 0) {
+//printf("~1 adding vtx 0x%x no %d to batch list\n",s->combs[i].vv,s->combs[i].vv->no);
+ s->combs[i].vv->batch = s->batch;
+ s->batch = s->combs[i].vv;
+ s->combs[i].vv->bch = 1;
+ }
+
+#ifdef INDEP_SURFACE
+ /* Set or update the vm */
+ sm_or(s, &s->combs[i].vv->buvm, &s->combs[i].vv->buvm, &s->combs[i].vm);
+//printf("~1 Vertex no %d buvm set/update to %s\n",s->combs[i].vv->no,psm(s,&s->combs[i].vv->buvm));
+#endif /* INDEP_SURFACE */
+ }
+ }
+
+ /* Add all vtx marked for deletion to the batch update list. */
+ for (ev1 = s->nxh; ev1 != NULL; ev1 = ev1->nxh) {
+
+#ifdef DEBUG
+ printf("Vertex no %d being added to pending delete batch list, bdvm %s\n",ev1->no,psm(s,&ev1->bdvm));
+#endif
+
+ if (ev1->bch == 0) {
+//printf("~1 adding vtx 0x%x no %d to batch list\n",ev1,ev1->no);
+ ev1->batch = s->batch;
+ s->batch = ev1;
+ ev1->bch = 1;
+ }
+
+#ifdef INDEP_SURFACE
+ /* Add node setmask to those that will be removed delete vertex visibility */
+# ifdef USE_DISJOINT_SETMASKS
+ sm_orand(s, &ev1->bdvm, &ev1->bdvm, &s->sc[nn->pmask].a_sm, &s->sc[ev1->cmask & nn->pmask].a_sm);
+# else
+ sm_or(s, &ev1->bdvm, &ev1->bdvm, &s->sc[nn->pmask].a_sm);
+# endif
+#endif /* INDEP_SURFACE */
+ }
+
+ /* Do first part of batch update. */
+ /* This will reset ->del on nodes that will be retained */
+ do_batch_update1(s, fixup);
+
+ /* Remove deleted vertex's from the vertex net, and their */
+ /* parent nodes. */
+ {
+ vtx *vx1, *vx2;
+ for (vx2 = s->nxh; vx2 != NULL; vx2 = vx2->nxh) {
+ int aa, bb, cc; /* Probable hit check */
+ int nnm, nmix;
+
+//printf("~1 Removing deleted vertex no %d from net\n",vx2->no);
+ if (vx2->del == 0) { /* It's not really being deleted */
+//printf("~1 vtx no %d is being retained\n",vx2->no);
+ continue;
+ }
+
+ /* Remove from vertex net */
+ for (j = 0; j < vx2->nnv; j++) {
+ vx1 = vx2->nv[j];
+
+//printf("~1 Removing vtx no %d from vtx no %d\n",vx2->no, vx1->no);
+// if (vx1->del == 0) { } /* Speed optimization */
+ {
+ vtx_rem_vertex(s, vx1, vx2);
+ }
+//else printf("~1 Not removing from vtx no %d because it will be deleted anyway\n",vx1->no);
+ }
+ vx2->nnv = 0;
+
+ /* Remove from parent nodes */
+ for (e = 0; e <= di; e++) {
+ int ix = vx2->nix[e];
+ node *pp = s->n[ix];
+ node_rem_vertex(s, pp, vx2);
+ }
+ }
+ }
+
+ /* Create/modify the vertex neighbour net lists for all the new vertexes. */
+ /* Use a brute force search of local nodes to create the vertex net. */
+ {
+ vtx *vx1, *vx2;
+
+ /* For each new vertx */
+ for (i = 0; i < nncombs; i++) {
+ vx1 = s->combs[i].vv;
+
+ if (vx1 == NULL || vx1->del)
+ continue;
+
+ /* Possibly add other new vertexes as neighbours */
+ for (j = i+1; j < nncombs; j++) {
+
+ vx2 = s->combs[j].vv;
+
+ if (vx2 != NULL && vx2->del == 0)
+ vtx_cnd_biadd_vtx(s, vx1, vx2, fixup);
+ }
+
+ /* Possibly add deleted and non-deleted vertexes */
+ for (k = 0; k < s->combs[i].count; k++) {
+
+#ifdef INDEP_SURFACE
+ /* Add deleted vertex if it isn't going to be deleted */
+ if (s->combs[i].v1[k]->del == 0) {
+ vtx_cnd_biadd_vtx(s, vx1, s->combs[i].v1[k], fixup);
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Add non-deleted vertex */
+ if (s->combs[i].v2[k]->del == 0)
+ vtx_cnd_biadd_vtx(s, vx1, s->combs[i].v2[k], fixup);
+ }
+
+ /* Add any existing vertexes of the node we're re-adding */
+ if (fixup) {
+ for (j = 0; j < nn->nvv; j++) {
+ if (nn->vv[j]->del)
+ continue;
+ vtx_cnd_biadd_vtx(s, vx1, nn->vv[j], fixup);
+ }
+ }
+ }
+ }
+
+ /* Do second part of batch update */
+ do_batch_update2(s, fixup);
+
+#ifdef DEBUG
+ printf("Add_to_vsurf done - added node %d\n",nn->ix);
+#endif
+
+ /* If we want intermediate fixup state: */
+ /* dump_node_vtxs(s, 0); */
+ /* sanity_check(s, 0); */
+
+#ifdef NEVER
+{
+ vtx *vx;
+
+ /* Dump vertex and associated vertex information */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ printf("Vertex no %d has Vtx net:",vx->no);
+ for (j = 0; j < vx->nnv; j++) {
+ vtx *vx2 = vx->nv[j];
+ printf(" %d",vx2->no);
+ }
+ printf("\n");
+ }
+ printf("\n");
+ fflush(stdout);
+}
+#endif /* NEVER */
+
+ return 1;
+}
+
+/* - - - - - - - - - - - */
+/* Deal with verticies marked for deletion or addition, */
+/* as well as updating the nodes consequently affects. */
+/* If fixup is set, add any new or updates vertexes to the s->fchl */
+
+/* Do the first part of the batch update */
+static void do_batch_update1(ofps *s, int fixup) {
+ int e, di = s->di;
+ vtx *vv, *nvv;
+ node *pp;
+
+#ifdef DEBUG
+ printf("Doing batch update to add/delete vertexes - 1\n");
+
+#endif
+ /* Update a vertexes vm, and decide whether it is going */
+ /* to be deleted or just hidden. */
+ for (vv = s->batch; vv != NULL; vv = vv->batch) {
+
+#ifdef DEBUG
+ printf("Pending vtx no %d del %d, add %d, vm %s |= %s &= %s\n",vv->no,vv->del,vv->add,psm(s,&vv->vm),psm(s,&vv->buvm),psm(s,&vv->bdvm));
+ if (vv->ofake)
+ error("An ofake vertex no %d was hit!\n",vv->ofake);
+#endif
+
+ if (vv->add == 1) { /* New node */
+
+#ifdef INDEP_SURFACE
+ sm_or(s, &vv->vm, &vv->vm, &vv->buvm);
+#ifdef DEBUG
+ printf("Set vertex no %d vm to %s\n",vv->no,psm(s,&vv->vm));
+#endif
+#endif /* INDEP_SURFACE */
+
+ /* Add it to the cache */
+ vtx_cache_add(s, vv);
+
+ /* Add it to the spatial accelleration grid */
+ ofps_add_vacc(s, vv);
+
+ /* Add to seeding lists */
+ ofps_add_vseed(s, vv);
+
+ } else if (vv->add == 2) { /* Update the visibility setmask */
+ int was_inseed = 0, is_inseed = 0;
+
+#ifdef INDEP_SURFACE
+ if (sm_andtest(s, &s->sc[0].a_sm, &vv->vm) != 0)
+ was_inseed = 1;
+
+ sm_or(s, &vv->vm, &vv->vm, &vv->buvm);
+#ifdef DEBUG
+ printf("Updated vertex no %d vm to %s\n",vv->no,psm(s,&vv->vm));
+#endif
+ if (sm_andtest(s, &s->sc[0].a_sm, &vv->vm) != 0)
+ is_inseed = 1;
+
+ if (vv->used == 0) {
+ /* Adjust presense in eserr tree if visibility has changed */
+ if (was_inseed && !is_inseed) {
+//printf("Removing (1) vtx no %d, used %d, eserr %f, vm %s nsp %d\n",vv->no,vv->used,vv->eserr,psm(s,&vv->vm),vv->nsp);
+ if ((aat_aerase(s->vtrees[vv->nsp], (void *)vv)) == 0)
+ error("aat_aerase vertex failed to find vertex no %d (1)", vv->no);
+ } else if (!was_inseed && is_inseed) {
+//printf("Adding (1) vtx no %d, used %d, eserr %f, vm %s nsp %d\n",vv->no,vv->used,vv->eserr,psm(s,&vv->vm),vv->nsp);
+ if ((aat_ainsert(s->vtrees[vv->nsp], (void *)vv)) == 0)
+ error("aat_ainsert vertex malloc failed");
+ }
+ }
+#endif /* INDEP_SURFACE */
+
+ } else if (vv->del != 0) {
+
+#ifdef INDEP_SURFACE
+ int was_inseed = 0, is_inseed = 0;
+
+ if (sm_andtest(s, &s->sc[0].a_sm, &vv->vm) != 0)
+ was_inseed = 1;
+//printf("Checked was_inseed %d for vtx no %d, used %d, eserr %f, vm %s nsp %d\n",was_inseed,vv->no,vv->used,vv->eserr,psm(s,&vv->vm),vv->nsp);
+
+ /* Remove visibility due to any deletes */
+ sm_andnot(s, &vv->vm, &vv->vm, &vv->bdvm);
+
+ if (sm_andtest(s, &s->sc[0].a_sm, &vv->vm) != 0)
+ is_inseed = 1;
+//printf("Checking is_inseed %d for vtx no %d, used %d, eserr %f, vm %s nsp %d\n",is_inseed,vv->no,vv->used,vv->eserr,psm(s,&vv->vm),vv->nsp);
+
+ /* Adjust presense in eserr tree if visibility has changed */
+ if (vv->used == 0 && was_inseed && !is_inseed) {
+//printf("Removing (2) vtx no %d, used %d, eserr %f, vm %s nsp %d\n",vv->no,vv->used,vv->eserr,psm(s,&vv->vm),vv->nsp);
+ if ((aat_aerase(s->vtrees[vv->nsp], (void *)vv)) == 0)
+ error("aat_aerase vertex failed to find vertex no %d (2)", vv->no);
+ }
+#ifdef DEBUG
+ printf("Delete vertex no %d vm to %s\n",vv->no,psm(s,&vv->vm));
+#endif
+ /* Don't delete vertex if it remains visible to some sub-surfaces. */
+ if (sm_test(s, &vv->vm) != 0) {
+ vv->del = 0;
+ vv->add = 2; /* Update it instead */
+#ifdef DEBUG
+ printf("Retaining vtx no %d marked for deletion because vm is %s\n",vv->no,psm(s,&vv->vm));
+#endif
+ }
+#endif /* INDEP_SURFACE */
+ }
+ }
+}
+
+/* Do the second part of the batch update */
+static void do_batch_update2(ofps *s, int fixup) {
+ int e, di = s->di;
+ vtx *vv, *nvv;
+ node *pp;
+
+#ifdef DEBUG
+ printf("Doing batch update to add/delete vertexes - 2\n");
+
+#endif
+ /* Add or delete a vertex */
+ for (vv = s->batch; vv != NULL; vv = nvv) {
+
+ nvv = vv->batch;
+ vv->batch = NULL; /* Ready for next time */
+ vv->bch = 0;
+
+ /* Setup vertex ready for another round */
+ sm_set(s, &vv->buvm, 0); /* Ready to OR in new visibility next time */
+ sm_set(s, &vv->bdvm, 0); /* Ready for OR in visibility to be remove next time */
+
+ if (vv->del) { /* delete vertex */
+
+#ifdef DEBUG
+ printf("Deleting vertex no %d\n",vv->no); fflush(stdout);
+#endif
+ /* Add all the parent nodes of this vertex to the update list */
+ for (e = 0; e <= di; e++) {
+ int ix = vv->nix[e];
+ node *pp = s->n[ix];
+
+ if (pp->upflag != s->flag) {
+ pp->nup = s->nup;
+ s->nup = pp;
+ pp->upflag = s->flag;
+ }
+ /* During fixups, maintain nodes vertexes lists */
+ /* (During re-seeding we update it as a batch) */
+ if (fixup)
+ node_rem_vertex(s, pp, vv);
+ }
+ del_vtx(s, vv);
+
+#ifdef DEBUG
+ {
+ vtx *vx;
+ int i, k;
+
+ printf("~1 checking that no references to vertex remain after delete:\n");
+ /* Check vertexes references to vertexes */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ for (k = 0; k < vx->nnv; k++) {
+ if (vx->nv[k] == vv) {
+ printf("Vertex 0x%x no %d still in no %d nv list after deletion\n",vv,vv->no,vx->no);
+#ifdef WARNINGS
+ warning("Vertex 0x%x no %d still in no %d nv list after deletion",vv,vv->no,vx->no);
+#endif
+ }
+ }
+ }
+ /* Check nodes references to vertexes */
+ for (i = 0; i < s->np; i++) { /* For all nodes */
+ node *p1 = s->n[i];
+ for (k = 0; k < p1->nvv; k++) { /* For all its vertexes */
+ if (p1->vv[k] == vv) {
+ printf("Vertex 0x%x no %d still in ix %d vv list after deletion\n",vv,vv->no,p1->ix);
+#ifdef WARNINGS
+ warning("Vertex 0x%x no %d still in ix %d vv list after deletion",vv,vv->no,p1->ix);
+#endif
+ }
+ }
+ }
+ /* Fixup sorted list reference to vertex */
+ for (i = 0; i < s->nsvtxs; i++) {
+ if (s->svtxs[i] == vv) {
+ printf("Vertex 0x%x no %d still in svtxs[%d] after deletion\n",vv,vv->no,i);
+#ifdef WARNINGS
+ warning("Vertex 0x%x no %d still in svtxs[%d] after deletion",vv,vv->no,i);
+#endif
+ }
+ }
+ }
+#endif /* DEBUG */
+
+ } else if (vv->add != 0) { /* New or updated vertex, set updates & checks */
+
+#ifdef DEBUG
+ printf("Adding vertex no %d\n",vv->no);
+#endif
+
+ /* Add all the parent nodes of this vertex to the update list */
+ for (e = 0; e <= di; e++) {
+ node *pp = s->n[vv->nix[e]];
+
+ if (pp->upflag != s->flag) {
+ /* Add node to update list */
+ pp->nup = s->nup;
+ s->nup = pp;
+ pp->upflag = s->flag;
+ }
+
+ /* During fixups, maintain nodes vertexes lists. */
+ /* (During re-seeding we update it as a batch) */
+ if (fixup && vv->add == 1)
+ node_add_vertex(s, pp, vv);
+ }
+
+ /* If this is a fixup and the vertex hasn't been added */
+ /* to the "check" list, do so */
+ if (fixup && vv->fflag != s->fflag) {
+ vv->fchl = s->fchl; /* Add vertex to the "to be checked" list */
+ if (s->fchl != NULL)
+ s->fchl->pfchl = &vv->fchl;
+ s->fchl = vv;
+ vv->pfchl = &s->fchl;
+ vv->fflag = s->fflag;
+#ifdef DEBUG
+ printf("Adding vtx no %d to check list due to addition\n",vv->no);
+#endif
+ }
+ }
+ }
+
+ s->batch = NULL; /* Nothing in pending delete list */
+ s->nup = NULL; /* Nothing in nodes to be updated list */
+}
+
+/* ------------------------------------------------------------------------------- */
+
+/* Do a quick count of the number of verticies hit by their */
+/* neighbour nodes. This is used during itteration to decide */
+/* whether to reseed or fixup. */
+/* Return the number of vertexes hit */
+static int
+ofps_quick_check_hits(ofps *s) {
+ int i, j, k, e, di = s->di;
+ int nvxhits = 0;
+
+ /* For all nodes */
+ for (i = -s->nbp; i < s->np; i++) {
+ node *nn = s->n[i]; /* Node being considered */
+
+ s->flag++; /* Marker flag for testing this node */
+ nn->flag = s->flag;
+
+ /* Check all the neighbors nodes */
+ for (j = 0; j < nn->nvn; j++) {
+ node *pp = s->n[nn->vn[j]];
+
+ /* Test nn against all of pp's vertexes */
+ for (k = 0; k < pp->nvv; k++) {
+ vtx *vx = pp->vv[k];
+
+ if (vx->cflag == s->flag)
+ continue; /* Don't test same node twice */
+ vx->cflag = s->flag;
+
+ /* If node that we're testing against is in vertex */
+ /* ignore it, we expect them to hit. */
+ for (e = 0; e <= di; e++) {
+ if (nn->ix == vx->nix[e])
+ break;
+ }
+ if (e <= di) {
+ continue;
+ }
+
+#ifdef INDEP_SURFACE
+ /* Check if this vertex is visible to this node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ if (nn->ix < 0) {
+ pleq *vp = &s->gpeqs[-1 - nn->ix];
+ double v = 0.0;
+
+ /* See if the vertex is on the wrong side of the plane */
+ for (v = vp->pe[di], e = 0; e < di; e++)
+ v += vp->pe[e] * vx->p[e];
+
+ if (v > 0.0) {
+ nvxhits++;
+ }
+ } else {
+ double eperr = ofps_comp_eperr7(s, NULL, vx->v, vx->p, nn->v, nn->p);
+
+ /* See if the vertex eperr will be improved */
+ if (eperr < (vx->eperr + 0.0)) {
+ nvxhits++;
+ }
+ }
+ }
+ }
+ }
+ return nvxhits;
+}
+
+/* ------------------------------------------------------------------------------- */
+
+/* Recursive hit search routine: */
+
+/* Test a vertex for a possible hit from a node. */
+/* Recursively search dorec recursions until there is at least */
+/* one hit, and stop after beyhit recursions beyond the hit region. */
+/* s->flag is assumed to be relevant for the given node. */
+/* Any hit vertexes are added to the s->nxh list. */
+/* s->vvchecks and s->nvcheckhits will be updated. */
+/* Return nz if vertex was hit */
+
+/* Breadth first search. */
+/* (Assumes s->flag has been incremented) */
+/* [We're assuming that there is a single connected hit region, which */
+/* is not valid for SUBD. ] */
+static int
+ofps_check_vtx(ofps *s, node *nn, vtx *vx, int dorec, int beyhit) {
+ int i, j, e, di = s->di;
+ vtx *slist = NULL; /* Next to search list */
+ int dist; /* Distance from initial vertex */
+ int hit = 0;
+ double tol = 0.0; /* Tollerance */
+
+#ifdef DEBUG
+ printf("ofps_check_vtx() for node ix %d starting at vertex no %d, dorec %d, beyhit %d\n",nn->ix,vx->no,dorec,beyhit);
+#endif
+
+#ifdef SANITY_CHECK_HIT
+ if (nn->ix < -s->nbp)
+ error("Calling ofps_check_node on fake outside node");
+#endif
+
+ if (vx->cflag == s->flag)
+ return vx->del; /* Already been checked */
+
+ /* Put the starting node on the search list */
+ vx->slist = slist;
+ slist = vx;
+ vx->sflag = s->flag; /* Mark as done for pre-hit search */
+
+ /* until we run out of vertexes, or we are done */
+ for (dist = 0; slist != NULL && dist <= dorec; dist++) {
+ vtx *nvx;
+
+ /* For each vertex in the search list, check it and recursion. */
+ for (vx = slist, slist = NULL; vx != NULL; vx = nvx) {
+ nvx = vx->slist;
+ vx->opqsq = 0; /* Not on the list anymore */
+
+ if (vx->ofake)
+ continue; /* ofake vertexes can't be hit */
+#ifdef DEBUG
+ printf("%d: Checking vtx no %d %s\n",dist, vx->no,hit ? "Post-Hit" : "Pre-Hit");
+#endif
+#ifdef INDEP_SURFACE
+ /* Only check for hit if the vertex is visible to the node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+# ifdef DEBUG
+ printf("%d: Vertex no %d xmask 0x%x vm %s isn't visible to ix %d pmask 0x%x a_sm %s\n",dist,vx->no,vx->cmask,psm(s,&vx->vm),nn->ix,nn->pmask,psm(s,&s->sc[nn->pmask].a_sm));
+# endif /* DEBUG */
+ continue;
+ }
+#endif /* INDEP_SURFACE */
+
+ /* If the vertex hasn't been checked yet: */
+ if (vx->cflag != s->flag) {
+ vx->add = 0;
+ vx->del = 0;
+ vx->par = 0;
+
+ s->vvchecks++; /* Checking a vertex */
+
+ /* Check if node is already parent to this vertex. */
+ /* This only happens during fixups if the reposition fails and we */
+ /* retain the vertex with the deleted vertex location (not currently */
+ /* done), or by slim numerical margine, so ignore such hits. */
+ /* We treat a parent as a hit node for the purposes of recursion, */
+ /* and add it to a special list used to complete the vertex net. */
+ if (nn->ixm & vx->nix[MXPD+2]) { /* Is in nixm */
+ for (e = 0; e <= di; e++) { /* Do exact check */
+ if (nn->ix == vx->nix[e])
+ break;
+ }
+ if (e <= di) {
+#ifdef DEBUG
+ printf("Vertex no %d has already got node ix %d\n",vx->no,nn->ix);
+#endif
+ vx->par = 1;
+ }
+ }
+
+ if (nn->ix < 0) {
+ pleq *vp = &s->gpeqs[-1 - nn->ix];
+ double v = 0.0;
+
+ /* See if the vertex is on the wrong side of the plane */
+ for (v = vp->pe[di], e = 0; e < di; e++)
+ v += vp->pe[e] * vx->p[e];
+
+ if (!vx->par && v > tol) {
+ s->nvcheckhits++;
+ if (!hit)
+ slist = nvx = NULL; /* Abort pre-hit search */
+ hit = 1;
+ vx->del = 1; /* Mark for deletion */
+ vx->nxh = s->nxh; /* Add vertex to list */
+ s->nxh = vx;
+ vx->disth = 0; /* This is a hit vertex */
+ vx->hflag = s->flag;
+#ifdef DEBUG
+ printf("%d: Gamut surface boundary plain hit by %f\n",dist,v);
+#endif
+ }
+#ifdef DEBUG
+ else { /* If worse */
+ printf("%d: Gamut surface boundary plain miss by %f\n",dist,v);
+ }
+#endif
+ } else { /* Node rather than boundary plane */
+
+ /* nba_eperr is assumed to be valid if vx->cflag == s->flag */
+ vx->nba_eperr = ofps_comp_eperr7(s, NULL, vx->v, vx->p, nn->v, nn->p);
+#ifdef DEBUG
+ printf("%d: Computing nba_eperr of %f for vtx no %d\n",dist, vx->nba_eperr, vx->no);
+#endif
+ /* See if the vertex eperr will be improved */
+ if (!vx->par && (vx->eperr - vx->nba_eperr) > tol) {
+ s->nvcheckhits++;
+ if (!hit)
+ slist = nvx = NULL; /* Abort pre-hit search */
+ hit = 1;
+ vx->del = 1; /* Mark for deletion */
+ vx->nxh = s->nxh; /* Add vertex to list */
+ s->nxh = vx;
+ vx->disth = 0; /* This is a hit vertex */
+ vx->hflag = s->flag;
+#ifdef DEBUG
+ printf("%d: Vertex error improvement hit by %f (%f < %f)\n",dist, vx->eperr-vx->nba_eperr,vx->nba_eperr,vx->eperr);
+
+ if (vx->par) {
+ printf("Vertex no %d hit by its own parent ix %d\n",vx->no, nn->ix);
+#ifdef WARNINGS
+ warning("Vertex no %d hit by its own parent ix %d",vx->no, nn->ix);
+#endif
+ }
+#endif
+ }
+#ifdef DEBUG
+ else { /* If worse */
+ printf("%d: Vertex error not hit by %f (%f < %f)\n",dist, vx->eperr-vx->nba_eperr,vx->nba_eperr,vx->eperr);
+ }
+#endif
+ }
+ vx->cflag = s->flag;
+// ~~777
+//if (vx->del && i_rand(1,1000) == 15) {
+// printf("~1 failing to check vertex no %d\n",vx->no);
+// vx->cflag = s->flag -1;
+// vx->del = 0;
+//}
+ }
+
+ /* Decide whether to recurse by adding vertexes to the new list */
+ if (!hit) {
+
+ /* Pre-hit recursion */
+ if (dist < dorec) { /* Still within search radius */
+
+ /* Add all the unsearched vertexes neighbors to the next search list */
+ for (j = 0; j < vx->nnv; j++) {
+ vtx *vx2 = vx->nv[j];
+
+ if (vx2->sflag == s->flag) /* Already been pre-hit searched */
+ continue;
+#ifdef DEBUG
+ printf("%d: Adding vtx no %d to next pre-hit search list\n",dist, vx2->no);
+#endif
+ /* Put the neighbour node on the search list */
+ vx2->slist = slist;
+ slist = vx2;
+ vx2->sflag = s->flag;
+ }
+ }
+
+ } else {
+
+ /* Post hit recursion */
+ if (vx->disth <= beyhit) { /* Still within post-hit search radius */
+ int disth = vx->disth + 1; /* Neighbours distance */
+
+ /* Add all the unsearched vertexes neighbors to the next search list */
+ for (j = 0; j < vx->nnv; j++) {
+ vtx *vx2 = vx->nv[j];
+
+ if (vx2->hflag == s->flag) { /* Already been post-hit searched */
+ if (disth >= vx2->disth)
+ continue; /* So skip it */
+
+ /* The already post-hit searched neighbour has an improved distance */
+#ifdef DEBUG
+ printf("%d: Improving ph searched vtx %d disth from %d to %d\n",dist, vx2->no,vx2->disth,disth);
+#endif
+ vx2->disth = disth; /* Improved distance to hit though */
+ if (vx2->disth > beyhit || vx2->opqsq)
+ continue; /* But it's still too far, or already on the list */
+ /* Search this neighbour again now that it is within radius */
+ } else {
+ vx2->disth = disth; /* Set hit distance */
+ }
+#ifdef DEBUG
+ printf("%d: Adding vtx no %d to next post-hit search list (disth = %d)\n",dist, vx2->no,vx2->disth);
+#endif
+ /* Put the neighbour node on the search list */
+ vx2->slist = slist;
+ slist = vx2;
+ vx2->sflag = vx2->hflag = s->flag;
+ vx2->opqsq = 1; /* On the list */
+ }
+ }
+#ifdef DEBUG
+ else
+ printf("%d: Vertex %d disth %d is > beyhit %d so not recursing\n",dist, vx->no,vx->disth,beyhit);
+#endif
+
+ }
+ } /* Next vertex in current list */
+#ifdef DEBUG
+ printf("Finished inner loop because vx 0x%x = NULL\n",vx);
+#endif
+ } /* Next list */
+#ifdef DEBUG
+ printf("Finished outer loop because slist 0x%x = NULL, || dist %d > dorec %d\n",slist,dist,dorec);
+#endif
+
+ return hit;
+}
+
+/* Non-recursive version of above used for sanity checking */
+/* that doesn't set any flags on vx */
+static int
+ofps_check_vtx_sanity(ofps *s, node *nn, vtx *vx, int fixit) {
+ int i, j, e, di = s->di;
+ vtx *slist = NULL; /* Next to search list */
+ int dist; /* Distance from initial vertex */
+ double tol = 1e-6;
+ int hit = 0;
+ int par = 0;
+
+#ifdef DEBUG
+ printf("ofps_check_vtx_sanity() for node ix %d and vertex no %d\n",nn->ix,vx->no);
+#endif
+ if (vx->cflag == s->flag) {
+#ifdef DEBUG
+ printf("Returning alread calculated del = %d\n",vx->del);
+#endif
+ return vx->del; /* Already been checked */
+ }
+
+ if (vx->ofake) { /* ofake nodes can't be hit */
+#ifdef DEBUG
+ printf("Returning ofake del = 0\n");
+#endif
+ return 0;
+ }
+
+#ifdef INDEP_SURFACE
+ /* Only check for hit if the vertex is visible to the node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+#ifdef DEBUG
+ printf("Returning non-visible del = 0\n");
+#endif
+ return 0;
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Check if node is already parent to this vertex. */
+ /* This only happens during fixups if the reposition fails and we */
+ /* retain the vertex with the deleted vertex location (not currently */
+ /* done), or by slim numerical margine, so ignore such hits. */
+ /* We treat a parent as a hit node for the purposes of recursion, */
+ /* and add it to a special list used to complete the vertex net. */
+ if (nn->ixm & vx->nix[MXPD+2]) { /* Is in nixm */
+ for (e = 0; e <= di; e++) { /* Do exact check */
+ if (nn->ix == vx->nix[e])
+ break;
+ }
+ if (e <= di)
+ par = 1;
+ }
+
+ if (nn->ix < 0) {
+ pleq *vp = &s->gpeqs[-1 - nn->ix];
+ double v = 0.0;
+
+ /* See if the vertex is on the wrong side of the plane */
+ for (v = vp->pe[di], e = 0; e < di; e++)
+ v += vp->pe[e] * vx->p[e];
+
+ if (!par && v > tol) {
+ hit = 1;
+
+ if (fixit) {
+ vx->slist = slist;
+ slist = vx;
+ vx->sflag = s->flag;
+ }
+ }
+ } else { /* Node rather than boundary plane */
+ double nba_eperr;
+
+ nba_eperr = ofps_comp_eperr7(s, NULL, vx->v, vx->p, nn->v, nn->p);
+
+ /* See if the vertex eperr will be improved */
+ if (!par && (vx->eperr - nba_eperr) > tol) {
+ hit = 1;
+ if (fixit) {
+ vx->slist = slist;
+ slist = vx;
+ vx->sflag = s->flag;
+ }
+ }
+ }
+
+#ifdef DEBUG
+ printf("Returning computed del = %d\n",hit);
+#endif
+ return hit;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Add a node to the currnent voronoi. */
+/* Return nz if the addition fails due to there being no vetex hits or a cooincince. */
+/* Return nz if abortonfail is set and we fail to position the node. */
+/* (This theoretically shouldn't happen, but does, due to the perceptual */
+/* geometry ?) */
+static int add_node2voronoi(
+ofps *s,
+int poi, /* Index of sample point to update/create Voronoi surface */
+int abortonfail /* 0 = ignore position failures, 1 = abort add if there are any failures */
+) {
+ node *nn = s->n[poi]; /* Node in question */
+ int e, di = s->di;
+ int i, j;
+ vtx *vx = NULL; /* Closest vertex */
+
+#ifdef DEBUG
+ printf("\nAdding Node ix %d pmask 0x%x at %s (perc %s) to Voronoi surface\n",poi,nn->pmask,ppos(di,nn->p),ppos(di,nn->v));
+#endif
+
+ if (poi < 0)
+ error("Attempt to add fake point to veronoi surface");
+
+ if (nn->nvv > 0)
+ error("ofps: assert, node vertex info should be empty on add_node2voronoi() entry");
+
+ for (i = 0; i < 20; i++) {
+ int pci; /* Point cell list index */
+ acell *cp; /* Acceleration cell */
+ node *pp;
+
+ /* Check if by some misfortune, this node colides with an existing node. */
+ pci = ofps_point2cell(s, nn->v, nn->p); /* Grid index of cell of interest */
+ cp = &s->grid[pci];
+ for (pp = cp->head; pp != NULL; pp = pp->n) {
+ for (e = 0; e < di; e++) {
+ if (fabs(nn->v[e] - pp->v[e]) > (COINTOL * 100.0))
+ break; /* Not cooincident */
+ }
+ if (e >= di) { /* Cooincident */
+#ifdef DEBUG
+ printf("Node oint collides with existing - joggling it\n");
+// warning("Node oint collides with existing - joggling it");
+#endif
+ /* Joggle it's position */
+ for (e = 0; e < di; e++) {
+ if (nn->p[e] < 0.5)
+ nn->p[e] += d_rand(0.0, 1e-4);
+ else
+ nn->p[e] -= d_rand(0.0, 1e-4);
+ }
+ /* Ignore confine planes. Next itter should fix it anyway ? */
+ ofps_clip_point6(s, nn->p, nn->p);
+ s->percept(s->od, nn->v, nn->p);
+ break;
+ }
+ }
+ if (pp == NULL)
+ break;
+ }
+ if (i >= 20) {
+ if (s->verb > 1)
+ warning("add_node2voronoi: Assert, was unable to joggle cooincindent point");
+ return 1;
+ }
+
+#ifdef DEBUG
+ printf("Locating all the hit vertexs\n");
+#endif
+
+ s->nvcheckhits = 0; /* Count number of vertexes hit by recursive check. */
+ s->batch = NULL; /* Nothing in pending delete list */
+ s->nup = NULL; /* Nothing in nodes to be updated list */
+ s->flag++; /* Marker flag for adding this node */
+ s->nxh = NULL; /* Nothing in nodes hit list */
+
+#ifdef DEBUG
+ printf("Done check of vertexes for hits\n");
+#endif
+
+ /* Number of nodes that would be checked by exaustive search */
+ s->vvpchecks += s->nv;
+
+ ofps_findhit_vtxs(s, nn);
+
+#ifdef SANITY_CHECK_HIT
+#ifdef DEBUG
+ printf("Doing sanity check of hits\n");
+#endif
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) { /* Check all vertexes */
+
+ if (vx->cflag != s->flag && ofps_check_vtx_sanity(s, nn, vx, 0)) {
+ warning("!!!!!! Sanity: Add hit missed vertex no %d at %s !!!!!!",vx->no,ppos(di,vx->p));
+ printf("!!!!!! Sanity: Add hit missed vertex no %d at %s !!!!!!\n",vx->no,ppos(di,vx->p));
+ /* Don't stop for out of gamut vertexes that would have been hit */
+ if (ofps_would_clip_point(s, vx->p))
+ continue;
+
+ /* Check if any of it's neighbours have been checked. */
+ for (j = 0; j < vx->nnv; j++) {
+ vtx *vx2 = vx->nv[j];
+
+ if (vx2->cflag == s->flag)
+ break; /* Yes */
+ }
+ if (j >= vx->nnv) {
+ warning("!!!!!! Sanity: Missed vertex was in isolated region");
+ } else {
+ warning("!!!!!! Sanity: Missed vertex was adjacent to no %d", vx->nv[j]->no);
+ }
+#ifdef SANITY_CHECK_HIT_FATAL
+ error("Failed to locate all hit vertexes");
+#endif /* SANITY_CHECK_HIT_FATAL */
+ }
+ }
+#endif /* SANITY_CHECK_HIT */
+
+#ifdef DEBUG
+ printf("There were %d vertexes that will be hit by adding node\n",s->nvcheckhits);
+#endif
+
+ if (s->nvcheckhits == 0) {
+ if (s->verb > 1)
+ warning("Failed to get any vertex hits when adding a new node ix %d at %s",nn->ix,ppos(di,nn->p));
+ return 1;
+ }
+
+ /* Now turn all the hit vertexes into new vertexes. */
+ if (add_to_vsurf(s, nn, 0, abortonfail) > 0) {
+ s->add_hit++;
+ } else {
+ if (abortonfail)
+ return 1;
+ s->add_mis++;
+ }
+
+ ofps_add_nacc(s, nn); /* Add to spatial accelleration grid */
+
+ s->np++;
+
+#ifdef DEBUG
+ printf("Done add_node2voronoi()\n");
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------------- */
+
+/* Given a list of di plane equations, */
+/* compute the intersection point. */
+/* return nz if there is no intersection */
+static int comp_vtx(ofps *s, double *p, pleq **peqs) {
+ int i, e, di = s->di;
+ double **ta, *TTA[MXPD], TA[MXPD][MXPD];
+
+ for (e = 0; e < di; e++)
+ TTA[e] = TA[e];
+ ta = TTA;
+
+ for (i = 0; i < di; i++) {
+ for (e = 0; e < di; e++)
+ ta[i][e] = peqs[i]->pe[e]; /* Plane normal becomes row of matrix */
+ p[i] = -peqs[i]->pe[di]; /* Plane constant becomes target */
+ }
+ /* Solve the simultaneous linear equations A.x = B */
+ /* Return 1 if the matrix is singular, 0 if OK */
+ if (polished_solve_se(ta, p, di))
+ return 1;
+
+ return 0;
+}
+
+/* --------------------------------------------------- */
+
+/* Use a brute force search to (re-)create the vertex net. */
+/* This is used in initialization. */
+static void create_vtx_net(ofps *s) {
+ int ff, f, e, di = s->di;
+ vtx *vx1, *vx2;
+
+#ifdef DEBUG
+ printf("Doing create_vtx_net\n");
+#endif
+
+ /* For each vertx */
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link) {
+
+ vx1->nnv = 0; /* Clear the current list */
+#ifdef DEBUG
+ printf("Creating neighbourhood net for vtx no %d\n",vx1->no);
+#endif
+
+ /* Search all other vertexes for neighbours */
+ for (vx2 = s->uvtx; vx2 != NULL; vx2 = vx2->link) {
+ int aa, bb, cc; /* Probable hit check */
+ int nnm, nmix;
+
+//printf("~1 checking against vtx %d\n",vx2->no);
+ if (vx1 == vx2) {
+//printf("~1 skip because it's the same\n");
+ continue;
+ }
+
+
+ /* Use the nixm to quickly check if all but one parent node matches */
+ aa = vx1->nix[MXPD+2]; /* nixm */
+ bb = vx2->nix[MXPD+2]; /* nixm */
+ if ((aa & bb) == 0 || (cc = aa & ~bb, (cc & (cc-1)) != 0)) {
+//printf("~1 skip because nixm 0x%x and 0x%x don't match\n",aa,bb);
+ continue; /* It's certainly not */
+ }
+
+ /* Do an exact check of all except one node match */
+ for (nnm = ff = e = 0; e <= di; e++) {
+ for (f = ff; f <= di; f++) {
+ if (vx1->nix[e] == vx2->nix[f]) {
+ ff = f; /* Start from here next time */
+ break;
+ }
+ if (vx1->nix[e] > vx2->nix[f]) /* No point in looking further */
+ f = di;
+ }
+ if (f > di) { /* Didn't match */
+ if (++nnm > 1)
+ break;
+ nmix = e;
+ }
+ }
+ if (e <= di) {
+//printf("~1 skip because nix %s and %s aren't one different\n",pcomb(di,vx1->nix),pcomb(di,vx2->nix));
+ continue; /* No match */
+ }
+
+ if (nnm == 0) {
+ error("ofps: two vertexes have the same nodes !\n"
+ "no %d at %s nix %s\nno %d at %s nix %s",
+ vx1->no,ppos(di,vx1->p),pcomb(di,vx1->nix),
+ vx2->no,ppos(di,vx2->p),pcomb(di,vx2->nix));
+ }
+
+ /* vx2 is a neighbour, so add it to the vtx net */
+ vtx_add_vertex(s, vx1, vx2);
+//printf("~1 brute force: adding vtx %d as neighbour to %d\n",vx2->no,vx1->no);
+ }
+ }
+}
+
+/* --------------------------------------------------- */
+
+/* Use a brute force search to discover all the valid */
+/* sub-surface combinations. */
+static void discover_subsuf(ofps *s) {
+ int co;
+ double p[MXPD];
+ pleq *peqs[MXPD];
+ int i, j, k, e, di = s->di;
+ setmask acm; /* Accumulated mask for special last entry */
+
+ if (s->sminit)
+ return; /* Do this once */
+
+#ifdef DEBUG
+ printf("Computing subd face combinations\n");
+#endif
+
+ if ((s->sc = (surfcomb *)calloc(sizeof(surfcomb), (1 << s->nbp))) == NULL)
+ error ("ofps: malloc failed on sufcomb array");
+
+ for (co = 0; co < (1 << s->nbp); co++) {
+
+ s->sc[co].co = co;
+
+ /* Count number of planes */
+ for (i = e = 0; e < s->nbp; e++) {
+ if (co & (1 << e))
+ i++;
+ /* Skip combo if odd and even dimension planes are set */
+ if ((e & 1) == 0 && e < (2 * di) && (co & (1 << e)) && (co & (1 << (e+1))))
+ break;
+ }
+ s->sc[co].nos = i;
+ if (i > di || e < s->nbp) {
+ s->sc[co].valid = 0;
+ continue;
+ }
+
+ /* Check that the combination results in a valid */
+ if (i == di) {
+ for ( j = e = 0; e < s->nbp; e++) {
+ if (co & (1 << e))
+ peqs[j++] = &s->gpeqs[e];
+ }
+ if (comp_vtx(s, p, peqs) != 0 || ofps_would_clip_point(s, p)) {
+ s->sc[co].valid = 0;
+ } else {
+ s->sc[co].valid = 1;
+ }
+ } else {
+ if (co == 0 || i == 1) {
+ s->sc[co].valid = 1;
+ } else {
+ s->sc[co].valid = -1;
+ }
+ }
+//printf("~1 val %s sc[%d].valid = %d\n",icmPdv(di, p), co,s->sc[co].valid);
+ }
+ /* Go through the unknown combinations, and see if there */
+ /* is a valid lower dimensional combination that is valid. */
+ for (co = 0; co < (1 << s->nbp); co++) {
+ if (s->sc[co].valid == -1) {
+ for (i = co+1; i < (1 << s->nbp); i++) {
+ if ((i & co) == co && s->sc[i].valid == 1) {
+ s->sc[co].valid = 1;
+ break;
+ }
+ }
+ if (i >= (1 << s->nbp)) /* Failed to find a valid combination */
+ s->sc[co].valid = 0;
+ }
+ }
+#ifdef USE_DISJOINT_SETMASKS
+ /* We can reduce the number of setmask bits by figuring out which */
+ /* combinations are disjoint, and using the same setmask bits for disjoint */
+ /* combinations. For CMYK, this reduces the setmask from 80-100 to less than 32 bits, */
+ /* permiting faster mask manipulation. */
+ {
+ surfcomb *scp, *zd = NULL; /* Zero Dimension combinations */
+ surfcomb *sets = NULL; /* Sets at a given nos */
+ int nsets = 0; /* Current number of sets */
+ int _nsets = 0; /* Allocated array size */
+ int nos; /* Number of surfaces */
+
+ /* init the circular lists, and add the 0D points to their list */
+ for (k = co = 0; co < (1 << s->nbp); co++) {
+ s->sc[co].ds = &s->sc[co]; /* Init circular list to itself */
+ if (s->sc[co].valid == 0)
+ continue;
+ /* Create a list of 0D points and count them */
+ if (s->sc[co].nos == di) {
+ k++;
+ if (zd == NULL)
+ zd = &s->sc[co];
+ else {
+ s->sc[co].ds = zd->ds;
+ zd->ds = &s->sc[co];
+ }
+ }
+ }
+
+ if (zd == NULL)
+ error("No zero-dim surface combinations (s->nbp = %d)",s->nbp);
+
+//printf("~1 total 0D points = %d\n",k);
+
+ /* Temporarily use the setmask to track 0D hits */
+ sm_init(s, k);
+
+ k = 2; /* Count total disjoint sets, including 2 for di D and 0 D */
+
+ /* Locates sets for each dimension level */
+ for (nos = 1; nos < di; nos++) {
+ nsets = 0;
+
+//printf("~1 doing nos = %d\n",nos);
+ /* Add the next combination to the sets */
+ for (co = 0; co < (1 << s->nbp); co++) {
+ if (s->sc[co].valid == 0 || s->sc[co].nos != nos)
+ continue;
+
+//printf("~1 checking combo 0x%x\n",co);
+ /* Figure out 0D hits on this combo */
+ i = 0;
+ scp = zd;
+ do {
+ if ((co & scp->co) == co)
+ sm_setbit(s, &s->sc[co].i_sm, i, 1);
+ i++;
+ scp = scp->ds;
+ } while(scp != zd);
+//printf("~1 combo 0x%x has hits %s\n",co,psm(s,&s->sc[co].i_sm));
+
+ /* Search through the existing sets, and see */
+ /* if this combo is disjoint */
+ for (j = 0; j < nsets; j++) {
+ setmask tsm;
+
+ if (sm_and(s, &tsm, &sets[j].i_sm, &s->sc[co].i_sm) == 0) {
+ /* Add this combo to the existing set */
+
+//printf("~1 adding to set %d\n",j);
+ s->sc[co].ds = sets[j].ds->ds;
+ sets[j].ds->ds = &s->sc[co];
+ sm_or(s, &sets[j].i_sm, &sets[j].i_sm, &s->sc[co].i_sm);
+ break;
+ }
+//else printf("Miss on set %d hits %s, AND %s\n",j,psm(s,&sets[j].i_sm),psm(s,&tsm));
+ }
+ /* If we can't use an existing set, create a new one */
+ if (j >= nsets) {
+ if (nsets >= _nsets) {
+ _nsets = 2 * _nsets + 5;
+ if ((sets = (surfcomb *)realloc(sets, sizeof(surfcomb) * _nsets)) == NULL)
+ error("malloc failed on disjoint sets size %d", _nsets);
+ }
+ sm_cp(s, &sets[j].i_sm, &s->sc[co].i_sm); /* Hits to this set */
+ sets[j].ds = &s->sc[co]; /* Only entry in circular list */
+//printf("New set %d hits %s\n",j,psm(s,&sets[j].i_sm));
+ nsets++;
+ k++;
+ }
+ }
+ }
+
+ if (sets != NULL)
+ free(sets);
+
+#ifdef DEBUG
+ printf("Total number of setmask disjoint sets = %d\n",k);
+#endif
+
+ /* Setup the setmask params */
+ sm_init(s, k);
+
+ /* Assign the individual setmask bits */
+ for (i = co = 0; co < (1 << s->nbp); co++) {
+ if (s->sc[co].valid == 0 || s->sc[co].smset == 1)
+ continue;
+
+//printf("~1 setting mask bit on comb 0x%x and its set\n",co);
+ /* Assign setmask to all in this set */
+ scp = &s->sc[co];
+ do {
+//printf("~1 setting mask bit %d on comb 0x%x\n",i,scp->co);
+ sm_set(s, &scp->i_sm, 0); /* Clear temporary hit mask */
+ sm_setbit(s, &scp->i_sm, i, 1);
+ scp->smset = 1;
+ scp = scp->ds;
+ } while(scp != &s->sc[co]);
+ i++;
+ }
+
+ }
+#else /* !USE_DISJOINT_SETMASKS */
+
+ /* Count the number of valid combinations */
+ for (i = co = 0; co < (1 << s->nbp); co++) {
+ if (s->sc[co].valid == 0)
+ continue;
+ i++;
+ }
+#ifdef DEBUG
+ printf("Total number of setmask sets = %d\n",i);
+#endif
+
+ /* Setup the setmask params */
+ sm_init(s, i);
+
+ /* Assign the individual setmask bits */
+ for (i = co = 0; co < (1 << s->nbp); co++) {
+ if (s->sc[co].valid == 0)
+ continue;
+ sm_setbit(s, &s->sc[co].i_sm, i, 1);
+ i++;
+ }
+#endif /* !USE_DISJOINT_SETMASKS */
+
+ sm_set(s, &acm, 0); /* Init overall accumulated mask */
+
+ /* Compute the accumulated setmask bits */
+ for (i = 0; i < (1 << s->nbp); i++) {
+ if (s->sc[i].valid == 0)
+ continue;
+ for (j = 0; j < (1 << s->nbp); j++) {
+ if ((i & j) != j || s->sc[j].valid == 0)
+ continue;
+ sm_or(s, &s->sc[i].a_sm, &s->sc[i].a_sm, &s->sc[j].i_sm);
+ }
+ sm_or(s, &acm, &acm, &s->sc[i].i_sm);
+ }
+
+ /* Set special "all planes, all valid" combination as the last */
+ /* entry for use by fake surface nodes. */
+ s->sc[(1 << s->nbp)-1].valid = 1;
+ s->sc[(1 << s->nbp)-1].nos = s->nbp;
+ sm_cp(s, &s->sc[(1 << s->nbp)-1].i_sm, &acm);
+ sm_cp(s, &s->sc[(1 << s->nbp)-1].a_sm, &acm);
+ s->sc[(1 << s->nbp)-1].smset = 1;
+ s->sc[(1 << s->nbp)-1].ds = NULL;
+
+#ifdef MAXINDEP_2D
+ /* Go through the combinations and invalidate any */
+ /* that are not full-d or more than 2D */
+ for (co = 0; co < (1 << s->nbp); co++) {
+ if (s->sc[co].valid) {
+// if (s->sc[co].nos != 0 && (di - s->sc[co].nos) > 1) // test in 3D
+ if (s->sc[co].nos != 0 && (di - s->sc[co].nos) > 2)
+ s->sc[co].valid = 0;
+ }
+ }
+#endif /* MAXINDEP_2D */
+
+#ifdef DEBUG
+ /* Print diagnostics */
+ for (i = 0; i < (1 << s->nbp); i++) {
+ if (s->sc[i].valid == 0)
+ continue;
+ printf(" Mask 0x%x, setmasks i = %s, a = %s\n",i,psm(s,&s->sc[i].i_sm),psm(s,&s->sc[i].a_sm));
+ }
+#endif
+
+ s->sminit = 1;
+}
+/* --------------------------------------------------- */
+
+/* Compute a simple but unbounded model of the */
+/* perceptual function. We use the current vertex values */
+/* to setup the model */
+/* (It would be faster to do the optimization per output channel!) */
+
+/* Matrix optimisation function handed to powell() */
+static double xfitfunc(void *edata, double *x) {
+ ofps *s = (ofps *)edata;
+ int e, di = s->di;
+ double rv = 0.0;
+ vtx *vx;
+
+ /* For all the vertexes */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ double v[MXPD], ev;
+
+ /* Apply matrix cube interpolation */
+ icxCubeInterp(x, di, di, v, vx->p);
+
+ /* Evaluate the error */
+ for (ev = 0.0, e = 0; e < di; e++) {
+ double tt;
+ tt = vx->v[e] - v[e];
+ ev += tt * tt;
+ }
+ rv += ev;
+ }
+
+// printf("~1 rv = %f\n",rv);
+
+ return rv;
+}
+
+/* Fit the unbounded perceptual model to just the inside vertexes */
+static void init_pmod(ofps *s) {
+ int e, di = s->di;
+ double sa[MXPD * (1 << MXPD)];
+ double rerr;
+
+ /* Setup matrix to be closest values initially */
+ for (e = 0; e < (1 << di); e++) { /* For each colorant combination */
+ int j, f;
+ double bdif = 1e6;
+ double ov[MXPD];
+ vtx *vx, *bvx = NULL;
+
+ /* Search the vertex list to find the one closest to this input combination */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ double dif = 0.0;
+
+ if (vx->ofake)
+ continue; /* Ignore outside vertexes */
+
+ for (j = 0; j < di; j++) {
+ double tt;
+ if (e & (1 << j))
+ tt = s->imax[j] - vx->p[j];
+ else
+ tt = s->imin[j] - vx->p[j];
+ dif += tt * tt;
+ }
+ if (dif < bdif) { /* best so far */
+ bdif = dif;
+ bvx = vx;
+ if (dif < 0.001)
+ break; /* Don't bother looking further */
+ }
+ }
+ for (f = 0; f < di; f++)
+ s->pmod[f * (1 << di) + e] = bvx->v[f];
+ }
+
+ for (e = 0; e < (di * (1 << di)); e++)
+ sa[e] = 10.0;
+
+ if (powell(&rerr, di * (1 << di), s->pmod, sa, 0.001, 1000,
+ xfitfunc, (void *)s, NULL, NULL) != 0) {
+ if (s->verb > 1)
+ warning("Powell failed to converge, residual error = %f",rerr);
+ }
+
+#ifdef DEBUG
+ printf("Perceptual model fit residual = %f\n",sqrt(rerr));
+#endif
+ s->pmod_init = 1;
+}
+
+/* --------------------------------------------------- */
+/* Init fake node contents, and setup the initial */
+/* voronoi surface with the first node. */
+static void ofps_binit(ofps *s) {
+ int e, di = s->di;
+ int doink = 0;
+ int i, j;
+ DCOUNT(co, MXPD, di, 0, 0, 2); /* Count through corner verticies */
+ int iix = -2 * di - 2; /* Fake inside node index */
+ node *inp = s->n[iix]; /* Fake inside node */
+ int oix = -2 * di - 3; /* Fake outside node index */
+ node *onp = s->n[oix]; /* Fake outside node */
+ double ivtx_whts[] = { /* Initial vertex weightings */
+ 3.7144267283692024e+165,
+ 1.3997102851752585e-152,
+ 6.1677886722367450e+223,
+ 1.7281009363426126e+097,
+ 2.0087766625640005e-139,
+ 4.9406564584124654e-323,
+ 7.7791723264315535e-260,
+ 8.5733372291341995e+170,
+ 6.0046007797559735e-067,
+ 2.8214561724952793e+243,
+ 5.0132438738338732e+262,
+ 1.6259745436952323e-260,
+ 7.9968034958246946e+001
+ };
+ double vtxwt; /* Combined initial vertexnode weighting */
+ unsigned int fullmask = 0;
+
+#ifdef DEBUG
+ printf("Binit called\n");
+#endif
+ if (s->ilimit < (double)di) /* Ink limit is active */
+ doink = 1;
+
+ /* Init fake inside and outside node */
+ inp->ix = iix;
+ inp->fx = 1;
+ inp->pmask = 0;
+ onp->ix = oix;
+ onp->fx = 1;
+ onp->pmask = 0;
+
+ for (i = 0; i < (2 * di); i++)
+ fullmask |= 1 << i;
+ if (doink)
+ fullmask |= 1 << i;
+
+ /* Init the axis aligned gamut surface plane equations */
+ /* and also setup nodes that are indexes by the fake indexes */
+ /* with just the information that will be used. */
+ for (i = 0; i < (2 * di); i++) { /* unit cell at 0 */
+ int ii = i >> 1; /* Dimension */
+ int ix; /* Surface "node" index */
+ pleq *vp; /* plane being initialized */
+ node *np;
+
+ ix = -i-1; /* -1 to -2di fake other nodes */
+ vp = &s->gpeqs[-1-ix]; /* Pointer to plane associated with fake node */
+ vp->ix = ix;
+
+ for (e = 0; e < di; e++)
+ vp->pe[e] = 0.0;
+ vp->pe[ii] = i & 1 ? 1.0 : -1.0; /* Normal */
+ vp->pe[di] = i & 1 ? -s->imax[ii] : s->imin[ii]; /* Constant */
+
+ np = s->n[ix];
+ np->ix = ix;
+ np->fx = 1; /* They don't move */
+ np->nsp = 1;
+ np->sp[0] = vp;
+ np->pmask = fullmask;
+// np->pmask = 1 << i; /* fake surface node pmask is itself for cmask ?? */
+// onp->pmask = inp->pmask |= np->pmask;
+ }
+ s->nbp = 2 * di; /* Number of boundary planes */
+
+ /* Add ink limit surface plane and its fake node */
+ if (doink) { /* Ink limit plane is orthogonal to diagonal */
+ int ix; /* Surface "node" index */
+ pleq *vp; /* plane being initialized */
+ node *np;
+ double len;
+
+ ix = -i-1; /* -1 to -2di fake other nodes */
+ vp = &s->gpeqs[-1-ix]; /* Pointer to plane associated with fake node */
+ vp->ix = ix;
+ len = 1.0/sqrt((double)di); /* Normalised length */
+ for (e = 0; e < di; e++)
+ vp->pe[e] = len;
+ vp->pe[di] = -s->ilimit * len;
+
+ np = s->n[ix];
+ np->ix = ix;
+ np->fx = 1; /* They don't move */
+ np->nsp = 1;
+ np->sp[0] = vp;
+ np->pmask = fullmask;
+// np->pmask = 1 << i; /* fake surface node pmask is itself for cmask ?? */
+// onp->pmask = inp->pmask |= np->pmask;
+ s->nbp++; /* Number of boundary planes */
+ } else {
+ s->n[-i-1]->ix = -i-1; /* Label unused node */
+ }
+
+#ifdef DEBUG
+ printf("Number of boundary planes = %d\nDiscovering all valid veronoi sub-surfaces\n",s->nbp);
+#endif
+
+ discover_subsuf(s);
+
+#ifdef DEBUG
+ printf("Creating rectangular initial vertexes\n");
+#endif
+
+ /* Compute initial node weighting */
+ for (vtxwt = 0.0, i = 0; i < (sizeof(ivtx_whts)/sizeof(double)-1); i++)
+ vtxwt += log(ivtx_whts[i]);
+ vtxwt += ivtx_whts[i];
+
+ /* Create initial verticies, one for each di combination of planes, */
+ /* and keep the ones that are in gamut. */
+ DC_INIT(co);
+ while(!DC_DONE(co)) {
+ double p[MXPD];
+ vtx *vi, *vo; /* Inside and outside vertex */
+
+ /* Compute vertex location */
+ for (e = 0; e < di; e++) {
+ if (co[e] != 0)
+ p[e] = s->imax[e];
+ else
+ p[e] = s->imin[e];
+ }
+
+ if (ofps_would_clip_point(s, p)) {
+#ifdef DEBUG
+ printf("Position %s rejected, out of gamut\n",ppos(di,p));
+#endif
+ goto next_co;
+ }
+#ifdef DEBUG
+ printf("Position %s accepted\n",ppos(di,p));
+#endif
+
+ vi = new_vtx(s);
+ vo = new_vtx(s);
+
+ for (e = 0; e < di; e++)
+ vi->p[e] = vtxwt * p[e];
+ ofps_cc_percept(s, vi->v, vi->p);
+
+ for (e = 0; e < di; e++)
+ vo->p[e] = (10.0 * (p[e] - 0.5)) + 0.5;
+// ofps_cc_percept(s, vo->v, vo->p);
+
+ /* Compute nodes involved */
+ for (e = 0; e < di; e++) {
+ if (co[e] == 0) {
+ vo->nix[e] = vi->nix[e] = -1 - (2 * e + 0);
+ } else {
+ vo->nix[e] = vi->nix[e] = -1 - (2 * e + 1);
+ }
+ }
+
+ vi->nix[di] = iix; /* First nodee */
+#ifdef DEBUG
+ printf("ivertex nix %s\n",pcomb(di,vi->nix));
+#endif
+ sort_nix(s, vi->nix);
+ vi->eperr = 10000.0; /* Very bad, so they get chosen first */
+ vi->eserr = 10000.0;
+
+ det_vtx_gsurf(s, vi); /* Set pmask & cmask */
+ sm_cp(s, &vi->vm, &s->sc[vi->cmask].a_sm); /* Set visibility */
+
+ vi->ifake = 1; /* Inside fake */
+
+ vtx_cache_add(s, vi); /* Add it to the vertex cache and spatial accelleration grid */
+ ofps_add_vacc(s, vi);
+ ofps_add_vseed(s, vi);
+
+ vo->nix[di] = oix; /* Fake outside node */
+#ifdef DEBUG
+ printf("overtex nix %s\n",pcomb(di,vo->nix));
+#endif
+ sort_nix(s, vo->nix);
+ vo->eperr = vtxwt * -9.0; /* Better than zero error */
+ vo->eserr = vtxwt * -9.0;
+ /* Leave pmask,cmask = 0 */
+ vo->pmask = vi->pmask; /* Copy from inner vertexes */
+ vo->cmask = vi->cmask;
+ sm_cp(s, &vo->vm, &s->sc[vo->cmask].a_sm); /* Set visibility */
+
+ vo->ofake = 1; /* Outside fake - don't plot vnets and don't use */
+ /* for perceptual function extension. */
+ vo->used = 1; /* Not a candidate for seeding */
+
+ next_co:;
+ DC_INC(co);
+ }
+
+ /* Add ink limit vertexes */
+ if (doink) { /* Ink limit plane is orthogonal to diagonal */
+ COMBO(nco, MXPD, di-1, s->nbp-1); /* di-1 out of neighbor nodes combination counter */
+
+#ifdef DEBUG
+ printf("Creating ink limit vertexes\n");
+#endif
+ /* Intersect the ink limit plane with each combination of */
+ /* it and and di-1 of the existing planes, to generate */
+ /* potential vertexes, and keep the ones that are in gamut. */
+ CB_INIT(nco);
+ while (!CB_DONE(nco)) {
+ pleq *peqs[MXPD];
+ double p[MXPD];
+
+ for (e = 0; e < (di-1); e++) {
+ peqs[e] = &s->gpeqs[nco[e]];
+ }
+ peqs[e] = &s->gpeqs[2 * di];
+
+ /* Compute device location of intersection */
+ if (comp_vtx(s, p, peqs) == 0) {
+ vtx *vi, *vo; /* Inside and outside vertex */
+
+ if (ofps_would_clip_point(s, p)) {
+#ifdef DEBUG
+ printf("Position %s rejected, out of gamut\n",ppos(di,p));
+#endif
+ goto next_nco;
+ }
+#ifdef DEBUG
+ printf("Position %s accepted\n",ppos(di,p));
+#endif
+
+ vi = new_vtx(s);
+ vo = new_vtx(s);
+
+ /* Device and perceptual */
+ for (e = 0; e < di; e++)
+ vi->p[e] = vtxwt * p[e];
+ ofps_cc_percept(s, vi->v, vi->p);
+
+ for (e = 0; e < di; e++)
+ vo->p[e] = (10.0 * (p[e] - 0.5)) + 0.5;
+// ofps_cc_percept(s, vo->v, vo->p);
+
+ for (e = 0; e < (di-1); e++)
+ vo->nix[e] = vi->nix[e] = -1-nco[e]; /* Fake gamut surface plane nodes */
+ vo->nix[e] = vi->nix[e] = -2 * di -1; /* Fake ink limit node */
+
+ vi->nix[di] = iix; /* First node */
+#ifdef DEBUG
+ printf("ivertex nix %s\n",pcomb(di,vi->nix));
+#endif
+ sort_nix(s, vi->nix);
+ vi->eperr = 10000.0; /* Very bad */
+ vi->eserr = 10000.0;
+
+ det_vtx_gsurf(s, vi); /* Set pmask & cmask */
+ sm_cp(s, &vi->vm, &s->sc[vi->cmask].a_sm); /* Set visibility */
+
+ vi->ifake = 1; /* Inside fake */
+
+ vtx_cache_add(s, vi); /* Add to vertex cache and spatial accelleration grid */
+ ofps_add_vacc(s, vi);
+ ofps_add_vseed(s, vi);
+
+ vo->nix[di] = oix; /* Fake outside node */
+#ifdef DEBUG
+ printf("overtex nix %s\n",pcomb(di,vo->nix));
+#endif
+ sort_nix(s, vo->nix);
+ vo->eperr = vtxwt * -9.0; /* Better than zero error */
+ vo->eserr = vtxwt * -9.0;
+ /* Leave pmask,cmask = 0 */
+ vo->pmask = vi->pmask; /* Copy from inner vertexes */
+ vo->cmask = vi->cmask;
+ sm_cp(s, &vo->vm, &s->sc[vo->cmask].a_sm); /* Set visibility */
+
+ vo->ofake = 1; /* Outside fake - don't plot vnets and don't use */
+ /* for perceptual function extension. */
+ vo->used = 1; /* Not a candidate for seeding */
+ }
+ next_nco:;
+ CB_INC(nco);
+ } /* Next combination */
+ }
+
+ /* Create an initial vertex network */
+ create_vtx_net(s);
+
+ /* Fit the unbounded perceptual model to just the inside vertexes */
+ if (s->pmod_init == 0)
+ init_pmod(s);
+
+ /* Compute the nodes node and vertex lists */
+ ofps_re_create_node_node_vtx_lists(s);
+
+#ifdef DUMP_STRUCTURE
+ printf("Done binit\n");
+ dump_node_vtxs(s, 1);
+// dump_node_vtxs2(s, "Done binit");
+ printf("=========================================================================\n");
+#endif
+#ifdef DUMP_PLOT_SEED
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 0, -1); /* Device, No wait, verticies */
+#endif /* DUMP_PLOT_SEED */
+}
+
+/* --------------------------------------------------- */
+/* Setup the perceptual lookup cache */
+static void
+ofps_init_pcache(ofps *s) {
+ int i, e;
+ int di = s->di;
+ int gr, gres[MXPD];
+ int tinp = s->tinp;
+
+#ifdef DEBUG
+ printf("Initializing perceptual lookup cache\n");
+#endif
+
+ /* Choose a grid resolution that aims for aproximately TNPAGRID nodes per grid */
+ if (tinp > 10000)
+ tinp = 10000;
+ gr = (int)(pow(tinp/TNPAGRID, 1.0/di) + 0.5);
+ gr |= 1; /* make it odd */
+
+ if (gr < TNPAGRIDMINRES)
+ gr = TNPAGRIDMINRES;
+ if (gr > TNPAGRIDMAXRES)
+ gr = TNPAGRIDMAXRES;
+
+ if (s->verb)
+ printf("Perceptual cache resolution = %d\n",gr);
+
+#ifdef DEBUG
+ printf("Perceptual cache resolution = %d\n",gr);
+#endif
+
+ /* Create a rspl to cache the perceptual lookup */
+
+ if ((s->pcache = new_rspl(RSPL_NOFLAGS, s->di, s->di)) == NULL)
+ error("new_rspl failed");
+
+ for (e = 0; e < di; e++)
+ gres[e] = gr;
+
+ s->pcache->set_rspl(s->pcache, RSPL_SET_APXLS, s->od, s->percept, NULL, NULL, gres, NULL, NULL);
+
+ /* Hmm. Should we store the underlying ->percept & ->od somewhere before we overwrite it ? */
+ s->percept = ofps_cache_percept;
+ s->od = s->pcache;
+
+}
+
+/* --------------------------------------------------- */
+/* Setup the acceleration grid structure and perceptual cache. */
+/* The grid is in device space, although it is used to find the point */
+/* with the smallest eperr. */
+/* (Note that ofps_cc_percept() can't be called on clipped values yet) */
+static void
+ofps_init_acc1(ofps *s) {
+ int i, e;
+ int di = s->di;
+ int gres[MXPD];
+ int tinp = s->tinp;
+
+#ifdef DEBUG
+ printf("Initializing accelleration array (1)\n");
+#endif
+
+ /* Create acceleration grid array */
+
+ /* Choose a grid resolution that aims for aproximately TNPAGRID nodes per grid */
+ if (tinp > 10000)
+ tinp = 10000;
+ s->agres = (int)(pow(tinp/TNPAGRID, 1.0/di) + 0.5);
+ if (s->agres < 1)
+ s->agres = 1;
+
+ if (s->verb)
+ printf("Acceleration grid res = %d\n",s->agres);
+
+#ifdef DEBUG
+ printf("Acceleration grid res = %d\n",s->agres);
+#endif
+
+ /* Cell width in grid units */
+ s->gw = 1.0/s->agres;
+
+ /* Compute grid index multipliers */
+ /* (We allocate an two extra rows for boundary cells to be looked up.) */
+ for (s->gim[0] = 1, e = 1; e < di; s->gim[e] = s->gim[e-1] * (s->agres+2), e++)
+ ;
+
+ /* Compute cell diagonal distance */
+ s->gcd = sqrt((double)di * s->gw * s->gw);
+
+ /* Compute number of cells in grid (with two extra rows) */
+ for (s->nig = 1, e = 0; e < di; e++)
+ s->nig *= (s->agres+2);
+
+ /* Allocate grid (with two extra rows) */
+ if ((s->_grid = (acell *)malloc(sizeof(acell) * s->nig)) == NULL)
+ error ("ofps: malloc failed for acceleration grid");
+
+ /* Set pointer to base of grid without extra row */
+ for (s->grid = s->_grid, e = 0; e < di; e++)
+ s->grid += s->gim[e];
+
+ /* Initialise grid (including extra gruard rows) */
+ {
+ DCOUNT(co, MXPD, di, -1, -1, (s->agres+1));
+
+ i = 0;
+ DC_INIT(co);
+ while (!DC_DONE(co)) {
+ acell *cp = &s->_grid[i];
+ unsigned int gflag = 0;
+
+ for (e = 0; e < di; e++) {
+ if (co[e] < 0 || co[e] >= s->agres)
+ gflag = BOUND_GFLAG;
+ cp->co[e] = co[e]; /* Grid coordinate of base of cell */
+ cp->p[e] = co[e] * s->gw; /* Device coord of base of cell */
+ cp->cp[e] = (co[e] + 0.5) * s->gw; /* Device coord of center of cell */
+ }
+
+ cp->gflag = gflag;
+ cp->head = NULL;
+ cp->vhead = NULL;
+
+ DC_INC(co);
+ i++;
+ }
+ }
+ s->gflag = 0;
+
+ /* Create the neighbour offset list */
+
+ /* There are 3^di -1 neighbours for each cell */
+ for (s->nacnl = 1, e = 0; e < di; s->nacnl *= 3, e++)
+ ;
+ s->nacnl--;
+
+ if ((s->acnl = (int *)malloc(sizeof(int) * s->nacnl)) == NULL)
+ error ("ofps: malloc failed on acnl list");
+
+ /* Initialise list from cube */
+ {
+ DCOUNT(co, MXPD, di, -1, -1, 2);
+
+ i = 0;
+ DC_INIT(co);
+ while (!DC_DONE(co)) {
+
+ /* check we're not at the center cell */
+ for (e = 0; e < di; e++) {
+ if (co[e] != 0)
+ break;
+ }
+ if (e < di) { /* Not center cell */
+ /* Compute offset */
+ for (s->acnl[i] = 0, e = 0; e < di; e++) {
+ s->acnl[i] += co[e] * s->gim[e];
+ }
+//printf("~1 acnl[%d] for co %s = %d\n",i,pco(di,co),s->acnl[i]);
+ i++;
+ }
+ DC_INC(co);
+ }
+ }
+}
+
+/* Init the grid location p[] and v[] values */
+static void
+ofps_init_acc2(ofps *s) {
+ int i, e, di = s->di;
+ int k;
+ DCOUNT(co, MXPD, di, 0, 0, 2);
+ double maxratio, avgratio, noratio;
+ double aitters = 0.0;
+
+#ifdef DEBUG
+ printf("Initializing accelleration array (2)\n");
+#endif
+
+ for (i = 0; i < s->nig; i++) {
+ acell *cp = &s->_grid[i];
+
+ /* Lookup perceptual base and center values */
+ ofps_cc_percept(s, cp->v, cp->p);
+ ofps_cc_percept(s, cp->cv, cp->cp);
+ }
+
+ /* Compute the worst case eperr from a corner to the center */
+ maxratio = -1.0;
+ avgratio = noratio = 0.0;
+ for (i = 0; i < s->nig; i++) {
+ acell *cp = &s->_grid[i];
+ double ratio;
+ double mov[MXPD];
+
+ if (cp->gflag == BOUND_GFLAG)
+ continue;
+
+#define ACELITERS 20
+ for (k = 0; ; k++) {
+ double eperr_avg, eperr_min, eperr_max, no;
+ cp->eperr = 0.0;
+
+ DC_INIT(co);
+ eperr_avg = no = 0.0;
+ eperr_min = 1e300;
+ eperr_max = -1.0;
+ while (!DC_DONE(co)) {
+ acell *np = &s->_grid[i];
+ double eperr;
+ int j;
+
+ /* Locate cell corner */
+ for (j = 0, e = 0; e < di; e++)
+ j += co[e] * s->gim[e];
+ np = &s->_grid[i + j];
+
+ /* eperr from that corner to center of this cell */
+ eperr = ofps_comp_eperr(s, NULL, cp->cv, cp->cp, np->v, np->p);
+ eperr_avg += eperr;
+ if (eperr > eperr_max)
+ eperr_max = eperr;
+ if (eperr < eperr_min)
+ eperr_min = eperr;
+
+ no++;
+
+ if (eperr > cp->eperr)
+ cp->eperr = eperr;
+
+ DC_INC(co);
+ }
+ eperr_avg /= no;
+
+ ratio = eperr_max/eperr_min;
+
+ if (k >= ACELITERS || ratio < 1.2) {
+ avgratio += ratio;
+ noratio++;
+ if (ratio > maxratio)
+ maxratio = ratio;
+
+ break;
+
+ } else {
+
+ /* Adjust the center position to minimuze range of eperr's */
+ for (e = 0; e < di; e++)
+ mov[e] = 0.0;
+
+//printf("~1 cp was at %s\n",ppos(di,cp->cp));
+ DC_INIT(co);
+ while (!DC_DONE(co)) {
+ acell *np = &s->_grid[i];
+ double eperr, wf;
+ int j;
+
+ /* Locate cell corner */
+ for (j = 0, e = 0; e < di; e++)
+ j += co[e] * s->gim[e];
+ np = &s->_grid[i + j];
+
+ /* Compose new center point from weighted corner points. */
+ /* Weighting is proportional to eperr value */
+ eperr = ofps_comp_eperr(s, NULL, cp->cv, cp->cp, np->v, np->p);
+
+ if (eperr < eperr_avg) {
+ /* Move away from corner */
+ wf = (eperr_avg - eperr)/eperr_avg;
+//printf("~1 eperr %f, avg %f, min %f, wf %f\n",eperr,eperr_avg,eperr_min,wf);
+ for (e = 0; e < di; e++)
+ mov[e] += wf * (cp->cp[e] - np->p[e]);
+ } else {
+ /* Move towards corner */
+ wf = (eperr - eperr_avg)/eperr_avg;
+//printf("~1 eperr %f, avg %f, max %f, wf %f\n",eperr,eperr_avg,eperr_max,wf);
+ for (e = 0; e < di; e++)
+ mov[e] += wf * (np->p[e] - cp->cp[e]);
+ }
+
+ DC_INC(co);
+ }
+ for (e = 0; e < di; e++) {
+ mov[e] = 1.2 * mov[e] / no;
+ cp->cp[e] += mov[e];
+ }
+ ofps_cc_percept(s, cp->cv, cp->cp);
+//printf("~1 moving by %s to %s\n",ppos(di,mov),ppos(di,cp->cp));
+ }
+ }
+ aitters += k;
+
+ cp->eperr *= CELLMAXEPERRFF; /* Times the fudge factor */
+ }
+ aitters /= s->nig;
+
+ avgratio /= noratio;
+#ifdef DEBUG
+ printf("Average acell eperr ratio = %f, maximum = %f, avg itters %f\n",avgratio,maxratio,aitters);
+
+#endif
+
+ s->agrid_init = 1;
+}
+
+/* Convert a location into an acceleration cell index */
+static int
+ofps_point2cell(ofps *s, double *v, double *p) {
+ int i, e, di = s->di;
+ int agres = s->agres;
+ double pp[MXPD];
+
+ ofps_clip_point(s, pp, p);
+
+ for (i = e = 0; e < di; e++) {
+ int t;
+ t = (int)floor(agres * pp[e]);
+ if (t < 0)
+ t = 0;
+ else if (t >= agres)
+ t = (agres-1);
+ i += s->gim[e] * t;
+ }
+ return i;
+}
+
+/* Diagnostic: Return the grid coordinates */
+static void ofps_gridcoords(ofps *s, int *c, double *v, double *p) {
+ int i, e, di = s->di;
+ int agres = s->agres;
+ double pp[MXPD];
+
+ ofps_clip_point(s, pp, p);
+
+ for (i = e = 0; e < di; e++) {
+ int t;
+ c[e] = (int)floor(agres * pp[e]);
+ if (c[e] < 0)
+ c[e] = 0;
+ else if (c[e] >= agres)
+ c[e] = (agres-1);
+ }
+}
+
+/* Add a node to the spatial acceleration grid */
+/* Note that little more than the node perceptual value */
+/* may be valid when this is called. */
+static void
+ofps_add_nacc(ofps *s, node *n) {
+ int pci;
+ acell *cp;
+
+ if (n->ix < 0)
+ return;
+
+ pci = ofps_point2cell(s, n->v, n->p);
+ cp = &s->grid[pci];
+ n->n = cp->head;
+ if (cp->head != NULL)
+ cp->head->pn = &n->n;
+ cp->head = n;
+ n->pn = &cp->head;
+ n->pci = pci;
+ n->cell = cp;
+
+#ifdef SANITY_CHECK_CLOSEST
+ if (s->agrid_init) {
+ double eperr;
+ /* Check that the eperr to the center of the cell */
+ /* is less than the worst case for that cell */
+ eperr = ofps_comp_eperr(s, NULL, cp->cv, cp->cp, n->v, n->p);
+ if (eperr > cp->eperr) {
+ warning("Sanity check ofps_add_nacc() node ix %d eperr %f > cell eperr %f",n->ix,eperr,cp->eperr);
+ printf("Sanity check ofps_add_nacc() node ix %d eperr %f > cell eperr %f\n",n->ix,eperr,cp->eperr);
+#ifdef SANITY_CHECK_CLOSEST_FATAL
+ error("ofps_add_nacc cell eperr failed");
+#endif
+ }
+ }
+#endif /* SANITY_CHECK_CLOSEST */
+}
+
+/* Remove a node from the spatial acceleration grid */
+static void
+ofps_rem_nacc(ofps *s, node *n) {
+ if (n->ix < 0)
+ return;
+ if (n->pn != NULL) { /* If is on acceleration list, remove it */
+ *n->pn = n->n;
+ if (n->n != NULL)
+ n->n->pn = n->pn;
+ }
+ n->pn = NULL;
+ n->n = NULL;
+}
+
+/* Add a vertex to the spatial acceleration grid */
+static void
+ofps_add_vacc(ofps *s, vtx *vx) {
+ int pci;
+ acell *cp;
+
+ /* Normal spatial acceleration grid */
+ pci = ofps_point2cell(s, vx->v, vx->p);
+ cp = &s->grid[pci];
+ vx->n = cp->vhead;
+ if (cp->vhead != NULL)
+ cp->vhead->pn = &vx->n;
+ cp->vhead = vx;
+ vx->pn = &cp->vhead;
+ vx->pci = pci;
+
+#ifdef DEBUG
+ printf("Adding vertex no %d to spatial accelleration grid in cell %d\n",vx->no,pci);
+#endif
+
+#ifdef SANITY_CHECK_CLOSEST
+ if (s->agrid_init) {
+ int e, di = s->di;
+ double eperr;
+ double p[MXPD], v[MXPD];
+
+ /* Check that the eperr to the center of the cell */
+ /* is less than the worst case for that cell */
+
+ /* Clip point in case it lies outside the grid, */
+ /* and would give an excessive eperr */
+ for (e = 0; e < di; e++) {
+ p[e] = vx->p[e];
+ if (p[e] < 0.0)
+ p[e] = 0.0;
+ else if (p[e] > 1.0)
+ p[e] = 1.0;
+ }
+ ofps_cc_percept(s, v, p);
+ eperr = ofps_comp_eperr(s, NULL, cp->cv, cp->cp, v, p);
+
+ if (eperr > cp->eperr) {
+
+//printf("~1 Cell ix %d co %s center %s (%s), vtx at %s (%s) clipped to %s (%s)\n",pci,pco(s->di,cp->co),ppos(di,cp->cp),ppos(di,cp->cv),ppos(di,vx->p),ppos(di,vx->v),ppos(di,p),ppos(di,v));
+ warning("Sanity check ofps_add_vacc() vtx no %d eperr %f > cell eperr %f",vx->no,eperr,cp->eperr);
+ printf("Sanity check ofps_add_vacc() vtx no %d eperr %f > cell eperr %f\n",vx->no,eperr,cp->eperr);
+
+#ifdef SANITY_CHECK_CLOSEST_FATAL
+ error("ofps_add_vacc cell eperr failed");
+#endif
+ }
+ }
+#endif /* SANITY_CHECK_CLOSEST */
+}
+
+/* Add a vertex to the seeding groups */
+static void
+ofps_add_vseed(ofps *s, vtx *vx) {
+ double oog;
+ int pci;
+ acell *cp;
+
+#ifdef DEBUG
+ printf("Adding vertex no %d to sorted binary tree\n",vx->no);
+#endif
+
+ /* Add the vertex to the sorted binary trees */
+ if ((aat_ainsert(s->vtreep, (void *)vx)) == 0)
+ error("aat_ainsert vertex malloc failed");
+
+ /* Out of gamut vertexes are not candidates for seeds */
+ if ((oog = ofps_oog(s, vx->p)) > COINTOL) {
+ vx->used = 1;
+//printf("Setting used on vtx no %d, used %d, eserr %f, vm %s nsp %d oog by %e\n",vx->no,vx->used,vx->eserr,psm(s,&vx->vm),vx->nsp, oog);
+ }
+
+ if (vx->used == 0) {
+#ifdef INDEP_SURFACE
+ /* Only pick full dimensional visible vertexes for seeding group, */
+ /* since only they have a full-d error value. */
+ if (sm_andtest(s, &s->sc[0].a_sm, &vx->vm) != 0) {
+#endif
+//printf("Adding (3) vtx no %d, used %d, eserr %f, vm %s nsp %d\n",vx->no,vx->used,vx->eserr,psm(s,&vx->vm),vx->nsp);
+ if ((aat_ainsert(s->vtrees[vx->nsp], (void *)vx)) == 0)
+ error("aat_ainsert vertex malloc failed");
+#ifdef INDEP_SURFACE
+ } else {
+//printf("Not adding (2) vtx no %d, used %d, eserr %f, vm %s nsp %d\n",vx->no,vx->used,vx->eserr,psm(s,&vx->vm),vx->nsp);
+ }
+#endif
+ }
+//else printf("Not adding (3) vtx no %d, used %d, eserr %f, vm %s nsp %d\n",vx->no,vx->used,vx->eserr,psm(s,&vx->vm),vx->nsp);
+}
+
+/* Remove a vertex from the seeding groups */
+static void
+ofps_rem_vseed(ofps *s, vtx *vx) {
+
+#ifdef DEBUG
+ printf("Removing vertex no %d from sorted binary tree\n",vx->no);
+#endif
+
+ /* Remove the vertex from the sorted binary tree */
+ if ((aat_aerase(s->vtreep, (void *)vx)) == 0)
+ error("aat_aerase vertex failed to find vertex no %d (3)", vx->no);
+
+ if (vx->used == 0) {
+#ifdef INDEP_SURFACE
+ /* Only pick full dimensional visible vertexes for seeding group, */
+ /* since only they have a full-d error value. */
+ if (sm_andtest(s, &s->sc[0].a_sm, &vx->vm) != 0) {
+#endif
+//printf("Removing (4) vtx no %d, 0x%x, used %d, eserr %f, vm %s nsp %d\n",vx->no,vx, vx->used,vx->eserr,psm(s,&vx->vm),vx->nsp);
+ if ((aat_aerase(s->vtrees[vx->nsp], (void *)vx)) == 0)
+ error("aat_aerase vertex failed to find vertex no %d (4)", vx->no);
+#ifdef INDEP_SURFACE
+ } else {
+//printf("Not removing (1) vtx no %d, 0x%x, used %d, eserr %f, vm %s nsp %d\n",vx->no,vx,vx->used,vx->eserr,psm(s,&vx->vm),vx->nsp);
+ }
+#endif
+ }
+// else printf("Not removing (2) vtx no %d, 0x%x, used %d, eserr %f, vm %s nsp %d\n",vx->no,vx,vx->used,vx->eserr,psm(s,&vx->vm),vx->nsp);
+}
+
+/* Remove a vertex from the spatial acceleration grid */
+static void
+ofps_rem_vacc(ofps *s, vtx *vx) {
+
+ /* Remove from spatial acceleration grid */
+ if (vx->pn != NULL) { /* If is on acceleration list, remove it */
+ *vx->pn = vx->n;
+ if (vx->n != NULL)
+ vx->n->pn = vx->pn;
+ }
+ vx->pn = NULL;
+ vx->n = NULL;
+}
+
+/* Clear the spatial acceleration grid */
+static void
+ofps_reset_acc(ofps *s) {
+ int i;
+
+ for (i = 0; i < s->nig; i++) {
+ acell *cp = &s->_grid[i];
+ if (cp->gflag != BOUND_GFLAG)
+ cp->gflag = 0;
+ cp->head = NULL;
+ cp->vhead = NULL;
+ }
+ s->gflag = 0;
+}
+
+/* --------------------------------------------------- */
+
+/* Creat a randomized order list of pointers to the fixed points */
+static void
+ofps_setup_fixed(
+ofps *s,
+fxpos *fxlist, /* List of existing fixed points */
+int fxno /* Number in fixed list */
+) {
+ int e, di = s->di;
+ int i, j;
+
+ s->fnp = 0;
+ if (fxno == 0)
+ return;
+
+ /* Allocate a list of pointers sufficient for all the fixed points */
+ if ((s->ufx = (fxpos **)calloc(sizeof(fxpos *), fxno)) == NULL)
+ error ("ofps: malloc failed on pointers to fixed list");
+
+ /* Add each fixed point to the list */
+ for (i = 0; i < fxno; i++) {
+
+ /* Clip the fixed point */
+ ofps_clip_point7(s, fxlist[i].p, fxlist[i].p);
+
+ /* Comute perceptual attributes */
+ s->percept(s->od, fxlist[i].v, fxlist[i].p);
+
+ /* Skip any duplicate points, or Voronoi will get confused.. */
+ for (j = 0; j < s->fnp; j++) {
+ for (e = 0; e < di; e++) {
+ if (fabs(s->ufx[j]->p[e] - fxlist[i].p[e]) > 1e-5)
+ break; /* Not a match */
+ }
+ if (e >= di)
+ break; /* Is a match */
+ }
+ if (j < s->fnp)
+ continue; /* Skip adding this point */
+
+ s->ufx[s->fnp++] = &fxlist[i];
+ }
+
+ /* Randomly shuffle the fixed points */
+ for (i = 0; i < s->fnp; i++) {
+ fxpos *tp;
+
+ j = i_rand(0, s->fnp-1);
+
+ /* Swap the pointers */
+ tp = s->ufx[i];
+ s->ufx[i] = s->ufx[j];
+ s->ufx[j] = tp;
+ }
+ s->tinp -= (fxno - s->fnp);
+
+}
+
+/* Seed the object with any fixed points */
+/* (I think this is only used if ofps is used to check the stats */
+/* on all the points. ) */
+/* Return NZ on failure */
+static int
+ofps_add_fixed(
+ofps *s
+) {
+ int e, di = s->di;
+ int i, j, ii;
+
+ /* Add fixed points if there are any */
+ if (s->fnp == 0)
+ return 0;
+
+ if (s->verb)
+ printf("Adding %d unique fixed points\n",s->fnp);
+
+ for (i = 0; i < s->fnp; i++) {
+ node *p = s->n[i]; /* Destination for point */
+
+ /* Make sure that fixed point is within our gamut */
+ ofps_clip_point(s, s->ufx[i]->p, s->ufx[i]->p);
+
+ for (e = 0; e < di; e++) { /* copy device and perceptual coords */
+ p->op[e] = p->p[e] = s->ufx[i]->p[e];
+ p->v[e] = s->ufx[i]->v[e];
+ }
+
+ /* Count gamut surface planes it lies on */
+ det_node_gsurf(s, p, p->p);
+
+ p->fx = 1; /* is a fixed point */
+
+ /* Compute the Voronoi for it, and inc s->np */
+ if (add_node2voronoi(s, s->np, 1)) {
+ /* In theory we could try adding points in a different order, */
+ /* by resetting the voronoi, shuffling all the fixedpoints */
+ /* and re-adding them again. */
+ warning("Adding a fixed point failed to hit any vertexes, and no points to swap with!");
+ return 1;
+ }
+
+ if (s->verb)
+ printf("%cAdded fixed %d/%d",cr_char,i,s->fnp); fflush(stdout);
+
+#ifdef DUMP_STRUCTURE
+ printf("Done node %d\n",s->np);
+ dump_node_vtxs(s, 0);
+ printf("=========================================================================\n");
+#endif
+#ifdef DUMP_PLOT_SEED
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 0, -1); /* Device, No wait, verticies */
+#endif /* DUMP_PLOT_SEED */
+ }
+
+ return 0;
+}
+
+/* Seed the object with any fixed and movable incremental farthest points. */
+/* (We are only called if there is at leaset one movable point) */
+static void
+ofps_seed(ofps *s) {
+ int e, di = s->di;
+ int ii, i, j, k, fc;
+ double rerr;
+ int needfirst = 0; /* Need a special first seed point (seems better without this ?) */
+ int dofixed = 0; /* Do a fixed point next */
+ int abortonfail = 0; /* Abort on failing to add fixed points (isn't always good ?) */
+ int nsp = 0; /* Number of surface points */
+ aat_atrav_t *aat_tr;
+
+ if (s->verb)
+ printf("\n");
+
+ if ((aat_tr = aat_atnew()) == NULL)
+ error("aat_atnew returned NULL");
+
+ if (s->verb) {
+ printf("There are %d unique fixed points to add (%d total fixed points)\n",s->fnp, s->fxno);
+ printf("There are %d far spread points to add\n",s->tinp - s->fnp);
+ }
+
+ if (!needfirst && s->fnp > 1) { /* There are fixed points to add */
+ dofixed = s->fnp > 2 ? 2 : 1;
+ }
+
+ /* Seed all the points. */
+ /* (i is the node we're creating, j is the verbose interval count, */
+ /* fc is the count of the fixed points added, ii is the movable count) */
+ for (fc = j = i = ii = 0; i < s->tinp; i++, j++) {
+ node *p = s->n[i]; /* New node */
+ double spref_mult;
+
+ /* Compute current surface preference weighting */
+ if (s->tinp - s->fnp <= 1) /* Prevent divide by zero */
+ spref_mult = 0.0;
+ else
+ spref_mult = ii/(s->tinp - s->fnp - 1.0);
+ spref_mult = (1.0 - spref_mult) * s->ssurfpref + spref_mult * s->esurfpref;
+
+ if (needfirst) { /* No initial fixed points, so seed the first */
+ /* point as a special. */
+ double min[MXPD], max[MXPD];
+
+ p->fx = 0;
+
+ /* If there are no fixed points in the bulk, make the */
+ /* first point such a point, to avoid pathology. */
+ for (e = 0; e < di; e++)
+ p->p[e] = s->imin[e] + (s->imax[e] - s->imin[e]) * 1.0/4.141592654;
+
+ /* Clip the new location */
+ ofps_clip_point8(s, p->p, p->p);
+
+ s->percept(s->od, p->v, p->p);
+#ifdef DEBUG
+ printf("Creating first seed point (moveable %d out of %d)\n",i+1,s->tinp);
+#endif
+ } else if (dofixed) { /* Setup to add a fixed point */
+
+#ifdef DEBUG
+ printf("Adding fixed point %d out of %d\n",fc+1,s->fnp);
+#endif
+
+ /* (Fixed points are already clipped and have perceptual value) */
+ for (e = 0; e < di; e++) { /* copy device and perceptual coords */
+ p->p[e] = s->ufx[fc]->p[e];
+ p->v[e] = s->ufx[fc]->v[e];
+ }
+
+ p->fx = 1; /* is a fixed point */
+
+ /* Count gamut surface planes it lies on */
+ if (det_node_gsurf(s, p, p->p) != 0)
+ nsp++;
+
+ } else { /* Setup to add a movable point */
+ int k;
+ int sf = 0;
+
+ double spref_mult;
+ double mx;
+ vtx *vx, *bvx;
+ double spweight[MXPD+1]; /* Surface preference weight table */
+ double bspweight; /* Biggest weight */
+
+#ifdef DEBUG
+ printf("Adding movable point %d out of %d\n",i+1,s->tinp);
+#endif
+
+ p->fx = 0;
+
+ /* Compute current surface preference weighting */
+ if (s->tinp - s->fnp <= 1) /* Prevent divide by zero */
+ spref_mult = 0.0;
+ else
+ spref_mult = ii/(s->tinp - s->fnp - 1.0);
+ spref_mult = (1.0 - spref_mult) * s->ssurfpref + spref_mult * s->esurfpref;
+
+ /* Until we use the next vertex, keep looking for a movable point */
+ for (;;) {
+
+#ifdef NEVER /* DEBUG: Show the contents of each list */
+ printf("All vertex list:\n");
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ printf(" Vtx %d, used %d, eserr %f, weserr %f, vm %s\n",vx->no,vx->used,vx->eserr,vx->eserr * spweight[vx->nsp],psm(s,&vx->vm));
+ }
+
+ for (e = 0; e <= (di+1); e++) {
+ printf("Sorted tree vertex list for nsp %d :\n",e);
+
+ for (vx = aat_atlast(aat_tr, s->vtrees[e]); vx != NULL; vx = aat_atprev(aat_tr)) {
+ printf(" Vtx %d, used %d, eserr %f, weserr %f, vm %s\n",vx->no,vx->used,vx->eserr,vx->eserr * spweight[vx->nsp],psm(s,&vx->vm));
+ }
+ }
+#endif
+ /* Compute the surface weighting multiplier for */
+ /* each possible nsp + 1 */
+ spweight[0] = 1.0;
+
+ for (e = 1; e <= di; e++)
+ spweight[e] = spweight[e-1] * spref_mult;
+
+ /* Locate the Voronoi vertex with the greatest distance to a sampling points */
+ for (mx = -1.0, bvx = NULL, e = 0; e <= (di+1); e++) {
+ double weserr;
+
+ /* Get largest eserr vertex for this nsp */
+ if ((vx = aat_atlast(aat_tr, s->vtrees[e])) == NULL)
+ continue;
+
+ weserr = vx->eserr * spweight[vx->nsp];
+
+//printf("~1 considering vertex no %d, eserr %f, weserr %f\n",vx->no,vx->eserr,weserr);
+ if (weserr > mx) {
+ mx = weserr;
+ bvx = vx;
+ }
+ }
+//if (bvx != NULL) printf("~1 got vertex no %d, eserr %f, weserr %f\n",bvx->no,bvx->eserr,mx);
+
+#ifdef SANITY_CHECK_SEED
+ /* Do exaustive search of candidate vertexes */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ double tweserr;
+
+ tweserr = vx->eserr * spweight[vx->nsp];
+
+ if (vx->used == 0 && tweserr > (mx + 10.0 * NUMTOL)
+#ifdef INDEP_SURFACE
+ /* Only pick full dimensional visible vertexes, */
+ /* since only they have a full-d error value. */
+ && sm_andtest(s, &s->sc[0].a_sm, &vx->vm) != 0
+#endif
+ ) {
+ warning("!!!!!! Sanity: Didn't pick largest eperr vtx no %d %f, picked %d %f instead !!!!!!",vx->no,tweserr,bvx->no,mx);
+ printf("!!!!!! Sanity: Didn't pick largest eperr vtx no %d %f, picked %d %f instead !!!!!!\n",vx->no,tweserr,bvx->no,mx);
+ mx = tweserr;
+ bvx = vx;
+ }
+ }
+#endif /* SANITY_CHECK_SEED */
+
+ if (bvx == NULL) { /* We've failed to find a movable point */
+ /* This could be because there are fixed points */
+ /* at all candidate locations. */
+
+ if (fc < s->fnp) { /* Use a fixed point */
+ /* (Fixed points are already clipped and have perceptual value) */
+ for (e = 0; e < di; e++) { /* copy device and perceptual coords */
+ p->p[e] = s->ufx[fc]->p[e];
+ p->v[e] = s->ufx[fc]->v[e];
+ }
+
+ p->fx = 1; /* is a fixed point */
+
+ /* Count gamut surface planes it lies on */
+ if (det_node_gsurf(s, p, p->p) != 0)
+ nsp++;
+ break; /* Go and use this point */
+ }
+ error("ofps: assert, there are no vertexes to choose in initial seed\n");
+ }
+
+#ifdef DEBUG
+ printf("Picking vertex no %d at %s with weserr %f, mask 0x%x\n",bvx->no,ppos(di,bvx->p),mx,bvx->pmask);
+#endif
+
+ /* Don't pick the vertex again */
+ bvx->used = 1;
+//printf("Removing (4) vtx no %d, used %d, eserr %f, vm %s nsp %d\n",bvx->no,bvx->used,bvx->eserr,psm(s,&bvx->vm),bvx->nsp);
+ if ((aat_aerase(s->vtrees[bvx->nsp], (void *)bvx)) == 0)
+ error("aat_aerase vertex failed to find vertex no %d (5)", bvx->no);
+
+ /* Add the new node */
+ for (e = 0; e < di; e++)
+ p->p[e] = bvx->p[e];
+
+ /* Count gamut surface planes it lies on */
+ if (det_node_gsurf(s, p, p->p) != 0)
+ nsp++;
+
+#ifdef RANDOM_PERTERB
+ /* Compute radius of closest real node to vertex */
+ rerr = 1.0;
+ for (k = 0; k <= di; k++) {
+ double rads;
+ int ix = bvx->nix[k];
+ node *np;
+ if (ix < 0)
+ break; /* Done */
+ np = s->n[ix];
+ for (rads = 0.0, e = 0; e < di; e++) {
+ double tt = bvx->p[e] - np->p[e];
+ rads += tt * tt;
+ }
+ if (rads < rerr)
+ rerr = rads;
+ }
+ rerr = s->lperterb * sqrt(rerr);
+ if (rerr < 0.001)
+ rerr = 0.001;
+
+ /* Add a random offset to the position, and retry */
+ /* if it collides with an existing node or future fixed point */
+ for (k = 0; k < 20; k++) {
+ int pci; /* Point list index */
+ acell *cp; /* Acceleration cell */
+ node *p1;
+
+ for (e = 0; e < di; e++)
+ p->p[e] = bvx->p[e] + d_rand(-rerr, rerr);
+
+ /* Confine node to planes vertex was on, */
+ /* bit not if we're having trouble avoiding collissions */
+ if (bvx->nsp > 0)
+ confineto_gsurf(s, p->p, p->sp, p->nsp);
+
+ ofps_clip_point9(s, p->p, p->p);
+
+ s->percept(s->od, p->v, p->p);
+
+ pci = ofps_point2cell(s, p->v, p->p); /* Grid index of cell of interest */
+ if ((cp = &s->grid[pci]) == NULL)
+ break; /* Nothing in cell */
+ for (p1 = cp->head; p1 != NULL; p1 = p1->n) {
+ for (e = 0; e < di; e++) {
+ if (fabs(p->v[e] - p1->v[e]) > COINTOL)
+ break; /* Not cooincident */
+ }
+ if (e >= di) { /* Cooincident */
+#ifdef DEBUG
+ printf("Random offset node ix %d at %s collides with ix %d at %s - retry random %d\n",p->ix,ppos(di,p->p),p1->ix,ppos(di,p1->p),k);
+#endif
+ break; /* Retry */
+ }
+ }
+ if (p1 != NULL) /* Coincident */
+ continue;
+
+ /* Check movable point against fixed points that are yet to be added */
+ /* (~~~ Ideally we should use an accelleration structure to check */
+ /* for cooincidence rather than doing an exaustive search. ~~~) */
+ if (fc < s->fnp) { /* There are more fixed points to add */
+ int f;
+
+ for (f = fc; f < s->fnp; f++) {
+ for (e = 0; e < di; e++) {
+ if (fabs(p->p[e] - s->ufx[f]->p[e]) > COINTOL)
+ break; /* Not cooincident */
+ }
+ if (e >= di) { /* Cooincident */
+#ifdef DEBUG
+ printf("Movable node ix %d at %s collides with fixed point %d at %s - retry movable %d\n",p->ix,ppos(di,p->p),f,ppos(di,s->ufx[f]->p),k);
+#endif
+ break;
+ }
+ }
+ if (f >= s->fnp)
+ break; /* movable point is not cooincident */
+ } else {
+ break; /* Not cooincident, so OK */
+ }
+ }
+ if (k >= 20) {
+ /* This can happen if we didn't pick the absolute largest weserr, */
+ /* and the vertex we ended up with is being confined to the same */
+ /* location as an existing vertex by the planes is on. */
+ /* (Why does it have an weperr > 0.0 then ????) */
+ /* Give up on this point and chose another one. */
+ continue;
+
+// error("ofps_seed: Assert, was unable to joggle cooincindent point");
+ }
+#else /* !RANDOM_PERTERB */
+ /* Confine node to planes vertex was on */
+ if (bvx->nsp > 0)
+ confineto_gsurf(s, p->p, p->sp, p->nsp);
+
+ ofps_clip_point9(s, p->p, p->p);
+
+ s->percept(s->od, p->v, p->p);
+#endif /* !RANDOM_PERTERB */
+
+ /* Added this movable point, so chosen the next point */
+ break;
+ } /* keep looking for a movable point */
+ }
+
+ /* We now have a first/fixed/moevable point to add */
+
+/* hack test */
+//p->p[0] = d_rand(0.0, 1.0);
+//p->p[1] = d_rand(0.0, 1.0);
+//ofps_cc_percept(s, p->v, p->p);
+
+ /* Establish original position */
+ for (e = 0; e < di; e++)
+ p->op[e] = p->p[e];
+
+ /* Compute the Voronoi for it, and inc s->np */
+ /* Fail if we get a position fail */
+ if (add_node2voronoi(s, i, dofixed && abortonfail)) {
+ if (dofixed) {
+ /* Pospone adding this vertex */
+ if ((s->fnp - fc) >= (s->tinp - i - 1)) { /* No room for moveable points */
+// error("Adding fixed point failed to hit any vertexes or posn. failed");
+ abortonfail = 0;
+ } else
+ dofixed = 0;
+ }
+ if (needfirst) {
+ /* Hmm. The first seed point has failed. What should we do ? */
+ error("Adding first seed point failed to hit any vertexes or posn. failed");
+ }
+
+ /* Skip this point */
+ --i;
+ --j;
+ continue;
+ }
+
+ /* Suceeded in adding the point */
+ if (p->fx) { /* Fixed point */
+ fc++;
+ dofixed--;
+ if ((s->fnp - fc) >= (s->tinp - i - 1)) { /* No room for moveable points */
+ dofixed = s->fnp - fc; /* Do all the fixed */
+ }
+ } else { /* Movable point */
+ ii++;
+ if (fc < s->fnp) { /* There are more fixed points to add */
+ dofixed = s->fnp - fc;
+ /* Add fixed 2 at a time to try and minimize the disruption */
+ /* of the movable point edge priority */
+ if (dofixed > 2)
+ dofixed = 2;
+ }
+ }
+
+ if (s->verb && (j == 11 || i == (s->tinp-1))) {
+ printf("%cAdded %d/%d",cr_char,s->np,s->tinp); fflush(stdout);
+ j = 0;
+ }
+#ifdef DUMP_STRUCTURE
+ printf("Done node %d\n",i);
+ dump_node_vtxs(s, 0);
+ printf("=========================================================================\n");
+#endif
+#ifdef DUMP_PLOT_SEED
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 0, -1); /* Device, No wait, verticies */
+#endif /* DUMP_PLOT_SEED */
+
+ needfirst = 0; /* Must have done first */
+ }
+//printf("Number of gamut surface points = %d\n",nsp);
+
+ aat_atdelete(aat_tr);
+
+ if (s->verb)
+ printf("\n");
+}
+
+/* Recreate the Voronoi diagram with the current point positions */
+static void
+ofps_redo_voronoi(
+ofps *s
+) {
+ vtx *vx, *nvx;
+ int i, j, k, e, di = s->di;
+
+ /* Retry if we get a failure to add a point */
+ for (k = 0; k < NINSERTTRIES; k++) {
+
+ /* (~9 should think about smoothing the pre-conditioning lookup */
+ /* if the number of tries is high. Add this to rspl.) */
+
+ /* Clear the voronoi nodes */
+ node_clear(s, s->n[-2 * di - 2]);
+ for (j = -s->gnp; j < s->np; j++)
+ node_clear(s, s->n[j]);
+
+ /* Delete the voronoi verticies */
+ for (vx = s->uvtx; vx != NULL; vx = nvx) {
+ nvx = vx->link;
+ del_vtx(s, vx);
+ }
+ s->uvtx = NULL;
+
+ /* Clear out the spatial acceleration grid */
+ ofps_reset_acc(s);
+
+ if (s->nv != 0)
+ warning("ofps: Assert, clear didn't leave us with 0 vertexes");
+
+ if (s->umid != NULL)
+ warning("ofps: Assert, clear didn't empty used midpoint list");
+
+ if (aat_asize(s->vtreep) != 0)
+ warning("ofps: Assert, clear didn't empty vertex tree");
+ for (e = 0; e <= (di+1); e++) {
+ if (aat_asize(s->vtrees[e]) != 0)
+ warning("ofps: Assert, clear didn't empty vertex tree");
+ }
+
+ /* Set number of points in voronoi to zero */
+ s->np = 0;
+
+ /* Initialse the empty veronoi etc. */
+ ofps_binit(s);
+
+ s->posfailstp = 0;
+
+ /* Add all points in again. */
+ for (i = 0 ;i < s->tinp; i++) { /* Same order as before */
+
+ /* Compute the Voronoi for it (will add it to spatial accelleration grid) */
+ /* and increment s->np */
+ if (add_node2voronoi(s, i, 0)) {
+
+ /* Hmm. Shuffle and retry the whole thing. */
+ shuffle_node_order(s);
+ break;
+ }
+
+ /* If it's not going well, re-shuffle and abort too */
+ if (i > 10 && s->posfailstp/(1.0+i) > 0.2) {
+//printf("~1 after node %d, posfailes = %d, prop %f\n",i,s->posfailstp, s->posfailstp/(1.0+i));
+ /* Hmm. Shuffle and and retry the whole thing. */
+ if (s->verb > 1)
+ warning("Too many nodes are failing to be inserted - reshuffling and re-starting\n");
+ shuffle_node_order(s);
+ break;
+ }
+
+#ifdef DUMP_STRUCTURE
+ printf("Done node %d\n",i);
+ dump_node_vtxs(s, 0);
+// ofps_re_create_node_node_vtx_lists(s);
+// if ((s->optit+1) >= 4)
+// { char buf[200]; sprintf(buf, "Itteration %d node ix %d",s->optit+1,s->np-1); dump_node_vtxs2(s, buf); }
+ printf("=========================================================================\n");
+#endif
+#ifdef DUMP_PLOT_RESEED
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 0, -1); /* Device, No wait, verticies */
+#endif /* DUMP_PLOT_RESEED */
+ }
+ if (i >= s->tinp) {
+#ifdef DEBUG
+ if (k > 1) printf("Took %d retries\n",k-1);
+#endif /* DEBUG */
+ break;
+ }
+ /* Retry the whole thing */
+ }
+ if (k >= NINSERTTRIES)
+ error("Failed to re-seed the veronoi after %d tries - too many node insertion failures ?",NINSERTTRIES);
+}
+
+/* ----------------------------------------------------------- */
+/* Ideas for improving the accelleration:
+
+ When there is no SUBD, then it is possible that the node
+ neighbourhood net (if it is kept up to date during seeding)
+ could be used to locate the closest node and then vertex.
+ (It can't be used for fixup, because the voronoi properties
+ aren't true during fixup.)
+ Starting at at the first node found using the spiral structure,
+ check all it's neigbours and if it's neighbour is closer to
+ the target, switch to it. If no neighbour is closer,
+ then that is the closest node.
+ The closest vertex is then connected to the closest node ?
+
+*/
+
+#undef DEBUG_FCLOSE
+
+/* Given a node, locate all vertexes that it hits. */
+/* s->flag is assumed to be relevant for the given node. */
+/* Any hit vertexes are added to the s->nxh list. */
+/* s->vvchecks and s->nvcheckhits will be updated. */
+/* Return nz if vertexs were hit */
+/* (This only returns visible vertexes.) */
+static int ofps_findhit_vtxs(ofps *s, node *nn) {
+ int e, di = s->di;
+ int i, j;
+ int pci; /* Point cell index */
+ acell *cp;
+ vtx *vx;
+ double beperr, eperr;
+ acell *slist = NULL, *sliste = NULL; /* Next to search list */
+ int hit = 0;
+
+ if (nn->ix < 0)
+ error("ofps_findhit_vtxs given gamut boudary node ix %d",nn->ix);
+
+#ifdef DEBUG
+ if (s->agrid_init == 0)
+ error("ofps_findhit_vtxs() called before agrid_init");
+#endif
+
+#ifdef DEBUG_FCLOSE
+ printf("\nLocating a hit vtx to node at p = %s, v = %s\n", ppos(di,nn->p), ppos(di,nn->v));
+#endif
+
+ /* Determine the largest eperr of any vertex */
+ {
+ aat_atrav_t *aat_tr;
+
+ beperr = 1e300;
+
+ if ((aat_tr = aat_atnew()) == NULL)
+ error("aat_atnew returned NULL");
+
+ /* Find the largest vertex eperr visible to the node */
+ for (vx = aat_atlast(aat_tr, s->vtreep); vx != NULL; vx = aat_atprev(aat_tr)) {
+#ifdef INDEP_SURFACE
+ if (sm_vtx_node(s, vx, nn) == 0)
+ continue;
+#endif /* INDEP_SURFACE */
+ beperr = vx->eperr;
+ break;
+ }
+ aat_atdelete(aat_tr);
+
+#ifdef DEBUG_FCLOSE
+ printf("Largest eperr of any vertex = %f\n", beperr);
+// fprintf(stderr,"Largest eperr of any vertex = %f\n", beperr);
+#endif
+ }
+
+ s->nvfschd += s->nv; /* Number of vertexes in a full search */
+ s->naccsrch++; /* Number of searches */
+
+ /* Do a breadth first seed search for any hit vertexes, or until */
+ /* we run out of cells that could possibly be hits. */
+
+ /* Locate a starting cell using the grid */
+ pci = ofps_point2cell(s, nn->v, nn->p); /* Grid index of cell of interest */
+ cp = &s->grid[pci];
+
+ s->gflag++; /* cell touched flag */
+
+ /* Put the starting cell on the search list */
+#ifdef DEBUG_FCLOSE
+ printf("Adding cell ix %d co %s to slist\n",cp - s->grid, pco(di,cp->co));
+#endif
+#ifdef NEVER
+ if (sliste == NULL) { /* First in empty list */
+ slist = cp;
+ } else {
+ sliste->slist = cp; /* Add to end of list */
+ }
+ sliste = cp;
+ cp->slist = NULL;
+#else
+ cp->slist = slist;
+ slist = cp;
+#endif
+ cp->gflag = s->gflag; /* Cell is on list to be searched */
+
+ /* until we run out of cells to search */
+ for (;slist != NULL;) {
+ acell *ncp;
+
+ /* For each cell in the search list, check it and recursion. */
+ for (cp = slist, slist = sliste = NULL; cp != NULL; cp = ncp) {
+ double ceperr;
+ ncp = cp->slist;
+
+#ifdef DEBUG_FCLOSE
+ printf("Checking cell ix %d co %s\n",cp - s->grid,pco(di,cp->co));
+#endif
+
+ /* Compute the smallest eperr possible in this cell, by computing the */
+ /* eperr of the cell center to the node minus the estimated */
+ /* largest eperr of any point within the cell to the center. */
+ ceperr = ofps_comp_eperr(s, NULL, cp->v, cp->p, nn->v, nn->p);
+ eperr = ceperr - cp->eperr;
+
+//printf("~1 ceperr %f, cp->eperr %f, eperr %f, beperr %f\n",ceperr,cp->eperr,eperr,beperr);
+ /* If smallest possible eperr is larger than largest vertexe eperr */
+ if (eperr > beperr) {
+//printf("~1 skipping cell\n");
+#ifdef SANITY_CHECK_CLOSEST
+ /* Check all nodees in the cell anyway */
+ for (vx = cp->vhead; vx != NULL; vx = vx->n) {
+ int par = 0;
+
+ if (vx->cflag == s->flag)
+ continue;
+#ifdef INDEP_SURFACE
+ if (sm_vtx_node(s, vx, nn) == 0)
+ continue;
+#endif /* INDEP_SURFACE */
+
+ if (nn->ixm & vx->nix[MXPD+2]) { /* Is in nixm */
+ for (e = 0; e <= di; e++) { /* Do exact check */
+ if (nn->ix == vx->nix[e])
+ break;
+ }
+ if (e <= di)
+ par = 1;
+ }
+
+ eperr = ofps_comp_eperr7(s, NULL, vx->v, vx->p, nn->v, nn->p);
+
+ if (!par && (vx->eperr - eperr) > 0.0) {
+//printf("~1 Node ix %d at %s (%s)\n Cell ix %d co %s center %s (%s),\n vtx no %d at %s (%s)\n",nn->ix, ppos(di,nn->p),ppos(di,nn->v),cp - s->grid,pco(s->di,cp->co),ppos(di,cp->cp),ppos(di,cp->cv),vx->no, ppos(di,vx->p),ppos(di,vx->v));
+ warning("Sanity check ofps_findhit_vtxs() cell skip failed, hit on vtx no %d, eperr %f < vx->eperr %f, cell ix %d eperr %f, est min eperr %f",vx->no,eperr,vx->eperr,cp - s->grid,ceperr,ceperr - cp->eperr);
+ printf("Sanity check ofps_findhit_vtxs() cell skip failed, hit on vtx no %d, eperr %f < vx->eperr %f, cell ix %d eperr %f, est min eperr %f\n",vx->no,eperr,vx->eperr,cp - s->grid,ceperr,ceperr - cp->eperr);
+#ifdef SANITY_CHECK_CLOSEST_FATAL
+ error("findclosest node cell skip failed");
+#endif
+ }
+ }
+#endif /* SANITY_CHECK_CLOSEST */
+ continue; /* Cell is not worth searching */
+ }
+
+ /* Search the cell */
+ s->ncellssch++;
+
+ /* For vertexes in this cell */
+ for (vx = cp->vhead; vx != NULL; vx = vx->n) {
+#ifdef DEBUG
+ printf("Checking vtx no %d\n",vx->no);
+#endif
+ /* If the vertex has already been checked */
+ if (vx->cflag == s->flag)
+ continue;
+
+ if (vx->ofake) /* ofake vertexes can't be hit */
+ continue;
+
+#ifdef INDEP_SURFACE
+ /* Only check for hit if the vertex is visible to the node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+# ifdef DEBUG
+ printf("Vertex no %d xmask 0x%x vm %s isn't visible to ix %d pmask 0x%x a_sm %s\n",vx->no,vx->cmask,psm(s,&vx->vm),nn->ix,nn->pmask,psm(s,&s->sc[nn->pmask].a_sm));
+# endif /* DEBUG */
+ continue;
+ }
+#endif /* INDEP_SURFACE */
+
+ vx->add = 0;
+ vx->del = 0;
+ vx->par = 0;
+
+ s->vvchecks++; /* Checking a vertex */
+
+ /* Check if node is already parent to this vertex. */
+ /* This only happens during fixups if the reposition fails and we */
+ /* retain the vertex with the deleted vertex location (not currently */
+ /* done), or by slim numerical margine, so ignore such hits. */
+ /* We treat a parent as a hit node for the purposes of recursion, */
+ /* and add it to a special list used to complete the vertex net. */
+ if (nn->ixm & vx->nix[MXPD+2]) { /* Is in nixm */
+ for (e = 0; e <= di; e++) { /* Do exact check */
+ if (nn->ix == vx->nix[e])
+ break;
+ }
+ if (e <= di) {
+#ifdef DEBUG
+ printf("Vertex no %d has already got node ix %d\n",vx->no,nn->ix);
+#endif
+ vx->par = 1;
+ }
+ }
+
+ /* nba_eperr is assumed to be valid if vx->cflag == s->flag */
+ vx->nba_eperr = ofps_comp_eperr7(s, NULL, vx->v, vx->p, nn->v, nn->p);
+#ifdef DEBUG
+ printf("Computing nba_eperr of %f for vtx no %d\n",vx->nba_eperr, vx->no);
+#endif
+ /* See if the vertex eperr will be improved */
+ if (!vx->par && (vx->eperr - vx->nba_eperr) > 0.0) {
+ s->nvcheckhits++;
+ hit = 1;
+ vx->del = 1; /* Mark for deletion */
+ vx->nxh = s->nxh; /* Add vertex to list */
+ s->nxh = vx;
+ vx->hflag = s->flag;
+#ifdef DEBUG
+ printf("Vertex error improvement hit by %f (%f < %f)\n",vx->eperr-vx->nba_eperr,vx->nba_eperr,vx->eperr);
+
+ if (vx->par) {
+ printf("Vertex no %d hit by its own parent ix %d\n",vx->no, nn->ix);
+ warning("Vertex no %d hit by its own parent ix %d",vx->no, nn->ix);
+ }
+#endif
+ }
+#ifdef DEBUG
+ else { /* If worse */
+ printf("Vertex error not hit by %f (%f < %f)\n",vx->eperr-vx->nba_eperr,vx->nba_eperr,vx->eperr);
+ }
+#endif
+ vx->cflag = s->flag;
+
+ } /* Next vertex in cell */
+
+ /* Put all this cells neighbours on the search list */
+ /* (This is probably the critical inner loop. If ->acnl was */
+ /* scaled by sizeof(acell), then the implicit multiply could */
+ /* be avoided) */
+ for (j = 0; j < s->nacnl; j++) {
+ acell *nc = cp + s->acnl[j];
+
+ if (nc->gflag >= s->gflag)
+ continue;
+
+#ifdef DEBUG_FCLOSE
+ printf("Adding cell ix %d co %s to slist\n",nc - s->grid, pco(di,nc->co));
+#endif
+#ifdef NEVER
+ if (sliste == NULL) { /* First in empty list */
+ slist = nc;
+ } else {
+ sliste->slist = nc; /* Add to end of list */
+ }
+ sliste = nc;
+ nc->slist = NULL;
+#else
+ nc->slist = slist;
+ slist = nc;
+#endif
+ nc->gflag = s->gflag; /* Cell is on list to be searched */
+ }
+ } /* Next cell in current list */
+//printf("~1 don that search list\n");
+ } /* Next list */
+//printf("~1 no more search lists\n");
+
+ return hit;
+}
+
+#ifdef DEBUG_FCLOSE
+#undef DEBUG_FCLOSE
+#endif
+
+
+#undef DEBUG_FCLOSE
+
+/* Given a vertex, locate the smallest eperr node. */
+/* Return NULL if none, and if ceperr is not NULL, set it to the */
+/* eperr to the returned node. */
+/* (This only returns visible nodes.) */
+static node *ofps_findclosest_node(ofps *s, double *ceperr, vtx *vx) {
+ int e, di = s->di;
+ int i, j;
+ int pci; /* Point cell index */
+ acell *cp;
+ double eperr, beperr = 1e300; /* eperr of closest node */
+ node *bno = NULL; /* Closest node */
+ acell *slist = NULL, *sliste = NULL; /* Next to search list */
+
+#ifdef DEBUG
+ if (s->agrid_init == 0)
+ error("ofps_findclosest_node() called befor agrid_init");
+#endif
+
+#ifdef DEBUG_FCLOSE
+ printf("\nLocating closest node to vtx at p = %s, v = %s\n", ppos(di,vx->p), ppos(di,vx->v));
+#endif
+
+ s->nnfschd += s->np; /* Number of nodes in a full search */
+ s->naccsrch++; /* Number of searches */
+
+ /* Do a breadth first seed search for any better nodees, or until */
+ /* we run out of cells that could improve on the current best. */
+
+ /* Locate a starting cell using the grid */
+ pci = ofps_point2cell(s, vx->v, vx->p); /* Grid index of cell of interest */
+ cp = &s->grid[pci];
+
+ s->gflag++; /* cell touched flag */
+
+ /* Put the starting cell on the search list */
+#ifdef DEBUG_FCLOSE
+ printf("Adding cell ix %d co %s to slist\n",cp - s->grid, pco(di,cp->co));
+#endif
+#ifdef NEVER
+ if (sliste == NULL) { /* First in empty list */
+ slist = cp;
+ } else {
+ sliste->slist = cp; /* Add to end of list */
+ }
+ sliste = cp;
+ cp->slist = NULL;
+#else
+ cp->slist = slist; /* Add it to start of list */
+ slist = cp;
+#endif
+ cp->gflag = s->gflag; /* Cell is on list to be searched */
+
+ /* until we run out of cells to search */
+ for (;slist != NULL;) {
+ acell *ncp;
+
+ /* For each cell in the search list, check it and recursion. */
+ for (cp = slist, slist = sliste = NULL; cp != NULL; cp = ncp) {
+ double ceperr;
+ ncp = cp->slist;
+
+#ifdef DEBUG_FCLOSE
+ printf("Checking cell ix %d co %s\n",cp - s->grid,pco(di,cp->co));
+#endif
+
+ /* Compute the eperr of the cell center to the vtx minus the estimated */
+ /* largest eperr of any point within the cell to the center. */
+ ceperr = ofps_comp_eperr(s, NULL, cp->v, cp->p, vx->v, vx->p);
+ eperr = ceperr - cp->eperr;
+
+ /* If the cell is worth searching */
+ if (eperr < beperr) {
+ node *no;
+
+ /* Search the cell */
+ s->ncellssch++;
+
+ for (no = cp->head; no != NULL; no = no->n) {
+
+#ifdef INDEP_SURFACE
+ /* Check if this node is visible to this vtx */
+ if (sm_vtx_node(s, vx, no) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Compute the eperr between the node to the new vtx */
+ eperr = ofps_comp_eperr(s, NULL, no->v, no->p, vx->v, vx->p);
+ if (eperr < beperr) {
+ bno = no;
+ beperr = eperr;
+#ifdef DEBUG_FCLOSE
+ printf("Improved to node ix %d eperr\n",bno->ix,beperr);
+#endif
+ }
+ }
+
+ /* Put all this cells neighbours on the search list */
+ /* (This is probably the critical ivxer loop. If ->acnl was */
+ /* scaled by sizeof(acell), then the implicit multiply could */
+ /* be avoided) */
+ for (j = 0; j < s->nacnl; j++) {
+ acell *nc = cp + s->acnl[j];
+
+ if (nc->gflag >= s->gflag)
+ continue;
+
+#ifdef DEBUG_FCLOSE
+ printf("Adding cell ix %d co %s to slist\n",nc - s->grid, pco(di,nc->co));
+#endif
+#ifdef NEVER
+ if (sliste == NULL) { /* First in empty list */
+ slist = nc;
+ } else {
+ sliste->slist = nc; /* Add to end of list */
+ }
+ sliste = nc;
+ nc->slist = NULL;
+#else
+ nc->slist = slist; /* Add it to start of list */
+ slist = nc;
+#endif
+ nc->gflag = s->gflag; /* Cell is on list to be searched */
+ }
+ }
+#ifdef SANITY_CHECK_CLOSEST
+ /* Check all nodees in the cell anyway */
+ else {
+ double teperr;
+ node *no;
+
+ for (no = cp->head; no != NULL; no = no->n) {
+
+#ifdef INDEP_SURFACE
+ /* Check if this node is visible to this vtx */
+ if (sm_vtx_node(s, vx, no) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Compute the eperr between the node to the new vtx */
+ teperr = ofps_comp_eperr(s, NULL, no->v, no->p, vx->v, vx->p);
+ if (teperr < beperr) {
+ warning("Sanity check ofps_findclosest_node() cell skip failed, estimated %f from cellc eperr %f - cell eperr %f, found %f from node ix %d",eperr,ceperr,cp->eperr,teperr,no->ix);
+ printf("Sanity check ofps_findclosest_node() cell skip failed, estimated %f from cellc eperr %f - cell eperr %f, found %f from node ix %d\n",eperr,ceperr,cp->eperr,teperr,no->ix);
+#ifdef SANITY_CHECK_CLOSEST_FATAL
+ error("findclosest node cell skip failed");
+#endif
+ }
+ }
+ }
+#endif /* SANITY_CHECK_CLOSEST */
+
+ } /* Next cell in current list */
+#ifdef DEBUG_FCLOSE
+ printf("Finished ivxer loop because p 0x%x = NULL\n",cp);
+#endif
+ } /* Next list */
+#ifdef DEBUG_FCLOSE
+ printf("Finished outer loop because slist 0x%x = NULL\n",slist);
+#endif
+
+#ifdef DEBUG_FCLOSE
+ if (bno == NULL)
+ printf("Failed to find a closest node");
+ else
+ printf("Returning best node ix %d, eperr %f\n",bno->ix,beperr);
+#endif
+
+#ifdef SANITY_CHECK_CLOSEST
+ /* Use exaustive search */
+ {
+ double ch_beperr = 1e300; /* Device distance squared of closest vertex */
+ node *ch_bno = NULL;
+ for (i = 0; i < (s->np-1); i++) {
+ node *nn = s->n[i];
+ double eperr;
+
+#ifdef INDEP_SURFACE
+ /* Check if this vertex is visible to this node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Compute the eperr between the node and the vertex */
+ eperr = ofps_comp_eperr(s, NULL, nn->v, nn->p, vx->v, vx->p);
+ if (eperr < ch_beperr) {
+ ch_bno = nn;
+ ch_beperr = eperr;
+ }
+ }
+
+ if (ch_bno != NULL && ch_beperr + 1e-3 < beperr) {
+ if (bno == NULL) {
+ warning("Sanity check ofps_findclosest_node() failed,\n found none, should be ix %d dist %f",ch_bno->ix,ch_beperr);
+ printf("Sanity check ofps_findclosest_node() failed,\n found none, should be ix %d dist %f\n",ch_bno->ix,ch_beperr);
+ } else {
+ warning("Sanity check ofps_findclosest_node() failed,\n found ix %d dist %f, should be ix %d dist %f",bno->ix,beperr,ch_bno->ix,ch_beperr);
+ printf("Sanity check ofps_findclosest_node() failed,\n found ix %d dist %f, should be ix %d dist %f\n",bno->ix,beperr,ch_bno->ix,ch_beperr);
+ }
+#ifdef SANITY_CHECK_CLOSEST_FATAL
+ error("findclosest node failed");
+#endif
+ }
+ }
+#endif
+
+ if (bno != NULL && ceperr != NULL)
+ *ceperr = beperr;
+
+ return bno;
+}
+
+/* ----------------------------------------------------------- */
+
+#ifdef NEVER /* No longer used */
+
+/* Given a node, locate the smallest eperr vertex. */
+/* Return NULL if none, and if ceperr is not NULL, set it to the */
+/* eperr to the returned vertex. */
+/* (This only returns visible vertexes.) */
+static vtx *ofps_findclosest_vtx(ofps *s, double *ceperr, node *nn) {
+ int e, di = s->di;
+ int i, j;
+ int pci; /* Point cell index */
+ acell *cp;
+ double eperr, beperr = 1e300; /* eperr of closest vertex */
+ vtx *bvx = NULL; /* Closest vertex */
+ acell *slist = NULL, *sliste = NULL; /* Next to search list */
+
+#ifdef DEBUG
+ if (s->agrid_init == 0)
+ error("ofps_findclosest_vtx() called befor agrid_init");
+#endif
+
+#ifdef DEBUG_FCLOSE
+ printf("\nLocating closest vtx to node at p = %s, v = %s\n", ppos(di,nn->p), ppos(di,nn->v));
+#endif
+
+ s->nvfschd += s->nv; /* Number of vertexes in a full search */
+ s->naccsrch++; /* Number of searches */
+
+ /* Do a breadth first seed search for any better vertexes, or until */
+ /* we run out of cells that could improve on the current best. */
+
+ /* Locate a starting cell using the grid */
+ pci = ofps_point2cell(s, nn->v, nn->p); /* Grid index of cell of interest */
+ cp = &s->grid[pci];
+
+ s->gflag++; /* cell touched flag */
+
+ /* Put the starting cell on the search list */
+#ifdef DEBUG_FCLOSE
+ printf("Adding cell ix %d co %s to slist\n",cp - s->grid, pco(di,cp->co));
+#endif
+ if (sliste == NULL) { /* First in empty list */
+ slist = cp;
+ } else {
+ sliste->slist = cp; /* Add to end of list */
+ }
+ sliste = cp;
+ cp->slist = NULL;
+ cp->gflag = s->gflag; /* Cell is on list to be searched */
+
+ /* until we run out of cells to search */
+ for (;slist != NULL;) {
+ acell *ncp;
+
+ /* For each cell in the search list, check it and recursion. */
+ for (cp = slist, slist = sliste = NULL; cp != NULL; cp = ncp) {
+ double ceperr;
+ ncp = cp->slist;
+
+#ifdef DEBUG_FCLOSE
+ printf("Checking cell ix %d co %s\n",cp - s->grid,pco(di,cp->co));
+#endif
+
+ /* Compute the eperr of the cell center to the node minus the estimated */
+ /* largest eperr of any point within the cell to the center. */
+ ceperr = ofps_comp_eperr(s, NULL, cp->v, cp->p, nn->v, nn->p);
+ eperr = ceperr - cp->eperr;
+
+ /* If the cell is worth searching */
+ if (eperr < beperr) {
+ vtx *vx;
+
+ /* Search the cell */
+ s->ncellssch++;
+
+ for (vx = cp->vhead; vx != NULL; vx = vx->n) {
+
+#ifdef INDEP_SURFACE
+ /* Check if this vertex is visible to this node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Compute the eperr between the vertex to the new node */
+ eperr = ofps_comp_eperr(s, NULL, vx->v, vx->p, nn->v, nn->p);
+ if (eperr < beperr) {
+ bvx = vx;
+ beperr = eperr;
+#ifdef DEBUG_FCLOSE
+ printf("Improved to vtx no %d eperr\n",bvx->no,beperr);
+#endif
+ }
+ }
+
+ /* Put all this cells neighbours on the search list */
+ /* (This is probably the critical inner loop. If ->acnl was */
+ /* scaled by sizeof(acell), then the implicit multiply could */
+ /* be avoided) */
+ for (j = 0; j < s->nacnl; j++) {
+ acell *nc = cp + s->acnl[j];
+
+ if (nc->gflag >= s->gflag)
+ continue;
+
+#ifdef DEBUG_FCLOSE
+ printf("Adding cell ix %d co %s to slist\n",nc - s->grid, pco(di,nc->co));
+#endif
+ if (sliste == NULL) { /* First in empty list */
+ slist = nc;
+ } else {
+ sliste->slist = nc; /* Add to end of list */
+ }
+ sliste = nc;
+ nc->slist = NULL;
+ nc->gflag = s->gflag; /* Cell is on list to be searched */
+ }
+ }
+#ifdef SANITY_CHECK_CLOSEST
+ /* Check all vertexes in the cell anyway */
+ else {
+ double teperr;
+ vtx *vx;
+
+ for (vx = cp->vhead; vx != NULL; vx = vx->n) {
+
+#ifdef INDEP_SURFACE
+ /* Check if this vertex is visible to this node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Compute the eperr between the vertex to the new node */
+ teperr = ofps_comp_eperr(s, NULL, vx->v, vx->p, nn->v, nn->p);
+ if (teperr < beperr) {
+ warning("Sanity check ofps_findclosest_vtx() cell skip failed, estimated %f from cellc eperr %f - cell eperr %f, found %f from vtx no %d",eperr,ceperr,cp->eperr,teperr,vx->no);
+ printf("Sanity check ofps_findclosest_vtx() cell skip failed, estimated %f from cellc eperr %f - cell eperr %f, found %f from vtx no %d\n",eperr,ceperr,cp->eperr,teperr,vx->no);
+#ifdef SANITY_CHECK_CLOSEST_FATAL
+ error("findclosest vertex cell skip failed");
+#endif
+ }
+ }
+ }
+#endif /* SANITY_CHECK_CLOSEST */
+
+ } /* Next cell in current list */
+#ifdef DEBUG_FCLOSE
+ printf("Finished inner loop because p 0x%x = NULL\n",cp);
+#endif
+ } /* Next list */
+#ifdef DEBUG_FCLOSE
+ printf("Finished outer loop because slist 0x%x = NULL\n",slist);
+#endif
+
+#ifdef DEBUG_FCLOSE
+ if (bvx == NULL)
+ printf("Failed to find a closest vertex");
+ else
+ printf("Returning best vtx no %d, eperr %f\n",bvx->no,beperr);
+#endif
+
+#ifdef SANITY_CHECK_CLOSEST
+ /* Use exaustive search */
+ {
+ double ch_beperr = 1e300; /* Device distance squared of closest vertex */
+ vtx *vx, *ch_bvx = NULL;
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) { /* Check all vertexes */
+ double eperr;
+
+#ifdef INDEP_SURFACE
+ /* Check if this vertex is visible to this node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Compute the eperr between the vertex to the new node */
+ eperr = ofps_comp_eperr(s, NULL, vx->v, vx->p, nn->v, nn->p);
+ if (eperr < ch_beperr) {
+ ch_bvx = vx;
+ ch_beperr = eperr;
+ }
+ }
+
+ if (ch_bvx != NULL && ch_beperr + 1e-3 < beperr) {
+ if (bvx == NULL) {
+ warning("Sanity check ofps_findclosest_vtx() failed,\n found none, should be no %d dist %f",ch_bvx->no,ch_beperr);
+ printf("Sanity check ofps_findclosest_vtx() failed,\n found none, should be no %d dist %f\n",ch_bvx->no,ch_beperr);
+ } else {
+ warning("Sanity check ofps_findclosest_vtx() failed,\n found no %d dist %f, should be no %d dist %f",bvx->no,beperr,ch_bvx->no,ch_beperr);
+ printf("Sanity check ofps_findclosest_vtx() failed,\n found no %d dist %f, should be no %d dist %f\n",bvx->no,beperr,ch_bvx->no,ch_beperr);
+ }
+#ifdef SANITY_CHECK_CLOSEST_FATAL
+ error("findclosest vertex failed");
+#endif
+ }
+ }
+#endif
+
+ if (bvx != NULL && ceperr != NULL)
+ *ceperr = beperr;
+
+ return bvx;
+}
+
+/* Given a node, locate a vertex that it hits. */
+/* Return NULL if none, and if ceperr is not NULL, set it to the */
+/* eperr to the returned vertex. */
+/* (This only returns visible vertexes.) */
+static vtx *ofps_findhit_vtx(ofps *s, double *ceperr, node *nn) {
+ int e, di = s->di;
+ int i, j;
+ int pci; /* Point cell index */
+ acell *cp;
+ double eperr, beperr = 1e300; /* eperr of closest vertex */
+ vtx *bvx = NULL; /* Closest vertex */
+ acell *slist = NULL, *sliste = NULL; /* Next to search list */
+
+#ifdef DEBUG
+ if (s->agrid_init == 0)
+ error("ofps_findhit_vtx() called befor agrid_init");
+#endif
+
+#ifdef DEBUG_FCLOSE
+ printf("\nLocating a hit vtx to node at p = %s, v = %s\n", ppos(di,nn->p), ppos(di,nn->v));
+#endif
+
+ s->nvfschd += s->nv; /* Number of vertexes in a full search */
+ s->naccsrch++; /* Number of searches */
+
+ /* Do a breadth first seed search for any hit vertexes, or until */
+ /* we run out of cells that could improve on the current best. */
+
+ /* Locate a starting cell using the grid */
+ pci = ofps_point2cell(s, nn->v, nn->p); /* Grid index of cell of interest */
+ cp = &s->grid[pci];
+
+ s->gflag++; /* cell touched flag */
+
+ /* Put the starting cell on the search list */
+ for (j = 0; j < s->nacnl; j++) {
+#ifdef DEBUG_FCLOSE
+ printf("Adding cell ix %d co %s to slist\n",cp - s->grid, pco(di,cp->co));
+#endif
+ if (sliste == NULL) { /* First in empty list */
+ slist = cp;
+ } else {
+ sliste->slist = cp; /* Add to end of list */
+ }
+ sliste = cp;
+ cp->slist = NULL;
+ cp->gflag = s->gflag; /* Cell is on list to be searched */
+ }
+
+ /* until we run out of cells to search */
+ for (;slist != NULL;) {
+ acell *ncp;
+
+ /* For each cell in the search list, check it and recursion. */
+ for (cp = slist, slist = sliste = NULL; cp != NULL; cp = ncp) {
+ ncp = cp->slist;
+
+#ifdef DEBUG_FCLOSE
+ printf("Checking cell ix %d co %s\n",cp - s->grid,pco(di,cp->co));
+#endif
+
+ /* If the cell is worth searching */
+ if (1) {
+ vtx *vx;
+
+ /* Search the cell */
+ s->ncellssch++;
+
+ for (vx = cp->vhead; vx != NULL; vx = vx->n) {
+
+#ifdef INDEP_SURFACE
+ /* Check if this vertex is visible to this node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ /* Compute the eperr between the vertex to the new node */
+ eperr = ofps_comp_eperr(s, NULL, vx->v, vx->p, nn->v, nn->p);
+ if (eperr < vx->eperr) {
+ bvx = vx;
+ beperr = eperr;
+#ifdef DEBUG_FCLOSE
+ printf("Found hit vtx no %d eperr\n",bvx->no,beperr);
+#endif
+ break;
+ }
+ }
+ if (vx != NULL)
+ break;
+
+ /* Put all this cells neighbours on the search list */
+ /* (This is probably the critical inner loop. If ->acnl was */
+ /* scaled by sizeof(acell), then the implicit multiply could */
+ /* be avoided) */
+ for (j = 0; j < s->nacnl; j++) {
+ acell *nc = cp + s->acnl[j];
+
+ if (nc->gflag >= s->gflag)
+ continue;
+
+#ifdef DEBUG_FCLOSE
+ printf("Adding cell ix %d co %s to slist\n",nc - s->grid, pco(di,nc->co));
+#endif
+ if (sliste == NULL) { /* First in empty list */
+ slist = nc;
+ } else {
+ sliste->slist = nc; /* Add to end of list */
+ }
+ sliste = nc;
+ nc->slist = NULL;
+ nc->gflag = s->gflag; /* Cell is on list to be searched */
+ }
+ }
+ } /* Next cell in current list */
+ } /* Next list */
+
+#ifdef DEBUG_FCLOSE
+ if (bvx == NULL)
+ printf("Failed to find a hit vertex");
+ else
+ printf("Returning hit vtx no %d, eperr %f\n",bvx->no,beperr);
+#endif
+
+ if (bvx != NULL && ceperr != NULL)
+ *ceperr = beperr;
+
+ return bvx;
+}
+
+#ifdef DEBUG_FCLOSE
+#undef DEBUG_FCLOSE
+#endif
+
+#endif /* NEVER */
+
+/* ----------------------------------------------------------- */
+
+/* Re-position the vertexes given the current point positions, */
+/* and fixup the veronoi. */
+static void
+ofps_repos_and_fix_voronoi(
+ofps *s
+) {
+ int e, di = s->di;
+ int i, j, k;
+ node *nds[MXPD+1]; /* Real nodes of vertex */
+ int ii; /* Number of real nodes */
+ double ee[MXPD+1]; /* Per node estimated error */
+ vtx *vx;
+ node *nn, *pp;
+ int nfuxups, l_nfuxups; /* Count of fixups */
+ int csllow; /* Count since last low */
+ int mxcsllow = 5; /* Threshold to give up */
+
+#ifdef DEBUG
+ printf("Repositioning vertexes\n");
+#endif
+
+ /* Re-position the vertexes to match optimized node positions */
+ s->fchl = NULL;
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ nodecomb nc;
+
+ if (vx->ifake || vx->ofake)
+ continue;
+
+ vx->p_eperr = vx->eperr;
+
+ /* Pointers to real nodes. */
+ for (ii = e = 0; e <= di; e++) {
+ if (vx->nix[e] >= 0)
+ nds[ii++] = s->n[vx->nix[e]];
+ if (vx->nix[e] < -s->nbp)
+ error("ofps_repos_and_fix_voronoi() got fake node no %d comb %s fake %d",vx->no,pcomb(di,vx->nix),vx->ofake);
+ }
+
+ /* Compute the current eperr at the vertex given the repositioned nodes, */
+ /* to set acceptance threshold for repositioned vertex. */
+ ofps_pn_eperr(s, NULL, ee, vx->v, vx->p, nds, ii);
+ nc.ceperr = ofps_eperr2(ee, ii);
+
+ /* Setup to re-position the vertex */
+ memset((void *)&nc, 0, sizeof(nodecomb));
+ for (e = 0; e < di; e++) {
+ nc.nix[e] = vx->nix[e];
+ nc.p[e] = vx->p[e];
+ nc.v[e] = vx->v[e];
+ }
+ nc.nix[e] = vx->nix[e];
+
+#ifdef DEBUG
+ printf("Repositioning vertex no %d nodes %s at %s, ceperr %f\n",vx->no,pcomb(di,vx->nix),ppos(di,vx->p),nc.ceperr);
+#endif
+
+ /* We're about to change the position and eperr: */
+ ofps_rem_vacc(s, vx);
+ ofps_rem_vseed(s, vx);
+
+ if (position_vtx(s, &nc, 1, 1, 0) == 2) {
+ /* Just leave it where it was. Perhaps fixups will delete it */
+ if (s->verb > 1)
+ warning("re_position_vtx failed for vtx no %d at %s",vx->no,ppos(di,vx->p));
+ } else {
+//printf("~1 moved from %s to %s\n",ppos(di,vx->p),ppos(di,nc.p));
+
+ for (e = 0; e < di; e++) {
+ vx->p[e] = nc.p[e];
+ vx->v[e] = nc.v[e];
+ }
+ vx->eperr = nc.eperr;
+ vx->eserr = nc.eserr;
+ }
+
+ /* Count the number of gamut surfaces the vertex falls on */
+ det_vtx_gsurf(s, vx);
+
+ /* We've changed the position and eperr: */
+ ofps_add_vacc(s, vx);
+ ofps_add_vseed(s, vx);
+
+ /* Add all vertexes to the "to be checked" list */
+ vx->fchl = s->fchl; /* Add vertex to the "to be checked" list */
+ if (s->fchl != NULL)
+ s->fchl->pfchl = &vx->fchl;
+ s->fchl = vx;
+ vx->pfchl = &s->fchl;
+ vx->fflag = s->fflag;
+ vx->fupcount = 0;
+ vx->fuptol = NUMTOL;
+ }
+
+#ifdef DUMP_PLOT_BEFORFIXUP
+ printf("Before applying fixups:\n");
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 0, -1); /* Device, No wait, verticies */
+#endif /* DUMP_PLOT_BEFORFIXUP */
+
+ /* Now fixup the veroni. */
+#ifdef DEBUG
+ printf("Doing fixups:\n");
+#endif
+
+ /* We loop until the check list is empty */
+ l_nfuxups = 1e9;
+ csllow = 0;
+ while (s->fchl != NULL && csllow < mxcsllow) {
+ vtx *nvx;
+
+ s->fflag++; /* Fixup round flag */
+ s->nsvtxs = 0;
+ nfuxups = 0;
+
+#ifdef DEBUG
+ printf("\nFixup round %d%s\n",s->fflag, s->fchl == NULL ? "" : " fchl != NULL");
+#endif
+
+ /* out of gamut, or whether the closest node to it */
+ /* is not one of its parent nodes. */
+ for (vx = s->fchl; vx != NULL; vx = nvx) {
+ double ceperr; /* eperr to closest node */
+ int hit = 0;
+
+ /* For each vertex on the check list, check if it is */
+ nvx = vx->fchl;
+#ifdef DEBUG
+ printf("Checking vtx no %d, fuptol %e\n",vx->no,vx->fuptol);
+#endif
+
+ vx->hnode = NULL;
+ nn = NULL;
+ /* Check if the vertex position is clipped, */
+ /* and add fake boundary node if it is */
+ /* For all the gamut boundary planes: */
+ for (i = 0; i < s->nbp; i++) {
+ pleq *vp = &s->gpeqs[i];
+ double v;
+
+ nn = s->n[-1-i];
+
+#ifdef INDEP_SURFACE
+ /* Check if this vertex is visible to this node */
+ if (sm_vtx_node(s, vx, nn) == 0) {
+ continue;
+ }
+#endif /* INDEP_SURFACE */
+
+ for (v = vp->pe[di], e = 0; e < di; e++)
+ v += vp->pe[e] * vx->p[e];
+ if (v > vx->fuptol) {
+
+#ifdef NEVER
+ /* This is an optimization: */
+ /* Check whether nn is already a parent of the node */
+ for (e = 0; e <= di; e++) {
+ if (nn->ix == vx->nix[e])
+ break;
+ }
+ if (e <= di) {
+ continue; /* It is */
+ }
+#endif
+
+ /* Add all the vertexes parent nodes to the nearest nodes "add" list */
+#ifdef DEBUG
+ printf("Vertex no %d hit by boundary node ix %d by %e\n",vx->no,nn->ix,v);
+#endif
+ hit = 1;
+ if (vx->hnode == NULL) {
+ vx->hnode = nn;
+ vx->hitmarg = 50.0 * v;
+
+ if (s->nsvtxs >= s->_nsvtxs) {
+ s->_nsvtxs = 2 * s->_nsvtxs + 5;
+ if ((s->svtxs = (vtx **)realloc(s->svtxs, sizeof(vtx *) * s->_nsvtxs)) == NULL)
+ error("ofps: malloc failed on svtxs%d", s->_nsvtxs);
+ }
+ s->svtxs[s->nsvtxs]= vx;
+ vx->psvtxs = &s->svtxs[s->nsvtxs];
+ s->nsvtxs++;
+
+ } else if (50.0 * v > vx->hitmarg) {
+ vx->hnode = nn;
+ vx->hitmarg = 50.0 * v;
+ }
+#ifdef DEBUG
+ printf("Added vtx no %d to node %d for fixup\n",vx->no,nn->ix);
+#endif
+ }
+ }
+
+ /* Or locate the nearest node to the vertex. */
+ /* (This only returns visible nodes) */
+ if ((nn = ofps_findclosest_node(s, &ceperr, vx)) != NULL) {
+ double errimp = vx->eperr - ceperr;
+
+ /* See if it is closer than the parent nodes */
+ if (errimp >= vx->fuptol) { /* It is */
+
+ /* Add the vertexe to the "to be fixed" list */
+#ifdef DEBUG
+ printf("Vertex no %d hit by node ix %d by %e\n",vx->no,nn->ix,errimp);
+#endif
+ hit = 1;
+
+ if (vx->hnode == NULL) {
+ vx->hnode = nn;
+ vx->hitmarg = errimp;
+
+ if (s->nsvtxs >= s->_nsvtxs) {
+ s->_nsvtxs = 2 * s->_nsvtxs + 5;
+ if ((s->svtxs = (vtx **)realloc(s->svtxs, sizeof(vtx *) * s->_nsvtxs)) == NULL)
+ error("ofps: malloc failed on svtxs%d", s->_nsvtxs);
+ }
+ s->svtxs[s->nsvtxs]= vx;
+ vx->psvtxs = &s->svtxs[s->nsvtxs];
+ s->nsvtxs++;
+
+ } else if (errimp > vx->hitmarg) {
+ vx->hnode = nn;
+ vx->hitmarg = errimp;
+ }
+#ifdef DEBUG
+ printf("Added node %d to vtx no %d fixup\n",nn->ix, vx->no);
+#endif
+ }
+ }
+
+ next_vtx:;
+ if (hit) {
+ vx->fupcount++;
+ vx->fuptol *= 2.0;
+ nfuxups++;
+ }
+
+ /* Remove this vertex from the check list */
+ if (vx->pfchl != NULL) { /* If is on fixup check list, remove it */
+ *vx->pfchl = vx->fchl;
+ if (vx->fchl != NULL)
+ vx->fchl->pfchl = vx->pfchl;
+ }
+ vx->pfchl = NULL;
+ vx->fchl = NULL;
+ }
+ if (s->fchl != NULL)
+ error("Check list should be empty!");
+
+ if (nfuxups < l_nfuxups) {
+ l_nfuxups = nfuxups;
+ csllow = 0;
+ } else {
+ csllow++;
+ }
+
+#ifdef DEBUG
+ printf("\nAbout to fixup %d marked vertexes\n",nfuxups);
+#endif
+ /* Smallest error to largest seems best, */
+ /* probably because the closer nodes cut off the */
+ /* further ones, reducing the number of redundant create/deletes */
+#define HEAP_COMPARE(A,B) ((A)->hitmarg < (B)->hitmarg)
+ HEAPSORT(vtx *, s->svtxs, s->nsvtxs);
+#undef HEAP_COMPARE
+
+ /* Fixup the back references after the sort */
+ for (i = 0; i < s->nsvtxs; i++) {
+ vx = s->svtxs[i];
+ vx->psvtxs = &s->svtxs[i];
+ }
+
+ /* For each vertex on the "to be fixed" list, */
+ /* search for hits by the node starting at that vertex, */
+ /* and recursively locate all the hit vertexes. */
+ for (i = 0; i < s->nsvtxs; i++) {
+
+ if ((vx = s->svtxs[i]) == NULL) {
+ continue; /* Vertex got deleted by a previous fix */
+ }
+ nn = vx->hnode;
+ s->svtxs[i] = NULL;
+ vx->psvtxs = NULL;
+
+ s->nvcheckhits = 0; /* Count number of vertexes hit by recursive check. */
+ s->batch = NULL; /* Nothing in pending delete list */
+ s->nup = NULL; /* Nothing in nodes to be updated list */
+ s->flag++; /* Marker flag for adding this node */
+ s->nxh = NULL; /* Nothing in nodes hit list */
+
+#ifdef DEBUG
+ printf("\nFixing up node ix %d starting at vx no %d\n",nn->ix,vx->no);
+// fprintf(stderr,"Fixing up node ix %d starting at vx no %d\n",nn->ix,vx->no);
+#endif
+ /* Recursively search for all vertexes hit by the new node */
+ /* Note that we don't care that this only finds connected hits, */
+ /* since there should be a separate s->svtxs[] entry for a hit by this */
+ /* node on a disconnected region. */
+ ofps_check_vtx(s, nn, vx, 100000, 0);
+
+#ifdef DEBUG
+ printf("Fixing up node ix %d, %d vertexes hit by it\n",nn->ix,s->nvcheckhits);
+#endif
+
+ /* Number of nodes that would be checked by exaustive search */
+ s->vvpchecks += s->nv;
+
+ /* Now re-add the node to the veronoi */
+ if (add_to_vsurf(s, nn, 1, 0) > 0) {
+ s->add_hit++;
+#ifdef DUMP_PLOT_EACHFIXUP
+ printf("After adding node ix %d at %s to vurf\n",nn->ix,ppos(di,nn->p));
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 0, -1); /* Device, No wait, verticies */
+#endif /* DUMP_PLOT_EACHFIXUP */
+ } else {
+#ifdef DUMP_PLOT_EACHFIXUP
+ printf("Adding node ix %d at %s to vurf was miss\n",nn->ix,ppos(di,nn->p));
+#endif /* DUMP_PLOT_EACHFIXUP */
+ s->fadd_mis++;
+ }
+ }
+ s->nsvtxs = 0;
+ } /* Loop until there are no more vertexes to check */
+
+#ifdef DEBUG
+ printf("Done fixups s->fchl 0x%x == NULL or csllow %d >= %d\n",s->fchl,csllow,mxcsllow);
+#endif
+
+#ifdef SANITY_CHECK_FIXUP
+ /* Check that no node other than a parent is closer to any vertex */
+ if (check_vertex_closest_node(s)) {
+#ifdef SANITY_CHECK_FIXUP_FATAL
+ error("!!!!!! Sanity: Fixup didn't work");
+#endif /* SANITY_CHECK_FIXUP_FATAL */
+ }
+#endif /* SANITY_CHECK_FIXUP */
+
+#ifdef DEBUG
+ printf("Applied fixups\n");
+#endif
+}
+
+/* --------------------------------------------------- */
+/* After seeding or re-positioning, create the node */
+/* neighbour node and vertex lists. */
+/* (Invalidates and deletes any midpoints) */
+static void ofps_re_create_node_node_vtx_lists(ofps *s) {
+ int i, e, di = s->di;
+ vtx *vx;
+
+ /* for each node, clear its vertex list */
+ for (i = -s->gnp; i < s->np; i++) {
+ node *p = s->n[i];
+ p->nvv = 0;
+ }
+
+ /* For each vertex, add it to each of its parent nodes */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ for (e = 0; e <= di; e++) {
+ node *p = s->n[vx->nix[e]];
+ node_add_vertex(s, p, vx);
+ }
+ }
+
+ /* For each node, recompute its neighbourhood nodes */
+ for (i = -s->gnp; i < s->np; i++) {
+ node *p = s->n[i];
+ node_recomp_nvn(s, p); /* Recompute the nodes associated vertex nodes */
+ }
+}
+
+/* --------------------------------------------------- */
+/* Midpoints */
+
+/* Finding midpoint location code using dnsqe() */
+
+/* Context for callback */
+typedef struct {
+ ofps *s;
+ node *nds[2]; /* List of nodes */
+} mopt_cx;
+
+/* calculate the functions at x[] */
+int dnsq_mid_solver( /* Return < 0 on abort */
+ void *fdata, /* Opaque data pointer */
+ int n, /* Dimenstionality */
+ double *x, /* Multivariate input values */
+ double *fvec, /* Multivariate output values */
+ int iflag /* Flag set to 0 to trigger debug output */
+) {
+ mopt_cx *cx = (mopt_cx *)fdata;
+ ofps *s = cx->s;
+ int e, di = s->di;
+ double pos[MXPD], sv[MXPD];
+ double cee[2], teperr;
+
+//printf("~1 dnsq_solver got %d nodes and %d planes\n",cx->nn,cx->nsp);
+
+ /* Compute pos as interpolation between node 0 and 1 */
+ for (e = 0; e < di; e++)
+ pos[e] = cx->nds[0]->p[e] * (1.0 - x[0]) + cx->nds[1]->p[e] * x[0];
+
+ ofps_cc_percept(s, sv, pos);
+
+ /* Get eperr */
+ cee[0] = ofps_comp_eperr8(s, NULL, sv, pos, cx->nds[0]->v, cx->nds[0]->p);
+ cee[1] = ofps_comp_eperr8(s, NULL, sv, pos, cx->nds[1]->v, cx->nds[1]->p);
+
+//printf("~1 error = %f, %f", cee[0], cee[1]);
+
+ teperr = 0.5 * (cee[0] + cee[1]);
+
+ fvec[0] = teperr - cee[0];
+
+// printf("dnsq_mid_solver returning %f from %f\n",fvec[0],x[0]);
+
+ return 0;
+}
+
+/* Create or re-create all the midpoints, given the vertexes are done. */
+static void
+ofps_create_mids(ofps *s) {
+ int e, di = s->di;
+ int i, j, k;
+ double rerr;
+ int nsp = 0; /* Number of surface points */
+ double dnsqtol = 1e-6; /* Solution tollerance to aim for */
+ vopt_cx cx;
+ double fvec[1];
+ int rv;
+
+ cx.s = s;
+
+//printf("~1 creating mid points\n");
+ /* Clear any existing midpoints */
+ for (i = 0; i < s->tinp; i++) {
+ node *p = s->n[i];
+
+ if (p->ix < 0)
+ break; /* Done when we get to gamut boundary nodes */
+
+ for (j = 0; j < p->nvn; j++) {
+ if (p->mm[j] != NULL) {
+ del_mid(s, p->mm[j]);
+ p->mm[j] = NULL;
+ }
+ }
+ }
+
+ /* For each node, make sure it and each neighbor node have a shared midpoint */
+ for (i = 0; i < s->tinp; i++) {
+ node *p = s->n[i];
+
+ if (p->ix < 0)
+ break; /* Done when we get to gamut boundary nodes */
+
+ /* For each neighbor node, create midpoint */
+ for (j = 0; j < p->nvn; j++) {
+ mid *mp;
+ node *p2;
+ double ee[2];
+
+ if (p->vn[j] < 0 || p->mm[j] != NULL)
+ continue; /* Gamut boundary or already got a midpoint */
+
+ /* Create a midpoint between node p->ix and p->vn[j] */
+ p2 = s->n[p->vn[j]];
+ mp = new_mid(s);
+ mp->refc++;
+
+ p->mm[j] = mp;
+ for (k = 0; k < p2->nvn; k++) {
+ if (p2->vn[k] == p->ix) {
+ p2->mm[k] = mp;
+ mp->refc++;
+ break;
+ }
+ }
+
+ mp->nix[0] = p->ix;
+ mp->nix[1] = p->vn[j];
+//printf("~1 creating midpoint %d between nodes %d %d\n",mp->no,p->ix,p->vn[j]);
+
+ cx.nds[0] = p;
+ cx.nds[1] = p2;
+ mp->np = 0.5;
+
+ /* Locate mid point */
+ if ((rv = dnsqe((void *)&cx, dnsq_mid_solver, NULL, 1, &mp->np,
+ 0.2, fvec, 0.0, dnsqtol, 0, 0)) != 1 && rv != 3) {
+ error("ofps: Locating midpoint failed with %d",rv);
+ }
+
+ for (e = 0; e < di; e++)
+ mp->p[e] = p->p[e] * (1.0 - mp->np) + p2->p[e] * mp->np;
+ ofps_cc_percept(s, mp->v, mp->p);
+
+ /* Compute the eperr's for midpoint */
+ ofps_pn_eperr(s, mp->ce, ee, mp->v, mp->p, cx.nds, 2);
+ mp->eperr = ofps_eperr2(ee, 2);
+ mp->eserr = ofps_eserr2(mp->ce, ee, 2);
+//printf("~1 location %s (%s) eperr %f\n",ppos(di,mp->p), ppos(di,mp->v), mp->eperr);
+ }
+ }
+}
+
+/* --------------------------------------------------- */
+/* Statistics: Compute serr stats. */
+
+static void ofps_stats(ofps *s) {
+ int e, di = s->di;
+ int i, j;
+ double acnt;
+ vtx *vx;
+ mid *mp;
+
+//printf("~1 stats called\n");
+ s->mn = 1e80;
+ s->mx = -1e80;
+ s->av = 0.0;
+ acnt = 0.0;
+
+ /* Vertex stats */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ double es;
+
+ if (vx->ghost) /* Skip a ghost (coincident) vertex */
+ continue;
+
+#ifdef INDEP_SURFACE
+ /* Ignore vertexes that aren't full dimension. */
+ if (sm_andtest(s, &s->sc[0].a_sm, &vx->vm) == 0)
+ continue;
+#endif
+ es = vx->eserr;
+ if (es >= 0.0 && es < s->mn)
+ s->mn = es;
+ if (es > s->mx)
+ s->mx = es;
+ s->av += es;
+ acnt++;
+ }
+
+ s->av /= acnt;
+
+ /* Midpoint/node stats */
+ for (s->smns = 1e6, mp = s->umid; mp != NULL; mp = mp->link) {
+
+ if (mp->nix[0] < 0 || mp->nix[1] < 0
+ || mp->eserr < 0.0)
+ continue; /* Skip fake points */
+
+ if (mp->eserr < s->smns) {
+ s->smns = mp->eserr;
+ }
+ }
+ s->smns *= 2.0; /* Error distance between nodes is double error to midpoint */
+}
+
+/* --------------------------------------------------- */
+/* Support accessing the list of generated sample points */
+
+/* Reset the read index */
+static void
+ofps_reset(ofps *s) {
+ s->rix = 0;
+}
+
+/* Read the next non-fixed point value */
+/* Return nz if no more */
+static int
+ofps_read(ofps *s, double *p, double *v) {
+ int e;
+
+ /* Advance to next non-fixed point */
+ while(s->rix < s->np && s->n[s->rix]->fx)
+ s->rix++;
+
+ if (s->rix >= s->np)
+ return 1;
+
+ /* Return point info to caller */
+ for (e = 0; e < s->di; e++) {
+ if (p != NULL)
+ p[e] = s->n[s->rix]->p[e];
+ if (v != NULL)
+ v[e] = s->n[s->rix]->v[e];
+ }
+ s->rix++;
+
+ return 0;
+}
+
+/* --------------------------------------------------- */
+
+/* Compute more optimum location for node amongst the surrounding */
+/* verticies. The result is put in ->np[] and ->nv[]. */
+/* The main aim is to minimize the maximum eserr of any vertex, */
+/* but moving away from low midpoint eserr's improves the */
+/* convergence rate and improves the eveness of the result. */
+static void comp_opt(ofps *s, int poi, double oshoot, double sep_weight) {
+ node *pp; /* Node in question */
+ int e, di = s->di;
+ double radsq = -1.0; /* Span/radius squared */
+ double rad;
+ double sum;
+ int i;
+ int bi = 0, bj = 0;
+
+ pp = s->n[poi]; /* Node in question */
+
+ /* Move towards vertex with highest eserr approach */
+ if (pp->nvv > 0) {
+ double aerr1, werr1, berr1, cnt1; /* Average, worst, best eserr from vertexes */
+ int weix1, beix1; /* Worst, best error vertex index */
+ double ov1[MXPD]; /* Optimization vector towards largest vertex error */
+ double aerr2, werr2, berr2, cnt2; /* Average, worst, best eserr from midpoints */
+ int weix2, beix2; /* Worst, best error midpoint index */
+ double ov2[MXPD]; /* Optimization vector away from smallest midpoint error */
+
+
+//printf("\n --------------------------------\n");
+//printf("~1 Optimizing ix %d, %f %f\n",poi,pp->p[0],pp->p[1]);
+
+ /* Compute the average and locate the largest error from verticies */
+ for (aerr1 = cnt1 = 0.0, werr1 = -1.0, berr1 = 1e80, i = 0; i < pp->nvv; i++) {
+ vtx *vp = pp->vv[i];
+
+#ifdef INDEP_SURFACE
+ /* Ingnore vertexes that are not visible to this node. */
+ if (sm_vtx_node(s, vp, pp) == 0) {
+ continue;
+ }
+#endif
+ aerr1 += vp->eserr;
+ cnt1++;
+
+//printf("~1 Vertex no %d at %f %f serr = %f\n",vp->no,vp->p[0],vp->p[1],vp->eserr);
+ if (vp->eserr > werr1) {
+ werr1 = vp->eserr;
+ weix1 = i;
+ }
+ if (vp->eserr < berr1) {
+ berr1 = vp->eserr;
+ beix1 = i;
+ }
+ }
+
+ if (cnt1 > 0.0 && werr1 > NUMTOL && berr1 > NUMTOL) {
+ double wbf, bbf;
+ double towards = 0.8; /* Amount to weight vector towards from closest */
+
+ /* Compute a blend factor that takes the current */
+ /* location towards the worst vertex error and */
+ /* away from the best */
+ aerr1 /= cnt1;
+ wbf = towards * (werr1 - aerr1)/werr1;
+ bbf = (1.0 - towards) * (aerr1 - berr1)/berr1;
+// wbf = towards * (werr1 - aerr1)/aerr1;
+// bbf = (1.0 - towards) * (aerr1 - berr1)/aerr1;
+
+ for (e = 0; e < di; e++)
+ ov1[e] = wbf * (pp->vv[weix1]->p[e] - pp->p[e])
+ + bbf * (pp->p[e] - pp->vv[beix1]->p[e]);
+//printf("~1 moved %f %f towards vtx no %d at %f %f\n",ov1[0],ov1[2],pp->vv[weix1]->no,pp->vv[weix1]->p[0],pp->vv[weix1]->p[1]);
+ } else {
+ for (e = 0; e < di; e++)
+ ov1[e] = 0.0;
+ }
+
+ /* Compute the average and locate the smallest error from midpoints */
+ for (aerr2 = cnt2 = 0.0, werr2 = 1e80, berr2 = -1.0, i = 0; i < pp->nvn; i++) {
+ mid *mp = pp->mm[i];
+ node *on = s->n[pp->vn[i]]; /* Other node involved */
+
+ if (mp == NULL || mp->nix[0] < 0 || mp->nix[1] < 0)
+ continue; /* Must be a fake gamut boundary node */
+
+#ifdef INDEP_SURFACE
+ /* Ingnore nodes of higher dimension */
+ if ((pp->pmask & on->pmask) != pp->pmask) {
+ continue;
+ }
+#endif
+ aerr2 += mp->eserr;
+ cnt2++;
+//printf("~1 plane no %d from node ix %d serr = %f\n",mp->no,on->ix,mp->eserr);
+ if (mp->eserr < werr2) {
+ werr2 = mp->eserr;
+ weix2 = i;
+ }
+ if (mp->eserr > berr2) {
+ berr2 = mp->eserr;
+ beix2 = i;
+ }
+ }
+
+ if (cnt2 > 0.0 && werr2 > NUMTOL && berr2 > NUMTOL) {
+ double wbf, bbf;
+ double away = 0.8; /* Amount to weight vector away from closest */
+
+ /* Compute a blend factor that takes the current */
+ /* location away from the worst plane error */
+ aerr2 /= cnt2;
+ wbf = away * (aerr2 - werr2)/werr2;
+ bbf = (1.0 - away) * (berr2 - aerr2)/berr2;
+// wbf = away * (aerr2 - werr2)/aerr2;
+// bbf = (1.0 - away) * (berr2 - aerr2)/aerr2;
+
+ for (e = 0; e < di; e++)
+ ov2[e] = wbf * (pp->p[e] - pp->mm[weix2]->p[e])
+ + bbf * (pp->mm[beix2]->p[e] - pp->p[e]);
+//printf("~1 moved %f %f away from node ix %d at %f %f\n",ov2[0],ov2[1],pp->vn[weix2],pp->mm[weix2]->p[0],pp->mm[weix2]->p[1]);
+ } else {
+ for (e = 0; e < di; e++)
+ ov2[e] = 0.0;
+ }
+//printf("~1 ov1 = %f %f, ov2 = %f %f, sep weight %f\n",ov1[0], ov1[1], ov2[0], ov2[1], sep_weight);
+
+ /* Move the node by the sum of the two vectors */
+ for (e = 0; e < di; e++)
+ pp->np[e] = pp->p[e] + (1.0 - sep_weight) * ov1[e] + sep_weight * ov2[e];
+//printf("~1 moved node %d by %f %f\n",pp->ix, (1.0 - sep_weight) * ov1[0] + sep_weight * ov2[0],(1.0 - sep_weight) * ov1[1] + sep_weight * ov2[1]);
+ }
+
+//printf("~1 check moved by %f %f\n",pp->np[0] - pp->p[0], pp->np[1] - pp->p[1]);
+ /* Apply overshoot/damping */
+ for (e = 0; e < di; e++)
+ pp->np[e] = pp->p[e] + (pp->np[e] - pp->p[e]) * oshoot;
+//printf("~1 after overshoot of %f got %f %f\n",oshoot,pp->np[0],pp->np[1]);
+
+ /* Clip the new location */
+ ofps_clip_point10(s, pp->np, pp->np);
+
+#if defined(KEEP_SURFACE) || defined(INDEP_SURFACE)
+ if (pp->nsp > 0) {
+ confineto_gsurf(s, pp->np, pp->sp, pp->nsp);
+ }
+#endif
+ /* Update perceptual */
+ s->percept(s->od, pp->nv, pp->np); /* Was clipped above */
+
+ /* Compute how far the point has moved */
+ /* (?? maybe should change this to change in average or max eserr ??) */
+ for (sum = 0.0, e = 0; e < di; e++) {
+ double tt = pp->np[e] - pp->p[e];
+ sum += tt * tt;
+//printf("~1 total motion = %f\n",sqrt(sum));
+ }
+ if (sum > s->mxmvsq) /* Track maximum movement */
+ s->mxmvsq = sum;
+}
+
+static void
+ofps_optimize(
+ofps *s
+) {
+ int maxits;
+ int transitters;
+ double transpow;
+ double oshoot, ioshoot, foshoot;
+ double sepw, isepw, fsepw;
+ double stoptol;
+ int e, di = s->di;
+ int i, j;
+
+ /* Default is "Good" */
+ maxits = OPT_MAXITS;
+ transitters = OPT_TRANS_ITTERS;
+ transpow = OPT_TRANS_POW;
+ ioshoot = OPT_INITIAL_OVERSHOOT;
+ foshoot = OPT_FINAL_OVERSHOOT;
+ isepw = OPT_INITIAL_SEP_WEIGHT;
+ fsepw = OPT_FINAL_SEP_WEIGHT;
+ stoptol = OPT_STOP_TOL;
+
+#ifdef OPT_MAXITS_2
+ /* Option is "Fast" */
+ if (s->good == 0) {
+ maxits = OPT_MAXITS_2;
+ transitters = OPT_TRANS_ITTERS_2;
+ transpow = OPT_TRANS_POW_2;
+ ioshoot = OPT_INITIAL_OVERSHOOT_2;
+ foshoot = OPT_FINAL_OVERSHOOT_2;
+ isepw = OPT_INITIAL_SEP_WEIGHT_2;
+ fsepw = OPT_FINAL_SEP_WEIGHT_2;
+ stoptol = OPT_STOP_TOL_2;
+ }
+#endif /* OPT_MAXITS_2 */
+
+ oshoot = ioshoot;
+ for (s->optit = 0; s->optit < maxits; s->optit++) { /* Up to maximum number of itterations */
+ vtx *vx;
+ double bf = 1.0;
+ int nvxhits;
+ double hratio, thresh;
+ int doinc = 0;
+
+ s->mxmvsq = 0.0;
+ if (s->optit < transitters)
+ bf = s->optit/(double)transitters;
+ bf = pow(bf, transpow);
+ oshoot = (1.0 - bf) * ioshoot + bf * foshoot;
+ sepw = (1.0 - bf) * isepw + bf * fsepw;
+
+ /* Compute optimized node positions */
+ for (i = 0; i < s->tinp; i++) {
+
+ if (s->n[i]->fx)
+ continue; /* Ignore fixed points */
+
+ comp_opt(s, i, oshoot, sepw);
+ }
+
+ /* Then update their positions to the optimized ones */
+ for (i = 0; i < s->tinp; i++) {
+ node *pp = s->n[i];
+
+ if (pp->fx)
+ continue; /* Ignore fixed points */
+
+ ofps_rem_nacc(s, pp); /* Remove from spatial accelleration grid */
+
+ for (e = 0; e < di; e++) {
+ pp->op[e] = pp->p[e]; /* Record previous position */
+ pp->p[e] = pp->np[e]; /* Move to optimized location */
+ pp->v[e] = pp->nv[e];
+ }
+ ofps_add_nacc(s, pp); /* Add to spatial acceleration grid */
+ }
+
+ /* Make sure that the optimized nodes don't accidentaly collide */
+ for (i = 0; i < s->tinp; i++) {
+ node *pp = s->n[i];
+
+ if (pp->fx)
+ continue; /* Ignore fixed points */
+
+ for (j = 0; j < 20; j++) { /* Retry until not cooincident */
+ int pci; /* Point list index */
+ acell *cp; /* Acceleration cell */
+ node *p1;
+ pci = ofps_point2cell(s, pp->v, pp->p); /* Grid index of cell of interest */
+
+ cp = &s->grid[pci];
+ for (p1 = cp->head; p1 != NULL; p1 = p1->n) {
+ if (p1 == pp)
+ continue;
+ for (e = 0; e < di; e++) {
+ if (fabs(pp->p[e] - p1->p[e]) > COINTOL)
+ break; /* Not cooincident */
+ }
+ if (e >= di) { /* Cooincident */
+#ifdef DEBUG
+ printf("Optimized node ix %d at %s collides with ix %d at %s - joggling it %d\n",pp->ix,ppos(di,pp->p),p1->ix,ppos(di,p1->p),i);
+ warning("Optimized node ix %d at %s collides with ix %d at %s - joggling it %d",pp->ix,ppos(di,pp->p),p1->ix,ppos(di,p1->p),i);
+#endif
+ ofps_rem_nacc(s, pp); /* Remove from spatial accelleration grid */
+
+ /* Joggle it's position */
+ for (e = 0; e < di; e++) {
+ if (pp->p[e] < 0.5)
+ pp->p[e] += d_rand(0.0, 1e-4);
+ else
+ pp->p[e] -= d_rand(0.0, 1e-4);
+ }
+ /* Ignore confine planes. Next itter should fix it anyway ? */
+ ofps_clip_point10(s, pp->p, pp->p);
+
+ /* Update perceptual (was clipped above) */
+ s->percept(s->od, pp->v, pp->p);
+
+ break;
+ }
+ }
+ if (p1 == NULL)
+ break;
+ }
+ if (j >= 20)
+ error("ofps_optimize: Assert, was unable to joggle cooincindent point");
+ }
+
+ /* Ideally the fixup method should create and delete fewer vertexes */
+ /* than reseeding, hence always be faster, but in practice this doesn't */
+ /* seem to be so. Perhaps this is because the fixups are being */
+ /* done in a far from optimal order ? What this means is that often */
+ /* for big movements reseeding will be faster. To get the best of both, */
+ /* we try and estimate when the fixup method will break even with */
+ /* reseeding, and switch over. */
+
+ /* Estimate how many vertexes will be hit by the move */
+ nvxhits = ofps_quick_check_hits(s);
+
+ /* Decide which way to go */
+ thresh = 1.0/(di * di);
+ hratio = nvxhits/(double)s->nv;
+//printf("~1 quick check of vertex hits = %d, ratio %f, threshold %f\n",nvxhits,hratio,thresh);
+
+ /* Hmm. Re-seed seems to sometimes be slower than expected for > 3D, */
+ /* so don't use it. */
+ if (hratio < thresh && di < 4) {
+ doinc = 1;
+ }
+
+#ifdef FORCE_RESEED /* Force reseed after itteration */
+ doinc = 0;
+#else
+# ifdef FORCE_INCREMENTAL /* Force incremental update after itteration */
+ doinc = 1;
+# endif
+#endif
+ /* Incrementally update veronoi */
+ if (doinc) {
+
+ if (s->verb)
+ printf("Fixing up veronoi\n");
+
+ /* Re-position the vertexes, and fixup the veronoi */
+ ofps_repos_and_fix_voronoi(s);
+
+ /* Reseed the veronoi */
+ } else {
+
+ if (s->verb)
+ printf("Re-seeding\n");
+
+ /* remove nodes from the spatial acceleration grid. */
+ for (i = 0; i < s->tinp; i++) {
+ node *pp = s->n[i];
+ ofps_rem_nacc(s, pp); /* Remove from spatial accelleration grid */
+ }
+
+ /* And recompute veronoi, and add to spatial accelleration grid. */
+ ofps_redo_voronoi(s);
+ }
+ ofps_re_create_node_node_vtx_lists(s);
+ ofps_create_mids(s);
+
+ ofps_stats(s);
+ if (s->verb) {
+ printf("It %d: Maxmv = %f, MinPoint = %.3f, Min = %.3f, Avg. = %.3f, Max = %.3f, %.1f secs.\n",s->optit+1,sqrt(s->mxmvsq),s->smns,s->mn,s->av,s->mx,(msec_time() - s->l_mstime) / 1000.0);
+#ifdef STATS
+ printf("Current vtx %d, created %d, deleted %d, positioned %d\n", s->nv,s->nvtxcreated - s->l_nvtxcreated,s->nvtxdeleted - s->l_nvtxdeleted, s->positions - s->l_positions);
+ s->l_positions = s->positions;
+ s->l_nvtxcreated = s->nvtxcreated;
+ s->l_nvtxdeleted = s->nvtxdeleted;
+#endif
+ s->l_mstime = msec_time();
+ }
+
+#ifdef DUMP_STRUCTURE
+ dump_node_vtxs(s, 1);
+// { char buf[200]; sprintf(buf, "After itteration %d",s->optit+1); dump_node_vtxs2(s, buf); }
+ printf("=========================================================================\n");
+#endif
+#ifdef DUMP_PLOT
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 1, -1); /* Device, wait, verticies */
+#endif /* DUMP_PLOT */
+
+#ifdef SANITY_RESEED_AFTER_FIXUPS
+ /* For debugging, replace the incremental fixed up veronoi with */
+ /* a from scratch one. */
+
+ if (s->verb)
+ printf("Re-seeding after fixup:\n");
+
+ /* Save the current incremental vertexes */
+ save_ivertexes(s);
+
+ ofps_redo_voronoi(s);
+ ofps_re_create_node_node_vtx_lists(s);
+ ofps_create_mids(s);
+
+ ofps_stats(s);
+ if (s->verb) {
+ printf("It %d: Maxmv = %f, MinPoint = %.3f, Min = %.3f, Avg. = %.3f, Max = %.3f, %.1f secs.\n",s->optit+1,sqrt(s->mxmvsq),s->smns,s->mn,s->av,s->mx,(msec_time() - s->l_mstime) / 1000.0);
+#ifdef STATS
+ printf("Current vtx %d, created %d, deleted %d, positioned %d\n", s->nvtxcreated - s->l_nvtxcreated,s->nvtxdeleted - s->l_nvtxdeleted, s->positions - s->l_positions);
+ s->l_positions = s->positions;
+ s->l_nvtxcreated = s->nvtxcreated;
+ s->l_nvtxdeleted = s->nvtxdeleted;
+#endif
+ s->l_mstime = msec_time();
+ }
+
+ /* Check that no node other than a parent is closer to any vertex */
+ if (check_vertex_closest_node(s)) {
+ warning("Verify that re-seed leaves only parents closest to vertexes failed");
+ }
+
+ /* Check the incremental vertexes against the re-seeded vertexes */
+ if (check_vertexes(s)) {
+ warning("Verify of incremental vertexes failed!");
+ printf("Verify of incremental vertexes failed!\n");
+ } else {
+ warning("Verify of incremental vertexes suceeded!");
+ }
+#ifdef DUMP_STRUCTURE
+ dump_node_vtxs(s, 1);
+#endif
+#ifdef DUMP_PLOT
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 1, -1); /* Device, wait, verticies */
+#endif /* DUMP_PLOT */
+#endif /* SANITY_RESEED_AFTER_FIXUPS */
+
+ if (sqrt(s->mxmvsq) < stoptol)
+ break;
+ }
+}
+
+/* ------------------------------------------------------------------------ */
+/* Main object creation/destruction */
+
+/* Destroy ourselves */
+static void
+ofps_del(ofps *s) {
+ int i, e, di = s->di;
+
+ if (s->ufx != NULL)
+ free(s->ufx);
+
+ /* Free our nodes */
+ for (i = 0; i < s->np; i++) {
+ node_free(s, s->n[i]);
+ }
+ s->n -= s->gnp; /* Fixup offset */
+ free(s->n);
+ free(s->_n);
+
+ /* Any free vertexes */
+ while (s->fvtx != NULL) {
+ vtx *p = s->fvtx;
+ s->fvtx = p->link;
+ free(p);
+ }
+
+ /* Any other allocations */
+ s->sob->del(s->sob);
+ if (s->combs != NULL) {
+ for (i = 0; i < s->_ncombs; i++) {
+ if (s->combs[i].v1 != NULL)
+ free(s->combs[i].v1);
+ if (s->combs[i].v2 != NULL)
+ free(s->combs[i].v2);
+ }
+ free(s->combs);
+ }
+ if (s->sc)
+ free(s->sc);
+
+ if (s->svtxs != NULL)
+ free(s->svtxs);
+
+ if (s->_grid != NULL)
+ free(s->_grid);
+
+ if (s->acnl != NULL)
+ free(s->acnl);
+
+ if (s->vtreep != NULL)
+ aat_adelete(s->vtreep);
+
+ for (e = 0; e <= (di+1); e++) {
+ if (s->vtrees[e] != NULL)
+ aat_adelete(s->vtrees[e]);
+ }
+
+ if (s->pcache != NULL)
+ s->pcache->del(s->pcache);
+
+ free(s);
+}
+
+/* Constructor */
+ofps *new_ofps(
+int verb, /* Verbosity level, 1 = progress, 2 = warnings */
+int di, /* Dimensionality of device space */
+double ilimit, /* Ink limit (sum of device coords max) */
+int tinp, /* Total number of points to generate, including fixed */
+int good, /* 0 = fast, 1 = good */
+double dadaptation, /* Degree of adaptation to device characteristic 0.0 - 1.0 */
+double devd_wght, /* Device space weighting (if dad < 0) */
+double perc_wght, /* Perceptual space weighting (if dad < 0) */
+double curv_wght, /* Curvature weighting (if dad < 0) */
+fxpos *fxlist, /* List of existing fixed points (may be NULL) */
+int fxno, /* Number of existing fixes points */
+void (*percept)(void *od, double *out, double *in), /* Perceptual lookup func. */
+void *od /* context for Perceptual function */
+) {
+ return new_ofps_ex(verb, di, ilimit, NULL, NULL, tinp, good,
+ dadaptation, devd_wght, perc_wght, curv_wght,
+ fxlist, fxno, percept, od, 0, -1);
+}
+
+/* Extended constructor */
+ofps *new_ofps_ex(
+int verb, /* Verbosity level, 1 = progress, 2 = warnings */
+int di, /* Dimensionality of device space */
+double ilimit, /* Total ink limit (sum of device coords max) */
+double *imin, /* Ink limit - limit on min of p[], usually >= 0.0 (may be NULL) */
+double *imax, /* Ink limit - limit on min of p[], usually <= 1.0 (may be NULL) */
+int tinp, /* Total number of points to generate, including fixed */
+int good, /* 0 = fast, 1 = good */
+double dadaptation, /* Degree of adaptation to device characteristic 0.0 - 1.0 */
+double devd_wght, /* Device space weighting (if dad < 0) */
+double perc_wght, /* Perceptual space weighting (if dad < 0) */
+double curv_wght, /* Curvature weighting (if dad < 0) */
+fxpos *fxlist, /* List of existing fixed points (may be NULL) */
+int fxno, /* Number of existing fixes points */
+void (*percept)(void *od, double *out, double *in), /* Perceptual lookup func. */
+void *od, /* context for Perceptual function */
+int ntostop, /* Debug - number of points until diagnostic stop */
+int nopstop /* Debug - number of optimizations until diagnostic stop, -1 = not */
+) {
+ int i, e;
+ ofps *s;
+ long stime,ttime;
+
+ stime = clock();
+
+ if ((s = (ofps *)calloc(sizeof(ofps), 1)) == NULL)
+ error ("ofps: malloc failed on new ofps");
+
+ if (di > MXPD)
+ error ("ofps: Can't handle di %d",di);
+
+ s->verb = verb;
+ s->ntostop = ntostop;
+ s->nopstop = nopstop;
+
+ if ((s->sob = new_sobol(di)) == NULL)
+ error ("ofps: new_sobol %d failed", di);
+
+ if (s->verb)
+ printf("Degree of adaptation: %.3f\n", dadaptation);
+
+ /* Set internal values explicitly */
+ if (dadaptation < 0.0) {
+ s->devd_wght = devd_wght;
+ s->perc_wght = perc_wght;
+ s->curv_wght = curv_wght;
+
+ /* Set values implicitly with adapation level */
+ } else {
+ if (dadaptation > 1.0)
+ dadaptation = 1.0;
+
+ /* Convert to internal numbers */
+ s->perc_wght = ADAPT_PERCWGHT * dadaptation;
+ s->curv_wght = ADAPT_CURVWGHT * dadaptation * dadaptation;
+ s->devd_wght = 1.0 - s->perc_wght;
+ }
+ if (s->verb)
+ printf("Adaptation weights: Device = %.3f, Perceptual = %.3f, Curvature = %.3f\n",
+ s->devd_wght,s->perc_wght,s->curv_wght);
+
+ s->di = di;
+
+ if (tinp < fxno) /* Make sure we return at least the fixed points */
+ tinp = fxno;
+
+ s->fxno = fxno; /* Number of fixed points provided */
+ s->tinp = tinp; /* Target total number of points */
+
+ /* Hack to workaround pathalogical case. At ilimit == di-2.0, we get > 32 bits */
+ /* of mask for CMYK */
+ if (di >= 3
+ && ilimit >= (di-2.0 - 2 * ILIMITEPS)
+ && ilimit <= (di-2.0 + 2 * ILIMITEPS))
+ ilimit = di-2.0 - 2 * ILIMITEPS;
+
+ s->ilimit = ilimit;
+
+ for (e = 0; e < di; e++) {
+ if (imin != NULL)
+ s->imin[e] = imin[e];
+ else
+ s->imin[e] = 0.0;
+
+ if (imax != NULL)
+ s->imax[e] = imax[e];
+ else
+ s->imax[e] = 1.0;
+ }
+
+ /* Compute an approximate half expected sample point spacing, */
+ /* and setup seeding acceleration grid. */
+ {
+ double vol = 1.0;
+ double eprange;
+
+ for (e = 0; e < di; e++)
+ vol *= s->imax[e] - s->imin[e];
+
+ vol /= tinp; /* Approx vol per point */
+ vol = pow(vol, 1.0/di); /* Distance per point */
+
+ s->surftol = SURFTOL * vol;
+//printf("~1 surftol = %f\n",s->surftol);
+ }
+
+#ifdef STANDALONE_TEST
+ /* If no perceptual function given, use default */
+ if (percept == NULL) {
+ s->percept = default_ofps_to_percept;
+ s->od = s;
+ } else {
+ s->percept = percept;
+ s->od = od;
+ }
+#else
+ /* If no perceptual function given, use default */
+//warning("~1 new_ofps_ex() forcing default perceptual function");
+ if (percept == NULL) {
+ s->percept = default_ofps_to_percept;
+ s->od = s;
+ } else {
+ s->percept = percept;
+ s->od = od;
+ }
+#endif
+
+ s->good = good; /* Fast/Good flag */
+ s->lperterb = PERTERB_AMOUNT;
+#ifdef OPT_MAXITS_2
+ if (s->good == 0)
+ s->lperterb = PERTERB_AMOUNT_2;
+#endif
+ s->ssurfpref = INITIAL_SURFACE_PREF;
+ s->esurfpref = FINAL_SURFACE_PREF;
+
+ /* Init method pointers */
+ s->reset = ofps_reset;
+ s->read = ofps_read;
+ s->stats = ofps_stats;
+ s->del = ofps_del;
+
+ s->gnp = 2 * di + 1 + 2; /* Gamut boundary + inside/outside fake points */
+ /* -1 to -2di-1 are fake boundary nodes indexes, */
+ /* with -2di-1 being the ink limit boundary. */
+ /* -2di-2 is the fake inside node. */
+ /* -2di-3 is the fake outside node. */
+
+ /* Allocate the space for the target number of points */
+ if ((s->_n = (node *)calloc(sizeof(node), s->gnp + s->tinp)) == NULL)
+ error ("ofps: malloc failed on sample nodes");
+ if ((s->n = (node **)calloc(sizeof(node *), s->gnp + s->tinp)) == NULL)
+ error ("ofps: malloc failed on sample nodes");
+ s->n += s->gnp; /* Allow -ve index for fake points */
+ for (i = -s->gnp; i < s->tinp; i++) {
+ int bitp;
+ s->n[i] = &s->_n[i + s->gnp];
+ s->n[i]->ix = i;
+
+ bitp = 31 & (i + (i >> 4) + (i >> 8) + (i >> 12));
+ s->n[i]->ixm = (1 << bitp);
+ }
+
+ s->np = s->fnp = 0;
+
+#ifdef STATS
+ /* Save current counts to report stats after a pass */
+ s->l_positions = s->positions;
+ s->l_nvtxcreated = s->nvtxcreated;
+ s->l_nvtxdeleted = s->nvtxdeleted;
+#endif
+ s->l_mstime = msec_time();
+
+ /* Setup the eperr sorted trees */
+ if ((s->vtreep = aat_anew(vtx_aat_cmp_eperr)) == NULL)
+ error("Allocating aat tree failed");
+
+ /* One sorted tree per number of surface planes */
+ for (e = 0; e <= (di+1); e++) {
+ if ((s->vtrees[e] = aat_anew(vtx_aat_cmp_eserr)) == NULL)
+ error("Allocating aat tree failed");
+ }
+
+#ifdef CACHE_PERCEPTUAL
+ ofps_init_pcache(s);
+# endif /* CACHE_PERCEPTUAL */
+
+ /* Setup spatial acceleration grid */
+ ofps_init_acc1(s);
+
+ /* Initialse the empty veronoi etc. */
+ ofps_binit(s);
+
+ /* Setup spatial acceleration grid (2) */
+ ofps_init_acc2(s);
+
+ /* Setup the fixed points */
+ ofps_setup_fixed(s, fxlist, fxno);
+
+ if (fxno > 0 && tinp <= fxno) { /* There are no moveable points to create */
+
+ /* Add the fixed points */
+ if (ofps_add_fixed(s)) {
+ s->del(s);
+ return NULL;
+ }
+
+ if (s->verb && fxno > 0) {
+ ofps_stats(s);
+ printf("After fixed points: MinPoint = %.3f, Min = %.3f, Avg. = %.3f, Max = %.3f\n",s->smns,s->mn,s->av,s->mx);
+ }
+ }
+
+ if (tinp > fxno) { /* There are movable points to create */
+
+ /* Add the fixed points and create the moveable points */
+ ofps_seed(s);
+ ofps_re_create_node_node_vtx_lists(s);
+ ofps_create_mids(s);
+
+ ofps_stats(s);
+ if (s->verb) {
+ printf("After seeding points: MinPoint = %.3f, Min = %.3f, Avg. = %.3f, Max = %.3f, %.1f secs\n",s->smns,s->mn,s->av,s->mx,(msec_time() - s->l_mstime) / 1000.0);
+
+#ifdef STATS
+ printf("Current vtx %d, created %d, deleted %d, positioned %d\n", s->nv,s->nvtxcreated - s->l_nvtxcreated,s->nvtxdeleted - s->l_nvtxdeleted, s->positions - s->l_positions);
+ s->l_positions = s->positions;
+ s->l_nvtxcreated = s->nvtxcreated;
+ s->l_nvtxdeleted = s->nvtxdeleted;
+#endif
+ s->l_mstime = msec_time();
+ }
+# ifdef DUMP_STRUCTURE
+ printf("After seeding:\n");
+ dump_node_vtxs(s, 1);
+// dump_node_vtxs2(s, "After seeding");
+#else /* !DUMP_STRUCTURE */
+#ifdef SANITY_CHECK_CONSISTENCY
+ sanity_check(s, 1);
+#endif
+#endif /* !DUMP_STRUCTURE */
+#ifdef DUMP_PLOT
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 1, -1); /* Device, No wait, no verticies */
+#endif /* DUMP_PLOT */
+
+#ifdef DOOPT
+ /* Do the optimization */
+ ofps_optimize(s);
+#endif /* DOOPT */
+
+# ifdef DUMP_STRUCTURE
+ printf("After optimization:\n");
+ dump_node_vtxs(s, 1);
+// dump_node_vtxs2(s, "After optimization");
+#else /* !DUMP_STRUCTURE */
+#ifdef SANITY_CHECK_CONSISTENCY
+ sanity_check(s, 1);
+#endif
+#endif /* !DUMP_STRUCTURE */
+ ofps_stats(s);
+ if (s->verb)
+ printf("After optimization: MinPoint = %.3f, Min = %.3f, Avg. = %.3f, Max = %.3f\n",s->smns, s->mn,s->av,s->mx);
+#ifdef DUMP_PLOT
+ dump_image(s, PERC_PLOT, DO_WAIT, DUMP_VTX, DUMP_PLA, 1, -1); /* Device, wait, verticies */
+#endif /* DUMP_PLOT */
+ }
+
+ ofps_reset(s); /* Reset read index */
+
+#if defined(DEBUG) || defined(STATS)
+ {
+ vtx *vx;
+ int novtx = 0;
+ int totvtxverts = 0;
+ int maxvtxverts = 0;
+ vtx **svtxs; /* Sorted vertexes by number of vertexes */
+
+ ttime = clock() - stime;
+ printf("Execution time = %f seconds\n",ttime/(double)CLOCKS_PER_SEC);
+
+ /* Look at the vertexes */
+ for (novtx = 0, vx = s->uvtx; vx != NULL; vx = vx->link, novtx++)
+ ;
+
+ if ((svtxs = (vtx **)malloc(sizeof(vtx *) * novtx)) == NULL)
+ error ("ofps: malloc failed on vertex pointer list");
+
+ /* Look at the vertexes */
+ for (novtx = 0, vx = s->uvtx; vx != NULL; vx = vx->link, novtx++) {
+
+ svtxs[novtx] = vx;
+
+ totvtxverts += vx->nnv;
+ if (vx->nnv > maxvtxverts)
+ maxvtxverts = vx->nnv;
+ }
+
+#define HEAP_COMPARE(A,B) ((A)->nnv > (B)->nnv)
+ HEAPSORT(vtx *, svtxs, novtx);
+#undef HEAP_COMPARE
+
+// printf("Top 20 vertexes per vertex:\n");
+// for (i = 0; i < 20 && i < novtx; i++) {
+// printf(" Vtx no %d, no vtxs = %d\n",svtxs[i]->no,svtxs[i]->nnv);
+// }
+
+ fprintf(stderr,"Average vertexes per vertex %.1f, max %d\n",totvtxverts/(double)novtx,maxvtxverts);
+ fprintf(stderr,"Average hit vertexes per add %.1f\n",s->nhitv/(double)s->nsurfadds,s->maxhitv);
+ fprintf(stderr,"Total number of vertex = %d\n",novtx);
+ fprintf(stderr,"Total vertex positions = %d\n",s->positions);
+ fprintf(stderr,"Total dnsqs = %d\n",s->dnsqs);
+ fprintf(stderr,"Total function calls = %d\n",s->funccount);
+ fprintf(stderr,"Average dnsqs/position = %.2f\n",s->dnsqs/(double)s->positions);
+ fprintf(stderr,"Average function calls/dnsq = %.1f\n",s->funccount/(double)s->dnsqs);
+ fprintf(stderr,"Maximum function calls/dnsq = %d\n",s->maxfunc);
+ fprintf(stderr,"Average function calls/sucessful dnsq = %.2f\n",s->sucfunc/(double)s->sucdnsq);
+ fprintf(stderr,"Average function calls/position = %.1f\n",s->funccount/(double)s->positions);
+ fprintf(stderr,"Maximum tries for dnsq sucess %d\n",s->maxretries);
+ fprintf(stderr,"Number of position_vtx failures %d\n",s->posfails);
+ fprintf(stderr,"Vertex hit check efficiency = %.1f%%\n",100.0 * (1.0 - s->vvchecks/(double)s->vvpchecks));
+ fprintf(stderr,"Average accell cells searched = %.2f\n",s->ncellssch/(double)s->naccsrch);
+ fprintf(stderr,"add_to_vsurf hit rate = %.1f%%\n",100.0 * s->add_hit/(s->add_hit + s->add_mis));
+#ifdef DOOPT
+ fprintf(stderr,"fixup add_to_vsurf hit rate = %.1f%%\n",100.0 * s->fadd_hit/(s->fadd_hit + s->fadd_mis));
+ fprintf(stderr,"Vertex closest search efficiency = %.1f%%\n",100.0 * (1.0 - s->nvschd/(double)s->nvfschd));
+ fprintf(stderr,"Node closest search efficiency = %.1f%%\n",100.0 * (1.0 - s->nnschd/(double)s->nnfschd));
+#endif
+
+ free(svtxs);
+ }
+#endif
+
+ return s;
+}
+
+/* =================================================== */
+
+#ifdef STANDALONE_TEST
+
+/* Graphics Gems curve */
+static double gcurve(double vv, double g) {
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ return vv;
+}
+
+
+static void sa_percept(void *od, double *p, double *d) {
+ double dd[2];
+
+ /* Default linear */
+ p[0] = 100.0 * (dd[0] = d[0]);
+ p[1] = 100.0 * (dd[1] = d[1]);
+
+ /* Normal non-linear test */
+// p[0] = 100.0 * gcurve(dd[0], -8.0);
+// p[1] = 100.0 * gcurve(dd[1], 4.0);
+
+ /* More extreme non-linear test */
+ p[0] = 100.0 * gcurve(dd[0], -16.0);
+ p[1] = 100.0 * gcurve(dd[1], 8.0);
+
+ /* An X break point to test curvature weighting */
+// if (dd[0] < 0.5)
+// p[0] = 100.0 * 0.6 * dd[0];
+// else
+// p[0] = 100.0 * (0.3 + 1.4 * (dd[0] - 0.5));
+// p[1] = 100.0 * dd[1];
+
+// if (dd[0] < 0.0)
+// dd[0] = 0.0;
+// if (dd[1] < 0.0)
+// dd[1] = 0.0;
+// p[0] = 100.0 * pow(dd[0], 0.5);
+// p[1] = 100.0 * pow(dd[1], 1.0);
+// p[1] = 0.8 * p[1] + 0.2 * p[0];
+
+ /* One that causes dnsq failures due to ACCELL failure */
+// p[0] = gcurve(dd[0], -4.0);
+// p[1] = gcurve(dd[1], 2.0);
+// p[0] = 100.0 * gcurve(0.6 * p[0] + 0.4 * p[1], 2.0);
+// p[1] = 100.0 * gcurve(0.1 * p[1] + 0.9 * p[1], -4.0);
+
+// p[0] = 100.0 * dd[0] * dd[0];
+// p[1] = 100.0 * dd[1] * dd[1];
+}
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int npoints = 55;
+ int ntostop = 0;
+ int nopstop = 0;
+ ofps *s;
+ fxpos fx[4]; /* Any fixed points */
+ int nfx = 0;
+
+ error_program = argv[0];
+
+ printf("Standalone test of ofps, args are: no. of points, default %d, points to skip before diag. plots, optim passes to skip\n",npoints);
+
+ if (argc > 1)
+ npoints = atoi(argv[1]);
+
+ if (argc > 2)
+ ntostop = atoi(argv[2]);
+
+ if (argc > 3)
+ nopstop = atoi(argv[3]);
+
+ fx[0].p[0] = 0.5;
+ fx[0].p[1] = 0.5;
+
+ fx[1].p[0] = 0.145722;
+ fx[1].p[1] = 0.0;
+
+ fx[2].p[0] = 1.0;
+ fx[2].p[1] = 0.104414;
+
+ nfx = 0;
+
+ /* Create the required points */
+ s = new_ofps_ex(1, 2, 1.5, NULL, NULL, npoints, 1,
+// s = new_ofps_ex(1, 2, 2.5, NULL, NULL, npoints, 1,
+ SA_ADAPT, SA_DEVD_MULT, SA_PERC_MULT, SA_INTERP_MULT,
+ fx, nfx, sa_percept, (void *)NULL, ntostop, nopstop);
+
+#ifdef DUMP_PLOT
+ printf("Device plot (with verts):\n");
+ dump_image(s, 0, DO_WAIT, 1, DUMP_PLA, 1, -1);
+ printf("Device plot:\n");
+ dump_image(s, 0, DO_WAIT, 0, 0, 1, -1);
+ printf("Perceptual plot (with verts):\n");
+ dump_image(s, 1, DO_WAIT, 1, DUMP_PLA, 1, -1);
+ printf("Perceptual plot:\n");
+ dump_image(s, 1, DO_WAIT, 0, 0, 1, -1);
+#endif /* DUMP_PLOT */
+
+ s->del(s);
+
+ return 0;
+}
+
+#endif /* STANDALONE_TEST */
+
+#define WIDTH 400 /* Raster size for debug plots */
+#define HEIGHT 400
+
+/* Utility - return a string containing the di coord */
+static char *pco(int di, int *co) {
+ static char buf[5][200];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ for (e = 0; e < di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%d", co[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Utility - return a string containing the di vector */
+static char *ppos(int di, double *p) {
+ static char buf[5][200];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ for (e = 0; e < di; e++) {
+ double val = p[e];
+ /* Make -0.00000000 turn into 0.000 for cosmetics */
+ if (val < 0.0 && val >-1e-9)
+ val = 0.0;
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%f", val); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Utility - return a string containing the di+1 combination */
+static char *pcomb(int di, int *n) {
+ static char buf[5][200];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ for (e = 0; e <= di; e++) {
+ if (e > 0)
+ *bp++ = ' ';
+ sprintf(bp, "%d", n[e]); bp += strlen(bp);
+ }
+ return buf[ix];
+}
+
+/* Utility - return a string containing the eperr/eserr value */
+static char *peperr(double eperr) {
+ static char buf[5][200];
+ static int ix = 0;
+ int e;
+ char *bp;
+
+ if (++ix >= 5)
+ ix = 0;
+ bp = buf[ix];
+
+ if (eperr >= 1e50)
+ sprintf(bp,"%s", "Big");
+ else
+ sprintf(bp,"%f",eperr);
+ return buf[ix];
+}
+
+/* --------------------------------------------------------------- */
+#if defined(DEBUG) || defined(DUMP_PLOT_SEED) || defined(DUMP_PLOT)
+
+/* Dump the current point positions to a plot window file */
+static void
+dump_image(
+ ofps *s,
+ int pcp, /* Do perceptual plot */
+ int dwt, /* Do wait for a key */
+ int dvx, /* Dump voronoi verticies and mid points */
+ int dpla, /* Dump node planes */
+ int ferr, /* Show final error rather than seeding error */
+ int noi /* -1 for general state, node of interest for particular */
+) {
+ int i, j, k, e, di = s->di;
+ double minx, miny, maxx, maxy;
+ static double *x1a = NULL; /* Previous sample locations */
+ static double *y1a = NULL;
+ static double *x2a = NULL; /* Current sample locations */
+ static double *y2a = NULL;
+ static char *_ntext, **ntext;
+ static int _n3 = 0; /* Current Voronoi verticies */
+ static double *x3a = NULL;
+ static double *y3a = NULL;
+ static plot_col *mcols = NULL;
+ static char *_mtext, **mtext;
+ int n3;
+ static double *x4a = NULL; /* plane vectors */
+ static double *y4a = NULL;
+ static double *x5a = NULL;
+ static double *y5a = NULL;
+ static plot_col *ocols = NULL;
+ static int _o4 = 0;
+ int o4;
+
+ if (pcp != 0) { /* Perceptual range */
+ vtx *vx;
+ minx = miny = 1e60;
+ maxx = maxy = -1e60;
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ double v[MXPD];
+
+ if (vx->v[0] < minx)
+ minx = vx->v[0];
+ if (vx->v[1] < miny)
+ miny = vx->v[1];
+ if (vx->v[0] > maxx)
+ maxx = vx->v[0];
+ if (vx->v[1] > maxy)
+ maxy = vx->v[1];
+ }
+ } else {
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 1.0;
+ maxy = 1.0;
+ }
+
+#ifdef NEVER
+ /* Expand the range a little */
+ minx -= 0.1 * (maxx - minx);
+ maxx += 0.1/1.1 * (maxx - minx);
+ miny -= 0.1 * (maxy - miny);
+ maxy += 0.1/1.1 * (maxy - miny);
+#endif
+
+ if (x1a == NULL) {
+ if ((x1a = (double *)malloc(s->tinp * sizeof(double))) == NULL)
+ error ("ofps: malloc failed x1a");
+ if ((y1a = (double *)malloc(s->tinp * sizeof(double))) == NULL)
+ error ("ofps: malloc failed ya1");
+ if ((x2a = (double *)malloc(s->tinp * sizeof(double))) == NULL)
+ error ("ofps: malloc failed x2a");
+ if ((y2a = (double *)malloc(s->tinp * sizeof(double))) == NULL)
+ error ("ofps: malloc failed y2a");
+ if ((_ntext = (char *)malloc(s->tinp * 10 * sizeof(char))) == NULL)
+ error ("ofps: malloc failed _ntext");
+ if ((ntext = (char **)malloc(s->tinp * sizeof(char *))) == NULL)
+ error ("ofps: malloc failed ntext");
+ for (i = 0; i < s->tinp; i++)
+ ntext[i] = _ntext + i * 10;
+ }
+
+ /* Add sample node location */
+ for (i = 0; i < s->np; i++) {
+ node *p = s->n[i];
+
+ if (pcp != 0) {
+ double ov[MXPD];
+ ofps_cc_percept(s, ov, p->op);
+ x1a[i] = ov[0];
+ y1a[i] = ov[1];
+ x2a[i] = p->v[0];
+ y2a[i] = p->v[1];
+ } else {
+ x1a[i] = p->op[0];
+ y1a[i] = p->op[1];
+ x2a[i] = p->p[0];
+ y2a[i] = p->p[1];
+ }
+ sprintf(ntext[i],"%d",p->ix);
+// sprintf(ntext[i],"",p->ix);
+ }
+
+ if (dvx) {
+ vtx *vx;
+ mid *mp;
+ node *p = NULL;
+// double rgb0[3] = { 0.0, 0.5, 0.5 }; /* "cool" */
+// double rgb1[3] = { 1.0, 0.5, 0.0 }; /* "warm" */
+ double rgb0[3] = { 0.0, 1.0, 0.0 }; /* "cool" */
+ double rgb1[3] = { 1.0, 0.0, 0.5 }; /* "warm" */
+ double mine, maxe; /* Min and max vertex eserr */
+
+ if (noi >= 0)
+ p = s->n[noi];
+
+ if (x3a == NULL) { /* Initial allocation */
+ _n3 = s->np * 4;
+ if ((x3a = (double *)malloc(_n3 * sizeof(double))) == NULL)
+ error ("ofps: malloc failed x3a");
+ if ((y3a = (double *)malloc(_n3 * sizeof(double))) == NULL)
+ error ("ofps: malloc failed y3a");
+ if ((mcols = (plot_col *)malloc(_n3 * sizeof(plot_col))) == NULL)
+ error ("ofps: malloc failed mcols");
+ if ((_mtext = (char *)malloc(_n3 * 10 * sizeof(char))) == NULL)
+ error ("ofps: malloc failed _mtext");
+ if ((mtext = (char **)malloc(_n3 * sizeof(char *))) == NULL)
+ error ("ofps: malloc failed mtext");
+ for (i = 0; i < _n3; i++)
+ mtext[i] = _mtext + i * 10;
+ }
+
+ /* Compute min & max serr for each vertex */
+ mine = 1e6;
+ maxe = -1e6;
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ if (vx->ghost)
+ continue;
+ if (vx->eserr > maxe)
+ maxe = vx->eserr;
+ if (vx->eserr > NUMTOL && vx->eserr < mine)
+ mine = vx->eserr;
+ }
+ if ((maxe - mine) < 10.0)
+ maxe = mine + 1.0;
+
+ /* Add mid points */
+ for (n3 = 0, mp = s->umid; mp != NULL; mp = mp->link, n3++) {
+
+ if (n3 >= _n3) { /* need more space */
+ _n3 = 2 * _n3 + 5;
+ if ((x3a = (double *)realloc(x3a, _n3 * sizeof(double))) == NULL)
+ error ("ofps: realloc failed x3a %d",_n3);
+ if ((y3a = (double *)realloc(y3a, _n3 * sizeof(double))) == NULL)
+ error ("ofps: realloc failed y3a");
+ if ((mcols = (plot_col *)realloc(mcols, _n3 * sizeof(plot_col))) == NULL)
+ error ("ofps: realloc failed mcols");
+ if ((_mtext = (char *)realloc(_mtext, _n3 * 10 * sizeof(char))) == NULL)
+ error ("ofps: realloc failed _mtext");
+ if ((mtext = (char **)realloc(mtext, _n3 * sizeof(char *))) == NULL)
+ error ("ofps: realloc failed mtest");
+ for (i = 0; i < _n3; i++)
+ mtext[i] = _mtext + i * 10;
+ }
+ if (pcp != 0) {
+ x3a[n3] = mp->v[0];
+ y3a[n3] = mp->v[1];
+ } else {
+ x3a[n3] = mp->p[0];
+ y3a[n3] = mp->p[1];
+ }
+
+ /* Show mid points in grey */
+ mcols[n3].rgb[0] = 0.85;
+ mcols[n3].rgb[1] = 0.85;
+ mcols[n3].rgb[2] = 0.85;
+
+ sprintf(mtext[n3],"");
+ sprintf(mtext[n3],"%d",mp->no);
+// sprintf(mtext[n3],"%d",(int)(mp->eserr + 0.5));
+ }
+
+ /* Add Voronoi verticies */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link, n3++) {
+
+ if (n3 >= _n3) { /* need more space */
+ _n3 = _n3 * 2 + 5;
+ if ((x3a = (double *)realloc(x3a, _n3 * sizeof(double))) == NULL)
+ error ("ofps: realloc failed x3a %d",_n3);
+ if ((y3a = (double *)realloc(y3a, _n3 * sizeof(double))) == NULL)
+ error ("ofps: realloc failed y3a");
+ if ((mcols = (plot_col *)realloc(mcols, _n3 * sizeof(plot_col))) == NULL)
+ error ("ofps: realloc failed mcols");
+ if ((_mtext = (char *)realloc(_mtext, _n3 * 10 * sizeof(char))) == NULL)
+ error ("ofps: realloc failed _mtext");
+ if ((mtext = (char **)realloc(mtext, _n3 * sizeof(char *))) == NULL)
+ error ("ofps: realloc failed mtext");
+ for (i = 0; i < _n3; i++)
+ mtext[i] = _mtext + i * 10;
+ }
+ if (pcp != 0) {
+ x3a[n3] = vx->v[0];
+ y3a[n3] = vx->v[1];
+ } else {
+ x3a[n3] = vx->p[0];
+ y3a[n3] = vx->p[1];
+ }
+
+ /* Show the vertexes as warm to cold, depending on their eserr */
+ if (p == NULL) {
+ double bf;
+
+ bf = (vx->eserr - mine)/(maxe - mine);
+ if (bf < 0.0)
+ bf = 0.0;
+ if (bf > 1.0)
+ bf = 1.0;
+
+ for (e = 0; e < 3; e++)
+ mcols[n3].rgb[e] = bf * rgb1[e] + (1.0 - bf) * rgb0[e];
+
+//printf("~1 serr = %f, color = %f %f %f\n",vx->eserr, mcols[n3].rgb[0], mcols[n3].rgb[1], mcols[n3].rgb[2]);
+// sprintf(mtext[n3],"");
+// sprintf(mtext[n3],"%d",(int)(vx->eserr + 0.5));
+
+#ifndef NEVER /* Vertex no */
+ sprintf(mtext[n3],"%d",vx->no);
+#endif
+
+#ifdef NEVER /* Vertex no and eserr */
+ if (vx->eserr >= 1e50)
+ sprintf(mtext[n3],"%d:Big",vx->no);
+ else
+ sprintf(mtext[n3],"%d:%d",vx->no,(int)(vx->eserr + 0.5));
+#endif
+
+#ifdef NEVER /* eserr */
+ if (vx->eserr >= 1e50)
+ sprintf(mtext[n3],"Big");
+ else
+ sprintf(mtext[n3],"%d",(int)(vx->eserr + 0.5));
+#endif
+
+ /* Highlight the vertcies of interest */
+ } else {
+ for (j = 0; j < p->nvv; j++) {
+ if (p->vv[j] == vx)
+ break;
+ }
+ if (j < p->nvv) { /* Vertex associated with node of interest */
+ mcols[n3].rgb[0] = 0.1;
+ mcols[n3].rgb[1] = 0.9;
+ mcols[n3].rgb[2] = 0.9;
+
+ sprintf(mtext[n3],"%d",(int)(vx->eserr + 0.5));
+
+ } else {
+ mcols[n3].rgb[0] = 0.82; /* default color */
+ mcols[n3].rgb[1] = 0.59;
+ mcols[n3].rgb[2] = 0.0;
+
+ sprintf(mtext[n3],"");
+ }
+ }
+ }
+#ifdef DUMP_EPERR /* Create .tiff of eperr */
+ if (s->np >= s->ntostop) {
+
+ unsigned char pa[WIDTH * 3];
+ char *name = "ofps.tif";
+ int width = WIDTH;
+ int height = HEIGHT;
+ int x, y;
+ TIFF *tif;
+ double pos[MXPD], vpos[MXPD];
+ double rgb_low[3] = { 0.0, 1.0, 0.0 }; /* "low error" */
+ double rgb_high[3] = { 1.0, 0.0, 0.0 }; /* "high error" */
+
+ if ((tif = TIFFOpen(name, "w")) == NULL) {
+ fprintf(stderr,"Failed to open output TIFF file '%s'\n",name);
+ exit (-1);
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+
+ mine = 0.0;
+
+ for (y = 0; y < height; y++) {
+ pos[1] = 1.0 - y/(height-1.0);
+
+ /* Fill in pa[] with colors for this line */
+ for (x = 0; x < width; x++) {
+ double ss;
+ unsigned char *dp;
+ double bf;
+ double beserr, eserr;
+
+ dp = pa + x * 3;
+ pos[0] = x/(width-1.0);
+ dp[0] = dp[1] = dp[2] = 0;
+//printf("~1 doing %d %d pos %f %f\n",x,y,pos[0],pos[1]);
+
+ /* Lookup perceptual value at sample point location */
+ ofps_cc_percept(s, vpos, pos);
+
+ /* See if the sample is in gamut */
+ for (ss = 0.0, e = 0; e < s->di; e++) {
+ if (pos[e] < s->imin[e]
+ || pos[e] > s->imax[e])
+ break;
+ ss += pos[e];
+ }
+ if (e < s->di || ss > (s->ilimit + ILIMITEPS)) {
+//printf("~1 out of gamut\n");
+ continue;
+ }
+
+ /* We determine the eserr by evaluating eserr for */
+ /* every node, and keeping the smallest. */
+ /* (This could be speeded up by using nearest search function) */
+ beserr = 1e80;
+ for (i = 0; i < s->np; i++) {
+ node *np = s->n[i];
+
+ eserr = ofps_comp_eperr9(s, NULL, vpos, pos, np->v, np->p);
+ if (eserr < beserr)
+ beserr = eserr;
+ }
+ bf = (beserr - mine)/(maxe - mine);
+//printf("~1 beserr = %f, bf = %f\n",beserr,bf);
+ if (bf < 0.0)
+ bf = 0.0;
+ if (bf > 1.0)
+ bf = 1.0;
+
+ for (e = 0; e < 3; e++)
+ dp[e] = (int)(255.0 * (bf * rgb_high[e] + (1.0 - bf) * rgb_low[e]) + 0.5);
+
+ }
+ if (TIFFWriteScanline(tif, (tdata_t)pa, y, 0) < 0) {
+ fprintf(stderr,"WriteScanline Failed at line %d\n",y);
+ exit (-1);
+ }
+ }
+ (void) TIFFClose(tif);
+ }
+#endif /* DUMP_EPERR */
+ }
+
+ /* Show veronoi planes by plotting the vertex network */
+ if (dpla) {
+ vtx *vx1, *vx2;
+
+ if (x4a == NULL) {
+ _o4 = s->tinp;
+ if ((x4a = (double *)malloc(_o4 * sizeof(double))) == NULL)
+ error ("ofps: malloc %d failed",_o4);
+ if ((y4a = (double *)malloc(_o4 * sizeof(double))) == NULL)
+ error ("ofps: malloc %d failed",_o4);
+ if ((x5a = (double *)malloc(_o4 * sizeof(double))) == NULL)
+ error ("ofps: malloc %d failed",_o4);
+ if ((y5a = (double *)malloc(_o4 * sizeof(double))) == NULL)
+ error ("ofps: malloc %d failed",_o4);
+ if ((ocols = (plot_col *)malloc(_o4 * sizeof(plot_col))) == NULL)
+ error ("ofps: malloc %d failed",_o4);
+ }
+
+ /* Add normal planes then subd planes, so that subd are always on top */
+ o4 = 0;
+#ifdef INDEP_SURFACE
+ for (k = 0; k < 2; k++) /* Do two passes */
+#else
+ for (k = 0; k < 1; k++)
+#endif
+ {
+ /* Add node planes */
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link) {
+
+ /* Don't plot faces involving the fake inside or outside node */
+ for (e = 0; e <= di; e++) {
+ if (vx1->nix[e] < -s->nbp)
+ break;
+ }
+ if (e <= di)
+ continue;
+
+ for (j = 0; j < vx1->nnv; j++) {
+ vx2 = vx1->nv[j];
+
+ /* Don't plot faces involving the fake inside or outside node */
+ for (e = 0; e <= di; e++) {
+ if (vx2->nix[e] < -s->nbp)
+ break;
+ }
+ if (e <= di)
+ continue;
+
+#ifdef INDEP_SURFACE
+ if (sm_andtest(s, &vx1->vm, &s->sc[0].a_sm) == 0
+ || sm_andtest(s, &vx2->vm, &s->sc[0].a_sm) == 0) { /* Subd plane */
+ if (k == 0)
+ continue; /* Doing non-zubd pass */
+ } else {
+ if (k == 1)
+ continue; /* Doing subd pass */
+ }
+#endif
+
+ if (o4 >= _o4) { /* need more space */
+ _o4 *= 2;
+ if ((x4a = (double *)realloc(x4a, _o4 * sizeof(double))) == NULL)
+ error ("ofps: realloc x4a %d failed", _o4);
+ if ((y4a = (double *)realloc(y4a, _o4 * sizeof(double))) == NULL)
+ error ("ofps: realloc y4a %d failed", _o4);
+ if ((x5a = (double *)realloc(x5a, _o4 * sizeof(double))) == NULL)
+ error ("ofps: realloc x5a %d failed", _o4);
+ if ((y5a = (double *)realloc(y5a, _o4 * sizeof(double))) == NULL)
+ error ("ofps: realloc y5a %d failed", _o4);
+ if ((ocols = (plot_col *)realloc(ocols, _o4 * sizeof(plot_col))) == NULL)
+ error ("ofps: realloc y5a %d failed", _o4);
+ }
+
+ if (pcp != 0) {
+ x4a[o4] = vx1->v[0];
+ y4a[o4] = vx1->v[1];
+ x5a[o4] = vx2->v[0];
+ y5a[o4] = vx2->v[1];
+ } else {
+ x4a[o4] = vx1->p[0];
+ y4a[o4] = vx1->p[1];
+ x5a[o4] = vx2->p[0];
+ y5a[o4] = vx2->p[1];
+ }
+
+#ifdef INDEP_SURFACE
+ /* Show the sub dimension outline in apricot */
+ if (k == 1) {
+ ocols[o4].rgb[0] = 1.0; /* Apricot */
+ ocols[o4].rgb[1] = 0.52;
+ ocols[o4].rgb[2] = 0.57;
+ } else
+#endif
+ {
+ ocols[o4].rgb[0] = 0.5; /* Light Blue */
+ ocols[o4].rgb[1] = 0.9;
+ ocols[o4].rgb[2] = 0.9;
+ }
+ o4++;
+ }
+ }
+ }
+ }
+
+ if ((s->nopstop >= 0 && s->optit < s->nopstop) || s->np < s->ntostop)
+ dwt = 0;
+
+ /* Plot the vectors */
+ do_plot_vec2(minx, maxx, miny, maxy,
+ x1a, y1a, x2a, y2a, ntext, s->np, dwt,
+ x3a, y3a, mcols, mtext, dvx ? n3 : 0,
+ x4a, y4a, x5a, y5a, ocols, dpla ? o4 : 0);
+
+}
+
+#endif /* DEBUG || DUMP_PLOT */
+
+/* ------------------------------------------------------------------- */
+#ifdef SANITY_RESEED_AFTER_FIXUPS
+
+/* Save the current used vertexes to the i_uvtx list, */
+/* so that they can be verified against the re-seeded vertexes */
+static void save_ivertexes(ofps *s) {
+ vtx *vx, *nvx;
+
+ s->i_uvtx = NULL;
+
+ for (vx = s->uvtx; vx != NULL; vx = nvx) {
+ nvx = vx->link;
+
+ /* Remove the vertex from used and other lists */
+ del_vtx1(s, vx);
+
+ /* Add it to the i_uvtx list */
+ vx->link = s->i_uvtx;
+ s->i_uvtx = vx;
+ }
+}
+
+/* Check the incremental vertexes against the re-seeded vertexes */
+static int check_vertexes(ofps *s) {
+ int i, j, e, k, di = s->di;
+ vtx *v1, *v2;
+ int fail = 0;
+
+ printf("Verifying incremental vertexes against re-seeded:\n");
+
+ /* For each reference (re-seeded) vertex */
+ for (v1 = s->uvtx; v1 != NULL; v1 = v1->link) {
+
+ /* Locate the equivalent incremental vertex */
+ for (v2 = s->i_uvtx; v2 != NULL; v2 = v2->link) {
+ for (e = 0; e <= di; e++) {
+ if (v1->nix[e] != v2->nix[e])
+ break;
+ }
+ if (e > di)
+ break; /* Found it */
+ }
+ if (v2 == NULL) {
+ printf("Missing vertex no %d comb %s\n",v1->no,pcomb(di,v1->nix));
+ fail = 1;
+ continue;
+ }
+
+ /* Check the vertex location */
+ for (e = 0; e < di; e++) {
+ if (fabs(v1->p[e] - v2->p[e]) > 1e-5) {
+ break;
+ }
+ }
+ if (e < di) {
+ printf("Vertex no %d (%d) comb %s in different location %s, should be %s\n",v1->no,v2->no,pcomb(di,v1->nix),ppos(di,v2->p),ppos(di,v1->p));
+ fail = 1;
+ }
+ /* Check the eserr */
+ if (fabs(v1->eserr - v2->eserr) > 1e-3) {
+ printf("Vertex no %d (%d) comb %s has different eserr %f, should be %f\n",v1->no,v2->no,pcomb(di,v1->nix),v2->eserr,v1->eserr);
+ fail = 1;
+ }
+
+ /* Check setmask */
+ if (!_sm_equal(s, &v1->vm, &v2->vm)) {
+ printf("Vertex no %d (%d) comb %s has different vm %s, should be %s\n",v1->no,v2->no,pcomb(di,v1->nix),psm(s,&v2->vm),psm(s,&v1->vm));
+ fail = 1;
+ }
+
+ /* Check that the vertex nets are the same */
+ for (i = 0; i < v1->nnv; i++) {
+ vtx *vv1 = v1->nv[i];
+
+ for (j = 0; j < v2->nnv; j++) {
+ vtx *vv2 = v2->nv[j];
+
+ for (e = 0; e <= di; e++) {
+ if (vv1->nix[e] != vv2->nix[e])
+ break;
+ }
+ if (e > di)
+ break; /* Found it */
+ }
+ if (j >= v2->nnv) {
+ printf("Vertex no %d comb %s, i_ missing neighbour no %d comb %s\n",v1->no,pcomb(di,v1->nix),vv1->no,pcomb(di,vv1->nix));
+ fail = 1;
+ }
+ }
+ for (j = 0; j < v2->nnv; j++) {
+ vtx *vv2 = v2->nv[j];
+
+ for (i = 0; i < v1->nnv; i++) {
+ vtx *vv1 = v1->nv[i];
+
+ for (e = 0; e <= di; e++) {
+ if (vv1->nix[e] != vv2->nix[e])
+ break;
+ }
+ if (e > di)
+ break; /* Found it */
+ }
+ if (i >= v1->nnv) {
+ printf("Vertex no %d comb %s, i_ extra neighbour no (%d) comb %s\n",v1->no,pcomb(di,v1->nix),vv2->no,pcomb(di,vv2->nix));
+ fail = 1;
+ }
+ }
+ }
+
+ /* For each incremental vertex, check that there is a corresponding re-seeded vertex */
+ for (v2 = s->i_uvtx; v2 != NULL; v2 = v2->link) {
+
+ for (v1 = s->uvtx; v1 != NULL; v1 = v1->link) {
+ for (e = 0; e <= di; e++) {
+ if (v1->nix[e] != v2->nix[e])
+ break;
+ }
+ if (e > di)
+ break; /* Found it */
+ }
+ if (v1 == NULL) {
+ printf("Extra vertex no (%d) comb %s\n",v2->no,pcomb(di,v2->nix));
+ fail = 1;
+ }
+ }
+
+ if (fail)
+ printf("Failed to verify incremental vertexes against re-seeded:\n");
+ else
+ printf("Successfully verified incremental vertexes against re-seeded\n");
+
+ return fail;
+}
+
+#endif /* SANITY_RESEED_AFTER_FIXUPS */
+
+/* ------------------------------------------------------------------- */
+/* Do an exaustive, very slow check for missing vertexes */
+/*
+ This may be really, really, really slow.
+
+ For every possible combination of di+1 nodes,
+ locate the corresponding vertex. If it is
+ locatable, check that no other node is closer to it.
+ If it meets these conditions, then check that it is in the veronoi surface.
+ */
+static void check_for_missing_vertexes(ofps *s) {
+ int e, di = s->di;
+ vtx *vx;
+ COMBO(co, MXPD+1, di+1, s->np + s->nbp); /* di-1 out of neighbor nodes combination counter */
+ nodecomb vv;
+ int lsc = -100;
+ int isok = 1;
+
+ printf("Doing exaustive check for missing vertexes:\n");
+
+ /* Mark all the vertexes so that we can tell if any are missed. */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ vx->sch = 0;
+ }
+
+ CB_INIT(co);
+ while (!CB_DONE(co)) {
+ int rl = 0;
+
+ memset((void *)&vv, 0, sizeof(nodecomb));
+ for (e = 0; e <= di; e++) {
+ vv.nix[e] = co[e] - s->nbp;
+ if (vv.nix[e] >= 0)
+ rl = 1;
+ }
+ if (rl == 0)
+ goto next_comb; /* No real nodes */
+
+ vv.vv = NULL;
+ vv.ceperr = 1e100;
+
+ sort_nix(s, vv.nix);
+
+ printf("Comb %s\n",pcomb(di, vv.nix));
+ if (lsc != vv.nix[di]) {
+ fprintf(stderr,"digit %d\n",vv.nix[di]);
+ lsc = vv.nix[di];
+ }
+
+ if (position_vtx(s, &vv, 0, 0, 0) == 0) {
+ int ix;
+ double eperr;
+ node *nn;
+
+ printf(" Located at %s (%s), eperr %f\n",ppos(di,vv.p),ppos(di,vv.v),vv.eperr);
+
+ /* Check that the point is not out of gamut */
+ if (ofps_in_dev_gamut(s, vv.p, NULL) < -s->surftol) {
+ printf(" vertex is out of gamut\n");
+ goto not_valid;
+ }
+
+ /* Check that no other vertex is closer */
+ for (ix = 0; ix < s->np; ix++) {
+ for (e = 0; e <= di; e++) {
+ if (vv.nix[e] == ix)
+ break;
+ }
+ if (e <= di)
+ continue; /* Is a parent */
+
+ nn = s->n[ix];
+ eperr = ofps_comp_eperr(s, NULL, nn->v, nn->p, vv.v, vv.p);
+
+ printf(" eperr to ix %d is %f\n",nn->ix,eperr);
+ if (eperr < vv.eperr) {
+ printf("vertex is closer to node ix %d\n",nn->ix);
+ break;
+ }
+ }
+ if (ix >= s->np) {
+
+ printf("Point %s is valid\n",pcomb(di,vv.nix));
+
+ /* see if we've created it */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+
+ for (e = 0; e <= di; e++) {
+ if (vx->nix[e] != vv.nix[e])
+ break;
+ }
+ if (e > di)
+ break; /* Found it */
+ }
+ if (vx == NULL) {
+ printf("Can't find vertex %s at %s (%s)\n",pcomb(di,vv.nix),ppos(di,vv.p),ppos(di,vv.v));
+ fprintf(stderr,"Can't find vertex %s at %s (%s)\n",pcomb(di,vv.nix),ppos(di,vv.p),ppos(di,vv.v));
+ isok = 0;
+ } else {
+ vx->sch = 1;
+ printf("Found vertex no %d nix %s at %s (%s) OK\n",vx->no,pcomb(di,vv.nix),ppos(di,vv.p),ppos(di,vv.v));
+ fprintf(stderr,"Found vertex no %d nix %s at %s (%s) OK\n",vx->no,pcomb(di,vv.nix),ppos(di,vv.p),ppos(di,vv.v));
+ }
+ }
+ not_valid:;
+ } else {
+ printf(" Failed to locate %s\n",pcomb(di,vv.nix));
+ }
+ next_comb:;
+ CB_INC(co);
+ }
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ if (vx->sch == 0) {
+ for (e = 0; e <= di; e++) {
+ if (vx->nix[e] < -s->nbp) /* involves inside or outside fake point */
+ break;
+ }
+ if (e <= di)
+ continue; /* Ignore */
+ printf("Extra vertex no %d nix %s at %s (%s) OK\n",vx->no,pcomb(di,vx->nix),ppos(di,vx->p),ppos(di,vx->v));
+ fprintf(stderr,"Extra vertex no %d nix %s at %s (%s) OK\n",vx->no,pcomb(di,vx->nix),ppos(di,vx->p),ppos(di,vx->v));
+ isok = 0;
+ }
+ }
+ if (isok) {
+ printf("Check for missing veftexes is OK\n");
+ fprintf(stderr,"Check for missing veftexes is OK\n");
+ } else {
+ printf("Check for missing veftexes FAILED\n");
+ fprintf(stderr,"Check for missing veftexes FAILED\n");
+ }
+}
+
+/* ------------------------------------------------------------------- */
+/* Check the veronoi to check that no node other than the parent */
+/* node is closer to any vertex. */
+/* return nz if there is a problem */
+static int check_vertex_closest_node(ofps *s) {
+ int i, e, di = s->di;
+ node *nn, *pp;
+ vtx *vx;
+
+ /* Check that no node other than a parent is closer to any vertex */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ double ceperr;
+
+ if (vx->ofake)
+ continue;
+
+ /* Check if the vertex position is clipped by a gamut boundary. */
+ for (i = 0; i < s->nbp; i++) {
+ pleq *vp = &s->gpeqs[i];
+ double v;
+
+ pp = s->n[-1-i];
+#ifdef INDEP_SURFACE
+ /* Check if this vertex is visible to this node */
+ if (sm_vtx_node(s, vx, pp) == 0) {
+ continue; /* It's hidden */
+ }
+#endif /* INDEP_SURFACE */
+
+ for (v = vp->pe[di], e = 0; e < di; e++)
+ v += vp->pe[e] * vx->p[e];
+ if (v > 2.0 * NUMTOL) {
+ /* Check whether pp is already a parent of the node */
+ for (e = 0; e <= di; e++) {
+ if (pp->ix == vx->nix[e])
+ break;
+ }
+ if (e <= di)
+ continue; /* It is */
+
+#ifdef DEBUG
+ printf("Vertex %d parents %s is clipped by boundary node %d by %e\n", vx->no,pcomb(di,vx->nix),pp->ix,v);
+#endif
+ warning("Vertex %d parents %s is clipped by boundary node %d by %e", vx->no,pcomb(di,vx->nix),pp->ix,v);
+ return 1;
+ }
+ }
+
+ /* locate the nearest node to the vertex */
+ if ((nn = ofps_findclosest_node(s, &ceperr, vx)) == NULL)
+ continue;
+
+ /* See if it is closer than the parent nodes */
+ if ((vx->eperr - ceperr) < 2.0 * NUMTOL)
+ continue; /* No it's not */
+
+ /* Check whether nn is already a parent of the node */
+ for (e = 0; e <= di; e++) {
+ if (nn->ix == vx->nix[e])
+ break;
+ }
+ if (e <= di)
+ continue; /* A parent */
+
+#ifdef DEBUG
+ printf("Vertex %d is closer to %d (%f) than parent nodes %s (%f) by %e\n",vx->no,nn->ix,ceperr,pcomb(di,vx->nix),vx->eperr, ceperr - vx->eperr);
+#endif
+ warning("Vertex %d is closer to %d (%f) than parent nodes %s (%f) by %e",vx->no,nn->ix,ceperr,pcomb(di,vx->nix),vx->eperr, ceperr - vx->eperr);
+ return 1;
+ }
+ fflush(stdout);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+
+#if defined(DEBUG) || defined(DUMP_PLOT) || defined (SANITY_CHECK_CONSISTENCY) || defined(DUMP_STRUCTURE)
+/* Do some sanity checking on the points */
+static void
+sanity_check(
+ ofps *s,
+ int check_nodelists /* nz to check node lists */
+) {
+ int i, j, k, e, di = s->di;
+ vtx *vx1, *vx2;
+ int fail = 0; /* 0 = pass, 1 = soft fail, 2 = hard fail */
+
+#ifdef DEBUG
+ printf("Running sanity check...\n");
+#endif
+
+ /* See if any of the sample nodes are near the same location */
+ for (i = 0; i < (s->np-1); i++) {
+ node *p1 = s->n[i];
+ for (j = i+1; j < s->np; j++) {
+ node *p2 = s->n[j];
+ double rad;
+ for (rad = 0.0, e = 0; e < di; e++) {
+ double tt = p1->p[e] - p2->p[e];
+ rad += tt * tt;
+ }
+ rad = sqrt(rad);
+ if (rad < 1e-5) {
+#ifdef DEBUG
+ printf("Nodes ix %d and ix %d are at %s and %s\n", i,j,ppos(di,p1->p),ppos(di,p2->p));
+#endif
+ fail = 2;
+ }
+ }
+ }
+
+ /* See if any of the vertexes have the same node combinations */
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link)
+ vx1->sch = 0;
+
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link) {
+ if (vx1->sch)
+ continue;
+ for (vx2 = vx1->link; vx2 != NULL; vx2 = vx2->link) {
+ if (vx2->sch)
+ continue;
+ for (e = 0; e <= di; e++) {
+ if (vx1->nix[e] != vx2->nix[e])
+ break;
+ }
+ if (e > di) {
+ vx1->sch = vx2->sch = 1; /* Don't do these again */
+#ifdef DEBUG
+ printf("Vertex ix %d and ix %d have same nix %s\n", vx1->no,vx2->no,pcomb(di,vx1->nix));
+#endif
+ fail = 2;
+ }
+ }
+ }
+
+ /* See if any of the vertexes are at the same location */
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link)
+ vx1->sch = 0;
+
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link) {
+ if (vx1->sch)
+ continue;
+ for (vx2 = vx1->link; vx2 != NULL; vx2 = vx2->link) {
+ double rad;
+ if (vx2->sch)
+ continue;
+ for (rad = 0.0, e = 0; e < di; e++) {
+ double tt = vx1->p[e] - vx2->p[e];
+ rad += tt * tt;
+ }
+ rad = sqrt(rad);
+ if (rad < 1e-10) {
+ vx1->sch = vx2->sch = 1; /* Don't do these again */
+#ifdef DEBUG
+ printf("Vertex no %d nix %s vm %s and no %d nix %s vm %s are at %s and %s", vx1->no,pcomb(di,vx1->nix),psm(s,&vx1->vm),vx2->no,pcomb(di,vx2->nix),psm(s,&vx2->vm),ppos(di,vx1->p),ppos(di,vx2->p));
+ if (fabs(vx1->eperr - vx2->eperr) > 1e-5)
+ printf(" and errs %f %f\n",vx1->eperr,vx2->eperr);
+ else
+ printf("\n");
+#endif
+ /* See if the two vertexes are both visible to each other */
+ if (sm_vtx_vtx(s, vx1, vx2) != 0) {
+ fail = 2;
+ }
+ }
+ }
+ }
+
+ /* See if any of the nodes and vertexes are near the same location */
+ for (i = 0; i < s->np; i++) {
+ node *p1 = s->n[i];
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link) {
+ double rad;
+ for (rad = 0.0, e = 0; e < di; e++) {
+ double tt = p1->p[e] - vx1->p[e];
+ rad += tt * tt;
+ }
+ rad = sqrt(rad);
+ if (rad < 1e-5) {
+#ifdef DEBUG
+ printf("Node ix %d and Vertex no %d are at %s and %s%s", i,vx1->no,ppos(di,p1->p),ppos(di,vx1->p),vx1->ghost ? " (ghost)" : "");
+ if (vx1->eperr > 1e-5)
+ printf(" and err %f\n",vx1->eperr);
+ else
+ printf("\n");
+#endif
+ if (vx1->ghost == 0)
+ fail = 1;
+ }
+ }
+ }
+
+ /* Check every node appears in at least one vertex */
+ for (i = 0; i < s->np; i++) { /* For all nodes */
+ node *p1 = s->n[i];
+ vtx *vx;
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ for (e = 0; e <= di; e++) {
+ if (vx->nix[e] == p1->ix)
+ break; /* yes */
+ }
+ if (e <= di)
+ break; /* yes */
+ }
+ if (vx == NULL) {
+#ifdef DEBUG
+ printf("Node ix %d has no vertexes that refer to it\n", p1->ix);
+#endif
+ fail = 2;
+ }
+ }
+
+ if (check_nodelists) {
+ /* See if any vertexes do not appear in their constituent nodes */
+ /* vertex list, or whether verexes nodes don't appear in neighbour list. */
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link) {
+ for (e = 0; e <= di; e++) {
+ int ix = vx1->nix[e];
+ node *pp = s->n[ix];
+
+ for (j = 0; j < pp->nvv; j++) {
+ if (pp->vv[j] == vx1)
+ break;
+ }
+ if (j >= pp->nvv) {
+#ifdef DEBUG
+ printf("Vertex no %d nix %s doesn't appear in node ix %d\n", vx1->no,pcomb(di,vx1->nix),pp->ix);
+#endif
+ fail = 2;
+ }
+ }
+ }
+ }
+
+ /* Check that every vertex of a node contains that node. */
+ for (i = 0; i < s->np; i++) { /* For all nodes */
+ node *p1 = s->n[i];
+ for (j = 0; j < p1->nvv; j++) { /* For all its vertexes */
+ vtx *vx = p1->vv[j];
+
+ for (e = 0; e <= di; e++) { /* All vertexes parent nodes */
+ int ix = vx->nix[e];
+ node *pp = s->n[ix];
+
+ if (ix == p1->ix)
+ break;
+ }
+ if (e > di) {
+#ifdef DEBUG
+ printf("Node ix %d has vtx no %d nix %s that doesn't contain node\n", p1->ix, vx->no,pcomb(di,vx->nix));
+#endif
+ fail = 2;
+ }
+ }
+ }
+
+ if (check_nodelists) {
+ /* Check that a node contains as neighbours all the parent */
+ /* nodes of its vertexes */
+ for (i = 0; i < s->np; i++) { /* For all nodes */
+ node *p1 = s->n[i];
+ for (j = 0; j < p1->nvv; j++) { /* For all its vertexes */
+ vtx *vx = p1->vv[j];
+
+ for (e = 0; e <= di; e++) {
+ int ix = vx->nix[e];
+ node *pp = s->n[ix];
+
+ if (ix == p1->ix)
+ continue; /* Neighbours don't include self */
+ for (k = 0; k < p1->nvn; k++) {
+ if (p1->vn[k] == ix)
+ break;
+ }
+ if (k >= p1->nvn) {
+#ifdef DEBUG
+ printf("Node ix %d has vtx no %d nix %s where neighbour ix %d is missing\n", p1->ix, vx->no,pcomb(di,vx->nix),ix);
+#endif
+ fail = 2;
+ }
+ }
+ }
+ }
+ }
+
+ /* Check that the vertex net is correct */
+ {
+ int ff, f, e, di = s->di;
+ vtx *vx1, *vx2;
+ int nnv = 0;
+ int _nnv = 0;
+ struct _vtx **nv = NULL;
+
+ /* Do a brute force search to locate all this vertexes net neighbours */
+ for (vx1 = s->uvtx; vx1 != NULL; vx1 = vx1->link) {
+
+ nnv = 0; /* Clear the current list */
+
+ /* Search all other vertexes for neighbours */
+ for (vx2 = s->uvtx; vx2 != NULL; vx2 = vx2->link) {
+ int aa, bb, cc; /* Probable hit check */
+ int nnm, nmix;
+
+ if (vx1 == vx2)
+ continue;
+
+#ifdef NEVER /* vertex net needs all neighbours ? */
+#ifdef INDEP_SURFACE
+ if (sm_vtx_vtx(s, vx1, vx2) == 0)
+ continue;
+#endif /* INDEP_SURFACE */
+#endif
+
+ /* Use the nixm to quickly check if all but one parent node matches */
+ aa = vx1->nix[MXPD+2]; /* nixm */
+ bb = vx2->nix[MXPD+2]; /* nixm */
+ if ((aa & bb) == 0 || (cc = aa & ~bb, (cc & (cc-1)) != 0))
+ continue; /* It's certainly not */
+
+ /* Do an exact check of all except one node match */
+ for (nnm = ff = e = 0; e <= di; e++) {
+ for (f = ff; f <= di; f++) {
+ if (vx1->nix[e] == vx2->nix[f]) {
+ ff = f; /* Start from here next time */
+ break;
+ }
+ if (vx1->nix[e] > vx2->nix[f]) /* No point in looking further */
+ f = di;
+ }
+ if (f > di) { /* Didn't match */
+ if (++nnm > 1)
+ break;
+ nmix = e;
+ }
+ }
+ if (e <= di)
+ continue; /* No match */
+
+ if (nnm == 0) {
+ error("ofps: two vertexes have the same nodes !\n"
+ "no %d at %s nix %s\nno %d at %s nix %s",
+ vx1->no,ppos(di,vx1->p),pcomb(di,vx1->nix),
+ vx2->no,ppos(di,vx2->p),pcomb(di,vx2->nix));
+ }
+ if (nnv >= _nnv) {
+ _nnv = 2 * _nnv + 1;
+ if ((nv = (vtx **)realloc(nv, sizeof(vtx *) * _nnv)) == NULL)
+ error("ofps: realloc failed on node vertex pointers");
+ }
+ nv[nnv++] = vx2;
+ }
+
+ /* Now check that the vertex nets match */
+ for (i = 0; i < nnv; i++) {
+ for (j = 0; j < vx1->nnv; j++) {
+ if (nv[i] == vx1->nv[j])
+ break;
+ }
+ if (j >= vx1->nnv) {
+ printf("Vtx no %d is missing vtx no %d from net\n",vx1->no,nv[i]->no);
+ fail = 2;
+ }
+ }
+ for (j = 0; j < vx1->nnv; j++) {
+ for (i = 0; i < nnv; i++) {
+ if (nv[i] == vx1->nv[j])
+ break;
+ }
+ if (i >= nnv) {
+ printf("Vtx no %d has extra vtx no %d in net\n",vx1->no,vx1->nv[j]->no);
+ fail = 2;
+ }
+ }
+ }
+ }
+ if (fail) {
+ if (fail == 1)
+ warning("Internal consistency check failed (soft)");
+ else
+ warning("Internal consistency check failed");
+#ifdef DEBUG
+ if (fail == 1)
+ printf("Internal consistency check failed (soft)\n");
+ else
+ printf("Internal consistency check failed\n");
+ fflush(stdout);
+#endif
+#ifdef SANITY_CHECK_CONSISTENCY_FATAL
+ if (fail == 2)
+ error("Internal consistency check failed");
+#endif
+ }
+
+#ifdef SANITY_CHECK_EXAUSTIVE_SEARCH_FOR_VERTEXES
+ check_for_missing_vertexes(s);
+#endif
+}
+#endif /* SANITY_CHECK_CONSISTENCY */
+
+#if defined(DEBUG) || defined(DUMP_STRUCTURE)
+
+/* ------------------------------------------------------------------- */
+
+/* Dump the node & vertex relationship */
+static void
+dump_node_vtxs(
+ ofps *s,
+ int check_nodelists
+) {
+ int i, j, e, di = s->di;
+ vtx *vx;
+
+ printf("\n");
+ printf("Dumping current state...\n");
+
+ /* Dump node information */
+ for (i = -s->gnp; i < s->np; i++) {
+ node *p1 = s->n[i];
+ printf("Node ix %d, pos %s, mask 0x%x, asm %s\n",p1->ix,ppos(di, p1->p),p1->pmask,psm(s,&s->sc[p1->pmask].a_sm));
+ }
+ printf("\n");
+
+ /* Dump vertex information */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ if (vx->ofake == 0)
+ printf("Vertex no %d, pmask 0x%x, cmask 0x%x, vm %s\n pos %s, nix %s, eperr = %s, eserr = %s\n",vx->no,vx->pmask,vx->cmask,psm(s,&vx->vm), ppos(di, vx->p), pcomb(di,vx->nix), peperr(vx->eperr), peperr(vx->eserr));
+ else
+ printf("Vertex no %d, pmask 0x%x, cmask 0x%x, vm %s, nix %s, eperr = %s, eserr = %s (ofake)\n",vx->no,vx->pmask,vx->cmask,psm(s,&vx->vm), pcomb(di,vx->nix), peperr(vx->eperr), peperr(vx->eserr));
+ }
+ printf("\n");
+
+ /* Dump vertex and associated vertex information */
+ for (vx = s->uvtx; vx != NULL; vx = vx->link) {
+ printf("Vertex no %d has Vtx net:",vx->no);
+ for (j = 0; j < vx->nnv; j++) {
+ vtx *vx2 = vx->nv[j];
+ printf(" %d",vx2->no);
+ }
+ printf("\n");
+ }
+ printf("\n");
+
+ /* Dump node and associated vertex information */
+ for (i = -s->nbp; i < s->np; i++) {
+ node *p1 = s->n[i];
+ printf("Node ix %d, pos %s, mask 0x%x, a_sm %s:\n",p1->ix,ppos(di, p1->p),p1->pmask,psm(s,&s->sc[p1->pmask].a_sm));
+ for (j = 0; j < p1->nvv; j++) {
+ vtx *vx = p1->vv[j];
+ if (vx->ofake == 0)
+ printf(" Vtx no %d pmask 0x%x cmask 0x%x vm %s pos %s nix %s eserr %s\n",vx->no,vx->pmask,vx->cmask,psm(s,&vx->vm),ppos(di, vx->p), pcomb(di, vx->nix), peperr(vx->eserr));
+ else
+ printf(" Vtx no %d pmask 0x%x cmask 0x%x vm %s nix %s eserr %s (ofake)\n",vx->no,vx->pmask,vx->cmask,psm(s,&vx->vm),pcomb(di,vx->nix), peperr(vx->eserr));
+ }
+ for (j = 0; j < p1->nvn; j++) {
+ int ix = p1->vn[j];
+ if (ix >= 0) {
+ node *n1 = s->n[ix];
+ printf(" Assoc. node ix %d pos %s\n",ix,ppos(di, n1->p));
+ } else {
+ printf(" Assoc. node ix %d\n",ix);
+ }
+ }
+ }
+ printf("\n");
+
+ sanity_check(s, check_nodelists);
+
+ fflush(stdout);
+}
+
+#ifdef NEVER
+/* Special dump the node & vertex relationship, */
+/* for comparing with "good" output. */
+/* Deal with vertexe order and numbering. */
+/* Note that the "new" "bad" code needs ofake vertexes */
+/* to work, wheras the "old" "good" code doesn't, so */
+/* skip reporting ofake vetexes. */
+static void
+dump_node_vtxs2(
+ ofps *s,
+ char *com
+) {
+ int i, j, e, di = s->di;
+ vtx *vx;
+ FILE *fp;
+ static int cc = 0;
+ int showofake = 1;
+ vtx **vlist;
+
+ if (cc == 0) {
+ if ((fp = fopen("bad.log","w")) == NULL)
+ error("Unable to open file '%s'\n","bad.log");
+ cc = 1;
+ } else {
+ if ((fp = fopen("bad.log","a")) == NULL)
+ error("Unable to open file '%s'\n","bad.log");
+ }
+
+ fprintf(fp,"\n");
+ fprintf(fp,"Dumping current state (%s) ...\n",com);
+
+ /* Dump node information */
+ for (i = -s->gnp; i < s->np; i++) {
+ node *p1 = s->n[i];
+ fprintf(fp,"Node ix %d, pos %s, mask 0x%x, asm %s\n",p1->ix,ppos(di, p1->p),p1->pmask,psm(s,&s->sc[p1->pmask].a_sm));
+ }
+ fprintf(fp,"\n");
+
+ /* Sort the vertexes by their nix */
+ {
+ int scl = s->gnp + s->np;
+ int nv;
+
+ int nused;
+ for (nused = 0, vx = s->uvtx; vx != NULL; vx = vx->link)
+ nused++;
+if (nused != s->nv) error("s->nv %d doesn't match uvtx list %d",s->nv,nused);
+
+//printf("~1 number of vertexes = %d\n",s->nv);
+ if ((vlist = (vtx **)malloc(sizeof(vtx *) * s->nv)) == NULL)
+ error ("ofps: malloc failed on sorted vertex list");
+ for (i = nv = 0, vx = s->uvtx; vx != NULL; vx = vx->link, i++) {
+ if (!showofake && vx->ofake)
+ continue;
+ vlist[nv++] = vx;
+
+ /* Convert nix into sort index */
+ vx->sch = 0;
+ for (e = 0; e <= di; e++) {
+ vx->sch = scl * vx->sch + (vx->nix[e] + s->gnp);
+ }
+//printf("~1 nix %s ix %d\n",pcomb(di,vx->nix),vx->sch);
+//fflush(stdout);
+ }
+
+ /* Sort */
+#define HEAP_COMPARE(A,B) ((A)->sch < (B)->sch)
+ HEAPSORT(vtx *, vlist, nv);
+#undef HEAP_COMPARE
+
+ for (i = 0; i < nv; i++) {
+ vx = vlist[i];
+ vx->sch = i; /* Sorted index */
+ }
+
+ /* Dump vertex information */
+ for (i = 0; i < nv; i++) {
+ vx = vlist[i];
+ fprintf(fp,"Vertex no %d, pmask 0x%x, cmask 0x%x, vm %s\n pos %s, nix %s, eserr = %s\n",vx->sch,vx->pmask,vx->cmask,psm(s,&vx->vm), ppos(di, vx->p), pcomb(di,vx->nix), peperr(vx->eserr));
+ }
+ fprintf(fp,"\n");
+ free(vlist);
+ }
+
+ /* Dump node and associated vertex information */
+ for (i = -s->nbp; i < s->np; i++) {
+ node *p1 = s->n[i];
+ vtx **vv;
+ int nvv;
+ int *vn;
+
+ fprintf(fp,"Node ix %d, pos %s, mask 0x%x, a_sm %s\n",p1->ix,ppos(di, p1->p),p1->pmask,psm(s,&s->sc[p1->pmask].a_sm));
+
+ /* Display the vertexes in order */
+ if ((vv = (vtx **)malloc(sizeof(vtx *) * p1->nvv)) == NULL)
+ error ("ofps: malloc failed on sorted vertex list");
+ for (nvv = j = 0; j < p1->nvv; j++) {
+ if (!showofake && p1->vv[j]->ofake)
+ continue;
+ vv[nvv++] = p1->vv[j];
+ }
+#define HEAP_COMPARE(A,B) ((A)->sch < (B)->sch)
+ HEAPSORT(vtx *, vv, nvv);
+#undef HEAP_COMPARE
+ for (j = 0; j < nvv; j++) {
+ vtx *vx = vv[j];
+ fprintf(fp," Vtx no %d pmask 0x%x cmask 0x%x vm %s pos %s nix %s eserr %s\n",vx->sch,vx->pmask,vx->cmask,psm(s,&vx->vm),ppos(di, vx->p), pcomb(di, vx->nix), peperr(vx->eserr));
+ }
+ free(vv);
+
+ /* Sort the nodes to be in order */
+ if ((vn = (int *)malloc(sizeof(int) * p1->nvn)) == NULL)
+ error ("ofps: malloc failed on sorted vertex list");
+ for (j = 0; j < p1->nvn; j++)
+ vn[j] = p1->vn[j];
+#define HEAP_COMPARE(A,B) ((A) < (B))
+ HEAPSORT(int, vn, p1->nvn);
+#undef HEAP_COMPARE
+ for (j = 0; j < p1->nvn; j++) {
+ int ix = vn[j];
+ if (ix >= 0) {
+ node *n1 = s->n[ix];
+ fprintf(fp," Assoc. node ix %d pos %s\n",ix,ppos(di, n1->p));
+ } else {
+ fprintf(fp," Assoc. node ix %d\n",ix);
+ }
+ }
+ free(vn);
+ }
+ printf("\n");
+ fflush(fp);
+ fclose(fp);
+}
+#endif /* NEVER */
+#endif /* DEBUG || DUMP_PLOT || DUMP_STRUCTURE */
+
+
+/* --------------------------------------------------------------- */
+#ifdef DUMP_FERR /* Create .tiff of dnsq function error */
+
+/* Draw a line in the output diagnostic raster */
+static int
+show_line(
+ofps *s, /* ofps object */
+int x1, int y1, int x2, int y2, /* line start and end points */
+unsigned char rgb[3], /* Color */
+unsigned char *base, /* Raster base of line */
+int pitch,
+int width,
+int height
+) {
+ unsigned char *pp;
+ int ow = width, oh = height; /* width and height of raster for clipping */
+ int dx, dy; /* Line deltas */
+ int adx, ady; /* Absolute deltas */
+
+ int e, k1, k2; /* Error and axial/diagonal error change values */
+ int m1,m2; /* axial/diagonal coordinate change values */
+
+ int ll; /* Line length */
+
+ /* Do a crude clip */
+ if (x1 < 0)
+ x1 = 0;
+ if (x1 >= ow)
+ x1 = ow-1;
+ if (x2 < 0)
+ x2 = 0;
+ if (x2 >= ow)
+ x2 = ow-1;
+ if (y1 < 0)
+ y1 = 0;
+ if (y1 >= oh)
+ y1 = oh-1;
+ if (y2 < 0)
+ y2 = 0;
+ if (y2 >= oh)
+ y2 = oh-1;
+
+ /* calculate the standard constants */
+ dx = x2 - x1;
+ dy = y2 - y1;
+
+ if(dx < 0) {
+ m1 = -3; /* x is going backwards */
+ adx = -dx; /* make this absolute */
+ } else {
+ m1 = 3; /* x is going forwards */
+ adx = dx;
+ }
+
+ e = 0;
+ if(dy < 0) {
+ m2 = -pitch; /* y is going upwards (decreasing) */
+ ady = -dy; /* make this absolute */
+ e = -1; /* make lines retraceable */
+ } else {
+ m2 = pitch; /* y is going downwards (increasing) */
+ ady = dy;
+ }
+
+ /* m1 has been set to x increment, m2 to y increment */
+
+ m2 += m1; /* make m2 the diagonal address increment */
+ /* and m1 the x axial inrement */
+ if(adx > ady) { /* x is driven */
+ ll = adx;
+ k1 = 2 * ady;
+ k2 = 2 * (ady - adx);
+ e += k1 - adx;
+ } else {
+ ll = ady;
+ k1 = 2 * adx;
+ k2 = 2 * (adx - ady);
+ e += k1 - ady;
+ m1 = m2 - m1; /* Make m1 the y increment */
+ }
+
+ /* Start pixel of line */
+ pp = base + y1 * pitch + 3 * x1;
+
+ ll++; /* Draw start and end point */
+
+ while( ll > 0) {
+ while(e < 0 && ll > 0) {
+ pp[0] = rgb[0];
+ pp[1] = rgb[1];
+ pp[2] = rgb[2];
+ pp += m1;
+ e += k1;
+ ll--;
+ }
+ while(e >= 0 && ll > 0) {
+ pp[0] = rgb[0];
+ pp[1] = rgb[1];
+ pp[2] = rgb[2];
+ pp += m2;
+ e += k2;
+ ll--;
+ }
+ }
+ return 0;
+}
+
+/* Dump a TIFF of the dnsq function values for a given point/plane set. */
+static void
+dump_dnsqe(
+ ofps *s,
+ char *fname,
+ int *nix,
+ vopt_cx *cx
+) {
+ int i, j, e, di = s->di;
+ unsigned char *base, *pa, col[2][3];
+ int width = WIDTH;
+ int height = HEIGHT;
+ int pitch = width * 3;
+ int x, y;
+ TIFF *tif;
+ double pos[MXPD], fval[MXPD];
+ double angle, mag;
+
+ printf("Dumping dnsqe error for combination %s\n",pcomb(di,nix));
+
+ if ((tif = TIFFOpen(fname, "w")) == NULL) {
+ fprintf(stderr,"Failed to open output TIFF file '%s'\n",fname);
+ exit (-1);
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+
+ /* allocate a raster */
+ if ((base = (unsigned char *)malloc(sizeof(unsigned char) * height * pitch)) == NULL)
+ error ("ofps: malloc failed on diagnostic raster");
+
+ for (y = 0; y < height; y++) {
+ pos[1] = 1.0 - y/(height-1.0);
+ pos[1] = 1.4 * pos[1] - 0.2;
+ pa = base + y * pitch;
+
+ /* Fill in pa[] with colors for this line */
+ for (x = 0; x < width; x++) {
+ double ss;
+ unsigned char *dp;
+ double beserr, eserr;
+ double bf, rgb[3];
+ double oog = 1.0;
+ double escale = 10.0; /* Error value scaling */
+
+ dp = pa + x * 3;
+ pos[0] = x/(width-1.0);
+ pos[0] = 1.4 * pos[0] - 0.2;
+ dp[0] = dp[1] = dp[2] = 255;
+//printf("~1 doing %d %d pos %f %f\n",x,y,pos[0],pos[1]);
+
+ /* Se if the sample is in gamut */
+ for (ss = 0.0, e = 0; e < s->di; e++) {
+ if (pos[e] < s->imin[e]
+ || pos[e] > s->imax[e])
+ break;
+ ss += pos[e];
+ }
+ if (e < s->di || ss > (s->ilimit + ILIMITEPS)) {
+ oog = 0.7; /* Show gamut boundary */
+ }
+
+#ifdef NEVER /* Test colors out */
+ fval[0] = pos[0] * 2.0 * escale - escale;
+ fval[1] = pos[1] * 2.0 * escale - escale;
+#else
+ /* Lookup the function value here */
+ dnsq_solver(cx, di, pos, fval, 0);
+#endif
+
+ /* Turn the two values into colors. */
+ for (e = 0; e < di; e++) {
+ fval[e] = (fval[e] / escale);
+ if (fval[e] >= 0.0)
+ fval[e] = pow(fval[e], 0.5);
+ else
+ fval[e] = -pow(-fval[e], 0.5);
+ }
+
+ /* Convert to angle and magnitude */
+ angle = 180.0/3.1415926 * atan2(fval[0], fval[1]);
+ if (angle < 0.0)
+ angle += 360.0;
+ else if (angle > 360.0)
+ angle -= 360.0;
+ mag = sqrt(fval[0] * fval[0] + fval[1] * fval[1]);
+ if (mag > 1.0)
+ mag = 1.0;
+
+ rgb[0] = rgb[1] = rgb[1] = 0.0;
+ if (angle < 120.0) { /* red to green */
+ bf = angle / 120.0;
+ rgb[0] = 1.0 - bf;
+ rgb[1] = bf;
+ rgb[2] = 0.0;
+ } else if (angle < 240.0) { /* green to blue */
+ bf = (angle - 120.0) / 120.0;
+ rgb[0] = 0.0;
+ rgb[1] = 1.0 - bf;
+ rgb[2] = bf;
+ } else { /* blue to red */
+ bf = (angle - 240.0) / 120.0;
+ rgb[0] = bf;
+ rgb[1] = 0.0;
+ rgb[2] = 1.0 - bf;
+ }
+
+ /* Scale to black with magnitude */
+ for (e = 0; e < 3; e++) {
+ rgb[e] = 1.0 - rgb[e];
+ rgb[e] = (1.0 - mag) * 0.0 + mag * rgb[e];
+ }
+
+ for (e = 0; e < 3; e++)
+ dp[e] = (int)(255.0 * oog * rgb[e] + 0.5);
+ }
+ }
+
+
+ /* Show the path the dnsq sampled */
+ col[0][0] = col[0][1] = 255, col[0][2] = 128;
+ col[1][0] = 128, col[1][1] = col[1][2] = 255;
+
+ for (i = 0; i < (cx->nl-1); i++) {
+//printf("~1 line %d: %f %f -> %f %f\n",i, cx->clist[i].p[0], cx->clist[i].p[1], cx->clist[i+1].p[0], cx->clist[i+1].p[1]);
+ show_line(s,
+ (int)(((cx->clist[i].p[0] + 0.2) / 1.4) * (width - 1.0) + 0.5),
+ (int)((1.0 - ((cx->clist[i].p[1] + 0.2) / 1.4)) * (height - 1.0) + 0.5),
+ (int)(((cx->clist[i+1].p[0] + 0.2) / 1.4) * (width - 1.0) + 0.5),
+ (int)((1.0 - ((cx->clist[i+1].p[1] + 0.2) / 1.4)) * (height - 1.0) + 0.5),
+ col[i & 1], base, pitch, width, height);
+ }
+
+ /* Write the raster out */
+ for (y = 0; y < height; y++) {
+ pa = base + y * pitch;
+
+ if (TIFFWriteScanline(tif, (tdata_t)pa, y, 0) < 0) {
+ fprintf(stderr,"WriteScanline Failed at line %d\n",y);
+ exit (-1);
+ }
+ }
+ (void) TIFFClose(tif);
+ free(base);
+}
+#endif /* DUMP_FERR */
+
+/* --------------------------------------------------------------- */
+
+#ifdef NEVER
+
+ /* Compute an aproximate bounding shere, and use */
+ /* the center of it as the start point. */
+
+ double radsq = -1.0; /* Span/radius squared */
+ double rad;
+ double sum;
+ int i, j;
+ int bi = 0, bj = 0;
+
+ /* Find the two vectors that are farthest apart. Brute force search */
+ /* Also track the device position for the points used to define the shere */
+ for (i = 0; i < (ii-1); i++) {
+ for (j = i+1; j < ii; j++) {
+ for (sum = 0.0, e = 0; e < di; e++) {
+ double tt = cx.nds[i]->p[e] - cx.nds[j]->p[e];
+ sum += tt * tt;
+ }
+ if (sum > radsq) {
+ radsq = sum;
+ bi = i;
+ bj = j;
+ }
+ }
+ }
+
+ /* Set initial bounding sphere */
+ for (e = 0; e < di; e++)
+ atp[e] = 0.5 * (cx.nds[bi]->p[e] + cx.nds[bj]->p[e]);
+ radsq /= 4.0; /* diam^2 -> rad^2 */
+ rad = sqrt(radsq);
+
+ /* Go though all the points again, expanding sphere if necessary */
+ for (i = 0; i < ii; i++) {
+
+ if (i == bi || i == bj)
+ continue;
+
+ /* Compute distance squared of vertex to bounding sphere center */
+ for (sum = 0.0, e = 0; e < di; e++) {
+ double tt = cx.nds[i]->p[e] - atp[e];
+ sum += tt * tt;
+ }
+ if (sum > radsq) {
+ double tt;
+
+ sum = sqrt(sum) + 1e-10; /* Radius to point */
+ rad = 0.5 * (rad + sum);
+ radsq = rad * rad;
+ tt = sum - rad;
+ for (e = 0; e < di; e++)
+ atp[e] = (rad * atp[e] + tt * cx.nds[i]->p[e])/sum;
+ }
+ }
+
+/* Given two sample point indexes, compute the plane between them. */
+/* (This will fail with a divide by zero error if two points are coincident) */
+static void comp_pleq(ofps *s, pleq *vp, int ix1, int ix2) {
+ node *p0 = s->n[ix1], *p1 = s->n[ix2];
+ int e, di = s->di;
+ double cp[MXPD];
+ double sum = 0.0;
+
+ /* Compute plane normal from ix1 to ix2 */
+ for (e = 0; e < di; e++) {
+ double tt = p1->p[e] - p0->p[e];
+ vp->pe[e] = tt;
+ sum += tt * tt;
+ }
+ sum = sqrt(sum);
+
+ /* Normalise it */
+ for (e = 0; e < di; e++)
+ vp->pe[e] /= sum;
+
+ /* Compute mid point */
+ for (e = 0; e < di; e++)
+ cp[e] = 0.5 * (p1->p[e] + p0->p[e]);
+
+ /* Compute the plane equation constant */
+ for (vp->pe[di] = 0.0, e = 0; e < di; e++)
+ vp->pe[di] -= vp->pe[e] * cp[e];
+}
+
+#endif // NEVER
+
diff --git a/target/ofps.h b/target/ofps.h
new file mode 100644
index 0000000..e2b1d55
--- /dev/null
+++ b/target/ofps.h
@@ -0,0 +1,438 @@
+
+#ifndef OFPS_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Optimised Farthest Point Sampling
+ *
+ * Author: Graeme W. Gill
+ * Date: 6/9/2004
+ *
+ * Copyright 2004 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.
+ */
+
+#ifndef MXPD
+#define MXPD 4 /* Maximum ofps dimentionality */
+#endif
+
+#define MXNIX (MXPD+3) /* Maximum vertex node indexes + hash + ixm */
+
+struct _acell;
+
+/* A gamut surface plane equation. */
+struct _pleq {
+ double pe[MXPD+1]; /* Vertex plane equation. First di elements are normalized */
+ /* outward pointing normal (from first sample point), last element */
+ /* is constant. If point . pe > 0, then point is outside surface */
+ int ix; /* Index of fake node associated with gamut surface (-ve) */
+}; typedef struct _pleq pleq;
+
+/* A sub-surface set mask */
+#define MXSMASKW 6 /* Maximum number of setmask words */
+typedef struct {
+ unsigned int m[MXSMASKW];
+} setmask;
+
+/* A vertex. This is a point that has the highest eserr within */
+/* the local region of di+1 nodes. It is therefore a candidate for a new */
+/* sample node during seeding, or a point at which the sampling */
+/* error of the current node locations can be estimated. */
+/* Vertexes are the vericies of the Voronoi polyhedra. */
+/* Because these are based on the natural eserr neighborhood, */
+/* they are not necessarily exactly poyhedra. */
+/* (Non gamut boundary verticies are shared) */
+struct _vtx {
+ int no; /* Serial number for id */
+ int nix[MXNIX]; /* di+1 Sample point node indexes involved in vertex */
+ /* Index is -ve if it is a fake gamut boundary node, */
+ /* sorted largest to smallest (so fake gamut nodes are last) */
+ /* [MXPD+1] is hash of all the node indexes, */
+ /* [MXPD+2] is the OR of all the node ixm's */
+ double ce[MXPD+1]; /* Estimated curvature error from mid point to each real node */
+ /* (ce's are compacted, skipping fake boundary nodes) */
+ int nnv; /* Number of neighbour verticies (vertex net) */
+ int _nnv; /* Number allocated */
+ struct _vtx **nv; /* List of neighbour verticies. This includes hidden verts. */
+ /* (If we didn't have to support INDEP_SURFACE, then there would */
+ /* be exactly di neighbour verticies.) */
+
+ double p[MXPD]; /* Vertex location */
+ double v[MXPD]; /* Subjective value at vertex (Labj) ? */
+ double eperr; /* Estimated position error */
+ double eserr; /* Estimated sampling error */
+ double p_eperr; /* Previous estimated position error */
+ char ghost; /* Don't use for optimization or stats. */
+ char ifake; /* A fake inside node */
+ char ofake; /* A fake outside node */
+ char used; /* Set to nz if already used for seeding */
+ char bch; /* nz if added to batch update list */
+ char del; /* Marked for deletion (used by add_to_vsurf()) */
+ char add; /* 1 = add to node, 2 = update hm (used by add_to_vsurf()) */
+ char par; /* Marked for deletion because it's already a parent node */
+ int sch; /* Sanity check houskeeping */
+ setmask buvm; /* Batch update to sub-surface hidden setmask */
+ setmask bdvm; /* Batch delete change to sub-surface hidden setmask */
+ struct _vtx *batch; /* Batch update list */
+ int nsp; /* Number of gamut surface planes it touches */
+ pleq *sp[MXPD+1]; /* List of gamut surface planes */
+ unsigned int pmask; /* Gamut surface plane mask, from its location */
+ unsigned int cmask; /* Gamut surface composition mask, from it's parent nodes */
+ setmask vm; /* Sub-surface visiblility setmask */
+ struct _vtx *link; /* Linked list of free/used vtx's */
+ struct _vtx **plp; /* Pointer to link pointer in used list */
+
+ struct _vtx *n; /* Next in acceleration list */
+ struct _vtx **pn; /* Pointer to link pointer in acceleration list */
+ int pci; /* Accelleration grid index */
+
+ struct _vtx *chn; /* Next in cache index list */
+ struct _vtx **pchn; /* Pointer to link pointer in cache index list */
+
+ int fflag; /* fchl set flag set from s->fflag */
+ struct _vtx *fchl; /* Next in fixup check list */
+ struct _vtx **pfchl;/* Pointer to link pointer */
+ int fupcount; /* Number of times vertex has fixed in a round */
+ double fuptol; /* Tollerance for fixing this vertex */
+ struct _node *hnode;/* Hit node */
+ double hitmarg; /* Hit margine to node */
+ struct _vtx **psvtxs; /* Pointer to entry in s->svtxs[] */
+
+ int cflag; /* Vertex checked for hit flag, set from s->flag */
+ int sflag; /* Vertex search before flag, set from s->flag */
+ int hflag; /* Vertex search after hit flag, set from s->flag */
+ char opqsq; /* flag, on post hit search queue */
+ struct _vtx *slist; /* Breadth first search list link */
+ int disth; /* Search distance from hit vertex, valid when hflag == s->flag */
+ struct _vtx *nxh; /* Vtxs hit by node (to be deleted) list set by ofps_check_vtx_vn() */
+ double nba_eperr; /* node being added eperr, valid if cflag == s->flag */
+
+ struct _vtx *dell; /* Deleted/Not Deleted list */
+}; typedef struct _vtx vtx;
+
+/* A mid point. This is a point that has the highest eserr directly */
+/* between two neighboring nodes. It is used during optimization */
+/* to try and encourage even spacing between nodes. */
+struct _mid {
+ int no; /* Serial number for id */
+ double p[MXPD]; /* Midpoint location */
+ int nix[2]; /* The two sample point node indexes involved in midpoint */
+ double ce[2]; /* Estimated curvature error from mid point to two nodes */
+ double np; /* Interpolation point between nux[0] and nix[1] */
+ double v[MXPD]; /* Subjective value at midpoint (Labj) ? */
+ double eperr; /* Estimated position error */
+ double eserr; /* Estimated sampling error */
+ int refc; /* Reference count */
+ struct _mid *link; /* Linked list of free/used mid's */
+ struct _mid **plp; /* Pointer to link pointer in used list */
+}; typedef struct _mid mid;
+
+
+/* A measurement sample point node. */
+/* Sample points are the points around which the Voronoi polyhedra */
+/* are constructed. If a network is constructed between nodes that */
+/* form a vertex, the netork will be the Delaunay tesselation. */
+struct _node {
+ int ix; /* Index of node in s->n[] */
+ int ixm; /* Hash mask of node ix */
+ int fx; /* nz if point is fixed */
+ double p[MXPD]; /* Device coordinate position */
+ double v[MXPD]; /* Subjective value (Labk) ? */
+
+ double np[MXPD]; /* Next device coordinates during opt */
+ double nv[MXPD]; /* Next subjective coordinates during opt */
+
+ double op[MXPD]; /* Previous device coordinates during opt */
+
+ int nvv; /* Number of Voronoi surface verticies */
+ int _nvv; /* Number allocated */
+ vtx **vv; /* List of Voronoi surface verticies */
+
+ int nvn; /* Number of Voronoi nodes & midpoints */
+ int _nvn; /* Number allocated */
+ int *vn; /* List of Voronoi nodes indexes. Doesn't include this node. */
+ /* Index is -ve if it is a fake gamut boundary node. */
+ mid **mm; /* List of midpoints. Midpoints will be NULL if not created yet. */
+
+ int nsp; /* Number of touched gamut surface planes */
+ pleq *sp[MXPD+1]; /* List of touched gamut surface planes */
+ unsigned int pmask; /* Gamut surface plane mask */
+
+ struct _acell *cell;/* Pointer to cell vertex is in */
+ struct _node *n; /* Next in acceleration list */
+ struct _node **pn; /* Pointer to link pointer in acceleration list */
+ int pci; /* Accelleration grid index */
+
+ int flag; /* Node being added access flag, set from s->flag */
+ int nvnflag; /* node_recomp_nvn_dmxs access flag */
+ struct _node *na; /* Next in 'to be added' list */
+ int upflag; /* Set to s->flag if node has been added to ->nup list */
+ struct _node *nup; /* Next node in 'recomp_nvn' list */
+
+}; typedef struct _node node;
+
+#define BOUND_GFLAG ((unsigned int)-1) /* Boundary cell gflag */
+
+/* An acceleration structure cube */
+struct _acell {
+ unsigned int gflag; /* Acceleration grid search touched & boundary flag */
+ node *head; /* List of nodes inside acceleration cell */
+ vtx *vhead; /* List of verticies with all real nodes inside acceleration cell */
+ int co[MXPD]; /* coordinate of cell */
+ double p[MXPD]; /* Device position of base of cell */
+ double v[MXPD]; /* Corresponfing perceptual value of base of cell */
+ double cp[MXPD]; /* Device position of center of cell */
+ double cv[MXPD]; /* Corresponfing perceptual value of center of cell */
+ double eperr; /* Worst case eperr from a corner to the center */
+ struct _acell *slist; /* Search list */
+}; typedef struct _acell acell;
+
+/* Storage for a node combination/new position */
+struct _nodecomb {
+ int nix[MXNIX]; /* di+1 Sample point node indexes involved in vertex */
+ double ce[MXPD+1]; /* Estimated curvature error from mid point to two nodes */
+ vtx **v1, **v2; /* Deleted and non-deleted vertex involved */
+ int _count; /* v1/v2 allocation */
+ int count; /* Number of times this is generated, used of v1/v2 */
+ double p[MXPD]; /* Position of resulting vertex or */
+ double v[MXPD]; /* Value of resulting vertex or */
+ double eperr;
+ double eserr;
+ double weserr;
+ int pvalid; /* Valid new position, else use deleted location & eserr */
+ vtx *vv; /* Existing vertex at this combination (if opt) */
+ double ceperr; /* Current eperr to be bettered */
+ double oog; /* Out of gamut value */
+ setmask vm; /* Sub-surface visibility setmask */
+ int startex; /* nz if existing p[] should be starting dnsqe point */
+}; typedef struct _nodecomb nodecomb;
+
+/* Vertex cache hash index/table size */
+#define VTXCHSIZE 33037
+//#define VTXCHSIZE 67493
+
+/* Record of a set of gamut surface plane combination */
+struct _surfcomb {
+ unsigned int co; /* Surface combination mask */
+ int valid; /* Valid flag */
+ int nos; /* Number surfaces */
+ int smset; /* i_sm has been set */
+ setmask i_sm; /* Indiviual set of this surface combination */
+ setmask a_sm; /* Accumulated set of this and higher dimensions */
+ struct _surfcomb *ds; /* Circular list of the disjoint set */
+}; typedef struct _surfcomb surfcomb;
+
+/* Main sample point object */
+struct _ofps {
+/* private: */
+ int verb; /* Verbose */
+
+ int di; /* Point dimensionality */
+ double ilimit; /* Ink limit - limit on sum of p[] */
+ double imin[MXPD]; /* Ink limit - limit on min of p[], must be >= 0.0 */
+ double imax[MXPD]; /* Ink limit - limit on min of p[], must be <= 1.0 */
+ int good; /* 0 = fast, 1 = good flag */
+ double surftol; /* Surface tollerance distance */
+ int maxits; /* Maximum itterative improvement passes */
+ double lperterb; /* level of random peturbation */
+ double ssurfpref, esurfpref; /* Start and end surface preference weightig */
+
+ /* Error estimate model parameters */
+ double devd_wght; /* Device space weighting */
+ double perc_wght; /* Perceptual space weighting */
+ double curv_wght; /* Curvature weighting */
+
+ int fxno; /* Total number of fixed points provided, possibly non-unique */
+ fxpos **ufx; /* fnp randomized unique fixed points to add */
+
+ int gnp; /* Number of fake gamut nodes (-ve index) */
+ /* -1 to -2di-1 are fake boundary node indexes, */
+ /* with -2di-1 being the ink limit boundary. */
+ /* -2di-2 is the fake inside node, */
+ /* -2di-3 is the fake outside node, */
+ int fnp; /* Number of unique fixed points in list */
+ int tinp; /* Target number of total points in list, including fnp */
+ int np; /* Number of points currently in list */
+ node *_n, **n; /* tinp allocation of points, list of pointers to points */
+ int nv; /* Current number of verticies */
+ int nxvno; /* Next vertex serial number */
+ int nxmno; /* Next midpoint serial number */
+
+ /* Gamut surface definition planes. */
+ int nbp; /* Number of boundary planes. Either 2di or 2di+1 */
+ pleq gpeqs[2 + MXPD * 2 + 1]; /* Plane equations associated */
+ /* with the fake gamut surface/boundary nodes */
+ /* points. Index is 1-ix */
+ /* (allow for other fakes, just in case) */
+ int sminit; /* Flag, nz if sc has been inited */
+ surfcomb *sc; /* Array of (1 << nbp) surface combinations */
+ int smbits; /* Total set mask bits */
+ int bpsmw; /* Bits per set mask word */
+ int nsmw; /* Number of setmask words */
+ unsigned int lwmask; /* Last word mask */
+
+ /* Perceptual function handed in. All device values must have been */
+ /* clipped before calling this, otherwise use It is assumed that */
+ void (*percept)(void *od, double *out, double *in);
+ void *od; /* Opaque data for perceptual point */
+
+ rspl *pcache; /* cache of perceptual lookup */
+
+ /* Other info */
+ int rix; /* Next read index */
+ double mn,mx,av; /* serr stats */
+ double smns; /* Closest node spacing */
+ double mxmvsq; /* Maximum movement during optimisation */
+ int optit; /* Optimization itteration */
+ vtx *nxh; /* Vtxs hit by node (to be deleted) list set by ofps_check_vtx_vn() */
+ vtx *nxp; /* Vtxs that are already parents of added node list (fixups) */
+ struct _vtx *batch; /* Batch update list */
+ int checklev; /* check node recursion level */
+ struct _vtx *fchl; /* Next vertex in fixup check list */
+ struct _vtx **svtxs;/* Vertex "to be fixed" list */
+ int nsvtxs; /* Number in vertex "to be fixed" list */
+ int _nsvtxs; /* Allocated size of vertex "to be fixed" list */
+ struct _node *nup; /* Next node in 'recomp_nvn' list */
+
+ /* Used and free lists */
+ struct _vtx *uvtx; /* Linked list of used vtx's */
+ struct _vtx *fvtx; /* Linked list of free vtx's */
+ struct _vtx *hvtx; /* Linked list of hidden vtx's */
+ struct _mid *umid; /* Linked list of used mid's */
+ struct _mid *fmid; /* Linked list of free mid's */
+
+ /* Unbounded perceptual model */
+ double pmod[MXPD * (1 << MXPD)];
+ int pmod_init; /* It's been initialised */
+
+ /* Acceleration structure */
+ int agres; /* Acceleration grid resolution (not including extra row) */
+ double gw; /* Grid cell width */
+ int gim[MXPD]; /* Grid index multiplier */
+ double gcd; /* Grid cell diagonal */
+ int nig; /* Number of cells in grid (including guard rows) */
+ acell *_grid; /* Pointer to allocated array of grid structures */
+ acell *grid; /* Pointer to base of array of grid structures */
+ int agrid_init; /* accell grid p[] and v[] have been inited */
+ unsigned int gflag; /* Acceleration grid search flag */
+ int nacnl; /* Number of bytes in Accelleration cell neighbour offset list */
+ int *acnl; /* Accelleration cell neighbour offset list */
+
+ int flag; /* Access flag associated with node being added */
+ int nvnflag; /* node_recomp_nvn_dmxs access flag */
+ int fflag; /* Fixup round flag */
+ vtx *vch[VTXCHSIZE]; /* Vertex cache index */
+
+ aat_atree_t *vtreep; /* Binary tree of vertexes sorted by eperr */
+ aat_atree_t *vtrees[MXPD+2]; /* Per nsp, binary tree of vertexes sorted by eserr */
+ /* We get di+2 planes for fake initial nodes */
+
+ /* Utility - avoid re-allocation/initialization */
+ sobol *sob;
+ nodecomb *combs; /* New node combinations being created in add_to_vsurf() */
+ int _ncombs; /* Number of node combinations allocated. */
+
+ /* Debug/stats */
+ int nopstop; /* Number of optimization passes before stopping with diagnostics */
+ int ntostop; /* Number of points before stopping with diagnostics */
+ int positions; /* Number of calls to locate vertex */
+ int dnsqs; /* Number of dnsq is called */
+ int funccount; /* Number of times dnsq callback function is called */
+ int maxfunc; /* Maximum function count per dnsq */
+ int sucfunc; /* Function count per sucessful dnsq */
+ int sucdnsq; /* Number of sucessful dnsqs */
+ int maxretries; /* Maximum retries used on sucessful dnsq */
+ int posfails; /* Number of position_vtx failures */
+ int posfailstp; /* Number of position_vtx failures this pass */
+ int nvtxcreated; /* Number of vertexes created */
+ int nvtxdeleted; /* Number of vertexes deleted */
+ int add_hit; /* Number of add_to_vsurf hits */
+ int add_mis; /* Number of add_to_vsurf misses */
+ int fadd_hit; /* Number of fixup add_to_vsurf hits */
+ int fadd_mis; /* Number of fixup add_to_vsurf misses */
+
+ int nvcheckhits; /* Number of vertexes hit durint ofps_check_node() */
+ int vvchecks; /* Number of vertexes checked for hit */
+ int vvpchecks; /* Number of vertexes that would be exaustively checked for hits */
+ int naccsrch; /* Number of accellerated searches */
+ int ncellssch; /* Number of accelleration cells searched */
+ int nnschd; /* Number of nodes nearest searched */
+ int nnfschd; /* Number of nodes for full nearest searched */
+ int nvschd; /* Number of vertexes nearest searched */
+ int nvfschd; /* Number of vertexes for full nearest searched */
+
+ int nsurfadds; /* Number of add_to_vsurf() calls */
+ int nhitv; /* Number of hit vertexes in add_to_vsurf() */
+ int maxhitv; /* Maximum number of hit vertexes in add_to_vsurf() */
+
+ int nfseeds; /* Number of times searched for vtx with largest eserr */
+ int nfseedsvtx; /* Number of vertexes searched for vtx with largest eserr */
+
+ unsigned int l_mstime; /* Last create surface pass timestamp */
+ int l_positions; /* Last Number of calls to locate vertex */
+ int l_nvtxcreated; /* Last Number of vertexes created */
+ int l_nvtxdeleted; /* Last Number of vertexes deleted */
+
+ struct _vtx *i_uvtx; /* Incrementallu created vertexes used by DEBUG_RESEED_AFTER_FIXUPS */
+
+/* public: */
+ /* return non-zero if the perceptual point is within the device gammut */
+ int (*pig)(struct _ofps *s, double *p);
+
+ /* Initialise, ready to read out all the points */
+ void (*reset)(struct _ofps *s);
+
+ /* Read the next set of non-fixed points values */
+ /* return non-zero when no more points */
+ /* p = position, v = value, either may be NULL */
+ int (*read)(struct _ofps *s, double *p, double *v);
+
+ /* Calculate and print stats */
+ void (*stats)(struct _ofps *s);
+
+ /* Destroy ourselves */
+ void (*del)(struct _ofps *s);
+
+ }; typedef struct _ofps ofps;
+
+
+/* Constructor */
+extern ofps *new_ofps(
+ int verb,
+ int di, double ilimit, int npoints,
+ int good,
+ double dadaptation,
+ double devd_wght,
+ double perc_wght,
+ double curv_wght,
+ fxpos *fxlist, int fxno, /* Existing, fixed point list */
+ void (*percept)(void *od, double *out, double *in), void *od);
+
+/* Extended constructor */
+ofps *new_ofps_ex(
+int verb, /* Verbosity */
+int di, /* Dimensionality of device space */
+double ilimit, /* Ink limit (sum of device coords max) */
+double *imin, /* Ink limit - limit on min of p[], normally >= 0.0 */
+double *imax, /* Ink limit - limit on min of p[], normally <= 1.0 */
+int tinp, /* Total number of points to generate, including fixed */
+int good, /* 0 = fast, 1 = good */
+double dadaptation, /* Degree of adaptation to device characteristic 0.0 - 1.0, */
+ /* use -ve value for explicit weightings: */
+double devd_wght, /* Device space weighting (if dad < 0) */
+double perc_wght, /* Perceptual space weighting (if dad < 0) */
+double curv_wght, /* Curvature weighting (if dad < 0) */
+fxpos *fxlist, /* List of existing fixed points (may be NULL) */
+int fxno, /* Number of existing fixes points */
+void (*percept)(void *od, double *out, double *in), /* Perceptual lookup func. */
+void *od, /* context for Perceptual function */
+int ntostop, /* Debug - number of points until diagnostic stop */
+int nopstop /* Debug - number of optimizations until diagnostic stop, -1 = not */
+);
+
+#define OFPS_H
+#endif /* OFPS_H */
diff --git a/target/ppoint.c b/target/ppoint.c
new file mode 100644
index 0000000..2a5dd26
--- /dev/null
+++ b/target/ppoint.c
@@ -0,0 +1,1056 @@
+
+// ppoint7c
+// Approach that picks poorly supprted points with maximum interpolation
+// error each time. Version that creates a candidate list when adding
+// previous points to the distance grid.
+// Development of version that uses interpolation error and perceptual
+// distance to nearest sample point driven point placement metric, this
+// one usin incremental rspl for interpolation estimation.
+
+/*
+ * Argyll Color Correction System
+ *
+ * Perceptually distributed point class
+ *
+ * Author: Graeme W. Gill
+ * Date: 5/10/96
+ *
+ * Copyright 1996 - 2004 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.
+ */
+
+/* TTBD:
+
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#include "numlib.h"
+#include "rspl.h"
+#include "sort.h"
+#include "plot.h"
+#include "icc.h"
+#include "xcolorants.h"
+#include "targen.h"
+#include "ppoint.h"
+
+#undef DEBUG
+#define DUMP_PLOT /* Show on screen plot */
+#define PERC_PLOT 0 /* Emit perceptive space plots */
+#define DO_WAIT 1 /* Wait for user key after each plot */
+
+#define ALWAYS
+#undef NEVER
+
+#ifdef NEVER
+#ifdef __STDC__
+#include <stdarg.h>
+void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...);
+#else
+#include <varargs.h>
+void error(), warning(), verbose();
+#endif
+#endif /* NEVER */
+
+#ifdef STANDALONE_TEST
+#ifdef DUMP_PLOT
+static void dump_image(ppoint *s, int pcp);
+#endif
+#endif
+
+static void add_dist_points(ppoint *s, co *pp, int nn);
+//static double far_dist(ppoint *s, double *p);
+
+/* Default convert the nodes device coordinates into approximate perceptual coordinates */
+/* (usually overriden by caller supplied function) */
+static void
+default_ppoint_to_percept(void *od, double *p, double *d) {
+ ppoint *s = (ppoint *)od;
+ int e;
+
+#ifndef NEVER
+ /* Default Do nothing - copy device to perceptual. */
+ for (e = 0; e < s->di; e++) {
+ double tt = d[e];
+ if (e == 0)
+ tt = pow(tt, 2.0);
+ else
+ tt = pow(tt, 0.5);
+ p[e] = tt * 100.0;
+ }
+#else
+ for (e = 0; e < s->di; e++) {
+ double tt = d[e];
+ /* Two slopes with a sharp turnover in X */
+ if (e == 0) {
+ if (tt < 0.5)
+ tt = tt * 0.3/0.5;
+ else
+ tt = 0.3 + ((tt-0.5) * 0.7/0.5);
+ }
+ p[e] = tt * 100.0;
+ }
+#endif
+}
+
+/* return the distance of the device value from the device gamut */
+/* This will be -ve if the point is outside */
+/* If bvp is non-null, the index of the closest dim times 2 */
+/* will be returned for the 0.0 boundary, dim * 2 + 1 for the 1.0 */
+/* boundary, and di * 2 for the ink limit boundary. */
+static double
+ppoint_in_dev_gamut(ppoint *s, double *d, int *bvp) {
+ int e;
+ int di = s->di;
+ double tt, dd = 1.0;
+ double ss = 0.0;
+ int bv = di;
+ for (e = 0; e < di; e++) {
+ tt = d[e];
+ if (tt < dd) {
+ dd = tt;
+ bv = e * 2;
+ }
+ tt = 1.0 - d[e];
+ if (tt < dd) {
+ dd = tt;
+ bv = e * 2 + 1;
+ }
+ ss += d[e];
+ }
+ ss = (s->ilimit-ss)/di; /* Axis aligned distance to ink limit */
+ tt = sqrt((double)di) * ss; /* Diagonal distance to ink limit */
+ if (tt < dd) {
+ dd = tt;
+ bv = di * 2;
+ }
+ if (bvp != NULL)
+ *bvp = bv;
+ return dd;
+}
+
+#ifdef NEVER /* Not currently used */
+/* Given the new intended device coordinates, */
+/* clip the new position to the device gamut edge */
+/* return non-zero if the point was clipped */
+static int
+ppoint_clip_point(ppoint *s, double *d) {
+ int e;
+ double ss = 0.0;
+ int rv = 0;
+ for (e = 0; e < s->di; e++) {
+ if (d[e] < 0.0) {
+ d[e] = 0.0;
+ rv |= 1;
+ } else if (d[e] > 1.0) {
+ d[e] = 1.0;
+ rv |= 1;
+ }
+ ss += d[e];
+ }
+ if (ss > s->ilimit) {
+ ss = (ss - s->ilimit)/s->di;
+ for (e = 0; e < s->di; e++)
+ d[e] -= ss;
+ rv |= 1;
+ }
+ return rv;
+}
+#endif /* NEVER */
+
+/* --------------------------------------------------- */
+/* Locate the best set of points to add */
+
+/* Definition of the optimization functions handed to powell(.) */
+/* Return distance error to be minimised (maximises distance from */
+/* an existing sample point) */
+static double efunc1(ppoint *s, double p[]) {
+ double rv = 0.0; /* return value */
+
+//printf("\n~1 p = %f %f\n",p[0],p[1]);
+ if ((rv = (ppoint_in_dev_gamut(s, p, NULL))) < 0.0) {
+ rv = rv * -500.0 + 50000.0; /* Discourage being out of gamut */
+//printf("~1 out of gamut, rv = %f\n",rv);
+
+ } else {
+ int e, di = s->di;
+ double vf[MXPD]; /* Perceptual value of reference */
+ co tp; /* Lookup from interpolation grid */
+ double ierr; /* Interpolation error */
+ double cdist; /* closest distance to point */
+ double errd; /* Overall error/distance to maximise */
+
+ for (e = 0; e < di; e++)
+ tp.p[e] = p[e];
+
+ s->pd->interp(s->pd, &tp); /* Lookup current closest distance value */
+ cdist = tp.v[di];
+ if (cdist >= 10000.0) /* Initial value */
+ cdist = 0.0;
+
+//printf("~1 min pdist = %f\n",cdist);
+
+ /* Not quite sure which is best here. */
+ /* Using percept() is slower, and has more point placement artefacts, */
+ /* but seems to arrive at a better result. */
+#ifdef NEVER
+ for (e = 0; e < di; e++)
+ vf[e] = tp.v[e]; /* Use interpolated perceptual value */
+#else
+ s->percept(s->od, vf, p); /* Lookup perceptual value */
+#endif
+ s->g->interp(s->g, &tp); /* Lookup current interpolation */
+
+//printf("~1 interp %f %f, percept %f %f\n",tp.v[0],tp.v[1],vf[0],vf[1]);
+ for (ierr = 0.0, e = 0; e < di; e++) {
+ double tt = tp.v[e] - vf[e];
+ ierr += tt * tt;
+ }
+ ierr = sqrt(ierr);
+//printf("~1 interp error = %f\n",ierr);
+
+ /* The ratio of interpolation error to support distance affects */
+ /* peak vs. average error in final result. */
+#ifdef NEVER
+ /* Weighted squares */
+ errd = ierr * ierr + DWEIGHT * cdist * cdist;
+#else
+ /* Linear weighted then squared */
+ errd = ierr + DWEIGHT * cdist;
+ errd = errd * errd;
+#endif
+
+ /* Convert max error to min return value */
+ rv = 1000.0/(0.1 + errd);
+//printf("~1 err val %f\n",rv);
+
+ }
+
+//printf("~1 efunc1 returning %f from %f %f\n",rv,p[0],p[1]);
+ return rv;
+}
+
+
+/* return the interpolation error at the given device location */
+static double
+ppoint_ierr(
+ppoint *s,
+double *p
+) {
+ int e, di = s->di;
+ double vf[MXPD]; /* Perceptual value of reference */
+ double err;
+ co tp; /* Perceptual value of test point */
+
+ for (e = 0; e < di; e++)
+ tp.p[e] = p[e];
+ s->g->interp(s->g, &tp);
+
+ s->percept(s->od, vf, p);
+
+ for (err = 0.0, e = 0; e < di; e++) {
+ double tt = tp.v[e] - vf[e];
+ err += tt * tt;
+ }
+ err = sqrt(err);
+
+ return err;
+}
+
+/* Find the next set of points to add to our test sample set. */
+/* Both device and perceptual value are returned. */
+/* We try and do a batch of points because adding points to the rspl interpolation */
+/* is a high cost operation. The main trap is that we may add points that are almost identical, */
+/* since we don't know the effect of adding other points in this batch. */
+/* To try and counter this, points are rejected that are two close together in this group. */
+
+/* Candidate points are located that have amongst the largest distances to existing */
+/* points (measured in a device/perceptual distance mix), and from those points, */
+/* the ones with the highest current interpolation mis-prediction error are selected. */
+/* In this way a well spread set of samples is hoped to be gemerated, but favouring */
+/* those that best reduce overall interpolation error. */
+static int
+ppoint_find_worst(
+ppoint *s,
+co *p, /* return device values */
+int tnn /* Number to return */
+) {
+ co *fp = s->fwfp; /* Copy of s-> info, stored in s because of size. */
+ int nfp; /* Current number in fp[] */
+ int opoints;
+ int e, di = s->di;
+ double sr[MXPD]; /* Search radius */
+ int i, j;
+
+ for (e = 0; e < di; e++)
+ sr[e] = 0.01; /* Device space search radius */
+
+//printf("~1 currently %d points in fp list\n",s->nfp);
+
+ /* The distance grid functions will have a list of the FPOINTS best */
+ /* grid points to start from. Make a copy of it */
+ for (nfp = 0; nfp < s->nfp; nfp++) {
+ fp[nfp] = s->fp[nfp]; /* Structure copy */
+ fp[nfp].v[0] = efunc1(s, fp[nfp].p); /* Compute optimiser error value */
+ }
+
+ /* If list is not full, fill with random numbers: */
+ if (nfp < FPOINTS) {
+//printf("~1 not full, so adding %d random points\n",FPOINTS-nfp);
+// for (; nfp < FPOINTS; nfp++) {
+ for (; nfp < tnn; nfp++) {
+ double sum;
+
+ for (;;) { /* Find an in-gamut point */
+ for (sum = 0.0, e = 0; e < di; e++)
+ sum += fp[nfp].p[e] = d_rand(0.0, 1.0);
+ if (sum <= s->ilimit)
+ break;
+ }
+ fp[nfp].v[0] = efunc1(s, fp[nfp].p); /* Compute optimiser dist error value */
+ }
+ }
+
+ /* Sort them by derr, smallest to largest */
+#define HEAP_COMPARE(A,B) ((A).v[0] < (B).v[0])
+ HEAPSORT(co, fp, nfp);
+#undef HEAP_COMPARE
+
+ opoints = nfp < OPOINTS ? nfp : OPOINTS;
+
+ /* Optimise best portion of the list of starting points, according to */
+ /* interpolation error weighted distance. */
+ for (i = 0; i < opoints; i++) {
+ double mx;
+
+ if (powell(&mx, di, fp[i].p, sr, 0.001, 1000,
+ (double (*)(void *, double *))efunc1, (void *)s, NULL, NULL) != 0 || mx >= 50000.0) {
+#ifdef ALWAYS
+ printf("ppoint powell failed, tt = %f\n",mx);
+#endif
+ }
+ fp[i].v[0] = mx;
+//printf("~1 optimised point %d to %f %f derr %f\n",i,fp[i].p[0],fp[i].p[1],mx);
+
+ /* Check if this duplicates a previous point */
+ for (j = 0; j < i; j++) {
+
+ double ddif = 0.0;
+ for (e = 0; e < di; e++) {
+ double tt = fp[i].p[e] - fp[j].p[e];
+ ddif += tt * tt;
+ }
+ ddif = sqrt(ddif); /* Device value difference */
+ if (ddif < CLOSED) {
+//printf("~1 duplicate of %d, so marked\n",j);
+ fp[i].v[0] = 50000.0; /* Mark so it won't be used */
+ break; /* too close */
+ }
+ }
+ }
+
+//printf("~1 derr sorted list:\n");
+//for (i = 0; i < opoints; i++)
+// printf("~1 %d: loc %f %f derr %f\n", i, fp[i].p[0],fp[i].p[1],fp[i].v[0]);
+
+ /* Compute the interpolation error for the points of interest */
+ for (i = 0; i < opoints; i++) {
+ if (fp[i].v[0] >= 50000.0) /* Duplicate or failed to optimis point */
+ fp[i].v[0] = -1.0; /* Impossibly low interpolation error */
+ else
+ fp[i].v[0] = ppoint_ierr(s, fp[i].p);
+ }
+
+ /* Sort them by ierr, largest to smallest */
+#define HEAP_COMPARE(A,B) ((A).v[0] > (B).v[0])
+ HEAPSORT(co, fp, opoints);
+#undef HEAP_COMPARE
+
+//printf("~1 ierr sorted list:\n");
+//for (i = 0; i < OPOINTS; i++)
+// printf("~1 %d: loc %f %f ierr %f\n", i, fp[i].p[0],fp[i].p[1],fp[i].v[0]);
+
+ /* Return the best tnn as next points */
+ for (j = i = 0; j < tnn && i < opoints; i++) {
+ if (fp[i].v[0] < 0.0)
+ continue; /* Skip marked points */
+ for (e = 0; e < di; e++)
+ p[j].p[e] = fp[i].p[e];
+ s->percept(s->od, p[j].v, p[j].p);
+ j++;
+ }
+//printf("~1 returning %d points\n",j);
+ return j;
+}
+
+
+/* --------------------------------------------------- */
+
+/* determine the errors between the rspl and 100000 random test points */
+static void
+ppoint_stats(
+ppoint *s
+) {
+ int i, n;
+ int e, di = s->di;
+ double mx = -1e80, av = 0.0, mn = 1e80;
+
+ for (i = n = 0; i < 100000; i++) {
+ co tp; /* Perceptual value of test point */
+ double vf[MXPD]; /* Perceptual value of reference */
+ double sum, err;
+
+ for (sum = 0.0, e = 0; e < di; e++)
+ sum += tp.p[e] = d_rand(0.0, 1.0);
+
+ if (sum <= s->ilimit) {
+
+ /* rspl estimate of expected profile interpolation */
+ s->g->interp(s->g, &tp);
+
+ /* Target values */
+ s->percept(s->od, vf, tp.p);
+
+ for (err = 0.0, e = 0; e < di; e++) {
+ double tt = tp.v[e] - vf[e];
+ err += tt * tt;
+ }
+ err = sqrt(err);
+ if (err > mx)
+ mx = err;
+ if (err < mn)
+ mn = err;
+ av += err;
+ n++;
+ }
+ }
+ av /= (double)n;
+
+ printf("~1 Random check errors max %f, avg %f, min %f\n",mx,av,mn);
+}
+
+/* --------------------------------------------------- */
+/* Support for maintaining the device/perceptual distance grid */
+/* as well as keeping the far point candidate list up to date. */
+
+/* Structure to hold data for callback function */
+struct _pdatas {
+ ppoint *s; /* ppoint structure */
+ int init; /* Initialisation flag */
+ co *pp; /* List of new points */
+ int nn; /* Number of points */
+}; typedef struct _pdatas pdatas;
+
+/* rspl set callback function for maintaining perceptual distance information */
+static void
+pdfunc1(
+ void *ctx, /* Context */
+ double *out, /* output value, = di percept + distance */
+ double *in /* inut value */
+) {
+ pdatas *pp = (pdatas *)ctx;
+ ppoint *s = pp->s;
+ int e, di = s->di;
+
+ if (pp->init) {
+ s->percept(s->od, out, in); /* Lookup perceptual value */
+ out[di] = 10000.0; /* Set to very high distance */
+
+ } else { /* Adding some points */
+ int i;
+ double sd = 1e80;
+
+ /* Find smallest distance from this grid point to any of the new points */
+ for (i = 0; i < pp->nn; i++) {
+ double ddist, pdist;
+ double dist; /* Combined distance */
+
+ /* Compute device and perceptual distance */
+ for (ddist = pdist = 0.0, e = 0; e < di; e++) {
+ double tt = out[e] - pp->pp[i].v[e];
+ pdist += tt * tt;
+ tt = 100.0 * (in[e] - pp->pp[i].p[e]);
+ ddist += tt * tt;
+ }
+ dist = DDMIX * ddist + (1.0-DDMIX) * pdist; /* Combine both */
+ if (dist < sd)
+ sd = dist;
+ }
+
+ sd = sqrt(sd);
+ if (sd < out[di])
+ out[di] = sd;
+
+ /* Update far point candidate list */
+ if (s->nfp < FPOINTS) { /* List isn't full yet */
+ for (e = 0; e < di; e++)
+ s->fp[s->nfp].p[e] = in[e];
+ s->fp[s->nfp].v[0] = sd; /* store distance here */
+
+ if (sd > s->wfpd) { /* If this is the worst */
+ s->wfpd = sd;
+ s->wfp = s->nfp;
+ }
+ s->nfp++;
+
+ } else if (sd < s->wfpd) { /* Found better, replace current worst */
+
+ for (e = 0; e < di; e++)
+ s->fp[s->wfp].p[e] = in[e];
+ s->fp[s->wfp].v[0] = sd; /* store distance here */
+
+ /* Locate the next worst */
+ s->wfpd = -1.0;
+ for (i = 0; i < s->nfp; i++) {
+ if (s->fp[i].v[0] > s->wfp) {
+ s->wfp = i;
+ s->wfpd = s->fp[i].v[0];
+ }
+ }
+ }
+ }
+}
+
+/* Add a list of new points to the perceptual distance grid */
+/* (Can change this to just adding 1 point) */
+static void add_dist_points(
+ppoint *s,
+co *pp, /* List of points including device and perceptual values */
+int nn /* Number in the list */
+) {
+ pdatas pdd; /* pd callback context */
+
+ pdd.s = s;
+ pdd.init = 0; /* Initialise values in the grid */
+ pdd.pp = pp;
+ pdd.nn = nn;
+
+ /* let callback do all the work */
+ s->pd->re_set_rspl(s->pd,
+ 0, /* No special flags */
+ &pdd, /* Callback function context */
+ pdfunc1); /* Callback function */
+}
+
+#ifdef NEVER /* Not currently used */
+/* Return the farthest distance value for this given location */
+static double far_dist(ppoint *s, double *p) {
+ int e, di = s->di;
+ double cdist;
+ co tp;
+
+ for (e = 0; e < di; e++)
+ tp.p[e] = p[e];
+
+ s->pd->interp(s->pd, &tp); /* Lookup current closest distance value */
+ cdist = tp.v[di];
+ if (cdist >= 10000.0) /* Initial value */
+ cdist = 0.0;
+ return cdist;
+}
+#endif /* NEVER */
+
+/* --------------------------------------------------- */
+/* Seed the whole thing with points */
+
+static void
+ppoint_seed(
+ppoint *s,
+fxpos *fxlist, /* List of existing fixed points */
+int fxno /* Number in fixed list */
+) {
+ int e, di = s->di;
+ int i, j;
+
+ if (fxno > 0) {
+ co *pp;
+
+ /* Place all the fixed points at the start of the list */
+ if ((pp = (co *)malloc(fxno * sizeof(co))) == NULL)
+ error ("ppoint: malloc failed on %d fixed nodes",fxno);
+
+ for (i = 0; (i < fxno) && (i < s->tinp); i++) {
+ node *p = &s->list[i]; /* Destination for point */
+
+ for (e = 0; e < di; e++)
+ p->p[e] = fxlist[i].p[e];
+
+ p->fx = 1; /* is a fixed point */
+ s->percept(s->od, p->v, p->p);
+
+ for (e = 0; e < di; e++) {
+ pp[i].p[e] = p->p[e];
+ pp[i].v[e] = p->v[e];
+ }
+ }
+ s->np = s->fnp = i;
+
+ /* Add new points to rspl interpolation */
+ s->g->add_rspl(s->g, 0, pp, i);
+
+ free(pp);
+ }
+
+ /* Seed the remainder points randomly */
+ i = 0;
+ while(s->np < s->tinp) {
+
+
+#ifdef NEVER
+ node *p = &s->list[s->np];
+ double sum;
+
+ /* Add random points */
+ for (sum = 0.0, e = 0; e < di; e++)
+ sum += p->p[e] = d_rand(0.0, 1.0);
+
+ if (sum > s->ilimit)
+ continue;
+ s->np++;
+ i++;
+ printf("%cAdded: %d",cr_char,i);
+#else
+
+#ifdef NEVER
+ int nn;
+ co pp[WPOINTS]; /* Space for return values */
+
+ /* Add points at location with the largest error */
+ nn = WPOINTS;
+
+ if ((s->np + nn) > s->tinp) /* Limit to desired value */
+ nn = s->tinp - s->np;
+ nn = ppoint_find_worst(s, pp, nn);
+
+ /* Add new points to rspl interpolation and far field */
+ s->g->add_rspl(s->g, 0, pp, nn);
+ add_dist_points(s, pp, nn);
+#else
+ /* Diagnostic version */
+ int nn;
+ co pp[WPOINTS]; /* Space for return values */
+ double err1[WPOINTS];
+ double err2[WPOINTS];
+
+ nn = WPOINTS;
+
+ if ((s->np + nn) > s->tinp) /* Limit to desired value */
+ nn = s->tinp - s->np;
+ nn = ppoint_find_worst(s, pp, nn);
+
+ for (j = 0; j < nn; j++)
+ err1[j] = ppoint_ierr(s, pp[j].p);
+
+ /* Add new points to rspl interpolation and far field */
+ s->g->add_rspl(s->g, 0, pp, nn);
+ add_dist_points(s, pp, nn);
+
+ for (j = 0; j < nn; j++)
+ err2[j] = ppoint_ierr(s, pp[j].p);
+
+ for (j = 0; j < nn; j++)
+ printf("~1 improvement after adding point is %f to %f\n",err1[j],err2[j]);
+#endif
+ /* Copy points into ppoint */
+ for (j = 0; j < nn; j++) {
+ for (e = 0; e < di; e++) {
+ s->list[s->np].p[e] = pp[j].p[e];
+ s->list[s->np].v[e] = pp[j].v[e];
+ }
+ s->np++;
+ }
+ i += nn;
+ printf("%cAdded: %d",cr_char,i);
+#endif
+ }
+ printf("\n"); /* Finish "Added:" */
+}
+
+/* --------------------------------------------------- */
+
+/* Rest the read index */
+static void
+ppoint_reset(ppoint *s) {
+ s->rix = 0;
+}
+
+/* Read the next non-fixed point value */
+/* Return nz if no more */
+static int
+ppoint_read(ppoint *s, double *p, double *f) {
+ int e;
+
+ /* Advance to next non-fixed point */
+ while(s->rix < s->np && s->list[s->rix].fx)
+ s->rix++;
+
+ if (s->rix >= s->np)
+ return 1;
+
+ /* Return point info to caller */
+ for (e = 0; e < s->di; e++) {
+ if (p != NULL)
+ p[e] = s->list[s->rix].p[e];
+ if (f != NULL)
+ f[e] = s->list[s->rix].v[e];
+ }
+ s->rix++;
+
+ return 0;
+}
+
+/* Destroy ourselves */
+static void
+ppoint_del(ppoint *s) {
+
+ /* Free our nodes */
+ free(s->list);
+
+ /* Free our rspl interpolation */
+ s->g->del(s->g);
+
+ /* Free our perceptual distance grid */
+ s->pd->del(s->pd);
+
+ free (s);
+}
+
+/* Creator */
+ppoint *new_ppoint(
+int di, /* Dimensionality of device space */
+double ilimit, /* Ink limit (sum of device coords max) */
+int tinp, /* Total number of points to generate, including fixed */
+fxpos *fxlist, /* List of existing fixed points (may be NULL) */
+int fxno, /* Number of existing fixes points */
+void (*percept)(void *od, double *out, double *in), /* Perceptual lookup func. */
+void *od /* context for Perceptual function */
+) {
+ ppoint *s;
+
+ // ~~~99 Info for logging
+ fprintf(stderr, "WPOINTS = %d\n",WPOINTS);
+ fprintf(stderr, "FPOINTS = %d\n",FPOINTS);
+ fprintf(stderr, "OPOINTS = %d\n",OPOINTS);
+ fprintf(stderr, "DDMIX = %f\n",DDMIX);
+ fprintf(stderr, "DWEIGHT = %f\n",DWEIGHT);
+ fprintf(stderr, "CLOSED = %f\n",CLOSED);
+
+ if ((s = (ppoint *)calloc(sizeof(ppoint), 1)) == NULL)
+ error ("ppoint: malloc failed");
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ if (di > MXPD)
+ error ("ppoint: Can't handle di %d",di);
+
+ s->di = di;
+
+ if (tinp < fxno) /* Make sure we return at least the fixed points */
+ tinp = fxno;
+
+ s->tinp = tinp; /* Target total number of points */
+ s->ilimit = ilimit;
+
+ /* Init method pointers */
+ s->reset = ppoint_reset;
+ s->read = ppoint_read;
+ s->stats = ppoint_stats;
+ s->del = ppoint_del;
+
+ /* If no perceptual function given, use default */
+ if (percept == NULL) {
+ s->percept = default_ppoint_to_percept;
+ s->od = s;
+ } else {
+ s->percept = percept;
+ s->od = od;
+ }
+
+ /* Allocate the list of points */
+ s->np = 0;
+
+ if ((s->list = (node *)calloc(sizeof(node), tinp)) == NULL)
+ error ("ppoint: malloc failed on nodes");
+
+ /* Setup the interpolation and perceptual distance rspls */
+ {
+ int e;
+ int tres, gres[MXDI];
+ datai pl,ph;
+ datai vl,vh;
+ double avgdev[MXDO];
+ pdatas pdd; /* pd callback context */
+
+#ifndef NEVER /* High res. */
+ if (di <= 2)
+ tres = 41; /* Make depend on no points and dim ? */
+ else if (di <= 3)
+ tres = 33; /* Make depend on no points and dim ? */
+ else
+ tres = 15;
+#else
+ if (di <= 2)
+ tres = 3; /* Make depend on no points and dim ? */
+ else if (di <= 3)
+ tres = 17; /* Make depend on no points and dim ? */
+ else
+ tres = 9;
+#endif
+
+ /* The interpolation grid mimics the operation of the profile */
+ /* package creating a device to CIE mapping for the device from */
+ /* the given test points. */
+ s->g = new_rspl(RSPL_NOFLAGS, di, di);
+
+ for (e = 0; e < di; e++) {
+ pl[e] = 0.0;
+ ph[e] = 1.0;
+ if (e == 1 || e == 2) { /* Assume Lab */
+ vl[e] = -128.0;
+ vh[e] = 128.0;
+ } else {
+ vl[e] = 0.0;
+ vh[e] = 100.0;
+ }
+ gres[e] = tres;
+ avgdev[e] = 0.005;
+ }
+
+ /* Setup other details of rspl */
+ s->g->fit_rspl(s->g,
+ RSPL_INCREMENTAL |
+ /* RSPL_EXTRAFIT | */ /* Extra fit flag */
+ 0,
+ NULL, /* No test points initialy */
+ 0, /* No test points */
+ pl, ph, gres, /* Low, high, resolution of grid */
+ vl, vh, /* Data scale */
+ 0.3, /* Smoothing */
+ avgdev, /* Average Deviation */
+ NULL);
+
+
+ /* Track closest perceptual distance to existing test points. */
+ /* To save looking up the perceptual value for every grid location */
+ /* every time a point is added, cache this values in the grid too. */
+ s->pd = new_rspl(RSPL_NOFLAGS, di, di+1);
+
+ /* Initialise the pd grid ready for the first points. */
+ pdd.s = s;
+ pdd.init = 1; /* Initialise values in the grid */
+
+ s->pd->set_rspl(s->pd,
+ 0, /* No special flags */
+ &pdd, /* Callback function context */
+ pdfunc1, /* Callback function */
+ pl, ph, gres, /* Low, high, resolution of grid */
+ vl, vh); /* Data scale */
+
+ s->wfpd = -1.0; /* Impossibly good worst point distance */
+ }
+
+ /* Create the points */
+ ppoint_seed(s, fxlist, fxno);
+
+ /* Print some stats */
+ ppoint_stats(s);
+
+ ppoint_reset(s); /* Reset read index */
+
+ return s;
+}
+
+/* =================================================== */
+
+#ifdef STANDALONE_TEST
+
+/* Graphics Gems curve */
+static double gcurve(double vv, double g) {
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ return vv;
+}
+
+#ifdef NEVER
+static void sa_percept(void *od, double *out, double *in) {
+ double lab[3];
+
+ clu->dev_to_rLab(clu, lab, in);
+
+ out[0] = lab[0];
+// out[1] = (lab[1]+100.0)/2.0;
+ out[1] = (lab[2]+100.0)/2.0;
+}
+#else
+
+static void sa_percept(void *od, double *p, double *d) {
+
+#ifndef NEVER
+ /* Default Do nothing - copy device to perceptual. */
+ p[0] = 100.0 * gcurve(d[0], -4.5);
+ p[1] = 100.0 * gcurve(d[1], 2.8);
+ p[1] = 0.8 * p[1] + 0.2 * p[0];
+#else
+ for (e = 0; e < di; e++) {
+ double tt = d[e];
+ /* Two slopes with a sharp turnover in X */
+ if (e == 0) {
+ if (tt < 0.5)
+ tt = tt * 0.3/0.5;
+ else
+ tt = 0.3 + ((tt-0.5) * 0.7/0.5);
+ }
+ p[e] = tt * 100.0;
+ }
+#endif
+}
+#endif
+
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int npoints = 21;
+ ppoint *s;
+ long stime,ttime;
+ error_program = argv[0];
+
+ printf("Standalone test of ppoint, argument is number of points, default %d\n",npoints);
+
+ if (argc > 1)
+ npoints = atoi(argv[1]);
+
+ /* Create the required points */
+ stime = clock();
+ s = new_ppoint(2, 1.5, npoints, NULL, 0, sa_percept, (void *)NULL);
+
+ ttime = clock() - stime;
+ printf("Execution time = %f seconds\n",ttime/(double)CLOCKS_PER_SEC);
+
+#ifdef DUMP_PLOT
+ printf("Perceptual plot:\n");
+ dump_image(s, 1);
+
+ printf("Device plot:\n");
+ dump_image(s, 0);
+#endif /* DUMP_PLOT */
+
+ s->del(s);
+
+ return 0;
+}
+
+#ifdef NEVER
+/* Basic printf type error() and warning() routines */
+#ifdef __STDC__
+void
+error(char *fmt, ...)
+#else
+void
+error(va_alist)
+va_dcl
+#endif
+{
+ va_list args;
+#ifndef __STDC__
+ char *fmt;
+#endif
+
+ fprintf(stderr,"ppoint: Error - ");
+#ifdef __STDC__
+ va_start(args, fmt);
+#else
+ va_start(args);
+ fmt = va_arg(args, char *);
+#endif
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ exit (-1);
+}
+#endif /* NEVER */
+#endif /* STANDALONE_TEST */
+
+
+#ifdef STANDALONE_TEST
+#ifdef DUMP_PLOT
+
+/* Dump the current point positions to a plot window file */
+void
+static dump_image(ppoint *s, int pcp) {
+ int i;
+ double minx, miny, maxx, maxy;
+ static double *x1a = NULL;
+ static double *y1a = NULL;
+
+ if (pcp != 0) { /* Perceptual range */
+ minx = 0.0; /* Assume */
+ maxx = 100.0;
+ miny = 0.0;
+ maxy = 100.0;
+ } else {
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 1.0;
+ maxy = 1.0;
+ }
+
+ if (x1a == NULL) {
+ if ((x1a = (double *)malloc(s->np * sizeof(double))) == NULL)
+ error ("ppoint: malloc failed");
+ if ((y1a = (double *)malloc(s->np * sizeof(double))) == NULL)
+ error ("ppoint: malloc failed");
+ }
+
+ for (i = 0; i < s->np; i++) {
+ node *p = &s->list[i];
+
+ if (pcp != 0) {
+ x1a[i] = p->v[0];
+ y1a[i] = p->v[1];
+ } else {
+ x1a[i] = p->p[0];
+ y1a[i] = p->p[1];
+ }
+ }
+
+ /* Plot the vectors */
+ do_plot_vec(minx, maxx, miny, maxy,
+ x1a, y1a, x1a, y1a, s->np, DO_WAIT, NULL, NULL, NULL, NULL, 0);
+}
+
+#endif /* DUMP_PLOT */
+#endif /* STANDALONE_TEST */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/target/ppoint.h b/target/ppoint.h
new file mode 100644
index 0000000..2a4bc52
--- /dev/null
+++ b/target/ppoint.h
@@ -0,0 +1,134 @@
+
+#ifndef PPOINT_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Perceptually distributed point class
+ *
+ * Author: Graeme W. Gill
+ * Date: 16/10/96
+ *
+ * Copyright 1996 - 2004 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.
+ */
+
+#define MXPD 4 /* Maximum ppoint dimentionality */
+#define POW2MXPD 16 /* 2 ^ MXPD */
+#define POW3MXPD 81 /* 3 ^ MXPD */
+#define MXNP (MXPD + 1 + 20) /* Maximum near points */
+
+/* tuning parameters */
+#define WPOINTS 20 /* Points returned per group */
+#define FPOINTS 5000 /* Number of far points to track - more is better. */
+#define OPOINTS 250 /* Number of optimsed far points to use - more is slower */
+#define DDMIX 0.75 /* Device distance to perceptual ratio in distance computation */
+#define DWEIGHT 0.05 /* Distance factor weight added to maximum error in opt func */
+#define CLOSED 0.05 /* Too close criteria */
+
+/* A sample point node */
+struct _node {
+ int fx; /* nz if point is fixed */
+ double p[MXPD]; /* Device coordinate position */
+ double v[MXPD]; /* Subjective value (Labk) */
+}; typedef struct _node node;
+
+/* Main perceptual point object */
+struct _ppoint {
+/* private: */
+ int di; /* Point dimensionality */
+ double ilimit; /* Ink limit - limit on sum of p[] */
+ int fnp; /* Number of existing fixed points in list */
+ int tinp; /* target number of total points in list */
+
+ node *list; /* tinp list of points */
+ int np; /* Number of points currently in list */
+
+ /* Perceptual function handed in */
+ void (*percept)(void *od, double *out, double *in);
+ void *od; /* Opaque data for perceptual point */
+
+ /* Progressive interpolation grid */
+ rspl *g;
+
+ /* Perceptual distance map */
+ rspl *pd;
+
+ /* Candidate far point starting values */
+ co fp[FPOINTS]; /* Candidate points */
+ int nfp; /* Current number in fp[] */
+ int wfp; /* Index of current worst far point */
+ double wfpd; /* worst far point distance */
+ co fwfp[FPOINTS]; /* Working space for find_worst() */
+
+ /* Other info */
+ int rix; /* Next read index */
+// double mn,mx,av; /* Perceptual distance stats */
+
+/* public: */
+ /* return non-zero if the perceptual point is within the device gammut */
+ int (*pig)(struct _ppoint *s, double *p);
+
+ /* Initialise, ready to read out all the points */
+ void (*reset)(struct _ppoint *s);
+
+ /* Read the next set of non-fixed points values */
+ /* return non-zero when no more points */
+ int (*read)(struct _ppoint *s, double *p, double *f);
+
+ /* Calculate and print stats */
+ void (*stats)(struct _ppoint *s);
+
+ /* Destroy ourselves */
+ void (*del)(struct _ppoint *s);
+
+ }; typedef struct _ppoint ppoint;
+
+
+/* Constructor */
+extern ppoint *new_ppoint(int di, double ilimit, int npoints,
+ fxpos *fxlist, int fxno,
+ void (*percept)(void *od, double *out, double *in), void *od);
+
+/* ------------------------------------------------------- */
+/* Macros for a di dimensional counter */
+/* Declare the counter name nn, dimensions di, & count */
+
+#define DCOUNT(nn, di, start, reset, count) \
+ int nn[MXPD]; /* counter value */ \
+ int nn##_di = (di); /* Number of dimensions */ \
+ int nn##_stt = (start); /* start count value */ \
+ int nn##_rst = (reset); /* reset on carry value */ \
+ int nn##_res = (count); /* last count +1 */ \
+ int nn##_e /* dimension index */
+
+/* Set the counter value to 0 */
+#define DC_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
+ nn[nn##_e] = nn##_stt; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define DC_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < nn##_res) \
+ break; /* No carry */ \
+ nn[nn##_e] = nn##_rst; \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define DC_DONE(nn) \
+ (nn##_e >= nn##_di)
+
+/* ------------------------------------------------------- */
+
+#define PPOINT_H
+#endif /* PPOINT_H */
diff --git a/target/prand.c b/target/prand.c
new file mode 100644
index 0000000..927243a
--- /dev/null
+++ b/target/prand.c
@@ -0,0 +1,604 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Perceptual space random test point class
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/9/2004
+ *
+ * Copyright 2004, 2009 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.
+ */
+
+
+/* TTBD:
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#ifdef DEBUG
+#include "plot.h"
+#endif
+#include "numlib.h"
+#include "sort.h"
+#include "plot.h"
+#include "icc.h"
+#include "xicc.h"
+#include "xcolorants.h"
+#include "targen.h"
+#include "prand.h"
+
+static int prand_from_percept( prand *s, double *p, double *v);
+
+/* ----------------------------------------------------- */
+
+/* Default convert the nodes device coordinates into approximate perceptual coordinates */
+/* (usually overriden by caller supplied function) */
+static void
+default_prand(void *od, double *p, double *d) {
+ prand *s = (prand *)od;
+ int e;
+
+ /* Default Do nothing - copy device to perceptual. */
+ for (e = 0; e < s->di; e++) {
+ p[e] = d[e] * 100.0;
+ }
+}
+
+/* Return the largest distance of the point outside the device gamut. */
+/* This will be 0 if inside the gamut, and > 0 if outside. */
+static double
+prand_in_dev_gamut(prand *s, double *d) {
+ int e;
+ int di = s->di;
+ double tt, dd = 0.0;
+ double ss = 0.0;
+
+ for (e = 0; e < di; e++) {
+ ss += d[e];
+
+ tt = 0.0 - d[e];
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ tt = d[e] - 1.0;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ }
+ tt = ss - s->ilimit;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ return dd;
+}
+
+/* --------------------------------------------------- */
+/* Seed the object with the initial fixed points */
+
+static void
+prand_add_fixed(
+prand *s,
+fxpos *fxlist, /* List of existing fixed points */
+int fxno /* Number in fixed list */
+) {
+ int e, di = s->di;
+ int i;
+
+ /* Add fixed points if there are any */
+ if (fxno > 0) {
+
+ for (i = 0; (i < fxno) && (i < s->tinp); i++) {
+ prnode *p = &s->n[i]; /* Destination for point */
+
+ for (e = 0; e < di; e++)
+ p->p[e] = fxlist[i].p[e];
+
+ p->fx = 1; /* is a fixed point */
+ s->percept(s->od, p->v, p->p);
+ s->np = s->fnp = i+1;
+ }
+ }
+}
+
+/* Seed the object with the perceptual space random points. */
+static void
+prand_seed(prand *s) {
+ int e, di = s->di;
+
+ printf("\n");
+
+ /* Seed the non-fixed points */
+ for (; s->np < s->tinp;) {
+ prnode *p = &s->n[s->np]; /* Next node */
+
+ for (e = 0; e < di; e++) {
+ if (e == 1 || e == 2)
+ p->v[e] = d_rand(-128.0, 128.0);
+ else
+ p->v[e] = d_rand(0.0, 100.0);
+ }
+ if (prand_from_percept(s, p->p, p->v) == 0) {
+ s->np++;
+ printf("%cAdded %d/%d",cr_char,s->np,s->tinp); fflush(stdout);
+ }
+ }
+ printf("\n");
+}
+
+/* Seed the object with the perceptual space quasi random points. */
+static void
+pqrand_seed(prand *s) {
+ int e, di = s->di;
+ sobol *sl = NULL;
+
+ if ((sl = new_sobol(di)) == NULL)
+ error("Creating sobol sequence generator failed");
+
+ printf("\n");
+
+ /* Seed the non-fixed points */
+ for (; s->np < s->tinp;) {
+ prnode *p = &s->n[s->np]; /* Next node */
+
+ if (sl->next(sl, p->v))
+ error("Run out of sobol random numbers!");
+
+ for (e = 0; e < di; e++) {
+ if (e == 1 || e == 2)
+ p->v[e] = p->v[e] * 256.0 - 128.0;
+ else
+ p->v[e] *= 100.0;
+ }
+ if (prand_from_percept(s, p->p, p->v) == 0) {
+ s->np++;
+ printf("%cAdded %d/%d",cr_char,s->np,s->tinp); fflush(stdout);
+ }
+ }
+ printf("\n");
+ sl->del(sl);
+}
+
+/* --------------------------------------------------- */
+/* Support accessing the list of generated sample points */
+
+/* Rest the read index */
+static void
+prand_reset(prand *s) {
+ s->rix = 0;
+}
+
+/* Read the next non-fixed point value */
+/* Return nz if no more */
+static int
+prand_read(prand *s, double *p, double *f) {
+ int e;
+
+ /* Advance to next non-fixed point */
+ while(s->rix < s->np && s->n[s->rix].fx)
+ s->rix++;
+
+ if (s->rix >= s->np)
+ return 1;
+
+ /* Return point info to caller */
+ for (e = 0; e < s->di; e++) {
+ if (p != NULL)
+ p[e] = s->n[s->rix].p[e];
+ if (f != NULL)
+ f[e] = s->n[s->rix].v[e];
+ }
+ s->rix++;
+
+ return 0;
+}
+
+/* --------------------------------------------------- */
+/* Main object creation/destruction */
+
+static void init_pmod(prand *s);
+
+/* Destroy ourselves */
+static void
+prand_del(prand *s) {
+ free(s->n);
+
+ if (s->pmod != NULL)
+ free(s->pmod);
+
+ free (s);
+}
+
+/* Creator */
+prand *new_prand(
+int di, /* Dimensionality of device space */
+double ilimit, /* Ink limit (sum of device coords max) */
+int tinp, /* Total number of points to generate, including fixed */
+fxpos *fxlist, /* List of existing fixed points (may be NULL) */
+int fxno, /* Number of existing fixes points */
+int quasi, /* nz to use quasi random (sobol) */
+void (*percept)(void *od, double *out, double *in), /* Perceptual lookup func. */
+void *od /* context for Perceptual function */
+) {
+ prand *s;
+
+ if ((s = (prand *)calloc(sizeof(prand), 1)) == NULL)
+ error ("prand: malloc failed");
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ s->di = di;
+
+ if (tinp < fxno) /* Make sure we return at least the fixed points */
+ tinp = fxno;
+
+ s->tinp = tinp; /* Target total number of points */
+ s->ilimit = ilimit;
+
+ /* Init method pointers */
+ s->reset = prand_reset;
+ s->read = prand_read;
+ s->del = prand_del;
+
+ /* If no perceptual function given, use default */
+ if (percept == NULL) {
+ s->percept = default_prand;
+ s->od = s;
+ } else {
+ s->percept = percept;
+ s->od = od;
+ }
+
+ /* Init the inverse perceptual function lookup */
+ init_pmod(s);
+
+ /* Allocate the space for the target number of points */
+ if ((s->n = (prnode *)calloc(sizeof(prnode), s->tinp)) == NULL)
+ error ("prand: malloc failed on sample nodes");
+ s->np = s->fnp = 0;
+
+ /* Setup the fixed points */
+ prand_add_fixed(s, fxlist, fxno);
+
+ if (tinp > fxno) { /* Create the perceptual space random points */
+ if (quasi)
+ pqrand_seed(s);
+ else
+ prand_seed(s);
+ }
+
+ prand_reset(s); /* Reset read index */
+
+ return s;
+}
+
+/* =================================================== */
+/* Compute a simple but unbounded model of the */
+/* perceptual function, used by inversion. We use the */
+/* current vertex values to setup the model */
+/* (Perhaps this should be moved to targen ?) */
+
+/* A vertex point */
+struct _vxpt {
+ double p[MXTD]; /* Device position */
+ double v[MXTD]; /* Perceptual value */
+}; typedef struct _vxpt vxpt;
+
+/* Structure to hold data for unbounded optimization function */
+struct _ubfit {
+ prand *s; /* prand structure */
+ vxpt *vxs; /* List of vertex values */
+ int _nvxs, nvxs;
+}; typedef struct _ubfit ubfit;
+
+/* Matrix optimisation function handed to powell() */
+static double xfitfunc(void *edata, double *x) {
+ ubfit *uf = (ubfit *)edata;
+ prand *s = uf->s;
+ int i, e, di = s->di;
+ double rv = 0.0;
+
+ /* For all the vertexes */
+ for (i = 0; i < uf->nvxs; i++) {
+ double v[MXTD], ev;
+
+ /* Apply matrix cube interpolation */
+ icxCubeInterp(x, di, di, v, uf->vxs[i].p);
+
+ /* Evaluate the error */
+ for (ev = 0.0, e = 0; e < di; e++) {
+ double tt;
+ tt = uf->vxs[i].v[e] - v[e];
+ ev += tt * tt;
+ }
+ rv += ev;
+ }
+ return rv;
+}
+
+/* Fit the unbounded perceptual model to the perceptual function */
+static void init_pmod(prand *s) {
+ int i, ee, e, k, di = s->di;
+ double *sa;
+ double rerr;
+ ubfit uf;
+
+ uf.s = s;
+ uf.vxs = NULL;
+ uf.nvxs = uf._nvxs = 0;
+
+ /* Allocate space for parameters */
+ if ((s->pmod = malloc(di * (1 << di) * sizeof(double))) == NULL)
+ error("Malloc failed for pmod");
+ if ((sa = malloc(di * (1 << di) * sizeof(double))) == NULL)
+ error("Malloc failed for pmod sa");
+
+ /* Create a list of vertex values for the colorspace */
+ /* Use in gamut vertexes, and compute clipped edges */
+ for (ee = 0; ee < (1 << di); ee++) {
+ double p[MXTD], ss;
+
+ for (ss = 0.0, e = 0; e < di; e++) {
+ if (ee & (1 << e))
+ p[e] = 1.0;
+ else
+ p[e] = 0.0;
+ ss += p[e];
+ }
+ if (ss < s->ilimit) { /* Within gamut */
+ if (uf.nvxs >= uf._nvxs) {
+ uf._nvxs = 5 + uf._nvxs * 2;
+ if ((uf.vxs = (vxpt *)realloc(uf.vxs, sizeof(vxpt) * uf._nvxs)) == NULL)
+ error ("Failed to malloc uf.vxs");
+ }
+ for (k = 0; k < di; k++)
+ uf.vxs[uf.nvxs].p[k] = p[k];
+ uf.nvxs++;
+ } else if ((ss - 1.0) < s->ilimit) { /* far end of edge out of gamut */
+ double max = s->ilimit - (ss - 1.0); /* Maximum value of one */
+ for (e = 0; e < di; e++) {
+ if ((ee & (1 << e)) == 0)
+ continue;
+ p[e] = max;
+ if (uf.nvxs >= uf._nvxs) {
+ uf._nvxs = 5 + uf._nvxs * 2;
+ if ((uf.vxs = (vxpt *)realloc(uf.vxs, sizeof(vxpt) * uf._nvxs)) == NULL)
+ error ("Failed to malloc uf.vxs");
+ }
+ for (k = 0; k < di; k++)
+ uf.vxs[uf.nvxs].p[k] = p[k];
+ uf.nvxs++;
+
+ p[e] = 1.0; /* Restore */
+ }
+ } /* Else whole edge is out of gamut */
+ }
+
+ /* Lookup perceptual values */
+ for (i = 0; i < uf.nvxs; i++) {
+ s->percept(s->od, uf.vxs[i].v, uf.vxs[i].p);
+//printf("~1 vtx %d: dev %f %f %f, perc %f %f %f\n",i, uf.vxs[i].p[0], uf.vxs[i].p[1], uf.vxs[i].p[2], uf.vxs[i].v[0], uf.vxs[i].v[1], uf.vxs[i].v[2]);
+ }
+
+ /* Setup matrix to be closest values initially */
+ for (e = 0; e < (1 << di); e++) { /* For each colorant combination */
+ int j, f;
+ double bdif = 1e6;
+ double ov[MXTD];
+ int bix = -1;
+
+ /* Search the vertex list to find the one closest to this input combination */
+ for (i = 0; i < uf.nvxs; i++) {
+ double dif = 0.0;
+
+ for (j = 0; j < di; j++) {
+ double tt;
+ if (e & (1 << j))
+ tt = 1.0 - uf.vxs[i].p[j];
+ else
+ tt = 0.0 - uf.vxs[i].p[j];
+ dif += tt * tt;
+ }
+ if (dif < bdif) { /* best so far */
+ bdif = dif;
+ bix = i;
+ if (dif < 0.001)
+ break; /* Don't bother looking further */
+ }
+ }
+ for (f = 0; f < di; f++)
+ s->pmod[f * (1 << di) + e] = uf.vxs[bix].v[f];
+ }
+
+ for (e = 0; e < (di * (1 << di)); e++)
+ sa[e] = 10.0;
+
+ if (powell(&rerr, di * (1 << di), s->pmod, sa, 0.001, 1000,
+ xfitfunc, (void *)&uf, NULL, NULL) != 0) {
+ warning("Powell failed to converge, residual error = %f",rerr);
+ }
+
+#ifdef DEBUG
+ printf("Perceptual model fit residual = %f\n",sqrt(rerr));
+#endif
+ s->pmod_init = 1;
+
+ free(sa);
+}
+
+/* Clip a device value to the gamut */
+static int
+prand_clip_point(prand *s, double *cd, double *d) {
+ int e, di = s->di;
+ double ss = 0.0;
+ int rv = 0;
+
+ for (e = 0; e < di; e++) {
+ ss += d[e];
+ cd[e] = d[e];
+ if (cd[e] < 0.0) {
+ cd[e] = 0.0;
+ rv |= 1;
+ } else if (cd[e] > 1.0) {
+ cd[e] = 1.0;
+ rv |= 1;
+ } \
+ }
+
+ if (ss > s->ilimit) {
+ ss = (ss - s->ilimit)/s->di;
+ for (e = 0; e < di; e++)
+ cd[e] -= ss;
+ rv |= 1;
+ }
+ return rv;
+}
+
+/* Unbounded perceptual lookup. */
+/* return nz if it was actually clipped and extended */
+static int prand_cc_percept(prand *s, double *v, double *p) {
+ double cp[MXTD];
+ int clip;
+
+ clip = prand_clip_point(s, cp, p);
+
+ s->percept(s->od, v, cp);
+
+ /* Extend perceptual value using matrix model */
+ if (clip) {
+ int e, di = s->di;
+ double mcv[MXTD], zv[MXTD];
+
+#ifdef DEBUG
+ if (s->pmod_init == 0)
+ error("ofps_cc_percept() called before pmod has been inited");
+#endif
+ /* Lookup matrix mode of perceptual at clipped device */
+ icxCubeInterp(s->pmod, di, di, mcv, cp);
+
+ /* Compute a correction factor to add to the matrix model to */
+ /* give the actual perceptual value at the clipped location */
+ for (e = 0; e < di; e++)
+ zv[e] = v[e] - mcv[e];
+
+ /* Compute the unclipped matrix model perceptual value */
+ icxCubeInterp(s->pmod, di, di, v, p);
+
+ /* Add the correction value to it */
+ for (e = 0; e < di; e++)
+ v[e] += zv[e];
+ }
+ return clip;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Reverse lookup function :- perceptual to device coordinates */
+/* Using dnsq */
+
+/* Structure to hold data for optimization function */
+struct _rdatas {
+ prand *s; /* prand structure */
+ double *ptv; /* Perceptual target value */
+}; typedef struct _rdatas rdatas;
+
+
+/* calculate the functions at x[] */
+int prand_dnsq_solver( /* Return < 0 on abort */
+ void *fdata, /* Opaque data pointer */
+ int n, /* Dimenstionality */
+ double *x, /* Multivariate input values */
+ double *fvec, /* Multivariate output values */
+ int iflag /* Flag set to 0 to trigger debug output */
+) {
+ rdatas *ed = (rdatas *)fdata;
+ prand *s = ed->s;
+ double v[MXTD];
+ int e, di = s->di;
+
+ prand_cc_percept(s, v, x);
+
+ for (e = 0; e < di; e++)
+ fvec[e] = ed->ptv[e] - v[e];
+
+//printf("~1 %f %f %f from %f %f %f\n", fvec[0], fvec[1], fvec[2], x[0], x[1], x[2]);
+ return 0;
+}
+
+/* Given a point in perceptual space, an approximate point */
+/* in device space, return the device value corresponding to */
+/* the perceptual value, plus the clipped perceptual value. */
+/* Return 1 if the point is out of gamut or dnsq failed. */
+static int
+prand_from_percept(
+prand *s,
+double *p, /* return (clipped) device position */
+double *v /* target perceptual */
+) {
+ int e, di = s->di;
+ rdatas ed;
+ double ss; /* Initial search area */
+ double fvec[MXTD]; /* Array that will be RETURNed with thefunction values at the solution */
+ double dtol; /* Desired tollerance of the solution */
+ double tol; /* Desired tollerance of root */
+ int maxfev; /* Maximum number of function calls. set to 0 for automatic */
+ int rv;
+
+//printf("~1 percept2 called with %f %f %f\n", v[0], v[1], v[2]);
+ ed.s = s;
+ ed.ptv = v; /* Set target perceptual point */
+
+ for (e = 0; e < di; e++)
+ p[e] = 0.3; /* Start location */
+ ss = 0.1;
+ dtol = 1e-6;
+ tol = 1e-8;
+ maxfev = 1000;
+
+ rv = dnsqe((void *)&ed, prand_dnsq_solver, NULL, di, p, ss, fvec, dtol, tol, maxfev, 0);
+
+ if (rv != 1 && rv != 3) { /* Fail to converge */
+//printf("~1 failed with rv %d\n",rv);
+ return 1;
+ }
+
+//printf("~1 got soln %f %f %f\n", p[0], p[1], p[2]);
+ if (prand_clip_point(s, p, p)) {
+//printf("~1 clipped\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/target/prand.h b/target/prand.h
new file mode 100644
index 0000000..d7e50eb
--- /dev/null
+++ b/target/prand.h
@@ -0,0 +1,68 @@
+
+#ifndef PRAND_H
+
+/*
+ * Argyll Color Correction System
+ *
+ * Perceptual space random test point class
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/9/2004
+ *
+ * Copyright 2004 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.
+ */
+
+/* A sample point node */
+struct _prnode {
+ int fx; /* nz if point is fixed */
+ double p[MXTD]; /* Device coordinate position */
+ double v[MXTD]; /* Subjective value (Labk) */
+}; typedef struct _prnode prnode;
+
+
+/* Main object */
+struct _prand {
+/* private: */
+ int di; /* Point dimensionality */
+ double ilimit; /* Ink limit - limit on sum of p[] */
+ int fnp; /* Number of existing fixed points in list */
+ int tinp; /* target number of total points in list, including fixed points */
+
+ int np; /* Number of points currently in list */
+ prnode *n; /* tinp list of points */
+
+ /* Perceptual function handed in */
+ void (*percept)(void *od, double *out, double *in);
+ void *od; /* Opaque data for perceptual point */
+
+ /* Unbounded perceptual model */
+ double *pmod;
+ int pmod_init; /* It's been initialised */
+
+ /* Other info */
+ int rix; /* Next read index */
+
+/* public: */
+ /* Initialise, ready to read out all the points */
+ void (*reset)(struct _prand *s);
+
+ /* Read the next set of non-fixed points values */
+ /* return non-zero when no more points */
+ int (*read)(struct _prand *s, double *d, double *p);
+
+ /* Destroy ourselves */
+ void (*del)(struct _prand *s);
+
+ }; typedef struct _prand prand;
+
+/* Constructor */
+extern prand *new_prand(int di, double ilimit, int npoints,
+ fxpos *fxlist, int fxno, int quasi,
+ void (*percept)(void *od, double *out, double *in), void *od);
+
+#define PRAND_H
+#endif /* PRAND_H */
diff --git a/target/printtarg.c b/target/printtarg.c
new file mode 100644
index 0000000..25d889a
--- /dev/null
+++ b/target/printtarg.c
@@ -0,0 +1,4300 @@
+
+/*
+ * Argyll Color Correction System
+ * PostScript print chart generator module.
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/96
+ *
+ * Copyright 1996 - 2009 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.
+ */
+
+/*
+
+ TTBD:
+
+ Add "single pixel patch" mode, for pure digital processing for
+ abstract profile creation.
+
+ Add -h2 flag for Munki for super high-res chart ?
+ Note: i1Pro: Illum spot: 3.5mm Aperture: 4.5mm, Physical aperture: 4.55mm
+ Munki: Illum spot: 8.0mm Aperture: 6.0mm, Physical aperture: 7.63mm
+
+ Add an option that allows including a scale gauge, to detect
+ accidental re-scaling.
+
+ Make it aportion extra space evenly around the chart
+ rather than at the trailing edges.
+
+ Add direct PDF support, including NChannel output.
+*/
+
+/* This program generates a PostScript or TIFF print target file, */
+/* containing color test patches, given the .ti1 file specifying */
+/* what the colors are. */
+
+/* The output is designed to suite a general XY spectrometer (such as */
+/* the Gretag SpectrScan), a handheld, manual instrument, or */
+/* an Xrite DTP51, DTP41 or Eye-One strip spectrometer. */
+
+/* Description:
+
+ This program simply generates a PostScripto or TIFF file containing
+ the patches layed out for an Xrite DTP20/DTP22/DTP51/DTP41/SpectroScan/i1pro/Munki.
+ It allows them to be layed out on a choice of paper sizes,
+ with the appropriate contrasting color spacers between
+ each patch for the strip reading instruments. Unlike other
+ charts, Argyll charts are generated as required, rather
+ that being fixed. Also unlike most other strip reading charts,
+ the spacers may colored, so that the density contrast ratio is
+ guaranteed, even when two patches are about 50% density.
+
+ Another feature is the pseudo random patch layout. This has
+ three purposes. One is to try and average out any variation
+ in the device response in relationship to the location of
+ the patch on the paper. Color copiers and printing presses
+ (for instance), are notorious in having side to side density
+ variations.
+
+ Another purpose of the random patch layout, is that it gives
+ the reading program a good mechanism for detecting user error.
+ It can guess the expected values, compare them to the readings,
+ and complain if it seems that the strip is probably the wrong
+ one. It can also be used to identify and rectify a strip
+ that has been read in backwards.
+
+ The final purpose of the random patch layout is to optimse the
+ contrast between patches in a strip, to improve the robustness
+ of the strip reading, and to be able to distinguish the directin
+ a strip has been read in. Using this, small charts may be even be
+ generated without any gaps between the test patches.
+
+ */
+
+/*
+ * Nomencalture:
+ *
+ * Largely due to how the strip readers name things, the following terms
+ * are used for how patches are grouped:
+ *
+ * Pass, Row: One row of patches in a strip. A pass is usually labeled
+ * with a unique alphabetic label.
+ * Strip: A group of passes that can be read by a strip reader.
+ * For an XY instrument, the strip is a complete sheet, and
+ * each pass is one column. The rows of an XY chart are
+ * the step numbers within a pass.
+ * Step: One test patch in a pass.
+ * Sheet: One sheet of paper, containing full and partial strips.
+ * For an XY instrument, there will be only one strip per sheet.
+ *
+ */
+
+/* TTBD:
+ *
+ * Improve EPS support to add a preview to each eps file.
+ */
+
+#undef DEBUG
+#undef FORCEN /* For testing, force DeviceN */
+#define DEN_COMPRESS /* Compress density estimates > 1.0 */
+ /* - this biases it towards white spacers */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <ctype.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "cgats.h"
+#include "icc.h"
+#include "xicc.h"
+#include "insttypes.h"
+#include "render.h"
+#include "randix.h"
+#include "alphix.h"
+#include "rspl.h"
+#include "sort.h"
+
+#include <stdarg.h>
+
+/* Convert inches into mm */
+#define inch2mm(xx) ((xx) * 25.4)
+
+/* Convert mm into points */
+#define mm2pnt(xx) ((xx) * 72.0/25.4)
+
+/* A color structure */
+struct _col {
+ int nmask; /* colorant mask */
+ int altrep; /* alternate grey or CMY representation type 0..8 */
+ int i; /* cols list index */
+ int ix; /* random list index */
+ char *id; /* Id string */
+ char loc[10]; /* Location ID string */
+ int t; /* Tag */
+#define T_XYZ 0x0001
+#define T_LAB 0x0002
+#define T_DEN 0x0004
+#define T_RGB 0x0008
+#define T_N 0x0010
+#define T_NFB 0x2000 /* DeviceN fallback enabled */
+#define T_PRESET 0x4000 /* A preset color rather than a test patch */
+#define T_PAD 0x8000 /* A padding color patch */
+ double XYZ[3]; /* Aproximate XYZ */
+ double Lab[3]; /* Aproximate Lab */
+ double den[4]; /* Approx statusT density + visual density */
+ int dtp20_octval; /* DTP20 octal value */
+ double dtp20_psize; /* DTP20 patch width */
+ double rgb[3]; /* Aproximate sRGB */
+ int n; /* Number of colorants */
+ double dev[ICX_MXINKS]; /* Value of colorants */
+
+ struct _col *nc[2]; /* Neigborhood colors */
+ struct _col *oc; /* Opposite direction color */
+ double wnd; /* Worst neigborhood contrast density */
+}; typedef struct _col col;
+
+#define min2(a,b) ((a) < (b) ? (a) : (b))
+#define min3(a,b,c) (min2((a), min2((b),(c))))
+#define max2(a,b) ((a) > (b) ? (a) : (b))
+#define max3(a,b,c) (max2((a), max2((b),(c))))
+
+/* Declare edge tracking functions */
+void et_init(void);
+void et_height(double height);
+void et_media(double *rgb);
+void et_color(double *rgb);
+void et_edge(int isx, int negh, double mj, double mi0, double mi1);
+void et_patch(char *id, double xo, double yo, double w, double h);
+void et_fiducial(double x, double y);
+void et_write(char *fname, col *cols, int *rix, int si, int ei);
+void et_clear(void);
+
+/* ====================================================== */
+/* Calibration Target rendering class */
+/* Outputs either PostScript or TIFF raster */
+/* test charts. */
+/* We just do an error() if something goes wrong */
+
+/* Common class structure */
+#define TREND_STRUCT \
+ /* Start a page */ \
+ void (*startpage)(struct _trend *s, int pn); \
+ /* End a page */ \
+ void (*endpage)(struct _trend *s); \
+ /* set the color */ \
+ void (*setcolor)(struct _trend *s, xcal *cal, col *c); \
+ /* A rectangle, with optional edge tracking */ \
+ void (*rectangle)(struct _trend *s, /* Render a rectangle */ \
+ double x, double y, /* Top left corner of rectangle in mm from origin */ \
+ double w, double h, /* Width and height */ \
+ char *id, /* Patch id, NULL if not a diagnostic mark */ \
+ int et /* nz if use edge tracking on this */ \
+ ); \
+ /* A testpad hexagon. */ \
+ void (*hexagon)(struct _trend *s, \
+ double x, double y, /* Top left vertex of hex mm from origin */ \
+ double w, double h, /* Width and height */ \
+ int step, /* Step number from 0 to figure odd/even */ \
+ char *id /* Patch id, NULL if not a diagnostic mark */ \
+ ); \
+ /* A centered string */ \
+ void (*string)(struct _trend *s, \
+ double x, double y, /* Bot Left Corner of rectangle in mm from origin */ \
+ double w, double h, /* Width and height */ \
+ char *str /* String */ \
+ ); \
+ /* A vertically centered string, rendered from bottom to top */ \
+ void (*vstring)(struct _trend *s, \
+ double x, double y, /* Bot Right Corner of rectangle in mm from origin */ \
+ double w, double h, /* Width and height */ \
+ char *str /* String */ \
+ ); \
+ /* A dotted line */ \
+ void (*dline)(struct _trend *s, \
+ double x0, double y0, /* Start of line */ \
+ double x1, double y1, /* End of line */ \
+ double w /* Width */ \
+ ); \
+ /* Delete the object */ \
+ void (*del)(struct _trend *s); \
+
+struct _trend {
+ TREND_STRUCT
+}; typedef struct _trend trend;
+
+/* ==================================== */
+/* PostScript output class */
+
+struct _ps_trend {
+ TREND_STRUCT
+ FILE *of; /* Postscript output file */
+ int eps; /* EPS flag */
+ char *fname;
+}; typedef struct _ps_trend ps_trend;
+
+/* Start a page */
+static void ps_startpage(trend *ss, int pagen) {
+ ps_trend *s = (ps_trend *)ss;
+
+ fprintf(s->of,"%%%%Page: (Page %d) %d\n",pagen,pagen);
+}
+
+/* End a page */
+static void ps_endpage(trend *ss) {
+ ps_trend *s = (ps_trend *)ss;
+
+ fprintf(s->of,"showpage\n");
+ fprintf(s->of,"\n");
+}
+
+/* Set a device N color with fallback */
+static void
+gen_ncolor(ps_trend *s, col *c) {
+ int i;
+
+ /* define the colorspace */
+ fprintf(s->of,"[ /DeviceN [ ");
+ for (i = 0; i < c->n; i++) {
+ int imask = icx_index2ink(c->nmask, i);
+ fprintf(s->of,"/%s ", icx_ink2psstring(imask));
+ }
+
+ if (c->t & T_NFB) { /* Use color fallback */
+ fprintf(s->of,"] /DeviceRGB "); /* Fallback to RGB */
+ fprintf(s->of,"{ ");
+ for (i = 0; i < c->n; i++) /* Remove N values */
+ fprintf(s->of,"pop ");
+ for (i = 0; i < 3; i++) /* Set RGB values */
+ fprintf(s->of,"%f ",c->rgb[i]);
+ } else {
+ fprintf(s->of,"] /DeviceGray "); /* Fallback to Gray */
+ fprintf(s->of,"{ ");
+ for (i = 0; i < c->n; i++) /* Remove N values */
+ fprintf(s->of,"pop ");
+ fprintf(s->of,"%f ",(c->rgb[0] + c->rgb[1] + c->rgb[2])/3.0); /* Set Gray value */
+ }
+
+ fprintf(s->of," } ] setcolorspace\n");
+
+ /* Set the color */
+ for (i = 0; i < c->n; i++)
+ fprintf(s->of,"%f ",c->dev[i]);
+ fprintf(s->of,"setcolor\n");
+}
+
+
+/* Set a device color */
+/* Set it by the rep with most components */
+static void ps_setcolor(trend *ss, xcal *cal, col *c) {
+ ps_trend *s = (ps_trend *)ss;
+ double cdev[ICX_MXINKS]; /* Calibrated device color */
+
+ if (cal != NULL)
+ cal->interp(cal, cdev, c->dev);
+ else {
+ int j;
+ for (j = 0; j < c->n; j++)
+ cdev[j] = c->dev[j];
+ }
+
+ if ((c->t & T_N) == 0)
+ error("ps_setcolor with no device values set");
+
+#ifndef FORCEN
+ if (c->nmask == ICX_W) {
+ if ((c->t & T_PRESET) == 0)
+ fprintf(s->of,"%% Ref %s %s %f\n",c->id, c->loc, 100.0 * cdev[0]);
+
+ if (c->altrep == 0) { /* DeviceGray */
+ fprintf(s->of,"%f setgray\n",cdev[0]);
+ } else if (c->altrep == 4) { /* DeviceRGB */
+ fprintf(s->of,"%f %f %f setrgbcolor\n",cdev[0],cdev[0],cdev[0]);
+ } else if (c->altrep == 5) { /* Separation */
+ fprintf(s->of,"[ /Separation (White) /DeviceGray { pop %f } ] setcolorspace\n",
+ cdev[0]);
+ fprintf(s->of,"%f setcolor\n",cdev[0]);
+ } else if (c->altrep == 6) { /* DeviceN */
+ gen_ncolor(s, c);
+ } else {
+ error("Device white encoding not approproate!");
+ }
+
+ } else if (c->nmask == ICX_K) {
+ if ((c->t & T_PRESET) == 0)
+ fprintf(s->of,"%% Ref %s %s %f\n",c->id, c->loc, 100.0 * cdev[0]);
+ if (c->altrep == 0) { /* DeviceGray */
+ fprintf(s->of,"%f setgray\n",1.0 - cdev[0]);
+ } else if (c->altrep == 1) { /* DeviceCMYK */
+ fprintf(s->of,"0.0 0.0 0.0 %f setcmykcolor\n",cdev[0]);
+ } else if (c->altrep == 2) { /* Separation */
+ fprintf(s->of,"[ /Separation (Black) /DeviceGray { pop %f } ] setcolorspace\n",
+ 1.0 - cdev[0]);
+ fprintf(s->of,"%f setcolor\n",cdev[0]);
+ } else if (c->altrep == 3) { /* DeviceN */
+ gen_ncolor(s, c);
+ } else {
+ error("Device black encoding not approproate!");
+ }
+
+ } else if (c->nmask == ICX_CMY) {
+ if ((c->t & T_PRESET) == 0)
+ fprintf(s->of,"%% Ref %s %s %f %f %f\n", c->id, c->loc,
+ 100.0 * cdev[0], 100.0 * cdev[1], 100.0 * cdev[2]);
+
+ if (c->altrep == 0) { /* DeviceCMYK */
+ fprintf(s->of,"%f %f %f 0.0 setcmykcolor\n",cdev[0],cdev[1],cdev[2]);
+ } else if (c->altrep == 7) { /* Inverted DeviceRGB */
+ fprintf(s->of,"%f %f %f setrgbcolor\n",1.0-cdev[0],1.0-cdev[1],1.0-cdev[2]);
+ } else if (c->altrep == 8) { /* DeviceN */
+ gen_ncolor(s, c);
+ } else {
+ error("Device CMY encoding not approproate!");
+ }
+
+ } else if (c->nmask == ICX_RGB || c->nmask == ICX_IRGB) {
+ if ((c->t & T_PRESET) == 0)
+ fprintf(s->of,"%% Ref %s %s %f %f %f\n",c->id, c->loc,
+ 100.0 * cdev[0], 100.0 *cdev[1], 100.0 *cdev[2]);
+ fprintf(s->of,"%f %f %f setrgbcolor\n",cdev[0],cdev[1],cdev[2]);
+
+ } else if (c->nmask == ICX_CMYK) {
+ if ((c->t & T_PRESET) == 0)
+ fprintf(s->of,"%% Ref %s %s %f %f %f %f\n", c->id, c->loc,
+ 100.0 * cdev[0], 100.0 * cdev[1], 100.0 * cdev[2], 100.0 * cdev[3]);
+ fprintf(s->of,"%f %f %f %f setcmykcolor\n",cdev[0],cdev[1],cdev[2],cdev[3]);
+
+ } else
+#endif /* !FORCEN */
+ { /* Device N */
+ int i;
+ if ((c->t & T_PRESET) == 0) {
+ fprintf(s->of,"%% Ref %s %s",c->id, c->loc);
+ for (i = 0; i < c->n; i++)
+ fprintf(s->of,"%f ", 100.0 * cdev[i]);
+ fprintf(s->of,"\n");
+ }
+ gen_ncolor(s, c);
+ }
+
+ /* Remember edge tracking color */
+ et_color(c->rgb);
+}
+
+/* Generate a rectangle, with optional edge tracking */
+/* Note the page coordinate origin is bottom left. */
+static void ps_rectangle(trend *ss,
+ double x, double y, /* Top left corner of rectangle in mm from origin */
+ double w, double h, /* Width and height */
+ char *id, /* Patch id, NULL if not a diagnostic mark */
+ int et /* nz if use edge tracking on this */
+) {
+ ps_trend *s = (ps_trend *)ss;
+
+ if (w < 1e-6 || h < 1e-6)
+ return; /* Skip zero sized rectangle */
+ y -= h; /* Convert to bottom left corner */
+ x = mm2pnt(x);
+ y = mm2pnt(y);
+ w = mm2pnt(w);
+ h = mm2pnt(h);
+ fprintf(s->of,"%f %f %f %f rect\n",w,h,x,y);
+
+ if (et) {
+ et_patch(id, x, y, w, h);
+ et_edge(1, 0, x, y, y + h);
+ et_edge(1, 1, x + w, y, y + h);
+ et_edge(0, 0, y, x, x + w);
+ et_edge(0, 1, y + h, x, x + w);
+ }
+}
+
+/* Generate one testpad hexagon. */
+/* Note the page coordinate origin is bottom left. */
+/* The hex always has left/right sides */
+/* and peaks at the top and the bottom. */
+static void ps_hexagon(trend *ss,
+ double x, double y, /* Top left vertex of hex mm from origin */
+ double w, double h, /* Width and height */
+ int step, /* Step number from 0 to figure odd/even */
+ char *id /* Patch id, NULL if not a diagnostic mark */
+) {
+ ps_trend *s = (ps_trend *)ss;
+
+ if (w < 1e-6 || h < 1e-6)
+ return; /* Skip zero sized rectangle */
+ if ((step & 1) == 0) /* Even so left side of stagger */
+ x -= 0.25 * w;
+ else /* Odd so right side of stagger */
+ x += 0.25 * w;
+ y = y - 5.0/6.0 * h;
+ h *= 2.0/3.0; /* Convert to hex side length */
+ x = mm2pnt(x);
+ y = mm2pnt(y);
+ w = mm2pnt(w);
+ h = mm2pnt(h);
+ fprintf(s->of,"%f %f %f %f hex\n",w,h,x,y);
+}
+
+/* A centered string */
+static void ps_string(trend *ss,
+ double x, double y, /* Bot Left Corner of rectangle in mm from origin */
+ double w, double h, /* Width and height */
+ char *str /* String */
+) {
+ ps_trend *s = (ps_trend *)ss;
+
+ if (fabs(w) < 1e-6 || fabs(h) < 1e-6)
+ return; /* Skip zero sized string */
+ x = mm2pnt(x);
+ y = mm2pnt(y);
+ w = mm2pnt(w);
+ h = mm2pnt(h);
+ fprintf(s->of,"%f scaleTimes\n",h * 0.75);
+ fprintf(s->of,"(%s) %f %f centerShow\n",str,x+w/2.0,y+h/2.0);
+}
+
+/* A vertically centered string */
+static void ps_vstring(trend *ss,
+ double x, double y, /* Bot Right Corner of rectangle in mm from origin */
+ double w, double h, /* Width and height */
+ char *str /* String */
+) {
+ ps_trend *s = (ps_trend *)ss;
+
+ if (fabs(w) < 1e-6 || fabs(h) < 1e-6)
+ return; /* Skip zero sized string */
+ x = mm2pnt(x);
+ y = mm2pnt(y);
+ w = mm2pnt(w);
+ h = mm2pnt(h);
+ fprintf(s->of,"%f scaleTimes\n",w * 0.75);
+ fprintf(s->of,"(%s) %f %f vcenterShow\n",str,x-w/2.0,y+h/2.0);
+}
+
+/* A dotted line */
+static void ps_dline(trend *ss,
+ double x1, double y1, /* Start of line */
+ double x2, double y2, /* End of line */
+ double w /* Width */
+) {
+ ps_trend *s = (ps_trend *)ss;
+
+ if (fabs(w) < 1e-6 || fabs(y2 - y1) < 1e-6)
+ return; /* Skip zero sized line */
+ x1 = mm2pnt(x1);
+ x2 = mm2pnt(x2);
+ y1 = mm2pnt(y1);
+ y2 = mm2pnt(y2);
+ w = mm2pnt(w);
+ fprintf(s->of,"[%f %f] %f setdash\n",mm2pnt(1.0),mm2pnt(2.0),mm2pnt(0.0));
+ fprintf(s->of,"%f setlinewidth\n",w);
+ fprintf(s->of,"newpath %f %f moveto %f %f lineto stroke\n",x1,y1,x2,y2);
+}
+
+/* Complete operations, then delete the object */
+static void ps_del(trend *ss) {
+ ps_trend *s = (ps_trend *)ss;
+
+ if (s->of) {
+ fprintf(s->of,"\n");
+ fprintf(s->of,"%%%%EOF\n");
+
+ if (fclose(s->of))
+ error ("Unable to close output file '%s'",s->fname);
+ }
+ if (s->fname)
+ free(s->fname);
+
+ free(s);
+}
+
+trend *new_ps_trend(
+ char *fname, /* File name */
+ int npages, /* Number of pages needed */
+ int nmask, /* Non zero if we are doing a DeviceN chart */
+ double pw, double ph, /* Page width and height in mm */
+ int eps, /* EPS flag */
+ int rand, /* randomize */
+ int rstart /* Random start number/chart ID */
+) {
+ ps_trend *s;
+
+ if ((s = (ps_trend *)calloc(1, sizeof(ps_trend))) == NULL) {
+ return NULL;
+ }
+
+ s->startpage = ps_startpage;
+ s->endpage = ps_endpage;
+ s->setcolor = ps_setcolor;
+ s->rectangle = ps_rectangle;
+ s->hexagon = ps_hexagon;
+ s->string = ps_string;
+ s->vstring = ps_vstring;
+ s->dline = ps_dline;
+ s->del = ps_del;
+
+ s->eps = eps;
+
+ if ((s->of = fopen(fname,"w")) == NULL) {
+ error ("Unable to open output file '%s'",fname);
+ }
+
+ if ((s->fname = strdup(fname)) == NULL)
+ error("stdup of fname failed");
+
+ /* Generate PS file prolog */
+ {
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ int ipw, iph;
+
+ ipw = (int)ceil(mm2pnt(pw));
+ iph = (int)ceil(mm2pnt(ph));
+ if (eps)
+ fprintf(s->of,"%%!PS-Adobe-3.0 EPSF-3.0\n");
+ else
+ fprintf(s->of,"%%!PS-Adobe-3.0\n");
+ fprintf(s->of,"%%%%Title: Argyll Color Calibration Target\n");
+#ifdef FORCEN
+ if (1) {
+#else
+ if (nmask != ICX_W /* If not a Gray, RGB or CMYK device space */
+ && nmask != ICX_K
+ && nmask != ICX_RGB
+ && nmask != ICX_IRGB
+ && nmask != ICX_CMYK) {
+#endif
+ fprintf(s->of,"%%%%LanguageLevel: 3\n");
+ } else {
+ fprintf(s->of,"%%%%LanguageLevel: 1\n");
+ if (nmask == ICX_CMYK)
+ fprintf(s->of,"%%%%Extensions: CMYK\n");
+ }
+
+ fprintf(s->of,"%%%%Creator: Argyll target chart generator\n");
+ fprintf(s->of,"%%%%For: The user who wants accurate color\n");
+// fprintf(s->of,"%%%%Version: %s\n",VERSION);
+ fprintf(s->of,"%%%%CreationDate: %s",asctime(tsp));
+ fprintf(s->of,"%%%%DocumentData: Clean7Bit\n");
+ if (eps)
+ fprintf(s->of,"%%%%Pages: %d\n",1);
+ else
+ fprintf(s->of,"%%%%Pages: %d\n",npages);
+ fprintf(s->of,"%%%%PageOrder: Ascend\n");
+ fprintf(s->of,"%%%%BoundingBox: %d %d %d %d\n",0,0,ipw-1,iph-1);
+ fprintf(s->of,"%%%%Orientation: Portrait\n"); /* Rows are always virtical */
+ fprintf(s->of,"%%%%EndComments\n");
+ fprintf(s->of,"\n");
+ if (!eps) {
+ fprintf(s->of,"<< /PageSize [%d %d] >> setpagedevice\n",ipw, iph);
+ fprintf(s->of,"\n");
+ }
+ fprintf(s->of,"%%%%BeginProlog\n\n");
+#ifdef NEVER
+ fprintf(s->of,"%% Duplicate nth element of stack\n");
+ fprintf(s->of,"%% arguments: n, the offset from the element bellow the n\n");
+ fprintf(s->of,"/dupn { 2 add dup -1 roll dup 3 -1 roll 1 roll } bind def\n");
+ fprintf(s->of,"\n");
+#endif
+ fprintf(s->of,"%% arbitrary rectangle\n");
+ fprintf(s->of,"%% arguments: w h x y\n");
+ fprintf(s->of,"/rect { gsave \n");
+ fprintf(s->of,"newpath\n");
+ fprintf(s->of,"moveto\n");
+ fprintf(s->of,"dup 0.0 exch rlineto\n");
+ fprintf(s->of,"exch 0.0 rlineto\n");
+ fprintf(s->of,"0.0 exch neg rlineto\n");
+ fprintf(s->of,"closepath\n");
+ fprintf(s->of,"fill\n");
+ fprintf(s->of,"grestore } bind def\n");
+ fprintf(s->of,"\n");
+ fprintf(s->of,"%% hexagon with bottom left origin\n");
+ fprintf(s->of,"%% arguments: w h x y\n");
+ fprintf(s->of,"/hex { gsave \n");
+ fprintf(s->of,"newpath\n");
+ fprintf(s->of,"moveto\n");
+ fprintf(s->of,"0 1 index rlineto\n");
+ fprintf(s->of,"1 index 2 div 1 index 2 div rlineto\n");
+ fprintf(s->of,"1 index 2 div 1 index 2 div neg rlineto\n");
+ fprintf(s->of,"0 1 index neg rlineto\n");
+ fprintf(s->of,"1 index 2 div neg 1 index 2 div neg rlineto\n");
+ fprintf(s->of,"pop pop\n");
+ fprintf(s->of,"closepath\n");
+ fprintf(s->of,"fill\n");
+ fprintf(s->of,"grestore } bind def\n");
+ fprintf(s->of,"\n");
+ fprintf(s->of,"%% set times-roman font\n");
+ fprintf(s->of,"%% argument: scale\n");
+ fprintf(s->of,"/scaleTimes {\n");
+ fprintf(s->of,"/Times-Roman findfont\n");
+ fprintf(s->of,"exch scalefont\n");
+ fprintf(s->of,"setfont } bind def\n");
+ fprintf(s->of,"\n");
+ fprintf(s->of,"%% Print a centered string\n");
+ fprintf(s->of,"%% argument: string, x, y\n");
+ fprintf(s->of,"/centerShow {\n");
+ fprintf(s->of,"gsave translate\n");
+ fprintf(s->of,"newpath 0.0 0.0 moveto dup true charpath pathbbox\n");
+ fprintf(s->of,"3 -1 roll sub exch 3 -1 roll sub\n");
+ fprintf(s->of,"-0.5 mul exch -0.5 mul\n");
+ fprintf(s->of,"moveto show grestore} bind def\n");
+ fprintf(s->of,"\n");
+ fprintf(s->of,"%% Print a vertically centered string\n");
+ fprintf(s->of,"%% argument: string, x, y\n");
+ fprintf(s->of,"/vcenterShow {\n");
+ fprintf(s->of,"gsave translate 90.0 rotate\n");
+ fprintf(s->of,"newpath 0.0 0.0 moveto dup true charpath pathbbox\n");
+ fprintf(s->of,"3 -1 roll sub exch 3 -1 roll sub\n");
+ fprintf(s->of,"-0.5 mul exch -0.5 mul\n");
+ fprintf(s->of,"moveto show grestore} bind def\n");
+
+ fprintf(s->of,"%%%%EndProlog\n");
+ fprintf(s->of,"\n");
+
+ if (rand != 0)
+ fprintf(s->of,"%% RandomStart %d\n",rstart);
+ else
+ fprintf(s->of,"%% ChartID %d\n",rstart);
+ fprintf(s->of,"\n");
+ }
+
+ return (trend *)s;
+}
+
+/* ==================================== */
+/* TIFF raster output class */
+/* We use the render library to do all the hard work. */
+
+struct _tiff_trend {
+ TREND_STRUCT
+
+ render2d *r; /* Raster renderer object */
+ char *fname;
+ color2d c; /* Last set color */
+ int comp; /* Flag, use compression */
+
+}; typedef struct _tiff_trend tiff_trend;
+
+/* Start a page */
+static void tiff_startpage(trend *ss, int pn) {
+ tiff_trend *s = (tiff_trend *)ss;
+
+ /* Nothing to do */
+}
+
+/* End a page */
+static void tiff_endpage(trend *ss) {
+ tiff_trend *s = (tiff_trend *)ss;
+
+ /* Nothing to do */
+}
+
+/* set the color */
+static void tiff_setcolor(trend *ss, xcal *cal, col *c) {
+ tiff_trend *s = (tiff_trend *)ss;
+ double cdev[ICX_MXINKS]; /* Calibrated device color */
+
+ if (cal != NULL)
+ cal->interp(cal, cdev, c->dev);
+ else {
+ int j;
+ for (j = 0; j < c->n; j++)
+ cdev[j] = c->dev[j];
+ }
+
+ if ((c->t & T_N) == 0)
+ error("tiff_setcolor with no device values set");
+
+ if (c->nmask == ICX_W) {
+ if (c->altrep == 0) { /* DeviceGray */
+ s->c[0] = cdev[0];
+ } else if (c->altrep == 4) { /* DeviceRGB */
+ s->c[0] = cdev[0];
+ s->c[1] = cdev[0];
+ s->c[2] = cdev[0];
+ } else if (c->altrep == 5) { /* Separation */
+ s->c[0] = cdev[0];
+ } else if (c->altrep == 6) { /* DeviceN single channel */
+ s->c[0] = cdev[0];
+ } else {
+ error("Device white encoding not approproate!");
+ }
+
+ } else if (c->nmask == ICX_K) {
+ if (c->altrep == 0) { /* DeviceGray */
+ s->c[0] = cdev[0];
+ } else if (c->altrep == 1) { /* DeviceCMYK */
+ s->c[0] = 0.0;
+ s->c[1] = 0.0;
+ s->c[2] = 0.0;
+ s->c[3] = cdev[0];
+ } else if (c->altrep == 2) { /* Separation */
+ s->c[0] = cdev[0];
+ } else if (c->altrep == 3) { /* DeviceN single channel */
+ s->c[0] = cdev[0];
+ } else {
+ error("Device black encoding not approproate!");
+ }
+
+ } else if (c->nmask == ICX_CMY) {
+ if (c->altrep == 0) { /* DeviceCMYK */
+ s->c[0] = cdev[0];
+ s->c[1] = cdev[1];
+ s->c[2] = cdev[2];
+ s->c[3] = 0.0;
+ } else if (c->altrep == 7) { /* Inverted DeviceRGB */
+ s->c[0] = 1.0-cdev[0];
+ s->c[1] = 1.0-cdev[1];
+ s->c[2] = 1.0-cdev[2];
+ } else if (c->altrep == 8) { /* DeviceN three channel */
+ s->c[0] = cdev[0];
+ s->c[1] = cdev[1];
+ s->c[2] = cdev[2];
+ } else {
+ error("Device CMY encoding not approproate!");
+ }
+
+ } else {
+ int j;
+ for (j = 0; j < s->r->ncc; j++)
+ s->c[j] = cdev[j];
+ }
+
+ /* Remember edge tracking color */
+ et_color(c->rgb);
+}
+
+/* A rectangle, with optional edge tracking */
+static void tiff_rectangle(trend *ss,
+ double x, double y, /* Top left corner of rectangle in mm from origin */
+ double w, double h, /* Width and height */
+ char *id, /* Patch id, NULL if not a diagnostic mark */
+ int et /* nz if use edge tracking on this */
+) {
+ tiff_trend *s = (tiff_trend *)ss;
+
+ y -= h; /* Convert to bottom left corner */
+ s->r->add(s->r, new_rect2d(s->r, x, y, w, h, s->c));
+
+ if (et) {
+ et_patch(id, x, y, w, h);
+ et_edge(1, 0, x, y, y + h);
+ et_edge(1, 1, x + w, y, y + h);
+ et_edge(0, 0, y, x, x + w);
+ et_edge(0, 1, y + h, x, x + w);
+ }
+}
+
+/* A testpad hexagon. */
+static void tiff_hexagon(trend *ss,
+ double x, double y, /* Top left vertex of hex mm from origin */
+ double w, double h, /* Width and height */
+ int step, /* Step number from 0 to figure odd/even */
+ char *id /* Patch id, NULL if not a diagnostic mark */
+) {
+ tiff_trend *s = (tiff_trend *)ss;
+ double vv[3][2];
+ color2d cc[3];
+ int i, j;
+
+ if ((step & 1) == 0) /* Even so left side of stagger */
+ x -= 0.25 * w;
+ else /* Odd so right side of stagger */
+ x += 0.25 * w;
+ y = y - 5.0/6.0 * h;
+ h *= 2.0/3.0; /* Convert to hex side length */
+
+ /* Triangle color */
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < s->r->ncc; j++)
+ cc[i][j] = s->c[j];
+
+ /* Top triangle */
+ vv[0][0] = x;
+ vv[0][1] = y + h;
+ vv[1][0] = x + w;
+ vv[1][1] = y + h;
+ vv[2][0] = x + 0.5 * w;
+ vv[2][1] = y + 1.5 * h;
+ s->r->add(s->r, new_trivs2d(s->r, vv, cc));
+
+ /* Center rectangle */
+ s->r->add(s->r, new_rect2d(s->r, x, y, w, h, s->c));
+
+ /* Bottom triangle */
+ vv[0][0] = x;
+ vv[0][1] = y;
+ vv[1][0] = x + w;
+ vv[1][1] = y;
+ vv[2][0] = x + 0.5 * w;
+ vv[2][1] = y - 0.5 * h;
+ s->r->add(s->r, new_trivs2d(s->r, vv, cc));
+}
+
+/* A centered string */
+static void tiff_string(trend *ss,
+ double x, double y, /* Bot Left Corner of rectangle in mm from origin */
+ double w, double h, /* Width and height */
+ char *str /* String */
+) {
+ tiff_trend *s = (tiff_trend *)ss;
+ double sw = 0.0, sh = 0.0;
+
+ sh = h * 0.57;
+ meas_string2d(s->r,&sw,NULL,timesr_b,str,sh,0);
+ /* Center the string within the recangle */
+ x += 0.5 * (w - sw);
+ y += 0.5 * (h - sh);
+ add_string2d(s->r,NULL,NULL,timesr_b,str,x,y,sh,0,s->c);
+}
+
+/* A vertically centered string */
+static void tiff_vstring(trend *ss,
+ double x, double y, /* Bot Right Corner of rectangle in mm from origin */
+ double w, double h, /* Width and height */
+ char *str /* String */
+) {
+ tiff_trend *s = (tiff_trend *)ss;
+ double sw = 0.0, sh = 0.0;
+
+ x -= w; /* Make it bot left corner */
+ sw = w * 0.57;
+ meas_string2d(s->r,NULL, &sh,timesr_b,str,sw,3);
+ /* Center the string within the recangle */
+ x += 0.5 * (w + sw);
+ y += 0.5 * (h - sh);
+ add_string2d(s->r,NULL,NULL,timesr_b,str,x,y,sw,3,s->c);
+}
+
+/* A dotted line */
+static void tiff_dline(trend *ss,
+ double x0, double y0, /* Start of line */
+ double x1, double y1, /* End of line */
+ double w /* Width */
+) {
+ tiff_trend *s = (tiff_trend *)ss;
+
+ add_dashed_line2d(s->r,x0,y0,x1,y1,w,1.0,2.0,0,s->c);
+}
+
+/* Complete operations, then delete the object */
+static void tiff_del(trend *ss) {
+ tiff_trend *s = (tiff_trend *)ss;
+
+ if (s->r != NULL) {
+ s->r->write(s->r, s->fname, s->comp);
+ s->r->del(s->r);
+ }
+ if (s->fname != NULL)
+ free(s->fname);
+ free(s);
+}
+
+static trend *new_tiff_trend(
+ char *fname, /* File name */
+ int nmask, /* Non zero if we are doing a DeviceN chart */
+ depth2d dpth, /* 8 or 16 bit */
+ double pw, double ph, /* Page width and height in mm */
+ double marg, /* Page margine in mm */
+ double hres, double vres, /* Resolution */
+ int altrep, /* printer grey/CMY representation type 0..8 */
+ int ncha, /* flag, use nchannel alpha */
+ int comp, /* flag, use compression */
+ int dith /* flag, use 8 bit dithering */
+) {
+ tiff_trend *s;
+ color2d c; /* Background color */
+ colort2d csp;
+ double ma[4]; /* Page margins */
+ int nc = 0;
+ int j;
+
+ if ((s = (tiff_trend *)calloc(1, sizeof(tiff_trend))) == NULL) {
+ error("Failed to create a tiff target rendering object");
+ }
+
+ s->startpage = tiff_startpage;
+ s->endpage = tiff_endpage;
+ s->setcolor = tiff_setcolor;
+ s->rectangle = tiff_rectangle;
+ s->hexagon = tiff_hexagon;
+ s->string = tiff_string;
+ s->vstring = tiff_vstring;
+ s->dline = tiff_dline;
+ s->del = tiff_del;
+
+ if (nmask == ICX_W) {
+ if (altrep == 0 /* DeviceGray */
+ || altrep == 5) { /* Separation single channel */
+ csp = w_2d;
+ nc = 1;
+ } else if (altrep == 4) { /* DeviceRGB */
+ csp = rgb_2d;
+ nc = 3;
+ } else if (altrep == 6) { /* DeviceN single channel */
+ csp = ncol_2d;
+ nc = icx_noofinks(nmask);
+ nc = 1;
+ } else {
+ error("Device white encoding not approproate");
+ }
+
+ } else if (nmask == ICX_K) {
+ if (altrep == 0 /* DeviceGray */
+ || altrep == 2) { /* Separation single channel */
+ csp = k_2d;
+ nc = 1;
+ } else if (altrep == 1) { /* DeviceCMYK */
+ csp = cmyk_2d;
+ nc = 4;
+ } else if (altrep == 3) { /* DeviceN single channel */
+ csp = ncol_2d;
+ nc = icx_noofinks(nmask);
+ nc = 1;
+ } else {
+ error("Device black encoding not approproate");
+ }
+
+ } else if (nmask == ICX_RGB || nmask == ICX_IRGB) {
+ csp = rgb_2d;
+ nc = 3;
+
+ } else if (nmask == ICX_CMY) {
+ if (altrep == 0) { /* DeviceCMYK */
+ csp = cmyk_2d;
+ nc = 4;
+ } else if (altrep == 7) { /* Inverted DeviceRGB */
+ csp = rgb_2d;
+ nc = 3;
+ } else if (altrep == 8) { /* DeviceN three channel */
+ csp = ncol_2d;
+ nc = icx_noofinks(nmask);
+ } else {
+ error("Device CMY encoding not approproate");
+ }
+
+ } else if (nmask == ICX_CMYK) {
+ csp = cmyk_2d;
+ nc = 4;
+ } else { /* Device N */
+ if (ncha)
+ csp = ncol_a_2d;
+ else
+ csp = ncol_2d;
+ nc = icx_noofinks(nmask);
+ }
+
+ if (marg > 0)
+ ma[0] = ma[1] = ma[2] = ma[3] = marg;
+ else
+ ma[0] = ma[1] = ma[2] = ma[3] = 0;
+
+ if ((s->r = new_render2d(pw, ph, ma, hres, vres, csp, nc, dpth, dith)) == NULL) {
+ error("Failed to create a render2d object for tiff output");
+ }
+
+ /* We're goin to assume this is all printed output, so */
+ /* the background should be white. */
+ if ((nmask & ICX_ADDITIVE)
+ || (nmask == ICX_CMY && altrep == 7)) { /* CMY as inverted RGB */
+ for (j = 0; j < nc; j++)
+ c[j] = 1.0;
+ } else {
+ for (j = 0; j < nc; j++)
+ c[j] = 0.0;
+ }
+ s->r->set_defc(s->r, c);
+
+ s->comp = comp;
+
+ if ((s->fname = strdup(fname)) == NULL)
+ error("stdup of fname failed");
+
+ return (trend *)s;
+}
+
+
+/* ====================================================== */
+
+/* Convert XYZ represention into Lab, XYZ density and RGB */
+void
+col_convert(col *cp, double *wp) {
+
+ if ((cp->t & T_XYZ) == 0 || (cp->t & T_N) == 0)
+ error("gen_color needs XYZ and device colors set !");
+
+ if ((cp->t & T_LAB) == 0) {
+ icmXYZNumber w;
+ w.X = wp[0];
+ w.Y = wp[1];
+ w.Z = wp[2];
+ icmXYZ2Lab(&w, cp->Lab, cp->XYZ);
+ cp->t |= T_LAB;
+ }
+ if ((cp->t & T_DEN) == 0) {
+ icx_XYZ2Tdens(cp->den, cp->XYZ);
+
+#ifdef DEN_COMPRESS
+ /* Compress densities > 1.0, 2:1 */
+ {
+ int e;
+ for (e = 0; e < 3; e++) {
+ if (cp->den[e] > 1.0)
+ cp->den[e] = 1.0 + (cp->den[e] - 1.0) * 0.5;
+ }
+ }
+#endif /* DEN_COMPRESS */
+ cp->t |= T_DEN;
+ }
+
+ if ((cp->t & T_RGB) == 0) {
+ icx_XYZ2sRGB(cp->rgb, wp, cp->XYZ);
+ cp->t |= T_RGB;
+ }
+}
+
+/* return the middle of 3 values */
+double mid3(double a, double b, double c) {
+
+ if ((a < b && a > c) || (a < c && a > b))
+ return a;
+ if ((b < a && b > c) || (b < c && b > a))
+ return b;
+ return c;
+}
+
+/* return the vector difference of 3 values */
+double vec3(double a, double b, double c) {
+
+ return sqrt(a * a + b * b + c * c);
+}
+
+/* Type of density rule to use with color patches/spacers. */
+/* This really depends on the algorithm used by the strip */
+/* reading instrument. For an Xrite DTP41, it appears that */
+/* using max3 is the best. This agrees with their documentation, */
+/* that it is looking for the largest change in one of the three */
+/* channels. Another make of instrument might use a different */
+/* algorithm. */
+/* Choices are: */
+/* max3 - aim for largest change to be greatest */
+/* mid3 - aim for middle change to be greatest */
+/* min3 - aim for minimum change to be greatest */
+/* vec3 - aim for the vector change to be greatest */
+
+#define RULE3 max3
+
+/* Setup a suitable spacer color, and */
+/* Return the worst case density difference. */
+double setup_spacer(
+col **psc, /* Return pointer to spacer color */
+col *pp, /* Previous patch color */
+col *cp, /* Current patch color */
+col *pcol, /* 8 pre-defined spacer colors */
+int sptype, /* Spacer type code, -1 = none, */
+ /* 0 = No spacer, 1 = b&W spacer, */
+ /* 2 = colored */
+int usede /* Aim for maximum delta E rather than density */
+) {
+ col *sc = NULL; /* Spacer chosen */
+ double dd, pdd;
+
+//printf("~1\n");
+//printf("~1 setting spacer between %s (%s) and %s (%s)\n",pp->loc, pp->id, cp->loc, cp->id);
+
+ /* Compute contrast between the patches */
+ if (usede) {
+ pdd = icmLabDE(pp->Lab, cp->Lab);
+ } else {
+ /* return the density contrast between the patches */
+ if (pp->nmask == ICX_W
+ || pp->nmask == ICX_K) { /* If only capable of single density */
+
+ pdd = fabs(pp->den[3] - cp->den[3]);
+//printf("~1 computed B&W diff of %f\n",dd);
+
+ } else {
+ pdd = RULE3(fabs(pp->den[0] - cp->den[0]),
+ fabs(pp->den[1] - cp->den[1]),
+ fabs(pp->den[2] - cp->den[2]));
+
+//printf("~1 computed color diff of %f\n",dd);
+ }
+ }
+
+ if (sptype <= 0) /* No spacers */
+ return pdd;
+
+ if (pp->nmask == ICX_W
+ || pp->nmask == ICX_K) { /* If only capable of single density */
+ sptype = 1; /* Force to B&W spacer */
+ }
+
+ if (sptype == 1) { /* B&W spacer */
+ double d1, d2;
+
+ if (usede) {
+ /* Choose whether space should be white or black */
+ /* Shoose color that has greatest worst contrast */
+ d1 = min2(icmLabDE(pcol[0].Lab, pp->Lab), icmLabDE(pcol[0].Lab, cp->Lab));
+ d2 = min2(icmLabDE(pcol[7].Lab, pp->Lab), icmLabDE(pcol[7].Lab, cp->Lab));
+
+//printf("~1 worst difference to white = %f\n", d1);
+//printf("~1 worst difference to black = %f\n", d2);
+
+ if (d1 > d2) {
+//printf("~1 chosen white\n");
+ sc = &pcol[0];
+ dd = d1;
+ } else {
+//printf("~1 chosen black\n");
+ sc = &pcol[7];
+ dd = d2;
+ }
+
+ } else {
+ /* Choose whether space should be white or black */
+ /* Shoose color that has greatest worst contrast */
+ d1 = min2(fabs(pcol[0].den[3] - pp->den[3]), fabs(pcol[0].den[3] - cp->den[3]));
+ d2 = min2(fabs(pcol[7].den[3] - pp->den[3]), fabs(pcol[7].den[3] - cp->den[3]));
+
+//printf("~1 worst difference to white = %f\n", d1);
+//printf("~1 worst difference to black = %f\n", d2);
+
+ if (d1 > d2) {
+//printf("~1 chosen white\n");
+ sc = &pcol[0];
+ dd = d1;
+ } else {
+//printf("~1 chosen black\n");
+ sc = &pcol[7];
+ dd = d2;
+ }
+ }
+
+ } else { /* else colored spacer */
+ int ii, i;
+
+ /* Check out all the possible space values for the one that gives the best */
+ /* and second best contrast to each edge */
+
+ if (usede) {
+
+ /* for all possible spacer colors */
+ dd = -1.0;
+ for (i = 0; i < 8; i++) {
+ double bb;
+
+ bb = min2(icmLabDE(pcol[i].Lab, pp->Lab), icmLabDE(pcol[i].Lab, cp->Lab));
+
+ /* Worst of two edges best is better than any previous */
+ if (bb > dd) {
+ dd = bb; /* Worst color of worst edge */
+ ii = i;
+ sc = &pcol[i];
+ }
+ }
+
+ } else {
+ /* for all possible spacer colors */
+ dd = -1.0;
+ for (i = 0; i < 8; i++) {
+ double b1, b2, bb;
+
+ b1 = RULE3(fabs(pcol[i].den[0] - pp->den[0]),
+ fabs(pcol[i].den[1] - pp->den[1]),
+ fabs(pcol[i].den[2] - pp->den[2]));
+
+ b2 = RULE3(fabs(pcol[i].den[0] - cp->den[0]),
+ fabs(pcol[i].den[1] - cp->den[1]),
+ fabs(pcol[i].den[2] - cp->den[2]));
+
+ bb = min2(b1, b2); /* Worst of two edges */
+
+ /* Worst of two edges best is better than any previous */
+ if (bb > dd) {
+ dd = bb; /* Worst color of worst edge */
+ ii = i;
+ sc = &pcol[i];
+ }
+ }
+ }
+ }
+
+//printf("~1 returning spacer contrast %f + patch contrast %f\n",dd,pdd);
+ if (psc != NULL)
+ *psc = sc; /* Return pointer to chosen spacer */
+
+ return 0.6 * dd + 0.4 * pdd; /* Return propotion of spacer and patch contrast */
+}
+
+/* Given two patches, compute the density difference between them */
+double density_difference(
+col *p1, /* Previous patch color */
+col *p2, /* Current patch color */
+int usede /* Aim for maximum delta E rather than density */
+) {
+ double dd, pdd;
+
+ /* Compute contrast between the patches */
+ if (usede) {
+ pdd = icmLabDE(p1->Lab, p2->Lab);
+ } else {
+ /* return the density contrast between the patches */
+ if (p1->nmask == ICX_W
+ || p1->nmask == ICX_K) { /* If only capable of single density */
+
+ pdd = fabs(p1->den[3] - p2->den[3]);
+
+ } else {
+ pdd = RULE3(fabs(p1->den[0] - p2->den[0]),
+ fabs(p1->den[1] - p2->den[1]),
+ fabs(p1->den[2] - p2->den[2]));
+
+ }
+ }
+
+ return pdd;
+}
+
+/* Given a number, return the DTP20 SID patch encoding. */
+/* return nz on error */
+static int dtp20_enc(
+ col *pcol, /* pcol[8] of spacer patch colors */
+ int ndig, /* Number of octal digits/patches */
+ int lend, /* NZ if little endian order for SID row index */
+ col **ppcol, /* return the pointers to pcol for the encoding */
+ unsigned int rix /* Number to encode */
+) {
+ int si, ei, ii;
+ int i, wv = rix;
+
+ if (lend) /* Little endian order */
+ si = 0, ei = ndig, ii = 1;
+ else
+ si = ndig-1, ei = -1, ii = -1;
+
+ /* LSB to MSB octal */
+ for (i = si; i != ei; i += ii) {
+ int j, k;
+ j = wv % 8; /* Digit value */
+ wv /= 8;
+ for (k = 0; k < 8; k++) {
+ if (pcol[k].dtp20_octval == j)
+ break;
+ }
+ if (k >= 8)
+ return 1; /* Something weird happened */
+ ppcol[i] = &pcol[k];
+ }
+ if (wv != 0)
+ return 1; /* Number is too big to be encoded */
+//printf("~1dtp20_enc %d ->",rix);
+//for (i = 0; i < ndig; i++)
+// printf(" %d",ppcol[i]->dtp20_octval);
+//printf("\n");
+ return 0;
+}
+
+
+/* Sort function for stree */
+static int cmp_eperr(const void *p1, const void *p2) {
+ return ((col *)p1)->wnd == ((col *)p2)->wnd ? 0 :
+ (((col *)p1)->wnd < ((col *)p2)->wnd ? -1 : 1);
+}
+
+#define SYMWT 1.3 /* Amount to discount direction delta E compared to spacers */
+
+/* Setup the randomised index. */
+/* The index only covers test sample patches, not TID or max/min/SID patches */
+void setup_randix(
+int *rix, /* Index lookup array to fill in */
+int npat, /* Number of test targets needed */
+int rand, /* Randomise flag */
+int rstart, /* Starting index for random */
+int verb, /* Verbose flag */
+col *cols, /* Array of colors to be put on target chart */
+col *pcol, /* 8 spacer colors */
+int tpprow, /* Test sample patches per row */
+int spacer, /* Spacer code, 0 = None, 1 = b&w, 2 = colored */
+int needpc, /* Need patch to patch contrast in a row */
+int domaxmin, /* Top and tail strip with max/min or SID. 0 = DTP51, 2 = DTP20 SID */
+col *media, /* Alias for media color */
+int usede /* NZ to use delta E rather than density */
+) {
+ int i;
+ randix *r = NULL; /* Random index order object */
+
+ if (rand)
+ r = new_randix(npat, rstart);
+
+ /* Setup initial linear or randomised index */
+ for (i = 0; i < npat; i++) {
+ if (rand) {
+ rix[i] = r->next(r);
+ } else {
+ rix[i] = i;
+ }
+ cols[rix[i]].ix = i; /* This colors random index */
+ }
+ rix[i] = 0; /* npat+1 may be read, so fill extra entry at end. */
+
+ if (rand)
+ r->del(r);
+
+ /* Setup initial contrast check */
+ {
+ col *pp, *cp, *np, *op; /* Previous, current, next and opposite patch */
+ col *maxd; /* Alias for maximum density */
+ col *mind; /* Alias for minimum density */
+ aat_atree_t *stree; /* Tree holding colors sorted by worst case contrast */
+ aat_atrav_t *aat_tr; /* Tree accessor */
+ double temp, trate; /* Annealing temperature & rate */
+ double tstart, tend;/* Annealing chedule range */
+
+ mind = &pcol[0]; /* White */
+ maxd = &pcol[7]; /* Black */
+
+ /* Create sorted tree so as to be able to locate the largest wnd */
+ if ((stree = aat_anew(cmp_eperr)) == NULL)
+ error("Allocating aat tree for colors failed");
+ if ((aat_tr = aat_atnew()) == NULL)
+ error("aat_atnew returned NULL");
+
+ for (i = 0; i < npat; i++) {
+ int j, k; /* Patch index, Row index */
+ int tpitr; /* Test patches in this row */
+ double tt;
+
+ j = (i % tpprow);
+ k = i / tpprow;
+
+ /* Figure previous patch */
+ if (j == 0) { /* First in row */
+ if (domaxmin == 1)
+ pp = maxd; /* Maxd will be before first patch */
+ else if (domaxmin == 2) {
+ col *ppcol[3];
+ /* Compute the SID colors the DTP20 will use before row */
+ if (dtp20_enc(pcol, 3, 1, ppcol, k+1) != 0)
+ error("Internal, dtp20 SID row id failed, val %d, digits %d",k+1,3);
+ pp = ppcol[2]; /* Barcode patch next to first test patch */
+ } else
+ pp = media; /* Media will be before first patch */
+ } else {
+ pp = &cols[rix[i-1]];
+ }
+
+ /* Current patch */
+ cp = &cols[rix[i]];
+
+ /* Next patch */
+ if (j == (tpprow-1) || i == (npat-1)) { /* Last in row or last patch */
+ if ((j == (tpprow-1) || i == (npat-1)) && domaxmin == 1)
+ np = mind;
+ else if ((j == (tpprow-1) || i == (npat-1)) && domaxmin == 2)
+ np = mind; /* DTP20 has white trailing patch */
+ else
+ np = media;
+ } else {
+ np = &cols[rix[i+1]];
+ }
+
+ /* Opposite patch */
+
+ if (k == npat/tpprow) /* Last row */
+ tpitr = npat - tpprow * (npat/tpprow);
+ else
+ tpitr = tpprow;
+ op = &cols[rix[ k * tpprow + (tpitr -1 - j)]];
+
+ /* Setup pointers and worst case contrast */
+ cp->nc[0] = pp;
+ cp->nc[1] = np;
+ cp->oc = op;
+ cp->wnd = setup_spacer(NULL, pp, cp, pcol, spacer, usede);
+ tt = setup_spacer(NULL, cp, np, pcol, spacer, usede);
+ if (tt < cp->wnd)
+ cp->wnd = tt;
+ if (cp != op) {
+ tt = SYMWT * density_difference(cp, op, usede);
+ if (tt < cp->wnd)
+ cp->wnd = tt;
+ }
+
+ /* Insert it into the sorted list */
+ if ((aat_ainsert(stree, (void *)cp)) == 0)
+ error("aat_ainsert color %d failed",i);
+ }
+
+ if (verb) {
+ double wrdc = 1e300;
+
+ if ((cp = aat_atfirst(aat_tr, stree)) == NULL)
+ error("There seem to be no colors in the tree");
+ if (usede)
+ printf("Worst case delta E = %f\n", cp->wnd);
+ else
+ printf("Worst case density contrast = %f\n", cp->wnd);
+
+ /* Evaluate each strips direction confusion */
+ for (i = 0; ; i++) {
+ int j, tpitr; /* Test patches in this row */
+ double tot = 0.0;
+ if ((i * tpprow) >= npat)
+ break;
+ if (i == npat/tpprow) /* Last row */
+ tpitr = npat - tpprow * (npat/tpprow);
+ else
+ tpitr = tpprow;
+
+ for (tot = 0.0, j = 0; j < tpitr; j++) {
+ tot += density_difference(&cols[rix[ i * tpprow + j]],
+ &cols[rix[ i * tpprow + (tpitr -1 - j)]], usede);
+ }
+ tot /= tpitr;
+ if (tot < wrdc)
+ wrdc = tot;
+ }
+ if (usede)
+ printf("Worst case direction distinction delta E = %f\n", wrdc);
+ else
+ printf("Worst case direction distinction density contrast = %f\n", wrdc);
+ }
+
+ if (needpc == 0 || !rand || npat < 3)
+ return; /* Current order is sufficient */
+
+ if (verb) {
+ printf("Optimising layout for strip reader:\n");
+ printf(" 0%%"); fflush(stdout);
+ }
+
+ if (spacer == 2) { /* Colored spacer, don't optimise too hard */
+ tstart = 0.4;
+ tend = 0.00001;
+ trate = 0.87;
+ } else { /* No spacer or B&W spacer, do more optimisation */
+ tstart = 0.4;
+ tend = 0.000005;
+ trate = 0.95;
+ }
+ /* Simulated anealing */
+ for (temp = tstart; temp > tend; temp *= trate) {
+
+ int ii, itlim; /* Maximum passes at a temperature */
+ int nsuc = 0; /* Number that succeed */
+ int suclim; /* Number of successful changes before continuing */
+
+ if (spacer == 2) { /* Colored spacer, don't optimise too hard */
+ itlim = npat * 10;
+ suclim = npat;
+ } else {
+ itlim = npat * 14;
+ suclim = npat;
+ }
+
+ if (verb) { /* Output percent intervals */
+ double pc;
+
+ pc = (log(temp) - log(tstart))/(log(tend) - log(tstart));
+ printf("%c%2d%%",cr_char,(int)(100.0 * pc+0.5)); fflush(stdout);
+ }
+
+ /* Improve the ordering */
+ for (ii = 0; ii < itlim ; ii++) {
+ col *p1, *p2;
+ double tt, de;
+
+ /* Chose another patch to try swapping worst with */
+ p1 = aat_atfirst(aat_tr, stree); /* worst */
+ for (;;) {
+ tt = d_rand(0.0, 1.0);
+ p2 = &cols[(int)(tt * (npat-1.0))]; /* Swap candidate */
+ if (p1 != p2 && p2 != p1->oc)
+ break; /* Swap is not the worst or opposite */
+ }
+
+ /* Check p1 in p2's place */
+ de = setup_spacer(NULL, p2->nc[0], p1, pcol, spacer, usede);
+ tt = setup_spacer(NULL, p1, p2->nc[1], pcol, spacer, usede);
+ if (tt < de)
+ de = tt;
+ tt = SYMWT * density_difference(p2->oc, p1, usede);
+ if (tt < de)
+ de = tt;
+
+ /* Check p2 in p1's place */
+ tt = setup_spacer(NULL, p1->nc[0], p2, pcol, spacer, usede);
+ if (tt < de)
+ de = tt;
+ tt = setup_spacer(NULL, p2, p1->nc[1], pcol, spacer, usede);
+ if (tt < de)
+ de = tt;
+ tt = SYMWT * density_difference(p1->oc, p2, usede);
+ if (tt < de)
+ de = tt;
+
+ de = de - p1->wnd; /* Increase in worst difference */
+
+ /* If this swap will improve things, or temp is high enough, */
+ /* then actually do the swap. */
+ if (de > 0.0
+ || d_rand(0.0, 1.0) < exp(de/temp)) {
+ int t;
+ col *tp0, *tp1;
+
+ nsuc++;
+
+//printf("~1 temp = %f, ii = %d, swapping %d and %d\n",temp,ii,p1->i, p2->i);
+
+ /* Remove them from the tree */
+ if ((aat_aerase(stree, (void *)p1)) == 0)
+ error("aat_aerase failed to find color no %d", p1->i);
+ if ((aat_aerase(stree, (void *)p2)) == 0)
+ error("aat_aerase failed to find color no %d", p2->i);
+
+ /* Swap them in random index list */
+ rix[p1->ix] = p2->i;
+ rix[p2->ix] = p1->i;
+ t = p1->ix;
+ p1->ix = p2->ix;
+ p2->ix = t;
+
+ /* Swap their neighbors, taking care */
+ /* of the situation if they are neigbors */
+ tp0 = p1->nc[0];
+ tp1 = p2->nc[0];
+ if (tp0 == p1)
+ tp0 = p2;
+ else if (tp0 == p2)
+ tp0 = p1;
+ if (tp1 == p1)
+ tp1 = p2;
+ else if (tp1 == p2)
+ tp1 = p1;
+ p2->nc[0] = tp0;
+ p1->nc[0] = tp1;
+
+ tp0 = p1->nc[1];
+ tp1 = p2->nc[1];
+ if (tp0 == p1)
+ tp0 = p2;
+ else if (tp0 == p2)
+ tp0 = p1;
+ if (tp1 == p1)
+ tp1 = p2;
+ else if (tp1 == p2)
+ tp1 = p1;
+ p2->nc[1] = tp0;
+ p1->nc[1] = tp1;
+
+ /* Swap their opposites (they cannot be opposites of each other) */
+ p1->oc->oc = p2;
+ p2->oc->oc = p1;
+ tp0 = p1->oc;
+ p1->oc = p2->oc;
+ p2->oc = tp0;
+
+ /* Reset backwards references */
+ p1->nc[0]->nc[1] = p1;
+ p1->nc[1]->nc[0] = p1;
+ p2->nc[0]->nc[1] = p2;
+ p2->nc[1]->nc[0] = p2;
+
+ /* re-compute contrast to neighbors */
+ p1->wnd = setup_spacer(NULL, p1->nc[0], p1, pcol, spacer, usede);
+ tt = setup_spacer(NULL, p1, p1->nc[1], pcol, spacer, usede);
+ if (tt < p1->wnd)
+ p1->wnd = tt;
+ if (p1 != p1->oc) {
+ tt = SYMWT * density_difference(p1, p1->oc, usede);
+ if (tt < p1->wnd)
+ p1->wnd = tt;
+ }
+
+ p2->wnd = setup_spacer(NULL, p2->nc[0], p2, pcol, spacer, usede);
+ tt = setup_spacer(NULL, p2, p2->nc[1], pcol, spacer, usede);
+ if (tt < p2->wnd)
+ p2->wnd = tt;
+ if (p2 != p2->oc) {
+ tt = SYMWT * density_difference(p2, p2->oc, usede);
+ if (tt < p2->wnd)
+ p2->wnd = tt;
+ }
+
+ /* (!!! We haven't recomputed the possible change in the ->oc's */
+ /* ->wnd due to it's opposite haveing changed. !!!) */
+
+ /* Add them back to the tree */
+ if ((aat_ainsert(stree, (void *)p1)) == 0)
+ error("aat_ainsert color no %d failed",p1->i);
+ if ((aat_ainsert(stree, (void *)p2)) == 0)
+ error("aat_ainsert color no %d failed",p2->i);
+
+#ifdef NEVER
+printf("~1 current list = \n");
+for (cp = aat_atfirst(aat_tr, stree); cp != NULL; cp = aat_atnext(aat_tr))
+ printf("%d: %f\n",cp->i,cp->wnd);
+cp = aat_atfirst(aat_tr, stree);
+printf("~1 worst case contrast = %f, list index %d, id '%s', loc '%s'\n",
+cp->wnd, cp->i,cp->id,cp->loc);
+printf("~1 neighbor list index %d, id '%s', loc '%s'\n",
+cp->nc[0]->i,cp->nc[0]->id,cp->nc[0]->loc);
+printf("~1 neighbor list index %d, id '%s', loc '%s'\n",
+cp->nc[1]->i,cp->nc[1]->id,cp->nc[1]->loc);
+#endif
+
+ if (nsuc > suclim)
+ break;
+ }
+ }
+ }
+
+ if (verb) {
+ double wrdc = 1e300;
+ if ((cp = aat_atfirst(aat_tr, stree)) == NULL)
+ error("There seem to be no colors in the tree");
+ if (usede)
+ printf("%c100%%\nAfter optimisation, worst delta E = %f\n",cr_char,cp->wnd);
+ else
+ printf("%c100%%\nAfter optimisation, density contrast = %f\n",cr_char,cp->wnd);
+
+ /* Evaluate each strips direction confusion */
+ for (i = 0; ; i++) {
+ int j, tpitr; /* Test patches in this row */
+ double tot = 0.0;
+ if ((i * tpprow) >= npat)
+ break;
+ if (i == npat/tpprow) /* Last row */
+ tpitr = npat - tpprow * (npat/tpprow);
+ else
+ tpitr = tpprow;
+
+ for (tot = 0.0, j = 0; j < tpitr; j++) {
+ tot += density_difference(&cols[rix[ i * tpprow + j]],
+ &cols[rix[ i * tpprow + (tpitr -1 - j)]], usede);
+ }
+ tot /= tpitr;
+ if (tot < wrdc)
+ wrdc = tot;
+ }
+ if (usede)
+ printf("Worst case direction distinction delta E = %f\n", wrdc);
+ else
+ printf("Worst case direction distinction density contrast = %f\n", wrdc);
+ }
+
+
+ aat_atdelete(aat_tr);
+ aat_adelete(stree);
+
+ }
+
+}
+
+#define MAXPPROW 500 /* Absolute maximum patches per pass/row permitted */
+#define MAXROWLEN 2000.0 /* Absolute maximum row length */
+
+void
+generate_file(
+instType itype, /* Target instrument type */
+char *bname, /* Output file basename */
+col *cols, /* Array of colors to be put on target chart */
+int npat, /* Number of test targets needed */
+xcal *cal, /* Optional printer calibration, NULL if none */
+char *label, /* Per strip label */
+double pw, /* Page width */
+double ph, /* Page height */
+double bord, /* Border margin in mm */
+int nosubmarg, /* NZ if bord is not to be subtracted from raster */
+int nollimit, /* NZ to not limit the strip length */
+int nolpcbord, /* NZ to suppress left paper clip border */
+int rand, /* Randomise flag */
+int rstart, /* Starting index for random */
+alphix *saix, /* Strip alpha index object */
+alphix *paix, /* Patch alpha index object */
+int ixord, /* Index order, 0 = strip then patch */
+double pscale, /* Test patch & spacers scale factor */
+double sscale, /* Spacers scale factor */
+int hflag, /* Spectroscan/Munki high density modified */
+int verb, /* Verbose flag */
+int scanc, /* Scan compatible bits, 1 = .cht gen, 2 = wide first row */
+int oft, /* PS/EPS/TIFF select (0,1,2) */
+depth2d tiffdpth, /* TIFF pixel depth */
+double tiffres, /* TIFF resolution in DPI */
+int ncha, /* flag, use nchannel alpha */
+int tiffdith, /* flag, nz to use TIFF 8 bit dithering */
+int tiffcomp, /* flag, nz to use TIFF compression */
+int spacer, /* Spacer code, -1 = default, 0 = None, 1 = b&w, 2 = colored */
+int nmask, /* DeviceN mask */
+int altrep, /* printer grey/CMY representation type 0..8 */
+col *pcol, /* 8 spacer colors or 8 barcode colors for DTP20 */
+double *wp, /* Approximate white XYZ point */
+int *ptpprow, /* Return Test sample patches per row */
+unsigned char **pprps, /* Return malloced array holding Passes per strip */
+double *p_patchlen, /* Return patch length in mm */
+double *p_gaplen, /* Return gap length in mm */
+double *p_taplen, /* Return trailer length in mm */
+int *p_npat /* Return number of patches including padding */
+) {
+ char psname[MAXNAMEL+20]; /* Name of output file */
+ trend *tro = NULL; /* Target rendering object */
+ double x1, y1, x2, y2; /* Bounding box in mm */
+ double iw, ih; /* Imagable areas width and height in mm */
+ double arowl; /* Available row length */
+
+ int hex = 0; /* Hexagon patches flag (Spectrolino) */
+ double stagger = 0.0; /* Stagger alternate rows by half patch length */
+
+ /* Chart definition variables. Set to default and override */
+ /* for particular instruments. */
+ double lbord = 0.0; /* Additional left border */
+ int domaxmin = 0; /* if == 1, Top and tail strip with max and min values (DTP51) */
+ /* if == 2, Top and tail with DTP20 strip identification (SID) */
+ int nmaxp = 0; /* Number of max (header) patches for max/min/sid */
+ int nminp = 0; /* Number of min (trailer) patches for max/min/sid */
+ int nextrap = 0; /* Number of extra patches for max and min = nmaxp + nminp */
+ int needpc = 0; /* Need patch to patch contrast in a row */
+ int dorspace = 0; /* Do a rrsp from center of last patch to cut line & print label. */
+ int dopglabel = 0; /* Write a per page label */
+ double pglth = 0.0; /* Page Label text height */
+ int padlrow = 0; /* flag - Pad the last row with white */
+ double lspa = 0.0; /* Leader space before first patch containint border, label, SID etc. */
+ double lcar = 0.0; /* Leading clear area before first patch. Will be white */
+ double plen = 0.0; /* Patch min length */
+ double tidplen = 0.0; /* TID Patch min length */
+ double pspa = 0.0; /* Patch to patch spacer */
+ double tspa = 0.0; /* Clear space after last patch */
+ double txhi = 0.0; /* Step/cut, row label text height */
+ double txhisl = 0.0;/* Strip/column label text height */
+ int docutmarks = 0; /* Generate strip cut marks */
+ double clwi = 0.0; /* Cut line width */
+
+ int dorowlabel = 0; /* Generate a set of row labels */
+ double rlwi = 0.0; /* Row label test width */
+
+ double hxew = 0.0; /* Hexagon chart extra width padding to the right of patches */
+ double hxeh = 0.0; /* Hexagon chart extra height padding around patches */
+
+ double pwid = 0.0; /* Patch min width */
+ double rrsp = 0.0; /* Row to row spacing */
+ double pwex = 0.0; /* Patch width expansion between rows of a strip */
+
+ int mxpprow = 0; /* Maximum patches per row permitted (including min/max patches) */
+ double mxrowl = 0; /* Maximum row length for patchs (including min/max patches) */
+ /* Number of patches is strip by whichever is shorter */
+ int tidrows = 0; /* Rows on first page for target ID (ie. DTP20) */
+ int tidtype = 0; /* Target ID type. 0 = DTP20 */
+ int tidminp = 0; /* Target ID minumum number of patches */
+ int tidpad = 0; /* Initial padding to place TID near middle */
+ int tidnpat = npat; /* Number of test targets needed, including TID row */
+ int rpstrip = 0; /* Rows per strip */
+ int usede = 0; /* Use delta E to maximize patch/spacer conrast rather than density */
+
+ double mints, minbs; /* Minimum top & bottom space from paper edges */
+ double amints, aminbs; /* Actual mints & minbs, allowing for unused space */
+ double swid; /* Whole strip width */
+ int pprow; /* patches per row (inc. max/min/sid patches) */
+ int tidpprow; /* TID patches per row (inc. max/min/sid patches) */
+ int tpprow; /* test patches per row (excludes max/min/sid patches) */
+ int sppage; /* whole & partial strips per page */
+ int rppstrip; /* rows per partial strip on whole page */
+ int npages; /* Number whole & partial pages */
+ int lsppage; /* Last page whole & partial strips per page */
+ int lrpstrip; /* Last strips whole & partial rows per strip */
+ int lpprow; /* last row patches per row (inc. max/min/sid patches) */
+ int ppstrip; /* Real patches per whole strip */
+ int pppage; /* Real patches per whole page */
+ int rem; /* temporary */
+ double sxwi = 0.0; /* Scan compatible first row extra width */
+
+ int *rix; /* Random index lookup (Logical -> patch index) */
+ int i; /* Logical patch in target list */
+ int l_si; /* Last start of page value of i */
+ int ix; /* Patch index in target list */
+ int pir; /* Patch in row */
+ int ris; /* Row in strip */
+ int sip; /* Set in page (including partial strip) */
+ int pif; /* Page in file */
+ double x = 0.0, y = 0.0; /* Current position */
+ col *pp = NULL, *cp = NULL; /* Previous and current printed patch colors */
+ int cpf = 0; /* Current patch special flag. 1 = start bit, 2 = stop bit */
+ int slix; /* Strip label index, -1 for TID */
+ char *slab = NULL; /* Strip label string */
+ unsigned char *rpsp; /* Rows per strip, pointer */
+ col *mark; /* Alias for mark color */
+ col *media; /* Alias for media color */
+ col *maxd; /* Alias for minimum density */
+ col *mind; /* Alias for maximum density */
+ col *sc; /* Alias for current spacer color */
+
+ /* Note pcol[] is setup by targen to be:
+ 0 = white
+ 1 = Cyan
+ 2 = Magenta
+ 3 = Blue
+ 4 = Yellow
+ 5 = Green
+ 6 = Red
+ 7 = Black
+ 8 = 50/50/50 CMY Grey
+ (Should switch to symbols for these ??)
+ */
+
+ /* We assume that since this is intended for a printer, */
+ /* the media is always white. This may not be the case */
+ /* on other output media. */
+ if (itype == instDTP20)
+ mark = &pcol[8]; /* Grey */
+ else
+ mark = &pcol[7]; /* Black */
+ media = &pcol[0]; /* White */
+ mind = &pcol[0]; /* White */
+ maxd = &pcol[7]; /* Black */
+
+ /* Setup DTP20 bar code encoding for spacers. */
+ pcol[0].dtp20_octval = 0; /* White */
+ pcol[0].dtp20_psize = 6.5;
+ pcol[1].dtp20_octval = 4; /* Cyan */
+ pcol[1].dtp20_psize = 10.0;
+ pcol[2].dtp20_octval = 2; /* Magenta */
+ pcol[2].dtp20_psize = 0.0;
+ pcol[3].dtp20_octval = 6; /* Blue */
+ pcol[3].dtp20_psize = 12.5;
+ pcol[4].dtp20_octval = 1; /* Yellow */
+ pcol[4].dtp20_psize = 7.0;
+ pcol[5].dtp20_octval = 5; /* Green */
+ pcol[5].dtp20_psize = 0.0;
+ pcol[6].dtp20_octval = 3; /* Red */
+ pcol[6].dtp20_psize = 0.0;
+ pcol[7].dtp20_octval = 7; /* Black */
+ pcol[7].dtp20_psize = 13.0;
+
+ /* Setup .cht edge tracking information */
+ et_init();
+ et_height(oft != 2 ? mm2pnt(ph) : ph);
+ et_media(media->rgb);
+
+ /* Set Instrument specific parameters */
+ if (itype == instDTP20) { /* Xrite DTP20 */
+ hex = 0; /* No hex for strip instruments */
+ hxew = hxeh = 0.0; /* No extra padding because no hex */
+ domaxmin = 2; /* Print SID patches */
+ nmaxp = 4; /* Extra header patches */
+ nminp = 1; /* Extra trailer patches */
+ nextrap = nmaxp + nminp;/* Number of extra patches for max and min */
+ dorspace = 0; /* Maximise number of rows */
+ dopglabel = 1; /* Write a per page label */
+ padlrow = 1; /* Pad the last row with white */
+ spacer = 0; /* No Spacer between patches */
+ pspa = 0.0; /* No spacer width */
+ usede = 1; /* Use delta E to maximize patch/spacer conrast */
+ needpc = 1; /* Helps to have patch to patch contrast in a row ? */
+ lspa = bord + 5.0 + 5.0; /* Leader space before first patch = bord + pcar + yxhi */
+ lcar = 5.0; /* Leading clear area before first patch */
+ plen = pscale * (6.5); /* Patch min length */
+ if(plen <= 6.75) /* Patch length must be one of 5 lengths */
+ plen = 6.5;
+ else if(plen <= 8.0)
+ plen = 7.0;
+ else if(plen <= 11.25)
+ plen = 10.0;
+ else if(plen <= 12.75)
+ plen = 12.5;
+ else
+ plen = 13.0;
+ tidplen = 6.0; /* TID Patch length. Can't vary. */
+ tspa = 5.0; /* Clear space after last patch */
+ pwid = 10.0; /* Patch min width. (The guide slot is 12mm ?) */
+ if (plen > pwid)
+ pwid = plen; /* Make patch at least as wide as long */
+ rrsp = pwid; /* Row center to row center spacing */
+ pwex = 0.0; /* Patch width expansion between rows of a strip */
+ if (nollimit == 0) {
+ mxpprow = MAXPPROW; /* Maximum patches per row permitted (set by length) */
+ mxrowl = (240.0 - lcar - tspa); /* Maximum row length */
+ } else {
+ mxpprow = MAXPPROW; /* Maximum patches per row permitted (set by length) */
+ mxrowl = MAXROWLEN; /* No row length */
+ }
+ tidrows = 1; /* Rows on first page for target ID */
+ tidtype = 0; /* Target ID type. 0 = DTP20 */
+ tidminp = 21; /* Target ID minumum number of patches (+ white) */
+ rpstrip = 999; /* Rows per strip */
+ txhi = 5.0; /* Label Text Height */
+ txhisl = 2.0; /* Strip Label Text Height */
+ docutmarks = 0; /* Don't generate strip cut marks */
+ clwi = 0.0; /* Cut line width */
+ dorowlabel = 0; /* Don't generate row labels */
+ rlwi = 0.0; /* Row label width */
+ pglth = 5.0; /* Page Label text height */
+
+ if (npat > 4095)
+ error ("Number of patchs %d exceeds maximum of 4095 for DTP20");
+
+ } else if (itype == instDTP22 ) { /* X-Rite DTP22 Digital Swatchbook */
+ hex = hflag ? 1 : 0; /* Hex if requestested */
+ domaxmin = 0; /* Don't print max and min patches */
+ nextrap = 0; /* Number of extra patches for max and min */
+ nmaxp = nminp = 0; /* Extra max/min patches */
+ nextrap = nmaxp + nminp;/* Number of extra patches for max and min */
+ dorspace = 0; /* Do a rrsp from center of last patch to cut line */
+ dopglabel = 1; /* Write a per page label */
+ padlrow = 0; /* Pad the last row with white */
+ spacer = 0; /* No spacer */
+ usede = 1; /* Use delta E to maximize patch/spacer conrast */
+ needpc = 1; /* Need patch to patch contrast in a row */
+ lspa = bord + 8.0; /* Leader space before first patch = border + text */
+ lcar = 0.0; /* Leading clear area before first patch */
+ if (hex) {
+ plen = pscale * sqrt(0.75) * 8.0; /* Patch min length */
+ hxeh = 1.0/6.0 * plen; /* Extra border for hex tops & bottoms */
+ hxew = pscale * 0.25 * 8.0; /* Extra border for hex sides */
+ } else {
+ plen = pscale * 8.0; /* Patch min length */
+ hxew = hxeh = 0.0; /* No extra padding because no hex */
+ }
+ pspa = 0.0; /* Inbetween Patch spacer */
+ tspa = 0.0; /* Clear space after last patch */
+ pwid = pscale * 8.0; /* Patch min width */
+ rrsp = pscale * 8.0; /* Row center to row center spacing */
+ pwex = 0.0; /* Patch width expansion between rows of a strip */
+ mxpprow = MAXPPROW; /* Maximum patches per row permitted */
+ mxrowl = MAXROWLEN; /* Maximum row length */
+ tidrows = 0; /* No rows on first page for target ID */
+ rpstrip = 999; /* Rows per strip */
+ txhi = txhisl = 5.0; /* Text Height */
+ docutmarks = 0; /* Don't generate strip cut marks */
+ clwi = 0.0; /* Cut line width */
+ dorowlabel = 1; /* Generate row labels */
+ rlwi = 8.0; /* Row label width */
+ pglth = 5.0; /* Page Label text height */
+
+ } else if (itype == instDTP41) { /* Xrite DTP41 */
+ hex = 0; /* No hex for strip instruments */
+ hxew = hxeh = 0.0; /* No extra padding because no hex */
+ domaxmin = 0; /* Don't print max and min patches */
+ nmaxp = nminp = 0; /* Extra max/min patches */
+ nextrap = nmaxp + nminp;/* Number of extra patches for max and min */
+ dorspace = 0; /* Maximise number of rows */
+ dopglabel = 1; /* Write a per page label */
+ padlrow = 1; /* Pad the last row with white */
+ if (spacer < 0)
+ spacer = 2; /* Colored Spacer */
+ needpc = 1; /* Need patch to patch contrast in a row */
+ lspa = inch2mm(1.5); /* Leader space before first patch */
+ lcar = inch2mm(0.5); /* Leading clear area before first patch */
+ plen = pscale * inch2mm(0.29); /* Patch min length (should be 7.0 mm min.) */
+ if (spacer > 0)
+ pspa = pscale * sscale * inch2mm(0.08); /* Inbetween Patch spacer (should be 2.0 mm min.)*/
+ else
+ pspa = 0.0; /* No spacer */
+ tspa = 2 * (plen + pspa); /* Clear space after last patch */
+ pwid = inch2mm(0.5); /* Patch min width */
+ rrsp = inch2mm(0.5); /* Row center to row center spacing */
+ pwex = (rrsp - pwid)/2.0; /* Patch width expansion between rows of a strip */
+ if (nollimit == 0) {
+ mxpprow = 100; /* Maximum patches per row permitted */
+ mxrowl = inch2mm(55.0); /* Maximum row length */
+ } else {
+ mxpprow = MAXPPROW; /* Maximum patches per row permitted */
+ mxrowl = MAXROWLEN; /* Maximum row length */
+ }
+ tidrows = 0; /* No rows on first page for target ID */
+ rpstrip = 8; /* Rows per strip */
+ txhi = txhisl = 5.0; /* Text Height */
+ docutmarks = 1; /* Generate strip cut marks */
+ clwi = 0.3; /* Cut line width */
+ dorowlabel = 0; /* Don't generate row labels */
+ rlwi = 0.0; /* Row label width */
+ pglth = 5.0; /* Page Label text height */
+
+ } else if (itype == instDTP51) { /* Xrite DTP51 */
+ hex = 0; /* No hex for strip instruments */
+ hxew = hxeh = 0.0; /* No extra padding because no hex */
+ domaxmin = 1; /* Print max and min patches */
+ nmaxp = nminp = 1; /* Extra max/min patches */
+ nextrap = nmaxp + nminp;/* Number of extra patches for max and min */
+ dorspace = 1; /* Do a rrsp from center of last patch to cut line */
+ dopglabel = 0; /* No need for a per page label */
+ padlrow = 1; /* Pad the last row with white */
+ if (spacer < 0)
+ spacer = 2; /* Colored Spacer */
+ needpc = 1; /* Need patch to patch contrast in a row */
+ lspa = inch2mm(1.2); /* Leader space before first patch */
+ lcar = inch2mm(0.25); /* Leading clear area before first patch */
+ plen = pscale * inch2mm(0.4); /* Patch min length */
+ if (spacer > 0)
+ pspa = pscale * sscale * inch2mm(0.07); /* Inbetween Patch spacer */
+ else
+ pspa = 0.0; /* No spacer */
+ tspa = inch2mm(0.0); /* Clear space after last patch */
+ pwid = inch2mm(0.4); /* Patch min width */
+ rrsp = inch2mm(0.5); /* Row center to row center spacing */
+ pwex = (rrsp - pwid)/2.0; /* Patch width expansion between rows of a strip */
+ if (nollimit == 0) {
+ mxpprow = 72; /* Maximum patches per row permitted */
+ mxrowl = inch2mm(40.0); /* Maximum row length */
+ } else {
+ mxpprow = MAXPPROW; /* Maximum patches per row permitted */
+ mxrowl = MAXROWLEN; /* Maximum row length */
+ }
+ tidrows = 0; /* No rows on first page for target ID */
+ rpstrip = 6; /* Rows per strip */
+ txhi = txhisl = 5.0; /* Text Height */
+ docutmarks = 1; /* Generate strip cut marks */
+ clwi = 0.3; /* Cut line width */
+ dorowlabel = 0; /* Don't generate row labels */
+ rlwi = 0.0; /* Row label width */
+ pglth = 5.0; /* Page Label text height */
+
+ } else if (itype == instSpectroScan ) { /* GretagMacbeth SpectroScan */
+ hex = hflag ? 1 : 0; /* Hex if requestested */
+ domaxmin = 0; /* Don't print max and min patches */
+ nextrap = 0; /* Number of extra patches for max and min */
+ nmaxp = nminp = 0; /* Extra max/min patches */
+ nextrap = nmaxp + nminp;/* Number of extra patches for max and min */
+ dorspace = 0; /* Maximise number of rows */
+ dopglabel = 1; /* Write a per page label */
+ padlrow = 0; /* Pad the last row with white */
+ spacer = 0; /* No spacer */
+ needpc = 0; /* Don't need patch to patch contrast in a row */
+ lspa = bord + 7.0; /* Leader space before first patch = border + text */
+ lcar = 0.0; /* Leading clear area before first patch */
+ if (hex) {
+ plen = pscale * sqrt(0.75) * 7.0; /* Patch min length */
+ hxeh = 1.0/6.0 * plen; /* Extra border for hex tops & bottoms */
+ hxew = pscale * 0.25 * 7.0; /* Extra border for hex sides */
+ } else {
+ plen = pscale * 7.0; /* Patch min length */
+ hxew = hxeh = 0.0; /* No extra padding because no hex */
+ }
+ pspa = 0.0; /* Inbetween Patch spacer */
+ tspa = 0.0; /* Clear space after last patch */
+ pwid = pscale * 7.0; /* Patch min width */
+ rrsp = pscale * 7.0; /* Row center to row center spacing */
+ pwex = 0.0; /* Patch width expansion between rows of a strip */
+ mxpprow = MAXPPROW; /* Maximum patches per row permitted */
+ mxrowl = MAXROWLEN; /* Maximum row length */
+ tidrows = 0; /* No rows on first page for target ID */
+ rpstrip = 999; /* Rows per strip */
+ txhi = txhisl = 5.0; /* Row/Column Text Height */
+ docutmarks = 0; /* Don't generate strip cut marks */
+ clwi = 0.0; /* Cut line width */
+ dorowlabel = 1; /* Generate row labels */
+ rlwi = 7.5; /* Row label width */
+ pglth = 5.0; /* Page Label text height */
+
+ } else if (itype == instI1Pro ) { /* GretagMacbeth Eye-One Pro */
+ if (nolpcbord == 0 && bord < 26.0)
+ lbord = 26.0 - bord; /* need this for holder to grip paper and plastic spacer */
+ hex = 0; /* No hex for strip instruments */
+ hxew = hxeh = 0.0; /* No extra padding because no hex */
+ domaxmin = 0; /* Don't print max and min patches */
+ nextrap = 0; /* Number of extra patches for max and min */
+ nmaxp = nminp = 0; /* Extra max/min patches */
+ nextrap = nmaxp + nminp;/* Number of extra patches for max and min */
+ dorspace = 0; /* Maximise number of rows by having no space between them */
+ dopglabel = 1; /* Write a per page label */
+ padlrow = 1; /* Don't need to pad the last row for the i1, */
+ /* but the strip read logic can't handle it. */
+ if (spacer < 0)
+ spacer = 2; /* Colored Spacer */
+ needpc = 1; /* Need patch to patch contrast in a row */
+ usede = 1; /* Use delta E to maximize patch/spacer conrast */
+ lspa = bord + 7.0 + 10.0; /* Leader space before first patch = bord + txhisl + lcar */
+ lcar = 10.0; /* Leading clear area before first patch */
+ plen = pscale * 10.00; /* Patch min length - total 11 mm */
+ if (spacer > 0)
+ pspa = pscale * sscale * 1.00; /* Inbetween Patch spacer 1mm */
+ else
+ pspa = 0.0; /* No spacer */
+ tspa = 10.0; /* Clear space after last patch - run off */
+ pwid = pscale * 8.0; /* Patch min width */
+ rrsp = pscale * 8.0; /* Row center to row center spacing */
+ pwex = 0.0; /* Patch width expansion between rows of a strip */
+ if (nollimit == 0) {
+ mxpprow = MAXPPROW; /* Maximum patches per row permitted (set by length) */
+ mxrowl = (260.0 - lcar - tspa); /* Maximum holder row length */
+ } else {
+ mxpprow = MAXPPROW; /* Maximum */
+ mxrowl = MAXROWLEN; /* Maximum */
+ }
+ tidrows = 0; /* No rows on first page for target ID */
+ rpstrip = 999; /* Rows per strip */
+ txhi = txhisl = 7.0; /* Text Height */
+ docutmarks = 0; /* Don't generate strip cut marks */
+ clwi = 0.0; /* Cut line width */
+ dorowlabel = 0; /* Don't generate row labels */
+ rlwi = 0.0; /* Row label width */
+ pglth = 5.0; /* Page Label text height */
+
+ } else if (itype == instColorMunki ) { /* X-Rite ColorMunki */
+ hex = 0; /* No hex for strip instruments */
+ hxew = hxeh = 0.0; /* No extra padding because no hex */
+ domaxmin = 0; /* Don't print max and min patches */
+ nextrap = 0; /* Number of extra patches for max and min */
+ nmaxp = nminp = 0; /* Extra max/min patches */
+ nextrap = nmaxp + nminp;/* Number of extra patches for max and min */
+ dorspace = 0; /* Put spaces between rows for guidance */
+ dopglabel = 1; /* Write a per page label */
+ padlrow = 1; /* Don't need to pad the last row for the Munki, */
+ /* but the strip read logic can't handle it. */
+ if (spacer < 0)
+ spacer = 2; /* Colored Spacer */
+ needpc = 1; /* Need patch to patch contrast in a row */
+ usede = 1; /* Use delta E to maximize patch/spacer conrast */
+ lspa = bord + 7.0 + 20.0; /* Leader space before first patch = bord + txhisl + lcar */
+ lcar = 20.0; /* Leading clear area before first patch */
+ plen = pscale * 14.00; /* Patch min length - total 15 mm */
+ if (spacer > 0)
+ pspa = pscale * sscale * 1.0; /* Inbetween Patch spacer 1mm */
+ else
+ pspa = 0.0; /* No spacer */
+ tspa = 25.0; /* Clear space after last patch - run off */
+ if (hflag) { /* High density */
+ pwid = pscale * 13.7; /* Patch min width */
+ rrsp = pscale * 13.7; /* Row center to row center spacing */
+ hxeh = 0.25 * plen; /* Extra space for row stagger */
+ stagger = 0.5 * (plen + 0.5 * pspa); /* Do stagger */
+ } else {
+ pwid = pscale * 28.0; /* Patch min width */
+ rrsp = pscale * 28.0; /* Row center to row center spacing */
+ }
+ pwex = 0.0; /* Patch width expansion between rows of a strip */
+ mxpprow = MAXPPROW; /* Maximum patches per row permitted (set by length) */
+ mxrowl = MAXROWLEN; /* Maximum row length */
+ tidrows = 0; /* No rows on first page for target ID */
+ rpstrip = 999; /* Rows per strip */
+ txhi = txhisl = 7.0; /* Text Height */
+ docutmarks = 0; /* Don't generate strip cut marks */
+ clwi = 0.0; /* Cut line width */
+ dorowlabel = 0; /* Don't generate row labels */
+ rlwi = 0.0; /* Row label width */
+ pglth = 5.0; /* Page Label text height */
+
+
+ } else {
+ error("Unsupported intrument type");
+ }
+
+ /* Compute page limits */
+ x1 = bord + lbord; /* Bounding box in mm */
+ y1 = bord;
+ x2 = pw - bord;
+ y2 = ph - bord;
+ iw = x2 - x1; /* Imagable areas width and height in mm */
+ ih = y2 - y1;
+
+ *p_patchlen = plen; /* Return patch lenth in mm */
+ *p_gaplen = pspa; /* Return gap lenth in mm */
+ *p_taplen = tspa; /* Return trailer lenth in mm */
+
+ if (scanc & 2) /* Scan compatiblity */
+ sxwi = pwid/2.0; /* First row patches extra width */
+
+ /* Compute limits for this page size */
+ /* Figure the available space for patches */
+ mints = bord + txhisl + lcar; /* Minimum top space due to border, text and clear area */
+ if (mints < lspa)
+ mints = lspa; /* Minimum top space due to leader */
+ minbs = bord; /* Minimum botom space due to border */
+ if (minbs < tspa)
+ minbs = tspa; /* Minimum botom space due to trailer */
+ arowl = ph - mints - minbs - 2.0 * hxeh; /* Available space for printing test patches */
+ if (arowl > mxrowl)
+ arowl = mxrowl; /* Limit maximum row length */
+
+ /* We are assuming that every patch may be surounded by a spacer */
+ /* (ie. there are always pprow+1 gaps spacers are used) */
+ pprow = (int)((arowl - pspa)/(plen + pspa)); /* Raw Patches per row */
+ if (pprow > mxpprow) /* Limit to maximum */
+ pprow = mxpprow;
+
+ tidpprow = 0;
+ if (tidminp > 0 && tidplen > 0.0) {
+ tidpprow = (int)((arowl - pspa)/(tidplen + pspa)); /* Raw TID Patches per row */
+ if (tidpprow < tidminp) /* TID doesn't use nextrap */
+ error("Paper size not long enough for target identification row (need %.1f mm, got %.1f mm)!",tidminp * (tidplen + pspa) - pspa, arowl);
+ }
+
+ tidpad = (pprow - tidminp)/2; /* Center TID */
+
+ if (pprow < (1+nextrap))
+ error("Paper size not long enought for a single patch per row!");
+
+ *ptpprow = tpprow = pprow - nextrap; /* Test sample patches per row */
+
+ tidnpat = npat + (tidrows * tpprow); /* Total patches including TID row, but not max/min/sid */
+
+ /* (Sample patches per row including TID) */
+ if ((*pprps = (unsigned char *)malloc(sizeof(unsigned char) * (2 + (tidnpat/tpprow)))) == NULL)
+ error("Malloc failed!");
+ rpsp = *pprps;
+
+ /* Compute actual lowest coordinate used */
+ aminbs = ph - mints - pspa - pprow * (plen + pspa);
+ amints = mints + 0.5 * (aminbs - minbs); /* Distribute extra space */
+ aminbs = minbs + 0.5 * (aminbs - minbs);
+
+ /* Compute whole strip width */
+ if (dorspace)
+ swid = rpstrip * rrsp + pwid/2.0; /* set gutter is rrsp - pwid/2 wide */
+ else
+ swid = (rpstrip-1) * rrsp + pwid + clwi; /* set gutter is 0, but allow for cut line */
+
+ /* Compute strips per page. Number of whole strips + partial strips */
+ sppage = (int)((iw - rlwi - sxwi - 2.0 * hxew - (dopglabel ? pglth : 0.0))/swid) + 1;
+
+ /* Compute rows per partial strip on whole page */
+ if (dorspace)
+ rppstrip = (int)((iw - rlwi - sxwi - 2.0 * hxew - (dopglabel ? pglth : 0.0) - swid * (sppage-1) - pwid/2.0)/rrsp);
+ else
+ rppstrip = (int)((iw - rlwi - sxwi - 2.0 * hxew - (dopglabel ? pglth : 0.0) - swid * (sppage-1) - pwid + rrsp)/rrsp);
+ if (rppstrip < 0)
+ rppstrip = 0;
+ if (rppstrip == 0) { /* Make last partial strip a full strip */
+ sppage--;
+ rppstrip = rpstrip;
+ }
+
+ if (sppage <= 0)
+ error("Not enough width for even one row!");
+
+ /* The number of pages needed */
+ pppage = tpprow * ((sppage-1) * rpstrip + rppstrip);/* Real patches per page */
+ npages = (tidnpat + pppage -1)/pppage; /* whole & partial pages */
+ ppstrip = tpprow * rpstrip; /* Real patches per full strip */
+
+ rem = tidnpat; /* Total test patches to print */
+ rem -= (npages-1) * pppage; /* Remaining patches to be printed on last page */
+
+ lsppage = (rem + ppstrip -1)/ppstrip; /* Last pages whole & partial strips per page */
+ rem -= (lsppage - 1) * ppstrip; /* remaining patches to be printed in last strip */
+
+ lrpstrip = (rem + tpprow - 1)/tpprow;
+ /* Last strips whole & partial rows per strip */
+
+ rem -= (lrpstrip - 1) * tpprow; /* remaining patches to be printed in last row */
+
+ lpprow = rem + nextrap; /* Patches in last row of last strip of last page */
+
+ if (verb) {
+ fprintf(stderr,"Patches = %d\n",npat);
+ fprintf(stderr,"Test patches per row = %d\n",tpprow);
+ if (sppage == 1)
+ fprintf(stderr,"Rows per page = %d, patches per page = %d\n",rppstrip, pppage);
+ else
+ fprintf(stderr,"Strips per page = %d, rows per partial strip = %d, patches per page = %d\n",sppage, rppstrip, pppage);
+ if (tidrows > 0)
+ fprintf(stderr,"Target ID rows in first page = %d\n", tidrows);
+ fprintf(stderr,"Rows in last strip = %d, patches in last row = %d\n", lrpstrip, lpprow-nextrap);
+ fprintf(stderr,"Total pages needed = %d\n",npages);
+ }
+
+ if (padlrow) { /* Add in extra padding patches */
+ int i;
+ for (i = 0; lpprow < pprow; lpprow++, npat++, tidnpat++, i = (i + 1) & 7) {
+#ifdef NEVER
+ if (needpc && rand)
+ cols[npat] = pcol[i]; /* structure copy */
+ else
+ cols[npat] = *media; /* structure copy */
+#else
+ cols[npat] = *media; /* structure copy */
+#endif
+ cols[npat].i = npat; /* Now has an index */
+ cols[npat].t &= ~T_PRESET;
+ cols[npat].t |= T_PAD;
+ cols[npat].id = "0"; /* Padding identification */
+ }
+ }
+ *p_npat = npat; /* Return number of patches including padding */
+//printf("~1 padded no of patches = %d\n", npat);
+
+ /* Setup logical to random patch mapping */
+ if ((rix = (int *)malloc(sizeof(int) * (npat + 1))) == NULL)
+ error("Malloc failed!");
+
+ setup_randix(rix, npat, rand, rstart, verb, cols, pcol,
+ tpprow, spacer, needpc, domaxmin, media, usede);
+ rix[npat] = -1; /* Shouldn't use this */
+
+ /* Init everything */
+ l_si = i = 0; /* Physical test patch index. */
+ ix = rix[i]; /* First index */
+
+ pir = 1; /* Starting patch in row (includes max/min patches) */
+ ris = 1; /* Starting row in strip. */
+ sip = 1; /* Starting strip in page */
+ pif = 1; /* Starting page in file */
+
+ /* slix is 0..n but is pre-incremented, so start at -1 */
+ slix = -1 -tidrows; /* Start at -2 if there is a TID */
+
+ /* Until there are no more patches to do */
+ for (;;) {
+ char *sp = NULL; /* String pointer - label */
+ double w; /* Width of next patch */
+ int flags; /* flags for current patch */
+#define IS_FPIR 0x00001 /* Is first patch in row (possibly max density patch) */
+#define IS_XPAT 0x00002 /* Is max density/SID patch */
+#define IS_NPAT 0x00004 /* Is min density/SID patch */
+#define IS_LPIR 0x00008 /* Is last patch in row (possibly min density patch) */
+#define IS_FRIS 0x00010 /* Is first row in strip */
+#define IS_LRIS 0x00020 /* Is last row in strip */
+#define IS_FSIP 0x00040 /* Is first strip in page */
+#define IS_LSIP 0x00080 /* Is last strip in page */
+#define IS_FPIF 0x00100 /* Is first page in file */
+#define IS_LPIF 0x00200 /* Is last page in file */
+#define IS_PAD 0x04000 /* Is fake padding patch, to round out very last row */
+
+ /* Init flags for this patch */
+ flags = 0;
+ if (pir == 1)
+ flags |= IS_FPIR;
+ if (pir <= nmaxp)
+ flags |= IS_XPAT;
+
+ if (slix < -1) { /* If TID row */
+
+ if (pir == tidpprow)
+ flags |= IS_LPIR;
+
+ } else {
+
+ if (pir > (pprow - nminp))
+ flags |= IS_NPAT;
+
+ if (pir == pprow)
+ flags |= IS_LPIR;
+ }
+
+ if (ris == 1)
+ flags |= IS_FRIS;
+ if (ris == rpstrip)
+ flags |= IS_LRIS;
+
+ if (sip == 1)
+ flags |= IS_FSIP;
+ if (sip == sppage) {
+ flags |= IS_LSIP;
+ if (ris == rppstrip)
+ flags |= IS_LRIS;
+ }
+ if (pif == 1)
+ flags |= IS_FPIF;
+ if (pif == npages) {
+ flags |= IS_LPIF;
+ if (sip == lsppage) {
+ flags |= IS_LSIP;
+ if (ris == lrpstrip) {
+ flags |= IS_LRIS;
+
+ if (padlrow) { /* Last row in chart may be a runt */
+ if (pir > lpprow)
+ flags |= IS_PAD;
+ } else {
+ if (pir > (lpprow - nminp))
+ flags |= IS_NPAT;
+ if (pir == lpprow)
+ flags |= IS_LPIR;
+ }
+ }
+ }
+ }
+
+//printf("~1 pir %d, ris %d, sip %d, pif %d\n", pir, ris, sip, pif);
+
+ /* Set initial patch width */
+ w = pwid;
+ if (!(flags & IS_FRIS))
+ w += pwex; /* Extend patch into previous row to row gap */
+ if (!(flags & IS_LRIS))
+ w += pwex; /* Extend patch into next row to row gap */
+
+ if ((flags & IS_FRIS) && (flags & IS_FSIP)) /* First row on page */
+ w += sxwi; /* Make first row fatter for scan compatiblity */
+
+ if (flags & IS_FPIR) { /* Start of row */
+ y = ph - amints; /* Start ready for spacer or patch */
+
+ if (flags & IS_FRIS) { /* Start of strip */
+ if (flags & IS_FSIP) { /* Start of page */
+ x = x1; /* Start at leftmost position */
+ if (oft == 0) { /* PS */
+ if (flags & IS_FPIF) { /* First page */
+ sprintf(psname,"%s.ps",bname);
+ if ((tro = new_ps_trend(psname,npages,nmask,pw,ph,oft,rand,rstart)) == NULL)
+ error ("Unable to create output rendering object file '%s'",psname);
+ if (verb)
+ printf("Creating file '%s'\n",psname);
+ }
+ } else if (oft == 1) { /* EPS */
+ if (npages > 1)
+ sprintf(psname,"%s_%02d.eps",bname,pif);
+ else
+ sprintf(psname,"%s.eps",bname);
+ if ((tro = new_ps_trend(psname,npages,nmask,pw,ph,oft,rand,rstart)) == NULL)
+ error ("Unable to create output rendering object file '%s'",psname);
+ if (verb)
+ printf("Creating file '%s'\n",psname);
+ } else { /* TIFF */
+ double res; /* pix/mm */
+ if (npages > 1)
+ sprintf(psname,"%s_%02d.tif",bname,pif);
+ else
+ sprintf(psname,"%s.tif",bname);
+
+ res = tiffres/25.4;
+ if ((tro = new_tiff_trend(psname,nmask,tiffdpth,pw,ph,
+ nosubmarg ? 0 : bord, res,res,altrep,ncha,tiffcomp, tiffdith)) == NULL)
+ error ("Unable to create output rendering object file '%s'",psname);
+ if (verb)
+ printf("Creating file '%s'\n",psname);
+ }
+ tro->startpage(tro,pif);
+
+ /* Print all the row labels */
+ if (dorowlabel) {
+ double ty = y; /* Temp y coord */
+ int tpir; /* Temp patch in row */
+
+ for (tpir = 0; tpir < pprow; tpir++) {
+ /* If we're within test sample patch range */
+ if (tpir >= nmaxp && tpir < (pprow - nminp)) {
+ char *rlabl;
+ if ((rlabl = paix->aix(paix, tpir - nmaxp)) == NULL)
+ error ("Patch in row label %d out of range",tpir);
+ tro->setcolor(tro, cal, mark);
+ tro->string(tro, x, ty-plen, rlwi, plen, rlabl);
+ free(rlabl);
+ }
+
+ ty -= plen + pspa;
+ }
+
+ x += rlwi;
+ }
+
+ x += hxew; /* Extra space on left for bits of hex */
+
+ /* Clear edge list tracking */
+ et_clear();
+ }
+ }
+
+ /* Increment strip label 0..n */
+ slix++;
+
+ /* Print strip label */
+ if ((lspa - lcar - bord) >= txhisl) { /* There is room for label */
+ if (slix < 0) { /* TID */
+ tro->setcolor(tro, cal, mark);
+ tro->string(tro,x,y2-txhisl,w,txhisl,"TID");
+ } else { /* Not TID */
+ if (slab != NULL)
+ free(slab);
+ if ((slab = saix->aix(saix, slix)) == NULL)
+ error("strip index %d out of range",slix);
+
+ tro->setcolor(tro, cal, mark);
+ tro->string(tro,x,y2-txhisl,w,txhisl,slab);
+ }
+ }
+
+ /* Start with background = media */
+ pp = media;
+
+ /* Stagger rows */
+ if (stagger > 0.0) {
+ if (slix & 1)
+ y -= stagger;
+ }
+ }
+
+ /* Figure the current patch color */
+ cpf = 0;
+ if (slix < 0) { /* TID */
+ cp = mind; /* Default padding color is white */
+ if (pir > tidpad && pir <= (tidpad + tidminp) ) {
+ int opir = pir - tidpad -1; /* TID index 0 .. tidminp-1 */
+
+ if (opir == 0) {
+ cp = &pcol[1]; /* Cyan */
+
+ } else if (opir >= 1 && opir <= 2) { /* Patches in each strip */
+ col *ppcol[2];
+ if (dtp20_enc(pcol, 2, 0, ppcol, tpprow) != 0)
+ error("Internal, dtp20 TID ppstrip failed, val %d, digits %d",tpprow,2);
+ cp = ppcol[opir-1];
+
+ } else if (opir >= 3 && opir <= 6) { /* Total patches, including padding */
+ col *ppcol[4];
+ if (dtp20_enc(pcol, 4, 0, ppcol, npat) != 0)
+ error("Internal, dtp20 tot patches failed, val %d, digits %d",npat,4);
+ cp = ppcol[opir-3];
+
+ } else if (opir == 7) { /* Patch size */
+ int j;
+ for (j = 0; j < 8; j++) {
+ if (fabs(pcol[j].dtp20_psize - plen) < 0.001)
+ break;
+ }
+ if (j >= 8)
+ error("Can't encode patch length for DTP20");
+ cp = &pcol[j];
+
+ } else if (opir == 8) { /* Patch spacer width */
+ int j, k;
+ k = (int)(pspa / 0.5 + 0.5);
+ for (j = 0; j < 8; j++) {
+ if (pcol[j].dtp20_octval == k)
+ break;
+ }
+ if (j >= 8)
+ error("Can't encode spacer length for DTP20");
+ cp = &pcol[j];
+
+ } else if (opir >= 9 && opir <= 18) { /* User defined */
+
+ if (opir == 9) { /* Indicate what user defined is used for */
+ cp = &pcol[0]; /* 0 = random seed format */
+ } else if (opir >= 10 && opir <= 13) { /* Random seend value */
+ col *ppcol[4];
+ if (dtp20_enc(pcol, 4, 0, ppcol, rstart) != 0)
+ error("Internal, dtp20 chart id failed, val %d, digits %d",rstart,4);
+ cp = ppcol[opir-10];
+
+ } else { /* 14 .. 18 */
+ cp = &pcol[0]; /* Currently unused */
+ }
+
+ } else if (opir == 19) {
+ cp = &pcol[4]; /* Yellow */
+ } else if (opir == 20) {
+ cp = &pcol[2]; /* Magenta */
+ }
+ }
+ } else {
+ if (flags & IS_XPAT) { /* Max or SID at start of row */
+ sp = NULL; /* Not a test patch (no label) */
+ if (domaxmin == 1) {
+ cp = maxd; /* Maximum density patch at start */
+ } else if (domaxmin == 2) {
+ if (pir == 1) { /* At very start */
+ cpf = 1; /* Create start bit */
+ cp = &pcol[8]; /* Starts with 50/50/50 DTP20 Grey */
+ } else {
+ col *ppcol[3];
+ /* Compute the patch colors the DTP20 will use before row */
+ if (dtp20_enc(pcol, 3, 1, ppcol, slix+1) != 0)
+ error("Internal, dtp20 SID row id failed, val %d, digits %d",slix+1,3);
+ cp = ppcol[pir-2];
+ }
+ }
+
+ } else if (flags & IS_NPAT) { /* Min at end of rows or stop bit */
+ sp = NULL; /* Not a test patch (no label) */
+ if (domaxmin == 1) {
+ cp = mind;
+ } else if (domaxmin == 2) { /* DTP20 end patch */
+ cpf = 2; /* Create stop bit */
+ cp = mind; /* Starts with mind */
+ }
+
+ } else if (flags & IS_PAD) { /* Fake blank patch */
+ sp = NULL; /* Not a test patch (no label) */
+ cp = media;
+
+ } else { /* set test sample patch location and color */
+ int apir = pir - nmaxp; /* Adjusted pir for max/min patches */
+ if (sp != NULL)
+ free(sp);
+ if ((sp = patch_location(saix, paix, ixord, slix, apir-1)) == NULL)
+ error ("Patch location out of range, strip %d patch %d",slix,apir-1);
+ if (ix < 0) {
+ error("Internal, got -ve patch index for generating patch %d",i);
+ }
+ strcpy(cols[ix].loc, sp); /* Record location */
+ cp = &cols[ix]; /* Get color for this patch */
+
+ i++; /* Consumed a test patch */
+ if (i > npat)
+ error("Internal - ran out of test patches !");
+
+ ix = rix[i]; /* Next patch index */
+ }
+ }
+
+ /* Print a spacer in front of patch if requested */
+ if (spacer > 0) {
+ setup_spacer(&sc, pp, cp, pcol, spacer, usede);
+ tro->setcolor(tro, cal, sc);
+ tro->rectangle(tro, x, y, w, pspa, NULL,1);
+ y -= pspa;
+ }
+
+ /* Print patch */
+ {
+ double wplen = plen;
+
+ if (slix < 0) {
+ wplen = tidplen; /* TID can have a different length patch */
+ }
+
+ tro->setcolor(tro, cal, cp); /* Patch color set above */
+ if (hex) {
+ int apir = pir - nmaxp; /* Adjusted pir for max/min patches */
+ tro->hexagon(tro, x, y, w, wplen, apir-1, sp);
+ } else {
+ /* We hack in the twin patches for the DTP20 start and stop */
+ /* Initial color is set above (as for regular patches) */
+ if (cpf == 1) { /* DTP20 start bit */
+ tro->rectangle(tro, x, y, w, 1.0, sp,1); /* 50/50/50 set above */
+ tro->setcolor(tro, cal, mind); /* White */
+ tro->rectangle(tro, x, y - 1.0, w, wplen - 1.0, sp,1);
+ } else if (cpf == 2) { /* DTP20 stop bit */
+ tro->rectangle(tro, x, y, w, wplen - 3.0, sp,1); /* mind set above */
+ tro->setcolor(tro, cal, &pcol[8]); /* 50/50/50 Grey for DTP20 */
+ tro->rectangle(tro, x, y - wplen + 3.0, w, 3.0, sp,1);
+ } else { /* Normal patch */
+ tro->rectangle(tro, x, y, w, wplen, sp,1);
+ }
+ }
+ y -= wplen;
+ }
+ if (sp != NULL) { /* Done with sp for the moment */
+ free(sp);
+ sp = NULL;
+ }
+
+ /* Advance the patch count */
+ pir++;
+ pp = cp; /* Current color becomes last color */
+
+ /* If this is the last patch in the row, */
+ /* print a possible last spacer. */
+ if (flags & IS_LPIR) { /* End of row */
+ cp = media;
+ if (spacer > 0) {
+ setup_spacer(&sc, pp, cp, pcol, spacer, usede);
+ tro->setcolor(tro, cal, sc);
+ tro->rectangle(tro, x, y, w, pspa, NULL,1);
+ y -= pspa;
+ }
+ }
+
+ if (flags & IS_LPIR) { /* Last patch in row */
+ pir = 1;
+ ris++;
+
+ /* First step to the middle of the patch */
+ if (flags & IS_FRIS)
+ x += pwid/2.0;
+ else
+ x += pwid/2.0 + pwex;
+
+ /* Then step to the start of the next patch */
+ if (flags & IS_LRIS) {
+ if (dorspace)
+ x += rrsp; /* row to row space, making gutter */
+ else
+ x += pwid/2.0 + clwi; /* no gutter, but room for cut line */
+ } else
+ x += pwid/2.0 + pwex;
+
+ if ((flags & IS_FRIS) && (flags & IS_FSIP)) /* First row on page */
+ x += sxwi; /* Allow for scan compatible fatter first row */
+
+ if (flags & IS_LRIS) { /* End of strip */
+ /* Ignore TID rows */
+ if ((flags & IS_FPIF) && (flags & IS_FSIP))
+ *rpsp++ = ris-tidrows-1; /* Record how many rows in this strip */
+ else
+ *rpsp++ = ris-1; /* Record how many rows in this strip */
+ ris = 1;
+ sip++;
+
+ /* Print end of strip crop line */
+ tro->setcolor(tro, cal, mark);
+ if (docutmarks) /* Generate strip cut marks */
+ tro->dline(tro,x-0.3/2.0,y1,x-0.3/2.0,y2,0.3); /* 0.3 wide dotted line */
+
+ /* Print end of strip identification if we've allowed space */
+ if (dorspace)
+ tro->vstring(tro,x,y1,rrsp-pwid/2.0-pwex,y2-y1,label);
+
+ if (flags & IS_LSIP) { /* End of page */
+ sip = 1;
+
+ x += hxew; /* Allow space for extra bits of hexagons */
+
+ /* Print per page label if we've allowed for it */
+ if (dopglabel) {
+ //tro->vstring(tro,x2,y1,pglth,y2-y1,label); /* At end of page */
+ tro->vstring(tro,x+pglth,y1,pglth,y2-y1,label); /* After last strip */
+ }
+
+ /* If we expect to scan this chart in, add some fiducial marks at the corners */
+ if (scanc & 1) {
+ double lw = 0.5; /* Line width */
+ double ll = 5.0; /* Line length */
+
+// fprintf(of,"%% Fiducial marks\n");
+
+ tro->setcolor(tro, cal, mark);
+
+ tro->rectangle(tro, x1, y2, ll, lw, NULL, 0); /* Top left */
+ tro->rectangle(tro, x1, y2, lw, ll, NULL, 0);
+ if (oft != 2)
+ et_fiducial(mm2pnt(x1 + 0.5 * lw), mm2pnt(y2 - 0.5 * lw));
+ else
+ et_fiducial(x1 + 0.5 * lw, y2 - 0.5 * lw);
+
+ tro->rectangle(tro, x2 - ll, y2, ll, lw, NULL, 0); /* Top right */
+ tro->rectangle(tro, x2 - lw, y2, lw, ll, NULL, 0);
+ if (oft != 2)
+ et_fiducial(mm2pnt(x2 - 0.5 * lw), mm2pnt(y2 - 0.5 * lw));
+ else
+ et_fiducial(x2 - 0.5 * lw, y2 - 0.5 * lw);
+
+ tro->rectangle(tro, x2 - ll, y1 + lw, ll, lw, NULL, 0); /* Bottom right */
+ tro->rectangle(tro, x2 - lw, y1 + ll, lw, ll, NULL, 0);
+ if (oft != 2)
+ et_fiducial(mm2pnt(x2 - 0.5 * lw), mm2pnt(y1 + 0.5 * lw));
+ else
+ et_fiducial(x2 - 0.5 * lw, y1 + 0.5 * lw);
+
+ tro->rectangle(tro, x1, y1 + lw, ll, lw, NULL, 0); /* Bottom left */
+ tro->rectangle(tro, x1, y1 + ll, lw, ll, NULL, 0);
+ if (oft != 2)
+ et_fiducial(mm2pnt(x1 + 0.5 * lw), mm2pnt(y1 + 0.5 * lw));
+ else
+ et_fiducial(x1 + 0.5 * lw, y1 + 0.5 * lw);
+ }
+
+ tro->endpage(tro);
+ if (oft != 0) { /* EPS or TIFF */
+ tro->del(tro);
+ }
+ if (flags & IS_LPIF) { /* Last page in file */
+ if (oft == 0) { /* PS */
+ tro->del(tro);
+ }
+ }
+
+ /* If we are anticipating that scanin may be used with the */
+ /* chart, create the scanin recognition file for this page. */
+ if (scanc & 1) {
+ char chtname[MAXNAMEL+20]; /* Name of .cht file */
+
+ if (npages > 1)
+ sprintf(chtname,"%s_%02d.cht",bname,pif);
+ else
+ sprintf(chtname,"%s.cht",bname);
+ et_write(chtname, cols, rix, l_si, i);
+ }
+
+ l_si = i; /* New last start i */
+
+ if (flags & IS_LPIF) { /* Last page in file */
+ break; /* Done */
+ }
+ pif++;
+ }
+ }
+ }
+ }
+ if (slab != NULL)
+ free(slab);
+ free(rix);
+
+ *rpsp++ = 0; /* End of rows per strip stuff */
+
+ et_clear(); /* Cleanup edge list structures */
+}
+
+/* A paper size structure */
+typedef struct {
+ char *name; /* User name (lower case) */
+ double w,h; /* Width and height in mm */
+ int def; /* Non-zero if default */
+} paper;
+
+static paper psizes[] = {
+ { "A4", 210.0, 297.0, 0 },
+ { "A4R", 297.0, 210.0, 0 },
+ { "A3", 297.0, 420.0, 1 },
+ { "A2", 420.0, 594.0, 0 },
+ { "Letter", 215.9, 279.4, 0 },
+ { "LetterR", 279.4, 215.9, 0 },
+ { "Legal", 215.9, 355.6, 0 },
+ { "4x6", 101.6, 152.4, 0 },
+ { "11x17", 279.4, 431.8, 0 },
+ { NULL, 0.0, 0.0, 0 }
+};
+
+#define DEF_MARGINE 6.0
+
+/* Case independent string compare */
+int
+cistrcmp(char *s1, char *s2) {
+ for (;;s1++, s2++) {
+ if (tolower(*s1) != tolower(*s2))
+ return 1;
+ if (*s1 == '\000')
+ return 0;
+ }
+}
+
+#define DEF_SIXPAT "A-Z, A-Z" /* Default strip index pattern */
+#define DEF_PIXPAT "0-9,@-9,@-9;1-999" /* Default patch index pattern */
+
+void usage(char *diag, ...) {
+ paper *pp;
+ fprintf(stderr,"Generate Target PostScrip file, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: printtarg [-v] [-i instr] [-r] [-s] [-p size] basename\n");
+ fprintf(stderr," -v Verbose mode\n");
+ fprintf(stderr," -i 20 | 22 | 41 | 51 | SS | i1 | CM Select target instrument (default DTP41)\n");
+ fprintf(stderr," 20 = DTP20, 22 = DTP22, 41 = DTP41, 51 = DTP51,\n");
+ fprintf(stderr," SS = SpectroScan, i1 = i1Pro, CM = ColorMunki\n");
+ fprintf(stderr," -h Use hexagon patches for SS, double density for CM\n");
+ fprintf(stderr," -a scale Scale patch size and spacers by factor (e.g. 0.857 or 1.5 etc.)\n");
+ fprintf(stderr," -A scale Scale spacers by additional factor (e.g. 0.857 or 1.5 etc.)\n");
+ fprintf(stderr," -r Don't randomize patch location\n");
+ fprintf(stderr," -s Create a scan image recognition (.cht) file\n");
+ fprintf(stderr," -S Same as -s, but don't generate wide orientation strip.\n");
+ fprintf(stderr," -c Force colored spacers\n");
+ fprintf(stderr," -b Force B&W spacers\n");
+ fprintf(stderr," -n Force no spacers\n");
+ fprintf(stderr," -f Create PostScript DeviceN Color fallback\n");
+ fprintf(stderr," -w g|r|s|n White colorspace encoding DeviceGray (def), DeviceRGB, Separation or DeviceN\n");
+ fprintf(stderr," -k g|c|s|n Black colorspace encoding DeviceGray (def), DeviceCMYK, Separation or DeviceN\n");
+ fprintf(stderr," -o k|r|n CMY colorspace encoding DefiveCMYK (def), inverted DeviceRGB or DeviceN\n");
+ fprintf(stderr," -e Output EPS compatible file\n");
+ fprintf(stderr," -t [res] Output 8 bit TIFF raster file, optional res DPI (default 100)\n");
+ fprintf(stderr," -T [res] Output 16 bit TIFF raster file, optional res DPI (default 100)\n");
+ fprintf(stderr," -C Don't use TIFF compression\n");
+ fprintf(stderr," -N Use TIFF alpha N channels more than 4\n");
+ fprintf(stderr," -D Dither 8 bit TIFF values down from 16 bit\n");
+ fprintf(stderr," -Q nbits Quantize test values to fit in nbits\n");
+ fprintf(stderr," -R rsnum Use given random start number\n");
+ fprintf(stderr," -K file.cal Apply printer calibration to patch values and include in .ti2\n");
+ fprintf(stderr," -I file.cal Include calibration in .ti2 (but don't apply it)\n");
+ fprintf(stderr," -x pattern Use given strip indexing pattern (Default = \"%s\")\n",DEF_SIXPAT);
+ fprintf(stderr," -y pattern Use given patch indexing pattern (Default = \"%s\")\n",DEF_PIXPAT);
+ fprintf(stderr," -m margin Set a page margin in mm (default %3.1f mm)\n",DEF_MARGINE);
+ fprintf(stderr," -M margin Set a page margin in mm and include it in TIFF\n");
+ fprintf(stderr," -P Don't limit strip length\n");
+ fprintf(stderr," -L Suppress any left paper clip border\n");
+ fprintf(stderr," -p size Select page size from:\n");
+ for (pp = psizes; pp->name != NULL; pp++)
+ fprintf(stderr," %-8s [%.1f x %.1f mm]%s\n", pp->name, pp->w, pp->h,
+ pp->def ? " (default)" : "");
+ fprintf(stderr," -p WWWxHHH Custom size, WWW mm wide by HHH mm high\n");
+ fprintf(stderr," basname Base name for input(.ti1), output(.ti2) and output(.ps/.eps/.tif)\n");
+ exit(1);
+ }
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int fa, nfa, mfa; /* argument we're looking at */
+ int verb = 0;
+ int hflag = 0; /* Hexagon patches for SS, high density for CM */
+ double pscale = 1.0; /* Patch size scale */
+ double sscale = 1.0; /* Spacer size scale */
+ int rand = 1;
+ int qbits = 0; /* Quantization bits */
+ int oft = 0; /* Ouput File type, 0 = PS, 1 = EPS , 2 = TIFF */
+ depth2d tiffdpth = bpc8_2d; /* TIFF pixel depth */
+ double tiffres = 100.0; /* TIFF resolution in DPI */
+ int ncha = 0; /* flag, use nchannel alpha */
+ int tiffdith = 0; /* flag, use TIFF 8 bit dithering */
+ int tiffcomp = 1; /* flag, use TIFF compression */
+ int spacer = -1; /* -1 = default for instrument */
+ /* 0 = forse no spacer, 1 = Force B&W spacers */
+ /* 2 = Force colored spacer */
+ int rstart = -1; /* Random sequence start value */
+ char *sixpat = DEF_SIXPAT; /* Strip index pattern */
+ char *pixpat = DEF_PIXPAT; /* Patch index pattern */
+ alphix *saix, *paix; /* Strip and Patch index generators */
+ int ixord = 0; /* Index order, 0 = strip then patch */
+ int scanc = 0; /* Scan compatible bits, 1 = .cht, 2 = wide first row */
+ int devnfb = 0; /* Add device N fallback colors */
+ int altrep = 0; /* Device K/W/CMY color type 0..8 */
+ int applycal = 0; /* NZ to apply calibration */
+ static char inname[MAXNAMEL+20] = { 0 }; /* Input cgats file name */
+ static char calname[MAXNAMEL+1] = { 0 }; /* Input printer calibration */
+ static char psname[MAXNAMEL+1] = { 0 }; /* Output postscrip file base name */
+ static char outname[MAXNAMEL+20] = { 0 }; /* Output cgats file name */
+ cgats *icg; /* input cgats structure */
+ cgats *ocg; /* output cgats structure */
+ xcal *cal = NULL; /* printer calibration */
+ instType itype = instDTP41; /* Default target instrument */
+ int nmask = 0; /* Device colorant mask */
+ int nchan = 0; /* Number of device chanels */
+ int i;
+ int si, fi, wi; /* sample id index, field index, keyWord index */
+ char label[400]; /* Space for chart label */
+ double marg = DEF_MARGINE; /* Margin from paper edge in mm */
+ int nosubmarg = 0; /* Don't subtract it from raster */
+ int nolpcbord = 0; /* NZ to suppress left paper clip border */
+ int nollimit = 0; /* NZ to release any strip length limits */
+ paper *pap = NULL; /* Paper size pointer, NULL if custom */
+ double cwidth, cheight; /* Custom paper width and height in mm */
+ col *cols; /* test patch colors */
+ int npat; /* Number of patches */
+ int nppat; /* Number of patches including padding */
+ col pcold[8]; /* pre-defined density extreme colors */
+ int pcolvv = 0; /* pcolv valid if nz */
+ col pcolv[9]; /* pre-defined device combination ecolors */
+ col *pcol; /* Chosen color patches for device */
+ double wp[3]; /* Approximate XYZ white point */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ int sip; /* Steps in Pass */
+ unsigned char *pis; /* Passes in strip array */
+ double plen, glen, tlen;/* Patch, gap and trailer length in mm */
+ char *bp, buf[500]; /* general sprintf buffer */
+
+ error_program = "printtarg";
+ check_if_not_interactive();
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ if (argc <= 1)
+ usage("Not enough arguments");
+
+#ifdef DEBUG
+ printf("target: DEBUG is #defined\n");
+#endif
+
+ /* Find the default paper size */
+ for (pap = psizes; pap->name != NULL; pap++) {
+ if (pap->def != 0)
+ break;
+ }
+ if (pap->name == NULL)
+ error ("Internal - can't find default paper size");
+
+ /* Process the arguments */
+ mfa = 1; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Requested usage");
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
+ verb = 1;
+
+ /* hflag patches */
+ else if (argv[fa][1] == 'h' || argv[fa][1] == 'H')
+ hflag = 1;
+
+ /* Patch scaling */
+ else if (argv[fa][1] == 'a') {
+ fa = nfa;
+ if (na == NULL) usage("Expected scale factor to -a");
+ pscale = atof(na);
+ if (pscale < 0.1 || pscale > 4.0)
+ usage("Scale factor %f is outside expected range 0.1 - 4.0",pscale);
+ }
+
+ /* Spacer scaling */
+ else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage("Expected scale factor to -a");
+ sscale = atof(na);
+ if (sscale < 0.1 || sscale > 8.0)
+ usage("Scale factor %f is outside expected range 0.1 - 8.0",sscale);
+ }
+
+ /* Scan compatible */
+ else if (argv[fa][1] == 's')
+ scanc = 3;
+
+ else if (argv[fa][1] == 'S')
+ scanc = 1;
+
+ /* Force colored spacer */
+ else if (argv[fa][1] == 'c')
+ spacer = 2;
+
+ /* Force B&W spacer */
+ else if (argv[fa][1] == 'b' || argv[fa][1] == 'B')
+ spacer = 1;
+
+ /* No spacer */
+ else if (argv[fa][1] == 'n')
+ spacer = 0;
+
+ /* Randomisation off */
+ else if (argv[fa][1] == 'r')
+ rand = 0;
+
+ /* Specify random seed */
+ else if (argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to -R");
+ rstart = atoi(na);
+ if (rstart < 0)
+ usage("Argument to -R must be positive");
+ }
+
+ /* Enable DeviceN color fallback */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F')
+ devnfb = 1;
+
+ /* Select the printer W color representation */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to -w");
+ switch(na[0]) {
+ case 'g':
+ case 'G':
+ altrep = 0;
+ break;
+ case 'r':
+ case 'R':
+ altrep = 4;
+ break;
+ case 's':
+ case 'S':
+ altrep = 5;
+ break;
+ case 'n':
+ case 'N':
+ altrep = 6;
+ break;
+ default:
+ usage("Unexpected argument to -w");
+ }
+ }
+
+ /* Select the printer K color representation */
+ else if (argv[fa][1] == 'k') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to -k");
+ switch(na[0]) {
+ case 'g':
+ case 'G':
+ altrep = 0;
+ break;
+ case 'c':
+ case 'C':
+ altrep = 1;
+ break;
+ case 's':
+ case 'S':
+ altrep = 2;
+ break;
+ case 'n':
+ case 'N':
+ altrep = 3;
+ break;
+ default:
+ usage("Unexpected argument to -k");
+ }
+ }
+
+ /* Select the printer CMY color representation */
+ else if (argv[fa][1] == 'o') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to -o");
+ switch(na[0]) {
+ case 'k':
+ case 'K':
+ altrep = 0;
+ break;
+ case 'r':
+ case 'R':
+ altrep = 7;
+ break;
+ case 'n':
+ case 'N':
+ altrep = 8;
+ break;
+ default:
+ usage("Unexpected argument to -o");
+ }
+ }
+
+ /* EPS */
+ else if (argv[fa][1] == 'e' || argv[fa][1] == 'E')
+ oft = 1;
+
+ /* TIFF */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ oft = 2;
+ if (argv[fa][1] == 'T')
+ tiffdpth = bpc16_2d;
+ else
+ tiffdpth = bpc8_2d;
+
+ if (na != NULL) { /* Found an optional resolution */
+ fa = nfa;
+ tiffres = atof(na);
+ if (tiffres <= 1.0 || tiffres > 1e6)
+ usage("TIFF resolution is out of range");
+ }
+ }
+ /* use Nchannel alpha for TIFF */
+ else if (argv[fa][1] == 'N') {
+ ncha = 1;
+ }
+ /* use 16->8 bit dithering for 8 bit TIFF */
+ else if (argv[fa][1] == 'D') {
+ tiffdith = 1;
+ }
+ /* Don't use TIFF compression */
+ else if (argv[fa][1] == 'C') {
+ tiffcomp = 0;
+ }
+
+ /* Specify quantization bits */
+ else if (argv[fa][1] == 'Q') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to -Q");
+ qbits = atoi(na);
+ if (qbits < 1 || qbits > 32)
+ usage("Argument to -Q must be between 1 and 32");
+ }
+
+ /* Specify strip index pattern */
+ else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to -x");
+ sixpat = na;
+ }
+
+ /* Specify patch index pattern */
+ else if (argv[fa][1] == 'y' || argv[fa][1] == 'Y') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to -y");
+ pixpat = na;
+ }
+
+ /* Border margin */
+ else if (argv[fa][1] == 'm' || argv[fa][1] == 'M') {
+ if (argv[fa][1] == 'M')
+ nosubmarg = 1;
+ fa = nfa;
+ if (na == NULL) usage("Expected border margine argument to -m");
+ marg = atof(na);
+ if (marg < 0.0 || marg > 50.0)
+ usage("Border margin %f is outside expected range",marg);
+ }
+
+ /* Don't limit the strip length */
+ else if (argv[fa][1] == 'P') {
+ nollimit = 1;
+ }
+
+ /* Suppress left paper clip border */
+ else if (argv[fa][1] == 'L') {
+ nolpcbord = 1;
+ }
+
+ /* Page size */
+ else if (argv[fa][1] == 'p') {
+ fa = nfa;
+ if (na == NULL) usage("Expected an argument to -p");
+ for (pap = psizes; pap->name != NULL; pap++) {
+ if (cistrcmp(na, pap->name) == 0)
+ break;
+ }
+
+ if (pap->name == NULL) { /* See if it matches a custom size */
+ if (sscanf(na,"%lfx%lf",&cwidth, &cheight) == 2) {
+ pap = NULL; /* Indicate custom */
+ if (cwidth < 1.0 || cwidth > 4000.0
+ || cheight < 1.0 || cheight > 4000.0)
+ usage("Argument to -p was of unexpected size"); /* Sanity check */
+ } else {
+ usage("Failed to recognise argument to -p");
+ }
+ }
+ }
+ /* Target Instrument type */
+ else if (argv[fa][1] == 'i') {
+ fa = nfa;
+ if (na == NULL) usage("Expected an argument to -i");
+
+ if (strcmp("20", na) == 0)
+ itype = instDTP20;
+ else if (strcmp("22", na) == 0)
+ itype = instDTP22;
+ else if (strcmp("41", na) == 0)
+ itype = instDTP41;
+ else if (strcmp("51", na) == 0)
+ itype = instDTP51;
+ else if (strcmp("SS", na) == 0 || strcmp("ss", na) == 0)
+ itype = instSpectroScan;
+ else if (strcmp("i1", na) == 0 || strcmp("I1", na) == 0)
+ itype = instI1Pro;
+ else if (strcmp("cm", na) == 0 || strcmp("CM", na) == 0)
+ itype = instColorMunki;
+ else
+ usage("Argument to -i wasn't recognised");
+
+ /* Printer calibration */
+ } else if (argv[fa][1] == 'K' || argv[fa][1] == 'I') {
+ if (argv[fa][1] == 'K')
+ applycal = 1;
+ else
+ applycal = 0;
+ fa = nfa;
+ if (na == NULL) usage("Expected an argument to -%c",argv[fa][1]);
+ strncpy(calname,na,MAXNAMEL); calname[MAXNAMEL] = '\000';
+ } else
+ usage("Unknown flag");
+ }
+ else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage("Expecting basename argument");
+ strncpy(inname,argv[fa],MAXNAMEL); inname[MAXNAMEL] = '\000';
+ strcpy(outname,inname);
+ strcpy(psname,inname);
+ strcat(inname,".ti1");
+ strcat(outname,".ti2");
+
+ if (calname[0] != '\000') {
+ if ((cal = new_xcal()) == NULL)
+ error("new_xcal failed");
+ if ((cal->read(cal, calname)) != 0)
+ error("%s",cal->err);
+ }
+
+ /* Set default qantization for known output */
+ if (qbits == 0 && oft == 2) {
+ if (tiffdpth == bpc16_2d || tiffdith != 0)
+ qbits = 16;
+ else if (tiffdpth == bpc8_2d)
+ qbits = 8;
+ }
+
+ if (itype == instSpectroScan) {
+ if (scanc) {
+ if (verb)
+ printf("Can only select hexagonal patches if no scan recognition is needed - ignored!\n");
+ hflag = 0;
+ }
+ } else if (itype == instColorMunki) {
+ /* OK */
+ } else if (hflag) {
+ if (verb)
+ printf("Can only select h flag for SpectrScan or ColorMunki - ignored!\n");
+ hflag = 0;
+ }
+
+ if ((saix = new_alphix(sixpat)) == NULL)
+ error("Strip indexing pattern '%s' doesn't parse",sixpat);
+
+ if ((paix = new_alphix(pixpat)) == NULL)
+ error("Patch in strip indexing pattern '%s' doesn't parse",pixpat);
+
+ icg = new_cgats(); /* Create a CGATS structure */
+ icg->add_other(icg, "CTI1"); /* our special input type is Calibration Target Information 1 */
+
+ if (icg->read_name(icg, inname))
+ error("CGATS file read error : %s",icg->err);
+
+ if (icg->t[0].tt != tt_other || icg->t[0].oi != 0)
+ error ("Input file isn't a CTI1 format file");
+ if (icg->ntables < 2 || icg->ntables > 3)
+ error ("Input file doesn't contain two or three tables");
+
+ if ((npat = icg->t[0].nsets) <= 0)
+ error ("No sets of data");
+
+ /* Allocate room for test patches and maximum padding patches */
+ if ((cols = (col *)malloc(sizeof(col) * (npat + MAXPPROW))) == NULL)
+ error("Malloc failed!");
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI2"); /* our special type is Calibration Target Information 2 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 2",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll printtarg", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ /* Note what instrument the chart is setup for */
+ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(itype) , NULL);
+
+ /* Copy various parameters through */
+ if ((wi = icg->find_kword(icg, 0, "SINGLE_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "SINGLE_DIM_STEPS",icg->t[0].kdata[wi], NULL);
+
+ if ((wi = icg->find_kword(icg, 0, "COMP_GREY_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "COMP_GREY_STEPS",icg->t[0].kdata[wi], NULL);
+
+ if ((wi = icg->find_kword(icg, 0, "MULTI_DIM_STEPS")) >= 0)
+ ocg->add_kword(ocg, 0, "MULTI_DIM_STEPS",icg->t[0].kdata[wi], NULL);
+
+ if ((wi = icg->find_kword(icg, 0, "FULL_SPREAD_PATCHES")) >= 0)
+ ocg->add_kword(ocg, 0, "FULL_SPREAD_PATCHES",icg->t[0].kdata[wi], NULL);
+
+ if ((wi = icg->find_kword(icg, 0, "ACCURATE_EXPECTED_VALUES")) >= 0)
+ ocg->add_kword(ocg, 0, "ACCURATE_EXPECTED_VALUES",icg->t[0].kdata[wi], NULL);
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+ ocg->add_field(ocg, 0, "SAMPLE_LOC", cs_t);
+
+ if ((si = icg->find_field(icg, 0, "SAMPLE_ID")) < 0)
+ error ("Input file '%s' doesn't contain field SAMPLE_ID in first table",inname);
+ if (icg->t[0].ftype[si] != nqcs_t)
+ error ("Field SAMPLE_ID is wrong type");
+
+ /* Read the approximate white point */
+ if ((fi = icg->find_kword(icg, 0, "APPROX_WHITE_POINT")) < 0)
+ error ("Input file doesn't contain keyword APPROX_WHITE_POINT");
+ if (sscanf(icg->t[0].kdata[fi], "%lf %lf %lf", &wp[0], &wp[1], &wp[2]) != 3)
+ error ("Couldn't parse the white point data correctly");
+ wp[0] /= 100.0; wp[1] /= 100.0; wp[2] /= 100.0;
+ ocg->add_kword(ocg, 0, "APPROX_WHITE_POINT",icg->t[0].kdata[fi], NULL);
+
+//printf("~1 got approx white point of %f %f %f\n",wp[0],wp[1],wp[2]);
+
+ /* Figure out the color space */
+ if ((fi = icg->find_kword(icg, 0, "COLOR_REP")) < 0)
+ error ("Input file '%s' doesn't contain keyword COLOR_REPS",inname);
+
+ if ((nmask = icx_char2inkmask(icg->t[0].kdata[fi])) != 0) {
+ int i, j, ii;
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ int xyzix[3]; /* XYZ chanel indexes */
+ char *ident; /* Full ident */
+ char *bident; /* Base ident */
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+ double qscale = (1 << qbits) - 1.0;
+
+ if (cal != NULL && nmask != cal->devmask)
+ error ("Calibration colorspace %s doesn't match .ti1 %s",icx_inkmask2char(cal->devmask, 1),icx_inkmask2char(nmask, 1));
+
+ if ((ii = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0)
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT",icg->t[0].kdata[ii], NULL);
+
+ nchan = icx_noofinks(nmask);
+ ident = icx_inkmask2char(nmask, 1);
+ bident = icx_inkmask2char(nmask, 0);
+
+ for (j = 0; j < nchan; j++) {
+ int imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 0, fname)) < 0)
+ error ("Input file '%s' doesn't contain field %s in first table",inname,fname);
+ if (icg->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+
+ ocg->add_field(ocg, 0, fname, r_t);
+ chix[j] = ii;
+ }
+
+ for (j = 0; j < 3; j++) {
+ if ((ii = icg->find_field(icg, 0, xyzfname[j])) < 0)
+ error ("Input '%s' file doesn't contain field %s in first table",inname,xyzfname[j]);
+ if (icg->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",xyzfname[j]);
+
+ ocg->add_field(ocg, 0, xyzfname[j], r_t);
+ xyzix[j] = ii;
+ }
+
+ ocg->add_kword(ocg, 0, "COLOR_REP", ident, NULL);
+
+ /* Read all the test patches in, and quantize them */
+ for (i = 0; i < npat; i++) {
+ cols[i].i = i;
+ cols[i].t = T_N | T_XYZ;
+ if (devnfb)
+ cols[i].t |= T_NFB;
+ cols[i].nmask = nmask;
+ cols[i].altrep = altrep;
+ cols[i].n = nchan;
+ cols[i].id = ((char *)icg->t[0].fdata[i][si]);
+ sprintf(cols[i].loc, "???");
+ for (j = 0; j < nchan; j++) {
+ double vr, vv = *((double *)icg->t[0].fdata[i][chix[j]]) / 100.0;
+ if (qbits > 0) {
+ vv *= qscale;
+ vr = floor(vv + 0.5);
+ if ((vr - vv) == 0.5 && (((int)vr) & 1) != 0) /* Round to even */
+ vr -= 1.0;
+ vv = vr/qscale;
+ }
+ cols[i].dev[j] = vv;
+ }
+ for (j = 0; j < 3; j++)
+ cols[i].XYZ[j] = *((double *)icg->t[0].fdata[i][xyzix[j]]) / 100.0;
+ col_convert(&cols[i], wp); /* Ensure other representations */
+ }
+
+ free(ident);
+ free(bident);
+ } else
+ error ("Input file keyword COLOR_REPS has unknown value");
+
+ /* Load up the pre-defined density extreme spacer colors */
+ {
+ int i, j, ii;
+ int nsp;
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ int xyzix[3]; /* XYZ chanel indexes */
+ char *bident;
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+
+ nchan = icx_noofinks(nmask);
+ bident = icx_inkmask2char(nmask, 0);
+
+ if ((nsp = icg->t[1].nsets) <= 0)
+ error ("No sets of data in second table");
+
+ for (j = 0; j < nchan; j++) {
+ int imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 1, fname)) < 0)
+ error ("Input file '%s' doesn't contain field %s in second table",inname,fname);
+ if (icg->t[1].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+ chix[j] = ii;
+ }
+
+ for (j = 0; j < 3; j++) {
+ if ((ii = icg->find_field(icg, 1, xyzfname[j])) < 0)
+ error ("Input file '%s' doesn't contain field %s in second table",inname,xyzfname[j]);
+ if (icg->t[1].ftype[ii] != r_t)
+ error ("Field %s is wrong type",xyzfname[j]);
+ xyzix[j] = ii;
+ }
+
+ if (nsp != 8)
+ error ("Expect second set of data to have 8 sets, found %d",nsp);
+
+ /* Read all the density spacer patches in */
+ for (i = 0; i < nsp; i++) {
+ pcold[i].i = -1;
+ pcold[i].t = T_N | T_XYZ | T_PRESET;
+ if (devnfb)
+ pcold[i].t |= T_NFB;
+ pcold[i].nmask = nmask;
+ pcold[i].altrep = altrep;
+ pcold[i].n = nchan;
+ pcold[i].id = "";
+ sprintf(cols[i].loc, "???");
+ for (j = 0; j < nchan; j++)
+ pcold[i].dev[j] = *((double *)icg->t[1].fdata[i][chix[j]]) / 100.0;
+ for (j = 0; j < 3; j++)
+ pcold[i].XYZ[j] = *((double *)icg->t[1].fdata[i][xyzix[j]]) / 100.0;
+ col_convert(&pcold[i], wp); /* Ensure other representations */
+ }
+
+ free(bident);
+ }
+
+ /* Load up the pre-defined device combination barcode colors */
+ if (icg->ntables >= 3) {
+ int i, j, ii;
+ int nsp;
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ int xyzix[3]; /* XYZ chanel indexes */
+ char *bident; /* Base ident */
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+
+ nchan = icx_noofinks(nmask);
+ bident = icx_inkmask2char(nmask, 0);
+
+ if ((nsp = icg->t[2].nsets) > 0) {
+
+ for (j = 0; j < nchan; j++) {
+ int imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = icg->find_field(icg, 2, fname)) < 0)
+ error ("Input file '%s' doesn't contain field %s in third table",inname,fname);
+ if (icg->t[2].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+ chix[j] = ii;
+ }
+
+ for (j = 0; j < 3; j++) {
+ if ((ii = icg->find_field(icg, 2, xyzfname[j])) < 0)
+ error ("Input file '%s' doesn't contain field %s in third table",inname,xyzfname[j]);
+ if (icg->t[2].ftype[ii] != r_t)
+ error ("Field %s is wrong type",xyzfname[j]);
+ xyzix[j] = ii;
+ }
+
+ if (nsp != 9)
+ error ("Expect third set of data to have 9 sets, found %d",nsp);
+
+ /* Read all the barcode CMY color patches in */
+ for (i = 0; i < nsp; i++) {
+ pcolv[i].i = -1;
+ pcolv[i].t = T_N | T_XYZ | T_PRESET;
+ if (devnfb)
+ pcolv[i].t |= T_NFB;
+ pcolv[i].nmask = nmask;
+ pcolv[i].altrep = altrep;
+ pcolv[i].n = nchan;
+ pcolv[i].id = "";
+ sprintf(cols[i].loc, "???");
+ for (j = 0; j < nchan; j++)
+ pcolv[i].dev[j] = *((double *)icg->t[2].fdata[i][chix[j]]) / 100.0;
+ for (j = 0; j < 3; j++)
+ pcolv[i].XYZ[j] = *((double *)icg->t[2].fdata[i][xyzix[j]]) / 100.0;
+ col_convert(&pcolv[i], wp); /* Ensure other representations */
+ }
+
+ free(bident);
+ pcolvv = 1;
+ }
+ }
+
+ if (verb) {
+ if (pap != NULL)
+ printf("Paper chosen is %s [%.1f x %.1f mm]\n", pap->name, pap->w, pap->h);
+ else
+ printf("Paper chosen is custom %.1f x %.1f mm\n", cwidth, cheight);
+ }
+
+ if (rstart == -1) {
+ rstart = clk % npat;
+ } else {
+ rstart = rstart % npat;
+ }
+ sprintf(buf,"%d",rstart);
+ if (rand)
+ ocg->add_kword(ocg, 0, "RANDOM_START", buf, NULL);
+ else
+ ocg->add_kword(ocg, 0, "CHART_ID", buf, NULL);
+
+ if (itype == instSpectroScan && hflag) {
+ ocg->add_kword(ocg, 0, "HEXAGON_PATCHES", "True", NULL);
+ }
+
+ if (itype == instDTP20) {
+ if (pcolvv == 0)
+ error("Input file '%s' doesn't contain device combination table needed for DTP20",inname);
+ pcol = pcolv; /* Barcode color values */
+ } else
+ pcol = pcold; /* Density spacer alues */
+
+
+ sprintf(label, "Argyll Color Management System - Test chart \"%s\" (%s %d) %s",
+ psname, rand ? "Random Start" : "Chart ID", rstart, atm);
+ generate_file(itype, psname, cols, npat, applycal ? cal : NULL, label,
+ pap != NULL ? pap->w : cwidth, pap != NULL ? pap->h : cheight,
+ marg, nosubmarg, nollimit, nolpcbord, rand, rstart, saix, paix, ixord,
+ pscale, sscale, hflag, verb, scanc, oft, tiffdpth, tiffres, ncha, tiffdith,
+ tiffcomp, spacer, nmask, altrep, pcol, wp,
+ &sip, &pis, &plen, &glen, &tlen, &nppat);
+
+ if (itype == instDTP20
+ || itype == instDTP41) { /* DTP20/41 needs this */
+ sprintf(buf,"%f",plen);
+ ocg->add_kword(ocg, 0, "PATCH_LENGTH", buf, NULL);
+ sprintf(buf,"%f",glen);
+ ocg->add_kword(ocg, 0, "GAP_LENGTH", buf, NULL);
+ if (itype == instDTP41) { /* DTP41 needs this */
+ sprintf(buf,"%f",tlen);
+ ocg->add_kword(ocg, 0, "TRAILER_LENGTH", buf, NULL);
+ }
+ }
+
+ sprintf(buf,"%d",sip);
+ ocg->add_kword(ocg, 0, "STEPS_IN_PASS", buf, NULL);
+
+ /* Convert pass in strips count to base 62 */
+ buf[0] = '\000';
+ bp = buf;
+ for (i = 0; ;i++) {
+ if (pis[i] == 0)
+ break;
+ sprintf(bp, "%s%d", i > 0 ? "," : "", pis[i]);
+ bp += strlen(bp);
+ }
+ ocg->add_kword(ocg, 0, "PASSES_IN_STRIPS2", buf, NULL);
+
+ /* Output the default Argyll style strip and patch numbering */
+ ocg->add_kword(ocg, 0, "STRIP_INDEX_PATTERN", sixpat, NULL);
+ ocg->add_kword(ocg, 0, "PATCH_INDEX_PATTERN", pixpat, NULL);
+ ocg->add_kword(ocg, 0, "INDEX_ORDER", ixord ? "PATCH_THEN_STRIP" : "STRIP_THEN_PATCH", NULL);
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < nppat; i++) {
+ cgats_set_elem ary[2 + ICX_MXINKS + 3];
+ int j;
+
+ if (strcmp(cols[i].loc, "???") == 0)
+ warning ("Internal, patch %s (%d) wasn't given a valid location string",cols[i].id,i+1);
+ ary[0].c = cols[i].id;
+ ary[1].c = cols[i].loc;
+ for (j = 0; j < nchan; j++)
+ ary[2 + j].d = 100.0 * cols[i].dev[j];
+ for (j = 0; j < 3; j++)
+ ary[2 + nchan + j].d = 100.0 * cols[i].XYZ[j];
+ ocg->add_setarr(ocg, 0, ary);
+ }
+
+ /* If there is a calibration, append it to the .ti2 file */
+ if (cal != NULL) {
+ if (cal->write_cgats(cal, ocg) != 0)
+ error("Writing cal error : %s",cal->err);
+ }
+
+ if (ocg->write_name(ocg, outname))
+ error("Write error : %s",ocg->err);
+
+ if (cal != NULL)
+ cal->del(cal);
+ paix->del(paix);
+ saix->del(saix);
+ free(pis);
+ free(cols);
+ ocg->del(ocg); /* Clean up */
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+/******************************************************************/
+/* Edge tracking support, for generating the scanner image */
+/* recognition reference chart file. */
+
+/* Establish width and height to convert between topleft and */
+/* bottom left origin ??? ~~9 */
+
+/*
+ Basic algorithm strategy:
+
+ First we simply accumulate the raw recognition and patch
+ identification information. Once the chart is generated, we:
+ sort into horizontal and vertical half edges
+ sort into +ve and -ve edges
+ match +ve and -ve edges
+ for each match, generate a delta edge segment
+ Assume any non-matched edges are against the media.
+ Coalesce delta edges into X & Y edge lists
+ Compute normalised strength.
+ Compute crossing count.
+ Figure average box size, and compute shrink.
+
+*/
+
+/* A half edge structure */
+/* coordinate origin is top left */
+struct _hedge {
+ double rgb[3]; /* Color this half edge transitions to */
+ int negh; /* 1 if this is a -ve major coordinate side half edge, 0 otherwise */
+ double mj; /* Major coordinate offset (ie. X coord for vertical edge) */
+ double mi0; /* Minor coordinate smaller value (ie. Y for vertical edge) */
+ double mi1; /* Minor coordinate larger value (ie. Y for vertical edge) */
+ struct _hedge *next; /* Next in linked list */
+}; typedef struct _hedge hedge;
+
+/* A patch identifier */
+/* coordinate origin is top left */
+struct _patch {
+ char id[20]; /* ID string, Zeri length if a diagnostic rectangle */
+ double xo; /* Location of the rectangle origin (bottom left ???) */
+ double yo;
+ double w; /* Size of the patch */
+ double h;
+ struct _patch *next; /* Next in linked list */
+}; typedef struct _patch patch;
+
+
+/* Structure to one edge */
+struct _edge {
+ double p1,p2; /* Start and end of line in orthogonal direction */
+ struct _edge *next; /* next in the linked list */
+}; typedef struct _edge edge;
+
+/* Structure of an edge list */
+struct _elist {
+ double pos; /* Position of edges along major axis */
+ double len; /* Total length of edges atthis position */
+ double cc; /* Crossing count */
+ int ne; /* Count of edges */
+ edge *e; /* Head of linked list of edges at this position */
+ struct _elist *next; /* Next in linked list */
+}; typedef struct _elist elist;
+
+/* - - - - - - - - - - - - - - - - - - - */
+/* Structure to track recognition edges */
+struct {
+ double height; /* Height of the page */
+ double mrgb[3]; /* Media RGB */
+ double rgb[3]; /* Currently set RGB */
+
+ int nfid; /* Number of fiducial marks. Must be 4 to cause output */
+ double fx[4]; /* Fiducial mark X coordinates */
+ double fy[4]; /* Fiducial mark Y coordinates */
+
+ /* Raw half edge lists, [vertical, horizontal] */
+ int nhe[2];
+ hedge *he[2];
+
+ /* Patch identity information */
+ int npatches;
+ patch *patches;
+
+ /* Processed information */
+ hedge **she[2]; /* Sorted half edges */
+
+ int nel[2]; /* Number of edge positions */
+ elist *el[2]; /* Head of edge linked list */
+ elist **nelp; /* Next edge to append to */
+} et;
+
+/* Initialise the structure */
+void et_init(void) {
+ memset(&et, 0, sizeof(et));
+}
+
+/* Tell et of the height, so the Y coordinate can be flipped */
+void et_height(double height) {
+ et.height = height;
+//printf("~1 media height set to %f\n",height);
+}
+
+/* Tell et of the media color */
+void et_media(double *rgb) {
+ int e;
+ for (e = 0; e < 3; e++)
+ et.mrgb[e] = rgb[e];
+}
+
+/* Track the current GC color */
+void et_color(
+double *rgb /* New RGB values */
+) {
+ int e;
+ for (e = 0; e < 3; e++)
+ et.rgb[e] = rgb[e];
+}
+
+/* Track a drawn object half edge */
+/* We assume that no object is written over any other object, */
+/* and that each half edge has a perfect opposite edge (ie. same */
+/* mi0 and mi1), or no matching half edge (it is over the media) - */
+/* ie. no partialy overlapping half edges. */
+/* The arguments origin is assumed to be bottom left */
+void et_edge(
+int isx, /* NZ if this is a vertical edge */
+int negh, /* NZ if this is a -ve major coordinate side half edge */
+double mj, /* Major coordinate offset (ie. X coord for vertical edge) */
+double mi0, /* Minor coordinate smaller value (ie. Y for vertical edge) */
+double mi1 /* Minor coordinate larger value (ie. Y for vertical edge) */
+) {
+ int e, h;
+ hedge *he;
+
+ if (mi1 < mi0)
+ error ("et_edge, minor coords wern't ordered");
+
+ if ((he = (hedge *)calloc(sizeof(hedge), 1)) == NULL)
+ error("Malloc of half edge structure failed");
+
+ for (e = 0; e < 3; e++)
+ he->rgb[e] = et.rgb[e];
+
+ /* Flip the Y coordinate */
+ if (isx) {
+ double tmi0, tmi1;
+ tmi0 = et.height - mi1; /* swap to keep smallest small */
+ tmi1 = et.height - mi0;
+ mi0 = tmi0;
+ mi1 = tmi1;
+ } else {
+ mj = et.height - mj;
+ }
+
+ he->negh = negh ? 1 : 0;
+ he->mj = mj;
+ he->mi0 = mi0;
+ he->mi1 = mi1;
+
+ /* Add half edges to the list */
+ h = isx ? 0 : 1;
+ et.nhe[h]++;
+ he->next = et.he[h];
+ et.he[h] = he;
+}
+
+/* Track a patch identity */
+/* The arguments origin is assumed to be bottom left */
+void et_patch(
+char *id, /* ID string, NULL if a diagnostic mark */
+double xo, /* Bottom left of the rectangle */
+double yo,
+double w, /* Size of the patch */
+double h
+) {
+ patch *p;
+
+//printf("~1 got patch at %f %f, w %f, h %f\n", xo, yo, w, h);
+
+ if ((p = (patch *)calloc(sizeof(patch), 1)) == NULL)
+ error("Malloc of patch structure failed");
+
+ /* Flip Y */
+ yo = et.height - (yo + h);
+
+ if (id != NULL) {
+ strncpy(p->id, id, 19);
+ p->id[19] = '\000';
+ } else {
+ p->id[0] = '\000';
+ }
+ p->xo = xo;
+ p->yo = yo;
+ p->h = h;
+ p->w = w;
+
+ /* Add patch to list */
+ et.npatches++;
+ p->next = et.patches;
+ et.patches = p;
+}
+
+/* Add a fiducial mark location */
+/* It is an error to add more than 4, */
+/* and exactly 4 have to be added to cause fiducials to be output. */
+void et_fiducial(
+double x, /* Bottom left of the rectangle */
+double y
+) {
+ if (et.nfid >= 4)
+ error("et_fiducial: too many fiducial marks");
+ et.fx[et.nfid] = x;
+ et.fy[et.nfid] = et.height - y; /* Flip Y */
+ et.nfid++;
+}
+
+/* Compute the image recognition information, and write the */
+/* .cht file. */
+void et_write(char *fname, col *cols, int *rix, int si, int ei) {
+ FILE *of;
+ hedge *ep;
+ int i, h;
+
+//printf("~1 et has %d vertical and %d horizontal half edges\n", et.nhe[0], et.nhe[1]);
+//printf("~1 et has %d patches\n", et.npatches);
+
+ for (h = 0; h < 2; h++) {
+ /* Create sorted list of vertical half edges */
+ if ((et.she[h] = (hedge **)malloc(sizeof(patch*) * et.nhe[h])) == NULL)
+ error("Malloc of array of vertical halfedge pointers failed");
+
+ for (ep = et.he[h], i = 0; i < et.nhe[h]; i++, ep = ep->next)
+ et.she[h][i] = ep;
+
+ /* Sort helf edges by their X location, then their Y0 location */
+#define HEAP_COMPARE(A,B) (fabs(A->mj - B->mj) < 1e-6 ? A->mi0 < B->mi0 : A->mj < B->mj)
+ HEAPSORT(hedge *, et.she[h], et.nhe[h]);
+#undef HEAP_COMPARE
+
+#ifdef NEVER
+for (i = 0; i < et.nhe[h]; i++) {
+printf("%s %d at %c = %f from %c = %f to %f\n",
+h == 0 ? "Vert" : "Horiz", i,
+h == 0 ? 'X' : 'Y', et.she[h][i]->mj,
+h == 0 ? 'Y' : 'X', et.she[h][i]->mi0, et.she[h][i]->mi1);
+}
+#endif /* NEVER */
+
+ et.nel[h] = 0;
+ et.nelp = &et.el[h]; /* Append next edge list here */
+ *et.nelp = NULL; /* No edge list at this position yet */
+
+ /* Create the edge list information */
+ for (i = 0; i < et.nhe[h];) {
+ int j, ii, nj;
+ double *rgb = NULL; /* Contrast RGB */
+ elist *el; /* Current elist */
+
+ el = *et.nelp;
+
+ /* Locate the end of the half edges at the same position */
+ for (ii = i; ii < et.nhe[h]; ii++) {
+ if (fabs(et.she[h][i]->mj - et.she[h][ii]->mj) > 1e-6)
+ break;
+ }
+
+//printf("~1 doing group from %d to %d\n",i, ii);
+ /* Find half edge pairs */
+ /* Note that we assume that the half edges match perfectly, */
+ /* or not at all. This will be normaly be the case with targets */
+ /* generated by printtarg. */
+ for (j = i; j < ii; j = nj, j++) {
+ int e, k = j+1;
+ double vv;
+
+ if (k < ii
+ && et.she[h][j]->negh != et.she[h][k]->negh
+ && fabs(et.she[h][j]->mi0 - et.she[h][k]->mi0) < 1e-5
+ && fabs(et.she[h][j]->mi1 - et.she[h][k]->mi1) < 1e-5) {
+ /* Found a matching half edge */
+
+ nj = k;
+ rgb = et.she[h][k]->rgb;
+
+ } else if (k < ii /* Assert */
+ && ( (et.she[h][j]->mi0+1e-6) < et.she[h][k]->mi1
+ && et.she[h][j]->mi1 > (et.she[h][k]->mi0+1e-6))) {
+
+ /* Found an overlapping non-matching edge */
+ nj = k;
+
+#ifdef NEVER
+fprintf(stderr,"i = %d, j = %d\n",i,j);
+fprintf(stderr,"%s %d at %c = %f from %c = %f to %f, half %s\n",
+h == 0 ? "Vert" : "Horiz", i,
+h == 0 ? 'X' : 'Y', et.she[h][j]->mj,
+h == 0 ? 'Y' : 'X', et.she[h][j]->mi0, et.she[h][j]->mi1,
+et.she[h][j]->negh ? "Neg" : "Pos");
+fprintf(stderr,"%s %d at %c = %f from %c = %f to %f, half %s\n",
+h == 0 ? "Vert" : "Horiz", i,
+h == 0 ? 'X' : 'Y', et.she[h][k]->mj,
+h == 0 ? 'Y' : 'X', et.she[h][k]->mi0, et.she[h][k]->mi1,
+et.she[h][k]->negh ? "Neg" : "Pos");
+#endif /* NEVER */
+ error("Internal - half edges don't match");
+
+ } else {
+ /* Must be a non-matching edge */
+ nj = j;
+ rgb = et.mrgb; /* Edge must be against media */
+ }
+
+ /* Compute vector delta in rgb */
+ /* Add entry to edge list */
+ for (e = 0, vv = 0.0; e < 3; e++) {
+ double tt = rgb[e] - et.she[h][j]->rgb[e];
+ vv += tt * tt;
+ }
+
+//printf("~1 h %d, mj %f, mi %f, vv = %f\n",h, et.she[h][j]->mj, et.she[h][j]->mi0, vv);
+ /* If edge is of sufficient magnitude */
+ // ~~99
+ if (vv > 0.2) {
+ edge *ep;
+
+ /* See if we need to add a first elist for this position */
+ if (el == NULL) { /* We do */
+ if ((el = (elist *)calloc(sizeof(elist), 1)) == NULL)
+ error("Malloc of elist structure failed");
+ *et.nelp = el;
+ el->pos = et.she[h][j]->mj;
+ et.nel[h]++;
+ }
+
+ /* Add another edge entry */
+ if ((ep = (edge *)calloc(sizeof(edge), 1)) == NULL)
+ error("Malloc of edge structure failed");
+
+ ep->next = el->e;
+ ep->p1 = et.she[h][j]->mi0;
+ ep->p2 = et.she[h][j]->mi1;
+
+ el->e = ep; /* Add to edge list */
+ el->ne++;
+ }
+ }
+
+ if (el != NULL) {
+ /* We've done that position, so get ready for next */
+ et.nelp = &el->next; /* Append any more positions here */
+ *et.nelp = NULL;
+ }
+ i = ii; /* Start search for next group here */
+ }
+ }
+
+ /* Figure the crossing count */
+ for (h = 0; h < 2; h++) {
+ int oh = 1 - h; /* The other list */
+ elist *el, *pl; /* Current, previous elist */
+
+ for (pl = NULL, el = et.el[h]; el != NULL; pl = el, el = el->next) {
+ edge *ep;
+ double pp, np; /* Window in pos direction for crossing */
+
+ if (pl != NULL)
+ pp = (pl->pos + el->pos)/2.0; /* Half distance to next line */
+ else
+ pp = -1e6;
+
+ if (el->next != NULL)
+ np = (el->next->pos + el->pos)/2.0; /* Half distance to next line */
+ else
+ np = 1e6;
+
+ /* For each edge on this edge position */
+ for (ep = el->e; ep != NULL; ep = ep->next) {
+ elist *oel; /* Other edge list pointer */
+
+ /* For each edge in other list */
+ for (oel = et.el[oh]; oel != NULL; oel = oel->next) {
+ edge *oep;
+
+ if (oel->pos < ep->p1 || oel->pos > ep->p2)
+ continue; /* Other edge doesn't intersect this segment */
+
+ for (oep = oel->e; oep != NULL; oep = oep->next) {
+
+ /* If crosses on this line within +-0.5 of line each side */
+ if (oep->p1 <= np && oep->p2 >= pp) {
+ el->cc++; /* Count crossing */
+ }
+
+ }
+ }
+ }
+ }
+ }
+
+ /* Compute and normalise the length (strength) & crossing count of each edge */
+ for (h = 0; h < 2; h++) {
+ elist *el; /* Current elist */
+ double maxlen = 0.0;
+ double maxcc = 0.0;
+
+ for (el = et.el[h]; el != NULL; el = el->next) {
+ edge *ep;
+ double tlen;
+
+ for (tlen = 0.0, ep = el->e; ep != NULL; ep = ep->next) {
+ tlen += ep->p2 - ep->p1;
+ }
+ el->len = tlen;
+ if (maxlen < tlen)
+ maxlen = tlen;
+ if (maxcc < el->cc)
+ maxcc = el->cc;
+ }
+
+ /* Normalise */
+ for (el = et.el[h]; el != NULL; el = el->next) {
+ el->len /= maxlen;
+ el->cc /= maxcc;
+ }
+ }
+
+ /* Output the .cht file */
+ if ((of = fopen(fname,"w")) == NULL)
+ error ("Unable to open output file '%s' for writing",fname);
+
+ fprintf(of,"\n\n");
+ fprintf(of, "BOXES %d\n",et.npatches);
+
+
+ /* Locate fiducials if they've been added to chart */
+ if (et.nfid == 4) {
+ fprintf(of, " F _ _ %f %f %f %f %f %f %f %f\n",
+ et.fx[0], et.fy[0], et.fx[1], et.fy[1], et.fx[2], et.fy[2], et.fx[3], et.fy[3]);
+ }
+
+ {
+ int fidc = 0;
+ patch *pp;
+ double mins; /* Minimum sample box size */
+
+ for (pp = et.patches; pp != NULL; pp = pp->next) {
+
+ if (pp->id[0] == '\000') {
+ fprintf(of, " D MARK%d MARK%d _ _ %f %f %f %f 0 0\n",
+ fidc, fidc, pp->w, pp->h, pp->xo, pp->yo);
+ fidc++;
+ }
+ }
+
+ mins = 1e6;
+ for (pp = et.patches; pp != NULL; pp = pp->next) {
+
+ if (pp->id[0] != '\000') {
+ fprintf(of, " X %s %s _ _ %f %f %f %f 0 0\n",
+ pp->id, pp->id, pp->w, pp->h, pp->xo, pp->yo);
+ if (mins > pp->w)
+ mins = pp->w;
+ if (mins > pp->h)
+ mins = pp->h;
+ }
+ }
+ fprintf(of,"\n");
+
+ /* Use a 15% box shrink */
+ fprintf(of, "BOX_SHRINK %f\n", mins * 0.15);
+ fprintf(of,"\n");
+
+ }
+
+ fprintf(of,"REF_ROTATION %f\n", 0.0);
+ fprintf(of,"\n");
+
+ {
+ elist *el; /* Current elist */
+
+ fprintf(of,"XLIST %d\n",et.nel[0]);
+ for (el = et.el[0]; el != NULL; el = el->next)
+ fprintf(of," %f %f %f\n",el->pos, el->len, el->cc);
+ fprintf(of,"\n");
+
+ fprintf(of,"YLIST %d\n",et.nel[1]);
+ for (el = et.el[1]; el != NULL; el = el->next)
+ fprintf(of," %f %f %f\n",el->pos, el->len, el->cc);
+ fprintf(of,"\n");
+
+ fprintf(of,"\n");
+ }
+
+
+ fprintf(of, "EXPECTED XYZ %d\n",ei - si);
+
+ for (i = si; i < ei; i++) {
+ int ix = rix[i];
+ fprintf(of, " %s %f %f %f\n", cols[ix].loc, 100.0 * cols[ix].XYZ[0], 100.0 * cols[ix].XYZ[1], 100.0 * cols[ix].XYZ[2]);
+ }
+ fprintf(of,"\n");
+
+ if (fclose(of))
+ error ("Unable to close output file '%s'",fname);
+}
+
+
+/* Cleanup any allocation */
+void et_clear(void) {
+ int h;
+ patch *p;
+
+ et.nfid = 0;
+
+ for (h = 0; h < 2; h++) {
+ hedge *he;
+ elist *el;
+
+ /* Free up half edges */
+ he = et.he[h];
+ while (he != NULL) {
+ hedge *ne = he->next;
+ free(he);
+ he = ne;
+ }
+ et.nhe[h] = 0;
+ et.he[h] = NULL;
+
+ /* Free up sorted half edge lists */
+ if (et.she[h] != NULL)
+ free(et.she[h]);
+ et.she[h] = NULL;
+
+ /* Free up edge lists and edges */
+ el = et.el[h];
+ while (el != NULL) {
+ elist *nel;
+ edge *ep;
+
+ ep = el->e;
+ while (ep != NULL) {
+ edge *nep;
+
+ nep = ep->next;
+ free(ep);
+ ep = nep;
+ }
+ el->ne = 0;
+ el->e = NULL;
+
+ nel = el->next;
+ free(el);
+ el = nel;
+ }
+ et.nel[h] = 0;
+ et.el[h] = NULL;
+ }
+ et.nelp = NULL;
+
+ p = et.patches;
+ while (p != NULL) {
+ patch *np = p->next;
+ free(p);
+ p = np;
+ }
+ et.patches = NULL;
+ et.npatches = 0;
+}
+
+
+
+
+
+
+
+
diff --git a/target/randix.c b/target/randix.c
new file mode 100644
index 0000000..bf85764
--- /dev/null
+++ b/target/randix.c
@@ -0,0 +1,166 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Random index routines.
+ *
+ * Author: Graeme W. Gill
+ * Date: 5/10/96
+ *
+ * Copyright 1996, 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "randix.h"
+
+#include <stdarg.h>
+void error(char *fmt, ...), warning(char *fmt, ...), verbose(int level, char *fmt, ...);
+
+/* A table entry structure */
+typedef struct {
+ int bits; /* Number of bits */
+ int length; /* Length of sequence */
+ int xorm; /* Xor mask */
+} tabe;
+
+
+static tabe table[] = {
+ { 1, (1<<1)-1, 0x1},
+ { 2, (1<<2)-1, 0x3},
+ { 3, (1<<3)-1, 0x3},
+ { 4, (1<<4)-1, 0x13},
+ { 5, (1<<5)-1, 0x1b},
+ { 6, (1<<6)-1, 0x1b},
+ { 7, (1<<7)-1, 0x65},
+ { 8, (1<<8)-1, 0xc3},
+ { 9, (1<<9)-1, 0x1b5},
+ { 10, (1<<10)-1, 0x1c7},
+ { 11, (1<<11)-1, 0x6bb},
+ { 12, (1<<12)-1, 0x5c5},
+ { 13, (1<<13)-1, 0x15b9},
+ { 14, (1<<14)-1, 0x36d1},
+ { 15, (1<<15)-1, 0x376b},
+ { 16, (1<<16)-1, 0x5bab},
+ { 17, (1<<17)-1, 0x1b5c5},
+ { 18, (1<<18)-1, 0x15561},
+ { 19, (1<<19)-1, 0x5b4db},
+ { 20, (1<<20)-1, 0xf6e01},
+ { 21, (1<<21)-1, 0x186517},
+ { 22, (1<<22)-1, 0x6bf4f},
+ { 23, (1<<23)-1, 0x376623},
+ { 24, (1<<24)-1, 0xf54e35},
+ { 0, 0, 0}
+};
+
+#define PSRAND(S, XOV, TBIT, MASK) ((((S) & TBIT) ? (((S) << 1) ^ (XOV)) : ((S) << 1)) & MASK)
+
+static int
+randix_next(struct _randix *p) {
+ int rv = p->ss-1; /* Return start value first */
+ do {
+ p->ss = PSRAND(p->ss, p->xorm, p->tbit, p->mask);
+ } while(p->ss >= p->length);
+ return rv;
+}
+
+
+/* Destroy ourselves */
+static void
+randix_del(randix *p) {
+ free (p);
+}
+
+/* Creator */
+randix *new_randix(int length, int start)
+{
+ int i;
+ randix *p;
+ if ((p = (randix *)malloc(sizeof(randix))) == NULL)
+ error ("randix: malloc failed");
+
+ p->next = randix_next;
+ p->del = randix_del;
+
+ if (length == 0)
+ error ("randix: Can't handle length %d",length);
+
+ start %= length;
+
+ p->length = length+1;
+ for (i = 0; table[i].bits != 0; i++) {
+ if (length <= table[i].length) {
+ p->tbit = 1 << (table[i].bits-1);
+ p->mask = (p->tbit << 1)-1;
+ p->xorm = table[i].xorm;
+ p->ss = start + 1;
+ return p;
+ break;
+ }
+ }
+ error ("randix: Can't handle length %d",length);
+ return NULL;
+}
+
+
+
+
+
+#ifdef NEVER
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int length = 11;
+ int i, iv, cv;
+ randix *r;
+
+ if (argc > 1)
+ length = atoi(argv[1]);
+
+ r = new_randix(length, 0);
+
+ iv = r->next(r);
+ printf("First Val = %d\n",iv);
+ i = 0;
+ do {
+ cv = r->next(r);
+ i++;
+ } while (cv != iv);
+ printf("Last Val = %d\n",cv);
+ printf("Count for length %d = %d\n",length,i);
+ return 0;
+}
+
+/* Basic printf type error() and warning() routines */
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"targen: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ fflush(stdout);
+ exit (-1);
+}
+#endif /* NEVER */
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/target/randix.h b/target/randix.h
new file mode 100644
index 0000000..b4c36c0
--- /dev/null
+++ b/target/randix.h
@@ -0,0 +1,41 @@
+
+#ifndef RANDIX_H
+/*
+ * Argyll Color Correction System
+ *
+ * Random array indexing class
+ *
+ * Author: Graeme W. Gill
+ * Date: 16/10/96
+ *
+ * Copyright 1996, 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.
+ */
+
+struct _randix {
+/* private: */
+ int tbit; /* Top bit mask */
+ int mask; /* Overall mask */
+ int xorm; /* Xor value */
+ int length; /* Length needed */
+ int ss; /* Current value */
+
+/* public: */
+ /* return the next in the sequence */
+ int (*next)(struct _randix *p);
+
+ /* Destroy ourselves */
+ void (*del)(struct _randix *p);
+
+ }; typedef struct _randix randix;
+
+/* Creator */
+/* Counts withing range 0 to length-1 */
+extern randix *new_randix(int length, int start);
+
+
+#define RANDIX_H
+#endif /* RANDIX_H */
diff --git a/target/simdlat.c b/target/simdlat.c
new file mode 100644
index 0000000..c5edf36
--- /dev/null
+++ b/target/simdlat.c
@@ -0,0 +1,1063 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Device space latice test point generator class,
+ * set to generate a body centered cubic lattice.
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/8/2004
+ *
+ * Copyright 2002 - 2004 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.
+ *
+ * Based on simplat.c
+ */
+
+/* TTBD:
+
+ This is not the most efficient way to generate a body centered
+ cubic lattice, a simpler grid counter would work faster, without
+ having to track what points have been generated.
+
+ This seems too inexact/slow to read a specified number of test
+ points for use in higher dimensions.
+
+ */
+
+#undef DEBUG
+#undef DUMP_PLOT /* Show on screen plot */
+#define PERC_PLOT 0 /* Emit perceptive space plots */
+#define DO_WAIT 1 /* Wait for user key after each plot */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#ifdef DEBUG
+#include "plot.h"
+#endif
+#include "numlib.h"
+#include "sort.h"
+#include "plot.h"
+#include "icc.h"
+#include "xcolorants.h"
+#include "targen.h"
+#include "simdlat.h"
+
+#if defined(DEBUG) || defined(DUMP_PLOT)
+static void dump_image(simdlat *s, int pcp);
+static void dump_image_final(simdlat *s, int pcp);
+#endif
+
+#define SNAP_TOL 0.02 /* Snap to gamut boundary tollerance */
+#define MAX_TRIES 30 /* Maximum itterations */
+
+
+/* ----------------------------------------------------- */
+
+/* Default convert the nodes device coordinates into approximate perceptual coordinates */
+/* (usually overriden by caller supplied function) */
+static void
+default_simdlat_to_percept(void *od, double *p, double *d) {
+ simdlat *s = (simdlat *)od;
+ int e;
+
+ /* Default Do nothing - copy device to perceptual. */
+ for (e = 0; e < s->di; e++) {
+ p[e] = d[e] * 100.0;
+ }
+}
+
+
+#ifdef NEVER /* Not currently used */
+/* Return the largest distance of the point outside the device gamut. */
+/* This will be 0 if inside the gamut, and > 0 if outside. */
+static double
+simdlat_in_dev_gamut(simdlat *s, double *d) {
+ int e;
+ int di = s->di;
+ double tt, dd = 0.0;
+ double ss = 0.0;
+
+ for (e = 0; e < di; e++) {
+ ss += d[e];
+
+ tt = 0.0 - d[e];
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ tt = d[e] - 1.0;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ }
+ tt = ss - s->ilimit;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ return dd;
+}
+#endif /* NEVER */
+
+/* Snap a point to the device gamut boundary. */
+/* Return nz if it has been snapped. */
+static int snap_to_gamut(simdlat *s, double *d) {
+ int e;
+ int di = s->di;
+ double dd; /* Smallest distance */
+ double ss; /* Sum */
+ int rv = 0;
+
+ /* Snap to ink limit first */
+ for (ss = 0.0, e = 0; e < di; e++)
+ ss += d[e];
+ dd = ss - s->ilimit;
+
+ if (dd >= -s->tol) { /* Within tol or beyond limit */
+ int j;
+ for (j = 0; j < di; j++)
+ d[j] *= s->ilimit/ss; /* Snap to ink limit */
+ rv = 1;
+ }
+
+ /* Now snap to any other dimension */
+ for (e = 0; e < di; e++) {
+
+ dd = 0.0 - d[e];
+ if (dd >= -s->tol) {
+ d[e] = 0.0; /* Snap to orthogonal boundary */
+ rv = 1;
+ }
+ dd = d[e] - 1.0;
+ if (dd >= -s->tol) {
+ d[e] = 1.0; /* Snap to orthogonal boundary */
+ rv = 1;
+ }
+ }
+
+ return rv;
+}
+
+/* Snap a point to the gamut boundary if it is close enough. */
+/* Return 1 if the point has been clipped. */
+/* Return 2 if the point has been clipped by a dia. */
+static int snap_to_gamut2(simdlat *s, double *d) {
+ int rv = 0;
+ double ud[MXTD];
+ int e, di = s->di;
+
+//printf("\n~1 snap_to_gamut2() called with %f %f\n",d[0],d[1]);
+
+ for (e = 0; e < di; e++)
+ ud[e] = d[e]; /* save unclipped location */
+
+ if (snap_to_gamut(s, d)) {
+ double tt;
+
+ tt = 0.0;
+ for (e = 0; e < di; e++) {
+ double t = ud[e] - d[e];
+ tt += t * t;
+ }
+ tt = sqrt(tt);
+//printf("~1 Got snapped to %f %f by dist %f\n",d[0], d[1], tt);
+ if (tt > (0.5 * s->dia))
+ rv = 2; /* invalid & !explore */
+ else
+ rv = 1; /* Valid & explore */
+ }
+//else
+//printf("~1 Didn't get snapped\n");
+
+//printf("~1 snap_to_gamut2() on %f %f returning %d\n",d[0],d[1],rv);
+ return rv;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Compute the equalateral simplex basis vectors */
+static void comp_basis(
+simdlat *s,
+int type, /* 0 = body centered cubic */
+ /* 1 = equilateral simplex */
+ /* 2 = face centered cubic */
+double dia, /* Diameter of simplex circumspehere */
+double off, /* Starting offset in device space */
+double angle /* Rotation angle 0.0 - 1.0 */
+) {
+ int i, j, di = s->di;
+ double sx[MXTD+1][MXTD]; /* Simplex verticies */
+
+ switch (type) {
+
+ case SIMDLAT_BCC:
+ /* Create the node positions for body centered */
+ /* cubic latice simplex basis vectors */
+ /* Body centered places points at locations where the */
+ /* lattice integer coordinates are all even or all odd. */
+ for (i = 0; i < (di+1); i++) {
+
+ for (j = 0; j < di; j++)
+ sx[i][j] = -0.5;
+ if (i < di) {
+ if (i > 0)
+ sx[i][i-1] += dia;
+ } else {
+ for (j = 0; j < di; j++)
+ sx[i][j] += 0.5 * dia;
+ }
+ }
+ break;
+
+ case SIMDLAT_EQSPLX:
+ /* Create the node positions for the */
+ /* equalateral simplex basis vectors */
+ for (i = 0; i < (di+1); i++) {
+ double rr = 1.0; /* Current radius squared */
+ double ss = dia / sqrt(3.0); /* Scale */
+
+ /* The bounding points form a equalateral simplex */
+ /* whose vertexes are on a sphere about the data */
+ for (j = 0; j < di; j++) {
+ double ddi;
+ double hh = 1.0/(di-j); /* Weight for remaining points */
+
+ if (j > i)
+ sx[i][j] = 0.0; /* If beyond last */
+ else if (j == i) /* If last non-zero */
+ sx[i][j] = ss * sqrt(rr);
+ else /* If before last */
+ sx[i][j] = -hh * ss * sqrt(rr);
+
+ ddi = (double)(di - j);
+ rr *= (ddi * ddi - 1.0)/(ddi * ddi);
+ }
+ }
+ break;
+
+ case SIMDLAT_FCC:
+ /* Create the node positions for the */
+ /* face centered arrangement */
+ /* Face centered places points at locations where the */
+ /* sum of the lattice integer coordinates is even. */
+ for (i = 0; i < (di+1); i++) {
+
+ for (j = 0; j < di; j++)
+ sx[i][j] = 0.0 * -0.5;
+
+ if (i > 0 && i < di) {
+ sx[i][i-1] += 0.5 * dia;
+ sx[i][di-1] += 0.5 * dia;
+ } else if (i == di) {
+ sx[i][di-1] += dia;
+ }
+ }
+ break;
+ }
+
+ /* Apply a rotation to avoid possible alignment with */
+ /* the device axes */
+ {
+ int m, k;
+ int ldi = di-1; /* Last dimension */
+ double a, b;
+
+ b = angle;
+ a = sqrt(1.0 - b * b);
+
+ /* Apply rotation to all except last dimension */
+ for (m = 0; m < ldi; m++) { /* Dimension being rotated */
+
+ for (i = 0; i < (di+1); i++) { /* Node being rotated */
+ double out[MXTD];
+
+ for (j = 0; j < di; j++) { /* Coord being produced */
+ out[j] = 0.0;
+
+ for (k = 0; k < di; k++) { /* Coord being used */
+ if ((j == m && k == m)
+ || (j == ldi && k == ldi))
+ out[j] += a * sx[i][k]; /* Diagonal multiplier */
+ else if (j == m && k == ldi)
+ out[j] += b * sx[i][k];
+ else if (j == ldi && k == m)
+ out[j] -= b * sx[i][k];
+ else if (j == k)
+ out[j] += sx[i][k];
+ }
+ }
+ for (j = 0; j < di; j++)
+ sx[i][j] = out[j]; /* Transfer result */
+ }
+ }
+ }
+
+#ifdef DEBUG /* Dump stats on verticies */
+for(i = 0; i < (di+1); i++) {
+ double val = 0.0;
+ printf("vert %d = ",i);
+ for(j = 0; j < di; j++) {
+ val += sx[i][j] * sx[i][j];
+ printf("%f ",sx[i][j]);
+ }
+ printf(" (%f)\n",sqrt(val));
+}
+
+for(i = 0; i < di; i++) {
+ for (j = i+1; j < (di+1); j++) {
+ int e;
+ double val;
+
+ /* Distance between nodes */
+ for (val = 0.0, e = 0; e < di; e++) {
+ double tt = sx[i][e] - sx[j][e];
+ val += tt * tt;
+ }
+ val = sqrt(val);
+ printf("dist %d %d = %f\n",i,j,val);
+ }
+}
+#endif /* DEBUG */
+
+ /* Convert from di+1 verticies to di base vectors */
+ for (i = 0; i < di; i++) {
+ for (j = 0; j < di; j++) {
+ s->bv[i][j] = sx[i+1][j] - sx[i][j];
+ }
+ }
+
+ /* Establish the basis origin */
+ {
+ for (j = 0; j < di; j++)
+ s->bo[j] = off * s->ilimit/di;
+ }
+}
+
+/* Compute the hash */
+static int comp_hash(
+simdlat *s,
+int *x /* Index */
+) {
+ int j, di = s->di;
+ unsigned long hash;
+
+ for (hash = 0, j = 0; j < di; j++)
+ hash = hash * 7 + x[j];
+ hash %= SPT_HASHSIZE;
+
+ return hash;
+}
+
+/* Check if a node already exists. Return -1 if not, */
+/* or node index if it does. */
+static int check_exists(
+simdlat *s,
+int *x, /* Index */
+int hash /* Hash */
+) {
+ int di = s->di;
+ int hp; /* node index */
+ int j;
+
+ for (hp = s->hash[hash]; hp >= 0; hp = s->nodes[hp].hp) {
+
+ /* Check if we have a match */
+ for (j = 0; j < di; j++) {
+ if (s->nodes[hp].x[j] != x[j])
+ break;
+ }
+ if (j >= di)
+ break; /* Found a match */
+ }
+
+ return hp;
+}
+
+/* Create a new node. We assume it doesn't already exist */
+/* Return its index */
+static int new_node(
+simdlat *s,
+int *x, /* Index */
+int hash /* Hash */
+) {
+ int di = s->di;
+ int b = 0; /* NZ if a boundary point */
+ int nn; /* New node index */
+ int hp; /* Hash chain index */
+ int i, j;
+
+ /* Make room for it */
+ if ((s->np+1) >= s->np_a) {
+ s->np_a *= 2;
+ if ((s->nodes = (sdtnode *)realloc(s->nodes, s->np_a * sizeof(sdtnode))) == NULL)
+ error ("simdlat: node realloc failed");
+ }
+
+ nn = s->np++; /* Add the new point */
+
+ /* Compute the intended device value */
+ for (j = 0; j < di; j++)
+ s->nodes[nn].p[j] = s->bo[j];
+
+ for (i = 0; i < di; i++) {
+ for (j = 0; j < di; j++) {
+ s->nodes[nn].p[j] += x[i] * s->bv[i][j]; /* Sum basis vector product */
+ }
+ }
+
+ /* See whether we are well outside the gamut or not */
+ b = snap_to_gamut2(s, s->nodes[nn].p);
+
+ s->percept(s->od, s->nodes[nn].v, s->nodes[nn].p); /* Compute perceptual */
+
+ /* Store node information */
+ for (j = 0; j < di; j++)
+ s->nodes[nn].x[j] = x[j];
+
+ s->nodes[nn].b = b;
+ if (b < 2) {
+ s->nodes[nn].vald = 1; /* Valid if within or on gamut */
+ s->nvp++; /* Got another valid one */
+ } else
+ s->nodes[nn].vald = 0; /* Not valid if it's a boundary point */
+ s->nodes[nn].expm[0] =
+ s->nodes[nn].expm[1] = (1 << di)-1; /* Assum all dimensions need exploring */
+ s->nodes[nn].hp = s->nodes[nn].up = -1; /* Linked list indexes */
+
+ /* Add an entry in the hash table */
+ if (s->hash[hash] < 0)
+ s->hash[hash] = nn; /* We are the only entry */
+ else {
+ hp = s->hash[hash];
+ while (s->nodes[hp].hp >= 0)
+ hp = s->nodes[hp].hp; /* Follow chain */
+ s->nodes[hp].hp = nn; /* Add at the end of the chain */
+ }
+
+ return nn;
+}
+
+/* ============================================= */
+/* Main object functions */
+
+/* Initialise, ready to read out all the points */
+static void simdlat_reset(simdlat *s) {
+ s->rix = 0;
+}
+
+/* Read the next set of non-fixed points values */
+/* return non-zero when no more points */
+static int simdlat_read(
+simdlat *s,
+double *d, /* Device position */
+double *p /* Perceptual value */
+) {
+ int j;
+
+ for (; s->rix < s->bnp; s->rix++) {
+
+ if (s->bnodes[s->rix].vald != 0) {
+ for (j = 0; j < s->di; j++) {
+ if (d != NULL)
+ d[j] = s->bnodes[s->rix].p[j];
+ if (p != NULL)
+ p[j] = s->bnodes[s->rix].v[j];
+ }
+ s->rix++;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Do a pass of seed filling the whole gamut, given a simplex dia. */
+/* Return the number of nodes produced */
+static int do_pass(
+simdlat *s,
+double dia /* Simplex diameter to try */
+) {
+ int di = s->di;
+ int hash;
+ int i, j, k;
+ int x[MXTD];
+ int nn; /* New nodes index */
+ int np;
+
+ /* Rest the current list */
+ s->np = 0;
+ s->nvp = 0;
+ for (i = 0; i < SPT_HASHSIZE; i++)
+ s->hash[i] = -1;
+
+ /* Initial alloc of nodes */
+ if (s->nodes == NULL) {
+ s->np_a = 10;
+ if ((s->nodes = (sdtnode *)malloc(s->np_a * sizeof(sdtnode))) == NULL)
+ error ("simdlat: nodes malloc failed");
+ }
+
+ /* Compute the simplex basis vectors */
+ /* arguments: simplex diameter, device space offset, angle to skew grid */
+// comp_basis(s, s->type, dia, 0.5, s->angle);
+ comp_basis(s, s->type, dia, 0.4 + dia/150.0, s->angle);
+
+ s->dia = dia;
+
+ /* Add an initial seed point */
+ for (j = 0; j < di; j++)
+ x[j] = 0;
+ hash = comp_hash(s, x);
+ nn = new_node(s, x, hash);
+
+ if (s->nodes[nn].b > 1) {
+ error("simdlat: initial seed point is not within gamut");
+ }
+
+ s->unex = nn; /* Initial entry in unexplored list */
+
+//printf("~1 seed node is [%d %d]\n",s->nodes[nn].x[0], s->nodes[nn].x[1]);
+
+ /* While there is more unexplored area */
+ /* and we arn't finding a ridiculous number of points */
+ while(s->unex >= 0 && (s->nvp < 3 * s->inp)) {
+ int pos; /* Positive or -ve direction */
+ nn = s->unex; /* Node we're looking at */
+ s->unex = s->nodes[nn].up; /* remove from unexplored list */
+
+//printf("\n~1 exploring beyond node [%d %d]\n",s->nodes[nn].x[0], s->nodes[nn].x[1]);
+
+ if (s->nodes[nn].b > 1)
+ continue; /* Don't look at boundary points */
+
+ /* For all unexplored directions */
+ for (i = 0; i < di; i++) {
+ for (pos = 0; pos < 2; pos++) {
+ int on; /* Other node index */
+
+//printf("~1 checking direction dim %d, sign %d, [%d %d]\n",i,pos,x[0],x[1]);
+
+ if (((1 << i) & s->nodes[nn].expm[pos]) == 0) {
+//printf("~1 that direction has been explored\n");
+ continue; /* Try next direction */
+ }
+
+ /* Check out that direction */
+ for (j = 0; j < di; j++)
+ x[j] = s->nodes[nn].x[j];
+ x[i] += pos ? 1 : -1;
+
+ /* If that node already exists */
+ hash = comp_hash(s, x);
+ if ((on = check_exists(s, x, hash)) >= 0) {
+ /* back direction doesn't need checking */
+ s->nodes[on].expm[pos ^ 1] &= ~(1 << i);
+//printf("~1 that node already exists\n");
+ continue; /* Try next direction */
+ }
+
+ /* Create a new node in that direction */
+ on = new_node(s, x, hash);
+
+ if (s->nodes[on].b > 1) { /* If new node is boundary, don't explore beyond it */
+//printf("~1 added new boundary node [%d %d]\n",x[0],x[1]);
+ continue;
+ }
+ /* back direction on new node doesn't need checking */
+ s->nodes[on].expm[pos ^ 1] &= ~(1 << i);
+
+//printf("~1 added new internal node [%d %d] **\n",x[0],x[1]);
+ s->nodes[on].up = s->unex; /* Add this node to unexplored list */
+ s->unex = on;
+ }
+ }
+ }
+
+
+ /* Rationalise cooincident points, and count final valid */
+ s->nvp = 0;
+ for (i = 0; i < s->np; i++) {
+
+//printf("~1 rationalising %d, = %f %f\n",i, s->nodes[i].p[0], s->nodes[i].p[1]);
+ if (s->nodes[i].vald == 0) {
+//printf("~1 point %d is not valid\n",i);
+ continue;
+ }
+
+ /* First against fixed points in device space */
+ for (k = 0; k < s->fxno; k++) {
+ double dd;
+
+ /* Compute distance */
+ dd = 0.0;
+ for (j = 0; j < di; j++) {
+ double tt = s->nodes[i].p[j] - s->fxlist[k].p[j];
+ dd += tt * tt;
+ }
+ dd = sqrt(dd);
+
+ if (dd < s->tol) {
+ s->nodes[i].vald = 0; /* Ignore this point */
+//printf("~1 point %d matches input point %d\n",i, k);
+ break;
+ }
+ }
+
+ if (s->nodes[i].vald == 0)
+ continue;
+
+ /* Then against all the other points */
+ for (k = i+1; k < s->np; k++) {
+ double dd;
+
+ if (s->nodes[k].vald == 0)
+ continue;
+
+ /* Compute distance */
+ dd = 0.0;
+ for (j = 0; j < di; j++) {
+ double tt = s->nodes[i].p[j] - s->nodes[k].p[j];
+ dd += tt * tt;
+ }
+ dd = sqrt(dd);
+
+ if (dd < s->tol) {
+ s->nodes[i].vald = 0; /* Ignore this point */
+//printf("~1 point %d matches other point %d\n",i, k);
+ break;
+ }
+ }
+
+ if (s->nodes[i].vald != 0)
+ s->nvp++; /* Found a valid one */
+ }
+
+#ifdef DUMP_PLOT
+ /* Dump plot */
+ dump_image(s, PERC_PLOT);
+#endif /* DUMP_PLOT */
+
+//printf("~1 got %d valid out of %d total\n",s->nvp, s->np);
+ np = s->nvp;
+
+ /* If we have a new best */
+ if (s->nvp <= s->inp && (s->inp - s->nvp) < (s->inp - s->bnvp)) {
+ sdtnode *tnodes;
+ int tnp_a;
+ tnodes = s->bnodes; /* Swap them */
+ tnp_a = s->bnp_a;
+ s->bnp = s->np;
+ s->bnvp = s->nvp;
+ s->bnodes = s->nodes;
+ s->bnp_a = s->np_a;
+ s->bdia = s->dia;
+ s->nodes = tnodes;
+ s->np_a = tnp_a;
+ s->np = s->nvp = 0; /* Zero current */
+ }
+
+ return np;
+}
+
+/* Destroy ourselves */
+static void
+simdlat_del(simdlat *s) {
+
+ if (s->nodes != NULL)
+ free(s->nodes);
+ if (s->bnodes != NULL)
+ free(s->bnodes);
+
+ free (s);
+}
+
+/* Constructor */
+simdlat *new_simdlat(
+int di, /* Dimensionality of device space */
+double ilimit, /* Ink limit (sum of device coords max) */
+int inp, /* Number of points to generate */
+fxpos *fxlist, /* List of existing fixed points (may be NULL) */
+int fxno, /* Number of existing fixes points */
+int type, /* type of geometry, 0 = body centered cubic, */
+ /* 1 = equilateral simplex, 2 = face centered cubic */
+double angle, /* Angle to orient grid at (0.0 - 0.5 typical) */
+void (*percept)(void *od, double *out, double *in), /* Perceptual lookup func. */
+void *od /* context for Perceptual function */
+) {
+ int i;
+ double ctol;
+ double hdia, ldia, dia;
+ int hnp, lnp, np;
+ simdlat *s;
+
+#ifdef DEBUG
+ printf("new_simdlat called with di %d, inp %d\n",di,inp);
+#endif
+
+ if ((s = (simdlat *)calloc(sizeof(simdlat), 1)) == NULL)
+ error ("simdlat: simdlat malloc failed");
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ s->reset = simdlat_reset;
+ s->read = simdlat_read;
+ s->del = simdlat_del;
+
+ /* If no perceptual function given, use default */
+ /* (Not that it's used here) */
+ if (percept == NULL) {
+ s->percept = default_simdlat_to_percept;
+ s->od = s;
+ } else {
+ s->percept = percept;
+ s->od = od;
+ }
+
+ s->ilimit = ilimit;
+
+ s->inp = inp - fxno; /* Intended number of points */
+ s->angle = angle; /* desired grid angle */
+
+ s->tol = SNAP_TOL;
+
+ ctol = 0.6/pow((double)s->inp, 1.0/di);
+ if (ctol < s->tol) {
+ s->tol = ctol;
+ }
+//printf("~1 tol = %f\n",s->tol);
+
+ s->fxlist = fxlist; /* remember fixed points */
+ s->fxno = fxno;
+
+ /* Compute perceptual values in fixed list */
+ for (i = 0; i < s->fxno; i++)
+ s->percept(s->od, s->fxlist[i].v, s->fxlist[i].p);
+
+ if (di > MXTD)
+ error ("simdlat: Can't handle di %d",di);
+ s->di = di;
+
+ /* We need to do a binary search to establish the desired */
+ /* latice spacing. */
+
+ /* Do an initial stab */
+#ifdef NEVER
+ dia = 0.3;
+#else
+ { /* For body centered cubic */
+ double vol = (double)ilimit/(double)di;
+ double cellvol = (2.0 * vol * di)/(double)inp;
+ dia = pow(cellvol, 1.0/di);
+ printf("~1 initial dia = %f\n",dia);
+ }
+#endif
+ np = do_pass(s, dia);
+ if (np == 0)
+ error("simdlat: First pass gave 0 points!");
+
+//printf("~1 first cut dia %f ang %f gave %d points, target = %d\n",dia, s->angle, np, s->inp);
+
+ if (np < s->inp) { /* Low count */
+ ldia = dia;
+ lnp = np;
+ for(;;) {
+ dia = pow(np/(1.5 * s->inp), 1.0/di) * dia;
+//printf("~1 next try dia %f in hope of %f\n",dia, 1.5 * s->inp);
+
+ np = do_pass(s, dia);
+//printf("~1 second cut dia %f ang %f gave %d points, target = %d\n",dia, s->angle, np,s->inp);
+ if (np >= s->inp)
+ break;
+ ldia = dia; /* New low count */
+ lnp = np;
+ }
+ hdia = dia;
+ hnp = np;
+ } else {
+ hdia = dia; /* High count */
+ hnp = np;
+ for(;;) {
+ dia = pow(np/(0.6 * s->inp), 1.0/di) * dia;
+//printf("~1 next try dia %f in hope of %f\n",dia, 0.6 * s->inp);
+ np = do_pass(s, dia);
+//printf("~1 second cut dia %f ang %f gave %d points, target = %d\n",dia, s->angle, np,s->inp);
+ if (np <= s->inp)
+ break;
+ hdia = dia; /* new high count */
+ hnp = np;
+ }
+ ldia = dia;
+ lnp = np;
+ }
+
+ /* Now zoom into correct number, with linear interp. binary search. */
+ for (i = 0; s->bnvp != s->inp && i < MAX_TRIES; i++) {
+ double ratio;
+
+ /* Bail out early if we're close enough */
+ if ((3 * i) > MAX_TRIES) {
+ if (((double)s->bnvp/(double)s->inp) > 0.99)
+ break;
+ }
+
+ ratio = ((double)s->inp - lnp)/(hnp - lnp); /* Distance between low and high */
+ dia = ratio * (hdia - ldia) + ldia;
+ np = do_pass(s, dia);
+
+//printf("~1 try %d, cut dia %f ang %f gave %d points, target = %d\n",i, dia, s->angle, np,s->inp);
+ if (np > s->inp) {
+ hdia = dia;
+ hnp = np;
+ } else {
+ ldia = dia;
+ lnp = np;
+ }
+ }
+
+ simdlat_reset(s);
+
+//printf("~1 total of %d patches\n",s->bnvp);
+
+ return s;
+}
+
+/* =================================================== */
+
+#ifdef STANDALONE_TEST
+
+//#define ANGLE 0.33333
+#define ANGLE 0.0
+
+icxColorantLu *clu;
+
+#ifdef NEVER
+static void sa_percept(void *od, double *out, double *in) {
+ double lab[3];
+
+ clu->dev_to_rLab(clu, lab, in);
+
+ out[0] = lab[0];
+// out[1] = (lab[1]+100.0)/2.0;
+ out[1] = (lab[2]+100.0)/2.0;
+}
+#else
+
+static void sa_percept(void *od, double *p, double *d) {
+ int e, di = 2;
+
+#ifndef NEVER
+ /* Default Do nothing - copy device to perceptual. */
+ for (e = 0; e < di; e++) {
+ double tt = d[e];
+ if (e == 0)
+ tt = pow(tt, 2.0);
+ else
+ tt = pow(tt, 0.5);
+ p[e] = tt * 100.0;
+ }
+#else
+ for (e = 0; e < di; e++) {
+ double tt = d[e];
+ /* Two slopes with a sharp turnover in X */
+ if (e == 0) {
+ if (tt < 0.5)
+ tt = tt * 0.3/0.5;
+ else
+ tt = 0.3 + ((tt-0.5) * 0.7/0.5);
+ }
+ p[e] = tt * 100.0;
+ }
+#endif
+}
+#endif
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int npoints = 50;
+ simdlat *s;
+ int mask = ICX_BLACK | ICX_GREEN;
+
+ error_program = argv[0];
+
+ if (argc > 1)
+ npoints = atoi(argv[1]);
+
+ if ((clu = new_icxColorantLu(mask)) == NULL)
+ error ("Creation of xcolorant lu object failed");
+
+ /* Create the required points */
+ s = new_simdlat(2, 1.5, npoints, NULL, 0, SIMDLAT_BCC, ANGLE, sa_percept, NULL);
+
+#ifdef DUMP_PLOT
+ printf("Perceptual plot:\n");
+ dump_image_final(s, 1);
+
+ printf("Device plot:\n");
+ dump_image_final(s, 0);
+#endif /* DUMP_PLOT */
+
+ s->del(s);
+
+ return 0;
+}
+
+#endif /* STANDALONE_TEST */
+
+
+
+#if defined(DEBUG) || defined(DUMP_PLOT)
+
+/* Dump the current point positions to a plot window file */
+static void
+dump_image(simdlat *s, int pcp) {
+ double minx, miny, maxx, maxy;
+ double *x1a = NULL;
+ double *y1a = NULL;
+ double *x2a = NULL;
+ double *y2a = NULL;
+ double *x3a = NULL;
+ double *y3a = NULL;
+
+ int i, nu;
+ sdtnode *p;
+
+ if (s->nvp == 0)
+ return;
+
+ if (pcp) { /* Perceptual range */
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 100.0;
+ maxy = 100.0;
+ } else {
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 1.0;
+ maxy = 1.0;
+ }
+
+ if ((x1a = (double *)malloc(s->nvp * sizeof(double))) == NULL)
+ error ("simdlat: plot malloc failed %d",s->nvp);
+ if ((y1a = (double *)malloc(s->nvp * sizeof(double))) == NULL)
+ error ("simdlat: plot malloc failed %d",s->nvp);
+ if ((x2a = (double *)malloc(s->nvp * sizeof(double))) == NULL)
+ error ("simdlat: plot malloc failed %d",s->nvp);
+ if ((y2a = (double *)malloc(s->nvp * sizeof(double))) == NULL)
+ error ("simdlat: plot malloc failed %d",s->nvp);
+
+ for (nu = i = 0; i < s->np; i++) {
+ p = &s->nodes[i];
+
+ if (p->vald == 0)
+ continue;
+ if (pcp) {
+ x1a[nu] = p->v[0];
+ y1a[nu] = p->v[1];
+ x2a[nu] = p->v[0];
+ y2a[nu] = p->v[1];
+ } else {
+ x1a[nu] = p->p[0];
+ y1a[nu] = p->p[1];
+ x2a[nu] = p->p[0];
+ y2a[nu] = p->p[1];
+ }
+ nu++;
+ }
+
+ /* Plot the vectors */
+ do_plot_vec(minx, maxx, miny, maxy,
+ x1a, y1a, x2a, y2a, nu, DO_WAIT, x3a, y3a, 0);
+
+ free(x1a);
+ free(y1a);
+ free(x2a);
+ free(y2a);
+}
+
+/* Dump the final point positions to a plot window file */
+static void
+dump_image_final(simdlat *s, int pcp) {
+ double minx, miny, maxx, maxy;
+ double *x1a = NULL;
+ double *y1a = NULL;
+ double *x2a = NULL;
+ double *y2a = NULL;
+ double *x3a = NULL;
+ double *y3a = NULL;
+
+ int i, nu;
+ sdtnode *p;
+
+ if (pcp) { /* Perceptual range */
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 100.0;
+ maxy = 100.0;
+ } else {
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 1.0;
+ maxy = 1.0;
+ }
+
+ if ((x1a = (double *)malloc(s->bnvp * sizeof(double))) == NULL)
+ error ("simdlat: plot malloc failed");
+ if ((y1a = (double *)malloc(s->bnvp * sizeof(double))) == NULL)
+ error ("simdlat: plot malloc failed");
+ if ((x2a = (double *)malloc(s->bnvp * sizeof(double))) == NULL)
+ error ("simdlat: plot malloc failed");
+ if ((y2a = (double *)malloc(s->bnvp * sizeof(double))) == NULL)
+ error ("simdlat: plot malloc failed");
+
+ for (nu = i = 0; i < s->bnp; i++) {
+ p = &s->bnodes[i];
+
+ if (p->vald == 0)
+ continue;
+ if (pcp) {
+ x1a[nu] = p->v[0];
+ y1a[nu] = p->v[1];
+ x2a[nu] = p->v[0];
+ y2a[nu] = p->v[1];
+ } else {
+ x1a[nu] = p->p[0];
+ y1a[nu] = p->p[1];
+ x2a[nu] = p->p[0];
+ y2a[nu] = p->p[1];
+ }
+ nu++;
+ }
+
+ /* Plot the vectors */
+ do_plot_vec(minx, maxx, miny, maxy,
+ x1a, y1a, x2a, y2a, nu, DO_WAIT, x3a, y3a, 0);
+
+ free(x1a);
+ free(y1a);
+ free(x2a);
+ free(y2a);
+}
+
+#endif /* DEBUG */
+
+
+
+
+
diff --git a/target/simdlat.h b/target/simdlat.h
new file mode 100644
index 0000000..93e0ad3
--- /dev/null
+++ b/target/simdlat.h
@@ -0,0 +1,94 @@
+
+#ifndef SIMDLAT_H
+/*
+ * Argyll Color Correction System
+ *
+ * Simplex device space latice test point class
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/8/2004
+ *
+ * Copyright 2002 - 2004 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.
+ *
+ * Based on simplat.h
+ */
+
+#define SPT_HASHSIZE 4463 /* Hash index size */
+
+/* A sample point node */
+struct _sdtnode {
+ int vald; /* Valid flag */
+ int x[MXTD]; /* Index */
+ double p[MXTD]; /* Device coordinate position */
+ double v[MXTD]; /* Subjective value (Labk) */
+ int b; /* 1 if a gamut point, 2 if a boundary point */
+ unsigned long expm[2]; /* -ve/+ve dimention explored flags */
+
+ int hp; /* Hash linked list index */
+ int up; /* Unexplored linked list index */
+}; typedef struct _sdtnode sdtnode;
+
+
+/* Main simplex latice object */
+struct _simdlat {
+/* private: */
+ int di; /* Point dimensionality */
+ double ilimit; /* Ink limit - limit on sum of p[] */
+ int inp; /* Intended number of points in list */
+ int type; /* Type of point geometry, 0 = body centered etc. */
+ double angle; /* Grid angle */
+ double bo[MXTD]; /* Basis origin */
+ double bv[MXTD][MXTD]; /* Simplex basis vectors */
+ int np; /* Number of point nodes in list */
+ int nvp; /* Number of valid point nodes in list */
+ int np_a; /* Number of points allocated */
+ double dia; /* Point spacing in latice */
+ sdtnode *nodes; /* Current array of nodes */
+ int bnp; /* Number of point nodes in best list */
+ int bnvp; /* Number of best valid point nodes in list */
+ int bnp_a; /* Number of best points allocated */
+ double bdia; /* Point spacing in best latice */
+ sdtnode *bnodes; /* Current best array of nodes */
+ int hash[SPT_HASHSIZE]; /* Hash index */
+ int unex; /* Head of unexplored list index */
+ double tol; /* Snap tollerance */
+
+ /* Perceptual function */
+ void (*percept)(void *od, double *out, double *in);
+ void *od; /* Opaque data for perceptual point */
+
+ /* Fixed points to avoid */
+ fxpos *fxlist; /* List of existing fixed points (may be NULL) */
+ int fxno; /* Number of existing fixes points */
+
+ int rix; /* Next read index */
+
+/* public: */
+ /* Initialise, ready to read out all the points */
+ void (*reset)(struct _simdlat *s);
+
+ /* Read the next set of non-fixed points values */
+ /* return non-zero when no more points */
+ int (*read)(struct _simdlat *s, double *d, double *p);
+
+ /* Destroy ourselves */
+ void (*del)(struct _simdlat *s);
+
+ }; typedef struct _simdlat simdlat;
+
+ /* geometry type */
+#define SIMDLAT_BCC 0 /* Body centered Cubic */
+#define SIMDLAT_EQSPLX 1 /* Equilateral Simplex */
+#define SIMDLAT_FCC 2 /* Face Centered Cubic */
+
+/* Constructor */
+extern simdlat *new_simdlat(int di, double ilimit, int npoints,
+ fxpos *fxlist, int fxno, int type, double angle,
+ void (*percept)(void *od, double *out, double *in), void *od);
+
+#define SIMDLAT_H
+#endif /* SIMDLAT_H */
diff --git a/target/simplat.c b/target/simplat.c
new file mode 100644
index 0000000..736b0e8
--- /dev/null
+++ b/target/simplat.c
@@ -0,0 +1,1095 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Simplex perceptual space latice test point class
+ * set to generate an equilateral simplex regular lattice,
+ * in perceptual space.
+ *
+ * Author: Graeme W. Gill
+ * Date: 27/3/2002
+ *
+ * Copyright 2002 - 2004 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.
+ */
+
+/* TTBD:
+
+ This seems too inexact/slow to read a specified number of test
+ points for use in higher dimensions.
+
+ */
+
+#undef SPHERICAL /* spherical (equalateral simplex) packing, rather */
+ /* than body centered cubic lattice. Better than face centered, */
+ /* worse than body centered. */
+#undef FCCPACK /* Face centered cubic lattice (worse than body centered and spherical) */
+
+#undef DEBUG
+#undef DUMP_PLOT /* Show on screen plot */
+#define PERC_PLOT 1 /* Emit perceptive space plots */
+#define DO_WAIT 1 /* Wait for user key after each plot */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#if defined(__IBMC__)
+#include <float.h>
+#endif
+#ifdef DEBUG
+#include "plot.h"
+#endif
+#include "numlib.h"
+#include "sort.h"
+#include "plot.h"
+#include "icc.h"
+#include "xcolorants.h"
+#include "targen.h"
+#include "simplat.h"
+
+#if defined(DEBUG) || defined(DUMP_PLOT)
+static void dump_image(simplat *s, int pcp);
+static void dump_image_final(simplat *s, int pcp);
+#endif
+
+#define SNAP_TOL 0.01 /* Snap to gamut boundary tollerance */
+#define MAX_TRIES 30 /* Maximum itterations */
+
+
+/* ----------------------------------------------------- */
+
+/* Default convert the nodes device coordinates into approximate perceptual coordinates */
+/* (usually overriden by caller supplied function) */
+static void
+default_simplat_to_percept(void *od, double *p, double *d) {
+ simplat *s = (simplat *)od;
+ int e;
+
+ /* Default Do nothing - copy device to perceptual. */
+ for (e = 0; e < s->di; e++) {
+ p[e] = d[e] * 100.0;
+ }
+}
+
+/* Return the largest distance of the point outside the device gamut. */
+/* This will be 0 if inside the gamut, and > 0 if outside. */
+static double
+simplat_in_dev_gamut(simplat *s, double *d) {
+ int e;
+ int di = s->di;
+ double tt, dd = 0.0;
+ double ss = 0.0;
+
+ for (e = 0; e < di; e++) {
+ ss += d[e];
+
+ tt = 0.0 - d[e];
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ tt = d[e] - 1.0;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ }
+ tt = ss - s->ilimit;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ return dd;
+}
+
+/* Snap a point to the device gamut boundary. */
+/* Return nz if it has been snapped. */
+static int snap_to_gamut(simplat *s, double *d) {
+ int e;
+ int di = s->di;
+ double dd; /* Smallest distance */
+ double ss; /* Sum */
+ int rv = 0;
+
+ /* Snap to ink limit first */
+ for (ss = 0.0, e = 0; e < di; e++)
+ ss += d[e];
+ dd = fabs(ss - s->ilimit);
+
+ if (dd <= s->tol) {
+ int j;
+ for (j = 0; j < di; j++)
+ d[j] *= s->ilimit/ss; /* Snap to ink limit */
+ rv = 1;
+ }
+
+ /* Now snap to any other dimension */
+ for (e = 0; e < di; e++) {
+
+ dd = fabs(d[e] - 0.0);
+ if (dd < s->tol) {
+ d[e] = 0.0; /* Snap to orthogonal boundary */
+ rv = 1;
+ }
+ dd = fabs(1.0 - d[e]);
+ if (dd < s->tol) {
+ d[e] = 1.0; /* Snap to orthogonal boundary */
+ rv = 1;
+ }
+ }
+
+ return rv;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Reverse lookup function :- perceptual to device coordinates */
+
+/* Structure to hold data for optimization function */
+struct _edatas {
+ simplat *s; /* simplat structure */
+ double *ptp; /* Perceptual target point */
+ }; typedef struct _edatas edatas;
+
+/* Definition of the optimization functions handed to powell() */
+
+/* This one returns error from perceptual target point, and */
+/* an error >= 50000 on being out of device gamut */
+static double efunc(void *edata, double p[]) {
+ edatas *ed = (edatas *)edata;
+ simplat *s = ed->s;
+ int e, di = s->di;
+ double rv, pp[MXTD];
+ if ((rv = (simplat_in_dev_gamut(s, p))) > 0.0) {
+ rv = rv * 5000.0 + 100000.0; /* Discourage being out of gamut */
+ } else {
+ s->percept(s->od, pp, p);
+ for (rv = 0.0, e = 0; e < di; e++) {
+ double tt = pp[e] - ed->ptp[e];
+ rv += tt * tt;
+ }
+ }
+//printf("rv = %f from %f %f\n",rv,p[0],p[1]);
+ return rv;
+}
+
+/* Given a point in perceptual space, an approximate point */
+/* in device space, return the device value corresponding to */
+/* the perceptual value, plus the clipped perceptual value. */
+/* Return 1 if the point has been clipped. */
+/* Return 2 if the point has been clipped by a dia. */
+static int
+simplat_from_percept(
+simplat *s,
+double *d, /* return device position */
+double *p /* Given perceptual value */
+) {
+ int e, di = s->di;
+ edatas ed;
+ double pp[MXTD];
+ double sr[MXTD]; /* Search radius */
+ double tt;
+ double drad = 50.0; /* Search radius */
+ double ptol = 0.00001; /* Tolerance */
+ ed.s = s;
+ ed.ptp = p; /* Set target perceptual point */
+
+ for (e = 0; e < di; e++) {
+ sr[e] = drad; /* Device space search radius */
+ }
+ if (powell(&tt, di, d, sr, ptol, 500, efunc, (void *)&ed, NULL, NULL) != 0 || tt >= 50000.0) {
+ error("simplat: powell failed, tt = %f\n",tt);
+ }
+ snap_to_gamut(s, d);
+ s->percept(s->od, pp, d); /* Lookup clipped perceptual */
+
+ tt = 0.0;
+ for (e = 0; e < di; e++) {
+ double t = p[e] - pp[e];
+ p[e] = pp[e];
+ tt += t * t;
+ }
+ tt = sqrt(tt);
+//printf("~1 perc %f %f -> %f %f dev %f %f, err = %f\n",ed.ptp[0],ed.ptp[1],p[0],p[1],d[0],d[1],tt);
+ if (tt > (0.5 * s->dia))
+ return 2; /* invalid & !explore */
+ if (tt > 0.5)
+ return 1; /* Valid & explore */
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Compute the simplex basis vectors */
+static void comp_basis(
+simplat *s,
+double dia, /* Diameter of simplex circumspehere */
+double off, /* Starting offset in device space */
+double angle /* Rotation angle 0.0 - 1.0 */
+) {
+ int i, j, di = s->di;
+ double sx[MXTD+1][MXTD]; /* Simplex verticies */
+
+#ifdef SPHERICAL
+
+ /* Create the node positions for the */
+ /* equalateral simplex basis vectors */
+ for (i = 0; i < (di+1); i++) {
+ double rr = 1.0; /* Current radius squared */
+ double ss = dia / sqrt(3.0); /* Scale */
+
+ /* The bounding points form a equalateral simplex */
+ /* whose vertexes are on a sphere about the data */
+ for (j = 0; j < di; j++) {
+ double ddi;
+ double hh = 1.0/(di-j); /* Weight for remaining points */
+
+ if (j > i)
+ sx[i][j] = 0.0; /* If beyond last */
+ else if (j == i) /* If last non-zero */
+ sx[i][j] = ss * sqrt(rr);
+ else /* If before last */
+ sx[i][j] = -hh * ss * sqrt(rr);
+
+ ddi = (double)(di - j);
+ rr *= (ddi * ddi - 1.0)/(ddi * ddi);
+ }
+ }
+
+#else /* !SPHERICAL */
+
+#ifdef FCCPACK
+
+ /* Create the node positions for the */
+ /* face centered arrangement */
+ /* Face centered places points at locations where the */
+ /* sum of the lattice integer coordinates is even. */
+ for (i = 0; i < (di+1); i++) {
+
+ for (j = 0; j < di; j++)
+ sx[i][j] = 0.0 * -0.5;
+
+ if (i > 0 && i < di) {
+ sx[i][i-1] += 0.5 * dia;
+ sx[i][di-1] += 0.5 * dia;
+ } else if (i == di) {
+ sx[i][di-1] += dia;
+ }
+ }
+
+#else /* Body cenetered */
+
+ /* Create the node positions for body centered */
+ /* cubic latice simplex basis vectors */
+ /* Body centered places points at locations where the */
+ /* lattice integer coordinates are all even or all odd. */
+ for (i = 0; i < (di+1); i++) {
+
+ for (j = 0; j < di; j++)
+ sx[i][j] = -0.5;
+ if (i < di) {
+ if (i > 0)
+ sx[i][i-1] += dia;
+ } else {
+ for (j = 0; j < di; j++)
+ sx[i][j] += 0.5 * dia;
+ }
+ }
+
+#endif /* !FCCPACK */
+#endif /* !SPHERICAL */
+
+ /* Apply a rotation to avoid possible alignment with */
+ /* the device axes */
+ {
+ int m, k;
+ int ldi = di-1; /* Last dimension */
+ double a, b;
+
+ b = angle;
+ a = sqrt(1.0 - b * b);
+
+ /* Apply rotation to all except last dimension */
+ for (m = 0; m < ldi; m++) { /* Dimension being rotated */
+
+ for (i = 0; i < (di+1); i++) { /* Node being rotated */
+ double out[MXTD];
+
+ for (j = 0; j < di; j++) { /* Coord being produced */
+ out[j] = 0.0;
+
+ for (k = 0; k < di; k++) { /* Coord being used */
+ if ((j == m && k == m)
+ || (j == ldi && k == ldi))
+ out[j] += a * sx[i][k]; /* Diagonal multiplier */
+ else if (j == m && k == ldi)
+ out[j] += b * sx[i][k];
+ else if (j == ldi && k == m)
+ out[j] -= b * sx[i][k];
+ else if (j == k)
+ out[j] += sx[i][k];
+ }
+ }
+ for (j = 0; j < di; j++)
+ sx[i][j] = out[j]; /* Transfer result */
+ }
+ }
+ }
+
+#ifdef DEBUG /* Dump stats on verticies */
+for(i = 0; i < (di+1); i++) {
+ double val = 0.0;
+ printf("vert %d = ",i);
+ for(j = 0; j < di; j++) {
+ val += sx[i][j] * sx[i][j];
+ printf("%f ",sx[i][j]);
+ }
+ printf(" (%f)\n",sqrt(val));
+}
+
+for(i = 0; i < di; i++) {
+ for (j = i+1; j < (di+1); j++) {
+ int e;
+ double val;
+
+ /* Distance between nodes */
+ for (val = 0.0, e = 0; e < di; e++) {
+ double tt = sx[i][e] - sx[j][e];
+ val += tt * tt;
+ }
+ val = sqrt(val);
+ printf("dist %d %d = %f\n",i,j,val);
+ }
+}
+#endif /* DEBUG */
+
+ /* Convert from di+1 verticies to di base vectors */
+ for (i = 0; i < di; i++) {
+ for (j = 0; j < di; j++) {
+ s->bv[i][j] = sx[i+1][j] - sx[i][j];
+ }
+ }
+
+ /* Establish the basis origin */
+ {
+ double dv[MXTD];
+
+ for (j = 0; j < di; j++)
+ dv[j] = off * s->ilimit/di;
+ s->percept(s->od, s->bo, dv);
+ }
+}
+
+/* Compute the hash */
+static int comp_hash(
+simplat *s,
+int *x /* Index */
+) {
+ int j, di = s->di;
+ unsigned long hash;
+
+ for (hash = 0, j = 0; j < di; j++)
+ hash = hash * 7 + x[j];
+ hash %= SPT_HASHSIZE;
+
+ return hash;
+}
+
+/* Check if a node already exists. Return -1 if not, */
+/* or node index if it does. */
+static int check_exists(
+simplat *s,
+int *x, /* Index */
+int hash /* Hash */
+) {
+ int di = s->di;
+ int hp; /* node index */
+ int j;
+
+ for (hp = s->hash[hash]; hp >= 0; hp = s->nodes[hp].hp) {
+
+ /* Check if we have a match */
+ for (j = 0; j < di; j++) {
+ if (s->nodes[hp].x[j] != x[j])
+ break;
+ }
+ if (j >= di)
+ break; /* Found a match */
+ }
+
+ return hp;
+}
+
+/* Create a new node. We assume it doesn't already exist */
+/* Return its index */
+static int new_node(
+simplat *s,
+int *x, /* Index */
+int hash /* Hash */
+) {
+ int di = s->di;
+ int b = 0; /* NZ if a boundary point */
+ int nn; /* New node index */
+ int hp; /* Hash chain index */
+ int i, j;
+
+ /* Make room for it */
+ if ((s->np+1) >= s->np_a) {
+ s->np_a *= 2;
+ if ((s->nodes = (sptnode *)realloc(s->nodes, s->np_a * sizeof(sptnode))) == NULL)
+ error ("simplat: node realloc failed");
+ }
+
+ nn = s->np++; /* Add the new point */
+
+ /* Compute the target perceptual value */
+ for (j = 0; j < di; j++) {
+ s->nodes[nn].v[j] = s->bo[j];
+ s->nodes[nn].p[j] = 0.5; /* Search start point */
+ }
+ for (i = 0; i < di; i++) {
+ for (j = 0; j < di; j++) {
+ s->nodes[nn].v[j] += x[i] * s->bv[i][j]; /* Sum basis vector product */
+ }
+ }
+
+ /* Lookup the device position */
+ b = simplat_from_percept(s, s->nodes[nn].p, s->nodes[nn].v);
+
+ /* Store node information */
+ for (j = 0; j < di; j++)
+ s->nodes[nn].x[j] = x[j];
+
+ s->nodes[nn].b = b;
+ if (b < 2) {
+ s->nodes[nn].vald = 1; /* Valid if within or on gamut */
+ s->nvp++; /* Got another valid one */
+ } else
+ s->nodes[nn].vald = 0; /* Not valid if it's a boundary point */
+ s->nodes[nn].expm[0] =
+ s->nodes[nn].expm[1] = (1 << di)-1; /* Assum all dimensions need exploring */
+ s->nodes[nn].hp = s->nodes[nn].up = -1; /* Linked list indexes */
+
+ /* Add an entry in the hash table */
+ if (s->hash[hash] < 0)
+ s->hash[hash] = nn; /* We are the only entry */
+ else {
+ hp = s->hash[hash];
+ while (s->nodes[hp].hp >= 0)
+ hp = s->nodes[hp].hp; /* Follow chain */
+ s->nodes[hp].hp = nn; /* Add at the end of the chain */
+ }
+
+ return nn;
+}
+
+/* ============================================= */
+/* Main object functions */
+
+/* Initialise, ready to read out all the points */
+static void simplat_reset(simplat *s) {
+ s->rix = 0;
+}
+
+/* Read the next set of non-fixed points values */
+/* return non-zero when no more points */
+static int simplat_read(
+simplat *s,
+double *d, /* Device position */
+double *p /* Perceptual value */
+) {
+ int j;
+
+ for (; s->rix < s->bnp; s->rix++) {
+
+ if (s->bnodes[s->rix].vald != 0) {
+ for (j = 0; j < s->di; j++) {
+ if (d != NULL)
+ d[j] = s->bnodes[s->rix].p[j];
+ if (p != NULL)
+ p[j] = s->bnodes[s->rix].v[j];
+ }
+ s->rix++;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Do a pass of seed filling the whole gamut, given a simplex dia. */
+/* Return the number of nodes produced */
+static int do_pass(
+simplat *s,
+double dia /* Simplex diameter to try */
+) {
+ int di = s->di;
+ int hash;
+ int i, j, k;
+ int x[MXTD];
+ int nn; /* New nodes index */
+ int np;
+
+ /* Rest the current list */
+ s->np = 0;
+ s->nvp = 0;
+ for (i = 0; i < SPT_HASHSIZE; i++)
+ s->hash[i] = -1;
+
+ /* Initial alloc of nodes */
+ if (s->nodes == NULL) {
+ s->np_a = 10;
+ if ((s->nodes = (sptnode *)malloc(s->np_a * sizeof(sptnode))) == NULL)
+ error ("simplat: nodes malloc failed");
+ }
+
+ /* Compute the simplex basis vectors */
+ /* arguments: simplex diameter, device space offset, angle to skew grid */
+ comp_basis(s, dia, 0.5, s->angle);
+
+// comp_basis(s, dia, 0.5, ANGLE);
+// comp_basis(s, dia, 0.5, dia/200.0);
+// comp_basis(s, dia, 0.4 + dia/150.0, ANGLE);
+// comp_basis(s, dia, 0.4 + dia/150.0, dia/147.0);
+// comp_basis(s, dia, 0.5, fmod(dia, 1.0));
+
+ s->dia = dia;
+
+ /* Add an initial seed point */
+ for (j = 0; j < di; j++)
+ x[j] = 0;
+ hash = comp_hash(s, x);
+ nn = new_node(s, x, hash);
+
+ if (s->nodes[nn].b > 1) {
+ error("simplat: initial seed point is not within gamut");
+ }
+
+ s->unex = nn; /* Initial entry in unexplored list */
+
+//printf("~1 seed node is [%d %d]\n",s->nodes[nn].x[0], s->nodes[nn].x[1]);
+
+ /* While there is more unexplored area */
+ /* and we arn't finding a ridiculous number of points */
+ while(s->unex >= 0 && (s->nvp < 3 * s->inp)) {
+ int pos; /* Positive or -ve direction */
+ nn = s->unex; /* Node we're looking at */
+ s->unex = s->nodes[nn].up; /* remove from unexplored list */
+
+//printf("\n~1 exploring beyond node [%d %d]\n",s->nodes[nn].x[0], s->nodes[nn].x[1]);
+
+ if (s->nodes[nn].b > 1)
+ continue; /* Don't look at boundary points */
+
+ /* For all unexplored directions */
+ for (i = 0; i < di; i++) {
+ for (pos = 0; pos < 2; pos++) {
+ int on; /* Other node index */
+
+//printf("~1 checking direction dim %d, sign %d, [%d %d]\n",i,pos,x[0],x[1]);
+
+ if (((1 << i) & s->nodes[nn].expm[pos]) == 0) {
+//printf("~1 that direction has been explored\n");
+ continue; /* Try next direction */
+ }
+
+ /* Check out that direction */
+ for (j = 0; j < di; j++)
+ x[j] = s->nodes[nn].x[j];
+ x[i] += pos ? 1 : -1;
+
+ /* If that node already exists */
+ hash = comp_hash(s, x);
+ if ((on = check_exists(s, x, hash)) >= 0) {
+ /* back direction doesn't need checking */
+ s->nodes[on].expm[pos ^ 1] &= ~(1 << i);
+//printf("~1 that node already exists\n");
+ continue; /* Try next direction */
+ }
+
+ /* Create a new node in that direction */
+ on = new_node(s, x, hash);
+
+ if (s->nodes[on].b > 1) { /* If new node is boundary, don't explore beyond it */
+//printf("~1 added new boundary node [%d %d]\n",x[0],x[1]);
+ continue;
+ }
+ /* back direction on new node doesn't need checking */
+ s->nodes[on].expm[pos ^ 1] &= ~(1 << i);
+
+//printf("~1 added new internal node [%d %d] **\n",x[0],x[1]);
+ s->nodes[on].up = s->unex; /* Add this node to unexplored list */
+ s->unex = on;
+ }
+ }
+ }
+
+
+ /* Rationalise cooincident points, and count final valid */
+ s->nvp = 0;
+ for (i = 0; i < s->np; i++) {
+
+//printf("~1 rationalising %d, = %f %f\n",i, s->nodes[i].v[0], s->nodes[i].v[1]);
+ if (s->nodes[i].vald == 0) {
+//printf("~1 point %d is not valid\n",i);
+ continue;
+ }
+
+ /* First against fixed points in device space */
+ for (k = 0; k < s->fxno; k++) {
+ double dd;
+
+ /* Compute distance */
+ dd = 0.0;
+ for (j = 0; j < di; j++) {
+ double tt = s->nodes[i].v[j] - s->fxlist[k].v[j];
+ dd += tt * tt;
+ }
+ dd = 0.01 * sqrt(dd);
+
+ if (dd < s->tol) {
+ s->nodes[i].vald = 0; /* Ignore this point */
+//printf("~1 point %d matches input point %d\n",i, k);
+ break;
+ }
+ }
+
+ if (s->nodes[i].vald == 0)
+ continue;
+
+ /* Then against all the other points */
+ for (k = i+1; k < s->np; k++) {
+ double dd;
+
+ if (s->nodes[k].vald == 0)
+ continue;
+
+ /* Compute distance */
+ dd = 0.0;
+ for (j = 0; j < di; j++) {
+ double tt = s->nodes[i].v[j] - s->nodes[k].v[j];
+ dd += tt * tt;
+ }
+ dd = 0.01 * sqrt(dd);
+
+ if (dd < s->tol) {
+ s->nodes[i].vald = 0; /* Ignore this point */
+//printf("~1 point %d matches other point %d\n",i, k);
+ break;
+ }
+ }
+
+ if (s->nodes[i].vald != 0)
+ s->nvp++; /* Found a valid one */
+ }
+
+#ifdef DUMP_PLOT
+ /* Dump plot */
+ dump_image(s, PERC_PLOT);
+#endif /* DUMP_PLOT */
+
+printf("~1 got %d valid out of %d total\n",s->nvp, s->np);
+ np = s->nvp;
+
+ /* If we have a new best */
+ if (s->nvp <= s->inp && (s->inp - s->nvp) < (s->inp - s->bnvp)) {
+ sptnode *tnodes;
+ int tnp_a;
+ tnodes = s->bnodes; /* Swap them */
+ tnp_a = s->bnp_a;
+ s->bnp = s->np;
+ s->bnvp = s->nvp;
+ s->bnodes = s->nodes;
+ s->bnp_a = s->np_a;
+ s->bdia = s->dia;
+ s->nodes = tnodes;
+ s->np_a = tnp_a;
+ s->np = s->nvp = 0; /* Zero current */
+ }
+
+ return np;
+}
+
+/* Destroy ourselves */
+static void
+simplat_del(simplat *s) {
+
+ if (s->nodes != NULL)
+ free(s->nodes);
+ if (s->bnodes != NULL)
+ free(s->bnodes);
+
+ free (s);
+}
+
+/* Constructor */
+simplat *new_simplat(
+int di, /* Dimensionality of device space */
+double ilimit, /* Ink limit (sum of device coords max) */
+int inp, /* Number of points to generate */
+fxpos *fxlist, /* List of existing fixed points (may be NULL) */
+int fxno, /* Number of existing fixes points */
+double angle, /* Angle to orient grid at (0.0 - 0.5 typical) */
+void (*percept)(void *od, double *out, double *in), /* Perceptual lookup func. */
+void *od /* context for Perceptual function */
+) {
+ int i;
+ double ctol;
+ double hdia, ldia, dia;
+ int hnp, lnp, np;
+ simplat *s;
+
+#ifdef DEBUG
+ printf("new_simplat called with di %d, inp %d\n",di,inp);
+#endif
+
+ if ((s = (simplat *)calloc(sizeof(simplat), 1)) == NULL)
+ error ("simplat: simplat malloc failed");
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ s->reset = simplat_reset;
+ s->read = simplat_read;
+ s->del = simplat_del;
+
+ /* If no perceptual function given, use default */
+ if (percept == NULL) {
+ s->percept = default_simplat_to_percept;
+ s->od = s;
+ } else {
+ s->percept = percept;
+ s->od = od;
+ }
+
+ s->ilimit = ilimit;
+
+ s->inp = inp - fxno; /* Intended number of points */
+ s->angle = angle; /* desired grid angle */
+
+ s->tol = SNAP_TOL;
+
+ ctol = 0.6/pow((double)s->inp, 1.0/di);
+ if (ctol < s->tol) {
+ s->tol = ctol;
+ }
+printf("~1 tol = %f\n",s->tol);
+
+ s->fxlist = fxlist; /* remember fixed points */
+ s->fxno = fxno;
+
+ /* Compute perceptual values in fixed list */
+ for (i = 0; i < s->fxno; i++)
+ s->percept(s->od, s->fxlist[i].v, s->fxlist[i].p);
+
+
+ if (di > MXTD)
+ error ("simplat: Can't handle di %d",di);
+ s->di = di;
+
+ /* We need to do a binary search to establish the desired */
+ /* latice spacing. */
+
+ /* Do an initial stab */
+ dia = 50.0;
+ np = do_pass(s, dia);
+ if (np == 0)
+ error("simplat: First pass gave 0 points!");
+
+printf("~1 first cut dia %f gave %d points, target = %d\n",dia, np, s->inp);
+
+ if (np < s->inp) { /* Low count */
+ ldia = dia;
+ lnp = np;
+ for(;;) {
+ dia = pow(np/(1.5 * s->inp), 1.0/di) * dia;
+//printf("~1 next try dia %f in hope of %f\n",dia, 1.5 * s->inp);
+
+ np = do_pass(s, dia);
+printf("~1 second cut dia %f gave %d points, target = %d\n",dia, np,s->inp);
+ if (np >= s->inp)
+ break;
+ ldia = dia; /* New low count */
+ lnp = np;
+ }
+ hdia = dia;
+ hnp = np;
+ } else {
+ hdia = dia; /* High count */
+ hnp = np;
+ for(;;) {
+ dia = pow(np/(0.6 * s->inp), 1.0/di) * dia;
+//printf("~1 next try dia %f in hope of %f\n",dia, 0.6 * s->inp);
+ np = do_pass(s, dia);
+printf("~1 second cut dia %f gave %d points, target = %d\n",dia, np,s->inp);
+ if (np <= s->inp)
+ break;
+ hdia = dia; /* new high count */
+ hnp = np;
+ }
+ ldia = dia;
+ lnp = np;
+ }
+
+ /* Now zoom into correct number, with linear interp. binary search. */
+ for (i = 0; s->bnvp != s->inp && i < MAX_TRIES; i++) {
+ double ratio;
+
+ /* Bail out early if we're close enough */
+ if ((3 * i) > MAX_TRIES) {
+ if (((double)s->bnvp/(double)s->inp) > 0.99)
+ break;
+ }
+
+ ratio = ((double)s->inp - lnp)/(hnp - lnp); /* Distance between low and high */
+ dia = ratio * (hdia - ldia) + ldia;
+ np = do_pass(s, dia);
+
+printf("~1 try %d, cut dia %f gave %d points, target = %d\n",i, dia, np,s->inp);
+ if (np > s->inp) {
+ hdia = dia;
+ hnp = np;
+ } else {
+ ldia = dia;
+ lnp = np;
+ }
+ }
+
+ simplat_reset(s);
+
+printf("~1 total of %d patches\n",s->bnvp);
+
+ return s;
+}
+
+/* =================================================== */
+
+#ifdef STANDALONE_TEST
+
+#define ANGLE 0.0
+
+icxColorantLu *clu;
+
+#ifdef NEVER
+static void sa_percept(void *od, double *out, double *in) {
+ double lab[3];
+
+ clu->dev_to_rLab(clu, lab, in);
+
+ out[0] = lab[0];
+// out[1] = (lab[1]+100.0)/2.0;
+ out[1] = (lab[2]+100.0)/2.0;
+}
+#else
+
+static void sa_percept(void *od, double *p, double *d) {
+ int e, di = 2;
+
+#ifndef NEVER
+ /* Default Do nothing - copy device to perceptual. */
+ for (e = 0; e < di; e++) {
+ double tt = d[e];
+ if (e == 0)
+ tt = pow(tt, 2.0);
+ else
+ tt = pow(tt, 0.5);
+ p[e] = tt * 100.0;
+ }
+#else
+ for (e = 0; e < di; e++) {
+ double tt = d[e];
+ /* Two slopes with a sharp turnover in X */
+ if (e == 0) {
+ if (tt < 0.5)
+ tt = tt * 0.3/0.5;
+ else
+ tt = 0.3 + ((tt-0.5) * 0.7/0.5);
+ }
+ p[e] = tt * 100.0;
+ }
+#endif
+}
+#endif
+
+int
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int npoints = 50;
+ simplat *s;
+ int mask = ICX_BLACK | ICX_GREEN;
+
+ error_program = argv[0];
+
+ if (argc > 1)
+ npoints = atoi(argv[1]);
+
+ if ((clu = new_icxColorantLu(mask)) == NULL)
+ error ("Creation of xcolorant lu object failed");
+
+ /* Create the required points */
+ s = new_simplat(2, 1.5, npoints, NULL, 0, ANGLE, sa_percept, (void *)NULL);
+
+#ifdef DUMP_PLOT
+ printf("Perceptual plot:\n");
+ dump_image_final(s, 1);
+
+ printf("Device plot:\n");
+ dump_image_final(s, 0);
+#endif /* DUMP_PLOT */
+
+ s->del(s);
+
+ return 0;
+}
+
+#endif /* STANDALONE_TEST */
+
+
+
+#if defined(DEBUG) || defined(DUMP_PLOT)
+
+/* Dump the current point positions to a plot window file */
+static void
+dump_image(simplat *s, int pcp) {
+ double minx, miny, maxx, maxy;
+ double *x1a = NULL;
+ double *y1a = NULL;
+ double *x2a = NULL;
+ double *y2a = NULL;
+ double *x3a = NULL;
+ double *y3a = NULL;
+
+ int i, nu;
+ sptnode *p;
+
+ if (s->nvp == 0)
+ return;
+
+ if (pcp) { /* Perceptual range */
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 100.0;
+ maxy = 100.0;
+ } else {
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 1.0;
+ maxy = 1.0;
+ }
+
+ if ((x1a = (double *)malloc(s->nvp * sizeof(double))) == NULL)
+ error ("simplat: plot malloc failed %d",s->nvp);
+ if ((y1a = (double *)malloc(s->nvp * sizeof(double))) == NULL)
+ error ("simplat: plot malloc failed %d",s->nvp);
+ if ((x2a = (double *)malloc(s->nvp * sizeof(double))) == NULL)
+ error ("simplat: plot malloc failed %d",s->nvp);
+ if ((y2a = (double *)malloc(s->nvp * sizeof(double))) == NULL)
+ error ("simplat: plot malloc failed %d",s->nvp);
+
+ for (nu = i = 0; i < s->np; i++) {
+ p = &s->nodes[i];
+
+ if (p->vald == 0)
+ continue;
+ if (pcp) {
+ x1a[nu] = p->v[0];
+ y1a[nu] = p->v[1];
+ x2a[nu] = p->v[0];
+ y2a[nu] = p->v[1];
+ } else {
+ x1a[nu] = p->p[0];
+ y1a[nu] = p->p[1];
+ x2a[nu] = p->p[0];
+ y2a[nu] = p->p[1];
+ }
+ nu++;
+ }
+
+ /* Plot the vectors */
+ do_plot_vec(minx, maxx, miny, maxy,
+ x1a, y1a, x2a, y2a, nu, DO_WAIT, x3a, y3a, 0);
+
+ free(x1a);
+ free(y1a);
+ free(x2a);
+ free(y2a);
+}
+
+/* Dump the final point positions to a plot window file */
+static void
+dump_image_final(simplat *s, int pcp) {
+ double minx, miny, maxx, maxy;
+ double *x1a = NULL;
+ double *y1a = NULL;
+ double *x2a = NULL;
+ double *y2a = NULL;
+ double *x3a = NULL;
+ double *y3a = NULL;
+
+ int i, nu;
+ sptnode *p;
+
+ if (pcp) { /* Perceptual range */
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 100.0;
+ maxy = 100.0;
+ } else {
+ minx = 0.0; /* Assume */
+ miny = 0.0;
+ maxx = 1.0;
+ maxy = 1.0;
+ }
+
+ if ((x1a = (double *)malloc(s->bnvp * sizeof(double))) == NULL)
+ error ("simplat: plot malloc failed");
+ if ((y1a = (double *)malloc(s->bnvp * sizeof(double))) == NULL)
+ error ("simplat: plot malloc failed");
+ if ((x2a = (double *)malloc(s->bnvp * sizeof(double))) == NULL)
+ error ("simplat: plot malloc failed");
+ if ((y2a = (double *)malloc(s->bnvp * sizeof(double))) == NULL)
+ error ("simplat: plot malloc failed");
+
+ for (nu = i = 0; i < s->bnp; i++) {
+ p = &s->bnodes[i];
+
+ if (p->vald == 0)
+ continue;
+ if (pcp) {
+ x1a[nu] = p->v[0];
+ y1a[nu] = p->v[1];
+ x2a[nu] = p->v[0];
+ y2a[nu] = p->v[1];
+ } else {
+ x1a[nu] = p->p[0];
+ y1a[nu] = p->p[1];
+ x2a[nu] = p->p[0];
+ y2a[nu] = p->p[1];
+ }
+ nu++;
+ }
+
+ /* Plot the vectors */
+ do_plot_vec(minx, maxx, miny, maxy,
+ x1a, y1a, x2a, y2a, nu, DO_WAIT, x3a, y3a, 0);
+
+ free(x1a);
+ free(y1a);
+ free(x2a);
+ free(y2a);
+}
+
+#endif /* DEBUG */
+
+
+
+
+
diff --git a/target/simplat.h b/target/simplat.h
new file mode 100644
index 0000000..4cede20
--- /dev/null
+++ b/target/simplat.h
@@ -0,0 +1,86 @@
+
+#ifndef SIMPLAT_H
+/*
+ * Argyll Color Correction System
+ *
+ * Simplex perceptual space latice test point class
+ *
+ * Author: Graeme W. Gill
+ * Date: 27/3/2002
+ *
+ * Copyright 2002 - 2004 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.
+ */
+
+#define SPT_HASHSIZE 4463 /* Hash index size */
+
+/* A sample point node */
+struct _sptnode {
+ int vald; /* Valid flag */
+ int x[MXTD]; /* Index */
+ double p[MXTD]; /* Device coordinate position */
+ double v[MXTD]; /* Subjective value (Labk) */
+ int b; /* 1 if a gamut point, 2 if a boundary point */
+ unsigned long expm[2]; /* -ve/+ve dimention explored flags */
+
+ int hp; /* Hash linked list index */
+ int up; /* Unexplored linked list index */
+}; typedef struct _sptnode sptnode;
+
+
+/* Main simplex latice object */
+struct _simplat {
+/* private: */
+ int di; /* Point dimensionality */
+ double ilimit; /* Ink limit - limit on sum of p[] */
+ int inp; /* Intended number of points in list */
+ double angle; /* Grid angle */
+ double bo[MXTD]; /* Basis origin */
+ double bv[MXTD][MXTD]; /* Simplex basis vectors */
+ int np; /* Number of point nodes in list */
+ int nvp; /* Number of valid point nodes in list */
+ int np_a; /* Number of points allocated */
+ double dia; /* Point spacing in latice */
+ sptnode *nodes; /* Current array of nodes */
+ int bnp; /* Number of point nodes in best list */
+ int bnvp; /* Number of best valid point nodes in list */
+ int bnp_a; /* Number of best points allocated */
+ double bdia; /* Point spacing in best latice */
+ sptnode *bnodes; /* Current best array of nodes */
+ int hash[SPT_HASHSIZE]; /* Hash index */
+ int unex; /* Head of unexplored list index */
+ double tol; /* Snap tollerance */
+
+ /* Perceptual function */
+ void (*percept)(void *od, double *out, double *in);
+ void *od; /* Opaque data for perceptual point */
+
+ /* Fixed points to avoid */
+ fxpos *fxlist; /* List of existing fixed points (may be NULL) */
+ int fxno; /* Number of existing fixes points */
+
+ int rix; /* Next read index */
+
+/* public: */
+ /* Initialise, ready to read out all the points */
+ void (*reset)(struct _simplat *s);
+
+ /* Read the next set of non-fixed points values */
+ /* return non-zero when no more points */
+ int (*read)(struct _simplat *s, double *d, double *p);
+
+ /* Destroy ourselves */
+ void (*del)(struct _simplat *s);
+
+ }; typedef struct _simplat simplat;
+
+/* Constructor */
+extern simplat *new_simplat(int di, double ilimit, int npoints,
+ fxpos *fxlist, int fxno, double angle,
+ void (*percept)(void *od, double *out, double *in), void *od);
+
+#define SIMPLAT_H
+#endif /* SIMPLAT_H */
diff --git a/target/targen.c b/target/targen.c
new file mode 100644
index 0000000..09dcc35
--- /dev/null
+++ b/target/targen.c
@@ -0,0 +1,2224 @@
+
+/*
+ * Argyll Color Correction System
+ * Test target chart Generator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/9/96
+ *
+ * Copyright 1996 - 2004, 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.
+ */
+
+/* This program generates a CGATS.5 compatibe file, that */
+/* containing device color test patch values. */
+
+/* TTBD:
+
+ Should add an option to generate grey and near grey
+ or other PCS based pattern test points based on the previous profile.
+ How about an option to read in an CGATS file containing
+ PCS or device values ? How is the black level chosen for PCS though ?
+
+ Would be nice to be able to take a previous .ti3 and
+ then suppliment the measured patches. Would have to add another
+ set of measurement columns to .ti1 & .ti2 to carry the
+ already measured values through, or do clumbsy post merge ?
+
+ Would be nice to be able to generate secondary
+ color ramps (ie. CMY for RGB space, RGB for CMYK space.)
+
+ Using adaptive patch creation for grey colorspace is broken.
+ This should be fixed.
+
+ */
+
+/* NOTE:
+
+ The device model is assumed to not take xpow into account,
+ hence the expected values don't reflect its effect.
+ The general filter is applied prior to the xpow being applied.
+ Many of the test patch types do take it into account
+ when computing the ink limit.
+ The ones that don't are the more complicated full spread patches.
+
+ */
+
+/* Description:
+
+ >> THIS NEEDS REVISION <<
+
+ Nearly all current Color correction systems generate test charts (or
+ device characterisation target charts) by laying out a regular rectangular
+ grid of test points in device space (Targen will do this if you feed it a non-zero
+ m option). On some consideration, this approach is far from optimal. Not only
+ is a regular grid inefficent in packing the multidimentional device space,
+ but if the points are spaced evenly in device space, they will be poorly
+ spaced in human perceptual space, and errors in perceptual space are
+ the ultimate arbiter of the end profiles accuracy. Some commercial
+ color systems tackle the latter problem by "pre-linearising" the device,
+ which amounts to distorting the regular device space grid points with
+ a perceptual inverse per device chanel lookup curve.
+
+ The approach I have taken with Argyll, is a little different. By
+ using an iterative sphere packing algorithm, I constrain the given
+ number of test points to the devices physical gamut (including an
+ ink limit for a printer device), and then try and pack the points
+ evenly in human perceptual space, or even space them to minimise
+ curvature approximation errors. Because the packing is a stocastic
+ process, the resulting points are distributed without evident
+ patterns.
+
+#ifdef NEVER
+ For higher dimensional spaces, where the aim is to create a
+ more aproximate device profile, I've used a "perfect simplex
+ latice" generator to lay out perfectly packed sample points
+ in perceptual space. The latice spacing is sized by an
+ iterative search to (hopefully) create the right number of
+ test points.
+#else
+ For higher dimensional spaces, where the aim is to create a
+ more aproximate device profile, I've used an "incremental far
+ point" point generator, that for each added point, locates
+ the device values that result in a percetual value farthest
+ from any existing points in the test set.
+#endif
+
+ Another issue with laying test points out in regular grids, is
+ that this means that the device response is poorly sampled
+ (since the grids are usually coarse), and this can make it
+ impossible to create detailed device linearisation "shaper"
+ curves from the resulting data !
+ Ideally, in any colorspace (input or output), when viewed from
+ any possible angle, none of the test data points should appear
+ to line up. The Argyll target generator seems to acheive this goal.
+
+ */
+
+#undef DEBUG
+
+#define VRML_DIAG /* Enable option to dump a VRML of the resulting full spread points */
+#undef ADDRECCLIPPOINTS /* Add ink limited clipping points to regular grid */
+#define EMPH_NEUTRAL /* Emphasise neutral axis, like CIE94 does */
+#define NEMPH_DEFAULT 0.5 /* Default emphasis == 2 x CIE94 */
+#define DEFANGLE 0.3333 /* For simdlat and simplat */
+#define SIMDLAT_TYPE SIMDLAT_BCC /* Simdlat geometry type */
+#define MATCH_TOLL 1e-3 /* Tollerance of device value to consider a patch a duplicate */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "vrml.h"
+#include "rspl.h"
+#include "cgats.h"
+#include "icc.h"
+#include "xicc.h"
+#include "targen.h"
+//#include "ppoint.h"
+#include "ofps.h"
+#include "ifarp.h"
+#include "simplat.h"
+#include "simdlat.h"
+#include "prand.h"
+
+#include <stdarg.h>
+
+#define min2(a,b) ((a) < (b) ? (a) : (b))
+#define min3(a,b,c) (min2((a), min2((b),(c))))
+#define max2(a,b) ((a) > (b) ? (a) : (b))
+#define max3(a,b,c) (max2((a), max2((b),(c))))
+
+/* 32 bit pseudo random sequencer */
+#define PSRAND32(S) (((S) & 0x80000000) ? (((S) << 1) ^ 0xa398655d) : ((S) << 1))
+
+/* ---------------------------- */
+/* The perception function data */
+/* (Used for test point distribution) */
+struct _pcpt {
+/* public: */
+ void (*del)(struct _pcpt *s); /* We're done with it */
+
+ int (*is_specific)(struct _pcpt *s); /* Is a specific model, not defaulte */
+
+ /* Conversions */
+ void (*dev_to_perc)(struct _pcpt *s, double *out, double *in); /* N-chan Perceptual */
+ void (*dev_to_XYZ)(struct _pcpt *s, double *out, double *in); /* Absolute XYZ */
+ void (*dev_to_rLab)(struct _pcpt *s, double *out, double *in); /* Relative Lab */
+ void (*den_to_dev)(struct _pcpt *s, double *out, double *in); /* Density to device */
+ void (*rLab_to_dev)(struct _pcpt *s, double *out, double *in); /* Lab to device */
+
+ /* !!! Should add perc_to_dev using code from prand that uses dnsq !!! */
+
+/* private: */
+ inkmask xmask; /* external xcolorants inkmask */
+ inkmask nmask; /* internal xcolorants inkmask */
+ int di; /* Number of Device dimensions */
+
+ /* Tuning parameters */
+ double nemph; /* neutral emphasis, 0.0 - 1.0. Default 0.35 for == CIE94 */
+
+ /* ICC profile based */
+ icmFile *fp;
+ icc *icco;
+ icmLuBase *luo; /* Device -> rLab conversion */
+ icmLuBase *luo2; /* Device -> XYZ conversion */
+
+ /* MPP profile based */
+ mpp *mlu; /* Device -> XYZ */
+
+ /* Xcolorants model based */
+ icxColorantLu *clu; /* Device -> CIE */
+
+ rspl *nlin[MXTD - 3]; /* Perceptual linearisation for other chanels */
+ int e; /* Chanel being set */
+
+ /* Reverse lookup support */
+ double ilimit; /* Ink limit (scale 1.0) */
+ double den[3]; /* Target density or Lab */
+ double uniform; /* NZ if target is uniform */
+ int kchan; /* Set to the K chanel (-1 if none) */
+
+}; typedef struct _pcpt pcpt;
+
+
+/* Absolute XYZ conversion function */
+/* Internal device values 0.0 - 1.0 are converted into XYZ values */
+/* (Used for downstream checking) */
+static void
+pcpt_to_XYZ(pcpt *s, double *out, double *in) {
+ int e;
+ double inv[MXTD];
+
+ if (s->xmask == s->nmask) {
+ for (e = 0; e < s->di; e++)
+ inv[e] = in[e];
+ } else {
+ for (e = 0; e < s->di; e++)
+ inv[e] = 1.0 - in[e];
+ }
+ if (s->luo2 != NULL)
+ s->luo2->lookup(s->luo2, out, inv);
+ else if (s->mlu != NULL)
+ s->mlu->lookup(s->mlu, out, inv);
+ else if (s->clu != NULL)
+ s->clu->dev_to_XYZ(s->clu, out, inv);
+ else { /* Linear conversion */
+ out[0] = 100.0 * inv[0];
+ out[1] = 100.0 * inv[1] - 50.0;
+ out[2] = 100.0 * inv[2] - 50.0;
+ icmLab2XYZ(&icmD50, out, out);
+ }
+}
+
+
+/* Relative Lab conversion function */
+/* Internal device values 0.0 - 1.0 are converted into Lab values */
+/* (Used for VRML visualisation checking) */
+static void
+pcpt_to_rLab(pcpt *s, double *out, double *in) {
+ int e;
+ double inv[MXTD];
+
+ if (s->xmask == s->nmask) {
+ for (e = 0; e < s->di; e++)
+ inv[e] = in[e];
+ } else {
+ for (e = 0; e < s->di; e++)
+ inv[e] = 1.0 - in[e];
+ }
+ if (s->luo != NULL)
+ s->luo->lookup(s->luo, out, inv);
+ else if (s->mlu != NULL) {
+ s->mlu->lookup(s->mlu, out, inv);
+ icmXYZ2Lab(&icmD50, out, out);
+ } else if (s->clu != NULL)
+ s->clu->dev_to_rLab(s->clu, out, inv);
+ else { /* Linear conversion */
+ out[0] = 100.0 * inv[0];
+ out[1] = 100.0 * inv[1] - 50.0;
+ out[2] = 100.0 * inv[2] - 50.0;
+ }
+}
+
+/* Perceptual conversion function */
+/* Internal device values 0.0 - 1.0 are converted into perceptually uniform 0.0 - 100.0 */
+static void
+pcpt_to_nLab(pcpt *s, double *out, double *in) {
+ int e;
+ double inv[MXTD];
+
+ if (s->xmask == s->nmask) {
+ for (e = 0; e < s->di; e++)
+ inv[e] = in[e];
+ } else {
+ for (e = 0; e < s->di; e++)
+ inv[e] = 1.0 - in[e];
+ }
+
+ /* If we have some sort of perceptual conversion */
+ if (s->luo != NULL || s->mlu != NULL || s->clu != NULL) {
+ double lab[3];
+
+ if (s->luo != NULL)
+ s->luo->lookup(s->luo, lab, inv);
+ else if (s->mlu != NULL) {
+ s->mlu->lookup(s->mlu, lab, inv);
+ icmXYZ2Lab(&icmD50, lab, lab);
+ } else
+ s->clu->dev_to_rLab(s->clu, lab, inv);
+
+#ifdef EMPH_NEUTRAL /* Emphasise neutral axis, like CIE94 does */
+ {
+ double c; /* Chromanance */
+
+ c = sqrt(lab[1] * lab[1] + lab[2] * lab[2]); /* Compute chromanance */
+
+// c = 2.6624 / (1.0 + 0.013 * c); /* Full strength scale factor */
+ c = 3.0 / (1.0 + 0.03 * c); /* Full strength scale factor */
+ c = 1.0 + s->nemph * (c - 1.0); /* Reduced strength scale factor */
+
+ lab[1] *= c; /* scale a & b */
+ lab[2] *= c;
+ }
+#endif
+ /* Copy Lab values to output */
+ for (e = 0; e < (s->di < 3 ? s->di : 3); e++)
+ out[e] = lab[e];
+
+ /* Lookup perceptual linearised auxiliary values */
+ for (e = 0; e < (s->di-3); e++) {
+ co cc;
+ cc.p[0] = inv[3 + e];
+ s->nlin[e]->interp(s->nlin[e], &cc);
+ out[3 + e] = cc.v[0];
+ }
+
+ } else {
+ /* Default linear in Device space */
+
+ for (e = 0; e < s->di; e++)
+ out[e] = 100.0 * inv[e];
+ if (e == 1 || e == 2)
+ out[e] -= 50.0; /* Make it Lab like */
+ }
+}
+
+
+/* Return the largest distance of the point outside the device gamut. */
+/* This will be 0 if inside the gamut, and > 0 if outside. */
+static double
+pcpt_in_dev_gamut(pcpt *s, double *d) {
+ int e;
+ int di = s->di;
+ double tt, dd = 0.0;
+ double ss = 0.0;
+ double id[MXTD];
+
+ if (s->xmask == s->nmask) {
+ for (e = 0; e < s->di; e++)
+ id[e] = d[e];
+ } else {
+ for (e = 0; e < s->di; e++)
+ id[e] = 1.0 - d[e];
+ }
+
+ for (e = 0; e < di; e++) {
+ ss += id[e];
+
+ tt = 0.0 - id[e];
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ tt = id[e] - 1.0;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ }
+ tt = ss - s->ilimit;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ return dd;
+}
+
+/* optimisation function to find device values */
+/* for a target density value. */
+static double efunc(void *edata, double p[]) {
+ pcpt *s = (pcpt *)edata;
+ int e, di = s->di;
+ double rv, xyz[3], den[4];
+
+//printf("~1 efunc got dev %f %f %f %f\n",p[0],p[1],p[2],p[3]);
+ pcpt_to_XYZ(s, xyz, p); /* Convert device to XYZ */
+//printf("~1 efunc got XYZ %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+ icx_XYZ2Tdens(den, xyz); /* Convert XYZ to approx statusT density */
+//printf("~1 efunc got density %f %f %f %f\n",den[0],den[1],den[2],den[3]);
+
+//printf("~1 efunc got in_dev_gamut %f\n",pcpt_in_dev_gamut(s, p));
+
+ /* Penalise for being out of gamut */
+ rv = 5000.0 * pcpt_in_dev_gamut(s, p);
+
+ /* Error to density target */
+ {
+ double ss = 0.0;
+ for (e = 0; e < 3; e++) {
+ double tt;
+ tt = s->den[e] - den[e];
+ ss += tt * tt;
+ }
+ rv += ss;
+//printf("~1 efunc target den %f %f %f, err = %f, toterr %f\n",s->den[0],s->den[1],s->den[2],ss, rv);
+ }
+
+ {
+ /* Minimise all channels beyond the */
+ /* (assumed) first primary 3, but don't count black. */
+ /* Minimise all channels except black if nchan >= 4 and uniform target */
+ double ss = 0.0;
+
+ for (e = 0; e < di; e++) {
+ double tt = 0.0;
+
+ if (di >= 4 && s->uniform && e < 3 && e != s->kchan)
+ tt = p[e]; /* Minimise primary non-black if uniform */
+// else if (!s->uniform && (e < 3 || e == s->kchan))
+// tt = p[e]; /* Minimise sum of primaries & black if uniform */
+ else if (e >= 3 && e != s->kchan)
+ tt = 3.0 * p[e]; /* Suppress non-primary, non-black */
+
+ ss += tt;
+ }
+ rv += 1.5 * ss * ss;
+//printf("~1 efunc sum err = %f, toterr %f\n",ss, rv);
+ }
+
+//printf("~1 returning %f\n",rv);
+ return rv;
+}
+
+/* Given target CMY densities, return a suitable device value */
+static void
+pcpt_den_to_dev(pcpt *s, double *out, double *in) {
+ int e, di = s->di;
+ double tt, sr[MXTD]; /* Search radius */
+
+//printf("\n");
+//printf("~1 targen density = %f %f %f\n",in[0],in[1],in[2]);
+//printf("~1 di = %d, ilimit = %f\n",s->di,s->ilimit);
+
+ for (e = 0; e < 3; e++)
+ s->den[e] = in[e];
+
+ for (e = 0; e < di; e++) {
+ sr[e] = 0.5; /* Device space search radius */
+ out[e] = 0.5;
+ }
+
+ if (fabs(in[0] - in[1]) < 0.1
+ && fabs(in[0] - in[2]) < 0.1
+ && fabs(in[1] - in[2]) < 0.1) {
+ s->uniform = 1;
+//printf("~1 uniform set\n");
+ } else
+ s->uniform = 0;
+
+ if (powell(&tt, di, out, sr, 0.0001, 2000, efunc, (void *)s, NULL, NULL) != 0 || tt >= 50000.0) {
+ error("targen: powell failed, tt = %f\n",tt);
+ }
+
+ /* Filter out silly values */
+ for (e = 0; e < di; e++) {
+ if (out[e] < 0.001)
+ out[e] = 0.0;
+ else if (out[e] > 0.999)
+ out[e] = 1.0;
+ }
+//printf("~1 returning device values %f %f %f\n",out[0],out[1],out[2]);
+}
+
+/* Optimisation function to find device values */
+/* for a target Lab value. */
+static double efunc2(void *edata, double p[]) {
+ pcpt *s = (pcpt *)edata;
+ int e, di = s->di;
+ double rv, lab[3];
+
+//printf("~1 efunc2 got dev %f %f %f %f\n",p[0],p[1],p[2],p[3]);
+//printf("~1 efunc2 got dev %f %f %f %f %f %f\n",p[0],p[1],p[2],p[3],p[4],p[5]);
+
+ pcpt_to_rLab(s, lab, p); /* Convert device to rLab */
+//printf("~1 efunc2 got Lab %f %f %f\n",lab[0],lab[1],lab[2]);
+
+//printf("~1 efunc2 got in_dev_gamut %f\n",pcpt_in_dev_gamut(s, p));
+
+ /* Penalise for being out of gamut */
+ rv = 5000.0 * pcpt_in_dev_gamut(s, p);
+
+ /* Error to Lab target */
+ {
+ double ss = 0.0;
+ for (e = 0; e < 3; e++) {
+ double tt;
+ tt = s->den[e] - lab[e];
+ ss += tt * tt;
+ }
+ rv += ss;
+//printf("~1 efunc2 target Lab %f %f %f, err = %f, toterr %f\n",s->den[0],s->den[1],s->den[2],ss, rv);
+ }
+
+ {
+ int f;
+
+ /* Minimise all channels except K, and especially any */
+ /* beyond the first primary 3 or 4. */
+ double ss = 0.0;
+
+ if ((s->nmask & ICX_CMYK) == ICX_CMYK)
+ f = 4;
+ else
+ f = 3;
+ for (e = 0; e < di; e++) {
+ if (e >= f)
+ ss += 10.0 * p[e]; /* Suppress non-primary */
+ else if (e < 3)
+ ss += 0.05 * p[e]; /* Suppress first 3 primary slightly */
+ }
+ rv += ss * ss;
+//printf("~1 efunc2 sum err = %f, toterr %f\n",ss, rv);
+ }
+
+//printf("~1 efunc2 returning %f\n\n",rv);
+ return rv;
+}
+
+/* Given target Lab densities, return a suitable device value */
+static void
+pcpt_rLab_to_dev(pcpt *s, double *out, double *in) {
+ int e, di = s->di;
+ double tt, sr[MXTD]; /* Search radius */
+
+//printf("\n");
+//printf("#######################3\n");
+//printf("~1 targen Lab = %f %f %f\n",in[0],in[1],in[2]);
+//printf("~1 di = %d, ilimit = %f\n",s->di,s->ilimit);
+
+ for (e = 0; e < 3; e++)
+ s->den[e] = in[e];
+
+ for (e = 0; e < di; e++) {
+ sr[e] = 0.5; /* Device space search radius */
+ out[e] = 0.5;
+ }
+
+ if (powell(&tt, di, out, sr, 0.0001, 2000, efunc2, (void *)s, NULL, NULL) != 0 || tt >= 50000.0) {
+ error("targen: powell failed, tt = %f\n",tt);
+ }
+
+ /* Filter out silly values */
+ for (e = 0; e < di; e++) {
+ if (out[e] <= 0.02)
+ out[e] = 0.0;
+ else if (out[e] >= 0.98)
+ out[e] = 1.0;
+ }
+//printf("~1 returning device values %f %f %f\n",out[0],out[1],out[2]);
+}
+
+/* Callback to setup s->nlin[e] mapping */
+static void set_nlin(void *cbntx, double *out, double *in) {
+ pcpt *s = (pcpt *)cbntx; /* Object we're setting up from */
+ int e, di = s->di;
+ double dev[MXTD];
+ double lab[3];
+
+ /* Just input extra channel into perceptual type lookup */
+ if (s->xmask == s->nmask) {
+ for (e = 0; e < di; e++)
+ dev[e] = 0.0;
+ dev[3 + s->e] = in[0];
+ } else { /* Fake RGB */
+ for (e = 0; e < di; e++)
+ dev[e] = 1.0;
+ dev[3 + s->e] = 1.0 - in[0];
+ }
+
+ if (s->luo != NULL) {
+ s->luo->lookup(s->luo, lab, dev);
+ } else if (s->mlu != NULL) {
+ s->mlu->lookup(s->mlu, lab, dev);
+ icmXYZ2Lab(&icmD50, lab, lab);
+ } else if (s->clu != NULL) {
+ s->clu->dev_to_rLab(s->clu, lab, dev);
+ } else {
+ lab[0] = 100.0 * in[0];
+ }
+
+ /* ~~~ should we make this delta lab along locus, rather than L value ??? */
+ out[0] = lab[0];
+}
+
+/* Is a specific model, not default */
+int pcpt_is_specific(pcpt *s) {
+ if (s->luo2 != NULL || s->mlu != NULL)
+ return 1;
+ return 0;
+}
+
+/* Free the pcpt */
+static void pcpt_del(pcpt *s) {
+
+ if (s != NULL) {
+ int e;
+
+ if (s->luo != NULL) {
+ s->luo->del(s->luo);
+ s->luo2->del(s->luo2);
+ s->icco->del(s->icco);
+ s->fp->del(s->fp);
+ }
+ if (s->mlu != NULL) {
+ s->mlu->del(s->mlu);
+ }
+ if (s->clu != NULL) {
+ s->clu->del(s->clu);
+ }
+ for (e = 0; e < (s->di-3); e++) {
+ if (s->nlin[e] != NULL)
+ s->nlin[e]->del(s->nlin[e]);
+ }
+
+ free(s);
+ }
+}
+
+/* Create a pcpt conversion class */
+pcpt *new_pcpt(
+char *profName, /* ICC or MPP profile path, NULL for default, "none" for linear */
+inkmask xmask, /* external xcolorants mask */
+inkmask nmask, /* internal xcolorants mask */
+double *ilimit, /* ink sum limit (scale 1.0) input and return, -1 if default */
+double *uilimit, /* underlying ink sum limit (scale 1.0) input and return, -1 if default */
+double nemph /* Neutral emphasis, 0.0 - 1.0. < 0.0 for default == CIE94 */
+) {
+ int e;
+ pcpt *s;
+
+ if ((s = (pcpt *)calloc(1, sizeof(pcpt))) == NULL) {
+ fprintf(stderr,"targen: malloc failed allocating pcpt object\n");
+ exit(-1);
+ }
+
+ /* Initialise methods */
+ s->del = pcpt_del;
+ s->is_specific = pcpt_is_specific;
+ s->dev_to_perc = pcpt_to_nLab;
+ s->dev_to_XYZ = pcpt_to_XYZ;
+ s->dev_to_rLab = pcpt_to_rLab;
+ s->den_to_dev = pcpt_den_to_dev;
+ s->rLab_to_dev = pcpt_rLab_to_dev;
+
+ s->xmask = xmask;
+ s->nmask = nmask;
+ s->di = icx_noofinks(nmask);
+
+ if (nemph < 0.0)
+ nemph = NEMPH_DEFAULT;
+ s->nemph = nemph;
+
+ /* See if we have a profile */
+ if (profName != NULL
+ && profName[0] != '\000'
+ && strcmp(profName, "none") != 0
+ && strcmp(profName, "NONE") != 0) {
+ int rv = 0;
+
+ /* Try and open the file as an ICC profile */
+ if ((s->fp = new_icmFileStd_name(profName,"r")) == NULL)
+ error ("Can't open device profile '%s'",profName);
+
+
+ if ((s->icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ if ((rv = s->icco->read(s->icco,s->fp,0)) == 0) {
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ xcal *cal = NULL; /* Device calibration curves */
+
+ /* Get a conversion object for relative Lab */
+ if ((s->luo = s->icco->get_luobj(s->icco, icmFwd, icRelativeColorimetric,
+ icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((s->luo = s->icco->get_luobj(s->icco, icmFwd, icmDefaultIntent,
+ icSigLabData, icmLuOrdNorm)) == NULL) {
+ error ("%d, %s",s->icco->errc, s->icco->err);
+ }
+ }
+
+ /* Get a conversion object for absolute XYZ */
+ if ((s->luo2 = s->icco->get_luobj(s->icco, icmFwd, icAbsoluteColorimetric,
+ icSigXYZData, icmLuOrdNorm)) == NULL) {
+ if ((s->luo2 = s->icco->get_luobj(s->icco, icmFwd, icmDefaultIntent,
+ icSigXYZData, icmLuOrdNorm)) == NULL) {
+ error ("%d, %s",s->icco->errc, s->icco->err);
+ }
+ }
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ s->luo->spaces(s->luo, &ins, NULL, &outs, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ if (icx_colorant_comb_match_icc(xmask, ins) == 0) {
+ s->luo->del(s->luo);
+ error("ICC profile doesn't match device!");
+ }
+
+ /* Grab any device calibration curves */
+ cal = xiccReadCalTag(s->icco);
+
+ /* Set the default ink limits if not set by user */
+ if (*ilimit < 0.0) {
+
+ if (cal != NULL) {
+ *ilimit = s->icco->get_tac(s->icco, NULL, xiccCalCallback, (void *)cal);
+ *uilimit = s->icco->get_tac(s->icco, NULL, NULL, NULL);
+ } else {
+ *uilimit = *ilimit = s->icco->get_tac(s->icco, NULL, NULL, NULL);
+ }
+ *ilimit += 0.1; /* + 10% */
+ *uilimit += 0.1; /* + 10% */
+
+ /* Convert the user limit to a maximum underlying limit */
+ } else if (cal != NULL && *ilimit < (double)s->di) {
+ *uilimit = icxMaxUnderlyingLimit(cal, *ilimit);
+ }
+
+ } else { /* Not a valid ICC */
+ /* Close out the ICC profile */
+ s->icco->del(s->icco);
+ s->icco = NULL;
+ s->fp->del(s->fp);
+ s->fp = NULL;
+ }
+
+ /* If we don't have an ICC lookup object, look for an MPP */
+ if (s->luo == NULL) {
+ inkmask imask;
+ double dlimit = 0.0;
+
+ if ((s->mlu = new_mpp()) == NULL)
+ error ("Creation of MPP object failed");
+
+ if ((rv = s->mlu->read_mpp(s->mlu, profName)) != 0)
+ error ("%d, %s",rv,s->mlu->err);
+
+ s->mlu->get_info(s->mlu, &imask, NULL, &dlimit, NULL, NULL, NULL, NULL, NULL);
+
+ if (xmask != imask) {
+ s->mlu->del(s->mlu);
+ error("MPP profile doesn't match device!");
+ }
+ if (*ilimit < 0.0 && dlimit > 0.0) {/* If not user specified, use MPP inklimit */
+ *uilimit = *ilimit = dlimit + 0.1;
+ }
+ }
+ }
+
+ /* Fall back on an xcolorants model */
+ if (s->luo == NULL
+ && s->mlu == NULL
+ && strcmp(profName, "none") != 0
+ && strcmp(profName, "NONE") != 0) {
+ if ((s->clu = new_icxColorantLu(xmask)) == NULL)
+ error ("Creation of xcolorant lu object failed");
+ }
+ /* else leave pointers NULL */
+
+ if (*ilimit < 0.0)
+ s->ilimit = (double)s->di; /* Default to no limit */
+ else
+ s->ilimit = *ilimit/100.0;
+
+ if (s->di > 1)
+ s->kchan = icx_ink2index(xmask, ICX_BLACK);
+ else
+ s->kchan = -1;
+
+ /* Create extra chanel linearisation lookups */
+ for (e = 0; e < (s->di-3); e++) {
+ double inmin = 0.0, inmax = 1.0;
+ double outmax = 100.0;
+ int gres = 256;
+
+ if ((s->nlin[e] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL)
+ error("RSPL creation failed");
+
+ s->e = e; /* Chanel to set */
+ s->nlin[e]->set_rspl(s->nlin[e], 0, s, set_nlin,
+ &inmin, &inmax, &gres, &inmax, &outmax);
+ }
+
+ return s;
+}
+
+/* ------------------------------------ */
+
+void
+usage(int level, char *diag, ...) {
+ int i;
+ fprintf(stderr,"Generate Target deviceb test chart color values, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: targen [options] outfile\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr," Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr," -v [level] Verbose mode [optional level 1..N]\n");
+ fprintf(stderr," -d col_comb choose colorant combination from the following:\n");
+ for (i = 0; ; i++) {
+ char *desc;
+ if (icx_enum_colorant_comb(i, &desc) == 0)
+ break;
+ fprintf(stderr," %d: %s\n",i,desc);
+ }
+ fprintf(stderr," -D colorant Add or delete colorant from combination:\n");
+ if (level == 0)
+ fprintf(stderr," (Use -?? to list known colorants)\n");
+ else {
+ fprintf(stderr," %d: %s\n",0,"Additive");
+ for (i = 0; ; i++) {
+ char *desc;
+ if (icx_enum_colorant(i, &desc) == 0)
+ break;
+ fprintf(stderr," %d: %s\n",i+1,desc);
+ }
+ }
+ fprintf(stderr," -G Generate good optimized points rather than Fast\n");
+ fprintf(stderr," -e patches White test patches (default 4)\n");
+ fprintf(stderr," -s steps Single channel steps (default grey 50, color 0)\n");
+ fprintf(stderr," -g steps Grey axis RGB or CMY steps (default 0)\n");
+ fprintf(stderr," -m steps Multidimensional device space cube steps (default 0)\n");
+ fprintf(stderr," -f patches Add iterative & adaptive full spread patches to total (default grey 0, color 836)\n");
+ fprintf(stderr," Default is Optimised Farthest Point Sampling (OFPS)\n");
+ fprintf(stderr," -t Use incremental far point for full spread\n");
+ fprintf(stderr," -r Use device space random for full spread\n");
+ fprintf(stderr," -R Use perceptual space random for full spread\n");
+ fprintf(stderr," -q Use device space-filling quasi-random for full spread\n");
+ fprintf(stderr," -Q Use perceptual space-filling quasi-random for full spread\n");
+ fprintf(stderr," -i Use device space body centered cubic grid for full spread\n");
+ fprintf(stderr," -I Use perceptual space body centered cubic grid for full spread\n");
+ fprintf(stderr," -a angle Simplex grid angle 0.0 - 0.5 for B.C.C. grid, default %f\n",DEFANGLE);
+ fprintf(stderr," -A adaptation Degree of adaptation of OFPS 0.0 - 1.0 (default 0.1, -c profile used 1.0)\n");
+/* Research options: */
+/* fprintf(stderr," -A pPERCWGHT Device (0.0) ... Perceptual (1.0) weighting\n"); */
+/* fprintf(stderr," -A cCURVEWGHT Curvature weighting 0.0 = none ... "); */
+ fprintf(stderr," -l ilimit Total ink limit in %% (default = none)\n");
+ fprintf(stderr," -p power Optional power-like value applied to all device values.\n");
+ fprintf(stderr," -c profile Optional device ICC or MPP pre-conditioning profile filename\n");
+ fprintf(stderr," (Use \"none\" to turn off any conditioning)\n");
+ fprintf(stderr," -N emphasis Degree of neutral axis patch concentration 0.0-1.0 (default %.2f)\n",NEMPH_DEFAULT);
+ fprintf(stderr," -F L,a,b,rad Filter out samples outside Lab sphere.\n");
+#ifdef VRML_DIAG
+ fprintf(stderr," -w Dump diagnostic outfilel.wrl file (Lab locations)\n");
+ fprintf(stderr," -W Dump diagnostic outfiled.wrl file (Device locations)\n");
+#endif /* VRML_DIAG */
+ fprintf(stderr," outfile Base name for output(.ti1)\n");
+ exit(1);
+}
+
+/* Test if outside filter sphere. Return nz if it is */
+int dofilt(
+ pcpt *pdata, /* Perceptual conversion routine */
+ double *filt, /* Filter sphere definition */
+ double *dev /* Device values to check */
+) {
+ int i;
+ double Lab[3], rr;
+ pdata->dev_to_rLab(pdata, Lab, dev);
+ for (rr = 0.0, i = 0; i < 3; i++) {
+ double tt = Lab[i] - filt[i];
+ rr += tt * tt;
+ }
+ if (rr > (filt[3] * filt[3])) {
+//printf("~1 rejecting rad %f of %f %f %f <=> %f %f %f\n",sqrt(rr),Lab[0],Lab[1],Lab[2],filt[0],filt[1],filt[2]);
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ int i, j, k;
+ int fa, nfa, mfa; /* current argument we're looking at */
+ int verb = 0; /* Verbose flag */
+#ifdef VRML_DIAG
+ int dumpvrml = 0; /* Dump diagnostic .wrl file */
+#endif /* VRML_DIAG */
+ inkmask xmask = 0; /* External ink mask combination */
+ inkmask nmask = 0; /* Working ink mask combination (ie. CMY for printer external sRGB) */
+ int di = 0; /* Output dimensions */
+ char *ident; /* Ink combination identifier (includes possible leading 'i') */
+ int good = 0; /* 0 - fast, 1 = good */
+ int esteps = 4; /* White color patches */
+ int ssteps = -1; /* Single channel steps */
+ double xpow = 1.0; /* Power to apply to all device values created */
+ int gsteps = 0; /* Composite grey wedge steps */
+ int msteps = 0; /* Regular grid multidimensional steps */
+ int fsteps = -1; /* Fitted Multidimensional patches */
+ int uselat = 0; /* Use incremental far point alg. for full spread points */
+ int userand = 0; /* Use random for full spread points, 2 = perceptual */
+ int useqrand = 0; /* Use sobol for full spread points, 2 = perceptual */
+ int usedsim = 0; /* Use device space simplex grid */
+ int usepsim = 0; /* Use perceptual space simplex grid */
+ double simangle = DEFANGLE; /* BCC grid angle */
+ double dadapt = -2.0; /* Degree of iterative adaptation */
+ double perc_wght = 0.0; /* Perceptual weighting */
+ double curv_wght = 0.0; /* Curvature weighting */
+ double ilimit = -1.0; /* Ink limit (scale 1.0) (default none) */
+ double uilimit = -1.0; /* Underlying (pre-calibration, scale 1.0) ink limit */
+ double nemph = NEMPH_DEFAULT;
+ int filter = 0; /* Filter values */
+ double filt[4] = { 50,0,0,0 };
+ static char fname[MAXNAMEL+1] = { 0 }; /* Output file base name */
+ static char pname[MAXNAMEL+1] = { 0 }; /* Device profile name */
+ static char wdname[MAXNAMEL+1] = { 0 }; /* Device diagnostic .wrl name */
+ static char wlname[MAXNAMEL+1] = { 0 }; /* Lab diagnostic .wrl name */
+ char buf[500]; /* Genaral use text buffer */
+ int id = 1; /* Sample ID */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats *pp; /* cgats structure */
+ long stime,ttime;
+ pcpt *pdata; /* Space linearisation callback struct */
+ fxpos *fxlist = NULL; /* Fixed point list for full spread */
+ int fxlist_a = 0; /* Fixed point list allocation */
+ int fxno = 0; /* The number of fixed points */
+
+#ifdef NUMSUP_H
+ error_program = "targen";
+#endif
+ check_if_not_interactive();
+
+ if (argc <= 1)
+ usage(0,"Too few arguments, got %d expect at least %d",argc-1,1);
+
+ /* Process the arguments */
+ mfa = 1; /* Minimum final arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1+mfa) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?' || argv[fa][1] == '-') {
+ if (argv[fa][2] == '?' || argv[fa][2] == '-')
+ usage(1, "Extended usage requested");
+ usage(0, "Usage requested");
+ }
+
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ if (na != NULL && na[0] >= '0' && na[0] <= '9') {
+ verb = atoi(na);
+ fa = nfa;
+ }
+ }
+
+ /* Select the ink enumeration */
+ else if (argv[fa][1] == 'd') {
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -d");
+ i = atoi(na);
+ if (i == 0 && na[0] != '0')
+ usage(0,"Expect number argument after -d");
+ if ((xmask = icx_enum_colorant_comb(i, NULL)) == 0)
+ usage(0,"Argument to -d is not recognized");
+ }
+ /* Toggle the colorant in ink combination */
+ else if (argv[fa][1] == 'D') {
+ int tmask;
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -D");
+ i = atoi(na);
+ if (i == 0 && na[0] != '0')
+ usage(0,"Expect number argument after -D");
+ if (i == 0)
+ tmask = ICX_ADDITIVE;
+ else
+ if ((tmask = icx_enum_colorant(i-1, NULL)) == 0)
+ usage(0,"Argument to -D is not recognized");
+ xmask ^= tmask;
+ }
+ /* Good rather than fast */
+ else if (argv[fa][1] == 'G') {
+ good = 1;
+ }
+ /* White color patches */
+ else if (argv[fa][1] == 'e' || argv[fa][1] == 'E') {
+ int tt;
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -e");
+ if ((tt = atoi(na)) >= 0)
+ esteps = tt;
+ }
+ /* Individual chanel steps */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ int tt;
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -s");
+ if ((tt = atoi(na)) >= 0)
+ ssteps = tt;
+ }
+ /* RGB or CMY grey wedge steps */
+ else if (argv[fa][1] == 'g') {
+ int tt;
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -g");
+ if ((tt = atoi(na)) >= 0)
+ gsteps = tt;
+ }
+ /* Multidimentional cube steps */
+ else if (argv[fa][1] == 'm') {
+ int tt;
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -m");
+ if ((tt = atoi(na)) >= 0) {
+ msteps = tt;
+ if (msteps == 1)
+ msteps = 2;
+ }
+ }
+ /* Full even spread Multidimentional patches */
+ else if (argv[fa][1] == 'f') {
+ int tt;
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -f");
+ if ((tt = atoi(na)) >= 0)
+ fsteps = tt;
+ }
+
+ /* Use incremental far point algorithm for full spread */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ uselat = 1;
+ userand = 0;
+ useqrand = 0;
+ usedsim = 0;
+ usepsim = 0;
+ }
+
+ /* Random requested */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ uselat = 0;
+ if (argv[fa][1] == 'R')
+ userand = 2;
+ else
+ userand = 1;
+ useqrand = 0;
+ usedsim = 0;
+ usepsim = 0;
+ }
+
+ /* Space filling quasi-random requested */
+ else if (argv[fa][1] == 'q' || argv[fa][1] == 'Q') {
+ uselat = 0;
+ userand = 0;
+ if (argv[fa][1] == 'Q')
+ useqrand = 2;
+ else
+ useqrand = 1;
+ usedsim = 0;
+ usepsim = 0;
+ }
+
+
+ /* Device simplex grid requested */
+ else if (argv[fa][1] == 'i') {
+ uselat = 0;
+ userand = 0;
+ useqrand = 0;
+ usedsim = 1;
+ usepsim = 0;
+ }
+
+ /* Perceptual simplex grid requested */
+ else if (argv[fa][1] == 'I') {
+ uselat = 0;
+ userand = 0;
+ useqrand = 0;
+ usedsim = 0;
+ usepsim = 1;
+ }
+
+ /* Simplex grid angle */
+ else if (argv[fa][1] == 'a') {
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -a");
+ simangle = atof(na);
+ }
+
+ /* Degree of iterative adaptation */
+ else if (argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage(0,"Expected argument to average deviation flag -A");
+ if (na[0] == 'p') { /* (relative, for verification) */
+ perc_wght = atof(na+1);
+ if (perc_wght < 0.0 || perc_wght > 1.0)
+ usage(0,"Perceptual weighting argument %f to '-Ap' must be between 0.0 and 1.0",perc_wght);
+ dadapt = -1.0;
+ } else if (na[0] == 'c') { /* (absolute, for testing) */
+ curv_wght = atof(na+1);
+ if (curv_wght < 0.0 || curv_wght > 100.0)
+ usage(0,"Curvature weighting argument %f to '-Ac' must be between 0.0 and 100.0",curv_wght);
+ dadapt = -1.0;
+ } else {
+ dadapt = atof(na);
+ if (dadapt < 0.0 || dadapt > 1.0)
+ usage(0,"Average Deviation argument %f must be between 0.0 and 1.0",dadapt);
+ }
+ }
+
+ /* Ink limit percentage */
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') {
+ double tt;
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -l");
+ if ((tt = atof(na)) > 0.0)
+ uilimit = ilimit = 0.01 * tt;
+ }
+
+ /* Extra device power-like to use */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ double tt;
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -p");
+ if ((tt = atof(na)) > 0.0)
+ xpow = tt;
+ }
+
+ /* ICC profile for perceptual linearisation */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -c");
+ strncpy(pname,na,MAXNAMEL-1); pname[MAXNAMEL-1] = '\000';
+ }
+
+ /* Degree of neutral axis emphasis */
+ else if (argv[fa][1] == 'N') {
+ fa = nfa;
+ if (na == NULL) usage(0,"Expected argument to neutral emphasis flag -N");
+ nemph = atof(na);
+ if (nemph < 0.0 || nemph > 10.0)
+ usage(0,"Neautral weighting argument %f to '-N' is out of range",nemph);
+ }
+
+ /* Filter out samples outside given sphere */
+ else if (argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage(0,"Expect argument after -F");
+ if (sscanf(na, " %lf,%lf,%lf,%lf ",&filt[0], &filt[1], &filt[2], &filt[3]) != 4)
+ usage(0,"Argument to -F '%s' isn't correct",na);
+ filter = 1;
+ }
+
+#ifdef VRML_DIAG
+ else if (argv[fa][1] == 'w') /* Lab */
+ dumpvrml |= 1;
+ else if (argv[fa][1] == 'W') /* Device */
+ dumpvrml |= 2;
+#endif /* VRML_DIAG */
+ else
+ usage(0,"Unknown flag '%c'",argv[fa][1]);
+ }
+ else
+ break;
+ }
+
+ /* Get the file name argument */
+ if (fa >= argc || argv[fa][0] == '-') usage(0,"Expect file base name argument");
+ strncpy(fname,argv[fa],MAXNAMEL-4); fname[MAXNAMEL-4] = '\000';
+ strcat(fname,".ti1");
+
+ strncpy(wdname,argv[fa],MAXNAMEL-5); wdname[MAXNAMEL-5] = '\000';
+ strcat(wdname,"d.wrl");
+
+ strncpy(wlname,argv[fa],MAXNAMEL-5); wlname[MAXNAMEL-5] = '\000';
+ strcat(wlname,"l.wrl");
+
+ /* Set default colorant combination as CMYK */
+ if (xmask == 0)
+ xmask = ICX_CMYK;
+
+ nmask = xmask;
+
+ /* Deal with fake printer RGB, where we use CMY internally and invert all */
+ /* the resulting device values. */
+ if (xmask & ICX_INVERTED) {
+ if (xmask != ICX_IRGB)
+ error("Don't know how to deal with inverted colorant combination 0x%x\n",xmask);
+ nmask = ICX_CMY; /* Internally treat it as CMY and invert the result */
+ }
+
+ ident = icx_inkmask2char(xmask, 1);
+ di = icx_noofinks(nmask); /* Lookup number of dimensions */
+ stime = clock();
+
+ /* Implement some defaults */
+ if (di == 1) {
+ if (ssteps < 0)
+ ssteps = 50;
+ if (fsteps < 0)
+ fsteps = 0;
+ } else {
+ if (ssteps < 0) /* Defaults */
+ ssteps = 0;
+ if (fsteps < 0)
+ fsteps = 836;
+ }
+
+ /* Do some sanity checking */
+ if (di == 1) {
+ if (ssteps == 0 && fsteps == 0 && msteps == 0)
+ error ("Must have some Gray steps");
+ if (gsteps > 0) {
+ warning ("Composite grey steps ignored for monochrome output");
+ gsteps = 0;
+ }
+ } else if (di == 3) {
+ if (ssteps == 0 && fsteps == 0 && msteps == 0 && gsteps == 0)
+ error ("Must have some single or multi dimensional RGB or CMY steps");
+ } else {
+ if (ssteps == 0 && fsteps == 0 && msteps == 0 && gsteps == 0)
+ error ("Must have some single or multi dimensional steps");
+ }
+
+ /* Deal with ICC, MPP or fallback profile */
+ if ((pdata = new_pcpt(pname, xmask, nmask, &ilimit, &uilimit, nemph)) == NULL) {
+ error("Perceptual lookup object creation failed");
+ }
+
+ /* Set default adapation level */
+ if (dadapt < -1.5) { /* Not set by user */
+ if (pname[0] != '\000')
+ dadapt = 1.0;
+ else
+ dadapt = 0.1;
+ }
+
+ if (verb) {
+ printf("%s test chart\n",ident);
+
+ if (ssteps > 0)
+ printf("Single channel steps = %d\n",ssteps);
+ if (gsteps > 0)
+ printf("Compostie Grey steps = %d\n",gsteps);
+ if (fsteps > 0)
+ printf("Full spread patches = %d\n",fsteps);
+ if (msteps > 0)
+ printf("Multi-dimention cube steps = %d\n",msteps);
+ if (ilimit >= 0.0)
+ printf("Ink limit = %.1f%% (underlying %.1f%%)\n",ilimit * 100.0, uilimit * 100.0);
+ if (filter) {
+ printf("Filtering out samples outside sphere at %f %f %f radius %f\n",
+ filt[0], filt[1], filt[2], filt[3]);
+ }
+ }
+ pp = new_cgats(); /* Create a CGATS structure */
+ pp->add_other(pp, "CTI1"); /* our special type is Calibration Target Information 1 */
+
+ pp->add_table(pp, tt_other, 0); /* Add the first table for target points */
+ pp->add_table(pp, tt_other, 0); /* Add the second table for density pre-defined device values */
+ pp->add_table(pp, tt_other, 0); /* Add the second table for device pre-defined device values */
+ pp->add_kword(pp, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 1",NULL);
+ pp->add_kword(pp, 1, "DESCRIPTOR", "Argyll Calibration Target chart information 1",NULL);
+ pp->add_kword(pp, 2, "DESCRIPTOR", "Argyll Calibration Target chart information 1",NULL);
+ pp->add_kword(pp, 0, "ORIGINATOR", "Argyll targen", NULL);
+ pp->add_kword(pp, 1, "ORIGINATOR", "Argyll targen", NULL);
+ pp->add_kword(pp, 2, "ORIGINATOR", "Argyll targen", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ pp->add_kword(pp, 0, "CREATED",atm, NULL);
+
+ /* Make available the aproximate white point to allow relative */
+ /* interpretation of the aproximate XYZ values */
+ {
+ int e;
+ double val[MXTD], XYZ[3];
+
+ /* Setup device white */
+ if (nmask & ICX_ADDITIVE)
+ for (e = 0; e < di; e++)
+ val[e] = 1.0;
+ else
+ for (e = 0; e < di; e++)
+ val[e] = 0.0;
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Lookup white XYZ */
+
+ sprintf(buf,"%f %f %f", 100.0 * XYZ[0], 100.0 * XYZ[1], 100.0 * XYZ[2]);
+ pp->add_kword(pp, 0, "APPROX_WHITE_POINT", buf, NULL);
+ }
+
+ pp->add_field(pp, 0, "SAMPLE_ID", cs_t);
+ pp->add_field(pp, 1, "INDEX", i_t); /* Index no. 0..7 in second table */
+ pp->add_field(pp, 2, "INDEX", i_t); /* Index no. 0..7 in third table */
+
+ /* Setup CGATS fields */
+ {
+ int j;
+ char c_ilimit[20];
+ char *bident = icx_inkmask2char(xmask, 0);
+
+ for (j = 0; j < di; j++) {
+ int imask;
+ char fname[100];
+
+ imask = icx_index2ink(xmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ pp->add_field(pp, 0, fname, r_t);
+ pp->add_field(pp, 1, fname, r_t);
+ pp->add_field(pp, 2, fname, r_t);
+ }
+
+ pp->add_kword(pp, 0, "COLOR_REP", ident, NULL);
+
+ if (ilimit >= 0.0) {
+ sprintf(c_ilimit,"%5.1f",ilimit * 100.0);
+ pp->add_kword(pp, 0, "TOTAL_INK_LIMIT", c_ilimit, NULL);
+ }
+ free(bident);
+ }
+
+ /* ilimit is assumed to be in a valid range from here on */
+ if (ilimit < 0.0) {
+ uilimit = ilimit = di; /* default is no limit */
+ }
+
+ /* Add expected XYZ values to aid previews, scan recognition & strip recognition */
+ pp->add_field(pp, 0, "XYZ_X", r_t);
+ pp->add_field(pp, 0, "XYZ_Y", r_t);
+ pp->add_field(pp, 0, "XYZ_Z", r_t);
+ pp->add_field(pp, 1, "XYZ_X", r_t);
+ pp->add_field(pp, 1, "XYZ_Y", r_t);
+ pp->add_field(pp, 1, "XYZ_Z", r_t);
+ pp->add_field(pp, 2, "XYZ_X", r_t);
+ pp->add_field(pp, 2, "XYZ_Y", r_t);
+ pp->add_field(pp, 2, "XYZ_Z", r_t);
+
+ /* Note if the expected values are expected to be accurate */
+ if (pdata->is_specific(pdata))
+ pp->add_kword(pp, 0, "ACCURATE_EXPECTED_VALUES", "true", NULL);
+
+ if (xpow != 1.0) {
+ sprintf(buf,"%f",xpow);
+ pp->add_kword(pp, 0, "EXTRA_DEV_POW",buf, NULL);
+ }
+
+ /* Only use optimsed full spread if <= 4 dimensions, else use ifarp */
+ if (di > 4
+ && userand == 0 /* Not other high D useful method */
+ && useqrand == 0
+ && usedsim == 0
+ && usepsim == 0)
+ uselat = 1;
+
+ /* Allocate space to record fixed steps */
+ {
+ fxlist_a = 4;
+ if ((fxlist = (fxpos *)malloc(sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+
+ /* White color patches */
+ if (esteps > 0) {
+ int j, e;
+
+ sprintf(buf,"%d",esteps);
+ pp->add_kword(pp, 0, "WHITE_COLOR_PATCHES",buf, NULL);
+
+ for (j = 0; j < esteps; j++) {
+ double val[MXTD], XYZ[3];
+ cgats_set_elem ary[1 + MXTD + 3];
+
+ if (nmask & ICX_ADDITIVE) {
+ for (e = 0; e < di; e++) {
+ val[e] = 1.0; /* White is full colorant */
+ }
+ } else {
+ for (e = 0; e < di; e++) {
+ val[e] = 0.0; /* White is no colorant */
+ }
+ }
+
+ /* Apply general filter */
+ if (filter && dofilt(pdata, filt, val))
+ continue;
+
+ sprintf(buf,"%d",id++);
+ ary[0].c = buf;
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * icx_powlike(val[e],xpow);
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - icx_powlike(val[e],xpow));
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 0, ary);
+
+ if (fxlist != NULL) { /* Note in fixed list */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (e = 0; e < di; e++)
+ fxlist[fxno].p[e] = val[e];
+ fxno++;
+ }
+ }
+ }
+
+ /* Primary wedge steps */
+ if (ssteps > 0) {
+ sprintf(buf,"%d",ssteps);
+ pp->add_kword(pp, 0, "SINGLE_DIM_STEPS",buf, NULL);
+ for (j = 0; j < di; j++) {
+ for (i = 0; i < ssteps; i++) {
+ int addp, e;
+ double val[MXTD], XYZ[3];
+ cgats_set_elem ary[1 + MXTD + 3];
+
+ addp = 1; /* Default add the point */
+
+ for (e = 0; e < di; e++) {
+ if (e == j)
+ val[e] = (double)i/(ssteps-1);
+ else
+ val[e] = 0.0;
+ }
+
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+
+ /* See if it is already in the fixed list */
+ if (fxlist != NULL) {
+ int k;
+ for (k = 0; k < fxno; k++) {
+ for (e = 0; e < di; e++) {
+ double tt;
+ tt = fabs(fxlist[k].p[e] - val[e]);
+ if (tt > MATCH_TOLL)
+ break; /* Not identical */
+ }
+ if (e >= di)
+ break; /* Was identical */
+ }
+ if (k < fxno) /* Found an identical patch */
+ addp = 0; /* Don't add the point */
+ }
+
+ /* Apply general filter */
+ if (filter && dofilt(pdata, filt, val))
+ addp = 0;
+
+ if (addp) {
+
+ sprintf(buf,"%d",id++);
+ ary[0].c = buf;
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * icx_powlike(val[e],xpow);
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - icx_powlike(val[e],xpow));
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 0, ary);
+
+ if (fxlist != NULL) { /* Note in fixed list */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (e = 0; e < di; e++)
+ fxlist[fxno].p[e] = val[e];
+ fxno++;
+ }
+ }
+ }
+ }
+ }
+
+ /* Composite gray wedge steps */
+ if (gsteps > 0) {
+ int cix[3]; /* Composite indexes */
+
+ sprintf(buf,"%d",gsteps);
+ pp->add_kword(pp, 0, "COMP_GREY_STEPS",buf, NULL);
+
+ if (nmask & ICX_ADDITIVE) { /* Look for the RGB */
+ cix[0] = icx_ink2index(nmask, ICX_RED);
+ cix[1] = icx_ink2index(nmask, ICX_GREEN);
+ cix[2] = icx_ink2index(nmask, ICX_BLUE);
+
+ } else { /* Look for the CMY */
+ cix[0] = icx_ink2index(nmask, ICX_CYAN);
+ cix[1] = icx_ink2index(nmask, ICX_MAGENTA);
+ cix[2] = icx_ink2index(nmask, ICX_YELLOW);
+ }
+ if (cix[0] < 0 || cix[1] < 0 || cix[2] < 0)
+ error("Composite grey wedges aren't appropriate for %s device\n",ident);
+
+ for (i = 0; i < gsteps; i++) {
+ int addp, e;
+ double sum, val[MXTD], XYZ[3];
+ cgats_set_elem ary[1 + MXTD + 3];
+
+ addp = 1; /* Default add the point */
+
+ for (e = 0; e < di; e++) {
+ if (e == cix[0] || e == cix[1] || e == cix[2])
+ val[e] = (double)i/(gsteps-1);
+ else
+ val[e] = 0.0;
+ }
+
+ /* Apply general filter */
+ if (filter && dofilt(pdata, filt, val))
+ addp = 0;
+
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+
+ /* Compute sum that includes affect of power */
+ for (sum = 0.0, e = 0; e < di; e++)
+ sum += icx_powlike(val[e], xpow);
+
+ if (sum > uilimit)
+ addp = 0;
+
+ /* See if it is already in the fixed list */
+ if (fxlist != NULL) {
+ int k;
+ for (k = 0; k < fxno; k++) {
+ for (e = 0; e < di; e++) {
+ double tt;
+ tt = fabs(fxlist[k].p[e] - val[e]);
+ if (tt > MATCH_TOLL)
+ break; /* Not identical */
+ }
+ if (e >= di)
+ break; /* Was identical */
+ }
+ if (k < fxno) /* Found an identical patch */
+ addp = 0; /* Don't add the point */
+ }
+
+ if (addp) {
+
+ sprintf(buf,"%d",id++);
+ ary[0].c = buf;
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * icx_powlike(val[e],xpow);
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - icx_powlike(val[e],xpow));
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 0, ary);
+
+ if (fxlist != NULL) { /* Note in fixed list */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (e = 0; e < di; e++)
+ fxlist[fxno].p[e] = val[e];
+ fxno++;
+ }
+ }
+ }
+ }
+
+ /* Regular Gridded Multi dimension steps */
+ if (msteps > 0) {
+ int gc[MXTD]; /* Grid coordinate */
+
+ sprintf(buf,"%d",msteps);
+ pp->add_kword(pp, 0, "MULTI_DIM_STEPS",buf, NULL);
+
+ for (j = 0; j < di; j++)
+ gc[j] = 0; /* init coords */
+
+ for (;;) { /* For all grid points */
+ double sum, val[MXTD], XYZ[3];
+ int addp, e;
+
+ addp = 1; /* Default add the point */
+
+ for (e = 0; e < di; e++)
+ val[e] = (double)gc[e]/(msteps-1);
+
+ /* Apply general filter */
+ if (filter && dofilt(pdata, filt, val))
+ addp = 0;
+
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+
+ /* Compute sum that includes affect of power */
+ for (sum = 0.0, e = 0; e < di; e++)
+ sum += icx_powlike(val[e], xpow);
+
+ if (sum > uilimit)
+ addp = 0; /* Don't add patches over ink limit */
+
+ /* See if it is already in the fixed list */
+ if (addp && fxlist != NULL) {
+ int k;
+ for (k = 0; k < fxno; k++) {
+ for (e = 0; e < di; e++) {
+ double tt;
+ tt = fabs(fxlist[k].p[e] - val[e]);
+ if (tt > MATCH_TOLL)
+ break; /* Not identical */
+ }
+ if (e >= di)
+ break; /* Was identical */
+ }
+ if (k < fxno) /* Found an identical patch */
+ addp = 0; /* Don't add the point */
+ }
+
+ /* Add patch to list if OK */
+ if (addp) {
+ cgats_set_elem ary[1 + MXTD + 3];
+
+ sprintf(buf,"%d",id++);
+ ary[0].c = buf;
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * icx_powlike(val[e],xpow);
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - icx_powlike(val[e],xpow));
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 0, ary);
+
+ if (fxlist != NULL) { /* Note in fixed list */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (e = 0; e < di; e++)
+ fxlist[fxno].p[e] = val[e];
+ fxno++;
+ }
+ }
+
+ next_cpoint:;
+ /* Increment grid index and position */
+ for (j = 0; j < di; j++) {
+ gc[j]++;
+ if (gc[j] < msteps)
+ break; /* No carry */
+ gc[j] = 0;
+ }
+ if (j >= di)
+ break; /* Done grid */
+ }
+
+#ifdef ADDRECCLIPPOINTS
+ /* Add extra points that intersect */
+ /* grid, and lie on ink limit plane */
+ /* !!!!!!!!!! this doesn't cope with xpow !!!!!!!!!!! */
+ if (uilimit < (di * 100.0)) {
+ double val[MXTD], tv;
+ double XYZ[3];
+ for (k = 0; k < di; k++) { /* dimension not on grid */
+ for (j = 0; j < di; j++)
+ gc[j] = 0; /* init coords */
+
+ for (;;) { /* Until done */
+ for (tv = 0.0, j = 0; j < di; j++) {
+ if (j != k)
+ tv += val[j] = (double)gc[j]/(msteps-1);
+ }
+ if (tv <= uilimit && (tv + 1.0) >= uilimit) { /* Will intersect */
+ double fr;
+ val[k] = uilimit - tv; /* Point of intersection */
+ fr = fmod((val[k] * msteps), 1.0);
+ if (fr > 0.05 && fr < 0.95) { /* Not within 5% of a grid point */
+ int addp, e;
+ cgats_set_elem ary[1 + MXTD + 3];
+
+ addp = 1; /* Default add the point */
+
+ /* See if it is already in the fixed list */
+ if (fxlist != NULL) {
+ int k;
+ for (k = 0; k < fxno; k++) {
+ for (e = 0; e < di; e++) {
+ double tt;
+ tt = fabs(fxlist[k].p[e] - val[e]);
+ if (tt > MATCH_TOLL)
+ break; /* Not identical */
+ }
+ if (e >= di)
+ break; /* Was identical */
+ }
+ if (k < fxno) { /* Found an identical patch */
+ addp = 0; /* Don't add the point */
+ }
+ }
+
+ /* Apply general filter */
+ if (filter && dofilt(pdata, filt, val)) {
+ addp = 0;
+ }
+
+ if (addp) {
+ sprintf(buf,"%d",id++);
+ ary[0].c = buf;
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * icx_powlike(val[e],xpow);
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - icx_powlike(val[e],xpow));
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 0, ary);
+
+ if (fxlist != NULL) { /* Note in fixed list */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (e = 0; e < di; e++)
+ fxlist[fxno].p[e] = val[e];
+ fxno++;
+ }
+ }
+ }
+ }
+
+ /* Increment grid index and position */
+ for (j = 0; j < di; j++) {
+ gc[j]++;
+ if (j != k && gc[j] < msteps)
+ break; /* No carry */
+ gc[j] = 0;
+ }
+ if (j >= di)
+ break; /* ALL done */
+ }
+ }
+ }
+#endif /* ADDRECCLIPPOINTS */
+ }
+
+ if (fsteps > fxno) { /* Top up with full spread (perceptually even) and other patch types */
+
+ /* Generate device random numbers. Don't check for duplicates */
+ if (userand == 1 || useqrand == 1) {
+ int i, j;
+ sobol *sl = NULL;
+
+ if (useqrand) {
+ if ((sl = new_sobol(di)) == NULL)
+ error("Creating sobol sequence generator failed");
+ }
+
+ /* Create more points up to fsteps */
+ if (verb)
+ printf("\n");
+ for (j = 0, i = fxno; i < fsteps;) {
+ int e;
+ double sum;
+ double val[MXTD], XYZ[3];
+ cgats_set_elem ary[1 + MXTD + 3];
+
+ if (sl != NULL) {
+ if (sl->next(sl, val))
+ error("Run out of sobol random numbers!");
+ } else { /* else uniform random distribution */
+ for (e = 0; e < di; e++)
+ val[e] = d_rand(0.0, 1.0);
+ }
+
+ /* Apply general filter */
+ if (filter && dofilt(pdata, filt, val))
+ continue;
+
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+
+ /* Compute sum that includes the affect of power */
+ for (sum = 0.0, e = 0; e < di; e++)
+ sum += icx_powlike(val[e], xpow);
+
+ if (sum > uilimit)
+ continue;
+
+ sprintf(buf,"%d",id++);
+ ary[0].c = buf;
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * icx_powlike(val[e],xpow);
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - icx_powlike(val[e],xpow));
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 0, ary);
+
+ if (fxlist != NULL) { /* Note in fixed list to allow stats later */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (e = 0; e < di; e++)
+ fxlist[fxno].p[e] = val[e];
+ fxno++;
+ }
+
+ if (verb) {
+ printf("%cAdded %d/%d",cr_char,i+1,fxno); fflush(stdout);
+ }
+ i++, j++;
+ }
+ if (verb)
+ printf("\n");
+
+ sprintf(buf,"%d",j);
+ if (sl != NULL)
+ pp->add_kword(pp, 0, "SPACEFILLING_RANDOM_PATCHES", buf, NULL);
+ else
+ pp->add_kword(pp, 0, "RANDOM_DEVICE_PATCHES", buf, NULL);
+
+ if (sl != NULL)
+ sl->del(sl);
+
+ } else {
+// ppoint *s = NULL;
+ ofps *s = NULL;
+ ifarp *t = NULL;
+ simdlat *dx = NULL;
+ simplat *px = NULL;
+ prand *rx = NULL;
+
+ /* (Note that the ink limit for these algorithms won't take into account the xpow), */
+ /* and that we're not applying the filter until after generation, so the */
+ /* number of patches won't reach the target. This could be fixed fairly easily */
+ /* for some of these (new_prand). */
+ if (uselat) {
+ /* A "greedy"/incremental far point approach */
+ t = new_ifarp(di, uilimit, fsteps, fxlist, fxno,
+ (void(*)(void *, double *, double *))pdata->dev_to_perc, (void *)pdata);
+ sprintf(buf,"%d",fsteps - fxno);
+ pp->add_kword(pp, 0, "IFP_PATCHES", buf, NULL);
+ } else if (usedsim) {
+ /* Device space simplex latice test points */
+ dx = new_simdlat(di, uilimit, fsteps, fxlist, fxno, SIMDLAT_TYPE, simangle,
+ (void(*)(void *, double *, double *))pdata->dev_to_perc, (void *)pdata);
+ sprintf(buf,"%d",fsteps - fxno);
+ pp->add_kword(pp, 0, "SIMPLEX_DEVICE_PATCHES", buf, NULL);
+ } else if (usepsim) {
+ /* Perceptual space simplex latice test points */
+ px = new_simplat(di, uilimit, fsteps, fxlist, fxno, simangle,
+ (void(*)(void *, double *, double *))pdata->dev_to_perc, (void *)pdata);
+ sprintf(buf,"%d",fsteps - fxno);
+ pp->add_kword(pp, 0, "SIMPLEX_PERCEPTUAL_PATCHES", buf, NULL);
+ } else if (userand == 2 || useqrand == 2) {
+ /* Perceptual random test points */
+ rx = new_prand(di, uilimit, fsteps, fxlist, fxno, useqrand == 2 ? 1 : 0,
+ (void(*)(void *, double *, double *))pdata->dev_to_perc, (void *)pdata);
+ sprintf(buf,"%d",fsteps - fxno);
+ pp->add_kword(pp, 0, "RANDOM_PERCEPTUAL_PATCHES", buf, NULL);
+
+ } else { /* Default full spread algorithm */
+ /* Optimised Farthest Point Sampling */
+ s = new_ofps(verb, di, uilimit, fsteps, good,
+ dadapt, 1.0 - perc_wght, perc_wght, curv_wght, fxlist, fxno,
+ (void(*)(void *, double *, double *))pdata->dev_to_perc, (void *)pdata);
+ sprintf(buf,"%d",fsteps - fxno);
+ pp->add_kword(pp, 0, "OFPS_PATCHES", buf, NULL);
+ }
+
+
+ for (;;) {
+ int e;
+ double XYZ[3], val[MXTD];
+ cgats_set_elem ary[1 + MXTD + 3];
+ if (( s ? s->read(s, val, NULL) :
+ t ? t->read(t, val, NULL) :
+ dx ? dx->read(dx, val, NULL) :
+ rx ? rx->read(rx, val, NULL) :
+ px->read(px, val, NULL)))
+ break;
+
+ /* Filter out silly values from ppoint */
+ for (e = 0; e < di; e++) {
+ if (val[e] < 0.001)
+ val[e] = 0.0;
+ else if (val[e] > 0.999)
+ val[e] = 1.0;
+ }
+
+ /* Apply general filter */
+ if (filter && dofilt(pdata, filt, val))
+ continue;
+
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+
+ /* Do a simple ink limit that include the effect of xpow */
+ if (uilimit < (double)di) {
+ double tot = 0.0;
+ for (e = 0; e < di; e++)
+ tot += icx_powlike(val[e],xpow);
+ if (tot > uilimit) {
+ for (e = 0; e < di; e++)
+ val[e] = icx_powlike(icx_powlike(val[e],xpow) * uilimit/tot, 1.0/xpow);
+ }
+ }
+
+ sprintf(buf,"%d",id++);
+ ary[0].c = buf;
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * icx_powlike(val[e],xpow);
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - icx_powlike(val[e],xpow));
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 0, ary);
+
+ if (fxlist != NULL) { /* Note in fixed list to allow stats later */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (e = 0; e < di; e++)
+ fxlist[fxno].p[e] = val[e];
+ fxno++;
+ }
+ }
+ (s ? s->del(s) : t ? t->del(t) : dx ? dx->del(dx) : rx ? rx->del(rx) : px->del(px));
+ }
+ }
+
+ /* Use ofps to measure the stats of the points */
+ /* Note that if new_ofps() fails it will exit() */
+ if (verb > 1
+ && di <= 4
+ && (userand || useqrand || usedsim || usepsim || uselat)) {
+ ofps *s;
+ printf("Computing device space point stats:\n");
+ if ((s = new_ofps(verb, di, uilimit, fxno, 0, 0.0, 0.0, 0.0, 0.0, fxlist, fxno,
+ (void(*)(void *, double *, double *))pdata->dev_to_perc, (void *)pdata)) == NULL) {
+ printf("Failed to compute stats\n");
+ } else {
+ s->stats(s);
+ printf("Max distance stats: Min = %f, Average = %f, Max = %f\n",s->mn,s->av,s->mx);
+ s->del(s);
+ }
+ }
+
+ /* Add the eight entries in the second table. */
+ /* These are legal device values that we think may */
+ /* give all combinations of min/max CMY density values. */
+ /* These are typically used for DTP51 and DTP41 patch separators. */
+ {
+ int i;
+
+ pp->add_kword(pp, 1, "DENSITY_EXTREME_VALUES", "8", NULL);
+
+ for (i = 0; i < 8; i++) {
+ int e;
+ double den[4], val[MXTD], XYZ[3];
+ cgats_set_elem ary[1 + MXTD + 3];
+
+ /* Setup target density combination */
+ for (e = 0; e < 3; e++) {
+ if (i & (1 << e))
+ den[e] = 2.5;
+ else
+ den[e] = -0.5;
+ }
+
+ /* Lookup device values for target density */
+ pdata->den_to_dev(pdata, val, den);
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+
+ /* Apply extra power */
+ for (e = 0; e < di; e++)
+ val[e] = icx_powlike(val[e], xpow);
+
+ /* Do a simple ink limit */
+ if (uilimit < (double)di) {
+ double tot = 0.0;
+ for (e = 0; e < di; e++)
+ tot += val[e];
+ if (tot > uilimit) {
+ for (e = 0; e < di; e++)
+ val[e] *= uilimit/tot;
+ }
+ }
+
+ ary[0].i = i;
+
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * val[e];
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - val[e]);
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 1, ary);
+
+ }
+ }
+
+ /* Add the nine entries in the third table. */
+ /* These are legal device values that we calculate */
+ /* give all combinations of typical CMY device values + 50% CMY */
+ /* These are typically use for DTP20 bar coding. */
+ {
+ int i;
+
+ icxColorantLu *ftarg = NULL;
+
+ /* If not possible to use native space, use fake CMY */
+ if ((nmask & ICX_CMYK) != ICX_CMYK
+ && (nmask & ICX_CMY) != ICX_CMY
+ && (nmask & ICX_RGB) != ICX_RGB) {
+ if ((ftarg = new_icxColorantLu(ICX_CMY)) == NULL)
+ error ("Creation of xcolorant lu object failed");
+ }
+
+ pp->add_kword(pp, 2, "DEVICE_COMBINATION_VALUES", "9", NULL);
+
+ for (i = 0; i < 9; i++) {
+ int e;
+ double val[MXTD], lab[3], XYZ[3];
+ cgats_set_elem ary[1 + MXTD + 3];
+
+ for (e = 0; e < di; e++)
+ val[e] = 0.0;
+
+ /* Setup target device combination */
+ /* Order must be White, Cyan, Magenta, Blue Yellow Green Red Black */
+ if (ftarg != NULL || (nmask & ICX_CMY) == ICX_CMY) {
+ for (e = 0; e < 3; e++) {
+ if (i & (1 << e))
+ val[e] = 1.0;
+ else
+ val[e] = 0.0;
+ }
+ if (i == 7)
+ val[3] = 1.0;
+ if (i == 8) { /* Special 50/50/50 grey for DTP20 */
+ val[0] = val[1] = val[2] = 0.5;
+ val[3] = 0.0;
+ }
+
+ } else { /* RGB like */
+ for (e = 0; e < 3; e++) {
+ if (i & (1 << e))
+ val[e] = 0.0;
+ else
+ val[e] = 1.0;
+ }
+ if (i == 8)
+ val[0] = val[1] = val[2] = 0.5;
+ }
+
+ /* If target space isn't something we recognise, convert it */
+ if (ftarg != NULL) {
+ ftarg->dev_to_rLab(ftarg, lab, val);
+ pdata->rLab_to_dev(pdata, val, lab);
+ }
+
+ pdata->dev_to_XYZ(pdata, XYZ, val); /* Add expected XYZ */
+
+ /* Apply extra power */
+ for (e = 0; e < di; e++)
+ val[e] = icx_powlike(val[e], xpow);
+
+ /* Do a simple ink limit */
+ if (uilimit < (double)di) {
+ double tot = 0.0;
+ for (e = 0; e < di; e++)
+ tot += val[e];
+ if (tot > uilimit) {
+ for (e = 0; e < di; e++)
+ val[e] *= uilimit/tot;
+ }
+ }
+
+ ary[0].i = i;
+ if (xmask == nmask) {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * val[e];
+ } else {
+ for (e = 0; e < di; e++)
+ ary[1 + e].d = 100.0 * (1.0 - val[e]);
+ }
+ ary[1 + di + 0].d = 100.0 * XYZ[0];
+ ary[1 + di + 1].d = 100.0 * XYZ[1];
+ ary[1 + di + 2].d = 100.0 * XYZ[2];
+
+ pp->add_setarr(pp, 2, ary);
+ }
+
+ if (ftarg != NULL)
+ ftarg->del(ftarg);
+ }
+
+ ttime = clock() - stime;
+ if (verb) {
+ printf("Total number of patches = %d\n",id-1);
+ if (id < (1 + (1 << di)))
+ printf("WARNING : not enough patches for %d channels, need at least %d\n",di,(1 + (1 << di)));
+ printf("Execution time = %f seconds\n",ttime/(double)CLOCKS_PER_SEC);
+ }
+
+ if (pp->write_name(pp, fname))
+ error("Write error : %s",pp->err);
+
+#ifdef VRML_DIAG /* Dump a VRML of the resulting points */
+ if (dumpvrml & 1) { /* Lab space */
+ vrml *wrl;
+ int nsets = pp->t[0].nsets;
+ double rad;
+ double dev[MXTD], Lab[3], col[3];
+
+ wrl = new_vrml(wlname, 1, 0); /* Do axes */
+
+ /* Fudge sphere diameter */
+ rad = 15.0/pow(nsets, 1.0/(double)(di <= 3 ? di : 3));
+
+ for (i = 0; i < nsets; i++) {
+ /* Re-do any inversion before using dev_to_rLab() */
+ if (xmask == nmask) {
+ for (j = 0; j < di; j++)
+ dev[j] = 0.01 * *((double *)pp->t[0].fdata[i][j + 1]);
+ } else {
+ for (j = 0; j < di; j++)
+ dev[j] = 0.01 * (100.0 - *((double *)pp->t[0].fdata[i][j + 1]));
+ }
+ pdata->dev_to_rLab(pdata, Lab, dev);
+ wrl->Lab2RGB(wrl, col, Lab);
+
+ wrl->add_marker(wrl, Lab, col, rad);
+ }
+ wrl->del(wrl); /* Write file and delete */
+ }
+ if (dumpvrml & 2) { /* Device space */
+ vrml *wrl;
+ int nsets = pp->t[0].nsets;
+ double rad;
+ double dev[MXTD], idev[MXTD], Lab[3], col[3];
+
+ wrl = new_vrml(wdname, 0, 0);
+
+ /* Fudge sphere diameter */
+ rad = 15.0/pow(nsets, 1.0/(double)(di <= 3 ? di : 3));
+
+ for (i = 0; i < nsets; i++) {
+ /* Re-do any inversion before using dev_to_rLab() */
+ if (xmask == nmask) {
+ for (j = 0; j < di; j++)
+ idev[j] = dev[j] = 0.01 * *((double *)pp->t[0].fdata[i][j + 1]);
+ } else {
+ for (j = 0; j < di; j++) {
+ dev[j] = 0.01 * *((double *)pp->t[0].fdata[i][j + 1]);
+ idev[j] = 1.0 - dev[j];
+ }
+ }
+ pdata->dev_to_rLab(pdata, Lab, idev);
+ wrl->Lab2RGB(wrl, col, Lab);
+
+ /* Fudge device locations into Lab space */
+ Lab[0] = 100.0 * dev[0];
+ Lab[1] = 100.0 * dev[1] - 50.0;
+ Lab[2] = 100.0 * dev[2] - 50.0;
+
+ wrl->add_marker(wrl, Lab, col, rad);
+ }
+ wrl->del(wrl); /* Write file and delete */
+ }
+#endif /* VRML_DIAG */
+
+ pdata->del(pdata); /* Cleanup perceptual conversion */
+
+ free(ident);
+ pp->del(pp); /* Clean up */
+ if (fxlist != NULL)
+ free(fxlist);
+
+ return 0;
+}
+
+
+
+
+
+
diff --git a/target/targen.h b/target/targen.h
new file mode 100644
index 0000000..2f4665a
--- /dev/null
+++ b/target/targen.h
@@ -0,0 +1,30 @@
+
+#ifndef TARGEN_H
+/*
+ * Argyll Color Correction System
+ * Test target chart Generator.
+ *
+ * Author: Graeme W. Gill
+ * Date: 7/4/2002
+ *
+ * Copyright 2002, 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.
+ */
+
+
+/* Targen generation common defines */
+
+#define MXTD ICX_MXINKS /* From xicc/xcolorants.h */
+
+/* A fixed point position */
+struct _fxpos {
+ double p[MXTD]; /* Device coordinate position */
+ double v[MXTD]; /* Room for perceptual value */
+}; typedef struct _fxpos fxpos;
+
+
+#define TARGEN_H
+#endif /* TARGEN_H */
diff --git a/tiff/COPYRIGHT b/tiff/COPYRIGHT
new file mode 100644
index 0000000..8282186
--- /dev/null
+++ b/tiff/COPYRIGHT
@@ -0,0 +1,21 @@
+Copyright (c) 1988-1997 Sam Leffler
+Copyright (c) 1991-1997 Silicon Graphics, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation for any purpose is hereby granted without fee, provided
+that (i) the above copyright notices and this permission notice appear in
+all copies of the software and related documentation, and (ii) the names of
+Sam Leffler and Silicon Graphics may not be used in any advertising or
+publicity relating to the software without the specific, prior written
+permission of Sam Leffler and Silicon Graphics.
+
+THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
diff --git a/tiff/ChangeLog b/tiff/ChangeLog
new file mode 100644
index 0000000..2411f2c
--- /dev/null
+++ b/tiff/ChangeLog
@@ -0,0 +1,4590 @@
+2010-06-15 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff 3.9.4 released.
+
+2010-06-13 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: avoid re-preparing jpeg tables unnecessarily
+ (gdal #3633, libtiff #2135).
+
+ * libtiff/tif_dirread.c: Fixed bad handling of out of order tags
+ definated late by a codec (#2210)
+
+ * libtiff/tif_dirread.c: Fixed inadequate validation of the
+ SubjectDistance field (#2212).
+
+ * tiff2pdf.c: Fix assorted bugs in tiff2pdf: missing "return"
+ in t2p_read_tiff_size() causes t2p->tiff_datasize to be set entirely
+ wrong for COMPRESSION_JPEG case, resulting in memory stomp if actual
+ size is larger. Also, there are a bunch of places that try to
+ memset() a malloc'd buffer before checking for malloc failure, which
+ would result in core dump if there actually were a failure. (#2211)
+
+2010-06-11 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiff2rgba.c: Applied portion of patch (from Tom Lane)
+ which was left out in order to fully resolve "CVE-2009-2347
+ libtiff: integer overflows in various inter-color space conversion
+ tools". http://bugzilla.maptools.org/show_bug.cgi?id=2079
+
+ * libtiff/tiffiop.h (TIFFSafeMultiply): Need more castings to
+ avoid compiler warnings if parameter types are not sign
+ consistent.
+
+ * tools/tiffcrop.c: Applied patch from Richard Nolde: Corrected
+ European page size dimensions. Added an option to allow the user
+ to specify a custom page size on the command line. Fix the case
+ where a page size specified with a fractional part was being
+ coerced to an integer by retyping the variables that define the
+ paper size.
+
+ * libtiff 3.9.3 released.
+
+ * tools/tiffcp.c (tiffcp): Applied Tom Lane's patch to reject
+ YCbCr subsampled data since tiffcp currently doesn't support it.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2097
+
+ * Update libtool to version 2.2.10.
+
+2010-06-10 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tiffiop.h (TIFFSafeMultiply): Work properly if
+ multiplier is zero.
+
+2010-06-09 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_dir.h: Restore ReferenceBlackWhite as a non-custom
+ field. This avoids a multi-thread reentrancy problem as well as
+ fixing output of wrong tag value due to redundant definitions for
+ the same tag in the tiffFieldInfo[] array. Resolves
+ http://bugzilla.maptools.org/show_bug.cgi?id=2185
+
+ * libtiff/tif_fax3.c (Fax3SetupState): Yesterday's fix for
+ CVE-2010-1411 was not complete.
+
+ * libtiff/tiffiop.h (TIFFSafeMultiply): New macro to safely
+ multiply two integers. Returns zero if there is an integer
+ overflow.
+
+ * tools/tiffcp.c (main): Fix more TIFF handle leaks.
+
+ * libtiff/tif_read.c (TIFFReadBufferSetup): Skip allocating
+ tif_rawdata if tif_rawdatasize becomes zero.
+
+2010-06-08 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiffcrop.c: Removed duplicated macros such as
+ TIFFhowmany().
+
+ * Update libtool to version 2.2.8.
+
+ * libtiff/tif_fax3.c (Fax3SetupState): Avoid under-allocation of
+ buffer due to integer overflow in TIFFroundup() and several other
+ potential overflows. In conjunction with the fix to TIFFhowmany(),
+ fixes CVE-2010-1411.
+
+ * libtiff/tiffiop.h (TIFFhowmany): Return zero if parameters would
+ result in an integer overflow. This causes TIFFroundup() to also
+ return zero if there would be an integer overflow.
+
+ * libtiff/tif_read.c (TIFFReadBufferSetup): Return an error if
+ tif_rawdatasize becomes zero due to an initial raw size of zero or
+ an overflow reported by TIFFroundup().
+
+ * libtiff/tif_ojpeg.c (OJPEGReadBufferFill): Report an error and
+ avoid a crash if the input file is so broken that the strip
+ offsets are not defined.
+
+ * tools/tiffcp.c (main): tiffcp should not leak memory if an error
+ is reported when reading the input file.
+
+ * libtiff/tif_aux.c (_TIFFCheckRealloc): Produce a fully detailed
+ error message string.
+
+ * Add an emacs formatting mode footer to all source files so that
+ emacs can be effectively used.
+
+2010-06-03 Oliver Chen Feng <scip8183@gmail.com>
+
+ * libtiff/tools/tiffcp.c: add a new option -x to force merged tiff
+ file PAGENUMBER value in sequence for users who care the page
+ sequence, this will also prevent tiff2pdf from creating pdf file from
+ the merged tiff file with wrong page sequence.
+
+2010-05-07 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: Ensure that quality is always set in
+ JPEGPreEncode(), not just when we want to output local tables.
+ Otherwise the quality used during compression may not be right and
+ might not match the tables in the tables tag. This bug only occurs
+ when seeking between directories in the midst of writing blocks.
+ http://trac.osgeo.org/gdal/ticket/3539
+
+2010-05-05 Olivier Paquet <olivier.paquet@gmail.com>
+
+ * libtiff/tif_print.c: Have TIFFTAG_REFERENCEBLACKWHITE always print 6
+ floats instead of 2*SamplesPerPixel.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2186
+ * man/TIFFGetField.3tiff, man/TIFFSetField.3tiff: Fixed doc to reflect the
+ fact that libtiff considers TIFFTAG_REFERENCEBLACKWHITE to be 6 floats.
+
+2010-04-10 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/ppm2tiff.c (main): While case for parsing comment line
+ requires extra parenthesis to work as expected. Reported by
+ Thomas Sinclair.
+
+2010-02-22 Lee Howard <faxguy@howardsilvan.com>
+
+ * libtiff/tif_jpeg.c: Do not generate a JPEGTables tag when creating
+ the JPEG TIFF as is is not required in order to prevent it from
+ being unused and filled with invalid data. (Leave it to be
+ generated by later activity.)
+ http://bugzilla.maptools.org/show_bug.cgi?id=2135
+ * tools/tiff2pdf.c: Write the JPEG SOI headers into the TIFF strip
+ data rather than skipping them. This fixes the ability to view in
+ Acrobat Reader, Evince, and Ghostscript.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2135
+ * libtiff/tif_fax3.c: Don't return error on badly-terminated MMR
+ strips.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2029
+
+2010-01-06 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dir.c: Ensure tile and scanline sizes are reset
+ when moving to new directories.
+ http://bugzilla.maptools.org/show_bug.cgi?id=1936
+
+2009-12-03 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: Fix a couple of issues that trigger failures in
+ some cases when using TIFFReadScanline() with JPEG compressed
+ subsampled ycbcr images.
+ http://bugzilla.maptools.org/show_bug.cgi?id=1936
+
+2009-11-04 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff 3.9.2 released.
+
+2009-11-03 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiffcrop.c: Updated tiffcrop from Richard Nolde. This
+ version has undergone substantial testing with arbitrary sample
+ bit depths. Also eliminates GCC compilation warnings.
+
+2009-11-02 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * port/libport.h: Added header file for porting prototypes and
+ extern declarations.
+
+2009-10-31 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_dirwrite.c (TIFFWriteAnyArray): Add missing break
+ statement so writing an array of TIFF_DOUBLE works.
+
+2009-10-29 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_dirread.c: Eliminate GCC "dereferencing type-punned
+ pointer" warnings.
+
+2009-10-28 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * html/tools.html: Add manual page links, and a summary
+ description of tiffcrop.
+
+2009-10-07 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * configure.ac: x86_64 should use the same fill order as i386.
+
+2009-09-24 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiffcrop.c, man/tiffcrop.1: New tiffcrop from Richard
+ Nolde. Major updates to add significant functionality for reading
+ and writing tile based images with bit depths not a multiple of 8
+ which cannot be handled by tiffcp.
+
+2009-09-03 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_ojpeg.c (OJPEGWriteHeaderInfo): IJG JPEG 7 needs
+ do_fancy_upsampling=FALSE in order to read raw data. Resolves
+ "Bug 2090 - OJPEG crash with libjpeg v7".
+ http://bugzilla.maptools.org/show_bug.cgi?id=2090
+
+2009-08-30 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * contrib/iptcutil/iptcutil.c,
+ libtiff/tif_getimage.c,libtiff/tif_jpeg.c,libtiff/tif_ojpeg.c,tools/tiffcrop.c,tools/tiffgt.c:
+ Applied patch from Oden Eriksson to allow building with GCC using
+ the "-Wformat -Werror=format-security" flags.
+
+2009-08-28 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff 3.9.1 released.
+
+2009-08-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirwrite.c: Back out changes from 2007-11-22 that
+ resulted in the final strip not being written in some circumstances.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2088
+
+2009-08-27 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_write.c (TIFFAppendToStrip): Remove cast which
+ caused libtiff to output a wrong last strip with byte-count and
+ strip-offset of zero. This cast was added on the day of the 3.9.0
+ release.
+
+ * libtiff/tif_config.vc.h: tiffiop.h needs the TIFF_INT64_T and
+ TIFF_UINT64_T defines in order to compile. Copy existing
+ definitions from tiffconf.vc.h.
+
+2009-08-21 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * test/Makefile.am (AUTOMAKE_OPTIONS): Colorized tests was not
+ actually activated since it needed to be enabled in this
+ Makefile.am. Also activated parallel-tests mode since it offers
+ useful features such as per-test .log files and a summary test
+ report .log file.
+
+2009-08-20 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff 3.9.0 released.
+
+ * libtiff/tif_print.c (TIFFPrintDirectory): Applied patch for "tag
+ error may cause segfault in tif_print.c."
+ http://bugzilla.maptools.org/show_bug.cgi?id=1896
+
+ * tools/{rgb2ycbcr.c, tiff2rgba.c}: Applied patch for
+ CVE-2009-2347 libtiff: integer overflows in various inter-color
+ space conversion tools.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2079
+
+ * configure.ac: Updated autotools. Autoconf 2.64, Automake 1.11,
+ libtool 2.2.6. Enabled support for silent build rules
+ (--enable-silent-rules or 'make V=0') and colorized tests.
+
+2009-06-30 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_luv.c: correct return codes from encoderow to be
+ 1 on success instead of zero.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2069
+
+2009-06-22 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_lzw.c: Fix buffer underflow bug.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2065
+
+2009-06-03 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_write.c: do not override the planar configuration to be
+ contig for one sample files if planar configuration is already set.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2057
+
+2009-02-12 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_luv.c: Fix handling of tiled logluv images.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2005
+
+2009-01-23 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_predict.c: Add support for 32bit integer horz. predictors.
+ http://bugzilla.maptools.org/show_bug.cgi?id=1911
+
+2009-01-20 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiffsplit.c: fix sampleformat to be shortv instead of longv.
+
+2009-01-12 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiff2ps.c: Remove spurious message printed to stderr.
+
+2009-01-11 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiff2ps.c: Incorporated significant functionality update
+ from Richard Nolde. In particular, support for rotating the image
+ by 90, 180, 270, and 'auto' has been added.
+
+ * tools/tiffcrop.c: Incorporated significant functionality update
+ from Richard Nolde.
+
+2009-01-06 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tiffiop.h: Add private type declarations for int64, and
+ uint64 so that bundled utilities (like tiffcrop) can use it when
+ necessary.
+
+2009-01-01 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * configure.ac: Updated to test for 64-bit types. This version of
+ the library does not require a 64-bit type, but tiffcrop needs it.
+
+2008-12-31 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * Update to use current FSF autotools versions.
+ * libtiff/tiffio.h: GCC will now validate format specifications
+ for TIFFError(), TIFFErrorExt(), TIFFWarning(), and
+ TIFFWarningExt() in order to reveal bugs. Cleaned up resulting
+ warnings throughout for 32 bit build only.
+
+2008-12-31 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiffcrop.c, man/tiffcrop.1: A major update from Richard
+ Nolde.
+
+2008-12-21 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: Avoid errors if the application writes a full
+ strip for the last partial strip in a jpeg compressed file.
+ http://bugzilla.maptools.org/show_bug.cgi?id=1981
+
+2008-12-21 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_getimage.c, tiffio.h: More ABI corrections.
+ Removed SubsamplingHor/Ver from TIFFRGBAImage structure.
+ http://bugzilla.maptools.org/show_bug.cgi?id=1980
+
+2008-12-18 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_getimage.c,tiffio.h: removed all use of UaToAa and
+ Bitmap16to8 arrays in TIFFRGBAImage structure to restore ABI
+ compatability. These were just an attempt to speed up processing
+ with precalculated tables.
+ http://bugzilla.maptools.org/show_bug.cgi?id=1979
+
+ * libtiff/tif_codec.c: Avoid printing c->name if it does not exist.
+
+2008-10-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_jbig.c: Support the JBIG-KIT 2.0 (compatibility with
+ the older versions retained).
+
+2008-09-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffsplit.c: Use dynamically allocated array instead of static
+ when constructing output file names.
+
+2008-09-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffsplit.c: Get rid of unsafe strcpy()/strcat() calls when
+ doing the filename/path construction.
+
+ * tools/tiff2pdf.c: More appropriate format string in
+ t2p_write_pdf_string(); avoid signed/unsigned mismatch.
+
+ * libtiff/tif_lzw.c: Properly zero out the codetable. As per bug
+
+ http://bugzilla.maptools.org/show_bug.cgi?id=1929
+
+ * libtiff/tif_lzw.c: Properly zero out the string table. Fixes
+ CVE-2008-2327 security issue.
+
+2008-05-24 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_codec.c: Avoid NULL pointer dereferencing for exotic
+ compression codec codes.
+
+ * tif_dirread.c: zero tif->tif_dir after freeing the directory
+ in TIFFReadCustomDirectory(). I don't exactly remember why this
+ was important.
+
+ * tif_dirwrite.c: Fix potential memory leak writing large double
+ tags.
+
+ * tif_dirread.c: Fix unchecked malloc result.
+
+2008-01-30 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tif_fax3.c: Make find0span() and find1span() non-inline to
+ make MSVC 6.0 compiler happy.
+
+2007-11-26 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_fax3.c: fix leak of FAXCS state (per bug 1603).
+
+2007-11-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.com, libtiff/tif_vms.c: Better OpenVMS support. Patches
+ from Alexey Chupahin.
+
+2007-11-22 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_write.c: Rip out the fancy logic in TIFFAppendToStrip() for
+ establishing if an existing tile can be rewritten to the same location
+ by comparing the current size to all the other blocks in the same
+ directory. This is dangerous in many situations and can easily
+ corrupt a file. (observed in esoteric GDAL situation that's hard to
+ document). This change involves leaving the stripbytecount[] values
+ unaltered till TIFFAppendToStrip(). Now we only write a block back
+ to the same location it used to be at if the new data is the same
+ size or smaller - otherwise we move it to the end of file.
+
+ * tif_dirwrite.c: Try to avoid writing out a full readbuffer of tile
+ data when writing the directory just because we have BEENWRITING at
+ some point in the past. This was causing odd junk to be written out
+ in a tile of data when a single tile had an interleaving of reading
+ and writing with reading last. (highlighted by gdal
+ autotest/gcore/tif_write.py test 7.
+
+ * tif_predict.c: use working buffer in PredictorEncodeTile to avoid
+ modifying callers buffer.
+ http://trac.osgeo.org/gdal/ticket/1965
+
+ * tif_predict.c/h, tif_lzw.c, tif_zip.c: Improvements so that
+ predictor based encoding and decoding works in read-write update
+ mode properly.
+ http://trac.osgeo.org/gdal/ticket/1948
+
+2007-10-05 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiff2pdf.c: Fixed setting of alpha value per report on list.
+
+2007-09-13 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_dirinfo.c: _TIFFMergeFields() now only merges in field
+ definitions that are missing. Existing definitions are silently
+ ignored. (Bug #1585)
+
+2007-07-18 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{Makefile.am, Makefile.v}: Do not distribute tiffconf.h,
+ remove tif_config.h/tiffconf.h during cleaning. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1573
+
+2007-07-13 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.9.0beta released.
+
+2007-07-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Added missed extern optind as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1567
+
+2007-07-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps.c: Added support 16-bit images as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1566
+
+ Patch from William Bader.
+
+ * tools/tiff2pdf.c: Fix for TIFFTAG_JPEGTABLES tag fetching and
+ significant upgrade of the whole utility as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1560
+
+ Now we don't need tiffiop.h in tiff2pdf anymore and will open output
+ PDF file using TIFFClientOpen() machinery as it is implemented
+ by Leon Bottou.
+
+2007-06-29 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_dirinfo.c (_TIFFFindFieldInfo): Don't attempt to
+ bsearch() on a NULL fieldinfo list.
+ (_TIFFFindFieldInfoByName): Don't attempt to
+ lfind() on a NULL fieldinfo list.
+
+2007-05-01 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirwrite.c: Fixed problem introduced with a fix for a
+ byte swapping issue
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1363
+
+ As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1550
+
+2007-04-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Check the tmpfile() return status as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=154
+
+2007-04-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dir.h, tif_dirread.c, tif_dirinfo.c, tif_jpeg.c,
+ tif_fax3.c, tif_jbig.c, tif_luv.c, tif_ojpeg.c, tif_pixarlog.c,
+ tif_predict.c, tif_zip.c}: Finally fix bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1274
+
+ by introducing _TIFFMergeFieldInfo() returning integer error status
+ instead of void in case of problems with field merging (e.g., if the
+ field with such a tag already registered). TIFFMergeFieldInfo() in
+ public API remains void. Use _TIFFMergeFieldInfo() everywhere and
+ check returned value.
+
+2007-04-07 Frank Warmerdam <warmerdam@pobox.com>
+
+ * contrib/addtiffo/tif_overview.c: Fix problems with odd sized output
+ blocks in TIFF_DownSample_Subsampled() (bug 1542).
+
+2007-04-06 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: Changed JPEGInitializeLibJPEG() so that it
+ will convert from decompressor to compressor or compress to decompress
+ if required by the force arguments. This works around a problem in
+ where the JPEGFixupTestSubsampling() may cause a decompressor to
+ be setup on a directory when later a compressor is required with the
+ force flag set. Occurs with the addtiffo program for instance.
+
+2007-04-06 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirwrite.c: Fixed swapping of byte arrays stored
+ in-place in tag offsets as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1363
+
+ * tools/tiffcrop.c, man/tiffcrop.1: Significant update in
+ functionality from Richard Nolde. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1525
+
+2007-03-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_fax3.c: "inline static" -> "static inline" for IRIC CC.
+
+2007-03-07 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_getimage.c: workaround for 'Fractional scanline' error reading
+ OJPEG images with rowsperstrip that is not a multiple of vertical subsampling
+ factor. This bug is mentioned in:
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1390
+ http://www.asmail.be/msg0054766825.html
+
+2007-03-07 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_win32.c: made inclusion of windows.h unconditional
+
+ * libtiff/tif_win32.c: replaced preprocessor indication for consiously
+ unused arguments by standard C indication for the same
+
+2007-02-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Use uint32 type instead of tsize_t in byte
+ counters in TIFFFetchData(). Should finally fix the issue
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=890
+
+2007-02-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffset.c: Properly handle tags with TIFF_VARIABLE writecount.
+ As per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1350
+
+ * libtiff/tif_dirread.c: Added special function to handle
+ SubjectDistance EXIF tag as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1362
+
+ * tools/tiff2pdf.c: Do not assume inches when the resolution units
+ do not specified. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1366
+
+ * tools/{tiffcp.c, tiffcrop.c}: Do not change RowsPerStrip value if
+ it was set as infinite. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1368
+
+ * tools/tiffcrop.c, man/tiffcrop.1: New tiffcrop utility contributed
+ by Richard Nolde. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1383
+
+2007-02-22 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: Workaround for incorrect TIFFs with
+ ExtraSamples == 999 produced by Corel Draw. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1490
+
+ * libtiff/{tif_dirread.c, tif_read.c}: Type of the byte counters
+ changed from tsize_t to uint32 to be able to work with data arrays
+ larger than 2GB. Fixes bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=890
+
+ Idea submitted by Matt Hancher.
+
+2007-01-31 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tif2rgba.c: This utility does not work properly on big-endian
+ architectures. It was fixed including the bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1149
+
+2007-01-15 Mateusz Loskot <mateusz@loskot.net>
+
+ * Submitted libtiff port for Windows CE platform
+ * libtiff/tif_config.wince.h: Added configuration header for WinCE.
+ * libtiff/tiffconf.wince.h: Ported old configuration header for WinCE.
+ * libtiff/tif_wince.c: Added WinCE-specific implementation of some
+ functons from tif_win32.c.
+ * libtiff/tif_win32.c: Disabled some functions already reimplemented in tif_wince.c.
+ * libtiff/tiffiop.h, port/lfind.c: Added conditional include of some
+ standard header files for Windows CE build.
+ * tools/tiffinfoce.c: Ported tiffinfo utility for Windows CE.
+
+2006-11-19 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_write.c: TIFFAppendToStrip() - clear sorted flag if
+ we move a strip.
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1359
+
+2006-10-13 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: More fixes for vulnerabilities, reported
+ in Gentoo bug ():
+
+ http://bugs.gentoo.org/show_bug.cgi?id=142383
+
+ * libtiff/contrib/dbs/xtiff/xtiff.c: Make xtiff utility compilable.
+ Though it is still far from the state of being working and useful.
+
+2006-10-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_fax3.c: Save the state of printdir codec dependent
+ method.
+
+ * libtiff/tif_jpeg.c: Save the state of printdir codec dependent method
+ as per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1273
+
+ * libtiff/tif_win32.c: Fixed problem with offset value manipulation
+ as per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1322
+
+ * libtiff/{tif_read.c, tif_jpeg.c, tif_dir.c}: More fixes for
+ vulnerabilities, reported in Gentoo bug ():
+
+ http://bugs.gentoo.org/show_bug.cgi?id=142383
+
+2006-09-28 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_fax3.c, tif_next.c, tif_pixarlog.c}: Fixed multiple
+ vulnerabilities, as per Gentoo bug ():
+
+ http://bugs.gentoo.org/show_bug.cgi?id=142383
+
+2006-09-27 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_lzw.c, libtiff/tif_zip.c: Fixed problems with mixing
+ encoding and decoding on the same read-write TIFF handle. The LZW
+ code can now maintain encode and decode state at the same time. The
+ ZIP code will switch back and forth as needed.
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=757
+
+2006-09-20 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff: Rename config.h.vc and tif_config.h.vc to config.vc.h and
+ tif_config.vc.h for easier identification by folks using an IDE.
+
+2006-07-25 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_msdos.c: Avoid handle leak for failed opens. c/o Thierry Pierron
+
+2006-07-19 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_dirwrite.c: take care not to flush out buffer of strip/tile
+ data in _TIFFWriteDirectory if TIFF_BEENWRITING not set. Relates
+ to bug report by Peng Gao with black strip at bottom of images.
+
+2006-07-12 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_dirwrite.c: make sure to use uint32 for wordcount in
+ TIFFWriteNormanTag if writecount is VARIABLE2 for ASCII fields.
+ It already seems to have been done for other field types. Needed
+ for "tiffset" on files with geotiff ascii text.
+
+2006-07-04 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * {configure.ac, libtiff/tif_config.h.vc, libtiff/tif_jbig.c}
+ (JBIGDecode): jbg_newlen is not available in older JBIG-KIT and
+ its use does not appear to be required, so use it only when it is
+ available.
+
+2006-06-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirinfo.c: Added missed EXIF tag ColorSpace (40961).
+
+ * libtiff/tif_dirread.c: Move IFD fetching code in the separate
+ function TIFFFetchDirectory() avoiding code duplication in
+ TIFFReadDirectory() and TIFFReadCustomDirectory().
+
+2006-06-19 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiff2pdf.c: Fix handling of -q values.
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=587
+
+2006-06-17 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_readdir.c: Added case in EstimateStripByteCounts() for tiled
+ files. Modified TIFFReadDirectory() to not invoke
+ EstimateStripByteCounts() for case where entry 0 and 1 are unequal
+ but one of them is zero.
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1204
+
+2006-06-08 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_open.c, tif_dirread.c, tiffiop.h}: Move IFD looping
+ checking code in the separate function TIFFCheckDirOffset().
+
+ * libtiff/tif_aux.c: Added _TIFFCheckRealloc() function.
+
+ * tools/tiffcmp.c: Fixed floating point comparison logic as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1191
+
+ * libtiff/tif_fax3.c: Fixed problems in fax decoder as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1194
+
+ * tools/tiff2pdf.c: Fixed buffer overflow condition in
+ t2p_write_pdf_string() as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1196
+
+2006-06-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * {configure, configure.ac, libtiff/tif_jbig.c, tools/tiffcp.c}: Added
+ support for JBIG compression scheme (34661 code) contributed by Lee
+ Howard. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=896
+
+ * configure, configure.ac: OJPEG support enabled by default.
+
+ * contrib/ojpeg/: Removed. New OJPEG support does not need this patch.
+
+2006-06-03 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/{tif_dirinfo.c, tif_print.c} : Fix crash in
+ TIFFPrintDirectory(). Joris Van Damme authored the fix.
+
+2006-04-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Unified line ending characters (always use '\n')
+ as per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1163
+
+ * README.vms, Makefile.am, configure.com, libtiff/{Makefile.am,
+ tif_config.h-vms, tif_stream.cxx, tif_vms.c, tiffconf.h-vms}:
+ Added support for OpenVMS by Alexey Chupahin, elvis_75@mail.ru.
+
+2006-04-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/{fax2ps.c, fax2tiff.c, ppm2tiff.c, ras2tiff.c, tiff2pdf.c}:
+ Properly set the binary mode for stdin stream as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1141
+
+ * man/{bmp2tiff.1, fax2ps.1, fax2tiff.1, gif2tiff.1, ras2tiff.1,
+ raw2tiff.1, rgb2ycbcr.1, sgi2tiff.1, tiff2bw.1, tiff2pdf.1, tiff2ps.1,
+ tiff2rgba.1, tiffcmp.1, tiffcp.1, tiffdither.1, tiffdump.1, tiffgt.1,
+ tiffset.1}: Improvements in page formatting as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1140
+
+ * html/tools.html, html/man/Makefile.am, tools/tiff2pdf.c: Fixed
+ typos as per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1139
+
+2006-04-18 Frank Warmerdam <warmerdam@pobox.com>
+
+ * nmake.opt: use /EHsc for VS2005 compatibility. Also define
+ _CRT_SECURE_NO_DEPRECATE to avoid noise on VS2005.
+
+2006-04-12 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_getimage.c: Added support for planarconfig separate
+ non-subsampled YCbCr (i.e. separate YCbCr with subsampling [1,1])
+
+2006-04-11 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_getimage.c: Revision of all RGB(A) put routines
+ - Conversion of unassociated alpha to associated alpha now done with
+ more performant LUT, and calculation more correct
+ - Conversion of 16bit data to 8bit data now done with
+ more performant LUT, and calculation more correct
+ - Bugfix of handling of 16bit RGB with unassociated alpha
+
+2006-04-11 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_getimage.c:
+ - When there is no alpha, gtTileSeparate and gtStripSeparate allocated
+ buffer for alpha strile and filled it, only to never read it back.
+ Removed allocation and fill.
+ - Minor rename of vars in gtTileSeparate and gtStripSeparate
+ anticipating planned functionality extension
+
+2006-04-08 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_getimage.c: renamed pickTileContigCase to PickContigCase
+ and pickTileSeparateCase to PickSeparateCase as both work on strips as
+ well
+
+ * libtiff/tif_getimage.c: moved img->get selection from
+ TIFFRGBAImageBegin into PickContigCase and PickSeparateCase to create
+ logical hook for planned functionality extension
+
+2006-04-08 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_ojpeg.c: resolved memory leak that was a consequence
+ of inappropriate use of jpeg_abort instead of jpeg_destroy
+
+2006-04-07 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_getimage.c: replaced usage of TIFFScanlineSize in
+ gtStripContig with TIFFNewScanlineSize so as to fix buggy behaviour
+ on subsampled images - this ought to get sorted when we feel brave
+ enough to replace TIFFScanlineSize alltogether
+
+ * libtiff/tif_ojpeg.c: fixed bug in OJPEGReadSkip
+
+2006-04-04 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tiffio.h: added new type tstrile_t
+
+ * libtiff/tif_dir.h: changed types of td_stripsperimage and td_nstrips
+ to new tstrile_t, types of td_stripoffset and td_stripbytecount to
+ toff_t*
+
+ * libtiff/tif_ojpeg.c: totally new implementation
+
+ * libtiff/tif_dirread.c: added several hacks to suit new support of
+ OJPEG
+
+ * libtiff/tif_getimage.c: removed TIFFTAG_JPEGCOLORMODE handling
+ of OJPEG images in favor of tif_getimage.c native handling of
+ YCbCr and desubsampling
+
+2006-03-29 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: JPEGVSetField() so that altering the photometric
+ interpretation causes the "upsampled" flag to be recomputed. Fixes
+ peculiar bug where photometric flag had to be set before jpegcolormode
+ flag.
+
+2006-03-25 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_jpeg.c: strip size related bugfix in encode raw
+
+ * libtiff/tif_strip.c: temporarilly added two new versions of
+ TIFFScanlineSize
+ - TIFFNewScanlineSize: proposed new version, after all related
+ issues and side-effects are sorted out
+ - TIFFOldScanlineSize: old version, from prior to 2006-03-21 change
+ This needs further sorting out.
+
+2006-03-25 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * contrib/addtiffo/tif_ovrcache.c: bugfix to correctly pass size
+ of last truncated strip data to TIFFWriteEncodedStrip
+
+2006-03-25 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/{tif_jpeg.c, tif_strip.c}: bugfix of tif_jpeg decode raw
+
+2006-03-25 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tif_getimage.c: bugfix/rewrite of putcontig8bitYCbCr22tile
+
+ * libtiff/tif_getimage.c: added putcontig8bitYCbCr12tile
+
+ * libtiff/tif_read.c: added support for new TIFF_NOREADRAW flag to
+ prepare the path for new tif_ojpeg.c
+
+2006-03-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.8.2 released.
+
+ * tools/Makefile.am: Use runtime paths linker flags when rpath
+ option enabled.
+
+2006-03-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/libtiff.def: Added missed exports as per bug
+ http://bugzilla.remotesensing.org/attachment.cgi?id=337
+
+ * contrib/addtiffo/Makefile.vc, libtiff/Makefile.vc, port/Makefile.vc,
+ tools/Makefile.vc: Makefiles improvements as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1128
+
+ * nmake.opt libtiff/{tif_config.h.vc, tif_unix.c, tiffio.h},
+ tools/{fax2ps.c, fax2tiff.c, tiff2pdf.c}: Fixed win32 I/O functions
+ usage as per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1127
+
+ * libtiff/tif_strip.c: Take subsampling in account when calculating
+ TIFFScanlineSize().
+
+ * tools/tiffcp.c: Do not set RowsPerStrip bigger than image length.
+
+2006-03-17 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/fax2tiff.c: Fixed wrong TIFFerror() invocations as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1125
+
+ * tools/fax2ps.c: Fixed reading the input stream from stdin as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1124
+
+2006-03-16 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiffiop.h: Added decalration for
+ _TIFFSetDefaultCompressionState().
+
+ * libtiff/{tif_jpeg.c, tif_fax3.c, tif_zip.c, tif_pixarlog.c,
+ tif_lzw.c, tif_luv.c}: Use _TIFFSetDefaultCompressionState() in all
+ codec cleanup methods. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1120
+
+2006-03-15 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_jpeg.c: Do not cleanup codec state in TIFFInitJPEG(). As
+ per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1119
+
+ * tools/raw2tiff.c: Do not set RowsPerStrip larger than ImageLength.
+ As per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1110
+
+ * libtiff/tiffiop.h: dblparam_t typedef removed; GLOBALDATA macro
+ removed; move here the STRIP_SIZE_DEFAULT macro definition.
+
+ * libtiff/{tif_dirread.c, tif_strip.c}: Removed STRIP_SIZE_DEFAULT
+ macro definition.
+
+ * libtiff/tif_dir.c: Use double type instead of dblparam_t.
+
+2006-03-14 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Do not check the PlanarConfig tag presence
+ in TIFFReadDirectory, because it is always set at the start of
+ function and we allow TIFFs without that tag set.
+
+2005-03-13 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.8.1 released.
+
+2006-03-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Fixed error reporting in TIFFFetchAnyArray()
+ function as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1102
+
+ * libtiff/tif_dirread.c: More wise check for integer overflow
+ condition as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1102
+
+ * libtiff/{tif_jpeg.c, tif_pixarlog.c, tif_fax3.c, tif_zip.c}:
+ Properly restore setfield/getfield methods in cleanup functions. As
+ per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1102
+
+2006-03-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_predict.c, tif_predict.h}: Added new function
+ TIFFPredictorCleanup() to restore parent decode/encode/field methods.
+
+ * libtiff/{tif_lzw.c, tif_pixarlog.c, tif_zip.c}: Use
+ TIFFPredictorCleanup() in codec cleanup methods. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1102
+
+ * libtiff/tif_dirread.c: Fixed integer overflow condition in
+ TIFFFetchData() function. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1102
+
+2006-03-01 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_ojpeg.c: Set the ReferenceBlackWhite with the
+ TIFFSetField() method, not directly. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1043
+
+ * tools/ppm2tiff.c: Added support for PBM files as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1044
+
+2006-02-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_write.c: Small code rearrangement in TIFFWriteScanline()
+ to avoid crash as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1081.
+
+2006-02-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Functions t2p_sample_rgbaa_to_rgb() and
+ t2p_sample_rgba_to_rgb() was used in place of each other, that was
+ resulted in problems with RGBA images with associated alpha.
+ As per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1097
+
+2006-02-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirwrite.c: Properly write TIFFTAG_DOTRANGE tag as per
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1088.
+
+ * libtiff/tif_print.c: Properly read TIFFTAG_PAGENUMBER,
+ TIFFTAG_HALFTONEHINTS, TIFFTAG_YCBCRSUBSAMPLING and TIFFTAG_DOTRANGE
+ tags as per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1088.
+
+ * tools/tiff2ps.c: Properly scale all the pages when converting
+ multipage TIFF with /width/height/center options set. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1080
+
+2006-02-15 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Do not create output file until all option checks
+ will be done. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1072
+
+ * tools/bmp2tiff.c: Added ability to create multipage TIFFs from the
+ list of input files as per bug:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1077
+
+2006-02-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_tile.c: Fix error reporting in TIFFCheckTile() as per
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1063.
+
+ * tools/tiffgt.c: Avoid crashing in case of image unsupported by
+ TIFFRGBAImage interface.
+
+ * libtiff/tif_color.c: Avoid overflow in case of wrong input as per
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=1065.
+
+2006-02-07 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiff2pdf.c: Fixed support for non-YCbCr encoded JPEG
+ compressed TIFF files, per submission from Dan Cobra.
+
+2006-02-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dirread.c, tif_packbits.c, tif_win32.c}: Properly
+ cast values to avoid warnings. As per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1033.
+
+ * libtiff/tif_dirinfo.c: Use TIFF_NOTYPE instead of 0 when
+ appropriate. As per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1033.
+
+ * libtiff/tif_aux.c: Fixed type of temporary variable in
+ _TIFFCheckMalloc() as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1033.
+
+2006-02-06 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_aux.c: Return static array when fetching default
+ YCbCrCoefficients (another problem, reported a the
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1029 entry).
+
+2006-02-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: Special handling for PageNumber, HalftoneHints,
+ YCbCrSubsampling and DotRange tags as per bugs
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1029
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1034
+
+ * libtiff/tif_dirread.c: Use _TIFFGetExifFieldInfo() instead of
+ _TIFFGetFieldInfo() in TIFFReadEXIFDirectory() call as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1026.
+
+2006-01-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtool related stuff updated from the 2.1a branch.
+
+2006-01-11 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/bmp2tiff,pal2rgb,ppm2tiff,ras2tiff,raw2tiff,sgi2tiff,
+ tiff2bw,tiffcp: Fixed jpeg option processing so -c jpeg:r:50 works
+ properly as per bug:
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1025
+
+2006-01-09 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * configure.ac: Fix with_default_strip_size comparison as reported
+ by Norihiko Murase.
+
+2006-01-08 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * test/Makefile.am (LIBTIFF): Due to linking against libtiff
+ incorrectly, tests were not actually testing the uninstalled
+ libtiff. Now they are.
+
+2006-01-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirinfo.c: Change definitions for TIFFTAG_ICCPROFILE,
+ TIFFTAG_PHOTOSHOP, TIFFTAG_RICHTIFFIPTC, TIFFTAG_XMLPACKET: readcount
+ should be uint32 value.
+
+2006-01-02 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * html/man/Makefile.am (htmldoc): Fix htmldoc rule so that it can
+ be used if build directory is not the same as source directory.
+ * man/{TIFFGetField.3tiff, TIFFSetField.3tiff}: Documented
+ TIFFTAG_PHOTOSHOP, TIFFTAG_RICHTIFFIPTC, and TIFFTAG_XMLPACKET,
+ and re-sorted tag names in alphabetical order.
+
+2005-12-29 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.8.0 released.
+
+2005-12-28 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/bmp2tiff.c (main): Fixed warning regarding returning
+ inconsistent types from a condition.
+ * tools/tiffcmp.c (CheckLongTag): Eliminate warning due to printf
+ format.
+ * tools/bmp2tiff.c: Reduce compilation warnings on big-endian CPUs.
+
+2005-12-28 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * html/{index.html, support.hml, libtiff.html}: Cleaned up HTML
+
+2005-12-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiffio.h: Added VC_EXTRALEAN definition before including
+ windows.h, to reduce the compile time.
+
+2005-12-26 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_jpeg.c: Improve compilation under MinGW.
+
+2005-12-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dir.c, tif_dir.h, tif_dirread.c, tif_dirinfo.c}:
+ tiffFieldInfo and exifFieldInfo arrays definitions moved back to
+ tif_dirinfo.c; added _TIFFGetFieldInfo() and _TIFFGetExifFieldInfo()
+ private functions to retrieve FieldInfo arrays.
+
+2005-12-24 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * html/build.html: Added some additional instructions for when
+ building using MSVC under Windows. Also fixed two HTML syntax
+ errors and used HTML Tidy to tidy up the HTML syntax and
+ formatting.
+
+2005-12-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_aux.c, tif_dir.c, tif_dir.h, tif_dirwrite.c,
+ tif_print.c, tif_getimage.c}: Make InkSet, NumberOfInks, DotRange and
+ StoNits tags custom.
+
+2005-12-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_aux.c, tif_dir.c, tif_dir.h, tif_print.c}: Make
+ WhitePoint tag custom.
+
+ * libtiff/{tif_dir.h, tiff.h}: More EXIF tags added.
+
+2005-12-23 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/tiffio.h: fixed typo that potentially resulted in
+ redefininition of USE_WIN32_FILEIO
+
+ * libtiff/*: Added more 'dual-mode' error handling: Done TIFFWarning
+ calls in core LibTiff.
+
+2005-12-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dir.c, tif_dir.h, tif_print.c}: Make RichTIFFIPTC,
+ Photoshop and ICCProfile tags custom.
+
+2005-12-21 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * libtiff/*, contrib/*: Added 'dual-mode' error handling, enabling
+ newer code to get context indicator in error handler and still
+ remain compatible with older code: Done TIFFError calls everywhere
+ except in tools
+
+2005-12-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c: Added many error reporting messages; fixed integer
+ overflow as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=789
+
+2005-12-16 Frank Warmerdam <warmerdam@pobox.com>
+
+ * contrib/addtiffo/*: Major upgrade by Joris to support subsampled
+ YCbCr images in jpeg compressed TIFF files.
+
+2005-12-14 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c: Return non-zero status when reading fails (again).
+
+2005-12-13 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c: Return non-zero status when reading fails.
+
+2005-12-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dir.h, tiff.h}: Added more EXIF tags.
+
+2005-12-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dir.c, tif_dir.h, tif_print.c}: Make XMLPacket tag
+ custom.
+
+ * tools/tiffinfo.c: Print EXIF directory contents if exist.
+
+ * libtiff/tiff.h: Few EXIF tag numbers added.
+
+ * libtiff/{tif_dirinfo.c, tif_dirread.c, tif_dir.h, tif_dir.c,
+ tiffio.h}: Preliminary support to read custom directories. New
+ functions: TIFFReadCustomDirectory() and TIFFReadEXIFDirectory().
+
+2005-12-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dirinfo.c, tif_dirread.c, tif_dir.h, tif_dir.c}:
+ More work to implement custom directory read support.
+
+ * libtiff/{tif_aux.c, tif_dirinfo.c, tif_dirread.c, tif_dir.h,
+ tif_dir.c, tif_print.c}: Make YCbCrCoefficients and ReferenceBlackWhite
+ tags custom.
+
+2005-12-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: One more workaround for broken
+ StripByteCounts tag. Handle the case when StripByteCounts array filled
+ with completely wrong values.
+
+2005-11-30 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirinfo.c: Release file descriptor in case of failure
+ in the TIFFOpenW() function as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1003
+
+ * libtiff/tif_dirinfo.c: Correctly yse bsearch() and lfind()
+ functions as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1008
+
+2005-11-20 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_open.c, tiff.h, tiffdump.c: Incorporate preliminary support
+ for MS MDI format.
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1002
+
+ * .cvsignore: many files added, and a few update according
+ to suggestion of Brad HArds on tiff mailing list.
+
+2005-11-03 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/libtiff.def, tiffiop.h, tiffio.h: Made TIFFFreeDirectory
+ public.
+
+2005-10-31 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/fax2tiff.c: Properly calculate sizes of temporary arrays
+ as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=943
+
+ * tools/fax2tiff.c: Added option '-r' to set RowsPerStrip parameter
+ as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=944
+
+ * tools/tiffdump.c: Fixed typeshift and typemask arrays initialization
+ problem as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=946
+
+ * tools/bmp2tiff.c: Fixed possible integer overflow error as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=965
+
+ * libtiff/tif_dirinfo.c: Make XResolution, YResolution and
+ ResolutionUnit tags modifiable during write process. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=977
+
+ * tools/tiffsplit.c: Copy fax related fields over splitted parts
+ as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=983
+
+2005-10-21 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_dirread.c: Don't try and split single strips into "0" strips
+ in ChopUpSingleUncompressedStrip. This happens in some degenerate
+ cases (like 1x1 files with stripbytecounts==0 (gtsmall.jp2 embed tiff)
+
+2005-10-20 Joris Van Damme <joris.at.lebbeke@skynet.be>
+
+ * tif_fax3.c: changed 'at scanline ...' style warning/errors
+ with incorrect use of tif_row, to 'at line ... of
+ strip/tile ...' style
+
+2005-10-15 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_write.c: fixed setting of planarconfig as per bug report
+ on the mailing list from Joris.
+
+2005-10-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.ac, configure, nmake.opt, libtiff/{tif_config.h,
+ tif_dirread.c}: Make the default strip size configurable via the
+ --with-default-strip-size and STRIP_SIZE_DEFAULT options.
+
+2005-09-30 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * html/support.html: Fixed link to documentation on Greg Ward's
+ LogLuv TIFF format.
+
+2005-09-28 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffdump.c: Fixed crash when reading malformed tags.
+
+2005-09-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Added missed 'break' statement as per bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=932
+
+2005-09-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.7.4 released.
+
+ * {configure, configure.ac, Makefile.am, autogen.sh}: Applied patch
+ from Patrick Welche (all scripts moved in the 'config' and 'm4'
+ directories).
+
+2005-09-12 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_open.c: reintroduce seek to avoid problem on solaris.
+
+2005-09-05 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dir.c: When prefreeing tv->value in TIFFSetFieldV
+ also set it to NULL to avoid double free when re-setting custom
+ string fields as per:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=922
+
+2005-08-12 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_print.c: avoid signed/unsigned warning.
+
+ * libtiff/tif_dirread.c: removed unused variable.
+
+2005-07-30 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dir.c: Fixed up support for swapping "double complex"
+ values (128 bits as 2 64 bits doubles). GDAL gcore tests now
+ pass on bigendian (macosx) system.
+
+2005-07-28 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_aux.c, tif_dirread.c, tif_fax3.c, tiffiop.h}: Rename
+ CheckMalloc() function to _TIFFCheckMalloc() and make it available
+ globally as an internal helper routine.
+
+2005-07-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: More improvements in the "pass by value" part of
+ the custom tags handling code.
+
+2005-07-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dirread.c, tif_dirinfo.c}: Do not upcast BYTEs to
+ SHORTs in the TIFFFetchByteArray(). Remove TIFFFetchExtraSamples()
+ function, use TIFFFetchNormalTag() instead as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=831
+
+ Remove TIFFFetchExtraSamples() function, use TIFFFetchNormalTag()
+ instead.
+
+ * libtiff/tiffconf.h.in: One more attempt to fix the AIX bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=39
+
+2005-07-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_print.c: Fixed printing of the BYTE and SBYTE arrays.
+
+ * tools/tiffdump.c: Added support for TIFF_IFD datatype.
+
+2005-07-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_write.c: Do not check the PlanarConfiguration field in
+ the TIFFWriteCheck() function in case of single band images (as per
+ TIFF spec).
+
+2005-07-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * SConstruct, libtiff/SConstruct: Added the first very preliminary
+ support for SCons software building tool (http://www.scons.org/).
+ This is experimental infrastructure and it will exist along with the
+ autotools mechanics.
+
+2005-07-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * port/{getopt.c, strcasecmp.c, strtoul.c}: Update modules from
+ the NetBSD source tree (the old 4-clause BSD license changed to
+ the new 3-clause one).
+
+ * configure.ac, port/lfind.c, libtiff/tiffiop.h: Added lfind()
+ replacement module.
+
+ * port/dummy.c: Make the dummy function static.
+
+2005-07-06 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c: Fixed WhitePoint tag copying.
+
+ * libtiff/{tif_dir.c, tif_dir.h, tif_dirinfo.c, tif_print.c}:
+ Make FieldOfViewCotangent, MatrixWorldToScreen, MatrixWorldToCamera,
+ ImageFullWidth, ImageFullLength and PrimaryChromaticities tags custom.
+
+2005-07-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.7.3 released.
+
+ * configure, configure.ac: Do not use empty -R option when linking
+ with --enable-rpath.
+
+2005-07-01 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffiop.h, tif_open.c}: Added open option 'h' to avoid
+ reading the first IFD when needed. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=875
+
+ * libtiff/tif_color.c: Better use of TIFFmin() macro to avoid side
+ effects.
+
+2005-06-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Print two characters per loop in the
+ t2p_write_pdf_trailer(). As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=594
+
+ * tools/tiffgt.c: Use MacOS X OpenGL framework when appropriate. As
+ per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=844
+
+ * acinclude.m4: Updated to latest OpenGL test macros versions.
+
+ * libtiff/tiff.h: Use correct int size on Sparc 64bit/Sun compiler
+ platform. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=855
+
+2005-06-14 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirinfo.c: Added support for ClipPath, XClipPathUnits
+ and YClipPathUnits tags.
+
+2005-06-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * contrib/addtiffo/tif_ovrcache.c: Properly extract tile/strip size;
+ use pixel sized shift in contigous case.
+
+2005-06-06 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * contrib/addtiffo/{tif_overview.c, tif_ovrcache.c, tif_ovrcache.h}:
+ Make overviews working for contiguos images.
+
+2005-06-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_open.c: Replace runtime endianess check with the compile
+ time one.
+
+ * libtiff/tif_predict.c: Floating point predictor now works on
+ big-endian hosts.
+
+2005-06-01 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: Use _TIFFsetString() function when read custom
+ ASCII values.
+
+ * libtiff/{tif_dirinfo.c, tif_dir.h, tif_dir.c, tif_print.c}: Make
+ DocumentName, Artist, HostComputer, ImageDescription, Make, Model,
+ Copyright, DateTime, PageName, TextureFormat, TextureWrapModes and
+ TargetPrinter tags custom.
+
+ * libtiff/tif_jpeg.c: Cleanup the codec state depending on
+ TIFF_CODERSETUP flag (to fix memry leaks).
+
+ * libtiff/tif_jpeg.c: Initialize JPEGTables array with zero after
+ allocating.
+
+2005-05-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.ac, libtiff/Makefile.am: Added workaround for
+ OpenBSD/MirOS soname problem as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=838
+
+ * libtiff/tif_dirwrite.c: Use tdir_count when calling
+ TIFFCvtNativeToIEEEDouble() in the TIFFWriteDoubleArray() function as
+ per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=845
+
+2005-05-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/ppm2tiff.c: Fixed format string when read PPM file header with
+ the fscanf() function. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=861
+
+ * libtiff/{tif_dirinfo.c, tif_print.c}: TIFFFetchByteArray() returns
+ uint16 array when fetching the BYTE and SBYTE filds, so we should
+ consider result as pointer to uint16 array and not as array of chars.
+ As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=831
+
+ * libtiff/tif_dir.c: More efficient custom tags retrieval as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=830
+
+ * libtiff/tif_win32.c: Use FILE_SHARE_READ | FILE_SHARE_WRITE share
+ mode in CreateFile() call as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=829
+
+ * libtiff/Makefile.am: Fixed parallel compilation of the libtiff and
+ libtiffxx libraries as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=826
+
+ * contrib/addtiffo/{tif_overview.c, tif_ovrcache.h}: Sinchronized with
+ GDAL.
+
+2005-05-23 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: Substantial fix for addtiffo problems with
+ JPEG encoded TIFF files. Pre-allocate lots of space for jpegtables
+ in directory.
+
+2005-05-22 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirread.c: Changed the code that computes
+ stripbytecount[0] if it appears bogus to ignore if stripoffset[0] is
+ zero. This is a common case with GDAL indicating a "null" tile/strip.
+
+2005-05-17 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffsplit.c: Check for JPEGTables tag presence before copying.
+
+2005-05-06 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirread.c: Applied similar change to
+ TIFFFetchPerSampleLongs and TIFFFetchPerSampleAnys.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=843
+
+ * libtiff/tif_jpeg.c: added LIB_JPEG_MK1 support in JPEGDecodeRaw().
+
+2005-05-06 Andrey Kiselev <dron@ak4719.spb.edu>
+ * tools/tiff2pdfr.c, man/tiff2pdf.1: Calculate the tile width properly;
+ added new option '-b' to use interpolation in output PDF files (Bruno
+ Ledoux).
+
+2005-05-05 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirread.c: Ensure that broken files with too many
+ values in PerSampleShorts work ok instead of crashing.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=843
+
+2005-04-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffdither.c: Copy the PhotometricInterpretation tag from the
+ input file.
+
+2005-04-15 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_predict.c: Added ability to encode floating point
+ predictor, as per TIFF Technical Note 3.
+
+2005-04-14 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_predict.h, tif_predict.c}: Added ability to decode
+ floating point predictor, as per TIFF Technical Note 3.
+
+2005-04-13 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffio.h, tiffiop.h, tif_dir.c, tif_read.c, tif_swab.c}:
+ Added _TIFFSwab24BitData() and TIFFSwabArrayOfLong() functions used to
+ swap 24-bit floating point values.
+
+ * libtiff/tiff.h: Added predictor constants.
+
+2005-04-08 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffiop.h, tif_dir.c}: Use uint32 type for appropriate
+ values in _TIFFVSetField() function. Inspired by the bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=816
+
+ * man/TIFFSetField.3tiff: Fixed definition of the TIFFTAG_INKNAMES tag
+ as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=816
+
+2005-03-30 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_open.c: Do not read header in case the output file
+ should be truncated (Ron).
+
+ * libtiff/{tif_dirinfo.c, tif_config.h.vc}: Use lfind() instead
+ of bsearch() in _TIFFFindFieldInfoByName() function (Ron).
+
+ * libtiff/{tiff.h, tif_dirinfo.c}: Fixes in EXIF tag ordering (Ron).
+
+2005-03-22 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.ac, libtiff/Makefile.am: Use libtool machinery to pass
+ rpath option.
+
+2005-03-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dir.c, tif_print.c}: Handle all data types in custom
+ tags.
+
+2005-03-18 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/dirinfo.c: Added DNG tags.
+
+ * libtiff/{tif_dir.c, tif_print.c}: More improvements in custom tag
+ handling code.
+
+ * libtiff/tiff.h: More comments; added missed DNG tag (LensInfo);
+ added DNG 1.1.0.0 tags.
+
+ * tools/tif2pdf.c: Fixed problem with alpha channel handling as per
+ bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=794
+
+ * man/TIFFGetField.3tiff: Add a note about autoregistered tags.
+
+2005-03-17 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * nmake.opt: Build with Win32 CRT library by default.
+
+ * tools/tiff2ps.c: Fixed typo in page size handling code.
+
+ * libtiff/{tif_dir.c, tif_print.c}: Support for custom tags, passed
+ by value.
+
+ * libtiff/{tiff.h, tif_dirinfo.c, tiffiop.h}: Added EXIF related tags.
+
+2005-03-15 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.7.2 released.
+
+2005-03-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcmp.c: Added ability to compare the 32-bit integer and
+ floating point data; complain on unsupported bit depths.
+
+2005-03-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tif_stream.cxx: Use ios namespace instead of ios_base to support
+ GCC 2.95.
+
+ * libtiff/{tiff.h, tif_fax3.tif, tif_jpeg.c}: Applied correct patch from
+ Lee Howard for HylaFax DCS tag
+ (see http://bugzilla.remotesensing.org/show_bug.cgi?id=771)
+
+2005-03-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure, configure.ac: Use -rpath option instead of -R as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=732
+
+ * libtiff/{tiff.h, tif_fax3.tif, tif_jpeg.c}: Applied patch from Lee
+ Howard to support a new tag TIFFTAG_FAXDCS (34911) used in HylaFax
+ software. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=771
+
+ * nmake.opt, html/build.html: Add more comments, change the config
+ file organization a bit as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=764
+
+ * tools/tiffcmp.c: Use properly sized buffer in short arrays comparison
+ as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=785
+
+2005-03-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: More logic to guess missed strip size as per
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=705
+
+ * tools/fax2ps.c: Replace insecure mktemp() function with the
+ tmpfile() as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=786
+
+2005-02-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiff.h: Changed the int8 definition to be always signed char
+ as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=727
+
+ * libtiff/tiffio.h: Move TIFFOpenW() function into the extern "C"{}
+ block as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=763
+
+2005-02-03 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiffgt.c: Fix problem on big-endian CPUs so that images
+ display more correctly. Images display brighter than they should
+ on a Sun workstation.
+
+2005-02-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Estimate strip size in case of wrong or
+ suspicious values in the tags. As per bugs
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=705
+
+ and
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=320
+
+ * tools/tiff2ps.c: Fixed problem with page sizes as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=742
+
+2005-01-31 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tiff.h (TIFFTAG_TILEWIDTH): Corrected description.
+ (TIFFTAG_TILELENGTH): Corrected description.
+
+2005-01-30 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.ac: Fixes for --with-docdir option as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=759
+
+ * libtiff/tif_open.c: Remove unnesessary TIFFSeekFile() call as per
+ bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=756
+
+ * libtiff/tif_stream.cxx: Fixes for C++ stream interface from
+ Michael Rinne and Edward Lam.
+
+2005-01-15 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.ac: Make the documentation directory location configurable
+ via the --with-docdir option (as suggested by Jeremy C. Reed).
+
+ * libtiff/tif_color.c: Use double as the second argument of pow()
+ function in TIFFCIELabToRGBInit(). As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=741
+
+ * libtiff/tif_pixarlog.c: Avoid warnings when converting float to
+ integer as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=740
+
+ * libtiff/tif_getimage.c: Always fill the error message buffer in
+ TIFFRGBAImageBegin() as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=739
+
+2005-01-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_jpeg.c: Added ability to read/write the fax specific
+ TIFFTAG_FAXRECVPARAMS, TIFFTAG_FAXSUBADDRESS and TIFFTAG_FAXRECVTIME
+ tags as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=736
+
+ * libtiff/tif_win32.c: Fixed message formatting in functions
+ Win32WarningHandler() and Win32ErrorHandler() as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=735
+
+ * tools/tiff2ps.c: Interpret the -w and -h options independently. As
+ per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=689
+
+2005-01-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiffio.h: Move the color conversion routines in the 'extern
+ "C"' section as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=727
+
+ * libtiff/tiff.h: Restore back the workaround for AIX Visual Age C
+ compiler to avoid double definition of BSD types as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=39
+
+ * libtiff/Makefile.am: Place the C++ stream API in the separate
+ library called libtiffxx to avoid unneeded dependencies. Probably
+ there will be more C++ API in the future. As per bugs
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=733
+
+ and
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=730
+
+2005-01-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffdump.c: Fixed problem when read broken TIFFs with the
+ wrong tag counts (Dmitry V. Levin, Martin Pitt).
+
+ * configure.ac: Replace --disable-c++ with the --disable-cxx option as
+ per bug http://bugzilla.remotesensing.org/show_bug.cgi?id=730
+
+2004-12-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_getimage.c: More fixes for multiple-alpha-channelled
+ RGB-images as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=713
+
+
+ * tools/tiffset.c: Convert character option to integer value as per
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=725
+
+2004-12-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.7.1 released.
+
+ * html/tiffset.1.html: Add missed manual page as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=678
+
+ * libtiff/tiff.h: Revert back libtiff data type definitions as per
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=687
+
+2004-12-19 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Do not forget about TIFF_VARIABLE2 when
+ checking for tag count in TIFFReadDirectory() function. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=713
+
+ * libtiff/{tif_dirread.c, tif_fax3.c}: More argument checking in
+ CheckMallock() function.
+
+ * libtiff/tif_getimage.c: Support for multiple-alpha-channelled
+ RGB-images as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=718
+
+2004-12-15 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_getimage.c: #define A1 bracketing for clean build on
+ SunPro compiler.
+
+2004-12-11 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * autogen.sh: aclocal and autoheader should be executed after
+ libtoolize. Also add '-I .' to aclocal invocation to check
+ current directory for macros.
+
+2004-12-10 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirwrite.c: Always write TIFFTAG_SUBIFD using LONG type
+ as per bugs
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=703
+
+ and
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=704
+
+2004-12-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * nmake.opt: Link with the user32.lib in windowed mode. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=697
+
+ * libtiff/tif_win32.c: Use char* strings instead of TCHAR in windowed
+ mode as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=697
+
+ * libtiff/tif_config.in.vc: Removed unneded definitions for
+ read/open/close/lseek functions to fix the
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=680
+
+2004-12-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dir.c, tif_dirread.c}: Remove TIFFReassignTagToIgnore()
+ call from the TIFFReadDirectory() function. TIFFReassignTagToIgnore
+ must be removed in the future, as it was never used properly. As per
+ bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=692
+
+2004-11-30 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_jpeg.c: Added a work-around in order to allow
+ compilation with the heavily modified version of libjpeg delivered
+ with Cygwin.
+
+2004-11-29 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: Properly handle tags, which have the uint32
+ counts. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=693
+
+ * tools/fax2ps.c: Be able to extract the first page (#0). As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=690
+
+2004-11-28 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_unix.c: Make UNIX module compilable (and usable)
+ on Windows.
+
+ * nmake.opt: Add missed DLLNAME variable.
+
+2004-11-26 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/makefile.vc: make it easier to rename the libtiff DLL.
+
+2004-11-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * man/libtiff.3tiff: Improvements in the "LIST OF ROUTINES" table as
+ per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=545
+
+ * man/tiffset.1: Added manual page for tiffset tool written by Jay
+ Berkenbilt. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=678
+
+2004-11-23 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_error.c: fixed TIFFerror call to be TIFFError.
+
+2004-11-21 Frank Warmerdam <warmerdam@pobox.com>
+
+ * html/document.html: Updated Adobe web links as per email from Joris.
+
+2004-11-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffio.hxx, tiffio.h}: C++ stream interface moved to new
+ file tiffio.hxx. We don't have any C++ in tiffio.h, those who want to
+ use C++ streams should #include <tiffio.hxx>.
+
+2004-11-13 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiff.h: Added Adobe DNG tags.
+
+ * libtiff/tif_win32.c: Typo fixed.
+
+ * libtiff/{tif_stream.cxx, tiffio.h}: C++ stream interface updated to
+ be compliant with the latest standard. Appropriate additions in
+ makefiles now completed.
+
+2004-11-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffset.c, libtiff/tif_dirinfo.c: Properly handle the
+ different tag types. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=600
+
+2004-11-10 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_aux.c: Set the appropriate ReferenceBlackWhite array for
+ YCbCr image which lacks that tag (noted by Hans Petter Selasky).
+
+2004-11-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_color.c: Division by zero fixed (Hans Petter Selasky).
+
+2004-11-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_stream.cxx, tiffio.h}: Added C++ stream interface
+ contributed by Edward Lam (see
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=654 for details).
+ Though no changes in any makefiles yet.
+
+2004-11-05 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_open.c: Removed close() in TIFFClientOpen() if file
+ is bad. This is the callers responsibility.
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=651
+
+2004-11-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffio.h, tif_win32.c, libtiff.def}: Added TIFFOpenW()
+ function to work with the double byte strings (used to represent
+ filenames in some locales). As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=625
+
+ * libtiff/tif_dirread.c: Fixed problem when fetching BitsPerSample and
+ Compression tags of type LONG from broken TIFFS as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=662
+
+ * libtiff/tif_dirinfo.c: Fixed definition for TIFFTAG_RICHTIFFIPTC,
+ the writecount should have uint32 type. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=662
+
+ * libtiff/tif_write.c: Fixed wrong if() statement in
+ TIFFAppendToStrip() function as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=660
+
+2004-11-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirinfo.c: Change definition for TIFFTAG_EXTRASAMPLES
+ field. The caller should supply a count when setting this field. As
+ per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=648
+
+ * libtiff/{tif_jpeg.c, tif_ojpeg.c}: TIFFTAG_JPEGTABLES should have
+ uint32 count. Use this type everywhere.
+
+2004-11-03 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_next.c: avoid use of u_long and u_char types. Bug 653.
+
+2004-11-02 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiff2rgba.c: removed extra newlines in usage message.
+
+2004-10-30 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirwrite.c: Improvements in tag writing code.
+
+ * tools/tiff2ps.c: Fixed wrong variable data type when read Position
+ tags (Tristan Hill).
+
+2004-10-30 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tiffiop.h: added fallback definition of assert() if we
+ don't have assert.h.
+
+2004-10-29 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_fax3.c: Fixed case with the wrong decode routines
+ choosing when the incorrect Group4Options tag set. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=323
+
+ * libtiff/tif_dirwrite.c: Fixed problem with passing count variable of
+ wrong type when writing the TIFF_BYTE/TIFF_SBYTE tags in
+ TIFFWriteNormalTag().
+
+2004-10-28 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps.c: Fixed wrong variable data type when read Resolution
+ tags (Peter Fales).
+
+ * tools/{bmp2tiff.c, raw2tiff.c}: Get rid of stream I/O functions.
+
+2004-10-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiff2pdf.c: added casts to avoid warnings.
+
+ * libtiff/libtiff.def: Added several more entry points required
+ to link fax2tiff.c against the DLL on windows.
+
+2004-10-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure, configure.ac: Added --enable-rpath option to embed linker
+ paths into library binary.
+
+2004-10-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffset.c: Check the malloc return value (Dmitry V. Levin).
+
+ * libtiff/{tif_strip.c, tif_tile.c}: Zero division problem fixed
+ (Vladimir Nadvornik, Dmitry V. Levin).
+
+2004-10-16 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.7.0 released.
+
+2004-10-15 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tif_jpeg.c: There seems to be no need to include stdio.h
+ in this file so its inclusion is removed. Including stdio.h
+ sometimes incurs an INT32 typedef conflict between MinGW's
+ basetsd.h and libjpeg's jmorecfg.h.
+
+2004-10-15 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * man/bmp2tiff.1: Added manual page for bmp2tiff utility.
+
+2004-10-13 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiffcmp.c (leof): Renamed from 'eof' in order to avoid
+ conflict noticed under MinGW.
+ * ltmain.sh: Fix for MinGW compilation.
+
+2004-10-13 Frank Warmerdam <warmerdam@pobox.com>
+
+ * man/tiffsplit.1: Fixed to indicate using aaa-zzz, not aa-zz.
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=635
+
+2004-10-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dirread.c, tif_jpeg.c, tif_luv.c, tif_ojpeg.c,
+ tif_pixarlog.c, tif_write.c}: Handle the zero strip/tile sizes
+ properly (Dmitry V. Levin, Marcus Meissner).
+
+2004-10-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirinfo.c: Type of the TIFFTAG_SUBIFD field changed
+ to TIFF_IFD.
+
+2004-10-10 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/bmp2tif.c: Check the space allocation results.
+
+2004-10-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: Initialize td_tilewidth and td_tilelength fields
+ of the TIFFDirectory structure with the 0 instead of -1 to avoid
+ confusing integer overflows in TIFFTileRowSize() for striped images.
+
+ * tools/tiff2pdf.c: Fixed TransferFunction tag handling reported
+ by Ross A. Finlayson.
+
+ * libtiff/tif_dir.c: Fixed custom tags handling as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=629
+
+2004-10-08 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirinfo.c: Fix bug with tif_foundfield and reallocation
+ of tif_fieldinfo.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=630
+
+2004-10-04 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * contrib/iptcutil/README: Added the missing README which goes
+ along with iptcutil.
+
+2004-10-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_compress.c: Improved error reporting in
+ TIFFGetConfiguredCODECs() (Dmitry V. Levin).
+
+2004-10-02 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.7.0beta2 released.
+
+ * libtiff/{tif_aux.c, tif_compress.c, tif_dirinfo.c, tif_dirwrite.c,
+ tif_extension.c, tif_fax3.c, tif_luv.c, tif_packbits.c,
+ tif_pixarlog.c, tif_write.c}: Added checks for failed memory
+ allocations and integer overflows (Dmitry V. Levin).
+
+ * libtiff/tiff.h: Missed TIFF_BIGTIFF_VERSION constant added.
+
+2004-10-01 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_open.c: added a more informative message if a BigTIFF
+ file is opened.
+
+2004-09-30 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirinfo.c: changed type of XMLPacket (tag 700) to
+ TIFFTAG_BYTE instead of TIFFTAG_UNDEFINED to comply with the info
+ in the Adobe XMP Specification.
+
+2004-09-29 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_jpeg.c, tif_pixarlog.c}: Use _TIFFmemset() instead of
+ memset().
+
+ * libtiff/{tif_dirread.c, tif_strip.c, tif_tile.c}: Applied patches
+ from Dmitry V. Levin to fix possible integer overflow problems.
+
+2004-09-28 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_getimage.c: Check for allocated buffers before clearing
+ (Dmitry V. Levin).
+
+2004-09-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dir.h, tif_dir.c, tif_dirread.c, tif_write.c}:
+ Optimize checking for the strip bounds.
+
+ * libtiff/{tif_dirread.c, tif_strip.c}: TIFFScanlineSize() and
+ TIFFRasterScanlineSize() functions report zero in the case of integer
+ overflow now. Properly handle this case in TIFFReadDirectory()
+ (patches from Dmitry V. Levin).
+
+2004-09-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_dirinfo.c, tif_strip.c, tif_tile.c}: Use TIFFhowmany8()
+ macro where appropriate.
+
+ * tools/tiff2bw.c: Write ImageWidth/Height tags to output file, as
+ noted by Gennady Khokhorin.
+
+ * libtiff/tif_dirread.c: Always check the return values, returned
+ by the _TIFFmalloc() (Dmitry V. Levin).
+
+ * libtiff/tif_dir.c: Fixed possible integer overflow _TIFFset*Array()
+ functions (Dmitry V. Levin).
+
+ * libtiff/{tif_dirread.c, tif_dir.c, tif_write.c}:
+ Potential memory leak fixed in TIFFReadDirectory(), _TIFFVSetField(),
+ TIFFGrowStrips() (found by Dmitry V. Levin).
+
+2004-09-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffio.h, tif_compress.c}: Added TIFFGetConfiguredCODECs()
+ to get the list of configured codecs.
+
+ * libtiff/{tiffiop.h, tif_dirread.c}: More overflow fixes from
+ Dmitry V. Levin.
+
+2004-09-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Applied patch from Dmitry V. Levin to fix
+ possible integer overflow in CheckMalloc() function.
+
+2004-09-22 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffiop.h, tif_strip.c}: Use TIFFhowmany8() macro instead
+ of plain TIFFhowmany() where appropriate.
+
+2004-09-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_getimage.c: Initialize arrays after space allocation.
+
+2004-09-19 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.7.0beta released.
+
+ * libtiff/{tif_luv.c, tif_next.c, tif_thunder.c}: Several buffer
+ overruns fixed, as noted by Chris Evans.
+
+2004-09-14 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * commit: Added a script to make it more convenient to commit
+ updates. The CVS commit message is extracted from this ChangeLog
+ file.
+
+2004-09-14 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.ac, configure, aclocal.m4, libtiff/{mkspans.c, tif_fax3.c,
+ tif_getimage.c, tif_luv.c, tif_lzw.c, tif_ojpeg.c, tif_packbits.c,
+ tif_predict.c, tif_read.c, tif_swab.c, tif_thunder.c, tif_write.c,
+ tif_dir.c, tif_dirread.c, tif_dirwrite.c, tif_jpeg.c, tif_dirinfo.c,
+ tif_vms.c, tif_print.c, tif_strip.c, tif_tile.c, tif_dir.h,
+ tif_config.h.in, tiffiop.h}:
+ Get rid of BSD data types (u_char, u_short, u_int, u_long).
+
+2004-09-13 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * libtiff/tiff.h: Fix column tagging. Reference current Adobe XMP
+ specification. Reference libtiff bug tracking system to submit
+ private tag additions.
+
+2004-09-12 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * tools/tiffgt.c: Include "tif_config.h".
+
+ * configure.ac: Use AM_PROG_CC_C_O since it is now needed to build
+ tiffgt. This results in the 'compile' script being added to the
+ project.
+
+ * tools/Makefile.am (tiffgt_CFLAGS): Add extra build options
+ required to find OpenGL headers necessary to build tiffgt. Also
+ ensure that the libtiff that we built is used rather than some other
+ libtiff installed on the system.
+
+2004-09-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.ac, acinclude.m4, aclocal.m4: New macros to detect GLUT
+ libraries.
+
+2004-09-11 Bob Friesenhahn <bfriesen@simple.dallas.tx.us>
+
+ * configure.ac: Pass library configuration defines via
+ tif_config.h rather than extending CPPFLAGS. Configure a
+ libtiff/tiffconf.h in order to satisfy application requirements
+ (not used by library build). Do not define _POSIX_C_SOURCE=2 since
+ this causes failure to build on systems which properly respect
+ this request.
+
+ * libtiff/tiffconf.h.in: New file to act as the template for the
+ configured tiffconf.h
+
+ * libtiff/files.lst (HDRS): Install the configured tiffconf.h.
+
+2004-09-10 Frank Warmerdam <warmerdam@pobox.com>
+
+ * html/internals.html: Split off a discussion of adding new tags
+ into addingtags.html.
+
+2004-09-10 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * test/{ascii_tag.c, long_tag.c}: Preliminary test suite added.
+
+ * tools/tiff2pdf.c: Fixed reading TransferFunction tag as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=590
+
+ * libtiff/tif_print.c: Fixes in InkNames and NumberOfInks reporting.
+
+ * libtiff/tif_dirread.c: Don't reject to read tags of the
+ SamplesPerPixel size when the tag count is greater than number of
+ samples as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=576
+
+ * libtiff/tiff.h: Use _TIFF_DATA_TYPEDEFS_ guardian to switch off
+ defining int8/uint8/... etc. types. As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=607
+
+2004-09-09 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiff2ps.c, tools/tiffmedian.c: fiddle with include files
+ to avoid compile warnings about getopt() and a few other things.
+
+2004-09-02 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Use memcpy() function instead of pointer
+ assigning magic in TIFFFetchFloat().
+
+2004-09-01 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffio.h, tif_open.c}: Applied patches from Joris Van Damme
+ to avoid requirement for tiffiop.h inclusion in some applications. See
+ here
+
+ http://www.asmail.be/msg0054799560.html
+
+ for details.
+
+ * tools/fax2tiff.c: Use the new functions in the code.
+
+2004-08-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Initialize arrays properly.
+
+ * tools/tiff2ps.c: Avoid zero division in setupPageState() function;
+ properly initialize array in PSDataBW().
+
+2004-08-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: More fixes for bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=590
+
+ from Ross Finlayson.
+
+2004-08-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps.c: Fixed problem with uninitialized values.
+
+ * libtiff/tif_dir.c: Initialize tif_foundfield data member in the
+ TIFFDefaultDirectory() (in addition to 2004-08-19 fix).
+
+ * tools/tiff2pdf.c: Fixed a bunch of problems as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=590
+
+2004-08-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Applied patch from Ross Finlayson that checks
+ that the input file has compression, photometric interpretation,
+ etcetra, tags or if not than a more descriptive error is returned.
+
+ * libtiff/tif_dirread.c: Fixed problem in TIFFReadDirectory() in the
+ code, responsible for tag data type checking.
+
+2004-08-19 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffiop.h, tif_dirinfo.c}: Fixed problem with the static
+ variable as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=593
+
+2004-08-16 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/ras2tiff.c: Fixed issue with missed big-endian checks as per
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=586
+
+2004-08-01 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_config.h.in, tif_config.h.vc}: config.h.in and
+ config.h.vc files renamed in the tif_config.h.in and tif_config.h.vc.
+
+2004-07-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_lzw.c: LZW compression code is merged back from the
+ separate package. All libtiff tools are updated to not advertise an
+ abcence of LZW support.
+
+2004-07-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiffio.h: Revert thandle_t back to void* type.
+
+2004-07-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_read.c, tif_tile.c, tif_strip.c}: Fixes in error
+ messages, as suggested by Bernd Herd.
+
+2004-07-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: Call TIFFError() instead of producing warnings
+ when setting custom tags by value. Reported by Eric Fieleke.
+
+2004-06-14 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/bmp2tiff.c: Add missed RawsPerStrip setting.
+
+2004-06-08 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/bmp2tiff.c: Added new utility to convert Windows BMP files
+ into TIFFs.
+
+2004-06-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.7.0alpha released.
+
+2004-06-06 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiff.h, tif_dirwrite.c, tif_fax3.c, tif_packbits.c,}: Get rid
+ of ugly 64-bit hacks, replace them with the clever (autoconf based )
+ ones :-).
+
+ * libtiff/tiffio.h: Define thandle_t as int, not void* (may cause
+ problems in 64-bit environment).
+
+2004-06-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffset.c: tiffset now can set any libtiff supported tags.
+ Tags can be supplied by the mnemonic name or number.
+
+ * libtiff/{tiffio.h, tif_dir.h, tif_dirinfo.c,}: Added two new
+ functions TIFFFindFieldInfoByName() and TIFFFieldWithName().
+
+2004-05-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_ojpeg.c: Fixed problem with duplicated SOI and SOF
+ markers as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=581
+
+2004-05-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffsplit.c: Don't forget to copy Photometric
+ Interpretation tag.
+
+2004-05-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_open.c, tiffio.h}: New function added:
+ TIFFIsBigEndian(). Function returns nonzero if given was file written
+ in big-endian order.
+
+ * tools/tiffsplit.c: Fixed problem with unproperly written multibyte
+ files. Now output files will be written using the same byte order
+ flag as in the input image. See
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=574
+
+ for details.
+
+2004-05-19 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_print.c: added (untested) support for printing
+ SSHORT, SLONG and SRATIONAL fields.
+
+ * tools/tiffcp.c: close output file on normal exit.
+
+2004-05-17 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_fax3.c: Avoid reading CCITT compression options
+ if compression type mismatches. See
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=565
+
+2004-04-30 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_strip.c: Never return 0 from the
+ TIFFNumberOfStrips().
+
+2004-04-29 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Workaround for broken TIFF writers which
+ store single SampleFormat value for multisampled images. See
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=562
+
+2004-04-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure.ac, libtiff/{tiff.h, config.h.in}: Added tests for int8,
+ int16 and int32 types to avoid complains on some compilers. Details at
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=39
+
+2004-04-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2pdf.c: Fixed problem with unaligned access as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=555
+
+2004-04-14 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_write.c: Allow in-place updating of the compressed
+ images (don't work properly with all codecs). For details see GDAL bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=534
+
+2004-04-06 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_jpeg.c: Workaround for wrong sampling factors used
+ in the Intergarph JPEG compressed TIFF images as per bug:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=532
+
+2004-04-04 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_open.c: close clientdata if TIFFClientOpen() fails
+ via bad2.
+
+2004-03-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c: Properly set Photometric Interpretation in case of
+ JPEG compression of grayscale images.
+
+ * tools/tiffcp.c: Don't emit warnings when Orientation tag does not
+ present in the input image.
+
+2004-03-19 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * {many}: The first attempt to switch to autotools.
+
+2004-03-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_open.c: Use dummy mmap/munmap functions in
+ TIFFClientOpen() when the appropriate client functions was not
+ supplied by user.
+
+2004-03-02 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/ycbcr.c: fixed main() declaration as per:
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=513
+
+2004-02-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffsplit.c: Copy JPEGTables tag contents for JPEG compressed
+ images. Reported by Artem Mirolubov.
+
+ * libtiff/tif_dirread.c: Fixed problem with handling TIFF_UNDEFINED
+ tag type in TIFFFetchNormalTag() as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=508
+
+2004-02-17 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_codec.c: Fixed typo in TIFFInitPackBits name as per:
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=494
+
+2004-02-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_fax3.c: Fixed problem with CCITT encoding modes as per
+ bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=483
+
+ But we need more work on fax codec to support update mode.
+
+2004-01-30 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/libtiff.def: Added TIFFCurrentDirOffset, TIFFWriteCheck,
+ TIFFRGBAImageOK, and TIFFNumberOfDirectories as suggested by
+ Scott Reynolds.
+
+2004-01-29 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiff.h: Fixed tag definitions for TIFFTAG_YCLIPPATHUNITS
+ and TIFFTAG_INDEXED as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=475
+
+ * libtiff/{tif_win32.c, tif_unix.c}: Check whether the pointer is
+ NULL before proceeding further as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=474
+
+ Check results, returned by the TIFFFdOpen() before returning and close
+ file if TIFFFdOpen() failed as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=468
+
+ * libtiff/tif_open.c: More fixes for
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=468
+
+2004-01-28 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{libtiff.def, tif_close.c, tiffio.h, tif_open.c}: Separate
+ TIFFCleanup() from the TIFFClose() in order to fix the bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=468
+
+ * tools/tiffcp.c: Fixed problem with wrong interpretation of the
+ InkNames tag as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=466
+
+ Memory leak fixed.
+
+2004-01-21 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirwrite.c: Fixed handling of writable ASCII tags that
+ are field_passcount=TRUE properly. Arguably anonymous custom tags
+ should be declared as passcount=FALSE, but I don't want to change
+ that without a careful review.
+
+2004-01-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_write.c: Fixed reporting size of the buffer in case of
+ stripped image in TIFFWriteBufferSetup(). As per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=460
+
+2004-01-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: Incomplete cleanup in TIFFFreeDirectory(),
+ patch from Gerben Koopmans.
+
+ * libtiff/tif_dirread.c: Check field_passcount value before setting
+ the value of undefined type, patch from Gerben Koopmans.
+
+2004-01-02 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c: Fixed problem with wrong Photometric setting for
+ non-RGB images.
+
+2003-12-31 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_win32.c: Fixed problem with _TIFFrealloc() when the NULL
+ pointer passed. Patch supplied by Larry Grill.
+
+ * libtiff/{tiff.h, tif_fax3.c}:Fixes for AMD 64 platform as
+ suggested by Jeremy C. Reed.
+
+2003-12-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff 3.6.1 released.
+
+2003-12-24 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * config.guess, config.sub: Updated from the recent upstream.
+
+2003-12-22 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_color, tif_getimage.c, tiffio.h}, man/TIFFcolor.3t:
+ More cleanups in color conversion interface, added appropriate manual
+ page.
+
+2003-12-19 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_extension.c, tif_dirinfo.c, tiff.h}: Warnings fixed as
+ per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=357
+
+ * tools/tiff2ps.c: Added support for alpha channel. Fixes
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=428
+
+ * libtiff/{libtiff.def, tif_color.c, tif_getimage.c, tiffio.h}:
+ Interface for Lab->RGB color conversion is finally cleaned up.
+ Added support for ReferenceBlackWhite tag handling when converted from
+ YCbCr color space. The latter closes
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=120
+
+2003-12-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_getimage.c, tiffio.h}: Avoid warnings.
+
+ * libtiff/makefile.vc, tools/makefile.vc: Support for IJG JPEG
+ library.
+
+2003-12-06 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_getimage.c, tif_aux.c}: Read WhitePoint tag from the
+ file and properly use it for CIE Lab->RGB transform.
+
+2003-12-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_getimage.c, tif_color.c, tiffio.h}: YCbCr->RGB
+ conversion routines now in the tif_color.c module. New function
+ TIFFYCbCrtoRGB() available in TIFF API.
+
+ * libtiff/tif_dirwrite.c: Handle TIFF_IFD tag type correctly.
+
+2003-12-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_getimage.c, tif_color.c, tiffio.h}: Improvements in
+ CIE Lab conversion code. Start moving YCbCr stuff to the tif_color.c
+ module.
+
+ * libtiff/{tif_getimage.c, tiffio.h}, man{TIFFReadRGBAImage.3t,
+ TIFFReadRGBAStrip.3t, TIFFReadRGBATile.3t, TIFFRGBAImage.3t}:
+ Finally resolved problems with orientation handling. TIFFRGBAImage
+ interface now properly supports all possible orientations, i.e. images
+ will be flipped both in horizontal and vertical directions if
+ required. 'Known bugs' section now removed from the appropriate manual
+ pages. Closed bug entry:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=322
+
+2003-12-02 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dir.c: Fixed order of the parameters in TIFFError()
+ function calls as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=440
+
+2003-11-28 Ross Finlayson <libtiff@apexinternetsoftware.com>
+
+ * tools/tiff2pdf.c: Some bugs fixed.
+
+2003-11-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_luv.c: Fixed bug in 48-bit to 24-bit conversion routine,
+ reported by Antonio Scuri.
+
+ * man/tiff2pdf.1: Few improvements in page layout.
+
+ * Makefile.in, /man/Makefile.in, /html/man/tiff2pdf.1.html:
+ Added support fpr tiff2pdf manual page.
+
+2003-11-26 Ross Finlayson <libtiff@apexinternetsoftware.com>
+
+ * /man/tiff2pdf.1: File added to repository.
+
+2003-11-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * Makefile.in, /tools/{Makefile.in, makefile.vc}:
+ Added support fpr tiff2pdf utility.
+
+2003-11-25 Ross Finlayson <libtiff@apexinternetsoftware.com>
+
+ * /tools/tiff2pdf.c: File added to repository.
+
+2003-11-22 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /tools/raw2tiff.c: sqrtf() replaced with sqrt().
+
+2003-11-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /tools/raw2tiff.c: #include <getopt.h> removed.
+
+ * tools/{Makefile.in, tiffgt.c}: Unmaintained and platform dependent
+ sgigt utility removed and replaced with the completely rewritten
+ portable tiffgt tool (depend on OpenGL and GLUT). Initial revision,
+ there is a lot of things to improve.
+
+ * libtiff/tif_ojpeg.c: TIFFVGetField() function now can properly
+ extract the fields from the OJPEG files. Patch supplied by Ross
+ Finlayson.
+
+ * libtiff/{tiffio.h, tif_codec.c}, man/{libtiff.3t, TIFFcodec.3t}:
+ Added new function TIFFIsCODECConfigured(), suggested by Ross
+ Finlayson.
+
+2003-11-18 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirinfo.c: Implemented binary search in
+ _TIFFMergeFieldInfo(). Patch supplied by Ross Finlayson.
+
+ * libtiff/tif_dir.h: _TIFFFindOrRegisterdInfo declaration replaced
+ with _TIFFFindOrRegisterFieldInfo as reported by Ross Finlayson.
+
+2003-11-17 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_dirread.c: do not mark all anonymously defined tags to be
+ IGNOREd.
+
+2003-11-17 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * contrib/pds/{tif_pdsdirread.c, tif_pdsdirwrite.c}: Use
+ TIFFDataWidth() function insted of tiffDataWidth array.
+
+2003-11-16 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiff.h, tif_dirinfo.c}: Added support for IFD (13)
+ datatype, intruduced in "Adobe PageMaker TIFF Tech. Notes".
+
+2003-11-15 Frank Warmerdam <warmerdam@pobox.com>
+
+ * Makefile.in: fixed missing backslash for tif_color.c in list.
+
+2003-11-13 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_color.c, tif_getimage.c, tiffio.h, Makefile.in}:
+ New color space conversion code: CIE L*a*b* 1976 images now supported
+ by the TIFFRGBAImage interface. All introduced routines go to new
+ module tif_color.c. Eventually all color conversion functions should
+ be moved there.
+
+2003-11-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/{ras2tiff.c, rasterfile.h}: Properly determine SUN Rasterfiles
+ with the reverse byte order (it is reported by the magic header
+ field). Problem reported by Andreas Wiesmann.
+
+ * tools/raw2tiff.c, man/raw2tiff.1: Few improvements in correlation
+ calculation function. Guessing mechanics now documented in manual page.
+
+2003-11-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/raw2tiff.c: Implemented image size guessing using
+ correlation coefficient calculation between two neighbour lines.
+
+2003-11-09 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_tile.c: remove spurious use of "s" (sample) in the
+ planarconfig_contig case in TIFFComputeTile().
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=387
+
+2003-11-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiffiop.h: New macros: TIFFmax, TIFFmin and TIFFrint.
+
+2003-11-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffio.h, tif_strip.c}, man/{TIFFstrip.3t, libtiff.3t}:
+ Added TIFFRawStripSize() function as suggested by Chris Hanson.
+
+2003-11-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_lzw.c, tif_fax3.c}: Proper support for update mode as
+ per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=424
+
+2003-10-29 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/libtiff.def: Added TIFFReadRGBAImageOriented.
+
+ * html/build.html: Added note about GNU make requirement.
+
+2003-10-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * Makefile.in: Fixes in using MAKEFLAGS as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=418
+
+ * port/install.sh.in: Option -p added to the mkdir command to create
+ all directory tree structure before installing.
+
+2003-10-18 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /tools/tiff2ps.c: #include <strings.h> replaced with the
+ #include <string.h>.
+
+2003-10-16 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * Makefile.in: Add an absolute path to the test_pics.sh call.
+
+2003-10-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tiffcomp.h: #define _BSDTYPES_DEFINED when defining BSD
+ typedefs.
+
+2003-10-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure, libtiff/{Makefile.in, mkversion.c}:
+ Relative buildings fixed.
+
+ * tools/Makefile.in: Added "-I../libtiff" to the tiffset building
+ rule.
+
+2003-10-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * Makefile.in: Added missed v3.6.0.html.
+
+ * libtiff/tiffio.h: Typo fixed: ORIENTATION_BOTTOMLEFT replaced with
+ ORIENTATION_BOTLEFT.
+
+2003-10-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * 3.6.0 final release.
+
+2003-10-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tif_getimage.c, tiffio.h}, man/TIFFReadRGBAImage.3t: New
+ function TIFFReadRGBAImageOriented() implemented to retrieve raster
+ array with user-specified origin position as suggested by Jason Frank.
+ See
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=322
+
+ for details.
+
+ * tools/tiff2rgba.c: Switched to use TIFFReadRGBAImageOriented()
+ instead of TIFFReadRGBAImage().
+
+ * tools/tiff2ps.c: Fixed possible endless loop as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=404
+
+2003-09-30 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Check field counter against number of fields
+ in order to fix
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=366
+
+ * libtiff/tif_fax3.c: Fix wrong line numbering as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=342
+
+2003-09-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/{tiffiop.h, tif_dirread.c, tif_dir.c, tif_open.c,
+ tif_close.c}: Store a list of opened IFD to prevent looping as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=383
+
+2003-09-23 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: More fixes for EstimateStripByteCounts(). See
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=358
+
+2003-08-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffmedian.c: int declaration replaced with the uint32 to
+ support large images as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=382
+
+2003-08-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/Makefile.in: Fixed problem with building in different
+ directory.
+
+ * tools/tiff2ps.c: Added missing #include <strings.h>.
+
+ * libtiff/tif_dirwrite.c: More fixes for custom tags code
+ from Ashley Dreier.
+
+2003-08-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps.c: Added page size setting when creating PS Level 2.
+ Patch submitted by Balatoni Denes (with corrections from Tom
+ Kacvinsky).
+
+ * tools/tiff2ps.c: Fixed PS comment emitted when FlateDecode is
+ being used. Reported by Tom Kacvinsky.
+
+ * libtiff/tif_dirwrite.c: Fixed problem with custom tags writing,
+ reported by Ashley Dreier.
+
+ * libtiff/tif_print.c: Fixed problem with float tags reading, support
+ for printing RATIONAL and BYTE tags added.
+
+2003-08-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_lzw.c: Move LZW codec state block allocation back to
+ TIFFInitLZW(), because its initialization in LZWSetupDecode() cause
+ problems with predictor initialization. Remove O_RDONLY check during
+ state block allocation to be able open LZW compressed files in update
+ mode.
+
+ Problem exist for libtiff version of the tif_lzw.c module. One from
+ lzw-compression-kit hasn't such troubles.
+
+2003-08-04 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_write.c: modified tif_write.c so that the various
+ encoded write functions use tif_postdecode() to apply byte order
+ swapping (swab) to the application passed data buffer if the same
+ would be done when reading. This allows us to write pixel data with
+ more than 8 bits per sample to existing files of a non-native byte
+ order. One side effect of this change is the applications buffer
+ itself is altered in this case by the act of writing.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=171
+
+2003-07-25 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_open.c: avoid signed/unsigned casting warning
+ initializing typemask as per patch from J.A. Strother.
+
+ * tools/tiffcp.c: fixed signed/unsigned casting warning.
+
+ * libtiff/tif_print.c: dos2unix conversion.
+
+ * tools/tiffsplit.c: increased the maximum number of pages that
+ can be split. Patch provided by Andrew J. Montalenti.
+
+2003-07-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/raw2tiff.c: Added option `-p' to explicitly select color
+ space of input image data. Closes
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=364
+
+2003-07-08 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_aux.c, tif_codec.c, tif_dir.c, tif_dirread.c, tif_extension.c,
+ tif_fax3.c, tif_getimage.c, tif_luv.c, tif_lzw.c, tif_next.c,
+ tif_packbits.c, tif_predict.c, tif_print.c, tif_swab.c, tif_thunder.c:
+ avoid casting warning at /W4.
+
+2003-07-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/thumbnail.c: Memory leak fixed as reported by Robert S. Kissel.
+
+2003-06-30 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_pixarlog.c: Unused variables removed.
+
+ * libtiff/{tif_dirread.c, tif_dir.c}: Fixed problem with
+ EstimateStripByteCounts() as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=358
+
+ * libtiff/{tif_dirwrite.c, tif_packbits.c}: Fixed compilation on
+ 64-bit architectures as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=357
+
+ * libtiff/tif_dirinfo.c: TIFFDataWidth() returns 0 in case of
+ unknown data type.
+
+2003-06-19 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_print.c: fixed some serious bugs when printing
+ custom tags ... almost certain to crash.
+
+ * libtiff/tif_dirread.c: Don't ignore custom fields that are
+ autodefined. Not sure how this got to be like this.
+
+2003-06-18 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * 3.6.0 Beta2 released.
+
+ * tools/tiffcmp.c, man/tiffcmp.1: Fixed problem with unused data
+ comparing as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=349
+
+ `-z' option now can be used to set the number of reported different
+ bytes.
+
+2003-06-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c, man/tiffcp.1: Added possibility to specify value -1
+ to -r option to get the entire image as one strip. See
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=343
+
+ for details.
+
+2003-06-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c: Set the correct RowsPerStrip and PageNumber
+ values as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=343
+
+2003-05-27 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: modified segment_height calculation to always
+ be a full height tile for tiled images. Also changed error to just
+ be a warning.
+
+2003-05-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/fax2tiff.c: Page numbering fixed, as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=341
+
+2003-05-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * contrib/ojpeg/{Makefile.in, jdhuff.h, jinclude.h, ojpeg.c, README},
+ configure, Makefile.in: Switched back to the old behaviour. Likely
+ better solution should be found for OJPEG support.
+
+2003-05-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/mkversion.c: Fixed problem with wrong string size when
+ reading RELEASE-DATE file.
+
+2003-05-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps.c: Fixed bug in Ascii85EncodeBlock() function: array
+ index was out of range.
+
+2003-05-06 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * contrib/ojpeg/{Makefile.in, jdhuff.h, jinclude.h, ojpeg.c, README},
+ configure, Makefile.in: Improved libtiff compilation with OJPEG
+ support. Now no need for patching IJG JPEG library, hack requred by
+ libtiff will be compiled and used in-place. Implemented with
+ suggestion and help from Bill Allombert, Debian's libjpeg maintainer.
+
+ * libtiff/tif_aux.c: Properly handle TIFFTAG_PREDICTOR in
+ TIFFVGetFieldDefaulted() function.
+
+2003-05-05 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/ppm2tiff.c: PPM header parser improved: now able to skip
+ comments.
+
+ * tools/tiffdither.c: Fixed problem with bit fill order tag setting:
+ was not copied from source image.
+
+ * libtiff/getimage.c: Workaround for some images without correct
+ info about alpha channel as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=331
+
+2003-04-29 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps.c, man/tiff2ps.1: Add ability to generate PS Level 3.
+ It basically allows one to use the /flateDecode filter for ZIP
+ compressed TIFF images. Patch supplied by Tom Kacvinsky. Fixes
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=328
+
+ * tools/tiff2ps.c: Force deadzone printing when EPS output specified
+ as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=325
+
+2003-04-17 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Removed additional check for StripByteCounts
+ due to problems with multidirectory images. Quality of error messages
+ improved.
+
+2003-04-16 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiffcp.c: Fixed problem with colorspace conversion for JPEG
+ encoded images. See bug entries
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=275
+
+ and
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=23
+
+ * libtiff/tif_dirread.c: Additional check for StripByteCounts
+ correctness. Fixes
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=320
+
+2003-03-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/{fax2ps.c, fax2tiff.c, gif2tiff.c, pal2rgb.c, ppm2tiff.c,
+ ras2tiff.c, raw2tiff.c, rgb2ycbcr.c, thumbnail.c, tiff2bw.c,
+ tiff2ps.c, tiff2rgba.c, tiffcp.c, tiffdither.c, tiffinfo.c,
+ tiffmedian.c}: Added library version reporting facility to all tools.
+
+2003-03-06 Frank Warmerdam <warmerdam@pobox.com>
+
+ * port/install.sh.in: Fixed problems with install producing paths
+ like ///usr/local/lib on cygwin.
+
+2003-02-27 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/fax2tiff.c, man/fax2tiff.1: New switch (-X) to set width of
+ raw input page. Patch supplied by Julien Gaulmin. See
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=293
+
+ for details.
+
+2003-02-26 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dir.c: fixed up the tif_postdecode settings
+ responsible for byte swapping complex image data.
+
+ * libtiff/tif_lzw.c: fixed so that decoder state isn't allocated till
+ LZWSetupDecode(). Needed to read LZW files in "r+" mode.
+
+2003-02-07 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/ppm2tiff.c: Fixed problem with too many arguments.
+
+2003-02-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/raw2tiff.c: Memory leak fixed.
+
+2003-02-03 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/fax2tiff.c, man/fax2tiff.1: Applied patch from Julien Gaulmin
+ (thanks, Julien!). More switches for fax2tiff tool for better control
+ of input and output. Details at
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=272
+
+2003-02-03 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: Modified to defer initialization of jpeg
+ library so that we can check if there is already any tile/strip data
+ before deciding between creating a compressor or a decompressor.
+
+2003-01-31 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_write.c: TIFFWriteCheck() now fails if the image is
+ a pre-existing compressed image. That is, image writing to
+ pre-existing compressed images is not allowed.
+
+ * libtiff/tif_open.c: Removed error if opening a compressed file
+ in update mode.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=198
+
+2003-01-31 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * config.guess, config.sub: Updated to recent upstream versions.
+
+2003-01-15 Frank Warmerdam <warmerdam@pobox.com>
+
+ * cut 3.6.0 Beta release.
+
+2002-12-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/fax2ps.c, man/fax2ps.1: Page size was determined
+ in wrong way as per bug
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=239
+
+2002-12-17 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirread.c: Allow wrong sized arrays in
+ TIFFFetchStripThing().
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=49
+
+2002-12-02 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dir.c: fix problem with test on td_customValueCount.
+ Was using realloc even first time. Fix by Igor Venevtsev.
+
+2002-11-30 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dir.c: fixed bug with resetting an existing custom
+ field value.
+
+ * libtiff/tif_dir.c: Fixed potential problem with ascii "custom"
+ tags in TIFFVGetField() ... added missing break.
+
+2002-10-14 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiff2ps.c: fixes a problem where "tiff2ps -1e" did not make
+ the scanline buffer long enough when writing rgb triplets.
+ The scanline needs to be 3 X the number of dots or else it will
+ contain an incomplete triplet and programs that try to separate
+ the eps by redefining the colorimage operator will get messed up.
+ Patch supplied by William Bader.
+
+ * Makefile.in: added tif_extension.c to file list as per
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=218.
+
+2002-10-11 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * configure, config.site, libtiff/{tif_unix.c, Makefile.in}: Fix for
+ large files (>2GiB) supporting. New option in the config.site:
+ LARGEFILE="yes". Should be enough for I/O of the large files.
+
+2002-10-10 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/html/v3.6.0.html: new release notes.
+
+ * libtiff/index.html: removed faq, cvs snapshot cruft. Added email
+ link for Andrey. Pointer to v3.6.0.html.
+
+ * libtiff/Makefile.in: added direct rule for tiffvers.h for release.
+
+2002-10-07 Andrey Kiselev <dron@ak4719.spb.edu>
+ * tools/tiff2ps.c, man/tiff2ps.1: Applied patch form Sebastian Eken
+ (thanks, Sebastian!). New switches:
+ -b # for a bottom margin of # inches
+ -c center image
+ -l # for a left margin of # inches
+ -r rotate the image by 180 degrees
+ New features merged with code for shrinking/overlapping.
+ Previously added -c and -n switches (for overriding PS units) renamed
+ in -x and -y respectively.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=200
+
+ * html/man/*.html: Updated from actual manual pages.
+
+2002-10-06 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: fixed problem with boolean defined with wrong
+ size on windows. Use #define boolean hack.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=188
+
+ * libtiff/tiff.h: Don't do special type handling in tiff.h unless
+ USING_VISUALAGE is defined.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=39
+
+2002-10-03 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tiff.h: added COMPRESSION_JP2000.
+
+2002-10-02 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_dirread.c: Another fix for the fetching SBYTE arrays
+ by the TIFFFetchByteArray() function. Should finally resolve
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=52
+
+ * configure: Set -DPIXARLOG_SUPPORT option along with -DZIP_SUPPORT
+
+ * html/Makefile.in: New targets added: html and groffhtml for
+ producing HTML representations of the manual pages automatically.
+ html target uses man2html tool, groffhtml uses groff tool.
+
+2002-09-29 Frank Warmerdam <warmerdam@pobox.com>
+
+ * configure, libtiff/Makefile.in: Added SCO OpenServer 5.0.6 support
+ from John H. DuBois III.
+
+2002-09-15 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * Makefile.in, /man/{raw2tiff.1, Makefile.in, libtiff.3}: Added
+ manual page for raw2tiff(1) tool.
+
+2002-09-12 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /libtiff/{tiffio.h, tif_dir.h}: TIFFDataWidth() declaration moved to
+ the tiffio.h header file.
+
+ * Makefile.in, /man/{TIFFDataWidth.3t, Makefile.in, libtiff.3}: Added
+ manual page for TIFFDataWidth() function
+
+2002-09-08 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirread.c: Expand v[2] to v[4] in TIFFFetchShortPair()
+ as per http://bugzilla.remotesensing.org/show_bug.cgi?id=196.
+
+ * tools/tiff2ps.c: Don't emit BeginData/EndData DSC comments
+ since we are unable to properly include the amount to skip.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=80
+
+2002-09-02 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /libtiff/tif_dirread.c: Fixed problem with SBYTE type data fetching
+ in TIFFFetchByteArray(). Problem described at
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=52
+
+2002-08-22 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /libtiff/tif_dirinfo.c: Further additions to free custom fields
+ in _TIFFSetupFieldInfo() function.
+ See http://bugzilla.remotesensing.org/show_bug.cgi?id=169 for details.
+
+ * /libtiff/tif_lzw.c: Additional consistency checking added in
+ LZWDecode() and LZWDecodeCompat().
+ Fixes http://bugzilla.remotesensing.org/show_bug.cgi?id=190
+ and http://bugzilla.remotesensing.org/show_bug.cgi?id=100
+
+ * /libtiff/tif_lzw.c:
+ Added check for valid code lengths in LZWDecode() and
+ LZWDecodeCompat(). Fixes
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=115
+
+2002-08-16 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /libtiff/{Makefile.vc, libtiff.def}:
+ Missed declarations added.
+
+2002-08-15 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_getimage.c: Ensure that TIFFRGBAImageBegin() returns the
+ return code from the underlying pick function.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=177
+
+ * tif_dir.h: changed FIELD_CODEC to 66 from 64 to avoid overlap
+ with FIELD_CUSTOM as mentioned in bug 169.
+
+ * tif_close.c: added logic to free dynamically created anonymous
+ field definitions to correct a small memory leak.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=169
+
+2002-08-10 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /tools/{raw2tiff.c, Makefile.in, Makefile.lcc, Makefile.vc}:
+ New tool: raw2tiff --- raw images to TIFF converter. No manual page yet.
+
+2002-07-31 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: Fixed problem with setting of nrows in
+ JPEGDecode() as per bugzilla bug (issue 1):
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=129
+
+ * libtiff/{tif_jpeg.c,tif_strip.c,tif_print.c}: Hacked tif_jpeg.c to
+ fetch TIFFTAG_YCBCRSUBSAMPLING from the jpeg data stream if it isn't
+ present in the tiff tags.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=168
+
+ * libtiff/tif_read.c, libtiff/tif_write.c: TIFFReadScanline() and
+ TIFFWriteScanline() now set tif_row explicitly in case the codec has
+ fooled with the value.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=129
+
+2002-06-22 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * /tools/tiff2ps.c: Added workaround for some software that may crash
+ when last strip of image contains fewer number of scanlines than
+ specified by the `/Height' variable. See
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=164
+ for explanation.
+
+2002-06-21 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps, man/tiff2ps.1: New functionality for tiff2ps utility:
+ splitting long images in several pages. See
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=142 for explanation.
+ Patch granted by John Williams <williams@morinda.com>.
+
+2002-06-11 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/contrib/win95: renamed to contrib/win_dib. Added new
+ Tiffile.cpp example of converting TIFF files into a DIB on Win32.
+ This one is described in:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=143
+
+ * libtiff/tif_ojpeg.c: Major upgrade from Scott. See details at:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=156
+
+2002-05-10 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps: New commandline switches to override resolution
+ units obtained from the input file. Closes
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=131
+
+2002-04-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/libtiff.def: Added missed declaration.
+
+2002-04-22 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/fax2tiff.c: Updated to reflect latest changes in libtiff.
+ Closes http://bugzilla.remotesensing.org/show_bug.cgi?id=125
+
+2002-04-20 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_open.c: Pointers to custom procedures
+ in TIFFClientOpen() are checked to be not NULL-pointers.
+
+2002-04-18 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/libtiff.def: Added missed declarations.
+
+ * libtiff/tif_pixarlog.c: Updated for using tif_tagmethods structure.
+
+2002-04-16 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_lzw.c: Additional checks for data integrity introduced.
+ Should finally close
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=100
+
+2002-04-10 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/tiff2ps: Division by zero fixed.
+ Closes http://bugzilla.remotesensing.org/show_bug.cgi?id=88
+
+2002-04-09 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/: tif_dirwrite.c, tif_write.c, tiffio.h:
+ TIFFCheckpointDirectory() routine added.
+ Closes http://bugzilla.remotesensing.org/show_bug.cgi?id=124
+
+ * man/: TIFFWriteDirectory.3t, Makefile.in: Added description
+ for the new function.
+
+2002-04-08 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/: tif_codec.c, tif_compress.c, tiffiop.h: Introduced
+ additional members tif->tif_decodestatus and tif->tif_encodestatus
+ for correct handling of unconfigured codecs (we should not try to read
+ data or to define data size without correct codecs).
+
+ * libtiff/tif_getimage.c: The way of codecs checking in TIFFRGBAImageOK
+ changed. Now it has used tif->tif_decodestatus and
+ tif->tif_encodestatus.
+ Should fix http://bugzilla.remotesensing.org/show_bug.cgi?id=119 (in
+ case of __cvs_8.tif test image).
+
+ * libtiff/: tif_dirinfo.c, tif_dirread.c: Somebody makes a bug in
+ tif_dirread.c when TIFFCreateAnonFieldInfo was introduced.
+ Closes http://bugzilla.remotesensing.org/show_bug.cgi?id=119 in case
+ of _cvs_00000-00.tif, _cvs_00000-01.tif and _cvs_00000-02.tif.
+
+2002-04-04 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/: tif_lzw.c: Assertions in LZWDecode and LZWDecodeCompat
+ replaced by warnings. Now libtiff should read corrupted LZW-compressed
+ files by skipping bad strips.
+ Closes http://bugzilla.remotesensing.org/show_bug.cgi?id=100
+
+2002-04-03 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirwrite.c: Removed some dead code.
+
+ * libtiff/*: Cleanup some warnings.
+
+ * libtiff/tif_dir.c: Fixed bug with count returned by TIFFGetField()
+ for variable length FIELD_CUSTOM values. Was int * but should be
+ u_short *.
+
+2002-04-01 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * tools/: tifcp.c: Added support for 'Orientation' tag in tiffcp
+ utility (at cpStripToTile routine).
+
+2002-03-27 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_dirread.c: avoid div-by-zero if rowbytes is zero in chop func.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=111
+
+ * tif_print.c: Fixed so that ASCII FIELD_CUSTOM values with
+ passcount set FALSE can be printed (such as TIFFTAG_SOFTWARE).
+
+ * libtiff/tif_dir.c,tif_dirinfo.c,tif_dir.h,tif_ojpeg.c: modified so
+ that TIFFTAG_SOFTWARE uses FIELD_CUSTOM as an example.
+
+2002-03-26 Dwight Kelly <dbmalloc@remotesensing.org>
+
+ * libtiff/: tiff.h, tif_dir.c, tif_dir.h, tif_dirinfo.c, tif_dirread.c,
+ tif_dirwrite.c: Added get/put code for new tag XMLPACKET as defined
+ in Adobe XMP Technote. Added missing INKSET tag value from TIFF 6.0 spec
+ INKSET_MULTIINK (=2). Added missing tags from Adobe TIFF technotes:
+ CLIPPATH, XCLIPPATHUNITS, YCLIPPATHUNITS, OPIIMAGEID, OPIPROXY and
+ INDEXED. Added PHOTOMETRIC tag value from TIFF technote 4 ICCLAB (=9).
+
+2002-03-26 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/: tif_getimage.c: TIFFReadRGBAStrip and TIFFReadRGBATile
+ now also uses TIFFRGBAImageOK before reading. This is additional fix
+ for http://bugzilla.remotesensing.org/show_bug.cgi?id=110
+
+2002-03-25 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/: tif_getimage.c: Additional check for supported
+ codecs added in TIFFRGBAImageOK and TIFFReadRGBAImage now uses
+ TIFFRGBAImageOK before reading.
+ Closes http://bugzilla.remotesensing.org/show_bug.cgi?id=110
+
+2002-03-15 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/: tif_dir.c, tif_dir.h, tif_dirinfo.c, tif_dirread.c,
+ tif_dirwrite.c: Added routine TIFFDataWidth for detrmining
+ TIFFDataType sizes instead of working with tiffDataWidth array
+ directly. Should prevent out-of-borders bugs in case of unknown or
+ broken data types. EstimateStripByteCounts routine modified, so it
+ won't work when tags with uknown sizes founded.
+ Closes http://bugzilla.remotesensing.org/show_bug.cgi?id=109
+
+2002-03-13 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/tif_getimage.c: Added support for correct handling
+ `Orientation' tag in gtTileContig. Should be added in other gt*
+ functions as well, but I have not images for testing yet. Partially
+ resolves http://bugzilla.remotesensing.org/show_bug.cgi?id=23
+
+2002-03-10 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/: tif_dirinfo.c, tif_dirwrite.c: Added possibility to
+ read broken TIFFs with LONG type used for TIFFTAG_COMPRESSION,
+ TIFFTAG_BITSPERSAMPLE, TIFFTAG_PHOTOMETRIC. Closes
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=99
+
+2002-03-08 Andrey Kiselev <dron@ak4719.spb.edu>
+
+ * libtiff/Makefile.in, tools/Makefile.in: Shared library will not
+ be stripped when installing, utility binaries will do. Closes
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=93
+
+2002-02-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * man/TIFFGetField: fixed type of TIFFTAG_COPYRIGHT.
+
+ * man/libtiff.3t: added copyright tag info.
+
+2002-02-11 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/{tiff.h,tif_fax3.c}: Add support for __arch64__.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=94
+
+ * man/Makefile.in: Patch DESTDIR handling
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=95
+
+ * configure: OpenBSD changes for Sparc64 and DSO version.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=96
+
+2002-02-05 Frank Warmerdam <warmerdam@pobox.com>
+
+ * config.site/configure: added support for OJPEG=yes option to enable
+ OJPEG support from config.site.
+
+2002-01-27 Frank Warmerdam <warmerdam@pobox.com>
+
+ * html/document.html: fixed links for TIFf 6 docs.
+
+2002-01-18 Frank Warmerdam <warmerdam@pobox.com>
+
+ * config.guess, config.sub: Updated from ftp.gnu.org/pub/config.
+
+ * libtiff/tif_read.c: Fixed TIFFReadEncodedStrip() to fail if the
+ decodestrip function returns anything not greater than zero as per
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=97
+
+ * configure: Modify CheckForBigEndian so it can work in a cross
+ compiled situation.
+
+2002-01-16 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiffdump.c: include TIFFTAG_JPEGTABLES in tag list.
+
+ * tools/tiffset.c: fix bug in error reporting.
+
+ * tools/tiffcp.c: fix several warnings that show up with -Wall.
+
+2002-01-04 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: fixed computation of segment_width for
+ tiles files to avoid error about it not matching the
+ cinfo.d.image_width values ("JPEGPreDecode: Improper JPEG strip/tile
+ size.") for ITIFF files. Apparently the problem was incorporated since
+ 3.5.5, presumably during the OJPEG/JPEG work recently.
+
+2001-12-15 Frank Warmerdam <warmerdam@pobox.com>
+
+ * configure, libtiff/Makefile.in: Changes for building on MacOS 10.1.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=94
+
+ * libtiff/tif_getimage.c: If DEFAULT_EXTRASAMPLE_AS_ALPHA is 1
+ (defined in tiffconf.h - 1 by default) then the RGBA interface
+ will assume that a fourth extra sample is ASSOCALPHA if the
+ EXTRASAMPLE value isn't set for it. This changes the behaviour of
+ the library, but makes it work better with RGBA files produced by
+ lots of applications that don't mark the alpha values properly.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=93
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=65
+
+2001-12-12 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: allow jpeg data stream sampling values to
+ override those from tiff directory. This makes this work with
+ ImageGear generated files.
+
+2001-12-07 Frank Warmerdam <warmerdam@pobox.com>
+
+ * html/Makefile.in: added missing images per bug 92.
+
+ * port/Makefile.in: fixed clean target per bug 92.
+
+2001-11-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * Reissue 3.5.7 release.
+
+ * libtiff/mkversion.c: Fix output of TIFF_VERSION to be
+ YYYYMMDD so that it is increasing over time.
+
+ * Makefile.in: Ensure that tiffvers.h is regenerated in the
+ make release target.
+
+ * Makefile.in: added libtiff/tiffvers.h to the release file list.
+
+2001-11-23 Frank Warmerdam <warmerdam@pobox.com>
+
+ * added html/v3.5.7.html, updated html/index.html.
+
+ * Makefile.in: added contrib/addtiffo/tif_ovrcache.{c,h}.
+
+2001-11-15 Frank Warmerdam <warmerdam@pobox.com>
+
+ * configure: fixed test for -lm.
+
+2001-11-02 Frank Warmerdam <warmerdam@pobox.com>
+
+ * Added PHOTOMETRIC_ITULAB as per bug 90.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=90
+
+2001-10-10 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tiff.h: I have created COMPRESSION_CCITT_T4,
+ COMPRESSION_CCITT_T6, TIFFTAG_T4OPTIONS and TIFFTAG_T6OPTIONS aliases
+ in keeping with TIFF 6.0 standard in tiff.h
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=83
+
+2001-09-26 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirwrite.c: added TIFFRewriteDirectory() function.
+ Updated TIFFWriteDirectory man page to include TIFFRewriteDirectory.
+
+2001-09-24 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_lzw.c: Avoid MS VC++ 5.0 optimization bug.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=78
+
+ * libtiff/tif_lzw.c: added dummy LZWSetupEncode() to report an
+ error about LZW not being available.
+
+ * libtiff/tif_dir.c: propagate failure to initialize compression
+ back from TIFFSetField() as an error status, so applications can
+ detect failure.
+
+ * libtiff/tif_dir.c: removed the auto replacement of
+ COMPRESSION_LZW with COMPRESSION_NONE in _TIFFVSetField().
+
+ * Removed Makefile, tools/Makefile, port/install.sh, man/Makefile
+ from CVS as they are all supposed to be auto-generated by configure.
+
+2001-09-22 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_ojpeg.c: new update from Scott.
+
+2001-09-09 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtif/tif_fax3.c: Removed #ifdef PURIFY logic, and modified to
+ always use the "safe" version, even if there is a very slight
+ cost in performance.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=54
+
+ * libtiff/Makefile.in: Fixed @DSOSUB_VERSION to be @DSOSUF_VERSION@
+ in two places.
+
+ * libtiff/tif_getimage.c: Fixed problem with reading strips or
+ tiles that don't start on a tile boundary. Fix contributed by
+ Josep Vallverdu (from HP), and further described in bug 47.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=47
+
+ * tools/tiff2ps.c: added OJPEG YCbCr to RGB support.
+
+ * libtiff/tif_ojpeg.c: Applied substantial patch from Scott.
+
+2001-09-06 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_packbits.c: fixed memory overrun error.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=77
+
+2001-08-31 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_getimage.c: relax handling of contig case where
+ there are extra samples that are supposed to be ignored. This
+ should now work for 8bit greyscale or palletted images.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=75
+
+2001-08-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_getimage.c: Don't complain for CMYK (separated)
+ images with more than four samples per pixel. See:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=73
+
+2001-08-10 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_getimage.c: Use memmove() instead of TIFFmemcpy()
+ in TIFFReadRGBATile() to avoid issues in cases of overlapping
+ buffers. See Bug 69 in Bugzilla.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=69
+
+ * tools/tiff2rgba.c: fixed getopt() call so that -b works again.
+
+2001-08-09 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tiff.h, libtiff/tif_fax3.c: added check for __LP64__
+ when checking for 64 bit architectures as per bugzilla bug 67.
+
+2001-07-27 Frank Warmerdam <warmerdam@pobox.com>
+
+ * man/Makefile.in: add TIFFClientOpen link as per debian submitted
+ bug 66.
+
+2001-07-20 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_jpeg.c: Define HAVE_BOOLEAN on windows if RPCNDR.H
+ has been included.
+
+2001-07-19 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_open.c: Seek back to zero after failed read,
+ before writing header.
+
+2001-07-18 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_ojpeg.c: updates from Scott. Handles colors
+ much better. Now depends on having patched libjpeg as per
+ patch in contrib/ojpeg/*.
+
+2001-07-17 Frank Warmerdam <warmerdam@pobox.com>
+
+ * */Makefile.in: added DESTDIR support.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=60
+
+2001-07-16 Frank Warmerdam <warmerdam@pobox.com>
+
+ * configure, libtiff/Makefile.in: applied OpenBSD patches
+ as per:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=61
+
+2001-06-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_getimage.c: Fixed so that failure is properly
+ reported by gtTileContig, gtStripContig, gtTileSeparate and
+ gtStripSeparate.
+
+ See http://bugzilla.remotesensing.org/show_bug.cgi?id=51
+
+ * tiffcmp.c: Fixed multi samples per pixel support for ContigCompare.
+ Updated bug section of tiffcmp.1 to note tiled file issues.
+
+ See http://bugzilla.remotesensing.org/show_bug.cgi?id=53
+
+2001-06-22 Frank Warmerdam <warmerdam@pobox.com>
+
+ * configure: Changes for DSO generation on AIX provided by
+ John Marquart <jomarqua@indiana.edu>.
+
+ * configure, libtiff/Makeifle.in: Modified to build DSOs properly
+ on Darwin thanks to Robert Krajewski (rpk@alum.mit.edu) and
+ Keisuke Fujii (fujiik@jlcuxf.kek.jp).
+
+2001-06-13 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tools/tiff2rgba.c: added -n flag to avoid emitting alpha component.
+
+ * man/tiff2rgba.1: new
+
+2001-05-22 Frank Warmerdam <warmerdam@pobox.com>
+
+ * Added tiffset and tif_ojpeg to the dist lists in Makefile.in.
+
+2001-05-13 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tools/thumbnail.c: changed default output compression
+ to packbits from LZW since LZW isn't generally available.
+
+2001-05-12 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_ojpeg.c: New.
+ libtiff/tif_jpeg.c, tiffconf.h, tif_getimage.c: changes related
+ to OJPEG support.
+
+ Scott Marovich <marovich@hpl.hp.com> supplied OJPEG support.
+
+2001-05-11 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tiff.h: removed, it duplicates libtiff/tiff.h.
+
+2001-05-08 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirinfo.c: moved pixar and copyright flags to
+ ensure everything is in order.
+
+ * libtiff/libtiff.def: added TIFFCreateDirectory and
+ TIFFDefaultStripSize as per:
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=46
+
+2001-05-02 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirinfo.c: Modified the TIFF_BYTE definition for
+ TIFFTAG_PHOTOSHOP to use a writecount of TIFF_VARIABLE2 (-3) to
+ force use of uint32 counts instead of short counts.
+
+ * libtiff/tif_dirwrite.c: Added support for TIFF_VARIABLE2 in the
+ case of writing TIFF_BYTE/TIFF_SBYTE fields.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=43
+
+2001-05-01 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_dirinfo.c: removed duplicate TIFFTAG_PHOTOSHOP as per
+ bug report http://bugzilla.remotesensing.org/show_bug.cgi?id=44
+
+2001-04-05 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tiffio.h: removed C++ style comment.
+
+ * configure: fixed up SCRIPT_SH/SHELL handling.
+
+ * Makefile.in: Fixed SCRIPT_SH/SHELL handling.
+
+ * config.guess: documented more variables as per bug 40.
+
+2001-04-03 Frank Warmerdam <warmerdam@pobox.com>
+
+ * configure, *Makefile.in: Various changes to improve configuration
+ for HP/UX specifically, and also in general. They include:
+ - Try to handle /usr/bin/sh instead of /bin/sh where necessary.
+ - Upgrade to HP/UX 10.x+ compiler, linker and dso options.
+ - Fixed mmap() test to avoid MMAP_FIXED ... it isn't available on HP
+ - Use -${MAKEFLAGS} in sub makes from makefiles.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=40
+
+2001-04-02 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tiff.h: Applied hac to try and resolve the problem
+ with the inttypes.h include file on AIX.
+
+ See http://bugzilla.remotesensing.org/show_bug.cgi?id=39
+
+ * VERSION: update to 3.5.7 beta in preparation for release.
+
+ * configure/config.site: modified to check if -lm is needed for
+ MACHDEPLIBS if not supplied by config.site. Needed for Darwin.
+
+ * config.guess: updated wholesale to an FSF version apparently
+ from 1998 (as opposed to 1994). This is mainly inspired by
+ providing for MacOS X support.
+
+2001-03-29 Frank Warmerdam <warmerdam@pobox.com>
+
+ * configure, Makefile.in, etc: added support for OPTIMIZER being
+ set from config.site.
+
+2001-03-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * fax2ps.c: Helge (libtiff at oldach.net) submitted fix:
+
+ Here's a fix for fax2ps that corrects behaviour for non-Letter paper
+ sizes. It fixes two problems:
+
+ Without scaling (-S) the fax is now centered on the page size specified
+ with -H and/or -W. Before, fax2ps was using an obscure and practially
+ useless algorithm to allocate the image relative to Letter sized paper
+ which sometime sled to useless whitespace on the paper, while at the
+ same time cutting of the faxes printable area at the opposite border.
+
+ Second, scaling now preserves aspect ratio, which makes unusual faxes
+ (in particular short ones) print properly.
+
+ See http://bugzilla.remotesensing.org/show_bug.cgi?id=35
+
+ * tiff2ps.c/tiff2ps.1: Substantial changes to tiff2ps by
+ Bruce A. Mallett. See check message for detailed information
+ on all the changes, including a faster encoder, fixes for level
+ 2 PostScript, and support for the imagemask operator.
+
+2001-03-27 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tiffio.h: Changed "#if LOGLUV_PUBLIC" to
+ "#ifdef LOGLUV_PUBLIC" so it will work with VisualAge on AIX.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=39
+
+2001-03-16 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_dirinfo.c: moved definition of copyright tag in field list.
+ Apparently they have to be in sorted order by tag id.
+
+2001-03-13 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_getimage.c: Added support for 16bit minisblack/miniswhite
+ images in RGBA interface.
+
+2001-03-02 Frank Warmerdam <warmerdam@pobox.com>
+
+ * Added TIFFTAG_COPYRIGHT support.
+
+2001-02-19 Frank Warmerdam <warmerdam@pobox.com>
+
+ * Brent Roman contributed updated tiffcp utility (and tiffcp.1)
+ with support for extracting subimages with the ,n syntax, and also
+ adding the -b bias removal flag.
+
+2001-02-16 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/libtiff.def: Brent Roman submitted new version adding
+ serveral missing entry points.
+
+ * libtiff/tif_dirinfo.c: don't declare tiffFieldInfo static on VMS.
+ Some sort of weird VMS thing.
+
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=31
+
+ * tif_luv.c/tiff.h/tiffio.h:
+ New version of TIFF LogLuv (SGILOG) modules contributed by Greg Ward
+ (greg@shutterfly.com). He writes:
+
+ 1) I improved the gamut-mapping function in tif_luv.c for imaginary
+ colors, because some images were being super-saturated on the input
+ side and this resulted in some strange color shifts in the output.
+
+ 2) I added a psuedotag in tiff.h to control random dithering during
+ LogLuv encoding. This is turned off by default for 32-bit LogLuv and
+ on for 24-bit LogLuv output. Dithering improves the average color
+ accuracy over the image.
+
+ 3) I added a #define for LOG_LUV_PUBLIC, which is enabled by default in
+ tiffio.h, to expose internal routines for converting between LogLuv and
+ XYZ coordinates. This is helpful for writing more efficient,
+ specialized conversion routines, especially for reading LogLuv files.
+
+ Changes applied with minor edits.
+
+2001-01-23 Frank Warmerdam <warmerdam@pobox.com>
+
+ * tif_fax3.c: keep rw_mode flag internal to fax3 state to remember
+ whether we are encoding or decoding. This is to ensure graceful
+ recovery if TIFFClientOpen() discovers an attempt to open a compressed
+ file for "r+" access, and subsequently close it, as it resets the
+ tif_mode flag to O_RDONLY in this case to avoid writes, confusing the
+ compressor's concept of whether it is in encode or decode mode.
+
+2001-01-08 Mike Welles <mike@bangstate.com>
+
+ * Makefile.in: Now cleaning up after itself after creating the .tar.gz and .zip
+
+2001-01-07 Frank Warmerdam <warmerdam@pobox.com>
+
+ * html/libtiff.html: Fixed arguments in example for TIFFRGBAImageGet()
+ as per bug report by Patrick Connor.
+
+2000-12-28 Frank Warmerdam <warmerdam@pobox.com>
+
+ * Added RELEASE-DATE file to release file list.
+
+ * Fixed libtiff/makefile.vc to make tiffvers.h not version.h.
+
+2000-12-22 Mike Welles <mike@bangstate.com>
+ * added link to CVS mirror from index.html
+
+ * updated html/internals.html to note that LZW compression is
+ not supported by default.
+
+2000-12-22 Frank Warmerdam <warmerdam@pobox.com>
+
+ * updated html/libtiff.html to not point at Niles' old JPL web site
+ for the man pages, point at www.libtiff.org.
+
+2000-12-21 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/tif_apple.c: Applied "Carbon" support patches supplied by
+ Leonard Rosenthol <leonardr@lazerware.com>. May interfere
+ with correct building on older systems. If so, please let me know.
+
+2000-12-19 Mike Welles <mike@bangsate.com>
+
+ * Took out LZW Encoding from tif_lzw.c
+
+ * Created HOWTO-RELEASE
+
+ * Created html/v3.5.6.html
+
+ * updated index.html
+
+2000-12-01 Frank Warmerdam <warmerdam@pobox.com>
+
+ * Added patches for EOFB support in tif_fax3.c and tif_fax3.h.
+ Patches supplied by Frank Cringle <fdc@cliwe.ping.de>
+ Example file at: ftp://ftp.remotesensing.org/pub/libtiff/eofb_396.tif
+
+2000-11-24 Frank Warmerdam <warmerdam@pobox.com>
+
+ * libtiff/Makefile.in: Added an installPrivateHdrs and install-private
+ target so that the private headers required by libgeotiff can be
+ installed with the others. They are not installed by default.
+
+ * libtiff/Makefile.in: Added @MACHLIBDEPS@ to LINUXdso and GNULDdso
+ targets so libtiff.so will be built with an explicit dependency
+ on libm.so.
+
+ * libtiff/Makefile.in: Use softlinks to link libtiff.so.3 to
+ libtiff.so.3.5.5.
+
+ * libtiff/Makefile.in & configure: Remove all references to the ALPHA
+ file, or ALPHA version logic. Added stuff about DIST_POINT in
+ place of DIST_TYPE and the alpha release number stuff.
+
+2000-11-22 Frank Warmerdam <warmerdam@pobox.com>
+
+ * I have applied a patch from Steffen Moeller <moeller@ebi.ac.uk> to
+ the configure script so that it now accepts the --prefix, and
+ --exec-prefix directives.
+
+2000-11-13 Frank Warmerdam <warmerda@cs46980-c>
+
+ * I have made a variety of modifications in an effort to ensure the
+ TIFFLIB_VERSION macro is automatically generated from the RELEASE-DATE
+ file which seems to be updated regularly.
+
+ o mkversion.c now reads RELEASE-DATE and emits TIFFLIB_VERSION in
+ version include file.
+ o renamed version.h to tiffvers.h because we now have to install it
+ with the public libtiff include files.
+ o include tiffvers.h in tiffio.h.
+ o updated tif_version.c to use tiffvers.h.
+ o Updated Makefile.in accordingly.
+
+ * As per http://bugzilla.remotesensing.org/show_bug.cgi?id=25
+ I have updated the win32 detection rules in tiffcomp.h.
+
+2000-10-20 Frank Warmerdam <warmerda@cs46980-c>
+
+ * tif_getimage.c: Fixed RGBA translation for YCbCr images for which
+ the strip/tile width and height aren't multiples of the sampling size.
+ See http://bugzilla.remotesensing.org/show_bug.cgi?id=20
+ Some patches from Rick LaMont of Dot C Software.
+
+ * Modified tif_packbits.c encoder to avoid compressing more
+ data than provided if rowsize doesn't factor into provided data
+ (such as occurs for YCbCr).
+
+2000-10-19 Frank Warmerdam <warmerda@cs46980-c>
+
+ * tools/rgb2ycbcr.c: fixed output strip size to account for vertical
+ roundup if rows_per_strip not a multiple of vertical sample size.
+
+2000-10-16 Frank Warmerdam <warmerda@cs46980-c>
+
+ * tif_dir.c: Clear TIFF_ISTILED flag in TIFFDefaultDirectory
+ as per http://bugzilla.remotesensing.org/show_bug.cgi?id=18
+ from vandrove@vc.cvut.cz.
+
+ * Modified tif_packbits.c decoding to avoid overrunning the
+ output buffer, and to issue a warning if data needs to be
+ discarded. See http://bugzilla.remotesensing.org/show_bug.cgi?id=18
+
+2000-10-12 Frank Warmerdam <warmerda@cs46980-c>
+
+ * Modified tiff2bw to ensure portions add to 100%, and that
+ white is properly recovered.
+
+ See bug http://bugzilla.remotesensing.org/show_bug.cgi?id=15
+ Patch c/o Stanislav Brabec <utx@penguin.cz>
+
+2000-09-30 Frank Warmerdam <warmerda@cs46980-c>
+
+ * Modified TIFFClientOpen() to emit an error on an attempt to
+ open a comperessed file for update (O_RDWR/r+) access. This is
+ because the compressor/decompressor code gets very confused when
+ the mode is O_RDWR, assuming this means writing only. See
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=13
+
+2000-09-27 Frank Warmerdam <warmerda@cs46980-c>
+
+ * Added GNULDdso target an`d switched linux and freebsd to use it.
+
+2000-09-26 Frank Warmerdam <warmerda@cs46980-c>
+
+ * Applied patch for 0x0000 sequences in tif_fax3.h's definition
+ of EXPAND1D() as per bug 11 (from Roman).
+
+2000-09-25 Frank Warmerdam <warmerda@cs46980-c>
+ * Fixed tiffcomp.h to avoid win32 stuff if unix #defined, to improve
+ cygwin compatibility.
+
+ * Applied patch from Roman Shpount to tif_fax3.c. This seems to
+ be a proper fix to the buffer sizing problem. See
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=11
+
+ * Fixed tif_getimage.c to fix overrun bug with YCbCr images without
+ downsampling. http://bugzilla.remotesensing.org/show_bug.cgi?id=10
+ Thanks to Nick Lamb <njl98r@ecs.soton.ac.uk> for reporting the
+ bug and proving the patch.
+
+2000-09-18 Frank Warmerdam <warmerda@cs46980-c>
+
+ * Fixed tif_jpeg.c so avoid destroying the decompressor before
+ we are done access data thanks to bug report from:
+ Michael Eckstein <eckstein@gepro.cz>.
+
+ * Reverted tif_flush change.
+
+2000-09-14 Frank Warmerdam <warmerda@cs46980-c>
+
+ * tif_flush.c: Changed so that TIFFFlushData() doesn't return an
+ error when TIFF_BEENWRITING is not set. This ensures that the
+ directory contents can still be flushed by TIFFFlush().
+
+2000-08-14 Frank Warmerdam <warmerda@rommel.atlsci.com>
+
+ * tif_open.c: Don't set MMAP for O_RDWR files.
+
+ * tif_open.c: Set STRIPCHOP_DEFAULT for O_RDWR as well as O_RDONLY
+ so that files opened for update can be strip chopped too.
+
+ * tif_read.c: fixed up bug with files missing rowsperstrip and
+ the strips per separation fix done a few weeks ago.
+
+2000-07-17 Frank Warmerdam <warmerda@cs46980-c>
+
+ * Tentatively added support for SAMPLEFORMAT_COMPLEXIEEEFP, and
+ SAMPLEFORMAT_COMPLEXINT.
+
+2000-07-13 Mike Welles <mike@onshore.com>
+
+ * index.html, bugs.html: added bugzilla info.
+
+2000-07-12 Frank Warmerdam <warmerda@rommel.atlsci.com>
+
+ * tif_read.c: fix subtle bug with determining the number of
+ rows for strips that are the last strip in a separation but
+ not the last strip of all in TIFFReadEncodedStrip().
+
+ * Applied 16/32 bit fix to tif_fax3.c. Fix supplied by
+ Peter Skarpetis <peters@serendipity-software.com.au>
+
+2000-06-15 Frank Warmerdam <warmerda@rommel.atlsci.com>
+
+ * Modified tiffio.h logic with regard to including windows.h. It
+ won't include it when building with __CYGWIN__.
+
+2000-05-11 Frank Warmerdam <warmerda@cs46980-c>
+
+ * README: update to mention www.libtiff.org, don't list Sam's old
+ email address.
+
+ * configure: Fixed DSO test for Linux as per patch from
+ Jan Van Buggenhout <chipzz@Ace.ULYSSIS.Student.KULeuven.Ac.Be>.
+
+2000-04-21 Frank Warmerdam <warmerda@rommel.atlsci.com>
+
+ * libtiff/tif_dirread.c: Don't use estimate strip byte count for
+ one tile/strip images with an offset, and byte count of zero. These
+ could be "unpopulated" images.
+
+2000-04-18 Frank Warmerdam <warmerda@rommel.atlsci.com>
+
+ * contrib/addtiffo: Added "averaging" resampling option.
+
+ * tools/tiffsplit.c: Copy TIFFTAG_SAMPLEFORMAT.
+
+Tue Apr 18 16:18:08 2000 Frank Warmerdam <warmerda@esabot.atlsci.com>
+
+ * tools/Makefile.in: Modified to install properly on SGI.
+
+2000-04-12 Mike Welles <mike@onshore.com>
+ * configure: Fixed stupid mistake in libc6 test on Linux
+
+2000-04-04 Mike Welles <mike@onshore.com>
+ * tif_win32.c: Applied patch to fix overreads and ovverwrites
+ caught by BoundsChecker. From Arvan Pritchard
+ <arvan.pritchard@infomatix.co.uk> (untested).
+
+ * tif_getimage.c: Applied patch to silence VC6 warnings. From
+ Arvan Pritchard <arvan.pritchard@informatix.co.uk>
+
+ * tif_lzw.c: Applied patch to silence VC6 warnings. From
+ Arvan Pritchard <arvan.pritchard@informatix.co.uk>
+
+2000-03-28 Frank Warmerdam <warmerda@cs46980-c>
+
+ * Added contrib/stream (stream io) code submitted by Avi Bleiweiss.
+
+2000-03-28 Frank Warmerdam <warmerda@cs46980-c> *** 3.5.5 release ***
+
+ * fax2ps: Fixed mixup of width and height in bounding box statement
+ as per submission by Nalin Dahyabhai <nalin@redhat.com>.
+
+2000-03-27 Mike Welles <mike@onshore.com>
+
+ * fax2ps: Modified printruns to take uint32 instead of uint16.
+ Patch courtesy of Bernt Herd <herd@herdsoft.com>
+
+2000-03-20 Mike Welles <mike@onshore.com>
+
+ * configure: added test for libc6 for linux targets. Bug reported by
+ Stanislav Brabec <utx@k332.feld.cvut.cz>
+
+ * Added 3.5 docs to html/Makefile.in.
+ Thanks to Stanislav Brabec <utx@k332.feld.cvut.cz>
+
+ * configure: fixed bugs in sed scripts
+ (applied sed script s:/@:s;@:;s:/s;;:;: to configure).
+ fix submitted to Stanislav Brabec <utx@k332.feld.cvut.cz>
+
+ * tools/iptcutil was not in files list, and wasn't being
+ added to tar archive. Updated Makefile.in.
+
+2000-03-17 Frank Warmerdam <warmerda@cs46980-c>
+
+ * tif_fax3.c: Fixed serious bug introduced during the uint16->uint32
+ conversion for the run arrays.
+
+2000-03-03 Frank Warmerdam <warmerda@cs46980-c.mtnk1.on.wave.home.com>
+
+ * Set td_sampleformat default to SAMPLEFORMAT_UINT instead of
+ SAMPLEFORMAT_VOID in TIFFDefaultDirectory() in tif_dir.c.
+
+2000-03-02 Frank Warmerdam <warmerda@cs46980-c.mtnk1.on.wave.home.com>
+
+ * Added "GetDefaulted" support for TIFFTAG_SAMPLEFORMAT in tif_aux.c.
+
+ * Patched tif_fax3.c so that dsp->runs is allocated a bit bigger
+ to avoid overruns encountered with frle_bug.tif.
+
+Tue Feb 15 22:01:05 2000 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Fixed tools/tiffcmp so that stopondiff testing works.
+ Patch care of Joseph Orost <joe@sanskrit.lz.att.com>.
+
+2000-01-28 <warmerda@CS46980-B>
+
+ * Modified tif_unix.c to support 2-4GB seeks if USE_64BIT_API is
+ set to 1, and added default (off) setting in tiffconf.h. This
+ should eventually be set by the configure script somehow.
+
+ The original work on all these 2-4GB changes was done by
+ Peter Smith (psmith@creo.com).
+
+ * Modified tif_win32.c to support 2-4GB seeks.
+
+ * tentatively changed toff_t to be unsigned instead of signed to
+ facilitate support for 2-4GB files.
+
+ * Updated a variety of files to use toff_t. Fixed some mixups
+ between toff_t and tsize_t.
+
+Fri Jan 28 10:13:49 2000 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Largely reimplemented contrib/addtiffo to avoid temp files,
+ updating the TIFF file in place. Fixed a few other bugs to.
+
+ * Set tif_rawdatasize to zero when freeing raw data buffer in
+ TIFFWriteDirectory().
+
+ * Enabled "REWRITE_HACK" in tif_write.c by default.
+
+ * Fix bug in tif_write.c when switching between reading one directory
+ and writing to another.
+
+ * Made TIFFWriteCheck() public, and added TIFFCreateDirectory()
+
+Wed Jan 5 12:37:48 2000 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added TIFFmemory(3t) functions to libtiff.def.
+
+Tue Jan 4 13:39:00 2000 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added libtiff/libtiff.def to TIFFILES distribution list.
+
+Mon Dec 27 12:13:39 EST 1999 Mike Welles <mike@onshore.com>
+
+ * Created lzw compression kit, as a new module (libtiff-lzw-compression-kit).
+
+ * Altered descriptions in tools to reflect "by default" lzw not supported
+
+ * Updated index.html to note lzw compression kit.
+
+Tue Dec 21 14:01:51 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added fax3sm_winnt.c to distribution list in Makefile.in.
+
+Tue Dec 21 11:04:45 EST 1999 Mike Welles <mike@onshore.com> *** 3.5.4 release ***
+
+ * Aadded Pixar tag support. Contributed by Phil Beffery <phil@pixar.com>
+
+ * Made one more change to tif_dir.c for removal of LZW compression. Also added notice
+ when LZW compression invoked.
+
+ * Changed default compression in tools to TIFF_PACKBITS, and changed usage descriptions
+ in tools to reflect removal of LZW compression
+
+Mon Dec 20 18:39:02 EST 1999 Mike Welles <mike@onshore.com>
+
+ * Fixed bug that caused LZW (non) compression to segfault. Added
+ warning about LZW compression removed being removed, and why.
+
+ * Added nostrip to install in tools/Makefile.in so that debugging
+ symbols are kept.
+
+Tue Dec 7 12:04:47 EST 1999 Mike Welles <mike@onshore.com>
+
+ * Added patch from Ivo Penzar <ivo.penzar@infolink-software.com>,
+ supporting Adobe ZIP deflate. Untested.
+
+Sat Dec 4 15:47:11 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Made Packbits the default compression in tools/tiff2rgba.c instead
+ of LZW.
+
+Tue Nov 30 14:41:43 1999 Frank Warmerdam <warmerda@gdal.velocet.ca> *** 3.5.3. release ***
+
+ * Added tif_luv to contrib/djgpp/Makefile.lib.
+
+Tue Nov 30 14:15:32 EST 1999 Mike Welles <mike@onshore.com>
+
+ * Added zip creation to relase makefile target
+
+ * Added html for TIFFWriteTile.3t man page.
+
+Tue Nov 30 09:20:16 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added some changes to tif_write.c to support rewriting existing
+ fixed sized tiles and strips. Code mods disabled by default, only
+ enabled if REWRITE_HACK is defined for now.
+
+Mon Nov 29 11:43:42 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added TIFFWriteTile.3t man page.
+
+Sun Nov 28 20:36:18 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added notes on use of makefile.vc in build.html, and fixed
+ email subscription address.
+
+199-11-28 Mike Welles <mike@onshore.com>
+
+ * Fixed apocalypse-inducing y2k bug in contrib/ras/ras2tiff.c
+
+ * Did some casts cleaning up to reduce compiler warnings in tif_fax3.c,
+ from Bruce Carmeron <cameron@petris.com> -- modifications of
+ changes made by Frank (sun cc still complained on cast).
+
+ * Added tiffconf.h to install target per request from Bill
+ Radcliffe <billr@corbis.com>: "We need a way for ImageMagick to
+ know features have been compiled into the TIFF library in order to
+ handle things properly".
+
+Sat Nov 27 16:49:21 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * fixed various VC++ warnings as suggested by Gilles Vollant
+ <info@winimage.com>.
+
+Wed Nov 24 12:08:16 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Modified TIFFquery.3t man pages info on TIFFIsByteSwapped() to
+ not imply applications are responsible for image data swapping.
+
+1999-11-22 Mike Welles <mike@onshore.com>
+ * HTML-ized the man pages, added to html/man
+
+ * Removed LZW Compression to comply with Unisys patent extortion.
+
+1999-09-29 Mike Welles <mike@onshore.com>
+ * Corrected one remaining 16 -> 32 bit value in tif_fax3.c,
+ From Ivo Penzar <ivo.penzar@infolink-software.com.
+
+ * Added patch from Ivo Penzar to have TiffAdvanceDirectory handle
+ memory mapped files. <ivo.penzar@infolink-software.com>
+
+1999-09-26 Mike Welles <mike@onshore.com> *** 3.5.2 release ***
+ * Corrected alpha versioning.
+
+ * Removed distinction between alpha and release targets in Makefile.in.
+
+ * added release.stamp target, which tags cvs tree, and updates
+ "RELEASE-DATE"
+
+ * added releasediff target, which diffs tree with source as of
+ date in "RELEASE-DATE"
+
+ * Ticked up version to 3.5.2 (alpha 01 -- but I think we'll moving
+ away from alpha/non-alpha distinctions).
+
+ * updated html to reflect release
+
+1999-09-23 <warmerda@CS46980-B>
+
+ * Set O_BINARY for tif_unix.c open() ... used on cygwin for instance.
+
+ * Added CYGWIN case in configure.
+
+Fri Sep 17 00:13:51 CEST 1999 Mike Welles <mike@onshore.com>
+
+ * Applied Francois Dagand's patch to handle fax decompression bug.
+ (sizes >= 65536 were failing)
+
+Tue Sep 14 21:31:43 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Applied "a" mode fix to tif_win32.c/TIFFOpen() as suggested
+ by Christopher Lawton <clawton@mathworks.com>
+
+Wed Sep 8 08:19:18 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added IRIX/gcc, and OSF/1 4.x support on behalf of
+ Albert Chin-A-Young <china@thewrittenword.com>
+
+ * Added TIFFReassignTagToIgnore() API on behalf of
+ Bruce Cameron <cameron@petris.com>. Man page still pending.
+
+Wed Aug 25 11:39:07 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added test target in Makefile, test_pics.sh script and pics/*.rpt
+ files to provide for a rudimentary testsuite.
+
+ * Added contrib/tags back from old distribution ... fixed up a bit.
+
+1999-08-16 <warmerda@CS46980-B>
+
+ * Added simple makefile.vc makefiles for building with MS VC++
+ on Windows NT/98/95 in console mode. Stuff in contrib/win* make give
+ better solutions for some users.
+
+Mon Aug 16 21:52:11 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * Added addtiffo (add overviews to a TIFF file) in contrib. Didn't
+ put it in tools since part of it is in C++.
+
+1999-08-16 Michael L. Welles <mike@kurtz.fake>
+
+ * Updated html/index.html with anon CVS instructions.
+
+Mon Aug 16 13:18:41 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
+
+ * pre-remove so link before softlink in LINUXdso action in
+ libtiff/Makefile.in to avoid failure on LINUXdso builds other than
+ the first.
+
+ * Fixed problem with cvtcmap() in tif_getimage.c modifying the
+ colormaps owned by the TIFF handle itself when trying to fixup wrong
+ (eight bit) colormaps. Corrected by maintaining a private copy of
+ the colormap.
+
+ * Added TIFFReadRGBATile()/TIFFReadRGBAStrip() support in
+ tif_getimage.c.
+
+ * CVS Repository placed at remotesensing.org. ChangeLog added.
diff --git a/tiff/HOWTO-RELEASE b/tiff/HOWTO-RELEASE
new file mode 100644
index 0000000..4bf4de7
--- /dev/null
+++ b/tiff/HOWTO-RELEASE
@@ -0,0 +1,105 @@
+HOWTO-RELEASE:
+
+Notes on releasing.
+
+0. Make sure that you have current FSF releases of autoconf, automake,
+ and libtool packages installed under a common installation prefix
+ and that these tools are in your executable search path prior to
+ any other installed versions. Versions delivered with Linux may be
+ altered so it is best to install official FSF releases. GNU 'm4'
+ 1.4.6 or later is needed in order to avoid bugs in m4. These
+ packages may be downloaded from the following ftp locations:
+
+ autoconf - ftp://ftp.gnu.org/pub/gnu/autoconf
+ automake - ftp://ftp.gnu.org/pub/gnu/automake
+ libtool - ftp://ftp.gnu.org/pub/gnu/libtool
+
+ Release builds should only be done on a system with a functioning
+ and correctly set system clock and on a filesystem which accurately
+ records file update times. Use of GNU make is recommended.
+
+1. Commit any unsaved changes.
+
+2. Create html/vX.X.html. Take ChangeLog entries and html-ify in there.
+ Easist thing to do is take html/vX.(X-1).html and use it as a template.
+ Add that file to the list of EXTRA_DIST files in the html/Makefile.am.
+
+3. Update html/index.html to refer to this new page as the current release.
+
+4. Increment the release version in configure.ac. Put 'alpha' or
+ 'beta' after the version, if applicable. For example:
+
+ 3.9.1
+ or
+ 3.9.1beta
+
+ Version should be updated in two places: in the second argument of the
+ AC_INIT macro and in LIBTIFF_xxx_VERSION variables.
+
+5. Add an entry to Changelog similar to:
+
+ * libtiff 3.9.1 released.
+
+6. In the source tree do
+
+ ./autogen.sh
+
+ This step may be skipped if you have already been using a
+ maintainer build with current autoconf, automake, and libtool
+ packages. It is only needed when updating tool versions.
+
+7. It is recommended (but not required) to build outside of the source
+ tree so that the source tree is kept in a pristine state. This
+ also allows sharing the source directory on several networked
+ systems. For example:
+
+ mkdir libtiff-build
+ cd libtiff-build
+ /path/to/libtiff/configure --enable-maintainer-mode
+
+ otherwise do
+
+ ./configure --enable-maintainer-mode
+
+8. In the build tree do
+
+ make release
+
+ This will update "RELEASE-DATE", "VERSION", and libtiff/tiffvers.h
+ in the source tree.
+
+9. In the source tree, verify that the version info in RELEASE-DATE,
+ VERSION and libtiff/tiffvers.h is right.
+
+10. In the build tree do
+
+ make
+ make distcheck
+
+ If 'make distcheck' fails, then correct any issues until it
+ succeeds.
+
+ Two files with names tiff-version.tar.gz and tiff-version.zip will
+ be created in the top level build directory.
+
+11. In the source tree do
+
+ 'cvs commit'.
+
+12. In the source tree do
+
+ cvs tag Release-v3-9-2
+
+ (or the appropriate name for the release)
+
+13. Copy release packages from the build tree to the
+ ftp.remotesensing.org ftp site.
+
+ scp tiff-*.tar.gz tiff-*.zip \
+ frankw@upload.osgeo.org:/osgeo/download/libtiff
+
+14. Announce to list, tiff@lists.maptools.org
+
+15. Update libtiff page on freshmeat with new version announcement.
+
+
diff --git a/tiff/Jamfile b/tiff/Jamfile
new file mode 100644
index 0000000..3cd3113
--- /dev/null
+++ b/tiff/Jamfile
@@ -0,0 +1,73 @@
+
+PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+#PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ;
+
+# Run configure if it seems to be needed
+if $(UNIX) {
+ DEFINES += "unix" ; # libtiff assumes this
+ # Genfile actually creates libtiff/tif_config.h and libtiff/tiffconf.h:
+ GenFileNND libtiff/tif_config.h :
+ "(cd $(SUBDIR); chmod +x configure ; ./configure --disable-old-jpeg --disable-pixarlog --disable-zlib --disable-jbig)" : configure ;
+# "(cd $(SUBDIR); chmod +x configure ; ./configure --disable-jpeg --disable-old-jpeg --disable-pixarlog --disable-zlib --disable-jbig)" : configure ;
+ # Workaround Jam problem of two products from one action:
+ FakeFile libtiff/tiffconf.h : libtiff/tif_config.h ;
+}
+
+# else copy them
+if $(NT) {
+ File libtiff/tiffconf.h : libtiff/tiffconf.vc.h ;
+ File libtiff/tif_config.h : libtiff/tif_config.vc.h ;
+}
+
+ObjectKeep port/getopt.c ;
+
+# support library for generation utilities
+#Library libport.lib : [ CatPaths port : getopt.c strcasecmp.c strtoul.c ] ;
+if $(UNIX) {
+ Library libport.lib : [ CatPaths port : strcasecmp.c ] ;
+} else {
+ Library libport.lib : [ CatPaths port : getopt.c strcasecmp.c ] ;
+}
+
+# generation utilities
+Main mkg3states : libtiff/mkg3states.c ;
+LinkLibraries mkg3states : libport.lib ;
+GenFileND libtiff/tif_fax3sm.c : mkg3states -c const [ NormPaths libtiff/tif_fax3sm.c ] ;
+
+# tiff library
+LIBSRCS = tif_fax3.c tif_aux.c tif_close.c tif_codec.c tif_fax3sm.c tif_predict.c
+ tif_compress.c tif_dir.c tif_dirinfo.c tif_dirread.c tif_dirwrite.c
+ tif_dumpmode.c tif_error.c tif_getimage.c tif_flush.c tif_luv.c
+ tif_lzw.c tif_next.c tif_open.c tif_packbits.c tif_print.c
+ tif_read.c tif_swab.c tif_strip.c tif_thunder.c tif_tile.c
+ tif_version.c tif_warning.c tif_write.c tif_extension.c
+ tif_jpeg.c tif_ojpeg.c ;
+
+if $(UNIX) {
+ LIBSRCS += tif_unix.c ;
+} else {
+ LIBSRCS += tif_msdos.c ;
+}
+
+# Optional codecs not included
+# tif_zip.c
+# tif_pixarlog.c
+Library libtiff.lib : [ CatPaths libtiff : $(LIBSRCS) ] : : : $(JPEGINC) libtiff : ;
+
+#Library library : sources : flags : defines : hdrpaths : objects
+
+# copy header file to lib directory
+File tiffconf.h : libtiff/tiffconf.h ;
+#File tif_config.h : libtiff/tif_config.h ;
+File tiffvers.h : libtiff/tiffvers.h ;
+File tiffio.h : libtiff/tiffio.h ;
+File tiff.h : libtiff/tiff.h ;
+# Because we're copying them, Jam doesn't scan them, so
+# we have to set the co-dependencies explicitly :-(
+NIncludes tiff.h : tiffconf.h ;
+NIncludes tiffio.h : tiff.h tiffvers.h ;
+
+# Compile some of the tools
+SubInclude tools ;
+
diff --git a/tiff/Makefile.am b/tiff/Makefile.am
new file mode 100644
index 0000000..7069094
--- /dev/null
+++ b/tiff/Makefile.am
@@ -0,0 +1,56 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+docdir = $(LIBTIFF_DOCDIR)
+
+AUTOMAKE_OPTIONS = 1.11 dist-zip foreign
+ACLOCAL_AMFLAGS = -I m4
+
+docfiles = \
+ COPYRIGHT \
+ ChangeLog \
+ README \
+ README.vms \
+ RELEASE-DATE \
+ TODO \
+ VERSION
+
+EXTRA_DIST = \
+ HOWTO-RELEASE \
+ Makefile.vc \
+ SConstruct \
+ autogen.sh \
+ configure.com \
+ nmake.opt
+
+dist_doc_DATA = $(docfiles)
+
+SUBDIRS = port libtiff tools build contrib test man html
+
+release:
+ (rm -f $(top_srcdir)/RELEASE-DATE && echo $(LIBTIFF_RELEASE_DATE) > $(top_srcdir)/RELEASE-DATE)
+ (rm -f $(top_srcdir)/VERSION && echo $(LIBTIFF_VERSION) > $(top_srcdir)/VERSION)
+ (rm -f $(top_srcdir)/libtiff/tiffvers.h && sed 's,LIBTIFF_VERSION,$(LIBTIFF_VERSION),;s,LIBTIFF_RELEASE_DATE,$(LIBTIFF_RELEASE_DATE),' $(top_srcdir)/libtiff/tiffvers.h.in > $(top_srcdir)/libtiff/tiffvers.h)
+
diff --git a/tiff/Makefile.in b/tiff/Makefile.in
new file mode 100644
index 0000000..7e96cf3
--- /dev/null
+++ b/tiff/Makefile.in
@@ -0,0 +1,842 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = .
+DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(top_srcdir)/configure ChangeLog TODO config/compile \
+ config/config.guess config/config.sub config/depcomp \
+ config/install-sh config/ltmain.sh config/missing \
+ config/mkinstalldirs
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(docdir)"
+DATA = $(dist_doc_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir dist dist-all distcheck
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ { test ! -d "$(distdir)" \
+ || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -fr "$(distdir)"; }; }
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+DIST_ARCHIVES = $(distdir).tar.gz $(distdir).zip
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = $(LIBTIFF_DOCDIR)
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = 1.11 dist-zip foreign
+ACLOCAL_AMFLAGS = -I m4
+docfiles = \
+ COPYRIGHT \
+ ChangeLog \
+ README \
+ README.vms \
+ RELEASE-DATE \
+ TODO \
+ VERSION
+
+EXTRA_DIST = \
+ HOWTO-RELEASE \
+ Makefile.vc \
+ SConstruct \
+ autogen.sh \
+ configure.com \
+ nmake.opt
+
+dist_doc_DATA = $(docfiles)
+SUBDIRS = port libtiff tools build contrib test man html
+all: all-recursive
+
+.SUFFIXES:
+am--refresh:
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)"
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(docdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(docdir)" && rm -f $$files
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d "$(distdir)" || mkdir "$(distdir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -test -n "$(am__skip_mode_fix)" \
+ || find "$(distdir)" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+ $(am__remove_distdir)
+
+dist-lzma: distdir
+ tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+ $(am__remove_distdir)
+
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
+ $(am__remove_distdir)
+
+dist-tarZ: distdir
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__remove_distdir)
+
+dist-shar: distdir
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__remove_distdir)
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+dist dist-all: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lzma*) \
+ unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir); chmod a+w $(distdir)
+ mkdir $(distdir)/_build
+ mkdir $(distdir)/_inst
+ chmod a-w $(distdir)
+ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build \
+ && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @$(am__cd) '$(distuninstallcheck_dir)' \
+ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-libtool \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am am--refresh check check-am clean clean-generic \
+ clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \
+ dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
+ distcheck distclean distclean-generic distclean-libtool \
+ distclean-tags distcleancheck distdir distuninstallcheck dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-recursive uninstall uninstall-am \
+ uninstall-dist_docDATA
+
+
+release:
+ (rm -f $(top_srcdir)/RELEASE-DATE && echo $(LIBTIFF_RELEASE_DATE) > $(top_srcdir)/RELEASE-DATE)
+ (rm -f $(top_srcdir)/VERSION && echo $(LIBTIFF_VERSION) > $(top_srcdir)/VERSION)
+ (rm -f $(top_srcdir)/libtiff/tiffvers.h && sed 's,LIBTIFF_VERSION,$(LIBTIFF_VERSION),;s,LIBTIFF_RELEASE_DATE,$(LIBTIFF_RELEASE_DATE),' $(top_srcdir)/libtiff/tiffvers.h.in > $(top_srcdir)/libtiff/tiffvers.h)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/Makefile.vc b/tiff/Makefile.vc
new file mode 100644
index 0000000..894f9ab
--- /dev/null
+++ b/tiff/Makefile.vc
@@ -0,0 +1,65 @@
+# $Id: Makefile.vc,v 1.6 2006/10/13 10:30:21 dron Exp $
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+# Makefile for MS Visual C and Watcom C compilers.
+# Edit nmake.opt file if you want to ajust building options.
+#
+# To build:
+# C:\libtiff> nmake /f makefile.vc
+
+!INCLUDE nmake.opt
+
+all: port lib tools
+
+port::
+ cd port
+ $(MAKE) /f Makefile.vc
+ cd..
+
+lib: port
+ cd libtiff
+ $(MAKE) /f Makefile.vc
+ cd..
+
+tools: lib
+ cd tools
+ $(MAKE) /f Makefile.vc
+ cd ..
+
+clean:
+ -del *.exe.manifest
+ cd port
+ $(MAKE) /f Makefile.vc clean
+ cd..
+ cd libtiff
+ $(MAKE) /f Makefile.vc clean
+ cd..
+ cd tools
+ $(MAKE) /f Makefile.vc clean
+ cd ..
+
+ -del *.ilk
+ -del *.dll.manifest
+ -del *.exe.manifest
+ -del *.exp
+ -del *.pdb
diff --git a/tiff/README b/tiff/README
new file mode 100644
index 0000000..c0e5521
--- /dev/null
+++ b/tiff/README
@@ -0,0 +1,59 @@
+$Header: /cvs/maptools/cvsroot/libtiff/README,v 1.5 2004/10/30 13:44:45 dron Exp $
+
+
+TIFF Software Distribution
+--------------------------
+This file is just a placeholder; all the documentation is now in
+HTML in the html directory. To view the documentation point your
+favorite WWW viewer at html/index.html; e.g.
+
+ netscape html/index.html
+
+If you don't have an HTML viewer then you can read the HTML source
+or fetch a PostScript version of this documentation from the directory
+
+ ftp://ftp.remotesensing.org/pub/libtiff/
+
+If you can't hack either of these options then basically what you
+want to do is:
+
+ % ./configure
+ % make
+ % su
+ # make install
+
+More information, email contacts, and mailing list information can be
+found online at http://www.remotesensing.org/libtiff/.
+
+
+Use and Copyright
+-----------------
+Silicon Graphics has seen fit to allow us to give this work away. It
+is free. There is no support or guarantee of any sort as to its
+operations, correctness, or whatever. If you do anything useful with
+all or parts of it you need to honor the copyright notices. I would
+also be interested in knowing about it and, hopefully, be acknowledged.
+
+The legal way of saying that is:
+
+Copyright (c) 1988-1997 Sam Leffler
+Copyright (c) 1991-1997 Silicon Graphics, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation for any purpose is hereby granted without fee, provided
+that (i) the above copyright notices and this permission notice appear in
+all copies of the software and related documentation, and (ii) the names of
+Sam Leffler and Silicon Graphics may not be used in any advertising or
+publicity relating to the software without the specific, prior written
+permission of Sam Leffler and Silicon Graphics.
+
+THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
diff --git a/tiff/README.vms b/tiff/README.vms
new file mode 100644
index 0000000..44d9663
--- /dev/null
+++ b/tiff/README.vms
@@ -0,0 +1,12 @@
+Dear OpenVMS user
+to make this library, execute
+$@CONFIGURE
+$@BUILD
+
+Build process should be error and warning free. When process will be finished,
+LIBTIFF$STRATUP.COM file containing all required definitions, will be created.
+Please call it from system startup procedure or individual user procedure LOGIN.COM
+To link software with libtiff, use TIFF:LIBTIFF.OPT
+
+best regards,
+Alexey Chupahin, elvis_75@mail.ru
diff --git a/tiff/RELEASE-DATE b/tiff/RELEASE-DATE
new file mode 100644
index 0000000..a1b1eb9
--- /dev/null
+++ b/tiff/RELEASE-DATE
@@ -0,0 +1 @@
+20100615
diff --git a/tiff/SConstruct b/tiff/SConstruct
new file mode 100644
index 0000000..682246e
--- /dev/null
+++ b/tiff/SConstruct
@@ -0,0 +1,171 @@
+# $Id: SConstruct,v 1.4 2007/02/24 15:03:47 dron Exp $
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2005, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# This file contains rules to build software with the SCons tool
+# (see the http://www.scons.org/ for details on SCons).
+
+import os
+
+env = Environment()
+
+# Read the user supplied options
+opts = Options('libtiff.conf')
+opts.Add(PathOption('PREFIX', \
+ 'install architecture-independent files in this directory', \
+ '/usr/local', PathOption.PathIsDirCreate))
+opts.Add(BoolOption('ccitt', \
+ 'enable support for CCITT Group 3 & 4 algorithms', \
+ 'yes'))
+opts.Add(BoolOption('packbits', \
+ 'enable support for Macintosh PackBits algorithm', \
+ 'yes'))
+opts.Add(BoolOption('lzw', \
+ 'enable support for LZW algorithm', \
+ 'yes'))
+opts.Add(BoolOption('thunder', \
+ 'enable support for ThunderScan 4-bit RLE algorithm', \
+ 'yes'))
+opts.Add(BoolOption('next', \
+ 'enable support for NeXT 2-bit RLE algorithm', \
+ 'yes'))
+opts.Add(BoolOption('logluv', \
+ 'enable support for LogLuv high dynamic range encoding', \
+ 'yes'))
+opts.Add(BoolOption('strip_chopping', \
+ 'support for strip chopping (whether or not to convert single-strip uncompressed images to mutiple strips of ~8Kb to reduce memory usage)', \
+ 'yes'))
+opts.Add(BoolOption('extrasample_as_alpha', \
+ 'the RGBA interface will treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many packages produce RGBA files but don\'t mark the alpha properly', \
+ 'yes'))
+opts.Add(BoolOption('check_ycbcr_subsampling', \
+ 'disable picking up YCbCr subsampling info from the JPEG data stream to support files lacking the tag', \
+ 'yes'))
+opts.Update(env)
+opts.Save('libtiff.conf', env)
+Help(opts.GenerateHelpText(env))
+
+# Here are our installation paths:
+idir_prefix = '$PREFIX'
+idir_lib = '$PREFIX/lib'
+idir_bin = '$PREFIX/bin'
+idir_inc = '$PREFIX/include'
+idir_doc = '$PREFIX/doc'
+Export([ 'env', 'idir_prefix', 'idir_lib', 'idir_bin', 'idir_inc', 'idir_doc' ])
+
+# Now proceed to system feature checks
+target_cpu, target_vendor, target_kernel, target_os = \
+ os.popen("./config/config.guess").readlines()[0].split("-")
+
+def Define(context, key, have):
+ import SCons.Conftest
+ SCons.Conftest._Have(context, key, have)
+
+def CheckCustomOption(context, name):
+ context.Message('Checking is the ' + name + ' option set... ')
+ ret = env[name]
+ Define(context, name + '_SUPPORT', ret)
+ context.Result(ret)
+ return ret
+
+def CheckFillorderOption(context):
+ context.Message('Checking for the native cpu bit order... ')
+ if target_cpu[0] == 'i' and target_cpu[2:] == '86':
+ Define(context, 'HOST_FILLORDER', 'FILLORDER_LSB2MSB')
+ context.Result('lsb2msb')
+ else:
+ Define(context, 'HOST_FILLORDER', 'FILLORDER_MSB2LSB')
+ context.Result('msb2lsb')
+ return 1
+
+def CheckIEEEFPOption(context):
+ context.Message('Checking for the IEEE floating point format... ')
+ Define(context, 'HAVE_IEEEFP', 1)
+ context.Result(1)
+ return 1
+
+def CheckOtherOption(context, name):
+ context.Message('Checking is the ' + name + ' option set... ')
+ ret = env[name]
+ Define(context, 'HAVE_' + name, ret)
+ context.Result(ret)
+ return ret
+
+custom_tests = { \
+ 'CheckCustomOption' : CheckCustomOption, \
+ 'CheckFillorderOption' : CheckFillorderOption, \
+ 'CheckIEEEFPOption' : CheckIEEEFPOption, \
+ 'CheckOtherOption' : CheckOtherOption \
+ }
+conf = Configure(env, custom_tests = custom_tests, \
+ config_h = 'libtiff/tif_config.h')
+
+# Check for standard library
+conf.CheckLib('c')
+if target_os != 'cygwin' \
+ and target_os != 'mingw32' \
+ and target_os != 'beos' \
+ and target_os != 'darwin':
+ conf.CheckLib('m')
+
+# Check for system headers
+conf.CheckCHeader('assert.h')
+conf.CheckCHeader('fcntl.h')
+conf.CheckCHeader('io.h')
+conf.CheckCHeader('limits.h')
+conf.CheckCHeader('malloc.h')
+conf.CheckCHeader('search.h')
+conf.CheckCHeader('sys/time.h')
+conf.CheckCHeader('unistd.h')
+
+# Check for standard library functions
+conf.CheckFunc('floor')
+conf.CheckFunc('isascii')
+conf.CheckFunc('memmove')
+conf.CheckFunc('memset')
+conf.CheckFunc('mmap')
+conf.CheckFunc('pow')
+conf.CheckFunc('setmode')
+conf.CheckFunc('sqrt')
+conf.CheckFunc('strchr')
+conf.CheckFunc('strrchr')
+conf.CheckFunc('strstr')
+conf.CheckFunc('strtol')
+
+conf.CheckFillorderOption()
+conf.CheckIEEEFPOption()
+conf.CheckCustomOption('ccitt')
+conf.CheckCustomOption('packbits')
+conf.CheckCustomOption('lzw')
+conf.CheckCustomOption('thunder')
+conf.CheckCustomOption('next')
+conf.CheckCustomOption('logluv')
+conf.CheckOtherOption('strip_chopping')
+conf.CheckOtherOption('extrasample_as_alpha')
+conf.CheckOtherOption('check_ycbcr_subsampling')
+
+env = conf.Finish()
+
+# Ok, now go to build files in the subdirectories
+SConscript(dirs = [ 'libtiff' ], name = 'SConstruct')
diff --git a/tiff/TODO b/tiff/TODO
new file mode 100644
index 0000000..6c58eb0
--- /dev/null
+++ b/tiff/TODO
@@ -0,0 +1,12 @@
+# $Header: /cvs/maptools/cvsroot/libtiff/TODO,v 1.6 2002/10/10 05:28:43 warmerda Exp $
+
+o gif2tiff segaulting on selected images
+o tiffcmp read data by strip/tile instead of scanline
+o YCbCr sampling support
+o extracate colorspace conversion support
+o look at isolating all codecs from TIFF library
+o JPEG colormode order dependency problem
+o Write documentation on how do extend tags, and how the custom field
+ stuff all works.
+
+
diff --git a/tiff/VERSION b/tiff/VERSION
new file mode 100644
index 0000000..e0d61b5
--- /dev/null
+++ b/tiff/VERSION
@@ -0,0 +1 @@
+3.9.4
diff --git a/tiff/aclocal.m4 b/tiff/aclocal.m4
new file mode 100644
index 0000000..ad4f304
--- /dev/null
+++ b/tiff/aclocal.m4
@@ -0,0 +1,1059 @@
+# generated automatically by aclocal 1.11 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],,
+[m4_warning([this file was generated for autoconf 2.65.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.11'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.11], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.11])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 10
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
+ [$1], CXX, [depcc="$CXX" am_compiler_list=],
+ [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], UPC, [depcc="$UPC" am_compiler_list=],
+ [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 16
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.62])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES(CC)],
+ [define([AC_PROG_CC],
+ defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES(CXX)],
+ [define([AC_PROG_CXX],
+ defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES(OBJC)],
+ [define([AC_PROG_OBJC],
+ defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless `enable' is passed literally.
+# For symmetry, `disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_PROG_CC_C_O
+# --------------
+# Like AC_PROG_CC_C_O, but changed for automake.
+AC_DEFUN([AM_PROG_CC_C_O],
+[AC_REQUIRE([AC_PROG_CC_C_O])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
+eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
+if test "$am_t" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+dnl Make sure AC_PROG_CC is never called again, or it will override our
+dnl setting of CC.
+m4_define([AC_PROG_CC],
+ [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])])
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+ [[\\/$]]* | ?:[[\\/]]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+alias in your environment])
+ fi
+
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# (`yes' being less verbose, `no' or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules],
+[ --enable-silent-rules less verbose build output (undo: `make V=1')
+ --disable-silent-rules verbose build output (undo: `make V=0')])
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no) AM_DEFAULT_VERBOSITY=1;;
+*) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006, 2008 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+ [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+ [m4_case([$1], [ustar],, [pax],,
+ [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar;
+ do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/acinclude.m4])
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
diff --git a/tiff/afiles b/tiff/afiles
new file mode 100644
index 0000000..81e47bc
--- /dev/null
+++ b/tiff/afiles
@@ -0,0 +1,448 @@
+afiles
+Jamfile
+aclocal.m4
+autogen.sh
+build/Makefile.am
+build/Makefile.in
+build/README
+ChangeLog
+config/compile
+config/config.guess
+config/config.sub
+config/depcomp
+config/install-sh
+config/ltmain.sh
+config/missing
+config/mkinstalldirs
+configure
+configure.ac
+configure.com
+contrib/acorn/cleanlib
+contrib/acorn/convert
+contrib/acorn/install
+contrib/acorn/Makefile.acorn
+contrib/acorn/Makefile.am
+contrib/acorn/Makefile.in
+contrib/acorn/ReadMe
+contrib/acorn/SetVars
+contrib/addtiffo/addtiffo.c
+contrib/addtiffo/Makefile.am
+contrib/addtiffo/Makefile.in
+contrib/addtiffo/Makefile.vc
+contrib/addtiffo/README
+contrib/addtiffo/tif_overview.c
+contrib/addtiffo/tif_ovrcache.c
+contrib/addtiffo/tif_ovrcache.h
+contrib/dbs/Makefile.am
+contrib/dbs/Makefile.in
+contrib/dbs/README
+contrib/dbs/tiff-bi.c
+contrib/dbs/tiff-grayscale.c
+contrib/dbs/tiff-palette.c
+contrib/dbs/tiff-rgb.c
+contrib/dbs/xtiff/Makefile.am
+contrib/dbs/xtiff/Makefile.in
+contrib/dbs/xtiff/patchlevel.h
+contrib/dbs/xtiff/README
+contrib/dbs/xtiff/xtiff.c
+contrib/dbs/xtiff/xtifficon.h
+contrib/iptcutil/iptcutil.c
+contrib/iptcutil/Makefile.am
+contrib/iptcutil/Makefile.in
+contrib/iptcutil/README
+contrib/iptcutil/test.iptc
+contrib/iptcutil/test.txt
+contrib/mac-cw/mac_main.c
+contrib/mac-cw/mac_main.h
+contrib/mac-cw/Makefile.am
+contrib/mac-cw/Makefile.in
+contrib/mac-cw/Makefile.script
+contrib/mac-cw/metrowerks.note
+contrib/mac-cw/mkg3_main.c
+contrib/mac-cw/README
+contrib/mac-cw/version.h
+contrib/mac-mpw/BUILD.mpw
+contrib/mac-mpw/libtiff.make
+contrib/mac-mpw/mactrans.c
+contrib/mac-mpw/Makefile.am
+contrib/mac-mpw/Makefile.in
+contrib/mac-mpw/port.make
+contrib/mac-mpw/README
+contrib/mac-mpw/tools.make
+contrib/mac-mpw/top.make
+contrib/Makefile.am
+contrib/Makefile.in
+contrib/mfs/Makefile.am
+contrib/mfs/Makefile.in
+contrib/mfs/mfs_file.c
+contrib/mfs/README
+contrib/pds/Makefile.am
+contrib/pds/Makefile.in
+contrib/pds/README
+contrib/pds/tif_imageiter.c
+contrib/pds/tif_imageiter.h
+contrib/pds/tif_pdsdirread.c
+contrib/pds/tif_pdsdirwrite.c
+contrib/ras/Makefile.am
+contrib/ras/Makefile.in
+contrib/ras/ras2tif.c
+contrib/ras/README
+contrib/ras/tif2ras.c
+contrib/README
+contrib/stream/Makefile.am
+contrib/stream/Makefile.in
+contrib/stream/README
+contrib/stream/tiffstream.cpp
+contrib/stream/tiffstream.h
+contrib/tags/listtif.c
+contrib/tags/Makefile.am
+contrib/tags/Makefile.in
+contrib/tags/maketif.c
+contrib/tags/README
+contrib/tags/xtiffio.h
+contrib/tags/xtiffiop.h
+contrib/tags/xtif_dir.c
+contrib/win_dib/Makefile.am
+contrib/win_dib/Makefile.in
+contrib/win_dib/Makefile.w95
+contrib/win_dib/README.tiff2dib
+contrib/win_dib/README.Tiffile
+contrib/win_dib/tiff2dib.c
+contrib/win_dib/Tiffile.cpp
+COPYRIGHT
+HOWTO-RELEASE
+html/addingtags.html
+html/bugs.html
+html/build.html
+html/contrib.html
+html/document.html
+html/images/back.gif
+html/images/bali.jpg
+html/images/cat.gif
+html/images/cover.jpg
+html/images/cramps.gif
+html/images/dave.gif
+html/images/info.gif
+html/images/jello.jpg
+html/images/jim.gif
+html/images/Makefile.am
+html/images/Makefile.in
+html/images/note.gif
+html/images/oxford.gif
+html/images/quad.jpg
+html/images/ring.gif
+html/images/smallliz.jpg
+html/images/strike.gif
+html/images/warning.gif
+html/images.html
+html/index.html
+html/internals.html
+html/intro.html
+html/libtiff.html
+html/Makefile.am
+html/Makefile.in
+html/man/fax2ps.1.html
+html/man/fax2tiff.1.html
+html/man/gif2tiff.1.html
+html/man/index.html
+html/man/libtiff.3tiff.html
+html/man/Makefile.am
+html/man/Makefile.in
+html/man/pal2rgb.1.html
+html/man/ppm2tiff.1.html
+html/man/ras2tiff.1.html
+html/man/raw2tiff.1.html
+html/man/rgb2ycbcr.1.html
+html/man/sgi2tiff.1.html
+html/man/thumbnail.1.html
+html/man/tiff2bw.1.html
+html/man/tiff2pdf.1.html
+html/man/tiff2ps.1.html
+html/man/tiff2rgba.1.html
+html/man/TIFFbuffer.3tiff.html
+html/man/TIFFClose.3tiff.html
+html/man/tiffcmp.1.html
+html/man/TIFFcodec.3tiff.html
+html/man/TIFFcolor.3tiff.html
+html/man/tiffcp.1.html
+html/man/tiffcrop.1.html
+html/man/TIFFDataWidth.3tiff.html
+html/man/tiffdither.1.html
+html/man/tiffdump.1.html
+html/man/TIFFError.3tiff.html
+html/man/TIFFFlush.3tiff.html
+html/man/TIFFGetField.3tiff.html
+html/man/tiffgt.1.html
+html/man/tiffinfo.1.html
+html/man/tiffmedian.1.html
+html/man/TIFFmemory.3tiff.html
+html/man/TIFFOpen.3tiff.html
+html/man/TIFFPrintDirectory.3tiff.html
+html/man/TIFFquery.3tiff.html
+html/man/TIFFReadDirectory.3tiff.html
+html/man/TIFFReadEncodedStrip.3tiff.html
+html/man/TIFFReadEncodedTile.3tiff.html
+html/man/TIFFReadRawStrip.3tiff.html
+html/man/TIFFReadRawTile.3tiff.html
+html/man/TIFFReadRGBAImage.3tiff.html
+html/man/TIFFReadRGBAStrip.3tiff.html
+html/man/TIFFReadRGBATile.3tiff.html
+html/man/TIFFReadScanline.3tiff.html
+html/man/TIFFReadTile.3tiff.html
+html/man/TIFFRGBAImage.3tiff.html
+html/man/tiffset.1.html
+html/man/TIFFSetDirectory.3tiff.html
+html/man/TIFFSetField.3tiff.html
+html/man/TIFFsize.3tiff.html
+html/man/tiffsplit.1.html
+html/man/TIFFstrip.3tiff.html
+html/man/tiffsv.1.html
+html/man/TIFFswab.3tiff.html
+html/man/TIFFtile.3tiff.html
+html/man/TIFFWarning.3tiff.html
+html/man/TIFFWriteDirectory.3tiff.html
+html/man/TIFFWriteEncodedStrip.3tiff.html
+html/man/TIFFWriteEncodedTile.3tiff.html
+html/man/TIFFWriteRawStrip.3tiff.html
+html/man/TIFFWriteRawTile.3tiff.html
+html/man/TIFFWriteScanline.3tiff.html
+html/man/TIFFWriteTile.3tiff.html
+html/misc.html
+html/support.html
+html/TIFFTechNote2.html
+html/tools.html
+html/v3.4beta007.html
+html/v3.4beta016.html
+html/v3.4beta018.html
+html/v3.4beta024.html
+html/v3.4beta028.html
+html/v3.4beta029.html
+html/v3.4beta031.html
+html/v3.4beta032.html
+html/v3.4beta033.html
+html/v3.4beta034.html
+html/v3.4beta035.html
+html/v3.4beta036.html
+html/v3.5.1.html
+html/v3.5.2.html
+html/v3.5.3.html
+html/v3.5.4.html
+html/v3.5.5.html
+html/v3.5.6-beta.html
+html/v3.5.7.html
+html/v3.6.0.html
+html/v3.6.1.html
+html/v3.7.0.html
+html/v3.7.0alpha.html
+html/v3.7.0beta.html
+html/v3.7.0beta2.html
+html/v3.7.1.html
+html/v3.7.2.html
+html/v3.7.3.html
+html/v3.7.4.html
+html/v3.8.0.html
+html/v3.8.1.html
+html/v3.8.2.html
+html/v3.9.0beta.html
+html/v3.9.1.html
+html/v3.9.2.html
+libtiff/libtiff.def
+libtiff/Makefile.am
+libtiff/Makefile.in
+libtiff/Makefile.vc
+libtiff/mkg3states.c
+libtiff/SConstruct
+libtiff/t4.h
+libtiff/tiff.h
+libtiff/tiffconf.h.in
+libtiff/tiffconf.vc.h
+libtiff/tiffconf.wince.h
+libtiff/tiffio.h
+libtiff/tiffio.hxx
+libtiff/tiffiop.h
+libtiff/tiffvers.h
+libtiff/tif_acorn.c
+libtiff/tif_apple.c
+libtiff/tif_atari.c
+libtiff/tif_aux.c
+libtiff/tif_close.c
+libtiff/tif_codec.c
+libtiff/tif_color.c
+libtiff/tif_compress.c
+libtiff/tif_config.h-vms
+libtiff/tif_config.h.in
+libtiff/tif_config.vc.h
+libtiff/tif_config.wince.h
+libtiff/tif_dir.c
+libtiff/tif_dir.h
+libtiff/tif_dirinfo.c
+libtiff/tif_dirread.c
+libtiff/tif_dirwrite.c
+libtiff/tif_dumpmode.c
+libtiff/tif_error.c
+libtiff/tif_extension.c
+libtiff/tif_fax3.c
+libtiff/tif_fax3.h
+libtiff/tif_fax3sm.c
+libtiff/tif_flush.c
+libtiff/tif_getimage.c
+libtiff/tif_jbig.c
+libtiff/tif_jpeg.c
+libtiff/tif_luv.c
+libtiff/tif_lzw.c
+libtiff/tif_msdos.c
+libtiff/tif_next.c
+libtiff/tif_ojpeg.c
+libtiff/tif_open.c
+libtiff/tif_packbits.c
+libtiff/tif_pixarlog.c
+libtiff/tif_predict.c
+libtiff/tif_predict.h
+libtiff/tif_print.c
+libtiff/tif_read.c
+libtiff/tif_stream.cxx
+libtiff/tif_strip.c
+libtiff/tif_swab.c
+libtiff/tif_thunder.c
+libtiff/tif_tile.c
+libtiff/tif_unix.c
+libtiff/tif_version.c
+libtiff/tif_warning.c
+libtiff/tif_win3.c
+libtiff/tif_win32.c
+libtiff/tif_write.c
+libtiff/tif_zip.c
+libtiff/uvcode.h
+m4/acinclude.m4
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+Makefile.am
+Makefile.in
+Makefile.vc
+man/bmp2tiff.1
+man/fax2ps.1
+man/fax2tiff.1
+man/gif2tiff.1
+man/libtiff.3tiff
+man/Makefile.am
+man/Makefile.in
+man/pal2rgb.1
+man/ppm2tiff.1
+man/ras2tiff.1
+man/raw2tiff.1
+man/rgb2ycbcr.1
+man/sgi2tiff.1
+man/thumbnail.1
+man/tiff2bw.1
+man/tiff2pdf.1
+man/tiff2ps.1
+man/tiff2rgba.1
+man/TIFFbuffer.3tiff
+man/TIFFClose.3tiff
+man/tiffcmp.1
+man/TIFFcodec.3tiff
+man/TIFFcolor.3tiff
+man/tiffcp.1
+man/tiffcrop.1
+man/TIFFDataWidth.3tiff
+man/tiffdither.1
+man/tiffdump.1
+man/TIFFError.3tiff
+man/TIFFFlush.3tiff
+man/TIFFGetField.3tiff
+man/tiffgt.1
+man/tiffinfo.1
+man/tiffmedian.1
+man/TIFFmemory.3tiff
+man/TIFFOpen.3tiff
+man/TIFFPrintDirectory.3tiff
+man/TIFFquery.3tiff
+man/TIFFReadDirectory.3tiff
+man/TIFFReadEncodedStrip.3tiff
+man/TIFFReadEncodedTile.3tiff
+man/TIFFReadRawStrip.3tiff
+man/TIFFReadRawTile.3tiff
+man/TIFFReadRGBAImage.3tiff
+man/TIFFReadRGBAStrip.3tiff
+man/TIFFReadRGBATile.3tiff
+man/TIFFReadScanline.3tiff
+man/TIFFReadTile.3tiff
+man/TIFFRGBAImage.3tiff
+man/tiffset.1
+man/TIFFSetDirectory.3tiff
+man/TIFFSetField.3tiff
+man/TIFFsize.3tiff
+man/tiffsplit.1
+man/TIFFstrip.3tiff
+man/tiffsv.1
+man/TIFFswab.3tiff
+man/TIFFtile.3tiff
+man/TIFFWarning.3tiff
+man/TIFFWriteDirectory.3tiff
+man/TIFFWriteEncodedStrip.3tiff
+man/TIFFWriteEncodedTile.3tiff
+man/TIFFWriteRawStrip.3tiff
+man/TIFFWriteRawTile.3tiff
+man/TIFFWriteScanline.3tiff
+man/TIFFWriteTile.3tiff
+nmake.opt
+port/dummy.c
+port/getopt.c
+port/lfind.c
+port/libport.h
+port/Makefile.am
+port/Makefile.in
+port/Makefile.vc
+port/strcasecmp.c
+port/strtoul.c
+README
+README.vms
+RELEASE-DATE
+SConstruct
+test/ascii_tag.c
+test/check_tag.c
+test/long_tag.c
+test/Makefile.am
+test/Makefile.in
+test/short_tag.c
+test/strip.c
+test/strip_rw.c
+test/test_arrays.c
+test/test_arrays.h
+TODO
+tools/Jamfile
+tools/bmp2tiff.c
+tools/fax2ps.c
+tools/fax2tiff.c
+tools/gif2tiff.c
+tools/Makefile.am
+tools/Makefile.in
+tools/Makefile.vc
+tools/pal2rgb.c
+tools/ppm2tiff.c
+tools/ras2tiff.c
+tools/rasterfile.h
+tools/raw2tiff.c
+tools/rgb2ycbcr.c
+tools/sgi2tiff.c
+tools/sgisv.c
+tools/thumbnail.c
+tools/tiff2bw.c
+tools/tiff2pdf.c
+tools/tiff2ps.c
+tools/tiff2rgba.c
+tools/tiffcmp.c
+tools/tiffcp.c
+tools/tiffcrop.c
+tools/tiffdither.c
+tools/tiffdump.c
+tools/tiffgt.c
+tools/tiffinfo.c
+tools/tiffmedian.c
+tools/tiffset.c
+tools/tiffsplit.c
+tools/ycbcr.c
+VERSION
diff --git a/tiff/autogen.sh b/tiff/autogen.sh
new file mode 100644
index 0000000..5633885
--- /dev/null
+++ b/tiff/autogen.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -x
+libtoolize --force --copy
+aclocal -I ./m4
+autoheader
+automake --foreign --add-missing --copy
+autoconf
+
diff --git a/tiff/build/Makefile.am b/tiff/build/Makefile.am
new file mode 100644
index 0000000..27219c1
--- /dev/null
+++ b/tiff/build/Makefile.am
@@ -0,0 +1,31 @@
+# $Id: Makefile.am,v 1.1 2007/02/24 15:03:49 dron Exp $
+#
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = README
+
+SUBDIRS =
+
diff --git a/tiff/build/Makefile.in b/tiff/build/Makefile.in
new file mode 100644
index 0000000..1a7f23e
--- /dev/null
+++ b/tiff/build/Makefile.in
@@ -0,0 +1,625 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# $Id: Makefile.am,v 1.1 2007/02/24 15:03:49 dron Exp $
+#
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2007, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = build
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = README
+SUBDIRS =
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign build/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign build/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ ctags ctags-recursive distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/build/README b/tiff/build/README
new file mode 100644
index 0000000..f765efc
--- /dev/null
+++ b/tiff/build/README
@@ -0,0 +1,3 @@
+This directory contains scripts and tools needed to build libtiff library
+and its utilities in various environments.
+
diff --git a/tiff/config/compile b/tiff/config/compile
new file mode 100644
index 0000000..1b1d232
--- /dev/null
+++ b/tiff/config/compile
@@ -0,0 +1,142 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2005-05-14.22
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as `compile cc -o foo foo.c'.
+ # So we strip `-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no `-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # `.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/tiff/config/config.guess b/tiff/config/config.guess
new file mode 100644
index 0000000..0f0fe71
--- /dev/null
+++ b/tiff/config/config.guess
@@ -0,0 +1,1516 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2007-03-06'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep __LP64__ >/dev/null
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:[3456]*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ EM64T | authenticamd)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips
+ #undef mipsel
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mipsel
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef mips64
+ #undef mips64el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=mips64el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=mips64
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^CPU/{
+ s: ::g
+ p
+ }'`"
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ xtensa:Linux:*:*)
+ echo xtensa-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ # Set LC_ALL=C to ensure ld outputs messages in English.
+ ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <features.h>
+ #ifdef __ELF__
+ # ifdef __GLIBC__
+ # if __GLIBC__ >= 2
+ LIBC=gnu
+ # else
+ LIBC=gnulibc1
+ # endif
+ # else
+ LIBC=gnulibc1
+ # endif
+ #else
+ #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ LIBC=gnu
+ #else
+ LIBC=gnuaout
+ #endif
+ #endif
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+ /^LIBC/{
+ s: ::g
+ p
+ }'`"
+ test x"${LIBC}" != x && {
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit
+ }
+ test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+ http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/tiff/config/config.sub b/tiff/config/config.sub
new file mode 100644
index 0000000..5defff6
--- /dev/null
+++ b/tiff/config/config.sub
@@ -0,0 +1,1622 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation,
+# Inc.
+
+timestamp='2007-01-18'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray)
+ os=
+ basic_machine=$1
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64vr | mips64vrel \
+ | mips64orion | mips64orionel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | mt \
+ | msp430 \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic80 | tron \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k)
+ basic_machine=$basic_machine-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tron-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa-* \
+ | ymp-* \
+ | z8k-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16c)
+ basic_machine=cr16c-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tic54x | c54x*)
+ basic_machine=tic54x-unknown
+ os=-coff
+ ;;
+ tic55x | c55x*)
+ basic_machine=tic55x-unknown
+ os=-coff
+ ;;
+ tic6x | c6x*)
+ basic_machine=tic6x-unknown
+ os=-coff
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/tiff/config/depcomp b/tiff/config/depcomp
new file mode 100644
index 0000000..04701da
--- /dev/null
+++ b/tiff/config/depcomp
@@ -0,0 +1,530 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2005-07-09.11
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by `PROGRAMS ARGS'.
+ object Object file output by `PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputing dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+ "$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+ tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'. On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like `#:fec' to the end of the
+ # dependency line.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+ tr '
+' ' ' >> $depfile
+ echo >> $depfile
+
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' '
+' < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> $depfile
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts `$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
+ tmpdepfile="$stripped.u"
+ if test "$libtool" = yes; then
+ "$@" -Wc,-M
+ else
+ "$@" -M
+ fi
+ stat=$?
+
+ if test -f "$tmpdepfile"; then :
+ else
+ stripped=`echo "$stripped" | sed 's,^.*/,,'`
+ tmpdepfile="$stripped.u"
+ fi
+
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+
+ if test -f "$tmpdepfile"; then
+ outname="$stripped.o"
+ # Each line is of the form `foo.o: dependent.h'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
+ sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
+ else
+ # The sourcefile does not contain any dependencies, so just
+ # store a dummy comment line, to avoid errors with the Makefile
+ # "include basename.Plo" scheme.
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+icc)
+ # Intel's C compiler understands `-MD -MF file'. However on
+ # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+ # ICC 7.0 will fill foo.d with something like
+ # foo.o: sub/foo.c
+ # foo.o: sub/foo.h
+ # which is wrong. We want:
+ # sub/foo.o: sub/foo.c
+ # sub/foo.o: sub/foo.h
+ # sub/foo.c:
+ # sub/foo.h:
+ # ICC 7.1 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using \ :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+ sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in `foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+ test "x$dir" = "x$object" && dir=
+ base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+ if test "$libtool" = yes; then
+ # With Tru64 cc, shared objects can also be used to make a
+ # static library. This mecanism is used in libtool 1.4 series to
+ # handle both shared and static libraries in a single compilation.
+ # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+ #
+ # With libtool 1.5 this exception was removed, and libtool now
+ # generates 2 separate objects for the 2 libraries. These two
+ # compilations output dependencies in in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
+ tmpdepfile2=$dir$base.o.d # libtool 1.5
+ tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
+ tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.o.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ tmpdepfile4=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -eq 0; then :
+ else
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+ # That's a tab and a space in the [].
+ sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+ else
+ echo "#dummy" > "$depfile"
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for `:'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+ "$@" $dashmflag |
+ sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no
+ for arg in "$@"; do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix="`echo $object | sed 's/^.*\././'`"
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test $1 != '--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove `-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E |
+ sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+ sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o,
+ # because we must use -o when running libtool.
+ "$@" || exit $?
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
+ echo " " >> "$depfile"
+ . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/tiff/config/install-sh b/tiff/config/install-sh
new file mode 100644
index 0000000..0ae12c0
--- /dev/null
+++ b/tiff/config/install-sh
@@ -0,0 +1,401 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2005-11-07.23
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+posix_glob=
+posix_mkdir=
+
+# Symbolic mode for testing mkdir with directories.
+# It is the same as 755, but also tests that "u+" works.
+test_mode=u=rwx,g=rx,o=rx,u+wx
+
+# Desired mode of installed file.
+mode=0755
+
+# Desired mode of newly created intermediate directories.
+# It is empty if not known yet.
+intermediate_mode=
+
+chmodcmd=$chmodprog
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+no_target_directory=
+
+usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+-c (ignored)
+-d create directories instead of installing files.
+-g GROUP $chgrpprog installed files to GROUP.
+-m MODE $chmodprog installed files to MODE.
+-o USER $chownprog installed files to USER.
+-s $stripprog installed files.
+-t DIRECTORY install into DIRECTORY.
+-T report an error if DSTFILE is a directory.
+--help display this help and exit.
+--version display version info and exit.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+ case $1 in
+ -c) shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t) dstarg=$2
+ shift
+ shift
+ continue;;
+
+ -T) no_target_directory=true
+ shift
+ continue;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ *) # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ test -n "$dir_arg$dstarg" && break
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dstarg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dstarg"
+ shift # fnord
+ fi
+ shift # arg
+ dstarg=$arg
+ done
+ break;;
+ esac
+done
+
+if test -z "$1"; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call `install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+test -n "$dir_arg" || trap '(exit $?); exit' 1 2 13 15
+
+for src
+do
+ # Protect names starting with `-'.
+ case $src in
+ -*) src=./$src ;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dstarg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+
+ dst=$dstarg
+ # Protect names starting with `-'.
+ case $dst in
+ -*) dst=./$dst ;;
+ esac
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dstarg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ posix_mkdir=false
+ if $mkdirprog -m $test_mode -p -- / >/dev/null 2>&1; then
+ posix_mkdir=true
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./-m "$test_mode" ./-p ./-- 2>/dev/null
+ fi ;;
+ esac
+
+ if
+ $posix_mkdir && {
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, create it using the same intermediate mode that
+ # mkdir -p would use when creating intermediate directories.
+ # POSIX says that this mode is "$(umask -S),u+wx", so use that
+ # if umask -S works.
+
+ if test -n "$dir_arg"; then
+ mkdir_mode=$mode
+ else
+ case $intermediate_mode in
+ '')
+ if umask_S=`(umask -S) 2>/dev/null`; then
+ intermediate_mode=$umask_S,u+wx
+ else
+ intermediate_mode=$test_mode
+ fi ;;
+ esac
+ mkdir_mode=$intermediate_mode
+ fi
+
+ $mkdirprog -m "$mkdir_mode" -p -- "$dstdir"
+ }
+ then :
+ else
+
+ # mkdir does not conform to POSIX, or it failed possibly due to
+ # a race condition. Create the directory the slow way, step by
+ # step, checking for races as we go.
+
+ case $dstdir in
+ /*) pathcomp=/ ;;
+ -*) pathcomp=./ ;;
+ *) pathcomp= ;;
+ esac
+
+ case $posix_glob in
+ '')
+ if (set -f) 2>/dev/null; then
+ posix_glob=true
+ else
+ posix_glob=false
+ fi ;;
+ esac
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob && set -f
+ set fnord $dstdir
+ shift
+ $posix_glob && set +f
+ IFS=$oIFS
+
+ for d
+ do
+ test "x$d" = x && continue
+
+ pathcomp=$pathcomp$d
+ if test ! -d "$pathcomp"; then
+ $mkdirprog "$pathcomp"
+ # Don't fail if two instances are running concurrently.
+ test -d "$pathcomp" || exit 1
+ fi
+ pathcomp=$pathcomp/
+ done
+ obsolete_mkdir_used=true
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd "$mode" "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ $doit $cpprog "$src" "$dsttmp" &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
+ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
+ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
+ && { test -z "$chmodcmd" || $doit $chmodcmd "$mode" "$dsttmp"; } &&
+
+ # Now rename the file to the real destination.
+ { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
+ || {
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ if test -f "$dst"; then
+ $doit $rmcmd -f "$dst" 2>/dev/null \
+ || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
+ && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
+ || {
+ echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ else
+ :
+ fi
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ } || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/tiff/config/ltmain.sh b/tiff/config/ltmain.sh
new file mode 100644
index 0000000..04eaea4
--- /dev/null
+++ b/tiff/config/ltmain.sh
@@ -0,0 +1,8745 @@
+# Generated from ltmain.m4sh.
+
+# libtool (GNU libtool) 2.2.10
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+# --config show all configuration variables
+# --debug enable verbose shell tracing
+# -n, --dry-run display commands without modifying any files
+# --features display basic configuration information and exit
+# --mode=MODE use operation mode MODE
+# --preserve-dup-deps don't remove duplicate dependency libraries
+# --quiet, --silent don't print informational messages
+# --no-quiet, --no-silent
+# print informational messages (default)
+# --tag=TAG use configuration variables from tag TAG
+# -v, --verbose print more informational messages than default
+# --no-verbose don't print the extra informational messages
+# --version print version information
+# -h, --help, --help-all print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+# clean remove files from the build directory
+# compile compile a source file into a libtool object
+# execute automatically set library path, then run a program
+# finish complete the installation of libtool libraries
+# install install libraries or executables
+# link create a library or an executable
+# uninstall remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE. When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+# host-triplet: $host
+# shell: $SHELL
+# compiler: $LTCC
+# compiler flags: $LTCFLAGS
+# linker: $LD (gnu? $with_gnu_ld)
+# $progname: (GNU libtool) 2.2.10
+# automake: $automake_version
+# autoconf: $autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION=2.2.10
+TIMESTAMP=""
+package_revision=1.3175
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test \"\${$lt_var+set}\" = set; then
+ save_$lt_var=\$$lt_var
+ $lt_var=C
+ export $lt_var
+ lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+ lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+ fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${EGREP="grep -E"}
+: ${FGREP="grep -F"}
+: ${GREP="grep"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SED="sed"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" $lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+ func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+}
+
+# Generated shell functions inserted here.
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+ s@/\./@/@g
+ t dotsl
+ s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+# value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+ # Start from root dir and reassemble the path.
+ func_normal_abspath_result=
+ func_normal_abspath_tpath=$1
+ func_normal_abspath_altnamespace=
+ case $func_normal_abspath_tpath in
+ "")
+ # Empty path, that just means $cwd.
+ func_stripname '' '/' "`pwd`"
+ func_normal_abspath_result=$func_stripname_result
+ return
+ ;;
+ # The next three entries are used to spot a run of precisely
+ # two leading slashes without using negated character classes;
+ # we take advantage of case's first-match behaviour.
+ ///*)
+ # Unusual form of absolute path, do nothing.
+ ;;
+ //*)
+ # Not necessarily an ordinary path; POSIX reserves leading '//'
+ # and for example Cygwin uses it to access remote file shares
+ # over CIFS/SMB, so we conserve a leading double slash if found.
+ func_normal_abspath_altnamespace=/
+ ;;
+ /*)
+ # Absolute path, do nothing.
+ ;;
+ *)
+ # Relative path, prepend $cwd.
+ func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+ ;;
+ esac
+ # Cancel out all the simple stuff to save iterations. We also want
+ # the path to end with a slash for ease of parsing, so make sure
+ # there is one (and only one) here.
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+ while :; do
+ # Processed it all yet?
+ if test "$func_normal_abspath_tpath" = / ; then
+ # If we ascended to the root using ".." the result may be empty now.
+ if test -z "$func_normal_abspath_result" ; then
+ func_normal_abspath_result=/
+ fi
+ break
+ fi
+ func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$pathcar"`
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$pathcdr"`
+ # Figure out what to do with it
+ case $func_normal_abspath_tcomponent in
+ "")
+ # Trailing empty path component, ignore it.
+ ;;
+ ..)
+ # Parent dir; strip last assembled component from result.
+ func_dirname "$func_normal_abspath_result"
+ func_normal_abspath_result=$func_dirname_result
+ ;;
+ *)
+ # Actual path component, append it.
+ func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+ ;;
+ esac
+ done
+ # Restore leading double-slash if one was found on entry.
+ func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+# value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+ func_relative_path_result=
+ func_normal_abspath "$1"
+ func_relative_path_tlibdir=$func_normal_abspath_result
+ func_normal_abspath "$2"
+ func_relative_path_tbindir=$func_normal_abspath_result
+
+ # Ascend the tree starting from libdir
+ while :; do
+ # check if we have found a prefix of bindir
+ case $func_relative_path_tbindir in
+ $func_relative_path_tlibdir)
+ # found an exact match
+ func_relative_path_tcancelled=
+ break
+ ;;
+ $func_relative_path_tlibdir*)
+ # found a matching prefix
+ func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+ func_relative_path_tcancelled=$func_stripname_result
+ if test -z "$func_relative_path_result"; then
+ func_relative_path_result=.
+ fi
+ break
+ ;;
+ *)
+ func_dirname $func_relative_path_tlibdir
+ func_relative_path_tlibdir=${func_dirname_result}
+ if test "x$func_relative_path_tlibdir" = x ; then
+ # Have to descend all the way to the root!
+ func_relative_path_result=../$func_relative_path_result
+ func_relative_path_tcancelled=$func_relative_path_tbindir
+ break
+ fi
+ func_relative_path_result=../$func_relative_path_result
+ ;;
+ esac
+ done
+
+ # Now calculate path; take care to avoid doubling-up slashes.
+ func_stripname '' '/' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ func_stripname '/' '/' "$func_relative_path_tcancelled"
+ if test "x$func_stripname_result" != x ; then
+ func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+ fi
+
+ # Normalisation. If bindir is libdir, return empty string,
+ # else relative path ending with a slash; either way, target
+ # file name can be directly appended.
+ if test ! -z "$func_relative_path_result"; then
+ func_stripname './' '' "$func_relative_path_result/"
+ func_relative_path_result=$func_stripname_result
+ fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+ [\\/]*|[A-Za-z]:\\*) ;;
+ *[\\/]*)
+ progdir=$func_dirname_result
+ progdir=`cd "$progdir" && pwd`
+ progpath="$progdir/$progname"
+ ;;
+ *)
+ save_IFS="$IFS"
+ IFS=:
+ for progdir in $PATH; do
+ IFS="$save_IFS"
+ test -x "$progdir/$progname" && break
+ done
+ IFS="$save_IFS"
+ test -n "$progdir" || progdir=`pwd`
+ progpath="$progdir/$progname"
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same. If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'. `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+ s/$bs4/&\\
+/g
+ s/^$bs2$dollar/$bs&/
+ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+ s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+ $ECHO "$progname${mode+: }$mode: $*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+ $opt_verbose && func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+ $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+ $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2
+
+ # bash bug again:
+ :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ func_error ${1+"$@"}
+ func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information." ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+ $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+ my_directory_path="$1"
+ my_dir_list=
+
+ if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+ # Protect directory names starting with `-'
+ case $my_directory_path in
+ -*) my_directory_path="./$my_directory_path" ;;
+ esac
+
+ # While some portion of DIR does not yet exist...
+ while test ! -d "$my_directory_path"; do
+ # ...make a list in topmost first order. Use a colon delimited
+ # list incase some portion of path contains whitespace.
+ my_dir_list="$my_directory_path:$my_dir_list"
+
+ # If the last portion added has no slash in it, the list is done
+ case $my_directory_path in */*) ;; *) break ;; esac
+
+ # ...otherwise throw away the child directory and loop
+ my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+ done
+ my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+ save_mkdir_p_IFS="$IFS"; IFS=':'
+ for my_dir in $my_dir_list; do
+ IFS="$save_mkdir_p_IFS"
+ # mkdir can fail with a `File exist' error if two processes
+ # try to create one of the directories concurrently. Don't
+ # stop in that case!
+ $MKDIR "$my_dir" 2>/dev/null || :
+ done
+ IFS="$save_mkdir_p_IFS"
+
+ # Bail out if we (or some other process) failed to create a directory.
+ test -d "$my_directory_path" || \
+ func_fatal_error "Failed to create \`$1'"
+ fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+ my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+ if test "$opt_dry_run" = ":"; then
+ # Return a directory name, but don't create it in dry-run mode
+ my_tmpdir="${my_template}-$$"
+ else
+
+ # If mktemp works, use that first and foremost
+ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$my_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+ save_mktempdir_umask=`umask`
+ umask 0077
+ $MKDIR "$my_tmpdir"
+ umask $save_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$my_tmpdir" || \
+ func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+ fi
+
+ $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+ case $1 in
+ *[\\\`\"\$]*)
+ func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+ *)
+ func_quote_for_eval_unquoted_result="$1" ;;
+ esac
+
+ case $func_quote_for_eval_unquoted_result in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and and variable
+ # expansion for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+ ;;
+ *)
+ func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+ esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+ case $1 in
+ *[\\\`\"]*)
+ my_arg=`$ECHO "$1" | $SED \
+ -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+ *)
+ my_arg="$1" ;;
+ esac
+
+ case $my_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting and command substitution for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ my_arg="\"$my_arg\""
+ ;;
+ esac
+
+ func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$my_cmd"
+ my_status=$?
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it. Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$lt_user_locale
+ $my_cmd"
+ my_status=$?
+ eval "$lt_safe_locale"
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $SED -n '/(C)/!b go
+ :more
+ /\./!{
+ N
+ s/\n# / /
+ b more
+ }
+ :go
+ /^# '$PROGRAM' (GNU /,/# warranty; / {
+ s/^# //
+ s/^# *$//
+ s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+ p
+ }' < "$progpath"
+ exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+ $SED -n '/^# Usage:/,/^# *.*--help/ {
+ s/^# //
+ s/^# *$//
+ s/\$progname/'$progname'/
+ p
+ }' < "$progpath"
+ echo
+ $ECHO "run \`$progname --help | more' for full usage"
+ exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+ $SED -n '/^# Usage:/,/# Report bugs to/ {
+ s/^# //
+ s/^# *$//
+ s*\$progname*'$progname'*
+ s*\$host*'"$host"'*
+ s*\$SHELL*'"$SHELL"'*
+ s*\$LTCC*'"$LTCC"'*
+ s*\$LTCFLAGS*'"$LTCFLAGS"'*
+ s*\$LD*'"$LD"'*
+ s/\$with_gnu_ld/'"$with_gnu_ld"'/
+ s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/
+ s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/
+ p
+ }' < "$progpath"
+ ret=$?
+ if test -z "$1"; then
+ exit $ret
+ fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+ func_error "missing argument for $1."
+ exit_cmd=exit
+}
+
+exit_cmd=:
+
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+# $mode is unset
+nonopt=
+execute_dlfiles=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+opt_dry_run=false
+opt_duplicate_deps=false
+opt_silent=false
+opt_debug=:
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+ func_error ${1+"$@"}
+ func_error "See the $PACKAGE documentation for more information."
+ func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+ re_begincf='^# ### BEGIN LIBTOOL'
+ re_endcf='^# ### END LIBTOOL'
+
+ # Default configuration.
+ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+ done
+
+ exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+ echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+
+ exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+ # Global variable:
+ tagname="$1"
+
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
+
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
+ *)
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
+}
+
+# Parse options once, thoroughly. This comes as soon as possible in
+# the script to make things like `libtool --version' happen quickly.
+{
+
+ # Shorthand for --mode=foo, only valid as the first argument
+ case $1 in
+ clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+ compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+ execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+ finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+ link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+ uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+ esac
+
+ # Parse non-mode specific arguments:
+ while test "$#" -gt 0; do
+ opt="$1"
+ shift
+
+ case $opt in
+ --config) func_config ;;
+
+ --debug) preserve_args="$preserve_args $opt"
+ func_echo "enabling shell trace mode"
+ opt_debug='set -x'
+ $opt_debug
+ ;;
+
+ -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ execute_dlfiles="$execute_dlfiles $1"
+ shift
+ ;;
+
+ --dry-run | -n) opt_dry_run=: ;;
+ --features) func_features ;;
+ --finish) mode="finish" ;;
+
+ --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ case $1 in
+ # Valid mode arguments:
+ clean) ;;
+ compile) ;;
+ execute) ;;
+ finish) ;;
+ install) ;;
+ link) ;;
+ relink) ;;
+ uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $opt"
+ exit_cmd=exit
+ break
+ ;;
+ esac
+
+ mode="$1"
+ shift
+ ;;
+
+ --preserve-dup-deps)
+ opt_duplicate_deps=: ;;
+
+ --quiet|--silent) preserve_args="$preserve_args $opt"
+ opt_silent=:
+ opt_verbose=false
+ ;;
+
+ --no-quiet|--no-silent)
+ preserve_args="$preserve_args $opt"
+ opt_silent=false
+ ;;
+
+ --verbose| -v) preserve_args="$preserve_args $opt"
+ opt_silent=false
+ opt_verbose=:
+ ;;
+
+ --no-verbose) preserve_args="$preserve_args $opt"
+ opt_verbose=false
+ ;;
+
+ --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break
+ preserve_args="$preserve_args $opt $1"
+ func_enable_tag "$1" # tagname is set here
+ shift
+ ;;
+
+ # Separate optargs to long options:
+ -dlopen=*|--mode=*|--tag=*)
+ func_opt_split "$opt"
+ set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"}
+ shift
+ ;;
+
+ -\?|-h) func_usage ;;
+ --help) opt_help=: ;;
+ --help-all) opt_help=': help-all' ;;
+ --version) func_version ;;
+
+ -*) func_fatal_help "unrecognized option \`$opt'" ;;
+
+ *) nonopt="$opt"
+ break
+ ;;
+ esac
+ done
+
+
+ case $host in
+ *cygwin* | *mingw* | *pw32* | *cegcc*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_duplicate_deps
+ ;;
+ esac
+
+ # Having warned about all mis-specified options, bail out if
+ # anything was wrong.
+ $exit_cmd $EXIT_FAILURE
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+ fi
+
+ exit $EXIT_MISMATCH
+ fi
+}
+
+
+## ----------- ##
+## Main. ##
+## ----------- ##
+
+$opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+
+ if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ func_fatal_configuration "not configured to build any kind of library"
+ fi
+
+ test -z "$mode" && func_fatal_error "error: you must specify a MODE."
+
+
+ # Darwin sucks
+ eval std_shrext=\"$shrext_cmds\"
+
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ func_error "unrecognized option \`-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$progname --help --mode=$mode' for more information."
+}
+
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+ test -f "$1" &&
+ $SED -e 4q "$1" 2>/dev/null \
+ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs. To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway. Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+ lalib_p=no
+ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+ for lalib_p_l in 1 2 3 4
+ do
+ read lalib_p_line
+ case "$lalib_p_line" in
+ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+ esac
+ done
+ exec 0<&5 5<&-
+ fi
+ test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+ func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+ func_ltwrapper_exec_suffix=
+ case $1 in
+ *.exe) ;;
+ *) func_ltwrapper_exec_suffix=.exe ;;
+ esac
+ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+ func_ltwrapper_scriptname_result=""
+ if func_ltwrapper_executable_p "$1"; then
+ func_dirname_and_basename "$1" "" "."
+ func_stripname '' '.exe' "$func_basename_result"
+ func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+ fi
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+ $opt_debug
+ save_ifs=$IFS; IFS='~'
+ for cmd in $1; do
+ IFS=$save_ifs
+ eval cmd=\"$cmd\"
+ func_show_eval "$cmd" "${2-:}"
+ done
+ IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)! Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+ $opt_debug
+ case $1 in
+ */* | *\\*) . "$1" ;;
+ *) . "./$1" ;;
+ esac
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ $opt_debug
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ func_quote_for_eval "$arg"
+ CC_quoted="$CC_quoted $func_quote_for_eval_result"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ func_quote_for_eval "$arg"
+ CC_quoted="$CC_quoted $func_quote_for_eval_result"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case "$@ " in
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ func_echo "unable to infer tagged configuration"
+ func_fatal_error "specify a tag with \`--tag'"
+# else
+# func_verbose "using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+ write_libobj=${1}
+ if test "$build_libtool_libs" = yes; then
+ write_lobj=\'${2}\'
+ else
+ write_lobj=none
+ fi
+
+ if test "$build_old_libs" = yes; then
+ write_oldobj=\'${3}\'
+ else
+ write_oldobj=none
+ fi
+
+ $opt_dry_run || {
+ cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+ $MV "${write_libobj}T" "${write_libobj}"
+ }
+}
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+ $opt_debug
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+ pie_flag=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ test -n "$libobj" && \
+ func_fatal_error "you cannot specify \`-o' more than once"
+ arg_mode=target
+ continue
+ ;;
+
+ -pie | -fpie | -fPIE)
+ pie_flag="$pie_flag $arg"
+ continue
+ ;;
+
+ -shared | -static | -prefer-pic | -prefer-non-pic)
+ later="$later $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$arg"
+ lastarg="$lastarg $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$lastarg"
+ lastarg=$func_stripname_result
+
+ # Add the arguments to base_compile.
+ base_compile="$base_compile $lastarg"
+ continue
+ ;;
+
+ *)
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ func_quote_for_eval "$lastarg"
+ base_compile="$base_compile $func_quote_for_eval_result"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ func_fatal_error "you must specify an argument for -Xcompile"
+ ;;
+ target)
+ func_fatal_error "you must specify a target with \`-o'"
+ ;;
+ *)
+ # Get the name of the library object.
+ test -z "$libobj" && {
+ func_basename "$srcfile"
+ libobj="$func_basename_result"
+ }
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ case $libobj in
+ *.[cCFSifmso] | \
+ *.ada | *.adb | *.ads | *.asm | \
+ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+ *.[fF][09]? | *.for | *.java | *.obj | *.sx | *.cu | *.cup)
+ func_xform "$libobj"
+ libobj=$func_xform_result
+ ;;
+ esac
+
+ case $libobj in
+ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+ *)
+ func_fatal_error "cannot determine name of library object from \`$libobj'"
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ continue
+ ;;
+
+ -static)
+ build_libtool_libs=no
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ func_quote_for_eval "$libobj"
+ test "X$libobj" != "X$func_quote_for_eval_result" \
+ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && func_warning "libobj name \`$libobj' may not contain shell special characters."
+ func_dirname_and_basename "$obj" "/" ""
+ objname="$func_basename_result"
+ xdir="$func_dirname_result"
+ lobj=${xdir}$objdir/$objname
+
+ test -z "$base_compile" && \
+ func_fatal_help "you must specify a compilation command"
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2* | cegcc*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+ removelist="$removelist $output_obj"
+ $ECHO "$srcfile" > "$lockfile"
+ fi
+
+ $opt_dry_run || $RM $removelist
+ removelist="$removelist $lockfile"
+ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+ func_quote_for_eval "$srcfile"
+ qsrcfile=$func_quote_for_eval_result
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ func_mkdir_p "$xdir$objdir"
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ command="$command -o $lobj"
+ fi
+
+ func_show_eval_locale "$command" \
+ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ func_show_eval '$MV "$output_obj" "$lobj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+
+ # Allow error messages only from the first compilation.
+ if test "$suppress_opt" = yes; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile$pie_flag"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ func_show_eval_locale "$command" \
+ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ func_show_eval '$MV "$output_obj" "$obj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+ fi
+
+ $opt_dry_run || {
+ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ removelist=$lockfile
+ $RM "$lockfile"
+ fi
+ }
+
+ exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+ test "$mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+ # We need to display help for each of the modes.
+ case $mode in
+ "")
+ # Generic help is extracted from the usage comments
+ # at the start of this file.
+ func_help
+ ;;
+
+ clean)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ compile)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -no-suppress do not suppress compiler output for multiple passes
+ -prefer-pic try to build PIC objects only
+ -prefer-non-pic try to build non-PIC objects only
+ -shared do not build a \`.o' file suitable for static linking
+ -static only build a \`.o' file suitable for static linking
+ -Wc,FLAG pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+ execute)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+ finish)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+ install)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+ -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+ link)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -bindir BINDIR specify path to binaries directory (for systems where
+ libraries must be found in the PATH setting at runtime)
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -shared only do dynamic linking of libtool libraries
+ -shrext SUFFIX override the standard shared library file extension
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+ -weak LIBNAME declare that the target provides the LIBNAME interface
+ -Wc,FLAG
+ -Xcompiler FLAG pass linker-specific FLAG directly to the compiler
+ -Wl,FLAG
+ -Xlinker FLAG pass linker-specific FLAG directly to the linker
+ -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+ uninstall)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ *)
+ func_fatal_help "invalid operation mode \`$mode'"
+ ;;
+ esac
+
+ echo
+ $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+ if test "$opt_help" = :; then
+ func_mode_help
+ else
+ {
+ func_help noexit
+ for mode in compile link execute install finish uninstall clean; do
+ func_mode_help
+ done
+ } | sed -n '1p; 2,$s/^Usage:/ or: /p'
+ {
+ func_help noexit
+ for mode in compile link execute install finish uninstall clean; do
+ echo
+ func_mode_help
+ done
+ } |
+ sed '1d
+ /^When reporting/,/^Report/{
+ H
+ d
+ }
+ $x
+ /information about other modes/d
+ /more detailed .*MODE/d
+ s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+ fi
+ exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+ $opt_debug
+ # The first argument is the command name.
+ cmd="$nonopt"
+ test -z "$cmd" && \
+ func_fatal_help "you must specify a COMMAND"
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ test -f "$file" \
+ || func_fatal_help "\`$file' is not a file"
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+ func_source "$file"
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && \
+ func_warning "\`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ ;;
+
+ *)
+ func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -* | *.la | *.lo ) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if func_ltwrapper_script_p "$file"; then
+ func_source "$file"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ elif func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ func_source "$func_ltwrapper_scriptname_result"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ func_quote_for_eval "$file"
+ args="$args $func_quote_for_eval_result"
+ done
+
+ if test "X$opt_dry_run" = Xfalse; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ else
+ $lt_unset $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ echo "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+ $opt_debug
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $opt_dry_run || eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ $opt_silent && exit $EXIT_SUCCESS
+
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $ECHO " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $ECHO " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $ECHO " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ echo
+
+ echo "See any operating system documentation about shared libraries for"
+ case $host in
+ solaris2.[6789]|solaris2.1[0-9])
+ echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+ echo "pages."
+ ;;
+ *)
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ ;;
+ esac
+ echo "----------------------------------------------------------------------"
+ exit $EXIT_SUCCESS
+}
+
+test "$mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+ $opt_debug
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ case $nonopt in *shtool*) :;; *) false;; esac; then
+ # Aesthetically quote it.
+ func_quote_for_eval "$nonopt"
+ install_prog="$func_quote_for_eval_result "
+ arg=$1
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ func_quote_for_eval "$arg"
+ install_prog="$install_prog$func_quote_for_eval_result"
+ install_shared_prog=$install_prog
+ case " $install_prog " in
+ *[\\\ /]cp\ *) install_cp=: ;;
+ *) install_cp=false ;;
+ esac
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ no_mode=:
+ for arg
+ do
+ arg2=
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f)
+ if $install_cp; then :; else
+ prev=$arg
+ fi
+ ;;
+ -g | -m | -o)
+ prev=$arg
+ ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ if test "x$prev" = x-m && test -n "$install_override_mode"; then
+ arg2=$install_override_mode
+ no_mode=false
+ fi
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ func_quote_for_eval "$arg"
+ install_prog="$install_prog $func_quote_for_eval_result"
+ if test -n "$arg2"; then
+ func_quote_for_eval "$arg2"
+ fi
+ install_shared_prog="$install_shared_prog $func_quote_for_eval_result"
+ done
+
+ test -z "$install_prog" && \
+ func_fatal_help "you must specify an install program"
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prev' option requires an argument"
+
+ if test -n "$install_override_mode" && $no_mode; then
+ if $install_cp; then :; else
+ func_quote_for_eval "$install_override_mode"
+ install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result"
+ fi
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ func_fatal_help "no file or destination specified"
+ else
+ func_fatal_help "you must specify a destination"
+ fi
+ fi
+
+ # Strip any trailing slash from the destination.
+ func_stripname '' '/' "$dest"
+ dest=$func_stripname_result
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ func_dirname_and_basename "$dest" "" "."
+ destdir="$func_dirname_result"
+ destname="$func_basename_result"
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files; shift
+ test "$#" -gt 1 && \
+ func_fatal_help "\`$dest' is not a directory"
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ func_fatal_help "\`$destdir' must be an absolute directory name"
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$file' is not a valid libtool archive"
+
+ library_names=
+ old_library=
+ relink_command=
+ func_source "$file"
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ func_dirname "$file" "/" ""
+ dir="$func_dirname_result"
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ test "$inst_prefix_dir" = "$destdir" && \
+ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ func_warning "relinking \`$file'"
+ func_show_eval "$relink_command" \
+ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names; shift
+ if test -n "$1"; then
+ realname="$1"
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+ 'exit $?'
+ tstripme="$stripme"
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $realname in
+ *.dll.a)
+ tstripme=""
+ ;;
+ esac
+ ;;
+ esac
+ if test -n "$tstripme" && test -n "$striplib"; then
+ func_show_eval "$striplib $destdir/$realname" 'exit $?'
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try `ln -sf' first, because the `ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ test "$linkname" != "$realname" \
+ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ func_execute_cmds "$postinstall_cmds" 'exit $?'
+ fi
+
+ # Install the pseudo-library for information purposes.
+ func_basename "$file"
+ name="$func_basename_result"
+ instname="$dir/$name"i
+ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ func_lo2o "$destfile"
+ staticdest=$func_lo2o_result
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ func_fatal_help "cannot copy a libtool object to \`$destfile'"
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ test -n "$destfile" && \
+ func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ func_lo2o "$file"
+ staticobj=$func_lo2o_result
+ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin* | *mingw*)
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ wrapper=$func_ltwrapper_scriptname_result
+ else
+ func_stripname '' '.exe' "$file"
+ wrapper=$func_stripname_result
+ fi
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if func_ltwrapper_script_p "$wrapper"; then
+ notinst_deplibs=
+ relink_command=
+
+ func_source "$wrapper"
+
+ # Check the variables that should have been set.
+ test -z "$generated_by_libtool_version" && \
+ func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ func_source "$lib"
+ fi
+ libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ func_warning "\`$lib' has not been installed in \`$libdir'"
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ func_source "$wrapper"
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ $opt_dry_run || {
+ if test "$finalize" = yes; then
+ tmpdir=`func_mktempdir`
+ func_basename "$file$stripped_ext"
+ file="$func_basename_result"
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $opt_silent || {
+ func_quote_for_expand "$relink_command"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ if eval "$relink_command"; then :
+ else
+ func_error "error: relink \`$file' with the above command before installing it"
+ $opt_dry_run || ${RM}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ func_warning "cannot relink \`$file'"
+ fi
+ }
+ else
+ # Install the binary that we compiled earlier.
+ file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ func_stripname '' '.exe' "$destfile"
+ destfile=$func_stripname_result
+ ;;
+ esac
+ ;;
+ esac
+ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+ $opt_dry_run || if test -n "$outputname"; then
+ ${RM}r "$tmpdir"
+ fi
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ func_basename "$file"
+ name="$func_basename_result"
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ func_show_eval "$old_striplib $oldlib" 'exit $?'
+ fi
+
+ # Do each command in the postinstall commands.
+ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+ done
+
+ test -n "$future_libdirs" && \
+ func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ $opt_dry_run && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+ $opt_debug
+ my_outputname="$1"
+ my_originator="$2"
+ my_pic_p="${3-no}"
+ my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+ my_dlsyms=
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ my_dlsyms="${my_outputname}S.c"
+ else
+ func_error "not configured to extract global symbols from dlpreopened files"
+ fi
+ fi
+
+ if test -n "$my_dlsyms"; then
+ case $my_dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${my_outputname}.nm"
+
+ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+ # Parse the name list into a source file.
+ func_verbose "creating $output_objdir/$my_dlsyms"
+
+ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ func_verbose "generating symbol list for \`$output'"
+
+ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ for progfile in $progfiles; do
+ func_verbose "extracting global C symbols from \`$progfile'"
+ $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $opt_dry_run || {
+ eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $opt_dry_run || {
+ eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$outputname.exp"
+ $opt_dry_run || {
+ $RM $export_symbols
+ eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ else
+ $opt_dry_run || {
+ eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ fi
+ fi
+
+ for dlprefile in $dlprefiles; do
+ func_verbose "extracting global C symbols from \`$dlprefile'"
+ func_basename "$dlprefile"
+ name="$func_basename_result"
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ done
+
+ $opt_dry_run || {
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if $GREP -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ $GREP -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+ fi
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols. */
+typedef struct {
+ const char *name;
+ void *address;
+} lt_dlsymlist;
+"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ echo >> "$output_objdir/$my_dlsyms" "\
+/* DATA imports from DLLs on WIN32 con't be const, because
+ runtime relocations are performed -- see ld's documentation
+ on pseudo-relocs. */"
+ lt_dlsym_const= ;;
+ *osf5*)
+ echo >> "$output_objdir/$my_dlsyms" "\
+/* This system does not cope well with relocations in const data */"
+ lt_dlsym_const= ;;
+ *)
+ lt_dlsym_const=const ;;
+ esac
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+extern $lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+$lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+ { \"$my_originator\", (void *) 0 },"
+
+ case $need_lib_prefix in
+ no)
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ *)
+ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ esac
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ } # !$opt_dry_run
+
+ pic_flag_for_symtable=
+ case "$compile_command " in
+ *" -static "*) ;;
+ *)
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+ *-*-hpux*)
+ pic_flag_for_symtable=" $pic_flag" ;;
+ *)
+ if test "X$my_pic_p" != Xno; then
+ pic_flag_for_symtable=" $pic_flag"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ symtab_cflags=
+ for arg in $LTCFLAGS; do
+ case $arg in
+ -pie | -fpie | -fPIE) ;;
+ *) symtab_cflags="$symtab_cflags $arg" ;;
+ esac
+ done
+
+ # Now compile the dynamic symbol file.
+ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+ # Clean up the generated files.
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+ # Transform the symbol file into the correct name.
+ symfileobj="$output_objdir/${my_outputname}S.$objext"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ if test -f "$output_objdir/$my_outputname.def"; then
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ else
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ fi
+ ;;
+ *)
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ ;;
+ esac
+ ;;
+ *)
+ func_fatal_error "unknown suffix for \`$my_dlsyms'"
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+ fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+ $opt_debug
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+ $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+ win32_nmres=`eval $NM -f posix -A $1 |
+ $SED -n -e '
+ 1,100{
+ / I /{
+ s,.*,import,
+ p
+ q
+ }
+ }'`
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $ECHO "$win32_libid_type"
+}
+
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ $opt_debug
+ f_ex_an_ar_dir="$1"; shift
+ f_ex_an_ar_oldlib="$1"
+ if test "$lock_old_archive_extraction" = yes; then
+ lockfile=$f_ex_an_ar_oldlib.lock
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ fi
+ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+ 'stat=$?; rm -f "$lockfile"; exit $stat'
+ if test "$lock_old_archive_extraction" = yes; then
+ $opt_dry_run || rm -f "$lockfile"
+ fi
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+ fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ $opt_debug
+ my_gentop="$1"; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=""
+ my_xlib=""
+ my_xabs=""
+ my_xdir=""
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ func_basename "$my_xlib"
+ my_xlib="$func_basename_result"
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ func_arith $extracted_serial + 1
+ extracted_serial=$func_arith_result
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir="$my_gentop/$my_xlib_u"
+
+ func_mkdir_p "$my_xdir"
+
+ case $host in
+ *-darwin*)
+ func_verbose "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ $opt_dry_run || {
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ darwin_base_archive=`basename "$darwin_archive"`
+ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches ; do
+ func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ cd "$darwin_curdir"
+ $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ done # $darwin_arches
+ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd $darwin_orig_dir
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ } # !$opt_dry_run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+ done
+
+ func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable. Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take. If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory. This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+ func_emit_wrapper_arg1=${1-no}
+
+ $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='$macro_version'
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$ECHO are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ file=\"\$0\""
+
+ qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+ ECHO=\"$qECHO\"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=\$0
+ shift
+ for lt_opt
+ do
+ case \"\$lt_opt\" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+ test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+ lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+ cat \"\$lt_dump_D/\$lt_dump_F\"
+ exit 0
+ ;;
+ --lt-*)
+ \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n \"\$lt_option_debug\"; then
+ echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+ lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2* | *-cegcc*)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $ECHO "\
+ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ for lt_wr_arg
+ do
+ case \$lt_wr_arg in
+ --lt-*) ;;
+ *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+ esac
+ shift
+ done
+ func_exec_program_core \${1+\"\$@\"}
+}
+
+ # Parse options
+ func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $ECHO "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" ||
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $MKDIR \"\$progdir\"
+ else
+ $RM \"\$progdir/\$file\"
+ fi"
+
+ $ECHO "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $ECHO \"\$relink_command_output\" >&2
+ $RM \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $RM \"\$progdir/\$program\";
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $RM \"\$progdir/\$file\"
+ fi"
+ else
+ $ECHO "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $ECHO "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $ECHO "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $ECHO "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $ECHO "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+ func_exec_program \${1+\"\$@\"}
+ fi
+ else
+ # The program doesn't exist.
+ \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+ \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+}
+
+
+# func_to_host_path arg
+#
+# Convert paths to host format when used with build tools.
+# Intended for use with "native" mingw (where libtool itself
+# is running under the msys shell), or in the following cross-
+# build environments:
+# $build $host
+# mingw (msys) mingw [e.g. native]
+# cygwin mingw
+# *nix + wine mingw
+# where wine is equipped with the `winepath' executable.
+# In the native mingw case, the (msys) shell automatically
+# converts paths for any non-msys applications it launches,
+# but that facility isn't available from inside the cwrapper.
+# Similar accommodations are necessary for $host mingw and
+# $build cygwin. Calling this function does no harm for other
+# $host/$build combinations not listed above.
+#
+# ARG is the path (on $build) that should be converted to
+# the proper representation for $host. The result is stored
+# in $func_to_host_path_result.
+func_to_host_path ()
+{
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ case $host in
+ *mingw* )
+ lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+ case $build in
+ *mingw* ) # actually, msys
+ # awkward: cmd appends spaces to result
+ func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+ ;;
+ *cygwin* )
+ func_to_host_path_result=`cygpath -w "$1" |
+ $SED -e "$lt_sed_naive_backslashify"`
+ ;;
+ * )
+ # Unfortunately, winepath does not exit with a non-zero
+ # error code, so we are forced to check the contents of
+ # stdout. On the other hand, if the command is not
+ # found, the shell will set an exit code of 127 and print
+ # *an error message* to stdout. So we must check for both
+ # error code of zero AND non-empty stdout, which explains
+ # the odd construction:
+ func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null`
+ if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then
+ func_to_host_path_result=`$ECHO "$func_to_host_path_tmp1" |
+ $SED -e "$lt_sed_naive_backslashify"`
+ else
+ # Allow warning below.
+ func_to_host_path_result=
+ fi
+ ;;
+ esac
+ if test -z "$func_to_host_path_result" ; then
+ func_error "Could not determine host path corresponding to"
+ func_error " \`$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback:
+ func_to_host_path_result="$1"
+ fi
+ ;;
+ esac
+ fi
+}
+# end: func_to_host_path
+
+# func_to_host_pathlist arg
+#
+# Convert pathlists to host format when used with build tools.
+# See func_to_host_path(), above. This function supports the
+# following $build/$host combinations (but does no harm for
+# combinations not listed here):
+# $build $host
+# mingw (msys) mingw [e.g. native]
+# cygwin mingw
+# *nix + wine mingw
+#
+# Path separators are also converted from $build format to
+# $host format. If ARG begins or ends with a path separator
+# character, it is preserved (but converted to $host format)
+# on output.
+#
+# ARG is a pathlist (on $build) that should be converted to
+# the proper representation on $host. The result is stored
+# in $func_to_host_pathlist_result.
+func_to_host_pathlist ()
+{
+ func_to_host_pathlist_result="$1"
+ if test -n "$1"; then
+ case $host in
+ *mingw* )
+ lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+ # Remove leading and trailing path separator characters from
+ # ARG. msys behavior is inconsistent here, cygpath turns them
+ # into '.;' and ';.', and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_pathlist_tmp1=$func_stripname_result
+ case $build in
+ *mingw* ) # Actually, msys.
+ # Awkward: cmd appends spaces to result.
+ func_to_host_pathlist_result=`
+ ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+ ;;
+ *cygwin* )
+ func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" |
+ $SED -e "$lt_sed_naive_backslashify"`
+ ;;
+ * )
+ # unfortunately, winepath doesn't convert pathlists
+ func_to_host_pathlist_result=""
+ func_to_host_pathlist_oldIFS=$IFS
+ IFS=:
+ for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do
+ IFS=$func_to_host_pathlist_oldIFS
+ if test -n "$func_to_host_pathlist_f" ; then
+ func_to_host_path "$func_to_host_pathlist_f"
+ if test -n "$func_to_host_path_result" ; then
+ if test -z "$func_to_host_pathlist_result" ; then
+ func_to_host_pathlist_result="$func_to_host_path_result"
+ else
+ func_append func_to_host_pathlist_result ";$func_to_host_path_result"
+ fi
+ fi
+ fi
+ done
+ IFS=$func_to_host_pathlist_oldIFS
+ ;;
+ esac
+ if test -z "$func_to_host_pathlist_result"; then
+ func_error "Could not determine the host path(s) corresponding to"
+ func_error " \`$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback. This may break if $1 contains DOS-style drive
+ # specifications. The fix is not to complicate the expression
+ # below, but for the user to provide a working wine installation
+ # with winepath so that path translation in the cross-to-mingw
+ # case works properly.
+ lt_replace_pathsep_nix_to_dos="s|:|;|g"
+ func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\
+ $SED -e "$lt_replace_pathsep_nix_to_dos"`
+ fi
+ # Now, add the leading and trailing path separators back
+ case "$1" in
+ :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result"
+ ;;
+ esac
+ case "$1" in
+ *: ) func_append func_to_host_pathlist_result ";"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+}
+# end: func_to_host_pathlist
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+ cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+*/
+EOF
+ cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+# include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+# define _INTPTR_T_DEFINED
+# define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+ cat <<EOF
+const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ func_to_host_pathlist "$temp_rpath"
+ cat <<EOF
+const char * LIB_PATH_VALUE = "$func_to_host_pathlist_result";
+EOF
+ else
+ cat <<"EOF"
+const char * LIB_PATH_VALUE = "";
+EOF
+ fi
+
+ if test -n "$dllsearchpath"; then
+ func_to_host_pathlist "$dllsearchpath:"
+ cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE = "$func_to_host_pathlist_result";
+EOF
+ else
+ cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE = "";
+EOF
+ fi
+
+ if test "$fast_install" = yes; then
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+ else
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+ fi
+
+
+ cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int newargc;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *actual_cwrapper_name;
+ char *target_name;
+ char *lt_argv_zero;
+ intptr_t rval = 127;
+
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ newargz = XMALLOC (char *, argc + 1);
+
+ /* very simple arg parsing; don't want to rely on getopt
+ * also, copy all non cwrapper options to newargz, except
+ * argz[0], which is handled differently
+ */
+ newargc=0;
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], dumpscript_opt) == 0)
+ {
+EOF
+ case "$host" in
+ *mingw* | *cygwin* )
+ # make stdout use "unix" line endings
+ echo " setmode(1,_O_BINARY);"
+ ;;
+ esac
+
+ cat <<"EOF"
+ lt_dump_script (stdout);
+ return 0;
+ }
+ if (strcmp (argv[i], debug_opt) == 0)
+ {
+ lt_debug = 1;
+ continue;
+ }
+ if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+ {
+ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+ namespace, but it is not one of the ones we know about and
+ have already dealt with, above (inluding dump-script), then
+ report an error. Otherwise, targets might begin to believe
+ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+ namespace. The first time any user complains about this, we'll
+ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+ or a configure.ac-settable value.
+ */
+ lt_fatal (__FILE__, __LINE__,
+ "unrecognized %s option: '%s'",
+ ltwrapper_option_prefix, argv[i]);
+ }
+ /* otherwise ... */
+ newargz[++newargc] = xstrdup (argv[i]);
+ }
+ newargz[++newargc] = NULL;
+
+EOF
+ cat <<EOF
+ /* The GNU banner must be the first non-error debug message */
+ lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+ cat <<"EOF"
+ lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
+ lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (before symlink chase) at: %s\n",
+ tmp_pathspec);
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (after symlink chase) at: %s\n",
+ actual_cwrapper_path);
+ XFREE (tmp_pathspec);
+
+ actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+ strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+ /* wrapper name transforms */
+ strendzap (actual_cwrapper_name, ".exe");
+ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+ XFREE (actual_cwrapper_name);
+ actual_cwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ /* target_name transforms -- use actual target program name; might have lt- prefix */
+ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+ strendzap (target_name, ".exe");
+ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+ XFREE (target_name);
+ target_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) libtool target name: %s\n",
+ target_name);
+EOF
+
+ cat <<EOF
+ newargz[0] =
+ XMALLOC (char, (strlen (actual_cwrapper_path) +
+ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+ strcpy (newargz[0], actual_cwrapper_path);
+ strcat (newargz[0], "$objdir");
+ strcat (newargz[0], "/");
+EOF
+
+ cat <<"EOF"
+ /* stop here, and copy so we don't have to do this twice */
+ tmp_pathspec = xstrdup (newargz[0]);
+
+ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+ strcat (newargz[0], actual_cwrapper_name);
+
+ /* DO want the lt- prefix here if it exists, so use target_name */
+ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+ XFREE (tmp_pathspec);
+ tmp_pathspec = NULL;
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p;
+ while ((p = strchr (newargz[0], '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE (target_name);
+ XFREE (actual_cwrapper_path);
+ XFREE (actual_cwrapper_name);
+
+ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
+ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+
+ lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+ nonnull (lt_argv_zero));
+ for (i = 0; i < newargc; i++)
+ {
+ lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+ i, nonnull (newargz[i]));
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ /* execv doesn't actually work on mingw as expected on unix */
+ newargz = prepare_spawn (newargz);
+ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ if (rval == -1)
+ {
+ /* failed to start process */
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) failed to launch target \"%s\": %s\n",
+ lt_argv_zero, nonnull (strerror (errno)));
+ return 127;
+ }
+ return rval;
+EOF
+ ;;
+ *)
+ cat <<"EOF"
+ execv (lt_argv_zero, newargz);
+ return rval; /* =127, but avoids unused variable warning */
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void *p = (void *) malloc (num);
+ if (!p)
+ lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+ string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable (const char *path)
+{
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0)
+ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return 1;
+ else
+ return 0;
+}
+
+int
+make_executable (const char *path)
+{
+ int rval = 0;
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+ }
+ return rval;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+ int has_slash = 0;
+ const char *p;
+ const char *p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ int tmp_len;
+ char *concat_name;
+
+ lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+ nonempty (wrapper));
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char *path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char *q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR (*q))
+ break;
+ p_len = q - p;
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name =
+ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name =
+ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup (pathspec);
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ char *tmp_pathspec = xstrdup (pathspec);
+ char *p;
+ int has_symlinks = 0;
+ while (strlen (tmp_pathspec) && !has_symlinks)
+ {
+ lt_debugprintf (__FILE__, __LINE__,
+ "checking path component for symlinks: %s\n",
+ tmp_pathspec);
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK (s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ p--;
+ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "error accessing file \"%s\": %s",
+ tmp_pathspec, nonnull (strerror (errno)));
+ }
+ }
+ XFREE (tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup (pathspec);
+ }
+
+ tmp_pathspec = realpath (pathspec, buf);
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert (str != NULL);
+ assert (pat != NULL);
+
+ len = strlen (str);
+ patlen = strlen (pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp (str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+ if (lt_debug)
+ {
+ (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+ va_start (args, fmt);
+ (void) vfprintf (stderr, fmt, args);
+ va_end (args);
+ }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+ int line, const char *mode,
+ const char *message, va_list ap)
+{
+ fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+ va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+ return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+ return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_setenv) setting '%s' to '%s'\n",
+ nonnull (name), nonnull (value));
+ {
+#ifdef HAVE_SETENV
+ /* always make a copy, for consistency with !HAVE_SETENV */
+ char *str = xstrdup (value);
+ setenv (name, str, 1);
+#else
+ int len = strlen (name) + 1 + strlen (value) + 1;
+ char *str = XMALLOC (char, len);
+ sprintf (str, "%s=%s", name, value);
+ if (putenv (str) != EXIT_SUCCESS)
+ {
+ XFREE (str);
+ }
+#endif
+ }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+ char *new_value;
+ if (orig_value && *orig_value)
+ {
+ int orig_value_len = strlen (orig_value);
+ int add_len = strlen (add);
+ new_value = XMALLOC (char, add_len + orig_value_len + 1);
+ if (to_end)
+ {
+ strcpy (new_value, orig_value);
+ strcpy (new_value + orig_value_len, add);
+ }
+ else
+ {
+ strcpy (new_value, add);
+ strcpy (new_value + add_len, orig_value);
+ }
+ }
+ else
+ {
+ new_value = xstrdup (add);
+ }
+ return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ /* some systems can't cope with a ':'-terminated path #' */
+ int len = strlen (new_value);
+ while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ {
+ new_value[len-1] = '\0';
+ }
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+EOF
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+ Note that spawn() does not by itself call the command interpreter
+ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&v);
+ v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+ }) ? "cmd.exe" : "command.com").
+ Instead it simply concatenates the arguments, separated by ' ', and calls
+ CreateProcess(). We must quote the arguments since Win32 CreateProcess()
+ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+ special way:
+ - Space and tab are interpreted as delimiters. They are not treated as
+ delimiters if they are surrounded by double quotes: "...".
+ - Unescaped double quotes are removed from the input. Their only effect is
+ that within double quotes, space and tab are treated like normal
+ characters.
+ - Backslashes not followed by double quotes are not special.
+ - But 2*n+1 backslashes followed by a double quote become
+ n backslashes followed by a double quote (n >= 0):
+ \" -> "
+ \\\" -> \"
+ \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+ size_t argc;
+ char **new_argv;
+ size_t i;
+
+ /* Count number of arguments. */
+ for (argc = 0; argv[argc] != NULL; argc++)
+ ;
+
+ /* Allocate new argument vector. */
+ new_argv = XMALLOC (char *, argc + 1);
+
+ /* Put quoted arguments into the new argument vector. */
+ for (i = 0; i < argc; i++)
+ {
+ const char *string = argv[i];
+
+ if (string[0] == '\0')
+ new_argv[i] = xstrdup ("\"\"");
+ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+ {
+ int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+ size_t length;
+ unsigned int backslashes;
+ const char *s;
+ char *quoted_string;
+ char *p;
+
+ length = 0;
+ backslashes = 0;
+ if (quote_around)
+ length++;
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ length += backslashes + 1;
+ length++;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ length += backslashes + 1;
+
+ quoted_string = XMALLOC (char, length + 1);
+
+ p = quoted_string;
+ backslashes = 0;
+ if (quote_around)
+ *p++ = '"';
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ {
+ unsigned int j;
+ for (j = backslashes + 1; j > 0; j--)
+ *p++ = '\\';
+ }
+ *p++ = c;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ {
+ unsigned int j;
+ for (j = backslashes; j > 0; j--)
+ *p++ = '\\';
+ *p++ = '"';
+ }
+ *p = '\0';
+
+ new_argv[i] = quoted_string;
+ }
+ else
+ new_argv[i] = (char *) string;
+ }
+ new_argv[argc] = NULL;
+
+ return new_argv;
+}
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+ func_emit_wrapper yes |
+ $SED -e 's/\([\\"]\)/\\\1/g' \
+ -e 's/^/ fputs ("/' -e 's/$/\\n", f);/'
+
+ cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+ $opt_debug
+ case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+ *import*) : ;;
+ *) false ;;
+ esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+ $opt_debug
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args=$nonopt
+ base_compile="$nonopt $@"
+ compile_command=$nonopt
+ finalize_command=$nonopt
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+ new_inherited_linker_flags=
+
+ avoid_version=no
+ bindir=
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+ weak_libs=
+ single_module="${wl}-single_module"
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ break
+ ;;
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ func_warning "complete static linking is impossible in this configuration"
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ func_quote_for_eval "$arg"
+ qarg=$func_quote_for_eval_unquoted_result
+ func_append libtool_args " $func_quote_for_eval_result"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ func_append compile_command " @OUTPUT@"
+ func_append finalize_command " @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ bindir)
+ bindir="$arg"
+ prev=
+ continue
+ ;;
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ func_append compile_command " @SYMFILE@"
+ func_append finalize_command " @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ test -f "$arg" \
+ || func_fatal_error "symbol file \`$arg' does not exist"
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ framework)
+ case $host in
+ *-*-darwin*)
+ case "$deplibs " in
+ *" $qarg.ltframework "*) ;;
+ *) deplibs="$deplibs $qarg.ltframework" # this is fixed later
+ ;;
+ esac
+ ;;
+ esac
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat "$save_arg"`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ done
+ else
+ func_fatal_error "link input file \`$arg' does not exist"
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ weak)
+ weak_libs="$weak_libs $arg"
+ prev=
+ continue
+ ;;
+ xcclinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ func_append compile_command " $wl$qarg"
+ func_append finalize_command " $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ # See comment for -static flag below, for more details.
+ func_append compile_command " $link_static_flag"
+ func_append finalize_command " $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -bindir)
+ prev=bindir
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ func_fatal_error "more than one -exported-symbols argument is not allowed"
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework)
+ prev=framework
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ func_stripname '-L' '' "$arg"
+ dir=$func_stripname_result
+ if test -z "$dir"; then
+ if test "$#" -gt 0; then
+ func_fatal_error "require no space between \`-L' and \`$1'"
+ else
+ func_fatal_error "need path for \`-L' option"
+ fi
+ fi
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ test -z "$absdir" && \
+ func_fatal_error "cannot determine absolute directory name of \`$dir'"
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ ::) dllsearchpath=$dir;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ deplibs="$deplibs System.ltframework"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test "X$arg" = "X-lc" && continue
+ ;;
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ # Darwin uses the -arch flag to determine output architecture.
+ -model|-arch|-isysroot)
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+ compiler_flags="$compiler_flags $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;;
+ esac
+ continue
+ ;;
+
+ -multi_module)
+ single_module="${wl}-multi_module"
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ func_warning "\`-no-install' is ignored for $host"
+ func_warning "assuming \`-no-fast-install' instead"
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ func_stripname '-R' '' "$arg"
+ dir=$func_stripname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -shared)
+ # The effects of -shared are defined in a previous loop.
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -weak)
+ prev=weak
+ continue
+ ;;
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ arg="$arg $func_quote_for_eval_result"
+ compiler_flags="$compiler_flags $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Wl,*)
+ func_stripname '-Wl,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ arg="$arg $wl$func_quote_for_eval_result"
+ compiler_flags="$compiler_flags $wl$func_quote_for_eval_result"
+ linker_flags="$linker_flags $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # -msg_* for osf cc
+ -msg_*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ # Flags to be passed through unchanged, with rationale:
+ # -64, -mips[0-9] enable 64-bit mode for the SGI compiler
+ # -r[0-9][0-9]* specify processor for the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+ # +DA*, +DD* enable 64-bit mode for the HP compiler
+ # -q* compiler args for the IBM compiler
+ # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+ # -F/path path to uninstalled frameworks, gcc on darwin
+ # -p, -pg, --coverage, -fprofile-* profiling flags for GCC
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ compiler_flags="$compiler_flags $arg"
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+ done # argument parsing loop
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prevarg' option requires an argument"
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ func_basename "$output"
+ outputname="$func_basename_result"
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ func_dirname "$output" "/" ""
+ output_objdir="$func_dirname_result$objdir"
+ # Create the object directory.
+ func_mkdir_p "$output_objdir"
+
+ # Determine the type of output
+ case $output in
+ "")
+ func_fatal_help "you must specify an output file"
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if $opt_duplicate_deps ; then
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ libs="$libs $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if $opt_duplicate_compiler_generated_deps; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+
+ case $linkmode in
+ lib)
+ passes="conv dlpreopen link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+
+ for pass in $passes; do
+ # The preopen pass in lib mode reverses $deplibs; put it back here
+ # so that -L comes before libs that need it for instance...
+ if test "$linkmode,$pass" = "lib,link"; then
+ ## FIXME: Find the place where the list is rebuilt in the wrong
+ ## order, and fix it there properly
+ tmp_deplibs=
+ for deplib in $deplibs; do
+ tmp_deplibs="$deplib $tmp_deplibs"
+ done
+ deplibs="$tmp_deplibs"
+ fi
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+ esac
+ fi
+ if test "$linkmode,$pass" = "lib,dlpreopen"; then
+ # Collect and forward deplibs of preopened libtool libs
+ for lib in $dlprefiles; do
+ # Ignore non-libtool-libs
+ dependency_libs=
+ case $lib in
+ *.la) func_source "$lib" ;;
+ esac
+
+ # Collect preopened libtool deplibs, except any this library
+ # has declared as weak libs
+ for deplib in $dependency_libs; do
+ func_basename "$deplib"
+ deplib_base=$func_basename_result
+ case " $weak_libs " in
+ *" $deplib_base "*) ;;
+ *) deplibs="$deplibs $deplib" ;;
+ esac
+ done
+ done
+ libs="$dlprefiles"
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags $deplib"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ func_warning "\`-l' is ignored for archives/objects"
+ continue
+ fi
+ func_stripname '-l' '' "$deplib"
+ name=$func_stripname_result
+ if test "$linkmode" = lib; then
+ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+ else
+ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+ fi
+ for searchdir in $searchdirs; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if func_lalib_p "$lib"; then
+ library_names=
+ old_library=
+ func_source "$lib"
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ *.ltframework)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ *)
+ func_warning "\`-L' is ignored for archives/objects"
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ func_stripname '-R' '' "$deplib"
+ dir=$func_stripname_result
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ # Linking convenience modules into shared libraries is allowed,
+ # but linking other static libraries is non-portable.
+ case " $dlpreconveniencelibs " in
+ *" $deplib "*) ;;
+ *)
+ valid_a_lib=no
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=yes
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=yes
+ ;;
+ esac
+ if test "$valid_a_lib" != yes; then
+ echo
+ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because the file extensions .$libext of this argument makes me believe"
+ echo "*** that it is just a static archive that I should not use here."
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ ;;
+ esac
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+ fi
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$lib" \
+ || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ inherited_linker_flags=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ func_source "$lib"
+
+ # Convert "-framework foo" to "foo.ltframework"
+ if test -n "$inherited_linker_flags"; then
+ tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+ case " $new_inherited_linker_flags " in
+ *" $tmp_inherited_linker_flag "*) ;;
+ *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";;
+ esac
+ done
+ fi
+ dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ func_fatal_error "\`$lib' is not a convenience library"
+ fi
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+ fi
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ dlprefiles="$dlprefiles $lib $dependency_libs"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ func_warning "cannot determine absolute directory name of \`$ladir'"
+ func_warning "passing it literally to the linker, although it might fail"
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ func_basename "$lib"
+ laname="$func_basename_result"
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ func_warning "library \`$lib' was moved."
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir="$ladir"
+ absdir="$abs_ladir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi
+ fi # $installed = yes
+ func_stripname 'lib' '.la' "$laname"
+ name=$func_stripname_result
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir" && test "$linkmode" = prog; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ newlib_search_path="$newlib_search_path $func_stripname_result"
+ ;;
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { { test "$prefer_static_libs" = no ||
+ test "$prefer_static_libs,$installed" = "built,yes"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath:" in
+ *"$absdir:"*) ;;
+ *) temp_rpath="$temp_rpath$absdir:" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test "$use_static_libs" = built && test "$installed" = yes; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ case $host in
+ *cygwin* | *mingw* | *cegcc*)
+ # No point in relinking DLLs because paths are not encoded
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=no
+ ;;
+ *)
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+ ;;
+ esac
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some
+ # systems (darwin). Don't bleat about dlopened modules though!
+ dlopenmodule=""
+ for dlpremoduletest in $dlprefiles; do
+ if test "X$dlpremoduletest" = "X$lib"; then
+ dlopenmodule="$dlpremoduletest"
+ break
+ fi
+ done
+ if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+ echo
+ if test "$linkmode" = prog; then
+ $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $ECHO "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw* | *cegcc*)
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ func_basename "$soroot"
+ soname="$func_basename_result"
+ func_stripname 'lib' '.dll' "$soname"
+ newlib=libimp-$func_stripname_result.a
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ func_verbose "extracting exported symbol list from \`$soname'"
+ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ func_verbose "generating import library for \`$soname'"
+ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a (non-dlopened) module then we can not
+ # link against it, someone is ignoring the earlier warnings
+ if /usr/bin/file -L $add 2> /dev/null |
+ $GREP ": [^:]* bundle" >/dev/null ; then
+ if test "X$dlopenmodule" != "X$lib"; then
+ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ echo
+ echo "*** And there doesn't seem to be a static archive available"
+ echo "*** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ elif test -n "$old_library"; then
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ func_fatal_configuration "unsupported hardcode properties"
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes &&
+ test "$hardcode_minus_L" != yes &&
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ echo
+ $ECHO "*** Warning: This system can not link to static lib archive $lib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ echo "*** But as you try to build a module library, libtool will still create "
+ echo "*** a static module, that should work as long as the dlopening application"
+ echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) func_stripname '-R' '' "$libdir"
+ temp_xrpath=$func_stripname_result
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ if $opt_duplicate_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ path=
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ func_dirname "$deplib" "" "."
+ dir="$func_dirname_result"
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ func_warning "cannot determine absolute directory name of \`$dir'"
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if $GREP "^installed=no" $deplib > /dev/null; then
+ case $host in
+ *-*-darwin*)
+ depdepl=
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$absdir/$objdir/$depdepl" ; then
+ depdepl="$absdir/$objdir/$depdepl"
+ darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -z "$darwin_install_name"; then
+ darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ fi
+ compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+ linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}"
+ path=
+ fi
+ fi
+ ;;
+ *)
+ path="-L$absdir/$objdir"
+ ;;
+ esac
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ test "$absdir" != "$libdir" && \
+ func_warning "\`$deplib' seems to be moved"
+
+ path="-L$absdir"
+ fi
+ ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test "$pass" = link; then
+ if test "$linkmode" = "prog"; then
+ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ fi
+ fi
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ tmp_libs="$tmp_libs $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ fi
+ if test "$linkmode" = prog || test "$linkmode" = lib; then
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for archives"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for archives" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for archives"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for archives"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for archives"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for archives"
+
+ test -n "$export_symbols$export_symbols_regex" && \
+ func_warning "\`-export-symbols' is ignored for archives"
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ func_stripname 'lib' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ test "$module" = no && \
+ func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ func_stripname '' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ func_stripname '' '.la' "$outputname"
+ libname=$func_stripname_result
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+ $ECHO "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ test "$dlself" != no && \
+ func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+ set dummy $rpath
+ shift
+ test "$#" -gt 1 && \
+ func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+ install_libdir="$1"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for convenience libraries"
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ shift
+ IFS="$save_ifs"
+
+ test -n "$7" && \
+ func_fatal_help "too many parameters to \`-version-info'"
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$1"
+ number_minor="$2"
+ number_revision="$3"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ darwin|linux|osf|windows|none)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|qnx|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_minor"
+ lt_irix_increment=no
+ ;;
+ esac
+ ;;
+ no)
+ current="$1"
+ revision="$2"
+ age="$3"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "CURRENT \`$current' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "REVISION \`$revision' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "AGE \`$age' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ func_error "AGE \`$age' is greater than the current interface number \`$current'"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ func_arith $current + 1
+ minor_current=$func_arith_result
+ xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ irix | nonstopux)
+ if test "X$lt_irix_increment" = "Xno"; then
+ func_arith $current - $age
+ else
+ func_arith $current - $age + 1
+ fi
+ major=$func_arith_result
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ func_arith $revision - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ func_arith $current - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ qnx)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+
+ *)
+ func_fatal_configuration "unknown library version type \`$version_type'"
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ func_warning "undefined symbols not allowed in $host shared libraries"
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+
+ fi
+
+ func_generate_dlsyms "$libname" "$libname" "yes"
+ libobjs="$libobjs $symfileobj"
+ test "X$libobjs" = "X " && libobjs=
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$ECHO "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext | *.gcno)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if test "X$precious_files_regex" != "X"; then
+ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ test -n "$removelist" && \
+ func_show_eval "${RM}r \$removelist"
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+ # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+ # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs System.ltframework"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $opt_dry_run || $RM conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which I believe you do not have"
+ echo "*** because a test_compile did reveal that the linker did not use it for"
+ echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ ;;
+ *)
+ newdeplibs="$newdeplibs $i"
+ ;;
+ esac
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because a test_compile did reveal that the linker did not use this one"
+ echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ ;;
+ *)
+ newdeplibs="$newdeplibs $i"
+ ;;
+ esac
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method; shift
+ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null |
+ $GREP " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+ $SED -e 10q |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+ $EGREP "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+ done
+ fi
+ case $tmp_deplibs in
+ *[!\ \ ]*)
+ echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ ;;
+ esac
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library with the System framework
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ echo
+ echo "*** Since this library must not contain undefined symbols,"
+ echo "*** because either the platform does not support them or"
+ echo "*** it was explicitly requested with -no-undefined,"
+ echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ case $host in
+ *-*-darwin*)
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ deplibs="$new_libs"
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ if test -n "$hardcode_libdir_flag_spec_ld"; then
+ eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+ else
+ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+ fi
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ linknames=
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ test "X$libobjs" = "X " && libobjs=
+
+ delfiles=
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+ export_symbols="$output_objdir/$libname.uexp"
+ delfiles="$delfiles $export_symbols"
+ fi
+
+ orig_export_symbols=
+ case $host_os in
+ cygwin* | mingw* | cegcc*)
+ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+ # exporting using user supplied symfile
+ if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+ # and it's NOT already a .def file. Must figure out
+ # which of the given symbols are data symbols and tag
+ # them as such. So, trigger use of export_symbols_cmds.
+ # export_symbols gets reassigned inside the "prepare
+ # the list of exported symbols" if statement, so the
+ # include_expsyms logic still works.
+ orig_export_symbols="$export_symbols"
+ export_symbols=
+ always_export_symbols=yes
+ fi
+ fi
+ ;;
+ esac
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ func_len " $cmd"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ func_show_eval "$cmd" 'exit $?'
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ func_verbose "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ tmp_deplibs="$tmp_deplibs $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec" &&
+ test "$compiler_needs_object" = yes &&
+ test -z "$libobjs"; then
+ # extract the archives, so we have objects to list.
+ # TODO: could optimize this to just extract one archive.
+ whole_archive_flag_spec=
+ fi
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ else
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ libobjs="$libobjs $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" &&
+ func_len " $test_cmds" &&
+ len=$func_len_result &&
+ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise
+ # or, if using GNU ld and skipped_export is not :, use a linker
+ # script.
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ func_basename "$output"
+ output_la=$func_basename_result
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ last_robj=
+ k=1
+
+ if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+ output=${output_objdir}/${output_la}.lnkscript
+ func_verbose "creating GNU ld script: $output"
+ echo 'INPUT (' > $output
+ for obj in $save_libobjs
+ do
+ $ECHO "$obj" >> $output
+ done
+ echo ')' >> $output
+ delfiles="$delfiles $output"
+ elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+ output=${output_objdir}/${output_la}.lnk
+ func_verbose "creating linker input file list: $output"
+ : > $output
+ set x $save_libobjs
+ shift
+ firstobj=
+ if test "$compiler_needs_object" = yes; then
+ firstobj="$1 "
+ shift
+ fi
+ for obj
+ do
+ $ECHO "$obj" >> $output
+ done
+ delfiles="$delfiles $output"
+ output=$firstobj\"$file_list_spec$output\"
+ else
+ if test -n "$save_libobjs"; then
+ func_verbose "creating reloadable object files..."
+ output=$output_objdir/$output_la-${k}.$objext
+ eval test_cmds=\"$reload_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ if test "X$objlist" = X ||
+ test "$len" -lt "$max_cmd_len"; then
+ func_append objlist " $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ reload_objs=$objlist
+ eval concat_cmds=\"$reload_cmds\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-${k}.$objext
+ func_arith $k + 1
+ k=$func_arith_result
+ output=$output_objdir/$output_la-${k}.$objext
+ objlist=" $obj"
+ func_len " $last_robj"
+ func_arith $len0 + $func_len_result
+ len=$func_arith_result
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+ fi
+ delfiles="$delfiles $output"
+
+ else
+ output=
+ fi
+
+ if ${skipped_export-false}; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ fi
+
+ test -n "$save_libobjs" &&
+ func_verbose "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+
+ if ${skipped_export-false}; then
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+ fi
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+ fi
+
+ if test -n "$delfiles"; then
+ # Append the command to remove temporary files to $cmds.
+ eval cmds=\"\$cmds~\$RM $delfiles\"
+ fi
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ libobjs="$libobjs $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for objects"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for objects" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for objects"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for objects"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for objects"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for objects"
+
+ case $output in
+ *.lo)
+ test -n "$objs$old_deplibs" && \
+ func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+ libobj=$output
+ func_lo2o "$libobj"
+ obj=$func_lo2o_result
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $opt_dry_run || $RM $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec and hope we can get by with
+ # turning comma into space..
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+ reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ else
+ gentop="$output_objdir/${obj}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+ fi
+
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result.exe;;
+ esac
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for programs"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for programs"
+
+ test "$preload" = yes \
+ && test "$dlopen_support" = unknown \
+ && test "$dlopen_self" = unknown \
+ && test "$dlopen_self_static" = unknown && \
+ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ case $host in
+ *-*-darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ # But is supposedly fixed on 10.4 or later (yay!).
+ if test "$tagname" = CXX ; then
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[0123])
+ compile_command="$compile_command ${wl}-bind_at_load"
+ finalize_command="$finalize_command ${wl}-bind_at_load"
+ ;;
+ esac
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ new_libs="$new_libs -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ ;;
+ *) new_libs="$new_libs $deplib" ;;
+ esac
+ done
+ compile_deplibs="$new_libs"
+
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ ::) dllsearchpath=$libdir;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) dllsearchpath="$dllsearchpath:$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ fi
+
+ func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+ # template prelinking step
+ if test -n "$prelink_cmds"; then
+ func_execute_cmds "$prelink_cmds" 'exit $?'
+ fi
+
+ wrappers_required=yes
+ case $host in
+ *cegcc* | *mingw32ce*)
+ # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+ wrappers_required=no
+ ;;
+ *cygwin* | *mingw* )
+ if test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ *)
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ esac
+ if test "$wrappers_required" = no; then
+ # Replace the output file specification.
+ compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ exit_status=0
+ func_show_eval "$link_command" 'exit_status=$?'
+
+ # Delete the generated files.
+ if test -f "$output_objdir/${outputname}S.${objext}"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+ fi
+
+ exit $exit_status
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $opt_dry_run || $RM $output
+ # Link the executable and exit
+ func_show_eval "$link_command" 'exit $?'
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "\`$output' will be relinked during installation"
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ func_show_eval "$link_command" 'exit $?'
+
+ # Now create the wrapper script.
+ func_verbose "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if not in dry run mode.
+ $opt_dry_run || {
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ func_stripname '' '.exe' "$outputname"
+ outputname=$func_stripname_result ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ func_dirname_and_basename "$output" "" "."
+ output_name=$func_basename_result
+ output_path=$func_dirname_result
+ cwrappersource="$output_path/$objdir/lt-$output_name.c"
+ cwrapper="$output_path/$output_name.exe"
+ $RM $cwrappersource $cwrapper
+ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_cwrapperexe_src > $cwrappersource
+
+ # The wrapper executable is built using the $host compiler,
+ # because it contains $host paths and files. If cross-
+ # compiling, it, like the target executable, must be
+ # executed on the $host or under an emulation environment.
+ $opt_dry_run || {
+ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+ $STRIP $cwrapper
+ }
+
+ # Now, create the wrapper script for func_source use:
+ func_ltwrapper_scriptname $cwrapper
+ $RM $func_ltwrapper_scriptname_result
+ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+ $opt_dry_run || {
+ # note: this script will not be executed, so do not chmod.
+ if test "x$build" = "x$host" ; then
+ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+ else
+ func_emit_wrapper no > $func_ltwrapper_scriptname_result
+ fi
+ }
+ ;;
+ * )
+ $RM $output
+ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_wrapper no > $output
+ chmod +x $output
+ ;;
+ esac
+ }
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ if test "$preload" = yes && test -f "$symfileobj"; then
+ oldobjs="$oldobjs $symfileobj"
+ fi
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $addlibs
+ oldobjs="$oldobjs $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ oldobjs="$oldobjs $func_extract_archives_result"
+ fi
+
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ func_basename "$obj"
+ $ECHO "$func_basename_result"
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ echo "copying selected object files to avoid basename conflicts..."
+ gentop="$output_objdir/${outputname}x"
+ generated="$generated $gentop"
+ func_mkdir_p "$gentop"
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ func_basename "$obj"
+ objbase="$func_basename_result"
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ func_arith $counter + 1
+ counter=$func_arith_result
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ oldobjs="$oldobjs $gentop/$newobj"
+ ;;
+ *) oldobjs="$oldobjs $obj" ;;
+ esac
+ done
+ fi
+ eval cmds=\"$old_archive_cmds\"
+
+ func_len " $cmds"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ func_verbose "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ oldobjs=
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ eval test_cmds=\"$old_archive_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+ for obj in $save_oldobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ func_append objlist " $obj"
+ if test "$len" -lt "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ len=$len0
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ func_execute_cmds "$cmds" 'exit $?'
+ done
+
+ test -n "$generated" && \
+ func_show_eval "${RM}r$generated"
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ func_verbose "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+
+ # Only create the output if not a dry run.
+ $opt_dry_run || {
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ func_basename "$deplib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+
+ for lib in $dlfiles; do
+ case $lib in
+ *.la)
+ func_basename "$lib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ newdlfiles="$newdlfiles $libdir/$name"
+ ;;
+ *) newdlfiles="$newdlfiles $lib" ;;
+ esac
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ *.la)
+ # Only pass preopened files to the pseudo-archive (for
+ # eventual linking with the app. that links it) if we
+ # didn't already link the preopened objects directly into
+ # the library:
+ func_basename "$lib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ ;;
+ esac
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlfiles="$newdlfiles $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ newdlprefiles="$newdlprefiles $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $RM $output
+ # place dlname in correct position for cygwin
+ # In fact, it would be nice if we could use this code for all target
+ # systems that can't hard-code library paths into their executables
+ # and that have no shared library path variable independent of PATH,
+ # but it turns out we can't easily determine that from inspecting
+ # libtool variables, so we have to hard-code the OSs to which it
+ # applies here; at the moment, that means platforms that use the PE
+ # object format with DLL files. See the long comment at the top of
+ # tests/bindir.at for full details.
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+ # If a -bindir argument was supplied, place the dll there.
+ if test "x$bindir" != x ;
+ then
+ func_relative_path "$install_libdir" "$bindir"
+ tdlname=$func_relative_path_result$dlname
+ else
+ # Otherwise fall back on heuristic.
+ tdlname=../bin/$dlname
+ fi
+ ;;
+ esac
+ $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $ECHO >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ }
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+}
+
+{ test "$mode" = link || test "$mode" = relink; } &&
+ func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+ $opt_debug
+ RM="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) RM="$RM $arg"; rmforce=yes ;;
+ -*) RM="$RM $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ test -z "$RM" && \
+ func_fatal_help "you must specify an RM program"
+
+ rmdirs=
+
+ origobjdir="$objdir"
+ for file in $files; do
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ if test "X$dir" = X.; then
+ objdir="$origobjdir"
+ else
+ objdir="$dir/$origobjdir"
+ fi
+ func_basename "$file"
+ name="$func_basename_result"
+ test "$mode" = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test "$mode" = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if { test -L "$file"; } >/dev/null 2>&1 ||
+ { test -h "$file"; } >/dev/null 2>&1 ||
+ test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if func_lalib_p "$file"; then
+ func_source $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+
+ case "$mode" in
+ clean)
+ case " $library_names " in
+ # " " in the beginning catches empty $dlname
+ *" $dlname "*) ;;
+ *) rmfiles="$rmfiles $objdir/$dlname" ;;
+ esac
+ test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if func_lalib_p "$file"; then
+
+ # Read the .lo file
+ func_source $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" &&
+ test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" &&
+ test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ func_stripname '' '.exe' "$name"
+ noexename=$func_stripname_result
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ rmfiles="$rmfiles $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if func_ltwrapper_p "$file"; then
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ relink_command=
+ func_source $func_ltwrapper_scriptname_result
+ rmfiles="$rmfiles $func_ltwrapper_scriptname_result"
+ else
+ relink_command=
+ func_source $dir/$noexename
+ fi
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ func_show_eval "$RM $rmfiles" 'exit_status=1'
+ done
+ objdir="$origobjdir"
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ func_show_eval "rmdir $dir >/dev/null 2>&1"
+ fi
+ done
+
+ exit $exit_status
+}
+
+{ test "$mode" = uninstall || test "$mode" = clean; } &&
+ func_mode_uninstall ${1+"$@"}
+
+test -z "$mode" && {
+ help="$generic_help"
+ func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+ func_fatal_help "invalid operation mode \`$mode'"
+
+if test -n "$exec_cmd"; then
+ eval exec "$exec_cmd"
+ exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/tiff/config/missing b/tiff/config/missing
new file mode 100644
index 0000000..894e786
--- /dev/null
+++ b/tiff/config/missing
@@ -0,0 +1,360 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2005-06-08.21
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+fi
+
+run=:
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+ configure_ac=configure.ac
+else
+ configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case "$1" in
+--run)
+ # Try to run requested program, and just exit if it succeeds.
+ run=
+ shift
+ "$@" && exit 0
+ # Exit code 63 means version mismatch. This often happens
+ # when the user try to use an ancient version of a tool on
+ # a file that requires a minimum version. In this case we
+ # we should proceed has if the program had been absent, or
+ # if --run hadn't been passed.
+ if test $? = 63; then
+ run=:
+ msg="probably too old"
+ fi
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+ --run try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+ aclocal touch file \`aclocal.m4'
+ autoconf touch file \`configure'
+ autoheader touch file \`config.h.in'
+ automake touch all \`Makefile.in' files
+ bison create \`y.tab.[ch]', if possible, from existing .[ch]
+ flex create \`lex.yy.c', if possible, from existing .c
+ help2man touch the output file
+ lex create \`lex.yy.c', if possible, from existing .c
+ makeinfo touch the output file
+ tar try tar, gnutar, gtar, then tar without non-portable flags
+ yacc create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: Unknown \`$1' option"
+ echo 1>&2 "Try \`$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Now exit if we have it, but it failed. Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).
+case "$1" in
+ lex|yacc)
+ # Not GNU programs, they don't have --version.
+ ;;
+
+ tar)
+ if test -n "$run"; then
+ echo 1>&2 "ERROR: \`tar' requires --run"
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ exit 1
+ fi
+ ;;
+
+ *)
+ if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+ # We have it, but it failed.
+ exit 1
+ elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+ # Could not run --version or --help. This is probably someone
+ # running `$TOOL --version' or `$TOOL --help' to check whether
+ # $TOOL exists and not knowing $TOOL uses missing.
+ exit 1
+ fi
+ ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case "$1" in
+ aclocal*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acinclude.m4' or \`${configure_ac}'. You might want
+ to install the \`Automake' and \`Perl' packages. Grab them from
+ any GNU archive site."
+ touch aclocal.m4
+ ;;
+
+ autoconf)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`${configure_ac}'. You might want to install the
+ \`Autoconf' and \`GNU m4' packages. Grab them from any GNU
+ archive site."
+ touch configure
+ ;;
+
+ autoheader)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`acconfig.h' or \`${configure_ac}'. You might want
+ to install the \`Autoconf' and \`GNU m4' packages. Grab them
+ from any GNU archive site."
+ files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+ test -z "$files" && files="config.h"
+ touch_files=
+ for f in $files; do
+ case "$f" in
+ *:*) touch_files="$touch_files "`echo "$f" |
+ sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+ *) touch_files="$touch_files $f.in";;
+ esac
+ done
+ touch $touch_files
+ ;;
+
+ automake*)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+ You might want to install the \`Automake' and \`Perl' packages.
+ Grab them from any GNU archive site."
+ find . -type f -name Makefile.am -print |
+ sed 's/\.am$/.in/' |
+ while read f; do touch "$f"; done
+ ;;
+
+ autom4te)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them.
+ You can get \`$1' as part of \`Autoconf' from any GNU
+ archive site."
+
+ file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
+ test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
+ if test -f "$file"; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo "#! /bin/sh"
+ echo "# Created by GNU Automake missing as a replacement of"
+ echo "# $ $@"
+ echo "exit 0"
+ chmod +x $file
+ exit 1
+ fi
+ ;;
+
+ bison|yacc)
+ echo 1>&2 "\
+WARNING: \`$1' $msg. You should only need it if
+ you modified a \`.y' file. You may need the \`Bison' package
+ in order for those modifications to take effect. You can get
+ \`Bison' from any GNU archive site."
+ rm -f y.tab.c y.tab.h
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.y)
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.c
+ fi
+ SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" y.tab.h
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f y.tab.h ]; then
+ echo >y.tab.h
+ fi
+ if [ ! -f y.tab.c ]; then
+ echo 'main() { return 0; }' >y.tab.c
+ fi
+ ;;
+
+ lex|flex)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.l' file. You may need the \`Flex' package
+ in order for those modifications to take effect. You can get
+ \`Flex' from any GNU archive site."
+ rm -f lex.yy.c
+ if [ $# -ne 1 ]; then
+ eval LASTARG="\${$#}"
+ case "$LASTARG" in
+ *.l)
+ SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+ if [ -f "$SRCFILE" ]; then
+ cp "$SRCFILE" lex.yy.c
+ fi
+ ;;
+ esac
+ fi
+ if [ ! -f lex.yy.c ]; then
+ echo 'main() { return 0; }' >lex.yy.c
+ fi
+ ;;
+
+ help2man)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a dependency of a manual page. You may need the
+ \`Help2man' package in order for those modifications to take
+ effect. You can get \`Help2man' from any GNU archive site."
+
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
+ fi
+ if [ -f "$file" ]; then
+ touch $file
+ else
+ test -z "$file" || exec >$file
+ echo ".ab help2man is required to generate this page"
+ exit 1
+ fi
+ ;;
+
+ makeinfo)
+ echo 1>&2 "\
+WARNING: \`$1' is $msg. You should only need it if
+ you modified a \`.texi' or \`.texinfo' file, or any other file
+ indirectly affecting the aspect of the manual. The spurious
+ call might also be the consequence of using a buggy \`make' (AIX,
+ DU, IRIX). You might want to install the \`Texinfo' package or
+ the \`GNU make' package. Grab either from any GNU archive site."
+ # The file to touch is that specified with -o ...
+ file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
+ if test -z "$file"; then
+ # ... or it is the one specified with @setfilename ...
+ infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+ file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile`
+ # ... or it is derived from the source name (dir/f.texi becomes f.info)
+ test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+ fi
+ # If the file does not exist, the user really needs makeinfo;
+ # let's fail without touching anything.
+ test -f $file || exit 1
+ touch $file
+ ;;
+
+ tar)
+ shift
+
+ # We have already tried tar in the generic part.
+ # Look for gnutar/gtar before invocation to avoid ugly error
+ # messages.
+ if (gnutar --version > /dev/null 2>&1); then
+ gnutar "$@" && exit 0
+ fi
+ if (gtar --version > /dev/null 2>&1); then
+ gtar "$@" && exit 0
+ fi
+ firstarg="$1"
+ if shift; then
+ case "$firstarg" in
+ *o*)
+ firstarg=`echo "$firstarg" | sed s/o//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ case "$firstarg" in
+ *h*)
+ firstarg=`echo "$firstarg" | sed s/h//`
+ tar "$firstarg" "$@" && exit 0
+ ;;
+ esac
+ fi
+
+ echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+ You may want to install GNU tar or Free paxutils, or check the
+ command line arguments."
+ exit 1
+ ;;
+
+ *)
+ echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+ You might have modified some files without having the
+ proper tools for further handling them. Check the \`README' file,
+ it often tells you about the needed prerequisites for installing
+ this package. You may also peek at any GNU archive site, in case
+ some other package would contain this missing \`$1' program."
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/tiff/config/mkinstalldirs b/tiff/config/mkinstalldirs
new file mode 100644
index 0000000..259dbfc
--- /dev/null
+++ b/tiff/config/mkinstalldirs
@@ -0,0 +1,158 @@
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+
+scriptversion=2005-06-29.22
+
+# Original author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain.
+#
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+errstatus=0
+dirmode=
+
+usage="\
+Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ...
+
+Create each directory DIR (with mode MODE, if specified), including all
+leading file name components.
+
+Report bugs to <bug-automake@gnu.org>."
+
+# process command line arguments
+while test $# -gt 0 ; do
+ case $1 in
+ -h | --help | --h*) # -h for help
+ echo "$usage"
+ exit $?
+ ;;
+ -m) # -m PERM arg
+ shift
+ test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
+ dirmode=$1
+ shift
+ ;;
+ --version)
+ echo "$0 $scriptversion"
+ exit $?
+ ;;
+ --) # stop option processing
+ shift
+ break
+ ;;
+ -*) # unknown option
+ echo "$usage" 1>&2
+ exit 1
+ ;;
+ *) # first non-opt arg
+ break
+ ;;
+ esac
+done
+
+for file
+do
+ if test -d "$file"; then
+ shift
+ else
+ break
+ fi
+done
+
+case $# in
+ 0) exit 0 ;;
+esac
+
+# Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and
+# mkdir -p a/c at the same time, both will detect that a is missing,
+# one will create a, then the other will try to create a and die with
+# a "File exists" error. This is a problem when calling mkinstalldirs
+# from a parallel make. We use --version in the probe to restrict
+# ourselves to GNU mkdir, which is thread-safe.
+case $dirmode in
+ '')
+ if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
+ echo "mkdir -p -- $*"
+ exec mkdir -p -- "$@"
+ else
+ # On NextStep and OpenStep, the `mkdir' command does not
+ # recognize any option. It will interpret all options as
+ # directories to create, and then abort because `.' already
+ # exists.
+ test -d ./-p && rmdir ./-p
+ test -d ./--version && rmdir ./--version
+ fi
+ ;;
+ *)
+ if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 &&
+ test ! -d ./--version; then
+ echo "mkdir -m $dirmode -p -- $*"
+ exec mkdir -m "$dirmode" -p -- "$@"
+ else
+ # Clean up after NextStep and OpenStep mkdir.
+ for d in ./-m ./-p ./--version "./$dirmode";
+ do
+ test -d $d && rmdir $d
+ done
+ fi
+ ;;
+esac
+
+for file
+do
+ case $file in
+ /*) pathcomp=/ ;;
+ *) pathcomp= ;;
+ esac
+ oIFS=$IFS
+ IFS=/
+ set fnord $file
+ shift
+ IFS=$oIFS
+
+ for d
+ do
+ test "x$d" = x && continue
+
+ pathcomp=$pathcomp$d
+ case $pathcomp in
+ -*) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp"
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ else
+ if test ! -z "$dirmode"; then
+ echo "chmod $dirmode $pathcomp"
+ lasterr=
+ chmod "$dirmode" "$pathcomp" || lasterr=$?
+
+ if test ! -z "$lasterr"; then
+ errstatus=$lasterr
+ fi
+ fi
+ fi
+ fi
+
+ pathcomp=$pathcomp/
+ done
+done
+
+exit $errstatus
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/tiff/configure b/tiff/configure
new file mode 100644
index 0000000..b0bd9f1
--- /dev/null
+++ b/tiff/configure
@@ -0,0 +1,21416 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.65 for LibTIFF Software 3.9.4.
+#
+# Report bugs to <tiff@lists.maptools.org>.
+#
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ # We cannot yet assume a decent shell, so we have to provide a
+ # neutralization value for shells without unset; and this also
+ # works around shells that cannot unset nonexistent variables.
+ BASH_ENV=/dev/null
+ ENV=/dev/null
+ (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org and
+$0: tiff@lists.maptools.org about your system, including
+$0: any error possibly output before this message. Then
+$0: install a modern shell, or manually run the script
+$0: under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with status $?, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$?; test $as_status -eq 0 && as_status=1
+ if test "$3"; then
+ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+ fi
+ $as_echo "$as_me: error: $1" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='LibTIFF Software'
+PACKAGE_TARNAME='tiff'
+PACKAGE_VERSION='3.9.4'
+PACKAGE_STRING='LibTIFF Software 3.9.4'
+PACKAGE_BUGREPORT='tiff@lists.maptools.org'
+PACKAGE_URL=''
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBDIR
+HAVE_OPENGL_FALSE
+HAVE_OPENGL_TRUE
+GLUT_LIBS
+GLUT_CFLAGS
+GLU_LIBS
+GLU_CFLAGS
+GL_LIBS
+GL_CFLAGS
+PTHREAD_CFLAGS
+PTHREAD_LIBS
+PTHREAD_CC
+acx_pthread_config
+X_EXTRA_LIBS
+X_LIBS
+X_PRE_LIBS
+X_CFLAGS
+XMKMF
+HAVE_CXX_FALSE
+HAVE_CXX_TRUE
+LIBTIFF_DOCDIR
+HAVE_RPATH_FALSE
+HAVE_RPATH_TRUE
+LIBOBJS
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+CXXCPP
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
+ac_ct_CXX
+CXXFLAGS
+CXX
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+RANLIB
+AR
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LIBTOOL
+OBJDUMP
+DLLTOOL
+AS
+LN_S
+LD
+FGREP
+EGREP
+GREP
+SED
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+LIBTIFF_RELEASE_DATE
+LIBTIFF_VERSION_INFO
+LIBTIFF_VERSION
+LIBTIFF_ALPHA_VERSION
+LIBTIFF_MICRO_VERSION
+LIBTIFF_MINOR_VERSION
+LIBTIFF_MAJOR_VERSION
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_maintainer_mode
+enable_dependency_tracking
+with_gnu_ld
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+enable_libtool_lock
+enable_silent_rules
+enable_rpath
+enable_largefile
+with_docdir
+enable_ccitt
+enable_packbits
+enable_lzw
+enable_thunder
+enable_next
+enable_logluv
+enable_mdi
+enable_zlib
+with_zlib_include_dir
+with_zlib_lib_dir
+enable_pixarlog
+enable_jpeg
+with_jpeg_include_dir
+with_jpeg_lib_dir
+enable_old_jpeg
+enable_jbig
+with_jbig_include_dir
+with_jbig_lib_dir
+enable_cxx
+with_x
+with_apple_opengl_framework
+enable_strip_chopping
+with_default_strip_size
+enable_extrasample_as_alpha
+enable_check_ycbcr_subsampling
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+CXX
+CXXFLAGS
+CCC
+CXXCPP
+XMKMF'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information."
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures LibTIFF Software 3.9.4 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/tiff]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+X features:
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+ --target=TARGET configure for building compilers for TARGET [HOST]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of LibTIFF Software 3.9.4:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-maintainer-mode enable make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer
+ --disable-dependency-tracking speeds up one-time build
+ --enable-dependency-tracking do not reject slow dependency extractors
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-static[=PKGS] build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --enable-silent-rules less verbose build output (undo: `make V=1')
+ --disable-silent-rules verbose build output (undo: `make V=0')
+ --enable-rpath Enable runtime linker paths (-R libtool option)
+ --disable-largefile omit support for large files
+ --disable-ccitt disable support for CCITT Group 3 & 4 algorithms
+ --disable-packbits disable support for Macintosh PackBits algorithm
+ --disable-lzw disable support for LZW algorithm
+ --disable-thunder disable support for ThunderScan 4-bit RLE algorithm
+ --disable-next disable support for NeXT 2-bit RLE algorithm
+ --disable-logluv disable support for LogLuv high dynamic range
+ encoding
+ --disable-mdi disable support for Microsoft Document Imaging
+ --disable-zlib disable Zlib usage (required for Deflate
+ compression, enabled by default)
+ --disable-pixarlog disable support for Pixar log-format algorithm
+ (requires Zlib)
+ --disable-jpeg disable IJG JPEG library usage (required for JPEG
+ compression, enabled by default)
+ --disable-old-jpeg disable support for Old JPEG compresson (read-only,
+ enabled by default)
+ --disable-jbig disable JBIG-KIT usage (required for ISO JBIG
+ compression, enabled by default)
+ --enable-cxx enable C++ stream API building (requires C++
+ compiler)
+ --disable-strip-chopping
+ disable support for strip chopping (whether or not
+ to convert single-strip uncompressed images to
+ mutiple strips of specified size to reduce memory
+ usage)
+ --disable-extrasample-as-alpha
+ the RGBA interface will treat a fourth sample with
+ no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+ packages produce RGBA files but don't mark the alpha
+ properly
+ --disable-check-ycbcr-subsampling
+ disable picking up YCbCr subsampling info from the
+ JPEG data stream to support files lacking the tag
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-pic try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-docdir=DIR directory where documentation should be installed
+ --with-zlib-include-dir=DIR
+ location of Zlib headers
+ --with-zlib-lib-dir=DIR location of Zlib library binary
+ --with-jpeg-include-dir=DIR
+ location of IJG JPEG library headers
+ --with-jpeg-lib-dir=DIR location of IJG JPEG library binary
+ --with-jbig-include-dir=DIR
+ location of JBIG-KIT headers
+ --with-jbig-lib-dir=DIR location of JBIG-KIT library binary
+ --with-x use the X Window System
+ --with-apple-opengl-framework
+ use Apple OpenGL framework (Mac OS X only)
+ --with-default-strip-size=SIZE
+ default size of the strip in bytes (when strip
+ chopping enabled) [[default=8192]]
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ CXXCPP C++ preprocessor
+ XMKMF Path to xmkmf, Makefile generator for X Window System
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <tiff@lists.maptools.org>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+LibTIFF Software configure 3.9.4
+generated by GNU Autoconf 2.65
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_func
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_cxx_try_cpp LINENO
+# ------------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } >/dev/null && {
+ test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_cpp
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+( cat <<\_ASBOX
+## -------------------------------------- ##
+## Report this to tiff@lists.maptools.org ##
+## -------------------------------------- ##
+_ASBOX
+ ) | sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
+# -------------------------------------------
+# Tests whether TYPE exists after having included INCLUDES, setting cache
+# variable VAR accordingly.
+ac_fn_c_check_type ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=no"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof ($2))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+if (sizeof (($2)))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ eval "$3=yes"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_type
+
+# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES
+# --------------------------------------------
+# Tries to find the compile-time value of EXPR in a program that includes
+# INCLUDES, setting VAR accordingly. Returns whether the value could be
+# computed
+ac_fn_c_compute_int ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if test "$cross_compiling" = yes; then
+ # Depending upon the size, compute the lo and hi bounds.
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_lo=0 ac_mid=0
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=$ac_mid; break
+else
+ as_fn_arith $ac_mid + 1 && ac_lo=$as_val
+ if test $ac_lo -le $ac_mid; then
+ ac_lo= ac_hi=
+ break
+ fi
+ as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) < 0)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=-1 ac_mid=-1
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) >= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_lo=$ac_mid; break
+else
+ as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val
+ if test $ac_mid -le $ac_hi; then
+ ac_lo= ac_hi=
+ break
+ fi
+ as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+else
+ ac_lo= ac_hi=
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+# Binary search between lo and hi bounds.
+while test "x$ac_lo" != "x$ac_hi"; do
+ as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+static int test_array [1 - 2 * !(($2) <= $ac_mid)];
+test_array [0] = 0
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_hi=$ac_mid
+else
+ as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+case $ac_lo in #((
+?*) eval "$3=\$ac_lo"; ac_retval=0 ;;
+'') ac_retval=1 ;;
+esac
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+static long int longval () { return $2; }
+static unsigned long int ulongval () { return $2; }
+#include <stdio.h>
+#include <stdlib.h>
+int
+main ()
+{
+
+ FILE *f = fopen ("conftest.val", "w");
+ if (! f)
+ return 1;
+ if (($2) < 0)
+ {
+ long int i = longval ();
+ if (i != ($2))
+ return 1;
+ fprintf (f, "%ld", i);
+ }
+ else
+ {
+ unsigned long int i = ulongval ();
+ if (i != ($2))
+ return 1;
+ fprintf (f, "%lu", i);
+ }
+ /* Do not output a trailing newline, as this causes \r\n confusion
+ on some platforms. */
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ echo >>conftest.val; read $3 <conftest.val; ac_retval=0
+else
+ ac_retval=1
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+rm -f conftest.val
+
+ fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_compute_int
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by LibTIFF Software $as_me 3.9.4, which was
+generated by GNU Autoconf 2.65. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ ac_site_file1=$CONFIG_SITE
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_aux_dir=
+for ac_dir in config "$srcdir"/config; do
+ for ac_t in install-sh install.sh shtool; do
+ if test -f "$ac_dir/$ac_t"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/$ac_t -c"
+ break 2
+ fi
+ done
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if test "${ac_cv_target+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$target_alias" = x; then
+ ac_cv_target=$ac_cv_host
+else
+ ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+ as_fn_error "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+am__api_version='1.11'
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error "ls -t appears to fail. Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+ am_missing_run="$MISSING --run "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'. However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if test "${ac_cv_path_mkdir+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+ [\\/$]* | ?:[\\/]*) ;;
+ */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='tiff'
+ VERSION='3.9.4'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+ # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+ if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+LIBTIFF_MAJOR_VERSION=3
+LIBTIFF_MINOR_VERSION=9
+LIBTIFF_MICRO_VERSION=4
+LIBTIFF_ALPHA_VERSION=
+LIBTIFF_VERSION=$LIBTIFF_MAJOR_VERSION.$LIBTIFF_MINOR_VERSION.$LIBTIFF_MICRO_VERSION$LIBTIFF_ALPHA_VERSION
+LIBTIFF_RELEASE_DATE=`date +"%Y%m%d"`
+
+# This is a special hack for OpenBSD and MirOS systems. The dynamic linker
+# in OpenBSD uses some special semantics for shared libraries. Their soname
+# contains only two numbers, major and minor.
+# See http://bugzilla.remotesensing.org/show_bug.cgi?id=838 for details.
+case "$target_os" in
+ openbsd* | mirbsd*)
+ LIBTIFF_VERSION_INFO=$LIBTIFF_MAJOR_VERSION$LIBTIFF_MINOR_VERSION:$LIBTIFF_MICRO_VERSION:0
+ ;;
+ *)
+ LIBTIFF_VERSION_INFO=$LIBTIFF_MAJOR_VERSION:$LIBTIFF_MINOR_VERSION:$LIBTIFF_MICRO_VERSION
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+# Ensure that make can run correctly
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ rm -f conftest.file
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error "ls -t appears to fail. Make sure there is not a broken
+alias in your environment" "$LINENO" 5
+ fi
+
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "no acceptable C compiler found in \$PATH
+See \`config.log' for more details." "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "C compiler cannot create executables
+See \`config.log' for more details." "$LINENO" 5; }; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+ case $ac_cv_prog_cc_stdc in #(
+ no) :
+ ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #(
+ *) :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
+$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
+if test "${ac_cv_prog_cc_c99+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c99=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
+{
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
+}
+
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
+
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
+
+typedef const char *ccp;
+
+static inline int
+test_restrict (ccp restrict text)
+{
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
+ return 0;
+}
+
+// Check varargs and va_copy.
+static void
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ const char *str;
+ int number;
+ float fnumber;
+
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
+}
+
+int
+main ()
+{
+
+ // Check bool.
+ _Bool success = false;
+
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
+
+ // Check varargs.
+ test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
+
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
+
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
+
+ ni.number = 58;
+
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
+
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
+
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c99=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c99" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c99" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c99"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c99" != xno; then :
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+else
+ ac_cv_prog_cc_stdc=no
+fi
+
+fi
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5
+$as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; }
+ if test "${ac_cv_prog_cc_stdc+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+fi
+
+ case $ac_cv_prog_cc_stdc in #(
+ no) :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;; #(
+ '') :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;; #(
+ *) :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5
+$as_echo "$ac_cv_prog_cc_stdc" >&6; } ;;
+esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if test "${ac_cv_path_SED+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if test "${ac_cv_path_FGREP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case "$ECHO" in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+
+if test "x$CC" != xcc; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5
+$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5
+$as_echo_n "checking whether cc understands -c and -o together... " >&6; }
+fi
+set dummy $CC; ac_cc=`$as_echo "$2" |
+ sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+# Make sure it works both with $CC and with simple cc.
+# We do the test twice because some compilers refuse to overwrite an
+# existing .o file with -o, though they will create one.
+ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+rm -f conftest2.*
+if { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } &&
+ test -f conftest2.$ac_objext && { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; };
+then
+ eval ac_cv_prog_cc_${ac_cc}_c_o=yes
+ if test "x$CC" != xcc; then
+ # Test first that cc exists at all.
+ if { ac_try='cc -c conftest.$ac_ext >&5'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+ rm -f conftest2.*
+ if { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } &&
+ test -f conftest2.$ac_objext && { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; };
+ then
+ # cc works too.
+ :
+ else
+ # cc exists but doesn't like -o.
+ eval ac_cv_prog_cc_${ac_cc}_c_o=no
+ fi
+ fi
+ fi
+else
+ eval ac_cv_prog_cc_${ac_cc}_c_o=no
+fi
+rm -f core conftest*
+
+fi
+if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h
+
+fi
+
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
+if test "$am_t" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+ ansi=
+ if test -z "$ansi"; then
+ msg="for C compiler warning flags"
+ else
+ msg="for C compiler warning and ANSI conformance flags"
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking $msg" >&5
+$as_echo_n "checking $msg... " >&6; }
+if test "${vl_cv_prog_cc_warnings+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if test -n "$CC"; then
+ cat > conftest.c <<EOF
+int main(int argc, char **argv) { return 0; }
+EOF
+
+ if test "$GCC" = "yes"; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-Wall -W"
+ else
+ vl_cv_prog_cc_warnings="-Wall -W -ansi -pedantic"
+ fi
+
+
+ elif $CC -V 2>&1 | grep -i "WorkShop" > /dev/null 2>&1 &&
+ $CC -c -v -Xc conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-v"
+ else
+ vl_cv_prog_cc_warnings="-v -Xc"
+ fi
+
+ elif $CC -V 2>&1 | grep -i "Digital UNIX Compiler" > /dev/null 2>&1 &&
+ $CC -c -verbose -w0 -warnprotos -std1 conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-verbose -w0 -warnprotos"
+ else
+ vl_cv_prog_cc_warnings="-verbose -w0 -warnprotos -std1"
+ fi
+
+ elif $CC 2>&1 | grep -i "C for AIX Compiler" > /dev/null 2>&1 &&
+ $CC -c -qlanglvl=ansi -qinfo=all conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd"
+ else
+ vl_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd -qlanglvl=ansi"
+ fi
+
+ elif $CC -version 2>&1 | grep -i "MIPSpro Compilers" > /dev/null 2>&1 &&
+ $CC -c -fullwarn -ansi -ansiE conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-fullwarn"
+ else
+ vl_cv_prog_cc_warnings="-fullwarn -ansi -ansiE"
+ fi
+
+ elif what $CC 2>&1 | grep -i "HP C Compiler" > /dev/null 2>&1 &&
+ $CC -c -Aa +w1 conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="+w1"
+ else
+ vl_cv_prog_cc_warnings="+w1 -Aa"
+ fi
+
+ elif $CC -V 2>&1 | grep "/SX" > /dev/null 2>&1 &&
+ $CC -c -pvctl,fullmsg -Xc conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-pvctl,fullmsg"
+ else
+ vl_cv_prog_cc_warnings="-pvctl,fullmsg -Xc"
+ fi
+
+ elif $CC -V 2>&1 | grep -i "Cray" > /dev/null 2>&1 &&
+ $CC -c -h msglevel 2 conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-h msglevel 2"
+ else
+ vl_cv_prog_cc_warnings="-h msglevel 2 -h conform"
+ fi
+
+ fi
+ rm -f conftest.*
+ fi
+ if test -n "$vl_cv_prog_cc_warnings"; then
+ CFLAGS="$CFLAGS $vl_cv_prog_cc_warnings"
+ else
+ vl_cv_prog_cc_warnings="unknown"
+ fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $vl_cv_prog_cc_warnings" >&5
+$as_echo "$vl_cv_prog_cc_warnings" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+
+
+
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.2.10'
+macro_revision='1.3175'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if test "${lt_cv_path_NM+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in dumpbin "link -dump"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DUMPBIN+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in dumpbin "link -dump"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if test "${lt_cv_nm_interface+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if test "${lt_cv_ld_reload_flag+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJDUMP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if test "${lt_cv_deplibs_check_method+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AR+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_AR="ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+ (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if test "${lt_cv_cc_needs_belf+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DSYMUTIL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_NMEDIT+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_LIPO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL64+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if test "${lt_cv_apple_cc_single_mod+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if test "${lt_cv_ld_exported_symbols_list+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if test "${lt_cv_ld_force_load+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+ echo "$AR cru libconftest.a conftest.o" >&5
+ $AR cru libconftest.a conftest.o 2>&5
+ echo "$RANLIB libconftest.a" >&5
+ $RANLIB libconftest.a 2>&5
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[012]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
+set dummy ${ac_tool_prefix}as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AS+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AS"; then
+ ac_cv_prog_AS="$AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_AS="${ac_tool_prefix}as"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AS=$ac_cv_prog_AS
+if test -n "$AS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AS" >&5
+$as_echo "$AS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AS"; then
+ ac_ct_AS=$AS
+ # Extract the first word of "as", so it can be a program name with args.
+set dummy as; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_AS+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AS"; then
+ ac_cv_prog_ac_ct_AS="$ac_ct_AS" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_AS="as"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AS=$ac_cv_prog_ac_ct_AS
+if test -n "$ac_ct_AS"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AS" >&5
+$as_echo "$ac_ct_AS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AS" = x; then
+ AS="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AS=$ac_ct_AS
+ fi
+else
+ AS="$ac_cv_prog_AS"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DLLTOOL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DLLTOOL"; then
+ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+ ac_ct_DLLTOOL=$DLLTOOL
+ # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DLLTOOL+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DLLTOOL"; then
+ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DLLTOOL" = x; then
+ DLLTOOL="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DLLTOOL=$ac_ct_DLLTOOL
+ fi
+else
+ DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJDUMP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+ ;;
+esac
+
+test -z "$AS" && AS=as
+
+
+
+
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+ enable_dlopen=no
+
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+ # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; pic_mode="$withval"
+else
+ pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if test "${lt_cv_objdir+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl='-Xlinker '
+ lt_prog_compiler_pic='-Xcompiler -fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ F* | *Sun*Fortran*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5
+$as_echo "$lt_prog_compiler_pic" >&6; }
+
+
+
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test "${lt_cv_prog_compiler_static_works+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ export_dynamic_flag_spec='${wl}--export-all-symbols'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld='-rpath $libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ fi
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ else
+ whole_archive_flag_spec=''
+ fi
+ link_all_deplibs=yes
+ allow_undefined_flag="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ freebsd1*)
+ ld_shlibs=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld='+b $libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if test "${lt_cv_prog_compiler__b+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler__b=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -b"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler__b=yes
+ fi
+ else
+ lt_cv_prog_compiler__b=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo(void) {}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if test "${lt_cv_archive_cmds_need_lc+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc=no
+ else
+ lt_cv_archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+haiku*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+ test "$inherit_rpath" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = x""yes; then :
+ lt_cv_dlopen="shl_load"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = x""yes; then :
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = x""yes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = x""yes; then :
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self_static+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report which library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+ if test -n "$CCC"; then
+ CXX=$CCC
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CXX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_ac_ct_CXX="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CXX" && break
+done
+
+ if test "x$ac_ct_CXX" = x; then
+ CXX="g++"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CXX=$ac_ct_CXX
+ fi
+fi
+
+ fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if test "${ac_cv_prog_cxx_g+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+ ac_cxx_werror_flag=yes
+ ac_cv_prog_cxx_g=no
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+else
+ CXXFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CXX" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named `D' -- because `-MD' means `put the output
+ # in D'.
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CXX_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+ # Solaris 8's {/usr,}/bin/sh.
+ touch sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with `-c' and `-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle `-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # after this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvisualcpp | msvcmsys)
+ # This compiler won't grok `-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CXX_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+ am__fastdepCXX_TRUE=
+ am__fastdepCXX_FALSE='#'
+else
+ am__fastdepCXX_TRUE='#'
+ am__fastdepCXX_FALSE=
+fi
+
+
+
+ if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+ if test "${ac_cv_prog_CXXCPP+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CXXCPP needs to be expanded
+ for CXXCPP in "$CXX -E" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+ CXXCPP=$ac_cv_prog_CXXCPP
+else
+ ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details." "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+else
+ _lt_caught_CXX_error=yes
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+compiler_needs_object_CXX=no
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_direct_absolute_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_flag_spec_ld_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_shlibpath_var_CXX=unsupported
+hardcode_automatic_CXX=no
+inherit_rpath_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+reload_flag_CXX=$reload_flag
+reload_cmds_CXX=$reload_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+ # save warnings/boilerplate of simple test code
+ ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ compiler=$CC
+ compiler_CXX=$CC
+ for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+ else
+ lt_prog_compiler_no_builtin_flag_CXX=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_CXX=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+ ld_shlibs_CXX=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_CXX=''
+ hardcode_direct_CXX=yes
+ hardcode_direct_absolute_CXX=yes
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+ file_list_spec_CXX='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct_CXX=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_CXX=yes
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ hardcode_libdir_separator_CXX=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec_CXX='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ always_export_symbols_CXX=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_CXX='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_CXX="-z nodefs"
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_CXX=' ${wl}-bernotok'
+ allow_undefined_flag_CXX=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_CXX='$convenience'
+ fi
+ archive_cmds_need_lc_CXX=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_CXX=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-all-symbols'
+ allow_undefined_flag_CXX=unsupported
+ always_export_symbols_CXX=no
+ enable_shared_with_static_runtimes_CXX=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc_CXX=no
+ hardcode_direct_CXX=no
+ hardcode_automatic_CXX=yes
+ hardcode_shlibpath_var_CXX=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ else
+ whole_archive_flag_spec_CXX=''
+ fi
+ link_all_deplibs_CXX=yes
+ allow_undefined_flag_CXX="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+
+ else
+ ld_shlibs_CXX=no
+ fi
+
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ freebsd[12]*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ ld_shlibs_CXX=no
+ ;;
+
+ freebsd-elf*)
+ archive_cmds_need_lc_CXX=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ ld_shlibs_CXX=yes
+ ;;
+
+ gnu*)
+ ;;
+
+ haiku*)
+ archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs_CXX=yes
+ ;;
+
+ hpux9*)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ hardcode_direct_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC*)
+ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ ;;
+ *)
+ hardcode_direct_CXX=yes
+ hardcode_direct_absolute_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ fi
+ fi
+ link_all_deplibs_CXX=yes
+ ;;
+ esac
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ inherit_rpath_CXX=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ archive_cmds_need_lc_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [1-5].* | *pgcpp\ [1-5].*)
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ no_undefined_flag_CXX=' -zdefs'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object_CXX=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ ld_shlibs_CXX=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ ld_shlibs_CXX=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ hardcode_direct_absolute_CXX=yes
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ allow_undefined_flag_CXX=' -expect_unresolved \*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ ;;
+ esac
+
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ archive_cmds_need_lc_CXX=yes
+ no_undefined_flag_CXX=' -zdefs'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_shlibpath_var_CXX=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ link_all_deplibs_CXX=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag_CXX='${wl}-z,text'
+ archive_cmds_need_lc_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag_CXX='${wl}-z,text'
+ allow_undefined_flag_CXX='${wl}-z,nodefs'
+ archive_cmds_need_lc_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir'
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+ export_dynamic_flag_spec_CXX='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~
+ '"$old_archive_cmds_CXX"
+ reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~
+ '"$reload_cmds_CXX"
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+ test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+ GCC_CXX="$GXX"
+ LD_CXX="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ # Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$compiler_lib_search_path_CXX"; then
+ compiler_lib_search_path_CXX="${prev}${p}"
+ else
+ compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$postdeps_CXX"; then
+ postdeps_CXX="${prev}${p}"
+ else
+ postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$predep_objects_CXX"; then
+ predep_objects_CXX="$p"
+ else
+ predep_objects_CXX="$predep_objects_CXX $p"
+ fi
+ else
+ if test -z "$postdep_objects_CXX"; then
+ postdep_objects_CXX="$p"
+ else
+ postdep_objects_CXX="$postdep_objects_CXX $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+case $host_os in
+interix[3-9]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ predep_objects_CXX=
+ postdep_objects_CXX=
+ postdeps_CXX=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ postdeps_CXX='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ postdeps_CXX='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+ compiler_lib_search_dirs_CXX=
+if test -n "${compiler_lib_search_path_CXX}"; then
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_CXX='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ lt_prog_compiler_pic_CXX=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static_CXX=
+ ;;
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_CXX=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_CXX='-fPIC -shared'
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[4-9]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ else
+ lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ lt_prog_compiler_pic_CXX='+Z'
+ fi
+ ;;
+ aCC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-fPIC'
+ lt_prog_compiler_static_CXX='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-fpic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[cC]* | mpixl[cC]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-qpic'
+ lt_prog_compiler_static_CXX='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ lt_prog_compiler_wl_CXX='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ lt_prog_compiler_pic_CXX='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_CXX='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ lt_prog_compiler_wl_CXX='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ lt_prog_compiler_wl_CXX='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ lt_prog_compiler_pic_CXX='-pic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ lt_prog_compiler_can_build_shared_CXX=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_CXX=
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5
+$as_echo "$lt_prog_compiler_pic_CXX" >&6; }
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works_CXX=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works_CXX=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then
+ case $lt_prog_compiler_pic_CXX in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+ esac
+else
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works_CXX=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works_CXX=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works_CXX=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then
+ :
+else
+ lt_prog_compiler_static_CXX=
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o_CXX=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_CXX=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o_CXX=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_CXX=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix[4-9]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global defined
+ # symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ export_symbols_cmds_CXX="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+ exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+with_gnu_ld_CXX=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_CXX=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_CXX in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if test "${lt_cv_archive_cmds_need_lc_CXX+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_CXX
+ pic_flag=$lt_prog_compiler_pic_CXX
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+ allow_undefined_flag_CXX=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc_CXX=no
+ else
+ lt_cv_archive_cmds_need_lc_CXX=yes
+ fi
+ allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; }
+ archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[123]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+haiku*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" ||
+ test -n "$runpath_var_CXX" ||
+ test "X$hardcode_automatic_CXX" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct_CXX" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
+ test "$hardcode_minus_L_CXX" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_CXX=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_CXX=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_CXX=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
+$as_echo "$hardcode_action_CXX" >&6; }
+
+if test "$hardcode_action_CXX" = relink ||
+ test "$inherit_rpath_CXX" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+# Enable support for silent build rules
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no) AM_DEFAULT_VERBOSITY=1;;
+*) AM_DEFAULT_VERBOSITY=1;;
+esac
+AM_BACKSLASH='\'
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lc" >&5
+$as_echo_n "checking for main in -lc... " >&6; }
+if test "${ac_cv_lib_c_main+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+
+int
+main ()
+{
+return main ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_c_main=yes
+else
+ ac_cv_lib_c_main=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_main" >&5
+$as_echo "$ac_cv_lib_c_main" >&6; }
+if test "x$ac_cv_lib_c_main" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBC 1
+_ACEOF
+
+ LIBS="-lc $LIBS"
+
+fi
+
+
+case "${host_os}" in
+ cygwin* | mingw32* | beos* | darwin*)
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sin in -lm" >&5
+$as_echo_n "checking for sin in -lm... " >&6; }
+if test "${ac_cv_lib_m_sin+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sin ();
+int
+main ()
+{
+return sin ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_sin=yes
+else
+ ac_cv_lib_m_sin=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sin" >&5
+$as_echo "$ac_cv_lib_m_sin" >&6; }
+if test "x$ac_cv_lib_m_sin" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ ;;
+esac
+
+for ac_header in assert.h fcntl.h io.h limits.h malloc.h search.h sys/time.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+eval as_val=\$$as_ac_Header
+ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5
+$as_echo_n "checking for an ANSI C-conforming const... " >&6; }
+if test "${ac_cv_c_const+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset cs;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *pcpcc;
+ char **ppc;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ pcpcc = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++pcpcc;
+ ppc = (char**) pcpcc;
+ pcpcc = (char const *const *) ppc;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ if (s) return 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ if (!foo) return 0;
+ }
+ return !cs[0] && !zero.x;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_const=yes
+else
+ ac_cv_c_const=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5
+$as_echo "$ac_cv_c_const" >&6; }
+if test $ac_cv_c_const = no; then
+
+$as_echo "#define const /**/" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5
+$as_echo_n "checking for inline... " >&6; }
+if test "${ac_cv_c_inline+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_inline=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$ac_cv_c_inline" != no && break
+done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5
+$as_echo "$ac_cv_c_inline" >&6; }
+
+case $ac_cv_c_inline in
+ inline | yes) ;;
+ *)
+ case $ac_cv_c_inline in
+ no) ac_val=;;
+ *) ac_val=$ac_cv_c_inline;;
+ esac
+ cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+ ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if test "${ac_cv_c_bigendian+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_c_bigendian=unknown
+ # See if we're dealing with a universal compiler.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifndef __APPLE_CC__
+ not a universal capable compiler
+ #endif
+ typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+ # Check for potential -arch flags. It is not universal unless
+ # there are at least two -arch flags with different values.
+ ac_arch=
+ ac_prev=
+ for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+ if test -n "$ac_prev"; then
+ case $ac_word in
+ i?86 | x86_64 | ppc | ppc64)
+ if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+ ac_arch=$ac_word
+ else
+ ac_cv_c_bigendian=universal
+ break
+ fi
+ ;;
+ esac
+ ac_prev=
+ elif test "x$ac_word" = "x-arch"; then
+ ac_prev=arch
+ fi
+ done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if sys/param.h defines the BYTE_ORDER macro.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+ && LITTLE_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ #include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+ bogus endian macros
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ # It does; now see whether it defined to _BIG_ENDIAN or not.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+ not big endian
+ #endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_c_bigendian=yes
+else
+ ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+ if test $ac_cv_c_bigendian = unknown; then
+ # Compile a test program.
+ if test "$cross_compiling" = yes; then :
+ # Try to guess by grepping values from an object file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+short int ascii_mm[] =
+ { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+ short int ascii_ii[] =
+ { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+ int use_ascii (int i) {
+ return ascii_mm[i] + ascii_ii[i];
+ }
+ short int ebcdic_ii[] =
+ { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+ short int ebcdic_mm[] =
+ { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+ int use_ebcdic (int i) {
+ return ebcdic_mm[i] + ebcdic_ii[i];
+ }
+ extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+ ac_cv_c_bigendian=yes
+ fi
+ if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+ if test "$ac_cv_c_bigendian" = unknown; then
+ ac_cv_c_bigendian=no
+ else
+ # finding both strings is unlikely to happen, but who knows?
+ ac_cv_c_bigendian=unknown
+ fi
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$ac_includes_default
+int
+main ()
+{
+
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long int l;
+ char c[sizeof (long int)];
+ } u;
+ u.l = 1;
+ return u.c[sizeof (long int) - 1] == 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ ac_cv_c_bigendian=no
+else
+ ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+ yes)
+ $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+ no)
+ ;; #(
+ universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+ ;; #(
+ *)
+ as_fn_error "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default"
+if test "x$ac_cv_type_off_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define off_t long int
+_ACEOF
+
+fi
+
+ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default"
+if test "x$ac_cv_type_size_t" = x""yes; then :
+
+else
+
+cat >>confdefs.h <<_ACEOF
+#define size_t unsigned int
+_ACEOF
+
+fi
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5
+$as_echo_n "checking size of int... " >&6; }
+if test "${ac_cv_sizeof_int+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_int" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (int)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_int=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5
+$as_echo "$ac_cv_sizeof_int" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_INT $ac_cv_sizeof_int
+_ACEOF
+
+
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5
+$as_echo_n "checking size of long... " >&6; }
+if test "${ac_cv_sizeof_long+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (long)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5
+$as_echo "$ac_cv_sizeof_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_LONG $ac_cv_sizeof_long
+_ACEOF
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5
+$as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; }
+if test "${ac_cv_header_time+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_time=yes
+else
+ ac_cv_header_time=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_time" >&5
+$as_echo "$ac_cv_header_time" >&6; }
+if test $ac_cv_header_time = yes; then
+
+$as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
+$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
+if test "${ac_cv_struct_tm+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+ int *p = &tm.tm_sec;
+ return !p;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_struct_tm=time.h
+else
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5
+$as_echo "$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+
+$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h
+
+fi
+
+ac_fn_c_check_type "$LINENO" "int8" "ac_cv_type_int8" "
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+"
+if test "x$ac_cv_type_int8" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INT8 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "int16" "ac_cv_type_int16" "
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+"
+if test "x$ac_cv_type_int16" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INT16 1
+_ACEOF
+
+
+fi
+ac_fn_c_check_type "$LINENO" "int32" "ac_cv_type_int32" "
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+"
+if test "x$ac_cv_type_int32" = x""yes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_INT32 1
+_ACEOF
+
+
+fi
+
+
+# Obtain size of a 'signed long' and define as SIZEOF_SIGNED_LONG
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of signed long" >&5
+$as_echo_n "checking size of signed long... " >&6; }
+if test "${ac_cv_sizeof_signed_long+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (signed long))" "ac_cv_sizeof_signed_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_signed_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (signed long)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_signed_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_signed_long" >&5
+$as_echo "$ac_cv_sizeof_signed_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIGNED_LONG $ac_cv_sizeof_signed_long
+_ACEOF
+
+
+
+# Obtain size of a 'unsigned long' and define as SIZEOF_UNSIGNED_LONG
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5
+$as_echo_n "checking size of unsigned long... " >&6; }
+if test "${ac_cv_sizeof_unsigned_long+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (unsigned long)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_unsigned_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5
+$as_echo "$ac_cv_sizeof_unsigned_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
+_ACEOF
+
+
+
+# Obtain size of a 'long long' and define as SIZEOF_SIGNED_LONG_LONG.
+# If 'long long' is not supported then the value defined is zero.
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of signed long long" >&5
+$as_echo_n "checking size of signed long long... " >&6; }
+if test "${ac_cv_sizeof_signed_long_long+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (signed long long))" "ac_cv_sizeof_signed_long_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_signed_long_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (signed long long)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_signed_long_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_signed_long_long" >&5
+$as_echo "$ac_cv_sizeof_signed_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_SIGNED_LONG_LONG $ac_cv_sizeof_signed_long_long
+_ACEOF
+
+
+
+# Obtain size of a 'unsigned long long' and define as
+# SIZEOF_UNSIGNED_LONG_LONG. If 'unsigned long long' is not
+# supported then the value defined is zero.
+# The cast to long int works around a bug in the HP C Compiler
+# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
+# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
+# This bug is HP SR number 8606223364.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long long" >&5
+$as_echo_n "checking size of unsigned long long... " >&6; }
+if test "${ac_cv_sizeof_unsigned_long_long+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long long))" "ac_cv_sizeof_unsigned_long_long" "$ac_includes_default"; then :
+
+else
+ if test "$ac_cv_type_unsigned_long_long" = yes; then
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ as_fn_set_status 77
+as_fn_error "cannot compute sizeof (unsigned long long)
+See \`config.log' for more details." "$LINENO" 5; }; }
+ else
+ ac_cv_sizeof_unsigned_long_long=0
+ fi
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long_long" >&5
+$as_echo "$ac_cv_sizeof_unsigned_long_long" >&6; }
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define SIZEOF_UNSIGNED_LONG_LONG $ac_cv_sizeof_unsigned_long_long
+_ACEOF
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for signed 64-bit type" >&5
+$as_echo_n "checking for signed 64-bit type... " >&6; }
+INT64_T='none'
+INT64_FORMAT='none'
+if test $ac_cv_sizeof_signed_long -eq 8
+then
+ INT64_T='signed long'
+ INT64_FORMAT='"%ld"'
+elif test $ac_cv_sizeof_signed_long_long -eq 8
+then
+ INT64_FORMAT='"%lld"'
+ INT64_T='signed long long'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INT64_T" >&5
+$as_echo "$INT64_T" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define TIFF_INT64_T $INT64_T
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define TIFF_INT64_FORMAT $INT64_FORMAT
+_ACEOF
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for unsigned 64-bit type" >&5
+$as_echo_n "checking for unsigned 64-bit type... " >&6; }
+UINT64_T='none'
+UINT64_FORMAT='none'
+if test $ac_cv_sizeof_unsigned_long -eq 8
+then
+ UINT64_T='unsigned long'
+ UINT64_FORMAT='"%lu"'
+elif test $ac_cv_sizeof_unsigned_long_long -eq 8
+then
+ UINT64_T='unsigned long long'
+ UINT64_FORMAT='"%llu"'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $UINT64_T" >&5
+$as_echo "$UINT64_T" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define TIFF_UINT64_T $UINT64_T
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define TIFF_UINT64_FORMAT $UINT64_FORMAT
+_ACEOF
+
+
+for ac_func in floor isascii memmove memset mmap pow setmode sqrt strchr strrchr strstr strtol
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+for ac_func in getopt
+do :
+ ac_fn_c_check_func "$LINENO" "getopt" "ac_cv_func_getopt"
+if test "x$ac_cv_func_getopt" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_GETOPT 1
+_ACEOF
+
+else
+ case " $LIBOBJS " in
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext"
+ ;;
+esac
+
+fi
+done
+
+
+for ac_func in strcasecmp
+do :
+ ac_fn_c_check_func "$LINENO" "strcasecmp" "ac_cv_func_strcasecmp"
+if test "x$ac_cv_func_strcasecmp" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STRCASECMP 1
+_ACEOF
+
+else
+ case " $LIBOBJS " in
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext"
+ ;;
+esac
+
+fi
+done
+
+
+for ac_func in strtoul
+do :
+ ac_fn_c_check_func "$LINENO" "strtoul" "ac_cv_func_strtoul"
+if test "x$ac_cv_func_strtoul" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_STRTOUL 1
+_ACEOF
+
+else
+ case " $LIBOBJS " in
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext"
+ ;;
+esac
+
+fi
+done
+
+
+for ac_func in lfind
+do :
+ ac_fn_c_check_func "$LINENO" "lfind" "ac_cv_func_lfind"
+if test "x$ac_cv_func_lfind" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LFIND 1
+_ACEOF
+
+else
+ case " $LIBOBJS " in
+ *" $ac_func.$ac_objext "* ) ;;
+ *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext"
+ ;;
+esac
+
+fi
+done
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking native cpu bit order" >&5
+$as_echo_n "checking native cpu bit order... " >&6; }
+case "$target_cpu" in
+ i*86*|x86_64*)
+ HOST_FILLORDER=FILLORDER_LSB2MSB
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: lsb2msb" >&5
+$as_echo "lsb2msb" >&6; }
+ ;;
+ *)
+ HOST_FILLORDER=FILLORDER_MSB2LSB
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: msb2lsb" >&5
+$as_echo "msb2lsb" >&6; }
+ ;;
+esac
+
+cat >>confdefs.h <<_ACEOF
+#define HOST_FILLORDER $HOST_FILLORDER
+_ACEOF
+
+
+if test "$ac_cv_c_bigendian" = yes ; then
+ HOST_BIGENDIAN=1
+else
+ HOST_BIGENDIAN=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HOST_BIGENDIAN $HOST_BIGENDIAN
+_ACEOF
+
+
+#_POSIX_C_SOURCE=2
+#AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE, $_POSIX_C_SOURCE, [Define this macro to a positive integer to control which POSIX functionality is made available.])
+
+HAVE_IEEEFP=1
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_IEEEFP $HAVE_IEEEFP
+_ACEOF
+
+
+
+# Check whether --enable-rpath was given.
+if test "${enable_rpath+set}" = set; then :
+ enableval=$enable_rpath; HAVE_RPATH=$enableval
+else
+ HAVE_RPATH=no
+fi
+
+ if test "$HAVE_RPATH" = "yes"; then
+ HAVE_RPATH_TRUE=
+ HAVE_RPATH_FALSE='#'
+else
+ HAVE_RPATH_TRUE='#'
+ HAVE_RPATH_FALSE=
+fi
+
+
+
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then :
+ enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
+if test "${ac_cv_sys_largefile_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_sys_largefile_CC=no
+ if test "$GCC" != yes; then
+ ac_save_CC=$CC
+ while :; do
+ # IRIX 6.2 and later do not support large files by default,
+ # so use the C compiler's -n32 option if that helps.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_c_try_compile "$LINENO"; then :
+ break
+fi
+rm -f core conftest.err conftest.$ac_objext
+ CC="$CC -n32"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext
+ break
+ done
+ CC=$ac_save_CC
+ rm -f conftest.$ac_ext
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+ if test "$ac_cv_sys_largefile_CC" != no; then
+ CC=$CC$ac_cv_sys_largefile_CC
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if test "${ac_cv_sys_file_offset_bits+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_sys_file_offset_bits=unknown
+ break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -rf conftest*
+ if test $ac_cv_sys_file_offset_bits = unknown; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
+if test "${ac_cv_sys_large_files+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ while :; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+ We can't simply define LARGE_OFF_T to be 9223372036854775807,
+ since some C++ compilers masquerading as C compilers
+ incorrectly reject 9223372036854775807. */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+ int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+ && LARGE_OFF_T % 2147483647 == 1)
+ ? 1 : -1];
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cv_sys_large_files=unknown
+ break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+$as_echo "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+ no | unknown) ;;
+ *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -rf conftest*
+ fi
+fi
+
+
+
+LIBTIFF_DOCDIR=\${prefix}/share/doc/${PACKAGE}-${LIBTIFF_VERSION}
+
+
+# Check whether --with-docdir was given.
+if test "${with_docdir+set}" = set; then :
+ withval=$with_docdir;
+fi
+
+if test "x$with_docdir" != "x" ; then
+ LIBTIFF_DOCDIR=$with_docdir
+fi
+
+
+
+
+# Check whether --enable-ccitt was given.
+if test "${enable_ccitt+set}" = set; then :
+ enableval=$enable_ccitt; HAVE_CCITT=$enableval
+else
+ HAVE_CCITT=yes
+fi
+
+
+if test "$HAVE_CCITT" = "yes" ; then
+
+$as_echo "#define CCITT_SUPPORT 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-packbits was given.
+if test "${enable_packbits+set}" = set; then :
+ enableval=$enable_packbits; HAVE_PACKBITS=$enableval
+else
+ HAVE_PACKBITS=yes
+fi
+
+
+if test "$HAVE_PACKBITS" = "yes" ; then
+
+$as_echo "#define PACKBITS_SUPPORT 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-lzw was given.
+if test "${enable_lzw+set}" = set; then :
+ enableval=$enable_lzw; HAVE_LZW=$enableval
+else
+ HAVE_LZW=yes
+fi
+
+
+if test "$HAVE_LZW" = "yes" ; then
+
+$as_echo "#define LZW_SUPPORT 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-thunder was given.
+if test "${enable_thunder+set}" = set; then :
+ enableval=$enable_thunder; HAVE_THUNDER=$enableval
+else
+ HAVE_THUNDER=yes
+fi
+
+
+if test "$HAVE_THUNDER" = "yes" ; then
+
+$as_echo "#define THUNDER_SUPPORT 1" >>confdefs.h
+
+fi
+
+HAVE_NEXT=yes
+
+# Check whether --enable-next was given.
+if test "${enable_next+set}" = set; then :
+ enableval=$enable_next; HAVE_NEXT=$enableval
+else
+ HAVE_NEXT=yes
+fi
+
+
+if test "$HAVE_NEXT" = "yes" ; then
+
+$as_echo "#define NEXT_SUPPORT 1" >>confdefs.h
+
+fi
+
+# Check whether --enable-logluv was given.
+if test "${enable_logluv+set}" = set; then :
+ enableval=$enable_logluv; HAVE_LOGLUV=$enableval
+else
+ HAVE_LOGLUV=yes
+fi
+
+
+if test "$HAVE_LOGLUV" = "yes" ; then
+
+$as_echo "#define LOGLUV_SUPPORT 1" >>confdefs.h
+
+fi
+
+
+# Check whether --enable-mdi was given.
+if test "${enable_mdi+set}" = set; then :
+ enableval=$enable_mdi; HAVE_MDI=$enableval
+else
+ HAVE_MDI=yes
+fi
+
+
+if test "$HAVE_MDI" = "yes" ; then
+
+$as_echo "#define MDI_SUPPORT 1" >>confdefs.h
+
+fi
+
+
+HAVE_ZLIB=no
+
+# Check whether --enable-zlib was given.
+if test "${enable_zlib+set}" = set; then :
+ enableval=$enable_zlib;
+fi
+
+
+# Check whether --with-zlib-include-dir was given.
+if test "${with_zlib_include_dir+set}" = set; then :
+ withval=$with_zlib_include_dir;
+fi
+
+
+# Check whether --with-zlib-lib-dir was given.
+if test "${with_zlib_lib_dir+set}" = set; then :
+ withval=$with_zlib_lib_dir;
+fi
+
+
+if test "x$enable_zlib" != "xno" ; then
+
+ if test "x$with_zlib_lib_dir" != "x" ; then
+ LDFLAGS="-L$with_zlib_lib_dir $LDFLAGS"
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inflateEnd in -lz" >&5
+$as_echo_n "checking for inflateEnd in -lz... " >&6; }
+if test "${ac_cv_lib_z_inflateEnd+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inflateEnd ();
+int
+main ()
+{
+return inflateEnd ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_z_inflateEnd=yes
+else
+ ac_cv_lib_z_inflateEnd=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_inflateEnd" >&5
+$as_echo "$ac_cv_lib_z_inflateEnd" >&6; }
+if test "x$ac_cv_lib_z_inflateEnd" = x""yes; then :
+ zlib_lib=yes
+else
+ zlib_lib=no
+fi
+
+ if test "$zlib_lib" = "no" -a "x$with_zlib_lib_dir" != "x"; then
+ as_fn_error "Zlib library not found at $with_zlib_lib_dir" "$LINENO" 5
+ fi
+
+ if test "x$with_zlib_include_dir" != "x" ; then
+ CPPFLAGS="-I$with_zlib_include_dir $CPPFLAGS"
+ fi
+ ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default"
+if test "x$ac_cv_header_zlib_h" = x""yes; then :
+ zlib_h=yes
+else
+ zlib_h=no
+fi
+
+
+ if test "$zlib_h" = "no" -a "x$with_zlib_include_dir" != "x" ; then
+ as_fn_error "Zlib headers not found at $with_zlib_include_dir" "$LINENO" 5
+ fi
+
+ if test "$zlib_lib" = "yes" -a "$zlib_h" = "yes" ; then
+ HAVE_ZLIB=yes
+ fi
+
+fi
+
+if test "$HAVE_ZLIB" = "yes" ; then
+
+$as_echo "#define ZIP_SUPPORT 1" >>confdefs.h
+
+ LIBS="-lz $LIBS"
+
+ if test "$HAVE_RPATH" = "yes" -a "x$with_zlib_lib_dir" != "x" ; then
+ LIBDIR="-R $with_zlib_lib_dir $LIBDIR"
+ fi
+
+fi
+
+
+# Check whether --enable-pixarlog was given.
+if test "${enable_pixarlog+set}" = set; then :
+ enableval=$enable_pixarlog; HAVE_PIXARLOG=$enableval
+else
+ HAVE_PIXARLOG=yes
+fi
+
+
+if test "$HAVE_ZLIB" = "yes" -a "$HAVE_PIXARLOG" = "yes" ; then
+
+$as_echo "#define PIXARLOG_SUPPORT 1" >>confdefs.h
+
+else
+ HAVE_PIXARLOG=no
+fi
+
+
+HAVE_JPEG=no
+
+# Check whether --enable-jpeg was given.
+if test "${enable_jpeg+set}" = set; then :
+ enableval=$enable_jpeg;
+fi
+
+
+# Check whether --with-jpeg-include-dir was given.
+if test "${with_jpeg_include_dir+set}" = set; then :
+ withval=$with_jpeg_include_dir;
+fi
+
+
+# Check whether --with-jpeg-lib-dir was given.
+if test "${with_jpeg_lib_dir+set}" = set; then :
+ withval=$with_jpeg_lib_dir;
+fi
+
+
+if test "x$enable_jpeg" != "xno" ; then
+
+ if test "x$with_jpeg_lib_dir" != "x" ; then
+ LDFLAGS="-L$with_jpeg_lib_dir $LDFLAGS"
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jpeg_read_scanlines in -ljpeg" >&5
+$as_echo_n "checking for jpeg_read_scanlines in -ljpeg... " >&6; }
+if test "${ac_cv_lib_jpeg_jpeg_read_scanlines+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljpeg $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char jpeg_read_scanlines ();
+int
+main ()
+{
+return jpeg_read_scanlines ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_jpeg_jpeg_read_scanlines=yes
+else
+ ac_cv_lib_jpeg_jpeg_read_scanlines=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jpeg_jpeg_read_scanlines" >&5
+$as_echo "$ac_cv_lib_jpeg_jpeg_read_scanlines" >&6; }
+if test "x$ac_cv_lib_jpeg_jpeg_read_scanlines" = x""yes; then :
+ jpeg_lib=yes
+else
+ jpeg_lib=no
+fi
+
+ if test "$jpeg_lib" = "no" -a "x$with_jpeg_lib_dir" != "x" ; then
+ as_fn_error "IJG JPEG library not found at $with_jpeg_lib_dir" "$LINENO" 5
+ fi
+
+ if test "x$with_jpeg_include_dir" != "x" ; then
+ CPPFLAGS="-I$with_jpeg_include_dir $CPPFLAGS"
+ fi
+ ac_fn_c_check_header_mongrel "$LINENO" "jpeglib.h" "ac_cv_header_jpeglib_h" "$ac_includes_default"
+if test "x$ac_cv_header_jpeglib_h" = x""yes; then :
+ jpeg_h=yes
+else
+ jpeg_h=no
+fi
+
+
+ if test "$jpeg_h" = "no" -a "x$with_jpeg_include_dir" != "x" ; then
+ as_fn_error "IJG JPEG library headers not found at $with_jpeg_include_dir" "$LINENO" 5
+ fi
+
+ if test "$jpeg_lib" = "yes" -a "$jpeg_h" = "yes" ; then
+ HAVE_JPEG=yes
+ fi
+
+fi
+
+if test "$HAVE_JPEG" = "yes" ; then
+
+$as_echo "#define JPEG_SUPPORT 1" >>confdefs.h
+
+ LIBS="-ljpeg $LIBS"
+
+ if test "$HAVE_RPATH" = "yes" -a "x$with_jpeg_lib_dir" != "x" ; then
+ LIBDIR="-R $with_jpeg_lib_dir $LIBDIR"
+ fi
+
+fi
+
+
+# Check whether --enable-old-jpeg was given.
+if test "${enable_old_jpeg+set}" = set; then :
+ enableval=$enable_old_jpeg; HAVE_OJPEG=${enableval}
+else
+ HAVE_OJPEG=yes
+fi
+
+
+if test "$HAVE_JPEG" = "yes" -a "$HAVE_OJPEG" = "yes" ; then
+
+$as_echo "#define OJPEG_SUPPORT 1" >>confdefs.h
+
+else
+ HAVE_OJPEG=no
+fi
+
+
+HAVE_JBIG=no
+
+# Check whether --enable-jbig was given.
+if test "${enable_jbig+set}" = set; then :
+ enableval=$enable_jbig;
+fi
+
+
+# Check whether --with-jbig-include-dir was given.
+if test "${with_jbig_include_dir+set}" = set; then :
+ withval=$with_jbig_include_dir;
+fi
+
+
+# Check whether --with-jbig-lib-dir was given.
+if test "${with_jbig_lib_dir+set}" = set; then :
+ withval=$with_jbig_lib_dir;
+fi
+
+
+if test "x$enable_jbig" != "xno" ; then
+
+ if test "x$with_jbig_lib_dir" != "x" ; then
+ LDFLAGS="-L$with_jbig_lib_dir $LDFLAGS"
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for jbg_dec_init in -ljbig" >&5
+$as_echo_n "checking for jbg_dec_init in -ljbig... " >&6; }
+if test "${ac_cv_lib_jbig_jbg_dec_init+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ljbig $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char jbg_dec_init ();
+int
+main ()
+{
+return jbg_dec_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_jbig_jbg_dec_init=yes
+else
+ ac_cv_lib_jbig_jbg_dec_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_jbig_jbg_dec_init" >&5
+$as_echo "$ac_cv_lib_jbig_jbg_dec_init" >&6; }
+if test "x$ac_cv_lib_jbig_jbg_dec_init" = x""yes; then :
+ jbig_lib=yes
+else
+ jbig_lib=no
+fi
+
+ if test "$jbig_lib" = "no" -a "x$with_jbig_lib_dir" != "x" ; then
+ as_fn_error "JBIG-KIT library not found at $with_jbig_lib_dir" "$LINENO" 5
+ fi
+
+ if test "x$with_jbig_include_dir" != "x" ; then
+ CPPFLAGS="-I$with_jbig_include_dir $CPPFLAGS"
+ fi
+ ac_fn_c_check_header_mongrel "$LINENO" "jbig.h" "ac_cv_header_jbig_h" "$ac_includes_default"
+if test "x$ac_cv_header_jbig_h" = x""yes; then :
+ jbig_h=yes
+else
+ jbig_h=no
+fi
+
+
+ if test "$jbig_h" = "no" -a "x$with_jbig_include_dir" != "x" ; then
+ as_fn_error "JBIG-KIT library headers not found at $with_jbig_include_dir" "$LINENO" 5
+ fi
+
+ if test "$jbig_lib" = "yes" -a "$jbig_h" = "yes" ; then
+ HAVE_JBIG=yes
+ fi
+
+fi
+
+if test "$HAVE_JBIG" = "yes" ; then
+
+$as_echo "#define JBIG_SUPPORT 1" >>confdefs.h
+
+ LIBS="-ljbig $LIBS"
+
+ if test "$HAVE_RPATH" = "yes" -a "x$with_jbig_lib_dir" != "x" ; then
+ LIBDIR="-R $with_jbig_lib_dir $LIBDIR"
+ fi
+
+ # Older versions of jbigkit lack jbg_newlen
+ for ac_func in jbg_newlen
+do :
+ ac_fn_c_check_func "$LINENO" "jbg_newlen" "ac_cv_func_jbg_newlen"
+if test "x$ac_cv_func_jbg_newlen" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_JBG_NEWLEN 1
+_ACEOF
+
+fi
+done
+
+
+fi
+
+
+# Check whether --enable-cxx was given.
+if test "${enable_cxx+set}" = set; then :
+ enableval=$enable_cxx; HAVE_CXX=$enableval
+else
+ HAVE_CXX=yes
+fi
+
+
+if test "$HAVE_CXX" = "yes" ; then
+
+$as_echo "#define CXX_SUPPORT 1" >>confdefs.h
+
+else
+ HAVE_CXX=no
+fi
+
+ if test "$HAVE_CXX" = "yes"; then
+ HAVE_CXX_TRUE=
+ HAVE_CXX_FALSE='#'
+else
+ HAVE_CXX_TRUE='#'
+ HAVE_CXX_FALSE=
+fi
+
+
+
+HAVE_OPENGL=no
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5
+$as_echo_n "checking for X... " >&6; }
+
+
+# Check whether --with-x was given.
+if test "${with_x+set}" = set; then :
+ withval=$with_x;
+fi
+
+# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
+if test "x$with_x" = xno; then
+ # The user explicitly disabled X.
+ have_x=disabled
+else
+ case $x_includes,$x_libraries in #(
+ *\'*) as_fn_error "cannot use X directory names containing '" "$LINENO" 5;; #(
+ *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ # One or both of the vars are not set, and there is no cached value.
+ac_x_includes=no ac_x_libraries=no
+rm -f -r conftest.dir
+if mkdir conftest.dir; then
+ cd conftest.dir
+ cat >Imakefile <<'_ACEOF'
+incroot:
+ @echo incroot='${INCROOT}'
+usrlibdir:
+ @echo usrlibdir='${USRLIBDIR}'
+libdir:
+ @echo libdir='${LIBDIR}'
+_ACEOF
+ if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then
+ # GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+ for ac_var in incroot usrlibdir libdir; do
+ eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`"
+ done
+ # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
+ for ac_extension in a so sl dylib la dll; do
+ if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" &&
+ test -f "$ac_im_libdir/libX11.$ac_extension"; then
+ ac_im_usrlibdir=$ac_im_libdir; break
+ fi
+ done
+ # Screen out bogus values from the imake configuration. They are
+ # bogus both because they are the default anyway, and because
+ # using them would break gcc on systems where it needs fixed includes.
+ case $ac_im_incroot in
+ /usr/include) ac_x_includes= ;;
+ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;;
+ esac
+ case $ac_im_usrlibdir in
+ /usr/lib | /usr/lib64 | /lib | /lib64) ;;
+ *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;;
+ esac
+ fi
+ cd ..
+ rm -f -r conftest.dir
+fi
+
+# Standard set of common directories for X headers.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ac_x_header_dirs='
+/usr/X11/include
+/usr/X11R7/include
+/usr/X11R6/include
+/usr/X11R5/include
+/usr/X11R4/include
+
+/usr/include/X11
+/usr/include/X11R7
+/usr/include/X11R6
+/usr/include/X11R5
+/usr/include/X11R4
+
+/usr/local/X11/include
+/usr/local/X11R7/include
+/usr/local/X11R6/include
+/usr/local/X11R5/include
+/usr/local/X11R4/include
+
+/usr/local/include/X11
+/usr/local/include/X11R7
+/usr/local/include/X11R6
+/usr/local/include/X11R5
+/usr/local/include/X11R4
+
+/usr/X386/include
+/usr/x386/include
+/usr/XFree86/include/X11
+
+/usr/include
+/usr/local/include
+/usr/unsupported/include
+/usr/athena/include
+/usr/local/x11r5/include
+/usr/lpp/Xamples/include
+
+/usr/openwin/include
+/usr/openwin/share/include'
+
+if test "$ac_x_includes" = no; then
+ # Guess where to find include files, by looking for Xlib.h.
+ # First, try using that file with no special directory specified.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # We can compile using X headers with no special include directory.
+ac_x_includes=
+else
+ for ac_dir in $ac_x_header_dirs; do
+ if test -r "$ac_dir/X11/Xlib.h"; then
+ ac_x_includes=$ac_dir
+ break
+ fi
+done
+fi
+rm -f conftest.err conftest.$ac_ext
+fi # $ac_x_includes = no
+
+if test "$ac_x_libraries" = no; then
+ # Check for the libraries.
+ # See if we find them without any special options.
+ # Don't add to $LIBS permanently.
+ ac_save_LIBS=$LIBS
+ LIBS="-lX11 $LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <X11/Xlib.h>
+int
+main ()
+{
+XrmInitialize ()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ LIBS=$ac_save_LIBS
+# We can link X programs with no special library path.
+ac_x_libraries=
+else
+ LIBS=$ac_save_LIBS
+for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g`
+do
+ # Don't even attempt the hair of trying to link an X program!
+ for ac_extension in a so sl dylib la dll; do
+ if test -r "$ac_dir/libX11.$ac_extension"; then
+ ac_x_libraries=$ac_dir
+ break 2
+ fi
+ done
+done
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi # $ac_x_libraries = no
+
+case $ac_x_includes,$ac_x_libraries in #(
+ no,* | *,no | *\'*)
+ # Didn't find X, or a directory has "'" in its name.
+ ac_cv_have_x="have_x=no";; #(
+ *)
+ # Record where we found X for the cache.
+ ac_cv_have_x="have_x=yes\
+ ac_x_includes='$ac_x_includes'\
+ ac_x_libraries='$ac_x_libraries'"
+esac
+fi
+;; #(
+ *) have_x=yes;;
+ esac
+ eval "$ac_cv_have_x"
+fi # $with_x != no
+
+if test "$have_x" != yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5
+$as_echo "$have_x" >&6; }
+ no_x=yes
+else
+ # If each of the values was on the command line, it overrides each guess.
+ test "x$x_includes" = xNONE && x_includes=$ac_x_includes
+ test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries
+ # Update the cache value to reflect the command line values.
+ ac_cv_have_x="have_x=yes\
+ ac_x_includes='$x_includes'\
+ ac_x_libraries='$x_libraries'"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5
+$as_echo "libraries $x_libraries, headers $x_includes" >&6; }
+fi
+
+if test "$no_x" = yes; then
+ # Not all programs may use this symbol, but it does not hurt to define it.
+
+$as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h
+
+ X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS=
+else
+ if test -n "$x_includes"; then
+ X_CFLAGS="$X_CFLAGS -I$x_includes"
+ fi
+
+ # It would also be nice to do this for all -L options, not just this one.
+ if test -n "$x_libraries"; then
+ X_LIBS="$X_LIBS -L$x_libraries"
+ # For Solaris; some versions of Sun CC require a space after -R and
+ # others require no space. Words are not sufficient . . . .
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5
+$as_echo_n "checking whether -R must be followed by a space... " >&6; }
+ ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries"
+ ac_xsave_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ X_LIBS="$X_LIBS -R$x_libraries"
+else
+ LIBS="$ac_xsave_LIBS -R $x_libraries"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ X_LIBS="$X_LIBS -R $x_libraries"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5
+$as_echo "neither works" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_c_werror_flag=$ac_xsave_c_werror_flag
+ LIBS=$ac_xsave_LIBS
+ fi
+
+ # Check for system-dependent libraries X programs must link with.
+ # Do this before checking for the system-independent R6 libraries
+ # (-lICE), since we may need -lsocket or whatever for X linking.
+
+ if test "$ISC" = yes; then
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet"
+ else
+ # Martyn Johnson says this is needed for Ultrix, if the X
+ # libraries were built with DECnet support. And Karl Berry says
+ # the Alpha needs dnet_stub (dnet does not exist).
+ ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char XOpenDisplay ();
+int
+main ()
+{
+return XOpenDisplay ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; }
+if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dnet_dnet_ntoa=yes
+else
+ ac_cv_lib_dnet_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet"
+fi
+
+ if test $ac_cv_lib_dnet_dnet_ntoa = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5
+$as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; }
+if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldnet_stub $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dnet_ntoa ();
+int
+main ()
+{
+return dnet_ntoa ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dnet_stub_dnet_ntoa=yes
+else
+ ac_cv_lib_dnet_stub_dnet_ntoa=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5
+$as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; }
+if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub"
+fi
+
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_xsave_LIBS"
+
+ # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT,
+ # to get the SysV transport functions.
+ # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4)
+ # needs -lnsl.
+ # The nsl library prevents programs from opening the X display
+ # on Irix 5.2, according to T.E. Dickey.
+ # The functions gethostbyname, getservbyname, and inet_addr are
+ # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking.
+ ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname"
+if test "x$ac_cv_func_gethostbyname" = x""yes; then :
+
+fi
+
+ if test $ac_cv_func_gethostbyname = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5
+$as_echo_n "checking for gethostbyname in -lnsl... " >&6; }
+if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnsl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_nsl_gethostbyname=yes
+else
+ ac_cv_lib_nsl_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5
+$as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; }
+if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl"
+fi
+
+ if test $ac_cv_lib_nsl_gethostbyname = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5
+$as_echo_n "checking for gethostbyname in -lbsd... " >&6; }
+if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lbsd $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_bsd_gethostbyname=yes
+else
+ ac_cv_lib_bsd_gethostbyname=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5
+$as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; }
+if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd"
+fi
+
+ fi
+ fi
+
+ # lieder@skyler.mavd.honeywell.com says without -lsocket,
+ # socket/setsockopt and other routines are undefined under SCO ODT
+ # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary
+ # on later versions), says Simon Leinen: it contains gethostby*
+ # variants that don't use the name server (or something). -lsocket
+ # must be given before -lnsl if both are needed. We assume that
+ # if connect needs -lnsl, so does gethostbyname.
+ ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect"
+if test "x$ac_cv_func_connect" = x""yes; then :
+
+fi
+
+ if test $ac_cv_func_connect = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5
+$as_echo_n "checking for connect in -lsocket... " >&6; }
+if test "${ac_cv_lib_socket_connect+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsocket $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char connect ();
+int
+main ()
+{
+return connect ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_socket_connect=yes
+else
+ ac_cv_lib_socket_connect=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5
+$as_echo "$ac_cv_lib_socket_connect" >&6; }
+if test "x$ac_cv_lib_socket_connect" = x""yes; then :
+ X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS"
+fi
+
+ fi
+
+ # Guillermo Gomez says -lposix is necessary on A/UX.
+ ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove"
+if test "x$ac_cv_func_remove" = x""yes; then :
+
+fi
+
+ if test $ac_cv_func_remove = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5
+$as_echo_n "checking for remove in -lposix... " >&6; }
+if test "${ac_cv_lib_posix_remove+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lposix $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char remove ();
+int
+main ()
+{
+return remove ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_posix_remove=yes
+else
+ ac_cv_lib_posix_remove=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5
+$as_echo "$ac_cv_lib_posix_remove" >&6; }
+if test "x$ac_cv_lib_posix_remove" = x""yes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix"
+fi
+
+ fi
+
+ # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay.
+ ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat"
+if test "x$ac_cv_func_shmat" = x""yes; then :
+
+fi
+
+ if test $ac_cv_func_shmat = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5
+$as_echo_n "checking for shmat in -lipc... " >&6; }
+if test "${ac_cv_lib_ipc_shmat+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lipc $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shmat ();
+int
+main ()
+{
+return shmat ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ipc_shmat=yes
+else
+ ac_cv_lib_ipc_shmat=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5
+$as_echo "$ac_cv_lib_ipc_shmat" >&6; }
+if test "x$ac_cv_lib_ipc_shmat" = x""yes; then :
+ X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc"
+fi
+
+ fi
+ fi
+
+ # Check for libraries that X11R6 Xt/Xaw programs need.
+ ac_save_LDFLAGS=$LDFLAGS
+ test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries"
+ # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to
+ # check for ICE first), but we must link in the order -lSM -lICE or
+ # we get undefined symbols. So assume we have SM if we have ICE.
+ # These have to be linked with before -lX11, unlike the other
+ # libraries we check for below, so use a different variable.
+ # John Interrante, Karl Berry
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5
+$as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; }
+if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lICE $X_EXTRA_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char IceConnectionNumber ();
+int
+main ()
+{
+return IceConnectionNumber ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_ICE_IceConnectionNumber=yes
+else
+ ac_cv_lib_ICE_IceConnectionNumber=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5
+$as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; }
+if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then :
+ X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE"
+fi
+
+ LDFLAGS=$ac_save_LDFLAGS
+
+fi
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS" >&5
+$as_echo_n "checking for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_join ();
+int
+main ()
+{
+return pthread_join ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ acx_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5
+$as_echo "$acx_pthread_ok" >&6; }
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthread or
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5
+$as_echo_n "checking whether pthreads work without any flags... " >&6; }
+ ;;
+
+ -*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $flag" >&5
+$as_echo_n "checking whether pthreads work with $flag... " >&6; }
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ # Extract the first word of "pthread-config", so it can be a program name with args.
+set dummy pthread-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_acx_pthread_config+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$acx_pthread_config"; then
+ ac_cv_prog_acx_pthread_config="$acx_pthread_config" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_acx_pthread_config="yes"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_acx_pthread_config" && ac_cv_prog_acx_pthread_config="no"
+fi
+fi
+acx_pthread_config=$ac_cv_prog_acx_pthread_config
+if test -n "$acx_pthread_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_config" >&5
+$as_echo "$acx_pthread_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$flag" >&5
+$as_echo_n "checking for the pthreads library -l$flag... " >&6; }
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0);
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ acx_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_pthread_ok" >&5
+$as_echo "$acx_pthread_ok" >&6; }
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5
+$as_echo_n "checking for joinable pthread attribute... " >&6; }
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread.h>
+int
+main ()
+{
+int attr=$attr;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ attr_name=$attr; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $attr_name" >&5
+$as_echo "$attr_name" >&6; }
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+
+cat >>confdefs.h <<_ACEOF
+#define PTHREAD_CREATE_JOINABLE $attr_name
+_ACEOF
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if more special flags are required for pthreads" >&5
+$as_echo_n "checking if more special flags are required for pthreads... " >&6; }
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${flag}" >&5
+$as_echo "${flag}" >&6; }
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: must compile with cc_r
+ # Extract the first word of "cc_r", so it can be a program name with args.
+set dummy cc_r; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_PTHREAD_CC+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PTHREAD_CC"; then
+ ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_PTHREAD_CC="cc_r"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_PTHREAD_CC" && ac_cv_prog_PTHREAD_CC="${CC}"
+fi
+fi
+PTHREAD_CC=$ac_cv_prog_PTHREAD_CC
+if test -n "$PTHREAD_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5
+$as_echo "$PTHREAD_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+else
+ PTHREAD_CC="$CC"
+fi
+
+
+
+
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+
+$as_echo "#define HAVE_PTHREAD 1" >>confdefs.h
+
+ :
+else
+ acx_pthread_ok=no
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+#
+# There isn't a reliable way to know we should use the Apple OpenGL framework
+# without a configure option. A Mac OS X user may have installed an
+# alternative GL implementation (e.g., Mesa), which may or may not depend on X.
+#
+
+# Check whether --with-apple-opengl-framework was given.
+if test "${with_apple_opengl_framework+set}" = set; then :
+ withval=$with_apple_opengl_framework;
+fi
+
+if test "X$with_apple_opengl_framework" = "Xyes"; then
+
+$as_echo "#define HAVE_APPLE_OPENGL_FRAMEWORK 1" >>confdefs.h
+
+ GL_LIBS="-framework OpenGL"
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the Microsoft C compiler" >&5
+$as_echo_n "checking whether we are using the Microsoft C compiler... " >&6; }
+if test "${ax_cv_c_compiler_ms+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef _MSC_VER
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ax_compiler_ms=yes
+else
+ ax_compiler_ms=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ax_cv_c_compiler_ms=$ax_compiler_ms
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_c_compiler_ms" >&5
+$as_echo "$ax_cv_c_compiler_ms" >&6; }
+ if test X$ax_compiler_ms = Xno; then
+ GL_CFLAGS="${PTHREAD_CFLAGS}"
+ GL_LIBS="${PTHREAD_LIBS} -lm"
+ fi
+
+ #
+ # Use x_includes and x_libraries if they have been set (presumably by
+ # AC_PATH_X).
+ #
+ if test "X$no_x" != "Xyes"; then
+ if test -n "$x_includes"; then
+ GL_CFLAGS="-I${x_includes} ${GL_CFLAGS}"
+ fi
+ if test -n "$x_libraries"; then
+ GL_LIBS="-L${x_libraries} -lX11 ${GL_LIBS}"
+ fi
+ fi
+
+ for ac_header in windows.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default"
+if test "x$ac_cv_header_windows_h" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_WINDOWS_H 1
+_ACEOF
+
+fi
+
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenGL library" >&5
+$as_echo_n "checking for OpenGL library... " >&6; }
+if test "${ax_cv_check_gl_libgl+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_check_gl_libgl="no"
+ ax_save_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${GL_CFLAGS} ${CPPFLAGS}"
+ ax_save_LIBS="${LIBS}"
+ LIBS=""
+ ax_check_libs="-lopengl32 -lGL"
+ for ax_lib in ${ax_check_libs}; do
+ if test X$ax_compiler_ms = Xyes; then
+ ax_try_lib=`echo $ax_lib | sed -e 's/^-l//' -e 's/$/.lib/'`
+ else
+ ax_try_lib="${ax_lib}"
+ fi
+ LIBS="${ax_try_lib} ${GL_LIBS} ${ax_save_LIBS}"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# if HAVE_WINDOWS_H && defined(_WIN32)
+# include <windows.h>
+# endif
+# include <GL/gl.h>
+int
+main ()
+{
+glBegin(0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_check_gl_libgl="${ax_try_lib}"; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ done
+ LIBS=${ax_save_LIBS}
+ CPPFLAGS=${ax_save_CPPFLAGS}
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_gl_libgl" >&5
+$as_echo "$ax_cv_check_gl_libgl" >&6; }
+
+ if test "X${ax_cv_check_gl_libgl}" = "Xno"; then
+ no_gl="yes"
+ GL_CFLAGS=""
+ GL_LIBS=""
+ else
+ GL_LIBS="${ax_cv_check_gl_libgl} ${GL_LIBS}"
+ fi
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+
+
+
+
+GLU_CFLAGS="${GL_CFLAGS}"
+if test "X${with_apple_opengl_framework}" != "Xyes"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OpenGL Utility library" >&5
+$as_echo_n "checking for OpenGL Utility library... " >&6; }
+if test "${ax_cv_check_glu_libglu+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_check_glu_libglu="no"
+ ax_save_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${GL_CFLAGS} ${CPPFLAGS}"
+ ax_save_LIBS="${LIBS}"
+ LIBS=""
+ ax_check_libs="-lglu32 -lGLU"
+ for ax_lib in ${ax_check_libs}; do
+ if test X$ax_compiler_ms = Xyes; then
+ ax_try_lib=`echo $ax_lib | sed -e 's/^-l//' -e 's/$/.lib/'`
+ else
+ ax_try_lib="${ax_lib}"
+ fi
+ LIBS="${ax_try_lib} ${GL_LIBS} ${ax_save_LIBS}"
+ #
+ # libGLU typically links with libstdc++ on POSIX platforms. However,
+ # setting the language to C++ means that test program source is named
+ # "conftest.cc"; and Microsoft cl doesn't know what to do with such a
+ # file.
+ #
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+ if test X$ax_compiler_ms = Xyes; then
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ fi
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# if HAVE_WINDOWS_H && defined(_WIN32)
+# include <windows.h>
+# endif
+# include <GL/glu.h>
+int
+main ()
+{
+gluBeginCurve(0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_check_glu_libglu="${ax_try_lib}"; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test X$ax_compiler_ms = Xyes; then
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+ fi
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ done
+ LIBS=${ax_save_LIBS}
+ CPPFLAGS=${ax_save_CPPFLAGS}
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_glu_libglu" >&5
+$as_echo "$ax_cv_check_glu_libglu" >&6; }
+ if test "X${ax_cv_check_glu_libglu}" = "Xno"; then
+ no_glu="yes"
+ GLU_CFLAGS=""
+ GLU_LIBS=""
+ else
+ GLU_LIBS="${ax_cv_check_glu_libglu} ${GL_LIBS}"
+ fi
+fi
+
+
+
+
+if test "X$with_apple_opengl_framework" = "Xyes"; then
+ GLUT_CFLAGS="${GLU_CFLAGS}"
+ GLUT_LIBS="-framework GLUT -lobjc ${GL_LIBS}"
+else
+ GLUT_CFLAGS=${GLU_CFLAGS}
+ GLUT_LIBS=${GLU_LIBS}
+
+ #
+ # If X is present, assume GLUT depends on it.
+ #
+ if test "X${no_x}" != "Xyes"; then
+ GLUT_LIBS="${X_PRE_LIBS} -lXmu -lXi ${X_EXTRA_LIBS} ${GLUT_LIBS}"
+ fi
+
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ ax_save_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${GLUT_CFLAGS} ${CPPFLAGS}"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLUT library" >&5
+$as_echo_n "checking for GLUT library... " >&6; }
+if test "${ax_cv_check_glut_libglut+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ax_cv_check_glut_libglut="no"
+ ax_save_LIBS="${LIBS}"
+ LIBS=""
+ ax_check_libs="-lglut32 -lglut"
+ for ax_lib in ${ax_check_libs}; do
+ if test X$ax_compiler_ms = Xyes; then
+ ax_try_lib=`echo $ax_lib | sed -e 's/^-l//' -e 's/$/.lib/'`
+ else
+ ax_try_lib="${ax_lib}"
+ fi
+ LIBS="${ax_try_lib} ${GLUT_LIBS} ${ax_save_LIBS}"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# if HAVE_WINDOWS_H && defined(_WIN32)
+# include <windows.h>
+# endif
+# include <GL/glut.h>
+int
+main ()
+{
+glutMainLoop()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ax_cv_check_glut_libglut="${ax_try_lib}"; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ done
+ LIBS=${ax_save_LIBS}
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_glut_libglut" >&5
+$as_echo "$ax_cv_check_glut_libglut" >&6; }
+ CPPFLAGS="${ax_save_CPPFLAGS}"
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ if test "X${ax_cv_check_glut_libglut}" = "Xno"; then
+ no_glut="yes"
+ GLUT_CFLAGS=""
+ GLUT_LIBS=""
+ else
+ GLUT_LIBS="${ax_cv_check_glut_libglut} ${GLUT_LIBS}"
+ fi
+fi
+
+
+
+
+
+if test "$no_x" != "yes" -a "$no_gl" != "yes" \
+ -a "$no_glu" != "yes" -a "$no_glut" != "yes" ; then
+ HAVE_OPENGL=yes
+fi
+
+ if test "$HAVE_OPENGL" = "yes"; then
+ HAVE_OPENGL_TRUE=
+ HAVE_OPENGL_FALSE='#'
+else
+ HAVE_OPENGL_TRUE='#'
+ HAVE_OPENGL_FALSE=
+fi
+
+
+
+
+
+
+
+
+
+# Check whether --enable-strip-chopping was given.
+if test "${enable_strip_chopping+set}" = set; then :
+ enableval=$enable_strip_chopping; HAVE_STRIPCHOP=$enableval
+else
+ HAVE_STRIPCHOP=yes
+fi
+
+
+# Check whether --with-default-strip-size was given.
+if test "${with_default_strip_size+set}" = set; then :
+ withval=$with_default_strip_size;
+fi
+
+
+if test "$HAVE_STRIPCHOP" = "yes" \
+ -a "x$with_default_strip_size" != "xno"; then
+
+$as_echo "#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP" >>confdefs.h
+
+
+ if test "x$with_default_strip_size" = "x" \
+ -o "x$with_default_strip_size" = "xyes"; then
+ with_default_strip_size="8192"
+ fi
+
+
+cat >>confdefs.h <<_ACEOF
+#define STRIP_SIZE_DEFAULT $with_default_strip_size
+_ACEOF
+
+
+fi
+
+
+$as_echo "#define SUBIFD_SUPPORT 1" >>confdefs.h
+
+
+
+# Check whether --enable-extrasample-as-alpha was given.
+if test "${enable_extrasample_as_alpha+set}" = set; then :
+ enableval=$enable_extrasample_as_alpha; HAVE_EXTRASAMPLE_AS_ALPHA=$enableval
+else
+ HAVE_EXTRASAMPLE_AS_ALPHA=yes
+fi
+
+
+if test "$HAVE_EXTRASAMPLE_AS_ALPHA" = "yes" ; then
+
+$as_echo "#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1" >>confdefs.h
+
+fi
+
+
+# Check whether --enable-check-ycbcr-subsampling was given.
+if test "${enable_check_ycbcr_subsampling+set}" = set; then :
+ enableval=$enable_check_ycbcr_subsampling; CHECK_JPEG_YCBCR_SUBSAMPLING=$enableval
+else
+ CHECK_JPEG_YCBCR_SUBSAMPLING=yes
+fi
+
+
+if test "$CHECK_JPEG_YCBCR_SUBSAMPLING" = "yes" ; then
+
+$as_echo "#define CHECK_JPEG_YCBCR_SUBSAMPLING 1" >>confdefs.h
+
+fi
+
+
+
+
+ac_config_headers="$ac_config_headers libtiff/tif_config.h libtiff/tiffconf.h"
+
+
+ac_config_files="$ac_config_files Makefile build/Makefile contrib/Makefile contrib/acorn/Makefile contrib/addtiffo/Makefile contrib/dbs/Makefile contrib/dbs/xtiff/Makefile contrib/iptcutil/Makefile contrib/mac-cw/Makefile contrib/mac-mpw/Makefile contrib/mfs/Makefile contrib/pds/Makefile contrib/ras/Makefile contrib/stream/Makefile contrib/tags/Makefile contrib/win_dib/Makefile html/Makefile html/images/Makefile html/man/Makefile libtiff/Makefile man/Makefile port/Makefile test/Makefile tools/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ test "x$cache_file" != "x/dev/null" &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ cat confcache >$cache_file
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ as_fn_error "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+ as_fn_error "conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+if test -z "${HAVE_RPATH_TRUE}" && test -z "${HAVE_RPATH_FALSE}"; then
+ as_fn_error "conditional \"HAVE_RPATH\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_CXX_TRUE}" && test -z "${HAVE_CXX_FALSE}"; then
+ as_fn_error "conditional \"HAVE_CXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_OPENGL_TRUE}" && test -z "${HAVE_OPENGL_FALSE}"; then
+ as_fn_error "conditional \"HAVE_OPENGL\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error ERROR [LINENO LOG_FD]
+# ---------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with status $?, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$?; test $as_status -eq 0 && as_status=1
+ if test "$3"; then
+ as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3
+ fi
+ $as_echo "$as_me: error: $1" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -p'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -p'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -p'
+ fi
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+ as_test_x='test -x'
+else
+ if ls -dL / >/dev/null 2>&1; then
+ as_ls_L_option=L
+ else
+ as_ls_L_option=
+ fi
+ as_test_x='
+ eval sh -c '\''
+ if test -d "$1"; then
+ test -d "$1/.";
+ else
+ case $1 in #(
+ -*)set "./$1";;
+ esac;
+ case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #((
+ ???[sx]*):;;*)false;;esac;fi
+ '\'' sh
+ '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by LibTIFF Software $as_me 3.9.4, which was
+generated by GNU Autoconf 2.65. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <tiff@lists.maptools.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+LibTIFF Software config.status 3.9.4
+configured by $0, generated by GNU Autoconf 2.65,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+AS='`$ECHO "$AS" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`'
+predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`'
+postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`'
+predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`'
+postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`'
+LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`'
+reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`'
+reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`'
+GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`'
+predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`'
+postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SED \
+GREP \
+EGREP \
+FGREP \
+SHELL \
+ECHO \
+LD \
+AS \
+DLLTOOL \
+OBJDUMP \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+deplibs_check_method \
+file_magic_cmd \
+AR \
+AR_FLAGS \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_wl \
+lt_prog_compiler_pic \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_flag_spec_ld \
+hardcode_libdir_separator \
+fix_srcfile_path \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib \
+compiler_lib_search_dirs \
+predep_objects \
+postdep_objects \
+predeps \
+postdeps \
+compiler_lib_search_path \
+LD_CXX \
+reload_flag_CXX \
+compiler_CXX \
+lt_prog_compiler_no_builtin_flag_CXX \
+lt_prog_compiler_wl_CXX \
+lt_prog_compiler_pic_CXX \
+lt_prog_compiler_static_CXX \
+lt_cv_prog_compiler_c_o_CXX \
+export_dynamic_flag_spec_CXX \
+whole_archive_flag_spec_CXX \
+compiler_needs_object_CXX \
+with_gnu_ld_CXX \
+allow_undefined_flag_CXX \
+no_undefined_flag_CXX \
+hardcode_libdir_flag_spec_CXX \
+hardcode_libdir_flag_spec_ld_CXX \
+hardcode_libdir_separator_CXX \
+fix_srcfile_path_CXX \
+exclude_expsyms_CXX \
+include_expsyms_CXX \
+file_list_spec_CXX \
+compiler_lib_search_dirs_CXX \
+predep_objects_CXX \
+postdep_objects_CXX \
+predeps_CXX \
+postdeps_CXX \
+compiler_lib_search_path_CXX; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec \
+reload_cmds_CXX \
+old_archive_cmds_CXX \
+old_archive_from_new_cmds_CXX \
+old_archive_from_expsyms_cmds_CXX \
+archive_cmds_CXX \
+archive_expsym_cmds_CXX \
+module_cmds_CXX \
+module_expsym_cmds_CXX \
+export_symbols_cmds_CXX \
+prelink_cmds_CXX; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "libtiff/tif_config.h") CONFIG_HEADERS="$CONFIG_HEADERS libtiff/tif_config.h" ;;
+ "libtiff/tiffconf.h") CONFIG_HEADERS="$CONFIG_HEADERS libtiff/tiffconf.h" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "build/Makefile") CONFIG_FILES="$CONFIG_FILES build/Makefile" ;;
+ "contrib/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/Makefile" ;;
+ "contrib/acorn/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/acorn/Makefile" ;;
+ "contrib/addtiffo/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/addtiffo/Makefile" ;;
+ "contrib/dbs/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/dbs/Makefile" ;;
+ "contrib/dbs/xtiff/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/dbs/xtiff/Makefile" ;;
+ "contrib/iptcutil/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/iptcutil/Makefile" ;;
+ "contrib/mac-cw/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/mac-cw/Makefile" ;;
+ "contrib/mac-mpw/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/mac-mpw/Makefile" ;;
+ "contrib/mfs/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/mfs/Makefile" ;;
+ "contrib/pds/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/pds/Makefile" ;;
+ "contrib/ras/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/ras/Makefile" ;;
+ "contrib/stream/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/stream/Makefile" ;;
+ "contrib/tags/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/tags/Makefile" ;;
+ "contrib/win_dib/Makefile") CONFIG_FILES="$CONFIG_FILES contrib/win_dib/Makefile" ;;
+ "html/Makefile") CONFIG_FILES="$CONFIG_FILES html/Makefile" ;;
+ "html/images/Makefile") CONFIG_FILES="$CONFIG_FILES html/images/Makefile" ;;
+ "html/man/Makefile") CONFIG_FILES="$CONFIG_FILES html/man/Makefile" ;;
+ "libtiff/Makefile") CONFIG_FILES="$CONFIG_FILES libtiff/Makefile" ;;
+ "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;;
+ "port/Makefile") CONFIG_FILES="$CONFIG_FILES port/Makefile" ;;
+ "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
+ "tools/Makefile") CONFIG_FILES="$CONFIG_FILES tools/Makefile" ;;
+
+ *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp=
+ trap 'exit_status=$?
+ { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+ || as_fn_error "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[ ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_t"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$tmp/stdin" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined." >&2;}
+
+ rm -f "$tmp/stdin"
+ case $ac_file in
+ -) cat "$tmp/out" && rm -f "$tmp/out";;
+ *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+ } >"$tmp/config.h" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$tmp/config.h" "$ac_file" \
+ || as_fn_error "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Autoconf 2.62 quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named `Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running `make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # When using ansi2knr, U may be empty or an underscore; expand it
+ U=`sed -n 's/^U = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
+# Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="CXX "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Assembler program.
+AS=$lt_AS
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Object dumper program.
+OBJDUMP=$lt_OBJDUMP
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=$(( $* ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=${#1}
+}
+
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+}
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[^=]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "$@"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1+=\$2"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1=\$$1\$2"
+}
+
+_LT_EOF
+ ;;
+ esac
+
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+
+ cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_CXX
+reload_cmds=$lt_reload_cmds_CXX
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_CXX
+
+# A language specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_CXX
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_CXX
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_CXX
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_CXX
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path_CXX
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_CXX
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_CXX
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_CXX
+postdep_objects=$lt_postdep_objects_CXX
+predeps=$lt_predeps_CXX
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# ### END LIBTOOL TAG CONFIG: CXX
+_LT_EOF
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit $?
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+
+echo ""
+echo "Libtiff is now configured for ${host}"
+echo ""
+echo " Installation directory: ${prefix}"
+echo " Documentation directory: ${LIBTIFF_DOCDIR}"
+echo " C compiler: ${CC} ${CFLAGS}"
+echo " C++ compiler: ${CXX} ${CXXFLAGS}"
+echo " Enable runtime linker paths: ${HAVE_RPATH}"
+echo " Support Microsoft Document Imaging: ${HAVE_MDI}"
+echo ""
+echo " Support for internal codecs:"
+echo " CCITT Group 3 & 4 algorithms: ${HAVE_CCITT}"
+echo " Macintosh PackBits algorithm: ${HAVE_PACKBITS}"
+echo " LZW algorithm: ${HAVE_LZW}"
+echo " ThunderScan 4-bit RLE algorithm: ${HAVE_THUNDER}"
+echo " NeXT 2-bit RLE algorithm: ${HAVE_NEXT}"
+echo " LogLuv high dynamic range encoding: ${HAVE_LOGLUV}"
+echo ""
+echo " Support for external codecs:"
+echo " ZLIB support: ${HAVE_ZLIB}"
+echo " Pixar log-format algorithm: ${HAVE_PIXARLOG}"
+echo " JPEG support: ${HAVE_JPEG}"
+echo " Old JPEG support: ${HAVE_OJPEG}"
+echo " ISO JBIG support: ${HAVE_JBIG}"
+echo ""
+echo " C++ support: ${HAVE_CXX}"
+echo ""
+echo " OpenGL support: ${HAVE_OPENGL}"
+echo ""
+
diff --git a/tiff/configure.ac b/tiff/configure.ac
new file mode 100644
index 0000000..e0e0ae1
--- /dev/null
+++ b/tiff/configure.ac
@@ -0,0 +1,703 @@
+dnl -*- Autoconf -*-
+dnl Tag Image File Format (TIFF) Software
+dnl
+dnl Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+dnl
+dnl Permission to use, copy, modify, distribute, and sell this software and
+dnl its documentation for any purpose is hereby granted without fee, provided
+dnl that (i) the above copyright notices and this permission notice appear in
+dnl all copies of the software and related documentation, and (ii) the names of
+dnl Sam Leffler and Silicon Graphics may not be used in any advertising or
+dnl publicity relating to the software without the specific, prior written
+dnl permission of Sam Leffler and Silicon Graphics.
+dnl
+dnl THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+dnl EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+dnl WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+dnl
+dnl IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+dnl ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+dnl OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+dnl WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+dnl LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+dnl OF THIS SOFTWARE.
+
+dnl Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.64)
+AC_INIT([LibTIFF Software],[3.9.4],[tiff@lists.maptools.org],[tiff])
+AC_CONFIG_AUX_DIR(config)
+AC_CONFIG_MACRO_DIR(m4)
+AC_LANG(C)
+
+dnl Compute the canonical target-system type variable
+AC_CANONICAL_TARGET
+
+AM_INIT_AUTOMAKE
+dnl Do not rebuild generated files every time
+AM_MAINTAINER_MODE
+
+dnl Versioning.
+dnl Don't fill the ALPHA_VERSION field, if not applicable.
+LIBTIFF_MAJOR_VERSION=3
+LIBTIFF_MINOR_VERSION=9
+LIBTIFF_MICRO_VERSION=4
+LIBTIFF_ALPHA_VERSION=
+LIBTIFF_VERSION=$LIBTIFF_MAJOR_VERSION.$LIBTIFF_MINOR_VERSION.$LIBTIFF_MICRO_VERSION$LIBTIFF_ALPHA_VERSION
+dnl This will be used with the 'make release' target
+LIBTIFF_RELEASE_DATE=`date +"%Y%m%d"`
+
+# This is a special hack for OpenBSD and MirOS systems. The dynamic linker
+# in OpenBSD uses some special semantics for shared libraries. Their soname
+# contains only two numbers, major and minor.
+# See http://bugzilla.remotesensing.org/show_bug.cgi?id=838 for details.
+case "$target_os" in
+ openbsd* | mirbsd*)
+ LIBTIFF_VERSION_INFO=$LIBTIFF_MAJOR_VERSION$LIBTIFF_MINOR_VERSION:$LIBTIFF_MICRO_VERSION:0
+ ;;
+ *)
+ LIBTIFF_VERSION_INFO=$LIBTIFF_MAJOR_VERSION:$LIBTIFF_MINOR_VERSION:$LIBTIFF_MICRO_VERSION
+ ;;
+esac
+
+AC_SUBST(LIBTIFF_MAJOR_VERSION)
+AC_SUBST(LIBTIFF_MINOR_VERSION)
+AC_SUBST(LIBTIFF_MICRO_VERSION)
+AC_SUBST(LIBTIFF_ALPHA_VERSION)
+AC_SUBST(LIBTIFF_VERSION)
+AC_SUBST(LIBTIFF_VERSION_INFO)
+AC_SUBST(LIBTIFF_RELEASE_DATE)
+
+# Ensure that make can run correctly
+AM_SANITY_CHECK
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_CC_STDC
+AC_PROG_CPP
+LT_PATH_LD
+
+AM_PROG_CC_C_O
+LT_PATH_LD
+
+dnl We want warnings. As many warnings as possible.
+VL_PROG_CC_WARNINGS()
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_PROG_LN_S
+
+dnl Tests for Windows
+AC_EXEEXT
+AC_OBJEXT
+
+dnl initialize libtool
+LT_INIT([win32-dll])
+LT_LANG([C++])
+
+# Enable support for silent build rules
+AM_SILENT_RULES
+
+dnl Checks for libraries.
+AC_CHECK_LIB([c], [main])
+
+dnl We don't need to add math library to all targets
+case "${host_os}" in
+ cygwin* | mingw32* | beos* | darwin*)
+ ;;
+ *)
+ AC_CHECK_LIB(m,sin,,,)
+ ;;
+esac
+
+dnl Checks for header files.
+AC_CHECK_HEADERS([assert.h fcntl.h io.h limits.h malloc.h search.h sys/time.h unistd.h])
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_C_BIGENDIAN
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(long)
+AC_HEADER_TIME
+AC_STRUCT_TM
+dnl Some compilers (IBM VisualAge) has these types defined, so check it here:
+AC_CHECK_TYPES([int8, int16, int32],,,
+[
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+])
+
+# Obtain size of a 'signed long' and define as SIZEOF_SIGNED_LONG
+AC_CHECK_SIZEOF(signed long)
+
+# Obtain size of a 'unsigned long' and define as SIZEOF_UNSIGNED_LONG
+AC_CHECK_SIZEOF(unsigned long)
+
+# Obtain size of a 'long long' and define as SIZEOF_SIGNED_LONG_LONG.
+# If 'long long' is not supported then the value defined is zero.
+AC_CHECK_SIZEOF(signed long long)
+
+# Obtain size of a 'unsigned long long' and define as
+# SIZEOF_UNSIGNED_LONG_LONG. If 'unsigned long long' is not
+# supported then the value defined is zero.
+AC_CHECK_SIZEOF(unsigned long long)
+
+AC_MSG_CHECKING(for signed 64-bit type)
+INT64_T='none'
+INT64_FORMAT='none'
+if test $ac_cv_sizeof_signed_long -eq 8
+then
+ INT64_T='signed long'
+ INT64_FORMAT='"%ld"'
+elif test $ac_cv_sizeof_signed_long_long -eq 8
+then
+ INT64_FORMAT='"%lld"'
+ INT64_T='signed long long'
+fi
+AC_MSG_RESULT($INT64_T)
+AC_DEFINE_UNQUOTED(TIFF_INT64_T,$INT64_T,[Signed 64-bit type])
+AC_DEFINE_UNQUOTED(TIFF_INT64_FORMAT,$INT64_FORMAT,[Signed 64-bit type formatter])
+
+AC_MSG_CHECKING(for unsigned 64-bit type)
+UINT64_T='none'
+UINT64_FORMAT='none'
+if test $ac_cv_sizeof_unsigned_long -eq 8
+then
+ UINT64_T='unsigned long'
+ UINT64_FORMAT='"%lu"'
+elif test $ac_cv_sizeof_unsigned_long_long -eq 8
+then
+ UINT64_T='unsigned long long'
+ UINT64_FORMAT='"%llu"'
+fi
+AC_MSG_RESULT($UINT64_T)
+AC_DEFINE_UNQUOTED(TIFF_UINT64_T,$UINT64_T,[Unsigned 64-bit type])
+AC_DEFINE_UNQUOTED(TIFF_UINT64_FORMAT,$UINT64_FORMAT,[Unsigned 64-bit type formatter])
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS([floor isascii memmove memset mmap pow setmode sqrt strchr strrchr strstr strtol])
+
+dnl Will use local replacements for unavailable functions
+AC_REPLACE_FUNCS(getopt)
+AC_REPLACE_FUNCS(strcasecmp)
+AC_REPLACE_FUNCS(strtoul)
+AC_REPLACE_FUNCS(lfind)
+
+dnl ---------------------------------------------------------------------------
+dnl Check the native cpu bit order.
+dnl ---------------------------------------------------------------------------
+AC_MSG_CHECKING([native cpu bit order])
+case "$target_cpu" in
+ i*86*|x86_64*)
+ HOST_FILLORDER=FILLORDER_LSB2MSB
+ AC_MSG_RESULT([lsb2msb])
+ ;;
+ *)
+ HOST_FILLORDER=FILLORDER_MSB2LSB
+ AC_MSG_RESULT([msb2lsb])
+ ;;
+esac
+AC_DEFINE_UNQUOTED(HOST_FILLORDER, $HOST_FILLORDER, [Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB)])
+
+dnl ---------------------------------------------------------------------------
+dnl Configure legacy tifconf.h HOST_BIGENDIAN.
+dnl ---------------------------------------------------------------------------
+if test "$ac_cv_c_bigendian" = yes ; then
+ HOST_BIGENDIAN=1
+else
+ HOST_BIGENDIAN=0
+fi
+AC_DEFINE_UNQUOTED(HOST_BIGENDIAN,$HOST_BIGENDIAN,[Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian (Intel)])
+
+dnl ---------------------------------------------------------------------------
+dnl Make the POSIX.2 features available.
+dnl ---------------------------------------------------------------------------
+#_POSIX_C_SOURCE=2
+#AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE, $_POSIX_C_SOURCE, [Define this macro to a positive integer to control which POSIX functionality is made available.])
+
+dnl ---------------------------------------------------------------------------
+dnl Set the floating point format.
+dnl FIXME: write appropriate test.
+dnl ---------------------------------------------------------------------------
+HAVE_IEEEFP=1
+AC_DEFINE_UNQUOTED(HAVE_IEEEFP, $HAVE_IEEEFP, [Define as 0 or 1 according to the floating point format suported by the machine])
+
+dnl ---------------------------------------------------------------------------
+dnl Enable run-time paths to libraries usage.
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(rpath,
+ AS_HELP_STRING([--enable-rpath],
+ [Enable runtime linker paths (-R libtool option)]),
+ [HAVE_RPATH=$enableval], [HAVE_RPATH=no])
+AM_CONDITIONAL(HAVE_RPATH, test "$HAVE_RPATH" = "yes")
+
+dnl ---------------------------------------------------------------------------
+dnl Support large files.
+dnl ---------------------------------------------------------------------------
+
+AC_SYS_LARGEFILE
+
+dnl ---------------------------------------------------------------------------
+dnl Point to path where we should install documentation.
+dnl ---------------------------------------------------------------------------
+
+LIBTIFF_DOCDIR=\${prefix}/share/doc/${PACKAGE}-${LIBTIFF_VERSION}
+
+AC_ARG_WITH(docdir,
+ AS_HELP_STRING([--with-docdir=DIR],
+ [directory where documentation should be installed]),,)
+if test "x$with_docdir" != "x" ; then
+ LIBTIFF_DOCDIR=$with_docdir
+fi
+
+AC_SUBST(LIBTIFF_DOCDIR)
+
+dnl ---------------------------------------------------------------------------
+dnl Switch on/off internal codecs.
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(ccitt,
+ AS_HELP_STRING([--disable-ccitt],
+ [disable support for CCITT Group 3 & 4 algorithms]),
+ [HAVE_CCITT=$enableval], [HAVE_CCITT=yes])
+
+if test "$HAVE_CCITT" = "yes" ; then
+ AC_DEFINE(CCITT_SUPPORT,1,[Support CCITT Group 3 & 4 algorithms])
+fi
+
+AC_ARG_ENABLE(packbits,
+ AS_HELP_STRING([--disable-packbits],
+ [disable support for Macintosh PackBits algorithm]),
+ [HAVE_PACKBITS=$enableval], [HAVE_PACKBITS=yes])
+
+if test "$HAVE_PACKBITS" = "yes" ; then
+ AC_DEFINE(PACKBITS_SUPPORT,1,[Support Macintosh PackBits algorithm])
+fi
+
+AC_ARG_ENABLE(lzw,
+ AS_HELP_STRING([--disable-lzw],
+ [disable support for LZW algorithm]),
+ [HAVE_LZW=$enableval], [HAVE_LZW=yes])
+
+if test "$HAVE_LZW" = "yes" ; then
+ AC_DEFINE(LZW_SUPPORT,1,[Support LZW algorithm])
+fi
+
+AC_ARG_ENABLE(thunder,
+ AS_HELP_STRING([--disable-thunder],
+ [disable support for ThunderScan 4-bit RLE algorithm]),
+ [HAVE_THUNDER=$enableval], [HAVE_THUNDER=yes])
+
+if test "$HAVE_THUNDER" = "yes" ; then
+ AC_DEFINE(THUNDER_SUPPORT,1,[Support ThunderScan 4-bit RLE algorithm])
+fi
+
+HAVE_NEXT=yes
+
+AC_ARG_ENABLE(next,
+ AS_HELP_STRING([--disable-next],
+ [disable support for NeXT 2-bit RLE algorithm]),
+ [HAVE_NEXT=$enableval], [HAVE_NEXT=yes])
+
+if test "$HAVE_NEXT" = "yes" ; then
+ AC_DEFINE(NEXT_SUPPORT,1,[Support NeXT 2-bit RLE algorithm])
+fi
+
+AC_ARG_ENABLE(logluv,
+ AS_HELP_STRING([--disable-logluv],
+ [disable support for LogLuv high dynamic range encoding]),
+ [HAVE_LOGLUV=$enableval], [HAVE_LOGLUV=yes])
+
+if test "$HAVE_LOGLUV" = "yes" ; then
+ AC_DEFINE(LOGLUV_SUPPORT,1,[Support LogLuv high dynamic range encoding])
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Switch on/off support for Microsoft Document Imaging
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(mdi,
+ AS_HELP_STRING([--disable-mdi],
+ [disable support for Microsoft Document Imaging]),
+ [HAVE_MDI=$enableval], [HAVE_MDI=yes])
+
+if test "$HAVE_MDI" = "yes" ; then
+ AC_DEFINE(MDI_SUPPORT,1,[Support Microsoft Document Imaging format])
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Check for ZLIB.
+dnl ---------------------------------------------------------------------------
+
+HAVE_ZLIB=no
+
+AC_ARG_ENABLE(zlib,
+ AS_HELP_STRING([--disable-zlib],
+ [disable Zlib usage (required for Deflate compression, enabled by default)]),,)
+AC_ARG_WITH(zlib-include-dir,
+ AS_HELP_STRING([--with-zlib-include-dir=DIR],
+ [location of Zlib headers]),,)
+AC_ARG_WITH(zlib-lib-dir,
+ AS_HELP_STRING([--with-zlib-lib-dir=DIR],
+ [location of Zlib library binary]),,)
+
+if test "x$enable_zlib" != "xno" ; then
+
+ if test "x$with_zlib_lib_dir" != "x" ; then
+ LDFLAGS="-L$with_zlib_lib_dir $LDFLAGS"
+ fi
+
+ AC_CHECK_LIB(z, inflateEnd, [zlib_lib=yes], [zlib_lib=no],)
+ if test "$zlib_lib" = "no" -a "x$with_zlib_lib_dir" != "x"; then
+ AC_MSG_ERROR([Zlib library not found at $with_zlib_lib_dir])
+ fi
+
+ if test "x$with_zlib_include_dir" != "x" ; then
+ CPPFLAGS="-I$with_zlib_include_dir $CPPFLAGS"
+ fi
+ AC_CHECK_HEADER(zlib.h, [zlib_h=yes], [zlib_h=no])
+ if test "$zlib_h" = "no" -a "x$with_zlib_include_dir" != "x" ; then
+ AC_MSG_ERROR([Zlib headers not found at $with_zlib_include_dir])
+ fi
+
+ if test "$zlib_lib" = "yes" -a "$zlib_h" = "yes" ; then
+ HAVE_ZLIB=yes
+ fi
+
+fi
+
+if test "$HAVE_ZLIB" = "yes" ; then
+ AC_DEFINE(ZIP_SUPPORT,1,[Support Deflate compression])
+ LIBS="-lz $LIBS"
+
+ if test "$HAVE_RPATH" = "yes" -a "x$with_zlib_lib_dir" != "x" ; then
+ LIBDIR="-R $with_zlib_lib_dir $LIBDIR"
+ fi
+
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Check for Pixar log-format algorithm.
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(pixarlog,
+ AS_HELP_STRING([--disable-pixarlog],
+ [disable support for Pixar log-format algorithm (requires Zlib)]),
+ [HAVE_PIXARLOG=$enableval], [HAVE_PIXARLOG=yes])
+
+if test "$HAVE_ZLIB" = "yes" -a "$HAVE_PIXARLOG" = "yes" ; then
+ AC_DEFINE(PIXARLOG_SUPPORT, 1,
+ [Support Pixar log-format algorithm (requires Zlib)])
+else
+ HAVE_PIXARLOG=no
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Check for JPEG.
+dnl ---------------------------------------------------------------------------
+
+HAVE_JPEG=no
+
+AC_ARG_ENABLE(jpeg,
+ AS_HELP_STRING([--disable-jpeg],
+ [disable IJG JPEG library usage (required for JPEG compression, enabled by default)]),,)
+AC_ARG_WITH(jpeg-include-dir,
+ AS_HELP_STRING([--with-jpeg-include-dir=DIR],
+ [location of IJG JPEG library headers]),,)
+AC_ARG_WITH(jpeg-lib-dir,
+ AS_HELP_STRING([--with-jpeg-lib-dir=DIR],
+ [location of IJG JPEG library binary]),,)
+
+if test "x$enable_jpeg" != "xno" ; then
+
+ if test "x$with_jpeg_lib_dir" != "x" ; then
+ LDFLAGS="-L$with_jpeg_lib_dir $LDFLAGS"
+
+ fi
+
+ AC_CHECK_LIB(jpeg, jpeg_read_scanlines, [jpeg_lib=yes], [jpeg_lib=no],)
+ if test "$jpeg_lib" = "no" -a "x$with_jpeg_lib_dir" != "x" ; then
+ AC_MSG_ERROR([IJG JPEG library not found at $with_jpeg_lib_dir])
+ fi
+
+ if test "x$with_jpeg_include_dir" != "x" ; then
+ CPPFLAGS="-I$with_jpeg_include_dir $CPPFLAGS"
+ fi
+ AC_CHECK_HEADER(jpeglib.h, [jpeg_h=yes], [jpeg_h=no])
+ if test "$jpeg_h" = "no" -a "x$with_jpeg_include_dir" != "x" ; then
+ AC_MSG_ERROR([IJG JPEG library headers not found at $with_jpeg_include_dir])
+ fi
+
+ if test "$jpeg_lib" = "yes" -a "$jpeg_h" = "yes" ; then
+ HAVE_JPEG=yes
+ fi
+
+fi
+
+if test "$HAVE_JPEG" = "yes" ; then
+ AC_DEFINE(JPEG_SUPPORT,1,[Support JPEG compression (requires IJG JPEG library)])
+ LIBS="-ljpeg $LIBS"
+
+ if test "$HAVE_RPATH" = "yes" -a "x$with_jpeg_lib_dir" != "x" ; then
+ LIBDIR="-R $with_jpeg_lib_dir $LIBDIR"
+ fi
+
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Check for Old JPEG.
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(old-jpeg,
+ AS_HELP_STRING([--disable-old-jpeg],
+ [disable support for Old JPEG compresson (read-only, enabled by default)]),
+ [HAVE_OJPEG=${enableval}], [HAVE_OJPEG=yes])
+
+if test "$HAVE_JPEG" = "yes" -a "$HAVE_OJPEG" = "yes" ; then
+ AC_DEFINE(OJPEG_SUPPORT, 1,
+ [Support Old JPEG compresson (read-only)])
+else
+ HAVE_OJPEG=no
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Check for JBIG-KIT.
+dnl ---------------------------------------------------------------------------
+
+HAVE_JBIG=no
+
+AC_ARG_ENABLE(jbig,
+ AS_HELP_STRING([--disable-jbig],
+ [disable JBIG-KIT usage (required for ISO JBIG compression, enabled by default)]),,)
+AC_ARG_WITH(jbig-include-dir,
+ AS_HELP_STRING([--with-jbig-include-dir=DIR],
+ [location of JBIG-KIT headers]),,)
+AC_ARG_WITH(jbig-lib-dir,
+ AS_HELP_STRING([--with-jbig-lib-dir=DIR],
+ [location of JBIG-KIT library binary]),,)
+
+if test "x$enable_jbig" != "xno" ; then
+
+ if test "x$with_jbig_lib_dir" != "x" ; then
+ LDFLAGS="-L$with_jbig_lib_dir $LDFLAGS"
+
+ fi
+
+ AC_CHECK_LIB(jbig, jbg_dec_init, [jbig_lib=yes], [jbig_lib=no],)
+ if test "$jbig_lib" = "no" -a "x$with_jbig_lib_dir" != "x" ; then
+ AC_MSG_ERROR([JBIG-KIT library not found at $with_jbig_lib_dir])
+ fi
+
+ if test "x$with_jbig_include_dir" != "x" ; then
+ CPPFLAGS="-I$with_jbig_include_dir $CPPFLAGS"
+ fi
+ AC_CHECK_HEADER(jbig.h, [jbig_h=yes], [jbig_h=no])
+ if test "$jbig_h" = "no" -a "x$with_jbig_include_dir" != "x" ; then
+ AC_MSG_ERROR([JBIG-KIT library headers not found at $with_jbig_include_dir])
+ fi
+
+ if test "$jbig_lib" = "yes" -a "$jbig_h" = "yes" ; then
+ HAVE_JBIG=yes
+ fi
+
+fi
+
+if test "$HAVE_JBIG" = "yes" ; then
+ AC_DEFINE(JBIG_SUPPORT,1,[Support ISO JBIG compression (requires JBIG-KIT library)])
+ LIBS="-ljbig $LIBS"
+
+ if test "$HAVE_RPATH" = "yes" -a "x$with_jbig_lib_dir" != "x" ; then
+ LIBDIR="-R $with_jbig_lib_dir $LIBDIR"
+ fi
+
+ # Older versions of jbigkit lack jbg_newlen
+ AC_CHECK_FUNCS([jbg_newlen])
+
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Check for C++.
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(cxx,
+ AS_HELP_STRING([--enable-cxx],
+ [enable C++ stream API building (requires C++ compiler)]),
+ [HAVE_CXX=$enableval], [HAVE_CXX=yes])
+
+if test "$HAVE_CXX" = "yes" ; then
+ AC_DEFINE(CXX_SUPPORT, 1, [Support C++ stream API (requires C++ compiler)])
+else
+ HAVE_CXX=no
+fi
+
+AM_CONDITIONAL(HAVE_CXX, test "$HAVE_CXX" = "yes")
+
+dnl ---------------------------------------------------------------------------
+dnl Check for OpenGL and GLUT.
+dnl ---------------------------------------------------------------------------
+
+HAVE_OPENGL=no
+
+AC_PATH_XTRA
+
+AX_CHECK_GL
+AX_CHECK_GLU
+AX_CHECK_GLUT
+
+if test "$no_x" != "yes" -a "$no_gl" != "yes" \
+ -a "$no_glu" != "yes" -a "$no_glut" != "yes" ; then
+ HAVE_OPENGL=yes
+fi
+
+AM_CONDITIONAL(HAVE_OPENGL, test "$HAVE_OPENGL" = "yes")
+
+dnl ---------------------------------------------------------------------------
+dnl Check for X Athena Widgets
+dnl ---------------------------------------------------------------------------
+
+dnl HAVE_XAW=no
+
+dnl ICE_FIND_ATHENA
+
+dnl if test "$no_xaw" != "yes" ; then
+dnl HAVE_XAW=yes
+dnl fi
+
+dnl AM_CONDITIONAL(HAVE_XAW, test "$HAVE_XAW" = "yes")
+
+dnl ===========================================================================
+dnl ``Orthogonal Features''
+dnl ===========================================================================
+
+dnl ---------------------------------------------------------------------------
+dnl Default handling of strip chopping support.
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(strip-chopping,
+ AS_HELP_STRING([--disable-strip-chopping],
+ [disable support for strip chopping (whether or not to convert single-strip uncompressed images to mutiple strips of specified size to reduce memory usage)]),
+ [HAVE_STRIPCHOP=$enableval], [HAVE_STRIPCHOP=yes])
+AC_ARG_WITH(default-strip-size,
+ AS_HELP_STRING([--with-default-strip-size=SIZE],
+ [default size of the strip in bytes (when strip chopping enabled) [[default=8192]]]),,)
+
+if test "$HAVE_STRIPCHOP" = "yes" \
+ -a "x$with_default_strip_size" != "xno"; then
+ AC_DEFINE(STRIPCHOP_DEFAULT,TIFF_STRIPCHOP,[Support strip chopping (whether or not to convert single-strip uncompressed images to mutiple strips of specified size to reduce memory usage)])
+
+ if test "x$with_default_strip_size" = "x" \
+ -o "x$with_default_strip_size" = "xyes"; then
+ with_default_strip_size="8192"
+ fi
+
+ AC_DEFINE_UNQUOTED(STRIP_SIZE_DEFAULT,$with_default_strip_size,[Default size of the strip in bytes (when strip chopping enabled)])
+
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Default subifd support.
+dnl ---------------------------------------------------------------------------
+AC_DEFINE(SUBIFD_SUPPORT,1,[Enable SubIFD tag (330) support])
+
+dnl ---------------------------------------------------------------------------
+dnl Default handling of ASSOCALPHA support.
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(extrasample-as-alpha,
+ AS_HELP_STRING([--disable-extrasample-as-alpha],
+ [the RGBA interface will treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many packages produce RGBA files but don't mark the alpha properly]),
+ [HAVE_EXTRASAMPLE_AS_ALPHA=$enableval],
+ [HAVE_EXTRASAMPLE_AS_ALPHA=yes])
+
+if test "$HAVE_EXTRASAMPLE_AS_ALPHA" = "yes" ; then
+ AC_DEFINE(DEFAULT_EXTRASAMPLE_AS_ALPHA, 1,
+ [Treat extra sample as alpha (default enabled). The RGBA interface will treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many packages produce RGBA files but don't mark the alpha properly.])
+fi
+
+dnl ---------------------------------------------------------------------------
+dnl Default handling of YCbCr subsampling support.
+dnl See Bug 168 in Bugzilla, and JPEGFixupTestSubsampling() for details.
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE(check-ycbcr-subsampling,
+ AS_HELP_STRING([--disable-check-ycbcr-subsampling],
+ [disable picking up YCbCr subsampling info from the JPEG data stream to support files lacking the tag]),
+ [CHECK_JPEG_YCBCR_SUBSAMPLING=$enableval],
+ [CHECK_JPEG_YCBCR_SUBSAMPLING=yes])
+
+if test "$CHECK_JPEG_YCBCR_SUBSAMPLING" = "yes" ; then
+ AC_DEFINE(CHECK_JPEG_YCBCR_SUBSAMPLING, 1,
+ [Pick up YCbCr subsampling info from the JPEG data stream to support files lacking the tag (default enabled).])
+fi
+
+dnl ---------------------------------------------------------------------------
+
+AC_SUBST(LIBDIR)
+
+AC_CONFIG_HEADERS([libtiff/tif_config.h libtiff/tiffconf.h])
+
+AC_CONFIG_FILES([Makefile \
+ build/Makefile \
+ contrib/Makefile \
+ contrib/acorn/Makefile \
+ contrib/addtiffo/Makefile \
+ contrib/dbs/Makefile \
+ contrib/dbs/xtiff/Makefile \
+ contrib/iptcutil/Makefile \
+ contrib/mac-cw/Makefile \
+ contrib/mac-mpw/Makefile \
+ contrib/mfs/Makefile \
+ contrib/pds/Makefile \
+ contrib/ras/Makefile \
+ contrib/stream/Makefile \
+ contrib/tags/Makefile \
+ contrib/win_dib/Makefile \
+ html/Makefile \
+ html/images/Makefile \
+ html/man/Makefile \
+ libtiff/Makefile \
+ man/Makefile \
+ port/Makefile \
+ test/Makefile \
+ tools/Makefile])
+AC_OUTPUT
+
+dnl ---------------------------------------------------------------------------
+dnl Display configuration status
+dnl ---------------------------------------------------------------------------
+
+LOC_MSG()
+LOC_MSG([Libtiff is now configured for ${host}])
+LOC_MSG()
+LOC_MSG([ Installation directory: ${prefix}])
+LOC_MSG([ Documentation directory: ${LIBTIFF_DOCDIR}])
+LOC_MSG([ C compiler: ${CC} ${CFLAGS}])
+LOC_MSG([ C++ compiler: ${CXX} ${CXXFLAGS}])
+LOC_MSG([ Enable runtime linker paths: ${HAVE_RPATH}])
+LOC_MSG([ Support Microsoft Document Imaging: ${HAVE_MDI}])
+LOC_MSG()
+LOC_MSG([ Support for internal codecs:])
+LOC_MSG([ CCITT Group 3 & 4 algorithms: ${HAVE_CCITT}])
+LOC_MSG([ Macintosh PackBits algorithm: ${HAVE_PACKBITS}])
+LOC_MSG([ LZW algorithm: ${HAVE_LZW}])
+LOC_MSG([ ThunderScan 4-bit RLE algorithm: ${HAVE_THUNDER}])
+LOC_MSG([ NeXT 2-bit RLE algorithm: ${HAVE_NEXT}])
+LOC_MSG([ LogLuv high dynamic range encoding: ${HAVE_LOGLUV}])
+LOC_MSG()
+LOC_MSG([ Support for external codecs:])
+LOC_MSG([ ZLIB support: ${HAVE_ZLIB}])
+LOC_MSG([ Pixar log-format algorithm: ${HAVE_PIXARLOG}])
+LOC_MSG([ JPEG support: ${HAVE_JPEG}])
+LOC_MSG([ Old JPEG support: ${HAVE_OJPEG}])
+LOC_MSG([ ISO JBIG support: ${HAVE_JBIG}])
+LOC_MSG()
+LOC_MSG([ C++ support: ${HAVE_CXX}])
+LOC_MSG()
+dnl LOC_MSG([ X Athena Widgets support: ${HAVE_XAW}])
+LOC_MSG([ OpenGL support: ${HAVE_OPENGL}])
+LOC_MSG()
+
diff --git a/tiff/configure.com b/tiff/configure.com
new file mode 100644
index 0000000..6a5d8b5
--- /dev/null
+++ b/tiff/configure.com
@@ -0,0 +1,1345 @@
+$! $Id: configure.com,v 1.1.2.2 2009-08-20 22:31:00 bfriesen Exp $
+$!
+$! OpenVMS configure procedure for libtiff
+$! (c) Alexey Chupahin 22-NOV-2007
+$! elvis_75@mail.ru
+$!
+$! Permission to use, copy, modify, distribute, and sell this software and
+$! its documentation for any purpose is hereby granted without fee, provided
+$! that (i) the above copyright notices and this permission notice appear in
+$! all copies of the software and related documentation, and (ii) the names of
+$! Sam Leffler and Silicon Graphics may not be used in any advertising or
+$! publicity relating to the software without the specific, prior written
+$! permission of Sam Leffler and Silicon Graphics.
+$!
+$! THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+$! EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+$! WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+$!
+$! IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+$! ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+$! OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+$! WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+$! LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+$! OF THIS SOFTWARE.
+$!
+$!
+$ SET NOON
+$WRITE SYS$OUTPUT " "
+$WRITE SYS$OUTPUT "Configuring libTIFF library"
+$WRITE SYS$OUTPUT " "
+$! Checking architecture
+$DECC = F$SEARCH("SYS$SYSTEM:DECC$COMPILER.EXE") .NES. ""
+$IF (.NOT. DECC) THEN $WRITE SYS$OUTPUT "BAD compiler" GOTO EXIT
+$ IF F$GETSYI("ARCH_TYPE").EQ.1 THEN CPU = "VAX"
+$ IF F$GETSYI("ARCH_TYPE").EQ.2 THEN CPU = "Alpha"
+$ IF F$GETSYI("ARCH_TYPE").EQ.3 THEN CPU = "I64"
+$ OS = F$GETSYI("VERSION")
+$WRITE SYS$OUTPUT "Checking architecture ... ", CPU
+$WRITE SYS$OUTPUT "Checking OS ... OpenVMS ",OS
+$SHARED=0
+$IF ( (CPU.EQS."Alpha").OR.(CPU.EQS."I64") )
+$ THEN
+$ SHARED=64
+$ ELSE
+$ SHARED=32
+$ENDIF
+$MMS = F$SEARCH("SYS$SYSTEM:MMS.EXE") .NES. ""
+$MMK = F$TYPE(MMK)
+$IF (MMS .OR. MMK.NES."") THEN GOTO TEST_LIBRARIES
+$! I cant find any make tool
+$GOTO EXIT
+$!
+$!
+$TEST_LIBRARIES:
+$! Setting as MAKE utility one of MMS or MMK. I prefer MMS.
+$IF (MMK.NES."") THEN MAKE="MMK"
+$IF (MMS) THEN MAKE="MMS"
+$WRITE SYS$OUTPUT "Checking build utility ... ''MAKE'"
+$WRITE SYS$OUTPUT " "
+$!
+$!
+$IF (P1.EQS."STATIC").OR.(P1.EQS."static") THEN SHARED=0
+$!
+$!
+$!"Checking for strcasecmp "
+$ DEFINE SYS$ERROR _NLA0:
+$ DEFINE SYS$OUTPUT _NLA0:
+$ CC/OBJECT=TEST.OBJ/INCLUDE=(ZLIB) SYS$INPUT
+ #include <strings.h>
+ #include <stdlib.h>
+
+ int main()
+ {
+ if (strcasecmp("bla", "Bla")==0) exit(0);
+ else exit(2);
+ }
+$!
+$TMP = $STATUS
+$DEASS SYS$ERROR
+$DEAS SYS$OUTPUT
+$IF (TMP .NE. %X10B90001)
+$ THEN
+$ HAVE_STRCASECMP=0
+$ GOTO NEXT1
+$ENDIF
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$LINK/EXE=TEST TEST
+$TMP = $STATUS
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10000001)
+$ THEN
+$ HAVE_STRCASECMP=0
+$ GOTO NEXT1
+$ENDIF
+$!
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$RUN TEST
+$IF ($STATUS .NE. %X00000001)
+$ THEN
+$ HAVE_STRCASECMP=0
+$ ELSE
+$ HAVE_STRCASECMP=1
+$ENDIF
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$NEXT1:
+$IF (HAVE_STRCASECMP.EQ.1)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for strcasecmp ... Yes"
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for strcasecmp ... No"
+$ENDIF
+$!
+$!
+
+$!"Checking for lfind "
+$ DEFINE SYS$ERROR _NLA0:
+$ DEFINE SYS$OUTPUT _NLA0:
+$ CC/OBJECT=TEST.OBJ/INCLUDE=(ZLIB) SYS$INPUT
+ #include <search.h>
+
+ int main()
+ {
+ lfind((const void *)key, (const void *)NULL, (size_t *)NULL,
+ (size_t) 0, NULL);
+ }
+$!
+$TMP = $STATUS
+$DEASS SYS$ERROR
+$DEAS SYS$OUTPUT
+$IF (TMP .NE. %X10B90001)
+$ THEN
+$ HAVE_LFIND=0
+$ GOTO NEXT2
+$ENDIF
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$LINK/EXE=TEST TEST
+$TMP = $STATUS
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10000001)
+$ THEN
+$ HAVE_LFIND=0
+$ GOTO NEXT2
+$ ELSE
+$ HAVE_LFIND=1
+$ENDIF
+$!
+$NEXT2:
+$IF (HAVE_LFIND.EQ.1)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for lfind ... Yes"
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for lfind ... No"
+$ENDIF
+$!
+$!
+$!"Checking for correct zlib library "
+$ DEFINE SYS$ERROR _NLA0:
+$ DEFINE SYS$OUTPUT _NLA0:
+$ CC/OBJECT=TEST.OBJ/INCLUDE=(ZLIB) SYS$INPUT
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <zlib.h>
+ int main()
+ {
+ printf("checking version zlib: %s\n",zlibVersion());
+ }
+$TMP = $STATUS
+$DEASS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10B90001)
+$ THEN
+$ HAVE_ZLIB=0
+$ GOTO EXIT
+$ENDIF
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$LINK/EXE=TEST TEST,ZLIB:LIBZ/LIB
+$TMP = $STATUS
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10000001)
+$ THEN
+$ HAVE_ZLIB=0
+$ GOTO EXIT
+$ ELSE
+$ HAVE_ZLIB=1
+$ENDIF
+$IF (HAVE_ZLIB.EQ.1)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for correct zlib library ... Yes"
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for correct zlib library ... No"
+$ WRITE SYS$OUTPUT "This is fatal. Please download and install good library from fafner.dyndns.org/~alexey/libsdl/public.html"
+$ENDIF
+$RUN TEST
+$!
+
+$DEL TEST.OBJ;*
+$! Checking for JPEG ...
+$ DEFINE SYS$ERROR _NLA0:
+$ DEFINE SYS$OUTPUT _NLA0:
+$ CC/OBJECT=TEST.OBJ/INCLUDE=(JPEG) SYS$INPUT
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <jpeglib.h>
+ #include <jversion.h>
+ int main()
+ {
+ printf("checking version jpeg: %s\n",JVERSION);
+ jpeg_quality_scaling(0);
+ return 0;
+ }
+$TMP = $STATUS
+$DEASS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10B90001)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for static jpeg library ... No"
+$ HAVE_JPEG=0
+$ENDIF
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$LINK/EXE=TEST TEST,JPEG:LIBJPEG/LIB
+$TMP = $STATUS
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10000001)
+$ THEN
+$ HAVE_JPEG=0
+$ ELSE
+$ HAVE_JPEG=1
+$ENDIF
+$IF (HAVE_JPEG.EQ.1)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for static jpeg library ... Yes"
+$ JPEG_LIBRARY_PATH="JPEG:LIBJPEG/LIB"
+$ RUN TEST
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for static jpeg library ... No"
+$ENDIF
+$!
+$!"Checking for SHARED JPEG library "
+$OPEN/WRITE OUT TEST.OPT
+$WRITE OUT "SYS$SHARE:LIBJPEG$SHR/SHARE"
+$WRITE OUT "ZLIB:LIBZ/LIB"
+$CLOSE OUT
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$LINK/EXE=TEST TEST,TEST/OPT
+$TMP = $STATUS
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
+$!WRITE SYS$OUTPUT TMP
+$IF (TMP .NE. %X10000001)
+$ THEN
+$ HAVE_JPEG_SHARED=0
+$ ELSE
+$ HAVE_JPEG_SHARED=1
+$ENDIF
+$IF (HAVE_JPEG_SHARED.EQ.1)
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for shared jpeg library ... Yes"
+$ JPEG_LIBRARY_PATH="SYS$SHARE:LIBJPEG$SHR/SHARE"
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for shared jpeg library ... No"
+$ENDIF
+$!
+$ IF ( (HAVE_JPEG_SHARED.EQ.0).AND.(HAVE_JPEG.EQ.0) )
+$ THEN
+$ WRITE SYS$OUTPUT "No JPEG library installed. This is fatal. Please download and install good library from fafner.dyndns.org/~alexey/libsdl/public.html"
+$ GOTO EXIT
+$ ENDIF
+$!
+$!
+$!
+$! Checking for X11 ...
+$IF F$TRNLNM("DECW$INCLUDE") .NES. ""
+$ THEN
+$ WRITE SYS$OUTPUT "Checking for X11 ... Yes"
+$ ELSE
+$ WRITE SYS$OUTPUT "Checking for X11 ... No"
+$ WRITE SYS$OUTPUT "This is fatal. Please install X11 software"
+$ GOTO EXIT
+$ENDIF
+$!
+$!WRITING BUILD FILES
+$OPEN/WRITE OUT BUILD.COM
+$ WRITE OUT "$set def [.port]"
+$ WRITE OUT "$",MAKE
+$ WRITE OUT "$set def [-.libtiff]"
+$ WRITE OUT "$",MAKE
+$ WRITE OUT "$set def [-.tools]"
+$ WRITE OUT "$",MAKE
+$ WRITE OUT "$set def [-]"
+$ WRITE OUT "$cop [.PORT]LIBPORT.OLB [.LIBTIFF]LIBPORT.OLB"
+$ WRITE OUT "$ CURRENT = F$ENVIRONMENT (""DEFAULT"") "
+$ WRITE OUT "$TIFF=CURRENT"
+$ WRITE OUT "$OPEN/WRITE OUTT LIBTIFF$STARTUP.COM"
+$ WRITE OUT "$TIFF[F$LOCATE(""]"",TIFF),9]:="".LIBTIFF]"""
+$ WRITE OUT "$WRITE OUTT ""DEFINE TIFF ","'","'","TIFF'"" "
+$ WRITE OUT "$TIFF=CURRENT"
+$ WRITE OUT "$TIFF[F$LOCATE(""]"",TIFF),7]:="".TOOLS]"""
+$ WRITE OUT "$WRITE OUTT ""BMP2TIFF:==$", "'","'","TIFF'BMP2TIFF"""
+$ WRITE OUT "$WRITE OUTT ""FAX2PS:==$", "'","'","TIFF'FAX2PS"""
+$ WRITE OUT "$WRITE OUTT ""FAX2TIFF:==$", "'","'","TIFF'FAX2TIFF"""
+$ WRITE OUT "$WRITE OUTT ""GIF2TIFF:==$", "'","'","TIFF'GIF2TIFF"""
+$ WRITE OUT "$WRITE OUTT ""PAL2RGB:==$", "'","'","TIFF'PAL2RGB"""
+$ WRITE OUT "$WRITE OUTT ""PPM2TIFF:==$", "'","'","TIFF'PPM2TIFF"""
+$ WRITE OUT "$WRITE OUTT ""RAS2TIFF:==$", "'","'","TIFF'RAS2TIFF"""
+$ WRITE OUT "$WRITE OUTT ""RAW2TIFF:==$", "'","'","TIFF'RAW2TIFF"""
+$ WRITE OUT "$WRITE OUTT ""RGB2YCBCR:==$", "'","'","TIFF'RGB2YCBCR"""
+$ WRITE OUT "$WRITE OUTT ""THUMBNAIL:==$", "'","'","TIFF'THUMBNAIL"""
+$ WRITE OUT "$WRITE OUTT ""TIFF2BW:==$", "'","'","TIFF'TIFF2BW"""
+$ WRITE OUT "$WRITE OUTT ""TIFF2PDF:==$", "'","'","TIFF'TIFF2PDF"""
+$ WRITE OUT "$WRITE OUTT ""TIFF2PS:==$", "'","'","TIFF'TIFF2PS"""
+$ WRITE OUT "$WRITE OUTT ""TIFF2RGBA:==$", "'","'","TIFF'TIFF2RGBA"""
+$ WRITE OUT "$WRITE OUTT ""TIFFCMP:==$", "'","'","TIFF'TIFFCMP"""
+$ WRITE OUT "$WRITE OUTT ""TIFFCP:==$", "'","'","TIFF'TIFFCP"""
+$ WRITE OUT "$WRITE OUTT ""TIFFDITHER:==$", "'","'","TIFF'TIFFDITHER"""
+$ WRITE OUT "$WRITE OUTT ""TIFFDUMP:==$", "'","'","TIFF'TIFFDUMP"""
+$ WRITE OUT "$WRITE OUTT ""TIFFINFO:==$", "'","'","TIFF'TIFFINFO"""
+$ WRITE OUT "$WRITE OUTT ""TIFFMEDIAN:==$", "'","'","TIFF'TIFFMEDIAN"""
+$ WRITE OUT "$WRITE OUTT ""TIFFCROP:==$", "'","'","TIFF'TIFFCROP"""
+$ WRITE OUT "$WRITE OUTT ""TIFFSET:==$", "'","'","TIFF'TIFFSET"""
+$ WRITE OUT "$CLOSE OUTT"
+$ WRITE OUT "$OPEN/WRITE OUTT [.LIBTIFF]LIBTIFF.OPT"
+$ WRITE OUT "$WRITE OUTT ""TIFF:TIFF/LIB""
+$ WRITE OUT "$WRITE OUTT ""TIFF:LIBPORT/LIB""
+$ WRITE OUT "$WRITE OUTT ""JPEG:LIBJPEG/LIB""
+$ WRITE OUT "$WRITE OUTT ""ZLIB:LIBZ/LIB""
+$ WRITE OUT "$CLOSE OUTT"
+$!
+$ WRITE OUT "$WRITE SYS$OUTPUT "" "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""***************************************************************************** "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""LIBTIFF$STARTUP.COM has been created. "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""This file setups all logicals needed. It should be execute before using LibTIFF "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""Nice place to call it - LOGIN.COM "" "
+$ WRITE OUT "$WRITE SYS$OUTPUT """" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""Using the library:"" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""CC/INC=TIFF ASCII_TAG.C"" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""LINK ASCII_TAG,TIFF:LIBTIFF/OPT"" "
+$ WRITE OUT "$WRITE SYS$OUTPUT ""***************************************************************************** "" "
+$CLOSE OUT
+$!
+$! DESCRIP.MMS in [.PORT]
+$OBJ="dummy.obj"
+$IF HAVE_STRCASECMP.NE.1
+$ THEN
+$ OBJ=OBJ+",strcasecmp.obj"
+$ENDIF
+$IF HAVE_LFIND.NE.1
+$ THEN
+$ OBJ=OBJ+",lfind.obj"
+$ENDIF
+$OPEN/WRITE OUT [.PORT]DESCRIP.MMS
+$WRITE OUT "OBJ=",OBJ
+$WRITE OUT ""
+$WRITE OUT "LIBPORT.OLB : $(OBJ)"
+$WRITE OUT " LIB/CREA LIBPORT $(OBJ)"
+$WRITE OUT ""
+$WRITE OUT ""
+$WRITE OUT "dummy.obj : dummy.c"
+$WRITE OUT " $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)"
+$WRITE OUT ""
+$WRITE OUT ""
+$WRITE OUT "strcasecmp.obj : strcasecmp.c"
+$WRITE OUT " $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)"
+$WRITE OUT ""
+$WRITE OUT ""
+$WRITE OUT "lfind.obj : lfind.c"
+$WRITE OUT " $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)"
+$WRITE OUT ""
+$WRITE OUT ""
+$CLOSE OUT
+$!
+$!
+$WRITE SYS$OUTPUT "Creating LIBTIFF$DEF.OPT"
+$IF (SHARED.EQ.64)
+$ THEN
+$ COPY SYS$INPUT TIFF$DEF.OPT
+SYMBOL_VECTOR= (-
+TIFFOpen=PROCEDURE,-
+TIFFGetVersion=PROCEDURE,-
+TIFFCleanup=PROCEDURE,-
+TIFFClose=PROCEDURE,-
+TIFFFlush=PROCEDURE,-
+TIFFFlushData=PROCEDURE,-
+TIFFGetField=PROCEDURE,-
+TIFFVGetField=PROCEDURE,-
+TIFFGetFieldDefaulted=PROCEDURE,-
+TIFFVGetFieldDefaulted=PROCEDURE,-
+TIFFGetTagListEntry=PROCEDURE,-
+TIFFGetTagListCount=PROCEDURE,-
+TIFFReadDirectory=PROCEDURE,-
+TIFFScanlineSize=PROCEDURE,-
+TIFFStripSize=PROCEDURE,-
+TIFFVStripSize=PROCEDURE,-
+TIFFRawStripSize=PROCEDURE,-
+TIFFTileRowSize=PROCEDURE,-
+TIFFTileSize=PROCEDURE,-
+TIFFVTileSize=PROCEDURE,-
+TIFFFileno=PROCEDURE,-
+TIFFSetFileno=PROCEDURE,-
+TIFFGetMode=PROCEDURE,-
+TIFFIsTiled=PROCEDURE,-
+TIFFIsByteSwapped=PROCEDURE,-
+TIFFIsBigEndian=PROCEDURE,-
+TIFFIsMSB2LSB=PROCEDURE,-
+TIFFIsUpSampled=PROCEDURE,-
+TIFFCIELabToRGBInit=PROCEDURE,-
+TIFFCIELabToXYZ=PROCEDURE,-
+TIFFXYZToRGB=PROCEDURE,-
+TIFFYCbCrToRGBInit=PROCEDURE,-
+TIFFYCbCrtoRGB=PROCEDURE,-
+TIFFCurrentRow=PROCEDURE,-
+TIFFCurrentDirectory=PROCEDURE,-
+TIFFCurrentStrip=PROCEDURE,-
+TIFFCurrentTile=PROCEDURE,-
+TIFFDataWidth=PROCEDURE,-
+TIFFReadBufferSetup=PROCEDURE,-
+TIFFWriteBufferSetup=PROCEDURE,-
+TIFFSetupStrips=PROCEDURE,-
+TIFFLastDirectory=PROCEDURE,-
+TIFFSetDirectory=PROCEDURE,-
+TIFFSetSubDirectory=PROCEDURE,-
+TIFFUnlinkDirectory=PROCEDURE,-
+TIFFSetField=PROCEDURE,-
+TIFFVSetField=PROCEDURE,-
+TIFFCheckpointDirectory=PROCEDURE,-
+TIFFWriteDirectory=PROCEDURE,-
+TIFFRewriteDirectory=PROCEDURE,-
+TIFFPrintDirectory=PROCEDURE,-
+TIFFReadScanline=PROCEDURE,-
+TIFFWriteScanline=PROCEDURE,-
+TIFFReadRGBAImage=PROCEDURE,-
+TIFFReadRGBAImageOriented=PROCEDURE,-
+TIFFFdOpen=PROCEDURE,-
+TIFFClientOpen=PROCEDURE,-
+TIFFFileName=PROCEDURE,-
+TIFFError=PROCEDURE,-
+TIFFErrorExt=PROCEDURE,-
+TIFFWarning=PROCEDURE,-
+TIFFWarningExt=PROCEDURE,-
+TIFFSetErrorHandler=PROCEDURE,-
+TIFFSetErrorHandlerExt=PROCEDURE,-
+TIFFSetWarningHandler=PROCEDURE,-
+TIFFSetWarningHandlerExt=PROCEDURE,-
+TIFFComputeTile=PROCEDURE,-
+TIFFCheckTile=PROCEDURE,-
+TIFFNumberOfTiles=PROCEDURE,-
+TIFFReadTile=PROCEDURE,-
+TIFFWriteTile=PROCEDURE,-
+TIFFComputeStrip=PROCEDURE,-
+TIFFNumberOfStrips=PROCEDURE,-
+TIFFRGBAImageBegin=PROCEDURE,-
+TIFFRGBAImageGet=PROCEDURE,-
+TIFFRGBAImageEnd=PROCEDURE,-
+TIFFReadEncodedStrip=PROCEDURE,-
+TIFFReadRawStrip=PROCEDURE,-
+TIFFReadEncodedTile=PROCEDURE,-
+TIFFReadRawTile=PROCEDURE,-
+TIFFReadRGBATile=PROCEDURE,-
+TIFFReadRGBAStrip=PROCEDURE,-
+TIFFWriteEncodedStrip=PROCEDURE,-
+TIFFWriteRawStrip=PROCEDURE,-
+TIFFWriteEncodedTile=PROCEDURE,-
+TIFFWriteRawTile=PROCEDURE,-
+TIFFSetWriteOffset=PROCEDURE,-
+TIFFSwabDouble=PROCEDURE,-
+TIFFSwabShort=PROCEDURE,-
+TIFFSwabLong=PROCEDURE,-
+TIFFSwabArrayOfShort=PROCEDURE,-
+TIFFSwabArrayOfLong=PROCEDURE,-
+TIFFSwabArrayOfDouble=PROCEDURE,-
+TIFFSwabArrayOfTriples=PROCEDURE,-
+TIFFReverseBits=PROCEDURE,-
+TIFFGetBitRevTable=PROCEDURE,-
+TIFFDefaultStripSize=PROCEDURE,-
+TIFFDefaultTileSize=PROCEDURE,-
+TIFFRasterScanlineSize=PROCEDURE,-
+_TIFFmalloc=PROCEDURE,-
+_TIFFrealloc=PROCEDURE,-
+_TIFFfree=PROCEDURE,-
+_TIFFmemset=PROCEDURE,-
+_TIFFmemcpy=PROCEDURE,-
+_TIFFmemcmp=PROCEDURE,-
+TIFFCreateDirectory=PROCEDURE,-
+TIFFSetTagExtender=PROCEDURE,-
+TIFFMergeFieldInfo=PROCEDURE,-
+TIFFFindFieldInfo=PROCEDURE,-
+TIFFFindFieldInfoByName=PROCEDURE,-
+TIFFFieldWithName=PROCEDURE,-
+TIFFFieldWithTag=PROCEDURE,-
+TIFFCurrentDirOffset=PROCEDURE,-
+TIFFWriteCheck=PROCEDURE,-
+TIFFRGBAImageOK=PROCEDURE,-
+TIFFNumberOfDirectories=PROCEDURE,-
+TIFFSetFileName=PROCEDURE,-
+TIFFSetClientdata=PROCEDURE,-
+TIFFSetMode=PROCEDURE,-
+TIFFClientdata=PROCEDURE,-
+TIFFGetReadProc=PROCEDURE,-
+TIFFGetWriteProc=PROCEDURE,-
+TIFFGetSeekProc=PROCEDURE,-
+TIFFGetCloseProc=PROCEDURE,-
+TIFFGetSizeProc=PROCEDURE,-
+TIFFGetMapFileProc=PROCEDURE,-
+TIFFGetUnmapFileProc=PROCEDURE,-
+TIFFIsCODECConfigured=PROCEDURE,-
+TIFFGetConfiguredCODECs=PROCEDURE,-
+TIFFFindCODEC=PROCEDURE,-
+TIFFRegisterCODEC=PROCEDURE,-
+TIFFUnRegisterCODEC=PROCEDURE,-
+TIFFFreeDirectory=PROCEDURE,-
+TIFFReadCustomDirectory=PROCEDURE,-
+TIFFReadEXIFDirectory=PROCEDURE,-
+TIFFAccessTagMethods=PROCEDURE,-
+TIFFGetClientInfo=PROCEDURE,-
+TIFFSetClientInfo=PROCEDURE,-
+TIFFReassignTagToIgnore=PROCEDURE-
+)
+
+$ENDIF
+$IF (SHARED.EQ.32)
+$ THEN
+$ COPY SYS$INPUT TIFF$DEF.OPT
+UNIVERSAL=TIFFOpen
+UNIVERSAL=TIFFGetVersion
+UNIVERSAL=TIFFCleanup
+UNIVERSAL=TIFFClose
+UNIVERSAL=TIFFFlush
+UNIVERSAL=TIFFFlushData
+UNIVERSAL=TIFFGetField
+UNIVERSAL=TIFFVGetField
+UNIVERSAL=TIFFGetFieldDefaulted
+UNIVERSAL=TIFFVGetFieldDefaulted
+UNIVERSAL=TIFFGetTagListEntry
+UNIVERSAL=TIFFGetTagListCount
+UNIVERSAL=TIFFReadDirectory
+UNIVERSAL=TIFFScanlineSize
+UNIVERSAL=TIFFStripSize
+UNIVERSAL=TIFFVStripSize
+UNIVERSAL=TIFFRawStripSize
+UNIVERSAL=TIFFTileRowSize
+UNIVERSAL=TIFFTileSize
+UNIVERSAL=TIFFVTileSize
+UNIVERSAL=TIFFFileno
+UNIVERSAL=TIFFSetFileno
+UNIVERSAL=TIFFGetMode
+UNIVERSAL=TIFFIsTiled
+UNIVERSAL=TIFFIsByteSwapped
+UNIVERSAL=TIFFIsBigEndian
+UNIVERSAL=TIFFIsMSB2LSB
+UNIVERSAL=TIFFIsUpSampled
+UNIVERSAL=TIFFCIELabToRGBInit
+UNIVERSAL=TIFFCIELabToXYZ
+UNIVERSAL=TIFFXYZToRGB
+UNIVERSAL=TIFFYCbCrToRGBInit
+UNIVERSAL=TIFFYCbCrtoRGB
+UNIVERSAL=TIFFCurrentRow
+UNIVERSAL=TIFFCurrentDirectory
+UNIVERSAL=TIFFCurrentStrip
+UNIVERSAL=TIFFCurrentTile
+UNIVERSAL=TIFFDataWidth
+UNIVERSAL=TIFFReadBufferSetup
+UNIVERSAL=TIFFWriteBufferSetup
+UNIVERSAL=TIFFSetupStrips
+UNIVERSAL=TIFFLastDirectory
+UNIVERSAL=TIFFSetDirectory
+UNIVERSAL=TIFFSetSubDirectory
+UNIVERSAL=TIFFUnlinkDirectory
+UNIVERSAL=TIFFSetField
+UNIVERSAL=TIFFVSetField
+UNIVERSAL=TIFFCheckpointDirectory
+UNIVERSAL=TIFFWriteDirectory
+UNIVERSAL=TIFFRewriteDirectory
+UNIVERSAL=TIFFPrintDirectory
+UNIVERSAL=TIFFReadScanline
+UNIVERSAL=TIFFWriteScanline
+UNIVERSAL=TIFFReadRGBAImage
+UNIVERSAL=TIFFReadRGBAImageOriented
+UNIVERSAL=TIFFFdOpen
+UNIVERSAL=TIFFClientOpen
+UNIVERSAL=TIFFFileName
+UNIVERSAL=TIFFError
+UNIVERSAL=TIFFErrorExt
+UNIVERSAL=TIFFWarning
+UNIVERSAL=TIFFWarningExt
+UNIVERSAL=TIFFSetErrorHandler
+UNIVERSAL=TIFFSetErrorHandlerExt
+UNIVERSAL=TIFFSetWarningHandler
+UNIVERSAL=TIFFSetWarningHandlerExt
+UNIVERSAL=TIFFComputeTile
+UNIVERSAL=TIFFCheckTile
+UNIVERSAL=TIFFNumberOfTiles
+UNIVERSAL=TIFFReadTile
+UNIVERSAL=TIFFWriteTile
+UNIVERSAL=TIFFComputeStrip
+UNIVERSAL=TIFFNumberOfStrips
+UNIVERSAL=TIFFRGBAImageBegin
+UNIVERSAL=TIFFRGBAImageGet
+UNIVERSAL=TIFFRGBAImageEnd
+UNIVERSAL=TIFFReadEncodedStrip
+UNIVERSAL=TIFFReadRawStrip
+UNIVERSAL=TIFFReadEncodedTile
+UNIVERSAL=TIFFReadRawTile
+UNIVERSAL=TIFFReadRGBATile
+UNIVERSAL=TIFFReadRGBAStrip
+UNIVERSAL=TIFFWriteEncodedStrip
+UNIVERSAL=TIFFWriteRawStrip
+UNIVERSAL=TIFFWriteEncodedTile
+UNIVERSAL=TIFFWriteRawTile
+UNIVERSAL=TIFFSetWriteOffset
+UNIVERSAL=TIFFSwabDouble
+UNIVERSAL=TIFFSwabShort
+UNIVERSAL=TIFFSwabLong
+UNIVERSAL=TIFFSwabArrayOfShort
+UNIVERSAL=TIFFSwabArrayOfLong
+UNIVERSAL=TIFFSwabArrayOfDouble
+UNIVERSAL=TIFFSwabArrayOfTriples
+UNIVERSAL=TIFFReverseBits
+UNIVERSAL=TIFFGetBitRevTable
+UNIVERSAL=TIFFDefaultStripSize
+UNIVERSAL=TIFFDefaultTileSize
+UNIVERSAL=TIFFRasterScanlineSize
+UNIVERSAL=_TIFFmalloc
+UNIVERSAL=_TIFFrealloc
+UNIVERSAL=_TIFFfree
+UNIVERSAL=_TIFFmemset
+UNIVERSAL=_TIFFmemcpy
+UNIVERSAL=_TIFFmemcmp
+UNIVERSAL=TIFFCreateDirectory
+UNIVERSAL=TIFFSetTagExtender
+UNIVERSAL=TIFFMergeFieldInfo
+UNIVERSAL=TIFFFindFieldInfo
+UNIVERSAL=TIFFFindFieldInfoByName
+UNIVERSAL=TIFFFieldWithName
+UNIVERSAL=TIFFFieldWithTag
+UNIVERSAL=TIFFCurrentDirOffset
+UNIVERSAL=TIFFWriteCheck
+UNIVERSAL=TIFFRGBAImageOK
+UNIVERSAL=TIFFNumberOfDirectories
+UNIVERSAL=TIFFSetFileName
+UNIVERSAL=TIFFSetClientdata
+UNIVERSAL=TIFFSetMode
+UNIVERSAL=TIFFClientdata
+UNIVERSAL=TIFFGetReadProc
+UNIVERSAL=TIFFGetWriteProc
+UNIVERSAL=TIFFGetSeekProc
+UNIVERSAL=TIFFGetCloseProc
+UNIVERSAL=TIFFGetSizeProc
+UNIVERSAL=TIFFGetMapFileProc
+UNIVERSAL=TIFFGetUnmapFileProc
+UNIVERSAL=TIFFIsCODECConfigured
+UNIVERSAL=TIFFGetConfiguredCODECs
+UNIVERSAL=TIFFFindCODEC
+UNIVERSAL=TIFFRegisterCODEC
+UNIVERSAL=TIFFUnRegisterCODEC
+UNIVERSAL=TIFFFreeDirectory
+UNIVERSAL=TIFFReadCustomDirectory
+UNIVERSAL=TIFFReadEXIFDirectory
+UNIVERSAL=TIFFAccessTagMethods
+UNIVERSAL=TIFFGetClientInfo
+UNIVERSAL=TIFFSetClientInfo
+UNIVERSAL=TIFFReassignTagToIgnore
+
+$ENDIF
+$!
+$!
+$! Writing TIFF$SHR.OPT file to build TOOLS
+$ IF (SHARED.GT.0)
+$ THEN
+$ OPEN/WRITE OUT TIFF$SHR.OPT
+$ WRITE OUT "[]TIFF/LIB"
+$ WRITE OUT "[-.PORT]LIBPORT/LIB"
+$ WRITE OUT JPEG_LIBRARY_PATH
+$ WRITE OUT "ZLIB:LIBZ/LIB"
+$ CLOSE OUT
+$ ENDIF
+$!
+$!
+$! Writing OPT.OPT file to build TOOLS
+$OPEN/WRITE OUT OPT.OPT
+$ IF (SHARED.GT.0)
+$ THEN
+$ WRITE OUT "[-.LIBTIFF]TIFF$SHR/SHARE"
+$ WRITE OUT JPEG_LIBRARY_PATH
+$ ELSE
+$ WRITE OUT "[-.LIBTIFF]TIFF/LIB"
+$ WRITE OUT "[-.PORT]LIBPORT/LIB"
+$ WRITE OUT JPEG_LIBRARY_PATH
+$ ENDIF
+$ WRITE OUT "ZLIB:LIBZ/LIB"
+$CLOSE OUT
+$!
+$!
+$COPY SYS$INPUT [.LIBTIFF]DESCRIP.MMS
+# (c) Alexey Chupahin 22-NOV-2007
+# OpenVMS 7.3-1, DEC 2000 mod.300
+# OpenVMS 8.3, HP rx1620
+# Makefile for DEC C compilers.
+#
+
+INCL = /INCLUDE=(JPEG,ZLIB,[])
+
+CFLAGS = $(INCL)
+
+OBJ_SYSDEP_MODULE = tif_vms.obj
+
+OBJ = \
+tif_aux.obj,\
+tif_close.obj,\
+tif_codec.obj,\
+tif_color.obj,\
+tif_compress.obj,\
+tif_dir.obj,\
+tif_dirinfo.obj,\
+tif_dirread.obj,\
+tif_dirwrite.obj,\
+tif_dumpmode.obj,\
+tif_error.obj,\
+tif_extension.obj,\
+tif_fax3.obj,\
+tif_fax3sm.obj,\
+tif_flush.obj,\
+tif_getimage.obj,\
+tif_jbig.obj,\
+tif_jpeg.obj,\
+tif_luv.obj,\
+tif_lzw.obj,\
+tif_next.obj,\
+tif_ojpeg.obj,\
+tif_open.obj,\
+tif_packbits.obj,\
+tif_pixarlog.obj,\
+tif_predict.obj,\
+tif_print.obj,\
+tif_read.obj,\
+tif_strip.obj,\
+tif_swab.obj,\
+tif_thunder.obj,\
+tif_tile.obj,\
+tif_version.obj,\
+tif_warning.obj,\
+tif_write.obj,\
+tif_zip.obj, $(OBJ_SYSDEP_MODULE)
+
+$IF (SHARED.GT.0)
+$ THEN
+$ APP SYS$INPUT [.LIBTIFF]DESCRIP.MMS
+ALL : tiff.olb, tiff$shr.exe
+ $WRITE SYS$OUTPUT "Done"
+
+tiff$shr.exe : tiff.olb
+ LINK/SHARE=TIFF$SHR.EXE TIF_AUX,[-]TIFF$DEF/OPT, [-]TIFF$SHR/OPT
+ COPY TIFF$SHR.EXE SYS$SHARE
+ PURGE SYS$SHARE:TIFF$SHR.EXE
+
+$ ELSE
+$ APP SYS$INPUT [.LIBTIFF]DESCRIP.MMS
+ALL : tiff.olb
+ $WRITE SYS$OUTPUT "Done"
+
+$ENDIF
+$!
+$!
+$ APP SYS$INPUT [.LIBTIFF]DESCRIP.MMS
+
+tiff.olb : $(OBJ)
+ lib/crea tiff.olb $(OBJ)
+
+#tif_config.h : tif_config.h-vms
+# copy tif_config.h-vms tif_config.h
+#
+#tiffconf.h : tiffconf.h-vms
+# copy tiffconf.h-vms tiffconf.h
+
+tif_aux.obj : tif_aux.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_close.obj : tif_close.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_codec.obj : tif_codec.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_color.obj : tif_color.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_compress.obj : tif_compress.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_dir.obj : tif_dir.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_dirinfo.obj : tif_dirinfo.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_dirread.obj : tif_dirread.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_dirwrite.obj : tif_dirwrite.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_dumpmode.obj : tif_dumpmode.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_error.obj : tif_error.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_extension.obj : tif_extension.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_fax3.obj : tif_fax3.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_fax3sm.obj : tif_fax3sm.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_flush.obj : tif_flush.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_getimage.obj : tif_getimage.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_jbig.obj : tif_jbig.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_jpeg.obj : tif_jpeg.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_luv.obj : tif_luv.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_lzw.obj : tif_lzw.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_next.obj : tif_next.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_ojpeg.obj : tif_ojpeg.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_open.obj : tif_open.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_packbits.obj : tif_packbits.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_pixarlog.obj : tif_pixarlog.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_predict.obj : tif_predict.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_print.obj : tif_print.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_read.obj : tif_read.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_strip.obj : tif_strip.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_swab.obj : tif_swab.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_thunder.obj : tif_thunder.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_tile.obj : tif_tile.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_unix.obj : tif_unix.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_version.obj : tif_version.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_warning.obj : tif_warning.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_write.obj : tif_write.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tif_zip.obj : tif_zip.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+
+clean :
+ del *.obj;*
+ del *.olb;*
+$!
+$!
+$!
+$COPY SYS$INPUT [.TOOLS]DESCRIP.MMS
+# (c) Alexey Chupahin 22-NOV-2007
+# OpenVMS 7.3-1, DEC 2000 mod.300
+# OpenVMS 8.3, HP rx1620
+
+INCL = /INCL=([],[-.LIBTIFF])
+CFLAGS = $(INCL)
+LIBS = [-]OPT/OPT
+
+OBJ=\
+bmp2tiff.exe,\
+fax2ps.exe,\
+fax2tiff.exe,\
+gif2tiff.exe,\
+pal2rgb.exe,\
+ppm2tiff.exe,\
+ras2tiff.exe,\
+raw2tiff.exe,\
+rgb2ycbcr.exe,\
+thumbnail.exe,\
+tiff2bw.exe,\
+tiff2pdf.exe,\
+tiff2ps.exe,\
+tiff2rgba.exe,\
+tiffcmp.exe,\
+tiffcp.exe,\
+tiffcrop.exe,\
+tiffdither.exe,\
+tiffdump.exe,\
+tiffinfo.exe,\
+tiffmedian.exe,\
+tiffset.exe,\
+tiffsplit.exe,\
+ycbcr.exe
+
+
+all : $(OBJ)
+ $!
+
+bmp2tiff.obj : bmp2tiff.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+bmp2tiff.exe : bmp2tiff.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+fax2ps.obj : fax2ps.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+fax2ps.exe : fax2ps.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+fax2tiff.obj : fax2tiff.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+fax2tiff.exe : fax2tiff.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+gif2tiff.obj : gif2tiff.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+gif2tiff.exe : gif2tiff.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+pal2rgb.obj : pal2rgb.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+pal2rgb.exe : pal2rgb.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+ppm2tiff.obj : ppm2tiff.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+ppm2tiff.exe : ppm2tiff.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+ras2tiff.obj : ras2tiff.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+ras2tiff.exe : ras2tiff.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+raw2tiff.obj : raw2tiff.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+raw2tiff.exe : raw2tiff.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+rgb2ycbcr.obj : rgb2ycbcr.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+rgb2ycbcr.exe : rgb2ycbcr.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+sgi2tiff.obj : sgi2tiff.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+sgi2tiff.exe : sgi2tiff.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+sgisv.obj : sgisv.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+sgisv.exe : sgisv.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+thumbnail.obj : thumbnail.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+thumbnail.exe : thumbnail.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiff2bw.obj : tiff2bw.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiff2bw.exe : tiff2bw.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiff2pdf.obj : tiff2pdf.c
+ $(CC) $(CFLAGS) /NOWARN $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiff2pdf.exe : tiff2pdf.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiff2ps.obj : tiff2ps.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiff2ps.exe : tiff2ps.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiff2rgba.obj : tiff2rgba.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiff2rgba.exe : tiff2rgba.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffcmp.obj : tiffcmp.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffcmp.exe : tiffcmp.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffcp.obj : tiffcp.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffcp.exe : tiffcp.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffcrop.obj : tiffcrop.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffcrop.exe : tiffcrop.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffdither.obj : tiffdither.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffdither.exe : tiffdither.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffdump.obj : tiffdump.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffdump.exe : tiffdump.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffgt.obj : tiffgt.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffgt.exe : tiffgt.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffinfo.obj : tiffinfo.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffinfo.exe : tiffinfo.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffmedian.obj : tiffmedian.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffmedian.exe : tiffmedian.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffset.obj : tiffset.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffset.exe : tiffset.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+tiffsplit.obj : tiffsplit.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+tiffsplit.exe : tiffsplit.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+ycbcr.obj : ycbcr.c
+ $(CC) $(CFLAGS) $(MMS$SOURCE) /OBJ=$(MMS$TARGET)
+
+ycbcr.exe : ycbcr.obj
+ LINK/EXE=$(MMS$TARGET) $(MMS$SOURCE), $(LIBS)
+
+
+CLEAN :
+ DEL ALL.;*
+ DEL *.OBJ;*
+ DEL *.EXE;*
+
+$!
+$!
+$!
+$!copiing and patching TIFF_CONF.H, TIF_CONFIG.H
+$!
+$CURRENT = F$ENVIRONMENT (""DEFAULT"")
+$CURRENT[F$LOCATE("]",CURRENT),9]:=".LIBTIFF]"
+$WRITE SYS$OUTPUT "Creating TIFFCONF.H and TIF_CONFIG.H"
+$COPY SYS$INPUT 'CURRENT'TIFFCONF.H
+/*
+ Configuration defines for installed libtiff.
+ This file maintained for backward compatibility. Do not use definitions
+ from this file in your programs.
+*/
+
+#ifndef _TIFFCONF_
+#define _TIFFCONF_
+
+/* Define to 1 if the system has the type `int16'. */
+//#define HAVE_INT16
+
+/* Define to 1 if the system has the type `int32'. */
+//#define HAVE_INT32
+
+/* Define to 1 if the system has the type `int8'. */
+//#define HAVE_INT8
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* Compatibility stuff. */
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+
+#ifdef __IEEE_FLOAT
+#define HAVE_IEEEFP 1
+#endif
+
+#define HAVE_GETOPT 1
+
+/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
+ (Intel) */
+#define HOST_BIGENDIAN 0
+
+/* Support CCITT Group 3 & 4 algorithms */
+#define CCITT_SUPPORT 1
+
+/* Support LogLuv high dynamic range encoding */
+#define LOGLUV_SUPPORT 1
+
+/* Support LZW algorithm */
+#define LZW_SUPPORT 1
+
+/* Support NeXT 2-bit RLE algorithm */
+#define NEXT_SUPPORT 1
+
+/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation
+ fails with unpatched IJG JPEG library) */
+
+/* Support Macintosh PackBits algorithm */
+#define PACKBITS_SUPPORT 1
+
+/* Support Pixar log-format algorithm (requires Zlib) */
+#define PIXARLOG_SUPPORT 1
+
+/* Support ThunderScan 4-bit RLE algorithm */
+#define THUNDER_SUPPORT 1
+
+/* Support Deflate compression */
+/* #undef ZIP_SUPPORT */
+
+/* Support strip chopping (whether or not to convert single-strip uncompressed
+ images to mutiple strips of ~8Kb to reduce memory usage) */
+#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP
+
+/* Enable SubIFD tag (330) support */
+#define SUBIFD_SUPPORT 1
+
+/* Treat extra sample as alpha (default enabled). The RGBA interface will
+ treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+ packages produce RGBA files but don't mark the alpha properly. */
+#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1
+
+/* Pick up YCbCr subsampling info from the JPEG data stream to support files
+ lacking the tag (default enabled). */
+#define CHECK_JPEG_YCBCR_SUBSAMPLING 1
+
+/*
+ * Feature support definitions.
+ * XXX: These macros are obsoleted. Don't use them in your apps!
+ * Macros stays here for backward compatibility and should be always defined.
+ */
+#define COLORIMETRY_SUPPORT
+#define YCBCR_SUPPORT
+#define CMYK_SUPPORT
+#define ICC_SUPPORT
+#define PHOTOSHOP_SUPPORT
+#define IPTC_SUPPORT
+
+#endif /* _TIFFCONF_ */
+
+
+$COPY SYS$INPUT 'CURRENT'TIF_CONFIG.H
+/* Define to 1 if you have the <assert.h> header file. */
+
+#ifndef HAVE_GETOPT
+# define HAVE_GETOPT 1
+#endif
+
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+
+#ifdef __IEEE_FLOAT
+#define HAVE_IEEEFP 1
+#endif
+
+#define HAVE_UNISTD_H 1
+
+#define HAVE_STRING_H 1
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <io.h> header file. */
+//#define HAVE_IO_H 1
+
+/* Define to 1 if you have the <search.h> header file. */
+//#define HAVE_SEARCH_H 1
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* Set the native cpu bit order */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+/*
+#ifndef __cplusplus
+# ifndef inline
+# define inline __inline
+# endif
+#endif
+*/
+
+/* Support CCITT Group 3 & 4 algorithms */
+#define CCITT_SUPPORT 1
+
+/* Pick up YCbCr subsampling info from the JPEG data stream to support files
+ lacking the tag (default enabled). */
+#define CHECK_JPEG_YCBCR_SUBSAMPLING 1
+/* Support C++ stream API (requires C++ compiler) */
+#define CXX_SUPPORT 1
+
+/* Treat extra sample as alpha (default enabled). The RGBA interface will
+ treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+ packages produce RGBA files but don't mark the alpha properly. */
+#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1
+
+/* little Endian */
+#define HOST_BIGENDIAN 0
+#define JPEG_SUPPORT 1
+#define LOGLUV_SUPPORT 1
+/* Support LZW algorithm */
+#define LZW_SUPPORT 1
+
+/* Support Microsoft Document Imaging format */
+#define MDI_SUPPORT 1
+
+/* Support NeXT 2-bit RLE algorithm */
+#define NEXT_SUPPORT 1
+#define OJPEG_SUPPORT 1
+
+/* Name of package */
+#define PACKAGE "tiff"
+
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "tiff@lists.maptools.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "LibTIFF Software"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "LibTIFF Software 3.9.0 for VMS"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "tiff"
+
+$PURGE 'CURRENT'TIFFCONF.H
+$PURGE 'CURRENT'TIF_CONFIG.H
+$OPEN/APPEND OUT 'CURRENT'TIF_CONFIG.H
+$IF HAVE_LFIND.EQ.1
+$ THEN
+$ WRITE OUT "#define HAVE_SEARCH_H 1"
+$ ELSE
+$ WRITE OUT "#undef HAVE_SEARCH_H"
+$ENDIF
+$CLOSE OUT
+$!
+$!
+$WRITE SYS$OUTPUT " "
+$WRITE SYS$OUTPUT " "
+$WRITE SYS$OUTPUT "Now you can type @BUILD "
+$!
+$EXIT:
+$DEFINE SYS$ERROR _NLA0:
+$DEFINE SYS$OUTPUT _NLA0:
+$DEL TEST.OBJ;*
+$DEL TEST.C;*
+$DEL TEST.EXE;*
+$DEAS SYS$ERROR
+$DEAS SYS$OUTPUT
diff --git a/tiff/contrib/Makefile.am b/tiff/contrib/Makefile.am
new file mode 100644
index 0000000..574b67b
--- /dev/null
+++ b/tiff/contrib/Makefile.am
@@ -0,0 +1,29 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = README
+
+SUBDIRS = acorn addtiffo dbs iptcutil mac-cw mac-mpw mfs pds ras stream tags win_dib
+
diff --git a/tiff/contrib/Makefile.in b/tiff/contrib/Makefile.in
new file mode 100644
index 0000000..3a7bb9d
--- /dev/null
+++ b/tiff/contrib/Makefile.in
@@ -0,0 +1,623 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = README
+SUBDIRS = acorn addtiffo dbs iptcutil mac-cw mac-mpw mfs pds ras stream tags win_dib
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ ctags ctags-recursive distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/README b/tiff/contrib/README
new file mode 100644
index 0000000..26b7c5f
--- /dev/null
+++ b/tiff/contrib/README
@@ -0,0 +1,2 @@
+This directory contains various contributions from libtiff users.
+
diff --git a/tiff/contrib/acorn/Makefile.acorn b/tiff/contrib/acorn/Makefile.acorn
new file mode 100644
index 0000000..8f01477
--- /dev/null
+++ b/tiff/contrib/acorn/Makefile.acorn
@@ -0,0 +1,165 @@
+# Project: LibTIFF
+
+
+# Toolflags:
+CCflags = -c -zo -ffah -depend !Depend -IC:
+C++flags = -c -depend !Depend -IC: -throwback
+Linkflags = -aif -c++ -o $@
+DrLinkflags = -nounused -aif -c++ -o $@
+ObjAsmflags = -throwback -NoCache -depend !Depend
+CMHGflags =
+LibFileflags = -c -o $@
+Squeezeflags = -o $@
+
+
+# Final targets:
+@.o.LIBTIFF: \
+ @.o.tif_acorn \
+ @.o.tif_aux \
+ @.o.tif_close \
+ @.o.tif_codec \
+ @.o.tif_compress \
+ @.o.tif_dir \
+ @.o.tif_dirinfo \
+ @.o.tif_dirread \
+ @.o.tif_dirwrite \
+ @.o.tif_dumpmode \
+ @.o.tif_error \
+ @.o.tif_fax3 \
+ @.o.tif_flush \
+ @.o.tif_getimage \
+ @.o.tif_jpeg \
+ @.o.tif_lzw \
+ @.o.tif_next \
+ @.o.tif_open \
+ @.o.tif_packbits \
+ @.o.tif_predict \
+ @.o.tif_print \
+ @.o.tif_read \
+ @.o.tif_strip \
+ @.o.tif_swab \
+ @.o.tif_thunder \
+ @.o.tif_tile \
+ @.o.tif_version \
+ @.o.tif_warning \
+ @.o.tif_write \
+ @.o.tif_zip \
+ @.o.tif_fax3sm \
+ @.h.version
+ LibFile $(LibFileflags) \
+ @.o.tif_acorn \
+ @.o.tif_aux \
+ @.o.tif_close \
+ @.o.tif_codec \
+ @.o.tif_compress \
+ @.o.tif_dir \
+ @.o.tif_dirinfo \
+ @.o.tif_dirread \
+ @.o.tif_dirwrite \
+ @.o.tif_dumpmode \
+ @.o.tif_error \
+ @.o.tif_fax3 \
+ @.o.tif_flush \
+ @.o.tif_getimage \
+ @.o.tif_jpeg \
+ @.o.tif_lzw \
+ @.o.tif_next \
+ @.o.tif_open \
+ @.o.tif_packbits \
+ @.o.tif_predict \
+ @.o.tif_print \
+ @.o.tif_read \
+ @.o.tif_strip \
+ @.o.tif_swab \
+ @.o.tif_thunder \
+ @.o.tif_tile \
+ @.o.tif_version \
+ @.o.tif_warning \
+ @.o.tif_write \
+ @.o.tif_zip \
+ @.o.tif_fax3sm
+
+
+# User-editable dependencies:
+@.mkversion: @.o.mkversion C:o.Stubs
+ Link $(linkflags) @.o.mkversion C:o.Stubs
+@.h.version: @.VERSION @.mkversion
+ <Prefix$Dir>.mkversion -v @.VERSION -a @.tiff/alpha @.h.version
+@.mkg3states: @.o.mkg3states @.o.getopt C:o.Stubs
+ link $(linkflags) @.o.mkg3states C:o.Stubs @.o.getopt
+@.c.tif_fax3sm: @.mkg3states
+ <Prefix$Dir>.mkg3states -c const @.c.tif_fax3sm
+
+# Static dependencies:
+@.o.tif_acorn: @.c.tif_acorn
+ cc $(ccflags) -o @.o.tif_acorn @.c.tif_acorn
+@.o.tif_aux: @.c.tif_aux
+ cc $(ccflags) -o @.o.tif_aux @.c.tif_aux
+@.o.tif_close: @.c.tif_close
+ cc $(ccflags) -o @.o.tif_close @.c.tif_close
+@.o.tif_codec: @.c.tif_codec
+ cc $(ccflags) -o @.o.tif_codec @.c.tif_codec
+@.o.tif_compress: @.c.tif_compress
+ cc $(ccflags) -o @.o.tif_compress @.c.tif_compress
+@.o.tif_dir: @.c.tif_dir
+ cc $(ccflags) -o @.o.tif_dir @.c.tif_dir
+@.o.tif_dirinfo: @.c.tif_dirinfo
+ cc $(ccflags) -o @.o.tif_dirinfo @.c.tif_dirinfo
+@.o.tif_dirread: @.c.tif_dirread
+ cc $(ccflags) -o @.o.tif_dirread @.c.tif_dirread
+@.o.tif_dirwrite: @.c.tif_dirwrite
+ cc $(ccflags) -o @.o.tif_dirwrite @.c.tif_dirwrite
+@.o.tif_dumpmode: @.c.tif_dumpmode
+ cc $(ccflags) -o @.o.tif_dumpmode @.c.tif_dumpmode
+@.o.tif_error: @.c.tif_error
+ cc $(ccflags) -o @.o.tif_error @.c.tif_error
+@.o.tif_fax3: @.c.tif_fax3
+ cc $(ccflags) -o @.o.tif_fax3 @.c.tif_fax3
+@.o.tif_flush: @.c.tif_flush
+ cc $(ccflags) -o @.o.tif_flush @.c.tif_flush
+@.o.tif_getimage: @.c.tif_getimage
+ cc $(ccflags) -o @.o.tif_getimage @.c.tif_getimage
+@.o.tif_jpeg: @.c.tif_jpeg
+ cc $(ccflags) -o @.o.tif_jpeg @.c.tif_jpeg
+@.o.tif_lzw: @.c.tif_lzw
+ cc $(ccflags) -o @.o.tif_lzw @.c.tif_lzw
+@.o.tif_next: @.c.tif_next
+ cc $(ccflags) -o @.o.tif_next @.c.tif_next
+@.o.tif_open: @.c.tif_open
+ cc $(ccflags) -o @.o.tif_open @.c.tif_open
+@.o.tif_packbits: @.c.tif_packbits
+ cc $(ccflags) -o @.o.tif_packbits @.c.tif_packbits
+@.o.tif_predict: @.c.tif_predict
+ cc $(ccflags) -o @.o.tif_predict @.c.tif_predict
+@.o.tif_print: @.c.tif_print
+ cc $(ccflags) -o @.o.tif_print @.c.tif_print
+@.o.tif_read: @.c.tif_read
+ cc $(ccflags) -o @.o.tif_read @.c.tif_read
+@.o.tif_strip: @.c.tif_strip
+ cc $(ccflags) -o @.o.tif_strip @.c.tif_strip
+@.o.tif_swab: @.c.tif_swab
+ cc $(ccflags) -o @.o.tif_swab @.c.tif_swab
+@.o.tif_thunder: @.c.tif_thunder
+ cc $(ccflags) -o @.o.tif_thunder @.c.tif_thunder
+@.o.tif_tile: @.c.tif_tile
+ cc $(ccflags) -o @.o.tif_tile @.c.tif_tile
+@.o.tif_version: @.c.tif_version
+ cc $(ccflags) -o @.o.tif_version @.c.tif_version
+@.o.tif_warning: @.c.tif_warning
+ cc $(ccflags) -o @.o.tif_warning @.c.tif_warning
+@.o.tif_write: @.c.tif_write
+ cc $(ccflags) -o @.o.tif_write @.c.tif_write
+@.o.tif_zip: @.c.tif_zip
+ cc $(ccflags) -o @.o.tif_zip @.c.tif_zip
+@.o.mkg3states: @.c.mkg3states
+ cc $(ccflags) -o @.o.mkg3states @.c.mkg3states
+@.o.getopt: @.c.getopt
+ cc $(ccflags) -o @.o.getopt @.c.getopt
+@.o.mkspans: @.c.mkspans
+ cc $(ccflags) -o @.o.mkspans @.c.mkspans
+@.o.tif_fax3sm: @.c.tif_fax3sm
+ cc $(ccflags) -o @.o.tif_fax3sm @.c.tif_fax3sm
+@.o.mkversion: @.c.mkversion
+ cc $(ccflags) -o @.o.mkversion @.c.mkversion
+
+# Dynamic dependencies:
diff --git a/tiff/contrib/acorn/Makefile.am b/tiff/contrib/acorn/Makefile.am
new file mode 100644
index 0000000..ca2b132
--- /dev/null
+++ b/tiff/contrib/acorn/Makefile.am
@@ -0,0 +1,28 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = Makefile.acorn ReadMe SetVars cleanlib convert install
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
diff --git a/tiff/contrib/acorn/Makefile.in b/tiff/contrib/acorn/Makefile.in
new file mode 100644
index 0000000..593bda9
--- /dev/null
+++ b/tiff/contrib/acorn/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/acorn
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = Makefile.acorn ReadMe SetVars cleanlib convert install
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/acorn/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/acorn/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/acorn/ReadMe b/tiff/contrib/acorn/ReadMe
new file mode 100644
index 0000000..dc16a79
--- /dev/null
+++ b/tiff/contrib/acorn/ReadMe
@@ -0,0 +1,79 @@
+Building the Software on an Acorn RISC OS system
+
+The directory contrib/acorn contains support for compiling the library under
+Acorn C/C++ under Acorn's RISC OS 3.10 or above. Subsequent pathnames will
+use the Acorn format: The full-stop or period character is a pathname
+delimeter, and the slash character is not interpreted; the reverse position
+from Unix. Thus "libtiff/tif_acorn.c" becomes "libtiff.tif_acorn/c".
+
+This support was contributed by Peter Greenham.
+(peterg@angmulti.demon.co.uk).
+
+Installing LibTIFF:
+
+LIBTIFF uses several files which have names longer than the normal RISC OS
+maximum of ten characters. This complicates matters. Maybe one day Acorn will
+address the problem and implement long filenames properly. Until then this
+gets messy, especially as I'm trying to do this with obeyfiles and not have
+to include binaries in this distribution.
+
+First of all, ensure you have Truncate configured on (type *Configure
+Truncate On) Although it is, of course, preferable to have long filenames,
+LIBTIFF can be installed with short filenames, and it will compile and link
+without problems. However, getting it there is more problematic.
+contrib.acorn.install is an installation obeyfile which will create a normal
+Acorn-style library from the source (ie: with c, h and o folders etc.), but
+needs the distribution library to have been unpacked into a location which is
+capable of supporting long filenames, even if only temporarily.
+
+My recommendation, until Acorn address this problem properly, is to use Jason
+Tribbeck's LongFilenames , or any other working system that gives you long
+filenames, like a nearby NFS server for instance.
+
+If you are using Longfilenames, even if only temporarily to install LIBTIFF,
+unpack the TAR into a RAMDisc which has been longfilenamed (ie: *addlongfs
+ram) and then install from there to the hard disk. Unfortunately
+Longfilenames seems a bit unhappy about copying a bunch of long-named files
+across the same filing system, but is happy going between systems. You'll
+need to create a ramdisk of about 2Mb.
+
+Now you can run the installation script I've supplied (in contrib.acorn),
+which will automate the process of installing LIBTIFF as an Acorn-style
+library. The syntax is as follows:
+
+install <source_dir> <dest_dir>
+
+Install will then create <dest_dir> and put the library in there. For
+example, having used LongFilenames on the RAMDisk and unpacked the library
+into there, you can then type:
+
+Obey RAM::RamDisc0.$.contrib.acorn.install RAM::RamDisc0.$ ADFS::4.$.LIBTIFF
+
+It doesn't matter if the destination location can cope with long filenames or
+not. The filenames will be truncated if necessary (*Configure Truncate On if
+you get errors) and all will be well.
+
+Compiling LibTIFF:
+
+Once the LibTIFF folder has been created and the files put inside, making the
+library should be just a matter of running 'SetVars' to set the appropriate
+system variables, then running 'Makefile'.
+
+OSLib
+
+OSLib is a comprehensive API for RISC OS machines, written by Jonathan
+Coxhead of Acorn Computers (although OSLib is not an official Acorn product).
+Using the OSLib SWI veneers produces code which is more compact and more
+efficient than code written using _kernel_swi or _swi. The Acorn port of
+LibTIFF can take advantage of this if present. Edit the Makefile and go to
+the Static dependencies section. The first entry is:
+
+# Static dependencies:
+@.o.tif_acorn: @.c.tif_acorn
+ cc $(ccflags) -o @.o.tif_acorn @.c.tif_acorn
+Change the cc line to:
+
+ cc $(ccflags) -DINCLUDE_OSLIB -o @.o.tif_acorn @.c.tif_acorn
+
+Remember, however, that OSLib is only recommended for efficiency's sake. It
+is not required.
diff --git a/tiff/contrib/acorn/SetVars b/tiff/contrib/acorn/SetVars
new file mode 100644
index 0000000..ea12d71
--- /dev/null
+++ b/tiff/contrib/acorn/SetVars
@@ -0,0 +1,3 @@
+Set LibTIFF$Dir <Obey$Dir>
+Set LibTIFF$Path <LibTIFF$Dir>.
+Set C$Path <C$Path>,LibTIFF:
diff --git a/tiff/contrib/acorn/cleanlib b/tiff/contrib/acorn/cleanlib
new file mode 100644
index 0000000..78a2d03
--- /dev/null
+++ b/tiff/contrib/acorn/cleanlib
@@ -0,0 +1,5 @@
+IfThere LibTIFF:o.* THEN Wipe LibTIFF:o.* ~CFR~V
+IfThere LibTIFF:c.tif_fax3sm THEN Delete LibTIFF:c.tif_fax3sm
+IfThere LibTIFF:mkg3states THEN Delete LibTIFF:mkg3states
+IfThere LibTIFF:h.version THEN Delete LibTIFF:h.version
+IfThere LibTIFF:mkversion THEN Delete LibTIFF:mkversion
diff --git a/tiff/contrib/acorn/convert b/tiff/contrib/acorn/convert
new file mode 100644
index 0000000..1f64ed2
--- /dev/null
+++ b/tiff/contrib/acorn/convert
@@ -0,0 +1,175 @@
+RISC OS Conversion log
+======================
+
+mkversion.c
+~~~~~~~~~~~
+The RISC OS command-line does not allow the direct creation of the version.h
+file in the proper manner. To remedy this in such a way that the version
+header is made at compiletime, I wrote this small program. It is fully
+portable, so should work quite happily for any other platform that might need
+it.
+
+msg3states.c
+~~~~~~~~~~~~
+Needed getopt.c from the port folder, then compiled and worked fine.
+
+
+tiff.h
+~~~~~~
+
+====1====
+
+The symbol _MIPS_SZLONG, if not defined, causes a compiler error. Fixed by
+ensuring it does exist. This looks to me like this wouldn't be an
+Acorn-specific problem. The new code fragment is as follows:
+
+#ifndef _MIPS_SZLONG
+#define _MIPS_SZLONG 32
+#endif
+#if defined(__alpha) || _MIPS_SZLONG == 64
+
+
+
+tiffcomp.h
+~~~~~~~~~~
+
+====1====
+
+#if !defined(__MWERKS__) && !defined(THINK_C)
+#include <sys/types.h>
+#endif
+
+Acorn also doesn't have this header so:
+
+#if !defined(__MWERKS__) && !defined(THINK_C) && !defined(__acorn)
+#include <sys/types.h>
+#endif
+
+====2====
+
+#ifdef VMS
+#include <file.h>
+#include <unixio.h>
+#else
+#include <fcntl.h>
+#endif
+
+This seems to indicate that fcntl.h is included on all systems except
+VMS. Odd, because I've never heard of it before. Sure it's in the ANSI
+definition? Anyway, following change:
+
+#ifdef VMS
+#include <file.h>
+#include <unixio.h>
+#else
+#ifndef __acorn
+#include <fcntl.h>
+#endif
+#endif
+
+This will probably change when I find out what it wants from fcntl.h!
+
+====3====
+
+#if defined(__MWERKS__) || defined(THINK_C) || defined(applec)
+#include <stdlib.h>
+#define BSDTYPES
+#endif
+
+Added RISC OS to above thus:
+
+#if defined(__MWERKS__) || defined(THINK_C) || defined(applec) || defined(__acorn)
+#include <stdlib.h>
+#define BSDTYPES
+#endif
+
+====4====
+
+/*
+ * The library uses the ANSI C/POSIX SEEK_*
+ * definitions that should be defined in unistd.h
+ * (except on VMS where they are in stdio.h and
+ * there is no unistd.h).
+ */
+#ifndef SEEK_SET
+#if !defined(VMS) && !defined (applec) && !defined(THINK_C) && !defined(__MWERKS__)
+#include <unistd.h>
+#endif
+
+RISC OS is like VMS and Mac in this regard. So changed to:
+
+/*
+ * The library uses the ANSI C/POSIX SEEK_*
+ * definitions that should be defined in unistd.h
+ * (except on VMS or the Mac or RISC OS, where they are in stdio.h and
+ * there is no unistd.h).
+ */
+#ifndef SEEK_SET
+#if !defined(VMS) && !defined (applec) && !defined(THINK_C) && !defined(__MWERKS__) && !defined(__acorn)
+#include <unistd.h>
+#endif
+#endif
+
+====5====
+
+NB: HAVE_IEEEFP is defined in tiffconf.h, not tiffcomp.h as mentioned
+in libtiff.README. (Note written on original port from 3.4beta004)
+
+Acorn C/C++ claims to accord with IEEE 754, so no change (yet) to
+tiffconf.h.
+
+====6====
+
+Unsure about whether this compiler supports inline functions. Will
+leave it on for the time being and see if it works! (Likely if
+everything else does.)
+
+... Seems to be OK ...
+
+====7====
+
+Added to the end:
+
+/*
+ * osfcn.h is part of C++Lib on Acorn C/C++, and as such can't be used
+ * on C alone. For that reason, the relevant functions have been
+ * implemented by myself in tif_acorn.c, and the elements from the header
+ * included here.
+ */
+
+#ifdef __acorn
+#ifdef __cplusplus
+#include <osfcn.h>
+#else
+#include "kernel.h"
+#define O_RDONLY 0
+#define O_WRONLY 1
+#define O_RDWR 2
+#define O_APPEND 8
+#define O_CREAT 0x200
+#define O_TRUNC 0x400
+typedef long off_t;
+extern int open(const char *name, int flags, int mode);
+extern int close(int fd);
+extern int write(int fd, const char *buf, int nbytes);
+extern int read(int fd, char *buf, int nbytes);
+extern off_t lseek(int fd, off_t offset, int whence);
+#endif
+#endif
+
+
+===============================================================================
+
+tif_acorn.c
+~~~~~~~~~~~
+
+Created file tif_acorn.c, copied initially from tif_unix.c
+
+Documented internally where necessary.
+
+Note that I have implemented the low-level file-handling functions normally
+found in osfcn.h in here, and put the header info at the bottom of
+tiffcomp.h. This is further documented from a RISC OS perspective inside the
+file.
+
+===============================================================================
diff --git a/tiff/contrib/acorn/install b/tiff/contrib/acorn/install
new file mode 100644
index 0000000..fa49d1b
--- /dev/null
+++ b/tiff/contrib/acorn/install
@@ -0,0 +1,128 @@
+If "%0" = "" Then Error Syntax: install |<source_dir> |<dest_dir>
+If "%1" = "" Then Error Syntax: install |<source_dir> |<dest_dir>
+Set LibTiffInstall$Dir %0
+Set LibTiff$Dir %1
+Set Alias$CPY Copy <LibTiffInstall$Dir>.%%0 <LibTiff$Dir>.%%1 ~C~DF~NRV
+CDir <LibTiff$Dir>
+CDir <LibTiff$Dir>.c
+CDir <LibTiff$Dir>.h
+CDir <LibTiff$Dir>.o
+CPY COPYRIGHT COPYRIGHT
+CPY README README
+CPY VERSION VERSION
+CPY dist.tiff/alpha tiff/alpha
+CPY contrib.acorn.SetVars SetVars
+CPY contrib.acorn.Makefile Makefile
+CPY contrib.acorn.cleanlib cleanlib
+CPY port.getopt/c c.getopt
+CPY libtiff.mkg3states/c c.mkg3states
+CPY libtiff.mkspans/c c.mkspans
+CPY libtiff.mkversion/c c.mkversion
+CPY libtiff.tif_acorn/c c.tif_acorn
+CPY libtiff.tif_aux/c c.tif_aux
+CPY libtiff.tif_close/c c.tif_close
+CPY libtiff.tif_codec/c c.tif_codec
+CPY libtiff.tif_compress/c c.tif_compre
+CPY libtiff.tif_dir/c c.tif_dir
+CPY libtiff.tif_dirinfo/c c.tif_dirinf
+CPY libtiff.tif_dirread/c c.tif_dirrea
+CPY libtiff.tif_dirwrite/c c.tif_dirwri
+CPY libtiff.tif_dumpmode/c c.tif_dumpmo
+CPY libtiff.tif_error/c c.tif_error
+CPY libtiff.tif_fax3/c c.tif_fax3
+CPY libtiff.tif_flush/c c.tif_flush
+CPY libtiff.tif_getimage/c c.tif_getima
+CPY libtiff.tif_jpeg/c c.tif_jpeg
+CPY libtiff.tif_lzw/c c.tif_lzw
+CPY libtiff.tif_next/c c.tif_next
+CPY libtiff.tif_open/c c.tif_open
+CPY libtiff.tif_packbits/c c.tif_packbi
+CPY libtiff.tif_predict/c c.tif_predic
+CPY libtiff.tif_print/c c.tif_print
+CPY libtiff.tif_read/c c.tif_read
+CPY libtiff.tif_strip/c c.tif_strip
+CPY libtiff.tif_swab/c c.tif_swab
+CPY libtiff.tif_thunder/c c.tif_thunde
+CPY libtiff.tif_tile/c c.tif_tile
+CPY libtiff.tif_version/c c.tif_versio
+CPY libtiff.tif_warning/c c.tif_warnin
+CPY libtiff.tif_write/c c.tif_write
+CPY libtiff.tif_zip/c c.tif_zip
+CPY libtiff.t4/h h.t4
+CPY libtiff.tiff/h h.tiff
+CPY libtiff.tiffcomp/h h.tiffcomp
+CPY libtiff.tiffconf/h h.tiffconf
+CPY libtiff.tiffio/h h.tiffio
+CPY libtiff.tiffiop/h h.tiffiop
+CPY libtiff.tif_dir/h h.tif_dir
+CPY libtiff.tif_fax3/h h.tif_fax3
+CPY libtiff.tif_predict/h h.tif_predic
+SetType <LibTiff$Dir>.COPYRIGHT Text
+SetType <LibTiff$Dir>.README Text
+SetType <LibTiff$Dir>.VERSION Text
+SetType <LibTiff$Dir>.tiff/alpha Text
+SetType <LibTiff$Dir>.SetVars Obey
+SetType <LibTiff$Dir>.Makefile fe1
+SetType <LibTiff$Dir>.cleanlib Obey
+SetType <LibTiff$Dir>.c.getopt Text
+SetType <LibTiff$Dir>.c.mkg3states Text
+SetType <LibTiff$Dir>.c.mkspans Text
+SetType <LibTiff$Dir>.c.mkversion Text
+SetType <LibTiff$Dir>.c.tif_acorn Text
+SetType <LibTiff$Dir>.c.tif_aux Text
+SetType <LibTiff$Dir>.c.tif_close Text
+SetType <LibTiff$Dir>.c.tif_codec Text
+SetType <LibTiff$Dir>.c.tif_compre Text
+SetType <LibTiff$Dir>.c.tif_dir Text
+SetType <LibTiff$Dir>.c.tif_dirinf Text
+SetType <LibTiff$Dir>.c.tif_dirrea Text
+SetType <LibTiff$Dir>.c.tif_dirwri Text
+SetType <LibTiff$Dir>.c.tif_dumpmo Text
+SetType <LibTiff$Dir>.c.tif_error Text
+SetType <LibTiff$Dir>.c.tif_fax3 Text
+SetType <LibTiff$Dir>.c.tif_flush Text
+SetType <LibTiff$Dir>.c.tif_getima Text
+SetType <LibTiff$Dir>.c.tif_jpeg Text
+SetType <LibTiff$Dir>.c.tif_lzw Text
+SetType <LibTiff$Dir>.c.tif_next Text
+SetType <LibTiff$Dir>.c.tif_open Text
+SetType <LibTiff$Dir>.c.tif_packbi Text
+SetType <LibTiff$Dir>.c.tif_predic Text
+SetType <LibTiff$Dir>.c.tif_print Text
+SetType <LibTiff$Dir>.c.tif_read Text
+SetType <LibTiff$Dir>.c.tif_strip Text
+SetType <LibTiff$Dir>.c.tif_swab Text
+SetType <LibTiff$Dir>.c.tif_thunde Text
+SetType <LibTiff$Dir>.c.tif_tile Text
+SetType <LibTiff$Dir>.c.tif_versio Text
+SetType <LibTiff$Dir>.c.tif_warnin Text
+SetType <LibTiff$Dir>.c.tif_write Text
+SetType <LibTiff$Dir>.c.tif_zip Text
+SetType <LibTiff$Dir>.h.t4 Text
+SetType <LibTiff$Dir>.h.tiff Text
+SetType <LibTiff$Dir>.h.tiffcomp Text
+SetType <LibTiff$Dir>.h.tiffconf Text
+SetType <LibTiff$Dir>.h.tiffio Text
+SetType <LibTiff$Dir>.h.tiffiop Text
+SetType <LibTiff$Dir>.h.tif_dir Text
+SetType <LibTiff$Dir>.h.tif_fax3 Text
+SetType <LibTiff$Dir>.h.tif_predic Text
+Unset Alias$CPY
+Unset LibTiffInstall$Dir
+| Now attempt to restore longfilename status. If it causes an error, OK.
+Set Alias$RN Rename <LibTiff$Dir>.%%0 <LibTiff$Dir>.%%1
+Unset LibTiff$Dir
+RN c.tif_compre c.tif_compress
+RN c.tif_dirinf c.tif_dirinfo
+RN c.tif_dirrea c.tif_dirread
+RN c.tif_dirwri c.tif_dirwrite
+RN c.tif_dumpmo c.tif_dumpmode
+RN c.tif_getima c.tif_getimage
+RN c.tif_packbi c.tif_packbits
+RN c.tif_predic c.tif_predict
+RN c.tif_thunde c.tif_thunder
+RN c.tif_versio c.tif_version
+RN c.tif_warnin c.tif_warning
+RN h.tif_predic h.tif_predict
+Unset Alias$RN
+Echo All done!
diff --git a/tiff/contrib/addtiffo/Makefile.am b/tiff/contrib/addtiffo/Makefile.am
new file mode 100644
index 0000000..f3158ef
--- /dev/null
+++ b/tiff/contrib/addtiffo/Makefile.am
@@ -0,0 +1,36 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+
+EXTRA_DIST = README Makefile.vc
+
+noinst_PROGRAMS = addtiffo
+
+addtiffo_SOURCES = addtiffo.c tif_overview.c tif_ovrcache.c tif_ovrcache.h
+addtiffo_LDADD = $(LIBTIFF)
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+
diff --git a/tiff/contrib/addtiffo/Makefile.in b/tiff/contrib/addtiffo/Makefile.in
new file mode 100644
index 0000000..4cf406f
--- /dev/null
+++ b/tiff/contrib/addtiffo/Makefile.in
@@ -0,0 +1,556 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+noinst_PROGRAMS = addtiffo$(EXEEXT)
+subdir = contrib/addtiffo
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am_addtiffo_OBJECTS = addtiffo.$(OBJEXT) tif_overview.$(OBJEXT) \
+ tif_ovrcache.$(OBJEXT)
+addtiffo_OBJECTS = $(am_addtiffo_OBJECTS)
+addtiffo_DEPENDENCIES = $(LIBTIFF)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libtiff
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(addtiffo_SOURCES)
+DIST_SOURCES = $(addtiffo_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+EXTRA_DIST = README Makefile.vc
+addtiffo_SOURCES = addtiffo.c tif_overview.c tif_ovrcache.c tif_ovrcache.h
+addtiffo_LDADD = $(LIBTIFF)
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/addtiffo/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/addtiffo/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+addtiffo$(EXEEXT): $(addtiffo_OBJECTS) $(addtiffo_DEPENDENCIES)
+ @rm -f addtiffo$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(addtiffo_OBJECTS) $(addtiffo_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addtiffo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_overview.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_ovrcache.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstPROGRAMS ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/addtiffo/Makefile.vc b/tiff/contrib/addtiffo/Makefile.vc
new file mode 100644
index 0000000..2777dc2
--- /dev/null
+++ b/tiff/contrib/addtiffo/Makefile.vc
@@ -0,0 +1,28 @@
+#
+# If libtiff.a is installed in /usr/lib or /usr/local/lib just point
+# LIBTIFF_DIR there. It doesn't need a full libtiff tree.
+#
+!INCLUDE ..\..\nmake.opt
+
+LIBTIFF_DIR = ..\..\libtiff
+#
+INCL = -I..\..\libtiff
+LIBS = $(LIBTIFF_DIR)\libtiff.lib
+
+addtiffo: addtiffo.obj tif_overview.obj tif_ovrcache.obj
+ $(CC) $(CFLAGS) addtiffo.obj tif_overview.obj tif_ovrcache.obj \
+ $(LIBS) /Feaddtiffo.exe
+
+
+addtiffo.obj: addtiffo.c
+ $(CC) -c $(CFLAGS) addtiffo.c
+
+tif_overview.obj: tif_overview.c
+ $(CC) -c $(CFLAGS) tif_overview.c
+
+tif_ovrcache.obj: tif_ovrcache.c
+ $(CC) -c $(CFLAGS) tif_ovrcache.c
+
+clean:
+ -del *.obj
+ -del addtiffo.exe
diff --git a/tiff/contrib/addtiffo/README b/tiff/contrib/addtiffo/README
new file mode 100644
index 0000000..a6ca45f
--- /dev/null
+++ b/tiff/contrib/addtiffo/README
@@ -0,0 +1,142 @@
+ addtiffo 1.0
+ ============
+
+The addtiffo utility is used to add overview pyramids to an existing
+TIFF or GeoTIFF file. Some applications can take advantage of these
+overviews to accelerate overview display performance of large rasters.
+
+This release of addtiffo is primarily intended for compatibility testing
+with applications, and to see if there is interest in a cleaner release
+of the capability ... perhaps incorporation into the libtiff tools
+distribution.
+
+Please feel free to contact me with questions, or problems.
+
+warmerda@home.com
+http://home.gdal.org/~warmerda/
+
+
+Usage
+-----
+
+Usage: addtiffo [-r {average/nearest} [-subifd]
+ tiff_filename [resolution_reductions]
+
+Example:
+ % addtiffo abc.tif 2 4 8 16
+
+The numeric arguments are the list of reduction factors to
+generate. In this example a 1/2, 1/4 1/8 and 1/16
+
+
+
+Limitations
+-----------
+
+See tif_overview.cpp for up to date details.
+
+ o Currently only images with bits_per_sample of a multiple of eight
+ will work.
+
+ o The code will attempt to use the same kind of compression,
+ photometric interpretation, and organization as the source image, but
+ it doesn't copy geotiff tags to the reduced resolution images.
+
+ o Reduced resolution overviews for multi-sample files will currently
+ always be generated as PLANARCONFIG_SEPARATE. This could be fixed
+ reasonable easily if needed to improve compatibility with other
+ packages. Many don't properly support PLANARCONFIG_SEPARATE.
+
+ o Overviews are always written as appended IFDs, rather than using the
+ ``tree of tree's'' approach using the SUBIFD tag. I wanted to implement
+ both, but it isn't currently easy to add a SUBIFD tag to an existing
+ main tiff IFD with libtiff. I hope to try this again later.
+
+
+TIFF File Tags
+--------------
+
+The results of running addtiffo on a 1024x1024 tiled greyscale file
+with the arguments ``2 4 8 16'' is to add four additional TIFF directories
+appended on the file with the SUBFILETYPE flag to 0x1 indicating the extra
+items are reduced resolution images.
+
+The tiffinfo output of such a file might look like this:
+
+TIFF Directory at offset 0x118008
+ Image Width: 1024 Image Length: 1024
+ Tile Width: 256 Tile Length: 112
+ Bits/Sample: 8
+ Compression Scheme: none
+ Photometric Interpretation: min-is-black
+ Samples/Pixel: 1
+ Planar Configuration: single image plane
+TIFF Directory at offset 0x15e1d2
+ Subfile Type: reduced-resolution image (1 = 0x1)
+ Image Width: 512 Image Length: 512
+ Tile Width: 256 Tile Length: 112
+ Bits/Sample: 8
+ Compression Scheme: none
+ Photometric Interpretation: min-is-black
+ Samples/Pixel: 1
+ Planar Configuration: separate image planes
+TIFF Directory at offset 0x1732b8
+ Subfile Type: reduced-resolution image (1 = 0x1)
+ Image Width: 256 Image Length: 256
+ Tile Width: 256 Tile Length: 112
+ Bits/Sample: 8
+ Compression Scheme: none
+ Photometric Interpretation: min-is-black
+ Samples/Pixel: 1
+ Planar Configuration: separate image planes
+TIFF Directory at offset 0x17a366
+ Subfile Type: reduced-resolution image (1 = 0x1)
+ Image Width: 128 Image Length: 128
+ Tile Width: 128 Tile Length: 112
+ Bits/Sample: 8
+ Compression Scheme: none
+ Photometric Interpretation: min-is-black
+ Samples/Pixel: 1
+ Planar Configuration: separate image planes
+TIFF Directory at offset 0x17b40c
+ Subfile Type: reduced-resolution image (1 = 0x1)
+ Image Width: 64 Image Length: 64
+ Tile Width: 64 Tile Length: 64
+ Bits/Sample: 8
+ Compression Scheme: none
+ Photometric Interpretation: min-is-black
+ Samples/Pixel: 1
+ Planar Configuration: separate image planes
+
+
+Building
+--------
+
+You will need a C compiler. You will need to have libtiff already
+built and installed. The provided Makefile should work on most Unix systems.
+A similar file will be needed for Windows, but is not provided.
+
+The CFLAGS and LIBS macros in the Makefile will have to be updated to
+point to the correct location of the libtiff include files, and library.
+
+
+Credits
+-------
+
+ o Intergraph Corporation for partially funding the work.
+
+ o Global Geomatics for partially funding reorganization of the overview
+ building ability as a separate utility.
+
+ o Orrin Long, and Ed Grissom of Intergraph for explaining what needed to
+ be done.
+
+ o Max Martinez of Erdas for his discussion of external overviews.
+
+ o Atlantis Scientific who supported adding averaging, and some other
+ generalizations.
+
+ o Frank Warmerdam for writing the bulk of the code.
+
+ o Sam Leffler since this only exists because of his libtiff.
+
diff --git a/tiff/contrib/addtiffo/addtiffo.c b/tiff/contrib/addtiffo/addtiffo.c
new file mode 100644
index 0000000..107df36
--- /dev/null
+++ b/tiff/contrib/addtiffo/addtiffo.c
@@ -0,0 +1,176 @@
+/******************************************************************************
+ * $Id: addtiffo.c,v 1.6.2.1 2010-06-08 18:50:40 bfriesen Exp $
+ *
+ * Project: GeoTIFF Overview Builder
+ * Purpose: Mainline for building overviews in a TIFF file.
+ * Author: Frank Warmerdam, warmerdam@pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 1999, Frank Warmerdam
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log: addtiffo.c,v $
+ * Revision 1.6.2.1 2010-06-08 18:50:40 bfriesen
+ * * Add an emacs formatting mode footer to all source files so that
+ * emacs can be effectively used.
+ *
+ * Revision 1.6 2005/12/16 05:59:55 fwarmerdam
+ * Major upgrade to support YCbCr subsampled jpeg images
+ *
+ * Revision 1.4 2004/09/21 13:31:23 dron
+ * Add missed include string.h.
+ *
+ * Revision 1.3 2000/04/18 22:48:31 warmerda
+ * Added support for averaging resampling
+ *
+ * Revision 1.2 2000/01/28 15:36:38 warmerda
+ * pass TIFF handle instead of filename to overview builder
+ *
+ * Revision 1.1 1999/08/17 01:47:59 warmerda
+ * New
+ *
+ * Revision 1.1 1999/03/12 17:46:32 warmerda
+ * New
+ *
+ * Revision 1.2 1999/02/11 22:27:12 warmerda
+ * Added multi-sample support
+ *
+ * Revision 1.1 1999/02/11 18:12:30 warmerda
+ * New
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "tiffio.h"
+
+void TIFFBuildOverviews( TIFF *, int, int *, int, const char *,
+ int (*)(double,void*), void * );
+
+/************************************************************************/
+/* main() */
+/************************************************************************/
+
+int main( int argc, char ** argv )
+
+{
+ int anOverviews[100]; /* TODO: un-hardwire array length, flexible allocate */
+ int nOverviewCount = 0;
+ int bUseSubIFD = 0;
+ TIFF *hTIFF;
+ const char *pszResampling = "nearest";
+
+/* -------------------------------------------------------------------- */
+/* Usage: */
+/* -------------------------------------------------------------------- */
+ if( argc < 2 )
+ {
+ printf( "Usage: addtiffo [-r {nearest,average,mode}]\n"
+ " tiff_filename [resolution_reductions]\n"
+ "\n"
+ "Example:\n"
+ " %% addtiffo abc.tif 2 4 8 16\n" );
+ return( 1 );
+ }
+
+ while( argv[1][0] == '-' )
+ {
+ if( strcmp(argv[1],"-subifd") == 0 )
+ {
+ bUseSubIFD = 1;
+ argv++;
+ argc--;
+ }
+ else if( strcmp(argv[1],"-r") == 0 )
+ {
+ argv += 2;
+ argc -= 2;
+ pszResampling = *argv;
+ }
+ else
+ {
+ fprintf( stderr, "Incorrect parameters\n" );
+ return( 1 );
+ }
+ }
+
+ /* TODO: resampling mode parameter needs to be encoded in an integer from this point on */
+
+/* -------------------------------------------------------------------- */
+/* Collect the user requested reduction factors. */
+/* -------------------------------------------------------------------- */
+ while( nOverviewCount < argc - 2 && nOverviewCount < 100 )
+ {
+ anOverviews[nOverviewCount] = atoi(argv[nOverviewCount+2]);
+ if( anOverviews[nOverviewCount] <= 0)
+ {
+ fprintf( stderr, "Incorrect parameters\n" );
+ return(1);
+ }
+ nOverviewCount++;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Default to four overview levels. It would be nicer if it */
+/* defaulted based on the size of the source image. */
+/* -------------------------------------------------------------------- */
+ /* TODO: make it default based on the size of the source image */
+ if( nOverviewCount == 0 )
+ {
+ nOverviewCount = 4;
+
+ anOverviews[0] = 2;
+ anOverviews[1] = 4;
+ anOverviews[2] = 8;
+ anOverviews[3] = 16;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Build the overview. */
+/* -------------------------------------------------------------------- */
+ hTIFF = TIFFOpen( argv[1], "r+" );
+ if( hTIFF == NULL )
+ {
+ fprintf( stderr, "TIFFOpen(%s) failed.\n", argv[1] );
+ return( 1 );
+ }
+
+ TIFFBuildOverviews( hTIFF, nOverviewCount, anOverviews, bUseSubIFD,
+ pszResampling, NULL, NULL );
+
+ TIFFClose( hTIFF );
+
+/* -------------------------------------------------------------------- */
+/* Optionally test for memory leaks. */
+/* -------------------------------------------------------------------- */
+#ifdef DBMALLOC
+ malloc_dump(1);
+#endif
+
+ return( 0 );
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/addtiffo/tif_overview.c b/tiff/contrib/addtiffo/tif_overview.c
new file mode 100644
index 0000000..994451c
--- /dev/null
+++ b/tiff/contrib/addtiffo/tif_overview.c
@@ -0,0 +1,896 @@
+/******************************************************************************
+ * tif_overview.c,v 1.9 2005/05/25 09:03:16 dron Exp
+ *
+ * Project: TIFF Overview Builder
+ * Purpose: Library function for building overviews in a TIFF file.
+ * Author: Frank Warmerdam, warmerdam@pobox.com
+ *
+ * Notes:
+ * o Currently only images with bits_per_sample of a multiple of eight
+ * will work.
+ *
+ * o The downsampler currently just takes the top left pixel from the
+ * source rectangle. Eventually sampling options of averaging, mode, and
+ * ``center pixel'' should be offered.
+ *
+ * o The code will attempt to use the same kind of compression,
+ * photometric interpretation, and organization as the source image, but
+ * it doesn't copy geotiff tags to the reduced resolution images.
+ *
+ * o Reduced resolution overviews for multi-sample files will currently
+ * always be generated as PLANARCONFIG_SEPARATE. This could be fixed
+ * reasonable easily if needed to improve compatibility with other
+ * packages. Many don't properly support PLANARCONFIG_SEPARATE.
+ *
+ ******************************************************************************
+ * Copyright (c) 1999, Frank Warmerdam
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ */
+
+/* TODO: update notes in header above */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tiffio.h"
+#include "tif_ovrcache.h"
+
+#ifndef FALSE
+# define FALSE 0
+# define TRUE 1
+#endif
+
+#ifndef MAX
+# define MIN(a,b) ((a<b) ? a : b)
+# define MAX(a,b) ((a>b) ? a : b)
+#endif
+
+void TIFFBuildOverviews( TIFF *, int, int *, int, const char *,
+ int (*)(double,void*), void * );
+
+/************************************************************************/
+/* TIFF_WriteOverview() */
+/* */
+/* Create a new directory, without any image data for an overview. */
+/* Returns offset of newly created overview directory, but the */
+/* current directory is reset to be the one in used when this */
+/* function is called. */
+/************************************************************************/
+
+uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize,
+ int nBitsPerPixel, int nPlanarConfig, int nSamples,
+ int nBlockXSize, int nBlockYSize,
+ int bTiled, int nCompressFlag, int nPhotometric,
+ int nSampleFormat,
+ unsigned short *panRed,
+ unsigned short *panGreen,
+ unsigned short *panBlue,
+ int bUseSubIFDs,
+ int nHorSubsampling, int nVerSubsampling )
+
+{
+ uint32 nBaseDirOffset;
+ uint32 nOffset;
+
+ nBaseDirOffset = TIFFCurrentDirOffset( hTIFF );
+
+ TIFFCreateDirectory( hTIFF );
+
+/* -------------------------------------------------------------------- */
+/* Setup TIFF fields. */
+/* -------------------------------------------------------------------- */
+ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize );
+ TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize );
+ if( nSamples == 1 )
+ TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
+ else
+ TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig );
+
+ TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel );
+ TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples );
+ TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag );
+ TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric );
+ TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat );
+
+ if( bTiled )
+ {
+ TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize );
+ TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize );
+ }
+ else
+ TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize );
+
+ TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE );
+
+ if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB )
+ {
+ TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, nHorSubsampling, nVerSubsampling);
+ /* TODO: also write YCbCrPositioning and YCbCrCoefficients tag identical to source IFD */
+ }
+ /* TODO: add command-line parameter for selecting jpeg compression quality
+ * that gets ignored when compression isn't jpeg */
+
+/* -------------------------------------------------------------------- */
+/* Write color table if one is present. */
+/* -------------------------------------------------------------------- */
+ if( panRed != NULL )
+ {
+ TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Write directory, and return byte offset. */
+/* -------------------------------------------------------------------- */
+ if( TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" ) == 0 )
+ return 0;
+
+ TIFFWriteDirectory( hTIFF );
+ TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) );
+
+ nOffset = TIFFCurrentDirOffset( hTIFF );
+
+ TIFFSetSubDirectory( hTIFF, nBaseDirOffset );
+
+ return nOffset;
+}
+
+/************************************************************************/
+/* TIFF_GetSourceSamples() */
+/************************************************************************/
+
+static void
+TIFF_GetSourceSamples( double * padfSamples, unsigned char *pabySrc,
+ int nPixelBytes, int nSampleFormat,
+ int nXSize, int nYSize,
+ int nPixelOffset, int nLineOffset )
+{
+ int iXOff, iYOff, iSample;
+
+ iSample = 0;
+
+ for( iYOff = 0; iYOff < nYSize; iYOff++ )
+ {
+ for( iXOff = 0; iXOff < nXSize; iXOff++ )
+ {
+ unsigned char *pabyData;
+
+ pabyData = pabySrc + iYOff * nLineOffset + iXOff * nPixelOffset;
+
+ if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 1 )
+ {
+ padfSamples[iSample++] = *pabyData;
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 2 )
+ {
+ padfSamples[iSample++] = ((uint16 *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 4 )
+ {
+ padfSamples[iSample++] = ((uint32 *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 2 )
+ {
+ padfSamples[iSample++] = ((int16 *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 32 )
+ {
+ padfSamples[iSample++] = ((int32 *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 4 )
+ {
+ padfSamples[iSample++] = ((float *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 8 )
+ {
+ padfSamples[iSample++] = ((double *) pabyData)[0];
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* TIFF_SetSample() */
+/************************************************************************/
+
+static void
+TIFF_SetSample( unsigned char * pabyData, int nPixelBytes, int nSampleFormat,
+ double dfValue )
+
+{
+ if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 1 )
+ {
+ *pabyData = (unsigned char) MAX(0,MIN(255,dfValue));
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 2 )
+ {
+ *((uint16 *)pabyData) = (uint16) MAX(0,MIN(65535,dfValue));
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 4 )
+ {
+ *((uint32 *)pabyData) = (uint32) dfValue;
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 2 )
+ {
+ *((int16 *)pabyData) = (int16) MAX(-32768,MIN(32767,dfValue));
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 32 )
+ {
+ *((int32 *)pabyData) = (int32) dfValue;
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 4 )
+ {
+ *((float *)pabyData) = (float) dfValue;
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 8 )
+ {
+ *((double *)pabyData) = dfValue;
+ }
+}
+
+/************************************************************************/
+/* TIFF_DownSample() */
+/* */
+/* Down sample a tile of full res data into a window of a tile */
+/* of downsampled data. */
+/************************************************************************/
+
+static
+void TIFF_DownSample( unsigned char *pabySrcTile,
+ int nBlockXSize, int nBlockYSize,
+ int nPixelSkewBits, int nBitsPerPixel,
+ unsigned char * pabyOTile,
+ int nOBlockXSize, int nOBlockYSize,
+ int nTXOff, int nTYOff, int nOMult,
+ int nSampleFormat, const char * pszResampling )
+
+{
+ int i, j, k, nPixelBytes = (nBitsPerPixel) / 8;
+ int nPixelGroupBytes = (nBitsPerPixel+nPixelSkewBits)/8;
+ unsigned char *pabySrc, *pabyDst;
+ double *padfSamples;
+
+ assert( nBitsPerPixel >= 8 );
+
+ padfSamples = (double *) malloc(sizeof(double) * nOMult * nOMult);
+
+/* ==================================================================== */
+/* Loop over scanline chunks to process, establishing where the */
+/* data is going. */
+/* ==================================================================== */
+ for( j = 0; j*nOMult < nBlockYSize; j++ )
+ {
+ if( j + nTYOff >= nOBlockYSize )
+ break;
+
+ pabyDst = pabyOTile + ((j+nTYOff)*nOBlockXSize + nTXOff)
+ * nPixelBytes * nPixelGroupBytes;
+
+/* -------------------------------------------------------------------- */
+/* Handler nearest resampling ... we don't even care about the */
+/* data type, we just do a bytewise copy. */
+/* -------------------------------------------------------------------- */
+ if( strncmp(pszResampling,"nearest",4) == 0
+ || strncmp(pszResampling,"NEAR",4) == 0 )
+ {
+ pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes;
+
+ for( i = 0; i*nOMult < nBlockXSize; i++ )
+ {
+ if( i + nTXOff >= nOBlockXSize )
+ break;
+
+ /*
+ * For now use simple subsampling, from the top left corner
+ * of the source block of pixels.
+ */
+
+ for( k = 0; k < nPixelBytes; k++ )
+ pabyDst[k] = pabySrc[k];
+
+ pabyDst += nPixelBytes * nPixelGroupBytes;
+ pabySrc += nOMult * nPixelGroupBytes;
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Handle the case of averaging. For this we also have to */
+/* handle each sample format we are concerned with. */
+/* -------------------------------------------------------------------- */
+ else if( strncmp(pszResampling,"averag",6) == 0
+ || strncmp(pszResampling,"AVERAG",6) == 0 )
+ {
+ pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes;
+
+ for( i = 0; i*nOMult < nBlockXSize; i++ )
+ {
+ double dfTotal;
+ int iSample;
+ int nXSize, nYSize;
+
+ if( i + nTXOff >= nOBlockXSize )
+ break;
+
+ nXSize = MIN(nOMult,nBlockXSize-i);
+ nYSize = MIN(nOMult,nBlockYSize-j);
+
+ TIFF_GetSourceSamples( padfSamples, pabySrc,
+ nPixelBytes, nSampleFormat,
+ nXSize, nYSize,
+ nPixelGroupBytes,
+ nPixelGroupBytes * nBlockXSize );
+
+ dfTotal = 0;
+ for( iSample = 0; iSample < nXSize*nYSize; iSample++ )
+ {
+ dfTotal += padfSamples[iSample];
+ }
+
+ TIFF_SetSample( pabyDst, nPixelBytes, nSampleFormat,
+ dfTotal / (nXSize*nYSize) );
+
+ pabySrc += nOMult * nPixelGroupBytes;
+ pabyDst += nPixelBytes;
+ }
+ }
+ }
+
+ free( padfSamples );
+}
+
+/************************************************************************/
+/* TIFF_DownSample_Subsampled() */
+/************************************************************************/
+static
+void TIFF_DownSample_Subsampled( unsigned char *pabySrcTile, int nSample,
+ int nBlockXSize, int nBlockYSize,
+ unsigned char * pabyOTile,
+ int nOBlockXSize, int nOBlockYSize,
+ int nTXOff, int nTYOff, int nOMult,
+ const char * pszResampling,
+ int nHorSubsampling, int nVerSubsampling )
+{
+ /* TODO: test with variety of subsampling values, and incovinient tile/strip sizes */
+ int nSampleBlockSize;
+ int nSourceSampleRowSize;
+ int nDestSampleRowSize;
+ int nSourceX, nSourceY;
+ int nSourceXSec, nSourceYSec;
+ int nSourceXSecEnd, nSourceYSecEnd;
+ int nDestX, nDestY;
+ int nSampleOffsetInSampleBlock;
+ unsigned char * pSourceBase;
+ unsigned char * pDestBase;
+ int nSourceBaseInc;
+ unsigned char * pSourceBaseEnd;
+ unsigned int nCummulator;
+ unsigned int nCummulatorCount;
+
+ nSampleBlockSize = nHorSubsampling * nVerSubsampling + 2;
+ nSourceSampleRowSize =
+ ( ( nBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize;
+ nDestSampleRowSize =
+ ( ( nOBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize;
+
+ if( strncmp(pszResampling,"nearest",4) == 0
+ || strncmp(pszResampling,"NEAR",4) == 0 )
+ {
+ if( nSample == 0 )
+ {
+ for( nSourceY = 0, nDestY = nTYOff;
+ nSourceY < nBlockYSize;
+ nSourceY += nOMult, nDestY ++)
+ {
+ if( nDestY >= nOBlockYSize )
+ break;
+
+ for( nSourceX = 0, nDestX = nTXOff;
+ nSourceX < nBlockXSize;
+ nSourceX += nOMult, nDestX ++)
+ {
+ if( nDestX >= nOBlockXSize )
+ break;
+
+ * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize
+ + ( nDestY % nVerSubsampling ) * nHorSubsampling
+ + ( nDestX / nHorSubsampling ) * nSampleBlockSize
+ + ( nDestX % nHorSubsampling ) ) =
+ * ( pabySrcTile + ( nSourceY / nVerSubsampling ) * nSourceSampleRowSize
+ + ( nSourceY % nVerSubsampling ) * nHorSubsampling
+ + ( nSourceX / nHorSubsampling ) * nSampleBlockSize
+ + ( nSourceX % nHorSubsampling ) );
+ }
+ }
+ }
+ else
+ {
+ nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1;
+ for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling );
+ nSourceY < ( nBlockYSize / nVerSubsampling );
+ nSourceY += nOMult, nDestY ++)
+ {
+ if( nDestY*nVerSubsampling >= nOBlockYSize )
+ break;
+
+ for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling );
+ nSourceX < ( nBlockXSize / nHorSubsampling );
+ nSourceX += nOMult, nDestX ++)
+ {
+ if( nDestX*nHorSubsampling >= nOBlockXSize )
+ break;
+
+ * ( pabyOTile + nDestY * nDestSampleRowSize
+ + nDestX * nSampleBlockSize
+ + nSampleOffsetInSampleBlock ) =
+ * ( pabySrcTile + nSourceY * nSourceSampleRowSize
+ + nSourceX * nSampleBlockSize
+ + nSampleOffsetInSampleBlock );
+ }
+ }
+ }
+ }
+ else if( strncmp(pszResampling,"averag",6) == 0
+ || strncmp(pszResampling,"AVERAG",6) == 0 )
+ {
+ if( nSample == 0 )
+ {
+ for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++)
+ {
+ if( nDestY >= nOBlockYSize )
+ break;
+
+ for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++)
+ {
+ if( nDestX >= nOBlockXSize )
+ break;
+
+ nSourceXSecEnd = nSourceX + nOMult;
+ if( nSourceXSecEnd > nBlockXSize )
+ nSourceXSecEnd = nBlockXSize;
+ nSourceYSecEnd = nSourceY + nOMult;
+ if( nSourceYSecEnd > nBlockYSize )
+ nSourceYSecEnd = nBlockYSize;
+ nCummulator = 0;
+ for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++)
+ {
+ for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++)
+ {
+ nCummulator += * ( pabySrcTile + ( nSourceYSec / nVerSubsampling ) * nSourceSampleRowSize
+ + ( nSourceYSec % nVerSubsampling ) * nHorSubsampling
+ + ( nSourceXSec / nHorSubsampling ) * nSampleBlockSize
+ + ( nSourceXSec % nHorSubsampling ) );
+ }
+ }
+ nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY );
+ * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize
+ + ( nDestY % nVerSubsampling ) * nHorSubsampling
+ + ( nDestX / nHorSubsampling ) * nSampleBlockSize
+ + ( nDestX % nHorSubsampling ) ) =
+ ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount );
+ }
+ }
+ }
+ else
+ {
+ nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1;
+ for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling );
+ nSourceY += nOMult, nDestY ++)
+ {
+ if( nDestY*nVerSubsampling >= nOBlockYSize )
+ break;
+
+ for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling );
+ nSourceX += nOMult, nDestX ++)
+ {
+ if( nDestX*nHorSubsampling >= nOBlockXSize )
+ break;
+
+ nSourceXSecEnd = nSourceX + nOMult;
+ if( nSourceXSecEnd > ( nBlockXSize / nHorSubsampling ) )
+ nSourceXSecEnd = ( nBlockXSize / nHorSubsampling );
+ nSourceYSecEnd = nSourceY + nOMult;
+ if( nSourceYSecEnd > ( nBlockYSize / nVerSubsampling ) )
+ nSourceYSecEnd = ( nBlockYSize / nVerSubsampling );
+ nCummulator = 0;
+ for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++)
+ {
+ for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++)
+ {
+ nCummulator += * ( pabySrcTile + nSourceYSec * nSourceSampleRowSize
+ + nSourceXSec * nSampleBlockSize
+ + nSampleOffsetInSampleBlock );
+ }
+ }
+ nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY );
+ * ( pabyOTile + nDestY * nDestSampleRowSize
+ + nDestX * nSampleBlockSize
+ + nSampleOffsetInSampleBlock ) =
+ ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount );
+ }
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* TIFF_ProcessFullResBlock() */
+/* */
+/* Process one block of full res data, downsampling into each */
+/* of the overviews. */
+/************************************************************************/
+
+void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig,
+ int bSubsampled, int nHorSubsampling, int nVerSubsampling,
+ int nOverviews, int * panOvList,
+ int nBitsPerPixel,
+ int nSamples, TIFFOvrCache ** papoRawBIs,
+ int nSXOff, int nSYOff,
+ unsigned char *pabySrcTile,
+ int nBlockXSize, int nBlockYSize,
+ int nSampleFormat, const char * pszResampling )
+
+{
+ int iOverview, iSample;
+
+ for( iSample = 0; iSample < nSamples; iSample++ )
+ {
+ /*
+ * We have to read a tile/strip for each sample for
+ * PLANARCONFIG_SEPARATE. Otherwise, we just read all the samples
+ * at once when handling the first sample.
+ */
+ if( nPlanarConfig == PLANARCONFIG_SEPARATE || iSample == 0 )
+ {
+ if( TIFFIsTiled(hTIFF) )
+ {
+ TIFFReadEncodedTile( hTIFF,
+ TIFFComputeTile(hTIFF, nSXOff, nSYOff,
+ 0, (tsample_t)iSample ),
+ pabySrcTile,
+ TIFFTileSize(hTIFF));
+ }
+ else
+ {
+ TIFFReadEncodedStrip( hTIFF,
+ TIFFComputeStrip(hTIFF, nSYOff,
+ (tsample_t) iSample),
+ pabySrcTile,
+ TIFFStripSize(hTIFF) );
+ }
+ }
+
+ /*
+ * Loop over destination overview layers
+ */
+ for( iOverview = 0; iOverview < nOverviews; iOverview++ )
+ {
+ TIFFOvrCache *poRBI = papoRawBIs[iOverview];
+ unsigned char *pabyOTile;
+ int nTXOff, nTYOff, nOXOff, nOYOff, nOMult;
+ int nOBlockXSize = poRBI->nBlockXSize;
+ int nOBlockYSize = poRBI->nBlockYSize;
+ int nSkewBits, nSampleByteOffset;
+
+ /*
+ * Fetch the destination overview tile
+ */
+ nOMult = panOvList[iOverview];
+ nOXOff = (nSXOff/nOMult) / nOBlockXSize;
+ nOYOff = (nSYOff/nOMult) / nOBlockYSize;
+
+ if( bSubsampled )
+ {
+ pabyOTile = TIFFGetOvrBlock_Subsampled( poRBI, nOXOff, nOYOff );
+
+ /*
+ * Establish the offset into this tile at which we should
+ * start placing data.
+ */
+ nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult;
+ nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult;
+
+
+#ifdef DBMALLOC
+ malloc_chain_check( 1 );
+#endif
+ TIFF_DownSample_Subsampled( pabySrcTile, iSample,
+ nBlockXSize, nBlockYSize,
+ pabyOTile,
+ poRBI->nBlockXSize, poRBI->nBlockYSize,
+ nTXOff, nTYOff,
+ nOMult, pszResampling,
+ nHorSubsampling, nVerSubsampling );
+#ifdef DBMALLOC
+ malloc_chain_check( 1 );
+#endif
+
+ }
+ else
+ {
+
+ pabyOTile = TIFFGetOvrBlock( poRBI, nOXOff, nOYOff, iSample );
+
+ /*
+ * Establish the offset into this tile at which we should
+ * start placing data.
+ */
+ nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult;
+ nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult;
+
+ /*
+ * Figure out the skew (extra space between ``our samples'') and
+ * the byte offset to the first sample.
+ */
+ assert( (nBitsPerPixel % 8) == 0 );
+ if( nPlanarConfig == PLANARCONFIG_SEPARATE )
+ {
+ nSkewBits = 0;
+ nSampleByteOffset = 0;
+ }
+ else
+ {
+ nSkewBits = nBitsPerPixel * (nSamples-1);
+ nSampleByteOffset = (nBitsPerPixel/8) * iSample;
+ }
+
+ /*
+ * Perform the downsampling.
+ */
+#ifdef DBMALLOC
+ malloc_chain_check( 1 );
+#endif
+ TIFF_DownSample( pabySrcTile + nSampleByteOffset,
+ nBlockXSize, nBlockYSize,
+ nSkewBits, nBitsPerPixel, pabyOTile,
+ poRBI->nBlockXSize, poRBI->nBlockYSize,
+ nTXOff, nTYOff,
+ nOMult, nSampleFormat, pszResampling );
+#ifdef DBMALLOC
+ malloc_chain_check( 1 );
+#endif
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* TIFF_BuildOverviews() */
+/* */
+/* Build the requested list of overviews. Overviews are */
+/* maintained in a bunch of temporary files and then these are */
+/* written back to the TIFF file. Only one pass through the */
+/* source TIFF file is made for any number of output */
+/* overviews. */
+/************************************************************************/
+
+void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
+ int bUseSubIFDs, const char *pszResampleMethod,
+ int (*pfnProgress)( double, void * ),
+ void * pProgressData )
+
+{
+ TIFFOvrCache **papoRawBIs;
+ uint32 nXSize, nYSize, nBlockXSize, nBlockYSize;
+ uint16 nBitsPerPixel, nPhotometric, nCompressFlag, nSamples,
+ nPlanarConfig, nSampleFormat;
+ int bSubsampled;
+ uint16 nHorSubsampling, nVerSubsampling;
+ int bTiled, nSXOff, nSYOff, i;
+ unsigned char *pabySrcTile;
+ uint16 *panRedMap, *panGreenMap, *panBlueMap;
+ TIFFErrorHandler pfnWarning;
+
+/* -------------------------------------------------------------------- */
+/* Get the base raster size. */
+/* -------------------------------------------------------------------- */
+ TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
+ TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
+
+ TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerPixel );
+ /* TODO: nBitsPerPixel seems misnomer and may need renaming to nBitsPerSample */
+ TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamples );
+ TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig );
+
+ TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric );
+ TIFFGetFieldDefaulted( hTIFF, TIFFTAG_COMPRESSION, &nCompressFlag );
+ TIFFGetFieldDefaulted( hTIFF, TIFFTAG_SAMPLEFORMAT, &nSampleFormat );
+
+ if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB )
+ {
+ if( nBitsPerPixel != 8 || nSamples != 3 || nPlanarConfig != PLANARCONFIG_CONTIG ||
+ nSampleFormat != SAMPLEFORMAT_UINT)
+ {
+ /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */
+ TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews",
+ "File `%s' has an unsupported subsampling configuration.\n",
+ TIFFFileName(hTIFF) );
+ /* If you need support for this particular flavor, please contact either
+ * Frank Warmerdam warmerdam@pobox.com
+ * Joris Van Damme info@awaresystems.be
+ */
+ return;
+ }
+ bSubsampled = 1;
+ TIFFGetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, &nHorSubsampling, &nVerSubsampling );
+ /* TODO: find out if maybe TIFFGetFieldDefaulted is better choice for YCbCrSubsampling tag */
+ }
+ else
+ {
+ if( nBitsPerPixel < 8 )
+ {
+ /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */
+ TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews",
+ "File `%s' has samples of %d bits per sample. Sample\n"
+ "sizes of less than 8 bits per sample are not supported.\n",
+ TIFFFileName(hTIFF), nBitsPerPixel );
+ return;
+ }
+ bSubsampled = 0;
+ nHorSubsampling = 1;
+ nVerSubsampling = 1;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Turn off warnings to avoid alot of repeated warnings while */
+/* rereading directories. */
+/* -------------------------------------------------------------------- */
+ pfnWarning = TIFFSetWarningHandler( NULL );
+
+/* -------------------------------------------------------------------- */
+/* Get the base raster block size. */
+/* -------------------------------------------------------------------- */
+ if( TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(nBlockYSize) ) )
+ {
+ nBlockXSize = nXSize;
+ bTiled = FALSE;
+ }
+ else
+ {
+ TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &nBlockXSize );
+ TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &nBlockYSize );
+ bTiled = TRUE;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Capture the pallette if there is one. */
+/* -------------------------------------------------------------------- */
+ if( TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
+ &panRedMap, &panGreenMap, &panBlueMap ) )
+ {
+ uint16 *panRed2, *panGreen2, *panBlue2;
+ int nColorCount = 1 << nBitsPerPixel;
+
+ panRed2 = (uint16 *) _TIFFmalloc(2*nColorCount);
+ panGreen2 = (uint16 *) _TIFFmalloc(2*nColorCount);
+ panBlue2 = (uint16 *) _TIFFmalloc(2*nColorCount);
+
+ memcpy( panRed2, panRedMap, 2 * nColorCount );
+ memcpy( panGreen2, panGreenMap, 2 * nColorCount );
+ memcpy( panBlue2, panBlueMap, 2 * nColorCount );
+
+ panRedMap = panRed2;
+ panGreenMap = panGreen2;
+ panBlueMap = panBlue2;
+ }
+ else
+ {
+ panRedMap = panGreenMap = panBlueMap = NULL;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Initialize overviews. */
+/* -------------------------------------------------------------------- */
+ papoRawBIs = (TIFFOvrCache **) _TIFFmalloc(nOverviews*sizeof(void*));
+
+ for( i = 0; i < nOverviews; i++ )
+ {
+ int nOXSize, nOYSize, nOBlockXSize, nOBlockYSize;
+ uint32 nDirOffset;
+
+ nOXSize = (nXSize + panOvList[i] - 1) / panOvList[i];
+ nOYSize = (nYSize + panOvList[i] - 1) / panOvList[i];
+
+ nOBlockXSize = MIN((int)nBlockXSize,nOXSize);
+ nOBlockYSize = MIN((int)nBlockYSize,nOYSize);
+
+ if( bTiled )
+ {
+ if( (nOBlockXSize % 16) != 0 )
+ nOBlockXSize = nOBlockXSize + 16 - (nOBlockXSize % 16);
+
+ if( (nOBlockYSize % 16) != 0 )
+ nOBlockYSize = nOBlockYSize + 16 - (nOBlockYSize % 16);
+ }
+
+ nDirOffset = TIFF_WriteOverview( hTIFF, nOXSize, nOYSize,
+ nBitsPerPixel, nPlanarConfig,
+ nSamples, nOBlockXSize, nOBlockYSize,
+ bTiled, nCompressFlag, nPhotometric,
+ nSampleFormat,
+ panRedMap, panGreenMap, panBlueMap,
+ bUseSubIFDs,
+ nHorSubsampling, nVerSubsampling );
+
+ papoRawBIs[i] = TIFFCreateOvrCache( hTIFF, nDirOffset );
+ }
+
+ if( panRedMap != NULL )
+ {
+ _TIFFfree( panRedMap );
+ _TIFFfree( panGreenMap );
+ _TIFFfree( panBlueMap );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Allocate a buffer to hold a source block. */
+/* -------------------------------------------------------------------- */
+ if( bTiled )
+ pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFTileSize(hTIFF));
+ else
+ pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFStripSize(hTIFF));
+
+/* -------------------------------------------------------------------- */
+/* Loop over the source raster, applying data to the */
+/* destination raster. */
+/* -------------------------------------------------------------------- */
+ for( nSYOff = 0; nSYOff < (int) nYSize; nSYOff += nBlockYSize )
+ {
+ for( nSXOff = 0; nSXOff < (int) nXSize; nSXOff += nBlockXSize )
+ {
+ /*
+ * Read and resample into the various overview images.
+ */
+
+ TIFF_ProcessFullResBlock( hTIFF, nPlanarConfig,
+ bSubsampled,nHorSubsampling,nVerSubsampling,
+ nOverviews, panOvList,
+ nBitsPerPixel, nSamples, papoRawBIs,
+ nSXOff, nSYOff, pabySrcTile,
+ nBlockXSize, nBlockYSize,
+ nSampleFormat, pszResampleMethod );
+ }
+ }
+
+ _TIFFfree( pabySrcTile );
+
+/* -------------------------------------------------------------------- */
+/* Cleanup the rawblockedimage files. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < nOverviews; i++ )
+ {
+ TIFFDestroyOvrCache( papoRawBIs[i] );
+ }
+
+ if( papoRawBIs != NULL )
+ _TIFFfree( papoRawBIs );
+
+ TIFFSetWarningHandler( pfnWarning );
+}
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/addtiffo/tif_ovrcache.c b/tiff/contrib/addtiffo/tif_ovrcache.c
new file mode 100644
index 0000000..646b534
--- /dev/null
+++ b/tiff/contrib/addtiffo/tif_ovrcache.c
@@ -0,0 +1,341 @@
+/******************************************************************************
+ * $Id: tif_ovrcache.c,v 1.7.2.1 2010-06-08 18:50:40 bfriesen Exp $
+ *
+ * Project: TIFF Overview Builder
+ * Purpose: Library functions to maintain two rows of tiles or two strips
+ * of data for output overviews as an output cache.
+ * Author: Frank Warmerdam, warmerdam@pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2000, Frank Warmerdam
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ */
+
+#include "tiffiop.h"
+#include "tif_ovrcache.h"
+#include <assert.h>
+
+/************************************************************************/
+/* TIFFCreateOvrCache() */
+/* */
+/* Create an overview cache to hold two rows of blocks from an */
+/* existing TIFF directory. */
+/************************************************************************/
+
+TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, int nDirOffset )
+
+{
+ TIFFOvrCache *psCache;
+ uint32 nBaseDirOffset;
+
+ psCache = (TIFFOvrCache *) _TIFFmalloc(sizeof(TIFFOvrCache));
+ psCache->nDirOffset = nDirOffset;
+ psCache->hTIFF = hTIFF;
+
+/* -------------------------------------------------------------------- */
+/* Get definition of this raster from the TIFF file itself. */
+/* -------------------------------------------------------------------- */
+ nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF );
+ TIFFSetSubDirectory( hTIFF, nDirOffset );
+
+ TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &(psCache->nXSize) );
+ TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &(psCache->nYSize) );
+
+ TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(psCache->nBitsPerPixel) );
+ TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &(psCache->nSamples) );
+ TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(psCache->nPlanarConfig) );
+
+ if( !TIFFIsTiled( hTIFF ) )
+ {
+ TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(psCache->nBlockYSize) );
+ psCache->nBlockXSize = psCache->nXSize;
+ psCache->nBytesPerBlock = TIFFStripSize(hTIFF);
+ psCache->bTiled = FALSE;
+ }
+ else
+ {
+ TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(psCache->nBlockXSize) );
+ TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(psCache->nBlockYSize) );
+ psCache->nBytesPerBlock = TIFFTileSize(hTIFF);
+ psCache->bTiled = TRUE;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Compute some values from this. */
+/* -------------------------------------------------------------------- */
+
+ psCache->nBlocksPerRow = (psCache->nXSize + psCache->nBlockXSize - 1)
+ / psCache->nBlockXSize;
+ psCache->nBlocksPerColumn = (psCache->nYSize + psCache->nBlockYSize - 1)
+ / psCache->nBlockYSize;
+
+ if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE)
+ psCache->nBytesPerRow = psCache->nBytesPerBlock
+ * psCache->nBlocksPerRow * psCache->nSamples;
+ else
+ psCache->nBytesPerRow =
+ psCache->nBytesPerBlock * psCache->nBlocksPerRow;
+
+
+/* -------------------------------------------------------------------- */
+/* Allocate and initialize the data buffers. */
+/* -------------------------------------------------------------------- */
+
+ psCache->pabyRow1Blocks =
+ (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow);
+ psCache->pabyRow2Blocks =
+ (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow);
+
+ if( psCache->pabyRow1Blocks == NULL
+ || psCache->pabyRow2Blocks == NULL )
+ {
+ TIFFErrorExt( hTIFF->tif_clientdata, hTIFF->tif_name,
+ "Can't allocate memory for overview cache." );
+ /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */
+ return NULL;
+ }
+
+ _TIFFmemset( psCache->pabyRow1Blocks, 0, psCache->nBytesPerRow );
+ _TIFFmemset( psCache->pabyRow2Blocks, 0, psCache->nBytesPerRow );
+
+ psCache->nBlockOffset = 0;
+
+ TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset );
+
+ return psCache;
+}
+
+/************************************************************************/
+/* TIFFWriteOvrRow() */
+/* */
+/* Write one entire row of blocks (row 1) to the tiff file, and */
+/* then rotate the block buffers, essentially moving things */
+/* down by one block. */
+/************************************************************************/
+
+static void TIFFWriteOvrRow( TIFFOvrCache * psCache )
+
+{
+ int nRet, iTileX, iTileY = psCache->nBlockOffset;
+ unsigned char *pabyData;
+ uint32 nBaseDirOffset;
+ uint32 RowsInStrip;
+
+/* -------------------------------------------------------------------- */
+/* If the output cache is multi-byte per sample, and the file */
+/* being written to is of a different byte order than the current */
+/* platform, we will need to byte swap the data. */
+/* -------------------------------------------------------------------- */
+ if( TIFFIsByteSwapped(psCache->hTIFF) )
+ {
+ if( psCache->nBitsPerPixel == 16 )
+ TIFFSwabArrayOfShort( (uint16 *) psCache->pabyRow1Blocks,
+ (psCache->nBytesPerBlock * psCache->nSamples) / 2 );
+
+ else if( psCache->nBitsPerPixel == 32 )
+ TIFFSwabArrayOfLong( (uint32 *) psCache->pabyRow1Blocks,
+ (psCache->nBytesPerBlock * psCache->nSamples) / 4 );
+
+ else if( psCache->nBitsPerPixel == 64 )
+ TIFFSwabArrayOfDouble( (double *) psCache->pabyRow1Blocks,
+ (psCache->nBytesPerBlock * psCache->nSamples) / 8 );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Record original directory position, so we can restore it at */
+/* end. */
+/* -------------------------------------------------------------------- */
+ nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF );
+ nRet = TIFFSetSubDirectory( psCache->hTIFF, psCache->nDirOffset );
+ assert( nRet == 1 );
+
+/* -------------------------------------------------------------------- */
+/* Write blocks to TIFF file. */
+/* -------------------------------------------------------------------- */
+ for( iTileX = 0; iTileX < psCache->nBlocksPerRow; iTileX++ )
+ {
+ int nTileID;
+
+ if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE)
+ {
+ int iSample;
+
+ for( iSample = 0; iSample < psCache->nSamples; iSample++ )
+ {
+ pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, iSample );
+
+ if( psCache->bTiled )
+ {
+ nTileID = TIFFComputeTile( psCache->hTIFF,
+ iTileX * psCache->nBlockXSize,
+ iTileY * psCache->nBlockYSize,
+ 0, (tsample_t) iSample );
+ TIFFWriteEncodedTile( psCache->hTIFF, nTileID,
+ pabyData,
+ TIFFTileSize(psCache->hTIFF) );
+ }
+ else
+ {
+ nTileID = TIFFComputeStrip( psCache->hTIFF,
+ iTileY * psCache->nBlockYSize,
+ (tsample_t) iSample );
+ RowsInStrip=psCache->nBlockYSize;
+ if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize)
+ RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize;
+ TIFFWriteEncodedStrip( psCache->hTIFF, nTileID,
+ pabyData,
+ TIFFVStripSize(psCache->hTIFF,RowsInStrip) );
+ }
+ }
+
+ }
+ else
+ {
+ pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, 0 );
+
+ if( psCache->bTiled )
+ {
+ nTileID = TIFFComputeTile( psCache->hTIFF,
+ iTileX * psCache->nBlockXSize,
+ iTileY * psCache->nBlockYSize,
+ 0, 0 );
+ TIFFWriteEncodedTile( psCache->hTIFF, nTileID,
+ pabyData,
+ TIFFTileSize(psCache->hTIFF) );
+ }
+ else
+ {
+ nTileID = TIFFComputeStrip( psCache->hTIFF,
+ iTileY * psCache->nBlockYSize,
+ 0 );
+ RowsInStrip=psCache->nBlockYSize;
+ if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize)
+ RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize;
+ TIFFWriteEncodedStrip( psCache->hTIFF, nTileID,
+ pabyData,
+ TIFFVStripSize(psCache->hTIFF,RowsInStrip) );
+ }
+ }
+ }
+ /* TODO: add checks on error status return of TIFFWriteEncodedTile and TIFFWriteEncodedStrip */
+
+/* -------------------------------------------------------------------- */
+/* Rotate buffers. */
+/* -------------------------------------------------------------------- */
+ pabyData = psCache->pabyRow1Blocks;
+ psCache->pabyRow1Blocks = psCache->pabyRow2Blocks;
+ psCache->pabyRow2Blocks = pabyData;
+
+ _TIFFmemset( pabyData, 0, psCache->nBytesPerRow );
+
+ psCache->nBlockOffset++;
+
+/* -------------------------------------------------------------------- */
+/* Restore access to original directory. */
+/* -------------------------------------------------------------------- */
+ TIFFFlush( psCache->hTIFF );
+ /* TODO: add checks on error status return of TIFFFlush */
+ TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset );
+ /* TODO: add checks on error status return of TIFFSetSubDirectory */
+}
+
+/************************************************************************/
+/* TIFFGetOvrBlock() */
+/************************************************************************/
+
+/* TODO: make TIFF_Downsample handle iSample offset, so that we can
+ * do with a single TIFFGetOvrBlock and no longer need TIFFGetOvrBlock_Subsampled */
+unsigned char *TIFFGetOvrBlock( TIFFOvrCache *psCache, int iTileX, int iTileY,
+ int iSample )
+
+{
+ int nRowOffset;
+
+ if( iTileY > psCache->nBlockOffset + 1 )
+ TIFFWriteOvrRow( psCache );
+
+ assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow );
+ assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn );
+ assert( iTileY >= psCache->nBlockOffset
+ && iTileY < psCache->nBlockOffset+2 );
+ assert( iSample >= 0 && iSample < psCache->nSamples );
+
+ if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE)
+ nRowOffset = ((iTileX * psCache->nSamples) + iSample)
+ * psCache->nBytesPerBlock;
+ else
+ nRowOffset = iTileX * psCache->nBytesPerBlock +
+ (psCache->nBitsPerPixel + 7) / 8 * iSample;
+
+ if( iTileY == psCache->nBlockOffset )
+ return psCache->pabyRow1Blocks + nRowOffset;
+ else
+ return psCache->pabyRow2Blocks + nRowOffset;
+}
+
+/************************************************************************/
+/* TIFFGetOvrBlock_Subsampled() */
+/************************************************************************/
+
+unsigned char *TIFFGetOvrBlock_Subsampled( TIFFOvrCache *psCache,
+ int iTileX, int iTileY )
+
+{
+ int nRowOffset;
+
+ if( iTileY > psCache->nBlockOffset + 1 )
+ TIFFWriteOvrRow( psCache );
+
+ assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow );
+ assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn );
+ assert( iTileY >= psCache->nBlockOffset
+ && iTileY < psCache->nBlockOffset+2 );
+ assert( psCache->nPlanarConfig != PLANARCONFIG_SEPARATE );
+
+ nRowOffset = iTileX * psCache->nBytesPerBlock;
+
+ if( iTileY == psCache->nBlockOffset )
+ return psCache->pabyRow1Blocks + nRowOffset;
+ else
+ return psCache->pabyRow2Blocks + nRowOffset;
+}
+
+/************************************************************************/
+/* TIFFDestroyOvrCache() */
+/************************************************************************/
+
+void TIFFDestroyOvrCache( TIFFOvrCache * psCache )
+
+{
+ while( psCache->nBlockOffset < psCache->nBlocksPerColumn )
+ TIFFWriteOvrRow( psCache );
+
+ _TIFFfree( psCache->pabyRow1Blocks );
+ _TIFFfree( psCache->pabyRow2Blocks );
+ _TIFFfree( psCache );
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/addtiffo/tif_ovrcache.h b/tiff/contrib/addtiffo/tif_ovrcache.h
new file mode 100644
index 0000000..928de36
--- /dev/null
+++ b/tiff/contrib/addtiffo/tif_ovrcache.h
@@ -0,0 +1,108 @@
+/******************************************************************************
+ * tif_ovrcache.h,v 1.3 2005/05/25 09:03:16 dron Exp
+ *
+ * Project: TIFF Overview Builder
+ * Purpose: Library functions to maintain two rows of tiles or two strips
+ * of data for output overviews as an output cache.
+ * Author: Frank Warmerdam, warmerdam@pobox.com
+ *
+ * This code could potentially be used by other applications wanting to
+ * manage a once-through write cache.
+ *
+ ******************************************************************************
+ * Copyright (c) 2000, Frank Warmerdam
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ */
+
+#ifndef TIF_OVRCACHE_H_INCLUDED
+#define TIF_OVRCACHE_H_INCLUDED
+
+#include "tiffio.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef struct
+{
+ uint32 nXSize;
+ uint32 nYSize;
+
+ uint16 nBitsPerPixel;
+ uint16 nSamples;
+ uint16 nPlanarConfig;
+ uint32 nBlockXSize;
+ uint32 nBlockYSize;
+ uint32 nBytesPerBlock;
+ uint32 nBytesPerRow;
+
+ int nBlocksPerRow;
+ int nBlocksPerColumn;
+
+ int nBlockOffset; /* what block is the first in papabyBlocks? */
+ unsigned char *pabyRow1Blocks;
+ unsigned char *pabyRow2Blocks;
+
+ int nDirOffset;
+ TIFF *hTIFF;
+ int bTiled;
+
+} TIFFOvrCache;
+
+TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, int nDirOffset );
+unsigned char *TIFFGetOvrBlock( TIFFOvrCache *psCache, int iTileX, int iTileY,
+ int iSample );
+unsigned char *TIFFGetOvrBlock_Subsampled( TIFFOvrCache *psCache, int iTileX, int iTileY );
+void TIFFDestroyOvrCache( TIFFOvrCache * );
+
+void TIFFBuildOverviews( TIFF *, int, int *, int, const char *,
+ int (*)(double,void*), void * );
+
+void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig,
+ int bSubsampled, int nHorSamples, int nVerSamples,
+ int nOverviews, int * panOvList,
+ int nBitsPerPixel,
+ int nSamples, TIFFOvrCache ** papoRawBIs,
+ int nSXOff, int nSYOff,
+ unsigned char *pabySrcTile,
+ int nBlockXSize, int nBlockYSize,
+ int nSampleFormat, const char * pszResampling );
+
+uint32 TIFF_WriteOverview( TIFF *, int, int, int, int, int, int, int,
+ int, int, int, int, unsigned short *,
+ unsigned short *, unsigned short *, int,
+ int, int);
+
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* ndef TIF_OVRCACHE_H_INCLUDED */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/dbs/Makefile.am b/tiff/contrib/dbs/Makefile.am
new file mode 100644
index 0000000..608a0ad
--- /dev/null
+++ b/tiff/contrib/dbs/Makefile.am
@@ -0,0 +1,43 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+SUBDIRS = xtiff
+
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+
+EXTRA_DIST = README
+
+noinst_PROGRAMS = tiff-bi tiff-grayscale tiff-palette tiff-rgb
+
+tiff_bi_SOURCES = tiff-bi.c
+tiff_bi_LDADD = $(LIBTIFF)
+tiff_grayscale_SOURCES = tiff-grayscale.c
+tiff_grayscale_LDADD = $(LIBTIFF)
+tiff_palette_SOURCES = tiff-palette.c
+tiff_palette_LDADD = $(LIBTIFF)
+tiff_rgb_SOURCES = tiff-rgb.c
+tiff_rgb_LDADD = $(LIBTIFF)
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
diff --git a/tiff/contrib/dbs/Makefile.in b/tiff/contrib/dbs/Makefile.in
new file mode 100644
index 0000000..72eaf43
--- /dev/null
+++ b/tiff/contrib/dbs/Makefile.in
@@ -0,0 +1,737 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+noinst_PROGRAMS = tiff-bi$(EXEEXT) tiff-grayscale$(EXEEXT) \
+ tiff-palette$(EXEEXT) tiff-rgb$(EXEEXT)
+subdir = contrib/dbs
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am_tiff_bi_OBJECTS = tiff-bi.$(OBJEXT)
+tiff_bi_OBJECTS = $(am_tiff_bi_OBJECTS)
+tiff_bi_DEPENDENCIES = $(LIBTIFF)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+am_tiff_grayscale_OBJECTS = tiff-grayscale.$(OBJEXT)
+tiff_grayscale_OBJECTS = $(am_tiff_grayscale_OBJECTS)
+tiff_grayscale_DEPENDENCIES = $(LIBTIFF)
+am_tiff_palette_OBJECTS = tiff-palette.$(OBJEXT)
+tiff_palette_OBJECTS = $(am_tiff_palette_OBJECTS)
+tiff_palette_DEPENDENCIES = $(LIBTIFF)
+am_tiff_rgb_OBJECTS = tiff-rgb.$(OBJEXT)
+tiff_rgb_OBJECTS = $(am_tiff_rgb_OBJECTS)
+tiff_rgb_DEPENDENCIES = $(LIBTIFF)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libtiff
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(tiff_bi_SOURCES) $(tiff_grayscale_SOURCES) \
+ $(tiff_palette_SOURCES) $(tiff_rgb_SOURCES)
+DIST_SOURCES = $(tiff_bi_SOURCES) $(tiff_grayscale_SOURCES) \
+ $(tiff_palette_SOURCES) $(tiff_rgb_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = xtiff
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+EXTRA_DIST = README
+tiff_bi_SOURCES = tiff-bi.c
+tiff_bi_LDADD = $(LIBTIFF)
+tiff_grayscale_SOURCES = tiff-grayscale.c
+tiff_grayscale_LDADD = $(LIBTIFF)
+tiff_palette_SOURCES = tiff-palette.c
+tiff_palette_LDADD = $(LIBTIFF)
+tiff_rgb_SOURCES = tiff-rgb.c
+tiff_rgb_LDADD = $(LIBTIFF)
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/dbs/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/dbs/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+tiff-bi$(EXEEXT): $(tiff_bi_OBJECTS) $(tiff_bi_DEPENDENCIES)
+ @rm -f tiff-bi$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff_bi_OBJECTS) $(tiff_bi_LDADD) $(LIBS)
+tiff-grayscale$(EXEEXT): $(tiff_grayscale_OBJECTS) $(tiff_grayscale_DEPENDENCIES)
+ @rm -f tiff-grayscale$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff_grayscale_OBJECTS) $(tiff_grayscale_LDADD) $(LIBS)
+tiff-palette$(EXEEXT): $(tiff_palette_OBJECTS) $(tiff_palette_DEPENDENCIES)
+ @rm -f tiff-palette$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff_palette_OBJECTS) $(tiff_palette_LDADD) $(LIBS)
+tiff-rgb$(EXEEXT): $(tiff_rgb_OBJECTS) $(tiff_rgb_DEPENDENCIES)
+ @rm -f tiff-rgb$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff_rgb_OBJECTS) $(tiff_rgb_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff-bi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff-grayscale.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff-palette.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff-rgb.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(PROGRAMS)
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ clean-noinstPROGRAMS ctags ctags-recursive distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/dbs/README b/tiff/contrib/dbs/README
new file mode 100644
index 0000000..e05d0a9
--- /dev/null
+++ b/tiff/contrib/dbs/README
@@ -0,0 +1,7 @@
+Wed May 9 09:11:35 PDT 1990
+
+This directory contains programs from Dan Sears
+(dbs@decwrl.dec.com). Contact him directly if
+you have questions/problems.
+
+ Sam
diff --git a/tiff/contrib/dbs/tiff-bi.c b/tiff/contrib/dbs/tiff-bi.c
new file mode 100644
index 0000000..f549209
--- /dev/null
+++ b/tiff/contrib/dbs/tiff-bi.c
@@ -0,0 +1,91 @@
+/* $Id: tiff-bi.c,v 1.2.2.1 2010-06-08 18:50:40 bfriesen Exp $ */
+
+/*
+ * tiff-bi.c -- create a Class B (bilevel) TIFF file
+ *
+ * Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tiffio.h"
+
+#define WIDTH 512
+#define HEIGHT WIDTH
+
+int main(int argc, char **argv)
+{
+ int i;
+ unsigned char * scan_line;
+ TIFF * tif;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s tiff-image\n", argv[0]);
+ return 0;
+ }
+
+ if ((tif = TIFFOpen(argv[1], "w")) == NULL) {
+ fprintf(stderr, "can't open %s as a TIFF file\n", argv[1]);
+ return 0;
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, WIDTH);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, HEIGHT);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE);
+
+ scan_line = (unsigned char *) malloc(WIDTH / 8);
+
+ for (i = 0; i < (WIDTH / 8) / 2; i++)
+ scan_line[i] = 0;
+
+ for (i = (WIDTH / 8) / 2; i < (WIDTH / 8); i++)
+ scan_line[i] = 255;
+
+ for (i = 0; i < HEIGHT / 2; i++)
+ TIFFWriteScanline(tif, scan_line, i, 0);
+
+ for (i = 0; i < (WIDTH / 8) / 2; i++)
+ scan_line[i] = 255;
+
+ for (i = (WIDTH / 8) / 2; i < (WIDTH / 8); i++)
+ scan_line[i] = 0;
+
+ for (i = HEIGHT / 2; i < HEIGHT; i++)
+ TIFFWriteScanline(tif, scan_line, i, 0);
+
+ free(scan_line);
+ TIFFClose(tif);
+ return 0;
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/dbs/tiff-grayscale.c b/tiff/contrib/dbs/tiff-grayscale.c
new file mode 100644
index 0000000..e8f474c
--- /dev/null
+++ b/tiff/contrib/dbs/tiff-grayscale.c
@@ -0,0 +1,146 @@
+/* $Id: tiff-grayscale.c,v 1.4.2.1 2010-06-08 18:50:40 bfriesen Exp $ */
+
+/*
+ * tiff-grayscale.c -- create a Class G (grayscale) TIFF file
+ * with a gray response curve in linear optical density
+ *
+ * Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tiffio.h"
+
+#define WIDTH 512
+#define HEIGHT WIDTH
+
+char * programName;
+void Usage();
+
+int main(int argc, char **argv)
+{
+ int bits_per_pixel = 8, cmsize, i, j, k,
+ gray_index, chunk_size = 32, nchunks = 16;
+ unsigned char * scan_line;
+ uint16 * gray;
+ float refblackwhite[2*1];
+ TIFF * tif;
+
+ programName = argv[0];
+
+ if (argc != 4)
+ Usage();
+
+ if (!strcmp(argv[1], "-depth"))
+ bits_per_pixel = atoi(argv[2]);
+ else
+ Usage();
+
+ switch (bits_per_pixel) {
+ case 8:
+ nchunks = 16;
+ chunk_size = 32;
+ break;
+ case 4:
+ nchunks = 4;
+ chunk_size = 128;
+ break;
+ case 2:
+ nchunks = 2;
+ chunk_size = 256;
+ break;
+ default:
+ Usage();
+ }
+
+ cmsize = nchunks * nchunks;
+ gray = (uint16 *) malloc(cmsize * sizeof(uint16));
+
+ gray[0] = 3000;
+ for (i = 1; i < cmsize; i++)
+ gray[i] = (uint16) (-log10((double) i / (cmsize - 1)) * 1000);
+
+ refblackwhite[0] = 0.0;
+ refblackwhite[1] = (float)((1L<<bits_per_pixel) - 1);
+
+ if ((tif = TIFFOpen(argv[3], "w")) == NULL) {
+ fprintf(stderr, "can't open %s as a TIFF file\n", argv[3]);
+ return 0;
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, WIDTH);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, HEIGHT);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits_per_pixel);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE, refblackwhite);
+ TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, gray);
+ TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE);
+
+ scan_line = (unsigned char *) malloc(WIDTH / (8 / bits_per_pixel));
+
+ for (i = 0; i < HEIGHT; i++) {
+ for (j = 0, k = 0; j < WIDTH;) {
+ gray_index = (j / chunk_size) + ((i / chunk_size) * nchunks);
+
+ switch (bits_per_pixel) {
+ case 8:
+ scan_line[k++] = gray_index;
+ j++;
+ break;
+ case 4:
+ scan_line[k++] = (gray_index << 4) + gray_index;
+ j += 2;
+ break;
+ case 2:
+ scan_line[k++] = (gray_index << 6) + (gray_index << 4)
+ + (gray_index << 2) + gray_index;
+ j += 4;
+ break;
+ }
+ }
+ TIFFWriteScanline(tif, scan_line, i, 0);
+ }
+
+ free(scan_line);
+ TIFFClose(tif);
+ return 0;
+}
+
+void
+Usage()
+{
+ fprintf(stderr, "Usage: %s -depth (8 | 4 | 2) tiff-image\n", programName);
+ exit(0);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/dbs/tiff-palette.c b/tiff/contrib/dbs/tiff-palette.c
new file mode 100644
index 0000000..054000b
--- /dev/null
+++ b/tiff/contrib/dbs/tiff-palette.c
@@ -0,0 +1,283 @@
+/* $Id: tiff-palette.c,v 1.3.2.1 2010-06-08 18:50:40 bfriesen Exp $ */
+
+/*
+ * tiff-palette.c -- create a Class P (palette) TIFF file
+ *
+ * Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tiffio.h"
+
+#define WIDTH 512
+#define HEIGHT WIDTH
+#define SCALE(x) ((x) * 257L)
+
+char * programName;
+void Usage();
+
+int main(int argc, char **argv)
+{
+ int bits_per_pixel = 8, cmsize, i, j, k,
+ cmap_index, chunk_size = 32, nchunks = 16;
+ unsigned char * scan_line;
+ uint16 *red, *green, *blue;
+ TIFF * tif;
+
+ programName = argv[0];
+
+ if (argc != 4)
+ Usage();
+
+ if (!strcmp(argv[1], "-depth"))
+ bits_per_pixel = atoi(argv[2]);
+ else
+ Usage();
+
+ switch (bits_per_pixel) {
+ case 8:
+ nchunks = 16;
+ chunk_size = 32;
+ break;
+ case 4:
+ nchunks = 4;
+ chunk_size = 128;
+ break;
+ case 2:
+ nchunks = 2;
+ chunk_size = 256;
+ break;
+ case 1:
+ nchunks = 2;
+ chunk_size = 256;
+ break;
+ default:
+ Usage();
+ }
+
+ if (bits_per_pixel != 1) {
+ cmsize = nchunks * nchunks;
+ } else {
+ cmsize = 2;
+ }
+ red = (uint16 *) malloc(cmsize * sizeof(uint16));
+ green = (uint16 *) malloc(cmsize * sizeof(uint16));
+ blue = (uint16 *) malloc(cmsize * sizeof(uint16));
+
+ switch (bits_per_pixel) {
+ case 8:
+ for (i = 0; i < cmsize; i++) {
+ if (i < 32)
+ red[i] = 0;
+ else if (i < 64)
+ red[i] = SCALE(36);
+ else if (i < 96)
+ red[i] = SCALE(73);
+ else if (i < 128)
+ red[i] = SCALE(109);
+ else if (i < 160)
+ red[i] = SCALE(146);
+ else if (i < 192)
+ red[i] = SCALE(182);
+ else if (i < 224)
+ red[i] = SCALE(219);
+ else if (i < 256)
+ red[i] = SCALE(255);
+
+ if ((i % 32) < 4)
+ green[i] = 0;
+ else if (i < 8)
+ green[i] = SCALE(36);
+ else if ((i % 32) < 12)
+ green[i] = SCALE(73);
+ else if ((i % 32) < 16)
+ green[i] = SCALE(109);
+ else if ((i % 32) < 20)
+ green[i] = SCALE(146);
+ else if ((i % 32) < 24)
+ green[i] = SCALE(182);
+ else if ((i % 32) < 28)
+ green[i] = SCALE(219);
+ else if ((i % 32) < 32)
+ green[i] = SCALE(255);
+
+ if ((i % 4) == 0)
+ blue[i] = SCALE(0);
+ else if ((i % 4) == 1)
+ blue[i] = SCALE(85);
+ else if ((i % 4) == 2)
+ blue[i] = SCALE(170);
+ else if ((i % 4) == 3)
+ blue[i] = SCALE(255);
+ }
+ break;
+ case 4:
+ red[0] = SCALE(255);
+ green[0] = 0;
+ blue[0] = 0;
+
+ red[1] = 0;
+ green[1] = SCALE(255);
+ blue[1] = 0;
+
+ red[2] = 0;
+ green[2] = 0;
+ blue[2] = SCALE(255);
+
+ red[3] = SCALE(255);
+ green[3] = SCALE(255);
+ blue[3] = SCALE(255);
+
+ red[4] = 0;
+ green[4] = SCALE(255);
+ blue[4] = SCALE(255);
+
+ red[5] = SCALE(255);
+ green[5] = 0;
+ blue[5] = SCALE(255);
+
+ red[6] = SCALE(255);
+ green[6] = SCALE(255);
+ blue[6] = 0;
+
+ red[7] = 0;
+ green[7] = 0;
+ blue[7] = 0;
+
+ red[8] = SCALE(176);
+ green[8] = SCALE(224);
+ blue[8] = SCALE(230);
+ red[9] = SCALE(100);
+ green[9] = SCALE(149);
+ blue[9] = SCALE(237);
+ red[10] = SCALE(46);
+ green[10] = SCALE(139);
+ blue[10] = SCALE(87);
+ red[11] = SCALE(160);
+ green[11] = SCALE(82);
+ blue[11] = SCALE(45);
+ red[12] = SCALE(238);
+ green[12] = SCALE(130);
+ blue[12] = SCALE(238);
+ red[13] = SCALE(176);
+ green[13] = SCALE(48);
+ blue[13] = SCALE(96);
+ red[14] = SCALE(50);
+ green[14] = SCALE(205);
+ blue[14] = SCALE(50);
+ red[15] = SCALE(240);
+ green[15] = SCALE(152);
+ blue[15] = SCALE(35);
+ break;
+ case 2:
+ red[0] = SCALE(255);
+ green[0] = 0;
+ blue[0] = 0;
+
+ red[1] = 0;
+ green[1] = SCALE(255);
+ blue[1] = 0;
+
+ red[2] = 0;
+ green[2] = 0;
+ blue[2] = SCALE(255);
+ red[3] = SCALE(255);
+ green[3] = SCALE(255);
+ blue[3] = SCALE(255);
+ break;
+ case 1:
+ red[0] = 0;
+ green[0] = 0;
+ blue[0] = 0;
+
+ red[1] = SCALE(255);
+ green[1] = SCALE(255);
+ blue[1] = SCALE(255);
+ break;
+ }
+
+ if ((tif = TIFFOpen(argv[3], "w")) == NULL) {
+ fprintf(stderr, "can't open %s as a TIFF file\n", argv[3]);
+ return 0;
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, WIDTH);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, HEIGHT);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits_per_pixel);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE);
+ TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
+
+ scan_line = (unsigned char *) malloc(WIDTH / (8 / bits_per_pixel));
+
+ for (i = 0; i < HEIGHT; i++) {
+ for (j = 0, k = 0; j < WIDTH;) {
+ cmap_index = (j / chunk_size) + ((i / chunk_size) * nchunks);
+
+ switch (bits_per_pixel) {
+ case 8:
+ scan_line[k++] = cmap_index;
+ j++;
+ break;
+ case 4:
+ scan_line[k++] = (cmap_index << 4) + cmap_index;
+ j += 2;
+ break;
+ case 2:
+ scan_line[k++] = (cmap_index << 6) + (cmap_index << 4)
+ + (cmap_index << 2) + cmap_index;
+ j += 4;
+ break;
+ case 1:
+ scan_line[k++] =
+ ((j / chunk_size) == (i / chunk_size)) ? 0x00 : 0xff;
+ j += 8;
+ break;
+ }
+ }
+ TIFFWriteScanline(tif, scan_line, i, 0);
+ }
+
+ free(scan_line);
+ TIFFClose(tif);
+ return 0;
+}
+
+void
+Usage()
+{
+ fprintf(stderr, "Usage: %s -depth (8 | 4 | 2 | 1) tiff-image\n", programName);
+ exit(0);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/dbs/tiff-rgb.c b/tiff/contrib/dbs/tiff-rgb.c
new file mode 100644
index 0000000..dcde673
--- /dev/null
+++ b/tiff/contrib/dbs/tiff-rgb.c
@@ -0,0 +1,201 @@
+/* $Id: tiff-rgb.c,v 1.3.2.1 2010-06-08 18:50:40 bfriesen Exp $ */
+
+/*
+ * tiff-rgb.c -- create a 24-bit Class R (rgb) TIFF file
+ *
+ * Copyright 1990 by Digital Equipment Corporation, Maynard, Massachusetts.
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tiffio.h"
+
+#define ROUND(x) (uint16) ((x) + 0.5)
+#define CMSIZE 256
+#define WIDTH 525
+#define HEIGHT 512
+#define TIFF_GAMMA 2.2
+
+void Usage();
+char * programName;
+
+int main(int argc, char **argv)
+{
+ char * input_file = NULL;
+ double image_gamma = TIFF_GAMMA;
+ int i, j;
+ TIFF * tif;
+ unsigned char * scan_line;
+ uint16 red[CMSIZE], green[CMSIZE], blue[CMSIZE];
+ float refblackwhite[2*3];
+
+ programName = argv[0];
+
+ switch (argc) {
+ case 2:
+ image_gamma = TIFF_GAMMA;
+ input_file = argv[1];
+ break;
+ case 4:
+ if (!strcmp(argv[1], "-gamma")) {
+ image_gamma = atof(argv[2]);
+ input_file = argv[3];
+ } else
+ Usage();
+ break;
+ default:
+ Usage();
+ }
+
+ for (i = 0; i < CMSIZE; i++) {
+ if (i == 0)
+ red[i] = green[i] = blue[i] = 0;
+ else {
+ red[i] = ROUND((pow(i / 255.0, 1.0 / image_gamma) * 65535.0));
+ green[i] = ROUND((pow(i / 255.0, 1.0 / image_gamma) * 65535.0));
+ blue[i] = ROUND((pow(i / 255.0, 1.0 / image_gamma) * 65535.0));
+ }
+ }
+ refblackwhite[0] = 0.0; refblackwhite[1] = 255.0;
+ refblackwhite[2] = 0.0; refblackwhite[3] = 255.0;
+ refblackwhite[4] = 0.0; refblackwhite[5] = 255.0;
+
+ if ((tif = TIFFOpen(input_file, "w")) == NULL) {
+ fprintf(stderr, "can't open %s as a TIFF file\n", input_file);
+ exit(0);
+ }
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, WIDTH);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, HEIGHT);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE);
+#ifdef notdef
+ TIFFSetField(tif, TIFFTAG_WHITEPOINT, whitex, whitey);
+ TIFFSetField(tif, TIFFTAG_PRIMARYCHROMATICITIES, primaries);
+#endif
+ TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE, refblackwhite);
+ TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, red, green, blue);
+
+ scan_line = (unsigned char *) malloc(WIDTH * 3);
+
+ for (i = 0; i < 255; i++) {
+ for (j = 0; j < 75; j++) {
+ scan_line[j * 3] = 255;
+ scan_line[(j * 3) + 1] = 255 - i;
+ scan_line[(j * 3) + 2] = 255 - i;
+ }
+ for (j = 75; j < 150; j++) {
+ scan_line[j * 3] = 255 - i;
+ scan_line[(j * 3) + 1] = 255;
+ scan_line[(j * 3) + 2] = 255 - i;
+ }
+ for (j = 150; j < 225; j++) {
+ scan_line[j * 3] = 255 - i;
+ scan_line[(j * 3) + 1] = 255 - i;
+ scan_line[(j * 3) + 2] = 255;
+ }
+ for (j = 225; j < 300; j++) {
+ scan_line[j * 3] = (i - 1) / 2;
+ scan_line[(j * 3) + 1] = (i - 1) / 2;
+ scan_line[(j * 3) + 2] = (i - 1) / 2;
+ }
+ for (j = 300; j < 375; j++) {
+ scan_line[j * 3] = 255 - i;
+ scan_line[(j * 3) + 1] = 255;
+ scan_line[(j * 3) + 2] = 255;
+ }
+ for (j = 375; j < 450; j++) {
+ scan_line[j * 3] = 255;
+ scan_line[(j * 3) + 1] = 255 - i;
+ scan_line[(j * 3) + 2] = 255;
+ }
+ for (j = 450; j < 525; j++) {
+ scan_line[j * 3] = 255;
+ scan_line[(j * 3) + 1] = 255;
+ scan_line[(j * 3) + 2] = 255 - i;
+ }
+ TIFFWriteScanline(tif, scan_line, i, 0);
+ }
+ for (i = 255; i < 512; i++) {
+ for (j = 0; j < 75; j++) {
+ scan_line[j * 3] = i;
+ scan_line[(j * 3) + 1] = 0;
+ scan_line[(j * 3) + 2] = 0;
+ }
+ for (j = 75; j < 150; j++) {
+ scan_line[j * 3] = 0;
+ scan_line[(j * 3) + 1] = i;
+ scan_line[(j * 3) + 2] = 0;
+ }
+ for (j = 150; j < 225; j++) {
+ scan_line[j * 3] = 0;
+ scan_line[(j * 3) + 1] = 0;
+ scan_line[(j * 3) + 2] = i;
+ }
+ for (j = 225; j < 300; j++) {
+ scan_line[j * 3] = (i - 1) / 2;
+ scan_line[(j * 3) + 1] = (i - 1) / 2;
+ scan_line[(j * 3) + 2] = (i - 1) / 2;
+ }
+ for (j = 300; j < 375; j++) {
+ scan_line[j * 3] = 0;
+ scan_line[(j * 3) + 1] = i;
+ scan_line[(j * 3) + 2] = i;
+ }
+ for (j = 375; j < 450; j++) {
+ scan_line[j * 3] = i;
+ scan_line[(j * 3) + 1] = 0;
+ scan_line[(j * 3) + 2] = i;
+ }
+ for (j = 450; j < 525; j++) {
+ scan_line[j * 3] = i;
+ scan_line[(j * 3) + 1] = i;
+ scan_line[(j * 3) + 2] = 0;
+ }
+ TIFFWriteScanline(tif, scan_line, i, 0);
+ }
+
+ free(scan_line);
+ TIFFClose(tif);
+ exit(0);
+}
+
+void
+Usage()
+{
+ fprintf(stderr, "Usage: %s -gamma gamma tiff-image\n", programName);
+ exit(0);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/dbs/xtiff/Makefile.am b/tiff/contrib/dbs/xtiff/Makefile.am
new file mode 100644
index 0000000..84c8a16
--- /dev/null
+++ b/tiff/contrib/dbs/xtiff/Makefile.am
@@ -0,0 +1,43 @@
+# $Id: Makefile.am,v 1.4 2007/02/24 15:03:49 dron Exp $
+#
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+#LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+
+EXTRA_DIST = README patchlevel.h xtiff.c xtifficon.h
+
+#noinst_PROGRAMS =
+
+#if HAVE_XAW
+#noinst_PROGRAMS += xtiff
+#endif
+
+#xtiff_SOURCES = patchlevel.h xtiff.c xtifficon.h
+#xtiff_CFLAGS = $(CFLAGS) $(XAW_CFLAGS) $(AM_CFLAGS)
+#xtiff_LDADD = $(LIBTIFF) $(X_LIBS) $(XAW_LIBS)
+
+#INCLUDES = -I$(top_srcdir)/libtiff
+
diff --git a/tiff/contrib/dbs/xtiff/Makefile.in b/tiff/contrib/dbs/xtiff/Makefile.in
new file mode 100644
index 0000000..65b5259
--- /dev/null
+++ b/tiff/contrib/dbs/xtiff/Makefile.in
@@ -0,0 +1,436 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# $Id: Makefile.am,v 1.4 2007/02/24 15:03:49 dron Exp $
+#
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+#LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/dbs/xtiff
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = README patchlevel.h xtiff.c xtifficon.h
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/dbs/xtiff/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/dbs/xtiff/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+#noinst_PROGRAMS =
+
+#if HAVE_XAW
+#noinst_PROGRAMS += xtiff
+#endif
+
+#xtiff_SOURCES = patchlevel.h xtiff.c xtifficon.h
+#xtiff_CFLAGS = $(CFLAGS) $(XAW_CFLAGS) $(AM_CFLAGS)
+#xtiff_LDADD = $(LIBTIFF) $(X_LIBS) $(XAW_LIBS)
+
+#INCLUDES = -I$(top_srcdir)/libtiff
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/dbs/xtiff/README b/tiff/contrib/dbs/xtiff/README
new file mode 100644
index 0000000..fa15147
--- /dev/null
+++ b/tiff/contrib/dbs/xtiff/README
@@ -0,0 +1,6 @@
+xtiff 2.0
+
+xtiff is a tool for viewing a TIFF file in an X window. It was written to
+handle as many different kinds of TIFF files as possible while remaining
+simple, portable and efficient. xtiff requires X11 R4, the Athena Widgets
+and Sam Leffler's libtiff package (which can be found on ucbvax.berkeley.edu).
diff --git a/tiff/contrib/dbs/xtiff/patchlevel.h b/tiff/contrib/dbs/xtiff/patchlevel.h
new file mode 100644
index 0000000..538b6d9
--- /dev/null
+++ b/tiff/contrib/dbs/xtiff/patchlevel.h
@@ -0,0 +1,8 @@
+#define PATCHLEVEL 0
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/dbs/xtiff/xtiff.c b/tiff/contrib/dbs/xtiff/xtiff.c
new file mode 100644
index 0000000..7fe3977
--- /dev/null
+++ b/tiff/contrib/dbs/xtiff/xtiff.c
@@ -0,0 +1,1290 @@
+/*
+ * $Id: xtiff.c,v 1.2.2.1 2010-06-08 18:50:40 bfriesen Exp $
+ *
+ * xtiff - view a TIFF file in an X window
+ *
+ * Dan Sears
+ * Chris Sears
+ *
+ * Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts.
+ *
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation, and that the name of Digital not be
+ * used in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ *
+ * Revision 1.0 90/05/07
+ * Initial release.
+ * Revision 2.0 90/12/20
+ * Converted to use the Athena Widgets and the Xt Intrinsics.
+ *
+ * Notes:
+ *
+ * According to the TIFF 5.0 Specification, it is possible to have
+ * both a TIFFTAG_COLORMAP and a TIFFTAG_COLORRESPONSECURVE. This
+ * doesn't make sense since a TIFFTAG_COLORMAP is 16 bits wide and
+ * a TIFFTAG_COLORRESPONSECURVE is tfBitsPerSample bits wide for each
+ * channel. This is probably a bug in the specification.
+ * In this case, TIFFTAG_COLORRESPONSECURVE is ignored.
+ * This might make sense if TIFFTAG_COLORMAP was 8 bits wide.
+ *
+ * TIFFTAG_COLORMAP is often incorrectly written as ranging from
+ * 0 to 255 rather than from 0 to 65535. CheckAndCorrectColormap()
+ * takes care of this.
+ *
+ * Only ORIENTATION_TOPLEFT is supported correctly. This is the
+ * default TIFF and X orientation. Other orientations will be
+ * displayed incorrectly.
+ *
+ * There is no support for or use of 3/3/2 DirectColor visuals.
+ * TIFFTAG_MINSAMPLEVALUE and TIFFTAG_MAXSAMPLEVALUE are not supported.
+ *
+ * Only TIFFTAG_BITSPERSAMPLE values that are 1, 2, 4 or 8 are supported.
+ */
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tiffio.h>
+#include <X11/Xatom.h>
+#include <X11/Intrinsic.h>
+#include <X11/StringDefs.h>
+#include <X11/Xproto.h>
+#include <X11/Shell.h>
+#include <X11/Xaw/Form.h>
+#include <X11/Xaw/List.h>
+#include <X11/Xaw/Label.h>
+#include <X11/cursorfont.h>
+#define XK_MISCELLANY
+#include <X11/keysymdef.h>
+#include "xtifficon.h"
+
+#define TIFF_GAMMA "2.2" /* default gamma from the TIFF 5.0 spec */
+#define ROUND(x) (uint16) ((x) + 0.5)
+#define SCALE(x, s) (((x) * 65535L) / (s))
+#define MCHECK(m) if (!m) { fprintf(stderr, "malloc failed\n"); exit(0); }
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define VIEWPORT_WIDTH 700
+#define VIEWPORT_HEIGHT 500
+#define KEY_TRANSLATE 20
+
+#ifdef __STDC__
+#define PP(args) args
+#else
+#define PP(args) ()
+#endif
+
+int main PP((int argc, char **argv));
+void OpenTIFFFile PP((void));
+void GetTIFFHeader PP((void));
+void SetNameLabel PP((void));
+void CheckAndCorrectColormap PP((void));
+void SimpleGammaCorrection PP((void));
+void GetVisual PP((void));
+Boolean SearchVisualList PP((int image_depth,
+ int visual_class, Visual **visual));
+void GetTIFFImage PP((void));
+void CreateXImage PP((void));
+XtCallbackProc SelectProc PP((Widget w, caddr_t unused_1, caddr_t unused_2));
+void QuitProc PP((void));
+void NextProc PP((void));
+void PreviousProc PP((void));
+void PageProc PP((int direction));
+void EventProc PP((Widget widget, caddr_t unused, XEvent *event));
+void ResizeProc PP((void));
+int XTiffErrorHandler PP((Display *display, XErrorEvent *error_event));
+void Usage PP((void));
+
+int xtVersion = XtSpecificationRelease; /* xtiff depends on R4 or higher */
+
+/*
+ * Xt data structures
+ */
+Widget shellWidget, formWidget, listWidget, labelWidget, imageWidget;
+
+enum { ButtonQuit = 0, ButtonPreviousPage = 1, ButtonNextPage = 2 };
+
+String buttonStrings[] = { "Quit", "Previous", "Next" };
+
+static XrmOptionDescRec shellOptions[] = {
+ { "-help", "*help", XrmoptionNoArg, (caddr_t) "True" },
+ { "-gamma", "*gamma", XrmoptionSepArg, NULL },
+ { "-usePixmap", "*usePixmap", XrmoptionSepArg, NULL },
+ { "-viewportWidth", "*viewportWidth", XrmoptionSepArg, NULL },
+ { "-viewportHeight", "*viewportHeight", XrmoptionSepArg, NULL },
+ { "-translate", "*translate", XrmoptionSepArg, NULL },
+ { "-verbose", "*verbose", XrmoptionSepArg, NULL }
+};
+
+typedef struct {
+ Boolean help;
+ float gamma;
+ Boolean usePixmap;
+ uint32 viewportWidth;
+ uint32 viewportHeight;
+ int translate;
+ Boolean verbose;
+} AppData, *AppDataPtr;
+
+AppData appData;
+
+XtResource clientResources[] = {
+ {
+ "help", XtCBoolean, XtRBoolean, sizeof(Boolean),
+ XtOffset(AppDataPtr, help), XtRImmediate, (XtPointer) False
+ }, {
+ "gamma", "Gamma", XtRFloat, sizeof(float),
+ XtOffset(AppDataPtr, gamma), XtRString, (XtPointer) TIFF_GAMMA
+ }, {
+ "usePixmap", "UsePixmap", XtRBoolean, sizeof(Boolean),
+ XtOffset(AppDataPtr, usePixmap), XtRImmediate, (XtPointer) True
+ }, {
+ "viewportWidth", "ViewportWidth", XtRInt, sizeof(int),
+ XtOffset(AppDataPtr, viewportWidth), XtRImmediate,
+ (XtPointer) VIEWPORT_WIDTH
+ }, {
+ "viewportHeight", "ViewportHeight", XtRInt, sizeof(int),
+ XtOffset(AppDataPtr, viewportHeight), XtRImmediate,
+ (XtPointer) VIEWPORT_HEIGHT
+ }, {
+ "translate", "Translate", XtRInt, sizeof(int),
+ XtOffset(AppDataPtr, translate), XtRImmediate, (XtPointer) KEY_TRANSLATE
+ }, {
+ "verbose", "Verbose", XtRBoolean, sizeof(Boolean),
+ XtOffset(AppDataPtr, verbose), XtRImmediate, (XtPointer) True
+ }
+};
+
+Arg formArgs[] = {
+ { XtNresizable, True }
+};
+
+Arg listArgs[] = {
+ { XtNresizable, False },
+ { XtNborderWidth, 0 },
+ { XtNdefaultColumns, 3 },
+ { XtNforceColumns, True },
+ { XtNlist, (int) buttonStrings },
+ { XtNnumberStrings, XtNumber(buttonStrings) },
+ { XtNtop, XtChainTop },
+ { XtNleft, XtChainLeft },
+ { XtNbottom, XtChainTop },
+ { XtNright, XtChainLeft }
+};
+
+Arg labelArgs[] = {
+ { XtNresizable, False },
+ { XtNwidth, 200 },
+ { XtNborderWidth, 0 },
+ { XtNjustify, XtJustifyLeft },
+ { XtNtop, XtChainTop },
+ { XtNleft, XtChainLeft },
+ { XtNbottom, XtChainTop },
+ { XtNright, XtChainLeft }
+};
+
+Arg imageArgs[] = {
+ { XtNresizable, True },
+ { XtNborderWidth, 0 },
+ { XtNtop, XtChainTop },
+ { XtNleft, XtChainLeft },
+ { XtNbottom, XtChainTop },
+ { XtNright, XtChainLeft }
+};
+
+XtActionsRec actionsTable[] = {
+ { "quit", QuitProc },
+ { "next", NextProc },
+ { "previous", PreviousProc },
+ { "notifyresize", ResizeProc }
+};
+
+char translationsTable[] = "<Key>q: quit() \n \
+ <Key>Q: quit() \n \
+ <Message>WM_PROTOCOLS: quit()\n \
+ <Key>p: previous() \n \
+ <Key>P: previous() \n \
+ <Key>n: next() \n \
+ <Key>N: next() \n \
+ <Configure>: notifyresize()";
+
+/*
+ * X data structures
+ */
+Colormap xColormap;
+Display * xDisplay;
+Pixmap xImagePixmap;
+Visual * xVisual;
+XImage * xImage;
+GC xWinGc;
+int xImageDepth, xScreen, xRedMask, xGreenMask, xBlueMask,
+ xOffset = 0, yOffset = 0, grabX = -1, grabY = -1;
+unsigned char basePixel = 0;
+
+/*
+ * TIFF data structures
+ */
+TIFF * tfFile = NULL;
+uint32 tfImageWidth, tfImageHeight;
+uint16 tfBitsPerSample, tfSamplesPerPixel, tfPlanarConfiguration,
+ tfPhotometricInterpretation, tfGrayResponseUnit,
+ tfImageDepth, tfBytesPerRow;
+int tfDirectory = 0, tfMultiPage = False;
+double tfUnitMap, tfGrayResponseUnitMap[] = {
+ -1, -10, -100, -1000, -10000, -100000
+ };
+
+/*
+ * display data structures
+ */
+double *dRed, *dGreen, *dBlue;
+
+/*
+ * shared data structures
+ */
+uint16 * redMap = NULL, *greenMap = NULL, *blueMap = NULL,
+ *grayMap = NULL, colormapSize;
+char * imageMemory;
+char * fileName;
+
+int
+main(int argc, char **argv)
+{
+ XSetWindowAttributes window_attributes;
+ Widget widget_list[3];
+ Arg args[5];
+
+ setbuf(stdout, NULL); setbuf(stderr, NULL);
+
+ shellWidget = XtInitialize(argv[0], "XTiff", shellOptions,
+ XtNumber(shellOptions), &argc, argv);
+
+ XSetErrorHandler(XTiffErrorHandler);
+
+ XtGetApplicationResources(shellWidget, &appData,
+ (XtResourceList) clientResources, (Cardinal) XtNumber(clientResources),
+ (ArgList) NULL, (Cardinal) 0);
+
+ if ((argc <= 1) || (argc > 2) || appData.help)
+ Usage();
+
+ if (appData.verbose == False) {
+ TIFFSetErrorHandler(0);
+ TIFFSetWarningHandler(0);
+ }
+
+ fileName = argv[1];
+
+ xDisplay = XtDisplay(shellWidget);
+ xScreen = DefaultScreen(xDisplay);
+
+ OpenTIFFFile();
+ GetTIFFHeader();
+ SimpleGammaCorrection();
+ GetVisual();
+ GetTIFFImage();
+
+ /*
+ * Send visual, colormap, depth and iconPixmap to shellWidget.
+ * Sending the visual to the shell is only possible with the advent of R4.
+ */
+ XtSetArg(args[0], XtNvisual, xVisual);
+ XtSetArg(args[1], XtNcolormap, xColormap);
+ XtSetArg(args[2], XtNdepth,
+ xImageDepth == 1 ? DefaultDepth(xDisplay, xScreen) : xImageDepth);
+ XtSetArg(args[3], XtNiconPixmap,
+ XCreateBitmapFromData(xDisplay, RootWindow(xDisplay, xScreen),
+ xtifficon_bits, xtifficon_width, xtifficon_height));
+ XtSetArg(args[4], XtNallowShellResize, True);
+ XtSetValues(shellWidget, args, 5);
+
+ /*
+ * widget instance hierarchy
+ */
+ formWidget = XtCreateManagedWidget("form", formWidgetClass,
+ shellWidget, formArgs, XtNumber(formArgs));
+
+ widget_list[0] = listWidget = XtCreateWidget("list",
+ listWidgetClass, formWidget, listArgs, XtNumber(listArgs));
+
+ widget_list[1] = labelWidget = XtCreateWidget("label",
+ labelWidgetClass, formWidget, labelArgs, XtNumber(labelArgs));
+
+ widget_list[2] = imageWidget = XtCreateWidget("image",
+ widgetClass, formWidget, imageArgs, XtNumber(imageArgs));
+
+ XtManageChildren(widget_list, XtNumber(widget_list));
+
+ /*
+ * initial widget sizes - for small images let xtiff size itself
+ */
+ if (tfImageWidth >= appData.viewportWidth) {
+ XtSetArg(args[0], XtNwidth, appData.viewportWidth);
+ XtSetValues(shellWidget, args, 1);
+ }
+ if (tfImageHeight >= appData.viewportHeight) {
+ XtSetArg(args[0], XtNheight, appData.viewportHeight);
+ XtSetValues(shellWidget, args, 1);
+ }
+
+ XtSetArg(args[0], XtNwidth, tfImageWidth);
+ XtSetArg(args[1], XtNheight, tfImageHeight);
+ XtSetValues(imageWidget, args, 2);
+
+ /*
+ * formWidget uses these constraints but they are stored in the children.
+ */
+ XtSetArg(args[0], XtNfromVert, listWidget);
+ XtSetValues(imageWidget, args, 1);
+ XtSetArg(args[0], XtNfromHoriz, listWidget);
+ XtSetValues(labelWidget, args, 1);
+
+ SetNameLabel();
+
+ XtAddCallback(listWidget, XtNcallback, (XtCallbackProc) SelectProc,
+ (XtPointer) NULL);
+
+ XtAddActions(actionsTable, XtNumber(actionsTable));
+ XtSetArg(args[0], XtNtranslations,
+ XtParseTranslationTable(translationsTable));
+ XtSetValues(formWidget, &args[0], 1);
+ XtSetValues(imageWidget, &args[0], 1);
+
+ /*
+ * This is intended to be a little faster than going through
+ * the translation manager.
+ */
+ XtAddEventHandler(imageWidget, ExposureMask | ButtonPressMask
+ | ButtonReleaseMask | Button1MotionMask | KeyPressMask,
+ False, EventProc, NULL);
+
+ XtRealizeWidget(shellWidget);
+
+ window_attributes.cursor = XCreateFontCursor(xDisplay, XC_fleur);
+ XChangeWindowAttributes(xDisplay, XtWindow(imageWidget),
+ CWCursor, &window_attributes);
+
+ CreateXImage();
+
+ XtMainLoop();
+
+ return 0;
+}
+
+void
+OpenTIFFFile()
+{
+ if (tfFile != NULL)
+ TIFFClose(tfFile);
+
+ if ((tfFile = TIFFOpen(fileName, "r")) == NULL) {
+ fprintf(appData.verbose ? stderr : stdout,
+ "xtiff: can't open %s as a TIFF file\n", fileName);
+ exit(0);
+ }
+
+ tfMultiPage = (TIFFLastDirectory(tfFile) ? False : True);
+}
+
+void
+GetTIFFHeader()
+{
+ register int i;
+
+ if (!TIFFSetDirectory(tfFile, tfDirectory)) {
+ fprintf(stderr, "xtiff: can't seek to directory %d in %s\n",
+ tfDirectory, fileName);
+ exit(0);
+ }
+
+ TIFFGetField(tfFile, TIFFTAG_IMAGEWIDTH, &tfImageWidth);
+ TIFFGetField(tfFile, TIFFTAG_IMAGELENGTH, &tfImageHeight);
+
+ /*
+ * If the following tags aren't present then use the TIFF defaults.
+ */
+ TIFFGetFieldDefaulted(tfFile, TIFFTAG_BITSPERSAMPLE, &tfBitsPerSample);
+ TIFFGetFieldDefaulted(tfFile, TIFFTAG_SAMPLESPERPIXEL, &tfSamplesPerPixel);
+ TIFFGetFieldDefaulted(tfFile, TIFFTAG_PLANARCONFIG, &tfPlanarConfiguration);
+ TIFFGetFieldDefaulted(tfFile, TIFFTAG_GRAYRESPONSEUNIT, &tfGrayResponseUnit);
+
+ tfUnitMap = tfGrayResponseUnitMap[tfGrayResponseUnit];
+ colormapSize = 1 << tfBitsPerSample;
+ tfImageDepth = tfBitsPerSample * tfSamplesPerPixel;
+
+ dRed = (double *) malloc(colormapSize * sizeof(double));
+ dGreen = (double *) malloc(colormapSize * sizeof(double));
+ dBlue = (double *) malloc(colormapSize * sizeof(double));
+ MCHECK(dRed); MCHECK(dGreen); MCHECK(dBlue);
+
+ /*
+ * If TIFFTAG_PHOTOMETRIC is not present then assign a reasonable default.
+ * The TIFF 5.0 specification doesn't give a default.
+ */
+ if (!TIFFGetField(tfFile, TIFFTAG_PHOTOMETRIC,
+ &tfPhotometricInterpretation)) {
+ if (tfSamplesPerPixel != 1)
+ tfPhotometricInterpretation = PHOTOMETRIC_RGB;
+ else if (tfBitsPerSample == 1)
+ tfPhotometricInterpretation = PHOTOMETRIC_MINISBLACK;
+ else if (TIFFGetField(tfFile, TIFFTAG_COLORMAP,
+ &redMap, &greenMap, &blueMap)) {
+ tfPhotometricInterpretation = PHOTOMETRIC_PALETTE;
+ redMap = greenMap = blueMap = NULL;
+ } else
+ tfPhotometricInterpretation = PHOTOMETRIC_MINISBLACK;
+ }
+
+ /*
+ * Given TIFFTAG_PHOTOMETRIC extract or create the response curves.
+ */
+ switch (tfPhotometricInterpretation) {
+ case PHOTOMETRIC_RGB:
+ redMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ greenMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ blueMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ MCHECK(redMap); MCHECK(greenMap); MCHECK(blueMap);
+ for (i = 0; i < colormapSize; i++)
+ dRed[i] = dGreen[i] = dBlue[i]
+ = (double) SCALE(i, colormapSize - 1);
+ break;
+ case PHOTOMETRIC_PALETTE:
+ if (!TIFFGetField(tfFile, TIFFTAG_COLORMAP,
+ &redMap, &greenMap, &blueMap)) {
+ redMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ greenMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ blueMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ MCHECK(redMap); MCHECK(greenMap); MCHECK(blueMap);
+ for (i = 0; i < colormapSize; i++)
+ dRed[i] = dGreen[i] = dBlue[i]
+ = (double) SCALE(i, colormapSize - 1);
+ } else {
+ CheckAndCorrectColormap();
+ for (i = 0; i < colormapSize; i++) {
+ dRed[i] = (double) redMap[i];
+ dGreen[i] = (double) greenMap[i];
+ dBlue[i] = (double) blueMap[i];
+ }
+ }
+ break;
+ case PHOTOMETRIC_MINISWHITE:
+ redMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ greenMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ blueMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ MCHECK(redMap); MCHECK(greenMap); MCHECK(blueMap);
+ for (i = 0; i < colormapSize; i++)
+ dRed[i] = dGreen[i] = dBlue[i] = (double)
+ SCALE(colormapSize-1-i, colormapSize-1);
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ redMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ greenMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ blueMap = (uint16 *) malloc(colormapSize * sizeof(uint16));
+ MCHECK(redMap); MCHECK(greenMap); MCHECK(blueMap);
+ for (i = 0; i < colormapSize; i++)
+ dRed[i] = dGreen[i] = dBlue[i] = (double) SCALE(i, colormapSize-1);
+ break;
+ default:
+ fprintf(stderr,
+ "xtiff: can't display photometric interpretation type %d\n",
+ tfPhotometricInterpretation);
+ exit(0);
+ }
+}
+
+void
+SetNameLabel()
+{
+ char buffer[BUFSIZ];
+ Arg args[1];
+
+ if (tfMultiPage)
+ sprintf(buffer, "%s - page %d", fileName, tfDirectory);
+ else
+ strcpy(buffer, fileName);
+ XtSetArg(args[0], XtNlabel, buffer);
+ XtSetValues(labelWidget, args, 1);
+}
+
+/*
+ * Many programs get TIFF colormaps wrong. They use 8-bit colormaps instead of
+ * 16-bit colormaps. This function is a heuristic to detect and correct this.
+ */
+void
+CheckAndCorrectColormap()
+{
+ register int i;
+
+ for (i = 0; i < colormapSize; i++)
+ if ((redMap[i] > 255) || (greenMap[i] > 255) || (blueMap[i] > 255))
+ return;
+
+ for (i = 0; i < colormapSize; i++) {
+ redMap[i] = SCALE(redMap[i], 255);
+ greenMap[i] = SCALE(greenMap[i], 255);
+ blueMap[i] = SCALE(blueMap[i], 255);
+ }
+ TIFFWarning(fileName, "Assuming 8-bit colormap");
+}
+
+void
+SimpleGammaCorrection()
+{
+ register int i;
+ register double i_gamma = 1.0 / appData.gamma;
+
+ for (i = 0; i < colormapSize; i++) {
+ if (((tfPhotometricInterpretation == PHOTOMETRIC_MINISWHITE)
+ && (i == colormapSize - 1))
+ || ((tfPhotometricInterpretation == PHOTOMETRIC_MINISBLACK)
+ && (i == 0)))
+ redMap[i] = greenMap[i] = blueMap[i] = 0;
+ else {
+ redMap[i] = ROUND((pow(dRed[i] / 65535.0, i_gamma) * 65535.0));
+ greenMap[i] = ROUND((pow(dGreen[i] / 65535.0, i_gamma) * 65535.0));
+ blueMap[i] = ROUND((pow(dBlue[i] / 65535.0, i_gamma) * 65535.0));
+ }
+ }
+
+ free(dRed); free(dGreen); free(dBlue);
+}
+
+static char* classNames[] = {
+ "StaticGray",
+ "GrayScale",
+ "StaticColor",
+ "PseudoColor",
+ "TrueColor",
+ "DirectColor"
+};
+
+/*
+ * Current limitation: the visual is set initially by the first file.
+ * It cannot be changed.
+ */
+void
+GetVisual()
+{
+ XColor *colors = NULL;
+ unsigned long *pixels = NULL;
+ unsigned long i;
+
+ switch (tfImageDepth) {
+ /*
+ * X really wants a 32-bit image with the fourth channel unused,
+ * but the visual structure thinks it's 24-bit. bitmap_unit is 32.
+ */
+ case 32:
+ case 24:
+ if (SearchVisualList(24, DirectColor, &xVisual) == False) {
+ fprintf(stderr, "xtiff: 24-bit DirectColor visual not available\n");
+ exit(0);
+ }
+
+ colors = (XColor *) malloc(3 * colormapSize * sizeof(XColor));
+ MCHECK(colors);
+
+ for (i = 0; i < colormapSize; i++) {
+ colors[i].pixel = (i << 16) + (i << 8) + i;
+ colors[i].red = redMap[i];
+ colors[i].green = greenMap[i];
+ colors[i].blue = blueMap[i];
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+
+ xColormap = XCreateColormap(xDisplay, RootWindow(xDisplay, xScreen),
+ xVisual, AllocAll);
+ XStoreColors(xDisplay, xColormap, colors, colormapSize);
+ break;
+ case 8:
+ case 4:
+ case 2:
+ /*
+ * We assume that systems with 24-bit visuals also have 8-bit visuals.
+ * We don't promote from 8-bit PseudoColor to 24/32 bit DirectColor.
+ */
+ switch (tfPhotometricInterpretation) {
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ if (SearchVisualList((int) tfImageDepth, GrayScale, &xVisual) == True)
+ break;
+ case PHOTOMETRIC_PALETTE:
+ if (SearchVisualList((int) tfImageDepth, PseudoColor, &xVisual) == True)
+ break;
+ default:
+ fprintf(stderr, "xtiff: Unsupported TIFF/X configuration\n");
+ exit(0);
+ }
+
+ colors = (XColor *) malloc(colormapSize * sizeof(XColor));
+ MCHECK(colors);
+
+ for (i = 0; i < colormapSize; i++) {
+ colors[i].pixel = i;
+ colors[i].red = redMap[i];
+ colors[i].green = greenMap[i];
+ colors[i].blue = blueMap[i];
+ colors[i].flags = DoRed | DoGreen | DoBlue;
+ }
+
+ /*
+ * xtiff's colormap allocation is private. It does not attempt
+ * to detect whether any existing colormap entries are suitable
+ * for its use. This will cause colormap flashing. Furthermore,
+ * background and foreground are taken from the environment.
+ * For example, the foreground color may be red when the visual
+ * is GrayScale. If the colormap is completely populated,
+ * Xt will not be able to allocate fg and bg.
+ */
+ if (tfImageDepth == 8)
+ xColormap = XCreateColormap(xDisplay, RootWindow(xDisplay, xScreen),
+ xVisual, AllocAll);
+ else {
+ xColormap = XCreateColormap(xDisplay, RootWindow(xDisplay, xScreen),
+ xVisual, AllocNone);
+ pixels = (unsigned long *)
+ malloc(colormapSize * sizeof(unsigned long));
+ MCHECK(pixels);
+ (void) XAllocColorCells(xDisplay, xColormap, True,
+ NULL, 0, pixels, colormapSize);
+ basePixel = (unsigned char) pixels[0];
+ free(pixels);
+ }
+ XStoreColors(xDisplay, xColormap, colors, colormapSize);
+ break;
+ case 1:
+ xImageDepth = 1;
+ xVisual = DefaultVisual(xDisplay, xScreen);
+ xColormap = DefaultColormap(xDisplay, xScreen);
+ break;
+ default:
+ fprintf(stderr, "xtiff: unsupported image depth %d\n", tfImageDepth);
+ exit(0);
+ }
+
+ if (appData.verbose == True)
+ fprintf(stderr, "%s: Using %d-bit %s visual.\n",
+ fileName, xImageDepth, classNames[xVisual->class]);
+
+ if (colors != NULL)
+ free(colors);
+ if (grayMap != NULL)
+ free(grayMap);
+ if (redMap != NULL)
+ free(redMap);
+ if (greenMap != NULL)
+ free(greenMap);
+ if (blueMap != NULL)
+ free(blueMap);
+
+ colors = NULL; grayMap = redMap = greenMap = blueMap = NULL;
+}
+
+/*
+ * Search for an appropriate visual. Promote where necessary.
+ * Check to make sure that ENOUGH colormap entries are writeable.
+ * basePixel was determined when XAllocColorCells() contiguously
+ * allocated enough entries. basePixel is used below in GetTIFFImage.
+ */
+Boolean
+SearchVisualList(image_depth, visual_class, visual)
+ int image_depth, visual_class;
+ Visual **visual;
+{
+ XVisualInfo template_visual, *visual_list, *vl;
+ int i, n_visuals;
+
+ template_visual.screen = xScreen;
+ vl = visual_list = XGetVisualInfo(xDisplay, VisualScreenMask,
+ &template_visual, &n_visuals);
+
+ if (n_visuals == 0) {
+ fprintf(stderr, "xtiff: visual list not available\n");
+ exit(0);
+ }
+
+ for (i = 0; i < n_visuals; vl++, i++) {
+ if ((vl->class == visual_class) && (vl->depth >= image_depth)
+ && (vl->visual->map_entries >= (1 << vl->depth))) {
+ *visual = vl->visual;
+ xImageDepth = vl->depth;
+ xRedMask = vl->red_mask;
+ xGreenMask = vl->green_mask;
+ xBlueMask = vl->blue_mask;
+ XFree((char *) visual_list);
+ return True;
+ }
+ }
+
+ XFree((char *) visual_list);
+ return False;
+}
+
+void
+GetTIFFImage()
+{
+ int pixel_map[3], red_shift, green_shift, blue_shift;
+ char *scan_line, *output_p, *input_p;
+ uint32 i, j;
+ uint16 s;
+
+ scan_line = (char *) malloc(tfBytesPerRow = TIFFScanlineSize(tfFile));
+ MCHECK(scan_line);
+
+ if ((tfImageDepth == 32) || (tfImageDepth == 24)) {
+ output_p = imageMemory = (char *)
+ malloc(tfImageWidth * tfImageHeight * 4);
+ MCHECK(imageMemory);
+
+ /*
+ * Handle different color masks for different frame buffers.
+ */
+ if (ImageByteOrder(xDisplay) == LSBFirst) { /* DECstation 5000 */
+ red_shift = pixel_map[0] = xRedMask == 0xFF000000 ? 3
+ : (xRedMask == 0xFF0000 ? 2 : (xRedMask == 0xFF00 ? 1 : 0));
+ green_shift = pixel_map[1] = xGreenMask == 0xFF000000 ? 3
+ : (xGreenMask == 0xFF0000 ? 2 : (xGreenMask == 0xFF00 ? 1 : 0));
+ blue_shift = pixel_map[2] = xBlueMask == 0xFF000000 ? 3
+ : (xBlueMask == 0xFF0000 ? 2 : (xBlueMask == 0xFF00 ? 1 : 0));
+ } else { /* Ardent */
+ red_shift = pixel_map[0] = xRedMask == 0xFF000000 ? 0
+ : (xRedMask == 0xFF0000 ? 1 : (xRedMask == 0xFF00 ? 2 : 3));
+ green_shift = pixel_map[0] = xGreenMask == 0xFF000000 ? 0
+ : (xGreenMask == 0xFF0000 ? 1 : (xGreenMask == 0xFF00 ? 2 : 3));
+ blue_shift = pixel_map[0] = xBlueMask == 0xFF000000 ? 0
+ : (xBlueMask == 0xFF0000 ? 1 : (xBlueMask == 0xFF00 ? 2 : 3));
+ }
+
+ if (tfPlanarConfiguration == PLANARCONFIG_CONTIG) {
+ for (i = 0; i < tfImageHeight; i++) {
+ if (TIFFReadScanline(tfFile, scan_line, i, 0) < 0)
+ break;
+ for (input_p = scan_line, j = 0; j < tfImageWidth; j++) {
+ *(output_p + red_shift) = *input_p++;
+ *(output_p + green_shift) = *input_p++;
+ *(output_p + blue_shift) = *input_p++;
+ output_p += 4;
+ if (tfSamplesPerPixel == 4) /* skip the fourth channel */
+ input_p++;
+ }
+ }
+ } else {
+ for (s = 0; s < tfSamplesPerPixel; s++) {
+ if (s == 3) /* skip the fourth channel */
+ continue;
+ for (i = 0; i < tfImageHeight; i++) {
+ if (TIFFReadScanline(tfFile, scan_line, i, s) < 0)
+ break;
+ input_p = scan_line;
+ output_p = imageMemory + (i*tfImageWidth*4) + pixel_map[s];
+ for (j = 0; j < tfImageWidth; j++, output_p += 4)
+ *output_p = *input_p++;
+ }
+ }
+ }
+ } else {
+ if (xImageDepth == tfImageDepth) {
+ output_p = imageMemory = (char *)
+ malloc(tfBytesPerRow * tfImageHeight);
+ MCHECK(imageMemory);
+
+ for (i = 0; i < tfImageHeight; i++, output_p += tfBytesPerRow)
+ if (TIFFReadScanline(tfFile, output_p, i, 0) < 0)
+ break;
+ } else if ((xImageDepth == 8) && (tfImageDepth == 4)) {
+ output_p = imageMemory = (char *)
+ malloc(tfBytesPerRow * 2 * tfImageHeight + 2);
+ MCHECK(imageMemory);
+
+ /*
+ * If a scanline is of odd size the inner loop below will overshoot.
+ * This is handled very simply by recalculating the start point at
+ * each scanline and padding imageMemory a little at the end.
+ */
+ for (i = 0; i < tfImageHeight; i++) {
+ if (TIFFReadScanline(tfFile, scan_line, i, 0) < 0)
+ break;
+ output_p = &imageMemory[i * tfImageWidth];
+ input_p = scan_line;
+ for (j = 0; j < tfImageWidth; j += 2, input_p++) {
+ *output_p++ = (*input_p >> 4) + basePixel;
+ *output_p++ = (*input_p & 0xf) + basePixel;
+ }
+ }
+ } else if ((xImageDepth == 8) && (tfImageDepth == 2)) {
+ output_p = imageMemory = (char *)
+ malloc(tfBytesPerRow * 4 * tfImageHeight + 4);
+ MCHECK(imageMemory);
+
+ for (i = 0; i < tfImageHeight; i++) {
+ if (TIFFReadScanline(tfFile, scan_line, i, 0) < 0)
+ break;
+ output_p = &imageMemory[i * tfImageWidth];
+ input_p = scan_line;
+ for (j = 0; j < tfImageWidth; j += 4, input_p++) {
+ *output_p++ = (*input_p >> 6) + basePixel;
+ *output_p++ = ((*input_p >> 4) & 3) + basePixel;
+ *output_p++ = ((*input_p >> 2) & 3) + basePixel;
+ *output_p++ = (*input_p & 3) + basePixel;
+ }
+ }
+ } else if ((xImageDepth == 4) && (tfImageDepth == 2)) {
+ output_p = imageMemory = (char *)
+ malloc(tfBytesPerRow * 2 * tfImageHeight + 2);
+ MCHECK(imageMemory);
+
+ for (i = 0; i < tfImageHeight; i++) {
+ if (TIFFReadScanline(tfFile, scan_line, i, 0) < 0)
+ break;
+ output_p = &imageMemory[i * tfBytesPerRow * 2];
+ input_p = scan_line;
+ for (j = 0; j < tfImageWidth; j += 4, input_p++) {
+ *output_p++ = (((*input_p>>6) << 4)
+ | ((*input_p >> 4) & 3)) + basePixel;
+ *output_p++ = ((((*input_p>>2) & 3) << 4)
+ | (*input_p & 3)) + basePixel;
+ }
+ }
+ } else {
+ fprintf(stderr,
+ "xtiff: can't handle %d-bit TIFF file on an %d-bit display\n",
+ tfImageDepth, xImageDepth);
+ exit(0);
+ }
+ }
+
+ free(scan_line);
+}
+
+void
+CreateXImage()
+{
+ XGCValues gc_values;
+ GC bitmap_gc;
+
+ xOffset = yOffset = 0;
+ grabX = grabY = -1;
+
+ xImage = XCreateImage(xDisplay, xVisual, xImageDepth,
+ xImageDepth == 1 ? XYBitmap : ZPixmap, /* offset */ 0,
+ (char *) imageMemory, tfImageWidth, tfImageHeight,
+ /* bitmap_pad */ 8, /* bytes_per_line */ 0);
+
+ /*
+ * libtiff converts LSB data into MSB but doesn't change the FillOrder tag.
+ */
+ if (xImageDepth == 1)
+ xImage->bitmap_bit_order = MSBFirst;
+ if (xImageDepth <= 8)
+ xImage->byte_order = MSBFirst;
+
+ /*
+ * create an appropriate GC
+ */
+ gc_values.function = GXcopy;
+ gc_values.plane_mask = AllPlanes;
+ if (tfPhotometricInterpretation == PHOTOMETRIC_MINISBLACK) {
+ gc_values.foreground = XWhitePixel(xDisplay, xScreen);
+ gc_values.background = XBlackPixel(xDisplay, xScreen);
+ } else {
+ gc_values.foreground = XBlackPixel(xDisplay, xScreen);
+ gc_values.background = XWhitePixel(xDisplay, xScreen);
+ }
+ xWinGc = XCreateGC(xDisplay, XtWindow(shellWidget),
+ GCFunction | GCPlaneMask | GCForeground | GCBackground, &gc_values);
+
+ /*
+ * create the pixmap and load the image
+ */
+ if (appData.usePixmap == True) {
+ xImagePixmap = XCreatePixmap(xDisplay, RootWindow(xDisplay, xScreen),
+ xImage->width, xImage->height, xImageDepth);
+
+ /*
+ * According to the O'Reilly X Protocol Reference Manual, page 53,
+ * "A pixmap depth of one is always supported and listed, but windows
+ * of depth one might not be supported." Therefore we create a pixmap
+ * of depth one and use XCopyPlane(). This is idiomatic.
+ */
+ if (xImageDepth == 1) { /* just pass the bits through */
+ gc_values.foreground = 1; /* foreground describes set bits */
+ gc_values.background = 0; /* background describes clear bits */
+ bitmap_gc = XCreateGC(xDisplay, xImagePixmap,
+ GCForeground | GCBackground, &gc_values);
+ XPutImage(xDisplay, xImagePixmap, bitmap_gc, xImage,
+ 0, 0, 0, 0, xImage->width, xImage->height);
+ } else
+ XPutImage(xDisplay, xImagePixmap, xWinGc, xImage,
+ 0, 0, 0, 0, xImage->width, xImage->height);
+ XDestroyImage(xImage);
+ free(imageMemory);
+ }
+}
+
+XtCallbackProc
+SelectProc(w, unused_1, unused_2)
+ Widget w;
+ caddr_t unused_1;
+ caddr_t unused_2;
+{
+ XawListReturnStruct *list_return;
+
+ list_return = XawListShowCurrent(w);
+
+ switch (list_return->list_index) {
+ case ButtonQuit:
+ QuitProc();
+ break;
+ case ButtonPreviousPage:
+ PreviousProc();
+ break;
+ case ButtonNextPage:
+ NextProc();
+ break;
+ default:
+ fprintf(stderr, "error in SelectProc\n");
+ exit(0);
+ }
+ XawListUnhighlight(w);
+}
+
+void
+QuitProc(void)
+{
+ exit(0);
+}
+
+void
+NextProc()
+{
+ PageProc(ButtonNextPage);
+}
+
+void
+PreviousProc()
+{
+ PageProc(ButtonPreviousPage);
+}
+
+void
+PageProc(direction)
+ int direction;
+{
+ XEvent fake_event;
+ Arg args[4];
+
+ switch (direction) {
+ case ButtonPreviousPage:
+ if (tfDirectory > 0)
+ TIFFSetDirectory(tfFile, --tfDirectory);
+ else
+ return;
+ break;
+ case ButtonNextPage:
+ if (TIFFReadDirectory(tfFile) == True)
+ tfDirectory++;
+ else
+ return;
+ break;
+ default:
+ fprintf(stderr, "error in PageProc\n");
+ exit(0);
+ }
+
+ xOffset = yOffset = 0;
+ grabX = grabY = -1;
+
+ GetTIFFHeader();
+ SetNameLabel();
+ GetTIFFImage();
+
+ if (appData.usePixmap == True)
+ XFreePixmap(xDisplay, xImagePixmap);
+ else
+ XDestroyImage(xImage);
+
+ CreateXImage();
+
+ /*
+ * Using XtSetValues() to set the widget size causes a resize.
+ * This resize gets propagated up to the parent shell.
+ * In order to disable this visually disconcerting effect,
+ * shell resizing is temporarily disabled.
+ */
+ XtSetArg(args[0], XtNallowShellResize, False);
+ XtSetValues(shellWidget, args, 1);
+
+ XtSetArg(args[0], XtNwidth, tfImageWidth);
+ XtSetArg(args[1], XtNheight, tfImageHeight);
+ XtSetValues(imageWidget, args, 2);
+
+ XtSetArg(args[0], XtNallowShellResize, True);
+ XtSetValues(shellWidget, args, 1);
+
+ XClearWindow(xDisplay, XtWindow(imageWidget));
+
+ fake_event.type = Expose;
+ fake_event.xexpose.x = fake_event.xexpose.y = 0;
+ fake_event.xexpose.width = tfImageWidth; /* the window will clip */
+ fake_event.xexpose.height = tfImageHeight;
+ EventProc(imageWidget, NULL, &fake_event);
+}
+
+void
+EventProc(widget, unused, event)
+ Widget widget;
+ caddr_t unused;
+ XEvent *event;
+{
+ int ih, iw, ww, wh, sx, sy, w, h, dx, dy;
+ Dimension w_width, w_height;
+ XEvent next_event;
+ Arg args[2];
+
+ if (event->type == MappingNotify) {
+ XRefreshKeyboardMapping((XMappingEvent *) event);
+ return;
+ }
+
+ if (!XtIsRealized(widget))
+ return;
+
+ if ((event->type == ButtonPress) || (event->type == ButtonRelease))
+ if (event->xbutton.button != Button1)
+ return;
+
+ iw = tfImageWidth; /* avoid sign problems */
+ ih = tfImageHeight;
+
+ /*
+ * The grabX and grabY variables record where the user grabbed the image.
+ * They also record whether the mouse button is down or not.
+ */
+ if (event->type == ButtonPress) {
+ grabX = event->xbutton.x;
+ grabY = event->xbutton.y;
+ return;
+ }
+
+ /*
+ * imageWidget is a Core widget and doesn't get resized.
+ * So we calculate the size of its viewport here.
+ */
+ XtSetArg(args[0], XtNwidth, &w_width);
+ XtSetArg(args[1], XtNheight, &w_height);
+ XtGetValues(shellWidget, args, 2);
+ ww = w_width;
+ wh = w_height;
+ XtGetValues(listWidget, args, 2);
+ wh -= w_height;
+
+ switch (event->type) {
+ case Expose:
+ dx = event->xexpose.x;
+ dy = event->xexpose.y;
+ sx = dx + xOffset;
+ sy = dy + yOffset;
+ w = MIN(event->xexpose.width, iw);
+ h = MIN(event->xexpose.height, ih);
+ break;
+ case KeyPress:
+ if ((grabX >= 0) || (grabY >= 0)) /* Mouse button is still down */
+ return;
+ switch (XLookupKeysym((XKeyEvent *) event, /* KeySyms index */ 0)) {
+ case XK_Up:
+ if (ih < wh) /* Don't scroll if the window fits the image. */
+ return;
+ sy = yOffset + appData.translate;
+ sy = MIN(ih - wh, sy);
+ if (sy == yOffset) /* Filter redundant stationary refreshes. */
+ return;
+ yOffset = sy;
+ sx = xOffset;
+ dx = dy = 0;
+ w = ww; h = wh;
+ break;
+ case XK_Down:
+ if (ih < wh)
+ return;
+ sy = yOffset - appData.translate;
+ sy = MAX(sy, 0);
+ if (sy == yOffset)
+ return;
+ yOffset = sy;
+ sx = xOffset;
+ dx = dy = 0;
+ w = ww; h = wh;
+ break;
+ case XK_Left:
+ if (iw < ww)
+ return;
+ sx = xOffset + appData.translate;
+ sx = MIN(iw - ww, sx);
+ if (sx == xOffset)
+ return;
+ xOffset = sx;
+ sy = yOffset;
+ dx = dy = 0;
+ w = ww; h = wh;
+ break;
+ case XK_Right:
+ if (iw < ww)
+ return;
+ sx = xOffset - appData.translate;
+ sx = MAX(sx, 0);
+ if (sx == xOffset)
+ return;
+ xOffset = sx;
+ sy = yOffset;
+ dx = dy = 0;
+ w = ww; h = wh;
+ break;
+ default:
+ return;
+ }
+ break;
+ case MotionNotify:
+ /*
+ * MotionEvent compression. Ignore multiple motion events.
+ * Ignore motion events if the mouse button is up.
+ */
+ if (XPending(xDisplay)) /* Xlib doesn't flush the output buffer */
+ if (XtPeekEvent(&next_event))
+ if (next_event.type == MotionNotify)
+ return;
+ if ((grabX < 0) || (grabY < 0))
+ return;
+ sx = xOffset + grabX - (int) event->xmotion.x;
+ if (sx >= (iw - ww)) /* clamp x motion but allow y motion */
+ sx = iw - ww;
+ sx = MAX(sx, 0);
+ sy = yOffset + grabY - (int) event->xmotion.y;
+ if (sy >= (ih - wh)) /* clamp y motion but allow x motion */
+ sy = ih - wh;
+ sy = MAX(sy, 0);
+ if ((sx == xOffset) && (sy == yOffset))
+ return;
+ dx = dy = 0;
+ w = ww; h = wh;
+ break;
+ case ButtonRelease:
+ xOffset = xOffset + grabX - (int) event->xbutton.x;
+ xOffset = MIN(iw - ww, xOffset);
+ xOffset = MAX(xOffset, 0);
+ yOffset = yOffset + grabY - (int) event->xbutton.y;
+ yOffset = MIN(ih - wh, yOffset);
+ yOffset = MAX(yOffset, 0);
+ grabX = grabY = -1;
+ default:
+ return;
+ }
+
+ if (appData.usePixmap == True) {
+ if (xImageDepth == 1)
+ XCopyPlane(xDisplay, xImagePixmap, XtWindow(widget),
+ xWinGc, sx, sy, w, h, dx, dy, 1);
+ else
+ XCopyArea(xDisplay, xImagePixmap, XtWindow(widget),
+ xWinGc, sx, sy, w, h, dx, dy);
+ } else
+ XPutImage(xDisplay, XtWindow(widget), xWinGc, xImage,
+ sx, sy, dx, dy, w, h);
+}
+
+void
+ResizeProc()
+{
+ Dimension w_width, w_height;
+ int xo, yo, ww, wh;
+ XEvent fake_event;
+ Arg args[2];
+
+ if ((xOffset == 0) && (yOffset == 0))
+ return;
+
+ XtSetArg(args[0], XtNwidth, &w_width);
+ XtSetArg(args[1], XtNheight, &w_height);
+ XtGetValues(shellWidget, args, 2);
+ ww = w_width;
+ wh = w_height;
+ XtGetValues(listWidget, args, 2);
+ wh -= w_height;
+
+ xo = xOffset; yo = yOffset;
+
+ if ((xOffset + ww) >= tfImageWidth)
+ xOffset = MAX((int) tfImageWidth - ww, 0);
+ if ((yOffset + wh) >= tfImageHeight)
+ yOffset = MAX((int) tfImageHeight - wh, 0);
+
+ /*
+ * Send an ExposeEvent if the origin changed.
+ * We have to do this because of the use and semantics of bit gravity.
+ */
+ if ((xo != xOffset) || (yo != yOffset)) {
+ fake_event.type = Expose;
+ fake_event.xexpose.x = fake_event.xexpose.y = 0;
+ fake_event.xexpose.width = tfImageWidth;
+ fake_event.xexpose.height = tfImageHeight;
+ EventProc(imageWidget, NULL, &fake_event);
+ }
+}
+
+int
+XTiffErrorHandler(display, error_event)
+ Display *display;
+ XErrorEvent *error_event;
+{
+ char message[80];
+
+ /*
+ * Some X servers limit the size of pixmaps.
+ */
+ if ((error_event->error_code == BadAlloc)
+ && (error_event->request_code == X_CreatePixmap))
+ fprintf(stderr, "xtiff: requested pixmap too big for display\n");
+ else {
+ XGetErrorText(display, error_event->error_code, message, 80);
+ fprintf(stderr, "xtiff: error code %s\n", message);
+ }
+
+ exit(0);
+}
+
+void
+Usage()
+{
+ fprintf(stderr, "Usage xtiff: [options] tiff-file\n");
+ fprintf(stderr, "\tstandard Xt options\n");
+ fprintf(stderr, "\t[-help]\n");
+ fprintf(stderr, "\t[-gamma gamma]\n");
+ fprintf(stderr, "\t[-usePixmap (True | False)]\n");
+ fprintf(stderr, "\t[-viewportWidth pixels]\n");
+ fprintf(stderr, "\t[-viewportHeight pixels]\n");
+ fprintf(stderr, "\t[-translate pixels]\n");
+ fprintf(stderr, "\t[-verbose (True | False)]\n");
+ exit(0);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/dbs/xtiff/xtifficon.h b/tiff/contrib/dbs/xtiff/xtifficon.h
new file mode 100644
index 0000000..3eac48e
--- /dev/null
+++ b/tiff/contrib/dbs/xtiff/xtifficon.h
@@ -0,0 +1,21 @@
+#define xtifficon_width 32
+#define xtifficon_height 32
+static char xtifficon_bits[] = {
+ 0xff, 0x00, 0x00, 0xc0, 0xfe, 0x01, 0x7e, 0xc0, 0xfc, 0x03, 0x7e, 0x60,
+ 0xf8, 0x07, 0x06, 0x30, 0xf8, 0x07, 0x1e, 0x18, 0xf0, 0x0f, 0x1e, 0x0c,
+ 0xe0, 0x1f, 0x06, 0x06, 0xc0, 0x3f, 0x06, 0x06, 0xc0, 0x3f, 0x06, 0x03,
+ 0x80, 0x7f, 0x80, 0x01, 0x00, 0xff, 0xc0, 0x00, 0x00, 0xfe, 0x61, 0x00,
+ 0x00, 0xfe, 0x31, 0x7e, 0x7e, 0xfc, 0x33, 0x7e, 0x7e, 0xf8, 0x1b, 0x06,
+ 0x18, 0xf0, 0x0d, 0x1e, 0x18, 0xf0, 0x0e, 0x1e, 0x18, 0x60, 0x1f, 0x06,
+ 0x18, 0xb0, 0x3f, 0x06, 0x18, 0x98, 0x7f, 0x06, 0x18, 0x98, 0x7f, 0x00,
+ 0x00, 0x0c, 0xff, 0x00, 0x00, 0x06, 0xfe, 0x01, 0x00, 0x63, 0xfc, 0x03,
+ 0x80, 0x61, 0xfc, 0x03, 0xc0, 0x60, 0xf8, 0x07, 0xc0, 0x60, 0xf0, 0x0f,
+ 0x60, 0x60, 0xe0, 0x1f, 0x30, 0x60, 0xe0, 0x1f, 0x18, 0x60, 0xc0, 0x3f,
+ 0x0c, 0x60, 0x80, 0x7f, 0x06, 0x00, 0x00, 0xff};
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/iptcutil/Makefile.am b/tiff/contrib/iptcutil/Makefile.am
new file mode 100644
index 0000000..9b94ed7
--- /dev/null
+++ b/tiff/contrib/iptcutil/Makefile.am
@@ -0,0 +1,36 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+
+EXTRA_DIST = README test.iptc test.txt
+
+noinst_PROGRAMS = iptcutil
+
+iptcutil_SOURCES = iptcutil.c
+iptcutil_LDADD = $(LIBTIFF)
+
+INCLUDES = -I$(top_srcdir)/libtiff
+
diff --git a/tiff/contrib/iptcutil/Makefile.in b/tiff/contrib/iptcutil/Makefile.in
new file mode 100644
index 0000000..6207a44
--- /dev/null
+++ b/tiff/contrib/iptcutil/Makefile.in
@@ -0,0 +1,553 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+noinst_PROGRAMS = iptcutil$(EXEEXT)
+subdir = contrib/iptcutil
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+PROGRAMS = $(noinst_PROGRAMS)
+am_iptcutil_OBJECTS = iptcutil.$(OBJEXT)
+iptcutil_OBJECTS = $(am_iptcutil_OBJECTS)
+iptcutil_DEPENDENCIES = $(LIBTIFF)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libtiff
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(iptcutil_SOURCES)
+DIST_SOURCES = $(iptcutil_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+EXTRA_DIST = README test.iptc test.txt
+iptcutil_SOURCES = iptcutil.c
+iptcutil_LDADD = $(LIBTIFF)
+INCLUDES = -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/iptcutil/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/iptcutil/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+iptcutil$(EXEEXT): $(iptcutil_OBJECTS) $(iptcutil_DEPENDENCIES)
+ @rm -f iptcutil$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(iptcutil_OBJECTS) $(iptcutil_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iptcutil.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstPROGRAMS ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/iptcutil/README b/tiff/contrib/iptcutil/README
new file mode 100644
index 0000000..1619ef4
--- /dev/null
+++ b/tiff/contrib/iptcutil/README
@@ -0,0 +1,25 @@
+
+Program: IPTCUTIL.C
+
+Purpose: Convert between IPTC binary and a "special" IPTC text file format.
+
+Usage: iptcutil -t | -b [-i file] [-o file] <input >output
+
+Notes: You tell the program the "type" of input file via the -t and -b
+ switches. The -t says that the input is text, while the -b says
+ that the input is binary IPTC. You can use either the -i or the
+ -o switches to tell the program what the input and output files
+ will be, or use simple piping.
+
+Author: William T. Radcliffe (billr@corbis.com)
+ Parts of this program were derived from other places. The original
+ binary to text conversion was taken from the PHP distribution and
+ the tokenizer was written many years ago, by someone else as well.
+
+This software is provided freely "as is", without warranty of any kind,
+express or implied, including but not limited to the warranties of
+merchantability, fitness for a particular purpose and noninfringement.
+In no event shall William T. Radcliffe be liable for any claim, damages or
+other liability, whether in an action of contract, tort or otherwise,
+arising from, out of or in connection with IPTCUTIL
+
diff --git a/tiff/contrib/iptcutil/iptcutil.c b/tiff/contrib/iptcutil/iptcutil.c
new file mode 100644
index 0000000..557a67e
--- /dev/null
+++ b/tiff/contrib/iptcutil/iptcutil.c
@@ -0,0 +1,941 @@
+/* $Id: iptcutil.c,v 1.4.2.2 2010-06-08 18:50:41 bfriesen Exp $ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef WIN32
+#define STRNICMP strnicmp
+#else
+#define STRNICMP strncasecmp
+#endif
+
+typedef struct _tag_spec
+{
+ short
+ id;
+
+ char
+ *name;
+} tag_spec;
+
+static tag_spec tags[] = {
+ { 5,"Image Name" },
+ { 7,"Edit Status" },
+ { 10,"Priority" },
+ { 15,"Category" },
+ { 20,"Supplemental Category" },
+ { 22,"Fixture Identifier" },
+ { 25,"Keyword" },
+ { 30,"Release Date" },
+ { 35,"Release Time" },
+ { 40,"Special Instructions" },
+ { 45,"Reference Service" },
+ { 47,"Reference Date" },
+ { 50,"Reference Number" },
+ { 55,"Created Date" },
+ { 60,"Created Time" },
+ { 65,"Originating Program" },
+ { 70,"Program Version" },
+ { 75,"Object Cycle" },
+ { 80,"Byline" },
+ { 85,"Byline Title" },
+ { 90,"City" },
+ { 95,"Province State" },
+ { 100,"Country Code" },
+ { 101,"Country" },
+ { 103,"Original Transmission Reference" },
+ { 105,"Headline" },
+ { 110,"Credit" },
+ { 115,"Source" },
+ { 116,"Copyright String" },
+ { 120,"Caption" },
+ { 121,"Local Caption" },
+ { 122,"Caption Writer" },
+ { 200,"Custom Field 1" },
+ { 201,"Custom Field 2" },
+ { 202,"Custom Field 3" },
+ { 203,"Custom Field 4" },
+ { 204,"Custom Field 5" },
+ { 205,"Custom Field 6" },
+ { 206,"Custom Field 7" },
+ { 207,"Custom Field 8" },
+ { 208,"Custom Field 9" },
+ { 209,"Custom Field 10" },
+ { 210,"Custom Field 11" },
+ { 211,"Custom Field 12" },
+ { 212,"Custom Field 13" },
+ { 213,"Custom Field 14" },
+ { 214,"Custom Field 15" },
+ { 215,"Custom Field 16" },
+ { 216,"Custom Field 17" },
+ { 217,"Custom Field 18" },
+ { 218,"Custom Field 19" },
+ { 219,"Custom Field 20" }
+};
+
+/*
+ * We format the output using HTML conventions
+ * to preserve control characters and such.
+ */
+void formatString(FILE *ofile, const char *s, int len)
+{
+ putc('"', ofile);
+ for (; len > 0; --len, ++s) {
+ int c = *s;
+ switch (c) {
+ case '&':
+ fputs("&amp;", ofile);
+ break;
+#ifdef HANDLE_GT_LT
+ case '<':
+ fputs("&lt;", ofile);
+ break;
+ case '>':
+ fputs("&gt;", ofile);
+ break;
+#endif
+ case '"':
+ fputs("&quot;", ofile);
+ break;
+ default:
+ if (iscntrl(c))
+ fprintf(ofile, "&#%d;", c);
+ else
+ putc(*s, ofile);
+ break;
+ }
+ }
+ fputs("\"\n", ofile);
+}
+
+typedef struct _html_code
+{
+ short
+ len;
+ const char
+ *code,
+ val;
+} html_code;
+
+static html_code html_codes[] = {
+#ifdef HANDLE_GT_LT
+ { 4,"&lt;",'<' },
+ { 4,"&gt;",'>' },
+#endif
+ { 5,"&amp;",'&' },
+ { 6,"&quot;",'"' }
+};
+
+/*
+ * This routine converts HTML escape sequence
+ * back to the original ASCII representation.
+ * - returns the number of characters dropped.
+ */
+int convertHTMLcodes(char *s, int len)
+{
+ if (len <=0 || s==(char*)NULL || *s=='\0')
+ return 0;
+
+ if (s[1] == '#')
+ {
+ int val, o;
+
+ if (sscanf(s,"&#%d;",&val) == 1)
+ {
+ o = 3;
+ while (s[o] != ';')
+ {
+ o++;
+ if (o > 5)
+ break;
+ }
+ if (o < 5)
+ strcpy(s+1, s+1+o);
+ *s = val;
+ return o;
+ }
+ }
+ else
+ {
+ int
+ i,
+ codes = sizeof(html_codes) / sizeof(html_code);
+
+ for (i=0; i < codes; i++)
+ {
+ if (html_codes[i].len <= len)
+ if (STRNICMP(s, html_codes[i].code, html_codes[i].len) == 0)
+ {
+ strcpy(s+1, s+html_codes[i].len);
+ *s = html_codes[i].val;
+ return html_codes[i].len-1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int formatIPTC(FILE *ifile, FILE *ofile)
+{
+ unsigned int
+ foundiptc,
+ tagsfound;
+
+ unsigned char
+ recnum,
+ dataset;
+
+ char
+ *readable,
+ *str;
+
+ long
+ tagindx,
+ taglen;
+
+ int
+ i,
+ tagcount = sizeof(tags) / sizeof(tag_spec);
+
+ char
+ c;
+
+ foundiptc = 0; /* found the IPTC-Header */
+ tagsfound = 0; /* number of tags found */
+
+ c = getc(ifile);
+ while (c != EOF)
+ {
+ if (c == 0x1c)
+ foundiptc = 1;
+ else
+ {
+ if (foundiptc)
+ return -1;
+ else
+ continue;
+ }
+
+ /* we found the 0x1c tag and now grab the dataset and record number tags */
+ dataset = getc(ifile);
+ if ((char) dataset == EOF)
+ return -1;
+ recnum = getc(ifile);
+ if ((char) recnum == EOF)
+ return -1;
+ /* try to match this record to one of the ones in our named table */
+ for (i=0; i< tagcount; i++)
+ {
+ if (tags[i].id == recnum)
+ break;
+ }
+ if (i < tagcount)
+ readable = tags[i].name;
+ else
+ readable = "";
+
+ /* then we decode the length of the block that follows - long or short fmt */
+ c = getc(ifile);
+ if (c == EOF)
+ return 0;
+ if (c & (unsigned char) 0x80)
+ {
+ unsigned char
+ buffer[4];
+
+ for (i=0; i<4; i++)
+ {
+ c = buffer[i] = getc(ifile);
+ if (c == EOF)
+ return -1;
+ }
+ taglen = (((long) buffer[ 0 ]) << 24) |
+ (((long) buffer[ 1 ]) << 16) |
+ (((long) buffer[ 2 ]) << 8) |
+ (((long) buffer[ 3 ]));
+ }
+ else
+ {
+ unsigned char
+ x = c;
+
+ taglen = ((long) x) << 8;
+ x = getc(ifile);
+ if ((char)x == EOF)
+ return -1;
+ taglen |= (long) x;
+ }
+ /* make a buffer to hold the tag data and snag it from the input stream */
+ str = (char *) malloc((unsigned int) (taglen+1));
+ if (str == (char *) NULL)
+ {
+ printf("Memory allocation failed");
+ return 0;
+ }
+ for (tagindx=0; tagindx<taglen; tagindx++)
+ {
+ c = str[tagindx] = getc(ifile);
+ if (c == EOF)
+ return -1;
+ }
+ str[ taglen ] = 0;
+
+ /* now finish up by formatting this binary data into ASCII equivalent */
+ if (strlen(readable) > 0)
+ fprintf(ofile, "%d#%d#%s=",(unsigned int)dataset, (unsigned int) recnum, readable);
+ else
+ fprintf(ofile, "%d#%d=",(unsigned int)dataset, (unsigned int) recnum);
+ formatString( ofile, str, taglen );
+ free(str);
+
+ tagsfound++;
+
+ c = getc(ifile);
+ }
+ return tagsfound;
+}
+
+int tokenizer(unsigned inflag,char *token,int tokmax,char *line,
+char *white,char *brkchar,char *quote,char eschar,char *brkused,
+int *next,char *quoted);
+
+char *super_fgets(char *b, int *blen, FILE *file)
+{
+ int
+ c,
+ len;
+
+ char
+ *q;
+
+ len=*blen;
+ for (q=b; ; q++)
+ {
+ c=fgetc(file);
+ if (c == EOF || c == '\n')
+ break;
+ if (((int)q - (int)b + 1 ) >= (int) len)
+ {
+ int
+ tlen;
+
+ tlen=(int)q-(int)b;
+ len<<=1;
+ b=(char *) realloc((char *) b,(len+2));
+ if ((char *) b == (char *) NULL)
+ break;
+ q=b+tlen;
+ }
+ *q=(unsigned char) c;
+ }
+ *blen=0;
+ if ((unsigned char *)b != (unsigned char *) NULL)
+ {
+ int
+ tlen;
+
+ tlen=(int)q - (int)b;
+ if (tlen == 0)
+ return (char *) NULL;
+ b[tlen] = '\0';
+ *blen=++tlen;
+ }
+ return b;
+}
+
+#define BUFFER_SZ 4096
+
+int main(int argc, char *argv[])
+{
+ unsigned int
+ length;
+
+ unsigned char
+ *buffer;
+
+ int
+ i,
+ mode; /* iptc binary, or iptc text */
+
+ FILE
+ *ifile = stdin,
+ *ofile = stdout;
+
+ char
+ c,
+ *usage = "usage: iptcutil -t | -b [-i file] [-o file] <input >output";
+
+ if( argc < 2 )
+ {
+ printf("%s\n", usage);
+ return 1;
+ }
+
+ mode = 0;
+ length = -1;
+ buffer = (unsigned char *)NULL;
+
+ for (i=1; i<argc; i++)
+ {
+ c = argv[i][0];
+ if (c == '-' || c == '/')
+ {
+ c = argv[i][1];
+ switch( c )
+ {
+ case 't':
+ mode = 1;
+#ifdef WIN32
+ /* Set "stdout" to binary mode: */
+ _setmode( _fileno( ofile ), _O_BINARY );
+#endif
+ break;
+ case 'b':
+ mode = 0;
+#ifdef WIN32
+ /* Set "stdin" to binary mode: */
+ _setmode( _fileno( ifile ), _O_BINARY );
+#endif
+ break;
+ case 'i':
+ if (mode == 0)
+ ifile = fopen(argv[++i], "rb");
+ else
+ ifile = fopen(argv[++i], "rt");
+ if (ifile == (FILE *)NULL)
+ {
+ printf("Unable to open: %s\n", argv[i]);
+ return 1;
+ }
+ break;
+ case 'o':
+ if (mode == 0)
+ ofile = fopen(argv[++i], "wt");
+ else
+ ofile = fopen(argv[++i], "wb");
+ if (ofile == (FILE *)NULL)
+ {
+ printf("Unable to open: %s\n", argv[i]);
+ return 1;
+ }
+ break;
+ default:
+ printf("Unknown option: %s\n", argv[i]);
+ return 1;
+ }
+ }
+ else
+ {
+ printf("%s\n", usage);
+ return 1;
+ }
+ }
+
+ if (mode == 0) /* handle binary iptc info */
+ formatIPTC(ifile, ofile);
+
+ if (mode == 1) /* handle text form of iptc info */
+ {
+ char
+ brkused,
+ quoted,
+ *line,
+ *token,
+ *newstr;
+
+ int
+ state,
+ next;
+
+ unsigned char
+ recnum = 0,
+ dataset = 0;
+
+ int
+ inputlen = BUFFER_SZ;
+
+ line = (char *) malloc(inputlen);
+ token = (char *)NULL;
+ while((line = super_fgets(line,&inputlen,ifile))!=NULL)
+ {
+ state=0;
+ next=0;
+
+ token = (char *) malloc(inputlen);
+ newstr = (char *) malloc(inputlen);
+ while(tokenizer(0, token, inputlen, line, "", "=", "\"", 0,
+ &brkused,&next,&quoted)==0)
+ {
+ if (state == 0)
+ {
+ int
+ state,
+ next;
+
+ char
+ brkused,
+ quoted;
+
+ state=0;
+ next=0;
+ while(tokenizer(0, newstr, inputlen, token, "", "#", "", 0,
+ &brkused, &next, &quoted)==0)
+ {
+ if (state == 0)
+ dataset = (unsigned char) atoi(newstr);
+ else
+ if (state == 1)
+ recnum = (unsigned char) atoi(newstr);
+ state++;
+ }
+ }
+ else
+ if (state == 1)
+ {
+ int
+ next;
+
+ unsigned long
+ len;
+
+ char
+ brkused,
+ quoted;
+
+ next=0;
+ len = strlen(token);
+ while(tokenizer(0, newstr, inputlen, token, "", "&", "", 0,
+ &brkused, &next, &quoted)==0)
+ {
+ if (brkused && next > 0)
+ {
+ char
+ *s = &token[next-1];
+
+ len -= convertHTMLcodes(s, strlen(s));
+ }
+ }
+
+ fputc(0x1c, ofile);
+ fputc(dataset, ofile);
+ fputc(recnum, ofile);
+ if (len < 0x10000)
+ {
+ fputc((len >> 8) & 255, ofile);
+ fputc(len & 255, ofile);
+ }
+ else
+ {
+ fputc(((len >> 24) & 255) | 0x80, ofile);
+ fputc((len >> 16) & 255, ofile);
+ fputc((len >> 8) & 255, ofile);
+ fputc(len & 255, ofile);
+ }
+ next=0;
+ while (len--)
+ fputc(token[next++], ofile);
+ }
+ state++;
+ }
+ free(token);
+ token = (char *)NULL;
+ free(newstr);
+ newstr = (char *)NULL;
+ }
+ free(line);
+
+ fclose( ifile );
+ fclose( ofile );
+ }
+
+ return 0;
+}
+
+/*
+ This routine is a generalized, finite state token parser. It allows
+ you extract tokens one at a time from a string of characters. The
+ characters used for white space, for break characters, and for quotes
+ can be specified. Also, characters in the string can be preceded by
+ a specifiable escape character which removes any special meaning the
+ character may have.
+
+ There are a lot of formal parameters in this subroutine call, but
+ once you get familiar with them, this routine is fairly easy to use.
+ "#define" macros can be used to generate simpler looking calls for
+ commonly used applications of this routine.
+
+ First, some terminology:
+
+ token: used here, a single unit of information in
+ the form of a group of characters.
+
+ white space: space that gets ignored (except within quotes
+ or when escaped), like blanks and tabs. in
+ addition, white space terminates a non-quoted
+ token.
+
+ break character: a character that separates non-quoted tokens.
+ commas are a common break character. the
+ usage of break characters to signal the end
+ of a token is the same as that of white space,
+ except multiple break characters with nothing
+ or only white space between generate a null
+ token for each two break characters together.
+
+ for example, if blank is set to be the white
+ space and comma is set to be the break
+ character, the line ...
+
+ A, B, C , , DEF
+
+ ... consists of 5 tokens:
+
+ 1) "A"
+ 2) "B"
+ 3) "C"
+ 4) "" (the null string)
+ 5) "DEF"
+
+ quote character: a character that, when surrounding a group
+ of other characters, causes the group of
+ characters to be treated as a single token,
+ no matter how many white spaces or break
+ characters exist in the group. also, a
+ token always terminates after the closing
+ quote. for example, if ' is the quote
+ character, blank is white space, and comma
+ is the break character, the following
+ string ...
+
+ A, ' B, CD'EF GHI
+
+ ... consists of 4 tokens:
+
+ 1) "A"
+ 2) " B, CD" (note the blanks & comma)
+ 3) "EF"
+ 4) "GHI"
+
+ the quote characters themselves do
+ not appear in the resultant tokens. the
+ double quotes are delimiters i use here for
+ documentation purposes only.
+
+ escape character: a character which itself is ignored but
+ which causes the next character to be
+ used as is. ^ and \ are often used as
+ escape characters. an escape in the last
+ position of the string gets treated as a
+ "normal" (i.e., non-quote, non-white,
+ non-break, and non-escape) character.
+ for example, assume white space, break
+ character, and quote are the same as in the
+ above examples, and further, assume that
+ ^ is the escape character. then, in the
+ string ...
+
+ ABC, ' DEF ^' GH' I ^ J K^ L ^
+
+ ... there are 7 tokens:
+
+ 1) "ABC"
+ 2) " DEF ' GH"
+ 3) "I"
+ 4) " " (a lone blank)
+ 5) "J"
+ 6) "K L"
+ 7) "^" (passed as is at end of line)
+
+
+ OK, now that you have this background, here's how to call "tokenizer":
+
+ result=tokenizer(flag,token,maxtok,string,white,break,quote,escape,
+ brkused,next,quoted)
+
+ result: 0 if we haven't reached EOS (end of string), and
+ 1 if we have (this is an "int").
+
+ flag: right now, only the low order 3 bits are used.
+ 1 => convert non-quoted tokens to upper case
+ 2 => convert non-quoted tokens to lower case
+ 0 => do not convert non-quoted tokens
+ (this is a "char").
+
+ token: a character string containing the returned next token
+ (this is a "char[]").
+
+ maxtok: the maximum size of "token". characters beyond
+ "maxtok" are truncated (this is an "int").
+
+ string: the string to be parsed (this is a "char[]").
+
+ white: a string of the valid white spaces. example:
+
+ char whitesp[]={" \t"};
+
+ blank and tab will be valid white space (this is
+ a "char[]").
+
+ break: a string of the valid break characters. example:
+
+ char breakch[]={";,"};
+
+ semicolon and comma will be valid break characters
+ (this is a "char[]").
+
+ IMPORTANT: do not use the name "break" as a C
+ variable, as this is a reserved word in C.
+
+ quote: a string of the valid quote characters. an example
+ would be
+
+ char whitesp[]={"'\"");
+
+ (this causes single and double quotes to be valid)
+ note that a token starting with one of these characters
+ needs the same quote character to terminate it.
+
+ for example,
+
+ "ABC '
+
+ is unterminated, but
+
+ "DEF" and 'GHI'
+
+ are properly terminated. note that different quote
+ characters can appear on the same line; only for
+ a given token do the quote characters have to be
+ the same (this is a "char[]").
+
+ escape: the escape character (NOT a string ... only one
+ allowed). use zero if none is desired (this is
+ a "char").
+
+ brkused: the break character used to terminate the current
+ token. if the token was quoted, this will be the
+ quote used. if the token is the last one on the
+ line, this will be zero (this is a pointer to a
+ "char").
+
+ next: this variable points to the first character of the
+ next token. it gets reset by "tokenizer" as it steps
+ through the string. set it to 0 upon initialization,
+ and leave it alone after that. you can change it
+ if you want to jump around in the string or re-parse
+ from the beginning, but be careful (this is a
+ pointer to an "int").
+
+ quoted: set to 1 (true) if the token was quoted and 0 (false)
+ if not. you may need this information (for example:
+ in C, a string with quotes around it is a character
+ string, while one without is an identifier).
+
+ (this is a pointer to a "char").
+*/
+
+/* states */
+
+#define IN_WHITE 0
+#define IN_TOKEN 1
+#define IN_QUOTE 2
+#define IN_OZONE 3
+
+int _p_state; /* current state */
+unsigned _p_flag; /* option flag */
+char _p_curquote; /* current quote char */
+int _p_tokpos; /* current token pos */
+
+/* routine to find character in string ... used only by "tokenizer" */
+
+int sindex(char ch,char *string)
+{
+ char *cp;
+ for(cp=string;*cp;++cp)
+ if(ch==*cp)
+ return (int)(cp-string); /* return postion of character */
+ return -1; /* eol ... no match found */
+}
+
+/* routine to store a character in a string ... used only by "tokenizer" */
+
+void chstore(char *string,int max,char ch)
+{
+ char c;
+ if(_p_tokpos>=0&&_p_tokpos<max-1)
+ {
+ if(_p_state==IN_QUOTE)
+ c=ch;
+ else
+ switch(_p_flag&3)
+ {
+ case 1: /* convert to upper */
+ c=toupper(ch);
+ break;
+
+ case 2: /* convert to lower */
+ c=tolower(ch);
+ break;
+
+ default: /* use as is */
+ c=ch;
+ break;
+ }
+ string[_p_tokpos++]=c;
+ }
+ return;
+}
+
+int tokenizer(unsigned inflag,char *token,int tokmax,char *line,
+ char *white,char *brkchar,char *quote,char eschar,char *brkused,
+ int *next,char *quoted)
+{
+ int qp;
+ char c,nc;
+
+ *brkused=0; /* initialize to null */
+ *quoted=0; /* assume not quoted */
+
+ if(!line[*next]) /* if we're at end of line, indicate such */
+ return 1;
+
+ _p_state=IN_WHITE; /* initialize state */
+ _p_curquote=0; /* initialize previous quote char */
+ _p_flag=inflag; /* set option flag */
+
+ for(_p_tokpos=0;(c=line[*next]);++(*next)) /* main loop */
+ {
+ if((qp=sindex(c,brkchar))>=0) /* break */
+ {
+ switch(_p_state)
+ {
+ case IN_WHITE: /* these are the same here ... */
+ case IN_TOKEN: /* ... just get out */
+ case IN_OZONE: /* ditto */
+ ++(*next);
+ *brkused=brkchar[qp];
+ goto byebye;
+
+ case IN_QUOTE: /* just keep going */
+ chstore(token,tokmax,c);
+ break;
+ }
+ }
+ else if((qp=sindex(c,quote))>=0) /* quote */
+ {
+ switch(_p_state)
+ {
+ case IN_WHITE: /* these are identical, */
+ _p_state=IN_QUOTE; /* change states */
+ _p_curquote=quote[qp]; /* save quote char */
+ *quoted=1; /* set to true as long as something is in quotes */
+ break;
+
+ case IN_QUOTE:
+ if(quote[qp]==_p_curquote) /* same as the beginning quote? */
+ {
+ _p_state=IN_OZONE;
+ _p_curquote=0;
+ }
+ else
+ chstore(token,tokmax,c); /* treat as regular char */
+ break;
+
+ case IN_TOKEN:
+ case IN_OZONE:
+ *brkused=c; /* uses quote as break char */
+ goto byebye;
+ }
+ }
+ else if((qp=sindex(c,white))>=0) /* white */
+ {
+ switch(_p_state)
+ {
+ case IN_WHITE:
+ case IN_OZONE:
+ break; /* keep going */
+
+ case IN_TOKEN:
+ _p_state=IN_OZONE;
+ break;
+
+ case IN_QUOTE:
+ chstore(token,tokmax,c); /* it's valid here */
+ break;
+ }
+ }
+ else if(c==eschar) /* escape */
+ {
+ nc=line[(*next)+1];
+ if(nc==0) /* end of line */
+ {
+ *brkused=0;
+ chstore(token,tokmax,c);
+ ++(*next);
+ goto byebye;
+ }
+ switch(_p_state)
+ {
+ case IN_WHITE:
+ --(*next);
+ _p_state=IN_TOKEN;
+ break;
+
+ case IN_TOKEN:
+ case IN_QUOTE:
+ ++(*next);
+ chstore(token,tokmax,nc);
+ break;
+
+ case IN_OZONE:
+ goto byebye;
+ }
+ }
+ else /* anything else is just a real character */
+ {
+ switch(_p_state)
+ {
+ case IN_WHITE:
+ _p_state=IN_TOKEN; /* switch states */
+
+ case IN_TOKEN: /* these 2 are */
+ case IN_QUOTE: /* identical here */
+ chstore(token,tokmax,c);
+ break;
+
+ case IN_OZONE:
+ goto byebye;
+ }
+ }
+ } /* end of main loop */
+
+byebye:
+ token[_p_tokpos]=0; /* make sure token ends with EOS */
+
+ return 0;
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/iptcutil/test.iptc b/tiff/contrib/iptcutil/test.iptc
new file mode 100644
index 0000000..a260562
--- /dev/null
+++ b/tiff/contrib/iptcutil/test.iptc
Binary files differ
diff --git a/tiff/contrib/iptcutil/test.txt b/tiff/contrib/iptcutil/test.txt
new file mode 100644
index 0000000..d518100
--- /dev/null
+++ b/tiff/contrib/iptcutil/test.txt
@@ -0,0 +1,32 @@
+2#0="&#0;&#2;"
+2#120#Caption="Chairman of the US House Judiciary Committee, Henry Hyde,R-IL, makes his opening statement during impeachment hearings 11 December on Capitol Hill in Washington, DC. The committee is debating the articles of impechment and my take a vote on the impeachment of US President BIll Clinton on charges that he obstucted justice, lied and abused the power of his office as early as today. AFP PHOTO Paul J. RICHARDS&#13;"
+2#122#Caption Writer="kb/lt"
+2#100#Country Code="USA"
+2#105#Headline="Old fart squeezing two fingers."
+2#30#Release Date="19981211"
+2#35#Release Time="000000+0000"
+2#40#Special Instructions="This is a test. This is only a test. ABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890"
+2#80#Byline="PAUL J. RICHARDS"
+2#85#Byline Title="STF"
+2#110#Credit="AFP"
+2#65#Originating Program="MacDesk Reporter"
+2#115#Source="AFP"
+2#5#Image Name="US-HYDE"
+2#55#Created Date="19981211"
+2#90#City="WASHINGTON"
+2#95#Province State="DC"
+2#101#Country="UNITED STATES"
+2#103#Original Transmission Reference="DCA03"
+2#15#Category="POL"
+2#20#Supplemental Category="GOVERNMENT"
+2#10#Priority="5"
+2#25#Keyword="fart"
+2#25#Keyword="squeezing"
+2#25#Keyword="old"
+2#25#Keyword="fingers"
+2#75#Object Cycle="a"
+2#60#Created Time="000000+0000"
+2#70#Program Version="2.0.3"
+2#130="3S"
+2#135="GB"
+2#231="Kaya A. Hoffmann 12/14/98 12:00:44 PM Copy To : Selects - \\KINYANI\Selects&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;&#0;"
diff --git a/tiff/contrib/mac-cw/Makefile.am b/tiff/contrib/mac-cw/Makefile.am
new file mode 100644
index 0000000..827fa31
--- /dev/null
+++ b/tiff/contrib/mac-cw/Makefile.am
@@ -0,0 +1,27 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = Makefile.script README mac_main.c mac_main.h metrowerks.note mkg3_main.c version.h
+
diff --git a/tiff/contrib/mac-cw/Makefile.in b/tiff/contrib/mac-cw/Makefile.in
new file mode 100644
index 0000000..51e5478
--- /dev/null
+++ b/tiff/contrib/mac-cw/Makefile.in
@@ -0,0 +1,420 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/mac-cw
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = Makefile.script README mac_main.c mac_main.h metrowerks.note mkg3_main.c version.h
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/mac-cw/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/mac-cw/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/mac-cw/Makefile.script b/tiff/contrib/mac-cw/Makefile.script
new file mode 100644
index 0000000..85614c8
--- /dev/null
+++ b/tiff/contrib/mac-cw/Makefile.script
@@ -0,0 +1,72 @@
+
+(* You must manually set the top-level PATHNAME here; everything else is automatic *)
+
+set PATHNAME to "ritter:tiff-v3.4beta028:"
+set PRINTING to "NO"
+
+set MKG3STATES to PATHNAME & "mkg3states.mw"
+set LIBTIFF to PATHNAME & "libtiff-68K.mw"
+set TIFFINFO to PATHNAME & "tiffinfo.mw"
+
+with timeout of 60000 seconds
+ tell application "MW C/C++ 68K 1.2.2"
+
+ activate
+
+
+ (* Create tif_fax3sm.c file *)
+ Create Project {file MKG3STATES}
+ Add Files {"mkg3states.c", "mkg3_main.c", "getopt.c"}
+ Add Files {"MacOS.lib"} To Segment 2
+ Add Files {"ANSI (4i/8d) C.68K.Lib"} To Segment 3
+ Add Files {"SIOUX.68K.Lib"} To Segment 4
+ Add Files {"MathLib68K (4i/8d).Lib"} To Segment 5
+
+ Set Preferences To {Activate CPlusPlus:false, ARM Conformance:false, ANSI Keywords Only:false, Require Function Prototypes:false, Expand Trigraph Sequences:false, Enums Always Ints:false, MPW Pointer Type Rules:false, Prefix File:"mac_main.h"}
+ Set Preferences To {Illegal Pragmas:false, Empty Declarations:false, Possible Errors:false, Unused Variables:false, Unused Arguments:false, Extra Commas:false, Extended Error Checking:false}
+ Set Preferences To {Code Model:2, Struct Alignment:0, MC68020 CodeGen:false, MC68881 CodeGen:false, Four Bytes Ints:true, Eight Byte Double:true, Peephole Optimizer:true, CSE Optimizer:true, Optimize For Size:true, Far Data:true, Use Profiler:false, Far Virtual Function Tables:false, Far String Constants:true}
+ Set Preferences To {MacsBug Symbols:2, Generate SYM File:false, Full Path In Sym Files:true, Generate Link Map:false, Generate A6 Stack Frames:true, The Debugger Aware:false, Link Single Segment:false, Fast Link:true}
+ Set Preferences To {Project Type:0, File Name:"mkg3states", File Creator:"????", File Type:"APPL"}
+
+ Make Project
+ Run Project
+ Remove Binaries
+ Close Project
+
+
+ (* Create LIBTIFF *)
+ Create Project {file LIBTIFF}
+ Add Files {"tif_apple.c", "tif_aux.c", "tif_close.c", "tif_codec.c", "tif_compress.c", "tif_dumpmode.c", "tif_error.c", "tif_flush.c", "tif_lzw.c", "tif_next.c", "tif_open.c", "tif_packbits.c"}
+ Add Files {"tif_fax3.c"} To Segment 2
+ Add Files {"tif_dirinfo.c", "tif_dir.c", "tif_dirwrite.c", "tif_dirread.c"} To Segment 3
+ Add Files {"tif_predict.c", "tif_print.c", "tif_read.c", "tif_strip.c", "tif_swab.c", "tif_thunder.c", "tif_tile.c", "tif_version.c", "tif_zip.c", "tif_jpeg.c", "tif_warning.c", "tif_write.c"} To Segment 4
+ Add Files {"tif_fax3sm.c"} To Segment 5
+ Add Files {"tif_getimage.c"} To Segment 6
+
+ Set Preferences To {Activate CPlusPlus:false, ARM Conformance:false, ANSI Keywords Only:false, Require Function Prototypes:false, Expand Trigraph Sequences:false, Enums Always Ints:false, MPW Pointer Type Rules:false, Prefix File:"MacHeaders68K"}
+ Set Preferences To {Illegal Pragmas:false, Empty Declarations:false, Possible Errors:false, Unused Variables:false, Unused Arguments:false, Extra Commas:false, Extended Error Checking:false}
+ Set Preferences To {Code Model:2, Struct Alignment:0, MC68020 CodeGen:false, MC68881 CodeGen:false, Four Bytes Ints:true, Eight Byte Double:true, Peephole Optimizer:true, CSE Optimizer:true, Optimize For Size:true, Far Data:true, Use Profiler:false, Far Virtual Function Tables:false, Far String Constants:true}
+ Set Preferences To {MacsBug Symbols:2, Generate SYM File:true, Full Path In Sym Files:true, Generate Link Map:false, Generate A6 Stack Frames:true, The Debugger Aware:false, Link Single Segment:false, Fast Link:true}
+ Set Preferences To {Project Type:2, File Name:"libtiff-68K", File Creator:"????", File Type:"APPL"}
+ Make Project
+ Close Project
+
+ Create Project {file TIFFINFO}
+ Add Files {"tiffinfo.c", "mac_main.c", "getopt.c"}
+ Add Files {"MacOS.lib"} To Segment 2
+ Add Files {"ANSI (4i/8d) C.68K.Lib"} To Segment 3
+ Add Files {"SIOUX.68K.Lib"} To Segment 4
+ Add Files {"MathLib68K (4i/8d).Lib"} To Segment 5
+ Add Files {"libtiff-68K"} To Segment 6
+
+ Set Preferences To {Activate CPlusPlus:false, ARM Conformance:false, ANSI Keywords Only:false, Require Function Prototypes:false, Expand Trigraph Sequences:false, Enums Always Ints:false, MPW Pointer Type Rules:false, Prefix File:"mac_main.h"}
+ Set Preferences To {Illegal Pragmas:false, Empty Declarations:false, Possible Errors:false, Unused Variables:false, Unused Arguments:false, Extra Commas:false, Extended Error Checking:false}
+ Set Preferences To {Code Model:2, Struct Alignment:0, MC68020 CodeGen:false, MC68881 CodeGen:false, Four Bytes Ints:true, Eight Byte Double:true, Peephole Optimizer:true, CSE Optimizer:true, Optimize For Size:true, Far Data:true, Use Profiler:false, Far Virtual Function Tables:false, Far String Constants:true}
+ Set Preferences To {MacsBug Symbols:2, Generate SYM File:false, Full Path In Sym Files:true, Generate Link Map:false, Generate A6 Stack Frames:true, The Debugger Aware:false, Link Single Segment:false, Fast Link:true}
+ Set Preferences To {Project Type:0, File Name:"tiffinfo", File Creator:"????", File Type:"APPL"}
+
+ Make Project
+ Close Project
+
+ end tell
+end timeout
diff --git a/tiff/contrib/mac-cw/README b/tiff/contrib/mac-cw/README
new file mode 100644
index 0000000..a973469
--- /dev/null
+++ b/tiff/contrib/mac-cw/README
@@ -0,0 +1,18 @@
+----------------------------------------------------
+Build instructions for LIBTIFF - CodeWarrior (6.1):
+----------------------------------------------------
+
+In this directory you will find a Makefile.script Applescript
+file, which should be run in order to build the libtiff code
+using MetroWerks CodeWarrior.
+
+Refer to the "metrowerks.note" instructions on building the
+library for 68k and PowerPC native code, as well as building
+some of the libtiff tools, which are rather unix-like, but
+at least give an example of how to link everything together.
+
+ Questions, comments, bug reports to Niles Ritter
+ (ndr@tazboy.jpl.nasa.gov). Sam Leffler takes no responsibility
+ for the viability of this stuff.
+
+ -Niles.
diff --git a/tiff/contrib/mac-cw/mac_main.c b/tiff/contrib/mac-cw/mac_main.c
new file mode 100644
index 0000000..66b5a83
--- /dev/null
+++ b/tiff/contrib/mac-cw/mac_main.c
@@ -0,0 +1,27 @@
+/*
+ * mac_main.c -- The REAL entry point which
+ * calls the tools main code. For the tools
+ * the symbol "main" has been #defined to "tool_main"
+ * so that this entry point may be used to access
+ * the user-input first.
+ */
+
+#undef main
+
+int
+main()
+{
+ int argc;
+ char **argv;
+
+ argc=ccommand(&argv);
+
+ return tool_main(argc,argv); // Call the tool "main()" routine
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/mac-cw/mac_main.h b/tiff/contrib/mac-cw/mac_main.h
new file mode 100644
index 0000000..5a5facb
--- /dev/null
+++ b/tiff/contrib/mac-cw/mac_main.h
@@ -0,0 +1,19 @@
+/*
+ * mac_main.h -- redefines main entry point
+ */
+
+#ifndef _mac_main_h
+#define _mac_main_h
+
+#undef main
+#define main tool_main
+
+#endif /* _mac_main_h */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/mac-cw/metrowerks.note b/tiff/contrib/mac-cw/metrowerks.note
new file mode 100644
index 0000000..9917cfd
--- /dev/null
+++ b/tiff/contrib/mac-cw/metrowerks.note
@@ -0,0 +1,84 @@
+----------------------------------------------------
+Build instructions for LIBTIFF - CodeWarrior (6.1):
+----------------------------------------------------
+
+Note: there is a bug in CW earlier than 6.1 which will generate
+16-bit offset link errors for any projects using libtiff; you must
+download the CodeWarrior 6.1 patch located at:
+
+ ftp://ftp.metrowerks.com/pub/updates/metro-patches-61.hqx
+
+unpack the archive, insert the files and recompile the libraries
+using the AppleScript provided.
+
+
+1. Make sure that the directory containing these files is under
+ the "contrib" directory of the tiff folder; otherwise, some
+ access path preferences will need to be updated.
+
+2. The instructions below are for the 68k platform build.
+ A similar script can be put together for the PPC version,
+ or you can just directly convert the projects. Be sure to
+ use the native libraries as well. NOTE: if anyone cooks
+ up an equivalent script for PPC, send it to me and I'll include
+ it with the rest of the package.
+
+3. Open the file Makefile.script with an AppleScript Editor
+ and change the PATHNAME variable to point to your
+ top-level TIFF directory
+
+4. Run the Script. It will do the following things:
+
+ 4a. Prompt you for the current location of the CodeWarrior 68K
+ program.
+
+ 4b. Create the source file "tif_fax3sm.c":
+
+ i) Build the project CW project mkg3states.cw. It will
+ produce a small program called mkg3states. Only a
+ 68k version is provided, since you only have to run
+ this code once, and it only takes a few seconds.
+
+ ii) Run the built mkg3states program:
+
+ The program will temporarily take over ALL of the CPU, so
+ don't panic. After a few seconds it will produce a file called
+ "tif_fax3sm.c".
+
+ 4c. Build the library project libtiff-68K.mw, producing library
+ called libtiff-68K.
+
+ 4d. Build program project tiffinfo.mw; it will produce a
+ program called tiffinfo, which can dump the tiff tags of
+ a named file. Passing in no arguments will dump a help file
+ for the program. It is unix-flavored, but hey, it works.
+
+5 When the script finishes, you will have a usable libtiff-68K
+ library, a passable "tiffinfo" program, and the projects used
+ to build them. Note that to get tiffinfo to work I have put
+ an include file in the project that redefines main(), and
+ then have a mac_main.c program that calls ccommand() first
+ and passes that to the actual main code. A real mac app,
+ of course, would never use this stuff at all...
+
+ . The tiffinfo.mw project may be used as a template to build
+ most of the other libtiff tools, or your own code. When
+ modifying a copy of the project, you will most likely need
+ to update the "Access Paths" directory if it is moved out of
+ the contrib folder.
+
+6. If you are going to create a project from scratch, be sure
+ to set up the preferences with
+
+ 4-byte ints
+ 8-byte doubles
+ Far Code/Far Data
+ Large Linking model
+
+ and everything should work fine. If the console-style error
+ reports bother you, you can always override the error and
+ warning mechanism with TIFFSetErrorHandler to do something
+ more Mac-like.
+
+Questions, comments to Niles Ritter (ndr@tazboy.jpl.nasa.gov).
+
diff --git a/tiff/contrib/mac-cw/mkg3_main.c b/tiff/contrib/mac-cw/mkg3_main.c
new file mode 100644
index 0000000..0faea07
--- /dev/null
+++ b/tiff/contrib/mac-cw/mkg3_main.c
@@ -0,0 +1,21 @@
+/*
+ * mkg3_main.c -- passes fake arguments into main
+ */
+
+#undef main
+
+int
+main()
+{
+ static char *argv[4] = {
+ "mkg3states", "-c", "const", "tif_fax3sm.c" };
+
+ return tool_main(4,argv); // Call the tool "main()" routine
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/mac-cw/version.h b/tiff/contrib/mac-cw/version.h
new file mode 100644
index 0000000..ee4a5e4
--- /dev/null
+++ b/tiff/contrib/mac-cw/version.h
@@ -0,0 +1,11 @@
+#define VERSION \
+"LIBTIFF, Version 3.4beta028 \n"\
+"Copyright (c) 1988-1995 Sam Leffler\n"\
+"Copyright (c) 1991-1996 Silicon Graphics, Inc."
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/mac-mpw/BUILD.mpw b/tiff/contrib/mac-mpw/BUILD.mpw
new file mode 100644
index 0000000..7abf83a
--- /dev/null
+++ b/tiff/contrib/mac-mpw/BUILD.mpw
@@ -0,0 +1,47 @@
+# BUILD.mpw:
+#
+# Full build for Apple Macintosh Programmer's Workshop (MPW).
+#
+# This is an executable MPW script which creates various
+# utilities, sets up the MPW makefiles and runs the builds.
+# This script should be run at the top level TIFF directory with:
+#
+# directory :::
+# :contrib:mac-mpw:BUILD.mpw
+#
+# NOTE: The full build requires that MPW have at least 6 MB
+# allocated to it to compile the CCITT Fax codec tables. To
+# deactivate CCITT compression edit the file :contrib:mac:libtiff.make
+# first and follow the directions for disabling Fax decoding.
+#
+# All TIFF tools are built as MPW tools, executable from the
+# MPW shell or other compatible tool server.
+#
+# Written by: Niles Ritter (ndr@tazboy.jpl.nasa.gov).
+#
+
+echo "############# Full Scratch Build for MPW #############"
+
+# Create the ascii->mpw translation tool; this is used to
+# convert standard ASCII files into ones using the special
+# MPW characters, which don't live comfortably in unix tar files.
+#
+echo "######## Creating ASCII->MPW translator ########"
+set contrib ':contrib:mac-mpw:'
+directory {contrib}
+createmake -tool mactrans mactrans.c > dev:null
+make -f mactrans.make | streamedit -e "/CSANELib/||/Math/||/ToolLibs/ del" > mactrans.bld
+execute mactrans.bld > dev:null
+delete -y mactrans.make mactrans.bld mactrans.c.o || set status 0
+directory ::: #An mpw trick for going up two levels
+
+# Create the top-level Makefile and run it
+echo "######## Creating Makefile ########"
+catenate {contrib}top.make | {contrib}mactrans > Makefile
+
+echo "######## Running Makefile ########"
+make > build.mpw
+execute build.mpw
+echo "############# MPW Build Complete #############"
+exit 0
+
diff --git a/tiff/contrib/mac-mpw/Makefile.am b/tiff/contrib/mac-mpw/Makefile.am
new file mode 100644
index 0000000..fd1e663
--- /dev/null
+++ b/tiff/contrib/mac-mpw/Makefile.am
@@ -0,0 +1,27 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = BUILD.mpw README libtiff.make mactrans.c port.make tools.make top.make
+
diff --git a/tiff/contrib/mac-mpw/Makefile.in b/tiff/contrib/mac-mpw/Makefile.in
new file mode 100644
index 0000000..9aced32
--- /dev/null
+++ b/tiff/contrib/mac-mpw/Makefile.in
@@ -0,0 +1,420 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/mac-mpw
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = BUILD.mpw README libtiff.make mactrans.c port.make tools.make top.make
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/mac-mpw/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/mac-mpw/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/mac-mpw/README b/tiff/contrib/mac-mpw/README
new file mode 100644
index 0000000..053b0d0
--- /dev/null
+++ b/tiff/contrib/mac-mpw/README
@@ -0,0 +1,20 @@
+######################
+About contrib:mac-mpw:
+######################
+
+This directory contains all of the utilities and makefile source
+to build the LIBTIFF library and tools from the MPW Shell. The
+file BUILD.mpw in this directory is an executable script
+which uses all of these files to create the MPW makefiles and
+run them.
+
+The <file>.make files are not MPW makefiles as such,
+but are when run through the "mactrans" program, which turns
+the ascii "%nn" metacharacters into the standard weird MPW
+make characters.
+
+This translation trick is necessary to protect the files when
+they are put into unix tarfiles, which tend to mangle the
+special characters.
+
+ --Niles Ritter (ndr@tazboy.jpl.nasa.gov)
diff --git a/tiff/contrib/mac-mpw/libtiff.make b/tiff/contrib/mac-mpw/libtiff.make
new file mode 100644
index 0000000..ee5296e
--- /dev/null
+++ b/tiff/contrib/mac-mpw/libtiff.make
@@ -0,0 +1,202 @@
+#
+# Tag Image File Format Library
+#
+# Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994 Sam Leffler
+# Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+#
+# Makefile for Mac using MPW 3.3.1 and MPW C 3.2.4
+#
+# Note: This file must be run through "mactrans" before it can
+# be recognized by MPW as a valid makefile. The problem is that MPW
+# uses special non-ASCII characters, which tend to get mangled when stored
+# in unix tar files, etc. "mactrans" is built as part of the TIFF MPW build.
+#
+#
+
+DEPTH = ::
+
+# FAX Options: If you do not wish to include the FAX options, uncomment
+# the first four definitions and comment out the next four
+# definitions. Note that to build programs with the FAX libraries you
+# have to include "-model far" in your compile and link statements.
+#
+# Also, to build the fax code (including the tif_fax3sm.c file, which is
+# created by the MPW tool "mkg3states", also built below), you will
+# need to size the MPW program up to about 6 megabytes or so.
+
+#FAX_OPTIONS =
+#FAX_OBJECTS =
+#FAX_SOURCES = tif_fax3.c
+#FAX_CONFIG =
+
+FAX_OPTIONS = -model far
+FAX_OBJECTS = tif_fax3.c.o tif_fax3sm.c.o
+FAX_SOURCES = tif_fax3.c tif_fax3sm.c
+FAX_CONFIG = -d CCITT_SUPPORT
+
+NULL=
+
+RM = delete -y -i
+COPTS =
+
+LIBPORT=::port:libport.o
+
+#
+.c.o %c4 .c
+ {C} -model far {CFLAGS} -s {Default} {DepDir}{Default}.c -o {TargDir}{Default}.c.o
+
+
+CONF_LIBRARY= %b6
+ -d HAVE_IEEEFP=1 %b6
+ -d BSDTYPES
+
+CONF_COMPRESSION= %b6
+ {FAX_CONFIG} %b6
+ -d COMPRESSION_SUPPORT %b6
+ -d PACKBITS_SUPPORT %b6
+ -d LZW_SUPPORT %b6
+ -d THUNDER_SUPPORT %b6
+ -d NEXT_SUPPORT
+
+CFLAGS= {FAX_OPTIONS} {IPATH} {CONF_LIBRARY} {CONF_COMPRESSION}
+
+INCS= tiff.h tiffio.h
+
+SRCS= %b6
+ {FAX_SOURCES} %b6
+ tif_apple.c %b6
+ tif_aux.c %b6
+ tif_close.c %b6
+ tif_codec.c %b6
+ tif_compress.c %b6
+ tif_dir.c %b6
+ tif_dirinfo.c %b6
+ tif_dirread.c %b6
+ tif_dirwrite.c %b6
+ tif_dumpmode.c %b6
+ tif_error.c %b6
+ tif_getimage.c %b6
+ tif_jpeg.c %b6
+ tif_flush.c %b6
+ tif_lzw.c %b6
+ tif_next.c %b6
+ tif_open.c %b6
+ tif_packbits.c %b6
+ tif_predict.c %b6
+ tif_print.c %b6
+ tif_read.c %b6
+ tif_swab.c %b6
+ tif_strip.c %b6
+ tif_thunder.c %b6
+ tif_tile.c %b6
+ tif_version.c %b6
+ tif_warning.c %b6
+ tif_write.c %b6
+ tif_zip.c %b6
+ {NULL}
+
+OBJS= %b6
+ {FAX_OBJECTS} %b6
+ tif_apple.c.o %b6
+ tif_aux.c.o %b6
+ tif_close.c.o %b6
+ tif_codec.c.o %b6
+ tif_compress.c.o %b6
+ tif_dir.c.o %b6
+ tif_dirinfo.c.o %b6
+ tif_dirread.c.o %b6
+ tif_dirwrite.c.o %b6
+ tif_dumpmode.c.o %b6
+ tif_error.c.o %b6
+ tif_getimage.c.o %b6
+ tif_jpeg.c.o %b6
+ tif_flush.c.o %b6
+ tif_lzw.c.o %b6
+ tif_next.c.o %b6
+ tif_open.c.o %b6
+ tif_packbits.c.o %b6
+ tif_predict.c.o %b6
+ tif_print.c.o %b6
+ tif_read.c.o %b6
+ tif_swab.c.o %b6
+ tif_strip.c.o %b6
+ tif_thunder.c.o %b6
+ tif_tile.c.o %b6
+ tif_version.c.o %b6
+ tif_warning.c.o %b6
+ tif_write.c.o %b6
+ tif_zip.c.o %b6
+ {NULL}
+
+ALL=libtiff.o
+
+all %c4 {ALL}
+
+libtiff.o %c4 {OBJS}
+ Lib {OBJS} -o libtiff.o
+
+
+{OBJS} %c4 tiffio.h tiff.h tiffcomp.h tiffiop.h tiffconf.h
+
+#
+# The finite state machine tables used by the G3/G4 decoders
+# are generated by the mkg3states program. On systems without
+# make these rules have to be manually carried out.
+#
+tif_fax3sm.c %c4 mkg3states tif_fax3.h
+ {RM} tif_fax3sm.c || set status 0
+ :mkg3states -c const tif_fax3sm.c
+
+mkg3states.c.o %c4 mkg3states.c
+ C -model far mkg3states.c -o mkg3states.c.o
+
+mkg3states %c4%c4 mkg3states.c.o
+ Link -model far -d -c 'MPS ' -t MPST %b6
+ mkg3states.c.o %b6
+ {LIBPORT} %b6
+ "{CLibraries}"StdClib.o %b6
+ "{Libraries}"Stubs.o %b6
+ "{Libraries}"Runtime.o %b6
+ "{Libraries}"Interface.o %b6
+ -o mkg3states
+
+ALPHA = "{DEPTH}dist:tiff.alpha"
+VERSION = "{DEPTH}VERSION"
+
+version.h %c4 {VERSION} {ALPHA}
+ Set VERSION1 `catenate {VERSION}`
+ Set VERSION2 "{VERSION1}`streamedit -e "1 rep /%a5%c5 %c5 (%c5)%a81/ %a81" {ALPHA}`"
+ delete -y -i version.h || set status 0
+ echo '#define VERSION "LIBTIFF, Version' {VERSION2} '\nCopyright (c) 1988-1995 Sam Leffler\nCopyright (c) 1991-1995 Silicon Graphics, Inc."' >version.h
+
+tif_version.c.o %c4 version.h
+
+clean %c4
+ {RM} {ALL} || set status 0
+ {RM} {OBJS} || set status 0
+ {RM} mkg3states || set status 0
+ {RM} mkg3states.c.o || set status 0
+ {RM} tif_fax3sm.c%c5 || set status 0
+ {RM} version.h || set status 0
+
diff --git a/tiff/contrib/mac-mpw/mactrans.c b/tiff/contrib/mac-mpw/mactrans.c
new file mode 100644
index 0000000..d35373e
--- /dev/null
+++ b/tiff/contrib/mac-mpw/mactrans.c
@@ -0,0 +1,63 @@
+/*
+ * mactrans.c -- Hack filter used to generate MPW files
+ * with special characters from pure ASCII, denoted "%nn"
+ * where nn is hex. (except for "%%", which is literal '%').
+ *
+ * calling sequence:
+ *
+ * catenate file | mactrans [-toascii | -fromascii] > output
+ *
+ * Written by: Niles Ritter.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+void to_ascii(void);
+void from_ascii(void);
+
+main(int argc, char *argv[])
+{
+ if (argc<2 || argv[1][1]=='f') from_ascii();
+ else to_ascii();
+ exit (0);
+}
+
+void from_ascii(void)
+{
+ char c;
+ int d;
+ while ((c=getchar())!=EOF)
+ {
+ if (c!='%' || (c=getchar())=='%') putchar(c);
+ else
+ {
+ ungetc(c,stdin);
+ scanf("%2x",&d);
+ *((unsigned char *)&c) = d;
+ putchar(c);
+ }
+ }
+}
+
+void to_ascii(void)
+{
+ char c;
+ int d;
+ while ((c=getchar())!=EOF)
+ {
+ if (isascii(c)) putchar (c);
+ else
+ {
+ d = *((unsigned char *)&c);
+ printf("%%%2x",d);
+ }
+ }
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/mac-mpw/port.make b/tiff/contrib/mac-mpw/port.make
new file mode 100644
index 0000000..492c527
--- /dev/null
+++ b/tiff/contrib/mac-mpw/port.make
@@ -0,0 +1,53 @@
+#
+# Tag Image File Format Library
+#
+# Copyright (c) 1995 Sam Leffler
+# Copyright (c) 1995 Silicon Graphics, Inc.
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+DEPTH= ::
+SRCDIR= :
+
+NULL =
+CC = C
+AR = Lib
+AROPTS =
+RM= delete -y
+
+IPATH = -I {DEPTH} -I {SRCDIR}
+COPTS =
+OPTIMIZER=
+CFLAGS = {COPTS} {OPTIMIZER} {IPATH}
+
+CFILES =
+OBJECTS = getopt.c.o
+TARGETS = libport.o
+
+.c.o %c4 .c
+ {CC} -model far {COptions} {CFLAGS} -s {Default} {DepDir}{Default}.c -o {TargDir}{Default}.c.o
+
+all %c4 {TARGETS}
+
+libport.o %c4 {OBJECTS}
+ {AR} {OBJECTS} -o libport.o
+
+clean %c4
+ {RM} {TARGETS} {OBJECTS} || set status 0
diff --git a/tiff/contrib/mac-mpw/tools.make b/tiff/contrib/mac-mpw/tools.make
new file mode 100644
index 0000000..13b14e4
--- /dev/null
+++ b/tiff/contrib/mac-mpw/tools.make
@@ -0,0 +1,138 @@
+#
+# Tag Image File Format Library
+#
+# Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994 Sam Leffler
+# Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Stanford and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+#
+# Makefile for Mac using MPW 3.2.3 and MPW C 3.2.4
+#
+COPTS = -model far
+
+.c.o %c4 .c
+ {C} {COPTS} {CFLAGS} -s {Default} {DepDir}{Default}.c -o {TargDir}{Default}.c.o
+
+RM = delete -y -i
+
+CONF_LIBRARY= %b6
+ -d USE_CONST=0 %b6
+ -d BSDTYPES
+NULL=
+
+IPATH= -I ::libtiff
+
+CFLAGS= -w -m {IPATH} {CONF_LIBRARY}
+
+LIBPORT= ::port:libport.o
+
+LOptions= -model far -w -srt -d -c 'MPS ' -t MPST
+
+LIBTIFF= ::libtiff:libtiff.o
+
+LIBS= {LIBTIFF} %b6
+ {LIBPORT} %b6
+ "{CLibraries}"CSANELib.o %b6
+ "{CLibraries}"Math.o %b6
+ "{CLibraries}"StdClib.o %b6
+ "{Libraries}"Stubs.o %b6
+ "{Libraries}"Runtime.o %b6
+ "{Libraries}"Interface.o %b6
+ "{Libraries}"ToolLibs.o %b6
+ {NULL}
+
+SRCS= %b6
+ pal2rgb.c %b6
+ ras2tiff.c %b6
+ thumbnail.c %b6
+ tiff2bw.c %b6
+ tiff2ps.c %b6
+ tiffcmp.c %b6
+ tiffcp.c %b6
+ tiffdither.c %b6
+ tiffdump.c %b6
+ tiffinfo.c %b6
+ tiffmedian.c %b6
+ {NULL}
+
+MACHALL=ras2tiff
+
+ALL= %b6
+ tiffinfo %b6
+ tiffcmp %b6
+ tiffcp %b6
+ tiffdump %b6
+ tiffmedian %b6
+ tiff2bw %b6
+ tiffdither %b6
+ tiff2ps %b6
+ pal2rgb %b6
+ gif2tiff %b6
+ {MACHALL}
+
+all %c4 {ALL}
+
+tiffinfo %c4 tiffinfo.c.o {LIBTIFF}
+ Link {LOptions} tiffinfo.c.o {LIBS} -o tiffinfo
+
+tiffcmp %c4 tiffcmp.c.o {LIBTIFF}
+ Link {LOptions} tiffcmp.c.o {LIBS} -o tiffcmp
+
+tiffcp %c4 tiffcp.c.o {LIBTIFF}
+ Link {LOptions} tiffcp.c.o {LIBS} -o tiffcp
+
+tiffdump %c4 tiffdump.c.o {LIBTIFF}
+ Link {LOptions} tiffdump.c.o {LIBS} -o tiffdump
+
+tiffmedian %c4 tiffmedian.c.o {LIBTIFF}
+ Link {LOptions} tiffmedian.c.o {LIBS} -o tiffmedian
+
+tiff2ps %c4 tiff2ps.c.o {LIBTIFF}
+ Link {LOptions} tiff2ps.c.o {LIBS} -o tiff2ps
+
+# junky stuff...
+# convert RGB image to B&W
+tiff2bw %c4 tiff2bw.c.o {LIBTIFF}
+ Link {LOptions} tiff2bw.c.o {LIBS} -o tiff2bw
+
+# convert B&W image to bilevel w/ FS dithering
+tiffdither %c4 tiffdither.c.o {LIBTIFF}
+ Link {LOptions} tiffdither.c.o {LIBS} -o tiffdither
+
+# GIF converter
+gif2tiff %c4 gif2tiff.c.o {LIBTIFF}
+ Link {LOptions} gif2tiff.c.o {LIBS} -o gif2tiff
+
+# convert Palette image to RGB
+pal2rgb %c4 pal2rgb.c.o {LIBTIFF}
+ Link {LOptions} pal2rgb.c.o {LIBS} -o pal2rgb
+
+# Sun rasterfile converter
+ras2tiff %c4 ras2tiff.c.o {LIBTIFF}
+ Link {LOptions} ras2tiff.c.o {LIBS} -o ras2tiff
+
+# generate thumbnail images from fax
+thumbnail %c4 thumbnail.c.o {LIBTIFF}
+ Link {LOptions} thumbnail.c.o {LIBS} -o thumbnail
+
+clean %c4
+ {RM} {ALL} %c5.c.o ycbcr
diff --git a/tiff/contrib/mac-mpw/top.make b/tiff/contrib/mac-mpw/top.make
new file mode 100644
index 0000000..5a6a29b
--- /dev/null
+++ b/tiff/contrib/mac-mpw/top.make
@@ -0,0 +1,133 @@
+#
+# Tag Image File Format Library
+#
+# Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994 Sam Leffler
+# Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Stanford and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+#
+# Makefile for Mac using MPW 3.2.3 and MPW C 3.2.4
+#
+#
+# Written by: Niles D. Ritter
+#
+
+RM= delete -y -i
+PORT=:port:
+LIBTIFF=:libtiff:
+TOOLS=:tools:
+CONTRIB=:contrib:mac-mpw:
+
+MACTRANS="{CONTRIB}mactrans"
+
+NULL=
+
+MAKEFILES = %b6
+ {PORT}Makefile %b6
+ {LIBTIFF}Makefile %b6
+ {TOOLS}Makefile %b6
+ {NULL}
+
+all %c4 PORT LIBTIFF TOOLS
+
+MAKEFILES %c4 {MAKEFILES}
+TOOLS %c4 LIBTIFF
+
+LIBTIFF %c4 PORT
+
+# Create the port routines
+PORT %c4 {PORT}Makefile
+ directory {PORT}
+ (make || set status 0) > build.mpw
+ set echo 1
+ execute build.mpw
+ set echo 0
+ {RM} build.mpw || set status 0
+ directory ::
+
+# Create the port routines
+LIBTIFF %c4 {LIBTIFF}Makefile
+ directory {LIBTIFF}
+ (make || set status 0) > build.mpw
+ set echo 1
+ execute build.mpw
+ set echo 0
+ {RM} build.mpw || set status 0
+ directory ::
+
+# Create the tools
+TOOLS %c4 {TOOLS}Makefile
+ directory {TOOLS}
+ (make || set status 0) > build.mpw
+ set echo 1
+ execute build.mpw
+ set echo 0
+ {RM} build.mpw || set status 0
+ directory ::
+
+# Makefile dependencies
+{PORT}Makefile %c4 {CONTRIB}port.make
+ catenate {CONTRIB}port.make | {MACTRANS} > {PORT}Makefile
+
+{LIBTIFF}Makefile %c4 {CONTRIB}libtiff.make
+ catenate {CONTRIB}libtiff.make | {MACTRANS} > {LIBTIFF}Makefile
+
+{TOOLS}Makefile %c4 {CONTRIB}tools.make
+ catenate {CONTRIB}tools.make | {MACTRANS} > {TOOLS}Makefile
+
+
+clean %c4 clean.port clean.contrib clean.libtiff clean.tools clean.make
+
+clean.port %c4
+ directory {PORT}
+ (make clean || set status 0) > purge
+ purge
+ {RM} purge || set status 0
+ {RM} Makefile || set status 0
+ {RM} build.mpw || set status 0
+ cd ::
+
+clean.contrib %c4
+ {RM} {MACTRANS} || set status 0
+
+clean.libtiff %c4
+ directory {LIBTIFF}
+ (make clean || set status 0) > purge
+ purge
+ {RM} purge || set status 0
+ {RM} Makefile || set status 0
+ {RM} build.mpw || set status 0
+ cd ::
+
+clean.tools %c4
+ directory {TOOLS}
+ (make clean || set status 0) > purge
+ purge
+ {RM} purge || set status 0
+ {RM} Makefile || set status 0
+ {RM} build.mpw || set status 0
+ cd ::
+
+clean.make %c4
+ {RM} {MAKEFILES} || set status 0
+ {RM} build.mpw || set status 0
+
diff --git a/tiff/contrib/mfs/Makefile.am b/tiff/contrib/mfs/Makefile.am
new file mode 100644
index 0000000..9a398c5
--- /dev/null
+++ b/tiff/contrib/mfs/Makefile.am
@@ -0,0 +1,28 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = README mfs_file.c
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff \ No newline at end of file
diff --git a/tiff/contrib/mfs/Makefile.in b/tiff/contrib/mfs/Makefile.in
new file mode 100644
index 0000000..e7e7850
--- /dev/null
+++ b/tiff/contrib/mfs/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/mfs
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = README mfs_file.c
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/mfs/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/mfs/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/mfs/README b/tiff/contrib/mfs/README
new file mode 100644
index 0000000..6f9befb
--- /dev/null
+++ b/tiff/contrib/mfs/README
@@ -0,0 +1,37 @@
+Date: Mon, 23 Jun 1997 13:30:48 +0200
+To: <sam@cthulhu.engr.sgi.com>
+
+From: "Mike Johnson" <mikehunt@swipnet.se>
+Subject: libtiff - Thanks
+
+Return-Path: mikehunt@swipnet.se
+Delivery-Date: Mon, 23 Jun 1997 06:53:39 -0700
+
+Hi Sam,
+
+I noticed in the README from libtiff that you would like to know about
+what people have done with libtiff, so I thought I would drop you a
+line.
+
+We have used libtiff to create and convert TIFF images of financial
+documents which are sent from and to major document processing systems
+in Sweden and Denmark.
+
+I would like to express my deep gratitude to yourself and Sillicon
+Graphics for making this excellent library available for public use.
+There is obviously a lot of work that has gone in to libtiff and the
+quality of the code and documentation is an example to others.
+
+One thing that libtiff did not do was work on a memory area rather than
+files. In my applications I had already read a TIFF or other format
+file in to memory and did not want to waste I/O writing it out again
+for libtiff's benefit. I therefore constructed a set of functions to
+pass up to TIFFClientOpen to simulate a file in memory. I have attached
+my mfs (memory file system) source code for you to use or junk, as you
+see fit. :-)
+
+Once again, thanks very much for making my life simpler.
+
+Best Regards,
+
+Mike Johnson.
diff --git a/tiff/contrib/mfs/mfs_file.c b/tiff/contrib/mfs/mfs_file.c
new file mode 100644
index 0000000..6675e2a
--- /dev/null
+++ b/tiff/contrib/mfs/mfs_file.c
@@ -0,0 +1,586 @@
+/*
+--------------------------------------------------------------------------------
+- Module : mem_file.c
+- Description : A general purpose library for manipulating a memory area
+- as if it were a file.
+- mfs_ stands for memory file system.
+- Author : Mike Johnson - Banctec AB 03/07/96
+-
+--------------------------------------------------------------------------------
+*/
+
+/*
+
+Copyright (c) 1996 Mike Johnson
+Copyright (c) 1996 BancTec AB
+
+Permission to use, copy, modify, distribute, and sell this software
+for any purpose is hereby granted without fee, provided
+that (i) the above copyright notices and this permission notice appear in
+all copies of the software and related documentation, and (ii) the names of
+Mike Johnson and BancTec may not be used in any advertising or
+publicity relating to the software.
+
+THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+IN NO EVENT SHALL MIKE JOHNSON OR BANCTEC BE LIABLE FOR
+ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
+
+*/
+
+
+/*
+--------------------------------------------------------------------------------
+- Includes
+--------------------------------------------------------------------------------
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+--------------------------------------------------------------------------------
+- Definitions
+--------------------------------------------------------------------------------
+*/
+
+#define MAX_BUFFS 20
+#define FALSE 0
+#define TRUE 1
+
+/*
+--------------------------------------------------------------------------------
+- Globals
+--------------------------------------------------------------------------------
+*/
+
+static char *buf[MAX_BUFFS]; /* Memory for each open buf */
+static long buf_off[MAX_BUFFS]; /* File pointer for each buf */
+static long buf_size[MAX_BUFFS]; /* Count of bytes allocated for each buf */
+static long fds[MAX_BUFFS]; /* File descriptor status */
+static int buf_mode[MAX_BUFFS]; /* Mode of buffer (r, w, a) */
+
+static int library_init_done = FALSE;
+
+
+/*
+--------------------------------------------------------------------------------
+- Function prototypes
+--------------------------------------------------------------------------------
+*/
+
+int mfs_open (void *ptr, int size, char *mode);
+int mfs_lseek (int fd, int offset, int whence);
+int mfs_read (int fd, void *buf, int size);
+int mfs_write (int fd, void *buf, int size);
+int mfs_size (int fd);
+int mfs_map (int fd, char **addr, size_t *len);
+int mfs_unmap (int fd);
+int mfs_close (int fd);
+static int extend_mem_file (int fd, int size);
+static void mem_init ();
+
+/*
+--------------------------------------------------------------------------------
+- Function code
+--------------------------------------------------------------------------------
+*/
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_open ()
+-
+- Arguments : Pointer to allocated buffer, initial size of buffer,
+- mode spec (r, w, a)
+-
+- Returns : File descriptor or -1 if error.
+-
+- Description : Register this area of memory (which has been allocated
+- and has a file read into it) under the mem_file library.
+- A file descriptor is returned which can the be passed
+- back to TIFFClientOpen and used as if it was a disk
+- based fd.
+- If the call is for mode 'w' then pass (void *)NULL as
+- the buffer and zero size and the library will
+- allocate memory for you.
+- If the mode is append then pass (void *)NULL and size
+- zero or with a valid address.
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_open (void *buffer, int size, char *mode)
+{
+ int ret, i;
+ void *tmp;
+
+ if (library_init_done == FALSE)
+ {
+ mem_init ();
+ library_init_done = TRUE;
+ }
+
+ ret = -1;
+
+ /* Find a free fd */
+
+ for (i = 0; i < MAX_BUFFS; i++)
+ {
+ if (fds[i] == -1)
+ {
+ ret = i;
+ break;
+ }
+ }
+
+ if (i == MAX_BUFFS) /* No more free descriptors */
+ {
+ ret = -1;
+ errno = EMFILE;
+ }
+
+ if (ret >= 0 && *mode == 'r')
+ {
+ if (buffer == (void *)NULL)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+ else
+ {
+ buf[ret] = (char *)buffer;
+ buf_size[ret] = size;
+ buf_off[ret] = 0;
+ }
+ }
+ else if (ret >= 0 && *mode == 'w')
+ {
+
+ if (buffer != (void *)NULL)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+
+ else
+ {
+ tmp = malloc (0); /* Get a pointer */
+ if (tmp == (void *)NULL)
+ {
+ ret = -1;
+ errno = EDQUOT;
+ }
+ else
+ {
+ buf[ret] = (char *)tmp;
+ buf_size[ret] = 0;
+ buf_off[ret] = 0;
+ }
+ }
+ }
+ else if (ret >= 0 && *mode == 'a')
+ {
+ if (buffer == (void *) NULL) /* Create space for client */
+ {
+ tmp = malloc (0); /* Get a pointer */
+ if (tmp == (void *)NULL)
+ {
+ ret = -1;
+ errno = EDQUOT;
+ }
+ else
+ {
+ buf[ret] = (char *)tmp;
+ buf_size[ret] = 0;
+ buf_off[ret] = 0;
+ }
+ }
+ else /* Client has file read in already */
+ {
+ buf[ret] = (char *)buffer;
+ buf_size[ret] = size;
+ buf_off[ret] = 0;
+ }
+ }
+ else /* Some other invalid combination of parameters */
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+
+ if (ret != -1)
+ {
+ fds[ret] = 0;
+ buf_mode[ret] = *mode;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_lseek ()
+-
+- Arguments : File descriptor, offset, whence
+-
+- Returns : as per man lseek (2)
+-
+- Description : Does the same as lseek (2) except on a memory based file.
+- Note: the memory area will be extended if the caller
+- attempts to seek past the current end of file (memory).
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_lseek (int fd, int offset, int whence)
+{
+ int ret;
+ long test_off;
+
+ if (fds[fd] == -1) /* Not open */
+ {
+ ret = -1;
+ errno = EBADF;
+ }
+ else if (offset < 0 && whence == SEEK_SET)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+ else
+ {
+ switch (whence)
+ {
+ case SEEK_SET:
+ if (offset > buf_size[fd])
+ extend_mem_file (fd, offset);
+ buf_off[fd] = offset;
+ ret = offset;
+ break;
+
+ case SEEK_CUR:
+ test_off = buf_off[fd] + offset;
+
+ if (test_off < 0)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+ else
+ {
+ if (test_off > buf_size[fd])
+ extend_mem_file (fd, test_off);
+ buf_off[fd] = test_off;
+ ret = test_off;
+ }
+ break;
+
+ case SEEK_END:
+ test_off = buf_size[fd] + offset;
+
+ if (test_off < 0)
+ {
+ ret = -1;
+ errno = EINVAL;
+ }
+ else
+ {
+ if (test_off > buf_size[fd])
+ extend_mem_file (fd, test_off);
+ buf_off[fd] = test_off;
+ ret = test_off;
+ }
+ break;
+
+ default:
+ errno = EINVAL;
+ ret = -1;
+ break;
+ }
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_read ()
+-
+- Arguments : File descriptor, buffer, size
+-
+- Returns : as per man read (2)
+-
+- Description : Does the same as read (2) except on a memory based file.
+- Note: An attempt to read past the end of memory currently
+- allocated to the file will return 0 (End Of File)
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_read (int fd, void *clnt_buf, int size)
+{
+ int ret;
+
+ if (fds[fd] == -1 || buf_mode[fd] != 'r')
+ {
+ /* File is either not open, or not opened for read */
+
+ ret = -1;
+ errno = EBADF;
+ }
+ else if (buf_off[fd] + size > buf_size[fd])
+ {
+ ret = 0; /* EOF */
+ }
+ else
+ {
+ memcpy (clnt_buf, (void *) (buf[fd] + buf_off[fd]), size);
+ buf_off[fd] = buf_off[fd] + size;
+ ret = size;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_write ()
+-
+- Arguments : File descriptor, buffer, size
+-
+- Returns : as per man write (2)
+-
+- Description : Does the same as write (2) except on a memory based file.
+- Note: the memory area will be extended if the caller
+- attempts to write past the current end of file (memory).
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_write (int fd, void *clnt_buf, int size)
+{
+ int ret;
+
+ if (fds[fd] == -1 || buf_mode[fd] == 'r')
+ {
+ /* Either the file is not open or it is opened for reading only */
+
+ ret = -1;
+ errno = EBADF;
+ }
+ else if (buf_mode[fd] == 'w')
+ {
+ /* Write */
+
+ if (buf_off[fd] + size > buf_size[fd])
+ {
+ extend_mem_file (fd, buf_off[fd] + size);
+ buf_size[fd] = (buf_off[fd] + size);
+ }
+
+ memcpy ((buf[fd] + buf_off[fd]), clnt_buf, size);
+ buf_off[fd] = buf_off[fd] + size;
+
+ ret = size;
+ }
+ else
+ {
+ /* Append */
+
+ if (buf_off[fd] != buf_size[fd])
+ buf_off[fd] = buf_size[fd];
+
+ extend_mem_file (fd, buf_off[fd] + size);
+ buf_size[fd] += size;
+
+ memcpy ((buf[fd] + buf_off[fd]), clnt_buf, size);
+ buf_off[fd] = buf_off[fd] + size;
+
+ ret = size;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_size ()
+-
+- Arguments : File descriptor
+-
+- Returns : integer file size
+-
+- Description : This function returns the current size of the file in bytes.
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_size (int fd)
+{
+ int ret;
+
+ if (fds[fd] == -1) /* Not open */
+ {
+ ret = -1;
+ errno = EBADF;
+ }
+ else
+ ret = buf_size[fd];
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_map ()
+-
+- Arguments : File descriptor, ptr to address, ptr to length
+-
+- Returns : Map status (succeeded or otherwise)
+-
+- Description : This function tells the client where the file is mapped
+- in memory and what size the mapped area is. It is provided
+- to satisfy the MapProc function in libtiff. It pretends
+- that the file has been mmap (2)ped.
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_map (int fd, char **addr, size_t *len)
+{
+ int ret;
+
+ if (fds[fd] == -1) /* Not open */
+ {
+ ret = -1;
+ errno = EBADF;
+ }
+ else
+ {
+ *addr = buf[fd];
+ *len = buf_size[fd];
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_unmap ()
+-
+- Arguments : File descriptor
+-
+- Returns : UnMap status (succeeded or otherwise)
+-
+- Description : This function does nothing as the file is always
+- in memory.
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_unmap (int fd)
+{
+ return (0);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mfs_close ()
+-
+- Arguments : File descriptor
+-
+- Returns : close status (succeeded or otherwise)
+-
+- Description : Close the open memory file. (Make fd available again.)
+-
+--------------------------------------------------------------------------------
+*/
+
+int mfs_close (int fd)
+{
+ int ret;
+
+ if (fds[fd] == -1) /* Not open */
+ {
+ ret = -1;
+ errno = EBADF;
+ }
+ else
+ {
+ fds[fd] = -1;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : extend_mem_file ()
+-
+- Arguments : File descriptor, length to extend to.
+-
+- Returns : 0 - All OK, -1 - realloc () failed.
+-
+- Description : Increase the amount of memory allocated to a file.
+-
+--------------------------------------------------------------------------------
+*/
+
+static int extend_mem_file (int fd, int size)
+{
+ void *new_mem;
+ int ret;
+
+ if ((new_mem = realloc (buf[fd], size)) == (void *) NULL)
+ ret = -1;
+ else
+ {
+ buf[fd] = (char *) new_mem;
+ ret = 0;
+ }
+
+ return (ret);
+}
+
+/*
+--------------------------------------------------------------------------------
+- Function : mem_init ()
+-
+- Arguments : None
+-
+- Returns : void
+-
+- Description : Initialise the library.
+-
+--------------------------------------------------------------------------------
+*/
+
+static void mem_init ()
+{
+ int i;
+
+ for (i = 0; i < MAX_BUFFS; i++)
+ {
+ fds[i] = -1;
+ buf[i] = (char *)NULL;
+ buf_size[i] = 0;
+ buf_off[i] = 0;
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/pds/Makefile.am b/tiff/contrib/pds/Makefile.am
new file mode 100644
index 0000000..2ead6a7
--- /dev/null
+++ b/tiff/contrib/pds/Makefile.am
@@ -0,0 +1,28 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = README tif_imageiter.c tif_imageiter.h tif_pdsdirread.c tif_pdsdirwrite.c
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
diff --git a/tiff/contrib/pds/Makefile.in b/tiff/contrib/pds/Makefile.in
new file mode 100644
index 0000000..bc5134b
--- /dev/null
+++ b/tiff/contrib/pds/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/pds
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = README tif_imageiter.c tif_imageiter.h tif_pdsdirread.c tif_pdsdirwrite.c
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/pds/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/pds/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/pds/README b/tiff/contrib/pds/README
new file mode 100644
index 0000000..b9abc6b
--- /dev/null
+++ b/tiff/contrib/pds/README
@@ -0,0 +1,90 @@
+Date: Fri, 01 Aug 1997 20:14:52 MDT
+To: Sam Leffler <sam@cthulhu.engr.sgi.com>
+
+From: "Conrad J. Poelman (WSAT)" <poelmanc@plk.af.mil>
+Subject: Potential TIFF library additions
+
+Delivery-Date: Fri, 01 Aug 1997 19:21:06 -0700
+
+Sam,
+
+You probably don't remember me, but I sent in a couple of bug fixes
+regarding the TIFF library about a 16 months ago or so...
+
+I just wanted to send you two other additions that I have made to our
+local version of the TIFF library in hopes that you will want to
+incorporate them into your next major release of the TIFF library.
+(These additions are based on TIFF version 3.4beta31, but they sit on
+top of the library so they shouldn't be much trouble to incorporate them
+into any more recent version.) They are internally documented to a
+reasonable extent and we've been successfully using them in our code
+here for over a year. If you think they would make good additions to the
+TIFF library, I'd be happy to clean them up more, document them more,
+and/or integrate them with the latest version of the TIFF library, but I
+figured I'd see if you were interested in using them before I went to
+all that trouble.
+
+TIFF Image Iterator
+-------------------
+Your ReadRGBA() routine works well for reading many different formats
+(TILED, STIP, compressed or not, etc.) of the most basic types of data
+(RGB, 8-bit greyscale, 8-bit colormapped) into an SGI-style data array,
+and serves as a good template for users with other needs. I used it as
+an exmaple of how to make an iterator which, rather than fill a data
+array, calls an arbitrary user-supplied callback function for each
+"chunk" of data - that "chunk" might be a strip or a tile, and might
+have one sample-per-pixel or two, and might be 8-bit data or 16-bit or
+24-bit. The callback function can do whatever it wants with the data -
+store it in a big array, convert it to RGBA, or draw it directly to the
+screen. I was able to use this iterator to read 16-bit greyscale and 32-
+and 64-bit floating point data, which wasn't possible with ReadRGBA().
+
+I have tested this routine with 8- and 16-bit greyscale data as well as
+with 32- and 64-bit floating point data. I believe nearly all of our
+data is organized in strips, so actually I'd appreciate it if you had
+some tiled images that I could test it with.
+
+It should certainly be possible and would be cleanest to reimplement
+ReadRGBA() in terms of the image iterator, but I haven't done that.
+
+
+Private Sub-Directory Read/Write
+--------------------------------
+TIFF-PL is a Phillips Laboratory extension to the TIFF tags that allows
+us to store satellite imaging-specific information in a TIFF format,
+such as the satellite's trajectory, the imaging time, etc. In order to
+give us the flexibility to modify the tag definitions without getting
+approval from the TIFF committee every time, we were given only three
+TIFF tags - a PL signature, a PL version number, and PL directory
+offset, which lists the position in the file at which to find a private
+sub-directory of tags-value pairs. So I wrote two routines:
+TIFFWritePrivateDataSubDirectory(), which takes a list of tags and a
+"get" function and writes the tag values into the TIFF file, returning
+the offset within the file at which it wrote the directory; and
+TIFFReadPrivateDataSubDirectory(), which takes an offset, a list of
+tags, and a "set" function and reads all the data from the private
+directory. The functions themselves are pretty simple. (The files are
+huge because I had to basically copy all of the tif_dirread.c and
+tif_dirwrite.c files in order to access the various fetching routines
+which were all declared static and therefore inaccessible in the TIFF
+library.)
+
+
+I'm including the four source files (tif_imgiter.h, tif_imgiter.c,
+tif_pdsdirread.c, tif_pdsdirwrite.c) in case you want to take a look at
+them. I can also send you some sample code that uses them if you like.
+If you're interested in having them incorporated into the standard TIFF
+library, I'd be happy to do that integration and clean up and document
+the routines. (For example, I've already realized that instead of
+limiting the SEP callback function to three bands (R,G,B) it should take
+an array to enable the handling of n-banded multi-spectral data...) If
+not, I'll just leave them as they are, since they work fine for us now.
+
+Holler if you have any questions.
+
+-- Conrad
+__________________________________________________________________
+ Capt Conrad J. Poelman PL/WSAT (Phillips Laboratory)
+ 505-846-4347 3550 Aberdeen Ave SE
+ (FAX) 505-846-4374 Kirtland AFB, NM 87117-5776
+
diff --git a/tiff/contrib/pds/tif_imageiter.c b/tiff/contrib/pds/tif_imageiter.c
new file mode 100644
index 0000000..6140f96
--- /dev/null
+++ b/tiff/contrib/pds/tif_imageiter.c
@@ -0,0 +1,525 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/contrib/pds/tif_imageiter.c,v 1.3.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1996 Sam Leffler
+ * Copyright (c) 1991-1996 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Written by Conrad J. Poelman, PL/WSAT, Kirtland AFB, NM on 26 Mar 96.
+ *
+ * This file contains code to allow a calling program to "iterate" over each
+ * pixels in an image as it is read from the file. The iterator takes care of
+ * reading strips versus (possibly clipped) tiles, decoding the information
+ * according to the decoding method, and so on, so that calling program can
+ * ignore those details. The calling program does, however, need to be
+ * conscious of the type of the pixel data that it is receiving.
+ *
+ * For reasons of efficiency, the callback function actually gets called for
+ * "blocks" of pixels rather than for individual pixels. The format of the
+ * callback arguments is given below.
+ *
+ * This code was taken from TIFFReadRGBAImage() in tif_getimage.c of the original
+ * TIFF distribution, and simplified and generalized to provide this general
+ * iteration capability. Those routines could certainly be re-implemented in terms
+ * of a TIFFImageIter if desired.
+ *
+ */
+#include "tiffiop.h"
+#include "tif_imageiter.h"
+#include <assert.h>
+#include <stdio.h>
+
+static int gtTileContig(TIFFImageIter*, void *udata, uint32, uint32);
+static int gtTileSeparate(TIFFImageIter*, void *udata, uint32, uint32);
+static int gtStripContig(TIFFImageIter*, void *udata, uint32, uint32);
+static int gtStripSeparate(TIFFImageIter*, void *udata, uint32, uint32);
+
+static const char photoTag[] = "PhotometricInterpretation";
+
+static int
+isCCITTCompression(TIFF* tif)
+{
+ uint16 compress;
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
+ return (compress == COMPRESSION_CCITTFAX3 ||
+ compress == COMPRESSION_CCITTFAX4 ||
+ compress == COMPRESSION_CCITTRLE ||
+ compress == COMPRESSION_CCITTRLEW);
+}
+
+int
+TIFFImageIterBegin(TIFFImageIter* img, TIFF* tif, int stop, char emsg[1024])
+{
+ uint16* sampleinfo;
+ uint16 extrasamples;
+ uint16 planarconfig;
+ int colorchannels;
+
+ img->tif = tif;
+ img->stoponerr = stop;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample);
+ img->alpha = 0;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
+ &extrasamples, &sampleinfo);
+ if (extrasamples == 1)
+ switch (sampleinfo[0]) {
+ case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */
+ case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */
+ img->alpha = sampleinfo[0];
+ break;
+ }
+ colorchannels = img->samplesperpixel - extrasamples;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) {
+ switch (colorchannels) {
+ case 1:
+ if (isCCITTCompression(tif))
+ img->photometric = PHOTOMETRIC_MINISWHITE;
+ else
+ img->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 3:
+ img->photometric = PHOTOMETRIC_RGB;
+ break;
+ default:
+ sprintf(emsg, "Missing needed %s tag", photoTag);
+ return (0);
+ }
+ }
+ switch (img->photometric) {
+ case PHOTOMETRIC_PALETTE:
+ if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
+ &img->redcmap, &img->greencmap, &img->bluecmap)) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Missing required \"Colormap\" tag");
+ return (0);
+ }
+ /* fall thru... */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+/* This should work now so skip the check - BSR
+ if (planarconfig == PLANARCONFIG_CONTIG && img->samplesperpixel != 1) {
+ sprintf(emsg,
+ "Sorry, can not handle contiguous data with %s=%d, and %s=%d",
+ photoTag, img->photometric,
+ "Samples/pixel", img->samplesperpixel);
+ return (0);
+ }
+ */
+ break;
+ case PHOTOMETRIC_YCBCR:
+ if (planarconfig != PLANARCONFIG_CONTIG) {
+ sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d",
+ "Planarconfiguration", planarconfig);
+ return (0);
+ }
+ /* It would probably be nice to have a reality check here. */
+ { uint16 compress;
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
+ if (compress == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) {
+ /* can rely on libjpeg to convert to RGB */
+ /* XXX should restore current state on exit */
+ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ img->photometric = PHOTOMETRIC_RGB;
+ }
+ }
+ break;
+ case PHOTOMETRIC_RGB:
+ if (colorchannels < 3) {
+ sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
+ "Color channels", colorchannels);
+ return (0);
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED: {
+ uint16 inkset;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
+ if (inkset != INKSET_CMYK) {
+ sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+ "InkSet", inkset);
+ return (0);
+ }
+ if (img->samplesperpixel != 4) {
+ sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+ "Samples/pixel", img->samplesperpixel);
+ return (0);
+ }
+ break;
+ }
+ default:
+ sprintf(emsg, "Sorry, can not handle image with %s=%d",
+ photoTag, img->photometric);
+ return (0);
+ }
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
+
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation);
+ switch (img->orientation) {
+ case ORIENTATION_BOTRIGHT:
+ case ORIENTATION_RIGHTBOT: /* XXX */
+ case ORIENTATION_LEFTBOT: /* XXX */
+ TIFFWarning(TIFFFileName(tif), "using bottom-left orientation");
+ img->orientation = ORIENTATION_BOTLEFT;
+ /* fall thru... */
+ case ORIENTATION_BOTLEFT:
+ break;
+ case ORIENTATION_TOPRIGHT:
+ case ORIENTATION_RIGHTTOP: /* XXX */
+ case ORIENTATION_LEFTTOP: /* XXX */
+ default:
+ TIFFWarning(TIFFFileName(tif), "using top-left orientation");
+ img->orientation = ORIENTATION_TOPLEFT;
+ /* fall thru... */
+ case ORIENTATION_TOPLEFT:
+ break;
+ }
+
+ img->isContig =
+ !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1);
+ if (img->isContig) {
+ img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig;
+ } else {
+ img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate;
+ }
+ return (1);
+}
+
+int
+TIFFImageIterGet(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ if (img->get == NULL) {
+ TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup");
+ return (0);
+ }
+ if (img->callback.any == NULL) {
+ TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif),
+ "No \"put\" routine setupl; probably can not handle image format");
+ return (0);
+ }
+ return (*img->get)(img, udata, w, h);
+}
+
+TIFFImageIterEnd(TIFFImageIter* img)
+{
+ /* Nothing to free... ? */
+}
+
+/*
+ * Read the specified image into an ABGR-format raster.
+ */
+int
+TIFFReadImageIter(TIFF* tif,
+ uint32 rwidth, uint32 rheight, uint8* raster, int stop)
+{
+ char emsg[1024];
+ TIFFImageIter img;
+ int ok;
+
+ if (TIFFImageIterBegin(&img, tif, stop, emsg)) {
+ /* XXX verify rwidth and rheight against width and height */
+ ok = TIFFImageIterGet(&img, raster, rwidth, img.height);
+ TIFFImageIterEnd(&img);
+ } else {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), emsg);
+ ok = 0;
+ }
+ return (ok);
+}
+
+
+/*
+ * Get an tile-organized image that has
+ * PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ * SamplesPerPixel == 1
+ */
+static int
+gtTileContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ ImageIterTileContigRoutine callback = img->callback.contig;
+ uint16 orientation;
+ uint32 col, row;
+ uint32 tw, th;
+ u_char* buf;
+ int32 fromskew;
+ uint32 nrow;
+
+ buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif));
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+ orientation = img->orientation;
+ for (row = 0; row < h; row += th) {
+ nrow = (row + th > h ? h - row : th);
+ for (col = 0; col < w; col += tw) {
+ if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0 && img->stoponerr)
+ break;
+ if (col + tw > w) {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ uint32 npix = w - col;
+ fromskew = tw - npix;
+ (*callback)(img, udata, col, row, npix, nrow, fromskew, buf);
+ } else {
+ (*callback)(img, udata, col, row, tw, nrow, 0, buf);
+ }
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+/*
+ * Get an tile-organized image that has
+ * SamplesPerPixel > 1
+ * PlanarConfiguration separated
+ * We assume that all such images are RGB.
+ */
+static int
+gtTileSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ ImageIterTileSeparateRoutine callback = img->callback.separate;
+ uint16 orientation;
+ uint32 col, row;
+ uint32 tw, th;
+ u_char* buf;
+ u_char* r;
+ u_char* g;
+ u_char* b;
+ u_char* a;
+ tsize_t tilesize;
+ int32 fromskew;
+ int alpha = img->alpha;
+ uint32 nrow;
+
+ tilesize = TIFFTileSize(tif);
+ buf = (u_char*) _TIFFmalloc(4*tilesize);
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ r = buf;
+ g = r + tilesize;
+ b = g + tilesize;
+ a = b + tilesize;
+ if (!alpha)
+ memset(a, 0xff, tilesize);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+ orientation = img->orientation;
+ for (row = 0; row < h; row += th) {
+ nrow = (row + th > h ? h - row : th);
+ for (col = 0; col < w; col += tw) {
+ if (TIFFReadTile(tif, r, col, row,0,0) < 0 && img->stoponerr)
+ break;
+ if (TIFFReadTile(tif, g, col, row,0,1) < 0 && img->stoponerr)
+ break;
+ if (TIFFReadTile(tif, b, col, row,0,2) < 0 && img->stoponerr)
+ break;
+ if (alpha && TIFFReadTile(tif,a,col,row,0,3) < 0 && img->stoponerr)
+ break;
+ if (col + tw > w) {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ uint32 npix = w - col;
+ fromskew = tw - npix;
+ (*callback)(img, udata, col, row, npix, nrow, fromskew, r, g, b, a);
+ } else {
+ (*callback)(img, udata, col, row, tw, nrow, 0, r, g, b, a);
+ }
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+/*
+ * Get a strip-organized image that has
+ * PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ * SamplesPerPixel == 1
+ */
+static int
+gtStripContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ ImageIterTileContigRoutine callback = img->callback.contig;
+ uint16 orientation;
+ uint32 row, nrow;
+ u_char* buf;
+ uint32 rowsperstrip;
+ uint32 imagewidth = img->width;
+ tsize_t scanline;
+ int32 fromskew;
+
+ buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif));
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
+ return (0);
+ }
+ orientation = img->orientation;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ scanline = TIFFScanlineSize(tif);
+ fromskew = (w < imagewidth ? imagewidth - w : 0);
+ for (row = 0; row < h; row += rowsperstrip) {
+ nrow = (row + rowsperstrip > h ? h - row : rowsperstrip);
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0),
+ buf, nrow*scanline) < 0 && img->stoponerr)
+ break;
+ (*callback)(img, udata, 0, row, w, nrow, fromskew, buf);
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+/*
+ * Get a strip-organized image with
+ * SamplesPerPixel > 1
+ * PlanarConfiguration separated
+ * We assume that all such images are RGB.
+ */
+static int
+gtStripSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ ImageIterTileSeparateRoutine callback = img->callback.separate;
+ uint16 orientation;
+ u_char *buf;
+ u_char *r, *g, *b, *a;
+ uint32 row, nrow;
+ tsize_t scanline;
+ uint32 rowsperstrip;
+ uint32 imagewidth = img->width;
+ tsize_t stripsize;
+ int32 fromskew;
+ int alpha = img->alpha;
+
+ stripsize = TIFFStripSize(tif);
+ r = buf = (u_char *)_TIFFmalloc(4*stripsize);
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ g = r + stripsize;
+ b = g + stripsize;
+ a = b + stripsize;
+ if (!alpha)
+ memset(a, 0xff, stripsize);
+ orientation = img->orientation;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ scanline = TIFFScanlineSize(tif);
+ fromskew = (w < imagewidth ? imagewidth - w : 0);
+ for (row = 0; row < h; row += rowsperstrip) {
+ nrow = (row + rowsperstrip > h ? h - row : rowsperstrip);
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0),
+ r, nrow*scanline) < 0 && img->stoponerr)
+ break;
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 1),
+ g, nrow*scanline) < 0 && img->stoponerr)
+ break;
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 2),
+ b, nrow*scanline) < 0 && img->stoponerr)
+ break;
+ if (alpha &&
+ (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 3),
+ a, nrow*scanline) < 0 && img->stoponerr))
+ break;
+ (*callback)(img, udata, 0, row, w, nrow, fromskew, r, g, b, a);
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+DECLAREContigCallbackFunc(TestContigCallback)
+{
+ printf("Contig Callback called with x = %d, y = %d, w = %d, h = %d, fromskew = %d\n",
+ x, y, w, h, fromskew);
+}
+
+
+DECLARESepCallbackFunc(TestSepCallback)
+{
+ printf("Sep Callback called with x = %d, y = %d, w = %d, h = %d, fromskew = %d\n",
+ x, y, w, h, fromskew);
+}
+
+
+#ifdef MAIN
+main(int argc, char **argv)
+{
+ char emsg[1024];
+ TIFFImageIter img;
+ int ok;
+ int stop = 1;
+
+ TIFF *tif;
+ unsigned long nx, ny;
+ unsigned short BitsPerSample, SamplesPerPixel;
+ int isColorMapped, isPliFile;
+ unsigned char *ColorMap;
+ unsigned char *data;
+
+ if (argc < 2) {
+ fprintf(stderr,"usage: %s tiff_file\n",argv[0]);
+ exit(1);
+ }
+ tif = (TIFF *)PLIGetImage(argv[1], (void *) &data, &ColorMap,
+ &nx, &ny, &BitsPerSample, &SamplesPerPixel,
+ &isColorMapped, &isPliFile);
+ if (tif != NULL) {
+
+ if (TIFFImageIterBegin(&img, tif, stop, emsg)) {
+ /* Here need to set data and callback function! */
+ if (img.isContig) {
+ img.callback = TestContigCallback;
+ } else {
+ img.callback = TestSepCallback;
+ }
+ ok = TIFFImageIterGet(&img, NULL, img.width, img.height);
+ TIFFImageIterEnd(&img);
+ } else {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), emsg);
+ }
+ }
+
+}
+#endif
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/pds/tif_imageiter.h b/tiff/contrib/pds/tif_imageiter.h
new file mode 100644
index 0000000..e7dbe46
--- /dev/null
+++ b/tiff/contrib/pds/tif_imageiter.h
@@ -0,0 +1,64 @@
+typedef struct _TIFFImageIter TIFFImageIter;
+
+/* The callback function is called for each "block" of image pixel data after
+ it has been read from the file and decoded. This image pixel data is in the
+ buffer pp, and this data represents the image pixels from (x,y) to
+ (x+w,y+h). It is stored in pixel format, so each pixel contains
+ img->samplesperpixel consecutive samples each containing img->bitspersample
+ bits of data. The array pp is ordered in h consecutive rows of w+fromskew
+ pixels each. */
+typedef void (*ImageIterTileContigRoutine)
+ (TIFFImageIter*, void *, uint32, uint32, uint32, uint32, int32,
+ unsigned char*);
+#define DECLAREContigCallbackFunc(name) \
+static void name(\
+ TIFFImageIter* img, \
+ void* user_data, \
+ uint32 x, uint32 y, \
+ uint32 w, uint32 h, \
+ int32 fromskew, \
+ u_char* pp \
+)
+
+typedef void (*ImageIterTileSeparateRoutine)
+ (TIFFImageIter*, void *, uint32, uint32, uint32, uint32, int32,
+ unsigned char*, unsigned char*, unsigned char*, unsigned char*);
+#define DECLARESepCallbackFunc(name) \
+static void name(\
+ TIFFImageIter* img, \
+ void* user_data, \
+ uint32 x, uint32 y, \
+ uint32 w, uint32 h,\
+ int32 fromskew, \
+ u_char* r, u_char* g, u_char* b, u_char* a\
+)
+
+struct _TIFFImageIter {
+ TIFF* tif; /* image handle */
+ int stoponerr; /* stop on read error */
+ int isContig; /* data is packed/separate */
+ int alpha; /* type of alpha data present */
+ uint32 width; /* image width */
+ uint32 height; /* image height */
+ uint16 bitspersample; /* image bits/sample */
+ uint16 samplesperpixel; /* image samples/pixel */
+ uint16 orientation; /* image orientation */
+ uint16 photometric; /* image photometric interp */
+ uint16* redcmap; /* colormap pallete */
+ uint16* greencmap;
+ uint16* bluecmap;
+ /* get image data routine */
+ int (*get)(TIFFImageIter*, void *udata, uint32, uint32);
+ union {
+ void (*any)(TIFFImageIter*);
+ ImageIterTileContigRoutine contig;
+ ImageIterTileSeparateRoutine separate;
+ } callback; /* fn to exec for each block */
+};
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/pds/tif_pdsdirread.c b/tiff/contrib/pds/tif_pdsdirread.c
new file mode 100644
index 0000000..3d01311
--- /dev/null
+++ b/tiff/contrib/pds/tif_pdsdirread.c
@@ -0,0 +1,1131 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/contrib/pds/tif_pdsdirread.c,v 1.3.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1996 Sam Leffler
+ * Copyright (c) 1991-1996 Silicon Graphics, Inc.
+ * Copyright (c( 1996 USAF Phillips Laboratory
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * These routines written by Conrad J. Poelman on a single late-night of
+ * March 20-21, 1996.
+ *
+ * The entire purpose of this file is to provide a single external function,
+ * TIFFReadPrivateDataSubDirectory(). This function is intended for use in reading a
+ * private subdirectory from a TIFF file into a private structure. The
+ * actual writing of data into the structure is handled by the setFieldFn(),
+ * which is passed to TIFFReadPrivateDataSubDirectory() as a parameter. The idea is to
+ * enable any application wishing to store private subdirectories to do so
+ * easily using this function, without modifying the TIFF library.
+ *
+ * The astute observer will notice that only two functions are at all different
+ * from the original tif_dirread.c file: TIFFReadPrivateDataSubDirectory() and
+ * TIFFFetchNormalSubTag(). All the other stuff that makes this file so huge
+ * is only necessary because all of those functions are declared static in
+ * tif_dirread.c, so we have to totally duplicate them in order to use them.
+ *
+ * Oh, also note the bug fix in TIFFFetchFloat().
+ *
+ */
+
+#include "tiffiop.h"
+
+#define IGNORE 0 /* tag placeholder used below */
+
+#if HAVE_IEEEFP
+#define TIFFCvtIEEEFloatToNative(tif, n, fp)
+#define TIFFCvtIEEEDoubleToNative(tif, n, dp)
+#else
+extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*);
+extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*);
+#endif
+
+static void EstimateStripByteCounts(TIFF*, TIFFDirEntry*, uint16);
+static void MissingRequired(TIFF*, const char*);
+static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32);
+static tsize_t TIFFFetchData(TIFF*, TIFFDirEntry*, char*);
+static tsize_t TIFFFetchString(TIFF*, TIFFDirEntry*, char*);
+static float TIFFFetchRational(TIFF*, TIFFDirEntry*);
+static int TIFFFetchNormalSubTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*,
+ int (*getFieldFn)(TIFF *tif,ttag_t tag,...));
+static int TIFFFetchPerSampleShorts(TIFF*, TIFFDirEntry*, int*);
+static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchShortArray(TIFF*, TIFFDirEntry*, uint16*);
+static int TIFFFetchStripThing(TIFF*, TIFFDirEntry*, long, uint32**);
+static int TIFFFetchExtraSamples(TIFF*, TIFFDirEntry*);
+static int TIFFFetchRefBlackWhite(TIFF*, TIFFDirEntry*);
+static float TIFFFetchFloat(TIFF*, TIFFDirEntry*);
+static int TIFFFetchFloatArray(TIFF*, TIFFDirEntry*, float*);
+static int TIFFFetchDoubleArray(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchAnyArray(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchShortPair(TIFF*, TIFFDirEntry*);
+#if STRIPCHOP_SUPPORT
+static void ChopUpSingleUncompressedStrip(TIFF*);
+#endif
+
+static char *
+CheckMalloc(TIFF* tif, tsize_t n, const char* what)
+{
+ char *cp = (char*)_TIFFmalloc(n);
+ if (cp == NULL)
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "No space %s", what);
+ return (cp);
+}
+
+/* Just as was done with TIFFWritePrivateDataSubDirectory(), here we implement
+ TIFFReadPrivateDataSubDirectory() which takes an offset into the TIFF file,
+ a TIFFFieldInfo structure specifying the types of the various tags,
+ and a function to use to set individual tags when they are encountered.
+ The data is read from the file, translated using the TIFF library's
+ built-in machine-independent conversion functions, and filled into
+ private subdirectory structure.
+
+ This code was written by copying the original TIFFReadDirectory() function
+ from tif_dirread.c and paring it down to what is needed for this.
+
+ It is the caller's responsibility to allocate and initialize the internal
+ structure that setFieldFn() will be writing into. If this function is being
+ called more than once before closing the file, the caller also must be
+ careful to free data in the structure before re-initializing.
+
+ It is also the caller's responsibility to verify the presence of
+ any required fields after reading the directory in.
+*/
+
+
+int
+TIFFReadPrivateDataSubDirectory(TIFF* tif, toff_t pdir_offset,
+ TIFFFieldInfo *field_info,
+ int (*setFieldFn)(TIFF *tif, ttag_t tag, ...))
+{
+ register TIFFDirEntry* dp;
+ register int n;
+ register TIFFDirectory* td;
+ TIFFDirEntry* dir;
+ int iv;
+ long v;
+ double dv;
+ const TIFFFieldInfo* fip;
+ int fix;
+ uint16 dircount;
+ uint32 nextdiroff;
+ char* cp;
+ int diroutoforderwarning = 0;
+
+ /* Skipped part about checking for directories or compression data. */
+
+ if (!isMapped(tif)) {
+ if (!SeekOK(tif, pdir_offset)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Seek error accessing TIFF private subdirectory");
+ return (0);
+ }
+ if (!ReadOK(tif, &dircount, sizeof (uint16))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Can not read TIFF private subdirectory count");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ dir = (TIFFDirEntry *)CheckMalloc(tif,
+ dircount * sizeof (TIFFDirEntry), "to read TIFF private subdirectory");
+ if (dir == NULL)
+ return (0);
+ if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Can not read TIFF private subdirectory");
+ goto bad;
+ }
+ /*
+ * Read offset to next directory for sequential scans.
+ */
+ (void) ReadOK(tif, &nextdiroff, sizeof (uint32));
+ } else {
+ toff_t off = pdir_offset;
+
+ if (off + sizeof (short) > tif->tif_size) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Can not read TIFF private subdirectory count");
+ return (0);
+ } else
+ _TIFFmemcpy(&dircount, tif->tif_base + off, sizeof (uint16));
+ off += sizeof (uint16);
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ dir = (TIFFDirEntry *)CheckMalloc(tif,
+ dircount * sizeof (TIFFDirEntry), "to read TIFF private subdirectory");
+ if (dir == NULL)
+ return (0);
+ if (off + dircount*sizeof (TIFFDirEntry) > tif->tif_size) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Can not read TIFF private subdirectory");
+ goto bad;
+ } else
+ _TIFFmemcpy(dir, tif->tif_base + off,
+ dircount*sizeof (TIFFDirEntry));
+ off += dircount* sizeof (TIFFDirEntry);
+ if (off + sizeof (uint32) < tif->tif_size)
+ _TIFFmemcpy(&nextdiroff, tif->tif_base+off, sizeof (uint32));
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&nextdiroff);
+
+ /*
+ * Setup default value and then make a pass over
+ * the fields to check type and tag information,
+ * and to extract info required to size data
+ * structures. A second pass is made afterwards
+ * to read in everthing not taken in the first pass.
+ */
+ td = &tif->tif_dir;
+
+ for (fip = field_info, dp = dir, n = dircount;
+ n > 0; n--, dp++) {
+ if (tif->tif_flags & TIFF_SWAB) {
+ TIFFSwabArrayOfShort(&dp->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dp->tdir_count, 2);
+ }
+ /*
+ * Find the field information entry for this tag.
+ */
+ /*
+ * Silicon Beach (at least) writes unordered
+ * directory tags (violating the spec). Handle
+ * it here, but be obnoxious (maybe they'll fix it?).
+ */
+ if (dp->tdir_tag < fip->field_tag) {
+ if (!diroutoforderwarning) {
+ TIFFWarning(tif->tif_name,
+ "invalid TIFF private subdirectory; tags are not sorted in ascending order");
+ diroutoforderwarning = 1;
+ }
+ fip = field_info; /* O(n^2) */
+ }
+
+ while (fip->field_tag && fip->field_tag < dp->tdir_tag)
+ fip++;
+ if (!fip->field_tag || fip->field_tag != dp->tdir_tag) {
+ TIFFWarning(tif->tif_name,
+ "unknown field with tag %d (0x%x) in private subdirectory ignored",
+ dp->tdir_tag, dp->tdir_tag);
+ dp->tdir_tag = IGNORE;
+ fip = field_info;/* restart search */
+ continue;
+ }
+ /*
+ * Null out old tags that we ignore.
+ */
+
+ /* Not implemented yet, since FIELD_IGNORE is specific to
+ the main directories. Could pass this in too... */
+ if (0 /* && fip->field_bit == FIELD_IGNORE */) {
+ ignore:
+ dp->tdir_tag = IGNORE;
+ continue;
+ }
+
+ /*
+ * Check data type.
+ */
+
+ while (dp->tdir_type != (u_short)fip->field_type) {
+ if (fip->field_type == TIFF_ANY) /* wildcard */
+ break;
+ fip++;
+ if (!fip->field_tag || fip->field_tag != dp->tdir_tag) {
+ TIFFWarning(tif->tif_name,
+ "wrong data type %d for \"%s\"; tag ignored",
+ dp->tdir_type, fip[-1].field_name);
+ goto ignore;
+ }
+ }
+ /*
+ * Check count if known in advance.
+ */
+ if (fip->field_readcount != TIFF_VARIABLE) {
+ uint32 expected = (fip->field_readcount == TIFF_SPP) ?
+ (uint32) td->td_samplesperpixel :
+ (uint32) fip->field_readcount;
+ if (!CheckDirCount(tif, dp, expected))
+ goto ignore;
+ }
+
+ /* Now read in and process data from field. */
+ if (!TIFFFetchNormalSubTag(tif, dp, fip, setFieldFn))
+ goto bad;
+
+ }
+
+ if (dir)
+ _TIFFfree(dir);
+ return (1);
+bad:
+ if (dir)
+ _TIFFfree(dir);
+ return (0);
+}
+
+static void
+EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
+{
+ register TIFFDirEntry *dp;
+ register TIFFDirectory *td = &tif->tif_dir;
+ uint16 i;
+
+ if (td->td_stripbytecount)
+ _TIFFfree(td->td_stripbytecount);
+ td->td_stripbytecount = (uint32*)
+ CheckMalloc(tif, td->td_nstrips * sizeof (uint32),
+ "for \"StripByteCounts\" array");
+ if (td->td_compression != COMPRESSION_NONE) {
+ uint32 space = (uint32)(sizeof (TIFFHeader)
+ + sizeof (uint16)
+ + (dircount * sizeof (TIFFDirEntry))
+ + sizeof (uint32));
+ toff_t filesize = TIFFGetFileSize(tif);
+ uint16 n;
+
+ /* calculate amount of space used by indirect values */
+ for (dp = dir, n = dircount; n > 0; n--, dp++) {
+ uint32 cc = dp->tdir_count*TIFFDataWidth(dp->tdir_type);
+ if (cc > sizeof (uint32))
+ space += cc;
+ }
+ space = (filesize - space) / td->td_samplesperpixel;
+ for (i = 0; i < td->td_nstrips; i++)
+ td->td_stripbytecount[i] = space;
+ /*
+ * This gross hack handles the case were the offset to
+ * the last strip is past the place where we think the strip
+ * should begin. Since a strip of data must be contiguous,
+ * it's safe to assume that we've overestimated the amount
+ * of data in the strip and trim this number back accordingly.
+ */
+ i--;
+ if (td->td_stripoffset[i] + td->td_stripbytecount[i] > filesize)
+ td->td_stripbytecount[i] =
+ filesize - td->td_stripoffset[i];
+ } else {
+ uint32 rowbytes = TIFFScanlineSize(tif);
+ uint32 rowsperstrip = td->td_imagelength / td->td_nstrips;
+ for (i = 0; i < td->td_nstrips; i++)
+ td->td_stripbytecount[i] = rowbytes*rowsperstrip;
+ }
+ TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
+ if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
+ td->td_rowsperstrip = td->td_imagelength;
+}
+
+static void
+MissingRequired(TIFF* tif, const char* tagname)
+{
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "TIFF directory is missing required \"%s\" field", tagname);
+}
+
+/*
+ * Check the count field of a directory
+ * entry against a known value. The caller
+ * is expected to skip/ignore the tag if
+ * there is a mismatch.
+ */
+static int
+CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count)
+{
+ if (count != dir->tdir_count) {
+ TIFFWarning(tif->tif_name,
+ "incorrect count for field \"%s\" (%lu, expecting %lu); tag ignored",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
+ dir->tdir_count, count);
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Fetch a contiguous directory item.
+ */
+static tsize_t
+TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ int w = TIFFDataWidth(dir->tdir_type);
+ tsize_t cc = dir->tdir_count * w;
+
+ if (!isMapped(tif)) {
+ if (!SeekOK(tif, dir->tdir_offset))
+ goto bad;
+ if (!ReadOK(tif, cp, cc))
+ goto bad;
+ } else {
+ if (dir->tdir_offset + cc > tif->tif_size)
+ goto bad;
+ _TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc);
+ }
+ if (tif->tif_flags & TIFF_SWAB) {
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count);
+ break;
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count);
+ break;
+ }
+ }
+ return (cc);
+bad:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error fetching data for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return ((tsize_t) 0);
+}
+
+/*
+ * Fetch an ASCII item from the file.
+ */
+static tsize_t
+TIFFFetchString(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ if (dir->tdir_count <= 4) {
+ uint32 l = dir->tdir_offset;
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&l);
+ _TIFFmemcpy(cp, &l, dir->tdir_count);
+ return (1);
+ }
+ return (TIFFFetchData(tif, dir, cp));
+}
+
+/*
+ * Convert numerator+denominator to float.
+ */
+static int
+cvtRational(TIFF* tif, TIFFDirEntry* dir, uint32 num, uint32 denom, float* rv)
+{
+ if (denom == 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%s: Rational with zero denominator (num = %lu)",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num);
+ return (0);
+ } else {
+ if (dir->tdir_type == TIFF_RATIONAL)
+ *rv = ((float)num / (float)denom);
+ else
+ *rv = ((float)(int32)num / (float)(int32)denom);
+ return (1);
+ }
+}
+
+/*
+ * Fetch a rational item from the file
+ * at offset off and return the value
+ * as a floating point number.
+ */
+static float
+TIFFFetchRational(TIFF* tif, TIFFDirEntry* dir)
+{
+ uint32 l[2];
+ float v;
+
+ return (!TIFFFetchData(tif, dir, (char *)l) ||
+ !cvtRational(tif, dir, l[0], l[1], &v) ? 1.0f : v);
+}
+
+/*
+ * Fetch a single floating point value
+ * from the offset field and return it
+ * as a native float.
+ */
+static float
+TIFFFetchFloat(TIFF* tif, TIFFDirEntry* dir)
+{
+ /* This appears to be a flagrant bug in the TIFF library, yet I
+ actually don't understand how it could have ever worked the old
+ way. Look at the comments in my new code and you'll understand. */
+#if (0)
+ float v = (float)
+ TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset);
+ TIFFCvtIEEEFloatToNative(tif, 1, &v);
+#else
+ float v;
+ /* This is a little bit tricky - if we just cast the uint32 to a float,
+ C will perform a numerical conversion, which is not what we want.
+ We want to take the actual bit pattern in the uint32 and interpret
+ it as a float. Thus we cast a uint32 * into a float * and then
+ dereference to get v. */
+ uint32 l = (uint32)
+ TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset);
+ v = * (float *) &l;
+ TIFFCvtIEEEFloatToNative(tif, 1, &v);
+#endif
+ return (v);
+
+}
+
+/*
+ * Fetch an array of BYTE or SBYTE values.
+ */
+static int
+TIFFFetchByteArray(TIFF* tif, TIFFDirEntry* dir, uint16* v)
+{
+ if (dir->tdir_count <= 4) {
+ /*
+ * Extract data from offset field.
+ */
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ switch (dir->tdir_count) {
+ case 4: v[3] = dir->tdir_offset & 0xff;
+ case 3: v[2] = (dir->tdir_offset >> 8) & 0xff;
+ case 2: v[1] = (dir->tdir_offset >> 16) & 0xff;
+ case 1: v[0] = dir->tdir_offset >> 24;
+ }
+ } else {
+ switch (dir->tdir_count) {
+ case 4: v[3] = dir->tdir_offset >> 24;
+ case 3: v[2] = (dir->tdir_offset >> 16) & 0xff;
+ case 2: v[1] = (dir->tdir_offset >> 8) & 0xff;
+ case 1: v[0] = dir->tdir_offset & 0xff;
+ }
+ }
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char*) v) != 0); /* XXX */
+}
+
+/*
+ * Fetch an array of SHORT or SSHORT values.
+ */
+static int
+TIFFFetchShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v)
+{
+ if (dir->tdir_count <= 2) {
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ switch (dir->tdir_count) {
+ case 2: v[1] = dir->tdir_offset & 0xffff;
+ case 1: v[0] = dir->tdir_offset >> 16;
+ }
+ } else {
+ switch (dir->tdir_count) {
+ case 2: v[1] = dir->tdir_offset >> 16;
+ case 1: v[0] = dir->tdir_offset & 0xffff;
+ }
+ }
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char *)v) != 0);
+}
+
+/*
+ * Fetch a pair of SHORT or BYTE values.
+ */
+static int
+TIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir)
+{
+ uint16 v[2];
+ int ok = 0;
+
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ ok = TIFFFetchShortArray(tif, dir, v);
+ break;
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ ok = TIFFFetchByteArray(tif, dir, v);
+ break;
+ }
+ if (ok)
+ TIFFSetField(tif, dir->tdir_tag, v[0], v[1]);
+ return (ok);
+}
+
+/*
+ * Fetch an array of LONG or SLONG values.
+ */
+static int
+TIFFFetchLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v)
+{
+ if (dir->tdir_count == 1) {
+ v[0] = dir->tdir_offset;
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char*) v) != 0);
+}
+
+/*
+ * Fetch an array of RATIONAL or SRATIONAL values.
+ */
+static int
+TIFFFetchRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+ int ok = 0;
+ uint32* l;
+
+ l = (uint32*)CheckMalloc(tif,
+ dir->tdir_count*TIFFDataWidth(dir->tdir_type),
+ "to fetch array of rationals");
+ if (l) {
+ if (TIFFFetchData(tif, dir, (char *)l)) {
+ uint32 i;
+ for (i = 0; i < dir->tdir_count; i++) {
+ ok = cvtRational(tif, dir,
+ l[2*i+0], l[2*i+1], &v[i]);
+ if (!ok)
+ break;
+ }
+ }
+ _TIFFfree((char *)l);
+ }
+ return (ok);
+}
+
+/*
+ * Fetch an array of FLOAT values.
+ */
+static int
+TIFFFetchFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+
+ if (dir->tdir_count == 1) {
+ v[0] = *(float*) &dir->tdir_offset;
+ TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else if (TIFFFetchData(tif, dir, (char*) v)) {
+ TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * Fetch an array of DOUBLE values.
+ */
+static int
+TIFFFetchDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v)
+{
+ if (TIFFFetchData(tif, dir, (char*) v)) {
+ TIFFCvtIEEEDoubleToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * Fetch an array of ANY values. The actual values are
+ * returned as doubles which should be able hold all the
+ * types. Yes, there really should be an tany_t to avoid
+ * this potential non-portability ... Note in particular
+ * that we assume that the double return value vector is
+ * large enough to read in any fundamental type. We use
+ * that vector as a buffer to read in the base type vector
+ * and then convert it in place to double (from end
+ * to front of course).
+ */
+static int
+TIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double* v)
+{
+ int i;
+
+ switch (dir->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ if (!TIFFFetchByteArray(tif, dir, (uint16*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_BYTE) {
+ uint16* vp = (uint16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int16* vp = (int16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ if (!TIFFFetchShortArray(tif, dir, (uint16*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_SHORT) {
+ uint16* vp = (uint16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int16* vp = (int16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ if (!TIFFFetchLongArray(tif, dir, (uint32*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_LONG) {
+ uint32* vp = (uint32*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int32* vp = (int32*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ if (!TIFFFetchRationalArray(tif, dir, (float*) v))
+ return (0);
+ { float* vp = (float*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_FLOAT:
+ if (!TIFFFetchFloatArray(tif, dir, (float*) v))
+ return (0);
+ { float* vp = (float*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_DOUBLE:
+ return (TIFFFetchDoubleArray(tif, dir, (double*) v));
+ default:
+ /* TIFF_NOTYPE */
+ /* TIFF_ASCII */
+ /* TIFF_UNDEFINED */
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot read TIFF_ANY type %d for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return (0);
+ }
+ return (1);
+}
+
+
+/*
+ * Fetch a tag that is not handled by special case code.
+ */
+/* The standard function TIFFFetchNormalTag() could definitely be replaced
+ with a simple call to this function, just adding TIFFSetField() as the
+ last argument. */
+static int
+TIFFFetchNormalSubTag(TIFF* tif, TIFFDirEntry* dp, const TIFFFieldInfo* fip,
+ int (*setFieldFn)(TIFF *tif, ttag_t tag, ...))
+{
+ static char mesg[] = "to fetch tag value";
+ int ok = 0;
+
+ if (dp->tdir_count > 1) { /* array of values */
+ char* cp = NULL;
+
+ switch (dp->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ /* NB: always expand BYTE values to shorts */
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (uint16), mesg);
+ ok = cp && TIFFFetchByteArray(tif, dp, (uint16*) cp);
+ break;
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (uint16), mesg);
+ ok = cp && TIFFFetchShortArray(tif, dp, (uint16*) cp);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (uint32), mesg);
+ ok = cp && TIFFFetchLongArray(tif, dp, (uint32*) cp);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (float), mesg);
+ ok = cp && TIFFFetchRationalArray(tif, dp, (float*) cp);
+ break;
+ case TIFF_FLOAT:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (float), mesg);
+ ok = cp && TIFFFetchFloatArray(tif, dp, (float*) cp);
+ break;
+ case TIFF_DOUBLE:
+ cp = CheckMalloc(tif,
+ dp->tdir_count * sizeof (double), mesg);
+ ok = cp && TIFFFetchDoubleArray(tif, dp, (double*) cp);
+ break;
+ case TIFF_ASCII:
+ case TIFF_UNDEFINED: /* bit of a cheat... */
+ /*
+ * Some vendors write strings w/o the trailing
+ * NULL byte, so always append one just in case.
+ */
+ cp = CheckMalloc(tif, dp->tdir_count+1, mesg);
+ if (ok = (cp && TIFFFetchString(tif, dp, cp)))
+ cp[dp->tdir_count] = '\0'; /* XXX */
+ break;
+ }
+ if (ok) {
+ ok = (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, dp->tdir_count, cp)
+ : (*setFieldFn)(tif, dp->tdir_tag, cp));
+ }
+ if (cp != NULL)
+ _TIFFfree(cp);
+ } else if (CheckDirCount(tif, dp, 1)) { /* singleton value */
+ switch (dp->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ /*
+ * If the tag is also acceptable as a LONG or SLONG
+ * then (*setFieldFn) will expect an uint32 parameter
+ * passed to it (through varargs). Thus, for machines
+ * where sizeof (int) != sizeof (uint32) we must do
+ * a careful check here. It's hard to say if this
+ * is worth optimizing.
+ *
+ * NB: We use TIFFFieldWithTag here knowing that
+ * it returns us the first entry in the table
+ * for the tag and that that entry is for the
+ * widest potential data type the tag may have.
+ */
+ { TIFFDataType type = fip->field_type;
+ if (type != TIFF_LONG && type != TIFF_SLONG) {
+ uint16 v = (uint16)
+ TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset);
+ ok = (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, 1, &v)
+ : (*setFieldFn)(tif, dp->tdir_tag, v));
+ break;
+ }
+ }
+ /* fall thru... */
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ { uint32 v32 =
+ TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset);
+ ok = (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, 1, &v32)
+ : (*setFieldFn)(tif, dp->tdir_tag, v32));
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ { float v = (dp->tdir_type == TIFF_FLOAT ?
+ TIFFFetchFloat(tif, dp)
+ : TIFFFetchRational(tif, dp));
+ ok = (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, 1, &v)
+ : (*setFieldFn)(tif, dp->tdir_tag, v));
+ }
+ break;
+ case TIFF_DOUBLE:
+ { double v;
+ ok = (TIFFFetchDoubleArray(tif, dp, &v) &&
+ (fip->field_passcount ?
+ (*setFieldFn)(tif, dp->tdir_tag, 1, &v)
+ : (*setFieldFn)(tif, dp->tdir_tag, v))
+ );
+ }
+ break;
+ case TIFF_ASCII:
+ case TIFF_UNDEFINED: /* bit of a cheat... */
+ { char c[2];
+ if (ok = (TIFFFetchString(tif, dp, c) != 0)) {
+ c[1] = '\0'; /* XXX paranoid */
+ ok = (*setFieldFn)(tif, dp->tdir_tag, c);
+ }
+ }
+ break;
+ }
+ }
+ return (ok);
+}
+
+/* Everything after this is exactly duplicated from the standard tif_dirread.c
+ file, necessitated by the fact that they are declared static there so
+ we can't call them!
+*/
+#define NITEMS(x) (sizeof (x) / sizeof (x[0]))
+/*
+ * Fetch samples/pixel short values for
+ * the specified tag and verify that
+ * all values are the same.
+ */
+static int
+TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir, int* pl)
+{
+ int samples = tif->tif_dir.td_samplesperpixel;
+ int status = 0;
+
+ if (CheckDirCount(tif, dir, (uint32) samples)) {
+ uint16 buf[10];
+ uint16* v = buf;
+
+ if (samples > NITEMS(buf))
+ v = (uint16*) _TIFFmalloc(samples * sizeof (uint16));
+ if (TIFFFetchShortArray(tif, dir, v)) {
+ int i;
+ for (i = 1; i < samples; i++)
+ if (v[i] != v[0]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot handle different per-sample values for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ goto bad;
+ }
+ *pl = v[0];
+ status = 1;
+ }
+ bad:
+ if (v != buf)
+ _TIFFfree((char*) v);
+ }
+ return (status);
+}
+
+/*
+ * Fetch samples/pixel ANY values for
+ * the specified tag and verify that
+ * all values are the same.
+ */
+static int
+TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl)
+{
+ int samples = (int) tif->tif_dir.td_samplesperpixel;
+ int status = 0;
+
+ if (CheckDirCount(tif, dir, (uint32) samples)) {
+ double buf[10];
+ double* v = buf;
+
+ if (samples > NITEMS(buf))
+ v = (double*) _TIFFmalloc(samples * sizeof (double));
+ if (TIFFFetchAnyArray(tif, dir, v)) {
+ int i;
+ for (i = 1; i < samples; i++)
+ if (v[i] != v[0]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot handle different per-sample values for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ goto bad;
+ }
+ *pl = v[0];
+ status = 1;
+ }
+ bad:
+ if (v != buf)
+ _TIFFfree(v);
+ }
+ return (status);
+}
+#undef NITEMS
+
+/*
+ * Fetch a set of offsets or lengths.
+ * While this routine says "strips",
+ * in fact it's also used for tiles.
+ */
+static int
+TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, long nstrips, uint32** lpp)
+{
+ register uint32* lp;
+ int status;
+
+ if (!CheckDirCount(tif, dir, (uint32) nstrips))
+ return (0);
+ /*
+ * Allocate space for strip information.
+ */
+ if (*lpp == NULL &&
+ (*lpp = (uint32 *)CheckMalloc(tif,
+ nstrips * sizeof (uint32), "for strip array")) == NULL)
+ return (0);
+ lp = *lpp;
+ if (dir->tdir_type == (int)TIFF_SHORT) {
+ /*
+ * Handle uint16->uint32 expansion.
+ */
+ uint16* dp = (uint16*) CheckMalloc(tif,
+ dir->tdir_count* sizeof (uint16), "to fetch strip tag");
+ if (dp == NULL)
+ return (0);
+ if (status = TIFFFetchShortArray(tif, dir, dp)) {
+ register uint16* wp = dp;
+ while (nstrips-- > 0)
+ *lp++ = *wp++;
+ }
+ _TIFFfree((char*) dp);
+ } else
+ status = TIFFFetchLongArray(tif, dir, lp);
+ return (status);
+}
+
+#define NITEMS(x) (sizeof (x) / sizeof (x[0]))
+/*
+ * Fetch and set the ExtraSamples tag.
+ */
+static int
+TIFFFetchExtraSamples(TIFF* tif, TIFFDirEntry* dir)
+{
+ uint16 buf[10];
+ uint16* v = buf;
+ int status;
+
+ if (dir->tdir_count > NITEMS(buf))
+ v = (uint16*) _TIFFmalloc(dir->tdir_count * sizeof (uint16));
+ if (dir->tdir_type == TIFF_BYTE)
+ status = TIFFFetchByteArray(tif, dir, v);
+ else
+ status = TIFFFetchShortArray(tif, dir, v);
+ if (status)
+ status = TIFFSetField(tif, dir->tdir_tag, dir->tdir_count, v);
+ if (v != buf)
+ _TIFFfree((char*) v);
+ return (status);
+}
+#undef NITEMS
+
+#ifdef COLORIMETRY_SUPPORT
+/*
+ * Fetch and set the RefBlackWhite tag.
+ */
+static int
+TIFFFetchRefBlackWhite(TIFF* tif, TIFFDirEntry* dir)
+{
+ static char mesg[] = "for \"ReferenceBlackWhite\" array";
+ char* cp;
+ int ok;
+
+ if (dir->tdir_type == TIFF_RATIONAL)
+ return (1/*TIFFFetchNormalTag(tif, dir) just so linker won't complain - this part of the code is never used anyway */);
+ /*
+ * Handle LONG's for backward compatibility.
+ */
+ cp = CheckMalloc(tif, dir->tdir_count * sizeof (uint32), mesg);
+ if (ok = (cp && TIFFFetchLongArray(tif, dir, (uint32*) cp))) {
+ float* fp = (float*)
+ CheckMalloc(tif, dir->tdir_count * sizeof (float), mesg);
+ if (ok = (fp != NULL)) {
+ uint32 i;
+ for (i = 0; i < dir->tdir_count; i++)
+ fp[i] = (float)((uint32*) cp)[i];
+ ok = TIFFSetField(tif, dir->tdir_tag, fp);
+ _TIFFfree((char*) fp);
+ }
+ }
+ if (cp)
+ _TIFFfree(cp);
+ return (ok);
+}
+#endif
+
+#if STRIPCHOP_SUPPORT
+/*
+ * Replace a single strip (tile) of uncompressed data by
+ * multiple strips (tiles), each approximately 8Kbytes.
+ * This is useful for dealing with large images or
+ * for dealing with machines with a limited amount
+ * memory.
+ */
+static void
+ChopUpSingleUncompressedStrip(TIFF* tif)
+{
+ register TIFFDirectory *td = &tif->tif_dir;
+ uint32 bytecount = td->td_stripbytecount[0];
+ uint32 offset = td->td_stripoffset[0];
+ tsize_t rowbytes = TIFFVTileSize(tif, 1), stripbytes;
+ tstrip_t strip, nstrips, rowsperstrip;
+ uint32* newcounts;
+ uint32* newoffsets;
+
+ /*
+ * Make the rows hold at least one
+ * scanline, but fill 8k if possible.
+ */
+ if (rowbytes > 8192) {
+ stripbytes = rowbytes;
+ rowsperstrip = 1;
+ } else {
+ rowsperstrip = 8192 / rowbytes;
+ stripbytes = rowbytes * rowsperstrip;
+ }
+ /* never increase the number of strips in an image */
+ if (rowsperstrip >= td->td_rowsperstrip)
+ return;
+ nstrips = (tstrip_t) TIFFhowmany(bytecount, stripbytes);
+ newcounts = (uint32*) CheckMalloc(tif, nstrips * sizeof (uint32),
+ "for chopped \"StripByteCounts\" array");
+ newoffsets = (uint32*) CheckMalloc(tif, nstrips * sizeof (uint32),
+ "for chopped \"StripOffsets\" array");
+ if (newcounts == NULL || newoffsets == NULL) {
+ /*
+ * Unable to allocate new strip information, give
+ * up and use the original one strip information.
+ */
+ if (newcounts != NULL)
+ _TIFFfree(newcounts);
+ if (newoffsets != NULL)
+ _TIFFfree(newoffsets);
+ return;
+ }
+ /*
+ * Fill the strip information arrays with
+ * new bytecounts and offsets that reflect
+ * the broken-up format.
+ */
+ for (strip = 0; strip < nstrips; strip++) {
+ if (stripbytes > bytecount)
+ stripbytes = bytecount;
+ newcounts[strip] = stripbytes;
+ newoffsets[strip] = offset;
+ offset += stripbytes;
+ bytecount -= stripbytes;
+ }
+ /*
+ * Replace old single strip info with multi-strip info.
+ */
+ td->td_stripsperimage = td->td_nstrips = nstrips;
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ _TIFFfree(td->td_stripbytecount);
+ _TIFFfree(td->td_stripoffset);
+ td->td_stripbytecount = newcounts;
+ td->td_stripoffset = newoffsets;
+}
+#endif /* STRIPCHOP_SUPPORT */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/pds/tif_pdsdirwrite.c b/tiff/contrib/pds/tif_pdsdirwrite.c
new file mode 100644
index 0000000..eb71d42
--- /dev/null
+++ b/tiff/contrib/pds/tif_pdsdirwrite.c
@@ -0,0 +1,971 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/contrib/pds/tif_pdsdirwrite.c,v 1.3.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/* When writing data to TIFF files, it is often useful to store application-
+ specific data in a private TIFF directory so that the tags don't need to
+ be registered and won't conflict with other people's user-defined tags.
+ One needs to have a registered public tag which contains some amount of
+ raw data. That raw data, however, is interpreted at an independent,
+ separate, private tiff directory. This file provides some routines which
+ will be useful for converting that data from its raw binary form into
+ the proper form for your application.
+*/
+
+/*
+ * Copyright (c) 1988-1996 Sam Leffler
+ * Copyright (c) 1991-1996 Silicon Graphics, Inc.
+ * Copyright (c( 1996 USAF Phillips Laboratory
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * These routines written by Conrad J. Poelman on a single late-night of
+ * March 20-21, 1996.
+ *
+ * The entire purpose of this file is to provide a single external function,
+ * TIFFWritePrivateDataSubDirectory(). This function is intended for use
+ * in writing a private subdirectory structure into a TIFF file. The
+ * actual reading of data from the structure is handled by the getFieldFn(),
+ * which is passed to TIFFWritePrivateDataSubDirectory() as a parameter. The
+ * idea is to enable any application wishing to read private subdirectories to
+ * do so easily using this function, without modifying the TIFF library.
+ *
+ * The astute observer will notice that only two functions are at all different
+ * from the original tif_dirwrite.c file: TIFFWritePrivateDataSubDirectory()and
+ * TIFFWriteNormalSubTag(). All the other stuff that makes this file so huge
+ * is only necessary because all of those functions are declared static in
+ * tif_dirwrite.c, so we have to totally duplicate them in order to use them.
+ *
+ * Oh, also please note the bug-fix in the routine TIFFWriteNormalSubTag(),
+ * which equally should be applied to TIFFWriteNormalTag().
+ *
+ */
+#include "tiffiop.h"
+
+#if HAVE_IEEEFP
+#define TIFFCvtNativeToIEEEFloat(tif, n, fp)
+#define TIFFCvtNativeToIEEEDouble(tif, n, dp)
+#else
+extern void TIFFCvtNativeToIEEEFloat(TIFF*, uint32, float*);
+extern void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*);
+#endif
+
+static int TIFFWriteNormalTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*);
+static int TIFFWriteNormalSubTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*,
+ int (*getFieldFn)(TIFF *tif,ttag_t tag,...));
+static void TIFFSetupShortLong(TIFF*, ttag_t, TIFFDirEntry*, uint32);
+static int TIFFSetupShortPair(TIFF*, ttag_t, TIFFDirEntry*);
+static int TIFFWritePerSampleShorts(TIFF*, ttag_t, TIFFDirEntry*);
+static int TIFFWritePerSampleAnys(TIFF*, TIFFDataType, ttag_t, TIFFDirEntry*);
+static int TIFFWriteShortTable(TIFF*, ttag_t, TIFFDirEntry*, uint32, uint16**);
+static int TIFFWriteShortArray(TIFF*,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, uint16*);
+static int TIFFWriteLongArray(TIFF *,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, uint32*);
+static int TIFFWriteRationalArray(TIFF *,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, float*);
+static int TIFFWriteFloatArray(TIFF *,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, float*);
+static int TIFFWriteDoubleArray(TIFF *,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*);
+static int TIFFWriteByteArray(TIFF*, TIFFDirEntry*, char*);
+static int TIFFWriteAnyArray(TIFF*,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*);
+#ifdef COLORIMETRY_SUPPORT
+static int TIFFWriteTransferFunction(TIFF*, TIFFDirEntry*);
+#endif
+static int TIFFWriteData(TIFF*, TIFFDirEntry*, char*);
+static int TIFFLinkDirectory(TIFF*);
+
+#define WriteRationalPair(type, tag1, v1, tag2, v2) { \
+ if (!TIFFWriteRational(tif, type, tag1, dir, v1)) \
+ goto bad; \
+ if (!TIFFWriteRational(tif, type, tag2, dir+1, v2)) \
+ goto bad; \
+ dir++; \
+}
+#define TIFFWriteRational(tif, type, tag, dir, v) \
+ TIFFWriteRationalArray((tif), (type), (tag), (dir), 1, &(v))
+#ifndef TIFFWriteRational
+static int TIFFWriteRational(TIFF*,
+ TIFFDataType, ttag_t, TIFFDirEntry*, float);
+#endif
+
+/* This function will write an entire directory to the disk, and return the
+ offset value indicating where in the file it wrote the beginning of the
+ directory structure. This is NOT the same as the offset value before
+ calling this function, because some of the fields may have caused various
+ data items to be written out BEFORE writing the directory structure.
+
+ This code was basically written by ripping of the TIFFWriteDirectory()
+ code and generalizing it, using RPS's TIFFWritePliIfd() code for
+ inspiration. My original goal was to make this code general enough that
+ the original TIFFWriteDirectory() could be rewritten to just call this
+ function with the appropriate field and field-accessing arguments.
+
+ However, now I realize that there's a lot of code that gets executed for
+ the main, standard TIFF directories that does not apply to special
+ private subdirectories, so such a reimplementation for the sake of
+ eliminating redundant or duplicate code is probably not possible,
+ unless we also pass in a Main flag to indiciate which type of handling
+ to do, which would be kind of a hack. I've marked those places where I
+ changed or ripped out code which would have to be re-inserted to
+ generalize this function. If it can be done in a clean and graceful way,
+ it would be a great way to generalize the TIFF library. Otherwise, I'll
+ just leave this code here where it duplicates but remains on top of and
+ hopefully mostly independent of the main TIFF library.
+
+ The caller will probably want to free the sub directory structure after
+ returning from this call, since otherwise once written out, the user
+ is likely to forget about it and leave data lying around.
+*/
+toff_t
+TIFFWritePrivateDataSubDirectory(TIFF* tif,
+ uint32 pdir_fieldsset[], int pdir_fields_last,
+ TIFFFieldInfo *field_info,
+ int (*getFieldFn)(TIFF *tif, ttag_t tag, ...))
+{
+ uint16 dircount;
+ uint32 diroff, nextdiroff;
+ ttag_t tag;
+ uint32 nfields;
+ tsize_t dirsize;
+ char* data;
+ TIFFDirEntry* dir;
+ u_long b, *fields, fields_size;
+ toff_t directory_offset;
+ TIFFFieldInfo* fip;
+
+ /*
+ * Deleted out all of the encoder flushing and such code from here -
+ * not necessary for subdirectories.
+ */
+
+ /* Finish writing out any image data. */
+ TIFFFlushData(tif);
+
+ /*
+ * Size the directory so that we can calculate
+ * offsets for the data items that aren't kept
+ * in-place in each field.
+ */
+ nfields = 0;
+ for (b = 0; b <= pdir_fields_last; b++)
+ if (FieldSet(pdir_fieldsset, b))
+ /* Deleted code to make size of first 4 tags 2
+ instead of 1. */
+ nfields += 1;
+ dirsize = nfields * sizeof (TIFFDirEntry);
+ data = (char*) _TIFFmalloc(dirsize);
+ if (data == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot write private subdirectory, out of space");
+ return (0);
+ }
+ /*
+ * Place directory in data section of the file. If there isn't one
+ * yet, place it at the end of the file. The directory is treated as
+ * data, so we don't link it into the directory structure at all.
+ */
+ if (tif->tif_dataoff == 0)
+ tif->tif_dataoff =(TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
+ diroff = tif->tif_dataoff;
+ tif->tif_dataoff = (toff_t)(
+ diroff + sizeof (uint16) + dirsize + sizeof (toff_t));
+ if (tif->tif_dataoff & 1)
+ tif->tif_dataoff++;
+ (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
+ /*tif->tif_curdir++;*/
+ dir = (TIFFDirEntry*) data;
+ /*
+ * Setup external form of directory
+ * entries and write data items.
+ */
+ /*
+ * We make a local copy of the fieldsset here so that we don't mess
+ * up the original one when we call ResetFieldBit(). But I'm not sure
+ * why the original code calls ResetFieldBit(), since we're already
+ * going through the fields in order...
+ *
+ * fields_size is the number of uint32's we will need to hold the
+ * bit-mask for all of the fields. If our highest field number is
+ * 100, then we'll need 100 / (8*4)+1 == 4 uint32's to hold the
+ * fieldset.
+ *
+ * Unlike the original code, we allocate fields dynamically based
+ * on the requested pdir_fields_last value, allowing private
+ * data subdirectories to contain more than the built-in code's limit
+ * of 95 tags in a directory.
+ */
+ fields_size = pdir_fields_last / (8*sizeof(uint32)) + 1;
+ fields = _TIFFmalloc(fields_size*sizeof(uint32));
+ _TIFFmemcpy(fields, pdir_fieldsset, fields_size * sizeof(uint32));
+
+ /* Deleted "write out extra samples tag" code here. */
+
+ /* Deleted code for checking a billion little special cases for the
+ * standard TIFF tags. Should add a general mechanism for overloading
+ * write function for each field, just like Brian kept telling me!!!
+ */
+ for (fip = field_info; fip->field_tag; fip++) {
+ /* Deleted code to check for FIELD_IGNORE!! */
+ if (/* fip->field_bit == FIELD_IGNORE || */
+ !FieldSet(fields, fip->field_bit))
+ continue;
+ if (!TIFFWriteNormalSubTag(tif, dir, fip, getFieldFn))
+ goto bad;
+ dir++;
+ ResetFieldBit(fields, fip->field_bit);
+ }
+
+ /* Now we've written all of the referenced data, and are about to
+ write the main directory structure, so grab the tif_dataoff value
+ now so we can remember where we wrote the directory. */
+ directory_offset = tif->tif_dataoff;
+
+ /*
+ * Write directory.
+ */
+ dircount = (uint16) nfields;
+ /* Deleted code to link to the next directory - we set it to zero! */
+ nextdiroff = 0;
+ if (tif->tif_flags & TIFF_SWAB) {
+ /*
+ * The file's byte order is opposite to the
+ * native machine architecture. We overwrite
+ * the directory information with impunity
+ * because it'll be released below after we
+ * write it to the file. Note that all the
+ * other tag construction routines assume that
+ * we do this byte-swapping; i.e. they only
+ * byte-swap indirect data.
+ */
+ for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) {
+ TIFFSwabArrayOfShort(&dir->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dir->tdir_count, 2);
+ }
+ dircount = (uint16) nfields;
+ TIFFSwabShort(&dircount);
+ TIFFSwabLong(&nextdiroff);
+ }
+
+ (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
+ if (!WriteOK(tif, &dircount, sizeof (dircount))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing private subdirectory count");
+ goto bad;
+ }
+ if (!WriteOK(tif, data, dirsize)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing private subdirectory contents");
+ goto bad;
+ }
+ if (!WriteOK(tif, &nextdiroff, sizeof (nextdiroff))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing private subdirectory link");
+ goto bad;
+ }
+ tif->tif_dataoff += sizeof(dircount) + dirsize + sizeof(nextdiroff);
+
+ _TIFFfree(data);
+ _TIFFfree(fields);
+ tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+
+#if (0)
+ /* This stuff commented out because I don't think we want it for
+ subdirectories, but I could be wrong. */
+ (*tif->tif_cleanup)(tif);
+
+ /*
+ * Reset directory-related state for subsequent
+ * directories.
+ */
+ TIFFDefaultDirectory(tif);
+ tif->tif_curoff = 0;
+ tif->tif_row = (uint32) -1;
+ tif->tif_curstrip = (tstrip_t) -1;
+#endif
+
+ return (directory_offset);
+bad:
+ _TIFFfree(data);
+ _TIFFfree(fields);
+ return (0);
+}
+#undef WriteRationalPair
+
+/*
+ * Process tags that are not special cased.
+ */
+/* The standard function TIFFWriteNormalTag() could definitely be replaced
+ with a simple call to this function, just adding TIFFGetField() as the
+ last argument. */
+static int
+TIFFWriteNormalSubTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip,
+ int (*getFieldFn)(TIFF *tif, ttag_t tag, ...))
+{
+ u_short wc = (u_short) fip->field_writecount;
+
+ dir->tdir_tag = fip->field_tag;
+ dir->tdir_type = (u_short) fip->field_type;
+ dir->tdir_count = wc;
+#define WRITEF(x,y) x(tif, fip->field_type, fip->field_tag, dir, wc, y)
+ switch (fip->field_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ if (wc > 1) {
+ uint16* wp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &wp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &wp);
+ if (!WRITEF(TIFFWriteShortArray, wp))
+ return (0);
+ } else {
+ uint16 sv;
+ (*getFieldFn)(tif, fip->field_tag, &sv);
+ dir->tdir_offset =
+ TIFFInsertData(tif, dir->tdir_type, sv);
+ }
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ if (wc > 1) {
+ uint32* lp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &lp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &lp);
+ if (!WRITEF(TIFFWriteLongArray, lp))
+ return (0);
+ } else {
+ /* XXX handle LONG->SHORT conversion */
+ (*getFieldFn)(tif, fip->field_tag, &dir->tdir_offset);
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ if (wc > 1) {
+ float* fp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &fp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &fp);
+ if (!WRITEF(TIFFWriteRationalArray, fp))
+ return (0);
+ } else {
+ float fv;
+ (*getFieldFn)(tif, fip->field_tag, &fv);
+ if (!WRITEF(TIFFWriteRationalArray, &fv))
+ return (0);
+ }
+ break;
+ case TIFF_FLOAT:
+ if (wc > 1) {
+ float* fp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &fp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &fp);
+ if (!WRITEF(TIFFWriteFloatArray, fp))
+ return (0);
+ } else {
+ float fv;
+ (*getFieldFn)(tif, fip->field_tag, &fv);
+ if (!WRITEF(TIFFWriteFloatArray, &fv))
+ return (0);
+ }
+ break;
+ case TIFF_DOUBLE:
+ /* Hey - I think this is a bug, or at least a "gross
+ inconsistency", in the TIFF library. Look at the original
+ TIFF library code below within the "#if (0) ... #else".
+ Just from the type of *dp, you can see that this code
+ expects TIFFGetField() to be handed a double ** for
+ any TIFF_DOUBLE tag, even for the constant wc==1 case.
+ This is totally inconsistent with other fields (like
+ TIFF_FLOAT, above) and is also inconsistent with the
+ TIFFSetField() function for TIFF_DOUBLEs, which expects
+ to be passed a single double by value for the wc==1 case.
+ (See the handling of TIFFFetchNormalTag() in tif_dirread.c
+ for an example.) Maybe this function was written before
+ TIFFWriteDoubleArray() was written, not that that's an
+ excuse. Anyway, the new code below is a trivial modification
+ of the TIFF_FLOAT code above. The fact that even single
+ doubles get written out in the data segment and get an
+ offset value stored is irrelevant here - that is all
+ handled by TIFFWriteDoubleArray(). */
+#if (0)
+ { double* dp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &dp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &dp);
+ TIFFCvtNativeToIEEEDouble(tif, wc, dp);
+ if (!TIFFWriteData(tif, dir, (char*) dp))
+ return (0);
+ }
+#else
+ if (wc > 1) {
+ double* dp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &dp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &dp);
+ if (!WRITEF(TIFFWriteDoubleArray, dp))
+ return (0);
+ } else {
+ double dv;
+ (*getFieldFn)(tif, fip->field_tag, &dv);
+ if (!WRITEF(TIFFWriteDoubleArray, &dv))
+ return (0);
+ }
+#endif
+ break;
+ case TIFF_ASCII:
+ { char* cp;
+ (*getFieldFn)(tif, fip->field_tag, &cp);
+ dir->tdir_count = (uint32) (strlen(cp) + 1);
+ if (!TIFFWriteByteArray(tif, dir, cp))
+ return (0);
+ }
+ break;
+ case TIFF_UNDEFINED:
+ { char* cp;
+ if (wc == (u_short) TIFF_VARIABLE) {
+ (*getFieldFn)(tif, fip->field_tag, &wc, &cp);
+ dir->tdir_count = wc;
+ } else
+ (*getFieldFn)(tif, fip->field_tag, &cp);
+ if (!TIFFWriteByteArray(tif, dir, cp))
+ return (0);
+ }
+ break;
+ }
+ return (1);
+}
+#undef WRITEF
+
+/* Everything after this is exactly duplicated from the standard tif_dirwrite.c
+ file, necessitated by the fact that they are declared static there so
+ we can't call them!
+*/
+/*
+ * Setup a directory entry with either a SHORT
+ * or LONG type according to the value.
+ */
+static void
+TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_count = 1;
+ if (v > 0xffffL) {
+ dir->tdir_type = (short) TIFF_LONG;
+ dir->tdir_offset = v;
+ } else {
+ dir->tdir_type = (short) TIFF_SHORT;
+ dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v);
+ }
+}
+#undef MakeShortDirent
+
+#ifndef TIFFWriteRational
+/*
+ * Setup a RATIONAL directory entry and
+ * write the associated indirect value.
+ */
+static int
+TIFFWriteRational(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, float v)
+{
+ return (TIFFWriteRationalArray(tif, type, tag, dir, 1, &v));
+}
+#endif
+
+#define NITEMS(x) (sizeof (x) / sizeof (x[0]))
+/*
+ * Setup a directory entry that references a
+ * samples/pixel array of SHORT values and
+ * (potentially) write the associated indirect
+ * values.
+ */
+static int
+TIFFWritePerSampleShorts(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
+{
+ uint16 buf[10], v;
+ uint16* w = buf;
+ int i, status, samples = tif->tif_dir.td_samplesperpixel;
+
+ if (samples > NITEMS(buf))
+ w = (uint16*) _TIFFmalloc(samples * sizeof (uint16));
+ TIFFGetField(tif, tag, &v);
+ for (i = 0; i < samples; i++)
+ w[i] = v;
+ status = TIFFWriteShortArray(tif, TIFF_SHORT, tag, dir, samples, w);
+ if (w != buf)
+ _TIFFfree((char*) w);
+ return (status);
+}
+
+/*
+ * Setup a directory entry that references a samples/pixel array of ``type''
+ * values and (potentially) write the associated indirect values. The source
+ * data from TIFFGetField() for the specified tag must be returned as double.
+ */
+static int
+TIFFWritePerSampleAnys(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir)
+{
+ double buf[10], v;
+ double* w = buf;
+ int i, status;
+ int samples = (int) tif->tif_dir.td_samplesperpixel;
+
+ if (samples > NITEMS(buf))
+ w = (double*) _TIFFmalloc(samples * sizeof (double));
+ TIFFGetField(tif, tag, &v);
+ for (i = 0; i < samples; i++)
+ w[i] = v;
+ status = TIFFWriteAnyArray(tif, type, tag, dir, samples, w);
+ if (w != buf)
+ _TIFFfree(w);
+ return (status);
+}
+#undef NITEMS
+
+/*
+ * Setup a pair of shorts that are returned by
+ * value, rather than as a reference to an array.
+ */
+static int
+TIFFSetupShortPair(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
+{
+ uint16 v[2];
+
+ TIFFGetField(tif, tag, &v[0], &v[1]);
+ return (TIFFWriteShortArray(tif, TIFF_SHORT, tag, dir, 2, v));
+}
+
+/*
+ * Setup a directory entry for an NxM table of shorts,
+ * where M is known to be 2**bitspersample, and write
+ * the associated indirect data.
+ */
+static int
+TIFFWriteShortTable(TIFF* tif,
+ ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16** table)
+{
+ uint32 i, off;
+
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) TIFF_SHORT;
+ /* XXX -- yech, fool TIFFWriteData */
+ dir->tdir_count = (uint32) (1L<<tif->tif_dir.td_bitspersample);
+ off = tif->tif_dataoff;
+ for (i = 0; i < n; i++)
+ if (!TIFFWriteData(tif, dir, (char *)table[i]))
+ return (0);
+ dir->tdir_count *= n;
+ dir->tdir_offset = off;
+ return (1);
+}
+
+/*
+ * Write/copy data associated with an ASCII or opaque tag value.
+ */
+static int
+TIFFWriteByteArray(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ if (dir->tdir_count > 4) {
+ if (!TIFFWriteData(tif, dir, cp))
+ return (0);
+ } else
+ _TIFFmemcpy(&dir->tdir_offset, cp, dir->tdir_count);
+ return (1);
+}
+
+/*
+ * Setup a directory entry of an array of SHORT
+ * or SSHORT and write the associated indirect values.
+ */
+static int
+TIFFWriteShortArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16* v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ if (n <= 2) {
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ dir->tdir_offset = (uint32) ((long) v[0] << 16);
+ if (n == 2)
+ dir->tdir_offset |= v[1] & 0xffff;
+ } else {
+ dir->tdir_offset = v[0] & 0xffff;
+ if (n == 2)
+ dir->tdir_offset |= (long) v[1] << 16;
+ }
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Setup a directory entry of an array of LONG
+ * or SLONG and write the associated indirect values.
+ */
+static int
+TIFFWriteLongArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, uint32* v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ if (n == 1) {
+ dir->tdir_offset = v[0];
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Setup a directory entry of an array of RATIONAL
+ * or SRATIONAL and write the associated indirect values.
+ */
+static int
+TIFFWriteRationalArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, float* v)
+{
+ uint32 i;
+ uint32* t;
+ int status;
+
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ t = (uint32*) _TIFFmalloc(2*n * sizeof (uint32));
+ for (i = 0; i < n; i++) {
+ float fv = v[i];
+ int sign = 1;
+ uint32 den;
+
+ if (fv < 0) {
+ if (type == TIFF_RATIONAL) {
+ TIFFWarning(tif->tif_name,
+ "\"%s\": Information lost writing value (%g) as (unsigned) RATIONAL",
+ _TIFFFieldWithTag(tif,tag)->field_name, v);
+ fv = 0;
+ } else
+ fv = -fv, sign = -1;
+ }
+ den = 1L;
+ if (fv > 0) {
+ while (fv < 1L<<(31-3) && den < 1L<<(31-3))
+ fv *= 1<<3, den *= 1L<<3;
+ }
+ t[2*i+0] = sign * (fv + 0.5);
+ t[2*i+1] = den;
+ }
+ status = TIFFWriteData(tif, dir, (char *)t);
+ _TIFFfree((char*) t);
+ return (status);
+}
+
+static int
+TIFFWriteFloatArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, float* v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ TIFFCvtNativeToIEEEFloat(tif, n, v);
+ if (n == 1) {
+ dir->tdir_offset = *(uint32*) &v[0];
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+static int
+TIFFWriteDoubleArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v)
+{
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ TIFFCvtNativeToIEEEDouble(tif, n, v);
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Write an array of ``type'' values for a specified tag (i.e. this is a tag
+ * which is allowed to have different types, e.g. SMaxSampleType).
+ * Internally the data values are represented as double since a double can
+ * hold any of the TIFF tag types (yes, this should really be an abstract
+ * type tany_t for portability). The data is converted into the specified
+ * type in a temporary buffer and then handed off to the appropriate array
+ * writer.
+ */
+static int
+TIFFWriteAnyArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v)
+{
+ char buf[10 * sizeof(double)];
+ char* w = buf;
+ int i, status = 0;
+
+ if (n * TIFFDataWidth(type) > sizeof buf)
+ w = (char*) _TIFFmalloc(n * TIFFDataWidth(type));
+ switch (type) {
+ case TIFF_BYTE:
+ { unsigned char* bp = (unsigned char*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (unsigned char) v[i];
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ if (!TIFFWriteByteArray(tif, dir, (char*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_SBYTE:
+ { signed char* bp = (signed char*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (signed char) v[i];
+ dir->tdir_tag = tag;
+ dir->tdir_type = (short) type;
+ dir->tdir_count = n;
+ if (!TIFFWriteByteArray(tif, dir, (char*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_SHORT:
+ { uint16* bp = (uint16*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (uint16) v[i];
+ if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp))
+ goto out;
+ }
+ break;
+ case TIFF_SSHORT:
+ { int16* bp = (int16*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (int16) v[i];
+ if (!TIFFWriteShortArray(tif, type, tag, dir, n, (uint16*)bp))
+ goto out;
+ }
+ break;
+ case TIFF_LONG:
+ { uint32* bp = (uint32*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (uint32) v[i];
+ if (!TIFFWriteLongArray(tif, type, tag, dir, n, bp))
+ goto out;
+ }
+ break;
+ case TIFF_SLONG:
+ { int32* bp = (int32*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (int32) v[i];
+ if (!TIFFWriteLongArray(tif, type, tag, dir, n, (uint32*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_FLOAT:
+ { float* bp = (float*) w;
+ for (i = 0; i < n; i++)
+ bp[i] = (float) v[i];
+ if (!TIFFWriteFloatArray(tif, type, tag, dir, n, bp))
+ goto out;
+ }
+ break;
+ case TIFF_DOUBLE:
+ return (TIFFWriteDoubleArray(tif, type, tag, dir, n, v));
+ default:
+ /* TIFF_NOTYPE */
+ /* TIFF_ASCII */
+ /* TIFF_UNDEFINED */
+ /* TIFF_RATIONAL */
+ /* TIFF_SRATIONAL */
+ goto out;
+ }
+ status = 1;
+ out:
+ if (w != buf)
+ _TIFFfree(w);
+ return (status);
+}
+
+#ifdef COLORIMETRY_SUPPORT
+static int
+TIFFWriteTransferFunction(TIFF* tif, TIFFDirEntry* dir)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ tsize_t n = (1L<<td->td_bitspersample) * sizeof (uint16);
+ uint16** tf = td->td_transferfunction;
+ int ncols;
+
+ /*
+ * Check if the table can be written as a single column,
+ * or if it must be written as 3 columns. Note that we
+ * write a 3-column tag if there are 2 samples/pixel and
+ * a single column of data won't suffice--hmm.
+ */
+ switch (td->td_samplesperpixel - td->td_extrasamples) {
+ default: if (_TIFFmemcmp(tf[0], tf[2], n)) { ncols = 3; break; }
+ case 2: if (_TIFFmemcmp(tf[0], tf[1], n)) { ncols = 3; break; }
+ case 1: case 0: ncols = 1;
+ }
+ return (TIFFWriteShortTable(tif,
+ TIFFTAG_TRANSFERFUNCTION, dir, ncols, tf));
+}
+#endif
+
+/*
+ * Write a contiguous directory item.
+ */
+static int
+TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ tsize_t cc;
+
+ if (tif->tif_flags & TIFF_SWAB) {
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count);
+ break;
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count);
+ break;
+ }
+ }
+ dir->tdir_offset = tif->tif_dataoff;
+ cc = dir->tdir_count * TIFFDataWidth(dir->tdir_type);
+ if (SeekOK(tif, dir->tdir_offset) &&
+ WriteOK(tif, cp, cc)) {
+ tif->tif_dataoff += (cc + 1) & ~1;
+ return (1);
+ }
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing data for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return (0);
+}
+
+/*
+ * Link the current directory into the
+ * directory chain for the file.
+ */
+static int
+TIFFLinkDirectory(TIFF* tif)
+{
+ static const char module[] = "TIFFLinkDirectory";
+ uint32 nextdir;
+ uint32 diroff;
+
+ tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
+ diroff = (uint32) tif->tif_diroff;
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&diroff);
+#if SUBIFD_SUPPORT
+ if (tif->tif_flags & TIFF_INSUBIFD) {
+ (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Error writing SubIFD directory link",
+ tif->tif_name);
+ return (0);
+ }
+ /*
+ * Advance to the next SubIFD or, if this is
+ * the last one configured, revert back to the
+ * normal directory linkage.
+ */
+ if (--tif->tif_nsubifd)
+ tif->tif_subifdoff += sizeof (diroff);
+ else
+ tif->tif_flags &= ~TIFF_INSUBIFD;
+ return (1);
+ }
+#endif
+ if (tif->tif_header.tiff_diroff == 0) {
+ /*
+ * First directory, overwrite offset in header.
+ */
+ tif->tif_header.tiff_diroff = (uint32) tif->tif_diroff;
+#define HDROFF(f) ((toff_t) &(((TIFFHeader*) 0)->f))
+ (void) TIFFSeekFile(tif, HDROFF(tiff_diroff), SEEK_SET);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Error writing TIFF header");
+ return (0);
+ }
+ return (1);
+ }
+ /*
+ * Not the first directory, search to the last and append.
+ */
+ nextdir = tif->tif_header.tiff_diroff;
+ do {
+ uint16 dircount;
+
+ if (!SeekOK(tif, nextdir) ||
+ !ReadOK(tif, &dircount, sizeof (dircount))) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory count");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ (void) TIFFSeekFile(tif,
+ dircount * sizeof (TIFFDirEntry), SEEK_CUR);
+ if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Error fetching directory link");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&nextdir);
+ } while (nextdir != 0);
+ (void) TIFFSeekFile(tif, -(toff_t) sizeof (nextdir), SEEK_CUR);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link");
+ return (0);
+ }
+ return (1);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/ras/Makefile.am b/tiff/contrib/ras/Makefile.am
new file mode 100644
index 0000000..c80acd0
--- /dev/null
+++ b/tiff/contrib/ras/Makefile.am
@@ -0,0 +1,28 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = README ras2tif.c tif2ras.c
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
diff --git a/tiff/contrib/ras/Makefile.in b/tiff/contrib/ras/Makefile.in
new file mode 100644
index 0000000..a994bcb
--- /dev/null
+++ b/tiff/contrib/ras/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/ras
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = README ras2tif.c tif2ras.c
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/ras/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/ras/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/ras/README b/tiff/contrib/ras/README
new file mode 100644
index 0000000..f87bfde
--- /dev/null
+++ b/tiff/contrib/ras/README
@@ -0,0 +1,10 @@
+Sun May 19 22:28:16 PDT 1991
+
+These programs are from Patrick Naughton (naughton@wind.sun.com).
+I've tried to update them to reflect changes to the library, but
+I am unable to verify that they operate properly, because they
+require the Sun pixrect library.
+
+Please contact Patrick directly if you have questions/problems.
+
+ Sam
diff --git a/tiff/contrib/ras/ras2tif.c b/tiff/contrib/ras/ras2tif.c
new file mode 100644
index 0000000..c44b313
--- /dev/null
+++ b/tiff/contrib/ras/ras2tif.c
@@ -0,0 +1,254 @@
+#ifndef lint
+static char sccsid[] = "@(#)ras2tif.c 1.2 90/03/06";
+#endif
+/*-
+ * ras2tif.c - Converts from a Sun Rasterfile to a Tagged Image File.
+ *
+ * Copyright (c) 1990 by Sun Microsystems, Inc.
+ *
+ * Author: Patrick J. Naughton
+ * naughton@wind.sun.com
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind. The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof. In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Comments and additions should be sent to the author:
+ *
+ * Patrick J. Naughton
+ * Sun Microsystems
+ * 2550 Garcia Ave, MS 14-40
+ * Mountain View, CA 94043
+ * (415) 336-1080
+ *
+ * Revision History:
+ * 11-Jan-89: Created.
+ * 06-Mar-90: fix bug in SCALE() macro.
+ * got rid of xres and yres, (they weren't working anyways).
+ * fixed bpsl calculation.
+ * 25-Nov-99: y2k fix (year as 1900 + tm_year) <mike@onshore.com>
+ *
+ * Description:
+ * This program takes a Sun Rasterfile [see rasterfile(5)] as input and
+ * writes a MicroSoft/Aldus "Tagged Image File Format" image or "TIFF" file.
+ * The input file may be standard input, but the output TIFF file must be a
+ * real file since seek(2) is used.
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <pixrect/pixrect_hs.h>
+#include "tiffio.h"
+
+typedef int boolean;
+#define True (1)
+#define False (0)
+#define SCALE(x) (((x)*((1L<<16)-1))/255)
+
+boolean Verbose = False;
+boolean dummyinput = False;
+char *pname; /* program name (used for error messages) */
+
+void
+error(s1, s2)
+ char *s1,
+ *s2;
+{
+ fprintf(stderr, s1, pname, s2);
+ exit(1);
+}
+
+void
+usage()
+{
+ error("usage: %s -[vq] [-|rasterfile] TIFFfile\n", NULL);
+}
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *inf = NULL;
+ char *outf = NULL;
+ FILE *fp;
+ int depth,
+ i;
+ long row;
+ TIFF *tif;
+ Pixrect *pix; /* The Sun Pixrect */
+ colormap_t Colormap; /* The Pixrect Colormap */
+ u_short red[256],
+ green[256],
+ blue[256];
+ struct tm *ct;
+ struct timeval tv;
+ long width,
+ height;
+ long rowsperstrip;
+ int year;
+ short photometric;
+ short samplesperpixel;
+ short bitspersample;
+ int bpsl;
+ static char *version = "ras2tif 1.0";
+ static char *datetime = "1990:01:01 12:00:00";
+
+ gettimeofday(&tv, (struct timezone *) NULL);
+ ct = localtime(&tv.tv_sec);
+ year=1900 + ct->tm_year;
+ sprintf(datetime, "%04d:%02d:%02d %02d:%02d:%02d",
+ year, ct->tm_mon + 1, ct->tm_mday,
+ ct->tm_hour, ct->tm_min, ct->tm_sec);
+
+ setbuf(stderr, NULL);
+ pname = argv[0];
+
+ while (--argc) {
+ if ((++argv)[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'v':
+ Verbose = True;
+ break;
+ case 'q':
+ usage();
+ break;
+ case '\0':
+ if (inf == NULL)
+ dummyinput = True;
+ else
+ usage();
+ break;
+ default:
+ fprintf(stderr, "%s: illegal option -%c.\n", pname,
+ argv[0][1]);
+ exit(1);
+ }
+ } else if (inf == NULL && !dummyinput) {
+ inf = argv[0];
+ } else if (outf == NULL)
+ outf = argv[0];
+ else
+ usage();
+ }
+
+ if (outf == NULL)
+ error("%s: can't write output file to a stream.\n", NULL);
+
+ if (dummyinput || inf == NULL) {
+ inf = "Standard Input";
+ fp = stdin;
+ } else if ((fp = fopen(inf, "r")) == NULL)
+ error("%s: %s couldn't be opened.\n", inf);
+
+ if (Verbose)
+ fprintf(stderr, "Reading rasterfile from %s...", inf);
+
+ pix = pr_load(fp, &Colormap);
+ if (pix == NULL)
+ error("%s: %s is not a raster file.\n", inf);
+
+ if (Verbose)
+ fprintf(stderr, "done.\n");
+
+ if (Verbose)
+ fprintf(stderr, "Writing %s...", outf);
+
+ tif = TIFFOpen(outf, "w");
+
+ if (tif == NULL)
+ error("%s: error opening TIFF file %s", outf);
+
+ width = pix->pr_width;
+ height = pix->pr_height;
+ depth = pix->pr_depth;
+
+ switch (depth) {
+ case 1:
+ samplesperpixel = 1;
+ bitspersample = 1;
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 8:
+ samplesperpixel = 1;
+ bitspersample = 8;
+ photometric = PHOTOMETRIC_PALETTE;
+ break;
+ case 24:
+ samplesperpixel = 3;
+ bitspersample = 8;
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ case 32:
+ samplesperpixel = 4;
+ bitspersample = 8;
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ default:
+ error("%s: bogus depth: %d\n", depth);
+ }
+
+ bpsl = ((depth * width + 15) >> 3) & ~1;
+ rowsperstrip = (8 * 1024) / bpsl;
+
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(tif, TIFFTAG_DOCUMENTNAME, inf);
+ TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "converted Sun rasterfile");
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ TIFFSetField(tif, TIFFTAG_STRIPBYTECOUNTS, height / rowsperstrip);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_SOFTWARE, version);
+ TIFFSetField(tif, TIFFTAG_DATETIME, datetime);
+
+ memset(red, 0, sizeof(red));
+ memset(green, 0, sizeof(green));
+ memset(blue, 0, sizeof(blue));
+ if (depth == 8) {
+ TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
+ for (i = 0; i < Colormap.length; i++) {
+ red[i] = SCALE(Colormap.map[0][i]);
+ green[i] = SCALE(Colormap.map[1][i]);
+ blue[i] = SCALE(Colormap.map[2][i]);
+ }
+ }
+ if (Verbose)
+ fprintf(stderr, "%dx%dx%d image, ", width, height, depth);
+
+ for (row = 0; row < height; row++)
+ if (TIFFWriteScanline(tif,
+ (u_char *) mprd_addr(mpr_d(pix), 0, row),
+ row, 0) < 0) {
+ fprintf("failed a scanline write (%d)\n", row);
+ break;
+ }
+ TIFFFlushData(tif);
+ TIFFClose(tif);
+
+ if (Verbose)
+ fprintf(stderr, "done.\n");
+
+ pr_destroy(pix);
+
+ exit(0);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/ras/tif2ras.c b/tiff/contrib/ras/tif2ras.c
new file mode 100644
index 0000000..b665aed
--- /dev/null
+++ b/tiff/contrib/ras/tif2ras.c
@@ -0,0 +1,344 @@
+#ifndef lint
+static char id[] = "$Id: tif2ras.c,v 1.2.2.1 2010-06-08 18:50:41 bfriesen Exp $";
+#endif
+/*-
+ * tif2ras.c - Converts from a Tagged Image File Format image to a Sun Raster.
+ *
+ * Copyright (c) 1990 by Sun Microsystems, Inc.
+ *
+ * Author: Patrick J. Naughton
+ * naughton@wind.sun.com
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind. The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof. In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Comments and additions should be sent to the author:
+ *
+ * Patrick J. Naughton
+ * Sun Microsystems
+ * 2550 Garcia Ave, MS 14-40
+ * Mountain View, CA 94043
+ * (415) 336-1080
+ *
+ * Revision History:
+ * 10-Jan-89: Created.
+ * 06-Mar-90: Change to byte encoded rasterfiles.
+ * fix bug in call to ReadScanline().
+ * fix bug in CVT() macro.
+ * fix assignment of td, (missing &).
+ *
+ * Description:
+ * This program takes a MicroSoft/Aldus "Tagged Image File Format" image or
+ * "TIFF" file as input and writes a Sun Rasterfile [see rasterfile(5)]. The
+ * output file may be standard output, but the input TIFF file must be a real
+ * file since seek(2) is used.
+ */
+
+#include <stdio.h>
+#include <pixrect/pixrect_hs.h>
+#include "tiffio.h"
+
+typedef int boolean;
+#define True (1)
+#define False (0)
+#define CVT(x) (((x) * 255) / ((1L<<16)-1))
+
+boolean Verbose = False;
+char *pname; /* program name (used for error messages) */
+
+void
+error(s1, s2)
+ char *s1,
+ *s2;
+{
+ fprintf(stderr, s1, pname, s2);
+ exit(1);
+}
+
+void
+usage()
+{
+ error("usage: %s -[vq] TIFFfile [rasterfile]\n", NULL);
+}
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *inf = NULL;
+ char *outf = NULL;
+ FILE *fp;
+ long width,
+ height;
+ int depth,
+ numcolors;
+ register TIFF *tif;
+ TIFFDirectory *td;
+ register u_char *inp,
+ *outp;
+ register int col,
+ i;
+ register long row;
+ u_char *Map = NULL;
+ u_char *buf;
+ short bitspersample;
+ short samplesperpixel;
+ short photometric;
+ u_short *redcolormap,
+ *bluecolormap,
+ *greencolormap;
+
+ Pixrect *pix; /* The Sun Pixrect */
+ colormap_t Colormap; /* The Pixrect Colormap */
+ u_char red[256],
+ green[256],
+ blue[256];
+
+ setbuf(stderr, NULL);
+ pname = argv[0];
+
+ while (--argc) {
+ if ((++argv)[0][0] == '-')
+ switch (argv[0][1]) {
+ case 'v':
+ Verbose = True;
+ break;
+ case 'q':
+ usage();
+ break;
+ default:
+ fprintf(stderr, "%s: illegal option -%c.\n", pname,
+ argv[0][1]);
+ exit(1);
+ }
+ else if (inf == NULL)
+ inf = argv[0];
+ else if (outf == NULL)
+ outf = argv[0];
+ else
+ usage();
+
+ }
+
+ if (inf == NULL)
+ error("%s: can't read input file from a stream.\n", NULL);
+
+ if (Verbose)
+ fprintf(stderr, "Reading %s...", inf);
+
+ tif = TIFFOpen(inf, "r");
+
+ if (tif == NULL)
+ error("%s: error opening TIFF file %s", inf);
+
+ if (Verbose)
+ TIFFPrintDirectory(tif, stderr, True, False, False);
+ TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample > 8)
+ error("%s: can't handle more than 8-bits per sample\n", NULL);
+
+ TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ switch (samplesperpixel) {
+ case 1:
+ if (bitspersample == 1)
+ depth = 1;
+ else
+ depth = 8;
+ break;
+ case 3:
+ case 4:
+ depth = 24;
+ break;
+ default:
+ error("%s: only handle 1-channel gray scale or 3-channel color\n");
+ }
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
+
+ if (Verbose)
+ fprintf(stderr, "%dx%dx%d image, ", width, height, depth);
+ if (Verbose)
+ fprintf(stderr, "%d bits/sample, %d samples/pixel, ",
+ bitspersample, samplesperpixel);
+
+ pix = mem_create(width, height, depth);
+ if (pix == (Pixrect *) NULL)
+ error("%s: can't allocate memory for output pixrect...\n", NULL);
+
+ numcolors = (1 << bitspersample);
+
+ TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
+ if (numcolors == 2) {
+ if (Verbose)
+ fprintf(stderr, "monochrome ");
+ Colormap.type = RMT_NONE;
+ Colormap.length = 0;
+ Colormap.map[0] = Colormap.map[1] = Colormap.map[2] = NULL;
+ } else {
+ switch (photometric) {
+ case PHOTOMETRIC_MINISBLACK:
+ if (Verbose)
+ fprintf(stderr, "%d graylevels (min=black), ", numcolors);
+ Map = (u_char *) malloc(numcolors * sizeof(u_char));
+ for (i = 0; i < numcolors; i++)
+ Map[i] = (255 * i) / numcolors;
+ Colormap.type = RMT_EQUAL_RGB;
+ Colormap.length = numcolors;
+ Colormap.map[0] = Colormap.map[1] = Colormap.map[2] = Map;
+ break;
+ case PHOTOMETRIC_MINISWHITE:
+ if (Verbose)
+ fprintf(stderr, "%d graylevels (min=white), ", numcolors);
+ Map = (u_char *) malloc(numcolors * sizeof(u_char));
+ for (i = 0; i < numcolors; i++)
+ Map[i] = 255 - ((255 * i) / numcolors);
+ Colormap.type = RMT_EQUAL_RGB;
+ Colormap.length = numcolors;
+ Colormap.map[0] = Colormap.map[1] = Colormap.map[2] = Map;
+ break;
+ case PHOTOMETRIC_RGB:
+ if (Verbose)
+ fprintf(stderr, "truecolor ");
+ Colormap.type = RMT_NONE;
+ Colormap.length = 0;
+ Colormap.map[0] = Colormap.map[1] = Colormap.map[2] = NULL;
+ break;
+ case PHOTOMETRIC_PALETTE:
+ if (Verbose)
+ fprintf(stderr, "colormapped ");
+ Colormap.type = RMT_EQUAL_RGB;
+ Colormap.length = numcolors;
+ memset(red, 0, sizeof(red));
+ memset(green, 0, sizeof(green));
+ memset(blue, 0, sizeof(blue));
+ TIFFGetField(tif, TIFFTAG_COLORMAP,
+ &redcolormap, &greencolormap, &bluecolormap);
+ for (i = 0; i < numcolors; i++) {
+ red[i] = (u_char) CVT(redcolormap[i]);
+ green[i] = (u_char) CVT(greencolormap[i]);
+ blue[i] = (u_char) CVT(bluecolormap[i]);
+ }
+ Colormap.map[0] = red;
+ Colormap.map[1] = green;
+ Colormap.map[2] = blue;
+ break;
+ case PHOTOMETRIC_MASK:
+ error("%s: Don't know how to handle PHOTOMETRIC_MASK\n");
+ break;
+ case PHOTOMETRIC_DEPTH:
+ error("%s: Don't know how to handle PHOTOMETRIC_DEPTH\n");
+ break;
+ default:
+ error("%s: unknown photometric (cmap): %d\n", photometric);
+ }
+ }
+
+ buf = (u_char *) malloc(TIFFScanlineSize(tif));
+ if (buf == NULL)
+ error("%s: can't allocate memory for scanline buffer...\n", NULL);
+
+ for (row = 0; row < height; row++) {
+ if (TIFFReadScanline(tif, buf, row, 0) < 0)
+ error("%s: bad data read on line: %d\n", row);
+ inp = buf;
+ outp = (u_char *) mprd_addr(mpr_d(pix), 0, row);
+ switch (photometric) {
+ case PHOTOMETRIC_RGB:
+ if (samplesperpixel == 4)
+ for (col = 0; col < width; col++) {
+ *outp++ = *inp++; /* Blue */
+ *outp++ = *inp++; /* Green */
+ *outp++ = *inp++; /* Red */
+ inp++; /* skip alpha channel */
+ }
+ else
+ for (col = 0; col < width; col++) {
+ *outp++ = *inp++; /* Blue */
+ *outp++ = *inp++; /* Green */
+ *outp++ = *inp++; /* Red */
+ }
+ break;
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ switch (bitspersample) {
+ case 1:
+ for (col = 0; col < ((width + 7) / 8); col++)
+ *outp++ = *inp++;
+ break;
+ case 2:
+ for (col = 0; col < ((width + 3) / 4); col++) {
+ *outp++ = (*inp >> 6) & 3;
+ *outp++ = (*inp >> 4) & 3;
+ *outp++ = (*inp >> 2) & 3;
+ *outp++ = *inp++ & 3;
+ }
+ break;
+ case 4:
+ for (col = 0; col < width / 2; col++) {
+ *outp++ = *inp >> 4;
+ *outp++ = *inp++ & 0xf;
+ }
+ break;
+ case 8:
+ for (col = 0; col < width; col++)
+ *outp++ = *inp++;
+ break;
+ default:
+ error("%s: bad bits/sample: %d\n", bitspersample);
+ }
+ break;
+ case PHOTOMETRIC_PALETTE:
+ memcpy(outp, inp, width);
+ break;
+ default:
+ error("%s: unknown photometric (write): %d\n", photometric);
+ }
+ }
+
+ free((char *) buf);
+
+ if (Verbose)
+ fprintf(stderr, "done.\n");
+
+ if (outf == NULL || strcmp(outf, "Standard Output") == 0) {
+ outf = "Standard Output";
+ fp = stdout;
+ } else {
+ if (!(fp = fopen(outf, "w")))
+ error("%s: %s couldn't be opened for writing.\n", outf);
+ }
+
+ if (Verbose)
+ fprintf(stderr, "Writing rasterfile in %s...", outf);
+
+ if (pr_dump(pix, fp, &Colormap, RT_BYTE_ENCODED, 0) == PIX_ERR)
+ error("%s: error writing Sun Rasterfile: %s\n", outf);
+
+ if (Verbose)
+ fprintf(stderr, "done.\n");
+
+ pr_destroy(pix);
+
+ if (fp != stdout)
+ fclose(fp);
+
+ exit(0);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/stream/Makefile.am b/tiff/contrib/stream/Makefile.am
new file mode 100644
index 0000000..e98ae33
--- /dev/null
+++ b/tiff/contrib/stream/Makefile.am
@@ -0,0 +1,28 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = README tiffstream.cpp tiffstream.h
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
diff --git a/tiff/contrib/stream/Makefile.in b/tiff/contrib/stream/Makefile.in
new file mode 100644
index 0000000..2ab998b
--- /dev/null
+++ b/tiff/contrib/stream/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/stream
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = README tiffstream.cpp tiffstream.h
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/stream/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/stream/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/stream/README b/tiff/contrib/stream/README
new file mode 100644
index 0000000..df9e43e
--- /dev/null
+++ b/tiff/contrib/stream/README
@@ -0,0 +1,30 @@
+Subject: tiff stream interface (contrib)
+Date: Thu, 30 Mar 2000 10:48:51 -0800
+From: "Avi Bleiweiss" <avi@shutterfly.com>
+To: <warmerda@home.com>, <mike@onshore.com>
+
+Here at Shutterfly we have augmented the file based tiff library to support
+C++ streams. The implementation is an adaptor class, which takes any C++
+stream from the user and in return it deposits i/o operation method pointers
+(e.g. read, write, seek and close) into the tiff's library client state.
+
+The class TiffStream has an overloaded factory method - makeFileStream -
+which takes the C++ stream as an argument, calls TIFFClientOpen and returns
+a tiff handle. The class retains the tiff handle in its local state and
+provides a helper function (getTiffHandle) to query the handle at any time.
+Additional helper method - getStreamSize - provides the stream size to the
+user. The implementation assumes client responsibility to delete the stream
+object. The class calls TIFFClose at destruction time.
+
+Attached are a definition (tiffstream.h) and an implementation
+(tiffstream.cpp) files of the TiffStream class. No changes are required to
+the tiff core piece and the class sits on top of the library. The code is
+fairly tested at this point and is used internally in Shutterfly imaging
+software. The code is portable across WindowsNT/Linux/Solaris.
+
+We at Shutterfly believe this software has benefits to the larger community
+of tiff library users and would like to contribute this software to be part
+of the tiff distributed package. Let me know of any issue.
+
+Thanks
+Avi
diff --git a/tiff/contrib/stream/tiffstream.cpp b/tiff/contrib/stream/tiffstream.cpp
new file mode 100644
index 0000000..ffff687
--- /dev/null
+++ b/tiff/contrib/stream/tiffstream.cpp
@@ -0,0 +1,238 @@
+// tiff stream interface class implementation
+
+#include "tiffstream.h"
+
+const char* TiffStream::m_name = "TiffStream";
+
+TiffStream::TiffStream()
+{
+ m_tif = NULL;
+
+
+ m_inStream = NULL;
+ m_outStream = NULL;
+ m_ioStream = NULL;
+
+ m_streamLength = 0;
+
+ m_this = reinterpret_cast<thandle_t>(this);
+};
+
+TiffStream::~TiffStream()
+{
+ if(m_tif != NULL) TIFFClose(m_tif);
+}
+
+TIFF*
+TiffStream::makeFileStream(istream* str)
+{
+ m_inStream = str;
+ m_outStream = NULL;
+ m_ioStream = NULL;
+ m_streamLength = getSize(m_this);
+
+ m_tif = TIFFClientOpen(m_name,
+ "r",
+ m_this,
+ read,
+ write,
+ seek,
+ close,
+ size,
+ map,
+ unmap);
+ return m_tif;
+}
+
+TIFF*
+TiffStream::makeFileStream(ostream* str)
+{
+ m_inStream = NULL;
+ m_outStream = str;
+ m_ioStream = NULL;
+ m_streamLength = getSize(m_this);
+
+ m_tif = TIFFClientOpen(m_name,
+ "w",
+ m_this,
+ read,
+ write,
+ seek,
+ close,
+ size,
+ map,
+ unmap);
+ return m_tif;
+}
+
+TIFF*
+TiffStream::makeFileStream(iostream* str)
+{
+ m_inStream = NULL;
+ m_outStream = NULL;
+ m_ioStream = str;
+ m_streamLength = getSize(m_this);
+
+ m_tif = TIFFClientOpen(m_name,
+ "r+w",
+ m_this,
+ read,
+ write,
+ seek,
+ close,
+ size,
+ map,
+ unmap);
+ return m_tif;
+}
+
+tsize_t
+TiffStream::read(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ istream* istr;
+ TiffStream* ts = reinterpret_cast<TiffStream*>(fd);
+ if(ts->m_inStream != NULL) {
+ istr = ts->m_inStream;
+ } else if(ts->m_ioStream != NULL) {
+ istr = ts->m_ioStream;
+ }
+
+ int remain = ts->m_streamLength - ts->tell(fd);
+ int actual = remain < size ? remain : size;
+ istr->read(reinterpret_cast<char*>(buf), actual);
+ return istr->gcount();
+}
+
+tsize_t
+TiffStream::write(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ TiffStream* ts = reinterpret_cast<TiffStream*>(fd);
+ ostream* ostr;
+ if(ts->m_outStream != NULL) {
+ ostr = ts->m_outStream;
+ } else if(ts->m_ioStream != NULL) {
+ ostr = ts->m_ioStream;
+ }
+
+ streampos start = ostr->tellp();
+ ostr->write(reinterpret_cast<const char*>(buf), size);
+ return ostr->tellp() - start;
+}
+
+toff_t
+TiffStream::seek(thandle_t fd, toff_t offset, int origin)
+{
+ TiffStream* ts = reinterpret_cast<TiffStream*>(fd);
+ if(ts->seekInt(fd, offset, origin) == true) return offset;
+ else return -1;
+}
+
+int
+TiffStream::close(thandle_t fd)
+{
+ TiffStream* ts = reinterpret_cast<TiffStream*>(fd);
+ if(ts->m_inStream != NULL) {
+ ts->m_inStream = NULL;
+ return 0;
+ } else if(ts->m_outStream != NULL) {
+ ts->m_outStream = NULL;
+ return 0;
+ } else if(ts->m_ioStream != NULL) {
+ ts->m_ioStream = NULL;
+ return 0;
+ }
+ return -1;
+}
+
+toff_t
+TiffStream::size(thandle_t fd)
+{
+ TiffStream* ts = reinterpret_cast<TiffStream*>(fd);
+ return ts->getSize(fd);
+}
+
+int
+TiffStream::map(thandle_t fd, tdata_t* phase, toff_t* psize)
+{
+ return 0;
+}
+
+void
+TiffStream::unmap(thandle_t fd, tdata_t base, tsize_t size)
+{
+}
+
+unsigned int
+TiffStream::getSize(thandle_t fd)
+{
+ if(!isOpen(fd)) return 0;
+
+ unsigned int pos = tell(fd);
+ seekInt(fd, 0, end);
+ unsigned int size = tell(fd);
+ seekInt(fd, pos, beg);
+
+ return size;
+}
+
+unsigned int
+TiffStream::tell(thandle_t fd)
+{
+ TiffStream* ts = reinterpret_cast<TiffStream*>(fd);
+ if(ts->m_inStream != NULL) {
+ return ts->m_inStream->tellg();
+ } else if(ts->m_outStream != NULL) {
+ return ts->m_outStream->tellp();
+ } else if(ts->m_ioStream != NULL) {
+ return ts->m_ioStream->tellg();
+ }
+ return 0;
+}
+
+bool
+TiffStream::seekInt(thandle_t fd, unsigned int offset, int origin)
+{
+ if(!isOpen(fd)) return false;
+
+ ios::seek_dir org;
+ switch(origin) {
+ case beg:
+ org = ios::beg;
+ break;
+ case cur:
+ org = ios::cur;
+ break;
+ case end:
+ org = ios::end;
+ break;
+ }
+
+ TiffStream* ts = reinterpret_cast<TiffStream*>(fd);
+ if(ts->m_inStream != NULL) {
+ ts->m_inStream->seekg(offset, org);
+ return true;
+ } else if(ts->m_outStream != NULL) {
+ ts->m_outStream->seekp(offset, org);
+ return true;
+ } else if(ts->m_ioStream != NULL) {
+ ts->m_ioStream->seekg(offset, org);
+ ts->m_ioStream->seekp(offset, org);
+ return true;
+ }
+ return false;
+}
+
+bool
+TiffStream::isOpen(thandle_t fd)
+{
+ TiffStream* ts = reinterpret_cast<TiffStream*>(fd);
+ return (ts->m_inStream != NULL ||
+ ts->m_outStream != NULL ||
+ ts->m_ioStream != NULL);
+}/*
+ * Local Variables:
+ * mode: c++
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/stream/tiffstream.h b/tiff/contrib/stream/tiffstream.h
new file mode 100644
index 0000000..815a1a5
--- /dev/null
+++ b/tiff/contrib/stream/tiffstream.h
@@ -0,0 +1,69 @@
+// tiff stream interface class definition
+
+#ifndef _TIFF_STREAM_H_
+#define _TIFF_STREAM_H_
+
+#include <iostream.h>
+
+#include "tiffio.h"
+
+class TiffStream {
+
+public:
+ // ctor/dtor
+ TiffStream();
+ ~TiffStream();
+
+public:
+ enum SeekDir {
+ beg,
+ cur,
+ end,
+ };
+
+public:
+ // factory methods
+ TIFF* makeFileStream(iostream* str);
+ TIFF* makeFileStream(istream* str);
+ TIFF* makeFileStream(ostream* str);
+
+public:
+ // tiff client methods
+ static tsize_t read(thandle_t fd, tdata_t buf, tsize_t size);
+ static tsize_t write(thandle_t fd, tdata_t buf, tsize_t size);
+ static toff_t seek(thandle_t fd, toff_t offset, int origin);
+ static toff_t size(thandle_t fd);
+ static int close(thandle_t fd);
+ static int map(thandle_t fd, tdata_t* phase, toff_t* psize);
+ static void unmap(thandle_t fd, tdata_t base, tsize_t size);
+
+public:
+ // query method
+ TIFF* getTiffHandle() const { return m_tif; }
+ unsigned int getStreamLength() { return m_streamLength; }
+
+private:
+ // internal methods
+ unsigned int getSize(thandle_t fd);
+ unsigned int tell(thandle_t fd);
+ bool seekInt(thandle_t fd, unsigned int offset, int origin);
+ bool isOpen(thandle_t fd);
+
+private:
+ thandle_t m_this;
+ TIFF* m_tif;
+ static const char* m_name;
+ istream* m_inStream;
+ ostream* m_outStream;
+ iostream* m_ioStream;
+ int m_streamLength;
+
+};
+
+#endif // _TIFF_STREAM_H_/*
+ * Local Variables:
+ * mode: c++
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/tags/Makefile.am b/tiff/contrib/tags/Makefile.am
new file mode 100644
index 0000000..cab05ff
--- /dev/null
+++ b/tiff/contrib/tags/Makefile.am
@@ -0,0 +1,28 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = README listtif.c maketif.c xtif_dir.c xtiffio.h xtiffiop.h
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
diff --git a/tiff/contrib/tags/Makefile.in b/tiff/contrib/tags/Makefile.in
new file mode 100644
index 0000000..3b380ac
--- /dev/null
+++ b/tiff/contrib/tags/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/tags
+DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = README listtif.c maketif.c xtif_dir.c xtiffio.h xtiffiop.h
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/tags/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/tags/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/tags/README b/tiff/contrib/tags/README
new file mode 100644
index 0000000..73c6c21
--- /dev/null
+++ b/tiff/contrib/tags/README
@@ -0,0 +1,132 @@
+
+NOTE: Sept/2004
+
+The following described approach to managing tag extensions has been
+mostly superceeded since libtiff 3.6.0. The described approach requires
+internal knowledge of the libtiff API and tends to be very fragile
+in the face of libtiff upgrades.
+
+Please read over the html/addingtags.html in preference to the below
+described approach.
+
+
+
+==================================
+
+Client module for adding to LIBTIFF tagset
+-------------------------------------------
+ Author: Niles Ritter
+
+
+
+
+In the past, users of the "libtiff" package had to modify the
+source code of the library if they required additional private tags
+or codes not recognized by libtiff. Thus, whenever
+a new revision of libtiff came out the client would have to
+perform modifications to six or seven different files to re-install
+their tags.
+
+The latest versions of libtiff now provide client software new routines,
+giving them the opportunity to install private extensions at runtime,
+rather than compile-time. This means that the client may encapsulate
+all of their private tags into a separate module, which need only
+be recompiled when new versions of libtiff are released; no manual
+editing of files is required.
+
+How it works
+------------
+
+The mechanism for overriding the tag access has been enabled with
+a single new routine, which has the following calling sequence:
+
+ TIFFExtendProc old_extender;
+
+ old_extender = TIFFSetTagExtender(tag_extender);
+
+which must be called prior to opening or creating TIFF files.
+
+This routine sets a static pointer to the user-specified function
+<tag_extender>, which in turn is called by TIFFDefaultDirectory(),
+just after the usual TIFFSetField() and TIFFGetField() methods
+are defined, and just before the compression tag is set. It also
+returns a pointer to the previously-defined value of the tag-extender,
+so that multiple clients may be installed.
+
+The TIFFExtendProc method that you define should be used to override
+the TIFF file's "vsetfield" and "vgetfield" methods, so that you
+can trap your new, private tags, and install their values into
+a private directory structure. For your convienience, a new pointer
+has also been added to the "TIFF" file structure:
+
+ tidata_t tif_clientdir; /* client TIFF directory */
+
+into which you may install whatever private directory structures you like.
+You should also override the tag-printing method from within your
+"vsetfield" method, to permit the symbolic printing of your new tags.
+
+
+Example Client Code:
+--------------------
+
+An example module has been provided as a template for installing
+your own tags into a client tag extender. The module is called
+"xtif_dir.c", and defines all of the interface routines, tag field
+access, tag printing, etc. for most purpose.
+
+To see how the client module operates, there are three "fake"
+tags currently installed. If you use the existing makefile you can
+build them with:
+
+ make all -f Makefile.gcc !or Makefile.mpw
+ maketif
+ listtif
+
+This will build two example programs called "maketif" and "listtif"
+and then run them. These programs do nothing more than create a small
+file called "newtif.tif", install the fake tags, and then list them out
+using TIFFPrintDirectory().
+
+Installing Private Tags
+-----------------------
+
+To use this module for installing your own tags, edit each of the files
+
+ xtif_dir.c
+ xtiffio.h
+ xtiffiop.h
+
+and search for the string "XXX". At these locations the comments
+will direct you how to install your own tag values, define their
+types, etc. Three examples tags are currently installed, demonstrating
+how to implement multi-valued tags, single-valued tags, and ASCII tags.
+The examples are not valid, registered tags, so you must replace them with
+your own.
+
+To test the routines, also edit the test programs "maketif.c" and
+"listtif.c" and replace the portions of the code that set the
+private tag values and list them.
+
+Once you have edited these files, you may build the client module
+with the Makefile provided, and run the test programs.
+
+To use these files in your own code, the "xtif_dir.c" module defines
+replacement routines for the standard "TIFFOpen()" "TIFFFdOpen",
+and "TIFFClose()" routines, called XTIFFOpen, XTIFFFdOpen and XTIFFClose.
+You must use these routines in order to have the extended tag handlers
+installed. Once installed, the standard TIFFGetField() and TIFFSetField
+routines may be used as before.
+
+Adding Extended Tags to "tools"
+-------------------------------
+To create an extended-tag savvy "tiffinfo" program or other utility, you may
+simply recompile and link the tools to your "libxtiff" library, adding
+
+ -DTIFFOpen=XTIFFOpen -DTIFFClose=XTIFFClose -DTIFFFdOpen=XTIFFFdOpen
+
+to the compile statement.
+
+Bugs, Comments Etc:
+------------------
+ Send all reports and suggestions to ndr@tazboy.jpl.nasa.gov
+ (Niles Ritter).
diff --git a/tiff/contrib/tags/listtif.c b/tiff/contrib/tags/listtif.c
new file mode 100644
index 0000000..605de84
--- /dev/null
+++ b/tiff/contrib/tags/listtif.c
@@ -0,0 +1,39 @@
+/*
+ * listtif.c -- lists a tiff file.
+ */
+
+#include "xtiffio.h"
+#include <stdlib.h>
+
+void main(int argc,char *argv[])
+{
+ char *fname="newtif.tif";
+ int flags;
+
+ TIFF *tif=(TIFF*)0; /* TIFF-level descriptor */
+
+ if (argc>1) fname=argv[1];
+
+ tif=XTIFFOpen(fname,"r");
+ if (!tif) goto failure;
+
+ /* We want the double array listed */
+ flags = TIFFPRINT_MYMULTIDOUBLES;
+
+ TIFFPrintDirectory(tif,stdout,flags);
+ XTIFFClose(tif);
+ exit (0);
+
+failure:
+ printf("failure in listtif\n");
+ if (tif) XTIFFClose(tif);
+ exit (-1);
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/tags/maketif.c b/tiff/contrib/tags/maketif.c
new file mode 100644
index 0000000..e965201
--- /dev/null
+++ b/tiff/contrib/tags/maketif.c
@@ -0,0 +1,77 @@
+/*
+ * maketif.c -- creates a little TIFF file, with
+ * the XTIFF extended tiff example tags.
+ */
+
+#include <stdlib.h>
+#include "xtiffio.h"
+
+
+void SetUpTIFFDirectory(TIFF *tif);
+void WriteImage(TIFF *tif);
+
+#define WIDTH 20
+#define HEIGHT 20
+
+void main()
+{
+ TIFF *tif=(TIFF*)0; /* TIFF-level descriptor */
+
+ tif=XTIFFOpen("newtif.tif","w");
+ if (!tif) goto failure;
+
+ SetUpTIFFDirectory(tif);
+ WriteImage(tif);
+
+ XTIFFClose(tif);
+ exit (0);
+
+failure:
+ printf("failure in maketif\n");
+ if (tif) XTIFFClose(tif);
+ exit (-1);
+}
+
+
+void SetUpTIFFDirectory(TIFF *tif)
+{
+ double mymulti[6]={0.0,1.0,2.0, 3.1415926, 5.0,1.0};
+ uint32 mysingle=3456;
+ char *ascii="This file was produced by Steven Spielberg. NOT";
+
+ TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,WIDTH);
+ TIFFSetField(tif,TIFFTAG_IMAGELENGTH,HEIGHT);
+ TIFFSetField(tif,TIFFTAG_COMPRESSION,COMPRESSION_NONE);
+ TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_MINISBLACK);
+ TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG);
+ TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8);
+ TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,20);
+
+ /* Install the extended TIFF tag examples */
+ TIFFSetField(tif,TIFFTAG_EXAMPLE_MULTI,6,mymulti);
+ TIFFSetField(tif,TIFFTAG_EXAMPLE_SINGLE,mysingle);
+ TIFFSetField(tif,TIFFTAG_EXAMPLE_ASCII,ascii);
+}
+
+
+void WriteImage(TIFF *tif)
+{
+ int i;
+ char buffer[WIDTH];
+
+ memset(buffer,0,sizeof(buffer));
+ for (i=0;i<HEIGHT;i++)
+ if (!TIFFWriteScanline(tif, buffer, i, 0))
+ TIFFErrorExt(tif->tif_clientdata, "WriteImage","failure in WriteScanline\n");
+}
+
+
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/tags/xtif_dir.c b/tiff/contrib/tags/xtif_dir.c
new file mode 100644
index 0000000..e67a6ab
--- /dev/null
+++ b/tiff/contrib/tags/xtif_dir.c
@@ -0,0 +1,350 @@
+/*
+ * xtif_dir.c
+ *
+ * Extended TIFF Directory Tag Support.
+ *
+ * You may use this file as a template to add your own
+ * extended tags to the library. Only the parts of the code
+ * marked with "XXX" require modification. Three example tags
+ * are shown; you should replace them with your own.
+ *
+ * Author: Niles D. Ritter
+ */
+
+#include "xtiffiop.h"
+#include <stdio.h>
+
+/* Tiff info structure.
+ *
+ * Entry format:
+ * { TAGNUMBER, ReadCount, WriteCount, DataType, FIELDNUM,
+ * OkToChange, PassDirCountOnSet, AsciiName }
+ *
+ * For ReadCount, WriteCount, -1 = unknown; used for mult-valued
+ * tags and ASCII.
+ */
+
+static const TIFFFieldInfo xtiffFieldInfo[] = {
+
+ /* XXX Replace these example tags with your own extended tags */
+ { TIFFTAG_EXAMPLE_MULTI, -1,-1, TIFF_DOUBLE, FIELD_EXAMPLE_MULTI,
+ TRUE, TRUE, "MyMultivaluedTag" },
+ { TIFFTAG_EXAMPLE_SINGLE, 1, 1, TIFF_LONG, FIELD_EXAMPLE_SINGLE,
+ TRUE, FALSE, "MySingleLongTag" },
+ { TIFFTAG_EXAMPLE_ASCII, -1,-1, TIFF_ASCII, FIELD_EXAMPLE_ASCII,
+ TRUE, FALSE, "MyAsciiTag" },
+};
+#define N(a) (sizeof (a) / sizeof (a[0]))
+
+
+static void
+_XTIFFPrintDirectory(TIFF* tif, FILE* fd, long flags)
+{
+ xtiff *xt = XTIFFDIR(tif);
+ XTIFFDirectory *xd = &xt->xtif_dir;
+ int i,num;
+
+ /* call the inherited method */
+ if (PARENT(xt,printdir))
+ (PARENT(xt,printdir))(tif,fd,flags);
+
+ /* XXX Add field printing here. Replace the three example
+ * tags implemented below with your own.
+ */
+
+ fprintf(fd,"--My Example Tags--\n");
+
+ /* Our first example tag may have a lot of values, so we
+ * will only print them out if the TIFFPRINT_MYMULTIDOUBLES
+ * flag is passed into the print method.
+ */
+ if (TIFFFieldSet(tif,FIELD_EXAMPLE_MULTI))
+ {
+ fprintf(fd, " My Multi-Valued Doubles:");
+ if (flags & TIFFPRINT_MYMULTIDOUBLES)
+ {
+ double *value = xd->xd_example_multi;
+
+ num = xd->xd_num_multi;
+ fprintf(fd,"(");
+ for (i=0;i<num;i++) fprintf(fd, " %lg", *value++);
+ fprintf(fd,")\n");
+ } else
+ fprintf(fd, "(present)\n");
+ }
+
+ if (TIFFFieldSet(tif,FIELD_EXAMPLE_SINGLE))
+ {
+ fprintf(fd, " My Single Long Tag: %lu\n", xd->xd_example_single);
+ }
+
+ if (TIFFFieldSet(tif,FIELD_EXAMPLE_ASCII))
+ {
+ _TIFFprintAsciiTag(fd,"My ASCII Tag",
+ xd->xd_example_ascii);
+ }
+}
+
+static int
+_XTIFFVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ xtiff *xt = XTIFFDIR(tif);
+ XTIFFDirectory* xd = &xt->xtif_dir;
+ int status = 1;
+ uint32 v32=0;
+ int i=0, v=0;
+ va_list ap1 = ap;
+
+ /* va_start is called by the calling routine */
+
+ switch (tag) {
+ /*
+ * XXX put your extended tags here; replace the implemented
+ * example tags with your own.
+ */
+ case TIFFTAG_EXAMPLE_MULTI:
+ /* multi-valued tags need to store the count as well */
+ xd->xd_num_multi = (uint16) va_arg(ap, int);
+ _TIFFsetDoubleArray(&xd->xd_example_multi, va_arg(ap, double*),
+ (long) xd->xd_num_multi);
+ break;
+ case TIFFTAG_EXAMPLE_SINGLE:
+ xd->xd_example_single = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_EXAMPLE_ASCII:
+ _TIFFsetString(&xd->xd_example_ascii, va_arg(ap, char*));
+ break;
+ default:
+ /* call the inherited method */
+ return (PARENT(xt,vsetfield))(tif,tag,ap);
+ break;
+ }
+ if (status) {
+ /* we have to override the print method here,
+ * after the compression tags have gotten to it.
+ * This makes sense because the only time we would
+ * need the extended print method is if an extended
+ * tag is set by the reader.
+ */
+ if (!(xt->xtif_flags & XTIFFP_PRINT))
+ {
+ PARENT(xt,printdir) = TIFFMEMBER(tif,printdir);
+ TIFFMEMBER(tif,printdir) = _XTIFFPrintDirectory;
+ xt->xtif_flags |= XTIFFP_PRINT;
+ }
+ TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit);
+ tif->tif_flags |= TIFF_DIRTYDIRECT;
+ }
+ va_end(ap);
+ return (status);
+badvalue:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "%d: Bad value for \"%s\"", v,
+ _TIFFFieldWithTag(tif, tag)->field_name);
+ va_end(ap);
+ return (0);
+badvalue32:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "%ld: Bad value for \"%s\"", v32,
+ _TIFFFieldWithTag(tif, tag)->field_name);
+ va_end(ap);
+ return (0);
+}
+
+
+static int
+_XTIFFVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ xtiff *xt = XTIFFDIR(tif);
+ XTIFFDirectory* xd = &xt->xtif_dir;
+
+ switch (tag) {
+ /*
+ * XXX put your extended tags here; replace the implemented
+ * example tags with your own.
+ */
+ case TIFFTAG_EXAMPLE_MULTI:
+ *va_arg(ap, uint16*) = xd->xd_num_multi;
+ *va_arg(ap, double**) = xd->xd_example_multi;
+ break;
+ case TIFFTAG_EXAMPLE_ASCII:
+ *va_arg(ap, char**) = xd->xd_example_ascii;
+ break;
+ case TIFFTAG_EXAMPLE_SINGLE:
+ *va_arg(ap, uint32*) = xd->xd_example_single;
+ break;
+ default:
+ /* return inherited method */
+ return (PARENT(xt,vgetfield))(tif,tag,ap);
+ break;
+ }
+ return (1);
+}
+
+#define CleanupField(member) { \
+ if (xd->member) { \
+ _TIFFfree(xd->member); \
+ xd->member = 0; \
+ } \
+}
+/*
+ * Release storage associated with a directory.
+ */
+static void
+_XTIFFFreeDirectory(xtiff* xt)
+{
+ XTIFFDirectory* xd = &xt->xtif_dir;
+
+ /*
+ * XXX - Purge all Your allocated memory except
+ * for the xtiff directory itself. This includes
+ * all fields that require a _TIFFsetXXX call in
+ * _XTIFFVSetField().
+ */
+
+ CleanupField(xd_example_multi);
+ CleanupField(xd_example_ascii);
+
+}
+#undef CleanupField
+
+static void _XTIFFLocalDefaultDirectory(TIFF *tif)
+{
+ xtiff *xt = XTIFFDIR(tif);
+ XTIFFDirectory* xd = &xt->xtif_dir;
+
+ /* Install the extended Tag field info */
+ _TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo));
+
+ /*
+ * free up any dynamically allocated arrays
+ * before the new directory is read in.
+ */
+
+ _XTIFFFreeDirectory(xt);
+ _TIFFmemset(xt,0,sizeof(xtiff));
+
+ /* Override the tag access methods */
+
+ PARENT(xt,vsetfield) = TIFFMEMBER(tif,vsetfield);
+ TIFFMEMBER(tif,vsetfield) = _XTIFFVSetField;
+ PARENT(xt,vgetfield) = TIFFMEMBER(tif,vgetfield);
+ TIFFMEMBER(tif,vgetfield) = _XTIFFVGetField;
+
+ /*
+ * XXX Set up any default values here.
+ */
+
+ xd->xd_example_single = 234;
+}
+
+
+
+/**********************************************************************
+ * Nothing below this line should need to be changed.
+ **********************************************************************/
+
+static TIFFExtendProc _ParentExtender;
+
+/*
+ * This is the callback procedure, and is
+ * called by the DefaultDirectory method
+ * every time a new TIFF directory is opened.
+ */
+
+static void
+_XTIFFDefaultDirectory(TIFF *tif)
+{
+ xtiff *xt;
+
+ /* Allocate Directory Structure if first time, and install it */
+ if (!(tif->tif_flags & XTIFF_INITIALIZED))
+ {
+ xt = _TIFFmalloc(sizeof(xtiff));
+ if (!xt)
+ {
+ /* handle memory allocation failure here ! */
+ return;
+ }
+ _TIFFmemset(xt,0,sizeof(xtiff));
+ /*
+ * Install into TIFF structure.
+ */
+ TIFFMEMBER(tif,clientdir) = (tidata_t)xt;
+ tif->tif_flags |= XTIFF_INITIALIZED; /* dont do this again! */
+ }
+
+ /* set up our own defaults */
+ _XTIFFLocalDefaultDirectory(tif);
+
+ /* Since an XTIFF client module may have overridden
+ * the default directory method, we call it now to
+ * allow it to set up the rest of its own methods.
+ */
+
+ if (_ParentExtender)
+ (*_ParentExtender)(tif);
+
+}
+
+/*
+ * XTIFF Initializer -- sets up the callback
+ * procedure for the TIFF module.
+ */
+
+static
+void _XTIFFInitialize(void)
+{
+ static first_time=1;
+
+ if (! first_time) return; /* Been there. Done that. */
+ first_time = 0;
+
+ /* Grab the inherited method and install */
+ _ParentExtender = TIFFSetTagExtender(_XTIFFDefaultDirectory);
+}
+
+
+/*
+ * Public File I/O Routines.
+ */
+TIFF*
+XTIFFOpen(const char* name, const char* mode)
+{
+ /* Set up the callback */
+ _XTIFFInitialize();
+
+ /* Open the file; the callback will set everything up
+ */
+ return TIFFOpen(name, mode);
+}
+
+TIFF*
+XTIFFFdOpen(int fd, const char* name, const char* mode)
+{
+ /* Set up the callback */
+ _XTIFFInitialize();
+
+ /* Open the file; the callback will set everything up
+ */
+ return TIFFFdOpen(fd, name, mode);
+}
+
+
+void
+XTIFFClose(TIFF *tif)
+{
+ xtiff *xt = XTIFFDIR(tif);
+
+ /* call inherited function first */
+ TIFFClose(tif);
+
+ /* Free up extended allocated memory */
+ _XTIFFFreeDirectory(xt);
+ _TIFFfree(xt);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/tags/xtiffio.h b/tiff/contrib/tags/xtiffio.h
new file mode 100644
index 0000000..e8600df
--- /dev/null
+++ b/tiff/contrib/tags/xtiffio.h
@@ -0,0 +1,59 @@
+/*
+ * xtiffio.h -- Public interface to Extended TIFF tags
+ *
+ * This is a template for defining a client module
+ * which supports tag extensions to the standard libtiff
+ * set. Only portions of the code marked "XXX" need to
+ * be changed to support your tag set.
+ *
+ * written by: Niles D. Ritter
+ */
+
+#ifndef __xtiffio_h
+#define __xtiffio_h
+
+#include "tiffio.h"
+
+/*
+ * XXX Define your private Tag names and values here
+ */
+
+/* These tags are not valid, but are provided for example */
+#define TIFFTAG_EXAMPLE_MULTI 61234
+#define TIFFTAG_EXAMPLE_SINGLE 61235
+#define TIFFTAG_EXAMPLE_ASCII 61236
+
+/*
+ * XXX Define Printing method flags. These
+ * flags may be passed in to TIFFPrintDirectory() to
+ * indicate that those particular field values should
+ * be printed out in full, rather than just an indicator
+ * of whether they are present or not.
+ */
+#define TIFFPRINT_MYMULTIDOUBLES 0x80000000
+
+/**********************************************************************
+ * Nothing below this line should need to be changed by the user.
+ **********************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern TIFF* XTIFFOpen(const char* name, const char* mode);
+extern TIFF* XTIFFFdOpen(int fd, const char* name, const char* mode);
+extern void XTIFFClose(TIFF *tif);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __xtiffio_h */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/tags/xtiffiop.h b/tiff/contrib/tags/xtiffiop.h
new file mode 100644
index 0000000..9d534a8
--- /dev/null
+++ b/tiff/contrib/tags/xtiffiop.h
@@ -0,0 +1,72 @@
+/*
+ * Private Extended TIFF library interface.
+ *
+ * uses private LIBTIFF interface.
+ *
+ * The portions of this module marked "XXX" should be
+ * modified to support your tags instead.
+ *
+ * written by: Niles D. Ritter
+ *
+ */
+
+#ifndef __xtiffiop_h
+#define __xtiffiop_h
+
+#include "tiffiop.h"
+#include "xtiffio.h"
+
+/**********************************************************************
+ * User Configuration
+ **********************************************************************/
+
+/* XXX - Define number of your extended tags here */
+#define NUM_XFIELD 3
+#define XFIELD_BASE (FIELD_LAST-NUM_XFIELD)
+
+/* XXX - Define your Tag Fields here */
+#define FIELD_EXAMPLE_MULTI (XFIELD_BASE+0)
+#define FIELD_EXAMPLE_SINGLE (XFIELD_BASE+1)
+#define FIELD_EXAMPLE_ASCII (XFIELD_BASE+2)
+
+
+/* XXX - Define Private directory tag structure here */
+struct XTIFFDirectory {
+ uint16 xd_num_multi; /* dir-count for the multi tag */
+ double* xd_example_multi;
+ uint32 xd_example_single;
+ char* xd_example_ascii;
+};
+typedef struct XTIFFDirectory XTIFFDirectory;
+
+/**********************************************************************
+ * Nothing below this line should need to be changed by the user.
+ **********************************************************************/
+
+struct xtiff {
+ TIFF *xtif_tif; /* parent TIFF pointer */
+ uint32 xtif_flags;
+#define XTIFFP_PRINT 0x00000001
+ XTIFFDirectory xtif_dir; /* internal rep of current directory */
+ TIFFVSetMethod xtif_vsetfield; /* inherited tag set routine */
+ TIFFVGetMethod xtif_vgetfield; /* inherited tag get routine */
+ TIFFPrintMethod xtif_printdir; /* inherited dir print method */
+};
+typedef struct xtiff xtiff;
+
+
+#define PARENT(xt,pmember) ((xt)->xtif_ ## pmember)
+#define TIFFMEMBER(tf,pmember) ((tf)->tif_ ## pmember)
+#define XTIFFDIR(tif) ((xtiff *)TIFFMEMBER(tif,clientdir))
+
+/* Extended TIFF flags */
+#define XTIFF_INITIALIZED 0x80000000
+
+#endif /* __xtiffiop_h */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/win_dib/Makefile.am b/tiff/contrib/win_dib/Makefile.am
new file mode 100644
index 0000000..aaf846f
--- /dev/null
+++ b/tiff/contrib/win_dib/Makefile.am
@@ -0,0 +1,28 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = Makefile.w95 README.Tiffile README.tiff2dib Tiffile.cpp tiff2dib.c
+
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff \ No newline at end of file
diff --git a/tiff/contrib/win_dib/Makefile.in b/tiff/contrib/win_dib/Makefile.in
new file mode 100644
index 0000000..c2f0f0d
--- /dev/null
+++ b/tiff/contrib/win_dib/Makefile.in
@@ -0,0 +1,421 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = contrib/win_dib
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = Makefile.w95 README.Tiffile README.tiff2dib Tiffile.cpp tiff2dib.c
+INCLUDES = -I../../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign contrib/win_dib/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign contrib/win_dib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/contrib/win_dib/Makefile.w95 b/tiff/contrib/win_dib/Makefile.w95
new file mode 100644
index 0000000..3f461ef
--- /dev/null
+++ b/tiff/contrib/win_dib/Makefile.w95
@@ -0,0 +1,134 @@
+# $Header: /usr/people/sam/tiff/libtiff/RCS/Makefile.w95,v 1.2 1994/11/28
+06:13:31 sam Exp $
+#
+# Tag Image File Format Library
+#
+# Copyright (c) 1988, 1989, 1990, 1991, 1992 Sam Leffler
+# Copyright (c) 1991, 1992 Silicon Graphics, Inc.
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+# This Makefile is for use with microsoft nmake version 1.50 and
+# Microsoft 32-bit C/C++ Compiler 9.00
+#
+DESTDIR=.
+#
+IPATH= -I.
+CONF_LIBRARY=$(NULL)
+COPTS= -Oxa -DBSDTYPES -Zd
+CFLAGS= $(COPTS) $(CONF_LIBRARY)
+#
+INCS= tiff.h tiffio.h
+SRCS= tif_aux.c \
+ tif_close.c \
+ tif_codec.c \
+ tif_compress.c \
+ tif_dir.c \
+ tif_dirinfo.c \
+ tif_dirread.c \
+ tif_dirwrite.c \
+ tif_dumpmode.c \
+ tif_error.c \
+ tif_getimage.c \
+ tif_jpeg.c \
+ tif_flush.c \
+ tif_lzw.c \
+ tif_next.c \
+ tif_open.c \
+ tif_packbits.c \
+ tif_predict \
+ tif_print.c \
+ tif_read.c \
+ tif_swab.c \
+ tif_strip.c \
+ tif_thunder.c \
+ tif_tile.c \
+ tif_version.c \
+ tif_warning.c \
+ tif_write.c \
+ tif_win32.c
+
+
+OBJS= tif_aux.obj \
+ tif_close.obj \
+ tif_codec.obj \
+ tif_compress.obj \
+ tif_dir.obj \
+ tif_dirinfo.obj \
+ tif_dirread.obj \
+ tif_dirwrite.obj \
+ tif_dumpmode.obj \
+ tif_error.obj \
+ tif_getimage.obj \
+ tif_jpeg.obj \
+ tif_flush.obj \
+ tif_lzw.obj \
+ tif_next.obj \
+ tif_open.obj \
+ tif_packbits.obj \
+ tif_predict.obj \
+ tif_print.obj \
+ tif_read.obj \
+ tif_swab.obj \
+ tif_strip.obj \
+ tif_thunder.obj \
+ tif_tile.obj \
+ tif_version.obj \
+ tif_warning.obj \
+ tif_write.obj \
+ tif_win32.obj
+
+
+
+ALL= libtiff.lib
+
+all: $(ALL)
+
+%.obj : %.c
+ $(CC) $(CFLAGS) -c $*.c
+
+
+#.INCLUDE .IGNORE : depend
+
+libtiff.lib: $(OBJS)
+ - del libtiff.lib
+ lib /OUT:libtiff.lib $(OBJS)
+
+
+#To include fax3 support, you need to modify mkg3states.c so it could run
+#under windows 95 or NT. This application make the file g3state.h.
+#after that, you have to add to the build script : tif_fax3.c and tif_fax3.obj
+#and define CCITT_SUPPORT in the file tifconf.h
+
+#$(OBJS): tiffio.h tiff.h tiffcomp.h tiffiop.h tiffconf.h
+#tif_fax3.obj: tif_fax3.c g3states.h t4.h tif_fax3.h
+
+#g3states.h: mkg3states.c t4.h
+# $(CC) $(CFLAGS) mkg3states.c
+# mkg3states -c > g3states.h
+
+
+clean:
+ del *.obj
+ del mkg3stat
+ del g3states.h
+
+tags: $(SRCS)
+ $(CTAGS) $(SRCS)
diff --git a/tiff/contrib/win_dib/README.Tiffile b/tiff/contrib/win_dib/README.Tiffile
new file mode 100644
index 0000000..82c6e5c
--- /dev/null
+++ b/tiff/contrib/win_dib/README.Tiffile
@@ -0,0 +1,31 @@
+Frank,
+
+I attached a file that uses RGBA interface (tif_getimage.c) to read a tiff
+file and convert to a DIB. It's advantage is that it is easy to read *any*
+tiff file suported by libtiff and easily convert it to a DIB. The disadvantage
+is that bilevel (B&W) bitmaps (and all other non-rgba images) are also
+converted to RGBA, thus taking up 32x as much memory as needed (4 bytes per
+pixel, rather than 1 bit). I read tiff files, but don't need to
+write them. And my files are typically small, so the overhead is mostly
+inconsequential. But for bilevel images, I overrode the get() and put()
+routines of the RGBA interface to just copy the data from the input raster
+to the output raster, rather than expanding out to full 32 bit format. It
+would be nice if there were a simple way to handle all palletized images,
+but that would take more custom routines, and it's not that important to me.
+
+Usage:
+
+ m_pDIB = (PBITMAPINFOHEADER)::ReadTIFF(pathName);
+ if (m_pDIB != 0) {
+ m_format = IMAGETYPE_TIF;
+ }
+
+This is intended as Win32, but the modifications for new get() and put()
+routines may be independent of platform.
+
+Thanks for your work supporting the forum and the library!
+
+Regards,
+
+Mark James
+mark@james.net
diff --git a/tiff/contrib/win_dib/README.tiff2dib b/tiff/contrib/win_dib/README.tiff2dib
new file mode 100644
index 0000000..3e6075f
--- /dev/null
+++ b/tiff/contrib/win_dib/README.tiff2dib
@@ -0,0 +1,51 @@
+
+Date: 04 Dec 95 10:34:23 EST
+From: Philippe <100423.3705@compuserve.com>
+To: TIFF/sam Leffler <sam@cthulhu.engr.sgi.com>
+Subject: TIFF library and Windows 95
+Message-Id: <951204153422_100423.3705_BHG101-1@CompuServe.COM>
+
+Sam,
+
+First, let me thanks all of you how have worked
+on that great TIFF library !
+
+Here is some information that may help someone.
+
+I build the library under Windows 95 as a 32-bit library.
+The contribution of Scott Wagner (tif_win32.c) worked fine, but
+the makefile "makefile.msc" was unsable because it was
+written for DOS or Windows 3.1 and all the files names
+are limited to 8 characters.
+
+Here is the makefile I used : makefile.w95
+
+Also, I had to disable fax3 support because I wasn't able
+to build (as it is) the tool "mkg3states" to generate the include
+file "g3states.h".
+This source file must be modify to be build under Windows 95.
+
+To build the library under Windows 95 with Visual C++ 2.0,
+I had to :
+
+- undefine CCITT_SUPPORT in "tiffconf.h"
+
+- create the file version.h with this line :
+ #define VERSION "3.4beta024"
+
+- build the makefile "makefile.w95"
+
+I also join the source file "tif2dib.c" that I created,
+it contain the function LoadTIFFinDIB that load
+a TIFF file and build a memory DIB with it and return the
+HANDLE (HDIB) of the memory bloc containing this DIB.
+Since DIB is the "natural" bitmap format for Windows 3.1, 95 and NT,
+this function sould be usefull for some Windows 95 (or NT) developer.
+
+
+Sorry for my approximate english ...
+
+Regards,
+
+Philippe Tenenhaus 100423.3705@compuserve.com
+Paris
diff --git a/tiff/contrib/win_dib/Tiffile.cpp b/tiff/contrib/win_dib/Tiffile.cpp
new file mode 100644
index 0000000..9d958b1
--- /dev/null
+++ b/tiff/contrib/win_dib/Tiffile.cpp
@@ -0,0 +1,449 @@
+#include "StdAfx.h"
+
+//#define STRICT
+#include <windows.h>
+#include <windowsx.h>
+#include <commdlg.h>
+#include <stdlib.h> // MAX_ constants
+#include "diblib.h"
+
+/*--------------------------------------------------------------------
+ READ TIFF
+ Load the TIFF data from the file into memory. Return
+ a pointer to a valid DIB (or NULL for errors).
+ Uses the TIFFRGBA interface to libtiff.lib to convert
+ most file formats to a useable form. We just keep the 32 bit
+ form of the data to display, rather than optimizing for the
+ display.
+
+ Main entry points:
+
+ int ChkTIFF ( LPCTSTR lpszPath )
+ PVOID ReadTIFF ( LPCTSTR lpszPath )
+
+ RETURN
+ A valid DIB pointer for success; NULL for failure.
+
+ --------------------------------------------------------------------*/
+
+#include "TiffLib/tiff.h"
+#include "TiffLib/tiffio.h"
+#include <assert.h>
+#include <stdio.h>
+
+
+// piggyback some data on top of the RGBA Image
+struct TIFFDibImage {
+ TIFFRGBAImage tif;
+ int dibinstalled;
+} ;
+
+
+HANDLE LoadTIFFinDIB(LPCTSTR lpFileName);
+HANDLE TIFFRGBA2DIB(TIFFDibImage* dib, uint32* raster) ;
+
+static void
+MyWarningHandler(const char* module, const char* fmt, va_list ap)
+{
+ // ignore all warnings (unused tags, etc)
+ return;
+}
+
+static void
+MyErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+ return;
+}
+
+// Turn off the error and warning handlers to check if a valid file.
+// Necessary because of the way that the Doc loads images and restart files.
+int ChkTIFF ( LPCTSTR lpszPath )
+{
+ int rtn = 0;
+
+ TIFFErrorHandler eh;
+ TIFFErrorHandler wh;
+
+ eh = TIFFSetErrorHandler(NULL);
+ wh = TIFFSetWarningHandler(NULL);
+
+ TIFF* tif = TIFFOpen(lpszPath, "r");
+ if (tif) {
+ rtn = 1;
+ TIFFClose(tif);
+ }
+
+ TIFFSetErrorHandler(eh);
+ TIFFSetWarningHandler(wh);
+
+ return rtn;
+}
+
+void DibInstallHack(TIFFDibImage* img) ;
+
+PVOID ReadTIFF ( LPCTSTR lpszPath )
+{
+ void* pDIB = 0;
+ TIFFErrorHandler wh;
+
+ wh = TIFFSetWarningHandler(MyWarningHandler);
+
+ if (ChkTIFF(lpszPath)) {
+ TIFF* tif = TIFFOpen(lpszPath, "r");
+ if (tif) {
+ char emsg[1024];
+
+ if (TIFFRGBAImageOK(tif, emsg)) {
+ TIFFDibImage img;
+ char emsg[1024];
+
+ if (TIFFRGBAImageBegin(&img.tif, tif, -1, emsg)) {
+ size_t npixels;
+ uint32* raster;
+
+ DibInstallHack(&img);
+
+ npixels = img.tif.width * img.tif.height;
+ raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
+ if (raster != NULL) {
+ if (TIFFRGBAImageGet(&img.tif, raster, img.tif.width, img.tif.height)) {
+ pDIB = TIFFRGBA2DIB(&img, raster);
+ }
+ }
+ _TIFFfree(raster);
+ }
+ TIFFRGBAImageEnd(&img.tif);
+ }
+ else {
+ TRACE("Unable to open image(%s): %s\n", lpszPath, emsg );
+ }
+ TIFFClose(tif);
+ }
+ }
+
+ TIFFSetWarningHandler(wh);
+
+ return pDIB;
+}
+
+
+
+HANDLE TIFFRGBA2DIB(TIFFDibImage* dib, uint32* raster)
+{
+ void* pDIB = 0;
+ TIFFRGBAImage* img = &dib->tif;
+
+ uint32 imageLength;
+ uint32 imageWidth;
+ uint16 BitsPerSample;
+ uint16 SamplePerPixel;
+ uint32 RowsPerStrip;
+ uint16 PhotometricInterpretation;
+
+ BITMAPINFOHEADER bi;
+ int dwDIBSize ;
+
+ TIFFGetField(img->tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
+ TIFFGetField(img->tif, TIFFTAG_IMAGELENGTH, &imageLength);
+ TIFFGetField(img->tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample);
+ TIFFGetField(img->tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip);
+ TIFFGetField(img->tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel);
+ TIFFGetField(img->tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation);
+
+ if ( BitsPerSample == 1 && SamplePerPixel == 1 && dib->dibinstalled ) { // bilevel
+ bi.biSize = sizeof(BITMAPINFOHEADER);
+ bi.biWidth = imageWidth;
+ bi.biHeight = imageLength;
+ bi.biPlanes = 1; // always
+ bi.biBitCount = 1;
+ bi.biCompression = BI_RGB;
+ bi.biSizeImage = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight;
+ bi.biXPelsPerMeter = 0;
+ bi.biYPelsPerMeter = 0;
+ bi.biClrUsed = 0; // must be zero for RGB compression (none)
+ bi.biClrImportant = 0; // always
+
+ // Get the size of the DIB
+ dwDIBSize = GetDIBSize( &bi );
+
+ // Allocate for the BITMAPINFO structure and the color table.
+ pDIB = GlobalAllocPtr( GHND, dwDIBSize );
+ if (pDIB == 0) {
+ return( NULL );
+ }
+
+ // Copy the header info
+ *((BITMAPINFOHEADER*)pDIB) = bi;
+
+ // Get a pointer to the color table
+ RGBQUAD *pRgbq = (RGBQUAD *)((LPSTR)pDIB + sizeof(BITMAPINFOHEADER));
+
+ pRgbq[0].rgbRed = 0;
+ pRgbq[0].rgbBlue = 0;
+ pRgbq[0].rgbGreen = 0;
+ pRgbq[0].rgbReserved = 0;
+ pRgbq[1].rgbRed = 255;
+ pRgbq[1].rgbBlue = 255;
+ pRgbq[1].rgbGreen = 255;
+ pRgbq[1].rgbReserved = 255;
+
+ // Pointers to the bits
+ //PVOID pbiBits = (LPSTR)pRgbq + bi.biClrUsed * sizeof(RGBQUAD);
+ //
+ // In the BITMAPINFOHEADER documentation, it appears that
+ // there should be no color table for 32 bit images, but
+ // experience shows that the image is off by 3 words if it
+ // is not included. So here it is.
+ PVOID pbiBits = GetDIBImagePtr((BITMAPINFOHEADER*)pDIB); //(LPSTR)pRgbq + 3 * sizeof(RGBQUAD);
+
+ int sizeWords = bi.biSizeImage/4;
+ RGBQUAD* rgbDib = (RGBQUAD*)pbiBits;
+ long* rgbTif = (long*)raster;
+
+ _TIFFmemcpy(pbiBits, raster, bi.biSizeImage);
+ }
+
+ // For now just always default to the RGB 32 bit form. // save as 32 bit for simplicity
+ else if ( true /*BitsPerSample == 8 && SamplePerPixel == 3*/ ) { // 24 bit color
+
+ bi.biSize = sizeof(BITMAPINFOHEADER);
+ bi.biWidth = imageWidth;
+ bi.biHeight = imageLength;
+ bi.biPlanes = 1; // always
+ bi.biBitCount = 32;
+ bi.biCompression = BI_RGB;
+ bi.biSizeImage = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight;
+ bi.biXPelsPerMeter = 0;
+ bi.biYPelsPerMeter = 0;
+ bi.biClrUsed = 0; // must be zero for RGB compression (none)
+ bi.biClrImportant = 0; // always
+
+ // Get the size of the DIB
+ dwDIBSize = GetDIBSize( &bi );
+
+ // Allocate for the BITMAPINFO structure and the color table.
+ pDIB = GlobalAllocPtr( GHND, dwDIBSize );
+ if (pDIB == 0) {
+ return( NULL );
+ }
+
+ // Copy the header info
+ *((BITMAPINFOHEADER*)pDIB) = bi;
+
+ // Get a pointer to the color table
+ RGBQUAD *pRgbq = (RGBQUAD *)((LPSTR)pDIB + sizeof(BITMAPINFOHEADER));
+
+ // Pointers to the bits
+ //PVOID pbiBits = (LPSTR)pRgbq + bi.biClrUsed * sizeof(RGBQUAD);
+ //
+ // In the BITMAPINFOHEADER documentation, it appears that
+ // there should be no color table for 32 bit images, but
+ // experience shows that the image is off by 3 words if it
+ // is not included. So here it is.
+ PVOID pbiBits = (LPSTR)pRgbq + 3 * sizeof(RGBQUAD);
+
+ int sizeWords = bi.biSizeImage/4;
+ RGBQUAD* rgbDib = (RGBQUAD*)pbiBits;
+ long* rgbTif = (long*)raster;
+
+ // Swap the byte order while copying
+ for ( int i = 0 ; i < sizeWords ; ++i )
+ {
+ rgbDib[i].rgbRed = TIFFGetR(rgbTif[i]);
+ rgbDib[i].rgbBlue = TIFFGetB(rgbTif[i]);
+ rgbDib[i].rgbGreen = TIFFGetG(rgbTif[i]);
+ rgbDib[i].rgbReserved = 0;
+ }
+ }
+
+ return pDIB;
+}
+
+
+
+
+///////////////////////////////////////////////////////////////
+//
+// Hacked from tif_getimage.c in libtiff in v3.5.7
+//
+//
+typedef unsigned char u_char;
+
+
+#define DECLAREContigPutFunc(name) \
+static void name(\
+ TIFFRGBAImage* img, \
+ uint32* cp, \
+ uint32 x, uint32 y, \
+ uint32 w, uint32 h, \
+ int32 fromskew, int32 toskew, \
+ u_char* pp \
+)
+
+#define DECLARESepPutFunc(name) \
+static void name(\
+ TIFFRGBAImage* img,\
+ uint32* cp,\
+ uint32 x, uint32 y, \
+ uint32 w, uint32 h,\
+ int32 fromskew, int32 toskew,\
+ u_char* r, u_char* g, u_char* b, u_char* a\
+)
+
+DECLAREContigPutFunc(putContig1bitTile);
+static int getStripContig1Bit(TIFFRGBAImage* img, uint32* uraster, uint32 w, uint32 h);
+
+//typdef struct TIFFDibImage {
+// TIFFRGBAImage tif;
+// dibinstalled;
+//} TIFFDibImage ;
+
+void DibInstallHack(TIFFDibImage* dib) {
+ TIFFRGBAImage* img = &dib->tif;
+ dib->dibinstalled = false;
+ switch (img->photometric) {
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ switch (img->bitspersample) {
+ case 1:
+ img->put.contig = putContig1bitTile;
+ img->get = getStripContig1Bit;
+ dib->dibinstalled = true;
+ break;
+ }
+ break;
+ }
+}
+
+/*
+ * 1-bit packed samples => 1-bit
+ *
+ * Override to just copy the data
+ */
+DECLAREContigPutFunc(putContig1bitTile)
+{
+ int samplesperpixel = img->samplesperpixel;
+
+ (void) y;
+ fromskew *= samplesperpixel;
+ int wb = WIDTHBYTES(w);
+ u_char* ucp = (u_char*)cp;
+
+ /* Conver 'w' to bytes from pixels (rounded up) */
+ w = (w+7)/8;
+
+ while (h-- > 0) {
+ _TIFFmemcpy(ucp, pp, w);
+ /*
+ for (x = wb; x-- > 0;) {
+ *cp++ = rgbi(Map[pp[0]], Map[pp[1]], Map[pp[2]]);
+ pp += samplesperpixel;
+ }
+ */
+ ucp += (wb + toskew);
+ pp += (w + fromskew);
+ }
+}
+
+/*
+ * Hacked from the tif_getimage.c file.
+ */
+static uint32
+setorientation(TIFFRGBAImage* img, uint32 h)
+{
+ TIFF* tif = img->tif;
+ uint32 y;
+
+ switch (img->orientation) {
+ case ORIENTATION_BOTRIGHT:
+ case ORIENTATION_RIGHTBOT: /* XXX */
+ case ORIENTATION_LEFTBOT: /* XXX */
+ TIFFWarning(TIFFFileName(tif), "using bottom-left orientation");
+ img->orientation = ORIENTATION_BOTLEFT;
+ /* fall thru... */
+ case ORIENTATION_BOTLEFT:
+ y = 0;
+ break;
+ case ORIENTATION_TOPRIGHT:
+ case ORIENTATION_RIGHTTOP: /* XXX */
+ case ORIENTATION_LEFTTOP: /* XXX */
+ default:
+ TIFFWarning(TIFFFileName(tif), "using top-left orientation");
+ img->orientation = ORIENTATION_TOPLEFT;
+ /* fall thru... */
+ case ORIENTATION_TOPLEFT:
+ y = h-1;
+ break;
+ }
+ return (y);
+}
+
+/*
+ * Get a strip-organized image that has
+ * PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ * SamplesPerPixel == 1
+ *
+ * Hacked from the tif_getimage.c file.
+ *
+ * This is set up to allow us to just copy the data to the raster
+ * for 1-bit bitmaps
+ */
+static int
+getStripContig1Bit(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ tileContigRoutine put = img->put.contig;
+ uint16 orientation;
+ uint32 row, y, nrow, rowstoread;
+ uint32 pos;
+ u_char* buf;
+ uint32 rowsperstrip;
+ uint32 imagewidth = img->width;
+ tsize_t scanline;
+ int32 fromskew, toskew;
+ tstrip_t strip;
+ tsize_t stripsize;
+ u_char* braster = (u_char*)raster; // byte wide raster
+ uint32 wb = WIDTHBYTES(w);
+ int ret = 1;
+
+ buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif));
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
+ return (0);
+ }
+ y = setorientation(img, h);
+ orientation = img->orientation;
+ toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? wb+wb : wb-wb);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ scanline = TIFFScanlineSize(tif);
+ fromskew = (w < imagewidth ? imagewidth - w : 0)/8;
+ for (row = 0; row < h; row += nrow)
+ {
+ rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip;
+ nrow = (row + rowstoread > h ? h - row : rowstoread);
+ strip = TIFFComputeStrip(tif,row+img->row_offset, 0);
+ stripsize = ((row + img->row_offset)%rowsperstrip + nrow) * scanline;
+ if (TIFFReadEncodedStrip(tif, strip, buf, stripsize ) < 0
+ && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+
+ pos = ((row + img->row_offset) % rowsperstrip) * scanline;
+ (*put)(img, (uint32*)(braster+y*wb), 0, y, w, nrow, fromskew, toskew, buf + pos);
+ y += (orientation == ORIENTATION_TOPLEFT ?-(int32) nrow : (int32) nrow);
+ }
+ _TIFFfree(buf);
+ return (ret);
+}
+
+/*
+ * Local Variables:
+ * mode: c++
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/contrib/win_dib/tiff2dib.c b/tiff/contrib/win_dib/tiff2dib.c
new file mode 100644
index 0000000..475ef30
--- /dev/null
+++ b/tiff/contrib/win_dib/tiff2dib.c
@@ -0,0 +1,379 @@
+/*************************************************************************
+ *
+ * Source file for Windows 95/Win32.
+ *
+ * The function LoadTIFFinDIB in this source file let you load
+ * a TIFF file and build a memory DIB with it and return the
+ * HANDLE (HDIB) of the memory bloc containing the DIB.
+ *
+ * Example :
+ *
+ * HDIB hDIB;
+ * hDIB = LoadTIFFinDIB("sample.tif");
+ *
+ *
+ * To build this source file you must include the TIFF library
+ * in your project.
+ *
+ * 4/12/95 Philippe Tenenhaus 100423.3705@compuserve.com
+ *
+ ************************************************************************/
+
+
+#include "tiffio.h"
+
+#define HDIB HANDLE
+#define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
+#define CVT(x) (((x) * 255L) / ((1L<<16)-1))
+
+static HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount);
+static LPSTR FindDIBBits(LPSTR lpDIB);
+static WORD PaletteSize(LPSTR lpDIB);
+static WORD DIBNumColors(LPSTR lpDIB);
+static int checkcmap(int n, uint16* r, uint16* g, uint16* b);
+
+
+
+/*************************************************************************
+ *
+ * HDIB LoadTIFFinDIB(LPSTR lpFileName)
+ *
+ * Parameter:
+ *
+ * LPSTR lpDIB - File name of a tiff imag
+ *
+ * Return Value:
+ *
+ * LPSTR - HANDLE of a DIB
+ *
+ * Description:
+ *
+ * This function load a TIFF file and build a memory DIB with it
+ * and return the HANDLE (HDIB) of the memory bloc containing
+ * the DIB.
+ *
+ * 4/12/95 Philippe Tenenhaus 100423.3705@compuserve.com
+ *
+ ************************************************************************/
+
+HDIB LoadTIFFinDIB(LPSTR lpFileName)
+{
+ TIFF *tif;
+ unsigned long imageLength;
+ unsigned long imageWidth;
+ unsigned int BitsPerSample;
+ unsigned long LineSize;
+ unsigned int SamplePerPixel;
+ unsigned long RowsPerStrip;
+ int PhotometricInterpretation;
+ long nrow;
+ unsigned long row;
+ char *buf;
+ LPBITMAPINFOHEADER lpDIB;
+ HDIB hDIB;
+ char *lpBits;
+ HGLOBAL hStrip;
+ int i,l;
+ int Align;
+
+ tif = TIFFOpen(lpFileName, "r");
+
+ if (!tif)
+ goto TiffOpenError;
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
+ TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample);
+ TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip);
+ TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip);
+ TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation);
+
+ LineSize = TIFFScanlineSize(tif); //Number of byte in ine line
+
+ SamplePerPixel = (int) (LineSize/imageWidth);
+
+ //Align = Number of byte to add at the end of each line of the DIB
+ Align = 4 - (LineSize % 4);
+ if (Align == 4) Align = 0;
+
+
+ //Create a new DIB
+ hDIB = CreateDIB((DWORD) imageWidth, (DWORD) imageLength, (WORD)
+(BitsPerSample*SamplePerPixel));
+ lpDIB = (LPBITMAPINFOHEADER) GlobalLock(hDIB);
+ if (!lpDIB)
+ goto OutOfDIBMemory;
+
+ if (lpDIB)
+ lpBits = FindDIBBits((LPSTR) lpDIB);
+
+ //In the tiff file the lines are save from up to down
+ //In a DIB the lines must be save from down to up
+ if (lpBits)
+ {
+ lpBits = FindDIBBits((LPSTR) lpDIB);
+ lpBits+=((imageWidth*SamplePerPixel)+Align)*(imageLength-1);
+ //now lpBits pointe on the bottom line
+
+ hStrip = GlobalAlloc(GHND,TIFFStripSize(tif));
+ buf = GlobalLock(hStrip);
+
+ if (!buf)
+ goto OutOfBufMemory;
+
+ //PhotometricInterpretation = 2 image is RGB
+ //PhotometricInterpretation = 3 image have a color palette
+ if (PhotometricInterpretation == 3)
+ {
+ uint16* red;
+ uint16* green;
+ uint16* blue;
+ int16 i;
+ LPBITMAPINFO lpbmi;
+ int Palette16Bits;
+
+ TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue);
+
+ //Is the palette 16 or 8 bits ?
+ if (checkcmap(1<<BitsPerSample, red, green, blue) == 16)
+ Palette16Bits = TRUE;
+ else
+ Palette16Bits = FALSE;
+
+ lpbmi = (LPBITMAPINFO)lpDIB;
+
+ //load the palette in the DIB
+ for (i = (1<<BitsPerSample)-1; i >= 0; i--)
+ {
+ if (Palette16Bits)
+ {
+ lpbmi->bmiColors[i].rgbRed =(BYTE) CVT(red[i]);
+ lpbmi->bmiColors[i].rgbGreen = (BYTE) CVT(green[i]);
+ lpbmi->bmiColors[i].rgbBlue = (BYTE) CVT(blue[i]);
+ }
+ else
+ {
+ lpbmi->bmiColors[i].rgbRed = (BYTE) red[i];
+ lpbmi->bmiColors[i].rgbGreen = (BYTE) green[i];
+ lpbmi->bmiColors[i].rgbBlue = (BYTE) blue[i];
+ }
+ }
+
+ }
+
+ //read the tiff lines and save them in the DIB
+ //with RGB mode, we have to change the order of the 3 samples RGB
+<=> BGR
+ for (row = 0; row < imageLength; row += RowsPerStrip)
+ {
+ nrow = (row + RowsPerStrip > imageLength ? imageLength - row :
+RowsPerStrip);
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0),
+ buf, nrow*LineSize)==-1)
+ {
+ goto TiffReadError;
+ }
+ else
+ {
+ for (l = 0; l < nrow; l++)
+ {
+ if (SamplePerPixel == 3)
+ for (i=0;i< (int) (imageWidth);i++)
+ {
+ lpBits[i*SamplePerPixel+0]=buf[l*LineSize+i*Sample
+PerPixel+2];
+ lpBits[i*SamplePerPixel+1]=buf[l*LineSize+i*Sample
+PerPixel+1];
+ lpBits[i*SamplePerPixel+2]=buf[l*LineSize+i*Sample
+PerPixel+0];
+ }
+ else
+ memcpy(lpBits, &buf[(int) (l*LineSize)], (int)
+imageWidth*SamplePerPixel);
+
+ lpBits-=imageWidth*SamplePerPixel+Align;
+
+ }
+ }
+ }
+ GlobalUnlock(hStrip);
+ GlobalFree(hStrip);
+ GlobalUnlock(hDIB);
+ TIFFClose(tif);
+ }
+
+ return hDIB;
+
+ OutOfBufMemory:
+
+ TiffReadError:
+ GlobalUnlock(hDIB);
+ GlobalFree(hStrip);
+ OutOfDIBMemory:
+ TIFFClose(tif);
+ TiffOpenError:
+ return (HANDLE) 0;
+
+
+}
+
+
+static int checkcmap(int n, uint16* r, uint16* g, uint16* b)
+{
+ while (n-- > 0)
+ if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+ return (16);
+
+ return (8);
+}
+
+
+
+/*************************************************************************
+ * All the following functions were created by microsoft, they are
+ * parts of the sample project "wincap" given with the SDK Win32.
+ *
+ * Microsoft says that :
+ *
+ * You have a royalty-free right to use, modify, reproduce and
+ * distribute the Sample Files (and/or any modified version) in
+ * any way you find useful, provided that you agree that
+ * Microsoft has no warranty obligations or liability for any
+ * Sample Application Files which are modified.
+ *
+ ************************************************************************/
+
+HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount)
+{
+ BITMAPINFOHEADER bi; // bitmap header
+ LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER
+ DWORD dwLen; // size of memory block
+ HDIB hDIB;
+ DWORD dwBytesPerLine; // Number of bytes per scanline
+
+
+ // Make sure bits per pixel is valid
+ if (wBitCount <= 1)
+ wBitCount = 1;
+ else if (wBitCount <= 4)
+ wBitCount = 4;
+ else if (wBitCount <= 8)
+ wBitCount = 8;
+ else if (wBitCount <= 24)
+ wBitCount = 24;
+ else
+ wBitCount = 4; // set default value to 4 if parameter is bogus
+
+ // initialize BITMAPINFOHEADER
+ bi.biSize = sizeof(BITMAPINFOHEADER);
+ bi.biWidth = dwWidth; // fill in width from parameter
+ bi.biHeight = dwHeight; // fill in height from parameter
+ bi.biPlanes = 1; // must be 1
+ bi.biBitCount = wBitCount; // from parameter
+ bi.biCompression = BI_RGB;
+ bi.biSizeImage = (dwWidth*dwHeight*wBitCount)/8; //0; // 0's here
+mean "default"
+ bi.biXPelsPerMeter = 2834; //0;
+ bi.biYPelsPerMeter = 2834; //0;
+ bi.biClrUsed = 0;
+ bi.biClrImportant = 0;
+
+ // calculate size of memory block required to store the DIB. This
+ // block should be big enough to hold the BITMAPINFOHEADER, the color
+ // table, and the bits
+
+ dwBytesPerLine = (((wBitCount * dwWidth) + 31) / 32 * 4);
+ dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + (dwBytesPerLine * dwHeight);
+
+ // alloc memory block to store our bitmap
+ hDIB = GlobalAlloc(GHND, dwLen);
+
+ // major bummer if we couldn't get memory block
+ if (!hDIB)
+ {
+ return NULL;
+ }
+
+ // lock memory and get pointer to it
+ lpbi = (VOID FAR *)GlobalLock(hDIB);
+
+ // use our bitmap info structure to fill in first part of
+ // our DIB with the BITMAPINFOHEADER
+ *lpbi = bi;
+
+ // Since we don't know what the colortable and bits should contain,
+ // just leave these blank. Unlock the DIB and return the HDIB.
+
+ GlobalUnlock(hDIB);
+
+ /* return handle to the DIB */
+ return hDIB;
+}
+
+
+LPSTR FAR FindDIBBits(LPSTR lpDIB)
+{
+ return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB));
+}
+
+
+WORD FAR PaletteSize(LPSTR lpDIB)
+{
+ /* calculate the size required by the palette */
+ if (IS_WIN30_DIB (lpDIB))
+ return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
+ else
+ return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
+}
+
+
+WORD DIBNumColors(LPSTR lpDIB)
+{
+ WORD wBitCount; // DIB bit count
+
+ /* If this is a Windows-style DIB, the number of colors in the
+ * color table can be less than the number of bits per pixel
+ * allows for (i.e. lpbi->biClrUsed can be set to some value).
+ * If this is the case, return the appropriate value.
+ */
+
+ if (IS_WIN30_DIB(lpDIB))
+ {
+ DWORD dwClrUsed;
+
+ dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
+ if (dwClrUsed)
+ return (WORD)dwClrUsed;
+ }
+
+ /* Calculate the number of colors in the color table based on
+ * the number of bits per pixel for the DIB.
+ */
+ if (IS_WIN30_DIB(lpDIB))
+ wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
+ else
+ wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
+
+ /* return number of colors based on bits per pixel */
+ switch (wBitCount)
+ {
+ case 1:
+ return 2;
+
+ case 4:
+ return 16;
+
+ case 8:
+ return 256;
+
+ default:
+ return 0;
+ }
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/html/Makefile.am b/tiff/html/Makefile.am
new file mode 100644
index 0000000..c8fe721
--- /dev/null
+++ b/tiff/html/Makefile.am
@@ -0,0 +1,84 @@
+# $Id: Makefile.am,v 1.16.2.2 2009-11-04 17:28:45 bfriesen Exp $
+#
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+docdir = $(LIBTIFF_DOCDIR)/html
+
+docfiles = \
+ addingtags.html \
+ bugs.html \
+ build.html \
+ contrib.html \
+ document.html \
+ images.html \
+ index.html \
+ internals.html \
+ intro.html \
+ libtiff.html \
+ misc.html \
+ support.html \
+ TIFFTechNote2.html \
+ tools.html \
+ v3.4beta007.html \
+ v3.4beta016.html \
+ v3.4beta018.html \
+ v3.4beta024.html \
+ v3.4beta028.html \
+ v3.4beta029.html \
+ v3.4beta031.html \
+ v3.4beta032.html \
+ v3.4beta033.html \
+ v3.4beta034.html \
+ v3.4beta035.html \
+ v3.4beta036.html \
+ v3.5.1.html \
+ v3.5.2.html \
+ v3.5.3.html \
+ v3.5.4.html \
+ v3.5.5.html \
+ v3.5.6-beta.html \
+ v3.5.7.html \
+ v3.6.0.html \
+ v3.6.1.html \
+ v3.7.0alpha.html \
+ v3.7.0beta.html \
+ v3.7.0beta2.html \
+ v3.7.0.html \
+ v3.7.1.html \
+ v3.7.2.html \
+ v3.7.3.html \
+ v3.7.4.html \
+ v3.8.0.html \
+ v3.8.1.html \
+ v3.8.2.html \
+ v3.9.0beta.html \
+ v3.9.1.html \
+ v3.9.2.html
+
+dist_doc_DATA = $(docfiles)
+
+SUBDIRS = images man
+
diff --git a/tiff/html/Makefile.in b/tiff/html/Makefile.in
new file mode 100644
index 0000000..e1bf866
--- /dev/null
+++ b/tiff/html/Makefile.in
@@ -0,0 +1,725 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# $Id: Makefile.am,v 1.16.2.2 2009-11-04 17:28:45 bfriesen Exp $
+#
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = html
+DIST_COMMON = $(dist_doc_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(docdir)"
+DATA = $(dist_doc_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = $(LIBTIFF_DOCDIR)/html
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+docfiles = \
+ addingtags.html \
+ bugs.html \
+ build.html \
+ contrib.html \
+ document.html \
+ images.html \
+ index.html \
+ internals.html \
+ intro.html \
+ libtiff.html \
+ misc.html \
+ support.html \
+ TIFFTechNote2.html \
+ tools.html \
+ v3.4beta007.html \
+ v3.4beta016.html \
+ v3.4beta018.html \
+ v3.4beta024.html \
+ v3.4beta028.html \
+ v3.4beta029.html \
+ v3.4beta031.html \
+ v3.4beta032.html \
+ v3.4beta033.html \
+ v3.4beta034.html \
+ v3.4beta035.html \
+ v3.4beta036.html \
+ v3.5.1.html \
+ v3.5.2.html \
+ v3.5.3.html \
+ v3.5.4.html \
+ v3.5.5.html \
+ v3.5.6-beta.html \
+ v3.5.7.html \
+ v3.6.0.html \
+ v3.6.1.html \
+ v3.7.0alpha.html \
+ v3.7.0beta.html \
+ v3.7.0beta2.html \
+ v3.7.0.html \
+ v3.7.1.html \
+ v3.7.2.html \
+ v3.7.3.html \
+ v3.7.4.html \
+ v3.8.0.html \
+ v3.8.1.html \
+ v3.8.2.html \
+ v3.9.0beta.html \
+ v3.9.1.html \
+ v3.9.2.html
+
+dist_doc_DATA = $(docfiles)
+SUBDIRS = images man
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign html/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign html/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)"
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(docdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(docdir)" && rm -f $$files
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \
+ install-am install-strip tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ ctags ctags-recursive distclean distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-recursive uninstall uninstall-am \
+ uninstall-dist_docDATA
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/html/TIFFTechNote2.html b/tiff/html/TIFFTechNote2.html
new file mode 100644
index 0000000..92bace4
--- /dev/null
+++ b/tiff/html/TIFFTechNote2.html
@@ -0,0 +1,707 @@
+<pre>
+DRAFT TIFF Technical Note #2 17-Mar-95
+============================
+
+This Technical Note describes serious problems that have been found in
+TIFF 6.0's design for embedding JPEG-compressed data in TIFF (Section 22
+of the TIFF 6.0 spec of 3 June 1992). A replacement TIFF/JPEG
+specification is given. Some corrections to Section 21 are also given.
+
+To permit TIFF implementations to continue to read existing files, the 6.0
+JPEG fields and tag values will remain reserved indefinitely. However,
+TIFF writers are strongly discouraged from using the 6.0 JPEG design. It
+is expected that the next full release of the TIFF specification will not
+describe the old design at all, except to note that certain tag numbers
+are reserved. The existing Section 22 will be replaced by the
+specification text given in the second part of this Tech Note.
+
+
+Problems in TIFF 6.0 JPEG
+=========================
+
+Abandoning a published spec is not a step to be taken lightly. This
+section summarizes the reasons that have forced this decision.
+TIFF 6.0's JPEG design suffers from design errors and limitations,
+ambiguities, and unnecessary complexity.
+
+
+Design errors and limitations
+-----------------------------
+
+The fundamental design error in the existing Section 22 is that JPEG's
+various tables and parameters are broken out as separate fields which the
+TIFF control logic must manage. This is bad software engineering: that
+information should be treated as private to the JPEG codec
+(compressor/decompressor). Worse, the fields themselves are specified
+without sufficient thought for future extension and without regard to
+well-established TIFF conventions. Here are some of the significant
+problems:
+
+* The JPEGxxTable fields do not store the table data directly in the
+IFD/field structure; rather, the fields hold pointers to information
+elsewhere in the file. This requires special-purpose code to be added to
+*every* TIFF-manipulating application, whether it needs to decode JPEG
+image data or not. Even a trivial TIFF editor, for example a program to
+add an ImageDescription field to a TIFF file, must be explicitly aware of
+the internal structure of the JPEG-related tables, or else it will probably
+break the file. Every other auxiliary field in the TIFF spec contains
+data, not pointers, and can be copied or relocated by standard code that
+doesn't know anything about the particular field. This is a crucial
+property of the TIFF format that must not be given up.
+
+* To manipulate these fields, the TIFF control logic is required to know a
+great deal about JPEG details, for example such arcana as how to compute
+the length of a Huffman code table --- the length is not supplied in the
+field structure and can only be found by inspecting the table contents.
+This is again a violation of good software practice. Moreover, it will
+prevent easy adoption of future JPEG extensions that might change these
+low-level details.
+
+* The design neglects the fact that baseline JPEG codecs support only two
+sets of Huffman tables: it specifies a separate table for each color
+component. This implies that encoders must waste space (by storing
+duplicate Huffman tables) or else violate the well-founded TIFF convention
+that prohibits duplicate pointers. Furthermore, baseline decoders must
+test to find out which tables are identical, a waste of time and code
+space.
+
+* The JPEGInterchangeFormat field also violates TIFF's proscription against
+duplicate pointers: the normal strip/tile pointers are expected to point
+into the larger data area pointed to by JPEGInterchangeFormat. All TIFF
+editing applications must be specifically aware of this relationship, since
+they must maintain it or else delete the JPEGInterchangeFormat field. The
+JPEGxxTables fields are also likely to point into the JPEGInterchangeFormat
+area, creating additional pointer relationships that must be maintained.
+
+* The JPEGQTables field is fixed at a byte per table entry; there is no
+way to support 16-bit quantization values. This is a serious impediment
+to extending TIFF to use 12-bit JPEG.
+
+* The 6.0 design cannot support using different quantization tables in
+different strips/tiles of an image (so as to encode some areas at higher
+quality than others). Furthermore, since quantization tables are tied
+one-for-one to color components, the design cannot support table switching
+options that are likely to be added in future JPEG revisions.
+
+
+Ambiguities
+-----------
+
+Several incompatible interpretations are possible for 6.0's treatment of
+JPEG restart markers:
+
+ * It is unclear whether restart markers must be omitted at TIFF segment
+ (strip/tile) boundaries, or whether they are optional.
+
+ * It is unclear whether the segment size is required to be chosen as
+ a multiple of the specified restart interval (if any); perhaps the
+ JPEG codec is supposed to be reset at each segment boundary as if
+ there were a restart marker there, even if the boundary does not fall
+ at a multiple of the nominal restart interval.
+
+ * The spec fails to address the question of restart marker numbering:
+ do the numbers begin again within each segment, or not?
+
+That last point is particularly nasty. If we make numbering begin again
+within each segment, we give up the ability to impose a TIFF strip/tile
+structure on an existing JPEG datastream with restarts (which was clearly a
+goal of Section 22's authors). But the other choice interferes with random
+access to the image segments: a reader must compute the first restart
+number to be expected within a segment, and must have a way to reset its
+JPEG decoder to expect a nonzero restart number first. This may not even
+be possible with some JPEG chips.
+
+The tile height restriction found on page 104 contradicts Section 15's
+general description of tiles. For an image that is not vertically
+downsampled, page 104 specifies a tile height of one MCU or 8 pixels; but
+Section 15 requires tiles to be a multiple of 16 pixels high.
+
+This Tech Note does not attempt to resolve these ambiguities, so
+implementations that follow the 6.0 design should be aware that
+inter-application compatibility problems are likely to arise.
+
+
+Unnecessary complexity
+----------------------
+
+The 6.0 design creates problems for implementations that need to keep the
+JPEG codec separate from the TIFF control logic --- for example, consider
+using a JPEG chip that was not designed specifically for TIFF. JPEG codecs
+generally want to produce or consume a standard ISO JPEG datastream, not
+just raw compressed data. (If they were to handle raw data, a separate
+out-of-band mechanism would be needed to load tables into the codec.)
+With such a codec, the TIFF control logic must parse JPEG markers emitted
+by the codec to create the TIFF table fields (when writing) or synthesize
+JPEG markers from the TIFF fields to feed the codec (when reading). This
+means that the control logic must know a great deal more about JPEG details
+than we would like. The parsing and reconstruction of the markers also
+represents a fair amount of unnecessary work.
+
+Quite a few implementors have proposed writing "TIFF/JPEG" files in which
+a standard JPEG datastream is simply dumped into the file and pointed to
+by JPEGInterchangeFormat. To avoid parsing the JPEG datastream, they
+suggest not writing the JPEG auxiliary fields (JPEGxxTables etc) nor even
+the basic TIFF strip/tile data pointers. This approach is incompatible
+with implementations that handle the full TIFF 6.0 JPEG design, since they
+will expect to find strip/tile pointers and auxiliary fields. Indeed this
+is arguably not TIFF at all, since *all* TIFF-reading applications expect
+to find strip or tile pointers. A subset implementation that is not
+upward-compatible with the full spec is clearly unacceptable. However,
+the frequency with which this idea has come up makes it clear that
+implementors find the existing Section 22 too complex.
+
+
+Overview of the solution
+========================
+
+To solve these problems, we adopt a new design for embedding
+JPEG-compressed data in TIFF files. The new design uses only complete,
+uninterpreted ISO JPEG datastreams, so it should be much more forgiving of
+extensions to the ISO standard. It should also be far easier to implement
+using unmodified JPEG codecs.
+
+To reduce overhead in multi-segment TIFF files, we allow JPEG overhead
+tables to be stored just once in a JPEGTables auxiliary field. This
+feature does not violate the integrity of the JPEG datastreams, because it
+uses the notions of "tables-only datastreams" and "abbreviated image
+datastreams" as defined by the ISO standard.
+
+To prevent confusion with the old design, the new design is given a new
+Compression tag value, Compression=7. Readers that need to handle
+existing 6.0 JPEG files may read both old and new files, using whatever
+interpretation of the 6.0 spec they did before. Compression tag value 6
+and the field tag numbers defined by 6.0 section 22 will remain reserved
+indefinitely, even though detailed descriptions of them will be dropped
+from future editions of the TIFF specification.
+
+
+Replacement TIFF/JPEG specification
+===================================
+
+[This section of the Tech Note is expected to replace Section 22 in the
+next release of the TIFF specification.]
+
+This section describes TIFF compression scheme 7, a high-performance
+compression method for continuous-tone images.
+
+Introduction
+------------
+
+This TIFF compression method uses the international standard for image
+compression ISO/IEC 10918-1, usually known as "JPEG" (after the original
+name of the standards committee, Joint Photographic Experts Group). JPEG
+is a joint ISO/CCITT standard for compression of continuous-tone images.
+
+The JPEG committee decided that because of the broad scope of the standard,
+no one algorithmic procedure was able to satisfy the requirements of all
+applications. Instead, the JPEG standard became a "toolkit" of multiple
+algorithms and optional capabilities. Individual applications may select
+a subset of the JPEG standard that meets their requirements.
+
+The most important distinction among the JPEG processes is between lossy
+and lossless compression. Lossy compression methods provide high
+compression but allow only approximate reconstruction of the original
+image. JPEG's lossy processes allow the encoder to trade off compressed
+file size against reconstruction fidelity over a wide range. Typically,
+10:1 or more compression of full-color data can be obtained while keeping
+the reconstructed image visually indistinguishable from the original. Much
+higher compression ratios are possible if a low-quality reconstructed image
+is acceptable. Lossless compression provides exact reconstruction of the
+source data, but the achievable compression ratio is much lower than for
+the lossy processes; JPEG's rather simple lossless process typically
+achieves around 2:1 compression of full-color data.
+
+The most widely implemented JPEG subset is the "baseline" JPEG process.
+This provides lossy compression of 8-bit-per-channel data. Optional
+extensions include 12-bit-per-channel data, arithmetic entropy coding for
+better compression, and progressive/hierarchical representations. The
+lossless process is an independent algorithm that has little in
+common with the lossy processes.
+
+It should be noted that the optional arithmetic-coding extension is subject
+to several US and Japanese patents. To avoid patent problems, use of
+arithmetic coding processes in TIFF files intended for inter-application
+interchange is discouraged.
+
+All of the JPEG processes are useful only for "continuous tone" data,
+in which the difference between adjacent pixel values is usually small.
+Low-bit-depth source data is not appropriate for JPEG compression, nor
+are palette-color images good candidates. The JPEG processes work well
+on grayscale and full-color data.
+
+Describing the JPEG compression algorithms in sufficient detail to permit
+implementation would require more space than we have here. Instead, we
+refer the reader to the References section.
+
+
+What data is being compressed?
+------------------------------
+
+In lossy JPEG compression, it is customary to convert color source data
+to YCbCr and then downsample it before JPEG compression. This gives
+2:1 data compression with hardly any visible image degradation, and it
+permits additional space savings within the JPEG compression step proper.
+However, these steps are not considered part of the ISO JPEG standard.
+The ISO standard is "color blind": it accepts data in any color space.
+
+For TIFF purposes, the JPEG compression tag is considered to represent the
+ISO JPEG compression standard only. The ISO standard is applied to the
+same data that would be stored in the TIFF file if no compression were
+used. Therefore, if color conversion or downsampling are used, they must
+be reflected in the regular TIFF fields; these steps are not considered to
+be implicit in the JPEG compression tag value. PhotometricInterpretation
+and related fields shall describe the color space actually stored in the
+file. With the TIFF 6.0 field definitions, downsampling is permissible
+only for YCbCr data, and it must correspond to the YCbCrSubSampling field.
+(Note that the default value for this field is not 1,1; so the default for
+YCbCr is to apply downsampling!) It is likely that future versions of TIFF
+will provide additional PhotometricInterpretation values and a more general
+way of defining subsampling, so as to allow more flexibility in
+JPEG-compressed files. But that issue is not addressed in this Tech Note.
+
+Implementors should note that many popular JPEG codecs
+(compressor/decompressors) provide automatic color conversion and
+downsampling, so that the application may supply full-size RGB data which
+is nonetheless converted to downsampled YCbCr. This is an implementation
+convenience which does not excuse the TIFF control layer from its
+responsibility to know what is really going on. The
+PhotometricInterpretation and subsampling fields written to the file must
+describe what is actually in the file.
+
+A JPEG-compressed TIFF file will typically have PhotometricInterpretation =
+YCbCr and YCbCrSubSampling = [2,1] or [2,2], unless the source data was
+grayscale or CMYK.
+
+
+Basic representation of JPEG-compressed images
+----------------------------------------------
+
+JPEG compression works in either strip-based or tile-based TIFF files.
+Rather than repeating "strip or tile" constantly, we will use the term
+"segment" to mean either a strip or a tile.
+
+When the Compression field has the value 7, each image segment contains
+a complete JPEG datastream which is valid according to the ISO JPEG
+standard (ISO/IEC 10918-1). Any sequential JPEG process can be used,
+including lossless JPEG, but progressive and hierarchical processes are not
+supported. Since JPEG is useful only for continuous-tone images, the
+PhotometricInterpretation of the image shall not be 3 (palette color) nor
+4 (transparency mask). The bit depth of the data is also restricted as
+specified below.
+
+Each image segment in a JPEG-compressed TIFF file shall contain a valid
+JPEG datastream according to the ISO JPEG standard's rules for
+interchange-format or abbreviated-image-format data. The datastream shall
+contain a single JPEG frame storing that segment of the image. The
+required JPEG markers within a segment are:
+ SOI (must appear at very beginning of segment)
+ SOFn
+ SOS (one for each scan, if there is more than one scan)
+ EOI (must appear at very end of segment)
+The actual compressed data follows SOS; it may contain RSTn markers if DRI
+is used.
+
+Additional JPEG "tables and miscellaneous" markers may appear between SOI
+and SOFn, between SOFn and SOS, and before each subsequent SOS if there is
+more than one scan. These markers include:
+ DQT
+ DHT
+ DAC (not to appear unless arithmetic coding is used)
+ DRI
+ APPn (shall be ignored by TIFF readers)
+ COM (shall be ignored by TIFF readers)
+DNL markers shall not be used in TIFF files. Readers should abort if any
+other marker type is found, especially the JPEG reserved markers;
+occurrence of such a marker is likely to indicate a JPEG extension.
+
+The tables/miscellaneous markers may appear in any order. Readers are
+cautioned that although the SOFn marker refers to DQT tables, JPEG does not
+require those tables to precede the SOFn, only the SOS. Missing-table
+checks should be made when SOS is reached.
+
+If no JPEGTables field is used, then each image segment shall be a complete
+JPEG interchange datastream. Each segment must define all the tables it
+references. To allow readers to decode segments in any order, no segment
+may rely on tables being carried over from a previous segment.
+
+When a JPEGTables field is used, image segments may omit tables that have
+been specified in the JPEGTables field. Further details appear below.
+
+The SOFn marker shall be of type SOF0 for strict baseline JPEG data, of
+type SOF1 for non-baseline lossy JPEG data, or of type SOF3 for lossless
+JPEG data. (SOF9 or SOF11 would be used for arithmetic coding.) All
+segments of a JPEG-compressed TIFF image shall use the same JPEG
+compression process, in particular the same SOFn type.
+
+The data precision field of the SOFn marker shall agree with the TIFF
+BitsPerSample field. (Note that when PlanarConfiguration=1, this implies
+that all components must have the same BitsPerSample value; when
+PlanarConfiguration=2, different components could have different bit
+depths.) For SOF0 only precision 8 is permitted; for SOF1, precision 8 or
+12 is permitted; for SOF3, precisions 2 to 16 are permitted.
+
+The image dimensions given in the SOFn marker shall agree with the logical
+dimensions of that particular strip or tile. For strip images, the SOFn
+image width shall equal ImageWidth and the height shall equal RowsPerStrip,
+except in the last strip; its SOFn height shall equal the number of rows
+remaining in the ImageLength. (In other words, no padding data is counted
+in the SOFn dimensions.) For tile images, each SOFn shall have width
+TileWidth and height TileHeight; adding and removing any padding needed in
+the edge tiles is the concern of some higher level of the TIFF software.
+(The dimensional rules are slightly different when PlanarConfiguration=2,
+as described below.)
+
+The ISO JPEG standard only permits images up to 65535 pixels in width or
+height, due to 2-byte fields in the SOFn markers. In TIFF, this limits
+the size of an individual JPEG-compressed strip or tile, but the total
+image size can be greater.
+
+The number of components in the JPEG datastream shall equal SamplesPerPixel
+for PlanarConfiguration=1, and shall be 1 for PlanarConfiguration=2. The
+components shall be stored in the same order as they are described at the
+TIFF field level. (This applies both to their order in the SOFn marker,
+and to the order in which they are scanned if multiple JPEG scans are
+used.) The component ID bytes are arbitrary so long as each component
+within an image segment is given a distinct ID. To avoid any possible
+confusion, we require that all segments of a TIFF image use the same ID
+code for a given component.
+
+In PlanarConfiguration 1, the sampling factors given in SOFn markers shall
+agree with the sampling factors defined by the related TIFF fields (or with
+the default values that are specified in the absence of those fields).
+
+When DCT-based JPEG is used in a strip TIFF file, RowsPerStrip is required
+to be a multiple of 8 times the largest vertical sampling factor, i.e., a
+multiple of the height of an interleaved MCU. (For simplicity of
+specification, we require this even if the data is not actually
+interleaved.) For example, if YCbCrSubSampling = [2,2] then RowsPerStrip
+must be a multiple of 16. An exception to this rule is made for
+single-strip images (RowsPerStrip >= ImageLength): the exact value of
+RowsPerStrip is unimportant in that case. This rule ensures that no data
+padding is needed at the bottom of a strip, except perhaps the last strip.
+Any padding required at the right edge of the image, or at the bottom of
+the last strip, is expected to occur internally to the JPEG codec.
+
+When DCT-based JPEG is used in a tiled TIFF file, TileLength is required
+to be a multiple of 8 times the largest vertical sampling factor, i.e.,
+a multiple of the height of an interleaved MCU; and TileWidth is required
+to be a multiple of 8 times the largest horizontal sampling factor, i.e.,
+a multiple of the width of an interleaved MCU. (For simplicity of
+specification, we require this even if the data is not actually
+interleaved.) All edge padding required will therefore occur in the course
+of normal TIFF tile padding; it is not special to JPEG.
+
+Lossless JPEG does not impose these constraints on strip and tile sizes,
+since it is not DCT-based.
+
+Note that within JPEG datastreams, multibyte values appear in the MSB-first
+order specified by the JPEG standard, regardless of the byte ordering of
+the surrounding TIFF file.
+
+
+JPEGTables field
+----------------
+
+The only auxiliary TIFF field added for Compression=7 is the optional
+JPEGTables field. The purpose of JPEGTables is to predefine JPEG
+quantization and/or Huffman tables for subsequent use by JPEG image
+segments. When this is done, these rather bulky tables need not be
+duplicated in each segment, thus saving space and processing time.
+JPEGTables may be used even in a single-segment file, although there is no
+space savings in that case.
+
+JPEGTables:
+ Tag = 347 (15B.H)
+ Type = UNDEFINED
+ N = number of bytes in tables datastream, typically a few hundred
+JPEGTables provides default JPEG quantization and/or Huffman tables which
+are used whenever a segment datastream does not contain its own tables, as
+specified below.
+
+Notice that the JPEGTables field is required to have type code UNDEFINED,
+not type code BYTE. This is to cue readers that expanding individual bytes
+to short or long integers is not appropriate. A TIFF reader will generally
+need to store the field value as an uninterpreted byte sequence until it is
+fed to the JPEG decoder.
+
+Multibyte quantities within the tables follow the ISO JPEG convention of
+MSB-first storage, regardless of the byte ordering of the surrounding TIFF
+file.
+
+When the JPEGTables field is present, it shall contain a valid JPEG
+"abbreviated table specification" datastream. This datastream shall begin
+with SOI and end with EOI. It may contain zero or more JPEG "tables and
+miscellaneous" markers, namely:
+ DQT
+ DHT
+ DAC (not to appear unless arithmetic coding is used)
+ DRI
+ APPn (shall be ignored by TIFF readers)
+ COM (shall be ignored by TIFF readers)
+Since JPEG defines the SOI marker to reset the DAC and DRI state, these two
+markers' values cannot be carried over into any image datastream, and thus
+they are effectively no-ops in the JPEGTables field. To avoid confusion,
+it is recommended that writers not place DAC or DRI markers in JPEGTables.
+However readers must properly skip over them if they appear.
+
+When JPEGTables is present, readers shall load the table specifications
+contained in JPEGTables before processing image segment datastreams.
+Image segments may simply refer to these preloaded tables without defining
+them. An image segment can still define and use its own tables, subject to
+the restrictions below.
+
+An image segment may not redefine any table defined in JPEGTables. (This
+restriction is imposed to allow readers to process image segments in random
+order without having to reload JPEGTables between segments.) Therefore, use
+of JPEGTables divides the available table slots into two groups: "global"
+slots are defined in JPEGTables and may be used but not redefined by
+segments; "local" slots are available for local definition and use in each
+segment. To permit random access, a segment may not reference any local
+tables that it does not itself define.
+
+
+Special considerations for PlanarConfiguration 2
+------------------------------------------------
+
+In PlanarConfiguration 2, each image segment contains data for only one
+color component. To avoid confusing the JPEG codec, we wish the segments
+to look like valid single-channel (i.e., grayscale) JPEG datastreams. This
+means that different rules must be used for the SOFn parameters.
+
+In PlanarConfiguration 2, the dimensions given in the SOFn of a subsampled
+component shall be scaled down by the sampling factors compared to the SOFn
+dimensions that would be used in PlanarConfiguration 1. This is necessary
+to match the actual number of samples stored in that segment, so that the
+JPEG codec doesn't complain about too much or too little data. In strip
+TIFF files the computed dimensions may need to be rounded up to the next
+integer; in tiled files, the restrictions on tile size make this case
+impossible.
+
+Furthermore, all SOFn sampling factors shall be given as 1. (This is
+merely to avoid confusion, since the sampling factors in a single-channel
+JPEG datastream have no real effect.)
+
+Any downsampling will need to happen externally to the JPEG codec, since
+JPEG sampling factors are defined with reference to the full-precision
+component. In PlanarConfiguration 2, the JPEG codec will be working on
+only one component at a time and thus will have no reference component to
+downsample against.
+
+
+Minimum requirements for TIFF/JPEG
+----------------------------------
+
+ISO JPEG is a large and complex standard; most implementations support only
+a subset of it. Here we define a "core" subset of TIFF/JPEG which readers
+must support to claim TIFF/JPEG compatibility. For maximum
+cross-application compatibility, we recommend that writers confine
+themselves to this subset unless there is very good reason to do otherwise.
+
+Use the ISO baseline JPEG process: 8-bit data precision, Huffman coding,
+with no more than 2 DC and 2 AC Huffman tables. Note that this implies
+BitsPerSample = 8 for each component. We recommend deviating from baseline
+JPEG only if 12-bit data precision or lossless coding is required.
+
+Use no subsampling (all JPEG sampling factors = 1) for color spaces other
+than YCbCr. (This is, in fact, required with the TIFF 6.0 field
+definitions, but may not be so in future revisions.) For YCbCr, use one of
+the following choices:
+ YCbCrSubSampling field JPEG sampling factors
+ 1,1 1h1v, 1h1v, 1h1v
+ 2,1 2h1v, 1h1v, 1h1v
+ 2,2 (default value) 2h2v, 1h1v, 1h1v
+We recommend that RGB source data be converted to YCbCr for best compression
+results. Other source data colorspaces should probably be left alone.
+Minimal readers need not support JPEG images with colorspaces other than
+YCbCr and grayscale (PhotometricInterpretation = 6 or 1).
+
+A minimal reader also need not support JPEG YCbCr images with nondefault
+values of YCbCrCoefficients or YCbCrPositioning, nor with values of
+ReferenceBlackWhite other than [0,255,128,255,128,255]. (These values
+correspond to the RGB<=>YCbCr conversion specified by JFIF, which is widely
+implemented in JPEG codecs.)
+
+Writers are reminded that a ReferenceBlackWhite field *must* be included
+when PhotometricInterpretation is YCbCr, because the default
+ReferenceBlackWhite values are inappropriate for YCbCr.
+
+If any subsampling is used, PlanarConfiguration=1 is preferred to avoid the
+possibly-confusing requirements of PlanarConfiguration=2. In any case,
+readers are not required to support PlanarConfiguration=2.
+
+If possible, use a single interleaved scan in each image segment. This is
+not legal JPEG if there are more than 4 SamplesPerPixel or if the sampling
+factors are such that more than 10 blocks would be needed per MCU; in that
+case, use a separate scan for each component. (The recommended color
+spaces and sampling factors will not run into that restriction, so a
+minimal reader need not support more than one scan per segment.)
+
+To claim TIFF/JPEG compatibility, readers shall support multiple-strip TIFF
+files and the optional JPEGTables field; it is not acceptable to read only
+single-datastream files. Support for tiled TIFF files is strongly
+recommended but not required.
+
+
+Other recommendations for implementors
+--------------------------------------
+
+The TIFF tag Compression=7 guarantees only that the compressed data is
+represented as ISO JPEG datastreams. Since JPEG is a large and evolving
+standard, readers should apply careful error checking to the JPEG markers
+to ensure that the compression process is within their capabilities. In
+particular, to avoid being confused by future extensions to the JPEG
+standard, it is important to abort if unknown marker codes are seen.
+
+The point of requiring that all image segments use the same JPEG process is
+to ensure that a reader need check only one segment to determine whether it
+can handle the image. For example, consider a TIFF reader that has access
+to fast but restricted JPEG hardware, as well as a slower, more general
+software implementation. It is desirable to check only one image segment
+to find out whether the fast hardware can be used. Thus, writers should
+try to ensure that all segments of an image look as much "alike" as
+possible: there should be no variation in scan layout, use of options such
+as DRI, etc. Ideally, segments will be processed identically except
+perhaps for using different local quantization or entropy-coding tables.
+
+Writers should avoid including "noise" JPEG markers (COM and APPn markers).
+Standard TIFF fields provide a better way to transport any non-image data.
+Some JPEG codecs may change behavior if they see an APPn marker they
+think they understand; since the TIFF spec requires these markers to be
+ignored, this behavior is undesirable.
+
+It is possible to convert an interchange-JPEG file (e.g., a JFIF file) to
+TIFF simply by dropping the interchange datastream into a single strip.
+(However, designers are reminded that the TIFF spec discourages huge
+strips; splitting the image is somewhat more work but may give better
+results.) Conversion from TIFF to interchange JPEG is more complex. A
+strip-based TIFF/JPEG file can be converted fairly easily if all strips use
+identical JPEG tables and no RSTn markers: just delete the overhead markers
+and insert RSTn markers between strips. Converting tiled images is harder,
+since the data will usually not be in the right order (unless the tiles are
+only one MCU high). This can still be done losslessly, but it will require
+undoing and redoing the entropy coding so that the DC coefficient
+differences can be updated.
+
+There is no default value for JPEGTables: standard TIFF files must define all
+tables that they reference. For some closed systems in which many files will
+have identical tables, it might make sense to define a default JPEGTables
+value to avoid actually storing the tables. Or even better, invent a
+private field selecting one of N default JPEGTables settings, so as to allow
+for future expansion. Either of these must be regarded as a private
+extension that will render the files unreadable by other applications.
+
+
+References
+----------
+
+[1] Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
+
+This is the best short technical introduction to the JPEG algorithms.
+It is a good overview but does not provide sufficiently detailed
+information to write an implementation.
+
+[2] Pennebaker, William B. and Mitchell, Joan L. "JPEG Still Image Data
+Compression Standard", Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
+638pp.
+
+This textbook is by far the most complete exposition of JPEG in existence.
+It includes the full text of the ISO JPEG standards (DIS 10918-1 and draft
+DIS 10918-2). No would-be JPEG implementor should be without it.
+
+[3] ISO/IEC IS 10918-1, "Digital Compression and Coding of Continuous-tone
+Still Images, Part 1: Requirements and guidelines", February 1994.
+ISO/IEC DIS 10918-2, "Digital Compression and Coding of Continuous-tone
+Still Images, Part 2: Compliance testing", final approval expected 1994.
+
+These are the official standards documents. Note that the Pennebaker and
+Mitchell textbook is likely to be cheaper and more useful than the official
+standards.
+
+
+Changes to Section 21: YCbCr Images
+===================================
+
+[This section of the Tech Note clarifies section 21 to make clear the
+interpretation of image dimensions in a subsampled image. Furthermore,
+the section is changed to allow the original image dimensions not to be
+multiples of the sampling factors. This change is necessary to support use
+of JPEG compression on odd-size images.]
+
+Add the following paragraphs to the Section 21 introduction (p. 89),
+just after the paragraph beginning "When a Class Y image is subsampled":
+
+ In a subsampled image, it is understood that all TIFF image
+ dimensions are measured in terms of the highest-resolution
+ (luminance) component. In particular, ImageWidth, ImageLength,
+ RowsPerStrip, TileWidth, TileLength, XResolution, and YResolution
+ are measured in luminance samples.
+
+ RowsPerStrip, TileWidth, and TileLength are constrained so that
+ there are an integral number of samples of each component in a
+ complete strip or tile. However, ImageWidth/ImageLength are not
+ constrained. If an odd-size image is to be converted to subsampled
+ format, the writer should pad the source data to a multiple of the
+ sampling factors by replication of the last column and/or row, then
+ downsample. The number of luminance samples actually stored in the
+ file will be a multiple of the sampling factors. Conversely,
+ readers must ignore any extra data (outside the specified image
+ dimensions) after upsampling.
+
+ When PlanarConfiguration=2, each strip or tile covers the same
+ image area despite subsampling; that is, the total number of strips
+ or tiles in the image is the same for each component. Therefore
+ strips or tiles of the subsampled components contain fewer samples
+ than strips or tiles of the luminance component.
+
+ If there are extra samples per pixel (see field ExtraSamples),
+ these data channels have the same number of samples as the
+ luminance component.
+
+Rewrite the YCbCrSubSampling field description (pp 91-92) as follows
+(largely to eliminate possibly-misleading references to
+ImageWidth/ImageLength of the subsampled components):
+
+ (first paragraph unchanged)
+
+ The two elements of this field are defined as follows:
+
+ Short 0: ChromaSubsampleHoriz:
+
+ 1 = there are equal numbers of luma and chroma samples horizontally.
+
+ 2 = there are twice as many luma samples as chroma samples
+ horizontally.
+
+ 4 = there are four times as many luma samples as chroma samples
+ horizontally.
+
+ Short 1: ChromaSubsampleVert:
+
+ 1 = there are equal numbers of luma and chroma samples vertically.
+
+ 2 = there are twice as many luma samples as chroma samples
+ vertically.
+
+ 4 = there are four times as many luma samples as chroma samples
+ vertically.
+
+ ChromaSubsampleVert shall always be less than or equal to
+ ChromaSubsampleHoriz. Note that Cb and Cr have the same sampling
+ ratios.
+
+ In a strip TIFF file, RowsPerStrip is required to be an integer
+ multiple of ChromaSubSampleVert (unless RowsPerStrip >=
+ ImageLength, in which case its exact value is unimportant).
+ If ImageWidth and ImageLength are not multiples of
+ ChromaSubsampleHoriz and ChromaSubsampleVert respectively, then the
+ source data shall be padded to the next integer multiple of these
+ values before downsampling.
+
+ In a tiled TIFF file, TileWidth must be an integer multiple of
+ ChromaSubsampleHoriz and TileLength must be an integer multiple of
+ ChromaSubsampleVert. Padding will occur to tile boundaries.
+
+ The default values of this field are [ 2,2 ]. Thus, YCbCr data is
+ downsampled by default!
+</pre>
diff --git a/tiff/html/addingtags.html b/tiff/html/addingtags.html
new file mode 100644
index 0000000..452821c
--- /dev/null
+++ b/tiff/html/addingtags.html
@@ -0,0 +1,292 @@
+<HTML>
+<HEAD>
+<TITLE>
+Modifying The TIFF Library
+</TITLE>
+</HEAD>
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<H1>
+Defining New TIFF Tags
+</H1>
+
+Libtiff has built-in knowledge of all the standard TIFF tags, as
+well as extentions. The following describes how to add knowledge of
+new tags as builtins to libtiff, or how to application specific tags can
+be used by applications without modifying libtiff.
+<p>
+
+<h2>TIFFFieldInfo</h2>
+
+How libtiff manages specific tags is primarily controlled by the
+definition for that tag value stored internally as a TIFFFieldInfo structure.
+This structure looks like this:
+<p>
+
+<pre>
+typedef struct {
+ ttag_t field_tag; /* field's tag */
+ short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */
+ short field_writecount; /* write count/TIFF_VARIABLE */
+ TIFFDataType field_type; /* type of associated data */
+ unsigned short field_bit; /* bit in fieldsset bit vector */
+ unsigned char field_oktochange;/* if true, can change while writing */
+ unsigned char field_passcount;/* if true, pass dir count on set */
+ char *field_name; /* ASCII name */
+} TIFFFieldInfo;
+</pre>
+
+<ul>
+<li> <b>field_tag</b>: the tag number. For instance 277 for the
+SamplesPerPixel tag. Builtin tags will generally have a #define in
+tiff.h for each known tag. <p>
+
+<li> <b>field_readcount</b>: The number of values which should be read.
+The special value TIFF_VARIABLE (-1) indicates that a variable number of
+values may be read. The special value TIFFTAG_SPP (-2) indicates that there
+should be one value for each sample as defined by TIFFTAG_SAMPLESPERPIXEL.
+The special value TIFF_VARIABLE2 (-3) is presumably similar to TIFF_VARIABLE
+though I am not sure what the distinction in behaviour is. This field
+is TIFF_VARIABLE for variable length ascii fields.<p>
+
+<li> <b>field_writecount</b>: The number of values which should be written.
+Generally the same as field_readcount. A few built-in exceptions exist, but
+I haven't analysed why they differ. <p>
+
+<li> <b>field_type</b>: Type of the field. One of TIFF_BYTE, TIFF_ASCII,
+TIFF_SHORT, TIFF_LONG, TIFF_RATIONAL, TIFF_SBYTE, TIFF_UNDEFINED,
+TIFF_SSHORT, TIFF_SLONG, TIFF_SRATIONAL, TIFF_FLOAT, TIFF_DOUBLE or
+TIFF_IFD. Note that some fields can support more than one type (for
+instance short and long). These fields should have multiple TIFFFieldInfos.
+<p>
+
+<li> <b>field_bit</b>: Built-in tags stored in special fields in the
+TIFF structure have assigned field numbers to distinguish them (ie.
+FIELD_SAMPLESPERPIXEL). New tags should generally just use
+FIELD_CUSTOM indicating they are stored in the generic tag list.<p>
+
+<li> <b>field_oktochange</b>: TRUE if it is OK to change this tag value
+while an image is being written. FALSE for stuff that must be set once
+and then left unchanged (like ImageWidth, or PhotometricInterpretation for
+instance).<p>
+
+<li> <b>field_passcount</b>: If TRUE, then the count value must be passed
+in TIFFSetField(), and TIFFGetField(), otherwise the count is not required.
+This should generally be TRUE for non-ascii variable count tags unless
+the count is implicit (such as with the colormap).<p>
+
+<li> <b>field_name</b>: A name for the tag. Normally mixed case (studly caps)
+like "StripByteCounts" and relatively short. <p>
+
+</ul>
+
+A TIFFFieldInfo definition exists for each built-in tag in the tif_dirinfo.c
+file. Some tags which support multiple data types have more than one
+definition, one per data type supported. <p>
+
+Various functions exist for getting the internal TIFFFieldInfo definitions,
+including _TIFFFindFieldInfo(), and _TIFFFindFieldInfoByName(). See
+tif_dirinfo.c for details. There must be some mechanism to get the whole
+list, though I don't see it off hand.<p>
+
+<h2>Default Tag Auto-registration</h2>
+
+In libtiff 3.6.0 a new mechanism was introduced allowing libtiff to
+read unrecognised tags automatically. When an unknown tags is encountered,
+it is automatically internally defined with a default name and a type
+derived from the tag value in the file. Applications only need to predefine
+application specific tags if they need to be able to set them in a file, or
+if particular calling conventions are desired for TIFFSetField() and
+TIFFGetField().<p>
+
+When tags are autodefined like this the <b>field_readcount</b> and
+<b>field_writecount</b> values are always TIFF_VARIABLE. The
+<b>field_passcount</b> is always TRUE, and the <b>field_bit</b> is
+FIELD_CUSTOM. The field name will be "Tag %d" where the %d is the tag
+number.<p>
+
+<h2>Defining Application Tags</h2>
+
+For various reasons, it is common for applications to want to define
+their own tags to store information outside the core TIFF specification.
+This is done by calling TIFFMergeFieldInfo() with one or more TIFFFieldInfos.
+<p>
+
+The libgeotiff library provides geospatial information extentions within
+a TIFF file. First, a set of TIFFFieldInfo's is prepared with information
+on the new tags:<p>
+
+<pre>
+static const TIFFFieldInfo xtiffFieldInfo[] = {
+
+ /* XXX Insert Your tags here */
+ { TIFFTAG_GEOPIXELSCALE, -1,-1, TIFF_DOUBLE, FIELD_CUSTOM,
+ TRUE, TRUE, "GeoPixelScale" },
+ { TIFFTAG_GEOTRANSMATRIX, -1,-1, TIFF_DOUBLE, FIELD_CUSTOM,
+ TRUE, TRUE, "GeoTransformationMatrix" },
+ { TIFFTAG_GEOTIEPOINTS, -1,-1, TIFF_DOUBLE, FIELD_CUSTOM,
+ TRUE, TRUE, "GeoTiePoints" },
+ { TIFFTAG_GEOKEYDIRECTORY, -1,-1, TIFF_SHORT, FIELD_CUSTOM,
+ TRUE, TRUE, "GeoKeyDirectory" },
+ { TIFFTAG_GEODOUBLEPARAMS, -1,-1, TIFF_DOUBLE, FIELD_CUSTOM,
+ TRUE, TRUE, "GeoDoubleParams" },
+ { TIFFTAG_GEOASCIIPARAMS, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ TRUE, FALSE, "GeoASCIIParams" }
+};
+</pre>
+
+In order to define the tags, we call TIFFMergeFieldInfo() on the
+desired TIFF handle with the list of TIFFFieldInfos.<p>
+
+<pre>
+#define N(a) (sizeof (a) / sizeof (a[0]))
+
+ /* Install the extended Tag field info */
+ TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo));
+</pre>
+
+The tags need to be defined for each TIFF file opened - and when reading
+they should be defined before the tags of the file are read, yet a valid
+TIFF * is needed to merge the tags against. In order to get them
+registered at the appropriate part of the setup process, it is necessary
+to register our merge function as an extender callback with libtiff.
+This is done with TIFFSetTagExtender(). We also keep track of the
+previous tag extender (if any) so that we can call it from our extender
+allowing a chain of customizations to take effect. <P>
+
+<pre>
+static TIFFExtendProc _ParentExtender = NULL;
+
+static
+void _XTIFFInitialize(void)
+{
+ static int first_time=1;
+
+ if (! first_time) return; /* Been there. Done that. */
+ first_time = 0;
+
+ /* Grab the inherited method and install */
+ _ParentExtender = TIFFSetTagExtender(_XTIFFDefaultDirectory);
+}
+</pre>
+
+The extender callback is looks like this. It merges in our new fields
+and then calls the next extender if there is one in effect.<p>
+
+<pre>
+static void
+_XTIFFDefaultDirectory(TIFF *tif)
+{
+ /* Install the extended Tag field info */
+ TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo));
+
+ /* Since an XTIFF client module may have overridden
+ * the default directory method, we call it now to
+ * allow it to set up the rest of its own methods.
+ */
+
+ if (_ParentExtender)
+ (*_ParentExtender)(tif);
+}
+</pre>
+
+The above approach ensures that our new definitions are used when reading
+or writing any TIFF file. However, since on reading we already have
+default definitions for tags, it is usually not critical to pre-define them.
+If tag definitions are only required for writing custom tags, you can just
+call TIFFMergeFieldInfo() before setting new tags. The whole extender
+architecture can then be avoided.<p>
+
+<A NAME=AddingTags><P><H2>Adding New Builtin Tags</H2></A>
+
+A similar approach is taken to the above. However, the TIFFFieldInfo
+should be added to the tiffFieldInfo[] list in tif_dirinfo.c. Ensure that
+new tags are added in sorted order by the tag number.<p>
+
+Normally new built-in tags should be defined with FIELD_CUSTOM; however, if
+it is desirable for the tag value to have it's own field in the TIFFDirectory
+structure, then you will need to #define a new FIELD_ value for it, and
+add appropriate handling as follows:
+
+
+<OL>
+<LI>Define the tag in <B>tiff.h</B>.
+<LI>Add a field to the directory structure in <B>tif_dir.h</B>
+ and define a <TT>FIELD_*</TT> bit (also update the definition of
+ <TT>FIELD_CODEC</TT> to reflect your addition).
+<LI>Add an entry in the <TT>TIFFFieldInfo</TT> array defined at the top of
+ <B>tif_dirinfo.c</B>.
+ Note that you must keep this array sorted by tag
+ number and that the widest variant entry for a tag should come
+ first (e.g. <TT>LONG</TT> before <TT>SHORT</TT>).
+<LI>Add entries in <TT>_TIFFVSetField()</TT> and <TT>_TIFFVGetField()</TT>
+ for the new tag.
+<LI>(<I>optional</I>) If the value associated with the tag is not a scalar value
+ (e.g. the array for <TT>TransferFunction</TT>) and requires
+ special processing,
+ then add the appropriate code to <TT>TIFFReadDirectory()</TT> and
+ <TT>TIFFWriteDirectory()</TT>. You're best off finding a similar tag and
+ cribbing code.
+<LI>Add support to <TT>TIFFPrintDirectory()</TT> in <B>tif_print.c</B>
+ to print the tag's value.
+</OL>
+
+<P>
+If you want to maintain portability, beware of making assumptions
+about data types. Use the typedefs (<TT>uint16</TT>, etc. when dealing with
+data on disk and <TT>t*_t</TT> when stuff is in memory) and be careful about
+passing items through printf or similar vararg interfaces.
+
+<A NAME=AddingCODECTags><P><H2>Adding New Codec-private Tags</H2></A>
+
+To add tags that are meaningful <EM>only when a particular compression
+algorithm is used</EM> follow these steps:
+
+<OL>
+<LI>Define the tag in <B>tiff.h</B>.
+<LI>Allocate storage for the tag values in the private state block of
+ the codec.
+<LI>Insure the state block is created when the codec is initialized.
+<LI>At <TT>TIFFInitfoo</TT> time override the method pointers in the
+ TIFF structure
+ for getting, setting and printing tag values. For example,
+<PRE>
+ sp->vgetparent = tif->tif_vgetfield;
+ tif->tif_vgetfield = fooVGetField; /* hook for codec tags */
+ sp->vsetparent = tif->tif_vsetfield;
+ tif->tif_vsetfield = fooVSetField; /* hook for codec tags */
+ tif->tif_printdir = fooPrintDir; /* hook for codec tags */
+</PRE>
+ (Actually you may decide not to override the
+ <TT>tif_printdir</TT> method, but rather just specify it).
+<LI>Create a private <TT>TIFFFieldInfo</TT> array for your tags and
+ merge them into the core tags at initialization time using
+ <TT>_TIFFMergeFieldInfo</TT>; e.g.
+<PRE>
+ _TIFFMergeFieldInfo(tif, fooFieldInfo, N(fooFieldInfo));
+</PRE>
+ (where <TT>N</TT> is a macro used liberaly throughout the distributed code).
+<LI>Fill in the get and set routines. Be sure to call the parent method
+ for tags that you are not handled directly. Also be sure to set the
+ <TT>FIELD_*</TT> bits for tags that are to be written to the file. Note that
+ you can create ``pseudo-tags'' by defining tags that are processed
+ exclusively in the get/set routines and never written to file (see
+ the handling of <TT>TIFFTAG_FAXMODE</TT> in <B>tif_fax3.c</B>
+ for an example of this).
+<LI>Fill in the print routine, if appropriate.
+</OL>
+
+Note that space has been allocated in the <TT>FIELD_*</TT> bit space for
+codec-private tags. Define your bits as <TT>FIELD_CODEC+&lt;offset&gt;</TT> to
+keep them away from the core tags. If you need more tags than there
+is room for, just increase <TT>FIELD_SETLONGS</TT> at the top of
+<B>tiffiop.h</B>.
+
+<HR>
+
+Last updated: $Date: 2004/09/10 14:43:18 $
+
+</BODY>
+
+</HTML>
diff --git a/tiff/html/bugs.html b/tiff/html/bugs.html
new file mode 100644
index 0000000..dd17c73
--- /dev/null
+++ b/tiff/html/bugs.html
@@ -0,0 +1,63 @@
+<HTML>
+<HEAD>
+<TITLE>Bugs and the TIFF Mailing List</TITLE>
+</HEAD>
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<H1>
+<IMG SRC=images/cover.jpg WIDTH=110 HEIGHT=110 ALIGN=left BORDER=1 HSPACE=6>
+Bugs, Bugzilla, and the TIFF Mailing List
+</H1>
+
+<P>
+This software is free. Please let us know when you find a problem or
+fix a bug.
+
+<P>
+Thanks to <A HREF=http://www.maptools.org/>MapTools.org</a>, libtiff now uses
+bugzilla to track bugs. All bugs filed in the older bugzilla at
+bugzilla.remotesensing.org (pre April 2008) have unfortunately been lost.
+<P>
+If you think you've discovered a bug, please first check to see if it is
+already known by looking at the list of already reported bugs. You can do so
+by visiting the buglist at
+<A HREF=http://bugzilla.maptools.org/buglist.cgi?product=libtiff>http://bugzilla.maptools.org/buglist.cgi?product=libtiff</A>. Also verify that
+the problem is still reproducable with the current development software
+from CVS.
+<P>
+If you'd like to enter a new bug, you can do so at
+<A HREF=http://bugzilla.maptools.org/enter_bug.cgi?product=libtiff>http://bugzilla.maptools.org/enter_bug.cgi?product=libtiff</A>.
+<P>
+If you'd like to inform us about some kind of security issue that should not
+be disclosed for a period of time, then you can contact maintainers directly.
+Send a copies of your report to the following people: Frank Warmerdam
+<a href="mailto:warmerdam@pobox.com">&lt;warmerdam@pobox.com&gt;</a>,
+Andrey Kiselev
+<a href="mailto:dron@ak4719.spb.edu">&lt;dron@ak4719.spb.edu&gt;</a>.
+<P>
+
+Of course, reporting bugs is no substitute for discussion. The
+<a href="mailto:tiff@lists.maptools.org">tiff@lists.maptools.org</a> mailing
+list is for users of this software, and discussion TIFF issues in general.
+It is managed with the Mailman software, and the web interface for subscribing
+and managing your access to the list is at:<p>
+
+ <a href="http://lists.maptools.org/mailman/listinfo/tiff">http://lists.maptools.org/mailman/listinfo/tiff</a><P>
+
+Posts to the list are only accepted from members of the list in order
+to limit the amount of spam propagated. Also, to be approved as a member
+you will need to email the list administrator with a brief description of
+why you are interested in TIFF so we can weed out spammers.<p>
+
+A <A HREF="http://www.awaresystems.be/imaging/tiff/tml.html">Long Term
+Archive</a> including recent messages, and most messages back to 1993,
+with search capabilities is available, and
+has been prepared and hosted by <a href="http://www.awaresystems.be">AWare
+Systems</a>. <p>
+
+
+<HR>
+
+Last updated: $Date: 2008/09/03 08:04:26 $
+</BODY>
+</HTML>
diff --git a/tiff/html/build.html b/tiff/html/build.html
new file mode 100644
index 0000000..e0b2157
--- /dev/null
+++ b/tiff/html/build.html
@@ -0,0 +1,880 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta name="generator" content=
+"HTML Tidy for Solaris (vers 12 April 2005), see www.w3.org">
+<title>Building the TIFF Software Distribution</title>
+</head>
+<body bgcolor="white">
+<h1><font face="Arial, Helvetica, Sans"><img src=
+"images/cramps.gif" width="159" height="203" align="left" border=
+"1" hspace="6"> Building the Software Distribution</font></h1>
+<ul>
+<li><a href="#UNIX">Building on a UNIX system</a>.</li>
+<li><a href="#MacMPW">Building on a Macintosh system with
+MPW</a>.</li>
+<li><a href="#MacCW">Building on a Macintosh system with
+CodeWarrior</a>.</li>
+<li><a href="#PC">Building on an MS-DOS or Windows system</a>.</li>
+<li><a href="#DJGPP">Building on MS-DOS with the DJGPP v2
+compiler</a>.</li>
+<li><a href="#VMS">Building on a VMS system</a>.</li>
+<li><a href="#Acorn">Building on an Acorn RISC OS system</a>.</li>
+<li><a href="#Other">Building the Software on Other
+Systems</a></li>
+</ul>
+<br clear="left">
+This chapter contains step-by-step instructions on how to configure
+and build the TIFF software distribution. The software is most
+easily built on a UNIX system, but with a little bit of work it can
+easily be built and used on other non-UNIX platforms. <a name=
+"UNIX" id="UNIX"></a>
+<hr>
+<h2>Building on a UNIX System</h2>
+To build the software on a UNIX system you need to first run the
+configure shell script that is located in the top level of the
+source directory. This script probes the target system for
+necessary tools and functions and constructs a build environment in
+which the software may be compiled. Once configuration is done, you
+simply run <tt>make</tt> (or <tt>gmake</tt>) to build the software
+and then <tt>make install</tt> to do the installation; for example:
+<div style="margin-left: 2em">
+<pre>
+hyla% <b>cd tiff-v3.4beta099</b>
+hyla% <b>./configure</b>
+ <i>...lots of messages...</i>
+hyla% <b>make</b>
+ <i>...lots of messages...</i>
+hyla# <b>make install</b>
+</pre></div>
+Supplied makefiles are depend on GNU <tt>make</tt> utility, so you
+will need the one. Depending on your installation <b>make</b>
+command may invoke standard system <tt>make</tt> and <b>gmake</b>
+invoke GNU make. In this case you should use former. If you don't
+have <tt>make</tt> at all, but only <tt>gmake</tt>, you should
+export environment variable <tt>MAKE=gmake</tt> before
+<b>./configure</b>.
+<p>In general, the software is designed such that the following
+should be ``<i>make-able</i>'' in each directory:</p>
+<div style="margin-left: 2em">
+<pre>
+make [all] build stuff
+make install build&amp;install stuff
+make clean remove .o files, executables and cruft
+make distclean remove everything, that can be recreated
+</pre></div>
+Note that after running "<tt>make distclean</tt>" the
+<tt>configure</tt> script must be run again to create the Makefiles
+and other make-related files. <a name="BuildTrees" id=
+"BuildTrees"></a>
+<hr width="65%" align="right">
+<h3>Build Trees</h3>
+There are two schemes for configuring and building the software. If
+you intend to build the software for only one target system, you
+can configure the software so that it is built in the same
+directories as the source code.
+<div style="margin-left: 2em">
+<pre>
+hyla% <b>cd tiff-v3.4beta099</b>
+hyla% <b>ls</b>
+COPYRIGHT VERSION config.sub dist man
+Makefile.in config.guess configure html port
+README config.site contrib libtiff tools
+hyla% <b>./configure</b>
+</pre></div>
+<p>Otherwise, you can configure a build tree that is parallel to
+the source tree hierarchy but which contains only configured files
+and files created during the build procedure.</p>
+<div style="margin-left: 2em">
+<pre>
+hyla% <b>cd tiff-v3.4beta099</b>
+hyla% <b>mkdir obj obj/mycpu</b>
+hyla% <b>cd obj/mycpu</b>
+hyla% <b>../../configure</b>
+</pre></div>
+This second scheme is useful for:
+<ul>
+<li>building multiple targets from a single source tree</li>
+<li>building from a read-only source tree (e.g. if you receive the
+distribution on CD-ROM)</li>
+</ul>
+<a name="ConfigOptions" id="ConfigOptions"></a>
+<hr width="65%" align="right">
+<h3>Configuration Options</h3>
+The configuration process is critical to the proper compilation,
+installation, and operation of the software. The configure script
+runs a series of tests to decide whether or not the target system
+supports required functionality and, if it does not, whether it can
+emulate or workaround the missing functions. This procedure is
+fairly complicated and, due to the nonstandard nature of most UNIX
+systems, prone to error. The first time that you configure the
+software for use you should check the output from the configure
+script and look for anything that does not make sense for your
+system.
+<p>A second function of the configure script is to set the default
+configuration parameters for the software. Of particular note are
+the directories where the software is to be installed. By default
+the software is installed in the <b>/usr/local</b> hierarchy. To
+change this behaviour the appropriate parameters can be specified
+on the command line to configure. Run <b>./configure --help</b> to
+get a list of possible options. Installation related options are
+shown below.</p>
+<pre>
+<tt>
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [/usr/local]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, `make install' will install all the files in
+`/usr/local/bin', `/usr/local/lib' etc. You can specify
+an installation prefix other than `/usr/local' using `--prefix',
+for instance `--prefix=$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+</tt>
+</pre>
+<a name="Packages" id="Packages"></a>
+<hr width="65%" align="right">
+<h3>Configuring Optional Packages/Support</h3>
+The TIFF software comes with several packages that are installed
+only as needed, or only if specifically configured at the time the
+configure script is run. Packages can be configured via the
+<b>configure</b> script commandline parameters.
+<dl>
+<dt><i>Static/Shared Objects Support</i></dt>
+<dd><tt>--enable-shared[=PKGS]&nbsp;&nbsp;&nbsp;&nbsp;build shared
+libraries [default=yes]<br>
+--enable-static[=PKGS]&nbsp;&nbsp;&nbsp;&nbsp;build static
+libraries [default=yes]</tt>
+<p>These options control whether or not to configure the software
+to build a shared and static binaries for the TIFF library. Use of
+shared libraries can significantly reduce the disk space needed for
+users of the TIFF software. If shared libarries are not used then
+the code is statically linked into each application that uses it.
+By default both types of binaries is configured.</p>
+<p><tt>--enable-rpath&nbsp;&nbsp;&nbsp;&nbsp;Enable runtime linker
+paths (-R libtool option)</tt></p>
+<p>Add library directories (see other options below) to the TIFF
+library run-time linker path.</p>
+</dd>
+<dt><i>JPEG Support</i></dt>
+<dd><tt>--disable-jpeg&nbsp;&nbsp;&nbsp;&nbsp;disable IJG JPEG
+library usage (required for JPEG compression, enabled by default)
+--with-jpeg-include-dir=DIR&nbsp;&nbsp;&nbsp;&nbsp;location of IJG
+JPEG library headers
+--with-jpeg-lib-dir=DIR&nbsp;&nbsp;&nbsp;&nbsp;location of IJG JPEG
+library binary)</tt></dd>
+<dd>The <tt>JPEG</tt> package enables support for the handling of
+TIFF images with JPEG-encoded data. Support for JPEG-encoded data
+requires the Independent JPEG Group (IJG) <tt>libjpeg</tt>
+distribution; this software is available at <a href=
+"ftp://ftp.uu.net/graphics/jpeg/">ftp.uu.net:/graphics/jpeg/</a>.
+<b>configure</b> script automatically tries to search the working
+IJG JPEG installation. If it fails to find library, JPEG support
+will be automatically disabled.If you want specify the exact paths
+to library binary and headers, use above switches for that.</dd>
+<dt><i>ZIP Support</i></dt>
+<dd>The <tt>ZIP</tt> support enables support for the handling of
+TIFF images with deflate-encoded data. Support for deflate-encoded
+data requires the freely available <tt>zlib</tt> distribution
+written by Jean-loup Gailly and Mark Adler; this software is
+available at <a href=
+"ftp://ftp.uu.net/pub/archiving/zip/zlib/">ftp.uu.net:/pub/archiving/zip/zlib/</a>
+(or try <a href=
+"ftp://quest.jpl.nasa.gov/beta/zlib/">quest.jpl.nasa.gov:/beta/zlib/</a>).
+If ZIP support is enabled the <tt>DIRS_LIBINC</tt> and
+<tt>DIR_GZLIB</tt> parameters should also be set (see below). By
+default this package is not configured.</dd>
+</dl>
+<a name="Sample" id="Sample"></a>
+<hr width="65%" align="right">
+<h3>A Sample Configuration Session</h3>
+This section shows a sample configuration session and describes the
+work done. The session is shown indented in a <tt>fixed width
+font</tt> with user-supplied input in a <tt><b>bold font</b></tt>.
+Comments are shown in a normal or <i>italic</i> font. This session
+was collected on a 486 machine running BSDI 1.1.
+<div style="margin-left: 2em">
+<pre>
+<tt>
+wullbrandt% <b>mkdir tiff</b>
+wullbrandt% <b>cd tiff</b>
+wullbrandt% <b>ln -s /hosts/oxford/usr/people/sam/tiff src</b>
+</tt>
+</pre></div>
+A build tree separate from the source tree is used here. In fact,
+in this case the distribution is accessed from a read-only
+NFS-mounted filesystem.
+<div style="margin-left: 2em">
+<pre>
+<tt>
+wullbrandt% <b>src/configure</b>
+Configuring TIFF Software v3.4beta015.
+
+Reading site-wide parameters from ../tiff-v3.4beta015/config.site.
+Reading local parameters from config.local.
+Gosh, aren't you lucky to have a i386-unknown-bsdi1.1 system!
+</tt>
+</pre></div>
+Note that configure announces the distribution version and the
+deduced target configuration (<tt>i386-unknown-bsdi1.1</tt> here).
+<div style="margin-left: 2em">
+<pre>
+<tt>
+Using /usr/local/bin/gcc for a C compiler (set CC to override).
+Looks like /usr/local/bin/gcc supports the -g option.
+Using " -g" for C compiler options.
+</tt>
+</pre></div>
+configure checked the normal shell search path for potential ANSI C
+compilers. The compiler is selected according to it properly
+compiling a small ANSI C test program. A specific compiler may be
+requested by setting the <tt>CC</tt> environment variable to the
+appropriate pathname, by supplying the parameter on the command
+line, e.g. <tt>-with-CC=gcc</tt>, or by setting <tt>CC</tt> in a
+configuration file.
+<p><img src="images/info.gif" align="left" hspace="10"> <em>Note
+that an ANSI C compiler is required to build the software. If a C
+compiler requires options to enable ANSI C compilation, they can be
+specified with the <tt>ENVOPTS</tt> parameter.</em></p>
+<p>Once a compiler is selected configure checks to see if the
+compiler accepts a -g option to enable the generation of debugging
+symbols, and if the compiler includes an ANSI C preprocessor.</p>
+<div style="margin-left: 2em">
+<pre>
+<tt>
+Using /usr/ucb/make to configure the software.
+</tt>
+</pre></div>
+Next various system-specific libraries that may or may not be
+needed are checked for (none are needed in this case). If your
+system requires a library that is not automatically included it can
+be specified by setting the <tt>MACHDEPLIBS</tt> parameter.
+<p><i>Creating port.h.</i> The <b>port.h</b> file is included by
+all the C code in the library (but not the tools). It includes
+definitions for functions and type definitions that are missing
+from system include files, <tt>#defines</tt> to enable or disable
+system-specific functionality, and other odds and ends.</p>
+<div style="margin-left: 2em">
+<pre>
+<tt>
+Creating libtiff/port.h with necessary definitions.
+... using LSB2MSB bit order for your i386 cpu
+... using big-endian byte order for your i386 cpu
+... configure use of mmap for memory-mapped files
+... O_RDONLY is in &lt;fcntl.h&gt;
+... using double for promoted floating point parameters
+... enabling use of inline functions
+Done creating libtiff/port.h.
+</tt>
+</pre></div>
+This file can take a long time to create so configure generates the
+file only when it is needed, either because the file does not exist
+or because a different target or compiler is to be used. Note that
+running "<tt>make distclean</tt>" in the top-level directory of the
+build tree will remove the <b>port.h</b> file (along with all the
+other files generated by configure).
+<p><i>Selecting emulated library functions.</i> Certain library
+functions used by the tools are not present on all systems and can
+be emulated using other system functionality. configure checks for
+the presence of such functions and if they are missing, will
+configure emulation code from the <b>port</b> directory to use
+instead. Building the TIFF software on unsupported systems may
+require adding to the code to the <b>port</b> directory.</p>
+<div style="margin-left: 2em">
+<pre>
+<tt>
+Checking system libraries for functionality to emulate.
+Done checking system libraries.
+</tt>
+</pre></div>
+If a routine must be emulated and configure does not automatically
+check for it, the routine name can be specified using the
+<tt>PORTFUNCS</tt> parameter. To add emulation support for a new
+function <tt>foo</tt>, create a file <b>port/foo.c</b> that
+contains the emulation code and then set <tt>PORTFUNCS=foo</tt> in
+a configuration file or modify the configure script to
+automatically check for the missing function.
+<div style="margin-left: 2em">
+<pre>
+<tt>
+Checking for Dynamic Shared Object (DSO) support.
+Done checking for DSO support.
+</tt>
+</pre></div>
+If the <tt>DSO</tt> package is enabled (<tt>DSO=auto</tt> or
+<tt>DSO=yes</tt>), then configure will verify the system and
+compiler are capable of constructing SVR4-style DSO's in the
+expected way. Note that while a system may support DSO's the
+compiler may not be capable of generating the required
+position-independent code and/or the compiler may not pass the
+needed options through to the loader.
+<p><i>Selecting utility programs.</i> configure locates various
+system utility programs that are used during installation of the
+software.</p>
+<div style="margin-left: 2em">
+<pre>
+<tt>
+Selecting programs used during installation.
+Looks like mv supports the -f option to force a move.
+Looks like /bin/ln supports the -s option to create a symbolic link.
+Done selecting programs.
+</tt>
+</pre></div>
+<p><i>Selecting default configuration parameters.</i> The remainder
+of the work done by configure involves setting up configuration
+parameters that control the placement and setup of files during the
+installation procedure.</p>
+<div style="margin-left: 2em">
+<pre>
+<tt>
+Selecting default TIFF configuration parameters.
+
+Looks like manual pages go in /usr/contrib/man.
+Looks like manual pages should be installed with bsd-nroff-gzip-0.gz.
+
+TIFF configuration parameters are:
+
+[ 1] Directory for tools: /usr/contrib/bin
+[ 2] Directory for libraries: /usr/contrib/lib
+[ 3] Directory for include files: /usr/contrib/include
+[ 4] Directory for manual pages: /usr/contrib/man
+[ 5] Manual page installation scheme: bsd-nroff-gzip-0.gz
+
+Are these ok [yes]?
+</tt>
+</pre></div>
+At this point you can interactively modify any of the displayed
+parameters. Hitting a carriage return or typing <tt>yes</tt> will
+accept the current parameters. Typing one of the number displayed
+along the left hand side causes configure to prompt for a new value
+of the specified parameter. Typing anything else causes configure
+to prompt for a new value <em>for each parameter</em>. In general
+hitting carriage return will accept the current value and typing
+anything that is unacceptable will cause a help message to be
+displayed. A description of each of the configuration parameters is
+given below.
+<p>Once acceptable parameters are setup configure will generate all
+the files that depend on these parameters. Note that certain files
+may or may not be created based on the configuration of optional
+packages and/or the functions supported by target system.</p>
+<div style="margin-left: 2em">
+<pre>
+<tt>
+Creating Makefile from ../tiff-v3.4beta015/Makefile.in
+Creating libtiff/Makefile from ../tiff-v3.4beta015/libtiff/Makefile.in
+Creating man/Makefile from ../tiff-v3.4beta015/man/Makefile.in
+Creating tools/Makefile from ../tiff-v3.4beta015/tools/Makefile.in
+Creating port/install.sh from ../tiff-v3.4beta015/port/install.sh.in
+Done.
+</tt>
+</pre></div>
+<a name="DSOSupport" id="DSOSupport"></a>
+<hr>
+<h3>Shared Library Support</h3>
+It is desirable to make the TIFF library be a shared object on
+systems that have support for shared libraries. Unfortunately the
+rules to use to build a shared library vary between operating
+systems and even compilers. The distributed software includes
+support for building a shared version of the library on a number of
+different systems. This support is split between rules in the file
+<b>libtiff/Makefile.in</b> that construct the shared library and
+checks done by the <tt>configure</tt> script to verify that the
+expected rules are supported by compilation tools for the target
+system.
+<p>To add new support for building a shared library both these
+files must be updated. In the configure script search for the
+section where the autoconfiguration setting of the <tt>DSO</tt>
+parameter is handled and add a new case for the target system that
+sets the <tt>DSOSUF</tt>, <tt>DSOLD</tt>, <tt>DSOOPTS</tt>, and
+<tt>LIBCOPTS</tt> options as appropriate for the system.
+<tt>DSOSUF</tt> specifies the filename suffix used for the shared
+library (e.g. ``.so'' for Dynamic Shared Objects on most SVR4-based
+systems). <tt>DSOLD</tt> specifies the program to use to build the
+shared library from a compiled object file; typically ``${LD}''
+though on some systems it is better to use the C compiler directly
+so system-dependent options and libraries are automatically
+supplied. <tt>DSOOPTS</tt> are options that must be specified to
+<tt>DSOLD</tt> when building the shared library. <tt>LIBCOPTS</tt>
+are options to pass to the C compiler when constructing a
+relocatable object file to include in a shared library; e.g. ``-K
+PIC'' on a Sun system. The <tt>DSO</tt> parameter must also be set
+to a unique label that identifies the target system and compilation
+tools. This label is used to select a target in
+<b>libtiff/Makefile.in</b> to do the actual work in building the
+shared library. Finally, to complete support for the shared library
+added the appropriate rules to <b>libtiff/Makefile.in</b> under the
+target specified in the <tt>configure</tt> script. <a name="PC" id=
+"PC"></a></p>
+<hr>
+<h2>Building the Software under Windows 95/98/NT/2000 with MS
+VC++</h2>
+With Microsoft Visual C++ installed, and properly configured for
+commandline use (you will likely need to source VCVARS32.BAT in
+AUTOEXEC.bAT or somewhere similar) you should be able to use the
+provided <tt>makefile.vc</tt>.
+<p>The source package is delivered using Unix line termination
+conventions, which work with MSVC but do not work with Windows
+'notepad'. If you use unzip from the <a href=
+"http://www.info-zip.org/pub/infozip/">Info-Zip</a> package, you
+can extract the files using Windows normal line termination
+conventions with a command similar to:</p>
+<pre>
+ unzip -aa -a tiff-3.7.4.zip
+</pre>
+<p>By default libtiff expects that a pre-built zlib and jpeg
+library are provided by the user. If this is not the case, then you
+may edit libtiff\tiffconf.h using a text editor (e.g. notepad) and
+comment out the entries for JPEG_SUPPORT, PIXARLOG_SUPPORT, and
+ZIP_SUPPORT. Ignore the comment at the top of the file which says
+that it has no influence on the build, because the statement is not
+true for Windows. However, by taking this approach, libtiff will
+not be able to open some TIFF files.</p>
+<p>To build using the provided makefile.vc you may use:</p>
+<pre>
+ C:\tiff-3.7.4&gt; nmake /f makefile.vc clean
+ C:\tiff-3.7.4&gt; nmake /f makefile.vc
+
+ or (the hard way)
+
+ C:\tiff-3.7.4&gt; cd port
+ C:\tiff-3.7.4\port&gt; nmake /f makefile.vc clean
+ C:\tiff-3.7.4\port&gt; nmake /f makefile.vc
+ C:\tiff-3.7.4&gt; cd ../libtiff
+ C:\tiff-3.7.4\libtiff&gt; nmake /f makefile.vc clean
+ C:\tiff-3.7.4\libtiff&gt; nmake /f makefile.vc
+ C:\tiff-3.7.4\libtiff&gt; cd ..\tools
+ C:\tiff-3.7.4\tools&gt; nmake /f makefile.vc clean
+ C:\tiff-3.7.4\tools&gt; nmake /f makefile.vc
+</pre>
+<p>This will build the library file
+<tt>libtiff\libtiff\libtiff.lib</tt>. This can be used in Win32
+programs. You may want to adjust the build options before start
+compiling. All parameters contained in the <tt>nmake.opt</tt>
+file.This is a plain text file you can open with your favorite text
+editor.</p>
+<p>The makefile also builds a DLL (libtiff.dll) with an associated
+import library (libtiff_i.lib). Any builds using libtiff will need
+to include the LIBTIFF\LIBTIFF directory in the include path.</p>
+<p>The <tt>libtiff\tools\makefile.vc</tt> should build .exe's for
+all the standard TIFF tool programs.</p>
+<p><a name="DJGPP" id="DJGPP"></a></p>
+<hr>
+<h2>Building the Software under MS/DOS with the DJGPP v2
+compiler</h2>
+[<i>From the file <b>contrib/dosdjgpp/README</b>.</i>]
+<p>The directory <b>contrib/dosdjgpp</b> contains the files
+necessary to build the library and tools with the DJGPP v2 compiler
+under MSDOS.</p>
+<p>All you have to do is copy the files in the directory into the
+respective directories and run make. If you want, you can use the
+<b>conf.bat</b> script to do that for you, make sure that the file
+is stored with MSDOS text EOL-convention (CR/LF), otherwise the
+<b>command.com</b> will not do anything.</p>
+<p>Note that you probably will not be able to build the library
+with the v1.x versions of djgpp, due to two problems. First, the
+top makefile calls a sub-make for each directory and you are likely
+to run out of memory, since each recursive invocation of a djgpp
+v1.x program requires about 130k, to avoid that, you can enter the
+directories manually and call make (well, there are only two dirs).
+The 2nd problem is that djgpp 1.x doesn't call the coff2exe
+(stubify) program when creating an executable. This means that all
+programs compiled are not converted to exe and consequently are not
+available for calling directly. For the tools directory, you can
+just call coff2exe for each program after make finishes, but in the
+libtiff directory, a few programs are created during the make
+process that have to be called for make to continue (e.g.
+mkg3states). Make will probably report an error at each such stage.
+To fix that, either add a coff2exe call before each program is
+called or call coff2exe manually and rerun make (there 2-3 such
+programs). <a name="MacMPW" id="MacMPW"></a></p>
+<hr>
+<h2>Building the Software on a Macintosh with MPW</h2>
+The directory <b>contrib/mac-mpw</b> contains support for compiling
+the library and tools under the MPW Shell on a Macintosh system.
+This support was contributed by Niles Ritter (<a href=
+"mailto:ndr@tazboy.jpl.nasa.gov">ndr@tazboy.jpl.nasa.gov</a>).
+<p>[<i>From the file <b>contrib/mac-mpw/README</b>.</i>]</p>
+<p>This directory contains all of the utilities and makefile source
+to build the LIBTIFF library and tools from the MPW Shell. The file
+BUILD.mpw in this directory is an executable script which uses all
+of these files to create the MPW makefiles and run them.</p>
+<p>The &lt;file&gt;.make files are not MPW makefiles as such, but
+are when run through the "mactrans" program, which turns the ascii
+"%nn" metacharacters into the standard weird MPW make
+characters.</p>
+<p>This translation trick is necessary to protect the files when
+they are put into unix tarfiles, which tend to mangle the special
+characters. <a name="MacCW" id="MacCW"></a></p>
+<hr>
+<h2>Building the Software on a Macintosh with CodeWarrior</h2>
+The directory <b>contrib/mac-cw</b> contains support for compiling
+the library and tools with MetroWerks CodeWarrior 6.1 on a
+Macintosh system. This support was contributed by Niles Ritter
+(<a href=
+"mailto:ndr@tazboy.jpl.nasa.gov">ndr@tazboy.jpl.nasa.gov</a>).
+<p>[<i>From the file <b>contrib/mac-cw/README</b>.</i>] In this
+directory you will find a Makefile.script Applescript file, which
+should be run in order to build the libtiff code using MetroWerks
+CodeWarrior. Refer to the "metrowerks.note" instructions on
+building the library for 68k and PowerPC native code, as well as
+building some of the libtiff tools, which are rather unix-like, but
+at least give an example of how to link everything together.
+<a name="VMS" id="VMS"></a></p>
+<hr>
+<h2>Building the Software on a VMS System</h2>
+The VMS port was done by Karsten Spang (<a href=
+"mailto:krs@kampsax.dk">krs@kampsax.dk</a>), who also "sort of"
+maintains it. The VMS specific files are not in the main
+directories. Instead they are placed under
+<tt>[.CONTRIB.VMS...]</tt> in the distribution tree. Installation:
+It is assumed that you have unpacked the tar file into a VMS
+directory tree, in this text called DISK:[TIFF].
+<ol>
+<li>Move the VMS specific files to their proper directories.
+<pre>
+$ SET DEFAULT DISK:[TIFF.CONTRIB.VMS]
+$ RENAME [.LIBTIFF]*.* [-.-.LIBTIFF]
+$ RENAME [.TOOLS]*.* [-.-.TOOLS]
+</pre></li>
+<li>Compile the library.
+<pre>
+$ SET DEFAULT DISK:[TIFF.LIBTIFF]
+$ @MAKEVMS
+</pre></li>
+<li>Compile the tools.
+<pre>
+$ SET DEFAULT DISK:[TIFF.TOOLS]
+$ @MAKEVMS
+</pre></li>
+<li>Define the programs.
+<pre>
+$ DEFINE TIFFSHR DISK:[TIFF.LIBTIFF]TIFFSHR
+$ FAX2PS :==$DISK:[TIFF.TOOLS]FAX2PS
+$ FAX2TIFF :==$DISK:[TIFF.TOOLS]FAX2TIFF
+$ GIF2TIFF :==$DISK:[TIFF.TOOLS]GIF2TIFF
+$ PAL2RGB :==$DISK:[TIFF.TOOLS]PAL2RGB
+$ PPM2TIFF :==$DISK:[TIFF.TOOLS]PPM2TIFF
+$ RAS2TIFF :==$DISK:[TIFF.TOOLS]RAS2TIFF
+$ RGB2YCBCR :==$DISK:[TIFF.TOOLS]RGB2YCBCR
+$ THUMBNAIL :==$DISK:[TIFF.TOOLS]THUMBNAIL
+$ TIFF2BW :==$DISK:[TIFF.TOOLS]TIFF2BW
+$ TIFF2PS :==$DISK:[TIFF.TOOLS]TIFF2PS
+$ TIFFCMP :==$DISK:[TIFF.TOOLS]TIFFCMP
+$ TIFFCP :==$DISK:[TIFF.TOOLS]TIFFCP
+$ TIFFDITHER:==$DISK:[TIFF.TOOLS]TIFFDITHER
+$ TIFFDUMP :==$DISK:[TIFF.TOOLS]TIFFDUMP
+$ TIFFINFO :==$DISK:[TIFF.TOOLS]TIFFINFO
+$ TIFFMEDIAN:==$DISK:[TIFF.TOOLS]TIFFMEDIAN
+$ TIFFSPLIT :==$DISK:[TIFF.TOOLS]TIFFSPLIT
+$ YCBCR :==$DISK:[TIFF.TOOLS]YCBCR
+</pre></li>
+</ol>
+You will want to add these lines to your <tt>LOGIN.COM</tt> file,
+after changing the name of the directory that you have used on your
+machine.
+<p>This release has been tested on OpenVMS/VAX 5.5-2, using VAX C
+3.2. A previous release was tested under OpenVMS/AXP ?.? using DEC
+C ?.?, it is believed that this release as well works on AXP. The
+code contains some GNU C specific things. This does *not* imply,
+however, that the VAX/GCC configuration has been tested, *it has
+not*.</p>
+<p>The command procedures (<tt>MAKEVMS.COM</tt>) for building the
+library and tools, is believed to choose the correct options for
+the VAX and AXP cases automatically.</p>
+<p>On the AXP, IEEE floating point is used by default. If you want
+VAX floating point, remove the <tt>/FLOAT=IEEE_FLOAT</tt>
+qualifier, and change <tt>HAVE_IEEEFP=1</tt> to
+<tt>HAVE_IEEEFP=0</tt> in the <tt>MAKEVMS.COM</tt> files in both
+the <b>libtiff</b> and <b>tools</b> directories.</p>
+<h3>Compiling your own program on a VMS system:</h3>
+When compiling a source file in which you <tt>"#include
+&lt;tiffio.h&gt;"</tt>, use the following command
+<pre>
+ $ CC/INCLUDE=DISK:[TIFF.LIBTIFF]
+</pre>
+This ensures that the header file is found. On the AXP, also add
+<tt>/FLOAT=IEEE_FLOAT</tt> (if used when building the library).
+<h3>Linking your own program to the TIFF library on a VMS
+system:</h3>
+You can link to the library in two ways: Either using the shareable
+library, or using the object library. On the VAX these
+possibilities are:
+<ol>
+<li>Using the shareable TIFF library.
+<pre>
+$ LINK MY_PROGRAM,DISK:[TIFF.LIBTIFF]TIFF/OPTIONS,SYS$INPUT:/OPTIONS
+ SYS$SHARE:VAXCRTL/SHAREABLE
+</pre></li>
+<li>Using the TIFF object library.
+<pre>
+$ LINK MY_PROGRAM, -
+ DISK:[TIFF.LIBTIFF]TIFF/LIBRARY/INCLUDE=(TIF_FAX3SM,TIF_CODEC), -
+ SYS$INPUT:/OPTIONS
+ SYS$SHARE:VAXCRTL/SHAREABLE
+</pre></li>
+</ol>
+On AXP (and possibly also using DEC C on VAX) the corresponding
+commands are
+<ol>
+<li>Using the shareable TIFF library.
+<pre>
+$ LINK MY_PROGRAM,DISK:[TIFF.LIBTIFF]TIFF/OPTIONS
+</pre></li>
+<li>Using the TIFF object library.
+<pre>
+$ LINK MY_PROGRAM,DISK:[TIFF.LIBTIFF]TIFF/LIBRARY
+</pre></li>
+</ol>
+Method 1 uses the shortest link time and smallest <tt>.EXE</tt>
+files, but it requires that <tt>TIFFSHR</tt> is defined as above at
+link time and <strong>at run time</strong>. Using the compilation
+procedure above, the tools are linked in this way.
+<p>Method 2 gives somewhat longer link time and larger
+<tt>.EXE</tt> files, but does not require <tt>TIFFSHR</tt> to be
+defined. This method is recommended if you want to run your program
+on another machine, and for some reason don't want to have the
+library on that machine. If you plan to have more than one program
+(including the tools) on the machine, it is recommended that you
+copy the library to the other machine and use method 1. <a name=
+"Acorn" id="Acorn"></a></p>
+<hr>
+<h2>Building the Software on an Acorn RISC OS system</h2>
+The directory <b>contrib/acorn</b> contains support for compiling
+the library under Acorn C/C++ under Acorn's RISC OS 3.10 or above.
+Subsequent pathnames will use the Acorn format: The full-stop or
+period character is a pathname delimeter, and the slash character
+is not interpreted; the reverse position from Unix. Thus
+"libtiff/tif_acorn.c" becomes "libtiff.tif_acorn/c".
+<p>This support was contributed by Peter Greenham. (<a href=
+"mailto:peter@enlarion.demon.co.uk">peter@enlarion.demon.co.uk</a>).</p>
+<h3>Installing LibTIFF:</h3>
+<p>LIBTIFF uses several files which have names longer than the
+normal RISC OS maximum of ten characters. This complicates matters.
+Maybe one day Acorn will address the problem and implement long
+filenames properly. Until then this gets messy, especially as I'm
+trying to do this with obeyfiles and not have to include binaries
+in this distribution.</p>
+<p>First of all, ensure you have Truncate configured on (type
+<tt>*Configure Truncate On</tt>)</p>
+<p>Although it is, of course, preferable to have long filenames,
+LIBTIFF can be installed with short filenames, and it will compile
+and link without problems. However, <i>getting</i> it there is more
+problematic. <b>contrib.acorn.install</b> is an installation
+obeyfile which will create a normal Acorn-style library from the
+source (ie: with c, h and o folders etc.), but needs the
+distribution library to have been unpacked into a location which is
+capable of supporting long filenames, even if only temporarily.</p>
+<p>My recommendation, until Acorn address this problem properly, is
+to use Jason Tribbeck's <a href=
+"ftp://ftp.demon.co.uk/pub/mirrors/hensa/micros/arch/riscos/c/c020/longfiles.arc">
+LongFilenames</a>, or any other working system that gives you long
+filenames, like a nearby NFS server for instance.</p>
+<p>If you are using Longfilenames, even if only temporarily to
+install LIBTIFF, unpack the TAR into a RAMDisc which has been
+longfilenamed (ie: <tt>*addlongfs ram</tt>) and then install from
+there to the hard disk. Unfortunately Longfilenames seems a bit
+unhappy about copying a bunch of long-named files across the same
+filing system, but is happy going between systems. You'll need to
+create a ramdisk of about 2Mb.</p>
+<p>Now you can run the installation script I've supplied (in
+contrib.acorn), which will automate the process of installing
+LIBTIFF as an Acorn-style library. The syntax is as follows:</p>
+<p><tt>install &lt;source_dir&gt; &lt;dest_dir&gt;</tt></p>
+<p>Install will then create &lt;dest_dir&gt; and put the library in
+there. For example, having used LongFilenames on the RAMDisk and
+unpacked the library into there, you can then type:</p>
+<p><tt>Obey RAM::RamDisc0.$.contrib.acorn.install RAM::RamDisc0.$
+ADFS::4.$.LIBTIFF</tt></p>
+<p>It doesn't matter if the destination location can cope with long
+filenames or not. The filenames will be truncated if necessary
+(*Configure Truncate On if you get errors) and all will be
+well.</p>
+<h3>Compiling LibTIFF:</h3>
+<p>Once the LibTIFF folder has been created and the files put
+inside, making the library should be just a matter of running
+'<b>SetVars</b>' to set the appropriate system variables, then
+running '<b>Makefile</b>'.</p>
+<p><b>OSLib</b></p>
+<p><a href=
+"ftp://ftp.acorn.co.uk/pub/riscos/releases/oslib/oslib.arc">OSLib</a>
+is a comprehensive API for RISC OS machines, written by Jonathan
+Coxhead of Acorn Computers (although OSLib is not an official Acorn
+product). Using the OSLib SWI veneers produces code which is more
+compact and more efficient than code written using _kernel_swi or
+_swi. The Acorn port of LibTIFF can take advantage of this if
+present. Edit the Makefile and go to the Static dependencies
+section. The first entry is:</p>
+<pre>
+# Static dependencies:
+@.o.tif_acorn: @.c.tif_acorn
+ cc $(ccflags) -o @.o.tif_acorn @.c.tif_acorn
+</pre>
+<p>Change the cc line to:</p>
+<pre>
+ cc $(ccflags) -DINCLUDE_OSLIB -o @.o.tif_acorn @.c.tif_acorn
+</pre>
+<p>Remember, however, that OSLib is only <i>recommended</i> for
+efficiency's sake. It is not required. <a name="Other" id=
+"Other"></a></p>
+<hr>
+<h2>Building the Software on Other Systems</h2>
+This section contains information that might be useful if you are
+working on a non-UNIX system that is not directly supported. All
+library-related files described below are located in the
+<b>libtiff</b> directory.
+<p>The library requires two files that are generated
+<i>on-the-fly</i>. The file <b>tif_fax3sm.c</b> has the state
+tables for the Group 3 and Group 4 decoders. This file is generated
+by the <tt>mkg3states</tt> program on a UNIX system; for
+example,</p>
+<div style="margin-left: 2em">
+<pre>
+<tt>
+cd libtiff
+cc -o mkg3states mkg3states.c
+rm -f tif_fax3sm.c
+./mkg3states -c const tif_fax3sm.c
+</tt>
+</pre></div>
+The <tt>-c</tt> option can be used to control whether or not the
+resutling tables are generated with a <tt>const</tt> declaration.
+The <tt>-s</tt> option can be used to specify a C storage class for
+the table declarations. The <tt>-b</tt> option can be used to force
+data values to be explicitly bracketed with ``{}'' (apparently
+needed for some MS-Windows compilers); otherwise the structures are
+emitted in as compact a format as possible. Consult the source code
+for this program if you have questions.
+<p>The second file required to build the library, <b>version.h</b>,
+contains the version information returned by the
+<tt>TIFFGetVersion</tt> routine. This file is built on most systems
+using the <tt>mkversion</tt> program and the contents of the
+<tt>VERSION</tt> and <tt>tiff.alpha</tt> files; for example,</p>
+<div style="margin-left: 2em">
+<pre>
+cd libtiff
+cc -o mkversion mkversion.c
+rm -f version.h
+./mkversion -v ../VERSION -a ../dist/tiff.alpha version.h
+</pre></div>
+<p>Otherwise, when building the library on a non-UNIX system be
+sure to consult the files <b>tiffcomp.h</b> and <b>tiffconf.h</b>.
+The former contains system compatibility definitions while the
+latter is provided so that the software configuration can be
+controlled on systems that do not support the make facility for
+building the software.</p>
+<p>Systems without a 32-bit compiler may not be able to handle some
+of the codecs in the library; especially the Group 3 and 4 decoder.
+If you encounter problems try disabling support for a particular
+codec; consult the <a href=
+"internals.html#Config">documentation</a>.</p>
+<p>Programs in the tools directory are written to assume an ANSI C
+compilation environment. There may be a few POSIX'isms as well. The
+code in the <b>port</b> directory is provided to emulate routines
+that may be missing on some systems. On UNIX systems the
+<tt>configure</tt> script automatically figures out which routines
+are not present on a system and enables the use of the equivalent
+emulation routines from the <b>port</b> directory. It may be
+necessary to manually do this work on a non-UNIX system. <a name=
+"Testing" id="Testing"></a></p>
+<hr>
+<h2>Checking out the Software</h2>
+<p>Assuming you have working versions of <tt>tiffgt</tt> and
+<tt>tiffsv</tt>, you can just use them to view any of the sample
+images available for testing (see the <a href="images.html">section
+on obtaining the test images</a>). Otherwise, you can do a cursory
+check of the library with the <tt>tiffcp</tt> and <tt>tiffcmp</tt>
+programs. For example,</p>
+<div style="margin-left: 2em">
+<pre>
+tiffcp -lzw cramps.tif x.tif
+tiffcmp cramps.tif x.tif
+</pre></div>
+<p>(<tt>tiffcmp</tt> should be silent if the files compare
+correctly). <a name="TOC" id="TOC"></a></p>
+<hr>
+<h2>Table of Contents</h2>
+The following files makup the core library:
+<pre>
+libtiff/tiff.h TIFF spec definitions
+libtiff/tiffcomp.h non-UNIX OS-compatibility definitions
+libtiff/tiffconf.h non-UNIX configuration definitions
+libtiff/tiffio.h public TIFF library definitions
+libtiff/tiffiop.h private TIFF library definitions
+libtiff/t4.h CCITT Group 3/4 code tables+definitions
+libtiff/tif_dir.h private defs for TIFF directory handling
+libtiff/tif_fax3.h CCITT Group 3/4-related definitions
+libtiff/tif_predict.h private defs for Predictor tag support
+libtiff/uvcode.h LogL/LogLuv codec-specific definitions
+libtiff/version.h version string (generated by Makefile)
+
+libtiff/tif_acorn.c Acorn-related OS support
+libtiff/tif_apple.c Apple-related OS support
+libtiff/tif_atari.c Atari-related OS support
+libtiff/tif_aux.c auxilary directory-related functions
+libtiff/tif_close.c close an open TIFF file
+libtiff/tif_codec.c configuration table of builtin codecs
+libtiff/tif_compress.c compression scheme support
+libtiff/tif_dir.c directory tag interface code
+libtiff/tif_dirinfo.c directory known tag support code
+libtiff/tif_dirread.c directory reading code
+libtiff/tif_dirwrite.c directory writing code
+libtiff/tif_dumpmode.c "no" compression codec
+libtiff/tif_error.c library error handler
+libtiff/tif_fax3.c CCITT Group 3 and 4 codec
+libtiff/tif_fax3sm.c G3/G4 state tables (generated by mkg3states)
+libtiff/tif_flush.c i/o and directory state flushing
+libtiff/tif_getimage.c TIFFRGBAImage support
+libtiff/tif_jpeg.c JPEG codec (interface to the IJG distribution)
+libtiff/tif_luv.c SGI LogL/LogLuv codec
+libtiff/tif_lzw.c LZW codec
+libtiff/tif_msdos.c MSDOS-related OS support
+libtiff/tif_next.c NeXT 2-bit scheme codec (decoding only)
+libtiff/tif_open.c open and simply query code
+libtiff/tif_packbits.c Packbits codec
+libtiff/tif_pixarlog.c Pixar codec
+libtiff/tif_predict.c Predictor tag support
+libtiff/tif_print.c directory printing support
+libtiff/tif_read.c image data reading support
+libtiff/tif_strip.c some strip-related code
+libtiff/tif_swab.c byte and bit swapping support
+libtiff/tif_thunder.c Thunderscan codec (decoding only)
+libtiff/tif_tile.c some tile-related code
+libtiff/tif_unix.c UNIX-related OS support
+libtiff/tif_version.c library version support
+libtiff/tif_vms.c VMS-related OS support
+libtiff/tif_warning.c library warning handler
+libtiff/tif_win3.c Windows-3.1-related OS support
+libtiff/tif_win32.c Win32 (95/98/NT) related OS support
+libtiff/tif_write.c image data writing support
+libtiff/tif_zip.c Deflate codec
+
+libtiff/mkg3states.c program to generate G3/G4 decoder state tables
+libtiff/mkspans.c program to generate black-white span tables
+libtiff/mkversion.c program to generate libtiff/version.h.
+</pre>
+<hr>
+Last updated: $Date: 2005/12/24 22:25:05 $
+</body>
+</html>
diff --git a/tiff/html/contrib.html b/tiff/html/contrib.html
new file mode 100644
index 0000000..d138900
--- /dev/null
+++ b/tiff/html/contrib.html
@@ -0,0 +1,209 @@
+<HTML>
+<HEAD>
+<TITLE>
+Contributed TIFF Software
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<H1>
+<IMG SRC=images/smallliz.jpg WIDTH=144 HEIGHT=108 ALIGN=left BORDER=1 HSPACE=6>
+Contributed TIFF Software
+</H1>
+
+
+<P>
+The <B>contrib</B> directory has contributed software that
+uses the TIFF library or which is associated with the library
+(typically glue and guidance for ports to non-UNIX platforms, or tools that
+aren't directly TIFF related).
+
+<BR CLEAR=left>
+
+<P>
+<TABLE BORDER CELLPADDING=3>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/vms</B>
+</TD>
+<TD>
+scripts and files from Karsten Spang for building
+ the library and tools under VMS
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/dbs</B>
+</TD>
+<TD>
+various tools from Dan & Chris Sears, including a simple X-based viewer
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/ras</B>
+</TD>
+<TD>
+two programs by Patrick Naughton for converting
+ between Sun rasterfile format and TIFF (these
+ require <TT>libpixrect.a</TT>, as opposed to the one in
+ tools that doesn't)
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/mac-mpw</B><br>
+<B>contrib/mac-cw</B>
+</TD>
+<TD>
+scripts and files from Niles Ritter for building
+the library and tools under Macintosh/MPW C and
+code warrior.
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/acorn</B>
+</TD>
+<TD>
+scripts and files from Peter Greenham for building
+ the library and tools on an Acorn RISC OS system.
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/win32</B>
+</TD>
+<TD>
+scripts and files from Scott Wagner for building
+the library under Windows NT and Windows 95. (The makefile.vc in the
+libtiff/libtiff directory may be sufficient for most users.)
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/win_dib</B>
+</TD>
+<TD>
+two separate implementations of TIFF to DIB code suitable for any Win32
+platform. Contributed by Mark James, and Philippe Tenenhaus.
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/ojpeg</B>
+</TD>
+<TD>
+Patch for IJG JPEG library related to support for some Old JPEG in TIFF files.
+Contributed by Scott Marovich.
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/dosdjgpp</B>
+</TD>
+<TD>
+scripts and files from Alexander Lehmann for building
+ the library under MSDOS with the DJGPP v2 compiler.
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/tags</B>
+</TD>
+<TD>
+scripts and files from Niles Ritter for adding private
+ tag support at runtime, without changing libtiff.
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/mfs</B>
+</TD>
+<TD>
+code from Mike Johnson to read+write images in memory
+without modifying the library
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/pds</B>
+</TD>
+<TD>
+various routines from Conrad Poelman; a TIFF image iterator and
+ code to support ``private sub-directories''
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/iptcutil</B>
+</TD>
+
+<TD>
+
+A utility by <A HREF=mailto:billr@corbis.com>Bill Radcliffe</a> to
+convert an extracted IPTC Newsphoto caption from a binary blob to
+ASCII text, and vice versa. IPTC binary blobs can be extracted from
+images via the <A
+HREF=http://www.ImageMagick.org/>ImageMagick</a> convert(1)
+utility.
+
+
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/addtiffo</B>
+</TD>
+
+<TD>
+
+A utility (and supporting subroutine) for building
+one or more reduce resolution
+overviews to an existing TIFF file. Supplied by
+<a href="http://pobox.com/~warmerdam">Frank Warmerdam</a>.
+
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top>
+<B>contrib/stream</B>
+</TD>
+
+<TD>
+
+A class (TiffStream) for accessing TIFF files through a C++ stream
+interface. Supplied by <a href="mailto:avi@shutterfly.com">Avi Bleiweiss</a>.
+
+</TD>
+</TR>
+
+</TABLE>
+
+<P>
+Questions regarding these packages are usually best directed toward
+their authors.
+
+<P>
+<HR>
+
+Last updated: $Date: 2006/01/03 01:42:30 $
+
+</BODY>
+</HTML>
diff --git a/tiff/html/document.html b/tiff/html/document.html
new file mode 100644
index 0000000..12f138f
--- /dev/null
+++ b/tiff/html/document.html
@@ -0,0 +1,48 @@
+<HTML>
+<HEAD>
+<TITLE>
+TIFF Documentation
+</TITLE>
+</HEAD>
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<H1>
+<IMG SRC=images/jim.gif WIDTH=139 HEIGHT=170 ALIGN=left BORDER=1 HSPACE=6>
+TIFF Documentation
+</H1>
+
+<P>
+A copy of the 6.0 specification is available from Adobe at
+<A HREF="http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf">http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf</A>, or from the libtiff
+ftp site at <a href="ftp://ftp.remotesensing.org/pub/libtiff/doc/TIFF6.pdf">
+ftp://ftp.remotesensing.org/pub/libtiff/doc/TIFF6.pdf</A>.<p>
+
+<P>
+Draft <a href="TIFFTechNote2.html">TIFF Technical Note #2</A> covers problems
+with the TIFF 6.0 design for embedding JPEG-compressed data in TIFF, and
+describes an alternative. <p>
+
+Other Adobe information on TIFF can be retrieved from:
+
+<A HREF="http://partners.adobe.com/public/developer/tiff/index.html">
+http://partners.adobe.com/public/developer/tiff/index.html</A>
+
+<P>
+Joris Van Damme maintains a list of known tags and their descriptions and
+definitions. It is available online at
+<A HREF="http://www.awaresystems.be/imaging/tiff/tifftags.html">
+http://www.awaresystems.be/imaging/tiff/tifftags.html</A>
+
+<P>
+There is a FAQ, related both to TIFF format and libtiff library:
+<A HREF="http://www.awaresystems.be/imaging/tiff/faq.html">
+http://www.awaresystems.be/imaging/tiff/faq.html</A>
+
+<HR>
+
+<ADDRESS>
+ Last updated: $Date: 2009-08-20 22:31:00 $
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/images.html b/tiff/html/images.html
new file mode 100644
index 0000000..150ed0c
--- /dev/null
+++ b/tiff/html/images.html
@@ -0,0 +1,41 @@
+<HTML>
+<HEAD>
+<TITLE>
+TIFF Test Images
+</TITLE>
+</HEAD>
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<H1>
+<IMG SRC=images/bali.jpg WIDTH=158 HEIGHT=107 ALIGN=left BORDER=1 HSPACE=6>
+TIFF Test Images
+</H1>
+
+<P>
+Test images are available for most formats supported by the library.
+Most of the images included in the test kit are also part of this
+documentation (albeit in TIFF rather than GIF or JFIF).
+The images are kept in a separate archive that should be located in
+the same directory as this software.
+
+<BR CLEAR=left>
+
+<P>
+The latest archive of test images is located at
+<A HREF="ftp://ftp.remotesensing.org/pub/libtiff/pics-3.8.0.tar.gz">
+ftp://ftp.remotesensing.org/pub/libtiff/pics-3.8.0.tar.gz</A>
+
+<P>
+There are two other good sources for TIFF test images:
+the contributed software <B>contrib/dbs</B> includes several
+programs that generate test images suitable for debugging, and
+the <TT>tiffcp</TT> program can be used to generate a variety
+of images with different storage characteristics.
+
+<P>
+<HR>
+
+Last updated: $Date: 2006/01/02 23:50:44 $
+
+</BODY>
+</HTML>
diff --git a/tiff/html/images/Makefile.am b/tiff/html/images/Makefile.am
new file mode 100644
index 0000000..840e149
--- /dev/null
+++ b/tiff/html/images/Makefile.am
@@ -0,0 +1,46 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+docdir = $(LIBTIFF_DOCDIR)/html/images
+
+docfiles = \
+ back.gif \
+ bali.jpg \
+ cat.gif \
+ cover.jpg \
+ cramps.gif \
+ dave.gif \
+ info.gif \
+ jello.jpg \
+ jim.gif \
+ note.gif \
+ oxford.gif \
+ quad.jpg \
+ ring.gif \
+ smallliz.jpg \
+ strike.gif \
+ warning.gif
+
+dist_doc_DATA = $(docfiles)
diff --git a/tiff/html/images/Makefile.in b/tiff/html/images/Makefile.in
new file mode 100644
index 0000000..a397f30
--- /dev/null
+++ b/tiff/html/images/Makefile.in
@@ -0,0 +1,487 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = html/images
+DIST_COMMON = $(dist_doc_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(docdir)"
+DATA = $(dist_doc_DATA)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = $(LIBTIFF_DOCDIR)/html/images
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+docfiles = \
+ back.gif \
+ bali.jpg \
+ cat.gif \
+ cover.jpg \
+ cramps.gif \
+ dave.gif \
+ info.gif \
+ jello.jpg \
+ jim.gif \
+ note.gif \
+ oxford.gif \
+ quad.jpg \
+ ring.gif \
+ smallliz.jpg \
+ strike.gif \
+ warning.gif
+
+dist_doc_DATA = $(docfiles)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign html/images/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign html/images/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)"
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(docdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(docdir)" && rm -f $$files
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ uninstall uninstall-am uninstall-dist_docDATA
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/html/images/back.gif b/tiff/html/images/back.gif
new file mode 100644
index 0000000..11d0c35
--- /dev/null
+++ b/tiff/html/images/back.gif
Binary files differ
diff --git a/tiff/html/images/bali.jpg b/tiff/html/images/bali.jpg
new file mode 100644
index 0000000..1f5c146
--- /dev/null
+++ b/tiff/html/images/bali.jpg
Binary files differ
diff --git a/tiff/html/images/cat.gif b/tiff/html/images/cat.gif
new file mode 100644
index 0000000..5bd3fac
--- /dev/null
+++ b/tiff/html/images/cat.gif
Binary files differ
diff --git a/tiff/html/images/cover.jpg b/tiff/html/images/cover.jpg
new file mode 100644
index 0000000..8698cfb
--- /dev/null
+++ b/tiff/html/images/cover.jpg
Binary files differ
diff --git a/tiff/html/images/cramps.gif b/tiff/html/images/cramps.gif
new file mode 100644
index 0000000..9153f9a
--- /dev/null
+++ b/tiff/html/images/cramps.gif
Binary files differ
diff --git a/tiff/html/images/dave.gif b/tiff/html/images/dave.gif
new file mode 100644
index 0000000..c36d447
--- /dev/null
+++ b/tiff/html/images/dave.gif
Binary files differ
diff --git a/tiff/html/images/info.gif b/tiff/html/images/info.gif
new file mode 100644
index 0000000..783d631
--- /dev/null
+++ b/tiff/html/images/info.gif
Binary files differ
diff --git a/tiff/html/images/jello.jpg b/tiff/html/images/jello.jpg
new file mode 100644
index 0000000..df99e66
--- /dev/null
+++ b/tiff/html/images/jello.jpg
Binary files differ
diff --git a/tiff/html/images/jim.gif b/tiff/html/images/jim.gif
new file mode 100644
index 0000000..9a18a03
--- /dev/null
+++ b/tiff/html/images/jim.gif
Binary files differ
diff --git a/tiff/html/images/note.gif b/tiff/html/images/note.gif
new file mode 100644
index 0000000..7177d68
--- /dev/null
+++ b/tiff/html/images/note.gif
Binary files differ
diff --git a/tiff/html/images/oxford.gif b/tiff/html/images/oxford.gif
new file mode 100644
index 0000000..dd4b86e
--- /dev/null
+++ b/tiff/html/images/oxford.gif
Binary files differ
diff --git a/tiff/html/images/quad.jpg b/tiff/html/images/quad.jpg
new file mode 100644
index 0000000..4b7df17
--- /dev/null
+++ b/tiff/html/images/quad.jpg
Binary files differ
diff --git a/tiff/html/images/ring.gif b/tiff/html/images/ring.gif
new file mode 100644
index 0000000..2a614f4
--- /dev/null
+++ b/tiff/html/images/ring.gif
Binary files differ
diff --git a/tiff/html/images/smallliz.jpg b/tiff/html/images/smallliz.jpg
new file mode 100644
index 0000000..8eb827f
--- /dev/null
+++ b/tiff/html/images/smallliz.jpg
Binary files differ
diff --git a/tiff/html/images/strike.gif b/tiff/html/images/strike.gif
new file mode 100644
index 0000000..0709d19
--- /dev/null
+++ b/tiff/html/images/strike.gif
Binary files differ
diff --git a/tiff/html/images/warning.gif b/tiff/html/images/warning.gif
new file mode 100644
index 0000000..f51eb4b
--- /dev/null
+++ b/tiff/html/images/warning.gif
Binary files differ
diff --git a/tiff/html/index.html b/tiff/html/index.html
new file mode 100644
index 0000000..21f8147
--- /dev/null
+++ b/tiff/html/index.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html lang="en">
+<head>
+ <title>LibTIFF - TIFF Library and Utilities</title>
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+ <meta http-equiv="content-language" content="en">
+ <style type="text/css">
+ <!--
+ th {text-align: left; vertical-align: top; padding-right: 1em; white-space: nowrap}
+ -->
+ </style>
+</head>
+<body lang="en" text="#000000" bgcolor="#ffffff" link="#0000ff" alink="#0000ff" vlink="#0000ff">
+ <h1>LibTIFF - TIFF Library and Utilities</h1>
+ <hr>
+ <table cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <th>Home Page</th>
+ <td><a href="http://www.remotesensing.org/libtiff/" title="Home of the LibTIFF software">http://www.remotesensing.org/libtiff/</a></td>
+ </tr>
+ <tr>
+ <th>Home Page Mirror</th>
+ <td><a href="http://libtiff.maptools.org/" title="Mirror of the LibTIFF software">http://libtiff.maptools.org/</a></td>
+ </tr>
+ <tr>
+ <th>Latest Stable Release</th>
+ <td><a href="v3.9.4.html">v3.9.4</a></td>
+ </tr>
+ <tr>
+ <th>Master Download Site</th>
+ <td><a href="ftp://ftp.remotesensing.org/pub/libtiff">ftp.remotesensing.org</a>, directory pub/libtiff</td>
+ </tr>
+ <tr>
+ <th>Mirror Download Site</th>
+ <td><a href="http://libtiff.maptools.org/dl/">http://libtiff.maptools.org/dl/</a></td>
+ </tr>
+ <tr>
+ <th>Windows Binaries</th>
+ <td><a href="http://gnuwin32.sourceforge.net/packages/libtiff.htm">GnuWin32 Project</a></td>
+ </tr>
+ <tr>
+ <th>Mailing List</th>
+ <td><a href="mailto:tiff@lists.maptools.org">tiff@lists.maptools.org</a>,
+ <a href="http://lists.maptools.org/mailman/listinfo/tiff/">Subscription</a>,
+ <a href="http://www.awaresystems.be/imaging/tiff/tml.html">Archive</a>.
+ Please, read the <a href="http://www.awaresystems.be/imaging/tiff/faq.html">TIFF FAQ</a>
+ before asking questions.</td>
+ </tr>
+ <tr>
+ <th>Anonymous CVS</th>
+ <td><tt>export CVSROOT=:pserver:cvsanon@cvs.maptools.org:/cvs/maptools/cvsroot<br>
+ cvs login</tt><br>
+ (use empty password)<br>
+ <tt>cvs checkout -r branch-3-9 libtiff<br></tt>
+ to get stable libtiff branch, or<br>
+ <tt>cvs checkout libtiff</tt><br>
+ to get bleeding edge development version of libtiff from CVS HEAD.</td>
+ </tr>
+ </table>
+ <hr>
+ <p>
+ This software provides support for the <i>Tag Image File Format</i> (TIFF),
+ a widely used format for storing image data. The latest version of
+ the TIFF specification is <a href="document.html">available on-line</a>
+ in several different formats.
+ </p>
+ <p>
+ Included in this software distribution is a library, libtiff, for reading
+ and writing TIFF, a small collection of tools for doing simple
+ manipulations of TIFF images, and documentation on the
+ library and tools. Libtiff is a portable software, it was built and
+ tested on various systems: UNIX flavors (Linux, BSD, Solaris, MacOS X),
+ Windows, OpenVMS. It should be possible to port libtiff and additional
+ tools on other OSes.
+ </p>
+ <p>
+ The library, along with associated tool programs, should handle most of
+ your needs for reading and writing TIFF images on 32- and 64-bit
+ machines. This software can also be used on older 16-bit systems
+ though it may require some effort and you may need to leave out some of
+ the compression support.
+ </p>
+ <p>
+ The software was originally authored and maintained by Sam Leffler.
+ While he keeps a fatherly eye on the mailing list, he is no longer
+ responsible for day to day maintenance.
+ </p>
+ <p>
+ Questions should be sent to the TIFF mailing list:
+ <a href="mailto:tiff@lists.maptools.org">tiff@lists.maptools.org</a>, with
+ a subscription interface at
+ <a href="http://lists.maptools.org/mailman/listinfo/tiff">http://lists.maptools.org/mailman/listinfo/tiff</a>.
+ </p>
+ <p>
+ The persons responsible for putting up this site and putting together
+ versions &gt;= 3.5.1 are
+ <a href="http://pobox.com/~warmerdam">Frank Warmerdam</a>,
+ <a href="mailto:dron@ak4719.spb.edu">Andrey Kiselev</a>, Bob Friesenhahn,
+Joris Van Damme and Lee Howard.
+ </p>
+ <p>
+ The following sections are included in this documentation:
+ </p>
+ <ul>
+ <li><a href="support.html">TIFF 6.0 specification coverage</a></li>
+ <li><a href="libtiff.html">Using the TIFF Library</a></li>
+ <li><a href="internals.html">Modifying the TIFF Library</a>
+ and <a href="addingtags.html">Adding New Tags</a></li>
+ <li><a href="tools.html">TIFF tools overview</a></li>
+ <li><a href="contrib.html">Contributed software</a></li>
+ <li><a href="document.html">TIFF documentation</a></li>
+ <li><a href="build.html">Building the software distribution</a></li>
+ <li><a href="bugs.html">Bugs, Bugzilla, and the TIFF mailing list</a></li>
+ <li><a href="images.html">Test images</a></li>
+ <li><a href="misc.html">Acknowledgements and copyright issues</a></li>
+ <li><a href="man/index.html">Man Pages</a></li>
+ </ul>
+ <hr>
+ <p>
+ Last updated $Date: 2010-06-11 22:02:15 $.
+ </p>
+</body>
+</html>
diff --git a/tiff/html/internals.html b/tiff/html/internals.html
new file mode 100644
index 0000000..3cc9673
--- /dev/null
+++ b/tiff/html/internals.html
@@ -0,0 +1,572 @@
+<HTML>
+<HEAD>
+<TITLE>
+Modifying The TIFF Library
+</TITLE>
+</HEAD>
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<H1>
+<IMG SRC=images/dave.gif WIDTH=107 HEIGHT=148 BORDER=2 ALIGN=left HSPACE=6>
+Modifying The TIFF Library
+</H1>
+
+
+<P>
+This chapter provides information about the internal structure of
+the library, how to control the configuration when building it, and
+how to add new support to the library.
+The following sections are found in this chapter:
+
+<UL>
+<LI><A HREF=#Config>Library Configuration</A>
+<LI><A HREF=#Portability>General Portability Comments</A>
+<LI><A HREF="#Types">Types and Portability</A>
+<LI><A HREF="addingtags.html">Adding New Tags</A>
+<LI><A HREF=#AddingCODECS>Adding New Builtin Codecs</A>
+<LI><A HREF="addingtags.html#AddingCODECTags">Adding New Codec-private Tags</A>
+<LI><A HREF=#Other>Other Comments</A>
+</UL>
+
+
+<A NAME="Config"><P><HR WIDTH=65% ALIGN=right><H3>Library Configuration</H3></A>
+
+Information on compiling the library is given
+<A HREF=build.html>elsewhere in this documentation</A>.
+This section describes the low-level mechanisms used to control
+the optional parts of the library that are configured at build
+time. Control is based on
+a collection of C defines that are specified either on the compiler
+command line or in a configuration file such as <TT>port.h</TT>
+(as generated by the <TT>configure</TT> script for UNIX systems)
+or <B>tiffconf.h</B>.
+
+<P>
+Configuration defines are split into three areas:
+<UL>
+<LI>those that control which compression schemes are
+ configured as part of the builtin codecs,
+<LI>those that control support for groups of tags that
+ are considered optional, and
+<LI>those that control operating system or machine-specific support.
+</UL>
+
+<P>
+If the define <TT>COMPRESSION_SUPPORT</TT> is <STRONG>not defined</STRONG>
+then a default set of compression schemes is automatically
+configured:
+<UL>
+<LI>CCITT Group 3 and 4 algorithms (compression codes 2, 3, 4, and 32771),
+<LI>the Macintosh PackBits algorithm (compression 32773),
+<LI>a 4-bit run-length encoding scheme from ThunderScan (compression 32809),
+<LI>a 2-bit encoding scheme used by NeXT (compression 32766), and
+<LI>two experimental schemes intended for images with high dynamic range
+(compression 34676 and 34677).
+</UL>
+
+<P>
+
+To override the default compression behaviour define
+<TT>COMPRESSION_SUPPORT</TT> and then one or more additional defines
+to enable configuration of the appropriate codecs (see the table
+below); e.g.
+
+<UL><PRE>
+#define COMPRESSION_SUPPORT
+#define CCITT_SUPPORT
+#define PACKBITS_SUPPORT
+</PRE></UL>
+
+Several other compression schemes are configured separately from
+the default set because they depend on ancillary software
+packages that are not distributed with <TT>libtiff</TT>.
+
+<P>
+Support for JPEG compression is controlled by <TT>JPEG_SUPPORT</TT>.
+The JPEG codec that comes with <TT>libtiff</TT> is designed for
+use with release 5 or later of the Independent JPEG Group's freely
+available software distribution.
+This software can be retrieved from the directory
+<A HREF=ftp://ftp.uu.net/graphics/jpeg>ftp.uu.net:/graphics/jpeg/</A>.
+
+
+<P>
+<IMG SRC="images/info.gif" ALT="NOTE: " ALIGN=left HSPACE=8>
+<EM>Enabling JPEG support automatically enables support for
+the TIFF 6.0 colorimetry and YCbCr-related tags.</EM>
+
+<P>
+Experimental support for the deflate algorithm is controlled by
+<TT>DEFLATE_SUPPORT</TT>.
+The deflate codec that comes with <TT>libtiff</TT> is designed
+for use with version 0.99 or later of the freely available
+<TT>libz</TT> library written by Jean-loup Gailly and Mark Adler.
+The data format used by this library is described
+in the files
+<A HREF=ftp://ftp.uu.net/pub/archiving/zip/doc/zlib-3.1.doc>zlib-3.1.doc</A>,
+and
+<A HREF=ftp://ftp.uu.net/pub/archiving/zip/doc/deflate-1.1.doc>deflate-1.1.doc</A>,
+available in the directory
+<A HREF=ftp://ftp.uu.net/pub/archiving/zip/doc>ftp.uu.net:/pub/archiving/zip/doc</A>.</EM>
+The library can be retried from the directory
+<A HREF=ftp://ftp.uu.net/pub/archiving/zip/zlib/>ftp.uu.net:/pub/archiving/zip/zlib/</A>
+(or try <A HREF=ftp://quest.jpl.nasa.gov/beta/zlib/>quest.jpl.nasa.gov:/beta/zlib/</A>).
+
+<P>
+<IMG SRC="images/warning.gif" ALT="NOTE: " ALIGN=left HSPACE=8 VSPACE=6>
+<EM>The deflate algorithm is experimental. Do not expect
+to exchange files using this compression scheme;
+it is included only because the similar, and more common,
+LZW algorithm is claimed to be governed by licensing restrictions.</EM>
+
+
+<P>
+By default <B>tiffconf.h</B> defines
+<TT>COLORIMETRY_SUPPORT</TT>,
+<TT>YCBCR_SUPPORT</TT>,
+and
+<TT>CMYK_SUPPORT</TT>.
+
+<P>
+<TABLE BORDER CELLPADDING=3>
+
+<TR><TH ALIGN=left>Define</TH><TH ALIGN=left>Description</TH></TR>
+
+<TR>
+<TD VALIGN=top><TT>CCITT_SUPPORT</TT></TD>
+<TD>CCITT Group 3 and 4 algorithms (compression codes 2, 3, 4,
+ and 32771)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>PACKBITS_SUPPORT</TT></TD>
+<TD>Macintosh PackBits algorithm (compression 32773)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>LZW_SUPPORT</TT></TD>
+<TD>Lempel-Ziv & Welch (LZW) algorithm (compression 5)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>THUNDER_SUPPORT</TT></TD>
+<TD>4-bit
+run-length encoding scheme from ThunderScan (compression 32809)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>NEXT_SUPPORT</TT></TD>
+<TD>2-bit encoding scheme used by NeXT (compression 32766)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>OJPEG_SUPPORT</TT></TD>
+<TD>obsolete JPEG scheme defined in the 6.0 spec (compression 6)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>JPEG_SUPPORT</TT></TD>
+<TD>current JPEG scheme defined in TTN2 (compression 7)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>ZIP_SUPPORT</TT></TD>
+<TD>experimental Deflate scheme (compression 32946)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>PIXARLOG_SUPPORT</TT></TD>
+<TD>Pixar's compression scheme for high-resolution color images (compression 32909)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>SGILOG_SUPPORT</TT></TD>
+<TD>SGI's compression scheme for high-resolution color images (compression 34676 and 34677)</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>COLORIMETRY_SUPPORT</TT></TD>
+<TD>support for the TIFF 6.0 colorimetry tags</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>YCBCR_SUPPORT</TT></TD>
+<TD>support for the TIFF 6.0 YCbCr-related tags</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>CMYK_SUPPORT</TT></TD>
+<TD>support for the TIFF 6.0 CMYK-related tags</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>ICC_SUPPORT</TT></TD>
+<TD>support for the ICC Profile tag; see
+<I>The ICC Profile Format Specification</I>,
+Annex B.3 "Embedding ICC Profiles in TIFF Files";
+available at
+<A HREF=http://www.color.org>http://www.color.org</A>
+</TD>
+</TR>
+
+</TABLE>
+
+
+<A NAME="Portability"><P><HR WIDTH=65% ALIGN=right><H3>General Portability Comments</H3></A>
+
+This software is developed on Silicon Graphics UNIX
+systems (big-endian, MIPS CPU, 32-bit ints,
+IEEE floating point).
+The <TT>configure</TT> shell script generates the appropriate
+include files and make files for UNIX systems.
+Makefiles exist for non-UNIX platforms that the
+code runs on -- this work has mostly been done by other people.
+
+<P>
+In general, the code is guaranteed to work only on SGI machines.
+In practice it is highly portable to any 32-bit or 64-bit system and much
+work has been done to insure portability to 16-bit systems.
+If you encounter portability problems please return fixes so
+that future distributions can be improved.
+
+<P>
+The software is written to assume an ANSI C compilation environment.
+If your compiler does not support ANSI function prototypes, <TT>const</TT>,
+and <TT>&lt;stdarg.h&gt;</TT> then you will have to make modifications to the
+software. In the past I have tried to support compilers without <TT>const</TT>
+and systems without <TT>&lt;stdarg.h&gt;</TT>, but I am
+<EM>no longer interested in these
+antiquated environments</EM>. With the general availability of
+the freely available GCC compiler, I
+see no reason to incorporate modifications to the software for these
+purposes.
+
+<P>
+An effort has been made to isolate as many of the
+operating system-dependencies
+as possible in two files: <B>tiffcomp.h</B> and
+<B>libtiff/tif_&lt;os&gt;.c</B>. The latter file contains
+operating system-specific routines to do I/O and I/O-related operations.
+The UNIX (<B>tif_unix.c</B>),
+Macintosh (<B>tif_apple.c</B>),
+and VMS (<B>tif_vms.c</B>)
+code has had the most use;
+the MS/DOS support (<B>tif_msdos.c</B>) assumes
+some level of UNIX system call emulation (i.e.
+<TT>open</TT>,
+<TT>read</TT>,
+<TT>write</TT>,
+<TT>fstat</TT>,
+<TT>malloc</TT>,
+<TT>free</TT>).
+
+<P>
+Native CPU byte order is determined on the fly by
+the library and does not need to be specified.
+The <TT>HOST_FILLORDER</TT> and <TT>HOST_BIGENDIAN</TT>
+definitions are not currently used, but may be employed by
+codecs for optimization purposes.
+
+<P>
+The following defines control general portability:
+
+<P>
+<TABLE BORDER CELLPADDING=3 WIDTH=100%>
+
+<TR>
+<TD VALIGN=top><TT>BSDTYPES</TT></TD>
+<TD>Define this if your system does NOT define the
+ usual BSD typedefs: <TT>u_char</TT>,
+ <TT>u_short</TT>, <TT>u_int</TT>, <TT>u_long</TT>.</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>HAVE_IEEEFP</TT></TD>
+<TD>Define this as 0 or 1 according to the floating point
+ format suported by the machine. If your machine does
+ not support IEEE floating point then you will need to
+ add support to tif_machdep.c to convert between the
+ native format and IEEE format.</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>HAVE_MMAP</TT></TD>
+<TD>Define this if there is <I>mmap-style</I> support for
+mapping files into memory (used only to read data).</TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>HOST_FILLORDER</TT></TD>
+<TD>Define the native CPU bit order: one of <TT>FILLORDER_MSB2LSB</TT>
+ or <TT>FILLORDER_LSB2MSB</TT></TD>
+</TR>
+
+<TR>
+<TD VALIGN=top><TT>HOST_BIGENDIAN</TT></TD>
+<TD>Define the native CPU byte order: 1 if big-endian (Motorola)
+ or 0 if little-endian (Intel); this may be used
+ in codecs to optimize code</TD>
+</TR>
+</TABLE>
+
+<P>
+On UNIX systems <TT>HAVE_MMAP</TT> is defined through the running of
+the <TT>configure</TT> script; otherwise support for memory-mapped
+files is disabled.
+Note that <B>tiffcomp.h</B> defines <TT>HAVE_IEEEFP</TT> to be
+1 (<TT>BSDTYPES</TT> is not defined).
+
+
+<A NAME="Types"><P><HR WIDTH=65% ALIGN=right><H3>Types and Portability</H3></A>
+
+The software makes extensive use of C typedefs to promote portability.
+Two sets of typedefs are used, one for communication with clients
+of the library and one for internal data structures and parsing of the
+TIFF format. There are interactions between these two to be careful
+of, but for the most part you should be able to deal with portability
+purely by fiddling with the following machine-dependent typedefs:
+
+
+<P>
+<TABLE BORDER CELLPADDING=3 WIDTH=100%>
+
+<TR>
+<TD>uint8</TD>
+<TD>8-bit unsigned integer</TD>
+<TD>tiff.h</TD>
+</TR>
+
+<TR>
+<TD>int8</TD>
+<TD>8-bit signed integer</TD>
+<TD>tiff.h</TD>
+</TR>
+
+<TR>
+<TD>uint16</TD>
+<TD>16-bit unsigned integer</TD>
+<TD>tiff.h</TD>
+</TR>
+
+<TR>
+<TD>int16</TD>
+<TD>16-bit signed integer</TD>
+<TD>tiff.h</TD>
+</TR>
+
+<TR>
+<TD>uint32</TD>
+<TD>32-bit unsigned integer</TD>
+<TD>tiff.h</TD>
+</TR>
+
+<TR>
+<TD>int32</TD>
+<TD>32-bit signed integer</TD>
+<TD>tiff.h</TD>
+</TR>
+
+<TR>
+<TD>dblparam_t</TD>
+<TD>promoted type for floats</TD>
+<TD>tiffcomp.h</TD>
+</TR>
+
+</TABLE>
+
+<P>
+(to clarify <TT>dblparam_t</TT>, it is the type that float parameters are
+promoted to when passed by value in a function call.)
+
+<P>
+The following typedefs are used throughout the library and interfaces
+to refer to certain objects whose size is dependent on the TIFF image
+structure:
+
+
+<P>
+<TABLE BORDER CELLPADDING=3 WIDTH=100%>
+
+<TR>
+<TD WIDTH=25%>typedef unsigned int ttag_t;</TD> <TD>directory tag</TD>
+</TR>
+
+<TR>
+<TD>typedef uint16 tdir_t;</TD> <TD>directory index</TD>
+</TR>
+
+<TR>
+<TD>typedef uint16 tsample_t;</TD> <TD>sample number</TD>
+</TR>
+
+<TR>
+<TD>typedef uint32 tstrip_t;</TD> <TD>strip number</TD>
+</TR>
+
+<TR>
+<TD>typedef uint32 ttile_t;</TD> <TD>tile number</TD>
+</TR>
+
+<TR>
+<TD>typedef int32 tsize_t;</TD> <TD>i/o size in bytes</TD>
+</TR>
+
+<TR>
+<TD>typedef void* tdata_t;</TD> <TD>image data ref</TD>
+</TR>
+
+<TR>
+<TD>typedef void* thandle_t;</TD> <TD>client data handle</TD>
+</TR>
+
+<TR>
+<TD>typedef int32 toff_t;</TD> <TD>file offset (should be off_t)</TD>
+</TR>
+
+<TR>
+<TD>typedef unsigned char* tidata_t;</TD> <TD>internal image data</TD>
+</TR>
+
+</TABLE>
+
+<P>
+Note that <TT>tstrip_t</TT>, <TT>ttile_t</TT>, and <TT>tsize_t</TT>
+are constrained to be
+no more than 32-bit quantities by 32-bit fields they are stored
+in in the TIFF image. Likewise <TT>tsample_t</TT> is limited by the 16-bit
+field used to store the <TT>SamplesPerPixel</TT> tag. <TT>tdir_t</TT>
+constrains
+the maximum number of IFDs that may appear in an image and may
+be an arbitrary size (without penalty). <TT>ttag_t</TT> must be either
+<TT>int</TT>, <TT>unsigned int</TT>, pointer, or <TT>double</TT>
+because the library uses a varargs
+interface and ANSI C restricts the type of the parameter before an
+ellipsis to be a promoted type. <TT>toff_t</TT> is defined as
+<TT>int32</TT> because
+TIFF file offsets are (unsigned) 32-bit quantities. A signed
+value is used because some interfaces return -1 on error (sigh).
+Finally, note that <TT>tidata_t</TT> is used internally to the library to
+manipulate internal data. User-specified data references are
+passed as opaque handles and only cast at the lowest layers where
+their type is presumed.
+
+
+<P><HR WIDTH=65% ALIGN=right><H3>General Comments</H3></A>
+
+The library is designed to hide as much of the details of TIFF from
+applications as
+possible. In particular, TIFF directories are read in their entirety
+into an internal format. Only the tags known by the library are
+available to a user and certain tag data may be maintained that a user
+does not care about (e.g. transfer function tables).
+
+<A NAME=AddingCODECS><P><HR WIDTH=65% ALIGN=right><H3>Adding New Builtin Codecs</H3></A>
+
+To add builtin support for a new compression algorithm, you can either
+use the "tag-extension" trick to override the handling of the
+TIFF Compression tag (see <A HREF=addingtags.html>Adding New Tags</A>),
+or do the following to add support directly to the core library:
+
+<OL>
+<LI>Define the tag value in <B>tiff.h</B>.
+<LI>Edit the file <B>tif_codec.c</B> to add an entry to the
+ _TIFFBuiltinCODECS array (see how other algorithms are handled).
+<LI>Add the appropriate function prototype declaration to
+ <B>tiffiop.h</B> (close to the bottom).
+<LI>Create a file with the compression scheme code, by convention files
+ are named <B>tif_*.c</B> (except perhaps on some systems where the
+ tif_ prefix pushes some filenames over 14 chars.
+<LI>Edit <B>Makefile.in</B> (and any other Makefiles)
+ to include the new source file.
+</OL>
+
+<P>
+A codec, say <TT>foo</TT>, can have many different entry points:
+
+<PRE>
+TIFFInitfoo(tif, scheme)/* initialize scheme and setup entry points in tif */
+fooSetupDecode(tif) /* called once per IFD after tags has been frozen */
+fooPreDecode(tif, sample)/* called once per strip/tile, after data is read,
+ but before the first row is decoded */
+fooDecode*(tif, bp, cc, sample)/* decode cc bytes of data into the buffer */
+ fooDecodeRow(...) /* called to decode a single scanline */
+ fooDecodeStrip(...) /* called to decode an entire strip */
+ fooDecodeTile(...) /* called to decode an entire tile */
+fooSetupEncode(tif) /* called once per IFD after tags has been frozen */
+fooPreEncode(tif, sample)/* called once per strip/tile, before the first row in
+ a strip/tile is encoded */
+fooEncode*(tif, bp, cc, sample)/* encode cc bytes of user data (bp) */
+ fooEncodeRow(...) /* called to decode a single scanline */
+ fooEncodeStrip(...) /* called to decode an entire strip */
+ fooEncodeTile(...) /* called to decode an entire tile */
+fooPostEncode(tif) /* called once per strip/tile, just before data is written */
+fooSeek(tif, row) /* seek forwards row scanlines from the beginning
+ of a strip (row will always be &gt;0 and &lt;rows/strip */
+fooCleanup(tif) /* called when compression scheme is replaced by user */
+</PRE>
+
+<P>
+Note that the encoding and decoding variants are only needed when
+a compression algorithm is dependent on the structure of the data.
+For example, Group 3 2D encoding and decoding maintains a reference
+scanline. The sample parameter identifies which sample is to be
+encoded or decoded if the image is organized with <TT>PlanarConfig</TT>=2
+(separate planes). This is important for algorithms such as JPEG.
+If <TT>PlanarConfig</TT>=1 (interleaved), then sample will always be 0.
+
+<A NAME=Other><P><HR WIDTH=65% ALIGN=right><H3>Other Comments</H3></A>
+
+The library handles most I/O buffering. There are two data buffers
+when decoding data: a raw data buffer that holds all the data in a
+strip, and a user-supplied scanline buffer that compression schemes
+place decoded data into. When encoding data the data in the
+user-supplied scanline buffer is encoded into the raw data buffer (from
+where it is written). Decoding routines should never have to explicitly
+read data -- a full strip/tile's worth of raw data is read and scanlines
+never cross strip boundaries. Encoding routines must be cognizant of
+the raw data buffer size and call <TT>TIFFFlushData1()</TT> when necessary.
+Note that any pending data is automatically flushed when a new strip/tile is
+started, so there's no need do that in the tif_postencode routine (if
+one exists). Bit order is automatically handled by the library when
+a raw strip or tile is filled. If the decoded samples are interpreted
+by the decoding routine before they are passed back to the user, then
+the decoding logic must handle byte-swapping by overriding the
+<TT>tif_postdecode</TT>
+routine (set it to <TT>TIFFNoPostDecode</TT>) and doing the required work
+internally. For an example of doing this look at the horizontal
+differencing code in the routines in <B>tif_predict.c</B>.
+
+<P>
+The variables <TT>tif_rawcc</TT>, <TT>tif_rawdata</TT>, and
+<TT>tif_rawcp</TT> in a <TT>TIFF</TT> structure
+are associated with the raw data buffer. <TT>tif_rawcc</TT> must be non-zero
+for the library to automatically flush data. The variable
+<TT>tif_scanlinesize</TT> is the size a user's scanline buffer should be. The
+variable <TT>tif_tilesize</TT> is the size of a tile for tiled images. This
+should not normally be used by compression routines, except where it
+relates to the compression algorithm. That is, the <TT>cc</TT> parameter to the
+<TT>tif_decode*</TT> and <TT>tif_encode*</TT>
+routines should be used in terminating
+decompression/compression. This ensures these routines can be used,
+for example, to decode/encode entire strips of data.
+
+<P>
+In general, if you have a new compression algorithm to add, work from
+the code for an existing routine. In particular,
+<B>tif_dumpmode.c</B>
+has the trivial code for the "nil" compression scheme,
+<B>tif_packbits.c</B> is a
+simple byte-oriented scheme that has to watch out for buffer
+boundaries, and <B>tif_lzw.c</B> has the LZW scheme that has the most
+complexity -- it tracks the buffer boundary at a bit level.
+Of course, using a private compression scheme (or private tags) limits
+the portability of your TIFF files.
+
+<P>
+<HR>
+
+Last updated: $Date: 2004/09/10 14:47:31 $
+
+</BODY>
+
+</HTML>
diff --git a/tiff/html/intro.html b/tiff/html/intro.html
new file mode 100644
index 0000000..61c01d4
--- /dev/null
+++ b/tiff/html/intro.html
@@ -0,0 +1,68 @@
+<HTML>
+<HEAD>
+<TITLE>
+Introduction to the TIFF Documentation
+</TITLE>
+</HEAD>
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<H1>
+<IMG SRC=images/strike.gif WIDTH=128 HEIGHT=100 ALIGN=left HSPACE=6>
+Introduction to the TIFF Documentation
+</H1>
+
+
+<P>
+The following definitions are used throughout this documentation.
+They are consistent with the terminology used in the TIFF 6.0 specification.
+
+<DL>
+<DT><I>Sample</I>
+<DD>The unit of information stored in an image; often called a
+ channel elsewhere. Sample values are numbers, usually unsigned
+ integers, but possibly in some other format if the SampleFormat
+ tag is specified in a TIFF
+<DT><I>Pixel</I>
+<DD>A collection of one or more samples that go together.
+<DT><I>Row</I>
+<DD>An Nx1 rectangular collection of pixels.
+<DT><I>Tile</I>
+<DD>An NxM rectangular organization of data (or pixels).
+<DT><I>Strip</I>
+<DD>A tile whose width is the full image width.
+<DT><I>Compression</I>
+<DD>A scheme by which pixel or sample data are stored in
+ an encoded form, specifically with the intent of reducing the
+ storage cost.
+<DT><I>Codec</I>
+<DD>Software that implements the decoding and encoding algorithms
+ of a compression scheme.
+</UL>
+
+<P>
+In order to better understand how TIFF works (and consequently this
+software) it is important to recognize the distinction between the
+physical organization of image data as it is stored in a TIFF and how
+the data is interpreted and manipulated as pixels in an image. TIFF
+supports a wide variety of storage and data compression schemes that
+can be used to optimize retrieval time and/or minimize storage space.
+These on-disk formats are independent of the image characteristics; it
+is the responsibility of the TIFF reader to process the on-disk storage
+into an in-memory format suitable for an application. Furthermore, it
+is the responsibility of the application to properly interpret the
+visual characteristics of the image data. TIFF defines a framework for
+specifying the on-disk storage format and image characteristics with
+few restrictions. This permits significant complexity that can be
+daunting. Good applications that handle TIFF work by handling as wide
+a range of storage formats as possible, while constraining the
+acceptable image characteristics to those that make sense for the
+application.
+
+
+<P>
+<HR>
+
+Last updated: $Date: 1999/08/09 20:21:21 $
+
+</BODY>
+</HTML>
diff --git a/tiff/html/libtiff.html b/tiff/html/libtiff.html
new file mode 100644
index 0000000..6a2c42e
--- /dev/null
+++ b/tiff/html/libtiff.html
@@ -0,0 +1,747 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html lang="en">
+<head>
+ <title>Using The TIFF Library</title>
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+ <meta http-equiv="content-language" content="en">
+ <style type="text/css">
+ <!--
+ th {text-align: left; vertical-align: top; font-style: italic; font-weight: normal}
+ -->
+ </style>
+</head>
+<body lang="en" text="#000000" bgcolor="#ffffff" link="#0000ff" alink="#0000ff" vlink="#0000ff">
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td style="padding-left: 1em; padding-right: 1em"><img src="images/cat.gif" width="113" height="146" alt=""></td>
+ <td>
+ <h1>Using The TIFF Library</h1>
+ <p>
+ <tt>libtiff</tt> is a set of C functions (a library) that support
+ the manipulation of TIFF image files.
+ The library requires an ANSI C compilation environment for building
+ and presumes an ANSI C environment for use.
+ </p>
+ </td>
+ </tr>
+ </table>
+ <br>
+ <p>
+ <tt>libtiff</tt>
+ provides interfaces to image data at several layers of abstraction (and cost).
+ At the highest level image data can be read into an 8-bit/sample,
+ ABGR pixel raster format without regard for the underlying data organization,
+ colorspace, or compression scheme. Below this high-level interface
+ the library provides scanline-, strip-, and tile-oriented interfaces that
+ return data decompressed but otherwise untransformed. These interfaces
+ require that the application first identify the organization of stored
+ data and select either a strip-based or tile-based API for manipulating
+ data. At the lowest level the library
+ provides access to the raw uncompressed strips or tiles,
+ returning the data exactly as it appears in the file.
+ </p>
+ <p>
+ The material presented in this chapter is a basic introduction
+ to the capabilities of the library; it is not an attempt to describe
+ everything a developer needs to know about the library or about TIFF.
+ Detailed information on the interfaces to the library are given in
+ the <a href="http://www.remotesensing.org/libtiff/man/index.html">UNIX
+ manual pages</a> that accompany this software.
+ </p>
+ <p>
+ Michael Still has also written a useful introduction to libtiff for the
+ IBM DeveloperWorks site available at
+ <a href="http://www.ibm.com/developerworks/linux/library/l-libtiff">http://www.ibm.com/developerworks/linux/library/l-libtiff</a>.
+ </p>
+ <p>
+ The following sections are found in this chapter:
+ </p>
+ <ul>
+ <li><a href="#version">How to tell which version you have</a></li>
+ <li><a href="#typedefs">Library Datatypes</a></li>
+ <li><a href="#mman">Memory Management</a></li>
+ <li><a href="#errors">Error Handling</a></li>
+ <li><a href="#fio">Basic File Handling</a></li>
+ <li><a href="#dirs">TIFF Directories</a></li>
+ <li><a href="#tags">TIFF Tags</a></li>
+ <li><a href="#compression">TIFF Compression Schemes</a></li>
+ <li><a href="#byteorder">Byte Order</a></li>
+ <li><a href="#dataplacement">Data Placement</a></li>
+ <li><a href="#tiffrgbaimage">TIFFRGBAImage Support</a></li>
+ <li><a href="#scanlines">Scanline-based Image I/O</a></li>
+ <li><a href="#strips">Strip-oriented Image I/O</a></li>
+ <li><a href="#tiles">Tile-oriented Image I/O</a></li>
+ <li><a href="#other">Other Stuff</a></li>
+ </ul>
+ <hr>
+ <h2 id="version">How to tell which version you have</h2>
+ <p>
+ The software version can be found by looking at the file named
+ <tt>VERSION</tt>
+ that is located at the top of the source tree; the precise alpha number
+ is given in the file <tt>dist/tiff.alpha</tt>.
+ If you have need to refer to this
+ specific software, you should identify it as:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>TIFF &lt;<i>version</i>&gt; &lt;<i>alpha</i>&gt;</tt>
+ </p>
+ <p>
+ where <tt>&lt;<i>version</i>&gt;</tt> is whatever you get from
+ <tt>"cat VERSION"</tt> and <tt>&lt;<i>alpha</i>&gt;</tt> is
+ what you get from <tt>"cat dist/tiff.alpha"</tt>.
+ </p>
+ <p>
+ Within an application that uses <tt>libtiff</tt> the <tt>TIFFGetVersion</tt>
+ routine will return a pointer to a string that contains software version
+ information.
+ The library include file <tt>&lt;tiffio.h&gt;</tt> contains a C pre-processor
+ define <tt>TIFFLIB_VERSION</tt> that can be used to check library
+ version compatiblity at compile time.
+ </p>
+ <hr>
+ <h2 id="typedefs">Library Datatypes</h2>
+ <p>
+ <tt>libtiff</tt> defines a portable programming interface through the
+ use of a set of C type definitions.
+ These definitions, defined in in the files <b>tiff.h</b> and
+ <b>tiffio.h</b>,
+ isolate the <tt>libtiff</tt> API from the characteristics
+ of the underlying machine.
+ To insure portable code and correct operation, applications that use
+ <tt>libtiff</tt> should use the typedefs and follow the function
+ prototypes for the library API.
+ </p>
+ <hr>
+ <h2 id="mman">Memory Management</h2>
+ <p>
+ <tt>libtiff</tt> uses a machine-specific set of routines for managing
+ dynamically allocated memory.
+ <tt>_TIFFmalloc</tt>, <tt>_TIFFrealloc</tt>, and <tt>_TIFFfree</tt>
+ mimic the normal ANSI C routines.
+ Any dynamically allocated memory that is to be passed into the library
+ should be allocated using these interfaces in order to insure pointer
+ compatibility on machines with a segmented architecture.
+ (On 32-bit UNIX systems these routines just call the normal <tt>malloc</tt>,
+ <tt>realloc</tt>, and <tt>free</tt> routines in the C library.)
+ </p>
+ <p>
+ To deal with segmented pointer issues <tt>libtiff</tt> also provides
+ <tt>_TIFFmemcpy</tt>, <tt>_TIFFmemset</tt>, and <tt>_TIFFmemmove</tt>
+ routines that mimic the equivalent ANSI C routines, but that are
+ intended for use with memory allocated through <tt>_TIFFmalloc</tt>
+ and <tt>_TIFFrealloc</tt>.
+ </p>
+ <hr>
+ <h2 id="errors">Error Handling</h2>
+ <p>
+ <tt>libtiff</tt> handles most errors by returning an invalid/erroneous
+ value when returning from a function call.
+ Various diagnostic messages may also be generated by the library.
+ All error messages are directed to a single global error handler
+ routine that can be specified with a call to <tt>TIFFSetErrorHandler</tt>.
+ Likewise warning messages are directed to a single handler routine
+ that can be specified with a call to <tt>TIFFSetWarningHandler</tt>
+ </p>
+ <hr>
+ <h2 id="fio">Basic File Handling</h2>
+ <p>
+ The library is modeled after the normal UNIX stdio library.
+ For example, to read from an existing TIFF image the
+ file must first be opened:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main()<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen("foo.tif", "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;... do stuff ...<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFFClose(tif);<br>
+ }</tt>
+ </p>
+ <p>
+ The handle returned by <tt>TIFFOpen</tt> is <i>opaque</i>, that is
+ the application is not permitted to know about its contents.
+ All subsequent library calls for this file must pass the handle
+ as an argument.
+ </p>
+ <p>
+ To create or overwrite a TIFF image the file is also opened, but with
+ a <tt>"w"</tt> argument:
+ <p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main()<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen("foo.tif", "w");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;... do stuff ...<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFFClose(tif);<br>
+ }</tt>
+ </p>
+ <p>
+ If the file already exists it is first truncated to zero length.
+ </p>
+ <table>
+ <tr>
+ <td valign=top><img src="images/warning.gif" width="40" height="40" alt=""></td>
+ <td><i>Note that unlike the stdio library TIFF image files may not be
+ opened for both reading and writing;
+ there is no support for altering the contents of a TIFF file.</i></td>
+ </tr>
+ </table>
+ <p>
+ <tt>libtiff</tt> buffers much information associated with writing a
+ valid TIFF image. Consequently, when writing a TIFF image it is necessary
+ to always call <tt>TIFFClose</tt> or <tt>TIFFFlush</tt> to flush any
+ buffered information to a file. Note that if you call <tt>TIFFClose</tt>
+ you do not need to call <tt>TIFFFlush</tt>.
+ </p>
+ <hr>
+ <h2 id="dirs">TIFF Directories</h2>
+ <p>
+ TIFF supports the storage of multiple images in a single file.
+ Each image has an associated data structure termed a <i>directory</i>
+ that houses all the information about the format and content of the
+ image data.
+ Images in a file are usually related but they do not need to be; it
+ is perfectly alright to store a color image together with a black and
+ white image.
+ Note however that while images may be related their directories are
+ not.
+ That is, each directory stands on its own; their is no need to read
+ an unrelated directory in order to properly interpret the contents
+ of an image.
+ </p>
+ <p>
+ <tt>libtiff</tt> provides several routines for reading and writing
+ directories. In normal use there is no need to explicitly
+ read or write a directory: the library automatically reads the first
+ directory in a file when opened for reading, and directory information
+ to be written is automatically accumulated and written when writing
+ (assuming <tt>TIFFClose</tt> or <tt>TIFFFlush</tt> are called).
+ </p>
+ <p>
+ For a file open for reading the <tt>TIFFSetDirectory</tt> routine can
+ be used to select an arbitrary directory; directories are referenced by
+ number with the numbering starting at 0. Otherwise the
+ <tt>TIFFReadDirectory</tt> and <tt>TIFFWriteDirectory</tt> routines can
+ be used for sequential access to directories.
+ For example, to count the number of directories in a file the following
+ code might be used:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main(int argc, char* argv[])<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen(argv[1], "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int dircount = 0;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;do {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dircount++;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} while (TIFFReadDirectory(tif));<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("%d directories in %s\n", dircount, argv[1]);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFClose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;exit(0);<br>
+ }</tt>
+ </p>
+ <p>
+ Finally, note that there are several routines for querying the
+ directory status of an open file:
+ <tt>TIFFCurrentDirectory</tt> returns the index of the current
+ directory and
+ <tt>TIFFLastDirectory</tt> returns an indication of whether the
+ current directory is the last directory in a file.
+ There is also a routine, <tt>TIFFPrintDirectory</tt>, that can
+ be called to print a formatted description of the contents of
+ the current directory; consult the manual page for complete details.
+ </p>
+ <hr>
+ <h2 id="tags">TIFF Tags</h2>
+ <p>
+ Image-related information such as the image width and height, number
+ of samples, orientation, colorimetric information, etc.
+ are stored in each image
+ directory in <i>fields</i> or <i>tags</i>.
+ Tags are identified by a number that is usually a value registered
+ with the Aldus (now Adobe) Corporation.
+ Beware however that some vendors write
+ TIFF images with tags that are unregistered; in this case interpreting
+ their contents is usually a waste of time.
+ </p>
+ <p>
+ <tt>libtiff</tt> reads the contents of a directory all at once
+ and converts the on-disk information to an appropriate in-memory
+ form. While the TIFF specification permits an arbitrary set of
+ tags to be defined and used in a file, the library only understands
+ a limited set of tags.
+ Any unknown tags that are encountered in a file are ignored.
+ There is a mechanism to extend the set of tags the library handles
+ without modifying the library itself;
+ this is described <a href="addingtags.html">elsewhere</a>.
+ </p>
+ <p>
+ <tt>libtiff</tt> provides two interfaces for getting and setting tag
+ values: <tt>TIFFGetField</tt> and <tt>TIFFSetField</tt>.
+ These routines use a variable argument list-style interface to pass
+ parameters of different type through a single function interface.
+ The <i>get interface</i> takes one or more pointers to memory locations
+ where the tag values are to be returned and also returns one or
+ zero according to whether the requested tag is defined in the directory.
+ The <i>set interface</i> takes the tag values either by-reference or
+ by-value.
+ The TIFF specification defines
+ <i>default values</i> for some tags.
+ To get the value of a tag, or its default value if it is undefined,
+ the <tt>TIFFGetFieldDefaulted</tt> interface may be used.
+ </p>
+ <p>
+ The manual pages for the tag get and set routines specifiy the exact data types
+ and calling conventions required for each tag supported by the library.
+ </p>
+ <hr>
+ <h2 id="compression">TIFF Compression Schemes</h2>
+ <p>
+ <tt>libtiff</tt> includes support for a wide variety of
+ data compression schemes.
+ In normal operation a compression scheme is automatically used when
+ the TIFF <tt>Compression</tt> tag is set, either by opening a file
+ for reading, or by setting the tag when writing.
+ </p>
+ <p>
+ Compression schemes are implemented by software modules termed <i>codecs</i>
+ that implement decoder and encoder routines that hook into the
+ core library i/o support.
+ Codecs other than those bundled with the library can be registered
+ for use with the <tt>TIFFRegisterCODEC</tt> routine.
+ This interface can also be used to override the core-library
+ implementation for a compression scheme.
+ </p>
+ <hr>
+ <h2 id="byteorder">Byte Order</h2>
+ <p>
+ The TIFF specification says, and has always said, that
+ <em>a correct TIFF
+ reader must handle images in big-endian and little-endian byte order</em>.
+ <tt>libtiff</tt> conforms in this respect.
+ Consequently there is no means to force a specific
+ byte order for the data written to a TIFF image file (data is
+ written in the native order of the host CPU unless appending to
+ an existing file, in which case it is written in the byte order
+ specified in the file).
+ </p>
+ <hr>
+ <h2 id="dataplacement">Data Placement</h2>
+ <p>
+ The TIFF specification requires that all information except an
+ 8-byte header can be placed anywhere in a file.
+ In particular, it is perfectly legitimate for directory information
+ to be written after the image data itself.
+ Consequently TIFF is inherently not suitable for passing through a
+ stream-oriented mechanism such as UNIX pipes.
+ Software that require that data be organized in a file in a particular
+ order (e.g. directory information before image data) does not
+ correctly support TIFF.
+ <tt>libtiff</tt> provides no mechanism for controlling the placement
+ of data in a file; image data is typically written before directory
+ information.
+ </p>
+ <hr>
+ <h2 id="tiffrgbaimage">TIFFRGBAImage Support</h2>
+ <p>
+ <tt>libtiff</tt> provides a high-level interface for reading image
+ data from a TIFF file. This interface handles the details of
+ data organization and format for a wide variety of TIFF files;
+ at least the large majority of those files that one would normally
+ encounter. Image data is, by default, returned as ABGR
+ pixels packed into 32-bit words (8 bits per sample). Rectangular
+ rasters can be read or data can be intercepted at an intermediate
+ level and packed into memory in a format more suitable to the
+ application.
+ The library handles all the details of the format of data stored on
+ disk and, in most cases, if any colorspace conversions are required:
+ bilevel to RGB, greyscale to RGB, CMYK to RGB, YCbCr to RGB, 16-bit
+ samples to 8-bit samples, associated/unassociated alpha, etc.
+ </p>
+ <p>
+ There are two ways to read image data using this interface. If
+ all the data is to be stored in memory and manipulated at once,
+ then the routine <tt>TIFFReadRGBAImage</tt> can be used:
+ </p>
+ <p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main(int argc, char* argv[])<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen(argv[1], "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 w, h;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t npixels;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32* raster;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &amp;w);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &amp;h);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;npixels = w * h;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (raster != NULL) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (TIFFReadRGBAImage(tif, w, h, raster, 0)) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...process raster data...<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_TIFFfree(raster);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFClose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;exit(0);<br>
+ }</tt>
+ </p>
+ <p>
+ Note above that <tt>_TIFFmalloc</tt> is used to allocate memory for
+ the raster passed to <tt>TIFFReadRGBAImage</tt>; this is important
+ to insure the ``appropriate type of memory'' is passed on machines
+ with segmented architectures.
+ </p>
+ <p>
+ Alternatively, <tt>TIFFReadRGBAImage</tt> can be replaced with a
+ more low-level interface that permits an application to have more
+ control over this reading procedure. The equivalent to the above
+ is:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main(int argc, char* argv[])<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen(argv[1], "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFRGBAImage img;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char emsg[1024];<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (TIFFRGBAImageBegin(&amp;img, tif, 0, emsg)) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size_t npixels;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32* raster;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;npixels = img.width * img.height;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (raster != NULL) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (TIFFRGBAImageGet(&amp;img, raster, img.width, img.height)) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...process raster data...<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_TIFFfree(raster);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFRGBAImageEnd(&amp;img);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFError(argv[1], emsg);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFClose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;exit(0);<br>
+ }</tt>
+ </p>
+ <p>
+ However this usage does not take advantage of the more fine-grained
+ control that's possible. That is, by using this interface it is
+ possible to:
+ </p>
+ <ul>
+ <li>repeatedly fetch (and manipulate) an image without opening
+ and closing the file</li>
+ <li>interpose a method for packing raster pixel data according to
+ application-specific needs (or write the data at all)</li>
+ <li>interpose methods that handle TIFF formats that are not already
+ handled by the core library</li>
+ </ul>
+ <p>
+ The first item means that, for example, image viewers that want to
+ handle multiple files can cache decoding information in order to
+ speedup the work required to display a TIFF image.
+ </p>
+ <p>
+ The second item is the main reason for this interface. By interposing
+ a "put method" (the routine that is called to pack pixel data in
+ the raster) it is possible share the core logic that understands how
+ to deal with TIFF while packing the resultant pixels in a format that
+ is optimized for the application. This alternate format might be very
+ different than the 8-bit per sample ABGR format the library writes by
+ default. For example, if the application is going to display the image
+ on an 8-bit colormap display the put routine might take the data and
+ convert it on-the-fly to the best colormap indices for display.
+ </p>
+ <p>
+ The last item permits an application to extend the library
+ without modifying the core code.
+ By overriding the code provided an application might add support
+ for some esoteric flavor of TIFF that it needs, or it might
+ substitute a packing routine that is able to do optimizations
+ using application/environment-specific information.
+ </p>
+ <p>
+ The TIFF image viewer found in <b>tools/sgigt.c</b> is an example
+ of an application that makes use of the <tt>TIFFRGBAImage</tt>
+ support.
+ </p>
+ <hr>
+ <h2 id="scanlines">Scanline-based Image I/O</h2>
+ <p>
+ The simplest interface provided by <tt>libtiff</tt> is a
+ scanline-oriented interface that can be used to read TIFF
+ images that have their image data organized in strips
+ (trying to use this interface to read data written in tiles
+ will produce errors.)
+ A scanline is a one pixel high row of image data whose width
+ is the width of the image.
+ Data is returned packed if the image data is stored with samples
+ packed together, or as arrays of separate samples if the data
+ is stored with samples separated.
+ The major limitation of the scanline-oriented interface, other
+ than the need to first identify an existing file as having a
+ suitable organization, is that random access to individual
+ scanlines can only be provided when data is not stored in a
+ compressed format, or when the number of rows in a strip
+ of image data is set to one (<tt>RowsPerStrip</tt> is one).
+ </p>
+ <p>
+ Two routines are provided for scanline-based i/o:
+ <tt>TIFFReadScanline</tt>
+ and
+ <tt>TIFFWriteScanline</tt>.
+ For example, to read the contents of a file that
+ is assumed to be organized in strips, the following might be used:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main()<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen("myfile.tif", "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 imagelength;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tdata_t buf;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 row;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &amp;imagelength);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf = _TIFFmalloc(TIFFScanlineSize(tif));<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (row = 0; row &lt; imagelength; row++)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffreadscanline(tif, buf, row);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_tifffree(buf);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffclose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ }</tt>
+ </p>
+ <p>
+ <tt>TIFFScanlineSize</tt> returns the number of bytes in
+ a decoded scanline, as returned by <tt>TIFFReadScanline</tt>.
+ Note however that if the file had been create with samples
+ written in separate planes, then the above code would only
+ read data that contained the first sample of each pixel;
+ to handle either case one might use the following instead:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main()<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen("myfile.tif", "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 imagelength;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tdata_t buf;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 row;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &amp;imagelength);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &amp;config);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf = _TIFFmalloc(TIFFScanlineSize(tif));<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (config == PLANARCONFIG_CONTIG) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (row = 0; row &lt; imagelength; row++)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffreadscanline(tif, buf, row);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} else if (config == planarconfig_separate) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint16 s, nsamples;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffgetfield(tif, tifftag_samplesperpixel, &amp;nsamples);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (s = 0; s &lt; nsamples; s++)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (row = 0; row &lt; imagelength; row++)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffreadscanline(tif, buf, row, s);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_tifffree(buf);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffclose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ }</tt>
+ </p>
+ <p>
+ Beware however that if the following code were used instead to
+ read data in the case <tt>PLANARCONFIG_SEPARATE</tt>,...
+ </p>
+ <p style="margin-left: 40px">
+ <tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (row = 0; row &lt; imagelength; row++)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (s = 0; s &lt; nsamples; s++)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffreadscanline(tif, buf, row, s);</tt>
+ </p>
+ <p>
+ ...then problems would arise if <tt>RowsPerStrip</tt> was not one
+ because the order in which scanlines are requested would require
+ random access to data within strips (something that is not supported
+ by the library when strips are compressed).
+ </p>
+ <hr>
+ <h2 id="strips">Strip-oriented Image I/O</h2>
+ <p>
+ The strip-oriented interfaces provided by the library provide
+ access to entire strips of data. Unlike the scanline-oriented
+ calls, data can be read or written compressed or uncompressed.
+ Accessing data at a strip (or tile) level is often desirable
+ because there are no complications with regard to random access
+ to data within strips.
+ </p>
+ <p>
+ A simple example of reading an image by strips is:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main()<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen("myfile.tif", "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tdata_t buf;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tstrip_t strip;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf = _TIFFmalloc(TIFFStripSize(tif));<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (strip = 0; strip &lt; tiffnumberofstrips(tif); strip++)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffreadencodedstrip(tif, strip, buf, (tsize_t) -1);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_tifffree(buf);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffclose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ }</tt>
+ </p>
+ <p>
+ Notice how a strip size of <tt>-1</tt> is used; <tt>TIFFReadEncodedStrip</tt>
+ will calculate the appropriate size in this case.
+ </p>
+ <p>
+ The above code reads strips in the order in which the
+ data is physically stored in the file. If multiple samples
+ are present and data is stored with <tt>PLANARCONFIG_SEPARATE</tt>
+ then all the strips of data holding the first sample will be
+ read, followed by strips for the second sample, etc.
+ </p>
+ <p>
+ Finally, note that the last strip of data in an image may have fewer
+ rows in it than specified by the <tt>RowsPerStrip</tt> tag. A
+ reader should not assume that each decoded strip contains a full
+ set of rows in it.
+ </p>
+ <p>
+ The following is an example of how to read raw strips of data from
+ a file:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main()<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen("myfile.tif", "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tdata_t buf;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tstrip_t strip;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32* bc;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 stripsize;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &amp;bc);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stripsize = bc[0];<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf = _TIFFmalloc(stripsize);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (strip = 0; strip &lt; tiffnumberofstrips(tif); strip++) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (bc[strip] &gt; stripsize) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf = _TIFFrealloc(buf, bc[strip]);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;stripsize = bc[strip];<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFReadRawStrip(tif, strip, buf, bc[strip]);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_TIFFfree(buf);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFClose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ }</tt>
+ </p>
+ <p>
+ As above the strips are read in the order in which they are
+ physically stored in the file; this may be different from the
+ logical ordering expected by an application.
+ </p>
+ <hr>
+ <h2 id="tiles">Tile-oriented Image I/O</h2>
+ <p>
+ Tiles of data may be read and written in a manner similar to strips.
+ With this interface, an image is
+ broken up into a set of rectangular areas that may have dimensions
+ less than the image width and height. All the tiles
+ in an image have the same size, and the tile width and length must each
+ be a multiple of 16 pixels. Tiles are ordered left-to-right and
+ top-to-bottom in an image. As for scanlines, samples can be packed
+ contiguously or separately. When separated, all the tiles for a sample
+ are colocated in the file. That is, all the tiles for sample 0 appear
+ before the tiles for sample 1, etc.
+ </p>
+ <p>
+ Tiles and strips may also be extended in a z dimension to form
+ volumes. Data volumes are organized as "slices". That is, all the
+ data for a slice is colocated. Volumes whose data is organized in
+ tiles can also have a tile depth so that data can be organized in
+ cubes.
+ </p>
+ <p>
+ There are actually two interfaces for tiles.
+ One interface is similar to scanlines, to read a tiled image,
+ code of the following sort might be used:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>main()<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen("myfile.tif", "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 imageWidth, imageLength;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 tileWidth, tileLength;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;uint32 x, y;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tdata_t buf;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &amp;imageWidth);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &amp;imageLength);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_TILEWIDTH, &amp;tileWidth);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TIFFGetField(tif, TIFFTAG_TILELENGTH, &amp;tileLength);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf = _TIFFmalloc(TIFFTileSize(tif));<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (y = 0; y &lt; imagelength; y += tilelength)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (x = 0; x &lt; imagewidth; x += tilewidth)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffreadtile(tif, buf, x, y, 0);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_tifffree(buf);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffclose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ }</tt>
+ </p>
+ <p>
+ (once again, we assume samples are packed contiguously.)
+ </p>
+ <p>
+ Alternatively a direct interface to the low-level data is provided
+ a la strips. Tiles can be read with
+ <tt>TIFFReadEncodedTile</tt> or <tt>TIFFReadRawTile</tt>,
+ and written with <tt>TIFFWriteEncodedTile</tt> or
+ <tt>TIFFWriteRawTile</tt>. For example, to read all the tiles in an image:
+ </p>
+ <p style="margin-left: 40px">
+ <tt>#include "tiffio.h"<br>
+ main()<br>
+ {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;TIFF* tif = TIFFOpen("myfile.tif", "r");<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;if (tif) {<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tdata_t buf;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ttile_t tile;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buf = _TIFFmalloc(TIFFTileSize(tif));<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (tile = 0; tile &lt; tiffnumberoftiles(tif); tile++)<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffreadencodedtile(tif, tile, buf, (tsize_t) -1);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_tifffree(buf);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tiffclose(tif);<br>
+ &nbsp;&nbsp;&nbsp;&nbsp;}<br>
+ }</tt>
+ </p>
+ <hr>
+ <h2 id="other">Other Stuff</h2>
+ <p>
+ Some other stuff will almost certainly go here...
+ </p>
+ <hr>
+ <p>
+ Last updated: $Date: 2005/12/28 06:53:18 $
+ </p>
+</body>
+</html>
diff --git a/tiff/html/man/Makefile.am b/tiff/html/man/Makefile.am
new file mode 100644
index 0000000..c14c4db
--- /dev/null
+++ b/tiff/html/man/Makefile.am
@@ -0,0 +1,119 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+docdir = $(LIBTIFF_DOCDIR)/html/man
+MANSRCDIR = $(top_srcdir)/man
+HTMLMANDIR = $(top_srcdir)/html/man
+
+GROFF = groff -Thtml -mandoc
+ECHO = echo
+
+indexfile = index.html
+docfiles = \
+ libtiff.3tiff.html \
+ TIFFbuffer.3tiff.html \
+ TIFFClose.3tiff.html \
+ TIFFcodec.3tiff.html \
+ TIFFcolor.3tiff.html \
+ TIFFDataWidth.3tiff.html \
+ TIFFError.3tiff.html \
+ TIFFFlush.3tiff.html \
+ TIFFGetField.3tiff.html \
+ TIFFmemory.3tiff.html \
+ TIFFOpen.3tiff.html \
+ TIFFPrintDirectory.3tiff.html \
+ TIFFquery.3tiff.html \
+ TIFFReadDirectory.3tiff.html \
+ TIFFReadEncodedStrip.3tiff.html \
+ TIFFReadEncodedTile.3tiff.html \
+ TIFFReadRawStrip.3tiff.html \
+ TIFFReadRawTile.3tiff.html \
+ TIFFReadRGBAImage.3tiff.html \
+ TIFFReadRGBAStrip.3tiff.html \
+ TIFFReadRGBATile.3tiff.html \
+ TIFFReadScanline.3tiff.html \
+ TIFFReadTile.3tiff.html \
+ TIFFRGBAImage.3tiff.html \
+ TIFFSetDirectory.3tiff.html \
+ TIFFSetField.3tiff.html \
+ TIFFsize.3tiff.html \
+ TIFFstrip.3tiff.html \
+ TIFFswab.3tiff.html \
+ TIFFtile.3tiff.html \
+ TIFFWarning.3tiff.html \
+ TIFFWriteDirectory.3tiff.html \
+ TIFFWriteEncodedStrip.3tiff.html \
+ TIFFWriteEncodedTile.3tiff.html \
+ TIFFWriteRawStrip.3tiff.html \
+ TIFFWriteRawTile.3tiff.html \
+ TIFFWriteScanline.3tiff.html \
+ TIFFWriteTile.3tiff.html \
+ fax2ps.1.html \
+ fax2tiff.1.html \
+ gif2tiff.1.html \
+ pal2rgb.1.html \
+ ppm2tiff.1.html \
+ ras2tiff.1.html \
+ raw2tiff.1.html \
+ rgb2ycbcr.1.html \
+ sgi2tiff.1.html \
+ thumbnail.1.html \
+ tiff2bw.1.html \
+ tiff2pdf.1.html \
+ tiff2ps.1.html \
+ tiff2rgba.1.html \
+ tiffcmp.1.html \
+ tiffcp.1.html \
+ tiffcrop.1.html \
+ tiffdither.1.html \
+ tiffdump.1.html \
+ tiffgt.1.html \
+ tiffinfo.1.html \
+ tiffmedian.1.html \
+ tiffset.1.html \
+ tiffsplit.1.html \
+ tiffsv.1.html
+
+dist_doc_DATA = $(indexfile) $(docfiles)
+
+INDEXSTART = '<HTML><HEAD><TITLE>Libtiff HTML manpage index</TITLE></HEAD><BODY BGCOLOR=white><ul><H2>Man Pages</h2><p>'
+INDEXEND = '</ul></BODY></HTML>'
+
+.PHONY: index
+index:
+ ${ECHO} ${INDEXSTART} > $(indexfile)
+ for i in $(docfiles); do \
+ ${ECHO} '<li><A HREF='$$i'>'$$i'</a>' >> $(indexfile); \
+ done
+ ${ECHO} ${INDEXEND} >> $(indexfile)
+
+manpages = $(docfiles:.html=)
+
+.PHONY: htmldoc
+htmldoc:
+ for i in $(manpages); do \
+ ${GROFF} $(MANSRCDIR)/$$i > $(HTMLMANDIR)/$$i.html; \
+ done
+
diff --git a/tiff/html/man/Makefile.in b/tiff/html/man/Makefile.in
new file mode 100644
index 0000000..37d2c70
--- /dev/null
+++ b/tiff/html/man/Makefile.in
@@ -0,0 +1,556 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = html/man
+DIST_COMMON = $(dist_doc_DATA) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(docdir)"
+DATA = $(dist_doc_DATA)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = $(LIBTIFF_DOCDIR)/html/man
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+MANSRCDIR = $(top_srcdir)/man
+HTMLMANDIR = $(top_srcdir)/html/man
+GROFF = groff -Thtml -mandoc
+ECHO = echo
+indexfile = index.html
+docfiles = \
+ libtiff.3tiff.html \
+ TIFFbuffer.3tiff.html \
+ TIFFClose.3tiff.html \
+ TIFFcodec.3tiff.html \
+ TIFFcolor.3tiff.html \
+ TIFFDataWidth.3tiff.html \
+ TIFFError.3tiff.html \
+ TIFFFlush.3tiff.html \
+ TIFFGetField.3tiff.html \
+ TIFFmemory.3tiff.html \
+ TIFFOpen.3tiff.html \
+ TIFFPrintDirectory.3tiff.html \
+ TIFFquery.3tiff.html \
+ TIFFReadDirectory.3tiff.html \
+ TIFFReadEncodedStrip.3tiff.html \
+ TIFFReadEncodedTile.3tiff.html \
+ TIFFReadRawStrip.3tiff.html \
+ TIFFReadRawTile.3tiff.html \
+ TIFFReadRGBAImage.3tiff.html \
+ TIFFReadRGBAStrip.3tiff.html \
+ TIFFReadRGBATile.3tiff.html \
+ TIFFReadScanline.3tiff.html \
+ TIFFReadTile.3tiff.html \
+ TIFFRGBAImage.3tiff.html \
+ TIFFSetDirectory.3tiff.html \
+ TIFFSetField.3tiff.html \
+ TIFFsize.3tiff.html \
+ TIFFstrip.3tiff.html \
+ TIFFswab.3tiff.html \
+ TIFFtile.3tiff.html \
+ TIFFWarning.3tiff.html \
+ TIFFWriteDirectory.3tiff.html \
+ TIFFWriteEncodedStrip.3tiff.html \
+ TIFFWriteEncodedTile.3tiff.html \
+ TIFFWriteRawStrip.3tiff.html \
+ TIFFWriteRawTile.3tiff.html \
+ TIFFWriteScanline.3tiff.html \
+ TIFFWriteTile.3tiff.html \
+ fax2ps.1.html \
+ fax2tiff.1.html \
+ gif2tiff.1.html \
+ pal2rgb.1.html \
+ ppm2tiff.1.html \
+ ras2tiff.1.html \
+ raw2tiff.1.html \
+ rgb2ycbcr.1.html \
+ sgi2tiff.1.html \
+ thumbnail.1.html \
+ tiff2bw.1.html \
+ tiff2pdf.1.html \
+ tiff2ps.1.html \
+ tiff2rgba.1.html \
+ tiffcmp.1.html \
+ tiffcp.1.html \
+ tiffcrop.1.html \
+ tiffdither.1.html \
+ tiffdump.1.html \
+ tiffgt.1.html \
+ tiffinfo.1.html \
+ tiffmedian.1.html \
+ tiffset.1.html \
+ tiffsplit.1.html \
+ tiffsv.1.html
+
+dist_doc_DATA = $(indexfile) $(docfiles)
+INDEXSTART = '<HTML><HEAD><TITLE>Libtiff HTML manpage index</TITLE></HEAD><BODY BGCOLOR=white><ul><H2>Man Pages</h2><p>'
+INDEXEND = '</ul></BODY></HTML>'
+manpages = $(docfiles:.html=)
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign html/man/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign html/man/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)"
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(docdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(docdir)" && rm -f $$files
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ uninstall uninstall-am uninstall-dist_docDATA
+
+
+.PHONY: index
+index:
+ ${ECHO} ${INDEXSTART} > $(indexfile)
+ for i in $(docfiles); do \
+ ${ECHO} '<li><A HREF='$$i'>'$$i'</a>' >> $(indexfile); \
+ done
+ ${ECHO} ${INDEXEND} >> $(indexfile)
+
+.PHONY: htmldoc
+htmldoc:
+ for i in $(manpages); do \
+ ${GROFF} $(MANSRCDIR)/$$i > $(HTMLMANDIR)/$$i.html; \
+ done
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/html/man/TIFFClose.3tiff.html b/tiff/html/man/TIFFClose.3tiff.html
new file mode 100644
index 0000000..42e3ba8
--- /dev/null
+++ b/tiff/html/man/TIFFClose.3tiff.html
@@ -0,0 +1,87 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFClose</title>
+</head>
+<body>
+
+<h1 align=center>TIFFClose</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFClose &minus; close a previously opened
+<small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>void TIFFClose(TIFF *</b><i>tif</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFClose</i> closes a file that was previously opened
+with <b>TIFFOpen</b>(3TIFF). Any buffered data are flushed
+to the file, including the contents of the current directory
+(if modified); and all resources are reclaimed.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the routine. Likewise,
+warning messages are directed to the
+<b>TIFFWarning</b>(3TIFF) routine.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>libtiff</b>(3TIFF), <b>TIFFOpen</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFDataWidth.3tiff.html b/tiff/html/man/TIFFDataWidth.3tiff.html
new file mode 100644
index 0000000..237296e
--- /dev/null
+++ b/tiff/html/man/TIFFDataWidth.3tiff.html
@@ -0,0 +1,98 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFDataWidth</title>
+</head>
+<body>
+
+<h1 align=center>TIFFDataWidth</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFDataWidth &minus; Get the size of TIFF data types</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFDataWidth(TIFFDataType</b>
+<i>type</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFDataWidth</i> returns a size of <i>type</i> in
+bytes. Currently following data types are supported:<i><br>
+TIFF_BYTE<br>
+TIFF_ASCII<br>
+TIFF_SBYTE<br>
+TIFF_UNDEFINED<br>
+TIFF_SHORT<br>
+TIFF_SSHORT<br>
+TIFF_LONG<br>
+TIFF_SLONG<br>
+TIFF_FLOAT<br>
+TIFF_IFD<br>
+TIFF_RATIONAL<br>
+TIFF_SRATIONAL<br>
+TIFF_DOUBLE</i></p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFDataWidth</i> returns a number of bytes occupied
+by the item of given type. 0 returned when uknown data type
+supplied.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>libtiff</b>(3TIFF),</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFError.3tiff.html b/tiff/html/man/TIFFError.3tiff.html
new file mode 100644
index 0000000..5d39a13
--- /dev/null
+++ b/tiff/html/man/TIFFError.3tiff.html
@@ -0,0 +1,106 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFError</title>
+</head>
+<body>
+
+<h1 align=center>TIFFError</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFError, TIFFSetErrorHandler &minus; library error
+handling interface</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>void TIFFError(const char *</b><i>module</i><b>, const
+char *</b><i>fmt</i><b>,</b> <i>...</i><b>)</b></p>
+<!-- INDENTATION -->
+<p><b>#include &lt;stdarg.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>typedef void (*TIFFErrorHandler)(const char
+*</b><i>module</i><b>, const char *</b><i>fmt</i><b>,
+va_list</b> <i>ap</i><b>);<br>
+TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler
+handler);</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFError</i> invokes the library-wide error handling
+function to (normally) write an error message to the
+<b>stderr</b>. The <i>fmt</i> parameter is a
+<i>printf</i>(3S) format string, and any number arguments
+can be supplied. The <i>module</i> parameter, if non-zero,
+is printed before the message; it typically is used to
+identify the software module in which an error is
+detected.</p>
+<!-- INDENTATION -->
+<p>Applications that desire to capture control in the event
+of an error should use <i>TIFFSetErrorHandler</i> to
+override the default error handler. A <small>NULL</small>
+(0) error handling function may be installed to suppress
+error messages.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFSetErrorHandler</i> returns a reference to the
+previous error handling function.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFWarning</b>(3TIFF), <b>libtiff</b>(3TIFF),
+<b>printf</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFFlush.3tiff.html b/tiff/html/man/TIFFFlush.3tiff.html
new file mode 100644
index 0000000..f32ccd3
--- /dev/null
+++ b/tiff/html/man/TIFFFlush.3tiff.html
@@ -0,0 +1,113 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFFlush</title>
+</head>
+<body>
+
+<h1 align=center>TIFFFlush</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFFlush, TIFFFlushData &minus; flush pending writes to
+an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFFlush(TIFF *</b><i>tif</i><b>)<br>
+int TIFFFlushData(TIFF *</b><i>tif</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFFlush</i> causes any pending writes for the
+specified file (including writes for the current directory)
+to be done. In normal operation this call is never needed
+&minus; the library automatically does any flushing
+required.</p>
+<!-- INDENTATION -->
+<p><i>TIFFFlushData</i> flushes any pending image data for
+the specified file to be written out; directory-related data
+are not flushed. In normal operation this call is never
+needed &minus; the library automatically does any flushing
+required.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>0 is returned if an error is encountered, otherwise 1 is
+returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF),
+<b>TIFFWriteEncodedStrip</b>(3TIFF),
+<b>TIFFWriteEncodedTile</b>(3TIFF),
+<b>TIFFWriteRawStrip</b>(3TIFF),
+<b>TIFFWriteRawTile</b>(3TIFF),
+<b>TIFFWriteScanline</b>(3TIFF), <b>TIFFWriteTile</b>(3TIFF)
+<b>libtiff</b>(3TIFF),</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFGetField.3tiff.html b/tiff/html/man/TIFFGetField.3tiff.html
new file mode 100644
index 0000000..e644b1d
--- /dev/null
+++ b/tiff/html/man/TIFFGetField.3tiff.html
@@ -0,0 +1,1446 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFGetField</title>
+</head>
+<body>
+
+<h1 align=center>TIFFGetField</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#AUTOREGISTERED TAGS">AUTOREGISTERED TAGS</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFGetField, TIFFVGetField &minus; get the value(s) of a
+tag in an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFGetField(TIFF *</b><i>tif</i><b>, ttag_t</b>
+<i>tag</i><b>,</b> <i>...</i><b>)</b></p>
+<!-- INDENTATION -->
+<p><b>#include &lt;stdarg.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFVGetField(TIFF *</b><i>tif</i><b>, ttag_t</b>
+<i>tag</i><b>, va_list</b> <i>ap</i><b>)<br>
+int TIFFGetFieldDefaulted(TIFF *</b><i>tif</i><b>,
+ttag_t</b> <i>tag</i><b>,</b> <i>...</i><b>)<br>
+int TIFFVGetFieldDefaulted(TIFF *</b><i>tif</i><b>,
+ttag_t</b> <i>tag</i><b>, va_list</b> <i>ap</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFGetField</i> returns the value of a tag or
+pseudo-tag associated with the the current directory of the
+opened <small>TIFF</small> file <i>tif</i>. (A
+<i>pseudo-tag</i> is a parameter that is used to control the
+operation of the <small>TIFF</small> library but whose value
+is not read or written to the underlying file.) The file
+must have been previously opened with
+<i>TIFFOpen</i>(3TIFF). The tag is identified by <i>tag</i>,
+one of the values defined in the include file <b>tiff.h</b>
+(see also the table below). The type and number of values
+returned is dependent on the tag being requested. The
+programming interface uses a variable argument list as
+prescribed by the <i>stdarg</i>(3) interface. The returned
+values should only be interpreted if <i>TIFFGetField</i>
+returns 1.</p>
+<!-- INDENTATION -->
+<p><i>TIFFVGetField</i> is functionally equivalent to
+<i>TIFFGetField</i> except that it takes a pointer to a
+variable argument list. <i>TIFFVGetField</i> is useful for
+layering interfaces on top of the functionality provided by
+<i>TIFFGetField</i>.</p>
+<!-- INDENTATION -->
+<p><i>TIFFGetFieldDefaulted</i> and
+<i>TIFFVGetFieldDefaulted</i> are identical to
+<i>TIFFGetField</i> and <i>TIFFVGetField</i>, except that if
+a tag is not defined in the current directory and it has a
+default value, then the default value is returned.</p>
+<!-- INDENTATION -->
+<p>The tags understood by <i>libtiff(3TIFF),</i> the number
+of parameter values, and the types for the returned values
+are shown below. The data types are specified as in C and
+correspond to the types used to specify tag values to
+<i>TIFFSetField</i>(3TIFF). Remember that
+<i>TIFFGetField</i> returns parameter values, so all the
+listed data types are pointers to storage where values
+should be returned. Consult the <small>TIFF</small>
+specification (or relevant industry specification) for
+information on the meaning of each tag and their possible
+values.</p></td>
+</table>
+<!-- TABS -->
+
+<p><i>Tag Name Count Types Notes</i></p>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_ARTIST</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_BADFAXLINES</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_BITSPERSAMPLE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_CLEANFAXDATA</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_COLORMAP</p>
+</td>
+<td width="8%">
+
+<p>3</p>
+</td>
+<td width="23%">
+
+<p>uint16**</p>
+</td>
+<td width="17%">
+
+<p>1&lt;&lt;BitsPerSample arrays</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_COMPRESSION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_CONSECUTIVEBADFAXLINES</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_COPYRIGHT</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_DATATYPE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_DATETIME</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_DOCUMENTNAME</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_DOTRANGE</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_EXTRASAMPLES</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint16*,uint16**</p>
+</td>
+<td width="17%">
+
+<p>count &amp; types array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_FAXFILLFUNC</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>TIFFFaxFillFunc*</p>
+</td>
+<td width="17%">
+
+<p>G3/G4 compression pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_FAXMODE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>int*</p>
+</td>
+<td width="17%">
+
+<p>G3/G4 compression pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_FILLORDER</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_GROUP3OPTIONS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_GROUP4OPTIONS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_HALFTONEHINTS</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_HOSTCOMPUTER</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_ICCPROFILE</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint32*,void**</p>
+</td>
+<td width="17%">
+
+<p>count, profile data</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_IMAGEDEPTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_IMAGEDESCRIPTION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_IMAGELENGTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_IMAGEWIDTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_INKNAMES</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_INKSET</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_JPEGCOLORMODE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>int*</p>
+</td>
+<td width="17%">
+
+<p>JPEG pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_JPEGQUALITY</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>int*</p>
+</td>
+<td width="17%">
+
+<p>JPEG pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_JPEGTABLES</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint32*,void**</p>
+</td>
+<td width="17%">
+
+<p>count &amp; tables</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_JPEGTABLESMODE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>int*</p>
+</td>
+<td width="17%">
+
+<p>JPEG pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MAKE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MATTEING</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MAXSAMPLEVALUE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MINSAMPLEVALUE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MODEL</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_ORIENTATION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PAGENAME</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PAGENUMBER</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PHOTOMETRIC</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PHOTOSHOP</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint32*,void**</p>
+</td>
+<td width="17%">
+
+<p>count, data</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PLANARCONFIG</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PREDICTOR</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PRIMARYCHROMATICITIES</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>float**</p>
+</td>
+<td width="17%">
+
+<p>6-entry array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_REFERENCEBLACKWHITE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>float**</p>
+</td>
+<td width="17%">
+
+<p>2*SamplesPerPixel array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_RESOLUTIONUNIT</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_RICHTIFFIPTC</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint32*,void**</p>
+</td>
+<td width="17%">
+
+<p>count, data</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_ROWSPERSTRIP</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SAMPLEFORMAT</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SAMPLESPERPIXEL</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SMAXSAMPLEVALUE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>double*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SMINSAMPLEVALUE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>double*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SOFTWARE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_STONITS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>double**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_STRIPBYTECOUNTS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_STRIPOFFSETS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SUBFILETYPE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SUBIFD</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint16*,uint32**</p>
+</td>
+<td width="17%">
+
+<p>count &amp; offsets array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TARGETPRINTER</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>char**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_THRESHHOLDING</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TILEBYTECOUNTS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TILEDEPTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TILELENGTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TILEOFFSETS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32**</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TILEWIDTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint32*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TRANSFERFUNCTION</p>
+</td>
+<td width="8%">
+
+<p>1 or 3&dagger;</p>
+</td>
+<td width="23%"></td>
+<td width="17%">
+
+<p>uint16**1&lt;&lt;BitsPerSample entry arrays</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_WHITEPOINT</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>float**</p>
+</td>
+<td width="17%">
+
+<p>2-entry array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_XMLPACKET</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint32*,void**</p>
+</td>
+<td width="17%">
+
+<p>count, data</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_XPOSITION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>float*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_XRESOLUTION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>float*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YCBCRCOEFFICIENTS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>float**</p>
+</td>
+<td width="17%">
+
+<p>3-entry array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YCBCRPOSITIONING</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YCBCRSUBSAMPLING</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="23%">
+
+<p>uint16*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YPOSITION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>float*</p>
+</td>
+<td width="17%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YRESOLUTION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="23%">
+
+<p>float*&Dagger;</p>
+</td>
+<td width="17%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>&dagger; If <i>SamplesPerPixel</i> is one, then a single
+array is returned; otherwise three arrays are returned.<br>
+&Dagger; The contents of this field are quite complex. See
+<i>The ICC Profile Format Specification</i>, Annex B.3
+&quot;Embedding ICC Profiles in TIFF Files&quot; (available
+at http://www.color.org) for an explanation.</p>
+</td>
+</table>
+<a name="AUTOREGISTERED TAGS"></a>
+<h2>AUTOREGISTERED TAGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>If you can&rsquo;t find the tag in the table above that
+means this is unsupported tag. But you still be able to read
+it&rsquo;s value if you know the data type of that tag. For
+example, if you want to read the LONG value from the tag
+33424 and ASCII string from the tag 36867 you can use the
+following code:</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>uint16 count;
+void *data;
+
+TIFFGetField(tiff, 33424, &amp;count, &amp;data);
+printf(&quot;Tag %d: %d, count %d0, 33424, *(uint32 *)data, count);
+TIFFGetField(tiff, 36867, &amp;count, &amp;data);
+printf(&quot;Tag %d: %s, count %d0, 36867, (char *)data, count);
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>is not supported by <b>libtiff(3TIFF),</b> library</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>1 is returned if the tag is defined in the current
+directory; otherwise a 0 is returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>Unknown field, tag 0x%x</b>. An unknown tag was
+supplied.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFSetField</b>(3TIFF),
+<b>TIFFSetDirectory</b>(3TIFF),
+<b>TIFFReadDirectory</b>(3TIFF),
+<b>TIFFWriteDirectory</b>(3TIFF) <b>libtiff</b>(3TIFF),</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFOpen.3tiff.html b/tiff/html/man/TIFFOpen.3tiff.html
new file mode 100644
index 0000000..6bc85d8
--- /dev/null
+++ b/tiff/html/man/TIFFOpen.3tiff.html
@@ -0,0 +1,421 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFOpen</title>
+</head>
+<body>
+
+<h1 align=center>TIFFOpen</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#BYTE ORDER">BYTE ORDER</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFOpen, TIFFFdOpen, TIFFClientOpen &minus; open a
+<small>TIFF</small> file for reading or writing</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>TIFF* TIFFOpen(const char *</b><i>filename</i><b>,
+const char *</b><i>mode</i><b>)<br>
+TIFF* TIFFFdOpen(const int</b> <i>fd</i><b>, const char
+*</b><i>filename</i><b>, const char
+*</b><i>mode</i><b>)</b></p>
+<!-- INDENTATION -->
+<p><b>typedef tsize_t (*TIFFReadWriteProc)(thandle_t,
+tdata_t, tsize_t);<br>
+typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int);<br>
+typedef int (*TIFFCloseProc)(thandle_t);<br>
+typedef toff_t (*TIFFSizeProc)(thandle_t);<br>
+typedef int (*TIFFMapFileProc)(thandle_t, tdata_t*,
+toff_t*);<br>
+typedef void (*TIFFUnmapFileProc)(thandle_t, tdata_t,
+toff_t);</b></p>
+<!-- INDENTATION -->
+<p><b>TIFF* TIFFClientOpen(const char
+*</b><i>filename</i><b>, const char *</b><i>mode</i><b>,
+thandle_t</b> <i>clientdata</i><b>, TIFFReadWriteProc</b>
+<i>readproc</i><b>, TIFFReadWriteProc</b>
+<i>writeproc</i><b>, TIFFSeekProc</b> <i>seekproc</i><b>,
+TIFFCloseProc</b> <i>closeproc</i><b>, TIFFSizeProc</b>
+<i>sizeproc</i><b>, TIFFMapFileProc</b> <i>mapproc</i><b>,
+TIFFUnmapFileProc</b> <i>unmapproc</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFOpen</i> opens a <small>TIFF</small> file whose
+name is <i>filename</i> and returns a handle to be used in
+subsequent calls to routines in <i>libtiff</i>. If the open
+operation fails, then zero is returned. The <i>mode</i>
+parameter specifies if the file is to be opened for reading
+(&lsquo;&lsquo;r&rsquo;&rsquo;), writing
+(&lsquo;&lsquo;w&rsquo;&rsquo;), or appending
+(&lsquo;&lsquo;a&rsquo;&rsquo;) and, optionally, whether to
+override certain default aspects of library operation (see
+below). When a file is opened for appending, existing data
+will not be touched; instead new data will be written as
+additional subfiles. If an existing file is opened for
+writing, all previous data is overwritten.</p>
+<!-- INDENTATION -->
+<p>If a file is opened for reading, the first
+<small>TIFF</small> directory in the file is automatically
+read (also see <i>TIFFSetDirectory</i>(3TIFF) for reading
+directories other than the first). If a file is opened for
+writing or appending, a default directory is automatically
+created for writing subsequent data. This directory has all
+the default values specified in <small>TIFF</small> Revision
+6.0: <i>BitsPerSample</i>=1, <i>ThreshHolding</i>=bilevel
+art scan, <i>FillOrder</i>=1 (most significant bit of each
+data byte is filled first), <i>Orientation</i>=1 (the 0th
+row represents the visual top of the image, and the 0th
+column represents the visual left hand side),
+<i>SamplesPerPixel</i>=1, <i>RowsPerStrip</i>=infinity,
+<i>ResolutionUnit</i>=2 (inches), and <i>Compression</i>=1
+(no compression). To alter these values, or to define values
+for additional fields, <i>TIFFSetField</i>(3TIFF) must be
+used.</p>
+<!-- INDENTATION -->
+<p><i>TIFFFdOpen</i> is like <i>TIFFOpen</i> except that it
+opens a <small>TIFF</small> file given an open file
+descriptor <i>fd</i>. The file&rsquo;s name and mode must
+reflect that of the open descriptor. The object associated
+with the file descriptor <b>must support random
+access</b>.</p>
+<!-- INDENTATION -->
+<p><i>TIFFClientOpen</i> is like <i>TIFFOpen</i> except that
+the caller supplies a collection of functions that the
+library will use to do <small>UNIX</small> -like I/O
+operations. The <i>readproc</i> and <i>writeproc</i> are
+called to read and write data at the current file position.
+<i>seekproc</i> is called to change the current file
+position a la <i>lseek</i>(2). <i>closeproc</i> is invoked
+to release any resources associated with an open file.
+<i>sizeproc</i> is invoked to obtain the size in bytes of a
+file. <i>mapproc</i> and <i>unmapproc</i> are called to map
+and unmap a file&rsquo;s contents in memory; c.f.
+<i>mmap</i>(2) and <i>munmap</i>(2). The <i>clientdata</i>
+parameter is an opaque &lsquo;&lsquo;handle&rsquo;&rsquo;
+passed to the client-specified routines passed as parameters
+to <i>TIFFClientOpen</i>.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The open mode parameter can include the following flags
+in addition to the &lsquo;&lsquo;r&rsquo;&rsquo;,
+&lsquo;&lsquo;w&rsquo;&rsquo;, and
+&lsquo;&lsquo;a&rsquo;&rsquo; flags. Note however that
+option flags must follow the read-write-append
+specification.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>l</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>When creating a new file force information be written
+with Little-Endian byte order (but see below). By default
+the library will create new files using the native
+<small>CPU</small> byte order.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>b</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>When creating a new file force information be written
+with Big-Endian byte order (but see below). By default the
+library will create new files using the native
+<small>CPU</small> byte order.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>L</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Force image data that is read or written to be treated
+with bits filled from Least Significant Bit (
+<small>LSB</small> ) to Most Significant Bit (
+<small>MSB</small> ). Note that this is the opposite to the
+way the library has worked from its inception.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>B</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Force image data that is read or written to be treated
+with bits filled from Most Significant Bit (
+<small>MSB</small> ) to Least Significant Bit (
+<small>LSB</small> ); this is the default.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>H</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Force image data that is read or written to be treated
+with bits filled in the same order as the native
+<small>CPU.</small></p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>M</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Enable the use of memory-mapped files for images opened
+read-only. If the underlying system does not support
+memory-mapped files or if the specific image being opened
+cannot be memory-mapped then the library will fallback to
+using the normal system interface for reading information.
+By default the library will attempt to use memory-mapped
+files.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>m</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Disable the use of memory-mapped files.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>C</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Enable the use of &lsquo;&lsquo;strip
+chopping&rsquo;&rsquo; when reading images that are
+comprised of a single strip or tile of uncompressed data.
+Strip chopping is a mechanism by which the library will
+automatically convert the single-strip image to multiple
+strips, each of which has about 8 Kilobytes of data. This
+facility can be useful in reducing the amount of memory used
+to read an image because the library normally reads each
+strip in its entirety. Strip chopping does however alter the
+apparent contents of the image because when an image is
+divided into multiple strips it looks as though the
+underlying file contains multiple separate strips. Finally,
+note that default handling of strip chopping is a
+compile-time configuration parameter. The default behaviour,
+for backwards compatibility, is to enable strip
+chopping.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>c</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Disable the use of strip chopping when reading
+images.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>h</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Read TIFF header only, do not load the first image
+directory. That could be useful in case of the broken first
+directory. We can open the file and proceed to the other
+directories.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="BYTE ORDER"></a>
+<h2>BYTE ORDER</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The <small>TIFF</small> specification (<b>all
+versions</b>) states that compliant readers <i>must be
+capable of reading images written in either byte order</i>.
+Nonetheless some software that claims to support the reading
+of <small>TIFF</small> images is incapable of reading images
+in anything but the native <small>CPU</small> byte order on
+which the software was written. (Especially notorious are
+applications written to run on Intel-based machines.) By
+default the library will create new files with the native
+byte-order of the <small>CPU</small> on which the
+application is run. This ensures optimal performance and is
+portable to any application that conforms to the TIFF
+specification. To force the library to use a specific
+byte-order when creating a new file the
+&lsquo;&lsquo;b&rsquo;&rsquo; and
+&lsquo;&lsquo;l&rsquo;&rsquo; option flags may be included
+in the call to open a file; for example,
+&lsquo;&lsquo;wb&rsquo;&rsquo; or
+&lsquo;&lsquo;wl&rsquo;&rsquo;.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Upon successful completion <i>TIFFOpen</i>,
+<i>TIFFFdOpen</i>, and <i>TIFFClientOpen</i> return a
+<small>TIFF</small> pointer. Otherwise, NULL is
+returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine. Likewise, warning messages
+are directed to the <i>TIFFWarning</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>&quot;%s&quot;: Bad mode</b>. The specified
+<i>mode</i> parameter was not one of
+&lsquo;&lsquo;r&rsquo;&rsquo; (read),
+&lsquo;&lsquo;w&rsquo;&rsquo; (write), or
+&lsquo;&lsquo;a&rsquo;&rsquo; (append).</p>
+<!-- INDENTATION -->
+<p><b>%s: Cannot open</b>. <i>TIFFOpen</i>() was unable to
+open the specified filename for read/writing.</p>
+<!-- INDENTATION -->
+<p><b>Cannot read TIFF header</b>. An error occurred while
+attempting to read the header information.</p>
+<!-- INDENTATION -->
+<p><b>Error writing TIFF header</b>. An error occurred while
+writing the default header information for a new file.</p>
+<!-- INDENTATION -->
+<p><b>Not a TIFF file, bad magic number %d (0x%x)</b>. The
+magic number in the header was not (hex) 0x4d4d or (hex)
+0x4949.</p>
+<!-- INDENTATION -->
+<p><b>Not a TIFF file, bad version number %d (0x%x)</b>. The
+version field in the header was not 42 (decimal).</p>
+<!-- INDENTATION -->
+<p><b>Cannot append to file that has opposite byte
+ordering</b>. A file with a byte ordering opposite to the
+native byte ordering of the current machine was opened for
+appending (&lsquo;&lsquo;a&rsquo;&rsquo;). This is a
+limitation of the library.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>libtiff</i>(3TIFF), <i>TIFFClose</i>(3TIFF)</p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFPrintDirectory.3tiff.html b/tiff/html/man/TIFFPrintDirectory.3tiff.html
new file mode 100644
index 0000000..a5f418a
--- /dev/null
+++ b/tiff/html/man/TIFFPrintDirectory.3tiff.html
@@ -0,0 +1,225 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFPrintDirectory</title>
+</head>
+<body>
+
+<h1 align=center>TIFFPrintDirectory</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFPrintDirectory &minus; print a description of a
+<small>TIFF</small> directory</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>void TIFFPrintDirectory(TIFF *</b><i>tif</i><b>, FILE
+*</b><i>fd</i><b>, long</b> <i>flags</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFPrintDirectory</i> prints a description of the
+current directory in the specified <small>TIFF</small> file
+to the standard I/O output stream <i>fd</i>. The
+<i>flags</i> parameter is used to control the <i>level of
+detail</i> of the printed information; it is a bit-or of the
+flags defined in <b>tiffio.h</b>:</p></td>
+</table>
+<!-- TABS -->
+
+<p>#define TIFFPRINT_NONE 0x0 /* no extra info */</p>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="1%">
+
+<p>#define</p>
+</td>
+<td width="30%">
+
+<p>TIFFPRINT_STRIPS</p>
+</td>
+<td width="10%">
+
+<p>0x1</p>
+</td>
+<td width="48%">
+
+<p>/* strips/tiles info */</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="1%">
+
+<p>#define</p>
+</td>
+<td width="30%">
+
+<p>TIFFPRINT_CURVES</p>
+</td>
+<td width="10%">
+
+<p>0x2</p>
+</td>
+<td width="48%">
+
+<p>/* color/gray response curves */</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="1%">
+
+<p>#define</p>
+</td>
+<td width="30%">
+
+<p>TIFFPRINT_COLORMAP</p>
+</td>
+<td width="10%">
+
+<p>0x4</p>
+</td>
+<td width="48%">
+
+<p>/* colormap */</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="1%">
+
+<p>#define</p>
+</td>
+<td width="30%">
+
+<p>TIFFPRINT_JPEGQTABLES</p>
+</td>
+<td width="10%">
+
+<p>0x100</p>
+</td>
+<td width="48%">
+
+<p>/* JPEG Q matrices */</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="1%">
+
+<p>#define</p>
+</td>
+<td width="30%">
+
+<p>TIFFPRINT_JPEGACTABLES</p>
+</td>
+<td width="10%">
+
+<p>0x200</p>
+</td>
+<td width="48%">
+
+<p>/* JPEG AC tables */</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="1%">
+
+<p>#define</p>
+</td>
+<td width="30%">
+
+<p>TIFFPRINT_JPEGDCTABLES</p>
+</td>
+<td width="10%">
+
+<p>0x200</p>
+</td>
+<td width="48%">
+
+<p>/* JPEG DC tables */</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>In C++ the <i>flags</i> parameter defaults to 0.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>libtiff</i>(3TIFF), <i>TIFFOpen</i>(3TIFF),
+<i>TIFFReadDirectory</i>(3TIFF),
+<i>TIFFSetDirectory</i>(3TIFF)</p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFRGBAImage.3tiff.html b/tiff/html/man/TIFFRGBAImage.3tiff.html
new file mode 100644
index 0000000..7bbee0f
--- /dev/null
+++ b/tiff/html/man/TIFFRGBAImage.3tiff.html
@@ -0,0 +1,319 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFRGBAImage</title>
+</head>
+<body>
+
+<h1 align=center>TIFFRGBAImage</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#ALTERNATE RASTER FORMATS">ALTERNATE RASTER FORMATS</a><br>
+<a href="#SIMULTANEOUS RASTER STORE AND DISPLAY">SIMULTANEOUS RASTER STORE AND DISPLAY</a><br>
+<a href="#SUPPORTING ADDITIONAL TIFF FORMATS">SUPPORTING ADDITIONAL TIFF FORMATS</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFRGBAImageOK, TIFFRGBAImageBegin, TIFFRGBAImageGet,
+TIFFRGBAImageEnd &minus; read and decode an image into a
+raster</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>typedef unsigned char TIFFRGBValue; typedef struct
+_TIFFRGBAImage TIFFRGBAImage;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFRGBAImageOK(TIFF *</b><i>tif</i><b>, char</b>
+<i>emsg[1024]</i><b>)<br>
+int TIFFRGBAImageBegin(TIFFRGBAImage *</b><i>img</i><b>,
+TIFF*</b> <i>tif</i><b>, int</b> <i>stopOnError</i><b>,
+char</b> <i>emsg[1024]</i><b>)<br>
+int TIFFRGBAImageGet(TIFFRGBAImage *</b><i>img</i><b>,
+uint32*</b> <i>raster</i><b>, uint32</b> <i>width</i> <b>,
+uint32</b> <i>height</i><b>)<br>
+void TIFFRGBAImageEnd(TIFFRGBAImage
+*</b><i>img</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The routines described here provide a high-level
+interface through which <small>TIFF</small> images may be
+read into memory. Images may be strip- or tile-based and
+have a variety of different characteristics: bits/sample,
+samples/pixel, photometric, etc. Decoding state is
+encapsulated in a <i>TIFFRGBAImage</i> structure making it
+possible to capture state for multiple images and quickly
+switch between them. The target raster format can be
+customized to a particular application&rsquo;s needs by
+installing custom routines that manipulate image data
+according to application requirements.</p>
+<!-- INDENTATION -->
+<p>The default usage for these routines is: check if an
+image can be processed using <i>TIFFRGBAImageOK</i>,
+construct a decoder state block using
+<i>TIFFRGBAImageBegin</i>, read and decode an image into a
+target raster using <i>TIFFRGBAImageGet</i>, and then
+release resources using <i>TIFFRGBAImageEnd</i>.
+<i>TIFFRGBAImageGet</i> can be called multiple times to
+decode an image using different state parameters. If
+multiple images are to be displayed and there is not enough
+space for each of the decoded rasters, multiple state blocks
+can be managed and then calls can be made to
+<i>TIFFRGBAImageGet</i> as needed to display an image.</p>
+<!-- INDENTATION -->
+<p>The generated raster is assumed to be an array of
+<i>width</i> times <i>height</i> 32-bit entries, where
+<i>width</i> must be less than or equal to the width of the
+image (<i>height</i> may be any non-zero size). If the
+raster dimensions are smaller than the image, the image data
+is cropped to the raster bounds. If the raster height is
+greater than that of the image, then the image data are
+placed in the lower part of the raster. (Note that the
+raster is assume to be organized such that the pixel at
+location (<i>x</i>,<i>y</i>) is
+<i>raster</i>[<i>y</i>*<i>width</i>+<i>x</i>]; with the
+raster origin in the <b>lower-left</b> hand corner.)</p>
+<!-- INDENTATION -->
+<p>Raster pixels are 8-bit packed red, green, blue, alpha
+samples. The macros <i>TIFFGetR</i>, <i>TIFFGetG</i>,
+<i>TIFFGetB</i>, and <i>TIFFGetA</i> should be used to
+access individual samples. Images without Associated Alpha
+matting information have a constant Alpha of 1.0 (255).</p>
+<!-- INDENTATION -->
+<p><i>TIFFRGBAImageGet</i> converts non-8-bit images by
+scaling sample values. Palette, grayscale, bilevel,
+<small>CMYK</small> , and YCbCr images are converted to
+<small>RGB</small> transparently. Raster pixels are returned
+uncorrected by any colorimetry information present in the
+directory.</p>
+<!-- INDENTATION -->
+<p>The parameter <i>stopOnError</i> specifies how to act if
+an error is encountered while reading the image. If
+<i>stopOnError</i> is non-zero, then an error will terminate
+the operation; otherwise <i>TIFFRGBAImageGet</i> will
+continue processing data until all the possible data in the
+image have been requested.</p>
+</td>
+</table>
+<a name="ALTERNATE RASTER FORMATS"></a>
+<h2>ALTERNATE RASTER FORMATS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>To use the core support for reading and processing
+<small>TIFF</small> images, but write the resulting raster
+data in a different format one need only override the
+&lsquo;&lsquo;<i>put methods</i>&rsquo;&rsquo; used to store
+raster data. These methods are are defined in the
+<i>TIFFRGBAImage</i> structure and initially setup by
+<i>TIFFRGBAImageBegin</i> to point to routines that pack
+raster data in the default <small>ABGR</small> pixel format.
+Two different routines are used according to the physical
+organization of the image data in the file:
+<i>PlanarConfiguration</i>=1 (packed samples), and
+<i>PlanarConfiguration</i>=2 (separated samples). Note that
+this mechanism can be used to transform the data before
+storing it in the raster. For example one can convert data
+to colormap indices for display on a colormap display.</p>
+</td>
+</table>
+<a name="SIMULTANEOUS RASTER STORE AND DISPLAY"></a>
+<h2>SIMULTANEOUS RASTER STORE AND DISPLAY</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>It is simple to display an image as it is being read into
+memory by overriding the put methods as described above for
+supporting alternate raster formats. Simply keep a reference
+to the default put methods setup by
+<i>TIFFRGBAImageBegin</i> and then invoke them before or
+after each display operation. For example, the
+<i>tiffgt</i>(1) utility uses the following put method to
+update the display as the raster is being filled:</p>
+<!-- INDENTATION -->
+<pre>static void
+putContigAndDraw(TIFFRGBAImage* img, uint32* raster,
+ uint32 x, uint32 y, uint32 w, uint32 h,
+ int32 fromskew, int32 toskew,
+ unsigned char* cp)
+{
+ (*putContig)(img, raster, x, y, w, h, fromskew, toskew, cp);
+ if (x+w == width) {
+ w = width;
+ if (img-&gt;orientation == ORIENTATION_TOPLEFT)
+ lrectwrite(0, y-(h-1), w-1, y, raster-x-(h-1)*w);
+ else
+ lrectwrite(0, y, w-1, y+h-1, raster);
+ }
+}
+</pre>
+<!-- INDENTATION -->
+<p>(the original routine provided by the library is saved in
+the variable <i>putContig</i>.)</p>
+</td>
+</table>
+<a name="SUPPORTING ADDITIONAL TIFF FORMATS"></a>
+<h2>SUPPORTING ADDITIONAL TIFF FORMATS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The <i>TIFFRGBAImage</i> routines support the most
+commonly encountered flavors of <small>TIFF.</small> It is
+possible to extend this support by overriding the
+&lsquo;&lsquo;<i>get method</i>&rsquo;&rsquo; invoked by
+<i>TIFFRGBAImageGet</i> to read <small>TIFF</small> image
+data. Details of doing this are a bit involved, it is best
+to make a copy of an existing get method and modify it to
+suit the needs of an application.</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Samples must be either 1, 2, 4, 8, or 16 bits.
+Colorimetric samples/pixel must be either 1, 3, or 4 (i.e.
+<i>SamplesPerPixel</i> minus <i>ExtraSamples</i>).</p>
+<!-- INDENTATION -->
+<p>Palette image colormaps that appear to be incorrectly
+written as 8-bit values are automatically scaled to
+16-bits.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All routines return 1 if the operation was successful.
+Otherwise, 0 is returned if an error was encountered and
+<i>stopOnError</i> is zero.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>Sorry, can not handle %d-bit pictures</b>. The image
+had <i>BitsPerSample</i> other than 1, 2, 4, 8, or 16.</p>
+<!-- INDENTATION -->
+<p><b>Sorry, can not handle %d-channel images</b>. The image
+had <i>SamplesPerPixel</i> other than 1, 3, or 4.</p>
+<!-- INDENTATION -->
+<p><b>Missing needed &quot;PhotometricInterpretation&quot;
+tag</b>. The image did not have a tag that describes how to
+display the data.</p>
+<!-- INDENTATION -->
+<p><b>No &quot;PhotometricInterpretation&quot; tag, assuming
+RGB</b>. The image was missing a tag that describes how to
+display it, but because it has 3 or 4 samples/pixel, it is
+assumed to be <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>No &quot;PhotometricInterpretation&quot; tag, assuming
+min-is-black</b>. The image was missing a tag that describes
+how to display it, but because it has 1 sample/pixel, it is
+assumed to be a grayscale or bilevel image.</p>
+<!-- INDENTATION -->
+<p><b>No space for photometric conversion table</b>. There
+was insufficient memory for a table used to convert image
+samples to 8-bit <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>Missing required &quot;Colormap&quot; tag</b>. A
+Palette image did not have a required <i>Colormap</i>
+tag.</p>
+<!-- INDENTATION -->
+<p><b>No space for tile buffer</b>. There was insufficient
+memory to allocate an i/o buffer.</p>
+<!-- INDENTATION -->
+<p><b>No space for strip buffer</b>. There was insufficient
+memory to allocate an i/o buffer.</p>
+<!-- INDENTATION -->
+<p><b>Can not handle format</b>. The image has a format
+(combination of <i>BitsPerSample</i>,
+<i>SamplesPerPixel</i>, and
+<i>PhotometricInterpretation</i>) that can not be
+handled.</p>
+<!-- INDENTATION -->
+<p><b>No space for B&amp;W mapping table</b>. There was
+insufficient memory to allocate a table used to map
+grayscale data to <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>No space for Palette mapping table</b>. There was
+insufficient memory to allocate a table used to map data to
+8-bit <small>RGB.</small></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFReadRGBAImage</b>(3TIFF),
+<b>TIFFReadRGBAImageOriented</b>(3TIFF),
+<b>TIFFReadRGBAStrip</b>(3TIFF),
+<b>TIFFReadRGBATile</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadDirectory.3tiff.html b/tiff/html/man/TIFFReadDirectory.3tiff.html
new file mode 100644
index 0000000..5bb828e
--- /dev/null
+++ b/tiff/html/man/TIFFReadDirectory.3tiff.html
@@ -0,0 +1,218 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadDirectory</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadDirectory</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>TIFFReadDirectory &minus; get the contents of the
+next directory in an open</big> TIFF <big>file</big></p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>#include &lt;tiffio.h&gt;</b></big></p>
+<!-- INDENTATION -->
+<p><big><b>int TIFFReadDirectory(TIFF
+*</b><i>tif</i><b>)</b></big></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>Read the next directory in the specified file and
+make it the current directory. Applications only need to
+call <i>TIFFReadDirectory</i> to read multiple subfiles in a
+single</big> TIFF <big>file&mdash; the first directory in a
+file is automatically read when <i>TIFFOpen</i> is
+called.</big></p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>If the library is compiled with</big>
+STRIPCHOP_SUPPORT <big>enabled, then images that have a
+single uncompressed strip or tile of data are automatically
+treated as if they were made up of multiple strips or tiles
+of approximately 8 kilobytes each. This operation is done
+only in-memory; it does not alter the contents of the file.
+However, the construction of the &lsquo;&lsquo;chopped
+strips&rsquo;&rsquo; is visible to the application through
+the number of strips [tiles] returned by
+<i>TIFFNumberOfStrips</i>
+[<i>TIFFNumberOfTiles</i>].</big></p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>If the next directory was successfully read, 1 is
+returned. Otherwise, 0 is returned if an error was
+encountered, or if there are no more directories to be
+read.</big></p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine. All warning messages are
+directed to the <i>TIFFWarning</i>(3TIFF) routine.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Seek error accessing TIFF directory</b>. An error
+occurred while positioning to the location of the
+directory.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Wrong data type %d for field &quot;%s&quot;</b>.
+The tag entry in the directory had an incorrect data type.
+For example, an <i>ImageDescription</i> tag with a</big>
+SHORT <big>data type.</big></p>
+<!-- INDENTATION -->
+<p><big><b>TIFF directory is missing required &quot;%s&quot;
+field</b>. The specified tag is required to be present by
+the</big> TIFF <big>5.0 specification, but is missing. The
+directory is (usually) unusable.</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: Rational with zero denominator</b>. A
+directory tag has a</big> RATIONAL <big>value whose
+denominator is zero.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Incorrect count %d for field &quot;%s&quot; (%lu,
+expecting %lu); tag ignored</b>. The specified tag&rsquo;s
+count field is bad. For example, a count other than 1 for a
+<i>SubFileType</i> tag.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Cannot handle different per-sample values for
+field &quot;%s&quot;</b>. The tag has <i>SamplesPerPixel</i>
+values and they are not all the same; e.g.
+<i>BitsPerSample</i>. The library is unable to handle images
+of this sort.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Count mismatch for field &quot;%s&quot;;
+expecting %d, got %d</b>. The count field in a tag does not
+agree with the number expected by the library. This should
+never happen, so if it does, the library refuses to read the
+directory.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Invalid TIFF directory; tags are not sorted in
+ascending order</b>. The directory tags are not properly
+sorted as specified in the</big> TIFF <big>5.0
+specification. This error is not fatal.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Ignoring unknown field with tag %d (0x%x)</b>. An
+unknown tag was encountered in the directory; the library
+ignores all such tags.</big></p>
+<!-- INDENTATION -->
+<p><big><b>TIFF directory is missing requred
+&quot;ImageLength&quot; field</b>. The image violates the
+specification by not having a necessary field. There is no
+way for the library to recover from this error.</big></p>
+<!-- INDENTATION -->
+<p><big><b>TIFF directory is missing requred
+&quot;PlanarConfig&quot; field</b>. The image violates the
+specification by not having a necessary field. There is no
+way for the library to recover from this error.</big></p>
+<!-- INDENTATION -->
+<p><big><b>TIFF directory is missing requred
+&quot;StripOffsets&quot; field</b>. The image has multiple
+strips, but is missing the tag that specifies the file
+offset to each strip of data. There is no way for the
+library to recover from this error.</big></p>
+<!-- INDENTATION -->
+<p><big><b>TIFF directory is missing requred
+&quot;TileOffsets&quot; field</b>. The image has multiple
+tiles, but is missing the tag that specifies the file offset
+to each tile of data. There is no way for the library to
+recover from this error.</big></p>
+<!-- INDENTATION -->
+<p><big><b>TIFF directory is missing required
+&quot;StripByteCounts&quot; field</b>. The image has
+multiple strips, but is missing the tag that specifies the
+size of each strip of data. There is no way for the library
+to recover from this error.</big></p>
+<!-- INDENTATION -->
+<p><big><b>TIFF directory is missing required
+&quot;StripByteCounts&quot; field, calculating from
+imagelength</b>. The image violates the specification by not
+having a necessary field. However, when the image is
+comprised of only one strip or tile, the library will
+estimate the missing value based on the file size.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Bogus &quot;StripByteCounts&quot; field, ignoring
+and calculating from imagelength</b>. Certain vendors
+violate the specification by writing zero for the
+StripByteCounts tag when they want to leave the value
+unspecified. If the image has a single strip, the library
+will estimate the missing value based on the file
+size.</big></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFOpen</b>(3TIFF),
+<b>TIFFWriteDirectory</b>(3TIFF),
+<b>TIFFSetDirectory</b>(3TIFF),
+<b>TIFFSetSubDirectory</b>(3TIFF),
+<b>libtiff</b>(3TIFF)</big></p>
+<!-- INDENTATION -->
+<p><big>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></big></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadEncodedStrip.3tiff.html b/tiff/html/man/TIFFReadEncodedStrip.3tiff.html
new file mode 100644
index 0000000..39d411d
--- /dev/null
+++ b/tiff/html/man/TIFFReadEncodedStrip.3tiff.html
@@ -0,0 +1,133 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadEncodedStrip</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadEncodedStrip</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>TIFFReadEncodedStrip &minus; read and decode a strip
+of data from an open</big> TIFF <big>file</big></p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>#include &lt;tiffio.h&gt;</b></big></p>
+<!-- INDENTATION -->
+<p><big><b>tsize_t TIFFReadEncodedStrip(TIFF
+*</b><i>tif</i><b>, tstrip_t</b> <i>strip</i><b>,
+tdata_t</b> <i>buf</i><b>, tsize_t</b>
+<i>size</i><b>)</b></big></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>Read the specified strip of data and place up to
+<i>size</i> bytes of decompressed information in the (user
+supplied) data buffer.</big></p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>The value of <i>strip</i> is a &lsquo;&lsquo;raw
+strip number.&rsquo;&rsquo; That is, the caller must take
+into account whether or not the data are organized in
+separate planes (<i>PlanarConfiguration</i>=2). To read a
+full strip of data the data buffer should typically be at
+least as large as the number returned by
+<b>TIFFStripSize</b>(3TIFF). If the -1 passed in <i>size</i>
+parameter, the whole strip will be read. You should be sure
+you have enough space allocated for the buffer.</big></p>
+<!-- INDENTATION -->
+<p><big>The library attempts to hide bit- and byte-ordering
+differences between the image and the native machine by
+converting data to the native machine order. Bit reversal is
+done if the <i>FillOrder</i> tag is opposite to the native
+machine bit order. 16- and 32-bit samples are automatically
+byte-swapped if the file was written with a byte order
+opposite to the native machine byte order,</big></p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>The actual number of bytes of data that were placed
+in <i>buf</i> is returned; <i>TIFFReadEncodedStrip</i>
+returns &minus;1 if an error was encountered.</big></p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</big></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFOpen</b>(3TIFF),
+<b>TIFFReadRawStrip</b>(3TIFF),
+<b>TIFFReadScanline</b>(3TIFF),
+<b>libtiff</b>(3TIFF)</big></p>
+<!-- INDENTATION -->
+<p><big>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></big></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadEncodedTile.3tiff.html b/tiff/html/man/TIFFReadEncodedTile.3tiff.html
new file mode 100644
index 0000000..752b1ea
--- /dev/null
+++ b/tiff/html/man/TIFFReadEncodedTile.3tiff.html
@@ -0,0 +1,130 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadEncodedTile</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadEncodedTile</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadEncodedTile &minus; read and decode a tile of
+data from an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFReadEncodedTile(TIFF *</b><i>tif</i><b>,
+ttile_t</b> <i>tile</i><b>, tdata_t</b> <i>buf</i><b>,
+tsize_t</b> <i>size</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Read the specified tile of data and place up to
+<i>size</i> bytes of decompressed information in the (user
+supplied) data buffer.</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The value of <i>tile</i> is a &lsquo;&lsquo;raw tile
+number.&rsquo;&rsquo; That is, the caller must take into
+account whether or not the data are organized in separate
+planes (<i>PlanarConfiguration</i>=2).
+<i>TIFFComputeTile</i> automatically does this when
+converting an (x,y,z,sample) coordinate quadruple to a tile
+number. To read a full tile of data the data buffer should
+be at least as large as the value returned by
+<i>TIFFTileSize</i>.</p>
+<!-- INDENTATION -->
+<p>The library attempts to hide bit- and byte-ordering
+differences between the image and the native machine by
+converting data to the native machine order. Bit reversal is
+done if the <i>FillOrder</i> tag is opposite to the native
+machine bit order. 16- and 32-bit samples are automatically
+byte-swapped if the file was written with a byte order
+opposite to the native machine byte order,</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The actual number of bytes of data that were placed in
+<i>buf</i> is returned; <i>TIFFReadEncodedTile</i> returns
+&minus;1 if an error was encountered.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFReadRawTile</b>(3TIFF),
+<b>TIFFReadTile</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadRGBAImage.3tiff.html b/tiff/html/man/TIFFReadRGBAImage.3tiff.html
new file mode 100644
index 0000000..165284e
--- /dev/null
+++ b/tiff/html/man/TIFFReadRGBAImage.3tiff.html
@@ -0,0 +1,301 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadRGBAImage</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadRGBAImage</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadRGBAImage, TIFFReadRGBAImageOriented &minus; read
+and decode an image into a fixed-format raster</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>#define TIFFGetR(abgr) ((abgr) &amp; 0xff)<br>
+#define TIFFGetG(abgr) (((abgr) &gt;&gt; 8) &amp; 0xff)<br>
+#define TIFFGetB(abgr) (((abgr) &gt;&gt; 16) &amp; 0xff)<br>
+#define TIFFGetA(abgr) (((abgr) &gt;&gt; 24) &amp;
+0xff)</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFReadRGBAImage(TIFF *</b><i>tif</i><b>,
+uint32</b> <i>width</i><b>, uint32</b> <i>height</i><b>,
+uint32 *</b><i>raster</i><b>, int</b>
+<i>stopOnError</i><b>)<br>
+int TIFFReadRGBAImageOriented(TIFF *</b><i>tif</i><b>,
+uint32</b> <i>width</i><b>, uint32</b> <i>height</i><b>,
+uint32 *</b><i>raster</i><b>, int</b> <i>orientation</i><b>,
+int</b> <i>stopOnError</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFReadRGBAImage</i> reads a strip- or tile-based
+image into memory, storing the result in the user supplied
+<i>raster</i>. The raster is assumed to be an array of
+<i>width</i> times <i>height</i> 32-bit entries, where
+<i>width</i> must be less than or equal to the width of the
+image (<i>height</i> may be any non-zero size). If the
+raster dimensions are smaller than the image, the image data
+is cropped to the raster bounds. If the raster height is
+greater than that of the image, then the image data are
+placed in the lower part of the raster. (Note that the
+raster is assume to be organized such that the pixel at
+location (<i>x</i>,<i>y</i>) is
+<i>raster</i>[<i>y</i>*<i>width</i>+<i>x</i>]; with the
+raster origin in the lower-left hand corner.)</p>
+<!-- INDENTATION -->
+<p><i>TIFFReadRGBAImageOriented</i> works like
+<i>TIFFReadRGBAImage</i> with except of that user can
+specify the raster origin position with the
+<i>orientation</i> parameter. Four orientations
+supported:</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>ORIENTATION_TOPLEFT</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>origin in top-left corner,</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>ORIENTATION_TOPRIGHT</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>origin in top-right corner,</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>ORIENTATION_BOTLEFT</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>origin in bottom-left corner and</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>ORIENTATION_BOTRIGHT</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>origin in bottom-right corner.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>If you choose <b>ORIENTATION_BOTLEFT</b> result will be
+the same as returned by the <i>TIFFReadRGBAImage.</i></p>
+<!-- INDENTATION -->
+<p>Raster pixels are 8-bit packed red, green, blue, alpha
+samples. The macros <i>TIFFGetR</i>, <i>TIFFGetG</i>,
+<i>TIFFGetB</i>, and <i>TIFFGetA</i> should be used to
+access individual samples. Images without Associated Alpha
+matting information have a constant Alpha of 1.0 (255).</p>
+<!-- INDENTATION -->
+<p><i>TIFFReadRGBAImage</i> converts non-8-bit images by
+scaling sample values. Palette, grayscale, bilevel,
+<small>CMYK</small> , and YCbCr images are converted to
+<small>RGB</small> transparently. Raster pixels are returned
+uncorrected by any colorimetry information present in the
+directory.</p>
+<!-- INDENTATION -->
+<p>The paramater <i>stopOnError</i> specifies how to act if
+an error is encountered while reading the image. If
+<i>stopOnError</i> is non-zero, then an error will terminate
+the operation; otherwise <i>TIFFReadRGBAImage</i> will
+continue processing data until all the possible data in the
+image have been requested.</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>In C++ the <i>stopOnError</i> parameter defaults to
+0.</p>
+<!-- INDENTATION -->
+<p>Samples must be either 1, 2, 4, 8, or 16 bits.
+Colorimetric samples/pixel must be either 1, 3, or 4 (i.e.
+<i>SamplesPerPixel</i> minus <i>ExtraSamples</i>).</p>
+<!-- INDENTATION -->
+<p>Palettte image colormaps that appear to be incorrectly
+written as 8-bit values are automatically scaled to
+16-bits.</p>
+<!-- INDENTATION -->
+<p><i>TIFFReadRGBAImage</i> is just a wrapper around the
+more general <i>TIFFRGBAImage</i>(3TIFF) facilities.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>1 is returned if the image was successfully read and
+converted. Otherwise, 0 is returned if an error was
+encountered and <i>stopOnError</i> is zero.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>Sorry, can not handle %d-bit pictures</b>. The image
+had <i>BitsPerSample</i> other than 1, 2, 4, 8, or 16.</p>
+<!-- INDENTATION -->
+<p><b>Sorry, can not handle %d-channel images</b>. The image
+had <i>SamplesPerPixel</i> other than 1, 3, or 4.</p>
+<!-- INDENTATION -->
+<p><b>Missing needed &quot;PhotometricInterpretation&quot;
+tag</b>. The image did not have a tag that describes how to
+display the data.</p>
+<!-- INDENTATION -->
+<p><b>No &quot;PhotometricInterpretation&quot; tag, assuming
+RGB</b>. The image was missing a tag that describes how to
+display it, but because it has 3 or 4 samples/pixel, it is
+assumed to be <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>No &quot;PhotometricInterpretation&quot; tag, assuming
+min-is-black</b>. The image was missing a tag that describes
+how to display it, but because it has 1 sample/pixel, it is
+assumed to be a grayscale or bilevel image.</p>
+<!-- INDENTATION -->
+<p><b>No space for photometric conversion table</b>. There
+was insufficient memory for a table used to convert image
+samples to 8-bit <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>Missing required &quot;Colormap&quot; tag</b>. A
+Palette image did not have a required <i>Colormap</i>
+tag.</p>
+<!-- INDENTATION -->
+<p><b>No space for tile buffer</b>. There was insufficient
+memory to allocate an i/o buffer.</p>
+<!-- INDENTATION -->
+<p><b>No space for strip buffer</b>. There was insufficient
+memory to allocate an i/o buffer.</p>
+<!-- INDENTATION -->
+<p><b>Can not handle format</b>. The image has a format
+(combination of <i>BitsPerSample</i>,
+<i>SamplesPerPixel</i>, and
+<i>PhotometricInterpretation</i>) that
+<i>TIFFReadRGBAImage</i> can not handle.</p>
+<!-- INDENTATION -->
+<p><b>No space for B&amp;W mapping table</b>. There was
+insufficient memory to allocate a table used to map
+grayscale data to <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>No space for Palette mapping table</b>. There was
+insufficient memory to allocate a table used to map data to
+8-bit <small>RGB.</small></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFRGBAImage</b>(3TIFF),
+<b>TIFFReadRGBAStrip</b>(3TIFF),
+<b>TIFFReadRGBATile</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadRGBAStrip.3tiff.html b/tiff/html/man/TIFFReadRGBAStrip.3tiff.html
new file mode 100644
index 0000000..df09f64
--- /dev/null
+++ b/tiff/html/man/TIFFReadRGBAStrip.3tiff.html
@@ -0,0 +1,208 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadRGBAStrip</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadRGBAStrip</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadRGBAStrip &minus; read and decode an image strip
+into a fixed-format raster</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>#define TIFFGetR(abgr) ((abgr) &amp; 0xff)<br>
+#define TIFFGetG(abgr) (((abgr) &gt;&gt; 8) &amp; 0xff)<br>
+#define TIFFGetB(abgr) (((abgr) &gt;&gt; 16) &amp; 0xff)<br>
+#define TIFFGetA(abgr) (((abgr) &gt;&gt; 24) &amp;
+0xff)</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFReadRGBAStrip(TIFF *</b><i>tif</i><b>,
+uint32</b> <i>row</i><b>, uint32
+*</b><i>raster</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFReadRGBAStrip</i> reads a single strip of a
+strip-based image into memory, storing the result in the
+user supplied RGBA <i>raster</i>. The raster is assumed to
+be an array of width times rowsperstrip 32-bit entries,
+where width is the width of the image (TIFFTAG_IMAGEWIDTH)
+and rowsperstrip is the maximum lines in a strip
+(TIFFTAG_ROWSPERSTRIP).</p>
+<!-- INDENTATION -->
+<p>The <i>row</i> value should be the row of the first row
+in the strip (strip * rowsperstrip, zero based).</p>
+<!-- INDENTATION -->
+<p>Note that the raster is assume to be organized such that
+the pixel at location (<i>x</i>,<i>y</i>) is
+<i>raster</i>[<i>y</i>*<i>width</i>+<i>x</i>]; with the
+raster origin in the <i>lower-left hand corner</i> of the
+strip. That is bottom to top organization. When reading a
+partial last strip in the file the last line of the image
+will begin at the beginning of the buffer.</p>
+<!-- INDENTATION -->
+<p>Raster pixels are 8-bit packed red, green, blue, alpha
+samples. The macros <i>TIFFGetR</i>, <i>TIFFGetG</i>,
+<i>TIFFGetB</i>, and <i>TIFFGetA</i> should be used to
+access individual samples. Images without Associated Alpha
+matting information have a constant Alpha of 1.0 (255).</p>
+<!-- INDENTATION -->
+<p>See the <i>TIFFRGBAImage</i>(3TIFF) page for more details
+on how various image types are converted to RGBA values.</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Samples must be either 1, 2, 4, 8, or 16 bits.
+Colorimetric samples/pixel must be either 1, 3, or 4 (i.e.
+<i>SamplesPerPixel</i> minus <i>ExtraSamples</i>).</p>
+<!-- INDENTATION -->
+<p>Palette image colormaps that appear to be incorrectly
+written as 8-bit values are automatically scaled to
+16-bits.</p>
+<!-- INDENTATION -->
+<p><i>TIFFReadRGBAStrip</i> is just a wrapper around the
+more general <i>TIFFRGBAImage</i>(3TIFF) facilities.
+It&rsquo;s main advantage over the similar
+<i>TIFFReadRGBAImage()</i> function is that for large images
+a single buffer capable of holding the whole image
+doesn&rsquo;t need to be allocated, only enough for one
+strip. The <i>TIFFReadRGBATile()</i> function does a similar
+operation for tiled images.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>1 is returned if the image was successfully read and
+converted. Otherwise, 0 is returned if an error was
+encountered.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>Sorry, can not handle %d-bit pictures</b>. The image
+had <i>BitsPerSample</i> other than 1, 2, 4, 8, or 16.</p>
+<!-- INDENTATION -->
+<p><b>Sorry, can not handle %d-channel images</b>. The image
+had <i>SamplesPerPixel</i> other than 1, 3, or 4.</p>
+<!-- INDENTATION -->
+<p><b>Missing needed &quot;PhotometricInterpretation&quot;
+tag</b>. The image did not have a tag that describes how to
+display the data.</p>
+<!-- INDENTATION -->
+<p><b>No &quot;PhotometricInterpretation&quot; tag, assuming
+RGB</b>. The image was missing a tag that describes how to
+display it, but because it has 3 or 4 samples/pixel, it is
+assumed to be <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>No &quot;PhotometricInterpretation&quot; tag, assuming
+min-is-black</b>. The image was missing a tag that describes
+how to display it, but because it has 1 sample/pixel, it is
+assumed to be a grayscale or bilevel image.</p>
+<!-- INDENTATION -->
+<p><b>No space for photometric conversion table</b>. There
+was insufficient memory for a table used to convert image
+samples to 8-bit <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>Missing required &quot;Colormap&quot; tag</b>. A
+Palette image did not have a required <i>Colormap</i>
+tag.</p>
+<!-- INDENTATION -->
+<p><b>No space for tile buffer</b>. There was insufficient
+memory to allocate an i/o buffer.</p>
+<!-- INDENTATION -->
+<p><b>No space for strip buffer</b>. There was insufficient
+memory to allocate an i/o buffer.</p>
+<!-- INDENTATION -->
+<p><b>Can not handle format</b>. The image has a format
+(combination of <i>BitsPerSample</i>,
+<i>SamplesPerPixel</i>, and
+<i>PhotometricInterpretation</i>) that
+<i>TIFFReadRGBAImage</i> can not handle.</p>
+<!-- INDENTATION -->
+<p><b>No space for B&amp;W mapping table</b>. There was
+insufficient memory to allocate a table used to map
+grayscale data to <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>No space for Palette mapping table</b>. There was
+insufficient memory to allocate a table used to map data to
+8-bit <small>RGB.</small></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFRGBAImage</b>(3TIFF),
+<b>TIFFReadRGBAImage</b>(3TIFF),
+<b>TIFFReadRGBATile</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadRGBATile.3tiff.html b/tiff/html/man/TIFFReadRGBATile.3tiff.html
new file mode 100644
index 0000000..ed67b83
--- /dev/null
+++ b/tiff/html/man/TIFFReadRGBATile.3tiff.html
@@ -0,0 +1,261 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadRGBATile</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadRGBATile</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadRGBATile &minus; read and decode an image tile
+into a fixed-format raster</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="-2%">
+
+<p><b>#define TIFFGetR(abgr)</b></p>
+</td>
+<td width="25%"></td>
+<td width="6%"></td>
+<td width="61%">
+
+<p><b>((abgr) &amp; 0xff)</b></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="-2%">
+
+<p><b>#define TIFFGetG(abgr)</b></p>
+</td>
+<td width="25%"></td>
+<td width="6%"></td>
+<td width="61%">
+
+<p><b>(((abgr) &gt;&gt; 8) &amp; 0xff)</b></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="-2%">
+
+<p><b>#define TIFFGetB(abgr)</b></p>
+</td>
+<td width="25%"></td>
+<td width="6%"></td>
+<td width="61%">
+
+<p><b>(((abgr) &gt;&gt; 16) &amp; 0xff)</b></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="-2%">
+
+<p><b>#define TIFFGetA(abgr)</b></p>
+</td>
+<td width="25%"></td>
+<td width="6%"></td>
+<td width="61%">
+
+<p><b>(((abgr) &gt;&gt; 24) &amp; 0xff)</b></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>int TIFFReadRGBATile(TIFF *</b><i>tif</i><b>,
+uint32</b> <i>x</i><b>, uint32</b> <i>y</i><b>, uint32
+*</b><i>raster</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFReadRGBATile</i> reads a single tile of a
+tile-based image into memory, storing the result in the user
+supplied RGBA <i>raster</i>. The raster is assumed to be an
+array of width times length 32-bit entries, where width is
+the width of a tile (TIFFTAG_TILEWIDTH) and length is the
+height of a tile (TIFFTAG_TILELENGTH).</p>
+<!-- INDENTATION -->
+<p>The <i>x</i> and <i>y</i> values are the offsets from the
+top left corner to the top left corner of the tile to be
+read. They must be an exact multiple of the tile width and
+length.</p>
+<!-- INDENTATION -->
+<p>Note that the raster is assume to be organized such that
+the pixel at location (<i>x</i>,<i>y</i>) is
+<i>raster</i>[<i>y</i>*<i>width</i>+<i>x</i>]; with the
+raster origin in the <i>lower-left hand corner</i> of the
+tile. That is bottom to top organization. Edge tiles which
+partly fall off the image will be filled out with
+appropriate zeroed areas.</p>
+<!-- INDENTATION -->
+<p>Raster pixels are 8-bit packed red, green, blue, alpha
+samples. The macros <i>TIFFGetR</i>, <i>TIFFGetG</i>,
+<i>TIFFGetB</i>, and <i>TIFFGetA</i> should be used to
+access individual samples. Images without Associated Alpha
+matting information have a constant Alpha of 1.0 (255).</p>
+<!-- INDENTATION -->
+<p>See the <i>TIFFRGBAImage</i>(3TIFF) page for more details
+on how various image types are converted to RGBA values.</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Samples must be either 1, 2, 4, 8, or 16 bits.
+Colorimetric samples/pixel must be either 1, 3, or 4 (i.e.
+<i>SamplesPerPixel</i> minus <i>ExtraSamples</i>).</p>
+<!-- INDENTATION -->
+<p>Palette image colormaps that appear to be incorrectly
+written as 8-bit values are automatically scaled to
+16-bits.</p>
+<!-- INDENTATION -->
+<p><i>TIFFReadRGBATile</i> is just a wrapper around the more
+general <i>TIFFRGBAImage</i>(3TIFF) facilities. It&rsquo;s
+main advantage over the similar <i>TIFFReadRGBAImage()</i>
+function is that for large images a single buffer capable of
+holding the whole image doesn&rsquo;t need to be allocated,
+only enough for one tile. The <i>TIFFReadRGBAStrip()</i>
+function does a similar operation for stripped images.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>1 is returned if the image was successfully read and
+converted. Otherwise, 0 is returned if an error was
+encountered.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>Sorry, can not handle %d-bit pictures</b>. The image
+had <i>BitsPerSample</i> other than 1, 2, 4, 8, or 16.</p>
+<!-- INDENTATION -->
+<p><b>Sorry, can not handle %d-channel images</b>. The image
+had <i>SamplesPerPixel</i> other than 1, 3, or 4.</p>
+<!-- INDENTATION -->
+<p><b>Missing needed &quot;PhotometricInterpretation&quot;
+tag</b>. The image did not have a tag that describes how to
+display the data.</p>
+<!-- INDENTATION -->
+<p><b>No &quot;PhotometricInterpretation&quot; tag, assuming
+RGB</b>. The image was missing a tag that describes how to
+display it, but because it has 3 or 4 samples/pixel, it is
+assumed to be <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>No &quot;PhotometricInterpretation&quot; tag, assuming
+min-is-black</b>. The image was missing a tag that describes
+how to display it, but because it has 1 sample/pixel, it is
+assumed to be a grayscale or bilevel image.</p>
+<!-- INDENTATION -->
+<p><b>No space for photometric conversion table</b>. There
+was insufficient memory for a table used to convert image
+samples to 8-bit <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>Missing required &quot;Colormap&quot; tag</b>. A
+Palette image did not have a required <i>Colormap</i>
+tag.</p>
+<!-- INDENTATION -->
+<p><b>No space for tile buffer</b>. There was insufficient
+memory to allocate an i/o buffer.</p>
+<!-- INDENTATION -->
+<p><b>No space for strip buffer</b>. There was insufficient
+memory to allocate an i/o buffer.</p>
+<!-- INDENTATION -->
+<p><b>Can not handle format</b>. The image has a format
+(combination of <i>BitsPerSample</i>,
+<i>SamplesPerPixel</i>, and
+<i>PhotometricInterpretation</i>) that
+<i>TIFFReadRGBAImage</i> can not handle.</p>
+<!-- INDENTATION -->
+<p><b>No space for B&amp;W mapping table</b>. There was
+insufficient memory to allocate a table used to map
+grayscale data to <small>RGB.</small></p>
+<!-- INDENTATION -->
+<p><b>No space for Palette mapping table</b>. There was
+insufficient memory to allocate a table used to map data to
+8-bit <small>RGB.</small></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFRGBAImage</b>(3TIFF),
+<b>TIFFReadRGBAImage</b>(3TIFF),
+<b>TIFFReadRGBAStrip</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadRawStrip.3tiff.html b/tiff/html/man/TIFFReadRawStrip.3tiff.html
new file mode 100644
index 0000000..bd14f72
--- /dev/null
+++ b/tiff/html/man/TIFFReadRawStrip.3tiff.html
@@ -0,0 +1,109 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadRawStrip</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadRawStrip</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadRawStrip &minus; return the undecoded contents of
+a strip of data from an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>tsize_t TIFFReadRawStrip(TIFF *</b><i>tif</i><b>,
+tstrip_t</b> <i>strip</i><b>, tdata_t</b> <i>buf</i><b>,
+tsize_t</b> <i>size</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Read the contents of the specified strip into the (user
+supplied) data buffer. Note that the value of <i>strip</i>
+is a &lsquo;&lsquo;raw strip number.&rsquo;&rsquo; That is,
+the caller must take into account whether or not the data is
+organized in separate planes (<i>PlanarConfiguration</i>=2).
+To read a full strip of data the data buffer should
+typically be at least as large as the number returned by
+<i>TIFFStripSize</i>.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The actual number of bytes of data that were placed in
+<i>buf</i> is returned; <i>TIFFReadEncodedStrip</i> returns
+&minus;1 if an error was encountered.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF),
+<b>TIFFReadEncodedStrip</b>(3TIFF),
+<b>TIFFReadScanline</b>(3TIFF), <b>TIFFStripSize</b>(3TIFF),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadRawTile.3tiff.html b/tiff/html/man/TIFFReadRawTile.3tiff.html
new file mode 100644
index 0000000..bae2b46
--- /dev/null
+++ b/tiff/html/man/TIFFReadRawTile.3tiff.html
@@ -0,0 +1,111 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadRawTile</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadRawTile</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadRawTile &minus; return an undecoded tile of data
+from an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>tsize_t TIFFReadRawTile(TIFF *</b><i>tif</i><b>,
+ttile_t</b> <i>tile</i><b>, tdata_t</b> <i>buf</i><b>,
+tsize_t</b> <i>size</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Read the contents of the specified tile into the (user
+supplied) data buffer. Note that the value of <i>tile</i> is
+a &lsquo;&lsquo;raw tile number.&rsquo;&rsquo; That is, the
+caller must take into account whether or not the data is
+organized in separate planes (<i>PlanarConfiguration</i>=2).
+<i>TIFFComputeTile</i> automatically does this when
+converting an (x,y,z,sample) coordinate quadruple to a tile
+number. To read a full tile of data the data buffer should
+typically be at least as large as the value returned by
+<i>TIFFTileSize</i>.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The actual number of bytes of data that were placed in
+<i>buf</i> is returned; <i>TIFFReadEncodedTile</i> returns
+&minus;1 if an error was encountered.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF),
+<b>TIFFReadEncodedTile</b>(3TIFF),
+<b>TIFFReadTile</b>(3TIFF), <b>TIFFTileSize</b>(3TIFF),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadScanline.3tiff.html b/tiff/html/man/TIFFReadScanline.3tiff.html
new file mode 100644
index 0000000..423645c
--- /dev/null
+++ b/tiff/html/man/TIFFReadScanline.3tiff.html
@@ -0,0 +1,157 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadScanline</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadScanline</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadScanline &minus; read and decode a scanline of
+data from an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFReadScanline(TIFF *</b><i>tif</i><b>,
+tdata_t</b> <i>buf</i><b>, uint32</b> <i>row</i><b>,
+tsample_t</b> <i>sample</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Read the data for the specified row into the (user
+supplied) data buffer <i>buf</i>. The data are returned
+decompressed and, in the native byte- and bit-ordering, but
+are otherwise packed (see further below). The buffer must be
+large enough to hold an entire scanline of data.
+Applications should call the routine <i>TIFFScanlineSize</i>
+to find out the size (in bytes) of a scanline buffer. The
+<i>row</i> parameter is always used by
+<i>TIFFReadScanline</i>; the <i>sample</i> parameter is used
+only if data are organized in separate planes
+(<i>PlanarConfiguration</i>=2).</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The library attempts to hide bit- and byte-ordering
+differences between the image and the native machine by
+converting data to the native machine order. Bit reversal is
+done if the <i>FillOrder</i> tag is opposite to the native
+machine bit order. 16- and 32-bit samples are automatically
+byte-swapped if the file was written with a byte order
+opposite to the native machine byte order,</p>
+<!-- INDENTATION -->
+<p>In C++ the <i>sample</i> parameter defaults to 0.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFReadScanline</i> returns &minus;1 if it detects an
+error; otherwise 1 is returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>Compression algorithm does not support random
+access</b>. Data was requested in a non-sequential order
+from a file that uses a compression algorithm and that has
+<i>RowsPerStrip</i> greater than one. That is, data in the
+image is stored in a compressed form, and with multiple rows
+packed into a strip. In this case, the library does not
+support random access to the data. The data should either be
+accessed sequentially, or the file should be converted so
+that each strip is made up of one row of data.</p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Reading subsampled YCbCR data does not work correctly
+because, for <i>PlanarConfiguration</i>=2 the size of a
+scanline is not calculated on a per-sample basis, and for
+<i>PlanarConfiguration</i>=1 the library does not unpack the
+block-interleaved samples; use the strip- and tile-based
+interfaces to read these formats.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF),
+<b>TIFFReadEncodedStrip</b>(3TIFF),
+<b>TIFFReadRawStrip</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFReadTile.3tiff.html b/tiff/html/man/TIFFReadTile.3tiff.html
new file mode 100644
index 0000000..ff726b4
--- /dev/null
+++ b/tiff/html/man/TIFFReadTile.3tiff.html
@@ -0,0 +1,133 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:16 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFReadTile</title>
+</head>
+<body>
+
+<h1 align=center>TIFFReadTile</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadTile &minus; read and decode a tile of data from
+an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>tsize_t TIFFReadTile(TIFF *</b><i>tif</i><b>,
+tdata_t</b> <i>buf</i><b>, uint32</b> <i>x</i><b>,
+uint32</b> <i>y</i><b>, uint32</b> <i>z</i><b>,
+tsample_t</b> <i>sample</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Return the data for the tile <i>containing</i> the
+specified coordinates. The data placed in <i>buf</i> are
+returned decompressed and, typically, in the native byte-
+and bit-ordering, but are otherwise packed (see further
+below). The buffer must be large enough to hold an entire
+tile of data. Applications should call the routine
+<i>TIFFTileSize</i> to find out the size (in bytes) of a
+tile buffer. The <i>x</i> and <i>y</i> parameters are always
+used by <i>TIFFReadTile</i>. The <i>z</i> parameter is used
+if the image is deeper than 1 slice
+(<i>ImageDepth</i>&gt;1). The <i>sample</i> parameter is
+used only if data are organized in separate planes
+(<i>PlanarConfiguration</i>=2).</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The library attempts to hide bit- and byte-ordering
+differences between the image and the native machine by
+converting data to the native machine order. Bit reversal is
+done if the <i>FillOrder</i> tag is opposite to the native
+machine bit order. 16- and 32-bit samples are automatically
+byte-swapped if the file was written with a byte order
+opposite to the native machine byte order,</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFReadTile</i> returns &minus;1 if it detects an
+error; otherwise the number of bytes in the decoded tile is
+returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFCheckTile</b>(3TIFF),
+<b>TIFFComputeTile</b>(3TIFF), <b>TIFFOpen</b>(3TIFF),
+<b>TIFFReadEncodedTile</b>(3TIFF),
+<b>TIFFReadRawTile</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFSetDirectory.3tiff.html b/tiff/html/man/TIFFSetDirectory.3tiff.html
new file mode 100644
index 0000000..a0e5cfc
--- /dev/null
+++ b/tiff/html/man/TIFFSetDirectory.3tiff.html
@@ -0,0 +1,122 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFSetDirectory</title>
+</head>
+<body>
+
+<h1 align=center>TIFFSetDirectory</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFSetDirectory, TIFFSetSubDirectory &minus; set the
+current directory for an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFSetDirectory(TIFF *</b><i>tif</i><b>,
+tdir_t</b> <i>dirnum</i><b>)<br>
+int TIFFSetSubDirectory(TIFF *</b><i>tif</i><b>, uint32</b>
+<i>diroff</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFSetDirectory</i> changes the current directory and
+reads its contents with <i>TIFFReadDirectory</i>. The
+parameter <i>dirnum</i> specifies the subfile/directory as
+an integer number, with the first directory numbered
+zero.</p>
+<!-- INDENTATION -->
+<p><i>TIFFSetSubDirectory</i> acts like
+<i>TIFFSetDirectory</i>, except the directory is specified
+as a file offset instead of an index; this is required for
+accessing subdirectories linked through a <i>SubIFD</i>
+tag.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>On successful return 1 is returned. Otherwise, 0 is
+returned if <i>dirnum</i> or <i>diroff</i> specifies a
+non-existent directory, or if an error was encountered while
+reading the directory&rsquo;s contents.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>%s: Error fetching directory count</b>. An error was
+encountered while reading the &lsquo;&lsquo;directory
+count&rsquo;&rsquo; field.</p>
+<!-- INDENTATION -->
+<p><b>%s: Error fetching directory link</b>. An error was
+encountered while reading the &lsquo;&lsquo;link
+value&rsquo;&rsquo; that points to the next directory in a
+file.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFCurrentDirectory</i>(3TIFF),
+<i>TIFFOpen</i>(3TIFF), <i>TIFFReadDirectory</i>(3TIFF),
+<i>TIFFWriteDirectory</i>(3TIFF), <i>libtiff</i>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFSetField.3tiff.html b/tiff/html/man/TIFFSetField.3tiff.html
new file mode 100644
index 0000000..2e70225
--- /dev/null
+++ b/tiff/html/man/TIFFSetField.3tiff.html
@@ -0,0 +1,1362 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFSetField</title>
+</head>
+<body>
+
+<h1 align=center>TIFFSetField</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFSetField, TIFFVSetField &minus; set the value(s) of a
+tag in a <small>TIFF</small> file open for writing</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFSetField(TIFF *</b><i>tif</i><b>, ttag_t</b>
+<i>tag</i><b>,</b> <i>...</i><b>)</b></p>
+<!-- INDENTATION -->
+<p><b>#include &lt;stdarg.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFVSetField(TIFF *</b><i>tif</i><b>, ttag_t</b>
+<i>tag</i><b>, va_list</b> <i>ap</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFSetField</i> sets the value of a field or
+pseudo-tag in the current directory associated with the open
+<small>TIFF</small> file <i>tif</i>. (A <i>pseudo-tag</i> is
+a parameter that is used to control the operation of the
+<small>TIFF</small> library but whose value is not read or
+written to the underlying file.) To set the value of a field
+the file must have been previously opened for writing with
+<i>TIFFOpen</i>(3TIFF); pseudo-tags can be set whether the
+file was opened for reading or writing. The field is
+identified by <i>tag</i>, one of the values defined in the
+include file <b>tiff.h</b> (see also the table below). The
+actual value is specified using a variable argument list, as
+prescribed by the <i>stdarg</i>(3) interface (or, on some
+machines, the <i>varargs</i>(3) interface.)</p>
+<!-- INDENTATION -->
+<p><i>TIFFVSetField</i> is functionally equivalent to
+<i>TIFFSetField</i> except that it takes a pointer to a
+variable argument list. <i>TIFFVSetField</i> is useful for
+writing routines that are layered on top of the
+functionality provided by <i>TIFFSetField</i>.</p>
+<!-- INDENTATION -->
+<p>The tags understood by <i>libtiff</i>, the number of
+parameter values, and the expected types for the parameter
+values are shown below. The data types are: <i>char*</i> is
+null-terminated string and corresponds to the
+<small>ASCII</small> data type; <i>uint16</i> is an unsigned
+16-bit value; <i>uint32</i> is an unsigned 32-bit value;
+<i>uint16*</i> is an array of unsigned 16-bit values.
+<i>void*</i> is an array of data values of unspecified
+type.</p>
+<!-- INDENTATION -->
+<p>Consult the <small>TIFF</small> specification for
+information on the meaning of each tag.</p></td>
+</table>
+<!-- TABS -->
+
+<p><i>Tag Name Count Types Notes</i></p>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_ARTIST</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_BADFAXLINES</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_BITSPERSAMPLE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_CLEANFAXDATA</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_COLORMAP</p>
+</td>
+<td width="8%">
+
+<p>3</p>
+</td>
+<td width="24%">
+
+<p>uint16*</p>
+</td>
+<td width="16%">
+
+<p>1&lt;&lt;BitsPerSample arrays</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_COMPRESSION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_CONSECUTIVEBADFAXLINES</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_COPYRIGHT</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_DATETIME</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_DOCUMENTNAME</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_DOTRANGE</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_EXTRASAMPLES</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint16,uint16*</p>
+</td>
+<td width="16%">
+
+<p>&dagger; count &amp; types array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_FAXFILLFUNC</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>TIFFFaxFillFunc</p>
+</td>
+<td width="16%">
+
+<p>G3/G4 compression pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_FAXMODE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>int</p>
+</td>
+<td width="16%">
+
+<p>&dagger; G3/G4 compression pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_FILLORDER</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_GROUP3OPTIONS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_GROUP4OPTIONS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_HALFTONEHINTS</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_HOSTCOMPUTER</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_ICCPROFILE</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint32,void*</p>
+</td>
+<td width="16%">
+
+<p>count, profile data</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_IMAGEDEPTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_IMAGEDESCRIPTION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_IMAGELENGTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_IMAGEWIDTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_INKNAMES</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint16, char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_INKSET</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_JPEGCOLORMODE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>int</p>
+</td>
+<td width="16%">
+
+<p>&dagger; JPEG pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_JPEGQUALITY</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>int</p>
+</td>
+<td width="16%">
+
+<p>JPEG pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_JPEGTABLES</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint32*,void*</p>
+</td>
+<td width="16%">
+
+<p>&dagger; count &amp; tables</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_JPEGTABLESMODE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>int</p>
+</td>
+<td width="16%">
+
+<p>&dagger; JPEG pseudo-tag</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MAKE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MATTEING</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MAXSAMPLEVALUE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MINSAMPLEVALUE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_MODEL</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_ORIENTATION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PAGENAME</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PAGENUMBER</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PHOTOMETRIC</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PHOTOSHOP</p>
+</td>
+<td width="8%">
+
+<p>?</p>
+</td>
+<td width="24%">
+
+<p>uint32,void*</p>
+</td>
+<td width="16%">
+
+<p>count, data</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PLANARCONFIG</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PREDICTOR</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_PRIMARYCHROMATICITIES</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>float*</p>
+</td>
+<td width="16%">
+
+<p>6-entry array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_REFERENCEBLACKWHITE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>float*</p>
+</td>
+<td width="16%">
+
+<p>&dagger; 2*SamplesPerPixel array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_RESOLUTIONUNIT</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_RICHTIFFIPTC</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint32,void*</p>
+</td>
+<td width="16%">
+
+<p>count, data</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_ROWSPERSTRIP</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+
+<p>&dagger; must be &gt; 0</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SAMPLEFORMAT</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SAMPLESPERPIXEL</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger; value must be &lt;= 4</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SMAXSAMPLEVALUE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>double</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SMINSAMPLEVALUE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>double</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SOFTWARE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_STONITS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>double</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SUBFILETYPE</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_SUBIFD</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint16,uint32*</p>
+</td>
+<td width="16%">
+
+<p>count &amp; offsets array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TARGETPRINTER</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>char*</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_THRESHHOLDING</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TILEDEPTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TILELENGTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+
+<p>&dagger; must be a multiple of 8</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TILEWIDTH</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint32</p>
+</td>
+<td width="16%">
+
+<p>&dagger; must be a multiple of 8</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_TRANSFERFUNCTION</p>
+</td>
+<td width="8%">
+
+<p>1 or 3&Dagger; uint16*</p>
+</td>
+<td width="24%"></td>
+<td width="16%">
+
+<p>1&lt;&lt;BitsPerSample entry arrays</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_WHITEPOINT</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>float*</p>
+</td>
+<td width="16%">
+
+<p>2-entry array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_XMLPACKET</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint32,void*</p>
+</td>
+<td width="16%">
+
+<p>count, data</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_XPOSITION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>float</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_XRESOLUTION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>float</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YCBCRCOEFFICIENTS</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>float*</p>
+</td>
+<td width="16%">
+
+<p>&dagger; 3-entry array</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YCBCRPOSITIONING</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YCBCRSAMPLING</p>
+</td>
+<td width="8%">
+
+<p>2</p>
+</td>
+<td width="24%">
+
+<p>uint16</p>
+</td>
+<td width="16%">
+
+<p>&dagger;</p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YPOSITION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>float</p>
+</td>
+<td width="16%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="41%">
+
+<p>TIFFTAG_YRESOLUTION</p>
+</td>
+<td width="8%">
+
+<p>1</p>
+</td>
+<td width="24%">
+
+<p>float</p>
+</td>
+<td width="16%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>&dagger; Tag may not have its values changed once data is
+written.<br>
+&Dagger; If <i>SamplesPerPixel</i> is one, then a single
+array is passed; otherwise three arrays should be
+passed.<br>
+* The contents of this field are quite complex. See <b>The
+ICC Profile Format Specification</b>, Annex B.3
+&quot;Embedding ICC Profiles in TIFF Files&quot; (available
+at http://www.color.org) for an explanation.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>1 is returned if the operation was successful. Otherwise,
+0 is returned if an error was detected.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>%s: Cannot modify tag &quot;%s&quot; while
+writing</b>. Data has already been written to the file, so
+the specified tag&rsquo;s value can not be changed. This
+restriction is applied to all tags that affect the format of
+written data.</p>
+<!-- INDENTATION -->
+<p><b>%d: Bad value for &quot;%s&quot;</b>. An invalid value
+was supplied for the named tag.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFGetField</b>(3TIFF),
+<b>TIFFSetDirectory</b>(3TIFF),
+<b>TIFFWriteDirectory</b>(3TIFF),
+<b>TIFFReadDirectory</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFWarning.3tiff.html b/tiff/html/man/TIFFWarning.3tiff.html
new file mode 100644
index 0000000..df17073
--- /dev/null
+++ b/tiff/html/man/TIFFWarning.3tiff.html
@@ -0,0 +1,108 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFWarning</title>
+</head>
+<body>
+
+<h1 align=center>TIFFWarning</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFWarning, TIFFSetWarningHandler &minus; library
+warning interface</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>void TIFFWarning(const char *</b><i>module</i><b>,
+const char *</b><i>fmt</i><b>,</b> <i>...</i><b>)</b></p>
+<!-- INDENTATION -->
+<p><b>#include &lt;stdargh.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>typedef void (*TIFFWarningHandler)(const char
+*</b><i>module</i><b>, const char *</b><i>fmt</i><b>,
+va_list</b> <i>ap</i><b>);</b></p>
+<!-- INDENTATION -->
+<p><b>TIFFWarningHandler
+TIFFSetWarningHandler(TIFFWarningHandler</b>
+<i>handler</i><b>);</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFWarning</i> invokes the library-wide warning
+handler function to (normally) write a warning message to
+the <b>stderr</b>. The <i>fmt</i> parameter is a
+<i>printf</i>(3S) format string, and any number arguments
+can be supplied. The <i>module</i> parameter is interpreted
+as a string that, if non-zero, should be printed before the
+message; it typically is used to identify the software
+module in which a warning is detected.</p>
+<!-- INDENTATION -->
+<p>Applications that desire to capture control in the event
+of a warning should use <i>TIFFSetWarningHandler</i> to
+override the default warning handler. A <small>NULL</small>
+(0) warning handler function may be installed to suppress
+error messages.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFSetWarningHandler</i> returns a reference to the
+previous error handling function.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFError</b>(3TIFF), <b>libtiff</b>(3TIFF),
+<b>printf</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFWriteDirectory.3tiff.html b/tiff/html/man/TIFFWriteDirectory.3tiff.html
new file mode 100644
index 0000000..07a443e
--- /dev/null
+++ b/tiff/html/man/TIFFWriteDirectory.3tiff.html
@@ -0,0 +1,176 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFWriteDirectory</title>
+</head>
+<body>
+
+<h1 align=center>TIFFWriteDirectory</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFWriteDirectory, TIFFRewriteDirectory,
+TIFFCheckpointDirectory &minus; write the current directory
+in an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFWriteDirectory(TIFF *</b><i>tif</i><b>)<br>
+int TIFFRewriteDirectory(TIFF *</b><i>tif</i><b>)<br>
+int TIFFCheckpointDirectory(TIFF *</b><i>tif</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFWriteDirectory</i> will write the contents of the
+current directory to the file and setup to create a new
+subfile in the same file. Applications only need to call
+<i>TIFFWriteDirectory</i> when writing multiple subfiles to
+a single <small>TIFF</small> file. <i>TIFFWriteDirectory</i>
+is automatically called by <i>TIFFClose</i> and
+<i>TIFFFlush</i> to write a modified directory if the file
+is open for writing.</p>
+<!-- INDENTATION -->
+<p>The <i>TIFFRewriteDirectory</i> function operates
+similarly to <i>TIFFWriteDirectory,</i> but can be called
+with directories previously read or written that already
+have an established location in the file. It will rewrite
+the directory, but instead of place it at it&rsquo;s old
+location (as <i>TIFFWriteDirectory</i> would) it will place
+them at the end of the file, correcting the pointer from the
+preceeding directory or file header to point to it&rsquo;s
+new location. This is particularly important in cases where
+the size of the directory and pointed to data has grown, so
+it won&rsquo;t fit in the space available at the old
+location.</p>
+<!-- INDENTATION -->
+<p>The <i>TIFFCheckpointDirectory</i> writes the current
+state of the tiff directory into the file to make what is
+currently in the file readable. Unlike
+<i>TIFFWriteDirectory, TIFFCheckpointDirectory</i> does not
+free up the directory data structures in memory, so they can
+be updated (as strips/tiles are written) and written again.
+Reading such a partial file you will at worst get a tiff
+read error for the first strip/tile encountered that is
+incomplete, but you will at least get all the valid data in
+the file before that. When the file is complete, just use
+<i>TIFFWriteDirectory</i> as usual to finish it off
+cleanly.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>1 is returned when the contents are successfully written
+to the file. Otherwise, 0 is returned if an error was
+encountered when writing the directory contents.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>Error post-encoding before directory write</b>. Before
+writing the contents of the current directory, any pending
+data are flushed. This message indicates that an error
+occurred while doing this.</p>
+<!-- INDENTATION -->
+<p><b>Error flushing data before directory write</b>. Before
+writing the contents of the current directory, any pending
+data are flushed. This message indicates that an error
+occurred while doing this.</p>
+<!-- INDENTATION -->
+<p><b>Cannot write directory, out of space</b>. There was
+not enough space to allocate a temporary area for the
+directory that was to be written.</p>
+<!-- INDENTATION -->
+<p><b>Error writing directory count</b>. A write error
+occurred when writing the count of fields in the
+directory.</p>
+<!-- INDENTATION -->
+<p><b>Error writing directory contents</b>. A write error
+occurred when writing the directory fields.</p>
+<!-- INDENTATION -->
+<p><b>Error writing directory link</b>. A write error
+occurred when writing the link to the next directory.</p>
+<!-- INDENTATION -->
+<p><b>Error writing data for field &quot;%s&quot;</b>. A
+write error occurred when writing indirect data for the
+specified field.</p>
+<!-- INDENTATION -->
+<p><b>Error writing TIFF header</b>. A write error occurred
+when re-writing header at the front of the file.</p>
+<!-- INDENTATION -->
+<p><b>Error fetching directory count</b>. A read error
+occurred when fetching the directory count field for a
+previous directory. This can occur when setting up a link to
+the directory that is being written.</p>
+<!-- INDENTATION -->
+<p><b>Error fetching directory link</b>. A read error
+occurred when fetching the directory link field for a
+previous directory. This can occur when setting up a link to
+the directory that is being written.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFError</b>(3TIFF),
+<b>TIFFReadDirectory</b>(3TIFF),
+<b>TIFFSetDirectory</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFWriteEncodedStrip.3tiff.html b/tiff/html/man/TIFFWriteEncodedStrip.3tiff.html
new file mode 100644
index 0000000..5a45f59
--- /dev/null
+++ b/tiff/html/man/TIFFWriteEncodedStrip.3tiff.html
@@ -0,0 +1,153 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFWriteEncodedStrip</title>
+</head>
+<body>
+
+<h1 align=center>TIFFWriteEncodedStrip</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>TIFFWritedEncodedStrip &minus; compress and write a
+strip of data to an open</big> TIFF <big>file</big></p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>#include &lt;tiffio.h&gt;</b></big></p>
+<!-- INDENTATION -->
+<p><big><b>tsize_t TIFFWriteEncodedStrip(TIFF
+*</b><i>tif</i><b>, tstrip_t</b> <i>strip</i><b>,
+tdata_t</b> <i>buf</i><b>, tsize_t</b>
+<i>size</i><b>)</b></big></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>Compress <i>size</i> bytes of raw data from
+<i>buf</i> and write the result to the specified strip;
+replacing any previously written data. Note that the value
+of <i>strip</i> is a &lsquo;&lsquo;raw strip
+number.&rsquo;&rsquo; That is, the caller must take into
+account whether or not the data are organized in separate
+planes (<i>PlanarConfiguration</i>=2).</big></p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>The library writes encoded data using the native
+machine byte order. Correctly implemented</big> TIFF
+<big>readers are expected to do any necessary byte-swapping
+to correctly process image data with BitsPerSample greater
+than 8.</big></p>
+<!-- INDENTATION -->
+<p><big>The strip number must be valid according to the
+current settings of the <i>ImageLength</i> and
+<i>RowsPerStrip</i> tags. An image may be dynamically grown
+by increasing the value of <i>ImageLength</i> prior to each
+call to <i>TIFFWriteEncodedStrip</i>.</big></p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>&minus;1 is returned if an error was encountered.
+Otherwise, the value of <i>size</i> is returned.</big></p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: File not open for writing</b>. The file was
+opened for reading, not writing.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Can not write scanlines to a tiled image</b>. The
+image is assumed to be organized in tiles because the
+<i>TileWidth</i> and <i>TileLength</i> tags have been set
+with <i>TIFFSetField</i>(3TIFF).</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: Must set &quot;ImageWidth&quot; before
+writing data</b>. The image&rsquo;s width has not be set
+before the first write. See <i>TIFFSetField</i>(3TIFF) for
+information on how to do this.</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: Must set &quot;PlanarConfiguration&quot;
+before writing data</b>. The organization of data has not be
+defined before the first write. See
+<i>TIFFSetField</i>(3TIFF) for information on how to do
+this.</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: No space for strip arrays&quot;</b>. There
+was not enough space for the arrays that hold strip offsets
+and byte counts.</big></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFOpen</b>(3TIFF),
+<b>TIFFWriteScanline</b>(3TIFF),
+<b>TIFFWriteRawStrip</b>(3TIFF),
+<b>libtiff</b>(3TIFF)</big></p>
+<!-- INDENTATION -->
+<p><big>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></big></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFWriteEncodedTile.3tiff.html b/tiff/html/man/TIFFWriteEncodedTile.3tiff.html
new file mode 100644
index 0000000..0e6e1ba
--- /dev/null
+++ b/tiff/html/man/TIFFWriteEncodedTile.3tiff.html
@@ -0,0 +1,147 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFWriteEncodedTile</title>
+</head>
+<body>
+
+<h1 align=center>TIFFWriteEncodedTile</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>TIFFWritedEncodedTile &minus; compress and write a
+tile of data to an open</big> TIFF <big>file</big></p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>#include &lt;tiffio.h&gt;</b></big></p>
+<!-- INDENTATION -->
+<p><big><b>tsize_t TIFFWriteEncodedTile(TIFF
+*</b><i>tif</i><b>, ttile_t</b> <i>tile</i><b>, tdata_t</b>
+<i>buf</i><b>, tsize_t</b> <i>size</i><b>)</b></big></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>Compress <i>size</i> bytes of raw data from
+<i>buf</i> and <b>append</b> the result to the end of the
+specified tile. Note that the value of <i>tile</i> is a
+&lsquo;&lsquo;raw tile number.&rsquo;&rsquo; That is, the
+caller must take into account whether or not the data are
+organized in separate places (<i>PlanarConfiguration</i>=2).
+<i>TIFFComputeTile</i> automatically does this when
+converting an (x,y,z,sample) coordinate quadruple to a tile
+number.</big></p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>The library writes encoded data using the native
+machine byte order. Correctly implemented</big> TIFF
+<big>readers are expected to do any necessary byte-swapping
+to correctly process image data with BitsPerSample greater
+than 8.</big></p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>&minus;1 is returned if an error was encountered.
+Otherwise, the value of <i>size</i> is returned.</big></p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: File not open for writing</b>. The file was
+opened for reading, not writing.</big></p>
+<!-- INDENTATION -->
+<p><big><b>Can not write tiles to a stripped image</b>. The
+image is assumed to be organized in strips because neither
+of the <i>TileWidth</i> or <i>TileLength</i> tags have been
+set with <b>TIFFSetField</b>(3TIFF).</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: Must set &quot;ImageWidth&quot; before
+writing data</b>. The image&rsquo;s width has not be set
+before the first write. See <b>TIFFSetField</b>(3TIFF) for
+information on how to do this.</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: Must set &quot;PlanarConfiguration&quot;
+before writing data</b>. The organization of data has not be
+defined before the first write. See
+<b>TIFFSetField</b>(3TIFF) for information on how to do
+this.</big></p>
+<!-- INDENTATION -->
+<p><big><b>%s: No space for tile arrays&quot;</b>. There was
+not enough space for the arrays that hold tile offsets and
+byte counts.</big></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFOpen</b>(3TIFF), <b>TIFFWriteTile</b>(3TIFF),
+<b>TIFFWriteRawTile</b>(3TIFF),
+<b>libtiff</b>(3TIFF)</big></p>
+<!-- INDENTATION -->
+<p><big>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></big></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFWriteRawStrip.3tiff.html b/tiff/html/man/TIFFWriteRawStrip.3tiff.html
new file mode 100644
index 0000000..95b4857
--- /dev/null
+++ b/tiff/html/man/TIFFWriteRawStrip.3tiff.html
@@ -0,0 +1,144 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFWriteRawstrip</title>
+</head>
+<body>
+
+<h1 align=center>TIFFWriteRawstrip</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFWriteRawStrip &minus; write a strip of raw data to an
+open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>tsize_t TIFFWriteRawStrip(TIFF *</b><i>tif</i><b>,
+tstrip_t</b> <i>strip</i><b>, tdata_t</b> <i>buf</i><b>,
+tsize_t</b> <i>size</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Append <i>size</i> bytes of raw data to the specified
+strip.</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The strip number must be valid according to the current
+settings of the <i>ImageLength</i> and <i>RowsPerStrip</i>
+tags. An image may be dynamically grown by increasing the
+value of <i>ImageLength</i> prior to each call to
+<i>TIFFWriteRawStrip</i>.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>&minus;1 is returned if an error occurred. Otherwise, the
+value of <i>size</i> is returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>%s: File not open for writing</b>. The file was opened
+for reading, not writing.</p>
+<!-- INDENTATION -->
+<p><b>Can not write scanlines to a tiled image</b>. The
+image is assumed to be organized in tiles because the
+<i>TileWidth</i> and <i>TileLength</i> tags have been set
+with <b>TIFFSetField</b>(3TIFF).</p>
+<!-- INDENTATION -->
+<p><b>%s: Must set &quot;ImageWidth&quot; before writing
+data</b>. The image&rsquo;s width has not be set before the
+first write. See <b>TIFFSetField</b>(3TIFF) for information
+on how to do this.</p>
+<!-- INDENTATION -->
+<p><b>%s: Must set &quot;PlanarConfiguration&quot; before
+writing data</b>. The organization of data has not be
+defined before the first write. See
+<b>TIFFSetField</b>(3TIFF) for information on how to do
+this.</p>
+<!-- INDENTATION -->
+<p><b>%s: No space for strip arrays&quot;</b>. There was not
+enough space for the arrays that hold strip offsets and byte
+counts.</p>
+<!-- INDENTATION -->
+<p><b>%s: Strip %d out of range, max %d</b>. The specified
+strip is not a valid strip according to the currently
+specified image dimensions.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF),
+<b>TIFFWriteEncodedStrip</b>(3TIFF),
+<b>TIFFWriteScanline</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFWriteRawTile.3tiff.html b/tiff/html/man/TIFFWriteRawTile.3tiff.html
new file mode 100644
index 0000000..3d18ed1
--- /dev/null
+++ b/tiff/html/man/TIFFWriteRawTile.3tiff.html
@@ -0,0 +1,128 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFWriteRawtile</title>
+</head>
+<body>
+
+<h1 align=center>TIFFWriteRawtile</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFWriteRawTile &minus; write a tile of raw data to an
+open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>tsize_t TIFFWriteRawTile(TIFF *</b><i>tif</i><b>,
+ttile_t</b> <i>tile</i><b>, tdata_t</b> <i>buf</i><b>,
+tsize_t</b> <i>size</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Append <i>size</i> bytes of raw data to the specified
+tile.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>&minus;1 is returned if an error occurred. Otherwise, the
+value of <i>size</i> is returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>%s: File not open for writing</b>. The file was opened
+for reading, not writing.</p>
+<!-- INDENTATION -->
+<p><b>Can not write tiles to a stripped image</b>. The image
+is assumed to be organized in strips because neither of the
+<i>TileWidth</i> or <i>TileLength</i> tags have been set
+with <b>TIFFSetField</b>(3TIFF).</p>
+<!-- INDENTATION -->
+<p><b>%s: Must set &quot;ImageWidth&quot; before writing
+data</b>. The image&rsquo;s width has not be set before the
+first write. See <b>TIFFSetField</b>(3TIFF) for information
+on how to do this.</p>
+<!-- INDENTATION -->
+<p><b>%s: Must set &quot;PlanarConfiguration&quot; before
+writing data</b>. The organization of data has not be
+defined before the first write. See
+<b>TIFFSetField</b>(3TIFF) for information on how to do
+this.</p>
+<!-- INDENTATION -->
+<p><b>%s: No space for tile arrays&quot;</b>. There was not
+enough space for the arrays that hold tile offsets and byte
+counts.</p>
+<!-- INDENTATION -->
+<p><b>%s: Specified tile %d out of range, max %d</b>. The
+specified tile is not valid according to the currently
+specified image dimensions.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF),
+<b>TIFFWriteEncodedTile</b>(3TIFF),
+<b>TIFFWriteScanline</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFWriteScanline.3tiff.html b/tiff/html/man/TIFFWriteScanline.3tiff.html
new file mode 100644
index 0000000..bb9323d
--- /dev/null
+++ b/tiff/html/man/TIFFWriteScanline.3tiff.html
@@ -0,0 +1,206 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFWriteScanline</title>
+</head>
+<body>
+
+<h1 align=center>TIFFWriteScanline</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFWriteScanline &minus; write a scanline to an open
+<small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFWriteScanline(TIFF *</b><i>tif</i><b>,
+tdata_t</b> <i>buf</i><b>, uint32</b> <i>row</i><b>,
+tsample_t</b> <i>sample</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Write data to a file at the specified row. The
+<i>sample</i> parameter is used only if data are organized
+in separate planes (<i>PlanarConfiguration</i>=2). The data
+are assumed to be uncompressed and in the native bit- and
+byte-order of the host machine. The data written to the file
+is compressed according to the compression scheme of the
+current <small>TIFF</small> directory (see further below).
+If the current scanline is past the end of the current
+subfile, the <i>ImageLength</i> field is automatically
+increased to include the scanline (except for
+<i>PlanarConfiguration</i>=2, where the <i>ImageLength</i>
+cannot be changed once the first data are written). If the
+<i>ImageLength</i> is increased, the <i>StripOffsets</i> and
+<i>StripByteCounts</i> fields are similarly enlarged to
+reflect data written past the previous end of image.</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The library writes encoded data using the native machine
+byte order. Correctly implemented <small>TIFF</small>
+readers are expected to do any necessary byte-swapping to
+correctly process image data with BitsPerSample greater than
+8. The library attempts to hide bit-ordering differences
+between the image and the native machine by converting data
+from the native machine order.</p>
+<!-- INDENTATION -->
+<p>In C++ the <i>sample</i> parameter defaults to 0.</p>
+<!-- INDENTATION -->
+<p>Once data are written to a file for the current
+directory, the values of certain tags may not be altered;
+see <i>TIFFSetField</i>(3TIFF) for more information.</p>
+<!-- INDENTATION -->
+<p>It is not possible to write scanlines to a file that uses
+a tiled organization. The routine <i>TIFFIsTiled</i> can be
+used to determine if the file is organized as tiles or
+strips.</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFWriteScanline</i> returns &minus;1 if it
+immediately detects an error and 1 for a successful
+write.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<i>TIFFError</i>(3TIFF) routine.</p>
+<!-- INDENTATION -->
+<p><b>%s: File not open for writing .</b> The file was
+opened for reading, not writing.</p>
+<!-- INDENTATION -->
+<p><b>Can not write scanlines to a tiled image</b>. An
+attempt was made to write a scanline to a tiled image. The
+image is assumed to be organized in tiles because the
+<i>TileWidth</i> and <i>TileLength</i> tags have been set
+with <i>TIFFSetField</i>(3TIFF).</p>
+<!-- INDENTATION -->
+<p><b>Compression algorithm does not support random
+access</b>. Data was written in a non-sequential order to a
+file that uses a compression algorithm and that has
+<i>RowsPerStrip</i> greater than one. That is, data in the
+image is to be stored in a compressed form, and with
+multiple rows packed into a strip. In this case, the library
+does not support random access to the data. The data should
+either be written as entire strips, sequentially by rows, or
+the value of <i>RowsPerStrip</i> should be set to one.</p>
+<!-- INDENTATION -->
+<p><b>%s: Must set &quot;ImageWidth&quot; before writing
+data</b>. The image&rsquo;s width has not be set before the
+first write. See <b>TIFFSetField</b>(3TIFF) for information
+on how to do this.</p>
+<!-- INDENTATION -->
+<p><b>%s: Must set &quot;PlanarConfiguration&quot; before
+writing data</b>. The organization of data has not be
+defined before the first write. See
+<b>TIFFSetField</b>(3TIFF) for information on how to do
+this.</p>
+<!-- INDENTATION -->
+<p><b>Can not change &quot;ImageLength&quot; when using
+separate planes</b>. Separate image planes are being used
+(<i>PlanarConfiguration</i>=2), but the number of rows has
+not been specified before the first write. The library
+supports the dynamic growth of an image only when data are
+organized in a contiguous manner
+(<i>PlanarConfiguration</i>=1).</p>
+<!-- INDENTATION -->
+<p><b>%d: Sample out of range, max %d</b>. The <i>sample</i>
+parameter was greater than the value of the SamplesPerPixel
+tag.</p>
+<!-- INDENTATION -->
+<p><b>%s: No space for strip arrays .</b> There was not
+enough space for the arrays that hold strip offsets and byte
+counts.</p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Writing subsampled YCbCR data does not work correctly
+because, for <i>PlanarConfiguration</i>=2 the size of a
+scanline is not calculated on a per-sample basis, and for
+<i>PlanarConfiguration</i>=1 the library does not pack the
+block-interleaved samples.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF),
+<b>TIFFWriteEncodedStrip</b>(3TIFF),
+<b>TIFFWriteRawStrip</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFWriteTile.3tiff.html b/tiff/html/man/TIFFWriteTile.3tiff.html
new file mode 100644
index 0000000..d6bc5d8
--- /dev/null
+++ b/tiff/html/man/TIFFWriteTile.3tiff.html
@@ -0,0 +1,115 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFWriteTile</title>
+</head>
+<body>
+
+<h1 align=center>TIFFWriteTile</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#RETURN VALUES">RETURN VALUES</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFWriteTile &minus; encode and write a tile of data to
+an open <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>tsize_t TIFFWriteTile(TIFF *</b><i>tif</i><b>,
+tdata_t</b> <i>buf</i><b>, uint32</b> <i>x</i><b>,
+uint32</b> <i>y</i><b>, uint32</b> <i>z</i><b>,
+tsample_t</b> <i>sample</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Write the data for the tile <i>containing</i> the
+specified coordinates. The data in <i>buf</i> are is
+(potentially) compressed, and written to the indicated file,
+normally being appended to the end of the file. The buffer
+must be contain an entire tile of data. Applications should
+call the routine <i>TIFFTileSize</i> to find out the size
+(in bytes) of a tile buffer. The <i>x</i> and <i>y</i>
+parameters are always used by <i>TIFFWriteTile</i>. The
+<i>z</i> parameter is used if the image is deeper than 1
+slice (<i>ImageDepth</i>&gt;1). The <i>sample</i> parameter
+is used only if data are organized in separate planes
+(<i>PlanarConfiguration</i>=2).</p>
+</td>
+</table>
+<a name="RETURN VALUES"></a>
+<h2>RETURN VALUES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFWriteTile</i> returns &minus;1 if it detects an
+error; otherwise the number of bytes in the tile is
+returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>All error messages are directed to the
+<b>TIFFError</b>(3TIFF) routine.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFCheckTile</b>(3TIFF),
+<b>TIFFComputeTile</b>(3TIFF), <b>TIFFOpen</b>(3TIFF),
+<b>TIFFReadTile</b>(3TIFF), <b>TIFFWriteScanline</b>(3TIFF),
+<b>TIFFWriteEncodedTile</b>(3TIFF),
+<b>TIFFWriteRawTile</b>(3TIFF), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFbuffer.3tiff.html b/tiff/html/man/TIFFbuffer.3tiff.html
new file mode 100644
index 0000000..3d610ca
--- /dev/null
+++ b/tiff/html/man/TIFFbuffer.3tiff.html
@@ -0,0 +1,116 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:14 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFBUFFER</title>
+</head>
+<body>
+
+<h1 align=center>TIFFBUFFER</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFReadBufferSetup, TIFFWriteBufferSetup &minus; I/O
+buffering control routines</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<pre><b>#include &lt;tiffio.h&gt;
+
+int TIFFReadBufferSetup(TIFF *</b><i>tif</i><b>, tdata_t</b> <i>buffer</i><b>, tsize_t</b> <i>size</i><b>);
+int TIFFWriteBufferSetup(TIFF *</b><i>tif</i><b>, tdata_t</b> <i>buffer</i><b>, tsize_t</b> <i>size</i><b>);
+</b></pre>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following routines are provided for client-control of
+the I/O buffers used by the library. Applications need never
+use these routines; they are provided only for
+&lsquo;&lsquo;intelligent clients&rsquo;&rsquo; that wish to
+optimize memory usage and/or eliminate potential copy
+operations that can occur when working with images that have
+data stored without compression.</p>
+<!-- INDENTATION -->
+<p><i>TIFFReadBufferSetup</i> sets up the data buffer used
+to read raw (encoded) data from a file. If the specified
+pointer is <small>NULL</small> (zero), then a buffer of the
+appropriate size is allocated. Otherwise the caller must
+guarantee that the buffer is large enough to hold any
+individual strip of raw data. <i>TIFFReadBufferSetup</i>
+returns a non-zero value if the setup was successful and
+zero otherwise.</p>
+<!-- INDENTATION -->
+<p><i>TIFFWriteBufferSetup</i> sets up the data buffer used
+to write raw (encoded) data to a file. If the specified
+<i>size</i> is &minus;1 then the buffer size is selected to
+hold a complete tile or strip, or at least 8 kilobytes,
+whichever is greater. If the specified <i>buffer</i> is
+<small>NULL</small> (zero), then a buffer of the appropriate
+size is dynamically allocated. <i>TIFFWriteBufferSetup</i>
+returns a non-zero value if the setup was successful and
+zero otherwise.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>%s: No space for data buffer at scanline %ld</b>.
+<i>TIFFReadBufferSetup</i> was unable to dynamically
+allocate space for a data buffer.</p>
+<!-- INDENTATION -->
+<p><b>%s: No space for output buffer</b>.
+<i>TIFFWriteBufferSetup</i> was unable to dynamically
+allocate space for a data buffer.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFcodec.3tiff.html b/tiff/html/man/TIFFcodec.3tiff.html
new file mode 100644
index 0000000..8567b30
--- /dev/null
+++ b/tiff/html/man/TIFFcodec.3tiff.html
@@ -0,0 +1,116 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>CODEC</title>
+</head>
+<body>
+
+<h1 align=center>CODEC</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFFindCODEC, TIFFRegisterCODEC, TIFFUnRegisterCODEC,
+TIFFIsCODECConfigured &minus; codec-related utility
+routines</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>const TIFFCodec* TIFFFindCODEC(uint16</b>
+<i>scheme</i><b>);<br>
+TIFFCodec* TIFFRegisterCODEC(uint16</b> <i>scheme</i><b>,
+const char *</b><i>method</i><b>, TIFFInitMethod</b>
+<i>init</i><b>);<br>
+void TIFFUnRegisterCODEC(TIFFCodec
+*</b><i>codec</i><b>);<br>
+int TIFFIsCODECConfigured(uint16</b>
+<i>scheme</i><b>);</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>libtiff</i> supports a variety of compression schemes
+implemented by software <i>codecs</i>. Each codec adheres to
+a modular interface that provides for the decoding and
+encoding of image data; as well as some other methods for
+initialization, setup, cleanup, and the control of default
+strip and tile sizes. Codecs are identified by the
+associated value of the <small>TIFF</small>
+<i>Compression</i> tag; e.g. 5 for <small>LZW</small>
+compression.</p>
+<!-- INDENTATION -->
+<p>The <i>TIFFRegisterCODEC</i> routine can be used to
+augment or override the set of codecs available to an
+application. If the specified <i>scheme</i> already has a
+registered codec then it is <i>overridden</i> and any images
+with data encoded with this compression scheme will be
+decoded using the supplied coded.</p>
+<!-- INDENTATION -->
+<p><i>TIFFIsCODECConfigured</i> returns 1 if the codec is
+configured and working. Otherwise 0 will be returned.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>No space to register compression scheme %s</b>.
+<i>TIFFRegisterCODEC</i> was unable to allocate memory for
+the data structures needed to register a codec.</p>
+<!-- INDENTATION -->
+<p><b>Cannot remove compression scheme %s; not
+registered</b>. <i>TIFFUnRegisterCODEC</i> did not locate
+the specified codec in the table of registered compression
+schemes.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFcolor.3tiff.html b/tiff/html/man/TIFFcolor.3tiff.html
new file mode 100644
index 0000000..7e4eea5
--- /dev/null
+++ b/tiff/html/man/TIFFcolor.3tiff.html
@@ -0,0 +1,975 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>COLOR</title>
+</head>
+<body>
+
+<h1 align=center>COLOR</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFYCbCrToRGBInit, TIFFYCbCrtoRGB, TIFFCIELabToRGBInit,
+TIFFCIELabToXYZ, TIFFXYZToRGB &minus; color conversion
+routines.</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB
+*</b><i>ycbcr</i><b>, float *</b><i>luma</i><b>, float
+*</b><i>refBlackWhite&quot;</i><b>);&quot;<br>
+void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *</b><i>ycbcr</i><b>,
+uint32</b> <i>Y</i><b>, int32</b> <i>Cb</i><b>, int32</b>
+<i>Cr</i><b>, uint32 *</b><i>R</i><b>, uint32
+*</b><i>G</i><b>, uint32 *</b><i>B</i> <b>);</b></p>
+<!-- INDENTATION -->
+<p><b>int TIFFCIELabToRGBInit(TIFFCIELabToRGB
+*</b><i>cielab</i><b>, TIFFDisplay *</b><i>display</i><b>,
+float *</b><i>refWhite</i><b>);<br>
+void TIFFCIELabToXYZ(TIFFCIELabToRGB *</b><i>cielab</i><b>,
+uint32</b> <i>L</i><b>, int32</b> <i>a</i><b>, int32</b>
+<i>b</i><b>, float *</b><i>X</i><b>, float *</b><i>Y</i><b>,
+float *</b><i>Z</i><b>);<br>
+void TIFFXYZToRGB(TIFFCIELabToRGB *</b><i>cielab</i><b>,
+float</b> <i>X</i><b>, float</b> <i>Y</i><b>, float</b>
+<i>Z&quot;</i><b>,</b><i>uint32</i><b>*&quot;</b><i>R</i><b>,
+uint32 *</b><i>G</i><b>, uint32 *</b><i>B</i><b>);</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFF supports several color spaces for images stored in
+that format. There is usually a problem of application to
+handle the data properly and convert between different
+colorspaces for displaying and printing purposes. To
+simplify this task libtiff implements several color
+conversion routines itself. In particular, these routines
+used in <b>TIFFRGBAImage(3TIFF)</b> interface.</p>
+<!-- INDENTATION -->
+<p><b>TIFFYCbCrToRGBInit()</b> used to initialize
+<i>YCbCr</i> to <i>RGB</i> conversion state. Allocating and
+freeing of the <i>ycbcr</i> structure belongs to programmer.
+<i>TIFFYCbCrToRGB</i> defined in <b>tiffio.h</b> as</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>typedef struct { /* YCbCr-&gt;RGB support */
+ TIFFRGBValue* clamptab; /* range clamping table */
+</pre>
+</td>
+</table>
+<!-- TABS -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+
+<p>int*</p>
+<td width="28%"></td>
+<td width="-3%"></td>
+<td width="12%"></td>
+<td width="6%">
+
+<p>Cr_r_tab;<br>
+int*</p>
+</td>
+<td width="56%">
+</td>
+<tr valign="top" align="left">
+<td width="28%"></td>
+<td width="-3%"></td>
+<td width="12%"></td>
+<td width="6%">
+
+<p>Cb_b_tab;<br>
+int32*</p>
+</td>
+<td width="56%">
+</td>
+<tr valign="top" align="left">
+<td width="28%"></td>
+<td width="-3%"></td>
+<td width="12%"></td>
+<td width="6%">
+
+<p>Cr_g_tab;<br>
+int32*</p>
+</td>
+<td width="56%">
+</td>
+<tr valign="top" align="left">
+<td width="28%"></td>
+<td width="-3%"></td>
+<td width="12%"></td>
+<td width="6%">
+
+<p>Cb_g_tab;</p>
+</td>
+<td width="56%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>int32* Y_tab;<br>
+} TIFFYCbCrToRGB;</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>luma</i> is a float array of three values representing
+proportions of the red, green and blue in luminance, Y (see
+section 21 of the TIFF 6.0 specification, where the YCbCr
+images discussed). <i>TIFFTAG_YCBCRCOEFFICIENTS</i> holds
+that values in TIFF file. <i>refBlackWhite</i> is a float
+array of 6 values which specifies a pair of headroom and
+footroom image data values (codes) for each image component
+(see section 20 of the TIFF 6.0 specification where the
+colorinmetry fields discussed).
+<i>TIFFTAG_REFERENCEBLACKWHITE</i> is responsible for
+storing these values in TIFF file. Following code snippet
+should helps to understand the the technique:</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>float *luma, *refBlackWhite;
+uint16 hs, vs;
+
+/* Initialize structures */
+ycbcr = (TIFFYCbCrToRGB*)
+</pre>
+</td>
+</table>
+<!-- TABS -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>_TIFFmalloc(TIFFroundup(sizeof(TIFFYCbCrToRGB),
+sizeof(long))</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>+ 4*256*sizeof(TIFFRGBValue)</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>+ 2*256*sizeof(int)</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>+ 3*256*sizeof(int32));</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>if (ycbcr == NULL) {<br>
+TIFFError(&quot;YCbCr-&gt;RGB&quot;,</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="4" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>&quot;No space for YCbCr-&gt;RGB conversion
+state&quot;);</p>
+</td>
+<td width="62%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>exit(0);<br>
+}</p>
+<!-- INDENTATION -->
+<p>TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRCOEFFICIENTS,
+&amp;luma);<br>
+TIFFGetFieldDefaulted(tif, TIFFTAG_REFERENCEBLACKWHITE,
+&amp;refBlackWhite);<br>
+if (TIFFYCbCrToRGBInit(ycbcr, luma, refBlackWhite) &lt;
+0)</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>exit(0);</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>/* Start conversion */<br>
+uint32 r, g, b;<br>
+uint32 Y;<br>
+int32 Cb, Cr;</p>
+<!-- INDENTATION -->
+<p>for each pixel in image</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>TIFFYCbCrtoRGB(img-&gt;ycbcr, Y, Cb, Cr, &amp;r, &amp;g,
+&amp;b);</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>/* Free state structure */<br>
+_TIFFfree(ycbcr);</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFCIELabToRGBInit()</b> initializes the <i>CIE
+L*a*b* 1976</i> to <i>RGB</i> conversion state.
+<b>TIFFCIELabToRGB</b> defined as</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>#define CIELABTORGB_TABLE_RANGE 1500
+
+</pre>
+</td>
+</table>
+<!-- TABS -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="9" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="6%">
+
+<p>typedef struct {</p>
+</td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>/* CIE Lab 1976-&gt;RGB support */</p>
+</td>
+<td width="6%"></td>
+<td width="37%">
+</td>
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>int</p>
+</td>
+<td width="6%">
+
+<p>range;</p>
+</td>
+<td width="6%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>/* Size of conversion table */</p>
+</td>
+<td width="6%"></td>
+<td width="37%">
+</td>
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>float</p>
+</td>
+<td width="6%"></td>
+<td width="6%">
+
+<p>rstep, gstep, bstep;</p>
+</td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="37%">
+</td>
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>float</p>
+</td>
+<td width="6%"></td>
+<td width="6%">
+
+<p>X0, Y0, Z0;</p>
+</td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%">
+
+<p>/* Reference white point */</p>
+</td>
+<td width="37%">
+</td>
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="6%"></td>
+<td width="6%">
+
+<p>TIFFDisplay display;</p>
+</td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="37%">
+</td>
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>float</p>
+</td>
+<td width="6%"></td>
+<td width="6%">
+
+<p>Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr
+to r */</p>
+</td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="37%">
+</td>
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>float</p>
+</td>
+<td width="6%"></td>
+<td width="6%">
+
+<p>Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg
+to g */</p>
+</td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="37%">
+</td>
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>float</p>
+</td>
+<td width="6%"></td>
+<td width="6%">
+
+<p>Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb
+to b */</p>
+</td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="6%"></td>
+<td width="37%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>} TIFFCIELabToRGB;</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>display</i> is a display device description, declared
+as</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>typedef struct {
+</pre>
+</td>
+</table>
+<!-- TABS -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_mat[3][3]; /* XYZ -&gt; luminance matrix */</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_YCR; /* Light o/p for reference white */</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_YCG;</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_YCB;</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>uint32 d_Vrwr; /* Pixel values for ref. white */</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>uint32 d_Vrwg;</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>uint32 d_Vrwb;</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_Y0R; /* Residual light for black pixel */</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_Y0G;</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_Y0B;</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_gammaR; /* Gamma values for the three guns
+*/</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_gammaG;</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>float d_gammaB;</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>} TIFFDisplay;</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>For example, the one can use sRGB device, which has the
+following parameters:</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>TIFFDisplay display_sRGB = {
+</pre>
+</td>
+</table>
+<!-- TABS -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>{ /* XYZ -&gt; luminance matrix */</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>{ 3.2410F, -1.5374F, -0.4986F },</p>
+</td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>{ -0.9692F, 1.8760F, 0.0416F },</p>
+</td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>{ 0.0556F, -0.2040F, 1.0570F }</p>
+</td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>},</p>
+</td>
+<td width="6%">
+</td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>100.0F, 100.0F, 100.0F, /* Light o/p for reference white
+*/</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>255, 255, 255, /* Pixel values for ref. white */</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>1.0F, 1.0F, 1.0F, /* Residual light o/p for black pixel
+*/</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>2.4F, 2.4F, 2.4F, /* Gamma values for the three guns
+*/</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>};</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>refWhite</i> is a color temperature of the reference
+white. The <i>TIFFTAG_WHITEPOINT</i> contains the
+chromaticity of the white point of the image from where the
+reference white can be calculated using following
+formulae:</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>refWhite_Y = 100.0<br>
+refWhite_X = whitePoint_x / whitePoint_y * refWhite_Y<br>
+refWhite_Z = (1.0 - whitePoint_x - whitePoint_y) /
+whitePoint_y * refWhite_X</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The conversion itself performed in two steps: at the
+first one we will convert <i>CIE L*a*b* 1976</i> to <i>CIE
+XYZ</i> using <b>TIFFCIELabToXYZ()</b> routine, and at the
+second step we will convert <i>CIE XYZ</i> to <i>RGB</i>
+using <b>TIFFXYZToRGB().</b> Look at the code sample
+below:</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>float *whitePoint;
+float refWhite[3];
+
+/* Initialize structures */
+img-&gt;cielab = (TIFFCIELabToRGB *)
+</pre>
+</td>
+</table>
+<!-- TABS -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>_TIFFmalloc(sizeof(TIFFCIELabToRGB));</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>if (!cielab) {</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>TIFFError(&quot;CIE L*a*b*-&gt;RGB&quot;,</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>&quot;No space for CIE L*a*b*-&gt;RGB conversion
+state.&quot;);</p>
+</td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>exit(0);</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>}</p>
+<!-- INDENTATION -->
+<p>TIFFGetFieldDefaulted(tif, TIFFTAG_WHITEPOINT,
+&amp;whitePoint);<br>
+refWhite[1] = 100.0F;<br>
+refWhite[0] = whitePoint[0] / whitePoint[1] *
+refWhite[1];<br>
+refWhite[2] = (1.0F - whitePoint[0] -
+whitePoint[1])</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>/ whitePoint[1] * refWhite[1];</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>if (TIFFCIELabToRGBInit(cielab, &amp;display_sRGB,
+refWhite) &lt; 0) {</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>TIFFError(&quot;CIE L*a*b*-&gt;RGB&quot;,</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+</td>
+<td width="6%">
+
+<p>&quot;Failed to initialize CIE L*a*b*-&gt;RGB conversion
+state.&quot;);</p>
+</td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>_TIFFfree(cielab);</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="0%"></td>
+<td width="6%">
+
+<p>exit(0);</p>
+</td>
+<td width="6%"></td>
+<td width="62%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>}</p>
+<!-- INDENTATION -->
+<p>/* Now we can start to convert */<br>
+uint32 r, g, b;<br>
+uint32 L;<br>
+int32 a, b;<br>
+float X, Y, Z;</p>
+<!-- INDENTATION -->
+<p>for each pixel in image</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>TIFFCIELabToXYZ(cielab, L, a, b, &amp;X, &amp;Y,
+&amp;Z);</p>
+</td>
+<tr valign="top" align="left">
+<td width="24%"></td>
+<td width="75%">
+
+<p>TIFFXYZToRGB(cielab, X, Y, Z, &amp;r, &amp;g,
+&amp;b);</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>/* Don&rsquo;t forget to free the state structure */<br>
+_TIFFfree(cielab);</p></td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFRGBAImage</b>(3TIFF) <b>libtiff</b>(3TIFF),</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFmemory.3tiff.html b/tiff/html/man/TIFFmemory.3tiff.html
new file mode 100644
index 0000000..746b5ec
--- /dev/null
+++ b/tiff/html/man/TIFFmemory.3tiff.html
@@ -0,0 +1,110 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>MEMORY</title>
+</head>
+<body>
+
+<h1 align=center>MEMORY</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>_TIFFmalloc, _TIFFrealloc, _TIFFfree, _TIFFmemset,
+_TIFFmemcpy, _TIFFmemcmp, &minus; memory management-related
+functions for use with <small>TIFF</small> files</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>tdata_t _TIFFmalloc(tsize_t</b> <i>size</i><b>);<br>
+tdata_t _TIFFrealloc(tdata_t</b> <i>buffer</i><b>,
+tsize_t</b> <i>size</i><b>);<br>
+void _TIFFfree(tdata_t</b> <i>buffer</i><b>);<br>
+void _TIFFmemset(tdata_t</b> <i>s</i><b>, int</b>
+<i>c</i><b>, tsize_t</b> <i>n</i><b>);<br>
+void _TIFFmemcpy(tdata_t</b> <i>dest</i><b>, const
+tdata_t</b> <i>src</i><b>, tsize_t</b> <i>n</i><b>);<br>
+int _TIFFmemcmp(const tdata_t</b> <i>s1</i><b>, const
+tdata_t</b> <i>s2</i><b>, tsize_t</b> <i>n</i><b>);</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>These routines are provided for writing portable software
+that uses <i>libtiff</i>; they hide any memory-management
+related issues, such as dealing with segmented architectures
+found on 16-bit machines.</p>
+<!-- INDENTATION -->
+<p><i>_TIFFmalloc</i> and <i>_TIFFrealloc</i> are used to
+dynamically allocate and reallocate memory used by
+<i>libtiff</i>; such as memory passed into the I/O routines.
+Memory allocated through these interfaces is released back
+to the system using the <i>_TIFFfree</i> routine.</p>
+<!-- INDENTATION -->
+<p>Memory allocated through one of the above interfaces can
+be set to a known value using <i>_TIFFmemset</i>, copied to
+another memory location using <i>_TIFFmemcpy</i>, or
+compared for equality using <i>_TIFFmemcmp</i>. These
+routines conform to the equivalent <small>ANSI</small> C
+routines: <i>memset</i>, <i>memcpy</i>, and <i>memcmp</i>,
+repsectively.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>malloc</b>(3), <b>memory</b>(3),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFquery.3tiff.html b/tiff/html/man/TIFFquery.3tiff.html
new file mode 100644
index 0000000..e27354a
--- /dev/null
+++ b/tiff/html/man/TIFFquery.3tiff.html
@@ -0,0 +1,148 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:15 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>QUERY</title>
+</head>
+<body>
+
+<h1 align=center>QUERY</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFCurrentRow, TIFFCurrentStrip, TIFFCurrentTile,
+TIFFCurrentDirectory, TIFFLastDirectory, TIFFFileno,
+TIFFFileName, TIFFGetMode, TIFFIsTiled, TIFFIsByteSwapped,
+TIFFIsUpSampled, TIFFIsMSB2LSB, TIFFGetVersion &minus; query
+routines</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>uint32 TIFFCurrentRow(TIFF*</b> <i>tif</i><b>)<br>
+tstrip_t TIFFCurrentStrip(TIFF*</b> <i>tif</i><b>)<br>
+ttile_t TIFFCurrentTile(TIFF*</b> <i>tif</i><b>)<br>
+tdir_t TIFFCurrentDirectory(TIFF*</b> <i>tif</i><b>)<br>
+int TIFFLastDirectory(TIFF*</b> <i>tif</i><b>)<br>
+int TIFFFileno(TIFF*</b> <i>tif</i><b>)<br>
+char* TIFFFileName(TIFF*</b> <i>tif</i><b>)<br>
+int TIFFGetMode(TIFF*</b> <i>tif</i><b>)<br>
+int TIFFIsTiled(TIFF*</b> <i>tif</i><b>)<br>
+int TIFFIsByteSwapped(TIFF*</b> <i>tif</i><b>)<br>
+int TIFFIsUpSampled(TIFF*</b> <i>tif</i><b>)<br>
+int TIFFIsMSB2LSB(TIFF*</b> <i>tif</i><b>)<br>
+const char* TIFFGetVersion(void)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following routines return status information about an
+open <small>TIFF</small> file.</p>
+<!-- INDENTATION -->
+<p><i>TIFFCurrentDirectory</i> returns the index of the
+current directory (directories are numbered starting at 0).
+This number is suitable for use with the
+<i>TIFFSetDirectory</i> routine.</p>
+<!-- INDENTATION -->
+<p><i>TIFFLastDirectory</i> returns a non-zero value if the
+current directory is the last directory in the file;
+otherwise zero is returned.</p>
+<!-- INDENTATION -->
+<p><i>TIFFCurrentRow</i>, <i>TIFFCurrentStrip</i>, and
+<i>TIFFCurrentTile</i>, return the current row, strip, and
+tile, respectively, that is being read or written. These
+values are updated each time a read or write is done.</p>
+<!-- INDENTATION -->
+<p><i>TIFFFileno</i> returns the underlying file descriptor
+used to access the <small>TIFF</small> image in the
+filesystem.</p>
+<!-- INDENTATION -->
+<p><i>TIFFFileName</i> returns the pathname argument passed
+to <i>TIFFOpen</i> or <i>TIFFFdOpen</i>.</p>
+<!-- INDENTATION -->
+<p><i>TIFFGetMode</i> returns the mode with which the
+underlying file was opened. On <small>UNIX</small> systems,
+this is the value passed to the <i>open</i>(2) system
+call.</p>
+<!-- INDENTATION -->
+<p><i>TIFFIsTiled</i> returns a non-zero value if the image
+data has a tiled organization. Zero is returned if the image
+data is organized in strips.</p>
+<!-- INDENTATION -->
+<p><i>TIFFIsByteSwapped</i> returns a non-zero value if the
+image data was in a different byte-order than the host
+machine. Zero is returned if the TIFF file and local host
+byte-orders are the same. Note that TIFFReadTile(),
+TIFFReadStrip() and TIFFReadScanline() functions already
+normally perform byte swapping to local host order if
+needed.</p>
+<!-- INDENTATION -->
+<p><i>TIFFIsUpSampled</i> returns a non-zero value if image
+data returned through the read interface routines is being
+up-sampled. This can be useful to applications that want to
+calculate I/O buffer sizes to reflect this usage (though the
+usual strip and tile size routines already do this).</p>
+<!-- INDENTATION -->
+<p><i>TIFFIsMSB2LSB</i> returns a non-zero value if the
+image data is being returned with bit 0 as the most
+significant bit.</p>
+<!-- INDENTATION -->
+<p><i>TIFFGetVersion</i> returns an <small>ASCII</small>
+string that has a version stamp for the <small>TIFF</small>
+library software.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>libtiff</i>(3TIFF), <i>TIFFOpen</i>(3TIFF),
+<i>TIFFFdOpen</i>(3TIFF)</p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFsize.3tiff.html b/tiff/html/man/TIFFsize.3tiff.html
new file mode 100644
index 0000000..54fb71b
--- /dev/null
+++ b/tiff/html/man/TIFFsize.3tiff.html
@@ -0,0 +1,95 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFSIZE</title>
+</head>
+<body>
+
+<h1 align=center>TIFFSIZE</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFScanlineSize, TIFFRasterScanlineSize, &minus; return
+the size of various items associated with an open
+<small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>tsize_t TIFFRasterScanlineSize(TIFF
+*</b><i>tif</i><b>)<br>
+tsize_t TIFFScanlineSize(TIFF *</b><i>tif</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFScanlineSize</i> returns the size in bytes of a
+row of data as it would be returned in a call to
+<i>TIFFReadScanline</i>, or as it would be expected in a
+call to <i>TIFFWriteScanline</i>.</p>
+<!-- INDENTATION -->
+<p><i>TIFFRasterScanlineSize</i> returns the size in bytes
+of a complete decoded and packed raster scanline. Note that
+this value may be different from the value returned by
+<i>TIFFScanlineSize</i> if data is stored as separate
+planes.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFOpen</b>(3TIFF), <b>TIFFReadScanline</b>(3TIFF),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFstrip.3tiff.html b/tiff/html/man/TIFFstrip.3tiff.html
new file mode 100644
index 0000000..a0fc358
--- /dev/null
+++ b/tiff/html/man/TIFFstrip.3tiff.html
@@ -0,0 +1,129 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFSTRIP</title>
+</head>
+<body>
+
+<h1 align=center>TIFFSTRIP</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFDefaultStripSize, TIFFStripSize, TIFFVStripSize,
+TIFFRawStripSize, TIFFComputeStrip, TIFFNumberOfStrips
+&minus; strip-related utility routines</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>uint32 TIFFDefaultStripSize(TIFF *</b><i>tif</i><b>,
+uint32</b> <i>estimate</i><b>)<br>
+tsize_t TIFFStripSize(TIFF *</b><i>tif</i><b>)<br>
+tsize_t TIFFVStripSize(TIFF *</b><i>tif</i><b>, uint32</b>
+<i>nrows</i><b>)<br>
+tsize_t TIFFRawStripSize(TIFF *</b><i>tif</i><b>,
+tstrip_t</b> <i>strip</i><b>)<br>
+tstrip_t TIFFComputeStrip(TIFF *</b><i>tif</i><b>,
+uint32</b> <i>row</i><b>, tsample_t</b>
+<i>sample</i><b>)<br>
+tstrip_t TIFFNumberOfStrips(TIFF *</b><i>tif</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFDefaultStripSize</i> returns the number of rows
+for a reasonable-sized strip according to the current
+settings of the <i>ImageWidth</i>, <i>BitsPerSample</i>,
+<i>SamplesPerPixel</i>, tags and any compression-specific
+requirements. If the <i>estimate</i> parameter, if non-zero,
+then it is taken as an estimate of the desired strip size
+and adjusted according to any compression-specific
+requirements. The value returned by this function is
+typically used to define the <i>RowsPerStrip</i> tag. In
+lieu of any unusual requirements <i>TIFFDefaultStripSize</i>
+tries to create strips that have approximately 8 kilobytes
+of uncompressed data.</p>
+<!-- INDENTATION -->
+<p><i>TIFFStripSize</i> returns the equivalent size for a
+strip of data as it would be returned in a call to
+<i>TIFFReadEncodedStrip</i> or as it would be expected in a
+call to <i>TIFFWriteEncodedStrip</i>.</p>
+<!-- INDENTATION -->
+<p><i>TIFFVStripSize</i> returns the number of bytes in a
+strip with <i>nrows</i> rows of data.</p>
+<!-- INDENTATION -->
+<p><i>TIFFRawStripSize</i> returns the number of bytes in a
+raw strip (i.e. not decoded).</p>
+<!-- INDENTATION -->
+<p><i>TIFFComputeStrip</i> returns the strip that contains
+the specified coordinates. A valid strip is always returned;
+out-of-range coordinate values are clamped to the bounds of
+the image. The <i>row</i> parameter is always used in
+calculating a strip. The <i>sample</i> parameter is used
+only if data are organized in separate planes
+(<i>PlanarConfiguration</i>=2).</p>
+<!-- INDENTATION -->
+<p><i>TIFFNumberOfStrips</i> returns the number of strips in
+the image.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFReadEncodedStrip</b>(3TIFF),
+<b>TIFFReadRawStrip</b>(3TIFF),
+<b>TIFFWriteEncodedStrip</b>(3TIFF),
+<b>TIFFWriteRawStrip</b>(3TIFF), <b>libtiff</b>(3TIFF),</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFswab.3tiff.html b/tiff/html/man/TIFFswab.3tiff.html
new file mode 100644
index 0000000..2924a38
--- /dev/null
+++ b/tiff/html/man/TIFFswab.3tiff.html
@@ -0,0 +1,110 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>SWAB</title>
+</head>
+<body>
+
+<h1 align=center>SWAB</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFGetBitRevTable, TIFFReverseBits, TIFFSwabShort,
+TIFFSwabLong, TIFFSwabArrayOfShort, TIFFSwabArrayOfLong
+&minus; byte- and bit-swapping routines</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>const unsigned char* TIFFGetBitRevTable(int</b>
+<i>reversed</i><b>)<br>
+void TIFFReverseBits(u_char *</b><i>data</i><b>, unsigned
+long</b> <i>nbytes</i><b>)<br>
+void TIFFSwabShort(uint16 *</b><i>data</i><b>)<br>
+void TIFFSwabLong(uint32 *</b><i>data</i><b>)<br>
+void TIFFSwabArrayOfShort(uint16 *</b><i>data</i><b>,
+unsigned long</b> <i>nshorts</i><b>)<br>
+void TIFFSwabArrayOfLong(uint32 *</b><i>data</i><b>,
+unsigned long</b> <i>nlongs</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following routines are used by the library to swap
+16- and 32-bit data and to reverse the order of bits in
+bytes.</p>
+<!-- INDENTATION -->
+<p><i>TIFFSwabShort</i> and <i>TIFFSwabLong</i> swap the
+bytes in a single 16-bit and 32-bit item, respectively.
+<i>TIFFSwabArrayOfShort</i> and <i>TIFFSwabArrayOfLong</i>
+swap the bytes in an array of 16-bit and 32-bit items,
+respectively.</p>
+<!-- INDENTATION -->
+<p><i>TIFFReverseBits</i> replaces each byte in <i>data</i>
+with the equivalent bit-reversed value. This operation is
+performed with a lookup table, which is returned using the
+<i>TIFFGetBitRevTable</i> function. <i>reversed</i>
+parameter specifies which table should be returned. Supply
+<i>1</i> if you want bit reversal table. Supply <i>0</i> to
+get the table that do not reverse bit values. It is a lookup
+table that can be used as an <i>identity function</i>; i.e.
+<i>TIFFNoBitRevTable[n] == n</i>.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/TIFFtile.3tiff.html b/tiff/html/man/TIFFtile.3tiff.html
new file mode 100644
index 0000000..e8e0008
--- /dev/null
+++ b/tiff/html/man/TIFFtile.3tiff.html
@@ -0,0 +1,141 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:17 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFTILE</title>
+</head>
+<body>
+
+<h1 align=center>TIFFTILE</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>TIFFTileSize, TIFFTileRowSize, TIFFVTileSize,
+TIFFDefaultTileSize, TIFFComputeTile, TIFFCheckTile,
+TIFFNumberOfTiles &minus; tile-related utility routines</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>#include &lt;tiffio.h&gt;</b></p>
+<!-- INDENTATION -->
+<p><b>void TIFFDefaultTileSize(TIFF *</b><i>tif</i><b>,
+uint32 *</b><i>tw</i><b>, uint32 *</b><i>th</i><b>)<br>
+tsize_t TIFFTileSize(TIFF *</b><i>tif</i><b>)<br>
+tsize_t TIFFTileRowSize(TIFF *</b><i>tif</i><b>)<br>
+tsize_t TIFFVTileSize(TIFF *</b><i>tif</i><b>, uint32</b>
+<i>nrows</i><b>)<br>
+ttile_t TIFFComputeTile(TIFF *</b><i>tif</i><b>, uint32</b>
+<i>x</i><b>, uint32</b> <i>y</i><b>, uint32</b> <i>z</i><b>,
+tsample_t</b> <i>sample</i><b>)<br>
+int TIFFCheckTile(TIFF *</b><i>tif</i><b>, uint32</b>
+<i>x</i><b>, uint32</b> <i>y</i><b>, uint32</b> <i>z</i><b>,
+tsample_t</b> <i>sample</i><b>)<br>
+ttile_t TIFFNumberOfTiles(TIFF *</b><i>tif</i><b>)</b></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>TIFFDefaultTileSize</i> returns the pixel width and
+height of a reasonable-sized tile; suitable for setting up
+the <i>TileWidth</i> and <i>TileLength</i> tags. If the
+<i>tw</i> and <i>th</i> values passed in are non-zero, then
+they are adjusted to reflect any compression-specific
+requirements. The returned width and height are constrained
+to be a multiple of 16 pixels to conform with the
+<small>TIFF</small> specification.</p>
+<!-- INDENTATION -->
+<p><i>TIFFTileSize</i> returns the equivalent size for a
+tile of data as it would be returned in a call to
+<i>TIFFReadTile</i> or as it would be expected in a call to
+<i>TIFFWriteTile</i>.</p>
+<!-- INDENTATION -->
+<p><i>TIFFVTileSize</i> returns the number of bytes in a
+row-aligned tile with <i>nrows</i> of data.</p>
+<!-- INDENTATION -->
+<p><i>TIFFTileRowSize</i> returns the number of bytes of a
+row of data in a tile.</p>
+<!-- INDENTATION -->
+<p><i>TIFFComputeTile</i> returns the tile that contains the
+specified coordinates. A valid tile is always returned;
+out-of-range coordinate values are clamped to the bounds of
+the image. The <i>x</i> and <i>y</i> parameters are always
+used in calculating a tile. The <i>z</i> parameter is used
+if the image is deeper than 1 slice
+(<i>ImageDepth</i>&gt;1). The <i>sample</i> parameter is
+used only if data are organized in separate planes
+(<i>PlanarConfiguration</i>=2).</p>
+<!-- INDENTATION -->
+<p><i>TIFFCheckTile</i> returns a non-zero value if the
+supplied coordinates are within the bounds of the image and
+zero otherwise. The <i>x</i> parameter is checked against
+the value of the <i>ImageWidth</i> tag. The <i>y</i>
+parameter is checked against the value of the
+<i>ImageLength</i> tag. The <i>z</i> parameter is checked
+against the value of the <i>ImageDepth</i> tag (if defined).
+The <i>sample</i> parameter is checked against the value of
+the <i>SamplesPerPixel</i> parameter if the data are
+organized in separate planes.</p>
+<!-- INDENTATION -->
+<p><i>TIFFNumberOfTiles</i> returns the number of tiles in
+the image.</p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>TIFFReadEncodedTile</b>(3TIFF),
+<b>TIFFReadRawTile</b>(3TIFF), <b>TIFFReadTile</b>(3TIFF),
+<b>TIFFWriteEncodedTile</b>(3TIFF),
+<b>TIFFWriteRawTile</b>(3TIFF), <b>TIFFWriteTile</b>(3TIFF),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/fax2ps.1.html b/tiff/html/man/fax2ps.1.html
new file mode 100644
index 0000000..c539614
--- /dev/null
+++ b/tiff/html/man/fax2ps.1.html
@@ -0,0 +1,252 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>FAX2PS</title>
+</head>
+<body>
+
+<h1 align=center>FAX2PS</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>fax2ps &minus; convert a <small>TIFF</small> facsimile to
+compressed PostScript&trade;</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>fax2ps</b> [ <i>options</i> ] [ <i>file ...</i> ]</p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>fax2ps</i> reads one or more <small>TIFF</small>
+facsimile image files and prints a compressed form of
+PostScript on the standard output that is suitable for
+printing.</p>
+<!-- INDENTATION -->
+<p>By default, each page is scaled to reflect the image
+dimensions and resolutions stored in the file. The
+<b>&minus;x</b> and <b>&minus;y</b> options can be used to
+specify the horizontal and vertical image resolutions
+(lines/inch), respectively. If the <b>&minus;S</b> option is
+specified, each page is scaled to fill an output page. The
+default output page is 8.5 by 11 inches. Alternate page
+dimensions can be specified in inches with the
+<b>&minus;W</b> and <b>&minus;H</b> options.</p>
+<!-- INDENTATION -->
+<p>By default <i>fax2ps</i> generates PostScript for all
+pages in the file. The <b>&minus;p</b> option can be used to
+select one or more pages from a multi-page document.</p>
+<!-- INDENTATION -->
+<p><i>fax2ps</i> generates a compressed form of PostScript
+that is optimized for sending pages of text to a PostScript
+printer attached to a host through a low-speed link (such as
+a serial line). Each output page is filled with white and
+then only the black areas are drawn. The PostScript
+specification of the black drawing operations is optimized
+by using a special font that encodes the move-draw
+operations required to fill the black regions on the page.
+This compression scheme typically results in a substantially
+reduced PostScript description, relative to the
+straightforward imaging of the page with a PostScript
+<i>image</i> operator. This algorithm can, however, be
+ineffective for continuous-tone and white-on-black images.
+For these images, it sometimes is more efficient to send the
+raster bitmap image directly; see <b>tiff2ps</b>(1).</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="4" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="11%">
+
+<p><b>&minus;p</b> <i>number</i></p>
+</td>
+<td width="76%">
+
+<p>Print only the indicated page. Multiple pages may be
+printed by specifying this option more than once.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;x</b> <i>resolution</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="23%"></td>
+<td width="76%">
+<p>Use <i>resolution</i> as the horizontal resolution, in
+dots/inch, of the image data. By default this value is taken
+from the file.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;y</b> <i>resolution</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="23%"></td>
+<td width="76%">
+<p>Use <i>resolution</i> as the vertical resolution, in
+lines/inch, of the image data. By default this value is
+taken from the file.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="4" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="12%">
+
+<p><b>&minus;S</b></p>
+</td>
+<td width="76%">
+
+<p>Scale each page of image data to fill the output page
+dimensions. By default images are presented according to the
+dimension information recorded in the <small>TIFF</small>
+file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="12%">
+
+<p><b>&minus;W</b> <i>width</i></p>
+</td>
+<td width="76%">
+
+<p>Use <i>width</i> as the width, in inches, of the output
+page.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="12%">
+
+<p><b>&minus;H</b> <i>height</i></p>
+</td>
+<td width="76%">
+
+<p>Use <i>height</i> as the height, in inches, of the
+output page.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Some messages about malformed <small>TIFF</small> images
+come from the <small>TIFF</small> library.</p>
+<!-- INDENTATION -->
+<p>Various messages about badly formatted facsimile images
+may be generated due to transmission errors in received
+facsimile. <i>fax2ps</i> attempts to recover from such data
+errors by resynchronizing decoding at the end of the current
+scanline. This can result in long horizontal black lines in
+the resultant PostScript image.</p>
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>If the destination printer supports PostScript Level II
+then it is always faster to just send the encoded bitmap
+generated by the <b>tiff2ps</b>(1) program.</p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>fax2ps</i> should probably figure out when it is doing
+a poor job of compressing the output and just generate
+PostScript to image the bitmap raster instead.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiff2ps</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/fax2tiff.1.html b/tiff/html/man/fax2tiff.1.html
new file mode 100644
index 0000000..38b54c0
--- /dev/null
+++ b/tiff/html/man/fax2tiff.1.html
@@ -0,0 +1,607 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>FAX2TIFF</title>
+</head>
+<body>
+
+<h1 align=center>FAX2TIFF</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>fax2tiff &minus; create a <small>TIFF</small> Class F fax
+file from raw fax data</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>fax2tiff</b> [ <i>options</i> ] [ <b>&minus;o</b>
+<i>output.tif</i> ] <i>input.raw</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>Fax2tiff</i> creates a <small>TIFF</small> file
+containing <small>CCITT</small> Group 3 or Group 4 encoded
+data from one or more files containing
+&lsquo;&lsquo;raw&rsquo;&rsquo; Group 3 or Group 4 encoded
+data (typically obtained directly from a fax modem). By
+default, each row of data in the resultant
+<small>TIFF</small> file is 1-dimensionally encoded and
+padded or truncated to 1728 pixels, as needed. The resultant
+image is a set of low resolution (98 lines/inch) or medium
+resolution (196 lines/inch) pages, each of which is a single
+strip of data. The generated file conforms to the
+<small>TIFF</small> Class F ( <small>FAX</small> )
+specification for storing facsimile data. This means, in
+particular, that each page of the data does <b>not</b>
+include the trailing <i>return to control</i> (
+<small>RTC</small> ) code; as required for transmission by
+the <small>CCITT</small> Group 3 specifications. The old,
+&lsquo;&lsquo;classic&rsquo;&rsquo;, format is created if
+the <b>&minus;c</b> option is used. (The Class F format can
+also be requested with the <b>&minus;f</b> option.)</p>
+<!-- INDENTATION -->
+<p>The default name of the output image is <i>fax.tif</i>;
+this can be changed with the <b>&minus;o</b> option. Each
+input file is assumed to be a separate page of facsimile
+data from the same document. The order in which input files
+are specified on the command line is the order in which the
+resultant pages appear in the output file.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Options that affect the interpretation of input data
+are:</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;3</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data is <small>CCITT</small> Group 3
+encoded (default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;4</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data is <small>CCITT</small> Group 4
+encoded.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;U</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data is uncompressed (Group 3 or Group
+4).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;1</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data is encoded with the 1-dimensional
+version of the <small>CCITT</small> Group 3 Huffman encoding
+algorithm (default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;2</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data is 2-dimensional version of the
+<small>CCITT</small> Group 3 Huffman encoding algorithm.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;P</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data is <b>not</b> EOL-aligned (default).
+This option has effect with Group 3 encoded input only.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;A</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data is EOL-aligned. This option has effect
+with Group 3 encoded input only.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;M</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Treat input data as having bits filled from most
+significant bit ( <small>MSB</small> ) to most least bit (
+<small>LSB</small> ).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;L</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Treat input data as having bits filled from least
+significant bit ( <small>LSB</small> ) to most significant
+bit ( <small>MSB</small> ) (default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;B</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data was encoded with black as 0 and white
+as 1.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;W</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Assume input data was encoded with black as 1 and white
+as 0 (default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;R</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the vertical resolution, in lines/inch, of the
+input images. By default input are assumed to have a
+vertical resolution of 196 lines/inch. If images are low
+resolution facsimile, a value of 98 lines/inch should be
+specified.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;X</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the width, in pixels, of the input images. By
+default input are assumed to have a width of 1728
+pixels.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Options that affect the output file format are:</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;o</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the name of the output file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;7</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be compressed with the
+<small>CCITT</small> Group 3 Huffman encoding algorithm
+(default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;8</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be compressed with the
+<small>CCITT</small> Group 4 Huffman encoding.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;u</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be uncompressed (Group 3 or Group
+4).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;5</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be encoded with the 1-dimensional
+version of the <small>CCITT</small> Group 3 Huffman encoding
+algorithm.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;6</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be encoded with the 2-dimensional
+version of the <small>CCITT</small> Group 3 Huffman encoding
+algorithm (default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;a</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the last bit of each <i>End Of Line</i> (
+<small>EOL</small> ) code to land on a byte boundary
+(default). This &lsquo;&lsquo;zero padding&rsquo;&rsquo;
+will be reflected in the contents of the
+<i>Group3Options</i> tag of the resultant
+<small>TIFF</small> file. This option has effect with Group
+3 encoded output only.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;p</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Do not EOL-align output. This option has effect with
+Group 3 encoded output only.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Generate &quot;classic&quot; Group 3 TIFF format.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;f</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Generate TIFF Class F (TIFF/F) format (default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;m</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output data to have bits filled from most
+significant bit ( <small>MSB</small> ) to most least bit (
+<small>LSB</small> ).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;l</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output data to have bits filled from least
+significant bit ( <small>LSB</small> ) to most significant
+bit ( <small>MSB</small> ) (default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the number of rows (scanlines) in each strip of
+data written to the output file. By default (or when value
+<b>0</b> is specified), <i>tiffcp</i> attempts to set the
+rows/strip that no more than 8 kilobytes of data appear in a
+strip (with except of G3/G4 compression schemes). If you
+specify special value <b>&minus;1</b> it will results in
+infinite number of the rows per strip. The entire image will
+be the one strip in that case. This is default in case of
+G3/G4 output compression schemes.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;s</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Stretch the input image vertically by writing each input
+row of data twice to the output file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;v</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force <i>fax2tiff</i> to print the number of rows of
+data it retrieved from the input file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;z</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be compressed with the LZW encoding.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following warnings and errors come from the decoding
+routines in the library.</p>
+<!-- INDENTATION -->
+<p><b>Warning, %s: Premature EOL at scanline %d (x
+%d).\n</b>. The input data had a row that was shorter than
+the expected width. The row is padded with white.</p>
+<!-- INDENTATION -->
+<p><b>%s: Premature EOF at scanline %d (x %d).\n</b>. The
+decoder ran out of data in the middle of a scanline. The
+resultant row is padded with white.</p>
+<!-- INDENTATION -->
+<p><b>%s: Bad code word at row %d, x %d\n</b>. An invalid
+Group 3 <i>code</i> was encountered while decoding the input
+file. The row number and horizontal position is given. The
+remainder of the input row is discarded, while the
+corresponding output row is padded with white.</p>
+<!-- INDENTATION -->
+<p><b>%s: Bad 2D code word at scanline %d.\n</b>. An invalid
+Group 4 or 2D Group 3 <i>code</i> was encountered while
+decoding the input file. The row number and horizontal
+position is given. The remainder of the input row is
+discarded, while the corresponding output row is padded with
+white.</p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Input data are assumed to have a a &lsquo;&lsquo;top
+left&rsquo;&rsquo; orientation; it should be possible to
+override this assumption from the command line.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b><small>CCITT</small> Recommendation T.4</b>
+(Standardization of Group 3 Facsimile Apparatus for Document
+Transmission).</p>
+<!-- INDENTATION -->
+<p><b>The Spirit of TIFF Class F</b>, an appendix to the
+TIFF 5.0 specification prepared by Cygnet Technologies.</p>
+<!-- INDENTATION -->
+<p><b>tiffinfo</b>(1), <b>tiffdither</b>(1),
+<b>tiffgt</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/gif2tiff.1.html b/tiff/html/man/gif2tiff.1.html
new file mode 100644
index 0000000..6114bd3
--- /dev/null
+++ b/tiff/html/man/gif2tiff.1.html
@@ -0,0 +1,141 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>GIF2TIFF</title>
+</head>
+<body>
+
+<h1 align=center>GIF2TIFF</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>gif2tiff &minus; create a <small>TIFF</small> file from a
+GIF87 format image file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>gif2tiff</b> [ <i>options</i> ] <i>input.gif
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>Gif2tiff</i> converts a file in the GIF87 format to
+<small>TIFF.</small> The <small>TIFF</small> image is
+created as a palette image, with samples compressed with the
+Lempel-Ziv &amp; Welch algorithm (<i>Compression</i>=5).
+These characteristics can overridden, or explicitly
+specified with the options described below.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify a compression scheme to use when writing image
+data: <b>&minus;c none</b> for no compression, <b>&minus;c
+packbits</b> for the PackBits compression algorithm,
+<b>&minus;c zip</b> for the Deflate compression algorithm,
+and <b>&minus;c lzw</b> for Lempel-Ziv &amp; Welch (the
+default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Write data with a specified number of rows per strip; by
+default the number of rows/strip is selected so that each
+strip is approximately 8 kilobytes.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The program is based on Paul Haeberli&rsquo;s
+<i>fromgif</i> program which, in turn, is based on Marcel
+J.E. Mol&rsquo;s GIF reader.</p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Should have more options to control output format.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/index.html b/tiff/html/man/index.html
new file mode 100644
index 0000000..7e9e8d2
--- /dev/null
+++ b/tiff/html/man/index.html
@@ -0,0 +1,64 @@
+<HTML><HEAD><TITLE>Libtiff HTML manpage index</TITLE></HEAD><BODY BGCOLOR=white><ul><H2>Man Pages</h2><p>
+<li><A HREF=TIFFbuffer.3tiff.html>TIFFbuffer.3tiff.html</a>
+<li><A HREF=TIFFClose.3tiff.html>TIFFClose.3tiff.html</a>
+<li><A HREF=TIFFcodec.3tiff.html>TIFFcodec.3tiff.html</a>
+<li><A HREF=TIFFcolor.3tiff.html>TIFFcolor.3tiff.html</a>
+<li><A HREF=TIFFDataWidth.3tiff.html>TIFFDataWidth.3tiff.html</a>
+<li><A HREF=TIFFError.3tiff.html>TIFFError.3tiff.html</a>
+<li><A HREF=TIFFFlush.3tiff.html>TIFFFlush.3tiff.html</a>
+<li><A HREF=TIFFGetField.3tiff.html>TIFFGetField.3tiff.html</a>
+<li><A HREF=TIFFmemory.3tiff.html>TIFFmemory.3tiff.html</a>
+<li><A HREF=TIFFOpen.3tiff.html>TIFFOpen.3tiff.html</a>
+<li><A HREF=TIFFPrintDirectory.3tiff.html>TIFFPrintDirectory.3tiff.html</a>
+<li><A HREF=TIFFquery.3tiff.html>TIFFquery.3tiff.html</a>
+<li><A HREF=TIFFReadDirectory.3tiff.html>TIFFReadDirectory.3tiff.html</a>
+<li><A HREF=TIFFReadEncodedStrip.3tiff.html>TIFFReadEncodedStrip.3tiff.html</a>
+<li><A HREF=TIFFReadEncodedTile.3tiff.html>TIFFReadEncodedTile.3tiff.html</a>
+<li><A HREF=TIFFReadRawStrip.3tiff.html>TIFFReadRawStrip.3tiff.html</a>
+<li><A HREF=TIFFReadRawTile.3tiff.html>TIFFReadRawTile.3tiff.html</a>
+<li><A HREF=TIFFReadRGBAImage.3tiff.html>TIFFReadRGBAImage.3tiff.html</a>
+<li><A HREF=TIFFReadRGBAStrip.3tiff.html>TIFFReadRGBAStrip.3tiff.html</a>
+<li><A HREF=TIFFReadRGBATile.3tiff.html>TIFFReadRGBATile.3tiff.html</a>
+<li><A HREF=TIFFReadScanline.3tiff.html>TIFFReadScanline.3tiff.html</a>
+<li><A HREF=TIFFReadTile.3tiff.html>TIFFReadTile.3tiff.html</a>
+<li><A HREF=TIFFRGBAImage.3tiff.html>TIFFRGBAImage.3tiff.html</a>
+<li><A HREF=TIFFSetDirectory.3tiff.html>TIFFSetDirectory.3tiff.html</a>
+<li><A HREF=TIFFSetField.3tiff.html>TIFFSetField.3tiff.html</a>
+<li><A HREF=TIFFsize.3tiff.html>TIFFsize.3tiff.html</a>
+<li><A HREF=TIFFstrip.3tiff.html>TIFFstrip.3tiff.html</a>
+<li><A HREF=TIFFswab.3tiff.html>TIFFswab.3tiff.html</a>
+<li><A HREF=TIFFtile.3tiff.html>TIFFtile.3tiff.html</a>
+<li><A HREF=TIFFWarning.3tiff.html>TIFFWarning.3tiff.html</a>
+<li><A HREF=TIFFWriteDirectory.3tiff.html>TIFFWriteDirectory.3tiff.html</a>
+<li><A HREF=TIFFWriteEncodedStrip.3tiff.html>TIFFWriteEncodedStrip.3tiff.html</a>
+<li><A HREF=TIFFWriteEncodedTile.3tiff.html>TIFFWriteEncodedTile.3tiff.html</a>
+<li><A HREF=TIFFWriteRawStrip.3tiff.html>TIFFWriteRawStrip.3tiff.html</a>
+<li><A HREF=TIFFWriteRawTile.3tiff.html>TIFFWriteRawTile.3tiff.html</a>
+<li><A HREF=TIFFWriteScanline.3tiff.html>TIFFWriteScanline.3tiff.html</a>
+<li><A HREF=TIFFWriteTile.3tiff.html>TIFFWriteTile.3tiff.html</a>
+<li><A HREF=fax2ps.1.html>fax2ps.1.html</a>
+<li><A HREF=fax2tiff.1.html>fax2tiff.1.html</a>
+<li><A HREF=gif2tiff.1.html>gif2tiff.1.html</a>
+<li><A HREF=pal2rgb.1.html>pal2rgb.1.html</a>
+<li><A HREF=ppm2tiff.1.html>ppm2tiff.1.html</a>
+<li><A HREF=ras2tiff.1.html>ras2tiff.1.html</a>
+<li><A HREF=raw2tiff.1.html>raw2tiff.1.html</a>
+<li><A HREF=rgb2ycbcr.1.html>rgb2ycbcr.1.html</a>
+<li><A HREF=sgi2tiff.1.html>sgi2tiff.1.html</a>
+<li><A HREF=thumbnail.1.html>thumbnail.1.html</a>
+<li><A HREF=tiff2bw.1.html>tiff2bw.1.html</a>
+<li><A HREF=tiff2pdf.1.html>tiff2pdf.1.html</a>
+<li><A HREF=tiff2ps.1.html>tiff2ps.1.html</a>
+<li><A HREF=tiff2rgba.1.html>tiff2rgba.1.html</a>
+<li><A HREF=tiffcmp.1.html>tiffcmp.1.html</a>
+<li><A HREF=tiffcp.1.html>tiffcp.1.html</a>
+<li><A HREF=tiffcrop.1.html>tiffcrop.1.html</a>
+<li><A HREF=tiffdither.1.html>tiffdither.1.html</a>
+<li><A HREF=tiffdump.1.html>tiffdump.1.html</a>
+<li><A HREF=tiffgt.1.html>tiffgt.1.html</a>
+<li><A HREF=tiffinfo.1.html>tiffinfo.1.html</a>
+<li><A HREF=tiffmedian.1.html>tiffmedian.1.html</a>
+<li><A HREF=tiffset.1.html>tiffset.1.html</a>
+<li><A HREF=tiffsplit.1.html>tiffsplit.1.html</a>
+<li><A HREF=tiffsv.1.html>tiffsv.1.html</a>
+</ul></BODY></HTML>
diff --git a/tiff/html/man/libtiff.3tiff.html b/tiff/html/man/libtiff.3tiff.html
new file mode 100644
index 0000000..bea73f7
--- /dev/null
+++ b/tiff/html/man/libtiff.3tiff.html
@@ -0,0 +1,3137 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:14 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>INTRO</title>
+</head>
+<body>
+
+<h1 align=center>INTRO</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#DATA TYPES">DATA TYPES</a><br>
+<a href="#LIST OF ROUTINES">LIST OF ROUTINES</a><br>
+<a href="#TAG USAGE">TAG USAGE</a><br>
+<a href="#PSEUDO TAGS">PSEUDO TAGS</a><br>
+<a href="#DIAGNOSTICS">DIAGNOSTICS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+<a href="#BUGS">BUGS</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>libtiff &minus; introduction to <i>libtiff</i>, a
+library for reading and writing</big> TIFF
+<big>files</big></p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>#include &lt;tiffio.h&gt;</b></big></p>
+<!-- INDENTATION -->
+<p><big>cc file.c <b>-ltiff</b></big></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><i>libtiff</i> is a library for reading and writing
+data files encoded with the <i>Tag Image File</i> format,
+Revision 6.0 (or revision 5.0 or revision 4.0). This file
+format is suitable for archiving multi-color and
+monochromatic image data.</big></p>
+<!-- INDENTATION -->
+<p><big>The library supports several compression algorithms,
+as indicated by the <i>Compression</i> field, including: no
+compression (1),</big> CCITT <big>1D Huffman compression
+(2),</big> CCITT <big>Group 3 Facsimile compression
+(3),</big> CCITT <big>Group 4 Facsimile compression (4),
+Lempel-Ziv &amp; Welch compression (5), baseline JPEG
+compression (7), word-aligned 1D Huffman compression
+(32771), and PackBits compression (32773). In addition,
+several nonstandard compression algorithms are supported:
+the 4-bit compression algorithm used by the
+<i>ThunderScan</i> program (32809) (decompression only),
+NeXT&rsquo;s 2-bit compression algorithm (32766)
+(decompression only), an experimental LZ-style algorithm
+known as Deflate (32946), and an experimental CIE LogLuv
+compression scheme designed for images with high dynamic
+range (32845 for LogL and 32845 for LogLuv). Directory
+information may be in either little- or big-endian byte
+order&minus;byte swapping is automatically done by the
+library. Data bit ordering may be either Most Significant
+Bit (</big> MSB <big>) to Least Significant Bit (</big> LSB
+<big>) or</big> LSB <big>to</big> MSB. <big>Finally, the
+library does not support files in which the
+<i>BitsPerSample</i>, <i>Compression</i>,
+<i>MinSampleValue</i>, or <i>MaxSampleValue</i> fields are
+defined differently on a per-sample basis (in Rev. 6.0 the
+<i>Compression</i> tag is not defined on a per-sample basis,
+so this is immaterial).</big></p>
+</td>
+</table>
+<a name="DATA TYPES"></a>
+<h2>DATA TYPES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>The library makes extensive use of C typedefs to
+promote portability. Two sets of typedefs are used, one for
+communication with clients of the library and one for
+internal data structures and parsing of the</big> TIFF
+<big>format. The following typedefs are exposed to users
+either through function definitions or through parameters
+passed through the varargs interfaces.</big></p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="3" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef unsigned short uint16;</big></p>
+</td>
+<td width="38%">
+
+<p><big>16-bit unsigned integer</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef unsigned &lt;<i>thing</i>&gt;
+uint32;</big></p>
+</td>
+<td width="38%">
+
+<p><big>32-bit unsigned integer</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef unsigned int ttag_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>directory tag</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef uint16 tdir_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>directory index</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef uint16 tsample_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>sample number</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef uint32 tstrip_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>strip number</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef uint32 ttile_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>tile number</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef int32 tsize_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>i/o size in bytes</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef void* tdata_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>image data ref</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef void* thandle_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>client data handle</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="46%">
+
+<p><big>typedef int32 toff_t;</big></p>
+</td>
+<td width="38%">
+
+<p><big>file offset</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>Note that <i>tstrip_t</i>, <i>ttile_t</i>, and
+<i>tsize_t</i> are constrained to be no more than 32-bit
+quantities by 32-bit fields they are stored in in the</big>
+TIFF <big>image. Likewise <i>tsample_t</i> is limited by the
+16-bit field used to store the <i>SamplesPerPixel</i> tag.
+<i>tdir_t</i> constrains the maximum number of</big> IFDs
+<big>that may appear in an image and may be an arbitrary
+size (w/o penalty). <i>ttag_t</i> must be either int,
+unsigned int, pointer, or double because the library uses a
+varargs interface and</big> ANSI C <big>restricts the type
+of the parameter before an ellipsis to be a promoted type.
+<i>toff_t</i> is defined as int32 because TIFF file offsets
+are (unsigned) 32-bit quantities. A signed value is used
+because some interfaces return &minus;1 on error. Finally,
+note that user-specified data references are passed as
+opaque handles and only cast at the lowest layers where
+their type is presumed.</big></p>
+</td>
+</table>
+<a name="LIST OF ROUTINES"></a>
+<h2>LIST OF ROUTINES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>The following routines are part of the library.
+Consult specific manual pages for details on their
+operation; on most systems doing &lsquo;&lsquo;man
+function-name&rsquo;&rsquo; will work.</big></p></td>
+</table>
+<!-- TABS -->
+
+<p><big><i>Name Description</i></big></p>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="3" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFCheckpointDirectory</big></p>
+</td>
+<td width="67%">
+
+<p><big>writes the current state of the directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFCheckTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>very x,y,z,sample is within image</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFCIELabToRGBInit</big></p>
+</td>
+<td width="67%">
+
+<p><big>initialize CIE L*a*b* 1976 to RGB conversion
+state</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFCIELabToXYZ</big></p>
+</td>
+<td width="67%">
+
+<p><big>perform CIE L*a*b* 1976 to CIE XYZ
+conversion</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFClientOpen</big></p>
+</td>
+<td width="67%">
+
+<p><big>open a file for reading or writing</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFClose</big></p>
+</td>
+<td width="67%">
+
+<p><big>close an open file</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFComputeStrip</big></p>
+</td>
+<td width="67%">
+
+<p><big>return strip containing y,sample</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFComputeTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>return tile containing x,y,z,sample</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFCurrentDirectory</big></p>
+</td>
+<td width="67%">
+
+<p><big>return index of current directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFCurrentRow</big></p>
+</td>
+<td width="67%">
+
+<p><big>return index of current scanline</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFCurrentStrip</big></p>
+</td>
+<td width="67%">
+
+<p><big>return index of current strip</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFCurrentTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>return index of current tile</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFDataWidth</big></p>
+</td>
+<td width="67%">
+
+<p><big>return the size of TIFF data types</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFError</big></p>
+</td>
+<td width="67%">
+
+<p><big>library error handler</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFFdOpen</big></p>
+</td>
+<td width="67%">
+
+<p><big>open a file for reading or writing</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFFileName</big></p>
+</td>
+<td width="67%">
+
+<p><big>return name of open file</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFFileno</big></p>
+</td>
+<td width="67%">
+
+<p><big>return open file descriptor</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFFindCODEC</big></p>
+</td>
+<td width="67%">
+
+<p><big>find standard codec for the specific
+scheme</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFFlush</big></p>
+</td>
+<td width="67%">
+
+<p><big>flush all pending writes</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFFlushData</big></p>
+</td>
+<td width="67%">
+
+<p><big>flush pending data writes</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFGetBitRevTable</big></p>
+</td>
+<td width="67%">
+
+<p><big>return bit reversal table</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFGetField</big></p>
+</td>
+<td width="67%">
+
+<p><big>return tag value in current directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFGetFieldDefaulted</big></p>
+</td>
+<td width="67%">
+
+<p><big>return tag value in current directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFGetMode</big></p>
+</td>
+<td width="67%">
+
+<p><big>return open file mode</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFGetVersion</big></p>
+</td>
+<td width="67%">
+
+<p><big>return library version string</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFIsCODECConfigured</big></p>
+</td>
+<td width="67%">
+
+<p><big>check, whether we have working codec</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFIsMSB2LSB</big></p>
+</td>
+<td width="67%">
+
+<p><big>return true if image data is being
+returned</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%"></td>
+<td width="67%">
+
+<p><big>with bit 0 as the most significant bit</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFIsTiled</big></p>
+</td>
+<td width="67%">
+
+<p><big>return true if image data is tiled</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFIsByteSwapped</big></p>
+</td>
+<td width="67%">
+
+<p><big>return true if image data is byte-swapped</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFNumberOfStrips</big></p>
+</td>
+<td width="67%">
+
+<p><big>return number of strips in an image</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFNumberOfTiles</big></p>
+</td>
+<td width="67%">
+
+<p><big>return number of tiles in an image</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFOpen</big></p>
+</td>
+<td width="67%">
+
+<p><big>open a file for reading or writing</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFPrintDirectory</big></p>
+</td>
+<td width="67%">
+
+<p><big>print description of the current
+directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadBufferSetup</big></p>
+</td>
+<td width="67%">
+
+<p><big>specify i/o buffer for reading</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadDirectory</big></p>
+</td>
+<td width="67%">
+
+<p><big>read the next directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadEncodedStrip</big></p>
+</td>
+<td width="67%">
+
+<p><big>read and decode a strip of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadEncodedTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>read and decode a tile of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadRawStrip</big></p>
+</td>
+<td width="67%">
+
+<p><big>read a raw strip of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadRawTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>read a raw tile of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadRGBAImage</big></p>
+</td>
+<td width="67%">
+
+<p><big>read an image into a fixed format raster</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadScanline</big></p>
+</td>
+<td width="67%">
+
+<p><big>read and decode a row of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReadTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>read and decode a tile of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFRegisterCODEC</big></p>
+</td>
+<td width="67%">
+
+<p><big>override standard codec for the specific
+scheme</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFReverseBits</big></p>
+</td>
+<td width="67%">
+
+<p><big>reverse bits in an array of bytes</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFRGBAImageBegin</big></p>
+</td>
+<td width="67%">
+
+<p><big>setup decoder state for TIFFRGBAImageGet</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFRGBAImageEnd</big></p>
+</td>
+<td width="67%">
+
+<p><big>release TIFFRGBAImage decoder state</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFRGBAImageGet</big></p>
+</td>
+<td width="67%">
+
+<p><big>read and decode an image</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFRGBAImageOK</big></p>
+</td>
+<td width="67%">
+
+<p><big>is image readable by TIFFRGBAImageGet</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFScanlineSize</big></p>
+</td>
+<td width="67%">
+
+<p><big>return size of a scanline</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSetDirectory</big></p>
+</td>
+<td width="67%">
+
+<p><big>set the current directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSetSubDirectory</big></p>
+</td>
+<td width="67%">
+
+<p><big>set the current directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSetErrorHandler</big></p>
+</td>
+<td width="67%">
+
+<p><big>set error handler function</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSetField</big></p>
+</td>
+<td width="67%">
+
+<p><big>set a tag&rsquo;s value in the current
+directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSetWarningHandler</big></p>
+</td>
+<td width="67%">
+
+<p><big>set warning handler function</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFStripSize</big></p>
+</td>
+<td width="67%">
+
+<p><big>returns size of a strip</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFRawStripSize</big></p>
+</td>
+<td width="67%">
+
+<p><big>returns the number of bytes in a raw
+strip</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSwabShort</big></p>
+</td>
+<td width="67%">
+
+<p><big>swap bytes of short</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSwabLong</big></p>
+</td>
+<td width="67%">
+
+<p><big>swap bytes of long</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSwabArrayOfShort</big></p>
+</td>
+<td width="67%">
+
+<p><big>swap bytes of an array of shorts</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFSwabArrayOfLong</big></p>
+</td>
+<td width="67%">
+
+<p><big>swap bytes of an array of longs</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFTileRowSize</big></p>
+</td>
+<td width="67%">
+
+<p><big>return size of a row in a tile</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFTileSize</big></p>
+</td>
+<td width="67%">
+
+<p><big>return size of a tile</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFUnRegisterCODEC</big></p>
+</td>
+<td width="67%">
+
+<p><big>unregisters the codec</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFVGetField</big></p>
+</td>
+<td width="67%">
+
+<p><big>return tag value in current directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFVGetFieldDefaulted</big></p>
+</td>
+<td width="67%">
+
+<p><big>return tag value in current directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFVSetField</big></p>
+</td>
+<td width="67%">
+
+<p><big>set a tag&rsquo;s value in the current
+directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFVStripSize</big></p>
+</td>
+<td width="67%">
+
+<p><big>returns the number of bytes in a strip</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFWarning</big></p>
+</td>
+<td width="67%">
+
+<p><big>library warning handler</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFWriteDirectory</big></p>
+</td>
+<td width="67%">
+
+<p><big>write the current directory</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFWriteEncodedStrip</big></p>
+</td>
+<td width="67%">
+
+<p><big>compress and write a strip of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFWriteEncodedTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>compress and write a tile of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFWriteRawStrip</big></p>
+</td>
+<td width="67%">
+
+<p><big>write a raw strip of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFWriteRawTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>write a raw tile of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFWriteScanline</big></p>
+</td>
+<td width="67%">
+
+<p><big>write a scanline of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFWriteTile</big></p>
+</td>
+<td width="67%">
+
+<p><big>compress and write a tile of data</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFXYZToRGB</big></p>
+</td>
+<td width="67%">
+
+<p><big>perform CIE XYZ to RGB conversion</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFYCbCrToRGBInit</big></p>
+</td>
+<td width="67%">
+
+<p><big>initialize YCbCr to RGB conversion state</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>TIFFYCbCrtoRGB</big></p>
+</td>
+<td width="67%">
+
+<p><big>perform YCbCr to RGB conversion</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>Auxiliary functions:</big></p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="3" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>_TIFFfree</big></p>
+</td>
+<td width="67%">
+
+<p><big>free memory buffer</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>_TIFFmalloc</big></p>
+</td>
+<td width="67%">
+
+<p><big>dynamically allocate memory buffer</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>_TIFFmemcmp</big></p>
+</td>
+<td width="67%">
+
+<p><big>compare contents of the memory buffers</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>_TIFFmemcpy</big></p>
+</td>
+<td width="67%">
+
+<p><big>copy contents of the one buffer to
+another</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>_TIFFmemset</big></p>
+</td>
+<td width="67%">
+
+<p><big>fill memory buffer with a constant byte</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="23%">
+
+<p><big>_TIFFrealloc</big></p>
+</td>
+<td width="67%">
+
+<p><big>dynamically reallocate memory buffer</big></p>
+</td>
+</table>
+<a name="TAG USAGE"></a>
+<h2>TAG USAGE</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>The table below lists the</big> TIFF <big>tags that
+are recognized and handled by the library. If no use is
+indicated in the table, then the library reads and writes
+the tag, but does not use it internally. Note that some tags
+are meaningful only when a particular compression scheme is
+being used; e.g. <i>Group3Options</i> is only useful if
+<i>Compression</i> is set to</big> CCITT <big>Group 3
+encoding. Tags of this sort are considered
+<i>codec-specific</i> tags and the library does not
+recognize them except when the <i>Compression</i> tag has
+been previously set to the relevant compression
+scheme.</big></p>
+<!-- INDENTATION -->
+<pre><big><i>Tag Name Value R/W Library Use/Notes
+</i></big></pre>
+</td>
+</table>
+<!-- TABS -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Artist</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>315</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>BadFaxLines</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>326</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>BitsPerSample</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>258</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>lots</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>CellLength</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>265</big></p>
+</td>
+<td width="53%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>parsed but ignored</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>CellWidth</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>264</big></p>
+</td>
+<td width="53%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>parsed but ignored</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>CleanFaxData</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>327</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ColorMap</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>320</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ColorResponseUnit</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>300</big></p>
+</td>
+<td width="53%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>parsed but ignored</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Compression</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>259</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>choosing codec</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ConsecutiveBadFaxLines</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>328</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>Copyright 33432 R/W</big></p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>DataType</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>32996</big></p>
+</td>
+<td width="53%">
+
+<p><big>R</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>obsoleted by SampleFormat tag</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>DateTime</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>306</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>DocumentName</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>269</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>DotRange</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>336</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ExtraSamples</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>338</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>lots</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>FaxRecvParams</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>34908</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>FaxSubAddress</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>34909</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>FaxRecvTime</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>34910</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>FillOrder</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>266</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>control bit order</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>FreeByteCounts</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>289</big></p>
+</td>
+<td width="53%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>parsed but ignored</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>FreeOffsets</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>288</big></p>
+</td>
+<td width="53%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>parsed but ignored</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>GrayResponseCurve</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>291</big></p>
+</td>
+<td width="53%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>parsed but ignored</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>GrayResponseUnit</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>290</big></p>
+</td>
+<td width="53%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>parsed but ignored</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Group3Options</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>292</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>used by Group 3 codec</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Group4Options</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>293</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>HostComputer</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>316</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ImageDepth</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>32997</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>tile/strip calculations</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ImageDescription</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>270</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ImageLength</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>257</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>lots</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ImageWidth</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>256</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>lots</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>InkNames</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>333</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>InkSet</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>332</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>JPEGTables</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>347</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>used by JPEG codec</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Make</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>271</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Matteing</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>32995</big></p>
+</td>
+<td width="53%">
+
+<p><big>R</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>obsoleted by ExtraSamples tag</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>MaxSampleValue</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>281</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>MinSampleValue</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>280</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Model</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>272</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>NewSubFileType</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>254</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>called SubFileType in spec</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>NumberOfInks</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>334</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Orientation</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>274</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>PageName</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>285</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>PageNumber</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>297</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>PhotometricInterpretation</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>262</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>R/Wused by Group 3 and JPEG codecs</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>PlanarConfiguration</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>284</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>data i/o</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Predictor</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>317</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>used by LZW and Deflate codecs</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>PrimaryChromacities</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>319</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ReferenceBlackWhite</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>532</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>ResolutionUnit</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>296</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>used by Group 3 codec</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>RowsPerStrip</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>278</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>data i/o</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>SampleFormat</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>339</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>SamplesPerPixel</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>277</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>lots</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>SMinSampleValue</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>340</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>SMaxSampleValue</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>341</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Software</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>305</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>StoNits</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>37439</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>StripByteCounts</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>279</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>data i/o</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>StripOffsets</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>273</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>data i/o</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>SubFileType</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>255</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>called OSubFileType in spec</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TargetPrinter</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>337</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>Thresholding</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>263</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TileByteCounts</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>324</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>data i/o</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TileDepth</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>32998</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>tile/strip calculations</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TileLength</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>323</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>data i/o</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TileOffsets</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>324</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>data i/o</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TileWidth</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>322</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>data i/o</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TransferFunction</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>301</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>WhitePoint</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>318</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>XPosition</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>286</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>XResolution</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>282</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>YCbCrCoefficients</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>529</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>used by TIFFRGBAImage support</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>YCbCrPositioning</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>531</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>tile/strip size calulcations</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>YCbCrSubsampling</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>530</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>YPosition</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>286</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>YResolution</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>283</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>used by Group 3 codec</big></p>
+</td>
+</table>
+<a name="PSEUDO TAGS"></a>
+<h2>PSEUDO TAGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>In addition to the normal</big> TIFF <big>tags the
+library supports a collection of tags whose values lie in a
+range outside the valid range of</big> TIFF <big>tags. These
+tags are termed <i>pseud-tags</i> and are used to control
+various codec-specific functions within the library. The
+table below summarizes the defined pseudo-tags.</big></p>
+<!-- INDENTATION -->
+<pre><big><i>Tag Name Codec R/W Library Use/Notes
+</i></big></pre>
+</td>
+</table>
+<!-- TABS -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_FAXMODE</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>G3</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>general codec operation</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_FAXFILLFUNC</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>G3/G4</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>bitmap fill function</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_JPEGQUALITY</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>JPEG</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>compression quality control</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_JPEGCOLORMODE</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>JPEG</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>control colorspace conversions</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_JPEGTABLESMODE</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>JPEG</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>control contents of <i>JPEGTables</i> tag</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_ZIPQUALITY</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>Deflate</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/Wcompression quality level</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_PIXARLOGDATAFMT</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>PixarLog</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/Wuser data format</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_PIXARLOGQUALITY</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>PixarLog</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/Wcompression quality level</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%">
+
+<p><big>TIFFTAG_SGILOGDATAFMT</big></p>
+</td>
+<td width="8%"></td>
+<td width="6%">
+
+<p><big>SGILog</big></p>
+</td>
+<td width="53%">
+
+<p><big>R/W</big></p>
+</td>
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="21%"></td>
+<td width="8%"></td>
+<td width="6%"></td>
+<td width="53%">
+
+<p><big>user data format</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_FAXMODE</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control the operation of the Group 3 codec. Possible
+values (independent bits that can be combined by
+or&rsquo;ing them together) are: FAXMODE_CLASSIC (enable
+old-style format in which the</big> RTC <big>is written at
+the end of the last strip), FAXMODE_NORTC (opposite of
+FAXMODE_CLASSIC; also called FAXMODE_CLASSF), FAXMODE_NOEOL
+(do not write</big> EOL <big>codes at the start of each row
+of data), FAXMODE_BYTEALIGN (align each encoded row to an
+8-bit boundary), FAXMODE_WORDALIGN (align each encoded row
+to an 16-bit boundary), The default value is dependent on
+the compression scheme; this pseudo-tag is used by the
+various G3 and G4 codecs to share code.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_FAXFILLFUNC</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control the function used to convert arrays of black
+and white runs to packed bit arrays. This hook can be used
+to image decoded scanlines in multi-bit depth rasters (e.g.
+for display in colormap mode) or for other purposes. The
+default value is a pointer to a builtin function that images
+packed bilevel data.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_IPTCNEWSPHOTO</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Tag contaings image metadata per the IPTC newsphoto
+spec: Headline, captioning, credit, etc... Used by most wire
+services.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_PHOTOSHOP</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Tag contains Photoshop captioning information and
+metadata. Photoshop uses in parallel and redundantly
+alongside IPTCNEWSPHOTO information.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_JPEGQUALITY</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control the compression quality level used in the
+baseline algorithm. Note that quality levels are in the
+range 0-100 with a default value of 75.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_JPEGCOLORMODE</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control whether or not conversion is done between
+RGB and YCbCr colorspaces. Possible values are:
+JPEGCOLORMODE_RAW (do not convert), and JPEGCOLORMODE_RGB
+(convert to/from RGB) The default value is
+JPEGCOLORMODE_RAW.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_JPEGTABLESMODE</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control the information written in the
+<i>JPEGTables</i> tag. Possible values (independent bits
+that can be combined by or&rsquo;ing them together) are:
+JPEGTABLESMODE_QUANT (include quantization tables), and
+JPEGTABLESMODE_HUFF (include Huffman encoding tables). The
+default value is
+JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_ZIPQUALITY</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control the compression technique used by the
+Deflate codec. Quality levels are in the range 1-9 with
+larger numbers yielding better compression at the cost of
+more computation. The default quality level is 6 which
+yields a good time-space tradeoff.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_PIXARLOGDATAFMT</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control the format of user data passed <i>in</i> to
+the PixarLog codec when encoding and passed <i>out</i> from
+when decoding. Possible values are: PIXARLOGDATAFMT_8BIT for
+8-bit unsigned pixels, PIXARLOGDATAFMT_8BITABGR for 8-bit
+unsigned ABGR-ordered pixels, PIXARLOGDATAFMT_11BITLOG for
+11-bit log-encoded raw data, PIXARLOGDATAFMT_12BITPICIO for
+12-bit PICIO-compatible data, PIXARLOGDATAFMT_16BIT for
+16-bit signed samples, and PIXARLOGDATAFMT_FLOAT for 32-bit
+IEEE floating point samples.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_PIXARLOGQUALITY</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control the compression technique used by the
+PixarLog codec. This value is treated identically to
+TIFFTAG_ZIPQUALITY; see the above description.</big></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>TIFFTAG_SGILOGDATAFMT</b></big></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p><big>Control the format of client data passed <i>in</i>
+to the SGILog codec when encoding and passed <i>out</i> from
+when decoding. Possible values are: SGILOGDATAFMT_FLTXYZ for
+converting between LogLuv and 32-bit IEEE floating valued
+XYZ pixels, SGILOGDATAFMT_16BITLUV for 16-bit encoded Luv
+pixels, SGILOGDATAFMT_32BITRAW and SGILOGDATAFMT_24BITRAW
+for no conversion of data, SGILOGDATAFMT_8BITRGB for
+returning 8-bit RGB data (valid only when decoding
+LogLuv-encoded data), SGILOGDATAFMT_FLTY for converting
+between LogL and 32-bit IEEE floating valued Y pixels,
+SGILOGDATAFMT_16BITL for 16-bit encoded L pixels, and
+SGILOGDATAFMT_8BITGRY for returning 8-bit greyscale data
+(valid only when decoding LogL-encoded data).</big></p>
+</td>
+</table>
+<a name="DIAGNOSTICS"></a>
+<h2>DIAGNOSTICS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>All error messages are directed through the
+<i>TIFFError</i> routine. By default messages are directed
+to <b>stderr</b> in the form: <i>module: message\n.</i>
+Warning messages are likewise directed through the
+<i>TIFFWarning</i> routine.</big></p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big><b>fax2tiff</b>(1), <b>gif2tiff</b>(1),
+<b>pal2rgb</b>(1), <b>ppm2tiff</b>(1), <b>rgb2ycbcr</b>(1),
+<b>ras2tiff</b>(1), <b>raw2tiff</b>(1), <b>sgi2tiff</b>(1),
+<b>tiff2bw</b>(1), <b>tiffdither</b>(1), <b>tiffdump</b>(1),
+<b>tiffcp</b>(1), <b>tiffcmp</b>(1), <b>tiffgt</b>(1),
+<b>tiffinfo</b>(1), <b>tiffmedian</b>(1),
+<b>tiffsplit</b>(1), <b>tiffsv</b>(1).</big></p>
+<!-- INDENTATION -->
+<p><big><b>Tag Image File Format Specification &mdash;
+Revision 6.0</b>, an Aldus Technical Memorandum.</big></p>
+<!-- INDENTATION -->
+<p><big><b>The Spirit of TIFF Class F</b>, an appendix to
+the TIFF 5.0 specification prepared by Cygnet
+Technologies.</big></p>
+<!-- INDENTATION -->
+<p><big>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></big></p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><big>The library does not support multi-sample images
+where some samples have different bits/sample.</big></p>
+<!-- INDENTATION -->
+<p><big>The library does not support random access to
+compressed data that is organized with more than one row per
+tile or strip.</big></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/pal2rgb.1.html b/tiff/html/man/pal2rgb.1.html
new file mode 100644
index 0000000..5c3a679
--- /dev/null
+++ b/tiff/html/man/pal2rgb.1.html
@@ -0,0 +1,189 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>PAL2RGB</title>
+</head>
+<body>
+
+<h1 align=center>PAL2RGB</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>pal2rgb &minus; convert a palette color
+<small>TIFF</small> image to a full color image</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b> [ <i>options</i> ] <i>input.tif
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>Pal2rgb</i> converts a palette color
+<small>TIFF</small> image to a full color image by applying
+the colormap of the palette image to each sample to generate
+a full color <small>RGB</small> image.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Options that affect the interpretation of input data
+are:</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;C</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>This option overrides the default behavior of
+<i>pal2rgb</i> in determining whether or not colormap
+entries contain 16-bit or 8-bit values. By default the
+colormap is inspected and if no colormap entry greater than
+255 is found, the colormap is assumed to have only 8-bit
+values; otherwise 16-bit values (as required by the
+<small>TIFF</small> specification) are assumed. The
+<b>&minus;C</b> option can be used to explicitly specify the
+number of bits for colormap entries: <b>&minus;C 8</b> for
+8-bit values, <b>&minus;C 16</b> for 16-bit values.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Options that affect the output file format are:</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="5%">
+
+<p><b>&minus;p</b></p>
+</td>
+<td width="3%"></td>
+<td width="80%">
+
+<p>Explicitly select the planar configuration used in
+organizing data samples in the output image: <b>&minus;p
+contig</b> for samples packed contiguously, and <b>&minus;p
+separate</b> for samples stored separately. By default
+samples are packed.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="5%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="3%"></td>
+<td width="80%">
+
+<p>Use the specific compression algorithm to encoded image
+data in the output file: <b>&minus;c packbits</b> for
+Macintosh Packbits, <b>&minus;c lzw</b> for Lempel-Ziv &amp;
+Welch, <b>&minus;c zip</b> for Deflate, <b>&minus;c none</b>
+for no compression. If no compression-related option is
+specified, the input file&rsquo;s compression algorithm is
+used.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="5%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="3%"></td>
+<td width="80%">
+
+<p>Explicitly specify the number of rows in each strip of
+the output file. If the <b>&minus;r</b> option is not
+specified, a number is selected such that each output strip
+has approximately 8 kilobytes of data in it.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Only 8-bit images are handled.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/ppm2tiff.1.html b/tiff/html/man/ppm2tiff.1.html
new file mode 100644
index 0000000..60e56e1
--- /dev/null
+++ b/tiff/html/man/ppm2tiff.1.html
@@ -0,0 +1,141 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>PPM2TIFF</title>
+</head>
+<body>
+
+<h1 align=center>PPM2TIFF</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>ppm2tiff &minus; create a <small>TIFF</small> file from
+<small>PPM, PGM</small> and <small>PBM</small> image
+files</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>ppm2tiff</b> [ <i>options</i> ] [ <i>input.ppm</i> ]
+<i>output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>ppm2tiff</i> converts a file in the <small>PPM,
+PGM</small> and <small>PBM</small> image formats to
+<small>TIFF.</small> By default, the <small>TIFF</small>
+image is created with data samples packed
+(<i>PlanarConfiguration</i>=1), compressed with the Packbits
+algorithm (<i>Compression</i>=32773), and with each strip no
+more than 8 kilobytes. These characteristics can be
+overridden, or explicitly specified with the options
+described below</p>
+<!-- INDENTATION -->
+<p>If the <small>PPM</small> file contains greyscale data,
+then the <i>PhotometricInterpretation</i> tag is set to 1
+(min-is-black), otherwise it is set to 2 (RGB).</p>
+<!-- INDENTATION -->
+<p>If no <small>PPM</small> file is specified on the command
+line, <i>ppm2tiff</i> will read from the standard input.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify a compression scheme to use when writing image
+data: <b>none</b> for no compression, <b>packbits</b> for
+PackBits compression (will be used by default), <b>lzw</b>
+for Lempel-Ziv &amp; Welch compression, <b>jpeg</b> for
+baseline JPEG compression, <b>zip</b> for Deflate
+compression, <b>g3</b> for CCITT Group 3 (T.4) compression,
+and <b>g4</b> for CCITT Group 4 (T.6) compression.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Write data with a specified number of rows per strip; by
+default the number of rows/strip is selected so that each
+strip is approximately 8 kilobytes.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;R</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Mark the resultant image to have the specified X and Y
+resolution (in dots/inch).</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/ras2tiff.1.html b/tiff/html/man/ras2tiff.1.html
new file mode 100644
index 0000000..b0b8993
--- /dev/null
+++ b/tiff/html/man/ras2tiff.1.html
@@ -0,0 +1,139 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>RAS2TIFF</title>
+</head>
+<body>
+
+<h1 align=center>RAS2TIFF</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>ras2tiff &minus; create a <small>TIFF</small> file from a
+Sun rasterfile</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>ras2tiff</b> [ <i>options</i> ] <i>input.ras
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>ras2tiff</i> converts a file in the Sun rasterfile
+format to <small>TIFF.</small> By default, the
+<small>TIFF</small> image is created with data samples
+packed (<i>PlanarConfiguration</i>=1), compressed with the
+Lempel-Ziv &amp; Welch algorithm (<i>Compression</i>=5), and
+with each strip no more than 8 kilobytes. These
+characteristics can overridden, or explicitly specified with
+the options described below.</p>
+<!-- INDENTATION -->
+<p>Any colormap information in the rasterfile is carried
+over to the <small>TIFF</small> file by including a
+<i>Colormap</i> tag in the output file. If the rasterfile
+has a colormap, the <i>PhotometricInterpretation</i> tag is
+set to 3 (palette); otherwise it is set to 2 (RGB) if the
+depth is 24 or 1 (min-is-black) if the depth is not 24.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Specify a compression scheme to use when writing image
+data: <b>&minus;c none</b> for no compression, <b>&minus;c
+packbits</b> for the PackBits compression algorithm,
+<b>&minus;c jpeg</b> for the baseline JPEG compression
+algorithm, <b>&minus;c zip</b> for the Deflate compression
+algorithm, and <b>&minus;c lzw</b> for Lempel-Ziv &amp;
+Welch (the default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Write data with a specified number of rows per strip; by
+default the number of rows/strip is selected so that each
+strip is approximately 8 kilobytes.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Does not handle all possible rasterfiles. In particular,
+<i>ras2tiff</i> does not handle run-length encoded
+images.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/raw2tiff.1.html b/tiff/html/man/raw2tiff.1.html
new file mode 100644
index 0000000..360eb27
--- /dev/null
+++ b/tiff/html/man/raw2tiff.1.html
@@ -0,0 +1,510 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:18 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>RAW2TIFF</title>
+</head>
+<body>
+
+<h1 align=center>RAW2TIFF</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#GUESSING THE IMAGE GEOMETRY">GUESSING THE IMAGE GEOMETRY</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>raw2tiff &minus; create a <small>TIFF</small> file from a
+raw data</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>raw2tiff</b> [ <i>options</i> ] <i>input.raw
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>raw2tiff</i> converts a raw byte sequence into
+<small>TIFF.</small> By default, the <small>TIFF</small>
+image is created with data samples packed
+(<i>PlanarConfiguration</i>=1), compressed with the PackBits
+algorithm (<i>Compression</i>=32773), and with each strip no
+more than 8 kilobytes. These characteristics can overridden,
+or explicitly specified with the options described
+below.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;H</b> <i>number</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>size of input image file header in bytes (0 by default).
+This amount of data just will be skipped from the start of
+file while reading.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;w</b> <i>number</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>width of input image in pixels (can be guessed, see
+<b><small>GUESSING THE IMAGE GEOMETRY</small></b>
+below).</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;l</b> <i>number</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>length of input image in lines (can be guessed, see
+<b><small>GUESSING THE IMAGE GEOMETRY</small></b>
+below).</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;b</b> <i>number</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>number of bands in input image (1 by default).</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;d</b> <i>data_type</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>type of samples in input image, where <i>data_type</i>
+may be:</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="3" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="10%">
+
+<p><b>byte</b></p>
+</td>
+<td width="70%">
+
+<p>8-bit unsigned integer (default),</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="10%">
+
+<p><b>short</b></p>
+</td>
+<td width="70%">
+
+<p>16-bit unsigned integer,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="10%">
+
+<p><b>long</b></p>
+</td>
+<td width="70%">
+
+<p>32-bit unsigned integer,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="10%">
+
+<p><b>sbyte</b></p>
+</td>
+<td width="70%">
+
+<p>8-bit signed integer,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="10%">
+
+<p><b>sshort</b></p>
+</td>
+<td width="70%">
+
+<p>16-bit signed integer,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="10%">
+
+<p><b>slong</b></p>
+</td>
+<td width="70%">
+
+<p>32-bit signed integer,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="10%">
+
+<p><b>float</b></p>
+</td>
+<td width="70%">
+
+<p>32-bit IEEE floating point,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="10%">
+
+<p><b>double</b></p>
+</td>
+<td width="70%">
+
+<p>64-bit IEEE floating point.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;i</b> <i>config</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>type of samples interleaving in input image, where
+<i>config</i> may be:</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="3" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="8%">
+
+<p><b>pixel</b></p>
+</td>
+<td width="71%">
+
+<p>pixel interleaved data (default),</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="8%">
+
+<p><b>band</b></p>
+</td>
+<td width="71%">
+
+<p>band interleaved data.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;p</b> <i>photo</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>photometric interpretation (color space) of the input
+image, where <i>photo</i> may be:</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="3" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="15%">
+
+<p><b>miniswhite</b></p>
+</td>
+<td width="65%">
+
+<p>white color represented with 0 value,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="15%">
+
+<p><b>minisblack</b></p>
+</td>
+<td width="65%">
+
+<p>black color represented with 0 value (default),</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="15%">
+
+<p><b>rgb</b></p>
+</td>
+<td width="65%">
+
+<p>image has RGB color model,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="15%">
+
+<p><b>cmyk</b></p>
+</td>
+<td width="65%">
+
+<p>image has CMYK (separated) color model,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="15%">
+
+<p><b>ycbcr</b></p>
+</td>
+<td width="65%">
+
+<p>image has YCbCr color model,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="15%">
+
+<p><b>cielab</b></p>
+</td>
+<td width="65%">
+
+<p>image has CIE L*a*b color model,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="15%">
+
+<p><b>icclab</b></p>
+</td>
+<td width="65%">
+
+<p>image has ICC L*a*b color model,</p>
+</td>
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="15%">
+
+<p><b>itulab</b></p>
+</td>
+<td width="65%">
+
+<p>image has ITU L*a*b color model.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;s</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>swap bytes fetched from the input file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;L</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>input data has LSB2MSB bit order (default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;M</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>input data has MSB2LSB bit order.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify a compression scheme to use when writing image
+data: <b>&minus;c none</b> for no compression, <b>&minus;c
+packbits</b> for the PackBits compression algorithm (the
+default), <b>&minus;c jpeg</b> for the baseline JPEG
+compression algorithm, <b>&minus;c zip</b> for the Deflate
+compression algorithm, and <b>&minus;c lzw</b> for
+Lempel-Ziv &amp; Welch.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;r</b> <i>number</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Write data with a specified number of rows per strip; by
+default the number of rows/strip is selected so that each
+strip is approximately 8 kilobytes.</p>
+</td>
+</table>
+<a name="GUESSING THE IMAGE GEOMETRY"></a>
+<h2>GUESSING THE IMAGE GEOMETRY</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>raw2tiff</i> can guess image width and height in case
+one or both of these parameters are not specified. If you
+omit one of those parameters, the complementary one will be
+calculated based on the file size (taking into account
+header size, number of bands and data type). If you omit
+both parameters, the statistical approach will be used.
+Utility will compute correlation coefficient between two
+lines at the image center using several appropriate line
+sizes and the highest absolute value of the coefficient will
+indicate the right line size. That is why you should be
+cautious with the very large images, because guessing
+process may take a while (depending on your system
+performance). Of course, the utility can&rsquo;t guess the
+header size, number of bands and data type, so it should be
+specified manually. If you don&rsquo;t know anything about
+your image, just try with the several combinations of those
+options.</p>
+<!-- INDENTATION -->
+<p>There is no magic, it is just a mathematical statistics,
+so it can be wrong in some cases. But for most ordinary
+images guessing method will work fine.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/rgb2ycbcr.1.html b/tiff/html/man/rgb2ycbcr.1.html
new file mode 100644
index 0000000..5cff15f
--- /dev/null
+++ b/tiff/html/man/rgb2ycbcr.1.html
@@ -0,0 +1,155 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>RGB2YCBCR</title>
+</head>
+<body>
+
+<h1 align=center>RGB2YCBCR</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>rgb2ycbcr &minus; convert non-YCbCr <small>TIFF</small>
+images to a YCbCr <small>TIFF</small> image</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>rgb2ycbcr</b> [ <i>options</i> ] <i>src1.tif src2.tif
+... dst.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>rgb2ycbcr</i> converts <small>RGB</small> color,
+greyscale, or bi-level <small>TIFF</small> images to YCbCr
+images by transforming and sampling pixel data. If multiple
+files are specified on the command line each source file is
+converted to a separate directory in the destination
+file.</p>
+<!-- INDENTATION -->
+<p>By default, chrominance samples are created by sampling 2
+by 2 blocks of luminance values; this can be changed with
+the <b>&minus;h</b> and <b>&minus;v</b> options. Output data
+are compressed with the <small>PackBits</small> compression
+scheme, by default; an alternate scheme can be selected with
+the <b>&minus;c</b> option. By default, output data are
+compressed in strips with the number of rows in each strip
+selected so that the size of a strip is never more than 8
+kilobytes; the <b>&minus;r</b> option can be used to
+explicitly set the number of rows per strip.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify a compression scheme to use when writing image
+data: <b>&minus;c none</b> for no compression, <b>&minus;c
+packbits</b> for the PackBits compression algorithm (the
+default), <b>&minus;c jpeg</b> for the JPEG compression
+algorithm, <b>&minus;c zip</b> for the deflate compression
+algorithm, and <b>&minus;c lzw</b> for Lempel-Ziv &amp;
+Welch.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;h</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Set the horizontal sampling dimension to one of: 1, 2
+(default), or 4.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Write data with a specified number of rows per strip; by
+default the number of rows/strip is selected so that each
+strip is approximately 8 kilobytes.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;v</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Set the vertical sampling dimension to one of: 1, 2
+(default), or 4.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/sgi2tiff.1.html b/tiff/html/man/sgi2tiff.1.html
new file mode 100644
index 0000000..fe90d64
--- /dev/null
+++ b/tiff/html/man/sgi2tiff.1.html
@@ -0,0 +1,147 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>SGI2TIFF</title>
+</head>
+<body>
+
+<h1 align=center>SGI2TIFF</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>sgi2tiff &minus; create a <small>TIFF</small> file from
+an <small>SGI</small> image file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>sgi2tiff</b> [ <i>options</i> ] <i>input.rgb
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>sgi2tiff</i> converts a file in the <small>SGI</small>
+image format to <small>TIFF.</small> By default, the
+<small>TIFF</small> image is created with data samples
+packed (<i>PlanarConfiguration</i>=1), compressed with the
+Lempel-Ziv &amp; Welch algorithm (<i>Compression</i>=5), and
+with each strip no more than 8 kilobytes. These
+characteristics can overridden, or explicitly specified with
+the options described below.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify a compression scheme to use when writing image
+data: <b>&minus;c none</b> for no compression, <b>&minus;c
+packbits</b> for the PackBits compression algorithm),
+<b>&minus;c jpeg</b> for the baseline JPEG compression
+algorithm, <b>&minus;c zip</b> for the Deflate compression
+algorithm, and <b>&minus;c lzw</b> for Lempel-Ziv &amp;
+Welch (the default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;p</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Explicitly select the planar configuration used in
+organizing data samples in the output image: <b>&minus;p
+contig</b> for samples packed contiguously, and <b>&minus;p
+separate</b> for samples stored separately. By default
+samples are packed.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Write data with a specified number of rows per strip; by
+default the number of rows/strip is selected so that each
+strip is approximately 8 kilobytes.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Does not record colormap information.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/thumbnail.1.html b/tiff/html/man/thumbnail.1.html
new file mode 100644
index 0000000..fabc601
--- /dev/null
+++ b/tiff/html/man/thumbnail.1.html
@@ -0,0 +1,148 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>THUMBNAIL</title>
+</head>
+<body>
+
+<h1 align=center>THUMBNAIL</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>thumbnail &minus; create a <small>TIFF</small> file with
+thumbnail images</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>thumbnail</b> [ <i>options</i> ] <i>input.tif
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>thumbnail</i> is a program written to show how one
+might use the SubIFD tag (#330) to store thumbnail images.
+<i>thumbnail</i> copies a <small>TIFF</small> Class F
+facsimile file to the output file and for each image an
+8-bit greyscale <i>thumbnail sketch</i>. The output file
+contains the thumbnail image with the associated
+full-resolution page linked below with the SubIFD tag.</p>
+<!-- INDENTATION -->
+<p>By default, thumbnail images are 216 pixels wide by 274
+pixels high. Pixels are calculated by sampling and filtering
+the input image with each pixel value passed through a
+contrast curve.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;w</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the width of thumbnail images in pixels.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;h</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the height of thumbnail images in pixels.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify a contrast curve to apply in generating the
+thumbnail images. By default pixels values are passed
+through a linear contrast curve that simply maps the pixel
+value ranges. Alternative curves are: <b>exp50</b> for a 50%
+exponential curve, <b>exp60</b> for a 60% exponential curve,
+<b>exp70</b> for a 70% exponential curve, <b>exp80</b> for a
+80% exponential curve, <b>exp90</b> for a 90% exponential
+curve, <b>exp</b> for a pure exponential curve,
+<b>linear</b> for a linear curve.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>There are no options to control the format of the saved
+thumbnail images.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffdump</b>(1), <b>tiffgt</b>(1), <b>tiffinfo</b>(1),
+<b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiff2bw.1.html b/tiff/html/man/tiff2bw.1.html
new file mode 100644
index 0000000..6b6accf
--- /dev/null
+++ b/tiff/html/man/tiff2bw.1.html
@@ -0,0 +1,161 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFF2BW</title>
+</head>
+<body>
+
+<h1 align=center>TIFF2BW</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiff2bw &minus; convert a color <small>TIFF</small> image
+to greyscale</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiff2bw</b> [ <i>options</i> ] <i>input.tif
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>Tiff2bw</i> converts an <small>RGB</small> or Palette
+color <small>TIFF</small> image to a greyscale image by
+combining percentages of the red, green, and blue channels.
+By default, output samples are created by taking 28% of the
+red channel, 59% of the green channel, and 11% of the blue
+channel. To alter these percentages, the <b>&minus;R</b>,
+<b>&minus;G</b>, and <b>&minus;B</b> options may be
+used.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify a compression scheme to use when writing image
+data: <b>&minus;c none</b> for no compression, <b>&minus;c
+packbits</b> for the PackBits compression algorithm,
+<b>&minus;c zip</b> for the Deflate compression algorithm,
+<b>&minus;c g3</b> for the CCITT Group 3 compression
+algorithm, <b>&minus;c g4</b> for the CCITT Group 4
+compression algorithm, and <b>&minus;c lzw</b> for
+Lempel-Ziv &amp; Welch (the default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Write data with a specified number of rows per strip; by
+default the number of rows/strip is selected so that each
+strip is approximately 8 kilobytes.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;R</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the percentage of the red channel to use
+(default 28).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;G</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the percentage of the green channel to use
+(default 59).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;B</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the percentage of the blue channel to use
+(default 11).</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiff2pdf.1.html b/tiff/html/man/tiff2pdf.1.html
new file mode 100644
index 0000000..80e0d55
--- /dev/null
+++ b/tiff/html/man/tiff2pdf.1.html
@@ -0,0 +1,609 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFF2PDF</title>
+</head>
+<body>
+
+<h1 align=center>TIFF2PDF</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#EXAMPLES">EXAMPLES</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p>tiff2pdf &minus; convert a TIFF image to a PDF
+document</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>tiff2pdf</b> [ <i>options</i> ] <i>input.tiff</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><i>tiff2pdf</i> opens a TIFF image and writes a PDF
+document to standard output.</p>
+<!-- INDENTATION -->
+<p>The program converts one TIFF file to one PDF file,
+including multiple page TIFF files, tiled TIFF files, black
+and white. grayscale, and color TIFF files that contain data
+of TIFF photometric interpretations of bilevel, grayscale,
+RGB, YCbCr, CMYK separation, and ICC L*a*b* as supported by
+<i>libtiff</i> and PDF.</p>
+<!-- INDENTATION -->
+<p>If you have multiple TIFF files to convert into one PDF
+file then use <i>tiffcp</i> or other program to concatenate
+the files into a multiple page TIFF file. If the input TIFF
+file is of huge dimensions (greater than 10000 pixels height
+or width) convert the input image to a tiled TIFF if it is
+not already.</p>
+<!-- INDENTATION -->
+<p>The standard output is standard output. Set the output
+file name with the <b>&minus;o</b> <i>output.pdf</i>
+option.</p>
+<!-- INDENTATION -->
+<p>All black and white files are compressed into a single
+strip CCITT G4 Fax compressed PDF, unless tiled, where tiled
+black and white images are compressed into tiled CCITT G4
+Fax compressed PDF, <i>libtiff</i> CCITT support is
+assumed.</p>
+<!-- INDENTATION -->
+<p>Color and grayscale data can be compressed using either
+JPEG compression, ITU-T T.81, or Zip/Deflate LZ77
+compression. Set the compression type using the
+<b>&minus;j</b> or <b>&minus;z</b> options. JPEG compression
+support requires that <i>libtiff</i> be configured with JPEG
+support, and Zip/Deflate compression support requires that
+<i>libtiff</i> be configured with Zip support, in
+tiffconf.h. Use only one or the other of <b>&minus;j</b> and
+<b>&minus;z.</b></p>
+<!-- INDENTATION -->
+<p>If the input TIFF contains single strip CCITT G4 Fax
+compressed information, then that is written to the PDF file
+without transcoding, unless the options of no compression
+and no passthrough are set, <b>&minus;d</b> and
+<b>&minus;n.</b></p>
+<!-- INDENTATION -->
+<p>If the input TIFF contains JPEG or single strip
+Zip/Deflate compressed information, and they are configured,
+then that is written to the PDF file without transcoding,
+unless the options of no compression and no passthrough are
+set.</p>
+<!-- INDENTATION -->
+<p>The default page size upon which the TIFF image is placed
+is determined by the resolution and extent of the image
+data. Default values for the TIFF image resolution can be
+set using the <b>&minus;x</b> and <b>&minus;y</b> options.
+The page size can be set using the <b>&minus;p</b> option
+for paper size, or <b>&minus;w</b> and <b>&minus;l</b> for
+paper width and length, then each page of the TIFF image is
+centered on its page. The distance unit for default
+resolution and page width and length can be set by the
+<b>&minus;u</b> option, the default unit is inch.</p>
+<!-- INDENTATION -->
+<p>Various items of the output document information can be
+set with the <b>&minus;e</b>, <b>&minus;c</b>,
+<b>&minus;a</b>, <b>&minus;t</b>, <b>&minus;s</b>, and
+<b>&minus;k</b> options. Setting the argument of the option
+to &quot;&quot; for these tags causes the relevant document
+information field to be not written. Some of the document
+information values otherwise get their information from the
+input TIFF image, the software, author, document name, and
+image description.</p>
+<!-- INDENTATION -->
+<p>The Portable Document Format (PDF) specification is
+copyrighted by Adobe Systems, Incorporated.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;o</b> <i>output-file</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set the output to go to file. <i>output-file</i></p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="4" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="4%">
+
+<p><b>&minus;j</b></p>
+</td>
+<td width="5%"></td>
+<td width="77%">
+
+<p>Compress with JPEG (requires <i>libjpeg</i> configured
+with <i>libtiff</i>).</p>
+</td>
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="4%">
+
+<p><b>&minus;z</b></p>
+</td>
+<td width="5%"></td>
+<td width="77%">
+
+<p>Compress with Zip/Deflate (requires <i>zlib</i>
+configured with <i>libtiff</i>).</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;q</b> <i>quality</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set the compression quality, 1-100 for JPEG.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="4" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;n</b></p>
+</td>
+<td width="7%"></td>
+<td width="77%">
+
+<p>Do not allow data to be converted without uncompressing,
+no compressed data passthrough.</p>
+</td>
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;b</b></p>
+</td>
+<td width="7%"></td>
+<td width="77%">
+
+<p>Set PDF &lsquo;&lsquo;Interpolate&rsquo;&rsquo; user
+preference.</p>
+</td>
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;d</b></p>
+</td>
+<td width="7%"></td>
+<td width="77%">
+
+<p>Do not compress (decompress).</p>
+</td>
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;i</b></p>
+</td>
+<td width="7%"></td>
+<td width="77%">
+
+<p>Invert colors.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;p</b> <i>paper-size</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set paper size, e.g., <b>letter</b>, <b>legal</b>,
+<b>A4</b>.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;u</b> [<b>i</b>|<b>m</b>]</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set distance unit, <b>i</b> for inch, <b>m</b> for
+centimeter.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;w</b> <i>width</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set width in units.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;l</b> <i>length</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set length in units.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;x</b> <i>xres</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set x/width resolution default.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;y</b> <i>yres</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set y/length resolution default.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;r</b> [<b>d</b>|<b>o</b>]</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set <b>d</b> for resolution default for images without
+resolution, <b>o</b> for resolution override for all
+images.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;f</b></p>
+</td>
+<td width="13%"></td>
+<td width="57%">
+
+<p>Set PDF &lsquo;&lsquo;Fit Window&rsquo;&rsquo; user
+preference.</p>
+</td>
+<td width="14%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;e</b> <i>YYYYMMDDHHMMSS</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set document information date, overrides image or current
+date/time default, <i>YYYYMMDDHHMMSS.</i></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;c</b> <i>creator</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set document information creator, overrides image
+software default.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;a</b> <i>author</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set document information author, overrides image artist
+default.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;t</b> <i>title</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set document information title, overrides image document
+name default.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;s</b> <i>subject</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set document information subject, overrides image image
+description default.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>&minus;k</b> <i>keywords</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="21%"></td>
+<td width="77%">
+<p>Set document information keywords.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;h</b></p>
+</td>
+<td width="13%"></td>
+<td width="57%">
+
+<p>List usage reminder to stderr and exit.</p>
+</td>
+<td width="14%">
+</td>
+</table>
+<a name="EXAMPLES"></a>
+<h2>EXAMPLES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p>The following example would generate the file output.pdf
+from input.tiff.</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="20%"></td>
+<td width="79%">
+<pre>tiff2pdf &minus;o output.pdf input.tiff
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p>The following example would generate PDF output from
+input.tiff and write it to standard output.</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="20%"></td>
+<td width="79%">
+<pre>tiff2pdf input.tiff
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p>The following example would generate the file output.pdf
+from input.tiff, putting the image pages on a letter sized
+page, compressing the output with JPEG, with JPEG quality
+75, setting the title to
+&lsquo;&lsquo;Document&rsquo;&rsquo;, and setting the
+&lsquo;&lsquo;Fit Window&rsquo;&rsquo; option.</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="20%"></td>
+<td width="79%">
+<pre>tiff2pdf &minus;p letter &minus;j &minus;q 75 &minus;t &quot;Document&quot; &minus;f &minus;o output.pdf input.tiff
+</pre>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p>Please report bugs via the web interface at</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="20%"></td>
+<td width="79%">
+
+<p>http://bugzilla.remotesensing.org/enter_bug.cgi?product=libtiff</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="89%">
+<p><b>libtiff</b>(3), <b>tiffcp</b>(1),
+<b>tiff2ps</b>(1)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiff2ps.1.html b/tiff/html/man/tiff2ps.1.html
new file mode 100644
index 0000000..e13bb8f
--- /dev/null
+++ b/tiff/html/man/tiff2ps.1.html
@@ -0,0 +1,532 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFF2PS</title>
+</head>
+<body>
+
+<h1 align=center>TIFF2PS</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#EXAMPLES">EXAMPLES</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiff2ps &minus; convert a <small>TIFF</small> image to
+PostScript&trade;</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiff2ps</b> [ <i>options</i> ] <i>input.tif
+...</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiff2ps</i> reads <small>TIFF</small> images and
+writes PostScript or Encapsulated PostScript (EPS) on the
+standard output. By default, <i>tiff2ps</i> writes
+Encapsulated PostScript for the first image in the specified
+<small>TIFF</small> image file.</p>
+<!-- INDENTATION -->
+<p>By default, <i>tiff2ps</i> will generate PostScript that
+fills a printed area specified by the <small>TIFF</small>
+tags in the input file. If the file does not contain
+<i>XResolution</i> or <i>YResolution</i> tags, then the
+printed area is set according to the image dimensions. The
+<b>&minus;w</b> and <b>&minus;h</b> options (see below) can
+be used to set the dimensions of the printed area in inches;
+overriding any relevant <small>TIFF</small> tags.</p>
+<!-- INDENTATION -->
+<p>The PostScript generated for <small>RGB,</small> palette,
+and <small>CMYK</small> images uses the <i>colorimage</i>
+operator. The PostScript generated for greyscale and bilevel
+images uses the <i>image</i> operator. When the
+<i>colorimage</i> operator is used, PostScript code to
+emulate this operator on older PostScript printers is also
+generated. Note that this emulation code can be very
+slow.</p>
+<!-- INDENTATION -->
+<p>Color images with associated alpha data are composited
+over a white background.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;1</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Generate PostScript Level 1 (the default).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;2</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Generate PostScript Level 2.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;3</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Generate PostScript Level 3. It basically allows one to
+use the /flateDecode filter for ZIP compressed TIFF
+images.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;a</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Generate output for all IFDs (pages) in the input
+file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;b</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the bottom margin for the output (in inches).
+This does not affect the height of the printed image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Center the image in the output. This option only shows
+an effect if both the <b>&minus;w</b> and the
+<b>&minus;h</b> option are given.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;d</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Set the initial <small>TIFF</small> directory to the
+specified directory number. (NB: Directories are numbered
+starting at zero.) This option is useful for selecting
+individual pages in a multi-page (e.g. facsimile) file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;e</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the generation of Encapsulated PostScript (implies
+<b>&minus;z</b>).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;h</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the vertical size of the printed area (in
+inches).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;H</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the maximum height of image (in inches). Images
+with larger sizes will be split in several pages. Option
+<b>&minus;L</b> may be used for specifying size of split
+images overlapping.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;i</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Enable/disable pixel interpolation. This option requires
+a single numeric value: zero to disable pixel interpolation
+and non-zero to enable. The default is enabled.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;L</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the size of overlapping for split images (in
+inches). Used in conjunction with <b>&minus;H</b>
+option.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;l</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the left margin for the output (in inches). This
+does not affect the width of the printed image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;m</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Where possible render using the <i>imagemask</i>
+PostScript operator instead of the <i>image</i> operator.
+When this option is specified <i>tiff2ps</i> will use
+<i>imagemask</i> for rendering 1 bit deep images. If this
+option is not specified or if the image depth is greater
+than 1 then the <i>image</i> operator is used.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;o</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Set the initial <small>TIFF</small> directory to the
+<small>IFD</small> at the specified file offset. This option
+is useful for selecting thumbnail images and the like which
+are hidden using the <i>SubIFD</i> tag.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;p</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the generation of (non-Encapsulated)
+PostScript.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Rotate image by 180 degrees.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;s</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Generate output for a single IFD (page) in the input
+file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;w</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the horizontal size of the printed area (in
+inches).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;x</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Override resolution units specified in the TIFF as
+centimeters.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;y</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Override resolution units specified in the TIFF as
+inches.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;z</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>When generating PostScript Level 2, data is scaled so
+that it does not image into the <i>deadzone</i> on a page
+(the outer margin that the printing device is unable to
+mark). This option suppresses this behavior. When PostScript
+Level 1 is generated, data is imaged to the entire printed
+page and this option has no affect.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="EXAMPLES"></a>
+<h2>EXAMPLES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following generates PostScript Level 2 for all pages
+of a facsimile:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiff2ps &minus;a2 fax.tif | lpr
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Note also that if you have version 2.6.1 or newer of
+Ghostscript then you can efficiently preview facsimile
+generated with the above command.</p>
+<!-- INDENTATION -->
+<p>To generate Encapsulated PostScript for a the image at
+directory 2 of an image use:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiff2ps &minus;d 1 foo.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>(Notice that directories are numbered starting at
+zero.)</p>
+<!-- INDENTATION -->
+<p>If you have a long image, it may be split in several
+pages:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiff2ps &minus;h11 &minus;w8.5 &minus;H14 &minus;L.5 foo.tif &gt; foo.ps
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The page size is set to 8.5x11 by <b>&minus;w</b> and
+<b>&minus;h</b> options. We will accept a small amount of
+vertical compression, so <b>&minus;H</b> set to 14. Any
+pages between 11 and 14 inches will be fit onto one page.
+Pages longer than 14 inches are cut off at 11 and continued
+on the next page. The <b>&minus;L.5</b> option says to
+repeat a half inch on the next page (to improve
+readability).</p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Because PostScript does not support the notion of a
+colormap, 8-bit palette images produce 24-bit PostScript
+images. This conversion results in output that is six times
+bigger than the original image and which takes a long time
+to send to a printer over a serial line. Matters are even
+worse for 4-, 2-, and 1-bit palette images.</p>
+<!-- INDENTATION -->
+<p>Does not handle tiled images when generating PostScript
+Level I output.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffgt</b>(1), <b>tiffmedian</b>(1), <b>tiff2bw</b>(1),
+<b>tiffsv</b>(1), <b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiff2rgba.1.html b/tiff/html/man/tiff2rgba.1.html
new file mode 100644
index 0000000..eec3968
--- /dev/null
+++ b/tiff/html/man/tiff2rgba.1.html
@@ -0,0 +1,162 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFF2RGBA</title>
+</head>
+<body>
+
+<h1 align=center>TIFF2RGBA</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiff2rgba &minus; convert a <small>TIFF</small> image to
+RGBA color space</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiff2rgba</b> [ <i>options</i> ] <i>input.tif
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>Tiff2rgba</i> converts a wide variety of TIFF images
+into an RGBA TIFF image. This includes the ability to
+translate different color spaces and photometric
+interpretation into RGBA, support for alpha blending, and
+translation of many different bit depths into a 32bit RGBA
+image.</p>
+<!-- INDENTATION -->
+<p>Internally this program is implemented using the
+<i>TIFFReadRGBAImage()</i> function, and it suffers any
+limitations of that image. This includes limited support for
+&gt; 8 BitsPerSample images, and flaws with some esoteric
+combinations of BitsPerSample, photometric interpretation,
+block organization and planar configuration.</p>
+<!-- INDENTATION -->
+<p>The generated images are stripped images with four
+samples per pixel (red, green, blue and alpha) or if the
+<b>&minus;n</b> flag is used, three samples per pixel (red,
+green, and blue). The resulting images are always planar
+configuration contiguous. For this reason, this program is a
+useful utility for transform exotic TIFF files into a form
+ingestible by almost any TIFF supporting software.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify a compression scheme to use when writing image
+data: <b>&minus;c none</b> for no compression (the default),
+<b>&minus;c packbits</b> for the PackBits compression
+algorithm, <b>&minus;c zip</b> for the Deflate compression
+algorithm, <b>&minus;c jpeg</b> for the JPEG compression
+algorithm, and <b>&minus;c lzw</b> for Lempel-Ziv &amp;
+Welch.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Write data with a specified number of rows per strip; by
+default the number of rows/strip is selected so that each
+strip is approximately 8 kilobytes.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;b</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Process the image one block (strip/tile) at a time
+instead of by reading the whole image into memory at once.
+This may be necessary for very large images on systems with
+limited RAM.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;n</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Drop the alpha component from the output file, producing
+a pure RGB file. Currently this does not work if the
+<b>&minus;b</b> flag is also in effect.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiff2bw</b>(1), <b>TIFFReadRGBAImage</b>(3t),
+<b>libtiff</b>(3)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffcmp.1.html b/tiff/html/man/tiffcmp.1.html
new file mode 100644
index 0000000..a9fca2f
--- /dev/null
+++ b/tiff/html/man/tiffcmp.1.html
@@ -0,0 +1,156 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFCMP</title>
+</head>
+<body>
+
+<h1 align=center>TIFFCMP</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffcmp &minus; compare two <small>TIFF</small> files</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffcmp</b> [ <i>options</i> ] <i>file1.tif
+file2.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>Tiffcmp</i> compares the tags and data in two files
+created according to the Tagged Image File Format, Revision
+6.0. The schemes used for compressing data in each file are
+immaterial when data are compared&minus;data are compared on
+a scanline-by-scanline basis after decompression. Most
+directory tags are checked; notable exceptions are:
+<i>GrayResponseCurve</i>, <i>ColorResponseCurve</i>, and
+<i>ColorMap</i> tags. Data will not be compared if any of
+the <i>BitsPerSample</i>, <i>SamplesPerPixel</i>, or
+<i>ImageWidth</i> values are not equal. By default,
+<i>tiffcmp</i> will terminate if it encounters any
+difference.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;l</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>List each byte of image data that differs between the
+files.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;z</b> <i>number</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>List specified number of image data bytes that differs
+between the files.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>&minus;t</b></p>
+</td>
+<td width="11%"></td>
+<td width="52%">
+
+<p>Ignore any differences in directory tags.</p>
+</td>
+<td width="23%">
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Tags that are not recognized by the library are not
+compared; they may also generate spurious diagnostics.</p>
+<!-- INDENTATION -->
+<p>The image data of tiled files is not compared, since the
+<i>TIFFReadScanline()</i> function is used. An error will be
+reported for tiled files.</p>
+<!-- INDENTATION -->
+<p>The pixel and/or sample number reported in differences
+may be off in some exotic cases.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffcp.1.html b/tiff/html/man/tiffcp.1.html
new file mode 100644
index 0000000..c7e2b09
--- /dev/null
+++ b/tiff/html/man/tiffcp.1.html
@@ -0,0 +1,536 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFCP</title>
+</head>
+<body>
+
+<h1 align=center>TIFFCP</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#EXAMPLES">EXAMPLES</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffcp &minus; copy (and possibly convert) a
+<small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffcp</b> [ <i>options</i> ] <i>src1.tif ... srcN.tif
+dst.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiffcp</i> combines one or more files created
+according to the Tag Image File Format, Revision 6.0 into a
+single <small>TIFF</small> file. Because the output file may
+be compressed using a different algorithm than the input
+files, <i>tiffcp</i> is most often used to convert between
+different compression schemes.</p>
+<!-- INDENTATION -->
+<p>By default, <i>tiffcp</i> will copy all the understood
+tags in a <small>TIFF</small> directory of an input file to
+the associated directory in the output file.</p>
+<!-- INDENTATION -->
+<p><i>tiffcp</i> can be used to reorganize the storage
+characteristics of data in a file, but it is explicitly
+intended to not alter or convert the image data content in
+any way.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;b</b> <i>image</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>subtract the following monochrome image from all others
+processed. This can be used to remove a noise bias from a
+set of images. This bias image is typically an image of
+noise the camera saw with its shutter closed.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;B</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be written with Big-Endian byte order.
+This option only has an effect when the output file is
+created or overwritten and not when it is appended to.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;C</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Suppress the use of &lsquo;&lsquo;strip
+chopping&rsquo;&rsquo; when reading images that have a
+single strip/tile of uncompressed data.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the compression to use for data written to the
+output file: <b>none</b> for no compression, <b>packbits</b>
+for PackBits compression, <b>lzw</b> for Lempel-Ziv &amp;
+Welch compression, <b>jpeg</b> for baseline JPEG
+compression, <b>zip</b> for Deflate compression, <b>g3</b>
+for CCITT Group 3 (T.4) compression, and <b>g4</b> for CCITT
+Group 4 (T.6) compression. By default <i>tiffcp</i> will
+compress data according to the value of the
+<i>Compression</i> tag found in the source file.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>The <small>CCITT</small> Group 3 and Group 4 compression
+algorithms can only be used with bilevel data.</p>
+<!-- INDENTATION -->
+<p>Group 3 compression can be specified together with
+several T.4-specific options: <b>1d</b> for 1-dimensional
+encoding, <b>2d</b> for 2-dimensional encoding, and
+<b>fill</b> to force each encoded scanline to be zero-filled
+so that the terminating EOL code lies on a byte boundary.
+Group 3-specific options are specified by appending a
+&lsquo;&lsquo;:&rsquo;&rsquo;-separated list to the
+&lsquo;&lsquo;g3&rsquo;&rsquo; option; e.g. <b>&minus;c
+g3:2d:fill</b> to get 2D-encoded data with byte-aligned EOL
+codes.</p>
+<!-- INDENTATION -->
+<p><small>LZW</small> compression can be specified together
+with a <i>predictor</i> value. A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value of 1 forces each
+scanline to be encoded without differencing. LZW-specific
+options are specified by appending a
+&lsquo;&lsquo;:&rsquo;&rsquo;-separated list to the
+&lsquo;&lsquo;lzw&rsquo;&rsquo; option; e.g. <b>&minus;c
+lzw:2</b> for <small>LZW</small> compression with horizontal
+differencing.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;f</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the bit fill order to use in writing output
+data. By default, <i>tiffcp</i> will create a new file with
+the same fill order as the original. Specifying <b>&minus;f
+lsb2msb</b> will force data to be written with the FillOrder
+tag set to <small>LSB2MSB,</small> while <b>&minus;f
+msb2lsb</b> will force data to be written with the FillOrder
+tag set to <small>MSB2LSB.</small></p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;i</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Ignore non-fatal read errors and continue processing of
+the input file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;l</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the length of a tile (in pixels). <i>tiffcp</i>
+attempts to set the tile dimensions so that no more than 8
+kilobytes of data appear in a tile.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;L</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be written with Little-Endian byte
+order. This option only has an effect when the output file
+is created or overwritten and not when it is appended
+to.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;M</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Suppress the use of memory-mapped files when reading
+images.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;p</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the planar configuration to use in writing image
+data that has one 8-bit sample per pixel. By default,
+<i>tiffcp</i> will create a new file with the same planar
+configuration as the original. Specifying <b>&minus;p
+contig</b> will force data to be written with multi-sample
+data packed together, while <b>&minus;p separate</b> will
+force samples to be written in separate planes.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the number of rows (scanlines) in each strip of
+data written to the output file. By default (or when value
+<b>0</b> is specified), <i>tiffcp</i> attempts to set the
+rows/strip that no more than 8 kilobytes of data appear in a
+strip. If you specify special value <b>&minus;1</b> it will
+results in infinite number of the rows per strip. The entire
+image will be the one strip in that case.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;s</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the output file to be written with data organized
+in strips (rather than tiles).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;t</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the output file to be written with data organized
+in tiles (rather than strips). options can be used to force
+the resultant image to be written as strips or tiles of
+data, respectively.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;w</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the width of a tile (in pixels). <i>tiffcp</i>
+attempts to set the tile dimensions so that no more than 8
+kilobytes of data appear in a tile. <i>tiffcp</i> attempts
+to set the tile dimensions so that no more than 8 kilobytes
+of data appear in a tile.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;x</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the output file to be written with PAGENUMBER value
+in sequence.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;,=</b><i>character</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>substitute <i>character</i> for &lsquo;,&rsquo; in
+parsing image directory indices in files. This is necessary
+if filenames contain commas. Note that <b>&minus;,=</b> with
+whitespace immediately following will disable the special
+meaning of the &lsquo;,&rsquo; entirely. See examples.</p>
+</td>
+</table>
+<a name="EXAMPLES"></a>
+<h2>EXAMPLES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following concatenates two files and writes the
+result using <small>LZW</small> encoding:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcp &minus;c lzw a.tif b.tif result.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>To convert a G3 1d-encoded <small>TIFF</small> to a
+single strip of G4-encoded data the following might be
+used:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcp &minus;c g4 &minus;r 10000 g3.tif g4.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>(1000 is just a number that is larger than the number of
+rows in the source file.)</p>
+<!-- INDENTATION -->
+<p>To extract a selected set of images from a multi-image
+TIFF file, the file name may be immediately followed by a
+&lsquo;,&rsquo; separated list of image directory indices.
+The first image is always in directory 0. Thus, to copy the
+1st and 3rd images of image file
+&lsquo;&lsquo;album.tif&rsquo;&rsquo; to
+&lsquo;&lsquo;result.tif&rsquo;&rsquo;:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcp album.tif,0,2 result.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>A trailing comma denotes remaining images in sequence.
+The following command will copy all image with except the
+first one:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcp album.tif,1, result.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Given file &lsquo;&lsquo;CCD.tif&rsquo;&rsquo; whose
+first image is a noise bias followed by images which include
+that bias, subtract the noise from all those images
+following it (while decompressing) with the
+command:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcp &minus;c none &minus;b CCD.tif CCD.tif,1, result.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>If the file above were named
+&lsquo;&lsquo;CCD,X.tif&rsquo;&rsquo;, the <b>&minus;,=</b>
+option would be required to correctly parse this filename
+with image numbers, as follows:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcp &minus;c none &minus;,=% &minus;b CCD,X.tif CCD,X%1%.tif result.tif
+
+</pre>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffinfo</b>(1), <b>tiffcmp</b>(1),
+<b>tiffmedian</b>(1), <b>tiffsplit</b>(1),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffcrop.1.html b/tiff/html/man/tiffcrop.1.html
new file mode 100644
index 0000000..4c25c29
--- /dev/null
+++ b/tiff/html/man/tiffcrop.1.html
@@ -0,0 +1,851 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFCROP</title>
+</head>
+<body>
+
+<h1 align=center>TIFFCROP</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#EXAMPLES">EXAMPLES</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffcrop &minus; copy, convert, crop, extract, or process
+a <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffcrop</b> [ <i>options</i> ] <i>src1.tif ...
+srcN.tif dst.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiffcrop</i> combines one or more files created
+according to the Tag Image File Format, Revision 6.0 into a
+single <small>TIFF</small> file. The output file may be
+compressed using a different algorithm than the input files.
+<i>tiffcrop</i> is most often used to extract portions of an
+image for processing with bar code recognizer or OCR
+software when that software cannot restrict the region of
+interest to a specific portion of the image or to improve
+efficiency when the regions of interest must be rotated. It
+can also be used to subdivide all or part of a processed
+image into smaller sections.</p>
+<!-- INDENTATION -->
+<p>Functions are applied to the input image in the following
+order:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>cropping, fixed area extraction, zones, inversion, mirroring, rotation.
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Functions are applied to the output image in the
+following order:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>output resolution, output margins, rows and columns
+<b>or</b> page size divisions, orientation options, strip,
+tile, byte order, and compression options.</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>By default, <i>tiffcrop</i> will copy all the understood
+tags in a <small>TIFF</small> directory of an input file to
+the associated directory in the output file. Options can be
+used to force the resultant image to be written as strips or
+tiles of data, respectively.</p>
+<!-- INDENTATION -->
+<p><i>tiffcrop</i> can be used to reorganize the storage
+characteristics of data in a file, and to reorganize,
+extract, rotate, and otherwise process the image data as
+specified at the same time whereas tiffcp does not alter the
+image data itself.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;N odd|even|#,#-#,#|last</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Specify one or more series or range(s) of images within
+file to process. The words <b>odd</b> or <b>even</b> may be
+used to specify all odd or even numbered images. The word
+<b>last</b> may be used in place of a number in the sequence
+to indicate the final image in the file without knowing how
+many images there are. Ranges of images may be specified
+with a dash and multiple sets can be indicated by joining
+them in a comma-separated list. eg. use <b>&minus;N
+1,5-7,last</b> to process the 1st, 5th through 7th, and
+final image in the file.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;E top|bottom|left|right</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Specify the top, bottom, left, or right edge as the
+reference from which to calcuate the width and length of
+crop regions or sequence of postions for zones. May be
+abbreviated to first letter.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;U in|cm|px</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Specify the type of units to apply to dimensions for
+margins and crop regions for input and output images. Inches
+or centimeters are converted to pixels using the resolution
+unit specified in the TIFF file (which defaults to inches if
+not specified in the IFD).</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;m #,#,#,#</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Specify margins to be removed from the input image. The
+order must be top, left, bottom, right with only commas
+separating the elements of the list. Margins are scaled
+according to the current units and removed before any other
+extractions are computed. Captial M was in use.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>&minus;X #</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Set the horizontal (X-axis) dimension of a region to
+extract relative to the specified origin reference. If the
+origin is the top or bottom edge, the X axis value will be
+assumed to start at the left edge.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>&minus;Y #</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Set the vertical (Y-axis) dimension of a region to
+extract relative to the specified origin reference. If the
+origin is the left or right edge, the Y axis value will be
+assumed to start at the top.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;Z #:#,#:#</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Specify zones of the image designated as position X of Y
+equal sized portions measured from the reference edge, eg
+1:3 would be first third of the image starting from the
+reference edge minus any margins specified for the confining
+edges. Multiple zones can be specified as a comma separated
+list but they must reference the same edge. To extract the
+top quarter and the bottom third of an image you would use
+<b>&minus;Z 1:4,3:3.</b></p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;F horiz|vert</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Flip, ie mirror, the image or extracted region
+horizontally or vertically.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;R 90|180|270</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Rotate the image or extracted region 90, 180, or 270
+degrees clockwise.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>&minus;I</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Invert the colorspace values for grayscale and bilevel
+images. This would be used to correct negative images that
+have incorrect PHOTMETRIC INTERPRETATION tags. No support
+for color images.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>&minus;H #</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Set the horizontal resolution of output images to #
+expressed in the current units.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>&minus;V #</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Set the vertical resolution of the output images to #
+expressed in the current units.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>&minus;J #</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Set the horizontal margin of an output page size to #
+expressed in the current units.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>&minus;K #</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Set the vertical margin of an output page size to #
+expressed in the current units.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;O portrait|landscape|auto</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Set the output orientation of the pages or sections. Auto
+will use the arrangement that requires the fewest pages.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;S cols:rows</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Divide each image into cols across and rows down equal
+sections.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;P page</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Format the output images to fit on page size paper. Use
+-P list to show the supported page sizes and dimensions.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;B</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be written with Big-Endian byte order.
+This option only has an effect when the output file is
+created or overwritten and not when it is appended to.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;C</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Suppress the use of &lsquo;&lsquo;strip
+chopping&rsquo;&rsquo; when reading images that have a
+single strip/tile of uncompressed data.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the compression to use for data written to the
+output file: <b>none</b> for no compression, <b>packbits</b>
+for PackBits compression, <b>lzw</b> for Lempel-Ziv &amp;
+Welch compression, <b>jpeg</b> for baseline JPEG
+compression, <b>zip</b> for Deflate compression, <b>g3</b>
+for CCITT Group 3 (T.4) compression, and <b>g4</b> for CCITT
+Group 4 (T.6) compression. By default <i>tiffcrop</i> will
+compress data according to the value of the
+<i>Compression</i> tag found in the source file.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>The <small>CCITT</small> Group 3 and Group 4 compression
+algorithms can only be used with bilevel data.</p>
+<!-- INDENTATION -->
+<p>Group 3 compression can be specified together with
+several T.4-specific options: <b>1d</b> for 1-dimensional
+encoding, <b>2d</b> for 2-dimensional encoding, and
+<b>fill</b> to force each encoded scanline to be zero-filled
+so that the terminating EOL code lies on a byte boundary.
+Group 3-specific options are specified by appending a
+&lsquo;&lsquo;:&rsquo;&rsquo;-separated list to the
+&lsquo;&lsquo;g3&rsquo;&rsquo; option; e.g. <b>&minus;c
+g3:2d:fill</b> to get 2D-encoded data with byte-aligned EOL
+codes.</p>
+<!-- INDENTATION -->
+<p><small>LZW</small> compression can be specified together
+with a <i>predictor</i> value. A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value of 1 forces each
+scanline to be encoded without differencing. LZW-specific
+options are specified by appending a
+&lsquo;&lsquo;:&rsquo;&rsquo;-separated list to the
+&lsquo;&lsquo;lzw&rsquo;&rsquo; option; e.g. <b>&minus;c
+lzw:2</b> for <small>LZW</small> compression with horizontal
+differencing.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;f</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the bit fill order to use in writing output
+data. By default, <i>tiffcrop</i> will create a new file
+with the same fill order as the original. Specifying
+<b>&minus;f lsb2msb</b> will force data to be written with
+the FillOrder tag set to <small>LSB2MSB,</small> while
+<b>&minus;f msb2lsb</b> will force data to be written with
+the FillOrder tag set to <small>MSB2LSB.</small></p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;i</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Ignore non-fatal read errors and continue processing of
+the input file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;l</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the length of a tile (in pixels).
+<i>tiffcrop</i> attempts to set the tile dimensions so that
+no more than 8 kilobytes of data appear in a tile.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;L</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force output to be written with Little-Endian byte
+order. This option only has an effect when the output file
+is created or overwritten and not when it is appended
+to.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;M</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Suppress the use of memory-mapped files when reading
+images.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;p</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the planar configuration to use in writing image
+data that has more than one 8-bit sample per pixel. By
+default, <i>tiffcrop</i> will create a new file with the
+same planar configuration as the original. Specifying
+<b>&minus;p contig</b> will force data to be written with
+multi-sample data packed together, while <b>&minus;p
+separate</b> will force samples to be written in separate
+planes.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the number of rows (scanlines) in each strip of
+data written to the output file. By default (or when value
+<b>0</b> is specified), <i>tiffcrop</i> attempts to set the
+rows/strip that no more than 8 kilobytes of data appear in a
+strip. If you specify the special value <b>-1</b> it will
+results in infinite number of the rows per strip. The entire
+image will be the one strip in that case.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;s</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the output file to be written with data organized
+in strips (rather than tiles).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;t</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the output file to be written with data organized
+in tiles (rather than strips).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;w</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the width of a tile (in pixels). <i>tiffcrop</i>
+attempts to set the tile dimensions so that no more than 8
+kilobytes of data appear in a tile. <i>tiffcrop</i> attempts
+to set the tile dimensions so that no more than 8 kilobytes
+of data appear in a tile.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;,={character}</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>substitute {character} for &rsquo;,&rsquo; in parsing
+image directory indices in files. This is necessary if
+filenames contain commas. Note that &rsquo;,=&rsquo; with
+whitespace immediately following will disable the special
+meaning of the &rsquo;,&rsquo; entirely. See examples.</p>
+</td>
+</table>
+<a name="EXAMPLES"></a>
+<h2>EXAMPLES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following concatenates two files and writes the
+result using <small>LZW</small> encoding:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcrop -c lzw a.tif b.tif result.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>To convert a G3 1d-encoded <small>TIFF</small> to a
+single strip of G4-encoded data the following might be
+used:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcrop -c g4 -r 10000 g3.tif g4.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>(1000 is just a number that is larger than the number of
+rows in the source file.)</p>
+<!-- INDENTATION -->
+<p>To extract a selected set of images from a multi-image
+TIFF file use the -N option described above. Thus, to copy
+the 1st and 3rd images of image file &quot;album.tif&quot;
+to &quot;result.tif&quot;:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcrop -N 1,3 album.tif result.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Invert a bilevel image scan of a microfilmed document and
+crop off margins of 0.25 inches on the left and right, 0.5
+inch on the top, nad 0.75 inch on the bottom. From the
+remaining portion of the image, select the second and third
+quarters, ie, one half of the area left from the center to
+each margin.</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcrop -U in -m 0.5,0.25,0.75,0.25 -E left -Z 2:4,3:4 -I MicrofilmNegative.tif MicrofilmPostiveCenter.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Extract only the final image of a large Architectural E
+sized multipage TIFF file and rotate it 90 degrees clockwise
+while reformatting the output to fit on tabloid sized sheets
+with one quarter of an inch on each side:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffcrop -N last -R 90 -O auto -P tabloid -U in -J 0.25 -K 0.25 -H 300 -V 300 Big-PlatMap.tif BigPlatMap-Tabloid.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The output images will have a specified resolution of 300
+dpi in both directions. The orientation of each page will be
+determined by whichever choice requires the fewest pages. To
+specify a specific orientation, use the portrait or
+landscape option.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffinfo</b>(1), <b>tiffcmp</b>(1),
+<b>tiffcp</b>(1), <b>tiffmedian</b>(1), <b>tiffsplit</b>(1),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffdither.1.html b/tiff/html/man/tiffdither.1.html
new file mode 100644
index 0000000..2427a90
--- /dev/null
+++ b/tiff/html/man/tiffdither.1.html
@@ -0,0 +1,183 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:19 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFDITHER</title>
+</head>
+<body>
+
+<h1 align=center>TIFFDITHER</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffdither &minus; convert a greyscale image to bilevel
+using dithering</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffdither</b> [ <i>options</i> ] <i>input.tif
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiffdither</i> converts a single channel 8-bit
+greyscale image to a bilevel image using Floyd-Steinberg
+error propagation with thresholding.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Specify the compression to use for data written to the
+output file: <b>none</b> for no compression, <b>packbits</b>
+for PackBits compression, <b>lzw</b> for Lempel-Ziv &amp;
+Welch compression, <b>zip</b> for Deflate compression,
+<b>g3</b> for CCITT Group 3 (T.4) compression, and <b>g4</b>
+for CCITT Group 4 (T.6) compression. By default
+<i>tiffdither</i> will compress data according to the value
+of the <i>Compression</i> tag found in the source file.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p>The <small>CCITT</small> Group 3 and Group 4 compression
+algorithms can only be used with bilevel data.</p>
+<!-- INDENTATION -->
+<p>Group 3 compression can be specified together with
+several T.4-specific options: <b>1d</b> for 1-dimensional
+encoding, <b>2d</b> for 2-dimensional encoding, and
+<b>fill</b> to force each encoded scanline to be zero-filled
+so that the terminating EOL code lies on a byte boundary.
+Group 3-specific options are specified by appending a
+&lsquo;&lsquo;:&rsquo;&rsquo;-separated list to the
+&lsquo;&lsquo;g3&rsquo;&rsquo; option; e.g. <b>&minus;c
+g3:2d:fill</b> to get 2D-encoded data with byte-aligned EOL
+codes.</p>
+<!-- INDENTATION -->
+<p><small>LZW</small> compression can be specified together
+with a <i>predictor</i> value. A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value of 1 forces each
+scanline to be encoded without differencing. LZW-specific
+options are specified by appending a
+&lsquo;&lsquo;:&rsquo;&rsquo;-separated list to the
+&lsquo;&lsquo;lzw&rsquo;&rsquo; option; e.g. <b>&minus;c
+lzw:2</b> for <small>LZW</small> compression with horizontal
+differencing.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;f</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the bit fill order to use in writing output
+data. By default, <i>tiffdither</i> will create a new file
+with the same fill order as the original. Specifying
+<b>&minus;f lsb2msb</b> will force data to be written with
+the <i>FillOrder</i> tag set to <small>LSB2MSB ,</small>
+while <b>&minus;f msb2lsb</b> will force data to be written
+with the <i>Fill- Order</i> tag set to <small>MSB2LSB
+.</small></p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;t</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Set the threshold value for dithering. By default the
+threshold value is 128.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The dither algorithm is taken from the
+<b>tiffmedian</b>(1) program (written by Paul Heckbert).</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>fax2tiff</b>(1),
+<b>tiffinfo</b>(1), <b>tiffcp</b>(1), <b>tiff2bw</b>(1),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffdump.1.html b/tiff/html/man/tiffdump.1.html
new file mode 100644
index 0000000..abf0662
--- /dev/null
+++ b/tiff/html/man/tiffdump.1.html
@@ -0,0 +1,145 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:20 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFDUMP</title>
+</head>
+<body>
+
+<h1 align=center>TIFFDUMP</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffdump &minus; print verbatim information about
+<small>TIFF</small> files</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffdump</b> [ <i>options</i> ] <i>name ...</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiffdump</i> displays directory information from files
+created according to the Tag Image File Format, Revision
+6.0. The header of each <small>TIFF</small> file (magic
+number, version, and first directory offset) is displayed,
+followed by the tag contents of each directory in the file.
+For each tag, the name, data type, count, and value(s) is
+displayed. When the symbolic name for a tag or data type is
+known, the symbolic name is displayed followed by it&rsquo;s
+numeric (decimal) value. Tag values are displayed enclosed
+in &lsquo;&lsquo;&lt;&gt;&rsquo;&rsquo; characters
+immediately preceded by the value of the count field. For
+example, an <i>ImageWidth</i> tag might be displayed as
+&lsquo;&lsquo;ImageWidth (256) SHORT (3)
+1&lt;800&gt;&rsquo;&rsquo;.</p>
+<!-- INDENTATION -->
+<p><i>tiffdump</i> is particularly useful for investigating
+the contents of <small>TIFF</small> files that
+<i>libtiff</i> does not understand.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>&minus;h</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Force numeric data to be printed in hexadecimal rather
+than the default decimal.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;m</b> <i>items</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Change the number of indirect data items that are
+printed. By default, this will be 24.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;o</b> <i>offset</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Dump the contents of the <small>IFD</small> at the a
+particular file offset. The file offset may be specified
+using the usual C-style syntax; i.e. a leading
+&lsquo;&lsquo;0x&rsquo;&rsquo; for hexadecimal and a leading
+&lsquo;&lsquo;0&rsquo;&rsquo; for octal.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffinfo</b>(1), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffgt.1.html b/tiff/html/man/tiffgt.1.html
new file mode 100644
index 0000000..e8bd4b2
--- /dev/null
+++ b/tiff/html/man/tiffgt.1.html
@@ -0,0 +1,551 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:20 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFGT</title>
+</head>
+<body>
+
+<h1 align=center>TIFFGT</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffgt &minus; display an image stored in a
+<small>TIFF</small> file (Silicon Graphics version)</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffgt</b> [ <i>options</i> ] <i>input.tif ...</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiffgt</i> displays one or more images stored using
+the Tag Image File Format, Revision 6.0. Each image is
+placed in a fixed size window that the user must position on
+the display (unless configured otherwise through X
+defaults). If the display has fewer than 24 bitplanes, or if
+the image does not warrant full color, then
+<small>RGB</small> color values are mapped to the closest
+values that exist in the colormap (this is done using the
+<i>rgbi</i> routine found in the graphics utility library
+<b>&minus;lgutil</b>.)</p>
+<!-- INDENTATION -->
+<p><i>tiffgt</i> correctly handles files with any of the
+following characteristics:</p></td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="3" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="34%">
+
+<p><i>BitsPerSample</i></p>
+</td>
+<td width="50%">
+
+<p>1, 2, 4, 8, 16</p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="34%">
+
+<p><i>SamplesPerPixel</i></p>
+</td>
+<td width="50%">
+
+<p>1, 3, 4 (the 4th sample is ignored)</p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="34%">
+
+<p><i>PhotometricInterpretation</i></p>
+</td>
+<td width="50%">
+
+<p>0 (min-is-white), 1 (min-is-black), 2 (RGB), 3
+(palette), 6 (YCbCr)</p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="34%">
+
+<p><i>PlanarConfiguration</i></p>
+</td>
+<td width="50%">
+
+<p>1 (contiguous), 2 (separate)</p>
+</td>
+<tr valign="top" align="left">
+<td width="15%"></td>
+<td width="34%">
+
+<p><i>Orientation</i></p>
+</td>
+<td width="50%">
+
+<p>1 (top-left), 4 (bottom-left)</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Data may be organized as strips or tiles and may be
+compressed with any of the compression algorithms supported
+by the <i>libtiff</i>(3) library.</p>
+<!-- INDENTATION -->
+<p>For palette images (<i>PhotometricInterpretation</i>=3),
+<i>tiffgt</i> inspects the colormap values and assumes
+either 16-bit or 8-bit values according to the maximum
+value. That is, if no colormap entry greater than 255 is
+found, <i>tiffgt</i> assumes the colormap has only 8-bit
+values; otherwise it assumes 16-bit values. This inspection
+is done to handle old images written by previous (incorrect)
+versions of <i>libtiff</i>.</p>
+<!-- INDENTATION -->
+<p><i>tiffgt</i> can be used to display multiple images
+one-at-a-time. The left mouse button switches the display to
+the first image in the <i>next</i> file in the list of files
+specified on the command line. The right mouse button
+switches to the first image in the <i>previous</i> file in
+the list. The middle mouse button causes the first image in
+the first file specified on the command line to be
+displayed. In addition the following keyboard commands are
+recognized:</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="4" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>b</b></p>
+</td>
+<td width="80%">
+
+<p>Use a <i>PhotometricInterpretation</i> of MinIsBlack in
+displaying the current image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>l</b></p>
+</td>
+<td width="80%">
+
+<p>Use a <i>FillOrder</i> of lsb-to-msb in decoding the
+current image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>m</b></p>
+</td>
+<td width="80%">
+
+<p>Use a <i>FillOrder</i> of msb-to-lsb in decoding the
+current image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>c</b></p>
+</td>
+<td width="80%">
+
+<p>Use a colormap visual to display the current image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>r</b></p>
+</td>
+<td width="80%">
+
+<p>Use a true color (24-bit RGB) visual to display the
+current image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>w</b></p>
+</td>
+<td width="80%">
+
+<p>Use a <i>PhotometricInterpretation</i> of MinIsWhite in
+displaying the current image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>W</b></p>
+</td>
+<td width="80%">
+
+<p>Toggle (enable/disable) display of warning messages from
+the <small>TIFF</small> library when decoding images.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>E</b></p>
+</td>
+<td width="80%">
+
+<p>Toggle (enable/disable) display of error messages from
+the <small>TIFF</small> library when decoding images.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>z</b></p>
+</td>
+<td width="80%">
+
+<p>Reset all parameters to their default settings
+(<i>FillOrder</i>, <i>PhotometricInterpretation</i>,
+handling of warnings and errors).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="8%">
+
+<p><b>PageUp</b></p>
+</td>
+<td width="80%">
+
+<p>Display the previous image in the current file or the
+last image in the previous file.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>PageDown</b></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Display the next image in the current file or the first
+image in the next file.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>Home</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Display the first image in the current file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="6%">
+
+<p><b>End</b></p>
+</td>
+<td width="2%"></td>
+<td width="80%">
+
+<p>Display the last image in the current file
+(unimplemented).</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force image display in a colormap window.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;d</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify an image to display by directory number. By
+default the first image in the file is displayed.
+Directories are numbered starting at zero.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;e</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Enable reporting of error messages from the
+<small>TIFF</small> library. By default <i>tiffgt</i>
+silently ignores images that cannot be read.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;f</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force <i>tiffgt</i> to run as a foreground process. By
+default <i>tiffgt</i> will place itself in the background
+once it has opened the requested image file.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;l</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the presumed bit ordering to be <small>LSB</small>
+to <small>MSB.</small></p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;m</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force the presumed bit ordering to be <small>MSB</small>
+to <small>LSB.</small></p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;o</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify an image to display by directory offset. By
+default the first image in the file is displayed.
+Directories offsets may be specified using C-style syntax;
+i.e. a leading &lsquo;&lsquo;0x&rsquo;&rsquo; for
+hexadecimal and a leading &lsquo;&lsquo;0&rsquo;&rsquo; for
+octal.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;p</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Override the value of the
+<i>PhotometricInterpretation</i> tag; the parameter may be
+one of: <b>miniswhite</b>, <b>minisblack</b>, <b>rgb</b>,
+<b>palette</b>, <b>mask</b>, <b>separated</b>, <b>ycbcr</b>,
+and <b>cielab</b>.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Force image display in a full color window.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;s</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Stop on the first read error. By default all errors in
+the input data are ignored and <i>tiffgt</i> does it&rsquo;s
+best to display as much of an image as possible.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;w</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Enable reporting of warning messages from the
+<small>TIFF</small> library. By default <i>tiffgt</i>
+ignores warning messages generated when reading an
+image.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;v</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Place information in the title bar describing what type
+of window (full color or colormap) is being used, the name
+of the input file, and the directory index of the image (if
+non-zero). By default, the window type is not shown in the
+title bar.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Images wider and taller than the display are silently
+truncated to avoid crashing old versions of the window
+manager.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffdump</b>(1), <b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffinfo.1.html b/tiff/html/man/tiffinfo.1.html
new file mode 100644
index 0000000..4863ed3
--- /dev/null
+++ b/tiff/html/man/tiffinfo.1.html
@@ -0,0 +1,196 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:20 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFINFO</title>
+</head>
+<body>
+
+<h1 align=center>TIFFINFO</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffinfo &minus; print information about
+<small>TIFF</small> files</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffinfo</b> [ <i>options</i> ] <i>input.tif
+...</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>Tiffinfo</i> displays information about files created
+according to the Tag Image File Format, Revision 6.0. By
+default, the contents of each <small>TIFF</small> directory
+in each file is displayed, with the value of each tag shown
+symbolically (where sensible).</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Display the colormap and color/gray response curves, if
+present.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;D</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>In addition to displaying the directory tags, read and
+decompress all the data in each image (but not display
+it).</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;d</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>In addition to displaying the directory tags, print each
+byte of decompressed data in hexadecimal.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;j</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Display any <small>JPEG</small> -related tags that are
+present.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;o</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Set the initial <small>TIFF</small> directory according
+to the specified file offset. The file offset may be
+specified using the usual C-style syntax; i.e. a leading
+&lsquo;&lsquo;0x&rsquo;&rsquo; for hexadecimal and a leading
+&lsquo;&lsquo;0&rsquo;&rsquo; for octal.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;s</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Display the offsets and byte counts for each data strip
+in a directory.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;z</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Enable strip chopping when reading image data.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;#</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Set the initial <small>TIFF</small> directory to
+<i>#</i>.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffcp</b>(1), <b>tiffcmp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffmedian.1.html b/tiff/html/man/tiffmedian.1.html
new file mode 100644
index 0000000..5961317
--- /dev/null
+++ b/tiff/html/man/tiffmedian.1.html
@@ -0,0 +1,183 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:20 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFMEDIAN</title>
+</head>
+<body>
+
+<h1 align=center>TIFFMEDIAN</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#NOTES">NOTES</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffmedian &minus; apply the median cut algorithm to data
+in a <small>TIFF</small> file</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffmedian</b> [ <i>options</i> ] <i>input.tif
+output.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiffmedian</i> applies the median cut algorithm to an
+<small>RGB</small> image in <i>input.tif</i> to generate a
+palette image that is written to <i>output.tif</i>. The
+generated colormap has, by default, 256 entries. The image
+data is quantized by mapping each pixel to the closest color
+values in the colormap.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="11%"></td>
+<td width="2%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the compression to use for data written to the
+output file: <b>none</b> for no compression, <b>packbits</b>
+for PackBits compression, <b>lzw</b> for Lempel-Ziv &amp;
+Welch compression, and <b>zip</b> for Deflate compression.
+By default <i>tiffmedian</i> will compress data according to
+the value of the <i>Compression</i> tag found in the source
+file.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p><small>LZW</small> compression can be specified together
+with a <i>predictor</i> value. A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value of 1 forces each
+scanline to be encoded without differencing. LZW-specific
+options are specified by appending a
+&lsquo;&lsquo;:&rsquo;&rsquo;-separated list to the
+&lsquo;&lsquo;lzw&rsquo;&rsquo; option; e.g. <b>&minus;c
+lzw:2</b> for <small>LZW</small> compression with horizontal
+differencing.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>&minus;C</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Specify the number of entries to use in the generated
+colormap. By default all 256 entries/colors are used.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>&minus;f</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Apply Floyd-Steinberg dithering before selecting a
+colormap entry.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="2%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="6%"></td>
+<td width="80%">
+
+<p>Specify the number of rows (scanlines) in each strip of
+data written to the output file. By default,
+<i>tiffmedian</i> attempts to set the rows/strip that no
+more than 8 kilobytes of data appear in a strip.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="NOTES"></a>
+<h2>NOTES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>This program is derived from Paul Heckbert&rsquo;s
+<i>median</i> program.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>pal2rgb</b>(1), <b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffcmp</b>(1), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p><b>Color Image Quantization for Frame Buffer Display</b>,
+Paul Heckbert, SIGGRAPH proceedings, 1982, pp. 297-307.</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffset.1.html b/tiff/html/man/tiffset.1.html
new file mode 100644
index 0000000..fb4d0ed
--- /dev/null
+++ b/tiff/html/man/tiffset.1.html
@@ -0,0 +1,176 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:20 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFSET</title>
+</head>
+<body>
+
+<h1 align=center>TIFFSET</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#EXAMPLES">EXAMPLES</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffset &minus; set a field in a <small>TIFF</small>
+header</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffset</b> [ <i>options</i> ] <i>filename.tif</i></p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>Tiffset</i> sets the value of a <small>TIFF</small>
+header to a specified value.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;s</b> <i>tagnumber</i> [ <i>count</i> ]
+<i>value ...</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Set the value of the named tag to the value or values
+specified.</p>
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>&minus;sf</b> <i>tagnumber filename</i></p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="19%"></td>
+<td width="80%">
+<p>Set the value of the tag to the contents of filename.
+This option is supported for ASCII tags only.</p>
+</td>
+</table>
+<a name="EXAMPLES"></a>
+<h2>EXAMPLES</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following example sets the image description tag
+(270) of a.tif to the contents of the file descrip:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffset &minus;sf 270 descrip a.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>The following example sets the artist tag (315) of a.tif
+to the string
+&lsquo;&lsquo;Anonymous&rsquo;&rsquo;:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffset &minus;s 305 Anonymous a.tif
+</pre>
+</td>
+</table>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>This example sets the resolution of the file a.tif to 300
+dpi:</p></td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<pre>tiffset &minus;s 296 2 a.tif
+tiffset &minus;s 282 300.0 a.tif
+tiffset &minus;s 283 300.0 a.tif
+</pre>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffdump</b>(1), <b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffsplit.1.html b/tiff/html/man/tiffsplit.1.html
new file mode 100644
index 0000000..adbc2f8
--- /dev/null
+++ b/tiff/html/man/tiffsplit.1.html
@@ -0,0 +1,102 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:20 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFSPLIT</title>
+</head>
+<body>
+
+<h1 align=center>TIFFSPLIT</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffsplit &minus; split a multi-image <small>TIFF</small>
+into single-image <small>TIFF</small> files</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffsplit</b> <i>src.tif</i> [ <i>prefix</i> ]</p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiffsplit</i> takes a multi-directory (page)
+<small>TIFF</small> file and creates one or more
+single-directory (page) <small>TIFF</small> files from it.
+The output files are given names created by concatenating a
+prefix, a lexically ordered suffix in the range
+[<i>aaa</i>-<i>zzz</i>], the suffix <i>.tif</i> (e.g.
+<i>xaaa.tif</i>, <i>xaab.tif</i>, <i>xzzz.tif</i>). If a
+prefix is not specified on the command line, the default
+prefix of <i>x</i> is used.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>None.</p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Only a select set of &lsquo;&lsquo;known
+tags&rsquo;&rsquo; is copied when splitting.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffcp</b>(1), <b>tiffinfo</b>(1),
+<b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/man/tiffsv.1.html b/tiff/html/man/tiffsv.1.html
new file mode 100644
index 0000000..fb484b0
--- /dev/null
+++ b/tiff/html/man/tiffsv.1.html
@@ -0,0 +1,207 @@
+<!-- Creator : groff version 1.18.1 -->
+<!-- CreationDate: Fri Jul 13 17:43:20 2007 -->
+<html>
+<head>
+<meta name="generator" content="groff -Thtml, see www.gnu.org">
+<meta name="Content-Style" content="text/css">
+<title>TIFFSV</title>
+</head>
+<body>
+
+<h1 align=center>TIFFSV</h1>
+<a href="#NAME">NAME</a><br>
+<a href="#SYNOPSIS">SYNOPSIS</a><br>
+<a href="#DESCRIPTION">DESCRIPTION</a><br>
+<a href="#OPTIONS">OPTIONS</a><br>
+<a href="#NOTE">NOTE</a><br>
+<a href="#BUGS">BUGS</a><br>
+<a href="#SEE ALSO">SEE ALSO</a><br>
+
+<hr>
+<a name="NAME"></a>
+<h2>NAME</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>tiffsv &minus; save an image from the framebuffer in a
+<small>TIFF</small> file (Silicon Graphics version)</p>
+</td>
+</table>
+<a name="SYNOPSIS"></a>
+<h2>SYNOPSIS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>tiffsv</b> [ <i>options</i> ] <i>output.tif</i> [
+<i>x1 x2 y1 y2</i> ]</p>
+</td>
+</table>
+<a name="DESCRIPTION"></a>
+<h2>DESCRIPTION</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><i>tiffsv</i> saves all or part of the framebuffer in a
+file using the Tag Image File Format, Revision 6.0. By
+default, the image is saved with data samples packed
+(<i>PlanarConfiguration</i>=1), compressed with the
+Lempel-Ziv &amp; Welch algorithm (<i>Compression</i>=5), and
+with each strip no more than 8 kilobytes. These
+characteristics can be overridden, or explicitly specified
+with the options described below.</p>
+</td>
+</table>
+<a name="OPTIONS"></a>
+<h2>OPTIONS</h2>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;b</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Save the image as a greyscale image as if it were
+processed by <i>tiff2bw</i>(1). This option is included for
+compatibility with the standard <i>scrsave</i>(6D)
+program.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;c</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the compression to use for data written to the
+output file: <b>none</b> for no compression, <b>packbits</b>
+for PackBits compression, <b>jpeg</b> for baseline JPEG
+compression, <b>zip</b> for Deflate compression, and
+<b>lzw</b> for Lempel-Ziv &amp; Welch compression
+(default).</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="17%"></td>
+<td width="82%">
+<p><small>LZW</small> compression can be specified together
+with a <i>predictor</i> value. A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value of 1 forces each
+scanline to be encoded without differencing. LZW-specific
+options are specified by appending a
+&lsquo;&lsquo;:&rsquo;&rsquo;-separated list to the
+&lsquo;&lsquo;lzw&rsquo;&rsquo; option; e.g. <b>&minus;c
+lzw:2</b> for <small>LZW</small> compression with horizontal
+differencing.</p>
+</td>
+</table>
+<!-- TABS -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="5" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;p</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the planar configuration to use in writing image
+data. By default, <i>tiffsv</i> will create a new file with
+the data samples packed contiguously. Specifying <b>&minus;p
+contig</b> will force data to be written with multi-sample
+data packed together, while <b>&minus;p separate</b> will
+force samples to be written in separate planes.</p>
+</td>
+<td width="0%">
+</td>
+<tr valign="top" align="left">
+<td width="10%"></td>
+<td width="3%">
+
+<p><b>&minus;r</b></p>
+</td>
+<td width="5%"></td>
+<td width="80%">
+
+<p>Specify the number of rows (scanlines) in each strip of
+data written to the output file. By default, <i>tiffsv</i>
+attempts to set the rows/strip that no more than 8 kilobytes
+of data appear in a strip.</p>
+</td>
+<td width="0%">
+</td>
+</table>
+<a name="NOTE"></a>
+<h2>NOTE</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>Except for the use of <small>TIFF,</small> this program
+is equivalent to the standard <i>scrsave</i> program. This
+means, for example, that you can use it in conjunction with
+the standard <i>icut</i> program simply by creating a link
+called <i>scrsave</i>, or by creating a shell script called
+<i>scrsave</i> that invokes <i>tiffgt</i> with the
+appropriate options.</p>
+</td>
+</table>
+<a name="BUGS"></a>
+<h2>BUGS</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p>If data are saved compressed and in separate planes, then
+the rows in each strip is silently set to one to avoid
+limitations in the <b>libtiff</b>(3TIFF) library.</p>
+</td>
+</table>
+<a name="SEE ALSO"></a>
+<h2>SEE ALSO</h2>
+<!-- INDENTATION -->
+<table width="100%" border=0 rules="none" frame="void"
+ cols="2" cellspacing="0" cellpadding="0">
+<tr valign="top" align="left">
+<td width="8%"></td>
+<td width="91%">
+<p><b>scrsave</b>(6D) <b>pal2rgb</b>(1), <b>tiffdump</b>(1),
+<b>tiffgt</b>(1), <b>tiffinfo</b>(1), <b>tiffcp</b>(1),
+<b>tiffmedian</b>(1), <b>libtiff</b>(3TIFF)</p>
+<!-- INDENTATION -->
+<p>Libtiff library home page:
+<b>http://www.remotesensing.org/libtiff/</b></p>
+</td>
+</table>
+<hr>
+</body>
+</html>
diff --git a/tiff/html/misc.html b/tiff/html/misc.html
new file mode 100644
index 0000000..aed91a9
--- /dev/null
+++ b/tiff/html/misc.html
@@ -0,0 +1,116 @@
+<HTML>
+<HEAD>
+<TITLE>
+Acknowledgments and Other Issues
+</TITLE>
+</HEAD>
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<H1>
+<IMG SRC=images/ring.gif WIDTH=124 HEIGHT=124 ALIGN=left BORDER=1 HSPACE=6>
+Acknowledgments and Other Issues
+</H1>
+
+<P>
+Silicon Graphics has seen fit to allow us to give this work away. It
+is free. There is no support or guarantee of any sort as to its
+operations, correctness, or whatever. If you do anything useful with
+all or parts of it you need to honor the copyright notices. It would
+also be nice to be acknowledged.<p>
+
+<BR CLEAR=left>
+
+<H2>Acknowledgements</H2>
+
+The libtiff software was written by Sam Leffler while working for
+Silicon Graphics.<p>
+
+The LZW algorithm is derived from the compress program (the proper attribution
+is included in the source code). The Group 3 fax stuff originated as code
+from Jef Poskanzer, but has since been rewritten several times. The latest
+version uses an algorithm from Frank Cringle -- consult
+<TT>libtiff/mkg3states.c</TT> and <TT>libtiff/tif_fax3.h</TT> for further
+information. The JPEG support was written by Tom Lane and is dependent on the
+excellent work of Tom Lane and the Independent JPEG Group (IJG) who distribute
+their work under friendly licensing similar to this software. Joris Van Damme
+implemented the robust Old JPEG decoder (as included in libtiff since version
+3.9.0, there was another Old JPEG module in older releases, which was
+incomplete and unsuitable for many existing images of that format). JBIG
+module was written by Lee Howard and depends on JBIG library from the Markus
+Kuhn. Many other people have by now helped with bug fixes and code; a few of
+the more persistent contributors have been:
+
+<PRE>
+ Bjorn P. Brox
+ Dan McCoy
+ J.T. Conklin
+ Richard Minner
+ Frank D. Cringle
+ Richard Mlynarik
+ Soren Pingel Dalsgaard
+ Niles Ritter
+ Steve Johnson
+ Karsten Spang
+ Tom Lane
+ Peter Smith
+ Brent Roman
+ Mike Welles
+ Frank Warmerdam
+ Greg Ward
+ Stanislav Brabec
+ Roman Shpount
+ Peter Skarpetis
+ Arvan Pritchard
+ Bernt Herd
+ Joseph Orost
+ Phil Beffery
+ Ivo Penzar
+ Francois Dagand
+ Albert Chin-A-Young
+ Bruce A. Mallett
+ Dwight Kelly
+ Andrey Kiselev
+ Ross Finlayson
+ Dmitry V. Levin
+ Bob Friesenhahn
+ Lee Howard
+ Joris Van Damme
+ Tavis Ormandy
+ Richard Nolde
+</PRE>
+
+(my apology to anyone that was inadvertently not listed.)
+
+<H2>Use and Copyright</H2>
+
+<P><H5><PRE>
+Copyright (c) 1988-1997 Sam Leffler
+Copyright (c) 1991-1997 Silicon Graphics, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation for any purpose is hereby granted without fee, provided
+that (i) the above copyright notices and this permission notice appear in
+all copies of the software and related documentation, and (ii) the names of
+Sam Leffler and Silicon Graphics may not be used in any advertising or
+publicity relating to the software without the specific, prior written
+permission of Sam Leffler and Silicon Graphics.
+
+THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
+</PRE></H5>
+
+<P>
+<HR>
+
+
+Last updated: $Date: 2007/02/24 15:47:04 $
+</BODY>
+</HTML>
diff --git a/tiff/html/support.html b/tiff/html/support.html
new file mode 100644
index 0000000..f6f5d60
--- /dev/null
+++ b/tiff/html/support.html
@@ -0,0 +1,655 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html lang="en">
+<head>
+ <title>TIFF 6.0 Specification Coverage</title>
+ <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
+ <meta http-equiv="content-language" content="en">
+ <style type="text/css">
+ <!--
+ th {text-align: left; vertical-align: top; font-style: italic; font-weight: normal}
+ -->
+ </style>
+</head>
+<body lang="en" text="#000000" bgcolor="#ffffff" link="#0000ff" alink="#0000ff" vlink="#0000ff">
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td style="padding-left: 1em; padding-right: 1em"><img src="images/strike.gif" width="128" height="100" alt=""></td>
+ <td>
+ <h1>TIFF 6.0 Specification Coverage</h1>
+ <p>
+ The library is capable of dealing with images that are written to
+ follow the 5.0 or 6.0 TIFF spec. There is also considerable support
+ for some of the more esoteric portions of the 6.0 TIFF spec.
+ </p>
+ </td>
+ </tr>
+ </table>
+ <br>
+ <table border="1" cellspacing="0" cellpadding="5">
+ <tr>
+ <th>Core requirements</th>
+ <td>
+ <p>
+ Both <tt>"MM"</tt> and <tt>"II"</tt> byte orders are handled.
+ Both packed and separated planar configuration of samples.
+ Any number of samples per pixel (memory permitting).
+ Any image width and height (memory permitting).
+ Multiple subfiles can be read and written.
+ Editing is <b>not</b> supported in that related subfiles (e.g.
+ a reduced resolution version of an image) are not automatically
+ updated.
+ </p>
+ <p>
+ Tags handled: <tt>ExtraSamples</tt>, <tt>ImageWidth</tt>,
+ <tt>ImageLength</tt>, <tt>NewSubfileType</tt>, <tt>ResolutionUnit</tt>.
+ <tt>Rowsperstrip</tt>, <tt>StripOffsets</tt>, <tt>StripByteCounts</tt>,
+ <tt>XResolution</tt>, <tt>YResolution</tt>
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <th>Tiled Images</th>
+ <td><tt>TileWidth</tt>, <tt>TileLength</tt>, <tt>TileOffsets</tt>,
+ <tt>TileByteCounts</tt></td>
+ </tr>
+ <tr>
+ <th>Image Colorimetry Information</th>
+ <td><tt>WhitePoint</tt>, <tt>PrimaryChromaticities</tt>, <tt>TransferFunction</tt>,
+ <tt>ReferenceBlackWhite</tt></td>
+ </tr>
+ <tr>
+ <th>Class B for bilevel images</th>
+ <td><tt>SamplesPerPixel</tt> = 1<br>
+ <tt>BitsPerSample</tt> = 1<br>
+ <tt>Compression</tt> = 1 (none), 2 (CCITT 1D), or 32773 (PackBits)<br>
+ <tt>PhotometricInterpretation</tt> = 0 (Min-is-White), 1 (Min-is-Black)</td>
+ </tr>
+ <tr>
+ <th>Class G for grayscale images</th>
+ <td><tt>SamplesPerPixel</tt> = 1<br>
+ <tt>BitsPerSample</tt> = 4, 8<br>
+ <tt>Compression</tt> = 1 (none) 5 (LZW)<br>
+ <tt>PhotometricInterpretation</tt> = 0 (Min-is-White), 1 (Min-is-Black)</td>
+ </tr>
+ <tr>
+ <th>Class P for palette color images</th>
+ <td><tt>SamplesPerPixel</tt> = 1<br>
+ <tt>BitsPerSample</tt> = 1-8<br>
+ <tt>Compression</tt> = 1 (none) 5 (LZW)<br>
+ <tt>PhotometricInterpretation</tt> = 3 (Palette RGB)<br>
+ <tt>ColorMap</tt></td>
+ </tr>
+ <tr>
+ <th>Class R for RGB full color images</th>
+ <td><tt>SamplesPerPixel</tt> = 3<br>
+ <tt>BitsPerSample</tt> = &lt;8,8,8&gt;<br>
+ <tt>PlanarConfiguration</tt> = 1, 2<br>
+ <tt>Compression</tt> = 1 (none) 5 (LZW)<br>
+ <tt>PhotometricInterpretation</tt> = 2 (RGB)</td>
+ </tr>
+ <tr>
+ <th>Class F for facsimile</th>
+ <td>(<i>Class B tags plus...</i>)<br>
+ <tt>Compression</tt> = 3 (CCITT Group 3), 4 (CCITT Group 4)<br>
+ <tt>FillOrder</tt> = 1 (MSB), 2 (LSB)<br>
+ <tt>Group3Options</tt> = 1 (2d encoding), 4 (zero fill), 5 (2d+fill)<br>
+ <tt>ImageWidth</tt> = 1728, 2048, 2482<br>
+ <tt>NewSubFileType</tt> = 2<br>
+ <tt>ResolutionUnit</tt> = 2 (Inch), 3 (Centimeter)<br>
+ <tt>PageNumber</tt>,
+ <tt>XResolution</tt>,
+ <tt>YResolution</tt>,
+ <tt>Software</tt>,
+ <tt>BadFaxLines</tt>,
+ <tt>CleanFaxData</tt>,
+ <tt>ConsecutiveBadFaxLines</tt>,
+ <tt>DateTime</tt>,
+ <tt>DocumentName</tt>,
+ <tt>ImageDescription</tt>,
+ <tt>Orientation</tt></td>
+ </tr>
+ <tr>
+ <th>Class S for separated images</th>
+ <td><tt>SamplesPerPixel</tt> = 4<br>
+ <tt>PlanarConfiguration</tt> = 1, 2<br>
+ <tt>Compression</tt> = 1 (none), 5 (LZW)<br>
+ <tt>PhotometricInterpretation</tt> = 5 (Separated)<br>
+ <tt>InkSet</tt> = 1 (CMYK)<br>
+ <tt>DotRange</tt>,
+ <tt>InkNames</tt>,
+ <tt>DotRange</tt>,
+ <tt>TargetPrinter</tt></td>
+ </tr>
+ <tr>
+ <th>Class Y for YCbCr images</th>
+ <td><tt>SamplesPerPixel</tt> = 3<br>
+ <tt>BitsPerSample</tt> = &lt;8,8,8&gt;<br>
+ <tt>PlanarConfiguration</tt> = 1, 2<br>
+ <tt>Compression</tt> = 1 (none), 5 (LZW), 7 (JPEG)<br>
+ <tt>PhotometricInterpretation</tt> = 6 (YCbCr)<br>
+ <tt>YCbCrCoefficients</tt>,
+ <tt>YCbCrSubsampling</tt>,
+ <tt>YCbCrPositioning</tt><br>
+ (<i>colorimetry info from Appendix H; see above</i>)</td>
+ </tr>
+ <tr>
+ <th>Class "JPEG" for JPEG images (per TTN2)</th>
+ <td><tt>PhotometricInterpretation</tt> = 1 (grayscale), 2 (RGB), 5 (CMYK), 6 (YCbCr)<br>
+ (<i>Class Y tags if YCbCr</i>)<br>
+ (<i>Class S tags if CMYK</i>)<br>
+ <tt>Compression</tt> = 7 (JPEG)</td>
+ </tr>
+ </table>
+ <p>
+ In addition, the library supports some optional compression algorithms
+ that are, in some cases, of dubious value.
+ </p>
+ <table border="0" cellspacing="0" cellpadding="2">
+ <tr><th>Compression tag value</th><th>Compression algorithm</th></tr>
+ <tr><td>32766</td><td>NeXT 2-bit encoding</td></tr>
+ <tr><td>32809</td><td>ThunderScan 4-bit encoding</td></tr>
+ <tr><td>32909</td><td>Pixar companded 11-bit ZIP encoding</td></tr>
+ <tr><td>32946</td><td>PKZIP-style Deflate encoding (experimental)</td></tr>
+ <tr><td>34676</td><td>SGI 32-bit Log Luminance encoding (experimental)</td></tr>
+ <tr><td>34677</td><td>SGI 24-bit Log Luminance encoding (experimental)</td></tr>
+ </table>
+ <br>
+ <p>
+ Note that there is no support for the JPEG-related tags defined
+ in the 6.0 specification; the JPEG support is based on the post-6.0
+ proposal given in TIFF Technical Note #2.
+ </p>
+ <table>
+ <tr>
+ <td valign=top><img src="images/info.gif" width="32" height="32" alt=""></td>
+ <td>For more information on the experimental Log Luminance encoding
+ consult the materials available at
+ <a href="http://www.anyhere.com/gward/pixformat/tiffluv.html">http://www.anyhere.com/gward/pixformat/tiffluv.html</a>.</td>
+ </tr>
+ </table>
+ <br>
+ <p>
+ The following table shows the tags that are recognized
+ and how they are used by the library. If no use is indicated,
+ then the library reads and writes the tag, but does not use it internally.
+ </p>
+ <table border="1" cellspacing="0" cellpadding="5">
+ <tr>
+ <th>Tag Name</th>
+ <th>Value</th>
+ <th>R/W</th>
+ <th>Library's Use (Comments)</th>
+ </tr>
+ <tr>
+ <td><tt>NewSubFileType</tt></td>
+ <td>254</td>
+ <td>R/W</td>
+ <td>none (called <tt>SubFileType</tt> in &lt;tiff.h&gt;)</td>
+ </tr>
+ <tr>
+ <td><tt>SubFileType</tt></td>
+ <td>255</td>
+ <td>R/W</td>
+ <td>none (called <tt>OSubFileType</tt> in &lt;tiff.h&gt;)</td>
+ </tr>
+ <tr>
+ <td><tt>ImageWidth</tt></td>
+ <td>256</td>
+ <td>R/W</td>
+ <td>lots</td>
+ </tr>
+ <tr>
+ <td><tt>ImageLength</tt></td>
+ <td>257</td>
+ <td>R/W</td>
+ <td>lots</td>
+ </tr>
+ <tr>
+ <td><tt>BitsPerSample</tt></td>
+ <td>258</td>
+ <td>R/W</td>
+ <td>lots</td>
+ </tr>
+ <tr>
+ <td><tt>Compression</tt></td>
+ <td>259</td>
+ <td>R/W</td>
+ <td>to select appropriate codec</td>
+ </tr>
+ <tr>
+ <td><tt>PhotometricInterpretation</tt></td>
+ <td>262</td>
+ <td>R/W</td>
+ <td>lots</td>
+ </tr>
+ <tr>
+ <td><tt>Thresholding</tt></td>
+ <td>263</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>CellWidth</tt></td>
+ <td>264</td>
+ <td>&nbsp;</td>
+ <td>parsed but ignored</td>
+ </tr>
+ <tr>
+ <td><tt>CellLength</tt></td>
+ <td>265</td>
+ <td>&nbsp;</td>
+ <td>parsed but ignored</td>
+ </tr>
+ <tr>
+ <td><tt>FillOrder</tt></td>
+ <td>266</td>
+ <td>R/W</td>
+ <td>control bit order</td>
+ </tr>
+ <tr>
+ <td><tt>DocumentName</tt></td>
+ <td>269</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>ImageDescription</tt></td>
+ <td>270</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>Make</tt></td>
+ <td>271</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>Model</tt></td>
+ <td>272</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>StripOffsets</tt></td>
+ <td>273</td>
+ <td>R/W</td>
+ <td>data i/o</td>
+ </tr>
+ <tr>
+ <td><tt>Orientation</tt></td>
+ <td>274</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>SamplesPerPixel</tt></td>
+ <td>277</td>
+ <td>R/W</td>
+ <td>lots</td>
+ </tr>
+ <tr>
+ <td><tt>RowsPerStrip</tt></td>
+ <td>278</td>
+ <td>R/W</td>
+ <td>data i/o</td>
+ </tr>
+ <tr>
+ <td><tt>StripByteCounts</tt></td>
+ <td>279</td>
+ <td>R/W</td>
+ <td>data i/o</td>
+ </tr>
+ <tr>
+ <td><tt>MinSampleValue</tt></td>
+ <td>280</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>MaxSampleValue</tt></td>
+ <td>281</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>XResolution</tt></td>
+ <td>282</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>YResolution</tt></td>
+ <td>283</td>
+ <td>R/W</td>
+ <td>used by Group 3 2d encoder</td>
+ </tr>
+ <tr>
+ <td><tt>PlanarConfiguration</tt></td>
+ <td>284</td>
+ <td>R/W</td>
+ <td>data i/o</td>
+ </tr>
+ <tr>
+ <td><tt>PageName</tt></td>
+ <td>285</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>XPosition</tt></td>
+ <td>286</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>YPosition</tt></td>
+ <td>286</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>FreeOffsets</tt></td>
+ <td>288</td>
+ <td>&nbsp;</td>
+ <td>parsed but ignored</td>
+ </tr>
+ <tr>
+ <td><tt>FreeByteCounts</tt></td>
+ <td>289</td>
+ <td>&nbsp;</td>
+ <td>parsed but ignored</td>
+ </tr>
+ <tr>
+ <td><tt>GrayResponseUnit</tt></td>
+ <td>290</td>
+ <td>&nbsp;</td>
+ <td>parsed but ignored</td>
+ </tr>
+ <tr>
+ <td><tt>GrayResponseCurve</tt></td>
+ <td>291</td>
+ <td>&nbsp;</td>
+ <td>parsed but ignored</td>
+ </tr>
+ <tr>
+ <td><tt>Group3Options</tt></td>
+ <td>292</td>
+ <td>R/W</td>
+ <td>used by Group 3 codec</td>
+ </tr>
+ <tr>
+ <td><tt>Group4Options</tt></td>
+ <td>293</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>ResolutionUnit</tt></td>
+ <td>296</td>
+ <td>R/W</td>
+ <td>used by Group 3 2d encoder</td>
+ </tr>
+ <tr>
+ <td><tt>PageNumber</tt></td>
+ <td>297</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>ColorResponseUnit</tt></td>
+ <td>300</td>
+ <td>&nbsp;</td>
+ <td>parsed but ignored</td>
+ </tr>
+ <tr>
+ <td><tt>TransferFunction</tt></td>
+ <td>301</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>Software</tt></td>
+ <td>305</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>DateTime</tt></td>
+ <td>306</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>Artist</tt></td>
+ <td>315</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>HostComputer</tt></td>
+ <td>316</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>Predictor</tt></td>
+ <td>317</td>
+ <td>R/W</td>
+ <td>used by LZW codec</td>
+ </tr>
+ <tr>
+ <td><tt>WhitePoint</tt></td>
+ <td>318</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>PrimaryChromacities</tt></td>
+ <td>319</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>ColorMap</tt></td>
+ <td>320</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>TileWidth</tt></td>
+ <td>322</td>
+ <td>R/W</td>
+ <td>data i/o</td>
+ </tr>
+ <tr>
+ <td><tt>TileLength</tt></td>
+ <td>323</td>
+ <td>R/W</td>
+ <td>data i/o</td>
+ </tr>
+ <tr>
+ <td><tt>TileOffsets</tt></td>
+ <td>324</td>
+ <td>R/W</td>
+ <td>data i/o</td>
+ </tr>
+ <tr>
+ <td><tt>TileByteCounts</tt></td>
+ <td>324</td>
+ <td>R/W</td>
+ <td>data i/o</td>
+ </tr>
+ <tr>
+ <td><tt>BadFaxLines</tt></td>
+ <td>326</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>CleanFaxData</tt></td>
+ <td>327</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>ConsecutiveBadFaxLines</tt></td>
+ <td>328</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>SubIFD</tt></td>
+ <td>330</td>
+ <td>R/W</td>
+ <td>subimage descriptor support</td>
+ </tr>
+ <tr>
+ <td><tt>InkSet</tt></td>
+ <td>332</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>InkNames</tt></td>
+ <td>333</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>DotRange</tt></td>
+ <td>336</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>TargetPrinter</tt></td>
+ <td>337</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>ExtraSamples</tt></td>
+ <td>338</td>
+ <td>R/W</td>
+ <td>lots</td>
+ </tr>
+ <tr>
+ <td><tt>SampleFormat</tt></td>
+ <td>339</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>SMinSampleValue</tt></td>
+ <td>340</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>SMaxSampleValue</tt></td>
+ <td>341</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>JPEGTables</tt></td>
+ <td>347</td>
+ <td>R/W</td>
+ <td>used by JPEG codec</td>
+ </tr>
+ <tr>
+ <td><tt>YCbCrCoefficients</tt></td>
+ <td>529</td>
+ <td>R/W</td>
+ <td>used by <tt>TIFFReadRGBAImage</tt> support</td>
+ </tr>
+ <tr>
+ <td><tt>YCbCrSubsampling</tt></td>
+ <td>530</td>
+ <td>R/W</td>
+ <td>tile/strip size calculations</td>
+ </tr>
+ <tr>
+ <td><tt>YCbCrPositioning</tt></td>
+ <td>531</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>ReferenceBlackWhite</tt></td>
+ <td>532</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ <tr>
+ <td><tt>Matteing</tt></td>
+ <td>32995</td>
+ <td>R</td>
+ <td>none (obsoleted by <tt>ExtraSamples</tt> tag)</td>
+ </tr>
+ <tr>
+ <td><tt>DataType</tt></td>
+ <td>32996</td>
+ <td>R</td>
+ <td>none (obsoleted by <tt>SampleFormat</tt> tag)</td>
+ </tr>
+ <tr>
+ <td><tt>ImageDepth</tt></td>
+ <td>32997</td>
+ <td>R/W</td>
+ <td>tile/strip calculations</td>
+ </tr>
+ <tr>
+ <td><tt>TileDepth</tt></td>
+ <td>32998</td>
+ <td>R/W</td>
+ <td>tile/strip calculations</td>
+ </tr>
+ <tr>
+ <td><tt>StoNits</tt></td>
+ <td>37439</td>
+ <td>R/W</td>
+ <td>&nbsp;</td>
+ </tr>
+ </table>
+ <p>
+ The <tt>Matteing</tt> and <tt>DataType</tt>
+ tags have been obsoleted by the 6.0
+ <tt>ExtraSamples</tt> and <tt>SampleFormat</tt> tags.
+ Consult the documentation on the
+ <tt>ExtraSamples</tt> tag and Associated Alpha for elaboration. Note however
+ that if you use Associated Alpha, you are expected to save data that is
+ pre-multipled by Alpha. If this means nothing to you, check out
+ Porter &amp; Duff's paper in the '84 SIGGRAPH proceedings: "Compositing Digital
+ Images".
+ </p>
+ <p>
+ The <tt>ImageDepth</tt>
+ tag is a non-standard, but registered tag that specifies
+ the Z-dimension of volumetric data. The combination of <tt>ImageWidth</tt>,
+ <tt>ImageLength</tt>, and <tt>ImageDepth</tt>,
+ defines a 3D volume of pixels that are
+ further specified by <tt>BitsPerSample</tt> and
+ <tt>SamplesPerPixel</tt>. The <tt>TileDepth</tt>
+ tag (also non-standard, but registered) can be used to specified a
+ subvolume "tiling" of a volume of data.
+ </p>
+ <p>
+ The Colorimetry, and CMYK tags are additions that appear in TIFF 6.0.
+ Consult the TIFF 6.0 specification included in the <b>doc</b> directory
+ and <a href="document.html">online</a>.
+ </p>
+ <p>
+ The JPEG-related tag is specified in
+ <a href="TIFFTechNote2.html">TIFF Technical Note #2</a> which defines
+ a revised JPEG-in-TIFF scheme (revised over that appendix that was
+ part of the TIFF 6.0 specification).
+ </p>
+ <hr>
+ <p>
+ Last updated: $Date: 2005/12/28 06:53:18 $
+ </p>
+</body>
+</html>
+
diff --git a/tiff/html/tools.html b/tiff/html/tools.html
new file mode 100644
index 0000000..b1a757e
--- /dev/null
+++ b/tiff/html/tools.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta name="generator" content=
+"HTML Tidy for Solaris (vers 12 April 2005), see www.w3.org">
+<title>TIFF Tools Overview</title>
+</head>
+<body bgcolor="white">
+<h1><font face="Arial, Helvetica, Sans"><img src="images/quad.jpg"
+width="144" height="108" align="left" border="1" hspace="6"> TIFF
+Tools Overview</font></h1>
+<p>This software distribution comes with a small collection of
+programs for converting non-TIFF format images to TIFF and for
+manipulating and interrogating the contents of TIFF images. Several
+of these tools are useful in their own right. Many of them however
+are more intended to serve as programming examples for using the
+TIFF library.</p>
+<h3>Device-dependent Programs</h3>
+There are two device-dependent programs that serve as simple
+examples for writing programs to display and save TIFF images.
+<table border cellpadding="3">
+<tr>
+<td valign="top" width="10%">
+<tt><a href="man/tiffgt.1.html">tiffgt</a>&nbsp;&nbsp;&nbsp;&nbsp;</tt></td>
+<td>Display the contents of one or more TIFF images using OpenGL.
+The software makes extensive use of the <tt>TIFFRGBAImage</tt>
+facilities described elsewhere.</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffsv.1.html">tiffsv</a></tt></td>
+<td>A program to save all or part of a screen dump on a Silicon
+Graphics system. As for <tt>tiffgt</tt> this code, while written to
+use the IRIS GL, can be easily tailored to other devices.</td>
+</tr>
+</table>
+<h3>Device-independent Programs</h3>
+The remaining programs should be device-independent:
+<table border cellpadding="3">
+<tr>
+<td valign="top" width="10%"><tt><a href="man/bmp2tiff.1.html">bmp2tiff</a></tt></td>
+<td>Convert BMP images to TIFF</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/fax2ps.1.html">fax2ps</a></tt></td>
+<td>Convert a Group 3- or Group 4- compressed TIFF to PostScript
+that is significantly more compressed than is generated by
+<tt>tiff2ps</tt> (unless <tt>tiff2ps</tt> writes PS Level II)</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/fax2tiff.1.html">fax2tiff</a></tt></td>
+<td>Convert raw Group 3 or Group 4 facsimile data to TIFF</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/gif2tiff.1.html">gif2tiff</a></tt></td>
+<td>A quick hack that converts GIF 87a (old) format images to TIFF</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/pal2rgb.1.html">pal2rgb</a></tt></td>
+<td>Convert a Palette-style image to a full color RGB image by
+applying the colormap</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/ppm2tiff.1.html">ppm2tiff</a></tt></td>
+<td>A quick hack that converts 8-bit PPM format images to TIFF</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/ras2tiff.1.html">ras2tiff</a></tt></td>
+<td>A quick hack that converts Sun rasterfile format images to TIFF
+-- it's less than complete</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/raw2tiff.1.html">raw2tiff</a></tt></td>
+<td>Create a TIFF file from raw data</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/rgb2ycbcr.1.html">rgb2ycbcr</a></tt></td>
+<td>Convert an RGB, grayscale, or bilevel TIFF image to a YCbCr
+TIFF image; it's mainly provided for testing</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/sgi2tiff.1.html">sgi2tiff</a></tt></td>
+<td>A program to convert SGI image files to TIFF. This program is
+only useful on SGI machines as it uses <tt>-limage</tt>.</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/thumbnail.1.html">thumbnail</a></tt></tt></td>
+<td>Copy a bilevel TIFF to one that includes 8-bit greyscale
+"thumbnail images" for each page; it is provided as an example of
+how one might use the <tt>SubIFD</tt> tag (and the library support
+for it)</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiff2bw.1.html">tiff2bw</a></tt></td>
+<td>A simple program to convert a color image to grayscale</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiff2pdf.1.html">tiff2pdf</a></tt></td>
+<td>Convert TIFF images to PDF</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiff2ps.1.html">tiff2ps</a></tt></td>
+<td>Convert TIFF images to PostScript</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiff2rgba.1.html">tiff2rgba</a></tt></td>
+<td>Convert a TIFF image to RGBA color space</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffcmp.1.html">tiffcmp</a></tt></td>
+<td>Compare the contents of two TIFF files (it does not check all
+the directory information, but does check all the data)</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffcp.1.html">tiffcp</a></tt></td>
+<td>Copy, concatenate, and convert TIFF images (e.g. switching from
+Compression=5 to Compression=1)</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffcrop.1.html">tiffcrop</a></tt></td>
+<td>Provides selection of images from within one or more multi-image
+TIFF files, with orthogonal rotation, mirroring, cropping, and
+extraction of multiple sections and exporting to one or more files.
+It extends the functionality of tiffcp to support additional bit
+depths in strips and tiles and enhances the selection capabilities of
+tiffsplit. Bilevel images can be inverted and images may be split into
+segments to fit on multiple /pages/ (standard paper sizes), plus other
+functions described in the tiffcrop man page</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffdither.1.html">tiffdither</a></tt></td>
+<td>Dither a b&amp;w image into a bilevel image (suitable for use
+in creating fax files)</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffdump.1.html">tiffdump</a></tt></td>
+<td>Display the verbatim contents of the TIFF directory in a file
+(it's very useful for debugging bogus files that you may get from
+someone that claims they support TIFF)</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffinfo.1.html">tiffinfo</a></tt></td>
+<td>Display information about one or more TIFF files.</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffmedian.1.html">tiffmedian</a></tt></td>
+<td>A version of Paul Heckbert's median cut program that reads an
+RGB TIFF image, and creates a TIFF palette file as a result</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffset.1.html">tiffset</a></tt></td>
+<td>Set a field in a TIFF header</td>
+</tr>
+<tr>
+<td valign="top" width="10%"><tt><a href="man/tiffsplit.1.html">tiffsplit</a></tt></td>
+<td>Create one or more single-image files from a (possibly)
+multi-image file</td>
+</tr>
+</table>
+<p>Check out the manual pages for details about the above
+programs.</p>
+<hr>
+Last updated: $Date: 2009-10-28 22:13:58 $
+</body>
+</html>
diff --git a/tiff/html/v3.4beta007.html b/tiff/html/v3.4beta007.html
new file mode 100644
index 0000000..c535d27
--- /dev/null
+++ b/tiff/html/v3.4beta007.html
@@ -0,0 +1,112 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta007
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta007<BR>
+<B>Previous Version</B>: v3.4beta004<BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#port">Changes in the portability support</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>bit order was corrected for Pentium systems
+<LI>a new define, <TT>HOST_BIGENDIAN</TT>, was added for code that
+ wants to statically use information about native cpu byte order
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>the G3/G4 decoder was replaced by a new one that is faster and
+ has smaller state tables
+<LI>Niles Ritter's client tag extension hooks were added
+<LI>a new routine <TT>TIFFCurrentDirOffset</TT> was added for
+ applications that want to find out the file offset of a TIFF directory
+<LI>the calculation of the number of strips in an image was corected
+ for images with certain esoteric configurations
+<LI>a potential memory leak (very unlikely) was plugged
+<LI>the <TT>TIFFReadRGBAImage</TT> support was completely rewritten
+ and new, more flexible support was added for reading images into
+ a fixed-format raster
+<LI>YCbCr to RGB conversion done in the <TT>TIFFReadRGBAImage</TT> support
+ was optimized
+<LI>a bug in JPEG support calculation of strip size was corrected
+<LI>the LZW decoder was changed to initialize the code table to zero
+ to lessen potential problems that arise when invalid data is decoded
+<LI><B>tiffcomp.h</B> is now aware of OS/2
+<LI>some function prototypes in <B>tiffio.h</B> and <B>tiffiop.h</B>
+ that contained parameter
+ names have been changed to avoid complaints from certain compilers
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="port"><B><FONT SIZE=+3>C</FONT>HANGES IN THE PORTABILITY SUPPORT:</B></A>
+
+<UL>
+<LI><B>Makefile.in</B> has been corrected to use the parameters
+ chosen by the configure script
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI><TT>fax2ps</TT> has been rewritten and moved over from the user
+ contributed software
+<LI>an uninitialized variable in <TT>pal2rgb</TT> has been fixed
+<LI><TT>ras2tiff</TT> now converts 24-bit RGB raster data so that
+ samples are written in the proper order
+<LI><TT>tiff2ps</TT> has been updated to include fixes
+ and enhancements from Alberto Accomazzi
+<LI><TT>tiffcp</TT> now has a <TT>-o</TT> option to select a directory
+ by file offset
+<LI><TT>tiffinfo</TT> is now capable of displaying the raw undecoded
+ image data in a file
+<LI><TT>tiffgt</TT> has been rewritten to use the new <TT>TIFFRGBAImage</TT>
+ support and to handle multiple files
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta016.html b/tiff/html/v3.4beta016.html
new file mode 100644
index 0000000..22f185f
--- /dev/null
+++ b/tiff/html/v3.4beta016.html
@@ -0,0 +1,122 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta016
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta016<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta007.html>v3.4beta007</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#man">Changes in the manual pages</A>
+<LI><A HREF="#html">Changes in the documentation</A>
+<LI><A HREF="#contrib">Changes in contributed software</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>support was added for configuring the Deflate codec
+<LI>support was added for the HTML documentation
+<LI>codecs that are not configured for inclusion in the library
+ are no longer compiled
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>support was added for registering new codecs external to the library
+ and for overriding the codecs that are builtin to the library
+<LI>emulation support for the old <TT>DataType</TT> tag was improved
+<LI>suppport was added for the <TT>SMinSampleValue</TT>
+ and <TT>SMaxSampleValue</TT> tags
+<LI>the library no longer ignores <TT>TileWidth</TT> and <TT>TileLength</TT>
+ tags whose values are not a multiple of 16 (per the spec); this
+ permits old, improperly written, images to be read
+<LI>the support for the <TT>Predictor</TT> tag was placed in a reusable
+ module so that it can be shared by multiple codecs
+<LI>experimental compression support was added for the Deflate algorithm
+ (using the freely available zlib package)
+<LI>a new routine, <TT>TIFFWriteBufferSetup</TT> was added a la the
+ routine <TT>TIFFReadBufferSetup</TT>
+<LI>the DSO version of the library is now statically linked with the
+ JPEG and Deflate libraries; this means applications that link against
+ the DSO do not also need to link against these ancillary libraries
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI>all the tools now use common code to process compress-oriented arguments
+<LI><TT>tiffdump</TT> should now compile on a Macintosh with MPW
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="man"><B><FONT SIZE=+3>C</FONT>HANGES IN THE MANUAL PAGES:</B></A>
+
+<UL>
+<LI>everything was updated
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="html"><B><FONT SIZE=+3>C</FONT>HANGES IN THE DOCUMENTATION:</B></A>
+
+<UL>
+<LI>everything was updated
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN CONTRIBUTED SOFTWARE:</B></A>
+
+<UL>
+<LI><B>contrib/dbs/xtiff</B> was made to compile
+<LI><B>contrib/mac-mpw</B> is new support for compiling the software on
+ a Macintosh under MPW; consult <A HREF=build.html#Mac>the documentation</A>
+ for details
+<LI><B>contrib/tags</B> is information on how to use the tag extenion
+ facilities; consult
+ <A HREF=../contrib/tags/README>contrib/tags/README</A> for details
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta018.html b/tiff/html/v3.4beta018.html
new file mode 100644
index 0000000..ac1877f
--- /dev/null
+++ b/tiff/html/v3.4beta018.html
@@ -0,0 +1,84 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta018
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta018<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta016.html>v3.4beta016</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>configure now recognizes IRIX 6.x systems
+<LI>configure now uses <TT>ENVOPTS</TT> when searching for an ANSI
+ C compiler; this fixes a problem configuring the software under
+ HP/UX with the native C compiler
+<LI>configure now correctly recognizes memory-mapped files are supported
+ under AIX
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI><TT>make install</TT> now properly installs the include files
+<LI>some portability fixes from Bjorn Brox
+<LI>the G3/G4 codec now warns about decoded rows that are longer than
+ the image/tile width
+<LI>changes from Frank Cringle to make the library work with the
+ gcc-specific bounds checking software
+<LI>miscellaneous fixes to <TT>TIFFPrintDirectory</TT>
+<LI>bug fix to correct a problem where <TT>TIFFWriteRawStrip</TT>
+ could not be used to automatically grow an image's length
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI>fixes from Frank Cringle to update <TT>fax2tiff</TT>
+<LI>portability fixes to <TT>tiff2bw</TT> and <TT>tiffcmp</TT>
+<LI><TT>tiffdump</TT> now uses the byte swapping routines in the library
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta024.html b/tiff/html/v3.4beta024.html
new file mode 100644
index 0000000..25a3347
--- /dev/null
+++ b/tiff/html/v3.4beta024.html
@@ -0,0 +1,139 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta024
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta024<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta018.html>v3.4beta018</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#man">Changes in the manual pages</A>
+<LI><A HREF="#contrib">Changes in the contributed software</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>It is now possible to setup the software to build only the
+ library; configure reconizes this is the intent when the
+ <B>VERSION</B>, <B>tiff.alpha</B>, and <B>tif_version.c</B>
+ files are in the local directory (i.e. ``.'')
+<LI>configure no longer tries to setup HTML materials
+<LI>include file directories needed in building the library are now
+ specified with a <TT>DIRS_LIBINC</TT> config parameter
+<LI>configure no longer checks for alternate compilers if <TT>CC</TT>
+ is set; if the specified compiler is not found or is not appropriate
+ the configuration procedure aborts
+<LI>the <B>port.h</B> file generated by configure is now used only by
+ the library and as such as have been moved to the <B>libtiff</B>
+ directory
+<LI>there is beginning support for building DSO's on systems other than IRIX
+<LI>configure now verifies the JPEG and zlib directory pathnames by
+ checking for well-known include files in these directories
+<LI>configure no longer creates the <B>dist</B> directory needed only
+ on SGI machines (for building SGI binary distributions)
+<LI>a bug was fixed whereby configure would incorrectly set
+ <TT>ENVOPTS</TT> when building the software with gcc under AIX
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>two new typedefs were added to <B>tiff.h</TT>: <TT>int8</TT>
+ and <TT>uint8</TT> for signed and unsigned 8-bit quantities,
+ respectively; these are currently used only by
+ programs in the <B>tools</B> directory
+<LI>the <TT>BadFaxLines</TT>, <TT>CleanFaxData</TT>, and
+ <TT>ConsecutiveBadFaxLines</B> tags are now supported with
+ Group 4 compression
+<LI>byte order is now correctly identified on 64-bit machines
+<LI>a bug was fixed in the PackBits decoder where input data would
+ appear short when a no-op run was present
+<LI>a bug was fixed in calculations with very wide strips
+<LI><TT>TIFFWriteEncodedStrip</TT> and <TT>TIFFWriteRawStrip</TT>
+ were extended to support dynamically growing the number of
+ strips in an image (must set <TT>ImageLength</TT> prior to
+ making calls though)
+<LI><TT>TIFFDefaultTileSize</TT> now rounds tile width and height
+ up to a multiple of 16 pixels, as required by the TIFF 6.0 specification
+<LI>the file <B>version.h</B> is now built by a new <B>mkversion</B>
+ program; this was done for portability to non-UNIX systems
+<LI>support was added for the Acorn RISC OS (from Peter Greenham)
+<LI>the builtin codec table is now made <TT>const</TT> when compiling
+ under VMS so that <B>libtiff</B> can be built as a shared library
+<LI>support for the PowerPC Mac (from Ruedi Boesch)
+<LI>support for Window NT/Window 95 (from Scott Wagner)
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI>the tools no longer include <B>port.h</B>
+<LI>various portability fixes; mostly to eliminate implicit assumptions
+ about how long <TT>int32</TT> data types are
+<LI>PostScript Level II additions to <TT>tiff2ps</TT> from Bjorn Brox
+<LI><TT>sgi2tiff</TT> now handles RGBA images
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="man"><B><FONT SIZE=+3>C</FONT>HANGES IN THE MANUAL PAGES:</B></A>
+
+<UL>
+<LI>the documentation has been updated to reflect the current state of
+ the software
+<LI>some routines have been moved to different manual pages
+ to group like-routines together
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIBUTED SOFTWARE:</B></A>
+
+<UL>
+<LI>support was added for the Acorn RISC OS (from Peter Greenham)
+<LI>support for Windows NT/Windows 95 contributed for a previous
+ version of this software was sort of incorporated (it's broken
+ right now) (from Scott Wagner)
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta028.html b/tiff/html/v3.4beta028.html
new file mode 100644
index 0000000..ff7ef69
--- /dev/null
+++ b/tiff/html/v3.4beta028.html
@@ -0,0 +1,146 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta028
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta028<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta024.html>v3.4beta024</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#man">Changes in the manual pages</A>
+<LI><A HREF="#contrib">Changes in the contributed software</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>a <TT>-noninteractive</TT> flag was added to configure to
+ control whether or not it prints and prompts for configuration information
+<LI>various typos and fixes were made in configure for the the
+ library-only build support (this and other configure fixes from
+ Richard Mlynarik <A HREF=mailto:mly@adoc.xerox.com>&lt;mly@adoc.xerox.com&gt;</A>)
+<LI>bugs were fixed in the handling of pathnames supplied for external
+ packages; e.g. <TT>DIR_JPEG</TT>
+<LI>the handling of <TT>SETMAKE</TT> is now done properly
+<LI>the default prototype function declaration for <TT>pow</TT> was corrected
+<LI>a bug was fixed in <B>libtiff/Makefile.in</B> that caused installation
+ to fail on systems without DSO support
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>Acorn RISC O/S support that was accidentally left out of the
+ left out of the previous distribution is present (from Peter Greenham)
+<LI>complaints about unknown and/or unsupported codecs have been
+ delayed until they are invoked; this permits applications to open
+ images and look at tags even if the image data is compressed with
+ an unknown/unsupported compression scheme
+<LI>bugs in handling unknown tags have been corrected; applications
+ that use multiple codecs, each with codec-specific tags, no longer
+ generate confusing error messages
+<LI>a missing pseudo-tag definition in the CCITT G3 codec was fixed
+ (this problem caused core dumps in the <TT>tiffcp</TT> program)
+<LI>pseudo-tags are now treated specially; they are always considered
+ to be set (i.e. they do not use bits in the <TT>FIELD_*</TT> bit-vectors).
+<LI>the use of strip chopping can now be controlled on a per-file basis
+ through a mode parameter supplied when opening a file (``C'' to
+ enable strip chopping and ``c'' to disable)
+<LI>two bugs were fixed in the writing of opposite-endian byte-order
+ files
+<LI>support was added for three new fax-related tags registered to
+ SGI: FaxRecvParams, FaxRecvTime, and FaxSubAddress
+<LI>the bit order of image data read and written can now be controlled
+ on a per-file basis through a mode parameter supplied when opening
+ a file (``B'' to force MSB2LSB bit order, ``L'' for LSB2MSB bit
+ order, and ``H'' for the bit order of the native CPU)
+<LI>the byte order of image and tag data written to newly-created files
+ can now be controlled on a per-file basis through a mode parameter
+ supplied when openening a file (``b'' to force Big-Endian byte order
+ and ``l'' to force Little-Endian byte order)
+<LI>the use memory-mapped files for images opened read-only can now
+ be controlled on a per-file basis through a mode parameter supplied
+ when opening a file (``M'' to enable use of memory-mapped files
+ and ``m'' to disable use)
+<LI>the use of the <TT>WIN32</TT> define in <B>tiffiop.h</B> has
+ been replaced by <TT>__WIN32__</TT>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI><TT>fax2ps</TT> now does a <TT>save</TT> and <TT>restore</TT>
+ around each page of PostScript; this fixes a problem with VM
+ overflow when printing a many-page document on some printers
+<LI>a bug in the handling of 3-channel images by <TT>ras2tiff</TT>
+ was fixed
+<LI><TT>tiffcp</TT> has new options to control the byte order of
+ newly created files: <B>-B</B> for Big-Endian byte order, <B>-L</B>
+ for Little-Endian byte order; a <B>-M</B> option to disable the
+ use of memory-mapped files, and a <B>-C</B> option to disable the
+ use of strip chopping
+<LI>bugs were fixed in <TT>tiffcp</TT>'s handling of codec-specific tags
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="man"><B><FONT SIZE=+3>C</FONT>HANGES IN THE MANUAL PAGES:</B></A>
+
+<UL>
+<LI>the <TT>TIFFOpen</TT> page has been updated to reflect the new
+ optional open mode parameters
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIBUTED SOFTWARE:</B></A>
+
+<UL>
+<LI><B>contrib/win95</B> contains information and code from Philippe Tenenhaus
+ <A HREF=mailto:100423.3705@compuserve.com>&lt;100423.3705@compuserve.com&gt;</A>
+ about using the software under Windows 95
+<LI><B>contrib/winnt</B> contains information and code from Dave Dyer
+ <A HREF=mailto:ddyer@triple-i.com>&lt;ddyer@triple-i.com&gt;</A>
+ about using the software under Windows NT
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta029.html b/tiff/html/v3.4beta029.html
new file mode 100644
index 0000000..f2a3d3f
--- /dev/null
+++ b/tiff/html/v3.4beta029.html
@@ -0,0 +1,86 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta029
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta029<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta028.html>v3.4beta028</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#contrib">Changes in the contributed software</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI><B>configure</B> now relativizes pathname references given in
+ <TT>-L</TT> options (as frequently specified when configuring
+ ancillary packages)
+<LI>problems related to configuring the software on Ultrix 4.4 have
+ been corrected
+<LI>the shell to use in Makefiles and scripts can now be set with the
+ <TT>SCRIPT_SH</TT> configuration parameter
+<LI>comments in <B>config.site</B> now correctly indicate how to setup the
+ use of ancillary packages
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>mods for building the software on a Mac using the
+ MetroWerks CodeWarrior compilers
+<LI>a bug in the CCITT T.4/T.6 decoder was fixed where the last codeword in
+ a strip/tile might not be decoded; this was seen only when decoding
+ multi-strip images
+<LI>a bug in the CCITT RLE codecs was fixed whereby the pseudo tags were not
+ being properly registered
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIBUTED SOFTWARE:</B></A>
+
+<UL>
+<LI><B>contrib/mac-cw</B> contains information and code from Niles Ritter
+ <A HREF=mailto:ndr@tazboy.jpl.nasa.gov>&lt;ndr@tazboy.jpl.nasa.gov&gt;</A>
+ about building the software with the MetroWerks CodeWarrior compilers
+ on Macintosh systems
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta031.html b/tiff/html/v3.4beta031.html
new file mode 100644
index 0000000..d5b7eac
--- /dev/null
+++ b/tiff/html/v3.4beta031.html
@@ -0,0 +1,94 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta031
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta031<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta029.html>v3.4beta029</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#man">Changes in the manual pages</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI><B>configure</B> now captures significantly more information
+ in the <B>config.log</B> file and provides more information when
+ it is unable to setup a configuration
+<LI>support was added for building shared libraries on more systems:
+ AIX, HPUX, Solaris, and Linux.
+<LI>a new configuration parameter <TT>LIBCOPTS</TT> was added for
+ passing arguments to the C compiler to use when building only
+ the library; this is part of the enhanced support for building
+ shared libraries
+<LI>include files for optional packages that reside in <B>/usr/include</B>
+ are now handled correctly
+<LI>build trees may now be configured using either relative or absolute
+ pathnames to the source distribution
+<LI>several new configuration parameters were added, mainly for building
+ shared libraries: <TT>DIST_MAJOR</TT>, <TT>DIST_MINOR</TT>,
+ <TT>DIST_ALPHA</TT>, and <TT>DSOSUF_VERSION</TT>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>the Deflate support has been revised: it requires version 0.99 of
+ the zlib software distribution, <B>the output format has changed and
+ is incompatible with previous versions of this library</B> (each
+ strip now includes a header read and written by the zlib library)
+<LI>the codec name printed by the TIFFPrintDirectory routine is now
+ taken from the codec table instead of from a builtin table; this means
+ that application-defined codecs are handled correctly
+<LI>a new symbol was added that contains the library version number;
+ this can be used to do a compile-time compatibility check of the
+ library version
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="man"><B><FONT SIZE=+3>C</FONT>HANGES IN THE MANUAL PAGES:</B></A>
+
+<UL>
+<LI>the creation and installation of manual pages was redone; it now
+ implements the documented ``configuration scheme''
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta032.html b/tiff/html/v3.4beta032.html
new file mode 100644
index 0000000..bc14ef3
--- /dev/null
+++ b/tiff/html/v3.4beta032.html
@@ -0,0 +1,90 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta032
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta032<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta031.html>v3.4beta031</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contributed software</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>various fixups and subtle improvements to <B>configure</B>
+ from Richard Mlynarik
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>a new codec from Pixar designed for high-resolution color images;
+ note that this codec is not configured by default
+<LI>a bug fix for reading tags with a single <TT>FLOAT</TT> value
+<LI>change to the <TT>TIFFGetField</TT> calling convention:
+ a tag that has a single value of
+ type <TT>DOUBLE</TT> is now retrieved by passing a
+ ``<TT>double*</TT>'' instead of a
+ ``<TT>double**</TT>'' (this change makes the handling of tags with
+ <TT>DOUBLE</TT> values identical to the handling of tags with
+ <TT>FLOAT</TT> values)
+<LI>fix to VMS support for the handling of floating point values
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI><B>tiffdump</B> now handles tags with <TT>FLOAT</TT> and <TT>DOUBLE</TT>
+ values
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIBUTED SOFTWARE:</B></A>
+
+<UL>
+<LI>updates to the Acorn OS support from Peter Greenham
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta033.html b/tiff/html/v3.4beta033.html
new file mode 100644
index 0000000..8d8345a
--- /dev/null
+++ b/tiff/html/v3.4beta033.html
@@ -0,0 +1,82 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta033
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta033 (aka the v3.4 release)<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta032.html>v3.4beta032</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contributed software</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>support was added for building the library as a DSO under OSF/1
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>fixes to the Pixar codec
+<LI>portability mods for VMS
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI>fixes to <B>gif2tiff</B> and <B>ppm2tiff</B> for building under MS/DOS
+<LI>portability mods to <B>fax2ps</B> and <B>ycbcr</B> for VMS
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIBUTED SOFTWARE:</B></A>
+
+<UL>
+<LI>a new package from Alexander Lehmann
+ for building the library and tools under MS/DOS with DJGPP v2
+<LI>updated VMS support from Karsten Spang
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta034.html b/tiff/html/v3.4beta034.html
new file mode 100644
index 0000000..77d9863
--- /dev/null
+++ b/tiff/html/v3.4beta034.html
@@ -0,0 +1,68 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta034
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta034<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta033.html>v3.4beta033</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>support was added for building the library as a DSO under NetBSD
+<LI>a bug was fixed in the DSO support for Linux
+<LI>the handling of version strings has changed slightly to simplify parsing
+<LI>a new parameter, <TT>TIFFLIBREF</TT>, was added to control how the
+ library is referenced when linking programs in the <B>tools</B> directory
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>DSO creation under Solaris now forces the DSO name with a <TT>-h</TT> option
+<LI>the interface to the <B>mkversion</B> program was changed
+ to eliminate the need to parse files
+<LI>a bug was fixed in the EOL-detection logic of the T.4/T.6 decoder
+<LI>ANSI IT8 TIFF/IT tag definitions were added to <B>tiff.h</B>
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta035.html b/tiff/html/v3.4beta035.html
new file mode 100644
index 0000000..22fb2b8
--- /dev/null
+++ b/tiff/html/v3.4beta035.html
@@ -0,0 +1,63 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta035
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta035<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta034.html>v3.4beta034</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>support was added installing the HTML documentation
+<LI>support was added for building the library as a DSO under FreeBSD
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>the interface to the <B>mkversion</B> program was restored to
+ the form used prior to v3.4beta034
+<LI>several portability problems for 16-bit systems were fixed
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.4beta036.html b/tiff/html/v3.4beta036.html
new file mode 100644
index 0000000..e36754d
--- /dev/null
+++ b/tiff/html/v3.4beta036.html
@@ -0,0 +1,117 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.4beta036
+</TITLE>
+</HEAD>
+
+<BODY>
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.4beta036<BR>
+<B>Previous Version</B>: <A HREF=v3.4beta035.html>v3.4beta035</A><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.sgi.com/graphics/tiff">ftp.sgi.com (192.48.153.1), directory graphics/tiff</A><BR>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<LI>support was added for building the library as a DSO under HP-UX with
+ the native C compiler
+<LI>tools are now built with explicit pathnames for the DSO under IRIX,
+ Solaris, and Linux
+<LI>DSO configuration support for Linux was changed to require that
+ <B>libc.so</B> only be readable (not executable)
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+<LI>support was add for ICC: <TT>NumberOfInks</TT>, and <TT>ICCProfile</TT>
+<LI>a memory leak caused by doing <TT>TIFFSetDirectory(0)</TT> was fixed
+<LI>a bug was fixed whereby certain multi-directory files were not
+ properly handled when accessed by mapping the data into memory
+<LI>the strip chopping support is now always compiled
+ into the library with the default usage controlled by a
+ <TT>STRIPCHOP_DEFAULT</TT> configuration parameter
+<LI>the strip chopping support no longer chops tiled images
+<LI>all static strings are now const--for shared libraries
+<LI>the logic for estimating the strip size of images without
+ a <TT>StripByteCounts</TT> tag was improved by handling
+ <TT>PlanarContig</TT> images differently from <TT>PlanarSeparate</TT>
+<LI>a bug was fixed in the G3 codec when converting the Y resolution
+ of data specified in metric units
+<LI>a bug was fixed in the G3/G4 decoder for data where lines terminate
+ with a v0 code
+<LI>the <TT>TIFFRGBAImage</TT> support was changed to scale 16-bit colormap
+ entries more conservatively to avoid problems with applications
+ that do not generate fully saturated pixel values
+<LI>the LZW decoder was changed to use a more conservative scheme when
+ bounds checking the hash table array; this avoids pitfalls with
+ systems that load objects into memory in unusual locations
+<LI>a bug was fixed in <TT>TIFFPrintDirectory</TT>'s handling of the
+ <TT>InkNames</TT> tag
+<LI><TT>TIFFPrintDirectory</TT> now understands <TT>NumberOfInks</TT>
+ and ICC-related tags
+<LI>the routines for reading image data now provide more useful information
+ when a read error is encountered
+<LI>support was added for compiling with Microsoft Visual C++ 4.0
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI>a bug was fixed in <B>pal2rgb</B>'s colormap handling
+<LI><B>tiff2ps</B> now includes John Wehle's changes for maintaining
+ the aspect ratio
+ of images when scaling and for honoring the deadzone on a page when
+ generating PostScript Level II
+<LI><B>tiff2ps</B> does a better job guarding against the mishandling
+ of greyscale images
+<LI><B>tiff2ps</B> now correctly converts X- and Y-resolution values
+ specified in metric units
+<LI><B>tiffdump</B> has a new <TT>-m</TT> option to control the maximum
+ number of indirect
+ data values printed for a tag (by default 24)
+<LI><B>tiffdump</B> understands several new tags
+<LI><B>tiffdump</B> now shows any terminating null in ASCII strings
+<LI><B>tiffinfo</B> now suppresses strip chopping when interpreting an image;
+ a new <TT>-z</TT> option has been added to enable strip chopping
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+<ADDRESS>
+<A HREF="sam.html">Sam Leffler</A> / <A HREF="mailto:sam@engr.sgi.com">sam@engr.sgi.com</A>
+Last updated $Date: 1999/08/09 20:21:21 $.
+</ADDRESS>
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.5.1.html b/tiff/html/v3.5.1.html
new file mode 100644
index 0000000..0c88de9
--- /dev/null
+++ b/tiff/html/v3.5.1.html
@@ -0,0 +1,75 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.5.1
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.5.1<BR>
+<B>Previous Version</B>: v3.4beta037<BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.onshore.com/pub/libtiff">ftp.onshore.com, directory graphics/tiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff/>http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <LI> <em> None of consequence </em>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+
+<UL>
+<LI> Support was added for IPTC Newsphoto metadata (TIFFTAGE_IPTCNEWSPHOTO)
+<LI> Support was added for photoshop caption handling (TIFFTAG_PHOTOSHOP)
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<LI> <A HREF=mailto:billr@corbis.com>Bill Radcliffe's</a> iptcutil was
+added to the "contrib" subdirectory . It can convert an IPTC binary
+blob to ASCII text and vice-versa. The blob itself can be extracted
+from or added to an image with the <A
+href=http://www.ImageMagick.org/>ImageMagick</a> convert(1)
+utility.
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2006/01/03 01:42:30 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.5.2.html b/tiff/html/v3.5.2.html
new file mode 100644
index 0000000..71b486a
--- /dev/null
+++ b/tiff/html/v3.5.2.html
@@ -0,0 +1,108 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.5.2
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.5.2<BR>
+<B>Previous Version</B>: <A HREF=v3.5.1.html>v3.5.1</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.onshore.com/pub/libtiff">ftp.onshore.com, directory graphics/tiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff/">http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <LI> Corrected alpha versioning.
+
+ <LI> Removed distinction between alpha and release targets in Makefile.in.
+
+ <LI> Added release.stamp target, which tags cvs tree, and updates
+ "RELEASE-DATE"
+
+ <LI> Added releasediff target, which diffs tree with source as of
+ date in "RELEASE-DATE"
+
+ <LI>Ticked up version to 3.5.2 (alpha 01 -- but I think we'll moving
+ away from alpha/non-alpha distinctions).
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+
+<UL>
+ <LI> Added IRIX/gcc, and OSF/1 4.x support on behalf of
+ Albert Chin-A-Young <china@thewrittenword.com>
+
+ <LI> Added TIFFReassignTagToIgnore() API on behalf of
+ Bruce Cameron <cameron@petris.com>. Man page still pending.
+
+ <LI> pre-remove so link before softlink in LINUXdso action in
+ libtiff/Makefile.in to avoid failure on LINUXdso builds other than
+ the first.
+
+ <LI> Fixed problem with cvtcmap() in tif_getimage.c modifying the
+ colormaps owned by the TIFF handle itself when trying to fixup wrong
+ (eight bit) colormaps. Corrected by maintaining a private copy of
+ the colormap.
+
+ <LI> Added TIFFReadRGBATile()/TIFFReadRGBAStrip() support in
+ tif_getimage.c.
+
+ <LI> Applied "a" mode fix to tif_win32.c/TIFFOpen() as suggested
+ by Christopher Lawton <clawton@mathworks.com>
+
+ <LI> Set O_BINARY for tif_unix.c open() ... used on cygwin for instance.
+
+ <LI> Added CYGWIN case in configure.
+
+ <LI> Applied Francois Dagand's patch to handle fax decompression bug.
+ (sizes >= 65536 were failing)
+</UL>
+
+<P><HR WIDTH=65% ALIGN=right>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <LI> Added addtiffo (add overviews to a TIFF file) in contrib. Didn't
+ put it in tools since part of it is in C++.
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2004/11/26 14:37:20 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.5.3.html b/tiff/html/v3.5.3.html
new file mode 100644
index 0000000..e7910d9
--- /dev/null
+++ b/tiff/html/v3.5.3.html
@@ -0,0 +1,132 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.5.3
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Arial, Helvetica, Sans">
+<FONT FACE="Arial, Helvetica, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.5.3<BR>
+<B>Previous Version</B>: <A HREF=v3.5.2.html>v3.5.2</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.onshore.com/pub/libtiff">ftp.onshore.com</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff/">http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+</UL>
+<p>
+The ChangeLog will follow, but please note the most important change:
+LZW compression has been removed.
+<p>
+Unisys has the patent on LZW compression and have been very active in
+their enforcement of late, demanding payments of $5000 or more from
+websites using unlicensed software to create GIF's. They could well
+do the same do persons using libtiff to create LZW compressed TIFF
+images.
+<p>
+From <A HREF=http://burnallgifs.org>Burn All GIF's Day</a>:
+<br>
+<em>The catch is that it appears to be difficult or impossible to get a
+Unisys license to use LZW in free software that complies with the Open
+Source Definition</em>
+<P>
+Unfortunatly, the removal of LZW compression means that saved image size has
+grown dramatically. Without a change in the TIFF spec to support
+another lossless compression format, this is unavoidable.
+<P>
+The library can use zip for lossless compression, but as this is not
+part of the spec, TIFFs using zip compression may not work with other
+software
+<P>
+We will be making a patch available that will contain the LZW
+compression code for users who have either obtained a license from
+Unisys or are willing to risk it.
+<p>
+LZW decompression is unchanged.
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <LI> Added zip creation to release makefile target
+
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+
+<UL>
+
+ <LI> Added html for TIFFWriteTile.3t man page.
+
+ <LI> Added some changes to tif_write.c to support rewriting existing
+ fixed sized tiles and strips. Code mods disabled by default, only
+ enabled if REWRITE_HACK is defined for now.
+
+ <LI> Added TIFFWriteTile.3t man page.
+
+ <LI> Added notes on use of makefile.vc in build.html, and fixed
+ email subscription address.
+
+ <LI> Fixed apocalypse-inducing y2k bug in contrib/ras/ras2tiff.c
+
+ <LI> Did some casts cleaning up to reduce compiler warnings in tif_fax3.c,
+ from Bruce Carmeron <cameron@petris.com> -- modifications of
+ changes made by Frank (sun cc still complained on cast).
+
+ <LI> fixed various VC++ warnings as suggested by Gilles Vollant
+ <info@winimage.com>.
+
+ <LI> Modified TIFFquery.3t man pages info on TIFFIsByteSwapped() to
+ not imply applications are responsible for image data swapping.
+
+ <LI> HTML-ized the man pages, added to html/man
+
+ <LI> Removed LZW Compression to comply with Unisys patent extortion.
+
+ <LI> Corrected one remaining 16 -> 32 bit value in tif_fax3.c,
+ From Ivo Penzar <ivo.penzar@infolink-software.com.
+
+ <LI> Added patch from Ivo Penzar to have TiffAdvanceDirectory handle
+ memory mapped files. <ivo.penzar@infolink-software.com>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <LI> Fixed apocalypse-inducing y2k bug in contrib/ras/ras2tiff.c
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2004/11/26 14:37:20 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.5.4.html b/tiff/html/v3.5.4.html
new file mode 100644
index 0000000..714621e
--- /dev/null
+++ b/tiff/html/v3.5.4.html
@@ -0,0 +1,88 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.5.4
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.5.4<BR>
+<B>Previous Version</B>: <A HREF=v3.5.3.html>v3.5.3</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.onshore.com/pub/libtiff">ftp.onshore.com</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff/">http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <LI> None
+
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+
+<UL>
+
+ <li> Added Pixar tag support. Contributed by Phil Beffery <phil@pixar.com>
+
+ <li> Made one more change to tif_dir.c for removal of LZW compression. Also added notice
+ when LZW compression invoked.
+
+ <li> Fixed bug that caused LZW (non) compression to segfault. Added
+ warning about LZW compression removed being removed, and why.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> Changed default compression in tools to TIFF_PACKBITS, and changed usage descriptions
+ in tools to reflect removal of LZW compression
+
+ <li> Added nostrip to install in tools/Makefile.in so that debugging
+ symbols are kept.
+
+ <li> Made Packbits the default compression in tools/tiff2rgba.c instead
+ of LZW.
+
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2006/01/03 01:45:41 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.5.5.html b/tiff/html/v3.5.5.html
new file mode 100644
index 0000000..20be92f
--- /dev/null
+++ b/tiff/html/v3.5.5.html
@@ -0,0 +1,155 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.5.5
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.5.5<BR>
+<B>Previous Version</B>: <A HREF=v3.5.4.html>v3.5.4</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.onshore.com/pub/libtiff">ftp.onshore.com</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff/">http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+
+ <LI> configure: added test for libc6 for linux targets. Bug reported by
+ Stanislav Brabec <utx@k332.feld.cvut.cz>
+
+ <LI> configure: fixed bugs in sed scripts
+ (applied sed script s:/@:s;@:;s:/s;;:;: to configure).
+ fix submitted by Stanislav Brabec <utx@k332.feld.cvut.cz>
+
+ <LI> tools/iptcutil was not in files list, and wasn't being
+ added to tar archive. Updated Makefile.in.
+
+ <LI> Added 3.5 docs to html/Makefile.in.
+ Thanks to Stanislav Brabec <utx@k332.feld.cvut.cz>
+
+ <LI> Fixed tools/tiffcmp so that stopondiff testing works.
+ Patch care of Joseph Orost <joe@sanskrit.lz.att.com>.
+
+ <LI> Added fax3sm_winnt.c to distribution list in Makefile.in.
+
+ <LI> Added libtiff/libtiff.def to TIFFILES distribution list.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+
+<UL>
+ <LI>tif_fax3.c: Fixed serious bug introduced during the uint16->uint32
+ conversion for the run arrays.
+
+ <LI> Set td_sampleformat default to SAMPLEFORMAT_UINT instead of
+ SAMPLEFORMAT_VOID in TIFFDefaultDirectory() in tif_dir.c.
+
+ <LI> Added "GetDefaulted" support for TIFFTAG_SAMPLEFORMAT in tif_aux.c.
+
+ <LI> Patched tif_fax3.c so that dsp->runs is allocated a bit bigger
+ to avoid overruns encountered with frle_bug.tif.
+
+
+ <LI> Modified tif_unix.c to support 2-4GB seeks if USE_64BIT_API is
+ set to 1, and added default (off) setting in tiffconf.h. This
+ should eventually be set by the configure script somehow.
+
+ The original work on all these 2-4GB changes was done by
+ Peter Smith (psmith@creo.com).
+
+ <LI> Modified tif_win32.c to support 2-4GB seeks.
+
+ <LI> tentatively changed toff_t to be unsigned instead of signed to
+ facilitate support for 2-4GB files.
+
+ <LI> Updated a variety of files to use toff_t. Fixed some mixups
+ between toff_t and tsize_t.
+
+ <LI> Set tif_rawdatasize to zero when freeing raw data buffer in
+ TIFFWriteDirectory().
+
+ <LI> Enabled "REWRITE_HACK" in tif_write.c by default.
+
+ <LI> Fix bug in tif_write.c when switching between reading one directory
+ and writing to another.
+
+ <LI> Made TIFFWriteCheck() public, and added TIFFCreateDirectory()
+
+ <LI> Added TIFFmemory(3t) functions to libtiff.def.
+
+ <LI> Added libtiff/libtiff.def to TIFFILES distribution list.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <LI> fax2ps: Fixed mixup of width and height in bounding box statement
+ as per submission by Nalin Dahyabhai <nalin@redhat.com>.
+
+ <LI> fax2ps: Modified printruns to take uint32 instead of uint16.
+ Patch courtesy of Bernt Herd <herd@herdsoft.com>
+
+
+ <LI> Largely reimplemented contrib/addtiffo to avoid temp files,
+ updating the TIFF file in place. Fixed a few other bugs to.
+
+ <LI> Altered descriptions in tools to reflect "by default" lzw not supported
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION KIT</B></A>
+<UL>
+ <LI>created mangle-src.sh -- sed scripts to munge src into LZW enabled format. Thanks to Stanislav Brabec <utx@k332.feld.cvut.cz>
+
+ <LI>created Makefile
+
+ <LI>merged tif_dir.c with current source.
+
+
+ <LI> Created lzw compression kit, as a new CVS module (libtiff-lzw-compression-kit).
+
+ <LI> Updated index.html to note lzw compression kit.
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2004/11/26 14:37:20 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.5.6-beta.html b/tiff/html/v3.5.6-beta.html
new file mode 100644
index 0000000..682f845
--- /dev/null
+++ b/tiff/html/v3.5.6-beta.html
@@ -0,0 +1,185 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.5.6
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.5.6beta<BR>
+<B>Previous Version</B>: <A HREF=v3.5.5.html>v3.5.5</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.onshore.com/pub/libtiff">ftp.onshore.com</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff/">http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in contrib</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+
+ <LI> Added GNULDdso target and switched linux and freebsd to use it.
+ <LI> tools/Makefile.in: Modified to install properly on SGI.
+ <LI> configure: Fixed DSO test for Linux as per patch from
+ Jan Van Buggenhout <chipzz@Ace.ULYSSIS.Student.KULeuven.Ac.Be>.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+
+<UL>
+
+ <LI> tif_dir.c: Clear TIFF_ISTILED flag in TIFFDefaultDirectory
+ as per http://bugzilla.remotesensing.org/show_bug.cgi?id=18
+ from vandrove@vc.cvut.cz.
+
+ <LI> Modified tif_packbits.c decoding to avoid overrunning the
+ output buffer, and to issue a warning if data needs to be
+ discarded. See http://bugzilla.remotesensing.org/show_bug.cgi?id=18
+
+ <LI> Modified TIFFClientOpen() to emit an error on an attempt to
+ open a comperessed file for update (O_RDWR/r+) access. This is
+ because the compressor/decompressor code gets very confused when
+ the mode is O_RDWR, assuming this means writing only. See
+ bug http://bugzilla.remotesensing.org/show_bug.cgi?id=13
+
+ <LI> Applied patch for 0x0000 sequences in tif_fax3.h's definition
+ of EXPAND1D() as per bug 11 (from Roman).
+
+ <LI> Fixed tiffcomp.h to avoid win32 stuff if unix #defined, to improve
+ cygwin compatibility.
+
+ <LI> Applied patch from Roman Shpount to tif_fax3.c. This seems to
+ be a proper fix to the buffer sizing problem. See
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=11
+
+ <LI> Fixed tif_getimage.c to fix overrun bug with YCbCr images without
+ downsampling. http://bugzilla.remotesensing.org/show_bug.cgi?id=10
+ Thanks to Nick Lamb <njl98r@ecs.soton.ac.uk> for reporting the
+ bug and proving the patch.
+
+ <LI> Fixed tif_jpeg.c so avoid destroying the decompressor before
+ we are done access data thanks to bug report from:
+ Michael Eckstein <eckstein@gepro.cz>.
+
+ <LI> tif_open.c: Don't set MMAP for O_RDWR files.
+
+ <LI> tif_open.c: Set STRIPCHOP_DEFAULT for O_RDWR as well as O_RDONLY
+ so that files opened for update can be strip chopped too.
+
+ <LI> tif_read.c: fixed up bug with files missing rowsperstrip and
+ the strips per separation fix done a few weeks ago.
+
+ <LI> Tentatively added support for SAMPLEFORMAT_COMPLEXIEEEFP, and
+ SAMPLEFORMAT_COMPLEXINT.
+
+ <LI> index.html, bugs.html: added bugzilla info.
+
+ <LI> tif_read.c: fix subtle bug with determining the number of
+ rows for strips that are the last strip in a separation but
+ not the last strip of all in TIFFReadEncodedStrip().
+
+ <LI> Applied 16/32 bit fix to tif_fax3.c. Fix supplied by
+ Peter Skarpetis <peters@serendipity-software.com.au>
+
+ <LI> Modified tiffio.h logic with regard to including windows.h. It
+ won't include it when building with __CYGWIN__.
+
+ <LI> README: update to mention www.libtiff.org, don't list Sam's old
+ email address.
+
+ <LI> libtiff/tif_dirread.c: Don't use estimate strip byte count for
+ one tile/strip images with an offset, and byte count of zero. These
+ could be "unpopulated" images.
+
+ <LI> tif_win32.c: Applied patch to fix overreads and ovverwrites
+ caught by BoundsChecker. From Arvan Pritchard
+ <arvan.pritchard@infomatix.co.uk> (untested).
+
+ <LI> tif_getimage.c: Applied patch to silence VC6 warnings. From
+ Arvan Pritchard <arvan.pritchard@informatix.co.uk>
+
+ <LI> tif_lzw.c: Applied patch to silence VC6 warnings. From
+ Arvan Pritchard <arvan.pritchard@informatix.co.uk>
+
+ <LI> libtiff/tif_apple.c: Applied "Carbon" support patches supplied by
+ Leonard Rosenthol <leonardr@lazerware.com>. May interfere
+ with correct building on older systems. If so, please let me know.
+
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+
+ <LI> tools/rgb2ycbcr.c: fixed output strip size to account for vertical
+ roundup if rows_per_strip not a multiple of vertical sample size.
+
+ <LI> tools/tiffsplit.c: Copy TIFFTAG_SAMPLEFORMAT.
+
+ <LI> Modified tiff2bw to ensure portions add to 100%, and that
+ white is properly recovered. See bug
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=15 Patch
+ c/o Stanislav Brabec <utx@penguin.cz>
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN CONTRIB:</B></A>
+
+<UL>
+
+ <LI> contrib/addtiffo: Added "averaging" resampling option.
+
+ <LI> Added contrib/stream (stream io) code submitted by Avi Bleiweiss.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION KIT</B></A>
+<UL>
+
+ <LI> updated tif_dir.c to reflect changes to no-lzw tif_dir.c
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2006/03/18 17:12:47 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.5.7.html b/tiff/html/v3.5.7.html
new file mode 100644
index 0000000..528df74
--- /dev/null
+++ b/tiff/html/v3.5.7.html
@@ -0,0 +1,259 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.5.7
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.5.7<BR>
+<B>Previous Version</B>: <A HREF=v3.5.6-beta.html>v3.5.6 Beta</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff/">http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<li> libtiff/libtiff.def: Brent Roman submitted new version adding
+serveral missing entry points. Also add a few other entry points
+later.
+
+<li> configure, Makefile.in, etc: added support for OPTIMIZER being
+ set from config.site.
+<li> config.guess: updated wholesale to an FSF version apparently
+ from 1998 (as opposed to 1994). This is mainly inspired by
+ providing for MacOS X support.
+
+<li> configure/config.site: modified to check if -lm is needed for
+ MACHDEPLIBS if not supplied by config.site. Needed for Darwin.
+<li> libtiff/tiff.h: Applied hac to try and resolve the problem
+ with the inttypes.h include file on AIX. (Bug 39)
+
+<li> configure, *Makefile.in: Various changes to improve configuration
+ for HP/UX specifically, and also in general. (Bug 40) They include:
+<ul>
+ <li> Try to handle /usr/bin/sh instead of /bin/sh where necessary.
+ <li> Upgrade to HP/UX 10.x+ compiler, linker and dso options.
+ <li> Fixed mmap() test to avoid MMAP_FIXED ... it isn't available on HP
+ <li> Use -${MAKEFLAGS} in sub makes from makefiles.
+ <li> Fixed SCRIPT_SH/SHELL handling.
+</ul>
+<li> configure: Changes for DSO generation on AIX provided by
+ John Marquart <jomarqua@indiana.edu>.
+
+<li> configure, libtiff/Makefile.in: Modified to build DSOs properly
+ on Darwin thanks to Robert Krajewski (rpk@alum.mit.edu) and
+ Keisuke Fujii (fujiik@jlcuxf.kek.jp).
+
+<li> configure, libtiff/Makefile.in: applied OpenBSD patches as per bug 61.
+
+<li> Makefile.in: added DESTDIR support as per bug 60.
+
+<li> libtiff/tif_jpeg.c: Define HAVE_BOOLEAN on windows if RPCNDR.H
+ has been included.
+<li> man/Makefile.in: add TIFFClientOpen link as per debian submitted
+ bug 66.
+<li> libtiff/Makefile.in: Fixed @DSOSUB_VERSION to be @DSOSUF_VERSION@
+ in two places.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+
+<UL>
+<li> tif_fax3.c: keep rw_mode flag internal to fax3 state to remember
+ whether we are encoding or decoding. This is to ensure graceful
+ recovery if TIFFClientOpen() discovers an attempt to open a compressed
+ file for "r+" access, and subsequently close it, as it resets the
+ tif_mode flag to O_RDONLY in this case to avoid writes, confusing the
+ compressor's concept of whether it is in encode or decode mode.
+<li> tif_luv.c/tiff.h/tiffio.h:
+ New version of TIFF LogLuv (SGILOG) modules contributed by Greg Ward
+ (greg@shutterfly.com). He writes:
+
+<ol>
+ <li> I improved the gamut-mapping function in tif_luv.c for imaginary
+ colors, because some images were being super-saturated on the input
+ side and this resulted in some strange color shifts in the output.
+
+ <li> I added a psuedotag in tiff.h to control random dithering during
+ LogLuv encoding. This is turned off by default for 32-bit LogLuv and
+ on for 24-bit LogLuv output. Dithering improves the average color
+ accuracy over the image.
+
+ <li> I added a #define for LOG_LUV_PUBLIC, which is enabled by default in
+ tiffio.h, to expose internal routines for converting between LogLuv and
+ XYZ coordinates. This is helpful for writing more efficient,
+ specialized conversion routines, especially for reading LogLuv files.
+</ol>
+
+<li> libtiff/tif_dirinfo.c: don't declare tiffFieldInfo static on VMS.
+
+<li> Added TIFFTAG_COPYRIGHT support.
+<li> tif_getimage.c: Added support for 16bit minisblack/miniswhite
+ images in RGBA interface.
+<li> libtiff/tif_dirinfo.c: removed duplicate TIFFTAG_PHOTOSHOP as per
+ bug 44.
+<li> libtiff/tif_dirwrite.c: Added support for TIFF_VARIABLE2 in the
+ case of writing TIFF_BYTE/TIFF_SBYTE fields as per bug 43.
+
+<li> libtiff/tif_dirinfo.c: Modified the TIFF_BYTE definition for
+ TIFFTAG_PHOTOSHOP to use a writecount of TIFF_VARIABLE2 (-3) to
+ force use of uint32 counts instead of short counts.
+
+<li> libtiff/tif_dirinfo.c: moved pixar and copyright flags to
+ ensure everything is in order.
+
+<li> Integrated experimental OJPEG support from Scott Marovich of HP.
+
+<li> libtiff/tif_open.c: Seek back to zero after failed read,
+ before writing header.
+
+<li> libtiff/tiff.h, libtiff/tif_fax3.c: added check for __LP64__
+ when checking for 64 bit architectures as per bugzilla bug 67.
+<li> libtiff/tif_getimage.c: Use memmove() instead of TIFFmemcpy()
+ in TIFFReadRGBATile() to avoid issues in cases of overlapping
+ buffers. See Bug 69 in Bugzilla.
+<li> libtiff/tif_getimage.c: Don't complain for CMYK (separated)
+ images with more than four samples per pixel as per bug 73.
+
+<li> libtiff/tif_getimage.c: relax handling of contig case where
+there are extra samples that are supposed to be ignored as per bug 75. This
+should now work for 8bit greyscale or palletted images.
+
+<li> libtiff/tif_packbits.c: fixed memory overrun error as per bug 77.
+
+<li> libtiff/tif_getimage.c: Fixed problem with reading strips or
+tiles that don't start on a tile boundary. Fix contributed by
+Josep Vallverdu (from HP), and further described in bug 47.
+
+<li> libtif/tif_fax3.c: Removed #ifdef PURIFY logic, and modified to
+ always use the "safe" version, even if there is a very slight
+ cost in performance as per bug 54.
+<li> libtiff/tif_lzw.c: added dummy LZWSetupEncode() to report an
+ error about LZW not being available.
+
+<li> libtiff/tif_dir.c: propagate failure to initialize compression
+ back from TIFFSetField() as an error status, so applications can
+ detect failure.
+
+<li> libtiff/tif_lzw.c: Avoid MS VC++ 5.0 optimization bug as per bug 78.
+
+<li> libtiff/tif_dirwrite.c: added TIFFRewriteDirectory() function.
+Updated TIFFWriteDirectory man page to include TIFFRewriteDirectory.
+
+<li> libtiff/tiff.h: I have created COMPRESSION_CCITT_T4,
+ COMPRESSION_CCITT_T6, TIFFTAG_T4OPTIONS and TIFFTAG_T6OPTIONS aliases
+ in keeping with TIFF 6.0 standard in tiff.h as per bug 83.
+
+<li> Added PHOTOMETRIC_ITULAB as per bug 90.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+<li> Brent Roman contributed updated tiffcp utility (and tiffcp.1)
+ with support for extracting subimages with the ,n syntax, and also
+ adding the -b bias removal flag.
+<li> tiff2ps.c/tiff2ps.1: Substantial changes to tiff2ps by
+ Bruce A. Mallett, including a faster encoder, fixes for level
+ 2 PostScript, and support for the imagemask operator.
+<li> fax2ps.c: Helge (libtiff at oldach.net) submitted fix
+that corrects behaviour for non-Letter paper
+sizes. (Bug 35) It fixes two problems:
+<br>
+ Without scaling (-S) the fax is now centered on the page size specified
+ with -H and/or -W. Before, fax2ps was using an obscure and practially
+ useless algorithm to allocate the image relative to Letter sized paper
+ which sometime sled to useless whitespace on the paper, while at the
+ same time cutting of the faxes printable area at the opposite border.
+<br>
+
+ Second, scaling now preserves aspect ratio, which makes unusual faxes
+ (in particular short ones) print properly.
+
+<li> thumbnail.c: changed default output compression
+ to packbits from LZW since LZW isn't generally available.
+<li> tiff2rgba.c: added -n flag to avoid emitting alpha component. Also added
+a man page for tiff2rgba.
+
+<li> tiffcmp.c: Fixed multi samples per pixel support for ContigCompare
+as per bug 53.
+Updated bug section of tiffcmp.1 to note tiled file issues.
+
+<li> libtiff/tif_getimage.c: Fixed so that failure is properly
+ reported by gtTileContig, gtStripContig, gtTileSeparate and
+ gtStripSeparate as per bug 51.
+
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION KIT:</B></A>
+<UL>
+ <LI> Rewrote lzw patching process so that is required to enable full
+ LZW support is to drop the tif_lzw.c from the
+ libtiff-lzw-compression-kit over the one in the libtiff directory.
+
+ <LI> Some changes were made to make recovery from failure to
+ initialize the LZW compressor more graceful.
+
+ <LI> Note that as distributed libtiff support LZW decompression, but
+ not LZW compression.
+</UL>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+<UL>
+<li> Fixed distribution to include contrib/addtiffo/tif_ovrcache.{c,h}.
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2004/11/26 14:37:20 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.6.0.html b/tiff/html/v3.6.0.html
new file mode 100644
index 0000000..888e547
--- /dev/null
+++ b/tiff/html/v3.6.0.html
@@ -0,0 +1,434 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.6.0
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.6.0<BR>
+<B>Previous Version</B>: <A HREF=v3.5.7.html>v3.5.7</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<ul>
+ <li> New utility <a href=./man/raw2tiff.1.html>raw2tiff</a>
+for converting raw rasters into TIFF files.
+ <li> Lots of new <a href=./man/tiff2ps.1.html>tiff2ps</a> options.
+ <li> Lots of new <a href=./man/fax2tiff.1.html>fax2tiff</a> options.
+ <li> Lots of bug fixes for LZW, JPEG and OJPEG compression.
+</ul>
+
+<h3>Custom Tag Support</h3>
+
+The approach to extending libtiff with custom tags has changed radically.
+Previously, all internally supported TIFF tags had a place in the
+private TIFFDirectory structure within libtiff to hold the values (if read),
+and a "field number" (ie. FIELD_SUBFILETYPE) used to identify that tag.
+However, every time a new tag was added to the core, the size of the
+TIFFDirectory structure would changing, breaking any dynamically linked
+software that used the private data structures.<p>
+
+Also, any tag not recognised
+by libtiff would not be read and accessable to applications without some
+fairly complicated work on the applications part to pre-register the tags
+as exemplified by the support for "Geo"TIFF tags by libgeotiff layered on
+libtiff. <p>
+
+Amoung other things this approach required the extension code
+to access the private libtiff structures ... which made the higher level
+non-libtiff code be locked into a specific version of libtiff at compile time.
+This caused no end of bug reports!<p>
+
+The new approach is for libtiff to read all tags from TIFF files. Those that
+aren't recognised as "core tags" (those having an associated FIELD_ value,
+and place for storage in the TIFFDirectory structure) are now read into a
+dynamic list of extra tags (td_customValues in TIFFDirectory). When a new
+tag code is encountered for the first time in a given TIFF file, a new
+anonymous tag definition is created for the tag in the tag definition list.
+The type, and some other metadata is worked out from the instance encountered.
+These fields are known as "custom tags". <p>
+
+Custom tags can be set and fetched normally using TIFFSetField() and
+TIFFGetField(), and appear pretty much like normal tags to application code.
+However, they have no impact on internal libtiff processing (such as
+compression). Some utilities, such as tiffcp will now copy these custom
+tags to the new output files. <p>
+
+As well as the internal work with custom tags, new C API entry points
+were added so that extension libraries, such as libgeotiff, could
+define new tags more easily without accessing internal data structures.
+Because tag handling of extension tags is done via the "custom fields"
+mechanism as well, the definition provided externally mostly serves to provide
+a meaningful name for the tag.
+
+The addition of "custom tags" and the altered approach to extending libtiff
+with externally defined tags is the primary reason for the shift to the
+3.6.x version number from 3.5.x.<p>
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+<li> configure, config.site: Fix for large files (>2GiB) support. New
+option in the config.site: LARGEFILE="yes". Should be enougth for the large
+files I/O.
+
+<li> configure: Set -DPIXARLOG_SUPPORT option along with -DZIP_SUPPORT.
+
+<li> html/Makefile.in: Updated to use groffhtml for generating html pages
+from man pages.
+
+<li> configure, libtiff/Makefile.in: Added SCO OpenServer 5.0.6 support
+from John H. DuBois III.
+
+<li> libtiff/{Makefile.vc, libtiff.def}: Missed declarations added.
+
+<li> libtiff/Makefile.in, tools/Makefile.in: Shared library will not be
+stripped when installing, utility binaries will do be stripped. As per bug 93.
+
+<li> man/Makefile.in: Patch DESTDIR handling as per bug 95.
+
+<li> configure: OpenBSD changes for Sparc64 and DSO version as per bug 96.
+
+<li> config.site/configure: added support for OJPEG=yes option to enable
+OJPEG support from config.site.
+
+<li> config.guess, config.sub: Updated from ftp.gnu.org/pub/config.
+
+<li> configure: Modify CheckForBigEndian so it can work in a cross
+compiled situation.
+
+<li> configure, libtiff/Makefile.in: Changes for building on MacOS 10.1
+as per bug 94.
+
+<li> html/Makefile.in: added missing images per bug 92.
+
+<li> port/Makefile.in: fixed clean target per bug 92.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+
+<li> libtiff/tif_getimage.c: New function <A
+HREF="./man/TIFFReadRGBAImage.3t.html">TIFFReadRGBAImageOriented()</A>
+implemented to retrieve raster array with user-specified origin position.
+
+<li> libtiff/tif_fax3.c: Fix wrong line numbering.
+
+<li> libtiff/tif_dirread.c: Check field counter against number of fields.
+
+<li> Store a list of opened IFD to prevent directory looping.
+
+<li> libtiff/tif_jpeg.c: modified segment_height calculation to always
+be a full height tile for tiled images. Also changed error to just
+be a warning.
+
+<li> libtiff/tif_lzw.c: fixed so that decoder state isn't allocated till
+LZWSetupDecode(). Needed to read LZW files in "r+" mode.
+
+<li> libtiff/tif_dir.c: fixed up the tif_postdecode settings responsible
+for byte swapping complex image data.
+
+<li> libtiff/tif_open.c: Removed error if opening a compressed file
+in update mode bug (198).
+
+<li> libtiff/tif_write.c: TIFFWriteCheck() now fails if the image is
+a pre-existing compressed image. That is, image writing to pre-existing
+compressed images is not allowed.
+
+<li> html/man/*.html: Web pages regenerated from man pages.
+
+<li> libtiff/tif_jpeg.c: Hack to ensure that "boolean" is defined properly
+on Windows so as to avoid the structure size mismatch error from libjpeg
+(bug 188).
+
+<li> libtiff/tiff.h: #ifdef USING_VISUALAGE around previous Visual Age
+AIX porting hack as it screwed up gcc. (bug 39)
+
+<li> libtiff/tiff.h: added COMPRESSION_JP2000 (34712) for LEAD tools
+custom compression.
+
+<li> libtiff/tif_dirread.c: Another fix for the fetching SBYTE arrays
+by the TIFFFetchByteArray() function. (bug 52)
+
+<li> libtiff/tif_dirread.c: Expand v[2] to v[4] in TIFFFetchShortPair()
+as per bug 196.
+
+<li> libtiff/tif_lzw.c: Additional consistency checking added in
+LZWDecode() and LZWDecodeCompat() fixing bugs 190 and 100.
+
+<li> libtiff/tif_lzw.c: Added check for valid code lengths in LZWDecode()
+and LZWDecodeCompat(). Fixes bug 115.
+
+<li> tif_getimage.c: Ensure that TIFFRGBAImageBegin() returns the
+return code from the underlying pick function as per bug 177.
+
+<li> libtiff/{tif_jpeg.c,tif_strip.c,tif_print.c}: Hacked tif_jpeg.c to
+fetch TIFFTAG_YCBCRSUBSAMPLING from the jpeg data stream if it isn't
+present in the tiff tags as per bug 168.
+
+<li> libtiff/tif_jpeg.c: Fixed problem with setting of nrows in
+JPEGDecode() as per bug 129.
+
+<li> libtiff/tif_read.c, libtiff/tif_write.c: TIFFReadScanline() and
+TIFFWriteScanline() now set tif_row explicitly in case the codec has
+fooled with the value as per bug 129.
+
+<li> libtiff/tif_ojpeg.c: Major upgrade from Scott. Details in bug 156.
+
+<li> libtiff/tif_open.c: Pointers to custom procedures
+in TIFFClientOpen() are checked to be not NULL-pointers.
+
+<li> libtiff/tif_lzw.c: Assertions in LZWDecode and LZWDecodeCompat
+replaced by warnings. Now libtiff should read corrupted LZW-compressed
+files by skipping bad strips as per bug 100.
+
+<li> libtiff/: tif_dirwrite.c, tif_write.c, tiffio.h:
+<a href=./man/TIFFWriteDirectory.3t.html>TIFFCheckpointDirectory()</a>
+routine added as per bug 124. The
+<a href=./man/TIFFWriteDirectory.3t.html>TIFFWriteDirectory</a>
+man page discusses this new function as well as the related
+<a href=./man/TIFFWriteDirectory.3t.html>TIFFRewriteDirectory()</a>.
+
+<li> libtiff/: tif_codec.c, tif_compress.c, tiffiop.h, tif_getimage.c:
+Introduced
+additional members tif->tif_decodestatus and tif->tif_encodestatus
+for correct handling of unconfigured codecs (we should not try to read
+data or to define data size without correct codecs). See bug 119.
+
+<li> tif_dirread.c: avoid div-by-zero if rowbytes is zero in chop func as
+per bug 111.
+
+<li> libtiff/: tiff.h, tif_dir.c, tif_dir.h, tif_dirinfo.c, tif_dirread.c,
+tif_dirwrite.c: Dwight Kelly added get/put code for new tag XMLPACKET as
+defined in Adobe XMP Technote. Added missing INKSET tag value from TIFF 6.0
+spec INKSET_MULTIINK (=2). Added missing tags from Adobe TIFF technotes:
+CLIPPATH, XCLIPPATHUNITS, YCLIPPATHUNITS, OPIIMAGEID, OPIPROXY and
+INDEXED. Added PHOTOMETRIC tag value from TIFF technote 4 ICCLAB (=9).
+
+<li> libtiff/tif_getimage.c: Additional check for supported codecs added in
+TIFFRGBAImageOK, TIFFReadRGBAImage, TIFFReadRGBAStrip and TIFFReadRGBATile now
+use TIFFRGBAImageOK before reading a per bug 110.
+
+<li> libtiff/: tif_dir.c, tif_dir.h, tif_dirinfo.c, tif_dirread.c,
+tif_dirwrite.c: Added routine
+<a href=./man/TIFFDataWidth.3t.html>TIFFDataWidth</a> for determining
+TIFFDataType sizes instead of working with tiffDataWidth array
+directly as per bug 109.
+
+<li>libtiff/: tif_dirinfo.c, tif_dirwrite.c: Added possibility to
+read broken TIFFs with LONG type used for TIFFTAG_COMPRESSION,
+TIFFTAG_BITSPERSAMPLE, TIFFTAG_PHOTOMETRIC as per bug 99.
+
+<li> libtiff/{tiff.h,tif_fax3.c}: Add support for __arch64__ as per bug 94.
+
+<li> libtiff/tif_read.c: Fixed TIFFReadEncodedStrip() to fail if the
+decodestrip function returns anything not greater than zero as per bug 97.
+
+<li> libtiff/tif_jpeg.c: fixed computation of segment_width for
+tiles files to avoid error about it not matching the
+cinfo.d.image_width values ("JPEGPreDecode: Improper JPEG strip/tile
+size.") for ITIFF files. Apparently the problem was incorporated since
+3.5.5, presumably during the OJPEG/JPEG work recently.
+
+<li> libtiff/tif_getimage.c: If DEFAULT_EXTRASAMPLE_AS_ALPHA is 1
+(defined in tiffconf.h - 1 by default) then the RGBA interface
+will assume that a fourth extra sample is ASSOCALPHA if the
+EXTRASAMPLE value isn't set for it. This changes the behaviour of
+the library, but makes it work better with RGBA files produced by
+lots of applications that don't mark the alpha values properly.
+As per bugs 93 and 65.
+
+<li> libtiff/tif_jpeg.c: allow jpeg data stream sampling values to
+override those from tiff directory. This makes this work with
+ImageGear generated files.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>: Added page size setting
+when creating PS Level 2.
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>: Fixed PS comment emitted when
+FlateDecode is being used.
+
+<li> <a href=./man/tiffsplit.1.html>tiffsplit</a>: increased the maximum
+number of pages that can be split.
+
+<li> <a href=./man/raw2tiff.1.html>raw2tiff</a>: Added option `-p' to
+explicitly select color space of input image data.
+
+<li> <a href=./man/tiffmedian.1.html>tiffmedian</a>: Suppiort for large
+(> 2GB) images.
+
+<li> <a href=./man/ppm2tiff.1.html>ppm2tiff</a>: Fixed possible endless loop.
+
+<li> <a href=./man/tiff2rgba.1.html>tiff2rgba</a>: Switched to use
+<A HREF="./man/TIFFReadRGBAImage.3t.html">TIFFReadRGBAImageOriented()</A>
+instead of <A HREF="./man/TIFFReadRGBAImage.3t.html">TIFFReadRGBAImage()</A>.
+
+<li> <a href=./man/tiffcmp.1.html>tiffcmp</a>: Fixed problem with unused data
+comparing (bug 349). `-z' option now can be used to set the number of reported
+different bytes.
+
+<li> <a href=./man/tiffcp.1.html>tiffcp</a>: Added possibility to specify
+value -1 to -r option to get the entire image as one strip (bug 343).
+
+<li> <a href=./man/tiffcp.1.html>tiffcp</a>: Set the correct RowsPerStrip
+and PageNumber values (bug 343).
+
+<li> <a href=./man/fax2tiff.1.html>fax2tiff</a>: Page numbering fixed (bug
+341).
+
+<li> <a href=./man/ppm2tiff.1.html>ppm2tiff</a>: PPM header parser improved:
+now able to skip comments.
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>: Force deadzone printing when
+EPS output specified (bug 325).
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>: Add ability to generate
+PS Level 3. It basically allows one to use the /flateDecode filter for ZIP
+compressed TIFF images. Patch supplied by Tom Kacvinsky (bug 328).
+
+<li> <a href=./man/tiffcp.1.html>tiffcp</a>: Fixed problem with colorspace
+conversion for JPEG encoded images (bugs 23 and 275)
+
+<li> <a href=./man/fax2tiff.1.html>fax2tiff</a>: Applied patch from
+Julien Gaulmin. More switches for fax2tiff tool for better control
+of input and output (bugs 272 and 293).
+
+<li> <a href=./man/raw2tiff.1.html>raw2tiff</a>:
+New utility for turning raw raster images into TIFF files
+written by Andrey Kiselev.
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>:
+Sebastian Eken provided patches (bug 200) to add new these new
+switches:
+ <ul>
+ <li> <b>-b #</b>: for a bottom margin of # inches
+ <li> <b>-c</b>: center image
+ <li> <b>-l #</b>: for a left margin of # inches
+ <li> <b>-r</b>: rotate the image by 180 degrees
+ </ul>
+
+Also, new features merged with code for shrinking/overlapping.
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>: Don't emit BeginData/EndData
+DSC comments since we are unable to properly include the amount to skip
+as per bug 80.
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>: Added workaround for some
+software that may crash when last strip of image contains fewer number
+of scanlines than specified by the `/Height' variable as per bug 164.
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>: Patch from John Williams to add new
+functionality for tiff2ps utility splitting long images in several pages as
+per bug 142. New switches:
+ <ul>
+ <li> <b>-H #</b>: split image if height is more than # inches
+ <li> <b>-L #</b>: overLap split images by # inches
+ </ul>
+
+<li> <a href=./man/tiff2ps.1.html>tiff2ps</a>: New commandline
+switches to override resolution units obtained from the input file per bug 131:
+ <ul>
+ <li> <b>-x</b>: override resolution units as centimeters
+ <li> <b>-y</b>: override resolution units as inches
+ </ul>
+
+<li> <a href=./man/fax2tiff.1.html>fax2tiff</a>: Updated to reflect
+latest changes in libtiff per bug 125.
+
+<li> tiff2ps: Division by zero fixed as per bug 88.
+
+<li> <a href=./man/tiffcp.1.html>tiffcp<a>:
+Added support for 'Orientation' tag.
+
+<li> <a href=./man/tiffdump.1.html>tiffdump</a>:
+include TIFFTAG_JPEGTABLES in tag list.
+
+<li> tiffset: fix bug in error reporting.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+<UL>
+
+<li> Fixed distribution to include contrib/addtiffo/tif_ovrcache.{c,h}.
+<li> libtiff/contrib/win95: renamed to contrib/win_dib. Added new
+Tiffile.cpp example of converting TIFF files into a DIB on Win32 as per
+bug 143.
+
+</UL>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION
+KIT:</B></A>
+<UL>
+
+<li> LZW compression kit synchronized with actual libtiff version.
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2003/10/04 11:38:17 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.6.1.html b/tiff/html/v3.6.1.html
new file mode 100644
index 0000000..d106062
--- /dev/null
+++ b/tiff/html/v3.6.1.html
@@ -0,0 +1,199 @@
+<HTML>
+<HEAD>
+<TITLE>
+Changes in TIFF v3.6.1
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.6.1<BR>
+<B>Previous Version</B>: <A HREF=v3.6.0.html>v3.6.0</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<ul>
+ <li> New utility <a href="./man/tiff2pdf.1.html">tiff2pdf</a>
+ for converting TIFF images directly into PDF.
+ <li> New <a href="./man/TIFFcolor.3t.html">color conversion module</a>.
+ <li> Full support for Orientation tag in
+ <a href="./man/TIFFReadRGBAImage.3t.html">TIFFRGBAImage</a> interface.
+ <li> Many bugs fixed.
+</ul>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+
+<li> libtiff/makefile.vc, tools/makefile.vc: Support for IJG JPEG library.
+
+<li> Makefile.in: Add an absolute path to the test_pics.sh call.
+
+<li> Makefile.in: Add an absolute path to the test_pics.sh call.
+
+<li> libtiff/tiffcomp.h: #define _BSDTYPES_DEFINED when defining BSD typedefs.
+
+<li> configure, libtiff/{Makefile.in, mkversion.c}: Relative buildings fixed.
+
+<li> Makefile.in: Add an absolute path to the test_pics.sh call.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+
+<li> libtiff/{tif_color.c, tif_getimage.c, tiffio.h}: Added support
+for ReferenceBlackWhite tag handling when converted from YCbCr color space as
+per bug 120.
+
+<li> libtiff/{tif_getimage.c, tif_aux.c}: Read WhitePoint tag from the
+file and properly use it for CIE Lab 1976 to RGB transform.
+
+<li> libtiff/{tif_getimage.c, tiffio.h}: Finally resolved problems with
+orientation handling. TIFFRGBAImage interface now properly supports all
+possible orientations, i.e. images will be flipped both in horizontal and
+vertical directions if required. 'Known bugs' section now removed from the
+appropriate manual pages.
+
+<li> libtiff/tif_luv.c: Fixed bug in 48-bit to 24-bit conversion routine,
+reported by Antonio Scuri.
+
+<li> libtiff/{tiffio.h, tif_codec.c}: Added new function
+TIFFIsCODECConfigured(), suggested by Ross Finlayson.
+
+<li> libtiff/tif_ojpeg.c: TIFFVGetField() function now can properly extract
+the fields from the OJPEG files. Patch supplied by Ross Finlayson.
+
+<li> libtiff/tif_dir.h: _TIFFFindOrRegisterdInfo declaration replaced
+with _TIFFFindOrRegisterFieldInfo as reported by Ross Finlayson.
+
+<li> libtiff/tif_dirinfo.c: Implemented binary search in _TIFFMergeFieldInfo().
+Patch supplied by Ross Finlayson.
+
+<li> tif_dirread.c: do not mark all anonymously defined tags to be IGNOREd (as
+it was done in 3.6.0).
+
+<li> libtiff/{tiff.h, tif_dirinfo.c}: Added support for IFD (13) datatype,
+intruduced in "Adobe PageMaker TIFF Technical Notes".
+
+<li> libtiff/{tif_color.c, tif_getimage.c, tiffio.h}: New color space
+conversion code: CIE L*a*b* 1976 images now supported by the TIFFRGBAImage
+interface. YCbCr to RGB conversion code also moved there and now has
+<a href="./man/TIFFcolor.3t.html">publicly available interface</a>. These
+routines currently used in TIFFRGBAImage interface only and not supported in
+other libtiff tools yet. So if you want, for example, to convert CIE Lab image
+into PostScript file you should do it in two steps: chnge colorspace to RGB
+using <a href="./man/tiff2rgba.1.html">tiff2rgba</a> utility abd then process
+it with the <a href="./man/tiff2ps.1.html">tiff2ps</a>.
+
+<li> libtiff/tif_tile.c: Remove spurious use of "s" (sample) in the
+planarconfig_contig case in TIFFComputeTile() as per bug 387
+
+<li> libtiff/tiffiop.h: New macros: TIFFmax and TIFFmin.
+
+<li> libtiff/{tiffio.h, tif_strip.c}: Added TIFFRawStripSize() function
+as suggested by Chris Hanson.
+
+<li> libtiff/{tif_lzw.c, tif_fax3.c}: Proper support for update mode
+as per bug 424.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+
+<li> <a href=./man/tiff2pdf.1.html>tiff2pdf</a>: New tool, written by
+Ross Finlayson, to directly convert TIFF files to PDF.
+
+<li> <a href=./man/tiffgt.1.html>tiffgt</a>: Unmaintained and platform
+dependent sgigt utility removed and replaced with the completely rewritten
+portable <a href=./man/tiffgt.1.html>tiffgt</a> tool (depend on OpenGL and
+GLUT). This tool will not build by default.
+
+<li> <a href=./man/ras2tiff.1.html>ras2tiff</a>: Properly determine
+SUN Rasterfiles with the reverse byte order (it is reported by the magic
+header field). Problem reported by Andreas Wiesmann.
+
+<li> <a href=./man/raw2tiff.1.html>raw2tiff</a>: Implemented image size
+guessing using correlation coefficient calculation between two neighbour
+lines.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+<UL>
+
+<li> contrib/pds/{tif_pdsdirread.c, tif_pdsdirwrite.c}: Use TIFFDataWidth()
+function insted of tiffDataWidth array.
+
+</UL>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION
+KIT:</B></A>
+<UL>
+
+<li> Proper support for update mode as per bug 424.
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2003/12/24 22:14:15 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.7.0.html b/tiff/html/v3.7.0.html
new file mode 100644
index 0000000..413f2c6
--- /dev/null
+++ b/tiff/html/v3.7.0.html
@@ -0,0 +1,144 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.7.0
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.7.0<BR>
+<B>Previous Version</B>: <A HREF=v3.7.0beta2.html>v3.7.0beta2</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+
+ <li> Several bugs found after 3.7.0beta2 release were fixed.
+
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> ltmain.sh: Fix for MinGW compilation.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+
+ <li> libtiff/{tif_dirread.c, tif_jpeg.c, tif_luv.c, tif_ojpeg.c,
+ tif_pixarlog.c, tif_write.c}: Handle the zero strip/tile sizes
+ properly (Dmitry V. Levin, Marcus Meissner).
+
+ <li> libtiff/tif_dirinfo.c: Type of the TIFFTAG_SUBIFD field changed
+ to TIFF_IFD.
+
+ <li> Preliminary support for BigTIFF files: now libtiff can
+ recognize and reject to open such images. ;-)
+
+ <li> libtiff/tif_dir.c: Initialize td_tilewidth and td_tilelength fields
+ of the TIFFDirectory structure with the 0 instead of -1 to avoid
+ confusing integer overflows in TIFFTileRowSize() for striped images.
+
+ <li> libtiff/tif_dir.c: Initialize td_tilewidth and td_tilelength fields
+ of the TIFFDirectory structure with the 0 instead of -1 to avoid
+ confusing integer overflows in TIFFTileRowSize() for striped images.
+
+ <li> libtiff/tif_dirinfo.c: Fix bug with tif_foundfield and reallocation
+ of tif_fieldinfo as per bug
+ <A HREF="http://bugzilla.remotesensing.org/show_bug.cgi?id=630">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=630</A>
+
+ <li> libtiff/tif_compress.c: Improved error reporting in
+ TIFFGetConfiguredCODECs() (Dmitry V. Levin).
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiffcmp.c (leof): Renamed from 'eof' in order to avoid
+ conflict noticed under MinGW.
+
+ <li> tiff2pdf.c: Fixed TransferFunction tag handling reported
+ by Ross A. Finlayson.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> No changes.
+
+</UL>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION
+KIT:</B></A>
+<UL>
+
+ <li> This one is not longer needed.
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2004/12/20 19:31:44 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.7.0alpha.html b/tiff/html/v3.7.0alpha.html
new file mode 100644
index 0000000..95c633c
--- /dev/null
+++ b/tiff/html/v3.7.0alpha.html
@@ -0,0 +1,249 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.7.0alpha
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.7.0alpha<BR>
+<B>Previous Version</B>: <A HREF=v3.6.1.html>v3.6.1</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<ul>
+ <li> Significant changes in software configuration: we are switched
+ to GNU autotools now.
+
+ <li> tiffset: tiffset now can set any libtiff supported tags. Tags
+ can be supplied by the mnemonic name or number.
+</ul>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> Get rid of the old configuration system and switch to
+ GNU autotools.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> libtiff/tif_ojpeg.c: Fixed problem with duplicated SOI and SOF
+ markers as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=581"
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=581</a>.
+
+ <li> libtiff/{tif_open.c, tiffio.h}: New function added:
+ TIFFIsBigEndian(). Function returns nonzero if given was file written
+ in big-endian order.
+
+ <li> libtiff/tif_print.c: added (untested) support for printing
+ SSHORT, SLONG and SRATIONAL fields.
+
+ <li> libtiff/tif_fax3.c: Avoid reading CCITT compression options
+ if compression type mismatches. See
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=565">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=565</a>.
+
+ <li> libtiff/tif_strip.c: Never return 0 from the TIFFNumberOfStrips().
+
+ <li> libtiff/tif_dirread.c: Workaround for broken TIFF writers which
+ store single SampleFormat value for multisampled images. See
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=562">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=562</a>.
+
+ <li> libtiff/tif_write.c: Allow in-place updating of the compressed
+ images (don't work properly with all codecs). For details see GDAL bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=534">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=534</a>.
+
+ <li> libtiff/tif_jpeg.c: Workaround for wrong sampling factors used
+ in the Intergarph JPEG compressed TIFF images as per bug:
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=532">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=532</a>.
+
+ <li> libtiff/tif_open.c: Use dummy mmap/munmap functions in
+ TIFFClientOpen() when the appropriate client functions was not
+ supplied by user.
+
+ <li> libtiff/tif_dirread.c: Fixed problem with handling TIFF_UNDEFINED
+ tag type in TIFFFetchNormalTag() as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=508"
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=508</a>.
+
+ <li> libtiff/tif_codec.c: Fixed typo in TIFFInitPackBits name as per:
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=494">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=494</a>.
+
+ <li> libtiff/tif_fax3.c: Fixed problem, introdiced in 3.6.1 release,
+ with the CCITT encoding modes as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=483">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=483</a>.
+ We need more work on fax codec to support update mode.
+
+ <li> libtiff/tiff.h: Fixed tag definitions for TIFFTAG_YCLIPPATHUNITS
+ and TIFFTAG_INDEXED as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=475">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=475</a>.
+
+ <li> libtiff/{tif_win32.c, tif_unix.c}: Check whether the pointer is
+ NULL before proceeding further as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=474">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=474</a>.
+ Check results, returned by the TIFFFdOpen() before returning and close
+ file if TIFFFdOpen() failed as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=468">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=468</a>.
+
+ <li> libtiff/{libtiff.def, tif_close.c, tiffio.h, tif_open.c}:
+ Separate TIFFCleanup() from the TIFFClose() in order to fix the bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=468">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=468</a>.
+
+ <li> libtiff/tif_dirwrite.c: Fixed handling of writable ASCII tags
+ that are field_passcount=TRUE properly. Arguably anonymous custom
+ tags should be declared as passcount=FALSE, but I don't want to change
+ that without a careful review.
+
+ <li> libtiff/tif_write.c: Fixed reporting size of the buffer in case
+ of stripped image in TIFFWriteBufferSetup(). As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=460">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=460</a>.
+
+ <li> libtiff/tif_dir.c: Incomplete cleanup in TIFFFreeDirectory(),
+ patch from Gerben Koopmans.
+
+ <li> libtiff/tif_dirread.c: Check field_passcount value before setting
+ the value of undefined type, patch from Gerben Koopmans.
+
+ <li> libtiff/{tiff.h, tif_fax3.c}:Fixes for AMD 64 platform as
+ suggested by Jeremy C. Reed.
+
+ <li> libtiff/tif_win32.c: Fixed problem with _TIFFrealloc() when
+ the NULL pointer passed. Patch supplied by Larry Grill.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiffset: tiffset now can set any libtiff supported tags. Tags
+ can be supplied by the mnemonic name or number.
+
+ <li> ycbcr.c: fixed main() declaration as per:
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=513">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=513</a>.
+
+ <li> <a href=./man/tiffsplit.1.html>tiffsplit</a>: Don't forget
+ to copy Photometric Interpretation tag.
+
+ <li> <a href=./man/tiffsplit.1.html>tiffsplit</a>: Fixed problem with
+ unproperly written multibyte files. Now output files will be written
+ using the same byte order flag as in the input image. See
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=574"
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=574</a>.
+
+ <li> <a href=./man/tiffsplit.1.html>tiffsplit</a>: Copy JPEGTables
+ tag contents for JPEG compressed images. Reported by Artem Mirolubov.
+
+ <li> <a href=./man/tiffcp.1.html>tiffcp</a>: Close output file
+ on normal exit.
+
+ <li> <a href=./man/tiffcp.1.html>tiffcp</a>: Don't emit warnings
+ when Orientation tag does not present in the input image.
+
+ <li> <a href=./man/tiffcp.1.html>tiffcp</a>: Properly set
+ Photometric Interpretation in case of JPEG compression of grayscale
+ images.
+
+ <li> <a href=./man/tiffcp.1.html>tiffcp</a>: Fixed problem with wrong
+ interpretation of the InkNames tag as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=466">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=466</a>.
+ Memory leak fixed.
+
+ <li> <a href=./man/tiffcp.1.html>tiffcp</a>: Fixed problem with
+ wrong Photometric setting for non-RGB images.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> Outdated stuff removed.
+
+ <li> Almost all programs are sinchronized with the current libtiff
+ and should compile without problems.
+
+</UL>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION
+KIT:</B></A>
+<UL>
+
+<li> No changes.
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2006/03/18 17:12:47 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.7.0beta.html b/tiff/html/v3.7.0beta.html
new file mode 100644
index 0000000..7d7c868
--- /dev/null
+++ b/tiff/html/v3.7.0beta.html
@@ -0,0 +1,162 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.7.0beta
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.7.0beta<BR>
+<B>Previous Version</B>: <A HREF=v3.7.0alpha.html>v3.7.0alpha</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<ul>
+ <li> LZW compression enabled by default. You don't need the separate
+ compression kit anymore.
+
+ <li> bmp2tiff: Added new utility to convert Windows BMP files
+ into TIFFs.
+
+ <li> The first attempt to implement a test suite.
+</ul>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> Many portability fixes in the new autotooled build suite.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> libtiff/{tif_luv.c, tif_next.c, tif_thunder.c}: Several buffer
+ overruns fixed, as noted by Chris Evans.
+
+ <li> BSD data types (u_char, u_short, u_int, u_long) is no longer
+ used internally in the libtiff. Should result in simpler configuration
+ and better portability.
+
+ <li> libtiff/tiff.h: Fix column tagging. Reference current Adobe XMP
+ specification. Reference libtiff bug tracking system to submit
+ private tag additions.
+
+ <li> libtiff/tif_dirread.c: Don't reject to read tags of the
+ SamplesPerPixel size when the tag count is greater than number of
+ samples as per bug
+ <A HREF="http://bugzilla.remotesensing.org/show_bug.cgi?id=576">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=576</A>.
+
+ <li> libtiff/{tiffio.h, tif_open.c}: Applied patches from
+ Joris Van Damme to avoid requirement for tiffiop.h inclusion in
+ some applications. Look for details here:
+ <A HREF="http://www.asmail.be/msg0054799560.html">
+ http://www.asmail.be/msg0054799560.html</A>.
+
+ <li> libtiff/{tiffiop.h, tif_dirinfo.c}: Fixed problem with the static
+ variable as per bug
+ <A HREF="http://bugzilla.remotesensing.org/show_bug.cgi?id=593">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=593</A>.
+
+ <li> libtiff/tif_lzw.c: LZW compression code is merged back from the
+ separate package. All libtiff tools are updated to not advertise an
+ abcence of LZW support.
+
+ <li> libtiff/tif_dir.c: Call TIFFError() instead of producing warnings
+ when setting custom tags by value. Reported by Eric Fieleke.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiff2ps: Avoid zero division in setupPageState() function;
+ properly initialize array in PSDataBW().
+
+ <li> tiff2pdf: Multiple bugfixes.
+
+ <li> ras2tiff: Fixed issue with missed big-endian checks as per bug
+ </A HREF="http://bugzilla.remotesensing.org/show_bug.cgi?id=586">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=586</A>.
+
+ <li> bmp2tiff: Added new utility to convert Windows BMP files
+ into TIFFs.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> No changes.
+
+</UL>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION
+KIT:</B></A>
+<UL>
+
+ <li> This one is not longer needed.
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2006/03/18 17:12:47 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.7.0beta2.html b/tiff/html/v3.7.0beta2.html
new file mode 100644
index 0000000..67dd8da
--- /dev/null
+++ b/tiff/html/v3.7.0beta2.html
@@ -0,0 +1,131 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.7.0beta2
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.7.0beta2<BR>
+<B>Previous Version</B>: <A HREF=v3.7.0beta.html>v3.7.0beta</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+<LI><A HREF="#lzwkit">Changes in the LZW compression kit</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+
+ <li> The code has been reviewed by Dmitry Levin: added checks
+ for values, returned by the space allocation functions, fixed
+ problems with the possible integer overflows.
+
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> Several fixes in the test suite.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+
+ <li> Preliminary support for BigTIFF files: now libtiff can
+ recognize and reject to open such images. ;-)
+
+ <li> libtiff/tif_dirinfo.c: changed type of XMLPacket (tag 700) to
+ TIFFTAG_BYTE instead of TIFFTAG_UNDEFINED to comply with the info
+ in the Adobe XMP Specification.
+
+ <li> Added many checks for integer overflow and for successful space
+ allocations in the different parts of library. Code review
+ completed by Dmitry V. Levin.
+
+ <li> libtiff/{tiffio.h, tif_compress.c}: Added
+ TIFFGetConfiguredCODECs()function to get the list of configured codecs.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiff2bw: Write ImageWidth/Height tags to output file, as
+ noted by Gennady Khokhorin.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> No changes.
+
+</UL>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="lzwkit"><B><FONT SIZE=+3>C</FONT>HANGES IN THE LZW COMPRESSION
+KIT:</B></A>
+<UL>
+
+ <li> This one is not longer needed.
+
+</UL>
+
+<A HREF="index.html"><IMG SRC="images/back.gif"></A> TIFF home page.<BR>
+
+<HR>
+
+Last updated $Date: 2006/03/18 17:12:47 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.7.1.html b/tiff/html/v3.7.1.html
new file mode 100644
index 0000000..b888792
--- /dev/null
+++ b/tiff/html/v3.7.1.html
@@ -0,0 +1,233 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.7.1
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.7.1<BR>
+<B>Previous Version</B>: <A HREF=v3.7.0.html>v3.7.0</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+
+ <li> This is mostly bugfix release. Most important fix is the one
+ related to wrong custom tag read/write code.
+
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+
+ <li> autogen.sh: aclocal and autoheader should be executed after
+ libtoolize. Also add '-I .' to aclocal invocation to check
+ current directory for macros.
+
+ <li> nmake.opt: Link with the user32.lib in windowed mode. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=697">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=697</a>
+
+ <li> nmake.opt, makefile.vc: make it easier to rename the libtiff DLL.
+
+ <li> configure, configure.ac: Added --enable-rpath option to embed
+ linker paths into library binary.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+
+ <li> tiff.h: Revert back libtiff data type definitions as per
+ bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=687">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=687</a>
+
+ <li> tif_dirread.c: Do not forget about TIFF_VARIABLE2 when
+ checking for tag count in TIFFReadDirectory() function. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=713">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=713</a>
+
+ <li> tif_getimage.c: Support for multiple-alpha-channelled
+ RGB-images as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=718">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=718</a>
+
+ <li> tif_getimage.c: #define A1 bracketing for clean build on
+ SunPro compiler.
+
+ <li> tif_dirwrite.c: Always write TIFFTAG_SUBIFD using LONG type
+ as per bugs
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=703">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=703</a> and
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=704">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=704</a>.
+
+ <li> tif_win32.c: Use char* strings instead of TCHAR in windowed
+ mode as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=697">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=697</a>
+
+ <li> tif_dir.c, tif_dirread.c: Remove TIFFReassignTagToIgnore()
+ call from the TIFFReadDirectory() function. TIFFReassignTagToIgnore
+ must be removed in the future, as it was never used properly. As per
+ bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=692">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=692</a>
+
+ <li> tif_jpeg.c: Added a work-around in order to allow
+ compilation with the heavily modified version of libjpeg delivered
+ with Cygwin.
+
+ <li> tif_dir.c: Properly handle tags, which have the uint32
+ counts. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=693">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=693</a>
+
+ <li> tif_unix.c: Make UNIX module compilable (and usable)
+ on Windows.
+
+ <li> tiff.h: Added Adobe DNG tags.
+
+ <li> tif_aux.c: Set the appropriate ReferenceBlackWhite array for
+ YCbCr image which lacks that tag (noted by Hans Petter Selasky).
+
+ <li> tif_color.c: Division by zero fixed (Hans Petter Selasky).
+
+ <li> tif_stream.cxx, tiffio.h: Added C++ stream interface
+ contributed by Edward Lam (see
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=654">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=654</a>
+ for details). Those who want to use C++ streams should
+ #include <tiffio.hxx>.
+
+ <li> tif_open.c: Removed close() in TIFFClientOpen() if file
+ is bad. This is the callers responsibility.
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=651">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=651</a>
+
+ <li> tiffio.h, tif_win32.c, libtiff.def}: Added TIFFOpenW()
+ function to work with the double byte strings (used to represent
+ filenames in some locales). As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=625">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=625</a>
+
+ <li> tif_dirread.c: Fixed problem when fetching BitsPerSample and
+ Compression tags of type LONG from broken TIFFS as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=662">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=662</a>
+
+ <li> tif_dirinfo.c: Fixed definition for TIFFTAG_RICHTIFFIPTC,
+ the writecount should have uint32 type. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=662">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=662</a>
+
+ <li> tif_write.c: Fixed wrong if() statement in
+ TIFFAppendToStrip() function as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=660">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=660</a>
+
+ <li> tif_dirinfo.c: Change definition for TIFFTAG_EXTRASAMPLES
+ field. The caller should supply a count when setting this field. As
+ per bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=648">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=648</a>.
+
+ <li> tif_jpeg.c, tif_ojpeg.c: TIFFTAG_JPEGTABLES should have
+ uint32 count. Use this type everywhere.
+
+ <li> tif_next.c: avoid use of u_long and u_char types.
+
+ <li> tif_fax3.c: Fixed case with the wrong decode routines
+ choosing when the incorrect Group4Options tag set. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=323">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=323</a>
+
+ <li> tif_dirwrite.c: Fixed problem with passing count variable of
+ wrong type when writing the TIFF_BYTE/TIFF_SBYTE tags in
+ TIFFWriteNormalTag().
+
+ <li> tif_compress.c: Zero division problem fixed (Vladimir Nadvornik,
+ Dmitry V. Levin).
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+
+ <li> fax2ps.c: Be able to extract the first page (#0). As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=690">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=690</a>
+
+ <li> tiff2ps.c: Fixed wrong variable data type when read Position
+ tags (Tristan Hill).
+
+ <li> tiff2ps.c: Fixed wrong variable data type when read Resolution
+ tags (Peter Fales).
+
+ <li> tiffset.c: Check the malloc return value (Dmitry V. Levin).
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> No changes.
+
+</UL>
+
+Last updated $Date: 2004/12/20 19:31:44 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.7.2.html b/tiff/html/v3.7.2.html
new file mode 100644
index 0000000..6cb6f7c
--- /dev/null
+++ b/tiff/html/v3.7.2.html
@@ -0,0 +1,222 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.7.2
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.7.2<BR>
+<B>Previous Version</B>: <A HREF=v3.7.1.html>v3.7.1</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+
+ <li> Maintainance release. Many bugfixes in the build environment
+ and compatibility improvements.
+
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> configure.ac: Use -rpath option instead of -R as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=732">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=732</a>
+
+ <li> tif_stream.cxx: Fixes for C++ stream interface from
+ Michael Rinne and Edward Lam.
+
+ <li> configure.ac: Make the documentation directory location
+ configurable via the --with-docdir option (as suggested by
+ Jeremy C. Reed).
+
+ <li> Place the C++ stream API in the separate library called
+ libtiffxx to avoid unneeded dependencies. Probably there will be
+ more C++ API in the future. As per bugs
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=733">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=733</a>
+ and <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=730">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=730</a>
+
+ <li> configure, configure.ac: Replace --disable-c++ with the
+ --disable-cxx option as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=730">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=730</a>.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+
+ <li> Applied patch from Lee Howard to support a new tag TIFFTAG_FAXDCS
+ (34911) used in HylaFax software. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=771">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=771</a>
+
+ <li> tif_open.c: Remove unnesessary TIFFSeekFile() call as per
+ bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=756">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=756</a>
+
+ <li> tiff.h: Changed the int8 definition to be always signed char
+ as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=727">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=727</a>
+
+ <li> tiffio.h: Move TIFFOpenW() function into the extern "C"{}
+ block as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=763">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=763</a>
+
+ <li> tif_dirread.c: Estimate strip size in case of wrong or
+ suspicious values in the tags. As per bugs
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=705">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=705</a>
+ and <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=320">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=320</a>
+
+ <li> tif_color.c: Use double as the second argument of pow()
+ function in TIFFCIELabToRGBInit(). As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=741">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=741</a>
+
+ <li> tif_pixarlog.c: Avoid warnings when converting float to
+ integer as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=740">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=740</a>
+
+ <li> tif_getimage.c: Always fill the error message buffer in
+ TIFFRGBAImageBegin() as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=739">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=739</a>
+
+ <li> tif_jpeg.c: Added ability to read/write the fax specific
+ TIFFTAG_FAXRECVPARAMS, TIFFTAG_FAXSUBADDRESS and TIFFTAG_FAXRECVTIME
+ tags as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=736">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=736</a>
+
+ <li> tif_win32.c: Fixed message formatting in functions
+ Win32WarningHandler() and Win32ErrorHandler() as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=735">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=735</a>
+
+ <li> tiffio.h: Move the color conversion routines in the 'extern
+ "C"' section as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=727">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=727</a>
+
+ <li> tiff.h: Restore back the workaround for AIX Visual Age C
+ compiler to avoid double definition of BSD types as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=39">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=39</a>
+
+ <li> tif_getimage.c: More fixes for multiple-alpha-channelled
+ RGB-images as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=713">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=713</a>
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+
+ <li> tiffcmp.c: Added ability to compare the 32-bit integer and
+ floating point data; complain on unsupported bit depths.
+
+ <li> tiffcmp.c: Use properly sized buffer in short arrays comparison
+ as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=785">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=785</a>
+
+ <li> fax2ps.c: Replace insecure mktemp() function with the
+ tmpfile() as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=786">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=786</a>
+
+ <li> tiffgt.c: Fix problem on big-endian CPUs so that images
+ display more correctly. Images display brighter than they should
+ on a Sun workstation.
+
+ <li> tiff2ps.c: Fixed problem with page sizes as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=742">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=742</a>
+
+ <li> tiff2ps.c: Interpret the -w and -h options independently. As
+ per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=689">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=689</a>
+
+ <li> tiffdump.c: Fixed problem when read broken TIFFs with the
+ wrong tag counts (Dmitry V. Levin, Martin Pitt).
+
+ <li> tiffset.c: Convert character option to integer value as per
+ bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=725">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=725</a>.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> No changes.
+
+</UL>
+
+Last updated $Date: 2005/03/15 15:17:44 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.7.3.html b/tiff/html/v3.7.3.html
new file mode 100644
index 0000000..d698451
--- /dev/null
+++ b/tiff/html/v3.7.3.html
@@ -0,0 +1,230 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.7.3
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.7.3<BR>
+<B>Previous Version</B>: <A HREF=v3.7.2.html>v3.7.2</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+ <li> Replace runtime endianess check with the compile time one.
+
+ <li> Added support for the new predictor type (floating point
+ predictor), defined at the TIFF Technical Note 3.
+
+ <li> Added Support for custom tags, passed by value.
+ Added support for all DNG tags.
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> Do not use empty -R option when linking with --enable-rpath.
+
+ <li> Added workaround for OpenBSD/MirOS soname problem as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=838">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=838</a>
+
+ <li> Fixed parallel compilation of the libtiff and
+ libtiffxx libraries as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=826">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=826</a>
+
+ <li> configure.ac, libtiff/Makefile.am: Use libtool machinery to pass
+ rpath option.
+
+ <li> make.opt: Build with Win32 CRT library by default.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> tiffiop.h, tif_open.c: Added open option 'h' to avoid reading
+ the first IFD when needed. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=875">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=875</a>
+
+ <li> tiff.h: Use correct int size on Sparc 64bit/Sun compiler
+ platform. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=855">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=855</a>
+
+ <li> tif_dirinfo.c: Added support for ClipPath, XClipPathUnits
+ and YClipPathUnits tags.
+
+ <li> tif_dirinfo.c, tif_dir.h, tif_dir.c, tif_print.c: Make
+ DocumentName, Artist, HostComputer, ImageDescription, Make, Model,
+ Copyright, DateTime, PageName, TextureFormat, TextureWrapModes and
+ TargetPrinter tags custom.
+
+ <li> tif_jpeg.c: Cleanup the codec state depending on TIFF_CODERSETUP
+ flag (to fix memory leaks).
+
+ <li> tif_dirwrite.c: Use tdir_count when calling
+ TIFFCvtNativeToIEEEDouble() in the TIFFWriteDoubleArray() function as
+ per bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=845">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=845</a>
+
+ <li> tif_dirinfo.c, tif_print.c: TIFFFetchByteArray() returns
+ uint16 array when fetching the BYTE and SBYTE fields, so we should
+ consider result as pointer to uint16 array and not as array of chars.
+ As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=831">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=831</a>
+
+ <li> tif_dir.c: More efficient custom tags retrieval as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=830">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=830</a>
+
+ <li> tif_win32.c: Use FILE_SHARE_READ | FILE_SHARE_WRITE share
+ mode in CreateFile() call as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=829">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=829</a>
+
+ <li> tif_jpeg.c: Substantial fix for addtiffo problems with
+ JPEG encoded TIFF files. Pre-allocate lots of space for jpegtables
+ in directory.
+
+ <li> tif_dirread.c: Changed the code that computes
+ stripbytecount[0] if it appears bogus to ignore if stripoffset[0] is
+ zero. This is a common case with GDAL indicating a "null" tile/strip.
+
+ <li> tif_jpeg.c: added LIB_JPEG_MK1 support in JPEGDecodeRaw().
+
+ <li> tif_dirread.c: Ensure that broken files with too many
+ values in PerSampleShorts, TIFFFetchPerSampleLongs and
+ TIFFFetchPerSampleAnys work ok instead of crashing.
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=843">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=843</a>
+
+ <li> tif_predict.h, tif_predict.c: Added ability to decode and encode
+ floating point predictor, as per TIFF Technical Note 3.
+ See http://chriscox.org/TIFF_TN3_Draft2.pdf for details.
+
+ <li> tiffio.h, tiffiop.h, tif_dir.c, tif_read.c, tif_swab.c:
+ Added _TIFFSwab24BitData() and TIFFSwabArrayOfLong() functions used to
+ swap 24-bit floating point values.
+
+ <li> tiff.h: Added predictor constants.
+
+ <li> tiffiop.h, tif_dir.c: Use uint32 type for appropriate values
+ in _TIFFVSetField() function. Inspired by the bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=816">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=816</a>
+
+ <li> tif_open.c: Do not read header in case the output file should
+ be truncated (Ron).
+
+ <li> tif_dirinfo.c, tif_config.h.vc: Use lfind() instead of bsearch()
+ in _TIFFFindFieldInfoByName() function (Ron).
+
+ <li> tif_dir.c, tif_print.c: Properly handle all data types in custom
+ tags.
+
+ <li> dirinfo.c: Added DNG tags.
+
+ <li> tiff.h: Added missed DNG tag (LensInfo); added DNG 1.1.0.0 tags.
+
+ <li> tif_dir.c, tif_print.c: Added Support for custom tags, passed
+ by value.
+
+ <li> tiff.h, tif_dirinfo.c, tiffiop.h: Added EXIF related tags.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiff2pdf.c: Print two characters per loop in the
+ t2p_write_pdf_trailer(). As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=594">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=594</a>
+
+ <li> tiffgt.c: Use MacOS X OpenGL framework when appropriate. As
+ per bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=844">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=844</a>
+
+ <li> ppm2tiff.c: Fixed format string when read PPM file header with
+ the fscanf() function. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=861">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=861</a>
+
+ <li> tiffsplit.c: Check for JPEGTables tag presence before copying.
+
+ <li> tiff2pdfr.c: Calculate the tile width properly; added new
+ option '-b' to use interpolation in output PDF files (Bruno Ledoux).
+
+ <li> tiffdither.c: Copy the PhotometricInterpretation tag from the
+ input file.
+
+ <li> tif2pdf.c: Fixed problem with alpha channel handling as per
+ bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=794">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=794</a>.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> addtiffo/{tif_overview.c, tif_ovrcache.c, tif_ovrcache.h}:
+ Make overviews working for contiguous images.
+
+</UL>
+
+Last updated $Date: 2006/01/04 22:04:46 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.7.4.html b/tiff/html/v3.7.4.html
new file mode 100644
index 0000000..9437320
--- /dev/null
+++ b/tiff/html/v3.7.4.html
@@ -0,0 +1,133 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.7.4
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.7.4<BR>
+<B>Previous Version</B>: <A HREF=v3.7.3.html>v3.7.3</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+ <li> Fixed important bug in custom tags handling code..
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> Applied patch from Patrick Welche (all scripts moved in the
+ 'config' and 'm4' directories).
+
+ <li> SConstruct, libtiff/SConstruct: Added the first very preliminary
+ support for SCons software building tool (http://www.scons.org/).
+ This is experimental infrastructure and it will exist along with the
+ autotools stuff.
+
+ <li> port/lfind.c: Added lfind() replacement module.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> tif_dir.c: When prefreeing tv->value in TIFFSetFieldV
+ also set it to NULL to avoid double free when re-setting custom
+ string fields as per:
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=922">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=922</a>
+
+ <li> tif_dir.c: Fixed up support for swapping "double complex"
+ values (128 bits as 2 64 bits doubles). GDAL gcore tests now
+ pass on bigendian (macosx) system.
+
+ <li> libtiff/{tif_dirread.c, tif_dirinfo.c}: Do not upcast BYTEs to
+ SHORTs in the TIFFFetchByteArray(). Remove TIFFFetchExtraSamples()
+ function, use TIFFFetchNormalTag() instead as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=831">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=831</a>
+
+ Remove TIFFFetchExtraSamples() function, use TIFFFetchNormalTag()
+ instead.
+
+ <li> tif_print.c: Fixed printing of the BYTE and SBYTE arrays.
+
+ <li> tif_write.c: Do not check the PlanarConfiguration field in
+ the TIFFWriteCheck() function in case of single band images (as per
+ TIFF spec).
+
+ <li> libtiff/{tif_dir.c, tif_dir.h, tif_dirinfo.c, tif_print.c}:
+ Make FieldOfViewCotangent, MatrixWorldToScreen, MatrixWorldToCamera,
+ ImageFullWidth, ImageFullLength and PrimaryChromaticities tags custom.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiffcp.c: Fixed WhitePoint tag copying.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+ <li> tiffdump.c: Added support for TIFF_IFD datatype.
+
+ <li> addtiffo/{tif_overview.c, tif_ovrcache.c, tif_ovrcache.h}:
+ Make overviews working for contiguous images.
+
+</UL>
+
+Last updated $Date: 2005/11/03 14:18:43 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.8.0.html b/tiff/html/v3.8.0.html
new file mode 100644
index 0000000..914dcb0
--- /dev/null
+++ b/tiff/html/v3.8.0.html
@@ -0,0 +1,199 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.8.0
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.8.0<BR>
+<B>Previous Version</B>: <A HREF=v3.7.4.html>v3.7.4</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+ <li> Read-only support for custom directories (e.g. EXIF directory).
+
+ <li> Preliminary support for MS MDI format.
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> Make the default strip size configurable via the
+ --with-default-strip-size and STRIP_SIZE_DEFAULT options.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> tiffio.h: Added VC_EXTRALEAN definition before including
+ windows.h, to reduce the compile time.
+
+ <li> tif_jpeg.c: Improve compilation under MinGW.
+
+ <li> {tif_aux.c, tif_dir.c, tif_dir.h, tif_dirwrite.c,
+ tif_print.c, tif_getimage.c}: Make InkSet, NumberOfInks, DotRange and
+ StoNits tags custom.
+
+ <li> {tif_aux.c, tif_dir.c, tif_dir.h, tif_print.c}: Make
+ WhitePoint tag custom.
+
+ <li> tiffio.h: fixed typo that potentially resulted in
+ redefininition of USE_WIN32_FILEIO
+
+ <li> {tif_dir.c, tif_dir.h, tif_print.c}: Make RichTIFFIPTC,
+ Photoshop and ICCProfile tags custom.
+
+ <li> libtiff/*, contrib/*: Added 'dual-mode' error handling, enabling
+ newer code to get context indicator in error handler and still
+ remain compatible with older code: Done TIFFError calls everywhere
+ except in tools.
+
+ <li> tiffinfo.c: Print EXIF directory contents if exist.
+
+ <li> {tif_dirinfo.c, tif_dirread.c, tif_dir.h, tif_dir.c}:
+ Custom directory read-only support.
+
+ <li> {tif_aux.c, tif_dirinfo.c, tif_dirread.c, tif_dir.h,
+ tif_dir.c, tif_print.c}: Make YCbCrCoefficients and ReferenceBlackWhite
+ tags custom.
+
+ <li> tif_dirread.c: One more workaround for broken StripByteCounts
+ tag. Handle the case when StripByteCounts array filled with
+ completely wrong values.
+
+ <li> tif_dirinfo.c: Release file descriptor in case of failure
+ in the TIFFOpenW() function as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1003">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1003</a>
+
+ <li> tif_dirinfo.c: Correctly yse bsearch() and lfind()
+ functions as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1008">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1008</a>
+
+ <li> tif_open.c, tiff.h, tiffdump.c: Incorporate preliminary support
+ for MS MDI format.
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1002">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1002</a>
+
+ <li> libtiff.def, tiffiop.h, tiffio.h: Made TIFFFreeDirectory
+ public.
+
+ <li> /tif_dirinfo.c: Make XResolution, YResolution and
+ ResolutionUnit tags modifiable during write process. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=977">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=977</a>
+
+ <li> if_dirread.c: Don't try and split single strips into "0" strips
+ in ChopUpSingleUncompressedStrip. This happens in some degenerate
+ cases (like 1x1 files with stripbytecounts==0 (gtsmall.jp2 embed tiff)
+
+ <li> tif_fax3.c: changed 'at scanline ...' style warning/errors
+ with incorrect use of tif_row, to 'at line ... of
+ strip/tile ...' style.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiffcp.c: Added many error reporting messages; fixed integer
+ overflow as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=789">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=789</a>
+
+ <li> tiffcp.c: Return non-zero status when reading fails.
+
+ <li> fax2tiff.c: Properly calculate sizes of temporary arrays
+ as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=943">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=943</a>
+
+ <li> fax2tiff.c: Added option '-r' to set RowsPerStrip parameter
+ as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=944">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=944</a>
+
+ <li> tiffdump.c: Fixed typeshift and typemask arrays initialization
+ problem as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=946">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=946</a>
+
+ <li> bmp2tiff.c: Fixed possible integer overflow error as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=965">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=965</a>
+
+ <li> tiffsplit.c: Copy fax related fields over splitted parts
+ as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=983">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=983</a>
+
+ <li> tiffdump.c: Fixed crash when reading malformed tags.
+
+ <li> tiff2pdf.c: Added missed 'break' statement as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=932">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=932</a>
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+ <li> contrib/addtiffo/*: Major upgrade by Joris to support subsampled
+ YCbCr images in jpeg compressed TIFF files.
+
+</UL>
+
+Last updated $Date: 2006/01/04 23:38:38 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.8.1.html b/tiff/html/v3.8.1.html
new file mode 100644
index 0000000..9fea140
--- /dev/null
+++ b/tiff/html/v3.8.1.html
@@ -0,0 +1,217 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.8.1
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.8.1<BR>
+<B>Previous Version</B>: <A HREF=v3.8.0.html>v3.8.0</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+ <li> Bug-fix release.
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+ <li> libtool related stuff updated from the 2.1a branch.
+
+ <li> Fix with_default_strip_size comparison as reported by
+ Norihiko Murase.
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+
+ <li> tif_dirread.c: Fixed error reporting in TIFFFetchAnyArray()
+ function as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1102">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1102</a>
+
+ <li> tif_jpeg.c, tif_pixarlog.c, tif_fax3.c, tif_zip.c:
+ Properly restore setfield/getfield methods in cleanup functions. As
+ per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1102">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1102</a>
+
+ <li> tif_lzw.c, tif_pixarlog.c, tif_zip.c: Use
+ TIFFPredictorCleanup() in codec cleanup methods. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1102">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1102</a>
+
+ <li> tif_predict.c, tif_predict.h: Added new function
+ TIFFPredictorCleanup() to restore parent decode/encode/field methods.
+
+ <li> tif_dirread.c: Fixed integer overflow condition in
+ TIFFFetchData() function. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1102">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1102</a>
+
+ <li> tif_ojpeg.c: Set the ReferenceBlackWhite with the
+ TIFFSetField() method, not directly. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1043">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1043</a>
+
+ <li> tif_write.c: Small code rearrangement in TIFFWriteScanline()
+ to avoid crash as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1081">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1081</a>
+
+ <li> tif_dirwrite.c: Properly write TIFFTAG_DOTRANGE tag as per
+ bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1088">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1088</a>
+
+ <li> tif_print.c: Properly read TIFFTAG_PAGENUMBER,
+ TIFFTAG_HALFTONEHINTS, TIFFTAG_YCBCRSUBSAMPLING and TIFFTAG_DOTRANGE
+ tags as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1088">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1088</a>
+
+ <li> tif_tile.c: Fix error reporting in TIFFCheckTile() as per
+ bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1063">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1063</a>
+
+ <li> tif_color.c: Avoid overflow in case of wrong input as per
+ bug <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1065">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1065</a>
+
+ <li> tif_dirinfo.c: Use TIFF_NOTYPE instead of 0 when
+ appropriate. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1033">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1033</a>
+
+ <li> tif_aux.c: Fixed type of temporary variable in
+ _TIFFCheckMalloc() as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=103">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=103</a>
+
+ <li> tif_aux.c: Return static array when fetching default
+ YCbCrCoefficients (another problem, reported a the
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1029">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1029</a>
+ entry).
+
+ <li> tif_dir.c: Special handling for PageNumber, HalftoneHints,
+ YCbCrSubsampling and DotRange tags as per bugs
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1029">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1029</a>
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1034">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1034</a>
+
+ <li> tif_dirread.c: Use _TIFFGetExifFieldInfo() instead of
+ _TIFFGetFieldInfo() in TIFFReadEXIFDirectory() call as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1026">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1026</a>
+
+ <li> tif_dirinfo.c: Change definitions for TIFFTAG_ICCPROFILE,
+ TIFFTAG_PHOTOSHOP, TIFFTAG_RICHTIFFIPTC, TIFFTAG_XMLPACKET:
+ readcount should be uint32 value.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> ppm2tiff.c: Added support for PBM files as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1044">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1044</a>
+
+ <li> tiff2pdf.c: Functions t2p_sample_rgbaa_to_rgb() and
+ t2p_sample_rgba_to_rgb() was used in place of each other, that was
+ resulted in problems with RGBA images with associated alpha.
+ As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1097">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1097</a>
+
+ <li> tiff2ps.c: Properly scale all the pages when converting
+ multipage TIFF with /width/height/center options set. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1080">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1080</a>
+
+ <li> tiff2pdf.c: Do not create output file until all option checks
+ will be done. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1072">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1072</a>
+
+ <li> bmp2tiff.c: Added ability to create multipage TIFFs from the
+ list of input files as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1077">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1077</a>
+
+ <li> tiffgt.c: Avoid crashing in case of image unsupported by
+ TIFFRGBAImage interface.
+
+ <li> tiff2pdf.c: Fixed support for non-YCbCr encoded JPEG
+ compressed TIFF files, per submission from Dan Cobra.
+
+ <li> bmp2tiff, pal2rgb, ppm2tiff, ras2tiff, raw2tiff, sgi2tiff,
+ tiff2bw, tiffcp: Fixed jpeg option processing so -c jpeg:r:50 works
+ properly as per bug:
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1025">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1025</a>
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+</UL>
+
+Last updated $Date: 2006/03/13 14:52:12 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.8.2.html b/tiff/html/v3.8.2.html
new file mode 100644
index 0000000..e648127
--- /dev/null
+++ b/tiff/html/v3.8.2.html
@@ -0,0 +1,137 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.8.2
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.8.2<BR>
+<B>Previous Version</B>: <A HREF=v3.8.1.html>v3.8.1</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+ <li> Bug-fix release.
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+
+ <li> tools/Makefile.am: Use runtime paths linker flags when rpath
+ option enabled.
+
+ <li> Makefiles improvements as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1128">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1128</a>
+
+ <li> Fixed win32 I/O functions usage as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1127">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1127</a>
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> tif_strip.c: Take subsampling in account when calculating
+ TIFFScanlineSize().
+
+ <li> tif_jpeg.c, tif_fax3.c, tif_zip.c, tif_pixarlog.c,
+ tif_lzw.c, tif_luv.c: Use _TIFFSetDefaultCompressionState() in all
+ codec cleanup methods. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1120">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1120</a>
+
+ <li> tif_jpeg.c: Do not cleanup codec state in TIFFInitJPEG(). As
+ per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1119">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1119</a>
+
+ <li> tif_dir.c: Use double type instead of dblparam_t.
+
+ <li> tif_dirread.c: Do not check the PlanarConfig tag presence
+ in TIFFReadDirectory, because it is always set at the start of
+ function and we allow TIFFs without that tag set.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiffcp.c: Do not set RowsPerStrip bigger than image length.
+
+ <li> fax2tiff.c: Fixed wrong TIFFerror() invocations as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1125">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1125</a>
+
+ <li> fax2ps.c: Fixed reading the input stream from stdin as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1124">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1124</a>
+
+ <li> raw2tiff.c: Do not set RowsPerStrip larger than ImageLength.
+ As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1110">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1110</a>
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+</UL>
+
+Last updated $Date: 2006/03/23 14:54:01 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.9.0beta.html b/tiff/html/v3.9.0beta.html
new file mode 100644
index 0000000..053b34a
--- /dev/null
+++ b/tiff/html/v3.9.0beta.html
@@ -0,0 +1,304 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.9.0beta
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.9.0beta<BR>
+<B>Previous Version</B>: <A HREF=v3.8.2.html>v3.8.2</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above).
+If you don't find something listed here, then it was not done in this
+timeframe, or it was not considered important enough to be mentioned.
+The following information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+ <li> New <b>tiffcrop</b> utility contributed by Richard Nolde.
+ <b>tiffcrop</b> does the same as <b>tiffcp</b>, but also can crop,
+ extract, rotate and mirror images.
+
+ <li> tif_jbig.c: Added support for JBIG compression scheme
+ (34661 code), contributed by Lee Howard.
+
+ <li> Totally new implementation of OJPEG module from
+ Joris Van Damme. No need to patch libjpeg anymore. Many OJPEG files
+ should be supported now that was not supported previously.
+
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+
+ <li> tif_config.wince.h, tiffconf.wince.h, tif_wince.c: WinCE-specific
+ compatibility stuff from Mateusz Loskot.
+
+ <li> Rename config.h.vc and tif_config.h.vc to config.vc.h and
+ tif_config.vc.h for easier identification by folks using an IDE.
+
+ <li> configure, configure.ac: OJPEG support enabled by default (i.e.,
+ whe the conformant JPEG support enabled).
+
+ <li> README.vms, Makefile.am, configure.com, libtiff/{Makefile.am,
+ tif_config.h-vms, tif_stream.cxx, tif_vms.c, tiffconf.h-vms}:
+ Added support for OpenVMS by Alexey Chupahin.
+
+ <li> nmake.opt: use /EHsc for VS2005 compatibility. Also define
+ _CRT_SECURE_NO_DEPRECATE to avoid noise on VS2005.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> tif_dirinfo.c (_TIFFFindFieldInfo): Don't attempt to
+ bsearch() on a NULL fieldinfo list.
+ (_TIFFFindFieldInfoByName): Don't attempt to lfind() on a NULL
+ fieldinfo list.
+
+ <li> tif_jpeg.c: Changed JPEGInitializeLibJPEG() so that it
+ will convert from decompressor to compressor or compress to decompress
+ if required by the force arguments. This works around a problem in
+ where the JPEGFixupTestSubsampling() may cause a decompressor to
+ be setup on a directory when later a compressor is required with the
+ force flag set. Occurs with the addtiffo program for instance.
+
+ <li> tif_dirwrite.c: Fixed swapping of byte arrays stored
+ in-place in tag offsets as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1363">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1363</a>
+
+ <li> tif_getimage.c: workaround for 'Fractional scanline' error
+ reading OJPEG images with rowsperstrip that is not a multiple of
+ vertical subsampling factor. This bug is mentioned in
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1390">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1390</a> and
+ <a href="http://www.asmail.be/msg0054766825.html">
+ http://www.asmail.be/msg0054766825.html</a>
+
+ <li> tif_dirread.c: Added special function to handle
+ SubjectDistance EXIF tag as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1362">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1362</a>
+
+ <li> tif_dirread.c, tif_read.c: Type of the byte counters
+ changed from tsize_t to uint32 to be able to work with data arrays
+ larger than 2GB. Fixes bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=890">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=89</a>
+ Idea submitted by Matt Hancher.
+
+ <li> tif_dir.c: Workaround for incorrect TIFFs with
+ ExtraSamples == 999 produced by Corel Draw. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1490">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1490</a>
+
+ <li> tif_write.c: TIFFAppendToStrip() - clear sorted flag if
+ we move a strip.
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1359">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1359</a>
+
+ <li> tif_fax3.c: Save the state of printdir codec dependent method.
+
+ <li> tif_jpeg.c: Save the state of printdir codec dependent method
+ as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1273">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1273</a>
+
+ <li> tif_win32.c: Fixed problem with offset value manipulation
+ as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1322">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1322</a>
+
+ <li> tif_fax3.c, tif_next.c, tif_pixarlog.c: Fixed multiple
+ vulnerabilities, as per Gentoo bug ():
+ <a href="http://bugs.gentoo.org/show_bug.cgi?id=142383">
+ http://bugs.gentoo.org/show_bug.cgi?id=142383</a>
+
+ <li> tif_lzw.c, tif_zip.c: Fixed problems with mixing
+ encoding and decoding on the same read-write TIFF handle. The LZW
+ code can now maintain encode and decode state at the same time. The
+ ZIP code will switch back and forth as needed.
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=757">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=757</a>
+
+ <li> tif_msdos.c: Avoid handle leak for failed opens.
+ c/o Thierry Pierron
+
+ <li> tif_dirwrite.c: take care not to flush out buffer of strip/tile
+ data in _TIFFWriteDirectory if TIFF_BEENWRITING not set. Relates
+ to bug report by Peng Gao with black strip at bottom of images.
+
+ <li> tif_dirwrite.c: make sure to use uint32 for wordcount in
+ TIFFWriteNormanTag if writecount is VARIABLE2 for ASCII fields.
+ It already seems to have been done for other field types. Needed
+ for "tiffset" on files with geotiff ascii text.
+
+ <li> tif_dirinfo.c: Added missed EXIF tag ColorSpace (40961).
+
+ <li> tif_dirread.c: Move IFD fetching code in the separate
+ function TIFFFetchDirectory() avoiding code duplication in
+ TIFFReadDirectory() and TIFFReadCustomDirectory().
+
+ <li>tif_readdir.c: Added case in EstimateStripByteCounts() for tiled
+ files. Modified TIFFReadDirectory() to not invoke
+ EstimateStripByteCounts() for case where entry 0 and 1 are unequal but
+ one of them is zero.
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1204">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1204</a>
+
+ <li> tif_open.c, tif_dirread.c, tiffiop.h: Move IFD looping
+ checking code in the separate function TIFFCheckDirOffset().
+
+ <li> tif_aux.c: Added _TIFFCheckRealloc() function.
+
+ <li> tif_fax3.c: Fixed problems in fax decoder as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1194">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1194</a>
+
+ <li> tif_jbig.c: Added support for JBIG compression scheme
+ (34661 code) contributed by Lee Howard. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=896">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=896</a>
+
+ <li> tif_getimage.c: Added support for planarconfig separate
+ non-subsampled YCbCr (i.e. separate YCbCr with subsampling [1,1]).
+
+ <li> tif_getimage.c: Revision of all RGB(A) put routines:
+ <ul>
+ <li> Conversion of unassociated alpha to associated alpha
+ now done with more performant LUT, and calculation more
+ correct.
+ <li> Conversion of 16bit data to 8bit data now done with
+ more performant LUT, and calculation more correct
+ <li> Bugfix of handling of 16bit RGB with unassociated alpha
+ </ul>
+
+ <li> tif_ojpeg.c: totally new implementation
+
+ <li> tif_getimage.c: removed TIFFTAG_JPEGCOLORMODE handling
+ of OJPEG images in favor of tif_getimage.c native handling of
+ YCbCr and desubsampling.
+
+ <li> tif_jpeg.c: JPEGVSetField() so that altering the photometric
+ interpretation causes the "upsampled" flag to be recomputed. Fixes
+ peculiar bug where photometric flag had to be set before jpegcolormode
+ flag.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> tiff2ps.c: Added support 16-bit images as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1566">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1566</a>.
+ Patch from William Bader.
+
+ <li> tiff2pdf.c: Fix for TIFFTAG_JPEGTABLES tag fetching and
+ significant upgrade of the whole utility as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1560">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1560</a>.
+ Now we don't need tiffiop.h in tiff2pdf anymore and will open output
+ PDF file using TIFFClientOpen() machinery as it is implemented
+ by Leon Bottou.
+
+ <li> tiffcrop.c: New tiffcrop utility contributed
+ by Richard Nolde. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1383">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1383</a>
+
+ <li> tiff2pdf.c: Do not assume inches when the resolution units
+ do not specified. As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1366">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1366</a>
+
+ <li> tiffset.c: Properly handle tags with TIFF_VARIABLE writecount.
+ As per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1350">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1350</a>
+
+ <li> tif2rgba.c: This utility does not work properly on big-endian
+ architectures. It was fixed including the bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1149">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1149</a>
+
+ <li> tiff2pdf.c: Fix handling of -q values.
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=587">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=587</a>
+
+ <li> tiffcmp.c: Fixed floating point comparison logic as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1191">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1191</a>
+
+ <li> tiff2pdf.c: Fixed buffer overflow condition in
+ t2p_write_pdf_string() as per bug
+ <a href="http://bugzilla.remotesensing.org/show_bug.cgi?id=1196">
+ http://bugzilla.remotesensing.org/show_bug.cgi?id=1196</a>
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> contrib/addtiffo/tif_overview.c: Fix problems with odd sized
+ output blocks in TIFF_DownSample_Subsampled() (bug 1542).
+
+ <li> contrib/dbs/xtiff/xtiff.c: Make xtiff utility compilable.
+ Though it is still far from the state of being working and useful.
+
+</UL>
+
+Last updated $Date: 2007/07/13 13:40:12 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.9.1.html b/tiff/html/v3.9.1.html
new file mode 100644
index 0000000..9322848
--- /dev/null
+++ b/tiff/html/v3.9.1.html
@@ -0,0 +1,115 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.9.1
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.9.1<BR>
+<B>Previous Version</B>: <A HREF=v3.9.1.html>v3.9.1</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above). If you don't
+find something listed here, then it was not done in this timeframe, or
+it was not considered important enough to be mentioned. The following
+information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+ <li> This is a bug-fix release for several bugs (two of which
+ are dire) which were discovered in the 3.9.0 release.
+
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+
+ <li> Several defines were missing from tif_config.vc.h which
+ are necessary to compile the library using MSVC.
+
+ <li> Colorized tests were actually not enabled as expected.
+ Parallel tests mode is now also enabled so that tests can be
+ run in parallel, and test output is sent to .log files.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> libtiff/tif_write.c (TIFFAppendToStrip): Remove cast
+ which caused libtiff to output a wrong last strip with
+ byte-count and strip-offset of zero. This cast was added on
+ the day of the 3.9.0 release.
+
+ <li> libtiff/tif_dirwrite.c: Back out changes from 2007-11-22
+ that resulted in the final strip not being written in some
+ circumstances.
+ http://bugzilla.maptools.org/show_bug.cgi?id=2088
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+ <li> None
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> None
+
+</UL>
+
+Last updated $Date: 2009-08-28 18:49:02 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/html/v3.9.2.html b/tiff/html/v3.9.2.html
new file mode 100644
index 0000000..8d352f3
--- /dev/null
+++ b/tiff/html/v3.9.2.html
@@ -0,0 +1,122 @@
+<HTML>
+<HEAD>
+<TITLE>
+ Changes in TIFF v3.9.2
+</TITLE>
+</HEAD>
+
+<BODY BGCOLOR=white>
+<FONT FACE="Helvetica, Arial, Sans">
+<FONT FACE="Helvetica, Arial, Sans">
+
+<BASEFONT SIZE=4>
+<B><FONT SIZE=+3>T</FONT>IFF <FONT SIZE=+2>C</FONT>HANGE <FONT SIZE=+2>I</FONT>NFORMATION</B>
+<BASEFONT SIZE=3>
+
+<UL>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+<B>Current Version</B>: v3.9.2<BR>
+<B>Previous Version</B>: <A HREF=v3.9.1.html>v3.9.1</a><BR>
+<B>Master FTP Site</B>: <A HREF="ftp://ftp.remotesensing.org/pub/libtiff">
+ftp.remotesensing.org</a>, directory pub/libtiff</A><BR>
+<B>Master HTTP Site</B>: <A HREF="http://www.remotesensing.org/libtiff">
+http://www.remotesensing.org/libtiff</a>
+<HR SIZE=4 WIDTH=65% ALIGN=left>
+</UL>
+
+<P>
+This document describes the changes made to the software between the
+<I>previous</I> and <I>current</I> versions (see above). If you don't
+find something listed here, then it was not done in this timeframe, or
+it was not considered important enough to be mentioned. The following
+information is located here:
+<UL>
+<LI><A HREF="#hightlights">Major Changes</A>
+<LI><A HREF="#configure">Changes in the software configuration</A>
+<LI><A HREF="#libtiff">Changes in libtiff</A>
+<LI><A HREF="#tools">Changes in the tools</A>
+<LI><A HREF="#contrib">Changes in the contrib area</A>
+</UL>
+<p>
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="highlights"><B><FONT SIZE=+3>M</FONT>AJOR CHANGES:</B></A>
+
+<UL>
+
+ <li> Fixes a number of bugs present in the 3.9.1 release.
+
+ <li> OJPEG support updated to work with IJG JPEG 7 release.
+
+ <li> Tiffcrop validated for most TIFF storage subformats and sample depths.
+
+</UL>
+
+
+<P><HR WIDTH=65% ALIGN=left>
+<!--------------------------------------------------------------------------->
+
+<A NAME="configure"><B><FONT SIZE=+3>C</FONT>HANGES IN THE SOFTWARE CONFIGURATION:</B></A>
+
+<UL>
+
+ <li> x86_64 now uses the same default fill order as i386.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="libtiff"><B><FONT SIZE=+3>C</FONT>HANGES IN LIBTIFF:</B></A>
+
+<UL>
+ <li> Writing tags with an array value of type TIFF_DOUBLE now
+ returns correct error status. The TIFFTAG_SMINSAMPLEVALUE and
+ TIFFTAG_SMAXSAMPLEVALUE tags failed to write without this fix.
+
+ <li> OJPEG decoder now works with IJG JPEG 7. Resolves "Bug
+ 2090 - OJPEG crash with libjpeg v7".
+ http://bugzilla.maptools.org/show_bug.cgi?id=2090
+
+ <li> Eliminate most GCC "dereferencing type-punned pointer"
+ warnings.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!-------------------------------------------------------------------------->
+
+<A NAME="tools"><B><FONT SIZE=+3>C</FONT>HANGES IN THE TOOLS:</B></A>
+
+<UL>
+
+ <li> New tiffcrop from Richard Nolde. Major updates to add
+ significant functionality for reading and writing tile based
+ images with bit depths not a multiple of 8 which cannot be
+ handled by tiffcp.
+
+ <li> Allow building tools with GCC using the "-Wformat
+ -Werror=format-security" flags.
+
+</UL>
+
+<P><HR WIDTH=65% ALIGN=left>
+
+<!--------------------------------------------------------------------------->
+
+<A NAME="contrib"><B><FONT SIZE=+3>C</FONT>HANGES IN THE CONTRIB AREA:</B></A>
+
+<UL>
+
+ <li> None
+
+</UL>
+
+Last updated $Date: 2009-11-04 17:28:46 $.
+
+</BODY>
+</HTML>
diff --git a/tiff/libtiff/Makefile.am b/tiff/libtiff/Makefile.am
new file mode 100644
index 0000000..b918bb9
--- /dev/null
+++ b/tiff/libtiff/Makefile.am
@@ -0,0 +1,143 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+LIBPORT = $(top_builddir)/port/libport.la
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+libtiffincludedir = $(includedir)
+
+EXTRA_DIST = Makefile.vc \
+ SConstruct \
+ tif_config.h-vms \
+ tif_config.vc.h \
+ tif_config.wince.h \
+ tiffconf.vc.h \
+ tiffconf.wince.h \
+ libtiff.def \
+ $(EXTRA_SRCS)
+
+libtiffinclude_HEADERS = \
+ tiff.h \
+ tiffio.h \
+ tiffvers.h
+
+if HAVE_CXX
+libtiffinclude_HEADERS += tiffio.hxx
+endif
+
+noinst_HEADERS = \
+ t4.h \
+ tif_dir.h \
+ tif_predict.h \
+ tiffiop.h \
+ uvcode.h
+
+nodist_libtiffinclude_HEADERS = \
+ tiffconf.h
+
+libtiff_la_SOURCES = \
+ tif_aux.c \
+ tif_close.c \
+ tif_codec.c \
+ tif_color.c \
+ tif_compress.c \
+ tif_dir.c \
+ tif_dirinfo.c \
+ tif_dirread.c \
+ tif_dirwrite.c \
+ tif_dumpmode.c \
+ tif_error.c \
+ tif_extension.c \
+ tif_fax3.c \
+ tif_fax3sm.c \
+ tif_flush.c \
+ tif_getimage.c \
+ tif_jbig.c \
+ tif_jpeg.c \
+ tif_luv.c \
+ tif_lzw.c \
+ tif_next.c \
+ tif_ojpeg.c \
+ tif_open.c \
+ tif_packbits.c \
+ tif_pixarlog.c \
+ tif_predict.c \
+ tif_print.c \
+ tif_read.c \
+ tif_strip.c \
+ tif_swab.c \
+ tif_thunder.c \
+ tif_tile.c \
+ tif_unix.c \
+ tif_version.c \
+ tif_warning.c \
+ tif_write.c \
+ tif_zip.c
+
+libtiffxx_la_SOURCES = \
+ tif_stream.cxx
+
+EXTRA_SRCS = \
+ tif_acorn.c \
+ tif_apple.c \
+ tif_atari.c \
+ tif_msdos.c \
+ tif_next.c \
+ tif_win3.c \
+ tif_win32.c
+
+lib_LTLIBRARIES = libtiff.la
+if HAVE_CXX
+lib_LTLIBRARIES += libtiffxx.la
+endif
+
+libtiff_la_LDFLAGS = \
+ -no-undefined \
+ -version-number $(LIBTIFF_VERSION_INFO)
+if HAVE_RPATH
+libtiff_la_LDFLAGS += $(LIBDIR)
+endif
+libtiff_la_LIBADD = $(LIBPORT)
+
+libtiffxx_la_LDFLAGS = \
+ -no-undefined \
+ -version-number $(LIBTIFF_VERSION_INFO)
+if HAVE_RPATH
+libtiffxx_la_LDFLAGS += $(LIBDIR)
+endif
+libtiffxx_la_LIBADD = $(LIBTIFF) $(LIBPORT)
+libtiffxx_la_DEPENDENCIES = libtiff.la
+
+#
+# The finite state machine tables used by the G3/G4 decoders
+# are generated by the mkg3states program. On systems without
+# make these rules have to be manually carried out.
+#
+noinst_PROGRAMS = mkg3states
+mkg3states_SOURCES = mkg3states.c tif_fax3.h
+mkg3states_LDADD = $(LIBPORT)
+
+faxtable: mkg3states
+ (rm -f tif_fax3sm.c && ./mkg3states -b -c const tif_fax3sm.c)
+
diff --git a/tiff/libtiff/Makefile.in b/tiff/libtiff/Makefile.in
new file mode 100644
index 0000000..52b10e6
--- /dev/null
+++ b/tiff/libtiff/Makefile.in
@@ -0,0 +1,887 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@HAVE_CXX_TRUE@am__append_1 = tiffio.hxx
+@HAVE_CXX_TRUE@am__append_2 = libtiffxx.la
+@HAVE_RPATH_TRUE@am__append_3 = $(LIBDIR)
+@HAVE_RPATH_TRUE@am__append_4 = $(LIBDIR)
+noinst_PROGRAMS = mkg3states$(EXEEXT)
+subdir = libtiff
+DIST_COMMON = $(am__libtiffinclude_HEADERS_DIST) $(noinst_HEADERS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/tif_config.h.in $(srcdir)/tiffconf.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = tif_config.h tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" \
+ "$(DESTDIR)$(libtiffincludedir)" \
+ "$(DESTDIR)$(libtiffincludedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libtiff_la_DEPENDENCIES = $(LIBPORT)
+am_libtiff_la_OBJECTS = tif_aux.lo tif_close.lo tif_codec.lo \
+ tif_color.lo tif_compress.lo tif_dir.lo tif_dirinfo.lo \
+ tif_dirread.lo tif_dirwrite.lo tif_dumpmode.lo tif_error.lo \
+ tif_extension.lo tif_fax3.lo tif_fax3sm.lo tif_flush.lo \
+ tif_getimage.lo tif_jbig.lo tif_jpeg.lo tif_luv.lo tif_lzw.lo \
+ tif_next.lo tif_ojpeg.lo tif_open.lo tif_packbits.lo \
+ tif_pixarlog.lo tif_predict.lo tif_print.lo tif_read.lo \
+ tif_strip.lo tif_swab.lo tif_thunder.lo tif_tile.lo \
+ tif_unix.lo tif_version.lo tif_warning.lo tif_write.lo \
+ tif_zip.lo
+libtiff_la_OBJECTS = $(am_libtiff_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libtiff_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libtiff_la_LDFLAGS) $(LDFLAGS) -o $@
+am_libtiffxx_la_OBJECTS = tif_stream.lo
+libtiffxx_la_OBJECTS = $(am_libtiffxx_la_OBJECTS)
+libtiffxx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(libtiffxx_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_CXX_TRUE@am_libtiffxx_la_rpath = -rpath $(libdir)
+PROGRAMS = $(noinst_PROGRAMS)
+am_mkg3states_OBJECTS = mkg3states.$(OBJEXT)
+mkg3states_OBJECTS = $(am_mkg3states_OBJECTS)
+mkg3states_DEPENDENCIES = $(LIBPORT)
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_$(V))
+am__v_CXX_ = $(am__v_CXX_$(AM_DEFAULT_VERBOSITY))
+am__v_CXX_0 = @echo " CXX " $@;
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_$(V))
+am__v_CXXLD_ = $(am__v_CXXLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libtiff_la_SOURCES) $(libtiffxx_la_SOURCES) \
+ $(mkg3states_SOURCES)
+DIST_SOURCES = $(libtiff_la_SOURCES) $(libtiffxx_la_SOURCES) \
+ $(mkg3states_SOURCES)
+am__libtiffinclude_HEADERS_DIST = tiff.h tiffio.h tiffvers.h \
+ tiffio.hxx
+HEADERS = $(libtiffinclude_HEADERS) $(nodist_libtiffinclude_HEADERS) \
+ $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+LIBPORT = $(top_builddir)/port/libport.la
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+libtiffincludedir = $(includedir)
+EXTRA_DIST = Makefile.vc \
+ SConstruct \
+ tif_config.h-vms \
+ tif_config.vc.h \
+ tif_config.wince.h \
+ tiffconf.vc.h \
+ tiffconf.wince.h \
+ libtiff.def \
+ $(EXTRA_SRCS)
+
+libtiffinclude_HEADERS = tiff.h tiffio.h tiffvers.h $(am__append_1)
+noinst_HEADERS = \
+ t4.h \
+ tif_dir.h \
+ tif_predict.h \
+ tiffiop.h \
+ uvcode.h
+
+nodist_libtiffinclude_HEADERS = \
+ tiffconf.h
+
+libtiff_la_SOURCES = \
+ tif_aux.c \
+ tif_close.c \
+ tif_codec.c \
+ tif_color.c \
+ tif_compress.c \
+ tif_dir.c \
+ tif_dirinfo.c \
+ tif_dirread.c \
+ tif_dirwrite.c \
+ tif_dumpmode.c \
+ tif_error.c \
+ tif_extension.c \
+ tif_fax3.c \
+ tif_fax3sm.c \
+ tif_flush.c \
+ tif_getimage.c \
+ tif_jbig.c \
+ tif_jpeg.c \
+ tif_luv.c \
+ tif_lzw.c \
+ tif_next.c \
+ tif_ojpeg.c \
+ tif_open.c \
+ tif_packbits.c \
+ tif_pixarlog.c \
+ tif_predict.c \
+ tif_print.c \
+ tif_read.c \
+ tif_strip.c \
+ tif_swab.c \
+ tif_thunder.c \
+ tif_tile.c \
+ tif_unix.c \
+ tif_version.c \
+ tif_warning.c \
+ tif_write.c \
+ tif_zip.c
+
+libtiffxx_la_SOURCES = \
+ tif_stream.cxx
+
+EXTRA_SRCS = \
+ tif_acorn.c \
+ tif_apple.c \
+ tif_atari.c \
+ tif_msdos.c \
+ tif_next.c \
+ tif_win3.c \
+ tif_win32.c
+
+lib_LTLIBRARIES = libtiff.la $(am__append_2)
+libtiff_la_LDFLAGS = -no-undefined -version-number \
+ $(LIBTIFF_VERSION_INFO) $(am__append_3)
+libtiff_la_LIBADD = $(LIBPORT)
+libtiffxx_la_LDFLAGS = -no-undefined -version-number \
+ $(LIBTIFF_VERSION_INFO) $(am__append_4)
+libtiffxx_la_LIBADD = $(LIBTIFF) $(LIBPORT)
+libtiffxx_la_DEPENDENCIES = libtiff.la
+mkg3states_SOURCES = mkg3states.c tif_fax3.h
+mkg3states_LDADD = $(LIBPORT)
+all: tif_config.h tiffconf.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cxx .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libtiff/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign libtiff/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+tif_config.h: stamp-h1
+ @if test ! -f $@; then \
+ rm -f stamp-h1; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+ else :; fi
+
+stamp-h1: $(srcdir)/tif_config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status libtiff/tif_config.h
+$(srcdir)/tif_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+tiffconf.h: stamp-h2
+ @if test ! -f $@; then \
+ rm -f stamp-h2; \
+ $(MAKE) $(AM_MAKEFLAGS) stamp-h2; \
+ else :; fi
+
+stamp-h2: $(srcdir)/tiffconf.h.in $(top_builddir)/config.status
+ @rm -f stamp-h2
+ cd $(top_builddir) && $(SHELL) ./config.status libtiff/tiffconf.h
+
+distclean-hdr:
+ -rm -f tif_config.h stamp-h1 tiffconf.h stamp-h2
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libtiff.la: $(libtiff_la_OBJECTS) $(libtiff_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libtiff_la_LINK) -rpath $(libdir) $(libtiff_la_OBJECTS) $(libtiff_la_LIBADD) $(LIBS)
+libtiffxx.la: $(libtiffxx_la_OBJECTS) $(libtiffxx_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libtiffxx_la_LINK) $(am_libtiffxx_la_rpath) $(libtiffxx_la_OBJECTS) $(libtiffxx_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+mkg3states$(EXEEXT): $(mkg3states_OBJECTS) $(mkg3states_DEPENDENCIES)
+ @rm -f mkg3states$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(mkg3states_OBJECTS) $(mkg3states_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mkg3states.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_aux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_close.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_codec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_color.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_compress.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_dir.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_dirinfo.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_dirread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_dirwrite.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_dumpmode.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_error.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_extension.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_fax3.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_fax3sm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_flush.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_getimage.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_jbig.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_jpeg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_luv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_lzw.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_next.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_ojpeg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_open.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_packbits.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_pixarlog.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_predict.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_read.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_stream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_strip.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_swab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_thunder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_tile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_unix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_version.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_warning.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_write.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tif_zip.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+.cxx.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $<
+
+.cxx.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cxx.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-libtiffincludeHEADERS: $(libtiffinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(libtiffincludedir)" || $(MKDIR_P) "$(DESTDIR)$(libtiffincludedir)"
+ @list='$(libtiffinclude_HEADERS)'; test -n "$(libtiffincludedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libtiffincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libtiffincludedir)" || exit $$?; \
+ done
+
+uninstall-libtiffincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libtiffinclude_HEADERS)'; test -n "$(libtiffincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libtiffincludedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libtiffincludedir)" && rm -f $$files
+install-nodist_libtiffincludeHEADERS: $(nodist_libtiffinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(libtiffincludedir)" || $(MKDIR_P) "$(DESTDIR)$(libtiffincludedir)"
+ @list='$(nodist_libtiffinclude_HEADERS)'; test -n "$(libtiffincludedir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libtiffincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libtiffincludedir)" || exit $$?; \
+ done
+
+uninstall-nodist_libtiffincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_libtiffinclude_HEADERS)'; test -n "$(libtiffincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(libtiffincludedir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(libtiffincludedir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) tif_config.h.in tiffconf.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) tif_config.h.in tiffconf.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) tif_config.h.in tiffconf.h.in $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) tif_config.h.in tiffconf.h.in $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS) tif_config.h \
+ tiffconf.h
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libtiffincludedir)" "$(DESTDIR)$(libtiffincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-libtiffincludeHEADERS \
+ install-nodist_libtiffincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES uninstall-libtiffincludeHEADERS \
+ uninstall-nodist_libtiffincludeHEADERS
+
+.MAKE: all install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS ctags \
+ distclean distclean-compile distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES \
+ install-libtiffincludeHEADERS install-man \
+ install-nodist_libtiffincludeHEADERS install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-libLTLIBRARIES \
+ uninstall-libtiffincludeHEADERS \
+ uninstall-nodist_libtiffincludeHEADERS
+
+
+faxtable: mkg3states
+ (rm -f tif_fax3sm.c && ./mkg3states -b -c const tif_fax3sm.c)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/libtiff/Makefile.vc b/tiff/libtiff/Makefile.vc
new file mode 100644
index 0000000..96e8289
--- /dev/null
+++ b/tiff/libtiff/Makefile.vc
@@ -0,0 +1,102 @@
+# $Id: Makefile.vc,v 1.17.2.2 2007/07/18 14:30:05 dron Exp $
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+# Makefile for MS Visual C and Watcom C compilers.
+#
+# To build:
+# C:\libtiff\libtiff> nmake /f makefile.vc all
+#
+
+!INCLUDE ..\nmake.opt
+
+INCL = -I. $(JPEG_INCLUDE) $(ZLIB_INCLUDE) $(JBIG_INCLUDE)
+
+!IFDEF USE_WIN_CRT_LIB
+OBJ_SYSDEP_MODULE = tif_unix.obj
+!ELSE
+OBJ_SYSDEP_MODULE = tif_win32.obj
+!ENDIF
+
+OBJ = \
+ tif_aux.obj \
+ tif_close.obj \
+ tif_codec.obj \
+ tif_color.obj \
+ tif_compress.obj \
+ tif_dir.obj \
+ tif_dirinfo.obj \
+ tif_dirread.obj \
+ tif_dirwrite.obj \
+ tif_dumpmode.obj \
+ tif_error.obj \
+ tif_extension.obj \
+ tif_fax3.obj \
+ tif_fax3sm.obj \
+ tif_getimage.obj \
+ tif_jbig.obj \
+ tif_jpeg.obj \
+ tif_ojpeg.obj \
+ tif_flush.obj \
+ tif_luv.obj \
+ tif_lzw.obj \
+ tif_next.obj \
+ tif_open.obj \
+ tif_packbits.obj \
+ tif_pixarlog.obj \
+ tif_predict.obj \
+ tif_print.obj \
+ tif_read.obj \
+ tif_stream.obj \
+ tif_swab.obj \
+ tif_strip.obj \
+ tif_thunder.obj \
+ tif_tile.obj \
+ tif_version.obj \
+ tif_warning.obj \
+ tif_write.obj \
+ tif_zip.obj \
+ tif_jbig.obj \
+ $(OBJ_SYSDEP_MODULE)
+
+all: libtiff.lib $(DLLNAME)
+
+tif_config.h: tif_config.vc.h
+ copy tif_config.vc.h tif_config.h
+
+tiffconf.h: tiffconf.vc.h
+ copy tiffconf.vc.h tiffconf.h
+
+libtiff.lib: tif_config.h tiffconf.h $(OBJ)
+ $(AR) /out:libtiff.lib $(OBJ) $(LIBS)
+
+$(DLLNAME): tif_config.h tiffconf.h libtiff.def $(OBJ)
+ $(LD) /debug /dll /def:libtiff.def /out:$(DLLNAME) \
+ /implib:libtiff_i.lib $(OBJ) $(LIBS)
+
+clean:
+ -del tif_config.h tiffconf.h
+ -del *.obj
+ -del *.lib
+ -del *.dll
+ -del *.exe
+ -del *.pdb
diff --git a/tiff/libtiff/SConstruct b/tiff/libtiff/SConstruct
new file mode 100644
index 0000000..cb6a7cc
--- /dev/null
+++ b/tiff/libtiff/SConstruct
@@ -0,0 +1,73 @@
+# $Id: SConstruct,v 1.4 2007/02/24 15:03:50 dron Exp $
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2005, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# This file contains rules to build software with the SCons tool
+# (see the http://www.scons.org/ for details on SCons).
+
+# Import globally defined options
+Import([ 'env', 'idir_lib' ])
+
+SRCS = [ \
+ 'tif_aux.c', \
+ 'tif_close.c', \
+ 'tif_codec.c', \
+ 'tif_color.c', \
+ 'tif_compress.c', \
+ 'tif_dir.c', \
+ 'tif_dirinfo.c', \
+ 'tif_dirread.c', \
+ 'tif_dirwrite.c', \
+ 'tif_dumpmode.c', \
+ 'tif_error.c', \
+ 'tif_extension.c', \
+ 'tif_fax3.c', \
+ 'tif_fax3sm.c', \
+ 'tif_flush.c', \
+ 'tif_getimage.c', \
+ 'tif_jbig.c', \
+ 'tif_jpeg.c', \
+ 'tif_luv.c', \
+ 'tif_lzw.c', \
+ 'tif_next.c', \
+ 'tif_ojpeg.c', \
+ 'tif_open.c', \
+ 'tif_packbits.c', \
+ 'tif_pixarlog.c', \
+ 'tif_predict.c', \
+ 'tif_print.c', \
+ 'tif_read.c', \
+ 'tif_strip.c', \
+ 'tif_swab.c', \
+ 'tif_thunder.c', \
+ 'tif_tile.c', \
+ 'tif_unix.c', \
+ 'tif_version.c', \
+ 'tif_warning.c', \
+ 'tif_write.c', \
+ 'tif_zip.c' ]
+
+StaticLibrary('tiff', SRCS)
+SharedLibrary('tiff', SRCS)
+
diff --git a/tiff/libtiff/libtiff.def b/tiff/libtiff/libtiff.def
new file mode 100644
index 0000000..3caefd8
--- /dev/null
+++ b/tiff/libtiff/libtiff.def
@@ -0,0 +1,140 @@
+EXPORTS TIFFOpen
+ TIFFOpenW
+ TIFFGetVersion
+ TIFFCleanup
+ TIFFClose
+ TIFFFlush
+ TIFFFlushData
+ TIFFGetField
+ TIFFVGetField
+ TIFFGetFieldDefaulted
+ TIFFVGetFieldDefaulted
+ TIFFGetTagListEntry
+ TIFFGetTagListCount
+ TIFFReadDirectory
+ TIFFScanlineSize
+ TIFFStripSize
+ TIFFVStripSize
+ TIFFRawStripSize
+ TIFFTileRowSize
+ TIFFTileSize
+ TIFFVTileSize
+ TIFFFileno
+ TIFFSetFileno
+ TIFFGetMode
+ TIFFIsTiled
+ TIFFIsByteSwapped
+ TIFFIsBigEndian
+ TIFFIsMSB2LSB
+ TIFFIsUpSampled
+ TIFFCIELabToRGBInit
+ TIFFCIELabToXYZ
+ TIFFXYZToRGB
+ TIFFYCbCrToRGBInit
+ TIFFYCbCrtoRGB
+ TIFFCurrentRow
+ TIFFCurrentDirectory
+ TIFFCurrentStrip
+ TIFFCurrentTile
+ TIFFDataWidth
+ TIFFReadBufferSetup
+ TIFFWriteBufferSetup
+ TIFFSetupStrips
+ TIFFLastDirectory
+ TIFFSetDirectory
+ TIFFSetSubDirectory
+ TIFFUnlinkDirectory
+ TIFFSetField
+ TIFFVSetField
+ TIFFCheckpointDirectory
+ TIFFWriteDirectory
+ TIFFRewriteDirectory
+ TIFFPrintDirectory
+ TIFFReadScanline
+ TIFFWriteScanline
+ TIFFReadRGBAImage
+ TIFFReadRGBAImageOriented
+ TIFFFdOpen
+ TIFFClientOpen
+ TIFFFileName
+ TIFFError
+ TIFFErrorExt
+ TIFFWarning
+ TIFFWarningExt
+ TIFFSetErrorHandler
+ TIFFSetErrorHandlerExt
+ TIFFSetWarningHandler
+ TIFFSetWarningHandlerExt
+ TIFFComputeTile
+ TIFFCheckTile
+ TIFFNumberOfTiles
+ TIFFReadTile
+ TIFFWriteTile
+ TIFFComputeStrip
+ TIFFNumberOfStrips
+ TIFFRGBAImageBegin
+ TIFFRGBAImageGet
+ TIFFRGBAImageEnd
+ TIFFReadEncodedStrip
+ TIFFReadRawStrip
+ TIFFReadEncodedTile
+ TIFFReadRawTile
+ TIFFReadRGBATile
+ TIFFReadRGBAStrip
+ TIFFWriteEncodedStrip
+ TIFFWriteRawStrip
+ TIFFWriteEncodedTile
+ TIFFWriteRawTile
+ TIFFSetWriteOffset
+ TIFFSwabDouble
+ TIFFSwabShort
+ TIFFSwabLong
+ TIFFSwabArrayOfShort
+ TIFFSwabArrayOfLong
+ TIFFSwabArrayOfDouble
+ TIFFSwabArrayOfTriples
+ TIFFReverseBits
+ TIFFGetBitRevTable
+ TIFFDefaultStripSize
+ TIFFDefaultTileSize
+ TIFFRasterScanlineSize
+ _TIFFmalloc
+ _TIFFrealloc
+ _TIFFfree
+ _TIFFmemset
+ _TIFFmemcpy
+ _TIFFmemcmp
+ TIFFCreateDirectory
+ TIFFSetTagExtender
+ TIFFMergeFieldInfo
+ TIFFFindFieldInfo
+ TIFFFindFieldInfoByName
+ TIFFFieldWithName
+ TIFFFieldWithTag
+ TIFFCurrentDirOffset
+ TIFFWriteCheck
+ TIFFRGBAImageOK
+ TIFFNumberOfDirectories
+ TIFFSetFileName
+ TIFFSetClientdata
+ TIFFSetMode
+ TIFFClientdata
+ TIFFGetReadProc
+ TIFFGetWriteProc
+ TIFFGetSeekProc
+ TIFFGetCloseProc
+ TIFFGetSizeProc
+ TIFFGetMapFileProc
+ TIFFGetUnmapFileProc
+ TIFFIsCODECConfigured
+ TIFFGetConfiguredCODECs
+ TIFFFindCODEC
+ TIFFRegisterCODEC
+ TIFFUnRegisterCODEC
+ TIFFFreeDirectory
+ TIFFReadCustomDirectory
+ TIFFReadEXIFDirectory
+ TIFFAccessTagMethods
+ TIFFGetClientInfo
+ TIFFSetClientInfo
+ TIFFReassignTagToIgnore
diff --git a/tiff/libtiff/mkg3states.c b/tiff/libtiff/mkg3states.c
new file mode 100644
index 0000000..7f4346b
--- /dev/null
+++ b/tiff/libtiff/mkg3states.c
@@ -0,0 +1,451 @@
+/* "$Id: mkg3states.c,v 1.10.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/* Initialise fax decoder tables
+ * Decoder support is derived, with permission, from the code
+ * in Frank Cringle's viewfax program;
+ * Copyright (C) 1990, 1995 Frank D. Cringle.
+ */
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tif_fax3.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+
+/* NB: can't use names in tif_fax3.h 'cuz they are declared const */
+TIFFFaxTabEnt MainTable[128];
+TIFFFaxTabEnt WhiteTable[4096];
+TIFFFaxTabEnt BlackTable[8192];
+
+struct proto {
+ uint16 code; /* right justified, lsb-first, zero filled */
+ uint16 val; /* (pixel count)<<4 + code width */
+};
+
+static struct proto Pass[] = {
+{ 0x0008, 4 },
+{ 0, 0 }
+};
+
+static struct proto Horiz[] = {
+{ 0x0004, 3 },
+{ 0, 0 }
+};
+
+static struct proto V0[] = {
+{ 0x0001, 1 },
+{ 0, 0 }
+};
+
+static struct proto VR[] = {
+{ 0x0006, (1<<4)+3 },
+{ 0x0030, (2<<4)+6 },
+{ 0x0060, (3<<4)+7 },
+{ 0, 0 }
+};
+
+static struct proto VL[] = {
+{ 0x0002, (1<<4)+3 },
+{ 0x0010, (2<<4)+6 },
+{ 0x0020, (3<<4)+7 },
+{ 0, 0 }
+};
+
+static struct proto Ext[] = {
+{ 0x0040, 7 },
+{ 0, 0 }
+};
+
+static struct proto EOLV[] = {
+{ 0x0000, 7 },
+{ 0, 0 }
+};
+
+static struct proto MakeUpW[] = {
+{ 0x001b, 1029 },
+{ 0x0009, 2053 },
+{ 0x003a, 3078 },
+{ 0x0076, 4103 },
+{ 0x006c, 5128 },
+{ 0x00ec, 6152 },
+{ 0x0026, 7176 },
+{ 0x00a6, 8200 },
+{ 0x0016, 9224 },
+{ 0x00e6, 10248 },
+{ 0x0066, 11273 },
+{ 0x0166, 12297 },
+{ 0x0096, 13321 },
+{ 0x0196, 14345 },
+{ 0x0056, 15369 },
+{ 0x0156, 16393 },
+{ 0x00d6, 17417 },
+{ 0x01d6, 18441 },
+{ 0x0036, 19465 },
+{ 0x0136, 20489 },
+{ 0x00b6, 21513 },
+{ 0x01b6, 22537 },
+{ 0x0032, 23561 },
+{ 0x0132, 24585 },
+{ 0x00b2, 25609 },
+{ 0x0006, 26630 },
+{ 0x01b2, 27657 },
+{ 0, 0 }
+};
+
+static struct proto MakeUpB[] = {
+{ 0x03c0, 1034 },
+{ 0x0130, 2060 },
+{ 0x0930, 3084 },
+{ 0x0da0, 4108 },
+{ 0x0cc0, 5132 },
+{ 0x02c0, 6156 },
+{ 0x0ac0, 7180 },
+{ 0x06c0, 8205 },
+{ 0x16c0, 9229 },
+{ 0x0a40, 10253 },
+{ 0x1a40, 11277 },
+{ 0x0640, 12301 },
+{ 0x1640, 13325 },
+{ 0x09c0, 14349 },
+{ 0x19c0, 15373 },
+{ 0x05c0, 16397 },
+{ 0x15c0, 17421 },
+{ 0x0dc0, 18445 },
+{ 0x1dc0, 19469 },
+{ 0x0940, 20493 },
+{ 0x1940, 21517 },
+{ 0x0540, 22541 },
+{ 0x1540, 23565 },
+{ 0x0b40, 24589 },
+{ 0x1b40, 25613 },
+{ 0x04c0, 26637 },
+{ 0x14c0, 27661 },
+{ 0, 0 }
+};
+
+static struct proto MakeUp[] = {
+{ 0x0080, 28683 },
+{ 0x0180, 29707 },
+{ 0x0580, 30731 },
+{ 0x0480, 31756 },
+{ 0x0c80, 32780 },
+{ 0x0280, 33804 },
+{ 0x0a80, 34828 },
+{ 0x0680, 35852 },
+{ 0x0e80, 36876 },
+{ 0x0380, 37900 },
+{ 0x0b80, 38924 },
+{ 0x0780, 39948 },
+{ 0x0f80, 40972 },
+{ 0, 0 }
+};
+
+static struct proto TermW[] = {
+{ 0x00ac, 8 },
+{ 0x0038, 22 },
+{ 0x000e, 36 },
+{ 0x0001, 52 },
+{ 0x000d, 68 },
+{ 0x0003, 84 },
+{ 0x0007, 100 },
+{ 0x000f, 116 },
+{ 0x0019, 133 },
+{ 0x0005, 149 },
+{ 0x001c, 165 },
+{ 0x0002, 181 },
+{ 0x0004, 198 },
+{ 0x0030, 214 },
+{ 0x000b, 230 },
+{ 0x002b, 246 },
+{ 0x0015, 262 },
+{ 0x0035, 278 },
+{ 0x0072, 295 },
+{ 0x0018, 311 },
+{ 0x0008, 327 },
+{ 0x0074, 343 },
+{ 0x0060, 359 },
+{ 0x0010, 375 },
+{ 0x000a, 391 },
+{ 0x006a, 407 },
+{ 0x0064, 423 },
+{ 0x0012, 439 },
+{ 0x000c, 455 },
+{ 0x0040, 472 },
+{ 0x00c0, 488 },
+{ 0x0058, 504 },
+{ 0x00d8, 520 },
+{ 0x0048, 536 },
+{ 0x00c8, 552 },
+{ 0x0028, 568 },
+{ 0x00a8, 584 },
+{ 0x0068, 600 },
+{ 0x00e8, 616 },
+{ 0x0014, 632 },
+{ 0x0094, 648 },
+{ 0x0054, 664 },
+{ 0x00d4, 680 },
+{ 0x0034, 696 },
+{ 0x00b4, 712 },
+{ 0x0020, 728 },
+{ 0x00a0, 744 },
+{ 0x0050, 760 },
+{ 0x00d0, 776 },
+{ 0x004a, 792 },
+{ 0x00ca, 808 },
+{ 0x002a, 824 },
+{ 0x00aa, 840 },
+{ 0x0024, 856 },
+{ 0x00a4, 872 },
+{ 0x001a, 888 },
+{ 0x009a, 904 },
+{ 0x005a, 920 },
+{ 0x00da, 936 },
+{ 0x0052, 952 },
+{ 0x00d2, 968 },
+{ 0x004c, 984 },
+{ 0x00cc, 1000 },
+{ 0x002c, 1016 },
+{ 0, 0 }
+};
+
+static struct proto TermB[] = {
+{ 0x03b0, 10 },
+{ 0x0002, 19 },
+{ 0x0003, 34 },
+{ 0x0001, 50 },
+{ 0x0006, 67 },
+{ 0x000c, 84 },
+{ 0x0004, 100 },
+{ 0x0018, 117 },
+{ 0x0028, 134 },
+{ 0x0008, 150 },
+{ 0x0010, 167 },
+{ 0x0050, 183 },
+{ 0x0070, 199 },
+{ 0x0020, 216 },
+{ 0x00e0, 232 },
+{ 0x0030, 249 },
+{ 0x03a0, 266 },
+{ 0x0060, 282 },
+{ 0x0040, 298 },
+{ 0x0730, 315 },
+{ 0x00b0, 331 },
+{ 0x01b0, 347 },
+{ 0x0760, 363 },
+{ 0x00a0, 379 },
+{ 0x0740, 395 },
+{ 0x00c0, 411 },
+{ 0x0530, 428 },
+{ 0x0d30, 444 },
+{ 0x0330, 460 },
+{ 0x0b30, 476 },
+{ 0x0160, 492 },
+{ 0x0960, 508 },
+{ 0x0560, 524 },
+{ 0x0d60, 540 },
+{ 0x04b0, 556 },
+{ 0x0cb0, 572 },
+{ 0x02b0, 588 },
+{ 0x0ab0, 604 },
+{ 0x06b0, 620 },
+{ 0x0eb0, 636 },
+{ 0x0360, 652 },
+{ 0x0b60, 668 },
+{ 0x05b0, 684 },
+{ 0x0db0, 700 },
+{ 0x02a0, 716 },
+{ 0x0aa0, 732 },
+{ 0x06a0, 748 },
+{ 0x0ea0, 764 },
+{ 0x0260, 780 },
+{ 0x0a60, 796 },
+{ 0x04a0, 812 },
+{ 0x0ca0, 828 },
+{ 0x0240, 844 },
+{ 0x0ec0, 860 },
+{ 0x01c0, 876 },
+{ 0x0e40, 892 },
+{ 0x0140, 908 },
+{ 0x01a0, 924 },
+{ 0x09a0, 940 },
+{ 0x0d40, 956 },
+{ 0x0340, 972 },
+{ 0x05a0, 988 },
+{ 0x0660, 1004 },
+{ 0x0e60, 1020 },
+{ 0, 0 }
+};
+
+static struct proto EOLH[] = {
+{ 0x0000, 11 },
+{ 0, 0 }
+};
+
+static void
+FillTable(TIFFFaxTabEnt *T, int Size, struct proto *P, int State)
+{
+ int limit = 1 << Size;
+
+ while (P->val) {
+ int width = P->val & 15;
+ int param = P->val >> 4;
+ int incr = 1 << width;
+ int code;
+ for (code = P->code; code < limit; code += incr) {
+ TIFFFaxTabEnt *E = T+code;
+ E->State = State;
+ E->Width = width;
+ E->Param = param;
+ }
+ P++;
+ }
+}
+
+static char* storage_class = "";
+static char* const_class = "";
+static int packoutput = 1;
+static char* prebrace = "";
+static char* postbrace = "";
+
+void
+WriteTable(FILE* fd, const TIFFFaxTabEnt* T, int Size, const char* name)
+{
+ int i;
+ char* sep;
+
+ fprintf(fd, "%s %s TIFFFaxTabEnt %s[%d] = {",
+ storage_class, const_class, name, Size);
+ if (packoutput) {
+ sep = "\n";
+ for (i = 0; i < Size; i++) {
+ fprintf(fd, "%s%s%d,%d,%d%s",
+ sep, prebrace, T->State, T->Width, (int) T->Param, postbrace);
+ if (((i+1) % 10) == 0)
+ sep = ",\n";
+ else
+ sep = ",";
+ T++;
+ }
+ } else {
+ sep = "\n ";
+ for (i = 0; i < Size; i++) {
+ fprintf(fd, "%s%s%3d,%3d,%4d%s",
+ sep, prebrace, T->State, T->Width, (int) T->Param, postbrace);
+ if (((i+1) % 6) == 0)
+ sep = ",\n ";
+ else
+ sep = ",";
+ T++;
+ }
+ }
+ fprintf(fd, "\n};\n");
+}
+
+/* initialise the huffman code tables */
+int
+main(int argc, char* argv[])
+{
+ FILE* fd;
+ char* outputfile;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:s:bp")) != -1)
+ switch (c) {
+ case 'c':
+ const_class = optarg;
+ break;
+ case 's':
+ storage_class = optarg;
+ break;
+ case 'p':
+ packoutput = 0;
+ break;
+ case 'b':
+ prebrace = "{";
+ postbrace = "}";
+ break;
+ case '?':
+ fprintf(stderr,
+ "usage: %s [-c const] [-s storage] [-p] [-b] file\n",
+ argv[0]);
+ return (-1);
+ }
+ outputfile = optind < argc ? argv[optind] : "g3states.h";
+ fd = fopen(outputfile, "w");
+ if (fd == NULL) {
+ fprintf(stderr, "%s: %s: Cannot create output file.\n",
+ argv[0], outputfile);
+ return (-2);
+ }
+ FillTable(MainTable, 7, Pass, S_Pass);
+ FillTable(MainTable, 7, Horiz, S_Horiz);
+ FillTable(MainTable, 7, V0, S_V0);
+ FillTable(MainTable, 7, VR, S_VR);
+ FillTable(MainTable, 7, VL, S_VL);
+ FillTable(MainTable, 7, Ext, S_Ext);
+ FillTable(MainTable, 7, EOLV, S_EOL);
+ FillTable(WhiteTable, 12, MakeUpW, S_MakeUpW);
+ FillTable(WhiteTable, 12, MakeUp, S_MakeUp);
+ FillTable(WhiteTable, 12, TermW, S_TermW);
+ FillTable(WhiteTable, 12, EOLH, S_EOL);
+ FillTable(BlackTable, 13, MakeUpB, S_MakeUpB);
+ FillTable(BlackTable, 13, MakeUp, S_MakeUp);
+ FillTable(BlackTable, 13, TermB, S_TermB);
+ FillTable(BlackTable, 13, EOLH, S_EOL);
+
+ fprintf(fd, "/* WARNING, this file was automatically generated by the\n");
+ fprintf(fd, " mkg3states program */\n");
+ fprintf(fd, "#include \"tiff.h\"\n");
+ fprintf(fd, "#include \"tif_fax3.h\"\n");
+ WriteTable(fd, MainTable, 128, "TIFFFaxMainTable");
+ WriteTable(fd, WhiteTable, 4096, "TIFFFaxWhiteTable");
+ WriteTable(fd, BlackTable, 8192, "TIFFFaxBlackTable");
+ fclose(fd);
+ return (0);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/t4.h b/tiff/libtiff/t4.h
new file mode 100644
index 0000000..870704f
--- /dev/null
+++ b/tiff/libtiff/t4.h
@@ -0,0 +1,292 @@
+/* $Id: t4.h,v 1.1.1.1.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _T4_
+#define _T4_
+/*
+ * CCITT T.4 1D Huffman runlength codes and
+ * related definitions. Given the small sizes
+ * of these tables it does not seem
+ * worthwhile to make code & length 8 bits.
+ */
+typedef struct tableentry {
+ unsigned short length; /* bit length of g3 code */
+ unsigned short code; /* g3 code */
+ short runlen; /* run length in bits */
+} tableentry;
+
+#define EOL 0x001 /* EOL code value - 0000 0000 0000 1 */
+
+/* status values returned instead of a run length */
+#define G3CODE_EOL -1 /* NB: ACT_EOL - ACT_WRUNT */
+#define G3CODE_INVALID -2 /* NB: ACT_INVALID - ACT_WRUNT */
+#define G3CODE_EOF -3 /* end of input data */
+#define G3CODE_INCOMP -4 /* incomplete run code */
+
+/*
+ * Note that these tables are ordered such that the
+ * index into the table is known to be either the
+ * run length, or (run length / 64) + a fixed offset.
+ *
+ * NB: The G3CODE_INVALID entries are only used
+ * during state generation (see mkg3states.c).
+ */
+#ifdef G3CODES
+const tableentry TIFFFaxWhiteCodes[] = {
+ { 8, 0x35, 0 }, /* 0011 0101 */
+ { 6, 0x7, 1 }, /* 0001 11 */
+ { 4, 0x7, 2 }, /* 0111 */
+ { 4, 0x8, 3 }, /* 1000 */
+ { 4, 0xB, 4 }, /* 1011 */
+ { 4, 0xC, 5 }, /* 1100 */
+ { 4, 0xE, 6 }, /* 1110 */
+ { 4, 0xF, 7 }, /* 1111 */
+ { 5, 0x13, 8 }, /* 1001 1 */
+ { 5, 0x14, 9 }, /* 1010 0 */
+ { 5, 0x7, 10 }, /* 0011 1 */
+ { 5, 0x8, 11 }, /* 0100 0 */
+ { 6, 0x8, 12 }, /* 0010 00 */
+ { 6, 0x3, 13 }, /* 0000 11 */
+ { 6, 0x34, 14 }, /* 1101 00 */
+ { 6, 0x35, 15 }, /* 1101 01 */
+ { 6, 0x2A, 16 }, /* 1010 10 */
+ { 6, 0x2B, 17 }, /* 1010 11 */
+ { 7, 0x27, 18 }, /* 0100 111 */
+ { 7, 0xC, 19 }, /* 0001 100 */
+ { 7, 0x8, 20 }, /* 0001 000 */
+ { 7, 0x17, 21 }, /* 0010 111 */
+ { 7, 0x3, 22 }, /* 0000 011 */
+ { 7, 0x4, 23 }, /* 0000 100 */
+ { 7, 0x28, 24 }, /* 0101 000 */
+ { 7, 0x2B, 25 }, /* 0101 011 */
+ { 7, 0x13, 26 }, /* 0010 011 */
+ { 7, 0x24, 27 }, /* 0100 100 */
+ { 7, 0x18, 28 }, /* 0011 000 */
+ { 8, 0x2, 29 }, /* 0000 0010 */
+ { 8, 0x3, 30 }, /* 0000 0011 */
+ { 8, 0x1A, 31 }, /* 0001 1010 */
+ { 8, 0x1B, 32 }, /* 0001 1011 */
+ { 8, 0x12, 33 }, /* 0001 0010 */
+ { 8, 0x13, 34 }, /* 0001 0011 */
+ { 8, 0x14, 35 }, /* 0001 0100 */
+ { 8, 0x15, 36 }, /* 0001 0101 */
+ { 8, 0x16, 37 }, /* 0001 0110 */
+ { 8, 0x17, 38 }, /* 0001 0111 */
+ { 8, 0x28, 39 }, /* 0010 1000 */
+ { 8, 0x29, 40 }, /* 0010 1001 */
+ { 8, 0x2A, 41 }, /* 0010 1010 */
+ { 8, 0x2B, 42 }, /* 0010 1011 */
+ { 8, 0x2C, 43 }, /* 0010 1100 */
+ { 8, 0x2D, 44 }, /* 0010 1101 */
+ { 8, 0x4, 45 }, /* 0000 0100 */
+ { 8, 0x5, 46 }, /* 0000 0101 */
+ { 8, 0xA, 47 }, /* 0000 1010 */
+ { 8, 0xB, 48 }, /* 0000 1011 */
+ { 8, 0x52, 49 }, /* 0101 0010 */
+ { 8, 0x53, 50 }, /* 0101 0011 */
+ { 8, 0x54, 51 }, /* 0101 0100 */
+ { 8, 0x55, 52 }, /* 0101 0101 */
+ { 8, 0x24, 53 }, /* 0010 0100 */
+ { 8, 0x25, 54 }, /* 0010 0101 */
+ { 8, 0x58, 55 }, /* 0101 1000 */
+ { 8, 0x59, 56 }, /* 0101 1001 */
+ { 8, 0x5A, 57 }, /* 0101 1010 */
+ { 8, 0x5B, 58 }, /* 0101 1011 */
+ { 8, 0x4A, 59 }, /* 0100 1010 */
+ { 8, 0x4B, 60 }, /* 0100 1011 */
+ { 8, 0x32, 61 }, /* 0011 0010 */
+ { 8, 0x33, 62 }, /* 0011 0011 */
+ { 8, 0x34, 63 }, /* 0011 0100 */
+ { 5, 0x1B, 64 }, /* 1101 1 */
+ { 5, 0x12, 128 }, /* 1001 0 */
+ { 6, 0x17, 192 }, /* 0101 11 */
+ { 7, 0x37, 256 }, /* 0110 111 */
+ { 8, 0x36, 320 }, /* 0011 0110 */
+ { 8, 0x37, 384 }, /* 0011 0111 */
+ { 8, 0x64, 448 }, /* 0110 0100 */
+ { 8, 0x65, 512 }, /* 0110 0101 */
+ { 8, 0x68, 576 }, /* 0110 1000 */
+ { 8, 0x67, 640 }, /* 0110 0111 */
+ { 9, 0xCC, 704 }, /* 0110 0110 0 */
+ { 9, 0xCD, 768 }, /* 0110 0110 1 */
+ { 9, 0xD2, 832 }, /* 0110 1001 0 */
+ { 9, 0xD3, 896 }, /* 0110 1001 1 */
+ { 9, 0xD4, 960 }, /* 0110 1010 0 */
+ { 9, 0xD5, 1024 }, /* 0110 1010 1 */
+ { 9, 0xD6, 1088 }, /* 0110 1011 0 */
+ { 9, 0xD7, 1152 }, /* 0110 1011 1 */
+ { 9, 0xD8, 1216 }, /* 0110 1100 0 */
+ { 9, 0xD9, 1280 }, /* 0110 1100 1 */
+ { 9, 0xDA, 1344 }, /* 0110 1101 0 */
+ { 9, 0xDB, 1408 }, /* 0110 1101 1 */
+ { 9, 0x98, 1472 }, /* 0100 1100 0 */
+ { 9, 0x99, 1536 }, /* 0100 1100 1 */
+ { 9, 0x9A, 1600 }, /* 0100 1101 0 */
+ { 6, 0x18, 1664 }, /* 0110 00 */
+ { 9, 0x9B, 1728 }, /* 0100 1101 1 */
+ { 11, 0x8, 1792 }, /* 0000 0001 000 */
+ { 11, 0xC, 1856 }, /* 0000 0001 100 */
+ { 11, 0xD, 1920 }, /* 0000 0001 101 */
+ { 12, 0x12, 1984 }, /* 0000 0001 0010 */
+ { 12, 0x13, 2048 }, /* 0000 0001 0011 */
+ { 12, 0x14, 2112 }, /* 0000 0001 0100 */
+ { 12, 0x15, 2176 }, /* 0000 0001 0101 */
+ { 12, 0x16, 2240 }, /* 0000 0001 0110 */
+ { 12, 0x17, 2304 }, /* 0000 0001 0111 */
+ { 12, 0x1C, 2368 }, /* 0000 0001 1100 */
+ { 12, 0x1D, 2432 }, /* 0000 0001 1101 */
+ { 12, 0x1E, 2496 }, /* 0000 0001 1110 */
+ { 12, 0x1F, 2560 }, /* 0000 0001 1111 */
+ { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */
+ { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */
+ { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */
+ { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */
+ { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */
+};
+
+const tableentry TIFFFaxBlackCodes[] = {
+ { 10, 0x37, 0 }, /* 0000 1101 11 */
+ { 3, 0x2, 1 }, /* 010 */
+ { 2, 0x3, 2 }, /* 11 */
+ { 2, 0x2, 3 }, /* 10 */
+ { 3, 0x3, 4 }, /* 011 */
+ { 4, 0x3, 5 }, /* 0011 */
+ { 4, 0x2, 6 }, /* 0010 */
+ { 5, 0x3, 7 }, /* 0001 1 */
+ { 6, 0x5, 8 }, /* 0001 01 */
+ { 6, 0x4, 9 }, /* 0001 00 */
+ { 7, 0x4, 10 }, /* 0000 100 */
+ { 7, 0x5, 11 }, /* 0000 101 */
+ { 7, 0x7, 12 }, /* 0000 111 */
+ { 8, 0x4, 13 }, /* 0000 0100 */
+ { 8, 0x7, 14 }, /* 0000 0111 */
+ { 9, 0x18, 15 }, /* 0000 1100 0 */
+ { 10, 0x17, 16 }, /* 0000 0101 11 */
+ { 10, 0x18, 17 }, /* 0000 0110 00 */
+ { 10, 0x8, 18 }, /* 0000 0010 00 */
+ { 11, 0x67, 19 }, /* 0000 1100 111 */
+ { 11, 0x68, 20 }, /* 0000 1101 000 */
+ { 11, 0x6C, 21 }, /* 0000 1101 100 */
+ { 11, 0x37, 22 }, /* 0000 0110 111 */
+ { 11, 0x28, 23 }, /* 0000 0101 000 */
+ { 11, 0x17, 24 }, /* 0000 0010 111 */
+ { 11, 0x18, 25 }, /* 0000 0011 000 */
+ { 12, 0xCA, 26 }, /* 0000 1100 1010 */
+ { 12, 0xCB, 27 }, /* 0000 1100 1011 */
+ { 12, 0xCC, 28 }, /* 0000 1100 1100 */
+ { 12, 0xCD, 29 }, /* 0000 1100 1101 */
+ { 12, 0x68, 30 }, /* 0000 0110 1000 */
+ { 12, 0x69, 31 }, /* 0000 0110 1001 */
+ { 12, 0x6A, 32 }, /* 0000 0110 1010 */
+ { 12, 0x6B, 33 }, /* 0000 0110 1011 */
+ { 12, 0xD2, 34 }, /* 0000 1101 0010 */
+ { 12, 0xD3, 35 }, /* 0000 1101 0011 */
+ { 12, 0xD4, 36 }, /* 0000 1101 0100 */
+ { 12, 0xD5, 37 }, /* 0000 1101 0101 */
+ { 12, 0xD6, 38 }, /* 0000 1101 0110 */
+ { 12, 0xD7, 39 }, /* 0000 1101 0111 */
+ { 12, 0x6C, 40 }, /* 0000 0110 1100 */
+ { 12, 0x6D, 41 }, /* 0000 0110 1101 */
+ { 12, 0xDA, 42 }, /* 0000 1101 1010 */
+ { 12, 0xDB, 43 }, /* 0000 1101 1011 */
+ { 12, 0x54, 44 }, /* 0000 0101 0100 */
+ { 12, 0x55, 45 }, /* 0000 0101 0101 */
+ { 12, 0x56, 46 }, /* 0000 0101 0110 */
+ { 12, 0x57, 47 }, /* 0000 0101 0111 */
+ { 12, 0x64, 48 }, /* 0000 0110 0100 */
+ { 12, 0x65, 49 }, /* 0000 0110 0101 */
+ { 12, 0x52, 50 }, /* 0000 0101 0010 */
+ { 12, 0x53, 51 }, /* 0000 0101 0011 */
+ { 12, 0x24, 52 }, /* 0000 0010 0100 */
+ { 12, 0x37, 53 }, /* 0000 0011 0111 */
+ { 12, 0x38, 54 }, /* 0000 0011 1000 */
+ { 12, 0x27, 55 }, /* 0000 0010 0111 */
+ { 12, 0x28, 56 }, /* 0000 0010 1000 */
+ { 12, 0x58, 57 }, /* 0000 0101 1000 */
+ { 12, 0x59, 58 }, /* 0000 0101 1001 */
+ { 12, 0x2B, 59 }, /* 0000 0010 1011 */
+ { 12, 0x2C, 60 }, /* 0000 0010 1100 */
+ { 12, 0x5A, 61 }, /* 0000 0101 1010 */
+ { 12, 0x66, 62 }, /* 0000 0110 0110 */
+ { 12, 0x67, 63 }, /* 0000 0110 0111 */
+ { 10, 0xF, 64 }, /* 0000 0011 11 */
+ { 12, 0xC8, 128 }, /* 0000 1100 1000 */
+ { 12, 0xC9, 192 }, /* 0000 1100 1001 */
+ { 12, 0x5B, 256 }, /* 0000 0101 1011 */
+ { 12, 0x33, 320 }, /* 0000 0011 0011 */
+ { 12, 0x34, 384 }, /* 0000 0011 0100 */
+ { 12, 0x35, 448 }, /* 0000 0011 0101 */
+ { 13, 0x6C, 512 }, /* 0000 0011 0110 0 */
+ { 13, 0x6D, 576 }, /* 0000 0011 0110 1 */
+ { 13, 0x4A, 640 }, /* 0000 0010 0101 0 */
+ { 13, 0x4B, 704 }, /* 0000 0010 0101 1 */
+ { 13, 0x4C, 768 }, /* 0000 0010 0110 0 */
+ { 13, 0x4D, 832 }, /* 0000 0010 0110 1 */
+ { 13, 0x72, 896 }, /* 0000 0011 1001 0 */
+ { 13, 0x73, 960 }, /* 0000 0011 1001 1 */
+ { 13, 0x74, 1024 }, /* 0000 0011 1010 0 */
+ { 13, 0x75, 1088 }, /* 0000 0011 1010 1 */
+ { 13, 0x76, 1152 }, /* 0000 0011 1011 0 */
+ { 13, 0x77, 1216 }, /* 0000 0011 1011 1 */
+ { 13, 0x52, 1280 }, /* 0000 0010 1001 0 */
+ { 13, 0x53, 1344 }, /* 0000 0010 1001 1 */
+ { 13, 0x54, 1408 }, /* 0000 0010 1010 0 */
+ { 13, 0x55, 1472 }, /* 0000 0010 1010 1 */
+ { 13, 0x5A, 1536 }, /* 0000 0010 1101 0 */
+ { 13, 0x5B, 1600 }, /* 0000 0010 1101 1 */
+ { 13, 0x64, 1664 }, /* 0000 0011 0010 0 */
+ { 13, 0x65, 1728 }, /* 0000 0011 0010 1 */
+ { 11, 0x8, 1792 }, /* 0000 0001 000 */
+ { 11, 0xC, 1856 }, /* 0000 0001 100 */
+ { 11, 0xD, 1920 }, /* 0000 0001 101 */
+ { 12, 0x12, 1984 }, /* 0000 0001 0010 */
+ { 12, 0x13, 2048 }, /* 0000 0001 0011 */
+ { 12, 0x14, 2112 }, /* 0000 0001 0100 */
+ { 12, 0x15, 2176 }, /* 0000 0001 0101 */
+ { 12, 0x16, 2240 }, /* 0000 0001 0110 */
+ { 12, 0x17, 2304 }, /* 0000 0001 0111 */
+ { 12, 0x1C, 2368 }, /* 0000 0001 1100 */
+ { 12, 0x1D, 2432 }, /* 0000 0001 1101 */
+ { 12, 0x1E, 2496 }, /* 0000 0001 1110 */
+ { 12, 0x1F, 2560 }, /* 0000 0001 1111 */
+ { 12, 0x1, G3CODE_EOL }, /* 0000 0000 0001 */
+ { 9, 0x1, G3CODE_INVALID }, /* 0000 0000 1 */
+ { 10, 0x1, G3CODE_INVALID }, /* 0000 0000 01 */
+ { 11, 0x1, G3CODE_INVALID }, /* 0000 0000 001 */
+ { 12, 0x0, G3CODE_INVALID }, /* 0000 0000 0000 */
+};
+#else
+extern const tableentry TIFFFaxWhiteCodes[];
+extern const tableentry TIFFFaxBlackCodes[];
+#endif
+#endif /* _T4_ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_acorn.c b/tiff/libtiff/tif_acorn.c
new file mode 100644
index 0000000..63f9234
--- /dev/null
+++ b/tiff/libtiff/tif_acorn.c
@@ -0,0 +1,526 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/Attic/tif_acorn.c,v 1.2.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library RISC OS specific Routines.
+ * Developed out of the Unix version.
+ * Peter Greenham, May 1995
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+Low-level file handling
+~~~~~~~~~~~~~~~~~~~~~~~
+The functions in osfcn.h are unavailable when compiling under C, as it's a
+C++ header. Therefore they have been implemented here.
+
+Now, why have I done it this way?
+
+The definitive API library for RISC OS is Jonathan Coxhead's OSLib, which
+uses heavily optimised ARM assembler or even plain inline SWI calls for
+maximum performance and minimum runtime size. However, I don't want to make
+LIBTIFF need that to survive. Therefore I have also emulated the functions
+using macros to _swi() and _swix() defined in the swis.h header, and
+borrowing types from kernel.h, which is less efficient but doesn't need any
+third-party libraries.
+ */
+
+#ifdef INCLUDE_OSLIB
+
+#include "osfile.h"
+#include "osgbpb.h"
+#include "osargs.h"
+#include "osfind.h"
+
+#else
+
+/* OSLIB EMULATION STARTS */
+
+#include "kernel.h"
+#include "swis.h"
+
+/* From oslib:types.h */
+typedef unsigned int bits;
+typedef unsigned char byte;
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef SKIP
+#define SKIP 0
+#endif
+
+/* From oslib:os.h */
+typedef _kernel_oserror os_error;
+typedef byte os_f;
+
+/* From oslib:osfile.h */
+#undef OS_File
+#define OS_File 0x8
+
+/* From oslib:osgbpb.h */
+#undef OS_GBPB
+#define OS_GBPB 0xC
+#undef OSGBPB_Write
+#define OSGBPB_Write 0x2
+#undef OSGBPB_Read
+#define OSGBPB_Read 0x4
+
+extern os_error *xosgbpb_write (os_f file,
+ byte *data,
+ int size,
+ int *unwritten);
+extern int osgbpb_write (os_f file,
+ byte *data,
+ int size);
+
+#define xosgbpb_write(file, data, size, unwritten) \
+ (os_error*) _swix(OS_GBPB, _IN(0)|_IN(1)|_IN(2)|_IN(3)|_IN(4)|_OUT(3), \
+ OSGBPB_WriteAt, \
+ file, \
+ data, \
+ size, \
+ unwritten)
+
+#define osgbpb_write(file, data, size) \
+ _swi(OS_GBPB, _IN(0)|_IN(1)|_IN(2)|_IN(3)|_RETURN(3), \
+ OSGBPB_Write, \
+ file, \
+ data, \
+ size)
+
+extern os_error *xosgbpb_read (os_f file,
+ byte *buffer,
+ int size,
+ int *unread);
+extern int osgbpb_read (os_f file,
+ byte *buffer,
+ int size);
+
+#define xosgbpb_read(file, buffer, size, unread) \
+ (os_error*) _swix(OS_GBPB, _IN(0)|_IN(1)|_IN(2)|_IN(3)|_OUT(3), \
+ OSGBPB_Read, \
+ file, \
+ buffer, \
+ size, \
+ unread)
+
+#define osgbpb_read(file, buffer, size) \
+ _swi(OS_GBPB, _IN(0)|_IN(1)|_IN(2)|_IN(3)|_RETURN(3), \
+ OSGBPB_Read, \
+ file, \
+ buffer, \
+ size)
+
+/* From oslib:osfind.h */
+#undef OS_Find
+#define OS_Find 0xD
+#undef OSFind_Openin
+#define OSFind_Openin 0x40
+#undef OSFind_Openout
+#define OSFind_Openout 0x80
+#undef OSFind_Openup
+#define OSFind_Openup 0xC0
+#undef OSFind_Close
+#define OSFind_Close 0x0
+
+#define xosfind_open(reason, file_name, path, file) \
+ (os_error*) _swix(OS_Find, _IN(0)|_IN(1)|_IN(2)|_OUT(0), \
+ reason, file_name, path, file)
+
+#define osfind_open(reason, file_name, path) \
+ (os_f) _swi(OS_Find, _IN(0)|_IN(1)|_IN(2)|_RETURN(0), \
+ reason, file_name, path)
+
+extern os_error *xosfind_openin (bits flags,
+ char *file_name,
+ char *path,
+ os_f *file);
+extern os_f osfind_openin (bits flags,
+ char *file_name,
+ char *path);
+
+#define xosfind_openin(flags, file_name, path, file) \
+ xosfind_open(flags | OSFind_Openin, file_name, path, file)
+
+#define osfind_openin(flags, file_name, path) \
+ osfind_open(flags | OSFind_Openin, file_name, path)
+
+extern os_error *xosfind_openout (bits flags,
+ char *file_name,
+ char *path,
+ os_f *file);
+extern os_f osfind_openout (bits flags,
+ char *file_name,
+ char *path);
+
+#define xosfind_openout(flags, file_name, path, file) \
+ xosfind_open(flags | OSFind_Openout, file_name, path, file)
+
+#define osfind_openout(flags, file_name, path) \
+ osfind_open(flags | OSFind_Openout, file_name, path)
+
+extern os_error *xosfind_openup (bits flags,
+ char *file_name,
+ char *path,
+ os_f *file);
+extern os_f osfind_openup (bits flags,
+ char *file_name,
+ char *path);
+
+#define xosfind_openup(flags, file_name, path, file) \
+ xosfind_open(flags | OSFind_Openup, file_name, path, file)
+
+#define osfind_openup(flags, file_name, path) \
+ osfind_open(flags | OSFind_Openup, file_name, path)
+
+extern os_error *xosfind_close (os_f file);
+extern void osfind_close (os_f file);
+
+#define xosfind_close(file) \
+ (os_error*) _swix(OS_Find, _IN(0)|_IN(1), \
+ OSFind_Close, \
+ file)
+
+#define osfind_close(file) \
+ (void) _swi(OS_Find, _IN(0)|_IN(1), \
+ OSFind_Close, \
+ file)
+
+/* From oslib:osargs.h */
+#undef OS_Args
+#define OS_Args 0x9
+#undef OSArgs_ReadPtr
+#define OSArgs_ReadPtr 0x0
+#undef OSArgs_SetPtr
+#define OSArgs_SetPtr 0x1
+#undef OSArgs_ReadExt
+#define OSArgs_ReadExt 0x2
+
+extern os_error *xosargs_read_ptr (os_f file,
+ int *ptr);
+extern int osargs_read_ptr (os_f file);
+
+#define xosargs_read_ptr(file, ptr) \
+ (os_error*) _swix(OS_Args, _IN(0)|_IN(1)|_OUT(2), \
+ OSArgs_ReadPtr, \
+ file, \
+ ptr)
+
+#define osargs_read_ptr(file) \
+ _swi(OS_Args, _IN(0)|_IN(1)|_RETURN(2), \
+ OSArgs_ReadPtr, \
+ file)
+
+extern os_error *xosargs_set_ptr (os_f file,
+ int ptr);
+extern void osargs_set_ptr (os_f file,
+ int ptr);
+
+#define xosargs_set_ptr(file, ptr) \
+ (os_error*) _swix(OS_Args, _IN(0)|_IN(1)|_IN(2), \
+ OSArgs_SetPtr, \
+ file, \
+ ptr)
+
+#define osargs_set_ptr(file, ptr) \
+ (void) _swi(OS_Args, _IN(0)|_IN(1)|_IN(2), \
+ OSArgs_SetPtr, \
+ file, \
+ ptr)
+
+extern os_error *xosargs_read_ext (os_f file,
+ int *ext);
+extern int osargs_read_ext (os_f file);
+
+#define xosargs_read_ext(file, ext) \
+ (os_error*) _swix(OS_Args, _IN(0)|_IN(1)|_OUT(2), \
+ OSArgs_ReadExt, \
+ file, \
+ ext)
+
+#define osargs_read_ext(file) \
+ _swi(OS_Args, _IN(0)|_IN(1)|_RETURN(2), \
+ OSArgs_ReadExt, \
+ file)
+
+/* OSLIB EMULATION ENDS */
+
+#endif
+
+#ifndef __osfcn_h
+/* Will be set or not during tiffcomp.h */
+/* You get this to compile under C++? Please say how! */
+
+extern int open(const char* name, int flags, int mode)
+{
+ /* From what I can tell, should return <0 for failure */
+ os_error* e = (os_error*) 1; /* Cheeky way to use a pointer eh? :-) */
+ os_f file = (os_f) -1;
+
+ flags = flags;
+
+ switch(mode)
+ {
+ case O_RDONLY:
+ {
+ e = xosfind_openin(SKIP, name, SKIP, &file);
+ break;
+ }
+ case O_WRONLY:
+ case O_RDWR|O_CREAT:
+ case O_RDWR|O_CREAT|O_TRUNC:
+ {
+ e = xosfind_openout(SKIP, name, SKIP, &file);
+ break;
+ }
+ case O_RDWR:
+ {
+ e = xosfind_openup(SKIP, name, SKIP, &file);
+ break;
+ }
+ }
+ if (e)
+ {
+ file = (os_f) -1;
+ }
+ return (file);
+}
+
+extern int close(int fd)
+{
+ return ((int) xosfind_close((os_f) fd));
+}
+
+extern int write(int fd, const char *buf, int nbytes)
+{
+ /* Returns number of bytes written */
+ return (nbytes - osgbpb_write((os_f) fd, (const byte*) buf, nbytes));
+}
+
+extern int read(int fd, char *buf, int nbytes)
+{
+ /* Returns number of bytes read */
+ return (nbytes - osgbpb_read((os_f) fd, (byte*) buf, nbytes));
+}
+
+extern off_t lseek(int fd, off_t offset, int whence)
+{
+ int absolute = 0;
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ {
+ absolute = (int) offset;
+ break;
+ }
+ case SEEK_CUR:
+ {
+ absolute = osargs_read_ptr((os_f) fd) + (int) offset;
+ break;
+ }
+ case SEEK_END:
+ {
+ absolute = osargs_read_ext((os_f) fd) + (int) offset;
+ break;
+ }
+ }
+
+ osargs_set_ptr((os_f) fd, absolute);
+
+ return ((off_t) osargs_read_ptr((os_f) fd));
+}
+#endif
+
+static tsize_t
+_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return ((tsize_t) read((int) fd, buf, (size_t) size));
+}
+
+static tsize_t
+_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return ((tsize_t) write((int) fd, buf, (size_t) size));
+}
+
+static toff_t
+_tiffSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ return ((toff_t) lseek((int) fd, (off_t) off, whence));
+}
+
+static int
+_tiffCloseProc(thandle_t fd)
+{
+ return (close((int) fd));
+}
+
+static toff_t
+_tiffSizeProc(thandle_t fd)
+{
+ return (lseek((int) fd, SEEK_END, SEEK_SET));
+}
+
+#ifdef HAVE_MMAP
+#error "I didn't know Acorn had that!"
+#endif
+
+/* !HAVE_MMAP */
+static int
+_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ (void) fd; (void) pbase; (void) psize;
+ return (0);
+}
+
+static void
+_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+ (void) fd; (void) base; (void) size;
+}
+
+/*
+ * Open a TIFF file descriptor for read/writing.
+ */
+TIFF*
+TIFFFdOpen(int fd, const char* name, const char* mode)
+{
+ TIFF* tif;
+
+ tif = TIFFClientOpen(name, mode,
+ (thandle_t) fd,
+ _tiffReadProc, _tiffWriteProc,
+ _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
+ _tiffMapProc, _tiffUnmapProc);
+ if (tif)
+ {
+ tif->tif_fd = fd;
+ }
+ return (tif);
+}
+
+/*
+ * Open a TIFF file for read/writing.
+ */
+TIFF*
+TIFFOpen(const char* name, const char* mode)
+{
+ static const char module[] = "TIFFOpen";
+ int m, fd;
+
+ m = _TIFFgetMode(mode, module);
+
+ if (m == -1)
+ {
+ return ((TIFF*) 0);
+ }
+
+ fd = open(name, 0, m);
+
+ if (fd < 0)
+ {
+ TIFFErrorExt(0, module, "%s: Cannot open", name);
+ return ((TIFF *)0);
+ }
+ return (TIFFFdOpen(fd, name, mode));
+}
+
+void*
+_TIFFmalloc(tsize_t s)
+{
+ return (malloc((size_t) s));
+}
+
+void
+_TIFFfree(tdata_t p)
+{
+ free(p);
+}
+
+void*
+_TIFFrealloc(tdata_t p, tsize_t s)
+{
+ return (realloc(p, (size_t) s));
+}
+
+void
+_TIFFmemset(tdata_t p, int v, tsize_t c)
+{
+ memset(p, v, (size_t) c);
+}
+
+void
+_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
+{
+ memcpy(d, s, (size_t) c);
+}
+
+int
+_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)
+{
+ return (memcmp(p1, p2, (size_t) c));
+}
+
+static void
+acornWarningHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ {
+ fprintf(stderr, "%s: ", module);
+ }
+ fprintf(stderr, "Warning, ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFwarningHandler = acornWarningHandler;
+
+static void
+acornErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ {
+ fprintf(stderr, "%s: ", module);
+ }
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFerrorHandler = acornErrorHandler;
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_apple.c b/tiff/libtiff/tif_apple.c
new file mode 100644
index 0000000..8c48228
--- /dev/null
+++ b/tiff/libtiff/tif_apple.c
@@ -0,0 +1,281 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/Attic/tif_apple.c,v 1.3.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library Macintosh-specific routines.
+ *
+ * These routines use only Toolbox and high-level File Manager traps.
+ * They make no calls to the THINK C "unix" compatibility library. Also,
+ * malloc is not used directly but it is still referenced internally by
+ * the ANSI library in rare cases. Heap fragmentation by the malloc ring
+ * buffer is therefore minimized.
+ *
+ * O_RDONLY and O_RDWR are treated identically here. The tif_mode flag is
+ * checked in TIFFWriteCheck().
+ *
+ * Create below fills in a blank creator signature and sets the file type
+ * to 'TIFF'. It is much better for the application to do this by Create'ing
+ * the file first and TIFFOpen'ing it later.
+ * ---------
+ * This code has been "Carbonized", and may not work with older MacOS versions.
+ * If so, grab the tif_apple.c out of an older libtiff distribution, like
+ * 3.5.5 from www.libtiff.org.
+ */
+
+#include "tiffiop.h"
+#include <Errors.h>
+#include <Files.h>
+#include <Memory.h>
+#include <Script.h>
+
+#if defined(__PPCC__) || defined(__SC__) || defined(__MRC__) || defined(applec)
+#define CtoPstr c2pstr
+#endif
+
+static tsize_t
+_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return (FSRead((short) fd, (long*) &size, (char*) buf) == noErr ?
+ size : (tsize_t) -1);
+}
+
+static tsize_t
+_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return (FSWrite((short) fd, (long*) &size, (char*) buf) == noErr ?
+ size : (tsize_t) -1);
+}
+
+static toff_t
+_tiffSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ long fpos, size;
+
+ if (GetEOF((short) fd, &size) != noErr)
+ return EOF;
+ (void) GetFPos((short) fd, &fpos);
+
+ switch (whence) {
+ case SEEK_CUR:
+ if (off + fpos > size)
+ SetEOF((short) fd, off + fpos);
+ if (SetFPos((short) fd, fsFromMark, off) != noErr)
+ return EOF;
+ break;
+ case SEEK_END:
+ if (off > 0)
+ SetEOF((short) fd, off + size);
+ if (SetFPos((short) fd, fsFromStart, off + size) != noErr)
+ return EOF;
+ break;
+ case SEEK_SET:
+ if (off > size)
+ SetEOF((short) fd, off);
+ if (SetFPos((short) fd, fsFromStart, off) != noErr)
+ return EOF;
+ break;
+ }
+
+ return (toff_t)(GetFPos((short) fd, &fpos) == noErr ? fpos : EOF);
+}
+
+static int
+_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ return (0);
+}
+
+static void
+_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+}
+
+static int
+_tiffCloseProc(thandle_t fd)
+{
+ return (FSClose((short) fd));
+}
+
+static toff_t
+_tiffSizeProc(thandle_t fd)
+{
+ long size;
+
+ if (GetEOF((short) fd, &size) != noErr) {
+ TIFFErrorExt(fd, "_tiffSizeProc", "%s: Cannot get file size");
+ return (-1L);
+ }
+ return ((toff_t) size);
+}
+
+/*
+ * Open a TIFF file descriptor for read/writing.
+ */
+TIFF*
+TIFFFdOpen(int fd, const char* name, const char* mode)
+{
+ TIFF* tif;
+
+ tif = TIFFClientOpen(name, mode, (thandle_t) fd,
+ _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
+ _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
+ if (tif)
+ tif->tif_fd = fd;
+ return (tif);
+}
+
+static void ourc2pstr( char* inString )
+{
+ int sLen = strlen( inString );
+ BlockMoveData( inString, &inString[1], sLen );
+ inString[0] = sLen;
+}
+
+/*
+ * Open a TIFF file for read/writing.
+ */
+TIFF*
+TIFFOpen(const char* name, const char* mode)
+{
+ static const char module[] = "TIFFOpen";
+ Str255 pname;
+ FInfo finfo;
+ short fref;
+ OSErr err;
+ FSSpec fSpec;
+
+ strcpy((char*) pname, name);
+ ourc2pstr((char*) pname);
+
+ err = FSMakeFSSpec( 0, 0, pname, &fSpec );
+
+ switch (_TIFFgetMode(mode, module)) {
+ default:
+ return ((TIFF*) 0);
+ case O_RDWR | O_CREAT | O_TRUNC:
+ if (FSpGetFInfo(&fSpec, &finfo) == noErr)
+ FSpDelete(&fSpec);
+ /* fall through */
+ case O_RDWR | O_CREAT:
+ if ((err = FSpGetFInfo(&fSpec, &finfo)) == fnfErr) {
+ if (FSpCreate(&fSpec, ' ', 'TIFF', smSystemScript) != noErr)
+ goto badCreate;
+ if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr)
+ goto badOpen;
+ } else if (err == noErr) {
+ if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr)
+ goto badOpen;
+ } else
+ goto badOpen;
+ break;
+ case O_RDONLY:
+ if (FSpOpenDF(&fSpec, fsRdPerm, &fref) != noErr)
+ goto badOpen;
+ break;
+ case O_RDWR:
+ if (FSpOpenDF(&fSpec, fsRdWrPerm, &fref) != noErr)
+ goto badOpen;
+ break;
+ }
+ return (TIFFFdOpen((int) fref, name, mode));
+badCreate:
+ TIFFErrorExt(0, module, "%s: Cannot create", name);
+ return ((TIFF*) 0);
+badOpen:
+ TIFFErrorExt(0, module, "%s: Cannot open", name);
+ return ((TIFF*) 0);
+}
+
+void
+_TIFFmemset(tdata_t p, int v, tsize_t c)
+{
+ memset(p, v, (size_t) c);
+}
+
+void
+_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
+{
+ memcpy(d, s, (size_t) c);
+}
+
+int
+_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)
+{
+ return (memcmp(p1, p2, (size_t) c));
+}
+
+tdata_t
+_TIFFmalloc(tsize_t s)
+{
+ return (NewPtr((size_t) s));
+}
+
+void
+_TIFFfree(tdata_t p)
+{
+ DisposePtr(p);
+}
+
+tdata_t
+_TIFFrealloc(tdata_t p, tsize_t s)
+{
+ Ptr n = p;
+
+ SetPtrSize(p, (size_t) s);
+ if (MemError() && (n = NewPtr((size_t) s)) != NULL) {
+ BlockMove(p, n, GetPtrSize(p));
+ DisposePtr(p);
+ }
+ return ((tdata_t) n);
+}
+
+static void
+appleWarningHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ fprintf(stderr, "Warning, ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFwarningHandler = appleWarningHandler;
+
+static void
+appleErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFerrorHandler = appleErrorHandler;
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_atari.c b/tiff/libtiff/tif_atari.c
new file mode 100644
index 0000000..4f56c2c
--- /dev/null
+++ b/tiff/libtiff/tif_atari.c
@@ -0,0 +1,250 @@
+/* "$Header: /cvs/maptools/cvsroot/libtiff/libtiff/Attic/tif_atari.c,v 1.2.2.1 2010-06-08 18:50:41 bfriesen Exp $" */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library ATARI-specific Routines.
+ */
+#include "tiffiop.h"
+#if defined(__TURBOC__)
+#include <tos.h>
+#include <stdio.h>
+#else
+#include <osbind.h>
+#include <fcntl.h>
+#endif
+
+#ifndef O_ACCMODE
+#define O_ACCMODE 3
+#endif
+
+#include <errno.h>
+
+#define AEFILNF -33
+
+static tsize_t
+_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ long r;
+
+ r = Fread((int) fd, size, buf);
+ if (r < 0) {
+ errno = (int)-r;
+ r = -1;
+ }
+ return r;
+}
+
+static tsize_t
+_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ long r;
+
+ r = Fwrite((int) fd, size, buf);
+ if (r < 0) {
+ errno = (int)-r;
+ r = -1;
+ }
+ return r;
+}
+
+static toff_t
+_tiffSeekProc(thandle_t fd, off_t off, int whence)
+{
+ char buf[256];
+ long current_off, expected_off, new_off;
+
+ if (whence == SEEK_END || off <= 0)
+ return Fseek(off, (int) fd, whence);
+ current_off = Fseek(0, (int) fd, SEEK_CUR); /* find out where we are */
+ if (whence == SEEK_SET)
+ expected_off = off;
+ else
+ expected_off = off + current_off;
+ new_off = Fseek(off, (int) fd, whence);
+ if (new_off == expected_off)
+ return new_off;
+ /* otherwise extend file -- zero filling the hole */
+ if (new_off < 0) /* error? */
+ new_off = Fseek(0, (int) fd, SEEK_END); /* go to eof */
+ _TIFFmemset(buf, 0, sizeof(buf));
+ while (expected_off > new_off) {
+ off = expected_off - new_off;
+ if (off > sizeof(buf))
+ off = sizeof(buf);
+ if ((current_off = Fwrite((int) fd, off, buf)) != off)
+ return (current_off > 0) ?
+ new_off + current_off : new_off;
+ new_off += off;
+ }
+ return new_off;
+}
+
+static int
+_tiffCloseProc(thandle_t fd)
+{
+ long r;
+
+ r = Fclose((int) fd);
+ if (r < 0) {
+ errno = (int)-r;
+ r = -1;
+ }
+ return (int)r;
+}
+
+static toff_t
+_tiffSizeProc(thandle_t fd)
+{
+ long pos, eof;
+
+ pos = Fseek(0, (int) fd, SEEK_CUR);
+ eof = Fseek(0, (int) fd, SEEK_END);
+ Fseek(pos, (int) fd, SEEK_SET);
+ return eof;
+}
+
+static int
+_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ return (0);
+}
+
+static void
+_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+}
+
+/*
+* Open a TIFF file descriptor for read/writing.
+*/
+TIFF*
+TIFFFdOpen(int fd, const char* name, const char* mode)
+{
+ TIFF* tif;
+
+ tif = TIFFClientOpen(name, mode,
+ (thandle_t) fd,
+ _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
+ _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
+ if (tif)
+ tif->tif_fd = fd;
+ return (tif);
+}
+
+/*
+* Open a TIFF file for read/writing.
+*/
+TIFF*
+TIFFOpen(const char* name, const char* mode)
+{
+ static const char module[] = "TIFFOpen";
+ int m;
+ long fd;
+
+ m = _TIFFgetMode(mode, module);
+ if (m == -1)
+ return ((TIFF*)0);
+ if (m & O_TRUNC) {
+ fd = Fcreate(name, 0);
+ } else {
+ fd = Fopen(name, m & O_ACCMODE);
+ if (fd == AEFILNF && m & O_CREAT)
+ fd = Fcreate(name, 0);
+ }
+ if (fd < 0)
+ errno = (int)fd;
+ if (fd < 0) {
+ TIFFErrorExt(0, module, "%s: Cannot open", name);
+ return ((TIFF*)0);
+ }
+ return (TIFFFdOpen(fd, name, mode));
+}
+
+#include <stdlib.h>
+
+tdata_t
+_TIFFmalloc(tsize_t s)
+{
+ return (malloc((size_t) s));
+}
+
+void
+_TIFFfree(tdata_t p)
+{
+ free(p);
+}
+
+tdata_t
+_TIFFrealloc(tdata_t p, tsize_t s)
+{
+ return (realloc(p, (size_t) s));
+}
+
+void
+_TIFFmemset(tdata_t p, int v, size_t c)
+{
+ memset(p, v, (size_t) c);
+}
+
+void
+_TIFFmemcpy(tdata_t d, const tdata_t s, size_t c)
+{
+ memcpy(d, s, (size_t) c);
+}
+
+int
+_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)
+{
+ return (memcmp(p1, p2, (size_t) c));
+}
+
+static void
+atariWarningHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ fprintf(stderr, "Warning, ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFwarningHandler = atariWarningHandler;
+
+static void
+atariErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFerrorHandler = atariErrorHandler;
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_aux.c b/tiff/libtiff/tif_aux.c
new file mode 100644
index 0000000..272f0d9
--- /dev/null
+++ b/tiff/libtiff/tif_aux.c
@@ -0,0 +1,290 @@
+/* $Id: tif_aux.c,v 1.20.2.3 2010-06-09 21:15:27 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Auxiliary Support Routines.
+ */
+#include "tiffiop.h"
+#include "tif_predict.h"
+#include <math.h>
+
+tdata_t
+_TIFFCheckRealloc(TIFF* tif, tdata_t buffer,
+ size_t nmemb, size_t elem_size, const char* what)
+{
+ tdata_t cp = NULL;
+ tsize_t bytes = nmemb * elem_size;
+
+ /*
+ * XXX: Check for integer overflow.
+ */
+ if (nmemb && elem_size && bytes / elem_size == nmemb)
+ cp = _TIFFrealloc(buffer, bytes);
+
+ if (cp == NULL)
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Failed to allocate memory for %s "
+ "(%ld elements of %ld bytes each)",
+ what,(long) nmemb, (long) elem_size);
+
+ return cp;
+}
+
+tdata_t
+_TIFFCheckMalloc(TIFF* tif, size_t nmemb, size_t elem_size, const char* what)
+{
+ return _TIFFCheckRealloc(tif, NULL, nmemb, elem_size, what);
+}
+
+static int
+TIFFDefaultTransferFunction(TIFFDirectory* td)
+{
+ uint16 **tf = td->td_transferfunction;
+ tsize_t i, n, nbytes;
+
+ tf[0] = tf[1] = tf[2] = 0;
+ if (td->td_bitspersample >= sizeof(tsize_t) * 8 - 2)
+ return 0;
+
+ n = 1<<td->td_bitspersample;
+ nbytes = n * sizeof (uint16);
+ if (!(tf[0] = (uint16 *)_TIFFmalloc(nbytes)))
+ return 0;
+ tf[0][0] = 0;
+ for (i = 1; i < n; i++) {
+ double t = (double)i/((double) n-1.);
+ tf[0][i] = (uint16)floor(65535.*pow(t, 2.2) + .5);
+ }
+
+ if (td->td_samplesperpixel - td->td_extrasamples > 1) {
+ if (!(tf[1] = (uint16 *)_TIFFmalloc(nbytes)))
+ goto bad;
+ _TIFFmemcpy(tf[1], tf[0], nbytes);
+ if (!(tf[2] = (uint16 *)_TIFFmalloc(nbytes)))
+ goto bad;
+ _TIFFmemcpy(tf[2], tf[0], nbytes);
+ }
+ return 1;
+
+bad:
+ if (tf[0])
+ _TIFFfree(tf[0]);
+ if (tf[1])
+ _TIFFfree(tf[1]);
+ if (tf[2])
+ _TIFFfree(tf[2]);
+ tf[0] = tf[1] = tf[2] = 0;
+ return 0;
+}
+
+static int
+TIFFDefaultRefBlackWhite(TIFFDirectory* td)
+{
+ int i;
+
+ if (!(td->td_refblackwhite = (float *)_TIFFmalloc(6*sizeof (float))))
+ return 0;
+ if (td->td_photometric == PHOTOMETRIC_YCBCR) {
+ /*
+ * YCbCr (Class Y) images must have the ReferenceBlackWhite
+ * tag set. Fix the broken images, which lacks that tag.
+ */
+ td->td_refblackwhite[0] = 0.0F;
+ td->td_refblackwhite[1] = td->td_refblackwhite[3] =
+ td->td_refblackwhite[5] = 255.0F;
+ td->td_refblackwhite[2] = td->td_refblackwhite[4] = 128.0F;
+ } else {
+ /*
+ * Assume RGB (Class R)
+ */
+ for (i = 0; i < 3; i++) {
+ td->td_refblackwhite[2*i+0] = 0;
+ td->td_refblackwhite[2*i+1] =
+ (float)((1L<<td->td_bitspersample)-1L);
+ }
+ }
+ return 1;
+}
+
+/*
+ * Like TIFFGetField, but return any default
+ * value if the tag is not present in the directory.
+ *
+ * NB: We use the value in the directory, rather than
+ * explcit values so that defaults exist only one
+ * place in the library -- in TIFFDefaultDirectory.
+ */
+int
+TIFFVGetFieldDefaulted(TIFF* tif, ttag_t tag, va_list ap)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if (TIFFVGetField(tif, tag, ap))
+ return (1);
+ switch (tag) {
+ case TIFFTAG_SUBFILETYPE:
+ *va_arg(ap, uint32 *) = td->td_subfiletype;
+ return (1);
+ case TIFFTAG_BITSPERSAMPLE:
+ *va_arg(ap, uint16 *) = td->td_bitspersample;
+ return (1);
+ case TIFFTAG_THRESHHOLDING:
+ *va_arg(ap, uint16 *) = td->td_threshholding;
+ return (1);
+ case TIFFTAG_FILLORDER:
+ *va_arg(ap, uint16 *) = td->td_fillorder;
+ return (1);
+ case TIFFTAG_ORIENTATION:
+ *va_arg(ap, uint16 *) = td->td_orientation;
+ return (1);
+ case TIFFTAG_SAMPLESPERPIXEL:
+ *va_arg(ap, uint16 *) = td->td_samplesperpixel;
+ return (1);
+ case TIFFTAG_ROWSPERSTRIP:
+ *va_arg(ap, uint32 *) = td->td_rowsperstrip;
+ return (1);
+ case TIFFTAG_MINSAMPLEVALUE:
+ *va_arg(ap, uint16 *) = td->td_minsamplevalue;
+ return (1);
+ case TIFFTAG_MAXSAMPLEVALUE:
+ *va_arg(ap, uint16 *) = td->td_maxsamplevalue;
+ return (1);
+ case TIFFTAG_PLANARCONFIG:
+ *va_arg(ap, uint16 *) = td->td_planarconfig;
+ return (1);
+ case TIFFTAG_RESOLUTIONUNIT:
+ *va_arg(ap, uint16 *) = td->td_resolutionunit;
+ return (1);
+ case TIFFTAG_PREDICTOR:
+ {
+ TIFFPredictorState* sp = (TIFFPredictorState*) tif->tif_data;
+ *va_arg(ap, uint16*) = (uint16) sp->predictor;
+ return 1;
+ }
+ case TIFFTAG_DOTRANGE:
+ *va_arg(ap, uint16 *) = 0;
+ *va_arg(ap, uint16 *) = (1<<td->td_bitspersample)-1;
+ return (1);
+ case TIFFTAG_INKSET:
+ *va_arg(ap, uint16 *) = INKSET_CMYK;
+ return 1;
+ case TIFFTAG_NUMBEROFINKS:
+ *va_arg(ap, uint16 *) = 4;
+ return (1);
+ case TIFFTAG_EXTRASAMPLES:
+ *va_arg(ap, uint16 *) = td->td_extrasamples;
+ *va_arg(ap, uint16 **) = td->td_sampleinfo;
+ return (1);
+ case TIFFTAG_MATTEING:
+ *va_arg(ap, uint16 *) =
+ (td->td_extrasamples == 1 &&
+ td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA);
+ return (1);
+ case TIFFTAG_TILEDEPTH:
+ *va_arg(ap, uint32 *) = td->td_tiledepth;
+ return (1);
+ case TIFFTAG_DATATYPE:
+ *va_arg(ap, uint16 *) = td->td_sampleformat-1;
+ return (1);
+ case TIFFTAG_SAMPLEFORMAT:
+ *va_arg(ap, uint16 *) = td->td_sampleformat;
+ return(1);
+ case TIFFTAG_IMAGEDEPTH:
+ *va_arg(ap, uint32 *) = td->td_imagedepth;
+ return (1);
+ case TIFFTAG_YCBCRCOEFFICIENTS:
+ {
+ /* defaults are from CCIR Recommendation 601-1 */
+ static float ycbcrcoeffs[] = { 0.299f, 0.587f, 0.114f };
+ *va_arg(ap, float **) = ycbcrcoeffs;
+ return 1;
+ }
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[0];
+ *va_arg(ap, uint16 *) = td->td_ycbcrsubsampling[1];
+ return (1);
+ case TIFFTAG_YCBCRPOSITIONING:
+ *va_arg(ap, uint16 *) = td->td_ycbcrpositioning;
+ return (1);
+ case TIFFTAG_WHITEPOINT:
+ {
+ static float whitepoint[2];
+
+ /* TIFF 6.0 specification tells that it is no default
+ value for the WhitePoint, but AdobePhotoshop TIFF
+ Technical Note tells that it should be CIE D50. */
+ whitepoint[0] = D50_X0 / (D50_X0 + D50_Y0 + D50_Z0);
+ whitepoint[1] = D50_Y0 / (D50_X0 + D50_Y0 + D50_Z0);
+ *va_arg(ap, float **) = whitepoint;
+ return 1;
+ }
+ case TIFFTAG_TRANSFERFUNCTION:
+ if (!td->td_transferfunction[0] &&
+ !TIFFDefaultTransferFunction(td)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "No space for \"TransferFunction\" tag");
+ return (0);
+ }
+ *va_arg(ap, uint16 **) = td->td_transferfunction[0];
+ if (td->td_samplesperpixel - td->td_extrasamples > 1) {
+ *va_arg(ap, uint16 **) = td->td_transferfunction[1];
+ *va_arg(ap, uint16 **) = td->td_transferfunction[2];
+ }
+ return (1);
+ case TIFFTAG_REFERENCEBLACKWHITE:
+ if (!td->td_refblackwhite && !TIFFDefaultRefBlackWhite(td))
+ return (0);
+ *va_arg(ap, float **) = td->td_refblackwhite;
+ return (1);
+ }
+ return 0;
+}
+
+/*
+ * Like TIFFGetField, but return any default
+ * value if the tag is not present in the directory.
+ */
+int
+TIFFGetFieldDefaulted(TIFF* tif, ttag_t tag, ...)
+{
+ int ok;
+ va_list ap;
+
+ va_start(ap, tag);
+ ok = TIFFVGetFieldDefaulted(tif, tag, ap);
+ va_end(ap);
+ return (ok);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_close.c b/tiff/libtiff/tif_close.c
new file mode 100644
index 0000000..02591ba
--- /dev/null
+++ b/tiff/libtiff/tif_close.c
@@ -0,0 +1,126 @@
+/* $Id: tif_close.c,v 1.10.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+/************************************************************************/
+/* TIFFCleanup() */
+/************************************************************************/
+
+/**
+ * Auxiliary function to free the TIFF structure. Given structure will be
+ * completetly freed, so you should save opened file handle and pointer
+ * to the close procedure in external variables before calling
+ * _TIFFCleanup(), if you will need these ones to close the file.
+ *
+ * @param tif A TIFF pointer.
+ */
+
+void
+TIFFCleanup(TIFF* tif)
+{
+ if (tif->tif_mode != O_RDONLY)
+ /*
+ * Flush buffered data and directory (if dirty).
+ */
+ TIFFFlush(tif);
+ (*tif->tif_cleanup)(tif);
+ TIFFFreeDirectory(tif);
+
+ if (tif->tif_dirlist)
+ _TIFFfree(tif->tif_dirlist);
+
+ /* Clean up client info links */
+ while( tif->tif_clientinfo )
+ {
+ TIFFClientInfoLink *link = tif->tif_clientinfo;
+
+ tif->tif_clientinfo = link->next;
+ _TIFFfree( link->name );
+ _TIFFfree( link );
+ }
+
+ if (tif->tif_rawdata && (tif->tif_flags&TIFF_MYBUFFER))
+ _TIFFfree(tif->tif_rawdata);
+ if (isMapped(tif))
+ TIFFUnmapFileContents(tif, tif->tif_base, tif->tif_size);
+
+ /* Clean up custom fields */
+ if (tif->tif_nfields > 0)
+ {
+ size_t i;
+
+ for (i = 0; i < tif->tif_nfields; i++)
+ {
+ TIFFFieldInfo *fld = tif->tif_fieldinfo[i];
+ if (fld->field_bit == FIELD_CUSTOM &&
+ strncmp("Tag ", fld->field_name, 4) == 0)
+ {
+ _TIFFfree(fld->field_name);
+ _TIFFfree(fld);
+ }
+ }
+
+ _TIFFfree(tif->tif_fieldinfo);
+ }
+
+ _TIFFfree(tif);
+}
+
+/************************************************************************/
+/* TIFFClose() */
+/************************************************************************/
+
+/**
+ * Close a previously opened TIFF file.
+ *
+ * TIFFClose closes a file that was previously opened with TIFFOpen().
+ * Any buffered data are flushed to the file, including the contents of
+ * the current directory (if modified); and all resources are reclaimed.
+ *
+ * @param tif A TIFF pointer.
+ */
+
+void
+TIFFClose(TIFF* tif)
+{
+ TIFFCloseProc closeproc = tif->tif_closeproc;
+ thandle_t fd = tif->tif_clientdata;
+
+ TIFFCleanup(tif);
+ (void) (*closeproc)(fd);
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_codec.c b/tiff/libtiff/tif_codec.c
new file mode 100644
index 0000000..d5c6fd1
--- /dev/null
+++ b/tiff/libtiff/tif_codec.c
@@ -0,0 +1,160 @@
+/* $Id: tif_codec.c,v 1.10.2.2 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Builtin Compression Scheme Configuration Support.
+ */
+#include "tiffiop.h"
+
+static int NotConfigured(TIFF*, int);
+
+#ifndef LZW_SUPPORT
+#define TIFFInitLZW NotConfigured
+#endif
+#ifndef PACKBITS_SUPPORT
+#define TIFFInitPackBits NotConfigured
+#endif
+#ifndef THUNDER_SUPPORT
+#define TIFFInitThunderScan NotConfigured
+#endif
+#ifndef NEXT_SUPPORT
+#define TIFFInitNeXT NotConfigured
+#endif
+#ifndef JPEG_SUPPORT
+#define TIFFInitJPEG NotConfigured
+#endif
+#ifndef OJPEG_SUPPORT
+#define TIFFInitOJPEG NotConfigured
+#endif
+#ifndef CCITT_SUPPORT
+#define TIFFInitCCITTRLE NotConfigured
+#define TIFFInitCCITTRLEW NotConfigured
+#define TIFFInitCCITTFax3 NotConfigured
+#define TIFFInitCCITTFax4 NotConfigured
+#endif
+#ifndef JBIG_SUPPORT
+#define TIFFInitJBIG NotConfigured
+#endif
+#ifndef ZIP_SUPPORT
+#define TIFFInitZIP NotConfigured
+#endif
+#ifndef PIXARLOG_SUPPORT
+#define TIFFInitPixarLog NotConfigured
+#endif
+#ifndef LOGLUV_SUPPORT
+#define TIFFInitSGILog NotConfigured
+#endif
+
+/*
+ * Compression schemes statically built into the library.
+ */
+#ifdef VMS
+const TIFFCodec _TIFFBuiltinCODECS[] = {
+#else
+TIFFCodec _TIFFBuiltinCODECS[] = {
+#endif
+ { "None", COMPRESSION_NONE, TIFFInitDumpMode },
+ { "LZW", COMPRESSION_LZW, TIFFInitLZW },
+ { "PackBits", COMPRESSION_PACKBITS, TIFFInitPackBits },
+ { "ThunderScan", COMPRESSION_THUNDERSCAN,TIFFInitThunderScan },
+ { "NeXT", COMPRESSION_NEXT, TIFFInitNeXT },
+ { "JPEG", COMPRESSION_JPEG, TIFFInitJPEG },
+ { "Old-style JPEG", COMPRESSION_OJPEG, TIFFInitOJPEG },
+ { "CCITT RLE", COMPRESSION_CCITTRLE, TIFFInitCCITTRLE },
+ { "CCITT RLE/W", COMPRESSION_CCITTRLEW, TIFFInitCCITTRLEW },
+ { "CCITT Group 3", COMPRESSION_CCITTFAX3, TIFFInitCCITTFax3 },
+ { "CCITT Group 4", COMPRESSION_CCITTFAX4, TIFFInitCCITTFax4 },
+ { "ISO JBIG", COMPRESSION_JBIG, TIFFInitJBIG },
+ { "Deflate", COMPRESSION_DEFLATE, TIFFInitZIP },
+ { "AdobeDeflate", COMPRESSION_ADOBE_DEFLATE , TIFFInitZIP },
+ { "PixarLog", COMPRESSION_PIXARLOG, TIFFInitPixarLog },
+ { "SGILog", COMPRESSION_SGILOG, TIFFInitSGILog },
+ { "SGILog24", COMPRESSION_SGILOG24, TIFFInitSGILog },
+ { NULL, 0, NULL }
+};
+
+static int
+_notConfigured(TIFF* tif)
+{
+ const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
+ char compression_code[20];
+
+ sprintf( compression_code, "%d", tif->tif_dir.td_compression );
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%s compression support is not configured",
+ c ? c->name : compression_code );
+ return (0);
+}
+
+static int
+NotConfigured(TIFF* tif, int scheme)
+{
+ (void) scheme;
+
+ tif->tif_decodestatus = FALSE;
+ tif->tif_setupdecode = _notConfigured;
+ tif->tif_encodestatus = FALSE;
+ tif->tif_setupencode = _notConfigured;
+ return (1);
+}
+
+/************************************************************************/
+/* TIFFIsCODECConfigured() */
+/************************************************************************/
+
+/**
+ * Check whether we have working codec for the specific coding scheme.
+ *
+ * @return returns 1 if the codec is configured and working. Otherwise
+ * 0 will be returned.
+ */
+
+int
+TIFFIsCODECConfigured(uint16 scheme)
+{
+ const TIFFCodec* codec = TIFFFindCODEC(scheme);
+
+ if(codec == NULL) {
+ return 0;
+ }
+ if(codec->init == NULL) {
+ return 0;
+ }
+ if(codec->init != NotConfigured){
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_color.c b/tiff/libtiff/tif_color.c
new file mode 100644
index 0000000..02eb346
--- /dev/null
+++ b/tiff/libtiff/tif_color.c
@@ -0,0 +1,282 @@
+/* $Id: tif_color.c,v 1.12.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * CIE L*a*b* to CIE XYZ and CIE XYZ to RGB conversion routines are taken
+ * from the VIPS library (http://www.vips.ecs.soton.ac.uk) with
+ * the permission of John Cupitt, the VIPS author.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Color space conversion routines.
+ */
+
+#include "tiffiop.h"
+#include <math.h>
+
+/*
+ * Convert color value from the CIE L*a*b* 1976 space to CIE XYZ.
+ */
+void
+TIFFCIELabToXYZ(TIFFCIELabToRGB *cielab, uint32 l, int32 a, int32 b,
+ float *X, float *Y, float *Z)
+{
+ float L = (float)l * 100.0F / 255.0F;
+ float cby, tmp;
+
+ if( L < 8.856F ) {
+ *Y = (L * cielab->Y0) / 903.292F;
+ cby = 7.787F * (*Y / cielab->Y0) + 16.0F / 116.0F;
+ } else {
+ cby = (L + 16.0F) / 116.0F;
+ *Y = cielab->Y0 * cby * cby * cby;
+ }
+
+ tmp = (float)a / 500.0F + cby;
+ if( tmp < 0.2069F )
+ *X = cielab->X0 * (tmp - 0.13793F) / 7.787F;
+ else
+ *X = cielab->X0 * tmp * tmp * tmp;
+
+ tmp = cby - (float)b / 200.0F;
+ if( tmp < 0.2069F )
+ *Z = cielab->Z0 * (tmp - 0.13793F) / 7.787F;
+ else
+ *Z = cielab->Z0 * tmp * tmp * tmp;
+}
+
+#define RINT(R) ((uint32)((R)>0?((R)+0.5):((R)-0.5)))
+/*
+ * Convert color value from the XYZ space to RGB.
+ */
+void
+TIFFXYZToRGB(TIFFCIELabToRGB *cielab, float X, float Y, float Z,
+ uint32 *r, uint32 *g, uint32 *b)
+{
+ int i;
+ float Yr, Yg, Yb;
+ float *matrix = &cielab->display.d_mat[0][0];
+
+ /* Multiply through the matrix to get luminosity values. */
+ Yr = matrix[0] * X + matrix[1] * Y + matrix[2] * Z;
+ Yg = matrix[3] * X + matrix[4] * Y + matrix[5] * Z;
+ Yb = matrix[6] * X + matrix[7] * Y + matrix[8] * Z;
+
+ /* Clip input */
+ Yr = TIFFmax(Yr, cielab->display.d_Y0R);
+ Yg = TIFFmax(Yg, cielab->display.d_Y0G);
+ Yb = TIFFmax(Yb, cielab->display.d_Y0B);
+
+ /* Avoid overflow in case of wrong input values */
+ Yr = TIFFmin(Yr, cielab->display.d_YCR);
+ Yg = TIFFmin(Yg, cielab->display.d_YCG);
+ Yb = TIFFmin(Yb, cielab->display.d_YCB);
+
+ /* Turn luminosity to colour value. */
+ i = (int)((Yr - cielab->display.d_Y0R) / cielab->rstep);
+ i = TIFFmin(cielab->range, i);
+ *r = RINT(cielab->Yr2r[i]);
+
+ i = (int)((Yg - cielab->display.d_Y0G) / cielab->gstep);
+ i = TIFFmin(cielab->range, i);
+ *g = RINT(cielab->Yg2g[i]);
+
+ i = (int)((Yb - cielab->display.d_Y0B) / cielab->bstep);
+ i = TIFFmin(cielab->range, i);
+ *b = RINT(cielab->Yb2b[i]);
+
+ /* Clip output. */
+ *r = TIFFmin(*r, cielab->display.d_Vrwr);
+ *g = TIFFmin(*g, cielab->display.d_Vrwg);
+ *b = TIFFmin(*b, cielab->display.d_Vrwb);
+}
+#undef RINT
+
+/*
+ * Allocate conversion state structures and make look_up tables for
+ * the Yr,Yb,Yg <=> r,g,b conversions.
+ */
+int
+TIFFCIELabToRGBInit(TIFFCIELabToRGB* cielab,
+ TIFFDisplay *display, float *refWhite)
+{
+ int i;
+ double gamma;
+
+ cielab->range = CIELABTORGB_TABLE_RANGE;
+
+ _TIFFmemcpy(&cielab->display, display, sizeof(TIFFDisplay));
+
+ /* Red */
+ gamma = 1.0 / cielab->display.d_gammaR ;
+ cielab->rstep =
+ (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
+ for(i = 0; i <= cielab->range; i++) {
+ cielab->Yr2r[i] = cielab->display.d_Vrwr
+ * ((float)pow((double)i / cielab->range, gamma));
+ }
+
+ /* Green */
+ gamma = 1.0 / cielab->display.d_gammaG ;
+ cielab->gstep =
+ (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
+ for(i = 0; i <= cielab->range; i++) {
+ cielab->Yg2g[i] = cielab->display.d_Vrwg
+ * ((float)pow((double)i / cielab->range, gamma));
+ }
+
+ /* Blue */
+ gamma = 1.0 / cielab->display.d_gammaB ;
+ cielab->bstep =
+ (cielab->display.d_YCR - cielab->display.d_Y0R) / cielab->range;
+ for(i = 0; i <= cielab->range; i++) {
+ cielab->Yb2b[i] = cielab->display.d_Vrwb
+ * ((float)pow((double)i / cielab->range, gamma));
+ }
+
+ /* Init reference white point */
+ cielab->X0 = refWhite[0];
+ cielab->Y0 = refWhite[1];
+ cielab->Z0 = refWhite[2];
+
+ return 0;
+}
+
+/*
+ * Convert color value from the YCbCr space to CIE XYZ.
+ * The colorspace conversion algorithm comes from the IJG v5a code;
+ * see below for more information on how it works.
+ */
+#define SHIFT 16
+#define FIX(x) ((int32)((x) * (1L<<SHIFT) + 0.5))
+#define ONE_HALF ((int32)(1<<(SHIFT-1)))
+#define Code2V(c, RB, RW, CR) ((((c)-(int32)(RB))*(float)(CR))/(float)(((RW)-(RB)) ? ((RW)-(RB)) : 1))
+#define CLAMP(f,min,max) ((f)<(min)?(min):(f)>(max)?(max):(f))
+#define HICLAMP(f,max) ((f)>(max)?(max):(f))
+
+void
+TIFFYCbCrtoRGB(TIFFYCbCrToRGB *ycbcr, uint32 Y, int32 Cb, int32 Cr,
+ uint32 *r, uint32 *g, uint32 *b)
+{
+ /* XXX: Only 8-bit YCbCr input supported for now */
+ Y = HICLAMP(Y, 255), Cb = CLAMP(Cb, 0, 255), Cr = CLAMP(Cr, 0, 255);
+
+ *r = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cr_r_tab[Cr]];
+ *g = ycbcr->clamptab[ycbcr->Y_tab[Y]
+ + (int)((ycbcr->Cb_g_tab[Cb] + ycbcr->Cr_g_tab[Cr]) >> SHIFT)];
+ *b = ycbcr->clamptab[ycbcr->Y_tab[Y] + ycbcr->Cb_b_tab[Cb]];
+}
+
+/*
+ * Initialize the YCbCr->RGB conversion tables. The conversion
+ * is done according to the 6.0 spec:
+ *
+ * R = Y + Cr*(2 - 2*LumaRed)
+ * B = Y + Cb*(2 - 2*LumaBlue)
+ * G = Y
+ * - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen
+ * - LumaRed*Cr*(2-2*LumaRed)/LumaGreen
+ *
+ * To avoid floating point arithmetic the fractional constants that
+ * come out of the equations are represented as fixed point values
+ * in the range 0...2^16. We also eliminate multiplications by
+ * pre-calculating possible values indexed by Cb and Cr (this code
+ * assumes conversion is being done for 8-bit samples).
+ */
+int
+TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, float *luma, float *refBlackWhite)
+{
+ TIFFRGBValue* clamptab;
+ int i;
+
+#define LumaRed luma[0]
+#define LumaGreen luma[1]
+#define LumaBlue luma[2]
+
+ clamptab = (TIFFRGBValue*)(
+ (tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)));
+ _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */
+ ycbcr->clamptab = (clamptab += 256);
+ for (i = 0; i < 256; i++)
+ clamptab[i] = (TIFFRGBValue) i;
+ _TIFFmemset(clamptab+256, 255, 2*256); /* v > 255 => 255 */
+ ycbcr->Cr_r_tab = (int*) (clamptab + 3*256);
+ ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256;
+ ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256);
+ ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256;
+ ycbcr->Y_tab = ycbcr->Cb_g_tab + 256;
+
+ { float f1 = 2-2*LumaRed; int32 D1 = FIX(f1);
+ float f2 = LumaRed*f1/LumaGreen; int32 D2 = -FIX(f2);
+ float f3 = 2-2*LumaBlue; int32 D3 = FIX(f3);
+ float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4);
+ int x;
+
+#undef LumaBlue
+#undef LumaGreen
+#undef LumaRed
+
+ /*
+ * i is the actual input pixel value in the range 0..255
+ * Cb and Cr values are in the range -128..127 (actually
+ * they are in a range defined by the ReferenceBlackWhite
+ * tag) so there is some range shifting to do here when
+ * constructing tables indexed by the raw pixel data.
+ */
+ for (i = 0, x = -128; i < 256; i++, x++) {
+ int32 Cr = (int32)Code2V(x, refBlackWhite[4] - 128.0F,
+ refBlackWhite[5] - 128.0F, 127);
+ int32 Cb = (int32)Code2V(x, refBlackWhite[2] - 128.0F,
+ refBlackWhite[3] - 128.0F, 127);
+
+ ycbcr->Cr_r_tab[i] = (int32)((D1*Cr + ONE_HALF)>>SHIFT);
+ ycbcr->Cb_b_tab[i] = (int32)((D3*Cb + ONE_HALF)>>SHIFT);
+ ycbcr->Cr_g_tab[i] = D2*Cr;
+ ycbcr->Cb_g_tab[i] = D4*Cb + ONE_HALF;
+ ycbcr->Y_tab[i] =
+ (int32)Code2V(x + 128, refBlackWhite[0], refBlackWhite[1], 255);
+ }
+ }
+
+ return 0;
+}
+#undef HICLAMP
+#undef CLAMP
+#undef Code2V
+#undef SHIFT
+#undef ONE_HALF
+#undef FIX
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_compress.c b/tiff/libtiff/tif_compress.c
new file mode 100644
index 0000000..0ce509b
--- /dev/null
+++ b/tiff/libtiff/tif_compress.c
@@ -0,0 +1,295 @@
+/* $Id: tif_compress.c,v 1.13.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Compression Scheme Configuration Support.
+ */
+#include "tiffiop.h"
+
+static int
+TIFFNoEncode(TIFF* tif, const char* method)
+{
+ const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
+
+ if (c) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%s %s encoding is not implemented",
+ c->name, method);
+ } else {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Compression scheme %u %s encoding is not implemented",
+ tif->tif_dir.td_compression, method);
+ }
+ return (-1);
+}
+
+int
+_TIFFNoRowEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s)
+{
+ (void) pp; (void) cc; (void) s;
+ return (TIFFNoEncode(tif, "scanline"));
+}
+
+int
+_TIFFNoStripEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s)
+{
+ (void) pp; (void) cc; (void) s;
+ return (TIFFNoEncode(tif, "strip"));
+}
+
+int
+_TIFFNoTileEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s)
+{
+ (void) pp; (void) cc; (void) s;
+ return (TIFFNoEncode(tif, "tile"));
+}
+
+static int
+TIFFNoDecode(TIFF* tif, const char* method)
+{
+ const TIFFCodec* c = TIFFFindCODEC(tif->tif_dir.td_compression);
+
+ if (c)
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%s %s decoding is not implemented",
+ c->name, method);
+ else
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Compression scheme %u %s decoding is not implemented",
+ tif->tif_dir.td_compression, method);
+ return (-1);
+}
+
+int
+_TIFFNoRowDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s)
+{
+ (void) pp; (void) cc; (void) s;
+ return (TIFFNoDecode(tif, "scanline"));
+}
+
+int
+_TIFFNoStripDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s)
+{
+ (void) pp; (void) cc; (void) s;
+ return (TIFFNoDecode(tif, "strip"));
+}
+
+int
+_TIFFNoTileDecode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s)
+{
+ (void) pp; (void) cc; (void) s;
+ return (TIFFNoDecode(tif, "tile"));
+}
+
+int
+_TIFFNoSeek(TIFF* tif, uint32 off)
+{
+ (void) off;
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Compression algorithm does not support random access");
+ return (0);
+}
+
+int
+_TIFFNoPreCode(TIFF* tif, tsample_t s)
+{
+ (void) tif; (void) s;
+ return (1);
+}
+
+static int _TIFFtrue(TIFF* tif) { (void) tif; return (1); }
+static void _TIFFvoid(TIFF* tif) { (void) tif; }
+
+void
+_TIFFSetDefaultCompressionState(TIFF* tif)
+{
+ tif->tif_decodestatus = TRUE;
+ tif->tif_setupdecode = _TIFFtrue;
+ tif->tif_predecode = _TIFFNoPreCode;
+ tif->tif_decoderow = _TIFFNoRowDecode;
+ tif->tif_decodestrip = _TIFFNoStripDecode;
+ tif->tif_decodetile = _TIFFNoTileDecode;
+ tif->tif_encodestatus = TRUE;
+ tif->tif_setupencode = _TIFFtrue;
+ tif->tif_preencode = _TIFFNoPreCode;
+ tif->tif_postencode = _TIFFtrue;
+ tif->tif_encoderow = _TIFFNoRowEncode;
+ tif->tif_encodestrip = _TIFFNoStripEncode;
+ tif->tif_encodetile = _TIFFNoTileEncode;
+ tif->tif_close = _TIFFvoid;
+ tif->tif_seek = _TIFFNoSeek;
+ tif->tif_cleanup = _TIFFvoid;
+ tif->tif_defstripsize = _TIFFDefaultStripSize;
+ tif->tif_deftilesize = _TIFFDefaultTileSize;
+ tif->tif_flags &= ~(TIFF_NOBITREV|TIFF_NOREADRAW);
+}
+
+int
+TIFFSetCompressionScheme(TIFF* tif, int scheme)
+{
+ const TIFFCodec *c = TIFFFindCODEC((uint16) scheme);
+
+ _TIFFSetDefaultCompressionState(tif);
+ /*
+ * Don't treat an unknown compression scheme as an error.
+ * This permits applications to open files with data that
+ * the library does not have builtin support for, but which
+ * may still be meaningful.
+ */
+ return (c ? (*c->init)(tif, scheme) : 1);
+}
+
+/*
+ * Other compression schemes may be registered. Registered
+ * schemes can also override the builtin versions provided
+ * by this library.
+ */
+typedef struct _codec {
+ struct _codec* next;
+ TIFFCodec* info;
+} codec_t;
+static codec_t* registeredCODECS = NULL;
+
+const TIFFCodec*
+TIFFFindCODEC(uint16 scheme)
+{
+ const TIFFCodec* c;
+ codec_t* cd;
+
+ for (cd = registeredCODECS; cd; cd = cd->next)
+ if (cd->info->scheme == scheme)
+ return ((const TIFFCodec*) cd->info);
+ for (c = _TIFFBuiltinCODECS; c->name; c++)
+ if (c->scheme == scheme)
+ return (c);
+ return ((const TIFFCodec*) 0);
+}
+
+TIFFCodec*
+TIFFRegisterCODEC(uint16 scheme, const char* name, TIFFInitMethod init)
+{
+ codec_t* cd = (codec_t*)
+ _TIFFmalloc(sizeof (codec_t) + sizeof (TIFFCodec) + strlen(name)+1);
+
+ if (cd != NULL) {
+ cd->info = (TIFFCodec*) ((tidata_t) cd + sizeof (codec_t));
+ cd->info->name = (char*)
+ ((tidata_t) cd->info + sizeof (TIFFCodec));
+ strcpy(cd->info->name, name);
+ cd->info->scheme = scheme;
+ cd->info->init = init;
+ cd->next = registeredCODECS;
+ registeredCODECS = cd;
+ } else {
+ TIFFErrorExt(0, "TIFFRegisterCODEC",
+ "No space to register compression scheme %s", name);
+ return NULL;
+ }
+ return (cd->info);
+}
+
+void
+TIFFUnRegisterCODEC(TIFFCodec* c)
+{
+ codec_t* cd;
+ codec_t** pcd;
+
+ for (pcd = &registeredCODECS; (cd = *pcd); pcd = &cd->next)
+ if (cd->info == c) {
+ *pcd = cd->next;
+ _TIFFfree(cd);
+ return;
+ }
+ TIFFErrorExt(0, "TIFFUnRegisterCODEC",
+ "Cannot remove compression scheme %s; not registered", c->name);
+}
+
+/************************************************************************/
+/* TIFFGetConfisuredCODECs() */
+/************************************************************************/
+
+/**
+ * Get list of configured codecs, both built-in and registered by user.
+ * Caller is responsible to free this structure.
+ *
+ * @return returns array of TIFFCodec records (the last record should be NULL)
+ * or NULL if function failed.
+ */
+
+TIFFCodec*
+TIFFGetConfiguredCODECs()
+{
+ int i = 1;
+ codec_t *cd;
+ const TIFFCodec *c;
+ TIFFCodec *codecs = NULL, *new_codecs;
+
+ for (cd = registeredCODECS; cd; cd = cd->next) {
+ new_codecs = (TIFFCodec *)
+ _TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+ if (!new_codecs) {
+ _TIFFfree (codecs);
+ return NULL;
+ }
+ codecs = new_codecs;
+ _TIFFmemcpy(codecs + i - 1, cd, sizeof(TIFFCodec));
+ i++;
+ }
+ for (c = _TIFFBuiltinCODECS; c->name; c++) {
+ if (TIFFIsCODECConfigured(c->scheme)) {
+ new_codecs = (TIFFCodec *)
+ _TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+ if (!new_codecs) {
+ _TIFFfree (codecs);
+ return NULL;
+ }
+ codecs = new_codecs;
+ _TIFFmemcpy(codecs + i - 1, (const tdata_t)c, sizeof(TIFFCodec));
+ i++;
+ }
+ }
+
+ new_codecs = (TIFFCodec *) _TIFFrealloc(codecs, i * sizeof(TIFFCodec));
+ if (!new_codecs) {
+ _TIFFfree (codecs);
+ return NULL;
+ }
+ codecs = new_codecs;
+ _TIFFmemset(codecs + i - 1, 0, sizeof(TIFFCodec));
+
+ return codecs;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_config.h-vms b/tiff/libtiff/tif_config.h-vms
new file mode 100644
index 0000000..d653bd8
--- /dev/null
+++ b/tiff/libtiff/tif_config.h-vms
@@ -0,0 +1,46 @@
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+#define HAVE_IEEEFP 1
+
+#define HAVE_UNISTD_H 1
+
+#define HAVE_STRING_H 1
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <io.h> header file. */
+//#define HAVE_IO_H 1
+
+/* Define to 1 if you have the <search.h> header file. */
+//#define HAVE_SEARCH_H 1
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* Set the native cpu bit order */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+/*
+#ifndef __cplusplus
+# ifndef inline
+# define inline __inline
+# endif
+#endif
+*/
+
+// #define lfind _lfind
diff --git a/tiff/libtiff/tif_config.h.in b/tiff/libtiff/tif_config.h.in
new file mode 100644
index 0000000..01e54de
--- /dev/null
+++ b/tiff/libtiff/tif_config.h.in
@@ -0,0 +1,309 @@
+/* libtiff/tif_config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Support CCITT Group 3 & 4 algorithms */
+#undef CCITT_SUPPORT
+
+/* Pick up YCbCr subsampling info from the JPEG data stream to support files
+ lacking the tag (default enabled). */
+#undef CHECK_JPEG_YCBCR_SUBSAMPLING
+
+/* Support C++ stream API (requires C++ compiler) */
+#undef CXX_SUPPORT
+
+/* Treat extra sample as alpha (default enabled). The RGBA interface will
+ treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+ packages produce RGBA files but don't mark the alpha properly. */
+#undef DEFAULT_EXTRASAMPLE_AS_ALPHA
+
+/* Use the Apple OpenGL framework. */
+#undef HAVE_APPLE_OPENGL_FRAMEWORK
+
+/* Define to 1 if you have the <assert.h> header file. */
+#undef HAVE_ASSERT_H
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `floor' function. */
+#undef HAVE_FLOOR
+
+/* Define to 1 if you have the `getopt' function. */
+#undef HAVE_GETOPT
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+#undef HAVE_IEEEFP
+
+/* Define to 1 if the system has the type `int16'. */
+#undef HAVE_INT16
+
+/* Define to 1 if the system has the type `int32'. */
+#undef HAVE_INT32
+
+/* Define to 1 if the system has the type `int8'. */
+#undef HAVE_INT8
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* Define to 1 if you have the `isascii' function. */
+#undef HAVE_ISASCII
+
+/* Define to 1 if you have the `jbg_newlen' function. */
+#undef HAVE_JBG_NEWLEN
+
+/* Define to 1 if you have the `lfind' function. */
+#undef HAVE_LFIND
+
+/* Define to 1 if you have the `c' library (-lc). */
+#undef HAVE_LIBC
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the `mmap' function. */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the `pow' function. */
+#undef HAVE_POW
+
+/* Define if you have POSIX threads libraries and header files. */
+#undef HAVE_PTHREAD
+
+/* Define to 1 if you have the <search.h> header file. */
+#undef HAVE_SEARCH_H
+
+/* Define to 1 if you have the `setmode' function. */
+#undef HAVE_SETMODE
+
+/* Define to 1 if you have the `sqrt' function. */
+#undef HAVE_SQRT
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the `strchr' function. */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strrchr' function. */
+#undef HAVE_STRRCHR
+
+/* Define to 1 if you have the `strstr' function. */
+#undef HAVE_STRSTR
+
+/* Define to 1 if you have the `strtol' function. */
+#undef HAVE_STRTOL
+
+/* Define to 1 if you have the `strtoul' function. */
+#undef HAVE_STRTOUL
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the <windows.h> header file. */
+#undef HAVE_WINDOWS_H
+
+/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
+ (Intel) */
+#undef HOST_BIGENDIAN
+
+/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
+#undef HOST_FILLORDER
+
+/* Support ISO JBIG compression (requires JBIG-KIT library) */
+#undef JBIG_SUPPORT
+
+/* Support JPEG compression (requires IJG JPEG library) */
+#undef JPEG_SUPPORT
+
+/* Support LogLuv high dynamic range encoding */
+#undef LOGLUV_SUPPORT
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Support LZW algorithm */
+#undef LZW_SUPPORT
+
+/* Support Microsoft Document Imaging format */
+#undef MDI_SUPPORT
+
+/* Support NeXT 2-bit RLE algorithm */
+#undef NEXT_SUPPORT
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Support Old JPEG compresson (read-only) */
+#undef OJPEG_SUPPORT
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Support Macintosh PackBits algorithm */
+#undef PACKBITS_SUPPORT
+
+/* Support Pixar log-format algorithm (requires Zlib) */
+#undef PIXARLOG_SUPPORT
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+#undef PTHREAD_CREATE_JOINABLE
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `signed long', as computed by sizeof. */
+#undef SIZEOF_SIGNED_LONG
+
+/* The size of `signed long long', as computed by sizeof. */
+#undef SIZEOF_SIGNED_LONG_LONG
+
+/* The size of `unsigned long', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* The size of `unsigned long long', as computed by sizeof. */
+#undef SIZEOF_UNSIGNED_LONG_LONG
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Support strip chopping (whether or not to convert single-strip uncompressed
+ images to mutiple strips of specified size to reduce memory usage) */
+#undef STRIPCHOP_DEFAULT
+
+/* Default size of the strip in bytes (when strip chopping enabled) */
+#undef STRIP_SIZE_DEFAULT
+
+/* Enable SubIFD tag (330) support */
+#undef SUBIFD_SUPPORT
+
+/* Support ThunderScan 4-bit RLE algorithm */
+#undef THUNDER_SUPPORT
+
+/* Signed 64-bit type formatter */
+#undef TIFF_INT64_FORMAT
+
+/* Signed 64-bit type */
+#undef TIFF_INT64_T
+
+/* Unsigned 64-bit type formatter */
+#undef TIFF_UINT64_FORMAT
+
+/* Unsigned 64-bit type */
+#undef TIFF_UINT64_T
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+# undef WORDS_BIGENDIAN
+# endif
+#endif
+
+/* Define to 1 if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+/* Support Deflate compression */
+#undef ZIP_SUPPORT
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `long int' if <sys/types.h> does not define. */
+#undef off_t
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
diff --git a/tiff/libtiff/tif_config.vc.h b/tiff/libtiff/tif_config.vc.h
new file mode 100644
index 0000000..4dd77dd
--- /dev/null
+++ b/tiff/libtiff/tif_config.vc.h
@@ -0,0 +1,63 @@
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+#define HAVE_IEEEFP 1
+
+/* Define to 1 if you have the `jbg_newlen' function. */
+#define HAVE_JBG_NEWLEN 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define to 1 if you have the <search.h> header file. */
+#define HAVE_SEARCH_H 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed __int64
+
+/* Unsigned 64-bit type */
+#define TIFF_UINT64_T unsigned __int64
+
+/* Set the native cpu bit order */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+# ifndef inline
+# define inline __inline
+# endif
+#endif
+
+#define lfind _lfind
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_config.wince.h b/tiff/libtiff/tif_config.wince.h
new file mode 100644
index 0000000..857c651
--- /dev/null
+++ b/tiff/libtiff/tif_config.wince.h
@@ -0,0 +1,74 @@
+/* $Id: tif_config.wince.h,v 1.1.2.1 2010-06-08 18:50:41 bfriesen Exp $ */
+
+/*
+ * TIFF library configuration header for Windows CE platform.
+ */
+#ifndef _WIN32_WCE
+# error This version of tif_config.h header is dedicated for Windows CE platform!
+#endif
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+#define HAVE_IEEEFP 1
+
+/* Define to 1 if you have the `jbg_newlen' function. */
+#define HAVE_JBG_NEWLEN 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define to 1 if you have the <search.h> header file. */
+#define HAVE_SEARCH_H 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `bsearch' function. */
+#define HAVE_BSEARCH 1
+#define bsearch wceex_bsearch
+
+/* Define to 1 if you have the `lfind' function. */
+#define HAVE_LFIND 1
+#define lfind wceex_lfind
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* Set the native cpu bit order */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+# ifndef inline
+# define inline __inline
+# endif
+#endif
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_dir.c b/tiff/libtiff/tif_dir.c
new file mode 100644
index 0000000..ac44b38
--- /dev/null
+++ b/tiff/libtiff/tif_dir.c
@@ -0,0 +1,1389 @@
+/* $Id: tif_dir.c,v 1.75.2.5 2010-06-09 21:15:27 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Tag Get & Set Routines.
+ * (and also some miscellaneous stuff)
+ */
+#include "tiffiop.h"
+
+/*
+ * These are used in the backwards compatibility code...
+ */
+#define DATATYPE_VOID 0 /* !untyped data */
+#define DATATYPE_INT 1 /* !signed integer data */
+#define DATATYPE_UINT 2 /* !unsigned integer data */
+#define DATATYPE_IEEEFP 3 /* !IEEE floating point data */
+
+static void
+setByteArray(void** vpp, void* vp, size_t nmemb, size_t elem_size)
+{
+ if (*vpp)
+ _TIFFfree(*vpp), *vpp = 0;
+ if (vp) {
+ tsize_t bytes = nmemb * elem_size;
+ if (elem_size && bytes / elem_size == nmemb)
+ *vpp = (void*) _TIFFmalloc(bytes);
+ if (*vpp)
+ _TIFFmemcpy(*vpp, vp, bytes);
+ }
+}
+void _TIFFsetByteArray(void** vpp, void* vp, uint32 n)
+ { setByteArray(vpp, vp, n, 1); }
+void _TIFFsetString(char** cpp, char* cp)
+ { setByteArray((void**) cpp, (void*) cp, strlen(cp)+1, 1); }
+void _TIFFsetNString(char** cpp, char* cp, uint32 n)
+ { setByteArray((void**) cpp, (void*) cp, n, 1); }
+void _TIFFsetShortArray(uint16** wpp, uint16* wp, uint32 n)
+ { setByteArray((void**) wpp, (void*) wp, n, sizeof (uint16)); }
+void _TIFFsetLongArray(uint32** lpp, uint32* lp, uint32 n)
+ { setByteArray((void**) lpp, (void*) lp, n, sizeof (uint32)); }
+void _TIFFsetFloatArray(float** fpp, float* fp, uint32 n)
+ { setByteArray((void**) fpp, (void*) fp, n, sizeof (float)); }
+void _TIFFsetDoubleArray(double** dpp, double* dp, uint32 n)
+ { setByteArray((void**) dpp, (void*) dp, n, sizeof (double)); }
+
+/*
+ * Install extra samples information.
+ */
+static int
+setExtraSamples(TIFFDirectory* td, va_list ap, uint32* v)
+{
+/* XXX: Unassociated alpha data == 999 is a known Corel Draw bug, see below */
+#define EXTRASAMPLE_COREL_UNASSALPHA 999
+
+ uint16* va;
+ uint32 i;
+
+ *v = va_arg(ap, uint32);
+ if ((uint16) *v > td->td_samplesperpixel)
+ return 0;
+ va = va_arg(ap, uint16*);
+ if (*v > 0 && va == NULL) /* typically missing param */
+ return 0;
+ for (i = 0; i < *v; i++) {
+ if (va[i] > EXTRASAMPLE_UNASSALPHA) {
+ /*
+ * XXX: Corel Draw is known to produce incorrect
+ * ExtraSamples tags which must be patched here if we
+ * want to be able to open some of the damaged TIFF
+ * files:
+ */
+ if (va[i] == EXTRASAMPLE_COREL_UNASSALPHA)
+ va[i] = EXTRASAMPLE_UNASSALPHA;
+ else
+ return 0;
+ }
+ }
+ td->td_extrasamples = (uint16) *v;
+ _TIFFsetShortArray(&td->td_sampleinfo, va, td->td_extrasamples);
+ return 1;
+
+#undef EXTRASAMPLE_COREL_UNASSALPHA
+}
+
+static uint32
+checkInkNamesString(TIFF* tif, uint32 slen, const char* s)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ uint16 i = td->td_samplesperpixel;
+
+ if (slen > 0) {
+ const char* ep = s+slen;
+ const char* cp = s;
+ for (; i > 0; i--) {
+ for (; *cp != '\0'; cp++)
+ if (cp >= ep)
+ goto bad;
+ cp++; /* skip \0 */
+ }
+ return (cp-s);
+ }
+bad:
+ TIFFErrorExt(tif->tif_clientdata, "TIFFSetField",
+ "%s: Invalid InkNames value; expecting %d names, found %d",
+ tif->tif_name,
+ td->td_samplesperpixel,
+ td->td_samplesperpixel-i);
+ return (0);
+}
+
+static int
+_TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ static const char module[] = "_TIFFVSetField";
+
+ TIFFDirectory* td = &tif->tif_dir;
+ int status = 1;
+ uint32 v32, i, v;
+ char* s;
+
+ switch (tag) {
+ case TIFFTAG_SUBFILETYPE:
+ td->td_subfiletype = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_IMAGEWIDTH:
+ td->td_imagewidth = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_IMAGELENGTH:
+ td->td_imagelength = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_BITSPERSAMPLE:
+ td->td_bitspersample = (uint16) va_arg(ap, int);
+ /*
+ * If the data require post-decoding processing to byte-swap
+ * samples, set it up here. Note that since tags are required
+ * to be ordered, compression code can override this behaviour
+ * in the setup method if it wants to roll the post decoding
+ * work in with its normal work.
+ */
+ if (tif->tif_flags & TIFF_SWAB) {
+ if (td->td_bitspersample == 16)
+ tif->tif_postdecode = _TIFFSwab16BitData;
+ else if (td->td_bitspersample == 24)
+ tif->tif_postdecode = _TIFFSwab24BitData;
+ else if (td->td_bitspersample == 32)
+ tif->tif_postdecode = _TIFFSwab32BitData;
+ else if (td->td_bitspersample == 64)
+ tif->tif_postdecode = _TIFFSwab64BitData;
+ else if (td->td_bitspersample == 128) /* two 64's */
+ tif->tif_postdecode = _TIFFSwab64BitData;
+ }
+ break;
+ case TIFFTAG_COMPRESSION:
+ v = va_arg(ap, uint32) & 0xffff;
+ /*
+ * If we're changing the compression scheme, the notify the
+ * previous module so that it can cleanup any state it's
+ * setup.
+ */
+ if (TIFFFieldSet(tif, FIELD_COMPRESSION)) {
+ if (td->td_compression == v)
+ break;
+ (*tif->tif_cleanup)(tif);
+ tif->tif_flags &= ~TIFF_CODERSETUP;
+ }
+ /*
+ * Setup new compression routine state.
+ */
+ if( (status = TIFFSetCompressionScheme(tif, v)) != 0 )
+ td->td_compression = (uint16) v;
+ else
+ status = 0;
+ break;
+ case TIFFTAG_PHOTOMETRIC:
+ td->td_photometric = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_THRESHHOLDING:
+ td->td_threshholding = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_FILLORDER:
+ v = va_arg(ap, uint32);
+ if (v != FILLORDER_LSB2MSB && v != FILLORDER_MSB2LSB)
+ goto badvalue;
+ td->td_fillorder = (uint16) v;
+ break;
+ case TIFFTAG_ORIENTATION:
+ v = va_arg(ap, uint32);
+ if (v < ORIENTATION_TOPLEFT || ORIENTATION_LEFTBOT < v)
+ goto badvalue;
+ else
+ td->td_orientation = (uint16) v;
+ break;
+ case TIFFTAG_SAMPLESPERPIXEL:
+ /* XXX should cross check -- e.g. if pallette, then 1 */
+ v = va_arg(ap, uint32);
+ if (v == 0)
+ goto badvalue;
+ td->td_samplesperpixel = (uint16) v;
+ break;
+ case TIFFTAG_ROWSPERSTRIP:
+ v32 = va_arg(ap, uint32);
+ if (v32 == 0)
+ goto badvalue32;
+ td->td_rowsperstrip = v32;
+ if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
+ td->td_tilelength = v32;
+ td->td_tilewidth = td->td_imagewidth;
+ }
+ break;
+ case TIFFTAG_MINSAMPLEVALUE:
+ td->td_minsamplevalue = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_MAXSAMPLEVALUE:
+ td->td_maxsamplevalue = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_SMINSAMPLEVALUE:
+ td->td_sminsamplevalue = va_arg(ap, double);
+ break;
+ case TIFFTAG_SMAXSAMPLEVALUE:
+ td->td_smaxsamplevalue = va_arg(ap, double);
+ break;
+ case TIFFTAG_XRESOLUTION:
+ td->td_xresolution = (float) va_arg(ap, double);
+ break;
+ case TIFFTAG_YRESOLUTION:
+ td->td_yresolution = (float) va_arg(ap, double);
+ break;
+ case TIFFTAG_PLANARCONFIG:
+ v = va_arg(ap, uint32);
+ if (v != PLANARCONFIG_CONTIG && v != PLANARCONFIG_SEPARATE)
+ goto badvalue;
+ td->td_planarconfig = (uint16) v;
+ break;
+ case TIFFTAG_XPOSITION:
+ td->td_xposition = (float) va_arg(ap, double);
+ break;
+ case TIFFTAG_YPOSITION:
+ td->td_yposition = (float) va_arg(ap, double);
+ break;
+ case TIFFTAG_RESOLUTIONUNIT:
+ v = va_arg(ap, uint32);
+ if (v < RESUNIT_NONE || RESUNIT_CENTIMETER < v)
+ goto badvalue;
+ td->td_resolutionunit = (uint16) v;
+ break;
+ case TIFFTAG_PAGENUMBER:
+ td->td_pagenumber[0] = (uint16) va_arg(ap, int);
+ td->td_pagenumber[1] = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_HALFTONEHINTS:
+ td->td_halftonehints[0] = (uint16) va_arg(ap, int);
+ td->td_halftonehints[1] = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_COLORMAP:
+ v32 = (uint32)(1L<<td->td_bitspersample);
+ _TIFFsetShortArray(&td->td_colormap[0], va_arg(ap, uint16*), v32);
+ _TIFFsetShortArray(&td->td_colormap[1], va_arg(ap, uint16*), v32);
+ _TIFFsetShortArray(&td->td_colormap[2], va_arg(ap, uint16*), v32);
+ break;
+ case TIFFTAG_EXTRASAMPLES:
+ if (!setExtraSamples(td, ap, &v))
+ goto badvalue;
+ break;
+ case TIFFTAG_MATTEING:
+ td->td_extrasamples = (uint16) (va_arg(ap, int) != 0);
+ if (td->td_extrasamples) {
+ uint16 sv = EXTRASAMPLE_ASSOCALPHA;
+ _TIFFsetShortArray(&td->td_sampleinfo, &sv, 1);
+ }
+ break;
+ case TIFFTAG_TILEWIDTH:
+ v32 = va_arg(ap, uint32);
+ if (v32 % 16) {
+ if (tif->tif_mode != O_RDONLY)
+ goto badvalue32;
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "Nonstandard tile width %d, convert file", v32);
+ }
+ td->td_tilewidth = v32;
+ tif->tif_flags |= TIFF_ISTILED;
+ break;
+ case TIFFTAG_TILELENGTH:
+ v32 = va_arg(ap, uint32);
+ if (v32 % 16) {
+ if (tif->tif_mode != O_RDONLY)
+ goto badvalue32;
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "Nonstandard tile length %d, convert file", v32);
+ }
+ td->td_tilelength = v32;
+ tif->tif_flags |= TIFF_ISTILED;
+ break;
+ case TIFFTAG_TILEDEPTH:
+ v32 = va_arg(ap, uint32);
+ if (v32 == 0)
+ goto badvalue32;
+ td->td_tiledepth = v32;
+ break;
+ case TIFFTAG_DATATYPE:
+ v = va_arg(ap, uint32);
+ switch (v) {
+ case DATATYPE_VOID: v = SAMPLEFORMAT_VOID; break;
+ case DATATYPE_INT: v = SAMPLEFORMAT_INT; break;
+ case DATATYPE_UINT: v = SAMPLEFORMAT_UINT; break;
+ case DATATYPE_IEEEFP: v = SAMPLEFORMAT_IEEEFP;break;
+ default: goto badvalue;
+ }
+ td->td_sampleformat = (uint16) v;
+ break;
+ case TIFFTAG_SAMPLEFORMAT:
+ v = va_arg(ap, uint32);
+ if (v < SAMPLEFORMAT_UINT || SAMPLEFORMAT_COMPLEXIEEEFP < v)
+ goto badvalue;
+ td->td_sampleformat = (uint16) v;
+
+ /* Try to fix up the SWAB function for complex data. */
+ if( td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT
+ && td->td_bitspersample == 32
+ && tif->tif_postdecode == _TIFFSwab32BitData )
+ tif->tif_postdecode = _TIFFSwab16BitData;
+ else if( (td->td_sampleformat == SAMPLEFORMAT_COMPLEXINT
+ || td->td_sampleformat == SAMPLEFORMAT_COMPLEXIEEEFP)
+ && td->td_bitspersample == 64
+ && tif->tif_postdecode == _TIFFSwab64BitData )
+ tif->tif_postdecode = _TIFFSwab32BitData;
+ break;
+ case TIFFTAG_IMAGEDEPTH:
+ td->td_imagedepth = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_SUBIFD:
+ if ((tif->tif_flags & TIFF_INSUBIFD) == 0) {
+ td->td_nsubifd = (uint16) va_arg(ap, int);
+ _TIFFsetLongArray(&td->td_subifd, va_arg(ap, uint32*),
+ (long) td->td_nsubifd);
+ } else {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Sorry, cannot nest SubIFDs",
+ tif->tif_name);
+ status = 0;
+ }
+ break;
+ case TIFFTAG_YCBCRPOSITIONING:
+ td->td_ycbcrpositioning = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ td->td_ycbcrsubsampling[0] = (uint16) va_arg(ap, int);
+ td->td_ycbcrsubsampling[1] = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_TRANSFERFUNCTION:
+ v = (td->td_samplesperpixel - td->td_extrasamples) > 1 ? 3 : 1;
+ for (i = 0; i < v; i++)
+ _TIFFsetShortArray(&td->td_transferfunction[i],
+ va_arg(ap, uint16*), 1L<<td->td_bitspersample);
+ break;
+ case TIFFTAG_REFERENCEBLACKWHITE:
+ /* XXX should check for null range */
+ _TIFFsetFloatArray(&td->td_refblackwhite, va_arg(ap, float*), 6);
+ break;
+ case TIFFTAG_INKNAMES:
+ v = va_arg(ap, uint32);
+ s = va_arg(ap, char*);
+ v = checkInkNamesString(tif, v, s);
+ status = v > 0;
+ if( v > 0 ) {
+ _TIFFsetNString(&td->td_inknames, s, v);
+ td->td_inknameslen = v;
+ }
+ break;
+ default: {
+ TIFFTagValue *tv;
+ int tv_size, iCustom;
+ const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY);
+
+ /*
+ * This can happen if multiple images are open with different
+ * codecs which have private tags. The global tag information
+ * table may then have tags that are valid for one file but not
+ * the other. If the client tries to set a tag that is not valid
+ * for the image's codec then we'll arrive here. This
+ * happens, for example, when tiffcp is used to convert between
+ * compression schemes and codec-specific tags are blindly copied.
+ */
+ if(fip == NULL || fip->field_bit != FIELD_CUSTOM) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Invalid %stag \"%s\" (not supported by codec)",
+ tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "",
+ fip ? fip->field_name : "Unknown");
+ status = 0;
+ break;
+ }
+
+ /*
+ * Find the existing entry for this custom value.
+ */
+ tv = NULL;
+ for (iCustom = 0; iCustom < td->td_customValueCount; iCustom++) {
+ if (td->td_customValues[iCustom].info->field_tag == tag) {
+ tv = td->td_customValues + iCustom;
+ if (tv->value != NULL) {
+ _TIFFfree(tv->value);
+ tv->value = NULL;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Grow the custom list if the entry was not found.
+ */
+ if(tv == NULL) {
+ TIFFTagValue *new_customValues;
+
+ td->td_customValueCount++;
+ new_customValues = (TIFFTagValue *)
+ _TIFFrealloc(td->td_customValues,
+ sizeof(TIFFTagValue) * td->td_customValueCount);
+ if (!new_customValues) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Failed to allocate space for list of custom values",
+ tif->tif_name);
+ status = 0;
+ goto end;
+ }
+
+ td->td_customValues = new_customValues;
+
+ tv = td->td_customValues + (td->td_customValueCount - 1);
+ tv->info = fip;
+ tv->value = NULL;
+ tv->count = 0;
+ }
+
+ /*
+ * Set custom value ... save a copy of the custom tag value.
+ */
+ tv_size = _TIFFDataSize(fip->field_type);
+ if (tv_size == 0) {
+ status = 0;
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Bad field type %d for \"%s\"",
+ tif->tif_name, fip->field_type,
+ fip->field_name);
+ goto end;
+ }
+
+ if(fip->field_passcount) {
+ if (fip->field_writecount == TIFF_VARIABLE2)
+ tv->count = (uint32) va_arg(ap, uint32);
+ else
+ tv->count = (int) va_arg(ap, int);
+ } else if (fip->field_writecount == TIFF_VARIABLE
+ || fip->field_writecount == TIFF_VARIABLE2)
+ tv->count = 1;
+ else if (fip->field_writecount == TIFF_SPP)
+ tv->count = td->td_samplesperpixel;
+ else
+ tv->count = fip->field_writecount;
+
+
+ if (fip->field_type == TIFF_ASCII)
+ _TIFFsetString((char **)&tv->value, va_arg(ap, char *));
+ else {
+ tv->value = _TIFFCheckMalloc(tif, tv_size, tv->count,
+ "Tag Value");
+ if (!tv->value) {
+ status = 0;
+ goto end;
+ }
+
+ if ((fip->field_passcount
+ || fip->field_writecount == TIFF_VARIABLE
+ || fip->field_writecount == TIFF_VARIABLE2
+ || fip->field_writecount == TIFF_SPP
+ || tv->count > 1)
+ && fip->field_tag != TIFFTAG_PAGENUMBER
+ && fip->field_tag != TIFFTAG_HALFTONEHINTS
+ && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
+ && fip->field_tag != TIFFTAG_DOTRANGE) {
+ _TIFFmemcpy(tv->value, va_arg(ap, void *),
+ tv->count * tv_size);
+ } else {
+ /*
+ * XXX: The following loop required to handle
+ * TIFFTAG_PAGENUMBER, TIFFTAG_HALFTONEHINTS,
+ * TIFFTAG_YCBCRSUBSAMPLING and TIFFTAG_DOTRANGE tags.
+ * These tags are actually arrays and should be passed as
+ * array pointers to TIFFSetField() function, but actually
+ * passed as a list of separate values. This behaviour
+ * must be changed in the future!
+ */
+ int i;
+ char *val = (char *)tv->value;
+
+ for (i = 0; i < tv->count; i++, val += tv_size) {
+ switch (fip->field_type) {
+ case TIFF_BYTE:
+ case TIFF_UNDEFINED:
+ {
+ uint8 v = (uint8)va_arg(ap, int);
+ _TIFFmemcpy(val, &v, tv_size);
+ }
+ break;
+ case TIFF_SBYTE:
+ {
+ int8 v = (int8)va_arg(ap, int);
+ _TIFFmemcpy(val, &v, tv_size);
+ }
+ break;
+ case TIFF_SHORT:
+ {
+ uint16 v = (uint16)va_arg(ap, int);
+ _TIFFmemcpy(val, &v, tv_size);
+ }
+ break;
+ case TIFF_SSHORT:
+ {
+ int16 v = (int16)va_arg(ap, int);
+ _TIFFmemcpy(val, &v, tv_size);
+ }
+ break;
+ case TIFF_LONG:
+ case TIFF_IFD:
+ {
+ uint32 v = va_arg(ap, uint32);
+ _TIFFmemcpy(val, &v, tv_size);
+ }
+ break;
+ case TIFF_SLONG:
+ {
+ int32 v = va_arg(ap, int32);
+ _TIFFmemcpy(val, &v, tv_size);
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ {
+ float v = (float)va_arg(ap, double);
+ _TIFFmemcpy(val, &v, tv_size);
+ }
+ break;
+ case TIFF_DOUBLE:
+ {
+ double v = va_arg(ap, double);
+ _TIFFmemcpy(val, &v, tv_size);
+ }
+ break;
+ default:
+ _TIFFmemset(val, 0, tv_size);
+ status = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (status) {
+ TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit);
+ tif->tif_flags |= TIFF_DIRTYDIRECT;
+ }
+
+end:
+ va_end(ap);
+ return (status);
+badvalue:
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Bad value %d for \"%s\" tag",
+ tif->tif_name, v,
+ _TIFFFieldWithTag(tif, tag)->field_name);
+ va_end(ap);
+ return (0);
+badvalue32:
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Bad value %u for \"%s\" tag",
+ tif->tif_name, v32,
+ _TIFFFieldWithTag(tif, tag)->field_name);
+ va_end(ap);
+ return (0);
+}
+
+/*
+ * Return 1/0 according to whether or not
+ * it is permissible to set the tag's value.
+ * Note that we allow ImageLength to be changed
+ * so that we can append and extend to images.
+ * Any other tag may not be altered once writing
+ * has commenced, unless its value has no effect
+ * on the format of the data that is written.
+ */
+static int
+OkToChangeTag(TIFF* tif, ttag_t tag)
+{
+ const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY);
+ if (!fip) { /* unknown tag */
+ TIFFErrorExt(tif->tif_clientdata, "TIFFSetField", "%s: Unknown %stag %u",
+ tif->tif_name, isPseudoTag(tag) ? "pseudo-" : "", tag);
+ return (0);
+ }
+ if (tag != TIFFTAG_IMAGELENGTH && (tif->tif_flags & TIFF_BEENWRITING) &&
+ !fip->field_oktochange) {
+ /*
+ * Consult info table to see if tag can be changed
+ * after we've started writing. We only allow changes
+ * to those tags that don't/shouldn't affect the
+ * compression and/or format of the data.
+ */
+ TIFFErrorExt(tif->tif_clientdata, "TIFFSetField",
+ "%s: Cannot modify tag \"%s\" while writing",
+ tif->tif_name, fip->field_name);
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Record the value of a field in the
+ * internal directory structure. The
+ * field will be written to the file
+ * when/if the directory structure is
+ * updated.
+ */
+int
+TIFFSetField(TIFF* tif, ttag_t tag, ...)
+{
+ va_list ap;
+ int status;
+
+ va_start(ap, tag);
+ status = TIFFVSetField(tif, tag, ap);
+ va_end(ap);
+ return (status);
+}
+
+/*
+ * Like TIFFSetField, but taking a varargs
+ * parameter list. This routine is useful
+ * for building higher-level interfaces on
+ * top of the library.
+ */
+int
+TIFFVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ return OkToChangeTag(tif, tag) ?
+ (*tif->tif_tagmethods.vsetfield)(tif, tag, ap) : 0;
+}
+
+static int
+_TIFFVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ int ret_val = 1;
+
+ switch (tag) {
+ case TIFFTAG_SUBFILETYPE:
+ *va_arg(ap, uint32*) = td->td_subfiletype;
+ break;
+ case TIFFTAG_IMAGEWIDTH:
+ *va_arg(ap, uint32*) = td->td_imagewidth;
+ break;
+ case TIFFTAG_IMAGELENGTH:
+ *va_arg(ap, uint32*) = td->td_imagelength;
+ break;
+ case TIFFTAG_BITSPERSAMPLE:
+ *va_arg(ap, uint16*) = td->td_bitspersample;
+ break;
+ case TIFFTAG_COMPRESSION:
+ *va_arg(ap, uint16*) = td->td_compression;
+ break;
+ case TIFFTAG_PHOTOMETRIC:
+ *va_arg(ap, uint16*) = td->td_photometric;
+ break;
+ case TIFFTAG_THRESHHOLDING:
+ *va_arg(ap, uint16*) = td->td_threshholding;
+ break;
+ case TIFFTAG_FILLORDER:
+ *va_arg(ap, uint16*) = td->td_fillorder;
+ break;
+ case TIFFTAG_ORIENTATION:
+ *va_arg(ap, uint16*) = td->td_orientation;
+ break;
+ case TIFFTAG_SAMPLESPERPIXEL:
+ *va_arg(ap, uint16*) = td->td_samplesperpixel;
+ break;
+ case TIFFTAG_ROWSPERSTRIP:
+ *va_arg(ap, uint32*) = td->td_rowsperstrip;
+ break;
+ case TIFFTAG_MINSAMPLEVALUE:
+ *va_arg(ap, uint16*) = td->td_minsamplevalue;
+ break;
+ case TIFFTAG_MAXSAMPLEVALUE:
+ *va_arg(ap, uint16*) = td->td_maxsamplevalue;
+ break;
+ case TIFFTAG_SMINSAMPLEVALUE:
+ *va_arg(ap, double*) = td->td_sminsamplevalue;
+ break;
+ case TIFFTAG_SMAXSAMPLEVALUE:
+ *va_arg(ap, double*) = td->td_smaxsamplevalue;
+ break;
+ case TIFFTAG_XRESOLUTION:
+ *va_arg(ap, float*) = td->td_xresolution;
+ break;
+ case TIFFTAG_YRESOLUTION:
+ *va_arg(ap, float*) = td->td_yresolution;
+ break;
+ case TIFFTAG_PLANARCONFIG:
+ *va_arg(ap, uint16*) = td->td_planarconfig;
+ break;
+ case TIFFTAG_XPOSITION:
+ *va_arg(ap, float*) = td->td_xposition;
+ break;
+ case TIFFTAG_YPOSITION:
+ *va_arg(ap, float*) = td->td_yposition;
+ break;
+ case TIFFTAG_RESOLUTIONUNIT:
+ *va_arg(ap, uint16*) = td->td_resolutionunit;
+ break;
+ case TIFFTAG_PAGENUMBER:
+ *va_arg(ap, uint16*) = td->td_pagenumber[0];
+ *va_arg(ap, uint16*) = td->td_pagenumber[1];
+ break;
+ case TIFFTAG_HALFTONEHINTS:
+ *va_arg(ap, uint16*) = td->td_halftonehints[0];
+ *va_arg(ap, uint16*) = td->td_halftonehints[1];
+ break;
+ case TIFFTAG_COLORMAP:
+ *va_arg(ap, uint16**) = td->td_colormap[0];
+ *va_arg(ap, uint16**) = td->td_colormap[1];
+ *va_arg(ap, uint16**) = td->td_colormap[2];
+ break;
+ case TIFFTAG_STRIPOFFSETS:
+ case TIFFTAG_TILEOFFSETS:
+ *va_arg(ap, uint32**) = td->td_stripoffset;
+ break;
+ case TIFFTAG_STRIPBYTECOUNTS:
+ case TIFFTAG_TILEBYTECOUNTS:
+ *va_arg(ap, uint32**) = td->td_stripbytecount;
+ break;
+ case TIFFTAG_MATTEING:
+ *va_arg(ap, uint16*) =
+ (td->td_extrasamples == 1 &&
+ td->td_sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA);
+ break;
+ case TIFFTAG_EXTRASAMPLES:
+ *va_arg(ap, uint16*) = td->td_extrasamples;
+ *va_arg(ap, uint16**) = td->td_sampleinfo;
+ break;
+ case TIFFTAG_TILEWIDTH:
+ *va_arg(ap, uint32*) = td->td_tilewidth;
+ break;
+ case TIFFTAG_TILELENGTH:
+ *va_arg(ap, uint32*) = td->td_tilelength;
+ break;
+ case TIFFTAG_TILEDEPTH:
+ *va_arg(ap, uint32*) = td->td_tiledepth;
+ break;
+ case TIFFTAG_DATATYPE:
+ switch (td->td_sampleformat) {
+ case SAMPLEFORMAT_UINT:
+ *va_arg(ap, uint16*) = DATATYPE_UINT;
+ break;
+ case SAMPLEFORMAT_INT:
+ *va_arg(ap, uint16*) = DATATYPE_INT;
+ break;
+ case SAMPLEFORMAT_IEEEFP:
+ *va_arg(ap, uint16*) = DATATYPE_IEEEFP;
+ break;
+ case SAMPLEFORMAT_VOID:
+ *va_arg(ap, uint16*) = DATATYPE_VOID;
+ break;
+ }
+ break;
+ case TIFFTAG_SAMPLEFORMAT:
+ *va_arg(ap, uint16*) = td->td_sampleformat;
+ break;
+ case TIFFTAG_IMAGEDEPTH:
+ *va_arg(ap, uint32*) = td->td_imagedepth;
+ break;
+ case TIFFTAG_SUBIFD:
+ *va_arg(ap, uint16*) = td->td_nsubifd;
+ *va_arg(ap, uint32**) = td->td_subifd;
+ break;
+ case TIFFTAG_YCBCRPOSITIONING:
+ *va_arg(ap, uint16*) = td->td_ycbcrpositioning;
+ break;
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[0];
+ *va_arg(ap, uint16*) = td->td_ycbcrsubsampling[1];
+ break;
+ case TIFFTAG_TRANSFERFUNCTION:
+ *va_arg(ap, uint16**) = td->td_transferfunction[0];
+ if (td->td_samplesperpixel - td->td_extrasamples > 1) {
+ *va_arg(ap, uint16**) = td->td_transferfunction[1];
+ *va_arg(ap, uint16**) = td->td_transferfunction[2];
+ }
+ break;
+ case TIFFTAG_REFERENCEBLACKWHITE:
+ *va_arg(ap, float**) = td->td_refblackwhite;
+ break;
+ case TIFFTAG_INKNAMES:
+ *va_arg(ap, char**) = td->td_inknames;
+ break;
+ default:
+ {
+ const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY);
+ int i;
+
+ /*
+ * This can happen if multiple images are open with different
+ * codecs which have private tags. The global tag information
+ * table may then have tags that are valid for one file but not
+ * the other. If the client tries to get a tag that is not valid
+ * for the image's codec then we'll arrive here.
+ */
+ if( fip == NULL || fip->field_bit != FIELD_CUSTOM )
+ {
+ TIFFErrorExt(tif->tif_clientdata, "_TIFFVGetField",
+ "%s: Invalid %stag \"%s\" "
+ "(not supported by codec)",
+ tif->tif_name,
+ isPseudoTag(tag) ? "pseudo-" : "",
+ fip ? fip->field_name : "Unknown");
+ ret_val = 0;
+ break;
+ }
+
+ /*
+ * Do we have a custom value?
+ */
+ ret_val = 0;
+ for (i = 0; i < td->td_customValueCount; i++) {
+ TIFFTagValue *tv = td->td_customValues + i;
+
+ if (tv->info->field_tag != tag)
+ continue;
+
+ if (fip->field_passcount) {
+ if (fip->field_readcount == TIFF_VARIABLE2)
+ *va_arg(ap, uint32*) = (uint32)tv->count;
+ else /* Assume TIFF_VARIABLE */
+ *va_arg(ap, uint16*) = (uint16)tv->count;
+ *va_arg(ap, void **) = tv->value;
+ ret_val = 1;
+ } else {
+ if ((fip->field_type == TIFF_ASCII
+ || fip->field_readcount == TIFF_VARIABLE
+ || fip->field_readcount == TIFF_VARIABLE2
+ || fip->field_readcount == TIFF_SPP
+ || tv->count > 1)
+ && fip->field_tag != TIFFTAG_PAGENUMBER
+ && fip->field_tag != TIFFTAG_HALFTONEHINTS
+ && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
+ && fip->field_tag != TIFFTAG_DOTRANGE) {
+ *va_arg(ap, void **) = tv->value;
+ ret_val = 1;
+ } else {
+ int j;
+ char *val = (char *)tv->value;
+
+ for (j = 0; j < tv->count;
+ j++, val += _TIFFDataSize(tv->info->field_type)) {
+ switch (fip->field_type) {
+ case TIFF_BYTE:
+ case TIFF_UNDEFINED:
+ *va_arg(ap, uint8*) =
+ *(uint8 *)val;
+ ret_val = 1;
+ break;
+ case TIFF_SBYTE:
+ *va_arg(ap, int8*) =
+ *(int8 *)val;
+ ret_val = 1;
+ break;
+ case TIFF_SHORT:
+ *va_arg(ap, uint16*) =
+ *(uint16 *)val;
+ ret_val = 1;
+ break;
+ case TIFF_SSHORT:
+ *va_arg(ap, int16*) =
+ *(int16 *)val;
+ ret_val = 1;
+ break;
+ case TIFF_LONG:
+ case TIFF_IFD:
+ *va_arg(ap, uint32*) =
+ *(uint32 *)val;
+ ret_val = 1;
+ break;
+ case TIFF_SLONG:
+ *va_arg(ap, int32*) =
+ *(int32 *)val;
+ ret_val = 1;
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ *va_arg(ap, float*) =
+ *(float *)val;
+ ret_val = 1;
+ break;
+ case TIFF_DOUBLE:
+ *va_arg(ap, double*) =
+ *(double *)val;
+ ret_val = 1;
+ break;
+ default:
+ ret_val = 0;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ return(ret_val);
+}
+
+/*
+ * Return the value of a field in the
+ * internal directory structure.
+ */
+int
+TIFFGetField(TIFF* tif, ttag_t tag, ...)
+{
+ int status;
+ va_list ap;
+
+ va_start(ap, tag);
+ status = TIFFVGetField(tif, tag, ap);
+ va_end(ap);
+ return (status);
+}
+
+/*
+ * Like TIFFGetField, but taking a varargs
+ * parameter list. This routine is useful
+ * for building higher-level interfaces on
+ * top of the library.
+ */
+int
+TIFFVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY);
+ return (fip && (isPseudoTag(tag) || TIFFFieldSet(tif, fip->field_bit)) ?
+ (*tif->tif_tagmethods.vgetfield)(tif, tag, ap) : 0);
+}
+
+#define CleanupField(member) { \
+ if (td->member) { \
+ _TIFFfree(td->member); \
+ td->member = 0; \
+ } \
+}
+
+/*
+ * Release storage associated with a directory.
+ */
+void
+TIFFFreeDirectory(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ int i;
+
+ _TIFFmemset(td->td_fieldsset, 0, FIELD_SETLONGS);
+ CleanupField(td_colormap[0]);
+ CleanupField(td_colormap[1]);
+ CleanupField(td_colormap[2]);
+ CleanupField(td_sampleinfo);
+ CleanupField(td_subifd);
+ CleanupField(td_inknames);
+ CleanupField(td_refblackwhite);
+ CleanupField(td_transferfunction[0]);
+ CleanupField(td_transferfunction[1]);
+ CleanupField(td_transferfunction[2]);
+ CleanupField(td_stripoffset);
+ CleanupField(td_stripbytecount);
+ TIFFClrFieldBit(tif, FIELD_YCBCRSUBSAMPLING);
+ TIFFClrFieldBit(tif, FIELD_YCBCRPOSITIONING);
+
+ /* Cleanup custom tag values */
+ for( i = 0; i < td->td_customValueCount; i++ ) {
+ if (td->td_customValues[i].value)
+ _TIFFfree(td->td_customValues[i].value);
+ }
+
+ td->td_customValueCount = 0;
+ CleanupField(td_customValues);
+}
+#undef CleanupField
+
+/*
+ * Client Tag extension support (from Niles Ritter).
+ */
+static TIFFExtendProc _TIFFextender = (TIFFExtendProc) NULL;
+
+TIFFExtendProc
+TIFFSetTagExtender(TIFFExtendProc extender)
+{
+ TIFFExtendProc prev = _TIFFextender;
+ _TIFFextender = extender;
+ return (prev);
+}
+
+/*
+ * Setup for a new directory. Should we automatically call
+ * TIFFWriteDirectory() if the current one is dirty?
+ *
+ * The newly created directory will not exist on the file till
+ * TIFFWriteDirectory(), TIFFFlush() or TIFFClose() is called.
+ */
+int
+TIFFCreateDirectory(TIFF* tif)
+{
+ TIFFDefaultDirectory(tif);
+ tif->tif_diroff = 0;
+ tif->tif_nextdiroff = 0;
+ tif->tif_curoff = 0;
+ tif->tif_row = (uint32) -1;
+ tif->tif_curstrip = (tstrip_t) -1;
+
+ return 0;
+}
+
+/*
+ * Setup a default directory structure.
+ */
+int
+TIFFDefaultDirectory(TIFF* tif)
+{
+ register TIFFDirectory* td = &tif->tif_dir;
+
+ size_t tiffFieldInfoCount;
+ const TIFFFieldInfo *tiffFieldInfo =
+ _TIFFGetFieldInfo(&tiffFieldInfoCount);
+ _TIFFSetupFieldInfo(tif, tiffFieldInfo, tiffFieldInfoCount);
+
+ _TIFFmemset(td, 0, sizeof (*td));
+ td->td_fillorder = FILLORDER_MSB2LSB;
+ td->td_bitspersample = 1;
+ td->td_threshholding = THRESHHOLD_BILEVEL;
+ td->td_orientation = ORIENTATION_TOPLEFT;
+ td->td_samplesperpixel = 1;
+ td->td_rowsperstrip = (uint32) -1;
+ td->td_tilewidth = 0;
+ td->td_tilelength = 0;
+ td->td_tiledepth = 1;
+ td->td_stripbytecountsorted = 1; /* Our own arrays always sorted. */
+ td->td_resolutionunit = RESUNIT_INCH;
+ td->td_sampleformat = SAMPLEFORMAT_UINT;
+ td->td_imagedepth = 1;
+ td->td_ycbcrsubsampling[0] = 2;
+ td->td_ycbcrsubsampling[1] = 2;
+ td->td_ycbcrpositioning = YCBCRPOSITION_CENTERED;
+ tif->tif_postdecode = _TIFFNoPostDecode;
+ tif->tif_foundfield = NULL;
+ tif->tif_tagmethods.vsetfield = _TIFFVSetField;
+ tif->tif_tagmethods.vgetfield = _TIFFVGetField;
+ tif->tif_tagmethods.printdir = NULL;
+ /*
+ * Give client code a chance to install their own
+ * tag extensions & methods, prior to compression overloads.
+ */
+ if (_TIFFextender)
+ (*_TIFFextender)(tif);
+ (void) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ /*
+ * NB: The directory is marked dirty as a result of setting
+ * up the default compression scheme. However, this really
+ * isn't correct -- we want TIFF_DIRTYDIRECT to be set only
+ * if the user does something. We could just do the setup
+ * by hand, but it seems better to use the normal mechanism
+ * (i.e. TIFFSetField).
+ */
+ tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+
+ /*
+ * As per http://bugzilla.remotesensing.org/show_bug.cgi?id=19
+ * we clear the ISTILED flag when setting up a new directory.
+ * Should we also be clearing stuff like INSUBIFD?
+ */
+ tif->tif_flags &= ~TIFF_ISTILED;
+ /*
+ * Clear other directory-specific fields.
+ */
+ tif->tif_tilesize = -1;
+ tif->tif_scanlinesize = -1;
+
+ return (1);
+}
+
+static int
+TIFFAdvanceDirectory(TIFF* tif, uint32* nextdir, toff_t* off)
+{
+ static const char module[] = "TIFFAdvanceDirectory";
+ uint16 dircount;
+ if (isMapped(tif))
+ {
+ toff_t poff=*nextdir;
+ if (poff+sizeof(uint16) > tif->tif_size)
+ {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
+ tif->tif_name);
+ return (0);
+ }
+ _TIFFmemcpy(&dircount, tif->tif_base+poff, sizeof (uint16));
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ poff+=sizeof (uint16)+dircount*sizeof (TIFFDirEntry);
+ if (off != NULL)
+ *off = poff;
+ if (((toff_t) (poff+sizeof (uint32))) > tif->tif_size)
+ {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link",
+ tif->tif_name);
+ return (0);
+ }
+ _TIFFmemcpy(nextdir, tif->tif_base+poff, sizeof (uint32));
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(nextdir);
+ return (1);
+ }
+ else
+ {
+ if (!SeekOK(tif, *nextdir) ||
+ !ReadOK(tif, &dircount, sizeof (uint16))) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory count",
+ tif->tif_name);
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ if (off != NULL)
+ *off = TIFFSeekFile(tif,
+ dircount*sizeof (TIFFDirEntry), SEEK_CUR);
+ else
+ (void) TIFFSeekFile(tif,
+ dircount*sizeof (TIFFDirEntry), SEEK_CUR);
+ if (!ReadOK(tif, nextdir, sizeof (uint32))) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Error fetching directory link",
+ tif->tif_name);
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(nextdir);
+ return (1);
+ }
+}
+
+/*
+ * Count the number of directories in a file.
+ */
+tdir_t
+TIFFNumberOfDirectories(TIFF* tif)
+{
+ toff_t nextdir = tif->tif_header.tiff_diroff;
+ tdir_t n = 0;
+
+ while (nextdir != 0 && TIFFAdvanceDirectory(tif, &nextdir, NULL))
+ n++;
+ return (n);
+}
+
+/*
+ * Set the n-th directory as the current directory.
+ * NB: Directories are numbered starting at 0.
+ */
+int
+TIFFSetDirectory(TIFF* tif, tdir_t dirn)
+{
+ toff_t nextdir;
+ tdir_t n;
+
+ nextdir = tif->tif_header.tiff_diroff;
+ for (n = dirn; n > 0 && nextdir != 0; n--)
+ if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
+ return (0);
+ tif->tif_nextdiroff = nextdir;
+ /*
+ * Set curdir to the actual directory index. The
+ * -1 is because TIFFReadDirectory will increment
+ * tif_curdir after successfully reading the directory.
+ */
+ tif->tif_curdir = (dirn - n) - 1;
+ /*
+ * Reset tif_dirnumber counter and start new list of seen directories.
+ * We need this to prevent IFD loops.
+ */
+ tif->tif_dirnumber = 0;
+ return (TIFFReadDirectory(tif));
+}
+
+/*
+ * Set the current directory to be the directory
+ * located at the specified file offset. This interface
+ * is used mainly to access directories linked with
+ * the SubIFD tag (e.g. thumbnail images).
+ */
+int
+TIFFSetSubDirectory(TIFF* tif, uint32 diroff)
+{
+ tif->tif_nextdiroff = diroff;
+ /*
+ * Reset tif_dirnumber counter and start new list of seen directories.
+ * We need this to prevent IFD loops.
+ */
+ tif->tif_dirnumber = 0;
+ return (TIFFReadDirectory(tif));
+}
+
+/*
+ * Return file offset of the current directory.
+ */
+uint32
+TIFFCurrentDirOffset(TIFF* tif)
+{
+ return (tif->tif_diroff);
+}
+
+/*
+ * Return an indication of whether or not we are
+ * at the last directory in the file.
+ */
+int
+TIFFLastDirectory(TIFF* tif)
+{
+ return (tif->tif_nextdiroff == 0);
+}
+
+/*
+ * Unlink the specified directory from the directory chain.
+ */
+int
+TIFFUnlinkDirectory(TIFF* tif, tdir_t dirn)
+{
+ static const char module[] = "TIFFUnlinkDirectory";
+ toff_t nextdir;
+ toff_t off;
+ tdir_t n;
+
+ if (tif->tif_mode == O_RDONLY) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Can not unlink directory in read-only file");
+ return (0);
+ }
+ /*
+ * Go to the directory before the one we want
+ * to unlink and nab the offset of the link
+ * field we'll need to patch.
+ */
+ nextdir = tif->tif_header.tiff_diroff;
+ off = sizeof (uint16) + sizeof (uint16);
+ for (n = dirn-1; n > 0; n--) {
+ if (nextdir == 0) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Directory %d does not exist", dirn);
+ return (0);
+ }
+ if (!TIFFAdvanceDirectory(tif, &nextdir, &off))
+ return (0);
+ }
+ /*
+ * Advance to the directory to be unlinked and fetch
+ * the offset of the directory that follows.
+ */
+ if (!TIFFAdvanceDirectory(tif, &nextdir, NULL))
+ return (0);
+ /*
+ * Go back and patch the link field of the preceding
+ * directory to point to the offset of the directory
+ * that follows.
+ */
+ (void) TIFFSeekFile(tif, off, SEEK_SET);
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&nextdir);
+ if (!WriteOK(tif, &nextdir, sizeof (uint32))) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Error writing directory link");
+ return (0);
+ }
+ /*
+ * Leave directory state setup safely. We don't have
+ * facilities for doing inserting and removing directories,
+ * so it's safest to just invalidate everything. This
+ * means that the caller can only append to the directory
+ * chain.
+ */
+ (*tif->tif_cleanup)(tif);
+ if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+ _TIFFfree(tif->tif_rawdata);
+ tif->tif_rawdata = NULL;
+ tif->tif_rawcc = 0;
+ }
+ tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP|TIFF_POSTENCODE);
+ TIFFFreeDirectory(tif);
+ TIFFDefaultDirectory(tif);
+ tif->tif_diroff = 0; /* force link on next write */
+ tif->tif_nextdiroff = 0; /* next write must be at end */
+ tif->tif_curoff = 0;
+ tif->tif_row = (uint32) -1;
+ tif->tif_curstrip = (tstrip_t) -1;
+ return (1);
+}
+
+/* [BFC]
+ *
+ * Author: Bruce Cameron <cameron@petris.com>
+ *
+ * Set a table of tags that are to be replaced during directory process by the
+ * 'IGNORE' state - or return TRUE/FALSE for the requested tag such that
+ * 'ReadDirectory' can use the stored information.
+ *
+ * FIXME: this is never used properly. Should be removed in the future.
+ */
+int
+TIFFReassignTagToIgnore (enum TIFFIgnoreSense task, int TIFFtagID)
+{
+ static int TIFFignoretags [FIELD_LAST];
+ static int tagcount = 0 ;
+ int i; /* Loop index */
+ int j; /* Loop index */
+
+ switch (task)
+ {
+ case TIS_STORE:
+ if ( tagcount < (FIELD_LAST - 1) )
+ {
+ for ( j = 0 ; j < tagcount ; ++j )
+ { /* Do not add duplicate tag */
+ if ( TIFFignoretags [j] == TIFFtagID )
+ return (TRUE) ;
+ }
+ TIFFignoretags [tagcount++] = TIFFtagID ;
+ return (TRUE) ;
+ }
+ break ;
+
+ case TIS_EXTRACT:
+ for ( i = 0 ; i < tagcount ; ++i )
+ {
+ if ( TIFFignoretags [i] == TIFFtagID )
+ return (TRUE) ;
+ }
+ break;
+
+ case TIS_EMPTY:
+ tagcount = 0 ; /* Clear the list */
+ return (TRUE) ;
+
+ default:
+ break;
+ }
+
+ return (FALSE);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_dir.h b/tiff/libtiff/tif_dir.h
new file mode 100644
index 0000000..515af19
--- /dev/null
+++ b/tiff/libtiff/tif_dir.h
@@ -0,0 +1,211 @@
+/* $Id: tif_dir.h,v 1.30.2.3 2010-06-09 21:15:27 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFDIR_
+#define _TIFFDIR_
+/*
+ * ``Library-private'' Directory-related Definitions.
+ */
+
+/*
+ * Internal format of a TIFF directory entry.
+ */
+typedef struct {
+#define FIELD_SETLONGS 4
+ /* bit vector of fields that are set */
+ unsigned long td_fieldsset[FIELD_SETLONGS];
+
+ uint32 td_imagewidth, td_imagelength, td_imagedepth;
+ uint32 td_tilewidth, td_tilelength, td_tiledepth;
+ uint32 td_subfiletype;
+ uint16 td_bitspersample;
+ uint16 td_sampleformat;
+ uint16 td_compression;
+ uint16 td_photometric;
+ uint16 td_threshholding;
+ uint16 td_fillorder;
+ uint16 td_orientation;
+ uint16 td_samplesperpixel;
+ uint32 td_rowsperstrip;
+ uint16 td_minsamplevalue, td_maxsamplevalue;
+ double td_sminsamplevalue, td_smaxsamplevalue;
+ float td_xresolution, td_yresolution;
+ uint16 td_resolutionunit;
+ uint16 td_planarconfig;
+ float td_xposition, td_yposition;
+ uint16 td_pagenumber[2];
+ uint16* td_colormap[3];
+ uint16 td_halftonehints[2];
+ uint16 td_extrasamples;
+ uint16* td_sampleinfo;
+ /* even though the name is misleading, td_stripsperimage is the number
+ * of striles (=strips or tiles) per plane, and td_nstrips the total
+ * number of striles */
+ tstrile_t td_stripsperimage;
+ tstrile_t td_nstrips; /* size of offset & bytecount arrays */
+ toff_t* td_stripoffset;
+ toff_t* td_stripbytecount; /* FIXME: it should be tsize_t array */
+ int td_stripbytecountsorted; /* is the bytecount array sorted ascending? */
+ uint16 td_nsubifd;
+ uint32* td_subifd;
+ /* YCbCr parameters */
+ uint16 td_ycbcrsubsampling[2];
+ uint16 td_ycbcrpositioning;
+ /* Colorimetry parameters */
+ float* td_refblackwhite;
+ uint16* td_transferfunction[3];
+ /* CMYK parameters */
+ int td_inknameslen;
+ char* td_inknames;
+
+ int td_customValueCount;
+ TIFFTagValue *td_customValues;
+} TIFFDirectory;
+
+/*
+ * Field flags used to indicate fields that have
+ * been set in a directory, and to reference fields
+ * when manipulating a directory.
+ */
+
+/*
+ * FIELD_IGNORE is used to signify tags that are to
+ * be processed but otherwise ignored. This permits
+ * antiquated tags to be quietly read and discarded.
+ * Note that a bit *is* allocated for ignored tags;
+ * this is understood by the directory reading logic
+ * which uses this fact to avoid special-case handling
+ */
+#define FIELD_IGNORE 0
+
+/* multi-item fields */
+#define FIELD_IMAGEDIMENSIONS 1
+#define FIELD_TILEDIMENSIONS 2
+#define FIELD_RESOLUTION 3
+#define FIELD_POSITION 4
+
+/* single-item fields */
+#define FIELD_SUBFILETYPE 5
+#define FIELD_BITSPERSAMPLE 6
+#define FIELD_COMPRESSION 7
+#define FIELD_PHOTOMETRIC 8
+#define FIELD_THRESHHOLDING 9
+#define FIELD_FILLORDER 10
+#define FIELD_ORIENTATION 15
+#define FIELD_SAMPLESPERPIXEL 16
+#define FIELD_ROWSPERSTRIP 17
+#define FIELD_MINSAMPLEVALUE 18
+#define FIELD_MAXSAMPLEVALUE 19
+#define FIELD_PLANARCONFIG 20
+#define FIELD_RESOLUTIONUNIT 22
+#define FIELD_PAGENUMBER 23
+#define FIELD_STRIPBYTECOUNTS 24
+#define FIELD_STRIPOFFSETS 25
+#define FIELD_COLORMAP 26
+#define FIELD_EXTRASAMPLES 31
+#define FIELD_SAMPLEFORMAT 32
+#define FIELD_SMINSAMPLEVALUE 33
+#define FIELD_SMAXSAMPLEVALUE 34
+#define FIELD_IMAGEDEPTH 35
+#define FIELD_TILEDEPTH 36
+#define FIELD_HALFTONEHINTS 37
+#define FIELD_YCBCRSUBSAMPLING 39
+#define FIELD_YCBCRPOSITIONING 40
+#define FIELD_REFBLACKWHITE 41
+#define FIELD_TRANSFERFUNCTION 44
+#define FIELD_INKNAMES 46
+#define FIELD_SUBIFD 49
+/* FIELD_CUSTOM (see tiffio.h) 65 */
+/* end of support for well-known tags; codec-private tags follow */
+#define FIELD_CODEC 66 /* base of codec-private tags */
+
+
+/*
+ * Pseudo-tags don't normally need field bits since they
+ * are not written to an output file (by definition).
+ * The library also has express logic to always query a
+ * codec for a pseudo-tag so allocating a field bit for
+ * one is a waste. If codec wants to promote the notion
+ * of a pseudo-tag being ``set'' or ``unset'' then it can
+ * do using internal state flags without polluting the
+ * field bit space defined for real tags.
+ */
+#define FIELD_PSEUDO 0
+
+#define FIELD_LAST (32*FIELD_SETLONGS-1)
+
+#define TIFFExtractData(tif, type, v) \
+ ((uint32) ((tif)->tif_header.tiff_magic == TIFF_BIGENDIAN ? \
+ ((v) >> (tif)->tif_typeshift[type]) & (tif)->tif_typemask[type] : \
+ (v) & (tif)->tif_typemask[type]))
+#define TIFFInsertData(tif, type, v) \
+ ((uint32) ((tif)->tif_header.tiff_magic == TIFF_BIGENDIAN ? \
+ ((v) & (tif)->tif_typemask[type]) << (tif)->tif_typeshift[type] : \
+ (v) & (tif)->tif_typemask[type]))
+
+
+#define BITn(n) (((unsigned long)1L)<<((n)&0x1f))
+#define BITFIELDn(tif, n) ((tif)->tif_dir.td_fieldsset[(n)/32])
+#define TIFFFieldSet(tif, field) (BITFIELDn(tif, field) & BITn(field))
+#define TIFFSetFieldBit(tif, field) (BITFIELDn(tif, field) |= BITn(field))
+#define TIFFClrFieldBit(tif, field) (BITFIELDn(tif, field) &= ~BITn(field))
+
+#define FieldSet(fields, f) (fields[(f)/32] & BITn(f))
+#define ResetFieldBit(fields, f) (fields[(f)/32] &= ~BITn(f))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern const TIFFFieldInfo *_TIFFGetFieldInfo(size_t *);
+extern const TIFFFieldInfo *_TIFFGetExifFieldInfo(size_t *);
+extern void _TIFFSetupFieldInfo(TIFF*, const TIFFFieldInfo[], size_t);
+extern int _TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], int);
+extern void _TIFFPrintFieldInfo(TIFF*, FILE*);
+extern TIFFDataType _TIFFSampleToTagType(TIFF*);
+extern const TIFFFieldInfo* _TIFFFindOrRegisterFieldInfo( TIFF *tif,
+ ttag_t tag,
+ TIFFDataType dt );
+extern TIFFFieldInfo* _TIFFCreateAnonFieldInfo( TIFF *tif, ttag_t tag,
+ TIFFDataType dt );
+
+#define _TIFFFindFieldInfo TIFFFindFieldInfo
+#define _TIFFFindFieldInfoByName TIFFFindFieldInfoByName
+#define _TIFFFieldWithTag TIFFFieldWithTag
+#define _TIFFFieldWithName TIFFFieldWithName
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* _TIFFDIR_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_dirinfo.c b/tiff/libtiff/tif_dirinfo.c
new file mode 100644
index 0000000..0a77c97
--- /dev/null
+++ b/tiff/libtiff/tif_dirinfo.c
@@ -0,0 +1,888 @@
+/* $Id: tif_dirinfo.c,v 1.65.2.9 2010-06-09 21:15:27 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Core Directory Tag Support.
+ */
+#include "tiffiop.h"
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * NB: NB: THIS ARRAY IS ASSUMED TO BE SORTED BY TAG.
+ * If a tag can have both LONG and SHORT types then the LONG must be
+ * placed before the SHORT for writing to work properly.
+ *
+ * NOTE: The second field (field_readcount) and third field (field_writecount)
+ * sometimes use the values TIFF_VARIABLE (-1), TIFF_VARIABLE2 (-3)
+ * and TIFFTAG_SPP (-2). The macros should be used but would throw off
+ * the formatting of the code, so please interprete the -1, -2 and -3
+ * values accordingly.
+ */
+static const TIFFFieldInfo
+tiffFieldInfo[] = {
+ { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_LONG, FIELD_SUBFILETYPE,
+ 1, 0, "SubfileType" },
+/* XXX SHORT for compatibility w/ old versions of the library */
+ { TIFFTAG_SUBFILETYPE, 1, 1, TIFF_SHORT, FIELD_SUBFILETYPE,
+ 1, 0, "SubfileType" },
+ { TIFFTAG_OSUBFILETYPE, 1, 1, TIFF_SHORT, FIELD_SUBFILETYPE,
+ 1, 0, "OldSubfileType" },
+ { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_LONG, FIELD_IMAGEDIMENSIONS,
+ 0, 0, "ImageWidth" },
+ { TIFFTAG_IMAGEWIDTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDIMENSIONS,
+ 0, 0, "ImageWidth" },
+ { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_LONG, FIELD_IMAGEDIMENSIONS,
+ 1, 0, "ImageLength" },
+ { TIFFTAG_IMAGELENGTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDIMENSIONS,
+ 1, 0, "ImageLength" },
+ { TIFFTAG_BITSPERSAMPLE, -1,-1, TIFF_SHORT, FIELD_BITSPERSAMPLE,
+ 0, 0, "BitsPerSample" },
+/* XXX LONG for compatibility with some broken TIFF writers */
+ { TIFFTAG_BITSPERSAMPLE, -1,-1, TIFF_LONG, FIELD_BITSPERSAMPLE,
+ 0, 0, "BitsPerSample" },
+ { TIFFTAG_COMPRESSION, -1, 1, TIFF_SHORT, FIELD_COMPRESSION,
+ 0, 0, "Compression" },
+/* XXX LONG for compatibility with some broken TIFF writers */
+ { TIFFTAG_COMPRESSION, -1, 1, TIFF_LONG, FIELD_COMPRESSION,
+ 0, 0, "Compression" },
+ { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_SHORT, FIELD_PHOTOMETRIC,
+ 0, 0, "PhotometricInterpretation" },
+/* XXX LONG for compatibility with some broken TIFF writers */
+ { TIFFTAG_PHOTOMETRIC, 1, 1, TIFF_LONG, FIELD_PHOTOMETRIC,
+ 0, 0, "PhotometricInterpretation" },
+ { TIFFTAG_THRESHHOLDING, 1, 1, TIFF_SHORT, FIELD_THRESHHOLDING,
+ 1, 0, "Threshholding" },
+ { TIFFTAG_CELLWIDTH, 1, 1, TIFF_SHORT, FIELD_IGNORE,
+ 1, 0, "CellWidth" },
+ { TIFFTAG_CELLLENGTH, 1, 1, TIFF_SHORT, FIELD_IGNORE,
+ 1, 0, "CellLength" },
+ { TIFFTAG_FILLORDER, 1, 1, TIFF_SHORT, FIELD_FILLORDER,
+ 0, 0, "FillOrder" },
+ { TIFFTAG_DOCUMENTNAME, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "DocumentName" },
+ { TIFFTAG_IMAGEDESCRIPTION, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "ImageDescription" },
+ { TIFFTAG_MAKE, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "Make" },
+ { TIFFTAG_MODEL, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "Model" },
+ { TIFFTAG_STRIPOFFSETS, -1,-1, TIFF_LONG, FIELD_STRIPOFFSETS,
+ 0, 0, "StripOffsets" },
+ { TIFFTAG_STRIPOFFSETS, -1,-1, TIFF_SHORT, FIELD_STRIPOFFSETS,
+ 0, 0, "StripOffsets" },
+ { TIFFTAG_ORIENTATION, 1, 1, TIFF_SHORT, FIELD_ORIENTATION,
+ 0, 0, "Orientation" },
+ { TIFFTAG_SAMPLESPERPIXEL, 1, 1, TIFF_SHORT, FIELD_SAMPLESPERPIXEL,
+ 0, 0, "SamplesPerPixel" },
+ { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_LONG, FIELD_ROWSPERSTRIP,
+ 0, 0, "RowsPerStrip" },
+ { TIFFTAG_ROWSPERSTRIP, 1, 1, TIFF_SHORT, FIELD_ROWSPERSTRIP,
+ 0, 0, "RowsPerStrip" },
+ { TIFFTAG_STRIPBYTECOUNTS, -1,-1, TIFF_LONG, FIELD_STRIPBYTECOUNTS,
+ 0, 0, "StripByteCounts" },
+ { TIFFTAG_STRIPBYTECOUNTS, -1,-1, TIFF_SHORT, FIELD_STRIPBYTECOUNTS,
+ 0, 0, "StripByteCounts" },
+ { TIFFTAG_MINSAMPLEVALUE, -2,-1, TIFF_SHORT, FIELD_MINSAMPLEVALUE,
+ 1, 0, "MinSampleValue" },
+ { TIFFTAG_MAXSAMPLEVALUE, -2,-1, TIFF_SHORT, FIELD_MAXSAMPLEVALUE,
+ 1, 0, "MaxSampleValue" },
+ { TIFFTAG_XRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_RESOLUTION,
+ 1, 0, "XResolution" },
+ { TIFFTAG_YRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_RESOLUTION,
+ 1, 0, "YResolution" },
+ { TIFFTAG_PLANARCONFIG, 1, 1, TIFF_SHORT, FIELD_PLANARCONFIG,
+ 0, 0, "PlanarConfiguration" },
+ { TIFFTAG_PAGENAME, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "PageName" },
+ { TIFFTAG_XPOSITION, 1, 1, TIFF_RATIONAL, FIELD_POSITION,
+ 1, 0, "XPosition" },
+ { TIFFTAG_YPOSITION, 1, 1, TIFF_RATIONAL, FIELD_POSITION,
+ 1, 0, "YPosition" },
+ { TIFFTAG_FREEOFFSETS, -1,-1, TIFF_LONG, FIELD_IGNORE,
+ 0, 0, "FreeOffsets" },
+ { TIFFTAG_FREEBYTECOUNTS, -1,-1, TIFF_LONG, FIELD_IGNORE,
+ 0, 0, "FreeByteCounts" },
+ { TIFFTAG_GRAYRESPONSEUNIT, 1, 1, TIFF_SHORT, FIELD_IGNORE,
+ 1, 0, "GrayResponseUnit" },
+ { TIFFTAG_GRAYRESPONSECURVE,-1,-1, TIFF_SHORT, FIELD_IGNORE,
+ 1, 0, "GrayResponseCurve" },
+ { TIFFTAG_RESOLUTIONUNIT, 1, 1, TIFF_SHORT, FIELD_RESOLUTIONUNIT,
+ 1, 0, "ResolutionUnit" },
+ { TIFFTAG_PAGENUMBER, 2, 2, TIFF_SHORT, FIELD_PAGENUMBER,
+ 1, 0, "PageNumber" },
+ { TIFFTAG_COLORRESPONSEUNIT, 1, 1, TIFF_SHORT, FIELD_IGNORE,
+ 1, 0, "ColorResponseUnit" },
+ { TIFFTAG_TRANSFERFUNCTION, -1,-1, TIFF_SHORT, FIELD_TRANSFERFUNCTION,
+ 1, 0, "TransferFunction" },
+ { TIFFTAG_SOFTWARE, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "Software" },
+ { TIFFTAG_DATETIME, 20,20, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "DateTime" },
+ { TIFFTAG_ARTIST, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "Artist" },
+ { TIFFTAG_HOSTCOMPUTER, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "HostComputer" },
+ { TIFFTAG_WHITEPOINT, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "WhitePoint" },
+ { TIFFTAG_PRIMARYCHROMATICITIES,6,6,TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "PrimaryChromaticities" },
+ { TIFFTAG_COLORMAP, -1,-1, TIFF_SHORT, FIELD_COLORMAP,
+ 1, 0, "ColorMap" },
+ { TIFFTAG_HALFTONEHINTS, 2, 2, TIFF_SHORT, FIELD_HALFTONEHINTS,
+ 1, 0, "HalftoneHints" },
+ { TIFFTAG_TILEWIDTH, 1, 1, TIFF_LONG, FIELD_TILEDIMENSIONS,
+ 0, 0, "TileWidth" },
+ { TIFFTAG_TILEWIDTH, 1, 1, TIFF_SHORT, FIELD_TILEDIMENSIONS,
+ 0, 0, "TileWidth" },
+ { TIFFTAG_TILELENGTH, 1, 1, TIFF_LONG, FIELD_TILEDIMENSIONS,
+ 0, 0, "TileLength" },
+ { TIFFTAG_TILELENGTH, 1, 1, TIFF_SHORT, FIELD_TILEDIMENSIONS,
+ 0, 0, "TileLength" },
+ { TIFFTAG_TILEOFFSETS, -1, 1, TIFF_LONG, FIELD_STRIPOFFSETS,
+ 0, 0, "TileOffsets" },
+ { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_LONG, FIELD_STRIPBYTECOUNTS,
+ 0, 0, "TileByteCounts" },
+ { TIFFTAG_TILEBYTECOUNTS, -1, 1, TIFF_SHORT, FIELD_STRIPBYTECOUNTS,
+ 0, 0, "TileByteCounts" },
+ { TIFFTAG_SUBIFD, -1,-1, TIFF_IFD, FIELD_SUBIFD,
+ 1, 1, "SubIFD" },
+ { TIFFTAG_SUBIFD, -1,-1, TIFF_LONG, FIELD_SUBIFD,
+ 1, 1, "SubIFD" },
+ { TIFFTAG_INKSET, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "InkSet" },
+ { TIFFTAG_INKNAMES, -1,-1, TIFF_ASCII, FIELD_INKNAMES,
+ 1, 1, "InkNames" },
+ { TIFFTAG_NUMBEROFINKS, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "NumberOfInks" },
+ { TIFFTAG_DOTRANGE, 2, 2, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "DotRange" },
+ { TIFFTAG_DOTRANGE, 2, 2, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 0, "DotRange" },
+ { TIFFTAG_TARGETPRINTER, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "TargetPrinter" },
+ { TIFFTAG_EXTRASAMPLES, -1,-1, TIFF_SHORT, FIELD_EXTRASAMPLES,
+ 0, 1, "ExtraSamples" },
+/* XXX for bogus Adobe Photoshop v2.5 files */
+ { TIFFTAG_EXTRASAMPLES, -1,-1, TIFF_BYTE, FIELD_EXTRASAMPLES,
+ 0, 1, "ExtraSamples" },
+ { TIFFTAG_SAMPLEFORMAT, -1,-1, TIFF_SHORT, FIELD_SAMPLEFORMAT,
+ 0, 0, "SampleFormat" },
+ { TIFFTAG_SMINSAMPLEVALUE, -2,-1, TIFF_ANY, FIELD_SMINSAMPLEVALUE,
+ 1, 0, "SMinSampleValue" },
+ { TIFFTAG_SMAXSAMPLEVALUE, -2,-1, TIFF_ANY, FIELD_SMAXSAMPLEVALUE,
+ 1, 0, "SMaxSampleValue" },
+ { TIFFTAG_CLIPPATH, -1, -3, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 1, "ClipPath" },
+ { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SLONG, FIELD_CUSTOM,
+ 0, 0, "XClipPathUnits" },
+ { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SSHORT, FIELD_CUSTOM,
+ 0, 0, "XClipPathUnits" },
+ { TIFFTAG_XCLIPPATHUNITS, 1, 1, TIFF_SBYTE, FIELD_CUSTOM,
+ 0, 0, "XClipPathUnits" },
+ { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SLONG, FIELD_CUSTOM,
+ 0, 0, "YClipPathUnits" },
+ { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SSHORT, FIELD_CUSTOM,
+ 0, 0, "YClipPathUnits" },
+ { TIFFTAG_YCLIPPATHUNITS, 1, 1, TIFF_SBYTE, FIELD_CUSTOM,
+ 0, 0, "YClipPathUnits" },
+ { TIFFTAG_YCBCRCOEFFICIENTS, 3, 3, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "YCbCrCoefficients" },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, 2, TIFF_SHORT, FIELD_YCBCRSUBSAMPLING,
+ 0, 0, "YCbCrSubsampling" },
+ { TIFFTAG_YCBCRPOSITIONING, 1, 1, TIFF_SHORT, FIELD_YCBCRPOSITIONING,
+ 0, 0, "YCbCrPositioning" },
+ { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_RATIONAL, FIELD_REFBLACKWHITE,
+ 1, 0, "ReferenceBlackWhite" },
+/* XXX temporarily accept LONG for backwards compatibility */
+ { TIFFTAG_REFERENCEBLACKWHITE, 6, 6, TIFF_LONG, FIELD_REFBLACKWHITE,
+ 1, 0, "ReferenceBlackWhite" },
+ { TIFFTAG_XMLPACKET, -3,-3, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 1, "XMLPacket" },
+/* begin SGI tags */
+ { TIFFTAG_MATTEING, 1, 1, TIFF_SHORT, FIELD_EXTRASAMPLES,
+ 0, 0, "Matteing" },
+ { TIFFTAG_DATATYPE, -2,-1, TIFF_SHORT, FIELD_SAMPLEFORMAT,
+ 0, 0, "DataType" },
+ { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_LONG, FIELD_IMAGEDEPTH,
+ 0, 0, "ImageDepth" },
+ { TIFFTAG_IMAGEDEPTH, 1, 1, TIFF_SHORT, FIELD_IMAGEDEPTH,
+ 0, 0, "ImageDepth" },
+ { TIFFTAG_TILEDEPTH, 1, 1, TIFF_LONG, FIELD_TILEDEPTH,
+ 0, 0, "TileDepth" },
+ { TIFFTAG_TILEDEPTH, 1, 1, TIFF_SHORT, FIELD_TILEDEPTH,
+ 0, 0, "TileDepth" },
+/* end SGI tags */
+/* begin Pixar tags */
+ { TIFFTAG_PIXAR_IMAGEFULLWIDTH, 1, 1, TIFF_LONG, FIELD_CUSTOM,
+ 1, 0, "ImageFullWidth" },
+ { TIFFTAG_PIXAR_IMAGEFULLLENGTH, 1, 1, TIFF_LONG, FIELD_CUSTOM,
+ 1, 0, "ImageFullLength" },
+ { TIFFTAG_PIXAR_TEXTUREFORMAT, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "TextureFormat" },
+ { TIFFTAG_PIXAR_WRAPMODES, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "TextureWrapModes" },
+ { TIFFTAG_PIXAR_FOVCOT, 1, 1, TIFF_FLOAT, FIELD_CUSTOM,
+ 1, 0, "FieldOfViewCotangent" },
+ { TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN, 16,16, TIFF_FLOAT,
+ FIELD_CUSTOM, 1, 0, "MatrixWorldToScreen" },
+ { TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA, 16,16, TIFF_FLOAT,
+ FIELD_CUSTOM, 1, 0, "MatrixWorldToCamera" },
+ { TIFFTAG_COPYRIGHT, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "Copyright" },
+/* end Pixar tags */
+ { TIFFTAG_RICHTIFFIPTC, -3, -3, TIFF_LONG, FIELD_CUSTOM,
+ 0, 1, "RichTIFFIPTC" },
+ { TIFFTAG_PHOTOSHOP, -3, -3, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 1, "Photoshop" },
+ { TIFFTAG_EXIFIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM,
+ 0, 0, "EXIFIFDOffset" },
+ { TIFFTAG_ICCPROFILE, -3, -3, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 0, 1, "ICC Profile" },
+ { TIFFTAG_GPSIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM,
+ 0, 0, "GPSIFDOffset" },
+ { TIFFTAG_STONITS, 1, 1, TIFF_DOUBLE, FIELD_CUSTOM,
+ 0, 0, "StoNits" },
+ { TIFFTAG_INTEROPERABILITYIFD, 1, 1, TIFF_LONG, FIELD_CUSTOM,
+ 0, 0, "InteroperabilityIFDOffset" },
+/* begin DNG tags */
+ { TIFFTAG_DNGVERSION, 4, 4, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 0, "DNGVersion" },
+ { TIFFTAG_DNGBACKWARDVERSION, 4, 4, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 0, "DNGBackwardVersion" },
+ { TIFFTAG_UNIQUECAMERAMODEL, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "UniqueCameraModel" },
+ { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "LocalizedCameraModel" },
+ { TIFFTAG_LOCALIZEDCAMERAMODEL, -1, -1, TIFF_BYTE, FIELD_CUSTOM,
+ 1, 1, "LocalizedCameraModel" },
+ { TIFFTAG_CFAPLANECOLOR, -1, -1, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 1, "CFAPlaneColor" },
+ { TIFFTAG_CFALAYOUT, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "CFALayout" },
+ { TIFFTAG_LINEARIZATIONTABLE, -1, -1, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 1, "LinearizationTable" },
+ { TIFFTAG_BLACKLEVELREPEATDIM, 2, 2, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "BlackLevelRepeatDim" },
+ { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_LONG, FIELD_CUSTOM,
+ 0, 1, "BlackLevel" },
+ { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 1, "BlackLevel" },
+ { TIFFTAG_BLACKLEVEL, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 1, "BlackLevel" },
+ { TIFFTAG_BLACKLEVELDELTAH, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "BlackLevelDeltaH" },
+ { TIFFTAG_BLACKLEVELDELTAV, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "BlackLevelDeltaV" },
+ { TIFFTAG_WHITELEVEL, -2, -2, TIFF_LONG, FIELD_CUSTOM,
+ 0, 0, "WhiteLevel" },
+ { TIFFTAG_WHITELEVEL, -2, -2, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "WhiteLevel" },
+ { TIFFTAG_DEFAULTSCALE, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "DefaultScale" },
+ { TIFFTAG_BESTQUALITYSCALE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "BestQualityScale" },
+ { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_LONG, FIELD_CUSTOM,
+ 0, 0, "DefaultCropOrigin" },
+ { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "DefaultCropOrigin" },
+ { TIFFTAG_DEFAULTCROPORIGIN, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "DefaultCropOrigin" },
+ { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_LONG, FIELD_CUSTOM,
+ 0, 0, "DefaultCropSize" },
+ { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "DefaultCropSize" },
+ { TIFFTAG_DEFAULTCROPSIZE, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "DefaultCropSize" },
+ { TIFFTAG_COLORMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "ColorMatrix1" },
+ { TIFFTAG_COLORMATRIX2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "ColorMatrix2" },
+ { TIFFTAG_CAMERACALIBRATION1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "CameraCalibration1" },
+ { TIFFTAG_CAMERACALIBRATION2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "CameraCalibration2" },
+ { TIFFTAG_REDUCTIONMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "ReductionMatrix1" },
+ { TIFFTAG_REDUCTIONMATRIX2, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "ReductionMatrix2" },
+ { TIFFTAG_ANALOGBALANCE, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 1, "AnalogBalance" },
+ { TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 1, "AsShotNeutral" },
+ { TIFFTAG_ASSHOTNEUTRAL, -1, -1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 1, "AsShotNeutral" },
+ { TIFFTAG_ASSHOTWHITEXY, 2, 2, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "AsShotWhiteXY" },
+ { TIFFTAG_BASELINEEXPOSURE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 0, "BaselineExposure" },
+ { TIFFTAG_BASELINENOISE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "BaselineNoise" },
+ { TIFFTAG_BASELINESHARPNESS, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "BaselineSharpness" },
+ { TIFFTAG_BAYERGREENSPLIT, 1, 1, TIFF_LONG, FIELD_CUSTOM,
+ 0, 0, "BayerGreenSplit" },
+ { TIFFTAG_LINEARRESPONSELIMIT, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "LinearResponseLimit" },
+ { TIFFTAG_CAMERASERIALNUMBER, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "CameraSerialNumber" },
+ { TIFFTAG_LENSINFO, 4, 4, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "LensInfo" },
+ { TIFFTAG_CHROMABLURRADIUS, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "ChromaBlurRadius" },
+ { TIFFTAG_ANTIALIASSTRENGTH, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "AntiAliasStrength" },
+ { TIFFTAG_SHADOWSCALE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 0, 0, "ShadowScale" },
+ { TIFFTAG_DNGPRIVATEDATA, -1, -1, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 1, "DNGPrivateData" },
+ { TIFFTAG_MAKERNOTESAFETY, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "MakerNoteSafety" },
+ { TIFFTAG_CALIBRATIONILLUMINANT1, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "CalibrationIlluminant1" },
+ { TIFFTAG_CALIBRATIONILLUMINANT2, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "CalibrationIlluminant2" },
+ { TIFFTAG_RAWDATAUNIQUEID, 16, 16, TIFF_BYTE, FIELD_CUSTOM,
+ 0, 0, "RawDataUniqueID" },
+ { TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "OriginalRawFileName" },
+ { TIFFTAG_ORIGINALRAWFILENAME, -1, -1, TIFF_BYTE, FIELD_CUSTOM,
+ 1, 1, "OriginalRawFileName" },
+ { TIFFTAG_ORIGINALRAWFILEDATA, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 0, 1, "OriginalRawFileData" },
+ { TIFFTAG_ACTIVEAREA, 4, 4, TIFF_LONG, FIELD_CUSTOM,
+ 0, 0, "ActiveArea" },
+ { TIFFTAG_ACTIVEAREA, 4, 4, TIFF_SHORT, FIELD_CUSTOM,
+ 0, 0, "ActiveArea" },
+ { TIFFTAG_MASKEDAREAS, -1, -1, TIFF_LONG, FIELD_CUSTOM,
+ 0, 1, "MaskedAreas" },
+ { TIFFTAG_ASSHOTICCPROFILE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 0, 1, "AsShotICCProfile" },
+ { TIFFTAG_ASSHOTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "AsShotPreProfileMatrix" },
+ { TIFFTAG_CURRENTICCPROFILE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 0, 1, "CurrentICCProfile" },
+ { TIFFTAG_CURRENTPREPROFILEMATRIX, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 0, 1, "CurrentPreProfileMatrix" },
+/* end DNG tags */
+};
+
+static const TIFFFieldInfo
+exifFieldInfo[] = {
+ { EXIFTAG_EXPOSURETIME, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "ExposureTime" },
+ { EXIFTAG_FNUMBER, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "FNumber" },
+ { EXIFTAG_EXPOSUREPROGRAM, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "ExposureProgram" },
+ { EXIFTAG_SPECTRALSENSITIVITY, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "SpectralSensitivity" },
+ { EXIFTAG_ISOSPEEDRATINGS, -1, -1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 1, "ISOSpeedRatings" },
+ { EXIFTAG_OECF, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 1, "OptoelectricConversionFactor" },
+ { EXIFTAG_EXIFVERSION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 0, "ExifVersion" },
+ { EXIFTAG_DATETIMEORIGINAL, 20, 20, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "DateTimeOriginal" },
+ { EXIFTAG_DATETIMEDIGITIZED, 20, 20, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "DateTimeDigitized" },
+ { EXIFTAG_COMPONENTSCONFIGURATION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 0, "ComponentsConfiguration" },
+ { EXIFTAG_COMPRESSEDBITSPERPIXEL, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "CompressedBitsPerPixel" },
+ { EXIFTAG_SHUTTERSPEEDVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 1, 0, "ShutterSpeedValue" },
+ { EXIFTAG_APERTUREVALUE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "ApertureValue" },
+ { EXIFTAG_BRIGHTNESSVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 1, 0, "BrightnessValue" },
+ { EXIFTAG_EXPOSUREBIASVALUE, 1, 1, TIFF_SRATIONAL, FIELD_CUSTOM,
+ 1, 0, "ExposureBiasValue" },
+ { EXIFTAG_MAXAPERTUREVALUE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "MaxApertureValue" },
+ { EXIFTAG_SUBJECTDISTANCE, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "SubjectDistance" },
+ { EXIFTAG_METERINGMODE, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "MeteringMode" },
+ { EXIFTAG_LIGHTSOURCE, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "LightSource" },
+ { EXIFTAG_FLASH, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "Flash" },
+ { EXIFTAG_FOCALLENGTH, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "FocalLength" },
+ { EXIFTAG_SUBJECTAREA, -1, -1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 1, "SubjectArea" },
+ { EXIFTAG_MAKERNOTE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 1, "MakerNote" },
+ { EXIFTAG_USERCOMMENT, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 1, "UserComment" },
+ { EXIFTAG_SUBSECTIME, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "SubSecTime" },
+ { EXIFTAG_SUBSECTIMEORIGINAL, -1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "SubSecTimeOriginal" },
+ { EXIFTAG_SUBSECTIMEDIGITIZED,-1, -1, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "SubSecTimeDigitized" },
+ { EXIFTAG_FLASHPIXVERSION, 4, 4, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 0, "FlashpixVersion" },
+ { EXIFTAG_COLORSPACE, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "ColorSpace" },
+ { EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_LONG, FIELD_CUSTOM,
+ 1, 0, "PixelXDimension" },
+ { EXIFTAG_PIXELXDIMENSION, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "PixelXDimension" },
+ { EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_LONG, FIELD_CUSTOM,
+ 1, 0, "PixelYDimension" },
+ { EXIFTAG_PIXELYDIMENSION, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "PixelYDimension" },
+ { EXIFTAG_RELATEDSOUNDFILE, 13, 13, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "RelatedSoundFile" },
+ { EXIFTAG_FLASHENERGY, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "FlashEnergy" },
+ { EXIFTAG_SPATIALFREQUENCYRESPONSE, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 1, "SpatialFrequencyResponse" },
+ { EXIFTAG_FOCALPLANEXRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "FocalPlaneXResolution" },
+ { EXIFTAG_FOCALPLANEYRESOLUTION, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "FocalPlaneYResolution" },
+ { EXIFTAG_FOCALPLANERESOLUTIONUNIT, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "FocalPlaneResolutionUnit" },
+ { EXIFTAG_SUBJECTLOCATION, 2, 2, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "SubjectLocation" },
+ { EXIFTAG_EXPOSUREINDEX, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "ExposureIndex" },
+ { EXIFTAG_SENSINGMETHOD, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "SensingMethod" },
+ { EXIFTAG_FILESOURCE, 1, 1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 0, "FileSource" },
+ { EXIFTAG_SCENETYPE, 1, 1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 0, "SceneType" },
+ { EXIFTAG_CFAPATTERN, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 1, "CFAPattern" },
+ { EXIFTAG_CUSTOMRENDERED, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "CustomRendered" },
+ { EXIFTAG_EXPOSUREMODE, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "ExposureMode" },
+ { EXIFTAG_WHITEBALANCE, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "WhiteBalance" },
+ { EXIFTAG_DIGITALZOOMRATIO, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "DigitalZoomRatio" },
+ { EXIFTAG_FOCALLENGTHIN35MMFILM, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "FocalLengthIn35mmFilm" },
+ { EXIFTAG_SCENECAPTURETYPE, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "SceneCaptureType" },
+ { EXIFTAG_GAINCONTROL, 1, 1, TIFF_RATIONAL, FIELD_CUSTOM,
+ 1, 0, "GainControl" },
+ { EXIFTAG_CONTRAST, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "Contrast" },
+ { EXIFTAG_SATURATION, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "Saturation" },
+ { EXIFTAG_SHARPNESS, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "Sharpness" },
+ { EXIFTAG_DEVICESETTINGDESCRIPTION, -1, -1, TIFF_UNDEFINED, FIELD_CUSTOM,
+ 1, 1, "DeviceSettingDescription" },
+ { EXIFTAG_SUBJECTDISTANCERANGE, 1, 1, TIFF_SHORT, FIELD_CUSTOM,
+ 1, 0, "SubjectDistanceRange" },
+ { EXIFTAG_IMAGEUNIQUEID, 33, 33, TIFF_ASCII, FIELD_CUSTOM,
+ 1, 0, "ImageUniqueID" }
+};
+
+const TIFFFieldInfo *
+_TIFFGetFieldInfo(size_t *size)
+{
+ *size = TIFFArrayCount(tiffFieldInfo);
+ return tiffFieldInfo;
+}
+
+const TIFFFieldInfo *
+_TIFFGetExifFieldInfo(size_t *size)
+{
+ *size = TIFFArrayCount(exifFieldInfo);
+ return exifFieldInfo;
+}
+
+void
+_TIFFSetupFieldInfo(TIFF* tif, const TIFFFieldInfo info[], size_t n)
+{
+ if (tif->tif_fieldinfo) {
+ size_t i;
+
+ for (i = 0; i < tif->tif_nfields; i++)
+ {
+ TIFFFieldInfo *fld = tif->tif_fieldinfo[i];
+ if (fld->field_bit == FIELD_CUSTOM &&
+ strncmp("Tag ", fld->field_name, 4) == 0) {
+ _TIFFfree(fld->field_name);
+ _TIFFfree(fld);
+ }
+ }
+
+ _TIFFfree(tif->tif_fieldinfo);
+ tif->tif_nfields = 0;
+ }
+ if (!_TIFFMergeFieldInfo(tif, info, n))
+ {
+ TIFFErrorExt(tif->tif_clientdata, "_TIFFSetupFieldInfo",
+ "Setting up field info failed");
+ }
+}
+
+static int
+tagCompare(const void* a, const void* b)
+{
+ const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a;
+ const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) b;
+ /* NB: be careful of return values for 16-bit platforms */
+ if (ta->field_tag != tb->field_tag)
+ return (int)ta->field_tag - (int)tb->field_tag;
+ else
+ return (ta->field_type == TIFF_ANY) ?
+ 0 : ((int)tb->field_type - (int)ta->field_type);
+}
+
+static int
+tagNameCompare(const void* a, const void* b)
+{
+ const TIFFFieldInfo* ta = *(const TIFFFieldInfo**) a;
+ const TIFFFieldInfo* tb = *(const TIFFFieldInfo**) b;
+ int ret = strcmp(ta->field_name, tb->field_name);
+
+ if (ret)
+ return ret;
+ else
+ return (ta->field_type == TIFF_ANY) ?
+ 0 : ((int)tb->field_type - (int)ta->field_type);
+}
+
+void
+TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], int n)
+{
+ if (_TIFFMergeFieldInfo(tif, info, n) < 0)
+ {
+ TIFFErrorExt(tif->tif_clientdata, "TIFFMergeFieldInfo",
+ "Merging block of %d fields failed", n);
+ }
+}
+
+int
+_TIFFMergeFieldInfo(TIFF* tif, const TIFFFieldInfo info[], int n)
+{
+ static const char module[] = "_TIFFMergeFieldInfo";
+ static const char reason[] = "for field info array";
+ TIFFFieldInfo** tp;
+ int i;
+
+ tif->tif_foundfield = NULL;
+
+ if (tif->tif_nfields > 0) {
+ tif->tif_fieldinfo = (TIFFFieldInfo**)
+ _TIFFCheckRealloc(tif, tif->tif_fieldinfo,
+ (tif->tif_nfields + n),
+ sizeof (TIFFFieldInfo*), reason);
+ } else {
+ tif->tif_fieldinfo = (TIFFFieldInfo**)
+ _TIFFCheckMalloc(tif, n, sizeof (TIFFFieldInfo*),
+ reason);
+ }
+ if (!tif->tif_fieldinfo) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Failed to allocate field info array");
+ return 0;
+ }
+ tp = tif->tif_fieldinfo + tif->tif_nfields;
+ for (i = 0; i < n; i++)
+ {
+ const TIFFFieldInfo *fip =
+ _TIFFFindFieldInfo(tif, info[i].field_tag, info[i].field_type);
+
+ /* only add definitions that aren't already present */
+ if (!fip) {
+ *tp++ = (TIFFFieldInfo*) (info + i);
+ tif->tif_nfields++;
+ }
+ }
+
+ /* Sort the field info by tag number */
+ qsort(tif->tif_fieldinfo, tif->tif_nfields,
+ sizeof (TIFFFieldInfo*), tagCompare);
+
+ return n;
+}
+
+void
+_TIFFPrintFieldInfo(TIFF* tif, FILE* fd)
+{
+ size_t i;
+
+ fprintf(fd, "%s: \n", tif->tif_name);
+ for (i = 0; i < tif->tif_nfields; i++) {
+ const TIFFFieldInfo* fip = tif->tif_fieldinfo[i];
+ fprintf(fd, "field[%2d] %5lu, %2d, %2d, %d, %2d, %5s, %5s, %s\n"
+ , (int)i
+ , (unsigned long) fip->field_tag
+ , fip->field_readcount, fip->field_writecount
+ , fip->field_type
+ , fip->field_bit
+ , fip->field_oktochange ? "TRUE" : "FALSE"
+ , fip->field_passcount ? "TRUE" : "FALSE"
+ , fip->field_name
+ );
+ }
+}
+
+/*
+ * Return size of TIFFDataType in bytes
+ */
+int
+TIFFDataWidth(TIFFDataType type)
+{
+ switch(type)
+ {
+ case 0: /* nothing */
+ case 1: /* TIFF_BYTE */
+ case 2: /* TIFF_ASCII */
+ case 6: /* TIFF_SBYTE */
+ case 7: /* TIFF_UNDEFINED */
+ return 1;
+ case 3: /* TIFF_SHORT */
+ case 8: /* TIFF_SSHORT */
+ return 2;
+ case 4: /* TIFF_LONG */
+ case 9: /* TIFF_SLONG */
+ case 11: /* TIFF_FLOAT */
+ case 13: /* TIFF_IFD */
+ return 4;
+ case 5: /* TIFF_RATIONAL */
+ case 10: /* TIFF_SRATIONAL */
+ case 12: /* TIFF_DOUBLE */
+ return 8;
+ default:
+ return 0; /* will return 0 for unknown types */
+ }
+}
+
+/*
+ * Return size of TIFFDataType in bytes.
+ *
+ * XXX: We need a separate function to determine the space needed
+ * to store the value. For TIFF_RATIONAL values TIFFDataWidth() returns 8,
+ * but we use 4-byte float to represent rationals.
+ */
+int
+_TIFFDataSize(TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ case TIFF_ASCII:
+ case TIFF_UNDEFINED:
+ return 1;
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ return 2;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ case TIFF_IFD:
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ return 4;
+ case TIFF_DOUBLE:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Return nearest TIFFDataType to the sample type of an image.
+ */
+TIFFDataType
+_TIFFSampleToTagType(TIFF* tif)
+{
+ uint32 bps = TIFFhowmany8(tif->tif_dir.td_bitspersample);
+
+ switch (tif->tif_dir.td_sampleformat) {
+ case SAMPLEFORMAT_IEEEFP:
+ return (bps == 4 ? TIFF_FLOAT : TIFF_DOUBLE);
+ case SAMPLEFORMAT_INT:
+ return (bps <= 1 ? TIFF_SBYTE :
+ bps <= 2 ? TIFF_SSHORT : TIFF_SLONG);
+ case SAMPLEFORMAT_UINT:
+ return (bps <= 1 ? TIFF_BYTE :
+ bps <= 2 ? TIFF_SHORT : TIFF_LONG);
+ case SAMPLEFORMAT_VOID:
+ return (TIFF_UNDEFINED);
+ }
+ /*NOTREACHED*/
+ return (TIFF_UNDEFINED);
+}
+
+const TIFFFieldInfo*
+_TIFFFindFieldInfo(TIFF* tif, ttag_t tag, TIFFDataType dt)
+{
+ TIFFFieldInfo key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0};
+ TIFFFieldInfo* pkey = &key;
+ const TIFFFieldInfo **ret;
+
+ if (tif->tif_foundfield && tif->tif_foundfield->field_tag == tag &&
+ (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type))
+ return tif->tif_foundfield;
+
+ /* If we are invoked with no field information, then just return. */
+ if ( !tif->tif_fieldinfo ) {
+ return NULL;
+ }
+
+ /* NB: use sorted search (e.g. binary search) */
+ key.field_tag = tag;
+ key.field_type = dt;
+
+ ret = (const TIFFFieldInfo **) bsearch(&pkey,
+ tif->tif_fieldinfo,
+ tif->tif_nfields,
+ sizeof(TIFFFieldInfo *),
+ tagCompare);
+ return tif->tif_foundfield = (ret ? *ret : NULL);
+}
+
+const TIFFFieldInfo*
+_TIFFFindFieldInfoByName(TIFF* tif, const char *field_name, TIFFDataType dt)
+{
+ TIFFFieldInfo key = {0, 0, 0, TIFF_NOTYPE, 0, 0, 0, 0};
+ TIFFFieldInfo* pkey = &key;
+ const TIFFFieldInfo **ret;
+
+ if (tif->tif_foundfield
+ && streq(tif->tif_foundfield->field_name, field_name)
+ && (dt == TIFF_ANY || dt == tif->tif_foundfield->field_type))
+ return (tif->tif_foundfield);
+
+ /* If we are invoked with no field information, then just return. */
+ if ( !tif->tif_fieldinfo ) {
+ return NULL;
+ }
+
+ /* NB: use sorted search (e.g. binary search) */
+ key.field_name = (char *)field_name;
+ key.field_type = dt;
+
+ ret = (const TIFFFieldInfo **) lfind(&pkey,
+ tif->tif_fieldinfo,
+ &tif->tif_nfields,
+ sizeof(TIFFFieldInfo *),
+ tagNameCompare);
+ return tif->tif_foundfield = (ret ? *ret : NULL);
+}
+
+const TIFFFieldInfo*
+_TIFFFieldWithTag(TIFF* tif, ttag_t tag)
+{
+ const TIFFFieldInfo* fip = _TIFFFindFieldInfo(tif, tag, TIFF_ANY);
+ if (!fip) {
+ TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithTag",
+ "Internal error, unknown tag 0x%x",
+ (unsigned int) tag);
+ assert(fip != NULL);
+ /*NOTREACHED*/
+ }
+ return (fip);
+}
+
+const TIFFFieldInfo*
+_TIFFFieldWithName(TIFF* tif, const char *field_name)
+{
+ const TIFFFieldInfo* fip =
+ _TIFFFindFieldInfoByName(tif, field_name, TIFF_ANY);
+ if (!fip) {
+ TIFFErrorExt(tif->tif_clientdata, "TIFFFieldWithName",
+ "Internal error, unknown tag %s", field_name);
+ assert(fip != NULL);
+ /*NOTREACHED*/
+ }
+ return (fip);
+}
+
+const TIFFFieldInfo*
+_TIFFFindOrRegisterFieldInfo( TIFF *tif, ttag_t tag, TIFFDataType dt )
+
+{
+ const TIFFFieldInfo *fld;
+
+ fld = _TIFFFindFieldInfo( tif, tag, dt );
+ if( fld == NULL )
+ {
+ fld = _TIFFCreateAnonFieldInfo( tif, tag, dt );
+ if (!_TIFFMergeFieldInfo(tif, fld, 1))
+ return NULL;
+ }
+
+ return fld;
+}
+
+TIFFFieldInfo*
+_TIFFCreateAnonFieldInfo(TIFF *tif, ttag_t tag, TIFFDataType field_type)
+{
+ TIFFFieldInfo *fld;
+ (void) tif;
+
+ fld = (TIFFFieldInfo *) _TIFFmalloc(sizeof (TIFFFieldInfo));
+ if (fld == NULL)
+ return NULL;
+ _TIFFmemset( fld, 0, sizeof(TIFFFieldInfo) );
+
+ fld->field_tag = tag;
+ fld->field_readcount = TIFF_VARIABLE2;
+ fld->field_writecount = TIFF_VARIABLE2;
+ fld->field_type = field_type;
+ fld->field_bit = FIELD_CUSTOM;
+ fld->field_oktochange = TRUE;
+ fld->field_passcount = TRUE;
+ fld->field_name = (char *) _TIFFmalloc(32);
+ if (fld->field_name == NULL) {
+ _TIFFfree(fld);
+ return NULL;
+ }
+
+ /*
+ * note that this name is a special sign to TIFFClose() and
+ * _TIFFSetupFieldInfo() to free the field
+ */
+ sprintf(fld->field_name, "Tag %d", (int) tag);
+
+ return fld;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_dirread.c b/tiff/libtiff/tif_dirread.c
new file mode 100644
index 0000000..907b531
--- /dev/null
+++ b/tiff/libtiff/tif_dirread.c
@@ -0,0 +1,2081 @@
+/* $Id: tif_dirread.c,v 1.92.2.9 2010-06-14 00:21:46 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Read Support Routines.
+ */
+#include "tiffiop.h"
+
+#define IGNORE 0 /* tag placeholder used below */
+
+#ifdef HAVE_IEEEFP
+# define TIFFCvtIEEEFloatToNative(tif, n, fp)
+# define TIFFCvtIEEEDoubleToNative(tif, n, dp)
+#else
+extern void TIFFCvtIEEEFloatToNative(TIFF*, uint32, float*);
+extern void TIFFCvtIEEEDoubleToNative(TIFF*, uint32, double*);
+#endif
+
+static TIFFDirEntry* TIFFReadDirectoryFind(TIFFDirEntry* dir,
+ uint16 dircount, uint16 tagid);
+static int EstimateStripByteCounts(TIFF*, TIFFDirEntry*, uint16);
+static void MissingRequired(TIFF*, const char*);
+static int TIFFCheckDirOffset(TIFF*, toff_t);
+static int CheckDirCount(TIFF*, TIFFDirEntry*, uint32);
+static uint16 TIFFFetchDirectory(TIFF*, toff_t, TIFFDirEntry**, toff_t *);
+static tsize_t TIFFFetchData(TIFF*, TIFFDirEntry*, char*);
+static tsize_t TIFFFetchString(TIFF*, TIFFDirEntry*, char*);
+static float TIFFFetchRational(TIFF*, TIFFDirEntry*);
+static int TIFFFetchNormalTag(TIFF*, TIFFDirEntry*);
+static int TIFFFetchPerSampleShorts(TIFF*, TIFFDirEntry*, uint16*);
+static int TIFFFetchPerSampleLongs(TIFF*, TIFFDirEntry*, uint32*);
+static int TIFFFetchPerSampleAnys(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchShortArray(TIFF*, TIFFDirEntry*, uint16*);
+static int TIFFFetchStripThing(TIFF*, TIFFDirEntry*, long, uint32**);
+static int TIFFFetchRefBlackWhite(TIFF*, TIFFDirEntry*);
+static int TIFFFetchSubjectDistance(TIFF*, TIFFDirEntry*);
+static float TIFFFetchFloat(TIFF*, TIFFDirEntry*);
+static int TIFFFetchFloatArray(TIFF*, TIFFDirEntry*, float*);
+static int TIFFFetchDoubleArray(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchAnyArray(TIFF*, TIFFDirEntry*, double*);
+static int TIFFFetchShortPair(TIFF*, TIFFDirEntry*);
+static void ChopUpSingleUncompressedStrip(TIFF*);
+
+/*
+ * Read the next TIFF directory from a file and convert it to the internal
+ * format. We read directories sequentially.
+ */
+int
+TIFFReadDirectory(TIFF* tif)
+{
+ static const char module[] = "TIFFReadDirectory";
+
+ int n;
+ TIFFDirectory* td;
+ TIFFDirEntry *dp, *dir = NULL;
+ uint16 iv;
+ uint32 v;
+ const TIFFFieldInfo* fip;
+ size_t fix;
+ uint16 dircount;
+ int diroutoforderwarning = 0, compressionknown = 0;
+ int haveunknowntags = 0;
+
+ tif->tif_diroff = tif->tif_nextdiroff;
+ /*
+ * Check whether we have the last offset or bad offset (IFD looping).
+ */
+ if (!TIFFCheckDirOffset(tif, tif->tif_nextdiroff))
+ return 0;
+ /*
+ * Cleanup any previous compression state.
+ */
+ (*tif->tif_cleanup)(tif);
+ tif->tif_curdir++;
+ dircount = TIFFFetchDirectory(tif, tif->tif_nextdiroff,
+ &dir, &tif->tif_nextdiroff);
+ if (!dircount) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Failed to read directory at offset %u",
+ tif->tif_name, tif->tif_nextdiroff);
+ return 0;
+ }
+
+ tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */
+ /*
+ * Setup default value and then make a pass over
+ * the fields to check type and tag information,
+ * and to extract info required to size data
+ * structures. A second pass is made afterwards
+ * to read in everthing not taken in the first pass.
+ */
+ td = &tif->tif_dir;
+ /* free any old stuff and reinit */
+ TIFFFreeDirectory(tif);
+ TIFFDefaultDirectory(tif);
+ /*
+ * Electronic Arts writes gray-scale TIFF files
+ * without a PlanarConfiguration directory entry.
+ * Thus we setup a default value here, even though
+ * the TIFF spec says there is no default value.
+ */
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+
+ /*
+ * Sigh, we must make a separate pass through the
+ * directory for the following reason:
+ *
+ * We must process the Compression tag in the first pass
+ * in order to merge in codec-private tag definitions (otherwise
+ * we may get complaints about unknown tags). However, the
+ * Compression tag may be dependent on the SamplesPerPixel
+ * tag value because older TIFF specs permited Compression
+ * to be written as a SamplesPerPixel-count tag entry.
+ * Thus if we don't first figure out the correct SamplesPerPixel
+ * tag value then we may end up ignoring the Compression tag
+ * value because it has an incorrect count value (if the
+ * true value of SamplesPerPixel is not 1).
+ *
+ * It sure would have been nice if Aldus had really thought
+ * this stuff through carefully.
+ */
+ for (dp = dir, n = dircount; n > 0; n--, dp++) {
+ if (tif->tif_flags & TIFF_SWAB) {
+ TIFFSwabArrayOfShort(&dp->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dp->tdir_count, 2);
+ }
+ if (dp->tdir_tag == TIFFTAG_SAMPLESPERPIXEL) {
+ if (!TIFFFetchNormalTag(tif, dp))
+ goto bad;
+ dp->tdir_tag = IGNORE;
+ }
+ }
+ /*
+ * First real pass over the directory.
+ */
+ fix = 0;
+ for (dp = dir, n = dircount; n > 0; n--, dp++) {
+
+ if (dp->tdir_tag == IGNORE)
+ continue;
+ if (fix >= tif->tif_nfields)
+ fix = 0;
+
+ /*
+ * Silicon Beach (at least) writes unordered
+ * directory tags (violating the spec). Handle
+ * it here, but be obnoxious (maybe they'll fix it?).
+ */
+ if (dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) {
+ if (!diroutoforderwarning) {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: invalid TIFF directory; tags are not sorted in ascending order",
+ tif->tif_name);
+ diroutoforderwarning = 1;
+ }
+ fix = 0; /* O(n^2) */
+ }
+ while (fix < tif->tif_nfields &&
+ tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag)
+ fix++;
+ if (fix >= tif->tif_nfields ||
+ tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) {
+ /* Unknown tag ... we'll deal with it below */
+ haveunknowntags = 1;
+ continue;
+ }
+ /*
+ * Null out old tags that we ignore.
+ */
+ if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) {
+ ignore:
+ dp->tdir_tag = IGNORE;
+ continue;
+ }
+ /*
+ * Check data type.
+ */
+ fip = tif->tif_fieldinfo[fix];
+ while (dp->tdir_type != (unsigned short) fip->field_type
+ && fix < tif->tif_nfields) {
+ if (fip->field_type == TIFF_ANY) /* wildcard */
+ break;
+ fip = tif->tif_fieldinfo[++fix];
+ if (fix >= tif->tif_nfields ||
+ fip->field_tag != dp->tdir_tag) {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: wrong data type %d for \"%s\"; tag ignored",
+ tif->tif_name, dp->tdir_type,
+ tif->tif_fieldinfo[fix-1]->field_name);
+ goto ignore;
+ }
+ }
+ /*
+ * Check count if known in advance.
+ */
+ if (fip->field_readcount != TIFF_VARIABLE
+ && fip->field_readcount != TIFF_VARIABLE2) {
+ uint32 expected = (fip->field_readcount == TIFF_SPP) ?
+ (uint32) td->td_samplesperpixel :
+ (uint32) fip->field_readcount;
+ if (!CheckDirCount(tif, dp, expected))
+ goto ignore;
+ }
+
+ switch (dp->tdir_tag) {
+ case TIFFTAG_COMPRESSION:
+ /*
+ * The 5.0 spec says the Compression tag has
+ * one value, while earlier specs say it has
+ * one value per sample. Because of this, we
+ * accept the tag if one value is supplied.
+ */
+ if (dp->tdir_count == 1) {
+ v = TIFFExtractData(tif,
+ dp->tdir_type, dp->tdir_offset);
+ if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v))
+ goto bad;
+ else
+ compressionknown = 1;
+ break;
+ /* XXX: workaround for broken TIFFs */
+ } else if (dp->tdir_type == TIFF_LONG) {
+ if (!TIFFFetchPerSampleLongs(tif, dp, &v) ||
+ !TIFFSetField(tif, dp->tdir_tag, (uint16)v))
+ goto bad;
+ } else {
+ if (!TIFFFetchPerSampleShorts(tif, dp, &iv)
+ || !TIFFSetField(tif, dp->tdir_tag, iv))
+ goto bad;
+ }
+ dp->tdir_tag = IGNORE;
+ break;
+ case TIFFTAG_STRIPOFFSETS:
+ case TIFFTAG_STRIPBYTECOUNTS:
+ case TIFFTAG_TILEOFFSETS:
+ case TIFFTAG_TILEBYTECOUNTS:
+ TIFFSetFieldBit(tif, fip->field_bit);
+ break;
+ case TIFFTAG_IMAGEWIDTH:
+ case TIFFTAG_IMAGELENGTH:
+ case TIFFTAG_IMAGEDEPTH:
+ case TIFFTAG_TILELENGTH:
+ case TIFFTAG_TILEWIDTH:
+ case TIFFTAG_TILEDEPTH:
+ case TIFFTAG_PLANARCONFIG:
+ case TIFFTAG_ROWSPERSTRIP:
+ case TIFFTAG_EXTRASAMPLES:
+ if (!TIFFFetchNormalTag(tif, dp))
+ goto bad;
+ dp->tdir_tag = IGNORE;
+ break;
+ }
+ }
+
+ /*
+ * If we saw any unknown tags, make an extra pass over the directory
+ * to deal with them. This must be done separately because the tags
+ * could have become known when we registered a codec after finding
+ * the Compression tag. In a correctly-sorted directory there's
+ * no problem because Compression will come before any codec-private
+ * tags, but if the sorting is wrong that might not hold.
+ */
+ if (haveunknowntags) {
+ fix = 0;
+ for (dp = dir, n = dircount; n > 0; n--, dp++) {
+ if (dp->tdir_tag == IGNORE)
+ continue;
+ if (fix >= tif->tif_nfields ||
+ dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag)
+ fix = 0; /* O(n^2) */
+ while (fix < tif->tif_nfields &&
+ tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag)
+ fix++;
+ if (fix >= tif->tif_nfields ||
+ tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) {
+
+ TIFFWarningExt(tif->tif_clientdata,
+ module,
+ "%s: unknown field with tag %d (0x%x) encountered",
+ tif->tif_name,
+ dp->tdir_tag,
+ dp->tdir_tag);
+
+ if (!_TIFFMergeFieldInfo(tif,
+ _TIFFCreateAnonFieldInfo(tif,
+ dp->tdir_tag,
+ (TIFFDataType) dp->tdir_type),
+ 1))
+ {
+ TIFFWarningExt(tif->tif_clientdata,
+ module,
+ "Registering anonymous field with tag %d (0x%x) failed",
+ dp->tdir_tag,
+ dp->tdir_tag);
+ dp->tdir_tag = IGNORE;
+ continue;
+ }
+ fix = 0;
+ while (fix < tif->tif_nfields &&
+ tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag)
+ fix++;
+ }
+ /*
+ * Check data type.
+ */
+ fip = tif->tif_fieldinfo[fix];
+ while (dp->tdir_type != (unsigned short) fip->field_type
+ && fix < tif->tif_nfields) {
+ if (fip->field_type == TIFF_ANY) /* wildcard */
+ break;
+ fip = tif->tif_fieldinfo[++fix];
+ if (fix >= tif->tif_nfields ||
+ fip->field_tag != dp->tdir_tag) {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: wrong data type %d for \"%s\"; tag ignored",
+ tif->tif_name, dp->tdir_type,
+ tif->tif_fieldinfo[fix-1]->field_name);
+ dp->tdir_tag = IGNORE;
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * XXX: OJPEG hack.
+ * If a) compression is OJPEG, b) planarconfig tag says it's separate,
+ * c) strip offsets/bytecounts tag are both present and
+ * d) both contain exactly one value, then we consistently find
+ * that the buggy implementation of the buggy compression scheme
+ * matches contig planarconfig best. So we 'fix-up' the tag here
+ */
+ if ((td->td_compression==COMPRESSION_OJPEG) &&
+ (td->td_planarconfig==PLANARCONFIG_SEPARATE)) {
+ dp = TIFFReadDirectoryFind(dir,dircount,TIFFTAG_STRIPOFFSETS);
+ if ((dp!=0) && (dp->tdir_count==1)) {
+ dp = TIFFReadDirectoryFind(dir, dircount,
+ TIFFTAG_STRIPBYTECOUNTS);
+ if ((dp!=0) && (dp->tdir_count==1)) {
+ td->td_planarconfig=PLANARCONFIG_CONTIG;
+ TIFFWarningExt(tif->tif_clientdata,
+ "TIFFReadDirectory",
+ "Planarconfig tag value assumed incorrect, "
+ "assuming data is contig instead of chunky");
+ }
+ }
+ }
+
+ /*
+ * Allocate directory structure and setup defaults.
+ */
+ if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) {
+ MissingRequired(tif, "ImageLength");
+ goto bad;
+ }
+ /*
+ * Setup appropriate structures (by strip or by tile)
+ */
+ if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) {
+ td->td_nstrips = TIFFNumberOfStrips(tif);
+ td->td_tilewidth = td->td_imagewidth;
+ td->td_tilelength = td->td_rowsperstrip;
+ td->td_tiledepth = td->td_imagedepth;
+ tif->tif_flags &= ~TIFF_ISTILED;
+ } else {
+ td->td_nstrips = TIFFNumberOfTiles(tif);
+ tif->tif_flags |= TIFF_ISTILED;
+ }
+ if (!td->td_nstrips) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: cannot handle zero number of %s",
+ tif->tif_name, isTiled(tif) ? "tiles" : "strips");
+ goto bad;
+ }
+ td->td_stripsperimage = td->td_nstrips;
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+ td->td_stripsperimage /= td->td_samplesperpixel;
+ if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) {
+ if ((td->td_compression==COMPRESSION_OJPEG) &&
+ (isTiled(tif)==0) &&
+ (td->td_nstrips==1)) {
+ /*
+ * XXX: OJPEG hack.
+ * If a) compression is OJPEG, b) it's not a tiled TIFF,
+ * and c) the number of strips is 1,
+ * then we tolerate the absence of stripoffsets tag,
+ * because, presumably, all required data is in the
+ * JpegInterchangeFormat stream.
+ */
+ TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
+ } else {
+ MissingRequired(tif,
+ isTiled(tif) ? "TileOffsets" : "StripOffsets");
+ goto bad;
+ }
+ }
+
+ /*
+ * Second pass: extract other information.
+ */
+ for (dp = dir, n = dircount; n > 0; n--, dp++) {
+ if (dp->tdir_tag == IGNORE)
+ continue;
+ switch (dp->tdir_tag) {
+ case TIFFTAG_MINSAMPLEVALUE:
+ case TIFFTAG_MAXSAMPLEVALUE:
+ case TIFFTAG_BITSPERSAMPLE:
+ case TIFFTAG_DATATYPE:
+ case TIFFTAG_SAMPLEFORMAT:
+ /*
+ * The 5.0 spec says the Compression tag has
+ * one value, while earlier specs say it has
+ * one value per sample. Because of this, we
+ * accept the tag if one value is supplied.
+ *
+ * The MinSampleValue, MaxSampleValue, BitsPerSample
+ * DataType and SampleFormat tags are supposed to be
+ * written as one value/sample, but some vendors
+ * incorrectly write one value only -- so we accept
+ * that as well (yech). Other vendors write correct
+ * value for NumberOfSamples, but incorrect one for
+ * BitsPerSample and friends, and we will read this
+ * too.
+ */
+ if (dp->tdir_count == 1) {
+ v = TIFFExtractData(tif,
+ dp->tdir_type, dp->tdir_offset);
+ if (!TIFFSetField(tif, dp->tdir_tag, (uint16)v))
+ goto bad;
+ /* XXX: workaround for broken TIFFs */
+ } else if (dp->tdir_tag == TIFFTAG_BITSPERSAMPLE
+ && dp->tdir_type == TIFF_LONG) {
+ if (!TIFFFetchPerSampleLongs(tif, dp, &v) ||
+ !TIFFSetField(tif, dp->tdir_tag, (uint16)v))
+ goto bad;
+ } else {
+ if (!TIFFFetchPerSampleShorts(tif, dp, &iv) ||
+ !TIFFSetField(tif, dp->tdir_tag, iv))
+ goto bad;
+ }
+ break;
+ case TIFFTAG_SMINSAMPLEVALUE:
+ case TIFFTAG_SMAXSAMPLEVALUE:
+ {
+ double dv = 0.0;
+ if (!TIFFFetchPerSampleAnys(tif, dp, &dv) ||
+ !TIFFSetField(tif, dp->tdir_tag, dv))
+ goto bad;
+ }
+ break;
+ case TIFFTAG_STRIPOFFSETS:
+ case TIFFTAG_TILEOFFSETS:
+ if (!TIFFFetchStripThing(tif, dp,
+ td->td_nstrips, &td->td_stripoffset))
+ goto bad;
+ break;
+ case TIFFTAG_STRIPBYTECOUNTS:
+ case TIFFTAG_TILEBYTECOUNTS:
+ if (!TIFFFetchStripThing(tif, dp,
+ td->td_nstrips, &td->td_stripbytecount))
+ goto bad;
+ break;
+ case TIFFTAG_COLORMAP:
+ case TIFFTAG_TRANSFERFUNCTION:
+ {
+ char* cp;
+ /*
+ * TransferFunction can have either 1x or 3x
+ * data values; Colormap can have only 3x
+ * items.
+ */
+ v = 1L<<td->td_bitspersample;
+ if (dp->tdir_tag == TIFFTAG_COLORMAP ||
+ dp->tdir_count != v) {
+ if (!CheckDirCount(tif, dp, 3 * v))
+ break;
+ }
+ v *= sizeof(uint16);
+ cp = (char *)_TIFFCheckMalloc(tif,
+ dp->tdir_count,
+ sizeof (uint16),
+ "to read \"TransferFunction\" tag");
+ if (cp != NULL) {
+ if (TIFFFetchData(tif, dp, cp)) {
+ /*
+ * This deals with there being
+ * only one array to apply to
+ * all samples.
+ */
+ uint32 c = 1L << td->td_bitspersample;
+ if (dp->tdir_count == c)
+ v = 0L;
+ TIFFSetField(tif, dp->tdir_tag,
+ cp, cp+v, cp+2*v);
+ }
+ _TIFFfree(cp);
+ }
+ break;
+ }
+ case TIFFTAG_PAGENUMBER:
+ case TIFFTAG_HALFTONEHINTS:
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ case TIFFTAG_DOTRANGE:
+ (void) TIFFFetchShortPair(tif, dp);
+ break;
+ case TIFFTAG_REFERENCEBLACKWHITE:
+ (void) TIFFFetchRefBlackWhite(tif, dp);
+ break;
+/* BEGIN REV 4.0 COMPATIBILITY */
+ case TIFFTAG_OSUBFILETYPE:
+ v = 0L;
+ switch (TIFFExtractData(tif, dp->tdir_type,
+ dp->tdir_offset)) {
+ case OFILETYPE_REDUCEDIMAGE:
+ v = FILETYPE_REDUCEDIMAGE;
+ break;
+ case OFILETYPE_PAGE:
+ v = FILETYPE_PAGE;
+ break;
+ }
+ if (v)
+ TIFFSetField(tif, TIFFTAG_SUBFILETYPE, v);
+ break;
+/* END REV 4.0 COMPATIBILITY */
+ default:
+ (void) TIFFFetchNormalTag(tif, dp);
+ break;
+ }
+ }
+ /*
+ * OJPEG hack:
+ * - If a) compression is OJPEG, and b) photometric tag is missing,
+ * then we consistently find that photometric should be YCbCr
+ * - If a) compression is OJPEG, and b) photometric tag says it's RGB,
+ * then we consistently find that the buggy implementation of the
+ * buggy compression scheme matches photometric YCbCr instead.
+ * - If a) compression is OJPEG, and b) bitspersample tag is missing,
+ * then we consistently find bitspersample should be 8.
+ * - If a) compression is OJPEG, b) samplesperpixel tag is missing,
+ * and c) photometric is RGB or YCbCr, then we consistently find
+ * samplesperpixel should be 3
+ * - If a) compression is OJPEG, b) samplesperpixel tag is missing,
+ * and c) photometric is MINISWHITE or MINISBLACK, then we consistently
+ * find samplesperpixel should be 3
+ */
+ if (td->td_compression==COMPRESSION_OJPEG)
+ {
+ if (!TIFFFieldSet(tif,FIELD_PHOTOMETRIC))
+ {
+ TIFFWarningExt(tif->tif_clientdata, "TIFFReadDirectory",
+ "Photometric tag is missing, assuming data is YCbCr");
+ if (!TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,PHOTOMETRIC_YCBCR))
+ goto bad;
+ }
+ else if (td->td_photometric==PHOTOMETRIC_RGB)
+ {
+ td->td_photometric=PHOTOMETRIC_YCBCR;
+ TIFFWarningExt(tif->tif_clientdata, "TIFFReadDirectory",
+ "Photometric tag value assumed incorrect, "
+ "assuming data is YCbCr instead of RGB");
+ }
+ if (!TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
+ {
+ TIFFWarningExt(tif->tif_clientdata,"TIFFReadDirectory",
+ "BitsPerSample tag is missing, assuming 8 bits per sample");
+ if (!TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,8))
+ goto bad;
+ }
+ if (!TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
+ {
+ if ((td->td_photometric==PHOTOMETRIC_RGB)
+ || (td->td_photometric==PHOTOMETRIC_YCBCR))
+ {
+ TIFFWarningExt(tif->tif_clientdata,
+ "TIFFReadDirectory",
+ "SamplesPerPixel tag is missing, "
+ "assuming correct SamplesPerPixel value is 3");
+ if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,3))
+ goto bad;
+ }
+ else if ((td->td_photometric==PHOTOMETRIC_MINISWHITE)
+ || (td->td_photometric==PHOTOMETRIC_MINISBLACK))
+ {
+ TIFFWarningExt(tif->tif_clientdata,
+ "TIFFReadDirectory",
+ "SamplesPerPixel tag is missing, "
+ "assuming correct SamplesPerPixel value is 1");
+ if (!TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,1))
+ goto bad;
+ }
+ }
+ }
+ /*
+ * Verify Palette image has a Colormap.
+ */
+ if (td->td_photometric == PHOTOMETRIC_PALETTE &&
+ !TIFFFieldSet(tif, FIELD_COLORMAP)) {
+ MissingRequired(tif, "Colormap");
+ goto bad;
+ }
+ /*
+ * OJPEG hack:
+ * We do no further messing with strip/tile offsets/bytecounts in OJPEG
+ * TIFFs
+ */
+ if (td->td_compression!=COMPRESSION_OJPEG)
+ {
+ /*
+ * Attempt to deal with a missing StripByteCounts tag.
+ */
+ if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) {
+ /*
+ * Some manufacturers violate the spec by not giving
+ * the size of the strips. In this case, assume there
+ * is one uncompressed strip of data.
+ */
+ if ((td->td_planarconfig == PLANARCONFIG_CONTIG &&
+ td->td_nstrips > 1) ||
+ (td->td_planarconfig == PLANARCONFIG_SEPARATE &&
+ td->td_nstrips != td->td_samplesperpixel)) {
+ MissingRequired(tif, "StripByteCounts");
+ goto bad;
+ }
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: TIFF directory is missing required "
+ "\"%s\" field, calculating from imagelength",
+ tif->tif_name,
+ _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
+ if (EstimateStripByteCounts(tif, dir, dircount) < 0)
+ goto bad;
+ /*
+ * Assume we have wrong StripByteCount value (in case
+ * of single strip) in following cases:
+ * - it is equal to zero along with StripOffset;
+ * - it is larger than file itself (in case of uncompressed
+ * image);
+ * - it is smaller than the size of the bytes per row
+ * multiplied on the number of rows. The last case should
+ * not be checked in the case of writing new image,
+ * because we may do not know the exact strip size
+ * until the whole image will be written and directory
+ * dumped out.
+ */
+ #define BYTECOUNTLOOKSBAD \
+ ( (td->td_stripbytecount[0] == 0 && td->td_stripoffset[0] != 0) || \
+ (td->td_compression == COMPRESSION_NONE && \
+ td->td_stripbytecount[0] > TIFFGetFileSize(tif) - td->td_stripoffset[0]) || \
+ (tif->tif_mode == O_RDONLY && \
+ td->td_compression == COMPRESSION_NONE && \
+ td->td_stripbytecount[0] < TIFFScanlineSize(tif) * td->td_imagelength) )
+
+ } else if (td->td_nstrips == 1
+ && td->td_stripoffset[0] != 0
+ && BYTECOUNTLOOKSBAD) {
+ /*
+ * XXX: Plexus (and others) sometimes give a value of
+ * zero for a tag when they don't know what the
+ * correct value is! Try and handle the simple case
+ * of estimating the size of a one strip image.
+ */
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: Bogus \"%s\" field, ignoring and calculating from imagelength",
+ tif->tif_name,
+ _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
+ if(EstimateStripByteCounts(tif, dir, dircount) < 0)
+ goto bad;
+ } else if (td->td_planarconfig == PLANARCONFIG_CONTIG
+ && td->td_nstrips > 2
+ && td->td_compression == COMPRESSION_NONE
+ && td->td_stripbytecount[0] != td->td_stripbytecount[1]
+ && td->td_stripbytecount[0] != 0
+ && td->td_stripbytecount[1] != 0 ) {
+ /*
+ * XXX: Some vendors fill StripByteCount array with
+ * absolutely wrong values (it can be equal to
+ * StripOffset array, for example). Catch this case
+ * here.
+ */
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: Wrong \"%s\" field, ignoring and calculating from imagelength",
+ tif->tif_name,
+ _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name);
+ if (EstimateStripByteCounts(tif, dir, dircount) < 0)
+ goto bad;
+ }
+ }
+ if (dir) {
+ _TIFFfree((char *)dir);
+ dir = NULL;
+ }
+ if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE))
+ td->td_maxsamplevalue = (uint16)((1L<<td->td_bitspersample)-1);
+ /*
+ * Setup default compression scheme.
+ */
+
+ /*
+ * XXX: We can optimize checking for the strip bounds using the sorted
+ * bytecounts array. See also comments for TIFFAppendToStrip()
+ * function in tif_write.c.
+ */
+ if (td->td_nstrips > 1) {
+ tstrip_t strip;
+
+ td->td_stripbytecountsorted = 1;
+ for (strip = 1; strip < td->td_nstrips; strip++) {
+ if (td->td_stripoffset[strip - 1] >
+ td->td_stripoffset[strip]) {
+ td->td_stripbytecountsorted = 0;
+ break;
+ }
+ }
+ }
+
+ if (!TIFFFieldSet(tif, FIELD_COMPRESSION))
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ /*
+ * Some manufacturers make life difficult by writing
+ * large amounts of uncompressed data as a single strip.
+ * This is contrary to the recommendations of the spec.
+ * The following makes an attempt at breaking such images
+ * into strips closer to the recommended 8k bytes. A
+ * side effect, however, is that the RowsPerStrip tag
+ * value may be changed.
+ */
+ if (td->td_nstrips == 1 && td->td_compression == COMPRESSION_NONE &&
+ (tif->tif_flags & (TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP)
+ ChopUpSingleUncompressedStrip(tif);
+
+ /*
+ * Reinitialize i/o since we are starting on a new directory.
+ */
+ tif->tif_row = (uint32) -1;
+ tif->tif_curstrip = (tstrip_t) -1;
+ tif->tif_col = (uint32) -1;
+ tif->tif_curtile = (ttile_t) -1;
+ tif->tif_tilesize = (tsize_t) -1;
+
+ tif->tif_scanlinesize = TIFFScanlineSize(tif);
+ if (!tif->tif_scanlinesize) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: cannot handle zero scanline size",
+ tif->tif_name);
+ return (0);
+ }
+
+ if (isTiled(tif)) {
+ tif->tif_tilesize = TIFFTileSize(tif);
+ if (!tif->tif_tilesize) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: cannot handle zero tile size",
+ tif->tif_name);
+ return (0);
+ }
+ } else {
+ if (!TIFFStripSize(tif)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: cannot handle zero strip size",
+ tif->tif_name);
+ return (0);
+ }
+ }
+ return (1);
+bad:
+ if (dir)
+ _TIFFfree(dir);
+ return (0);
+}
+
+static TIFFDirEntry*
+TIFFReadDirectoryFind(TIFFDirEntry* dir, uint16 dircount, uint16 tagid)
+{
+ TIFFDirEntry* m;
+ uint16 n;
+ for (m=dir, n=0; n<dircount; m++, n++)
+ {
+ if (m->tdir_tag==tagid)
+ return(m);
+ }
+ return(0);
+}
+
+/*
+ * Read custom directory from the arbitarry offset.
+ * The code is very similar to TIFFReadDirectory().
+ */
+int
+TIFFReadCustomDirectory(TIFF* tif, toff_t diroff,
+ const TIFFFieldInfo info[], size_t n)
+{
+ static const char module[] = "TIFFReadCustomDirectory";
+
+ TIFFDirectory* td = &tif->tif_dir;
+ TIFFDirEntry *dp, *dir = NULL;
+ const TIFFFieldInfo* fip;
+ size_t fix;
+ uint16 i, dircount;
+
+ _TIFFSetupFieldInfo(tif, info, n);
+
+ dircount = TIFFFetchDirectory(tif, diroff, &dir, NULL);
+ if (!dircount) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Failed to read custom directory at offset %u",
+ tif->tif_name, diroff);
+ return 0;
+ }
+
+ TIFFFreeDirectory(tif);
+ _TIFFmemset(&tif->tif_dir, 0, sizeof(TIFFDirectory));
+
+ fix = 0;
+ for (dp = dir, i = dircount; i > 0; i--, dp++) {
+ if (tif->tif_flags & TIFF_SWAB) {
+ TIFFSwabArrayOfShort(&dp->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dp->tdir_count, 2);
+ }
+
+ if (fix >= tif->tif_nfields || dp->tdir_tag == IGNORE)
+ continue;
+
+ while (fix < tif->tif_nfields &&
+ tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag)
+ fix++;
+
+ if (fix >= tif->tif_nfields ||
+ tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) {
+
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: unknown field with tag %d (0x%x) encountered",
+ tif->tif_name, dp->tdir_tag, dp->tdir_tag);
+ if (!_TIFFMergeFieldInfo(tif,
+ _TIFFCreateAnonFieldInfo(tif,
+ dp->tdir_tag,
+ (TIFFDataType) dp->tdir_type),
+ 1))
+ {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "Registering anonymous field with tag %d (0x%x) failed",
+ dp->tdir_tag, dp->tdir_tag);
+ goto ignore;
+ }
+
+ fix = 0;
+ while (fix < tif->tif_nfields &&
+ tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag)
+ fix++;
+ }
+ /*
+ * Null out old tags that we ignore.
+ */
+ if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) {
+ ignore:
+ dp->tdir_tag = IGNORE;
+ continue;
+ }
+ /*
+ * Check data type.
+ */
+ fip = tif->tif_fieldinfo[fix];
+ while (dp->tdir_type != (unsigned short) fip->field_type
+ && fix < tif->tif_nfields) {
+ if (fip->field_type == TIFF_ANY) /* wildcard */
+ break;
+ fip = tif->tif_fieldinfo[++fix];
+ if (fix >= tif->tif_nfields ||
+ fip->field_tag != dp->tdir_tag) {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: wrong data type %d for \"%s\"; tag ignored",
+ tif->tif_name, dp->tdir_type,
+ tif->tif_fieldinfo[fix-1]->field_name);
+ goto ignore;
+ }
+ }
+ /*
+ * Check count if known in advance.
+ */
+ if (fip->field_readcount != TIFF_VARIABLE
+ && fip->field_readcount != TIFF_VARIABLE2) {
+ uint32 expected = (fip->field_readcount == TIFF_SPP) ?
+ (uint32) td->td_samplesperpixel :
+ (uint32) fip->field_readcount;
+ if (!CheckDirCount(tif, dp, expected))
+ goto ignore;
+ }
+
+ /*
+ * EXIF tags which need to be specifically processed.
+ */
+ switch (dp->tdir_tag) {
+ case EXIFTAG_SUBJECTDISTANCE:
+ (void) TIFFFetchSubjectDistance(tif, dp);
+ break;
+ default:
+ (void) TIFFFetchNormalTag(tif, dp);
+ break;
+ }
+ }
+
+ if (dir)
+ _TIFFfree(dir);
+ return 1;
+}
+
+/*
+ * EXIF is important special case of custom IFD, so we have a special
+ * function to read it.
+ */
+int
+TIFFReadEXIFDirectory(TIFF* tif, toff_t diroff)
+{
+ size_t exifFieldInfoCount;
+ const TIFFFieldInfo *exifFieldInfo =
+ _TIFFGetExifFieldInfo(&exifFieldInfoCount);
+ return TIFFReadCustomDirectory(tif, diroff, exifFieldInfo,
+ exifFieldInfoCount);
+}
+
+static int
+EstimateStripByteCounts(TIFF* tif, TIFFDirEntry* dir, uint16 dircount)
+{
+ static const char module[] = "EstimateStripByteCounts";
+
+ TIFFDirEntry *dp;
+ TIFFDirectory *td = &tif->tif_dir;
+ uint32 strip;
+
+ if (td->td_stripbytecount)
+ _TIFFfree(td->td_stripbytecount);
+ td->td_stripbytecount = (uint32*)
+ _TIFFCheckMalloc(tif, td->td_nstrips, sizeof (uint32),
+ "for \"StripByteCounts\" array");
+ if( td->td_stripbytecount == NULL )
+ return -1;
+
+ if (td->td_compression != COMPRESSION_NONE) {
+ uint32 space = (uint32)(sizeof (TIFFHeader)
+ + sizeof (uint16)
+ + (dircount * sizeof (TIFFDirEntry))
+ + sizeof (uint32));
+ toff_t filesize = TIFFGetFileSize(tif);
+ uint16 n;
+
+ /* calculate amount of space used by indirect values */
+ for (dp = dir, n = dircount; n > 0; n--, dp++)
+ {
+ uint32 cc = TIFFDataWidth((TIFFDataType) dp->tdir_type);
+ if (cc == 0) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Cannot determine size of unknown tag type %d",
+ tif->tif_name, dp->tdir_type);
+ return -1;
+ }
+ cc = cc * dp->tdir_count;
+ if (cc > sizeof (uint32))
+ space += cc;
+ }
+ space = filesize - space;
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+ space /= td->td_samplesperpixel;
+ for (strip = 0; strip < td->td_nstrips; strip++)
+ td->td_stripbytecount[strip] = space;
+ /*
+ * This gross hack handles the case were the offset to
+ * the last strip is past the place where we think the strip
+ * should begin. Since a strip of data must be contiguous,
+ * it's safe to assume that we've overestimated the amount
+ * of data in the strip and trim this number back accordingly.
+ */
+ strip--;
+ if (((toff_t)(td->td_stripoffset[strip]+
+ td->td_stripbytecount[strip])) > filesize)
+ td->td_stripbytecount[strip] =
+ filesize - td->td_stripoffset[strip];
+ } else if (isTiled(tif)) {
+ uint32 bytespertile = TIFFTileSize(tif);
+
+ for (strip = 0; strip < td->td_nstrips; strip++)
+ td->td_stripbytecount[strip] = bytespertile;
+ } else {
+ uint32 rowbytes = TIFFScanlineSize(tif);
+ uint32 rowsperstrip = td->td_imagelength/td->td_stripsperimage;
+ for (strip = 0; strip < td->td_nstrips; strip++)
+ td->td_stripbytecount[strip] = rowbytes * rowsperstrip;
+ }
+ TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
+ if (!TIFFFieldSet(tif, FIELD_ROWSPERSTRIP))
+ td->td_rowsperstrip = td->td_imagelength;
+ return 1;
+}
+
+static void
+MissingRequired(TIFF* tif, const char* tagname)
+{
+ static const char module[] = "MissingRequired";
+
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: TIFF directory is missing required \"%s\" field",
+ tif->tif_name, tagname);
+}
+
+/*
+ * Check the directory offset against the list of already seen directory
+ * offsets. This is a trick to prevent IFD looping. The one can create TIFF
+ * file with looped directory pointers. We will maintain a list of already
+ * seen directories and check every IFD offset against that list.
+ */
+static int
+TIFFCheckDirOffset(TIFF* tif, toff_t diroff)
+{
+ uint16 n;
+
+ if (diroff == 0) /* no more directories */
+ return 0;
+
+ for (n = 0; n < tif->tif_dirnumber && tif->tif_dirlist; n++) {
+ if (tif->tif_dirlist[n] == diroff)
+ return 0;
+ }
+
+ tif->tif_dirnumber++;
+
+ if (tif->tif_dirnumber > tif->tif_dirlistsize) {
+ toff_t* new_dirlist;
+
+ /*
+ * XXX: Reduce memory allocation granularity of the dirlist
+ * array.
+ */
+ new_dirlist = (toff_t *)_TIFFCheckRealloc(tif,
+ tif->tif_dirlist,
+ tif->tif_dirnumber,
+ 2 * sizeof(toff_t),
+ "for IFD list");
+ if (!new_dirlist)
+ return 0;
+ tif->tif_dirlistsize = 2 * tif->tif_dirnumber;
+ tif->tif_dirlist = new_dirlist;
+ }
+
+ tif->tif_dirlist[tif->tif_dirnumber - 1] = diroff;
+
+ return 1;
+}
+
+/*
+ * Check the count field of a directory entry against a known value. The
+ * caller is expected to skip/ignore the tag if there is a mismatch.
+ */
+static int
+CheckDirCount(TIFF* tif, TIFFDirEntry* dir, uint32 count)
+{
+ if (count > dir->tdir_count) {
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "incorrect count for field \"%s\" (%u, expecting %u); tag ignored",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
+ dir->tdir_count, count);
+ return (0);
+ } else if (count < dir->tdir_count) {
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "incorrect count for field \"%s\" (%u, expecting %u); tag trimmed",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
+ dir->tdir_count, count);
+ return (1);
+ }
+ return (1);
+}
+
+/*
+ * Read IFD structure from the specified offset. If the pointer to
+ * nextdiroff variable has been specified, read it too. Function returns a
+ * number of fields in the directory or 0 if failed.
+ */
+static uint16
+TIFFFetchDirectory(TIFF* tif, toff_t diroff, TIFFDirEntry **pdir,
+ toff_t *nextdiroff)
+{
+ static const char module[] = "TIFFFetchDirectory";
+
+ TIFFDirEntry *dir;
+ uint16 dircount;
+
+ assert(pdir);
+
+ tif->tif_diroff = diroff;
+ if (nextdiroff)
+ *nextdiroff = 0;
+ if (!isMapped(tif)) {
+ if (!SeekOK(tif, tif->tif_diroff)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Seek error accessing TIFF directory",
+ tif->tif_name);
+ return 0;
+ }
+ if (!ReadOK(tif, &dircount, sizeof (uint16))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Can not read TIFF directory count",
+ tif->tif_name);
+ return 0;
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount,
+ sizeof (TIFFDirEntry),
+ "to read TIFF directory");
+ if (dir == NULL)
+ return 0;
+ if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%.100s: Can not read TIFF directory",
+ tif->tif_name);
+ _TIFFfree(dir);
+ return 0;
+ }
+ /*
+ * Read offset to next directory for sequential scans if
+ * needed.
+ */
+ if (nextdiroff)
+ (void) ReadOK(tif, nextdiroff, sizeof(uint32));
+ } else {
+ toff_t off = tif->tif_diroff;
+
+ /*
+ * Check for integer overflow when validating the dir_off,
+ * otherwise a very high offset may cause an OOB read and
+ * crash the client. Make two comparisons instead of
+ *
+ * off + sizeof(uint16) > tif->tif_size
+ *
+ * to avoid overflow.
+ */
+ if (tif->tif_size < sizeof (uint16) ||
+ off > tif->tif_size - sizeof(uint16)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Can not read TIFF directory count",
+ tif->tif_name);
+ return 0;
+ } else {
+ _TIFFmemcpy(&dircount, tif->tif_base + off,
+ sizeof(uint16));
+ }
+ off += sizeof (uint16);
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ dir = (TIFFDirEntry *)_TIFFCheckMalloc(tif, dircount,
+ sizeof(TIFFDirEntry),
+ "to read TIFF directory");
+ if (dir == NULL)
+ return 0;
+ if (off + dircount * sizeof (TIFFDirEntry) > tif->tif_size) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Can not read TIFF directory",
+ tif->tif_name);
+ _TIFFfree(dir);
+ return 0;
+ } else {
+ _TIFFmemcpy(dir, tif->tif_base + off,
+ dircount * sizeof(TIFFDirEntry));
+ }
+ if (nextdiroff) {
+ off += dircount * sizeof (TIFFDirEntry);
+ if (off + sizeof (uint32) <= tif->tif_size) {
+ _TIFFmemcpy(nextdiroff, tif->tif_base + off,
+ sizeof (uint32));
+ }
+ }
+ }
+ if (nextdiroff && tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(nextdiroff);
+ *pdir = dir;
+ return dircount;
+}
+
+/*
+ * Fetch a contiguous directory item.
+ */
+static tsize_t
+TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ uint32 w = TIFFDataWidth((TIFFDataType) dir->tdir_type);
+ /*
+ * FIXME: butecount should have tsize_t type, but for now libtiff
+ * defines tsize_t as a signed 32-bit integer and we are losing
+ * ability to read arrays larger than 2^31 bytes. So we are using
+ * uint32 instead of tsize_t here.
+ */
+ uint32 cc = dir->tdir_count * w;
+
+ /* Check for overflow. */
+ if (!dir->tdir_count || !w || cc / w != dir->tdir_count)
+ goto bad;
+
+ if (!isMapped(tif)) {
+ if (!SeekOK(tif, dir->tdir_offset))
+ goto bad;
+ if (!ReadOK(tif, cp, cc))
+ goto bad;
+ } else {
+ /* Check for overflow. */
+ if (dir->tdir_offset + cc < dir->tdir_offset
+ || dir->tdir_offset + cc < cc
+ || dir->tdir_offset + cc > tif->tif_size)
+ goto bad;
+ _TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc);
+ }
+ if (tif->tif_flags & TIFF_SWAB) {
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count);
+ break;
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count);
+ break;
+ }
+ }
+ return (cc);
+bad:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error fetching data for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return (tsize_t) 0;
+}
+
+/*
+ * Fetch an ASCII item from the file.
+ */
+static tsize_t
+TIFFFetchString(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ if (dir->tdir_count <= 4) {
+ uint32 l = dir->tdir_offset;
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&l);
+ _TIFFmemcpy(cp, &l, dir->tdir_count);
+ return (1);
+ }
+ return (TIFFFetchData(tif, dir, cp));
+}
+
+/*
+ * Convert numerator+denominator to float.
+ */
+static int
+cvtRational(TIFF* tif, TIFFDirEntry* dir, uint32 num, uint32 denom, float* rv)
+{
+ if (denom == 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%s: Rational with zero denominator (num = %u)",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name, num);
+ return (0);
+ } else {
+ if (dir->tdir_type == TIFF_RATIONAL)
+ *rv = ((float)num / (float)denom);
+ else
+ *rv = ((float)(int32)num / (float)(int32)denom);
+ return (1);
+ }
+}
+
+/*
+ * Fetch a rational item from the file at offset off and return the value as a
+ * floating point number.
+ */
+static float
+TIFFFetchRational(TIFF* tif, TIFFDirEntry* dir)
+{
+ uint32 l[2];
+ float v;
+
+ return (!TIFFFetchData(tif, dir, (char *)l) ||
+ !cvtRational(tif, dir, l[0], l[1], &v) ? 1.0f : v);
+}
+
+/*
+ * Fetch a single floating point value from the offset field and return it as
+ * a native float.
+ */
+static float
+TIFFFetchFloat(TIFF* tif, TIFFDirEntry* dir)
+{
+ float v;
+ int32 l = TIFFExtractData(tif, dir->tdir_type, dir->tdir_offset);
+ _TIFFmemcpy(&v, &l, sizeof(float));
+ TIFFCvtIEEEFloatToNative(tif, 1, &v);
+ return (v);
+}
+
+/*
+ * Fetch an array of BYTE or SBYTE values.
+ */
+static int
+TIFFFetchByteArray(TIFF* tif, TIFFDirEntry* dir, uint8* v)
+{
+ if (dir->tdir_count <= 4) {
+ /*
+ * Extract data from offset field.
+ */
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ if (dir->tdir_type == TIFF_SBYTE)
+ switch (dir->tdir_count) {
+ case 4: v[3] = dir->tdir_offset & 0xff;
+ case 3: v[2] = (dir->tdir_offset >> 8) & 0xff;
+ case 2: v[1] = (dir->tdir_offset >> 16) & 0xff;
+ case 1: v[0] = dir->tdir_offset >> 24;
+ }
+ else
+ switch (dir->tdir_count) {
+ case 4: v[3] = dir->tdir_offset & 0xff;
+ case 3: v[2] = (dir->tdir_offset >> 8) & 0xff;
+ case 2: v[1] = (dir->tdir_offset >> 16) & 0xff;
+ case 1: v[0] = dir->tdir_offset >> 24;
+ }
+ } else {
+ if (dir->tdir_type == TIFF_SBYTE)
+ switch (dir->tdir_count) {
+ case 4: v[3] = dir->tdir_offset >> 24;
+ case 3: v[2] = (dir->tdir_offset >> 16) & 0xff;
+ case 2: v[1] = (dir->tdir_offset >> 8) & 0xff;
+ case 1: v[0] = dir->tdir_offset & 0xff;
+ }
+ else
+ switch (dir->tdir_count) {
+ case 4: v[3] = dir->tdir_offset >> 24;
+ case 3: v[2] = (dir->tdir_offset >> 16) & 0xff;
+ case 2: v[1] = (dir->tdir_offset >> 8) & 0xff;
+ case 1: v[0] = dir->tdir_offset & 0xff;
+ }
+ }
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char*) v) != 0); /* XXX */
+}
+
+/*
+ * Fetch an array of SHORT or SSHORT values.
+ */
+static int
+TIFFFetchShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v)
+{
+ if (dir->tdir_count <= 2) {
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ switch (dir->tdir_count) {
+ case 2: v[1] = (uint16) (dir->tdir_offset & 0xffff);
+ case 1: v[0] = (uint16) (dir->tdir_offset >> 16);
+ }
+ } else {
+ switch (dir->tdir_count) {
+ case 2: v[1] = (uint16) (dir->tdir_offset >> 16);
+ case 1: v[0] = (uint16) (dir->tdir_offset & 0xffff);
+ }
+ }
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char *)v) != 0);
+}
+
+/*
+ * Fetch a pair of SHORT or BYTE values. Some tags may have either BYTE
+ * or SHORT type and this function works with both ones.
+ */
+static int
+TIFFFetchShortPair(TIFF* tif, TIFFDirEntry* dir)
+{
+ /*
+ * Prevent overflowing the v stack arrays below by performing a sanity
+ * check on tdir_count, this should never be greater than two.
+ */
+ if (dir->tdir_count > 2) {
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "unexpected count for field \"%s\", %u, expected 2; ignored",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name,
+ dir->tdir_count);
+ return 0;
+ }
+
+ switch (dir->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ {
+ uint8 v[4];
+ return TIFFFetchByteArray(tif, dir, v)
+ && TIFFSetField(tif, dir->tdir_tag, v[0], v[1]);
+ }
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ {
+ uint16 v[2];
+ return TIFFFetchShortArray(tif, dir, v)
+ && TIFFSetField(tif, dir->tdir_tag, v[0], v[1]);
+ }
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Fetch an array of LONG or SLONG values.
+ */
+static int
+TIFFFetchLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v)
+{
+ if (dir->tdir_count == 1) {
+ v[0] = dir->tdir_offset;
+ return (1);
+ } else
+ return (TIFFFetchData(tif, dir, (char*) v) != 0);
+}
+
+/*
+ * Fetch an array of RATIONAL or SRATIONAL values.
+ */
+static int
+TIFFFetchRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+ int ok = 0;
+ uint32* l;
+
+ l = (uint32*)_TIFFCheckMalloc(tif,
+ dir->tdir_count, TIFFDataWidth((TIFFDataType) dir->tdir_type),
+ "to fetch array of rationals");
+ if (l) {
+ if (TIFFFetchData(tif, dir, (char *)l)) {
+ uint32 i;
+ for (i = 0; i < dir->tdir_count; i++) {
+ ok = cvtRational(tif, dir,
+ l[2*i+0], l[2*i+1], &v[i]);
+ if (!ok)
+ break;
+ }
+ }
+ _TIFFfree((char *)l);
+ }
+ return (ok);
+}
+
+/*
+ * Fetch an array of FLOAT values.
+ */
+static int
+TIFFFetchFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+
+ if (dir->tdir_count == 1) {
+ union
+ {
+ float f;
+ uint32 i;
+ } float_union;
+
+ float_union.i=dir->tdir_offset;
+ v[0]=float_union.f;
+ TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else if (TIFFFetchData(tif, dir, (char*) v)) {
+ TIFFCvtIEEEFloatToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * Fetch an array of DOUBLE values.
+ */
+static int
+TIFFFetchDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v)
+{
+ if (TIFFFetchData(tif, dir, (char*) v)) {
+ TIFFCvtIEEEDoubleToNative(tif, dir->tdir_count, v);
+ return (1);
+ } else
+ return (0);
+}
+
+/*
+ * Fetch an array of ANY values. The actual values are returned as doubles
+ * which should be able hold all the types. Yes, there really should be an
+ * tany_t to avoid this potential non-portability ... Note in particular that
+ * we assume that the double return value vector is large enough to read in
+ * any fundamental type. We use that vector as a buffer to read in the base
+ * type vector and then convert it in place to double (from end to front of
+ * course).
+ */
+static int
+TIFFFetchAnyArray(TIFF* tif, TIFFDirEntry* dir, double* v)
+{
+ int i;
+
+ switch (dir->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ if (!TIFFFetchByteArray(tif, dir, (uint8*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_BYTE) {
+ uint8* vp = (uint8*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int8* vp = (int8*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ if (!TIFFFetchShortArray(tif, dir, (uint16*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_SHORT) {
+ uint16* vp = (uint16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int16* vp = (int16*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ if (!TIFFFetchLongArray(tif, dir, (uint32*) v))
+ return (0);
+ if (dir->tdir_type == TIFF_LONG) {
+ uint32* vp = (uint32*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ } else {
+ int32* vp = (int32*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ if (!TIFFFetchRationalArray(tif, dir, (float*) v))
+ return (0);
+ { float* vp = (float*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_FLOAT:
+ if (!TIFFFetchFloatArray(tif, dir, (float*) v))
+ return (0);
+ { float* vp = (float*) v;
+ for (i = dir->tdir_count-1; i >= 0; i--)
+ v[i] = vp[i];
+ }
+ break;
+ case TIFF_DOUBLE:
+ return (TIFFFetchDoubleArray(tif, dir, (double*) v));
+ default:
+ /* TIFF_NOTYPE */
+ /* TIFF_ASCII */
+ /* TIFF_UNDEFINED */
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "cannot read TIFF_ANY type %d for field \"%s\"",
+ dir->tdir_type,
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Fetch a tag that is not handled by special case code.
+ */
+static int
+TIFFFetchNormalTag(TIFF* tif, TIFFDirEntry* dp)
+{
+ static const char mesg[] = "to fetch tag value";
+ int ok = 0;
+ const TIFFFieldInfo* fip = _TIFFFieldWithTag(tif, dp->tdir_tag);
+
+ if (dp->tdir_count > 1) { /* array of values */
+ char* cp = NULL;
+
+ switch (dp->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ cp = (char *)_TIFFCheckMalloc(tif,
+ dp->tdir_count, sizeof (uint8), mesg);
+ ok = cp && TIFFFetchByteArray(tif, dp, (uint8*) cp);
+ break;
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ cp = (char *)_TIFFCheckMalloc(tif,
+ dp->tdir_count, sizeof (uint16), mesg);
+ ok = cp && TIFFFetchShortArray(tif, dp, (uint16*) cp);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ cp = (char *)_TIFFCheckMalloc(tif,
+ dp->tdir_count, sizeof (uint32), mesg);
+ ok = cp && TIFFFetchLongArray(tif, dp, (uint32*) cp);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ cp = (char *)_TIFFCheckMalloc(tif,
+ dp->tdir_count, sizeof (float), mesg);
+ ok = cp && TIFFFetchRationalArray(tif, dp, (float*) cp);
+ break;
+ case TIFF_FLOAT:
+ cp = (char *)_TIFFCheckMalloc(tif,
+ dp->tdir_count, sizeof (float), mesg);
+ ok = cp && TIFFFetchFloatArray(tif, dp, (float*) cp);
+ break;
+ case TIFF_DOUBLE:
+ cp = (char *)_TIFFCheckMalloc(tif,
+ dp->tdir_count, sizeof (double), mesg);
+ ok = cp && TIFFFetchDoubleArray(tif, dp, (double*) cp);
+ break;
+ case TIFF_ASCII:
+ case TIFF_UNDEFINED: /* bit of a cheat... */
+ /*
+ * Some vendors write strings w/o the trailing
+ * NULL byte, so always append one just in case.
+ */
+ cp = (char *)_TIFFCheckMalloc(tif, dp->tdir_count + 1,
+ 1, mesg);
+ if( (ok = (cp && TIFFFetchString(tif, dp, cp))) != 0 )
+ cp[dp->tdir_count] = '\0'; /* XXX */
+ break;
+ }
+ if (ok) {
+ ok = (fip->field_passcount ?
+ TIFFSetField(tif, dp->tdir_tag, dp->tdir_count, cp)
+ : TIFFSetField(tif, dp->tdir_tag, cp));
+ }
+ if (cp != NULL)
+ _TIFFfree(cp);
+ } else if (CheckDirCount(tif, dp, 1)) { /* singleton value */
+ switch (dp->tdir_type) {
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ /*
+ * If the tag is also acceptable as a LONG or SLONG
+ * then TIFFSetField will expect an uint32 parameter
+ * passed to it (through varargs). Thus, for machines
+ * where sizeof (int) != sizeof (uint32) we must do
+ * a careful check here. It's hard to say if this
+ * is worth optimizing.
+ *
+ * NB: We use TIFFFieldWithTag here knowing that
+ * it returns us the first entry in the table
+ * for the tag and that that entry is for the
+ * widest potential data type the tag may have.
+ */
+ { TIFFDataType type = fip->field_type;
+ if (type != TIFF_LONG && type != TIFF_SLONG) {
+ uint16 v = (uint16)
+ TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset);
+ ok = (fip->field_passcount ?
+ TIFFSetField(tif, dp->tdir_tag, 1, &v)
+ : TIFFSetField(tif, dp->tdir_tag, v));
+ break;
+ }
+ }
+ /* fall thru... */
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ { uint32 v32 =
+ TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset);
+ ok = (fip->field_passcount ?
+ TIFFSetField(tif, dp->tdir_tag, 1, &v32)
+ : TIFFSetField(tif, dp->tdir_tag, v32));
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ { float v = (dp->tdir_type == TIFF_FLOAT ?
+ TIFFFetchFloat(tif, dp)
+ : TIFFFetchRational(tif, dp));
+ ok = (fip->field_passcount ?
+ TIFFSetField(tif, dp->tdir_tag, 1, &v)
+ : TIFFSetField(tif, dp->tdir_tag, v));
+ }
+ break;
+ case TIFF_DOUBLE:
+ { double v;
+ ok = (TIFFFetchDoubleArray(tif, dp, &v) &&
+ (fip->field_passcount ?
+ TIFFSetField(tif, dp->tdir_tag, 1, &v)
+ : TIFFSetField(tif, dp->tdir_tag, v))
+ );
+ }
+ break;
+ case TIFF_ASCII:
+ case TIFF_UNDEFINED: /* bit of a cheat... */
+ { char c[2];
+ if( (ok = (TIFFFetchString(tif, dp, c) != 0)) != 0 ) {
+ c[1] = '\0'; /* XXX paranoid */
+ ok = (fip->field_passcount ?
+ TIFFSetField(tif, dp->tdir_tag, 1, c)
+ : TIFFSetField(tif, dp->tdir_tag, c));
+ }
+ }
+ break;
+ }
+ }
+ return (ok);
+}
+
+#define NITEMS(x) (sizeof (x) / sizeof (x[0]))
+/*
+ * Fetch samples/pixel short values for
+ * the specified tag and verify that
+ * all values are the same.
+ */
+static int
+TIFFFetchPerSampleShorts(TIFF* tif, TIFFDirEntry* dir, uint16* pl)
+{
+ uint16 samples = tif->tif_dir.td_samplesperpixel;
+ int status = 0;
+
+ if (CheckDirCount(tif, dir, (uint32) samples)) {
+ uint16 buf[10];
+ uint16* v = buf;
+
+ if (dir->tdir_count > NITEMS(buf))
+ v = (uint16*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof(uint16),
+ "to fetch per-sample values");
+ if (v && TIFFFetchShortArray(tif, dir, v)) {
+ uint16 i;
+ int check_count = dir->tdir_count;
+ if( samples < check_count )
+ check_count = samples;
+
+ for (i = 1; i < check_count; i++)
+ if (v[i] != v[0]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot handle different per-sample values for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ goto bad;
+ }
+ *pl = v[0];
+ status = 1;
+ }
+ bad:
+ if (v && v != buf)
+ _TIFFfree(v);
+ }
+ return (status);
+}
+
+/*
+ * Fetch samples/pixel long values for
+ * the specified tag and verify that
+ * all values are the same.
+ */
+static int
+TIFFFetchPerSampleLongs(TIFF* tif, TIFFDirEntry* dir, uint32* pl)
+{
+ uint16 samples = tif->tif_dir.td_samplesperpixel;
+ int status = 0;
+
+ if (CheckDirCount(tif, dir, (uint32) samples)) {
+ uint32 buf[10];
+ uint32* v = buf;
+
+ if (dir->tdir_count > NITEMS(buf))
+ v = (uint32*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof(uint32),
+ "to fetch per-sample values");
+ if (v && TIFFFetchLongArray(tif, dir, v)) {
+ uint16 i;
+ int check_count = dir->tdir_count;
+
+ if( samples < check_count )
+ check_count = samples;
+ for (i = 1; i < check_count; i++)
+ if (v[i] != v[0]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot handle different per-sample values for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ goto bad;
+ }
+ *pl = v[0];
+ status = 1;
+ }
+ bad:
+ if (v && v != buf)
+ _TIFFfree(v);
+ }
+ return (status);
+}
+
+/*
+ * Fetch samples/pixel ANY values for the specified tag and verify that all
+ * values are the same.
+ */
+static int
+TIFFFetchPerSampleAnys(TIFF* tif, TIFFDirEntry* dir, double* pl)
+{
+ uint16 samples = tif->tif_dir.td_samplesperpixel;
+ int status = 0;
+
+ if (CheckDirCount(tif, dir, (uint32) samples)) {
+ double buf[10];
+ double* v = buf;
+
+ if (dir->tdir_count > NITEMS(buf))
+ v = (double*) _TIFFCheckMalloc(tif, dir->tdir_count, sizeof (double),
+ "to fetch per-sample values");
+ if (v && TIFFFetchAnyArray(tif, dir, v)) {
+ uint16 i;
+ int check_count = dir->tdir_count;
+ if( samples < check_count )
+ check_count = samples;
+
+ for (i = 1; i < check_count; i++)
+ if (v[i] != v[0]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot handle different per-sample values for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ goto bad;
+ }
+ *pl = v[0];
+ status = 1;
+ }
+ bad:
+ if (v && v != buf)
+ _TIFFfree(v);
+ }
+ return (status);
+}
+#undef NITEMS
+
+/*
+ * Fetch a set of offsets or lengths.
+ * While this routine says "strips", in fact it's also used for tiles.
+ */
+static int
+TIFFFetchStripThing(TIFF* tif, TIFFDirEntry* dir, long nstrips, uint32** lpp)
+{
+ register uint32* lp;
+ int status;
+
+ CheckDirCount(tif, dir, (uint32) nstrips);
+
+ /*
+ * Allocate space for strip information.
+ */
+ if (*lpp == NULL &&
+ (*lpp = (uint32 *)_TIFFCheckMalloc(tif,
+ nstrips, sizeof (uint32), "for strip array")) == NULL)
+ return (0);
+ lp = *lpp;
+ _TIFFmemset( lp, 0, sizeof(uint32) * nstrips );
+
+ if (dir->tdir_type == (int)TIFF_SHORT) {
+ /*
+ * Handle uint16->uint32 expansion.
+ */
+ uint16* dp = (uint16*) _TIFFCheckMalloc(tif,
+ dir->tdir_count, sizeof (uint16), "to fetch strip tag");
+ if (dp == NULL)
+ return (0);
+ if( (status = TIFFFetchShortArray(tif, dir, dp)) != 0 ) {
+ int i;
+
+ for( i = 0; i < nstrips && i < (int) dir->tdir_count; i++ )
+ {
+ lp[i] = dp[i];
+ }
+ }
+ _TIFFfree((char*) dp);
+
+ } else if( nstrips != (int) dir->tdir_count ) {
+ /* Special case to correct length */
+
+ uint32* dp = (uint32*) _TIFFCheckMalloc(tif,
+ dir->tdir_count, sizeof (uint32), "to fetch strip tag");
+ if (dp == NULL)
+ return (0);
+
+ status = TIFFFetchLongArray(tif, dir, dp);
+ if( status != 0 ) {
+ int i;
+
+ for( i = 0; i < nstrips && i < (int) dir->tdir_count; i++ )
+ {
+ lp[i] = dp[i];
+ }
+ }
+
+ _TIFFfree( (char *) dp );
+ } else
+ status = TIFFFetchLongArray(tif, dir, lp);
+
+ return (status);
+}
+
+/*
+ * Fetch and set the RefBlackWhite tag.
+ */
+static int
+TIFFFetchRefBlackWhite(TIFF* tif, TIFFDirEntry* dir)
+{
+ static const char mesg[] = "for \"ReferenceBlackWhite\" array";
+ char* cp;
+ int ok;
+
+ if (dir->tdir_type == TIFF_RATIONAL)
+ return (TIFFFetchNormalTag(tif, dir));
+ /*
+ * Handle LONG's for backward compatibility.
+ */
+ cp = (char *)_TIFFCheckMalloc(tif, dir->tdir_count,
+ sizeof (uint32), mesg);
+ if( (ok = (cp && TIFFFetchLongArray(tif, dir, (uint32*) cp))) != 0) {
+ float* fp = (float*)
+ _TIFFCheckMalloc(tif, dir->tdir_count, sizeof (float), mesg);
+ if( (ok = (fp != NULL)) != 0 ) {
+ uint32 i;
+ for (i = 0; i < dir->tdir_count; i++)
+ fp[i] = (float)((uint32*) cp)[i];
+ ok = TIFFSetField(tif, dir->tdir_tag, fp);
+ _TIFFfree((char*) fp);
+ }
+ }
+ if (cp)
+ _TIFFfree(cp);
+ return (ok);
+}
+
+/*
+ * Fetch and set the SubjectDistance EXIF tag.
+ */
+static int
+TIFFFetchSubjectDistance(TIFF* tif, TIFFDirEntry* dir)
+{
+ uint32 l[2];
+ float v;
+ int ok = 0;
+
+ if( dir->tdir_count != 1 || dir->tdir_type != TIFF_RATIONAL )
+ {
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "incorrect count or type for SubjectDistance, tag ignored" );
+ return (0);
+ }
+
+ if (TIFFFetchData(tif, dir, (char *)l)
+ && cvtRational(tif, dir, l[0], l[1], &v)) {
+ /*
+ * XXX: Numerator 0xFFFFFFFF means that we have infinite
+ * distance. Indicate that with a negative floating point
+ * SubjectDistance value.
+ */
+ ok = TIFFSetField(tif, dir->tdir_tag,
+ (l[0] != 0xFFFFFFFF) ? v : -v);
+ }
+
+ return ok;
+}
+
+/*
+ * Replace a single strip (tile) of uncompressed data by multiple strips
+ * (tiles), each approximately STRIP_SIZE_DEFAULT bytes. This is useful for
+ * dealing with large images or for dealing with machines with a limited
+ * amount memory.
+ */
+static void
+ChopUpSingleUncompressedStrip(TIFF* tif)
+{
+ register TIFFDirectory *td = &tif->tif_dir;
+ uint32 bytecount = td->td_stripbytecount[0];
+ uint32 offset = td->td_stripoffset[0];
+ tsize_t rowbytes = TIFFVTileSize(tif, 1), stripbytes;
+ tstrip_t strip, nstrips, rowsperstrip;
+ uint32* newcounts;
+ uint32* newoffsets;
+
+ /*
+ * Make the rows hold at least one scanline, but fill specified amount
+ * of data if possible.
+ */
+ if (rowbytes > STRIP_SIZE_DEFAULT) {
+ stripbytes = rowbytes;
+ rowsperstrip = 1;
+ } else if (rowbytes > 0 ) {
+ rowsperstrip = STRIP_SIZE_DEFAULT / rowbytes;
+ stripbytes = rowbytes * rowsperstrip;
+ }
+ else
+ return;
+
+ /*
+ * never increase the number of strips in an image
+ */
+ if (rowsperstrip >= td->td_rowsperstrip)
+ return;
+ nstrips = (tstrip_t) TIFFhowmany(bytecount, stripbytes);
+ if( nstrips == 0 ) /* something is wonky, do nothing. */
+ return;
+
+ newcounts = (uint32*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint32),
+ "for chopped \"StripByteCounts\" array");
+ newoffsets = (uint32*) _TIFFCheckMalloc(tif, nstrips, sizeof (uint32),
+ "for chopped \"StripOffsets\" array");
+ if (newcounts == NULL || newoffsets == NULL) {
+ /*
+ * Unable to allocate new strip information, give up and use
+ * the original one strip information.
+ */
+ if (newcounts != NULL)
+ _TIFFfree(newcounts);
+ if (newoffsets != NULL)
+ _TIFFfree(newoffsets);
+ return;
+ }
+ /*
+ * Fill the strip information arrays with new bytecounts and offsets
+ * that reflect the broken-up format.
+ */
+ for (strip = 0; strip < nstrips; strip++) {
+ if ((uint32)stripbytes > bytecount)
+ stripbytes = bytecount;
+ newcounts[strip] = stripbytes;
+ newoffsets[strip] = offset;
+ offset += stripbytes;
+ bytecount -= stripbytes;
+ }
+ /*
+ * Replace old single strip info with multi-strip info.
+ */
+ td->td_stripsperimage = td->td_nstrips = nstrips;
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ _TIFFfree(td->td_stripbytecount);
+ _TIFFfree(td->td_stripoffset);
+ td->td_stripbytecount = newcounts;
+ td->td_stripoffset = newoffsets;
+ td->td_stripbytecountsorted = 1;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_dirwrite.c b/tiff/libtiff/tif_dirwrite.c
new file mode 100644
index 0000000..8d308c4
--- /dev/null
+++ b/tiff/libtiff/tif_dirwrite.c
@@ -0,0 +1,1414 @@
+/* $Id: tif_dirwrite.c,v 1.37.2.7 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Write Support Routines.
+ */
+#include "tiffiop.h"
+
+#ifdef HAVE_IEEEFP
+# define TIFFCvtNativeToIEEEFloat(tif, n, fp)
+# define TIFFCvtNativeToIEEEDouble(tif, n, dp)
+#else
+extern void TIFFCvtNativeToIEEEFloat(TIFF*, uint32, float*);
+extern void TIFFCvtNativeToIEEEDouble(TIFF*, uint32, double*);
+#endif
+
+static int TIFFWriteNormalTag(TIFF*, TIFFDirEntry*, const TIFFFieldInfo*);
+static void TIFFSetupShortLong(TIFF*, ttag_t, TIFFDirEntry*, uint32);
+static void TIFFSetupShort(TIFF*, ttag_t, TIFFDirEntry*, uint16);
+static int TIFFSetupShortPair(TIFF*, ttag_t, TIFFDirEntry*);
+static int TIFFWritePerSampleShorts(TIFF*, ttag_t, TIFFDirEntry*);
+static int TIFFWritePerSampleAnys(TIFF*, TIFFDataType, ttag_t, TIFFDirEntry*);
+static int TIFFWriteShortTable(TIFF*, ttag_t, TIFFDirEntry*, uint32, uint16**);
+static int TIFFWriteShortArray(TIFF*, TIFFDirEntry*, uint16*);
+static int TIFFWriteLongArray(TIFF *, TIFFDirEntry*, uint32*);
+static int TIFFWriteRationalArray(TIFF *, TIFFDirEntry*, float*);
+static int TIFFWriteFloatArray(TIFF *, TIFFDirEntry*, float*);
+static int TIFFWriteDoubleArray(TIFF *, TIFFDirEntry*, double*);
+static int TIFFWriteByteArray(TIFF*, TIFFDirEntry*, char*);
+static int TIFFWriteAnyArray(TIFF*,
+ TIFFDataType, ttag_t, TIFFDirEntry*, uint32, double*);
+static int TIFFWriteTransferFunction(TIFF*, TIFFDirEntry*);
+static int TIFFWriteInkNames(TIFF*, TIFFDirEntry*);
+static int TIFFWriteData(TIFF*, TIFFDirEntry*, char*);
+static int TIFFLinkDirectory(TIFF*);
+
+#define WriteRationalPair(type, tag1, v1, tag2, v2) { \
+ TIFFWriteRational((tif), (type), (tag1), (dir), (v1)) \
+ TIFFWriteRational((tif), (type), (tag2), (dir)+1, (v2)) \
+ (dir)++; \
+}
+#define TIFFWriteRational(tif, type, tag, dir, v) \
+ (dir)->tdir_tag = (tag); \
+ (dir)->tdir_type = (type); \
+ (dir)->tdir_count = 1; \
+ if (!TIFFWriteRationalArray((tif), (dir), &(v))) \
+ goto bad;
+
+/*
+ * Write the contents of the current directory
+ * to the specified file. This routine doesn't
+ * handle overwriting a directory with auxiliary
+ * storage that's been changed.
+ */
+static int
+_TIFFWriteDirectory(TIFF* tif, int done)
+{
+ uint16 dircount;
+ toff_t diroff;
+ ttag_t tag;
+ uint32 nfields;
+ tsize_t dirsize;
+ char* data;
+ TIFFDirEntry* dir;
+ TIFFDirectory* td;
+ unsigned long b, fields[FIELD_SETLONGS];
+ int fi, nfi;
+
+ if (tif->tif_mode == O_RDONLY)
+ return (1);
+ /*
+ * Clear write state so that subsequent images with
+ * different characteristics get the right buffers
+ * setup for them.
+ */
+ if (done)
+ {
+ if (tif->tif_flags & TIFF_POSTENCODE) {
+ tif->tif_flags &= ~TIFF_POSTENCODE;
+ if (!(*tif->tif_postencode)(tif)) {
+ TIFFErrorExt(tif->tif_clientdata,
+ tif->tif_name,
+ "Error post-encoding before directory write");
+ return (0);
+ }
+ }
+ (*tif->tif_close)(tif); /* shutdown encoder */
+ /*
+ * Flush any data that might have been written
+ * by the compression close+cleanup routines.
+ */
+ if (tif->tif_rawcc > 0
+ && (tif->tif_flags & TIFF_BEENWRITING) != 0
+ && !TIFFFlushData1(tif)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error flushing data before directory write");
+ return (0);
+ }
+ if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) {
+ _TIFFfree(tif->tif_rawdata);
+ tif->tif_rawdata = NULL;
+ tif->tif_rawcc = 0;
+ tif->tif_rawdatasize = 0;
+ }
+ tif->tif_flags &= ~(TIFF_BEENWRITING|TIFF_BUFFERSETUP);
+ }
+
+ td = &tif->tif_dir;
+ /*
+ * Size the directory so that we can calculate
+ * offsets for the data items that aren't kept
+ * in-place in each field.
+ */
+ nfields = 0;
+ for (b = 0; b <= FIELD_LAST; b++)
+ if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM)
+ nfields += (b < FIELD_SUBFILETYPE ? 2 : 1);
+ nfields += td->td_customValueCount;
+ dirsize = nfields * sizeof (TIFFDirEntry);
+ data = (char*) _TIFFmalloc(dirsize);
+ if (data == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot write directory, out of space");
+ return (0);
+ }
+ /*
+ * Directory hasn't been placed yet, put
+ * it at the end of the file and link it
+ * into the existing directory structure.
+ */
+ if (tif->tif_diroff == 0 && !TIFFLinkDirectory(tif))
+ goto bad;
+ tif->tif_dataoff = (toff_t)(
+ tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t));
+ if (tif->tif_dataoff & 1)
+ tif->tif_dataoff++;
+ (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
+ tif->tif_curdir++;
+ dir = (TIFFDirEntry*) data;
+ /*
+ * Setup external form of directory
+ * entries and write data items.
+ */
+ _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields));
+ /*
+ * Write out ExtraSamples tag only if
+ * extra samples are present in the data.
+ */
+ if (FieldSet(fields, FIELD_EXTRASAMPLES) && !td->td_extrasamples) {
+ ResetFieldBit(fields, FIELD_EXTRASAMPLES);
+ nfields--;
+ dirsize -= sizeof (TIFFDirEntry);
+ } /*XXX*/
+ for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) {
+ const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi];
+
+ /*
+ * For custom fields, we test to see if the custom field
+ * is set or not. For normal fields, we just use the
+ * FieldSet test.
+ */
+ if( fip->field_bit == FIELD_CUSTOM )
+ {
+ int ci, is_set = FALSE;
+
+ for( ci = 0; ci < td->td_customValueCount; ci++ )
+ is_set |= (td->td_customValues[ci].info == fip);
+
+ if( !is_set )
+ continue;
+ }
+ else if (!FieldSet(fields, fip->field_bit))
+ continue;
+
+ /*
+ * Handle other fields.
+ */
+ switch (fip->field_bit)
+ {
+ case FIELD_STRIPOFFSETS:
+ /*
+ * We use one field bit for both strip and tile
+
+ * offsets, and so must be careful in selecting
+ * the appropriate field descriptor (so that tags
+ * are written in sorted order).
+ */
+ tag = isTiled(tif) ?
+ TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS;
+ if (tag != fip->field_tag)
+ continue;
+
+ dir->tdir_tag = (uint16) tag;
+ dir->tdir_type = (uint16) TIFF_LONG;
+ dir->tdir_count = (uint32) td->td_nstrips;
+ if (!TIFFWriteLongArray(tif, dir, td->td_stripoffset))
+ goto bad;
+ break;
+ case FIELD_STRIPBYTECOUNTS:
+ /*
+ * We use one field bit for both strip and tile
+ * byte counts, and so must be careful in selecting
+ * the appropriate field descriptor (so that tags
+ * are written in sorted order).
+ */
+ tag = isTiled(tif) ?
+ TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS;
+ if (tag != fip->field_tag)
+ continue;
+
+ dir->tdir_tag = (uint16) tag;
+ dir->tdir_type = (uint16) TIFF_LONG;
+ dir->tdir_count = (uint32) td->td_nstrips;
+ if (!TIFFWriteLongArray(tif, dir, td->td_stripbytecount))
+ goto bad;
+ break;
+ case FIELD_ROWSPERSTRIP:
+ TIFFSetupShortLong(tif, TIFFTAG_ROWSPERSTRIP,
+ dir, td->td_rowsperstrip);
+ break;
+ case FIELD_COLORMAP:
+ if (!TIFFWriteShortTable(tif, TIFFTAG_COLORMAP, dir,
+ 3, td->td_colormap))
+ goto bad;
+ break;
+ case FIELD_IMAGEDIMENSIONS:
+ TIFFSetupShortLong(tif, TIFFTAG_IMAGEWIDTH,
+ dir++, td->td_imagewidth);
+ TIFFSetupShortLong(tif, TIFFTAG_IMAGELENGTH,
+ dir, td->td_imagelength);
+ break;
+ case FIELD_TILEDIMENSIONS:
+ TIFFSetupShortLong(tif, TIFFTAG_TILEWIDTH,
+ dir++, td->td_tilewidth);
+ TIFFSetupShortLong(tif, TIFFTAG_TILELENGTH,
+ dir, td->td_tilelength);
+ break;
+ case FIELD_COMPRESSION:
+ TIFFSetupShort(tif, TIFFTAG_COMPRESSION,
+ dir, td->td_compression);
+ break;
+ case FIELD_PHOTOMETRIC:
+ TIFFSetupShort(tif, TIFFTAG_PHOTOMETRIC,
+ dir, td->td_photometric);
+ break;
+ case FIELD_POSITION:
+ WriteRationalPair(TIFF_RATIONAL,
+ TIFFTAG_XPOSITION, td->td_xposition,
+ TIFFTAG_YPOSITION, td->td_yposition);
+ break;
+ case FIELD_RESOLUTION:
+ WriteRationalPair(TIFF_RATIONAL,
+ TIFFTAG_XRESOLUTION, td->td_xresolution,
+ TIFFTAG_YRESOLUTION, td->td_yresolution);
+ break;
+ case FIELD_BITSPERSAMPLE:
+ case FIELD_MINSAMPLEVALUE:
+ case FIELD_MAXSAMPLEVALUE:
+ case FIELD_SAMPLEFORMAT:
+ if (!TIFFWritePerSampleShorts(tif, fip->field_tag, dir))
+ goto bad;
+ break;
+ case FIELD_SMINSAMPLEVALUE:
+ case FIELD_SMAXSAMPLEVALUE:
+ if (!TIFFWritePerSampleAnys(tif,
+ _TIFFSampleToTagType(tif), fip->field_tag, dir))
+ goto bad;
+ break;
+ case FIELD_PAGENUMBER:
+ case FIELD_HALFTONEHINTS:
+ case FIELD_YCBCRSUBSAMPLING:
+ if (!TIFFSetupShortPair(tif, fip->field_tag, dir))
+ goto bad;
+ break;
+ case FIELD_INKNAMES:
+ if (!TIFFWriteInkNames(tif, dir))
+ goto bad;
+ break;
+ case FIELD_TRANSFERFUNCTION:
+ if (!TIFFWriteTransferFunction(tif, dir))
+ goto bad;
+ break;
+ case FIELD_SUBIFD:
+ /*
+ * XXX: Always write this field using LONG type
+ * for backward compatibility.
+ */
+ dir->tdir_tag = (uint16) fip->field_tag;
+ dir->tdir_type = (uint16) TIFF_LONG;
+ dir->tdir_count = (uint32) td->td_nsubifd;
+ if (!TIFFWriteLongArray(tif, dir, td->td_subifd))
+ goto bad;
+ /*
+ * Total hack: if this directory includes a SubIFD
+ * tag then force the next <n> directories to be
+ * written as ``sub directories'' of this one. This
+ * is used to write things like thumbnails and
+ * image masks that one wants to keep out of the
+ * normal directory linkage access mechanism.
+ */
+ if (dir->tdir_count > 0) {
+ tif->tif_flags |= TIFF_INSUBIFD;
+ tif->tif_nsubifd = (uint16) dir->tdir_count;
+ if (dir->tdir_count > 1)
+ tif->tif_subifdoff = dir->tdir_offset;
+ else
+ tif->tif_subifdoff = (uint32)(
+ tif->tif_diroff
+ + sizeof (uint16)
+ + ((char*)&dir->tdir_offset-data));
+ }
+ break;
+ default:
+ /* XXX: Should be fixed and removed. */
+ if (fip->field_tag == TIFFTAG_DOTRANGE) {
+ if (!TIFFSetupShortPair(tif, fip->field_tag, dir))
+ goto bad;
+ }
+ else if (!TIFFWriteNormalTag(tif, dir, fip))
+ goto bad;
+ break;
+ }
+ dir++;
+
+ if( fip->field_bit != FIELD_CUSTOM )
+ ResetFieldBit(fields, fip->field_bit);
+ }
+
+ /*
+ * Write directory.
+ */
+ dircount = (uint16) nfields;
+ diroff = (uint32) tif->tif_nextdiroff;
+ if (tif->tif_flags & TIFF_SWAB) {
+ /*
+ * The file's byte order is opposite to the
+ * native machine architecture. We overwrite
+ * the directory information with impunity
+ * because it'll be released below after we
+ * write it to the file. Note that all the
+ * other tag construction routines assume that
+ * we do this byte-swapping; i.e. they only
+ * byte-swap indirect data.
+ */
+ for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) {
+ TIFFSwabArrayOfShort(&dir->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dir->tdir_count, 2);
+ }
+ dircount = (uint16) nfields;
+ TIFFSwabShort(&dircount);
+ TIFFSwabLong(&diroff);
+ }
+ (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET);
+ if (!WriteOK(tif, &dircount, sizeof (dircount))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error writing directory count");
+ goto bad;
+ }
+ if (!WriteOK(tif, data, dirsize)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error writing directory contents");
+ goto bad;
+ }
+ if (!WriteOK(tif, &diroff, sizeof (uint32))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error writing directory link");
+ goto bad;
+ }
+ if (done) {
+ TIFFFreeDirectory(tif);
+ tif->tif_flags &= ~TIFF_DIRTYDIRECT;
+ (*tif->tif_cleanup)(tif);
+
+ /*
+ * Reset directory-related state for subsequent
+ * directories.
+ */
+ TIFFCreateDirectory(tif);
+ }
+ _TIFFfree(data);
+ return (1);
+bad:
+ _TIFFfree(data);
+ return (0);
+}
+#undef WriteRationalPair
+
+int
+TIFFWriteDirectory(TIFF* tif)
+{
+ return _TIFFWriteDirectory(tif, TRUE);
+}
+
+/*
+ * Similar to TIFFWriteDirectory(), writes the directory out
+ * but leaves all data structures in memory so that it can be
+ * written again. This will make a partially written TIFF file
+ * readable before it is successfully completed/closed.
+ */
+int
+TIFFCheckpointDirectory(TIFF* tif)
+{
+ int rc;
+ /* Setup the strips arrays, if they haven't already been. */
+ if (tif->tif_dir.td_stripoffset == NULL)
+ (void) TIFFSetupStrips(tif);
+ rc = _TIFFWriteDirectory(tif, FALSE);
+ (void) TIFFSetWriteOffset(tif, TIFFSeekFile(tif, 0, SEEK_END));
+ return rc;
+}
+
+static int
+_TIFFWriteCustomDirectory(TIFF* tif, toff_t *pdiroff)
+{
+ uint16 dircount;
+ uint32 nfields;
+ tsize_t dirsize;
+ char* data;
+ TIFFDirEntry* dir;
+ TIFFDirectory* td;
+ unsigned long b, fields[FIELD_SETLONGS];
+ int fi, nfi;
+
+ if (tif->tif_mode == O_RDONLY)
+ return (1);
+
+ td = &tif->tif_dir;
+ /*
+ * Size the directory so that we can calculate
+ * offsets for the data items that aren't kept
+ * in-place in each field.
+ */
+ nfields = 0;
+ for (b = 0; b <= FIELD_LAST; b++)
+ if (TIFFFieldSet(tif, b) && b != FIELD_CUSTOM)
+ nfields += (b < FIELD_SUBFILETYPE ? 2 : 1);
+ nfields += td->td_customValueCount;
+ dirsize = nfields * sizeof (TIFFDirEntry);
+ data = (char*) _TIFFmalloc(dirsize);
+ if (data == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Cannot write directory, out of space");
+ return (0);
+ }
+ /*
+ * Put the directory at the end of the file.
+ */
+ tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
+ tif->tif_dataoff = (toff_t)(
+ tif->tif_diroff + sizeof (uint16) + dirsize + sizeof (toff_t));
+ if (tif->tif_dataoff & 1)
+ tif->tif_dataoff++;
+ (void) TIFFSeekFile(tif, tif->tif_dataoff, SEEK_SET);
+ dir = (TIFFDirEntry*) data;
+ /*
+ * Setup external form of directory
+ * entries and write data items.
+ */
+ _TIFFmemcpy(fields, td->td_fieldsset, sizeof (fields));
+
+ for (fi = 0, nfi = tif->tif_nfields; nfi > 0; nfi--, fi++) {
+ const TIFFFieldInfo* fip = tif->tif_fieldinfo[fi];
+
+ /*
+ * For custom fields, we test to see if the custom field
+ * is set or not. For normal fields, we just use the
+ * FieldSet test.
+ */
+ if( fip->field_bit == FIELD_CUSTOM )
+ {
+ int ci, is_set = FALSE;
+
+ for( ci = 0; ci < td->td_customValueCount; ci++ )
+ is_set |= (td->td_customValues[ci].info == fip);
+
+ if( !is_set )
+ continue;
+ }
+ else if (!FieldSet(fields, fip->field_bit))
+ continue;
+
+ if( fip->field_bit != FIELD_CUSTOM )
+ ResetFieldBit(fields, fip->field_bit);
+ }
+
+ /*
+ * Write directory.
+ */
+ dircount = (uint16) nfields;
+ *pdiroff = (uint32) tif->tif_nextdiroff;
+ if (tif->tif_flags & TIFF_SWAB) {
+ /*
+ * The file's byte order is opposite to the
+ * native machine architecture. We overwrite
+ * the directory information with impunity
+ * because it'll be released below after we
+ * write it to the file. Note that all the
+ * other tag construction routines assume that
+ * we do this byte-swapping; i.e. they only
+ * byte-swap indirect data.
+ */
+ for (dir = (TIFFDirEntry*) data; dircount; dir++, dircount--) {
+ TIFFSwabArrayOfShort(&dir->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dir->tdir_count, 2);
+ }
+ dircount = (uint16) nfields;
+ TIFFSwabShort(&dircount);
+ TIFFSwabLong(pdiroff);
+ }
+ (void) TIFFSeekFile(tif, tif->tif_diroff, SEEK_SET);
+ if (!WriteOK(tif, &dircount, sizeof (dircount))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error writing directory count");
+ goto bad;
+ }
+ if (!WriteOK(tif, data, dirsize)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error writing directory contents");
+ goto bad;
+ }
+ if (!WriteOK(tif, pdiroff, sizeof (uint32))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error writing directory link");
+ goto bad;
+ }
+ _TIFFfree(data);
+ return (1);
+bad:
+ _TIFFfree(data);
+ return (0);
+}
+
+int
+TIFFWriteCustomDirectory(TIFF* tif, toff_t *pdiroff)
+{
+ return _TIFFWriteCustomDirectory(tif, pdiroff);
+}
+
+/*
+ * Process tags that are not special cased.
+ */
+static int
+TIFFWriteNormalTag(TIFF* tif, TIFFDirEntry* dir, const TIFFFieldInfo* fip)
+{
+ uint16 wc = (uint16) fip->field_writecount;
+ uint32 wc2;
+
+ dir->tdir_tag = (uint16) fip->field_tag;
+ dir->tdir_type = (uint16) fip->field_type;
+ dir->tdir_count = wc;
+
+ switch (fip->field_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ if (fip->field_passcount) {
+ uint16* wp;
+ if (wc == (uint16) TIFF_VARIABLE2) {
+ TIFFGetField(tif, fip->field_tag, &wc2, &wp);
+ dir->tdir_count = wc2;
+ } else { /* Assume TIFF_VARIABLE */
+ TIFFGetField(tif, fip->field_tag, &wc, &wp);
+ dir->tdir_count = wc;
+ }
+ if (!TIFFWriteShortArray(tif, dir, wp))
+ return 0;
+ } else {
+ if (wc == 1) {
+ uint16 sv;
+ TIFFGetField(tif, fip->field_tag, &sv);
+ dir->tdir_offset =
+ TIFFInsertData(tif, dir->tdir_type, sv);
+ } else {
+ uint16* wp;
+ TIFFGetField(tif, fip->field_tag, &wp);
+ if (!TIFFWriteShortArray(tif, dir, wp))
+ return 0;
+ }
+ }
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_IFD:
+ if (fip->field_passcount) {
+ uint32* lp;
+ if (wc == (uint16) TIFF_VARIABLE2) {
+ TIFFGetField(tif, fip->field_tag, &wc2, &lp);
+ dir->tdir_count = wc2;
+ } else { /* Assume TIFF_VARIABLE */
+ TIFFGetField(tif, fip->field_tag, &wc, &lp);
+ dir->tdir_count = wc;
+ }
+ if (!TIFFWriteLongArray(tif, dir, lp))
+ return 0;
+ } else {
+ if (wc == 1) {
+ /* XXX handle LONG->SHORT conversion */
+ TIFFGetField(tif, fip->field_tag,
+ &dir->tdir_offset);
+ } else {
+ uint32* lp;
+ TIFFGetField(tif, fip->field_tag, &lp);
+ if (!TIFFWriteLongArray(tif, dir, lp))
+ return 0;
+ }
+ }
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ if (fip->field_passcount) {
+ float* fp;
+ if (wc == (uint16) TIFF_VARIABLE2) {
+ TIFFGetField(tif, fip->field_tag, &wc2, &fp);
+ dir->tdir_count = wc2;
+ } else { /* Assume TIFF_VARIABLE */
+ TIFFGetField(tif, fip->field_tag, &wc, &fp);
+ dir->tdir_count = wc;
+ }
+ if (!TIFFWriteRationalArray(tif, dir, fp))
+ return 0;
+ } else {
+ if (wc == 1) {
+ float fv;
+ TIFFGetField(tif, fip->field_tag, &fv);
+ if (!TIFFWriteRationalArray(tif, dir, &fv))
+ return 0;
+ } else {
+ float* fp;
+ TIFFGetField(tif, fip->field_tag, &fp);
+ if (!TIFFWriteRationalArray(tif, dir, fp))
+ return 0;
+ }
+ }
+ break;
+ case TIFF_FLOAT:
+ if (fip->field_passcount) {
+ float* fp;
+ if (wc == (uint16) TIFF_VARIABLE2) {
+ TIFFGetField(tif, fip->field_tag, &wc2, &fp);
+ dir->tdir_count = wc2;
+ } else { /* Assume TIFF_VARIABLE */
+ TIFFGetField(tif, fip->field_tag, &wc, &fp);
+ dir->tdir_count = wc;
+ }
+ if (!TIFFWriteFloatArray(tif, dir, fp))
+ return 0;
+ } else {
+ if (wc == 1) {
+ float fv;
+ TIFFGetField(tif, fip->field_tag, &fv);
+ if (!TIFFWriteFloatArray(tif, dir, &fv))
+ return 0;
+ } else {
+ float* fp;
+ TIFFGetField(tif, fip->field_tag, &fp);
+ if (!TIFFWriteFloatArray(tif, dir, fp))
+ return 0;
+ }
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (fip->field_passcount) {
+ double* dp;
+ if (wc == (uint16) TIFF_VARIABLE2) {
+ TIFFGetField(tif, fip->field_tag, &wc2, &dp);
+ dir->tdir_count = wc2;
+ } else { /* Assume TIFF_VARIABLE */
+ TIFFGetField(tif, fip->field_tag, &wc, &dp);
+ dir->tdir_count = wc;
+ }
+ if (!TIFFWriteDoubleArray(tif, dir, dp))
+ return 0;
+ } else {
+ if (wc == 1) {
+ double dv;
+ TIFFGetField(tif, fip->field_tag, &dv);
+ if (!TIFFWriteDoubleArray(tif, dir, &dv))
+ return 0;
+ } else {
+ double* dp;
+ TIFFGetField(tif, fip->field_tag, &dp);
+ if (!TIFFWriteDoubleArray(tif, dir, dp))
+ return 0;
+ }
+ }
+ break;
+ case TIFF_ASCII:
+ {
+ char* cp;
+ if (fip->field_passcount)
+ {
+ if( wc == (uint16) TIFF_VARIABLE2 )
+ TIFFGetField(tif, fip->field_tag, &wc2, &cp);
+ else
+ TIFFGetField(tif, fip->field_tag, &wc, &cp);
+ }
+ else
+ TIFFGetField(tif, fip->field_tag, &cp);
+
+ dir->tdir_count = (uint32) (strlen(cp) + 1);
+ if (!TIFFWriteByteArray(tif, dir, cp))
+ return (0);
+ }
+ break;
+
+ case TIFF_BYTE:
+ case TIFF_SBYTE:
+ if (fip->field_passcount) {
+ char* cp;
+ if (wc == (uint16) TIFF_VARIABLE2) {
+ TIFFGetField(tif, fip->field_tag, &wc2, &cp);
+ dir->tdir_count = wc2;
+ } else { /* Assume TIFF_VARIABLE */
+ TIFFGetField(tif, fip->field_tag, &wc, &cp);
+ dir->tdir_count = wc;
+ }
+ if (!TIFFWriteByteArray(tif, dir, cp))
+ return 0;
+ } else {
+ if (wc == 1) {
+ char cv;
+ TIFFGetField(tif, fip->field_tag, &cv);
+ if (!TIFFWriteByteArray(tif, dir, &cv))
+ return 0;
+ } else {
+ char* cp;
+ TIFFGetField(tif, fip->field_tag, &cp);
+ if (!TIFFWriteByteArray(tif, dir, cp))
+ return 0;
+ }
+ }
+ break;
+
+ case TIFF_UNDEFINED:
+ { char* cp;
+ if (wc == (unsigned short) TIFF_VARIABLE) {
+ TIFFGetField(tif, fip->field_tag, &wc, &cp);
+ dir->tdir_count = wc;
+ } else if (wc == (unsigned short) TIFF_VARIABLE2) {
+ TIFFGetField(tif, fip->field_tag, &wc2, &cp);
+ dir->tdir_count = wc2;
+ } else
+ TIFFGetField(tif, fip->field_tag, &cp);
+ if (!TIFFWriteByteArray(tif, dir, cp))
+ return (0);
+ }
+ break;
+
+ case TIFF_NOTYPE:
+ break;
+ }
+ return (1);
+}
+
+/*
+ * Setup a directory entry with either a SHORT
+ * or LONG type according to the value.
+ */
+static void
+TIFFSetupShortLong(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint32 v)
+{
+ dir->tdir_tag = (uint16) tag;
+ dir->tdir_count = 1;
+ if (v > 0xffffL) {
+ dir->tdir_type = (short) TIFF_LONG;
+ dir->tdir_offset = v;
+ } else {
+ dir->tdir_type = (short) TIFF_SHORT;
+ dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v);
+ }
+}
+
+/*
+ * Setup a SHORT directory entry
+ */
+static void
+TIFFSetupShort(TIFF* tif, ttag_t tag, TIFFDirEntry* dir, uint16 v)
+{
+ dir->tdir_tag = (uint16) tag;
+ dir->tdir_count = 1;
+ dir->tdir_type = (short) TIFF_SHORT;
+ dir->tdir_offset = TIFFInsertData(tif, (int) TIFF_SHORT, v);
+}
+#undef MakeShortDirent
+
+#define NITEMS(x) (sizeof (x) / sizeof (x[0]))
+/*
+ * Setup a directory entry that references a
+ * samples/pixel array of SHORT values and
+ * (potentially) write the associated indirect
+ * values.
+ */
+static int
+TIFFWritePerSampleShorts(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
+{
+ uint16 buf[10], v;
+ uint16* w = buf;
+ uint16 i, samples = tif->tif_dir.td_samplesperpixel;
+ int status;
+
+ if (samples > NITEMS(buf)) {
+ w = (uint16*) _TIFFmalloc(samples * sizeof (uint16));
+ if (w == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "No space to write per-sample shorts");
+ return (0);
+ }
+ }
+ TIFFGetField(tif, tag, &v);
+ for (i = 0; i < samples; i++)
+ w[i] = v;
+
+ dir->tdir_tag = (uint16) tag;
+ dir->tdir_type = (uint16) TIFF_SHORT;
+ dir->tdir_count = samples;
+ status = TIFFWriteShortArray(tif, dir, w);
+ if (w != buf)
+ _TIFFfree((char*) w);
+ return (status);
+}
+
+/*
+ * Setup a directory entry that references a samples/pixel array of ``type''
+ * values and (potentially) write the associated indirect values. The source
+ * data from TIFFGetField() for the specified tag must be returned as double.
+ */
+static int
+TIFFWritePerSampleAnys(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir)
+{
+ double buf[10], v;
+ double* w = buf;
+ uint16 i, samples = tif->tif_dir.td_samplesperpixel;
+ int status;
+
+ if (samples > NITEMS(buf)) {
+ w = (double*) _TIFFmalloc(samples * sizeof (double));
+ if (w == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "No space to write per-sample values");
+ return (0);
+ }
+ }
+ TIFFGetField(tif, tag, &v);
+ for (i = 0; i < samples; i++)
+ w[i] = v;
+ status = TIFFWriteAnyArray(tif, type, tag, dir, samples, w);
+ if (w != buf)
+ _TIFFfree(w);
+ return (status);
+}
+#undef NITEMS
+
+/*
+ * Setup a pair of shorts that are returned by
+ * value, rather than as a reference to an array.
+ */
+static int
+TIFFSetupShortPair(TIFF* tif, ttag_t tag, TIFFDirEntry* dir)
+{
+ uint16 v[2];
+
+ TIFFGetField(tif, tag, &v[0], &v[1]);
+
+ dir->tdir_tag = (uint16) tag;
+ dir->tdir_type = (uint16) TIFF_SHORT;
+ dir->tdir_count = 2;
+ return (TIFFWriteShortArray(tif, dir, v));
+}
+
+/*
+ * Setup a directory entry for an NxM table of shorts,
+ * where M is known to be 2**bitspersample, and write
+ * the associated indirect data.
+ */
+static int
+TIFFWriteShortTable(TIFF* tif,
+ ttag_t tag, TIFFDirEntry* dir, uint32 n, uint16** table)
+{
+ uint32 i, off;
+
+ dir->tdir_tag = (uint16) tag;
+ dir->tdir_type = (short) TIFF_SHORT;
+ /* XXX -- yech, fool TIFFWriteData */
+ dir->tdir_count = (uint32) (1L<<tif->tif_dir.td_bitspersample);
+ off = tif->tif_dataoff;
+ for (i = 0; i < n; i++)
+ if (!TIFFWriteData(tif, dir, (char *)table[i]))
+ return (0);
+ dir->tdir_count *= n;
+ dir->tdir_offset = off;
+ return (1);
+}
+
+/*
+ * Write/copy data associated with an ASCII or opaque tag value.
+ */
+static int
+TIFFWriteByteArray(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ if (dir->tdir_count <= 4) {
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ dir->tdir_offset = (uint32)cp[0] << 24;
+ if (dir->tdir_count >= 2)
+ dir->tdir_offset |= (uint32)cp[1] << 16;
+ if (dir->tdir_count >= 3)
+ dir->tdir_offset |= (uint32)cp[2] << 8;
+ if (dir->tdir_count == 4)
+ dir->tdir_offset |= cp[3];
+ } else {
+ dir->tdir_offset = cp[0];
+ if (dir->tdir_count >= 2)
+ dir->tdir_offset |= (uint32) cp[1] << 8;
+ if (dir->tdir_count >= 3)
+ dir->tdir_offset |= (uint32) cp[2] << 16;
+ if (dir->tdir_count == 4)
+ dir->tdir_offset |= (uint32) cp[3] << 24;
+ }
+ return 1;
+ } else
+ return TIFFWriteData(tif, dir, cp);
+}
+
+/*
+ * Setup a directory entry of an array of SHORT
+ * or SSHORT and write the associated indirect values.
+ */
+static int
+TIFFWriteShortArray(TIFF* tif, TIFFDirEntry* dir, uint16* v)
+{
+ if (dir->tdir_count <= 2) {
+ if (tif->tif_header.tiff_magic == TIFF_BIGENDIAN) {
+ dir->tdir_offset = (uint32) v[0] << 16;
+ if (dir->tdir_count == 2)
+ dir->tdir_offset |= v[1] & 0xffff;
+ } else {
+ dir->tdir_offset = v[0] & 0xffff;
+ if (dir->tdir_count == 2)
+ dir->tdir_offset |= (uint32) v[1] << 16;
+ }
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Setup a directory entry of an array of LONG
+ * or SLONG and write the associated indirect values.
+ */
+static int
+TIFFWriteLongArray(TIFF* tif, TIFFDirEntry* dir, uint32* v)
+{
+ if (dir->tdir_count == 1) {
+ dir->tdir_offset = v[0];
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Setup a directory entry of an array of RATIONAL
+ * or SRATIONAL and write the associated indirect values.
+ */
+static int
+TIFFWriteRationalArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+ uint32 i;
+ uint32* t;
+ int status;
+
+ t = (uint32*) _TIFFmalloc(2 * dir->tdir_count * sizeof (uint32));
+ if (t == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "No space to write RATIONAL array");
+ return (0);
+ }
+ for (i = 0; i < dir->tdir_count; i++) {
+ float fv = v[i];
+ int sign = 1;
+ uint32 den;
+
+ if (fv < 0) {
+ if (dir->tdir_type == TIFF_RATIONAL) {
+ TIFFWarningExt(tif->tif_clientdata,
+ tif->tif_name,
+ "\"%s\": Information lost writing value (%g) as (unsigned) RATIONAL",
+ _TIFFFieldWithTag(tif,dir->tdir_tag)->field_name,
+ fv);
+ fv = 0;
+ } else
+ fv = -fv, sign = -1;
+ }
+ den = 1L;
+ if (fv > 0) {
+ while (fv < 1L<<(31-3) && den < 1L<<(31-3))
+ fv *= 1<<3, den *= 1L<<3;
+ }
+ t[2*i+0] = (uint32) (sign * (fv + 0.5));
+ t[2*i+1] = den;
+ }
+ status = TIFFWriteData(tif, dir, (char *)t);
+ _TIFFfree((char*) t);
+ return (status);
+}
+
+static int
+TIFFWriteFloatArray(TIFF* tif, TIFFDirEntry* dir, float* v)
+{
+ TIFFCvtNativeToIEEEFloat(tif, dir->tdir_count, v);
+ if (dir->tdir_count == 1) {
+ dir->tdir_offset = *(uint32*) &v[0];
+ return (1);
+ } else
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+static int
+TIFFWriteDoubleArray(TIFF* tif, TIFFDirEntry* dir, double* v)
+{
+ TIFFCvtNativeToIEEEDouble(tif, dir->tdir_count, v);
+ return (TIFFWriteData(tif, dir, (char*) v));
+}
+
+/*
+ * Write an array of ``type'' values for a specified tag (i.e. this is a tag
+ * which is allowed to have different types, e.g. SMaxSampleType).
+ * Internally the data values are represented as double since a double can
+ * hold any of the TIFF tag types (yes, this should really be an abstract
+ * type tany_t for portability). The data is converted into the specified
+ * type in a temporary buffer and then handed off to the appropriate array
+ * writer.
+ */
+static int
+TIFFWriteAnyArray(TIFF* tif,
+ TIFFDataType type, ttag_t tag, TIFFDirEntry* dir, uint32 n, double* v)
+{
+ char buf[10 * sizeof(double)];
+ char* w = buf;
+ int i, status = 0;
+
+ if (n * TIFFDataWidth(type) > sizeof buf) {
+ w = (char*) _TIFFmalloc(n * TIFFDataWidth(type));
+ if (w == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "No space to write array");
+ return (0);
+ }
+ }
+
+ dir->tdir_tag = (uint16) tag;
+ dir->tdir_type = (uint16) type;
+ dir->tdir_count = n;
+
+ switch (type) {
+ case TIFF_BYTE:
+ {
+ uint8* bp = (uint8*) w;
+ for (i = 0; i < (int) n; i++)
+ bp[i] = (uint8) v[i];
+ if (!TIFFWriteByteArray(tif, dir, (char*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_SBYTE:
+ {
+ int8* bp = (int8*) w;
+ for (i = 0; i < (int) n; i++)
+ bp[i] = (int8) v[i];
+ if (!TIFFWriteByteArray(tif, dir, (char*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_SHORT:
+ {
+ uint16* bp = (uint16*) w;
+ for (i = 0; i < (int) n; i++)
+ bp[i] = (uint16) v[i];
+ if (!TIFFWriteShortArray(tif, dir, (uint16*)bp))
+ goto out;
+ }
+ break;
+ case TIFF_SSHORT:
+ {
+ int16* bp = (int16*) w;
+ for (i = 0; i < (int) n; i++)
+ bp[i] = (int16) v[i];
+ if (!TIFFWriteShortArray(tif, dir, (uint16*)bp))
+ goto out;
+ }
+ break;
+ case TIFF_LONG:
+ {
+ uint32* bp = (uint32*) w;
+ for (i = 0; i < (int) n; i++)
+ bp[i] = (uint32) v[i];
+ if (!TIFFWriteLongArray(tif, dir, bp))
+ goto out;
+ }
+ break;
+ case TIFF_SLONG:
+ {
+ int32* bp = (int32*) w;
+ for (i = 0; i < (int) n; i++)
+ bp[i] = (int32) v[i];
+ if (!TIFFWriteLongArray(tif, dir, (uint32*) bp))
+ goto out;
+ }
+ break;
+ case TIFF_FLOAT:
+ {
+ float* bp = (float*) w;
+ for (i = 0; i < (int) n; i++)
+ bp[i] = (float) v[i];
+ if (!TIFFWriteFloatArray(tif, dir, bp))
+ goto out;
+ }
+ break;
+ case TIFF_DOUBLE:
+ {
+ if( !TIFFWriteDoubleArray(tif, dir, v))
+ goto out;
+ }
+ break;
+ default:
+ /* TIFF_NOTYPE */
+ /* TIFF_ASCII */
+ /* TIFF_UNDEFINED */
+ /* TIFF_RATIONAL */
+ /* TIFF_SRATIONAL */
+ goto out;
+ }
+ status = 1;
+ out:
+ if (w != buf)
+ _TIFFfree(w);
+ return (status);
+}
+
+static int
+TIFFWriteTransferFunction(TIFF* tif, TIFFDirEntry* dir)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ tsize_t n = (1L<<td->td_bitspersample) * sizeof (uint16);
+ uint16** tf = td->td_transferfunction;
+ int ncols;
+
+ /*
+ * Check if the table can be written as a single column,
+ * or if it must be written as 3 columns. Note that we
+ * write a 3-column tag if there are 2 samples/pixel and
+ * a single column of data won't suffice--hmm.
+ */
+ switch (td->td_samplesperpixel - td->td_extrasamples) {
+ default: if (_TIFFmemcmp(tf[0], tf[2], n)) { ncols = 3; break; }
+ case 2: if (_TIFFmemcmp(tf[0], tf[1], n)) { ncols = 3; break; }
+ case 1: case 0: ncols = 1;
+ }
+ return (TIFFWriteShortTable(tif,
+ TIFFTAG_TRANSFERFUNCTION, dir, ncols, tf));
+}
+
+static int
+TIFFWriteInkNames(TIFF* tif, TIFFDirEntry* dir)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+
+ dir->tdir_tag = TIFFTAG_INKNAMES;
+ dir->tdir_type = (short) TIFF_ASCII;
+ dir->tdir_count = td->td_inknameslen;
+ return (TIFFWriteByteArray(tif, dir, td->td_inknames));
+}
+
+/*
+ * Write a contiguous directory item.
+ */
+static int
+TIFFWriteData(TIFF* tif, TIFFDirEntry* dir, char* cp)
+{
+ tsize_t cc;
+
+ if (tif->tif_flags & TIFF_SWAB) {
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*) cp, dir->tdir_count);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ TIFFSwabArrayOfLong((uint32*) cp, dir->tdir_count);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ TIFFSwabArrayOfLong((uint32*) cp, 2*dir->tdir_count);
+ break;
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*) cp, dir->tdir_count);
+ break;
+ }
+ }
+ dir->tdir_offset = tif->tif_dataoff;
+ cc = dir->tdir_count * TIFFDataWidth((TIFFDataType) dir->tdir_type);
+ if (SeekOK(tif, dir->tdir_offset) &&
+ WriteOK(tif, cp, cc)) {
+ tif->tif_dataoff += (cc + 1) & ~1;
+ return (1);
+ }
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error writing data for field \"%s\"",
+ _TIFFFieldWithTag(tif, dir->tdir_tag)->field_name);
+ return (0);
+}
+
+/*
+ * Similar to TIFFWriteDirectory(), but if the directory has already
+ * been written once, it is relocated to the end of the file, in case it
+ * has changed in size. Note that this will result in the loss of the
+ * previously used directory space.
+ */
+
+int
+TIFFRewriteDirectory( TIFF *tif )
+{
+ static const char module[] = "TIFFRewriteDirectory";
+
+ /* We don't need to do anything special if it hasn't been written. */
+ if( tif->tif_diroff == 0 )
+ return TIFFWriteDirectory( tif );
+
+ /*
+ ** Find and zero the pointer to this directory, so that TIFFLinkDirectory
+ ** will cause it to be added after this directories current pre-link.
+ */
+
+ /* Is it the first directory in the file? */
+ if (tif->tif_header.tiff_diroff == tif->tif_diroff)
+ {
+ tif->tif_header.tiff_diroff = 0;
+ tif->tif_diroff = 0;
+
+ TIFFSeekFile(tif, (toff_t)(TIFF_MAGIC_SIZE+TIFF_VERSION_SIZE),
+ SEEK_SET);
+ if (!WriteOK(tif, &(tif->tif_header.tiff_diroff),
+ sizeof (tif->tif_diroff)))
+ {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error updating TIFF header");
+ return (0);
+ }
+ }
+ else
+ {
+ toff_t nextdir, off;
+
+ nextdir = tif->tif_header.tiff_diroff;
+ do {
+ uint16 dircount;
+
+ if (!SeekOK(tif, nextdir) ||
+ !ReadOK(tif, &dircount, sizeof (dircount))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error fetching directory count");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ (void) TIFFSeekFile(tif,
+ dircount * sizeof (TIFFDirEntry), SEEK_CUR);
+ if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error fetching directory link");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&nextdir);
+ } while (nextdir != tif->tif_diroff && nextdir != 0);
+ off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */
+ (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET);
+ tif->tif_diroff = 0;
+ if (!WriteOK(tif, &(tif->tif_diroff), sizeof (nextdir))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error writing directory link");
+ return (0);
+ }
+ }
+
+ /*
+ ** Now use TIFFWriteDirectory() normally.
+ */
+
+ return TIFFWriteDirectory( tif );
+}
+
+
+/*
+ * Link the current directory into the directory chain for the file.
+ */
+static int
+TIFFLinkDirectory(TIFF* tif)
+{
+ static const char module[] = "TIFFLinkDirectory";
+ toff_t nextdir;
+ toff_t diroff, off;
+
+ tif->tif_diroff = (TIFFSeekFile(tif, (toff_t) 0, SEEK_END)+1) &~ 1;
+ diroff = tif->tif_diroff;
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&diroff);
+
+ /*
+ * Handle SubIFDs
+ */
+ if (tif->tif_flags & TIFF_INSUBIFD) {
+ (void) TIFFSeekFile(tif, tif->tif_subifdoff, SEEK_SET);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Error writing SubIFD directory link",
+ tif->tif_name);
+ return (0);
+ }
+ /*
+ * Advance to the next SubIFD or, if this is
+ * the last one configured, revert back to the
+ * normal directory linkage.
+ */
+ if (--tif->tif_nsubifd)
+ tif->tif_subifdoff += sizeof (diroff);
+ else
+ tif->tif_flags &= ~TIFF_INSUBIFD;
+ return (1);
+ }
+
+ if (tif->tif_header.tiff_diroff == 0) {
+ /*
+ * First directory, overwrite offset in header.
+ */
+ tif->tif_header.tiff_diroff = tif->tif_diroff;
+ (void) TIFFSeekFile(tif,
+ (toff_t)(TIFF_MAGIC_SIZE+TIFF_VERSION_SIZE),
+ SEEK_SET);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Error writing TIFF header");
+ return (0);
+ }
+ return (1);
+ }
+ /*
+ * Not the first directory, search to the last and append.
+ */
+ nextdir = tif->tif_header.tiff_diroff;
+ do {
+ uint16 dircount;
+
+ if (!SeekOK(tif, nextdir) ||
+ !ReadOK(tif, &dircount, sizeof (dircount))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error fetching directory count");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&dircount);
+ (void) TIFFSeekFile(tif,
+ dircount * sizeof (TIFFDirEntry), SEEK_CUR);
+ if (!ReadOK(tif, &nextdir, sizeof (nextdir))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error fetching directory link");
+ return (0);
+ }
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabLong(&nextdir);
+ } while (nextdir != 0);
+ off = TIFFSeekFile(tif, 0, SEEK_CUR); /* get current offset */
+ (void) TIFFSeekFile(tif, off - (toff_t)sizeof(nextdir), SEEK_SET);
+ if (!WriteOK(tif, &diroff, sizeof (diroff))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error writing directory link");
+ return (0);
+ }
+ return (1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_dumpmode.c b/tiff/libtiff/tif_dumpmode.c
new file mode 100644
index 0000000..da86150
--- /dev/null
+++ b/tiff/libtiff/tif_dumpmode.c
@@ -0,0 +1,126 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_dumpmode.c,v 1.5.2.2 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * "Null" Compression Algorithm Support.
+ */
+#include "tiffiop.h"
+
+/*
+ * Encode a hunk of pixels.
+ */
+static int
+DumpModeEncode(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s)
+{
+ (void) s;
+ while (cc > 0) {
+ tsize_t n;
+
+ n = cc;
+ if (tif->tif_rawcc + n > tif->tif_rawdatasize)
+ n = tif->tif_rawdatasize - tif->tif_rawcc;
+
+ assert( n > 0 );
+
+ /*
+ * Avoid copy if client has setup raw
+ * data buffer to avoid extra copy.
+ */
+ if (tif->tif_rawcp != pp)
+ _TIFFmemcpy(tif->tif_rawcp, pp, n);
+ tif->tif_rawcp += n;
+ tif->tif_rawcc += n;
+ pp += n;
+ cc -= n;
+ if (tif->tif_rawcc >= tif->tif_rawdatasize &&
+ !TIFFFlushData1(tif))
+ return (-1);
+ }
+ return (1);
+}
+
+/*
+ * Decode a hunk of pixels.
+ */
+static int
+DumpModeDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
+{
+ (void) s;
+/* fprintf(stderr,"DumpModeDecode: scanline %ld, expected %ld bytes, got %ld bytes\n", */
+/* (long) tif->tif_row, (long) tif->tif_rawcc, (long) cc); */
+ if (tif->tif_rawcc < cc) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "DumpModeDecode: Not enough data for scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+ /*
+ * Avoid copy if client has setup raw
+ * data buffer to avoid extra copy.
+ */
+ if (tif->tif_rawcp != buf)
+ _TIFFmemcpy(buf, tif->tif_rawcp, cc);
+ tif->tif_rawcp += cc;
+ tif->tif_rawcc -= cc;
+ return (1);
+}
+
+/*
+ * Seek forwards nrows in the current strip.
+ */
+static int
+DumpModeSeek(TIFF* tif, uint32 nrows)
+{
+ tif->tif_rawcp += nrows * tif->tif_scanlinesize;
+ tif->tif_rawcc -= nrows * tif->tif_scanlinesize;
+ return (1);
+}
+
+/*
+ * Initialize dump mode.
+ */
+int
+TIFFInitDumpMode(TIFF* tif, int scheme)
+{
+ (void) scheme;
+ tif->tif_decoderow = DumpModeDecode;
+ tif->tif_decodestrip = DumpModeDecode;
+ tif->tif_decodetile = DumpModeDecode;
+ tif->tif_encoderow = DumpModeEncode;
+ tif->tif_encodestrip = DumpModeEncode;
+ tif->tif_encodetile = DumpModeEncode;
+ tif->tif_seek = DumpModeSeek;
+ return (1);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_error.c b/tiff/libtiff/tif_error.c
new file mode 100644
index 0000000..2377abd
--- /dev/null
+++ b/tiff/libtiff/tif_error.c
@@ -0,0 +1,80 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_error.c,v 1.4.2.1 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+TIFFErrorHandlerExt _TIFFerrorHandlerExt = NULL;
+
+TIFFErrorHandler
+TIFFSetErrorHandler(TIFFErrorHandler handler)
+{
+ TIFFErrorHandler prev = _TIFFerrorHandler;
+ _TIFFerrorHandler = handler;
+ return (prev);
+}
+
+TIFFErrorHandlerExt
+TIFFSetErrorHandlerExt(TIFFErrorHandlerExt handler)
+{
+ TIFFErrorHandlerExt prev = _TIFFerrorHandlerExt;
+ _TIFFerrorHandlerExt = handler;
+ return (prev);
+}
+
+void
+TIFFError(const char* module, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ if (_TIFFerrorHandler)
+ (*_TIFFerrorHandler)(module, fmt, ap);
+ if (_TIFFerrorHandlerExt)
+ (*_TIFFerrorHandlerExt)(0, module, fmt, ap);
+ va_end(ap);
+}
+
+void
+TIFFErrorExt(thandle_t fd, const char* module, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ if (_TIFFerrorHandler)
+ (*_TIFFerrorHandler)(module, fmt, ap);
+ if (_TIFFerrorHandlerExt)
+ (*_TIFFerrorHandlerExt)(fd, module, fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_extension.c b/tiff/libtiff/tif_extension.c
new file mode 100644
index 0000000..b67c0f0
--- /dev/null
+++ b/tiff/libtiff/tif_extension.c
@@ -0,0 +1,118 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_extension.c,v 1.4.2.1 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Various routines support external extension of the tag set, and other
+ * application extension capabilities.
+ */
+
+#include "tiffiop.h"
+
+int TIFFGetTagListCount( TIFF *tif )
+
+{
+ TIFFDirectory* td = &tif->tif_dir;
+
+ return td->td_customValueCount;
+}
+
+ttag_t TIFFGetTagListEntry( TIFF *tif, int tag_index )
+
+{
+ TIFFDirectory* td = &tif->tif_dir;
+
+ if( tag_index < 0 || tag_index >= td->td_customValueCount )
+ return (ttag_t) -1;
+ else
+ return td->td_customValues[tag_index].info->field_tag;
+}
+
+/*
+** This provides read/write access to the TIFFTagMethods within the TIFF
+** structure to application code without giving access to the private
+** TIFF structure.
+*/
+TIFFTagMethods *TIFFAccessTagMethods( TIFF *tif )
+
+{
+ return &(tif->tif_tagmethods);
+}
+
+void *TIFFGetClientInfo( TIFF *tif, const char *name )
+
+{
+ TIFFClientInfoLink *link = tif->tif_clientinfo;
+
+ while( link != NULL && strcmp(link->name,name) != 0 )
+ link = link->next;
+
+ if( link != NULL )
+ return link->data;
+ else
+ return NULL;
+}
+
+void TIFFSetClientInfo( TIFF *tif, void *data, const char *name )
+
+{
+ TIFFClientInfoLink *link = tif->tif_clientinfo;
+
+ /*
+ ** Do we have an existing link with this name? If so, just
+ ** set it.
+ */
+ while( link != NULL && strcmp(link->name,name) != 0 )
+ link = link->next;
+
+ if( link != NULL )
+ {
+ link->data = data;
+ return;
+ }
+
+ /*
+ ** Create a new link.
+ */
+
+ link = (TIFFClientInfoLink *) _TIFFmalloc(sizeof(TIFFClientInfoLink));
+ assert (link != NULL);
+ link->next = tif->tif_clientinfo;
+ link->name = (char *) _TIFFmalloc(strlen(name)+1);
+ assert (link->name != NULL);
+ strcpy(link->name, name);
+ link->data = data;
+
+ tif->tif_clientinfo = link;
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_fax3.c b/tiff/libtiff/tif_fax3.c
new file mode 100644
index 0000000..9eec4ab
--- /dev/null
+++ b/tiff/libtiff/tif_fax3.c
@@ -0,0 +1,1626 @@
+/* $Id: tif_fax3.c,v 1.43.2.10 2010-06-09 17:16:58 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef CCITT_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * CCITT Group 3 (T.4) and Group 4 (T.6) Compression Support.
+ *
+ * This file contains support for decoding and encoding TIFF
+ * compression algorithms 2, 3, 4, and 32771.
+ *
+ * Decoder support is derived, with permission, from the code
+ * in Frank Cringle's viewfax program;
+ * Copyright (C) 1990, 1995 Frank D. Cringle.
+ */
+#include "tif_fax3.h"
+#define G3CODES
+#include "t4.h"
+#include <stdio.h>
+
+/*
+ * Compression+decompression state blocks are
+ * derived from this ``base state'' block.
+ */
+typedef struct {
+ int rw_mode; /* O_RDONLY for decode, else encode */
+ int mode; /* operating mode */
+ uint32 rowbytes; /* bytes in a decoded scanline */
+ uint32 rowpixels; /* pixels in a scanline */
+
+ uint16 cleanfaxdata; /* CleanFaxData tag */
+ uint32 badfaxrun; /* BadFaxRun tag */
+ uint32 badfaxlines; /* BadFaxLines tag */
+ uint32 groupoptions; /* Group 3/4 options tag */
+ uint32 recvparams; /* encoded Class 2 session params */
+ char* subaddress; /* subaddress string */
+ uint32 recvtime; /* time spent receiving (secs) */
+ char* faxdcs; /* Table 2/T.30 encoded session params */
+ TIFFVGetMethod vgetparent; /* super-class method */
+ TIFFVSetMethod vsetparent; /* super-class method */
+ TIFFPrintMethod printdir; /* super-class method */
+} Fax3BaseState;
+#define Fax3State(tif) ((Fax3BaseState*) (tif)->tif_data)
+
+typedef enum { G3_1D, G3_2D } Ttag;
+typedef struct {
+ Fax3BaseState b;
+
+ /* Decoder state info */
+ const unsigned char* bitmap; /* bit reversal table */
+ uint32 data; /* current i/o byte/word */
+ int bit; /* current i/o bit in byte */
+ int EOLcnt; /* count of EOL codes recognized */
+ TIFFFaxFillFunc fill; /* fill routine */
+ uint32* runs; /* b&w runs for current/previous row */
+ uint32* refruns; /* runs for reference line */
+ uint32* curruns; /* runs for current line */
+
+ /* Encoder state info */
+ Ttag tag; /* encoding state */
+ unsigned char* refline; /* reference line for 2d decoding */
+ int k; /* #rows left that can be 2d encoded */
+ int maxk; /* max #rows that can be 2d encoded */
+
+ int line;
+} Fax3CodecState;
+#define DecoderState(tif) ((Fax3CodecState*) Fax3State(tif))
+#define EncoderState(tif) ((Fax3CodecState*) Fax3State(tif))
+
+#define is2DEncoding(sp) \
+ (sp->b.groupoptions & GROUP3OPT_2DENCODING)
+#define isAligned(p,t) ((((unsigned long)(p)) & (sizeof (t)-1)) == 0)
+
+/*
+ * Group 3 and Group 4 Decoding.
+ */
+
+/*
+ * These macros glue the TIFF library state to
+ * the state expected by Frank's decoder.
+ */
+#define DECLARE_STATE(tif, sp, mod) \
+ static const char module[] = mod; \
+ Fax3CodecState* sp = DecoderState(tif); \
+ int a0; /* reference element */ \
+ int lastx = sp->b.rowpixels; /* last element in row */ \
+ uint32 BitAcc; /* bit accumulator */ \
+ int BitsAvail; /* # valid bits in BitAcc */ \
+ int RunLength; /* length of current run */ \
+ unsigned char* cp; /* next byte of input data */ \
+ unsigned char* ep; /* end of input data */ \
+ uint32* pa; /* place to stuff next run */ \
+ uint32* thisrun; /* current row's run array */ \
+ int EOLcnt; /* # EOL codes recognized */ \
+ const unsigned char* bitmap = sp->bitmap; /* input data bit reverser */ \
+ const TIFFFaxTabEnt* TabEnt
+#define DECLARE_STATE_2D(tif, sp, mod) \
+ DECLARE_STATE(tif, sp, mod); \
+ int b1; /* next change on prev line */ \
+ uint32* pb /* next run in reference line */\
+/*
+ * Load any state that may be changed during decoding.
+ */
+#define CACHE_STATE(tif, sp) do { \
+ BitAcc = sp->data; \
+ BitsAvail = sp->bit; \
+ EOLcnt = sp->EOLcnt; \
+ cp = (unsigned char*) tif->tif_rawcp; \
+ ep = cp + tif->tif_rawcc; \
+} while (0)
+/*
+ * Save state possibly changed during decoding.
+ */
+#define UNCACHE_STATE(tif, sp) do { \
+ sp->bit = BitsAvail; \
+ sp->data = BitAcc; \
+ sp->EOLcnt = EOLcnt; \
+ tif->tif_rawcc -= (tidata_t) cp - tif->tif_rawcp; \
+ tif->tif_rawcp = (tidata_t) cp; \
+} while (0)
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+Fax3PreDecode(TIFF* tif, tsample_t s)
+{
+ Fax3CodecState* sp = DecoderState(tif);
+
+ (void) s;
+ assert(sp != NULL);
+ sp->bit = 0; /* force initial read */
+ sp->data = 0;
+ sp->EOLcnt = 0; /* force initial scan for EOL */
+ /*
+ * Decoder assumes lsb-to-msb bit order. Note that we select
+ * this here rather than in Fax3SetupState so that viewers can
+ * hold the image open, fiddle with the FillOrder tag value,
+ * and then re-decode the image. Otherwise they'd need to close
+ * and open the image to get the state reset.
+ */
+ sp->bitmap =
+ TIFFGetBitRevTable(tif->tif_dir.td_fillorder != FILLORDER_LSB2MSB);
+ if (sp->refruns) { /* init reference line to white */
+ sp->refruns[0] = (uint32) sp->b.rowpixels;
+ sp->refruns[1] = 0;
+ }
+ sp->line = 0;
+ return (1);
+}
+
+/*
+ * Routine for handling various errors/conditions.
+ * Note how they are "glued into the decoder" by
+ * overriding the definitions used by the decoder.
+ */
+
+static void
+Fax3Unexpected(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Bad code word at line %u of %s %u (x %u)",
+ tif->tif_name, line, isTiled(tif) ? "tile" : "strip",
+ (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+ a0);
+}
+#define unexpected(table, a0) Fax3Unexpected(module, tif, sp->line, a0)
+
+static void
+Fax3Extension(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Uncompressed data (not supported) at line %u of %s %u (x %u)",
+ tif->tif_name, line, isTiled(tif) ? "tile" : "strip",
+ (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+ a0);
+}
+#define extension(a0) Fax3Extension(module, tif, sp->line, a0)
+
+static void
+Fax3BadLength(const char* module, TIFF* tif, uint32 line, uint32 a0, uint32 lastx)
+{
+ TIFFWarningExt(tif->tif_clientdata, module, "%s: %s at line %u of %s %u (got %u, expected %u)",
+ tif->tif_name,
+ a0 < lastx ? "Premature EOL" : "Line length mismatch",
+ line, isTiled(tif) ? "tile" : "strip",
+ (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+ a0, lastx);
+}
+#define badlength(a0,lastx) Fax3BadLength(module, tif, sp->line, a0, lastx)
+
+static void
+Fax3PrematureEOF(const char* module, TIFF* tif, uint32 line, uint32 a0)
+{
+ TIFFWarningExt(tif->tif_clientdata, module, "%s: Premature EOF at line %u of %s %u (x %u)",
+ tif->tif_name,
+ line, isTiled(tif) ? "tile" : "strip",
+ (isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip),
+ a0);
+}
+#define prematureEOF(a0) Fax3PrematureEOF(module, tif, sp->line, a0)
+
+#define Nop
+
+/*
+ * Decode the requested amount of G3 1D-encoded data.
+ */
+static int
+Fax3Decode1D(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s)
+{
+ DECLARE_STATE(tif, sp, "Fax3Decode1D");
+
+ (void) s;
+ CACHE_STATE(tif, sp);
+ thisrun = sp->curruns;
+ while ((long)occ > 0) {
+ a0 = 0;
+ RunLength = 0;
+ pa = thisrun;
+#ifdef FAX3_DEBUG
+ printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", tif->tif_row);
+ fflush(stdout);
+#endif
+ SYNC_EOL(EOF1D);
+ EXPAND1D(EOF1Da);
+ (*sp->fill)(buf, thisrun, pa, lastx);
+ buf += sp->b.rowbytes;
+ occ -= sp->b.rowbytes;
+ sp->line++;
+ continue;
+ EOF1D: /* premature EOF */
+ CLEANUP_RUNS();
+ EOF1Da: /* premature EOF */
+ (*sp->fill)(buf, thisrun, pa, lastx);
+ UNCACHE_STATE(tif, sp);
+ return (-1);
+ }
+ UNCACHE_STATE(tif, sp);
+ return (1);
+}
+
+#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; }
+/*
+ * Decode the requested amount of G3 2D-encoded data.
+ */
+static int
+Fax3Decode2D(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s)
+{
+ DECLARE_STATE_2D(tif, sp, "Fax3Decode2D");
+ int is1D; /* current line is 1d/2d-encoded */
+
+ (void) s;
+ CACHE_STATE(tif, sp);
+ while ((long)occ > 0) {
+ a0 = 0;
+ RunLength = 0;
+ pa = thisrun = sp->curruns;
+#ifdef FAX3_DEBUG
+ printf("\nBitAcc=%08X, BitsAvail = %d EOLcnt = %d",
+ BitAcc, BitsAvail, EOLcnt);
+#endif
+ SYNC_EOL(EOF2D);
+ NeedBits8(1, EOF2D);
+ is1D = GetBits(1); /* 1D/2D-encoding tag bit */
+ ClrBits(1);
+#ifdef FAX3_DEBUG
+ printf(" %s\n-------------------- %d\n",
+ is1D ? "1D" : "2D", tif->tif_row);
+ fflush(stdout);
+#endif
+ pb = sp->refruns;
+ b1 = *pb++;
+ if (is1D)
+ EXPAND1D(EOF2Da);
+ else
+ EXPAND2D(EOF2Da);
+ (*sp->fill)(buf, thisrun, pa, lastx);
+ SETVALUE(0); /* imaginary change for reference */
+ SWAP(uint32*, sp->curruns, sp->refruns);
+ buf += sp->b.rowbytes;
+ occ -= sp->b.rowbytes;
+ sp->line++;
+ continue;
+ EOF2D: /* premature EOF */
+ CLEANUP_RUNS();
+ EOF2Da: /* premature EOF */
+ (*sp->fill)(buf, thisrun, pa, lastx);
+ UNCACHE_STATE(tif, sp);
+ return (-1);
+ }
+ UNCACHE_STATE(tif, sp);
+ return (1);
+}
+#undef SWAP
+
+/*
+ * The ZERO & FILL macros must handle spans < 2*sizeof(long) bytes.
+ * For machines with 64-bit longs this is <16 bytes; otherwise
+ * this is <8 bytes. We optimize the code here to reflect the
+ * machine characteristics.
+ */
+#if SIZEOF_LONG == 8
+# define FILL(n, cp) \
+ switch (n) { \
+ case 15:(cp)[14] = 0xff; case 14:(cp)[13] = 0xff; case 13: (cp)[12] = 0xff;\
+ case 12:(cp)[11] = 0xff; case 11:(cp)[10] = 0xff; case 10: (cp)[9] = 0xff;\
+ case 9: (cp)[8] = 0xff; case 8: (cp)[7] = 0xff; case 7: (cp)[6] = 0xff;\
+ case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; case 4: (cp)[3] = 0xff;\
+ case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \
+ case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \
+ }
+# define ZERO(n, cp) \
+ switch (n) { \
+ case 15:(cp)[14] = 0; case 14:(cp)[13] = 0; case 13: (cp)[12] = 0; \
+ case 12:(cp)[11] = 0; case 11:(cp)[10] = 0; case 10: (cp)[9] = 0; \
+ case 9: (cp)[8] = 0; case 8: (cp)[7] = 0; case 7: (cp)[6] = 0; \
+ case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; case 4: (cp)[3] = 0; \
+ case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \
+ case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \
+ }
+#else
+# define FILL(n, cp) \
+ switch (n) { \
+ case 7: (cp)[6] = 0xff; case 6: (cp)[5] = 0xff; case 5: (cp)[4] = 0xff; \
+ case 4: (cp)[3] = 0xff; case 3: (cp)[2] = 0xff; case 2: (cp)[1] = 0xff; \
+ case 1: (cp)[0] = 0xff; (cp) += (n); case 0: ; \
+ }
+# define ZERO(n, cp) \
+ switch (n) { \
+ case 7: (cp)[6] = 0; case 6: (cp)[5] = 0; case 5: (cp)[4] = 0; \
+ case 4: (cp)[3] = 0; case 3: (cp)[2] = 0; case 2: (cp)[1] = 0; \
+ case 1: (cp)[0] = 0; (cp) += (n); case 0: ; \
+ }
+#endif
+
+/*
+ * Bit-fill a row according to the white/black
+ * runs generated during G3/G4 decoding.
+ */
+void
+_TIFFFax3fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
+{
+ static const unsigned char _fillmasks[] =
+ { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ unsigned char* cp;
+ uint32 x, bx, run;
+ int32 n, nw;
+ long* lp;
+
+ if ((erun-runs)&1)
+ *erun++ = 0;
+ x = 0;
+ for (; runs < erun; runs += 2) {
+ run = runs[0];
+ if (x+run > lastx || run > lastx )
+ run = runs[0] = (uint32) (lastx - x);
+ if (run) {
+ cp = buf + (x>>3);
+ bx = x&7;
+ if (run > 8-bx) {
+ if (bx) { /* align to byte boundary */
+ *cp++ &= 0xff << (8-bx);
+ run -= 8-bx;
+ }
+ if( (n = run >> 3) != 0 ) { /* multiple bytes to fill */
+ if ((n/sizeof (long)) > 1) {
+ /*
+ * Align to longword boundary and fill.
+ */
+ for (; n && !isAligned(cp, long); n--)
+ *cp++ = 0x00;
+ lp = (long*) cp;
+ nw = (int32)(n / sizeof (long));
+ n -= nw * sizeof (long);
+ do {
+ *lp++ = 0L;
+ } while (--nw);
+ cp = (unsigned char*) lp;
+ }
+ ZERO(n, cp);
+ run &= 7;
+ }
+ if (run)
+ cp[0] &= 0xff >> run;
+ } else
+ cp[0] &= ~(_fillmasks[run]>>bx);
+ x += runs[0];
+ }
+ run = runs[1];
+ if (x+run > lastx || run > lastx )
+ run = runs[1] = lastx - x;
+ if (run) {
+ cp = buf + (x>>3);
+ bx = x&7;
+ if (run > 8-bx) {
+ if (bx) { /* align to byte boundary */
+ *cp++ |= 0xff >> bx;
+ run -= 8-bx;
+ }
+ if( (n = run>>3) != 0 ) { /* multiple bytes to fill */
+ if ((n/sizeof (long)) > 1) {
+ /*
+ * Align to longword boundary and fill.
+ */
+ for (; n && !isAligned(cp, long); n--)
+ *cp++ = 0xff;
+ lp = (long*) cp;
+ nw = (int32)(n / sizeof (long));
+ n -= nw * sizeof (long);
+ do {
+ *lp++ = -1L;
+ } while (--nw);
+ cp = (unsigned char*) lp;
+ }
+ FILL(n, cp);
+ run &= 7;
+ }
+ if (run)
+ cp[0] |= 0xff00 >> run;
+ } else
+ cp[0] |= _fillmasks[run]>>bx;
+ x += runs[1];
+ }
+ }
+ assert(x == lastx);
+}
+#undef ZERO
+#undef FILL
+
+/*
+ * Setup G3/G4-related compression/decompression state
+ * before data is processed. This routine is called once
+ * per image -- it sets up different state based on whether
+ * or not decoding or encoding is being done and whether
+ * 1D- or 2D-encoded data is involved.
+ */
+static int
+Fax3SetupState(TIFF* tif)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ Fax3BaseState* sp = Fax3State(tif);
+ int needsRefLine;
+ Fax3CodecState* dsp = (Fax3CodecState*) Fax3State(tif);
+ uint32 rowbytes, rowpixels, nruns;
+
+ if (td->td_bitspersample != 1) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Bits/sample must be 1 for Group 3/4 encoding/decoding");
+ return (0);
+ }
+ /*
+ * Calculate the scanline/tile widths.
+ */
+ if (isTiled(tif)) {
+ rowbytes = TIFFTileRowSize(tif);
+ rowpixels = td->td_tilewidth;
+ } else {
+ rowbytes = TIFFScanlineSize(tif);
+ rowpixels = td->td_imagewidth;
+ }
+ sp->rowbytes = (uint32) rowbytes;
+ sp->rowpixels = (uint32) rowpixels;
+ /*
+ * Allocate any additional space required for decoding/encoding.
+ */
+ needsRefLine = (
+ (sp->groupoptions & GROUP3OPT_2DENCODING) ||
+ td->td_compression == COMPRESSION_CCITTFAX4
+ );
+
+ /*
+ Assure that allocation computations do not overflow.
+
+ TIFFroundup and TIFFSafeMultiply return zero on integer overflow
+ */
+ dsp->runs=(uint32*) NULL;
+ nruns = TIFFroundup(rowpixels,32);
+ if (needsRefLine) {
+ nruns = TIFFSafeMultiply(uint32,nruns,2);
+ }
+ if ((nruns == 0) || (TIFFSafeMultiply(uint32,nruns,2) == 0)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Row pixels integer overflow (rowpixels %u)",
+ rowpixels);
+ return (0);
+ }
+ dsp->runs = (uint32*) _TIFFCheckMalloc(tif,
+ TIFFSafeMultiply(uint32,nruns,2),
+ sizeof (uint32),
+ "for Group 3/4 run arrays");
+ if (dsp->runs == NULL)
+ return (0);
+ dsp->curruns = dsp->runs;
+ if (needsRefLine)
+ dsp->refruns = dsp->runs + nruns;
+ else
+ dsp->refruns = NULL;
+ if (td->td_compression == COMPRESSION_CCITTFAX3
+ && is2DEncoding(dsp)) { /* NB: default is 1D routine */
+ tif->tif_decoderow = Fax3Decode2D;
+ tif->tif_decodestrip = Fax3Decode2D;
+ tif->tif_decodetile = Fax3Decode2D;
+ }
+
+ if (needsRefLine) { /* 2d encoding */
+ Fax3CodecState* esp = EncoderState(tif);
+ /*
+ * 2d encoding requires a scanline
+ * buffer for the ``reference line''; the
+ * scanline against which delta encoding
+ * is referenced. The reference line must
+ * be initialized to be ``white'' (done elsewhere).
+ */
+ esp->refline = (unsigned char*) _TIFFmalloc(rowbytes);
+ if (esp->refline == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, "Fax3SetupState",
+ "%s: No space for Group 3/4 reference line",
+ tif->tif_name);
+ return (0);
+ }
+ } else /* 1d encoding */
+ EncoderState(tif)->refline = NULL;
+
+ return (1);
+}
+
+/*
+ * CCITT Group 3 FAX Encoding.
+ */
+
+#define Fax3FlushBits(tif, sp) { \
+ if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \
+ (void) TIFFFlushData1(tif); \
+ *(tif)->tif_rawcp++ = (tidataval_t) (sp)->data; \
+ (tif)->tif_rawcc++; \
+ (sp)->data = 0, (sp)->bit = 8; \
+}
+#define _FlushBits(tif) { \
+ if ((tif)->tif_rawcc >= (tif)->tif_rawdatasize) \
+ (void) TIFFFlushData1(tif); \
+ *(tif)->tif_rawcp++ = (tidataval_t) data; \
+ (tif)->tif_rawcc++; \
+ data = 0, bit = 8; \
+}
+static const int _msbmask[9] =
+ { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+#define _PutBits(tif, bits, length) { \
+ while (length > bit) { \
+ data |= bits >> (length - bit); \
+ length -= bit; \
+ _FlushBits(tif); \
+ } \
+ data |= (bits & _msbmask[length]) << (bit - length); \
+ bit -= length; \
+ if (bit == 0) \
+ _FlushBits(tif); \
+}
+
+/*
+ * Write a variable-length bit-value to
+ * the output stream. Values are
+ * assumed to be at most 16 bits.
+ */
+static void
+Fax3PutBits(TIFF* tif, unsigned int bits, unsigned int length)
+{
+ Fax3CodecState* sp = EncoderState(tif);
+ unsigned int bit = sp->bit;
+ int data = sp->data;
+
+ _PutBits(tif, bits, length);
+
+ sp->data = data;
+ sp->bit = bit;
+}
+
+/*
+ * Write a code to the output stream.
+ */
+#define putcode(tif, te) Fax3PutBits(tif, (te)->code, (te)->length)
+
+#ifdef FAX3_DEBUG
+#define DEBUG_COLOR(w) (tab == TIFFFaxWhiteCodes ? w "W" : w "B")
+#define DEBUG_PRINT(what,len) { \
+ int t; \
+ printf("%08X/%-2d: %s%5d\t", data, bit, DEBUG_COLOR(what), len); \
+ for (t = length-1; t >= 0; t--) \
+ putchar(code & (1<<t) ? '1' : '0'); \
+ putchar('\n'); \
+}
+#endif
+
+/*
+ * Write the sequence of codes that describes
+ * the specified span of zero's or one's. The
+ * appropriate table that holds the make-up and
+ * terminating codes is supplied.
+ */
+static void
+putspan(TIFF* tif, int32 span, const tableentry* tab)
+{
+ Fax3CodecState* sp = EncoderState(tif);
+ unsigned int bit = sp->bit;
+ int data = sp->data;
+ unsigned int code, length;
+
+ while (span >= 2624) {
+ const tableentry* te = &tab[63 + (2560>>6)];
+ code = te->code, length = te->length;
+#ifdef FAX3_DEBUG
+ DEBUG_PRINT("MakeUp", te->runlen);
+#endif
+ _PutBits(tif, code, length);
+ span -= te->runlen;
+ }
+ if (span >= 64) {
+ const tableentry* te = &tab[63 + (span>>6)];
+ assert(te->runlen == 64*(span>>6));
+ code = te->code, length = te->length;
+#ifdef FAX3_DEBUG
+ DEBUG_PRINT("MakeUp", te->runlen);
+#endif
+ _PutBits(tif, code, length);
+ span -= te->runlen;
+ }
+ code = tab[span].code, length = tab[span].length;
+#ifdef FAX3_DEBUG
+ DEBUG_PRINT(" Term", tab[span].runlen);
+#endif
+ _PutBits(tif, code, length);
+
+ sp->data = data;
+ sp->bit = bit;
+}
+
+/*
+ * Write an EOL code to the output stream. The zero-fill
+ * logic for byte-aligning encoded scanlines is handled
+ * here. We also handle writing the tag bit for the next
+ * scanline when doing 2d encoding.
+ */
+static void
+Fax3PutEOL(TIFF* tif)
+{
+ Fax3CodecState* sp = EncoderState(tif);
+ unsigned int bit = sp->bit;
+ int data = sp->data;
+ unsigned int code, length, tparm;
+
+ if (sp->b.groupoptions & GROUP3OPT_FILLBITS) {
+ /*
+ * Force bit alignment so EOL will terminate on
+ * a byte boundary. That is, force the bit alignment
+ * to 16-12 = 4 before putting out the EOL code.
+ */
+ int align = 8 - 4;
+ if (align != sp->bit) {
+ if (align > sp->bit)
+ align = sp->bit + (8 - align);
+ else
+ align = sp->bit - align;
+ code = 0;
+ tparm=align;
+ _PutBits(tif, 0, tparm);
+ }
+ }
+ code = EOL, length = 12;
+ if (is2DEncoding(sp))
+ code = (code<<1) | (sp->tag == G3_1D), length++;
+ _PutBits(tif, code, length);
+
+ sp->data = data;
+ sp->bit = bit;
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+Fax3PreEncode(TIFF* tif, tsample_t s)
+{
+ Fax3CodecState* sp = EncoderState(tif);
+
+ (void) s;
+ assert(sp != NULL);
+ sp->bit = 8;
+ sp->data = 0;
+ sp->tag = G3_1D;
+ /*
+ * This is necessary for Group 4; otherwise it isn't
+ * needed because the first scanline of each strip ends
+ * up being copied into the refline.
+ */
+ if (sp->refline)
+ _TIFFmemset(sp->refline, 0x00, sp->b.rowbytes);
+ if (is2DEncoding(sp)) {
+ float res = tif->tif_dir.td_yresolution;
+ /*
+ * The CCITT spec says that when doing 2d encoding, you
+ * should only do it on K consecutive scanlines, where K
+ * depends on the resolution of the image being encoded
+ * (2 for <= 200 lpi, 4 for > 200 lpi). Since the directory
+ * code initializes td_yresolution to 0, this code will
+ * select a K of 2 unless the YResolution tag is set
+ * appropriately. (Note also that we fudge a little here
+ * and use 150 lpi to avoid problems with units conversion.)
+ */
+ if (tif->tif_dir.td_resolutionunit == RESUNIT_CENTIMETER)
+ res *= 2.54f; /* convert to inches */
+ sp->maxk = (res > 150 ? 4 : 2);
+ sp->k = sp->maxk-1;
+ } else
+ sp->k = sp->maxk = 0;
+ sp->line = 0;
+ return (1);
+}
+
+static const unsigned char zeroruns[256] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */
+};
+static const unsigned char oneruns[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */
+};
+
+/*
+ * On certain systems it pays to inline
+ * the routines that find pixel spans.
+ */
+#ifdef VAXC
+static int32 find0span(unsigned char*, int32, int32);
+static int32 find1span(unsigned char*, int32, int32);
+#pragma inline(find0span,find1span)
+#endif
+
+/*
+ * Find a span of ones or zeros using the supplied
+ * table. The ``base'' of the bit string is supplied
+ * along with the start+end bit indices.
+ */
+static int32
+find0span(unsigned char* bp, int32 bs, int32 be)
+{
+ int32 bits = be - bs;
+ int32 n, span;
+
+ bp += bs>>3;
+ /*
+ * Check partial byte on lhs.
+ */
+ if (bits > 0 && (n = (bs & 7))) {
+ span = zeroruns[(*bp << n) & 0xff];
+ if (span > 8-n) /* table value too generous */
+ span = 8-n;
+ if (span > bits) /* constrain span to bit range */
+ span = bits;
+ if (n+span < 8) /* doesn't extend to edge of byte */
+ return (span);
+ bits -= span;
+ bp++;
+ } else
+ span = 0;
+ if (bits >= (int32)(2 * 8 * sizeof(long))) {
+ long* lp;
+ /*
+ * Align to longword boundary and check longwords.
+ */
+ while (!isAligned(bp, long)) {
+ if (*bp != 0x00)
+ return (span + zeroruns[*bp]);
+ span += 8, bits -= 8;
+ bp++;
+ }
+ lp = (long*) bp;
+ while ((bits >= (int32)(8 * sizeof(long))) && (0 == *lp)) {
+ span += 8*sizeof (long), bits -= 8*sizeof (long);
+ lp++;
+ }
+ bp = (unsigned char*) lp;
+ }
+ /*
+ * Scan full bytes for all 0's.
+ */
+ while (bits >= 8) {
+ if (*bp != 0x00) /* end of run */
+ return (span + zeroruns[*bp]);
+ span += 8, bits -= 8;
+ bp++;
+ }
+ /*
+ * Check partial byte on rhs.
+ */
+ if (bits > 0) {
+ n = zeroruns[*bp];
+ span += (n > bits ? bits : n);
+ }
+ return (span);
+}
+
+static int32
+find1span(unsigned char* bp, int32 bs, int32 be)
+{
+ int32 bits = be - bs;
+ int32 n, span;
+
+ bp += bs>>3;
+ /*
+ * Check partial byte on lhs.
+ */
+ if (bits > 0 && (n = (bs & 7))) {
+ span = oneruns[(*bp << n) & 0xff];
+ if (span > 8-n) /* table value too generous */
+ span = 8-n;
+ if (span > bits) /* constrain span to bit range */
+ span = bits;
+ if (n+span < 8) /* doesn't extend to edge of byte */
+ return (span);
+ bits -= span;
+ bp++;
+ } else
+ span = 0;
+ if (bits >= (int32)(2 * 8 * sizeof(long))) {
+ long* lp;
+ /*
+ * Align to longword boundary and check longwords.
+ */
+ while (!isAligned(bp, long)) {
+ if (*bp != 0xff)
+ return (span + oneruns[*bp]);
+ span += 8, bits -= 8;
+ bp++;
+ }
+ lp = (long*) bp;
+ while ((bits >= (int32)(8 * sizeof(long))) && (~0 == *lp)) {
+ span += 8*sizeof (long), bits -= 8*sizeof (long);
+ lp++;
+ }
+ bp = (unsigned char*) lp;
+ }
+ /*
+ * Scan full bytes for all 1's.
+ */
+ while (bits >= 8) {
+ if (*bp != 0xff) /* end of run */
+ return (span + oneruns[*bp]);
+ span += 8, bits -= 8;
+ bp++;
+ }
+ /*
+ * Check partial byte on rhs.
+ */
+ if (bits > 0) {
+ n = oneruns[*bp];
+ span += (n > bits ? bits : n);
+ }
+ return (span);
+}
+
+/*
+ * Return the offset of the next bit in the range
+ * [bs..be] that is different from the specified
+ * color. The end, be, is returned if no such bit
+ * exists.
+ */
+#define finddiff(_cp, _bs, _be, _color) \
+ (_bs + (_color ? find1span(_cp,_bs,_be) : find0span(_cp,_bs,_be)))
+/*
+ * Like finddiff, but also check the starting bit
+ * against the end in case start > end.
+ */
+#define finddiff2(_cp, _bs, _be, _color) \
+ (_bs < _be ? finddiff(_cp,_bs,_be,_color) : _be)
+
+/*
+ * 1d-encode a row of pixels. The encoding is
+ * a sequence of all-white or all-black spans
+ * of pixels encoded with Huffman codes.
+ */
+static int
+Fax3Encode1DRow(TIFF* tif, unsigned char* bp, uint32 bits)
+{
+ Fax3CodecState* sp = EncoderState(tif);
+ int32 span;
+ uint32 bs = 0;
+
+ for (;;) {
+ span = find0span(bp, bs, bits); /* white span */
+ putspan(tif, span, TIFFFaxWhiteCodes);
+ bs += span;
+ if (bs >= bits)
+ break;
+ span = find1span(bp, bs, bits); /* black span */
+ putspan(tif, span, TIFFFaxBlackCodes);
+ bs += span;
+ if (bs >= bits)
+ break;
+ }
+ if (sp->b.mode & (FAXMODE_BYTEALIGN|FAXMODE_WORDALIGN)) {
+ if (sp->bit != 8) /* byte-align */
+ Fax3FlushBits(tif, sp);
+ if ((sp->b.mode&FAXMODE_WORDALIGN) &&
+ !isAligned(tif->tif_rawcp, uint16))
+ Fax3FlushBits(tif, sp);
+ }
+ return (1);
+}
+
+static const tableentry horizcode =
+ { 3, 0x1, 0 }; /* 001 */
+static const tableentry passcode =
+ { 4, 0x1, 0 }; /* 0001 */
+static const tableentry vcodes[7] = {
+ { 7, 0x03, 0 }, /* 0000 011 */
+ { 6, 0x03, 0 }, /* 0000 11 */
+ { 3, 0x03, 0 }, /* 011 */
+ { 1, 0x1, 0 }, /* 1 */
+ { 3, 0x2, 0 }, /* 010 */
+ { 6, 0x02, 0 }, /* 0000 10 */
+ { 7, 0x02, 0 } /* 0000 010 */
+};
+
+/*
+ * 2d-encode a row of pixels. Consult the CCITT
+ * documentation for the algorithm.
+ */
+static int
+Fax3Encode2DRow(TIFF* tif, unsigned char* bp, unsigned char* rp, uint32 bits)
+{
+#define PIXEL(buf,ix) ((((buf)[(ix)>>3]) >> (7-((ix)&7))) & 1)
+ uint32 a0 = 0;
+ uint32 a1 = (PIXEL(bp, 0) != 0 ? 0 : finddiff(bp, 0, bits, 0));
+ uint32 b1 = (PIXEL(rp, 0) != 0 ? 0 : finddiff(rp, 0, bits, 0));
+ uint32 a2, b2;
+
+ for (;;) {
+ b2 = finddiff2(rp, b1, bits, PIXEL(rp,b1));
+ if (b2 >= a1) {
+ int32 d = b1 - a1;
+ if (!(-3 <= d && d <= 3)) { /* horizontal mode */
+ a2 = finddiff2(bp, a1, bits, PIXEL(bp,a1));
+ putcode(tif, &horizcode);
+ if (a0+a1 == 0 || PIXEL(bp, a0) == 0) {
+ putspan(tif, a1-a0, TIFFFaxWhiteCodes);
+ putspan(tif, a2-a1, TIFFFaxBlackCodes);
+ } else {
+ putspan(tif, a1-a0, TIFFFaxBlackCodes);
+ putspan(tif, a2-a1, TIFFFaxWhiteCodes);
+ }
+ a0 = a2;
+ } else { /* vertical mode */
+ putcode(tif, &vcodes[d+3]);
+ a0 = a1;
+ }
+ } else { /* pass mode */
+ putcode(tif, &passcode);
+ a0 = b2;
+ }
+ if (a0 >= bits)
+ break;
+ a1 = finddiff(bp, a0, bits, PIXEL(bp,a0));
+ b1 = finddiff(rp, a0, bits, !PIXEL(bp,a0));
+ b1 = finddiff(rp, b1, bits, PIXEL(bp,a0));
+ }
+ return (1);
+#undef PIXEL
+}
+
+/*
+ * Encode a buffer of pixels.
+ */
+static int
+Fax3Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ Fax3CodecState* sp = EncoderState(tif);
+
+ (void) s;
+ while ((long)cc > 0) {
+ if ((sp->b.mode & FAXMODE_NOEOL) == 0)
+ Fax3PutEOL(tif);
+ if (is2DEncoding(sp)) {
+ if (sp->tag == G3_1D) {
+ if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels))
+ return (0);
+ sp->tag = G3_2D;
+ } else {
+ if (!Fax3Encode2DRow(tif, bp, sp->refline,
+ sp->b.rowpixels))
+ return (0);
+ sp->k--;
+ }
+ if (sp->k == 0) {
+ sp->tag = G3_1D;
+ sp->k = sp->maxk-1;
+ } else
+ _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes);
+ } else {
+ if (!Fax3Encode1DRow(tif, bp, sp->b.rowpixels))
+ return (0);
+ }
+ bp += sp->b.rowbytes;
+ cc -= sp->b.rowbytes;
+ }
+ return (1);
+}
+
+static int
+Fax3PostEncode(TIFF* tif)
+{
+ Fax3CodecState* sp = EncoderState(tif);
+
+ if (sp->bit != 8)
+ Fax3FlushBits(tif, sp);
+ return (1);
+}
+
+static void
+Fax3Close(TIFF* tif)
+{
+ if ((Fax3State(tif)->mode & FAXMODE_NORTC) == 0) {
+ Fax3CodecState* sp = EncoderState(tif);
+ unsigned int code = EOL;
+ unsigned int length = 12;
+ int i;
+
+ if (is2DEncoding(sp))
+ code = (code<<1) | (sp->tag == G3_1D), length++;
+ for (i = 0; i < 6; i++)
+ Fax3PutBits(tif, code, length);
+ Fax3FlushBits(tif, sp);
+ }
+}
+
+static void
+Fax3Cleanup(TIFF* tif)
+{
+ Fax3CodecState* sp = DecoderState(tif);
+
+ assert(sp != 0);
+
+ tif->tif_tagmethods.vgetfield = sp->b.vgetparent;
+ tif->tif_tagmethods.vsetfield = sp->b.vsetparent;
+ tif->tif_tagmethods.printdir = sp->b.printdir;
+
+ if (sp->runs)
+ _TIFFfree(sp->runs);
+ if (sp->refline)
+ _TIFFfree(sp->refline);
+
+ if (Fax3State(tif)->subaddress)
+ _TIFFfree(Fax3State(tif)->subaddress);
+ if (Fax3State(tif)->faxdcs)
+ _TIFFfree(Fax3State(tif)->faxdcs);
+
+ _TIFFfree(tif->tif_data);
+ tif->tif_data = NULL;
+
+ _TIFFSetDefaultCompressionState(tif);
+}
+
+#define FIELD_BADFAXLINES (FIELD_CODEC+0)
+#define FIELD_CLEANFAXDATA (FIELD_CODEC+1)
+#define FIELD_BADFAXRUN (FIELD_CODEC+2)
+#define FIELD_RECVPARAMS (FIELD_CODEC+3)
+#define FIELD_SUBADDRESS (FIELD_CODEC+4)
+#define FIELD_RECVTIME (FIELD_CODEC+5)
+#define FIELD_FAXDCS (FIELD_CODEC+6)
+
+#define FIELD_OPTIONS (FIELD_CODEC+7)
+
+static const TIFFFieldInfo faxFieldInfo[] = {
+ { TIFFTAG_FAXMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO,
+ FALSE, FALSE, "FaxMode" },
+ { TIFFTAG_FAXFILLFUNC, 0, 0, TIFF_ANY, FIELD_PSEUDO,
+ FALSE, FALSE, "FaxFillFunc" },
+ { TIFFTAG_BADFAXLINES, 1, 1, TIFF_LONG, FIELD_BADFAXLINES,
+ TRUE, FALSE, "BadFaxLines" },
+ { TIFFTAG_BADFAXLINES, 1, 1, TIFF_SHORT, FIELD_BADFAXLINES,
+ TRUE, FALSE, "BadFaxLines" },
+ { TIFFTAG_CLEANFAXDATA, 1, 1, TIFF_SHORT, FIELD_CLEANFAXDATA,
+ TRUE, FALSE, "CleanFaxData" },
+ { TIFFTAG_CONSECUTIVEBADFAXLINES,1,1, TIFF_LONG, FIELD_BADFAXRUN,
+ TRUE, FALSE, "ConsecutiveBadFaxLines" },
+ { TIFFTAG_CONSECUTIVEBADFAXLINES,1,1, TIFF_SHORT, FIELD_BADFAXRUN,
+ TRUE, FALSE, "ConsecutiveBadFaxLines" },
+ { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS,
+ TRUE, FALSE, "FaxRecvParams" },
+ { TIFFTAG_FAXSUBADDRESS, -1,-1, TIFF_ASCII, FIELD_SUBADDRESS,
+ TRUE, FALSE, "FaxSubAddress" },
+ { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME,
+ TRUE, FALSE, "FaxRecvTime" },
+ { TIFFTAG_FAXDCS, -1,-1, TIFF_ASCII, FIELD_FAXDCS,
+ TRUE, FALSE, "FaxDcs" },
+};
+static const TIFFFieldInfo fax3FieldInfo[] = {
+ { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, FIELD_OPTIONS,
+ FALSE, FALSE, "Group3Options" },
+};
+static const TIFFFieldInfo fax4FieldInfo[] = {
+ { TIFFTAG_GROUP4OPTIONS, 1, 1, TIFF_LONG, FIELD_OPTIONS,
+ FALSE, FALSE, "Group4Options" },
+};
+#define N(a) (sizeof (a) / sizeof (a[0]))
+
+static int
+Fax3VSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ Fax3BaseState* sp = Fax3State(tif);
+ const TIFFFieldInfo* fip;
+
+ assert(sp != 0);
+ assert(sp->vsetparent != 0);
+
+ switch (tag) {
+ case TIFFTAG_FAXMODE:
+ sp->mode = va_arg(ap, int);
+ return 1; /* NB: pseudo tag */
+ case TIFFTAG_FAXFILLFUNC:
+ DecoderState(tif)->fill = va_arg(ap, TIFFFaxFillFunc);
+ return 1; /* NB: pseudo tag */
+ case TIFFTAG_GROUP3OPTIONS:
+ /* XXX: avoid reading options if compression mismatches. */
+ if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX3)
+ sp->groupoptions = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_GROUP4OPTIONS:
+ /* XXX: avoid reading options if compression mismatches. */
+ if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4)
+ sp->groupoptions = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_BADFAXLINES:
+ sp->badfaxlines = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_CLEANFAXDATA:
+ sp->cleanfaxdata = (uint16) va_arg(ap, int);
+ break;
+ case TIFFTAG_CONSECUTIVEBADFAXLINES:
+ sp->badfaxrun = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_FAXRECVPARAMS:
+ sp->recvparams = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_FAXSUBADDRESS:
+ _TIFFsetString(&sp->subaddress, va_arg(ap, char*));
+ break;
+ case TIFFTAG_FAXRECVTIME:
+ sp->recvtime = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_FAXDCS:
+ _TIFFsetString(&sp->faxdcs, va_arg(ap, char*));
+ break;
+ default:
+ return (*sp->vsetparent)(tif, tag, ap);
+ }
+
+ if ((fip = _TIFFFieldWithTag(tif, tag)))
+ TIFFSetFieldBit(tif, fip->field_bit);
+ else
+ return 0;
+
+ tif->tif_flags |= TIFF_DIRTYDIRECT;
+ return 1;
+}
+
+static int
+Fax3VGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ Fax3BaseState* sp = Fax3State(tif);
+
+ assert(sp != 0);
+
+ switch (tag) {
+ case TIFFTAG_FAXMODE:
+ *va_arg(ap, int*) = sp->mode;
+ break;
+ case TIFFTAG_FAXFILLFUNC:
+ *va_arg(ap, TIFFFaxFillFunc*) = DecoderState(tif)->fill;
+ break;
+ case TIFFTAG_GROUP3OPTIONS:
+ case TIFFTAG_GROUP4OPTIONS:
+ *va_arg(ap, uint32*) = sp->groupoptions;
+ break;
+ case TIFFTAG_BADFAXLINES:
+ *va_arg(ap, uint32*) = sp->badfaxlines;
+ break;
+ case TIFFTAG_CLEANFAXDATA:
+ *va_arg(ap, uint16*) = sp->cleanfaxdata;
+ break;
+ case TIFFTAG_CONSECUTIVEBADFAXLINES:
+ *va_arg(ap, uint32*) = sp->badfaxrun;
+ break;
+ case TIFFTAG_FAXRECVPARAMS:
+ *va_arg(ap, uint32*) = sp->recvparams;
+ break;
+ case TIFFTAG_FAXSUBADDRESS:
+ *va_arg(ap, char**) = sp->subaddress;
+ break;
+ case TIFFTAG_FAXRECVTIME:
+ *va_arg(ap, uint32*) = sp->recvtime;
+ break;
+ case TIFFTAG_FAXDCS:
+ *va_arg(ap, char**) = sp->faxdcs;
+ break;
+ default:
+ return (*sp->vgetparent)(tif, tag, ap);
+ }
+ return (1);
+}
+
+static void
+Fax3PrintDir(TIFF* tif, FILE* fd, long flags)
+{
+ Fax3BaseState* sp = Fax3State(tif);
+
+ assert(sp != 0);
+
+ (void) flags;
+ if (TIFFFieldSet(tif,FIELD_OPTIONS)) {
+ const char* sep = " ";
+ if (tif->tif_dir.td_compression == COMPRESSION_CCITTFAX4) {
+ fprintf(fd, " Group 4 Options:");
+ if (sp->groupoptions & GROUP4OPT_UNCOMPRESSED)
+ fprintf(fd, "%suncompressed data", sep);
+ } else {
+
+ fprintf(fd, " Group 3 Options:");
+ if (sp->groupoptions & GROUP3OPT_2DENCODING)
+ fprintf(fd, "%s2-d encoding", sep), sep = "+";
+ if (sp->groupoptions & GROUP3OPT_FILLBITS)
+ fprintf(fd, "%sEOL padding", sep), sep = "+";
+ if (sp->groupoptions & GROUP3OPT_UNCOMPRESSED)
+ fprintf(fd, "%suncompressed data", sep);
+ }
+ fprintf(fd, " (%lu = 0x%lx)\n",
+ (unsigned long) sp->groupoptions,
+ (unsigned long) sp->groupoptions);
+ }
+ if (TIFFFieldSet(tif,FIELD_CLEANFAXDATA)) {
+ fprintf(fd, " Fax Data:");
+ switch (sp->cleanfaxdata) {
+ case CLEANFAXDATA_CLEAN:
+ fprintf(fd, " clean");
+ break;
+ case CLEANFAXDATA_REGENERATED:
+ fprintf(fd, " receiver regenerated");
+ break;
+ case CLEANFAXDATA_UNCLEAN:
+ fprintf(fd, " uncorrected errors");
+ break;
+ }
+ fprintf(fd, " (%u = 0x%x)\n",
+ sp->cleanfaxdata, sp->cleanfaxdata);
+ }
+ if (TIFFFieldSet(tif,FIELD_BADFAXLINES))
+ fprintf(fd, " Bad Fax Lines: %lu\n",
+ (unsigned long) sp->badfaxlines);
+ if (TIFFFieldSet(tif,FIELD_BADFAXRUN))
+ fprintf(fd, " Consecutive Bad Fax Lines: %lu\n",
+ (unsigned long) sp->badfaxrun);
+ if (TIFFFieldSet(tif,FIELD_RECVPARAMS))
+ fprintf(fd, " Fax Receive Parameters: %08lx\n",
+ (unsigned long) sp->recvparams);
+ if (TIFFFieldSet(tif,FIELD_SUBADDRESS))
+ fprintf(fd, " Fax SubAddress: %s\n", sp->subaddress);
+ if (TIFFFieldSet(tif,FIELD_RECVTIME))
+ fprintf(fd, " Fax Receive Time: %lu secs\n",
+ (unsigned long) sp->recvtime);
+ if (TIFFFieldSet(tif,FIELD_FAXDCS))
+ fprintf(fd, " Fax DCS: %s\n", sp->faxdcs);
+}
+
+static int
+InitCCITTFax3(TIFF* tif)
+{
+ Fax3BaseState* sp;
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, faxFieldInfo, N(faxFieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata, "InitCCITTFax3",
+ "Merging common CCITT Fax codec-specific tags failed");
+ return 0;
+ }
+
+ /*
+ * Allocate state block so tag methods have storage to record values.
+ */
+ tif->tif_data = (tidata_t)
+ _TIFFmalloc(sizeof (Fax3CodecState));
+
+ if (tif->tif_data == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3",
+ "%s: No space for state block", tif->tif_name);
+ return (0);
+ }
+
+ sp = Fax3State(tif);
+ sp->rw_mode = tif->tif_mode;
+
+ /*
+ * Override parent get/set field methods.
+ */
+ sp->vgetparent = tif->tif_tagmethods.vgetfield;
+ tif->tif_tagmethods.vgetfield = Fax3VGetField; /* hook for codec tags */
+ sp->vsetparent = tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vsetfield = Fax3VSetField; /* hook for codec tags */
+ sp->printdir = tif->tif_tagmethods.printdir;
+ tif->tif_tagmethods.printdir = Fax3PrintDir; /* hook for codec tags */
+ sp->groupoptions = 0;
+ sp->recvparams = 0;
+ sp->subaddress = NULL;
+ sp->faxdcs = NULL;
+
+ if (sp->rw_mode == O_RDONLY) /* FIXME: improve for in place update */
+ tif->tif_flags |= TIFF_NOBITREV; /* decoder does bit reversal */
+ DecoderState(tif)->runs = NULL;
+ TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, _TIFFFax3fillruns);
+ EncoderState(tif)->refline = NULL;
+
+ /*
+ * Install codec methods.
+ */
+ tif->tif_setupdecode = Fax3SetupState;
+ tif->tif_predecode = Fax3PreDecode;
+ tif->tif_decoderow = Fax3Decode1D;
+ tif->tif_decodestrip = Fax3Decode1D;
+ tif->tif_decodetile = Fax3Decode1D;
+ tif->tif_setupencode = Fax3SetupState;
+ tif->tif_preencode = Fax3PreEncode;
+ tif->tif_postencode = Fax3PostEncode;
+ tif->tif_encoderow = Fax3Encode;
+ tif->tif_encodestrip = Fax3Encode;
+ tif->tif_encodetile = Fax3Encode;
+ tif->tif_close = Fax3Close;
+ tif->tif_cleanup = Fax3Cleanup;
+
+ return (1);
+}
+
+int
+TIFFInitCCITTFax3(TIFF* tif, int scheme)
+{
+ (void) scheme;
+ if (InitCCITTFax3(tif)) {
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, fax3FieldInfo, N(fax3FieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax3",
+ "Merging CCITT Fax 3 codec-specific tags failed");
+ return 0;
+ }
+
+ /*
+ * The default format is Class/F-style w/o RTC.
+ */
+ return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_CLASSF);
+ } else
+ return 01;
+}
+
+/*
+ * CCITT Group 4 (T.6) Facsimile-compatible
+ * Compression Scheme Support.
+ */
+
+#define SWAP(t,a,b) { t x; x = (a); (a) = (b); (b) = x; }
+/*
+ * Decode the requested amount of G4-encoded data.
+ */
+static int
+Fax4Decode(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s)
+{
+ DECLARE_STATE_2D(tif, sp, "Fax4Decode");
+
+ (void) s;
+ CACHE_STATE(tif, sp);
+ while ((long)occ > 0) {
+ a0 = 0;
+ RunLength = 0;
+ pa = thisrun = sp->curruns;
+ pb = sp->refruns;
+ b1 = *pb++;
+#ifdef FAX3_DEBUG
+ printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", tif->tif_row);
+ fflush(stdout);
+#endif
+ EXPAND2D(EOFG4);
+ if (EOLcnt)
+ goto EOFG4;
+ (*sp->fill)(buf, thisrun, pa, lastx);
+ SETVALUE(0); /* imaginary change for reference */
+ SWAP(uint32*, sp->curruns, sp->refruns);
+ buf += sp->b.rowbytes;
+ occ -= sp->b.rowbytes;
+ sp->line++;
+ continue;
+ EOFG4:
+ NeedBits16( 13, BADG4 );
+ BADG4:
+#ifdef FAX3_DEBUG
+ if( GetBits(13) != 0x1001 )
+ fputs( "Bad EOFB\n", stderr );
+#endif
+ ClrBits( 13 );
+ (*sp->fill)(buf, thisrun, pa, lastx);
+ UNCACHE_STATE(tif, sp);
+ return ( sp->line ? 1 : -1); /* don't error on badly-terminated strips */
+ }
+ UNCACHE_STATE(tif, sp);
+ return (1);
+}
+#undef SWAP
+
+/*
+ * Encode the requested amount of data.
+ */
+static int
+Fax4Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ Fax3CodecState *sp = EncoderState(tif);
+
+ (void) s;
+ while ((long)cc > 0) {
+ if (!Fax3Encode2DRow(tif, bp, sp->refline, sp->b.rowpixels))
+ return (0);
+ _TIFFmemcpy(sp->refline, bp, sp->b.rowbytes);
+ bp += sp->b.rowbytes;
+ cc -= sp->b.rowbytes;
+ }
+ return (1);
+}
+
+static int
+Fax4PostEncode(TIFF* tif)
+{
+ Fax3CodecState *sp = EncoderState(tif);
+
+ /* terminate strip w/ EOFB */
+ Fax3PutBits(tif, EOL, 12);
+ Fax3PutBits(tif, EOL, 12);
+ if (sp->bit != 8)
+ Fax3FlushBits(tif, sp);
+ return (1);
+}
+
+int
+TIFFInitCCITTFax4(TIFF* tif, int scheme)
+{
+ (void) scheme;
+ if (InitCCITTFax3(tif)) { /* reuse G3 support */
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, fax4FieldInfo, N(fax4FieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata, "TIFFInitCCITTFax4",
+ "Merging CCITT Fax 4 codec-specific tags failed");
+ return 0;
+ }
+
+ tif->tif_decoderow = Fax4Decode;
+ tif->tif_decodestrip = Fax4Decode;
+ tif->tif_decodetile = Fax4Decode;
+ tif->tif_encoderow = Fax4Encode;
+ tif->tif_encodestrip = Fax4Encode;
+ tif->tif_encodetile = Fax4Encode;
+ tif->tif_postencode = Fax4PostEncode;
+ /*
+ * Suppress RTC at the end of each strip.
+ */
+ return TIFFSetField(tif, TIFFTAG_FAXMODE, FAXMODE_NORTC);
+ } else
+ return (0);
+}
+
+/*
+ * CCITT Group 3 1-D Modified Huffman RLE Compression Support.
+ * (Compression algorithms 2 and 32771)
+ */
+
+/*
+ * Decode the requested amount of RLE-encoded data.
+ */
+static int
+Fax3DecodeRLE(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s)
+{
+ DECLARE_STATE(tif, sp, "Fax3DecodeRLE");
+ int mode = sp->b.mode;
+
+ (void) s;
+ CACHE_STATE(tif, sp);
+ thisrun = sp->curruns;
+ while ((long)occ > 0) {
+ a0 = 0;
+ RunLength = 0;
+ pa = thisrun;
+#ifdef FAX3_DEBUG
+ printf("\nBitAcc=%08X, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", tif->tif_row);
+ fflush(stdout);
+#endif
+ EXPAND1D(EOFRLE);
+ (*sp->fill)(buf, thisrun, pa, lastx);
+ /*
+ * Cleanup at the end of the row.
+ */
+ if (mode & FAXMODE_BYTEALIGN) {
+ int n = BitsAvail - (BitsAvail &~ 7);
+ ClrBits(n);
+ } else if (mode & FAXMODE_WORDALIGN) {
+ int n = BitsAvail - (BitsAvail &~ 15);
+ ClrBits(n);
+ if (BitsAvail == 0 && !isAligned(cp, uint16))
+ cp++;
+ }
+ buf += sp->b.rowbytes;
+ occ -= sp->b.rowbytes;
+ sp->line++;
+ continue;
+ EOFRLE: /* premature EOF */
+ (*sp->fill)(buf, thisrun, pa, lastx);
+ UNCACHE_STATE(tif, sp);
+ return (-1);
+ }
+ UNCACHE_STATE(tif, sp);
+ return (1);
+}
+
+int
+TIFFInitCCITTRLE(TIFF* tif, int scheme)
+{
+ (void) scheme;
+ if (InitCCITTFax3(tif)) { /* reuse G3 support */
+ tif->tif_decoderow = Fax3DecodeRLE;
+ tif->tif_decodestrip = Fax3DecodeRLE;
+ tif->tif_decodetile = Fax3DecodeRLE;
+ /*
+ * Suppress RTC+EOLs when encoding and byte-align data.
+ */
+ return TIFFSetField(tif, TIFFTAG_FAXMODE,
+ FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_BYTEALIGN);
+ } else
+ return (0);
+}
+
+int
+TIFFInitCCITTRLEW(TIFF* tif, int scheme)
+{
+ (void) scheme;
+ if (InitCCITTFax3(tif)) { /* reuse G3 support */
+ tif->tif_decoderow = Fax3DecodeRLE;
+ tif->tif_decodestrip = Fax3DecodeRLE;
+ tif->tif_decodetile = Fax3DecodeRLE;
+ /*
+ * Suppress RTC+EOLs when encoding and word-align data.
+ */
+ return TIFFSetField(tif, TIFFTAG_FAXMODE,
+ FAXMODE_NORTC|FAXMODE_NOEOL|FAXMODE_WORDALIGN);
+ } else
+ return (0);
+}
+#endif /* CCITT_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_fax3.h b/tiff/libtiff/tif_fax3.h
new file mode 100644
index 0000000..40718bc
--- /dev/null
+++ b/tiff/libtiff/tif_fax3.h
@@ -0,0 +1,532 @@
+/* $Id: tif_fax3.h,v 1.5.2.1 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _FAX3_
+#define _FAX3_
+/*
+ * TIFF Library.
+ *
+ * CCITT Group 3 (T.4) and Group 4 (T.6) Decompression Support.
+ *
+ * Decoder support is derived, with permission, from the code
+ * in Frank Cringle's viewfax program;
+ * Copyright (C) 1990, 1995 Frank D. Cringle.
+ */
+#include "tiff.h"
+
+/*
+ * To override the default routine used to image decoded
+ * spans one can use the pseduo tag TIFFTAG_FAXFILLFUNC.
+ * The routine must have the type signature given below;
+ * for example:
+ *
+ * fillruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
+ *
+ * where buf is place to set the bits, runs is the array of b&w run
+ * lengths (white then black), erun is the last run in the array, and
+ * lastx is the width of the row in pixels. Fill routines can assume
+ * the run array has room for at least lastx runs and can overwrite
+ * data in the run array as needed (e.g. to append zero runs to bring
+ * the count up to a nice multiple).
+ */
+typedef void (*TIFFFaxFillFunc)(unsigned char*, uint32*, uint32*, uint32);
+
+/*
+ * The default run filler; made external for other decoders.
+ */
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern void _TIFFFax3fillruns(unsigned char*, uint32*, uint32*, uint32);
+#if defined(__cplusplus)
+}
+#endif
+
+
+/* finite state machine codes */
+#define S_Null 0
+#define S_Pass 1
+#define S_Horiz 2
+#define S_V0 3
+#define S_VR 4
+#define S_VL 5
+#define S_Ext 6
+#define S_TermW 7
+#define S_TermB 8
+#define S_MakeUpW 9
+#define S_MakeUpB 10
+#define S_MakeUp 11
+#define S_EOL 12
+
+typedef struct { /* state table entry */
+ unsigned char State; /* see above */
+ unsigned char Width; /* width of code in bits */
+ uint32 Param; /* unsigned 32-bit run length in bits */
+} TIFFFaxTabEnt;
+
+extern const TIFFFaxTabEnt TIFFFaxMainTable[];
+extern const TIFFFaxTabEnt TIFFFaxWhiteTable[];
+extern const TIFFFaxTabEnt TIFFFaxBlackTable[];
+
+/*
+ * The following macros define the majority of the G3/G4 decoder
+ * algorithm using the state tables defined elsewhere. To build
+ * a decoder you need some setup code and some glue code. Note
+ * that you may also need/want to change the way the NeedBits*
+ * macros get input data if, for example, you know the data to be
+ * decoded is properly aligned and oriented (doing so before running
+ * the decoder can be a big performance win).
+ *
+ * Consult the decoder in the TIFF library for an idea of what you
+ * need to define and setup to make use of these definitions.
+ *
+ * NB: to enable a debugging version of these macros define FAX3_DEBUG
+ * before including this file. Trace output goes to stdout.
+ */
+
+#ifndef EndOfData
+#define EndOfData() (cp >= ep)
+#endif
+/*
+ * Need <=8 or <=16 bits of input data. Unlike viewfax we
+ * cannot use/assume a word-aligned, properly bit swizzled
+ * input data set because data may come from an arbitrarily
+ * aligned, read-only source such as a memory-mapped file.
+ * Note also that the viewfax decoder does not check for
+ * running off the end of the input data buffer. This is
+ * possible for G3-encoded data because it prescans the input
+ * data to count EOL markers, but can cause problems for G4
+ * data. In any event, we don't prescan and must watch for
+ * running out of data since we can't permit the library to
+ * scan past the end of the input data buffer.
+ *
+ * Finally, note that we must handle remaindered data at the end
+ * of a strip specially. The coder asks for a fixed number of
+ * bits when scanning for the next code. This may be more bits
+ * than are actually present in the data stream. If we appear
+ * to run out of data but still have some number of valid bits
+ * remaining then we makeup the requested amount with zeros and
+ * return successfully. If the returned data is incorrect then
+ * we should be called again and get a premature EOF error;
+ * otherwise we should get the right answer.
+ */
+#ifndef NeedBits8
+#define NeedBits8(n,eoflab) do { \
+ if (BitsAvail < (n)) { \
+ if (EndOfData()) { \
+ if (BitsAvail == 0) /* no valid bits */ \
+ goto eoflab; \
+ BitsAvail = (n); /* pad with zeros */ \
+ } else { \
+ BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \
+ BitsAvail += 8; \
+ } \
+ } \
+} while (0)
+#endif
+#ifndef NeedBits16
+#define NeedBits16(n,eoflab) do { \
+ if (BitsAvail < (n)) { \
+ if (EndOfData()) { \
+ if (BitsAvail == 0) /* no valid bits */ \
+ goto eoflab; \
+ BitsAvail = (n); /* pad with zeros */ \
+ } else { \
+ BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \
+ if ((BitsAvail += 8) < (n)) { \
+ if (EndOfData()) { \
+ /* NB: we know BitsAvail is non-zero here */ \
+ BitsAvail = (n); /* pad with zeros */ \
+ } else { \
+ BitAcc |= ((uint32) bitmap[*cp++])<<BitsAvail; \
+ BitsAvail += 8; \
+ } \
+ } \
+ } \
+ } \
+} while (0)
+#endif
+#define GetBits(n) (BitAcc & ((1<<(n))-1))
+#define ClrBits(n) do { \
+ BitsAvail -= (n); \
+ BitAcc >>= (n); \
+} while (0)
+
+#ifdef FAX3_DEBUG
+static const char* StateNames[] = {
+ "Null ",
+ "Pass ",
+ "Horiz ",
+ "V0 ",
+ "VR ",
+ "VL ",
+ "Ext ",
+ "TermW ",
+ "TermB ",
+ "MakeUpW",
+ "MakeUpB",
+ "MakeUp ",
+ "EOL ",
+};
+#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
+#define LOOKUP8(wid,tab,eoflab) do { \
+ int t; \
+ NeedBits8(wid,eoflab); \
+ TabEnt = tab + GetBits(wid); \
+ printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \
+ StateNames[TabEnt->State], TabEnt->Param); \
+ for (t = 0; t < TabEnt->Width; t++) \
+ DEBUG_SHOW; \
+ putchar('\n'); \
+ fflush(stdout); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+#define LOOKUP16(wid,tab,eoflab) do { \
+ int t; \
+ NeedBits16(wid,eoflab); \
+ TabEnt = tab + GetBits(wid); \
+ printf("%08lX/%d: %s%5d\t", (long) BitAcc, BitsAvail, \
+ StateNames[TabEnt->State], TabEnt->Param); \
+ for (t = 0; t < TabEnt->Width; t++) \
+ DEBUG_SHOW; \
+ putchar('\n'); \
+ fflush(stdout); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+
+#define SETVALUE(x) do { \
+ *pa++ = RunLength + (x); \
+ printf("SETVALUE: %d\t%d\n", RunLength + (x), a0); \
+ a0 += x; \
+ RunLength = 0; \
+} while (0)
+#else
+#define LOOKUP8(wid,tab,eoflab) do { \
+ NeedBits8(wid,eoflab); \
+ TabEnt = tab + GetBits(wid); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+#define LOOKUP16(wid,tab,eoflab) do { \
+ NeedBits16(wid,eoflab); \
+ TabEnt = tab + GetBits(wid); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+
+/*
+ * Append a run to the run length array for the
+ * current row and reset decoding state.
+ */
+#define SETVALUE(x) do { \
+ *pa++ = RunLength + (x); \
+ a0 += (x); \
+ RunLength = 0; \
+} while (0)
+#endif
+
+/*
+ * Synchronize input decoding at the start of each
+ * row by scanning for an EOL (if appropriate) and
+ * skipping any trash data that might be present
+ * after a decoding error. Note that the decoding
+ * done elsewhere that recognizes an EOL only consumes
+ * 11 consecutive zero bits. This means that if EOLcnt
+ * is non-zero then we still need to scan for the final flag
+ * bit that is part of the EOL code.
+ */
+#define SYNC_EOL(eoflab) do { \
+ if (EOLcnt == 0) { \
+ for (;;) { \
+ NeedBits16(11,eoflab); \
+ if (GetBits(11) == 0) \
+ break; \
+ ClrBits(1); \
+ } \
+ } \
+ for (;;) { \
+ NeedBits8(8,eoflab); \
+ if (GetBits(8)) \
+ break; \
+ ClrBits(8); \
+ } \
+ while (GetBits(1) == 0) \
+ ClrBits(1); \
+ ClrBits(1); /* EOL bit */ \
+ EOLcnt = 0; /* reset EOL counter/flag */ \
+} while (0)
+
+/*
+ * Cleanup the array of runs after decoding a row.
+ * We adjust final runs to insure the user buffer is not
+ * overwritten and/or undecoded area is white filled.
+ */
+#define CLEANUP_RUNS() do { \
+ if (RunLength) \
+ SETVALUE(0); \
+ if (a0 != lastx) { \
+ badlength(a0, lastx); \
+ while (a0 > lastx && pa > thisrun) \
+ a0 -= *--pa; \
+ if (a0 < lastx) { \
+ if (a0 < 0) \
+ a0 = 0; \
+ if ((pa-thisrun)&1) \
+ SETVALUE(0); \
+ SETVALUE(lastx - a0); \
+ } else if (a0 > lastx) { \
+ SETVALUE(lastx); \
+ SETVALUE(0); \
+ } \
+ } \
+} while (0)
+
+/*
+ * Decode a line of 1D-encoded data.
+ *
+ * The line expanders are written as macros so that they can be reused
+ * but still have direct access to the local variables of the "calling"
+ * function.
+ *
+ * Note that unlike the original version we have to explicitly test for
+ * a0 >= lastx after each black/white run is decoded. This is because
+ * the original code depended on the input data being zero-padded to
+ * insure the decoder recognized an EOL before running out of data.
+ */
+#define EXPAND1D(eoflab) do { \
+ for (;;) { \
+ for (;;) { \
+ LOOKUP16(12, TIFFFaxWhiteTable, eof1d); \
+ switch (TabEnt->State) { \
+ case S_EOL: \
+ EOLcnt = 1; \
+ goto done1d; \
+ case S_TermW: \
+ SETVALUE(TabEnt->Param); \
+ goto doneWhite1d; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("WhiteTable", a0); \
+ goto done1d; \
+ } \
+ } \
+ doneWhite1d: \
+ if (a0 >= lastx) \
+ goto done1d; \
+ for (;;) { \
+ LOOKUP16(13, TIFFFaxBlackTable, eof1d); \
+ switch (TabEnt->State) { \
+ case S_EOL: \
+ EOLcnt = 1; \
+ goto done1d; \
+ case S_TermB: \
+ SETVALUE(TabEnt->Param); \
+ goto doneBlack1d; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("BlackTable", a0); \
+ goto done1d; \
+ } \
+ } \
+ doneBlack1d: \
+ if (a0 >= lastx) \
+ goto done1d; \
+ if( *(pa-1) == 0 && *(pa-2) == 0 ) \
+ pa -= 2; \
+ } \
+eof1d: \
+ prematureEOF(a0); \
+ CLEANUP_RUNS(); \
+ goto eoflab; \
+done1d: \
+ CLEANUP_RUNS(); \
+} while (0)
+
+/*
+ * Update the value of b1 using the array
+ * of runs for the reference line.
+ */
+#define CHECK_b1 do { \
+ if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \
+ b1 += pb[0] + pb[1]; \
+ pb += 2; \
+ } \
+} while (0)
+
+/*
+ * Expand a row of 2D-encoded data.
+ */
+#define EXPAND2D(eoflab) do { \
+ while (a0 < lastx) { \
+ LOOKUP8(7, TIFFFaxMainTable, eof2d); \
+ switch (TabEnt->State) { \
+ case S_Pass: \
+ CHECK_b1; \
+ b1 += *pb++; \
+ RunLength += b1 - a0; \
+ a0 = b1; \
+ b1 += *pb++; \
+ break; \
+ case S_Horiz: \
+ if ((pa-thisrun)&1) { \
+ for (;;) { /* black first */ \
+ LOOKUP16(13, TIFFFaxBlackTable, eof2d); \
+ switch (TabEnt->State) { \
+ case S_TermB: \
+ SETVALUE(TabEnt->Param); \
+ goto doneWhite2da; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ goto badBlack2d; \
+ } \
+ } \
+ doneWhite2da:; \
+ for (;;) { /* then white */ \
+ LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \
+ switch (TabEnt->State) { \
+ case S_TermW: \
+ SETVALUE(TabEnt->Param); \
+ goto doneBlack2da; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ goto badWhite2d; \
+ } \
+ } \
+ doneBlack2da:; \
+ } else { \
+ for (;;) { /* white first */ \
+ LOOKUP16(12, TIFFFaxWhiteTable, eof2d); \
+ switch (TabEnt->State) { \
+ case S_TermW: \
+ SETVALUE(TabEnt->Param); \
+ goto doneWhite2db; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ goto badWhite2d; \
+ } \
+ } \
+ doneWhite2db:; \
+ for (;;) { /* then black */ \
+ LOOKUP16(13, TIFFFaxBlackTable, eof2d); \
+ switch (TabEnt->State) { \
+ case S_TermB: \
+ SETVALUE(TabEnt->Param); \
+ goto doneBlack2db; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ goto badBlack2d; \
+ } \
+ } \
+ doneBlack2db:; \
+ } \
+ CHECK_b1; \
+ break; \
+ case S_V0: \
+ CHECK_b1; \
+ SETVALUE(b1 - a0); \
+ b1 += *pb++; \
+ break; \
+ case S_VR: \
+ CHECK_b1; \
+ SETVALUE(b1 - a0 + TabEnt->Param); \
+ b1 += *pb++; \
+ break; \
+ case S_VL: \
+ CHECK_b1; \
+ SETVALUE(b1 - a0 - TabEnt->Param); \
+ b1 -= *--pb; \
+ break; \
+ case S_Ext: \
+ *pa++ = lastx - a0; \
+ extension(a0); \
+ goto eol2d; \
+ case S_EOL: \
+ *pa++ = lastx - a0; \
+ NeedBits8(4,eof2d); \
+ if (GetBits(4)) \
+ unexpected("EOL", a0); \
+ ClrBits(4); \
+ EOLcnt = 1; \
+ goto eol2d; \
+ default: \
+ badMain2d: \
+ unexpected("MainTable", a0); \
+ goto eol2d; \
+ badBlack2d: \
+ unexpected("BlackTable", a0); \
+ goto eol2d; \
+ badWhite2d: \
+ unexpected("WhiteTable", a0); \
+ goto eol2d; \
+ eof2d: \
+ prematureEOF(a0); \
+ CLEANUP_RUNS(); \
+ goto eoflab; \
+ } \
+ } \
+ if (RunLength) { \
+ if (RunLength + a0 < lastx) { \
+ /* expect a final V0 */ \
+ NeedBits8(1,eof2d); \
+ if (!GetBits(1)) \
+ goto badMain2d; \
+ ClrBits(1); \
+ } \
+ SETVALUE(0); \
+ } \
+eol2d: \
+ CLEANUP_RUNS(); \
+} while (0)
+#endif /* _FAX3_ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_fax3sm.c b/tiff/libtiff/tif_fax3sm.c
new file mode 100644
index 0000000..b2c6729
--- /dev/null
+++ b/tiff/libtiff/tif_fax3sm.c
@@ -0,0 +1,1253 @@
+/* WARNING, this file was automatically generated by the
+ mkg3states program */
+#include "tiff.h"
+#include "tif_fax3.h"
+ const TIFFFaxTabEnt TIFFFaxMainTable[128] = {
+12,7,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,
+5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,5,6,2,3,1,0,5,3,1,3,1,0,
+2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,
+4,3,1,3,1,0,5,7,3,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,
+1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,4,6,2,3,1,0,
+5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0,
+2,3,0,3,1,0,4,3,1,3,1,0,6,7,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,
+4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,
+5,6,2,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,
+5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,4,7,3,3,1,0,5,3,1,3,1,0,
+2,3,0,3,1,0,4,3,1,3,1,0,1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,
+4,3,1,3,1,0,4,6,2,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0,
+1,4,0,3,1,0,5,3,1,3,1,0,2,3,0,3,1,0,4,3,1,3,1,0
+};
+ const TIFFFaxTabEnt TIFFFaxWhiteTable[4096] = {
+12,11,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,
+7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,
+7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,
+7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,
+7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,
+7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,
+7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,11,1792,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,
+7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,
+9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,
+7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5,
+7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,
+7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,
+9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,
+7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,
+7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,
+7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,
+7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,
+9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,
+7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,
+7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6,
+7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,11,11,1856,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,
+7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,
+7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,
+7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,
+7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,
+9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,
+7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,
+7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,
+7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,
+9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,
+7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6,
+7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,
+7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,
+9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,
+9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+11,12,2112,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,
+7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,
+7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,
+7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,
+7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,
+7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,
+7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,
+7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,
+9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,
+7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5,
+7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,
+7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,
+9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,12,2368,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,
+7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6,
+7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,
+7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,
+7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,
+9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,
+7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,
+7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,
+7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,
+7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,
+7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,
+7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,
+7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,
+9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,
+7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,
+7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,11,12,1984,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,
+7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,
+9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,
+7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,
+7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,
+7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,
+9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,
+9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,
+7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,
+7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,
+7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,
+7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,
+7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,
+7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,11,1920,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,
+7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,
+9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,
+7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5,
+7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,
+7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,
+9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,
+7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,
+7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,
+7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,
+7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,
+9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,
+7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,
+7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6,
+7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,11,12,2240,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,
+7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,
+7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,
+7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,
+7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,
+9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,
+7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,
+7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,
+7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,
+9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,
+7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6,
+7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,
+7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,
+9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,
+9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+11,12,2496,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,
+7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,
+7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,
+7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,
+7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,
+7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,
+7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,12,11,0,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,
+7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,
+9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,
+7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5,
+7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,
+7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,
+9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,11,1792,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,
+7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6,
+7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,
+7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,
+7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,
+9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,
+7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,
+7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,
+7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,
+7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,
+7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,
+7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,
+7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,
+9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,
+7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,
+7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,11,11,1856,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,
+7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,
+9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,
+7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6,
+7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,
+7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,
+9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,
+9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,
+7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,
+7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,
+7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,
+7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6,7,8,31,7,5,8,
+7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,
+7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,12,2176,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,
+7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,
+9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,
+7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1600,7,4,5,
+7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,
+7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,
+9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,
+7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,
+7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,
+7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,
+7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5,7,8,43,7,6,17,
+9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,
+7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,
+7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,768,7,4,6,
+7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,11,12,2432,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,
+7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6,7,7,19,7,5,8,
+7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,
+7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,9,9,1408,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,
+7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,
+9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,
+7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,
+7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,
+7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,
+9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,
+7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,960,7,4,6,
+7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,
+7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,
+9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,
+9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+11,12,2048,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,
+7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,
+7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,
+7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,
+7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,7,8,32,7,5,8,
+7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,
+7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,
+7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,
+9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,
+7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1536,7,4,5,
+7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,
+7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,
+9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,11,1920,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,
+7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,9,9,896,7,4,6,
+7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,
+7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,
+7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5,7,8,44,7,6,17,
+9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,
+7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,
+7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,
+7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,
+7,7,23,7,4,3,7,7,27,7,4,5,7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,
+7,8,55,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,
+7,8,53,7,5,9,9,8,448,7,4,6,7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,9,9,1472,7,4,5,7,8,43,7,6,17,9,9,1216,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,
+7,8,61,7,4,4,7,4,2,7,4,7,7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,
+9,9,960,7,4,6,7,8,31,7,5,8,7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,9,9,704,7,4,6,7,8,37,9,5,128,
+7,7,25,7,6,15,9,8,320,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,
+7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,11,12,2304,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,7,20,9,5,128,7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,
+7,7,27,7,4,5,7,8,40,7,6,16,9,9,832,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,
+9,8,512,7,4,6,7,8,36,9,5,128,7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,9,9,1600,7,4,5,7,8,44,7,6,17,9,9,1344,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,
+7,6,12,7,5,9,9,6,1664,7,4,6,7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,
+7,4,2,7,4,7,7,8,48,7,4,3,7,8,60,7,4,5,7,8,42,7,6,16,9,9,1088,7,4,6,
+7,8,32,7,5,8,7,8,58,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,
+7,5,11,7,4,5,7,7,26,7,5,9,9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,
+9,8,384,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,
+9,7,256,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+0,0,0,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,
+7,7,24,7,6,14,7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,
+7,8,39,7,6,16,9,8,576,7,4,6,7,7,19,7,5,8,7,8,55,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,45,7,4,3,7,5,11,7,4,5,7,8,53,7,5,9,9,8,448,7,4,6,
+7,8,35,9,5,128,7,8,51,7,6,15,7,8,63,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,
+9,9,1536,7,4,5,7,8,43,7,6,17,9,9,1280,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,8,29,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,
+9,6,1664,7,4,6,7,8,33,9,5,128,7,8,49,7,6,14,7,8,61,7,4,4,7,4,2,7,4,7,
+7,8,47,7,4,3,7,8,59,7,4,5,7,8,41,7,6,16,9,9,1024,7,4,6,7,8,31,7,5,8,
+7,8,57,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,
+7,7,26,7,5,9,9,9,768,7,4,6,7,8,37,9,5,128,7,7,25,7,6,15,9,8,320,7,4,4,
+7,4,2,7,4,7,7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,
+7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,11,12,2560,7,4,3,
+7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,7,7,20,9,5,128,7,7,24,7,6,14,
+7,7,28,7,4,4,7,4,2,7,4,7,7,7,23,7,4,3,7,7,27,7,4,5,7,8,40,7,6,16,
+9,9,896,7,4,6,7,7,19,7,5,8,7,8,56,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7,
+7,8,46,7,4,3,7,5,11,7,4,5,7,8,54,7,5,9,9,8,512,7,4,6,7,8,36,9,5,128,
+7,8,52,7,6,15,7,8,0,7,4,4,7,4,2,7,4,7,7,6,13,7,4,3,9,9,1728,7,4,5,
+7,8,44,7,6,17,9,9,1408,7,4,6,7,6,1,7,5,8,9,6,192,9,5,64,7,5,10,7,4,4,
+7,4,2,7,4,7,7,8,30,7,4,3,7,5,11,7,4,5,7,6,12,7,5,9,9,6,1664,7,4,6,
+7,8,34,9,5,128,7,8,50,7,6,14,7,8,62,7,4,4,7,4,2,7,4,7,7,8,48,7,4,3,
+7,8,60,7,4,5,7,8,42,7,6,16,9,9,1152,7,4,6,7,8,32,7,5,8,7,8,58,9,5,64,
+7,5,10,7,4,4,7,4,2,7,4,7,7,7,22,7,4,3,7,5,11,7,4,5,7,7,26,7,5,9,
+9,8,640,7,4,6,7,8,38,9,5,128,7,7,25,7,6,15,9,8,384,7,4,4,7,4,2,7,4,7,
+7,6,13,7,4,3,7,7,18,7,4,5,7,7,21,7,6,17,9,7,256,7,4,6,7,6,1,7,5,8,
+9,6,192,9,5,64,7,5,10,7,4,4,7,4,2,7,4,7
+};
+ const TIFFFaxTabEnt TIFFFaxBlackTable[8192] = {
+12,11,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1792,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,11,23,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,20,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,11,25,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,12,128,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,56,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,30,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,11,11,1856,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,57,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,11,21,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,54,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,52,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,48,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+11,12,2112,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,44,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,36,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,12,384,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,28,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,60,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,40,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2368,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,11,12,1984,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,50,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,34,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1664,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,26,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,13,1408,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,32,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1920,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,61,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,42,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,10,13,1024,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,13,768,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,62,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,11,12,2240,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,46,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,38,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,512,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,11,19,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,24,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,22,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+11,12,2496,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,12,11,0,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1792,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,23,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,11,20,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,11,25,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,10,12,192,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1280,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,31,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,11,11,1856,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,58,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,11,21,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,896,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,13,640,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,49,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2176,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,45,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,37,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,10,12,448,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,29,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,13,1536,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,41,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,11,12,2432,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+11,12,2048,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,51,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,35,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,12,320,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,27,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,59,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,33,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1920,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,12,256,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,43,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,13,1152,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,55,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,63,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,11,12,2304,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,47,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,39,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,53,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,19,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,11,24,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,22,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2560,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,12,11,0,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,11,11,1792,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,23,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,11,20,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,25,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,12,128,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,56,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,30,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+11,11,1856,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,57,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,21,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,54,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,52,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,48,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2112,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,44,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,36,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,12,384,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,28,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,60,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,40,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,11,12,2368,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,1984,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,50,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,34,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,10,13,1728,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,26,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,13,1472,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,32,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,11,11,1920,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,61,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,42,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1088,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,832,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,62,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+11,12,2240,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,46,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,38,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,13,576,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,19,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,11,24,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,11,22,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2496,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,12,11,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,18,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,11,11,1792,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,11,23,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,11,20,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,25,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,12,192,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,13,1344,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,31,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,11,1856,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,58,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,11,21,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,10,13,960,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,13,704,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,49,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,11,12,2176,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,45,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,37,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,12,448,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,29,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1600,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,41,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+11,12,2432,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,0,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,10,18,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,10,17,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2048,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,51,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,35,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+10,12,320,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,27,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,59,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,33,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,11,11,1920,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,10,12,256,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,43,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,13,1216,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+0,0,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,8,13,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,9,15,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,12,55,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,63,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,11,12,2304,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,12,47,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,12,39,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,12,53,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,12,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,0,0,0,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,8,13,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,11,19,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,11,24,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,11,22,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,11,12,2560,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,7,10,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,10,16,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2,8,10,0,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,
+8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,10,10,64,8,2,3,
+8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,9,8,2,3,8,3,1,8,2,2,
+8,4,5,8,2,3,8,3,4,8,2,2,8,7,11,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,
+8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,
+8,8,14,8,2,3,8,3,1,8,2,2,8,4,6,8,2,3,8,3,4,8,2,2,8,6,8,8,2,3,
+8,3,1,8,2,2,8,4,5,8,2,3,8,3,4,8,2,2,8,7,12,8,2,3,8,3,1,8,2,2,
+8,4,6,8,2,3,8,3,4,8,2,2,8,5,7,8,2,3,8,3,1,8,2,2,8,4,5,8,2,3,
+8,3,4,8,2,2
+};
diff --git a/tiff/libtiff/tif_flush.c b/tiff/libtiff/tif_flush.c
new file mode 100644
index 0000000..7ecc4d8
--- /dev/null
+++ b/tiff/libtiff/tif_flush.c
@@ -0,0 +1,74 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_flush.c,v 1.3.2.1 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+int
+TIFFFlush(TIFF* tif)
+{
+
+ if (tif->tif_mode != O_RDONLY) {
+ if (!TIFFFlushData(tif))
+ return (0);
+ if ((tif->tif_flags & TIFF_DIRTYDIRECT) &&
+ !TIFFWriteDirectory(tif))
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Flush buffered data to the file.
+ *
+ * Frank Warmerdam'2000: I modified this to return 1 if TIFF_BEENWRITING
+ * is not set, so that TIFFFlush() will proceed to write out the directory.
+ * The documentation says returning 1 is an error indicator, but not having
+ * been writing isn't exactly a an error. Hopefully this doesn't cause
+ * problems for other people.
+ */
+int
+TIFFFlushData(TIFF* tif)
+{
+ if ((tif->tif_flags & TIFF_BEENWRITING) == 0)
+ return (0);
+ if (tif->tif_flags & TIFF_POSTENCODE) {
+ tif->tif_flags &= ~TIFF_POSTENCODE;
+ if (!(*tif->tif_postencode)(tif))
+ return (0);
+ }
+ return (TIFFFlushData1(tif));
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_getimage.c b/tiff/libtiff/tif_getimage.c
new file mode 100644
index 0000000..38455fb
--- /dev/null
+++ b/tiff/libtiff/tif_getimage.c
@@ -0,0 +1,2676 @@
+/* $Id: tif_getimage.c,v 1.63.2.4 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Read and return a packed RGBA image.
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+
+static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32);
+static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32);
+static int gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32);
+static int gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32);
+static int PickContigCase(TIFFRGBAImage*);
+static int PickSeparateCase(TIFFRGBAImage*);
+static const char photoTag[] = "PhotometricInterpretation";
+
+/*
+ * Helper constants used in Orientation tag handling
+ */
+#define FLIP_VERTICALLY 0x01
+#define FLIP_HORIZONTALLY 0x02
+
+/*
+ * Color conversion constants. We will define display types here.
+ */
+
+TIFFDisplay display_sRGB = {
+ { /* XYZ -> luminance matrix */
+ { 3.2410F, -1.5374F, -0.4986F },
+ { -0.9692F, 1.8760F, 0.0416F },
+ { 0.0556F, -0.2040F, 1.0570F }
+ },
+ 100.0F, 100.0F, 100.0F, /* Light o/p for reference white */
+ 255, 255, 255, /* Pixel values for ref. white */
+ 1.0F, 1.0F, 1.0F, /* Residual light o/p for black pixel */
+ 2.4F, 2.4F, 2.4F, /* Gamma values for the three guns */
+};
+
+/*
+ * Check the image to see if TIFFReadRGBAImage can deal with it.
+ * 1/0 is returned according to whether or not the image can
+ * be handled. If 0 is returned, emsg contains the reason
+ * why it is being rejected.
+ */
+int
+TIFFRGBAImageOK(TIFF* tif, char emsg[1024])
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ uint16 photometric;
+ int colorchannels;
+
+ if (!tif->tif_decodestatus) {
+ sprintf(emsg, "Sorry, requested compression method is not configured");
+ return (0);
+ }
+ switch (td->td_bitspersample) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ break;
+ default:
+ sprintf(emsg, "Sorry, can not handle images with %d-bit samples",
+ td->td_bitspersample);
+ return (0);
+ }
+ colorchannels = td->td_samplesperpixel - td->td_extrasamples;
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) {
+ switch (colorchannels) {
+ case 1:
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 3:
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ default:
+ sprintf(emsg, "Missing needed %s tag", photoTag);
+ return (0);
+ }
+ }
+ switch (photometric) {
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ case PHOTOMETRIC_PALETTE:
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG
+ && td->td_samplesperpixel != 1
+ && td->td_bitspersample < 8 ) {
+ sprintf(emsg,
+ "Sorry, can not handle contiguous data with %s=%d, "
+ "and %s=%d and Bits/Sample=%d",
+ photoTag, photometric,
+ "Samples/pixel", td->td_samplesperpixel,
+ td->td_bitspersample);
+ return (0);
+ }
+ /*
+ * We should likely validate that any extra samples are either
+ * to be ignored, or are alpha, and if alpha we should try to use
+ * them. But for now we won't bother with this.
+ */
+ break;
+ case PHOTOMETRIC_YCBCR:
+ /*
+ * TODO: if at all meaningful and useful, make more complete
+ * support check here, or better still, refactor to let supporting
+ * code decide whether there is support and what meaningfull
+ * error to return
+ */
+ break;
+ case PHOTOMETRIC_RGB:
+ if (colorchannels < 3) {
+ sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
+ "Color channels", colorchannels);
+ return (0);
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ {
+ uint16 inkset;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
+ if (inkset != INKSET_CMYK) {
+ sprintf(emsg,
+ "Sorry, can not handle separated image with %s=%d",
+ "InkSet", inkset);
+ return 0;
+ }
+ if (td->td_samplesperpixel < 4) {
+ sprintf(emsg,
+ "Sorry, can not handle separated image with %s=%d",
+ "Samples/pixel", td->td_samplesperpixel);
+ return 0;
+ }
+ break;
+ }
+ case PHOTOMETRIC_LOGL:
+ if (td->td_compression != COMPRESSION_SGILOG) {
+ sprintf(emsg, "Sorry, LogL data must have %s=%d",
+ "Compression", COMPRESSION_SGILOG);
+ return (0);
+ }
+ break;
+ case PHOTOMETRIC_LOGLUV:
+ if (td->td_compression != COMPRESSION_SGILOG &&
+ td->td_compression != COMPRESSION_SGILOG24) {
+ sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d",
+ "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24);
+ return (0);
+ }
+ if (td->td_planarconfig != PLANARCONFIG_CONTIG) {
+ sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d",
+ "Planarconfiguration", td->td_planarconfig);
+ return (0);
+ }
+ break;
+ case PHOTOMETRIC_CIELAB:
+ break;
+ default:
+ sprintf(emsg, "Sorry, can not handle image with %s=%d",
+ photoTag, photometric);
+ return (0);
+ }
+ return (1);
+}
+
+void
+TIFFRGBAImageEnd(TIFFRGBAImage* img)
+{
+ if (img->Map)
+ _TIFFfree(img->Map), img->Map = NULL;
+ if (img->BWmap)
+ _TIFFfree(img->BWmap), img->BWmap = NULL;
+ if (img->PALmap)
+ _TIFFfree(img->PALmap), img->PALmap = NULL;
+ if (img->ycbcr)
+ _TIFFfree(img->ycbcr), img->ycbcr = NULL;
+ if (img->cielab)
+ _TIFFfree(img->cielab), img->cielab = NULL;
+ if( img->redcmap ) {
+ _TIFFfree( img->redcmap );
+ _TIFFfree( img->greencmap );
+ _TIFFfree( img->bluecmap );
+ }
+}
+
+static int
+isCCITTCompression(TIFF* tif)
+{
+ uint16 compress;
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
+ return (compress == COMPRESSION_CCITTFAX3 ||
+ compress == COMPRESSION_CCITTFAX4 ||
+ compress == COMPRESSION_CCITTRLE ||
+ compress == COMPRESSION_CCITTRLEW);
+}
+
+int
+TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024])
+{
+ uint16* sampleinfo;
+ uint16 extrasamples;
+ uint16 planarconfig;
+ uint16 compress;
+ int colorchannels;
+ uint16 *red_orig, *green_orig, *blue_orig;
+ int n_color;
+
+ /* Initialize to normal values */
+ img->row_offset = 0;
+ img->col_offset = 0;
+ img->redcmap = NULL;
+ img->greencmap = NULL;
+ img->bluecmap = NULL;
+ img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */
+
+ img->tif = tif;
+ img->stoponerr = stop;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample);
+ switch (img->bitspersample) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ break;
+ default:
+ sprintf(emsg, "Sorry, can not handle images with %d-bit samples",
+ img->bitspersample);
+ return (0);
+ }
+ img->alpha = 0;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
+ &extrasamples, &sampleinfo);
+ if (extrasamples >= 1)
+ {
+ switch (sampleinfo[0]) {
+ case EXTRASAMPLE_UNSPECIFIED: /* Workaround for some images without */
+ if (img->samplesperpixel > 3) /* correct info about alpha channel */
+ img->alpha = EXTRASAMPLE_ASSOCALPHA;
+ break;
+ case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */
+ case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */
+ img->alpha = sampleinfo[0];
+ break;
+ }
+ }
+
+#ifdef DEFAULT_EXTRASAMPLE_AS_ALPHA
+ if( !TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric))
+ img->photometric = PHOTOMETRIC_MINISWHITE;
+
+ if( extrasamples == 0
+ && img->samplesperpixel == 4
+ && img->photometric == PHOTOMETRIC_RGB )
+ {
+ img->alpha = EXTRASAMPLE_ASSOCALPHA;
+ extrasamples = 1;
+ }
+#endif
+
+ colorchannels = img->samplesperpixel - extrasamples;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) {
+ switch (colorchannels) {
+ case 1:
+ if (isCCITTCompression(tif))
+ img->photometric = PHOTOMETRIC_MINISWHITE;
+ else
+ img->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 3:
+ img->photometric = PHOTOMETRIC_RGB;
+ break;
+ default:
+ sprintf(emsg, "Missing needed %s tag", photoTag);
+ return (0);
+ }
+ }
+ switch (img->photometric) {
+ case PHOTOMETRIC_PALETTE:
+ if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
+ &red_orig, &green_orig, &blue_orig)) {
+ sprintf(emsg, "Missing required \"Colormap\" tag");
+ return (0);
+ }
+
+ /* copy the colormaps so we can modify them */
+ n_color = (1L << img->bitspersample);
+ img->redcmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color);
+ img->greencmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color);
+ img->bluecmap = (uint16 *) _TIFFmalloc(sizeof(uint16)*n_color);
+ if( !img->redcmap || !img->greencmap || !img->bluecmap ) {
+ sprintf(emsg, "Out of memory for colormap copy");
+ return (0);
+ }
+
+ _TIFFmemcpy( img->redcmap, red_orig, n_color * 2 );
+ _TIFFmemcpy( img->greencmap, green_orig, n_color * 2 );
+ _TIFFmemcpy( img->bluecmap, blue_orig, n_color * 2 );
+
+ /* fall thru... */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ if (planarconfig == PLANARCONFIG_CONTIG
+ && img->samplesperpixel != 1
+ && img->bitspersample < 8 ) {
+ sprintf(emsg,
+ "Sorry, can not handle contiguous data with %s=%d, "
+ "and %s=%d and Bits/Sample=%d",
+ photoTag, img->photometric,
+ "Samples/pixel", img->samplesperpixel,
+ img->bitspersample);
+ return (0);
+ }
+ break;
+ case PHOTOMETRIC_YCBCR:
+ /* It would probably be nice to have a reality check here. */
+ if (planarconfig == PLANARCONFIG_CONTIG)
+ /* can rely on libjpeg to convert to RGB */
+ /* XXX should restore current state on exit */
+ switch (compress) {
+ case COMPRESSION_JPEG:
+ /*
+ * TODO: when complete tests verify complete desubsampling
+ * and YCbCr handling, remove use of TIFFTAG_JPEGCOLORMODE in
+ * favor of tif_getimage.c native handling
+ */
+ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ img->photometric = PHOTOMETRIC_RGB;
+ break;
+ default:
+ /* do nothing */;
+ break;
+ }
+ /*
+ * TODO: if at all meaningful and useful, make more complete
+ * support check here, or better still, refactor to let supporting
+ * code decide whether there is support and what meaningfull
+ * error to return
+ */
+ break;
+ case PHOTOMETRIC_RGB:
+ if (colorchannels < 3) {
+ sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
+ "Color channels", colorchannels);
+ return (0);
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ {
+ uint16 inkset;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
+ if (inkset != INKSET_CMYK) {
+ sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+ "InkSet", inkset);
+ return (0);
+ }
+ if (img->samplesperpixel < 4) {
+ sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
+ "Samples/pixel", img->samplesperpixel);
+ return (0);
+ }
+ }
+ break;
+ case PHOTOMETRIC_LOGL:
+ if (compress != COMPRESSION_SGILOG) {
+ sprintf(emsg, "Sorry, LogL data must have %s=%d",
+ "Compression", COMPRESSION_SGILOG);
+ return (0);
+ }
+ TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
+ img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */
+ img->bitspersample = 8;
+ break;
+ case PHOTOMETRIC_LOGLUV:
+ if (compress != COMPRESSION_SGILOG && compress != COMPRESSION_SGILOG24) {
+ sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d",
+ "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24);
+ return (0);
+ }
+ if (planarconfig != PLANARCONFIG_CONTIG) {
+ sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d",
+ "Planarconfiguration", planarconfig);
+ return (0);
+ }
+ TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
+ img->photometric = PHOTOMETRIC_RGB; /* little white lie */
+ img->bitspersample = 8;
+ break;
+ case PHOTOMETRIC_CIELAB:
+ break;
+ default:
+ sprintf(emsg, "Sorry, can not handle image with %s=%d",
+ photoTag, img->photometric);
+ return (0);
+ }
+ img->Map = NULL;
+ img->BWmap = NULL;
+ img->PALmap = NULL;
+ img->ycbcr = NULL;
+ img->cielab = NULL;
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation);
+ img->isContig =
+ !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1);
+ if (img->isContig) {
+ if (!PickContigCase(img)) {
+ sprintf(emsg, "Sorry, can not handle image");
+ return 0;
+ }
+ } else {
+ if (!PickSeparateCase(img)) {
+ sprintf(emsg, "Sorry, can not handle image");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int
+TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+ if (img->get == NULL) {
+ TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup");
+ return (0);
+ }
+ if (img->put.any == NULL) {
+ TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif),
+ "No \"put\" routine setupl; probably can not handle image format");
+ return (0);
+ }
+ return (*img->get)(img, raster, w, h);
+}
+
+/*
+ * Read the specified image into an ABGR-format rastertaking in account
+ * specified orientation.
+ */
+int
+TIFFReadRGBAImageOriented(TIFF* tif,
+ uint32 rwidth, uint32 rheight, uint32* raster,
+ int orientation, int stop)
+{
+ char emsg[1024] = "";
+ TIFFRGBAImage img;
+ int ok;
+
+ if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, stop, emsg)) {
+ img.req_orientation = orientation;
+ /* XXX verify rwidth and rheight against width and height */
+ ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth,
+ rwidth, img.height);
+ TIFFRGBAImageEnd(&img);
+ } else {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg);
+ ok = 0;
+ }
+ return (ok);
+}
+
+/*
+ * Read the specified image into an ABGR-format raster. Use bottom left
+ * origin for raster by default.
+ */
+int
+TIFFReadRGBAImage(TIFF* tif,
+ uint32 rwidth, uint32 rheight, uint32* raster, int stop)
+{
+ return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster,
+ ORIENTATION_BOTLEFT, stop);
+}
+
+static int
+setorientation(TIFFRGBAImage* img)
+{
+ switch (img->orientation) {
+ case ORIENTATION_TOPLEFT:
+ case ORIENTATION_LEFTTOP:
+ if (img->req_orientation == ORIENTATION_TOPRIGHT ||
+ img->req_orientation == ORIENTATION_RIGHTTOP)
+ return FLIP_HORIZONTALLY;
+ else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
+ img->req_orientation == ORIENTATION_RIGHTBOT)
+ return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
+ else if (img->req_orientation == ORIENTATION_BOTLEFT ||
+ img->req_orientation == ORIENTATION_LEFTBOT)
+ return FLIP_VERTICALLY;
+ else
+ return 0;
+ case ORIENTATION_TOPRIGHT:
+ case ORIENTATION_RIGHTTOP:
+ if (img->req_orientation == ORIENTATION_TOPLEFT ||
+ img->req_orientation == ORIENTATION_LEFTTOP)
+ return FLIP_HORIZONTALLY;
+ else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
+ img->req_orientation == ORIENTATION_RIGHTBOT)
+ return FLIP_VERTICALLY;
+ else if (img->req_orientation == ORIENTATION_BOTLEFT ||
+ img->req_orientation == ORIENTATION_LEFTBOT)
+ return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
+ else
+ return 0;
+ case ORIENTATION_BOTRIGHT:
+ case ORIENTATION_RIGHTBOT:
+ if (img->req_orientation == ORIENTATION_TOPLEFT ||
+ img->req_orientation == ORIENTATION_LEFTTOP)
+ return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
+ else if (img->req_orientation == ORIENTATION_TOPRIGHT ||
+ img->req_orientation == ORIENTATION_RIGHTTOP)
+ return FLIP_VERTICALLY;
+ else if (img->req_orientation == ORIENTATION_BOTLEFT ||
+ img->req_orientation == ORIENTATION_LEFTBOT)
+ return FLIP_HORIZONTALLY;
+ else
+ return 0;
+ case ORIENTATION_BOTLEFT:
+ case ORIENTATION_LEFTBOT:
+ if (img->req_orientation == ORIENTATION_TOPLEFT ||
+ img->req_orientation == ORIENTATION_LEFTTOP)
+ return FLIP_VERTICALLY;
+ else if (img->req_orientation == ORIENTATION_TOPRIGHT ||
+ img->req_orientation == ORIENTATION_RIGHTTOP)
+ return FLIP_HORIZONTALLY | FLIP_VERTICALLY;
+ else if (img->req_orientation == ORIENTATION_BOTRIGHT ||
+ img->req_orientation == ORIENTATION_RIGHTBOT)
+ return FLIP_HORIZONTALLY;
+ else
+ return 0;
+ default: /* NOTREACHED */
+ return 0;
+ }
+}
+
+/*
+ * Get an tile-organized image that has
+ * PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ * SamplesPerPixel == 1
+ */
+static int
+gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ tileContigRoutine put = img->put.contig;
+ uint32 col, row, y, rowstoread;
+ uint32 pos;
+ uint32 tw, th;
+ unsigned char* buf;
+ int32 fromskew, toskew;
+ uint32 nrow;
+ int ret = 1, flip;
+
+ buf = (unsigned char*) _TIFFmalloc(TIFFTileSize(tif));
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ _TIFFmemset(buf, 0, TIFFTileSize(tif));
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+
+ flip = setorientation(img);
+ if (flip & FLIP_VERTICALLY) {
+ y = h - 1;
+ toskew = -(int32)(tw + w);
+ }
+ else {
+ y = 0;
+ toskew = -(int32)(tw - w);
+ }
+
+ for (row = 0; row < h; row += nrow)
+ {
+ rowstoread = th - (row + img->row_offset) % th;
+ nrow = (row + rowstoread > h ? h - row : rowstoread);
+ for (col = 0; col < w; col += tw)
+ {
+ if (TIFFReadTile(tif, buf, col+img->col_offset,
+ row+img->row_offset, 0, 0) < 0 && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+
+ pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif);
+
+ if (col + tw > w)
+ {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ uint32 npix = w - col;
+ fromskew = tw - npix;
+ (*put)(img, raster+y*w+col, col, y,
+ npix, nrow, fromskew, toskew + fromskew, buf + pos);
+ }
+ else
+ {
+ (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf + pos);
+ }
+ }
+
+ y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow);
+ }
+ _TIFFfree(buf);
+
+ if (flip & FLIP_HORIZONTALLY) {
+ uint32 line;
+
+ for (line = 0; line < h; line++) {
+ uint32 *left = raster + (line * w);
+ uint32 *right = left + w - 1;
+
+ while ( left < right ) {
+ uint32 temp = *left;
+ *left = *right;
+ *right = temp;
+ left++, right--;
+ }
+ }
+ }
+
+ return (ret);
+}
+
+/*
+ * Get an tile-organized image that has
+ * SamplesPerPixel > 1
+ * PlanarConfiguration separated
+ * We assume that all such images are RGB.
+ */
+static int
+gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ tileSeparateRoutine put = img->put.separate;
+ uint32 col, row, y, rowstoread;
+ uint32 pos;
+ uint32 tw, th;
+ unsigned char* buf;
+ unsigned char* p0;
+ unsigned char* p1;
+ unsigned char* p2;
+ unsigned char* pa;
+ tsize_t tilesize;
+ int32 fromskew, toskew;
+ int alpha = img->alpha;
+ uint32 nrow;
+ int ret = 1, flip;
+
+ tilesize = TIFFTileSize(tif);
+ buf = (unsigned char*) _TIFFmalloc((alpha?4:3)*tilesize);
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ _TIFFmemset(buf, 0, (alpha?4:3)*tilesize);
+ p0 = buf;
+ p1 = p0 + tilesize;
+ p2 = p1 + tilesize;
+ pa = (alpha?(p2+tilesize):NULL);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+
+ flip = setorientation(img);
+ if (flip & FLIP_VERTICALLY) {
+ y = h - 1;
+ toskew = -(int32)(tw + w);
+ }
+ else {
+ y = 0;
+ toskew = -(int32)(tw - w);
+ }
+
+ for (row = 0; row < h; row += nrow)
+ {
+ rowstoread = th - (row + img->row_offset) % th;
+ nrow = (row + rowstoread > h ? h - row : rowstoread);
+ for (col = 0; col < w; col += tw)
+ {
+ if (TIFFReadTile(tif, p0, col+img->col_offset,
+ row+img->row_offset,0,0) < 0 && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+ if (TIFFReadTile(tif, p1, col+img->col_offset,
+ row+img->row_offset,0,1) < 0 && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+ if (TIFFReadTile(tif, p2, col+img->col_offset,
+ row+img->row_offset,0,2) < 0 && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+ if (alpha)
+ {
+ if (TIFFReadTile(tif,pa,col+img->col_offset,
+ row+img->row_offset,0,3) < 0 && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+ }
+
+ pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif);
+
+ if (col + tw > w)
+ {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ uint32 npix = w - col;
+ fromskew = tw - npix;
+ (*put)(img, raster+y*w+col, col, y,
+ npix, nrow, fromskew, toskew + fromskew,
+ p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL));
+ } else {
+ (*put)(img, raster+y*w+col, col, y,
+ tw, nrow, 0, toskew, p0 + pos, p1 + pos, p2 + pos, (alpha?(pa+pos):NULL));
+ }
+ }
+
+ y += (flip & FLIP_VERTICALLY ?-(int32) nrow : (int32) nrow);
+ }
+
+ if (flip & FLIP_HORIZONTALLY) {
+ uint32 line;
+
+ for (line = 0; line < h; line++) {
+ uint32 *left = raster + (line * w);
+ uint32 *right = left + w - 1;
+
+ while ( left < right ) {
+ uint32 temp = *left;
+ *left = *right;
+ *right = temp;
+ left++, right--;
+ }
+ }
+ }
+
+ _TIFFfree(buf);
+ return (ret);
+}
+
+/*
+ * Get a strip-organized image that has
+ * PlanarConfiguration contiguous if SamplesPerPixel > 1
+ * or
+ * SamplesPerPixel == 1
+ */
+static int
+gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ tileContigRoutine put = img->put.contig;
+ uint32 row, y, nrow, nrowsub, rowstoread;
+ uint32 pos;
+ unsigned char* buf;
+ uint32 rowsperstrip;
+ uint16 subsamplinghor,subsamplingver;
+ uint32 imagewidth = img->width;
+ tsize_t scanline;
+ int32 fromskew, toskew;
+ int ret = 1, flip;
+
+ buf = (unsigned char*) _TIFFmalloc(TIFFStripSize(tif));
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
+ return (0);
+ }
+ _TIFFmemset(buf, 0, TIFFStripSize(tif));
+
+ flip = setorientation(img);
+ if (flip & FLIP_VERTICALLY) {
+ y = h - 1;
+ toskew = -(int32)(w + w);
+ } else {
+ y = 0;
+ toskew = -(int32)(w - w);
+ }
+
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRSUBSAMPLING, &subsamplinghor, &subsamplingver);
+ scanline = TIFFNewScanlineSize(tif);
+ fromskew = (w < imagewidth ? imagewidth - w : 0);
+ for (row = 0; row < h; row += nrow)
+ {
+ rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip;
+ nrow = (row + rowstoread > h ? h - row : rowstoread);
+ nrowsub = nrow;
+ if ((nrowsub%subsamplingver)!=0)
+ nrowsub+=subsamplingver-nrowsub%subsamplingver;
+ if (TIFFReadEncodedStrip(tif,
+ TIFFComputeStrip(tif,row+img->row_offset, 0),
+ buf,
+ ((row + img->row_offset)%rowsperstrip + nrowsub) * scanline) < 0
+ && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+
+ pos = ((row + img->row_offset) % rowsperstrip) * scanline;
+ (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf + pos);
+ y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow);
+ }
+
+ if (flip & FLIP_HORIZONTALLY) {
+ uint32 line;
+
+ for (line = 0; line < h; line++) {
+ uint32 *left = raster + (line * w);
+ uint32 *right = left + w - 1;
+
+ while ( left < right ) {
+ uint32 temp = *left;
+ *left = *right;
+ *right = temp;
+ left++, right--;
+ }
+ }
+ }
+
+ _TIFFfree(buf);
+ return (ret);
+}
+
+/*
+ * Get a strip-organized image with
+ * SamplesPerPixel > 1
+ * PlanarConfiguration separated
+ * We assume that all such images are RGB.
+ */
+static int
+gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h)
+{
+ TIFF* tif = img->tif;
+ tileSeparateRoutine put = img->put.separate;
+ unsigned char *buf;
+ unsigned char *p0, *p1, *p2, *pa;
+ uint32 row, y, nrow, rowstoread;
+ uint32 pos;
+ tsize_t scanline;
+ uint32 rowsperstrip, offset_row;
+ uint32 imagewidth = img->width;
+ tsize_t stripsize;
+ int32 fromskew, toskew;
+ int alpha = img->alpha;
+ int ret = 1, flip;
+
+ stripsize = TIFFStripSize(tif);
+ p0 = buf = (unsigned char *)_TIFFmalloc((alpha?4:3)*stripsize);
+ if (buf == 0) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
+ return (0);
+ }
+ _TIFFmemset(buf, 0, (alpha?4:3)*stripsize);
+ p1 = p0 + stripsize;
+ p2 = p1 + stripsize;
+ pa = (alpha?(p2+stripsize):NULL);
+
+ flip = setorientation(img);
+ if (flip & FLIP_VERTICALLY) {
+ y = h - 1;
+ toskew = -(int32)(w + w);
+ }
+ else {
+ y = 0;
+ toskew = -(int32)(w - w);
+ }
+
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ scanline = TIFFScanlineSize(tif);
+ fromskew = (w < imagewidth ? imagewidth - w : 0);
+ for (row = 0; row < h; row += nrow)
+ {
+ rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip;
+ nrow = (row + rowstoread > h ? h - row : rowstoread);
+ offset_row = row + img->row_offset;
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0),
+ p0, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0
+ && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1),
+ p1, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0
+ && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2),
+ p2, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0
+ && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+ if (alpha)
+ {
+ if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 3),
+ pa, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0
+ && img->stoponerr)
+ {
+ ret = 0;
+ break;
+ }
+ }
+
+ pos = ((row + img->row_offset) % rowsperstrip) * scanline;
+ (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, p0 + pos, p1 + pos,
+ p2 + pos, (alpha?(pa+pos):NULL));
+ y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow);
+ }
+
+ if (flip & FLIP_HORIZONTALLY) {
+ uint32 line;
+
+ for (line = 0; line < h; line++) {
+ uint32 *left = raster + (line * w);
+ uint32 *right = left + w - 1;
+
+ while ( left < right ) {
+ uint32 temp = *left;
+ *left = *right;
+ *right = temp;
+ left++, right--;
+ }
+ }
+ }
+
+ _TIFFfree(buf);
+ return (ret);
+}
+
+/*
+ * The following routines move decoded data returned
+ * from the TIFF library into rasters filled with packed
+ * ABGR pixels (i.e. suitable for passing to lrecwrite.)
+ *
+ * The routines have been created according to the most
+ * important cases and optimized. PickContigCase and
+ * PickSeparateCase analyze the parameters and select
+ * the appropriate "get" and "put" routine to use.
+ */
+#define REPEAT8(op) REPEAT4(op); REPEAT4(op)
+#define REPEAT4(op) REPEAT2(op); REPEAT2(op)
+#define REPEAT2(op) op; op
+#define CASE8(x,op) \
+ switch (x) { \
+ case 7: op; case 6: op; case 5: op; \
+ case 4: op; case 3: op; case 2: op; \
+ case 1: op; \
+ }
+#define CASE4(x,op) switch (x) { case 3: op; case 2: op; case 1: op; }
+#define NOP
+
+#define UNROLL8(w, op1, op2) { \
+ uint32 _x; \
+ for (_x = w; _x >= 8; _x -= 8) { \
+ op1; \
+ REPEAT8(op2); \
+ } \
+ if (_x > 0) { \
+ op1; \
+ CASE8(_x,op2); \
+ } \
+}
+#define UNROLL4(w, op1, op2) { \
+ uint32 _x; \
+ for (_x = w; _x >= 4; _x -= 4) { \
+ op1; \
+ REPEAT4(op2); \
+ } \
+ if (_x > 0) { \
+ op1; \
+ CASE4(_x,op2); \
+ } \
+}
+#define UNROLL2(w, op1, op2) { \
+ uint32 _x; \
+ for (_x = w; _x >= 2; _x -= 2) { \
+ op1; \
+ REPEAT2(op2); \
+ } \
+ if (_x) { \
+ op1; \
+ op2; \
+ } \
+}
+
+#define SKEW(r,g,b,skew) { r += skew; g += skew; b += skew; }
+#define SKEW4(r,g,b,a,skew) { r += skew; g += skew; b += skew; a+= skew; }
+
+#define A1 (((uint32)0xffL)<<24)
+#define PACK(r,g,b) \
+ ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|A1)
+#define PACK4(r,g,b,a) \
+ ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24))
+#define W2B(v) (((v)>>8)&0xff)
+#define PACKW(r,g,b) \
+ ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|A1)
+#define PACKW4(r,g,b,a) \
+ ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24))
+
+#define DECLAREContigPutFunc(name) \
+static void name(\
+ TIFFRGBAImage* img, \
+ uint32* cp, \
+ uint32 x, uint32 y, \
+ uint32 w, uint32 h, \
+ int32 fromskew, int32 toskew, \
+ unsigned char* pp \
+)
+
+/*
+ * 8-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put8bitcmaptile)
+{
+ uint32** PALmap = img->PALmap;
+ int samplesperpixel = img->samplesperpixel;
+
+ (void) y;
+ while (h-- > 0) {
+ for (x = w; x-- > 0;)
+ {
+ *cp++ = PALmap[*pp][0];
+ pp += samplesperpixel;
+ }
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 4-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put4bitcmaptile)
+{
+ uint32** PALmap = img->PALmap;
+
+ (void) x; (void) y;
+ fromskew /= 2;
+ while (h-- > 0) {
+ uint32* bw;
+ UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 2-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put2bitcmaptile)
+{
+ uint32** PALmap = img->PALmap;
+
+ (void) x; (void) y;
+ fromskew /= 4;
+ while (h-- > 0) {
+ uint32* bw;
+ UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 1-bit palette => colormap/RGB
+ */
+DECLAREContigPutFunc(put1bitcmaptile)
+{
+ uint32** PALmap = img->PALmap;
+
+ (void) x; (void) y;
+ fromskew /= 8;
+ while (h-- > 0) {
+ uint32* bw;
+ UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 8-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(putgreytile)
+{
+ int samplesperpixel = img->samplesperpixel;
+ uint32** BWmap = img->BWmap;
+
+ (void) y;
+ while (h-- > 0) {
+ for (x = w; x-- > 0;)
+ {
+ *cp++ = BWmap[*pp][0];
+ pp += samplesperpixel;
+ }
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 16-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put16bitbwtile)
+{
+ int samplesperpixel = img->samplesperpixel;
+ uint32** BWmap = img->BWmap;
+
+ (void) y;
+ while (h-- > 0) {
+ uint16 *wp = (uint16 *) pp;
+
+ for (x = w; x-- > 0;)
+ {
+ /* use high order byte of 16bit value */
+
+ *cp++ = BWmap[*wp >> 8][0];
+ pp += 2 * samplesperpixel;
+ wp += samplesperpixel;
+ }
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 1-bit bilevel => colormap/RGB
+ */
+DECLAREContigPutFunc(put1bitbwtile)
+{
+ uint32** BWmap = img->BWmap;
+
+ (void) x; (void) y;
+ fromskew /= 8;
+ while (h-- > 0) {
+ uint32* bw;
+ UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 2-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put2bitbwtile)
+{
+ uint32** BWmap = img->BWmap;
+
+ (void) x; (void) y;
+ fromskew /= 4;
+ while (h-- > 0) {
+ uint32* bw;
+ UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 4-bit greyscale => colormap/RGB
+ */
+DECLAREContigPutFunc(put4bitbwtile)
+{
+ uint32** BWmap = img->BWmap;
+
+ (void) x; (void) y;
+ fromskew /= 2;
+ while (h-- > 0) {
+ uint32* bw;
+ UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 8-bit packed samples, no Map => RGB
+ */
+DECLAREContigPutFunc(putRGBcontig8bittile)
+{
+ int samplesperpixel = img->samplesperpixel;
+
+ (void) x; (void) y;
+ fromskew *= samplesperpixel;
+ while (h-- > 0) {
+ UNROLL8(w, NOP,
+ *cp++ = PACK(pp[0], pp[1], pp[2]);
+ pp += samplesperpixel);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 8-bit packed samples => RGBA w/ associated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBAAcontig8bittile)
+{
+ int samplesperpixel = img->samplesperpixel;
+
+ (void) x; (void) y;
+ fromskew *= samplesperpixel;
+ while (h-- > 0) {
+ UNROLL8(w, NOP,
+ *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]);
+ pp += samplesperpixel);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 8-bit packed samples => RGBA w/ unassociated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBUAcontig8bittile)
+{
+ int samplesperpixel = img->samplesperpixel;
+ (void) y;
+ fromskew *= samplesperpixel;
+ while (h-- > 0) {
+ uint32 r, g, b, a;
+ for (x = w; x-- > 0;) {
+ a = pp[3];
+ r = (a*pp[0] + 127) / 255;
+ g = (a*pp[1] + 127) / 255;
+ b = (a*pp[2] + 127) / 255;
+ *cp++ = PACK4(r,g,b,a);
+ pp += samplesperpixel;
+ }
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 16-bit packed samples => RGB
+ */
+DECLAREContigPutFunc(putRGBcontig16bittile)
+{
+ int samplesperpixel = img->samplesperpixel;
+ uint16 *wp = (uint16 *)pp;
+ (void) y;
+ fromskew *= samplesperpixel;
+ while (h-- > 0) {
+ for (x = w; x-- > 0;) {
+ *cp++ = PACKW(wp[0],wp[1],wp[2]);
+ wp += samplesperpixel;
+ }
+ cp += toskew;
+ wp += fromskew;
+ }
+}
+
+/*
+ * 16-bit packed samples => RGBA w/ associated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBAAcontig16bittile)
+{
+ int samplesperpixel = img->samplesperpixel;
+ uint16 *wp = (uint16 *)pp;
+ (void) y;
+ fromskew *= samplesperpixel;
+ while (h-- > 0) {
+ for (x = w; x-- > 0;) {
+ *cp++ = PACKW4(wp[0],wp[1],wp[2],wp[3]);
+ wp += samplesperpixel;
+ }
+ cp += toskew;
+ wp += fromskew;
+ }
+}
+
+/*
+ * 16-bit packed samples => RGBA w/ unassociated alpha
+ * (known to have Map == NULL)
+ */
+DECLAREContigPutFunc(putRGBUAcontig16bittile)
+{
+ int samplesperpixel = img->samplesperpixel;
+ uint16 *wp = (uint16 *)pp;
+ (void) y;
+ fromskew *= samplesperpixel;
+ while (h-- > 0) {
+ uint32 r,g,b,a;
+ for (x = w; x-- > 0;) {
+ a = W2B(wp[3]);
+ r = (a*W2B(wp[0]) + 127) / 255;
+ g = (a*W2B(wp[1]) + 127) / 255;
+ b = (a*W2B(wp[2]) + 127) / 255;
+ *cp++ = PACK4(r,g,b,a);
+ wp += samplesperpixel;
+ }
+ cp += toskew;
+ wp += fromskew;
+ }
+}
+
+/*
+ * 8-bit packed CMYK samples w/o Map => RGB
+ *
+ * NB: The conversion of CMYK->RGB is *very* crude.
+ */
+DECLAREContigPutFunc(putRGBcontig8bitCMYKtile)
+{
+ int samplesperpixel = img->samplesperpixel;
+ uint16 r, g, b, k;
+
+ (void) x; (void) y;
+ fromskew *= samplesperpixel;
+ while (h-- > 0) {
+ UNROLL8(w, NOP,
+ k = 255 - pp[3];
+ r = (k*(255-pp[0]))/255;
+ g = (k*(255-pp[1]))/255;
+ b = (k*(255-pp[2]))/255;
+ *cp++ = PACK(r, g, b);
+ pp += samplesperpixel);
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * 8-bit packed CMYK samples w/Map => RGB
+ *
+ * NB: The conversion of CMYK->RGB is *very* crude.
+ */
+DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile)
+{
+ int samplesperpixel = img->samplesperpixel;
+ TIFFRGBValue* Map = img->Map;
+ uint16 r, g, b, k;
+
+ (void) y;
+ fromskew *= samplesperpixel;
+ while (h-- > 0) {
+ for (x = w; x-- > 0;) {
+ k = 255 - pp[3];
+ r = (k*(255-pp[0]))/255;
+ g = (k*(255-pp[1]))/255;
+ b = (k*(255-pp[2]))/255;
+ *cp++ = PACK(Map[r], Map[g], Map[b]);
+ pp += samplesperpixel;
+ }
+ pp += fromskew;
+ cp += toskew;
+ }
+}
+
+#define DECLARESepPutFunc(name) \
+static void name(\
+ TIFFRGBAImage* img,\
+ uint32* cp,\
+ uint32 x, uint32 y, \
+ uint32 w, uint32 h,\
+ int32 fromskew, int32 toskew,\
+ unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a\
+)
+
+/*
+ * 8-bit unpacked samples => RGB
+ */
+DECLARESepPutFunc(putRGBseparate8bittile)
+{
+ (void) img; (void) x; (void) y; (void) a;
+ while (h-- > 0) {
+ UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++));
+ SKEW(r, g, b, fromskew);
+ cp += toskew;
+ }
+}
+
+/*
+ * 8-bit unpacked samples => RGBA w/ associated alpha
+ */
+DECLARESepPutFunc(putRGBAAseparate8bittile)
+{
+ (void) img; (void) x; (void) y;
+ while (h-- > 0) {
+ UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++));
+ SKEW4(r, g, b, a, fromskew);
+ cp += toskew;
+ }
+}
+
+/*
+ * 8-bit unpacked samples => RGBA w/ unassociated alpha
+ */
+DECLARESepPutFunc(putRGBUAseparate8bittile)
+{
+ (void) img; (void) y;
+ while (h-- > 0) {
+ uint32 rv, gv, bv, av;
+ for (x = w; x-- > 0;) {
+ av = *a++;
+ rv = (av* *r++ + 127) / 255;
+ gv = (av* *g++ + 127) / 255;
+ bv = (av* *b++ + 127) / 255;
+ *cp++ = PACK4(rv,gv,bv,av);
+ }
+ SKEW4(r, g, b, a, fromskew);
+ cp += toskew;
+ }
+}
+
+/*
+ * 16-bit unpacked samples => RGB
+ */
+DECLARESepPutFunc(putRGBseparate16bittile)
+{
+ uint16 *wr = (uint16*) r;
+ uint16 *wg = (uint16*) g;
+ uint16 *wb = (uint16*) b;
+ (void) img; (void) y; (void) a;
+ while (h-- > 0) {
+ for (x = 0; x < w; x++)
+ *cp++ = PACKW(*wr++,*wg++,*wb++);
+ SKEW(wr, wg, wb, fromskew);
+ cp += toskew;
+ }
+}
+
+/*
+ * 16-bit unpacked samples => RGBA w/ associated alpha
+ */
+DECLARESepPutFunc(putRGBAAseparate16bittile)
+{
+ uint16 *wr = (uint16*) r;
+ uint16 *wg = (uint16*) g;
+ uint16 *wb = (uint16*) b;
+ uint16 *wa = (uint16*) a;
+ (void) img; (void) y;
+ while (h-- > 0) {
+ for (x = 0; x < w; x++)
+ *cp++ = PACKW4(*wr++,*wg++,*wb++,*wa++);
+ SKEW4(wr, wg, wb, wa, fromskew);
+ cp += toskew;
+ }
+}
+
+/*
+ * 16-bit unpacked samples => RGBA w/ unassociated alpha
+ */
+DECLARESepPutFunc(putRGBUAseparate16bittile)
+{
+ uint16 *wr = (uint16*) r;
+ uint16 *wg = (uint16*) g;
+ uint16 *wb = (uint16*) b;
+ uint16 *wa = (uint16*) a;
+ (void) img; (void) y;
+ while (h-- > 0) {
+ uint32 r,g,b,a;
+ for (x = w; x-- > 0;) {
+ a = W2B(*wa++);
+ r = (a*W2B(*wr++) + 127) / 255;
+ g = (a*W2B(*wg++) + 127) / 255;
+ b = (a*W2B(*wb++) + 127) / 255;
+ *cp++ = PACK4(r,g,b,a);
+ }
+ SKEW4(wr, wg, wb, wa, fromskew);
+ cp += toskew;
+ }
+}
+
+/*
+ * 8-bit packed CIE L*a*b 1976 samples => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitCIELab)
+{
+ float X, Y, Z;
+ uint32 r, g, b;
+ (void) y;
+ fromskew *= 3;
+ while (h-- > 0) {
+ for (x = w; x-- > 0;) {
+ TIFFCIELabToXYZ(img->cielab,
+ (unsigned char)pp[0],
+ (signed char)pp[1],
+ (signed char)pp[2],
+ &X, &Y, &Z);
+ TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b);
+ *cp++ = PACK(r, g, b);
+ pp += 3;
+ }
+ cp += toskew;
+ pp += fromskew;
+ }
+}
+
+/*
+ * YCbCr -> RGB conversion and packing routines.
+ */
+
+#define YCbCrtoRGB(dst, Y) { \
+ uint32 r, g, b; \
+ TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b); \
+ dst = PACK(r, g, b); \
+}
+
+/*
+ * 8-bit packed YCbCr samples => RGB
+ * This function is generic for different sampling sizes,
+ * and can handle blocks sizes that aren't multiples of the
+ * sampling size. However, it is substantially less optimized
+ * than the specific sampling cases. It is used as a fallback
+ * for difficult blocks.
+ */
+#ifdef notdef
+static void putcontig8bitYCbCrGenericTile(
+ TIFFRGBAImage* img,
+ uint32* cp,
+ uint32 x, uint32 y,
+ uint32 w, uint32 h,
+ int32 fromskew, int32 toskew,
+ unsigned char* pp,
+ int h_group,
+ int v_group )
+
+{
+ uint32* cp1 = cp+w+toskew;
+ uint32* cp2 = cp1+w+toskew;
+ uint32* cp3 = cp2+w+toskew;
+ int32 incr = 3*w+4*toskew;
+ int32 Cb, Cr;
+ int group_size = v_group * h_group + 2;
+
+ (void) y;
+ fromskew = (fromskew * group_size) / h_group;
+
+ for( yy = 0; yy < h; yy++ )
+ {
+ unsigned char *pp_line;
+ int y_line_group = yy / v_group;
+ int y_remainder = yy - y_line_group * v_group;
+
+ pp_line = pp + v_line_group *
+
+
+ for( xx = 0; xx < w; xx++ )
+ {
+ Cb = pp
+ }
+ }
+ for (; h >= 4; h -= 4) {
+ x = w>>2;
+ do {
+ Cb = pp[16];
+ Cr = pp[17];
+
+ YCbCrtoRGB(cp [0], pp[ 0]);
+ YCbCrtoRGB(cp [1], pp[ 1]);
+ YCbCrtoRGB(cp [2], pp[ 2]);
+ YCbCrtoRGB(cp [3], pp[ 3]);
+ YCbCrtoRGB(cp1[0], pp[ 4]);
+ YCbCrtoRGB(cp1[1], pp[ 5]);
+ YCbCrtoRGB(cp1[2], pp[ 6]);
+ YCbCrtoRGB(cp1[3], pp[ 7]);
+ YCbCrtoRGB(cp2[0], pp[ 8]);
+ YCbCrtoRGB(cp2[1], pp[ 9]);
+ YCbCrtoRGB(cp2[2], pp[10]);
+ YCbCrtoRGB(cp2[3], pp[11]);
+ YCbCrtoRGB(cp3[0], pp[12]);
+ YCbCrtoRGB(cp3[1], pp[13]);
+ YCbCrtoRGB(cp3[2], pp[14]);
+ YCbCrtoRGB(cp3[3], pp[15]);
+
+ cp += 4, cp1 += 4, cp2 += 4, cp3 += 4;
+ pp += 18;
+ } while (--x);
+ cp += incr, cp1 += incr, cp2 += incr, cp3 += incr;
+ pp += fromskew;
+ }
+}
+#endif
+
+/*
+ * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr44tile)
+{
+ uint32* cp1 = cp+w+toskew;
+ uint32* cp2 = cp1+w+toskew;
+ uint32* cp3 = cp2+w+toskew;
+ int32 incr = 3*w+4*toskew;
+
+ (void) y;
+ /* adjust fromskew */
+ fromskew = (fromskew * 18) / 4;
+ if ((h & 3) == 0 && (w & 3) == 0) {
+ for (; h >= 4; h -= 4) {
+ x = w>>2;
+ do {
+ int32 Cb = pp[16];
+ int32 Cr = pp[17];
+
+ YCbCrtoRGB(cp [0], pp[ 0]);
+ YCbCrtoRGB(cp [1], pp[ 1]);
+ YCbCrtoRGB(cp [2], pp[ 2]);
+ YCbCrtoRGB(cp [3], pp[ 3]);
+ YCbCrtoRGB(cp1[0], pp[ 4]);
+ YCbCrtoRGB(cp1[1], pp[ 5]);
+ YCbCrtoRGB(cp1[2], pp[ 6]);
+ YCbCrtoRGB(cp1[3], pp[ 7]);
+ YCbCrtoRGB(cp2[0], pp[ 8]);
+ YCbCrtoRGB(cp2[1], pp[ 9]);
+ YCbCrtoRGB(cp2[2], pp[10]);
+ YCbCrtoRGB(cp2[3], pp[11]);
+ YCbCrtoRGB(cp3[0], pp[12]);
+ YCbCrtoRGB(cp3[1], pp[13]);
+ YCbCrtoRGB(cp3[2], pp[14]);
+ YCbCrtoRGB(cp3[3], pp[15]);
+
+ cp += 4, cp1 += 4, cp2 += 4, cp3 += 4;
+ pp += 18;
+ } while (--x);
+ cp += incr, cp1 += incr, cp2 += incr, cp3 += incr;
+ pp += fromskew;
+ }
+ } else {
+ while (h > 0) {
+ for (x = w; x > 0;) {
+ int32 Cb = pp[16];
+ int32 Cr = pp[17];
+ switch (x) {
+ default:
+ switch (h) {
+ default: YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */
+ case 3: YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */
+ case 2: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */
+ case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */
+ } /* FALLTHROUGH */
+ case 3:
+ switch (h) {
+ default: YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */
+ case 3: YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */
+ case 2: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */
+ case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */
+ } /* FALLTHROUGH */
+ case 2:
+ switch (h) {
+ default: YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */
+ case 3: YCbCrtoRGB(cp2[1], pp[ 9]); /* FALLTHROUGH */
+ case 2: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */
+ case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */
+ } /* FALLTHROUGH */
+ case 1:
+ switch (h) {
+ default: YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */
+ case 3: YCbCrtoRGB(cp2[0], pp[ 8]); /* FALLTHROUGH */
+ case 2: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */
+ case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */
+ } /* FALLTHROUGH */
+ }
+ if (x < 4) {
+ cp += x; cp1 += x; cp2 += x; cp3 += x;
+ x = 0;
+ }
+ else {
+ cp += 4; cp1 += 4; cp2 += 4; cp3 += 4;
+ x -= 4;
+ }
+ pp += 18;
+ }
+ if (h <= 4)
+ break;
+ h -= 4;
+ cp += incr, cp1 += incr, cp2 += incr, cp3 += incr;
+ pp += fromskew;
+ }
+ }
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr42tile)
+{
+ uint32* cp1 = cp+w+toskew;
+ int32 incr = 2*toskew+w;
+
+ (void) y;
+ fromskew = (fromskew * 10) / 4;
+ if ((h & 3) == 0 && (w & 1) == 0) {
+ for (; h >= 2; h -= 2) {
+ x = w>>2;
+ do {
+ int32 Cb = pp[8];
+ int32 Cr = pp[9];
+
+ YCbCrtoRGB(cp [0], pp[0]);
+ YCbCrtoRGB(cp [1], pp[1]);
+ YCbCrtoRGB(cp [2], pp[2]);
+ YCbCrtoRGB(cp [3], pp[3]);
+ YCbCrtoRGB(cp1[0], pp[4]);
+ YCbCrtoRGB(cp1[1], pp[5]);
+ YCbCrtoRGB(cp1[2], pp[6]);
+ YCbCrtoRGB(cp1[3], pp[7]);
+
+ cp += 4, cp1 += 4;
+ pp += 10;
+ } while (--x);
+ cp += incr, cp1 += incr;
+ pp += fromskew;
+ }
+ } else {
+ while (h > 0) {
+ for (x = w; x > 0;) {
+ int32 Cb = pp[8];
+ int32 Cr = pp[9];
+ switch (x) {
+ default:
+ switch (h) {
+ default: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */
+ case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */
+ } /* FALLTHROUGH */
+ case 3:
+ switch (h) {
+ default: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */
+ case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */
+ } /* FALLTHROUGH */
+ case 2:
+ switch (h) {
+ default: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */
+ case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */
+ } /* FALLTHROUGH */
+ case 1:
+ switch (h) {
+ default: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */
+ case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */
+ } /* FALLTHROUGH */
+ }
+ if (x < 4) {
+ cp += x; cp1 += x;
+ x = 0;
+ }
+ else {
+ cp += 4; cp1 += 4;
+ x -= 4;
+ }
+ pp += 10;
+ }
+ if (h <= 2)
+ break;
+ h -= 2;
+ cp += incr, cp1 += incr;
+ pp += fromskew;
+ }
+ }
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr41tile)
+{
+ (void) y;
+ /* XXX adjust fromskew */
+ do {
+ x = w>>2;
+ do {
+ int32 Cb = pp[4];
+ int32 Cr = pp[5];
+
+ YCbCrtoRGB(cp [0], pp[0]);
+ YCbCrtoRGB(cp [1], pp[1]);
+ YCbCrtoRGB(cp [2], pp[2]);
+ YCbCrtoRGB(cp [3], pp[3]);
+
+ cp += 4;
+ pp += 6;
+ } while (--x);
+
+ if( (w&3) != 0 )
+ {
+ int32 Cb = pp[4];
+ int32 Cr = pp[5];
+
+ switch( (w&3) ) {
+ case 3: YCbCrtoRGB(cp [2], pp[2]);
+ case 2: YCbCrtoRGB(cp [1], pp[1]);
+ case 1: YCbCrtoRGB(cp [0], pp[0]);
+ case 0: break;
+ }
+
+ cp += (w&3);
+ pp += 6;
+ }
+
+ cp += toskew;
+ pp += fromskew;
+ } while (--h);
+
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr22tile)
+{
+ uint32* cp2;
+ (void) y;
+ fromskew = (fromskew / 2) * 6;
+ cp2 = cp+w+toskew;
+ while (h>=2) {
+ x = w;
+ while (x>=2) {
+ uint32 Cb = pp[4];
+ uint32 Cr = pp[5];
+ YCbCrtoRGB(cp[0], pp[0]);
+ YCbCrtoRGB(cp[1], pp[1]);
+ YCbCrtoRGB(cp2[0], pp[2]);
+ YCbCrtoRGB(cp2[1], pp[3]);
+ cp += 2;
+ cp2 += 2;
+ pp += 6;
+ x -= 2;
+ }
+ if (x==1) {
+ uint32 Cb = pp[4];
+ uint32 Cr = pp[5];
+ YCbCrtoRGB(cp[0], pp[0]);
+ YCbCrtoRGB(cp2[0], pp[2]);
+ cp ++ ;
+ cp2 ++ ;
+ pp += 6;
+ }
+ cp += toskew*2+w;
+ cp2 += toskew*2+w;
+ pp += fromskew;
+ h-=2;
+ }
+ if (h==1) {
+ x = w;
+ while (x>=2) {
+ uint32 Cb = pp[4];
+ uint32 Cr = pp[5];
+ YCbCrtoRGB(cp[0], pp[0]);
+ YCbCrtoRGB(cp[1], pp[1]);
+ cp += 2;
+ cp2 += 2;
+ pp += 6;
+ x -= 2;
+ }
+ if (x==1) {
+ uint32 Cb = pp[4];
+ uint32 Cr = pp[5];
+ YCbCrtoRGB(cp[0], pp[0]);
+ }
+ }
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr21tile)
+{
+ (void) y;
+ fromskew = (fromskew * 4) / 2;
+ do {
+ x = w>>1;
+ do {
+ int32 Cb = pp[2];
+ int32 Cr = pp[3];
+
+ YCbCrtoRGB(cp[0], pp[0]);
+ YCbCrtoRGB(cp[1], pp[1]);
+
+ cp += 2;
+ pp += 4;
+ } while (--x);
+
+ if( (w&1) != 0 )
+ {
+ int32 Cb = pp[2];
+ int32 Cr = pp[3];
+
+ YCbCrtoRGB(cp[0], pp[0]);
+
+ cp += 1;
+ pp += 4;
+ }
+
+ cp += toskew;
+ pp += fromskew;
+ } while (--h);
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ 1,2 subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr12tile)
+{
+ uint32* cp2;
+ (void) y;
+ fromskew = (fromskew / 2) * 4;
+ cp2 = cp+w+toskew;
+ while (h>=2) {
+ x = w;
+ do {
+ uint32 Cb = pp[2];
+ uint32 Cr = pp[3];
+ YCbCrtoRGB(cp[0], pp[0]);
+ YCbCrtoRGB(cp2[0], pp[1]);
+ cp ++;
+ cp2 ++;
+ pp += 4;
+ } while (--x);
+ cp += toskew*2+w;
+ cp2 += toskew*2+w;
+ pp += fromskew;
+ h-=2;
+ }
+ if (h==1) {
+ x = w;
+ do {
+ uint32 Cb = pp[2];
+ uint32 Cr = pp[3];
+ YCbCrtoRGB(cp[0], pp[0]);
+ cp ++;
+ pp += 4;
+ } while (--x);
+ }
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ no subsampling => RGB
+ */
+DECLAREContigPutFunc(putcontig8bitYCbCr11tile)
+{
+ (void) y;
+ fromskew *= 3;
+ do {
+ x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */
+ do {
+ int32 Cb = pp[1];
+ int32 Cr = pp[2];
+
+ YCbCrtoRGB(*cp++, pp[0]);
+
+ pp += 3;
+ } while (--x);
+ cp += toskew;
+ pp += fromskew;
+ } while (--h);
+}
+
+/*
+ * 8-bit packed YCbCr samples w/ no subsampling => RGB
+ */
+DECLARESepPutFunc(putseparate8bitYCbCr11tile)
+{
+ (void) y;
+ (void) a;
+ /* TODO: naming of input vars is still off, change obfuscating declaration inside define, or resolve obfuscation */
+ while (h-- > 0) {
+ x = w;
+ do {
+ uint32 dr, dg, db;
+ TIFFYCbCrtoRGB(img->ycbcr,*r++,*g++,*b++,&dr,&dg,&db);
+ *cp++ = PACK(dr,dg,db);
+ } while (--x);
+ SKEW(r, g, b, fromskew);
+ cp += toskew;
+ }
+}
+#undef YCbCrtoRGB
+
+static int
+initYCbCrConversion(TIFFRGBAImage* img)
+{
+ static char module[] = "initYCbCrConversion";
+
+ float *luma, *refBlackWhite;
+
+ if (img->ycbcr == NULL) {
+ img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc(
+ TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long))
+ + 4*256*sizeof (TIFFRGBValue)
+ + 2*256*sizeof (int)
+ + 3*256*sizeof (int32)
+ );
+ if (img->ycbcr == NULL) {
+ TIFFErrorExt(img->tif->tif_clientdata, module,
+ "No space for YCbCr->RGB conversion state");
+ return (0);
+ }
+ }
+
+ TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma);
+ TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE,
+ &refBlackWhite);
+ if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0)
+ return(0);
+ return (1);
+}
+
+static tileContigRoutine
+initCIELabConversion(TIFFRGBAImage* img)
+{
+ static char module[] = "initCIELabConversion";
+
+ float *whitePoint;
+ float refWhite[3];
+
+ if (!img->cielab) {
+ img->cielab = (TIFFCIELabToRGB *)
+ _TIFFmalloc(sizeof(TIFFCIELabToRGB));
+ if (!img->cielab) {
+ TIFFErrorExt(img->tif->tif_clientdata, module,
+ "No space for CIE L*a*b*->RGB conversion state.");
+ return NULL;
+ }
+ }
+
+ TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint);
+ refWhite[1] = 100.0F;
+ refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1];
+ refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1])
+ / whitePoint[1] * refWhite[1];
+ if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0) {
+ TIFFErrorExt(img->tif->tif_clientdata, module,
+ "Failed to initialize CIE L*a*b*->RGB conversion state.");
+ _TIFFfree(img->cielab);
+ return NULL;
+ }
+
+ return putcontig8bitCIELab;
+}
+
+/*
+ * Greyscale images with less than 8 bits/sample are handled
+ * with a table to avoid lots of shifts and masks. The table
+ * is setup so that put*bwtile (below) can retrieve 8/bitspersample
+ * pixel values simply by indexing into the table with one
+ * number.
+ */
+static int
+makebwmap(TIFFRGBAImage* img)
+{
+ TIFFRGBValue* Map = img->Map;
+ int bitspersample = img->bitspersample;
+ int nsamples = 8 / bitspersample;
+ int i;
+ uint32* p;
+
+ if( nsamples == 0 )
+ nsamples = 1;
+
+ img->BWmap = (uint32**) _TIFFmalloc(
+ 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32)));
+ if (img->BWmap == NULL) {
+ TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for B&W mapping table");
+ return (0);
+ }
+ p = (uint32*)(img->BWmap + 256);
+ for (i = 0; i < 256; i++) {
+ TIFFRGBValue c;
+ img->BWmap[i] = p;
+ switch (bitspersample) {
+#define GREY(x) c = Map[x]; *p++ = PACK(c,c,c);
+ case 1:
+ GREY(i>>7);
+ GREY((i>>6)&1);
+ GREY((i>>5)&1);
+ GREY((i>>4)&1);
+ GREY((i>>3)&1);
+ GREY((i>>2)&1);
+ GREY((i>>1)&1);
+ GREY(i&1);
+ break;
+ case 2:
+ GREY(i>>6);
+ GREY((i>>4)&3);
+ GREY((i>>2)&3);
+ GREY(i&3);
+ break;
+ case 4:
+ GREY(i>>4);
+ GREY(i&0xf);
+ break;
+ case 8:
+ case 16:
+ GREY(i);
+ break;
+ }
+#undef GREY
+ }
+ return (1);
+}
+
+/*
+ * Construct a mapping table to convert from the range
+ * of the data samples to [0,255] --for display. This
+ * process also handles inverting B&W images when needed.
+ */
+static int
+setupMap(TIFFRGBAImage* img)
+{
+ int32 x, range;
+
+ range = (int32)((1L<<img->bitspersample)-1);
+
+ /* treat 16 bit the same as eight bit */
+ if( img->bitspersample == 16 )
+ range = (int32) 255;
+
+ img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue));
+ if (img->Map == NULL) {
+ TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif),
+ "No space for photometric conversion table");
+ return (0);
+ }
+ if (img->photometric == PHOTOMETRIC_MINISWHITE) {
+ for (x = 0; x <= range; x++)
+ img->Map[x] = (TIFFRGBValue) (((range - x) * 255) / range);
+ } else {
+ for (x = 0; x <= range; x++)
+ img->Map[x] = (TIFFRGBValue) ((x * 255) / range);
+ }
+ if (img->bitspersample <= 16 &&
+ (img->photometric == PHOTOMETRIC_MINISBLACK ||
+ img->photometric == PHOTOMETRIC_MINISWHITE)) {
+ /*
+ * Use photometric mapping table to construct
+ * unpacking tables for samples <= 8 bits.
+ */
+ if (!makebwmap(img))
+ return (0);
+ /* no longer need Map, free it */
+ _TIFFfree(img->Map), img->Map = NULL;
+ }
+ return (1);
+}
+
+static int
+checkcmap(TIFFRGBAImage* img)
+{
+ uint16* r = img->redcmap;
+ uint16* g = img->greencmap;
+ uint16* b = img->bluecmap;
+ long n = 1L<<img->bitspersample;
+
+ while (n-- > 0)
+ if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+ return (16);
+ return (8);
+}
+
+static void
+cvtcmap(TIFFRGBAImage* img)
+{
+ uint16* r = img->redcmap;
+ uint16* g = img->greencmap;
+ uint16* b = img->bluecmap;
+ long i;
+
+ for (i = (1L<<img->bitspersample)-1; i >= 0; i--) {
+#define CVT(x) ((uint16)((x)>>8))
+ r[i] = CVT(r[i]);
+ g[i] = CVT(g[i]);
+ b[i] = CVT(b[i]);
+#undef CVT
+ }
+}
+
+/*
+ * Palette images with <= 8 bits/sample are handled
+ * with a table to avoid lots of shifts and masks. The table
+ * is setup so that put*cmaptile (below) can retrieve 8/bitspersample
+ * pixel values simply by indexing into the table with one
+ * number.
+ */
+static int
+makecmap(TIFFRGBAImage* img)
+{
+ int bitspersample = img->bitspersample;
+ int nsamples = 8 / bitspersample;
+ uint16* r = img->redcmap;
+ uint16* g = img->greencmap;
+ uint16* b = img->bluecmap;
+ uint32 *p;
+ int i;
+
+ img->PALmap = (uint32**) _TIFFmalloc(
+ 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32)));
+ if (img->PALmap == NULL) {
+ TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No space for Palette mapping table");
+ return (0);
+ }
+ p = (uint32*)(img->PALmap + 256);
+ for (i = 0; i < 256; i++) {
+ TIFFRGBValue c;
+ img->PALmap[i] = p;
+#define CMAP(x) c = (TIFFRGBValue) x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff);
+ switch (bitspersample) {
+ case 1:
+ CMAP(i>>7);
+ CMAP((i>>6)&1);
+ CMAP((i>>5)&1);
+ CMAP((i>>4)&1);
+ CMAP((i>>3)&1);
+ CMAP((i>>2)&1);
+ CMAP((i>>1)&1);
+ CMAP(i&1);
+ break;
+ case 2:
+ CMAP(i>>6);
+ CMAP((i>>4)&3);
+ CMAP((i>>2)&3);
+ CMAP(i&3);
+ break;
+ case 4:
+ CMAP(i>>4);
+ CMAP(i&0xf);
+ break;
+ case 8:
+ CMAP(i);
+ break;
+ }
+#undef CMAP
+ }
+ return (1);
+}
+
+/*
+ * Construct any mapping table used
+ * by the associated put routine.
+ */
+static int
+buildMap(TIFFRGBAImage* img)
+{
+ switch (img->photometric) {
+ case PHOTOMETRIC_RGB:
+ case PHOTOMETRIC_YCBCR:
+ case PHOTOMETRIC_SEPARATED:
+ if (img->bitspersample == 8)
+ break;
+ /* fall thru... */
+ case PHOTOMETRIC_MINISBLACK:
+ case PHOTOMETRIC_MINISWHITE:
+ if (!setupMap(img))
+ return (0);
+ break;
+ case PHOTOMETRIC_PALETTE:
+ /*
+ * Convert 16-bit colormap to 8-bit (unless it looks
+ * like an old-style 8-bit colormap).
+ */
+ if (checkcmap(img) == 16)
+ cvtcmap(img);
+ else
+ TIFFWarningExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "Assuming 8-bit colormap");
+ /*
+ * Use mapping table and colormap to construct
+ * unpacking tables for samples < 8 bits.
+ */
+ if (img->bitspersample <= 8 && !makecmap(img))
+ return (0);
+ break;
+ }
+ return (1);
+}
+
+/*
+ * Select the appropriate conversion routine for packed data.
+ */
+static int
+PickContigCase(TIFFRGBAImage* img)
+{
+ img->get = TIFFIsTiled(img->tif) ? gtTileContig : gtStripContig;
+ img->put.contig = NULL;
+ switch (img->photometric) {
+ case PHOTOMETRIC_RGB:
+ switch (img->bitspersample) {
+ case 8:
+ if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+ img->put.contig = putRGBAAcontig8bittile;
+ else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+ {
+ img->put.contig = putRGBUAcontig8bittile;
+ }
+ else
+ img->put.contig = putRGBcontig8bittile;
+ break;
+ case 16:
+ if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+ {
+ img->put.contig = putRGBAAcontig16bittile;
+ }
+ else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+ {
+ img->put.contig = putRGBUAcontig16bittile;
+ }
+ else
+ {
+ img->put.contig = putRGBcontig16bittile;
+ }
+ break;
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ if (buildMap(img)) {
+ if (img->bitspersample == 8) {
+ if (!img->Map)
+ img->put.contig = putRGBcontig8bitCMYKtile;
+ else
+ img->put.contig = putRGBcontig8bitCMYKMaptile;
+ }
+ }
+ break;
+ case PHOTOMETRIC_PALETTE:
+ if (buildMap(img)) {
+ switch (img->bitspersample) {
+ case 8:
+ img->put.contig = put8bitcmaptile;
+ break;
+ case 4:
+ img->put.contig = put4bitcmaptile;
+ break;
+ case 2:
+ img->put.contig = put2bitcmaptile;
+ break;
+ case 1:
+ img->put.contig = put1bitcmaptile;
+ break;
+ }
+ }
+ break;
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ if (buildMap(img)) {
+ switch (img->bitspersample) {
+ case 16:
+ img->put.contig = put16bitbwtile;
+ break;
+ case 8:
+ img->put.contig = putgreytile;
+ break;
+ case 4:
+ img->put.contig = put4bitbwtile;
+ break;
+ case 2:
+ img->put.contig = put2bitbwtile;
+ break;
+ case 1:
+ img->put.contig = put1bitbwtile;
+ break;
+ }
+ }
+ break;
+ case PHOTOMETRIC_YCBCR:
+ if (img->bitspersample == 8)
+ {
+ if (initYCbCrConversion(img)!=0)
+ {
+ /*
+ * The 6.0 spec says that subsampling must be
+ * one of 1, 2, or 4, and that vertical subsampling
+ * must always be <= horizontal subsampling; so
+ * there are only a few possibilities and we just
+ * enumerate the cases.
+ * Joris: added support for the [1,2] case, nonetheless, to accomodate
+ * some OJPEG files
+ */
+ uint16 SubsamplingHor;
+ uint16 SubsamplingVer;
+ TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &SubsamplingHor, &SubsamplingVer);
+ switch ((SubsamplingHor<<4)|SubsamplingVer) {
+ case 0x44:
+ img->put.contig = putcontig8bitYCbCr44tile;
+ break;
+ case 0x42:
+ img->put.contig = putcontig8bitYCbCr42tile;
+ break;
+ case 0x41:
+ img->put.contig = putcontig8bitYCbCr41tile;
+ break;
+ case 0x22:
+ img->put.contig = putcontig8bitYCbCr22tile;
+ break;
+ case 0x21:
+ img->put.contig = putcontig8bitYCbCr21tile;
+ break;
+ case 0x12:
+ img->put.contig = putcontig8bitYCbCr12tile;
+ break;
+ case 0x11:
+ img->put.contig = putcontig8bitYCbCr11tile;
+ break;
+ }
+ }
+ }
+ break;
+ case PHOTOMETRIC_CIELAB:
+ if (buildMap(img)) {
+ if (img->bitspersample == 8)
+ img->put.contig = initCIELabConversion(img);
+ break;
+ }
+ }
+ return ((img->get!=NULL) && (img->put.contig!=NULL));
+}
+
+/*
+ * Select the appropriate conversion routine for unpacked data.
+ *
+ * NB: we assume that unpacked single channel data is directed
+ * to the "packed routines.
+ */
+static int
+PickSeparateCase(TIFFRGBAImage* img)
+{
+ img->get = TIFFIsTiled(img->tif) ? gtTileSeparate : gtStripSeparate;
+ img->put.separate = NULL;
+ switch (img->photometric) {
+ case PHOTOMETRIC_RGB:
+ switch (img->bitspersample) {
+ case 8:
+ if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+ img->put.separate = putRGBAAseparate8bittile;
+ else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+ {
+ img->put.separate = putRGBUAseparate8bittile;
+ }
+ else
+ img->put.separate = putRGBseparate8bittile;
+ break;
+ case 16:
+ if (img->alpha == EXTRASAMPLE_ASSOCALPHA)
+ {
+ img->put.separate = putRGBAAseparate16bittile;
+ }
+ else if (img->alpha == EXTRASAMPLE_UNASSALPHA)
+ {
+ img->put.separate = putRGBUAseparate16bittile;
+ }
+ else
+ {
+ img->put.separate = putRGBseparate16bittile;
+ }
+ break;
+ }
+ break;
+ case PHOTOMETRIC_YCBCR:
+ if ((img->bitspersample==8) && (img->samplesperpixel==3))
+ {
+ if (initYCbCrConversion(img)!=0)
+ {
+ uint16 hs, vs;
+ TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs);
+ switch ((hs<<4)|vs) {
+ case 0x11:
+ img->put.separate = putseparate8bitYCbCr11tile;
+ break;
+ /* TODO: add other cases here */
+ }
+ }
+ }
+ break;
+ }
+ return ((img->get!=NULL) && (img->put.separate!=NULL));
+}
+
+/*
+ * Read a whole strip off data from the file, and convert to RGBA form.
+ * If this is the last strip, then it will only contain the portion of
+ * the strip that is actually within the image space. The result is
+ * organized in bottom to top form.
+ */
+
+
+int
+TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster )
+
+{
+ char emsg[1024] = "";
+ TIFFRGBAImage img;
+ int ok;
+ uint32 rowsperstrip, rows_to_read;
+
+ if( TIFFIsTiled( tif ) )
+ {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+ "Can't use TIFFReadRGBAStrip() with tiled file.");
+ return (0);
+ }
+
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ if( (row % rowsperstrip) != 0 )
+ {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+ "Row passed to TIFFReadRGBAStrip() must be first in a strip.");
+ return (0);
+ }
+
+ if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
+
+ img.row_offset = row;
+ img.col_offset = 0;
+
+ if( row + rowsperstrip > img.height )
+ rows_to_read = img.height - row;
+ else
+ rows_to_read = rowsperstrip;
+
+ ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read );
+
+ TIFFRGBAImageEnd(&img);
+ } else {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg);
+ ok = 0;
+ }
+
+ return (ok);
+}
+
+/*
+ * Read a whole tile off data from the file, and convert to RGBA form.
+ * The returned RGBA data is organized from bottom to top of tile,
+ * and may include zeroed areas if the tile extends off the image.
+ */
+
+int
+TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster)
+
+{
+ char emsg[1024] = "";
+ TIFFRGBAImage img;
+ int ok;
+ uint32 tile_xsize, tile_ysize;
+ uint32 read_xsize, read_ysize;
+ uint32 i_row;
+
+ /*
+ * Verify that our request is legal - on a tile file, and on a
+ * tile boundary.
+ */
+
+ if( !TIFFIsTiled( tif ) )
+ {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+ "Can't use TIFFReadRGBATile() with stripped file.");
+ return (0);
+ }
+
+ TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize);
+ if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 )
+ {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif),
+ "Row/col passed to TIFFReadRGBATile() must be top"
+ "left corner of a tile.");
+ return (0);
+ }
+
+ /*
+ * Setup the RGBA reader.
+ */
+
+ if (!TIFFRGBAImageOK(tif, emsg)
+ || !TIFFRGBAImageBegin(&img, tif, 0, emsg)) {
+ TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "%s", emsg);
+ return( 0 );
+ }
+
+ /*
+ * The TIFFRGBAImageGet() function doesn't allow us to get off the
+ * edge of the image, even to fill an otherwise valid tile. So we
+ * figure out how much we can read, and fix up the tile buffer to
+ * a full tile configuration afterwards.
+ */
+
+ if( row + tile_ysize > img.height )
+ read_ysize = img.height - row;
+ else
+ read_ysize = tile_ysize;
+
+ if( col + tile_xsize > img.width )
+ read_xsize = img.width - col;
+ else
+ read_xsize = tile_xsize;
+
+ /*
+ * Read the chunk of imagery.
+ */
+
+ img.row_offset = row;
+ img.col_offset = col;
+
+ ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize );
+
+ TIFFRGBAImageEnd(&img);
+
+ /*
+ * If our read was incomplete we will need to fix up the tile by
+ * shifting the data around as if a full tile of data is being returned.
+ *
+ * This is all the more complicated because the image is organized in
+ * bottom to top format.
+ */
+
+ if( read_xsize == tile_xsize && read_ysize == tile_ysize )
+ return( ok );
+
+ for( i_row = 0; i_row < read_ysize; i_row++ ) {
+ memmove( raster + (tile_ysize - i_row - 1) * tile_xsize,
+ raster + (read_ysize - i_row - 1) * read_xsize,
+ read_xsize * sizeof(uint32) );
+ _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize,
+ 0, sizeof(uint32) * (tile_xsize - read_xsize) );
+ }
+
+ for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) {
+ _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize,
+ 0, sizeof(uint32) * tile_xsize );
+ }
+
+ return (ok);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_jbig.c b/tiff/libtiff/tif_jbig.c
new file mode 100644
index 0000000..c92ee3d
--- /dev/null
+++ b/tiff/libtiff/tif_jbig.c
@@ -0,0 +1,385 @@
+/* $Id: tif_jbig.c,v 1.2.2.3 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * JBIG Compression Algorithm Support.
+ * Contributed by Lee Howard <faxguy@deanox.com>
+ *
+ */
+
+#include "tiffiop.h"
+
+#ifdef JBIG_SUPPORT
+#include "jbig.h"
+
+typedef struct
+{
+ uint32 recvparams; /* encoded Class 2 session params */
+ char* subaddress; /* subaddress string */
+ uint32 recvtime; /* time spend receiving in seconds */
+ char* faxdcs; /* encoded fax parameters (DCS, Table 2/T.30) */
+
+ TIFFVGetMethod vgetparent;
+ TIFFVSetMethod vsetparent;
+} JBIGState;
+
+#define GetJBIGState(tif) ((JBIGState*)(tif)->tif_data)
+
+#define FIELD_RECVPARAMS (FIELD_CODEC+0)
+#define FIELD_SUBADDRESS (FIELD_CODEC+1)
+#define FIELD_RECVTIME (FIELD_CODEC+2)
+#define FIELD_FAXDCS (FIELD_CODEC+3)
+
+static const TIFFFieldInfo jbigFieldInfo[] =
+{
+ {TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS, TRUE, FALSE, "FaxRecvParams"},
+ {TIFFTAG_FAXSUBADDRESS, -1, -1, TIFF_ASCII, FIELD_SUBADDRESS, TRUE, FALSE, "FaxSubAddress"},
+ {TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME, TRUE, FALSE, "FaxRecvTime"},
+ {TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, FIELD_FAXDCS, TRUE, FALSE, "FaxDcs"},
+};
+
+static int JBIGSetupDecode(TIFF* tif)
+{
+ if (TIFFNumberOfStrips(tif) != 1)
+ {
+ TIFFError("JBIG", "Multistrip images not supported in decoder");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int JBIGDecode(TIFF* tif, tidata_t buffer, tsize_t size, tsample_t s)
+{
+ struct jbg_dec_state decoder;
+ int decodeStatus = 0;
+ unsigned char* pImage = NULL;
+ (void) size, (void) s;
+
+ if (isFillOrder(tif, tif->tif_dir.td_fillorder))
+ {
+ TIFFReverseBits(tif->tif_rawdata, tif->tif_rawdatasize);
+ }
+
+ jbg_dec_init(&decoder);
+
+#if defined(HAVE_JBG_NEWLEN)
+ jbg_newlen(tif->tif_rawdata, tif->tif_rawdatasize);
+ /*
+ * I do not check the return status of jbg_newlen because even if this
+ * function fails it does not necessarily mean that decoding the image
+ * will fail. It is generally only needed for received fax images
+ * that do not contain the actual length of the image in the BIE
+ * header. I do not log when an error occurs because that will cause
+ * problems when converting JBIG encoded TIFF's to
+ * PostScript. As long as the actual image length is contained in the
+ * BIE header jbg_dec_in should succeed.
+ */
+#endif /* HAVE_JBG_NEWLEN */
+
+ decodeStatus = jbg_dec_in(&decoder, tif->tif_rawdata,
+ tif->tif_rawdatasize, NULL);
+ if (JBG_EOK != decodeStatus)
+ {
+ /*
+ * XXX: JBG_EN constant was defined in pre-2.0 releases of the
+ * JBIG-KIT. Since the 2.0 the error reporting functions were
+ * changed. We will handle both cases here.
+ */
+ TIFFError("JBIG", "Error (%d) decoding: %s", decodeStatus,
+#if defined(JBG_EN)
+ jbg_strerror(decodeStatus, JBG_EN)
+#else
+ jbg_strerror(decodeStatus)
+#endif
+ );
+ return 0;
+ }
+
+ pImage = jbg_dec_getimage(&decoder, 0);
+ _TIFFmemcpy(buffer, pImage, jbg_dec_getsize(&decoder));
+ jbg_dec_free(&decoder);
+ return 1;
+}
+
+static int JBIGSetupEncode(TIFF* tif)
+{
+ if (TIFFNumberOfStrips(tif) != 1)
+ {
+ TIFFError("JBIG", "Multistrip images not supported in encoder");
+ return 0;
+ }
+
+ return 1;
+}
+
+static int JBIGCopyEncodedData(TIFF* tif, tidata_t pp, tsize_t cc, tsample_t s)
+{
+ (void) s;
+ while (cc > 0)
+ {
+ tsize_t n = cc;
+
+ if (tif->tif_rawcc + n > tif->tif_rawdatasize)
+ {
+ n = tif->tif_rawdatasize - tif->tif_rawcc;
+ }
+
+ assert(n > 0);
+ _TIFFmemcpy(tif->tif_rawcp, pp, n);
+ tif->tif_rawcp += n;
+ tif->tif_rawcc += n;
+ pp += n;
+ cc -= n;
+ if (tif->tif_rawcc >= tif->tif_rawdatasize &&
+ !TIFFFlushData1(tif))
+ {
+ return (-1);
+ }
+ }
+
+ return (1);
+}
+
+static void JBIGOutputBie(unsigned char* buffer, size_t len, void *userData)
+{
+ TIFF* tif = (TIFF*)userData;
+
+ if (isFillOrder(tif, tif->tif_dir.td_fillorder))
+ {
+ TIFFReverseBits(buffer, len);
+ }
+
+ JBIGCopyEncodedData(tif, buffer, len, 0);
+}
+
+static int JBIGEncode(TIFF* tif, tidata_t buffer, tsize_t size, tsample_t s)
+{
+ TIFFDirectory* dir = &tif->tif_dir;
+ struct jbg_enc_state encoder;
+
+ (void) size, (void) s;
+
+ jbg_enc_init(&encoder,
+ dir->td_imagewidth,
+ dir->td_imagelength,
+ 1,
+ &buffer,
+ JBIGOutputBie,
+ tif);
+ /*
+ * jbg_enc_out does the "real" encoding. As data is encoded,
+ * JBIGOutputBie is called, which writes the data to the directory.
+ */
+ jbg_enc_out(&encoder);
+ jbg_enc_free(&encoder);
+
+ return 1;
+}
+
+static void JBIGCleanup(TIFF* tif)
+{
+ JBIGState *sp = GetJBIGState(tif);
+
+ assert(sp != 0);
+
+ tif->tif_tagmethods.vgetfield = sp->vgetparent;
+ tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+ _TIFFfree(tif->tif_data);
+ tif->tif_data = NULL;
+
+ _TIFFSetDefaultCompressionState(tif);
+}
+
+static void JBIGPrintDir(TIFF* tif, FILE* fd, long flags)
+{
+ JBIGState* codec = GetJBIGState(tif);
+ (void)flags;
+
+ if (TIFFFieldSet(tif, FIELD_RECVPARAMS))
+ {
+ fprintf(fd,
+ " Fax Receive Parameters: %08lx\n",
+ (unsigned long)codec->recvparams);
+ }
+
+ if (TIFFFieldSet(tif, FIELD_SUBADDRESS))
+ {
+ fprintf(fd,
+ " Fax SubAddress: %s\n",
+ codec->subaddress);
+ }
+
+ if (TIFFFieldSet(tif, FIELD_RECVTIME))
+ {
+ fprintf(fd,
+ " Fax Receive Time: %lu secs\n",
+ (unsigned long)codec->recvtime);
+ }
+
+ if (TIFFFieldSet(tif, FIELD_FAXDCS))
+ {
+ fprintf(fd,
+ " Fax DCS: %s\n",
+ codec->faxdcs);
+ }
+}
+
+static int JBIGVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ JBIGState* codec = GetJBIGState(tif);
+
+ switch (tag)
+ {
+ case TIFFTAG_FAXRECVPARAMS:
+ *va_arg(ap, uint32*) = codec->recvparams;
+ break;
+
+ case TIFFTAG_FAXSUBADDRESS:
+ *va_arg(ap, char**) = codec->subaddress;
+ break;
+
+ case TIFFTAG_FAXRECVTIME:
+ *va_arg(ap, uint32*) = codec->recvtime;
+ break;
+
+ case TIFFTAG_FAXDCS:
+ *va_arg(ap, char**) = codec->faxdcs;
+ break;
+
+ default:
+ return (*codec->vgetparent)(tif, tag, ap);
+ }
+
+ return 1;
+}
+
+static int JBIGVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ JBIGState* codec = GetJBIGState(tif);
+
+ switch (tag)
+ {
+ case TIFFTAG_FAXRECVPARAMS:
+ codec->recvparams = va_arg(ap, uint32);
+ break;
+
+ case TIFFTAG_FAXSUBADDRESS:
+ _TIFFsetString(&codec->subaddress, va_arg(ap, char*));
+ break;
+
+ case TIFFTAG_FAXRECVTIME:
+ codec->recvtime = va_arg(ap, uint32);
+ break;
+
+ case TIFFTAG_FAXDCS:
+ _TIFFsetString(&codec->faxdcs, va_arg(ap, char*));
+ break;
+
+ default:
+ return (*codec->vsetparent)(tif, tag, ap);
+ }
+
+ TIFFSetFieldBit(tif, _TIFFFieldWithTag(tif, tag)->field_bit);
+ tif->tif_flags |= TIFF_DIRTYDIRECT;
+ return 1;
+}
+
+int TIFFInitJBIG(TIFF* tif, int scheme)
+{
+ JBIGState* codec = NULL;
+
+ assert(scheme == COMPRESSION_JBIG);
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, jbigFieldInfo,
+ TIFFArrayCount(jbigFieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata, "TIFFInitJBIG",
+ "Merging JBIG codec-specific tags failed");
+ return 0;
+ }
+
+ /* Allocate memory for the JBIGState structure.*/
+ tif->tif_data = (tdata_t)_TIFFmalloc(sizeof(JBIGState));
+ if (tif->tif_data == NULL)
+ {
+ TIFFError("TIFFInitJBIG", "Not enough memory for JBIGState");
+ return 0;
+ }
+ _TIFFmemset(tif->tif_data, 0, sizeof(JBIGState));
+ codec = GetJBIGState(tif);
+
+ /* Initialize codec private fields */
+ codec->recvparams = 0;
+ codec->subaddress = NULL;
+ codec->faxdcs = NULL;
+ codec->recvtime = 0;
+
+ /*
+ * Override parent get/set field methods.
+ */
+ codec->vgetparent = tif->tif_tagmethods.vgetfield;
+ codec->vsetparent = tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vgetfield = JBIGVGetField;
+ tif->tif_tagmethods.vsetfield = JBIGVSetField;
+ tif->tif_tagmethods.printdir = JBIGPrintDir;
+
+ /*
+ * These flags are set so the JBIG Codec can control when to reverse
+ * bits and when not to and to allow the jbig decoder and bit reverser
+ * to write to memory when necessary.
+ */
+ tif->tif_flags |= TIFF_NOBITREV;
+ tif->tif_flags &= ~TIFF_MAPPED;
+
+ /* Setup the function pointers for encode, decode, and cleanup. */
+ tif->tif_setupdecode = JBIGSetupDecode;
+ tif->tif_decodestrip = JBIGDecode;
+
+ tif->tif_setupencode = JBIGSetupEncode;
+ tif->tif_encodestrip = JBIGEncode;
+
+ tif->tif_cleanup = JBIGCleanup;
+
+ return 1;
+}
+
+#endif /* JBIG_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_jpeg.c b/tiff/libtiff/tif_jpeg.c
new file mode 100644
index 0000000..a967827
--- /dev/null
+++ b/tiff/libtiff/tif_jpeg.c
@@ -0,0 +1,2065 @@
+/* $Id: tif_jpeg.c,v 1.50.2.9 2010-06-14 02:47:16 fwarmerdam Exp $ */
+
+/*
+ * Copyright (c) 1994-1997 Sam Leffler
+ * Copyright (c) 1994-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#define VC_EXTRALEAN
+
+#include "tiffiop.h"
+#ifdef JPEG_SUPPORT
+
+/*
+ * TIFF Library
+ *
+ * JPEG Compression support per TIFF Technical Note #2
+ * (*not* per the original TIFF 6.0 spec).
+ *
+ * This file is simply an interface to the libjpeg library written by
+ * the Independent JPEG Group. You need release 5 or later of the IJG
+ * code, which you can find on the Internet at ftp.uu.net:/graphics/jpeg/.
+ *
+ * Contributed by Tom Lane <tgl@sss.pgh.pa.us>.
+ */
+#include <setjmp.h>
+
+int TIFFFillStrip(TIFF*, tstrip_t);
+int TIFFFillTile(TIFF*, ttile_t);
+
+/* We undefine FAR to avoid conflict with JPEG definition */
+
+#ifdef FAR
+#undef FAR
+#endif
+
+/*
+ Libjpeg's jmorecfg.h defines INT16 and INT32, but only if XMD_H is
+ not defined. Unfortunately, the MinGW and Borland compilers include
+ a typedef for INT32, which causes a conflict. MSVC does not include
+ a conficting typedef given the headers which are included.
+*/
+#if defined(__BORLANDC__) || defined(__MINGW32__)
+# define XMD_H 1
+#endif
+
+/*
+ The windows RPCNDR.H file defines boolean, but defines it with the
+ unsigned char size. You should compile JPEG library using appropriate
+ definitions in jconfig.h header, but many users compile library in wrong
+ way. That causes errors of the following type:
+
+ "JPEGLib: JPEG parameter struct mismatch: library thinks size is 432,
+ caller expects 464"
+
+ For such users we wil fix the problem here. See install.doc file from
+ the JPEG library distribution for details.
+*/
+
+/* Define "boolean" as unsigned char, not int, per Windows custom. */
+#if defined(WIN32) && !defined(__MINGW32__)
+# ifndef __RPCNDR_H__ /* don't conflict if rpcndr.h already read */
+ typedef unsigned char boolean;
+# endif
+# define HAVE_BOOLEAN /* prevent jmorecfg.h from redefining it */
+#endif
+
+#include "jpeglib.h"
+#include "jerror.h"
+
+/*
+ * We are using width_in_blocks which is supposed to be private to
+ * libjpeg. Unfortunately, the libjpeg delivered with Cygwin has
+ * renamed this member to width_in_data_units. Since the header has
+ * also renamed a define, use that unique define name in order to
+ * detect the problem header and adjust to suit.
+ */
+#if defined(D_MAX_DATA_UNITS_IN_MCU)
+#define width_in_blocks width_in_data_units
+#endif
+
+/*
+ * On some machines it may be worthwhile to use _setjmp or sigsetjmp
+ * in place of plain setjmp. These macros will make it easier.
+ */
+#define SETJMP(jbuf) setjmp(jbuf)
+#define LONGJMP(jbuf,code) longjmp(jbuf,code)
+#define JMP_BUF jmp_buf
+
+typedef struct jpeg_destination_mgr jpeg_destination_mgr;
+typedef struct jpeg_source_mgr jpeg_source_mgr;
+typedef struct jpeg_error_mgr jpeg_error_mgr;
+
+/*
+ * State block for each open TIFF file using
+ * libjpeg to do JPEG compression/decompression.
+ *
+ * libjpeg's visible state is either a jpeg_compress_struct
+ * or jpeg_decompress_struct depending on which way we
+ * are going. comm can be used to refer to the fields
+ * which are common to both.
+ *
+ * NB: cinfo is required to be the first member of JPEGState,
+ * so we can safely cast JPEGState* -> jpeg_xxx_struct*
+ * and vice versa!
+ */
+typedef struct {
+ union {
+ struct jpeg_compress_struct c;
+ struct jpeg_decompress_struct d;
+ struct jpeg_common_struct comm;
+ } cinfo; /* NB: must be first */
+ int cinfo_initialized;
+
+ jpeg_error_mgr err; /* libjpeg error manager */
+ JMP_BUF exit_jmpbuf; /* for catching libjpeg failures */
+ /*
+ * The following two members could be a union, but
+ * they're small enough that it's not worth the effort.
+ */
+ jpeg_destination_mgr dest; /* data dest for compression */
+ jpeg_source_mgr src; /* data source for decompression */
+ /* private state */
+ TIFF* tif; /* back link needed by some code */
+ uint16 photometric; /* copy of PhotometricInterpretation */
+ uint16 h_sampling; /* luminance sampling factors */
+ uint16 v_sampling;
+ tsize_t bytesperline; /* decompressed bytes per scanline */
+ /* pointers to intermediate buffers when processing downsampled data */
+ JSAMPARRAY ds_buffer[MAX_COMPONENTS];
+ int scancount; /* number of "scanlines" accumulated */
+ int samplesperclump;
+
+ TIFFVGetMethod vgetparent; /* super-class method */
+ TIFFVSetMethod vsetparent; /* super-class method */
+ TIFFPrintMethod printdir; /* super-class method */
+ TIFFStripMethod defsparent; /* super-class method */
+ TIFFTileMethod deftparent; /* super-class method */
+ /* pseudo-tag fields */
+ void* jpegtables; /* JPEGTables tag value, or NULL */
+ uint32 jpegtables_length; /* number of bytes in same */
+ int jpegquality; /* Compression quality level */
+ int jpegcolormode; /* Auto RGB<=>YCbCr convert? */
+ int jpegtablesmode; /* What to put in JPEGTables */
+
+ int ycbcrsampling_fetched;
+ uint32 recvparams; /* encoded Class 2 session params */
+ char* subaddress; /* subaddress string */
+ uint32 recvtime; /* time spent receiving (secs) */
+ char* faxdcs; /* encoded fax parameters (DCS, Table 2/T.30) */
+} JPEGState;
+
+#define JState(tif) ((JPEGState*)(tif)->tif_data)
+
+static int JPEGDecode(TIFF*, tidata_t, tsize_t, tsample_t);
+static int JPEGDecodeRaw(TIFF*, tidata_t, tsize_t, tsample_t);
+static int JPEGEncode(TIFF*, tidata_t, tsize_t, tsample_t);
+static int JPEGEncodeRaw(TIFF*, tidata_t, tsize_t, tsample_t);
+static int JPEGInitializeLibJPEG( TIFF * tif,
+ int force_encode, int force_decode );
+
+#define FIELD_JPEGTABLES (FIELD_CODEC+0)
+#define FIELD_RECVPARAMS (FIELD_CODEC+1)
+#define FIELD_SUBADDRESS (FIELD_CODEC+2)
+#define FIELD_RECVTIME (FIELD_CODEC+3)
+#define FIELD_FAXDCS (FIELD_CODEC+4)
+
+static const TIFFFieldInfo jpegFieldInfo[] = {
+ { TIFFTAG_JPEGTABLES, -3,-3, TIFF_UNDEFINED, FIELD_JPEGTABLES,
+ FALSE, TRUE, "JPEGTables" },
+ { TIFFTAG_JPEGQUALITY, 0, 0, TIFF_ANY, FIELD_PSEUDO,
+ TRUE, FALSE, "" },
+ { TIFFTAG_JPEGCOLORMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO,
+ FALSE, FALSE, "" },
+ { TIFFTAG_JPEGTABLESMODE, 0, 0, TIFF_ANY, FIELD_PSEUDO,
+ FALSE, FALSE, "" },
+ /* Specific for JPEG in faxes */
+ { TIFFTAG_FAXRECVPARAMS, 1, 1, TIFF_LONG, FIELD_RECVPARAMS,
+ TRUE, FALSE, "FaxRecvParams" },
+ { TIFFTAG_FAXSUBADDRESS, -1,-1, TIFF_ASCII, FIELD_SUBADDRESS,
+ TRUE, FALSE, "FaxSubAddress" },
+ { TIFFTAG_FAXRECVTIME, 1, 1, TIFF_LONG, FIELD_RECVTIME,
+ TRUE, FALSE, "FaxRecvTime" },
+ { TIFFTAG_FAXDCS, -1, -1, TIFF_ASCII, FIELD_FAXDCS,
+ TRUE, FALSE, "FaxDcs" },
+};
+#define N(a) (sizeof (a) / sizeof (a[0]))
+
+/*
+ * libjpeg interface layer.
+ *
+ * We use setjmp/longjmp to return control to libtiff
+ * when a fatal error is encountered within the JPEG
+ * library. We also direct libjpeg error and warning
+ * messages through the appropriate libtiff handlers.
+ */
+
+/*
+ * Error handling routines (these replace corresponding
+ * IJG routines from jerror.c). These are used for both
+ * compression and decompression.
+ */
+static void
+TIFFjpeg_error_exit(j_common_ptr cinfo)
+{
+ JPEGState *sp = (JPEGState *) cinfo; /* NB: cinfo assumed first */
+ char buffer[JMSG_LENGTH_MAX];
+
+ (*cinfo->err->format_message) (cinfo, buffer);
+ TIFFErrorExt(sp->tif->tif_clientdata, "JPEGLib", "%s", buffer); /* display the error message */
+ jpeg_abort(cinfo); /* clean up libjpeg state */
+ LONGJMP(sp->exit_jmpbuf, 1); /* return to libtiff caller */
+}
+
+/*
+ * This routine is invoked only for warning messages,
+ * since error_exit does its own thing and trace_level
+ * is never set > 0.
+ */
+static void
+TIFFjpeg_output_message(j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+
+ (*cinfo->err->format_message) (cinfo, buffer);
+ TIFFWarningExt(((JPEGState *) cinfo)->tif->tif_clientdata, "JPEGLib", "%s", buffer);
+}
+
+/*
+ * Interface routines. This layer of routines exists
+ * primarily to limit side-effects from using setjmp.
+ * Also, normal/error returns are converted into return
+ * values per libtiff practice.
+ */
+#define CALLJPEG(sp, fail, op) (SETJMP((sp)->exit_jmpbuf) ? (fail) : (op))
+#define CALLVJPEG(sp, op) CALLJPEG(sp, 0, ((op),1))
+
+static int
+TIFFjpeg_create_compress(JPEGState* sp)
+{
+ /* initialize JPEG error handling */
+ sp->cinfo.c.err = jpeg_std_error(&sp->err);
+ sp->err.error_exit = TIFFjpeg_error_exit;
+ sp->err.output_message = TIFFjpeg_output_message;
+
+ return CALLVJPEG(sp, jpeg_create_compress(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_create_decompress(JPEGState* sp)
+{
+ /* initialize JPEG error handling */
+ sp->cinfo.d.err = jpeg_std_error(&sp->err);
+ sp->err.error_exit = TIFFjpeg_error_exit;
+ sp->err.output_message = TIFFjpeg_output_message;
+
+ return CALLVJPEG(sp, jpeg_create_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_set_defaults(JPEGState* sp)
+{
+ return CALLVJPEG(sp, jpeg_set_defaults(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_set_colorspace(JPEGState* sp, J_COLOR_SPACE colorspace)
+{
+ return CALLVJPEG(sp, jpeg_set_colorspace(&sp->cinfo.c, colorspace));
+}
+
+static int
+TIFFjpeg_set_quality(JPEGState* sp, int quality, boolean force_baseline)
+{
+ return CALLVJPEG(sp,
+ jpeg_set_quality(&sp->cinfo.c, quality, force_baseline));
+}
+
+static int
+TIFFjpeg_suppress_tables(JPEGState* sp, boolean suppress)
+{
+ return CALLVJPEG(sp, jpeg_suppress_tables(&sp->cinfo.c, suppress));
+}
+
+static int
+TIFFjpeg_start_compress(JPEGState* sp, boolean write_all_tables)
+{
+ return CALLVJPEG(sp,
+ jpeg_start_compress(&sp->cinfo.c, write_all_tables));
+}
+
+static int
+TIFFjpeg_write_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int num_lines)
+{
+ return CALLJPEG(sp, -1, (int) jpeg_write_scanlines(&sp->cinfo.c,
+ scanlines, (JDIMENSION) num_lines));
+}
+
+static int
+TIFFjpeg_write_raw_data(JPEGState* sp, JSAMPIMAGE data, int num_lines)
+{
+ return CALLJPEG(sp, -1, (int) jpeg_write_raw_data(&sp->cinfo.c,
+ data, (JDIMENSION) num_lines));
+}
+
+static int
+TIFFjpeg_finish_compress(JPEGState* sp)
+{
+ return CALLVJPEG(sp, jpeg_finish_compress(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_write_tables(JPEGState* sp)
+{
+ return CALLVJPEG(sp, jpeg_write_tables(&sp->cinfo.c));
+}
+
+static int
+TIFFjpeg_read_header(JPEGState* sp, boolean require_image)
+{
+ return CALLJPEG(sp, -1, jpeg_read_header(&sp->cinfo.d, require_image));
+}
+
+static int
+TIFFjpeg_start_decompress(JPEGState* sp)
+{
+ return CALLVJPEG(sp, jpeg_start_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_read_scanlines(JPEGState* sp, JSAMPARRAY scanlines, int max_lines)
+{
+ return CALLJPEG(sp, -1, (int) jpeg_read_scanlines(&sp->cinfo.d,
+ scanlines, (JDIMENSION) max_lines));
+}
+
+static int
+TIFFjpeg_read_raw_data(JPEGState* sp, JSAMPIMAGE data, int max_lines)
+{
+ return CALLJPEG(sp, -1, (int) jpeg_read_raw_data(&sp->cinfo.d,
+ data, (JDIMENSION) max_lines));
+}
+
+static int
+TIFFjpeg_finish_decompress(JPEGState* sp)
+{
+ return CALLJPEG(sp, -1, (int) jpeg_finish_decompress(&sp->cinfo.d));
+}
+
+static int
+TIFFjpeg_abort(JPEGState* sp)
+{
+ return CALLVJPEG(sp, jpeg_abort(&sp->cinfo.comm));
+}
+
+static int
+TIFFjpeg_destroy(JPEGState* sp)
+{
+ return CALLVJPEG(sp, jpeg_destroy(&sp->cinfo.comm));
+}
+
+static JSAMPARRAY
+TIFFjpeg_alloc_sarray(JPEGState* sp, int pool_id,
+ JDIMENSION samplesperrow, JDIMENSION numrows)
+{
+ return CALLJPEG(sp, (JSAMPARRAY) NULL,
+ (*sp->cinfo.comm.mem->alloc_sarray)
+ (&sp->cinfo.comm, pool_id, samplesperrow, numrows));
+}
+
+/*
+ * JPEG library destination data manager.
+ * These routines direct compressed data from libjpeg into the
+ * libtiff output buffer.
+ */
+
+static void
+std_init_destination(j_compress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+ TIFF* tif = sp->tif;
+
+ sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata;
+ sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize;
+}
+
+static boolean
+std_empty_output_buffer(j_compress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+ TIFF* tif = sp->tif;
+
+ /* the entire buffer has been filled */
+ tif->tif_rawcc = tif->tif_rawdatasize;
+ TIFFFlushData1(tif);
+ sp->dest.next_output_byte = (JOCTET*) tif->tif_rawdata;
+ sp->dest.free_in_buffer = (size_t) tif->tif_rawdatasize;
+
+ return (TRUE);
+}
+
+static void
+std_term_destination(j_compress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+ TIFF* tif = sp->tif;
+
+ tif->tif_rawcp = (tidata_t) sp->dest.next_output_byte;
+ tif->tif_rawcc =
+ tif->tif_rawdatasize - (tsize_t) sp->dest.free_in_buffer;
+ /* NB: libtiff does the final buffer flush */
+}
+
+static void
+TIFFjpeg_data_dest(JPEGState* sp, TIFF* tif)
+{
+ (void) tif;
+ sp->cinfo.c.dest = &sp->dest;
+ sp->dest.init_destination = std_init_destination;
+ sp->dest.empty_output_buffer = std_empty_output_buffer;
+ sp->dest.term_destination = std_term_destination;
+}
+
+/*
+ * Alternate destination manager for outputting to JPEGTables field.
+ */
+
+static void
+tables_init_destination(j_compress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+
+ /* while building, jpegtables_length is allocated buffer size */
+ sp->dest.next_output_byte = (JOCTET*) sp->jpegtables;
+ sp->dest.free_in_buffer = (size_t) sp->jpegtables_length;
+}
+
+static boolean
+tables_empty_output_buffer(j_compress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+ void* newbuf;
+
+ /* the entire buffer has been filled; enlarge it by 1000 bytes */
+ newbuf = _TIFFrealloc((tdata_t) sp->jpegtables,
+ (tsize_t) (sp->jpegtables_length + 1000));
+ if (newbuf == NULL)
+ ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 100);
+ sp->dest.next_output_byte = (JOCTET*) newbuf + sp->jpegtables_length;
+ sp->dest.free_in_buffer = (size_t) 1000;
+ sp->jpegtables = newbuf;
+ sp->jpegtables_length += 1000;
+ return (TRUE);
+}
+
+static void
+tables_term_destination(j_compress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+
+ /* set tables length to number of bytes actually emitted */
+ sp->jpegtables_length -= sp->dest.free_in_buffer;
+}
+
+static int
+TIFFjpeg_tables_dest(JPEGState* sp, TIFF* tif)
+{
+ (void) tif;
+ /*
+ * Allocate a working buffer for building tables.
+ * Initial size is 1000 bytes, which is usually adequate.
+ */
+ if (sp->jpegtables)
+ _TIFFfree(sp->jpegtables);
+ sp->jpegtables_length = 1000;
+ sp->jpegtables = (void*) _TIFFmalloc((tsize_t) sp->jpegtables_length);
+ if (sp->jpegtables == NULL) {
+ sp->jpegtables_length = 0;
+ TIFFErrorExt(sp->tif->tif_clientdata, "TIFFjpeg_tables_dest", "No space for JPEGTables");
+ return (0);
+ }
+ sp->cinfo.c.dest = &sp->dest;
+ sp->dest.init_destination = tables_init_destination;
+ sp->dest.empty_output_buffer = tables_empty_output_buffer;
+ sp->dest.term_destination = tables_term_destination;
+ return (1);
+}
+
+/*
+ * JPEG library source data manager.
+ * These routines supply compressed data to libjpeg.
+ */
+
+static void
+std_init_source(j_decompress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+ TIFF* tif = sp->tif;
+
+ sp->src.next_input_byte = (const JOCTET*) tif->tif_rawdata;
+ sp->src.bytes_in_buffer = (size_t) tif->tif_rawcc;
+}
+
+static boolean
+std_fill_input_buffer(j_decompress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState* ) cinfo;
+ static const JOCTET dummy_EOI[2] = { 0xFF, JPEG_EOI };
+
+ /*
+ * Should never get here since entire strip/tile is
+ * read into memory before the decompressor is called,
+ * and thus was supplied by init_source.
+ */
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* insert a fake EOI marker */
+ sp->src.next_input_byte = dummy_EOI;
+ sp->src.bytes_in_buffer = 2;
+ return (TRUE);
+}
+
+static void
+std_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+
+ if (num_bytes > 0) {
+ if (num_bytes > (long) sp->src.bytes_in_buffer) {
+ /* oops, buffer overrun */
+ (void) std_fill_input_buffer(cinfo);
+ } else {
+ sp->src.next_input_byte += (size_t) num_bytes;
+ sp->src.bytes_in_buffer -= (size_t) num_bytes;
+ }
+ }
+}
+
+static void
+std_term_source(j_decompress_ptr cinfo)
+{
+ /* No work necessary here */
+ /* Or must we update tif->tif_rawcp, tif->tif_rawcc ??? */
+ /* (if so, need empty tables_term_source!) */
+ (void) cinfo;
+}
+
+static void
+TIFFjpeg_data_src(JPEGState* sp, TIFF* tif)
+{
+ (void) tif;
+ sp->cinfo.d.src = &sp->src;
+ sp->src.init_source = std_init_source;
+ sp->src.fill_input_buffer = std_fill_input_buffer;
+ sp->src.skip_input_data = std_skip_input_data;
+ sp->src.resync_to_restart = jpeg_resync_to_restart;
+ sp->src.term_source = std_term_source;
+ sp->src.bytes_in_buffer = 0; /* for safety */
+ sp->src.next_input_byte = NULL;
+}
+
+/*
+ * Alternate source manager for reading from JPEGTables.
+ * We can share all the code except for the init routine.
+ */
+
+static void
+tables_init_source(j_decompress_ptr cinfo)
+{
+ JPEGState* sp = (JPEGState*) cinfo;
+
+ sp->src.next_input_byte = (const JOCTET*) sp->jpegtables;
+ sp->src.bytes_in_buffer = (size_t) sp->jpegtables_length;
+}
+
+static void
+TIFFjpeg_tables_src(JPEGState* sp, TIFF* tif)
+{
+ TIFFjpeg_data_src(sp, tif);
+ sp->src.init_source = tables_init_source;
+}
+
+/*
+ * Allocate downsampled-data buffers needed for downsampled I/O.
+ * We use values computed in jpeg_start_compress or jpeg_start_decompress.
+ * We use libjpeg's allocator so that buffers will be released automatically
+ * when done with strip/tile.
+ * This is also a handy place to compute samplesperclump, bytesperline.
+ */
+static int
+alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info,
+ int num_components)
+{
+ JPEGState* sp = JState(tif);
+ int ci;
+ jpeg_component_info* compptr;
+ JSAMPARRAY buf;
+ int samples_per_clump = 0;
+
+ for (ci = 0, compptr = comp_info; ci < num_components;
+ ci++, compptr++) {
+ samples_per_clump += compptr->h_samp_factor *
+ compptr->v_samp_factor;
+ buf = TIFFjpeg_alloc_sarray(sp, JPOOL_IMAGE,
+ compptr->width_in_blocks * DCTSIZE,
+ (JDIMENSION) (compptr->v_samp_factor*DCTSIZE));
+ if (buf == NULL)
+ return (0);
+ sp->ds_buffer[ci] = buf;
+ }
+ sp->samplesperclump = samples_per_clump;
+ return (1);
+}
+
+
+/*
+ * JPEG Decoding.
+ */
+
+static int
+JPEGSetupDecode(TIFF* tif)
+{
+ JPEGState* sp = JState(tif);
+ TIFFDirectory *td = &tif->tif_dir;
+
+ JPEGInitializeLibJPEG( tif, 0, 1 );
+
+ assert(sp != NULL);
+ assert(sp->cinfo.comm.is_decompressor);
+
+ /* Read JPEGTables if it is present */
+ if (TIFFFieldSet(tif,FIELD_JPEGTABLES)) {
+ TIFFjpeg_tables_src(sp, tif);
+ if(TIFFjpeg_read_header(sp,FALSE) != JPEG_HEADER_TABLES_ONLY) {
+ TIFFErrorExt(tif->tif_clientdata, "JPEGSetupDecode", "Bogus JPEGTables field");
+ return (0);
+ }
+ }
+
+ /* Grab parameters that are same for all strips/tiles */
+ sp->photometric = td->td_photometric;
+ switch (sp->photometric) {
+ case PHOTOMETRIC_YCBCR:
+ sp->h_sampling = td->td_ycbcrsubsampling[0];
+ sp->v_sampling = td->td_ycbcrsubsampling[1];
+ break;
+ default:
+ /* TIFF 6.0 forbids subsampling of all other color spaces */
+ sp->h_sampling = 1;
+ sp->v_sampling = 1;
+ break;
+ }
+
+ /* Set up for reading normal data */
+ TIFFjpeg_data_src(sp, tif);
+ tif->tif_postdecode = _TIFFNoPostDecode; /* override byte swapping */
+ return (1);
+}
+
+/*
+ * Set up for decoding a strip or tile.
+ */
+static int
+JPEGPreDecode(TIFF* tif, tsample_t s)
+{
+ JPEGState *sp = JState(tif);
+ TIFFDirectory *td = &tif->tif_dir;
+ static const char module[] = "JPEGPreDecode";
+ uint32 segment_width, segment_height;
+ int downsampled_output;
+ int ci;
+
+ assert(sp != NULL);
+ assert(sp->cinfo.comm.is_decompressor);
+ /*
+ * Reset decoder state from any previous strip/tile,
+ * in case application didn't read the whole strip.
+ */
+ if (!TIFFjpeg_abort(sp))
+ return (0);
+ /*
+ * Read the header for this strip/tile.
+ */
+ if (TIFFjpeg_read_header(sp, TRUE) != JPEG_HEADER_OK)
+ return (0);
+ /*
+ * Check image parameters and set decompression parameters.
+ */
+ segment_width = td->td_imagewidth;
+ segment_height = td->td_imagelength - tif->tif_row;
+ if (isTiled(tif)) {
+ segment_width = td->td_tilewidth;
+ segment_height = td->td_tilelength;
+ sp->bytesperline = TIFFTileRowSize(tif);
+ } else {
+ if (segment_height > td->td_rowsperstrip)
+ segment_height = td->td_rowsperstrip;
+ sp->bytesperline = TIFFOldScanlineSize(tif);
+ }
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) {
+ /*
+ * For PC 2, scale down the expected strip/tile size
+ * to match a downsampled component
+ */
+ segment_width = TIFFhowmany(segment_width, sp->h_sampling);
+ segment_height = TIFFhowmany(segment_height, sp->v_sampling);
+ }
+ if (sp->cinfo.d.image_width < segment_width ||
+ sp->cinfo.d.image_height < segment_height) {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "Improper JPEG strip/tile size, "
+ "expected %dx%d, got %dx%d",
+ segment_width, segment_height,
+ sp->cinfo.d.image_width,
+ sp->cinfo.d.image_height);
+ }
+ if (sp->cinfo.d.image_width > segment_width ||
+ sp->cinfo.d.image_height > segment_height) {
+ /*
+ * This case could be dangerous, if the strip or tile size has
+ * been reported as less than the amount of data jpeg will
+ * return, some potential security issues arise. Catch this
+ * case and error out.
+ */
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "JPEG strip/tile size exceeds expected dimensions,"
+ " expected %dx%d, got %dx%d",
+ segment_width, segment_height,
+ sp->cinfo.d.image_width, sp->cinfo.d.image_height);
+ return (0);
+ }
+ if (sp->cinfo.d.num_components !=
+ (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+ td->td_samplesperpixel : 1)) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG component count");
+ return (0);
+ }
+#ifdef JPEG_LIB_MK1
+ if (12 != td->td_bitspersample && 8 != td->td_bitspersample) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision");
+ return (0);
+ }
+ sp->cinfo.d.data_precision = td->td_bitspersample;
+ sp->cinfo.d.bits_in_jsample = td->td_bitspersample;
+#else
+ if (sp->cinfo.d.data_precision != td->td_bitspersample) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG data precision");
+ return (0);
+ }
+#endif
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+ /* Component 0 should have expected sampling factors */
+ if (sp->cinfo.d.comp_info[0].h_samp_factor != sp->h_sampling ||
+ sp->cinfo.d.comp_info[0].v_samp_factor != sp->v_sampling) {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "Improper JPEG sampling factors %d,%d\n"
+ "Apparently should be %d,%d.",
+ sp->cinfo.d.comp_info[0].h_samp_factor,
+ sp->cinfo.d.comp_info[0].v_samp_factor,
+ sp->h_sampling, sp->v_sampling);
+
+ /*
+ * There are potential security issues here
+ * for decoders that have already allocated
+ * buffers based on the expected sampling
+ * factors. Lets check the sampling factors
+ * dont exceed what we were expecting.
+ */
+ if (sp->cinfo.d.comp_info[0].h_samp_factor
+ > sp->h_sampling
+ || sp->cinfo.d.comp_info[0].v_samp_factor
+ > sp->v_sampling) {
+ TIFFErrorExt(tif->tif_clientdata,
+ module,
+ "Cannot honour JPEG sampling factors"
+ " that exceed those specified.");
+ return (0);
+ }
+
+ /*
+ * XXX: Files written by the Intergraph software
+ * has different sampling factors stored in the
+ * TIFF tags and in the JPEG structures. We will
+ * try to deduce Intergraph files by the presense
+ * of the tag 33918.
+ */
+ if (!_TIFFFindFieldInfo(tif, 33918, TIFF_ANY)) {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "Decompressor will try reading with "
+ "sampling %d,%d.",
+ sp->cinfo.d.comp_info[0].h_samp_factor,
+ sp->cinfo.d.comp_info[0].v_samp_factor);
+
+ sp->h_sampling = (uint16)
+ sp->cinfo.d.comp_info[0].h_samp_factor;
+ sp->v_sampling = (uint16)
+ sp->cinfo.d.comp_info[0].v_samp_factor;
+ }
+ }
+ /* Rest should have sampling factors 1,1 */
+ for (ci = 1; ci < sp->cinfo.d.num_components; ci++) {
+ if (sp->cinfo.d.comp_info[ci].h_samp_factor != 1 ||
+ sp->cinfo.d.comp_info[ci].v_samp_factor != 1) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors");
+ return (0);
+ }
+ }
+ } else {
+ /* PC 2's single component should have sampling factors 1,1 */
+ if (sp->cinfo.d.comp_info[0].h_samp_factor != 1 ||
+ sp->cinfo.d.comp_info[0].v_samp_factor != 1) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Improper JPEG sampling factors");
+ return (0);
+ }
+ }
+ downsampled_output = FALSE;
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
+ sp->photometric == PHOTOMETRIC_YCBCR &&
+ sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+ /* Convert YCbCr to RGB */
+ sp->cinfo.d.jpeg_color_space = JCS_YCbCr;
+ sp->cinfo.d.out_color_space = JCS_RGB;
+ } else {
+ /* Suppress colorspace handling */
+ sp->cinfo.d.jpeg_color_space = JCS_UNKNOWN;
+ sp->cinfo.d.out_color_space = JCS_UNKNOWN;
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
+ (sp->h_sampling != 1 || sp->v_sampling != 1))
+ downsampled_output = TRUE;
+ /* XXX what about up-sampling? */
+ }
+ if (downsampled_output) {
+ /* Need to use raw-data interface to libjpeg */
+ sp->cinfo.d.raw_data_out = TRUE;
+ tif->tif_decoderow = JPEGDecodeRaw;
+ tif->tif_decodestrip = JPEGDecodeRaw;
+ tif->tif_decodetile = JPEGDecodeRaw;
+ } else {
+ /* Use normal interface to libjpeg */
+ sp->cinfo.d.raw_data_out = FALSE;
+ tif->tif_decoderow = JPEGDecode;
+ tif->tif_decodestrip = JPEGDecode;
+ tif->tif_decodetile = JPEGDecode;
+ }
+ /* Start JPEG decompressor */
+ if (!TIFFjpeg_start_decompress(sp))
+ return (0);
+ /* Allocate downsampled-data buffers if needed */
+ if (downsampled_output) {
+ if (!alloc_downsampled_buffers(tif, sp->cinfo.d.comp_info,
+ sp->cinfo.d.num_components))
+ return (0);
+ sp->scancount = DCTSIZE; /* mark buffer empty */
+ }
+ return (1);
+}
+
+/*
+ * Decode a chunk of pixels.
+ * "Standard" case: returned data is not downsampled.
+ */
+/*ARGSUSED*/ static int
+JPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
+{
+ JPEGState *sp = JState(tif);
+ tsize_t nrows;
+ (void) s;
+
+ nrows = cc / sp->bytesperline;
+ if (cc % sp->bytesperline)
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline not read");
+
+ if( nrows > (int) sp->cinfo.d.image_height )
+ nrows = sp->cinfo.d.image_height;
+
+ /* data is expected to be read in multiples of a scanline */
+ if (nrows)
+ {
+ JSAMPROW line_work_buf = NULL;
+
+ /*
+ ** For 6B, only use temporary buffer for 12 bit imagery.
+ ** For Mk1 always use it.
+ */
+#if !defined(JPEG_LIB_MK1)
+ if( sp->cinfo.d.data_precision == 12 )
+#endif
+ {
+ line_work_buf = (JSAMPROW)
+ _TIFFmalloc(sizeof(short) * sp->cinfo.d.output_width
+ * sp->cinfo.d.num_components );
+ }
+
+ do {
+ if( line_work_buf != NULL )
+ {
+ /*
+ ** In the MK1 case, we aways read into a 16bit buffer, and then
+ ** pack down to 12bit or 8bit. In 6B case we only read into 16
+ ** bit buffer for 12bit data, which we need to repack.
+ */
+ if (TIFFjpeg_read_scanlines(sp, &line_work_buf, 1) != 1)
+ return (0);
+
+ if( sp->cinfo.d.data_precision == 12 )
+ {
+ int value_pairs = (sp->cinfo.d.output_width
+ * sp->cinfo.d.num_components) / 2;
+ int iPair;
+
+ for( iPair = 0; iPair < value_pairs; iPair++ )
+ {
+ unsigned char *out_ptr =
+ ((unsigned char *) buf) + iPair * 3;
+ JSAMPLE *in_ptr = line_work_buf + iPair * 2;
+
+ out_ptr[0] = (in_ptr[0] & 0xff0) >> 4;
+ out_ptr[1] = ((in_ptr[0] & 0xf) << 4)
+ | ((in_ptr[1] & 0xf00) >> 8);
+ out_ptr[2] = ((in_ptr[1] & 0xff) >> 0);
+ }
+ }
+ else if( sp->cinfo.d.data_precision == 8 )
+ {
+ int value_count = (sp->cinfo.d.output_width
+ * sp->cinfo.d.num_components);
+ int iValue;
+
+ for( iValue = 0; iValue < value_count; iValue++ )
+ {
+ ((unsigned char *) buf)[iValue] =
+ line_work_buf[iValue] & 0xff;
+ }
+ }
+ }
+ else
+ {
+ /*
+ ** In the libjpeg6b 8bit case. We read directly into the
+ ** TIFF buffer.
+ */
+ JSAMPROW bufptr = (JSAMPROW)buf;
+
+ if (TIFFjpeg_read_scanlines(sp, &bufptr, 1) != 1)
+ return (0);
+ }
+
+ ++tif->tif_row;
+ buf += sp->bytesperline;
+ cc -= sp->bytesperline;
+ } while (--nrows > 0);
+
+ if( line_work_buf != NULL )
+ _TIFFfree( line_work_buf );
+ }
+
+ /* Close down the decompressor if we've finished the strip or tile. */
+ return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height
+ || TIFFjpeg_finish_decompress(sp);
+}
+
+/*
+ * Decode a chunk of pixels.
+ * Returned data is downsampled per sampling factors.
+ */
+/*ARGSUSED*/ static int
+JPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
+{
+ JPEGState *sp = JState(tif);
+ tsize_t nrows;
+ (void) s;
+
+ /* data is expected to be read in multiples of a scanline */
+ if ( (nrows = sp->cinfo.d.image_height) ) {
+ /* Cb,Cr both have sampling factors 1, so this is correct */
+ JDIMENSION clumps_per_line = sp->cinfo.d.comp_info[1].downsampled_width;
+ int samples_per_clump = sp->samplesperclump;
+
+#ifdef JPEG_LIB_MK1
+ unsigned short* tmpbuf = _TIFFmalloc(sizeof(unsigned short) *
+ sp->cinfo.d.output_width *
+ sp->cinfo.d.num_components);
+#endif
+
+ do {
+ jpeg_component_info *compptr;
+ int ci, clumpoffset;
+
+ /* Reload downsampled-data buffer if needed */
+ if (sp->scancount >= DCTSIZE) {
+ int n = sp->cinfo.d.max_v_samp_factor * DCTSIZE;
+ if (TIFFjpeg_read_raw_data(sp, sp->ds_buffer, n) != n)
+ return (0);
+ sp->scancount = 0;
+ }
+ /*
+ * Fastest way to unseparate data is to make one pass
+ * over the scanline for each row of each component.
+ */
+ clumpoffset = 0; /* first sample in clump */
+ for (ci = 0, compptr = sp->cinfo.d.comp_info;
+ ci < sp->cinfo.d.num_components;
+ ci++, compptr++) {
+ int hsamp = compptr->h_samp_factor;
+ int vsamp = compptr->v_samp_factor;
+ int ypos;
+
+ for (ypos = 0; ypos < vsamp; ypos++) {
+ JSAMPLE *inptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos];
+#ifdef JPEG_LIB_MK1
+ JSAMPLE *outptr = (JSAMPLE*)tmpbuf + clumpoffset;
+#else
+ JSAMPLE *outptr = (JSAMPLE*)buf + clumpoffset;
+#endif
+ JDIMENSION nclump;
+
+ if (hsamp == 1) {
+ /* fast path for at least Cb and Cr */
+ for (nclump = clumps_per_line; nclump-- > 0; ) {
+ outptr[0] = *inptr++;
+ outptr += samples_per_clump;
+ }
+ } else {
+ int xpos;
+
+ /* general case */
+ for (nclump = clumps_per_line; nclump-- > 0; ) {
+ for (xpos = 0; xpos < hsamp; xpos++)
+ outptr[xpos] = *inptr++;
+ outptr += samples_per_clump;
+ }
+ }
+ clumpoffset += hsamp;
+ }
+ }
+
+#ifdef JPEG_LIB_MK1
+ {
+ if (sp->cinfo.d.data_precision == 8)
+ {
+ int i=0;
+ int len = sp->cinfo.d.output_width * sp->cinfo.d.num_components;
+ for (i=0; i<len; i++)
+ {
+ ((unsigned char*)buf)[i] = tmpbuf[i] & 0xff;
+ }
+ }
+ else
+ { // 12-bit
+ int value_pairs = (sp->cinfo.d.output_width
+ * sp->cinfo.d.num_components) / 2;
+ int iPair;
+ for( iPair = 0; iPair < value_pairs; iPair++ )
+ {
+ unsigned char *out_ptr = ((unsigned char *) buf) + iPair * 3;
+ JSAMPLE *in_ptr = tmpbuf + iPair * 2;
+ out_ptr[0] = (in_ptr[0] & 0xff0) >> 4;
+ out_ptr[1] = ((in_ptr[0] & 0xf) << 4)
+ | ((in_ptr[1] & 0xf00) >> 8);
+ out_ptr[2] = ((in_ptr[1] & 0xff) >> 0);
+ }
+ }
+ }
+#endif
+
+ sp->scancount ++;
+ tif->tif_row += sp->v_sampling;
+ /* increment/decrement of buf and cc is still incorrect, but should not matter
+ * TODO: resolve this */
+ buf += sp->bytesperline;
+ cc -= sp->bytesperline;
+ nrows -= sp->v_sampling;
+ } while (nrows > 0);
+
+#ifdef JPEG_LIB_MK1
+ _TIFFfree(tmpbuf);
+#endif
+
+ }
+
+ /* Close down the decompressor if done. */
+ return sp->cinfo.d.output_scanline < sp->cinfo.d.output_height
+ || TIFFjpeg_finish_decompress(sp);
+}
+
+
+/*
+ * JPEG Encoding.
+ */
+
+static void
+unsuppress_quant_table (JPEGState* sp, int tblno)
+{
+ JQUANT_TBL* qtbl;
+
+ if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL)
+ qtbl->sent_table = FALSE;
+}
+
+static void
+unsuppress_huff_table (JPEGState* sp, int tblno)
+{
+ JHUFF_TBL* htbl;
+
+ if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL)
+ htbl->sent_table = FALSE;
+ if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL)
+ htbl->sent_table = FALSE;
+}
+
+static int
+prepare_JPEGTables(TIFF* tif)
+{
+ JPEGState* sp = JState(tif);
+
+ JPEGInitializeLibJPEG( tif, 0, 0 );
+
+ /* Initialize quant tables for current quality setting */
+ if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE))
+ return (0);
+ /* Mark only the tables we want for output */
+ /* NB: chrominance tables are currently used only with YCbCr */
+ if (!TIFFjpeg_suppress_tables(sp, TRUE))
+ return (0);
+ if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) {
+ unsuppress_quant_table(sp, 0);
+ if (sp->photometric == PHOTOMETRIC_YCBCR)
+ unsuppress_quant_table(sp, 1);
+ }
+ if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF) {
+ unsuppress_huff_table(sp, 0);
+ if (sp->photometric == PHOTOMETRIC_YCBCR)
+ unsuppress_huff_table(sp, 1);
+ }
+ /* Direct libjpeg output into jpegtables */
+ if (!TIFFjpeg_tables_dest(sp, tif))
+ return (0);
+ /* Emit tables-only datastream */
+ if (!TIFFjpeg_write_tables(sp))
+ return (0);
+
+ return (1);
+}
+
+static int
+JPEGSetupEncode(TIFF* tif)
+{
+ JPEGState* sp = JState(tif);
+ TIFFDirectory *td = &tif->tif_dir;
+ static const char module[] = "JPEGSetupEncode";
+
+ JPEGInitializeLibJPEG( tif, 1, 0 );
+
+ assert(sp != NULL);
+ assert(!sp->cinfo.comm.is_decompressor);
+
+ /*
+ * Initialize all JPEG parameters to default values.
+ * Note that jpeg_set_defaults needs legal values for
+ * in_color_space and input_components.
+ */
+ sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+ sp->cinfo.c.input_components = 1;
+ if (!TIFFjpeg_set_defaults(sp))
+ return (0);
+ /* Set per-file parameters */
+ sp->photometric = td->td_photometric;
+ switch (sp->photometric) {
+ case PHOTOMETRIC_YCBCR:
+ sp->h_sampling = td->td_ycbcrsubsampling[0];
+ sp->v_sampling = td->td_ycbcrsubsampling[1];
+ /*
+ * A ReferenceBlackWhite field *must* be present since the
+ * default value is inappropriate for YCbCr. Fill in the
+ * proper value if application didn't set it.
+ */
+ {
+ float *ref;
+ if (!TIFFGetField(tif, TIFFTAG_REFERENCEBLACKWHITE,
+ &ref)) {
+ float refbw[6];
+ long top = 1L << td->td_bitspersample;
+ refbw[0] = 0;
+ refbw[1] = (float)(top-1L);
+ refbw[2] = (float)(top>>1);
+ refbw[3] = refbw[1];
+ refbw[4] = refbw[2];
+ refbw[5] = refbw[1];
+ TIFFSetField(tif, TIFFTAG_REFERENCEBLACKWHITE,
+ refbw);
+ }
+ }
+ break;
+ case PHOTOMETRIC_PALETTE: /* disallowed by Tech Note */
+ case PHOTOMETRIC_MASK:
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "PhotometricInterpretation %d not allowed for JPEG",
+ (int) sp->photometric);
+ return (0);
+ default:
+ /* TIFF 6.0 forbids subsampling of all other color spaces */
+ sp->h_sampling = 1;
+ sp->v_sampling = 1;
+ break;
+ }
+
+ /* Verify miscellaneous parameters */
+
+ /*
+ * This would need work if libtiff ever supports different
+ * depths for different components, or if libjpeg ever supports
+ * run-time selection of depth. Neither is imminent.
+ */
+#ifdef JPEG_LIB_MK1
+ /* BITS_IN_JSAMPLE now permits 8 and 12 --- dgilbert */
+ if (td->td_bitspersample != 8 && td->td_bitspersample != 12)
+#else
+ if (td->td_bitspersample != BITS_IN_JSAMPLE )
+#endif
+ {
+ TIFFErrorExt(tif->tif_clientdata, module, "BitsPerSample %d not allowed for JPEG",
+ (int) td->td_bitspersample);
+ return (0);
+ }
+ sp->cinfo.c.data_precision = td->td_bitspersample;
+#ifdef JPEG_LIB_MK1
+ sp->cinfo.c.bits_in_jsample = td->td_bitspersample;
+#endif
+ if (isTiled(tif)) {
+ if ((td->td_tilelength % (sp->v_sampling * DCTSIZE)) != 0) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "JPEG tile height must be multiple of %d",
+ sp->v_sampling * DCTSIZE);
+ return (0);
+ }
+ if ((td->td_tilewidth % (sp->h_sampling * DCTSIZE)) != 0) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "JPEG tile width must be multiple of %d",
+ sp->h_sampling * DCTSIZE);
+ return (0);
+ }
+ } else {
+ if (td->td_rowsperstrip < td->td_imagelength &&
+ (td->td_rowsperstrip % (sp->v_sampling * DCTSIZE)) != 0) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "RowsPerStrip must be multiple of %d for JPEG",
+ sp->v_sampling * DCTSIZE);
+ return (0);
+ }
+ }
+
+ /* Create a JPEGTables field if appropriate */
+ if (sp->jpegtablesmode & (JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF)) {
+ if( sp->jpegtables == NULL
+ || memcmp(sp->jpegtables,"\0\0\0\0\0\0\0\0\0",8) == 0 )
+ {
+ if (!prepare_JPEGTables(tif))
+ return (0);
+ /* Mark the field present */
+ /* Can't use TIFFSetField since BEENWRITING is already set! */
+ tif->tif_flags |= TIFF_DIRTYDIRECT;
+ TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
+ }
+ } else {
+ /* We do not support application-supplied JPEGTables, */
+ /* so mark the field not present */
+ TIFFClrFieldBit(tif, FIELD_JPEGTABLES);
+ }
+
+ /* Direct libjpeg output to libtiff's output buffer */
+ TIFFjpeg_data_dest(sp, tif);
+
+ return (1);
+}
+
+/*
+ * Set encoding state at the start of a strip or tile.
+ */
+static int
+JPEGPreEncode(TIFF* tif, tsample_t s)
+{
+ JPEGState *sp = JState(tif);
+ TIFFDirectory *td = &tif->tif_dir;
+ static const char module[] = "JPEGPreEncode";
+ uint32 segment_width, segment_height;
+ int downsampled_input;
+
+ assert(sp != NULL);
+ assert(!sp->cinfo.comm.is_decompressor);
+ /*
+ * Set encoding parameters for this strip/tile.
+ */
+ if (isTiled(tif)) {
+ segment_width = td->td_tilewidth;
+ segment_height = td->td_tilelength;
+ sp->bytesperline = TIFFTileRowSize(tif);
+ } else {
+ segment_width = td->td_imagewidth;
+ segment_height = td->td_imagelength - tif->tif_row;
+ if (segment_height > td->td_rowsperstrip)
+ segment_height = td->td_rowsperstrip;
+ sp->bytesperline = TIFFOldScanlineSize(tif);
+ }
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE && s > 0) {
+ /* for PC 2, scale down the strip/tile size
+ * to match a downsampled component
+ */
+ segment_width = TIFFhowmany(segment_width, sp->h_sampling);
+ segment_height = TIFFhowmany(segment_height, sp->v_sampling);
+ }
+ if (segment_width > 65535 || segment_height > 65535) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Strip/tile too large for JPEG");
+ return (0);
+ }
+ sp->cinfo.c.image_width = segment_width;
+ sp->cinfo.c.image_height = segment_height;
+ downsampled_input = FALSE;
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+ sp->cinfo.c.input_components = td->td_samplesperpixel;
+ if (sp->photometric == PHOTOMETRIC_YCBCR) {
+ if (sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+ sp->cinfo.c.in_color_space = JCS_RGB;
+ } else {
+ sp->cinfo.c.in_color_space = JCS_YCbCr;
+ if (sp->h_sampling != 1 || sp->v_sampling != 1)
+ downsampled_input = TRUE;
+ }
+ if (!TIFFjpeg_set_colorspace(sp, JCS_YCbCr))
+ return (0);
+ /*
+ * Set Y sampling factors;
+ * we assume jpeg_set_colorspace() set the rest to 1
+ */
+ sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling;
+ sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling;
+ } else {
+ sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+ if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN))
+ return (0);
+ /* jpeg_set_colorspace set all sampling factors to 1 */
+ }
+ } else {
+ sp->cinfo.c.input_components = 1;
+ sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+ if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN))
+ return (0);
+ sp->cinfo.c.comp_info[0].component_id = s;
+ /* jpeg_set_colorspace() set sampling factors to 1 */
+ if (sp->photometric == PHOTOMETRIC_YCBCR && s > 0) {
+ sp->cinfo.c.comp_info[0].quant_tbl_no = 1;
+ sp->cinfo.c.comp_info[0].dc_tbl_no = 1;
+ sp->cinfo.c.comp_info[0].ac_tbl_no = 1;
+ }
+ }
+ /* ensure libjpeg won't write any extraneous markers */
+ sp->cinfo.c.write_JFIF_header = FALSE;
+ sp->cinfo.c.write_Adobe_marker = FALSE;
+ /* set up table handling correctly */
+ if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE))
+ return (0);
+ if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) {
+ unsuppress_quant_table(sp, 0);
+ unsuppress_quant_table(sp, 1);
+ }
+ if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF)
+ sp->cinfo.c.optimize_coding = FALSE;
+ else
+ sp->cinfo.c.optimize_coding = TRUE;
+ if (downsampled_input) {
+ /* Need to use raw-data interface to libjpeg */
+ sp->cinfo.c.raw_data_in = TRUE;
+ tif->tif_encoderow = JPEGEncodeRaw;
+ tif->tif_encodestrip = JPEGEncodeRaw;
+ tif->tif_encodetile = JPEGEncodeRaw;
+ } else {
+ /* Use normal interface to libjpeg */
+ sp->cinfo.c.raw_data_in = FALSE;
+ tif->tif_encoderow = JPEGEncode;
+ tif->tif_encodestrip = JPEGEncode;
+ tif->tif_encodetile = JPEGEncode;
+ }
+ /* Start JPEG compressor */
+ if (!TIFFjpeg_start_compress(sp, FALSE))
+ return (0);
+ /* Allocate downsampled-data buffers if needed */
+ if (downsampled_input) {
+ if (!alloc_downsampled_buffers(tif, sp->cinfo.c.comp_info,
+ sp->cinfo.c.num_components))
+ return (0);
+ }
+ sp->scancount = 0;
+
+ return (1);
+}
+
+/*
+ * Encode a chunk of pixels.
+ * "Standard" case: incoming data is not downsampled.
+ */
+static int
+JPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
+{
+ JPEGState *sp = JState(tif);
+ tsize_t nrows;
+ JSAMPROW bufptr[1];
+
+ (void) s;
+ assert(sp != NULL);
+ /* data is expected to be supplied in multiples of a scanline */
+ nrows = cc / sp->bytesperline;
+ if (cc % sp->bytesperline)
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline discarded");
+
+ /* The last strip will be limited to image size */
+ if( !isTiled(tif) && tif->tif_row+nrows > tif->tif_dir.td_imagelength )
+ nrows = tif->tif_dir.td_imagelength - tif->tif_row;
+
+ while (nrows-- > 0) {
+ bufptr[0] = (JSAMPROW) buf;
+ if (TIFFjpeg_write_scanlines(sp, bufptr, 1) != 1)
+ return (0);
+ if (nrows > 0)
+ tif->tif_row++;
+ buf += sp->bytesperline;
+ }
+ return (1);
+}
+
+/*
+ * Encode a chunk of pixels.
+ * Incoming data is expected to be downsampled per sampling factors.
+ */
+static int
+JPEGEncodeRaw(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
+{
+ JPEGState *sp = JState(tif);
+ JSAMPLE* inptr;
+ JSAMPLE* outptr;
+ tsize_t nrows;
+ JDIMENSION clumps_per_line, nclump;
+ int clumpoffset, ci, xpos, ypos;
+ jpeg_component_info* compptr;
+ int samples_per_clump = sp->samplesperclump;
+ tsize_t bytesperclumpline;
+
+ (void) s;
+ assert(sp != NULL);
+ /* data is expected to be supplied in multiples of a clumpline */
+ /* a clumpline is equivalent to v_sampling desubsampled scanlines */
+ /* TODO: the following calculation of bytesperclumpline, should substitute calculation of sp->bytesperline, except that it is per v_sampling lines */
+ bytesperclumpline = (((sp->cinfo.c.image_width+sp->h_sampling-1)/sp->h_sampling)
+ *(sp->h_sampling*sp->v_sampling+2)*sp->cinfo.c.data_precision+7)
+ /8;
+
+ nrows = ( cc / bytesperclumpline ) * sp->v_sampling;
+ if (cc % bytesperclumpline)
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name, "fractional scanline discarded");
+
+ /* Cb,Cr both have sampling factors 1, so this is correct */
+ clumps_per_line = sp->cinfo.c.comp_info[1].downsampled_width;
+
+ while (nrows > 0) {
+ /*
+ * Fastest way to separate the data is to make one pass
+ * over the scanline for each row of each component.
+ */
+ clumpoffset = 0; /* first sample in clump */
+ for (ci = 0, compptr = sp->cinfo.c.comp_info;
+ ci < sp->cinfo.c.num_components;
+ ci++, compptr++) {
+ int hsamp = compptr->h_samp_factor;
+ int vsamp = compptr->v_samp_factor;
+ int padding = (int) (compptr->width_in_blocks * DCTSIZE -
+ clumps_per_line * hsamp);
+ for (ypos = 0; ypos < vsamp; ypos++) {
+ inptr = ((JSAMPLE*) buf) + clumpoffset;
+ outptr = sp->ds_buffer[ci][sp->scancount*vsamp + ypos];
+ if (hsamp == 1) {
+ /* fast path for at least Cb and Cr */
+ for (nclump = clumps_per_line; nclump-- > 0; ) {
+ *outptr++ = inptr[0];
+ inptr += samples_per_clump;
+ }
+ } else {
+ /* general case */
+ for (nclump = clumps_per_line; nclump-- > 0; ) {
+ for (xpos = 0; xpos < hsamp; xpos++)
+ *outptr++ = inptr[xpos];
+ inptr += samples_per_clump;
+ }
+ }
+ /* pad each scanline as needed */
+ for (xpos = 0; xpos < padding; xpos++) {
+ *outptr = outptr[-1];
+ outptr++;
+ }
+ clumpoffset += hsamp;
+ }
+ }
+ sp->scancount++;
+ if (sp->scancount >= DCTSIZE) {
+ int n = sp->cinfo.c.max_v_samp_factor * DCTSIZE;
+ if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n)
+ return (0);
+ sp->scancount = 0;
+ }
+ tif->tif_row += sp->v_sampling;
+ buf += sp->bytesperline;
+ nrows -= sp->v_sampling;
+ }
+ return (1);
+}
+
+/*
+ * Finish up at the end of a strip or tile.
+ */
+static int
+JPEGPostEncode(TIFF* tif)
+{
+ JPEGState *sp = JState(tif);
+
+ if (sp->scancount > 0) {
+ /*
+ * Need to emit a partial bufferload of downsampled data.
+ * Pad the data vertically.
+ */
+ int ci, ypos, n;
+ jpeg_component_info* compptr;
+
+ for (ci = 0, compptr = sp->cinfo.c.comp_info;
+ ci < sp->cinfo.c.num_components;
+ ci++, compptr++) {
+ int vsamp = compptr->v_samp_factor;
+ tsize_t row_width = compptr->width_in_blocks * DCTSIZE
+ * sizeof(JSAMPLE);
+ for (ypos = sp->scancount * vsamp;
+ ypos < DCTSIZE * vsamp; ypos++) {
+ _TIFFmemcpy((tdata_t)sp->ds_buffer[ci][ypos],
+ (tdata_t)sp->ds_buffer[ci][ypos-1],
+ row_width);
+
+ }
+ }
+ n = sp->cinfo.c.max_v_samp_factor * DCTSIZE;
+ if (TIFFjpeg_write_raw_data(sp, sp->ds_buffer, n) != n)
+ return (0);
+ }
+
+ return (TIFFjpeg_finish_compress(JState(tif)));
+}
+
+static void
+JPEGCleanup(TIFF* tif)
+{
+ JPEGState *sp = JState(tif);
+
+ assert(sp != 0);
+
+ tif->tif_tagmethods.vgetfield = sp->vgetparent;
+ tif->tif_tagmethods.vsetfield = sp->vsetparent;
+ tif->tif_tagmethods.printdir = sp->printdir;
+
+ if( sp->cinfo_initialized )
+ TIFFjpeg_destroy(sp); /* release libjpeg resources */
+ if (sp->jpegtables) /* tag value */
+ _TIFFfree(sp->jpegtables);
+ _TIFFfree(tif->tif_data); /* release local state */
+ tif->tif_data = NULL;
+
+ _TIFFSetDefaultCompressionState(tif);
+}
+
+static void
+JPEGResetUpsampled( TIFF* tif )
+{
+ JPEGState* sp = JState(tif);
+ TIFFDirectory* td = &tif->tif_dir;
+
+ /*
+ * Mark whether returned data is up-sampled or not so TIFFStripSize
+ * and TIFFTileSize return values that reflect the true amount of
+ * data.
+ */
+ tif->tif_flags &= ~TIFF_UPSAMPLED;
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+ if (td->td_photometric == PHOTOMETRIC_YCBCR &&
+ sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+ tif->tif_flags |= TIFF_UPSAMPLED;
+ } else {
+#ifdef notdef
+ if (td->td_ycbcrsubsampling[0] != 1 ||
+ td->td_ycbcrsubsampling[1] != 1)
+ ; /* XXX what about up-sampling? */
+#endif
+ }
+ }
+
+ /*
+ * Must recalculate cached tile size in case sampling state changed.
+ * Should we really be doing this now if image size isn't set?
+ */
+ if( tif->tif_tilesize > 0 )
+ tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1;
+
+ if(tif->tif_scanlinesize > 0 )
+ tif->tif_scanlinesize = TIFFScanlineSize(tif);
+}
+
+static int
+JPEGVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ JPEGState* sp = JState(tif);
+ const TIFFFieldInfo* fip;
+ uint32 v32;
+
+ assert(sp != NULL);
+
+ switch (tag) {
+ case TIFFTAG_JPEGTABLES:
+ v32 = va_arg(ap, uint32);
+ if (v32 == 0) {
+ /* XXX */
+ return (0);
+ }
+ _TIFFsetByteArray(&sp->jpegtables, va_arg(ap, void*),
+ (long) v32);
+ sp->jpegtables_length = v32;
+ TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
+ break;
+ case TIFFTAG_JPEGQUALITY:
+ sp->jpegquality = va_arg(ap, int);
+ return (1); /* pseudo tag */
+ case TIFFTAG_JPEGCOLORMODE:
+ sp->jpegcolormode = va_arg(ap, int);
+ JPEGResetUpsampled( tif );
+ return (1); /* pseudo tag */
+ case TIFFTAG_PHOTOMETRIC:
+ {
+ int ret_value = (*sp->vsetparent)(tif, tag, ap);
+ JPEGResetUpsampled( tif );
+ return ret_value;
+ }
+ case TIFFTAG_JPEGTABLESMODE:
+ sp->jpegtablesmode = va_arg(ap, int);
+ return (1); /* pseudo tag */
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ /* mark the fact that we have a real ycbcrsubsampling! */
+ sp->ycbcrsampling_fetched = 1;
+ /* should we be recomputing upsampling info here? */
+ return (*sp->vsetparent)(tif, tag, ap);
+ case TIFFTAG_FAXRECVPARAMS:
+ sp->recvparams = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_FAXSUBADDRESS:
+ _TIFFsetString(&sp->subaddress, va_arg(ap, char*));
+ break;
+ case TIFFTAG_FAXRECVTIME:
+ sp->recvtime = va_arg(ap, uint32);
+ break;
+ case TIFFTAG_FAXDCS:
+ _TIFFsetString(&sp->faxdcs, va_arg(ap, char*));
+ break;
+ default:
+ return (*sp->vsetparent)(tif, tag, ap);
+ }
+
+ if ((fip = _TIFFFieldWithTag(tif, tag))) {
+ TIFFSetFieldBit(tif, fip->field_bit);
+ } else {
+ return (0);
+ }
+
+ tif->tif_flags |= TIFF_DIRTYDIRECT;
+ return (1);
+}
+
+/*
+ * Some JPEG-in-TIFF produces do not emit the YCBCRSUBSAMPLING values in
+ * the TIFF tags, but still use non-default (2,2) values within the jpeg
+ * data stream itself. In order for TIFF applications to work properly
+ * - for instance to get the strip buffer size right - it is imperative
+ * that the subsampling be available before we start reading the image
+ * data normally. This function will attempt to load the first strip in
+ * order to get the sampling values from the jpeg data stream. Various
+ * hacks are various places are done to ensure this function gets called
+ * before the td_ycbcrsubsampling values are used from the directory structure,
+ * including calling TIFFGetField() for the YCBCRSUBSAMPLING field from
+ * TIFFStripSize(), and the printing code in tif_print.c.
+ *
+ * Note that JPEGPreDeocode() will produce a fairly loud warning when the
+ * discovered sampling does not match the default sampling (2,2) or whatever
+ * was actually in the tiff tags.
+ *
+ * Problems:
+ * o This code will cause one whole strip/tile of compressed data to be
+ * loaded just to get the tags right, even if the imagery is never read.
+ * It would be more efficient to just load a bit of the header, and
+ * initialize things from that.
+ *
+ * See the bug in bugzilla for details:
+ *
+ * http://bugzilla.remotesensing.org/show_bug.cgi?id=168
+ *
+ * Frank Warmerdam, July 2002
+ */
+
+static void
+JPEGFixupTestSubsampling( TIFF * tif )
+{
+#ifdef CHECK_JPEG_YCBCR_SUBSAMPLING
+ JPEGState *sp = JState(tif);
+ TIFFDirectory *td = &tif->tif_dir;
+
+ JPEGInitializeLibJPEG( tif, 0, 0 );
+
+ /*
+ * Some JPEG-in-TIFF files don't provide the ycbcrsampling tags,
+ * and use a sampling schema other than the default 2,2. To handle
+ * this we actually have to scan the header of a strip or tile of
+ * jpeg data to get the sampling.
+ */
+ if( !sp->cinfo.comm.is_decompressor
+ || sp->ycbcrsampling_fetched
+ || td->td_photometric != PHOTOMETRIC_YCBCR )
+ return;
+
+ sp->ycbcrsampling_fetched = 1;
+ if( TIFFIsTiled( tif ) )
+ {
+ if( !TIFFFillTile( tif, 0 ) )
+ return;
+ }
+ else
+ {
+ if( !TIFFFillStrip( tif, 0 ) )
+ return;
+ }
+
+ TIFFSetField( tif, TIFFTAG_YCBCRSUBSAMPLING,
+ (uint16) sp->h_sampling, (uint16) sp->v_sampling );
+
+ /*
+ ** We want to clear the loaded strip so the application has time
+ ** to set JPEGCOLORMODE or other behavior modifiers. This essentially
+ ** undoes the JPEGPreDecode triggers by TIFFFileStrip(). (#1936)
+ */
+ tif->tif_curstrip = -1;
+
+#endif /* CHECK_JPEG_YCBCR_SUBSAMPLING */
+}
+
+static int
+JPEGVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ JPEGState* sp = JState(tif);
+
+ assert(sp != NULL);
+
+ switch (tag) {
+ case TIFFTAG_JPEGTABLES:
+ *va_arg(ap, uint32*) = sp->jpegtables_length;
+ *va_arg(ap, void**) = sp->jpegtables;
+ break;
+ case TIFFTAG_JPEGQUALITY:
+ *va_arg(ap, int*) = sp->jpegquality;
+ break;
+ case TIFFTAG_JPEGCOLORMODE:
+ *va_arg(ap, int*) = sp->jpegcolormode;
+ break;
+ case TIFFTAG_JPEGTABLESMODE:
+ *va_arg(ap, int*) = sp->jpegtablesmode;
+ break;
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ JPEGFixupTestSubsampling( tif );
+ return (*sp->vgetparent)(tif, tag, ap);
+ case TIFFTAG_FAXRECVPARAMS:
+ *va_arg(ap, uint32*) = sp->recvparams;
+ break;
+ case TIFFTAG_FAXSUBADDRESS:
+ *va_arg(ap, char**) = sp->subaddress;
+ break;
+ case TIFFTAG_FAXRECVTIME:
+ *va_arg(ap, uint32*) = sp->recvtime;
+ break;
+ case TIFFTAG_FAXDCS:
+ *va_arg(ap, char**) = sp->faxdcs;
+ break;
+ default:
+ return (*sp->vgetparent)(tif, tag, ap);
+ }
+ return (1);
+}
+
+static void
+JPEGPrintDir(TIFF* tif, FILE* fd, long flags)
+{
+ JPEGState* sp = JState(tif);
+
+ assert(sp != NULL);
+
+ (void) flags;
+ if (TIFFFieldSet(tif,FIELD_JPEGTABLES))
+ fprintf(fd, " JPEG Tables: (%lu bytes)\n",
+ (unsigned long) sp->jpegtables_length);
+ if (TIFFFieldSet(tif,FIELD_RECVPARAMS))
+ fprintf(fd, " Fax Receive Parameters: %08lx\n",
+ (unsigned long) sp->recvparams);
+ if (TIFFFieldSet(tif,FIELD_SUBADDRESS))
+ fprintf(fd, " Fax SubAddress: %s\n", sp->subaddress);
+ if (TIFFFieldSet(tif,FIELD_RECVTIME))
+ fprintf(fd, " Fax Receive Time: %lu secs\n",
+ (unsigned long) sp->recvtime);
+ if (TIFFFieldSet(tif,FIELD_FAXDCS))
+ fprintf(fd, " Fax DCS: %s\n", sp->faxdcs);
+}
+
+static uint32
+JPEGDefaultStripSize(TIFF* tif, uint32 s)
+{
+ JPEGState* sp = JState(tif);
+ TIFFDirectory *td = &tif->tif_dir;
+
+ s = (*sp->defsparent)(tif, s);
+ if (s < td->td_imagelength)
+ s = TIFFroundup(s, td->td_ycbcrsubsampling[1] * DCTSIZE);
+ return (s);
+}
+
+static void
+JPEGDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
+{
+ JPEGState* sp = JState(tif);
+ TIFFDirectory *td = &tif->tif_dir;
+
+ (*sp->deftparent)(tif, tw, th);
+ *tw = TIFFroundup(*tw, td->td_ycbcrsubsampling[0] * DCTSIZE);
+ *th = TIFFroundup(*th, td->td_ycbcrsubsampling[1] * DCTSIZE);
+}
+
+/*
+ * The JPEG library initialized used to be done in TIFFInitJPEG(), but
+ * now that we allow a TIFF file to be opened in update mode it is necessary
+ * to have some way of deciding whether compression or decompression is
+ * desired other than looking at tif->tif_mode. We accomplish this by
+ * examining {TILE/STRIP}BYTECOUNTS to see if there is a non-zero entry.
+ * If so, we assume decompression is desired.
+ *
+ * This is tricky, because TIFFInitJPEG() is called while the directory is
+ * being read, and generally speaking the BYTECOUNTS tag won't have been read
+ * at that point. So we try to defer jpeg library initialization till we
+ * do have that tag ... basically any access that might require the compressor
+ * or decompressor that occurs after the reading of the directory.
+ *
+ * In an ideal world compressors or decompressors would be setup
+ * at the point where a single tile or strip was accessed (for read or write)
+ * so that stuff like update of missing tiles, or replacement of tiles could
+ * be done. However, we aren't trying to crack that nut just yet ...
+ *
+ * NFW, Feb 3rd, 2003.
+ */
+
+static int JPEGInitializeLibJPEG( TIFF * tif, int force_encode, int force_decode )
+{
+ JPEGState* sp = JState(tif);
+ uint32 *byte_counts = NULL;
+ int data_is_empty = TRUE;
+ int decompress;
+
+
+ if(sp->cinfo_initialized)
+ {
+ if( force_encode && sp->cinfo.comm.is_decompressor )
+ TIFFjpeg_destroy( sp );
+ else if( force_decode && !sp->cinfo.comm.is_decompressor )
+ TIFFjpeg_destroy( sp );
+ else
+ return 1;
+
+ sp->cinfo_initialized = 0;
+ }
+
+ /*
+ * Do we have tile data already? Make sure we initialize the
+ * the state in decompressor mode if we have tile data, even if we
+ * are not in read-only file access mode.
+ */
+ if( TIFFIsTiled( tif )
+ && TIFFGetField( tif, TIFFTAG_TILEBYTECOUNTS, &byte_counts )
+ && byte_counts != NULL )
+ {
+ data_is_empty = byte_counts[0] == 0;
+ }
+ if( !TIFFIsTiled( tif )
+ && TIFFGetField( tif, TIFFTAG_STRIPBYTECOUNTS, &byte_counts)
+ && byte_counts != NULL )
+ {
+ data_is_empty = byte_counts[0] == 0;
+ }
+
+ if( force_decode )
+ decompress = 1;
+ else if( force_encode )
+ decompress = 0;
+ else if( tif->tif_mode == O_RDONLY )
+ decompress = 1;
+ else if( data_is_empty )
+ decompress = 0;
+ else
+ decompress = 1;
+
+ /*
+ * Initialize libjpeg.
+ */
+ if ( decompress ) {
+ if (!TIFFjpeg_create_decompress(sp))
+ return (0);
+
+ } else {
+ if (!TIFFjpeg_create_compress(sp))
+ return (0);
+ }
+
+ sp->cinfo_initialized = TRUE;
+
+ return 1;
+}
+
+int
+TIFFInitJPEG(TIFF* tif, int scheme)
+{
+ JPEGState* sp;
+
+ assert(scheme == COMPRESSION_JPEG);
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, jpegFieldInfo, N(jpegFieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata,
+ "TIFFInitJPEG",
+ "Merging JPEG codec-specific tags failed");
+ return 0;
+ }
+
+ /*
+ * Allocate state block so tag methods have storage to record values.
+ */
+ tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (JPEGState));
+
+ if (tif->tif_data == NULL) {
+ TIFFErrorExt(tif->tif_clientdata,
+ "TIFFInitJPEG", "No space for JPEG state block");
+ return 0;
+ }
+ _TIFFmemset(tif->tif_data, 0, sizeof(JPEGState));
+
+ sp = JState(tif);
+ sp->tif = tif; /* back link */
+
+ /*
+ * Override parent get/set field methods.
+ */
+ sp->vgetparent = tif->tif_tagmethods.vgetfield;
+ tif->tif_tagmethods.vgetfield = JPEGVGetField; /* hook for codec tags */
+ sp->vsetparent = tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vsetfield = JPEGVSetField; /* hook for codec tags */
+ sp->printdir = tif->tif_tagmethods.printdir;
+ tif->tif_tagmethods.printdir = JPEGPrintDir; /* hook for codec tags */
+
+ /* Default values for codec-specific fields */
+ sp->jpegtables = NULL;
+ sp->jpegtables_length = 0;
+ sp->jpegquality = 75; /* Default IJG quality */
+ sp->jpegcolormode = JPEGCOLORMODE_RAW;
+ sp->jpegtablesmode = JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF;
+
+ sp->recvparams = 0;
+ sp->subaddress = NULL;
+ sp->faxdcs = NULL;
+
+ sp->ycbcrsampling_fetched = 0;
+
+ /*
+ * Install codec methods.
+ */
+ tif->tif_setupdecode = JPEGSetupDecode;
+ tif->tif_predecode = JPEGPreDecode;
+ tif->tif_decoderow = JPEGDecode;
+ tif->tif_decodestrip = JPEGDecode;
+ tif->tif_decodetile = JPEGDecode;
+ tif->tif_setupencode = JPEGSetupEncode;
+ tif->tif_preencode = JPEGPreEncode;
+ tif->tif_postencode = JPEGPostEncode;
+ tif->tif_encoderow = JPEGEncode;
+ tif->tif_encodestrip = JPEGEncode;
+ tif->tif_encodetile = JPEGEncode;
+ tif->tif_cleanup = JPEGCleanup;
+ sp->defsparent = tif->tif_defstripsize;
+ tif->tif_defstripsize = JPEGDefaultStripSize;
+ sp->deftparent = tif->tif_deftilesize;
+ tif->tif_deftilesize = JPEGDefaultTileSize;
+ tif->tif_flags |= TIFF_NOBITREV; /* no bit reversal, please */
+
+ sp->cinfo_initialized = FALSE;
+
+ /*
+ ** Create a JPEGTables field if no directory has yet been created.
+ ** We do this just to ensure that sufficient space is reserved for
+ ** the JPEGTables field. It will be properly created the right
+ ** size later.
+ */
+ if( tif->tif_diroff == 0 )
+ {
+#define SIZE_OF_JPEGTABLES 2000
+/*
+The following line assumes incorrectly that all JPEG-in-TIFF files will have
+a JPEGTABLES tag generated and causes null-filled JPEGTABLES tags to be written
+when the JPEG data is placed with TIFFWriteRawStrip. The field bit should be
+set, anyway, later when actual JPEGTABLES header is generated, so removing it
+here hopefully is harmless.
+ TIFFSetFieldBit(tif, FIELD_JPEGTABLES);
+*/
+ sp->jpegtables_length = SIZE_OF_JPEGTABLES;
+ sp->jpegtables = (void *) _TIFFmalloc(sp->jpegtables_length);
+ _TIFFmemset(sp->jpegtables, 0, SIZE_OF_JPEGTABLES);
+#undef SIZE_OF_JPEGTABLES
+ }
+
+ /*
+ * Mark the TIFFTAG_YCBCRSAMPLES as present even if it is not
+ * see: JPEGFixupTestSubsampling().
+ */
+ TIFFSetFieldBit( tif, FIELD_YCBCRSUBSAMPLING );
+
+ return 1;
+}
+#endif /* JPEG_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_luv.c b/tiff/libtiff/tif_luv.c
new file mode 100644
index 0000000..eb622b9
--- /dev/null
+++ b/tiff/libtiff/tif_luv.c
@@ -0,0 +1,1629 @@
+/* $Id: tif_luv.c,v 1.17.2.4 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1997 Greg Ward Larson
+ * Copyright (c) 1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler, Greg Larson and Silicon Graphics may not be used in any
+ * advertising or publicity relating to the software without the specific,
+ * prior written permission of Sam Leffler, Greg Larson and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER, GREG LARSON OR SILICON GRAPHICS BE LIABLE
+ * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef LOGLUV_SUPPORT
+
+/*
+ * TIFF Library.
+ * LogLuv compression support for high dynamic range images.
+ *
+ * Contributed by Greg Larson.
+ *
+ * LogLuv image support uses the TIFF library to store 16 or 10-bit
+ * log luminance values with 8 bits each of u and v or a 14-bit index.
+ *
+ * The codec can take as input and produce as output 32-bit IEEE float values
+ * as well as 16-bit integer values. A 16-bit luminance is interpreted
+ * as a sign bit followed by a 15-bit integer that is converted
+ * to and from a linear magnitude using the transformation:
+ *
+ * L = 2^( (Le+.5)/256 - 64 ) # real from 15-bit
+ *
+ * Le = floor( 256*(log2(L) + 64) ) # 15-bit from real
+ *
+ * The actual conversion to world luminance units in candelas per sq. meter
+ * requires an additional multiplier, which is stored in the TIFFTAG_STONITS.
+ * This value is usually set such that a reasonable exposure comes from
+ * clamping decoded luminances above 1 to 1 in the displayed image.
+ *
+ * The 16-bit values for u and v may be converted to real values by dividing
+ * each by 32768. (This allows for negative values, which aren't useful as
+ * far as we know, but are left in case of future improvements in human
+ * color vision.)
+ *
+ * Conversion from (u,v), which is actually the CIE (u',v') system for
+ * you color scientists, is accomplished by the following transformation:
+ *
+ * u = 4*x / (-2*x + 12*y + 3)
+ * v = 9*y / (-2*x + 12*y + 3)
+ *
+ * x = 9*u / (6*u - 16*v + 12)
+ * y = 4*v / (6*u - 16*v + 12)
+ *
+ * This process is greatly simplified by passing 32-bit IEEE floats
+ * for each of three CIE XYZ coordinates. The codec then takes care
+ * of conversion to and from LogLuv, though the application is still
+ * responsible for interpreting the TIFFTAG_STONITS calibration factor.
+ *
+ * By definition, a CIE XYZ vector of [1 1 1] corresponds to a neutral white
+ * point of (x,y)=(1/3,1/3). However, most color systems assume some other
+ * white point, such as D65, and an absolute color conversion to XYZ then
+ * to another color space with a different white point may introduce an
+ * unwanted color cast to the image. It is often desirable, therefore, to
+ * perform a white point conversion that maps the input white to [1 1 1]
+ * in XYZ, then record the original white point using the TIFFTAG_WHITEPOINT
+ * tag value. A decoder that demands absolute color calibration may use
+ * this white point tag to get back the original colors, but usually it
+ * will be ignored and the new white point will be used instead that
+ * matches the output color space.
+ *
+ * Pixel information is compressed into one of two basic encodings, depending
+ * on the setting of the compression tag, which is one of COMPRESSION_SGILOG
+ * or COMPRESSION_SGILOG24. For COMPRESSION_SGILOG, greyscale data is
+ * stored as:
+ *
+ * 1 15
+ * |-+---------------|
+ *
+ * COMPRESSION_SGILOG color data is stored as:
+ *
+ * 1 15 8 8
+ * |-+---------------|--------+--------|
+ * S Le ue ve
+ *
+ * For the 24-bit COMPRESSION_SGILOG24 color format, the data is stored as:
+ *
+ * 10 14
+ * |----------|--------------|
+ * Le' Ce
+ *
+ * There is no sign bit in the 24-bit case, and the (u,v) chromaticity is
+ * encoded as an index for optimal color resolution. The 10 log bits are
+ * defined by the following conversions:
+ *
+ * L = 2^((Le'+.5)/64 - 12) # real from 10-bit
+ *
+ * Le' = floor( 64*(log2(L) + 12) ) # 10-bit from real
+ *
+ * The 10 bits of the smaller format may be converted into the 15 bits of
+ * the larger format by multiplying by 4 and adding 13314. Obviously,
+ * a smaller range of magnitudes is covered (about 5 orders of magnitude
+ * instead of 38), and the lack of a sign bit means that negative luminances
+ * are not allowed. (Well, they aren't allowed in the real world, either,
+ * but they are useful for certain types of image processing.)
+ *
+ * The desired user format is controlled by the setting the internal
+ * pseudo tag TIFFTAG_SGILOGDATAFMT to one of:
+ * SGILOGDATAFMT_FLOAT = IEEE 32-bit float XYZ values
+ * SGILOGDATAFMT_16BIT = 16-bit integer encodings of logL, u and v
+ * Raw data i/o is also possible using:
+ * SGILOGDATAFMT_RAW = 32-bit unsigned integer with encoded pixel
+ * In addition, the following decoding is provided for ease of display:
+ * SGILOGDATAFMT_8BIT = 8-bit default RGB gamma-corrected values
+ *
+ * For grayscale images, we provide the following data formats:
+ * SGILOGDATAFMT_FLOAT = IEEE 32-bit float Y values
+ * SGILOGDATAFMT_16BIT = 16-bit integer w/ encoded luminance
+ * SGILOGDATAFMT_8BIT = 8-bit gray monitor values
+ *
+ * Note that the COMPRESSION_SGILOG applies a simple run-length encoding
+ * scheme by separating the logL, u and v bytes for each row and applying
+ * a PackBits type of compression. Since the 24-bit encoding is not
+ * adaptive, the 32-bit color format takes less space in many cases.
+ *
+ * Further control is provided over the conversion from higher-resolution
+ * formats to final encoded values through the pseudo tag
+ * TIFFTAG_SGILOGENCODE:
+ * SGILOGENCODE_NODITHER = do not dither encoded values
+ * SGILOGENCODE_RANDITHER = apply random dithering during encoding
+ *
+ * The default value of this tag is SGILOGENCODE_NODITHER for
+ * COMPRESSION_SGILOG to maximize run-length encoding and
+ * SGILOGENCODE_RANDITHER for COMPRESSION_SGILOG24 to turn
+ * quantization errors into noise.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+/*
+ * State block for each open TIFF
+ * file using LogLuv compression/decompression.
+ */
+typedef struct logLuvState LogLuvState;
+
+struct logLuvState {
+ int user_datafmt; /* user data format */
+ int encode_meth; /* encoding method */
+ int pixel_size; /* bytes per pixel */
+
+ tidata_t* tbuf; /* translation buffer */
+ int tbuflen; /* buffer length */
+ void (*tfunc)(LogLuvState*, tidata_t, int);
+
+ TIFFVSetMethod vgetparent; /* super-class method */
+ TIFFVSetMethod vsetparent; /* super-class method */
+};
+
+#define DecoderState(tif) ((LogLuvState*) (tif)->tif_data)
+#define EncoderState(tif) ((LogLuvState*) (tif)->tif_data)
+
+#define SGILOGDATAFMT_UNKNOWN -1
+
+#define MINRUN 4 /* minimum run length */
+
+/*
+ * Decode a string of 16-bit gray pixels.
+ */
+static int
+LogL16Decode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
+{
+ LogLuvState* sp = DecoderState(tif);
+ int shft, i, npixels;
+ unsigned char* bp;
+ int16* tp;
+ int16 b;
+ int cc, rc;
+
+ assert(s == 0);
+ assert(sp != NULL);
+
+ npixels = occ / sp->pixel_size;
+
+ if (sp->user_datafmt == SGILOGDATAFMT_16BIT)
+ tp = (int16*) op;
+ else {
+ assert(sp->tbuflen >= npixels);
+ tp = (int16*) sp->tbuf;
+ }
+ _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0]));
+
+ bp = (unsigned char*) tif->tif_rawcp;
+ cc = tif->tif_rawcc;
+ /* get each byte string */
+ for (shft = 2*8; (shft -= 8) >= 0; ) {
+ for (i = 0; i < npixels && cc > 0; )
+ if (*bp >= 128) { /* run */
+ rc = *bp++ + (2-128);
+ b = (int16)(*bp++ << shft);
+ cc -= 2;
+ while (rc-- && i < npixels)
+ tp[i++] |= b;
+ } else { /* non-run */
+ rc = *bp++; /* nul is noop */
+ while (--cc && rc-- && i < npixels)
+ tp[i++] |= (int16)*bp++ << shft;
+ }
+ if (i != npixels) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LogL16Decode: Not enough data at row %d (short %d pixels)",
+ tif->tif_row, npixels - i);
+ tif->tif_rawcp = (tidata_t) bp;
+ tif->tif_rawcc = cc;
+ return (0);
+ }
+ }
+ (*sp->tfunc)(sp, op, npixels);
+ tif->tif_rawcp = (tidata_t) bp;
+ tif->tif_rawcc = cc;
+ return (1);
+}
+
+/*
+ * Decode a string of 24-bit pixels.
+ */
+static int
+LogLuvDecode24(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
+{
+ LogLuvState* sp = DecoderState(tif);
+ int cc, i, npixels;
+ unsigned char* bp;
+ uint32* tp;
+
+ assert(s == 0);
+ assert(sp != NULL);
+
+ npixels = occ / sp->pixel_size;
+
+ if (sp->user_datafmt == SGILOGDATAFMT_RAW)
+ tp = (uint32 *)op;
+ else {
+ assert(sp->tbuflen >= npixels);
+ tp = (uint32 *) sp->tbuf;
+ }
+ /* copy to array of uint32 */
+ bp = (unsigned char*) tif->tif_rawcp;
+ cc = tif->tif_rawcc;
+ for (i = 0; i < npixels && cc > 0; i++) {
+ tp[i] = bp[0] << 16 | bp[1] << 8 | bp[2];
+ bp += 3;
+ cc -= 3;
+ }
+ tif->tif_rawcp = (tidata_t) bp;
+ tif->tif_rawcc = cc;
+ if (i != npixels) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LogLuvDecode24: Not enough data at row %d (short %d pixels)",
+ tif->tif_row, npixels - i);
+ return (0);
+ }
+ (*sp->tfunc)(sp, op, npixels);
+ return (1);
+}
+
+/*
+ * Decode a string of 32-bit pixels.
+ */
+static int
+LogLuvDecode32(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
+{
+ LogLuvState* sp;
+ int shft, i, npixels;
+ unsigned char* bp;
+ uint32* tp;
+ uint32 b;
+ int cc, rc;
+
+ assert(s == 0);
+ sp = DecoderState(tif);
+ assert(sp != NULL);
+
+ npixels = occ / sp->pixel_size;
+
+ if (sp->user_datafmt == SGILOGDATAFMT_RAW)
+ tp = (uint32*) op;
+ else {
+ assert(sp->tbuflen >= npixels);
+ tp = (uint32*) sp->tbuf;
+ }
+ _TIFFmemset((tdata_t) tp, 0, npixels*sizeof (tp[0]));
+
+ bp = (unsigned char*) tif->tif_rawcp;
+ cc = tif->tif_rawcc;
+ /* get each byte string */
+ for (shft = 4*8; (shft -= 8) >= 0; ) {
+ for (i = 0; i < npixels && cc > 0; )
+ if (*bp >= 128) { /* run */
+ rc = *bp++ + (2-128);
+ b = (uint32)*bp++ << shft;
+ cc -= 2;
+ while (rc-- && i < npixels)
+ tp[i++] |= b;
+ } else { /* non-run */
+ rc = *bp++; /* nul is noop */
+ while (--cc && rc-- && i < npixels)
+ tp[i++] |= (uint32)*bp++ << shft;
+ }
+ if (i != npixels) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LogLuvDecode32: Not enough data at row %d (short %d pixels)",
+ tif->tif_row, npixels - i);
+ tif->tif_rawcp = (tidata_t) bp;
+ tif->tif_rawcc = cc;
+ return (0);
+ }
+ }
+ (*sp->tfunc)(sp, op, npixels);
+ tif->tif_rawcp = (tidata_t) bp;
+ tif->tif_rawcc = cc;
+ return (1);
+}
+
+/*
+ * Decode a strip of pixels. We break it into rows to
+ * maintain synchrony with the encode algorithm, which
+ * is row by row.
+ */
+static int
+LogLuvDecodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ tsize_t rowlen = TIFFScanlineSize(tif);
+
+ assert(cc%rowlen == 0);
+ while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s))
+ bp += rowlen, cc -= rowlen;
+ return (cc == 0);
+}
+
+/*
+ * Decode a tile of pixels. We break it into rows to
+ * maintain synchrony with the encode algorithm, which
+ * is row by row.
+ */
+static int
+LogLuvDecodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ tsize_t rowlen = TIFFTileRowSize(tif);
+
+ assert(cc%rowlen == 0);
+ while (cc && (*tif->tif_decoderow)(tif, bp, rowlen, s))
+ bp += rowlen, cc -= rowlen;
+ return (cc == 0);
+}
+
+/*
+ * Encode a row of 16-bit pixels.
+ */
+static int
+LogL16Encode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ LogLuvState* sp = EncoderState(tif);
+ int shft, i, j, npixels;
+ tidata_t op;
+ int16* tp;
+ int16 b;
+ int occ, rc=0, mask, beg;
+
+ assert(s == 0);
+ assert(sp != NULL);
+ npixels = cc / sp->pixel_size;
+
+ if (sp->user_datafmt == SGILOGDATAFMT_16BIT)
+ tp = (int16*) bp;
+ else {
+ tp = (int16*) sp->tbuf;
+ assert(sp->tbuflen >= npixels);
+ (*sp->tfunc)(sp, bp, npixels);
+ }
+ /* compress each byte string */
+ op = tif->tif_rawcp;
+ occ = tif->tif_rawdatasize - tif->tif_rawcc;
+ for (shft = 2*8; (shft -= 8) >= 0; )
+ for (i = 0; i < npixels; i += rc) {
+ if (occ < 4) {
+ tif->tif_rawcp = op;
+ tif->tif_rawcc = tif->tif_rawdatasize - occ;
+ if (!TIFFFlushData1(tif))
+ return (-1);
+ op = tif->tif_rawcp;
+ occ = tif->tif_rawdatasize - tif->tif_rawcc;
+ }
+ mask = 0xff << shft; /* find next run */
+ for (beg = i; beg < npixels; beg += rc) {
+ b = (int16) (tp[beg] & mask);
+ rc = 1;
+ while (rc < 127+2 && beg+rc < npixels &&
+ (tp[beg+rc] & mask) == b)
+ rc++;
+ if (rc >= MINRUN)
+ break; /* long enough */
+ }
+ if (beg-i > 1 && beg-i < MINRUN) {
+ b = (int16) (tp[i] & mask);/*check short run */
+ j = i+1;
+ while ((tp[j++] & mask) == b)
+ if (j == beg) {
+ *op++ = (tidataval_t)(128-2+j-i);
+ *op++ = (tidataval_t) (b >> shft);
+ occ -= 2;
+ i = beg;
+ break;
+ }
+ }
+ while (i < beg) { /* write out non-run */
+ if ((j = beg-i) > 127) j = 127;
+ if (occ < j+3) {
+ tif->tif_rawcp = op;
+ tif->tif_rawcc = tif->tif_rawdatasize - occ;
+ if (!TIFFFlushData1(tif))
+ return (-1);
+ op = tif->tif_rawcp;
+ occ = tif->tif_rawdatasize - tif->tif_rawcc;
+ }
+ *op++ = (tidataval_t) j; occ--;
+ while (j--) {
+ *op++ = (tidataval_t) (tp[i++] >> shft & 0xff);
+ occ--;
+ }
+ }
+ if (rc >= MINRUN) { /* write out run */
+ *op++ = (tidataval_t) (128-2+rc);
+ *op++ = (tidataval_t) (tp[beg] >> shft & 0xff);
+ occ -= 2;
+ } else
+ rc = 0;
+ }
+ tif->tif_rawcp = op;
+ tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+ return (1);
+}
+
+/*
+ * Encode a row of 24-bit pixels.
+ */
+static int
+LogLuvEncode24(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ LogLuvState* sp = EncoderState(tif);
+ int i, npixels, occ;
+ tidata_t op;
+ uint32* tp;
+
+ assert(s == 0);
+ assert(sp != NULL);
+ npixels = cc / sp->pixel_size;
+
+ if (sp->user_datafmt == SGILOGDATAFMT_RAW)
+ tp = (uint32*) bp;
+ else {
+ tp = (uint32*) sp->tbuf;
+ assert(sp->tbuflen >= npixels);
+ (*sp->tfunc)(sp, bp, npixels);
+ }
+ /* write out encoded pixels */
+ op = tif->tif_rawcp;
+ occ = tif->tif_rawdatasize - tif->tif_rawcc;
+ for (i = npixels; i--; ) {
+ if (occ < 3) {
+ tif->tif_rawcp = op;
+ tif->tif_rawcc = tif->tif_rawdatasize - occ;
+ if (!TIFFFlushData1(tif))
+ return (-1);
+ op = tif->tif_rawcp;
+ occ = tif->tif_rawdatasize - tif->tif_rawcc;
+ }
+ *op++ = (tidataval_t)(*tp >> 16);
+ *op++ = (tidataval_t)(*tp >> 8 & 0xff);
+ *op++ = (tidataval_t)(*tp++ & 0xff);
+ occ -= 3;
+ }
+ tif->tif_rawcp = op;
+ tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+ return (1);
+}
+
+/*
+ * Encode a row of 32-bit pixels.
+ */
+static int
+LogLuvEncode32(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ LogLuvState* sp = EncoderState(tif);
+ int shft, i, j, npixels;
+ tidata_t op;
+ uint32* tp;
+ uint32 b;
+ int occ, rc=0, mask, beg;
+
+ assert(s == 0);
+ assert(sp != NULL);
+
+ npixels = cc / sp->pixel_size;
+
+ if (sp->user_datafmt == SGILOGDATAFMT_RAW)
+ tp = (uint32*) bp;
+ else {
+ tp = (uint32*) sp->tbuf;
+ assert(sp->tbuflen >= npixels);
+ (*sp->tfunc)(sp, bp, npixels);
+ }
+ /* compress each byte string */
+ op = tif->tif_rawcp;
+ occ = tif->tif_rawdatasize - tif->tif_rawcc;
+ for (shft = 4*8; (shft -= 8) >= 0; )
+ for (i = 0; i < npixels; i += rc) {
+ if (occ < 4) {
+ tif->tif_rawcp = op;
+ tif->tif_rawcc = tif->tif_rawdatasize - occ;
+ if (!TIFFFlushData1(tif))
+ return (-1);
+ op = tif->tif_rawcp;
+ occ = tif->tif_rawdatasize - tif->tif_rawcc;
+ }
+ mask = 0xff << shft; /* find next run */
+ for (beg = i; beg < npixels; beg += rc) {
+ b = tp[beg] & mask;
+ rc = 1;
+ while (rc < 127+2 && beg+rc < npixels &&
+ (tp[beg+rc] & mask) == b)
+ rc++;
+ if (rc >= MINRUN)
+ break; /* long enough */
+ }
+ if (beg-i > 1 && beg-i < MINRUN) {
+ b = tp[i] & mask; /* check short run */
+ j = i+1;
+ while ((tp[j++] & mask) == b)
+ if (j == beg) {
+ *op++ = (tidataval_t)(128-2+j-i);
+ *op++ = (tidataval_t)(b >> shft);
+ occ -= 2;
+ i = beg;
+ break;
+ }
+ }
+ while (i < beg) { /* write out non-run */
+ if ((j = beg-i) > 127) j = 127;
+ if (occ < j+3) {
+ tif->tif_rawcp = op;
+ tif->tif_rawcc = tif->tif_rawdatasize - occ;
+ if (!TIFFFlushData1(tif))
+ return (-1);
+ op = tif->tif_rawcp;
+ occ = tif->tif_rawdatasize - tif->tif_rawcc;
+ }
+ *op++ = (tidataval_t) j; occ--;
+ while (j--) {
+ *op++ = (tidataval_t)(tp[i++] >> shft & 0xff);
+ occ--;
+ }
+ }
+ if (rc >= MINRUN) { /* write out run */
+ *op++ = (tidataval_t) (128-2+rc);
+ *op++ = (tidataval_t)(tp[beg] >> shft & 0xff);
+ occ -= 2;
+ } else
+ rc = 0;
+ }
+ tif->tif_rawcp = op;
+ tif->tif_rawcc = tif->tif_rawdatasize - occ;
+
+ return (1);
+}
+
+/*
+ * Encode a strip of pixels. We break it into rows to
+ * avoid encoding runs across row boundaries.
+ */
+static int
+LogLuvEncodeStrip(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ tsize_t rowlen = TIFFScanlineSize(tif);
+
+ assert(cc%rowlen == 0);
+ while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1)
+ bp += rowlen, cc -= rowlen;
+ return (cc == 0);
+}
+
+/*
+ * Encode a tile of pixels. We break it into rows to
+ * avoid encoding runs across row boundaries.
+ */
+static int
+LogLuvEncodeTile(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ tsize_t rowlen = TIFFTileRowSize(tif);
+
+ assert(cc%rowlen == 0);
+ while (cc && (*tif->tif_encoderow)(tif, bp, rowlen, s) == 1)
+ bp += rowlen, cc -= rowlen;
+ return (cc == 0);
+}
+
+/*
+ * Encode/Decode functions for converting to and from user formats.
+ */
+
+#include "uvcode.h"
+
+#ifndef UVSCALE
+#define U_NEU 0.210526316
+#define V_NEU 0.473684211
+#define UVSCALE 410.
+#endif
+
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#define log2(x) ((1./M_LN2)*log(x))
+#define exp2(x) exp(M_LN2*(x))
+
+#define itrunc(x,m) ((m)==SGILOGENCODE_NODITHER ? \
+ (int)(x) : \
+ (int)((x) + rand()*(1./RAND_MAX) - .5))
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+double
+LogL16toY(int p16) /* compute luminance from 16-bit LogL */
+{
+ int Le = p16 & 0x7fff;
+ double Y;
+
+ if (!Le)
+ return (0.);
+ Y = exp(M_LN2/256.*(Le+.5) - M_LN2*64.);
+ return (!(p16 & 0x8000) ? Y : -Y);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+LogL16fromY(double Y, int em) /* get 16-bit LogL from Y */
+{
+ if (Y >= 1.8371976e19)
+ return (0x7fff);
+ if (Y <= -1.8371976e19)
+ return (0xffff);
+ if (Y > 5.4136769e-20)
+ return itrunc(256.*(log2(Y) + 64.), em);
+ if (Y < -5.4136769e-20)
+ return (~0x7fff | itrunc(256.*(log2(-Y) + 64.), em));
+ return (0);
+}
+
+static void
+L16toY(LogLuvState* sp, tidata_t op, int n)
+{
+ int16* l16 = (int16*) sp->tbuf;
+ float* yp = (float*) op;
+
+ while (n-- > 0)
+ *yp++ = (float)LogL16toY(*l16++);
+}
+
+static void
+L16toGry(LogLuvState* sp, tidata_t op, int n)
+{
+ int16* l16 = (int16*) sp->tbuf;
+ uint8* gp = (uint8*) op;
+
+ while (n-- > 0) {
+ double Y = LogL16toY(*l16++);
+ *gp++ = (uint8) ((Y <= 0.) ? 0 : (Y >= 1.) ? 255 : (int)(256.*sqrt(Y)));
+ }
+}
+
+static void
+L16fromY(LogLuvState* sp, tidata_t op, int n)
+{
+ int16* l16 = (int16*) sp->tbuf;
+ float* yp = (float*) op;
+
+ while (n-- > 0)
+ *l16++ = (int16) (LogL16fromY(*yp++, sp->encode_meth));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+XYZtoRGB24(float xyz[3], uint8 rgb[3])
+{
+ double r, g, b;
+ /* assume CCIR-709 primaries */
+ r = 2.690*xyz[0] + -1.276*xyz[1] + -0.414*xyz[2];
+ g = -1.022*xyz[0] + 1.978*xyz[1] + 0.044*xyz[2];
+ b = 0.061*xyz[0] + -0.224*xyz[1] + 1.163*xyz[2];
+ /* assume 2.0 gamma for speed */
+ /* could use integer sqrt approx., but this is probably faster */
+ rgb[0] = (uint8)((r<=0.) ? 0 : (r >= 1.) ? 255 : (int)(256.*sqrt(r)));
+ rgb[1] = (uint8)((g<=0.) ? 0 : (g >= 1.) ? 255 : (int)(256.*sqrt(g)));
+ rgb[2] = (uint8)((b<=0.) ? 0 : (b >= 1.) ? 255 : (int)(256.*sqrt(b)));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+double
+LogL10toY(int p10) /* compute luminance from 10-bit LogL */
+{
+ if (p10 == 0)
+ return (0.);
+ return (exp(M_LN2/64.*(p10+.5) - M_LN2*12.));
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+LogL10fromY(double Y, int em) /* get 10-bit LogL from Y */
+{
+ if (Y >= 15.742)
+ return (0x3ff);
+ else if (Y <= .00024283)
+ return (0);
+ else
+ return itrunc(64.*(log2(Y) + 12.), em);
+}
+
+#define NANGLES 100
+#define uv2ang(u, v) ( (NANGLES*.499999999/M_PI) \
+ * atan2((v)-V_NEU,(u)-U_NEU) + .5*NANGLES )
+
+static int
+oog_encode(double u, double v) /* encode out-of-gamut chroma */
+{
+ static int oog_table[NANGLES];
+ static int initialized = 0;
+ register int i;
+
+ if (!initialized) { /* set up perimeter table */
+ double eps[NANGLES], ua, va, ang, epsa;
+ int ui, vi, ustep;
+ for (i = NANGLES; i--; )
+ eps[i] = 2.;
+ for (vi = UV_NVS; vi--; ) {
+ va = UV_VSTART + (vi+.5)*UV_SQSIZ;
+ ustep = uv_row[vi].nus-1;
+ if (vi == UV_NVS-1 || vi == 0 || ustep <= 0)
+ ustep = 1;
+ for (ui = uv_row[vi].nus-1; ui >= 0; ui -= ustep) {
+ ua = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
+ ang = uv2ang(ua, va);
+ i = (int) ang;
+ epsa = fabs(ang - (i+.5));
+ if (epsa < eps[i]) {
+ oog_table[i] = uv_row[vi].ncum + ui;
+ eps[i] = epsa;
+ }
+ }
+ }
+ for (i = NANGLES; i--; ) /* fill any holes */
+ if (eps[i] > 1.5) {
+ int i1, i2;
+ for (i1 = 1; i1 < NANGLES/2; i1++)
+ if (eps[(i+i1)%NANGLES] < 1.5)
+ break;
+ for (i2 = 1; i2 < NANGLES/2; i2++)
+ if (eps[(i+NANGLES-i2)%NANGLES] < 1.5)
+ break;
+ if (i1 < i2)
+ oog_table[i] =
+ oog_table[(i+i1)%NANGLES];
+ else
+ oog_table[i] =
+ oog_table[(i+NANGLES-i2)%NANGLES];
+ }
+ initialized = 1;
+ }
+ i = (int) uv2ang(u, v); /* look up hue angle */
+ return (oog_table[i]);
+}
+
+#undef uv2ang
+#undef NANGLES
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+uv_encode(double u, double v, int em) /* encode (u',v') coordinates */
+{
+ register int vi, ui;
+
+ if (v < UV_VSTART)
+ return oog_encode(u, v);
+ vi = itrunc((v - UV_VSTART)*(1./UV_SQSIZ), em);
+ if (vi >= UV_NVS)
+ return oog_encode(u, v);
+ if (u < uv_row[vi].ustart)
+ return oog_encode(u, v);
+ ui = itrunc((u - uv_row[vi].ustart)*(1./UV_SQSIZ), em);
+ if (ui >= uv_row[vi].nus)
+ return oog_encode(u, v);
+
+ return (uv_row[vi].ncum + ui);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+int
+uv_decode(double *up, double *vp, int c) /* decode (u',v') index */
+{
+ int upper, lower;
+ register int ui, vi;
+
+ if (c < 0 || c >= UV_NDIVS)
+ return (-1);
+ lower = 0; /* binary search */
+ upper = UV_NVS;
+ while (upper - lower > 1) {
+ vi = (lower + upper) >> 1;
+ ui = c - uv_row[vi].ncum;
+ if (ui > 0)
+ lower = vi;
+ else if (ui < 0)
+ upper = vi;
+ else {
+ lower = vi;
+ break;
+ }
+ }
+ vi = lower;
+ ui = c - uv_row[vi].ncum;
+ *up = uv_row[vi].ustart + (ui+.5)*UV_SQSIZ;
+ *vp = UV_VSTART + (vi+.5)*UV_SQSIZ;
+ return (0);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+LogLuv24toXYZ(uint32 p, float XYZ[3])
+{
+ int Ce;
+ double L, u, v, s, x, y;
+ /* decode luminance */
+ L = LogL10toY(p>>14 & 0x3ff);
+ if (L <= 0.) {
+ XYZ[0] = XYZ[1] = XYZ[2] = 0.;
+ return;
+ }
+ /* decode color */
+ Ce = p & 0x3fff;
+ if (uv_decode(&u, &v, Ce) < 0) {
+ u = U_NEU; v = V_NEU;
+ }
+ s = 1./(6.*u - 16.*v + 12.);
+ x = 9.*u * s;
+ y = 4.*v * s;
+ /* convert to XYZ */
+ XYZ[0] = (float)(x/y * L);
+ XYZ[1] = (float)L;
+ XYZ[2] = (float)((1.-x-y)/y * L);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+uint32
+LogLuv24fromXYZ(float XYZ[3], int em)
+{
+ int Le, Ce;
+ double u, v, s;
+ /* encode luminance */
+ Le = LogL10fromY(XYZ[1], em);
+ /* encode color */
+ s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
+ if (!Le || s <= 0.) {
+ u = U_NEU;
+ v = V_NEU;
+ } else {
+ u = 4.*XYZ[0] / s;
+ v = 9.*XYZ[1] / s;
+ }
+ Ce = uv_encode(u, v, em);
+ if (Ce < 0) /* never happens */
+ Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
+ /* combine encodings */
+ return (Le << 14 | Ce);
+}
+
+static void
+Luv24toXYZ(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ float* xyz = (float*) op;
+
+ while (n-- > 0) {
+ LogLuv24toXYZ(*luv, xyz);
+ xyz += 3;
+ luv++;
+ }
+}
+
+static void
+Luv24toLuv48(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ int16* luv3 = (int16*) op;
+
+ while (n-- > 0) {
+ double u, v;
+
+ *luv3++ = (int16)((*luv >> 12 & 0xffd) + 13314);
+ if (uv_decode(&u, &v, *luv&0x3fff) < 0) {
+ u = U_NEU;
+ v = V_NEU;
+ }
+ *luv3++ = (int16)(u * (1L<<15));
+ *luv3++ = (int16)(v * (1L<<15));
+ luv++;
+ }
+}
+
+static void
+Luv24toRGB(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ uint8* rgb = (uint8*) op;
+
+ while (n-- > 0) {
+ float xyz[3];
+
+ LogLuv24toXYZ(*luv++, xyz);
+ XYZtoRGB24(xyz, rgb);
+ rgb += 3;
+ }
+}
+
+static void
+Luv24fromXYZ(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ float* xyz = (float*) op;
+
+ while (n-- > 0) {
+ *luv++ = LogLuv24fromXYZ(xyz, sp->encode_meth);
+ xyz += 3;
+ }
+}
+
+static void
+Luv24fromLuv48(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ int16* luv3 = (int16*) op;
+
+ while (n-- > 0) {
+ int Le, Ce;
+
+ if (luv3[0] <= 0)
+ Le = 0;
+ else if (luv3[0] >= (1<<12)+3314)
+ Le = (1<<10) - 1;
+ else if (sp->encode_meth == SGILOGENCODE_NODITHER)
+ Le = (luv3[0]-3314) >> 2;
+ else
+ Le = itrunc(.25*(luv3[0]-3314.), sp->encode_meth);
+
+ Ce = uv_encode((luv3[1]+.5)/(1<<15), (luv3[2]+.5)/(1<<15),
+ sp->encode_meth);
+ if (Ce < 0) /* never happens */
+ Ce = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
+ *luv++ = (uint32)Le << 14 | Ce;
+ luv3 += 3;
+ }
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+void
+LogLuv32toXYZ(uint32 p, float XYZ[3])
+{
+ double L, u, v, s, x, y;
+ /* decode luminance */
+ L = LogL16toY((int)p >> 16);
+ if (L <= 0.) {
+ XYZ[0] = XYZ[1] = XYZ[2] = 0.;
+ return;
+ }
+ /* decode color */
+ u = 1./UVSCALE * ((p>>8 & 0xff) + .5);
+ v = 1./UVSCALE * ((p & 0xff) + .5);
+ s = 1./(6.*u - 16.*v + 12.);
+ x = 9.*u * s;
+ y = 4.*v * s;
+ /* convert to XYZ */
+ XYZ[0] = (float)(x/y * L);
+ XYZ[1] = (float)L;
+ XYZ[2] = (float)((1.-x-y)/y * L);
+}
+
+#if !LOGLUV_PUBLIC
+static
+#endif
+uint32
+LogLuv32fromXYZ(float XYZ[3], int em)
+{
+ unsigned int Le, ue, ve;
+ double u, v, s;
+ /* encode luminance */
+ Le = (unsigned int)LogL16fromY(XYZ[1], em);
+ /* encode color */
+ s = XYZ[0] + 15.*XYZ[1] + 3.*XYZ[2];
+ if (!Le || s <= 0.) {
+ u = U_NEU;
+ v = V_NEU;
+ } else {
+ u = 4.*XYZ[0] / s;
+ v = 9.*XYZ[1] / s;
+ }
+ if (u <= 0.) ue = 0;
+ else ue = itrunc(UVSCALE*u, em);
+ if (ue > 255) ue = 255;
+ if (v <= 0.) ve = 0;
+ else ve = itrunc(UVSCALE*v, em);
+ if (ve > 255) ve = 255;
+ /* combine encodings */
+ return (Le << 16 | ue << 8 | ve);
+}
+
+static void
+Luv32toXYZ(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ float* xyz = (float*) op;
+
+ while (n-- > 0) {
+ LogLuv32toXYZ(*luv++, xyz);
+ xyz += 3;
+ }
+}
+
+static void
+Luv32toLuv48(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ int16* luv3 = (int16*) op;
+
+ while (n-- > 0) {
+ double u, v;
+
+ *luv3++ = (int16)(*luv >> 16);
+ u = 1./UVSCALE * ((*luv>>8 & 0xff) + .5);
+ v = 1./UVSCALE * ((*luv & 0xff) + .5);
+ *luv3++ = (int16)(u * (1L<<15));
+ *luv3++ = (int16)(v * (1L<<15));
+ luv++;
+ }
+}
+
+static void
+Luv32toRGB(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ uint8* rgb = (uint8*) op;
+
+ while (n-- > 0) {
+ float xyz[3];
+
+ LogLuv32toXYZ(*luv++, xyz);
+ XYZtoRGB24(xyz, rgb);
+ rgb += 3;
+ }
+}
+
+static void
+Luv32fromXYZ(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ float* xyz = (float*) op;
+
+ while (n-- > 0) {
+ *luv++ = LogLuv32fromXYZ(xyz, sp->encode_meth);
+ xyz += 3;
+ }
+}
+
+static void
+Luv32fromLuv48(LogLuvState* sp, tidata_t op, int n)
+{
+ uint32* luv = (uint32*) sp->tbuf;
+ int16* luv3 = (int16*) op;
+
+ if (sp->encode_meth == SGILOGENCODE_NODITHER) {
+ while (n-- > 0) {
+ *luv++ = (uint32)luv3[0] << 16 |
+ (luv3[1]*(uint32)(UVSCALE+.5) >> 7 & 0xff00) |
+ (luv3[2]*(uint32)(UVSCALE+.5) >> 15 & 0xff);
+ luv3 += 3;
+ }
+ return;
+ }
+ while (n-- > 0) {
+ *luv++ = (uint32)luv3[0] << 16 |
+ (itrunc(luv3[1]*(UVSCALE/(1<<15)), sp->encode_meth) << 8 & 0xff00) |
+ (itrunc(luv3[2]*(UVSCALE/(1<<15)), sp->encode_meth) & 0xff);
+ luv3 += 3;
+ }
+}
+
+static void
+_logLuvNop(LogLuvState* sp, tidata_t op, int n)
+{
+ (void) sp; (void) op; (void) n;
+}
+
+static int
+LogL16GuessDataFmt(TIFFDirectory *td)
+{
+#define PACK(s,b,f) (((b)<<6)|((s)<<3)|(f))
+ switch (PACK(td->td_samplesperpixel, td->td_bitspersample, td->td_sampleformat)) {
+ case PACK(1, 32, SAMPLEFORMAT_IEEEFP):
+ return (SGILOGDATAFMT_FLOAT);
+ case PACK(1, 16, SAMPLEFORMAT_VOID):
+ case PACK(1, 16, SAMPLEFORMAT_INT):
+ case PACK(1, 16, SAMPLEFORMAT_UINT):
+ return (SGILOGDATAFMT_16BIT);
+ case PACK(1, 8, SAMPLEFORMAT_VOID):
+ case PACK(1, 8, SAMPLEFORMAT_UINT):
+ return (SGILOGDATAFMT_8BIT);
+ }
+#undef PACK
+ return (SGILOGDATAFMT_UNKNOWN);
+}
+
+static uint32
+multiply(size_t m1, size_t m2)
+{
+ uint32 bytes = m1 * m2;
+
+ if (m1 && bytes / m1 != m2)
+ bytes = 0;
+
+ return bytes;
+}
+
+static int
+LogL16InitState(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ LogLuvState* sp = DecoderState(tif);
+ static const char module[] = "LogL16InitState";
+
+ assert(sp != NULL);
+ assert(td->td_photometric == PHOTOMETRIC_LOGL);
+
+ /* for some reason, we can't do this in TIFFInitLogL16 */
+ if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
+ sp->user_datafmt = LogL16GuessDataFmt(td);
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ sp->pixel_size = sizeof (float);
+ break;
+ case SGILOGDATAFMT_16BIT:
+ sp->pixel_size = sizeof (int16);
+ break;
+ case SGILOGDATAFMT_8BIT:
+ sp->pixel_size = sizeof (uint8);
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "No support for converting user data format to LogL");
+ return (0);
+ }
+ if( isTiled(tif) )
+ sp->tbuflen = multiply(td->td_tilewidth, td->td_tilelength);
+ else
+ sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip);
+ if (multiply(sp->tbuflen, sizeof (int16)) == 0 ||
+ (sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (int16))) == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for SGILog translation buffer",
+ tif->tif_name);
+ return (0);
+ }
+ return (1);
+}
+
+static int
+LogLuvGuessDataFmt(TIFFDirectory *td)
+{
+ int guess;
+
+ /*
+ * If the user didn't tell us their datafmt,
+ * take our best guess from the bitspersample.
+ */
+#define PACK(a,b) (((a)<<3)|(b))
+ switch (PACK(td->td_bitspersample, td->td_sampleformat)) {
+ case PACK(32, SAMPLEFORMAT_IEEEFP):
+ guess = SGILOGDATAFMT_FLOAT;
+ break;
+ case PACK(32, SAMPLEFORMAT_VOID):
+ case PACK(32, SAMPLEFORMAT_UINT):
+ case PACK(32, SAMPLEFORMAT_INT):
+ guess = SGILOGDATAFMT_RAW;
+ break;
+ case PACK(16, SAMPLEFORMAT_VOID):
+ case PACK(16, SAMPLEFORMAT_INT):
+ case PACK(16, SAMPLEFORMAT_UINT):
+ guess = SGILOGDATAFMT_16BIT;
+ break;
+ case PACK( 8, SAMPLEFORMAT_VOID):
+ case PACK( 8, SAMPLEFORMAT_UINT):
+ guess = SGILOGDATAFMT_8BIT;
+ break;
+ default:
+ guess = SGILOGDATAFMT_UNKNOWN;
+ break;
+#undef PACK
+ }
+ /*
+ * Double-check samples per pixel.
+ */
+ switch (td->td_samplesperpixel) {
+ case 1:
+ if (guess != SGILOGDATAFMT_RAW)
+ guess = SGILOGDATAFMT_UNKNOWN;
+ break;
+ case 3:
+ if (guess == SGILOGDATAFMT_RAW)
+ guess = SGILOGDATAFMT_UNKNOWN;
+ break;
+ default:
+ guess = SGILOGDATAFMT_UNKNOWN;
+ break;
+ }
+ return (guess);
+}
+
+static int
+LogLuvInitState(TIFF* tif)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ LogLuvState* sp = DecoderState(tif);
+ static const char module[] = "LogLuvInitState";
+
+ assert(sp != NULL);
+ assert(td->td_photometric == PHOTOMETRIC_LOGLUV);
+
+ /* for some reason, we can't do this in TIFFInitLogLuv */
+ if (td->td_planarconfig != PLANARCONFIG_CONTIG) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "SGILog compression cannot handle non-contiguous data");
+ return (0);
+ }
+ if (sp->user_datafmt == SGILOGDATAFMT_UNKNOWN)
+ sp->user_datafmt = LogLuvGuessDataFmt(td);
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ sp->pixel_size = 3*sizeof (float);
+ break;
+ case SGILOGDATAFMT_16BIT:
+ sp->pixel_size = 3*sizeof (int16);
+ break;
+ case SGILOGDATAFMT_RAW:
+ sp->pixel_size = sizeof (uint32);
+ break;
+ case SGILOGDATAFMT_8BIT:
+ sp->pixel_size = 3*sizeof (uint8);
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "No support for converting user data format to LogLuv");
+ return (0);
+ }
+ if( isTiled(tif) )
+ sp->tbuflen = multiply(td->td_tilewidth, td->td_tilelength);
+ else
+ sp->tbuflen = multiply(td->td_imagewidth, td->td_rowsperstrip);
+ if (multiply(sp->tbuflen, sizeof (uint32)) == 0 ||
+ (sp->tbuf = (tidata_t*) _TIFFmalloc(sp->tbuflen * sizeof (uint32))) == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for SGILog translation buffer",
+ tif->tif_name);
+ return (0);
+ }
+ return (1);
+}
+
+static int
+LogLuvSetupDecode(TIFF* tif)
+{
+ LogLuvState* sp = DecoderState(tif);
+ TIFFDirectory* td = &tif->tif_dir;
+
+ tif->tif_postdecode = _TIFFNoPostDecode;
+ switch (td->td_photometric) {
+ case PHOTOMETRIC_LOGLUV:
+ if (!LogLuvInitState(tif))
+ break;
+ if (td->td_compression == COMPRESSION_SGILOG24) {
+ tif->tif_decoderow = LogLuvDecode24;
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ sp->tfunc = Luv24toXYZ;
+ break;
+ case SGILOGDATAFMT_16BIT:
+ sp->tfunc = Luv24toLuv48;
+ break;
+ case SGILOGDATAFMT_8BIT:
+ sp->tfunc = Luv24toRGB;
+ break;
+ }
+ } else {
+ tif->tif_decoderow = LogLuvDecode32;
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ sp->tfunc = Luv32toXYZ;
+ break;
+ case SGILOGDATAFMT_16BIT:
+ sp->tfunc = Luv32toLuv48;
+ break;
+ case SGILOGDATAFMT_8BIT:
+ sp->tfunc = Luv32toRGB;
+ break;
+ }
+ }
+ return (1);
+ case PHOTOMETRIC_LOGL:
+ if (!LogL16InitState(tif))
+ break;
+ tif->tif_decoderow = LogL16Decode;
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ sp->tfunc = L16toY;
+ break;
+ case SGILOGDATAFMT_8BIT:
+ sp->tfunc = L16toGry;
+ break;
+ }
+ return (1);
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Inappropriate photometric interpretation %d for SGILog compression; %s",
+ td->td_photometric, "must be either LogLUV or LogL");
+ break;
+ }
+ return (0);
+}
+
+static int
+LogLuvSetupEncode(TIFF* tif)
+{
+ LogLuvState* sp = EncoderState(tif);
+ TIFFDirectory* td = &tif->tif_dir;
+
+ switch (td->td_photometric) {
+ case PHOTOMETRIC_LOGLUV:
+ if (!LogLuvInitState(tif))
+ break;
+ if (td->td_compression == COMPRESSION_SGILOG24) {
+ tif->tif_encoderow = LogLuvEncode24;
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ sp->tfunc = Luv24fromXYZ;
+ break;
+ case SGILOGDATAFMT_16BIT:
+ sp->tfunc = Luv24fromLuv48;
+ break;
+ case SGILOGDATAFMT_RAW:
+ break;
+ default:
+ goto notsupported;
+ }
+ } else {
+ tif->tif_encoderow = LogLuvEncode32;
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ sp->tfunc = Luv32fromXYZ;
+ break;
+ case SGILOGDATAFMT_16BIT:
+ sp->tfunc = Luv32fromLuv48;
+ break;
+ case SGILOGDATAFMT_RAW:
+ break;
+ default:
+ goto notsupported;
+ }
+ }
+ break;
+ case PHOTOMETRIC_LOGL:
+ if (!LogL16InitState(tif))
+ break;
+ tif->tif_encoderow = LogL16Encode;
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ sp->tfunc = L16fromY;
+ break;
+ case SGILOGDATAFMT_16BIT:
+ break;
+ default:
+ goto notsupported;
+ }
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Inappropriate photometric interpretation %d for SGILog compression; %s",
+ td->td_photometric, "must be either LogLUV or LogL");
+ break;
+ }
+ return (1);
+notsupported:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "SGILog compression supported only for %s, or raw data",
+ td->td_photometric == PHOTOMETRIC_LOGL ? "Y, L" : "XYZ, Luv");
+ return (0);
+}
+
+static void
+LogLuvClose(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ /*
+ * For consistency, we always want to write out the same
+ * bitspersample and sampleformat for our TIFF file,
+ * regardless of the data format being used by the application.
+ * Since this routine is called after tags have been set but
+ * before they have been recorded in the file, we reset them here.
+ */
+ td->td_samplesperpixel =
+ (td->td_photometric == PHOTOMETRIC_LOGL) ? 1 : 3;
+ td->td_bitspersample = 16;
+ td->td_sampleformat = SAMPLEFORMAT_INT;
+}
+
+static void
+LogLuvCleanup(TIFF* tif)
+{
+ LogLuvState* sp = (LogLuvState *)tif->tif_data;
+
+ assert(sp != 0);
+
+ tif->tif_tagmethods.vgetfield = sp->vgetparent;
+ tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+ if (sp->tbuf)
+ _TIFFfree(sp->tbuf);
+ _TIFFfree(sp);
+ tif->tif_data = NULL;
+
+ _TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+LogLuvVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ LogLuvState* sp = DecoderState(tif);
+ int bps, fmt;
+
+ switch (tag) {
+ case TIFFTAG_SGILOGDATAFMT:
+ sp->user_datafmt = va_arg(ap, int);
+ /*
+ * Tweak the TIFF header so that the rest of libtiff knows what
+ * size of data will be passed between app and library, and
+ * assume that the app knows what it is doing and is not
+ * confused by these header manipulations...
+ */
+ switch (sp->user_datafmt) {
+ case SGILOGDATAFMT_FLOAT:
+ bps = 32, fmt = SAMPLEFORMAT_IEEEFP;
+ break;
+ case SGILOGDATAFMT_16BIT:
+ bps = 16, fmt = SAMPLEFORMAT_INT;
+ break;
+ case SGILOGDATAFMT_RAW:
+ bps = 32, fmt = SAMPLEFORMAT_UINT;
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ break;
+ case SGILOGDATAFMT_8BIT:
+ bps = 8, fmt = SAMPLEFORMAT_UINT;
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Unknown data format %d for LogLuv compression",
+ sp->user_datafmt);
+ return (0);
+ }
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps);
+ TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, fmt);
+ /*
+ * Must recalculate sizes should bits/sample change.
+ */
+ tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1;
+ tif->tif_scanlinesize = TIFFScanlineSize(tif);
+ return (1);
+ case TIFFTAG_SGILOGENCODE:
+ sp->encode_meth = va_arg(ap, int);
+ if (sp->encode_meth != SGILOGENCODE_NODITHER &&
+ sp->encode_meth != SGILOGENCODE_RANDITHER) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Unknown encoding %d for LogLuv compression",
+ sp->encode_meth);
+ return (0);
+ }
+ return (1);
+ default:
+ return (*sp->vsetparent)(tif, tag, ap);
+ }
+}
+
+static int
+LogLuvVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ LogLuvState *sp = (LogLuvState *)tif->tif_data;
+
+ switch (tag) {
+ case TIFFTAG_SGILOGDATAFMT:
+ *va_arg(ap, int*) = sp->user_datafmt;
+ return (1);
+ default:
+ return (*sp->vgetparent)(tif, tag, ap);
+ }
+}
+
+static const TIFFFieldInfo LogLuvFieldInfo[] = {
+ { TIFFTAG_SGILOGDATAFMT, 0, 0, TIFF_SHORT, FIELD_PSEUDO,
+ TRUE, FALSE, "SGILogDataFmt"},
+ { TIFFTAG_SGILOGENCODE, 0, 0, TIFF_SHORT, FIELD_PSEUDO,
+ TRUE, FALSE, "SGILogEncode"}
+};
+
+int
+TIFFInitSGILog(TIFF* tif, int scheme)
+{
+ static const char module[] = "TIFFInitSGILog";
+ LogLuvState* sp;
+
+ assert(scheme == COMPRESSION_SGILOG24 || scheme == COMPRESSION_SGILOG);
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, LogLuvFieldInfo,
+ TIFFArrayCount(LogLuvFieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Merging SGILog codec-specific tags failed");
+ return 0;
+ }
+
+ /*
+ * Allocate state block so tag methods have storage to record values.
+ */
+ tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (LogLuvState));
+ if (tif->tif_data == NULL)
+ goto bad;
+ sp = (LogLuvState*) tif->tif_data;
+ _TIFFmemset((tdata_t)sp, 0, sizeof (*sp));
+ sp->user_datafmt = SGILOGDATAFMT_UNKNOWN;
+ sp->encode_meth = (scheme == COMPRESSION_SGILOG24) ?
+ SGILOGENCODE_RANDITHER : SGILOGENCODE_NODITHER;
+ sp->tfunc = _logLuvNop;
+
+ /*
+ * Install codec methods.
+ * NB: tif_decoderow & tif_encoderow are filled
+ * in at setup time.
+ */
+ tif->tif_setupdecode = LogLuvSetupDecode;
+ tif->tif_decodestrip = LogLuvDecodeStrip;
+ tif->tif_decodetile = LogLuvDecodeTile;
+ tif->tif_setupencode = LogLuvSetupEncode;
+ tif->tif_encodestrip = LogLuvEncodeStrip;
+ tif->tif_encodetile = LogLuvEncodeTile;
+ tif->tif_close = LogLuvClose;
+ tif->tif_cleanup = LogLuvCleanup;
+
+ /*
+ * Override parent get/set field methods.
+ */
+ sp->vgetparent = tif->tif_tagmethods.vgetfield;
+ tif->tif_tagmethods.vgetfield = LogLuvVGetField; /* hook for codec tags */
+ sp->vsetparent = tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vsetfield = LogLuvVSetField; /* hook for codec tags */
+
+ return (1);
+bad:
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: No space for LogLuv state block", tif->tif_name);
+ return (0);
+}
+#endif /* LOGLUV_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_lzw.c b/tiff/libtiff/tif_lzw.c
new file mode 100644
index 0000000..d423866
--- /dev/null
+++ b/tiff/libtiff/tif_lzw.c
@@ -0,0 +1,1129 @@
+/* $Id: tif_lzw.c,v 1.29.2.6 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef LZW_SUPPORT
+/*
+ * TIFF Library.
+ * Rev 5.0 Lempel-Ziv & Welch Compression Support
+ *
+ * This code is derived from the compress program whose code is
+ * derived from software contributed to Berkeley by James A. Woods,
+ * derived from original work by Spencer Thomas and Joseph Orost.
+ *
+ * The original Berkeley copyright notice appears below in its entirety.
+ */
+#include "tif_predict.h"
+
+#include <stdio.h>
+
+/*
+ * NB: The 5.0 spec describes a different algorithm than Aldus
+ * implements. Specifically, Aldus does code length transitions
+ * one code earlier than should be done (for real LZW).
+ * Earlier versions of this library implemented the correct
+ * LZW algorithm, but emitted codes in a bit order opposite
+ * to the TIFF spec. Thus, to maintain compatibility w/ Aldus
+ * we interpret MSB-LSB ordered codes to be images written w/
+ * old versions of this library, but otherwise adhere to the
+ * Aldus "off by one" algorithm.
+ *
+ * Future revisions to the TIFF spec are expected to "clarify this issue".
+ */
+#define LZW_COMPAT /* include backwards compatibility code */
+/*
+ * Each strip of data is supposed to be terminated by a CODE_EOI.
+ * If the following #define is included, the decoder will also
+ * check for end-of-strip w/o seeing this code. This makes the
+ * library more robust, but also slower.
+ */
+#define LZW_CHECKEOS /* include checks for strips w/o EOI code */
+
+#define MAXCODE(n) ((1L<<(n))-1)
+/*
+ * The TIFF spec specifies that encoded bit
+ * strings range from 9 to 12 bits.
+ */
+#define BITS_MIN 9 /* start with 9 bits */
+#define BITS_MAX 12 /* max of 12 bit strings */
+/* predefined codes */
+#define CODE_CLEAR 256 /* code to clear string table */
+#define CODE_EOI 257 /* end-of-information code */
+#define CODE_FIRST 258 /* first free code entry */
+#define CODE_MAX MAXCODE(BITS_MAX)
+#define HSIZE 9001L /* 91% occupancy */
+#define HSHIFT (13-8)
+#ifdef LZW_COMPAT
+/* NB: +1024 is for compatibility with old files */
+#define CSIZE (MAXCODE(BITS_MAX)+1024L)
+#else
+#define CSIZE (MAXCODE(BITS_MAX)+1L)
+#endif
+
+/*
+ * State block for each open TIFF file using LZW
+ * compression/decompression. Note that the predictor
+ * state block must be first in this data structure.
+ */
+typedef struct {
+ TIFFPredictorState predict; /* predictor super class */
+
+ unsigned short nbits; /* # of bits/code */
+ unsigned short maxcode; /* maximum code for lzw_nbits */
+ unsigned short free_ent; /* next free entry in hash table */
+ long nextdata; /* next bits of i/o */
+ long nextbits; /* # of valid bits in lzw_nextdata */
+
+ int rw_mode; /* preserve rw_mode from init */
+} LZWBaseState;
+
+#define lzw_nbits base.nbits
+#define lzw_maxcode base.maxcode
+#define lzw_free_ent base.free_ent
+#define lzw_nextdata base.nextdata
+#define lzw_nextbits base.nextbits
+
+/*
+ * Encoding-specific state.
+ */
+typedef uint16 hcode_t; /* codes fit in 16 bits */
+typedef struct {
+ long hash;
+ hcode_t code;
+} hash_t;
+
+/*
+ * Decoding-specific state.
+ */
+typedef struct code_ent {
+ struct code_ent *next;
+ unsigned short length; /* string len, including this token */
+ unsigned char value; /* data value */
+ unsigned char firstchar; /* first token of string */
+} code_t;
+
+typedef int (*decodeFunc)(TIFF*, tidata_t, tsize_t, tsample_t);
+
+typedef struct {
+ LZWBaseState base;
+
+ /* Decoding specific data */
+ long dec_nbitsmask; /* lzw_nbits 1 bits, right adjusted */
+ long dec_restart; /* restart count */
+#ifdef LZW_CHECKEOS
+ long dec_bitsleft; /* available bits in raw data */
+#endif
+ decodeFunc dec_decode; /* regular or backwards compatible */
+ code_t* dec_codep; /* current recognized code */
+ code_t* dec_oldcodep; /* previously recognized code */
+ code_t* dec_free_entp; /* next free entry */
+ code_t* dec_maxcodep; /* max available entry */
+ code_t* dec_codetab; /* kept separate for small machines */
+
+ /* Encoding specific data */
+ int enc_oldcode; /* last code encountered */
+ long enc_checkpoint; /* point at which to clear table */
+#define CHECK_GAP 10000 /* enc_ratio check interval */
+ long enc_ratio; /* current compression ratio */
+ long enc_incount; /* (input) data bytes encoded */
+ long enc_outcount; /* encoded (output) bytes */
+ tidata_t enc_rawlimit; /* bound on tif_rawdata buffer */
+ hash_t* enc_hashtab; /* kept separate for small machines */
+} LZWCodecState;
+
+#define LZWState(tif) ((LZWBaseState*) (tif)->tif_data)
+#define DecoderState(tif) ((LZWCodecState*) LZWState(tif))
+#define EncoderState(tif) ((LZWCodecState*) LZWState(tif))
+
+static int LZWDecode(TIFF*, tidata_t, tsize_t, tsample_t);
+#ifdef LZW_COMPAT
+static int LZWDecodeCompat(TIFF*, tidata_t, tsize_t, tsample_t);
+#endif
+static void cl_hash(LZWCodecState*);
+
+/*
+ * LZW Decoder.
+ */
+
+#ifdef LZW_CHECKEOS
+/*
+ * This check shouldn't be necessary because each
+ * strip is suppose to be terminated with CODE_EOI.
+ */
+#define NextCode(_tif, _sp, _bp, _code, _get) { \
+ if ((_sp)->dec_bitsleft < nbits) { \
+ TIFFWarningExt(_tif->tif_clientdata, _tif->tif_name, \
+ "LZWDecode: Strip %d not terminated with EOI code", \
+ _tif->tif_curstrip); \
+ _code = CODE_EOI; \
+ } else { \
+ _get(_sp,_bp,_code); \
+ (_sp)->dec_bitsleft -= nbits; \
+ } \
+}
+#else
+#define NextCode(tif, sp, bp, code, get) get(sp, bp, code)
+#endif
+
+static int
+LZWSetupDecode(TIFF* tif)
+{
+ LZWCodecState* sp = DecoderState(tif);
+ static const char module[] = " LZWSetupDecode";
+ int code;
+
+ if( sp == NULL )
+ {
+ /*
+ * Allocate state block so tag methods have storage to record
+ * values.
+ */
+ tif->tif_data = (tidata_t) _TIFFmalloc(sizeof(LZWCodecState));
+ if (tif->tif_data == NULL)
+ {
+ TIFFErrorExt(tif->tif_clientdata, "LZWPreDecode", "No space for LZW state block");
+ return (0);
+ }
+
+ DecoderState(tif)->dec_codetab = NULL;
+ DecoderState(tif)->dec_decode = NULL;
+
+ /*
+ * Setup predictor setup.
+ */
+ (void) TIFFPredictorInit(tif);
+
+ sp = DecoderState(tif);
+ }
+
+ assert(sp != NULL);
+
+ if (sp->dec_codetab == NULL) {
+ sp->dec_codetab = (code_t*)_TIFFmalloc(CSIZE*sizeof (code_t));
+ if (sp->dec_codetab == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "No space for LZW code table");
+ return (0);
+ }
+ /*
+ * Pre-load the table.
+ */
+ code = 255;
+ do {
+ sp->dec_codetab[code].value = code;
+ sp->dec_codetab[code].firstchar = code;
+ sp->dec_codetab[code].length = 1;
+ sp->dec_codetab[code].next = NULL;
+ } while (code--);
+ /*
+ * Zero-out the unused entries
+ */
+ _TIFFmemset(&sp->dec_codetab[CODE_CLEAR], 0,
+ (CODE_FIRST - CODE_CLEAR) * sizeof (code_t));
+ }
+ return (1);
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+LZWPreDecode(TIFF* tif, tsample_t s)
+{
+ LZWCodecState *sp = DecoderState(tif);
+
+ (void) s;
+ assert(sp != NULL);
+ if( sp->dec_codetab == NULL )
+ {
+ tif->tif_setupdecode( tif );
+ }
+
+ /*
+ * Check for old bit-reversed codes.
+ */
+ if (tif->tif_rawdata[0] == 0 && (tif->tif_rawdata[1] & 0x1)) {
+#ifdef LZW_COMPAT
+ if (!sp->dec_decode) {
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "Old-style LZW codes, convert file");
+ /*
+ * Override default decoding methods with
+ * ones that deal with the old coding.
+ * Otherwise the predictor versions set
+ * above will call the compatibility routines
+ * through the dec_decode method.
+ */
+ tif->tif_decoderow = LZWDecodeCompat;
+ tif->tif_decodestrip = LZWDecodeCompat;
+ tif->tif_decodetile = LZWDecodeCompat;
+ /*
+ * If doing horizontal differencing, must
+ * re-setup the predictor logic since we
+ * switched the basic decoder methods...
+ */
+ (*tif->tif_setupdecode)(tif);
+ sp->dec_decode = LZWDecodeCompat;
+ }
+ sp->lzw_maxcode = MAXCODE(BITS_MIN);
+#else /* !LZW_COMPAT */
+ if (!sp->dec_decode) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Old-style LZW codes not supported");
+ sp->dec_decode = LZWDecode;
+ }
+ return (0);
+#endif/* !LZW_COMPAT */
+ } else {
+ sp->lzw_maxcode = MAXCODE(BITS_MIN)-1;
+ sp->dec_decode = LZWDecode;
+ }
+ sp->lzw_nbits = BITS_MIN;
+ sp->lzw_nextbits = 0;
+ sp->lzw_nextdata = 0;
+
+ sp->dec_restart = 0;
+ sp->dec_nbitsmask = MAXCODE(BITS_MIN);
+#ifdef LZW_CHECKEOS
+ sp->dec_bitsleft = tif->tif_rawcc << 3;
+#endif
+ sp->dec_free_entp = sp->dec_codetab + CODE_FIRST;
+ /*
+ * Zero entries that are not yet filled in. We do
+ * this to guard against bogus input data that causes
+ * us to index into undefined entries. If you can
+ * come up with a way to safely bounds-check input codes
+ * while decoding then you can remove this operation.
+ */
+ _TIFFmemset(sp->dec_free_entp, 0, (CSIZE-CODE_FIRST)*sizeof (code_t));
+ sp->dec_oldcodep = &sp->dec_codetab[-1];
+ sp->dec_maxcodep = &sp->dec_codetab[sp->dec_nbitsmask-1];
+ return (1);
+}
+
+/*
+ * Decode a "hunk of data".
+ */
+#define GetNextCode(sp, bp, code) { \
+ nextdata = (nextdata<<8) | *(bp)++; \
+ nextbits += 8; \
+ if (nextbits < nbits) { \
+ nextdata = (nextdata<<8) | *(bp)++; \
+ nextbits += 8; \
+ } \
+ code = (hcode_t)((nextdata >> (nextbits-nbits)) & nbitsmask); \
+ nextbits -= nbits; \
+}
+
+static void
+codeLoop(TIFF* tif)
+{
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecode: Bogus encoding, loop in the code table; scanline %d",
+ tif->tif_row);
+}
+
+static int
+LZWDecode(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s)
+{
+ LZWCodecState *sp = DecoderState(tif);
+ char *op = (char*) op0;
+ long occ = (long) occ0;
+ char *tp;
+ unsigned char *bp;
+ hcode_t code;
+ int len;
+ long nbits, nextbits, nextdata, nbitsmask;
+ code_t *codep, *free_entp, *maxcodep, *oldcodep;
+
+ (void) s;
+ assert(sp != NULL);
+ assert(sp->dec_codetab != NULL);
+ /*
+ * Restart interrupted output operation.
+ */
+ if (sp->dec_restart) {
+ long residue;
+
+ codep = sp->dec_codep;
+ residue = codep->length - sp->dec_restart;
+ if (residue > occ) {
+ /*
+ * Residue from previous decode is sufficient
+ * to satisfy decode request. Skip to the
+ * start of the decoded string, place decoded
+ * values in the output buffer, and return.
+ */
+ sp->dec_restart += occ;
+ do {
+ codep = codep->next;
+ } while (--residue > occ && codep);
+ if (codep) {
+ tp = op + occ;
+ do {
+ *--tp = codep->value;
+ codep = codep->next;
+ } while (--occ && codep);
+ }
+ return (1);
+ }
+ /*
+ * Residue satisfies only part of the decode request.
+ */
+ op += residue, occ -= residue;
+ tp = op;
+ do {
+ int t;
+ --tp;
+ t = codep->value;
+ codep = codep->next;
+ *tp = t;
+ } while (--residue && codep);
+ sp->dec_restart = 0;
+ }
+
+ bp = (unsigned char *)tif->tif_rawcp;
+ nbits = sp->lzw_nbits;
+ nextdata = sp->lzw_nextdata;
+ nextbits = sp->lzw_nextbits;
+ nbitsmask = sp->dec_nbitsmask;
+ oldcodep = sp->dec_oldcodep;
+ free_entp = sp->dec_free_entp;
+ maxcodep = sp->dec_maxcodep;
+
+ while (occ > 0) {
+ NextCode(tif, sp, bp, code, GetNextCode);
+ if (code == CODE_EOI)
+ break;
+ if (code == CODE_CLEAR) {
+ free_entp = sp->dec_codetab + CODE_FIRST;
+ _TIFFmemset(free_entp, 0,
+ (CSIZE - CODE_FIRST) * sizeof (code_t));
+ nbits = BITS_MIN;
+ nbitsmask = MAXCODE(BITS_MIN);
+ maxcodep = sp->dec_codetab + nbitsmask-1;
+ NextCode(tif, sp, bp, code, GetNextCode);
+ if (code == CODE_EOI)
+ break;
+ if (code == CODE_CLEAR) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecode: Corrupted LZW table at scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+ *op++ = (char)code, occ--;
+ oldcodep = sp->dec_codetab + code;
+ continue;
+ }
+ codep = sp->dec_codetab + code;
+
+ /*
+ * Add the new entry to the code table.
+ */
+ if (free_entp < &sp->dec_codetab[0] ||
+ free_entp >= &sp->dec_codetab[CSIZE]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecode: Corrupted LZW table at scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+
+ free_entp->next = oldcodep;
+ if (free_entp->next < &sp->dec_codetab[0] ||
+ free_entp->next >= &sp->dec_codetab[CSIZE]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecode: Corrupted LZW table at scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+ free_entp->firstchar = free_entp->next->firstchar;
+ free_entp->length = free_entp->next->length+1;
+ free_entp->value = (codep < free_entp) ?
+ codep->firstchar : free_entp->firstchar;
+ if (++free_entp > maxcodep) {
+ if (++nbits > BITS_MAX) /* should not happen */
+ nbits = BITS_MAX;
+ nbitsmask = MAXCODE(nbits);
+ maxcodep = sp->dec_codetab + nbitsmask-1;
+ }
+ oldcodep = codep;
+ if (code >= 256) {
+ /*
+ * Code maps to a string, copy string
+ * value to output (written in reverse).
+ */
+ if(codep->length == 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecode: Wrong length of decoded string: "
+ "data probably corrupted at scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+ if (codep->length > occ) {
+ /*
+ * String is too long for decode buffer,
+ * locate portion that will fit, copy to
+ * the decode buffer, and setup restart
+ * logic for the next decoding call.
+ */
+ sp->dec_codep = codep;
+ do {
+ codep = codep->next;
+ } while (codep && codep->length > occ);
+ if (codep) {
+ sp->dec_restart = occ;
+ tp = op + occ;
+ do {
+ *--tp = codep->value;
+ codep = codep->next;
+ } while (--occ && codep);
+ if (codep)
+ codeLoop(tif);
+ }
+ break;
+ }
+ len = codep->length;
+ tp = op + len;
+ do {
+ int t;
+ --tp;
+ t = codep->value;
+ codep = codep->next;
+ *tp = t;
+ } while (codep && tp > op);
+ if (codep) {
+ codeLoop(tif);
+ break;
+ }
+ op += len, occ -= len;
+ } else
+ *op++ = (char)code, occ--;
+ }
+
+ tif->tif_rawcp = (tidata_t) bp;
+ sp->lzw_nbits = (unsigned short) nbits;
+ sp->lzw_nextdata = nextdata;
+ sp->lzw_nextbits = nextbits;
+ sp->dec_nbitsmask = nbitsmask;
+ sp->dec_oldcodep = oldcodep;
+ sp->dec_free_entp = free_entp;
+ sp->dec_maxcodep = maxcodep;
+
+ if (occ > 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecode: Not enough data at scanline %d (short %ld bytes)",
+ tif->tif_row, occ);
+ return (0);
+ }
+ return (1);
+}
+
+#ifdef LZW_COMPAT
+/*
+ * Decode a "hunk of data" for old images.
+ */
+#define GetNextCodeCompat(sp, bp, code) { \
+ nextdata |= (unsigned long) *(bp)++ << nextbits; \
+ nextbits += 8; \
+ if (nextbits < nbits) { \
+ nextdata |= (unsigned long) *(bp)++ << nextbits;\
+ nextbits += 8; \
+ } \
+ code = (hcode_t)(nextdata & nbitsmask); \
+ nextdata >>= nbits; \
+ nextbits -= nbits; \
+}
+
+static int
+LZWDecodeCompat(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s)
+{
+ LZWCodecState *sp = DecoderState(tif);
+ char *op = (char*) op0;
+ long occ = (long) occ0;
+ char *tp;
+ unsigned char *bp;
+ int code, nbits;
+ long nextbits, nextdata, nbitsmask;
+ code_t *codep, *free_entp, *maxcodep, *oldcodep;
+
+ (void) s;
+ assert(sp != NULL);
+ /*
+ * Restart interrupted output operation.
+ */
+ if (sp->dec_restart) {
+ long residue;
+
+ codep = sp->dec_codep;
+ residue = codep->length - sp->dec_restart;
+ if (residue > occ) {
+ /*
+ * Residue from previous decode is sufficient
+ * to satisfy decode request. Skip to the
+ * start of the decoded string, place decoded
+ * values in the output buffer, and return.
+ */
+ sp->dec_restart += occ;
+ do {
+ codep = codep->next;
+ } while (--residue > occ);
+ tp = op + occ;
+ do {
+ *--tp = codep->value;
+ codep = codep->next;
+ } while (--occ);
+ return (1);
+ }
+ /*
+ * Residue satisfies only part of the decode request.
+ */
+ op += residue, occ -= residue;
+ tp = op;
+ do {
+ *--tp = codep->value;
+ codep = codep->next;
+ } while (--residue);
+ sp->dec_restart = 0;
+ }
+
+ bp = (unsigned char *)tif->tif_rawcp;
+ nbits = sp->lzw_nbits;
+ nextdata = sp->lzw_nextdata;
+ nextbits = sp->lzw_nextbits;
+ nbitsmask = sp->dec_nbitsmask;
+ oldcodep = sp->dec_oldcodep;
+ free_entp = sp->dec_free_entp;
+ maxcodep = sp->dec_maxcodep;
+
+ while (occ > 0) {
+ NextCode(tif, sp, bp, code, GetNextCodeCompat);
+ if (code == CODE_EOI)
+ break;
+ if (code == CODE_CLEAR) {
+ free_entp = sp->dec_codetab + CODE_FIRST;
+ _TIFFmemset(free_entp, 0,
+ (CSIZE - CODE_FIRST) * sizeof (code_t));
+ nbits = BITS_MIN;
+ nbitsmask = MAXCODE(BITS_MIN);
+ maxcodep = sp->dec_codetab + nbitsmask;
+ NextCode(tif, sp, bp, code, GetNextCodeCompat);
+ if (code == CODE_EOI)
+ break;
+ if (code == CODE_CLEAR) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecode: Corrupted LZW table at scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+ *op++ = code, occ--;
+ oldcodep = sp->dec_codetab + code;
+ continue;
+ }
+ codep = sp->dec_codetab + code;
+
+ /*
+ * Add the new entry to the code table.
+ */
+ if (free_entp < &sp->dec_codetab[0] ||
+ free_entp >= &sp->dec_codetab[CSIZE]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecodeCompat: Corrupted LZW table at scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+
+ free_entp->next = oldcodep;
+ if (free_entp->next < &sp->dec_codetab[0] ||
+ free_entp->next >= &sp->dec_codetab[CSIZE]) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecodeCompat: Corrupted LZW table at scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+ free_entp->firstchar = free_entp->next->firstchar;
+ free_entp->length = free_entp->next->length+1;
+ free_entp->value = (codep < free_entp) ?
+ codep->firstchar : free_entp->firstchar;
+ if (++free_entp > maxcodep) {
+ if (++nbits > BITS_MAX) /* should not happen */
+ nbits = BITS_MAX;
+ nbitsmask = MAXCODE(nbits);
+ maxcodep = sp->dec_codetab + nbitsmask;
+ }
+ oldcodep = codep;
+ if (code >= 256) {
+ char *op_orig = op;
+ /*
+ * Code maps to a string, copy string
+ * value to output (written in reverse).
+ */
+ if(codep->length == 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecodeCompat: Wrong length of decoded "
+ "string: data probably corrupted at scanline %d",
+ tif->tif_row);
+ return (0);
+ }
+ if (codep->length > occ) {
+ /*
+ * String is too long for decode buffer,
+ * locate portion that will fit, copy to
+ * the decode buffer, and setup restart
+ * logic for the next decoding call.
+ */
+ sp->dec_codep = codep;
+ do {
+ codep = codep->next;
+ } while (codep->length > occ);
+ sp->dec_restart = occ;
+ tp = op + occ;
+ do {
+ *--tp = codep->value;
+ codep = codep->next;
+ } while (--occ);
+ break;
+ }
+ op += codep->length, occ -= codep->length;
+ tp = op;
+ do {
+ *--tp = codep->value;
+ } while( (codep = codep->next) != NULL && tp > op_orig);
+ } else
+ *op++ = code, occ--;
+ }
+
+ tif->tif_rawcp = (tidata_t) bp;
+ sp->lzw_nbits = nbits;
+ sp->lzw_nextdata = nextdata;
+ sp->lzw_nextbits = nextbits;
+ sp->dec_nbitsmask = nbitsmask;
+ sp->dec_oldcodep = oldcodep;
+ sp->dec_free_entp = free_entp;
+ sp->dec_maxcodep = maxcodep;
+
+ if (occ > 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "LZWDecodeCompat: Not enough data at scanline %d (short %ld bytes)",
+ tif->tif_row, occ);
+ return (0);
+ }
+ return (1);
+}
+#endif /* LZW_COMPAT */
+
+/*
+ * LZW Encoding.
+ */
+
+static int
+LZWSetupEncode(TIFF* tif)
+{
+ LZWCodecState* sp = EncoderState(tif);
+ static const char module[] = "LZWSetupEncode";
+
+ assert(sp != NULL);
+ sp->enc_hashtab = (hash_t*) _TIFFmalloc(HSIZE*sizeof (hash_t));
+ if (sp->enc_hashtab == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, module, "No space for LZW hash table");
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+LZWPreEncode(TIFF* tif, tsample_t s)
+{
+ LZWCodecState *sp = EncoderState(tif);
+
+ (void) s;
+ assert(sp != NULL);
+
+ if( sp->enc_hashtab == NULL )
+ {
+ tif->tif_setupencode( tif );
+ }
+
+ sp->lzw_nbits = BITS_MIN;
+ sp->lzw_maxcode = MAXCODE(BITS_MIN);
+ sp->lzw_free_ent = CODE_FIRST;
+ sp->lzw_nextbits = 0;
+ sp->lzw_nextdata = 0;
+ sp->enc_checkpoint = CHECK_GAP;
+ sp->enc_ratio = 0;
+ sp->enc_incount = 0;
+ sp->enc_outcount = 0;
+ /*
+ * The 4 here insures there is space for 2 max-sized
+ * codes in LZWEncode and LZWPostDecode.
+ */
+ sp->enc_rawlimit = tif->tif_rawdata + tif->tif_rawdatasize-1 - 4;
+ cl_hash(sp); /* clear hash table */
+ sp->enc_oldcode = (hcode_t) -1; /* generates CODE_CLEAR in LZWEncode */
+ return (1);
+}
+
+#define CALCRATIO(sp, rat) { \
+ if (incount > 0x007fffff) { /* NB: shift will overflow */\
+ rat = outcount >> 8; \
+ rat = (rat == 0 ? 0x7fffffff : incount/rat); \
+ } else \
+ rat = (incount<<8) / outcount; \
+}
+#define PutNextCode(op, c) { \
+ nextdata = (nextdata << nbits) | c; \
+ nextbits += nbits; \
+ *op++ = (unsigned char)(nextdata >> (nextbits-8)); \
+ nextbits -= 8; \
+ if (nextbits >= 8) { \
+ *op++ = (unsigned char)(nextdata >> (nextbits-8)); \
+ nextbits -= 8; \
+ } \
+ outcount += nbits; \
+}
+
+/*
+ * Encode a chunk of pixels.
+ *
+ * Uses an open addressing double hashing (no chaining) on the
+ * prefix code/next character combination. We do a variant of
+ * Knuth's algorithm D (vol. 3, sec. 6.4) along with G. Knott's
+ * relatively-prime secondary probe. Here, the modular division
+ * first probe is gives way to a faster exclusive-or manipulation.
+ * Also do block compression with an adaptive reset, whereby the
+ * code table is cleared when the compression ratio decreases,
+ * but after the table fills. The variable-length output codes
+ * are re-sized at this point, and a CODE_CLEAR is generated
+ * for the decoder.
+ */
+static int
+LZWEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ register LZWCodecState *sp = EncoderState(tif);
+ register long fcode;
+ register hash_t *hp;
+ register int h, c;
+ hcode_t ent;
+ long disp;
+ long incount, outcount, checkpoint;
+ long nextdata, nextbits;
+ int free_ent, maxcode, nbits;
+ tidata_t op, limit;
+
+ (void) s;
+ if (sp == NULL)
+ return (0);
+
+ assert(sp->enc_hashtab != NULL);
+
+ /*
+ * Load local state.
+ */
+ incount = sp->enc_incount;
+ outcount = sp->enc_outcount;
+ checkpoint = sp->enc_checkpoint;
+ nextdata = sp->lzw_nextdata;
+ nextbits = sp->lzw_nextbits;
+ free_ent = sp->lzw_free_ent;
+ maxcode = sp->lzw_maxcode;
+ nbits = sp->lzw_nbits;
+ op = tif->tif_rawcp;
+ limit = sp->enc_rawlimit;
+ ent = sp->enc_oldcode;
+
+ if (ent == (hcode_t) -1 && cc > 0) {
+ /*
+ * NB: This is safe because it can only happen
+ * at the start of a strip where we know there
+ * is space in the data buffer.
+ */
+ PutNextCode(op, CODE_CLEAR);
+ ent = *bp++; cc--; incount++;
+ }
+ while (cc > 0) {
+ c = *bp++; cc--; incount++;
+ fcode = ((long)c << BITS_MAX) + ent;
+ h = (c << HSHIFT) ^ ent; /* xor hashing */
+#ifdef _WINDOWS
+ /*
+ * Check hash index for an overflow.
+ */
+ if (h >= HSIZE)
+ h -= HSIZE;
+#endif
+ hp = &sp->enc_hashtab[h];
+ if (hp->hash == fcode) {
+ ent = hp->code;
+ continue;
+ }
+ if (hp->hash >= 0) {
+ /*
+ * Primary hash failed, check secondary hash.
+ */
+ disp = HSIZE - h;
+ if (h == 0)
+ disp = 1;
+ do {
+ /*
+ * Avoid pointer arithmetic 'cuz of
+ * wraparound problems with segments.
+ */
+ if ((h -= disp) < 0)
+ h += HSIZE;
+ hp = &sp->enc_hashtab[h];
+ if (hp->hash == fcode) {
+ ent = hp->code;
+ goto hit;
+ }
+ } while (hp->hash >= 0);
+ }
+ /*
+ * New entry, emit code and add to table.
+ */
+ /*
+ * Verify there is space in the buffer for the code
+ * and any potential Clear code that might be emitted
+ * below. The value of limit is setup so that there
+ * are at least 4 bytes free--room for 2 codes.
+ */
+ if (op > limit) {
+ tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata);
+ TIFFFlushData1(tif);
+ op = tif->tif_rawdata;
+ }
+ PutNextCode(op, ent);
+ ent = c;
+ hp->code = free_ent++;
+ hp->hash = fcode;
+ if (free_ent == CODE_MAX-1) {
+ /* table is full, emit clear code and reset */
+ cl_hash(sp);
+ sp->enc_ratio = 0;
+ incount = 0;
+ outcount = 0;
+ free_ent = CODE_FIRST;
+ PutNextCode(op, CODE_CLEAR);
+ nbits = BITS_MIN;
+ maxcode = MAXCODE(BITS_MIN);
+ } else {
+ /*
+ * If the next entry is going to be too big for
+ * the code size, then increase it, if possible.
+ */
+ if (free_ent > maxcode) {
+ nbits++;
+ assert(nbits <= BITS_MAX);
+ maxcode = (int) MAXCODE(nbits);
+ } else if (incount >= checkpoint) {
+ long rat;
+ /*
+ * Check compression ratio and, if things seem
+ * to be slipping, clear the hash table and
+ * reset state. The compression ratio is a
+ * 24+8-bit fractional number.
+ */
+ checkpoint = incount+CHECK_GAP;
+ CALCRATIO(sp, rat);
+ if (rat <= sp->enc_ratio) {
+ cl_hash(sp);
+ sp->enc_ratio = 0;
+ incount = 0;
+ outcount = 0;
+ free_ent = CODE_FIRST;
+ PutNextCode(op, CODE_CLEAR);
+ nbits = BITS_MIN;
+ maxcode = MAXCODE(BITS_MIN);
+ } else
+ sp->enc_ratio = rat;
+ }
+ }
+ hit:
+ ;
+ }
+
+ /*
+ * Restore global state.
+ */
+ sp->enc_incount = incount;
+ sp->enc_outcount = outcount;
+ sp->enc_checkpoint = checkpoint;
+ sp->enc_oldcode = ent;
+ sp->lzw_nextdata = nextdata;
+ sp->lzw_nextbits = nextbits;
+ sp->lzw_free_ent = free_ent;
+ sp->lzw_maxcode = maxcode;
+ sp->lzw_nbits = nbits;
+ tif->tif_rawcp = op;
+ return (1);
+}
+
+/*
+ * Finish off an encoded strip by flushing the last
+ * string and tacking on an End Of Information code.
+ */
+static int
+LZWPostEncode(TIFF* tif)
+{
+ register LZWCodecState *sp = EncoderState(tif);
+ tidata_t op = tif->tif_rawcp;
+ long nextbits = sp->lzw_nextbits;
+ long nextdata = sp->lzw_nextdata;
+ long outcount = sp->enc_outcount;
+ int nbits = sp->lzw_nbits;
+
+ if (op > sp->enc_rawlimit) {
+ tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata);
+ TIFFFlushData1(tif);
+ op = tif->tif_rawdata;
+ }
+ if (sp->enc_oldcode != (hcode_t) -1) {
+ PutNextCode(op, sp->enc_oldcode);
+ sp->enc_oldcode = (hcode_t) -1;
+ }
+ PutNextCode(op, CODE_EOI);
+ if (nextbits > 0)
+ *op++ = (unsigned char)(nextdata << (8-nextbits));
+ tif->tif_rawcc = (tsize_t)(op - tif->tif_rawdata);
+ return (1);
+}
+
+/*
+ * Reset encoding hash table.
+ */
+static void
+cl_hash(LZWCodecState* sp)
+{
+ register hash_t *hp = &sp->enc_hashtab[HSIZE-1];
+ register long i = HSIZE-8;
+
+ do {
+ i -= 8;
+ hp[-7].hash = -1;
+ hp[-6].hash = -1;
+ hp[-5].hash = -1;
+ hp[-4].hash = -1;
+ hp[-3].hash = -1;
+ hp[-2].hash = -1;
+ hp[-1].hash = -1;
+ hp[ 0].hash = -1;
+ hp -= 8;
+ } while (i >= 0);
+ for (i += 8; i > 0; i--, hp--)
+ hp->hash = -1;
+}
+
+static void
+LZWCleanup(TIFF* tif)
+{
+ (void)TIFFPredictorCleanup(tif);
+
+ assert(tif->tif_data != 0);
+
+ if (DecoderState(tif)->dec_codetab)
+ _TIFFfree(DecoderState(tif)->dec_codetab);
+
+ if (EncoderState(tif)->enc_hashtab)
+ _TIFFfree(EncoderState(tif)->enc_hashtab);
+
+ _TIFFfree(tif->tif_data);
+ tif->tif_data = NULL;
+
+ _TIFFSetDefaultCompressionState(tif);
+}
+
+int
+TIFFInitLZW(TIFF* tif, int scheme)
+{
+ assert(scheme == COMPRESSION_LZW);
+ /*
+ * Allocate state block so tag methods have storage to record values.
+ */
+ tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (LZWCodecState));
+ if (tif->tif_data == NULL)
+ goto bad;
+ DecoderState(tif)->dec_codetab = NULL;
+ DecoderState(tif)->dec_decode = NULL;
+ EncoderState(tif)->enc_hashtab = NULL;
+ LZWState(tif)->rw_mode = tif->tif_mode;
+
+ /*
+ * Install codec methods.
+ */
+ tif->tif_setupdecode = LZWSetupDecode;
+ tif->tif_predecode = LZWPreDecode;
+ tif->tif_decoderow = LZWDecode;
+ tif->tif_decodestrip = LZWDecode;
+ tif->tif_decodetile = LZWDecode;
+ tif->tif_setupencode = LZWSetupEncode;
+ tif->tif_preencode = LZWPreEncode;
+ tif->tif_postencode = LZWPostEncode;
+ tif->tif_encoderow = LZWEncode;
+ tif->tif_encodestrip = LZWEncode;
+ tif->tif_encodetile = LZWEncode;
+ tif->tif_cleanup = LZWCleanup;
+ /*
+ * Setup predictor setup.
+ */
+ (void) TIFFPredictorInit(tif);
+ return (1);
+bad:
+ TIFFErrorExt(tif->tif_clientdata, "TIFFInitLZW",
+ "No space for LZW state block");
+ return (0);
+}
+
+/*
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+#endif /* LZW_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_msdos.c b/tiff/libtiff/tif_msdos.c
new file mode 100644
index 0000000..6ddbfcd
--- /dev/null
+++ b/tiff/libtiff/tif_msdos.c
@@ -0,0 +1,193 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/Attic/tif_msdos.c,v 1.3.2.1 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library MSDOS-specific Routines.
+ */
+#if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_MSC_VER)
+#include <io.h> /* for open, close, etc. function prototypes */
+#include <stdio.h>
+#endif
+#include "tiffiop.h"
+
+static tsize_t
+_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return (read((int) fd, buf, size));
+}
+
+static tsize_t
+_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return (write((int) fd, buf, size));
+}
+
+static toff_t
+_tiffSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ return (lseek((int) fd, (off_t) off, whence));
+}
+
+static int
+_tiffCloseProc(thandle_t fd)
+{
+ return (close((int) fd));
+}
+
+#include <sys/stat.h>
+
+static toff_t
+_tiffSizeProc(thandle_t fd)
+{
+ struct stat sb;
+ return (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size);
+}
+
+static int
+_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ return (0);
+}
+
+static void
+_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+}
+
+/*
+ * Open a TIFF file descriptor for read/writing.
+ */
+TIFF*
+TIFFFdOpen(int fd, const char* name, const char* mode)
+{
+ TIFF* tif;
+
+ tif = TIFFClientOpen(name, mode,
+ (void*) fd,
+ _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
+ _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
+ if (tif)
+ tif->tif_fd = fd;
+ return (tif);
+}
+
+/*
+ * Open a TIFF file for read/writing.
+ */
+TIFF*
+TIFFOpen(const char* name, const char* mode)
+{
+ static const char module[] = "TIFFOpen";
+ int m, fd;
+ TIFF *ret;
+
+ m = _TIFFgetMode(mode, module);
+ if (m == -1)
+ return ((TIFF*)0);
+ fd = open(name, m|O_BINARY, 0666);
+ if (fd < 0) {
+ TIFFErrorExt(0, module, "%s: Cannot open", name);
+ return ((TIFF*)0);
+ }
+ return (TIFFFdOpen(fd, name, mode));
+
+ ret = TIFFFdOpen(fd, name, mode);
+
+ if (ret == NULL) close(fd);
+
+ return ret;
+}
+
+#ifdef __GNUC__
+extern char* malloc();
+extern char* realloc();
+#else
+#include <malloc.h>
+#endif
+
+tdata_t
+_TIFFmalloc(tsize_t s)
+{
+ return (malloc((size_t) s));
+}
+
+void
+_TIFFfree(tdata_t p)
+{
+ free(p);
+}
+
+tdata_t
+_TIFFrealloc(tdata_t p, tsize_t s)
+{
+ return (realloc(p, (size_t) s));
+}
+
+void
+_TIFFmemset(tdata_t p, int v, tsize_t c)
+{
+ memset(p, v, (size_t) c);
+}
+
+void
+_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
+{
+ memcpy(d, s, (size_t) c);
+}
+
+int
+_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)
+{
+ return (memcmp(p1, p2, (size_t) c));
+}
+
+static void
+msdosWarningHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ fprintf(stderr, "Warning, ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFwarningHandler = msdosWarningHandler;
+
+static void
+msdosErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFerrorHandler = msdosErrorHandler;
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_next.c b/tiff/libtiff/tif_next.c
new file mode 100644
index 0000000..d7652bb
--- /dev/null
+++ b/tiff/libtiff/tif_next.c
@@ -0,0 +1,154 @@
+/* $Id: tif_next.c,v 1.8.2.1 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef NEXT_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * NeXT 2-bit Grey Scale Compression Algorithm Support
+ */
+
+#define SETPIXEL(op, v) { \
+ switch (npixels++ & 3) { \
+ case 0: op[0] = (unsigned char) ((v) << 6); break; \
+ case 1: op[0] |= (v) << 4; break; \
+ case 2: op[0] |= (v) << 2; break; \
+ case 3: *op++ |= (v); break; \
+ } \
+}
+
+#define LITERALROW 0x00
+#define LITERALSPAN 0x40
+#define WHITE ((1<<2)-1)
+
+static int
+NeXTDecode(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s)
+{
+ unsigned char *bp, *op;
+ tsize_t cc;
+ tidata_t row;
+ tsize_t scanline, n;
+
+ (void) s;
+ /*
+ * Each scanline is assumed to start off as all
+ * white (we assume a PhotometricInterpretation
+ * of ``min-is-black'').
+ */
+ for (op = buf, cc = occ; cc-- > 0;)
+ *op++ = 0xff;
+
+ bp = (unsigned char *)tif->tif_rawcp;
+ cc = tif->tif_rawcc;
+ scanline = tif->tif_scanlinesize;
+ for (row = buf; occ > 0; occ -= scanline, row += scanline) {
+ n = *bp++, cc--;
+ switch (n) {
+ case LITERALROW:
+ /*
+ * The entire scanline is given as literal values.
+ */
+ if (cc < scanline)
+ goto bad;
+ _TIFFmemcpy(row, bp, scanline);
+ bp += scanline;
+ cc -= scanline;
+ break;
+ case LITERALSPAN: {
+ tsize_t off;
+ /*
+ * The scanline has a literal span that begins at some
+ * offset.
+ */
+ off = (bp[0] * 256) + bp[1];
+ n = (bp[2] * 256) + bp[3];
+ if (cc < 4+n || off+n > scanline)
+ goto bad;
+ _TIFFmemcpy(row+off, bp+4, n);
+ bp += 4+n;
+ cc -= 4+n;
+ break;
+ }
+ default: {
+ uint32 npixels = 0, grey;
+ uint32 imagewidth = tif->tif_dir.td_imagewidth;
+
+ /*
+ * The scanline is composed of a sequence of constant
+ * color ``runs''. We shift into ``run mode'' and
+ * interpret bytes as codes of the form
+ * <color><npixels> until we've filled the scanline.
+ */
+ op = row;
+ for (;;) {
+ grey = (n>>6) & 0x3;
+ n &= 0x3f;
+ /*
+ * Ensure the run does not exceed the scanline
+ * bounds, potentially resulting in a security
+ * issue.
+ */
+ while (n-- > 0 && npixels < imagewidth)
+ SETPIXEL(op, grey);
+ if (npixels >= imagewidth)
+ break;
+ if (cc == 0)
+ goto bad;
+ n = *bp++, cc--;
+ }
+ break;
+ }
+ }
+ }
+ tif->tif_rawcp = (tidata_t) bp;
+ tif->tif_rawcc = cc;
+ return (1);
+bad:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "NeXTDecode: Not enough data for scanline %ld",
+ (long) tif->tif_row);
+ return (0);
+}
+
+int
+TIFFInitNeXT(TIFF* tif, int scheme)
+{
+ (void) scheme;
+ tif->tif_decoderow = NeXTDecode;
+ tif->tif_decodestrip = NeXTDecode;
+ tif->tif_decodetile = NeXTDecode;
+ return (1);
+}
+#endif /* NEXT_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_ojpeg.c b/tiff/libtiff/tif_ojpeg.c
new file mode 100644
index 0000000..9ae856c
--- /dev/null
+++ b/tiff/libtiff/tif_ojpeg.c
@@ -0,0 +1,2438 @@
+/* $Id: tif_ojpeg.c,v 1.24.2.6 2010-06-08 23:29:51 bfriesen Exp $ */
+
+/* WARNING: The type of JPEG encapsulation defined by the TIFF Version 6.0
+ specification is now totally obsolete and deprecated for new applications and
+ images. This file was was created solely in order to read unconverted images
+ still present on some users' computer systems. It will never be extended
+ to write such files. Writing new-style JPEG compressed TIFFs is implemented
+ in tif_jpeg.c.
+
+ The code is carefully crafted to robustly read all gathered JPEG-in-TIFF
+ testfiles, and anticipate as much as possible all other... But still, it may
+ fail on some. If you encounter problems, please report them on the TIFF
+ mailing list and/or to Joris Van Damme <info@awaresystems.be>.
+
+ Please read the file called "TIFF Technical Note #2" if you need to be
+ convinced this compression scheme is bad and breaks TIFF. That document
+ is linked to from the LibTiff site <http://www.remotesensing.org/libtiff/>
+ and from AWare Systems' TIFF section
+ <http://www.awaresystems.be/imaging/tiff.html>. It is also absorbed
+ in Adobe's specification supplements, marked "draft" up to this day, but
+ supported by the TIFF community.
+
+ This file interfaces with Release 6B of the JPEG Library written by the
+ Independent JPEG Group. Previous versions of this file required a hack inside
+ the LibJpeg library. This version no longer requires that. Remember to
+ remove the hack if you update from the old version.
+
+ Copyright (c) Joris Van Damme <info@awaresystems.be>
+ Copyright (c) AWare Systems <http://www.awaresystems.be/>
+
+ The licence agreement for this file is the same as the rest of the LibTiff
+ library.
+
+ IN NO EVENT SHALL JORIS VAN DAMME OR AWARE SYSTEMS BE LIABLE FOR
+ ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ OF THIS SOFTWARE.
+
+ Joris Van Damme and/or AWare Systems may be available for custom
+ developement. If you like what you see, and need anything similar or related,
+ contact <info@awaresystems.be>.
+*/
+
+/* What is what, and what is not?
+
+ This decoder starts with an input stream, that is essentially the JpegInterchangeFormat
+ stream, if any, followed by the strile data, if any. This stream is read in
+ OJPEGReadByte and related functions.
+
+ It analyzes the start of this stream, until it encounters non-marker data, i.e.
+ compressed image data. Some of the header markers it sees have no actual content,
+ like the SOI marker, and APP/COM markers that really shouldn't even be there. Some
+ other markers do have content, and the valuable bits and pieces of information
+ in these markers are saved, checking all to verify that the stream is more or
+ less within expected bounds. This happens inside the OJPEGReadHeaderInfoSecStreamXxx
+ functions.
+
+ Some OJPEG imagery contains no valid JPEG header markers. This situation is picked
+ up on if we've seen no SOF marker when we're at the start of the compressed image
+ data. In this case, the tables are read from JpegXxxTables tags, and the other
+ bits and pieces of information is initialized to its most basic value. This is
+ implemented in the OJPEGReadHeaderInfoSecTablesXxx functions.
+
+ When this is complete, a good and valid JPEG header can be assembled, and this is
+ passed through to LibJpeg. When that's done, the remainder of the input stream, i.e.
+ the compressed image data, can be passed through unchanged. This is done in
+ OJPEGWriteStream functions.
+
+ LibTiff rightly expects to know the subsampling values before decompression. Just like
+ in new-style JPEG-in-TIFF, though, or even more so, actually, the YCbCrsubsampling
+ tag is notoriously unreliable. To correct these tag values with the ones inside
+ the JPEG stream, the first part of the input stream is pre-scanned in
+ OJPEGSubsamplingCorrect, making no note of any other data, reporting no warnings
+ or errors, up to the point where either these values are read, or it's clear they
+ aren't there. This means that some of the data is read twice, but we feel speed
+ in correcting these values is important enough to warrant this sacrifice. Allthough
+ there is currently no define or other configuration mechanism to disable this behaviour,
+ the actual header scanning is build to robustly respond with error report if it
+ should encounter an uncorrected mismatch of subsampling values. See
+ OJPEGReadHeaderInfoSecStreamSof.
+
+ The restart interval and restart markers are the most tricky part... The restart
+ interval can be specified in a tag. It can also be set inside the input JPEG stream.
+ It can be used inside the input JPEG stream. If reading from strile data, we've
+ consistenly discovered the need to insert restart markers in between the different
+ striles, as is also probably the most likely interpretation of the original TIFF 6.0
+ specification. With all this setting of interval, and actual use of markers that is not
+ predictable at the time of valid JPEG header assembly, the restart thing may turn
+ out the Achilles heel of this implementation. Fortunately, most OJPEG writer vendors
+ succeed in reading back what they write, which may be the reason why we've been able
+ to discover ways that seem to work.
+
+ Some special provision is made for planarconfig separate OJPEG files. These seem
+ to consistently contain header info, a SOS marker, a plane, SOS marker, plane, SOS,
+ and plane. This may or may not be a valid JPEG configuration, we don't know and don't
+ care. We want LibTiff to be able to access the planes individually, without huge
+ buffering inside LibJpeg, anyway. So we compose headers to feed to LibJpeg, in this
+ case, that allow us to pass a single plane such that LibJpeg sees a valid
+ single-channel JPEG stream. Locating subsequent SOS markers, and thus subsequent
+ planes, is done inside OJPEGReadSecondarySos.
+
+ The benefit of the scheme is... that it works, basically. We know of no other that
+ does. It works without checking software tag, or otherwise going about things in an
+ OJPEG flavor specific manner. Instead, it is a single scheme, that covers the cases
+ with and without JpegInterchangeFormat, with and without striles, with part of
+ the header in JpegInterchangeFormat and remainder in first strile, etc. It is forgiving
+ and robust, may likely work with OJPEG flavors we've not seen yet, and makes most out
+ of the data.
+
+ Another nice side-effect is that a complete JPEG single valid stream is build if
+ planarconfig is not separate (vast majority). We may one day use that to build
+ converters to JPEG, and/or to new-style JPEG compression inside TIFF.
+
+ A dissadvantage is the lack of random access to the individual striles. This is the
+ reason for much of the complicated restart-and-position stuff inside OJPEGPreDecode.
+ Applications would do well accessing all striles in order, as this will result in
+ a single sequential scan of the input stream, and no restarting of LibJpeg decoding
+ session.
+*/
+
+
+#include "tiffiop.h"
+#ifdef OJPEG_SUPPORT
+
+/* Configuration defines here are:
+ * JPEG_ENCAP_EXTERNAL: The normal way to call libjpeg, uses longjump. In some environments,
+ * like eg LibTiffDelphi, this is not possible. For this reason, the actual calls to
+ * libjpeg, with longjump stuff, are encapsulated in dedicated functions. When
+ * JPEG_ENCAP_EXTERNAL is defined, these encapsulating functions are declared external
+ * to this unit, and can be defined elsewhere to use stuff other then longjump.
+ * The default mode, without JPEG_ENCAP_EXTERNAL, implements the call encapsulators
+ * here, internally, with normal longjump.
+ * SETJMP, LONGJMP, JMP_BUF: On some machines/environments a longjump equivalent is
+ * conviniently available, but still it may be worthwhile to use _setjmp or sigsetjmp
+ * in place of plain setjmp. These macros will make it easier. It is useless
+ * to fiddle with these if you define JPEG_ENCAP_EXTERNAL.
+ * OJPEG_BUFFER: Define the size of the desired buffer here. Should be small enough so as to guarantee
+ * instant processing, optimal streaming and optimal use of processor cache, but also big
+ * enough so as to not result in significant call overhead. It should be at least a few
+ * bytes to accomodate some structures (this is verified in asserts), but it would not be
+ * sensible to make it this small anyway, and it should be at most 64K since it is indexed
+ * with uint16. We recommend 2K.
+ * EGYPTIANWALK: You could also define EGYPTIANWALK here, but it is not used anywhere and has
+ * absolutely no effect. That is why most people insist the EGYPTIANWALK is a bit silly.
+ */
+
+/* #define LIBJPEG_ENCAP_EXTERNAL */
+#define SETJMP(jbuf) setjmp(jbuf)
+#define LONGJMP(jbuf,code) longjmp(jbuf,code)
+#define JMP_BUF jmp_buf
+#define OJPEG_BUFFER 2048
+/* define EGYPTIANWALK */
+
+#define JPEG_MARKER_SOF0 0xC0
+#define JPEG_MARKER_SOF1 0xC1
+#define JPEG_MARKER_SOF3 0xC3
+#define JPEG_MARKER_DHT 0xC4
+#define JPEG_MARKER_RST0 0XD0
+#define JPEG_MARKER_SOI 0xD8
+#define JPEG_MARKER_EOI 0xD9
+#define JPEG_MARKER_SOS 0xDA
+#define JPEG_MARKER_DQT 0xDB
+#define JPEG_MARKER_DRI 0xDD
+#define JPEG_MARKER_APP0 0xE0
+#define JPEG_MARKER_COM 0xFE
+
+#define FIELD_OJPEG_JPEGINTERCHANGEFORMAT (FIELD_CODEC+0)
+#define FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH (FIELD_CODEC+1)
+#define FIELD_OJPEG_JPEGQTABLES (FIELD_CODEC+2)
+#define FIELD_OJPEG_JPEGDCTABLES (FIELD_CODEC+3)
+#define FIELD_OJPEG_JPEGACTABLES (FIELD_CODEC+4)
+#define FIELD_OJPEG_JPEGPROC (FIELD_CODEC+5)
+#define FIELD_OJPEG_JPEGRESTARTINTERVAL (FIELD_CODEC+6)
+#define FIELD_OJPEG_COUNT 7
+
+static const TIFFFieldInfo ojpeg_field_info[] = {
+ {TIFFTAG_JPEGIFOFFSET,1,1,TIFF_LONG,FIELD_OJPEG_JPEGINTERCHANGEFORMAT,TRUE,FALSE,"JpegInterchangeFormat"},
+ {TIFFTAG_JPEGIFBYTECOUNT,1,1,TIFF_LONG,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH,TRUE,FALSE,"JpegInterchangeFormatLength"},
+ {TIFFTAG_JPEGQTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGQTABLES,FALSE,TRUE,"JpegQTables"},
+ {TIFFTAG_JPEGDCTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGDCTABLES,FALSE,TRUE,"JpegDcTables"},
+ {TIFFTAG_JPEGACTABLES,TIFF_VARIABLE,TIFF_VARIABLE,TIFF_LONG,FIELD_OJPEG_JPEGACTABLES,FALSE,TRUE,"JpegAcTables"},
+ {TIFFTAG_JPEGPROC,1,1,TIFF_SHORT,FIELD_OJPEG_JPEGPROC,FALSE,FALSE,"JpegProc"},
+ {TIFFTAG_JPEGRESTARTINTERVAL,1,1,TIFF_SHORT,FIELD_OJPEG_JPEGRESTARTINTERVAL,FALSE,FALSE,"JpegRestartInterval"},
+};
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+#include <setjmp.h>
+#endif
+
+#include "jpeglib.h"
+#include "jerror.h"
+
+typedef struct jpeg_error_mgr jpeg_error_mgr;
+typedef struct jpeg_common_struct jpeg_common_struct;
+typedef struct jpeg_decompress_struct jpeg_decompress_struct;
+typedef struct jpeg_source_mgr jpeg_source_mgr;
+
+typedef enum {
+ osibsNotSetYet,
+ osibsJpegInterchangeFormat,
+ osibsStrile,
+ osibsEof
+} OJPEGStateInBufferSource;
+
+typedef enum {
+ ososSoi,
+ ososQTable0,ososQTable1,ososQTable2,ososQTable3,
+ ososDcTable0,ososDcTable1,ososDcTable2,ososDcTable3,
+ ososAcTable0,ososAcTable1,ososAcTable2,ososAcTable3,
+ ososDri,
+ ososSof,
+ ososSos,
+ ososCompressed,
+ ososRst,
+ ososEoi
+} OJPEGStateOutState;
+
+typedef struct {
+ TIFF* tif;
+ #ifndef LIBJPEG_ENCAP_EXTERNAL
+ JMP_BUF exit_jmpbuf;
+ #endif
+ TIFFVGetMethod vgetparent;
+ TIFFVSetMethod vsetparent;
+ toff_t file_size;
+ uint32 image_width;
+ uint32 image_length;
+ uint32 strile_width;
+ uint32 strile_length;
+ uint32 strile_length_total;
+ uint8 samples_per_pixel;
+ uint8 plane_sample_offset;
+ uint8 samples_per_pixel_per_plane;
+ toff_t jpeg_interchange_format;
+ toff_t jpeg_interchange_format_length;
+ uint8 jpeg_proc;
+ uint8 subsamplingcorrect;
+ uint8 subsamplingcorrect_done;
+ uint8 subsampling_tag;
+ uint8 subsampling_hor;
+ uint8 subsampling_ver;
+ uint8 subsampling_force_desubsampling_inside_decompression;
+ uint8 qtable_offset_count;
+ uint8 dctable_offset_count;
+ uint8 actable_offset_count;
+ toff_t qtable_offset[3];
+ toff_t dctable_offset[3];
+ toff_t actable_offset[3];
+ uint8* qtable[4];
+ uint8* dctable[4];
+ uint8* actable[4];
+ uint16 restart_interval;
+ uint8 restart_index;
+ uint8 sof_log;
+ uint8 sof_marker_id;
+ uint32 sof_x;
+ uint32 sof_y;
+ uint8 sof_c[3];
+ uint8 sof_hv[3];
+ uint8 sof_tq[3];
+ uint8 sos_cs[3];
+ uint8 sos_tda[3];
+ struct {
+ uint8 log;
+ OJPEGStateInBufferSource in_buffer_source;
+ tstrile_t in_buffer_next_strile;
+ toff_t in_buffer_file_pos;
+ toff_t in_buffer_file_togo;
+ } sos_end[3];
+ uint8 readheader_done;
+ uint8 writeheader_done;
+ tsample_t write_cursample;
+ tstrile_t write_curstrile;
+ uint8 libjpeg_session_active;
+ uint8 libjpeg_jpeg_query_style;
+ jpeg_error_mgr libjpeg_jpeg_error_mgr;
+ jpeg_decompress_struct libjpeg_jpeg_decompress_struct;
+ jpeg_source_mgr libjpeg_jpeg_source_mgr;
+ uint8 subsampling_convert_log;
+ uint32 subsampling_convert_ylinelen;
+ uint32 subsampling_convert_ylines;
+ uint32 subsampling_convert_clinelen;
+ uint32 subsampling_convert_clines;
+ uint32 subsampling_convert_ybuflen;
+ uint32 subsampling_convert_cbuflen;
+ uint32 subsampling_convert_ycbcrbuflen;
+ uint8* subsampling_convert_ycbcrbuf;
+ uint8* subsampling_convert_ybuf;
+ uint8* subsampling_convert_cbbuf;
+ uint8* subsampling_convert_crbuf;
+ uint32 subsampling_convert_ycbcrimagelen;
+ uint8** subsampling_convert_ycbcrimage;
+ uint32 subsampling_convert_clinelenout;
+ uint32 subsampling_convert_state;
+ uint32 bytes_per_line; /* if the codec outputs subsampled data, a 'line' in bytes_per_line */
+ uint32 lines_per_strile; /* and lines_per_strile means subsampling_ver desubsampled rows */
+ OJPEGStateInBufferSource in_buffer_source;
+ tstrile_t in_buffer_next_strile;
+ tstrile_t in_buffer_strile_count;
+ toff_t in_buffer_file_pos;
+ uint8 in_buffer_file_pos_log;
+ toff_t in_buffer_file_togo;
+ uint16 in_buffer_togo;
+ uint8* in_buffer_cur;
+ uint8 in_buffer[OJPEG_BUFFER];
+ OJPEGStateOutState out_state;
+ uint8 out_buffer[OJPEG_BUFFER];
+ uint8* skip_buffer;
+} OJPEGState;
+
+static int OJPEGVGetField(TIFF* tif, ttag_t tag, va_list ap);
+static int OJPEGVSetField(TIFF* tif, ttag_t tag, va_list ap);
+static void OJPEGPrintDir(TIFF* tif, FILE* fd, long flags);
+
+static int OJPEGSetupDecode(TIFF* tif);
+static int OJPEGPreDecode(TIFF* tif, tsample_t s);
+static int OJPEGPreDecodeSkipRaw(TIFF* tif);
+static int OJPEGPreDecodeSkipScanlines(TIFF* tif);
+static int OJPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s);
+static int OJPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc);
+static int OJPEGDecodeScanlines(TIFF* tif, tidata_t buf, tsize_t cc);
+static void OJPEGPostDecode(TIFF* tif, tidata_t buf, tsize_t cc);
+static int OJPEGSetupEncode(TIFF* tif);
+static int OJPEGPreEncode(TIFF* tif, tsample_t s);
+static int OJPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s);
+static int OJPEGPostEncode(TIFF* tif);
+static void OJPEGCleanup(TIFF* tif);
+
+static void OJPEGSubsamplingCorrect(TIFF* tif);
+static int OJPEGReadHeaderInfo(TIFF* tif);
+static int OJPEGReadSecondarySos(TIFF* tif, tsample_t s);
+static int OJPEGWriteHeaderInfo(TIFF* tif);
+static void OJPEGLibjpegSessionAbort(TIFF* tif);
+
+static int OJPEGReadHeaderInfoSec(TIFF* tif);
+static int OJPEGReadHeaderInfoSecStreamDri(TIFF* tif);
+static int OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif);
+static int OJPEGReadHeaderInfoSecStreamDht(TIFF* tif);
+static int OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id);
+static int OJPEGReadHeaderInfoSecStreamSos(TIFF* tif);
+static int OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif);
+static int OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif);
+static int OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif);
+
+static int OJPEGReadBufferFill(OJPEGState* sp);
+static int OJPEGReadByte(OJPEGState* sp, uint8* byte);
+static int OJPEGReadBytePeek(OJPEGState* sp, uint8* byte);
+static void OJPEGReadByteAdvance(OJPEGState* sp);
+static int OJPEGReadWord(OJPEGState* sp, uint16* word);
+static int OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem);
+static void OJPEGReadSkip(OJPEGState* sp, uint16 len);
+
+static int OJPEGWriteStream(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len);
+static void OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len);
+static void OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len);
+static void OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len);
+static int OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len);
+static void OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len);
+
+#ifdef LIBJPEG_ENCAP_EXTERNAL
+extern int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo);
+extern int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image);
+extern int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo);
+extern int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines);
+extern int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines);
+extern void jpeg_encap_unwind(TIFF* tif);
+#else
+static int jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* j);
+static int jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image);
+static int jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo);
+static int jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines);
+static int jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines);
+static void jpeg_encap_unwind(TIFF* tif);
+#endif
+
+static void OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo);
+static void OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo);
+static void OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo);
+static boolean OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo);
+static void OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes);
+static boolean OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired);
+static void OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo);
+
+int
+TIFFInitOJPEG(TIFF* tif, int scheme)
+{
+ static const char module[]="TIFFInitOJPEG";
+ OJPEGState* sp;
+
+ assert(scheme==COMPRESSION_OJPEG);
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif,ojpeg_field_info,FIELD_OJPEG_COUNT)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Merging Old JPEG codec-specific tags failed");
+ return 0;
+ }
+
+ /* state block */
+ sp=_TIFFmalloc(sizeof(OJPEGState));
+ if (sp==NULL)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"No space for OJPEG state block");
+ return(0);
+ }
+ _TIFFmemset(sp,0,sizeof(OJPEGState));
+ sp->tif=tif;
+ sp->jpeg_proc=1;
+ sp->subsampling_hor=2;
+ sp->subsampling_ver=2;
+ TIFFSetField(tif,TIFFTAG_YCBCRSUBSAMPLING,2,2);
+ /* tif codec methods */
+ tif->tif_setupdecode=OJPEGSetupDecode;
+ tif->tif_predecode=OJPEGPreDecode;
+ tif->tif_postdecode=OJPEGPostDecode;
+ tif->tif_decoderow=OJPEGDecode;
+ tif->tif_decodestrip=OJPEGDecode;
+ tif->tif_decodetile=OJPEGDecode;
+ tif->tif_setupencode=OJPEGSetupEncode;
+ tif->tif_preencode=OJPEGPreEncode;
+ tif->tif_postencode=OJPEGPostEncode;
+ tif->tif_encoderow=OJPEGEncode;
+ tif->tif_encodestrip=OJPEGEncode;
+ tif->tif_encodetile=OJPEGEncode;
+ tif->tif_cleanup=OJPEGCleanup;
+ tif->tif_data=(tidata_t)sp;
+ /* tif tag methods */
+ sp->vgetparent=tif->tif_tagmethods.vgetfield;
+ tif->tif_tagmethods.vgetfield=OJPEGVGetField;
+ sp->vsetparent=tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vsetfield=OJPEGVSetField;
+ tif->tif_tagmethods.printdir=OJPEGPrintDir;
+ /* Some OJPEG files don't have strip or tile offsets or bytecounts tags.
+ Some others do, but have totally meaningless or corrupt values
+ in these tags. In these cases, the JpegInterchangeFormat stream is
+ reliable. In any case, this decoder reads the compressed data itself,
+ from the most reliable locations, and we need to notify encapsulating
+ LibTiff not to read raw strips or tiles for us. */
+ tif->tif_flags|=TIFF_NOREADRAW;
+ return(1);
+}
+
+static int
+OJPEGVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ switch(tag)
+ {
+ case TIFFTAG_JPEGIFOFFSET:
+ *va_arg(ap,uint32*)=(uint32)sp->jpeg_interchange_format;
+ break;
+ case TIFFTAG_JPEGIFBYTECOUNT:
+ *va_arg(ap,uint32*)=(uint32)sp->jpeg_interchange_format_length;
+ break;
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ if (sp->subsamplingcorrect_done==0)
+ OJPEGSubsamplingCorrect(tif);
+ *va_arg(ap,uint16*)=(uint16)sp->subsampling_hor;
+ *va_arg(ap,uint16*)=(uint16)sp->subsampling_ver;
+ break;
+ case TIFFTAG_JPEGQTABLES:
+ *va_arg(ap,uint32*)=(uint32)sp->qtable_offset_count;
+ *va_arg(ap,void**)=(void*)sp->qtable_offset;
+ break;
+ case TIFFTAG_JPEGDCTABLES:
+ *va_arg(ap,uint32*)=(uint32)sp->dctable_offset_count;
+ *va_arg(ap,void**)=(void*)sp->dctable_offset;
+ break;
+ case TIFFTAG_JPEGACTABLES:
+ *va_arg(ap,uint32*)=(uint32)sp->actable_offset_count;
+ *va_arg(ap,void**)=(void*)sp->actable_offset;
+ break;
+ case TIFFTAG_JPEGPROC:
+ *va_arg(ap,uint16*)=(uint16)sp->jpeg_proc;
+ break;
+ case TIFFTAG_JPEGRESTARTINTERVAL:
+ *va_arg(ap,uint16*)=sp->restart_interval;
+ break;
+ default:
+ return (*sp->vgetparent)(tif,tag,ap);
+ }
+ return (1);
+}
+
+static int
+OJPEGVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ static const char module[]="OJPEGVSetField";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint32 ma;
+ uint32* mb;
+ uint32 n;
+ switch(tag)
+ {
+ case TIFFTAG_JPEGIFOFFSET:
+ sp->jpeg_interchange_format=(toff_t)va_arg(ap,uint32);
+ break;
+ case TIFFTAG_JPEGIFBYTECOUNT:
+ sp->jpeg_interchange_format_length=(toff_t)va_arg(ap,uint32);
+ break;
+ case TIFFTAG_YCBCRSUBSAMPLING:
+ sp->subsampling_tag=1;
+ sp->subsampling_hor=(uint8)va_arg(ap,int);
+ sp->subsampling_ver=(uint8)va_arg(ap,int);
+ tif->tif_dir.td_ycbcrsubsampling[0]=sp->subsampling_hor;
+ tif->tif_dir.td_ycbcrsubsampling[1]=sp->subsampling_ver;
+ break;
+ case TIFFTAG_JPEGQTABLES:
+ ma=va_arg(ap,uint32);
+ if (ma!=0)
+ {
+ if (ma>3)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"JpegQTables tag has incorrect count");
+ return(0);
+ }
+ sp->qtable_offset_count=(uint8)ma;
+ mb=va_arg(ap,uint32*);
+ for (n=0; n<ma; n++)
+ sp->qtable_offset[n]=(toff_t)mb[n];
+ }
+ break;
+ case TIFFTAG_JPEGDCTABLES:
+ ma=va_arg(ap,uint32);
+ if (ma!=0)
+ {
+ if (ma>3)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"JpegDcTables tag has incorrect count");
+ return(0);
+ }
+ sp->dctable_offset_count=(uint8)ma;
+ mb=va_arg(ap,uint32*);
+ for (n=0; n<ma; n++)
+ sp->dctable_offset[n]=(toff_t)mb[n];
+ }
+ break;
+ case TIFFTAG_JPEGACTABLES:
+ ma=va_arg(ap,uint32);
+ if (ma!=0)
+ {
+ if (ma>3)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"JpegAcTables tag has incorrect count");
+ return(0);
+ }
+ sp->actable_offset_count=(uint8)ma;
+ mb=va_arg(ap,uint32*);
+ for (n=0; n<ma; n++)
+ sp->actable_offset[n]=(toff_t)mb[n];
+ }
+ break;
+ case TIFFTAG_JPEGPROC:
+ sp->jpeg_proc=(uint8)va_arg(ap,uint32);
+ break;
+ case TIFFTAG_JPEGRESTARTINTERVAL:
+ sp->restart_interval=(uint16)va_arg(ap,uint32);
+ break;
+ default:
+ return (*sp->vsetparent)(tif,tag,ap);
+ }
+ TIFFSetFieldBit(tif,_TIFFFieldWithTag(tif,tag)->field_bit);
+ tif->tif_flags|=TIFF_DIRTYDIRECT;
+ return(1);
+}
+
+static void
+OJPEGPrintDir(TIFF* tif, FILE* fd, long flags)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 m;
+ (void)flags;
+ assert(sp!=NULL);
+ if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMAT))
+ fprintf(fd," JpegInterchangeFormat: %lu\n",(unsigned long)sp->jpeg_interchange_format);
+ if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGINTERCHANGEFORMATLENGTH))
+ fprintf(fd," JpegInterchangeFormatLength: %lu\n",(unsigned long)sp->jpeg_interchange_format_length);
+ if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGQTABLES))
+ {
+ fprintf(fd," JpegQTables:");
+ for (m=0; m<sp->qtable_offset_count; m++)
+ fprintf(fd," %lu",(unsigned long)sp->qtable_offset[m]);
+ fprintf(fd,"\n");
+ }
+ if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGDCTABLES))
+ {
+ fprintf(fd," JpegDcTables:");
+ for (m=0; m<sp->dctable_offset_count; m++)
+ fprintf(fd," %lu",(unsigned long)sp->dctable_offset[m]);
+ fprintf(fd,"\n");
+ }
+ if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGACTABLES))
+ {
+ fprintf(fd," JpegAcTables:");
+ for (m=0; m<sp->actable_offset_count; m++)
+ fprintf(fd," %lu",(unsigned long)sp->actable_offset[m]);
+ fprintf(fd,"\n");
+ }
+ if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGPROC))
+ fprintf(fd," JpegProc: %u\n",(unsigned int)sp->jpeg_proc);
+ if (TIFFFieldSet(tif,FIELD_OJPEG_JPEGRESTARTINTERVAL))
+ fprintf(fd," JpegRestartInterval: %u\n",(unsigned int)sp->restart_interval);
+}
+
+static int
+OJPEGSetupDecode(TIFF* tif)
+{
+ static const char module[]="OJPEGSetupDecode";
+ TIFFWarningExt(tif->tif_clientdata,module,"Depreciated and troublesome old-style JPEG compression mode, please convert to new-style JPEG compression and notify vendor of writing software");
+ return(1);
+}
+
+static int
+OJPEGPreDecode(TIFF* tif, tsample_t s)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ tstrile_t m;
+ if (sp->subsamplingcorrect_done==0)
+ OJPEGSubsamplingCorrect(tif);
+ if (sp->readheader_done==0)
+ {
+ if (OJPEGReadHeaderInfo(tif)==0)
+ return(0);
+ }
+ if (sp->sos_end[s].log==0)
+ {
+ if (OJPEGReadSecondarySos(tif,s)==0)
+ return(0);
+ }
+ if isTiled(tif)
+ m=(tstrile_t)tif->tif_curtile;
+ else
+ m=(tstrile_t)tif->tif_curstrip;
+ if ((sp->writeheader_done!=0) && ((sp->write_cursample!=s) || (sp->write_curstrile>m)))
+ {
+ if (sp->libjpeg_session_active!=0)
+ OJPEGLibjpegSessionAbort(tif);
+ sp->writeheader_done=0;
+ }
+ if (sp->writeheader_done==0)
+ {
+ sp->plane_sample_offset=s;
+ sp->write_cursample=s;
+ sp->write_curstrile=s*tif->tif_dir.td_stripsperimage;
+ if ((sp->in_buffer_file_pos_log==0) ||
+ (sp->in_buffer_file_pos-sp->in_buffer_togo!=sp->sos_end[s].in_buffer_file_pos))
+ {
+ sp->in_buffer_source=sp->sos_end[s].in_buffer_source;
+ sp->in_buffer_next_strile=sp->sos_end[s].in_buffer_next_strile;
+ sp->in_buffer_file_pos=sp->sos_end[s].in_buffer_file_pos;
+ sp->in_buffer_file_pos_log=0;
+ sp->in_buffer_file_togo=sp->sos_end[s].in_buffer_file_togo;
+ sp->in_buffer_togo=0;
+ sp->in_buffer_cur=0;
+ }
+ if (OJPEGWriteHeaderInfo(tif)==0)
+ return(0);
+ }
+ while (sp->write_curstrile<m)
+ {
+ if (sp->libjpeg_jpeg_query_style==0)
+ {
+ if (OJPEGPreDecodeSkipRaw(tif)==0)
+ return(0);
+ }
+ else
+ {
+ if (OJPEGPreDecodeSkipScanlines(tif)==0)
+ return(0);
+ }
+ sp->write_curstrile++;
+ }
+ return(1);
+}
+
+static int
+OJPEGPreDecodeSkipRaw(TIFF* tif)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint32 m;
+ m=sp->lines_per_strile;
+ if (sp->subsampling_convert_state!=0)
+ {
+ if (sp->subsampling_convert_clines-sp->subsampling_convert_state>=m)
+ {
+ sp->subsampling_convert_state+=m;
+ if (sp->subsampling_convert_state==sp->subsampling_convert_clines)
+ sp->subsampling_convert_state=0;
+ return(1);
+ }
+ m-=sp->subsampling_convert_clines-sp->subsampling_convert_state;
+ sp->subsampling_convert_state=0;
+ }
+ while (m>=sp->subsampling_convert_clines)
+ {
+ if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0)
+ return(0);
+ m-=sp->subsampling_convert_clines;
+ }
+ if (m>0)
+ {
+ if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0)
+ return(0);
+ sp->subsampling_convert_state=m;
+ }
+ return(1);
+}
+
+static int
+OJPEGPreDecodeSkipScanlines(TIFF* tif)
+{
+ static const char module[]="OJPEGPreDecodeSkipScanlines";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint32 m;
+ if (sp->skip_buffer==NULL)
+ {
+ sp->skip_buffer=_TIFFmalloc(sp->bytes_per_line);
+ if (sp->skip_buffer==NULL)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+ return(0);
+ }
+ }
+ for (m=0; m<sp->lines_per_strile; m++)
+ {
+ if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&sp->skip_buffer,1)==0)
+ return(0);
+ }
+ return(1);
+}
+
+static int
+OJPEGDecode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ (void)s;
+ if (sp->libjpeg_jpeg_query_style==0)
+ {
+ if (OJPEGDecodeRaw(tif,buf,cc)==0)
+ return(0);
+ }
+ else
+ {
+ if (OJPEGDecodeScanlines(tif,buf,cc)==0)
+ return(0);
+ }
+ return(1);
+}
+
+static int
+OJPEGDecodeRaw(TIFF* tif, tidata_t buf, tsize_t cc)
+{
+ static const char module[]="OJPEGDecodeRaw";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8* m;
+ uint32 n;
+ uint8* oy;
+ uint8* ocb;
+ uint8* ocr;
+ uint8* p;
+ uint32 q;
+ uint8* r;
+ uint8 sx,sy;
+ if (cc%sp->bytes_per_line!=0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read");
+ return(0);
+ }
+ assert(cc>0);
+ m=buf;
+ n=cc;
+ do
+ {
+ if (sp->subsampling_convert_state==0)
+ {
+ if (jpeg_read_raw_data_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),sp->subsampling_convert_ycbcrimage,sp->subsampling_ver*8)==0)
+ return(0);
+ }
+ oy=sp->subsampling_convert_ybuf+sp->subsampling_convert_state*sp->subsampling_ver*sp->subsampling_convert_ylinelen;
+ ocb=sp->subsampling_convert_cbbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen;
+ ocr=sp->subsampling_convert_crbuf+sp->subsampling_convert_state*sp->subsampling_convert_clinelen;
+ p=m;
+ for (q=0; q<sp->subsampling_convert_clinelenout; q++)
+ {
+ r=oy;
+ for (sy=0; sy<sp->subsampling_ver; sy++)
+ {
+ for (sx=0; sx<sp->subsampling_hor; sx++)
+ *p++=*r++;
+ r+=sp->subsampling_convert_ylinelen-sp->subsampling_hor;
+ }
+ oy+=sp->subsampling_hor;
+ *p++=*ocb++;
+ *p++=*ocr++;
+ }
+ sp->subsampling_convert_state++;
+ if (sp->subsampling_convert_state==sp->subsampling_convert_clines)
+ sp->subsampling_convert_state=0;
+ m+=sp->bytes_per_line;
+ n-=sp->bytes_per_line;
+ } while(n>0);
+ return(1);
+}
+
+static int
+OJPEGDecodeScanlines(TIFF* tif, tidata_t buf, tsize_t cc)
+{
+ static const char module[]="OJPEGDecodeScanlines";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8* m;
+ uint32 n;
+ if (cc%sp->bytes_per_line!=0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Fractional scanline not read");
+ return(0);
+ }
+ assert(cc>0);
+ m=buf;
+ n=cc;
+ do
+ {
+ if (jpeg_read_scanlines_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),&m,1)==0)
+ return(0);
+ m+=sp->bytes_per_line;
+ n-=sp->bytes_per_line;
+ } while(n>0);
+ return(1);
+}
+
+static void
+OJPEGPostDecode(TIFF* tif, tidata_t buf, tsize_t cc)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ (void)buf;
+ (void)cc;
+ sp->write_curstrile++;
+ if (sp->write_curstrile%tif->tif_dir.td_stripsperimage==0)
+ {
+ assert(sp->libjpeg_session_active!=0);
+ OJPEGLibjpegSessionAbort(tif);
+ sp->writeheader_done=0;
+ }
+}
+
+static int
+OJPEGSetupEncode(TIFF* tif)
+{
+ static const char module[]="OJPEGSetupEncode";
+ TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead");
+ return(0);
+}
+
+static int
+OJPEGPreEncode(TIFF* tif, tsample_t s)
+{
+ static const char module[]="OJPEGPreEncode";
+ (void)s;
+ TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead");
+ return(0);
+}
+
+static int
+OJPEGEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
+{
+ static const char module[]="OJPEGEncode";
+ (void)buf;
+ (void)cc;
+ (void)s;
+ TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead");
+ return(0);
+}
+
+static int
+OJPEGPostEncode(TIFF* tif)
+{
+ static const char module[]="OJPEGPostEncode";
+ TIFFErrorExt(tif->tif_clientdata,module,"OJPEG encoding not supported; use new-style JPEG compression instead");
+ return(0);
+}
+
+static void
+OJPEGCleanup(TIFF* tif)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ if (sp!=0)
+ {
+ tif->tif_tagmethods.vgetfield=sp->vgetparent;
+ tif->tif_tagmethods.vsetfield=sp->vsetparent;
+ if (sp->qtable[0]!=0)
+ _TIFFfree(sp->qtable[0]);
+ if (sp->qtable[1]!=0)
+ _TIFFfree(sp->qtable[1]);
+ if (sp->qtable[2]!=0)
+ _TIFFfree(sp->qtable[2]);
+ if (sp->qtable[3]!=0)
+ _TIFFfree(sp->qtable[3]);
+ if (sp->dctable[0]!=0)
+ _TIFFfree(sp->dctable[0]);
+ if (sp->dctable[1]!=0)
+ _TIFFfree(sp->dctable[1]);
+ if (sp->dctable[2]!=0)
+ _TIFFfree(sp->dctable[2]);
+ if (sp->dctable[3]!=0)
+ _TIFFfree(sp->dctable[3]);
+ if (sp->actable[0]!=0)
+ _TIFFfree(sp->actable[0]);
+ if (sp->actable[1]!=0)
+ _TIFFfree(sp->actable[1]);
+ if (sp->actable[2]!=0)
+ _TIFFfree(sp->actable[2]);
+ if (sp->actable[3]!=0)
+ _TIFFfree(sp->actable[3]);
+ if (sp->libjpeg_session_active!=0)
+ OJPEGLibjpegSessionAbort(tif);
+ if (sp->subsampling_convert_ycbcrbuf!=0)
+ _TIFFfree(sp->subsampling_convert_ycbcrbuf);
+ if (sp->subsampling_convert_ycbcrimage!=0)
+ _TIFFfree(sp->subsampling_convert_ycbcrimage);
+ if (sp->skip_buffer!=0)
+ _TIFFfree(sp->skip_buffer);
+ _TIFFfree(sp);
+ tif->tif_data=NULL;
+ _TIFFSetDefaultCompressionState(tif);
+ }
+}
+
+static void
+OJPEGSubsamplingCorrect(TIFF* tif)
+{
+ static const char module[]="OJPEGSubsamplingCorrect";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 mh;
+ uint8 mv;
+ assert(sp->subsamplingcorrect_done==0);
+ if ((tif->tif_dir.td_samplesperpixel!=3) || ((tif->tif_dir.td_photometric!=PHOTOMETRIC_YCBCR) &&
+ (tif->tif_dir.td_photometric!=PHOTOMETRIC_ITULAB)))
+ {
+ if (sp->subsampling_tag!=0)
+ TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag not appropriate for this Photometric and/or SamplesPerPixel");
+ sp->subsampling_hor=1;
+ sp->subsampling_ver=1;
+ sp->subsampling_force_desubsampling_inside_decompression=0;
+ }
+ else
+ {
+ sp->subsamplingcorrect_done=1;
+ mh=sp->subsampling_hor;
+ mv=sp->subsampling_ver;
+ sp->subsamplingcorrect=1;
+ OJPEGReadHeaderInfoSec(tif);
+ if (sp->subsampling_force_desubsampling_inside_decompression!=0)
+ {
+ sp->subsampling_hor=1;
+ sp->subsampling_ver=1;
+ }
+ sp->subsamplingcorrect=0;
+ if (((sp->subsampling_hor!=mh) || (sp->subsampling_ver!=mv)) && (sp->subsampling_force_desubsampling_inside_decompression==0))
+ {
+ if (sp->subsampling_tag==0)
+ TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data [%d,%d] does not match default values [2,2]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver);
+ else
+ TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data [%d,%d] does not match subsampling tag values [%d,%d]; assuming subsampling inside JPEG data is correct",sp->subsampling_hor,sp->subsampling_ver,mh,mv);
+ }
+ if (sp->subsampling_force_desubsampling_inside_decompression!=0)
+ {
+ if (sp->subsampling_tag==0)
+ TIFFWarningExt(tif->tif_clientdata,module,"Subsampling tag is not set, yet subsampling inside JPEG data does not match default values [2,2] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression");
+ else
+ TIFFWarningExt(tif->tif_clientdata,module,"Subsampling inside JPEG data does not match subsampling tag values [%d,%d] (nor any other values allowed in TIFF); assuming subsampling inside JPEG data is correct and desubsampling inside JPEG decompression",mh,mv);
+ }
+ if (sp->subsampling_force_desubsampling_inside_decompression==0)
+ {
+ if (sp->subsampling_hor<sp->subsampling_ver)
+ TIFFWarningExt(tif->tif_clientdata,module,"Subsampling values [%d,%d] are not allowed in TIFF",sp->subsampling_hor,sp->subsampling_ver);
+ }
+ }
+ sp->subsamplingcorrect_done=1;
+}
+
+static int
+OJPEGReadHeaderInfo(TIFF* tif)
+{
+ static const char module[]="OJPEGReadHeaderInfo";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ assert(sp->readheader_done==0);
+ sp->image_width=tif->tif_dir.td_imagewidth;
+ sp->image_length=tif->tif_dir.td_imagelength;
+ if isTiled(tif)
+ {
+ sp->strile_width=tif->tif_dir.td_tilewidth;
+ sp->strile_length=tif->tif_dir.td_tilelength;
+ sp->strile_length_total=((sp->image_length+sp->strile_length-1)/sp->strile_length)*sp->strile_length;
+ }
+ else
+ {
+ sp->strile_width=sp->image_width;
+ sp->strile_length=tif->tif_dir.td_rowsperstrip;
+ sp->strile_length_total=sp->image_length;
+ }
+ sp->samples_per_pixel=tif->tif_dir.td_samplesperpixel;
+ if (sp->samples_per_pixel==1)
+ {
+ sp->plane_sample_offset=0;
+ sp->samples_per_pixel_per_plane=sp->samples_per_pixel;
+ sp->subsampling_hor=1;
+ sp->subsampling_ver=1;
+ }
+ else
+ {
+ if (sp->samples_per_pixel!=3)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"SamplesPerPixel %d not supported for this compression scheme",sp->samples_per_pixel);
+ return(0);
+ }
+ sp->plane_sample_offset=0;
+ if (tif->tif_dir.td_planarconfig==PLANARCONFIG_CONTIG)
+ sp->samples_per_pixel_per_plane=3;
+ else
+ sp->samples_per_pixel_per_plane=1;
+ }
+ if (sp->strile_length<sp->image_length)
+ {
+ if (sp->strile_length%(sp->subsampling_ver*8)!=0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Incompatible vertical subsampling and image strip/tile length");
+ return(0);
+ }
+ sp->restart_interval=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8))*(sp->strile_length/(sp->subsampling_ver*8));
+ }
+ if (OJPEGReadHeaderInfoSec(tif)==0)
+ return(0);
+ sp->sos_end[0].log=1;
+ sp->sos_end[0].in_buffer_source=sp->in_buffer_source;
+ sp->sos_end[0].in_buffer_next_strile=sp->in_buffer_next_strile;
+ sp->sos_end[0].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo;
+ sp->sos_end[0].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo;
+ sp->readheader_done=1;
+ return(1);
+}
+
+static int
+OJPEGReadSecondarySos(TIFF* tif, tsample_t s)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 m;
+ assert(s>0);
+ assert(s<3);
+ assert(sp->sos_end[0].log!=0);
+ assert(sp->sos_end[s].log==0);
+ sp->plane_sample_offset=s-1;
+ while(sp->sos_end[sp->plane_sample_offset].log==0)
+ sp->plane_sample_offset--;
+ sp->in_buffer_source=sp->sos_end[sp->plane_sample_offset].in_buffer_source;
+ sp->in_buffer_next_strile=sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile;
+ sp->in_buffer_file_pos=sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos;
+ sp->in_buffer_file_pos_log=0;
+ sp->in_buffer_file_togo=sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo;
+ sp->in_buffer_togo=0;
+ sp->in_buffer_cur=0;
+ while(sp->plane_sample_offset<s)
+ {
+ do
+ {
+ if (OJPEGReadByte(sp,&m)==0)
+ return(0);
+ if (m==255)
+ {
+ do
+ {
+ if (OJPEGReadByte(sp,&m)==0)
+ return(0);
+ if (m!=255)
+ break;
+ } while(1);
+ if (m==JPEG_MARKER_SOS)
+ break;
+ }
+ } while(1);
+ sp->plane_sample_offset++;
+ if (OJPEGReadHeaderInfoSecStreamSos(tif)==0)
+ return(0);
+ sp->sos_end[sp->plane_sample_offset].log=1;
+ sp->sos_end[sp->plane_sample_offset].in_buffer_source=sp->in_buffer_source;
+ sp->sos_end[sp->plane_sample_offset].in_buffer_next_strile=sp->in_buffer_next_strile;
+ sp->sos_end[sp->plane_sample_offset].in_buffer_file_pos=sp->in_buffer_file_pos-sp->in_buffer_togo;
+ sp->sos_end[sp->plane_sample_offset].in_buffer_file_togo=sp->in_buffer_file_togo+sp->in_buffer_togo;
+ }
+ return(1);
+}
+
+static int
+OJPEGWriteHeaderInfo(TIFF* tif)
+{
+ static const char module[]="OJPEGWriteHeaderInfo";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8** m;
+ uint32 n;
+ assert(sp->libjpeg_session_active==0);
+ sp->out_state=ososSoi;
+ sp->restart_index=0;
+ jpeg_std_error(&(sp->libjpeg_jpeg_error_mgr));
+ sp->libjpeg_jpeg_error_mgr.output_message=OJPEGLibjpegJpegErrorMgrOutputMessage;
+ sp->libjpeg_jpeg_error_mgr.error_exit=OJPEGLibjpegJpegErrorMgrErrorExit;
+ sp->libjpeg_jpeg_decompress_struct.err=&(sp->libjpeg_jpeg_error_mgr);
+ sp->libjpeg_jpeg_decompress_struct.client_data=(void*)tif;
+ if (jpeg_create_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0)
+ return(0);
+ sp->libjpeg_session_active=1;
+ sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=0;
+ sp->libjpeg_jpeg_source_mgr.init_source=OJPEGLibjpegJpegSourceMgrInitSource;
+ sp->libjpeg_jpeg_source_mgr.fill_input_buffer=OJPEGLibjpegJpegSourceMgrFillInputBuffer;
+ sp->libjpeg_jpeg_source_mgr.skip_input_data=OJPEGLibjpegJpegSourceMgrSkipInputData;
+ sp->libjpeg_jpeg_source_mgr.resync_to_restart=OJPEGLibjpegJpegSourceMgrResyncToRestart;
+ sp->libjpeg_jpeg_source_mgr.term_source=OJPEGLibjpegJpegSourceMgrTermSource;
+ sp->libjpeg_jpeg_decompress_struct.src=&(sp->libjpeg_jpeg_source_mgr);
+ if (jpeg_read_header_encap(sp,&(sp->libjpeg_jpeg_decompress_struct),1)==0)
+ return(0);
+ if ((sp->subsampling_force_desubsampling_inside_decompression==0) && (sp->samples_per_pixel_per_plane>1))
+ {
+ sp->libjpeg_jpeg_decompress_struct.raw_data_out=1;
+#if JPEG_LIB_VERSION >= 70
+ sp->libjpeg_jpeg_decompress_struct.do_fancy_upsampling=FALSE;
+#endif
+ sp->libjpeg_jpeg_query_style=0;
+ if (sp->subsampling_convert_log==0)
+ {
+ assert(sp->subsampling_convert_ycbcrbuf==0);
+ assert(sp->subsampling_convert_ycbcrimage==0);
+ sp->subsampling_convert_ylinelen=((sp->strile_width+sp->subsampling_hor*8-1)/(sp->subsampling_hor*8)*sp->subsampling_hor*8);
+ sp->subsampling_convert_ylines=sp->subsampling_ver*8;
+ sp->subsampling_convert_clinelen=sp->subsampling_convert_ylinelen/sp->subsampling_hor;
+ sp->subsampling_convert_clines=8;
+ sp->subsampling_convert_ybuflen=sp->subsampling_convert_ylinelen*sp->subsampling_convert_ylines;
+ sp->subsampling_convert_cbuflen=sp->subsampling_convert_clinelen*sp->subsampling_convert_clines;
+ sp->subsampling_convert_ycbcrbuflen=sp->subsampling_convert_ybuflen+2*sp->subsampling_convert_cbuflen;
+ sp->subsampling_convert_ycbcrbuf=_TIFFmalloc(sp->subsampling_convert_ycbcrbuflen);
+ if (sp->subsampling_convert_ycbcrbuf==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+ return(0);
+ }
+ sp->subsampling_convert_ybuf=sp->subsampling_convert_ycbcrbuf;
+ sp->subsampling_convert_cbbuf=sp->subsampling_convert_ybuf+sp->subsampling_convert_ybuflen;
+ sp->subsampling_convert_crbuf=sp->subsampling_convert_cbbuf+sp->subsampling_convert_cbuflen;
+ sp->subsampling_convert_ycbcrimagelen=3+sp->subsampling_convert_ylines+2*sp->subsampling_convert_clines;
+ sp->subsampling_convert_ycbcrimage=_TIFFmalloc(sp->subsampling_convert_ycbcrimagelen*sizeof(uint8*));
+ if (sp->subsampling_convert_ycbcrimage==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+ return(0);
+ }
+ m=sp->subsampling_convert_ycbcrimage;
+ *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3);
+ *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines);
+ *m++=(uint8*)(sp->subsampling_convert_ycbcrimage+3+sp->subsampling_convert_ylines+sp->subsampling_convert_clines);
+ for (n=0; n<sp->subsampling_convert_ylines; n++)
+ *m++=sp->subsampling_convert_ybuf+n*sp->subsampling_convert_ylinelen;
+ for (n=0; n<sp->subsampling_convert_clines; n++)
+ *m++=sp->subsampling_convert_cbbuf+n*sp->subsampling_convert_clinelen;
+ for (n=0; n<sp->subsampling_convert_clines; n++)
+ *m++=sp->subsampling_convert_crbuf+n*sp->subsampling_convert_clinelen;
+ sp->subsampling_convert_clinelenout=((sp->strile_width+sp->subsampling_hor-1)/sp->subsampling_hor);
+ sp->subsampling_convert_state=0;
+ sp->bytes_per_line=sp->subsampling_convert_clinelenout*(sp->subsampling_ver*sp->subsampling_hor+2);
+ sp->lines_per_strile=((sp->strile_length+sp->subsampling_ver-1)/sp->subsampling_ver);
+ sp->subsampling_convert_log=1;
+ }
+ }
+ else
+ {
+ sp->libjpeg_jpeg_decompress_struct.jpeg_color_space=JCS_UNKNOWN;
+ sp->libjpeg_jpeg_decompress_struct.out_color_space=JCS_UNKNOWN;
+ sp->libjpeg_jpeg_query_style=1;
+ sp->bytes_per_line=sp->samples_per_pixel_per_plane*sp->strile_width;
+ sp->lines_per_strile=sp->strile_length;
+ }
+ if (jpeg_start_decompress_encap(sp,&(sp->libjpeg_jpeg_decompress_struct))==0)
+ return(0);
+ sp->writeheader_done=1;
+ return(1);
+}
+
+static void
+OJPEGLibjpegSessionAbort(TIFF* tif)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ assert(sp->libjpeg_session_active!=0);
+ jpeg_destroy((jpeg_common_struct*)(&(sp->libjpeg_jpeg_decompress_struct)));
+ sp->libjpeg_session_active=0;
+}
+
+static int
+OJPEGReadHeaderInfoSec(TIFF* tif)
+{
+ static const char module[]="OJPEGReadHeaderInfoSec";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 m;
+ uint16 n;
+ uint8 o;
+ if (sp->file_size==0)
+ sp->file_size=TIFFGetFileSize(tif);
+ if (sp->jpeg_interchange_format!=0)
+ {
+ if (sp->jpeg_interchange_format>=sp->file_size)
+ {
+ sp->jpeg_interchange_format=0;
+ sp->jpeg_interchange_format_length=0;
+ }
+ else
+ {
+ if ((sp->jpeg_interchange_format_length==0) || (sp->jpeg_interchange_format+sp->jpeg_interchange_format_length>sp->file_size))
+ sp->jpeg_interchange_format_length=sp->file_size-sp->jpeg_interchange_format;
+ }
+ }
+ sp->in_buffer_source=osibsNotSetYet;
+ sp->in_buffer_next_strile=0;
+ sp->in_buffer_strile_count=tif->tif_dir.td_nstrips;
+ sp->in_buffer_file_togo=0;
+ sp->in_buffer_togo=0;
+ do
+ {
+ if (OJPEGReadBytePeek(sp,&m)==0)
+ return(0);
+ if (m!=255)
+ break;
+ OJPEGReadByteAdvance(sp);
+ do
+ {
+ if (OJPEGReadByte(sp,&m)==0)
+ return(0);
+ } while(m==255);
+ switch(m)
+ {
+ case JPEG_MARKER_SOI:
+ /* this type of marker has no data, and should be skipped */
+ break;
+ case JPEG_MARKER_COM:
+ case JPEG_MARKER_APP0:
+ case JPEG_MARKER_APP0+1:
+ case JPEG_MARKER_APP0+2:
+ case JPEG_MARKER_APP0+3:
+ case JPEG_MARKER_APP0+4:
+ case JPEG_MARKER_APP0+5:
+ case JPEG_MARKER_APP0+6:
+ case JPEG_MARKER_APP0+7:
+ case JPEG_MARKER_APP0+8:
+ case JPEG_MARKER_APP0+9:
+ case JPEG_MARKER_APP0+10:
+ case JPEG_MARKER_APP0+11:
+ case JPEG_MARKER_APP0+12:
+ case JPEG_MARKER_APP0+13:
+ case JPEG_MARKER_APP0+14:
+ case JPEG_MARKER_APP0+15:
+ /* this type of marker has data, but it has no use to us (and no place here) and should be skipped */
+ if (OJPEGReadWord(sp,&n)==0)
+ return(0);
+ if (n<2)
+ {
+ if (sp->subsamplingcorrect==0)
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data");
+ return(0);
+ }
+ if (n>2)
+ OJPEGReadSkip(sp,n-2);
+ break;
+ case JPEG_MARKER_DRI:
+ if (OJPEGReadHeaderInfoSecStreamDri(tif)==0)
+ return(0);
+ break;
+ case JPEG_MARKER_DQT:
+ if (OJPEGReadHeaderInfoSecStreamDqt(tif)==0)
+ return(0);
+ break;
+ case JPEG_MARKER_DHT:
+ if (OJPEGReadHeaderInfoSecStreamDht(tif)==0)
+ return(0);
+ break;
+ case JPEG_MARKER_SOF0:
+ case JPEG_MARKER_SOF1:
+ case JPEG_MARKER_SOF3:
+ if (OJPEGReadHeaderInfoSecStreamSof(tif,m)==0)
+ return(0);
+ if (sp->subsamplingcorrect!=0)
+ return(1);
+ break;
+ case JPEG_MARKER_SOS:
+ if (sp->subsamplingcorrect!=0)
+ return(1);
+ assert(sp->plane_sample_offset==0);
+ if (OJPEGReadHeaderInfoSecStreamSos(tif)==0)
+ return(0);
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata,module,"Unknown marker type %d in JPEG data",m);
+ return(0);
+ }
+ } while(m!=JPEG_MARKER_SOS);
+ if (sp->subsamplingcorrect)
+ return(1);
+ if (sp->sof_log==0)
+ {
+ if (OJPEGReadHeaderInfoSecTablesQTable(tif)==0)
+ return(0);
+ sp->sof_marker_id=JPEG_MARKER_SOF0;
+ for (o=0; o<sp->samples_per_pixel; o++)
+ sp->sof_c[o]=o;
+ sp->sof_hv[0]=((sp->subsampling_hor<<4)|sp->subsampling_ver);
+ for (o=1; o<sp->samples_per_pixel; o++)
+ sp->sof_hv[o]=17;
+ sp->sof_x=sp->strile_width;
+ sp->sof_y=sp->strile_length_total;
+ sp->sof_log=1;
+ if (OJPEGReadHeaderInfoSecTablesDcTable(tif)==0)
+ return(0);
+ if (OJPEGReadHeaderInfoSecTablesAcTable(tif)==0)
+ return(0);
+ for (o=1; o<sp->samples_per_pixel; o++)
+ sp->sos_cs[o]=o;
+ }
+ return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamDri(TIFF* tif)
+{
+ /* this could easilly cause trouble in some cases... but no such cases have occured sofar */
+ static const char module[]="OJPEGReadHeaderInfoSecStreamDri";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint16 m;
+ if (OJPEGReadWord(sp,&m)==0)
+ return(0);
+ if (m!=4)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DRI marker in JPEG data");
+ return(0);
+ }
+ if (OJPEGReadWord(sp,&m)==0)
+ return(0);
+ sp->restart_interval=m;
+ return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamDqt(TIFF* tif)
+{
+ /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */
+ static const char module[]="OJPEGReadHeaderInfoSecStreamDqt";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint16 m;
+ uint32 na;
+ uint8* nb;
+ uint8 o;
+ if (OJPEGReadWord(sp,&m)==0)
+ return(0);
+ if (m<=2)
+ {
+ if (sp->subsamplingcorrect==0)
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data");
+ return(0);
+ }
+ if (sp->subsamplingcorrect!=0)
+ OJPEGReadSkip(sp,m-2);
+ else
+ {
+ m-=2;
+ do
+ {
+ if (m<65)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data");
+ return(0);
+ }
+ na=sizeof(uint32)+69;
+ nb=_TIFFmalloc(na);
+ if (nb==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+ return(0);
+ }
+ *(uint32*)nb=na;
+ nb[sizeof(uint32)]=255;
+ nb[sizeof(uint32)+1]=JPEG_MARKER_DQT;
+ nb[sizeof(uint32)+2]=0;
+ nb[sizeof(uint32)+3]=67;
+ if (OJPEGReadBlock(sp,65,&nb[sizeof(uint32)+4])==0)
+ return(0);
+ o=nb[sizeof(uint32)+4]&15;
+ if (3<o)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DQT marker in JPEG data");
+ return(0);
+ }
+ if (sp->qtable[o]!=0)
+ _TIFFfree(sp->qtable[o]);
+ sp->qtable[o]=nb;
+ m-=65;
+ } while(m>0);
+ }
+ return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamDht(TIFF* tif)
+{
+ /* this is a table marker, and it is to be saved as a whole for exact pushing on the jpeg stream later on */
+ /* TODO: the following assumes there is only one table in this marker... but i'm not quite sure that assumption is guaranteed correct */
+ static const char module[]="OJPEGReadHeaderInfoSecStreamDht";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint16 m;
+ uint32 na;
+ uint8* nb;
+ uint8 o;
+ if (OJPEGReadWord(sp,&m)==0)
+ return(0);
+ if (m<=2)
+ {
+ if (sp->subsamplingcorrect==0)
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+ return(0);
+ }
+ if (sp->subsamplingcorrect!=0)
+ {
+ OJPEGReadSkip(sp,m-2);
+ }
+ else
+ {
+ na=sizeof(uint32)+2+m;
+ nb=_TIFFmalloc(na);
+ if (nb==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+ return(0);
+ }
+ *(uint32*)nb=na;
+ nb[sizeof(uint32)]=255;
+ nb[sizeof(uint32)+1]=JPEG_MARKER_DHT;
+ nb[sizeof(uint32)+2]=(m>>8);
+ nb[sizeof(uint32)+3]=(m&255);
+ if (OJPEGReadBlock(sp,m-2,&nb[sizeof(uint32)+4])==0)
+ return(0);
+ o=nb[sizeof(uint32)+4];
+ if ((o&240)==0)
+ {
+ if (3<o)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+ return(0);
+ }
+ if (sp->dctable[o]!=0)
+ _TIFFfree(sp->dctable[o]);
+ sp->dctable[o]=nb;
+ }
+ else
+ {
+ if ((o&240)!=16)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+ return(0);
+ }
+ o&=15;
+ if (3<o)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt DHT marker in JPEG data");
+ return(0);
+ }
+ if (sp->actable[o]!=0)
+ _TIFFfree(sp->actable[o]);
+ sp->actable[o]=nb;
+ }
+ }
+ return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamSof(TIFF* tif, uint8 marker_id)
+{
+ /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */
+ static const char module[]="OJPEGReadHeaderInfoSecStreamSof";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint16 m;
+ uint16 n;
+ uint8 o;
+ uint16 p;
+ uint16 q;
+ if (sp->sof_log!=0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JPEG data");
+ return(0);
+ }
+ if (sp->subsamplingcorrect==0)
+ sp->sof_marker_id=marker_id;
+ /* Lf: data length */
+ if (OJPEGReadWord(sp,&m)==0)
+ return(0);
+ if (m<11)
+ {
+ if (sp->subsamplingcorrect==0)
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data");
+ return(0);
+ }
+ m-=8;
+ if (m%3!=0)
+ {
+ if (sp->subsamplingcorrect==0)
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data");
+ return(0);
+ }
+ n=m/3;
+ if (sp->subsamplingcorrect==0)
+ {
+ if (n!=sp->samples_per_pixel)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of samples");
+ return(0);
+ }
+ }
+ /* P: Sample precision */
+ if (OJPEGReadByte(sp,&o)==0)
+ return(0);
+ if (o!=8)
+ {
+ if (sp->subsamplingcorrect==0)
+ TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected number of bits per sample");
+ return(0);
+ }
+ /* Y: Number of lines, X: Number of samples per line */
+ if (sp->subsamplingcorrect)
+ OJPEGReadSkip(sp,4);
+ else
+ {
+ /* TODO: probably best to also add check on allowed upper bound, especially x, may cause buffer overflow otherwise i think */
+ /* Y: Number of lines */
+ if (OJPEGReadWord(sp,&p)==0)
+ return(0);
+ if ((p<sp->image_length) && (p<sp->strile_length_total))
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected height");
+ return(0);
+ }
+ sp->sof_y=p;
+ /* X: Number of samples per line */
+ if (OJPEGReadWord(sp,&p)==0)
+ return(0);
+ if ((p<sp->image_width) && (p<sp->strile_width))
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected width");
+ return(0);
+ }
+ sp->sof_x=p;
+ }
+ /* Nf: Number of image components in frame */
+ if (OJPEGReadByte(sp,&o)==0)
+ return(0);
+ if (o!=n)
+ {
+ if (sp->subsamplingcorrect==0)
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOF marker in JPEG data");
+ return(0);
+ }
+ /* per component stuff */
+ /* TODO: double-check that flow implies that n cannot be as big as to make us overflow sof_c, sof_hv and sof_tq arrays */
+ for (q=0; q<n; q++)
+ {
+ /* C: Component identifier */
+ if (OJPEGReadByte(sp,&o)==0)
+ return(0);
+ if (sp->subsamplingcorrect==0)
+ sp->sof_c[q]=o;
+ /* H: Horizontal sampling factor, and V: Vertical sampling factor */
+ if (OJPEGReadByte(sp,&o)==0)
+ return(0);
+ if (sp->subsamplingcorrect!=0)
+ {
+ if (q==0)
+ {
+ sp->subsampling_hor=(o>>4);
+ sp->subsampling_ver=(o&15);
+ if (((sp->subsampling_hor!=1) && (sp->subsampling_hor!=2) && (sp->subsampling_hor!=4)) ||
+ ((sp->subsampling_ver!=1) && (sp->subsampling_ver!=2) && (sp->subsampling_ver!=4)))
+ sp->subsampling_force_desubsampling_inside_decompression=1;
+ }
+ else
+ {
+ if (o!=17)
+ sp->subsampling_force_desubsampling_inside_decompression=1;
+ }
+ }
+ else
+ {
+ sp->sof_hv[q]=o;
+ if (sp->subsampling_force_desubsampling_inside_decompression==0)
+ {
+ if (q==0)
+ {
+ if (o!=((sp->subsampling_hor<<4)|sp->subsampling_ver))
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values");
+ return(0);
+ }
+ }
+ else
+ {
+ if (o!=17)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"JPEG compressed data indicates unexpected subsampling values");
+ return(0);
+ }
+ }
+ }
+ }
+ /* Tq: Quantization table destination selector */
+ if (OJPEGReadByte(sp,&o)==0)
+ return(0);
+ if (sp->subsamplingcorrect==0)
+ sp->sof_tq[q]=o;
+ }
+ if (sp->subsamplingcorrect==0)
+ sp->sof_log=1;
+ return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecStreamSos(TIFF* tif)
+{
+ /* this marker needs to be checked, and part of its data needs to be saved for regeneration later on */
+ static const char module[]="OJPEGReadHeaderInfoSecStreamSos";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint16 m;
+ uint8 n;
+ uint8 o;
+ assert(sp->subsamplingcorrect==0);
+ if (sp->sof_log==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data");
+ return(0);
+ }
+ /* Ls */
+ if (OJPEGReadWord(sp,&m)==0)
+ return(0);
+ if (m!=6+sp->samples_per_pixel_per_plane*2)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data");
+ return(0);
+ }
+ /* Ns */
+ if (OJPEGReadByte(sp,&n)==0)
+ return(0);
+ if (n!=sp->samples_per_pixel_per_plane)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt SOS marker in JPEG data");
+ return(0);
+ }
+ /* Cs, Td, and Ta */
+ for (o=0; o<sp->samples_per_pixel_per_plane; o++)
+ {
+ /* Cs */
+ if (OJPEGReadByte(sp,&n)==0)
+ return(0);
+ sp->sos_cs[sp->plane_sample_offset+o]=n;
+ /* Td and Ta */
+ if (OJPEGReadByte(sp,&n)==0)
+ return(0);
+ sp->sos_tda[sp->plane_sample_offset+o]=n;
+ }
+ /* skip Ss, Se, Ah, en Al -> no check, as per Tom Lane recommendation, as per LibJpeg source */
+ OJPEGReadSkip(sp,3);
+ return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecTablesQTable(TIFF* tif)
+{
+ static const char module[]="OJPEGReadHeaderInfoSecTablesQTable";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 m;
+ uint8 n;
+ uint32 oa;
+ uint8* ob;
+ uint32 p;
+ if (sp->qtable_offset[0]==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables");
+ return(0);
+ }
+ sp->in_buffer_file_pos_log=0;
+ for (m=0; m<sp->samples_per_pixel; m++)
+ {
+ if ((sp->qtable_offset[m]!=0) && ((m==0) || (sp->qtable_offset[m]!=sp->qtable_offset[m-1])))
+ {
+ for (n=0; n<m-1; n++)
+ {
+ if (sp->qtable_offset[m]==sp->qtable_offset[n])
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegQTables tag value");
+ return(0);
+ }
+ }
+ oa=sizeof(uint32)+69;
+ ob=_TIFFmalloc(oa);
+ if (ob==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+ return(0);
+ }
+ *(uint32*)ob=oa;
+ ob[sizeof(uint32)]=255;
+ ob[sizeof(uint32)+1]=JPEG_MARKER_DQT;
+ ob[sizeof(uint32)+2]=0;
+ ob[sizeof(uint32)+3]=67;
+ ob[sizeof(uint32)+4]=m;
+ TIFFSeekFile(tif,sp->qtable_offset[m],SEEK_SET);
+ p=TIFFReadFile(tif,&ob[sizeof(uint32)+5],64);
+ if (p!=64)
+ return(0);
+ sp->qtable[m]=ob;
+ sp->sof_tq[m]=m;
+ }
+ else
+ sp->sof_tq[m]=sp->sof_tq[m-1];
+ }
+ return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecTablesDcTable(TIFF* tif)
+{
+ static const char module[]="OJPEGReadHeaderInfoSecTablesDcTable";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 m;
+ uint8 n;
+ uint8 o[16];
+ uint32 p;
+ uint32 q;
+ uint32 ra;
+ uint8* rb;
+ if (sp->dctable_offset[0]==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables");
+ return(0);
+ }
+ sp->in_buffer_file_pos_log=0;
+ for (m=0; m<sp->samples_per_pixel; m++)
+ {
+ if ((sp->dctable_offset[m]!=0) && ((m==0) || (sp->dctable_offset[m]!=sp->dctable_offset[m-1])))
+ {
+ for (n=0; n<m-1; n++)
+ {
+ if (sp->dctable_offset[m]==sp->dctable_offset[n])
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegDcTables tag value");
+ return(0);
+ }
+ }
+ TIFFSeekFile(tif,sp->dctable_offset[m],SEEK_SET);
+ p=TIFFReadFile(tif,o,16);
+ if (p!=16)
+ return(0);
+ q=0;
+ for (n=0; n<16; n++)
+ q+=o[n];
+ ra=sizeof(uint32)+21+q;
+ rb=_TIFFmalloc(ra);
+ if (rb==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+ return(0);
+ }
+ *(uint32*)rb=ra;
+ rb[sizeof(uint32)]=255;
+ rb[sizeof(uint32)+1]=JPEG_MARKER_DHT;
+ rb[sizeof(uint32)+2]=((19+q)>>8);
+ rb[sizeof(uint32)+3]=((19+q)&255);
+ rb[sizeof(uint32)+4]=m;
+ for (n=0; n<16; n++)
+ rb[sizeof(uint32)+5+n]=o[n];
+ p=TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q);
+ if (p!=q)
+ return(0);
+ sp->dctable[m]=rb;
+ sp->sos_tda[m]=(m<<4);
+ }
+ else
+ sp->sos_tda[m]=sp->sos_tda[m-1];
+ }
+ return(1);
+}
+
+static int
+OJPEGReadHeaderInfoSecTablesAcTable(TIFF* tif)
+{
+ static const char module[]="OJPEGReadHeaderInfoSecTablesAcTable";
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 m;
+ uint8 n;
+ uint8 o[16];
+ uint32 p;
+ uint32 q;
+ uint32 ra;
+ uint8* rb;
+ if (sp->actable_offset[0]==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Missing JPEG tables");
+ return(0);
+ }
+ sp->in_buffer_file_pos_log=0;
+ for (m=0; m<sp->samples_per_pixel; m++)
+ {
+ if ((sp->actable_offset[m]!=0) && ((m==0) || (sp->actable_offset[m]!=sp->actable_offset[m-1])))
+ {
+ for (n=0; n<m-1; n++)
+ {
+ if (sp->actable_offset[m]==sp->actable_offset[n])
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Corrupt JpegAcTables tag value");
+ return(0);
+ }
+ }
+ TIFFSeekFile(tif,sp->actable_offset[m],SEEK_SET);
+ p=TIFFReadFile(tif,o,16);
+ if (p!=16)
+ return(0);
+ q=0;
+ for (n=0; n<16; n++)
+ q+=o[n];
+ ra=sizeof(uint32)+21+q;
+ rb=_TIFFmalloc(ra);
+ if (rb==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,module,"Out of memory");
+ return(0);
+ }
+ *(uint32*)rb=ra;
+ rb[sizeof(uint32)]=255;
+ rb[sizeof(uint32)+1]=JPEG_MARKER_DHT;
+ rb[sizeof(uint32)+2]=((19+q)>>8);
+ rb[sizeof(uint32)+3]=((19+q)&255);
+ rb[sizeof(uint32)+4]=(16|m);
+ for (n=0; n<16; n++)
+ rb[sizeof(uint32)+5+n]=o[n];
+ p=TIFFReadFile(tif,&(rb[sizeof(uint32)+21]),q);
+ if (p!=q)
+ return(0);
+ sp->actable[m]=rb;
+ sp->sos_tda[m]=(sp->sos_tda[m]|m);
+ }
+ else
+ sp->sos_tda[m]=(sp->sos_tda[m]|(sp->sos_tda[m-1]&15));
+ }
+ return(1);
+}
+
+static int
+OJPEGReadBufferFill(OJPEGState* sp)
+{
+ uint16 m;
+ tsize_t n;
+ /* TODO: double-check: when subsamplingcorrect is set, no call to TIFFErrorExt or TIFFWarningExt should be made
+ * in any other case, seek or read errors should be passed through */
+ do
+ {
+ if (sp->in_buffer_file_togo!=0)
+ {
+ if (sp->in_buffer_file_pos_log==0)
+ {
+ TIFFSeekFile(sp->tif,sp->in_buffer_file_pos,SEEK_SET);
+ sp->in_buffer_file_pos_log=1;
+ }
+ m=OJPEG_BUFFER;
+ if (m>sp->in_buffer_file_togo)
+ m=(uint16)sp->in_buffer_file_togo;
+ n=TIFFReadFile(sp->tif,sp->in_buffer,(tsize_t)m);
+ if (n==0)
+ return(0);
+ assert(n>0);
+ assert(n<=OJPEG_BUFFER);
+ assert(n<65536);
+ assert((uint16)n<=sp->in_buffer_file_togo);
+ m=(uint16)n;
+ sp->in_buffer_togo=m;
+ sp->in_buffer_cur=sp->in_buffer;
+ sp->in_buffer_file_togo-=m;
+ sp->in_buffer_file_pos+=m;
+ break;
+ }
+ sp->in_buffer_file_pos_log=0;
+ switch(sp->in_buffer_source)
+ {
+ case osibsNotSetYet:
+ if (sp->jpeg_interchange_format!=0)
+ {
+ sp->in_buffer_file_pos=sp->jpeg_interchange_format;
+ sp->in_buffer_file_togo=sp->jpeg_interchange_format_length;
+ }
+ sp->in_buffer_source=osibsJpegInterchangeFormat;
+ break;
+ case osibsJpegInterchangeFormat:
+ sp->in_buffer_source=osibsStrile;
+ case osibsStrile:
+ if (sp->in_buffer_next_strile==sp->in_buffer_strile_count)
+ sp->in_buffer_source=osibsEof;
+ else
+ {
+ if (sp->tif->tif_dir.td_stripoffset == 0) {
+ TIFFErrorExt(sp->tif->tif_clientdata,sp->tif->tif_name,"Strip offsets are missing");
+ return(0);
+ }
+ sp->in_buffer_file_pos=sp->tif->tif_dir.td_stripoffset[sp->in_buffer_next_strile];
+ if (sp->in_buffer_file_pos!=0)
+ {
+ if (sp->in_buffer_file_pos>=sp->file_size)
+ sp->in_buffer_file_pos=0;
+ else
+ {
+ sp->in_buffer_file_togo=sp->tif->tif_dir.td_stripbytecount[sp->in_buffer_next_strile];
+ if (sp->in_buffer_file_togo==0)
+ sp->in_buffer_file_pos=0;
+ else if (sp->in_buffer_file_pos+sp->in_buffer_file_togo>sp->file_size)
+ sp->in_buffer_file_togo=sp->file_size-sp->in_buffer_file_pos;
+ }
+ }
+ sp->in_buffer_next_strile++;
+ }
+ break;
+ default:
+ return(0);
+ }
+ } while (1);
+ return(1);
+}
+
+static int
+OJPEGReadByte(OJPEGState* sp, uint8* byte)
+{
+ if (sp->in_buffer_togo==0)
+ {
+ if (OJPEGReadBufferFill(sp)==0)
+ return(0);
+ assert(sp->in_buffer_togo>0);
+ }
+ *byte=*(sp->in_buffer_cur);
+ sp->in_buffer_cur++;
+ sp->in_buffer_togo--;
+ return(1);
+}
+
+static int
+OJPEGReadBytePeek(OJPEGState* sp, uint8* byte)
+{
+ if (sp->in_buffer_togo==0)
+ {
+ if (OJPEGReadBufferFill(sp)==0)
+ return(0);
+ assert(sp->in_buffer_togo>0);
+ }
+ *byte=*(sp->in_buffer_cur);
+ return(1);
+}
+
+static void
+OJPEGReadByteAdvance(OJPEGState* sp)
+{
+ assert(sp->in_buffer_togo>0);
+ sp->in_buffer_cur++;
+ sp->in_buffer_togo--;
+}
+
+static int
+OJPEGReadWord(OJPEGState* sp, uint16* word)
+{
+ uint8 m;
+ if (OJPEGReadByte(sp,&m)==0)
+ return(0);
+ *word=(m<<8);
+ if (OJPEGReadByte(sp,&m)==0)
+ return(0);
+ *word|=m;
+ return(1);
+}
+
+static int
+OJPEGReadBlock(OJPEGState* sp, uint16 len, void* mem)
+{
+ uint16 mlen;
+ uint8* mmem;
+ uint16 n;
+ assert(len>0);
+ mlen=len;
+ mmem=mem;
+ do
+ {
+ if (sp->in_buffer_togo==0)
+ {
+ if (OJPEGReadBufferFill(sp)==0)
+ return(0);
+ assert(sp->in_buffer_togo>0);
+ }
+ n=mlen;
+ if (n>sp->in_buffer_togo)
+ n=sp->in_buffer_togo;
+ _TIFFmemcpy(mmem,sp->in_buffer_cur,n);
+ sp->in_buffer_cur+=n;
+ sp->in_buffer_togo-=n;
+ mlen-=n;
+ mmem+=n;
+ } while(mlen>0);
+ return(1);
+}
+
+static void
+OJPEGReadSkip(OJPEGState* sp, uint16 len)
+{
+ uint16 m;
+ uint16 n;
+ m=len;
+ n=m;
+ if (n>sp->in_buffer_togo)
+ n=sp->in_buffer_togo;
+ sp->in_buffer_cur+=n;
+ sp->in_buffer_togo-=n;
+ m-=n;
+ if (m>0)
+ {
+ assert(sp->in_buffer_togo==0);
+ n=m;
+ if (n>sp->in_buffer_file_togo)
+ n=sp->in_buffer_file_togo;
+ sp->in_buffer_file_pos+=n;
+ sp->in_buffer_file_togo-=n;
+ sp->in_buffer_file_pos_log=0;
+ /* we don't skip past jpeginterchangeformat/strile block...
+ * if that is asked from us, we're dealing with totally bazurk
+ * data anyway, and we've not seen this happening on any
+ * testfile, so we might as well likely cause some other
+ * meaningless error to be passed at some later time
+ */
+ }
+}
+
+static int
+OJPEGWriteStream(TIFF* tif, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ *len=0;
+ do
+ {
+ assert(sp->out_state<=ososEoi);
+ switch(sp->out_state)
+ {
+ case ososSoi:
+ OJPEGWriteStreamSoi(tif,mem,len);
+ break;
+ case ososQTable0:
+ OJPEGWriteStreamQTable(tif,0,mem,len);
+ break;
+ case ososQTable1:
+ OJPEGWriteStreamQTable(tif,1,mem,len);
+ break;
+ case ososQTable2:
+ OJPEGWriteStreamQTable(tif,2,mem,len);
+ break;
+ case ososQTable3:
+ OJPEGWriteStreamQTable(tif,3,mem,len);
+ break;
+ case ososDcTable0:
+ OJPEGWriteStreamDcTable(tif,0,mem,len);
+ break;
+ case ososDcTable1:
+ OJPEGWriteStreamDcTable(tif,1,mem,len);
+ break;
+ case ososDcTable2:
+ OJPEGWriteStreamDcTable(tif,2,mem,len);
+ break;
+ case ososDcTable3:
+ OJPEGWriteStreamDcTable(tif,3,mem,len);
+ break;
+ case ososAcTable0:
+ OJPEGWriteStreamAcTable(tif,0,mem,len);
+ break;
+ case ososAcTable1:
+ OJPEGWriteStreamAcTable(tif,1,mem,len);
+ break;
+ case ososAcTable2:
+ OJPEGWriteStreamAcTable(tif,2,mem,len);
+ break;
+ case ososAcTable3:
+ OJPEGWriteStreamAcTable(tif,3,mem,len);
+ break;
+ case ososDri:
+ OJPEGWriteStreamDri(tif,mem,len);
+ break;
+ case ososSof:
+ OJPEGWriteStreamSof(tif,mem,len);
+ break;
+ case ososSos:
+ OJPEGWriteStreamSos(tif,mem,len);
+ break;
+ case ososCompressed:
+ if (OJPEGWriteStreamCompressed(tif,mem,len)==0)
+ return(0);
+ break;
+ case ososRst:
+ OJPEGWriteStreamRst(tif,mem,len);
+ break;
+ case ososEoi:
+ OJPEGWriteStreamEoi(tif,mem,len);
+ break;
+ }
+ } while (*len==0);
+ return(1);
+}
+
+static void
+OJPEGWriteStreamSoi(TIFF* tif, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ assert(OJPEG_BUFFER>=2);
+ sp->out_buffer[0]=255;
+ sp->out_buffer[1]=JPEG_MARKER_SOI;
+ *len=2;
+ *mem=(void*)sp->out_buffer;
+ sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamQTable(TIFF* tif, uint8 table_index, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ if (sp->qtable[table_index]!=0)
+ {
+ *mem=(void*)(sp->qtable[table_index]+sizeof(uint32));
+ *len=*((uint32*)sp->qtable[table_index])-sizeof(uint32);
+ }
+ sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamDcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ if (sp->dctable[table_index]!=0)
+ {
+ *mem=(void*)(sp->dctable[table_index]+sizeof(uint32));
+ *len=*((uint32*)sp->dctable[table_index])-sizeof(uint32);
+ }
+ sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamAcTable(TIFF* tif, uint8 table_index, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ if (sp->actable[table_index]!=0)
+ {
+ *mem=(void*)(sp->actable[table_index]+sizeof(uint32));
+ *len=*((uint32*)sp->actable[table_index])-sizeof(uint32);
+ }
+ sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamDri(TIFF* tif, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ assert(OJPEG_BUFFER>=6);
+ if (sp->restart_interval!=0)
+ {
+ sp->out_buffer[0]=255;
+ sp->out_buffer[1]=JPEG_MARKER_DRI;
+ sp->out_buffer[2]=0;
+ sp->out_buffer[3]=4;
+ sp->out_buffer[4]=(sp->restart_interval>>8);
+ sp->out_buffer[5]=(sp->restart_interval&255);
+ *len=6;
+ *mem=(void*)sp->out_buffer;
+ }
+ sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamSof(TIFF* tif, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 m;
+ assert(OJPEG_BUFFER>=2+8+sp->samples_per_pixel_per_plane*3);
+ assert(255>=8+sp->samples_per_pixel_per_plane*3);
+ sp->out_buffer[0]=255;
+ sp->out_buffer[1]=sp->sof_marker_id;
+ /* Lf */
+ sp->out_buffer[2]=0;
+ sp->out_buffer[3]=8+sp->samples_per_pixel_per_plane*3;
+ /* P */
+ sp->out_buffer[4]=8;
+ /* Y */
+ sp->out_buffer[5]=(sp->sof_y>>8);
+ sp->out_buffer[6]=(sp->sof_y&255);
+ /* X */
+ sp->out_buffer[7]=(sp->sof_x>>8);
+ sp->out_buffer[8]=(sp->sof_x&255);
+ /* Nf */
+ sp->out_buffer[9]=sp->samples_per_pixel_per_plane;
+ for (m=0; m<sp->samples_per_pixel_per_plane; m++)
+ {
+ /* C */
+ sp->out_buffer[10+m*3]=sp->sof_c[sp->plane_sample_offset+m];
+ /* H and V */
+ sp->out_buffer[10+m*3+1]=sp->sof_hv[sp->plane_sample_offset+m];
+ /* Tq */
+ sp->out_buffer[10+m*3+2]=sp->sof_tq[sp->plane_sample_offset+m];
+ }
+ *len=10+sp->samples_per_pixel_per_plane*3;
+ *mem=(void*)sp->out_buffer;
+ sp->out_state++;
+}
+
+static void
+OJPEGWriteStreamSos(TIFF* tif, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ uint8 m;
+ assert(OJPEG_BUFFER>=2+6+sp->samples_per_pixel_per_plane*2);
+ assert(255>=6+sp->samples_per_pixel_per_plane*2);
+ sp->out_buffer[0]=255;
+ sp->out_buffer[1]=JPEG_MARKER_SOS;
+ /* Ls */
+ sp->out_buffer[2]=0;
+ sp->out_buffer[3]=6+sp->samples_per_pixel_per_plane*2;
+ /* Ns */
+ sp->out_buffer[4]=sp->samples_per_pixel_per_plane;
+ for (m=0; m<sp->samples_per_pixel_per_plane; m++)
+ {
+ /* Cs */
+ sp->out_buffer[5+m*2]=sp->sos_cs[sp->plane_sample_offset+m];
+ /* Td and Ta */
+ sp->out_buffer[5+m*2+1]=sp->sos_tda[sp->plane_sample_offset+m];
+ }
+ /* Ss */
+ sp->out_buffer[5+sp->samples_per_pixel_per_plane*2]=0;
+ /* Se */
+ sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+1]=63;
+ /* Ah and Al */
+ sp->out_buffer[5+sp->samples_per_pixel_per_plane*2+2]=0;
+ *len=8+sp->samples_per_pixel_per_plane*2;
+ *mem=(void*)sp->out_buffer;
+ sp->out_state++;
+}
+
+static int
+OJPEGWriteStreamCompressed(TIFF* tif, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ if (sp->in_buffer_togo==0)
+ {
+ if (OJPEGReadBufferFill(sp)==0)
+ return(0);
+ assert(sp->in_buffer_togo>0);
+ }
+ *len=sp->in_buffer_togo;
+ *mem=(void*)sp->in_buffer_cur;
+ sp->in_buffer_togo=0;
+ if (sp->in_buffer_file_togo==0)
+ {
+ switch(sp->in_buffer_source)
+ {
+ case osibsStrile:
+ if (sp->in_buffer_next_strile<sp->in_buffer_strile_count)
+ sp->out_state=ososRst;
+ else
+ sp->out_state=ososEoi;
+ break;
+ case osibsEof:
+ sp->out_state=ososEoi;
+ break;
+ default:
+ break;
+ }
+ }
+ return(1);
+}
+
+static void
+OJPEGWriteStreamRst(TIFF* tif, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ assert(OJPEG_BUFFER>=2);
+ sp->out_buffer[0]=255;
+ sp->out_buffer[1]=JPEG_MARKER_RST0+sp->restart_index;
+ sp->restart_index++;
+ if (sp->restart_index==8)
+ sp->restart_index=0;
+ *len=2;
+ *mem=(void*)sp->out_buffer;
+ sp->out_state=ososCompressed;
+}
+
+static void
+OJPEGWriteStreamEoi(TIFF* tif, void** mem, uint32* len)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ assert(OJPEG_BUFFER>=2);
+ sp->out_buffer[0]=255;
+ sp->out_buffer[1]=JPEG_MARKER_EOI;
+ *len=2;
+ *mem=(void*)sp->out_buffer;
+}
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_create_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo)
+{
+ return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_create_decompress(cinfo),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_header_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, uint8 require_image)
+{
+ return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_header(cinfo,require_image),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_start_decompress_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo)
+{
+ return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_start_decompress(cinfo),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_scanlines_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* scanlines, uint32 max_lines)
+{
+ return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_scanlines(cinfo,scanlines,max_lines),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static int
+jpeg_read_raw_data_encap(OJPEGState* sp, jpeg_decompress_struct* cinfo, void* data, uint32 max_lines)
+{
+ return(SETJMP(sp->exit_jmpbuf)?0:(jpeg_read_raw_data(cinfo,data,max_lines),1));
+}
+#endif
+
+#ifndef LIBJPEG_ENCAP_EXTERNAL
+static void
+jpeg_encap_unwind(TIFF* tif)
+{
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ LONGJMP(sp->exit_jmpbuf,1);
+}
+#endif
+
+static void
+OJPEGLibjpegJpegErrorMgrOutputMessage(jpeg_common_struct* cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message)(cinfo,buffer);
+ TIFFWarningExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg", "%s", buffer);
+}
+
+static void
+OJPEGLibjpegJpegErrorMgrErrorExit(jpeg_common_struct* cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message)(cinfo,buffer);
+ TIFFErrorExt(((TIFF*)(cinfo->client_data))->tif_clientdata,"LibJpeg", "%s", buffer);
+ jpeg_encap_unwind((TIFF*)(cinfo->client_data));
+}
+
+static void
+OJPEGLibjpegJpegSourceMgrInitSource(jpeg_decompress_struct* cinfo)
+{
+ (void)cinfo;
+}
+
+static boolean
+OJPEGLibjpegJpegSourceMgrFillInputBuffer(jpeg_decompress_struct* cinfo)
+{
+ TIFF* tif=(TIFF*)cinfo->client_data;
+ OJPEGState* sp=(OJPEGState*)tif->tif_data;
+ void* mem=0;
+ uint32 len=0;
+ if (OJPEGWriteStream(tif,&mem,&len)==0)
+ {
+ TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Premature end of JPEG data");
+ jpeg_encap_unwind(tif);
+ }
+ sp->libjpeg_jpeg_source_mgr.bytes_in_buffer=len;
+ sp->libjpeg_jpeg_source_mgr.next_input_byte=mem;
+ return(1);
+}
+
+static void
+OJPEGLibjpegJpegSourceMgrSkipInputData(jpeg_decompress_struct* cinfo, long num_bytes)
+{
+ TIFF* tif=(TIFF*)cinfo->client_data;
+ (void)num_bytes;
+ TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error");
+ jpeg_encap_unwind(tif);
+}
+
+static boolean
+OJPEGLibjpegJpegSourceMgrResyncToRestart(jpeg_decompress_struct* cinfo, int desired)
+{
+ TIFF* tif=(TIFF*)cinfo->client_data;
+ (void)desired;
+ TIFFErrorExt(tif->tif_clientdata,"LibJpeg","Unexpected error");
+ jpeg_encap_unwind(tif);
+ return(0);
+}
+
+static void
+OJPEGLibjpegJpegSourceMgrTermSource(jpeg_decompress_struct* cinfo)
+{
+ (void)cinfo;
+}
+
+#endif
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_open.c b/tiff/libtiff/tif_open.c
new file mode 100644
index 0000000..3b3b2ce
--- /dev/null
+++ b/tiff/libtiff/tif_open.c
@@ -0,0 +1,695 @@
+/* $Id: tif_open.c,v 1.33.2.1 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+static const long typemask[13] = {
+ (long)0L, /* TIFF_NOTYPE */
+ (long)0x000000ffL, /* TIFF_BYTE */
+ (long)0xffffffffL, /* TIFF_ASCII */
+ (long)0x0000ffffL, /* TIFF_SHORT */
+ (long)0xffffffffL, /* TIFF_LONG */
+ (long)0xffffffffL, /* TIFF_RATIONAL */
+ (long)0x000000ffL, /* TIFF_SBYTE */
+ (long)0x000000ffL, /* TIFF_UNDEFINED */
+ (long)0x0000ffffL, /* TIFF_SSHORT */
+ (long)0xffffffffL, /* TIFF_SLONG */
+ (long)0xffffffffL, /* TIFF_SRATIONAL */
+ (long)0xffffffffL, /* TIFF_FLOAT */
+ (long)0xffffffffL, /* TIFF_DOUBLE */
+};
+static const int bigTypeshift[13] = {
+ 0, /* TIFF_NOTYPE */
+ 24, /* TIFF_BYTE */
+ 0, /* TIFF_ASCII */
+ 16, /* TIFF_SHORT */
+ 0, /* TIFF_LONG */
+ 0, /* TIFF_RATIONAL */
+ 24, /* TIFF_SBYTE */
+ 24, /* TIFF_UNDEFINED */
+ 16, /* TIFF_SSHORT */
+ 0, /* TIFF_SLONG */
+ 0, /* TIFF_SRATIONAL */
+ 0, /* TIFF_FLOAT */
+ 0, /* TIFF_DOUBLE */
+};
+static const int litTypeshift[13] = {
+ 0, /* TIFF_NOTYPE */
+ 0, /* TIFF_BYTE */
+ 0, /* TIFF_ASCII */
+ 0, /* TIFF_SHORT */
+ 0, /* TIFF_LONG */
+ 0, /* TIFF_RATIONAL */
+ 0, /* TIFF_SBYTE */
+ 0, /* TIFF_UNDEFINED */
+ 0, /* TIFF_SSHORT */
+ 0, /* TIFF_SLONG */
+ 0, /* TIFF_SRATIONAL */
+ 0, /* TIFF_FLOAT */
+ 0, /* TIFF_DOUBLE */
+};
+
+/*
+ * Dummy functions to fill the omitted client procedures.
+ */
+static int
+_tiffDummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ (void) fd; (void) pbase; (void) psize;
+ return (0);
+}
+
+static void
+_tiffDummyUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+ (void) fd; (void) base; (void) size;
+}
+
+/*
+ * Initialize the shift & mask tables, and the
+ * byte swapping state according to the file
+ * contents and the machine architecture.
+ */
+static void
+TIFFInitOrder(TIFF* tif, int magic)
+{
+ tif->tif_typemask = typemask;
+ if (magic == TIFF_BIGENDIAN) {
+ tif->tif_typeshift = bigTypeshift;
+#ifndef WORDS_BIGENDIAN
+ tif->tif_flags |= TIFF_SWAB;
+#endif
+ } else {
+ tif->tif_typeshift = litTypeshift;
+#ifdef WORDS_BIGENDIAN
+ tif->tif_flags |= TIFF_SWAB;
+#endif
+ }
+}
+
+int
+_TIFFgetMode(const char* mode, const char* module)
+{
+ int m = -1;
+
+ switch (mode[0]) {
+ case 'r':
+ m = O_RDONLY;
+ if (mode[1] == '+')
+ m = O_RDWR;
+ break;
+ case 'w':
+ case 'a':
+ m = O_RDWR|O_CREAT;
+ if (mode[0] == 'w')
+ m |= O_TRUNC;
+ break;
+ default:
+ TIFFErrorExt(0, module, "\"%s\": Bad mode", mode);
+ break;
+ }
+ return (m);
+}
+
+TIFF*
+TIFFClientOpen(
+ const char* name, const char* mode,
+ thandle_t clientdata,
+ TIFFReadWriteProc readproc,
+ TIFFReadWriteProc writeproc,
+ TIFFSeekProc seekproc,
+ TIFFCloseProc closeproc,
+ TIFFSizeProc sizeproc,
+ TIFFMapFileProc mapproc,
+ TIFFUnmapFileProc unmapproc
+)
+{
+ static const char module[] = "TIFFClientOpen";
+ TIFF *tif;
+ int m;
+ const char* cp;
+
+ m = _TIFFgetMode(mode, module);
+ if (m == -1)
+ goto bad2;
+ tif = (TIFF *)_TIFFmalloc(sizeof (TIFF) + strlen(name) + 1);
+ if (tif == NULL) {
+ TIFFErrorExt(clientdata, module, "%s: Out of memory (TIFF structure)", name);
+ goto bad2;
+ }
+ _TIFFmemset(tif, 0, sizeof (*tif));
+ tif->tif_name = (char *)tif + sizeof (TIFF);
+ strcpy(tif->tif_name, name);
+ tif->tif_mode = m &~ (O_CREAT|O_TRUNC);
+ tif->tif_curdir = (tdir_t) -1; /* non-existent directory */
+ tif->tif_curoff = 0;
+ tif->tif_curstrip = (tstrip_t) -1; /* invalid strip */
+ tif->tif_row = (uint32) -1; /* read/write pre-increment */
+ tif->tif_clientdata = clientdata;
+ if (!readproc || !writeproc || !seekproc || !closeproc || !sizeproc) {
+ TIFFErrorExt(clientdata, module,
+ "One of the client procedures is NULL pointer.");
+ goto bad2;
+ }
+ tif->tif_readproc = readproc;
+ tif->tif_writeproc = writeproc;
+ tif->tif_seekproc = seekproc;
+ tif->tif_closeproc = closeproc;
+ tif->tif_sizeproc = sizeproc;
+ if (mapproc)
+ tif->tif_mapproc = mapproc;
+ else
+ tif->tif_mapproc = _tiffDummyMapProc;
+ if (unmapproc)
+ tif->tif_unmapproc = unmapproc;
+ else
+ tif->tif_unmapproc = _tiffDummyUnmapProc;
+ _TIFFSetDefaultCompressionState(tif); /* setup default state */
+ /*
+ * Default is to return data MSB2LSB and enable the
+ * use of memory-mapped files and strip chopping when
+ * a file is opened read-only.
+ */
+ tif->tif_flags = FILLORDER_MSB2LSB;
+ if (m == O_RDONLY )
+ tif->tif_flags |= TIFF_MAPPED;
+
+#ifdef STRIPCHOP_DEFAULT
+ if (m == O_RDONLY || m == O_RDWR)
+ tif->tif_flags |= STRIPCHOP_DEFAULT;
+#endif
+
+ /*
+ * Process library-specific flags in the open mode string.
+ * The following flags may be used to control intrinsic library
+ * behaviour that may or may not be desirable (usually for
+ * compatibility with some application that claims to support
+ * TIFF but only supports some braindead idea of what the
+ * vendor thinks TIFF is):
+ *
+ * 'l' use little-endian byte order for creating a file
+ * 'b' use big-endian byte order for creating a file
+ * 'L' read/write information using LSB2MSB bit order
+ * 'B' read/write information using MSB2LSB bit order
+ * 'H' read/write information using host bit order
+ * 'M' enable use of memory-mapped files when supported
+ * 'm' disable use of memory-mapped files
+ * 'C' enable strip chopping support when reading
+ * 'c' disable strip chopping support
+ * 'h' read TIFF header only, do not load the first IFD
+ *
+ * The use of the 'l' and 'b' flags is strongly discouraged.
+ * These flags are provided solely because numerous vendors,
+ * typically on the PC, do not correctly support TIFF; they
+ * only support the Intel little-endian byte order. This
+ * support is not configured by default because it supports
+ * the violation of the TIFF spec that says that readers *MUST*
+ * support both byte orders. It is strongly recommended that
+ * you not use this feature except to deal with busted apps
+ * that write invalid TIFF. And even in those cases you should
+ * bang on the vendors to fix their software.
+ *
+ * The 'L', 'B', and 'H' flags are intended for applications
+ * that can optimize operations on data by using a particular
+ * bit order. By default the library returns data in MSB2LSB
+ * bit order for compatibiltiy with older versions of this
+ * library. Returning data in the bit order of the native cpu
+ * makes the most sense but also requires applications to check
+ * the value of the FillOrder tag; something they probably do
+ * not do right now.
+ *
+ * The 'M' and 'm' flags are provided because some virtual memory
+ * systems exhibit poor behaviour when large images are mapped.
+ * These options permit clients to control the use of memory-mapped
+ * files on a per-file basis.
+ *
+ * The 'C' and 'c' flags are provided because the library support
+ * for chopping up large strips into multiple smaller strips is not
+ * application-transparent and as such can cause problems. The 'c'
+ * option permits applications that only want to look at the tags,
+ * for example, to get the unadulterated TIFF tag information.
+ */
+ for (cp = mode; *cp; cp++)
+ switch (*cp) {
+ case 'b':
+#ifndef WORDS_BIGENDIAN
+ if (m&O_CREAT)
+ tif->tif_flags |= TIFF_SWAB;
+#endif
+ break;
+ case 'l':
+#ifdef WORDS_BIGENDIAN
+ if ((m&O_CREAT))
+ tif->tif_flags |= TIFF_SWAB;
+#endif
+ break;
+ case 'B':
+ tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+ FILLORDER_MSB2LSB;
+ break;
+ case 'L':
+ tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+ FILLORDER_LSB2MSB;
+ break;
+ case 'H':
+ tif->tif_flags = (tif->tif_flags &~ TIFF_FILLORDER) |
+ HOST_FILLORDER;
+ break;
+ case 'M':
+ if (m == O_RDONLY)
+ tif->tif_flags |= TIFF_MAPPED;
+ break;
+ case 'm':
+ if (m == O_RDONLY)
+ tif->tif_flags &= ~TIFF_MAPPED;
+ break;
+ case 'C':
+ if (m == O_RDONLY)
+ tif->tif_flags |= TIFF_STRIPCHOP;
+ break;
+ case 'c':
+ if (m == O_RDONLY)
+ tif->tif_flags &= ~TIFF_STRIPCHOP;
+ break;
+ case 'h':
+ tif->tif_flags |= TIFF_HEADERONLY;
+ break;
+ }
+ /*
+ * Read in TIFF header.
+ */
+ if (tif->tif_mode & O_TRUNC ||
+ !ReadOK(tif, &tif->tif_header, sizeof (TIFFHeader))) {
+ if (tif->tif_mode == O_RDONLY) {
+ TIFFErrorExt(tif->tif_clientdata, name,
+ "Cannot read TIFF header");
+ goto bad;
+ }
+ /*
+ * Setup header and write.
+ */
+#ifdef WORDS_BIGENDIAN
+ tif->tif_header.tiff_magic = tif->tif_flags & TIFF_SWAB
+ ? TIFF_LITTLEENDIAN : TIFF_BIGENDIAN;
+#else
+ tif->tif_header.tiff_magic = tif->tif_flags & TIFF_SWAB
+ ? TIFF_BIGENDIAN : TIFF_LITTLEENDIAN;
+#endif
+ tif->tif_header.tiff_version = TIFF_VERSION;
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabShort(&tif->tif_header.tiff_version);
+ tif->tif_header.tiff_diroff = 0; /* filled in later */
+
+
+ /*
+ * The doc for "fopen" for some STD_C_LIBs says that if you
+ * open a file for modify ("+"), then you must fseek (or
+ * fflush?) between any freads and fwrites. This is not
+ * necessary on most systems, but has been shown to be needed
+ * on Solaris.
+ */
+ TIFFSeekFile( tif, 0, SEEK_SET );
+
+ if (!WriteOK(tif, &tif->tif_header, sizeof (TIFFHeader))) {
+ TIFFErrorExt(tif->tif_clientdata, name,
+ "Error writing TIFF header");
+ goto bad;
+ }
+ /*
+ * Setup the byte order handling.
+ */
+ TIFFInitOrder(tif, tif->tif_header.tiff_magic);
+ /*
+ * Setup default directory.
+ */
+ if (!TIFFDefaultDirectory(tif))
+ goto bad;
+ tif->tif_diroff = 0;
+ tif->tif_dirlist = NULL;
+ tif->tif_dirlistsize = 0;
+ tif->tif_dirnumber = 0;
+ return (tif);
+ }
+ /*
+ * Setup the byte order handling.
+ */
+ if (tif->tif_header.tiff_magic != TIFF_BIGENDIAN &&
+ tif->tif_header.tiff_magic != TIFF_LITTLEENDIAN
+#if MDI_SUPPORT
+ &&
+#if HOST_BIGENDIAN
+ tif->tif_header.tiff_magic != MDI_BIGENDIAN
+#else
+ tif->tif_header.tiff_magic != MDI_LITTLEENDIAN
+#endif
+ ) {
+ TIFFErrorExt(tif->tif_clientdata, name,
+ "Not a TIFF or MDI file, bad magic number %d (0x%x)",
+#else
+ ) {
+ TIFFErrorExt(tif->tif_clientdata, name,
+ "Not a TIFF file, bad magic number %d (0x%x)",
+#endif
+ tif->tif_header.tiff_magic,
+ tif->tif_header.tiff_magic);
+ goto bad;
+ }
+ TIFFInitOrder(tif, tif->tif_header.tiff_magic);
+ /*
+ * Swap header if required.
+ */
+ if (tif->tif_flags & TIFF_SWAB) {
+ TIFFSwabShort(&tif->tif_header.tiff_version);
+ TIFFSwabLong(&tif->tif_header.tiff_diroff);
+ }
+ /*
+ * Now check version (if needed, it's been byte-swapped).
+ * Note that this isn't actually a version number, it's a
+ * magic number that doesn't change (stupid).
+ */
+ if (tif->tif_header.tiff_version == TIFF_BIGTIFF_VERSION) {
+ TIFFErrorExt(tif->tif_clientdata, name,
+ "This is a BigTIFF file. This format not supported\n"
+ "by this version of libtiff." );
+ goto bad;
+ }
+ if (tif->tif_header.tiff_version != TIFF_VERSION) {
+ TIFFErrorExt(tif->tif_clientdata, name,
+ "Not a TIFF file, bad version number %d (0x%x)",
+ tif->tif_header.tiff_version,
+ tif->tif_header.tiff_version);
+ goto bad;
+ }
+ tif->tif_flags |= TIFF_MYBUFFER;
+ tif->tif_rawcp = tif->tif_rawdata = 0;
+ tif->tif_rawdatasize = 0;
+
+ /*
+ * Sometimes we do not want to read the first directory (for example,
+ * it may be broken) and want to proceed to other directories. I this
+ * case we use the TIFF_HEADERONLY flag to open file and return
+ * immediately after reading TIFF header.
+ */
+ if (tif->tif_flags & TIFF_HEADERONLY)
+ return (tif);
+
+ /*
+ * Setup initial directory.
+ */
+ switch (mode[0]) {
+ case 'r':
+ tif->tif_nextdiroff = tif->tif_header.tiff_diroff;
+ /*
+ * Try to use a memory-mapped file if the client
+ * has not explicitly suppressed usage with the
+ * 'm' flag in the open mode (see above).
+ */
+ if ((tif->tif_flags & TIFF_MAPPED) &&
+ !TIFFMapFileContents(tif, (tdata_t*) &tif->tif_base, &tif->tif_size))
+ tif->tif_flags &= ~TIFF_MAPPED;
+ if (TIFFReadDirectory(tif)) {
+ tif->tif_rawcc = -1;
+ tif->tif_flags |= TIFF_BUFFERSETUP;
+ return (tif);
+ }
+ break;
+ case 'a':
+ /*
+ * New directories are automatically append
+ * to the end of the directory chain when they
+ * are written out (see TIFFWriteDirectory).
+ */
+ if (!TIFFDefaultDirectory(tif))
+ goto bad;
+ return (tif);
+ }
+bad:
+ tif->tif_mode = O_RDONLY; /* XXX avoid flush */
+ TIFFCleanup(tif);
+bad2:
+ return ((TIFF*)0);
+}
+
+/*
+ * Query functions to access private data.
+ */
+
+/*
+ * Return open file's name.
+ */
+const char *
+TIFFFileName(TIFF* tif)
+{
+ return (tif->tif_name);
+}
+
+/*
+ * Set the file name.
+ */
+const char *
+TIFFSetFileName(TIFF* tif, const char *name)
+{
+ const char* old_name = tif->tif_name;
+ tif->tif_name = (char *)name;
+ return (old_name);
+}
+
+/*
+ * Return open file's I/O descriptor.
+ */
+int
+TIFFFileno(TIFF* tif)
+{
+ return (tif->tif_fd);
+}
+
+/*
+ * Set open file's I/O descriptor, and return previous value.
+ */
+int
+TIFFSetFileno(TIFF* tif, int fd)
+{
+ int old_fd = tif->tif_fd;
+ tif->tif_fd = fd;
+ return old_fd;
+}
+
+/*
+ * Return open file's clientdata.
+ */
+thandle_t
+TIFFClientdata(TIFF* tif)
+{
+ return (tif->tif_clientdata);
+}
+
+/*
+ * Set open file's clientdata, and return previous value.
+ */
+thandle_t
+TIFFSetClientdata(TIFF* tif, thandle_t newvalue)
+{
+ thandle_t m = tif->tif_clientdata;
+ tif->tif_clientdata = newvalue;
+ return m;
+}
+
+/*
+ * Return read/write mode.
+ */
+int
+TIFFGetMode(TIFF* tif)
+{
+ return (tif->tif_mode);
+}
+
+/*
+ * Return read/write mode.
+ */
+int
+TIFFSetMode(TIFF* tif, int mode)
+{
+ int old_mode = tif->tif_mode;
+ tif->tif_mode = mode;
+ return (old_mode);
+}
+
+/*
+ * Return nonzero if file is organized in
+ * tiles; zero if organized as strips.
+ */
+int
+TIFFIsTiled(TIFF* tif)
+{
+ return (isTiled(tif));
+}
+
+/*
+ * Return current row being read/written.
+ */
+uint32
+TIFFCurrentRow(TIFF* tif)
+{
+ return (tif->tif_row);
+}
+
+/*
+ * Return index of the current directory.
+ */
+tdir_t
+TIFFCurrentDirectory(TIFF* tif)
+{
+ return (tif->tif_curdir);
+}
+
+/*
+ * Return current strip.
+ */
+tstrip_t
+TIFFCurrentStrip(TIFF* tif)
+{
+ return (tif->tif_curstrip);
+}
+
+/*
+ * Return current tile.
+ */
+ttile_t
+TIFFCurrentTile(TIFF* tif)
+{
+ return (tif->tif_curtile);
+}
+
+/*
+ * Return nonzero if the file has byte-swapped data.
+ */
+int
+TIFFIsByteSwapped(TIFF* tif)
+{
+ return ((tif->tif_flags & TIFF_SWAB) != 0);
+}
+
+/*
+ * Return nonzero if the data is returned up-sampled.
+ */
+int
+TIFFIsUpSampled(TIFF* tif)
+{
+ return (isUpSampled(tif));
+}
+
+/*
+ * Return nonzero if the data is returned in MSB-to-LSB bit order.
+ */
+int
+TIFFIsMSB2LSB(TIFF* tif)
+{
+ return (isFillOrder(tif, FILLORDER_MSB2LSB));
+}
+
+/*
+ * Return nonzero if given file was written in big-endian order.
+ */
+int
+TIFFIsBigEndian(TIFF* tif)
+{
+ return (tif->tif_header.tiff_magic == TIFF_BIGENDIAN);
+}
+
+/*
+ * Return pointer to file read method.
+ */
+TIFFReadWriteProc
+TIFFGetReadProc(TIFF* tif)
+{
+ return (tif->tif_readproc);
+}
+
+/*
+ * Return pointer to file write method.
+ */
+TIFFReadWriteProc
+TIFFGetWriteProc(TIFF* tif)
+{
+ return (tif->tif_writeproc);
+}
+
+/*
+ * Return pointer to file seek method.
+ */
+TIFFSeekProc
+TIFFGetSeekProc(TIFF* tif)
+{
+ return (tif->tif_seekproc);
+}
+
+/*
+ * Return pointer to file close method.
+ */
+TIFFCloseProc
+TIFFGetCloseProc(TIFF* tif)
+{
+ return (tif->tif_closeproc);
+}
+
+/*
+ * Return pointer to file size requesting method.
+ */
+TIFFSizeProc
+TIFFGetSizeProc(TIFF* tif)
+{
+ return (tif->tif_sizeproc);
+}
+
+/*
+ * Return pointer to memory mapping method.
+ */
+TIFFMapFileProc
+TIFFGetMapFileProc(TIFF* tif)
+{
+ return (tif->tif_mapproc);
+}
+
+/*
+ * Return pointer to memory unmapping method.
+ */
+TIFFUnmapFileProc
+TIFFGetUnmapFileProc(TIFF* tif)
+{
+ return (tif->tif_unmapproc);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_packbits.c b/tiff/libtiff/tif_packbits.c
new file mode 100644
index 0000000..ee095f5
--- /dev/null
+++ b/tiff/libtiff/tif_packbits.c
@@ -0,0 +1,300 @@
+/* $Id: tif_packbits.c,v 1.13.2.2 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef PACKBITS_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * PackBits Compression Algorithm Support
+ */
+#include <stdio.h>
+
+static int
+PackBitsPreEncode(TIFF* tif, tsample_t s)
+{
+ (void) s;
+
+ if (!(tif->tif_data = (tidata_t)_TIFFmalloc(sizeof(tsize_t))))
+ return (0);
+ /*
+ * Calculate the scanline/tile-width size in bytes.
+ */
+ if (isTiled(tif))
+ *(tsize_t*)tif->tif_data = TIFFTileRowSize(tif);
+ else
+ *(tsize_t*)tif->tif_data = TIFFScanlineSize(tif);
+ return (1);
+}
+
+static int
+PackBitsPostEncode(TIFF* tif)
+{
+ if (tif->tif_data)
+ _TIFFfree(tif->tif_data);
+ return (1);
+}
+
+/*
+ * NB: tidata is the type representing *(tidata_t);
+ * if tidata_t is made signed then this type must
+ * be adjusted accordingly.
+ */
+typedef unsigned char tidata;
+
+/*
+ * Encode a run of pixels.
+ */
+static int
+PackBitsEncode(TIFF* tif, tidata_t buf, tsize_t cc, tsample_t s)
+{
+ unsigned char* bp = (unsigned char*) buf;
+ tidata_t op, ep, lastliteral;
+ long n, slop;
+ int b;
+ enum { BASE, LITERAL, RUN, LITERAL_RUN } state;
+
+ (void) s;
+ op = tif->tif_rawcp;
+ ep = tif->tif_rawdata + tif->tif_rawdatasize;
+ state = BASE;
+ lastliteral = 0;
+ while (cc > 0) {
+ /*
+ * Find the longest string of identical bytes.
+ */
+ b = *bp++, cc--, n = 1;
+ for (; cc > 0 && b == *bp; cc--, bp++)
+ n++;
+ again:
+ if (op + 2 >= ep) { /* insure space for new data */
+ /*
+ * Be careful about writing the last
+ * literal. Must write up to that point
+ * and then copy the remainder to the
+ * front of the buffer.
+ */
+ if (state == LITERAL || state == LITERAL_RUN) {
+ slop = op - lastliteral;
+ tif->tif_rawcc += lastliteral - tif->tif_rawcp;
+ if (!TIFFFlushData1(tif))
+ return (-1);
+ op = tif->tif_rawcp;
+ while (slop-- > 0)
+ *op++ = *lastliteral++;
+ lastliteral = tif->tif_rawcp;
+ } else {
+ tif->tif_rawcc += op - tif->tif_rawcp;
+ if (!TIFFFlushData1(tif))
+ return (-1);
+ op = tif->tif_rawcp;
+ }
+ }
+ switch (state) {
+ case BASE: /* initial state, set run/literal */
+ if (n > 1) {
+ state = RUN;
+ if (n > 128) {
+ *op++ = (tidata) -127;
+ *op++ = (tidataval_t) b;
+ n -= 128;
+ goto again;
+ }
+ *op++ = (tidataval_t)(-(n-1));
+ *op++ = (tidataval_t) b;
+ } else {
+ lastliteral = op;
+ *op++ = 0;
+ *op++ = (tidataval_t) b;
+ state = LITERAL;
+ }
+ break;
+ case LITERAL: /* last object was literal string */
+ if (n > 1) {
+ state = LITERAL_RUN;
+ if (n > 128) {
+ *op++ = (tidata) -127;
+ *op++ = (tidataval_t) b;
+ n -= 128;
+ goto again;
+ }
+ *op++ = (tidataval_t)(-(n-1)); /* encode run */
+ *op++ = (tidataval_t) b;
+ } else { /* extend literal */
+ if (++(*lastliteral) == 127)
+ state = BASE;
+ *op++ = (tidataval_t) b;
+ }
+ break;
+ case RUN: /* last object was run */
+ if (n > 1) {
+ if (n > 128) {
+ *op++ = (tidata) -127;
+ *op++ = (tidataval_t) b;
+ n -= 128;
+ goto again;
+ }
+ *op++ = (tidataval_t)(-(n-1));
+ *op++ = (tidataval_t) b;
+ } else {
+ lastliteral = op;
+ *op++ = 0;
+ *op++ = (tidataval_t) b;
+ state = LITERAL;
+ }
+ break;
+ case LITERAL_RUN: /* literal followed by a run */
+ /*
+ * Check to see if previous run should
+ * be converted to a literal, in which
+ * case we convert literal-run-literal
+ * to a single literal.
+ */
+ if (n == 1 && op[-2] == (tidata) -1 &&
+ *lastliteral < 126) {
+ state = (((*lastliteral) += 2) == 127 ?
+ BASE : LITERAL);
+ op[-2] = op[-1]; /* replicate */
+ } else
+ state = RUN;
+ goto again;
+ }
+ }
+ tif->tif_rawcc += op - tif->tif_rawcp;
+ tif->tif_rawcp = op;
+ return (1);
+}
+
+/*
+ * Encode a rectangular chunk of pixels. We break it up
+ * into row-sized pieces to insure that encoded runs do
+ * not span rows. Otherwise, there can be problems with
+ * the decoder if data is read, for example, by scanlines
+ * when it was encoded by strips.
+ */
+static int
+PackBitsEncodeChunk(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ tsize_t rowsize = *(tsize_t*)tif->tif_data;
+
+ while ((long)cc > 0) {
+ int chunk = rowsize;
+
+ if( cc < chunk )
+ chunk = cc;
+
+ if (PackBitsEncode(tif, bp, chunk, s) < 0)
+ return (-1);
+ bp += chunk;
+ cc -= chunk;
+ }
+ return (1);
+}
+
+static int
+PackBitsDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
+{
+ char *bp;
+ tsize_t cc;
+ long n;
+ int b;
+
+ (void) s;
+ bp = (char*) tif->tif_rawcp;
+ cc = tif->tif_rawcc;
+ while (cc > 0 && (long)occ > 0) {
+ n = (long) *bp++, cc--;
+ /*
+ * Watch out for compilers that
+ * don't sign extend chars...
+ */
+ if (n >= 128)
+ n -= 256;
+ if (n < 0) { /* replicate next byte -n+1 times */
+ if (n == -128) /* nop */
+ continue;
+ n = -n + 1;
+ if( occ < n )
+ {
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "PackBitsDecode: discarding %ld bytes "
+ "to avoid buffer overrun",
+ n - occ);
+ n = occ;
+ }
+ occ -= n;
+ b = *bp++, cc--;
+ while (n-- > 0)
+ *op++ = (tidataval_t) b;
+ } else { /* copy next n+1 bytes literally */
+ if (occ < n + 1)
+ {
+ TIFFWarningExt(tif->tif_clientdata, tif->tif_name,
+ "PackBitsDecode: discarding %ld bytes "
+ "to avoid buffer overrun",
+ n - occ + 1);
+ n = occ - 1;
+ }
+ _TIFFmemcpy(op, bp, ++n);
+ op += n; occ -= n;
+ bp += n; cc -= n;
+ }
+ }
+ tif->tif_rawcp = (tidata_t) bp;
+ tif->tif_rawcc = cc;
+ if (occ > 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "PackBitsDecode: Not enough data for scanline %ld",
+ (long) tif->tif_row);
+ return (0);
+ }
+ return (1);
+}
+
+int
+TIFFInitPackBits(TIFF* tif, int scheme)
+{
+ (void) scheme;
+ tif->tif_decoderow = PackBitsDecode;
+ tif->tif_decodestrip = PackBitsDecode;
+ tif->tif_decodetile = PackBitsDecode;
+ tif->tif_preencode = PackBitsPreEncode;
+ tif->tif_postencode = PackBitsPostEncode;
+ tif->tif_encoderow = PackBitsEncode;
+ tif->tif_encodestrip = PackBitsEncodeChunk;
+ tif->tif_encodetile = PackBitsEncodeChunk;
+ return (1);
+}
+#endif /* PACKBITS_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_pixarlog.c b/tiff/libtiff/tif_pixarlog.c
new file mode 100644
index 0000000..ed8eb40
--- /dev/null
+++ b/tiff/libtiff/tif_pixarlog.c
@@ -0,0 +1,1371 @@
+/* $Id: tif_pixarlog.c,v 1.15.2.4 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1996-1997 Sam Leffler
+ * Copyright (c) 1996 Pixar
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Pixar, Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Pixar, Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL PIXAR, SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef PIXARLOG_SUPPORT
+
+/*
+ * TIFF Library.
+ * PixarLog Compression Support
+ *
+ * Contributed by Dan McCoy.
+ *
+ * PixarLog film support uses the TIFF library to store companded
+ * 11 bit values into a tiff file, which are compressed using the
+ * zip compressor.
+ *
+ * The codec can take as input and produce as output 32-bit IEEE float values
+ * as well as 16-bit or 8-bit unsigned integer values.
+ *
+ * On writing any of the above are converted into the internal
+ * 11-bit log format. In the case of 8 and 16 bit values, the
+ * input is assumed to be unsigned linear color values that represent
+ * the range 0-1. In the case of IEEE values, the 0-1 range is assumed to
+ * be the normal linear color range, in addition over 1 values are
+ * accepted up to a value of about 25.0 to encode "hot" hightlights and such.
+ * The encoding is lossless for 8-bit values, slightly lossy for the
+ * other bit depths. The actual color precision should be better
+ * than the human eye can perceive with extra room to allow for
+ * error introduced by further image computation. As with any quantized
+ * color format, it is possible to perform image calculations which
+ * expose the quantization error. This format should certainly be less
+ * susceptable to such errors than standard 8-bit encodings, but more
+ * susceptable than straight 16-bit or 32-bit encodings.
+ *
+ * On reading the internal format is converted to the desired output format.
+ * The program can request which format it desires by setting the internal
+ * pseudo tag TIFFTAG_PIXARLOGDATAFMT to one of these possible values:
+ * PIXARLOGDATAFMT_FLOAT = provide IEEE float values.
+ * PIXARLOGDATAFMT_16BIT = provide unsigned 16-bit integer values
+ * PIXARLOGDATAFMT_8BIT = provide unsigned 8-bit integer values
+ *
+ * alternately PIXARLOGDATAFMT_8BITABGR provides unsigned 8-bit integer
+ * values with the difference that if there are exactly three or four channels
+ * (rgb or rgba) it swaps the channel order (bgr or abgr).
+ *
+ * PIXARLOGDATAFMT_11BITLOG provides the internal encoding directly
+ * packed in 16-bit values. However no tools are supplied for interpreting
+ * these values.
+ *
+ * "hot" (over 1.0) areas written in floating point get clamped to
+ * 1.0 in the integer data types.
+ *
+ * When the file is closed after writing, the bit depth and sample format
+ * are set always to appear as if 8-bit data has been written into it.
+ * That way a naive program unaware of the particulars of the encoding
+ * gets the format it is most likely able to handle.
+ *
+ * The codec does it's own horizontal differencing step on the coded
+ * values so the libraries predictor stuff should be turned off.
+ * The codec also handle byte swapping the encoded values as necessary
+ * since the library does not have the information necessary
+ * to know the bit depth of the raw unencoded buffer.
+ *
+ */
+
+#include "tif_predict.h"
+#include "zlib.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+/* Tables for converting to/from 11 bit coded values */
+
+#define TSIZE 2048 /* decode table size (11-bit tokens) */
+#define TSIZEP1 2049 /* Plus one for slop */
+#define ONE 1250 /* token value of 1.0 exactly */
+#define RATIO 1.004 /* nominal ratio for log part */
+
+#define CODE_MASK 0x7ff /* 11 bits. */
+
+static float Fltsize;
+static float LogK1, LogK2;
+
+#define REPEAT(n, op) { int i; i=n; do { i--; op; } while (i>0); }
+
+static void
+horizontalAccumulateF(uint16 *wp, int n, int stride, float *op,
+ float *ToLinearF)
+{
+ register unsigned int cr, cg, cb, ca, mask;
+ register float t0, t1, t2, t3;
+
+ if (n >= stride) {
+ mask = CODE_MASK;
+ if (stride == 3) {
+ t0 = ToLinearF[cr = wp[0]];
+ t1 = ToLinearF[cg = wp[1]];
+ t2 = ToLinearF[cb = wp[2]];
+ op[0] = t0;
+ op[1] = t1;
+ op[2] = t2;
+ n -= 3;
+ while (n > 0) {
+ wp += 3;
+ op += 3;
+ n -= 3;
+ t0 = ToLinearF[(cr += wp[0]) & mask];
+ t1 = ToLinearF[(cg += wp[1]) & mask];
+ t2 = ToLinearF[(cb += wp[2]) & mask];
+ op[0] = t0;
+ op[1] = t1;
+ op[2] = t2;
+ }
+ } else if (stride == 4) {
+ t0 = ToLinearF[cr = wp[0]];
+ t1 = ToLinearF[cg = wp[1]];
+ t2 = ToLinearF[cb = wp[2]];
+ t3 = ToLinearF[ca = wp[3]];
+ op[0] = t0;
+ op[1] = t1;
+ op[2] = t2;
+ op[3] = t3;
+ n -= 4;
+ while (n > 0) {
+ wp += 4;
+ op += 4;
+ n -= 4;
+ t0 = ToLinearF[(cr += wp[0]) & mask];
+ t1 = ToLinearF[(cg += wp[1]) & mask];
+ t2 = ToLinearF[(cb += wp[2]) & mask];
+ t3 = ToLinearF[(ca += wp[3]) & mask];
+ op[0] = t0;
+ op[1] = t1;
+ op[2] = t2;
+ op[3] = t3;
+ }
+ } else {
+ REPEAT(stride, *op = ToLinearF[*wp&mask]; wp++; op++)
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride,
+ wp[stride] += *wp; *op = ToLinearF[*wp&mask]; wp++; op++)
+ n -= stride;
+ }
+ }
+ }
+}
+
+static void
+horizontalAccumulate12(uint16 *wp, int n, int stride, int16 *op,
+ float *ToLinearF)
+{
+ register unsigned int cr, cg, cb, ca, mask;
+ register float t0, t1, t2, t3;
+
+#define SCALE12 2048.0F
+#define CLAMP12(t) (((t) < 3071) ? (uint16) (t) : 3071)
+
+ if (n >= stride) {
+ mask = CODE_MASK;
+ if (stride == 3) {
+ t0 = ToLinearF[cr = wp[0]] * SCALE12;
+ t1 = ToLinearF[cg = wp[1]] * SCALE12;
+ t2 = ToLinearF[cb = wp[2]] * SCALE12;
+ op[0] = CLAMP12(t0);
+ op[1] = CLAMP12(t1);
+ op[2] = CLAMP12(t2);
+ n -= 3;
+ while (n > 0) {
+ wp += 3;
+ op += 3;
+ n -= 3;
+ t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12;
+ t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12;
+ t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12;
+ op[0] = CLAMP12(t0);
+ op[1] = CLAMP12(t1);
+ op[2] = CLAMP12(t2);
+ }
+ } else if (stride == 4) {
+ t0 = ToLinearF[cr = wp[0]] * SCALE12;
+ t1 = ToLinearF[cg = wp[1]] * SCALE12;
+ t2 = ToLinearF[cb = wp[2]] * SCALE12;
+ t3 = ToLinearF[ca = wp[3]] * SCALE12;
+ op[0] = CLAMP12(t0);
+ op[1] = CLAMP12(t1);
+ op[2] = CLAMP12(t2);
+ op[3] = CLAMP12(t3);
+ n -= 4;
+ while (n > 0) {
+ wp += 4;
+ op += 4;
+ n -= 4;
+ t0 = ToLinearF[(cr += wp[0]) & mask] * SCALE12;
+ t1 = ToLinearF[(cg += wp[1]) & mask] * SCALE12;
+ t2 = ToLinearF[(cb += wp[2]) & mask] * SCALE12;
+ t3 = ToLinearF[(ca += wp[3]) & mask] * SCALE12;
+ op[0] = CLAMP12(t0);
+ op[1] = CLAMP12(t1);
+ op[2] = CLAMP12(t2);
+ op[3] = CLAMP12(t3);
+ }
+ } else {
+ REPEAT(stride, t0 = ToLinearF[*wp&mask] * SCALE12;
+ *op = CLAMP12(t0); wp++; op++)
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride,
+ wp[stride] += *wp; t0 = ToLinearF[wp[stride]&mask]*SCALE12;
+ *op = CLAMP12(t0); wp++; op++)
+ n -= stride;
+ }
+ }
+ }
+}
+
+static void
+horizontalAccumulate16(uint16 *wp, int n, int stride, uint16 *op,
+ uint16 *ToLinear16)
+{
+ register unsigned int cr, cg, cb, ca, mask;
+
+ if (n >= stride) {
+ mask = CODE_MASK;
+ if (stride == 3) {
+ op[0] = ToLinear16[cr = wp[0]];
+ op[1] = ToLinear16[cg = wp[1]];
+ op[2] = ToLinear16[cb = wp[2]];
+ n -= 3;
+ while (n > 0) {
+ wp += 3;
+ op += 3;
+ n -= 3;
+ op[0] = ToLinear16[(cr += wp[0]) & mask];
+ op[1] = ToLinear16[(cg += wp[1]) & mask];
+ op[2] = ToLinear16[(cb += wp[2]) & mask];
+ }
+ } else if (stride == 4) {
+ op[0] = ToLinear16[cr = wp[0]];
+ op[1] = ToLinear16[cg = wp[1]];
+ op[2] = ToLinear16[cb = wp[2]];
+ op[3] = ToLinear16[ca = wp[3]];
+ n -= 4;
+ while (n > 0) {
+ wp += 4;
+ op += 4;
+ n -= 4;
+ op[0] = ToLinear16[(cr += wp[0]) & mask];
+ op[1] = ToLinear16[(cg += wp[1]) & mask];
+ op[2] = ToLinear16[(cb += wp[2]) & mask];
+ op[3] = ToLinear16[(ca += wp[3]) & mask];
+ }
+ } else {
+ REPEAT(stride, *op = ToLinear16[*wp&mask]; wp++; op++)
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride,
+ wp[stride] += *wp; *op = ToLinear16[*wp&mask]; wp++; op++)
+ n -= stride;
+ }
+ }
+ }
+}
+
+/*
+ * Returns the log encoded 11-bit values with the horizontal
+ * differencing undone.
+ */
+static void
+horizontalAccumulate11(uint16 *wp, int n, int stride, uint16 *op)
+{
+ register unsigned int cr, cg, cb, ca, mask;
+
+ if (n >= stride) {
+ mask = CODE_MASK;
+ if (stride == 3) {
+ op[0] = cr = wp[0]; op[1] = cg = wp[1]; op[2] = cb = wp[2];
+ n -= 3;
+ while (n > 0) {
+ wp += 3;
+ op += 3;
+ n -= 3;
+ op[0] = (cr += wp[0]) & mask;
+ op[1] = (cg += wp[1]) & mask;
+ op[2] = (cb += wp[2]) & mask;
+ }
+ } else if (stride == 4) {
+ op[0] = cr = wp[0]; op[1] = cg = wp[1];
+ op[2] = cb = wp[2]; op[3] = ca = wp[3];
+ n -= 4;
+ while (n > 0) {
+ wp += 4;
+ op += 4;
+ n -= 4;
+ op[0] = (cr += wp[0]) & mask;
+ op[1] = (cg += wp[1]) & mask;
+ op[2] = (cb += wp[2]) & mask;
+ op[3] = (ca += wp[3]) & mask;
+ }
+ } else {
+ REPEAT(stride, *op = *wp&mask; wp++; op++)
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride,
+ wp[stride] += *wp; *op = *wp&mask; wp++; op++)
+ n -= stride;
+ }
+ }
+ }
+}
+
+static void
+horizontalAccumulate8(uint16 *wp, int n, int stride, unsigned char *op,
+ unsigned char *ToLinear8)
+{
+ register unsigned int cr, cg, cb, ca, mask;
+
+ if (n >= stride) {
+ mask = CODE_MASK;
+ if (stride == 3) {
+ op[0] = ToLinear8[cr = wp[0]];
+ op[1] = ToLinear8[cg = wp[1]];
+ op[2] = ToLinear8[cb = wp[2]];
+ n -= 3;
+ while (n > 0) {
+ n -= 3;
+ wp += 3;
+ op += 3;
+ op[0] = ToLinear8[(cr += wp[0]) & mask];
+ op[1] = ToLinear8[(cg += wp[1]) & mask];
+ op[2] = ToLinear8[(cb += wp[2]) & mask];
+ }
+ } else if (stride == 4) {
+ op[0] = ToLinear8[cr = wp[0]];
+ op[1] = ToLinear8[cg = wp[1]];
+ op[2] = ToLinear8[cb = wp[2]];
+ op[3] = ToLinear8[ca = wp[3]];
+ n -= 4;
+ while (n > 0) {
+ n -= 4;
+ wp += 4;
+ op += 4;
+ op[0] = ToLinear8[(cr += wp[0]) & mask];
+ op[1] = ToLinear8[(cg += wp[1]) & mask];
+ op[2] = ToLinear8[(cb += wp[2]) & mask];
+ op[3] = ToLinear8[(ca += wp[3]) & mask];
+ }
+ } else {
+ REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++)
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride,
+ wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++)
+ n -= stride;
+ }
+ }
+ }
+}
+
+
+static void
+horizontalAccumulate8abgr(uint16 *wp, int n, int stride, unsigned char *op,
+ unsigned char *ToLinear8)
+{
+ register unsigned int cr, cg, cb, ca, mask;
+ register unsigned char t0, t1, t2, t3;
+
+ if (n >= stride) {
+ mask = CODE_MASK;
+ if (stride == 3) {
+ op[0] = 0;
+ t1 = ToLinear8[cb = wp[2]];
+ t2 = ToLinear8[cg = wp[1]];
+ t3 = ToLinear8[cr = wp[0]];
+ op[1] = t1;
+ op[2] = t2;
+ op[3] = t3;
+ n -= 3;
+ while (n > 0) {
+ n -= 3;
+ wp += 3;
+ op += 4;
+ op[0] = 0;
+ t1 = ToLinear8[(cb += wp[2]) & mask];
+ t2 = ToLinear8[(cg += wp[1]) & mask];
+ t3 = ToLinear8[(cr += wp[0]) & mask];
+ op[1] = t1;
+ op[2] = t2;
+ op[3] = t3;
+ }
+ } else if (stride == 4) {
+ t0 = ToLinear8[ca = wp[3]];
+ t1 = ToLinear8[cb = wp[2]];
+ t2 = ToLinear8[cg = wp[1]];
+ t3 = ToLinear8[cr = wp[0]];
+ op[0] = t0;
+ op[1] = t1;
+ op[2] = t2;
+ op[3] = t3;
+ n -= 4;
+ while (n > 0) {
+ n -= 4;
+ wp += 4;
+ op += 4;
+ t0 = ToLinear8[(ca += wp[3]) & mask];
+ t1 = ToLinear8[(cb += wp[2]) & mask];
+ t2 = ToLinear8[(cg += wp[1]) & mask];
+ t3 = ToLinear8[(cr += wp[0]) & mask];
+ op[0] = t0;
+ op[1] = t1;
+ op[2] = t2;
+ op[3] = t3;
+ }
+ } else {
+ REPEAT(stride, *op = ToLinear8[*wp&mask]; wp++; op++)
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride,
+ wp[stride] += *wp; *op = ToLinear8[*wp&mask]; wp++; op++)
+ n -= stride;
+ }
+ }
+ }
+}
+
+/*
+ * State block for each open TIFF
+ * file using PixarLog compression/decompression.
+ */
+typedef struct {
+ TIFFPredictorState predict;
+ z_stream stream;
+ uint16 *tbuf;
+ uint16 stride;
+ int state;
+ int user_datafmt;
+ int quality;
+#define PLSTATE_INIT 1
+
+ TIFFVSetMethod vgetparent; /* super-class method */
+ TIFFVSetMethod vsetparent; /* super-class method */
+
+ float *ToLinearF;
+ uint16 *ToLinear16;
+ unsigned char *ToLinear8;
+ uint16 *FromLT2;
+ uint16 *From14; /* Really for 16-bit data, but we shift down 2 */
+ uint16 *From8;
+
+} PixarLogState;
+
+static int
+PixarLogMakeTables(PixarLogState *sp)
+{
+
+/*
+ * We make several tables here to convert between various external
+ * representations (float, 16-bit, and 8-bit) and the internal
+ * 11-bit companded representation. The 11-bit representation has two
+ * distinct regions. A linear bottom end up through .018316 in steps
+ * of about .000073, and a region of constant ratio up to about 25.
+ * These floating point numbers are stored in the main table ToLinearF.
+ * All other tables are derived from this one. The tables (and the
+ * ratios) are continuous at the internal seam.
+ */
+
+ int nlin, lt2size;
+ int i, j;
+ double b, c, linstep, v;
+ float *ToLinearF;
+ uint16 *ToLinear16;
+ unsigned char *ToLinear8;
+ uint16 *FromLT2;
+ uint16 *From14; /* Really for 16-bit data, but we shift down 2 */
+ uint16 *From8;
+
+ c = log(RATIO);
+ nlin = (int)(1./c); /* nlin must be an integer */
+ c = 1./nlin;
+ b = exp(-c*ONE); /* multiplicative scale factor [b*exp(c*ONE) = 1] */
+ linstep = b*c*exp(1.);
+
+ LogK1 = (float)(1./c); /* if (v >= 2) token = k1*log(v*k2) */
+ LogK2 = (float)(1./b);
+ lt2size = (int)(2./linstep) + 1;
+ FromLT2 = (uint16 *)_TIFFmalloc(lt2size*sizeof(uint16));
+ From14 = (uint16 *)_TIFFmalloc(16384*sizeof(uint16));
+ From8 = (uint16 *)_TIFFmalloc(256*sizeof(uint16));
+ ToLinearF = (float *)_TIFFmalloc(TSIZEP1 * sizeof(float));
+ ToLinear16 = (uint16 *)_TIFFmalloc(TSIZEP1 * sizeof(uint16));
+ ToLinear8 = (unsigned char *)_TIFFmalloc(TSIZEP1 * sizeof(unsigned char));
+ if (FromLT2 == NULL || From14 == NULL || From8 == NULL ||
+ ToLinearF == NULL || ToLinear16 == NULL || ToLinear8 == NULL) {
+ if (FromLT2) _TIFFfree(FromLT2);
+ if (From14) _TIFFfree(From14);
+ if (From8) _TIFFfree(From8);
+ if (ToLinearF) _TIFFfree(ToLinearF);
+ if (ToLinear16) _TIFFfree(ToLinear16);
+ if (ToLinear8) _TIFFfree(ToLinear8);
+ sp->FromLT2 = NULL;
+ sp->From14 = NULL;
+ sp->From8 = NULL;
+ sp->ToLinearF = NULL;
+ sp->ToLinear16 = NULL;
+ sp->ToLinear8 = NULL;
+ return 0;
+ }
+
+ j = 0;
+
+ for (i = 0; i < nlin; i++) {
+ v = i * linstep;
+ ToLinearF[j++] = (float)v;
+ }
+
+ for (i = nlin; i < TSIZE; i++)
+ ToLinearF[j++] = (float)(b*exp(c*i));
+
+ ToLinearF[2048] = ToLinearF[2047];
+
+ for (i = 0; i < TSIZEP1; i++) {
+ v = ToLinearF[i]*65535.0 + 0.5;
+ ToLinear16[i] = (v > 65535.0) ? 65535 : (uint16)v;
+ v = ToLinearF[i]*255.0 + 0.5;
+ ToLinear8[i] = (v > 255.0) ? 255 : (unsigned char)v;
+ }
+
+ j = 0;
+ for (i = 0; i < lt2size; i++) {
+ if ((i*linstep)*(i*linstep) > ToLinearF[j]*ToLinearF[j+1])
+ j++;
+ FromLT2[i] = j;
+ }
+
+ /*
+ * Since we lose info anyway on 16-bit data, we set up a 14-bit
+ * table and shift 16-bit values down two bits on input.
+ * saves a little table space.
+ */
+ j = 0;
+ for (i = 0; i < 16384; i++) {
+ while ((i/16383.)*(i/16383.) > ToLinearF[j]*ToLinearF[j+1])
+ j++;
+ From14[i] = j;
+ }
+
+ j = 0;
+ for (i = 0; i < 256; i++) {
+ while ((i/255.)*(i/255.) > ToLinearF[j]*ToLinearF[j+1])
+ j++;
+ From8[i] = j;
+ }
+
+ Fltsize = (float)(lt2size/2);
+
+ sp->ToLinearF = ToLinearF;
+ sp->ToLinear16 = ToLinear16;
+ sp->ToLinear8 = ToLinear8;
+ sp->FromLT2 = FromLT2;
+ sp->From14 = From14;
+ sp->From8 = From8;
+
+ return 1;
+}
+
+#define DecoderState(tif) ((PixarLogState*) (tif)->tif_data)
+#define EncoderState(tif) ((PixarLogState*) (tif)->tif_data)
+
+static int PixarLogEncode(TIFF*, tidata_t, tsize_t, tsample_t);
+static int PixarLogDecode(TIFF*, tidata_t, tsize_t, tsample_t);
+
+#define PIXARLOGDATAFMT_UNKNOWN -1
+
+static int
+PixarLogGuessDataFmt(TIFFDirectory *td)
+{
+ int guess = PIXARLOGDATAFMT_UNKNOWN;
+ int format = td->td_sampleformat;
+
+ /* If the user didn't tell us his datafmt,
+ * take our best guess from the bitspersample.
+ */
+ switch (td->td_bitspersample) {
+ case 32:
+ if (format == SAMPLEFORMAT_IEEEFP)
+ guess = PIXARLOGDATAFMT_FLOAT;
+ break;
+ case 16:
+ if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+ guess = PIXARLOGDATAFMT_16BIT;
+ break;
+ case 12:
+ if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_INT)
+ guess = PIXARLOGDATAFMT_12BITPICIO;
+ break;
+ case 11:
+ if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+ guess = PIXARLOGDATAFMT_11BITLOG;
+ break;
+ case 8:
+ if (format == SAMPLEFORMAT_VOID || format == SAMPLEFORMAT_UINT)
+ guess = PIXARLOGDATAFMT_8BIT;
+ break;
+ }
+
+ return guess;
+}
+
+static uint32
+multiply(size_t m1, size_t m2)
+{
+ uint32 bytes = m1 * m2;
+
+ if (m1 && bytes / m1 != m2)
+ bytes = 0;
+
+ return bytes;
+}
+
+static int
+PixarLogSetupDecode(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ PixarLogState* sp = DecoderState(tif);
+ tsize_t tbuf_size;
+ static const char module[] = "PixarLogSetupDecode";
+
+ assert(sp != NULL);
+
+ /* Make sure no byte swapping happens on the data
+ * after decompression. */
+ tif->tif_postdecode = _TIFFNoPostDecode;
+
+ /* for some reason, we can't do this in TIFFInitPixarLog */
+
+ sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+ td->td_samplesperpixel : 1);
+ tbuf_size = multiply(multiply(multiply(sp->stride, td->td_imagewidth),
+ td->td_rowsperstrip), sizeof(uint16));
+ if (tbuf_size == 0)
+ return (0);
+ sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size);
+ if (sp->tbuf == NULL)
+ return (0);
+ if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
+ sp->user_datafmt = PixarLogGuessDataFmt(td);
+ if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "PixarLog compression can't handle bits depth/data format combination (depth: %d)",
+ td->td_bitspersample);
+ return (0);
+ }
+
+ if (inflateInit(&sp->stream) != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg);
+ return (0);
+ } else {
+ sp->state |= PLSTATE_INIT;
+ return (1);
+ }
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+PixarLogPreDecode(TIFF* tif, tsample_t s)
+{
+ PixarLogState* sp = DecoderState(tif);
+
+ (void) s;
+ assert(sp != NULL);
+ sp->stream.next_in = tif->tif_rawdata;
+ sp->stream.avail_in = tif->tif_rawcc;
+ return (inflateReset(&sp->stream) == Z_OK);
+}
+
+static int
+PixarLogDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ PixarLogState* sp = DecoderState(tif);
+ static const char module[] = "PixarLogDecode";
+ int i, nsamples, llen;
+ uint16 *up;
+
+ switch (sp->user_datafmt) {
+ case PIXARLOGDATAFMT_FLOAT:
+ nsamples = occ / sizeof(float); /* XXX float == 32 bits */
+ break;
+ case PIXARLOGDATAFMT_16BIT:
+ case PIXARLOGDATAFMT_12BITPICIO:
+ case PIXARLOGDATAFMT_11BITLOG:
+ nsamples = occ / sizeof(uint16); /* XXX uint16 == 16 bits */
+ break;
+ case PIXARLOGDATAFMT_8BIT:
+ case PIXARLOGDATAFMT_8BITABGR:
+ nsamples = occ;
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%d bit input not supported in PixarLog",
+ td->td_bitspersample);
+ return 0;
+ }
+
+ llen = sp->stride * td->td_imagewidth;
+
+ (void) s;
+ assert(sp != NULL);
+ sp->stream.next_out = (unsigned char *) sp->tbuf;
+ sp->stream.avail_out = nsamples * sizeof(uint16);
+ do {
+ int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
+ if (state == Z_STREAM_END) {
+ break; /* XXX */
+ }
+ if (state == Z_DATA_ERROR) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Decoding error at scanline %d, %s",
+ tif->tif_name, tif->tif_row, sp->stream.msg);
+ if (inflateSync(&sp->stream) != Z_OK)
+ return (0);
+ continue;
+ }
+ if (state != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s",
+ tif->tif_name, sp->stream.msg);
+ return (0);
+ }
+ } while (sp->stream.avail_out > 0);
+
+ /* hopefully, we got all the bytes we needed */
+ if (sp->stream.avail_out != 0) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Not enough data at scanline %d (short %d bytes)",
+ tif->tif_name, tif->tif_row, sp->stream.avail_out);
+ return (0);
+ }
+
+ up = sp->tbuf;
+ /* Swap bytes in the data if from a different endian machine. */
+ if (tif->tif_flags & TIFF_SWAB)
+ TIFFSwabArrayOfShort(up, nsamples);
+
+ /*
+ * if llen is not an exact multiple of nsamples, the decode operation
+ * may overflow the output buffer, so truncate it enough to prevent
+ * that but still salvage as much data as possible.
+ */
+ if (nsamples % llen) {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "%s: stride %d is not a multiple of sample count, "
+ "%d, data truncated.", tif->tif_name, llen, nsamples);
+ nsamples -= nsamples % llen;
+ }
+
+ for (i = 0; i < nsamples; i += llen, up += llen) {
+ switch (sp->user_datafmt) {
+ case PIXARLOGDATAFMT_FLOAT:
+ horizontalAccumulateF(up, llen, sp->stride,
+ (float *)op, sp->ToLinearF);
+ op += llen * sizeof(float);
+ break;
+ case PIXARLOGDATAFMT_16BIT:
+ horizontalAccumulate16(up, llen, sp->stride,
+ (uint16 *)op, sp->ToLinear16);
+ op += llen * sizeof(uint16);
+ break;
+ case PIXARLOGDATAFMT_12BITPICIO:
+ horizontalAccumulate12(up, llen, sp->stride,
+ (int16 *)op, sp->ToLinearF);
+ op += llen * sizeof(int16);
+ break;
+ case PIXARLOGDATAFMT_11BITLOG:
+ horizontalAccumulate11(up, llen, sp->stride,
+ (uint16 *)op);
+ op += llen * sizeof(uint16);
+ break;
+ case PIXARLOGDATAFMT_8BIT:
+ horizontalAccumulate8(up, llen, sp->stride,
+ (unsigned char *)op, sp->ToLinear8);
+ op += llen * sizeof(unsigned char);
+ break;
+ case PIXARLOGDATAFMT_8BITABGR:
+ horizontalAccumulate8abgr(up, llen, sp->stride,
+ (unsigned char *)op, sp->ToLinear8);
+ op += llen * sizeof(unsigned char);
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "PixarLogDecode: unsupported bits/sample: %d",
+ td->td_bitspersample);
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+static int
+PixarLogSetupEncode(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ PixarLogState* sp = EncoderState(tif);
+ tsize_t tbuf_size;
+ static const char module[] = "PixarLogSetupEncode";
+
+ assert(sp != NULL);
+
+ /* for some reason, we can't do this in TIFFInitPixarLog */
+
+ sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+ td->td_samplesperpixel : 1);
+ tbuf_size = multiply(multiply(multiply(sp->stride, td->td_imagewidth),
+ td->td_rowsperstrip), sizeof(uint16));
+ if (tbuf_size == 0)
+ return (0);
+ sp->tbuf = (uint16 *) _TIFFmalloc(tbuf_size);
+ if (sp->tbuf == NULL)
+ return (0);
+ if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN)
+ sp->user_datafmt = PixarLogGuessDataFmt(td);
+ if (sp->user_datafmt == PIXARLOGDATAFMT_UNKNOWN) {
+ TIFFErrorExt(tif->tif_clientdata, module, "PixarLog compression can't handle %d bit linear encodings", td->td_bitspersample);
+ return (0);
+ }
+
+ if (deflateInit(&sp->stream, sp->quality) != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg);
+ return (0);
+ } else {
+ sp->state |= PLSTATE_INIT;
+ return (1);
+ }
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+PixarLogPreEncode(TIFF* tif, tsample_t s)
+{
+ PixarLogState *sp = EncoderState(tif);
+
+ (void) s;
+ assert(sp != NULL);
+ sp->stream.next_out = tif->tif_rawdata;
+ sp->stream.avail_out = tif->tif_rawdatasize;
+ return (deflateReset(&sp->stream) == Z_OK);
+}
+
+static void
+horizontalDifferenceF(float *ip, int n, int stride, uint16 *wp, uint16 *FromLT2)
+{
+
+ int32 r1, g1, b1, a1, r2, g2, b2, a2, mask;
+ float fltsize = Fltsize;
+
+#define CLAMP(v) ( (v<(float)0.) ? 0 \
+ : (v<(float)2.) ? FromLT2[(int)(v*fltsize)] \
+ : (v>(float)24.2) ? 2047 \
+ : LogK1*log(v*LogK2) + 0.5 )
+
+ mask = CODE_MASK;
+ if (n >= stride) {
+ if (stride == 3) {
+ r2 = wp[0] = (uint16) CLAMP(ip[0]);
+ g2 = wp[1] = (uint16) CLAMP(ip[1]);
+ b2 = wp[2] = (uint16) CLAMP(ip[2]);
+ n -= 3;
+ while (n > 0) {
+ n -= 3;
+ wp += 3;
+ ip += 3;
+ r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1;
+ g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1;
+ b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1;
+ }
+ } else if (stride == 4) {
+ r2 = wp[0] = (uint16) CLAMP(ip[0]);
+ g2 = wp[1] = (uint16) CLAMP(ip[1]);
+ b2 = wp[2] = (uint16) CLAMP(ip[2]);
+ a2 = wp[3] = (uint16) CLAMP(ip[3]);
+ n -= 4;
+ while (n > 0) {
+ n -= 4;
+ wp += 4;
+ ip += 4;
+ r1 = (int32) CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1;
+ g1 = (int32) CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1;
+ b1 = (int32) CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1;
+ a1 = (int32) CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1;
+ }
+ } else {
+ ip += n - 1; /* point to last one */
+ wp += n - 1; /* point to last one */
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]);
+ wp[stride] -= wp[0];
+ wp[stride] &= mask;
+ wp--; ip--)
+ n -= stride;
+ }
+ REPEAT(stride, wp[0] = (uint16) CLAMP(ip[0]); wp--; ip--)
+ }
+ }
+}
+
+static void
+horizontalDifference16(unsigned short *ip, int n, int stride,
+ unsigned short *wp, uint16 *From14)
+{
+ register int r1, g1, b1, a1, r2, g2, b2, a2, mask;
+
+/* assumption is unsigned pixel values */
+#undef CLAMP
+#define CLAMP(v) From14[(v) >> 2]
+
+ mask = CODE_MASK;
+ if (n >= stride) {
+ if (stride == 3) {
+ r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]);
+ b2 = wp[2] = CLAMP(ip[2]);
+ n -= 3;
+ while (n > 0) {
+ n -= 3;
+ wp += 3;
+ ip += 3;
+ r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1;
+ g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1;
+ b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1;
+ }
+ } else if (stride == 4) {
+ r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]);
+ b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]);
+ n -= 4;
+ while (n > 0) {
+ n -= 4;
+ wp += 4;
+ ip += 4;
+ r1 = CLAMP(ip[0]); wp[0] = (r1-r2) & mask; r2 = r1;
+ g1 = CLAMP(ip[1]); wp[1] = (g1-g2) & mask; g2 = g1;
+ b1 = CLAMP(ip[2]); wp[2] = (b1-b2) & mask; b2 = b1;
+ a1 = CLAMP(ip[3]); wp[3] = (a1-a2) & mask; a2 = a1;
+ }
+ } else {
+ ip += n - 1; /* point to last one */
+ wp += n - 1; /* point to last one */
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride, wp[0] = CLAMP(ip[0]);
+ wp[stride] -= wp[0];
+ wp[stride] &= mask;
+ wp--; ip--)
+ n -= stride;
+ }
+ REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--)
+ }
+ }
+}
+
+
+static void
+horizontalDifference8(unsigned char *ip, int n, int stride,
+ unsigned short *wp, uint16 *From8)
+{
+ register int r1, g1, b1, a1, r2, g2, b2, a2, mask;
+
+#undef CLAMP
+#define CLAMP(v) (From8[(v)])
+
+ mask = CODE_MASK;
+ if (n >= stride) {
+ if (stride == 3) {
+ r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]);
+ b2 = wp[2] = CLAMP(ip[2]);
+ n -= 3;
+ while (n > 0) {
+ n -= 3;
+ r1 = CLAMP(ip[3]); wp[3] = (r1-r2) & mask; r2 = r1;
+ g1 = CLAMP(ip[4]); wp[4] = (g1-g2) & mask; g2 = g1;
+ b1 = CLAMP(ip[5]); wp[5] = (b1-b2) & mask; b2 = b1;
+ wp += 3;
+ ip += 3;
+ }
+ } else if (stride == 4) {
+ r2 = wp[0] = CLAMP(ip[0]); g2 = wp[1] = CLAMP(ip[1]);
+ b2 = wp[2] = CLAMP(ip[2]); a2 = wp[3] = CLAMP(ip[3]);
+ n -= 4;
+ while (n > 0) {
+ n -= 4;
+ r1 = CLAMP(ip[4]); wp[4] = (r1-r2) & mask; r2 = r1;
+ g1 = CLAMP(ip[5]); wp[5] = (g1-g2) & mask; g2 = g1;
+ b1 = CLAMP(ip[6]); wp[6] = (b1-b2) & mask; b2 = b1;
+ a1 = CLAMP(ip[7]); wp[7] = (a1-a2) & mask; a2 = a1;
+ wp += 4;
+ ip += 4;
+ }
+ } else {
+ wp += n + stride - 1; /* point to last one */
+ ip += n + stride - 1; /* point to last one */
+ n -= stride;
+ while (n > 0) {
+ REPEAT(stride, wp[0] = CLAMP(ip[0]);
+ wp[stride] -= wp[0];
+ wp[stride] &= mask;
+ wp--; ip--)
+ n -= stride;
+ }
+ REPEAT(stride, wp[0] = CLAMP(ip[0]); wp--; ip--)
+ }
+ }
+}
+
+/*
+ * Encode a chunk of pixels.
+ */
+static int
+PixarLogEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ PixarLogState *sp = EncoderState(tif);
+ static const char module[] = "PixarLogEncode";
+ int i, n, llen;
+ unsigned short * up;
+
+ (void) s;
+
+ switch (sp->user_datafmt) {
+ case PIXARLOGDATAFMT_FLOAT:
+ n = cc / sizeof(float); /* XXX float == 32 bits */
+ break;
+ case PIXARLOGDATAFMT_16BIT:
+ case PIXARLOGDATAFMT_12BITPICIO:
+ case PIXARLOGDATAFMT_11BITLOG:
+ n = cc / sizeof(uint16); /* XXX uint16 == 16 bits */
+ break;
+ case PIXARLOGDATAFMT_8BIT:
+ case PIXARLOGDATAFMT_8BITABGR:
+ n = cc;
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%d bit input not supported in PixarLog",
+ td->td_bitspersample);
+ return 0;
+ }
+
+ llen = sp->stride * td->td_imagewidth;
+
+ for (i = 0, up = sp->tbuf; i < n; i += llen, up += llen) {
+ switch (sp->user_datafmt) {
+ case PIXARLOGDATAFMT_FLOAT:
+ horizontalDifferenceF((float *)bp, llen,
+ sp->stride, up, sp->FromLT2);
+ bp += llen * sizeof(float);
+ break;
+ case PIXARLOGDATAFMT_16BIT:
+ horizontalDifference16((uint16 *)bp, llen,
+ sp->stride, up, sp->From14);
+ bp += llen * sizeof(uint16);
+ break;
+ case PIXARLOGDATAFMT_8BIT:
+ horizontalDifference8((unsigned char *)bp, llen,
+ sp->stride, up, sp->From8);
+ bp += llen * sizeof(unsigned char);
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%d bit input not supported in PixarLog",
+ td->td_bitspersample);
+ return 0;
+ }
+ }
+
+ sp->stream.next_in = (unsigned char *) sp->tbuf;
+ sp->stream.avail_in = n * sizeof(uint16);
+
+ do {
+ if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Encoder error: %s",
+ tif->tif_name, sp->stream.msg);
+ return (0);
+ }
+ if (sp->stream.avail_out == 0) {
+ tif->tif_rawcc = tif->tif_rawdatasize;
+ TIFFFlushData1(tif);
+ sp->stream.next_out = tif->tif_rawdata;
+ sp->stream.avail_out = tif->tif_rawdatasize;
+ }
+ } while (sp->stream.avail_in > 0);
+ return (1);
+}
+
+/*
+ * Finish off an encoded strip by flushing the last
+ * string and tacking on an End Of Information code.
+ */
+
+static int
+PixarLogPostEncode(TIFF* tif)
+{
+ PixarLogState *sp = EncoderState(tif);
+ static const char module[] = "PixarLogPostEncode";
+ int state;
+
+ sp->stream.avail_in = 0;
+
+ do {
+ state = deflate(&sp->stream, Z_FINISH);
+ switch (state) {
+ case Z_STREAM_END:
+ case Z_OK:
+ if (sp->stream.avail_out != (uint32)tif->tif_rawdatasize) {
+ tif->tif_rawcc =
+ tif->tif_rawdatasize - sp->stream.avail_out;
+ TIFFFlushData1(tif);
+ sp->stream.next_out = tif->tif_rawdata;
+ sp->stream.avail_out = tif->tif_rawdatasize;
+ }
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s",
+ tif->tif_name, sp->stream.msg);
+ return (0);
+ }
+ } while (state != Z_STREAM_END);
+ return (1);
+}
+
+static void
+PixarLogClose(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ /* In a really sneaky maneuver, on close, we covertly modify both
+ * bitspersample and sampleformat in the directory to indicate
+ * 8-bit linear. This way, the decode "just works" even for
+ * readers that don't know about PixarLog, or how to set
+ * the PIXARLOGDATFMT pseudo-tag.
+ */
+ td->td_bitspersample = 8;
+ td->td_sampleformat = SAMPLEFORMAT_UINT;
+}
+
+static void
+PixarLogCleanup(TIFF* tif)
+{
+ PixarLogState* sp = (PixarLogState*) tif->tif_data;
+
+ assert(sp != 0);
+
+ (void)TIFFPredictorCleanup(tif);
+
+ tif->tif_tagmethods.vgetfield = sp->vgetparent;
+ tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+ if (sp->FromLT2) _TIFFfree(sp->FromLT2);
+ if (sp->From14) _TIFFfree(sp->From14);
+ if (sp->From8) _TIFFfree(sp->From8);
+ if (sp->ToLinearF) _TIFFfree(sp->ToLinearF);
+ if (sp->ToLinear16) _TIFFfree(sp->ToLinear16);
+ if (sp->ToLinear8) _TIFFfree(sp->ToLinear8);
+ if (sp->state&PLSTATE_INIT) {
+ if (tif->tif_mode == O_RDONLY)
+ inflateEnd(&sp->stream);
+ else
+ deflateEnd(&sp->stream);
+ }
+ if (sp->tbuf)
+ _TIFFfree(sp->tbuf);
+ _TIFFfree(sp);
+ tif->tif_data = NULL;
+
+ _TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+PixarLogVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ PixarLogState *sp = (PixarLogState *)tif->tif_data;
+ int result;
+ static const char module[] = "PixarLogVSetField";
+
+ switch (tag) {
+ case TIFFTAG_PIXARLOGQUALITY:
+ sp->quality = va_arg(ap, int);
+ if (tif->tif_mode != O_RDONLY && (sp->state&PLSTATE_INIT)) {
+ if (deflateParams(&sp->stream,
+ sp->quality, Z_DEFAULT_STRATEGY) != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s",
+ tif->tif_name, sp->stream.msg);
+ return (0);
+ }
+ }
+ return (1);
+ case TIFFTAG_PIXARLOGDATAFMT:
+ sp->user_datafmt = va_arg(ap, int);
+ /* Tweak the TIFF header so that the rest of libtiff knows what
+ * size of data will be passed between app and library, and
+ * assume that the app knows what it is doing and is not
+ * confused by these header manipulations...
+ */
+ switch (sp->user_datafmt) {
+ case PIXARLOGDATAFMT_8BIT:
+ case PIXARLOGDATAFMT_8BITABGR:
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ break;
+ case PIXARLOGDATAFMT_11BITLOG:
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+ TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ break;
+ case PIXARLOGDATAFMT_12BITPICIO:
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+ TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
+ break;
+ case PIXARLOGDATAFMT_16BIT:
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 16);
+ TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ break;
+ case PIXARLOGDATAFMT_FLOAT:
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
+ TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
+ break;
+ }
+ /*
+ * Must recalculate sizes should bits/sample change.
+ */
+ tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1;
+ tif->tif_scanlinesize = TIFFScanlineSize(tif);
+ result = 1; /* NB: pseudo tag */
+ break;
+ default:
+ result = (*sp->vsetparent)(tif, tag, ap);
+ }
+ return (result);
+}
+
+static int
+PixarLogVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ PixarLogState *sp = (PixarLogState *)tif->tif_data;
+
+ switch (tag) {
+ case TIFFTAG_PIXARLOGQUALITY:
+ *va_arg(ap, int*) = sp->quality;
+ break;
+ case TIFFTAG_PIXARLOGDATAFMT:
+ *va_arg(ap, int*) = sp->user_datafmt;
+ break;
+ default:
+ return (*sp->vgetparent)(tif, tag, ap);
+ }
+ return (1);
+}
+
+static const TIFFFieldInfo pixarlogFieldInfo[] = {
+ {TIFFTAG_PIXARLOGDATAFMT,0,0,TIFF_ANY, FIELD_PSEUDO,FALSE,FALSE,""},
+ {TIFFTAG_PIXARLOGQUALITY,0,0,TIFF_ANY, FIELD_PSEUDO,FALSE,FALSE,""}
+};
+
+int
+TIFFInitPixarLog(TIFF* tif, int scheme)
+{
+ static const char module[] = "TIFFInitPixarLog";
+
+ PixarLogState* sp;
+
+ assert(scheme == COMPRESSION_PIXARLOG);
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, pixarlogFieldInfo,
+ TIFFArrayCount(pixarlogFieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Merging PixarLog codec-specific tags failed");
+ return 0;
+ }
+
+ /*
+ * Allocate state block so tag methods have storage to record values.
+ */
+ tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (PixarLogState));
+ if (tif->tif_data == NULL)
+ goto bad;
+ sp = (PixarLogState*) tif->tif_data;
+ _TIFFmemset(sp, 0, sizeof (*sp));
+ sp->stream.data_type = Z_BINARY;
+ sp->user_datafmt = PIXARLOGDATAFMT_UNKNOWN;
+
+ /*
+ * Install codec methods.
+ */
+ tif->tif_setupdecode = PixarLogSetupDecode;
+ tif->tif_predecode = PixarLogPreDecode;
+ tif->tif_decoderow = PixarLogDecode;
+ tif->tif_decodestrip = PixarLogDecode;
+ tif->tif_decodetile = PixarLogDecode;
+ tif->tif_setupencode = PixarLogSetupEncode;
+ tif->tif_preencode = PixarLogPreEncode;
+ tif->tif_postencode = PixarLogPostEncode;
+ tif->tif_encoderow = PixarLogEncode;
+ tif->tif_encodestrip = PixarLogEncode;
+ tif->tif_encodetile = PixarLogEncode;
+ tif->tif_close = PixarLogClose;
+ tif->tif_cleanup = PixarLogCleanup;
+
+ /* Override SetField so we can handle our private pseudo-tag */
+ sp->vgetparent = tif->tif_tagmethods.vgetfield;
+ tif->tif_tagmethods.vgetfield = PixarLogVGetField; /* hook for codec tags */
+ sp->vsetparent = tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vsetfield = PixarLogVSetField; /* hook for codec tags */
+
+ /* Default values for codec-specific fields */
+ sp->quality = Z_DEFAULT_COMPRESSION; /* default comp. level */
+ sp->state = 0;
+
+ /* we don't wish to use the predictor,
+ * the default is none, which predictor value 1
+ */
+ (void) TIFFPredictorInit(tif);
+
+ /*
+ * build the companding tables
+ */
+ PixarLogMakeTables(sp);
+
+ return (1);
+bad:
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "No space for PixarLog state block");
+ return (0);
+}
+#endif /* PIXARLOG_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_predict.c b/tiff/libtiff/tif_predict.c
new file mode 100644
index 0000000..bbc221f
--- /dev/null
+++ b/tiff/libtiff/tif_predict.c
@@ -0,0 +1,736 @@
+/* $Id: tif_predict.c,v 1.11.2.4 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Predictor Tag Support (used by multiple codecs).
+ */
+#include "tiffiop.h"
+#include "tif_predict.h"
+
+#define PredictorState(tif) ((TIFFPredictorState*) (tif)->tif_data)
+
+static void horAcc8(TIFF*, tidata_t, tsize_t);
+static void horAcc16(TIFF*, tidata_t, tsize_t);
+static void horAcc32(TIFF*, tidata_t, tsize_t);
+static void swabHorAcc16(TIFF*, tidata_t, tsize_t);
+static void swabHorAcc32(TIFF*, tidata_t, tsize_t);
+static void horDiff8(TIFF*, tidata_t, tsize_t);
+static void horDiff16(TIFF*, tidata_t, tsize_t);
+static void horDiff32(TIFF*, tidata_t, tsize_t);
+static void fpAcc(TIFF*, tidata_t, tsize_t);
+static void fpDiff(TIFF*, tidata_t, tsize_t);
+static int PredictorDecodeRow(TIFF*, tidata_t, tsize_t, tsample_t);
+static int PredictorDecodeTile(TIFF*, tidata_t, tsize_t, tsample_t);
+static int PredictorEncodeRow(TIFF*, tidata_t, tsize_t, tsample_t);
+static int PredictorEncodeTile(TIFF*, tidata_t, tsize_t, tsample_t);
+
+static int
+PredictorSetup(TIFF* tif)
+{
+ static const char module[] = "PredictorSetup";
+
+ TIFFPredictorState* sp = PredictorState(tif);
+ TIFFDirectory* td = &tif->tif_dir;
+
+ switch (sp->predictor) /* no differencing */
+ {
+ case PREDICTOR_NONE:
+ return 1;
+ case PREDICTOR_HORIZONTAL:
+ if (td->td_bitspersample != 8
+ && td->td_bitspersample != 16
+ && td->td_bitspersample != 32) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Horizontal differencing \"Predictor\" not supported with %d-bit samples",
+ td->td_bitspersample);
+ return 0;
+ }
+ break;
+ case PREDICTOR_FLOATINGPOINT:
+ if (td->td_sampleformat != SAMPLEFORMAT_IEEEFP) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Floating point \"Predictor\" not supported with %d data format",
+ td->td_sampleformat);
+ return 0;
+ }
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "\"Predictor\" value %d not supported",
+ sp->predictor);
+ return 0;
+ }
+ sp->stride = (td->td_planarconfig == PLANARCONFIG_CONTIG ?
+ td->td_samplesperpixel : 1);
+ /*
+ * Calculate the scanline/tile-width size in bytes.
+ */
+ if (isTiled(tif))
+ sp->rowsize = TIFFTileRowSize(tif);
+ else
+ sp->rowsize = TIFFScanlineSize(tif);
+
+ return 1;
+}
+
+static int
+PredictorSetupDecode(TIFF* tif)
+{
+ TIFFPredictorState* sp = PredictorState(tif);
+ TIFFDirectory* td = &tif->tif_dir;
+
+ if (!(*sp->setupdecode)(tif) || !PredictorSetup(tif))
+ return 0;
+
+ if (sp->predictor == 2) {
+ switch (td->td_bitspersample) {
+ case 8: sp->decodepfunc = horAcc8; break;
+ case 16: sp->decodepfunc = horAcc16; break;
+ case 32: sp->decodepfunc = horAcc32; break;
+ }
+ /*
+ * Override default decoding method with one that does the
+ * predictor stuff.
+ */
+ if( tif->tif_decoderow != PredictorDecodeRow )
+ {
+ sp->decoderow = tif->tif_decoderow;
+ tif->tif_decoderow = PredictorDecodeRow;
+ sp->decodestrip = tif->tif_decodestrip;
+ tif->tif_decodestrip = PredictorDecodeTile;
+ sp->decodetile = tif->tif_decodetile;
+ tif->tif_decodetile = PredictorDecodeTile;
+ }
+ /*
+ * If the data is horizontally differenced 16-bit data that
+ * requires byte-swapping, then it must be byte swapped before
+ * the accumulation step. We do this with a special-purpose
+ * routine and override the normal post decoding logic that
+ * the library setup when the directory was read.
+ */
+ if (tif->tif_flags & TIFF_SWAB) {
+ if (sp->decodepfunc == horAcc16) {
+ sp->decodepfunc = swabHorAcc16;
+ tif->tif_postdecode = _TIFFNoPostDecode;
+ } else if (sp->decodepfunc == horAcc32) {
+ sp->decodepfunc = swabHorAcc32;
+ tif->tif_postdecode = _TIFFNoPostDecode;
+ }
+ }
+ }
+
+ else if (sp->predictor == 3) {
+ sp->decodepfunc = fpAcc;
+ /*
+ * Override default decoding method with one that does the
+ * predictor stuff.
+ */
+ if( tif->tif_decoderow != PredictorDecodeRow )
+ {
+ sp->decoderow = tif->tif_decoderow;
+ tif->tif_decoderow = PredictorDecodeRow;
+ sp->decodestrip = tif->tif_decodestrip;
+ tif->tif_decodestrip = PredictorDecodeTile;
+ sp->decodetile = tif->tif_decodetile;
+ tif->tif_decodetile = PredictorDecodeTile;
+ }
+ /*
+ * The data should not be swapped outside of the floating
+ * point predictor, the accumulation routine should return
+ * byres in the native order.
+ */
+ if (tif->tif_flags & TIFF_SWAB) {
+ tif->tif_postdecode = _TIFFNoPostDecode;
+ }
+ /*
+ * Allocate buffer to keep the decoded bytes before
+ * rearranging in the ight order
+ */
+ }
+
+ return 1;
+}
+
+static int
+PredictorSetupEncode(TIFF* tif)
+{
+ TIFFPredictorState* sp = PredictorState(tif);
+ TIFFDirectory* td = &tif->tif_dir;
+
+ if (!(*sp->setupencode)(tif) || !PredictorSetup(tif))
+ return 0;
+
+ if (sp->predictor == 2) {
+ switch (td->td_bitspersample) {
+ case 8: sp->encodepfunc = horDiff8; break;
+ case 16: sp->encodepfunc = horDiff16; break;
+ case 32: sp->encodepfunc = horDiff32; break;
+ }
+ /*
+ * Override default encoding method with one that does the
+ * predictor stuff.
+ */
+ if( tif->tif_encoderow != PredictorEncodeRow )
+ {
+ sp->encoderow = tif->tif_encoderow;
+ tif->tif_encoderow = PredictorEncodeRow;
+ sp->encodestrip = tif->tif_encodestrip;
+ tif->tif_encodestrip = PredictorEncodeTile;
+ sp->encodetile = tif->tif_encodetile;
+ tif->tif_encodetile = PredictorEncodeTile;
+ }
+ }
+
+ else if (sp->predictor == 3) {
+ sp->encodepfunc = fpDiff;
+ /*
+ * Override default encoding method with one that does the
+ * predictor stuff.
+ */
+ if( tif->tif_encoderow != PredictorEncodeRow )
+ {
+ sp->encoderow = tif->tif_encoderow;
+ tif->tif_encoderow = PredictorEncodeRow;
+ sp->encodestrip = tif->tif_encodestrip;
+ tif->tif_encodestrip = PredictorEncodeTile;
+ sp->encodetile = tif->tif_encodetile;
+ tif->tif_encodetile = PredictorEncodeTile;
+ }
+ }
+
+ return 1;
+}
+
+#define REPEAT4(n, op) \
+ switch (n) { \
+ default: { int i; for (i = n-4; i > 0; i--) { op; } } \
+ case 4: op; \
+ case 3: op; \
+ case 2: op; \
+ case 1: op; \
+ case 0: ; \
+ }
+
+static void
+horAcc8(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ tsize_t stride = PredictorState(tif)->stride;
+
+ char* cp = (char*) cp0;
+ if (cc > stride) {
+ cc -= stride;
+ /*
+ * Pipeline the most common cases.
+ */
+ if (stride == 3) {
+ unsigned int cr = cp[0];
+ unsigned int cg = cp[1];
+ unsigned int cb = cp[2];
+ do {
+ cc -= 3, cp += 3;
+ cp[0] = (char) (cr += cp[0]);
+ cp[1] = (char) (cg += cp[1]);
+ cp[2] = (char) (cb += cp[2]);
+ } while ((int32) cc > 0);
+ } else if (stride == 4) {
+ unsigned int cr = cp[0];
+ unsigned int cg = cp[1];
+ unsigned int cb = cp[2];
+ unsigned int ca = cp[3];
+ do {
+ cc -= 4, cp += 4;
+ cp[0] = (char) (cr += cp[0]);
+ cp[1] = (char) (cg += cp[1]);
+ cp[2] = (char) (cb += cp[2]);
+ cp[3] = (char) (ca += cp[3]);
+ } while ((int32) cc > 0);
+ } else {
+ do {
+ REPEAT4(stride, cp[stride] =
+ (char) (cp[stride] + *cp); cp++)
+ cc -= stride;
+ } while ((int32) cc > 0);
+ }
+ }
+}
+
+static void
+swabHorAcc16(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ tsize_t stride = PredictorState(tif)->stride;
+ uint16* wp = (uint16*) cp0;
+ tsize_t wc = cc / 2;
+
+ if (wc > stride) {
+ TIFFSwabArrayOfShort(wp, wc);
+ wc -= stride;
+ do {
+ REPEAT4(stride, wp[stride] += wp[0]; wp++)
+ wc -= stride;
+ } while ((int32) wc > 0);
+ }
+}
+
+static void
+horAcc16(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ tsize_t stride = PredictorState(tif)->stride;
+ uint16* wp = (uint16*) cp0;
+ tsize_t wc = cc / 2;
+
+ if (wc > stride) {
+ wc -= stride;
+ do {
+ REPEAT4(stride, wp[stride] += wp[0]; wp++)
+ wc -= stride;
+ } while ((int32) wc > 0);
+ }
+}
+
+static void
+swabHorAcc32(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ tsize_t stride = PredictorState(tif)->stride;
+ uint32* wp = (uint32*) cp0;
+ tsize_t wc = cc / 4;
+
+ if (wc > stride) {
+ TIFFSwabArrayOfLong(wp, wc);
+ wc -= stride;
+ do {
+ REPEAT4(stride, wp[stride] += wp[0]; wp++)
+ wc -= stride;
+ } while ((int32) wc > 0);
+ }
+}
+
+static void
+horAcc32(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ tsize_t stride = PredictorState(tif)->stride;
+ uint32* wp = (uint32*) cp0;
+ tsize_t wc = cc / 4;
+
+ if (wc > stride) {
+ wc -= stride;
+ do {
+ REPEAT4(stride, wp[stride] += wp[0]; wp++)
+ wc -= stride;
+ } while ((int32) wc > 0);
+ }
+}
+
+/*
+ * Floating point predictor accumulation routine.
+ */
+static void
+fpAcc(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ tsize_t stride = PredictorState(tif)->stride;
+ uint32 bps = tif->tif_dir.td_bitspersample / 8;
+ tsize_t wc = cc / bps;
+ tsize_t count = cc;
+ uint8 *cp = (uint8 *) cp0;
+ uint8 *tmp = (uint8 *)_TIFFmalloc(cc);
+
+ if (!tmp)
+ return;
+
+ while (count > stride) {
+ REPEAT4(stride, cp[stride] += cp[0]; cp++)
+ count -= stride;
+ }
+
+ _TIFFmemcpy(tmp, cp0, cc);
+ cp = (uint8 *) cp0;
+ for (count = 0; count < wc; count++) {
+ uint32 byte;
+ for (byte = 0; byte < bps; byte++) {
+#if WORDS_BIGENDIAN
+ cp[bps * count + byte] = tmp[byte * wc + count];
+#else
+ cp[bps * count + byte] =
+ tmp[(bps - byte - 1) * wc + count];
+#endif
+ }
+ }
+ _TIFFfree(tmp);
+}
+
+/*
+ * Decode a scanline and apply the predictor routine.
+ */
+static int
+PredictorDecodeRow(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s)
+{
+ TIFFPredictorState *sp = PredictorState(tif);
+
+ assert(sp != NULL);
+ assert(sp->decoderow != NULL);
+ assert(sp->decodepfunc != NULL);
+
+ if ((*sp->decoderow)(tif, op0, occ0, s)) {
+ (*sp->decodepfunc)(tif, op0, occ0);
+ return 1;
+ } else
+ return 0;
+}
+
+/*
+ * Decode a tile/strip and apply the predictor routine.
+ * Note that horizontal differencing must be done on a
+ * row-by-row basis. The width of a "row" has already
+ * been calculated at pre-decode time according to the
+ * strip/tile dimensions.
+ */
+static int
+PredictorDecodeTile(TIFF* tif, tidata_t op0, tsize_t occ0, tsample_t s)
+{
+ TIFFPredictorState *sp = PredictorState(tif);
+
+ assert(sp != NULL);
+ assert(sp->decodetile != NULL);
+
+ if ((*sp->decodetile)(tif, op0, occ0, s)) {
+ tsize_t rowsize = sp->rowsize;
+ assert(rowsize > 0);
+ assert(sp->decodepfunc != NULL);
+ while ((long)occ0 > 0) {
+ (*sp->decodepfunc)(tif, op0, (tsize_t) rowsize);
+ occ0 -= rowsize;
+ op0 += rowsize;
+ }
+ return 1;
+ } else
+ return 0;
+}
+
+static void
+horDiff8(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ TIFFPredictorState* sp = PredictorState(tif);
+ tsize_t stride = sp->stride;
+ char* cp = (char*) cp0;
+
+ if (cc > stride) {
+ cc -= stride;
+ /*
+ * Pipeline the most common cases.
+ */
+ if (stride == 3) {
+ int r1, g1, b1;
+ int r2 = cp[0];
+ int g2 = cp[1];
+ int b2 = cp[2];
+ do {
+ r1 = cp[3]; cp[3] = r1-r2; r2 = r1;
+ g1 = cp[4]; cp[4] = g1-g2; g2 = g1;
+ b1 = cp[5]; cp[5] = b1-b2; b2 = b1;
+ cp += 3;
+ } while ((int32)(cc -= 3) > 0);
+ } else if (stride == 4) {
+ int r1, g1, b1, a1;
+ int r2 = cp[0];
+ int g2 = cp[1];
+ int b2 = cp[2];
+ int a2 = cp[3];
+ do {
+ r1 = cp[4]; cp[4] = r1-r2; r2 = r1;
+ g1 = cp[5]; cp[5] = g1-g2; g2 = g1;
+ b1 = cp[6]; cp[6] = b1-b2; b2 = b1;
+ a1 = cp[7]; cp[7] = a1-a2; a2 = a1;
+ cp += 4;
+ } while ((int32)(cc -= 4) > 0);
+ } else {
+ cp += cc - 1;
+ do {
+ REPEAT4(stride, cp[stride] -= cp[0]; cp--)
+ } while ((int32)(cc -= stride) > 0);
+ }
+ }
+}
+
+static void
+horDiff16(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ TIFFPredictorState* sp = PredictorState(tif);
+ tsize_t stride = sp->stride;
+ int16 *wp = (int16*) cp0;
+ tsize_t wc = cc/2;
+
+ if (wc > stride) {
+ wc -= stride;
+ wp += wc - 1;
+ do {
+ REPEAT4(stride, wp[stride] -= wp[0]; wp--)
+ wc -= stride;
+ } while ((int32) wc > 0);
+ }
+}
+
+static void
+horDiff32(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ TIFFPredictorState* sp = PredictorState(tif);
+ tsize_t stride = sp->stride;
+ int32 *wp = (int32*) cp0;
+ tsize_t wc = cc/4;
+
+ if (wc > stride) {
+ wc -= stride;
+ wp += wc - 1;
+ do {
+ REPEAT4(stride, wp[stride] -= wp[0]; wp--)
+ wc -= stride;
+ } while ((int32) wc > 0);
+ }
+}
+
+/*
+ * Floating point predictor differencing routine.
+ */
+static void
+fpDiff(TIFF* tif, tidata_t cp0, tsize_t cc)
+{
+ tsize_t stride = PredictorState(tif)->stride;
+ uint32 bps = tif->tif_dir.td_bitspersample / 8;
+ tsize_t wc = cc / bps;
+ tsize_t count;
+ uint8 *cp = (uint8 *) cp0;
+ uint8 *tmp = (uint8 *)_TIFFmalloc(cc);
+
+ if (!tmp)
+ return;
+
+ _TIFFmemcpy(tmp, cp0, cc);
+ for (count = 0; count < wc; count++) {
+ uint32 byte;
+ for (byte = 0; byte < bps; byte++) {
+#if WORDS_BIGENDIAN
+ cp[byte * wc + count] = tmp[bps * count + byte];
+#else
+ cp[(bps - byte - 1) * wc + count] =
+ tmp[bps * count + byte];
+#endif
+ }
+ }
+ _TIFFfree(tmp);
+
+ cp = (uint8 *) cp0;
+ cp += cc - stride - 1;
+ for (count = cc; count > stride; count -= stride)
+ REPEAT4(stride, cp[stride] -= cp[0]; cp--)
+}
+
+static int
+PredictorEncodeRow(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ TIFFPredictorState *sp = PredictorState(tif);
+
+ assert(sp != NULL);
+ assert(sp->encodepfunc != NULL);
+ assert(sp->encoderow != NULL);
+
+ /* XXX horizontal differencing alters user's data XXX */
+ (*sp->encodepfunc)(tif, bp, cc);
+ return (*sp->encoderow)(tif, bp, cc, s);
+}
+
+static int
+PredictorEncodeTile(TIFF* tif, tidata_t bp0, tsize_t cc0, tsample_t s)
+{
+ static const char module[] = "PredictorEncodeTile";
+ TIFFPredictorState *sp = PredictorState(tif);
+ uint8 *working_copy;
+ tsize_t cc = cc0, rowsize;
+ unsigned char* bp;
+ int result_code;
+
+ assert(sp != NULL);
+ assert(sp->encodepfunc != NULL);
+ assert(sp->encodetile != NULL);
+
+ /*
+ * Do predictor manipulation in a working buffer to avoid altering
+ * the callers buffer. http://trac.osgeo.org/gdal/ticket/1965
+ */
+ working_copy = (uint8*) _TIFFmalloc(cc0);
+ if( working_copy == NULL )
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Out of memory allocating %d byte temp buffer.",
+ cc0 );
+ return 0;
+ }
+ memcpy( working_copy, bp0, cc0 );
+ bp = working_copy;
+
+ rowsize = sp->rowsize;
+ assert(rowsize > 0);
+ assert((cc0%rowsize)==0);
+ while (cc > 0) {
+ (*sp->encodepfunc)(tif, bp, rowsize);
+ cc -= rowsize;
+ bp += rowsize;
+ }
+ result_code = (*sp->encodetile)(tif, working_copy, cc0, s);
+
+ _TIFFfree( working_copy );
+
+ return result_code;
+}
+
+#define FIELD_PREDICTOR (FIELD_CODEC+0) /* XXX */
+
+static const TIFFFieldInfo predictFieldInfo[] = {
+ { TIFFTAG_PREDICTOR, 1, 1, TIFF_SHORT, FIELD_PREDICTOR,
+ FALSE, FALSE, "Predictor" },
+};
+
+static int
+PredictorVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ TIFFPredictorState *sp = PredictorState(tif);
+
+ assert(sp != NULL);
+ assert(sp->vsetparent != NULL);
+
+ switch (tag) {
+ case TIFFTAG_PREDICTOR:
+ sp->predictor = (uint16) va_arg(ap, int);
+ TIFFSetFieldBit(tif, FIELD_PREDICTOR);
+ break;
+ default:
+ return (*sp->vsetparent)(tif, tag, ap);
+ }
+ tif->tif_flags |= TIFF_DIRTYDIRECT;
+ return 1;
+}
+
+static int
+PredictorVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ TIFFPredictorState *sp = PredictorState(tif);
+
+ assert(sp != NULL);
+ assert(sp->vgetparent != NULL);
+
+ switch (tag) {
+ case TIFFTAG_PREDICTOR:
+ *va_arg(ap, uint16*) = sp->predictor;
+ break;
+ default:
+ return (*sp->vgetparent)(tif, tag, ap);
+ }
+ return 1;
+}
+
+static void
+PredictorPrintDir(TIFF* tif, FILE* fd, long flags)
+{
+ TIFFPredictorState* sp = PredictorState(tif);
+
+ (void) flags;
+ if (TIFFFieldSet(tif,FIELD_PREDICTOR)) {
+ fprintf(fd, " Predictor: ");
+ switch (sp->predictor) {
+ case 1: fprintf(fd, "none "); break;
+ case 2: fprintf(fd, "horizontal differencing "); break;
+ case 3: fprintf(fd, "floating point predictor "); break;
+ }
+ fprintf(fd, "%u (0x%x)\n", sp->predictor, sp->predictor);
+ }
+ if (sp->printdir)
+ (*sp->printdir)(tif, fd, flags);
+}
+
+int
+TIFFPredictorInit(TIFF* tif)
+{
+ TIFFPredictorState* sp = PredictorState(tif);
+
+ assert(sp != 0);
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, predictFieldInfo,
+ TIFFArrayCount(predictFieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata, "TIFFPredictorInit",
+ "Merging Predictor codec-specific tags failed");
+ return 0;
+ }
+
+ /*
+ * Override parent get/set field methods.
+ */
+ sp->vgetparent = tif->tif_tagmethods.vgetfield;
+ tif->tif_tagmethods.vgetfield =
+ PredictorVGetField;/* hook for predictor tag */
+ sp->vsetparent = tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vsetfield =
+ PredictorVSetField;/* hook for predictor tag */
+ sp->printdir = tif->tif_tagmethods.printdir;
+ tif->tif_tagmethods.printdir =
+ PredictorPrintDir; /* hook for predictor tag */
+
+ sp->setupdecode = tif->tif_setupdecode;
+ tif->tif_setupdecode = PredictorSetupDecode;
+ sp->setupencode = tif->tif_setupencode;
+ tif->tif_setupencode = PredictorSetupEncode;
+
+ sp->predictor = 1; /* default value */
+ sp->encodepfunc = NULL; /* no predictor routine */
+ sp->decodepfunc = NULL; /* no predictor routine */
+ return 1;
+}
+
+int
+TIFFPredictorCleanup(TIFF* tif)
+{
+ TIFFPredictorState* sp = PredictorState(tif);
+
+ assert(sp != 0);
+
+ tif->tif_tagmethods.vgetfield = sp->vgetparent;
+ tif->tif_tagmethods.vsetfield = sp->vsetparent;
+ tif->tif_tagmethods.printdir = sp->printdir;
+ tif->tif_setupdecode = sp->setupdecode;
+ tif->tif_setupencode = sp->setupencode;
+
+ return 1;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_predict.h b/tiff/libtiff/tif_predict.h
new file mode 100644
index 0000000..da0ad98
--- /dev/null
+++ b/tiff/libtiff/tif_predict.h
@@ -0,0 +1,77 @@
+/* $Id: tif_predict.h,v 1.3.2.2 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1995-1997 Sam Leffler
+ * Copyright (c) 1995-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFPREDICT_
+#define _TIFFPREDICT_
+/*
+ * ``Library-private'' Support for the Predictor Tag
+ */
+
+/*
+ * Codecs that want to support the Predictor tag must place
+ * this structure first in their private state block so that
+ * the predictor code can cast tif_data to find its state.
+ */
+typedef struct {
+ int predictor; /* predictor tag value */
+ int stride; /* sample stride over data */
+ tsize_t rowsize; /* tile/strip row size */
+
+ TIFFCodeMethod encoderow; /* parent codec encode/decode row */
+ TIFFCodeMethod encodestrip; /* parent codec encode/decode strip */
+ TIFFCodeMethod encodetile; /* parent codec encode/decode tile */
+ TIFFPostMethod encodepfunc; /* horizontal differencer */
+
+ TIFFCodeMethod decoderow; /* parent codec encode/decode row */
+ TIFFCodeMethod decodestrip; /* parent codec encode/decode strip */
+ TIFFCodeMethod decodetile; /* parent codec encode/decode tile */
+ TIFFPostMethod decodepfunc; /* horizontal accumulator */
+
+ TIFFVGetMethod vgetparent; /* super-class method */
+ TIFFVSetMethod vsetparent; /* super-class method */
+ TIFFPrintMethod printdir; /* super-class method */
+ TIFFBoolMethod setupdecode; /* super-class method */
+ TIFFBoolMethod setupencode; /* super-class method */
+} TIFFPredictorState;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern int TIFFPredictorInit(TIFF*);
+extern int TIFFPredictorCleanup(TIFF*);
+#if defined(__cplusplus)
+}
+#endif
+#endif /* _TIFFPREDICT_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_print.c b/tiff/libtiff/tif_print.c
new file mode 100644
index 0000000..eb4b1e7
--- /dev/null
+++ b/tiff/libtiff/tif_print.c
@@ -0,0 +1,646 @@
+/* $Id: tif_print.c,v 1.36.2.4 2010-06-08 18:50:42 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Directory Printing Support
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+static const char *photoNames[] = {
+ "min-is-white", /* PHOTOMETRIC_MINISWHITE */
+ "min-is-black", /* PHOTOMETRIC_MINISBLACK */
+ "RGB color", /* PHOTOMETRIC_RGB */
+ "palette color (RGB from colormap)", /* PHOTOMETRIC_PALETTE */
+ "transparency mask", /* PHOTOMETRIC_MASK */
+ "separated", /* PHOTOMETRIC_SEPARATED */
+ "YCbCr", /* PHOTOMETRIC_YCBCR */
+ "7 (0x7)",
+ "CIE L*a*b*", /* PHOTOMETRIC_CIELAB */
+};
+#define NPHOTONAMES (sizeof (photoNames) / sizeof (photoNames[0]))
+
+static const char *orientNames[] = {
+ "0 (0x0)",
+ "row 0 top, col 0 lhs", /* ORIENTATION_TOPLEFT */
+ "row 0 top, col 0 rhs", /* ORIENTATION_TOPRIGHT */
+ "row 0 bottom, col 0 rhs", /* ORIENTATION_BOTRIGHT */
+ "row 0 bottom, col 0 lhs", /* ORIENTATION_BOTLEFT */
+ "row 0 lhs, col 0 top", /* ORIENTATION_LEFTTOP */
+ "row 0 rhs, col 0 top", /* ORIENTATION_RIGHTTOP */
+ "row 0 rhs, col 0 bottom", /* ORIENTATION_RIGHTBOT */
+ "row 0 lhs, col 0 bottom", /* ORIENTATION_LEFTBOT */
+};
+#define NORIENTNAMES (sizeof (orientNames) / sizeof (orientNames[0]))
+
+static void
+_TIFFPrintField(FILE* fd, const TIFFFieldInfo *fip,
+ uint32 value_count, void *raw_data)
+{
+ uint32 j;
+
+ fprintf(fd, " %s: ", fip->field_name);
+
+ for(j = 0; j < value_count; j++) {
+ if(fip->field_type == TIFF_BYTE)
+ fprintf(fd, "%u", ((uint8 *) raw_data)[j]);
+ else if(fip->field_type == TIFF_UNDEFINED)
+ fprintf(fd, "0x%x",
+ (unsigned int) ((unsigned char *) raw_data)[j]);
+ else if(fip->field_type == TIFF_SBYTE)
+ fprintf(fd, "%d", ((int8 *) raw_data)[j]);
+ else if(fip->field_type == TIFF_SHORT)
+ fprintf(fd, "%u", ((uint16 *) raw_data)[j]);
+ else if(fip->field_type == TIFF_SSHORT)
+ fprintf(fd, "%d", ((int16 *) raw_data)[j]);
+ else if(fip->field_type == TIFF_LONG)
+ fprintf(fd, "%lu",
+ (unsigned long)((uint32 *) raw_data)[j]);
+ else if(fip->field_type == TIFF_SLONG)
+ fprintf(fd, "%ld", (long)((int32 *) raw_data)[j]);
+ else if(fip->field_type == TIFF_RATIONAL
+ || fip->field_type == TIFF_SRATIONAL
+ || fip->field_type == TIFF_FLOAT)
+ fprintf(fd, "%f", ((float *) raw_data)[j]);
+ else if(fip->field_type == TIFF_IFD)
+ fprintf(fd, "0x%ulx", ((uint32 *) raw_data)[j]);
+ else if(fip->field_type == TIFF_ASCII) {
+ fprintf(fd, "%s", (char *) raw_data);
+ break;
+ }
+ else if(fip->field_type == TIFF_DOUBLE)
+ fprintf(fd, "%f", ((double *) raw_data)[j]);
+ else if(fip->field_type == TIFF_FLOAT)
+ fprintf(fd, "%f", ((float *)raw_data)[j]);
+ else {
+ fprintf(fd, "<unsupported data type in TIFFPrint>");
+ break;
+ }
+
+ if(j < value_count - 1)
+ fprintf(fd, ",");
+ }
+
+ fprintf(fd, "\n");
+}
+
+static int
+_TIFFPrettyPrintField(TIFF* tif, FILE* fd, ttag_t tag,
+ uint32 value_count, void *raw_data)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ switch (tag)
+ {
+ case TIFFTAG_INKSET:
+ fprintf(fd, " Ink Set: ");
+ switch (*((uint16*)raw_data)) {
+ case INKSET_CMYK:
+ fprintf(fd, "CMYK\n");
+ break;
+ default:
+ fprintf(fd, "%u (0x%x)\n",
+ *((uint16*)raw_data),
+ *((uint16*)raw_data));
+ break;
+ }
+ return 1;
+ case TIFFTAG_DOTRANGE:
+ fprintf(fd, " Dot Range: %u-%u\n",
+ ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]);
+ return 1;
+ case TIFFTAG_WHITEPOINT:
+ fprintf(fd, " White Point: %g-%g\n",
+ ((float *)raw_data)[0], ((float *)raw_data)[1]); return 1;
+ case TIFFTAG_REFERENCEBLACKWHITE:
+ {
+ uint16 i;
+
+ fprintf(fd, " Reference Black/White:\n");
+ for (i = 0; i < 3; i++)
+ fprintf(fd, " %2d: %5g %5g\n", i,
+ ((float *)raw_data)[2*i+0],
+ ((float *)raw_data)[2*i+1]);
+ return 1;
+ }
+ case TIFFTAG_XMLPACKET:
+ {
+ uint32 i;
+
+ fprintf(fd, " XMLPacket (XMP Metadata):\n" );
+ for(i = 0; i < value_count; i++)
+ fputc(((char *)raw_data)[i], fd);
+ fprintf( fd, "\n" );
+ return 1;
+ }
+ case TIFFTAG_RICHTIFFIPTC:
+ /*
+ * XXX: for some weird reason RichTIFFIPTC tag
+ * defined as array of LONG values.
+ */
+ fprintf(fd,
+ " RichTIFFIPTC Data: <present>, %lu bytes\n",
+ (unsigned long) value_count * 4);
+ return 1;
+ case TIFFTAG_PHOTOSHOP:
+ fprintf(fd, " Photoshop Data: <present>, %lu bytes\n",
+ (unsigned long) value_count);
+ return 1;
+ case TIFFTAG_ICCPROFILE:
+ fprintf(fd, " ICC Profile: <present>, %lu bytes\n",
+ (unsigned long) value_count);
+ return 1;
+ case TIFFTAG_STONITS:
+ fprintf(fd,
+ " Sample to Nits conversion factor: %.4e\n",
+ *((double*)raw_data));
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Print the contents of the current directory
+ * to the specified stdio file stream.
+ */
+void
+TIFFPrintDirectory(TIFF* tif, FILE* fd, long flags)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ char *sep;
+ uint16 i;
+ long l, n;
+
+ fprintf(fd, "TIFF Directory at offset 0x%lx (%lu)\n",
+ (unsigned long)tif->tif_diroff, (unsigned long)tif->tif_diroff);
+ if (TIFFFieldSet(tif,FIELD_SUBFILETYPE)) {
+ fprintf(fd, " Subfile Type:");
+ sep = " ";
+ if (td->td_subfiletype & FILETYPE_REDUCEDIMAGE) {
+ fprintf(fd, "%sreduced-resolution image", sep);
+ sep = "/";
+ }
+ if (td->td_subfiletype & FILETYPE_PAGE) {
+ fprintf(fd, "%smulti-page document", sep);
+ sep = "/";
+ }
+ if (td->td_subfiletype & FILETYPE_MASK)
+ fprintf(fd, "%stransparency mask", sep);
+ fprintf(fd, " (%lu = 0x%lx)\n",
+ (long) td->td_subfiletype, (long) td->td_subfiletype);
+ }
+ if (TIFFFieldSet(tif,FIELD_IMAGEDIMENSIONS)) {
+ fprintf(fd, " Image Width: %lu Image Length: %lu",
+ (unsigned long) td->td_imagewidth, (unsigned long) td->td_imagelength);
+ if (TIFFFieldSet(tif,FIELD_IMAGEDEPTH))
+ fprintf(fd, " Image Depth: %lu",
+ (unsigned long) td->td_imagedepth);
+ fprintf(fd, "\n");
+ }
+ if (TIFFFieldSet(tif,FIELD_TILEDIMENSIONS)) {
+ fprintf(fd, " Tile Width: %lu Tile Length: %lu",
+ (unsigned long) td->td_tilewidth, (unsigned long) td->td_tilelength);
+ if (TIFFFieldSet(tif,FIELD_TILEDEPTH))
+ fprintf(fd, " Tile Depth: %lu",
+ (unsigned long) td->td_tiledepth);
+ fprintf(fd, "\n");
+ }
+ if (TIFFFieldSet(tif,FIELD_RESOLUTION)) {
+ fprintf(fd, " Resolution: %g, %g",
+ td->td_xresolution, td->td_yresolution);
+ if (TIFFFieldSet(tif,FIELD_RESOLUTIONUNIT)) {
+ switch (td->td_resolutionunit) {
+ case RESUNIT_NONE:
+ fprintf(fd, " (unitless)");
+ break;
+ case RESUNIT_INCH:
+ fprintf(fd, " pixels/inch");
+ break;
+ case RESUNIT_CENTIMETER:
+ fprintf(fd, " pixels/cm");
+ break;
+ default:
+ fprintf(fd, " (unit %u = 0x%x)",
+ td->td_resolutionunit,
+ td->td_resolutionunit);
+ break;
+ }
+ }
+ fprintf(fd, "\n");
+ }
+ if (TIFFFieldSet(tif,FIELD_POSITION))
+ fprintf(fd, " Position: %g, %g\n",
+ td->td_xposition, td->td_yposition);
+ if (TIFFFieldSet(tif,FIELD_BITSPERSAMPLE))
+ fprintf(fd, " Bits/Sample: %u\n", td->td_bitspersample);
+ if (TIFFFieldSet(tif,FIELD_SAMPLEFORMAT)) {
+ fprintf(fd, " Sample Format: ");
+ switch (td->td_sampleformat) {
+ case SAMPLEFORMAT_VOID:
+ fprintf(fd, "void\n");
+ break;
+ case SAMPLEFORMAT_INT:
+ fprintf(fd, "signed integer\n");
+ break;
+ case SAMPLEFORMAT_UINT:
+ fprintf(fd, "unsigned integer\n");
+ break;
+ case SAMPLEFORMAT_IEEEFP:
+ fprintf(fd, "IEEE floating point\n");
+ break;
+ case SAMPLEFORMAT_COMPLEXINT:
+ fprintf(fd, "complex signed integer\n");
+ break;
+ case SAMPLEFORMAT_COMPLEXIEEEFP:
+ fprintf(fd, "complex IEEE floating point\n");
+ break;
+ default:
+ fprintf(fd, "%u (0x%x)\n",
+ td->td_sampleformat, td->td_sampleformat);
+ break;
+ }
+ }
+ if (TIFFFieldSet(tif,FIELD_COMPRESSION)) {
+ const TIFFCodec* c = TIFFFindCODEC(td->td_compression);
+ fprintf(fd, " Compression Scheme: ");
+ if (c)
+ fprintf(fd, "%s\n", c->name);
+ else
+ fprintf(fd, "%u (0x%x)\n",
+ td->td_compression, td->td_compression);
+ }
+ if (TIFFFieldSet(tif,FIELD_PHOTOMETRIC)) {
+ fprintf(fd, " Photometric Interpretation: ");
+ if (td->td_photometric < NPHOTONAMES)
+ fprintf(fd, "%s\n", photoNames[td->td_photometric]);
+ else {
+ switch (td->td_photometric) {
+ case PHOTOMETRIC_LOGL:
+ fprintf(fd, "CIE Log2(L)\n");
+ break;
+ case PHOTOMETRIC_LOGLUV:
+ fprintf(fd, "CIE Log2(L) (u',v')\n");
+ break;
+ default:
+ fprintf(fd, "%u (0x%x)\n",
+ td->td_photometric, td->td_photometric);
+ break;
+ }
+ }
+ }
+ if (TIFFFieldSet(tif,FIELD_EXTRASAMPLES) && td->td_extrasamples) {
+ fprintf(fd, " Extra Samples: %u<", td->td_extrasamples);
+ sep = "";
+ for (i = 0; i < td->td_extrasamples; i++) {
+ switch (td->td_sampleinfo[i]) {
+ case EXTRASAMPLE_UNSPECIFIED:
+ fprintf(fd, "%sunspecified", sep);
+ break;
+ case EXTRASAMPLE_ASSOCALPHA:
+ fprintf(fd, "%sassoc-alpha", sep);
+ break;
+ case EXTRASAMPLE_UNASSALPHA:
+ fprintf(fd, "%sunassoc-alpha", sep);
+ break;
+ default:
+ fprintf(fd, "%s%u (0x%x)", sep,
+ td->td_sampleinfo[i], td->td_sampleinfo[i]);
+ break;
+ }
+ sep = ", ";
+ }
+ fprintf(fd, ">\n");
+ }
+ if (TIFFFieldSet(tif,FIELD_INKNAMES)) {
+ char* cp;
+ fprintf(fd, " Ink Names: ");
+ i = td->td_samplesperpixel;
+ sep = "";
+ for (cp = td->td_inknames; i > 0; cp = strchr(cp,'\0')+1, i--) {
+ fputs(sep, fd);
+ _TIFFprintAscii(fd, cp);
+ sep = ", ";
+ }
+ fputs("\n", fd);
+ }
+ if (TIFFFieldSet(tif,FIELD_THRESHHOLDING)) {
+ fprintf(fd, " Thresholding: ");
+ switch (td->td_threshholding) {
+ case THRESHHOLD_BILEVEL:
+ fprintf(fd, "bilevel art scan\n");
+ break;
+ case THRESHHOLD_HALFTONE:
+ fprintf(fd, "halftone or dithered scan\n");
+ break;
+ case THRESHHOLD_ERRORDIFFUSE:
+ fprintf(fd, "error diffused\n");
+ break;
+ default:
+ fprintf(fd, "%u (0x%x)\n",
+ td->td_threshholding, td->td_threshholding);
+ break;
+ }
+ }
+ if (TIFFFieldSet(tif,FIELD_FILLORDER)) {
+ fprintf(fd, " FillOrder: ");
+ switch (td->td_fillorder) {
+ case FILLORDER_MSB2LSB:
+ fprintf(fd, "msb-to-lsb\n");
+ break;
+ case FILLORDER_LSB2MSB:
+ fprintf(fd, "lsb-to-msb\n");
+ break;
+ default:
+ fprintf(fd, "%u (0x%x)\n",
+ td->td_fillorder, td->td_fillorder);
+ break;
+ }
+ }
+ if (TIFFFieldSet(tif,FIELD_YCBCRSUBSAMPLING))
+ {
+ /*
+ * For hacky reasons (see tif_jpeg.c - JPEGFixupTestSubsampling),
+ * we need to fetch this rather than trust what is in our
+ * structures.
+ */
+ uint16 subsampling[2];
+
+ TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING,
+ subsampling + 0, subsampling + 1 );
+ fprintf(fd, " YCbCr Subsampling: %u, %u\n",
+ subsampling[0], subsampling[1] );
+ }
+ if (TIFFFieldSet(tif,FIELD_YCBCRPOSITIONING)) {
+ fprintf(fd, " YCbCr Positioning: ");
+ switch (td->td_ycbcrpositioning) {
+ case YCBCRPOSITION_CENTERED:
+ fprintf(fd, "centered\n");
+ break;
+ case YCBCRPOSITION_COSITED:
+ fprintf(fd, "cosited\n");
+ break;
+ default:
+ fprintf(fd, "%u (0x%x)\n",
+ td->td_ycbcrpositioning, td->td_ycbcrpositioning);
+ break;
+ }
+ }
+ if (TIFFFieldSet(tif,FIELD_HALFTONEHINTS))
+ fprintf(fd, " Halftone Hints: light %u dark %u\n",
+ td->td_halftonehints[0], td->td_halftonehints[1]);
+ if (TIFFFieldSet(tif,FIELD_ORIENTATION)) {
+ fprintf(fd, " Orientation: ");
+ if (td->td_orientation < NORIENTNAMES)
+ fprintf(fd, "%s\n", orientNames[td->td_orientation]);
+ else
+ fprintf(fd, "%u (0x%x)\n",
+ td->td_orientation, td->td_orientation);
+ }
+ if (TIFFFieldSet(tif,FIELD_SAMPLESPERPIXEL))
+ fprintf(fd, " Samples/Pixel: %u\n", td->td_samplesperpixel);
+ if (TIFFFieldSet(tif,FIELD_ROWSPERSTRIP)) {
+ fprintf(fd, " Rows/Strip: ");
+ if (td->td_rowsperstrip == (uint32) -1)
+ fprintf(fd, "(infinite)\n");
+ else
+ fprintf(fd, "%lu\n", (unsigned long) td->td_rowsperstrip);
+ }
+ if (TIFFFieldSet(tif,FIELD_MINSAMPLEVALUE))
+ fprintf(fd, " Min Sample Value: %u\n", td->td_minsamplevalue);
+ if (TIFFFieldSet(tif,FIELD_MAXSAMPLEVALUE))
+ fprintf(fd, " Max Sample Value: %u\n", td->td_maxsamplevalue);
+ if (TIFFFieldSet(tif,FIELD_SMINSAMPLEVALUE))
+ fprintf(fd, " SMin Sample Value: %g\n",
+ td->td_sminsamplevalue);
+ if (TIFFFieldSet(tif,FIELD_SMAXSAMPLEVALUE))
+ fprintf(fd, " SMax Sample Value: %g\n",
+ td->td_smaxsamplevalue);
+ if (TIFFFieldSet(tif,FIELD_PLANARCONFIG)) {
+ fprintf(fd, " Planar Configuration: ");
+ switch (td->td_planarconfig) {
+ case PLANARCONFIG_CONTIG:
+ fprintf(fd, "single image plane\n");
+ break;
+ case PLANARCONFIG_SEPARATE:
+ fprintf(fd, "separate image planes\n");
+ break;
+ default:
+ fprintf(fd, "%u (0x%x)\n",
+ td->td_planarconfig, td->td_planarconfig);
+ break;
+ }
+ }
+ if (TIFFFieldSet(tif,FIELD_PAGENUMBER))
+ fprintf(fd, " Page Number: %u-%u\n",
+ td->td_pagenumber[0], td->td_pagenumber[1]);
+ if (TIFFFieldSet(tif,FIELD_COLORMAP)) {
+ fprintf(fd, " Color Map: ");
+ if (flags & TIFFPRINT_COLORMAP) {
+ fprintf(fd, "\n");
+ n = 1L<<td->td_bitspersample;
+ for (l = 0; l < n; l++)
+ fprintf(fd, " %5lu: %5u %5u %5u\n",
+ l,
+ td->td_colormap[0][l],
+ td->td_colormap[1][l],
+ td->td_colormap[2][l]);
+ } else
+ fprintf(fd, "(present)\n");
+ }
+ if (TIFFFieldSet(tif,FIELD_TRANSFERFUNCTION)) {
+ fprintf(fd, " Transfer Function: ");
+ if (flags & TIFFPRINT_CURVES) {
+ fprintf(fd, "\n");
+ n = 1L<<td->td_bitspersample;
+ for (l = 0; l < n; l++) {
+ fprintf(fd, " %2lu: %5u",
+ l, td->td_transferfunction[0][l]);
+ for (i = 1; i < td->td_samplesperpixel; i++)
+ fprintf(fd, " %5u",
+ td->td_transferfunction[i][l]);
+ fputc('\n', fd);
+ }
+ } else
+ fprintf(fd, "(present)\n");
+ }
+ if (TIFFFieldSet(tif, FIELD_SUBIFD) && (td->td_subifd)) {
+ fprintf(fd, " SubIFD Offsets:");
+ for (i = 0; i < td->td_nsubifd; i++)
+ fprintf(fd, " %5lu", (long) td->td_subifd[i]);
+ fputc('\n', fd);
+ }
+
+ /*
+ ** Custom tag support.
+ */
+ {
+ int i;
+ short count;
+
+ count = (short) TIFFGetTagListCount(tif);
+ for(i = 0; i < count; i++) {
+ ttag_t tag = TIFFGetTagListEntry(tif, i);
+ const TIFFFieldInfo *fip;
+ uint32 value_count;
+ int mem_alloc = 0;
+ void *raw_data;
+
+ fip = TIFFFieldWithTag(tif, tag);
+ if(fip == NULL)
+ continue;
+
+ if(fip->field_passcount) {
+ if(TIFFGetField(tif, tag, &value_count, &raw_data) != 1)
+ continue;
+ } else {
+ if (fip->field_readcount == TIFF_VARIABLE
+ || fip->field_readcount == TIFF_VARIABLE2)
+ value_count = 1;
+ else if (fip->field_readcount == TIFF_SPP)
+ value_count = td->td_samplesperpixel;
+ else
+ value_count = fip->field_readcount;
+ if ((fip->field_type == TIFF_ASCII
+ || fip->field_readcount == TIFF_VARIABLE
+ || fip->field_readcount == TIFF_VARIABLE2
+ || fip->field_readcount == TIFF_SPP
+ || value_count > 1)
+ && fip->field_tag != TIFFTAG_PAGENUMBER
+ && fip->field_tag != TIFFTAG_HALFTONEHINTS
+ && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
+ && fip->field_tag != TIFFTAG_DOTRANGE) {
+ if(TIFFGetField(tif, tag, &raw_data) != 1)
+ continue;
+ } else if (fip->field_tag != TIFFTAG_PAGENUMBER
+ && fip->field_tag != TIFFTAG_HALFTONEHINTS
+ && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
+ && fip->field_tag != TIFFTAG_DOTRANGE) {
+ raw_data = _TIFFmalloc(
+ _TIFFDataSize(fip->field_type)
+ * value_count);
+ mem_alloc = 1;
+ if(TIFFGetField(tif, tag, raw_data) != 1) {
+ _TIFFfree(raw_data);
+ continue;
+ }
+ } else {
+ /*
+ * XXX: Should be fixed and removed, see the
+ * notes related to TIFFTAG_PAGENUMBER,
+ * TIFFTAG_HALFTONEHINTS,
+ * TIFFTAG_YCBCRSUBSAMPLING and
+ * TIFFTAG_DOTRANGE tags in tif_dir.c. */
+ char *tmp;
+ raw_data = _TIFFmalloc(
+ _TIFFDataSize(fip->field_type)
+ * value_count);
+ tmp = raw_data;
+ mem_alloc = 1;
+ if(TIFFGetField(tif, tag, tmp,
+ tmp + _TIFFDataSize(fip->field_type)) != 1) {
+ _TIFFfree(raw_data);
+ continue;
+ }
+ }
+ }
+
+ /*
+ * Catch the tags which needs to be specially handled and
+ * pretty print them. If tag not handled in
+ * _TIFFPrettyPrintField() fall down and print it as any other
+ * tag.
+ */
+ if (_TIFFPrettyPrintField(tif, fd, tag, value_count, raw_data)) {
+ if(mem_alloc)
+ _TIFFfree(raw_data);
+ continue;
+ }
+ else
+ _TIFFPrintField(fd, fip, value_count, raw_data);
+
+ if(mem_alloc)
+ _TIFFfree(raw_data);
+ }
+ }
+
+ if (tif->tif_tagmethods.printdir)
+ (*tif->tif_tagmethods.printdir)(tif, fd, flags);
+ if ((flags & TIFFPRINT_STRIPS) &&
+ TIFFFieldSet(tif,FIELD_STRIPOFFSETS)) {
+ tstrip_t s;
+
+ fprintf(fd, " %lu %s:\n",
+ (long) td->td_nstrips,
+ isTiled(tif) ? "Tiles" : "Strips");
+ for (s = 0; s < td->td_nstrips; s++)
+ fprintf(fd, " %3lu: [%8lu, %8lu]\n",
+ (unsigned long) s,
+ (unsigned long) td->td_stripoffset[s],
+ (unsigned long) td->td_stripbytecount[s]);
+ }
+}
+
+void
+_TIFFprintAscii(FILE* fd, const char* cp)
+{
+ for (; *cp != '\0'; cp++) {
+ const char* tp;
+
+ if (isprint((int)*cp)) {
+ fputc(*cp, fd);
+ continue;
+ }
+ for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++)
+ if (*tp++ == *cp)
+ break;
+ if (*tp)
+ fprintf(fd, "\\%c", *tp);
+ else
+ fprintf(fd, "\\%03o", *cp & 0xff);
+ }
+}
+
+void
+_TIFFprintAsciiTag(FILE* fd, const char* name, const char* value)
+{
+ fprintf(fd, " %s: \"", name);
+ _TIFFprintAscii(fd, value);
+ fprintf(fd, "\"\n");
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_read.c b/tiff/libtiff/tif_read.c
new file mode 100644
index 0000000..8ac0ae6
--- /dev/null
+++ b/tiff/libtiff/tif_read.c
@@ -0,0 +1,750 @@
+/* $Id: tif_read.c,v 1.16.2.3 2010-06-09 14:32:47 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ * Scanline-oriented Read Support
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+
+ int TIFFFillStrip(TIFF*, tstrip_t);
+ int TIFFFillTile(TIFF*, ttile_t);
+static int TIFFStartStrip(TIFF*, tstrip_t);
+static int TIFFStartTile(TIFF*, ttile_t);
+static int TIFFCheckRead(TIFF*, int);
+
+#define NOSTRIP ((tstrip_t) -1) /* undefined state */
+#define NOTILE ((ttile_t) -1) /* undefined state */
+
+/*
+ * Seek to a random row+sample in a file.
+ */
+static int
+TIFFSeek(TIFF* tif, uint32 row, tsample_t sample)
+{
+ register TIFFDirectory *td = &tif->tif_dir;
+ tstrip_t strip;
+
+ if (row >= td->td_imagelength) { /* out of range */
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Row out of range, max %lu",
+ (unsigned long) row,
+ (unsigned long) td->td_imagelength);
+ return (0);
+ }
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+ if (sample >= td->td_samplesperpixel) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Sample out of range, max %lu",
+ (unsigned long) sample, (unsigned long) td->td_samplesperpixel);
+ return (0);
+ }
+ strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip;
+ } else
+ strip = row / td->td_rowsperstrip;
+ if (strip != tif->tif_curstrip) { /* different strip, refill */
+ if (!TIFFFillStrip(tif, strip))
+ return (0);
+ } else if (row < tif->tif_row) {
+ /*
+ * Moving backwards within the same strip: backup
+ * to the start and then decode forward (below).
+ *
+ * NB: If you're planning on lots of random access within a
+ * strip, it's better to just read and decode the entire
+ * strip, and then access the decoded data in a random fashion.
+ */
+ if (!TIFFStartStrip(tif, strip))
+ return (0);
+ }
+ if (row != tif->tif_row) {
+ /*
+ * Seek forward to the desired row.
+ */
+ if (!(*tif->tif_seek)(tif, row - tif->tif_row))
+ return (0);
+ tif->tif_row = row;
+ }
+ return (1);
+}
+
+int
+TIFFReadScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample)
+{
+ int e;
+
+ if (!TIFFCheckRead(tif, 0))
+ return (-1);
+ if( (e = TIFFSeek(tif, row, sample)) != 0) {
+ /*
+ * Decompress desired row into user buffer.
+ */
+ e = (*tif->tif_decoderow)
+ (tif, (tidata_t) buf, tif->tif_scanlinesize, sample);
+
+ /* we are now poised at the beginning of the next row */
+ tif->tif_row = row + 1;
+
+ if (e)
+ (*tif->tif_postdecode)(tif, (tidata_t) buf,
+ tif->tif_scanlinesize);
+ }
+ return (e > 0 ? 1 : -1);
+}
+
+/*
+ * Read a strip of data and decompress the specified
+ * amount into the user-supplied buffer.
+ */
+tsize_t
+TIFFReadEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ uint32 nrows;
+ tsize_t stripsize;
+ tstrip_t sep_strip, strips_per_sep;
+
+ if (!TIFFCheckRead(tif, 0))
+ return (-1);
+ if (strip >= td->td_nstrips) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%ld: Strip out of range, max %ld",
+ (long) strip, (long) td->td_nstrips);
+ return (-1);
+ }
+ /*
+ * Calculate the strip size according to the number of
+ * rows in the strip (check for truncated last strip on any
+ * of the separations).
+ */
+ if( td->td_rowsperstrip >= td->td_imagelength )
+ strips_per_sep = 1;
+ else
+ strips_per_sep = (td->td_imagelength+td->td_rowsperstrip-1)
+ / td->td_rowsperstrip;
+
+ sep_strip = strip % strips_per_sep;
+
+ if (sep_strip != strips_per_sep-1 ||
+ (nrows = td->td_imagelength % td->td_rowsperstrip) == 0)
+ nrows = td->td_rowsperstrip;
+
+ stripsize = TIFFVStripSize(tif, nrows);
+ if (size == (tsize_t) -1)
+ size = stripsize;
+ else if (size > stripsize)
+ size = stripsize;
+ if (TIFFFillStrip(tif, strip)
+ && (*tif->tif_decodestrip)(tif, (tidata_t) buf, size,
+ (tsample_t)(strip / td->td_stripsperimage)) > 0 ) {
+ (*tif->tif_postdecode)(tif, (tidata_t) buf, size);
+ return (size);
+ } else
+ return ((tsize_t) -1);
+}
+
+static tsize_t
+TIFFReadRawStrip1(TIFF* tif,
+ tstrip_t strip, tdata_t buf, tsize_t size, const char* module)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+ if (!isMapped(tif)) {
+ tsize_t cc;
+
+ if (!SeekOK(tif, td->td_stripoffset[strip])) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Seek error at scanline %lu, strip %lu",
+ tif->tif_name,
+ (unsigned long) tif->tif_row, (unsigned long) strip);
+ return (-1);
+ }
+ cc = TIFFReadFile(tif, buf, size);
+ if (cc != size) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Read error at scanline %lu; got %lu bytes, expected %lu",
+ tif->tif_name,
+ (unsigned long) tif->tif_row,
+ (unsigned long) cc,
+ (unsigned long) size);
+ return (-1);
+ }
+ } else {
+ if (td->td_stripoffset[strip] + size > tif->tif_size) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Read error at scanline %lu, strip %lu; got %lu bytes, expected %lu",
+ tif->tif_name,
+ (unsigned long) tif->tif_row,
+ (unsigned long) strip,
+ (unsigned long) tif->tif_size - td->td_stripoffset[strip],
+ (unsigned long) size);
+ return (-1);
+ }
+ _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[strip],
+ size);
+ }
+ return (size);
+}
+
+/*
+ * Read a strip of data from the file.
+ */
+tsize_t
+TIFFReadRawStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size)
+{
+ static const char module[] = "TIFFReadRawStrip";
+ TIFFDirectory *td = &tif->tif_dir;
+ /*
+ * FIXME: butecount should have tsize_t type, but for now libtiff
+ * defines tsize_t as a signed 32-bit integer and we are losing
+ * ability to read arrays larger than 2^31 bytes. So we are using
+ * uint32 instead of tsize_t here.
+ */
+ uint32 bytecount;
+
+ if (!TIFFCheckRead(tif, 0))
+ return ((tsize_t) -1);
+ if (strip >= td->td_nstrips) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Strip out of range, max %lu",
+ (unsigned long) strip,
+ (unsigned long) td->td_nstrips);
+ return ((tsize_t) -1);
+ }
+ if (tif->tif_flags&TIFF_NOREADRAW)
+ {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Compression scheme does not support access to raw uncompressed data");
+ return ((tsize_t) -1);
+ }
+ bytecount = td->td_stripbytecount[strip];
+ if (bytecount <= 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Invalid strip byte count, strip %lu",
+ (unsigned long) bytecount, (unsigned long) strip);
+ return ((tsize_t) -1);
+ }
+ if (size != (tsize_t)-1 && (uint32)size < bytecount)
+ bytecount = size;
+ return (TIFFReadRawStrip1(tif, strip, buf, bytecount, module));
+}
+
+/*
+ * Read the specified strip and setup for decoding. The data buffer is
+ * expanded, as necessary, to hold the strip's data.
+ */
+int
+TIFFFillStrip(TIFF* tif, tstrip_t strip)
+{
+ static const char module[] = "TIFFFillStrip";
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if ((tif->tif_flags&TIFF_NOREADRAW)==0)
+ {
+ /*
+ * FIXME: butecount should have tsize_t type, but for now
+ * libtiff defines tsize_t as a signed 32-bit integer and we
+ * are losing ability to read arrays larger than 2^31 bytes.
+ * So we are using uint32 instead of tsize_t here.
+ */
+ uint32 bytecount = td->td_stripbytecount[strip];
+ if (bytecount <= 0) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Invalid strip byte count %lu, strip %lu",
+ tif->tif_name, (unsigned long) bytecount,
+ (unsigned long) strip);
+ return (0);
+ }
+ if (isMapped(tif) &&
+ (isFillOrder(tif, td->td_fillorder)
+ || (tif->tif_flags & TIFF_NOBITREV))) {
+ /*
+ * The image is mapped into memory and we either don't
+ * need to flip bits or the compression routine is
+ * going to handle this operation itself. In this
+ * case, avoid copying the raw data and instead just
+ * reference the data from the memory mapped file
+ * image. This assumes that the decompression
+ * routines do not modify the contents of the raw data
+ * buffer (if they try to, the application will get a
+ * fault since the file is mapped read-only).
+ */
+ if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
+ _TIFFfree(tif->tif_rawdata);
+ tif->tif_flags &= ~TIFF_MYBUFFER;
+ /*
+ * We must check for overflow, potentially causing
+ * an OOB read. Instead of simple
+ *
+ * td->td_stripoffset[strip]+bytecount > tif->tif_size
+ *
+ * comparison (which can overflow) we do the following
+ * two comparisons:
+ */
+ if (bytecount > tif->tif_size ||
+ td->td_stripoffset[strip] > tif->tif_size - bytecount) {
+ /*
+ * This error message might seem strange, but
+ * it's what would happen if a read were done
+ * instead.
+ */
+ TIFFErrorExt(tif->tif_clientdata, module,
+
+ "%s: Read error on strip %lu; "
+ "got %lu bytes, expected %lu",
+ tif->tif_name, (unsigned long) strip,
+ (unsigned long) tif->tif_size - td->td_stripoffset[strip],
+ (unsigned long) bytecount);
+ tif->tif_curstrip = NOSTRIP;
+ return (0);
+ }
+ tif->tif_rawdatasize = bytecount;
+ tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip];
+ } else {
+ /*
+ * Expand raw data buffer, if needed, to hold data
+ * strip coming from file (perhaps should set upper
+ * bound on the size of a buffer we'll use?).
+ */
+ if (bytecount > (uint32)tif->tif_rawdatasize) {
+ tif->tif_curstrip = NOSTRIP;
+ if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
+ TIFFErrorExt(tif->tif_clientdata,
+ module,
+ "%s: Data buffer too small to hold strip %lu",
+ tif->tif_name,
+ (unsigned long) strip);
+ return (0);
+ }
+ if (!TIFFReadBufferSetup(tif, 0,
+ TIFFroundup(bytecount, 1024)))
+ return (0);
+ }
+ if ((uint32)TIFFReadRawStrip1(tif, strip,
+ (unsigned char *)tif->tif_rawdata,
+ bytecount, module) != bytecount)
+ return (0);
+ if (!isFillOrder(tif, td->td_fillorder) &&
+ (tif->tif_flags & TIFF_NOBITREV) == 0)
+ TIFFReverseBits(tif->tif_rawdata, bytecount);
+ }
+ }
+ return (TIFFStartStrip(tif, strip));
+}
+
+/*
+ * Tile-oriented Read Support
+ * Contributed by Nancy Cam (Silicon Graphics).
+ */
+
+/*
+ * Read and decompress a tile of data. The
+ * tile is selected by the (x,y,z,s) coordinates.
+ */
+tsize_t
+TIFFReadTile(TIFF* tif,
+ tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s)
+{
+ if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s))
+ return (-1);
+ return (TIFFReadEncodedTile(tif,
+ TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1));
+}
+
+/*
+ * Read a tile of data and decompress the specified
+ * amount into the user-supplied buffer.
+ */
+tsize_t
+TIFFReadEncodedTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tsize_t tilesize = tif->tif_tilesize;
+
+ if (!TIFFCheckRead(tif, 1))
+ return (-1);
+ if (tile >= td->td_nstrips) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%ld: Tile out of range, max %ld",
+ (long) tile, (unsigned long) td->td_nstrips);
+ return (-1);
+ }
+ if (size == (tsize_t) -1)
+ size = tilesize;
+ else if (size > tilesize)
+ size = tilesize;
+ if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif,
+ (tidata_t) buf, size, (tsample_t)(tile/td->td_stripsperimage))) {
+ (*tif->tif_postdecode)(tif, (tidata_t) buf, size);
+ return (size);
+ } else
+ return (-1);
+}
+
+static tsize_t
+TIFFReadRawTile1(TIFF* tif,
+ ttile_t tile, tdata_t buf, tsize_t size, const char* module)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+ if (!isMapped(tif)) {
+ tsize_t cc;
+
+ if (!SeekOK(tif, td->td_stripoffset[tile])) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Seek error at row %ld, col %ld, tile %ld",
+ tif->tif_name,
+ (long) tif->tif_row,
+ (long) tif->tif_col,
+ (long) tile);
+ return ((tsize_t) -1);
+ }
+ cc = TIFFReadFile(tif, buf, size);
+ if (cc != size) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Read error at row %ld, col %ld; got %lu bytes, expected %lu",
+ tif->tif_name,
+ (long) tif->tif_row,
+ (long) tif->tif_col,
+ (unsigned long) cc,
+ (unsigned long) size);
+ return ((tsize_t) -1);
+ }
+ } else {
+ if (td->td_stripoffset[tile] + size > tif->tif_size) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Read error at row %ld, col %ld, tile %ld; got %lu bytes, expected %lu",
+ tif->tif_name,
+ (long) tif->tif_row,
+ (long) tif->tif_col,
+ (long) tile,
+ (unsigned long) tif->tif_size - td->td_stripoffset[tile],
+ (unsigned long) size);
+ return ((tsize_t) -1);
+ }
+ _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[tile], size);
+ }
+ return (size);
+}
+
+/*
+ * Read a tile of data from the file.
+ */
+tsize_t
+TIFFReadRawTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size)
+{
+ static const char module[] = "TIFFReadRawTile";
+ TIFFDirectory *td = &tif->tif_dir;
+ /*
+ * FIXME: butecount should have tsize_t type, but for now libtiff
+ * defines tsize_t as a signed 32-bit integer and we are losing
+ * ability to read arrays larger than 2^31 bytes. So we are using
+ * uint32 instead of tsize_t here.
+ */
+ uint32 bytecount;
+
+ if (!TIFFCheckRead(tif, 1))
+ return ((tsize_t) -1);
+ if (tile >= td->td_nstrips) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Tile out of range, max %lu",
+ (unsigned long) tile, (unsigned long) td->td_nstrips);
+ return ((tsize_t) -1);
+ }
+ if (tif->tif_flags&TIFF_NOREADRAW)
+ {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Compression scheme does not support access to raw uncompressed data");
+ return ((tsize_t) -1);
+ }
+ bytecount = td->td_stripbytecount[tile];
+ if (size != (tsize_t) -1 && (uint32)size < bytecount)
+ bytecount = size;
+ return (TIFFReadRawTile1(tif, tile, buf, bytecount, module));
+}
+
+/*
+ * Read the specified tile and setup for decoding. The data buffer is
+ * expanded, as necessary, to hold the tile's data.
+ */
+int
+TIFFFillTile(TIFF* tif, ttile_t tile)
+{
+ static const char module[] = "TIFFFillTile";
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if ((tif->tif_flags&TIFF_NOREADRAW)==0)
+ {
+ /*
+ * FIXME: butecount should have tsize_t type, but for now
+ * libtiff defines tsize_t as a signed 32-bit integer and we
+ * are losing ability to read arrays larger than 2^31 bytes.
+ * So we are using uint32 instead of tsize_t here.
+ */
+ uint32 bytecount = td->td_stripbytecount[tile];
+ if (bytecount <= 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Invalid tile byte count, tile %lu",
+ (unsigned long) bytecount, (unsigned long) tile);
+ return (0);
+ }
+ if (isMapped(tif) &&
+ (isFillOrder(tif, td->td_fillorder)
+ || (tif->tif_flags & TIFF_NOBITREV))) {
+ /*
+ * The image is mapped into memory and we either don't
+ * need to flip bits or the compression routine is
+ * going to handle this operation itself. In this
+ * case, avoid copying the raw data and instead just
+ * reference the data from the memory mapped file
+ * image. This assumes that the decompression
+ * routines do not modify the contents of the raw data
+ * buffer (if they try to, the application will get a
+ * fault since the file is mapped read-only).
+ */
+ if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
+ _TIFFfree(tif->tif_rawdata);
+ tif->tif_flags &= ~TIFF_MYBUFFER;
+ /*
+ * We must check for overflow, potentially causing
+ * an OOB read. Instead of simple
+ *
+ * td->td_stripoffset[tile]+bytecount > tif->tif_size
+ *
+ * comparison (which can overflow) we do the following
+ * two comparisons:
+ */
+ if (bytecount > tif->tif_size ||
+ td->td_stripoffset[tile] > tif->tif_size - bytecount) {
+ tif->tif_curtile = NOTILE;
+ return (0);
+ }
+ tif->tif_rawdatasize = bytecount;
+ tif->tif_rawdata =
+ tif->tif_base + td->td_stripoffset[tile];
+ } else {
+ /*
+ * Expand raw data buffer, if needed, to hold data
+ * tile coming from file (perhaps should set upper
+ * bound on the size of a buffer we'll use?).
+ */
+ if (bytecount > (uint32)tif->tif_rawdatasize) {
+ tif->tif_curtile = NOTILE;
+ if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
+ TIFFErrorExt(tif->tif_clientdata,
+ module,
+ "%s: Data buffer too small to hold tile %ld",
+ tif->tif_name,
+ (long) tile);
+ return (0);
+ }
+ if (!TIFFReadBufferSetup(tif, 0,
+ TIFFroundup(bytecount, 1024)))
+ return (0);
+ }
+ if ((uint32)TIFFReadRawTile1(tif, tile,
+ (unsigned char *)tif->tif_rawdata,
+ bytecount, module) != bytecount)
+ return (0);
+ if (!isFillOrder(tif, td->td_fillorder) &&
+ (tif->tif_flags & TIFF_NOBITREV) == 0)
+ TIFFReverseBits(tif->tif_rawdata, bytecount);
+ }
+ }
+ return (TIFFStartTile(tif, tile));
+}
+
+/*
+ * Setup the raw data buffer in preparation for
+ * reading a strip of raw data. If the buffer
+ * is specified as zero, then a buffer of appropriate
+ * size is allocated by the library. Otherwise,
+ * the client must guarantee that the buffer is
+ * large enough to hold any individual strip of
+ * raw data.
+ */
+int
+TIFFReadBufferSetup(TIFF* tif, tdata_t bp, tsize_t size)
+{
+ static const char module[] = "TIFFReadBufferSetup";
+
+ assert((tif->tif_flags&TIFF_NOREADRAW)==0);
+ if (tif->tif_rawdata) {
+ if (tif->tif_flags & TIFF_MYBUFFER)
+ _TIFFfree(tif->tif_rawdata);
+ tif->tif_rawdata = NULL;
+ }
+
+ if (bp) {
+ tif->tif_rawdatasize = size;
+ tif->tif_rawdata = (tidata_t) bp;
+ tif->tif_flags &= ~TIFF_MYBUFFER;
+ } else {
+ tif->tif_rawdatasize = TIFFroundup(size, 1024);
+ if (tif->tif_rawdatasize > 0)
+ tif->tif_rawdata = (tidata_t) _TIFFmalloc(tif->tif_rawdatasize);
+ tif->tif_flags |= TIFF_MYBUFFER;
+ }
+ if ((tif->tif_rawdata == NULL) || (tif->tif_rawdatasize == 0)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: No space for data buffer at scanline %ld",
+ tif->tif_name, (long) tif->tif_row);
+ tif->tif_rawdatasize = 0;
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Set state to appear as if a
+ * strip has just been read in.
+ */
+static int
+TIFFStartStrip(TIFF* tif, tstrip_t strip)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+ if (!(*tif->tif_setupdecode)(tif))
+ return (0);
+ tif->tif_flags |= TIFF_CODERSETUP;
+ }
+ tif->tif_curstrip = strip;
+ tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+ if (tif->tif_flags&TIFF_NOREADRAW)
+ {
+ tif->tif_rawcp = NULL;
+ tif->tif_rawcc = 0;
+ }
+ else
+ {
+ tif->tif_rawcp = tif->tif_rawdata;
+ tif->tif_rawcc = td->td_stripbytecount[strip];
+ }
+ return ((*tif->tif_predecode)(tif,
+ (tsample_t)(strip / td->td_stripsperimage)));
+}
+
+/*
+ * Set state to appear as if a
+ * tile has just been read in.
+ */
+static int
+TIFFStartTile(TIFF* tif, ttile_t tile)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+ if (!(*tif->tif_setupdecode)(tif))
+ return (0);
+ tif->tif_flags |= TIFF_CODERSETUP;
+ }
+ tif->tif_curtile = tile;
+ tif->tif_row =
+ (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) *
+ td->td_tilelength;
+ tif->tif_col =
+ (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) *
+ td->td_tilewidth;
+ if (tif->tif_flags&TIFF_NOREADRAW)
+ {
+ tif->tif_rawcp = NULL;
+ tif->tif_rawcc = 0;
+ }
+ else
+ {
+ tif->tif_rawcp = tif->tif_rawdata;
+ tif->tif_rawcc = td->td_stripbytecount[tile];
+ }
+ return ((*tif->tif_predecode)(tif,
+ (tsample_t)(tile/td->td_stripsperimage)));
+}
+
+static int
+TIFFCheckRead(TIFF* tif, int tiles)
+{
+ if (tif->tif_mode == O_WRONLY) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "File not open for reading");
+ return (0);
+ }
+ if (tiles ^ isTiled(tif)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ?
+ "Can not read tiles from a stripped image" :
+ "Can not read scanlines from a tiled image");
+ return (0);
+ }
+ return (1);
+}
+
+void
+_TIFFNoPostDecode(TIFF* tif, tidata_t buf, tsize_t cc)
+{
+ (void) tif; (void) buf; (void) cc;
+}
+
+void
+_TIFFSwab16BitData(TIFF* tif, tidata_t buf, tsize_t cc)
+{
+ (void) tif;
+ assert((cc & 1) == 0);
+ TIFFSwabArrayOfShort((uint16*) buf, cc/2);
+}
+
+void
+_TIFFSwab24BitData(TIFF* tif, tidata_t buf, tsize_t cc)
+{
+ (void) tif;
+ assert((cc % 3) == 0);
+ TIFFSwabArrayOfTriples((uint8*) buf, cc/3);
+}
+
+void
+_TIFFSwab32BitData(TIFF* tif, tidata_t buf, tsize_t cc)
+{
+ (void) tif;
+ assert((cc & 3) == 0);
+ TIFFSwabArrayOfLong((uint32*) buf, cc/4);
+}
+
+void
+_TIFFSwab64BitData(TIFF* tif, tidata_t buf, tsize_t cc)
+{
+ (void) tif;
+ assert((cc & 7) == 0);
+ TIFFSwabArrayOfDouble((double*) buf, cc/8);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_stream.cxx b/tiff/libtiff/tif_stream.cxx
new file mode 100644
index 0000000..2a2351b
--- /dev/null
+++ b/tiff/libtiff/tif_stream.cxx
@@ -0,0 +1,295 @@
+/* $Id: tif_stream.cxx,v 1.6.2.1 2009-01-01 00:10:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1996 Sam Leffler
+ * Copyright (c) 1991-1996 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library UNIX-specific Routines.
+ */
+#include "tiffiop.h"
+#include <iostream>
+
+#ifndef __VMS
+using namespace std;
+#endif
+
+class tiffis_data
+{
+ public:
+
+ istream *myIS;
+ long myStreamStartPos;
+};
+
+class tiffos_data
+{
+ public:
+
+ ostream *myOS;
+ long myStreamStartPos;
+};
+
+static tsize_t
+_tiffosReadProc(thandle_t, tdata_t, tsize_t)
+{
+ return 0;
+}
+
+static tsize_t
+_tiffisReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ tiffis_data *data = (tiffis_data *)fd;
+
+ data->myIS->read((char *)buf, (int)size);
+
+ return data->myIS->gcount();
+}
+
+static tsize_t
+_tiffosWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ tiffos_data *data = (tiffos_data *)fd;
+ ostream *os = data->myOS;
+ int pos = os->tellp();
+
+ os->write((const char *)buf, size);
+
+ return ((int)os->tellp()) - pos;
+}
+
+static tsize_t
+_tiffisWriteProc(thandle_t, tdata_t, tsize_t)
+{
+ return 0;
+}
+
+static toff_t
+_tiffosSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ tiffos_data *data = (tiffos_data *)fd;
+ ostream *os = data->myOS;
+
+ // if the stream has already failed, don't do anything
+ if( os->fail() )
+ return os->tellp();
+
+ switch(whence) {
+ case SEEK_SET:
+ os->seekp(data->myStreamStartPos + off, ios::beg);
+ break;
+ case SEEK_CUR:
+ os->seekp(off, ios::cur);
+ break;
+ case SEEK_END:
+ os->seekp(off, ios::end);
+ break;
+ }
+
+ // Attempt to workaround problems with seeking past the end of the
+ // stream. ofstream doesn't have a problem with this but
+ // ostrstream/ostringstream does. In that situation, add intermediate
+ // '\0' characters.
+ if( os->fail() ) {
+#ifdef __VMS
+ int old_state;
+#else
+ ios::iostate old_state;
+#endif
+ toff_t origin=0;
+
+ old_state = os->rdstate();
+ // reset the fail bit or else tellp() won't work below
+ os->clear(os->rdstate() & ~ios::failbit);
+ switch( whence ) {
+ case SEEK_SET:
+ origin = data->myStreamStartPos;
+ break;
+ case SEEK_CUR:
+ origin = os->tellp();
+ break;
+ case SEEK_END:
+ os->seekp(0, ios::end);
+ origin = os->tellp();
+ break;
+ }
+ // restore original stream state
+ os->clear(old_state);
+
+ // only do something if desired seek position is valid
+ if( origin + off > data->myStreamStartPos ) {
+ toff_t num_fill;
+
+ // clear the fail bit
+ os->clear(os->rdstate() & ~ios::failbit);
+
+ // extend the stream to the expected size
+ os->seekp(0, ios::end);
+ num_fill = origin + off - (toff_t)os->tellp();
+ for( toff_t i = 0; i < num_fill; i++ )
+ os->put('\0');
+
+ // retry the seek
+ os->seekp(origin + off, ios::beg);
+ }
+ }
+
+ return os->tellp();
+}
+
+static toff_t
+_tiffisSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ tiffis_data *data = (tiffis_data *)fd;
+
+ switch(whence) {
+ case SEEK_SET:
+ data->myIS->seekg(data->myStreamStartPos + off, ios::beg);
+ break;
+ case SEEK_CUR:
+ data->myIS->seekg(off, ios::cur);
+ break;
+ case SEEK_END:
+ data->myIS->seekg(off, ios::end);
+ break;
+ }
+
+ return ((long)data->myIS->tellg()) - data->myStreamStartPos;
+}
+
+static toff_t
+_tiffosSizeProc(thandle_t fd)
+{
+ tiffos_data *data = (tiffos_data *)fd;
+ ostream *os = data->myOS;
+ toff_t pos = os->tellp();
+ toff_t len;
+
+ os->seekp(0, ios::end);
+ len = os->tellp();
+ os->seekp(pos);
+
+ return len;
+}
+
+static toff_t
+_tiffisSizeProc(thandle_t fd)
+{
+ tiffis_data *data = (tiffis_data *)fd;
+ int pos = data->myIS->tellg();
+ int len;
+
+ data->myIS->seekg(0, ios::end);
+ len = data->myIS->tellg();
+ data->myIS->seekg(pos);
+
+ return len;
+}
+
+static int
+_tiffosCloseProc(thandle_t fd)
+{
+ // Our stream was not allocated by us, so it shouldn't be closed by us.
+ delete (tiffos_data *)fd;
+ return 0;
+}
+
+static int
+_tiffisCloseProc(thandle_t fd)
+{
+ // Our stream was not allocated by us, so it shouldn't be closed by us.
+ delete (tiffis_data *)fd;
+ return 0;
+}
+
+static int
+_tiffDummyMapProc(thandle_t , tdata_t* , toff_t* )
+{
+ return (0);
+}
+
+static void
+_tiffDummyUnmapProc(thandle_t , tdata_t , toff_t )
+{
+}
+
+/*
+ * Open a TIFF file descriptor for read/writing.
+ */
+static TIFF*
+_tiffStreamOpen(const char* name, const char* mode, void *fd)
+{
+ TIFF* tif;
+
+ if( strchr(mode, 'w') ) {
+ tiffos_data *data = new tiffos_data;
+ data->myOS = (ostream *)fd;
+ data->myStreamStartPos = data->myOS->tellp();
+
+ // Open for writing.
+ tif = TIFFClientOpen(name, mode,
+ (thandle_t) data,
+ _tiffosReadProc, _tiffosWriteProc,
+ _tiffosSeekProc, _tiffosCloseProc,
+ _tiffosSizeProc,
+ _tiffDummyMapProc, _tiffDummyUnmapProc);
+ } else {
+ tiffis_data *data = new tiffis_data;
+ data->myIS = (istream *)fd;
+ data->myStreamStartPos = data->myIS->tellg();
+ // Open for reading.
+ tif = TIFFClientOpen(name, mode,
+ (thandle_t) data,
+ _tiffisReadProc, _tiffisWriteProc,
+ _tiffisSeekProc, _tiffisCloseProc,
+ _tiffisSizeProc,
+ _tiffDummyMapProc, _tiffDummyUnmapProc);
+ }
+
+ return (tif);
+}
+
+TIFF*
+TIFFStreamOpen(const char* name, ostream *os)
+{
+ // If os is either a ostrstream or ostringstream, and has no data
+ // written to it yet, then tellp() will return -1 which will break us.
+ // We workaround this by writing out a dummy character and
+ // then seek back to the beginning.
+ if( !os->fail() && (int)os->tellp() < 0 ) {
+ *os << '\0';
+ os->seekp(0);
+ }
+
+ // NB: We don't support mapped files with streams so add 'm'
+ return _tiffStreamOpen(name, "wm", os);
+}
+
+TIFF*
+TIFFStreamOpen(const char* name, istream *is)
+{
+ // NB: We don't support mapped files with streams so add 'm'
+ return _tiffStreamOpen(name, "rm", is);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
diff --git a/tiff/libtiff/tif_strip.c b/tiff/libtiff/tif_strip.c
new file mode 100644
index 0000000..63dec6b
--- /dev/null
+++ b/tiff/libtiff/tif_strip.c
@@ -0,0 +1,370 @@
+/* $Id: tif_strip.c,v 1.19.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Strip-organized Image Support Routines.
+ */
+#include "tiffiop.h"
+
+static uint32
+summarize(TIFF* tif, size_t summand1, size_t summand2, const char* where)
+{
+ /*
+ * XXX: We are using casting to uint32 here, bacause sizeof(size_t)
+ * may be larger than sizeof(uint32) on 64-bit architectures.
+ */
+ uint32 bytes = summand1 + summand2;
+
+ if (bytes - summand1 != summand2) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where);
+ bytes = 0;
+ }
+
+ return (bytes);
+}
+
+static uint32
+multiply(TIFF* tif, size_t nmemb, size_t elem_size, const char* where)
+{
+ uint32 bytes = nmemb * elem_size;
+
+ if (elem_size && bytes / elem_size != nmemb) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where);
+ bytes = 0;
+ }
+
+ return (bytes);
+}
+
+/*
+ * Compute which strip a (row,sample) value is in.
+ */
+tstrip_t
+TIFFComputeStrip(TIFF* tif, uint32 row, tsample_t sample)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tstrip_t strip;
+
+ strip = row / td->td_rowsperstrip;
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+ if (sample >= td->td_samplesperpixel) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Sample out of range, max %lu",
+ (unsigned long) sample, (unsigned long) td->td_samplesperpixel);
+ return ((tstrip_t) 0);
+ }
+ strip += sample*td->td_stripsperimage;
+ }
+ return (strip);
+}
+
+/*
+ * Compute how many strips are in an image.
+ */
+tstrip_t
+TIFFNumberOfStrips(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tstrip_t nstrips;
+
+ nstrips = (td->td_rowsperstrip == (uint32) -1 ? 1 :
+ TIFFhowmany(td->td_imagelength, td->td_rowsperstrip));
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+ nstrips = multiply(tif, nstrips, td->td_samplesperpixel,
+ "TIFFNumberOfStrips");
+ return (nstrips);
+}
+
+/*
+ * Compute the # bytes in a variable height, row-aligned strip.
+ */
+tsize_t
+TIFFVStripSize(TIFF* tif, uint32 nrows)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if (nrows == (uint32) -1)
+ nrows = td->td_imagelength;
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
+ td->td_photometric == PHOTOMETRIC_YCBCR &&
+ !isUpSampled(tif)) {
+ /*
+ * Packed YCbCr data contain one Cb+Cr for every
+ * HorizontalSampling*VerticalSampling Y values.
+ * Must also roundup width and height when calculating
+ * since images that are not a multiple of the
+ * horizontal/vertical subsampling area include
+ * YCbCr data for the extended image.
+ */
+ uint16 ycbcrsubsampling[2];
+ tsize_t w, scanline, samplingarea;
+
+ TIFFGetField( tif, TIFFTAG_YCBCRSUBSAMPLING,
+ ycbcrsubsampling + 0,
+ ycbcrsubsampling + 1 );
+
+ samplingarea = ycbcrsubsampling[0]*ycbcrsubsampling[1];
+ if (samplingarea == 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Invalid YCbCr subsampling");
+ return 0;
+ }
+
+ w = TIFFroundup(td->td_imagewidth, ycbcrsubsampling[0]);
+ scanline = TIFFhowmany8(multiply(tif, w, td->td_bitspersample,
+ "TIFFVStripSize"));
+ nrows = TIFFroundup(nrows, ycbcrsubsampling[1]);
+ /* NB: don't need TIFFhowmany here 'cuz everything is rounded */
+ scanline = multiply(tif, nrows, scanline, "TIFFVStripSize");
+ return ((tsize_t)
+ summarize(tif, scanline,
+ multiply(tif, 2, scanline / samplingarea,
+ "TIFFVStripSize"), "TIFFVStripSize"));
+ } else
+ return ((tsize_t) multiply(tif, nrows, TIFFScanlineSize(tif),
+ "TIFFVStripSize"));
+}
+
+
+/*
+ * Compute the # bytes in a raw strip.
+ */
+tsize_t
+TIFFRawStripSize(TIFF* tif, tstrip_t strip)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ tsize_t bytecount = td->td_stripbytecount[strip];
+
+ if (bytecount <= 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Invalid strip byte count, strip %lu",
+ (unsigned long) bytecount, (unsigned long) strip);
+ bytecount = (tsize_t) -1;
+ }
+
+ return bytecount;
+}
+
+/*
+ * Compute the # bytes in a (row-aligned) strip.
+ *
+ * Note that if RowsPerStrip is larger than the
+ * recorded ImageLength, then the strip size is
+ * truncated to reflect the actual space required
+ * to hold the strip.
+ */
+tsize_t
+TIFFStripSize(TIFF* tif)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+ uint32 rps = td->td_rowsperstrip;
+ if (rps > td->td_imagelength)
+ rps = td->td_imagelength;
+ return (TIFFVStripSize(tif, rps));
+}
+
+/*
+ * Compute a default strip size based on the image
+ * characteristics and a requested value. If the
+ * request is <1 then we choose a strip size according
+ * to certain heuristics.
+ */
+uint32
+TIFFDefaultStripSize(TIFF* tif, uint32 request)
+{
+ return (*tif->tif_defstripsize)(tif, request);
+}
+
+uint32
+_TIFFDefaultStripSize(TIFF* tif, uint32 s)
+{
+ if ((int32) s < 1) {
+ /*
+ * If RowsPerStrip is unspecified, try to break the
+ * image up into strips that are approximately
+ * STRIP_SIZE_DEFAULT bytes long.
+ */
+ tsize_t scanline = TIFFScanlineSize(tif);
+ s = (uint32)STRIP_SIZE_DEFAULT / (scanline == 0 ? 1 : scanline);
+ if (s == 0) /* very wide images */
+ s = 1;
+ }
+ return (s);
+}
+
+/*
+ * Return the number of bytes to read/write in a call to
+ * one of the scanline-oriented i/o routines. Note that
+ * this number may be 1/samples-per-pixel if data is
+ * stored as separate planes.
+ */
+tsize_t
+TIFFScanlineSize(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tsize_t scanline;
+
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+ if (td->td_photometric == PHOTOMETRIC_YCBCR
+ && !isUpSampled(tif)) {
+ uint16 ycbcrsubsampling[2];
+
+ TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING,
+ ycbcrsubsampling + 0,
+ ycbcrsubsampling + 1);
+
+ if (ycbcrsubsampling[0] == 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Invalid YCbCr subsampling");
+ return 0;
+ }
+
+ scanline = TIFFroundup(td->td_imagewidth,
+ ycbcrsubsampling[0]);
+ scanline = TIFFhowmany8(multiply(tif, scanline,
+ td->td_bitspersample,
+ "TIFFScanlineSize"));
+ return ((tsize_t)
+ summarize(tif, scanline,
+ multiply(tif, 2,
+ scanline / ycbcrsubsampling[0],
+ "TIFFVStripSize"),
+ "TIFFVStripSize"));
+ } else {
+ scanline = multiply(tif, td->td_imagewidth,
+ td->td_samplesperpixel,
+ "TIFFScanlineSize");
+ }
+ } else
+ scanline = td->td_imagewidth;
+ return ((tsize_t) TIFFhowmany8(multiply(tif, scanline,
+ td->td_bitspersample,
+ "TIFFScanlineSize")));
+}
+
+/*
+ * Some stuff depends on this older version of TIFFScanlineSize
+ * TODO: resolve this
+ */
+tsize_t
+TIFFOldScanlineSize(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tsize_t scanline;
+
+ scanline = multiply (tif, td->td_bitspersample, td->td_imagewidth,
+ "TIFFScanlineSize");
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG)
+ scanline = multiply (tif, scanline, td->td_samplesperpixel,
+ "TIFFScanlineSize");
+ return ((tsize_t) TIFFhowmany8(scanline));
+}
+
+/*
+ * Return the number of bytes to read/write in a call to
+ * one of the scanline-oriented i/o routines. Note that
+ * this number may be 1/samples-per-pixel if data is
+ * stored as separate planes.
+ * The ScanlineSize in case of YCbCrSubsampling is defined as the
+ * strip size divided by the strip height, i.e. the size of a pack of vertical
+ * subsampling lines divided by vertical subsampling. It should thus make
+ * sense when multiplied by a multiple of vertical subsampling.
+ * Some stuff depends on this newer version of TIFFScanlineSize
+ * TODO: resolve this
+ */
+tsize_t
+TIFFNewScanlineSize(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tsize_t scanline;
+
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+ if (td->td_photometric == PHOTOMETRIC_YCBCR
+ && !isUpSampled(tif)) {
+ uint16 ycbcrsubsampling[2];
+
+ TIFFGetField(tif, TIFFTAG_YCBCRSUBSAMPLING,
+ ycbcrsubsampling + 0,
+ ycbcrsubsampling + 1);
+
+ if (ycbcrsubsampling[0]*ycbcrsubsampling[1] == 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Invalid YCbCr subsampling");
+ return 0;
+ }
+
+ return((tsize_t) ((((td->td_imagewidth+ycbcrsubsampling[0]-1)
+ /ycbcrsubsampling[0])
+ *(ycbcrsubsampling[0]*ycbcrsubsampling[1]+2)
+ *td->td_bitspersample+7)
+ /8)/ycbcrsubsampling[1]);
+
+ } else {
+ scanline = multiply(tif, td->td_imagewidth,
+ td->td_samplesperpixel,
+ "TIFFScanlineSize");
+ }
+ } else
+ scanline = td->td_imagewidth;
+ return ((tsize_t) TIFFhowmany8(multiply(tif, scanline,
+ td->td_bitspersample,
+ "TIFFScanlineSize")));
+}
+
+/*
+ * Return the number of bytes required to store a complete
+ * decoded and packed raster scanline (as opposed to the
+ * I/O size returned by TIFFScanlineSize which may be less
+ * if data is store as separate planes).
+ */
+tsize_t
+TIFFRasterScanlineSize(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tsize_t scanline;
+
+ scanline = multiply (tif, td->td_bitspersample, td->td_imagewidth,
+ "TIFFRasterScanlineSize");
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+ scanline = multiply (tif, scanline, td->td_samplesperpixel,
+ "TIFFRasterScanlineSize");
+ return ((tsize_t) TIFFhowmany8(scanline));
+ } else
+ return ((tsize_t) multiply (tif, TIFFhowmany8(scanline),
+ td->td_samplesperpixel,
+ "TIFFRasterScanlineSize"));
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_swab.c b/tiff/libtiff/tif_swab.c
new file mode 100644
index 0000000..e4f1a6d
--- /dev/null
+++ b/tiff/libtiff/tif_swab.c
@@ -0,0 +1,242 @@
+/* $Id: tif_swab.c,v 1.4.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library Bit & Byte Swapping Support.
+ *
+ * XXX We assume short = 16-bits and long = 32-bits XXX
+ */
+#include "tiffiop.h"
+
+#ifndef TIFFSwabShort
+void
+TIFFSwabShort(uint16* wp)
+{
+ register unsigned char* cp = (unsigned char*) wp;
+ unsigned char t;
+
+ t = cp[1]; cp[1] = cp[0]; cp[0] = t;
+}
+#endif
+
+#ifndef TIFFSwabLong
+void
+TIFFSwabLong(uint32* lp)
+{
+ register unsigned char* cp = (unsigned char*) lp;
+ unsigned char t;
+
+ t = cp[3]; cp[3] = cp[0]; cp[0] = t;
+ t = cp[2]; cp[2] = cp[1]; cp[1] = t;
+}
+#endif
+
+#ifndef TIFFSwabArrayOfShort
+void
+TIFFSwabArrayOfShort(uint16* wp, register unsigned long n)
+{
+ register unsigned char* cp;
+ register unsigned char t;
+
+ /* XXX unroll loop some */
+ while (n-- > 0) {
+ cp = (unsigned char*) wp;
+ t = cp[1]; cp[1] = cp[0]; cp[0] = t;
+ wp++;
+ }
+}
+#endif
+
+#ifndef TIFFSwabArrayOfTriples
+void
+TIFFSwabArrayOfTriples(uint8* tp, unsigned long n)
+{
+ unsigned char* cp;
+ unsigned char t;
+
+ /* XXX unroll loop some */
+ while (n-- > 0) {
+ cp = (unsigned char*) tp;
+ t = cp[2]; cp[2] = cp[0]; cp[0] = t;
+ tp += 3;
+ }
+}
+#endif
+
+#ifndef TIFFSwabArrayOfLong
+void
+TIFFSwabArrayOfLong(register uint32* lp, register unsigned long n)
+{
+ register unsigned char *cp;
+ register unsigned char t;
+
+ /* XXX unroll loop some */
+ while (n-- > 0) {
+ cp = (unsigned char *)lp;
+ t = cp[3]; cp[3] = cp[0]; cp[0] = t;
+ t = cp[2]; cp[2] = cp[1]; cp[1] = t;
+ lp++;
+ }
+}
+#endif
+
+#ifndef TIFFSwabDouble
+void
+TIFFSwabDouble(double *dp)
+{
+ register uint32* lp = (uint32*) dp;
+ uint32 t;
+
+ TIFFSwabArrayOfLong(lp, 2);
+ t = lp[0]; lp[0] = lp[1]; lp[1] = t;
+}
+#endif
+
+#ifndef TIFFSwabArrayOfDouble
+void
+TIFFSwabArrayOfDouble(double* dp, register unsigned long n)
+{
+ register uint32* lp = (uint32*) dp;
+ register uint32 t;
+
+ TIFFSwabArrayOfLong(lp, n + n);
+ while (n-- > 0) {
+ t = lp[0]; lp[0] = lp[1]; lp[1] = t;
+ lp += 2;
+ }
+}
+#endif
+
+/*
+ * Bit reversal tables. TIFFBitRevTable[<byte>] gives
+ * the bit reversed value of <byte>. Used in various
+ * places in the library when the FillOrder requires
+ * bit reversal of byte values (e.g. CCITT Fax 3
+ * encoding/decoding). TIFFNoBitRevTable is provided
+ * for algorithms that want an equivalent table that
+ * do not reverse bit values.
+ */
+static const unsigned char TIFFBitRevTable[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+static const unsigned char TIFFNoBitRevTable[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+};
+
+const unsigned char*
+TIFFGetBitRevTable(int reversed)
+{
+ return (reversed ? TIFFBitRevTable : TIFFNoBitRevTable);
+}
+
+void
+TIFFReverseBits(register unsigned char* cp, register unsigned long n)
+{
+ for (; n > 8; n -= 8) {
+ cp[0] = TIFFBitRevTable[cp[0]];
+ cp[1] = TIFFBitRevTable[cp[1]];
+ cp[2] = TIFFBitRevTable[cp[2]];
+ cp[3] = TIFFBitRevTable[cp[3]];
+ cp[4] = TIFFBitRevTable[cp[4]];
+ cp[5] = TIFFBitRevTable[cp[5]];
+ cp[6] = TIFFBitRevTable[cp[6]];
+ cp[7] = TIFFBitRevTable[cp[7]];
+ cp += 8;
+ }
+ while (n-- > 0)
+ *cp = TIFFBitRevTable[*cp], cp++;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_thunder.c b/tiff/libtiff/tif_thunder.c
new file mode 100644
index 0000000..8e7a125
--- /dev/null
+++ b/tiff/libtiff/tif_thunder.c
@@ -0,0 +1,165 @@
+/* $Id: tif_thunder.c,v 1.5.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef THUNDER_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * ThunderScan 4-bit Compression Algorithm Support
+ */
+
+/*
+ * ThunderScan uses an encoding scheme designed for
+ * 4-bit pixel values. Data is encoded in bytes, with
+ * each byte split into a 2-bit code word and a 6-bit
+ * data value. The encoding gives raw data, runs of
+ * pixels, or pixel values encoded as a delta from the
+ * previous pixel value. For the latter, either 2-bit
+ * or 3-bit delta values are used, with the deltas packed
+ * into a single byte.
+ */
+#define THUNDER_DATA 0x3f /* mask for 6-bit data */
+#define THUNDER_CODE 0xc0 /* mask for 2-bit code word */
+/* code values */
+#define THUNDER_RUN 0x00 /* run of pixels w/ encoded count */
+#define THUNDER_2BITDELTAS 0x40 /* 3 pixels w/ encoded 2-bit deltas */
+#define DELTA2_SKIP 2 /* skip code for 2-bit deltas */
+#define THUNDER_3BITDELTAS 0x80 /* 2 pixels w/ encoded 3-bit deltas */
+#define DELTA3_SKIP 4 /* skip code for 3-bit deltas */
+#define THUNDER_RAW 0xc0 /* raw data encoded */
+
+static const int twobitdeltas[4] = { 0, 1, 0, -1 };
+static const int threebitdeltas[8] = { 0, 1, 2, 3, 0, -3, -2, -1 };
+
+#define SETPIXEL(op, v) { \
+ lastpixel = (v) & 0xf; \
+ if (npixels++ & 1) \
+ *op++ |= lastpixel; \
+ else \
+ op[0] = (tidataval_t) (lastpixel << 4); \
+}
+
+static int
+ThunderDecode(TIFF* tif, tidata_t op, tsize_t maxpixels)
+{
+ register unsigned char *bp;
+ register tsize_t cc;
+ unsigned int lastpixel;
+ tsize_t npixels;
+
+ bp = (unsigned char *)tif->tif_rawcp;
+ cc = tif->tif_rawcc;
+ lastpixel = 0;
+ npixels = 0;
+ while (cc > 0 && npixels < maxpixels) {
+ int n, delta;
+
+ n = *bp++, cc--;
+ switch (n & THUNDER_CODE) {
+ case THUNDER_RUN: /* pixel run */
+ /*
+ * Replicate the last pixel n times,
+ * where n is the lower-order 6 bits.
+ */
+ if (npixels & 1) {
+ op[0] |= lastpixel;
+ lastpixel = *op++; npixels++; n--;
+ } else
+ lastpixel |= lastpixel << 4;
+ npixels += n;
+ if (npixels < maxpixels) {
+ for (; n > 0; n -= 2)
+ *op++ = (tidataval_t) lastpixel;
+ }
+ if (n == -1)
+ *--op &= 0xf0;
+ lastpixel &= 0xf;
+ break;
+ case THUNDER_2BITDELTAS: /* 2-bit deltas */
+ if ((delta = ((n >> 4) & 3)) != DELTA2_SKIP)
+ SETPIXEL(op, lastpixel + twobitdeltas[delta]);
+ if ((delta = ((n >> 2) & 3)) != DELTA2_SKIP)
+ SETPIXEL(op, lastpixel + twobitdeltas[delta]);
+ if ((delta = (n & 3)) != DELTA2_SKIP)
+ SETPIXEL(op, lastpixel + twobitdeltas[delta]);
+ break;
+ case THUNDER_3BITDELTAS: /* 3-bit deltas */
+ if ((delta = ((n >> 3) & 7)) != DELTA3_SKIP)
+ SETPIXEL(op, lastpixel + threebitdeltas[delta]);
+ if ((delta = (n & 7)) != DELTA3_SKIP)
+ SETPIXEL(op, lastpixel + threebitdeltas[delta]);
+ break;
+ case THUNDER_RAW: /* raw data */
+ SETPIXEL(op, n);
+ break;
+ }
+ }
+ tif->tif_rawcp = (tidata_t) bp;
+ tif->tif_rawcc = cc;
+ if (npixels != maxpixels) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "ThunderDecode: %s data at scanline %ld (%lu != %lu)",
+ npixels < maxpixels ? "Not enough" : "Too much",
+ (long) tif->tif_row, (long) npixels, (long) maxpixels);
+ return (0);
+ }
+ return (1);
+}
+
+static int
+ThunderDecodeRow(TIFF* tif, tidata_t buf, tsize_t occ, tsample_t s)
+{
+ tidata_t row = buf;
+
+ (void) s;
+ while ((long)occ > 0) {
+ if (!ThunderDecode(tif, row, tif->tif_dir.td_imagewidth))
+ return (0);
+ occ -= tif->tif_scanlinesize;
+ row += tif->tif_scanlinesize;
+ }
+ return (1);
+}
+
+int
+TIFFInitThunderScan(TIFF* tif, int scheme)
+{
+ (void) scheme;
+ tif->tif_decoderow = ThunderDecodeRow;
+ tif->tif_decodestrip = ThunderDecodeRow;
+ return (1);
+}
+#endif /* THUNDER_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_tile.c b/tiff/libtiff/tif_tile.c
new file mode 100644
index 0000000..d8379e6
--- /dev/null
+++ b/tiff/libtiff/tif_tile.c
@@ -0,0 +1,280 @@
+/* $Id: tif_tile.c,v 1.12.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Tiled Image Support Routines.
+ */
+#include "tiffiop.h"
+
+static uint32
+summarize(TIFF* tif, size_t summand1, size_t summand2, const char* where)
+{
+ /*
+ * XXX: We are using casting to uint32 here, because sizeof(size_t)
+ * may be larger than sizeof(uint32) on 64-bit architectures.
+ */
+ uint32 bytes = summand1 + summand2;
+
+ if (bytes - summand1 != summand2) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where);
+ bytes = 0;
+ }
+
+ return (bytes);
+}
+
+static uint32
+multiply(TIFF* tif, size_t nmemb, size_t elem_size, const char* where)
+{
+ uint32 bytes = nmemb * elem_size;
+
+ if (elem_size && bytes / elem_size != nmemb) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Integer overflow in %s", where);
+ bytes = 0;
+ }
+
+ return (bytes);
+}
+
+/*
+ * Compute which tile an (x,y,z,s) value is in.
+ */
+ttile_t
+TIFFComputeTile(TIFF* tif, uint32 x, uint32 y, uint32 z, tsample_t s)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ uint32 dx = td->td_tilewidth;
+ uint32 dy = td->td_tilelength;
+ uint32 dz = td->td_tiledepth;
+ ttile_t tile = 1;
+
+ if (td->td_imagedepth == 1)
+ z = 0;
+ if (dx == (uint32) -1)
+ dx = td->td_imagewidth;
+ if (dy == (uint32) -1)
+ dy = td->td_imagelength;
+ if (dz == (uint32) -1)
+ dz = td->td_imagedepth;
+ if (dx != 0 && dy != 0 && dz != 0) {
+ uint32 xpt = TIFFhowmany(td->td_imagewidth, dx);
+ uint32 ypt = TIFFhowmany(td->td_imagelength, dy);
+ uint32 zpt = TIFFhowmany(td->td_imagedepth, dz);
+
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+ tile = (xpt*ypt*zpt)*s +
+ (xpt*ypt)*(z/dz) +
+ xpt*(y/dy) +
+ x/dx;
+ else
+ tile = (xpt*ypt)*(z/dz) + xpt*(y/dy) + x/dx;
+ }
+ return (tile);
+}
+
+/*
+ * Check an (x,y,z,s) coordinate
+ * against the image bounds.
+ */
+int
+TIFFCheckTile(TIFF* tif, uint32 x, uint32 y, uint32 z, tsample_t s)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if (x >= td->td_imagewidth) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Col out of range, max %lu",
+ (unsigned long) x,
+ (unsigned long) (td->td_imagewidth - 1));
+ return (0);
+ }
+ if (y >= td->td_imagelength) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Row out of range, max %lu",
+ (unsigned long) y,
+ (unsigned long) (td->td_imagelength - 1));
+ return (0);
+ }
+ if (z >= td->td_imagedepth) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Depth out of range, max %lu",
+ (unsigned long) z,
+ (unsigned long) (td->td_imagedepth - 1));
+ return (0);
+ }
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE &&
+ s >= td->td_samplesperpixel) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%lu: Sample out of range, max %lu",
+ (unsigned long) s,
+ (unsigned long) (td->td_samplesperpixel - 1));
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Compute how many tiles are in an image.
+ */
+ttile_t
+TIFFNumberOfTiles(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ uint32 dx = td->td_tilewidth;
+ uint32 dy = td->td_tilelength;
+ uint32 dz = td->td_tiledepth;
+ ttile_t ntiles;
+
+ if (dx == (uint32) -1)
+ dx = td->td_imagewidth;
+ if (dy == (uint32) -1)
+ dy = td->td_imagelength;
+ if (dz == (uint32) -1)
+ dz = td->td_imagedepth;
+ ntiles = (dx == 0 || dy == 0 || dz == 0) ? 0 :
+ multiply(tif, multiply(tif, TIFFhowmany(td->td_imagewidth, dx),
+ TIFFhowmany(td->td_imagelength, dy),
+ "TIFFNumberOfTiles"),
+ TIFFhowmany(td->td_imagedepth, dz), "TIFFNumberOfTiles");
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+ ntiles = multiply(tif, ntiles, td->td_samplesperpixel,
+ "TIFFNumberOfTiles");
+ return (ntiles);
+}
+
+/*
+ * Compute the # bytes in each row of a tile.
+ */
+tsize_t
+TIFFTileRowSize(TIFF* tif)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tsize_t rowsize;
+
+ if (td->td_tilelength == 0 || td->td_tilewidth == 0)
+ return ((tsize_t) 0);
+ rowsize = multiply(tif, td->td_bitspersample, td->td_tilewidth,
+ "TIFFTileRowSize");
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG)
+ rowsize = multiply(tif, rowsize, td->td_samplesperpixel,
+ "TIFFTileRowSize");
+ return ((tsize_t) TIFFhowmany8(rowsize));
+}
+
+/*
+ * Compute the # bytes in a variable length, row-aligned tile.
+ */
+tsize_t
+TIFFVTileSize(TIFF* tif, uint32 nrows)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ tsize_t tilesize;
+
+ if (td->td_tilelength == 0 || td->td_tilewidth == 0 ||
+ td->td_tiledepth == 0)
+ return ((tsize_t) 0);
+ if (td->td_planarconfig == PLANARCONFIG_CONTIG &&
+ td->td_photometric == PHOTOMETRIC_YCBCR &&
+ !isUpSampled(tif)) {
+ /*
+ * Packed YCbCr data contain one Cb+Cr for every
+ * HorizontalSampling*VerticalSampling Y values.
+ * Must also roundup width and height when calculating
+ * since images that are not a multiple of the
+ * horizontal/vertical subsampling area include
+ * YCbCr data for the extended image.
+ */
+ tsize_t w =
+ TIFFroundup(td->td_tilewidth, td->td_ycbcrsubsampling[0]);
+ tsize_t rowsize =
+ TIFFhowmany8(multiply(tif, w, td->td_bitspersample,
+ "TIFFVTileSize"));
+ tsize_t samplingarea =
+ td->td_ycbcrsubsampling[0]*td->td_ycbcrsubsampling[1];
+ if (samplingarea == 0) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, "Invalid YCbCr subsampling");
+ return 0;
+ }
+ nrows = TIFFroundup(nrows, td->td_ycbcrsubsampling[1]);
+ /* NB: don't need TIFFhowmany here 'cuz everything is rounded */
+ tilesize = multiply(tif, nrows, rowsize, "TIFFVTileSize");
+ tilesize = summarize(tif, tilesize,
+ multiply(tif, 2, tilesize / samplingarea,
+ "TIFFVTileSize"),
+ "TIFFVTileSize");
+ } else
+ tilesize = multiply(tif, nrows, TIFFTileRowSize(tif),
+ "TIFFVTileSize");
+ return ((tsize_t)
+ multiply(tif, tilesize, td->td_tiledepth, "TIFFVTileSize"));
+}
+
+/*
+ * Compute the # bytes in a row-aligned tile.
+ */
+tsize_t
+TIFFTileSize(TIFF* tif)
+{
+ return (TIFFVTileSize(tif, tif->tif_dir.td_tilelength));
+}
+
+/*
+ * Compute a default tile size based on the image
+ * characteristics and a requested value. If a
+ * request is <1 then we choose a size according
+ * to certain heuristics.
+ */
+void
+TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
+{
+ (*tif->tif_deftilesize)(tif, tw, th);
+}
+
+void
+_TIFFDefaultTileSize(TIFF* tif, uint32* tw, uint32* th)
+{
+ (void) tif;
+ if (*(int32*) tw < 1)
+ *tw = 256;
+ if (*(int32*) th < 1)
+ *th = 256;
+ /* roundup to a multiple of 16 per the spec */
+ if (*tw & 0xf)
+ *tw = TIFFroundup(*tw, 16);
+ if (*th & 0xf)
+ *th = TIFFroundup(*th, 16);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_unix.c b/tiff/libtiff/tif_unix.c
new file mode 100644
index 0000000..b73e80d
--- /dev/null
+++ b/tiff/libtiff/tif_unix.c
@@ -0,0 +1,300 @@
+/* $Id: tif_unix.c,v 1.12.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library UNIX-specific Routines. These are should also work with the
+ * Windows Common RunTime Library.
+ */
+#include "tif_config.h"
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffiop.h"
+
+static tsize_t
+_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return ((tsize_t) read((int) fd, buf, (size_t) size));
+}
+
+static tsize_t
+_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return ((tsize_t) write((int) fd, buf, (size_t) size));
+}
+
+static toff_t
+_tiffSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ return ((toff_t) lseek((int) fd, (off_t) off, whence));
+}
+
+static int
+_tiffCloseProc(thandle_t fd)
+{
+ return (close((int) fd));
+}
+
+
+static toff_t
+_tiffSizeProc(thandle_t fd)
+{
+#ifdef _AM29K
+ long fsize;
+ return ((fsize = lseek((int) fd, 0, SEEK_END)) < 0 ? 0 : fsize);
+#else
+ struct stat sb;
+ return (toff_t) (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size);
+#endif
+}
+
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+
+static int
+_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ toff_t size = _tiffSizeProc(fd);
+ if (size != (toff_t) -1) {
+ *pbase = (tdata_t)
+ mmap(0, size, PROT_READ, MAP_SHARED, (int) fd, 0);
+ if (*pbase != (tdata_t) -1) {
+ *psize = size;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void
+_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+ (void) fd;
+ (void) munmap(base, (off_t) size);
+}
+#else /* !HAVE_MMAP */
+static int
+_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ (void) fd; (void) pbase; (void) psize;
+ return (0);
+}
+
+static void
+_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+ (void) fd; (void) base; (void) size;
+}
+#endif /* !HAVE_MMAP */
+
+/*
+ * Open a TIFF file descriptor for read/writing.
+ */
+TIFF*
+TIFFFdOpen(int fd, const char* name, const char* mode)
+{
+ TIFF* tif;
+
+ tif = TIFFClientOpen(name, mode,
+ (thandle_t) fd,
+ _tiffReadProc, _tiffWriteProc,
+ _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
+ _tiffMapProc, _tiffUnmapProc);
+ if (tif)
+ tif->tif_fd = fd;
+ return (tif);
+}
+
+/*
+ * Open a TIFF file for read/writing.
+ */
+TIFF*
+TIFFOpen(const char* name, const char* mode)
+{
+ static const char module[] = "TIFFOpen";
+ int m, fd;
+ TIFF* tif;
+
+ m = _TIFFgetMode(mode, module);
+ if (m == -1)
+ return ((TIFF*)0);
+
+/* for cygwin and mingw */
+#ifdef O_BINARY
+ m |= O_BINARY;
+#endif
+
+#ifdef _AM29K
+ fd = open(name, m);
+#else
+ fd = open(name, m, 0666);
+#endif
+ if (fd < 0) {
+ TIFFErrorExt(0, module, "%s: Cannot open", name);
+ return ((TIFF *)0);
+ }
+
+ tif = TIFFFdOpen((int)fd, name, mode);
+ if(!tif)
+ close(fd);
+ return tif;
+}
+
+#ifdef __WIN32__
+#include <windows.h>
+/*
+ * Open a TIFF file with a Unicode filename, for read/writing.
+ */
+TIFF*
+TIFFOpenW(const wchar_t* name, const char* mode)
+{
+ static const char module[] = "TIFFOpenW";
+ int m, fd;
+ int mbsize;
+ char *mbname;
+ TIFF* tif;
+
+ m = _TIFFgetMode(mode, module);
+ if (m == -1)
+ return ((TIFF*)0);
+
+/* for cygwin and mingw */
+#ifdef O_BINARY
+ m |= O_BINARY;
+#endif
+
+ fd = _wopen(name, m, 0666);
+ if (fd < 0) {
+ TIFFErrorExt(0, module, "%s: Cannot open", name);
+ return ((TIFF *)0);
+ }
+
+ mbname = NULL;
+ mbsize = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL);
+ if (mbsize > 0) {
+ mbname = _TIFFmalloc(mbsize);
+ if (!mbname) {
+ TIFFErrorExt(0, module,
+ "Can't allocate space for filename conversion buffer");
+ return ((TIFF*)0);
+ }
+
+ WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize,
+ NULL, NULL);
+ }
+
+ tif = TIFFFdOpen((int)fd, (mbname != NULL) ? mbname : "<unknown>",
+ mode);
+
+ _TIFFfree(mbname);
+
+ if(!tif)
+ close(fd);
+ return tif;
+}
+#endif
+
+void*
+_TIFFmalloc(tsize_t s)
+{
+ return (malloc((size_t) s));
+}
+
+void
+_TIFFfree(tdata_t p)
+{
+ free(p);
+}
+
+void*
+_TIFFrealloc(tdata_t p, tsize_t s)
+{
+ return (realloc(p, (size_t) s));
+}
+
+void
+_TIFFmemset(tdata_t p, int v, tsize_t c)
+{
+ memset(p, v, (size_t) c);
+}
+
+void
+_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
+{
+ memcpy(d, s, (size_t) c);
+}
+
+int
+_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)
+{
+ return (memcmp(p1, p2, (size_t) c));
+}
+
+static void
+unixWarningHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ fprintf(stderr, "Warning, ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFwarningHandler = unixWarningHandler;
+
+static void
+unixErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+}
+TIFFErrorHandler _TIFFerrorHandler = unixErrorHandler;
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_version.c b/tiff/libtiff/tif_version.c
new file mode 100644
index 0000000..218dab5
--- /dev/null
+++ b/tiff/libtiff/tif_version.c
@@ -0,0 +1,40 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_version.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+/*
+ * Copyright (c) 1992-1997 Sam Leffler
+ * Copyright (c) 1992-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#include "tiffiop.h"
+
+static const char TIFFVersion[] = TIFFLIB_VERSION_STR;
+
+const char*
+TIFFGetVersion(void)
+{
+ return (TIFFVersion);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_warning.c b/tiff/libtiff/tif_warning.c
new file mode 100644
index 0000000..fe974d9
--- /dev/null
+++ b/tiff/libtiff/tif_warning.c
@@ -0,0 +1,81 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_warning.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ */
+#include "tiffiop.h"
+
+TIFFErrorHandlerExt _TIFFwarningHandlerExt = NULL;
+
+TIFFErrorHandler
+TIFFSetWarningHandler(TIFFErrorHandler handler)
+{
+ TIFFErrorHandler prev = _TIFFwarningHandler;
+ _TIFFwarningHandler = handler;
+ return (prev);
+}
+
+TIFFErrorHandlerExt
+TIFFSetWarningHandlerExt(TIFFErrorHandlerExt handler)
+{
+ TIFFErrorHandlerExt prev = _TIFFwarningHandlerExt;
+ _TIFFwarningHandlerExt = handler;
+ return (prev);
+}
+
+void
+TIFFWarning(const char* module, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ if (_TIFFwarningHandler)
+ (*_TIFFwarningHandler)(module, fmt, ap);
+ if (_TIFFwarningHandlerExt)
+ (*_TIFFwarningHandlerExt)(0, module, fmt, ap);
+ va_end(ap);
+}
+
+void
+TIFFWarningExt(thandle_t fd, const char* module, const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ if (_TIFFwarningHandler)
+ (*_TIFFwarningHandler)(module, fmt, ap);
+ if (_TIFFwarningHandlerExt)
+ (*_TIFFwarningHandlerExt)(fd, module, fmt, ap);
+ va_end(ap);
+}
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_win3.c b/tiff/libtiff/tif_win3.c
new file mode 100644
index 0000000..5ac7513
--- /dev/null
+++ b/tiff/libtiff/tif_win3.c
@@ -0,0 +1,232 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/Attic/tif_win3.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library Windows 3.x-specific Routines.
+ */
+#include "tiffiop.h"
+#if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(_MSC_VER)
+#include <io.h> /* for open, close, etc. function prototypes */
+#endif
+
+#include <windows.h>
+#include <windowsx.h>
+#include <memory.h>
+
+static tsize_t
+_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return (_hread(fd, buf, size));
+}
+
+static tsize_t
+_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ return (_hwrite(fd, buf, size));
+}
+
+static toff_t
+_tiffSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ return (_llseek(fd, (off_t) off, whence));
+}
+
+static int
+_tiffCloseProc(thandle_t fd)
+{
+ return (_lclose(fd));
+}
+
+#include <sys/stat.h>
+
+static toff_t
+_tiffSizeProc(thandle_t fd)
+{
+ struct stat sb;
+ return (fstat((int) fd, &sb) < 0 ? 0 : sb.st_size);
+}
+
+static int
+_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ return (0);
+}
+
+static void
+_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+}
+
+/*
+ * Open a TIFF file descriptor for read/writing.
+ */
+TIFF*
+TIFFFdOpen(int fd, const char* name, const char* mode)
+{
+ TIFF* tif;
+
+ tif = TIFFClientOpen(name, mode,
+ (thandle_t) fd,
+ _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
+ _tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
+ if (tif)
+ tif->tif_fd = fd;
+ return (tif);
+}
+
+/*
+ * Open a TIFF file for read/writing.
+ */
+TIFF*
+TIFFOpen(const char* name, const char* mode)
+{
+ static const char module[] = "TIFFOpen";
+ int m, fd;
+ OFSTRUCT of;
+ int mm = 0;
+
+ m = _TIFFgetMode(mode, module);
+ if (m == -1)
+ return ((TIFF*)0);
+ if (m & O_CREAT) {
+ if ((m & O_TRUNC) || OpenFile(name, &of, OF_EXIST) != HFILE_ERROR)
+ mm |= OF_CREATE;
+ }
+ if (m & O_WRONLY)
+ mm |= OF_WRITE;
+ if (m & O_RDWR)
+ mm |= OF_READWRITE;
+ fd = OpenFile(name, &of, mm);
+ if (fd < 0) {
+ TIFFErrorExt(0, module, "%s: Cannot open", name);
+ return ((TIFF*)0);
+ }
+ return (TIFFFdOpen(fd, name, mode));
+}
+
+tdata_t
+_TIFFmalloc(tsize_t s)
+{
+ return (tdata_t) GlobalAllocPtr(GHND, (DWORD) s);
+}
+
+void
+_TIFFfree(tdata_t p)
+{
+ GlobalFreePtr(p);
+}
+
+tdata_t
+_TIFFrealloc(tdata_t p, tsize_t s)
+{
+ return (tdata_t) GlobalReAllocPtr(p, (DWORD) s, GHND);
+}
+
+void
+_TIFFmemset(tdata_t p, int v, tsize_t c)
+{
+ char* pp = (char*) p;
+
+ while (c > 0) {
+ tsize_t chunk = 0x10000 - ((uint32) pp & 0xffff);/* What's left in segment */
+ if (chunk > 0xff00) /* No more than 0xff00 */
+ chunk = 0xff00;
+ if (chunk > c) /* No more than needed */
+ chunk = c;
+ memset(pp, v, chunk);
+ pp = (char*) (chunk + (char huge*) pp);
+ c -= chunk;
+ }
+}
+
+void
+_TIFFmemcpy(tdata_t d, const tdata_t s, tsize_t c)
+{
+ if (c > 0xFFFF)
+ hmemcpy((void _huge*) d, (void _huge*) s, c);
+ else
+ (void) memcpy(d, s, (size_t) c);
+}
+
+int
+_TIFFmemcmp(const tdata_t d, const tdata_t s, tsize_t c)
+{
+ char* dd = (char*) d;
+ char* ss = (char*) s;
+ tsize_t chunks, chunkd, chunk;
+ int result;
+
+ while (c > 0) {
+ chunks = 0x10000 - ((uint32) ss & 0xffff); /* What's left in segment */
+ chunkd = 0x10000 - ((uint32) dd & 0xffff); /* What's left in segment */
+ chunk = c; /* Get the largest of */
+ if (chunk > chunks) /* c, chunks, chunkd, */
+ chunk = chunks; /* 0xff00 */
+ if (chunk > chunkd)
+ chunk = chunkd;
+ if (chunk > 0xff00)
+ chunk = 0xff00;
+ result = memcmp(dd, ss, chunk);
+ if (result != 0)
+ return (result);
+ dd = (char*) (chunk + (char huge*) dd);
+ ss = (char*) (chunk + (char huge*) ss);
+ c -= chunk;
+ }
+ return (0);
+}
+
+static void
+win3WarningHandler(const char* module, const char* fmt, va_list ap)
+{
+ char e[512] = { '\0' };
+ if (module != NULL)
+ strcat(strcpy(e, module), ":");
+ vsprintf(e+strlen(e), fmt, ap);
+ strcat(e, ".");
+ MessageBox(GetActiveWindow(), e, "LibTIFF Warning",
+ MB_OK|MB_ICONEXCLAMATION);
+}
+TIFFErrorHandler _TIFFwarningHandler = win3WarningHandler;
+
+static void
+win3ErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+ char e[512] = { '\0' };
+ if (module != NULL)
+ strcat(strcpy(e, module), ":");
+ vsprintf(e+strlen(e), fmt, ap);
+ strcat(e, ".");
+ MessageBox(GetActiveWindow(), e, "LibTIFF Error", MB_OK|MB_ICONSTOP);
+}
+TIFFErrorHandler _TIFFerrorHandler = win3ErrorHandler;
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_win32.c b/tiff/libtiff/tif_win32.c
new file mode 100644
index 0000000..2ab944b
--- /dev/null
+++ b/tiff/libtiff/tif_win32.c
@@ -0,0 +1,408 @@
+/* $Id: tif_win32.c,v 1.21.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library Win32-specific Routines. Adapted from tif_unix.c 4/5/95 by
+ * Scott Wagner (wagner@itek.com), Itek Graphix, Rochester, NY USA
+ */
+#include "tiffiop.h"
+
+#include <windows.h>
+
+static tsize_t
+_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ DWORD dwSizeRead;
+ if (!ReadFile(fd, buf, size, &dwSizeRead, NULL))
+ return(0);
+ return ((tsize_t) dwSizeRead);
+}
+
+static tsize_t
+_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+{
+ DWORD dwSizeWritten;
+ if (!WriteFile(fd, buf, size, &dwSizeWritten, NULL))
+ return(0);
+ return ((tsize_t) dwSizeWritten);
+}
+
+static toff_t
+_tiffSeekProc(thandle_t fd, toff_t off, int whence)
+{
+ ULARGE_INTEGER li;
+ DWORD dwMoveMethod;
+
+ li.QuadPart = off;
+
+ switch(whence)
+ {
+ case SEEK_SET:
+ dwMoveMethod = FILE_BEGIN;
+ break;
+ case SEEK_CUR:
+ dwMoveMethod = FILE_CURRENT;
+ break;
+ case SEEK_END:
+ dwMoveMethod = FILE_END;
+ break;
+ default:
+ dwMoveMethod = FILE_BEGIN;
+ break;
+ }
+ return ((toff_t)SetFilePointer(fd, (LONG) li.LowPart,
+ (PLONG)&li.HighPart, dwMoveMethod));
+}
+
+static int
+_tiffCloseProc(thandle_t fd)
+{
+ return (CloseHandle(fd) ? 0 : -1);
+}
+
+static toff_t
+_tiffSizeProc(thandle_t fd)
+{
+ return ((toff_t)GetFileSize(fd, NULL));
+}
+
+static int
+_tiffDummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ (void) fd;
+ (void) pbase;
+ (void) psize;
+ return (0);
+}
+
+/*
+ * From "Hermann Josef Hill" <lhill@rhein-zeitung.de>:
+ *
+ * Windows uses both a handle and a pointer for file mapping,
+ * but according to the SDK documentation and Richter's book
+ * "Advanced Windows Programming" it is safe to free the handle
+ * after obtaining the file mapping pointer
+ *
+ * This removes a nasty OS dependency and cures a problem
+ * with Visual C++ 5.0
+ */
+static int
+_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ toff_t size;
+ HANDLE hMapFile;
+
+ if ((size = _tiffSizeProc(fd)) == 0xFFFFFFFF)
+ return (0);
+ hMapFile = CreateFileMapping(fd, NULL, PAGE_READONLY, 0, size, NULL);
+ if (hMapFile == NULL)
+ return (0);
+ *pbase = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
+ CloseHandle(hMapFile);
+ if (*pbase == NULL)
+ return (0);
+ *psize = size;
+ return(1);
+}
+
+static void
+_tiffDummyUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+ (void) fd;
+ (void) base;
+ (void) size;
+}
+
+static void
+_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+ UnmapViewOfFile(base);
+}
+
+/*
+ * Open a TIFF file descriptor for read/writing.
+ * Note that TIFFFdOpen and TIFFOpen recognise the character 'u' in the mode
+ * string, which forces the file to be opened unmapped.
+ */
+TIFF*
+TIFFFdOpen(int ifd, const char* name, const char* mode)
+{
+ TIFF* tif;
+ BOOL fSuppressMap = (mode[1] == 'u' || (mode[1]!=0 && mode[2] == 'u'));
+
+ tif = TIFFClientOpen(name, mode, (thandle_t)ifd,
+ _tiffReadProc, _tiffWriteProc,
+ _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
+ fSuppressMap ? _tiffDummyMapProc : _tiffMapProc,
+ fSuppressMap ? _tiffDummyUnmapProc : _tiffUnmapProc);
+ if (tif)
+ tif->tif_fd = ifd;
+ return (tif);
+}
+
+#ifndef _WIN32_WCE
+
+/*
+ * Open a TIFF file for read/writing.
+ */
+TIFF*
+TIFFOpen(const char* name, const char* mode)
+{
+ static const char module[] = "TIFFOpen";
+ thandle_t fd;
+ int m;
+ DWORD dwMode;
+ TIFF* tif;
+
+ m = _TIFFgetMode(mode, module);
+
+ switch(m)
+ {
+ case O_RDONLY:
+ dwMode = OPEN_EXISTING;
+ break;
+ case O_RDWR:
+ dwMode = OPEN_ALWAYS;
+ break;
+ case O_RDWR|O_CREAT:
+ dwMode = OPEN_ALWAYS;
+ break;
+ case O_RDWR|O_TRUNC:
+ dwMode = CREATE_ALWAYS;
+ break;
+ case O_RDWR|O_CREAT|O_TRUNC:
+ dwMode = CREATE_ALWAYS;
+ break;
+ default:
+ return ((TIFF*)0);
+ }
+ fd = (thandle_t)CreateFileA(name,
+ (m == O_RDONLY)?GENERIC_READ:(GENERIC_READ | GENERIC_WRITE),
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwMode,
+ (m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (fd == INVALID_HANDLE_VALUE) {
+ TIFFErrorExt(0, module, "%s: Cannot open", name);
+ return ((TIFF *)0);
+ }
+
+ tif = TIFFFdOpen((int)fd, name, mode);
+ if(!tif)
+ CloseHandle(fd);
+ return tif;
+}
+
+/*
+ * Open a TIFF file with a Unicode filename, for read/writing.
+ */
+TIFF*
+TIFFOpenW(const wchar_t* name, const char* mode)
+{
+ static const char module[] = "TIFFOpenW";
+ thandle_t fd;
+ int m;
+ DWORD dwMode;
+ int mbsize;
+ char *mbname;
+ TIFF *tif;
+
+ m = _TIFFgetMode(mode, module);
+
+ switch(m) {
+ case O_RDONLY: dwMode = OPEN_EXISTING; break;
+ case O_RDWR: dwMode = OPEN_ALWAYS; break;
+ case O_RDWR|O_CREAT: dwMode = OPEN_ALWAYS; break;
+ case O_RDWR|O_TRUNC: dwMode = CREATE_ALWAYS; break;
+ case O_RDWR|O_CREAT|O_TRUNC: dwMode = CREATE_ALWAYS; break;
+ default: return ((TIFF*)0);
+ }
+
+ fd = (thandle_t)CreateFileW(name,
+ (m == O_RDONLY)?GENERIC_READ:(GENERIC_READ|GENERIC_WRITE),
+ FILE_SHARE_READ, NULL, dwMode,
+ (m == O_RDONLY)?FILE_ATTRIBUTE_READONLY:FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (fd == INVALID_HANDLE_VALUE) {
+ TIFFErrorExt(0, module, "%S: Cannot open", name);
+ return ((TIFF *)0);
+ }
+
+ mbname = NULL;
+ mbsize = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL);
+ if (mbsize > 0) {
+ mbname = (char *)_TIFFmalloc(mbsize);
+ if (!mbname) {
+ TIFFErrorExt(0, module,
+ "Can't allocate space for filename conversion buffer");
+ return ((TIFF*)0);
+ }
+
+ WideCharToMultiByte(CP_ACP, 0, name, -1, mbname, mbsize,
+ NULL, NULL);
+ }
+
+ tif = TIFFFdOpen((int)fd,
+ (mbname != NULL) ? mbname : "<unknown>", mode);
+ if(!tif)
+ CloseHandle(fd);
+
+ _TIFFfree(mbname);
+
+ return tif;
+}
+
+#endif /* ndef _WIN32_WCE */
+
+
+tdata_t
+_TIFFmalloc(tsize_t s)
+{
+ return ((tdata_t)GlobalAlloc(GMEM_FIXED, s));
+}
+
+void
+_TIFFfree(tdata_t p)
+{
+ GlobalFree(p);
+ return;
+}
+
+tdata_t
+_TIFFrealloc(tdata_t p, tsize_t s)
+{
+ void* pvTmp;
+ tsize_t old;
+
+ if(p == NULL)
+ return ((tdata_t)GlobalAlloc(GMEM_FIXED, s));
+
+ old = GlobalSize(p);
+
+ if (old>=s) {
+ if ((pvTmp = GlobalAlloc(GMEM_FIXED, s)) != NULL) {
+ CopyMemory(pvTmp, p, s);
+ GlobalFree(p);
+ }
+ } else {
+ if ((pvTmp = GlobalAlloc(GMEM_FIXED, s)) != NULL) {
+ CopyMemory(pvTmp, p, old);
+ GlobalFree(p);
+ }
+ }
+ return ((tdata_t)pvTmp);
+}
+
+void
+_TIFFmemset(void* p, int v, tsize_t c)
+{
+ FillMemory(p, c, (BYTE)v);
+}
+
+void
+_TIFFmemcpy(void* d, const tdata_t s, tsize_t c)
+{
+ CopyMemory(d, s, c);
+}
+
+int
+_TIFFmemcmp(const tdata_t p1, const tdata_t p2, tsize_t c)
+{
+ register const BYTE *pb1 = (const BYTE *) p1;
+ register const BYTE *pb2 = (const BYTE *) p2;
+ register DWORD dwTmp = c;
+ register int iTmp;
+ for (iTmp = 0; dwTmp-- && !iTmp; iTmp = (int)*pb1++ - (int)*pb2++)
+ ;
+ return (iTmp);
+}
+
+#ifndef _WIN32_WCE
+
+static void
+Win32WarningHandler(const char* module, const char* fmt, va_list ap)
+{
+#ifndef TIF_PLATFORM_CONSOLE
+ LPTSTR szTitle;
+ LPTSTR szTmp;
+ LPCTSTR szTitleText = "%s Warning";
+ LPCTSTR szDefaultModule = "LIBTIFF";
+ LPCTSTR szTmpModule = (module == NULL) ? szDefaultModule : module;
+ if ((szTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmpModule) +
+ strlen(szTitleText) + strlen(fmt) + 128)*sizeof(char))) == NULL)
+ return;
+ sprintf(szTitle, szTitleText, szTmpModule);
+ szTmp = szTitle + (strlen(szTitle)+2)*sizeof(char);
+ vsprintf(szTmp, fmt, ap);
+ MessageBoxA(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONINFORMATION);
+ LocalFree(szTitle);
+ return;
+#else
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ fprintf(stderr, "Warning, ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+#endif
+}
+TIFFErrorHandler _TIFFwarningHandler = Win32WarningHandler;
+
+static void
+Win32ErrorHandler(const char* module, const char* fmt, va_list ap)
+{
+#ifndef TIF_PLATFORM_CONSOLE
+ LPTSTR szTitle;
+ LPTSTR szTmp;
+ LPCTSTR szTitleText = "%s Error";
+ LPCTSTR szDefaultModule = "LIBTIFF";
+ LPCTSTR szTmpModule = (module == NULL) ? szDefaultModule : module;
+ if ((szTitle = (LPTSTR)LocalAlloc(LMEM_FIXED, (strlen(szTmpModule) +
+ strlen(szTitleText) + strlen(fmt) + 128)*sizeof(char))) == NULL)
+ return;
+ sprintf(szTitle, szTitleText, szTmpModule);
+ szTmp = szTitle + (strlen(szTitle)+2)*sizeof(char);
+ vsprintf(szTmp, fmt, ap);
+ MessageBoxA(GetFocus(), szTmp, szTitle, MB_OK | MB_ICONEXCLAMATION);
+ LocalFree(szTitle);
+ return;
+#else
+ if (module != NULL)
+ fprintf(stderr, "%s: ", module);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ".\n");
+#endif
+}
+TIFFErrorHandler _TIFFerrorHandler = Win32ErrorHandler;
+
+#endif /* ndef _WIN32_WCE */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_write.c b/tiff/libtiff/tif_write.c
new file mode 100644
index 0000000..bd08418
--- /dev/null
+++ b/tiff/libtiff/tif_write.c
@@ -0,0 +1,718 @@
+/* $Id: tif_write.c,v 1.22.2.5 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library.
+ *
+ * Scanline-oriented Write Support
+ */
+#include "tiffiop.h"
+#include <stdio.h>
+
+#define STRIPINCR 20 /* expansion factor on strip array */
+
+#define WRITECHECKSTRIPS(tif, module) \
+ (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),0,module))
+#define WRITECHECKTILES(tif, module) \
+ (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),1,module))
+#define BUFFERCHECK(tif) \
+ ((((tif)->tif_flags & TIFF_BUFFERSETUP) && tif->tif_rawdata) || \
+ TIFFWriteBufferSetup((tif), NULL, (tsize_t) -1))
+
+static int TIFFGrowStrips(TIFF*, int, const char*);
+static int TIFFAppendToStrip(TIFF*, tstrip_t, tidata_t, tsize_t);
+
+int
+TIFFWriteScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample)
+{
+ static const char module[] = "TIFFWriteScanline";
+ register TIFFDirectory *td;
+ int status, imagegrew = 0;
+ tstrip_t strip;
+
+ if (!WRITECHECKSTRIPS(tif, module))
+ return (-1);
+ /*
+ * Handle delayed allocation of data buffer. This
+ * permits it to be sized more intelligently (using
+ * directory information).
+ */
+ if (!BUFFERCHECK(tif))
+ return (-1);
+ td = &tif->tif_dir;
+ /*
+ * Extend image length if needed
+ * (but only for PlanarConfig=1).
+ */
+ if (row >= td->td_imagelength) { /* extend image */
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Can not change \"ImageLength\" when using separate planes");
+ return (-1);
+ }
+ td->td_imagelength = row+1;
+ imagegrew = 1;
+ }
+ /*
+ * Calculate strip and check for crossings.
+ */
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+ if (sample >= td->td_samplesperpixel) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "%d: Sample out of range, max %d",
+ sample, td->td_samplesperpixel);
+ return (-1);
+ }
+ strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip;
+ } else
+ strip = row / td->td_rowsperstrip;
+ /*
+ * Check strip array to make sure there's space. We don't support
+ * dynamically growing files that have data organized in separate
+ * bitplanes because it's too painful. In that case we require that
+ * the imagelength be set properly before the first write (so that the
+ * strips array will be fully allocated above).
+ */
+ if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module))
+ return (-1);
+ if (strip != tif->tif_curstrip) {
+ /*
+ * Changing strips -- flush any data present.
+ */
+ if (!TIFFFlushData(tif))
+ return (-1);
+ tif->tif_curstrip = strip;
+ /*
+ * Watch out for a growing image. The value of strips/image
+ * will initially be 1 (since it can't be deduced until the
+ * imagelength is known).
+ */
+ if (strip >= td->td_stripsperimage && imagegrew)
+ td->td_stripsperimage =
+ TIFFhowmany(td->td_imagelength,td->td_rowsperstrip);
+ tif->tif_row =
+ (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+ if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+ if (!(*tif->tif_setupencode)(tif))
+ return (-1);
+ tif->tif_flags |= TIFF_CODERSETUP;
+ }
+
+ tif->tif_rawcc = 0;
+ tif->tif_rawcp = tif->tif_rawdata;
+
+ if( td->td_stripbytecount[strip] > 0 )
+ {
+ /* if we are writing over existing tiles, zero length */
+ td->td_stripbytecount[strip] = 0;
+
+ /* this forces TIFFAppendToStrip() to do a seek */
+ tif->tif_curoff = 0;
+ }
+
+ if (!(*tif->tif_preencode)(tif, sample))
+ return (-1);
+ tif->tif_flags |= TIFF_POSTENCODE;
+ }
+ /*
+ * Ensure the write is either sequential or at the
+ * beginning of a strip (or that we can randomly
+ * access the data -- i.e. no encoding).
+ */
+ if (row != tif->tif_row) {
+ if (row < tif->tif_row) {
+ /*
+ * Moving backwards within the same strip:
+ * backup to the start and then decode
+ * forward (below).
+ */
+ tif->tif_row = (strip % td->td_stripsperimage) *
+ td->td_rowsperstrip;
+ tif->tif_rawcp = tif->tif_rawdata;
+ }
+ /*
+ * Seek forward to the desired row.
+ */
+ if (!(*tif->tif_seek)(tif, row - tif->tif_row))
+ return (-1);
+ tif->tif_row = row;
+ }
+
+ /* swab if needed - note that source buffer will be altered */
+ tif->tif_postdecode( tif, (tidata_t) buf, tif->tif_scanlinesize );
+
+ status = (*tif->tif_encoderow)(tif, (tidata_t) buf,
+ tif->tif_scanlinesize, sample);
+
+ /* we are now poised at the beginning of the next row */
+ tif->tif_row = row + 1;
+ return (status);
+}
+
+/*
+ * Encode the supplied data and write it to the
+ * specified strip.
+ *
+ * NB: Image length must be setup before writing.
+ */
+tsize_t
+TIFFWriteEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc)
+{
+ static const char module[] = "TIFFWriteEncodedStrip";
+ TIFFDirectory *td = &tif->tif_dir;
+ tsample_t sample;
+
+ if (!WRITECHECKSTRIPS(tif, module))
+ return ((tsize_t) -1);
+ /*
+ * Check strip array to make sure there's space.
+ * We don't support dynamically growing files that
+ * have data organized in separate bitplanes because
+ * it's too painful. In that case we require that
+ * the imagelength be set properly before the first
+ * write (so that the strips array will be fully
+ * allocated above).
+ */
+ if (strip >= td->td_nstrips) {
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Can not grow image by strips when using separate planes");
+ return ((tsize_t) -1);
+ }
+ if (!TIFFGrowStrips(tif, 1, module))
+ return ((tsize_t) -1);
+ td->td_stripsperimage =
+ TIFFhowmany(td->td_imagelength, td->td_rowsperstrip);
+ }
+ /*
+ * Handle delayed allocation of data buffer. This
+ * permits it to be sized according to the directory
+ * info.
+ */
+ if (!BUFFERCHECK(tif))
+ return ((tsize_t) -1);
+ tif->tif_curstrip = strip;
+ tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+ if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+ if (!(*tif->tif_setupencode)(tif))
+ return ((tsize_t) -1);
+ tif->tif_flags |= TIFF_CODERSETUP;
+ }
+
+ tif->tif_rawcc = 0;
+ tif->tif_rawcp = tif->tif_rawdata;
+
+ if( td->td_stripbytecount[strip] > 0 )
+ {
+ /* Force TIFFAppendToStrip() to consider placing data at end
+ of file. */
+ tif->tif_curoff = 0;
+ }
+
+ tif->tif_flags &= ~TIFF_POSTENCODE;
+ sample = (tsample_t)(strip / td->td_stripsperimage);
+ if (!(*tif->tif_preencode)(tif, sample))
+ return ((tsize_t) -1);
+
+ /* swab if needed - note that source buffer will be altered */
+ tif->tif_postdecode( tif, (tidata_t) data, cc );
+
+ if (!(*tif->tif_encodestrip)(tif, (tidata_t) data, cc, sample))
+ return ((tsize_t) 0);
+ if (!(*tif->tif_postencode)(tif))
+ return ((tsize_t) -1);
+ if (!isFillOrder(tif, td->td_fillorder) &&
+ (tif->tif_flags & TIFF_NOBITREV) == 0)
+ TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc);
+ if (tif->tif_rawcc > 0 &&
+ !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc))
+ return ((tsize_t) -1);
+ tif->tif_rawcc = 0;
+ tif->tif_rawcp = tif->tif_rawdata;
+ return (cc);
+}
+
+/*
+ * Write the supplied data to the specified strip.
+ *
+ * NB: Image length must be setup before writing.
+ */
+tsize_t
+TIFFWriteRawStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc)
+{
+ static const char module[] = "TIFFWriteRawStrip";
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if (!WRITECHECKSTRIPS(tif, module))
+ return ((tsize_t) -1);
+ /*
+ * Check strip array to make sure there's space.
+ * We don't support dynamically growing files that
+ * have data organized in separate bitplanes because
+ * it's too painful. In that case we require that
+ * the imagelength be set properly before the first
+ * write (so that the strips array will be fully
+ * allocated above).
+ */
+ if (strip >= td->td_nstrips) {
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name,
+ "Can not grow image by strips when using separate planes");
+ return ((tsize_t) -1);
+ }
+ /*
+ * Watch out for a growing image. The value of
+ * strips/image will initially be 1 (since it
+ * can't be deduced until the imagelength is known).
+ */
+ if (strip >= td->td_stripsperimage)
+ td->td_stripsperimage =
+ TIFFhowmany(td->td_imagelength,td->td_rowsperstrip);
+ if (!TIFFGrowStrips(tif, 1, module))
+ return ((tsize_t) -1);
+ }
+ tif->tif_curstrip = strip;
+ tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
+ return (TIFFAppendToStrip(tif, strip, (tidata_t) data, cc) ?
+ cc : (tsize_t) -1);
+}
+
+/*
+ * Write and compress a tile of data. The
+ * tile is selected by the (x,y,z,s) coordinates.
+ */
+tsize_t
+TIFFWriteTile(TIFF* tif,
+ tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s)
+{
+ if (!TIFFCheckTile(tif, x, y, z, s))
+ return (-1);
+ /*
+ * NB: A tile size of -1 is used instead of tif_tilesize knowing
+ * that TIFFWriteEncodedTile will clamp this to the tile size.
+ * This is done because the tile size may not be defined until
+ * after the output buffer is setup in TIFFWriteBufferSetup.
+ */
+ return (TIFFWriteEncodedTile(tif,
+ TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1));
+}
+
+/*
+ * Encode the supplied data and write it to the
+ * specified tile. There must be space for the
+ * data. The function clamps individual writes
+ * to a tile to the tile size, but does not (and
+ * can not) check that multiple writes to the same
+ * tile do not write more than tile size data.
+ *
+ * NB: Image length must be setup before writing; this
+ * interface does not support automatically growing
+ * the image on each write (as TIFFWriteScanline does).
+ */
+tsize_t
+TIFFWriteEncodedTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc)
+{
+ static const char module[] = "TIFFWriteEncodedTile";
+ TIFFDirectory *td;
+ tsample_t sample;
+
+ if (!WRITECHECKTILES(tif, module))
+ return ((tsize_t) -1);
+ td = &tif->tif_dir;
+ if (tile >= td->td_nstrips) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Tile %lu out of range, max %lu",
+ tif->tif_name, (unsigned long) tile, (unsigned long) td->td_nstrips);
+ return ((tsize_t) -1);
+ }
+ /*
+ * Handle delayed allocation of data buffer. This
+ * permits it to be sized more intelligently (using
+ * directory information).
+ */
+ if (!BUFFERCHECK(tif))
+ return ((tsize_t) -1);
+ tif->tif_curtile = tile;
+
+ tif->tif_rawcc = 0;
+ tif->tif_rawcp = tif->tif_rawdata;
+
+ if( td->td_stripbytecount[tile] > 0 )
+ {
+ /* Force TIFFAppendToStrip() to consider placing data at end
+ of file. */
+ tif->tif_curoff = 0;
+ }
+
+ /*
+ * Compute tiles per row & per column to compute
+ * current row and column
+ */
+ tif->tif_row = (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength))
+ * td->td_tilelength;
+ tif->tif_col = (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth))
+ * td->td_tilewidth;
+
+ if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
+ if (!(*tif->tif_setupencode)(tif))
+ return ((tsize_t) -1);
+ tif->tif_flags |= TIFF_CODERSETUP;
+ }
+ tif->tif_flags &= ~TIFF_POSTENCODE;
+ sample = (tsample_t)(tile/td->td_stripsperimage);
+ if (!(*tif->tif_preencode)(tif, sample))
+ return ((tsize_t) -1);
+ /*
+ * Clamp write amount to the tile size. This is mostly
+ * done so that callers can pass in some large number
+ * (e.g. -1) and have the tile size used instead.
+ */
+ if ( cc < 1 || cc > tif->tif_tilesize)
+ cc = tif->tif_tilesize;
+
+ /* swab if needed - note that source buffer will be altered */
+ tif->tif_postdecode( tif, (tidata_t) data, cc );
+
+ if (!(*tif->tif_encodetile)(tif, (tidata_t) data, cc, sample))
+ return ((tsize_t) 0);
+ if (!(*tif->tif_postencode)(tif))
+ return ((tsize_t) -1);
+ if (!isFillOrder(tif, td->td_fillorder) &&
+ (tif->tif_flags & TIFF_NOBITREV) == 0)
+ TIFFReverseBits((unsigned char *)tif->tif_rawdata, tif->tif_rawcc);
+ if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile,
+ tif->tif_rawdata, tif->tif_rawcc))
+ return ((tsize_t) -1);
+ tif->tif_rawcc = 0;
+ tif->tif_rawcp = tif->tif_rawdata;
+ return (cc);
+}
+
+/*
+ * Write the supplied data to the specified strip.
+ * There must be space for the data; we don't check
+ * if strips overlap!
+ *
+ * NB: Image length must be setup before writing; this
+ * interface does not support automatically growing
+ * the image on each write (as TIFFWriteScanline does).
+ */
+tsize_t
+TIFFWriteRawTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc)
+{
+ static const char module[] = "TIFFWriteRawTile";
+
+ if (!WRITECHECKTILES(tif, module))
+ return ((tsize_t) -1);
+ if (tile >= tif->tif_dir.td_nstrips) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Tile %lu out of range, max %lu",
+ tif->tif_name, (unsigned long) tile,
+ (unsigned long) tif->tif_dir.td_nstrips);
+ return ((tsize_t) -1);
+ }
+ return (TIFFAppendToStrip(tif, tile, (tidata_t) data, cc) ?
+ cc : (tsize_t) -1);
+}
+
+#define isUnspecified(tif, f) \
+ (TIFFFieldSet(tif,f) && (tif)->tif_dir.td_imagelength == 0)
+
+int
+TIFFSetupStrips(TIFF* tif)
+{
+ TIFFDirectory* td = &tif->tif_dir;
+
+ if (isTiled(tif))
+ td->td_stripsperimage =
+ isUnspecified(tif, FIELD_TILEDIMENSIONS) ?
+ td->td_samplesperpixel : TIFFNumberOfTiles(tif);
+ else
+ td->td_stripsperimage =
+ isUnspecified(tif, FIELD_ROWSPERSTRIP) ?
+ td->td_samplesperpixel : TIFFNumberOfStrips(tif);
+ td->td_nstrips = td->td_stripsperimage;
+ if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
+ td->td_stripsperimage /= td->td_samplesperpixel;
+ td->td_stripoffset = (uint32 *)
+ _TIFFmalloc(td->td_nstrips * sizeof (uint32));
+ td->td_stripbytecount = (uint32 *)
+ _TIFFmalloc(td->td_nstrips * sizeof (uint32));
+ if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL)
+ return (0);
+ /*
+ * Place data at the end-of-file
+ * (by setting offsets to zero).
+ */
+ _TIFFmemset(td->td_stripoffset, 0, td->td_nstrips*sizeof (uint32));
+ _TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint32));
+ TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
+ TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
+ return (1);
+}
+#undef isUnspecified
+
+/*
+ * Verify file is writable and that the directory
+ * information is setup properly. In doing the latter
+ * we also "freeze" the state of the directory so
+ * that important information is not changed.
+ */
+int
+TIFFWriteCheck(TIFF* tif, int tiles, const char* module)
+{
+ if (tif->tif_mode == O_RDONLY) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: File not open for writing",
+ tif->tif_name);
+ return (0);
+ }
+ if (tiles ^ isTiled(tif)) {
+ TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ?
+ "Can not write tiles to a stripped image" :
+ "Can not write scanlines to a tiled image");
+ return (0);
+ }
+
+ /*
+ * On the first write verify all the required information
+ * has been setup and initialize any data structures that
+ * had to wait until directory information was set.
+ * Note that a lot of our work is assumed to remain valid
+ * because we disallow any of the important parameters
+ * from changing after we start writing (i.e. once
+ * TIFF_BEENWRITING is set, TIFFSetField will only allow
+ * the image's length to be changed).
+ */
+ if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Must set \"ImageWidth\" before writing data",
+ tif->tif_name);
+ return (0);
+ }
+ if (tif->tif_dir.td_samplesperpixel == 1) {
+ /*
+ * Planarconfiguration is irrelevant in case of single band
+ * images and need not be included. We will set it anyway,
+ * because this field is used in other parts of library even
+ * in the single band case.
+ */
+ if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG))
+ tif->tif_dir.td_planarconfig = PLANARCONFIG_CONTIG;
+ } else {
+ if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Must set \"PlanarConfiguration\" before writing data",
+ tif->tif_name);
+ return (0);
+ }
+ }
+ if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) {
+ tif->tif_dir.td_nstrips = 0;
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for %s arrays",
+ tif->tif_name, isTiled(tif) ? "tile" : "strip");
+ return (0);
+ }
+ tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1;
+ tif->tif_scanlinesize = TIFFScanlineSize(tif);
+ tif->tif_flags |= TIFF_BEENWRITING;
+ return (1);
+}
+
+/*
+ * Setup the raw data buffer used for encoding.
+ */
+int
+TIFFWriteBufferSetup(TIFF* tif, tdata_t bp, tsize_t size)
+{
+ static const char module[] = "TIFFWriteBufferSetup";
+
+ if (tif->tif_rawdata) {
+ if (tif->tif_flags & TIFF_MYBUFFER) {
+ _TIFFfree(tif->tif_rawdata);
+ tif->tif_flags &= ~TIFF_MYBUFFER;
+ }
+ tif->tif_rawdata = NULL;
+ }
+ if (size == (tsize_t) -1) {
+ size = (isTiled(tif) ?
+ tif->tif_tilesize : TIFFStripSize(tif));
+ /*
+ * Make raw data buffer at least 8K
+ */
+ if (size < 8*1024)
+ size = 8*1024;
+ bp = NULL; /* NB: force malloc */
+ }
+ if (bp == NULL) {
+ bp = _TIFFmalloc(size);
+ if (bp == NULL) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for output buffer",
+ tif->tif_name);
+ return (0);
+ }
+ tif->tif_flags |= TIFF_MYBUFFER;
+ } else
+ tif->tif_flags &= ~TIFF_MYBUFFER;
+ tif->tif_rawdata = (tidata_t) bp;
+ tif->tif_rawdatasize = size;
+ tif->tif_rawcc = 0;
+ tif->tif_rawcp = tif->tif_rawdata;
+ tif->tif_flags |= TIFF_BUFFERSETUP;
+ return (1);
+}
+
+/*
+ * Grow the strip data structures by delta strips.
+ */
+static int
+TIFFGrowStrips(TIFF* tif, int delta, const char* module)
+{
+ TIFFDirectory *td = &tif->tif_dir;
+ uint32 *new_stripoffset, *new_stripbytecount;
+
+ assert(td->td_planarconfig == PLANARCONFIG_CONTIG);
+ new_stripoffset = (uint32*)_TIFFrealloc(td->td_stripoffset,
+ (td->td_nstrips + delta) * sizeof (uint32));
+ new_stripbytecount = (uint32*)_TIFFrealloc(td->td_stripbytecount,
+ (td->td_nstrips + delta) * sizeof (uint32));
+ if (new_stripoffset == NULL || new_stripbytecount == NULL) {
+ if (new_stripoffset)
+ _TIFFfree(new_stripoffset);
+ if (new_stripbytecount)
+ _TIFFfree(new_stripbytecount);
+ td->td_nstrips = 0;
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: No space to expand strip arrays",
+ tif->tif_name);
+ return (0);
+ }
+ td->td_stripoffset = new_stripoffset;
+ td->td_stripbytecount = new_stripbytecount;
+ _TIFFmemset(td->td_stripoffset + td->td_nstrips,
+ 0, delta*sizeof (uint32));
+ _TIFFmemset(td->td_stripbytecount + td->td_nstrips,
+ 0, delta*sizeof (uint32));
+ td->td_nstrips += delta;
+ return (1);
+}
+
+/*
+ * Append the data to the specified strip.
+ */
+static int
+TIFFAppendToStrip(TIFF* tif, tstrip_t strip, tidata_t data, tsize_t cc)
+{
+ static const char module[] = "TIFFAppendToStrip";
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) {
+ assert(td->td_nstrips > 0);
+
+ if( td->td_stripbytecount[strip] != 0
+ && td->td_stripoffset[strip] != 0
+ && td->td_stripbytecount[strip] >= cc )
+ {
+ /*
+ * There is already tile data on disk, and the new tile
+ * data we have to will fit in the same space. The only
+ * aspect of this that is risky is that there could be
+ * more data to append to this strip before we are done
+ * depending on how we are getting called.
+ */
+ if (!SeekOK(tif, td->td_stripoffset[strip])) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Seek error at scanline %lu",
+ (unsigned long)tif->tif_row);
+ return (0);
+ }
+ }
+ else
+ {
+ /*
+ * Seek to end of file, and set that as our location to
+ * write this strip.
+ */
+ td->td_stripoffset[strip] = TIFFSeekFile(tif, 0, SEEK_END);
+ }
+
+ tif->tif_curoff = td->td_stripoffset[strip];
+
+ /*
+ * We are starting a fresh strip/tile, so set the size to zero.
+ */
+ td->td_stripbytecount[strip] = 0;
+ }
+
+ if (!WriteOK(tif, data, cc)) {
+ TIFFErrorExt(tif->tif_clientdata, module, "Write error at scanline %lu",
+ (unsigned long) tif->tif_row);
+ return (0);
+ }
+ tif->tif_curoff = tif->tif_curoff+cc;
+ td->td_stripbytecount[strip] += cc;
+ return (1);
+}
+
+/*
+ * Internal version of TIFFFlushData that can be
+ * called by ``encodestrip routines'' w/o concern
+ * for infinite recursion.
+ */
+int
+TIFFFlushData1(TIFF* tif)
+{
+ if (tif->tif_rawcc > 0) {
+ if (!isFillOrder(tif, tif->tif_dir.td_fillorder) &&
+ (tif->tif_flags & TIFF_NOBITREV) == 0)
+ TIFFReverseBits((unsigned char *)tif->tif_rawdata,
+ tif->tif_rawcc);
+ if (!TIFFAppendToStrip(tif,
+ isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip,
+ tif->tif_rawdata, tif->tif_rawcc))
+ return (0);
+ tif->tif_rawcc = 0;
+ tif->tif_rawcp = tif->tif_rawdata;
+ }
+ return (1);
+}
+
+/*
+ * Set the current write offset. This should only be
+ * used to set the offset to a known previous location
+ * (very carefully), or to 0 so that the next write gets
+ * appended to the end of the file.
+ */
+void
+TIFFSetWriteOffset(TIFF* tif, toff_t off)
+{
+ tif->tif_curoff = off;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tif_zip.c b/tiff/libtiff/tif_zip.c
new file mode 100644
index 0000000..15091f8
--- /dev/null
+++ b/tiff/libtiff/tif_zip.c
@@ -0,0 +1,419 @@
+/* $Id: tif_zip.c,v 1.11.2.4 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1995-1997 Sam Leffler
+ * Copyright (c) 1995-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tiffiop.h"
+#ifdef ZIP_SUPPORT
+/*
+ * TIFF Library.
+ *
+ * ZIP (aka Deflate) Compression Support
+ *
+ * This file is simply an interface to the zlib library written by
+ * Jean-loup Gailly and Mark Adler. You must use version 1.0 or later
+ * of the library: this code assumes the 1.0 API and also depends on
+ * the ability to write the zlib header multiple times (one per strip)
+ * which was not possible with versions prior to 0.95. Note also that
+ * older versions of this codec avoided this bug by supressing the header
+ * entirely. This means that files written with the old library cannot
+ * be read; they should be converted to a different compression scheme
+ * and then reconverted.
+ *
+ * The data format used by the zlib library is described in the files
+ * zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the
+ * directory ftp://ftp.uu.net/pub/archiving/zip/doc. The library was
+ * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz.
+ */
+#include "tif_predict.h"
+#include "zlib.h"
+
+#include <stdio.h>
+
+/*
+ * Sigh, ZLIB_VERSION is defined as a string so there's no
+ * way to do a proper check here. Instead we guess based
+ * on the presence of #defines that were added between the
+ * 0.95 and 1.0 distributions.
+ */
+#if !defined(Z_NO_COMPRESSION) || !defined(Z_DEFLATED)
+#error "Antiquated ZLIB software; you must use version 1.0 or later"
+#endif
+
+/*
+ * State block for each open TIFF
+ * file using ZIP compression/decompression.
+ */
+typedef struct {
+ TIFFPredictorState predict;
+ z_stream stream;
+ int zipquality; /* compression level */
+ int state; /* state flags */
+#define ZSTATE_INIT_DECODE 0x01
+#define ZSTATE_INIT_ENCODE 0x02
+
+ TIFFVGetMethod vgetparent; /* super-class method */
+ TIFFVSetMethod vsetparent; /* super-class method */
+} ZIPState;
+
+#define ZState(tif) ((ZIPState*) (tif)->tif_data)
+#define DecoderState(tif) ZState(tif)
+#define EncoderState(tif) ZState(tif)
+
+static int ZIPEncode(TIFF*, tidata_t, tsize_t, tsample_t);
+static int ZIPDecode(TIFF*, tidata_t, tsize_t, tsample_t);
+
+static int
+ZIPSetupDecode(TIFF* tif)
+{
+ ZIPState* sp = DecoderState(tif);
+ static const char module[] = "ZIPSetupDecode";
+
+ assert(sp != NULL);
+
+ /* if we were last encoding, terminate this mode */
+ if (sp->state & ZSTATE_INIT_ENCODE) {
+ deflateEnd(&sp->stream);
+ sp->state = 0;
+ }
+
+ if (inflateInit(&sp->stream) != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg);
+ return (0);
+ } else {
+ sp->state |= ZSTATE_INIT_DECODE;
+ return (1);
+ }
+}
+
+/*
+ * Setup state for decoding a strip.
+ */
+static int
+ZIPPreDecode(TIFF* tif, tsample_t s)
+{
+ ZIPState* sp = DecoderState(tif);
+
+ (void) s;
+ assert(sp != NULL);
+
+ if( (sp->state & ZSTATE_INIT_DECODE) == 0 )
+ tif->tif_setupdecode( tif );
+
+ sp->stream.next_in = tif->tif_rawdata;
+ sp->stream.avail_in = tif->tif_rawcc;
+ return (inflateReset(&sp->stream) == Z_OK);
+}
+
+static int
+ZIPDecode(TIFF* tif, tidata_t op, tsize_t occ, tsample_t s)
+{
+ ZIPState* sp = DecoderState(tif);
+ static const char module[] = "ZIPDecode";
+
+ (void) s;
+ assert(sp != NULL);
+ assert(sp->state == ZSTATE_INIT_DECODE);
+
+ sp->stream.next_out = op;
+ sp->stream.avail_out = occ;
+ do {
+ int state = inflate(&sp->stream, Z_PARTIAL_FLUSH);
+ if (state == Z_STREAM_END)
+ break;
+ if (state == Z_DATA_ERROR) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Decoding error at scanline %d, %s",
+ tif->tif_name, tif->tif_row, sp->stream.msg);
+ if (inflateSync(&sp->stream) != Z_OK)
+ return (0);
+ continue;
+ }
+ if (state != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s",
+ tif->tif_name, sp->stream.msg);
+ return (0);
+ }
+ } while (sp->stream.avail_out > 0);
+ if (sp->stream.avail_out != 0) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "%s: Not enough data at scanline %d (short %d bytes)",
+ tif->tif_name, tif->tif_row, sp->stream.avail_out);
+ return (0);
+ }
+ return (1);
+}
+
+static int
+ZIPSetupEncode(TIFF* tif)
+{
+ ZIPState* sp = EncoderState(tif);
+ static const char module[] = "ZIPSetupEncode";
+
+ assert(sp != NULL);
+ if (sp->state & ZSTATE_INIT_DECODE) {
+ inflateEnd(&sp->stream);
+ sp->state = 0;
+ }
+
+ if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: %s", tif->tif_name, sp->stream.msg);
+ return (0);
+ } else {
+ sp->state |= ZSTATE_INIT_ENCODE;
+ return (1);
+ }
+}
+
+/*
+ * Reset encoding state at the start of a strip.
+ */
+static int
+ZIPPreEncode(TIFF* tif, tsample_t s)
+{
+ ZIPState *sp = EncoderState(tif);
+
+ (void) s;
+ assert(sp != NULL);
+ if( sp->state != ZSTATE_INIT_ENCODE )
+ tif->tif_setupencode( tif );
+
+ sp->stream.next_out = tif->tif_rawdata;
+ sp->stream.avail_out = tif->tif_rawdatasize;
+ return (deflateReset(&sp->stream) == Z_OK);
+}
+
+/*
+ * Encode a chunk of pixels.
+ */
+static int
+ZIPEncode(TIFF* tif, tidata_t bp, tsize_t cc, tsample_t s)
+{
+ ZIPState *sp = EncoderState(tif);
+ static const char module[] = "ZIPEncode";
+
+ assert(sp != NULL);
+ assert(sp->state == ZSTATE_INIT_ENCODE);
+
+ (void) s;
+ sp->stream.next_in = bp;
+ sp->stream.avail_in = cc;
+ do {
+ if (deflate(&sp->stream, Z_NO_FLUSH) != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: Encoder error: %s",
+ tif->tif_name, sp->stream.msg);
+ return (0);
+ }
+ if (sp->stream.avail_out == 0) {
+ tif->tif_rawcc = tif->tif_rawdatasize;
+ TIFFFlushData1(tif);
+ sp->stream.next_out = tif->tif_rawdata;
+ sp->stream.avail_out = tif->tif_rawdatasize;
+ }
+ } while (sp->stream.avail_in > 0);
+ return (1);
+}
+
+/*
+ * Finish off an encoded strip by flushing the last
+ * string and tacking on an End Of Information code.
+ */
+static int
+ZIPPostEncode(TIFF* tif)
+{
+ ZIPState *sp = EncoderState(tif);
+ static const char module[] = "ZIPPostEncode";
+ int state;
+
+ sp->stream.avail_in = 0;
+ do {
+ state = deflate(&sp->stream, Z_FINISH);
+ switch (state) {
+ case Z_STREAM_END:
+ case Z_OK:
+ if ((int)sp->stream.avail_out != (int)tif->tif_rawdatasize)
+ {
+ tif->tif_rawcc =
+ tif->tif_rawdatasize - sp->stream.avail_out;
+ TIFFFlushData1(tif);
+ sp->stream.next_out = tif->tif_rawdata;
+ sp->stream.avail_out = tif->tif_rawdatasize;
+ }
+ break;
+ default:
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s",
+ tif->tif_name, sp->stream.msg);
+ return (0);
+ }
+ } while (state != Z_STREAM_END);
+ return (1);
+}
+
+static void
+ZIPCleanup(TIFF* tif)
+{
+ ZIPState* sp = ZState(tif);
+
+ assert(sp != 0);
+
+ (void)TIFFPredictorCleanup(tif);
+
+ tif->tif_tagmethods.vgetfield = sp->vgetparent;
+ tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+ if (sp->state & ZSTATE_INIT_ENCODE) {
+ deflateEnd(&sp->stream);
+ sp->state = 0;
+ } else if( sp->state & ZSTATE_INIT_DECODE) {
+ inflateEnd(&sp->stream);
+ sp->state = 0;
+ }
+ _TIFFfree(sp);
+ tif->tif_data = NULL;
+
+ _TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+ZIPVSetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ ZIPState* sp = ZState(tif);
+ static const char module[] = "ZIPVSetField";
+
+ switch (tag) {
+ case TIFFTAG_ZIPQUALITY:
+ sp->zipquality = va_arg(ap, int);
+ if ( sp->state&ZSTATE_INIT_ENCODE ) {
+ if (deflateParams(&sp->stream,
+ sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) {
+ TIFFErrorExt(tif->tif_clientdata, module, "%s: zlib error: %s",
+ tif->tif_name, sp->stream.msg);
+ return (0);
+ }
+ }
+ return (1);
+ default:
+ return (*sp->vsetparent)(tif, tag, ap);
+ }
+ /*NOTREACHED*/
+}
+
+static int
+ZIPVGetField(TIFF* tif, ttag_t tag, va_list ap)
+{
+ ZIPState* sp = ZState(tif);
+
+ switch (tag) {
+ case TIFFTAG_ZIPQUALITY:
+ *va_arg(ap, int*) = sp->zipquality;
+ break;
+ default:
+ return (*sp->vgetparent)(tif, tag, ap);
+ }
+ return (1);
+}
+
+static const TIFFFieldInfo zipFieldInfo[] = {
+ { TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, FIELD_PSEUDO,
+ TRUE, FALSE, "" },
+};
+
+int
+TIFFInitZIP(TIFF* tif, int scheme)
+{
+ static const char module[] = "TIFFInitZIP";
+ ZIPState* sp;
+
+ assert( (scheme == COMPRESSION_DEFLATE)
+ || (scheme == COMPRESSION_ADOBE_DEFLATE));
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFieldInfo(tif, zipFieldInfo,
+ TIFFArrayCount(zipFieldInfo))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Merging Deflate codec-specific tags failed");
+ return 0;
+ }
+
+ /*
+ * Allocate state block so tag methods have storage to record values.
+ */
+ tif->tif_data = (tidata_t) _TIFFmalloc(sizeof (ZIPState));
+ if (tif->tif_data == NULL)
+ goto bad;
+ sp = ZState(tif);
+ sp->stream.zalloc = NULL;
+ sp->stream.zfree = NULL;
+ sp->stream.opaque = NULL;
+ sp->stream.data_type = Z_BINARY;
+
+ /*
+ * Override parent get/set field methods.
+ */
+ sp->vgetparent = tif->tif_tagmethods.vgetfield;
+ tif->tif_tagmethods.vgetfield = ZIPVGetField; /* hook for codec tags */
+ sp->vsetparent = tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vsetfield = ZIPVSetField; /* hook for codec tags */
+
+ /* Default values for codec-specific fields */
+ sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */
+ sp->state = 0;
+
+ /*
+ * Install codec methods.
+ */
+ tif->tif_setupdecode = ZIPSetupDecode;
+ tif->tif_predecode = ZIPPreDecode;
+ tif->tif_decoderow = ZIPDecode;
+ tif->tif_decodestrip = ZIPDecode;
+ tif->tif_decodetile = ZIPDecode;
+ tif->tif_setupencode = ZIPSetupEncode;
+ tif->tif_preencode = ZIPPreEncode;
+ tif->tif_postencode = ZIPPostEncode;
+ tif->tif_encoderow = ZIPEncode;
+ tif->tif_encodestrip = ZIPEncode;
+ tif->tif_encodetile = ZIPEncode;
+ tif->tif_cleanup = ZIPCleanup;
+ /*
+ * Setup predictor setup.
+ */
+ (void) TIFFPredictorInit(tif);
+ return (1);
+bad:
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "No space for ZIP state block");
+ return (0);
+}
+#endif /* ZIP_SUPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tiff.h b/tiff/libtiff/tiff.h
new file mode 100644
index 0000000..0d4ab9f
--- /dev/null
+++ b/tiff/libtiff/tiff.h
@@ -0,0 +1,654 @@
+/* $Id: tiff.h,v 1.43.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFF_
+#define _TIFF_
+
+#include "tiffconf.h"
+
+/*
+ * Tag Image File Format (TIFF)
+ *
+ * Based on Rev 6.0 from:
+ * Developer's Desk
+ * Aldus Corporation
+ * 411 First Ave. South
+ * Suite 200
+ * Seattle, WA 98104
+ * 206-622-5500
+ *
+ * (http://partners.adobe.com/asn/developer/PDFS/TN/TIFF6.pdf)
+ *
+ * For Big TIFF design notes see the following link
+ * http://www.remotesensing.org/libtiff/bigtiffdesign.html
+ */
+#define TIFF_VERSION 42
+#define TIFF_BIGTIFF_VERSION 43
+
+#define TIFF_BIGENDIAN 0x4d4d
+#define TIFF_LITTLEENDIAN 0x4949
+#define MDI_LITTLEENDIAN 0x5045
+#define MDI_BIGENDIAN 0x4550
+/*
+ * Intrinsic data types required by the file format:
+ *
+ * 8-bit quantities int8/uint8
+ * 16-bit quantities int16/uint16
+ * 32-bit quantities int32/uint32
+ * strings unsigned char*
+ */
+
+#ifndef HAVE_INT8
+typedef signed char int8; /* NB: non-ANSI compilers may not grok */
+#endif
+typedef unsigned char uint8;
+#ifndef HAVE_INT16
+typedef short int16;
+#endif
+typedef unsigned short uint16; /* sizeof (uint16) must == 2 */
+#if SIZEOF_INT == 4
+#ifndef HAVE_INT32
+typedef int int32;
+#endif
+typedef unsigned int uint32; /* sizeof (uint32) must == 4 */
+#elif SIZEOF_LONG == 4
+#ifndef HAVE_INT32
+typedef long int32;
+#endif
+typedef unsigned long uint32; /* sizeof (uint32) must == 4 */
+#endif
+
+/* For TIFFReassignTagToIgnore */
+enum TIFFIgnoreSense /* IGNORE tag table */
+{
+ TIS_STORE,
+ TIS_EXTRACT,
+ TIS_EMPTY
+};
+
+/*
+ * TIFF header.
+ */
+typedef struct {
+ uint16 tiff_magic; /* magic number (defines byte order) */
+#define TIFF_MAGIC_SIZE 2
+ uint16 tiff_version; /* TIFF version number */
+#define TIFF_VERSION_SIZE 2
+ uint32 tiff_diroff; /* byte offset to first directory */
+#define TIFF_DIROFFSET_SIZE 4
+} TIFFHeader;
+
+
+/*
+ * TIFF Image File Directories are comprised of a table of field
+ * descriptors of the form shown below. The table is sorted in
+ * ascending order by tag. The values associated with each entry are
+ * disjoint and may appear anywhere in the file (so long as they are
+ * placed on a word boundary).
+ *
+ * If the value is 4 bytes or less, then it is placed in the offset
+ * field to save space. If the value is less than 4 bytes, it is
+ * left-justified in the offset field.
+ */
+typedef struct {
+ uint16 tdir_tag; /* see below */
+ uint16 tdir_type; /* data type; see below */
+ uint32 tdir_count; /* number of items; length in spec */
+ uint32 tdir_offset; /* byte offset to field data */
+} TIFFDirEntry;
+
+/*
+ * NB: In the comments below,
+ * - items marked with a + are obsoleted by revision 5.0,
+ * - items marked with a ! are introduced in revision 6.0.
+ * - items marked with a % are introduced post revision 6.0.
+ * - items marked with a $ are obsoleted by revision 6.0.
+ * - items marked with a & are introduced by Adobe DNG specification.
+ */
+
+/*
+ * Tag data type information.
+ *
+ * Note: RATIONALs are the ratio of two 32-bit integer values.
+ */
+typedef enum {
+ TIFF_NOTYPE = 0, /* placeholder */
+ TIFF_BYTE = 1, /* 8-bit unsigned integer */
+ TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */
+ TIFF_SHORT = 3, /* 16-bit unsigned integer */
+ TIFF_LONG = 4, /* 32-bit unsigned integer */
+ TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */
+ TIFF_SBYTE = 6, /* !8-bit signed integer */
+ TIFF_UNDEFINED = 7, /* !8-bit untyped data */
+ TIFF_SSHORT = 8, /* !16-bit signed integer */
+ TIFF_SLONG = 9, /* !32-bit signed integer */
+ TIFF_SRATIONAL = 10, /* !64-bit signed fraction */
+ TIFF_FLOAT = 11, /* !32-bit IEEE floating point */
+ TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */
+ TIFF_IFD = 13 /* %32-bit unsigned integer (offset) */
+} TIFFDataType;
+
+/*
+ * TIFF Tag Definitions.
+ */
+#define TIFFTAG_SUBFILETYPE 254 /* subfile data descriptor */
+#define FILETYPE_REDUCEDIMAGE 0x1 /* reduced resolution version */
+#define FILETYPE_PAGE 0x2 /* one page of many */
+#define FILETYPE_MASK 0x4 /* transparency mask */
+#define TIFFTAG_OSUBFILETYPE 255 /* +kind of data in subfile */
+#define OFILETYPE_IMAGE 1 /* full resolution image data */
+#define OFILETYPE_REDUCEDIMAGE 2 /* reduced size image data */
+#define OFILETYPE_PAGE 3 /* one page of many */
+#define TIFFTAG_IMAGEWIDTH 256 /* image width in pixels */
+#define TIFFTAG_IMAGELENGTH 257 /* image height in pixels */
+#define TIFFTAG_BITSPERSAMPLE 258 /* bits per channel (sample) */
+#define TIFFTAG_COMPRESSION 259 /* data compression technique */
+#define COMPRESSION_NONE 1 /* dump mode */
+#define COMPRESSION_CCITTRLE 2 /* CCITT modified Huffman RLE */
+#define COMPRESSION_CCITTFAX3 3 /* CCITT Group 3 fax encoding */
+#define COMPRESSION_CCITT_T4 3 /* CCITT T.4 (TIFF 6 name) */
+#define COMPRESSION_CCITTFAX4 4 /* CCITT Group 4 fax encoding */
+#define COMPRESSION_CCITT_T6 4 /* CCITT T.6 (TIFF 6 name) */
+#define COMPRESSION_LZW 5 /* Lempel-Ziv & Welch */
+#define COMPRESSION_OJPEG 6 /* !6.0 JPEG */
+#define COMPRESSION_JPEG 7 /* %JPEG DCT compression */
+#define COMPRESSION_NEXT 32766 /* NeXT 2-bit RLE */
+#define COMPRESSION_CCITTRLEW 32771 /* #1 w/ word alignment */
+#define COMPRESSION_PACKBITS 32773 /* Macintosh RLE */
+#define COMPRESSION_THUNDERSCAN 32809 /* ThunderScan RLE */
+/* codes 32895-32898 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) */
+#define COMPRESSION_IT8CTPAD 32895 /* IT8 CT w/padding */
+#define COMPRESSION_IT8LW 32896 /* IT8 Linework RLE */
+#define COMPRESSION_IT8MP 32897 /* IT8 Monochrome picture */
+#define COMPRESSION_IT8BL 32898 /* IT8 Binary line art */
+/* compression codes 32908-32911 are reserved for Pixar */
+#define COMPRESSION_PIXARFILM 32908 /* Pixar companded 10bit LZW */
+#define COMPRESSION_PIXARLOG 32909 /* Pixar companded 11bit ZIP */
+#define COMPRESSION_DEFLATE 32946 /* Deflate compression */
+#define COMPRESSION_ADOBE_DEFLATE 8 /* Deflate compression,
+ as recognized by Adobe */
+/* compression code 32947 is reserved for Oceana Matrix <dev@oceana.com> */
+#define COMPRESSION_DCS 32947 /* Kodak DCS encoding */
+#define COMPRESSION_JBIG 34661 /* ISO JBIG */
+#define COMPRESSION_SGILOG 34676 /* SGI Log Luminance RLE */
+#define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */
+#define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */
+#define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */
+#define PHOTOMETRIC_MINISWHITE 0 /* min value is white */
+#define PHOTOMETRIC_MINISBLACK 1 /* min value is black */
+#define PHOTOMETRIC_RGB 2 /* RGB color model */
+#define PHOTOMETRIC_PALETTE 3 /* color map indexed */
+#define PHOTOMETRIC_MASK 4 /* $holdout mask */
+#define PHOTOMETRIC_SEPARATED 5 /* !color separations */
+#define PHOTOMETRIC_YCBCR 6 /* !CCIR 601 */
+#define PHOTOMETRIC_CIELAB 8 /* !1976 CIE L*a*b* */
+#define PHOTOMETRIC_ICCLAB 9 /* ICC L*a*b* [Adobe TIFF Technote 4] */
+#define PHOTOMETRIC_ITULAB 10 /* ITU L*a*b* */
+#define PHOTOMETRIC_LOGL 32844 /* CIE Log2(L) */
+#define PHOTOMETRIC_LOGLUV 32845 /* CIE Log2(L) (u',v') */
+#define TIFFTAG_THRESHHOLDING 263 /* +thresholding used on data */
+#define THRESHHOLD_BILEVEL 1 /* b&w art scan */
+#define THRESHHOLD_HALFTONE 2 /* or dithered scan */
+#define THRESHHOLD_ERRORDIFFUSE 3 /* usually floyd-steinberg */
+#define TIFFTAG_CELLWIDTH 264 /* +dithering matrix width */
+#define TIFFTAG_CELLLENGTH 265 /* +dithering matrix height */
+#define TIFFTAG_FILLORDER 266 /* data order within a byte */
+#define FILLORDER_MSB2LSB 1 /* most significant -> least */
+#define FILLORDER_LSB2MSB 2 /* least significant -> most */
+#define TIFFTAG_DOCUMENTNAME 269 /* name of doc. image is from */
+#define TIFFTAG_IMAGEDESCRIPTION 270 /* info about image */
+#define TIFFTAG_MAKE 271 /* scanner manufacturer name */
+#define TIFFTAG_MODEL 272 /* scanner model name/number */
+#define TIFFTAG_STRIPOFFSETS 273 /* offsets to data strips */
+#define TIFFTAG_ORIENTATION 274 /* +image orientation */
+#define ORIENTATION_TOPLEFT 1 /* row 0 top, col 0 lhs */
+#define ORIENTATION_TOPRIGHT 2 /* row 0 top, col 0 rhs */
+#define ORIENTATION_BOTRIGHT 3 /* row 0 bottom, col 0 rhs */
+#define ORIENTATION_BOTLEFT 4 /* row 0 bottom, col 0 lhs */
+#define ORIENTATION_LEFTTOP 5 /* row 0 lhs, col 0 top */
+#define ORIENTATION_RIGHTTOP 6 /* row 0 rhs, col 0 top */
+#define ORIENTATION_RIGHTBOT 7 /* row 0 rhs, col 0 bottom */
+#define ORIENTATION_LEFTBOT 8 /* row 0 lhs, col 0 bottom */
+#define TIFFTAG_SAMPLESPERPIXEL 277 /* samples per pixel */
+#define TIFFTAG_ROWSPERSTRIP 278 /* rows per strip of data */
+#define TIFFTAG_STRIPBYTECOUNTS 279 /* bytes counts for strips */
+#define TIFFTAG_MINSAMPLEVALUE 280 /* +minimum sample value */
+#define TIFFTAG_MAXSAMPLEVALUE 281 /* +maximum sample value */
+#define TIFFTAG_XRESOLUTION 282 /* pixels/resolution in x */
+#define TIFFTAG_YRESOLUTION 283 /* pixels/resolution in y */
+#define TIFFTAG_PLANARCONFIG 284 /* storage organization */
+#define PLANARCONFIG_CONTIG 1 /* single image plane */
+#define PLANARCONFIG_SEPARATE 2 /* separate planes of data */
+#define TIFFTAG_PAGENAME 285 /* page name image is from */
+#define TIFFTAG_XPOSITION 286 /* x page offset of image lhs */
+#define TIFFTAG_YPOSITION 287 /* y page offset of image lhs */
+#define TIFFTAG_FREEOFFSETS 288 /* +byte offset to free block */
+#define TIFFTAG_FREEBYTECOUNTS 289 /* +sizes of free blocks */
+#define TIFFTAG_GRAYRESPONSEUNIT 290 /* $gray scale curve accuracy */
+#define GRAYRESPONSEUNIT_10S 1 /* tenths of a unit */
+#define GRAYRESPONSEUNIT_100S 2 /* hundredths of a unit */
+#define GRAYRESPONSEUNIT_1000S 3 /* thousandths of a unit */
+#define GRAYRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */
+#define GRAYRESPONSEUNIT_100000S 5 /* hundred-thousandths */
+#define TIFFTAG_GRAYRESPONSECURVE 291 /* $gray scale response curve */
+#define TIFFTAG_GROUP3OPTIONS 292 /* 32 flag bits */
+#define TIFFTAG_T4OPTIONS 292 /* TIFF 6.0 proper name alias */
+#define GROUP3OPT_2DENCODING 0x1 /* 2-dimensional coding */
+#define GROUP3OPT_UNCOMPRESSED 0x2 /* data not compressed */
+#define GROUP3OPT_FILLBITS 0x4 /* fill to byte boundary */
+#define TIFFTAG_GROUP4OPTIONS 293 /* 32 flag bits */
+#define TIFFTAG_T6OPTIONS 293 /* TIFF 6.0 proper name */
+#define GROUP4OPT_UNCOMPRESSED 0x2 /* data not compressed */
+#define TIFFTAG_RESOLUTIONUNIT 296 /* units of resolutions */
+#define RESUNIT_NONE 1 /* no meaningful units */
+#define RESUNIT_INCH 2 /* english */
+#define RESUNIT_CENTIMETER 3 /* metric */
+#define TIFFTAG_PAGENUMBER 297 /* page numbers of multi-page */
+#define TIFFTAG_COLORRESPONSEUNIT 300 /* $color curve accuracy */
+#define COLORRESPONSEUNIT_10S 1 /* tenths of a unit */
+#define COLORRESPONSEUNIT_100S 2 /* hundredths of a unit */
+#define COLORRESPONSEUNIT_1000S 3 /* thousandths of a unit */
+#define COLORRESPONSEUNIT_10000S 4 /* ten-thousandths of a unit */
+#define COLORRESPONSEUNIT_100000S 5 /* hundred-thousandths */
+#define TIFFTAG_TRANSFERFUNCTION 301 /* !colorimetry info */
+#define TIFFTAG_SOFTWARE 305 /* name & release */
+#define TIFFTAG_DATETIME 306 /* creation date and time */
+#define TIFFTAG_ARTIST 315 /* creator of image */
+#define TIFFTAG_HOSTCOMPUTER 316 /* machine where created */
+#define TIFFTAG_PREDICTOR 317 /* prediction scheme w/ LZW */
+#define PREDICTOR_NONE 1 /* no prediction scheme used */
+#define PREDICTOR_HORIZONTAL 2 /* horizontal differencing */
+#define PREDICTOR_FLOATINGPOINT 3 /* floating point predictor */
+#define TIFFTAG_WHITEPOINT 318 /* image white point */
+#define TIFFTAG_PRIMARYCHROMATICITIES 319 /* !primary chromaticities */
+#define TIFFTAG_COLORMAP 320 /* RGB map for pallette image */
+#define TIFFTAG_HALFTONEHINTS 321 /* !highlight+shadow info */
+#define TIFFTAG_TILEWIDTH 322 /* !tile width in pixels */
+#define TIFFTAG_TILELENGTH 323 /* !tile height in pixels */
+#define TIFFTAG_TILEOFFSETS 324 /* !offsets to data tiles */
+#define TIFFTAG_TILEBYTECOUNTS 325 /* !byte counts for tiles */
+#define TIFFTAG_BADFAXLINES 326 /* lines w/ wrong pixel count */
+#define TIFFTAG_CLEANFAXDATA 327 /* regenerated line info */
+#define CLEANFAXDATA_CLEAN 0 /* no errors detected */
+#define CLEANFAXDATA_REGENERATED 1 /* receiver regenerated lines */
+#define CLEANFAXDATA_UNCLEAN 2 /* uncorrected errors exist */
+#define TIFFTAG_CONSECUTIVEBADFAXLINES 328 /* max consecutive bad lines */
+#define TIFFTAG_SUBIFD 330 /* subimage descriptors */
+#define TIFFTAG_INKSET 332 /* !inks in separated image */
+#define INKSET_CMYK 1 /* !cyan-magenta-yellow-black color */
+#define INKSET_MULTIINK 2 /* !multi-ink or hi-fi color */
+#define TIFFTAG_INKNAMES 333 /* !ascii names of inks */
+#define TIFFTAG_NUMBEROFINKS 334 /* !number of inks */
+#define TIFFTAG_DOTRANGE 336 /* !0% and 100% dot codes */
+#define TIFFTAG_TARGETPRINTER 337 /* !separation target */
+#define TIFFTAG_EXTRASAMPLES 338 /* !info about extra samples */
+#define EXTRASAMPLE_UNSPECIFIED 0 /* !unspecified data */
+#define EXTRASAMPLE_ASSOCALPHA 1 /* !associated alpha data */
+#define EXTRASAMPLE_UNASSALPHA 2 /* !unassociated alpha data */
+#define TIFFTAG_SAMPLEFORMAT 339 /* !data sample format */
+#define SAMPLEFORMAT_UINT 1 /* !unsigned integer data */
+#define SAMPLEFORMAT_INT 2 /* !signed integer data */
+#define SAMPLEFORMAT_IEEEFP 3 /* !IEEE floating point data */
+#define SAMPLEFORMAT_VOID 4 /* !untyped data */
+#define SAMPLEFORMAT_COMPLEXINT 5 /* !complex signed int */
+#define SAMPLEFORMAT_COMPLEXIEEEFP 6 /* !complex ieee floating */
+#define TIFFTAG_SMINSAMPLEVALUE 340 /* !variable MinSampleValue */
+#define TIFFTAG_SMAXSAMPLEVALUE 341 /* !variable MaxSampleValue */
+#define TIFFTAG_CLIPPATH 343 /* %ClipPath
+ [Adobe TIFF technote 2] */
+#define TIFFTAG_XCLIPPATHUNITS 344 /* %XClipPathUnits
+ [Adobe TIFF technote 2] */
+#define TIFFTAG_YCLIPPATHUNITS 345 /* %YClipPathUnits
+ [Adobe TIFF technote 2] */
+#define TIFFTAG_INDEXED 346 /* %Indexed
+ [Adobe TIFF Technote 3] */
+#define TIFFTAG_JPEGTABLES 347 /* %JPEG table stream */
+#define TIFFTAG_OPIPROXY 351 /* %OPI Proxy [Adobe TIFF technote] */
+/*
+ * Tags 512-521 are obsoleted by Technical Note #2 which specifies a
+ * revised JPEG-in-TIFF scheme.
+ */
+#define TIFFTAG_JPEGPROC 512 /* !JPEG processing algorithm */
+#define JPEGPROC_BASELINE 1 /* !baseline sequential */
+#define JPEGPROC_LOSSLESS 14 /* !Huffman coded lossless */
+#define TIFFTAG_JPEGIFOFFSET 513 /* !pointer to SOI marker */
+#define TIFFTAG_JPEGIFBYTECOUNT 514 /* !JFIF stream length */
+#define TIFFTAG_JPEGRESTARTINTERVAL 515 /* !restart interval length */
+#define TIFFTAG_JPEGLOSSLESSPREDICTORS 517 /* !lossless proc predictor */
+#define TIFFTAG_JPEGPOINTTRANSFORM 518 /* !lossless point transform */
+#define TIFFTAG_JPEGQTABLES 519 /* !Q matrice offsets */
+#define TIFFTAG_JPEGDCTABLES 520 /* !DCT table offsets */
+#define TIFFTAG_JPEGACTABLES 521 /* !AC coefficient offsets */
+#define TIFFTAG_YCBCRCOEFFICIENTS 529 /* !RGB -> YCbCr transform */
+#define TIFFTAG_YCBCRSUBSAMPLING 530 /* !YCbCr subsampling factors */
+#define TIFFTAG_YCBCRPOSITIONING 531 /* !subsample positioning */
+#define YCBCRPOSITION_CENTERED 1 /* !as in PostScript Level 2 */
+#define YCBCRPOSITION_COSITED 2 /* !as in CCIR 601-1 */
+#define TIFFTAG_REFERENCEBLACKWHITE 532 /* !colorimetry info */
+#define TIFFTAG_XMLPACKET 700 /* %XML packet
+ [Adobe XMP Specification,
+ January 2004 */
+#define TIFFTAG_OPIIMAGEID 32781 /* %OPI ImageID
+ [Adobe TIFF technote] */
+/* tags 32952-32956 are private tags registered to Island Graphics */
+#define TIFFTAG_REFPTS 32953 /* image reference points */
+#define TIFFTAG_REGIONTACKPOINT 32954 /* region-xform tack point */
+#define TIFFTAG_REGIONWARPCORNERS 32955 /* warp quadrilateral */
+#define TIFFTAG_REGIONAFFINE 32956 /* affine transformation mat */
+/* tags 32995-32999 are private tags registered to SGI */
+#define TIFFTAG_MATTEING 32995 /* $use ExtraSamples */
+#define TIFFTAG_DATATYPE 32996 /* $use SampleFormat */
+#define TIFFTAG_IMAGEDEPTH 32997 /* z depth of image */
+#define TIFFTAG_TILEDEPTH 32998 /* z depth/data tile */
+/* tags 33300-33309 are private tags registered to Pixar */
+/*
+ * TIFFTAG_PIXAR_IMAGEFULLWIDTH and TIFFTAG_PIXAR_IMAGEFULLLENGTH
+ * are set when an image has been cropped out of a larger image.
+ * They reflect the size of the original uncropped image.
+ * The TIFFTAG_XPOSITION and TIFFTAG_YPOSITION can be used
+ * to determine the position of the smaller image in the larger one.
+ */
+#define TIFFTAG_PIXAR_IMAGEFULLWIDTH 33300 /* full image size in x */
+#define TIFFTAG_PIXAR_IMAGEFULLLENGTH 33301 /* full image size in y */
+ /* Tags 33302-33306 are used to identify special image modes and data
+ * used by Pixar's texture formats.
+ */
+#define TIFFTAG_PIXAR_TEXTUREFORMAT 33302 /* texture map format */
+#define TIFFTAG_PIXAR_WRAPMODES 33303 /* s & t wrap modes */
+#define TIFFTAG_PIXAR_FOVCOT 33304 /* cotan(fov) for env. maps */
+#define TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN 33305
+#define TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA 33306
+/* tag 33405 is a private tag registered to Eastman Kodak */
+#define TIFFTAG_WRITERSERIALNUMBER 33405 /* device serial number */
+/* tag 33432 is listed in the 6.0 spec w/ unknown ownership */
+#define TIFFTAG_COPYRIGHT 33432 /* copyright string */
+/* IPTC TAG from RichTIFF specifications */
+#define TIFFTAG_RICHTIFFIPTC 33723
+/* 34016-34029 are reserved for ANSI IT8 TIFF/IT <dkelly@apago.com) */
+#define TIFFTAG_IT8SITE 34016 /* site name */
+#define TIFFTAG_IT8COLORSEQUENCE 34017 /* color seq. [RGB,CMYK,etc] */
+#define TIFFTAG_IT8HEADER 34018 /* DDES Header */
+#define TIFFTAG_IT8RASTERPADDING 34019 /* raster scanline padding */
+#define TIFFTAG_IT8BITSPERRUNLENGTH 34020 /* # of bits in short run */
+#define TIFFTAG_IT8BITSPEREXTENDEDRUNLENGTH 34021/* # of bits in long run */
+#define TIFFTAG_IT8COLORTABLE 34022 /* LW colortable */
+#define TIFFTAG_IT8IMAGECOLORINDICATOR 34023 /* BP/BL image color switch */
+#define TIFFTAG_IT8BKGCOLORINDICATOR 34024 /* BP/BL bg color switch */
+#define TIFFTAG_IT8IMAGECOLORVALUE 34025 /* BP/BL image color value */
+#define TIFFTAG_IT8BKGCOLORVALUE 34026 /* BP/BL bg color value */
+#define TIFFTAG_IT8PIXELINTENSITYRANGE 34027 /* MP pixel intensity value */
+#define TIFFTAG_IT8TRANSPARENCYINDICATOR 34028 /* HC transparency switch */
+#define TIFFTAG_IT8COLORCHARACTERIZATION 34029 /* color character. table */
+#define TIFFTAG_IT8HCUSAGE 34030 /* HC usage indicator */
+#define TIFFTAG_IT8TRAPINDICATOR 34031 /* Trapping indicator
+ (untrapped=0, trapped=1) */
+#define TIFFTAG_IT8CMYKEQUIVALENT 34032 /* CMYK color equivalents */
+/* tags 34232-34236 are private tags registered to Texas Instruments */
+#define TIFFTAG_FRAMECOUNT 34232 /* Sequence Frame Count */
+/* tag 34377 is private tag registered to Adobe for PhotoShop */
+#define TIFFTAG_PHOTOSHOP 34377
+/* tags 34665, 34853 and 40965 are documented in EXIF specification */
+#define TIFFTAG_EXIFIFD 34665 /* Pointer to EXIF private directory */
+/* tag 34750 is a private tag registered to Adobe? */
+#define TIFFTAG_ICCPROFILE 34675 /* ICC profile data */
+/* tag 34750 is a private tag registered to Pixel Magic */
+#define TIFFTAG_JBIGOPTIONS 34750 /* JBIG options */
+#define TIFFTAG_GPSIFD 34853 /* Pointer to GPS private directory */
+/* tags 34908-34914 are private tags registered to SGI */
+#define TIFFTAG_FAXRECVPARAMS 34908 /* encoded Class 2 ses. parms */
+#define TIFFTAG_FAXSUBADDRESS 34909 /* received SubAddr string */
+#define TIFFTAG_FAXRECVTIME 34910 /* receive time (secs) */
+#define TIFFTAG_FAXDCS 34911 /* encoded fax ses. params, Table 2/T.30 */
+/* tags 37439-37443 are registered to SGI <gregl@sgi.com> */
+#define TIFFTAG_STONITS 37439 /* Sample value to Nits */
+/* tag 34929 is a private tag registered to FedEx */
+#define TIFFTAG_FEDEX_EDR 34929 /* unknown use */
+#define TIFFTAG_INTEROPERABILITYIFD 40965 /* Pointer to Interoperability private directory */
+/* Adobe Digital Negative (DNG) format tags */
+#define TIFFTAG_DNGVERSION 50706 /* &DNG version number */
+#define TIFFTAG_DNGBACKWARDVERSION 50707 /* &DNG compatibility version */
+#define TIFFTAG_UNIQUECAMERAMODEL 50708 /* &name for the camera model */
+#define TIFFTAG_LOCALIZEDCAMERAMODEL 50709 /* &localized camera model
+ name */
+#define TIFFTAG_CFAPLANECOLOR 50710 /* &CFAPattern->LinearRaw space
+ mapping */
+#define TIFFTAG_CFALAYOUT 50711 /* &spatial layout of the CFA */
+#define TIFFTAG_LINEARIZATIONTABLE 50712 /* &lookup table description */
+#define TIFFTAG_BLACKLEVELREPEATDIM 50713 /* &repeat pattern size for
+ the BlackLevel tag */
+#define TIFFTAG_BLACKLEVEL 50714 /* &zero light encoding level */
+#define TIFFTAG_BLACKLEVELDELTAH 50715 /* &zero light encoding level
+ differences (columns) */
+#define TIFFTAG_BLACKLEVELDELTAV 50716 /* &zero light encoding level
+ differences (rows) */
+#define TIFFTAG_WHITELEVEL 50717 /* &fully saturated encoding
+ level */
+#define TIFFTAG_DEFAULTSCALE 50718 /* &default scale factors */
+#define TIFFTAG_DEFAULTCROPORIGIN 50719 /* &origin of the final image
+ area */
+#define TIFFTAG_DEFAULTCROPSIZE 50720 /* &size of the final image
+ area */
+#define TIFFTAG_COLORMATRIX1 50721 /* &XYZ->reference color space
+ transformation matrix 1 */
+#define TIFFTAG_COLORMATRIX2 50722 /* &XYZ->reference color space
+ transformation matrix 2 */
+#define TIFFTAG_CAMERACALIBRATION1 50723 /* &calibration matrix 1 */
+#define TIFFTAG_CAMERACALIBRATION2 50724 /* &calibration matrix 2 */
+#define TIFFTAG_REDUCTIONMATRIX1 50725 /* &dimensionality reduction
+ matrix 1 */
+#define TIFFTAG_REDUCTIONMATRIX2 50726 /* &dimensionality reduction
+ matrix 2 */
+#define TIFFTAG_ANALOGBALANCE 50727 /* &gain applied the stored raw
+ values*/
+#define TIFFTAG_ASSHOTNEUTRAL 50728 /* &selected white balance in
+ linear reference space */
+#define TIFFTAG_ASSHOTWHITEXY 50729 /* &selected white balance in
+ x-y chromaticity
+ coordinates */
+#define TIFFTAG_BASELINEEXPOSURE 50730 /* &how much to move the zero
+ point */
+#define TIFFTAG_BASELINENOISE 50731 /* &relative noise level */
+#define TIFFTAG_BASELINESHARPNESS 50732 /* &relative amount of
+ sharpening */
+#define TIFFTAG_BAYERGREENSPLIT 50733 /* &how closely the values of
+ the green pixels in the
+ blue/green rows track the
+ values of the green pixels
+ in the red/green rows */
+#define TIFFTAG_LINEARRESPONSELIMIT 50734 /* &non-linear encoding range */
+#define TIFFTAG_CAMERASERIALNUMBER 50735 /* &camera's serial number */
+#define TIFFTAG_LENSINFO 50736 /* info about the lens */
+#define TIFFTAG_CHROMABLURRADIUS 50737 /* &chroma blur radius */
+#define TIFFTAG_ANTIALIASSTRENGTH 50738 /* &relative strength of the
+ camera's anti-alias filter */
+#define TIFFTAG_SHADOWSCALE 50739 /* &used by Adobe Camera Raw */
+#define TIFFTAG_DNGPRIVATEDATA 50740 /* &manufacturer's private data */
+#define TIFFTAG_MAKERNOTESAFETY 50741 /* &whether the EXIF MakerNote
+ tag is safe to preserve
+ along with the rest of the
+ EXIF data */
+#define TIFFTAG_CALIBRATIONILLUMINANT1 50778 /* &illuminant 1 */
+#define TIFFTAG_CALIBRATIONILLUMINANT2 50779 /* &illuminant 2 */
+#define TIFFTAG_BESTQUALITYSCALE 50780 /* &best quality multiplier */
+#define TIFFTAG_RAWDATAUNIQUEID 50781 /* &unique identifier for
+ the raw image data */
+#define TIFFTAG_ORIGINALRAWFILENAME 50827 /* &file name of the original
+ raw file */
+#define TIFFTAG_ORIGINALRAWFILEDATA 50828 /* &contents of the original
+ raw file */
+#define TIFFTAG_ACTIVEAREA 50829 /* &active (non-masked) pixels
+ of the sensor */
+#define TIFFTAG_MASKEDAREAS 50830 /* &list of coordinates
+ of fully masked pixels */
+#define TIFFTAG_ASSHOTICCPROFILE 50831 /* &these two tags used to */
+#define TIFFTAG_ASSHOTPREPROFILEMATRIX 50832 /* map cameras's color space
+ into ICC profile space */
+#define TIFFTAG_CURRENTICCPROFILE 50833 /* & */
+#define TIFFTAG_CURRENTPREPROFILEMATRIX 50834 /* & */
+/* tag 65535 is an undefined tag used by Eastman Kodak */
+#define TIFFTAG_DCSHUESHIFTVALUES 65535 /* hue shift correction data */
+
+/*
+ * The following are ``pseudo tags'' that can be used to control
+ * codec-specific functionality. These tags are not written to file.
+ * Note that these values start at 0xffff+1 so that they'll never
+ * collide with Aldus-assigned tags.
+ *
+ * If you want your private pseudo tags ``registered'' (i.e. added to
+ * this file), please post a bug report via the tracking system at
+ * http://www.remotesensing.org/libtiff/bugs.html with the appropriate
+ * C definitions to add.
+ */
+#define TIFFTAG_FAXMODE 65536 /* Group 3/4 format control */
+#define FAXMODE_CLASSIC 0x0000 /* default, include RTC */
+#define FAXMODE_NORTC 0x0001 /* no RTC at end of data */
+#define FAXMODE_NOEOL 0x0002 /* no EOL code at end of row */
+#define FAXMODE_BYTEALIGN 0x0004 /* byte align row */
+#define FAXMODE_WORDALIGN 0x0008 /* word align row */
+#define FAXMODE_CLASSF FAXMODE_NORTC /* TIFF Class F */
+#define TIFFTAG_JPEGQUALITY 65537 /* Compression quality level */
+/* Note: quality level is on the IJG 0-100 scale. Default value is 75 */
+#define TIFFTAG_JPEGCOLORMODE 65538 /* Auto RGB<=>YCbCr convert? */
+#define JPEGCOLORMODE_RAW 0x0000 /* no conversion (default) */
+#define JPEGCOLORMODE_RGB 0x0001 /* do auto conversion */
+#define TIFFTAG_JPEGTABLESMODE 65539 /* What to put in JPEGTables */
+#define JPEGTABLESMODE_QUANT 0x0001 /* include quantization tbls */
+#define JPEGTABLESMODE_HUFF 0x0002 /* include Huffman tbls */
+/* Note: default is JPEGTABLESMODE_QUANT | JPEGTABLESMODE_HUFF */
+#define TIFFTAG_FAXFILLFUNC 65540 /* G3/G4 fill function */
+#define TIFFTAG_PIXARLOGDATAFMT 65549 /* PixarLogCodec I/O data sz */
+#define PIXARLOGDATAFMT_8BIT 0 /* regular u_char samples */
+#define PIXARLOGDATAFMT_8BITABGR 1 /* ABGR-order u_chars */
+#define PIXARLOGDATAFMT_11BITLOG 2 /* 11-bit log-encoded (raw) */
+#define PIXARLOGDATAFMT_12BITPICIO 3 /* as per PICIO (1.0==2048) */
+#define PIXARLOGDATAFMT_16BIT 4 /* signed short samples */
+#define PIXARLOGDATAFMT_FLOAT 5 /* IEEE float samples */
+/* 65550-65556 are allocated to Oceana Matrix <dev@oceana.com> */
+#define TIFFTAG_DCSIMAGERTYPE 65550 /* imager model & filter */
+#define DCSIMAGERMODEL_M3 0 /* M3 chip (1280 x 1024) */
+#define DCSIMAGERMODEL_M5 1 /* M5 chip (1536 x 1024) */
+#define DCSIMAGERMODEL_M6 2 /* M6 chip (3072 x 2048) */
+#define DCSIMAGERFILTER_IR 0 /* infrared filter */
+#define DCSIMAGERFILTER_MONO 1 /* monochrome filter */
+#define DCSIMAGERFILTER_CFA 2 /* color filter array */
+#define DCSIMAGERFILTER_OTHER 3 /* other filter */
+#define TIFFTAG_DCSINTERPMODE 65551 /* interpolation mode */
+#define DCSINTERPMODE_NORMAL 0x0 /* whole image, default */
+#define DCSINTERPMODE_PREVIEW 0x1 /* preview of image (384x256) */
+#define TIFFTAG_DCSBALANCEARRAY 65552 /* color balance values */
+#define TIFFTAG_DCSCORRECTMATRIX 65553 /* color correction values */
+#define TIFFTAG_DCSGAMMA 65554 /* gamma value */
+#define TIFFTAG_DCSTOESHOULDERPTS 65555 /* toe & shoulder points */
+#define TIFFTAG_DCSCALIBRATIONFD 65556 /* calibration file desc */
+/* Note: quality level is on the ZLIB 1-9 scale. Default value is -1 */
+#define TIFFTAG_ZIPQUALITY 65557 /* compression quality level */
+#define TIFFTAG_PIXARLOGQUALITY 65558 /* PixarLog uses same scale */
+/* 65559 is allocated to Oceana Matrix <dev@oceana.com> */
+#define TIFFTAG_DCSCLIPRECTANGLE 65559 /* area of image to acquire */
+#define TIFFTAG_SGILOGDATAFMT 65560 /* SGILog user data format */
+#define SGILOGDATAFMT_FLOAT 0 /* IEEE float samples */
+#define SGILOGDATAFMT_16BIT 1 /* 16-bit samples */
+#define SGILOGDATAFMT_RAW 2 /* uninterpreted data */
+#define SGILOGDATAFMT_8BIT 3 /* 8-bit RGB monitor values */
+#define TIFFTAG_SGILOGENCODE 65561 /* SGILog data encoding control*/
+#define SGILOGENCODE_NODITHER 0 /* do not dither encoded values*/
+#define SGILOGENCODE_RANDITHER 1 /* randomly dither encd values */
+
+/*
+ * EXIF tags
+ */
+#define EXIFTAG_EXPOSURETIME 33434 /* Exposure time */
+#define EXIFTAG_FNUMBER 33437 /* F number */
+#define EXIFTAG_EXPOSUREPROGRAM 34850 /* Exposure program */
+#define EXIFTAG_SPECTRALSENSITIVITY 34852 /* Spectral sensitivity */
+#define EXIFTAG_ISOSPEEDRATINGS 34855 /* ISO speed rating */
+#define EXIFTAG_OECF 34856 /* Optoelectric conversion
+ factor */
+#define EXIFTAG_EXIFVERSION 36864 /* Exif version */
+#define EXIFTAG_DATETIMEORIGINAL 36867 /* Date and time of original
+ data generation */
+#define EXIFTAG_DATETIMEDIGITIZED 36868 /* Date and time of digital
+ data generation */
+#define EXIFTAG_COMPONENTSCONFIGURATION 37121 /* Meaning of each component */
+#define EXIFTAG_COMPRESSEDBITSPERPIXEL 37122 /* Image compression mode */
+#define EXIFTAG_SHUTTERSPEEDVALUE 37377 /* Shutter speed */
+#define EXIFTAG_APERTUREVALUE 37378 /* Aperture */
+#define EXIFTAG_BRIGHTNESSVALUE 37379 /* Brightness */
+#define EXIFTAG_EXPOSUREBIASVALUE 37380 /* Exposure bias */
+#define EXIFTAG_MAXAPERTUREVALUE 37381 /* Maximum lens aperture */
+#define EXIFTAG_SUBJECTDISTANCE 37382 /* Subject distance */
+#define EXIFTAG_METERINGMODE 37383 /* Metering mode */
+#define EXIFTAG_LIGHTSOURCE 37384 /* Light source */
+#define EXIFTAG_FLASH 37385 /* Flash */
+#define EXIFTAG_FOCALLENGTH 37386 /* Lens focal length */
+#define EXIFTAG_SUBJECTAREA 37396 /* Subject area */
+#define EXIFTAG_MAKERNOTE 37500 /* Manufacturer notes */
+#define EXIFTAG_USERCOMMENT 37510 /* User comments */
+#define EXIFTAG_SUBSECTIME 37520 /* DateTime subseconds */
+#define EXIFTAG_SUBSECTIMEORIGINAL 37521 /* DateTimeOriginal subseconds */
+#define EXIFTAG_SUBSECTIMEDIGITIZED 37522 /* DateTimeDigitized subseconds */
+#define EXIFTAG_FLASHPIXVERSION 40960 /* Supported Flashpix version */
+#define EXIFTAG_COLORSPACE 40961 /* Color space information */
+#define EXIFTAG_PIXELXDIMENSION 40962 /* Valid image width */
+#define EXIFTAG_PIXELYDIMENSION 40963 /* Valid image height */
+#define EXIFTAG_RELATEDSOUNDFILE 40964 /* Related audio file */
+#define EXIFTAG_FLASHENERGY 41483 /* Flash energy */
+#define EXIFTAG_SPATIALFREQUENCYRESPONSE 41484 /* Spatial frequency response */
+#define EXIFTAG_FOCALPLANEXRESOLUTION 41486 /* Focal plane X resolution */
+#define EXIFTAG_FOCALPLANEYRESOLUTION 41487 /* Focal plane Y resolution */
+#define EXIFTAG_FOCALPLANERESOLUTIONUNIT 41488 /* Focal plane resolution unit */
+#define EXIFTAG_SUBJECTLOCATION 41492 /* Subject location */
+#define EXIFTAG_EXPOSUREINDEX 41493 /* Exposure index */
+#define EXIFTAG_SENSINGMETHOD 41495 /* Sensing method */
+#define EXIFTAG_FILESOURCE 41728 /* File source */
+#define EXIFTAG_SCENETYPE 41729 /* Scene type */
+#define EXIFTAG_CFAPATTERN 41730 /* CFA pattern */
+#define EXIFTAG_CUSTOMRENDERED 41985 /* Custom image processing */
+#define EXIFTAG_EXPOSUREMODE 41986 /* Exposure mode */
+#define EXIFTAG_WHITEBALANCE 41987 /* White balance */
+#define EXIFTAG_DIGITALZOOMRATIO 41988 /* Digital zoom ratio */
+#define EXIFTAG_FOCALLENGTHIN35MMFILM 41989 /* Focal length in 35 mm film */
+#define EXIFTAG_SCENECAPTURETYPE 41990 /* Scene capture type */
+#define EXIFTAG_GAINCONTROL 41991 /* Gain control */
+#define EXIFTAG_CONTRAST 41992 /* Contrast */
+#define EXIFTAG_SATURATION 41993 /* Saturation */
+#define EXIFTAG_SHARPNESS 41994 /* Sharpness */
+#define EXIFTAG_DEVICESETTINGDESCRIPTION 41995 /* Device settings description */
+#define EXIFTAG_SUBJECTDISTANCERANGE 41996 /* Subject distance range */
+#define EXIFTAG_GAINCONTROL 41991 /* Gain control */
+#define EXIFTAG_GAINCONTROL 41991 /* Gain control */
+#define EXIFTAG_IMAGEUNIQUEID 42016 /* Unique image ID */
+
+#endif /* _TIFF_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tiffconf.h.in b/tiff/libtiff/tiffconf.h.in
new file mode 100644
index 0000000..1a52b37
--- /dev/null
+++ b/tiff/libtiff/tiffconf.h.in
@@ -0,0 +1,103 @@
+/*
+ Configuration defines for installed libtiff.
+ This file maintained for backward compatibility. Do not use definitions
+ from this file in your programs.
+*/
+
+#ifndef _TIFFCONF_
+#define _TIFFCONF_
+
+/* Define to 1 if the system has the type `int16'. */
+#undef HAVE_INT16
+
+/* Define to 1 if the system has the type `int32'. */
+#undef HAVE_INT32
+
+/* Define to 1 if the system has the type `int8'. */
+#undef HAVE_INT8
+
+/* The size of a `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of a `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* Compatibility stuff. */
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+#undef HAVE_IEEEFP
+
+/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
+#undef HOST_FILLORDER
+
+/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
+ (Intel) */
+#undef HOST_BIGENDIAN
+
+/* Support CCITT Group 3 & 4 algorithms */
+#undef CCITT_SUPPORT
+
+/* Support JPEG compression (requires IJG JPEG library) */
+#undef JPEG_SUPPORT
+
+/* Support JBIG compression (requires JBIG-KIT library) */
+#undef JBIG_SUPPORT
+
+/* Support LogLuv high dynamic range encoding */
+#undef LOGLUV_SUPPORT
+
+/* Support LZW algorithm */
+#undef LZW_SUPPORT
+
+/* Support NeXT 2-bit RLE algorithm */
+#undef NEXT_SUPPORT
+
+/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation
+ fails with unpatched IJG JPEG library) */
+#undef OJPEG_SUPPORT
+
+/* Support Macintosh PackBits algorithm */
+#undef PACKBITS_SUPPORT
+
+/* Support Pixar log-format algorithm (requires Zlib) */
+#undef PIXARLOG_SUPPORT
+
+/* Support ThunderScan 4-bit RLE algorithm */
+#undef THUNDER_SUPPORT
+
+/* Support Deflate compression */
+#undef ZIP_SUPPORT
+
+/* Support strip chopping (whether or not to convert single-strip uncompressed
+ images to mutiple strips of ~8Kb to reduce memory usage) */
+#undef STRIPCHOP_DEFAULT
+
+/* Enable SubIFD tag (330) support */
+#undef SUBIFD_SUPPORT
+
+/* Treat extra sample as alpha (default enabled). The RGBA interface will
+ treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+ packages produce RGBA files but don't mark the alpha properly. */
+#undef DEFAULT_EXTRASAMPLE_AS_ALPHA
+
+/* Pick up YCbCr subsampling info from the JPEG data stream to support files
+ lacking the tag (default enabled). */
+#undef CHECK_JPEG_YCBCR_SUBSAMPLING
+
+/* Support MS MDI magic number files as TIFF */
+#undef MDI_SUPPORT
+
+/*
+ * Feature support definitions.
+ * XXX: These macros are obsoleted. Don't use them in your apps!
+ * Macros stays here for backward compatibility and should be always defined.
+ */
+#define COLORIMETRY_SUPPORT
+#define YCBCR_SUPPORT
+#define CMYK_SUPPORT
+#define ICC_SUPPORT
+#define PHOTOSHOP_SUPPORT
+#define IPTC_SUPPORT
+
+#endif /* _TIFFCONF_ */
diff --git a/tiff/libtiff/tiffconf.vc.h b/tiff/libtiff/tiffconf.vc.h
new file mode 100644
index 0000000..47a9488
--- /dev/null
+++ b/tiff/libtiff/tiffconf.vc.h
@@ -0,0 +1,116 @@
+/*
+ Configuration defines for installed libtiff.
+ This file maintained for backward compatibility. Do not use definitions
+ from this file in your programs.
+*/
+
+#ifndef _TIFFCONF_
+#define _TIFFCONF_
+
+/* Define to 1 if the system has the type `int16'. */
+/* #undef HAVE_INT16 */
+
+/* Define to 1 if the system has the type `int32'. */
+/* #undef HAVE_INT32 */
+
+/* Define to 1 if the system has the type `int8'. */
+/* #undef HAVE_INT8 */
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* Signed 64-bit type formatter */
+#define TIFF_INT64_FORMAT "%I64d"
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed __int64
+
+/* Unsigned 64-bit type formatter */
+#define TIFF_UINT64_FORMAT "%I64u"
+
+/* Unsigned 64-bit type */
+#define TIFF_UINT64_T unsigned __int64
+
+/* Compatibility stuff. */
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+#define HAVE_IEEEFP 1
+
+/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
+ (Intel) */
+#define HOST_BIGENDIAN 0
+
+/* Support CCITT Group 3 & 4 algorithms */
+#define CCITT_SUPPORT 1
+
+/* Support JPEG compression (requires IJG JPEG library) */
+#define JPEG_SUPPORT
+
+/* Support LogLuv high dynamic range encoding */
+#define LOGLUV_SUPPORT 1
+
+/* Support LZW algorithm */
+#define LZW_SUPPORT 1
+
+/* Support NeXT 2-bit RLE algorithm */
+#define NEXT_SUPPORT 1
+
+/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation
+ fails with unpatched IJG JPEG library) */
+/* #undef OJPEG_SUPPORT */
+
+/* Support Macintosh PackBits algorithm */
+#define PACKBITS_SUPPORT 1
+
+/* Support Pixar log-format algorithm (requires Zlib) */
+/* #undef PIXARLOG_SUPPORT */
+
+/* Support ThunderScan 4-bit RLE algorithm */
+#define THUNDER_SUPPORT 1
+
+/* Support Deflate compression */
+/* #undef ZIP_SUPPORT */
+
+/* Support strip chopping (whether or not to convert single-strip uncompressed
+ images to mutiple strips of ~8Kb to reduce memory usage) */
+#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP
+
+/* Enable SubIFD tag (330) support */
+#define SUBIFD_SUPPORT 1
+
+/* Treat extra sample as alpha (default enabled). The RGBA interface will
+ treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+ packages produce RGBA files but don't mark the alpha properly. */
+#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1
+
+/* Pick up YCbCr subsampling info from the JPEG data stream to support files
+ lacking the tag (default enabled). */
+#define CHECK_JPEG_YCBCR_SUBSAMPLING 1
+
+/*
+ * Feature support definitions.
+ * XXX: These macros are obsoleted. Don't use them in your apps!
+ * Macros stays here for backward compatibility and should be always defined.
+ */
+#define COLORIMETRY_SUPPORT
+#define YCBCR_SUPPORT
+#define CMYK_SUPPORT
+#define ICC_SUPPORT
+#define PHOTOSHOP_SUPPORT
+#define IPTC_SUPPORT
+
+#endif /* _TIFFCONF_ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tiffconf.wince.h b/tiff/libtiff/tiffconf.wince.h
new file mode 100644
index 0000000..68ab31e
--- /dev/null
+++ b/tiff/libtiff/tiffconf.wince.h
@@ -0,0 +1,136 @@
+/* $Id: tiffconf.wince.h,v 1.1.2.2 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Windows CE platform tiffconf.wince.h
+ * Created by Mateusz Loskot (mateusz@loskot.net)
+ *
+ * NOTE: Requires WCELIBCEX library with wceex_* functions,
+ * It's an extension to C library on Windows CE platform.
+ * For example, HAVE_STDIO_H definition indicates there are
+ * following files available:
+ * stdio.h - from Windows CE / Windows Mobile SDK
+ * wce_stdio.h - from WCELIBCEX library
+ */
+
+
+/*
+ Configuration defines for installed libtiff.
+ This file maintained for backward compatibility. Do not use definitions
+ from this file in your programs.
+*/
+
+#ifndef _WIN32_WCE
+# error This version of tif_config.h header is dedicated for Windows CE platform!
+#endif
+
+
+#ifndef _TIFFCONF_
+#define _TIFFCONF_
+
+/* Define to 1 if the system has the type `int16'. */
+/* #undef HAVE_INT16 */
+
+/* Define to 1 if the system has the type `int32'. */
+/* #undef HAVE_INT32 */
+
+/* Define to 1 if the system has the type `int8'. */
+/* #undef HAVE_INT8 */
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* Signed 64-bit type formatter */
+#define TIFF_INT64_FORMAT "%I64d"
+
+/* Signed 64-bit type */
+#define TIFF_INT64_T signed __int64
+
+/* Unsigned 64-bit type formatter */
+#define TIFF_UINT64_FORMAT "%I64u"
+
+/* Unsigned 64-bit type */
+#define TIFF_UINT64_T unsigned __int64
+
+/* Compatibility stuff. */
+
+/* Define as 0 or 1 according to the floating point format suported by the
+ machine */
+#define HAVE_IEEEFP 1
+
+/* Set the native cpu bit order (FILLORDER_LSB2MSB or FILLORDER_MSB2LSB) */
+#define HOST_FILLORDER FILLORDER_LSB2MSB
+
+/* Native cpu byte order: 1 if big-endian (Motorola) or 0 if little-endian
+ (Intel) */
+#define HOST_BIGENDIAN 0
+
+/* Support CCITT Group 3 & 4 algorithms */
+#define CCITT_SUPPORT 1
+
+/* Support JPEG compression (requires IJG JPEG library) */
+/* #undef JPEG_SUPPORT */
+
+/* Support LogLuv high dynamic range encoding */
+#define LOGLUV_SUPPORT 1
+
+/* Support LZW algorithm */
+#define LZW_SUPPORT 1
+
+/* Support NeXT 2-bit RLE algorithm */
+#define NEXT_SUPPORT 1
+
+/* Support Old JPEG compresson (read contrib/ojpeg/README first! Compilation
+ fails with unpatched IJG JPEG library) */
+/* #undef OJPEG_SUPPORT */
+
+/* Support Macintosh PackBits algorithm */
+#define PACKBITS_SUPPORT 1
+
+/* Support Pixar log-format algorithm (requires Zlib) */
+/* #undef PIXARLOG_SUPPORT */
+
+/* Support ThunderScan 4-bit RLE algorithm */
+#define THUNDER_SUPPORT 1
+
+/* Support Deflate compression */
+/* #undef ZIP_SUPPORT */
+
+/* Support strip chopping (whether or not to convert single-strip uncompressed
+ images to mutiple strips of ~8Kb to reduce memory usage) */
+#define STRIPCHOP_DEFAULT TIFF_STRIPCHOP
+
+/* Enable SubIFD tag (330) support */
+#define SUBIFD_SUPPORT 1
+
+/* Treat extra sample as alpha (default enabled). The RGBA interface will
+ treat a fourth sample with no EXTRASAMPLE_ value as being ASSOCALPHA. Many
+ packages produce RGBA files but don't mark the alpha properly. */
+#define DEFAULT_EXTRASAMPLE_AS_ALPHA 1
+
+/* Pick up YCbCr subsampling info from the JPEG data stream to support files
+ lacking the tag (default enabled). */
+#define CHECK_JPEG_YCBCR_SUBSAMPLING 1
+
+/*
+ * Feature support definitions.
+ * XXX: These macros are obsoleted. Don't use them in your apps!
+ * Macros stays here for backward compatibility and should be always defined.
+ */
+#define COLORIMETRY_SUPPORT
+#define YCBCR_SUPPORT
+#define CMYK_SUPPORT
+#define ICC_SUPPORT
+#define PHOTOSHOP_SUPPORT
+#define IPTC_SUPPORT
+
+#endif /* _TIFFCONF_ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tiffio.h b/tiff/libtiff/tiffio.h
new file mode 100644
index 0000000..06ec25c
--- /dev/null
+++ b/tiff/libtiff/tiffio.h
@@ -0,0 +1,526 @@
+/* $Id: tiffio.h,v 1.56.2.4 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFIO_
+#define _TIFFIO_
+
+/*
+ * TIFF I/O Library Definitions.
+ */
+#include "tiff.h"
+#include "tiffvers.h"
+
+/*
+ * TIFF is defined as an incomplete type to hide the
+ * library's internal data structures from clients.
+ */
+typedef struct tiff TIFF;
+
+/*
+ * The following typedefs define the intrinsic size of
+ * data types used in the *exported* interfaces. These
+ * definitions depend on the proper definition of types
+ * in tiff.h. Note also that the varargs interface used
+ * to pass tag types and values uses the types defined in
+ * tiff.h directly.
+ *
+ * NB: ttag_t is unsigned int and not unsigned short because
+ * ANSI C requires that the type before the ellipsis be a
+ * promoted type (i.e. one of int, unsigned int, pointer,
+ * or double) and because we defined pseudo-tags that are
+ * outside the range of legal Aldus-assigned tags.
+ * NB: tsize_t is int32 and not uint32 because some functions
+ * return -1.
+ * NB: toff_t is not off_t for many reasons; TIFFs max out at
+ * 32-bit file offsets being the most important, and to ensure
+ * that it is unsigned, rather than signed.
+ */
+typedef uint32 ttag_t; /* directory tag */
+typedef uint16 tdir_t; /* directory index */
+typedef uint16 tsample_t; /* sample number */
+typedef uint32 tstrile_t; /* strip or tile number */
+typedef tstrile_t tstrip_t; /* strip number */
+typedef tstrile_t ttile_t; /* tile number */
+typedef int32 tsize_t; /* i/o size in bytes */
+typedef void* tdata_t; /* image data ref */
+typedef uint32 toff_t; /* file offset */
+
+#if !defined(__WIN32__) && (defined(_WIN32) || defined(WIN32))
+#define __WIN32__
+#endif
+
+/*
+ * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c
+ * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c).
+ *
+ * By default tif_unix.c is assumed.
+ */
+
+#if defined(_WINDOWS) || defined(__WIN32__) || defined(_Windows)
+# if !defined(__CYGWIN) && !defined(AVOID_WIN32_FILEIO) && !defined(USE_WIN32_FILEIO)
+# define AVOID_WIN32_FILEIO
+# endif
+#endif
+
+#if defined(USE_WIN32_FILEIO)
+# define VC_EXTRALEAN
+# include <windows.h>
+# ifdef __WIN32__
+DECLARE_HANDLE(thandle_t); /* Win32 file handle */
+# else
+typedef HFILE thandle_t; /* client data handle */
+# endif /* __WIN32__ */
+#else
+typedef void* thandle_t; /* client data handle */
+#endif /* USE_WIN32_FILEIO */
+
+/*
+ * Flags to pass to TIFFPrintDirectory to control
+ * printing of data structures that are potentially
+ * very large. Bit-or these flags to enable printing
+ * multiple items.
+ */
+#define TIFFPRINT_NONE 0x0 /* no extra info */
+#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */
+#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */
+#define TIFFPRINT_COLORMAP 0x4 /* colormap */
+#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */
+#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */
+#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */
+
+/*
+ * Colour conversion stuff
+ */
+
+/* reference white */
+#define D65_X0 (95.0470F)
+#define D65_Y0 (100.0F)
+#define D65_Z0 (108.8827F)
+
+#define D50_X0 (96.4250F)
+#define D50_Y0 (100.0F)
+#define D50_Z0 (82.4680F)
+
+/* Structure for holding information about a display device. */
+
+typedef unsigned char TIFFRGBValue; /* 8-bit samples */
+
+typedef struct {
+ float d_mat[3][3]; /* XYZ -> luminance matrix */
+ float d_YCR; /* Light o/p for reference white */
+ float d_YCG;
+ float d_YCB;
+ uint32 d_Vrwr; /* Pixel values for ref. white */
+ uint32 d_Vrwg;
+ uint32 d_Vrwb;
+ float d_Y0R; /* Residual light for black pixel */
+ float d_Y0G;
+ float d_Y0B;
+ float d_gammaR; /* Gamma values for the three guns */
+ float d_gammaG;
+ float d_gammaB;
+} TIFFDisplay;
+
+typedef struct { /* YCbCr->RGB support */
+ TIFFRGBValue* clamptab; /* range clamping table */
+ int* Cr_r_tab;
+ int* Cb_b_tab;
+ int32* Cr_g_tab;
+ int32* Cb_g_tab;
+ int32* Y_tab;
+} TIFFYCbCrToRGB;
+
+typedef struct { /* CIE Lab 1976->RGB support */
+ int range; /* Size of conversion table */
+#define CIELABTORGB_TABLE_RANGE 1500
+ float rstep, gstep, bstep;
+ float X0, Y0, Z0; /* Reference white point */
+ TIFFDisplay display;
+ float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */
+ float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */
+ float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */
+} TIFFCIELabToRGB;
+
+/*
+ * RGBA-style image support.
+ */
+typedef struct _TIFFRGBAImage TIFFRGBAImage;
+/*
+ * The image reading and conversion routines invoke
+ * ``put routines'' to copy/image/whatever tiles of
+ * raw image data. A default set of routines are
+ * provided to convert/copy raw image data to 8-bit
+ * packed ABGR format rasters. Applications can supply
+ * alternate routines that unpack the data into a
+ * different format or, for example, unpack the data
+ * and draw the unpacked raster on the display.
+ */
+typedef void (*tileContigRoutine)
+ (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32,
+ unsigned char*);
+typedef void (*tileSeparateRoutine)
+ (TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32,
+ unsigned char*, unsigned char*, unsigned char*, unsigned char*);
+/*
+ * RGBA-reader state.
+ */
+struct _TIFFRGBAImage {
+ TIFF* tif; /* image handle */
+ int stoponerr; /* stop on read error */
+ int isContig; /* data is packed/separate */
+ int alpha; /* type of alpha data present */
+ uint32 width; /* image width */
+ uint32 height; /* image height */
+ uint16 bitspersample; /* image bits/sample */
+ uint16 samplesperpixel; /* image samples/pixel */
+ uint16 orientation; /* image orientation */
+ uint16 req_orientation; /* requested orientation */
+ uint16 photometric; /* image photometric interp */
+ uint16* redcmap; /* colormap pallete */
+ uint16* greencmap;
+ uint16* bluecmap;
+ /* get image data routine */
+ int (*get)(TIFFRGBAImage*, uint32*, uint32, uint32);
+ /* put decoded strip/tile */
+ union {
+ void (*any)(TIFFRGBAImage*);
+ tileContigRoutine contig;
+ tileSeparateRoutine separate;
+ } put;
+ TIFFRGBValue* Map; /* sample mapping array */
+ uint32** BWmap; /* black&white map */
+ uint32** PALmap; /* palette image map */
+ TIFFYCbCrToRGB* ycbcr; /* YCbCr conversion state */
+ TIFFCIELabToRGB* cielab; /* CIE L*a*b conversion state */
+
+ int row_offset;
+ int col_offset;
+};
+
+/*
+ * Macros for extracting components from the
+ * packed ABGR form returned by TIFFReadRGBAImage.
+ */
+#define TIFFGetR(abgr) ((abgr) & 0xff)
+#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff)
+#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff)
+#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff)
+
+/*
+ * A CODEC is a software package that implements decoding,
+ * encoding, or decoding+encoding of a compression algorithm.
+ * The library provides a collection of builtin codecs.
+ * More codecs may be registered through calls to the library
+ * and/or the builtin implementations may be overridden.
+ */
+typedef int (*TIFFInitMethod)(TIFF*, int);
+typedef struct {
+ char* name;
+ uint16 scheme;
+ TIFFInitMethod init;
+} TIFFCodec;
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* share internal LogLuv conversion routines? */
+#ifndef LOGLUV_PUBLIC
+#define LOGLUV_PUBLIC 1
+#endif
+
+#if !defined(__GNUC__) && !defined(__attribute__)
+# define __attribute__(x) /*nothing*/
+#endif
+
+#if defined(c_plusplus) || defined(__cplusplus)
+extern "C" {
+#endif
+typedef void (*TIFFErrorHandler)(const char*, const char*, va_list);
+typedef void (*TIFFErrorHandlerExt)(thandle_t, const char*, const char*, va_list);
+typedef tsize_t (*TIFFReadWriteProc)(thandle_t, tdata_t, tsize_t);
+typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int);
+typedef int (*TIFFCloseProc)(thandle_t);
+typedef toff_t (*TIFFSizeProc)(thandle_t);
+typedef int (*TIFFMapFileProc)(thandle_t, tdata_t*, toff_t*);
+typedef void (*TIFFUnmapFileProc)(thandle_t, tdata_t, toff_t);
+typedef void (*TIFFExtendProc)(TIFF*);
+
+extern const char* TIFFGetVersion(void);
+
+extern const TIFFCodec* TIFFFindCODEC(uint16);
+extern TIFFCodec* TIFFRegisterCODEC(uint16, const char*, TIFFInitMethod);
+extern void TIFFUnRegisterCODEC(TIFFCodec*);
+extern int TIFFIsCODECConfigured(uint16);
+extern TIFFCodec* TIFFGetConfiguredCODECs(void);
+
+/*
+ * Auxiliary functions.
+ */
+
+extern tdata_t _TIFFmalloc(tsize_t);
+extern tdata_t _TIFFrealloc(tdata_t, tsize_t);
+extern void _TIFFmemset(tdata_t, int, tsize_t);
+extern void _TIFFmemcpy(tdata_t, const tdata_t, tsize_t);
+extern int _TIFFmemcmp(const tdata_t, const tdata_t, tsize_t);
+extern void _TIFFfree(tdata_t);
+
+/*
+** Stuff, related to tag handling and creating custom tags.
+*/
+extern int TIFFGetTagListCount( TIFF * );
+extern ttag_t TIFFGetTagListEntry( TIFF *, int tag_index );
+
+#define TIFF_ANY TIFF_NOTYPE /* for field descriptor searching */
+#define TIFF_VARIABLE -1 /* marker for variable length tags */
+#define TIFF_SPP -2 /* marker for SamplesPerPixel tags */
+#define TIFF_VARIABLE2 -3 /* marker for uint32 var-length tags */
+
+#define FIELD_CUSTOM 65
+
+typedef struct {
+ ttag_t field_tag; /* field's tag */
+ short field_readcount; /* read count/TIFF_VARIABLE/TIFF_SPP */
+ short field_writecount; /* write count/TIFF_VARIABLE */
+ TIFFDataType field_type; /* type of associated data */
+ unsigned short field_bit; /* bit in fieldsset bit vector */
+ unsigned char field_oktochange; /* if true, can change while writing */
+ unsigned char field_passcount; /* if true, pass dir count on set */
+ char *field_name; /* ASCII name */
+} TIFFFieldInfo;
+
+typedef struct _TIFFTagValue {
+ const TIFFFieldInfo *info;
+ int count;
+ void *value;
+} TIFFTagValue;
+
+extern void TIFFMergeFieldInfo(TIFF*, const TIFFFieldInfo[], int);
+extern const TIFFFieldInfo* TIFFFindFieldInfo(TIFF*, ttag_t, TIFFDataType);
+extern const TIFFFieldInfo* TIFFFindFieldInfoByName(TIFF* , const char *,
+ TIFFDataType);
+extern const TIFFFieldInfo* TIFFFieldWithTag(TIFF*, ttag_t);
+extern const TIFFFieldInfo* TIFFFieldWithName(TIFF*, const char *);
+
+typedef int (*TIFFVSetMethod)(TIFF*, ttag_t, va_list);
+typedef int (*TIFFVGetMethod)(TIFF*, ttag_t, va_list);
+typedef void (*TIFFPrintMethod)(TIFF*, FILE*, long);
+
+typedef struct {
+ TIFFVSetMethod vsetfield; /* tag set routine */
+ TIFFVGetMethod vgetfield; /* tag get routine */
+ TIFFPrintMethod printdir; /* directory print routine */
+} TIFFTagMethods;
+
+extern TIFFTagMethods *TIFFAccessTagMethods( TIFF * );
+extern void *TIFFGetClientInfo( TIFF *, const char * );
+extern void TIFFSetClientInfo( TIFF *, void *, const char * );
+
+extern void TIFFCleanup(TIFF*);
+extern void TIFFClose(TIFF*);
+extern int TIFFFlush(TIFF*);
+extern int TIFFFlushData(TIFF*);
+extern int TIFFGetField(TIFF*, ttag_t, ...);
+extern int TIFFVGetField(TIFF*, ttag_t, va_list);
+extern int TIFFGetFieldDefaulted(TIFF*, ttag_t, ...);
+extern int TIFFVGetFieldDefaulted(TIFF*, ttag_t, va_list);
+extern int TIFFReadDirectory(TIFF*);
+extern int TIFFReadCustomDirectory(TIFF*, toff_t, const TIFFFieldInfo[],
+ size_t);
+extern int TIFFReadEXIFDirectory(TIFF*, toff_t);
+extern tsize_t TIFFScanlineSize(TIFF*);
+extern tsize_t TIFFOldScanlineSize(TIFF*);
+extern tsize_t TIFFNewScanlineSize(TIFF*);
+extern tsize_t TIFFRasterScanlineSize(TIFF*);
+extern tsize_t TIFFStripSize(TIFF*);
+extern tsize_t TIFFRawStripSize(TIFF*, tstrip_t);
+extern tsize_t TIFFVStripSize(TIFF*, uint32);
+extern tsize_t TIFFTileRowSize(TIFF*);
+extern tsize_t TIFFTileSize(TIFF*);
+extern tsize_t TIFFVTileSize(TIFF*, uint32);
+extern uint32 TIFFDefaultStripSize(TIFF*, uint32);
+extern void TIFFDefaultTileSize(TIFF*, uint32*, uint32*);
+extern int TIFFFileno(TIFF*);
+extern int TIFFSetFileno(TIFF*, int);
+extern thandle_t TIFFClientdata(TIFF*);
+extern thandle_t TIFFSetClientdata(TIFF*, thandle_t);
+extern int TIFFGetMode(TIFF*);
+extern int TIFFSetMode(TIFF*, int);
+extern int TIFFIsTiled(TIFF*);
+extern int TIFFIsByteSwapped(TIFF*);
+extern int TIFFIsUpSampled(TIFF*);
+extern int TIFFIsMSB2LSB(TIFF*);
+extern int TIFFIsBigEndian(TIFF*);
+extern TIFFReadWriteProc TIFFGetReadProc(TIFF*);
+extern TIFFReadWriteProc TIFFGetWriteProc(TIFF*);
+extern TIFFSeekProc TIFFGetSeekProc(TIFF*);
+extern TIFFCloseProc TIFFGetCloseProc(TIFF*);
+extern TIFFSizeProc TIFFGetSizeProc(TIFF*);
+extern TIFFMapFileProc TIFFGetMapFileProc(TIFF*);
+extern TIFFUnmapFileProc TIFFGetUnmapFileProc(TIFF*);
+extern uint32 TIFFCurrentRow(TIFF*);
+extern tdir_t TIFFCurrentDirectory(TIFF*);
+extern tdir_t TIFFNumberOfDirectories(TIFF*);
+extern uint32 TIFFCurrentDirOffset(TIFF*);
+extern tstrip_t TIFFCurrentStrip(TIFF*);
+extern ttile_t TIFFCurrentTile(TIFF*);
+extern int TIFFReadBufferSetup(TIFF*, tdata_t, tsize_t);
+extern int TIFFWriteBufferSetup(TIFF*, tdata_t, tsize_t);
+extern int TIFFSetupStrips(TIFF *);
+extern int TIFFWriteCheck(TIFF*, int, const char *);
+extern void TIFFFreeDirectory(TIFF*);
+extern int TIFFCreateDirectory(TIFF*);
+extern int TIFFLastDirectory(TIFF*);
+extern int TIFFSetDirectory(TIFF*, tdir_t);
+extern int TIFFSetSubDirectory(TIFF*, uint32);
+extern int TIFFUnlinkDirectory(TIFF*, tdir_t);
+extern int TIFFSetField(TIFF*, ttag_t, ...);
+extern int TIFFVSetField(TIFF*, ttag_t, va_list);
+extern int TIFFWriteDirectory(TIFF *);
+extern int TIFFCheckpointDirectory(TIFF *);
+extern int TIFFRewriteDirectory(TIFF *);
+extern int TIFFReassignTagToIgnore(enum TIFFIgnoreSense, int);
+
+#if defined(c_plusplus) || defined(__cplusplus)
+extern void TIFFPrintDirectory(TIFF*, FILE*, long = 0);
+extern int TIFFReadScanline(TIFF*, tdata_t, uint32, tsample_t = 0);
+extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t = 0);
+extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int = 0);
+extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*,
+ int = ORIENTATION_BOTLEFT, int = 0);
+#else
+extern void TIFFPrintDirectory(TIFF*, FILE*, long);
+extern int TIFFReadScanline(TIFF*, tdata_t, uint32, tsample_t);
+extern int TIFFWriteScanline(TIFF*, tdata_t, uint32, tsample_t);
+extern int TIFFReadRGBAImage(TIFF*, uint32, uint32, uint32*, int);
+extern int TIFFReadRGBAImageOriented(TIFF*, uint32, uint32, uint32*, int, int);
+#endif
+
+extern int TIFFReadRGBAStrip(TIFF*, tstrip_t, uint32 * );
+extern int TIFFReadRGBATile(TIFF*, uint32, uint32, uint32 * );
+extern int TIFFRGBAImageOK(TIFF*, char [1024]);
+extern int TIFFRGBAImageBegin(TIFFRGBAImage*, TIFF*, int, char [1024]);
+extern int TIFFRGBAImageGet(TIFFRGBAImage*, uint32*, uint32, uint32);
+extern void TIFFRGBAImageEnd(TIFFRGBAImage*);
+extern TIFF* TIFFOpen(const char*, const char*);
+# ifdef __WIN32__
+extern TIFF* TIFFOpenW(const wchar_t*, const char*);
+# endif /* __WIN32__ */
+extern TIFF* TIFFFdOpen(int, const char*, const char*);
+extern TIFF* TIFFClientOpen(const char*, const char*,
+ thandle_t,
+ TIFFReadWriteProc, TIFFReadWriteProc,
+ TIFFSeekProc, TIFFCloseProc,
+ TIFFSizeProc,
+ TIFFMapFileProc, TIFFUnmapFileProc);
+extern const char* TIFFFileName(TIFF*);
+extern const char* TIFFSetFileName(TIFF*, const char *);
+extern void TIFFError(const char*, const char*, ...) __attribute__((format (printf,2,3)));
+extern void TIFFErrorExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4)));
+extern void TIFFWarning(const char*, const char*, ...) __attribute__((format (printf,2,3)));
+extern void TIFFWarningExt(thandle_t, const char*, const char*, ...) __attribute__((format (printf,3,4)));
+extern TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler);
+extern TIFFErrorHandlerExt TIFFSetErrorHandlerExt(TIFFErrorHandlerExt);
+extern TIFFErrorHandler TIFFSetWarningHandler(TIFFErrorHandler);
+extern TIFFErrorHandlerExt TIFFSetWarningHandlerExt(TIFFErrorHandlerExt);
+extern TIFFExtendProc TIFFSetTagExtender(TIFFExtendProc);
+extern ttile_t TIFFComputeTile(TIFF*, uint32, uint32, uint32, tsample_t);
+extern int TIFFCheckTile(TIFF*, uint32, uint32, uint32, tsample_t);
+extern ttile_t TIFFNumberOfTiles(TIFF*);
+extern tsize_t TIFFReadTile(TIFF*,
+ tdata_t, uint32, uint32, uint32, tsample_t);
+extern tsize_t TIFFWriteTile(TIFF*,
+ tdata_t, uint32, uint32, uint32, tsample_t);
+extern tstrip_t TIFFComputeStrip(TIFF*, uint32, tsample_t);
+extern tstrip_t TIFFNumberOfStrips(TIFF*);
+extern tsize_t TIFFReadEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t);
+extern tsize_t TIFFReadRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t);
+extern tsize_t TIFFReadEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t);
+extern tsize_t TIFFReadRawTile(TIFF*, ttile_t, tdata_t, tsize_t);
+extern tsize_t TIFFWriteEncodedStrip(TIFF*, tstrip_t, tdata_t, tsize_t);
+extern tsize_t TIFFWriteRawStrip(TIFF*, tstrip_t, tdata_t, tsize_t);
+extern tsize_t TIFFWriteEncodedTile(TIFF*, ttile_t, tdata_t, tsize_t);
+extern tsize_t TIFFWriteRawTile(TIFF*, ttile_t, tdata_t, tsize_t);
+extern int TIFFDataWidth(TIFFDataType); /* table of tag datatype widths */
+extern void TIFFSetWriteOffset(TIFF*, toff_t);
+extern void TIFFSwabShort(uint16*);
+extern void TIFFSwabLong(uint32*);
+extern void TIFFSwabDouble(double*);
+extern void TIFFSwabArrayOfShort(uint16*, unsigned long);
+extern void TIFFSwabArrayOfTriples(uint8*, unsigned long);
+extern void TIFFSwabArrayOfLong(uint32*, unsigned long);
+extern void TIFFSwabArrayOfDouble(double*, unsigned long);
+extern void TIFFReverseBits(unsigned char *, unsigned long);
+extern const unsigned char* TIFFGetBitRevTable(int);
+
+#ifdef LOGLUV_PUBLIC
+#define U_NEU 0.210526316
+#define V_NEU 0.473684211
+#define UVSCALE 410.
+extern double LogL16toY(int);
+extern double LogL10toY(int);
+extern void XYZtoRGB24(float*, uint8*);
+extern int uv_decode(double*, double*, int);
+extern void LogLuv24toXYZ(uint32, float*);
+extern void LogLuv32toXYZ(uint32, float*);
+#if defined(c_plusplus) || defined(__cplusplus)
+extern int LogL16fromY(double, int = SGILOGENCODE_NODITHER);
+extern int LogL10fromY(double, int = SGILOGENCODE_NODITHER);
+extern int uv_encode(double, double, int = SGILOGENCODE_NODITHER);
+extern uint32 LogLuv24fromXYZ(float*, int = SGILOGENCODE_NODITHER);
+extern uint32 LogLuv32fromXYZ(float*, int = SGILOGENCODE_NODITHER);
+#else
+extern int LogL16fromY(double, int);
+extern int LogL10fromY(double, int);
+extern int uv_encode(double, double, int);
+extern uint32 LogLuv24fromXYZ(float*, int);
+extern uint32 LogLuv32fromXYZ(float*, int);
+#endif
+#endif /* LOGLUV_PUBLIC */
+
+extern int TIFFCIELabToRGBInit(TIFFCIELabToRGB*, TIFFDisplay *, float*);
+extern void TIFFCIELabToXYZ(TIFFCIELabToRGB *, uint32, int32, int32,
+ float *, float *, float *);
+extern void TIFFXYZToRGB(TIFFCIELabToRGB *, float, float, float,
+ uint32 *, uint32 *, uint32 *);
+
+extern int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB*, float*, float*);
+extern void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *, uint32, int32, int32,
+ uint32 *, uint32 *, uint32 *);
+
+#if defined(c_plusplus) || defined(__cplusplus)
+}
+#endif
+
+#endif /* _TIFFIO_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tiffio.hxx b/tiff/libtiff/tiffio.hxx
new file mode 100644
index 0000000..ee3fd32
--- /dev/null
+++ b/tiff/libtiff/tiffio.hxx
@@ -0,0 +1,49 @@
+/* $Id: tiffio.hxx,v 1.1.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFIO_HXX_
+#define _TIFFIO_HXX_
+
+/*
+ * TIFF I/O library definitions which provide C++ streams API.
+ */
+
+#include <iostream>
+#include "tiff.h"
+
+extern TIFF* TIFFStreamOpen(const char*, std::ostream *);
+extern TIFF* TIFFStreamOpen(const char*, std::istream *);
+
+#endif /* _TIFFIO_HXX_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c++
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tiffiop.h b/tiff/libtiff/tiffiop.h
new file mode 100644
index 0000000..a064039
--- /dev/null
+++ b/tiff/libtiff/tiffiop.h
@@ -0,0 +1,350 @@
+/* $Id: tiffiop.h,v 1.51.2.6 2010-06-12 02:55:16 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _TIFFIOP_
+#define _TIFFIOP_
+/*
+ * ``Library-private'' definitions.
+ */
+
+#include "tif_config.h"
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+#ifdef HAVE_ASSERT_H
+# include <assert.h>
+#else
+# define assert(x)
+#endif
+
+#ifdef HAVE_SEARCH_H
+# include <search.h>
+#else
+extern void *lfind(const void *, const void *, size_t *, size_t,
+ int (*)(const void *, const void *));
+#endif
+
+/*
+ Libtiff itself does not require a 64-bit type, but bundled TIFF
+ utilities may use it.
+*/
+typedef TIFF_INT64_T int64;
+typedef TIFF_UINT64_T uint64;
+
+#include "tiffio.h"
+#include "tif_dir.h"
+
+#ifndef STRIP_SIZE_DEFAULT
+# define STRIP_SIZE_DEFAULT 8192
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+typedef struct client_info {
+ struct client_info *next;
+ void *data;
+ char *name;
+} TIFFClientInfoLink;
+
+/*
+ * Typedefs for ``method pointers'' used internally.
+ */
+typedef unsigned char tidataval_t; /* internal image data value type */
+typedef tidataval_t* tidata_t; /* reference to internal image data */
+
+typedef void (*TIFFVoidMethod)(TIFF*);
+typedef int (*TIFFBoolMethod)(TIFF*);
+typedef int (*TIFFPreMethod)(TIFF*, tsample_t);
+typedef int (*TIFFCodeMethod)(TIFF*, tidata_t, tsize_t, tsample_t);
+typedef int (*TIFFSeekMethod)(TIFF*, uint32);
+typedef void (*TIFFPostMethod)(TIFF*, tidata_t, tsize_t);
+typedef uint32 (*TIFFStripMethod)(TIFF*, uint32);
+typedef void (*TIFFTileMethod)(TIFF*, uint32*, uint32*);
+
+struct tiff {
+ char* tif_name; /* name of open file */
+ int tif_fd; /* open file descriptor */
+ int tif_mode; /* open mode (O_*) */
+ uint32 tif_flags;
+#define TIFF_FILLORDER 0x00003 /* natural bit fill order for machine */
+#define TIFF_DIRTYHEADER 0x00004 /* header must be written on close */
+#define TIFF_DIRTYDIRECT 0x00008 /* current directory must be written */
+#define TIFF_BUFFERSETUP 0x00010 /* data buffers setup */
+#define TIFF_CODERSETUP 0x00020 /* encoder/decoder setup done */
+#define TIFF_BEENWRITING 0x00040 /* written 1+ scanlines to file */
+#define TIFF_SWAB 0x00080 /* byte swap file information */
+#define TIFF_NOBITREV 0x00100 /* inhibit bit reversal logic */
+#define TIFF_MYBUFFER 0x00200 /* my raw data buffer; free on close */
+#define TIFF_ISTILED 0x00400 /* file is tile, not strip- based */
+#define TIFF_MAPPED 0x00800 /* file is mapped into memory */
+#define TIFF_POSTENCODE 0x01000 /* need call to postencode routine */
+#define TIFF_INSUBIFD 0x02000 /* currently writing a subifd */
+#define TIFF_UPSAMPLED 0x04000 /* library is doing data up-sampling */
+#define TIFF_STRIPCHOP 0x08000 /* enable strip chopping support */
+#define TIFF_HEADERONLY 0x10000 /* read header only, do not process */
+ /* the first directory */
+#define TIFF_NOREADRAW 0x20000 /* skip reading of raw uncompressed */
+ /* image data */
+#define TIFF_INCUSTOMIFD 0x40000 /* currently writing a custom IFD */
+ toff_t tif_diroff; /* file offset of current directory */
+ toff_t tif_nextdiroff; /* file offset of following directory */
+ toff_t* tif_dirlist; /* list of offsets to already seen */
+ /* directories to prevent IFD looping */
+ tsize_t tif_dirlistsize;/* number of entires in offset list */
+ uint16 tif_dirnumber; /* number of already seen directories */
+ TIFFDirectory tif_dir; /* internal rep of current directory */
+ TIFFDirectory tif_customdir; /* custom IFDs are separated from
+ the main ones */
+ TIFFHeader tif_header; /* file's header block */
+ const int* tif_typeshift; /* data type shift counts */
+ const long* tif_typemask; /* data type masks */
+ uint32 tif_row; /* current scanline */
+ tdir_t tif_curdir; /* current directory (index) */
+ tstrip_t tif_curstrip; /* current strip for read/write */
+ toff_t tif_curoff; /* current offset for read/write */
+ toff_t tif_dataoff; /* current offset for writing dir */
+/* SubIFD support */
+ uint16 tif_nsubifd; /* remaining subifds to write */
+ toff_t tif_subifdoff; /* offset for patching SubIFD link */
+/* tiling support */
+ uint32 tif_col; /* current column (offset by row too) */
+ ttile_t tif_curtile; /* current tile for read/write */
+ tsize_t tif_tilesize; /* # of bytes in a tile */
+/* compression scheme hooks */
+ int tif_decodestatus;
+ TIFFBoolMethod tif_setupdecode;/* called once before predecode */
+ TIFFPreMethod tif_predecode; /* pre- row/strip/tile decoding */
+ TIFFBoolMethod tif_setupencode;/* called once before preencode */
+ int tif_encodestatus;
+ TIFFPreMethod tif_preencode; /* pre- row/strip/tile encoding */
+ TIFFBoolMethod tif_postencode; /* post- row/strip/tile encoding */
+ TIFFCodeMethod tif_decoderow; /* scanline decoding routine */
+ TIFFCodeMethod tif_encoderow; /* scanline encoding routine */
+ TIFFCodeMethod tif_decodestrip;/* strip decoding routine */
+ TIFFCodeMethod tif_encodestrip;/* strip encoding routine */
+ TIFFCodeMethod tif_decodetile; /* tile decoding routine */
+ TIFFCodeMethod tif_encodetile; /* tile encoding routine */
+ TIFFVoidMethod tif_close; /* cleanup-on-close routine */
+ TIFFSeekMethod tif_seek; /* position within a strip routine */
+ TIFFVoidMethod tif_cleanup; /* cleanup state routine */
+ TIFFStripMethod tif_defstripsize;/* calculate/constrain strip size */
+ TIFFTileMethod tif_deftilesize;/* calculate/constrain tile size */
+ tidata_t tif_data; /* compression scheme private data */
+/* input/output buffering */
+ tsize_t tif_scanlinesize;/* # of bytes in a scanline */
+ tsize_t tif_scanlineskew;/* scanline skew for reading strips */
+ tidata_t tif_rawdata; /* raw data buffer */
+ tsize_t tif_rawdatasize;/* # of bytes in raw data buffer */
+ tidata_t tif_rawcp; /* current spot in raw buffer */
+ tsize_t tif_rawcc; /* bytes unread from raw buffer */
+/* memory-mapped file support */
+ tidata_t tif_base; /* base of mapped file */
+ toff_t tif_size; /* size of mapped file region (bytes)
+ FIXME: it should be tsize_t */
+ TIFFMapFileProc tif_mapproc; /* map file method */
+ TIFFUnmapFileProc tif_unmapproc;/* unmap file method */
+/* input/output callback methods */
+ thandle_t tif_clientdata; /* callback parameter */
+ TIFFReadWriteProc tif_readproc; /* read method */
+ TIFFReadWriteProc tif_writeproc;/* write method */
+ TIFFSeekProc tif_seekproc; /* lseek method */
+ TIFFCloseProc tif_closeproc; /* close method */
+ TIFFSizeProc tif_sizeproc; /* filesize method */
+/* post-decoding support */
+ TIFFPostMethod tif_postdecode; /* post decoding routine */
+/* tag support */
+ TIFFFieldInfo** tif_fieldinfo; /* sorted table of registered tags */
+ size_t tif_nfields; /* # entries in registered tag table */
+ const TIFFFieldInfo *tif_foundfield;/* cached pointer to already found tag */
+ TIFFTagMethods tif_tagmethods; /* tag get/set/print routines */
+ TIFFClientInfoLink *tif_clientinfo; /* extra client information. */
+};
+
+#define isPseudoTag(t) (t > 0xffff) /* is tag value normal or pseudo */
+
+#define isTiled(tif) (((tif)->tif_flags & TIFF_ISTILED) != 0)
+#define isMapped(tif) (((tif)->tif_flags & TIFF_MAPPED) != 0)
+#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0)
+#define isUpSampled(tif) (((tif)->tif_flags & TIFF_UPSAMPLED) != 0)
+#define TIFFReadFile(tif, buf, size) \
+ ((*(tif)->tif_readproc)((tif)->tif_clientdata,buf,size))
+#define TIFFWriteFile(tif, buf, size) \
+ ((*(tif)->tif_writeproc)((tif)->tif_clientdata,buf,size))
+#define TIFFSeekFile(tif, off, whence) \
+ ((*(tif)->tif_seekproc)((tif)->tif_clientdata,(toff_t)(off),whence))
+#define TIFFCloseFile(tif) \
+ ((*(tif)->tif_closeproc)((tif)->tif_clientdata))
+#define TIFFGetFileSize(tif) \
+ ((*(tif)->tif_sizeproc)((tif)->tif_clientdata))
+#define TIFFMapFileContents(tif, paddr, psize) \
+ ((*(tif)->tif_mapproc)((tif)->tif_clientdata,paddr,psize))
+#define TIFFUnmapFileContents(tif, addr, size) \
+ ((*(tif)->tif_unmapproc)((tif)->tif_clientdata,addr,size))
+
+/*
+ * Default Read/Seek/Write definitions.
+ */
+#ifndef ReadOK
+#define ReadOK(tif, buf, size) \
+ (TIFFReadFile(tif, (tdata_t) buf, (tsize_t)(size)) == (tsize_t)(size))
+#endif
+#ifndef SeekOK
+#define SeekOK(tif, off) \
+ (TIFFSeekFile(tif, (toff_t) off, SEEK_SET) == (toff_t) off)
+#endif
+#ifndef WriteOK
+#define WriteOK(tif, buf, size) \
+ (TIFFWriteFile(tif, (tdata_t) buf, (tsize_t) size) == (tsize_t) size)
+#endif
+
+/* NB: the uint32 casts are to silence certain ANSI-C compilers */
+#define TIFFhowmany(x, y) (((uint32)x < (0xffffffff - (uint32)(y-1))) ? \
+ ((((uint32)(x))+(((uint32)(y))-1))/((uint32)(y))) : \
+ 0U)
+#define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
+#define TIFFroundup(x, y) (TIFFhowmany(x,y)*(y))
+
+/* Safe multiply which returns zero if there is an integer overflow */
+#define TIFFSafeMultiply(t,v,m) ((((t)m != (t)0) && (((t)((v*m)/m)) == (t)v)) ? (t)(v*m) : (t)0)
+
+#define TIFFmax(A,B) ((A)>(B)?(A):(B))
+#define TIFFmin(A,B) ((A)<(B)?(A):(B))
+
+#define TIFFArrayCount(a) (sizeof (a) / sizeof ((a)[0]))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+extern int _TIFFgetMode(const char*, const char*);
+extern int _TIFFNoRowEncode(TIFF*, tidata_t, tsize_t, tsample_t);
+extern int _TIFFNoStripEncode(TIFF*, tidata_t, tsize_t, tsample_t);
+extern int _TIFFNoTileEncode(TIFF*, tidata_t, tsize_t, tsample_t);
+extern int _TIFFNoRowDecode(TIFF*, tidata_t, tsize_t, tsample_t);
+extern int _TIFFNoStripDecode(TIFF*, tidata_t, tsize_t, tsample_t);
+extern int _TIFFNoTileDecode(TIFF*, tidata_t, tsize_t, tsample_t);
+extern void _TIFFNoPostDecode(TIFF*, tidata_t, tsize_t);
+extern int _TIFFNoPreCode (TIFF*, tsample_t);
+extern int _TIFFNoSeek(TIFF*, uint32);
+extern void _TIFFSwab16BitData(TIFF*, tidata_t, tsize_t);
+extern void _TIFFSwab24BitData(TIFF*, tidata_t, tsize_t);
+extern void _TIFFSwab32BitData(TIFF*, tidata_t, tsize_t);
+extern void _TIFFSwab64BitData(TIFF*, tidata_t, tsize_t);
+extern int TIFFFlushData1(TIFF*);
+extern int TIFFDefaultDirectory(TIFF*);
+extern void _TIFFSetDefaultCompressionState(TIFF*);
+extern int TIFFSetCompressionScheme(TIFF*, int);
+extern int TIFFSetDefaultCompressionState(TIFF*);
+extern uint32 _TIFFDefaultStripSize(TIFF*, uint32);
+extern void _TIFFDefaultTileSize(TIFF*, uint32*, uint32*);
+extern int _TIFFDataSize(TIFFDataType);
+
+extern void _TIFFsetByteArray(void**, void*, uint32);
+extern void _TIFFsetString(char**, char*);
+extern void _TIFFsetShortArray(uint16**, uint16*, uint32);
+extern void _TIFFsetLongArray(uint32**, uint32*, uint32);
+extern void _TIFFsetFloatArray(float**, float*, uint32);
+extern void _TIFFsetDoubleArray(double**, double*, uint32);
+
+extern void _TIFFprintAscii(FILE*, const char*);
+extern void _TIFFprintAsciiTag(FILE*, const char*, const char*);
+
+extern TIFFErrorHandler _TIFFwarningHandler;
+extern TIFFErrorHandler _TIFFerrorHandler;
+extern TIFFErrorHandlerExt _TIFFwarningHandlerExt;
+extern TIFFErrorHandlerExt _TIFFerrorHandlerExt;
+
+extern tdata_t _TIFFCheckMalloc(TIFF*, size_t, size_t, const char*);
+extern tdata_t _TIFFCheckRealloc(TIFF*, tdata_t, size_t, size_t, const char*);
+
+extern int TIFFInitDumpMode(TIFF*, int);
+#ifdef PACKBITS_SUPPORT
+extern int TIFFInitPackBits(TIFF*, int);
+#endif
+#ifdef CCITT_SUPPORT
+extern int TIFFInitCCITTRLE(TIFF*, int), TIFFInitCCITTRLEW(TIFF*, int);
+extern int TIFFInitCCITTFax3(TIFF*, int), TIFFInitCCITTFax4(TIFF*, int);
+#endif
+#ifdef THUNDER_SUPPORT
+extern int TIFFInitThunderScan(TIFF*, int);
+#endif
+#ifdef NEXT_SUPPORT
+extern int TIFFInitNeXT(TIFF*, int);
+#endif
+#ifdef LZW_SUPPORT
+extern int TIFFInitLZW(TIFF*, int);
+#endif
+#ifdef OJPEG_SUPPORT
+extern int TIFFInitOJPEG(TIFF*, int);
+#endif
+#ifdef JPEG_SUPPORT
+extern int TIFFInitJPEG(TIFF*, int);
+#endif
+#ifdef JBIG_SUPPORT
+extern int TIFFInitJBIG(TIFF*, int);
+#endif
+#ifdef ZIP_SUPPORT
+extern int TIFFInitZIP(TIFF*, int);
+#endif
+#ifdef PIXARLOG_SUPPORT
+extern int TIFFInitPixarLog(TIFF*, int);
+#endif
+#ifdef LOGLUV_SUPPORT
+extern int TIFFInitSGILog(TIFF*, int);
+#endif
+#ifdef VMS
+extern const TIFFCodec _TIFFBuiltinCODECS[];
+#else
+extern TIFFCodec _TIFFBuiltinCODECS[];
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* _TIFFIOP_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/libtiff/tiffvers.h b/tiff/libtiff/tiffvers.h
new file mode 100644
index 0000000..314a22a
--- /dev/null
+++ b/tiff/libtiff/tiffvers.h
@@ -0,0 +1,9 @@
+#define TIFFLIB_VERSION_STR "LIBTIFF, Version 3.9.4\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc."
+/*
+ * This define can be used in code that requires
+ * compilation-related definitions specific to a
+ * version or versions of the library. Runtime
+ * version checking should be done based on the
+ * string returned by TIFFGetVersion.
+ */
+#define TIFFLIB_VERSION 20100615
diff --git a/tiff/libtiff/uvcode.h b/tiff/libtiff/uvcode.h
new file mode 100644
index 0000000..50f11d7
--- /dev/null
+++ b/tiff/libtiff/uvcode.h
@@ -0,0 +1,180 @@
+/* Version 1.0 generated April 7, 1997 by Greg Ward Larson, SGI */
+#define UV_SQSIZ (float)0.003500
+#define UV_NDIVS 16289
+#define UV_VSTART (float)0.016940
+#define UV_NVS 163
+static struct {
+ float ustart;
+ short nus, ncum;
+} uv_row[UV_NVS] = {
+ { (float)0.247663, 4, 0 },
+ { (float)0.243779, 6, 4 },
+ { (float)0.241684, 7, 10 },
+ { (float)0.237874, 9, 17 },
+ { (float)0.235906, 10, 26 },
+ { (float)0.232153, 12, 36 },
+ { (float)0.228352, 14, 48 },
+ { (float)0.226259, 15, 62 },
+ { (float)0.222371, 17, 77 },
+ { (float)0.220410, 18, 94 },
+ { (float)0.214710, 21, 112 },
+ { (float)0.212714, 22, 133 },
+ { (float)0.210721, 23, 155 },
+ { (float)0.204976, 26, 178 },
+ { (float)0.202986, 27, 204 },
+ { (float)0.199245, 29, 231 },
+ { (float)0.195525, 31, 260 },
+ { (float)0.193560, 32, 291 },
+ { (float)0.189878, 34, 323 },
+ { (float)0.186216, 36, 357 },
+ { (float)0.186216, 36, 393 },
+ { (float)0.182592, 38, 429 },
+ { (float)0.179003, 40, 467 },
+ { (float)0.175466, 42, 507 },
+ { (float)0.172001, 44, 549 },
+ { (float)0.172001, 44, 593 },
+ { (float)0.168612, 46, 637 },
+ { (float)0.168612, 46, 683 },
+ { (float)0.163575, 49, 729 },
+ { (float)0.158642, 52, 778 },
+ { (float)0.158642, 52, 830 },
+ { (float)0.158642, 52, 882 },
+ { (float)0.153815, 55, 934 },
+ { (float)0.153815, 55, 989 },
+ { (float)0.149097, 58, 1044 },
+ { (float)0.149097, 58, 1102 },
+ { (float)0.142746, 62, 1160 },
+ { (float)0.142746, 62, 1222 },
+ { (float)0.142746, 62, 1284 },
+ { (float)0.138270, 65, 1346 },
+ { (float)0.138270, 65, 1411 },
+ { (float)0.138270, 65, 1476 },
+ { (float)0.132166, 69, 1541 },
+ { (float)0.132166, 69, 1610 },
+ { (float)0.126204, 73, 1679 },
+ { (float)0.126204, 73, 1752 },
+ { (float)0.126204, 73, 1825 },
+ { (float)0.120381, 77, 1898 },
+ { (float)0.120381, 77, 1975 },
+ { (float)0.120381, 77, 2052 },
+ { (float)0.120381, 77, 2129 },
+ { (float)0.112962, 82, 2206 },
+ { (float)0.112962, 82, 2288 },
+ { (float)0.112962, 82, 2370 },
+ { (float)0.107450, 86, 2452 },
+ { (float)0.107450, 86, 2538 },
+ { (float)0.107450, 86, 2624 },
+ { (float)0.107450, 86, 2710 },
+ { (float)0.100343, 91, 2796 },
+ { (float)0.100343, 91, 2887 },
+ { (float)0.100343, 91, 2978 },
+ { (float)0.095126, 95, 3069 },
+ { (float)0.095126, 95, 3164 },
+ { (float)0.095126, 95, 3259 },
+ { (float)0.095126, 95, 3354 },
+ { (float)0.088276, 100, 3449 },
+ { (float)0.088276, 100, 3549 },
+ { (float)0.088276, 100, 3649 },
+ { (float)0.088276, 100, 3749 },
+ { (float)0.081523, 105, 3849 },
+ { (float)0.081523, 105, 3954 },
+ { (float)0.081523, 105, 4059 },
+ { (float)0.081523, 105, 4164 },
+ { (float)0.074861, 110, 4269 },
+ { (float)0.074861, 110, 4379 },
+ { (float)0.074861, 110, 4489 },
+ { (float)0.074861, 110, 4599 },
+ { (float)0.068290, 115, 4709 },
+ { (float)0.068290, 115, 4824 },
+ { (float)0.068290, 115, 4939 },
+ { (float)0.068290, 115, 5054 },
+ { (float)0.063573, 119, 5169 },
+ { (float)0.063573, 119, 5288 },
+ { (float)0.063573, 119, 5407 },
+ { (float)0.063573, 119, 5526 },
+ { (float)0.057219, 124, 5645 },
+ { (float)0.057219, 124, 5769 },
+ { (float)0.057219, 124, 5893 },
+ { (float)0.057219, 124, 6017 },
+ { (float)0.050985, 129, 6141 },
+ { (float)0.050985, 129, 6270 },
+ { (float)0.050985, 129, 6399 },
+ { (float)0.050985, 129, 6528 },
+ { (float)0.050985, 129, 6657 },
+ { (float)0.044859, 134, 6786 },
+ { (float)0.044859, 134, 6920 },
+ { (float)0.044859, 134, 7054 },
+ { (float)0.044859, 134, 7188 },
+ { (float)0.040571, 138, 7322 },
+ { (float)0.040571, 138, 7460 },
+ { (float)0.040571, 138, 7598 },
+ { (float)0.040571, 138, 7736 },
+ { (float)0.036339, 142, 7874 },
+ { (float)0.036339, 142, 8016 },
+ { (float)0.036339, 142, 8158 },
+ { (float)0.036339, 142, 8300 },
+ { (float)0.032139, 146, 8442 },
+ { (float)0.032139, 146, 8588 },
+ { (float)0.032139, 146, 8734 },
+ { (float)0.032139, 146, 8880 },
+ { (float)0.027947, 150, 9026 },
+ { (float)0.027947, 150, 9176 },
+ { (float)0.027947, 150, 9326 },
+ { (float)0.023739, 154, 9476 },
+ { (float)0.023739, 154, 9630 },
+ { (float)0.023739, 154, 9784 },
+ { (float)0.023739, 154, 9938 },
+ { (float)0.019504, 158, 10092 },
+ { (float)0.019504, 158, 10250 },
+ { (float)0.019504, 158, 10408 },
+ { (float)0.016976, 161, 10566 },
+ { (float)0.016976, 161, 10727 },
+ { (float)0.016976, 161, 10888 },
+ { (float)0.016976, 161, 11049 },
+ { (float)0.012639, 165, 11210 },
+ { (float)0.012639, 165, 11375 },
+ { (float)0.012639, 165, 11540 },
+ { (float)0.009991, 168, 11705 },
+ { (float)0.009991, 168, 11873 },
+ { (float)0.009991, 168, 12041 },
+ { (float)0.009016, 170, 12209 },
+ { (float)0.009016, 170, 12379 },
+ { (float)0.009016, 170, 12549 },
+ { (float)0.006217, 173, 12719 },
+ { (float)0.006217, 173, 12892 },
+ { (float)0.005097, 175, 13065 },
+ { (float)0.005097, 175, 13240 },
+ { (float)0.005097, 175, 13415 },
+ { (float)0.003909, 177, 13590 },
+ { (float)0.003909, 177, 13767 },
+ { (float)0.002340, 177, 13944 },
+ { (float)0.002389, 170, 14121 },
+ { (float)0.001068, 164, 14291 },
+ { (float)0.001653, 157, 14455 },
+ { (float)0.000717, 150, 14612 },
+ { (float)0.001614, 143, 14762 },
+ { (float)0.000270, 136, 14905 },
+ { (float)0.000484, 129, 15041 },
+ { (float)0.001103, 123, 15170 },
+ { (float)0.001242, 115, 15293 },
+ { (float)0.001188, 109, 15408 },
+ { (float)0.001011, 103, 15517 },
+ { (float)0.000709, 97, 15620 },
+ { (float)0.000301, 89, 15717 },
+ { (float)0.002416, 82, 15806 },
+ { (float)0.003251, 76, 15888 },
+ { (float)0.003246, 69, 15964 },
+ { (float)0.004141, 62, 16033 },
+ { (float)0.005963, 55, 16095 },
+ { (float)0.008839, 47, 16150 },
+ { (float)0.010490, 40, 16197 },
+ { (float)0.016994, 31, 16237 },
+ { (float)0.023659, 21, 16268 },
+};
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/m4/acinclude.m4 b/tiff/m4/acinclude.m4
new file mode 100644
index 0000000..a213cde
--- /dev/null
+++ b/tiff/m4/acinclude.m4
@@ -0,0 +1,669 @@
+dnl ---------------------------------------------------------------------------
+dnl Message output
+dnl ---------------------------------------------------------------------------
+AC_DEFUN([LOC_MSG],[echo "$1"])
+
+dnl ---------------------------------------------------------------------------
+dnl Available from the GNU Autoconf Macro Archive at:
+dnl http://www.gnu.org/software/ac-archive/vl_prog_cc_warnings.html
+dnl ---------------------------------------------------------------------------
+
+dnl @synopsis VL_PROG_CC_WARNINGS([ANSI])
+dnl
+dnl Enables a reasonable set of warnings for the C compiler.
+dnl Optionally, if the first argument is nonempty, turns on flags which
+dnl enforce and/or enable proper ANSI C if such are known with the
+dnl compiler used.
+dnl
+dnl Currently this macro knows about GCC, Solaris C compiler, Digital
+dnl Unix C compiler, C for AIX Compiler, HP-UX C compiler, IRIX C
+dnl compiler, NEC SX-5 (Super-UX 10) C compiler, and Cray J90 (Unicos
+dnl 10.0.0.8) C compiler.
+dnl
+dnl @category C
+dnl @author Ville Laurikari <vl@iki.fi>
+dnl @version 2002-04-04
+dnl @license AllPermissive
+
+AC_DEFUN([VL_PROG_CC_WARNINGS], [
+ ansi=$1
+ if test -z "$ansi"; then
+ msg="for C compiler warning flags"
+ else
+ msg="for C compiler warning and ANSI conformance flags"
+ fi
+ AC_CACHE_CHECK($msg, vl_cv_prog_cc_warnings, [
+ if test -n "$CC"; then
+ cat > conftest.c <<EOF
+int main(int argc, char **argv) { return 0; }
+EOF
+
+ dnl GCC. -W option has been renamed in -wextra in latest gcc versions.
+ if test "$GCC" = "yes"; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-Wall -W"
+ else
+ vl_cv_prog_cc_warnings="-Wall -W -ansi -pedantic"
+ fi
+
+ dnl Most compilers print some kind of a version string with some command
+ dnl line options (often "-V"). The version string should be checked
+ dnl before doing a test compilation run with compiler-specific flags.
+ dnl This is because some compilers (like the Cray compiler) only
+ dnl produce a warning message for unknown flags instead of returning
+ dnl an error, resulting in a false positive. Also, compilers may do
+ dnl erratic things when invoked with flags meant for a different
+ dnl compiler.
+
+ dnl Solaris C compiler
+ elif $CC -V 2>&1 | grep -i "WorkShop" > /dev/null 2>&1 &&
+ $CC -c -v -Xc conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-v"
+ else
+ vl_cv_prog_cc_warnings="-v -Xc"
+ fi
+
+ dnl Digital Unix C compiler
+ elif $CC -V 2>&1 | grep -i "Digital UNIX Compiler" > /dev/null 2>&1 &&
+ $CC -c -verbose -w0 -warnprotos -std1 conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-verbose -w0 -warnprotos"
+ else
+ vl_cv_prog_cc_warnings="-verbose -w0 -warnprotos -std1"
+ fi
+
+ dnl C for AIX Compiler
+ elif $CC 2>&1 | grep -i "C for AIX Compiler" > /dev/null 2>&1 &&
+ $CC -c -qlanglvl=ansi -qinfo=all conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd"
+ else
+ vl_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd -qlanglvl=ansi"
+ fi
+
+ dnl IRIX C compiler
+ elif $CC -version 2>&1 | grep -i "MIPSpro Compilers" > /dev/null 2>&1 &&
+ $CC -c -fullwarn -ansi -ansiE conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-fullwarn"
+ else
+ vl_cv_prog_cc_warnings="-fullwarn -ansi -ansiE"
+ fi
+
+ dnl HP-UX C compiler
+ elif what $CC 2>&1 | grep -i "HP C Compiler" > /dev/null 2>&1 &&
+ $CC -c -Aa +w1 conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="+w1"
+ else
+ vl_cv_prog_cc_warnings="+w1 -Aa"
+ fi
+
+ dnl The NEC SX-5 (Super-UX 10) C compiler
+ elif $CC -V 2>&1 | grep "/SX" > /dev/null 2>&1 &&
+ $CC -c -pvctl[,]fullmsg -Xc conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-pvctl[,]fullmsg"
+ else
+ vl_cv_prog_cc_warnings="-pvctl[,]fullmsg -Xc"
+ fi
+
+ dnl The Cray C compiler (Unicos)
+ elif $CC -V 2>&1 | grep -i "Cray" > /dev/null 2>&1 &&
+ $CC -c -h msglevel 2 conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o; then
+ if test -z "$ansi"; then
+ vl_cv_prog_cc_warnings="-h msglevel 2"
+ else
+ vl_cv_prog_cc_warnings="-h msglevel 2 -h conform"
+ fi
+
+ fi
+ rm -f conftest.*
+ fi
+ if test -n "$vl_cv_prog_cc_warnings"; then
+ CFLAGS="$CFLAGS $vl_cv_prog_cc_warnings"
+ else
+ vl_cv_prog_cc_warnings="unknown"
+ fi
+ ])
+])dnl
+
+dnl ---------------------------------------------------------------------------
+dnl Available from the GNU Autoconf Macro Archive at:
+dnl http://autoconf-archive.cryp.to/ax_lang_compiler_ms.html
+dnl ---------------------------------------------------------------------------
+
+dnl @synopsis AX_LANG_COMPILER_MS
+dnl
+dnl Check whether the compiler for the current language is Microsoft.
+dnl
+dnl This macro is modeled after _AC_LANG_COMPILER_GNU in the GNU
+dnl Autoconf implementation.
+dnl
+dnl @category InstalledPackages
+dnl @author Braden McDaniel <braden@endoframe.com>
+dnl @version 2004-11-15
+dnl @license AllPermissive
+
+AC_DEFUN([AX_LANG_COMPILER_MS],
+[AC_CACHE_CHECK([whether we are using the Microsoft _AC_LANG compiler],
+ [ax_cv_[]_AC_LANG_ABBREV[]_compiler_ms],
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[#ifndef _MSC_VER
+ choke me
+#endif
+]])],
+ [ax_compiler_ms=yes],
+ [ax_compiler_ms=no])
+ax_cv_[]_AC_LANG_ABBREV[]_compiler_ms=$ax_compiler_ms
+])])
+
+dnl ---------------------------------------------------------------------------
+dnl Available from the GNU Autoconf Macro Archive at:
+dnl http://www.gnu.org/software/ac-archive/ax_check_gl.html
+dnl ---------------------------------------------------------------------------
+
+dnl @synopsis AX_CHECK_GL
+dnl
+dnl Check for an OpenGL implementation. If GL is found, the required
+dnl compiler and linker flags are included in the output variables
+dnl "GL_CFLAGS" and "GL_LIBS", respectively. This macro adds the
+dnl configure option "--with-apple-opengl-framework", which users can
+dnl use to indicate that Apple's OpenGL framework should be used on Mac
+dnl OS X. If Apple's OpenGL framework is used, the symbol
+dnl "HAVE_APPLE_OPENGL_FRAMEWORK" is defined. If no GL implementation
+dnl is found, "no_gl" is set to "yes".
+dnl
+dnl @category InstalledPackages
+dnl @author Braden McDaniel <braden@endoframe.com>
+dnl @version 2004-11-15
+dnl @license AllPermissive
+
+AC_DEFUN([AX_CHECK_GL],
+[AC_REQUIRE([AC_PATH_X])dnl
+AC_REQUIRE([ACX_PTHREAD])dnl
+
+#
+# There isn't a reliable way to know we should use the Apple OpenGL framework
+# without a configure option. A Mac OS X user may have installed an
+# alternative GL implementation (e.g., Mesa), which may or may not depend on X.
+#
+AC_ARG_WITH([apple-opengl-framework],
+ [AC_HELP_STRING([--with-apple-opengl-framework],
+ [use Apple OpenGL framework (Mac OS X only)])])
+if test "X$with_apple_opengl_framework" = "Xyes"; then
+ AC_DEFINE([HAVE_APPLE_OPENGL_FRAMEWORK], [1],
+ [Use the Apple OpenGL framework.])
+ GL_LIBS="-framework OpenGL"
+else
+ AC_LANG_PUSH(C)
+
+ AX_LANG_COMPILER_MS
+ if test X$ax_compiler_ms = Xno; then
+ GL_CFLAGS="${PTHREAD_CFLAGS}"
+ GL_LIBS="${PTHREAD_LIBS} -lm"
+ fi
+
+ #
+ # Use x_includes and x_libraries if they have been set (presumably by
+ # AC_PATH_X).
+ #
+ if test "X$no_x" != "Xyes"; then
+ if test -n "$x_includes"; then
+ GL_CFLAGS="-I${x_includes} ${GL_CFLAGS}"
+ fi
+ if test -n "$x_libraries"; then
+ GL_LIBS="-L${x_libraries} -lX11 ${GL_LIBS}"
+ fi
+ fi
+
+ AC_CHECK_HEADERS([windows.h])
+
+ AC_CACHE_CHECK([for OpenGL library], [ax_cv_check_gl_libgl],
+ [ax_cv_check_gl_libgl="no"
+ ax_save_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${GL_CFLAGS} ${CPPFLAGS}"
+ ax_save_LIBS="${LIBS}"
+ LIBS=""
+ ax_check_libs="-lopengl32 -lGL"
+ for ax_lib in ${ax_check_libs}; do
+ if test X$ax_compiler_ms = Xyes; then
+ ax_try_lib=`echo $ax_lib | sed -e 's/^-l//' -e 's/$/.lib/'`
+ else
+ ax_try_lib="${ax_lib}"
+ fi
+ LIBS="${ax_try_lib} ${GL_LIBS} ${ax_save_LIBS}"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[
+# if HAVE_WINDOWS_H && defined(_WIN32)
+# include <windows.h>
+# endif
+# include <GL/gl.h>]],
+ [[glBegin(0)]])],
+ [ax_cv_check_gl_libgl="${ax_try_lib}"; break])
+ done
+ LIBS=${ax_save_LIBS}
+ CPPFLAGS=${ax_save_CPPFLAGS}])
+
+ if test "X${ax_cv_check_gl_libgl}" = "Xno"; then
+ no_gl="yes"
+ GL_CFLAGS=""
+ GL_LIBS=""
+ else
+ GL_LIBS="${ax_cv_check_gl_libgl} ${GL_LIBS}"
+ fi
+ AC_LANG_POP(C)
+fi
+
+AC_SUBST([GL_CFLAGS])
+AC_SUBST([GL_LIBS])
+])dnl
+
+dnl ---------------------------------------------------------------------------
+dnl Available from the GNU Autoconf Macro Archive at:
+dnl http://www.gnu.org/software/ac-archive/ax_check_glu.html
+dnl ---------------------------------------------------------------------------
+
+dnl @synopsis AX_CHECK_GLU
+dnl
+dnl Check for GLU. If GLU is found, the required preprocessor and
+dnl linker flags are included in the output variables "GLU_CFLAGS" and
+dnl "GLU_LIBS", respectively. This macro adds the configure option
+dnl "--with-apple-opengl-framework", which users can use to indicate
+dnl that Apple's OpenGL framework should be used on Mac OS X. If
+dnl Apple's OpenGL framework is used, the symbol
+dnl "HAVE_APPLE_OPENGL_FRAMEWORK" is defined. If no GLU implementation
+dnl is found, "no_glu" is set to "yes".
+dnl
+dnl @category InstalledPackages
+dnl @author Braden McDaniel <braden@endoframe.com>
+dnl @version 2004-11-15
+dnl @license AllPermissive
+
+AC_DEFUN([AX_CHECK_GLU],
+[AC_REQUIRE([AX_CHECK_GL])dnl
+AC_REQUIRE([AC_PROG_CXX])dnl
+GLU_CFLAGS="${GL_CFLAGS}"
+if test "X${with_apple_opengl_framework}" != "Xyes"; then
+ AC_CACHE_CHECK([for OpenGL Utility library], [ax_cv_check_glu_libglu],
+ [ax_cv_check_glu_libglu="no"
+ ax_save_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${GL_CFLAGS} ${CPPFLAGS}"
+ ax_save_LIBS="${LIBS}"
+ LIBS=""
+ ax_check_libs="-lglu32 -lGLU"
+ for ax_lib in ${ax_check_libs}; do
+ if test X$ax_compiler_ms = Xyes; then
+ ax_try_lib=`echo $ax_lib | sed -e 's/^-l//' -e 's/$/.lib/'`
+ else
+ ax_try_lib="${ax_lib}"
+ fi
+ LIBS="${ax_try_lib} ${GL_LIBS} ${ax_save_LIBS}"
+ #
+ # libGLU typically links with libstdc++ on POSIX platforms. However,
+ # setting the language to C++ means that test program source is named
+ # "conftest.cc"; and Microsoft cl doesn't know what to do with such a
+ # file.
+ #
+ AC_LANG_PUSH([C++])
+ if test X$ax_compiler_ms = Xyes; then
+ AC_LANG_PUSH([C])
+ fi
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[
+# if HAVE_WINDOWS_H && defined(_WIN32)
+# include <windows.h>
+# endif
+# include <GL/glu.h>]],
+ [[gluBeginCurve(0)]])],
+ [ax_cv_check_glu_libglu="${ax_try_lib}"; break])
+ if test X$ax_compiler_ms = Xyes; then
+ AC_LANG_POP([C])
+ fi
+ AC_LANG_POP([C++])
+ done
+ LIBS=${ax_save_LIBS}
+ CPPFLAGS=${ax_save_CPPFLAGS}])
+ if test "X${ax_cv_check_glu_libglu}" = "Xno"; then
+ no_glu="yes"
+ GLU_CFLAGS=""
+ GLU_LIBS=""
+ else
+ GLU_LIBS="${ax_cv_check_glu_libglu} ${GL_LIBS}"
+ fi
+fi
+AC_SUBST([GLU_CFLAGS])
+AC_SUBST([GLU_LIBS])
+])
+
+dnl ---------------------------------------------------------------------------
+dnl Available from the GNU Autoconf Macro Archive at:
+dnl http://www.gnu.org/software/ac-archive/ax_check_glut.html
+dnl ---------------------------------------------------------------------------
+
+dnl @synopsis AX_CHECK_GLUT
+dnl
+dnl Check for GLUT. If GLUT is found, the required compiler and linker
+dnl flags are included in the output variables "GLUT_CFLAGS" and
+dnl "GLUT_LIBS", respectively. This macro adds the configure option
+dnl "--with-apple-opengl-framework", which users can use to indicate
+dnl that Apple's OpenGL framework should be used on Mac OS X. If
+dnl Apple's OpenGL framework is used, the symbol
+dnl "HAVE_APPLE_OPENGL_FRAMEWORK" is defined. If GLUT is not found,
+dnl "no_glut" is set to "yes".
+dnl
+dnl @category InstalledPackages
+dnl @author Braden McDaniel <braden@endoframe.com>
+dnl @version 2004-11-15
+dnl @license AllPermissive
+
+AC_DEFUN([AX_CHECK_GLUT],
+[AC_REQUIRE([AX_CHECK_GLU])dnl
+AC_REQUIRE([AC_PATH_XTRA])dnl
+
+if test "X$with_apple_opengl_framework" = "Xyes"; then
+ GLUT_CFLAGS="${GLU_CFLAGS}"
+ GLUT_LIBS="-framework GLUT -lobjc ${GL_LIBS}"
+else
+ GLUT_CFLAGS=${GLU_CFLAGS}
+ GLUT_LIBS=${GLU_LIBS}
+
+ #
+ # If X is present, assume GLUT depends on it.
+ #
+ if test "X${no_x}" != "Xyes"; then
+ GLUT_LIBS="${X_PRE_LIBS} -lXmu -lXi ${X_EXTRA_LIBS} ${GLUT_LIBS}"
+ fi
+
+ AC_LANG_PUSH(C)
+
+ ax_save_CPPFLAGS="${CPPFLAGS}"
+ CPPFLAGS="${GLUT_CFLAGS} ${CPPFLAGS}"
+
+ AC_CACHE_CHECK([for GLUT library], [ax_cv_check_glut_libglut],
+ [ax_cv_check_glut_libglut="no"
+ ax_save_LIBS="${LIBS}"
+ LIBS=""
+ ax_check_libs="-lglut32 -lglut"
+ for ax_lib in ${ax_check_libs}; do
+ if test X$ax_compiler_ms = Xyes; then
+ ax_try_lib=`echo $ax_lib | sed -e 's/^-l//' -e 's/$/.lib/'`
+ else
+ ax_try_lib="${ax_lib}"
+ fi
+ LIBS="${ax_try_lib} ${GLUT_LIBS} ${ax_save_LIBS}"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([[
+# if HAVE_WINDOWS_H && defined(_WIN32)
+# include <windows.h>
+# endif
+# include <GL/glut.h>]],
+ [[glutMainLoop()]])],
+ [ax_cv_check_glut_libglut="${ax_try_lib}"; break])
+
+ done
+ LIBS=${ax_save_LIBS}
+ ])
+ CPPFLAGS="${ax_save_CPPFLAGS}"
+ AC_LANG_POP(C)
+
+ if test "X${ax_cv_check_glut_libglut}" = "Xno"; then
+ no_glut="yes"
+ GLUT_CFLAGS=""
+ GLUT_LIBS=""
+ else
+ GLUT_LIBS="${ax_cv_check_glut_libglut} ${GLUT_LIBS}"
+ fi
+fi
+
+AC_SUBST([GLUT_CFLAGS])
+AC_SUBST([GLUT_LIBS])
+])dnl
+
+dnl ---------------------------------------------------------------------------
+dnl Available from the GNU Autoconf Macro Archive at:
+dnl http://www.gnu.org/software/ac-archive/acx_pthread.html
+dnl ---------------------------------------------------------------------------
+
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl This macro figures out how to build C programs using POSIX threads.
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
+dnl C compiler flags that are needed. (The user can also force certain
+dnl compiler flags/libs to be tested by setting these environment
+dnl variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well. e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+dnl $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to use
+dnl these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl LIBS="$PTHREAD_LIBS $LIBS"
+dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
+dnl default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform, or
+dnl if you have any other suggestions or comments. This macro was based
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
+dnl We are also grateful for the helpful feedback of numerous users.
+dnl
+dnl @category InstalledPackages
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
+dnl @version 2005-01-14
+dnl @license GPLWithACException
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthread or
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ # More AIX lossage: must compile with cc_r
+ AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC})
+else
+ PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ acx_pthread_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff --git a/tiff/m4/libtool.m4 b/tiff/m4/libtool.m4
new file mode 100644
index 0000000..22924a8
--- /dev/null
+++ b/tiff/m4/libtool.m4
@@ -0,0 +1,7437 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
+# Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010 Free Software Foundation,
+# Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable. If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins. After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script. The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2010 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ _LT_PROG_XSI_SHELLFNS
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS="$save_LDFLAGS"
+ ])
+ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+ [lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+ echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+ $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES
+# --------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ m4_if([$1], [CXX],
+[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX
+# -----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+case "$ECHO" in
+ printf*) AC_MSG_RESULT([printf]) ;;
+ print*) AC_MSG_RESULT([print -r]) ;;
+ *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test "X`printf %s $ECHO`" = "X$ECHO" \
+ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ ppc64-*linux*|powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ ppc*-*linux*|powerpc*-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[AC_CHECK_TOOL(AR, ar, false)
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1])
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+ [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+ [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+ test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd1*)
+ dynamic_linker=no
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[123]]*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ hardcode_into_libs=yes
+ ;;
+
+haiku*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+ [lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [lt_cv_shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+ ])
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+ [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+ [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method == "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+ AC_SUBST([DUMPBIN])
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+ esac
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Xcompiler -fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ F* | *Sun*Fortran*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global defined
+ # symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ freebsd1*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ m4_if($1, [], [
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ _LT_LINKER_OPTION([if $CC understands -b],
+ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ AC_LINK_IFELSE(int foo(void) {},
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ )
+ LDFLAGS="$save_LDFLAGS"
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+ [$RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ ])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
+ [[If ld is used when linking, flag to hardcode $libdir into a binary
+ during linking. This must work even if $libdir does not exist]])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [fix_srcfile_path], [1],
+ [Fix the shell variable $srcfile for the compiler])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report which library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd[[12]]*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ gnu*)
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+ '"$_LT_TAGVAR(reload_cmds, $1)"
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)="$GXX"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+ _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ CC=${F77-"f77"}
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$G77"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+ _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ CC=${FC-"f95"}
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_XSI_SHELLFNS
+# ---------------------
+# Bourne and XSI compatible variants of some useful shell functions.
+m4_defun([_LT_PROG_XSI_SHELLFNS],
+[case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=$(( $[*] ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=${#1}
+}
+
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+}
+
+dnl func_dirname_and_basename
+dnl A portable version of this function is already defined in general.m4sh
+dnl so there is no need for it here.
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[[^=]]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "${1}" | $SED 's/\.[[^.]]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "$[@]"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$[1]+=\$[2]"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$[1]=\$$[1]\$[2]"
+}
+
+_LT_EOF
+ ;;
+ esac
+])
diff --git a/tiff/m4/ltoptions.m4 b/tiff/m4/ltoptions.m4
new file mode 100644
index 0000000..17cfd51
--- /dev/null
+++ b/tiff/m4/ltoptions.m4
@@ -0,0 +1,369 @@
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [pic_mode="$withval"],
+ [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/tiff/m4/ltsugar.m4 b/tiff/m4/ltsugar.m4
new file mode 100644
index 0000000..9000a05
--- /dev/null
+++ b/tiff/m4/ltsugar.m4
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/tiff/m4/ltversion.m4 b/tiff/m4/ltversion.m4
new file mode 100644
index 0000000..93fc771
--- /dev/null
+++ b/tiff/m4/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# Generated from ltversion.in.
+
+# serial 3175 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.2.10])
+m4_define([LT_PACKAGE_REVISION], [1.3175])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.2.10'
+macro_revision='1.3175'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/tiff/m4/lt~obsolete.m4 b/tiff/m4/lt~obsolete.m4
new file mode 100644
index 0000000..c573da9
--- /dev/null
+++ b/tiff/m4/lt~obsolete.m4
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
diff --git a/tiff/man/Makefile.am b/tiff/man/Makefile.am
new file mode 100644
index 0000000..745912b
--- /dev/null
+++ b/tiff/man/Makefile.am
@@ -0,0 +1,92 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+dist_man1_MANS = \
+ bmp2tiff.1 \
+ fax2ps.1 \
+ fax2tiff.1 \
+ gif2tiff.1 \
+ pal2rgb.1 \
+ ppm2tiff.1 \
+ ras2tiff.1 \
+ raw2tiff.1 \
+ rgb2ycbcr.1 \
+ sgi2tiff.1 \
+ thumbnail.1 \
+ tiff2bw.1 \
+ tiff2pdf.1 \
+ tiff2ps.1 \
+ tiff2rgba.1 \
+ tiffcmp.1 \
+ tiffcp.1 \
+ tiffcrop.1 \
+ tiffdither.1 \
+ tiffdump.1 \
+ tiffgt.1 \
+ tiffinfo.1 \
+ tiffmedian.1 \
+ tiffset.1 \
+ tiffsplit.1 \
+ tiffsv.1
+
+dist_man3_MANS = \
+ libtiff.3tiff \
+ TIFFbuffer.3tiff \
+ TIFFClose.3tiff \
+ TIFFcodec.3tiff \
+ TIFFcolor.3tiff \
+ TIFFDataWidth.3tiff \
+ TIFFError.3tiff \
+ TIFFFlush.3tiff \
+ TIFFGetField.3tiff \
+ TIFFmemory.3tiff \
+ TIFFOpen.3tiff \
+ TIFFPrintDirectory.3tiff \
+ TIFFquery.3tiff \
+ TIFFReadDirectory.3tiff \
+ TIFFReadEncodedStrip.3tiff \
+ TIFFReadEncodedTile.3tiff \
+ TIFFReadRawStrip.3tiff \
+ TIFFReadRawTile.3tiff \
+ TIFFReadRGBAImage.3tiff \
+ TIFFReadRGBAStrip.3tiff \
+ TIFFReadRGBATile.3tiff \
+ TIFFReadScanline.3tiff \
+ TIFFReadTile.3tiff \
+ TIFFRGBAImage.3tiff \
+ TIFFSetDirectory.3tiff \
+ TIFFSetField.3tiff \
+ TIFFsize.3tiff \
+ TIFFstrip.3tiff \
+ TIFFswab.3tiff \
+ TIFFtile.3tiff \
+ TIFFWarning.3tiff \
+ TIFFWriteDirectory.3tiff \
+ TIFFWriteEncodedStrip.3tiff \
+ TIFFWriteEncodedTile.3tiff \
+ TIFFWriteRawStrip.3tiff \
+ TIFFWriteRawTile.3tiff \
+ TIFFWriteScanline.3tiff \
+ TIFFWriteTile.3tiff
diff --git a/tiff/man/Makefile.in b/tiff/man/Makefile.in
new file mode 100644
index 0000000..08e1e8b
--- /dev/null
+++ b/tiff/man/Makefile.in
@@ -0,0 +1,602 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = man
+DIST_COMMON = $(dist_man1_MANS) $(dist_man3_MANS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+SOURCES =
+DIST_SOURCES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)"
+man3dir = $(mandir)/man3
+NROFF = nroff
+MANS = $(dist_man1_MANS) $(dist_man3_MANS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+dist_man1_MANS = \
+ bmp2tiff.1 \
+ fax2ps.1 \
+ fax2tiff.1 \
+ gif2tiff.1 \
+ pal2rgb.1 \
+ ppm2tiff.1 \
+ ras2tiff.1 \
+ raw2tiff.1 \
+ rgb2ycbcr.1 \
+ sgi2tiff.1 \
+ thumbnail.1 \
+ tiff2bw.1 \
+ tiff2pdf.1 \
+ tiff2ps.1 \
+ tiff2rgba.1 \
+ tiffcmp.1 \
+ tiffcp.1 \
+ tiffcrop.1 \
+ tiffdither.1 \
+ tiffdump.1 \
+ tiffgt.1 \
+ tiffinfo.1 \
+ tiffmedian.1 \
+ tiffset.1 \
+ tiffsplit.1 \
+ tiffsv.1
+
+dist_man3_MANS = \
+ libtiff.3tiff \
+ TIFFbuffer.3tiff \
+ TIFFClose.3tiff \
+ TIFFcodec.3tiff \
+ TIFFcolor.3tiff \
+ TIFFDataWidth.3tiff \
+ TIFFError.3tiff \
+ TIFFFlush.3tiff \
+ TIFFGetField.3tiff \
+ TIFFmemory.3tiff \
+ TIFFOpen.3tiff \
+ TIFFPrintDirectory.3tiff \
+ TIFFquery.3tiff \
+ TIFFReadDirectory.3tiff \
+ TIFFReadEncodedStrip.3tiff \
+ TIFFReadEncodedTile.3tiff \
+ TIFFReadRawStrip.3tiff \
+ TIFFReadRawTile.3tiff \
+ TIFFReadRGBAImage.3tiff \
+ TIFFReadRGBAStrip.3tiff \
+ TIFFReadRGBATile.3tiff \
+ TIFFReadScanline.3tiff \
+ TIFFReadTile.3tiff \
+ TIFFRGBAImage.3tiff \
+ TIFFSetDirectory.3tiff \
+ TIFFSetField.3tiff \
+ TIFFsize.3tiff \
+ TIFFstrip.3tiff \
+ TIFFswab.3tiff \
+ TIFFtile.3tiff \
+ TIFFWarning.3tiff \
+ TIFFWriteDirectory.3tiff \
+ TIFFWriteEncodedStrip.3tiff \
+ TIFFWriteEncodedTile.3tiff \
+ TIFFWriteRawStrip.3tiff \
+ TIFFWriteRawTile.3tiff \
+ TIFFWriteScanline.3tiff \
+ TIFFWriteTile.3tiff
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign man/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign man/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(dist_man1_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
+ @list='$(dist_man1_MANS)'; test -n "$(man1dir)" || exit 0; \
+ { for i in $$list; do echo "$$i"; done; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_man1_MANS)'; test -n "$(man1dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ test -z "$$files" || { \
+ echo " ( cd '$(DESTDIR)$(man1dir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(man1dir)" && rm -f $$files; }
+install-man3: $(dist_man3_MANS)
+ @$(NORMAL_INSTALL)
+ test -z "$(man3dir)" || $(MKDIR_P) "$(DESTDIR)$(man3dir)"
+ @list='$(dist_man3_MANS)'; test -n "$(man3dir)" || exit 0; \
+ { for i in $$list; do echo "$$i"; done; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man3:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_man3_MANS)'; test -n "$(man3dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ test -z "$$files" || { \
+ echo " ( cd '$(DESTDIR)$(man3dir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(man3dir)" && rm -f $$files; }
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+
+distdir: $(DISTFILES)
+ @list='$(MANS)'; if test -n "$$list"; then \
+ list=`for p in $$list; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \
+ if test -n "$$list" && \
+ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \
+ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \
+ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \
+ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \
+ echo " typically \`make maintainer-clean' will remove them" >&2; \
+ exit 1; \
+ else :; fi; \
+ else :; fi
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man3dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1 install-man3
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-man
+
+uninstall-man: uninstall-man1 uninstall-man3
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ distclean distclean-generic distclean-libtool distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-man1 \
+ install-man3 install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am uninstall uninstall-am uninstall-man uninstall-man1 \
+ uninstall-man3
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/man/TIFFClose.3tiff b/tiff/man/TIFFClose.3tiff
new file mode 100644
index 0000000..6dce01f
--- /dev/null
+++ b/tiff/man/TIFFClose.3tiff
@@ -0,0 +1,53 @@
+.\" $Id: TIFFClose.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFClose 3TIFF "November 2, 2005" "libtiff"
+.SH NAME
+TIFFClose \- close a previously opened
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "void TIFFClose(TIFF *" tif ")"
+.SH DESCRIPTION
+.IR TIFFClose
+closes a file that was previously opened with
+.BR TIFFOpen (3TIFF).
+Any buffered data are flushed to the file, including the contents of the
+current directory (if modified); and all resources are reclaimed.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.bR TIFFError (3TIFF)
+routine.
+Likewise, warning messages are directed to the
+.BR TIFFWarning (3TIFF)
+routine.
+.SH "SEE ALSO"
+.BR libtiff (3TIFF),
+.BR TIFFOpen (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFDataWidth.3tiff b/tiff/man/TIFFDataWidth.3tiff
new file mode 100644
index 0000000..614e69b
--- /dev/null
+++ b/tiff/man/TIFFDataWidth.3tiff
@@ -0,0 +1,74 @@
+.\" $Id: TIFFDataWidth.3tiff,v 1.3 2006/03/23 14:54:02 dron Exp $
+.\"
+.\" Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFDataWidth 3TIFF "September 12, 2002" "libtiff"
+.SH NAME
+TIFFDataWidth \- Get the size of TIFF data types
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFDataWidth(TIFFDataType " type ")"
+.SH DESCRIPTION
+.I TIFFDataWidth
+returns a size of
+.I type
+in bytes.
+Currently following data types are supported:
+.br
+.I TIFF_BYTE
+.br
+.I TIFF_ASCII
+.br
+.I TIFF_SBYTE
+.br
+.I TIFF_UNDEFINED
+.br
+.I TIFF_SHORT
+.br
+.I TIFF_SSHORT
+.br
+.I TIFF_LONG
+.br
+.I TIFF_SLONG
+.br
+.I TIFF_FLOAT
+.br
+.I TIFF_IFD
+.br
+.I TIFF_RATIONAL
+.br
+.I TIFF_SRATIONAL
+.br
+.I TIFF_DOUBLE
+.br
+.SH "RETURN VALUES"
+.br
+.IR TIFFDataWidth
+returns a number of bytes occupied by the item of given type. 0 returned when
+uknown data type supplied.
+.SH "SEE ALSO"
+.BR libtiff (3TIFF),
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFError.3tiff b/tiff/man/TIFFError.3tiff
new file mode 100644
index 0000000..677a1df
--- /dev/null
+++ b/tiff/man/TIFFError.3tiff
@@ -0,0 +1,69 @@
+.\" $Id: TIFFError.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFError 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFError, TIFFSetErrorHandler \- library error handling interface
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "void TIFFError(const char *" module ", const char *" fmt ", " ... ")"
+.sp
+.B "#include <stdarg.h>"
+.sp
+.BI "typedef void (*TIFFErrorHandler)(const char *" module ", const char *" fmt ", va_list " ap ");"
+.br
+.B "TIFFErrorHandler TIFFSetErrorHandler(TIFFErrorHandler handler);"
+.SH DESCRIPTION
+.I TIFFError
+invokes the library-wide error handling function to (normally) write an error
+message to the
+.BR stderr .
+The
+.I fmt
+parameter is a
+.IR printf (3S)
+format string, and any number arguments can be supplied. The
+.I module
+parameter, if non-zero, is printed before the message; it typically is used to
+identify the software module in which an error is detected.
+.PP
+Applications that desire to capture control in the event of an error should
+use
+.IR TIFFSetErrorHandler
+to override the default error handler.
+A
+.SM NULL
+(0) error handling function may be installed to suppress error messages.
+.SH "RETURN VALUES"
+.IR TIFFSetErrorHandler
+returns a reference to the previous error handling function.
+.SH "SEE ALSO"
+.BR TIFFWarning (3TIFF),
+.BR libtiff (3TIFF),
+.BR printf (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFFlush.3tiff b/tiff/man/TIFFFlush.3tiff
new file mode 100644
index 0000000..9d8f2a0
--- /dev/null
+++ b/tiff/man/TIFFFlush.3tiff
@@ -0,0 +1,64 @@
+.\" $Id: TIFFFlush.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFFlush 3TIFF "December 16, 1991" "libtiff"
+.SH NAME
+TIFFFlush, TIFFFlushData \- flush pending writes to an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFFlush(TIFF *" tif ")"
+.br
+.BI "int TIFFFlushData(TIFF *" tif ")"
+.SH DESCRIPTION
+.IR TIFFFlush
+causes any pending writes for the specified file (including writes for the
+current directory) to be done. In normal operation this call is never needed \-
+the library automatically does any flushing required.
+.PP
+.IR TIFFFlushData
+flushes any pending image data for the specified file to be written out;
+directory-related data are not flushed. In normal operation this call is never
+needed \- the library automatically does any flushing required.
+.SH "RETURN VALUES"
+0 is returned if an error is encountered, otherwise 1 is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFWriteEncodedStrip (3TIFF),
+.BR TIFFWriteEncodedTile (3TIFF),
+.BR TIFFWriteRawStrip (3TIFF),
+.BR TIFFWriteRawTile (3TIFF),
+.BR TIFFWriteScanline (3TIFF),
+.BR TIFFWriteTile (3TIFF)
+.BR libtiff (3TIFF),
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFGetField.3tiff b/tiff/man/TIFFGetField.3tiff
new file mode 100644
index 0000000..42c5165
--- /dev/null
+++ b/tiff/man/TIFFGetField.3tiff
@@ -0,0 +1,232 @@
+.\" $Id: TIFFGetField.3tiff,v 1.4.2.1 2010-05-06 02:54:43 olivier Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFGetField 3TIFF "March 18, 2005" "libtiff"
+.SH NAME
+TIFFGetField, TIFFVGetField \- get the value(s) of a tag in an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFGetField(TIFF *" tif ", ttag_t " tag ", " ... ")"
+.sp
+.B "#include <stdarg.h>"
+.sp
+.BI "int TIFFVGetField(TIFF *" tif ", ttag_t " tag ", va_list " ap ")"
+.br
+.BI "int TIFFGetFieldDefaulted(TIFF *" tif ", ttag_t " tag ", " ... ")"
+.br
+.BI "int TIFFVGetFieldDefaulted(TIFF *" tif ", ttag_t " tag ", va_list " ap ")"
+.SH DESCRIPTION
+.IR TIFFGetField
+returns the value of a tag or pseudo-tag associated with the the current
+directory of the opened
+.SM TIFF
+file
+.IR tif .
+(A
+.I pseudo-tag
+is a parameter that is used to control the operation of the
+.SM TIFF
+library but whose value is not read or written to the underlying file.) The
+file must have been previously opened with
+.IR TIFFOpen (3TIFF).
+The tag is identified by
+.IR tag ,
+one of the values defined in the include file
+.B tiff.h
+(see also the table below). The type and number of values returned is
+dependent on the tag being requested. The programming interface uses a
+variable argument list as prescribed by the
+.IR stdarg (3)
+interface. The returned values should only be interpreted if
+.IR TIFFGetField
+returns 1.
+.PP
+.IR TIFFVGetField
+is functionally equivalent to
+.IR TIFFGetField
+except that it takes a pointer to a variable argument list.
+.I TIFFVGetField
+is useful for layering interfaces on top of the functionality provided by
+.IR TIFFGetField .
+.PP
+.IR TIFFGetFieldDefaulted
+and
+.IR TIFFVGetFieldDefaulted
+are identical to
+.IR TIFFGetField
+and
+.IR TIFFVGetField ,
+except that if a tag is not defined in the current directory and it has a
+default value, then the default value is returned.
+.PP
+The tags understood by
+.IR libtiff(3TIFF),
+the number of parameter values, and the types for the returned values are
+shown below. The data types are specified as in C and correspond to the types
+used to specify tag values to
+.IR TIFFSetField (3TIFF).
+Remember that
+.IR TIFFGetField
+returns parameter values, so all the listed data types are pointers to storage
+where values should be returned.
+Consult the
+.SM TIFF
+specification (or relevant industry specification) for information on the
+meaning of each tag and their possible values.
+.PP
+.nf
+.ta \w'TIFFTAG_CONSECUTIVEBADFAXLINES'u+2n +\w'Count'u+2n +\w'TIFFFaxFillFunc*'u+2n
+\fITag Name\fP \fICount\fP \fITypes\fP \fINotes\fP
+.sp 5p
+TIFFTAG_ARTIST 1 char**
+TIFFTAG_BADFAXLINES 1 uint32*
+TIFFTAG_BITSPERSAMPLE 1 uint16*
+TIFFTAG_CLEANFAXDATA 1 uint16*
+TIFFTAG_COLORMAP 3 uint16** 1<<BitsPerSample arrays
+TIFFTAG_COMPRESSION 1 uint16*
+TIFFTAG_CONSECUTIVEBADFAXLINES 1 uint32*
+TIFFTAG_COPYRIGHT 1 char**
+TIFFTAG_DATATYPE 1 uint16*
+TIFFTAG_DATETIME 1 char**
+TIFFTAG_DOCUMENTNAME 1 char**
+TIFFTAG_DOTRANGE 2 uint16*
+TIFFTAG_EXTRASAMPLES 2 uint16*,uint16** count & types array
+TIFFTAG_FAXFILLFUNC 1 TIFFFaxFillFunc* G3/G4 compression pseudo-tag
+TIFFTAG_FAXMODE 1 int* G3/G4 compression pseudo-tag
+TIFFTAG_FILLORDER 1 uint16*
+TIFFTAG_GROUP3OPTIONS 1 uint32*
+TIFFTAG_GROUP4OPTIONS 1 uint32*
+TIFFTAG_HALFTONEHINTS 2 uint16*
+TIFFTAG_HOSTCOMPUTER 1 char**
+TIFFTAG_ICCPROFILE 2 uint32*,void** count, profile data
+TIFFTAG_IMAGEDEPTH 1 uint32*
+TIFFTAG_IMAGEDESCRIPTION 1 char**
+TIFFTAG_IMAGELENGTH 1 uint32*
+TIFFTAG_IMAGEWIDTH 1 uint32*
+TIFFTAG_INKNAMES 1 char**
+TIFFTAG_INKSET 1 uint16*
+TIFFTAG_JPEGCOLORMODE 1 int* JPEG pseudo-tag
+TIFFTAG_JPEGQUALITY 1 int* JPEG pseudo-tag
+TIFFTAG_JPEGTABLES 2 uint32*,void** count & tables
+TIFFTAG_JPEGTABLESMODE 1 int* JPEG pseudo-tag
+TIFFTAG_MAKE 1 char**
+TIFFTAG_MATTEING 1 uint16*
+TIFFTAG_MAXSAMPLEVALUE 1 uint16*
+TIFFTAG_MINSAMPLEVALUE 1 uint16*
+TIFFTAG_MODEL 1 char**
+TIFFTAG_ORIENTATION 1 uint16*
+TIFFTAG_PAGENAME 1 char**
+TIFFTAG_PAGENUMBER 2 uint16*
+TIFFTAG_PHOTOMETRIC 1 uint16*
+TIFFTAG_PHOTOSHOP 2 uint32*,void** count, data
+TIFFTAG_PLANARCONFIG 1 uint16*
+TIFFTAG_PREDICTOR 1 uint16*
+TIFFTAG_PRIMARYCHROMATICITIES 1 float** 6-entry array
+TIFFTAG_REFERENCEBLACKWHITE 1 float** 6-entry array
+TIFFTAG_RESOLUTIONUNIT 1 uint16*
+TIFFTAG_RICHTIFFIPTC 2 uint32*,void** count, data
+TIFFTAG_ROWSPERSTRIP 1 uint32*
+TIFFTAG_SAMPLEFORMAT 1 uint16*
+TIFFTAG_SAMPLESPERPIXEL 1 uint16*
+TIFFTAG_SMAXSAMPLEVALUE 1 double*
+TIFFTAG_SMINSAMPLEVALUE 1 double*
+TIFFTAG_SOFTWARE 1 char**
+TIFFTAG_STONITS 1 double**
+TIFFTAG_STRIPBYTECOUNTS 1 uint32**
+TIFFTAG_STRIPOFFSETS 1 uint32**
+TIFFTAG_SUBFILETYPE 1 uint32*
+TIFFTAG_SUBIFD 2 uint16*,uint32** count & offsets array
+TIFFTAG_TARGETPRINTER 1 char**
+TIFFTAG_THRESHHOLDING 1 uint16*
+TIFFTAG_TILEBYTECOUNTS 1 uint32**
+TIFFTAG_TILEDEPTH 1 uint32*
+TIFFTAG_TILELENGTH 1 uint32*
+TIFFTAG_TILEOFFSETS 1 uint32**
+TIFFTAG_TILEWIDTH 1 uint32*
+TIFFTAG_TRANSFERFUNCTION 1 or 3\(dg uint16**1<<BitsPerSample entry arrays
+TIFFTAG_WHITEPOINT 1 float** 2-entry array
+TIFFTAG_XMLPACKET 2 uint32*,void** count, data
+TIFFTAG_XPOSITION 1 float*
+TIFFTAG_XRESOLUTION 1 float*
+TIFFTAG_YCBCRCOEFFICIENTS 1 float** 3-entry array
+TIFFTAG_YCBCRPOSITIONING 1 uint16*
+TIFFTAG_YCBCRSUBSAMPLING 2 uint16*
+TIFFTAG_YPOSITION 1 float*
+TIFFTAG_YRESOLUTION 1 float*\(dd
+.fi
+\(dg If
+.I SamplesPerPixel
+is one, then a single array is returned; otherwise three arrays are returned.
+.fi
+\(dd The contents of this field are quite complex. See
+.IR "The ICC Profile Format Specification" ,
+Annex B.3 "Embedding ICC Profiles in TIFF Files" (available at
+http://www.color.org) for an explanation.
+.SH AUTOREGISTERED TAGS
+If you can't find the tag in the table above that means this is unsupported
+tag. But you still be able to read it's value if you know the data type of
+that tag. For example, if you want to read the LONG value from the tag 33424
+and ASCII string from the tag 36867 you can use the following code:
+.PP
+.RS
+.nf
+uint16 count;
+void *data;
+
+TIFFGetField(tiff, 33424, &count, &data);
+printf("Tag %d: %d, count %d\n", 33424, *(uint32 *)data, count);
+TIFFGetField(tiff, 36867, &count, &data);
+printf("Tag %d: %s, count %d\n", 36867, (char *)data, count);
+.fi
+.RE
+.PP
+
+
+is not supported by
+.BR libtiff(3TIFF),
+library
+.SH RETURN VALUES
+1 is returned if the tag is defined in the current directory; otherwise a 0 is
+returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.PP
+.BR "Unknown field, tag 0x%x" .
+An unknown tag was supplied.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFSetField (3TIFF),
+.BR TIFFSetDirectory (3TIFF),
+.BR TIFFReadDirectory (3TIFF),
+.BR TIFFWriteDirectory (3TIFF)
+.BR libtiff (3TIFF),
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFOpen.3tiff b/tiff/man/TIFFOpen.3tiff
new file mode 100644
index 0000000..dfb4c45
--- /dev/null
+++ b/tiff/man/TIFFOpen.3tiff
@@ -0,0 +1,279 @@
+.\" $Id: TIFFOpen.3tiff,v 1.2 2005/07/01 12:36:22 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFOpen 3TIFF "July 1, 2005" "libtiff"
+.SH NAME
+TIFFOpen, TIFFFdOpen, TIFFClientOpen \- open a
+.SM TIFF
+file for reading or writing
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "TIFF* TIFFOpen(const char *" filename ", const char *" mode ")"
+.br
+.BI "TIFF* TIFFFdOpen(const int " fd ", const char *" filename ", const char *" mode ")"
+.sp
+.B "typedef tsize_t (*TIFFReadWriteProc)(thandle_t, tdata_t, tsize_t);"
+.br
+.B "typedef toff_t (*TIFFSeekProc)(thandle_t, toff_t, int);"
+.br
+.B "typedef int (*TIFFCloseProc)(thandle_t);"
+.br
+.B "typedef toff_t (*TIFFSizeProc)(thandle_t);"
+.br
+.B "typedef int (*TIFFMapFileProc)(thandle_t, tdata_t*, toff_t*);"
+.br
+.B "typedef void (*TIFFUnmapFileProc)(thandle_t, tdata_t, toff_t);"
+.sp
+.BI "TIFF* TIFFClientOpen(const char *" filename ", const char *" mode ", thandle_t " clientdata ", TIFFReadWriteProc " readproc ", TIFFReadWriteProc " writeproc ", TIFFSeekProc " seekproc ", TIFFCloseProc " closeproc ", TIFFSizeProc " sizeproc ", TIFFMapFileProc " mapproc ", TIFFUnmapFileProc " unmapproc ")"
+.SH DESCRIPTION
+.IR TIFFOpen
+opens a
+.SM TIFF
+file whose name is
+.I filename
+and returns a handle to be used in subsequent calls to routines in
+.IR libtiff .
+If the open operation fails, then zero is returned.
+The
+.I mode
+parameter specifies if the file is to be opened for reading (``r''),
+writing (``w''), or appending (``a'') and, optionally, whether
+to override certain default aspects of library operation (see below).
+When a file is opened for appending, existing data will not
+be touched; instead new data will be written as additional subfiles.
+If an existing file is opened for writing, all previous data is
+overwritten.
+.PP
+If a file is opened for reading, the first
+.SM TIFF
+directory in the file is automatically read
+(also see
+.IR TIFFSetDirectory (3TIFF)
+for reading directories other than the first).
+If a file is opened for writing or appending, a default directory
+is automatically created for writing subsequent data.
+This directory has all the default values specified in
+.SM TIFF
+Revision 6.0:
+.IR BitsPerSample =1,
+.IR ThreshHolding "=bilevel art scan,"
+.IR FillOrder =1
+(most significant bit of each data byte is filled first),
+.IR Orientation =1
+(the 0th row represents the visual top of the image, and the 0th
+column represents the visual left hand side),
+.IR SamplesPerPixel =1,
+.IR RowsPerStrip =infinity,
+.IR ResolutionUnit =2
+(inches), and
+.IR Compression =1
+(no compression).
+To alter these values, or to define values for additional fields,
+.IR TIFFSetField (3TIFF)
+must be used.
+.PP
+.IR TIFFFdOpen
+is like
+.IR TIFFOpen
+except that it opens a
+.SM TIFF
+file given an open file descriptor
+.IR fd .
+The file's name and mode must reflect that of the open descriptor.
+The object associated with the file descriptor
+.BR "must support random access" .
+.PP
+.IR TIFFClientOpen
+is like
+.IR TIFFOpen
+except that the caller supplies a collection of functions that the
+library will use to do \s-1UNIX\s+1-like I/O operations.
+The
+.I readproc
+and
+.I writeproc
+are called to read and write data at the current file position.
+.I seekproc
+is called to change the current file position a la
+.IR lseek (2).
+.I closeproc
+is invoked to release any resources associated with an open file.
+.I sizeproc
+is invoked to obtain the size in bytes of a file.
+.I mapproc
+and
+.I unmapproc
+are called to map and unmap a file's contents in memory; c.f.
+.IR mmap (2)
+and
+.IR munmap (2).
+The
+.I clientdata
+parameter is an opaque ``handle'' passed to the client-specified
+routines passed as parameters to
+.IR TIFFClientOpen .
+.SH OPTIONS
+The open mode parameter can include the following flags in
+addition to the ``r'', ``w'', and ``a'' flags.
+Note however that option flags must follow the read-write-append
+specification.
+.TP
+.B l
+When creating a new file force information be written with
+Little-Endian byte order (but see below).
+By default the library will create new files using the native
+.SM CPU
+byte order.
+.TP
+.B b
+When creating a new file force information be written with
+Big-Endian byte order (but see below).
+By default the library will create new files using the native
+.SM CPU
+byte order.
+.TP
+.B L
+Force image data that is read or written to be treated with
+bits filled from Least Significant Bit (\s-1LSB\s+1) to
+Most Significant Bit (\s-1MSB\s+1).
+Note that this is the opposite to the way the library has
+worked from its inception.
+.TP
+.B B
+Force image data that is read or written to be treated with
+bits filled from Most Significant Bit (\s-1MSB\s+1) to
+Least Significant Bit (\s-1LSB\s+1); this is the default.
+.TP
+.B H
+Force image data that is read or written to be treated with
+bits filled in the same order as the native
+.SM CPU.
+.TP
+.B M
+Enable the use of memory-mapped files for images opened read-only.
+If the underlying system does not support memory-mapped files
+or if the specific image being opened cannot be memory-mapped
+then the library will fallback to using the normal system interface
+for reading information.
+By default the library will attempt to use memory-mapped files.
+.TP
+.B m
+Disable the use of memory-mapped files.
+.TP
+.B C
+Enable the use of ``strip chopping'' when reading images
+that are comprised of a single strip or tile of uncompressed data.
+Strip chopping is a mechanism by which the library will automatically
+convert the single-strip image to multiple strips,
+each of which has about 8 Kilobytes of data.
+This facility can be useful in reducing the amount of memory used
+to read an image because the library normally reads each strip
+in its entirety.
+Strip chopping does however alter the apparent contents of the
+image because when an image is divided into multiple strips it
+looks as though the underlying file contains multiple separate
+strips.
+Finally, note that default handling of strip chopping is a compile-time
+configuration parameter.
+The default behaviour, for backwards compatibility, is to enable
+strip chopping.
+.TP
+.B c
+Disable the use of strip chopping when reading images.
+.TP
+.B h
+Read TIFF header only, do not load the first image directory. That could be
+useful in case of the broken first directory. We can open the file and proceed
+to the other directories.
+.SH "BYTE ORDER"
+The
+.SM TIFF
+specification (\fBall versions\fP) states that compliant readers
+.IR "must be capable of reading images written in either byte order" .
+Nonetheless some software that claims to support the reading of
+.SM TIFF
+images is incapable of reading images in anything but the native
+.SM CPU
+byte order on which the software was written.
+(Especially notorious
+are applications written to run on Intel-based machines.)
+By default the library will create new files with the native
+byte-order of the
+.SM CPU
+on which the application is run.
+This ensures optimal performance and is portable to any application
+that conforms to the TIFF specification.
+To force the library to use a specific byte-order when creating
+a new file the ``b'' and ``l'' option flags may be included in
+the call to open a file; for example, ``wb'' or ``wl''.
+.SH "RETURN VALUES"
+Upon successful completion
+.IR TIFFOpen ,
+.IR TIFFFdOpen ,
+and
+.IR TIFFClientOpen
+return a
+.SM TIFF
+pointer.
+Otherwise, NULL is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+Likewise, warning messages are directed to the
+.IR TIFFWarning (3TIFF)
+routine.
+.PP
+\fB"%s": Bad mode\fP.
+The specified
+.I mode
+parameter was not one of ``r'' (read), ``w'' (write), or ``a'' (append).
+.PP
+.BR "%s: Cannot open" .
+.IR TIFFOpen ()
+was unable to open the specified filename for read/writing.
+.PP
+.BR "Cannot read TIFF header" .
+An error occurred while attempting to read the header information.
+.PP
+.BR "Error writing TIFF header" .
+An error occurred while writing the default header information
+for a new file.
+.PP
+.BR "Not a TIFF file, bad magic number %d (0x%x)" .
+The magic number in the header was not (hex)
+0x4d4d or (hex) 0x4949.
+.PP
+.BR "Not a TIFF file, bad version number %d (0x%x)" .
+The version field in the header was not 42 (decimal).
+.PP
+.BR "Cannot append to file that has opposite byte ordering" .
+A file with a byte ordering opposite to the native byte
+ordering of the current machine was opened for appending (``a'').
+This is a limitation of the library.
+.SH "SEE ALSO"
+.IR libtiff (3TIFF),
+.IR TIFFClose (3TIFF)
diff --git a/tiff/man/TIFFPrintDirectory.3tiff b/tiff/man/TIFFPrintDirectory.3tiff
new file mode 100644
index 0000000..73cc734
--- /dev/null
+++ b/tiff/man/TIFFPrintDirectory.3tiff
@@ -0,0 +1,70 @@
+.\" $Id: TIFFPrintDirectory.3tiff,v 1.1 2004/11/11 14:39:16 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFPrintDirectory 3TIFF "December 12, 1991" "libtiff"
+.SH NAME
+TIFFPrintDirectory \- print a description of a
+.SM TIFF
+directory
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "void TIFFPrintDirectory(TIFF *" tif ", FILE *" fd ", long " flags ")"
+.SH DESCRIPTION
+.I TIFFPrintDirectory
+prints a description of the current directory in the specified
+.SM TIFF
+file to the standard I/O output stream
+.IR fd .
+The
+.I flags
+parameter is used to control the
+.I "level of detail"
+of the printed information; it is a bit-or of the flags defined in
+.BR tiffio.h :
+.sp .5
+.nf
+.ta \w'#define 'u +\w'TIFFPRINT_JPEGDCTABLES 'u +\w'0x200 'u
+#define TIFFPRINT_NONE 0x0 /* no extra info */
+#define TIFFPRINT_STRIPS 0x1 /* strips/tiles info */
+#define TIFFPRINT_CURVES 0x2 /* color/gray response curves */
+#define TIFFPRINT_COLORMAP 0x4 /* colormap */
+#define TIFFPRINT_JPEGQTABLES 0x100 /* JPEG Q matrices */
+#define TIFFPRINT_JPEGACTABLES 0x200 /* JPEG AC tables */
+#define TIFFPRINT_JPEGDCTABLES 0x200 /* JPEG DC tables */
+.fi
+.SH NOTES
+In C++ the
+.I flags
+parameter defaults to 0.
+.SH "RETURN VALUES"
+None.
+.SH DIAGNOSTICS
+None.
+.SH "SEE ALSO"
+.IR libtiff (3TIFF),
+.IR TIFFOpen (3TIFF),
+.IR TIFFReadDirectory (3TIFF),
+.IR TIFFSetDirectory (3TIFF)
diff --git a/tiff/man/TIFFRGBAImage.3tiff b/tiff/man/TIFFRGBAImage.3tiff
new file mode 100644
index 0000000..5a9f83b
--- /dev/null
+++ b/tiff/man/TIFFRGBAImage.3tiff
@@ -0,0 +1,286 @@
+.\" $Id: TIFFRGBAImage.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFRGBAImage 3TIFF "October 29, 2004" "libtiff"
+.SH NAME
+TIFFRGBAImageOK, TIFFRGBAImageBegin, TIFFRGBAImageGet, TIFFRGBAImageEnd
+\- read and decode an image into a raster
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.B "typedef unsigned char TIFFRGBValue;"
+.B "typedef struct _TIFFRGBAImage TIFFRGBAImage;"
+.sp
+.BI "int TIFFRGBAImageOK(TIFF *" tif ", char " emsg[1024] ")"
+.br
+.BI "int TIFFRGBAImageBegin(TIFFRGBAImage *" img ", TIFF* " tif ", int " stopOnError ", char " emsg[1024] ")"
+.br
+.BI "int TIFFRGBAImageGet(TIFFRGBAImage *" img ", uint32* " raster ", uint32 " width " , uint32 " height ")"
+.br
+.BI "void TIFFRGBAImageEnd(TIFFRGBAImage *" img ")"
+.br
+.SH DESCRIPTION
+The routines described here provide a high-level interface
+through which
+.SM TIFF
+images may be read into memory.
+Images may be strip- or tile-based and have a variety of different
+characteristics: bits/sample, samples/pixel, photometric, etc.
+Decoding state is encapsulated in a
+.I TIFFRGBAImage
+structure making it possible to capture state for multiple images
+and quickly switch between them.
+The target raster format can be customized to a particular application's
+needs by installing custom routines that manipulate image data
+according to application requirements.
+.PP
+The default usage for these routines is: check if an image can
+be processed using
+.IR TIFFRGBAImageOK ,
+construct a decoder state block using
+.IR TIFFRGBAImageBegin ,
+read and decode an image into a target raster using
+.IR TIFFRGBAImageGet ,
+and then
+release resources using
+.IR TIFFRGBAImageEnd .
+.I TIFFRGBAImageGet
+can be called multiple times to decode an image using different
+state parameters.
+If multiple images are to be displayed and there is not enough
+space for each of the decoded rasters, multiple state blocks can
+be managed and then calls can be made to
+.I TIFFRGBAImageGet
+as needed to display an image.
+.PP
+The generated raster is assumed to be an array of
+.I width
+times
+.I height
+32-bit entries, where
+.I width
+must be less than or equal to the width of the image (\c
+.I height
+may be any non-zero size).
+If the raster dimensions are smaller than the image, the image data
+is cropped to the raster bounds.
+If the raster height is greater than that of the image, then the
+image data are placed in the lower part of the raster.
+(Note that the raster is assume to be organized such that the pixel
+at location (\fIx\fP,\fIy\fP) is \fIraster\fP[\fIy\fP*\fIwidth\fP+\fIx\fP];
+with the raster origin in the
+.B lower-left
+hand corner.)
+.PP
+Raster pixels are 8-bit packed red, green, blue, alpha samples.
+The macros
+.IR TIFFGetR ,
+.IR TIFFGetG ,
+.IR TIFFGetB ,
+and
+.I TIFFGetA
+should be used to access individual samples.
+Images without Associated Alpha matting information have a constant
+Alpha of 1.0 (255).
+.PP
+.I TIFFRGBAImageGet
+converts non-8-bit images by scaling sample values.
+Palette, grayscale, bilevel,
+.SM CMYK\c
+, and YCbCr images are converted to
+.SM RGB
+transparently.
+Raster pixels are returned uncorrected by any colorimetry information
+present in the directory.
+.PP
+The parameter
+.I stopOnError
+specifies how to act if an error is encountered while reading
+the image.
+If
+.I stopOnError
+is non-zero, then an error will terminate the operation; otherwise
+.I TIFFRGBAImageGet
+will continue processing data until all the possible data in the
+image have been requested.
+.SH "ALTERNATE RASTER FORMATS"
+To use the core support for reading and processing
+.SM TIFF
+images, but write the resulting raster data in a different format
+one need only override the ``\fIput methods\fP'' used to store raster data.
+These methods are are defined in the
+.I TIFFRGBAImage
+structure and initially setup by
+.I TIFFRGBAImageBegin
+to point to routines that pack raster data in the default
+.SM ABGR
+pixel format.
+Two different routines are used according to the physical organization
+of the image data in the file:
+.IR PlanarConfiguration =1
+(packed samples),
+and
+.IR PlanarConfiguration =2
+(separated samples).
+Note that this mechanism can be used to transform the data before
+storing it in the raster.
+For example one can convert data
+to colormap indices for display on a colormap display.
+.SH "SIMULTANEOUS RASTER STORE AND DISPLAY"
+It is simple to display an image as it is being read into memory
+by overriding the put methods as described above for supporting
+alternate raster formats.
+Simply keep a reference to the default put methods setup by
+.I TIFFRGBAImageBegin
+and then invoke them before or after each display operation.
+For example, the
+.IR tiffgt (1)
+utility uses the following put method to update the display as
+the raster is being filled:
+.sp
+.nf
+.ft C
+static void
+putContigAndDraw(TIFFRGBAImage* img, uint32* raster,
+ uint32 x, uint32 y, uint32 w, uint32 h,
+ int32 fromskew, int32 toskew,
+ unsigned char* cp)
+{
+ (*putContig)(img, raster, x, y, w, h, fromskew, toskew, cp);
+ if (x+w == width) {
+ w = width;
+ if (img->orientation == ORIENTATION_TOPLEFT)
+ lrectwrite(0, y-(h-1), w-1, y, raster-x-(h-1)*w);
+ else
+ lrectwrite(0, y, w-1, y+h-1, raster);
+ }
+}
+.ft R
+.fi
+.sp
+(the original routine provided by the library is saved in the
+variable
+.IR putContig .)
+.SH "SUPPORTING ADDITIONAL TIFF FORMATS"
+The
+.I TIFFRGBAImage
+routines support the most commonly encountered flavors of
+.SM TIFF.
+It is possible to extend this support by overriding the ``\fIget method\fP''
+invoked by
+.I TIFFRGBAImageGet
+to read
+.SM TIFF
+image data.
+Details of doing this are a bit involved, it is best to make a copy
+of an existing get method and modify it to suit the needs of an
+application.
+.SH NOTES
+Samples must be either 1, 2, 4, 8, or 16 bits.
+Colorimetric samples/pixel must be either 1, 3, or 4 (i.e.
+.I SamplesPerPixel
+minus
+.IR ExtraSamples ).
+.PP
+Palette image colormaps that appear to be incorrectly written
+as 8-bit values are automatically scaled to 16-bits.
+.SH "RETURN VALUES"
+All routines return
+1 if the operation was successful.
+Otherwise, 0 is returned if an error was encountered and
+.I stopOnError
+is zero.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+.BR "Sorry, can not handle %d-bit pictures" .
+The image had
+.I BitsPerSample
+other than 1, 2, 4, 8, or 16.
+.PP
+.BR "Sorry, can not handle %d-channel images" .
+The image had
+.I SamplesPerPixel
+other than 1, 3, or 4.
+.PP
+\fBMissing needed "PhotometricInterpretation" tag\fP.
+The image did not have a tag that describes how to display
+the data.
+.PP
+\fBNo "PhotometricInterpretation" tag, assuming RGB\fP.
+The image was missing a tag that describes how to display it,
+but because it has 3 or 4 samples/pixel, it is assumed to be
+.SM RGB.
+.PP
+\fBNo "PhotometricInterpretation" tag, assuming min-is-black\fP.
+The image was missing a tag that describes how to display it,
+but because it has 1 sample/pixel, it is assumed to be a grayscale
+or bilevel image.
+.PP
+.BR "No space for photometric conversion table" .
+There was insufficient memory for a table used to convert
+image samples to 8-bit
+.SM RGB.
+.PP
+\fBMissing required "Colormap" tag\fP.
+A Palette image did not have a required
+.I Colormap
+tag.
+.PP
+.BR "No space for tile buffer" .
+There was insufficient memory to allocate an i/o buffer.
+.PP
+.BR "No space for strip buffer" .
+There was insufficient memory to allocate an i/o buffer.
+.PP
+.BR "Can not handle format" .
+The image has a format (combination of
+.IR BitsPerSample ,
+.IR SamplesPerPixel ,
+and
+.IR PhotometricInterpretation )
+that can not be handled.
+.PP
+.BR "No space for B&W mapping table" .
+There was insufficient memory to allocate a table used to map
+grayscale data to
+.SM RGB.
+.PP
+.BR "No space for Palette mapping table" .
+There was insufficient memory to allocate a table used to map
+data to 8-bit
+.SM RGB.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadRGBAImage (3TIFF),
+.BR TIFFReadRGBAImageOriented (3TIFF),
+.BR TIFFReadRGBAStrip (3TIFF),
+.BR TIFFReadRGBATile (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadDirectory.3tiff b/tiff/man/TIFFReadDirectory.3tiff
new file mode 100644
index 0000000..a86bd82
--- /dev/null
+++ b/tiff/man/TIFFReadDirectory.3tiff
@@ -0,0 +1,164 @@
+.\" $Id: TIFFReadDirectory.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadDirectory 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFReadDirectory \- get the contents of the next directory in an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFReadDirectory(TIFF *" tif ")"
+.SH DESCRIPTION
+Read the next directory in the specified file and make it the current
+directory. Applications only need to call
+.I TIFFReadDirectory
+to read multiple subfiles in a single
+.SM TIFF
+file\(em
+the first directory in a file is automatically read when
+.IR TIFFOpen
+is called.
+.SH NOTES
+If the library is compiled with
+.SM STRIPCHOP_SUPPORT
+enabled, then images that have a single uncompressed strip or tile of data are
+automatically treated as if they were made up of multiple strips or tiles of
+approximately 8 kilobytes each. This operation is done only in-memory; it does
+not alter the contents of the file. However, the construction of the ``chopped
+strips'' is visible to the application through the number of strips [tiles]
+returned by
+.I TIFFNumberOfStrips
+[\c
+.IR TIFFNumberOfTiles ].
+.SH "RETURN VALUES"
+If the next directory was successfully read, 1 is returned. Otherwise, 0 is
+returned if an error was encountered, or if there are no more directories to
+be read.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+All warning messages are directed to the
+.IR TIFFWarning (3TIFF)
+routine.
+.PP
+\fBSeek error accessing TIFF directory\fP.
+An error occurred while positioning to the location of the
+directory.
+.PP
+\fBWrong data type %d for field "%s"\fP.
+The tag entry in the directory had an incorrect data type.
+For example, an
+.I ImageDescription
+tag with a
+.SM SHORT
+data type.
+.PP
+\fBTIFF directory is missing required "%s" field\fP.
+The specified tag is required to be present by the
+.SM TIFF
+5.0 specification, but is missing.
+The directory is (usually) unusable.
+.PP
+\fB%s: Rational with zero denominator\fP.
+A directory tag has a
+.SM RATIONAL
+value whose denominator is zero.
+.PP
+\fBIncorrect count %d for field "%s" (%lu, expecting %lu); tag ignored\fP.
+The specified tag's count field is bad.
+For example, a count other than 1 for a
+.I SubFileType
+tag.
+.PP
+\fBCannot handle different per-sample values for field "%s"\fP.
+The tag has
+.I SamplesPerPixel
+values and they are not all the same; e.g.
+.IR BitsPerSample .
+The library is unable to handle images of this sort.
+.PP
+\fBCount mismatch for field "%s"; expecting %d, got %d\fP.
+The count field in a
+tag does not agree with the number expected by the library.
+This should never happen, so if it does, the library refuses to
+read the directory.
+.PP
+\fBInvalid TIFF directory; tags are not sorted in ascending order\fP.
+The directory tags are not properly sorted as specified
+in the
+.SM TIFF
+5.0 specification.
+This error is not fatal.
+.PP
+\fBIgnoring unknown field with tag %d (0x%x)\fP.
+An unknown tag was encountered in the directory;
+the library ignores all such tags.
+.PP
+\fBTIFF directory is missing requred "ImageLength" field\fP.
+The image violates the specification by not having a necessary field.
+There is no way for the library to recover from this error.
+.PP
+\fBTIFF directory is missing requred "PlanarConfig" field\fP.
+The image violates the specification by not having a necessary field.
+There is no way for the library to recover from this error.
+.PP
+\fBTIFF directory is missing requred "StripOffsets" field\fP.
+The image has multiple strips, but is missing the tag that
+specifies the file offset to each strip of data.
+There is no way for the library to recover from this error.
+.PP
+\fBTIFF directory is missing requred "TileOffsets" field\fP.
+The image has multiple tiles, but is missing the tag that
+specifies the file offset to each tile of data.
+There is no way for the library to recover from this error.
+.PP
+\fBTIFF directory is missing required "StripByteCounts" field\fP.
+The image has multiple strips, but is missing the tag that
+specifies the size of each strip of data.
+There is no way for the library to recover from this error.
+.PP
+\fBTIFF directory is missing required "StripByteCounts" field, calculating from imagelength\fP.
+The image violates the specification by not having a necessary field.
+However, when the image is comprised of only one strip or tile, the
+library will estimate the missing value based on the file size.
+.PP
+\fBBogus "StripByteCounts" field, ignoring and calculating from imagelength\fP.
+Certain vendors violate the specification by writing zero for
+the StripByteCounts tag when they want to leave the value
+unspecified.
+If the image has a single strip, the library will estimate
+the missing value based on the file size.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFWriteDirectory (3TIFF),
+.BR TIFFSetDirectory (3TIFF),
+.BR TIFFSetSubDirectory (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadEncodedStrip.3tiff b/tiff/man/TIFFReadEncodedStrip.3tiff
new file mode 100644
index 0000000..83a2644
--- /dev/null
+++ b/tiff/man/TIFFReadEncodedStrip.3tiff
@@ -0,0 +1,78 @@
+.\" $Id: TIFFReadEncodedStrip.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadEncodedStrip 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFReadEncodedStrip \- read and decode a strip of data from an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFReadEncodedStrip(TIFF *" tif ", tstrip_t " strip ", tdata_t " buf ", tsize_t " size ")"
+.SH DESCRIPTION
+Read the specified strip of data and place up to
+.I size
+bytes of decompressed information in the (user supplied) data buffer.
+.SH NOTES
+The value of
+.I strip
+is a ``raw strip number.''
+That is, the caller must take into account whether or not the data are
+organized in separate planes (\c
+.IR PlanarConfiguration =2).
+To read a full strip of data the data buffer should typically be at least as
+large as the number returned by
+.BR TIFFStripSize (3TIFF).
+If the -1 passed in
+.I size
+parameter, the whole strip will be read. You should be sure you have enough
+space allocated for the buffer.
+.PP
+The library attempts to hide bit- and byte-ordering differences between the
+image and the native machine by converting data to the native machine order.
+Bit reversal is done if the
+.I FillOrder
+tag is opposite to the native machine bit order. 16- and 32-bit samples are
+automatically byte-swapped if the file was written with a byte order opposite
+to the native machine byte order,
+.SH "RETURN VALUES"
+The actual number of bytes of data that were placed in
+.I buf
+is returned;
+.IR TIFFReadEncodedStrip
+returns \-1 if an error was encountered.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadRawStrip (3TIFF),
+.BR TIFFReadScanline (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadEncodedTile.3tiff b/tiff/man/TIFFReadEncodedTile.3tiff
new file mode 100644
index 0000000..c97d6d7
--- /dev/null
+++ b/tiff/man/TIFFReadEncodedTile.3tiff
@@ -0,0 +1,76 @@
+.\" $Id: TIFFReadEncodedTile.3tiff,v 1.3 2006/10/13 07:22:01 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadEncodedTile 3TIFF "October 13, 2006" "libtiff"
+.SH NAME
+TIFFReadEncodedTile \- read and decode a tile of data from an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFReadEncodedTile(TIFF *" tif ", ttile_t " tile ", tdata_t " buf ", tsize_t " size ")"
+.SH DESCRIPTION
+Read the specified tile of data and place up to
+.I size
+bytes of decompressed information in the (user supplied) data buffer.
+.SH NOTES
+The value of
+.I tile
+is a ``raw tile number.''
+That is, the caller must take into account whether or not the data are
+organized in separate planes (\c
+.IR PlanarConfiguration =2).
+.IR TIFFComputeTile
+automatically does this when converting an (x,y,z,sample) coordinate quadruple
+to a tile number. To read a full tile of data the data buffer should be at
+least as large as the value returned by
+.IR TIFFTileSize .
+.PP
+The library attempts to hide bit- and byte-ordering differences between the
+image and the native machine by converting data to the native machine order.
+Bit reversal is done if the
+.I FillOrder
+tag is opposite to the native machine bit order. 16- and 32-bit samples are
+automatically byte-swapped if the file was written with a byte order opposite
+to the native machine byte order,
+.SH "RETURN VALUES"
+The actual number of bytes of data that were placed in
+.I buf
+is returned;
+.IR TIFFReadEncodedTile
+returns \-1 if an error was encountered.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadRawTile (3TIFF),
+.BR TIFFReadTile (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadRGBAImage.3tiff b/tiff/man/TIFFReadRGBAImage.3tiff
new file mode 100644
index 0000000..d2fe330
--- /dev/null
+++ b/tiff/man/TIFFReadRGBAImage.3tiff
@@ -0,0 +1,218 @@
+.\" $Id: TIFFReadRGBAImage.3tiff,v 1.4 2006/10/13 07:22:01 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadRGBAImage 3TIFF "October 13, 2006" "libtiff"
+.SH NAME
+TIFFReadRGBAImage, TIFFReadRGBAImageOriented \- read and decode an image
+into a fixed-format raster
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.B "#define TIFFGetR(abgr) ((abgr) & 0xff)"
+.br
+.B "#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff)"
+.br
+.B "#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff)"
+.br
+.B "#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff)"
+.sp
+.BI "int TIFFReadRGBAImage(TIFF *" tif ", uint32 " width ", uint32 " height ", uint32 *" raster ", int " stopOnError ")"
+.br
+.BI "int TIFFReadRGBAImageOriented(TIFF *" tif ", uint32 " width ", uint32 " height ", uint32 *" raster ", int " orientation ", int " stopOnError ")"
+.br
+.SH DESCRIPTION
+.IR TIFFReadRGBAImage
+reads a strip- or tile-based image into memory, storing the
+result in the user supplied
+.IR raster .
+The raster is assumed to be an array of
+.I width
+times
+.I height
+32-bit entries, where
+.I width
+must be less than or equal to the width of the image (\c
+.I height
+may be any non-zero size).
+If the raster dimensions are smaller than the image, the image data
+is cropped to the raster bounds.
+If the raster height is greater than that of the image, then the
+image data are placed in the lower part of the raster.
+(Note that the raster is assume to be organized such that the pixel
+at location (\fIx\fP,\fIy\fP) is \fIraster\fP[\fIy\fP*\fIwidth\fP+\fIx\fP];
+with the raster origin in the lower-left hand corner.)
+.PP
+.IR TIFFReadRGBAImageOriented
+works like
+.IR TIFFReadRGBAImage
+with except of that user can specify the raster origin position with the
+.I orientation
+parameter. Four orientations supported:
+.TP
+.B ORIENTATION_TOPLEFT
+origin in top-left corner,
+.TP
+.B ORIENTATION_TOPRIGHT
+origin in top-right corner,
+.TP
+.B ORIENTATION_BOTLEFT
+origin in bottom-left corner
+and
+.TP
+.B ORIENTATION_BOTRIGHT
+origin in bottom-right corner.
+.LP
+If you choose
+.B ORIENTATION_BOTLEFT
+result will be the same as returned by the
+.IR TIFFReadRGBAImage.
+.PP
+Raster pixels are 8-bit packed red, green, blue, alpha samples.
+The macros
+.IR TIFFGetR ,
+.IR TIFFGetG ,
+.IR TIFFGetB ,
+and
+.I TIFFGetA
+should be used to access individual samples.
+Images without Associated Alpha matting information have a constant
+Alpha of 1.0 (255).
+.PP
+.I TIFFReadRGBAImage
+converts non-8-bit images by scaling sample values.
+Palette, grayscale, bilevel,
+.SM CMYK\c
+, and YCbCr images are converted to
+.SM RGB
+transparently.
+Raster pixels are returned uncorrected by any colorimetry information
+present in the directory.
+.PP
+The paramater
+.I stopOnError
+specifies how to act if an error is encountered while reading
+the image.
+If
+.I stopOnError
+is non-zero, then an error will terminate the operation; otherwise
+.I TIFFReadRGBAImage
+will continue processing data until all the possible data in the
+image have been requested.
+.SH NOTES
+In C++ the
+.I stopOnError
+parameter defaults to 0.
+.PP
+Samples must be either 1, 2, 4, 8, or 16 bits.
+Colorimetric samples/pixel must be either 1, 3, or 4 (i.e.
+.I SamplesPerPixel
+minus
+.IR ExtraSamples ).
+.PP
+Palettte image colormaps that appear to be incorrectly written
+as 8-bit values are automatically scaled to 16-bits.
+.PP
+.I TIFFReadRGBAImage
+is just a wrapper around the more general
+.IR TIFFRGBAImage (3TIFF)
+facilities.
+.SH "RETURN VALUES"
+1 is returned if the image was successfully read and converted.
+Otherwise, 0 is returned if an error was encountered and
+.I stopOnError
+is zero.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+.BR "Sorry, can not handle %d-bit pictures" .
+The image had
+.I BitsPerSample
+other than 1, 2, 4, 8, or 16.
+.PP
+.BR "Sorry, can not handle %d-channel images" .
+The image had
+.I SamplesPerPixel
+other than 1, 3, or 4.
+.PP
+\fBMissing needed "PhotometricInterpretation" tag\fP.
+The image did not have a tag that describes how to display
+the data.
+.PP
+\fBNo "PhotometricInterpretation" tag, assuming RGB\fP.
+The image was missing a tag that describes how to display it,
+but because it has 3 or 4 samples/pixel, it is assumed to be
+.SM RGB.
+.PP
+\fBNo "PhotometricInterpretation" tag, assuming min-is-black\fP.
+The image was missing a tag that describes how to display it,
+but because it has 1 sample/pixel, it is assumed to be a grayscale
+or bilevel image.
+.PP
+.BR "No space for photometric conversion table" .
+There was insufficient memory for a table used to convert
+image samples to 8-bit
+.SM RGB.
+.PP
+\fBMissing required "Colormap" tag\fP.
+A Palette image did not have a required
+.I Colormap
+tag.
+.PP
+.BR "No space for tile buffer" .
+There was insufficient memory to allocate an i/o buffer.
+.PP
+.BR "No space for strip buffer" .
+There was insufficient memory to allocate an i/o buffer.
+.PP
+.BR "Can not handle format" .
+The image has a format (combination of
+.IR BitsPerSample ,
+.IR SamplesPerPixel ,
+and
+.IR PhotometricInterpretation )
+that
+.I TIFFReadRGBAImage
+can not handle.
+.PP
+.BR "No space for B&W mapping table" .
+There was insufficient memory to allocate a table used to map
+grayscale data to
+.SM RGB.
+.PP
+.BR "No space for Palette mapping table" .
+There was insufficient memory to allocate a table used to map
+data to 8-bit
+.SM RGB.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFRGBAImage (3TIFF),
+.BR TIFFReadRGBAStrip (3TIFF),
+.BR TIFFReadRGBATile (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadRGBAStrip.3tiff b/tiff/man/TIFFReadRGBAStrip.3tiff
new file mode 100644
index 0000000..2d8b067
--- /dev/null
+++ b/tiff/man/TIFFReadRGBAStrip.3tiff
@@ -0,0 +1,170 @@
+.\" $Id: TIFFReadRGBAStrip.3tiff,v 1.3 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadRGBAStrip 3TIFF "December 10, 1998" "libtiff"
+.SH NAME
+TIFFReadRGBAStrip \- read and decode an image strip into a fixed-format raster
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.B "#define TIFFGetR(abgr) ((abgr) & 0xff)"
+.br
+.B "#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff)"
+.br
+.B "#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff)"
+.br
+.B "#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff)"
+.sp
+.BI "int TIFFReadRGBAStrip(TIFF *" tif ", uint32 " row ", uint32 *" raster ")"
+.SH DESCRIPTION
+.IR TIFFReadRGBAStrip
+reads a single strip of a strip-based image into memory, storing the result in
+the user supplied RGBA
+.IR raster .
+The raster is assumed to be an array of width times rowsperstrip 32-bit
+entries, where width is the width of the image (TIFFTAG_IMAGEWIDTH) and
+rowsperstrip is the maximum lines in a strip (TIFFTAG_ROWSPERSTRIP).
+
+.PP
+The
+.IR row
+value should be the row of the first row in the strip (strip * rowsperstrip,
+zero based).
+
+.PP
+Note that the raster is assume to be organized such that the pixel at location
+(\fIx\fP,\fIy\fP) is \fIraster\fP[\fIy\fP*\fIwidth\fP+\fIx\fP]; with the
+raster origin in the
+.I lower-left hand corner
+of the strip. That is bottom to top organization. When reading a partial last
+strip in the file the last line of the image will begin at the beginning of
+the buffer.
+
+.PP
+Raster pixels are 8-bit packed red, green, blue, alpha samples. The macros
+.IR TIFFGetR ,
+.IR TIFFGetG ,
+.IR TIFFGetB ,
+and
+.I TIFFGetA
+should be used to access individual samples. Images without Associated Alpha
+matting information have a constant Alpha of 1.0 (255).
+.PP
+See the
+.IR TIFFRGBAImage (3TIFF)
+page for more details on how various image types are converted to RGBA values.
+.SH NOTES
+Samples must be either 1, 2, 4, 8, or 16 bits. Colorimetric samples/pixel must
+be either 1, 3, or 4 (i.e.
+.I SamplesPerPixel
+minus
+.IR ExtraSamples ).
+.PP
+Palette image colormaps that appear to be incorrectly written as 8-bit values
+are automatically scaled to 16-bits.
+.PP
+.I TIFFReadRGBAStrip
+is just a wrapper around the more general
+.IR TIFFRGBAImage (3TIFF)
+facilities. It's main advantage over the similar
+.IR TIFFReadRGBAImage()
+function is that for large images a single buffer capable of holding the whole
+image doesn't need to be allocated, only enough for one strip. The
+.IR TIFFReadRGBATile()
+function does a similar operation for tiled images.
+.SH "RETURN VALUES"
+1 is returned if the image was successfully read and converted.
+Otherwise, 0 is returned if an error was encountered.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+.BR "Sorry, can not handle %d-bit pictures" .
+The image had
+.I BitsPerSample
+other than 1, 2, 4, 8, or 16.
+.PP
+.BR "Sorry, can not handle %d-channel images" .
+The image had
+.I SamplesPerPixel
+other than 1, 3, or 4.
+.PP
+\fBMissing needed "PhotometricInterpretation" tag\fP.
+The image did not have a tag that describes how to display the data.
+.PP
+\fBNo "PhotometricInterpretation" tag, assuming RGB\fP.
+The image was missing a tag that describes how to display it, but because it
+has 3 or 4 samples/pixel, it is assumed to be
+.SM RGB.
+.PP
+\fBNo "PhotometricInterpretation" tag, assuming min-is-black\fP. The image was
+missing a tag that describes how to display it, but because it has 1
+sample/pixel, it is assumed to be a grayscale or bilevel image.
+.PP
+.BR "No space for photometric conversion table" .
+There was insufficient memory for a table used to convert image samples to
+8-bit
+.SM RGB.
+.PP
+\fBMissing required "Colormap" tag\fP.
+A Palette image did not have a required
+.I Colormap
+tag.
+.PP
+.BR "No space for tile buffer" .
+There was insufficient memory to allocate an i/o buffer.
+.PP
+.BR "No space for strip buffer" .
+There was insufficient memory to allocate an i/o buffer.
+.PP
+.BR "Can not handle format" .
+The image has a format (combination of
+.IR BitsPerSample ,
+.IR SamplesPerPixel ,
+and
+.IR PhotometricInterpretation )
+that
+.I TIFFReadRGBAImage
+can not handle.
+.PP
+.BR "No space for B&W mapping table" .
+There was insufficient memory to allocate a table used to map grayscale data
+to
+.SM RGB.
+.PP
+.BR "No space for Palette mapping table" .
+There was insufficient memory to allocate a table used to map data to 8-bit
+.SM RGB.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFRGBAImage (3TIFF),
+.BR TIFFReadRGBAImage (3TIFF),
+.BR TIFFReadRGBATile (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
+
diff --git a/tiff/man/TIFFReadRGBATile.3tiff b/tiff/man/TIFFReadRGBATile.3tiff
new file mode 100644
index 0000000..9b52f3d
--- /dev/null
+++ b/tiff/man/TIFFReadRGBATile.3tiff
@@ -0,0 +1,171 @@
+.\" $Id: TIFFReadRGBATile.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadRGBATile 3TIFF "December 10, 1998" "libtiff"
+.SH NAME
+TIFFReadRGBATile \- read and decode an image tile into a fixed-format raster
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.B "#define TIFFGetR(abgr) ((abgr) & 0xff)"
+.br
+.B "#define TIFFGetG(abgr) (((abgr) >> 8) & 0xff)"
+.br
+.B "#define TIFFGetB(abgr) (((abgr) >> 16) & 0xff)"
+.br
+.B "#define TIFFGetA(abgr) (((abgr) >> 24) & 0xff)"
+.sp
+.BI "int TIFFReadRGBATile(TIFF *" tif ", uint32 " x ", uint32 " y ", uint32 *" raster ")"
+.SH DESCRIPTION
+.IR TIFFReadRGBATile
+reads a single tile of a tile-based image into memory, storing the result in
+the user supplied RGBA
+.IR raster .
+The raster is assumed to be an array of width times length 32-bit entries,
+where width is the width of a tile (TIFFTAG_TILEWIDTH) and length is the
+height of a tile (TIFFTAG_TILELENGTH).
+
+.PP
+The
+.IR x
+and
+.IR y
+values are the offsets from the top left corner to the top left corner of the
+tile to be read. They must be an exact multiple of the tile width and length.
+
+.PP
+Note that the raster is assume to be organized such that the pixel at location
+(\fIx\fP,\fIy\fP) is \fIraster\fP[\fIy\fP*\fIwidth\fP+\fIx\fP]; with the
+raster origin in the
+.I lower-left hand corner
+of the tile. That is bottom to top organization. Edge tiles which partly fall
+off the image will be filled out with appropriate zeroed areas.
+
+.PP
+Raster pixels are 8-bit packed red, green, blue, alpha samples. The macros
+.IR TIFFGetR ,
+.IR TIFFGetG ,
+.IR TIFFGetB ,
+and
+.I TIFFGetA
+should be used to access individual samples. Images without Associated Alpha
+matting information have a constant Alpha of 1.0 (255).
+.PP
+See the
+.IR TIFFRGBAImage (3TIFF)
+page for more details on how various image types are converted to RGBA values.
+.SH NOTES
+Samples must be either 1, 2, 4, 8, or 16 bits. Colorimetric samples/pixel must
+be either 1, 3, or 4 (i.e.
+.I SamplesPerPixel
+minus
+.IR ExtraSamples ).
+.PP
+Palette image colormaps that appear to be incorrectly written as 8-bit values
+are automatically scaled to 16-bits.
+.PP
+.I TIFFReadRGBATile
+is just a wrapper around the more general
+.IR TIFFRGBAImage (3TIFF)
+facilities. It's main advantage over the similar
+.IR TIFFReadRGBAImage()
+function is that for large images a single buffer capable of holding the whole
+image doesn't need to be allocated, only enough for one tile. The
+.IR TIFFReadRGBAStrip()
+function does a similar operation for stripped images.
+.SH "RETURN VALUES"
+1 is returned if the image was successfully read and converted.
+Otherwise, 0 is returned if an error was encountered.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+.BR "Sorry, can not handle %d-bit pictures" .
+The image had
+.I BitsPerSample
+other than 1, 2, 4, 8, or 16.
+.PP
+.BR "Sorry, can not handle %d-channel images" .
+The image had
+.I SamplesPerPixel
+other than 1, 3, or 4.
+.PP
+\fBMissing needed "PhotometricInterpretation" tag\fP.
+The image did not have a tag that describes how to display the data.
+.PP
+\fBNo "PhotometricInterpretation" tag, assuming RGB\fP.
+The image was missing a tag that describes how to display it, but because it
+has 3 or 4 samples/pixel, it is assumed to be
+.SM RGB.
+.PP
+\fBNo "PhotometricInterpretation" tag, assuming min-is-black\fP.
+The image was missing a tag that describes how to display it,
+but because it has 1 sample/pixel, it is assumed to be a grayscale
+or bilevel image.
+.PP
+.BR "No space for photometric conversion table" .
+There was insufficient memory for a table used to convert
+image samples to 8-bit
+.SM RGB.
+.PP
+\fBMissing required "Colormap" tag\fP.
+A Palette image did not have a required
+.I Colormap
+tag.
+.PP
+.BR "No space for tile buffer" .
+There was insufficient memory to allocate an i/o buffer.
+.PP
+.BR "No space for strip buffer" .
+There was insufficient memory to allocate an i/o buffer.
+.PP
+.BR "Can not handle format" .
+The image has a format (combination of
+.IR BitsPerSample ,
+.IR SamplesPerPixel ,
+and
+.IR PhotometricInterpretation )
+that
+.I TIFFReadRGBAImage
+can not handle.
+.PP
+.BR "No space for B&W mapping table" .
+There was insufficient memory to allocate a table used to map
+grayscale data to
+.SM RGB.
+.PP
+.BR "No space for Palette mapping table" .
+There was insufficient memory to allocate a table used to map data to 8-bit
+.SM RGB.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFRGBAImage (3TIFF),
+.BR TIFFReadRGBAImage (3TIFF),
+.BR TIFFReadRGBAStrip (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadRawStrip.3tiff b/tiff/man/TIFFReadRawStrip.3tiff
new file mode 100644
index 0000000..1d4cac8
--- /dev/null
+++ b/tiff/man/TIFFReadRawStrip.3tiff
@@ -0,0 +1,64 @@
+.\" $Id: TIFFReadRawStrip.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadRawStrip 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFReadRawStrip \- return the undecoded contents of a strip of data from an
+open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFReadRawStrip(TIFF *" tif ", tstrip_t " strip ", tdata_t " buf ", tsize_t " size ")"
+.SH DESCRIPTION
+Read the contents of the specified strip into the (user supplied) data buffer.
+Note that the value of
+.I strip
+is a ``raw strip number.'' That is, the caller must take into account whether
+or not the data is organized in separate planes (\c
+.IR PlanarConfiguration =2).
+To read a full strip of data the data buffer should typically be at least as
+large as the number returned by
+.IR TIFFStripSize .
+.SH "RETURN VALUES"
+The actual number of bytes of data that were placed in
+.I buf
+is returned;
+.IR TIFFReadEncodedStrip
+returns \-1 if an error was encountered.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadEncodedStrip (3TIFF),
+.BR TIFFReadScanline (3TIFF),
+.BR TIFFStripSize (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadRawTile.3tiff b/tiff/man/TIFFReadRawTile.3tiff
new file mode 100644
index 0000000..5d4a56e
--- /dev/null
+++ b/tiff/man/TIFFReadRawTile.3tiff
@@ -0,0 +1,65 @@
+.\" $Id: TIFFReadRawTile.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadRawTile 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFReadRawTile \- return an undecoded tile of data from an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFReadRawTile(TIFF *" tif ", ttile_t " tile ", tdata_t " buf ", tsize_t " size ")"
+.SH DESCRIPTION
+Read the contents of the specified tile into the (user supplied) data buffer.
+Note that the value of
+.I tile
+is a ``raw tile number.'' That is, the caller must take into account whether
+or not the data is organized in separate planes (\c
+.IR PlanarConfiguration =2).
+.I TIFFComputeTile
+automatically does this when converting an (x,y,z,sample) coordinate quadruple
+to a tile number. To read a full tile of data the data buffer should typically
+be at least as large as the value returned by
+.IR TIFFTileSize .
+.SH "RETURN VALUES"
+The actual number of bytes of data that were placed in
+.I buf
+is returned;
+.IR TIFFReadEncodedTile
+returns \-1 if an error was encountered.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadEncodedTile (3TIFF),
+.BR TIFFReadTile (3TIFF),
+.BR TIFFTileSize (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadScanline.3tiff b/tiff/man/TIFFReadScanline.3tiff
new file mode 100644
index 0000000..0a46d58
--- /dev/null
+++ b/tiff/man/TIFFReadScanline.3tiff
@@ -0,0 +1,94 @@
+.\" $Id: TIFFReadScanline.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadScanline 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFReadScanline \- read and decode a scanline of data from an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFReadScanline(TIFF *" tif ", tdata_t " buf ", uint32 " row ", tsample_t " sample ")"
+.SH DESCRIPTION
+Read the data for the specified row into the (user supplied) data buffer
+.IR buf .
+The data are returned decompressed and, in the native byte- and bit-ordering,
+but are otherwise packed (see further below). The buffer must be large enough
+to hold an entire scanline of data. Applications should call the routine
+.IR TIFFScanlineSize
+to find out the size (in bytes) of a scanline buffer.
+The
+.I row
+parameter is always used by
+.IR TIFFReadScanline ;
+the
+.I sample
+parameter is used only if data are organized in separate planes (\c
+.IR PlanarConfiguration =2).
+.SH NOTES
+The library attempts to hide bit- and byte-ordering differences between the
+image and the native machine by converting data to the native machine order.
+Bit reversal is done if the
+.I FillOrder
+tag is opposite to the native machine bit order. 16- and 32-bit samples are
+automatically byte-swapped if the file was written with a byte order opposite
+to the native machine byte order,
+.PP
+In C++ the
+.I sample
+parameter defaults to 0.
+.SH "RETURN VALUES"
+.IR TIFFReadScanline
+returns \-1 if it detects an error; otherwise 1 is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+.BR "Compression algorithm does not support random access" .
+Data was requested in a non-sequential order from a file that uses a
+compression algorithm and that has
+.I RowsPerStrip
+greater than one.
+That is, data in the image is stored in a compressed form, and with multiple
+rows packed into a strip. In this case, the library does not support random
+access to the data. The data should either be accessed sequentially, or the
+file should be converted so that each strip is made up of one row of data.
+.SH BUGS
+Reading subsampled YCbCR data does not work correctly because, for
+.IR PlanarConfiguration =2
+the size of a scanline is not calculated on a per-sample basis, and for
+.IR PlanarConfiguration =1
+the library does not unpack the block-interleaved samples; use the strip- and
+tile-based interfaces to read these formats.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadEncodedStrip (3TIFF),
+.BR TIFFReadRawStrip (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFReadTile.3tiff b/tiff/man/TIFFReadTile.3tiff
new file mode 100644
index 0000000..512092d
--- /dev/null
+++ b/tiff/man/TIFFReadTile.3tiff
@@ -0,0 +1,84 @@
+.\" $Id: TIFFReadTile.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFReadTile 3TIFF "December 16, 1991" "libtiff"
+.SH NAME
+TIFFReadTile \- read and decode a tile of data from an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFReadTile(TIFF *" tif ", tdata_t " buf ", uint32 " x ", uint32 " y ", uint32 " z ", tsample_t " sample ")"
+.SH DESCRIPTION
+Return the data for the tile
+.I containing
+the specified coordinates. The data placed in
+.I buf
+are returned decompressed and, typically, in the native byte- and
+bit-ordering, but are otherwise packed (see further below). The buffer must be
+large enough to hold an entire tile of data. Applications should call the
+routine
+.IR TIFFTileSize
+to find out the size (in bytes) of a tile buffer. The
+.I x
+and
+.I y
+parameters are always used by
+.IR TIFFReadTile .
+The
+.I z
+parameter is used if the image is deeper than 1 slice (\c
+.IR ImageDepth >1).
+The
+.I sample
+parameter is used only if data are organized in separate planes (\c
+.IR PlanarConfiguration =2).
+.SH NOTES
+The library attempts to hide bit- and byte-ordering differences between the
+image and the native machine by converting data to the native machine order.
+Bit reversal is done if the
+.I FillOrder
+tag is opposite to the native machine bit order. 16- and 32-bit samples are
+automatically byte-swapped if the file was written with a byte order opposite
+to the native machine byte order,
+.SH "RETURN VALUES"
+.IR TIFFReadTile
+returns \-1 if it detects an error; otherwise the number of bytes in the
+decoded tile is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.SH "SEE ALSO"
+.BR TIFFCheckTile (3TIFF),
+.BR TIFFComputeTile (3TIFF),
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadEncodedTile (3TIFF),
+.BR TIFFReadRawTile (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFSetDirectory.3tiff b/tiff/man/TIFFSetDirectory.3tiff
new file mode 100644
index 0000000..cdd8e46
--- /dev/null
+++ b/tiff/man/TIFFSetDirectory.3tiff
@@ -0,0 +1,79 @@
+.\" $Id: TIFFSetDirectory.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFSetDirectory 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFSetDirectory, TIFFSetSubDirectory \- set the current directory for an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFSetDirectory(TIFF *" tif ", tdir_t " dirnum ")"
+.br
+.BI "int TIFFSetSubDirectory(TIFF *" tif ", uint32 " diroff ")"
+.SH DESCRIPTION
+.I TIFFSetDirectory
+changes the current directory and reads its contents with
+.IR TIFFReadDirectory .
+The parameter
+.I dirnum
+specifies the subfile/directory as an integer number, with the first directory
+numbered zero.
+.PP
+.I TIFFSetSubDirectory
+acts like
+.IR TIFFSetDirectory ,
+except the directory is specified as a file offset instead of an index; this
+is required for accessing subdirectories linked through a
+.I SubIFD
+tag.
+.SH "RETURN VALUES"
+On successful return 1 is returned. Otherwise, 0 is returned if
+.I dirnum
+or
+.I diroff
+specifies a non-existent directory, or if an error was encountered while
+reading the directory's contents.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+.BR "%s: Error fetching directory count" .
+An error was encountered while reading the ``directory count'' field.
+.PP
+.BR "%s: Error fetching directory link" .
+An error was encountered while reading the ``link value'' that points to the
+next directory in a file.
+.SH "SEE ALSO"
+.IR TIFFCurrentDirectory (3TIFF),
+.IR TIFFOpen (3TIFF),
+.IR TIFFReadDirectory (3TIFF),
+.IR TIFFWriteDirectory (3TIFF),
+.IR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFSetField.3tiff b/tiff/man/TIFFSetField.3tiff
new file mode 100644
index 0000000..e7baa8c
--- /dev/null
+++ b/tiff/man/TIFFSetField.3tiff
@@ -0,0 +1,217 @@
+.\" $Id: TIFFSetField.3tiff,v 1.4.2.1 2010-05-06 02:54:43 olivier Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFSetField 3TIFF "October 29, 2004" "libtiff"
+.SH NAME
+TIFFSetField, TIFFVSetField \- set the value(s) of a tag in a
+.SM TIFF
+file open for writing
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFSetField(TIFF *" tif ", ttag_t " tag ", " ... ")"
+.sp
+.B "#include <stdarg.h>"
+.sp
+.BI "int TIFFVSetField(TIFF *" tif ", ttag_t " tag ", va_list " ap ")"
+.SH DESCRIPTION
+.IR TIFFSetField
+sets the value of a field
+or pseudo-tag in the current directory associated with
+the open
+.SM TIFF
+file
+.IR tif .
+(A
+.I pseudo-tag
+is a parameter that is used to control the operation of the
+.SM TIFF
+library but whose value is not read or written to the underlying file.)
+To set the value of a field
+the file must have been previously opened for writing with
+.IR TIFFOpen (3TIFF);
+pseudo-tags can be set whether the file was opened for reading
+or writing.
+The field is identified by
+.IR tag ,
+one of the values defined in the include file
+.B tiff.h
+(see also the table below).
+The actual value is specified using a variable argument list,
+as prescribed by the
+.IR stdarg (3)
+interface (\c
+or, on some machines, the
+.IR varargs (3)
+interface.)
+.PP
+.IR TIFFVSetField
+is functionally equivalent to
+.IR TIFFSetField
+except that it takes a pointer to a variable
+argument list.
+.I TIFFVSetField
+is useful for writing routines that are layered
+on top of the functionality provided by
+.IR TIFFSetField .
+.PP
+The tags understood by
+.IR libtiff ,
+the number of parameter values, and the
+expected types for the parameter values are shown below.
+The data types are:
+.I char*
+is null-terminated string and corresponds to the
+.SM ASCII
+data type;
+.I uint16
+is an unsigned 16-bit value;
+.I uint32
+is an unsigned 32-bit value;
+.I uint16*
+is an array of unsigned 16-bit values.
+.I void*
+is an array of data values of unspecified type.
+
+Consult the
+.SM TIFF
+specification for information on the meaning of each tag.
+.PP
+.nf
+.ta \w'TIFFTAG_CONSECUTIVEBADFAXLINES'u+2n +\w'Count'u+2n +\w'TIFFFaxFillFunc \(dg'u+2n
+\fITag Name\fP \fICount\fP \fITypes\fP \fINotes\fP
+.sp 5p
+TIFFTAG_ARTIST 1 char*
+TIFFTAG_BADFAXLINES 1 uint32
+TIFFTAG_BITSPERSAMPLE 1 uint16 \(dg
+TIFFTAG_CLEANFAXDATA 1 uint16
+TIFFTAG_COLORMAP 3 uint16* 1<<BitsPerSample arrays
+TIFFTAG_COMPRESSION 1 uint16 \(dg
+TIFFTAG_CONSECUTIVEBADFAXLINES 1 uint32
+TIFFTAG_COPYRIGHT 1 char*
+TIFFTAG_DATETIME 1 char*
+TIFFTAG_DOCUMENTNAME 1 char*
+TIFFTAG_DOTRANGE 2 uint16
+TIFFTAG_EXTRASAMPLES 2 uint16,uint16* \(dg count & types array
+TIFFTAG_FAXFILLFUNC 1 TIFFFaxFillFunc G3/G4 compression pseudo-tag
+TIFFTAG_FAXMODE 1 int \(dg G3/G4 compression pseudo-tag
+TIFFTAG_FILLORDER 1 uint16 \(dg
+TIFFTAG_GROUP3OPTIONS 1 uint32 \(dg
+TIFFTAG_GROUP4OPTIONS 1 uint32 \(dg
+TIFFTAG_HALFTONEHINTS 2 uint16
+TIFFTAG_HOSTCOMPUTER 1 char*
+TIFFTAG_ICCPROFILE 2 uint32,void* count, profile data
+TIFFTAG_IMAGEDEPTH 1 uint32 \(dg
+TIFFTAG_IMAGEDESCRIPTION 1 char*
+TIFFTAG_IMAGELENGTH 1 uint32
+TIFFTAG_IMAGEWIDTH 1 uint32 \(dg
+TIFFTAG_INKNAMES 2 uint16, char*
+TIFFTAG_INKSET 1 uint16 \(dg
+TIFFTAG_JPEGCOLORMODE 1 int \(dg JPEG pseudo-tag
+TIFFTAG_JPEGQUALITY 1 int JPEG pseudo-tag
+TIFFTAG_JPEGTABLES 2 uint32*,void* \(dg count & tables
+TIFFTAG_JPEGTABLESMODE 1 int \(dg JPEG pseudo-tag
+TIFFTAG_MAKE 1 char*
+TIFFTAG_MATTEING 1 uint16 \(dg
+TIFFTAG_MAXSAMPLEVALUE 1 uint16
+TIFFTAG_MINSAMPLEVALUE 1 uint16
+TIFFTAG_MODEL 1 char*
+TIFFTAG_ORIENTATION 1 uint16
+TIFFTAG_PAGENAME 1 char*
+TIFFTAG_PAGENUMBER 2 uint16
+TIFFTAG_PHOTOMETRIC 1 uint16
+TIFFTAG_PHOTOSHOP ? uint32,void* count, data
+TIFFTAG_PLANARCONFIG 1 uint16 \(dg
+TIFFTAG_PREDICTOR 1 uint16 \(dg
+TIFFTAG_PRIMARYCHROMATICITIES 1 float* 6-entry array
+TIFFTAG_REFERENCEBLACKWHITE 1 float* \(dg 6-entry array
+TIFFTAG_RESOLUTIONUNIT 1 uint16
+TIFFTAG_RICHTIFFIPTC 2 uint32,void* count, data
+TIFFTAG_ROWSPERSTRIP 1 uint32 \(dg must be > 0
+TIFFTAG_SAMPLEFORMAT 1 uint16 \(dg
+TIFFTAG_SAMPLESPERPIXEL 1 uint16 \(dg value must be <= 4
+TIFFTAG_SMAXSAMPLEVALUE 1 double
+TIFFTAG_SMINSAMPLEVALUE 1 double
+TIFFTAG_SOFTWARE 1 char*
+TIFFTAG_STONITS 1 double \(dg
+TIFFTAG_SUBFILETYPE 1 uint32
+TIFFTAG_SUBIFD 2 uint16,uint32* count & offsets array
+TIFFTAG_TARGETPRINTER 1 char*
+TIFFTAG_THRESHHOLDING 1 uint16
+TIFFTAG_TILEDEPTH 1 uint32 \(dg
+TIFFTAG_TILELENGTH 1 uint32 \(dg must be a multiple of 8
+TIFFTAG_TILEWIDTH 1 uint32 \(dg must be a multiple of 8
+TIFFTAG_TRANSFERFUNCTION 1 or 3\(dd uint16* 1<<BitsPerSample entry arrays
+TIFFTAG_WHITEPOINT 1 float* 2-entry array
+TIFFTAG_XMLPACKET 2 uint32,void* count, data
+TIFFTAG_XPOSITION 1 float
+TIFFTAG_XRESOLUTION 1 float
+TIFFTAG_YCBCRCOEFFICIENTS 1 float* \(dg 3-entry array
+TIFFTAG_YCBCRPOSITIONING 1 uint16 \(dg
+TIFFTAG_YCBCRSAMPLING 2 uint16 \(dg
+TIFFTAG_YPOSITION 1 float
+TIFFTAG_YRESOLUTION 1 float
+.fi
+.sp 5p
+\(dg Tag may not have its values changed once data is written.
+.br
+.fi
+\(dd
+If
+.I SamplesPerPixel
+is one, then a single array is passed; otherwise three arrays should be
+passed.
+.fi
+* The contents of this field are quite complex. See
+.BR "The ICC Profile Format Specification" ,
+Annex B.3 "Embedding ICC Profiles in TIFF Files"
+(available at http://www.color.org) for an explanation.
+.br
+.SH "RETURN VALUES"
+1 is returned if the operation was successful.
+Otherwise, 0 is returned if an error was detected.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.PP
+\fB%s: Cannot modify tag "%s" while writing\fP.
+Data has already been written to the file, so the
+specified tag's value can not be changed.
+This restriction is applied to all tags that affect
+the format of written data.
+.PP
+\fB%d: Bad value for "%s"\fP.
+An invalid value was supplied for the named tag.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFGetField (3TIFF),
+.BR TIFFSetDirectory (3TIFF),
+.BR TIFFWriteDirectory (3TIFF),
+.BR TIFFReadDirectory (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFWarning.3tiff b/tiff/man/TIFFWarning.3tiff
new file mode 100644
index 0000000..0a71429
--- /dev/null
+++ b/tiff/man/TIFFWarning.3tiff
@@ -0,0 +1,70 @@
+.\" $Id: TIFFWarning.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFWarning 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFWarning, TIFFSetWarningHandler \- library warning interface
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "void TIFFWarning(const char *" module ", const char *" fmt ", " ... ")"
+.sp
+.B "#include <stdargh.h>"
+.sp
+.BI "typedef void (*TIFFWarningHandler)(const char *" module ", const char *" fmt ", va_list " ap ");"
+.sp
+.BI "TIFFWarningHandler TIFFSetWarningHandler(TIFFWarningHandler " handler ");"
+.SH DESCRIPTION
+.I TIFFWarning
+invokes the library-wide warning handler function to (normally) write a
+warning message to the
+.BR stderr .
+The
+.I fmt
+parameter is a
+.IR printf (3S)
+format string, and any number arguments can be supplied. The
+.I module
+parameter is interpreted as a string that, if non-zero, should be printed
+before the message; it typically is used to identify the software module in
+which a warning is detected.
+.PP
+Applications that desire to capture control in the event of a warning should
+use
+.IR TIFFSetWarningHandler
+to override the default warning handler.
+A
+.SM NULL
+(0) warning handler function may be installed to suppress error messages.
+.SH "RETURN VALUES"
+.IR TIFFSetWarningHandler
+returns a reference to the previous error handling function.
+.SH "SEE ALSO"
+.BR TIFFError (3TIFF),
+.BR libtiff (3TIFF),
+.BR printf (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFWriteDirectory.3tiff b/tiff/man/TIFFWriteDirectory.3tiff
new file mode 100644
index 0000000..85b267b
--- /dev/null
+++ b/tiff/man/TIFFWriteDirectory.3tiff
@@ -0,0 +1,138 @@
+.\" $Id: TIFFWriteDirectory.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFWriteDirectory 3TIFF "September 26, 2001" "libtiff"
+.SH NAME
+TIFFWriteDirectory, TIFFRewriteDirectory, TIFFCheckpointDirectory \- write the
+current directory in an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFWriteDirectory(TIFF *" tif ")"
+.br
+.BI "int TIFFRewriteDirectory(TIFF *" tif ")"
+.br
+.BI "int TIFFCheckpointDirectory(TIFF *" tif ")"
+.SH DESCRIPTION
+.IR TIFFWriteDirectory
+will write the contents of the current directory to the file and setup to
+create a new subfile in the same file. Applications only need to call
+.IR TIFFWriteDirectory
+when writing multiple subfiles to a single
+.SM TIFF
+file.
+.IR TIFFWriteDirectory
+is automatically called by
+.IR TIFFClose
+and
+.IR TIFFFlush
+to write a modified directory if the file is open for writing.
+.PP
+The
+.IR TIFFRewriteDirectory
+function operates similarly to
+.IR TIFFWriteDirectory,
+but can be called with directories previously read or written that already
+have an established location in the file. It will rewrite the directory,
+but instead of place it at it's old location (as
+.IR TIFFWriteDirectory
+would) it will place them at the end of the file, correcting the pointer from
+the preceeding directory or file header to point to it's new location. This
+is particularly important in cases where the size of the directory and
+pointed to data has grown, so it won't fit in the space available at the
+old location.
+.PP
+The
+.IR TIFFCheckpointDirectory
+writes the current state of the tiff directory into the file to make what
+is currently in the file readable. Unlike
+.IR TIFFWriteDirectory,
+.IR TIFFCheckpointDirectory
+does not free up the directory data structures in memory, so they can be
+updated (as strips/tiles are written) and written again. Reading such
+a partial file you will at worst get a tiff read error for the first
+strip/tile encountered that is incomplete, but you will at least get
+all the valid data in the file before that. When the file is complete,
+just use
+.IR TIFFWriteDirectory
+as usual to finish it off cleanly.
+.SH "RETURN VALUES"
+1 is returned when the contents are successfully written to the file.
+Otherwise, 0 is returned if an error was encountered when writing
+the directory contents.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+.BR "Error post-encoding before directory write" .
+Before writing the contents of the current directory, any pending data are
+flushed. This message indicates that an error occurred while doing this.
+.PP
+.BR "Error flushing data before directory write" .
+Before writing the contents of the current directory, any pending data are
+flushed. This message indicates that an error occurred while doing this.
+.PP
+.BR "Cannot write directory, out of space" .
+There was not enough space to allocate a temporary area for the directory that
+was to be written.
+.PP
+.BR "Error writing directory count" .
+A write error occurred when writing the count of fields in the directory.
+.PP
+.BR "Error writing directory contents" .
+A write error occurred when writing the directory fields.
+.PP
+.BR "Error writing directory link" .
+A write error occurred when writing the link to the next directory.
+.PP
+\fBError writing data for field "%s"\fP.
+A write error occurred when writing indirect data for the specified field.
+.PP
+.BR "Error writing TIFF header" .
+A write error occurred when re-writing header at the front of the file.
+.PP
+.BR "Error fetching directory count" .
+A read error occurred when fetching the directory count field for
+a previous directory.
+This can occur when setting up a link to the directory that is being
+written.
+.PP
+.BR "Error fetching directory link" .
+A read error occurred when fetching the directory link field for
+a previous directory.
+This can occur when setting up a link to the directory that is being
+written.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFError (3TIFF),
+.BR TIFFReadDirectory (3TIFF),
+.BR TIFFSetDirectory (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFWriteEncodedStrip.3tiff b/tiff/man/TIFFWriteEncodedStrip.3tiff
new file mode 100644
index 0000000..0427fa2
--- /dev/null
+++ b/tiff/man/TIFFWriteEncodedStrip.3tiff
@@ -0,0 +1,102 @@
+.\" $Id: TIFFWriteEncodedStrip.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFWriteEncodedStrip 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFWritedEncodedStrip \- compress and write a strip of data to an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFWriteEncodedStrip(TIFF *" tif ", tstrip_t " strip ", tdata_t " buf ", tsize_t " size ")"
+.SH DESCRIPTION
+Compress
+.I size
+bytes of raw data from
+.I buf
+and write the result to the specified strip; replacing any previously written
+data. Note that the value of
+.I strip
+is a ``raw strip number.'' That is, the caller must take into account whether
+or not the data are organized in separate planes (\c
+.IR PlanarConfiguration =2).
+.SH NOTES
+The library writes encoded data using the native machine byte order. Correctly
+implemented
+.SM TIFF
+readers are expected to do any necessary byte-swapping to correctly process
+image data with BitsPerSample greater than 8.
+.PP
+The strip number must be valid according to the current settings of the
+.I ImageLength
+and
+.I RowsPerStrip
+tags.
+An image may be dynamically grown by increasing the value of
+.I ImageLength
+prior to each call to
+.IR TIFFWriteEncodedStrip .
+.SH "RETURN VALUES"
+\-1 is returned if an error was encountered. Otherwise, the value of
+.IR size
+is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+\fB%s: File not open for writing\fP. The file was opened for reading, not
+writing.
+.PP
+\fBCan not write scanlines to a tiled image\fP. The image is assumed to be
+organized in tiles because the
+.I TileWidth
+and
+.I TileLength
+tags have been set with
+.IR TIFFSetField (3TIFF).
+.PP
+\fB%s: Must set "ImageWidth" before writing data\fP.
+The image's width has not be set before the first write. See
+.IR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: Must set "PlanarConfiguration" before writing data\fP.
+The organization of data has not be defined before the first write. See
+.IR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: No space for strip arrays"\fP.
+There was not enough space for the arrays that hold strip offsets and byte
+counts.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFWriteScanline (3TIFF),
+.BR TIFFWriteRawStrip (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFWriteEncodedTile.3tiff b/tiff/man/TIFFWriteEncodedTile.3tiff
new file mode 100644
index 0000000..20cd1aa
--- /dev/null
+++ b/tiff/man/TIFFWriteEncodedTile.3tiff
@@ -0,0 +1,96 @@
+.\" $Id: TIFFWriteEncodedTile.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFWriteEncodedTile 3TIFF "December 16, 1991" "libtiff"
+.SH NAME
+TIFFWritedEncodedTile \- compress and write a tile of data to an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFWriteEncodedTile(TIFF *" tif ", ttile_t " tile ", tdata_t " buf ", tsize_t " size ")"
+.SH DESCRIPTION
+Compress
+.I size
+bytes of raw data from
+.I buf
+and
+.B append
+the result to the end of the specified tile. Note that the value of
+.I tile
+is a ``raw tile number.'' That is, the caller must take into account whether
+or not the data are organized in separate places (\c
+.IR PlanarConfiguration =2).
+.IR TIFFComputeTile
+automatically does this when converting an (x,y,z,sample) coordinate quadruple
+to a tile number.
+.SH NOTES
+The library writes encoded data using the native machine byte order. Correctly
+implemented
+.SM TIFF
+readers are expected to do any necessary byte-swapping to correctly process
+image data with BitsPerSample greater than 8.
+.SH "RETURN VALUES"
+\-1 is returned if an error was encountered. Otherwise, the value of
+.IR size
+is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.PP
+\fB%s: File not open for writing\fP.
+The file was opened for reading, not writing.
+.PP
+\fBCan not write tiles to a stripped image\fP.
+The image is assumed to be organized in strips because neither of the
+.I TileWidth
+or
+.I TileLength
+tags have been set with
+.BR TIFFSetField (3TIFF).
+.PP
+\fB%s: Must set "ImageWidth" before writing data\fP. The image's width has not
+be set before the first write. See
+.BR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: Must set "PlanarConfiguration" before writing data\fP. The organization
+of data has not be defined before the first write. See
+.BR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: No space for tile arrays"\fP.
+There was not enough space for the arrays that hold tile offsets and byte
+counts.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFWriteTile (3TIFF),
+.BR TIFFWriteRawTile (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFWriteRawStrip.3tiff b/tiff/man/TIFFWriteRawStrip.3tiff
new file mode 100644
index 0000000..43b4a17
--- /dev/null
+++ b/tiff/man/TIFFWriteRawStrip.3tiff
@@ -0,0 +1,96 @@
+.\" $Id: TIFFWriteRawStrip.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFWriteRawstrip 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFWriteRawStrip \- write a strip of raw data to an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFWriteRawStrip(TIFF *" tif ", tstrip_t " strip ", tdata_t " buf ", tsize_t " size ")"
+.SH DESCRIPTION
+Append
+.I size
+bytes of raw data to the specified strip.
+.SH NOTES
+The strip number must be valid according to the current settings of the
+.I ImageLength
+and
+.I RowsPerStrip
+tags.
+An image may be dynamically grown by increasing the value of
+.I ImageLength
+prior to each call to
+.IR TIFFWriteRawStrip .
+.SH "RETURN VALUES"
+\-1 is returned if an error occurred.
+Otherwise, the value of
+.IR size
+is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.PP
+\fB%s: File not open for writing\fP.
+The file was opened for reading, not writing.
+.PP
+\fBCan not write scanlines to a tiled image\fP. The image is assumed to be
+organized in tiles because the
+.I TileWidth
+and
+.I TileLength
+tags have been set with
+.BR TIFFSetField (3TIFF).
+.PP
+\fB%s: Must set "ImageWidth" before writing data\fP.
+The image's width has not be set before the first write.
+See
+.BR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: Must set "PlanarConfiguration" before writing data\fP.
+The organization of data has not be defined before the first write.
+See
+.BR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: No space for strip arrays"\fP.
+There was not enough space for the arrays that hold strip
+offsets and byte counts.
+.PP
+\fB%s: Strip %d out of range, max %d\fP.
+The specified strip is not a valid strip according to the
+currently specified image dimensions.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFWriteEncodedStrip (3TIFF),
+.BR TIFFWriteScanline (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFWriteRawTile.3tiff b/tiff/man/TIFFWriteRawTile.3tiff
new file mode 100644
index 0000000..c6dbd87
--- /dev/null
+++ b/tiff/man/TIFFWriteRawTile.3tiff
@@ -0,0 +1,84 @@
+.\" $Id: TIFFWriteRawTile.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFWriteRawtile 3TIFF "December 16, 1991" "libtiff"
+.SH NAME
+TIFFWriteRawTile \- write a tile of raw data to an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFWriteRawTile(TIFF *" tif ", ttile_t " tile ", tdata_t " buf ", tsize_t " size ")"
+.SH DESCRIPTION
+Append
+.I size
+bytes of raw data to the specified tile.
+.SH "RETURN VALUES"
+\-1 is returned if an error occurred. Otherwise, the value of
+.IR size
+is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.PP
+\fB%s: File not open for writing\fP.
+The file was opened for reading, not writing.
+.PP
+\fBCan not write tiles to a stripped image\fP.
+The image is assumed to be organized in strips because neither of the
+.I TileWidth
+or
+.I TileLength
+tags have been set with
+.BR TIFFSetField (3TIFF).
+.PP
+\fB%s: Must set "ImageWidth" before writing data\fP.
+The image's width has not be set before the first write.
+See
+.BR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: Must set "PlanarConfiguration" before writing data\fP. The organization
+of data has not be defined before the first write. See
+.BR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: No space for tile arrays"\fP.
+There was not enough space for the arrays that hold tile offsets and byte
+counts.
+.PP
+\fB%s: Specified tile %d out of range, max %d\fP.
+The specified tile is not valid according to the currently specified image
+dimensions.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFWriteEncodedTile (3TIFF),
+.BR TIFFWriteScanline (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFWriteScanline.3tiff b/tiff/man/TIFFWriteScanline.3tiff
new file mode 100644
index 0000000..c8042f9
--- /dev/null
+++ b/tiff/man/TIFFWriteScanline.3tiff
@@ -0,0 +1,154 @@
+.\" $Id: TIFFWriteScanline.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFWriteScanline 3TIFF "December 16, 1991" "libtiff"
+.SH NAME
+TIFFWriteScanline \- write a scanline to an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFWriteScanline(TIFF *" tif ", tdata_t " buf ", uint32 " row ", tsample_t " sample ")"
+.SH DESCRIPTION
+Write data to a file at the specified row. The
+.I sample
+parameter is used only if data are organized in separate planes (\c
+.IR PlanarConfiguration =2).
+The data are assumed to be uncompressed and in the native bit- and byte-order
+of the host machine. The data written to the file is compressed according to
+the compression scheme of the current
+.SM TIFF
+directory (see further below). If the current scanline is past the end of the
+current subfile, the
+.I ImageLength
+field is automatically increased to include the scanline (except
+for
+.IR PlanarConfiguration =2,
+where the
+.I ImageLength
+cannot be changed once the first data are written). If the
+.I ImageLength
+is increased, the
+.I StripOffsets
+and
+.I StripByteCounts
+fields are similarly enlarged to reflect data written past the previous end of
+image.
+.SH NOTES
+The library writes encoded data using the native machine byte order. Correctly
+implemented
+.SM TIFF
+readers are expected to do any necessary byte-swapping to correctly process
+image data with BitsPerSample greater than 8. The library attempts to hide
+bit-ordering differences between the image and the native machine by
+converting data from the native machine order.
+.PP
+In C++ the
+.I sample
+parameter defaults to 0.
+.PP
+Once data are written to a file for the current directory, the values of
+certain tags may not be altered; see
+.IR TIFFSetField (3TIFF)
+for more information.
+.PP
+It is not possible to write scanlines to a file that uses a tiled
+organization. The routine
+.IR TIFFIsTiled
+can be used to determine if the file is organized as tiles or strips.
+.SH "RETURN VALUES"
+.IR TIFFWriteScanline
+returns \-1 if it immediately detects an error and 1 for a successful write.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.IR TIFFError (3TIFF)
+routine.
+.PP
+.BR "%s: File not open for writing .
+The file was opened for reading, not writing.
+.PP
+.BR "Can not write scanlines to a tiled image" .
+An attempt was made to write a scanline to a tiled image. The image is assumed
+to be organized in tiles because the
+.I TileWidth
+and
+.I TileLength
+tags have been set with
+.IR TIFFSetField (3TIFF).
+.PP
+.BR "Compression algorithm does not support random access" .
+Data was written in a non-sequential order to a file that uses a compression
+algorithm and that has
+.I RowsPerStrip
+greater than one. That is, data in the image is to be stored in a compressed
+form, and with multiple rows packed into a strip. In this case, the library
+does not support random access to the data. The data should either be written
+as entire strips, sequentially by rows, or the value of
+.I RowsPerStrip
+should be set to one.
+.PP
+\fB%s: Must set "ImageWidth" before writing data\fP.
+The image's width has not be set before the first write.
+See
+.BR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fB%s: Must set "PlanarConfiguration" before writing data\fP.
+The organization of data has not be defined before the first write.
+See
+.BR TIFFSetField (3TIFF)
+for information on how to do this.
+.PP
+\fBCan not change "ImageLength" when using separate planes\fP. Separate image
+planes are being used (\c
+.IR PlanarConfiguration =2),
+but the number of rows has not been specified before the first write. The
+library supports the dynamic growth of an image only when data are organized
+in a contiguous manner (\c
+.IR PlanarConfiguration =1).
+.PP
+.BR "%d: Sample out of range, max %d" .
+The
+.I sample
+parameter was greater than the value of the SamplesPerPixel tag.
+.PP
+.BR "%s: No space for strip arrays .
+There was not enough space for the arrays that hold strip offsets and byte
+counts.
+.SH BUGS
+Writing subsampled YCbCR data does not work correctly because, for
+.IR PlanarConfiguration =2
+the size of a scanline is not calculated on a per-sample basis, and for
+.IR PlanarConfiguration =1
+the library does not pack the block-interleaved samples.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFWriteEncodedStrip (3TIFF),
+.BR TIFFWriteRawStrip (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFWriteTile.3tiff b/tiff/man/TIFFWriteTile.3tiff
new file mode 100644
index 0000000..c6516af
--- /dev/null
+++ b/tiff/man/TIFFWriteTile.3tiff
@@ -0,0 +1,77 @@
+.\" $Id: TIFFWriteTile.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFWriteTile 3TIFF "November 29, 1999" "libtiff"
+.SH NAME
+TIFFWriteTile \- encode and write a tile of data to an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFWriteTile(TIFF *" tif ", tdata_t " buf ", uint32 " x ", uint32 " y ", uint32 " z ", tsample_t " sample ")"
+.SH DESCRIPTION
+Write the data for the tile
+.I containing
+the specified coordinates. The data in
+.I buf
+are is (potentially) compressed, and written to the indicated file, normally
+being appended to the end of the file. The buffer must be contain an entire
+tile of data. Applications should call the routine
+.IR TIFFTileSize
+to find out the size (in bytes) of a tile buffer. The
+.I x
+and
+.I y
+parameters are always used by
+.IR TIFFWriteTile .
+The
+.I z
+parameter is used if the image is deeper than 1 slice (\c
+.IR ImageDepth >1).
+The
+.I sample
+parameter is used only if data are organized in separate planes (\c
+.IR PlanarConfiguration =2).
+.SH "RETURN VALUES"
+.IR TIFFWriteTile
+returns \-1 if it detects an error; otherwise the number of bytes in the tile
+is returned.
+.SH DIAGNOSTICS
+All error messages are directed to the
+.BR TIFFError (3TIFF)
+routine.
+.SH "SEE ALSO"
+.BR TIFFCheckTile (3TIFF),
+.BR TIFFComputeTile (3TIFF),
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadTile (3TIFF),
+.BR TIFFWriteScanline (3TIFF),
+.BR TIFFWriteEncodedTile (3TIFF),
+.BR TIFFWriteRawTile (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFbuffer.3tiff b/tiff/man/TIFFbuffer.3tiff
new file mode 100644
index 0000000..5b45953
--- /dev/null
+++ b/tiff/man/TIFFbuffer.3tiff
@@ -0,0 +1,77 @@
+.\" $Id: TIFFbuffer.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1995 Sam Leffler
+.\" Copyright (c) 1995 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFBUFFER 3TIFF "November 1, 2005" "libtiff"
+.SH NAME
+TIFFReadBufferSetup, TIFFWriteBufferSetup \- I/O buffering control routines
+.SH SYNOPSIS
+.nf
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFReadBufferSetup(TIFF *" tif ", tdata_t " buffer ", tsize_t " size ");"
+.BI "int TIFFWriteBufferSetup(TIFF *" tif ", tdata_t " buffer ", tsize_t " size ");"
+.fi
+.SH DESCRIPTION
+The following routines are provided for client-control of the I/O buffers used
+by the library. Applications need never use these routines; they are provided
+only for ``intelligent clients'' that wish to optimize memory usage and/or
+eliminate potential copy operations that can occur when working with images
+that have data stored without compression.
+.PP
+.I TIFFReadBufferSetup
+sets up the data buffer used to read raw (encoded) data from a file. If the
+specified pointer is
+.SM NULL
+(zero), then a buffer of the appropriate size is allocated. Otherwise the
+caller must guarantee that the buffer is large enough to hold any individual
+strip of raw data.
+.I TIFFReadBufferSetup
+returns a non-zero value if the setup was successful and zero otherwise.
+.PP
+.I TIFFWriteBufferSetup
+sets up the data buffer used to write raw (encoded) data to a file. If the
+specified
+.I size
+is \-1 then the buffer size is selected to hold a complete tile or strip, or
+at least 8 kilobytes, whichever is greater. If the specified
+.I buffer
+is
+.SM NULL
+(zero), then a buffer of the appropriate size is dynamically allocated.
+.I TIFFWriteBufferSetup
+returns a non-zero value if the setup was successful and zero otherwise.
+.SH DIAGNOSTICS
+.BR "%s: No space for data buffer at scanline %ld" .
+.I TIFFReadBufferSetup
+was unable to dynamically allocate space for a data buffer.
+.PP
+.BR "%s: No space for output buffer" .
+.I TIFFWriteBufferSetup
+was unable to dynamically allocate space for a data buffer.
+.SH "SEE ALSO"
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFcodec.3tiff b/tiff/man/TIFFcodec.3tiff
new file mode 100644
index 0000000..55d0d38
--- /dev/null
+++ b/tiff/man/TIFFcodec.3tiff
@@ -0,0 +1,82 @@
+.\" $Id: TIFFcodec.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1995 Sam Leffler
+.\" Copyright (c) 1995 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH CODEC 3TIFF "October 29, 2004" "libtiff"
+.SH NAME
+TIFFFindCODEC, TIFFRegisterCODEC, TIFFUnRegisterCODEC, TIFFIsCODECConfigured
+\- codec-related utility routines
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "const TIFFCodec* TIFFFindCODEC(uint16 " scheme ");"
+.br
+.BI "TIFFCodec* TIFFRegisterCODEC(uint16 " scheme ", const char *" method ", TIFFInitMethod " init ");"
+.br
+.BI "void TIFFUnRegisterCODEC(TIFFCodec *" codec ");"
+.br
+.BI "int TIFFIsCODECConfigured(uint16 " scheme ");"
+.SH DESCRIPTION
+.I libtiff
+supports a variety of compression schemes implemented by software
+.IR codecs .
+Each codec adheres to a modular interface that provides for
+the decoding and encoding of image data; as well as some other
+methods for initialization, setup, cleanup, and the control
+of default strip and tile sizes.
+Codecs are identified by the associated value of the
+.SM TIFF
+.I Compression
+tag; e.g. 5 for
+.SM LZW
+compression.
+.PP
+The
+.I TIFFRegisterCODEC
+routine can be used to
+augment or override the set of codecs available to an application.
+If the specified
+.I scheme
+already has a registered codec then it is
+.I overridden
+and any images with data encoded with this
+compression scheme will be decoded using the supplied coded.
+.PP
+.I TIFFIsCODECConfigured
+returns 1 if the codec is configured and working. Otherwise 0 will be returned.
+.SH DIAGNOSTICS
+.BR "No space to register compression scheme %s" .
+.I TIFFRegisterCODEC
+was unable to allocate memory for the data structures needed
+to register a codec.
+.PP
+.BR "Cannot remove compression scheme %s; not registered" .
+.I TIFFUnRegisterCODEC
+did not locate the specified codec in the table of registered
+compression schemes.
+.SH "SEE ALSO"
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFcolor.3tiff b/tiff/man/TIFFcolor.3tiff
new file mode 100644
index 0000000..a3faf79
--- /dev/null
+++ b/tiff/man/TIFFcolor.3tiff
@@ -0,0 +1,268 @@
+.\" $Id: TIFFcolor.3tiff,v 1.3 2006/03/23 14:54:02 dron Exp $
+.\"
+.\" Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH COLOR 3TIFF "December 21, 2003" "libtiff"
+.SH NAME
+TIFFYCbCrToRGBInit, TIFFYCbCrtoRGB, TIFFCIELabToRGBInit, TIFFCIELabToXYZ,
+TIFFXYZToRGB \- color conversion routines.
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "int TIFFYCbCrToRGBInit(TIFFYCbCrToRGB *" ycbcr ", float *" luma ", float *"refBlackWhite" );"
+.br
+.BI "void TIFFYCbCrtoRGB(TIFFYCbCrToRGB *" ycbcr ", uint32 " Y ", int32 " Cb ", int32 " Cr ", uint32 *" R ", uint32 *" G ", uint32 *" B " );"
+.sp
+.BI "int TIFFCIELabToRGBInit(TIFFCIELabToRGB *" cielab ", TIFFDisplay *" display ", float *" refWhite ");"
+.br
+.BI "void TIFFCIELabToXYZ(TIFFCIELabToRGB *" cielab ", uint32 " L ", int32 " a ", int32 " b ", float *" X ", float *" Y ", float *" Z ");"
+.br
+.BI "void TIFFXYZToRGB(TIFFCIELabToRGB *" cielab ", float " X ", float " Y ", float " Z" , uint32 *" R ", uint32 *" G ", uint32 *" B ");"
+.SH DESCRIPTION
+TIFF supports several color spaces for images stored in that format. There is
+usually a problem of application to handle the data properly and convert
+between different colorspaces for displaying and printing purposes. To
+simplify this task libtiff implements several color conversion routines
+itself. In particular, these routines used in
+.B TIFFRGBAImage(3TIFF)
+interface.
+.PP
+.B TIFFYCbCrToRGBInit()
+used to initialize
+.I YCbCr
+to
+.I RGB
+conversion state. Allocating and freeing of the
+.I ycbcr
+structure belongs to programmer.
+.I TIFFYCbCrToRGB
+defined in
+.B tiffio.h
+as
+.PP
+.RS
+.nf
+typedef struct { /* YCbCr->RGB support */
+ TIFFRGBValue* clamptab; /* range clamping table */
+ int* Cr_r_tab;
+ int* Cb_b_tab;
+ int32* Cr_g_tab;
+ int32* Cb_g_tab;
+ int32* Y_tab;
+} TIFFYCbCrToRGB;
+.fi
+.RE
+.PP
+.I luma
+is a float array of three values representing proportions of the red, green
+and blue in luminance, Y (see section 21 of the TIFF 6.0 specification, where
+the YCbCr images discussed).
+.I TIFFTAG_YCBCRCOEFFICIENTS
+holds that values in TIFF file.
+.I refBlackWhite
+is a float array of 6 values which specifies a pair of headroom and footroom
+image data values (codes) for each image component (see section 20 of the
+TIFF 6.0 specification where the colorinmetry fields discussed).
+.I TIFFTAG_REFERENCEBLACKWHITE
+is responsible for storing these values in TIFF file. Following code snippet
+should helps to understand the the technique:
+.PP
+.RS
+.nf
+float *luma, *refBlackWhite;
+uint16 hs, vs;
+
+/* Initialize structures */
+ycbcr = (TIFFYCbCrToRGB*)
+ _TIFFmalloc(TIFFroundup(sizeof(TIFFYCbCrToRGB), sizeof(long))
+ + 4*256*sizeof(TIFFRGBValue)
+ + 2*256*sizeof(int)
+ + 3*256*sizeof(int32));
+if (ycbcr == NULL) {
+ TIFFError("YCbCr->RGB",
+ "No space for YCbCr->RGB conversion state");
+ exit(0);
+}
+
+TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma);
+TIFFGetFieldDefaulted(tif, TIFFTAG_REFERENCEBLACKWHITE, &refBlackWhite);
+if (TIFFYCbCrToRGBInit(ycbcr, luma, refBlackWhite) < 0)
+ exit(0);
+
+/* Start conversion */
+uint32 r, g, b;
+uint32 Y;
+int32 Cb, Cr;
+
+for each pixel in image
+ TIFFYCbCrtoRGB(img->ycbcr, Y, Cb, Cr, &r, &g, &b);
+
+/* Free state structure */
+_TIFFfree(ycbcr);
+.fi
+.RE
+.PP
+
+.PP
+.B TIFFCIELabToRGBInit()
+initializes the
+.I CIE L*a*b* 1976
+to
+.I RGB
+conversion state.
+.B TIFFCIELabToRGB
+defined as
+.PP
+.RS
+.nf
+#define CIELABTORGB_TABLE_RANGE 1500
+
+typedef struct { /* CIE Lab 1976->RGB support */
+ int range; /* Size of conversion table */
+ float rstep, gstep, bstep;
+ float X0, Y0, Z0; /* Reference white point */
+ TIFFDisplay display;
+ float Yr2r[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yr to r */
+ float Yg2g[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yg to g */
+ float Yb2b[CIELABTORGB_TABLE_RANGE + 1]; /* Conversion of Yb to b */
+} TIFFCIELabToRGB;
+.fi
+.RE
+.PP
+.I display
+is a display device description, declared as
+.PP
+.RS
+.nf
+typedef struct {
+ float d_mat[3][3]; /* XYZ -> luminance matrix */
+ float d_YCR; /* Light o/p for reference white */
+ float d_YCG;
+ float d_YCB;
+ uint32 d_Vrwr; /* Pixel values for ref. white */
+ uint32 d_Vrwg;
+ uint32 d_Vrwb;
+ float d_Y0R; /* Residual light for black pixel */
+ float d_Y0G;
+ float d_Y0B;
+ float d_gammaR; /* Gamma values for the three guns */
+ float d_gammaG;
+ float d_gammaB;
+} TIFFDisplay;
+.fi
+.RE
+.PP
+For example, the one can use sRGB device, which has the following parameters:
+.PP
+.RS
+.nf
+TIFFDisplay display_sRGB = {
+ { /* XYZ -> luminance matrix */
+ { 3.2410F, -1.5374F, -0.4986F },
+ { -0.9692F, 1.8760F, 0.0416F },
+ { 0.0556F, -0.2040F, 1.0570F }
+ },
+ 100.0F, 100.0F, 100.0F, /* Light o/p for reference white */
+ 255, 255, 255, /* Pixel values for ref. white */
+ 1.0F, 1.0F, 1.0F, /* Residual light o/p for black pixel */
+ 2.4F, 2.4F, 2.4F, /* Gamma values for the three guns */
+};
+.fi
+.RE
+.PP
+.I refWhite
+is a color temperature of the reference white. The
+.I TIFFTAG_WHITEPOINT
+contains the chromaticity of the white point of the image from where the
+reference white can be calculated using following formulae:
+.PP
+.RS
+refWhite_Y = 100.0
+.br
+refWhite_X = whitePoint_x / whitePoint_y * refWhite_Y
+.br
+refWhite_Z = (1.0 - whitePoint_x - whitePoint_y) / whitePoint_y * refWhite_X
+.br
+.RE
+.PP
+The conversion itself performed in two steps: at the first one we will convert
+.I CIE L*a*b* 1976
+to
+.I CIE XYZ
+using
+.B TIFFCIELabToXYZ()
+routine, and at the second step we will convert
+.I CIE XYZ
+to
+.I RGB
+using
+.B TIFFXYZToRGB().
+Look at the code sample below:
+.PP
+.RS
+.nf
+float *whitePoint;
+float refWhite[3];
+
+/* Initialize structures */
+img->cielab = (TIFFCIELabToRGB *)
+ _TIFFmalloc(sizeof(TIFFCIELabToRGB));
+if (!cielab) {
+ TIFFError("CIE L*a*b*->RGB",
+ "No space for CIE L*a*b*->RGB conversion state.");
+ exit(0);
+}
+
+TIFFGetFieldDefaulted(tif, TIFFTAG_WHITEPOINT, &whitePoint);
+refWhite[1] = 100.0F;
+refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1];
+refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1])
+ / whitePoint[1] * refWhite[1];
+if (TIFFCIELabToRGBInit(cielab, &display_sRGB, refWhite) < 0) {
+ TIFFError("CIE L*a*b*->RGB",
+ "Failed to initialize CIE L*a*b*->RGB conversion state.");
+ _TIFFfree(cielab);
+ exit(0);
+}
+
+/* Now we can start to convert */
+uint32 r, g, b;
+uint32 L;
+int32 a, b;
+float X, Y, Z;
+
+for each pixel in image
+ TIFFCIELabToXYZ(cielab, L, a, b, &X, &Y, &Z);
+ TIFFXYZToRGB(cielab, X, Y, Z, &r, &g, &b);
+
+/* Don't forget to free the state structure */
+_TIFFfree(cielab);
+.fi
+.RE
+.PP
+.SH "SEE ALSO"
+.BR TIFFRGBAImage (3TIFF)
+.BR libtiff (3TIFF),
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFmemory.3tiff b/tiff/man/TIFFmemory.3tiff
new file mode 100644
index 0000000..eaca15f
--- /dev/null
+++ b/tiff/man/TIFFmemory.3tiff
@@ -0,0 +1,90 @@
+.\" $Id: TIFFmemory.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1995 Sam Leffler
+.\" Copyright (c) 1995 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH MEMORY 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+_TIFFmalloc, \c
+_TIFFrealloc, \c
+_TIFFfree, \c
+_TIFFmemset, \c
+_TIFFmemcpy, \c
+_TIFFmemcmp, \c
+\- memory management-related functions for use with
+.SM TIFF
+files
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tdata_t _TIFFmalloc(tsize_t " size ");"
+.br
+.BI "tdata_t _TIFFrealloc(tdata_t " buffer ", tsize_t " size ");"
+.br
+.BI "void _TIFFfree(tdata_t " buffer ");"
+.br
+.BI "void _TIFFmemset(tdata_t " s ", int " c ", tsize_t " n ");"
+.br
+.BI "void _TIFFmemcpy(tdata_t " dest ", const tdata_t " src ", tsize_t " n ");"
+.br
+.BI "int _TIFFmemcmp(const tdata_t " s1 ", const tdata_t "s2 ", tsize_t " n ");"
+.SH DESCRIPTION
+These routines are provided for writing portable software that uses
+.IR libtiff ;
+they hide any memory-management related issues, such as dealing with segmented
+architectures found on 16-bit machines.
+.PP
+.I _TIFFmalloc
+and
+.I _TIFFrealloc
+are used to dynamically allocate and reallocate memory used by
+.IR libtiff ;
+such as memory passed into the I/O routines. Memory allocated through these
+interfaces is released back to the system using the
+.I _TIFFfree
+routine.
+.PP
+Memory allocated through one of the above interfaces can be set to a known
+value using
+.IR _TIFFmemset ,
+copied to another memory location using
+.IR _TIFFmemcpy ,
+or compared for equality using
+.IR _TIFFmemcmp .
+These routines conform to the equivalent
+.SM ANSI
+C routines:
+.IR memset ,
+.IR memcpy ,
+and
+.IR memcmp ,
+repsectively.
+.SH DIAGNOSTICS
+None.
+.SH "SEE ALSO"
+.BR malloc (3),
+.BR memory (3),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFquery.3tiff b/tiff/man/TIFFquery.3tiff
new file mode 100644
index 0000000..7e84097
--- /dev/null
+++ b/tiff/man/TIFFquery.3tiff
@@ -0,0 +1,142 @@
+.\" $Id: TIFFquery.3tiff,v 1.1 2004/11/11 14:39:16 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH QUERY 3TIFF "October 29, 2004" "libtiff"
+.SH NAME
+TIFFCurrentRow,
+TIFFCurrentStrip,
+TIFFCurrentTile,
+TIFFCurrentDirectory,
+TIFFLastDirectory,
+TIFFFileno,
+TIFFFileName,
+TIFFGetMode,
+TIFFIsTiled,
+TIFFIsByteSwapped,
+TIFFIsUpSampled,
+TIFFIsMSB2LSB,
+TIFFGetVersion
+\- query routines
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "uint32 TIFFCurrentRow(TIFF* " tif ")"
+.br
+.BI "tstrip_t TIFFCurrentStrip(TIFF* " tif ")"
+.br
+.BI "ttile_t TIFFCurrentTile(TIFF* " tif ")"
+.br
+.BI "tdir_t TIFFCurrentDirectory(TIFF* " tif ")"
+.br
+.BI "int TIFFLastDirectory(TIFF* " tif ")"
+.br
+.BI "int TIFFFileno(TIFF* " tif ")"
+.br
+.BI "char* TIFFFileName(TIFF* " tif ")"
+.br
+.BI "int TIFFGetMode(TIFF* " tif ")"
+.br
+.BI "int TIFFIsTiled(TIFF* " tif ")"
+.br
+.BI "int TIFFIsByteSwapped(TIFF* " tif ")"
+.br
+.BI "int TIFFIsUpSampled(TIFF* " tif ")"
+.br
+.BI "int TIFFIsMSB2LSB(TIFF* " tif ")"
+.br
+.BI "const char* TIFFGetVersion(void)"
+.SH DESCRIPTION
+The following routines return status information about an open
+.SM TIFF
+file.
+.PP
+.IR TIFFCurrentDirectory
+returns the index of the current directory (directories are numbered starting
+at 0). This number is suitable for use with the
+.IR TIFFSetDirectory
+routine.
+.PP
+.IR TIFFLastDirectory
+returns a non-zero value if the current directory is the last directory in the
+file; otherwise zero is returned.
+.PP
+.IR TIFFCurrentRow ,
+.IR TIFFCurrentStrip ,
+and
+.IR TIFFCurrentTile ,
+return the current row, strip, and tile, respectively, that is being read or
+written. These values are updated each time a read or write is done.
+.PP
+.IR TIFFFileno
+returns the underlying file descriptor used to access the
+.SM TIFF
+image in the filesystem.
+.PP
+.IR TIFFFileName
+returns the pathname argument passed to
+.IR TIFFOpen
+or
+.IR TIFFFdOpen .
+.PP
+.IR TIFFGetMode
+returns the mode with which the underlying file was opened. On
+.SM UNIX
+systems, this is the value passed to the
+.IR open (2)
+system call.
+.PP
+.IR TIFFIsTiled
+returns a non-zero value if the image data has a tiled organization. Zero is
+returned if the image data is organized in strips.
+.PP
+.IR TIFFIsByteSwapped
+returns a non-zero value if the image data was in a different byte-order than
+the host machine. Zero is returned if the TIFF file and local host byte-orders
+are the same. Note that TIFFReadTile(), TIFFReadStrip() and
+TIFFReadScanline() functions already normally perform byte swapping to local
+host order if needed.
+.PP
+.I TIFFIsUpSampled
+returns a non-zero value if image data returned through the read interface
+routines is being up-sampled. This can be useful to applications that want to
+calculate I/O buffer sizes to reflect this usage (though the usual strip and
+tile size routines already do this).
+.PP
+.I TIFFIsMSB2LSB
+returns a non-zero value if the image data is being returned with bit 0 as the
+most significant bit.
+.PP
+.IR TIFFGetVersion
+returns an
+.SM ASCII
+string that has a version stamp for the
+.SM TIFF
+library software.
+.SH DIAGNOSTICS
+None.
+.SH "SEE ALSO"
+.IR libtiff (3TIFF),
+.IR TIFFOpen (3TIFF),
+.IR TIFFFdOpen (3TIFF)
diff --git a/tiff/man/TIFFsize.3tiff b/tiff/man/TIFFsize.3tiff
new file mode 100644
index 0000000..ae6346c
--- /dev/null
+++ b/tiff/man/TIFFsize.3tiff
@@ -0,0 +1,59 @@
+.\" $Id: TIFFsize.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFSIZE 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFScanlineSize, TIFFRasterScanlineSize,
+\- return the size of various items associated with an open
+.SM TIFF
+file
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "tsize_t TIFFRasterScanlineSize(TIFF *" tif ")"
+.br
+.BI "tsize_t TIFFScanlineSize(TIFF *" tif ")"
+.SH DESCRIPTION
+.I TIFFScanlineSize
+returns the size in bytes of a row of data as it would be returned in a call
+to
+.IR TIFFReadScanline ,
+or as it would be expected in a call to
+.IR TIFFWriteScanline .
+.PP
+.I TIFFRasterScanlineSize
+returns the size in bytes of a complete decoded and packed raster scanline.
+Note that this value may be different from the value returned by
+.I TIFFScanlineSize
+if data is stored as separate planes.
+.SH DIAGNOSTICS
+None.
+.SH "SEE ALSO"
+.BR TIFFOpen (3TIFF),
+.BR TIFFReadScanline (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFstrip.3tiff b/tiff/man/TIFFstrip.3tiff
new file mode 100644
index 0000000..7c383c1
--- /dev/null
+++ b/tiff/man/TIFFstrip.3tiff
@@ -0,0 +1,99 @@
+.\" $Id: TIFFstrip.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1992-1997 Sam Leffler
+.\" Copyright (c) 1992-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFSTRIP 3TIFF "October 15, 1995" "libtiff"
+.SH NAME
+TIFFDefaultStripSize, TIFFStripSize, TIFFVStripSize, TIFFRawStripSize,
+TIFFComputeStrip, TIFFNumberOfStrips \- strip-related utility routines
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "uint32 TIFFDefaultStripSize(TIFF *" tif ", uint32 " estimate ")"
+.br
+.BI "tsize_t TIFFStripSize(TIFF *" tif ")"
+.br
+.BI "tsize_t TIFFVStripSize(TIFF *" tif ", uint32 " nrows ")"
+.br
+.BI "tsize_t TIFFRawStripSize(TIFF *" tif ", tstrip_t " strip ")"
+.br
+.BI "tstrip_t TIFFComputeStrip(TIFF *" tif ", uint32 " row ", tsample_t " sample ")"
+.br
+.BI "tstrip_t TIFFNumberOfStrips(TIFF *" tif ")"
+.SH DESCRIPTION
+.I TIFFDefaultStripSize
+returns the number of rows for a reasonable-sized strip according to the
+current settings of the
+.IR ImageWidth ,
+.IR BitsPerSample ,
+.IR SamplesPerPixel ,
+tags and any compression-specific requirements. If the
+.I estimate
+parameter, if non-zero, then it is taken as an estimate of the desired strip
+size and adjusted according to any compression-specific requirements. The
+value returned by this function is typically used to define the
+.I RowsPerStrip
+tag. In lieu of any unusual requirements
+.I TIFFDefaultStripSize
+tries to create strips that have approximately
+8 kilobytes of uncompressed data.
+.PP
+.IR TIFFStripSize
+returns the equivalent size for a strip of data as it would be returned in a
+call to
+.IR TIFFReadEncodedStrip
+or as it would be expected in a call to
+.IR TIFFWriteEncodedStrip .
+.PP
+.I TIFFVStripSize
+returns the number of bytes in a strip with
+.I nrows
+rows of data.
+.PP
+.I TIFFRawStripSize
+returns the number of bytes in a raw strip (i.e. not decoded).
+.PP
+.IR TIFFComputeStrip
+returns the strip that contains the specified coordinates. A valid strip is
+always returned; out-of-range coordinate values are clamped to the bounds of
+the image. The
+.I row
+parameter is always used in calculating a strip. The
+.I sample
+parameter is used only if data are organized in separate planes (\c
+.IR PlanarConfiguration =2).
+.PP
+.IR TIFFNumberOfStrips
+returns the number of strips in the image.
+.SH DIAGNOSTICS
+None.
+.SH "SEE ALSO"
+.BR TIFFReadEncodedStrip (3TIFF),
+.BR TIFFReadRawStrip (3TIFF),
+.BR TIFFWriteEncodedStrip (3TIFF),
+.BR TIFFWriteRawStrip (3TIFF),
+.BR libtiff (3TIFF),
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFswab.3tiff b/tiff/man/TIFFswab.3tiff
new file mode 100644
index 0000000..a72ea1b
--- /dev/null
+++ b/tiff/man/TIFFswab.3tiff
@@ -0,0 +1,80 @@
+.\" $Id: TIFFswab.3tiff,v 1.2 2005/11/02 11:07:18 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH SWAB 3TIFF "November 04, 2004" "libtiff"
+.SH NAME
+TIFFGetBitRevTable, TIFFReverseBits, TIFFSwabShort, TIFFSwabLong,
+TIFFSwabArrayOfShort, TIFFSwabArrayOfLong \- byte- and bit-swapping routines
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "const unsigned char* TIFFGetBitRevTable(int " reversed ")"
+.br
+.BI "void TIFFReverseBits(u_char *" data ", unsigned long " nbytes ")"
+.br
+.BI "void TIFFSwabShort(uint16 *" data ")"
+.br
+.BI "void TIFFSwabLong(uint32 *" data ")"
+.br
+.BI "void TIFFSwabArrayOfShort(uint16 *" data ", unsigned long " nshorts ")"
+.br
+.BI "void TIFFSwabArrayOfLong(uint32 *" data ", unsigned long " nlongs ")"
+.SH DESCRIPTION
+The following routines are used by the library to swap
+16- and 32-bit data and to reverse the order of bits in bytes.
+.PP
+.IR TIFFSwabShort
+and
+.IR TIFFSwabLong
+swap the bytes in a single 16-bit and 32-bit item, respectively.
+.IR TIFFSwabArrayOfShort
+and
+.IR TIFFSwabArrayOfLong
+swap the bytes in an array of 16-bit and 32-bit items, respectively.
+.PP
+.IR TIFFReverseBits
+replaces each byte in
+.I data
+with the equivalent bit-reversed value. This operation is performed with a
+lookup table, which is returned using the
+.IR TIFFGetBitRevTable
+function.
+.I reversed
+parameter specifies which table should be returned. Supply
+.I 1
+if you want bit reversal table. Supply
+.I 0
+to get the table that do not reverse bit values. It is a lookup table that can
+be used as an
+.IR "identity function" ;
+i.e.
+.IR "TIFFNoBitRevTable[n] == n" .
+.SH DIAGNOSTICS
+None.
+.SH "SEE ALSO"
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/TIFFtile.3tiff b/tiff/man/TIFFtile.3tiff
new file mode 100644
index 0000000..94bab6c
--- /dev/null
+++ b/tiff/man/TIFFtile.3tiff
@@ -0,0 +1,131 @@
+.\" $Id: TIFFtile.3tiff,v 1.2 2005/11/02 11:07:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFTILE 3TIFF "February 14, 1992" "libtiff"
+.SH NAME
+TIFFTileSize, TIFFTileRowSize, TIFFVTileSize, TIFFDefaultTileSize,
+TIFFComputeTile, TIFFCheckTile, TIFFNumberOfTiles \- tile-related utility
+routines
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+.BI "void TIFFDefaultTileSize(TIFF *" tif ", uint32 *" tw ", uint32 *" th ")"
+.br
+.BI "tsize_t TIFFTileSize(TIFF *" tif ")"
+.br
+.BI "tsize_t TIFFTileRowSize(TIFF *" tif ")"
+.br
+.BI "tsize_t TIFFVTileSize(TIFF *" tif ", uint32 " nrows ")"
+.br
+.BI "ttile_t TIFFComputeTile(TIFF *" tif ", uint32 " x ", uint32 " y ", uint32 " z ", tsample_t " sample ")"
+.br
+.BI "int TIFFCheckTile(TIFF *" tif ", uint32 " x ", uint32 " y ", uint32 " z ", tsample_t " sample ")"
+.br
+.BI "ttile_t TIFFNumberOfTiles(TIFF *" tif ")"
+.br
+.SH DESCRIPTION
+.I TIFFDefaultTileSize
+returns the pixel width and height of a reasonable-sized tile; suitable for
+setting up the
+.I TileWidth
+and
+.I TileLength
+tags.
+If the
+.I tw
+and
+.I th
+values passed in are non-zero, then they are adjusted to reflect any
+compression-specific requirements. The returned width and height are
+constrained to be a multiple of 16 pixels to conform with the
+.SM TIFF
+specification.
+.PP
+.I TIFFTileSize
+returns the equivalent size for a tile of data as it would be returned in a
+call to
+.I TIFFReadTile
+or as it would be expected in a call to
+.IR TIFFWriteTile .
+.PP
+.I TIFFVTileSize
+returns the number of bytes in a row-aligned tile with
+.I nrows
+of data.
+.PP
+.I TIFFTileRowSize
+returns the number of bytes of a row of data in a tile.
+.PP
+.IR TIFFComputeTile
+returns the tile that contains the specified coordinates. A valid tile is
+always returned; out-of-range coordinate values are clamped to the bounds of
+the image. The
+.I x
+and
+.I y
+parameters are always used in calculating a tile. The
+.I z
+parameter is used if the image is deeper than 1 slice (\c
+.IR ImageDepth >1).
+The
+.I sample
+parameter is used only if data are organized in separate planes (\c
+.IR PlanarConfiguration =2).
+.PP
+.IR TIFFCheckTile
+returns a non-zero value if the supplied coordinates are within the bounds of
+the image and zero otherwise. The
+.I x
+parameter is checked against the value of the
+.I ImageWidth
+tag. The
+.I y
+parameter is checked against the value of the
+.I ImageLength
+tag. The
+.I z
+parameter is checked against the value of the
+.I ImageDepth
+tag (if defined). The
+.I sample
+parameter is checked against the value of the
+.I SamplesPerPixel
+parameter if the data are organized in separate planes.
+.PP
+.IR TIFFNumberOfTiles
+returns the number of tiles in the image.
+.SH DIAGNOSTICS
+None.
+.SH "SEE ALSO"
+.BR TIFFReadEncodedTile (3TIFF),
+.BR TIFFReadRawTile (3TIFF),
+.BR TIFFReadTile (3TIFF),
+.BR TIFFWriteEncodedTile (3TIFF),
+.BR TIFFWriteRawTile (3TIFF),
+.BR TIFFWriteTile (3TIFF),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/bmp2tiff.1 b/tiff/man/bmp2tiff.1
new file mode 100644
index 0000000..40eaafc
--- /dev/null
+++ b/tiff/man/bmp2tiff.1
@@ -0,0 +1,85 @@
+.\" $Id: bmp2tiff.1,v 1.7 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH BMP2TIFF 1 "15 October, 2004" "libtiff"
+.SH NAME
+bmp2tiff \- create a
+.SM TIFF
+file from a Microsoft Windows Device Independent Bitmap image file
+.SH SYNOPSIS
+.B bmp2tiff
+[
+.I options
+]
+.I input.bmp
+[
+.I input2.bmp ...\&
+]
+.I output.tiff
+.SH DESCRIPTION
+.I bmp2tiff
+converts a Microsoft Windows Device Independent Bitmap image file to
+.SM TIFF.
+If several input BMP files are being specified the multipage
+.SM TIFF
+output file will be created. By default, the
+.SM TIFF
+image is created with data samples packed (\c
+.IR PlanarConfiguration =1),
+compressed with the PackBits algorithm (\c
+.IR Compression =32773),
+and with each strip no more than 8 kilobytes.
+These characteristics can overridden, or explicitly specified
+with the options described below.
+.SH OPTIONS
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B "\-c none"
+for no compression,
+.B "\-c packbits"
+for the PackBits compression algorithm (the default),
+.B "\-c jpeg"
+for the baseline JPEG compression algorithm,
+.B "\-c zip"
+for the Deflate compression algorithm,
+and
+.B "\-c lzw"
+for Lempel-Ziv & Welch.
+.TP
+.BI \-r " number"
+Write data with a specified number of rows per strip;
+by default the number of rows/strip is selected so that each strip
+is approximately 8 kilobytes.
+.SH "SEE ALSO"
+.BR gif2tiff (1),
+.BR pal2rgb (1),
+.BR ppm2tiff (1),
+.BR raw2tiff (1),
+.BR ras2tiff (1),
+.BR sgi2tiff (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/fax2ps.1 b/tiff/man/fax2ps.1
new file mode 100644
index 0000000..843dcd3
--- /dev/null
+++ b/tiff/man/fax2ps.1
@@ -0,0 +1,159 @@
+.\" $Id: fax2ps.1,v 1.4 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.ds Ps PostScript
+.if n .po 0
+.TH FAX2PS 1 "November 2, 2005" "libtiff"
+.SH NAME
+fax2ps \- convert a
+.SM TIFF
+facsimile to compressed \*(Ps\(tm
+.SH SYNOPSIS
+.B fax2ps
+[
+.I options
+] [
+.I file ...\&
+]
+.SH DESCRIPTION
+.I fax2ps
+reads one or more
+.SM TIFF
+facsimile image files and prints a compressed form of
+\*(Ps on the standard output that is suitable for printing.
+.PP
+By default, each page is scaled to reflect the
+image dimensions and resolutions stored in the file.
+The
+.B \-x
+and
+.B \-y
+options can be used to specify the horizontal and vertical
+image resolutions (lines/inch), respectively.
+If the
+.B \-S
+option is specified, each page is scaled to fill an output page.
+The default output page is 8.5 by 11 inches.
+Alternate page dimensions can be specified in inches with the
+.B \-W
+and
+.B \-H
+options.
+.PP
+By default
+.I fax2ps
+generates \*(Ps for all pages in the file.
+The
+.B \-p
+option can be used to select one or more pages from
+a multi-page document.
+.PP
+.I fax2ps
+generates a compressed form of \*(Ps that is
+optimized for sending pages of text to a \*(Ps
+printer attached to a host through a low-speed link (such
+as a serial line).
+Each output page is filled with white and then only
+the black areas are drawn.
+The \*(Ps specification of the black drawing operations
+is optimized by using a special font that encodes the
+move-draw operations required to fill
+the black regions on the page.
+This compression scheme typically results in a substantially
+reduced \*(Ps description, relative to the straightforward
+imaging of the page with a \*(Ps
+.I image
+operator.
+This algorithm can, however, be ineffective
+for continuous-tone and white-on-black images.
+For these images, it sometimes is more efficient to send
+the raster bitmap image directly; see
+.BR tiff2ps (1).
+.SH OPTIONS
+.TP 10
+.BI \-p " number"
+Print only the indicated page.
+Multiple pages may be printed by specifying
+this option more than once.
+.TP 10
+.BI \-x " resolution"
+Use
+.I resolution
+as the horizontal resolution, in dots/inch, of the image data.
+By default this value is taken from the file.
+.TP 10
+.BI \-y " resolution"
+Use
+.I resolution
+as the vertical resolution, in lines/inch, of the image data.
+By default this value is taken from the file.
+.TP 10
+.B \-S
+Scale each page of image data to fill the output page dimensions.
+By default images are presented according to the dimension
+information recorded in the
+.SM TIFF
+file.
+.TP 10
+.BI \-W " width"
+Use
+.I width
+as the width, in inches, of the output page.
+.TP 10
+.BI \-H " height"
+Use
+.I height
+as the height, in inches, of the output page.
+.SH DIAGNOSTICS
+Some messages about malformed
+.SM TIFF
+images come from the
+.SM TIFF
+library.
+.PP
+Various messages about badly formatted facsimile images
+may be generated due to transmission errors in received
+facsimile.
+.I fax2ps
+attempts to recover from such data errors by resynchronizing
+decoding at the end of the current scanline.
+This can result in long horizontal black lines in the resultant
+\*(Ps image.
+.SH NOTES
+If the destination printer supports \*(Ps Level II then
+it is always faster to just send the encoded bitmap generated
+by the
+.BR tiff2ps (1)
+program.
+.SH BUGS
+.I fax2ps
+should probably figure out when it is doing a poor
+job of compressing the output and just generate
+\*(Ps to image the bitmap raster instead.
+.SH "SEE ALSO"
+.BR tiff2ps (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/fax2tiff.1 b/tiff/man/fax2tiff.1
new file mode 100644
index 0000000..1ac4d7d
--- /dev/null
+++ b/tiff/man/fax2tiff.1
@@ -0,0 +1,286 @@
+.\" $Id: fax2tiff.1,v 1.7 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1990-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH FAX2TIFF 1 "November 2, 2005" "libtiff"
+.SH NAME
+fax2tiff \- create a
+.SM TIFF
+Class F fax file from raw fax data
+.SH SYNOPSIS
+.B fax2tiff
+[
+.I options
+] [
+.B \-o
+.I output.tif
+]
+.I input.raw
+.SH DESCRIPTION
+.I Fax2tiff
+creates a
+.SM TIFF
+file containing
+.SM CCITT
+Group 3 or Group 4 encoded data from one or more files containing ``raw''
+Group 3 or Group 4 encoded data (typically obtained directly from a fax modem).
+By default, each row of data in the resultant
+.SM TIFF
+file is 1-dimensionally encoded and
+padded or truncated to 1728 pixels, as needed.
+The resultant image is a set of low resolution (98 lines/inch)
+or medium resolution (196 lines/inch)
+pages, each of which is a single strip of data.
+The generated file conforms to the
+.SM TIFF
+Class F (\c
+.SM FAX\c
+) specification for storing facsimile data.
+This means, in particular, that each page of the data does
+.B not
+include the trailing
+.I "return to control"
+(\c
+.SM RTC\c
+) code; as required
+for transmission by the
+.SM CCITT
+Group 3 specifications.
+The old, ``classic'', format is created if the
+.B \-c
+option is used.
+(The Class F format can also be requested with the
+.B \-f
+option.)
+.PP
+The default name of the output image is
+.IR fax.tif ;
+this can be changed with the
+.B \-o
+option.
+Each input file is assumed to be a separate page of facsimile data
+from the same document.
+The order in which input files are specified on the command
+line is the order in which the resultant pages appear in the
+output file.
+.SH OPTIONS
+Options that affect the interpretation of input data are:
+.TP
+.B \-3
+Assume input data is
+.SM CCITT
+Group 3 encoded (default).
+.TP
+.B \-4
+Assume input data is
+.SM CCITT
+Group 4 encoded.
+.TP
+.B \-U
+Assume input data is uncompressed (Group 3 or Group 4).
+.TP
+.B \-1
+Assume input data is encoded with the 1-dimensional version of the
+.SM CCITT
+Group 3 Huffman encoding algorithm (default).
+.TP
+.B \-2
+Assume input data is 2-dimensional version of the
+.SM CCITT
+Group 3 Huffman encoding algorithm.
+.TP
+.B \-P
+Assume input data is
+.B not
+EOL-aligned (default). This option has effect with Group 3 encoded input only.
+.TP
+.B \-A
+Assume input data is EOL-aligned. This option has effect with Group 3
+encoded input only.
+.TP
+.B \-M
+Treat input data as having bits filled from most significant bit (\c
+.SM MSB\c
+) to most least bit (\c
+.SM LSB\c
+).
+.TP
+.B \-L
+Treat input data as having bits filled from least significant bit (\c
+.SM LSB\c
+) to most significant bit (\c
+.SM MSB\c
+) (default).
+.TP
+.B \-B
+Assume input data was encoded with black as 0 and white as 1.
+.TP
+.B \-W
+Assume input data was encoded with black as 1 and white as 0 (default).
+.TP
+.B \-R
+Specify the vertical resolution, in lines/inch, of the input images.
+By default input are assumed to have a vertical resolution of 196 lines/inch.
+If images are low resolution facsimile, a value of 98 lines/inch should
+be specified.
+.TP
+.B \-X
+Specify the width, in pixels, of the input images.
+By default input are assumed to have a width of 1728 pixels.
+.PP
+Options that affect the output file format are:
+.TP
+.B \-o
+Specify the name of the output file.
+.TP
+.B \-7
+Force output to be compressed with the
+.SM CCITT
+Group 3 Huffman encoding algorithm (default).
+.TP
+.B \-8
+Force output to be compressed with the
+.SM CCITT
+Group 4 Huffman encoding.
+.TP
+.B \-u
+Force output to be uncompressed (Group 3 or Group 4).
+.TP
+.B \-5
+Force output to be encoded with the 1-dimensional version of the
+.SM CCITT
+Group 3 Huffman encoding algorithm.
+.TP
+.B \-6
+Force output to be encoded with the 2-dimensional version of the
+.SM CCITT
+Group 3 Huffman encoding algorithm (default).
+.TP
+.B \-a
+Force the last bit of each
+.I "End Of Line"
+(\c
+.SM EOL\c
+) code to land on a byte boundary (default). This ``zero padding'' will
+be reflected in the contents of the
+.I Group3Options
+tag of the resultant
+.SM TIFF
+file. This option has effect with Group 3 encoded output only.
+.TP
+.B \-p
+Do not EOL-align output. This option has effect with Group 3 encoded
+output only.
+.TP
+.B \-c
+Generate "classic" Group 3 TIFF format.
+.TP
+.B \-f
+Generate TIFF Class F (TIFF/F) format (default).
+.TP
+.B \-m
+Force output data to have bits filled from most significant bit (\c
+.SM MSB\c
+) to most least bit (\c
+.SM LSB\c
+).
+.TP
+.B \-l
+Force output data to have bits filled from least significant bit (\c
+.SM LSB\c
+) to most significant bit (\c
+.SM MSB\c
+) (default).
+.TP
+.B \-r
+Specify the number of rows (scanlines) in each strip of data
+written to the output file.
+By default (or when value
+.B 0
+is specified),
+.I tiffcp
+attempts to set the rows/strip
+that no more than 8 kilobytes of data appear in a strip (with except of G3/G4
+compression schemes). If you specify special value
+.B \-1
+it will results in infinite number of the rows per strip. The entire image
+will be the one strip in that case. This is default in case of G3/G4 output
+compression schemes.
+.TP
+.B \-s
+Stretch the input image vertically by writing each input row of
+data twice to the output file.
+.TP
+.B \-v
+Force
+.I fax2tiff
+to print the number of rows of data it retrieved from the input file.
+.TP
+.B \-z
+Force output to be compressed with the LZW encoding.
+.SH DIAGNOSTICS
+The following warnings and errors come from the decoding
+routines in the library.
+.PP
+.BR "Warning, %s: Premature EOL at scanline %d (x %d).\en" .
+The input data had a row that was shorter than the expected width.
+The row is padded with white.
+.PP
+.BR "%s: Premature EOF at scanline %d (x %d).\en" .
+The decoder ran out of data in the middle of a scanline.
+The resultant row is padded with white.
+.PP
+.BR "%s: Bad code word at row %d, x %d\en" .
+An invalid Group 3
+.I code
+was encountered while decoding the input file.
+The row number and horizontal position is given.
+The remainder of the input row is discarded, while
+the corresponding output row is padded with white.
+.PP
+.BR "%s: Bad 2D code word at scanline %d.\en" .
+An invalid Group 4 or 2D Group 3
+.I code
+was encountered while decoding the input file.
+The row number and horizontal position is given.
+The remainder of the input row is discarded, while
+the corresponding output row is padded with white.
+.SH BUGS
+Input data are assumed to have a a ``top left'' orientation;
+it should be possible to override this assumption
+from the command line.
+.SH "SEE ALSO"
+.BR "\s-1CCITT\s+1 Recommendation T.4"
+(Standardization of Group 3 Facsimile Apparatus for Document Transmission).
+.PP
+.BR "The Spirit of TIFF Class F",
+an appendix to the TIFF 5.0 specification prepared by Cygnet Technologies.
+.PP
+.BR tiffinfo (1),
+.BR tiffdither (1),
+.BR tiffgt (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/gif2tiff.1 b/tiff/man/gif2tiff.1
new file mode 100644
index 0000000..14e33dd
--- /dev/null
+++ b/tiff/man/gif2tiff.1
@@ -0,0 +1,81 @@
+.\" $Id: gif2tiff.1,v 1.4 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH GIF2TIFF 1 "November 2, 2005" "libtiff"
+.SH NAME
+gif2tiff \- create a
+.SM TIFF
+file from a GIF87 format image file
+.SH SYNOPSIS
+.B gif2tiff
+[
+.I options
+]
+.I input.gif
+.I output.tif
+.SH DESCRIPTION
+.I Gif2tiff
+converts a file in the GIF87 format to
+.SM TIFF.
+The
+.SM TIFF
+image is created as a palette image, with samples
+compressed with the Lempel-Ziv & Welch algorithm (\c
+.IR Compression =5).
+These characteristics can overridden, or explicitly specified
+with the options described below.
+.SH OPTIONS
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B "\-c none"
+for no compression,
+.B "\-c packbits"
+for the PackBits compression algorithm,
+.B "\-c zip"
+for the Deflate compression algorithm,
+and
+.B "\-c lzw"
+for Lempel-Ziv & Welch (the default).
+.TP
+.B \-r
+Write data with a specified number of rows per strip;
+by default the number of rows/strip is selected so that each strip
+is approximately 8 kilobytes.
+.SH NOTES
+The program is based on Paul Haeberli's
+.I fromgif
+program which, in turn, is based on Marcel J.E. Mol's GIF reader.
+.SH BUGS
+Should have more options to control output format.
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/libtiff.3tiff b/tiff/man/libtiff.3tiff
new file mode 100644
index 0000000..0d8885f
--- /dev/null
+++ b/tiff/man/libtiff.3tiff
@@ -0,0 +1,536 @@
+.\" $Id: libtiff.3tiff,v 1.3 2005/11/02 11:07:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH INTRO 3TIFF "November 2, 2005" "libtiff"
+.SH NAME
+libtiff \- introduction to
+.IR libtiff ,
+a library for reading and writing
+.SM TIFF
+files
+.SH SYNOPSIS
+.B "#include <tiffio.h>"
+.sp
+cc file.c
+.B -ltiff
+.SH DESCRIPTION
+.I libtiff
+is a library for reading and writing data files encoded with the
+.I "Tag Image File"
+format, Revision 6.0 (or revision 5.0 or revision 4.0). This file format is
+suitable for archiving multi-color and monochromatic image data.
+.PP
+The library supports several compression algorithms, as indicated by the
+.I Compression
+field, including:
+no compression (1),
+.SM CCITT
+1D Huffman compression (2),
+.SM CCITT
+Group 3 Facsimile compression (3),
+.SM CCITT
+Group 4 Facsimile compression (4),
+Lempel-Ziv & Welch compression (5),
+baseline JPEG compression (7),
+word-aligned 1D Huffman compression (32771),
+and
+PackBits compression (32773).
+In addition, several nonstandard compression algorithms are supported: the
+4-bit compression algorithm used by the
+.I ThunderScan
+program (32809) (decompression only), NeXT's 2-bit compression algorithm
+(32766) (decompression only), an experimental LZ-style algorithm known as
+Deflate (32946), and an experimental CIE LogLuv compression scheme designed
+for images with high dynamic range (32845 for LogL and 32845 for LogLuv).
+Directory information may be in either little- or big-endian byte order\-byte
+swapping is automatically done by the library. Data bit ordering may be either
+Most Significant Bit (\c
+.SM MSB\c
+) to Least Significant Bit (\c
+.SM LSB\c
+) or
+.SM LSB
+to
+.SM MSB.
+Finally, the library does not support files in which the
+.IR BitsPerSample ,
+.IR Compression ,
+.IR MinSampleValue ,
+or
+.IR MaxSampleValue
+fields are defined differently on a per-sample basis
+(in Rev. 6.0 the
+.I Compression
+tag is not defined on a per-sample basis, so this is immaterial).
+.SH "DATA TYPES"
+The library makes extensive use of C typedefs to promote portability.
+Two sets of typedefs are used, one for communication with clients
+of the library and one for internal data structures and parsing of the
+.SM TIFF
+format.
+The following typedefs are exposed to users either through function
+definitions or through parameters passed through the varargs interfaces.
+.in +.5i
+.sp 5p
+.ta +\w'typedef unsigned <\fIthing\fP> uint32; 'u
+.nf
+typedef unsigned short uint16; 16-bit unsigned integer
+typedef unsigned <\fIthing\fP> uint32; 32-bit unsigned integer
+.sp 5p
+typedef unsigned int ttag_t; directory tag
+typedef uint16 tdir_t; directory index
+typedef uint16 tsample_t; sample number
+typedef uint32 tstrip_t; strip number
+typedef uint32 ttile_t; tile number
+typedef int32 tsize_t; i/o size in bytes
+typedef void* tdata_t; image data ref
+typedef void* thandle_t; client data handle
+typedef int32 toff_t; file offset
+.fi
+.sp 5p
+.in -.5i
+Note that
+.IR tstrip_t ,
+.IR ttile_t ,
+and
+.I tsize_t
+are constrained to be no more than 32-bit quantities by 32-bit fields they are
+stored in in the
+.SM TIFF
+image.
+Likewise
+.I tsample_t
+is limited by the 16-bit field used to store the
+.I SamplesPerPixel
+tag.
+.I tdir_t
+constrains the maximum number of
+.SM IFDs
+that may appear in an image and may be an arbitrary size (w/o penalty).
+.I ttag_t
+must be either int, unsigned int, pointer, or double because the library uses
+a varargs interface and
+.SM "ANSI C"
+restricts the type of the parameter before an ellipsis to be a promoted type.
+.I toff_t
+is defined as int32 because TIFF file offsets are (unsigned) 32-bit
+quantities. A signed value is used because some interfaces return \-1 on
+error. Finally, note that user-specified data references are passed as opaque
+handles and only cast at the lowest layers where their type is presumed.
+.SH "LIST OF ROUTINES"
+The following routines are part of the library. Consult specific manual pages
+for details on their operation; on most systems doing ``man function-name''
+will work.
+.sp
+.nf
+.ta \w'TIFFCheckpointDirectory'u+2n
+\fIName\fP \fIDescription\fP
+.sp 5p
+TIFFCheckpointDirectory writes the current state of the directory
+TIFFCheckTile very x,y,z,sample is within image
+TIFFCIELabToRGBInit initialize CIE L*a*b* 1976 to RGB conversion state
+TIFFCIELabToXYZ perform CIE L*a*b* 1976 to CIE XYZ conversion
+TIFFClientOpen open a file for reading or writing
+TIFFClose close an open file
+TIFFComputeStrip return strip containing y,sample
+TIFFComputeTile return tile containing x,y,z,sample
+TIFFCurrentDirectory return index of current directory
+TIFFCurrentRow return index of current scanline
+TIFFCurrentStrip return index of current strip
+TIFFCurrentTile return index of current tile
+TIFFDataWidth return the size of TIFF data types
+TIFFError library error handler
+TIFFFdOpen open a file for reading or writing
+TIFFFileName return name of open file
+TIFFFileno return open file descriptor
+TIFFFindCODEC find standard codec for the specific scheme
+TIFFFlush flush all pending writes
+TIFFFlushData flush pending data writes
+TIFFGetBitRevTable return bit reversal table
+TIFFGetField return tag value in current directory
+TIFFGetFieldDefaulted return tag value in current directory
+TIFFGetMode return open file mode
+TIFFGetVersion return library version string
+TIFFIsCODECConfigured check, whether we have working codec
+TIFFIsMSB2LSB return true if image data is being returned
+ with bit 0 as the most significant bit
+TIFFIsTiled return true if image data is tiled
+TIFFIsByteSwapped return true if image data is byte-swapped
+TIFFNumberOfStrips return number of strips in an image
+TIFFNumberOfTiles return number of tiles in an image
+TIFFOpen open a file for reading or writing
+TIFFPrintDirectory print description of the current directory
+TIFFReadBufferSetup specify i/o buffer for reading
+TIFFReadDirectory read the next directory
+TIFFReadEncodedStrip read and decode a strip of data
+TIFFReadEncodedTile read and decode a tile of data
+TIFFReadRawStrip read a raw strip of data
+TIFFReadRawTile read a raw tile of data
+TIFFReadRGBAImage read an image into a fixed format raster
+TIFFReadScanline read and decode a row of data
+TIFFReadTile read and decode a tile of data
+TIFFRegisterCODEC override standard codec for the specific scheme
+TIFFReverseBits reverse bits in an array of bytes
+TIFFRGBAImageBegin setup decoder state for TIFFRGBAImageGet
+TIFFRGBAImageEnd release TIFFRGBAImage decoder state
+TIFFRGBAImageGet read and decode an image
+TIFFRGBAImageOK is image readable by TIFFRGBAImageGet
+TIFFScanlineSize return size of a scanline
+TIFFSetDirectory set the current directory
+TIFFSetSubDirectory set the current directory
+TIFFSetErrorHandler set error handler function
+TIFFSetField set a tag's value in the current directory
+TIFFSetWarningHandler set warning handler function
+TIFFStripSize returns size of a strip
+TIFFRawStripSize returns the number of bytes in a raw strip
+TIFFSwabShort swap bytes of short
+TIFFSwabLong swap bytes of long
+TIFFSwabArrayOfShort swap bytes of an array of shorts
+TIFFSwabArrayOfLong swap bytes of an array of longs
+TIFFTileRowSize return size of a row in a tile
+TIFFTileSize return size of a tile
+TIFFUnRegisterCODEC unregisters the codec
+TIFFVGetField return tag value in current directory
+TIFFVGetFieldDefaulted return tag value in current directory
+TIFFVSetField set a tag's value in the current directory
+TIFFVStripSize returns the number of bytes in a strip
+TIFFWarning library warning handler
+TIFFWriteDirectory write the current directory
+TIFFWriteEncodedStrip compress and write a strip of data
+TIFFWriteEncodedTile compress and write a tile of data
+TIFFWriteRawStrip write a raw strip of data
+TIFFWriteRawTile write a raw tile of data
+TIFFWriteScanline write a scanline of data
+TIFFWriteTile compress and write a tile of data
+TIFFXYZToRGB perform CIE XYZ to RGB conversion
+TIFFYCbCrToRGBInit initialize YCbCr to RGB conversion state
+TIFFYCbCrtoRGB perform YCbCr to RGB conversion
+.sp
+Auxiliary functions:
+_TIFFfree free memory buffer
+_TIFFmalloc dynamically allocate memory buffer
+_TIFFmemcmp compare contents of the memory buffers
+_TIFFmemcpy copy contents of the one buffer to another
+_TIFFmemset fill memory buffer with a constant byte
+_TIFFrealloc dynamically reallocate memory buffer
+
+.fi
+.SH "TAG USAGE"
+The table below lists the
+.SM TIFF
+tags that are recognized and handled by the library.
+If no use is indicated in the table, then the library
+reads and writes the tag, but does not use it internally.
+Note that some tags are meaningful only when a particular
+compression scheme is being used; e.g.
+.I Group3Options
+is only useful if
+.I Compression
+is set to
+.SM CCITT
+Group 3 encoding.
+Tags of this sort are considered
+.I codec-specific
+tags and the library does not recognize them except when the
+.I Compression
+tag has been previously set to the relevant compression scheme.
+.sp
+.nf
+.ta \w'TIFFTAG_JPEGTABLESMODE'u+2n +\w'Value'u+2n +\w'R/W'u+2n
+\fITag Name\fP \fIValue\fP \fIR/W\fP \fILibrary Use/Notes\fP
+.sp 5p
+.nf
+Artist 315 R/W
+BadFaxLines 326 R/W
+BitsPerSample 258 R/W lots
+CellLength 265 parsed but ignored
+CellWidth 264 parsed but ignored
+CleanFaxData 327 R/W
+ColorMap 320 R/W
+ColorResponseUnit 300 parsed but ignored
+Compression 259 R/W choosing codec
+ConsecutiveBadFaxLines 328 R/W
+Copyright 33432 R/W
+DataType 32996 R obsoleted by SampleFormat tag
+DateTime 306 R/W
+DocumentName 269 R/W
+DotRange 336 R/W
+ExtraSamples 338 R/W lots
+FaxRecvParams 34908 R/W
+FaxSubAddress 34909 R/W
+FaxRecvTime 34910 R/W
+FillOrder 266 R/W control bit order
+FreeByteCounts 289 parsed but ignored
+FreeOffsets 288 parsed but ignored
+GrayResponseCurve 291 parsed but ignored
+GrayResponseUnit 290 parsed but ignored
+Group3Options 292 R/W used by Group 3 codec
+Group4Options 293 R/W
+HostComputer 316 R/W
+ImageDepth 32997 R/W tile/strip calculations
+ImageDescription 270 R/W
+ImageLength 257 R/W lots
+ImageWidth 256 R/W lots
+InkNames 333 R/W
+InkSet 332 R/W
+JPEGTables 347 R/W used by JPEG codec
+Make 271 R/W
+Matteing 32995 R obsoleted by ExtraSamples tag
+MaxSampleValue 281 R/W
+MinSampleValue 280 R/W
+Model 272 R/W
+NewSubFileType 254 R/W called SubFileType in spec
+NumberOfInks 334 R/W
+Orientation 274 R/W
+PageName 285 R/W
+PageNumber 297 R/W
+PhotometricInterpretation 262 R/W used by Group 3 and JPEG codecs
+PlanarConfiguration 284 R/W data i/o
+Predictor 317 R/W used by LZW and Deflate codecs
+PrimaryChromacities 319 R/W
+ReferenceBlackWhite 532 R/W
+ResolutionUnit 296 R/W used by Group 3 codec
+RowsPerStrip 278 R/W data i/o
+SampleFormat 339 R/W
+SamplesPerPixel 277 R/W lots
+SMinSampleValue 340 R/W
+SMaxSampleValue 341 R/W
+Software 305 R/W
+StoNits 37439 R/W
+StripByteCounts 279 R/W data i/o
+StripOffsets 273 R/W data i/o
+SubFileType 255 R/W called OSubFileType in spec
+TargetPrinter 337 R/W
+Thresholding 263 R/W
+TileByteCounts 324 R/W data i/o
+TileDepth 32998 R/W tile/strip calculations
+TileLength 323 R/W data i/o
+TileOffsets 324 R/W data i/o
+TileWidth 322 R/W data i/o
+TransferFunction 301 R/W
+WhitePoint 318 R/W
+XPosition 286 R/W
+XResolution 282 R/W
+YCbCrCoefficients 529 R/W used by TIFFRGBAImage support
+YCbCrPositioning 531 R/W tile/strip size calulcations
+YCbCrSubsampling 530 R/W
+YPosition 286 R/W
+YResolution 283 R/W used by Group 3 codec
+.SH "PSEUDO TAGS"
+In addition to the normal
+.SM TIFF
+tags the library supports a collection of
+tags whose values lie in a range outside the valid range of
+.SM TIFF
+tags.
+These tags are termed
+.I pseud-tags
+and are used to control various codec-specific functions within the library.
+The table below summarizes the defined pseudo-tags.
+.sp
+.nf
+.ta \w'TIFFTAG_JPEGTABLESMODE'u+2n +\w'Codec'u+2n +\w'R/W'u+2n
+\fITag Name\fP \fICodec\fP \fIR/W\fP \fILibrary Use/Notes\fP
+.sp 5p
+.nf
+TIFFTAG_FAXMODE G3 R/W general codec operation
+TIFFTAG_FAXFILLFUNC G3/G4 R/W bitmap fill function
+TIFFTAG_JPEGQUALITY JPEG R/W compression quality control
+TIFFTAG_JPEGCOLORMODE JPEG R/W control colorspace conversions
+TIFFTAG_JPEGTABLESMODE JPEG R/W control contents of \fIJPEGTables\fP tag
+TIFFTAG_ZIPQUALITY Deflate R/W compression quality level
+TIFFTAG_PIXARLOGDATAFMT PixarLog R/W user data format
+TIFFTAG_PIXARLOGQUALITY PixarLog R/W compression quality level
+TIFFTAG_SGILOGDATAFMT SGILog R/W user data format
+.fi
+.TP
+.B TIFFTAG_FAXMODE
+Control the operation of the Group 3 codec.
+Possible values (independent bits that can be combined by
+or'ing them together) are:
+FAXMODE_CLASSIC
+(enable old-style format in which the
+.SM RTC
+is written at the end of the last strip),
+FAXMODE_NORTC
+(opposite of
+FAXMODE_CLASSIC;
+also called
+FAXMODE_CLASSF),
+FAXMODE_NOEOL
+(do not write
+.SM EOL
+codes at the start of each row of data),
+FAXMODE_BYTEALIGN
+(align each encoded row to an 8-bit boundary),
+FAXMODE_WORDALIGN
+(align each encoded row to an 16-bit boundary),
+The default value is dependent on the compression scheme; this
+pseudo-tag is used by the various G3 and G4 codecs to share code.
+.TP
+.B TIFFTAG_FAXFILLFUNC
+Control the function used to convert arrays of black and white
+runs to packed bit arrays.
+This hook can be used to image decoded scanlines in multi-bit
+depth rasters (e.g. for display in colormap mode)
+or for other purposes.
+The default value is a pointer to a builtin function that images
+packed bilevel data.
+.TP
+.B TIFFTAG_IPTCNEWSPHOTO
+Tag contaings image metadata per the IPTC newsphoto spec: Headline,
+captioning, credit, etc... Used by most wire services.
+.TP
+.B TIFFTAG_PHOTOSHOP
+Tag contains Photoshop captioning information and metadata. Photoshop
+uses in parallel and redundantly alongside IPTCNEWSPHOTO information.
+.TP
+.B TIFFTAG_JPEGQUALITY
+Control the compression quality level used in the baseline algorithm.
+Note that quality levels are in the range 0-100 with a default value of 75.
+.TP
+.B TIFFTAG_JPEGCOLORMODE
+Control whether or not conversion is done between
+RGB and YCbCr colorspaces.
+Possible values are:
+JPEGCOLORMODE_RAW
+(do not convert), and
+JPEGCOLORMODE_RGB
+(convert to/from RGB)
+The default value is JPEGCOLORMODE_RAW.
+.TP
+.B TIFFTAG_JPEGTABLESMODE
+Control the information written in the
+.I JPEGTables
+tag.
+Possible values (independent bits that can be combined by
+or'ing them together) are:
+JPEGTABLESMODE_QUANT
+(include quantization tables),
+and
+JPEGTABLESMODE_HUFF
+(include Huffman encoding tables).
+The default value is JPEGTABLESMODE_QUANT|JPEGTABLESMODE_HUFF.
+.TP
+.B TIFFTAG_ZIPQUALITY
+Control the compression technique used by the Deflate codec.
+Quality levels are in the range 1-9 with larger numbers yielding better
+compression at the cost of more computation.
+The default quality level is 6 which yields a good time-space tradeoff.
+.TP
+.B TIFFTAG_PIXARLOGDATAFMT
+Control the format of user data passed
+.I in
+to the PixarLog codec when encoding and passed
+.I out
+from when decoding.
+Possible values are:
+PIXARLOGDATAFMT_8BIT
+for 8-bit unsigned pixels,
+PIXARLOGDATAFMT_8BITABGR
+for 8-bit unsigned ABGR-ordered pixels,
+PIXARLOGDATAFMT_11BITLOG
+for 11-bit log-encoded raw data,
+PIXARLOGDATAFMT_12BITPICIO
+for 12-bit PICIO-compatible data,
+PIXARLOGDATAFMT_16BIT
+for 16-bit signed samples,
+and
+PIXARLOGDATAFMT_FLOAT
+for 32-bit IEEE floating point samples.
+.TP
+.B TIFFTAG_PIXARLOGQUALITY
+Control the compression technique used by the PixarLog codec.
+This value is treated identically to TIFFTAG_ZIPQUALITY; see the
+above description.
+.TP
+.B TIFFTAG_SGILOGDATAFMT
+Control the format of client data passed
+.I in
+to the SGILog codec when encoding and passed
+.I out
+from when decoding.
+Possible values are:
+SGILOGDATAFMT_FLTXYZ
+for converting between LogLuv and 32-bit IEEE floating valued XYZ pixels,
+SGILOGDATAFMT_16BITLUV
+for 16-bit encoded Luv pixels,
+SGILOGDATAFMT_32BITRAW and SGILOGDATAFMT_24BITRAW
+for no conversion of data,
+SGILOGDATAFMT_8BITRGB
+for returning 8-bit RGB data (valid only when decoding LogLuv-encoded data),
+SGILOGDATAFMT_FLTY
+for converting between LogL and 32-bit IEEE floating valued Y pixels,
+SGILOGDATAFMT_16BITL
+for 16-bit encoded L pixels,
+and
+SGILOGDATAFMT_8BITGRY
+for returning 8-bit greyscale data
+(valid only when decoding LogL-encoded data).
+.SH DIAGNOSTICS
+All error messages are directed through the
+.IR TIFFError
+routine.
+By default messages are directed to
+.B stderr
+in the form:
+.IR "module: message\en."
+Warning messages are likewise directed through the
+.IR TIFFWarning
+routine.
+.SH "SEE ALSO"
+.BR fax2tiff (1),
+.BR gif2tiff (1),
+.BR pal2rgb (1),
+.BR ppm2tiff (1),
+.BR rgb2ycbcr (1),
+.BR ras2tiff (1),
+.BR raw2tiff (1),
+.BR sgi2tiff (1),
+.BR tiff2bw (1),
+.BR tiffdither (1),
+.BR tiffdump (1),
+.BR tiffcp (1),
+.BR tiffcmp (1),
+.BR tiffgt (1),
+.BR tiffinfo (1),
+.BR tiffmedian (1),
+.BR tiffsplit (1),
+.BR tiffsv (1).
+.PP
+.BR "Tag Image File Format Specification \(em Revision 6.0" ,
+an Aldus Technical Memorandum.
+.PP
+.BR "The Spirit of TIFF Class F" ,
+an appendix to the TIFF 5.0 specification prepared by Cygnet Technologies.
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
+.SH BUGS
+The library does not support multi-sample images
+where some samples have different bits/sample.
+.PP
+The library does not support random access to compressed data
+that is organized with more than one row per tile or strip.
diff --git a/tiff/man/pal2rgb.1 b/tiff/man/pal2rgb.1
new file mode 100644
index 0000000..8dd87ac
--- /dev/null
+++ b/tiff/man/pal2rgb.1
@@ -0,0 +1,111 @@
+.\" $Id: pal2rgb.1,v 1.3 2005/11/02 11:07:19 dron Exp $
+.\"
+.\" Copyright (c) 1990-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH PAL2RGB 1 "September 20, 2005" "libtiff"
+.SH NAME
+pal2rgb \- convert a palette color
+.SM TIFF
+image to a full color image
+.SH SYNOPSIS
+.B pal2rgb
+[
+.I options
+]
+.I input.tif
+.I output.tif
+.SH DESCRIPTION
+.I Pal2rgb
+converts a palette color
+.SM TIFF
+image to a full color image by
+applying the colormap of the palette image to each sample
+to generate a full color
+.SM RGB
+image.
+.SH OPTIONS
+Options that affect the interpretation of input data are:
+.TP
+.B \-C
+This option overrides the default behavior of
+.I pal2rgb
+in determining whether or not
+colormap entries contain 16-bit or 8-bit values.
+By default the colormap is inspected and
+if no colormap entry greater than 255 is found,
+the colormap is assumed to have only 8-bit values; otherwise
+16-bit values (as required by the
+.SM TIFF
+specification) are assumed.
+The
+.B \-C
+option can be used to explicitly specify the number of
+bits for colormap entries:
+.B "\-C 8"
+for 8-bit values,
+.B "\-C 16"
+for 16-bit values.
+.PP
+Options that affect the output file format are:
+.TP
+.B \-p
+Explicitly select the planar configuration used in organizing
+data samples in the output image:
+.B "\-p contig"
+for samples packed contiguously, and
+.B "\-p separate"
+for samples stored separately.
+By default samples are packed.
+.TP
+.B \-c
+Use the specific compression algorithm to encoded image data
+in the output file:
+.B "\-c packbits"
+for Macintosh Packbits,
+.B "\-c lzw"
+for Lempel-Ziv & Welch,
+.B "\-c zip"
+for Deflate,
+.B "\-c none"
+for no compression.
+If no compression-related option is specified, the input
+file's compression algorithm is used.
+.TP
+.B \-r
+Explicitly specify the number of rows in each strip of the
+output file.
+If the
+.B \-r
+option is not specified, a number is selected such that each
+output strip has approximately 8 kilobytes of data in it.
+.SH BUGS
+Only 8-bit images are handled.
+.SH "SEE ALSO"
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/ppm2tiff.1 b/tiff/man/ppm2tiff.1
new file mode 100644
index 0000000..b951444
--- /dev/null
+++ b/tiff/man/ppm2tiff.1
@@ -0,0 +1,105 @@
+.\" $Id: ppm2tiff.1,v 1.5 2006/03/01 11:20:33 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH PPM2TIFF 1 "March 1, 2006" "libtiff"
+.SH NAME
+ppm2tiff \- create a
+.SM TIFF
+file from
+.SM PPM, PGM
+and
+.SM PBM
+image files
+.SH SYNOPSIS
+.B ppm2tiff
+[
+.I options
+] [
+.I input.ppm
+]
+.I output.tif
+.SH DESCRIPTION
+.I ppm2tiff
+converts a file in the
+.SM PPM, PGM
+and
+.SM PBM
+image formats to
+.SM TIFF.
+By default, the
+.SM TIFF
+image is created with data samples packed (\c
+.IR PlanarConfiguration =1),
+compressed with the Packbits algorithm (\c
+.IR Compression =32773),
+and with each strip no more than 8 kilobytes. These characteristics can be
+overridden, or explicitly specified with the options described below
+.PP
+If the
+.SM PPM
+file contains greyscale data, then the
+.I PhotometricInterpretation
+tag is set to 1 (min-is-black), otherwise it is set to 2 (RGB).
+.PP
+If no
+.SM PPM
+file is specified on the command line,
+.I ppm2tiff
+will read from the standard input.
+.SH OPTIONS
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B none
+for no compression,
+.B packbits
+for PackBits compression (will be used by default),
+.B lzw
+for Lempel-Ziv & Welch compression,
+.B jpeg
+for baseline JPEG compression,
+.B zip
+for Deflate compression,
+.B g3
+for CCITT Group 3 (T.4) compression,
+and
+.B g4
+for CCITT Group 4 (T.6) compression.
+.TP
+.B \-r
+Write data with a specified number of rows per strip; by default the number of
+rows/strip is selected so that each strip is approximately 8 kilobytes.
+.TP
+.B \-R
+Mark the resultant image to have the specified X and Y resolution (in
+dots/inch).
+.SH "SEE ALSO"
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/ras2tiff.1 b/tiff/man/ras2tiff.1
new file mode 100644
index 0000000..a2c40c7
--- /dev/null
+++ b/tiff/man/ras2tiff.1
@@ -0,0 +1,96 @@
+.\" $Id: ras2tiff.1,v 1.4 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1990-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH RAS2TIFF 1 "November 2, 2005" "libtiff"
+.SH NAME
+ras2tiff \- create a
+.SM TIFF
+file from a Sun rasterfile
+.SH SYNOPSIS
+.B ras2tiff
+[
+.I options
+]
+.I input.ras
+.I output.tif
+.SH DESCRIPTION
+.I ras2tiff
+converts a file in the Sun rasterfile format to
+.SM TIFF.
+By default, the
+.SM TIFF
+image is created with data samples packed (\c
+.IR PlanarConfiguration =1),
+compressed with the Lempel-Ziv & Welch algorithm (\c
+.IR Compression =5),
+and with each strip no more than 8 kilobytes.
+These characteristics can overridden, or explicitly specified
+with the options described below.
+.PP
+Any colormap information in the rasterfile is carried over to the
+.SM TIFF
+file by including a
+.I Colormap
+tag in the output file.
+If the rasterfile has a colormap, the
+.I PhotometricInterpretation
+tag is set to 3 (palette);
+otherwise it is set to 2 (RGB) if the depth
+is 24 or 1 (min-is-black) if the depth is not 24.
+.SH OPTIONS
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B "\-c none"
+for no compression,
+.B "\-c packbits"
+for the PackBits compression algorithm,
+.B "\-c jpeg"
+for the baseline JPEG compression algorithm,
+.B "\-c zip
+for the Deflate compression algorithm,
+and
+.B "\-c lzw"
+for Lempel-Ziv & Welch (the default).
+.TP
+.B \-r
+Write data with a specified number of rows per strip;
+by default the number of rows/strip is selected so that each strip
+is approximately 8 kilobytes.
+.SH BUGS
+Does not handle all possible rasterfiles.
+In particular,
+.I ras2tiff
+does not handle run-length encoded images.
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
+
diff --git a/tiff/man/raw2tiff.1 b/tiff/man/raw2tiff.1
new file mode 100644
index 0000000..dc47b9e
--- /dev/null
+++ b/tiff/man/raw2tiff.1
@@ -0,0 +1,196 @@
+.\" $Id: raw2tiff.1,v 1.6 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1990-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH RAW2TIFF 1 "November 2, 2005" "libtiff"
+.SH NAME
+raw2tiff \- create a
+.SM TIFF
+file from a raw data
+.SH SYNOPSIS
+.B raw2tiff
+[
+.I options
+]
+.I input.raw
+.I output.tif
+.SH DESCRIPTION
+.I raw2tiff
+converts a raw byte sequence into
+.SM TIFF.
+By default, the
+.SM TIFF
+image is created with data samples packed (\c
+.IR PlanarConfiguration =1),
+compressed with the PackBits algorithm (\c
+.IR Compression =32773),
+and with each strip no more than 8 kilobytes.
+These characteristics can overridden, or explicitly specified
+with the options described below.
+.SH OPTIONS
+.TP
+.BI \-H " number"
+size of input image file header in bytes (0 by default). This amount of data
+just will be skipped from the start of file while reading.
+.TP
+.BI \-w " number"
+width of input image in pixels (can be guessed, see
+.SM
+.B "GUESSING THE IMAGE GEOMETRY"
+below).
+.TP
+.BI \-l " number"
+length of input image in lines (can be guessed, see
+.SM
+.B "GUESSING THE IMAGE GEOMETRY"
+below).
+.TP
+.BI \-b " number"
+number of bands in input image (1 by default).
+.TP
+.BI \-d " data_type"
+type of samples in input image, where
+.I data_type
+may be:
+.ta \w'\fBdouble \fR'u
+.br
+.B byte\t
+8-bit unsigned integer (default),
+.br
+.B short\t
+16-bit unsigned integer,
+.br
+.B long\t
+32-bit unsigned integer,
+.br
+.B sbyte\t
+8-bit signed integer,
+.br
+.B sshort\t
+16-bit signed integer,
+.br
+.B slong\t
+32-bit signed integer,
+.br
+.B float\t
+32-bit IEEE floating point,
+.br
+.B double\t
+64-bit IEEE floating point.
+.TP
+.BI \-i " config"
+type of samples interleaving in input image, where
+.I config
+may be:
+.ta \w'\fBpixel \fR'u
+.br
+.B pixel\t
+pixel interleaved data (default),
+.br
+.B band\t
+band interleaved data.
+.TP
+.BI \-p " photo"
+photometric interpretation (color space) of the input image, where
+.I photo
+may be:
+.ta \w'\fBminiswhite \fR'u
+.br
+.B miniswhite\t
+white color represented with 0 value,
+.br
+.B minisblack\t
+black color represented with 0 value (default),
+.br
+.B rgb\t
+image has RGB color model,
+.br
+.B cmyk\t
+image has CMYK (separated) color model,
+.br
+.B ycbcr\t
+image has YCbCr color model,
+.br
+.B cielab\t
+image has CIE L*a*b color model,
+.br
+.B icclab\t
+image has ICC L*a*b color model,
+.br
+.B itulab\t
+image has ITU L*a*b color model.
+.TP
+.B \-s
+swap bytes fetched from the input file.
+.TP
+.B \-L
+input data has LSB2MSB bit order (default).
+.TP
+.B \-M
+input data has MSB2LSB bit order.
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B "\-c none"
+for no compression,
+.B "\-c packbits"
+for the PackBits compression algorithm (the default),
+.B "\-c jpeg"
+for the baseline JPEG compression algorithm,
+.B "\-c zip"
+for the Deflate compression algorithm,
+and
+.B "\-c lzw"
+for Lempel-Ziv & Welch.
+.TP
+.BI \-r " number"
+Write data with a specified number of rows per strip;
+by default the number of rows/strip is selected so that each strip
+is approximately 8 kilobytes.
+.SH GUESSING THE IMAGE GEOMETRY
+.I raw2tiff
+can guess image width and height in case one or both of these parameters are
+not specified. If you omit one of those parameters, the complementary one will
+be calculated based on the file size (taking into account header size, number
+of bands and data type). If you omit both parameters, the statistical approach
+will be used. Utility will compute correlation coefficient between two lines
+at the image center using several appropriate line sizes and the highest
+absolute value of the coefficient will indicate the right line size. That is
+why you should be cautious with the very large images, because guessing
+process may take a while (depending on your system performance). Of course, the
+utility can't guess the header size, number of bands and data type, so it
+should be specified manually. If you don't know anything about your image,
+just try with the several combinations of those options.
+.P
+There is no magic, it is just a mathematical statistics, so it can be wrong
+in some cases. But for most ordinary images guessing method will work fine.
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.bR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/rgb2ycbcr.1 b/tiff/man/rgb2ycbcr.1
new file mode 100644
index 0000000..53f5050
--- /dev/null
+++ b/tiff/man/rgb2ycbcr.1
@@ -0,0 +1,99 @@
+.\" $Header: /cvs/maptools/cvsroot/libtiff/man/rgb2ycbcr.1,v 1.4 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH RGB2YCBCR 1 "November 2, 2005" "libtiff"
+.SH NAME
+rgb2ycbcr \- convert non-YCbCr
+.SM TIFF
+images to a YCbCr
+.SM TIFF
+image
+.SH SYNOPSIS
+.B rgb2ycbcr
+[
+.I options
+]
+.I "src1.tif src2.tif ... dst.tif"
+.SH DESCRIPTION
+.I rgb2ycbcr
+converts
+.SM RGB
+color, greyscale, or bi-level
+.SM TIFF
+images to YCbCr images by transforming and sampling pixel data. If multiple
+files are specified on the command line each source file is converted to a
+separate directory in the destination file.
+.PP
+By default, chrominance samples are created by sampling
+2 by 2 blocks of luminance values; this can be changed with the
+.B \-h
+and
+.B \-v
+options.
+Output data are compressed with the
+.SM PackBits
+compression scheme, by default; an alternate scheme can be selected with the
+.B \-c
+option.
+By default, output data are compressed in strips with
+the number of rows in each strip selected so that the
+size of a strip is never more than 8 kilobytes;
+the
+.B \-r
+option can be used to explicitly set the number of
+rows per strip.
+.SH OPTIONS
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B "\-c none"
+for no compression,
+.B "\-c packbits"
+for the PackBits compression algorithm (the default),
+.B "\-c jpeg"
+for the JPEG compression algorithm,
+.B "\-c zip"
+for the deflate compression algorithm,
+and
+.B "\-c lzw"
+for Lempel-Ziv & Welch.
+.TP
+.B \-h
+Set the horizontal sampling dimension to one of: 1, 2 (default), or 4.
+.TP
+.B \-r
+Write data with a specified number of rows per strip;
+by default the number of rows/strip is selected so that each strip
+is approximately 8 kilobytes.
+.TP
+.B \-v
+Set the vertical sampling dimension to one of: 1, 2 (default), or 4.
+.SH "SEE ALSO"
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff
diff --git a/tiff/man/sgi2tiff.1 b/tiff/man/sgi2tiff.1
new file mode 100644
index 0000000..b6e86b1
--- /dev/null
+++ b/tiff/man/sgi2tiff.1
@@ -0,0 +1,93 @@
+.\" $Id: sgi2tiff.1,v 1.4 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1991-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH SGI2TIFF 1 "November 2, 2005" "libtiff"
+.SH NAME
+sgi2tiff \- create a
+.SM TIFF
+file from an
+.SM SGI
+image file
+.SH SYNOPSIS
+.B sgi2tiff
+[
+.I options
+]
+.I input.rgb
+.I output.tif
+.SH DESCRIPTION
+.I sgi2tiff
+converts a file in the
+.SM SGI
+image format to
+.SM TIFF.
+By default, the
+.SM TIFF
+image is created with data samples packed (\c
+.IR PlanarConfiguration =1),
+compressed with the Lempel-Ziv & Welch algorithm (\c
+.IR Compression =5),
+and with each strip no more than 8 kilobytes.
+These characteristics can overridden, or explicitly specified
+with the options described below.
+.SH OPTIONS
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B "\-c none"
+for no compression,
+.B "\-c packbits"
+for the PackBits compression algorithm),
+.B "\-c jpeg"
+for the baseline JPEG compression algorithm,
+.B "\-c zip
+for the Deflate compression algorithm,
+and
+.B "\-c lzw"
+for Lempel-Ziv & Welch (the default).
+.TP
+.B \-p
+Explicitly select the planar configuration used in organizing
+data samples in the output image:
+.B "\-p contig"
+for samples packed contiguously, and
+.B "\-p separate"
+for samples stored separately.
+By default samples are packed.
+.TP
+.B \-r
+Write data with a specified number of rows per strip;
+by default the number of rows/strip is selected so that each strip
+is approximately 8 kilobytes.
+.SH BUGS
+Does not record colormap information.
+.SH "SEE ALSO"
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/thumbnail.1 b/tiff/man/thumbnail.1
new file mode 100644
index 0000000..e9d6213
--- /dev/null
+++ b/tiff/man/thumbnail.1
@@ -0,0 +1,90 @@
+.\" $Id: thumbnail.1,v 1.2 2005/11/02 11:07:19 dron Exp $
+.\"
+.\" Copyright (c) 1994-1997 Sam Leffler
+.\" Copyright (c) 1994-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH THUMBNAIL 1 "November 2, 2005" "libtiff"
+.SH NAME
+thumbnail \- create a
+.SM TIFF
+file with thumbnail images
+.SH SYNOPSIS
+.B thumbnail
+[
+.I options
+]
+.I input.tif
+.I output.tif
+.SH DESCRIPTION
+.I thumbnail
+is a program written to show how one might use the
+SubIFD tag (#330) to store thumbnail images.
+.I thumbnail
+copies a
+.SM TIFF
+Class F facsimile file to the output file
+and for each image an 8-bit greyscale
+.IR "thumbnail sketch" .
+The output file contains the thumbnail image with the associated
+full-resolution page linked below with the SubIFD tag.
+.PP
+By default, thumbnail images are 216 pixels wide by 274 pixels high.
+Pixels are calculated by sampling and filtering the input image
+with each pixel value passed through a contrast curve.
+.SH OPTIONS
+.TP
+.B \-w
+Specify the width of thumbnail images in pixels.
+.TP
+.B \-h
+Specify the height of thumbnail images in pixels.
+.TP
+.B \-c
+Specify a contrast curve to apply in generating the thumbnail images.
+By default pixels values are passed through a linear contrast curve
+that simply maps the pixel value ranges.
+Alternative curves are:
+.B exp50
+for a 50% exponential curve,
+.B exp60
+for a 60% exponential curve,
+.B exp70
+for a 70% exponential curve,
+.B exp80
+for a 80% exponential curve,
+.B exp90
+for a 90% exponential curve,
+.B exp
+for a pure exponential curve,
+.B linear
+for a linear curve.
+.SH BUGS
+There are no options to control the format of the saved thumbnail images.
+.SH "SEE ALSO"
+.BR tiffdump (1),
+.BR tiffgt (1),
+.BR tiffinfo (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiff2bw.1 b/tiff/man/tiff2bw.1
new file mode 100644
index 0000000..4949b9a
--- /dev/null
+++ b/tiff/man/tiff2bw.1
@@ -0,0 +1,94 @@
+.\" $Id: tiff2bw.1,v 1.3 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFF2BW 1 "November 2, 2005" "libtiff"
+.SH NAME
+tiff2bw \- convert a color
+.SM TIFF
+image to greyscale
+.SH SYNOPSIS
+.B tiff2bw
+[
+.I options
+]
+.I input.tif
+.I output.tif
+.SH DESCRIPTION
+.I Tiff2bw
+converts an
+.SM RGB
+or Palette color
+.SM TIFF
+image to a greyscale image by
+combining percentages of the red, green, and blue channels.
+By default, output samples are created by taking
+28% of the red channel, 59% of the green channel, and 11% of
+the blue channel.
+To alter these percentages, the
+.BR \-R ,
+.BR \-G ,
+and
+.BR \-B
+options may be used.
+.SH OPTIONS
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B "\-c none"
+for no compression,
+.B "\-c packbits"
+for the PackBits compression algorithm,
+.B "\-c zip
+for the Deflate compression algorithm,
+.B "\-c g3
+for the CCITT Group 3 compression algorithm,
+.B "\-c g4
+for the CCITT Group 4 compression algorithm,
+and
+.B "\-c lzw"
+for Lempel-Ziv & Welch (the default).
+.TP
+.B \-r
+Write data with a specified number of rows per strip;
+by default the number of rows/strip is selected so that each strip
+is approximately 8 kilobytes.
+.TP
+.B \-R
+Specify the percentage of the red channel to use (default 28).
+.TP
+.B \-G
+Specify the percentage of the green channel to use (default 59).
+.TP
+.B \-B
+Specify the percentage of the blue channel to use (default 11).
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiff2pdf.1 b/tiff/man/tiff2pdf.1
new file mode 100644
index 0000000..9c54e9e
--- /dev/null
+++ b/tiff/man/tiff2pdf.1
@@ -0,0 +1,251 @@
+.\" $Id: tiff2pdf.1,v 1.6 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 2003 Ross Finlayson
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the name of
+.\" Ross Finlayson may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Ross Finlayson.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL ROSS FINLAYSON BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.\" Process this file with
+.\" groff -man -Tascii tiff2pdf.1
+.\"
+.TH TIFF2PDF 1 "April 20, 2006" "libtiff"
+.SH NAME
+tiff2pdf \- convert a TIFF image to a PDF document
+.SH SYNOPSIS
+.B tiff2pdf
+[
+.I options
+]
+.I input.tiff
+.SH DESCRIPTION
+.I tiff2pdf
+opens a TIFF image and writes a PDF document to standard output.
+.PP
+The program converts one TIFF file to one PDF file, including multiple page
+TIFF files, tiled TIFF files, black and white. grayscale, and color TIFF
+files that contain data of TIFF photometric interpretations of bilevel,
+grayscale, RGB, YCbCr, CMYK separation, and ICC L*a*b* as supported by
+.I libtiff
+and PDF.
+.PP
+If you have multiple TIFF files to convert into one PDF file then use
+.I tiffcp
+or other program to concatenate the files into a multiple page TIFF file.
+If the input TIFF file is of huge dimensions (greater than 10000 pixels height
+or width) convert the input image to a tiled TIFF if it is not already.
+.PP
+The standard output is standard output. Set the output file name with the
+.BI \-o " output.pdf"
+option.
+.PP
+All black and white files are compressed into a single strip CCITT G4 Fax
+compressed PDF, unless tiled, where tiled black and white images are
+compressed into tiled CCITT G4 Fax compressed PDF,
+.I libtiff
+CCITT support is assumed.
+.PP
+Color and grayscale data can be compressed using either JPEG compression,
+ITU-T T.81, or Zip/Deflate LZ77 compression. Set the compression type using
+the
+.B \-j
+or
+.B \-z
+options. JPEG compression support
+requires that
+.I libtiff
+be configured with JPEG support, and Zip/Deflate compression support requires
+that
+.I libtiff
+be configured with Zip support, in tiffconf.h. Use only one or the other of
+.B \-j
+and
+.B \-z.
+.PP
+If the input TIFF contains single strip CCITT G4 Fax compressed information,
+then that is written to the PDF file without transcoding, unless the options
+of no compression and no passthrough are set,
+.B \-d
+and
+.B \-n.
+.PP
+If the input TIFF contains JPEG or single strip Zip/Deflate compressed
+information, and they are configured, then that is written to the PDF file
+without transcoding, unless the options of no compression and no passthrough
+are set.
+.PP
+The default page size upon which the TIFF image is placed is determined by
+the resolution and extent of the image data. Default values for the TIFF
+image resolution can be set using the
+.B \-x
+and
+.B \-y
+options. The page size can be set using the
+.B \-p
+option for paper size, or
+.B \-w
+and
+.B \-l
+for paper width and length, then each page of the TIFF image is centered on
+its page. The distance unit for default resolution and page width and
+length can be set by the
+.B \-u
+option, the default unit is inch.
+.PP
+Various items of the output document information can be set with the
+.BR \-e ,
+.BR \-c ,
+.BR \-a ,
+.BR \-t ,
+.BR \-s ,
+and
+.B \-k
+options. Setting the argument of the option to "" for these
+tags causes the relevant document information field to be not written. Some
+of the document information values otherwise get their information from the
+input TIFF image, the software, author, document name, and image description.
+.PP
+The Portable Document Format (PDF) specification is copyrighted by Adobe
+Systems, Incorporated.
+.SH OPTIONS
+.TP
+.BI \-o " output-file"
+Set the output to go to file.
+.I output-file
+.TP
+.B \-j
+Compress with JPEG (requires
+.I libjpeg
+configured with
+.IR libtiff ).
+.TP
+.B \-z
+Compress with Zip/Deflate (requires
+.I zlib
+configured with
+.IR libtiff ).
+.TP
+.BI \-q " quality"
+Set the compression quality, 1-100 for JPEG.
+.TP
+.B \-n
+Do not allow data to be converted without uncompressing, no compressed
+data passthrough.
+.TP
+.BI \-b
+Set PDF ``Interpolate'' user preference.
+.TP
+.B \-d
+Do not compress (decompress).
+.TP
+.B \-i
+Invert colors.
+.TP
+.BI \-p " paper-size"
+Set paper size, e.g.,
+.BR letter ,
+.BR legal ,
+.BR A4 .
+.TP
+.BR \-u " [" i | m ]
+Set distance unit,
+.B i
+for inch,
+.B m
+for centimeter.
+.TP
+.BI \-w " width"
+Set width in units.
+.TP
+.BI \-l " length"
+Set length in units.
+.TP
+.BI \-x " xres"
+Set x/width resolution default.
+.TP
+.BI \-y " yres"
+Set y/length resolution default.
+.TP
+.BR \-r " [" d | o ]
+Set
+.B d
+for resolution default for images without resolution,
+.B o
+for resolution override for all images.
+.TP
+.BI \-f
+Set PDF ``Fit Window'' user preference.
+.TP
+.BI \-e " YYYYMMDDHHMMSS"
+Set document information date, overrides image or current date/time default,
+.I YYYYMMDDHHMMSS.
+.TP
+.BI \-c " creator"
+Set document information creator, overrides image software default.
+.TP
+.BI \-a " author"
+Set document information author, overrides image artist default.
+.TP
+.BI \-t " title"
+Set document information title, overrides image document name default.
+.TP
+.BI \-s " subject"
+Set document information subject, overrides image image description default.
+.TP
+.BI \-k " keywords"
+Set document information keywords.
+.TP
+.B \-h
+List usage reminder to stderr and exit.
+.SH EXAMPLES
+.TP
+The following example would generate the file output.pdf from input.tiff.
+.RS
+.nf
+tiff2pdf \-o output.pdf input.tiff
+.fi
+.RE
+.PP
+The following example would generate PDF output from input.tiff and write it
+to standard output.
+.RS
+.nf
+tiff2pdf input.tiff
+.fi
+.RE
+.PP
+The following example would generate the file output.pdf from input.tiff,
+putting the image pages on a letter sized page, compressing the output
+with JPEG, with JPEG quality 75, setting the title to ``Document'', and setting
+the ``Fit Window'' option.
+.RS
+.nf
+tiff2pdf \-p letter \-j \-q 75 \-t "Document" \-f \-o output.pdf input.tiff
+.fi
+.RE
+.SH BUGS
+Please report bugs via the web interface at
+.IP
+\%http://bugzilla.remotesensing.org/enter_bug.cgi?product=libtiff
+.SH "SEE ALSO"
+.BR libtiff (3),
+.BR tiffcp (1),
+.BR tiff2ps (1)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiff2ps.1 b/tiff/man/tiff2ps.1
new file mode 100644
index 0000000..9b5508d
--- /dev/null
+++ b/tiff/man/tiff2ps.1
@@ -0,0 +1,268 @@
+.\" $Id: tiff2ps.1,v 1.9.2.2 2009-08-20 18:40:33 bfriesen Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.ds Ps PostScript
+.if n .po 0
+.TH TIFF2PS 1 "November 2, 2005" "libtiff"
+.SH NAME
+tiff2ps \- convert a
+.SM TIFF
+image to \*(Ps\*(Tm
+.SH SYNOPSIS
+.B tiff2ps
+[
+.I options
+]
+.I "input.tif ..."
+.SH DESCRIPTION
+.I tiff2ps
+reads
+.SM TIFF
+images and writes \*(Ps or Encapsulated \*(Ps (EPS)
+on the standard output.
+By default,
+.I tiff2ps
+writes Encapsulated \*(Ps for the first image in the specified
+.SM TIFF
+image file.
+.PP
+By default,
+.I tiff2ps
+will generate \*(Ps that fills a printed area specified
+by the
+.SM TIFF
+tags in the input file.
+If the file does not contain
+.I XResolution
+or
+.I YResolution
+tags, then the printed area is set according to the image dimensions.
+The
+.B \-w
+and
+.B \-h
+options (see below)
+can be used to set the dimensions of the printed area in inches;
+overriding any relevant
+.SM TIFF
+tags.
+.PP
+The \*(Ps generated for
+.SM RGB,
+palette, and
+.SM CMYK
+images uses the
+.I colorimage
+operator.
+The \*(Ps generated for
+greyscale and bilevel images
+uses the
+.I image
+operator.
+When the
+.I colorimage
+operator is used, \*(Ps code to emulate this operator
+on older \*(Ps printers is also generated.
+Note that this emulation code can be very slow.
+.PP
+Color images with associated alpha data are composited over
+a white background.
+.SH OPTIONS
+.TP
+.B \-1
+Generate \*(Ps Level 1 (the default).
+.TP
+.B \-2
+Generate \*(Ps Level 2.
+.TP
+.B \-3
+Generate \*(Ps Level 3. It basically allows one to use the /flateDecode
+filter for ZIP compressed TIFF images.
+.TP
+.B \-a
+Generate output for all IFDs (pages) in the input file.
+.TP
+.B \-b
+Specify the bottom margin for the output (in inches). This does not affect
+the height of the printed image.
+.TP
+.B \-c
+Center the image in the output. This option only shows an effect if both
+the
+.B \-w
+and the
+.B \-h
+option are given.
+.TP
+.B \-d
+Set the initial
+.SM TIFF
+directory to the specified directory number.
+(NB: Directories are numbered starting at zero.)
+This option is useful for selecting individual pages in a
+multi-page (e.g. facsimile) file.
+.TP
+.B \-e
+Force the generation of Encapsulated \*(Ps (implies
+.BR \-z ).
+.TP
+.B \-h
+Specify the vertical size of the printed area (in inches).
+.TP
+.B \-H
+Specify the maximum height of image (in inches). Images with larger sizes will
+be split in several pages. Option
+.B \-L
+may be used for specifying size of split images overlapping.
+.TP
+.B \-W
+Specify the maximum width of image (in inches). Images with larger sizes will
+be split in several pages. Options
+.B \-L
+and
+.B \-W
+are mutually exclusive.
+.B \-i
+Enable/disable pixel interpolation. This option requires a
+single numeric value: zero to disable pixel interpolation and
+non-zero to enable. The default is enabled.
+.TP
+.B \-L
+Specify the size of overlapping for split images (in inches). Used in
+conjunction with
+.B \-H
+option.
+.TP
+.B \-l
+Specify the left margin for the output (in inches). This does not affect
+the width of the printed image.
+.TP
+.B \-m
+Where possible render using the
+.I imagemask
+\*(Ps operator instead of the
+.I image
+operator. When this option is specified
+.I tiff2ps
+will use
+.I imagemask
+for rendering 1 bit deep images. If this option is not specified
+or if the image depth is greater than 1 then the
+.I image
+operator is used.
+.TP
+.B \-o
+Set the initial
+.SM TIFF
+directory to the
+.SM IFD
+at the specified file offset.
+This option is useful for selecting thumbnail images and the
+like which are hidden using the
+.I SubIFD
+tag.
+.TP
+.B \-p
+Force the generation of (non-Encapsulated) \*(Ps.
+.TP
+.B \-r
+Rotate image by 180 degrees.
+.TP
+.B \-s
+Generate output for a single IFD (page) in the input file.
+.TP
+.B \-w
+Specify the horizontal size of the printed area (in inches).
+.TP
+.B \-x
+Override resolution units specified in the TIFF as centimeters.
+.TP
+.B \-y
+Override resolution units specified in the TIFF as inches.
+.TP
+.B \-z
+When generating \*(Ps Level 2, data is scaled so that it does not
+image into the
+.I deadzone
+on a page (the outer margin that the printing device is unable to mark).
+This option suppresses this behavior.
+When \*(Ps Level 1 is generated, data is imaged to the entire printed
+page and this option has no affect.
+.SH EXAMPLES
+The following generates \*(Ps Level 2 for all pages of a facsimile:
+.RS
+.nf
+tiff2ps \-a2 fax.tif | lpr
+.fi
+.RE
+Note also that if you have version 2.6.1 or newer of Ghostscript then you
+can efficiently preview facsimile generated with the above command.
+.PP
+To generate Encapsulated \*(Ps for a the image at directory 2
+of an image use:
+.RS
+.nf
+tiff2ps \-d 1 foo.tif
+.fi
+.RE
+(Notice that directories are numbered starting at zero.)
+.PP
+If you have a long image, it may be split in several pages:
+.RS
+.nf
+tiff2ps \-h11 \-w8.5 \-H14 \-L.5 foo.tif > foo.ps
+.fi
+.RE
+The page size is set to 8.5x11 by
+.B \-w
+and
+.B \-h
+options. We will accept a small amount of vertical compression, so
+.B \-H
+set to 14. Any pages between 11 and 14 inches will be fit onto one page.
+Pages longer than 14 inches are cut off at 11 and continued on the next
+page. The
+.B \-L.5
+option says to repeat a half inch on the next page (to improve readability).
+.SH BUGS
+Because \*(Ps does not support the notion of a colormap,
+8-bit palette images produce 24-bit \*(Ps images.
+This conversion results in output that is six times
+bigger than the original image and which takes a long time
+to send to a printer over a serial line.
+Matters are even worse for 4-, 2-, and 1-bit palette images.
+.PP
+Does not handle tiled images when generating \*(Ps Level I output.
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffgt (1),
+.BR tiffmedian (1),
+.BR tiff2bw (1),
+.BR tiffsv (1),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiff2rgba.1 b/tiff/man/tiff2rgba.1
new file mode 100644
index 0000000..ec2b31e
--- /dev/null
+++ b/tiff/man/tiff2rgba.1
@@ -0,0 +1,97 @@
+.\" $Id: tiff2rgba.1,v 1.4 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFF2RGBA 1 "November 2, 2005" "libtiff"
+.SH NAME
+tiff2rgba \- convert a
+.SM TIFF
+image to RGBA color space
+.SH SYNOPSIS
+.B tiff2rgba
+[
+.I options
+]
+.I input.tif
+.I output.tif
+.SH DESCRIPTION
+.I Tiff2rgba
+converts a wide variety of TIFF images into an RGBA TIFF image. This
+includes the ability to translate different color spaces and photometric
+interpretation into RGBA, support for alpha blending, and translation
+of many different bit depths into a 32bit RGBA image.
+.P
+Internally this program is implemented using the
+.I TIFFReadRGBAImage()
+function, and it suffers any limitations of that image. This includes
+limited support for > 8 BitsPerSample images, and flaws with some
+esoteric combinations of BitsPerSample, photometric interpretation,
+block organization and planar configuration.
+.P
+The generated images are stripped images with four samples per pixel
+(red, green, blue and alpha) or if the
+.B \-n
+flag is used, three samples
+per pixel (red, green, and blue). The resulting images are always planar
+configuration contiguous. For this reason, this program is a useful utility
+for transform exotic TIFF files into a form ingestible by almost any TIFF
+supporting software.
+.SH OPTIONS
+.TP
+.B \-c
+Specify a compression scheme to use when writing image data:
+.B "\-c none"
+for no compression (the default),
+.B "\-c packbits"
+for the PackBits compression algorithm,
+.B "\-c zip"
+for the Deflate compression algorithm,
+.B "\-c jpeg"
+for the JPEG compression algorithm,
+and
+.B "\-c lzw"
+for Lempel-Ziv & Welch.
+.TP
+.B \-r
+Write data with a specified number of rows per strip;
+by default the number of rows/strip is selected so that each strip
+is approximately 8 kilobytes.
+.TP
+.B \-b
+Process the image one block (strip/tile) at a time instead of by reading
+the whole image into memory at once. This may be necessary for very large
+images on systems with limited RAM.
+.TP
+.B \-n
+Drop the alpha component from the output file, producing a pure RGB file.
+Currently this does not work if the
+.B \-b
+flag is also in effect.
+.SH "SEE ALSO"
+.BR tiff2bw (1),
+.BR TIFFReadRGBAImage (3t),
+.BR libtiff (3)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffcmp.1 b/tiff/man/tiffcmp.1
new file mode 100644
index 0000000..efd519f
--- /dev/null
+++ b/tiff/man/tiffcmp.1
@@ -0,0 +1,87 @@
+.\" $Id: tiffcmp.1,v 1.5 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFCMP 1 "November 2, 2005" "libtiff"
+.SH NAME
+tiffcmp \- compare two
+.SM TIFF
+files
+.SH SYNOPSIS
+.B tiffcmp
+[
+.I options
+]
+.I "file1.tif file2.tif"
+.SH DESCRIPTION
+.I Tiffcmp
+compares the tags and data in two files created according
+to the Tagged Image File Format, Revision 6.0.
+The schemes used for compressing data in each file
+are immaterial when data are compared\-data are compared on
+a scanline-by-scanline basis after decompression.
+Most directory tags are checked; notable exceptions are:
+.IR GrayResponseCurve ,
+.IR ColorResponseCurve ,
+and
+.IR ColorMap
+tags.
+Data will not be compared if any of the
+.IR BitsPerSample ,
+.IR SamplesPerPixel ,
+or
+.I ImageWidth
+values are not equal.
+By default,
+.I tiffcmp
+will terminate if it encounters any difference.
+.SH OPTIONS
+.TP
+.B \-l
+List each byte of image data that differs between the files.
+.TP
+.BI \-z " number"
+List specified number of image data bytes that differs between the files.
+.TP
+.B \-t
+Ignore any differences in directory tags.
+.SH BUGS
+Tags that are not recognized by the library are not
+compared; they may also generate spurious diagnostics.
+.PP
+The image data of tiled files is not compared, since the
+.I TIFFReadScanline()
+function is used. An error will be reported for tiled files.
+.PP
+The pixel and/or sample number reported in differences may be off
+in some exotic cases.
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.bR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffcp.1 b/tiff/man/tiffcp.1
new file mode 100644
index 0000000..56f4ebe
--- /dev/null
+++ b/tiff/man/tiffcp.1
@@ -0,0 +1,291 @@
+.\" $Id: tiffcp.1,v 1.9.2.1 2010-06-04 16:51:14 fwarmerdam Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFCP 1 "February 24, 2007" "libtiff"
+.SH NAME
+tiffcp \- copy (and possibly convert) a
+.SM TIFF
+file
+.SH SYNOPSIS
+.B tiffcp
+[
+.I options
+]
+.I "src1.tif ... srcN.tif dst.tif"
+.SH DESCRIPTION
+.I tiffcp
+combines one or more files created according
+to the Tag Image File Format, Revision 6.0
+into a single
+.SM TIFF
+file.
+Because the output file may be compressed using a different
+algorithm than the input files,
+.I tiffcp
+is most often used to convert between different compression
+schemes.
+.PP
+By default,
+.I tiffcp
+will copy all the understood tags in a
+.SM TIFF
+directory of an input
+file to the associated directory in the output file.
+.PP
+.I tiffcp
+can be used to reorganize the storage characteristics of data
+in a file, but it is explicitly intended to not alter or convert
+the image data content in any way.
+.SH OPTIONS
+.TP
+.BI \-b " image"
+subtract the following monochrome image from all others
+processed. This can be used to remove a noise bias
+from a set of images. This bias image is typically an
+image of noise the camera saw with its shutter closed.
+.TP
+.B \-B
+Force output to be written with Big-Endian byte order.
+This option only has an effect when the output file is created or
+overwritten and not when it is appended to.
+.TP
+.B \-C
+Suppress the use of ``strip chopping'' when reading images
+that have a single strip/tile of uncompressed data.
+.TP
+.B \-c
+Specify the compression to use for data written to the output file:
+.B none
+for no compression,
+.B packbits
+for PackBits compression,
+.B lzw
+for Lempel-Ziv & Welch compression,
+.B jpeg
+for baseline JPEG compression,
+.B zip
+for Deflate compression,
+.B g3
+for CCITT Group 3 (T.4) compression,
+and
+.B g4
+for CCITT Group 4 (T.6) compression.
+By default
+.I tiffcp
+will compress data according to the value of the
+.I Compression
+tag found in the source file.
+.IP
+The
+.SM CCITT
+Group 3 and Group 4 compression algorithms can only
+be used with bilevel data.
+.IP
+Group 3 compression can be specified together with several
+T.4-specific options:
+.B 1d
+for 1-dimensional encoding,
+.B 2d
+for 2-dimensional encoding,
+and
+.B fill
+to force each encoded scanline to be zero-filled so that the
+terminating EOL code lies on a byte boundary.
+Group 3-specific options are specified by appending a ``:''-separated
+list to the ``g3'' option; e.g.
+.B "\-c g3:2d:fill"
+to get 2D-encoded data with byte-aligned EOL codes.
+.IP
+.SM LZW
+compression can be specified together with a
+.I predictor
+value.
+A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value
+of 1 forces each scanline to be encoded without differencing.
+LZW-specific options are specified by appending a ``:''-separated
+list to the ``lzw'' option; e.g.
+.B "\-c lzw:2"
+for
+.SM LZW
+compression with horizontal differencing.
+.TP
+.B \-f
+Specify the bit fill order to use in writing output data.
+By default,
+.I tiffcp
+will create a new file with the same fill order as the original.
+Specifying
+.B "\-f lsb2msb"
+will force data to be written with the FillOrder tag set to
+.SM LSB2MSB,
+while
+.B "\-f msb2lsb"
+will force data to be written with the FillOrder tag set to
+.SM MSB2LSB.
+.TP
+.B \-i
+Ignore non-fatal read errors and continue processing of the input file.
+.TP
+.B \-l
+Specify the length of a tile (in pixels).
+.I tiffcp
+attempts to set the tile dimensions so
+that no more than 8 kilobytes of data appear in a tile.
+.TP
+.B \-L
+Force output to be written with Little-Endian byte order.
+This option only has an effect when the output file is created or
+overwritten and not when it is appended to.
+.TP
+.B \-M
+Suppress the use of memory-mapped files when reading images.
+.TP
+.B \-p
+Specify the planar configuration to use in writing image data
+that has one 8-bit sample per pixel.
+By default,
+.I tiffcp
+will create a new file with the same planar configuration as
+the original.
+Specifying
+.B "\-p contig"
+will force data to be written with multi-sample data packed
+together, while
+.B "\-p separate"
+will force samples to be written in separate planes.
+.TP
+.B \-r
+Specify the number of rows (scanlines) in each strip of data
+written to the output file.
+By default (or when value
+.B 0
+is specified),
+.I tiffcp
+attempts to set the rows/strip
+that no more than 8 kilobytes of data appear in a strip. If you specify
+special value
+.B \-1
+it will results in infinite number of the rows per strip. The entire image
+will be the one strip in that case.
+.TP
+.B \-s
+Force the output file to be written with data organized in strips
+(rather than tiles).
+.TP
+.B \-t
+Force the output file to be written with data organized in tiles (rather than
+strips). options can be used to force the resultant image to be written as
+strips or tiles of data, respectively.
+.TP
+.B \-w
+Specify the width of a tile (in pixels).
+.I tiffcp
+attempts to set the tile dimensions so that no more than 8 kilobytes of data
+appear in a tile.
+.I tiffcp
+attempts to set the tile dimensions so that no more than 8 kilobytes of data
+appear in a tile.
+.TP
+.B \-x
+Force the output file to be written with PAGENUMBER value in sequence.
+.TP
+.BI \-,= character
+substitute
+.I character
+for `,' in parsing image directory indices
+in files. This is necessary if filenames contain commas.
+Note that
+.B \-,=
+with whitespace immediately following will disable
+the special meaning of the `,' entirely. See examples.
+.SH EXAMPLES
+The following concatenates two files and writes the result using
+.SM LZW
+encoding:
+.RS
+.nf
+tiffcp \-c lzw a.tif b.tif result.tif
+.fi
+.RE
+.PP
+To convert a G3 1d-encoded
+.SM TIFF
+to a single strip of G4-encoded data the following might be used:
+.RS
+.nf
+tiffcp \-c g4 \-r 10000 g3.tif g4.tif
+.fi
+.RE
+(1000 is just a number that is larger than the number of rows in
+the source file.)
+
+To extract a selected set of images from a multi-image TIFF file, the file
+name may be immediately followed by a `,' separated list of image directory
+indices. The first image is always in directory 0. Thus, to copy the 1st and
+3rd images of image file ``album.tif'' to ``result.tif'':
+.RS
+.nf
+tiffcp album.tif,0,2 result.tif
+.fi
+.RE
+
+A trailing comma denotes remaining images in sequence. The following command
+will copy all image with except the first one:
+.RS
+.nf
+tiffcp album.tif,1, result.tif
+.fi
+.RE
+
+Given file ``CCD.tif'' whose first image is a noise bias
+followed by images which include that bias,
+subtract the noise from all those images following it
+(while decompressing) with the command:
+.RS
+.nf
+tiffcp \-c none \-b CCD.tif CCD.tif,1, result.tif
+.fi
+.RE
+
+If the file above were named ``CCD,X.tif'', the
+.B \-,=
+option would
+be required to correctly parse this filename with image numbers,
+as follows:
+.RS
+.nf
+tiffcp \-c none \-,=% \-b CCD,X.tif CCD,X%1%.tif result.tif
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR tiffinfo (1),
+.BR tiffcmp (1),
+.BR tiffmedian (1),
+.BR tiffsplit (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffcrop.1 b/tiff/man/tiffcrop.1
new file mode 100644
index 0000000..f5cffd5
--- /dev/null
+++ b/tiff/man/tiffcrop.1
@@ -0,0 +1,571 @@
+.\" $Id: tiffcrop.1,v 1.1.2.4 2010-06-11 22:24:23 bfriesen Exp $
+.\" tiffcrop -- a port of tiffcp.c extended to include extended processing of images
+.\"
+.\" Original code:
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.\" Additional code Copyright (c) 2006-2009 Richard Nolde
+.\" Lasted Updated 9/2009
+.\" .if n .po 0
+.TH "TIFFCROP" "1" "December, 2008" "libtiff" ""
+.SH "NAME"
+tiffcrop \- select, copy, crop, convert, extract, and/or process one or more
+.SM TIFF
+files.
+.SH "SYNOPSIS"
+.B tiffcrop
+[
+.I options
+]
+.I "src1.tif ... srcN.tif dst.tif"
+.SH "DESCRIPTION"
+.I Tiffcrop
+processes one or more files created according
+to the Tag Image File Format, Revision 6.0, specification
+into one or more
+.SM TIFF
+file(s).
+.I Tiffcrop
+is most often used to extract portions of an image for processing
+with bar code recognizer or OCR software when that software cannot
+restrict the region of interest to a specific portion of the image
+or to improve efficiency when the regions of interest must be rotated.
+It can also be used to subdivide all or part of a processed image into
+smaller sections and export individual images or sections of images
+as separate files or separate images within one or more files derived
+from the original input image or images.
+.PP
+The available functions can be grouped broadly into three classes:
+.IP
+Those that select individual images or sections of images from the input files.
+The options \-N for sequences or lists of individual images in the input files,
+\-Z for zones, \-z for regions, \-X and \-Y for fixed sized selections,
+\-m for margins, \-U for units, and \-E for edge reference provide a variety of
+ways to specify portions of the input image.
+.IP
+Those that allow the individual images or selections to be exported to one or
+more output files in different groupings and control the organization of the
+data in the output images. The options \-P for page size grouping, \-S for
+subdivision into columns and rows and \-e for export mode options that produce
+one or more files from each input image. The options \-r, \-s, \-t, \-w control
+strip and tile format and sizes while \-B \-L \-c \-f modify the endian addressing
+scheme, the compression options, and the bit fill sequence of images as they
+are written.
+.IP
+Those that perform some action on each image that is selected from the input file.
+The options include \-R for rotate, \-I for inversion of the photometric
+interpretation and/or data values, and \-F to flip (mirror) the image horizontally
+or vertically.
+.PP
+
+Functions are applied to the input image(s) in the following order:
+cropping, fixed area extraction, zone and region extraction,
+inversion, mirroring, rotation.
+.PP
+Functions are applied to the output image(s) in the following order:
+export mode options for grouping zones, regions, or images into
+one or more files,
+.I or
+row and column divisions with output margins,
+.I or
+page size divisions with page orientation options.
+.PP
+Finally, strip, tile, byte order, output resolution, and compression options are
+applied to all output images.
+.PP
+The output file(s) may be organized and compressed using a different
+algorithm from the input files.
+By default,
+.I tiffcrop
+will copy all the understood tags in a
+.SM TIFF
+directory of an input file to the associated directory in the output file.
+Options can be used to force the resultant image to be written as strips
+or tiles of data, respectively.
+.PP
+.I Tiffcrop
+can be used to reorganize the storage characteristics of data
+in a file, and to reorganize, extract, rotate, and otherwise
+process the image data as specified at the same time whereas
+tiffcp does not alter the image data within the file.
+.PP
+Using the options for selecting individual input images and the
+options for exporting images and/or segments defined as zones or
+regions of each input image,
+.I tiffcrop
+can perform the functions of tiffcp and tiffsplit in a single pass
+while applying multiple operations to individual selections or images.
+.PP
+.SH "OPTIONS"
+.TP
+.B \-h
+Display the syntax summary for tiffcrop.
+.TP
+.B \-v
+Report the current version and last modification date for tiffcrop.
+.TP
+.B \-N odd|even|#,#\-#,#|last
+Specify one or more series or range(s) of images within each file to process.
+The words
+.B odd
+or
+.B even
+may be used to specify all odd or even numbered images counting from one.
+Note that internally, TIFF images are numbered from zero rather than one
+but since this convention is not obvious to most users, tiffcrop used 1
+to specifiy the first image in a multipage file. The word
+.B last
+may be used in place of a number in the sequence to indicate the
+final image in the file without knowing how many images there are.
+Ranges of images may be specified with a dash and multiple sets
+can be indicated by joining them in a comma\-separated list. eg. use
+.B \-N 1,5\-7,last
+to process the 1st, 5th through 7th, and final image in the file.
+.TP
+.B \-E top|bottom|left|right
+Specify the top, bottom, left, or right edge as the reference from
+which to calcuate the width and length of crop regions or sequence
+of postions for zones. When used with the \-e option for exporting
+zones or regions, the reference edge determines how composite images
+are arranged. Using \-E left or right causes successive zones or
+regions to be merged horizontally whereas using \-E top or bottom
+causes successive zones or regions to be arranged vertically. This
+option has no effect on export layout when multiple zones or regions
+are not being exported to composite images. Edges may be abbreviated
+to the first letter.
+.TP
+.B \-e combined|divided|image|multiple|separate
+Specify the export mode for images and selections from input images.
+The final filename on the command line is considered to be the
+destination file or filename stem for automatically generated
+sequences of files. Modes may be abbreviated to the first letter.
+.IP
+combined All images and selections are written to a single file with
+multiple selections from one image combined into a single image (default)
+.IP
+divided All images and selections are written to a single file
+with each selection from one image written to a new image
+.IP
+image Each input image is written to a new file (numeric filename sequence)
+with multiple selections from the image combined into one image
+.IP
+multiple Each input image is written to a new file (numeric filename sequence)
+with each selection from the image written to a new image
+.IP
+separate Individual selections from each image are written to separate files
+.TP
+.B \-U in|cm|px
+Specify the type of units to apply to dimensions for margins and
+crop regions for input and output images. Inches or centimeters
+are converted to pixels using the resolution unit specified in the
+TIFF file (which defaults to inches if not specified in the IFD).
+.TP
+.B \-m #,#,#,#
+Specify margins to be removed from the input image. The order must
+be top, left, bottom, right with only commas separating the elements
+of the list. Margins are scaled according to the current units and
+removed before any other extractions are computed..
+.TP
+.B \-X #
+Set the horizontal (X\-axis) dimension of a region to extract relative to
+the specified origin reference. If the origin is the top or bottom
+edge, the X axis value will be assumed to start at the left edge.
+.TP
+.B \-Y #
+Set the vertical (Y\-axis) dimension of a region to extract relative to
+the specified origin reference. If the origin is the left or right
+edge, the Y axis value will be assumed to start at the top.
+.TP
+.B \-Z #:#,#:#
+Specify zones of the image designated as position X of Y equal sized portions
+measured from the reference edge, eg 1:3 would be first third of the
+image starting from the reference edge minus any margins specified
+for the confining edges. Multiple zones can be specified as a comma
+separated list but they must reference the same edge. To extract the
+top quarter and the bottom third of an image you would use
+.B \-Z 1:4,3:3.
+.TP
+.B \-z x1,y1,x2,y2: ... :xN,yN,xN+1,yN+1
+Specify a series of coordinates to define regions for processing and exporting.
+The coordinates represent the top left and lower right corners of each region
+in the current units, eg inch, cm, or pixels. Pixels are counted from one to
+width or height and inches or cm are calculated from image resolution data.
+
+Each colon delimited series of four values represents the horizontal and vertical
+offsets from the top and left edges of the image, regardless of the edge specified
+with the \-E option. The first and third values represent the horizontal offsets of
+the corner points from the left edge while the second and fourth values represent
+the vertical offsets from the top edge.
+.TP
+.B \-F horiz|vert
+Flip, ie mirror, the image or extracted region horizontally or vertically.
+.TP
+.B \-R 90|180|270
+Rotate the image or extracted region 90, 180, or 270 degrees clockwise.
+.TP
+.B \\-I [black|white|data|both]
+Invert color space, eg dark to light for bilevel and grayscale images.
+This can be used to modify negative images to positive or to correct
+images that have the PHOTOMETRIC_INTERPRETATIN tag set incorrectly.
+If the value is black or white, the PHOTOMETRIC_INTERPRETATION tag is set to
+MinIsBlack or MinIsWhite, without altering the image data. If the argument
+is data or both, the data values of the image are modified. Specifying both
+inverts the data and the PHOTOMETRIC_INTERPRETATION tag, whereas using data
+inverts the data but not the PHOTOMETRIC_INTERPRETATION tag.
+No support for modifying the color space of color images in this release.
+.TP
+.B \-H #
+Set the horizontal resolution of output images to #
+expressed in the current units.
+.TP
+.B \-V #
+Set the vertical resolution of the output images to #
+expressed in the current units.
+.TP
+.B \-J #
+Set the horizontal margin of an output page size to #
+expressed in the current units when sectioning image into columns x rows
+subimages using the \-S cols:rows option.
+.TP
+.B \-K #
+Set the vertical margin of an output page size to #
+expressed in the current units when sectioning image into columns x rows
+submiages using the \-S cols:rows option.
+.TP
+.B \-O portrait|landscape|auto
+Set the output orientation of the pages or sections.
+Auto will use the arrangement that requires the fewest pages.
+This option is only meaningful in conjunction with the -P
+option to format an image to fit on a specific paper size.
+.TP
+.B \-P page
+Format the output images to fit on page size paper. Use
+\-P list to show the supported page sizes and dimensions.
+You can define a custom page size by entering the width and length of the
+page in the current units with the following format #.#x#.#.
+.TP
+.B \-S cols:rows
+Divide each image into cols across and rows down equal sections.
+.TP
+.B \-B
+Force output to be written with Big\-Endian byte order.
+This option only has an effect when the output file is created or
+overwritten and not when it is appended to.
+.TP
+.B \-C
+Suppress the use of ``strip chopping'' when reading images
+that have a single strip/tile of uncompressed data.
+.TP
+.B \-c
+Specify the compression to use for data written to the output file:
+.B none
+for no compression,
+.B packbits
+for PackBits compression,
+.B lzw
+for Lempel\-Ziv & Welch compression,
+.B jpeg
+for baseline JPEG compression.
+.B zip
+for Deflate compression,
+.B g3
+for CCITT Group 3 (T.4) compression,
+and
+.B g4
+for CCITT Group 4 (T.6) compression.
+By default
+.I tiffcrop
+will compress data according to the value of the
+.I Compression
+tag found in the source file.
+.IP
+The
+.SM CCITT
+Group 3 and Group 4 compression algorithms can only
+be used with bilevel data.
+.IP
+Group 3 compression can be specified together with several
+T.4\-specific options:
+.B 1d
+for 1\-dimensional encoding,
+.B 2d
+for 2\-dimensional encoding,
+and
+.B fill
+to force each encoded scanline to be zero\-filled so that the
+terminating EOL code lies on a byte boundary.
+Group 3\-specific options are specified by appending a ``:''\-separated
+list to the ``g3'' option; e.g.
+.B "\-c g3:2d:fill"
+to get 2D\-encoded data with byte\-aligned EOL codes.
+.IP
+.SM LZW
+compression can be specified together with a
+.I predictor
+value.
+A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value
+of 1 forces each scanline to be encoded without differencing.
+LZW\-specific options are specified by appending a ``:''\-separated
+list to the ``lzw'' option; e.g.
+.B "\-c lzw:2"
+for
+.SM LZW
+compression with horizontal differencing.
+.TP
+.B \-f
+Specify the bit fill order to use in writing output data.
+By default,
+.I tiffcrop
+will create a new file with the same fill order as the original.
+Specifying
+.B "\-f lsb2msb"
+will force data to be written with the FillOrder tag set to
+.SM LSB2MSB,
+while
+.B "\-f msb2lsb"
+will force data to be written with the FillOrder tag set to
+.SM MSB2LSB.
+.TP
+.B \-i
+Ignore non\-fatal read errors and continue processing of the input file.
+.TP
+.B \-l
+Specify the length of a tile (in pixels).
+.I Tiffcrop
+attempts to set the tile dimensions so
+that no more than 8 kilobytes of data appear in a tile.
+.TP
+.B \-L
+Force output to be written with Little\-Endian byte order.
+This option only has an effect when the output file is created or
+overwritten and not when it is appended to.
+.TP
+.B \-M
+Suppress the use of memory\-mapped files when reading images.
+.TP
+.B \-p
+Specify the planar configuration to use in writing image data
+that has more than one sample per pixel.
+By default,
+.I tiffcrop
+will create a new file with the same planar configuration as
+the original.
+Specifying
+.B "\-p contig"
+will force data to be written with multi\-sample data packed
+together, while
+.B "\-p separate"
+will force samples to be written in separate planes.
+.TP
+.B \-r
+Specify the number of rows (scanlines) in each strip of data
+written to the output file.
+By default (or when value
+.B 0
+is specified),
+.I tiffcrop
+attempts to set the rows/strip that no more than 8 kilobytes of
+data appear in a strip. If you specify the special value
+.B \-1
+it will results in infinite number of the rows per strip. The entire image
+will be the one strip in that case.
+.TP
+.B \-s
+Force the output file to be written with data organized in strips
+(rather than tiles).
+.TP
+.B \-t
+Force the output file to be written with data organized in tiles
+(rather than strips).
+.TP
+.B \-w
+Specify the width of a tile (in pixels).
+.I tiffcrop
+attempts to set the tile dimensions so
+that no more than 8 kilobytes of data appear in a tile.
+.I tiffcrop
+attempts to set the tile dimensions so
+that no more than 8 kilobytes of data appear in a tile.
+.TP
+Debug and dump facility
+.B \-D opt1:value1,opt2:value2,opt3:value3:opt4:value4
+Display program progress and/or dump raw data to non\-TIFF files.
+Options include the following and must be joined as a comma
+separated list. The use of this option is generally limited to
+program debugging and development of future options. An equal sign
+may be substituted for the colon in option:value pairs.
+.IP
+debug:N Display limited program progress indicators where larger N
+increase the level of detail.
+.IP
+format:txt|raw Format any logged data as ASCII text or raw binary
+values. ASCII text dumps include strings of ones and zeroes representing
+the binary values in the image data plus identifying headers.
+.IP
+level:N Specify the level of detail presented in the dump files.
+This can vary from dumps of the entire input or output image data to dumps
+of data processed by specific functions. Current range of levels is 1 to 3.
+.IP
+input:full\-path\-to\-directory/input\-dumpname
+.IP
+output:full\-path\-to\-directory/output\-dumpname
+.IP
+When dump files are being written, each image will be written to a separate
+file with the name built by adding a numeric sequence value to the dumpname
+and an extension of .txt for ASCII dumps or .bin for binary dumps.
+
+The four debug/dump options are independent, though it makes little sense to
+specify a dump file without specifying a detail level.
+.IP
+Note: Tiffcrop may be compiled with -DDEVELMODE to enable additional very
+ low level debug reporting.
+.SH "EXAMPLES"
+The following concatenates two files and writes the result using
+.SM LZW
+encoding:
+.RS
+.nf
+tiffcrop \-c lzw a.tif b.tif result.tif
+.fi
+.RE
+.PP
+To convert a G3 1d\-encoded
+.SM TIFF
+to a single strip of G4\-encoded data the following might be used:
+.RS
+.nf
+tiffcrop \-c g4 \-r 10000 g3.tif g4.tif
+.fi
+.RE
+(1000 is just a number that is larger than the number of rows in
+the source file.)
+
+To extract a selected set of images from a multi\-image TIFF file
+use the \-N option described above. Thus, to copy the 1st and 3rd
+images of image file "album.tif" to "result.tif":
+.RS
+.nf
+tiffcrop \-N 1,3 album.tif result.tif
+.fi
+.RE
+.PP
+Invert a bilevel image scan of a microfilmed document and crop off margins of
+0.25 inches on the left and right, 0.5 inch on the top, and 0.75 inch on the
+bottom. From the remaining portion of the image, select the second and third
+quarters, ie, one half of the area left from the center to each margin.
+.RS
+tiffcrop \-U in \-m 0.5,0.25,0.75,0.25 \-E left \-Z 2:4,3:4 \-I both MicrofilmNegative.tif MicrofilmPostiveCenter.tif
+.fi
+.RE
+.PP
+Extract only the final image of a large Architectural E sized
+multipage TIFF file and rotate it 90 degrees clockwise while
+reformatting the output to fit on tabloid sized sheets with one
+quarter of an inch on each side:
+.RS
+tiffcrop \-N last \-R 90 \-O auto \-P tabloid \-U in \-J 0.25 \-K 0.25 \-H 300 \-V 300 Big\-PlatMap.tif BigPlatMap\-Tabloid.tif
+.fi
+.RE
+The output images will have a specified resolution of 300 dpi in both
+directions. The orientation of each page will be determined by whichever
+choice requires the fewest pages. To specify a specific orientation, use
+the portrait or landscape option. The paper size option does not resample
+the image. It breaks each original image into a series of smaller images
+that will fit on the target paper size at the specified resolution.
+.fi
+.RE
+.PP
+Extract two regions 2048 pixels wide by 2048 pixels high from each page of
+a multi\-page input file and write each region to a separate output file.
+.RS
+tiffcrop \-U px \-z 1,1,2048,2048:1,2049,2048,4097 \-e separate CheckScans.tiff Check
+.fi
+.RE
+The output file names will use the stem Check with a numeric suffix which is
+incremented for each region of each image, eg Check\-001.tiff, Check\-002.tiff ...
+Check\-NNN.tiff. To produce a unique file for each page of the input image
+with one new image for each region of the input image on that page, change
+the export option to \-e multiple.
+
+.SH "NOTES"
+.PP
+In general, bilevel, grayscale, palette and RGB(A) data with bit depths
+from 1 to 32 bits should work in both interleaved and separate plane
+formats. Unlike tiffcp, tiffcrop can read and write tiled images with
+bits per sample that are not a multiple of 8 in both interleaved and
+separate planar format. Floating point data types are supported at
+bit depts of 16, 24, 32 and 64 bits per sample.
+.PP
+Not all images can be converted from one compression scheme to another.
+Data with some photometric interpretations and/or bit depths are tied to
+specific compression schemes and vice-versa, e.g. Group 3/4 compression
+is only usable for bilevel data. JPEG compression is only useable on 8
+bit per sample data (or 12 bit if
+.I LibTIFF
+was compiled with 12 bit JPEG support). Support for OJPEG compressed
+images is problematic at best. Since OJPEG compression is no longer
+supported for writing images with LibTIFF, these images will be updated
+to the newer JPEG compression when they are copied or processed. This
+may cause the image to appear color shifted or distorted after conversion.
+In some cases, it is possible to remove the original compression from
+image data using the option -cnone.
+.PP
+Tiffcrop does not currently provide options to up or downsample data to
+different bit depths or convert data from one photometric interpretation
+to another, e.g. 16 bits per sample to 8 bits per sample or RGB to grayscale.
+.PP
+Tiffcrop is very loosely derived from code in
+.I tiffcp
+with extensive modifications and additions to support the selection of input
+images and regions and the exporting of them to one or more output files in
+various groupings. The image manipulation routines are entirely new and
+additional ones may be added in the future. It will handle tiled images with
+bit depths that are not a multiple of eight that tiffcp may refuse to read.
+.PP
+.I Tiffcrop
+was designed to handle large files containing many moderate sized images
+with memory usage that is independent of the number of images in the file.
+In order to support compression modes that are not based on individual
+scanlines, e.g. JPEG, it now reads images by strip or tile rather than by
+indvidual scanlines. In addition to the memory required by the input and
+output buffers associated with
+.I LibTIFF
+one or more buffers at least as large as the largest image to be read are
+required. The design favors large volume document processing uses over
+scientific or graphical manipulation of large datasets as might be found
+in research or remote sensing scenarios.
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR tiffinfo (1),
+.BR tiffcmp (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR tiffsplit (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
+
diff --git a/tiff/man/tiffdither.1 b/tiff/man/tiffdither.1
new file mode 100644
index 0000000..0e1294c
--- /dev/null
+++ b/tiff/man/tiffdither.1
@@ -0,0 +1,132 @@
+.\" $Id: tiffdither.1,v 1.4 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1990-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFDITHER 1 "September 20, 2005" "libtiff"
+.SH NAME
+tiffdither \- convert a greyscale image to bilevel using dithering
+.SH SYNOPSIS
+.B tiffdither
+[
+.I options
+]
+.I input.tif
+.I output.tif
+.SH DESCRIPTION
+.I tiffdither
+converts a single channel 8-bit greyscale image to a bilevel image
+using Floyd-Steinberg error propagation with thresholding.
+.SH OPTIONS
+.TP
+.B \-c
+Specify the compression to use for data written to the output file:
+.B none
+for no compression,
+.B packbits
+for PackBits compression,
+.B lzw
+for Lempel-Ziv & Welch compression,
+.B zip
+for Deflate compression,
+.B g3
+for CCITT Group 3 (T.4) compression,
+and
+.B g4
+for CCITT Group 4 (T.6) compression.
+By default
+.I tiffdither
+will compress data according to the value of the
+.I Compression
+tag found in the source file.
+.IP
+The
+.SM CCITT
+Group 3 and Group 4 compression algorithms can only
+be used with bilevel data.
+.IP
+Group 3 compression can be specified together with several
+T.4-specific options:
+.B 1d
+for 1-dimensional encoding,
+.B 2d
+for 2-dimensional encoding,
+and
+.B fill
+to force each encoded scanline to be zero-filled so that the
+terminating EOL code lies on a byte boundary.
+Group 3-specific options are specified by appending a ``:''-separated
+list to the ``g3'' option; e.g.
+.B "\-c g3:2d:fill"
+to get 2D-encoded data with byte-aligned EOL codes.
+.IP
+.SM LZW
+compression can be specified together with a
+.I predictor
+value.
+A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value
+of 1 forces each scanline to be encoded without differencing.
+LZW-specific options are specified by appending a ``:''-separated
+list to the ``lzw'' option; e.g.
+.B "\-c lzw:2"
+for
+.SM LZW
+compression with horizontal differencing.
+.TP
+.B \-f
+Specify the bit fill order to use in writing output data.
+By default,
+.I tiffdither
+will create a new file with the same fill order as the original.
+Specifying
+.B "\-f lsb2msb"
+will force data to be written with the
+.I Fill\%Order
+tag set to
+.SM LSB2MSB ,
+while
+.B "\-f msb2lsb"
+will force data to be written with the
+.I Fill\%Order
+tag set to
+.SM MSB2LSB .
+.TP
+.B \-t
+Set the threshold value for dithering.
+By default the threshold value is 128.
+.SH NOTES
+The dither algorithm is taken from the
+.BR tiffmedian (1)
+program (written by Paul Heckbert).
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR fax2tiff (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiff2bw (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffdump.1 b/tiff/man/tiffdump.1
new file mode 100644
index 0000000..fa2c2fe
--- /dev/null
+++ b/tiff/man/tiffdump.1
@@ -0,0 +1,81 @@
+.\" $Id: tiffdump.1,v 1.5 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFDUMP 1 "October 23, 2005" "libtiff"
+.SH NAME
+tiffdump \- print verbatim information about
+.SM TIFF
+files
+.SH SYNOPSIS
+.B tiffdump
+[
+.I options
+]
+.I "name \&..."
+.SH DESCRIPTION
+.I tiffdump
+displays directory information from files created according
+to the Tag Image File Format, Revision 6.0.
+The header of each
+.SM TIFF
+file (magic number, version, and first directory offset)
+is displayed, followed by the tag contents of each directory in the file.
+For each tag, the name, data type, count, and value(s) is displayed.
+When the symbolic name for a tag or data type is known, the symbolic
+name is displayed followed by it's numeric (decimal) value.
+Tag values are displayed enclosed in ``<>'' characters immediately
+preceded by the value of the count field.
+For example, an
+.I ImageWidth
+tag might be displayed as ``ImageWidth (256) SHORT (3) 1<800>''.
+.PP
+.I tiffdump
+is particularly useful for investigating the contents of
+.SM TIFF
+files that
+.I libtiff
+does not understand.
+.SH OPTIONS
+.TP
+.B \-h
+Force numeric data to be printed in hexadecimal rather than the
+default decimal.
+.TP
+.BI \-m " items"
+Change the number of indirect data items that are printed. By default, this
+will be 24.
+.TP
+.BI \-o " offset"
+Dump the contents of the
+.SM IFD
+at the a particular file offset.
+The file offset may be specified using the usual C-style syntax;
+i.e. a leading ``0x'' for hexadecimal and a leading ``0'' for octal.
+.SH "SEE ALSO"
+.BR tiffinfo (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffgt.1 b/tiff/man/tiffgt.1
new file mode 100644
index 0000000..1d5bb41
--- /dev/null
+++ b/tiff/man/tiffgt.1
@@ -0,0 +1,245 @@
+.\" $Id: tiffgt.1,v 1.4 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFGT 1 "September 20, 2005" "libtiff"
+.SH NAME
+tiffgt \- display an image stored in a
+.SM TIFF
+file (Silicon Graphics version)
+.SH SYNOPSIS
+.B tiffgt
+[
+.I options
+]
+.I "input.tif ..."
+.SH DESCRIPTION
+.I tiffgt
+displays one or more images stored using the
+Tag Image File Format, Revision 6.0.
+Each image is placed in a fixed size window that the
+user must position on the display (unless configured
+otherwise through X defaults).
+If the display has fewer than 24 bitplanes, or if the
+image does not warrant full color, then
+.SM RGB
+color values are mapped to the closest values that exist in
+the colormap (this is done using the
+.I rgbi
+routine found in the graphics utility library
+.BR \-lgutil .)
+.PP
+.I tiffgt
+correctly handles files with any of the following characteristics:
+.sp .5
+.in +0.5i
+.ta \w'\fIPhotometricInterpretation\fP 'u
+.nf
+\fIBitsPerSample\fP 1, 2, 4, 8, 16
+\fISamplesPerPixel\fP 1, 3, 4 (the 4th sample is ignored)
+\fIPhotometricInterpretation\fP 0 (min-is-white), 1 (min-is-black), 2 (RGB), 3 (palette), 6 (YCbCr)
+\fIPlanarConfiguration\fP 1 (contiguous), 2 (separate)
+\fIOrientation\fP 1 (top-left), 4 (bottom-left)
+.fi
+.in -0.5i
+.sp .5
+Data may be organized as strips or tiles and may be
+compressed with any of the compression algorithms supported
+by the
+.IR libtiff (3)
+library.
+.PP
+For palette images (\c
+.IR PhotometricInterpretation =3),
+.I tiffgt
+inspects the colormap values and assumes either 16-bit
+or 8-bit values according to the maximum value.
+That is, if no colormap entry greater than 255 is found,
+.I tiffgt
+assumes the colormap has only 8-bit values; otherwise
+it assumes 16-bit values.
+This inspection is done to handle old images written by
+previous (incorrect) versions of
+.IR libtiff .
+.PP
+.I tiffgt
+can be used to display multiple images one-at-a-time.
+The left mouse button switches the display to the first image in the
+.I next
+file in the list of files specified on the command line.
+The right mouse button switches to the first image in the
+.I previous
+file in the list.
+The middle mouse button causes the first image in the first file
+specified on the command line to be displayed.
+In addition the following keyboard commands are recognized:
+.TP
+.B b
+Use a
+.I PhotometricInterpretation
+of MinIsBlack in displaying the current image.
+.TP
+.B l
+Use a
+.I FillOrder
+of lsb-to-msb in decoding the current image.
+.TP
+.B m
+Use a
+.I FillOrder
+of msb-to-lsb in decoding the current image.
+.TP
+.B c
+Use a colormap visual to display the current image.
+.TP
+.B r
+Use a true color (24-bit RGB) visual to display the current image.
+.TP
+.B w
+Use a
+.I PhotometricInterpretation
+of MinIsWhite in displaying the current image.
+.TP
+.B W
+Toggle (enable/disable) display of warning messages from the
+.SM TIFF
+library when decoding images.
+.TP
+.B E
+Toggle (enable/disable) display of error messages from the
+.SM TIFF
+library when decoding images.
+.TP
+.B z
+Reset all parameters to their default settings (\c
+.IR FillOrder ,
+.IR PhotometricInterpretation ,
+handling of warnings and errors).
+.TP
+.B PageUp
+Display the previous image in the current file or the last
+image in the previous file.
+.TP
+.B PageDown
+Display the next image in the current file or the first image
+in the next file.
+.TP
+.B Home
+Display the first image in the current file.
+.TP
+.B End
+Display the last image in the current file (unimplemented).
+.SH OPTIONS
+.TP
+.B \-c
+Force image display in a colormap window.
+.TP
+.B \-d
+Specify an image to display by directory number.
+By default the first image in the file is displayed.
+Directories are numbered starting at zero.
+.TP
+.B \-e
+Enable reporting of error messages from the
+.SM TIFF
+library.
+By default
+.I tiffgt
+silently ignores images that cannot be read.
+.TP
+.B \-f
+Force
+.I tiffgt
+to run as a foreground process.
+By default
+.I tiffgt
+will place itself in the background once it has opened the
+requested image file.
+.TP
+.B \-l
+Force the presumed bit ordering to be
+.SM LSB
+to
+.SM MSB.
+.TP
+.B \-m
+Force the presumed bit ordering to be
+.SM MSB
+to
+.SM LSB.
+.TP
+.B \-o
+Specify an image to display by directory offset.
+By default the first image in the file is displayed.
+Directories offsets may be specified using C-style syntax;
+i.e. a leading ``0x'' for hexadecimal and a leading ``0'' for octal.
+.TP
+.B \-p
+Override the value of the
+.I PhotometricInterpretation
+tag; the parameter may be one of:
+.BR miniswhite ,
+.BR minisblack ,
+.BR rgb ,
+.BR palette ,
+.BR mask ,
+.BR separated ,
+.BR ycbcr ,
+and
+.BR cielab .
+.TP
+.B \-r
+Force image display in a full color window.
+.TP
+.B \-s
+Stop on the first read error.
+By default all errors in the input data are ignored and
+.I tiffgt
+does it's best to display as much of an image as possible.
+.TP
+.B \-w
+Enable reporting of warning messages from the
+.SM TIFF
+library.
+By default
+.I tiffgt
+ignores warning messages generated when reading an image.
+.TP
+.B \-v
+Place information in the title bar describing
+what type of window (full color or colormap) is being
+used, the name of the input file, and the directory
+index of the image (if non-zero).
+By default, the window type is not shown in the title bar.
+.SH BUGS
+Images wider and taller than the display are silently truncated to avoid
+crashing old versions of the window manager.
+.SH "SEE ALSO"
+.BR tiffdump (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffinfo.1 b/tiff/man/tiffinfo.1
new file mode 100644
index 0000000..764e473
--- /dev/null
+++ b/tiff/man/tiffinfo.1
@@ -0,0 +1,88 @@
+.\" $Id: tiffinfo.1,v 1.2 2005/11/02 11:07:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFINFO 1 "November 2, 2005" "libtiff"
+.SH NAME
+tiffinfo \- print information about
+.SM TIFF
+files
+.SH SYNOPSIS
+.B tiffinfo
+[
+.I options
+]
+.I "input.tif \&..."
+.SH DESCRIPTION
+.I Tiffinfo
+displays information about files created according
+to the Tag Image File Format, Revision 6.0.
+By default, the contents of each
+.SM TIFF
+directory in each file
+is displayed, with the value of each tag shown symbolically
+(where sensible).
+.SH OPTIONS
+.TP
+.B \-c
+Display the colormap and color/gray response curves, if present.
+.TP
+.B \-D
+In addition to displaying the directory tags,
+read and decompress all the data in each image (but not display it).
+.TP
+.B \-d
+In addition to displaying the directory tags,
+print each byte of decompressed data in hexadecimal.
+.TP
+.B \-j
+Display any \s-2JPEG\s0-related tags that are present.
+.TP
+.B \-o
+Set the initial
+.SM TIFF
+directory according to the specified file offset.
+The file offset may be specified using the usual C-style syntax;
+i.e. a leading ``0x'' for hexadecimal and a leading ``0'' for octal.
+.TP
+.B \-s
+Display the offsets and byte counts for each data strip in a directory.
+.TP
+.B \-z
+Enable strip chopping when reading image data.
+.TP
+.B \-#
+Set the initial
+.SM TIFF
+directory to
+.IR # .
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR tiffcp (1),
+.BR tiffcmp (1),
+.BR tiffmedian (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffmedian.1 b/tiff/man/tiffmedian.1
new file mode 100644
index 0000000..ffa6d04
--- /dev/null
+++ b/tiff/man/tiffmedian.1
@@ -0,0 +1,112 @@
+.\" $Id: tiffmedian.1,v 1.3 2005/11/02 11:07:19 dron Exp $
+.\"
+.\" Copyright (c) 1990-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFMEDIAN 1 "November 2, 2005" "libtiff"
+.SH NAME
+tiffmedian \- apply the median cut algorithm to data in a
+.SM TIFF
+file
+.SH SYNOPSIS
+.B tiffmedian
+[
+.I options
+]
+.I input.tif
+.I output.tif
+.SH DESCRIPTION
+.I tiffmedian
+applies the median cut algorithm to an
+.SM RGB
+image in
+.I input.tif
+to generate a palette image that is written to
+.IR output.tif .
+The generated colormap has, by default, 256 entries.
+The image data is quantized by mapping each
+pixel to the closest color values in the colormap.
+.SH OPTIONS
+.TP
+.B \-c
+Specify the compression to use for data written to the output file:
+.B none
+for no compression,
+.B packbits
+for PackBits compression,
+.B lzw
+for Lempel-Ziv & Welch compression,
+and
+.B zip
+for Deflate compression.
+By default
+.I tiffmedian
+will compress data according to the value of the
+.I Compression
+tag found in the source file.
+.IP
+.SM LZW
+compression can be specified together with a
+.I predictor
+value.
+A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value
+of 1 forces each scanline to be encoded without differencing.
+LZW-specific options are specified by appending a ``:''-separated
+list to the ``lzw'' option; e.g.
+.B "\-c lzw:2"
+for
+.SM LZW
+compression with horizontal differencing.
+.TP
+.B \-C
+Specify the number of entries to use in the generated colormap.
+By default all 256 entries/colors are used.
+.TP
+.B \-f
+Apply Floyd-Steinberg dithering before selecting a colormap entry.
+.TP
+.B \-r
+Specify the number of rows (scanlines) in each strip of data
+written to the output file.
+By default,
+.I tiffmedian
+attempts to set the rows/strip
+that no more than 8 kilobytes of data appear in a strip.
+.SH NOTES
+This program is derived from Paul Heckbert's
+.I median
+program.
+.SH "SEE ALSO"
+.BR pal2rgb (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffcmp (1),
+.BR libtiff (3TIFF)
+.PP
+.BR "Color Image Quantization for Frame Buffer Display",
+Paul Heckbert, SIGGRAPH proceedings, 1982, pp. 297-307.
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffset.1 b/tiff/man/tiffset.1
new file mode 100644
index 0000000..6906238
--- /dev/null
+++ b/tiff/man/tiffset.1
@@ -0,0 +1,82 @@
+.\" $Id: tiffset.1,v 1.3 2006/04/20 12:17:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFSET 1 "November 21, 2004" "libtiff"
+.SH NAME
+tiffset \- set a field in a
+.SM TIFF
+header
+.SH SYNOPSIS
+.B tiffset
+[
+.I options
+]
+.I filename.tif
+.SH DESCRIPTION
+.I Tiffset
+sets the value of a
+.SM TIFF
+header to a specified value.
+.SH OPTIONS
+.TP
+.BI \-s " tagnumber" "\fR [\fP" " count" "\fR ]\fP" " value ..."
+Set the value of the named tag to the value or values specified.
+.TP
+.BI \-sf " tagnumber filename"
+Set the value of the tag to the contents of filename. This option is
+supported for ASCII tags only.
+.SH EXAMPLES
+The following example sets the image description tag (270) of a.tif to
+the contents of the file descrip:
+.RS
+.nf
+tiffset \-sf 270 descrip a.tif
+.fi
+.RE
+.PP
+The following example sets the artist tag (315) of a.tif to the string
+``Anonymous'':
+.RS
+.nf
+tiffset \-s 305 Anonymous a.tif
+.fi
+.RE
+.PP
+This example sets the resolution of the file a.tif to 300 dpi:
+.RS
+.nf
+tiffset \-s 296 2 a.tif
+tiffset \-s 282 300.0 a.tif
+tiffset \-s 283 300.0 a.tif
+.fi
+.RE
+.SH "SEE ALSO"
+.BR tiffdump (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffsplit.1 b/tiff/man/tiffsplit.1
new file mode 100644
index 0000000..6495d46
--- /dev/null
+++ b/tiff/man/tiffsplit.1
@@ -0,0 +1,69 @@
+.\" $Id: tiffsplit.1,v 1.5 2005/11/02 11:07:19 dron Exp $
+.\"
+.\" Copyright (c) 1992-1997 Sam Leffler
+.\" Copyright (c) 1992-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFSPLIT 1 "September 20, 2005" "libtiff"
+.SH NAME
+tiffsplit \- split a multi-image
+.SM TIFF
+into single-image
+.SM TIFF
+files
+.SH SYNOPSIS
+.B tiffsplit
+.I src.tif
+[
+.I prefix
+]
+.SH DESCRIPTION
+.I tiffsplit
+takes a multi-directory (page)
+.SM TIFF
+file and creates one or more single-directory (page)
+.SM TIFF
+files from it.
+The output files are given names created by concatenating
+a prefix, a lexically ordered
+suffix in the range [\fIaaa\fP-\fIzzz\fP], the suffix
+.I .tif
+(e.g.
+.IR xaaa.tif ,
+.IR xaab.tif ,
+\...
+.IR xzzz.tif ).
+If a prefix is not specified on the command line,
+the default prefix of
+.I x
+is used.
+.SH OPTIONS
+None.
+.SH BUGS
+Only a select set of ``known tags'' is copied when splitting.
+.SH "SEE ALSO"
+.BR tiffcp (1),
+.BR tiffinfo (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/man/tiffsv.1 b/tiff/man/tiffsv.1
new file mode 100644
index 0000000..6e0214e
--- /dev/null
+++ b/tiff/man/tiffsv.1
@@ -0,0 +1,142 @@
+.\" $Id: tiffsv.1,v 1.3 2005/11/02 11:07:19 dron Exp $
+.\"
+.\" Copyright (c) 1988-1997 Sam Leffler
+.\" Copyright (c) 1991-1997 Silicon Graphics, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and
+.\" its documentation for any purpose is hereby granted without fee, provided
+.\" that (i) the above copyright notices and this permission notice appear in
+.\" all copies of the software and related documentation, and (ii) the names of
+.\" Sam Leffler and Silicon Graphics may not be used in any advertising or
+.\" publicity relating to the software without the specific, prior written
+.\" permission of Sam Leffler and Silicon Graphics.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+.\" EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+.\" WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\" IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+.\" ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+.\" OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+.\" WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+.\" LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+.\" OF THIS SOFTWARE.
+.\"
+.if n .po 0
+.TH TIFFSV 1 "September 20, 2005" "libtiff"
+.SH NAME
+tiffsv \- save an image from the framebuffer in a
+.SM TIFF
+file (Silicon Graphics version)
+.SH SYNOPSIS
+.B tiffsv
+[
+.I options
+]
+.I output.tif
+[
+.I "x1 x2 y1 y2"
+]
+.SH DESCRIPTION
+.I tiffsv
+saves all or part of the framebuffer in a file using the
+Tag Image File Format, Revision 6.0.
+By default, the image is saved with data samples packed (\c
+.IR PlanarConfiguration =1),
+compressed with the Lempel-Ziv & Welch algorithm (\c
+.IR Compression =5),
+and with each strip no more than 8 kilobytes.
+These characteristics can be overridden, or explicitly specified
+with the options described below.
+.SH OPTIONS
+.TP
+.B \-b
+Save the image as a greyscale image
+as if it were processed by
+.IR tiff2bw (1).
+This option is included for compatibility with the standard
+.IR scrsave (6D)
+program.
+.TP
+.B \-c
+Specify the compression to use for data written to the output file:
+.B none
+for no compression,
+.B packbits
+for PackBits compression,
+.B jpeg
+for baseline JPEG compression,
+.B zip
+for Deflate compression,
+and
+.B lzw
+for Lempel-Ziv & Welch compression (default).
+.IP
+.SM LZW
+compression can be specified together with a
+.I predictor
+value.
+A predictor value of 2 causes
+each scanline of the output image to undergo horizontal
+differencing before it is encoded; a value
+of 1 forces each scanline to be encoded without differencing.
+LZW-specific options are specified by appending a ``:''-separated
+list to the ``lzw'' option; e.g.
+.B "\-c lzw:2"
+for
+.SM LZW
+compression with horizontal differencing.
+.TP
+.B \-p
+Specify the planar configuration to use in writing image data.
+By default,
+.I tiffsv
+will create a new file with the data samples packed contiguously.
+Specifying
+.B "\-p contig"
+will force data to be written with multi-sample data packed
+together, while
+.B "\-p separate"
+will force samples to be written in separate planes.
+.TP
+.B \-r
+Specify the number of rows (scanlines) in each strip of data
+written to the output file.
+By default,
+.I tiffsv
+attempts to set the rows/strip
+that no more than 8 kilobytes of data appear in a strip.
+.SH NOTE
+Except for the use of
+.SM TIFF,
+this program is equivalent to the standard
+.I scrsave
+program.
+This means, for example, that you can use it in conjunction with
+the standard
+.IR icut
+program simply by creating a link called
+.IR scrsave ,
+or by creating a shell script called
+.I scrsave
+that invokes
+.I tiffgt
+with the appropriate options.
+.SH BUGS
+If data are saved compressed and in separate planes, then the
+rows in each strip is silently set to one to avoid limitations
+in the
+.BR libtiff (3TIFF)
+library.
+.SH "SEE ALSO"
+.BR scrsave (6D)
+.BR pal2rgb (1),
+.BR tiffdump (1),
+.BR tiffgt (1),
+.BR tiffinfo (1),
+.BR tiffcp (1),
+.BR tiffmedian (1),
+.BR libtiff (3TIFF)
+.PP
+Libtiff library home page:
+.BR http://www.remotesensing.org/libtiff/
diff --git a/tiff/nmake.opt b/tiff/nmake.opt
new file mode 100644
index 0000000..400ba58
--- /dev/null
+++ b/tiff/nmake.opt
@@ -0,0 +1,218 @@
+# $Id: nmake.opt,v 1.18 2006/06/07 16:33:45 dron Exp $
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Compile time parameters for MS Visual C++ compiler.
+# You may edit this file to specify building options.
+
+#
+###### Edit the following lines to choose a feature set you need. #######
+#
+
+#
+# Select WINMODE_CONSOLE to build a library which reports errors to stderr, or
+# WINMODE_WINDOWED to build such that errors are reported via MessageBox().
+#
+WINMODE_CONSOLE = 1
+#WINMODE_WINDOWED = 1
+
+#
+# Comment out the following lines to disable internal codecs.
+#
+# Support for CCITT Group 3 & 4 algorithms
+CCITT_SUPPORT = 1
+# Support for Macintosh PackBits algorithm
+PACKBITS_SUPPORT = 1
+# Support for LZW algorithm
+LZW_SUPPORT = 1
+# Support for ThunderScan 4-bit RLE algorithm
+THUNDER_SUPPORT = 1
+# Support for NeXT 2-bit RLE algorithm
+NEXT_SUPPORT = 1
+# Support for LogLuv high dynamic range encoding
+LOGLUV_SUPPORT = 1
+
+#
+# Uncomment and edit following lines to enable JPEG support.
+#
+#JPEG_SUPPORT = 1
+#JPEGDIR = d:/projects/jpeg-6b
+#JPEG_INCLUDE = -I$(JPEGDIR)
+#JPEG_LIB = $(JPEGDIR)/Release/jpeg.lib
+
+#
+# Uncomment and edit following lines to enable ZIP support
+# (required for Deflate compression and Pixar log-format)
+#
+#ZIP_SUPPORT = 1
+#ZLIBDIR = d:/projects/zlib-1.2.1
+#ZLIB_INCLUDE = -I$(ZLIBDIR)
+#ZLIB_LIB = $(ZLIBDIR)/zlib.lib
+
+#
+# Uncomment and edit following lines to enable ISO JBIG support
+#
+#JBIG_SUPPORT = 1
+#JBIGDIR = d:/projects/jbigkit
+#JBIG_INCLUDE = -I$(JBIGDIR)/libjbig
+#JBIG_LIB = $(JBIGDIR)/libjbig/jbig.lib
+
+#
+# Uncomment following line to enable Pixar log-format algorithm
+# (Zlib required).
+#
+#PIXARLOG_SUPPORT = 1
+
+#
+# Comment out the following lines to disable strip chopping
+# (whether or not to convert single-strip uncompressed images to mutiple
+# strips of specified size to reduce memory usage). Default strip size
+# is 8192 bytes, it can be configured via the STRIP_SIZE_DEFAULT parameter
+#
+STRIPCHOP_SUPPORT = 1
+STRIP_SIZE_DEFAULT = 8192
+
+#
+# Comment out the following lines to disable treating the fourth sample with
+# no EXTRASAMPLE_ value as being ASSOCALPHA. Many packages produce RGBA
+# files but don't mark the alpha properly.
+#
+EXTRASAMPLE_AS_ALPHA_SUPPORT = 1
+
+#
+# Comment out the following lines to disable picking up YCbCr subsampling
+# info from the JPEG data stream to support files lacking the tag.
+# See Bug 168 in Bugzilla, and JPEGFixupTestSubsampling() for details.
+#
+CHECK_JPEG_YCBCR_SUBSAMPLING = 1
+
+#
+####################### Compiler related options. #######################
+#
+
+#
+# Pick debug or optimized build flags. We default to an optimized build
+# with no debugging information.
+# NOTE: /EHsc option required if you want to build the C++ stream API
+#
+OPTFLAGS = /Ox /MD /EHsc /W3 /D_CRT_SECURE_NO_DEPRECATE
+#OPTFLAGS = /Zi
+
+#
+# Uncomment following line to enable using Windows Common RunTime Library
+# instead of Windows specific system calls. See notes on top of tif_unix.c
+# module for details.
+#
+USE_WIN_CRT_LIB = 1
+
+# Compiler specific options. You may probably want to adjust compilation
+# parameters in CFLAGS variable. Refer to your compiler documentation
+# for the option reference.
+#
+MAKE = nmake /nologo
+CC = cl /nologo
+CXX = cl /nologo
+AR = lib /nologo
+LD = link /nologo
+
+CFLAGS = $(OPTFLAGS) $(INCL) $(EXTRAFLAGS)
+CXXFLAGS = $(OPTFLAGS) $(INCL) $(EXTRAFLAGS)
+EXTRAFLAGS =
+LIBS =
+
+# Name of the output shared library
+DLLNAME = libtiff.dll
+
+#
+########### There is nothing to edit below this line normally. ###########
+#
+
+# Set the native cpu bit order
+EXTRAFLAGS = -DFILLODER_LSB2MSB $(EXTRAFLAGS)
+
+!IFDEF WINMODE_WINDOWED
+EXTRAFLAGS = -DTIF_PLATFORM_WINDOWED $(EXTRAFLAGS)
+LIBS = user32.lib $(LIBS)
+!ELSE
+EXTRAFLAGS = -DTIF_PLATFORM_CONSOLE $(EXTRAFLAGS)
+!ENDIF
+
+# Codec stuff
+!IFDEF CCITT_SUPPORT
+EXTRAFLAGS = -DCCITT_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF PACKBITS_SUPPORT
+EXTRAFLAGS = -DPACKBITS_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF LZW_SUPPORT
+EXTRAFLAGS = -DLZW_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF THUNDER_SUPPORT
+EXTRAFLAGS = -DTHUNDER_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF NEXT_SUPPORT
+EXTRAFLAGS = -DNEXT_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF LOGLUV_SUPPORT
+EXTRAFLAGS = -DLOGLUV_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF JPEG_SUPPORT
+LIBS = $(LIBS) $(JPEG_LIB)
+EXTRAFLAGS = -DJPEG_SUPPORT -DOJPEG_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF ZIP_SUPPORT
+LIBS = $(LIBS) $(ZLIB_LIB)
+EXTRAFLAGS = -DZIP_SUPPORT $(EXTRAFLAGS)
+!IFDEF PIXARLOG_SUPPORT
+EXTRAFLAGS = -DPIXARLOG_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+!ENDIF
+
+!IFDEF JBIG_SUPPORT
+LIBS = $(LIBS) $(JBIG_LIB)
+EXTRAFLAGS = -DJBIG_SUPPORT $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF STRIPCHOP_SUPPORT
+EXTRAFLAGS = -DSTRIPCHOP_DEFAULT=TIFF_STRIPCHOP -DSTRIP_SIZE_DEFAULT=$(STRIP_SIZE_DEFAULT) $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF EXTRASAMPLE_AS_ALPHA_SUPPORT
+EXTRAFLAGS = -DDEFAULT_EXTRASAMPLE_AS_ALPHA $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF CHECK_JPEG_YCBCR_SUBSAMPLING
+EXTRAFLAGS = -DCHECK_JPEG_YCBCR_SUBSAMPLING $(EXTRAFLAGS)
+!ENDIF
+
+!IFDEF USE_WIN_CRT_LIB
+EXTRAFLAGS = -DAVOID_WIN32_FILEIO $(EXTRAFLAGS)
+!ELSE
+EXTRAFLAGS = -DUSE_WIN32_FILEIO $(EXTRAFLAGS)
+!ENDIF
diff --git a/tiff/port/Makefile.am b/tiff/port/Makefile.am
new file mode 100644
index 0000000..ea614d9
--- /dev/null
+++ b/tiff/port/Makefile.am
@@ -0,0 +1,31 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+EXTRA_DIST = Makefile.vc
+
+noinst_LTLIBRARIES = libport.la
+libport_la_SOURCES = dummy.c libport.h
+libport_la_LIBADD = @LTLIBOBJS@
+
diff --git a/tiff/port/Makefile.in b/tiff/port/Makefile.in
new file mode 100644
index 0000000..930eadc
--- /dev/null
+++ b/tiff/port/Makefile.in
@@ -0,0 +1,555 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = port
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in getopt.c \
+ lfind.c strcasecmp.c strtoul.c
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libport_la_DEPENDENCIES = @LTLIBOBJS@
+am_libport_la_OBJECTS = dummy.lo
+libport_la_OBJECTS = $(am_libport_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libtiff
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libport_la_SOURCES)
+DIST_SOURCES = $(libport_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = Makefile.vc
+noinst_LTLIBRARIES = libport.la
+libport_la_SOURCES = dummy.c libport.h
+libport_la_LIBADD = @LTLIBOBJS@
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign port/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign port/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libport.la: $(libport_la_OBJECTS) $(libport_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libport_la_OBJECTS) $(libport_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/getopt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/lfind.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strcasecmp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/strtoul.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf $(DEPDIR) ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf $(DEPDIR) ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/port/Makefile.vc b/tiff/port/Makefile.vc
new file mode 100644
index 0000000..f5c85c6
--- /dev/null
+++ b/tiff/port/Makefile.vc
@@ -0,0 +1,43 @@
+# $Id: Makefile.vc,v 1.4 2006/03/23 14:54:02 dron Exp $
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+# Makefile for MS Visual C and Watcom C compilers.
+#
+# To build:
+# C:\libtiff\port> nmake /f makefile.vc
+
+!INCLUDE ..\nmake.opt
+
+OBJ = \
+ strcasecmp.obj \
+ getopt.obj
+
+all: libport.lib
+
+libport.lib: $(OBJ)
+ $(AR) /out:libport.lib $(OBJ)
+
+clean:
+ -del *.obj
+ -del *.lib
+
diff --git a/tiff/port/dummy.c b/tiff/port/dummy.c
new file mode 100644
index 0000000..1b48910
--- /dev/null
+++ b/tiff/port/dummy.c
@@ -0,0 +1,19 @@
+/* $Id: dummy.c,v 1.2.2.2 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Dummy function, just to be ensure that the library always will be created.
+ */
+
+void
+libport_dummy_function()
+{
+ return;
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/port/getopt.c b/tiff/port/getopt.c
new file mode 100644
index 0000000..032626c
--- /dev/null
+++ b/tiff/port/getopt.c
@@ -0,0 +1,131 @@
+/* $Id: getopt.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
+__RCSID("$NetBSD: getopt.c,v 1.26 2003/08/07 16:43:40 agc Exp $");
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt, /* character checked for validity */
+ optreset; /* reset getopt */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define BADARG (int)':'
+#define EMSG ""
+
+/*
+ * getopt --
+ * Parse argc/argv argument vector.
+ */
+int
+getopt(int argc, char * const argv[], const char *optstring)
+{
+ static char *place = EMSG; /* option letter processing */
+ char *oli; /* option letter list index */
+
+ if (optreset || *place == 0) { /* update scanning pointer */
+ optreset = 0;
+ place = argv[optind];
+ if (optind >= argc || *place++ != '-') {
+ /* Argument is absent or is not an option */
+ place = EMSG;
+ return (-1);
+ }
+ optopt = *place++;
+ if (optopt == '-' && *place == 0) {
+ /* "--" => end of options */
+ ++optind;
+ place = EMSG;
+ return (-1);
+ }
+ if (optopt == 0) {
+ /* Solitary '-', treat as a '-' option
+ if the program (eg su) is looking for it. */
+ place = EMSG;
+ if (strchr(optstring, '-') == NULL)
+ return -1;
+ optopt = '-';
+ }
+ } else
+ optopt = *place++;
+
+ /* See if option letter is one the caller wanted... */
+ if (optopt == ':' || (oli = strchr(optstring, optopt)) == NULL) {
+ if (*place == 0)
+ ++optind;
+ if (opterr && *optstring != ':')
+ (void)fprintf(stderr,
+ "unknown option -- %c\n", optopt);
+ return (BADCH);
+ }
+
+ /* Does this option need an argument? */
+ if (oli[1] != ':') {
+ /* don't need argument */
+ optarg = NULL;
+ if (*place == 0)
+ ++optind;
+ } else {
+ /* Option-argument is either the rest of this argument or the
+ entire next argument. */
+ if (*place)
+ optarg = place;
+ else if (argc > ++optind)
+ optarg = argv[optind];
+ else {
+ /* option-argument absent */
+ place = EMSG;
+ if (*optstring == ':')
+ return (BADARG);
+ if (opterr)
+ (void)fprintf(stderr,
+ "option requires an argument -- %c\n",
+ optopt);
+ return (BADCH);
+ }
+ place = EMSG;
+ ++optind;
+ }
+ return (optopt); /* return option letter */
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/port/lfind.c b/tiff/port/lfind.c
new file mode 100644
index 0000000..1cf30a2
--- /dev/null
+++ b/tiff/port/lfind.c
@@ -0,0 +1,69 @@
+/* $Id: lfind.c,v 1.4.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Roger L. Snyder.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)lsearch.c 8.1 (Berkeley) 6/4/93";
+__RCSID("$NetBSD: lsearch.c,v 1.2 2005/07/06 15:47:15 drochner Exp $");
+#endif
+
+#ifdef _WIN32_WCE
+# include <wce_types.h>
+#else
+# include <sys/types.h>
+#endif
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+void *
+lfind(const void *key, const void *base, size_t *nmemb, size_t size,
+ int(*compar)(const void *, const void *))
+{
+ char *element, *end;
+
+ end = (char *)base + *nmemb * size;
+ for (element = (char *)base; element < end; element += size)
+ if (!compar(element, key)) /* key found */
+ return element;
+
+ return NULL;
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/port/libport.h b/tiff/port/libport.h
new file mode 100644
index 0000000..65fe670
--- /dev/null
+++ b/tiff/port/libport.h
@@ -0,0 +1,58 @@
+/* $Id: libport.h,v 1.2.2.3 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2009 Frank Warmerdam
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef _LIBPORT_
+#define _LIBPORT_
+
+int getopt(int argc, char * const argv[], const char *optstring);
+extern char *optarg;
+extern int opterr;
+extern int optind;
+extern int optopt;
+
+int strcasecmp(const char *s1, const char *s2);
+
+#ifndef HAVE_GETOPT
+# define HAVE_GETOPT 1
+#endif
+
+#if 0
+unsigned long strtoul(const char *nptr, char **endptr, int base);
+#endif
+
+#if 0
+void *
+lfind(const void *key, const void *base, size_t *nmemb, size_t size,
+ int(*compar)(const void *, const void *));
+#endif
+
+#endif /* ndef _LIBPORT_ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/port/strcasecmp.c b/tiff/port/strcasecmp.c
new file mode 100644
index 0000000..ac61a41
--- /dev/null
+++ b/tiff/port/strcasecmp.c
@@ -0,0 +1,57 @@
+/* $Id: strcasecmp.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
+__RCSID("$NetBSD: strcasecmp.c,v 1.16 2003/08/07 16:43:49 agc Exp $");
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+int
+strcasecmp(const char *s1, const char *s2)
+{
+ const unsigned char *us1 = (const unsigned char *)s1,
+ *us2 = (const unsigned char *)s2;
+
+ while (tolower(*us1) == tolower(*us2++))
+ if (*us1++ == '\0')
+ return (0);
+ return (tolower(*us1) - tolower(*--us2));
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/port/strtoul.c b/tiff/port/strtoul.c
new file mode 100644
index 0000000..a3fd1f9
--- /dev/null
+++ b/tiff/port/strtoul.c
@@ -0,0 +1,116 @@
+/* $Id: strtoul.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+__RCSID("$NetBSD: strtoul.c,v 1.16 2003/08/07 16:43:45 agc Exp $");
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+/*
+ * Convert a string to an unsigned long integer.
+ *
+ * Ignores `locale' stuff. Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+unsigned long
+strtoul(const char *nptr, char **endptr, int base)
+{
+ const char *s;
+ unsigned long acc, cutoff;
+ int c;
+ int neg, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = (unsigned char) *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ cutoff = ULONG_MAX / (unsigned long)base;
+ cutlim = (int)(ULONG_MAX % (unsigned long)base);
+ for (acc = 0, any = 0;; c = (unsigned char) *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0)
+ continue;
+ if (acc > cutoff || (acc == cutoff && c > cutlim)) {
+ any = -1;
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else {
+ any = 1;
+ acc *= (unsigned long)base;
+ acc += c;
+ }
+ }
+ if (neg && any > 0)
+ acc = -acc;
+ if (endptr != 0)
+ /* LINTED interface specification */
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/test/Makefile.am b/tiff/test/Makefile.am
new file mode 100644
index 0000000..b953b95
--- /dev/null
+++ b/tiff/test/Makefile.am
@@ -0,0 +1,46 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+AUTOMAKE_OPTIONS = 1.11 color-tests parallel-tests foreign
+
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+
+#EXTRA_DIST = Makefile.vc
+
+TESTS = $(check_PROGRAMS)
+
+check_PROGRAMS = ascii_tag long_tag short_tag strip_rw
+
+ascii_tag_SOURCES = ascii_tag.c
+ascii_tag_LDADD = $(LIBTIFF)
+long_tag_SOURCES = long_tag.c check_tag.c
+long_tag_LDADD = $(LIBTIFF)
+short_tag_SOURCES = short_tag.c check_tag.c
+short_tag_LDADD = $(LIBTIFF)
+strip_rw_SOURCES = strip_rw.c strip.c test_arrays.c test_arrays.h
+strip_rw_LDADD = $(LIBTIFF)
+
+INCLUDES = -I$(top_srcdir)/libtiff
+
diff --git a/tiff/test/Makefile.in b/tiff/test/Makefile.in
new file mode 100644
index 0000000..8f85a40
--- /dev/null
+++ b/tiff/test/Makefile.in
@@ -0,0 +1,845 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+check_PROGRAMS = ascii_tag$(EXEEXT) long_tag$(EXEEXT) \
+ short_tag$(EXEEXT) strip_rw$(EXEEXT)
+subdir = test
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am_ascii_tag_OBJECTS = ascii_tag.$(OBJEXT)
+ascii_tag_OBJECTS = $(am_ascii_tag_OBJECTS)
+ascii_tag_DEPENDENCIES = $(LIBTIFF)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+am_long_tag_OBJECTS = long_tag.$(OBJEXT) check_tag.$(OBJEXT)
+long_tag_OBJECTS = $(am_long_tag_OBJECTS)
+long_tag_DEPENDENCIES = $(LIBTIFF)
+am_short_tag_OBJECTS = short_tag.$(OBJEXT) check_tag.$(OBJEXT)
+short_tag_OBJECTS = $(am_short_tag_OBJECTS)
+short_tag_DEPENDENCIES = $(LIBTIFF)
+am_strip_rw_OBJECTS = strip_rw.$(OBJEXT) strip.$(OBJEXT) \
+ test_arrays.$(OBJEXT)
+strip_rw_OBJECTS = $(am_strip_rw_OBJECTS)
+strip_rw_DEPENDENCIES = $(LIBTIFF)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libtiff
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(ascii_tag_SOURCES) $(long_tag_SOURCES) \
+ $(short_tag_SOURCES) $(strip_rw_SOURCES)
+DIST_SOURCES = $(ascii_tag_SOURCES) $(long_tag_SOURCES) \
+ $(short_tag_SOURCES) $(strip_rw_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+# If stdout is a non-dumb tty, use colors. If test -t is not supported,
+# then this fails; a conservative approach. Of course do not redirect
+# stdout here, just stderr.
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=; \
+test "X$(AM_COLOR_TESTS)" != Xno \
+&& test "X$$TERM" != Xdumb \
+&& { test "X$(AM_COLOR_TESTS)" = Xalways || test -t 1 2>/dev/null; } \
+&& { \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ std=''; \
+}
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+# Restructured Text title and section.
+am__rst_title = sed 's/.*/ & /;h;s/./=/g;p;x;p;g;p;s/.*//'
+am__rst_section = sed 'p;s/./=/g;p;g'
+# Put stdin (possibly several lines separated by ". ") in a box.
+am__text_box = $(AWK) '{ \
+ n = split($$0, lines, "\\. "); max = 0; \
+ for (i = 1; i <= n; ++i) \
+ if (max < length(lines[i])) \
+ max = length(lines[i]); \
+ for (i = 0; i < max; ++i) line = line "="; \
+ print line; \
+ for (i = 1; i <= n; ++i) if (lines[i]) print lines[i];\
+ print line; \
+}'
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL). This contradicts POSIX. Work around the problem
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log, and passes
+# TESTS_ENVIRONMENT. Save and restore TERM around use of
+# TESTS_ENVIRONMENT, in case that unsets it.
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+srcdir=$(srcdir); export srcdir; \
+rm -f $@-t; \
+trap 'st=$$?; rm -f '\''$(abs_builddir)/$@-t'\''; (exit $$st); exit $$st' \
+ 1 2 13 15; \
+am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`; \
+test "x$$am__odir" = x. || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; __SAVED_TERM=$$TERM; \
+$(TESTS_ENVIRONMENT)
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check check-html recheck recheck-html
+TEST_SUITE_LOG = test-suite.log
+TEST_SUITE_HTML = $(TEST_SUITE_LOG:.log=.html)
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+TEST_LOGS_TMP = $(TEST_LOGS:.log=.log-t)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = 1.11 color-tests parallel-tests foreign
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+
+#EXTRA_DIST = Makefile.vc
+TESTS = $(check_PROGRAMS)
+ascii_tag_SOURCES = ascii_tag.c
+ascii_tag_LDADD = $(LIBTIFF)
+long_tag_SOURCES = long_tag.c check_tag.c
+long_tag_LDADD = $(LIBTIFF)
+short_tag_SOURCES = short_tag.c check_tag.c
+short_tag_LDADD = $(LIBTIFF)
+strip_rw_SOURCES = strip_rw.c strip.c test_arrays.c test_arrays.h
+strip_rw_LDADD = $(LIBTIFF)
+INCLUDES = -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .html .lo .log .o .obj .test .test$(EXEEXT)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign test/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign test/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+ascii_tag$(EXEEXT): $(ascii_tag_OBJECTS) $(ascii_tag_DEPENDENCIES)
+ @rm -f ascii_tag$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ascii_tag_OBJECTS) $(ascii_tag_LDADD) $(LIBS)
+long_tag$(EXEEXT): $(long_tag_OBJECTS) $(long_tag_DEPENDENCIES)
+ @rm -f long_tag$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(long_tag_OBJECTS) $(long_tag_LDADD) $(LIBS)
+short_tag$(EXEEXT): $(short_tag_OBJECTS) $(short_tag_DEPENDENCIES)
+ @rm -f short_tag$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(short_tag_OBJECTS) $(short_tag_LDADD) $(LIBS)
+strip_rw$(EXEEXT): $(strip_rw_OBJECTS) $(strip_rw_DEPENDENCIES)
+ @rm -f strip_rw$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(strip_rw_OBJECTS) $(strip_rw_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ascii_tag.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/check_tag.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/long_tag.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/short_tag.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strip_rw.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_arrays.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# To be appended to the command running the test. Handle the stdout
+# and stderr redirection, and catch the exit status.
+am__check_post = \
+>$@-t 2>&1; \
+estatus=$$?; \
+if test -n '$(DISABLE_HARD_ERRORS)' \
+ && test $$estatus -eq 99; then \
+ estatus=1; \
+fi; \
+TERM=$$__SAVED_TERM; export TERM; \
+$(am__tty_colors); \
+xfailed=PASS; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ xfailed=XFAIL;; \
+esac; \
+case $$estatus:$$xfailed in \
+ 0:XFAIL) col=$$red; res=XPASS;; \
+ 0:*) col=$$grn; res=PASS ;; \
+ 77:*) col=$$blu; res=SKIP ;; \
+ 99:*) col=$$red; res=FAIL ;; \
+ *:XFAIL) col=$$lgn; res=XFAIL;; \
+ *:*) col=$$red; res=FAIL ;; \
+esac; \
+echo "$${col}$$res$${std}: $$f"; \
+echo "$$res: $$f (exit: $$estatus)" | \
+ $(am__rst_section) >$@; \
+cat $@-t >>$@; \
+rm -f $@-t
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__sh_e_setup); \
+ list='$(TEST_LOGS)'; \
+ results=`for f in $$list; do \
+ read line < $$f && echo "$$line" || echo FAIL; \
+ done`; \
+ all=`echo "$$results" | sed '/^$$/d' | wc -l | sed -e 's/^[ ]*//'`; \
+ fail=`echo "$$results" | grep -c '^FAIL'`; \
+ pass=`echo "$$results" | grep -c '^PASS'`; \
+ skip=`echo "$$results" | grep -c '^SKIP'`; \
+ xfail=`echo "$$results" | grep -c '^XFAIL'`; \
+ xpass=`echo "$$results" | grep -c '^XPASS'`; \
+ failures=`expr $$fail + $$xpass`; \
+ all=`expr $$all - $$skip`; \
+ if test "$$all" -eq 1; then tests=test; All=; \
+ else tests=tests; All="All "; fi; \
+ case fail=$$fail:xpass=$$xpass:xfail=$$xfail in \
+ fail=0:xpass=0:xfail=0) \
+ msg="$$All$$all $$tests passed. "; \
+ exit=true;; \
+ fail=0:xpass=0:xfail=*) \
+ msg="$$All$$all $$tests behaved as expected"; \
+ if test "$$xfail" -eq 1; then xfailures=failure; \
+ else xfailures=failures; fi; \
+ msg="$$msg ($$xfail expected $$xfailures). "; \
+ exit=true;; \
+ fail=*:xpass=0:xfail=*) \
+ msg="$$fail of $$all $$tests failed. "; \
+ exit=false;; \
+ fail=*:xpass=*:xfail=*) \
+ msg="$$failures of $$all $$tests did not behave as expected"; \
+ if test "$$xpass" -eq 1; then xpasses=pass; \
+ else xpasses=passes; fi; \
+ msg="$$msg ($$xpass unexpected $$xpasses). "; \
+ exit=false;; \
+ *) \
+ echo >&2 "incorrect case"; exit 4;; \
+ esac; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ msg="$$msg($$skip test was not run). "; \
+ else \
+ msg="$$msg($$skip tests were not run). "; \
+ fi; \
+ fi; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ echo "$$msg"; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for f in $$list; do \
+ read line < $$f; \
+ case $$line in \
+ PASS:*|XFAIL:*);; \
+ *) echo; cat $$f;; \
+ esac; \
+ done; \
+ } >$(TEST_SUITE_LOG).tmp; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if test "$$failures" -ne 0; then \
+ msg="$${msg}See $(subdir)/$(TEST_SUITE_LOG). "; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ msg="$${msg}Please report to $(PACKAGE_BUGREPORT). "; \
+ fi; \
+ fi; \
+ test x"$$VERBOSE" = x || $$exit || cat $(TEST_SUITE_LOG); \
+ $(am__tty_colors); \
+ if $$exit; then \
+ echo $(ECHO_N) "$$grn$(ECHO_C)"; \
+ else \
+ echo $(ECHO_N) "$$red$(ECHO_C)"; \
+ fi; \
+ echo "$$msg" | $(am__text_box); \
+ echo $(ECHO_N) "$$std$(ECHO_C)"; \
+ $$exit
+
+# Run all the tests.
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set_logs=; if test "X$(TEST_LOGS)" = X.log; then \
+ set_logs=TEST_LOGS=; \
+ fi; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) $$set_logs
+
+.log.html:
+ @list='$(RST2HTML) $$RST2HTML rst2html rst2html.py'; \
+ for r2h in $$list; do \
+ if ($$r2h --version) >/dev/null 2>&1; then \
+ R2H=$$r2h; \
+ fi; \
+ done; \
+ if test -z "$$R2H"; then \
+ echo >&2 "cannot find rst2html, cannot create $@"; \
+ exit 2; \
+ fi; \
+ $$R2H $< >$@.tmp
+ @mv $@.tmp $@
+
+# Be sure to run check first, and then to convert the result.
+# Beware of concurrent executions. Run "check" not "check-TESTS", as
+# check-SCRIPTS and other dependencies are rebuilt by the former only.
+# And expect check to fail.
+check-html:
+ @if $(MAKE) $(AM_MAKEFLAGS) check; then \
+ rv=0; else rv=$$?; \
+ fi; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_HTML) || exit 4; \
+ exit $$rv
+recheck recheck-html:
+ @target=`echo $@ | sed 's,^re,,'`; \
+ list='$(TEST_LOGS)'; \
+ list=`for f in $$list; do \
+ test -f $$f || continue; \
+ if read line < $$f; then \
+ case $$line in FAIL*|XPASS*) echo $$f;; esac; \
+ else echo $$f; fi; \
+ done | tr '\012\015' ' '`; \
+ $(MAKE) $(AM_MAKEFLAGS) $$target AM_MAKEFLAGS='$(AM_MAKEFLAGS) TEST_LOGS="'"$$list"'"'
+ascii_tag.log: ascii_tag$(EXEEXT)
+ @p='ascii_tag$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+long_tag.log: long_tag$(EXEEXT)
+ @p='long_tag$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+short_tag.log: short_tag$(EXEEXT)
+ @p='short_tag$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+strip_rw.log: strip_rw$(EXEEXT)
+ @p='strip_rw$(EXEEXT)'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+.test.log:
+ @p='$<'; $(am__check_pre) $(TEST_LOG_COMPILE) "$$tst" $(am__check_post)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; $(am__check_pre) $(TEST_LOG_COMPILE) "$$tst" $(am__check_post)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS_TMP)" || rm -f $(TEST_LOGS_TMP)
+ -test -z "$(TEST_SUITE_HTML)" || rm -f $(TEST_SUITE_HTML)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: check-am check-html install-am install-strip recheck \
+ recheck-html
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am check-html \
+ clean clean-checkPROGRAMS clean-generic clean-libtool ctags \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ recheck recheck-html tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/test/ascii_tag.c b/tiff/test/ascii_tag.c
new file mode 100644
index 0000000..bf81212
--- /dev/null
+++ b/tiff/test/ascii_tag.c
@@ -0,0 +1,177 @@
+/* $Id: ascii_tag.c,v 1.5.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Module to test ASCII tags read/write functions.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+const char *filename = "ascii_test.tiff";
+
+static struct Tags {
+ ttag_t tag;
+ const char *value;
+} ascii_tags[] = {
+ { TIFFTAG_DOCUMENTNAME, "Test TIFF image" },
+ { TIFFTAG_IMAGEDESCRIPTION, "Temporary test image" },
+ { TIFFTAG_MAKE, "This is not scanned image" },
+ { TIFFTAG_MODEL, "No scanner" },
+ { TIFFTAG_PAGENAME, "Test page" },
+ { TIFFTAG_SOFTWARE, "Libtiff library" },
+ { TIFFTAG_DATETIME, "2004:09:10 16:09:00" },
+ { TIFFTAG_ARTIST, "Andrey V. Kiselev" },
+ { TIFFTAG_HOSTCOMPUTER, "Debian GNU/Linux (Sarge)" },
+ { TIFFTAG_TARGETPRINTER, "No printer" },
+ { TIFFTAG_PIXAR_TEXTUREFORMAT, "No texture" },
+ { TIFFTAG_PIXAR_WRAPMODES, "No wrap" },
+ { TIFFTAG_COPYRIGHT, "Copyright (c) 2004, Andrey Kiselev" }
+};
+#define NTAGS (sizeof (ascii_tags) / sizeof (ascii_tags[0]))
+
+const char *ink_names = "Red\0Green\0Blue";
+const int ink_names_size = 15;
+
+int
+main(int argc, char **argv)
+{
+ TIFF *tif;
+ int i;
+ unsigned char buf[3] = { 0, 127, 255 };
+ char *value;
+
+ /* Test whether we can write tags. */
+ tif = TIFFOpen(filename, "w");
+ if (!tif) {
+ fprintf (stderr, "Can't create test TIFF file %s.\n", filename);
+ return 1;
+ }
+
+ if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, 1)) {
+ fprintf (stderr, "Can't set ImageWidth tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, 1)) {
+ fprintf (stderr, "Can't set ImageLength tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8)) {
+ fprintf (stderr, "Can't set BitsPerSample tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3)) {
+ fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
+ fprintf (stderr, "Can't set PlanarConfiguration tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)) {
+ fprintf (stderr, "Can't set PhotometricInterpretation tag.\n");
+ goto failure;
+ }
+
+ for (i = 0; i < NTAGS; i++) {
+ if (!TIFFSetField(tif, ascii_tags[i].tag,
+ ascii_tags[i].value)) {
+ fprintf(stderr, "Can't set tag %d.\n",
+ (int)ascii_tags[i].tag);
+ goto failure;
+ }
+ }
+
+ /* InkNames tag has special form, so we handle it separately. */
+ if (!TIFFSetField(tif, TIFFTAG_NUMBEROFINKS, 3)) {
+ fprintf (stderr, "Can't set tag %d.\n", TIFFTAG_NUMBEROFINKS);
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_INKNAMES, ink_names_size, ink_names)) {
+ fprintf (stderr, "Can't set tag %d.\n", TIFFTAG_INKNAMES);
+ goto failure;
+ }
+
+ /* Write dummy pixel data. */
+ if (!TIFFWriteScanline(tif, buf, 0, 0) < 0) {
+ fprintf (stderr, "Can't write image data.\n");
+ goto failure;
+ }
+
+ TIFFClose(tif);
+
+ /* Ok, now test whether we can read written values. */
+ tif = TIFFOpen(filename, "r");
+ if (!tif) {
+ fprintf (stderr, "Can't open test TIFF file %s.\n", filename);
+ return 1;
+ }
+
+ for (i = 0; i < NTAGS; i++) {
+ if (!TIFFGetField(tif, ascii_tags[i].tag, &value)
+ || strcmp(value, ascii_tags[i].value)) {
+ fprintf(stderr, "Can't get tag %d.\n",
+ (int)ascii_tags[i].tag);
+ goto failure;
+ }
+ }
+
+ if (!TIFFGetField(tif, TIFFTAG_INKNAMES, &value)
+ || memcmp(value, ink_names, ink_names_size)) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_INKNAMES);
+ goto failure;
+ }
+
+ TIFFClose(tif);
+
+ /* All tests passed; delete file and exit with success status. */
+ unlink(filename);
+ return 0;
+
+failure:
+ /* Something goes wrong; close file and return unsuccessful status. */
+ TIFFClose(tif);
+ unlink(filename);
+ return 1;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/test/check_tag.c b/tiff/test/check_tag.c
new file mode 100644
index 0000000..b396db3
--- /dev/null
+++ b/tiff/test/check_tag.c
@@ -0,0 +1,79 @@
+/* $Id: check_tag.c,v 1.2.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Module to test LONG tags read/write functions.
+ */
+
+#include "tiffio.h"
+
+int
+CheckShortField(TIFF *tif, ttag_t field, uint16 value)
+{
+ uint16 tmp = 0;
+
+ if (!TIFFGetField(tif, field, &tmp)) {
+ fprintf (stderr, "Problem fetching tag %lu.\n",
+ (unsigned long) field);
+ return -1;
+ }
+ if (tmp != value) {
+ fprintf (stderr, "Wrong SHORT value fetched for tag %lu.\n",
+ (unsigned long) field);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+CheckLongField(TIFF *tif, ttag_t field, uint32 value)
+{
+ uint32 tmp = 0;
+
+ if (!TIFFGetField(tif, field, &tmp)) {
+ fprintf (stderr, "Problem fetching tag %lu.\n",
+ (unsigned long) field);
+ return -1;
+ }
+ if (tmp != value) {
+ fprintf (stderr, "Wrong LONG value fetched for tag %lu.\n",
+ (unsigned long) field);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/test/long_tag.c b/tiff/test/long_tag.c
new file mode 100644
index 0000000..256bc8e
--- /dev/null
+++ b/tiff/test/long_tag.c
@@ -0,0 +1,161 @@
+/* $Id: long_tag.c,v 1.3.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Module to test LONG tags read/write functions.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+extern int CheckLongField(TIFF *, ttag_t, uint32);
+
+const char *filename = "long_test.tiff";
+
+static struct Tags {
+ ttag_t tag;
+ short count;
+ uint32 value;
+} long_tags[] = {
+ { TIFFTAG_SUBFILETYPE, 1, FILETYPE_REDUCEDIMAGE|FILETYPE_PAGE|FILETYPE_MASK }
+};
+#define NTAGS (sizeof (long_tags) / sizeof (long_tags[0]))
+
+const uint32 width = 1;
+const uint32 length = 1;
+const uint32 rows_per_strip = 1;
+
+int
+main(int argc, char **argv)
+{
+ TIFF *tif;
+ int i;
+ unsigned char buf[3] = { 0, 127, 255 };
+
+ /* Test whether we can write tags. */
+ tif = TIFFOpen(filename, "w");
+ if (!tif) {
+ fprintf (stderr, "Can't create test TIFF file %s.\n", filename);
+ return 1;
+ }
+
+ if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width)) {
+ fprintf (stderr, "Can't set ImageWidth tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length)) {
+ fprintf (stderr, "Can't set ImageLength tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8)) {
+ fprintf (stderr, "Can't set BitsPerSample tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3)) {
+ fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip)) {
+ fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
+ fprintf (stderr, "Can't set PlanarConfiguration tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)) {
+ fprintf (stderr, "Can't set PhotometricInterpretation tag.\n");
+ goto failure;
+ }
+
+ for (i = 0; i < NTAGS; i++) {
+ if (!TIFFSetField(tif, long_tags[i].tag,
+ long_tags[i].value)) {
+ fprintf(stderr, "Can't set tag %d.\n",
+ (int)long_tags[i].tag);
+ goto failure;
+ }
+ }
+
+ /* Write dummy pixel data. */
+ if (!TIFFWriteScanline(tif, buf, 0, 0) < 0) {
+ fprintf (stderr, "Can't write image data.\n");
+ goto failure;
+ }
+
+ TIFFClose(tif);
+
+ /* Ok, now test whether we can read written values. */
+ tif = TIFFOpen(filename, "r");
+ if (!tif) {
+ fprintf (stderr, "Can't open test TIFF file %s.\n", filename);
+ return 1;
+ }
+
+ if (CheckLongField(tif, TIFFTAG_IMAGEWIDTH, width) < 0)
+ goto failure;
+
+ if (CheckLongField(tif, TIFFTAG_IMAGELENGTH, length) < 0)
+ goto failure;
+
+ if (CheckLongField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip) < 0)
+ goto failure;
+
+ for (i = 0; i < NTAGS; i++) {
+ if (CheckLongField(tif, long_tags[i].tag,
+ long_tags[i].value) < 0)
+ goto failure;
+ }
+
+ TIFFClose(tif);
+
+ /* All tests passed; delete file and exit with success status. */
+ unlink(filename);
+ return 0;
+
+failure:
+ /* Something goes wrong; close file and return unsuccessful status. */
+ TIFFClose(tif);
+ unlink(filename);
+ return 1;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/test/short_tag.c b/tiff/test/short_tag.c
new file mode 100644
index 0000000..45214e1
--- /dev/null
+++ b/tiff/test/short_tag.c
@@ -0,0 +1,187 @@
+/* $Id: short_tag.c,v 1.6.2.2 2010-06-10 22:52:45 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Module to test SHORT tags read/write functions.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+extern int CheckLongField(TIFF *, ttag_t, uint32);
+extern int CheckShortField(TIFF *, ttag_t, uint16);
+
+const char *filename = "short_test.tiff";
+
+#define SPP 3 /* Samples per pixel */
+const uint16 width = 1;
+const uint16 length = 1;
+const uint16 bps = 8;
+const uint16 photometric = PHOTOMETRIC_RGB;
+const uint16 rows_per_strip = 1;
+const uint16 planarconfig = PLANARCONFIG_CONTIG;
+
+static struct SingleTags {
+ ttag_t tag;
+ uint16 value;
+} short_single_tags[] = {
+ { TIFFTAG_COMPRESSION, COMPRESSION_NONE },
+ { TIFFTAG_FILLORDER, FILLORDER_MSB2LSB },
+ { TIFFTAG_ORIENTATION, ORIENTATION_BOTRIGHT },
+ { TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH },
+ { TIFFTAG_INKSET, INKSET_MULTIINK },
+ { TIFFTAG_MINSAMPLEVALUE, 23 },
+ { TIFFTAG_MAXSAMPLEVALUE, 241 },
+ { TIFFTAG_NUMBEROFINKS, SPP },
+ { TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT }
+ /*{ TIFFTAG_IMAGEDEPTH, 1 },
+ { TIFFTAG_TILEDEPTH, 1 }*/
+};
+#define NSINGLETAGS (sizeof(short_single_tags) / sizeof(short_single_tags[0]))
+
+int
+main(int argc, char **argv)
+{
+ TIFF *tif;
+ int i;
+ unsigned char buf[3] = { 0, 127, 255 };
+
+ /* Test whether we can write tags. */
+ tif = TIFFOpen(filename, "w");
+ if (!tif) {
+ fprintf (stderr, "Can't create test TIFF file %s.\n", filename);
+ return 1;
+ }
+
+ if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width)) {
+ fprintf (stderr, "Can't set ImageWidth tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length)) {
+ fprintf (stderr, "Can't set ImageLength tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps)) {
+ fprintf (stderr, "Can't set BitsPerSample tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, SPP)) {
+ fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip)) {
+ fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, planarconfig)) {
+ fprintf (stderr, "Can't set PlanarConfiguration tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) {
+ fprintf (stderr, "Can't set PhotometricInterpretation tag.\n");
+ goto failure;
+ }
+
+ for (i = 0; i < NSINGLETAGS; i++) {
+ if (!TIFFSetField(tif, short_single_tags[i].tag,
+ short_single_tags[i].value)) {
+ fprintf(stderr, "Can't set tag %d.\n",
+ (int)short_single_tags[i].tag);
+ goto failure;
+ }
+ }
+
+ /* Write dummy pixel data. */
+ if (!TIFFWriteScanline(tif, buf, 0, 0) < 0) {
+ fprintf (stderr, "Can't write image data.\n");
+ goto failure;
+ }
+
+ TIFFClose(tif);
+
+ /* Ok, now test whether we can read written values. */
+ tif = TIFFOpen(filename, "r");
+ if (!tif) {
+ fprintf (stderr, "Can't open test TIFF file %s.\n", filename);
+ return 1;
+ }
+
+ if (CheckLongField(tif, TIFFTAG_IMAGEWIDTH, width) < 0)
+ goto failure;
+
+ if (CheckLongField(tif, TIFFTAG_IMAGELENGTH, length) < 0)
+ goto failure;
+
+ if (CheckShortField(tif, TIFFTAG_BITSPERSAMPLE, bps) < 0)
+ goto failure;
+
+ if (CheckShortField(tif, TIFFTAG_PHOTOMETRIC, photometric) < 0)
+ goto failure;
+
+ if (CheckShortField(tif, TIFFTAG_SAMPLESPERPIXEL, SPP) < 0)
+ goto failure;
+
+ if (CheckLongField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip) < 0)
+ goto failure;
+
+ if (CheckShortField(tif, TIFFTAG_PLANARCONFIG, planarconfig) < 0)
+ goto failure;
+
+ for (i = 0; i < NSINGLETAGS; i++) {
+ if (CheckShortField(tif, short_single_tags[i].tag,
+ short_single_tags[i].value) < 0)
+ goto failure;
+ }
+
+ TIFFClose(tif);
+
+ /* All tests passed; delete file and exit with success status. */
+ unlink(filename);
+ return 0;
+
+failure:
+ /* Something goes wrong; close file and return unsuccessful status. */
+ TIFFClose(tif);
+ unlink(filename);
+ return 1;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/test/strip.c b/tiff/test/strip.c
new file mode 100644
index 0000000..df6406e
--- /dev/null
+++ b/tiff/test/strip.c
@@ -0,0 +1,298 @@
+/* $Id: strip.c,v 1.3.2.2 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Functions to test strip interface of libtiff.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "tiffio.h"
+
+int
+write_strips(TIFF *tif, const tdata_t array, const tsize_t size)
+{
+ tstrip_t strip, nstrips;
+ tsize_t stripsize, offset;
+
+ stripsize = TIFFStripSize(tif);
+ if (!stripsize) {
+ fprintf (stderr, "Wrong size of strip.\n");
+ return -1;
+ }
+
+ nstrips = TIFFNumberOfStrips(tif);
+ for (offset = 0, strip = 0;
+ offset < size && strip < nstrips;
+ offset+=stripsize, strip++) {
+ /*
+ * Properly write last strip.
+ */
+ tsize_t bufsize = size - offset;
+ if (bufsize > stripsize)
+ bufsize = stripsize;
+
+ if (TIFFWriteEncodedStrip(tif, strip, (char *)array + offset,
+ bufsize) != bufsize) {
+ fprintf (stderr, "Can't write strip %lu.\n",
+ (unsigned long)strip);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int
+read_strips(TIFF *tif, const tdata_t array, const tsize_t size)
+{
+ tstrip_t strip, nstrips;
+ tsize_t stripsize, offset;
+ tdata_t buf = NULL;
+
+ stripsize = TIFFStripSize(tif);
+ if (!stripsize) {
+ fprintf (stderr, "Wrong size of strip.\n");
+ return -1;
+ }
+
+ buf = _TIFFmalloc(stripsize);
+ if (!buf) {
+ fprintf (stderr, "Can't allocate space for strip buffer.\n");
+ return -1;
+ }
+
+ nstrips = TIFFNumberOfStrips(tif);
+ for (offset = 0, strip = 0;
+ offset < size && strip < nstrips;
+ offset+=stripsize, strip++) {
+ /*
+ * Properly read last strip.
+ */
+ tsize_t bufsize = size - offset;
+ if (bufsize > stripsize)
+ bufsize = stripsize;
+
+ if (TIFFReadEncodedStrip(tif, strip, buf, -1) != bufsize) {
+ fprintf (stderr, "Can't read strip %lu.\n",
+ (unsigned long)strip);
+ return -1;
+ }
+ if (memcmp(buf, (char *)array + offset, bufsize) != 0) {
+ fprintf (stderr, "Wrong data read for strip %lu.\n",
+ (unsigned long)strip);
+ _TIFFfree(buf);
+ return -1;
+ }
+ }
+
+ _TIFFfree(buf);
+
+ return 0;
+}
+
+int
+create_image_striped(const char *name, uint32 width, uint32 length,
+ uint32 rowsperstrip, uint16 compression,
+ uint16 spp, uint16 bps, uint16 photometric,
+ uint16 sampleformat, uint16 planarconfig,
+ const tdata_t array, const tsize_t size)
+{
+ TIFF *tif;
+
+ /* Test whether we can write tags. */
+ tif = TIFFOpen(name, "w");
+ if (!tif)
+ goto openfailure;
+
+ if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width)) {
+ fprintf (stderr, "Can't set ImageWidth tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length)) {
+ fprintf (stderr, "Can't set ImageLength tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps)) {
+ fprintf (stderr, "Can't set BitsPerSample tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp)) {
+ fprintf (stderr, "Can't set SamplesPerPixel tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip)) {
+ fprintf (stderr, "Can't set RowsPerStrip tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, planarconfig)) {
+ fprintf (stderr, "Can't set PlanarConfiguration tag.\n");
+ goto failure;
+ }
+ if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) {
+ fprintf (stderr, "Can't set PhotometricInterpretation tag.\n");
+ goto failure;
+ }
+
+ if (write_strips(tif, array, size) < 0) {
+ fprintf (stderr, "Can't write image data.\n");
+ goto failure;
+ }
+
+ TIFFClose(tif);
+ return 0;
+
+failure:
+ TIFFClose(tif);
+openfailure:
+ fprintf (stderr, "Can't create test TIFF file %s:\n"
+" ImageWidth=%u, ImageLength=%u, RowsPerStrip=%u, Compression=%d,\n"
+" BitsPerSample=%d, SamplesPerPixel=%d, SampleFormat=%d,\n"
+" PlanarConfiguration=%d, PhotometricInterpretation=%d.\n",
+ name, width, length, rowsperstrip, compression,
+ bps, spp, sampleformat, planarconfig,
+ photometric);
+ return -1;
+}
+
+int
+read_image_striped(const char *name, uint32 width, uint32 length,
+ uint32 rowsperstrip, uint16 compression,
+ uint16 spp, uint16 bps, uint16 photometric,
+ uint16 sampleformat, uint16 planarconfig,
+ const tdata_t array, const tsize_t size)
+{
+ TIFF *tif;
+ uint16 value_u16;
+ uint32 value_u32;
+
+ /* Test whether we can read written values. */
+ tif = TIFFOpen(name, "r");
+ if (!tif)
+ goto openfailure;
+
+ if (TIFFIsTiled(tif)) {
+ fprintf (stderr, "Can't read image %s, it is tiled.\n",
+ name);
+ goto failure;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &value_u32)
+ || value_u32 != width) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_IMAGEWIDTH);
+ goto failure;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &value_u32)
+ || value_u32 != length) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_IMAGELENGTH);
+ goto failure;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &value_u16)
+ || value_u16 != bps) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_BITSPERSAMPLE);
+ goto failure;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &value_u16)
+ || value_u16 != photometric) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_PHOTOMETRIC);
+ goto failure;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &value_u16)
+ || value_u16 != spp) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_SAMPLESPERPIXEL);
+ goto failure;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &value_u32)
+ || value_u32 != rowsperstrip) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_ROWSPERSTRIP);
+ goto failure;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &value_u16)
+ || value_u16 != planarconfig) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_PLANARCONFIG);
+ goto failure;
+ }
+
+ if (read_strips(tif, array, size) < 0) {
+ fprintf (stderr, "Can't read image data.\n");
+ goto failure;
+ }
+
+ TIFFClose(tif);
+ return 0;
+
+failure:
+ TIFFClose(tif);
+openfailure:
+ fprintf (stderr, "Can't read test TIFF file %s:\n"
+" ImageWidth=%u, ImageLength=%u, RowsPerStrip=%u, Compression=%d,\n"
+" BitsPerSample=%d, SamplesPerPixel=%d, SampleFormat=%d,\n"
+" PlanarConfiguration=%d, PhotometricInterpretation=%d.\n",
+ name, width, length, rowsperstrip, compression,
+ bps, spp, sampleformat, planarconfig,
+ photometric);
+ return -1;
+}
+
+int
+write_scanlines(TIFF *tif, const tdata_t array, const tsize_t size)
+{
+ uint32 length, row;
+ tsize_t scanlinesize, offset;
+
+ (void) size;
+
+ if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &length)) {
+ fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_IMAGELENGTH);
+ return -1;
+ }
+
+ scanlinesize = TIFFScanlineSize(tif);
+ if (!scanlinesize) {
+ fprintf (stderr, "Wrong size of scanline.\n");
+ return -1;
+ }
+
+ for (offset = 0, row = 0; row < length; offset+=scanlinesize, row++) {
+ if (TIFFWriteScanline(tif, (char *)array + offset, row, 0) < 0) {
+ fprintf (stderr,
+ "Can't write image data at row %u.\n", row);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/test/strip_rw.c b/tiff/test/strip_rw.c
new file mode 100644
index 0000000..2ad0d80
--- /dev/null
+++ b/tiff/test/strip_rw.c
@@ -0,0 +1,162 @@
+/* $Id: strip_rw.c,v 1.5.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Test libtiff input/output routines.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+#include "test_arrays.h"
+
+extern int
+create_image_striped(const char *, uint32, uint32, uint32, uint16, uint16,
+ uint16, uint16, uint16, uint16, const tdata_t,
+ const tsize_t);
+extern int
+read_image_striped(const char *, uint32, uint32, uint32, uint16, uint16,
+ uint16, uint16, uint16, uint16, const tdata_t,
+ const tsize_t);
+
+const char *filename = "strip_test.tiff";
+
+int
+main(int argc, char **argv)
+{
+ uint32 rowsperstrip;
+ uint16 compression;
+ uint16 spp, bps, photometric, sampleformat, planarconfig;
+
+ /*
+ * Test two special cases: image consisting from single line and image
+ * consisting from single column.
+ */
+ rowsperstrip = 1;
+ compression = COMPRESSION_NONE;
+ spp = 1;
+ bps = 8;
+ photometric = PHOTOMETRIC_MINISBLACK;
+ sampleformat = SAMPLEFORMAT_UINT;
+ planarconfig = PLANARCONFIG_CONTIG;
+
+ if (create_image_striped(filename, XSIZE * YSIZE, 1, rowsperstrip,
+ compression, spp, bps, photometric,
+ sampleformat, planarconfig,
+ (const tdata_t) byte_array1, byte_array1_size) < 0) {
+ fprintf (stderr, "Can't create TIFF file %s.\n", filename);
+ goto failure;
+ }
+ if (read_image_striped(filename, XSIZE * YSIZE, 1, rowsperstrip,
+ compression, spp, bps, photometric,
+ sampleformat, planarconfig,
+ (const tdata_t) byte_array1, byte_array1_size) < 0) {
+ fprintf (stderr, "Can't read TIFF file %s.\n", filename);
+ goto failure;
+ }
+ unlink(filename);
+
+ if (create_image_striped(filename, 1, XSIZE * YSIZE, rowsperstrip,
+ compression, spp, bps, photometric,
+ sampleformat, planarconfig,
+ (const tdata_t) byte_array1, byte_array1_size) < 0) {
+ fprintf (stderr, "Can't create TIFF file %s.\n", filename);
+ goto failure;
+ }
+ if (read_image_striped(filename, 1, XSIZE * YSIZE, rowsperstrip,
+ compression, spp, bps, photometric,
+ sampleformat, planarconfig,
+ (const tdata_t) byte_array1, byte_array1_size) < 0) {
+ fprintf (stderr, "Can't read TIFF file %s.\n", filename);
+ goto failure;
+ }
+ unlink(filename);
+
+ /*
+ * Test one-channel image with different parameters.
+ */
+ rowsperstrip = 1;
+ spp = 1;
+ bps = 8;
+ photometric = PHOTOMETRIC_MINISBLACK;
+ sampleformat = SAMPLEFORMAT_UINT;
+ planarconfig = PLANARCONFIG_CONTIG;
+
+ if (create_image_striped(filename, XSIZE, YSIZE, rowsperstrip,
+ compression, spp, bps, photometric,
+ sampleformat, planarconfig,
+ (const tdata_t) byte_array1, byte_array1_size) < 0) {
+ fprintf (stderr, "Can't create TIFF file %s.\n", filename);
+ goto failure;
+ }
+ if (read_image_striped(filename, XSIZE, YSIZE, rowsperstrip,
+ compression, spp, bps, photometric,
+ sampleformat, planarconfig,
+ (const tdata_t) byte_array1, byte_array1_size) < 0) {
+ fprintf (stderr, "Can't read TIFF file %s.\n", filename);
+ goto failure;
+ }
+ unlink(filename);
+
+ rowsperstrip = YSIZE;
+ if (create_image_striped(filename, XSIZE, YSIZE, rowsperstrip,
+ compression, spp, bps, photometric,
+ sampleformat, planarconfig,
+ (const tdata_t) byte_array1, byte_array1_size) < 0) {
+ fprintf (stderr, "Can't create TIFF file %s.\n", filename);
+ goto failure;
+ }
+ if (read_image_striped(filename, XSIZE, YSIZE, rowsperstrip,
+ compression, spp, bps, photometric,
+ sampleformat, planarconfig,
+ (const tdata_t) byte_array1, byte_array1_size) < 0) {
+ fprintf (stderr, "Can't read TIFF file %s.\n", filename);
+ goto failure;
+ }
+ unlink(filename);
+
+ return 0;
+
+failure:
+ unlink(filename);
+ return 1;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/test/test_arrays.c b/tiff/test/test_arrays.c
new file mode 100644
index 0000000..49ef882
--- /dev/null
+++ b/tiff/test/test_arrays.c
@@ -0,0 +1,836 @@
+/* $Id: test_arrays.c,v 1.3.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Numerical arrays used to test libtiff's read/write functions.
+ */
+
+#include <stddef.h>
+
+#include "test_arrays.h"
+
+const unsigned char byte_array1[XSIZE * YSIZE]=
+{
+86, 84, 86, 90, 89, 85, 90, 78, 77, 79, 75, 77, 79, 86,
+87, 83, 82, 87, 89, 88, 86, 87, 88, 87, 81, 84, 85, 85,
+84, 86, 88, 91, 96, 95, 97, 95, 89,
+85, 82, 81, 88, 89, 85, 89, 83, 74, 79, 76, 77, 80, 87,
+87, 84, 84, 88, 90, 89, 87, 85, 87, 88, 83, 80, 82, 84,
+85, 87, 90, 95, 96, 95, 95, 92, 90,
+85, 81, 79, 84, 90, 87, 88, 88, 73, 79, 75, 76, 79, 88,
+88, 87, 85, 90, 92, 89, 88, 88, 87, 86, 84, 82, 82, 83,
+87, 89, 93, 94, 93, 93, 92, 92, 96,
+85, 82, 76, 80, 88, 89, 88, 89, 73, 80, 75, 75, 77, 89,
+92, 93, 91, 89, 94, 92, 90, 89, 88, 84, 84, 82, 82, 85,
+88, 91, 94, 93, 93, 89, 90, 96, 96,
+87, 83, 75, 77, 83, 89, 90, 90, 74, 78, 76, 76, 76, 84,
+94, 100, 89, 92, 94, 92, 90, 89, 90, 85, 84, 83, 83, 87,
+91, 92, 88, 92, 91, 88, 90, 97, 95,
+89, 83, 74, 77, 82, 84, 90, 92, 78, 72, 76, 75, 75, 81,
+95, 101, 95, 92, 95, 93, 90, 89, 90, 87, 86, 84, 86, 88,
+90, 90, 87, 90, 89, 90, 89, 98, 98,
+92, 84, 75, 76, 81, 81, 86, 91, 81, 72, 74, 74, 75, 81,
+104, 108, 93, 92, 95, 94, 88, 87, 89, 87, 85, 85, 88, 89,
+93, 91, 88, 88, 91, 88, 91, 106, 108,
+93, 89, 78, 75, 77, 80, 85, 86, 85, 73, 72, 73, 74, 79,
+102, 101, 88, 92, 93, 91, 87, 87, 86, 87, 85, 86, 88, 89,
+94, 94, 90, 88, 85, 86, 98, 109, 113,
+92, 93, 83, 76, 74, 79, 84, 85, 81, 75, 72, 73, 74, 79,
+105, 86, 86, 92, 96, 98, 104, 86, 85, 85, 85, 88, 90, 90,
+93, 92, 88, 87, 86, 89, 97, 110, 109,
+92, 93, 89, 78, 79, 78, 89, 84, 75, 76, 73, 72, 73, 78,
+105, 83, 82, 88, 83, 107, 95, 84, 85, 84, 86, 87, 90, 91,
+92, 90, 88, 87, 89, 90, 91, 99, 107,
+96, 94, 91, 82, 84, 86, 91, 87, 75, 74, 73, 73, 73, 77,
+101, 86, 83, 89, 92, 99, 98, 86, 86, 87, 83, 84, 89, 89,
+92, 92, 92, 96, 96, 87, 91, 90, 98,
+96, 97, 94, 87, 88, 89, 92, 90, 79, 72, 73, 73, 74, 77,
+100, 92, 84, 86, 98, 100, 92, 87, 88, 88, 84, 83, 87, 89,
+91, 94, 94, 96, 93, 87, 87, 84, 109,
+93, 92, 95, 92, 94, 93, 92, 91, 82, 72, 73, 74, 74, 76,
+95, 89, 85, 84, 102, 89, 85, 88, 94, 86, 82, 83, 82, 91,
+94, 97, 90, 92, 85, 90, 85, 79, 125,
+89, 96, 94, 90, 94, 95, 91, 91, 85, 76, 72, 73, 74, 75,
+88, 100, 83, 84, 84, 83, 85, 88, 90, 85, 84, 83, 84, 88,
+92, 93, 90, 89, 84, 90, 94, 79, 139,
+93, 97, 97, 93, 92, 95, 91, 90, 87, 81, 74, 73, 73, 74,
+85, 97, 95, 95, 89, 86, 86, 92, 87, 85, 84, 90, 86, 85,
+91, 87, 87, 86, 93, 124, 140, 106, 143,
+101, 95, 97, 97, 96, 95, 84, 88, 87, 82, 78, 73, 73, 74,
+82, 92, 104, 95, 88, 89, 87, 89, 86, 85, 86, 87, 87, 81,
+81, 83, 91, 106, 131, 153, 151, 123, 133,
+99, 101, 102, 99, 96, 90, 83, 82, 85, 84, 79, 76, 74, 74,
+78, 81, 89, 96, 90, 93, 88, 88, 86, 88, 89, 95, 89, 82,
+81, 85, 104, 118, 141, 160, 129, 137, 147,
+103, 104, 98, 99, 90, 88, 81, 76, 81, 83, 79, 77, 75, 75,
+75, 76, 80, 90, 94, 87, 86, 87, 92, 85, 85, 85, 87, 87,
+89, 91, 112, 115, 145, 154, 145, 141, 147,
+106, 103, 100, 99, 92, 82, 78, 75, 78, 81, 79, 77, 77, 78,
+78, 76, 77, 81, 89, 87, 84, 84, 90, 86, 85, 84, 80, 85,
+97, 104, 119, 119, 149, 147, 144, 146, 152,
+107, 105, 103, 100, 93, 83, 78, 74, 74, 79, 78, 77, 76, 78,
+80, 79, 76, 78, 83, 84, 81, 81, 84, 83, 82, 78, 78, 85,
+86, 97, 105, 114, 145, 146, 148, 147, 150,
+107, 105, 103, 97, 92, 84, 72, 72, 75, 77, 76, 75, 76, 79,
+80, 80, 77, 76, 82, 81, 80, 81, 80, 80, 80, 77, 74, 74,
+73, 77, 91, 110, 132, 141, 152, 152, 145,
+107, 105, 103, 96, 92, 86, 73, 71, 73, 75, 75, 76, 76, 78,
+80, 80, 80, 98, 80, 80, 82, 82, 80, 78, 76, 73, 71, 72,
+71, 74, 80, 108, 119, 136, 158, 142, 137,
+107, 104, 101, 97, 85, 87, 75, 70, 70, 74, 74, 75, 77, 78,
+80, 82, 110, 117, 110, 78, 81, 83, 81, 78, 76, 73, 71, 69,
+68, 71, 74, 95, 120, 138, 148, 143, 139
+};
+
+const size_t byte_array1_size = sizeof(byte_array1);
+
+const unsigned char byte_array2[YSIZE * XSIZE] =
+{
+77, 73, 76, 80, 79, 75, 82, 65, 62, 64, 59, 59, 61, 72,
+70, 67, 65, 70, 71, 70, 68, 66, 65, 67, 66, 66, 66, 66,
+66, 66, 66, 66, 66, 65, 63, 63, 62,
+75, 71, 71, 79, 81, 75, 81, 73, 59, 65, 60, 60, 64, 73,
+73, 68, 66, 70, 72, 71, 68, 66, 66, 67, 66, 66, 66, 67,
+67, 67, 66, 67, 66, 64, 63, 63, 63,
+76, 71, 66, 73, 81, 78, 80, 79, 59, 66, 60, 59, 62, 74,
+74, 71, 67, 70, 73, 71, 68, 66, 65, 65, 66, 66, 67, 67,
+67, 67, 67, 67, 66, 64, 64, 64, 64,
+76, 72, 64, 68, 79, 81, 80, 80, 59, 68, 60, 59, 60, 75,
+75, 73, 67, 68, 73, 72, 68, 66, 65, 63, 67, 67, 67, 67,
+68, 67, 67, 66, 65, 64, 65, 65, 65,
+79, 72, 63, 66, 73, 80, 83, 82, 60, 65, 61, 61, 60, 66,
+75, 75, 65, 70, 73, 72, 68, 66, 65, 64, 68, 67, 68, 68,
+68, 67, 67, 66, 65, 65, 65, 66, 65,
+81, 73, 62, 65, 72, 74, 82, 85, 66, 59, 62, 60, 60, 63,
+75, 76, 68, 69, 72, 72, 68, 66, 66, 65, 67, 68, 68, 68,
+68, 68, 66, 66, 64, 66, 65, 66, 66,
+84, 74, 64, 64, 70, 71, 78, 84, 70, 58, 60, 59, 59, 63,
+75, 80, 73, 67, 72, 72, 68, 66, 66, 65, 66, 68, 68, 68,
+68, 68, 66, 65, 65, 65, 66, 67, 68,
+87, 81, 66, 63, 65, 68, 76, 76, 75, 59, 58, 59, 59, 60,
+71, 92, 65, 64, 74, 72, 69, 67, 65, 65, 65, 68, 69, 68,
+69, 67, 65, 65, 65, 65, 67, 68, 69,
+86, 86, 73, 64, 62, 67, 75, 76, 70, 61, 58, 58, 59, 60,
+81, 68, 59, 63, 74, 90, 99, 67, 65, 65, 64, 67, 68, 68,
+68, 67, 65, 65, 66, 65, 66, 68, 68,
+85, 85, 80, 66, 67, 67, 81, 74, 62, 63, 59, 58, 58, 60,
+93, 61, 59, 59, 68, 115, 76, 67, 66, 64, 64, 66, 68, 68,
+68, 66, 65, 65, 66, 65, 64, 65, 69,
+90, 87, 83, 71, 74, 77, 83, 79, 63, 60, 59, 59, 58, 58,
+90, 61, 59, 59, 67, 80, 71, 68, 66, 64, 63, 63, 68, 68,
+68, 66, 65, 66, 67, 65, 64, 62, 87,
+91, 92, 86, 76, 78, 81, 85, 82, 67, 59, 59, 59, 59, 60,
+88, 72, 59, 60, 74, 80, 70, 67, 66, 64, 62, 60, 65, 68,
+67, 66, 65, 67, 66, 64, 62, 59, 111,
+84, 84, 87, 85, 87, 85, 84, 84, 72, 59, 59, 59, 59, 59,
+73, 71, 62, 59, 100, 70, 70, 67, 66, 64, 60, 58, 58, 67,
+68, 66, 65, 66, 64, 63, 59, 56, 131,
+80, 90, 87, 83, 88, 89, 84, 83, 76, 64, 59, 59, 59, 58,
+59, 97, 64, 62, 71, 68, 70, 73, 66, 63, 61, 58, 58, 62,
+67, 66, 64, 65, 63, 63, 61, 57, 149,
+86, 91, 92, 87, 85, 88, 83, 81, 78, 69, 61, 59, 59, 59,
+59, 61, 83, 72, 67, 67, 69, 69, 66, 64, 61, 72, 56, 57,
+64, 64, 64, 64, 65, 115, 150, 93, 151,
+97, 89, 91, 92, 89, 88, 74, 80, 78, 71, 65, 59, 58, 59,
+58, 59, 71, 72, 67, 70, 70, 69, 67, 64, 63, 66, 56, 54,
+57, 59, 64, 87, 139, 162, 160, 128, 141,
+94, 96, 97, 94, 89, 82, 71, 70, 76, 73, 67, 61, 59, 59,
+58, 59, 61, 71, 67, 75, 70, 68, 70, 65, 63, 63, 59, 56,
+54, 55, 90, 121, 149, 168, 138, 144, 157,
+99, 100, 93, 93, 82, 80, 70, 62, 70, 72, 67, 63, 60, 60,
+58, 58, 60, 68, 70, 70, 69, 68, 79, 68, 64, 62, 60, 59,
+57, 57, 88, 120, 151, 162, 154, 149, 155,
+103, 99, 95, 94, 84, 73, 67, 62, 65, 69, 67, 64, 63, 64,
+63, 59, 60, 65, 71, 69, 69, 67, 78, 65, 63, 61, 59, 61,
+60, 68, 100, 128, 155, 155, 152, 155, 164,
+104, 102, 99, 95, 86, 74, 67, 61, 61, 66, 65, 63, 63, 64,
+65, 63, 60, 63, 70, 69, 67, 67, 67, 65, 62, 60, 58, 57,
+62, 58, 71, 117, 150, 154, 157, 155, 163,
+104, 101, 99, 91, 84, 74, 59, 59, 62, 64, 63, 61, 62, 64,
+64, 64, 61, 60, 69, 68, 67, 69, 67, 65, 62, 59, 58, 57,
+57, 56, 59, 104, 137, 147, 159, 161, 158,
+104, 101, 99, 90, 85, 77, 60, 57, 60, 62, 62, 62, 63, 64,
+65, 65, 66, 100, 67, 67, 69, 69, 67, 65, 63, 60, 58, 56,
+54, 55, 56, 77, 122, 142, 166, 157, 150,
+104, 101, 97, 92, 77, 79, 64, 57, 57, 62, 62, 62, 64, 65,
+66, 65, 115, 138, 129, 64, 68, 70, 68, 66, 64, 60, 58, 56,
+53, 53, 56, 62, 115, 143, 157, 156, 159
+};
+
+const size_t byte_array2_size = sizeof(byte_array2);
+
+const unsigned char byte_array3[YSIZE * XSIZE] =
+{
+211, 221, 216, 201, 205, 216, 195, 236, 244, 237, 250, 250, 248, 218,
+223, 232, 236, 224, 221, 221, 227, 231, 232, 227, 229, 227, 227, 225,
+227, 225, 226, 226, 226, 228, 234, 234, 234, 216, 226, 228, 205, 200,
+214, 198, 215, 250, 233, 247, 250, 242, 219, 220, 229, 235, 225, 217,
+220, 227, 232, 230, 228, 229, 228, 227, 224, 225, 223, 226, 225, 226,
+230, 233, 233, 234, 213, 227, 237, 220, 200, 204, 202, 201, 248, 231,
+246, 250, 245, 214, 215, 223, 232, 225, 218, 218, 225, 230, 232, 231,
+229, 227, 225, 224, 223, 226, 224, 225, 228, 229, 230, 232, 231, 215,
+223, 242, 233, 206, 200, 201, 197, 250, 227, 250, 249, 248, 211, 212,
+216, 233, 229, 216, 218, 225, 230, 232, 237, 226, 224, 224, 223, 225,
+225, 224, 225, 228, 229, 231, 229, 231, 208, 220, 247, 238, 221, 202,
+194, 194, 245, 237, 247, 247, 249, 234, 210, 212, 237, 222, 219, 217,
+226, 229, 232, 235, 222, 222, 223, 223, 223, 224, 224, 227, 226, 229,
+229, 228, 231, 200, 221, 247, 239, 224, 217, 196, 189, 229, 248, 245,
+248, 250, 241, 210, 210, 230, 225, 218, 218, 224, 230, 230, 229, 224,
+222, 222, 222, 222, 223, 225, 226, 231, 226, 228, 229, 230, 191, 216,
+246, 245, 226, 228, 207, 191, 221, 251, 248, 249, 251, 245, 214, 214,
+233, 229, 217, 217, 224, 229, 230, 229, 225, 220, 223, 221, 222, 224,
+224, 227, 230, 227, 226, 229, 230, 187, 199, 238, 248, 242, 231, 213,
+211, 209, 246, 248, 251, 251, 250, 226, 215, 236, 237, 217, 215, 222,
+226, 229, 229, 227, 222, 222, 223, 222, 225, 227, 228, 226, 227, 228,
+228, 230, 188, 189, 221, 243, 247, 237, 215, 209, 223, 241, 248, 248,
+250, 248, 228, 234, 251, 239, 219, 210, 205, 224, 229, 228, 230, 221,
+223, 223, 222, 226, 229, 228, 224, 227, 229, 230, 232, 190, 190, 201,
+235, 236, 238, 198, 214, 243, 238, 248, 248, 250, 249, 215, 244, 250,
+250, 240, 168, 220, 224, 228, 230, 231, 226, 221, 224, 223, 226, 230,
+227, 226, 226, 230, 233, 234, 179, 185, 195, 224, 215, 210, 195, 204,
+239, 245, 250, 250, 252, 254, 216, 243, 249, 249, 233, 210, 215, 223,
+227, 230, 234, 234, 224, 223, 223, 227, 230, 226, 226, 228, 231, 235,
+212, 178, 174, 190, 211, 207, 199, 189, 194, 230, 250, 250, 250, 253,
+253, 222, 225, 250, 248, 218, 216, 217, 225, 226, 232, 239, 242, 229,
+223, 224, 229, 230, 225, 228, 230, 236, 241, 183, 194, 194, 185, 190,
+185, 190, 191, 191, 219, 250, 251, 250, 253, 254, 241, 225, 246, 249,
+198, 217, 220, 224, 225, 234, 241, 242, 246, 224, 223, 227, 229, 227,
+228, 234, 237, 245, 149, 203, 178, 182, 193, 185, 179, 191, 194, 211,
+236, 252, 252, 254, 254, 253, 192, 240, 244, 235, 224, 220, 229, 224,
+236, 239, 243, 244, 236, 224, 229, 230, 229, 231, 230, 233, 244, 128,
+188, 177, 171, 184, 191, 182, 196, 197, 208, 224, 247, 253, 255, 252,
+250, 248, 226, 216, 228, 230, 220, 220, 227, 234, 237, 231, 247, 244,
+231, 231, 229, 228, 229, 182, 128, 196, 118, 160, 182, 174, 172, 179,
+183, 216, 203, 206, 220, 236, 253, 254, 253, 253, 249, 225, 219, 232,
+230, 220, 224, 227, 233, 237, 234, 244, 250, 245, 240, 224, 212, 174,
+123, 124, 176, 127, 171, 163, 161, 167, 177, 198, 221, 228, 212, 215,
+233, 245, 252, 255, 253, 252, 251, 223, 231, 216, 222, 227, 231, 231,
+234, 227, 238, 245, 249, 244, 210, 177, 124, 129, 134, 124, 113, 156,
+155, 172, 168, 197, 201, 224, 247, 224, 219, 233, 242, 249, 250, 252,
+254, 252, 230, 230, 224, 224, 225, 225, 227, 232, 232, 235, 239, 239,
+241, 213, 178, 131, 128, 128, 120, 114, 149, 157, 165, 168, 191, 218,
+231, 246, 237, 226, 234, 241, 243, 239, 244, 252, 249, 237, 225, 226,
+224, 227, 220, 229, 235, 235, 239, 238, 236, 230, 204, 177, 125, 131,
+127, 117, 111, 146, 151, 158, 166, 187, 215, 230, 246, 246, 231, 238,
+243, 246, 243, 241, 244, 253, 245, 226, 226, 229, 229, 229, 231, 236,
+238, 241, 240, 241, 235, 224, 188, 134, 123, 127, 116, 116, 144, 151,
+158, 173, 190, 214, 251, 250, 243, 236, 242, 249, 246, 241, 241, 244,
+251, 251, 228, 230, 230, 226, 232, 231, 236, 241, 243, 244, 243, 243,
+235, 200, 150, 128, 122, 119, 117, 144, 151, 156, 176, 190, 207, 246,
+253, 244, 239, 244, 246, 244, 242, 240, 243, 249, 198, 239, 234, 226,
+226, 228, 234, 238, 241, 244, 245, 247, 250, 244, 219, 182, 138, 118,
+118, 116, 143, 150, 162, 173, 208, 205, 238, 253, 251, 241, 244, 244,
+242, 243, 238, 246, 193, 146, 173, 246, 231, 223, 230, 232, 236, 240,
+245, 247, 252, 252, 245, 233, 195, 138, 114, 118, 108
+};
+
+const size_t byte_array3_size = sizeof(byte_array3);
+
+const float array_float1[YSIZE * XSIZE] =
+{
+234.866, 229.404, 234.866, 245.790, 243.059, 232.135, 245.790, 213.018,
+210.287, 215.749, 204.825, 210.287, 215.749, 234.866, 237.597, 226.673,
+223.942, 237.597, 243.059, 240.328, 234.866, 237.597, 240.328, 237.597,
+221.211, 229.404, 232.135, 232.135, 229.404, 234.866, 240.328, 248.521,
+262.176, 259.445, 264.907, 259.445, 243.059,
+232.135, 223.942, 221.211, 240.328, 243.059, 232.135, 243.059, 226.673,
+202.094, 215.749, 207.556, 210.287, 218.480, 237.597, 237.597, 229.404,
+229.404, 240.328, 245.790, 243.059, 237.597, 232.135, 237.597, 240.328,
+226.673, 218.480, 223.942, 229.404, 232.135, 237.597, 245.790, 259.445,
+262.176, 259.445, 259.445, 251.252, 245.790,
+232.135, 221.211, 215.749, 229.404, 245.790, 237.597, 240.328, 240.328,
+199.363, 215.749, 204.825, 207.556, 215.749, 240.328, 240.328, 237.597,
+232.135, 245.790, 251.252, 243.059, 240.328, 240.328, 237.597, 234.866,
+229.404, 223.942, 223.942, 226.673, 237.597, 243.059, 253.983, 256.714,
+253.983, 253.983, 251.252, 251.252, 262.176,
+232.135, 223.942, 207.556, 218.480, 240.328, 243.059, 240.328, 243.059,
+199.363, 218.480, 204.825, 204.825, 210.287, 243.059, 251.252, 253.983,
+248.521, 243.059, 256.714, 251.252, 245.790, 243.059, 240.328, 229.404,
+229.404, 223.942, 223.942, 232.135, 240.328, 248.521, 256.714, 253.983,
+253.983, 243.059, 245.790, 262.176, 262.176,
+237.597, 226.673, 204.825, 210.287, 226.673, 243.059, 245.790, 245.790,
+202.094, 213.018, 207.556, 207.556, 207.556, 229.404, 256.714, 273.100,
+243.059, 251.252, 256.714, 251.252, 245.790, 243.059, 245.790, 232.135,
+229.404, 226.673, 226.673, 237.597, 248.521, 251.252, 240.328, 251.252,
+248.521, 240.328, 245.790, 264.907, 259.445,
+243.059, 226.673, 202.094, 210.287, 223.942, 229.404, 245.790, 251.252,
+213.018, 196.632, 207.556, 204.825, 204.825, 221.211, 259.445, 275.831,
+259.445, 251.252, 259.445, 253.983, 245.790, 243.059, 245.790, 237.597,
+234.866, 229.404, 234.866, 240.328, 245.790, 245.790, 237.597, 245.790,
+243.059, 245.790, 243.059, 267.638, 267.638,
+251.252, 229.404, 204.825, 207.556, 221.211, 221.211, 234.866, 248.521,
+221.211, 196.632, 202.094, 202.094, 204.825, 221.211, 284.024, 294.948,
+253.983, 251.252, 259.445, 256.714, 240.328, 237.597, 243.059, 237.597,
+232.135, 232.135, 240.328, 243.059, 253.983, 248.521, 240.328, 240.328,
+248.521, 240.328, 248.521, 289.486, 294.948,
+253.983, 243.059, 213.018, 204.825, 210.287, 218.480, 232.135, 234.866,
+232.135, 199.363, 196.632, 199.363, 202.094, 215.749, 278.562, 275.831,
+240.328, 251.252, 253.983, 248.521, 237.597, 237.597, 234.866, 237.597,
+232.135, 234.866, 240.328, 243.059, 256.714, 256.714, 245.790, 240.328,
+232.135, 234.866, 267.638, 297.679, 308.603,
+251.252, 253.983, 226.673, 207.556, 202.094, 215.749, 229.404, 232.135,
+221.211, 204.825, 196.632, 199.363, 202.094, 215.749, 286.755, 234.866,
+234.866, 251.252, 262.176, 267.638, 284.024, 234.866, 232.135, 232.135,
+232.135, 240.328, 245.790, 245.790, 253.983, 251.252, 240.328, 237.597,
+234.866, 243.059, 264.907, 300.410, 297.679,
+251.252, 253.983, 243.059, 213.018, 215.749, 213.018, 243.059, 229.404,
+204.825, 207.556, 199.363, 196.632, 199.363, 213.018, 286.755, 226.673,
+223.942, 240.328, 226.673, 292.217, 259.445, 229.404, 232.135, 229.404,
+234.866, 237.597, 245.790, 248.521, 251.252, 245.790, 240.328, 237.597,
+243.059, 245.790, 248.521, 270.369, 292.217,
+262.176, 256.714, 248.521, 223.942, 229.404, 234.866, 248.521, 237.597,
+204.825, 202.094, 199.363, 199.363, 199.363, 210.287, 275.831, 234.866,
+226.673, 243.059, 251.252, 270.369, 267.638, 234.866, 234.866, 237.597,
+226.673, 229.404, 243.059, 243.059, 251.252, 251.252, 251.252, 262.176,
+262.176, 237.597, 248.521, 245.790, 267.638,
+262.176, 264.907, 256.714, 237.597, 240.328, 243.059, 251.252, 245.790,
+215.749, 196.632, 199.363, 199.363, 202.094, 210.287, 273.100, 251.252,
+229.404, 234.866, 267.638, 273.100, 251.252, 237.597, 240.328, 240.328,
+229.404, 226.673, 237.597, 243.059, 248.521, 256.714, 256.714, 262.176,
+253.983, 237.597, 237.597, 229.404, 297.679,
+253.983, 251.252, 259.445, 251.252, 256.714, 253.983, 251.252, 248.521,
+223.942, 196.632, 199.363, 202.094, 202.094, 207.556, 259.445, 243.059,
+232.135, 229.404, 278.562, 243.059, 232.135, 240.328, 256.714, 234.866,
+223.942, 226.673, 223.942, 248.521, 256.714, 264.907, 245.790, 251.252,
+232.135, 245.790, 232.135, 215.749, 341.375,
+243.059, 262.176, 256.714, 245.790, 256.714, 259.445, 248.521, 248.521,
+232.135, 207.556, 196.632, 199.363, 202.094, 204.825, 240.328, 273.100,
+226.673, 229.404, 229.404, 226.673, 232.135, 240.328, 245.790, 232.135,
+229.404, 226.673, 229.404, 240.328, 251.252, 253.983, 245.790, 243.059,
+229.404, 245.790, 256.714, 215.749, 379.609,
+253.983, 264.907, 264.907, 253.983, 251.252, 259.445, 248.521, 245.790,
+237.597, 221.211, 202.094, 199.363, 199.363, 202.094, 232.135, 264.907,
+259.445, 259.445, 243.059, 234.866, 234.866, 251.252, 237.597, 232.135,
+229.404, 245.790, 234.866, 232.135, 248.521, 237.597, 237.597, 234.866,
+253.983, 338.644, 382.340, 289.486, 390.533,
+275.831, 259.445, 264.907, 264.907, 262.176, 259.445, 229.404, 240.328,
+237.597, 223.942, 213.018, 199.363, 199.363, 202.094, 223.942, 251.252,
+284.024, 259.445, 240.328, 243.059, 237.597, 243.059, 234.866, 232.135,
+234.866, 237.597, 237.597, 221.211, 221.211, 226.673, 248.521, 289.486,
+357.761, 417.843, 412.381, 335.913, 363.223,
+270.369, 275.831, 278.562, 270.369, 262.176, 245.790, 226.673, 223.942,
+232.135, 229.404, 215.749, 207.556, 202.094, 202.094, 213.018, 221.211,
+243.059, 262.176, 245.790, 253.983, 240.328, 240.328, 234.866, 240.328,
+243.059, 259.445, 243.059, 223.942, 221.211, 232.135, 284.024, 322.258,
+385.071, 436.960, 352.299, 374.147, 401.457,
+281.293, 284.024, 267.638, 270.369, 245.790, 240.328, 221.211, 207.556,
+221.211, 226.673, 215.749, 210.287, 204.825, 204.825, 204.825, 207.556,
+218.480, 245.790, 256.714, 237.597, 234.866, 237.597, 251.252, 232.135,
+232.135, 232.135, 237.597, 237.597, 243.059, 248.521, 305.872, 314.065,
+395.995, 420.574, 395.995, 385.071, 401.457,
+289.486, 281.293, 273.100, 270.369, 251.252, 223.942, 213.018, 204.825,
+213.018, 221.211, 215.749, 210.287, 210.287, 213.018, 213.018, 207.556,
+210.287, 221.211, 243.059, 237.597, 229.404, 229.404, 245.790, 234.866,
+232.135, 229.404, 218.480, 232.135, 264.907, 284.024, 324.989, 324.989,
+406.919, 401.457, 393.264, 398.726, 415.112,
+292.217, 286.755, 281.293, 273.100, 253.983, 226.673, 213.018, 202.094,
+202.094, 215.749, 213.018, 210.287, 207.556, 213.018, 218.480, 215.749,
+207.556, 213.018, 226.673, 229.404, 221.211, 221.211, 229.404, 226.673,
+223.942, 213.018, 213.018, 232.135, 234.866, 264.907, 286.755, 311.334,
+395.995, 398.726, 404.188, 401.457, 409.650,
+292.217, 286.755, 281.293, 264.907, 251.252, 229.404, 196.632, 196.632,
+204.825, 210.287, 207.556, 204.825, 207.556, 215.749, 218.480, 218.480,
+210.287, 207.556, 223.942, 221.211, 218.480, 221.211, 218.480, 218.480,
+218.480, 210.287, 202.094, 202.094, 199.363, 210.287, 248.521, 300.410,
+360.492, 385.071, 415.112, 415.112, 395.995,
+292.217, 286.755, 281.293, 262.176, 251.252, 234.866, 199.363, 193.901,
+199.363, 204.825, 204.825, 207.556, 207.556, 213.018, 218.480, 218.480,
+218.480, 267.638, 218.480, 218.480, 223.942, 223.942, 218.480, 213.018,
+207.556, 199.363, 193.901, 196.632, 193.901, 202.094, 218.480, 294.948,
+324.989, 371.416, 431.498, 387.802, 374.147,
+292.217, 284.024, 275.831, 264.907, 232.135, 237.597, 204.825, 191.170,
+191.170, 202.094, 202.094, 204.825, 210.287, 213.018, 218.480, 223.942,
+300.410, 319.527, 300.410, 213.018, 221.211, 226.673, 221.211, 213.018,
+207.556, 199.363, 193.901, 188.439, 185.708, 193.901, 202.094, 259.445,
+327.720, 376.878, 404.188, 390.533, 379.609
+};
+
+const size_t array_float1_size = sizeof(array_float1);
+
+const float array_float2[YSIZE * XSIZE] =
+{
+210.287, 199.363, 207.556, 218.480, 215.749, 204.825, 223.942, 177.515,
+169.322, 174.784, 161.129, 161.129, 166.591, 196.632, 191.170, 182.977,
+177.515, 191.170, 193.901, 191.170, 185.708, 180.246, 177.515, 182.977,
+180.246, 180.246, 180.246, 180.246, 180.246, 180.246, 180.246, 180.246,
+180.246, 177.515, 172.053, 172.053, 169.322,
+204.825, 193.901, 193.901, 215.749, 221.211, 204.825, 221.211, 199.363,
+161.129, 177.515, 163.860, 163.860, 174.784, 199.363, 199.363, 185.708,
+180.246, 191.170, 196.632, 193.901, 185.708, 180.246, 180.246, 182.977,
+180.246, 180.246, 180.246, 182.977, 182.977, 182.977, 180.246, 182.977,
+180.246, 174.784, 172.053, 172.053, 172.053,
+207.556, 193.901, 180.246, 199.363, 221.211, 213.018, 218.480, 215.749,
+161.129, 180.246, 163.860, 161.129, 169.322, 202.094, 202.094, 193.901,
+182.977, 191.170, 199.363, 193.901, 185.708, 180.246, 177.515, 177.515,
+180.246, 180.246, 182.977, 182.977, 182.977, 182.977, 182.977, 182.977,
+180.246, 174.784, 174.784, 174.784, 174.784,
+207.556, 196.632, 174.784, 185.708, 215.749, 221.211, 218.480, 218.480,
+161.129, 185.708, 163.860, 161.129, 163.860, 204.825, 204.825, 199.363,
+182.977, 185.708, 199.363, 196.632, 185.708, 180.246, 177.515, 172.053,
+182.977, 182.977, 182.977, 182.977, 185.708, 182.977, 182.977, 180.246,
+177.515, 174.784, 177.515, 177.515, 177.515,
+215.749, 196.632, 172.053, 180.246, 199.363, 218.480, 226.673, 223.942,
+163.860, 177.515, 166.591, 166.591, 163.860, 180.246, 204.825, 204.825,
+177.515, 191.170, 199.363, 196.632, 185.708, 180.246, 177.515, 174.784,
+185.708, 182.977, 185.708, 185.708, 185.708, 182.977, 182.977, 180.246,
+177.515, 177.515, 177.515, 180.246, 177.515,
+221.211, 199.363, 169.322, 177.515, 196.632, 202.094, 223.942, 232.135,
+180.246, 161.129, 169.322, 163.860, 163.860, 172.053, 204.825, 207.556,
+185.708, 188.439, 196.632, 196.632, 185.708, 180.246, 180.246, 177.515,
+182.977, 185.708, 185.708, 185.708, 185.708, 185.708, 180.246, 180.246,
+174.784, 180.246, 177.515, 180.246, 180.246,
+229.404, 202.094, 174.784, 174.784, 191.170, 193.901, 213.018, 229.404,
+191.170, 158.398, 163.860, 161.129, 161.129, 172.053, 204.825, 218.480,
+199.363, 182.977, 196.632, 196.632, 185.708, 180.246, 180.246, 177.515,
+180.246, 185.708, 185.708, 185.708, 185.708, 185.708, 180.246, 177.515,
+177.515, 177.515, 180.246, 182.977, 185.708,
+237.597, 221.211, 180.246, 172.053, 177.515, 185.708, 207.556, 207.556,
+204.825, 161.129, 158.398, 161.129, 161.129, 163.860, 193.901, 251.252,
+177.515, 174.784, 202.094, 196.632, 188.439, 182.977, 177.515, 177.515,
+177.515, 185.708, 188.439, 185.708, 188.439, 182.977, 177.515, 177.515,
+177.515, 177.515, 182.977, 185.708, 188.439,
+234.866, 234.866, 199.363, 174.784, 169.322, 182.977, 204.825, 207.556,
+191.170, 166.591, 158.398, 158.398, 161.129, 163.860, 221.211, 185.708,
+161.129, 172.053, 202.094, 245.790, 270.369, 182.977, 177.515, 177.515,
+174.784, 182.977, 185.708, 185.708, 185.708, 182.977, 177.515, 177.515,
+180.246, 177.515, 180.246, 185.708, 185.708,
+232.135, 232.135, 218.480, 180.246, 182.977, 182.977, 221.211, 202.094,
+169.322, 172.053, 161.129, 158.398, 158.398, 163.860, 253.983, 166.591,
+161.129, 161.129, 185.708, 314.065, 207.556, 182.977, 180.246, 174.784,
+174.784, 180.246, 185.708, 185.708, 185.708, 180.246, 177.515, 177.515,
+180.246, 177.515, 174.784, 177.515, 188.439,
+245.790, 237.597, 226.673, 193.901, 202.094, 210.287, 226.673, 215.749,
+172.053, 163.860, 161.129, 161.129, 158.398, 158.398, 245.790, 166.591,
+161.129, 161.129, 182.977, 218.480, 193.901, 185.708, 180.246, 174.784,
+172.053, 172.053, 185.708, 185.708, 185.708, 180.246, 177.515, 180.246,
+182.977, 177.515, 174.784, 169.322, 237.597,
+248.521, 251.252, 234.866, 207.556, 213.018, 221.211, 232.135, 223.942,
+182.977, 161.129, 161.129, 161.129, 161.129, 163.860, 240.328, 196.632,
+161.129, 163.860, 202.094, 218.480, 191.170, 182.977, 180.246, 174.784,
+169.322, 163.860, 177.515, 185.708, 182.977, 180.246, 177.515, 182.977,
+180.246, 174.784, 169.322, 161.129, 303.141,
+229.404, 229.404, 237.597, 232.135, 237.597, 232.135, 229.404, 229.404,
+196.632, 161.129, 161.129, 161.129, 161.129, 161.129, 199.363, 193.901,
+169.322, 161.129, 273.100, 191.170, 191.170, 182.977, 180.246, 174.784,
+163.860, 158.398, 158.398, 182.977, 185.708, 180.246, 177.515, 180.246,
+174.784, 172.053, 161.129, 152.936, 357.761,
+218.480, 245.790, 237.597, 226.673, 240.328, 243.059, 229.404, 226.673,
+207.556, 174.784, 161.129, 161.129, 161.129, 158.398, 161.129, 264.907,
+174.784, 169.322, 193.901, 185.708, 191.170, 199.363, 180.246, 172.053,
+166.591, 158.398, 158.398, 169.322, 182.977, 180.246, 174.784, 177.515,
+172.053, 172.053, 166.591, 155.667, 406.919,
+234.866, 248.521, 251.252, 237.597, 232.135, 240.328, 226.673, 221.211,
+213.018, 188.439, 166.591, 161.129, 161.129, 161.129, 161.129, 166.591,
+226.673, 196.632, 182.977, 182.977, 188.439, 188.439, 180.246, 174.784,
+166.591, 196.632, 152.936, 155.667, 174.784, 174.784, 174.784, 174.784,
+177.515, 314.065, 409.650, 253.983, 412.381,
+264.907, 243.059, 248.521, 251.252, 243.059, 240.328, 202.094, 218.480,
+213.018, 193.901, 177.515, 161.129, 158.398, 161.129, 158.398, 161.129,
+193.901, 196.632, 182.977, 191.170, 191.170, 188.439, 182.977, 174.784,
+172.053, 180.246, 152.936, 147.474, 155.667, 161.129, 174.784, 237.597,
+379.609, 442.422, 436.960, 349.568, 385.071,
+256.714, 262.176, 264.907, 256.714, 243.059, 223.942, 193.901, 191.170,
+207.556, 199.363, 182.977, 166.591, 161.129, 161.129, 158.398, 161.129,
+166.591, 193.901, 182.977, 204.825, 191.170, 185.708, 191.170, 177.515,
+172.053, 172.053, 161.129, 152.936, 147.474, 150.205, 245.790, 330.451,
+406.919, 458.808, 376.878, 393.264, 428.767,
+270.369, 273.100, 253.983, 253.983, 223.942, 218.480, 191.170, 169.322,
+191.170, 196.632, 182.977, 172.053, 163.860, 163.860, 158.398, 158.398,
+163.860, 185.708, 191.170, 191.170, 188.439, 185.708, 215.749, 185.708,
+174.784, 169.322, 163.860, 161.129, 155.667, 155.667, 240.328, 327.720,
+412.381, 442.422, 420.574, 406.919, 423.305,
+281.293, 270.369, 259.445, 256.714, 229.404, 199.363, 182.977, 169.322,
+177.515, 188.439, 182.977, 174.784, 172.053, 174.784, 172.053, 161.129,
+163.860, 177.515, 193.901, 188.439, 188.439, 182.977, 213.018, 177.515,
+172.053, 166.591, 161.129, 166.591, 163.860, 185.708, 273.100, 349.568,
+423.305, 423.305, 415.112, 423.305, 447.884,
+284.024, 278.562, 270.369, 259.445, 234.866, 202.094, 182.977, 166.591,
+166.591, 180.246, 177.515, 172.053, 172.053, 174.784, 177.515, 172.053,
+163.860, 172.053, 191.170, 188.439, 182.977, 182.977, 182.977, 177.515,
+169.322, 163.860, 158.398, 155.667, 169.322, 158.398, 193.901, 319.527,
+409.650, 420.574, 428.767, 423.305, 445.153,
+284.024, 275.831, 270.369, 248.521, 229.404, 202.094, 161.129, 161.129,
+169.322, 174.784, 172.053, 166.591, 169.322, 174.784, 174.784, 174.784,
+166.591, 163.860, 188.439, 185.708, 182.977, 188.439, 182.977, 177.515,
+169.322, 161.129, 158.398, 155.667, 155.667, 152.936, 161.129, 284.024,
+374.147, 401.457, 434.229, 439.691, 431.498,
+284.024, 275.831, 270.369, 245.790, 232.135, 210.287, 163.860, 155.667,
+163.860, 169.322, 169.322, 169.322, 172.053, 174.784, 177.515, 177.515,
+180.246, 273.100, 182.977, 182.977, 188.439, 188.439, 182.977, 177.515,
+172.053, 163.860, 158.398, 152.936, 147.474, 150.205, 152.936, 210.287,
+333.182, 387.802, 453.346, 428.767, 409.650,
+284.024, 275.831, 264.907, 251.252, 210.287, 215.749, 174.784, 155.667,
+155.667, 169.322, 169.322, 169.322, 174.784, 177.515, 180.246, 177.515,
+314.065, 376.878, 352.299, 174.784, 185.708, 191.170, 185.708, 180.246,
+174.784, 163.860, 158.398, 152.936, 144.743, 144.743, 152.936, 169.322,
+314.065, 390.533, 428.767, 426.036, 434.229
+};
+
+const size_t array_float2_size = sizeof(array_float2);
+
+const double array_double1[YSIZE * XSIZE] =
+{
+148.914762, 145.451628, 148.914762, 155.841030, 154.109463, 147.183195,
+155.841030, 135.062226, 133.330659, 136.793793, 129.867525, 133.330659,
+136.793793, 148.914762, 150.646329, 143.720061, 141.988494, 150.646329,
+154.109463, 152.377896, 148.914762, 150.646329, 152.377896, 150.646329,
+140.256927, 145.451628, 147.183195, 147.183195, 145.451628, 148.914762,
+152.377896, 157.572597, 166.230432, 164.498865, 167.961999, 164.498865,
+154.109463,
+147.183195, 141.988494, 140.256927, 152.377896, 154.109463, 147.183195,
+154.109463, 143.720061, 128.135958, 136.793793, 131.599092, 133.330659,
+138.525360, 150.646329, 150.646329, 145.451628, 145.451628, 152.377896,
+155.841030, 154.109463, 150.646329, 147.183195, 150.646329, 152.377896,
+143.720061, 138.525360, 141.988494, 145.451628, 147.183195, 150.646329,
+155.841030, 164.498865, 166.230432, 164.498865, 164.498865, 159.304164,
+155.841030,
+147.183195, 140.256927, 136.793793, 145.451628, 155.841030, 150.646329,
+152.377896, 152.377896, 126.404391, 136.793793, 129.867525, 131.599092,
+136.793793, 152.377896, 152.377896, 150.646329, 147.183195, 155.841030,
+159.304164, 154.109463, 152.377896, 152.377896, 150.646329, 148.914762,
+145.451628, 141.988494, 141.988494, 143.720061, 150.646329, 154.109463,
+161.035731, 162.767298, 161.035731, 161.035731, 159.304164, 159.304164,
+166.230432,
+147.183195, 141.988494, 131.599092, 138.525360, 152.377896, 154.109463,
+152.377896, 154.109463, 126.404391, 138.525360, 129.867525, 129.867525,
+133.330659, 154.109463, 159.304164, 161.035731, 157.572597, 154.109463,
+162.767298, 159.304164, 155.841030, 154.109463, 152.377896, 145.451628,
+145.451628, 141.988494, 141.988494, 147.183195, 152.377896, 157.572597,
+162.767298, 161.035731, 161.035731, 154.109463, 155.841030, 166.230432,
+166.230432,
+150.646329, 143.720061, 129.867525, 133.330659, 143.720061, 154.109463,
+155.841030, 155.841030, 128.135958, 135.062226, 131.599092, 131.599092,
+131.599092, 145.451628, 162.767298, 173.156700, 154.109463, 159.304164,
+162.767298, 159.304164, 155.841030, 154.109463, 155.841030, 147.183195,
+145.451628, 143.720061, 143.720061, 150.646329, 157.572597, 159.304164,
+152.377896, 159.304164, 157.572597, 152.377896, 155.841030, 167.961999,
+164.498865,
+154.109463, 143.720061, 128.135958, 133.330659, 141.988494, 145.451628,
+155.841030, 159.304164, 135.062226, 124.672824, 131.599092, 129.867525,
+129.867525, 140.256927, 164.498865, 174.888267, 164.498865, 159.304164,
+164.498865, 161.035731, 155.841030, 154.109463, 155.841030, 150.646329,
+148.914762, 145.451628, 148.914762, 152.377896, 155.841030, 155.841030,
+150.646329, 155.841030, 154.109463, 155.841030, 154.109463, 169.693566,
+169.693566,
+159.304164, 145.451628, 129.867525, 131.599092, 140.256927, 140.256927,
+148.914762, 157.572597, 140.256927, 124.672824, 128.135958, 128.135958,
+129.867525, 140.256927, 180.082968, 187.009236, 161.035731, 159.304164,
+164.498865, 162.767298, 152.377896, 150.646329, 154.109463, 150.646329,
+147.183195, 147.183195, 152.377896, 154.109463, 161.035731, 157.572597,
+152.377896, 152.377896, 157.572597, 152.377896, 157.572597, 183.546102,
+187.009236,
+161.035731, 154.109463, 135.062226, 129.867525, 133.330659, 138.525360,
+147.183195, 148.914762, 147.183195, 126.404391, 124.672824, 126.404391,
+128.135958, 136.793793, 176.619834, 174.888267, 152.377896, 159.304164,
+161.035731, 157.572597, 150.646329, 150.646329, 148.914762, 150.646329,
+147.183195, 148.914762, 152.377896, 154.109463, 162.767298, 162.767298,
+155.841030, 152.377896, 147.183195, 148.914762, 169.693566, 188.740803,
+195.667071,
+159.304164, 161.035731, 143.720061, 131.599092, 128.135958, 136.793793,
+145.451628, 147.183195, 140.256927, 129.867525, 124.672824, 126.404391,
+128.135958, 136.793793, 181.814535, 148.914762, 148.914762, 159.304164,
+166.230432, 169.693566, 180.082968, 148.914762, 147.183195, 147.183195,
+147.183195, 152.377896, 155.841030, 155.841030, 161.035731, 159.304164,
+152.377896, 150.646329, 148.914762, 154.109463, 167.961999, 190.472370,
+188.740803,
+159.304164, 161.035731, 154.109463, 135.062226, 136.793793, 135.062226,
+154.109463, 145.451628, 129.867525, 131.599092, 126.404391, 124.672824,
+126.404391, 135.062226, 181.814535, 143.720061, 141.988494, 152.377896,
+143.720061, 185.277669, 164.498865, 145.451628, 147.183195, 145.451628,
+148.914762, 150.646329, 155.841030, 157.572597, 159.304164, 155.841030,
+152.377896, 150.646329, 154.109463, 155.841030, 157.572597, 171.425133,
+185.277669,
+166.230432, 162.767298, 157.572597, 141.988494, 145.451628, 148.914762,
+157.572597, 150.646329, 129.867525, 128.135958, 126.404391, 126.404391,
+126.404391, 133.330659, 174.888267, 148.914762, 143.720061, 154.109463,
+159.304164, 171.425133, 169.693566, 148.914762, 148.914762, 150.646329,
+143.720061, 145.451628, 154.109463, 154.109463, 159.304164, 159.304164,
+159.304164, 166.230432, 166.230432, 150.646329, 157.572597, 155.841030,
+169.693566,
+166.230432, 167.961999, 162.767298, 150.646329, 152.377896, 154.109463,
+159.304164, 155.841030, 136.793793, 124.672824, 126.404391, 126.404391,
+128.135958, 133.330659, 173.156700, 159.304164, 145.451628, 148.914762,
+169.693566, 173.156700, 159.304164, 150.646329, 152.377896, 152.377896,
+145.451628, 143.720061, 150.646329, 154.109463, 157.572597, 162.767298,
+162.767298, 166.230432, 161.035731, 150.646329, 150.646329, 145.451628,
+188.740803,
+161.035731, 159.304164, 164.498865, 159.304164, 162.767298, 161.035731,
+159.304164, 157.572597, 141.988494, 124.672824, 126.404391, 128.135958,
+128.135958, 131.599092, 164.498865, 154.109463, 147.183195, 145.451628,
+176.619834, 154.109463, 147.183195, 152.377896, 162.767298, 148.914762,
+141.988494, 143.720061, 141.988494, 157.572597, 162.767298, 167.961999,
+155.841030, 159.304164, 147.183195, 155.841030, 147.183195, 136.793793,
+216.445875,
+154.109463, 166.230432, 162.767298, 155.841030, 162.767298, 164.498865,
+157.572597, 157.572597, 147.183195, 131.599092, 124.672824, 126.404391,
+128.135958, 129.867525, 152.377896, 173.156700, 143.720061, 145.451628,
+145.451628, 143.720061, 147.183195, 152.377896, 155.841030, 147.183195,
+145.451628, 143.720061, 145.451628, 152.377896, 159.304164, 161.035731,
+155.841030, 154.109463, 145.451628, 155.841030, 162.767298, 136.793793,
+240.687813,
+161.035731, 167.961999, 167.961999, 161.035731, 159.304164, 164.498865,
+157.572597, 155.841030, 150.646329, 140.256927, 128.135958, 126.404391,
+126.404391, 128.135958, 147.183195, 167.961999, 164.498865, 164.498865,
+154.109463, 148.914762, 148.914762, 159.304164, 150.646329, 147.183195,
+145.451628, 155.841030, 148.914762, 147.183195, 157.572597, 150.646329,
+150.646329, 148.914762, 161.035731, 214.714308, 242.419380, 183.546102,
+247.614081,
+174.888267, 164.498865, 167.961999, 167.961999, 166.230432, 164.498865,
+145.451628, 152.377896, 150.646329, 141.988494, 135.062226, 126.404391,
+126.404391, 128.135958, 141.988494, 159.304164, 180.082968, 164.498865,
+152.377896, 154.109463, 150.646329, 154.109463, 148.914762, 147.183195,
+148.914762, 150.646329, 150.646329, 140.256927, 140.256927, 143.720061,
+157.572597, 183.546102, 226.835277, 264.929751, 261.466617, 212.982741,
+230.298411,
+171.425133, 174.888267, 176.619834, 171.425133, 166.230432, 155.841030,
+143.720061, 141.988494, 147.183195, 145.451628, 136.793793, 131.599092,
+128.135958, 128.135958, 135.062226, 140.256927, 154.109463, 166.230432,
+155.841030, 161.035731, 152.377896, 152.377896, 148.914762, 152.377896,
+154.109463, 164.498865, 154.109463, 141.988494, 140.256927, 147.183195,
+180.082968, 204.324906, 244.150947, 277.050720, 223.372143, 237.224679,
+254.540349,
+178.351401, 180.082968, 169.693566, 171.425133, 155.841030, 152.377896,
+140.256927, 131.599092, 140.256927, 143.720061, 136.793793, 133.330659,
+129.867525, 129.867525, 129.867525, 131.599092, 138.525360, 155.841030,
+162.767298, 150.646329, 148.914762, 150.646329, 159.304164, 147.183195,
+147.183195, 147.183195, 150.646329, 150.646329, 154.109463, 157.572597,
+193.935504, 199.130205, 251.077215, 266.661318, 251.077215, 244.150947,
+254.540349,
+183.546102, 178.351401, 173.156700, 171.425133, 159.304164, 141.988494,
+135.062226, 129.867525, 135.062226, 140.256927, 136.793793, 133.330659,
+133.330659, 135.062226, 135.062226, 131.599092, 133.330659, 140.256927,
+154.109463, 150.646329, 145.451628, 145.451628, 155.841030, 148.914762,
+147.183195, 145.451628, 138.525360, 147.183195, 167.961999, 180.082968,
+206.056473, 206.056473, 258.003483, 254.540349, 249.345648, 252.808782,
+263.198184,
+185.277669, 181.814535, 178.351401, 173.156700, 161.035731, 143.720061,
+135.062226, 128.135958, 128.135958, 136.793793, 135.062226, 133.330659,
+131.599092, 135.062226, 138.525360, 136.793793, 131.599092, 135.062226,
+143.720061, 145.451628, 140.256927, 140.256927, 145.451628, 143.720061,
+141.988494, 135.062226, 135.062226, 147.183195, 148.914762, 167.961999,
+181.814535, 197.398638, 251.077215, 252.808782, 256.271916, 254.540349,
+259.735050,
+185.277669, 181.814535, 178.351401, 167.961999, 159.304164, 145.451628,
+124.672824, 124.672824, 129.867525, 133.330659, 131.599092, 129.867525,
+131.599092, 136.793793, 138.525360, 138.525360, 133.330659, 131.599092,
+141.988494, 140.256927, 138.525360, 140.256927, 138.525360, 138.525360,
+138.525360, 133.330659, 128.135958, 128.135958, 126.404391, 133.330659,
+157.572597, 190.472370, 228.566844, 244.150947, 263.198184, 263.198184,
+251.077215,
+185.277669, 181.814535, 178.351401, 166.230432, 159.304164, 148.914762,
+126.404391, 122.941257, 126.404391, 129.867525, 129.867525, 131.599092,
+131.599092, 135.062226, 138.525360, 138.525360, 138.525360, 169.693566,
+138.525360, 138.525360, 141.988494, 141.988494, 138.525360, 135.062226,
+131.599092, 126.404391, 122.941257, 124.672824, 122.941257, 128.135958,
+138.525360, 187.009236, 206.056473, 235.493112, 273.587586, 245.882514,
+237.224679,
+185.277669, 180.082968, 174.888267, 167.961999, 147.183195, 150.646329,
+129.867525, 121.209690, 121.209690, 128.135958, 128.135958, 129.867525,
+133.330659, 135.062226, 138.525360, 141.988494, 190.472370, 202.593339,
+190.472370, 135.062226, 140.256927, 143.720061, 140.256927, 135.062226,
+131.599092, 126.404391, 122.941257, 119.478123, 117.746556, 122.941257,
+128.135958, 164.498865, 207.788040, 238.956246, 256.271916, 247.614081,
+240.687813
+};
+
+const size_t array_double1_size = sizeof(array_double1);
+
+const double array_double2[YSIZE * XSIZE] =
+{
+133.330659, 126.404391, 131.599092, 138.525360, 136.793793, 129.867525,
+141.988494, 112.551855, 107.357154, 110.820288, 102.162453, 102.162453,
+105.625587, 124.672824, 121.209690, 116.014989, 112.551855, 121.209690,
+122.941257, 121.209690, 117.746556, 114.283422, 112.551855, 116.014989,
+114.283422, 114.283422, 114.283422, 114.283422, 114.283422, 114.283422,
+114.283422, 114.283422, 114.283422, 112.551855, 109.088721, 109.088721,
+107.357154,
+129.867525, 122.941257, 122.941257, 136.793793, 140.256927, 129.867525,
+140.256927, 126.404391, 102.162453, 112.551855, 103.894020, 103.894020,
+110.820288, 126.404391, 126.404391, 117.746556, 114.283422, 121.209690,
+124.672824, 122.941257, 117.746556, 114.283422, 114.283422, 116.014989,
+114.283422, 114.283422, 114.283422, 116.014989, 116.014989, 116.014989,
+114.283422, 116.014989, 114.283422, 110.820288, 109.088721, 109.088721,
+109.088721,
+131.599092, 122.941257, 114.283422, 126.404391, 140.256927, 135.062226,
+138.525360, 136.793793, 102.162453, 114.283422, 103.894020, 102.162453,
+107.357154, 128.135958, 128.135958, 122.941257, 116.014989, 121.209690,
+126.404391, 122.941257, 117.746556, 114.283422, 112.551855, 112.551855,
+114.283422, 114.283422, 116.014989, 116.014989, 116.014989, 116.014989,
+116.014989, 116.014989, 114.283422, 110.820288, 110.820288, 110.820288,
+110.820288,
+131.599092, 124.672824, 110.820288, 117.746556, 136.793793, 140.256927,
+138.525360, 138.525360, 102.162453, 117.746556, 103.894020, 102.162453,
+103.894020, 129.867525, 129.867525, 126.404391, 116.014989, 117.746556,
+126.404391, 124.672824, 117.746556, 114.283422, 112.551855, 109.088721,
+116.014989, 116.014989, 116.014989, 116.014989, 117.746556, 116.014989,
+116.014989, 114.283422, 112.551855, 110.820288, 112.551855, 112.551855,
+112.551855,
+136.793793, 124.672824, 109.088721, 114.283422, 126.404391, 138.525360,
+143.720061, 141.988494, 103.894020, 112.551855, 105.625587, 105.625587,
+103.894020, 114.283422, 129.867525, 129.867525, 112.551855, 121.209690,
+126.404391, 124.672824, 117.746556, 114.283422, 112.551855, 110.820288,
+117.746556, 116.014989, 117.746556, 117.746556, 117.746556, 116.014989,
+116.014989, 114.283422, 112.551855, 112.551855, 112.551855, 114.283422,
+112.551855,
+140.256927, 126.404391, 107.357154, 112.551855, 124.672824, 128.135958,
+141.988494, 147.183195, 114.283422, 102.162453, 107.357154, 103.894020,
+103.894020, 109.088721, 129.867525, 131.599092, 117.746556, 119.478123,
+124.672824, 124.672824, 117.746556, 114.283422, 114.283422, 112.551855,
+116.014989, 117.746556, 117.746556, 117.746556, 117.746556, 117.746556,
+114.283422, 114.283422, 110.820288, 114.283422, 112.551855, 114.283422,
+114.283422,
+145.451628, 128.135958, 110.820288, 110.820288, 121.209690, 122.941257,
+135.062226, 145.451628, 121.209690, 100.430886, 103.894020, 102.162453,
+102.162453, 109.088721, 129.867525, 138.525360, 126.404391, 116.014989,
+124.672824, 124.672824, 117.746556, 114.283422, 114.283422, 112.551855,
+114.283422, 117.746556, 117.746556, 117.746556, 117.746556, 117.746556,
+114.283422, 112.551855, 112.551855, 112.551855, 114.283422, 116.014989,
+117.746556,
+150.646329, 140.256927, 114.283422, 109.088721, 112.551855, 117.746556,
+131.599092, 131.599092, 129.867525, 102.162453, 100.430886, 102.162453,
+102.162453, 103.894020, 122.941257, 159.304164, 112.551855, 110.820288,
+128.135958, 124.672824, 119.478123, 116.014989, 112.551855, 112.551855,
+112.551855, 117.746556, 119.478123, 117.746556, 119.478123, 116.014989,
+112.551855, 112.551855, 112.551855, 112.551855, 116.014989, 117.746556,
+119.478123,
+148.914762, 148.914762, 126.404391, 110.820288, 107.357154, 116.014989,
+129.867525, 131.599092, 121.209690, 105.625587, 100.430886, 100.430886,
+102.162453, 103.894020, 140.256927, 117.746556, 102.162453, 109.088721,
+128.135958, 155.841030, 171.425133, 116.014989, 112.551855, 112.551855,
+110.820288, 116.014989, 117.746556, 117.746556, 117.746556, 116.014989,
+112.551855, 112.551855, 114.283422, 112.551855, 114.283422, 117.746556,
+117.746556,
+147.183195, 147.183195, 138.525360, 114.283422, 116.014989, 116.014989,
+140.256927, 128.135958, 107.357154, 109.088721, 102.162453, 100.430886,
+100.430886, 103.894020, 161.035731, 105.625587, 102.162453, 102.162453,
+117.746556, 199.130205, 131.599092, 116.014989, 114.283422, 110.820288,
+110.820288, 114.283422, 117.746556, 117.746556, 117.746556, 114.283422,
+112.551855, 112.551855, 114.283422, 112.551855, 110.820288, 112.551855,
+119.478123,
+155.841030, 150.646329, 143.720061, 122.941257, 128.135958, 133.330659,
+143.720061, 136.793793, 109.088721, 103.894020, 102.162453, 102.162453,
+100.430886, 100.430886, 155.841030, 105.625587, 102.162453, 102.162453,
+116.014989, 138.525360, 122.941257, 117.746556, 114.283422, 110.820288,
+109.088721, 109.088721, 117.746556, 117.746556, 117.746556, 114.283422,
+112.551855, 114.283422, 116.014989, 112.551855, 110.820288, 107.357154,
+150.646329,
+157.572597, 159.304164, 148.914762, 131.599092, 135.062226, 140.256927,
+147.183195, 141.988494, 116.014989, 102.162453, 102.162453, 102.162453,
+102.162453, 103.894020, 152.377896, 124.672824, 102.162453, 103.894020,
+128.135958, 138.525360, 121.209690, 116.014989, 114.283422, 110.820288,
+107.357154, 103.894020, 112.551855, 117.746556, 116.014989, 114.283422,
+112.551855, 116.014989, 114.283422, 110.820288, 107.357154, 102.162453,
+192.203937,
+145.451628, 145.451628, 150.646329, 147.183195, 150.646329, 147.183195,
+145.451628, 145.451628, 124.672824, 102.162453, 102.162453, 102.162453,
+102.162453, 102.162453, 126.404391, 122.941257, 107.357154, 102.162453,
+173.156700, 121.209690, 121.209690, 116.014989, 114.283422, 110.820288,
+103.894020, 100.430886, 100.430886, 116.014989, 117.746556, 114.283422,
+112.551855, 114.283422, 110.820288, 109.088721, 102.162453, 96.967752,
+226.835277,
+138.525360, 155.841030, 150.646329, 143.720061, 152.377896, 154.109463,
+145.451628, 143.720061, 131.599092, 110.820288, 102.162453, 102.162453,
+102.162453, 100.430886, 102.162453, 167.961999, 110.820288, 107.357154,
+122.941257, 117.746556, 121.209690, 126.404391, 114.283422, 109.088721,
+105.625587, 100.430886, 100.430886, 107.357154, 116.014989, 114.283422,
+110.820288, 112.551855, 109.088721, 109.088721, 105.625587, 98.699319,
+258.003483,
+148.914762, 157.572597, 159.304164, 150.646329, 147.183195, 152.377896,
+143.720061, 140.256927, 135.062226, 119.478123, 105.625587, 102.162453,
+102.162453, 102.162453, 102.162453, 105.625587, 143.720061, 124.672824,
+116.014989, 116.014989, 119.478123, 119.478123, 114.283422, 110.820288,
+105.625587, 124.672824, 96.967752, 98.699319, 110.820288, 110.820288,
+110.820288, 110.820288, 112.551855, 199.130205, 259.735050, 161.035731,
+261.466617,
+167.961999, 154.109463, 157.572597, 159.304164, 154.109463, 152.377896,
+128.135958, 138.525360, 135.062226, 122.941257, 112.551855, 102.162453,
+100.430886, 102.162453, 100.430886, 102.162453, 122.941257, 124.672824,
+116.014989, 121.209690, 121.209690, 119.478123, 116.014989, 110.820288,
+109.088721, 114.283422, 96.967752, 93.504618, 98.699319, 102.162453,
+110.820288, 150.646329, 240.687813, 280.513854, 277.050720, 221.640576,
+244.150947,
+162.767298, 166.230432, 167.961999, 162.767298, 154.109463, 141.988494,
+122.941257, 121.209690, 131.599092, 126.404391, 116.014989, 105.625587,
+102.162453, 102.162453, 100.430886, 102.162453, 105.625587, 122.941257,
+116.014989, 129.867525, 121.209690, 117.746556, 121.209690, 112.551855,
+109.088721, 109.088721, 102.162453, 96.967752, 93.504618, 95.236185,
+155.841030, 209.519607, 258.003483, 290.903256, 238.956246, 249.345648,
+271.856019,
+171.425133, 173.156700, 161.035731, 161.035731, 141.988494, 138.525360,
+121.209690, 107.357154, 121.209690, 124.672824, 116.014989, 109.088721,
+103.894020, 103.894020, 100.430886, 100.430886, 103.894020, 117.746556,
+121.209690, 121.209690, 119.478123, 117.746556, 136.793793, 117.746556,
+110.820288, 107.357154, 103.894020, 102.162453, 98.699319, 98.699319,
+152.377896, 207.788040, 261.466617, 280.513854, 266.661318, 258.003483,
+268.392885,
+178.351401, 171.425133, 164.498865, 162.767298, 145.451628, 126.404391,
+116.014989, 107.357154, 112.551855, 119.478123, 116.014989, 110.820288,
+109.088721, 110.820288, 109.088721, 102.162453, 103.894020, 112.551855,
+122.941257, 119.478123, 119.478123, 116.014989, 135.062226, 112.551855,
+109.088721, 105.625587, 102.162453, 105.625587, 103.894020, 117.746556,
+173.156700, 221.640576, 268.392885, 268.392885, 263.198184, 268.392885,
+283.976988,
+180.082968, 176.619834, 171.425133, 164.498865, 148.914762, 128.135958,
+116.014989, 105.625587, 105.625587, 114.283422, 112.551855, 109.088721,
+109.088721, 110.820288, 112.551855, 109.088721, 103.894020, 109.088721,
+121.209690, 119.478123, 116.014989, 116.014989, 116.014989, 112.551855,
+107.357154, 103.894020, 100.430886, 98.699319, 107.357154, 100.430886,
+122.941257, 202.593339, 259.735050, 266.661318, 271.856019, 268.392885,
+282.245421,
+180.082968, 174.888267, 171.425133, 157.572597, 145.451628, 128.135958,
+102.162453, 102.162453, 107.357154, 110.820288, 109.088721, 105.625587,
+107.357154, 110.820288, 110.820288, 110.820288, 105.625587, 103.894020,
+119.478123, 117.746556, 116.014989, 119.478123, 116.014989, 112.551855,
+107.357154, 102.162453, 100.430886, 98.699319, 98.699319, 96.967752,
+102.162453, 180.082968, 237.224679, 254.540349, 275.319153, 278.782287,
+273.587586,
+180.082968, 174.888267, 171.425133, 155.841030, 147.183195, 133.330659,
+103.894020, 98.699319, 103.894020, 107.357154, 107.357154, 107.357154,
+109.088721, 110.820288, 112.551855, 112.551855, 114.283422, 173.156700,
+116.014989, 116.014989, 119.478123, 119.478123, 116.014989, 112.551855,
+109.088721, 103.894020, 100.430886, 96.967752, 93.504618, 95.236185,
+96.967752, 133.330659, 211.251174, 245.882514, 287.440122, 271.856019,
+259.735050,
+180.082968, 174.888267, 167.961999, 159.304164, 133.330659, 136.793793,
+110.820288, 98.699319, 98.699319, 107.357154, 107.357154, 107.357154,
+110.820288, 112.551855, 114.283422, 112.551855, 199.130205, 238.956246,
+223.372143, 110.820288, 117.746556, 121.209690, 117.746556, 114.283422,
+110.820288, 103.894020, 100.430886, 96.967752, 91.773051, 91.773051,
+96.967752, 107.357154, 199.130205, 247.614081, 271.856019, 270.124452,
+275.319153
+};
+
+const size_t array_double2_size = sizeof(array_double2);
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/test/test_arrays.h b/tiff/test/test_arrays.h
new file mode 100644
index 0000000..bfedbba
--- /dev/null
+++ b/tiff/test/test_arrays.h
@@ -0,0 +1,70 @@
+/* $Id: test_arrays.h,v 1.3.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * TIFF Library
+ *
+ * Few declarations for the test numerical arrays.
+ */
+
+#ifndef _TEST_ARRAYS_
+#define _TEST_ARRAYS_
+
+#include <stddef.h>
+
+#define XSIZE 37
+#define YSIZE 23
+
+extern const unsigned char byte_array1[];
+extern const size_t byte_array1_size;
+
+extern const unsigned char byte_array2[];
+extern const size_t byte_array2_size;
+
+extern const unsigned char byte_array3[];
+extern const size_t byte_array3_size;
+
+extern const float array_float1[];
+extern const size_t array_float1_size;
+
+extern const float array_float2[];
+extern const size_t array_float2_size;
+
+extern const double array_double1[];
+extern const size_t array_double1_size;
+
+extern const double array_double2[];
+extern const size_t array_double2_size;
+
+#endif /* _TEST_ARRAYS_ */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/Jamfile b/tiff/tools/Jamfile
new file mode 100644
index 0000000..99f1307
--- /dev/null
+++ b/tiff/tools/Jamfile
@@ -0,0 +1,20 @@
+
+PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+#PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ;
+
+HDRS = .. ../libtiff ;
+
+LINKLIBS = ../libtiff ../libport ../$(JPEGLIB) ;
+
+Main tiffcp : tiffcp.c ;
+
+Main tiff2bw : tiff2bw.c ;
+
+Main tiffset : tiffset.c ;
+
+Main tiffdump : tiffdump.c ;
+
+Main tiffinfo : tiffinfo.c ;
+
+Main tiffsplit : tiffsplit.c ;
diff --git a/tiff/tools/Makefile.am b/tiff/tools/Makefile.am
new file mode 100644
index 0000000..0f3be93
--- /dev/null
+++ b/tiff/tools/Makefile.am
@@ -0,0 +1,145 @@
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+LIBPORT = $(top_builddir)/port/libport.la
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+
+EXTRA_DIST = Makefile.vc
+
+bin_PROGRAMS = \
+ bmp2tiff \
+ fax2ps \
+ fax2tiff \
+ gif2tiff \
+ pal2rgb \
+ ppm2tiff \
+ ras2tiff \
+ raw2tiff \
+ rgb2ycbcr \
+ thumbnail \
+ tiff2bw \
+ tiff2pdf \
+ tiff2ps \
+ tiff2rgba \
+ tiffcmp \
+ tiffcp \
+ tiffcrop \
+ tiffdither \
+ tiffdump \
+ tiffinfo \
+ tiffmedian \
+ tiffset \
+ tiffsplit
+if HAVE_OPENGL
+bin_PROGRAMS += tiffgt
+endif
+
+EXTRA_PROGRAMS = sgi2tiff sgisv ycbcr
+
+if HAVE_RPATH
+AM_LDFLAGS = $(LIBDIR)
+endif
+
+bmp2tiff_SOURCES = bmp2tiff.c
+bmp2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+fax2ps_SOURCES = fax2ps.c
+fax2ps_LDADD = $(LIBTIFF) $(LIBPORT)
+
+fax2tiff_SOURCES = fax2tiff.c
+fax2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+gif2tiff_SOURCES = gif2tiff.c
+gif2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+pal2rgb_SOURCES = pal2rgb.c
+pal2rgb_LDADD = $(LIBTIFF) $(LIBPORT)
+
+ppm2tiff_SOURCES = ppm2tiff.c
+ppm2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+ras2tiff_SOURCES = ras2tiff.c rasterfile.h
+ras2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+raw2tiff_SOURCES = raw2tiff.c
+raw2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+
+rgb2ycbcr_SOURCES = rgb2ycbcr.c
+rgb2ycbcr_LDADD = $(LIBTIFF) $(LIBPORT)
+
+thumbnail_SOURCES = thumbnail.c
+thumbnail_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiff2bw_SOURCES = tiff2bw.c
+tiff2bw_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiff2pdf_SOURCES = tiff2pdf.c
+tiff2pdf_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiff2ps_SOURCES = tiff2ps.c
+tiff2ps_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiff2rgba_SOURCES = tiff2rgba.c
+tiff2rgba_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffcmp_SOURCES = tiffcmp.c
+tiffcmp_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffcp_SOURCES = tiffcp.c
+tiffcp_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffcrop_SOURCES = tiffcrop.c
+tiffcrop_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffdither_SOURCES = tiffdither.c
+tiffdither_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffdump_SOURCES = tiffdump.c
+tiffdump_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffinfo_SOURCES = tiffinfo.c
+tiffinfo_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffmedian_SOURCES = tiffmedian.c
+tiffmedian_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffset_SOURCES = tiffset.c
+tiffset_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffsplit_SOURCES = tiffsplit.c
+tiffsplit_LDADD = $(LIBTIFF) $(LIBPORT)
+
+tiffgt_SOURCES = tiffgt.c
+tiffgt_CFLAGS = $(CFLAGS) $(GLUT_CFLAGS) $(AM_CFLAGS)
+tiffgt_LDADD = $(LIBTIFF) $(LIBPORT) $(X_LIBS) $(GLUT_LIBS)
+
+INCLUDES = -I../libtiff -I$(top_srcdir)/libtiff
+
+echo:
+ (echo $(CFLAGS))
+ (echo $(tiffgt_CFLAGS))
+ (echo $(GL_CFLAGS))
+ (echo $(GLU_CFLAGS))
+ (echo $(GLUT_CFLAGS))
diff --git a/tiff/tools/Makefile.in b/tiff/tools/Makefile.in
new file mode 100644
index 0000000..7682ca4
--- /dev/null
+++ b/tiff/tools/Makefile.in
@@ -0,0 +1,876 @@
+# Makefile.in generated by automake 1.11 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Tag Image File Format (TIFF) Software
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+
+# Process this file with automake to produce Makefile.in.
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+bin_PROGRAMS = bmp2tiff$(EXEEXT) fax2ps$(EXEEXT) fax2tiff$(EXEEXT) \
+ gif2tiff$(EXEEXT) pal2rgb$(EXEEXT) ppm2tiff$(EXEEXT) \
+ ras2tiff$(EXEEXT) raw2tiff$(EXEEXT) rgb2ycbcr$(EXEEXT) \
+ thumbnail$(EXEEXT) tiff2bw$(EXEEXT) tiff2pdf$(EXEEXT) \
+ tiff2ps$(EXEEXT) tiff2rgba$(EXEEXT) tiffcmp$(EXEEXT) \
+ tiffcp$(EXEEXT) tiffcrop$(EXEEXT) tiffdither$(EXEEXT) \
+ tiffdump$(EXEEXT) tiffinfo$(EXEEXT) tiffmedian$(EXEEXT) \
+ tiffset$(EXEEXT) tiffsplit$(EXEEXT) $(am__EXEEXT_1)
+@HAVE_OPENGL_TRUE@am__append_1 = tiffgt
+EXTRA_PROGRAMS = sgi2tiff$(EXEEXT) sgisv$(EXEEXT) ycbcr$(EXEEXT)
+subdir = tools
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/acinclude.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/libtiff/tif_config.h \
+ $(top_builddir)/libtiff/tiffconf.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+@HAVE_OPENGL_TRUE@am__EXEEXT_1 = tiffgt$(EXEEXT)
+am__installdirs = "$(DESTDIR)$(bindir)"
+PROGRAMS = $(bin_PROGRAMS)
+am_bmp2tiff_OBJECTS = bmp2tiff.$(OBJEXT)
+bmp2tiff_OBJECTS = $(am_bmp2tiff_OBJECTS)
+bmp2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+am_fax2ps_OBJECTS = fax2ps.$(OBJEXT)
+fax2ps_OBJECTS = $(am_fax2ps_OBJECTS)
+fax2ps_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_fax2tiff_OBJECTS = fax2tiff.$(OBJEXT)
+fax2tiff_OBJECTS = $(am_fax2tiff_OBJECTS)
+fax2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_gif2tiff_OBJECTS = gif2tiff.$(OBJEXT)
+gif2tiff_OBJECTS = $(am_gif2tiff_OBJECTS)
+gif2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_pal2rgb_OBJECTS = pal2rgb.$(OBJEXT)
+pal2rgb_OBJECTS = $(am_pal2rgb_OBJECTS)
+pal2rgb_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_ppm2tiff_OBJECTS = ppm2tiff.$(OBJEXT)
+ppm2tiff_OBJECTS = $(am_ppm2tiff_OBJECTS)
+ppm2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_ras2tiff_OBJECTS = ras2tiff.$(OBJEXT)
+ras2tiff_OBJECTS = $(am_ras2tiff_OBJECTS)
+ras2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_raw2tiff_OBJECTS = raw2tiff.$(OBJEXT)
+raw2tiff_OBJECTS = $(am_raw2tiff_OBJECTS)
+raw2tiff_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_rgb2ycbcr_OBJECTS = rgb2ycbcr.$(OBJEXT)
+rgb2ycbcr_OBJECTS = $(am_rgb2ycbcr_OBJECTS)
+rgb2ycbcr_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+sgi2tiff_SOURCES = sgi2tiff.c
+sgi2tiff_OBJECTS = sgi2tiff.$(OBJEXT)
+sgi2tiff_LDADD = $(LDADD)
+sgisv_SOURCES = sgisv.c
+sgisv_OBJECTS = sgisv.$(OBJEXT)
+sgisv_LDADD = $(LDADD)
+am_thumbnail_OBJECTS = thumbnail.$(OBJEXT)
+thumbnail_OBJECTS = $(am_thumbnail_OBJECTS)
+thumbnail_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiff2bw_OBJECTS = tiff2bw.$(OBJEXT)
+tiff2bw_OBJECTS = $(am_tiff2bw_OBJECTS)
+tiff2bw_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiff2pdf_OBJECTS = tiff2pdf.$(OBJEXT)
+tiff2pdf_OBJECTS = $(am_tiff2pdf_OBJECTS)
+tiff2pdf_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiff2ps_OBJECTS = tiff2ps.$(OBJEXT)
+tiff2ps_OBJECTS = $(am_tiff2ps_OBJECTS)
+tiff2ps_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiff2rgba_OBJECTS = tiff2rgba.$(OBJEXT)
+tiff2rgba_OBJECTS = $(am_tiff2rgba_OBJECTS)
+tiff2rgba_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffcmp_OBJECTS = tiffcmp.$(OBJEXT)
+tiffcmp_OBJECTS = $(am_tiffcmp_OBJECTS)
+tiffcmp_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffcp_OBJECTS = tiffcp.$(OBJEXT)
+tiffcp_OBJECTS = $(am_tiffcp_OBJECTS)
+tiffcp_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffcrop_OBJECTS = tiffcrop.$(OBJEXT)
+tiffcrop_OBJECTS = $(am_tiffcrop_OBJECTS)
+tiffcrop_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffdither_OBJECTS = tiffdither.$(OBJEXT)
+tiffdither_OBJECTS = $(am_tiffdither_OBJECTS)
+tiffdither_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffdump_OBJECTS = tiffdump.$(OBJEXT)
+tiffdump_OBJECTS = $(am_tiffdump_OBJECTS)
+tiffdump_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffgt_OBJECTS = tiffgt-tiffgt.$(OBJEXT)
+tiffgt_OBJECTS = $(am_tiffgt_OBJECTS)
+am__DEPENDENCIES_1 =
+tiffgt_DEPENDENCIES = $(LIBTIFF) $(LIBPORT) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+tiffgt_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(tiffgt_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+am_tiffinfo_OBJECTS = tiffinfo.$(OBJEXT)
+tiffinfo_OBJECTS = $(am_tiffinfo_OBJECTS)
+tiffinfo_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffmedian_OBJECTS = tiffmedian.$(OBJEXT)
+tiffmedian_OBJECTS = $(am_tiffmedian_OBJECTS)
+tiffmedian_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffset_OBJECTS = tiffset.$(OBJEXT)
+tiffset_OBJECTS = $(am_tiffset_OBJECTS)
+tiffset_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+am_tiffsplit_OBJECTS = tiffsplit.$(OBJEXT)
+tiffsplit_OBJECTS = $(am_tiffsplit_OBJECTS)
+tiffsplit_DEPENDENCIES = $(LIBTIFF) $(LIBPORT)
+ycbcr_SOURCES = ycbcr.c
+ycbcr_OBJECTS = ycbcr.$(OBJEXT)
+ycbcr_LDADD = $(LDADD)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libtiff
+depcomp = $(SHELL) $(top_srcdir)/config/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(bmp2tiff_SOURCES) $(fax2ps_SOURCES) $(fax2tiff_SOURCES) \
+ $(gif2tiff_SOURCES) $(pal2rgb_SOURCES) $(ppm2tiff_SOURCES) \
+ $(ras2tiff_SOURCES) $(raw2tiff_SOURCES) $(rgb2ycbcr_SOURCES) \
+ sgi2tiff.c sgisv.c $(thumbnail_SOURCES) $(tiff2bw_SOURCES) \
+ $(tiff2pdf_SOURCES) $(tiff2ps_SOURCES) $(tiff2rgba_SOURCES) \
+ $(tiffcmp_SOURCES) $(tiffcp_SOURCES) $(tiffcrop_SOURCES) \
+ $(tiffdither_SOURCES) $(tiffdump_SOURCES) $(tiffgt_SOURCES) \
+ $(tiffinfo_SOURCES) $(tiffmedian_SOURCES) $(tiffset_SOURCES) \
+ $(tiffsplit_SOURCES) ycbcr.c
+DIST_SOURCES = $(bmp2tiff_SOURCES) $(fax2ps_SOURCES) \
+ $(fax2tiff_SOURCES) $(gif2tiff_SOURCES) $(pal2rgb_SOURCES) \
+ $(ppm2tiff_SOURCES) $(ras2tiff_SOURCES) $(raw2tiff_SOURCES) \
+ $(rgb2ycbcr_SOURCES) sgi2tiff.c sgisv.c $(thumbnail_SOURCES) \
+ $(tiff2bw_SOURCES) $(tiff2pdf_SOURCES) $(tiff2ps_SOURCES) \
+ $(tiff2rgba_SOURCES) $(tiffcmp_SOURCES) $(tiffcp_SOURCES) \
+ $(tiffcrop_SOURCES) $(tiffdither_SOURCES) $(tiffdump_SOURCES) \
+ $(tiffgt_SOURCES) $(tiffinfo_SOURCES) $(tiffmedian_SOURCES) \
+ $(tiffset_SOURCES) $(tiffsplit_SOURCES) ycbcr.c
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GLUT_CFLAGS = @GLUT_CFLAGS@
+GLUT_LIBS = @GLUT_LIBS@
+GLU_CFLAGS = @GLU_CFLAGS@
+GLU_LIBS = @GLU_LIBS@
+GL_CFLAGS = @GL_CFLAGS@
+GL_LIBS = @GL_LIBS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBDIR = @LIBDIR@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTIFF_ALPHA_VERSION = @LIBTIFF_ALPHA_VERSION@
+LIBTIFF_DOCDIR = @LIBTIFF_DOCDIR@
+LIBTIFF_MAJOR_VERSION = @LIBTIFF_MAJOR_VERSION@
+LIBTIFF_MICRO_VERSION = @LIBTIFF_MICRO_VERSION@
+LIBTIFF_MINOR_VERSION = @LIBTIFF_MINOR_VERSION@
+LIBTIFF_RELEASE_DATE = @LIBTIFF_RELEASE_DATE@
+LIBTIFF_VERSION = @LIBTIFF_VERSION@
+LIBTIFF_VERSION_INFO = @LIBTIFF_VERSION_INFO@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+acx_pthread_config = @acx_pthread_config@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+LIBPORT = $(top_builddir)/port/libport.la
+LIBTIFF = $(top_builddir)/libtiff/libtiff.la
+EXTRA_DIST = Makefile.vc
+@HAVE_RPATH_TRUE@AM_LDFLAGS = $(LIBDIR)
+bmp2tiff_SOURCES = bmp2tiff.c
+bmp2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+fax2ps_SOURCES = fax2ps.c
+fax2ps_LDADD = $(LIBTIFF) $(LIBPORT)
+fax2tiff_SOURCES = fax2tiff.c
+fax2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+gif2tiff_SOURCES = gif2tiff.c
+gif2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+pal2rgb_SOURCES = pal2rgb.c
+pal2rgb_LDADD = $(LIBTIFF) $(LIBPORT)
+ppm2tiff_SOURCES = ppm2tiff.c
+ppm2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+ras2tiff_SOURCES = ras2tiff.c rasterfile.h
+ras2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+raw2tiff_SOURCES = raw2tiff.c
+raw2tiff_LDADD = $(LIBTIFF) $(LIBPORT)
+rgb2ycbcr_SOURCES = rgb2ycbcr.c
+rgb2ycbcr_LDADD = $(LIBTIFF) $(LIBPORT)
+thumbnail_SOURCES = thumbnail.c
+thumbnail_LDADD = $(LIBTIFF) $(LIBPORT)
+tiff2bw_SOURCES = tiff2bw.c
+tiff2bw_LDADD = $(LIBTIFF) $(LIBPORT)
+tiff2pdf_SOURCES = tiff2pdf.c
+tiff2pdf_LDADD = $(LIBTIFF) $(LIBPORT)
+tiff2ps_SOURCES = tiff2ps.c
+tiff2ps_LDADD = $(LIBTIFF) $(LIBPORT)
+tiff2rgba_SOURCES = tiff2rgba.c
+tiff2rgba_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffcmp_SOURCES = tiffcmp.c
+tiffcmp_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffcp_SOURCES = tiffcp.c
+tiffcp_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffcrop_SOURCES = tiffcrop.c
+tiffcrop_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffdither_SOURCES = tiffdither.c
+tiffdither_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffdump_SOURCES = tiffdump.c
+tiffdump_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffinfo_SOURCES = tiffinfo.c
+tiffinfo_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffmedian_SOURCES = tiffmedian.c
+tiffmedian_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffset_SOURCES = tiffset.c
+tiffset_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffsplit_SOURCES = tiffsplit.c
+tiffsplit_LDADD = $(LIBTIFF) $(LIBPORT)
+tiffgt_SOURCES = tiffgt.c
+tiffgt_CFLAGS = $(CFLAGS) $(GLUT_CFLAGS) $(AM_CFLAGS)
+tiffgt_LDADD = $(LIBTIFF) $(LIBPORT) $(X_LIBS) $(GLUT_LIBS)
+INCLUDES = -I../libtiff -I$(top_srcdir)/libtiff
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign tools/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+bmp2tiff$(EXEEXT): $(bmp2tiff_OBJECTS) $(bmp2tiff_DEPENDENCIES)
+ @rm -f bmp2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(bmp2tiff_OBJECTS) $(bmp2tiff_LDADD) $(LIBS)
+fax2ps$(EXEEXT): $(fax2ps_OBJECTS) $(fax2ps_DEPENDENCIES)
+ @rm -f fax2ps$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(fax2ps_OBJECTS) $(fax2ps_LDADD) $(LIBS)
+fax2tiff$(EXEEXT): $(fax2tiff_OBJECTS) $(fax2tiff_DEPENDENCIES)
+ @rm -f fax2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(fax2tiff_OBJECTS) $(fax2tiff_LDADD) $(LIBS)
+gif2tiff$(EXEEXT): $(gif2tiff_OBJECTS) $(gif2tiff_DEPENDENCIES)
+ @rm -f gif2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gif2tiff_OBJECTS) $(gif2tiff_LDADD) $(LIBS)
+pal2rgb$(EXEEXT): $(pal2rgb_OBJECTS) $(pal2rgb_DEPENDENCIES)
+ @rm -f pal2rgb$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(pal2rgb_OBJECTS) $(pal2rgb_LDADD) $(LIBS)
+ppm2tiff$(EXEEXT): $(ppm2tiff_OBJECTS) $(ppm2tiff_DEPENDENCIES)
+ @rm -f ppm2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ppm2tiff_OBJECTS) $(ppm2tiff_LDADD) $(LIBS)
+ras2tiff$(EXEEXT): $(ras2tiff_OBJECTS) $(ras2tiff_DEPENDENCIES)
+ @rm -f ras2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ras2tiff_OBJECTS) $(ras2tiff_LDADD) $(LIBS)
+raw2tiff$(EXEEXT): $(raw2tiff_OBJECTS) $(raw2tiff_DEPENDENCIES)
+ @rm -f raw2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(raw2tiff_OBJECTS) $(raw2tiff_LDADD) $(LIBS)
+rgb2ycbcr$(EXEEXT): $(rgb2ycbcr_OBJECTS) $(rgb2ycbcr_DEPENDENCIES)
+ @rm -f rgb2ycbcr$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(rgb2ycbcr_OBJECTS) $(rgb2ycbcr_LDADD) $(LIBS)
+sgi2tiff$(EXEEXT): $(sgi2tiff_OBJECTS) $(sgi2tiff_DEPENDENCIES)
+ @rm -f sgi2tiff$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sgi2tiff_OBJECTS) $(sgi2tiff_LDADD) $(LIBS)
+sgisv$(EXEEXT): $(sgisv_OBJECTS) $(sgisv_DEPENDENCIES)
+ @rm -f sgisv$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(sgisv_OBJECTS) $(sgisv_LDADD) $(LIBS)
+thumbnail$(EXEEXT): $(thumbnail_OBJECTS) $(thumbnail_DEPENDENCIES)
+ @rm -f thumbnail$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(thumbnail_OBJECTS) $(thumbnail_LDADD) $(LIBS)
+tiff2bw$(EXEEXT): $(tiff2bw_OBJECTS) $(tiff2bw_DEPENDENCIES)
+ @rm -f tiff2bw$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff2bw_OBJECTS) $(tiff2bw_LDADD) $(LIBS)
+tiff2pdf$(EXEEXT): $(tiff2pdf_OBJECTS) $(tiff2pdf_DEPENDENCIES)
+ @rm -f tiff2pdf$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff2pdf_OBJECTS) $(tiff2pdf_LDADD) $(LIBS)
+tiff2ps$(EXEEXT): $(tiff2ps_OBJECTS) $(tiff2ps_DEPENDENCIES)
+ @rm -f tiff2ps$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff2ps_OBJECTS) $(tiff2ps_LDADD) $(LIBS)
+tiff2rgba$(EXEEXT): $(tiff2rgba_OBJECTS) $(tiff2rgba_DEPENDENCIES)
+ @rm -f tiff2rgba$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiff2rgba_OBJECTS) $(tiff2rgba_LDADD) $(LIBS)
+tiffcmp$(EXEEXT): $(tiffcmp_OBJECTS) $(tiffcmp_DEPENDENCIES)
+ @rm -f tiffcmp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffcmp_OBJECTS) $(tiffcmp_LDADD) $(LIBS)
+tiffcp$(EXEEXT): $(tiffcp_OBJECTS) $(tiffcp_DEPENDENCIES)
+ @rm -f tiffcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffcp_OBJECTS) $(tiffcp_LDADD) $(LIBS)
+tiffcrop$(EXEEXT): $(tiffcrop_OBJECTS) $(tiffcrop_DEPENDENCIES)
+ @rm -f tiffcrop$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffcrop_OBJECTS) $(tiffcrop_LDADD) $(LIBS)
+tiffdither$(EXEEXT): $(tiffdither_OBJECTS) $(tiffdither_DEPENDENCIES)
+ @rm -f tiffdither$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffdither_OBJECTS) $(tiffdither_LDADD) $(LIBS)
+tiffdump$(EXEEXT): $(tiffdump_OBJECTS) $(tiffdump_DEPENDENCIES)
+ @rm -f tiffdump$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffdump_OBJECTS) $(tiffdump_LDADD) $(LIBS)
+tiffgt$(EXEEXT): $(tiffgt_OBJECTS) $(tiffgt_DEPENDENCIES)
+ @rm -f tiffgt$(EXEEXT)
+ $(AM_V_CCLD)$(tiffgt_LINK) $(tiffgt_OBJECTS) $(tiffgt_LDADD) $(LIBS)
+tiffinfo$(EXEEXT): $(tiffinfo_OBJECTS) $(tiffinfo_DEPENDENCIES)
+ @rm -f tiffinfo$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffinfo_OBJECTS) $(tiffinfo_LDADD) $(LIBS)
+tiffmedian$(EXEEXT): $(tiffmedian_OBJECTS) $(tiffmedian_DEPENDENCIES)
+ @rm -f tiffmedian$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffmedian_OBJECTS) $(tiffmedian_LDADD) $(LIBS)
+tiffset$(EXEEXT): $(tiffset_OBJECTS) $(tiffset_DEPENDENCIES)
+ @rm -f tiffset$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffset_OBJECTS) $(tiffset_LDADD) $(LIBS)
+tiffsplit$(EXEEXT): $(tiffsplit_OBJECTS) $(tiffsplit_DEPENDENCIES)
+ @rm -f tiffsplit$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(tiffsplit_OBJECTS) $(tiffsplit_LDADD) $(LIBS)
+ycbcr$(EXEEXT): $(ycbcr_OBJECTS) $(ycbcr_DEPENDENCIES)
+ @rm -f ycbcr$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(ycbcr_OBJECTS) $(ycbcr_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bmp2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fax2ps.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fax2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gif2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pal2rgb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppm2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ras2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/raw2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rgb2ycbcr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgi2tiff.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgisv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thumbnail.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff2bw.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff2pdf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff2ps.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiff2rgba.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffcmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffcp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffcrop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffdither.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffdump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffgt-tiffgt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffmedian.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffset.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tiffsplit.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ycbcr.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+tiffgt-tiffgt.o: tiffgt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tiffgt_CFLAGS) $(CFLAGS) -MT tiffgt-tiffgt.o -MD -MP -MF $(DEPDIR)/tiffgt-tiffgt.Tpo -c -o tiffgt-tiffgt.o `test -f 'tiffgt.c' || echo '$(srcdir)/'`tiffgt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tiffgt-tiffgt.Tpo $(DEPDIR)/tiffgt-tiffgt.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tiffgt.c' object='tiffgt-tiffgt.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tiffgt_CFLAGS) $(CFLAGS) -c -o tiffgt-tiffgt.o `test -f 'tiffgt.c' || echo '$(srcdir)/'`tiffgt.c
+
+tiffgt-tiffgt.obj: tiffgt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tiffgt_CFLAGS) $(CFLAGS) -MT tiffgt-tiffgt.obj -MD -MP -MF $(DEPDIR)/tiffgt-tiffgt.Tpo -c -o tiffgt-tiffgt.obj `if test -f 'tiffgt.c'; then $(CYGPATH_W) 'tiffgt.c'; else $(CYGPATH_W) '$(srcdir)/tiffgt.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/tiffgt-tiffgt.Tpo $(DEPDIR)/tiffgt-tiffgt.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tiffgt.c' object='tiffgt-tiffgt.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tiffgt_CFLAGS) $(CFLAGS) -c -o tiffgt-tiffgt.obj `if test -f 'tiffgt.c'; then $(CYGPATH_W) 'tiffgt.c'; else $(CYGPATH_W) '$(srcdir)/tiffgt.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(PROGRAMS)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-binPROGRAMS
+
+
+echo:
+ (echo $(CFLAGS))
+ (echo $(tiffgt_CFLAGS))
+ (echo $(GL_CFLAGS))
+ (echo $(GLU_CFLAGS))
+ (echo $(GLUT_CFLAGS))
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/tiff/tools/Makefile.vc b/tiff/tools/Makefile.vc
new file mode 100644
index 0000000..ea9e859
--- /dev/null
+++ b/tiff/tools/Makefile.vc
@@ -0,0 +1,51 @@
+# $Id: Makefile.vc,v 1.13 2007/02/24 15:26:09 dron Exp $
+#
+# Copyright (C) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+#
+# Permission to use, copy, modify, distribute, and sell this software and
+# its documentation for any purpose is hereby granted without fee, provided
+# that (i) the above copyright notices and this permission notice appear in
+# all copies of the software and related documentation, and (ii) the names of
+# Sam Leffler and Silicon Graphics may not be used in any advertising or
+# publicity relating to the software without the specific, prior written
+# permission of Sam Leffler and Silicon Graphics.
+#
+# THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+# WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+#
+# IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+# ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+# OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+# LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+# Makefile for MS Visual C and Watcom C compilers.
+#
+# To build:
+# C:\libtiff\tools> nmake /f makefile.vc
+
+!INCLUDE ..\nmake.opt
+
+TARGETS = bmp2tiff.exe tiffinfo.exe tiffdump.exe fax2tiff.exe \
+ fax2ps.exe gif2tiff.exe pal2rgb.exe ppm2tiff.exe \
+ rgb2ycbcr.exe thumbnail.exe ras2tiff.exe raw2tiff.exe \
+ tiff2bw.exe tiff2rgba.exe tiff2pdf.exe tiff2ps.exe \
+ tiffcmp.exe tiffcp.exe tiffcrop.exe tiffdither.exe \
+ tiffmedian.exe tiffset.exe tiffsplit.exe
+
+INCL = -I..\libtiff
+LIBS = $(LIBS) ..\port\libport.lib ..\libtiff\libtiff.lib
+
+default: $(TARGETS)
+
+.c.exe:
+ $(CC) $(CFLAGS) $*.c $(EXTRA_OBJ) $(LIBS)
+
+tiffgt.exe:
+ $(CC) $(CFLAGS) tiffgt.c $(EXTRA_OBJ) $(LIBS)
+
+clean:
+ -del *.exe
+ -del *.obj
diff --git a/tiff/tools/bmp2tiff.c b/tiff/tools/bmp2tiff.c
new file mode 100644
index 0000000..02b83b3
--- /dev/null
+++ b/tiff/tools/bmp2tiff.c
@@ -0,0 +1,850 @@
+/* $Id: bmp2tiff.c,v 1.20.2.1 2010-06-08 18:50:43 bfriesen Exp $
+ *
+ * Project: libtiff tools
+ * Purpose: Convert Windows BMP files in TIFF.
+ * Author: Andrey Kiselev, dron@ak4719.spb.edu
+ *
+ ******************************************************************************
+ * Copyright (c) 2004, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+enum BMPType
+{
+ BMPT_WIN4, /* BMP used in Windows 3.0/NT 3.51/95 */
+ BMPT_WIN5, /* BMP used in Windows NT 4.0/98/Me/2000/XP */
+ BMPT_OS21, /* BMP used in OS/2 PM 1.x */
+ BMPT_OS22 /* BMP used in OS/2 PM 2.x */
+};
+
+/*
+ * Bitmap file consists of a BMPFileHeader structure followed by a
+ * BMPInfoHeader structure. An array of BMPColorEntry structures (also called
+ * a colour table) follows the bitmap information header structure. The colour
+ * table is followed by a second array of indexes into the colour table (the
+ * actual bitmap data). Data may be comressed, for 4-bpp and 8-bpp used RLE
+ * compression.
+ *
+ * +---------------------+
+ * | BMPFileHeader |
+ * +---------------------+
+ * | BMPInfoHeader |
+ * +---------------------+
+ * | BMPColorEntry array |
+ * +---------------------+
+ * | Colour-index array |
+ * +---------------------+
+ *
+ * All numbers stored in Intel order with least significant byte first.
+ */
+
+enum BMPComprMethod
+{
+ BMPC_RGB = 0L, /* Uncompressed */
+ BMPC_RLE8 = 1L, /* RLE for 8 bpp images */
+ BMPC_RLE4 = 2L, /* RLE for 4 bpp images */
+ BMPC_BITFIELDS = 3L, /* Bitmap is not compressed and the colour table
+ * consists of three DWORD color masks that specify
+ * the red, green, and blue components of each
+ * pixel. This is valid when used with
+ * 16- and 32-bpp bitmaps. */
+ BMPC_JPEG = 4L, /* Indicates that the image is a JPEG image. */
+ BMPC_PNG = 5L /* Indicates that the image is a PNG image. */
+};
+
+enum BMPLCSType /* Type of logical color space. */
+{
+ BMPLT_CALIBRATED_RGB = 0, /* This value indicates that endpoints and
+ * gamma values are given in the appropriate
+ * fields. */
+ BMPLT_DEVICE_RGB = 1,
+ BMPLT_DEVICE_CMYK = 2
+};
+
+typedef struct
+{
+ int32 iCIEX;
+ int32 iCIEY;
+ int32 iCIEZ;
+} BMPCIEXYZ;
+
+typedef struct /* This structure contains the x, y, and z */
+{ /* coordinates of the three colors that */
+ /* correspond */
+ BMPCIEXYZ iCIERed; /* to the red, green, and blue endpoints for */
+ BMPCIEXYZ iCIEGreen; /* a specified logical color space. */
+ BMPCIEXYZ iCIEBlue;
+} BMPCIEXYZTriple;
+
+typedef struct
+{
+ char bType[2]; /* Signature "BM" */
+ uint32 iSize; /* Size in bytes of the bitmap file. Should
+ * always be ignored while reading because
+ * of error in Windows 3.0 SDK's description
+ * of this field */
+ uint16 iReserved1; /* Reserved, set as 0 */
+ uint16 iReserved2; /* Reserved, set as 0 */
+ uint32 iOffBits; /* Offset of the image from file start in bytes */
+} BMPFileHeader;
+
+/* File header size in bytes: */
+const int BFH_SIZE = 14;
+
+typedef struct
+{
+ uint32 iSize; /* Size of BMPInfoHeader structure in bytes.
+ * Should be used to determine start of the
+ * colour table */
+ int32 iWidth; /* Image width */
+ int32 iHeight; /* Image height. If positive, image has bottom
+ * left origin, if negative --- top left. */
+ int16 iPlanes; /* Number of image planes (must be set to 1) */
+ int16 iBitCount; /* Number of bits per pixel (1, 4, 8, 16, 24
+ * or 32). If 0 then the number of bits per
+ * pixel is specified or is implied by the
+ * JPEG or PNG format. */
+ uint32 iCompression; /* Compression method */
+ uint32 iSizeImage; /* Size of uncomressed image in bytes. May
+ * be 0 for BMPC_RGB bitmaps. If iCompression
+ * is BI_JPEG or BI_PNG, iSizeImage indicates
+ * the size of the JPEG or PNG image buffer. */
+ int32 iXPelsPerMeter; /* X resolution, pixels per meter (0 if not used) */
+ int32 iYPelsPerMeter; /* Y resolution, pixels per meter (0 if not used) */
+ uint32 iClrUsed; /* Size of colour table. If 0, iBitCount should
+ * be used to calculate this value
+ * (1<<iBitCount). This value should be
+ * unsigned for proper shifting. */
+ int32 iClrImportant; /* Number of important colours. If 0, all
+ * colours are required */
+
+ /*
+ * Fields above should be used for bitmaps, compatible with Windows NT 3.51
+ * and earlier. Windows 98/Me, Windows 2000/XP introduces additional fields:
+ */
+
+ int32 iRedMask; /* Colour mask that specifies the red component
+ * of each pixel, valid only if iCompression
+ * is set to BI_BITFIELDS. */
+ int32 iGreenMask; /* The same for green component */
+ int32 iBlueMask; /* The same for blue component */
+ int32 iAlphaMask; /* Colour mask that specifies the alpha
+ * component of each pixel. */
+ uint32 iCSType; /* Colour space of the DIB. */
+ BMPCIEXYZTriple sEndpoints; /* This member is ignored unless the iCSType
+ * member specifies BMPLT_CALIBRATED_RGB. */
+ int32 iGammaRed; /* Toned response curve for red. This member
+ * is ignored unless color values are
+ * calibrated RGB values and iCSType is set to
+ * BMPLT_CALIBRATED_RGB. Specified
+ * in 16^16 format. */
+ int32 iGammaGreen; /* Toned response curve for green. */
+ int32 iGammaBlue; /* Toned response curve for blue. */
+} BMPInfoHeader;
+
+/*
+ * Info header size in bytes:
+ */
+const unsigned int BIH_WIN4SIZE = 40; /* for BMPT_WIN4 */
+const unsigned int BIH_WIN5SIZE = 57; /* for BMPT_WIN5 */
+const unsigned int BIH_OS21SIZE = 12; /* for BMPT_OS21 */
+const unsigned int BIH_OS22SIZE = 64; /* for BMPT_OS22 */
+
+/*
+ * We will use plain byte array instead of this structure, but declaration
+ * provided for reference
+ */
+typedef struct
+{
+ char bBlue;
+ char bGreen;
+ char bRed;
+ char bReserved; /* Must be 0 */
+} BMPColorEntry;
+
+static uint16 compression = (uint16) -1;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+static uint16 predictor = 0;
+
+static void usage(void);
+static int processCompressOptions(char*);
+static void rearrangePixels(char *, uint32, uint32);
+
+int
+main(int argc, char* argv[])
+{
+ uint32 width, length;
+ uint16 nbands = 1; /* number of bands in input image */
+ uint16 depth = 8; /* bits per pixel in input image */
+ uint32 rowsperstrip = (uint32) -1;
+ uint16 photometric = PHOTOMETRIC_MINISBLACK;
+ int fd = 0;
+ struct stat instat;
+ char *outfilename = NULL, *infilename = NULL;
+ TIFF *out = NULL;
+
+ BMPFileHeader file_hdr;
+ BMPInfoHeader info_hdr;
+ int bmp_type;
+ uint32 clr_tbl_size, n_clr_elems = 3;
+ unsigned char *clr_tbl;
+ unsigned short *red_tbl = NULL, *green_tbl = NULL, *blue_tbl = NULL;
+ uint32 row, clr;
+
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:r:o:h")) != -1) {
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'o':
+ outfilename = optarg;
+ break;
+ case 'h':
+ usage();
+ default:
+ break;
+ }
+ }
+
+ if (argc - optind < 2)
+ usage();
+
+ if (outfilename == NULL)
+ outfilename = argv[argc-1];
+ out = TIFFOpen(outfilename, "w");
+ if (out == NULL) {
+ TIFFError(infilename, "Cannot open file %s for output",
+ outfilename);
+ goto bad3;
+ }
+
+
+ while (optind < argc-1) {
+ infilename = argv[optind];
+ optind++;
+
+ fd = open(infilename, O_RDONLY|O_BINARY, 0);
+ if (fd < 0) {
+ TIFFError(infilename, "Cannot open input file");
+ return -1;
+ }
+
+ read(fd, file_hdr.bType, 2);
+ if(file_hdr.bType[0] != 'B' || file_hdr.bType[1] != 'M') {
+ TIFFError(infilename, "File is not BMP");
+ goto bad;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Read the BMPFileHeader. We need iOffBits value only */
+/* -------------------------------------------------------------------- */
+ lseek(fd, 10, SEEK_SET);
+ read(fd, &file_hdr.iOffBits, 4);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabLong(&file_hdr.iOffBits);
+#endif
+ fstat(fd, &instat);
+ file_hdr.iSize = instat.st_size;
+
+/* -------------------------------------------------------------------- */
+/* Read the BMPInfoHeader. */
+/* -------------------------------------------------------------------- */
+
+ lseek(fd, BFH_SIZE, SEEK_SET);
+ read(fd, &info_hdr.iSize, 4);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabLong(&info_hdr.iSize);
+#endif
+
+ if (info_hdr.iSize == BIH_WIN4SIZE)
+ bmp_type = BMPT_WIN4;
+ else if (info_hdr.iSize == BIH_OS21SIZE)
+ bmp_type = BMPT_OS21;
+ else if (info_hdr.iSize == BIH_OS22SIZE
+ || info_hdr.iSize == 16)
+ bmp_type = BMPT_OS22;
+ else
+ bmp_type = BMPT_WIN5;
+
+ if (bmp_type == BMPT_WIN4
+ || bmp_type == BMPT_WIN5
+ || bmp_type == BMPT_OS22) {
+ read(fd, &info_hdr.iWidth, 4);
+ read(fd, &info_hdr.iHeight, 4);
+ read(fd, &info_hdr.iPlanes, 2);
+ read(fd, &info_hdr.iBitCount, 2);
+ read(fd, &info_hdr.iCompression, 4);
+ read(fd, &info_hdr.iSizeImage, 4);
+ read(fd, &info_hdr.iXPelsPerMeter, 4);
+ read(fd, &info_hdr.iYPelsPerMeter, 4);
+ read(fd, &info_hdr.iClrUsed, 4);
+ read(fd, &info_hdr.iClrImportant, 4);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabLong((uint32*) &info_hdr.iWidth);
+ TIFFSwabLong((uint32*) &info_hdr.iHeight);
+ TIFFSwabShort((uint16*) &info_hdr.iPlanes);
+ TIFFSwabShort((uint16*) &info_hdr.iBitCount);
+ TIFFSwabLong((uint32*) &info_hdr.iCompression);
+ TIFFSwabLong((uint32*) &info_hdr.iSizeImage);
+ TIFFSwabLong((uint32*) &info_hdr.iXPelsPerMeter);
+ TIFFSwabLong((uint32*) &info_hdr.iYPelsPerMeter);
+ TIFFSwabLong((uint32*) &info_hdr.iClrUsed);
+ TIFFSwabLong((uint32*) &info_hdr.iClrImportant);
+#endif
+ n_clr_elems = 4;
+ }
+
+ if (bmp_type == BMPT_OS22) {
+ /*
+ * FIXME: different info in different documents
+ * regarding this!
+ */
+ n_clr_elems = 3;
+ }
+
+ if (bmp_type == BMPT_OS21) {
+ int16 iShort;
+
+ read(fd, &iShort, 2);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabShort((uint16*) &iShort);
+#endif
+ info_hdr.iWidth = iShort;
+ read(fd, &iShort, 2);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabShort((uint16*) &iShort);
+#endif
+ info_hdr.iHeight = iShort;
+ read(fd, &iShort, 2);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabShort((uint16*) &iShort);
+#endif
+ info_hdr.iPlanes = iShort;
+ read(fd, &iShort, 2);
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabShort((uint16*) &iShort);
+#endif
+ info_hdr.iBitCount = iShort;
+ info_hdr.iCompression = BMPC_RGB;
+ n_clr_elems = 3;
+ }
+
+ if (info_hdr.iBitCount != 1 && info_hdr.iBitCount != 4 &&
+ info_hdr.iBitCount != 8 && info_hdr.iBitCount != 16 &&
+ info_hdr.iBitCount != 24 && info_hdr.iBitCount != 32) {
+ TIFFError(infilename,
+ "Cannot process BMP file with bit count %d",
+ info_hdr.iBitCount);
+ close(fd);
+ return 0;
+ }
+
+ width = info_hdr.iWidth;
+ length = (info_hdr.iHeight > 0) ? info_hdr.iHeight : -info_hdr.iHeight;
+
+ switch (info_hdr.iBitCount)
+ {
+ case 1:
+ case 4:
+ case 8:
+ nbands = 1;
+ depth = info_hdr.iBitCount;
+ photometric = PHOTOMETRIC_PALETTE;
+ /* Allocate memory for colour table and read it. */
+ if (info_hdr.iClrUsed)
+ clr_tbl_size =
+ ((uint32)(1<<depth)<info_hdr.iClrUsed)
+ ? (uint32) (1 << depth)
+ : info_hdr.iClrUsed;
+ else
+ clr_tbl_size = 1 << depth;
+ clr_tbl = (unsigned char *)
+ _TIFFmalloc(n_clr_elems * clr_tbl_size);
+ if (!clr_tbl) {
+ TIFFError(infilename,
+ "Can't allocate space for color table");
+ goto bad;
+ }
+
+ lseek(fd, BFH_SIZE + info_hdr.iSize, SEEK_SET);
+ read(fd, clr_tbl, n_clr_elems * clr_tbl_size);
+
+ red_tbl = (unsigned short*)
+ _TIFFmalloc(1<<depth * sizeof(unsigned short));
+ if (!red_tbl) {
+ TIFFError(infilename,
+ "Can't allocate space for red component table");
+ _TIFFfree(clr_tbl);
+ goto bad1;
+ }
+ green_tbl = (unsigned short*)
+ _TIFFmalloc(1<<depth * sizeof(unsigned short));
+ if (!green_tbl) {
+ TIFFError(infilename,
+ "Can't allocate space for green component table");
+ _TIFFfree(clr_tbl);
+ goto bad2;
+ }
+ blue_tbl = (unsigned short*)
+ _TIFFmalloc(1<<depth * sizeof(unsigned short));
+ if (!blue_tbl) {
+ TIFFError(infilename,
+ "Can't allocate space for blue component table");
+ _TIFFfree(clr_tbl);
+ goto bad3;
+ }
+
+ for(clr = 0; clr < clr_tbl_size; clr++) {
+ red_tbl[clr] = 257*clr_tbl[clr*n_clr_elems+2];
+ green_tbl[clr] = 257*clr_tbl[clr*n_clr_elems+1];
+ blue_tbl[clr] = 257*clr_tbl[clr*n_clr_elems];
+ }
+
+ _TIFFfree(clr_tbl);
+ break;
+ case 16:
+ case 24:
+ nbands = 3;
+ depth = info_hdr.iBitCount / nbands;
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ case 32:
+ nbands = 3;
+ depth = 8;
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ default:
+ break;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Create output file. */
+/* -------------------------------------------------------------------- */
+
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, nbands);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, depth);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+
+ if (red_tbl && green_tbl && blue_tbl) {
+ TIFFSetField(out, TIFFTAG_COLORMAP,
+ red_tbl, green_tbl, blue_tbl);
+ }
+
+ if (compression == (uint16) -1)
+ compression = COMPRESSION_PACKBITS;
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB
+ && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Read uncompressed image data. */
+/* -------------------------------------------------------------------- */
+
+ if (info_hdr.iCompression == BMPC_RGB) {
+ uint32 offset, size;
+ char *scanbuf;
+
+ /* XXX: Avoid integer overflow. We can calculate size
+ * in one step using
+ *
+ * size = ((width * info_hdr.iBitCount + 31) & ~31) / 8
+ *
+ * formulae, but we should check for overflow
+ * conditions during calculation.
+ */
+ size = width * info_hdr.iBitCount + 31;
+ if (!width || !info_hdr.iBitCount
+ || (size - 31) / info_hdr.iBitCount != width ) {
+ TIFFError(infilename,
+ "Wrong image parameters; can't "
+ "allocate space for scanline buffer");
+ goto bad3;
+ }
+ size = (size & ~31) / 8;
+
+ scanbuf = (char *) _TIFFmalloc(size);
+ if (!scanbuf) {
+ TIFFError(infilename,
+ "Can't allocate space for scanline buffer");
+ goto bad3;
+ }
+
+ for (row = 0; row < length; row++) {
+ if (info_hdr.iHeight > 0)
+ offset = file_hdr.iOffBits+(length-row-1)*size;
+ else
+ offset = file_hdr.iOffBits + row * size;
+ if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
+ TIFFError(infilename,
+ "scanline %lu: Seek error",
+ (unsigned long) row);
+ break;
+ }
+
+ if (read(fd, scanbuf, size) < 0) {
+ TIFFError(infilename,
+ "scanline %lu: Read error",
+ (unsigned long) row);
+ break;
+ }
+
+ rearrangePixels(scanbuf, width, info_hdr.iBitCount);
+
+ if (TIFFWriteScanline(out, scanbuf, row, 0)<0) {
+ TIFFError(infilename,
+ "scanline %lu: Write error",
+ (unsigned long) row);
+ break;
+ }
+ }
+
+ _TIFFfree(scanbuf);
+
+/* -------------------------------------------------------------------- */
+/* Read compressed image data. */
+/* -------------------------------------------------------------------- */
+
+ } else if ( info_hdr.iCompression == BMPC_RLE8
+ || info_hdr.iCompression == BMPC_RLE4 ) {
+ uint32 i, j, k, runlength;
+ uint32 compr_size, uncompr_size;
+ unsigned char *comprbuf;
+ unsigned char *uncomprbuf;
+
+ compr_size = file_hdr.iSize - file_hdr.iOffBits;
+ uncompr_size = width * length;
+ comprbuf = (unsigned char *) _TIFFmalloc( compr_size );
+ if (!comprbuf) {
+ TIFFError(infilename,
+ "Can't allocate space for compressed scanline buffer");
+ goto bad3;
+ }
+ uncomprbuf = (unsigned char *)_TIFFmalloc(uncompr_size);
+ if (!uncomprbuf) {
+ TIFFError(infilename,
+ "Can't allocate space for uncompressed scanline buffer");
+ goto bad3;
+ }
+
+ lseek(fd, file_hdr.iOffBits, SEEK_SET);
+ read(fd, comprbuf, compr_size);
+ i = 0;
+ j = 0;
+ if (info_hdr.iBitCount == 8) { /* RLE8 */
+ while(j < uncompr_size && i < compr_size) {
+ if ( comprbuf[i] ) {
+ runlength = comprbuf[i++];
+ while( runlength > 0
+ && j < uncompr_size
+ && i < compr_size ) {
+ uncomprbuf[j++] = comprbuf[i];
+ runlength--;
+ }
+ i++;
+ } else {
+ i++;
+ if (comprbuf[i] == 0) /* Next scanline */
+ i++;
+ else if (comprbuf[i] == 1) /* End of image */
+ break;
+ else if (comprbuf[i] == 2) { /* Move to... */
+ i++;
+ if (i < compr_size - 1) {
+ j+=comprbuf[i]+comprbuf[i+1]*width;
+ i += 2;
+ }
+ else
+ break;
+ } else { /* Absolute mode */
+ runlength = comprbuf[i++];
+ for (k = 0; k < runlength && j < uncompr_size && i < compr_size; k++)
+ uncomprbuf[j++] = comprbuf[i++];
+ if ( k & 0x01 )
+ i++;
+ }
+ }
+ }
+ }
+ else { /* RLE4 */
+ while( j < uncompr_size && i < compr_size ) {
+ if ( comprbuf[i] ) {
+ runlength = comprbuf[i++];
+ while( runlength > 0 && j < uncompr_size && i < compr_size ) {
+ if ( runlength & 0x01 )
+ uncomprbuf[j++] = (comprbuf[i] & 0xF0) >> 4;
+ else
+ uncomprbuf[j++] = comprbuf[i] & 0x0F;
+ runlength--;
+ }
+ i++;
+ } else {
+ i++;
+ if (comprbuf[i] == 0) /* Next scanline */
+ i++;
+ else if (comprbuf[i] == 1) /* End of image */
+ break;
+ else if (comprbuf[i] == 2) { /* Move to... */
+ i++;
+ if (i < compr_size - 1) {
+ j+=comprbuf[i]+comprbuf[i+1]*width;
+ i += 2;
+ }
+ else
+ break;
+ } else { /* Absolute mode */
+ runlength = comprbuf[i++];
+ for (k = 0; k < runlength && j < uncompr_size && i < compr_size; k++) {
+ if (k & 0x01)
+ uncomprbuf[j++] = comprbuf[i++] & 0x0F;
+ else
+ uncomprbuf[j++] = (comprbuf[i] & 0xF0) >> 4;
+ }
+ if (k & 0x01)
+ i++;
+ }
+ }
+ }
+ }
+
+ _TIFFfree(comprbuf);
+
+ for (row = 0; row < length; row++) {
+ if (TIFFWriteScanline(out,
+ uncomprbuf + (length - row - 1) * width,
+ row, 0) < 0) {
+ TIFFError(infilename,
+ "scanline %lu: Write error.\n",
+ (unsigned long) row);
+ }
+ }
+
+ _TIFFfree(uncomprbuf);
+ }
+ TIFFWriteDirectory(out);
+ if (blue_tbl) {
+ _TIFFfree(blue_tbl);
+ blue_tbl=NULL;
+ }
+ if (green_tbl) {
+ _TIFFfree(green_tbl);
+ green_tbl=NULL;
+ }
+ if (red_tbl) {
+ _TIFFfree(red_tbl);
+ red_tbl=NULL;
+ }
+ }
+
+bad3:
+ if (blue_tbl)
+ _TIFFfree(blue_tbl);
+bad2:
+ if (green_tbl)
+ _TIFFfree(green_tbl);
+bad1:
+ if (red_tbl)
+ _TIFFfree(red_tbl);
+bad:
+ close(fd);
+
+ if (out)
+ TIFFClose(out);
+ return 0;
+}
+
+/*
+ * Image data in BMP file stored in BGR (or ABGR) format. We should rearrange
+ * pixels to RGB (RGBA) format.
+ */
+static void
+rearrangePixels(char *buf, uint32 width, uint32 bit_count)
+{
+ char tmp;
+ uint32 i;
+
+ switch(bit_count) {
+ case 16: /* FIXME: need a sample file */
+ break;
+ case 24:
+ for (i = 0; i < width; i++, buf += 3) {
+ tmp = *buf;
+ *buf = *(buf + 2);
+ *(buf + 2) = tmp;
+ }
+ break;
+ case 32:
+ {
+ char *buf1 = buf;
+
+ for (i = 0; i < width; i++, buf += 4) {
+ tmp = *buf;
+ *buf1++ = *(buf + 2);
+ *buf1++ = *(buf + 1);
+ *buf1++ = tmp;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (strcmp(opt, "none") == 0)
+ compression = COMPRESSION_NONE;
+ else if (strcmp(opt, "packbits") == 0)
+ compression = COMPRESSION_PACKBITS;
+ else if (strncmp(opt, "jpeg", 4) == 0) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strncmp(opt, "lzw", 3) == 0) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strncmp(opt, "zip", 3) == 0) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+static char* stuff[] = {
+"bmp2tiff --- convert Windows BMP files to TIFF",
+"usage: bmp2tiff [options] input.bmp [input2.bmp ...] output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts]compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+" -o out.tif write output to out.tif",
+" -h this help message",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/fax2ps.c b/tiff/tools/fax2ps.c
new file mode 100644
index 0000000..b2611b9
--- /dev/null
+++ b/tiff/tools/fax2ps.c
@@ -0,0 +1,446 @@
+/* $Id: fax2ps.c,v 1.22.2.1 2010-06-08 18:50:43 bfriesen Exp $" */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+#include "tif_config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+float defxres = 204.; /* default x resolution (pixels/inch) */
+float defyres = 98.; /* default y resolution (lines/inch) */
+const float half = 0.5;
+const float points = 72.0;
+float pageWidth = 0; /* image page width (inches) */
+float pageHeight = 0; /* image page length (inches) */
+int scaleToPage = 0; /* if true, scale raster to page dimensions */
+int totalPages = 0; /* total # pages printed */
+int row; /* current output row */
+int maxline = 512; /* max output line of PostScript */
+
+/*
+ * Turn a bit-mapped scanline into the appropriate sequence
+ * of PostScript characters to be rendered.
+ *
+ * Original version written by Bret D. Whissel,
+ * Florida State University Meteorology Department
+ * March 13-15, 1995.
+ */
+static void
+printruns(unsigned char* buf, uint32* runs, uint32* erun, uint32 lastx)
+{
+ static struct {
+ char white, black;
+ unsigned short width;
+ } WBarr[] = {
+ { 'd', 'n', 512 }, { 'e', 'o', 256 }, { 'f', 'p', 128 },
+ { 'g', 'q', 64 }, { 'h', 'r', 32 }, { 'i', 's', 16 },
+ { 'j', 't', 8 }, { 'k', 'u', 4 }, { 'l', 'v', 2 },
+ { 'm', 'w', 1 }
+ };
+ static char* svalue =
+ " !\"#$&'*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abc";
+ int colormode = 1; /* 0 for white, 1 for black */
+ uint32 runlength = 0;
+ int n = maxline;
+ uint32 x = 0;
+ int l;
+
+ (void) buf;
+ printf("%d m(", row++);
+ while (runs < erun) {
+ if (runlength <= 0) {
+ colormode ^= 1;
+ runlength = *runs++;
+ if (x+runlength > lastx)
+ runlength = runs[-1] = lastx-x;
+ x += runlength;
+ if (!colormode && runs == erun)
+ break; /* don't bother printing the final white run */
+ }
+ /*
+ * If a runlength is greater than 6 pixels, then spit out
+ * black or white characters until the runlength drops to
+ * 6 or less. Once a runlength is <= 6, then combine black
+ * and white runlengths until a 6-pixel pattern is obtained.
+ * Then write out the special character. Six-pixel patterns
+ * were selected since 64 patterns is the largest power of
+ * two less than the 92 "easily printable" PostScript
+ * characters (i.e., no escape codes or octal chars).
+ */
+ l = 0;
+ while (runlength > 6) { /* Run is greater than six... */
+ if (runlength >= WBarr[l].width) {
+ if (n == 0) {
+ putchar('\n');
+ n = maxline;
+ }
+ putchar(colormode ? WBarr[l].black : WBarr[l].white), n--;
+ runlength -= WBarr[l].width;
+ } else
+ l++;
+ }
+ while (runlength > 0 && runlength <= 6) {
+ uint32 bitsleft = 6;
+ int t = 0;
+ while (bitsleft) {
+ if (runlength <= bitsleft) {
+ if (colormode)
+ t |= ((1 << runlength)-1) << (bitsleft-runlength);
+ bitsleft -= runlength;
+ runlength = 0;
+ if (bitsleft) {
+ if (runs >= erun)
+ break;
+ colormode ^= 1;
+ runlength = *runs++;
+ if (x+runlength > lastx)
+ runlength = runs[-1] = lastx-x;
+ x += runlength;
+ }
+ } else { /* runlength exceeds bits left */
+ if (colormode)
+ t |= ((1 << bitsleft)-1);
+ runlength -= bitsleft;
+ bitsleft = 0;
+ }
+ }
+ if (n == 0) {
+ putchar('\n');
+ n = maxline;
+ }
+ putchar(svalue[t]), n--;
+ }
+ }
+ printf(")s\n");
+}
+
+/*
+ * Create a special PostScript font for printing FAX documents. By taking
+ * advantage of the font-cacheing mechanism, a substantial speed-up in
+ * rendering time is realized.
+ */
+static void
+emitFont(FILE* fd)
+{
+ static const char* fontPrologue[] = {
+ "/newfont 10 dict def newfont begin /FontType 3 def /FontMatrix [1",
+ "0 0 1 0 0] def /FontBBox [0 0 512 1] def /Encoding 256 array def",
+ "0 1 31{Encoding exch /255 put}for 120 1 255{Encoding exch /255",
+ "put}for Encoding 37 /255 put Encoding 40 /255 put Encoding 41 /255",
+ "put Encoding 92 /255 put /count 0 def /ls{Encoding exch count 3",
+ "string cvs cvn put /count count 1 add def}def 32 1 36{ls}for",
+ "38 1 39{ls}for 42 1 91{ls}for 93 1 99{ls}for /count 100",
+ "def 100 1 119{ls}for /CharDict 5 dict def CharDict begin /white",
+ "{dup 255 eq{pop}{1 dict begin 100 sub neg 512 exch bitshift",
+ "/cw exch def cw 0 0 0 cw 1 setcachedevice end}ifelse}def /black",
+ "{dup 255 eq{pop}{1 dict begin 110 sub neg 512 exch bitshift",
+ "/cw exch def cw 0 0 0 cw 1 setcachedevice 0 0 moveto cw 0 rlineto",
+ "0 1 rlineto cw neg 0 rlineto closepath fill end}ifelse}def /numbuild",
+ "{dup 255 eq{pop}{6 0 0 0 6 1 setcachedevice 0 1 5{0 moveto",
+ "dup 32 and 32 eq{1 0 rlineto 0 1 rlineto -1 0 rlineto closepath",
+ "fill newpath}if 1 bitshift}for pop}ifelse}def /.notdef {}",
+ "def /255 {}def end /BuildChar{exch begin dup 110 ge{Encoding",
+ "exch get 3 string cvs cvi CharDict /black get}{dup 100 ge {Encoding",
+ "exch get 3 string cvs cvi CharDict /white get}{Encoding exch get",
+ "3 string cvs cvi CharDict /numbuild get}ifelse}ifelse exec end",
+ "}def end /Bitfont newfont definefont 1 scalefont setfont",
+ NULL
+ };
+ int i;
+ for (i = 0; fontPrologue[i] != NULL; i++)
+ fprintf(fd, "%s\n", fontPrologue[i]);
+}
+
+void
+printTIF(TIFF* tif, uint16 pageNumber)
+{
+ uint32 w, h;
+ uint16 unit, compression;
+ float xres, yres, scale = 1.0;
+ tstrip_t s, ns;
+ time_t creation_time;
+
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
+ if (!TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression)
+ || compression < COMPRESSION_CCITTRLE
+ || compression > COMPRESSION_CCITT_T6)
+ return;
+ if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres) || !xres) {
+ TIFFWarning(TIFFFileName(tif),
+ "No x-resolution, assuming %g dpi", defxres);
+ xres = defxres;
+ }
+ if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres) || !yres) {
+ TIFFWarning(TIFFFileName(tif),
+ "No y-resolution, assuming %g lpi", defyres);
+ yres = defyres; /* XXX */
+ }
+ if (TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &unit) &&
+ unit == RESUNIT_CENTIMETER) {
+ xres *= 2.54F;
+ yres *= 2.54F;
+ }
+ if (pageWidth == 0)
+ pageWidth = w / xres;
+ if (pageHeight == 0)
+ pageHeight = h / yres;
+
+ printf("%%!PS-Adobe-3.0\n");
+ printf("%%%%Creator: fax2ps\n");
+#ifdef notdef
+ printf("%%%%Title: %s\n", file);
+#endif
+ creation_time = time(0);
+ printf("%%%%CreationDate: %s", ctime(&creation_time));
+ printf("%%%%Origin: 0 0\n");
+ printf("%%%%BoundingBox: 0 0 %u %u\n",
+ (int)(pageWidth * points), (int)(pageHeight * points)); /* XXX */
+ printf("%%%%Pages: (atend)\n");
+ printf("%%%%EndComments\n");
+ printf("%%%%BeginProlog\n");
+ emitFont(stdout);
+ printf("/d{bind def}def\n"); /* bind and def proc */
+ printf("/m{0 exch moveto}d\n");
+ printf("/s{show}d\n");
+ printf("/p{showpage}d \n"); /* end page */
+ printf("%%%%EndProlog\n");
+ printf("%%%%Page: \"%u\" %u\n", pageNumber, pageNumber);
+ printf("/$pageTop save def gsave\n");
+ if (scaleToPage)
+ scale = pageHeight / (h/yres) < pageWidth / (w/xres) ?
+ pageHeight / (h/yres) : pageWidth / (w/xres);
+ printf("%g %g translate\n",
+ points * (pageWidth - scale*w/xres) * half,
+ points * (scale*h/yres + (pageHeight - scale*h/yres) * half));
+ printf("%g %g scale\n", points/xres*scale, -points/yres*scale);
+ printf("0 setgray\n");
+ TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, printruns);
+ ns = TIFFNumberOfStrips(tif);
+ row = 0;
+ for (s = 0; s < ns; s++)
+ (void) TIFFReadEncodedStrip(tif, s, (tdata_t) NULL, (tsize_t) -1);
+ printf("p\n");
+ printf("grestore $pageTop restore\n");
+ totalPages++;
+}
+
+#define GetPageNumber(tif) \
+TIFFGetField(tif, TIFFTAG_PAGENUMBER, &pn, &ptotal)
+
+int
+findPage(TIFF* tif, uint16 pageNumber)
+{
+ uint16 pn = (uint16) -1;
+ uint16 ptotal = (uint16) -1;
+ if (GetPageNumber(tif)) {
+ while (pn != pageNumber && TIFFReadDirectory(tif) && GetPageNumber(tif))
+ ;
+ return (pn == pageNumber);
+ } else
+ return (TIFFSetDirectory(tif, (tdir_t)(pageNumber-1)));
+}
+
+void
+fax2ps(TIFF* tif, uint16 npages, uint16* pages, char* filename)
+{
+ if (npages > 0) {
+ uint16 pn, ptotal;
+ int i;
+
+ if (!GetPageNumber(tif))
+ fprintf(stderr, "%s: No page numbers, counting directories.\n",
+ filename);
+ for (i = 0; i < npages; i++) {
+ if (findPage(tif, pages[i]))
+ printTIF(tif, pages[i]);
+ else
+ fprintf(stderr, "%s: No page number %d\n", filename, pages[i]);
+ }
+ } else {
+ uint16 pageNumber = 0;
+ do
+ printTIF(tif, pageNumber++);
+ while (TIFFReadDirectory(tif));
+ }
+}
+
+#undef GetPageNumber
+
+static int
+pcompar(const void* va, const void* vb)
+{
+ const int* pa = (const int*) va;
+ const int* pb = (const int*) vb;
+ return (*pa - *pb);
+}
+
+static void usage(int code);
+
+int
+main(int argc, char** argv)
+{
+ extern int optind;
+ extern char* optarg;
+ uint16 *pages = NULL, npages = 0, pageNumber;
+ int c, dowarnings = 0; /* if 1, enable library warnings */
+ TIFF* tif;
+
+ while ((c = getopt(argc, argv, "l:p:x:y:W:H:wS")) != -1)
+ switch (c) {
+ case 'H': /* page height */
+ pageHeight = (float)atof(optarg);
+ break;
+ case 'S': /* scale to page */
+ scaleToPage = 1;
+ break;
+ case 'W': /* page width */
+ pageWidth = (float)atof(optarg);
+ break;
+ case 'p': /* print specific page */
+ pageNumber = (uint16)atoi(optarg);
+ if (pages)
+ pages = (uint16*) realloc(pages, (npages+1)*sizeof(uint16));
+ else
+ pages = (uint16*) malloc(sizeof(uint16));
+ pages[npages++] = pageNumber;
+ break;
+ case 'w':
+ dowarnings = 1;
+ break;
+ case 'x':
+ defxres = (float)atof(optarg);
+ break;
+ case 'y':
+ defyres = (float)atof(optarg);
+ break;
+ case 'l':
+ maxline = atoi(optarg);
+ break;
+ case '?':
+ usage(-1);
+ }
+ if (npages > 0)
+ qsort(pages, npages, sizeof(uint16), pcompar);
+ if (!dowarnings)
+ TIFFSetWarningHandler(0);
+ if (optind < argc) {
+ do {
+ tif = TIFFOpen(argv[optind], "r");
+ if (tif) {
+ fax2ps(tif, npages, pages, argv[optind]);
+ TIFFClose(tif);
+ } else
+ fprintf(stderr, "%s: Can not open, or not a TIFF file.\n",
+ argv[optind]);
+ } while (++optind < argc);
+ } else {
+ int n;
+ FILE* fd;
+ char buf[16*1024];
+
+ fd = tmpfile();
+ if (fd == NULL) {
+ fprintf(stderr, "Could not create temporary file, exiting.\n");
+ fclose(fd);
+ exit(-2);
+ }
+#if defined(HAVE_SETMODE) && defined(O_BINARY)
+ setmode(fileno(stdin), O_BINARY);
+#endif
+ while ((n = read(fileno(stdin), buf, sizeof (buf))) > 0)
+ write(fileno(fd), buf, n);
+ lseek(fileno(fd), 0, SEEK_SET);
+#if defined(_WIN32) && defined(USE_WIN32_FILEIO)
+ tif = TIFFFdOpen(_get_osfhandle(fileno(fd)), "temp", "r");
+#else
+ tif = TIFFFdOpen(fileno(fd), "temp", "r");
+#endif
+ if (tif) {
+ fax2ps(tif, npages, pages, "<stdin>");
+ TIFFClose(tif);
+ } else
+ fprintf(stderr, "Can not open, or not a TIFF file.\n");
+ fclose(fd);
+ }
+ printf("%%%%Trailer\n");
+ printf("%%%%Pages: %u\n", totalPages);
+ printf("%%%%EOF\n");
+
+ return (0);
+}
+
+char* stuff[] = {
+"usage: fax2ps [options] [input.tif ...]",
+"where options are:",
+" -w suppress warning messages",
+" -l chars set maximum output line length for generated PostScript",
+" -p page# select page to print (can use multiple times)",
+" -x xres set default horizontal resolution of input data (dpi)",
+" -y yres set default vertical resolution of input data (lpi)",
+" -S scale output to page size",
+" -W width set output page width (inches), default is 8.5",
+" -H height set output page height (inches), default is 11",
+NULL
+};
+
+static void
+usage(int code)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(code);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/fax2tiff.c b/tiff/tools/fax2tiff.c
new file mode 100644
index 0000000..951b568
--- /dev/null
+++ b/tiff/tools/fax2tiff.c
@@ -0,0 +1,465 @@
+/* $Id: fax2tiff.c,v 1.19.2.1 2010-06-08 18:50:43 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * Convert a CCITT Group 3 or 4 FAX file to TIFF Group 3 or 4 format.
+ */
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h> /* should have atof & getopt */
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffiop.h"
+
+#ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+#endif
+#ifndef EXIT_FAILURE
+# define EXIT_FAILURE 1
+#endif
+
+#define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
+
+TIFF *faxTIFF;
+char *rowbuf;
+char *refbuf;
+
+uint32 xsize = 1728;
+int verbose;
+int stretch;
+uint16 badfaxrun;
+uint32 badfaxlines;
+
+int copyFaxFile(TIFF* tifin, TIFF* tifout);
+static void usage(void);
+
+int
+main(int argc, char* argv[])
+{
+ FILE *in;
+ TIFF *out = NULL;
+ TIFFErrorHandler whandler = NULL;
+ int compression_in = COMPRESSION_CCITTFAX3;
+ int compression_out = COMPRESSION_CCITTFAX3;
+ int fillorder_in = FILLORDER_LSB2MSB;
+ int fillorder_out = FILLORDER_LSB2MSB;
+ uint32 group3options_in = 0; /* 1d-encoded */
+ uint32 group3options_out = 0; /* 1d-encoded */
+ uint32 group4options_in = 0; /* compressed */
+ uint32 group4options_out = 0; /* compressed */
+ uint32 defrowsperstrip = (uint32) 0;
+ uint32 rowsperstrip;
+ int photometric_in = PHOTOMETRIC_MINISWHITE;
+ int photometric_out = PHOTOMETRIC_MINISWHITE;
+ int mode = FAXMODE_CLASSF;
+ int rows;
+ int c;
+ int pn, npages;
+ float resY = 196.0;
+ extern int optind;
+ extern char* optarg;
+
+
+ while ((c = getopt(argc, argv, "R:X:o:1234ABLMPUW5678abcflmprsuvwz?")) != -1)
+ switch (c) {
+ /* input-related options */
+ case '3': /* input is g3-encoded */
+ compression_in = COMPRESSION_CCITTFAX3;
+ break;
+ case '4': /* input is g4-encoded */
+ compression_in = COMPRESSION_CCITTFAX4;
+ break;
+ case 'U': /* input is uncompressed (g3 and g4) */
+ group3options_in |= GROUP3OPT_UNCOMPRESSED;
+ group4options_in |= GROUP4OPT_UNCOMPRESSED;
+ break;
+ case '1': /* input is 1d-encoded (g3 only) */
+ group3options_in &= ~GROUP3OPT_2DENCODING;
+ break;
+ case '2': /* input is 2d-encoded (g3 only) */
+ group3options_in |= GROUP3OPT_2DENCODING;
+ break;
+ case 'P': /* input has not-aligned EOL (g3 only) */
+ group3options_in &= ~GROUP3OPT_FILLBITS;
+ break;
+ case 'A': /* input has aligned EOL (g3 only) */
+ group3options_in |= GROUP3OPT_FILLBITS;
+ break;
+ case 'W': /* input has 0 mean white */
+ photometric_in = PHOTOMETRIC_MINISWHITE;
+ break;
+ case 'B': /* input has 0 mean black */
+ photometric_in = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 'L': /* input has lsb-to-msb fillorder */
+ fillorder_in = FILLORDER_LSB2MSB;
+ break;
+ case 'M': /* input has msb-to-lsb fillorder */
+ fillorder_in = FILLORDER_MSB2LSB;
+ break;
+ case 'R': /* input resolution */
+ resY = (float) atof(optarg);
+ break;
+ case 'X': /* input width */
+ xsize = (uint32) atoi(optarg);
+ break;
+
+ /* output-related options */
+ case '7': /* generate g3-encoded output */
+ compression_out = COMPRESSION_CCITTFAX3;
+ break;
+ case '8': /* generate g4-encoded output */
+ compression_out = COMPRESSION_CCITTFAX4;
+ break;
+ case 'u': /* generate uncompressed output (g3 and g4) */
+ group3options_out |= GROUP3OPT_UNCOMPRESSED;
+ group4options_out |= GROUP4OPT_UNCOMPRESSED;
+ break;
+ case '5': /* generate 1d-encoded output (g3 only) */
+ group3options_out &= ~GROUP3OPT_2DENCODING;
+ break;
+ case '6': /* generate 2d-encoded output (g3 only) */
+ group3options_out |= GROUP3OPT_2DENCODING;
+ break;
+ case 'c': /* generate "classic" g3 format */
+ mode = FAXMODE_CLASSIC;
+ break;
+ case 'f': /* generate Class F format */
+ mode = FAXMODE_CLASSF;
+ break;
+ case 'm': /* output's fillorder is msb-to-lsb */
+ fillorder_out = FILLORDER_MSB2LSB;
+ break;
+ case 'l': /* output's fillorder is lsb-to-msb */
+ fillorder_out = FILLORDER_LSB2MSB;
+ break;
+ case 'o':
+ out = TIFFOpen(optarg, "w");
+ if (out == NULL) {
+ fprintf(stderr,
+ "%s: Can not create or open %s\n",
+ argv[0], optarg);
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'a': /* generate EOL-aligned output (g3 only) */
+ group3options_out |= GROUP3OPT_FILLBITS;
+ break;
+ case 'p': /* generate not EOL-aligned output (g3 only) */
+ group3options_out &= ~GROUP3OPT_FILLBITS;
+ break;
+ case 'r': /* rows/strip */
+ defrowsperstrip = atol(optarg);
+ break;
+ case 's': /* stretch image by dup'ng scanlines */
+ stretch = 1;
+ break;
+ case 'w': /* undocumented -- for testing */
+ photometric_out = PHOTOMETRIC_MINISWHITE;
+ break;
+ case 'b': /* undocumented -- for testing */
+ photometric_out = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 'z': /* undocumented -- for testing */
+ compression_out = COMPRESSION_LZW;
+ break;
+ case 'v': /* -v for info */
+ verbose++;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ npages = argc - optind;
+ if (npages < 1)
+ usage();
+
+ rowbuf = _TIFFmalloc(TIFFhowmany8(xsize));
+ refbuf = _TIFFmalloc(TIFFhowmany8(xsize));
+ if (rowbuf == NULL || refbuf == NULL) {
+ fprintf(stderr, "%s: Not enough memory\n", argv[0]);
+ return (EXIT_FAILURE);
+ }
+
+ if (out == NULL) {
+ out = TIFFOpen("fax.tif", "w");
+ if (out == NULL) {
+ fprintf(stderr, "%s: Can not create fax.tif\n",
+ argv[0]);
+ return (EXIT_FAILURE);
+ }
+ }
+
+ faxTIFF = TIFFClientOpen("(FakeInput)", "w",
+ /* TIFFClientOpen() fails if we don't set existing value here */
+ TIFFClientdata(out),
+ TIFFGetReadProc(out), TIFFGetWriteProc(out),
+ TIFFGetSeekProc(out), TIFFGetCloseProc(out),
+ TIFFGetSizeProc(out), TIFFGetMapFileProc(out),
+ TIFFGetUnmapFileProc(out));
+ if (faxTIFF == NULL) {
+ fprintf(stderr, "%s: Can not create fake input file\n",
+ argv[0]);
+ return (EXIT_FAILURE);
+ }
+ TIFFSetMode(faxTIFF, O_RDONLY);
+ TIFFSetField(faxTIFF, TIFFTAG_IMAGEWIDTH, xsize);
+ TIFFSetField(faxTIFF, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(faxTIFF, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(faxTIFF, TIFFTAG_FILLORDER, fillorder_in);
+ TIFFSetField(faxTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(faxTIFF, TIFFTAG_PHOTOMETRIC, photometric_in);
+ TIFFSetField(faxTIFF, TIFFTAG_YRESOLUTION, resY);
+ TIFFSetField(faxTIFF, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+
+ /* NB: this must be done after directory info is setup */
+ TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, compression_in);
+ if (compression_in == COMPRESSION_CCITTFAX3)
+ TIFFSetField(faxTIFF, TIFFTAG_GROUP3OPTIONS, group3options_in);
+ else if (compression_in == COMPRESSION_CCITTFAX4)
+ TIFFSetField(faxTIFF, TIFFTAG_GROUP4OPTIONS, group4options_in);
+ for (pn = 0; optind < argc; pn++, optind++) {
+ in = fopen(argv[optind], "rb");
+ if (in == NULL) {
+ fprintf(stderr,
+ "%s: %s: Can not open\n", argv[0], argv[optind]);
+ continue;
+ }
+#if defined(_WIN32) && defined(USE_WIN32_FILEIO)
+ TIFFSetClientdata(faxTIFF, (thandle_t)_get_osfhandle(fileno(in)));
+#else
+ TIFFSetClientdata(faxTIFF, (thandle_t)fileno(in));
+#endif
+ TIFFSetFileName(faxTIFF, (const char*)argv[optind]);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, xsize);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression_out);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric_out);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
+ switch (compression_out) {
+ /* g3 */
+ case COMPRESSION_CCITTFAX3:
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS,
+ group3options_out);
+ TIFFSetField(out, TIFFTAG_FAXMODE, mode);
+ rowsperstrip =
+ (defrowsperstrip)?defrowsperstrip:(uint32)-1L;
+ break;
+
+ /* g4 */
+ case COMPRESSION_CCITTFAX4:
+ TIFFSetField(out, TIFFTAG_GROUP4OPTIONS,
+ group4options_out);
+ TIFFSetField(out, TIFFTAG_FAXMODE, mode);
+ rowsperstrip =
+ (defrowsperstrip)?defrowsperstrip:(uint32)-1L;
+ break;
+
+ default:
+ rowsperstrip = (defrowsperstrip) ?
+ defrowsperstrip : TIFFDefaultStripSize(out, 0);
+ }
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder_out);
+ TIFFSetField(out, TIFFTAG_SOFTWARE, "fax2tiff");
+ TIFFSetField(out, TIFFTAG_XRESOLUTION, 204.0);
+ if (!stretch) {
+ TIFFGetField(faxTIFF, TIFFTAG_YRESOLUTION, &resY);
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, resY);
+ } else
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, 196.);
+ TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pn, npages);
+
+ if (!verbose)
+ whandler = TIFFSetWarningHandler(NULL);
+ rows = copyFaxFile(faxTIFF, out);
+ fclose(in);
+ if (!verbose)
+ (void) TIFFSetWarningHandler(whandler);
+
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, rows);
+
+ if (verbose) {
+ fprintf(stderr, "%s:\n", argv[optind]);
+ fprintf(stderr, "%d rows in input\n", rows);
+ fprintf(stderr, "%ld total bad rows\n",
+ (long) badfaxlines);
+ fprintf(stderr, "%d max consecutive bad rows\n", badfaxrun);
+ }
+ if (compression_out == COMPRESSION_CCITTFAX3 &&
+ mode == FAXMODE_CLASSF) {
+ TIFFSetField(out, TIFFTAG_BADFAXLINES, badfaxlines);
+ TIFFSetField(out, TIFFTAG_CLEANFAXDATA, badfaxlines ?
+ CLEANFAXDATA_REGENERATED : CLEANFAXDATA_CLEAN);
+ TIFFSetField(out, TIFFTAG_CONSECUTIVEBADFAXLINES, badfaxrun);
+ }
+ TIFFWriteDirectory(out);
+ }
+ TIFFClose(out);
+ _TIFFfree(rowbuf);
+ _TIFFfree(refbuf);
+ return (EXIT_SUCCESS);
+}
+
+int
+copyFaxFile(TIFF* tifin, TIFF* tifout)
+{
+ uint32 row;
+ uint32 linesize = TIFFhowmany8(xsize);
+ uint16 badrun;
+ int ok;
+
+ tifin->tif_rawdatasize = TIFFGetFileSize(tifin);
+ tifin->tif_rawdata = _TIFFmalloc(tifin->tif_rawdatasize);
+ if (tifin->tif_rawdata == NULL) {
+ TIFFError(tifin->tif_name, "Not enough memory");
+ return (0);
+ }
+ if (!ReadOK(tifin, tifin->tif_rawdata, tifin->tif_rawdatasize)) {
+ TIFFError(tifin->tif_name, "Read error at scanline 0");
+ return (0);
+ }
+ tifin->tif_rawcp = tifin->tif_rawdata;
+ tifin->tif_rawcc = tifin->tif_rawdatasize;
+
+ (*tifin->tif_setupdecode)(tifin);
+ (*tifin->tif_predecode)(tifin, (tsample_t) 0);
+ tifin->tif_row = 0;
+ badfaxlines = 0;
+ badfaxrun = 0;
+
+ _TIFFmemset(refbuf, 0, linesize);
+ row = 0;
+ badrun = 0; /* current run of bad lines */
+ while (tifin->tif_rawcc > 0) {
+ ok = (*tifin->tif_decoderow)(tifin, (tdata_t) rowbuf,
+ linesize, 0);
+ if (!ok) {
+ badfaxlines++;
+ badrun++;
+ /* regenerate line from previous good line */
+ _TIFFmemcpy(rowbuf, refbuf, linesize);
+ } else {
+ if (badrun > badfaxrun)
+ badfaxrun = badrun;
+ badrun = 0;
+ _TIFFmemcpy(refbuf, rowbuf, linesize);
+ }
+ tifin->tif_row++;
+
+ if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) {
+ fprintf(stderr, "%s: Write error at row %ld.\n",
+ tifout->tif_name, (long) row);
+ break;
+ }
+ row++;
+ if (stretch) {
+ if (TIFFWriteScanline(tifout, rowbuf, row, 0) < 0) {
+ fprintf(stderr, "%s: Write error at row %ld.\n",
+ tifout->tif_name, (long) row);
+ break;
+ }
+ row++;
+ }
+ }
+ if (badrun > badfaxrun)
+ badfaxrun = badrun;
+ _TIFFfree(tifin->tif_rawdata);
+ return (row);
+}
+
+char* stuff[] = {
+"usage: fax2tiff [options] input.raw...",
+"where options are:",
+" -3 input data is G3-encoded [default]",
+" -4 input data is G4-encoded",
+" -U input data is uncompressed (G3 or G4)",
+" -1 input data is 1D-encoded (G3 only) [default]",
+" -2 input data is 2D-encoded (G3 only)",
+" -P input is not EOL-aligned (G3 only) [default]",
+" -A input is EOL-aligned (G3 only)",
+" -M input data has MSB2LSB bit order",
+" -L input data has LSB2MSB bit order [default]",
+" -B input data has min 0 means black",
+" -W input data has min 0 means white [default]",
+" -R # input data has # resolution (lines/inch) [default is 196]",
+" -X # input data has # width [default is 1728]",
+"",
+" -o out.tif write output to out.tif",
+" -7 generate G3-encoded output [default]",
+" -8 generate G4-encoded output",
+" -u generate uncompressed output (G3 or G4)",
+" -5 generate 1D-encoded output (G3 only)",
+" -6 generate 2D-encoded output (G3 only) [default]",
+" -p generate not EOL-aligned output (G3 only)",
+" -a generate EOL-aligned output (G3 only) [default]",
+" -c generate \"classic\" TIFF format",
+" -f generate TIFF Class F (TIFF/F) format [default]",
+" -m output fill order is MSB2LSB",
+" -l output fill order is LSB2MSB [default]",
+" -r # make each strip have no more than # rows",
+" -s stretch image by duplicating scanlines",
+" -v print information about conversion work",
+" -z generate LZW compressed output",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(EXIT_FAILURE);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/gif2tiff.c b/tiff/tools/gif2tiff.c
new file mode 100644
index 0000000..9c2cfa4
--- /dev/null
+++ b/tiff/tools/gif2tiff.c
@@ -0,0 +1,522 @@
+/* $Id: gif2tiff.c,v 1.8.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/*
+ * convert a GIF file into a TIFF file.
+ * based on Paul Haeberli's fromgif program which in turn is
+ * based on a GIF file reader by Marcel J.E. Mol March 23 1989
+ *
+ * if input is 320 by 200 pixel aspect is probably 1.2
+ * if input is 640 350 pixel aspect is probably 1.37
+ *
+ */
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define GIFGAMMA (1.5) /* smaller makes output img brighter */
+#define IMAX 0xffff /* max intensity value */
+#define EXTRAFUDGE 128 /* some people write BAD .gif files */
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+unsigned short gamtab[256];
+
+void
+makegamtab(float gam)
+{
+ int i;
+
+ for(i=0; i<256; i++)
+ gamtab[i] = (unsigned short) (IMAX*pow(i/255.0,gam)+0.5);
+}
+
+char* stuff[] = {
+"usage: gif2tiff [options] input.gif output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+#define COLSIZE 256
+
+unsigned char *stackp;
+unsigned int prefix[4096];
+unsigned char suffix[4096];
+unsigned char stack[4096];
+int datasize,codesize,codemask; /* Decoder working variables */
+int clear,eoi; /* Special code values */
+int avail, oldcode;
+
+FILE *infile;
+int global; /* Is there a global color map? */
+int globalbits; /* Number of bits of global colors */
+unsigned char globalmap[COLSIZE][3];/* RGB values for global color map */
+unsigned char *raster; /* Decoded image data */
+unsigned long width, height;
+unsigned short red[COLSIZE];
+unsigned short green[COLSIZE];
+unsigned short blue[COLSIZE];
+char *filename, *imagename;
+
+static uint16 compression = COMPRESSION_PACKBITS;
+static uint16 predictor = 0;
+static uint32 rowsperstrip = (uint32) -1;
+static int processCompressOptions(char*);
+
+int convert(void);
+int checksignature(void);
+void readscreen(void);
+int readgifimage(char*);
+void readextension(void);
+int readraster(void);
+int process(int, unsigned char**);
+void initcolors(unsigned char [COLSIZE][3], int);
+void rasterize(int, char*);
+
+int
+main(int argc, char* argv[])
+{
+ extern int optind;
+ extern char *optarg;
+ int c, status;
+
+ while ((c = getopt(argc, argv, "c:r:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+
+ makegamtab(GIFGAMMA);
+ filename = argv[optind];
+ imagename = argv[optind+1];
+ if ((infile = fopen(imagename, "rb")) != NULL) {
+ int c;
+ fclose(infile);
+ printf("overwrite %s? ", imagename); fflush(stdout);
+ c = getc(stdin);
+ if (c != 'y' && c != 'Y')
+ return (1);
+ }
+ if ((infile = fopen(filename, "rb")) == NULL) {
+ perror(filename);
+ return (1);
+ }
+ status = convert();
+ fclose(infile);
+ return (status);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+int
+convert(void)
+{
+ int ch;
+ char* mode = "w";
+
+ if (!checksignature())
+ return (-1);
+ readscreen();
+ while ((ch = getc(infile)) != ';' && ch != EOF) {
+ switch (ch) {
+ case '\0': break; /* this kludge for non-standard files */
+ case ',': if (!readgifimage(mode))
+ return (-1);
+ mode = "a"; /* subsequent images append */
+ break;
+ case '!': readextension();
+ break;
+ default: fprintf(stderr, "illegal GIF block type\n");
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+int
+checksignature(void)
+{
+ char buf[6];
+
+ fread(buf,1,6,infile);
+ if (strncmp(buf,"GIF",3)) {
+ fprintf(stderr, "file is not a GIF file\n");
+ return 0;
+ }
+ if (strncmp(&buf[3],"87a",3)) {
+ fprintf(stderr, "unknown GIF version number\n");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * readscreen -
+ * Get information which is global to all the images stored
+ * in the file
+ */
+void
+readscreen(void)
+{
+ unsigned char buf[7];
+
+ fread(buf,1,7,infile);
+ global = buf[4] & 0x80;
+ if (global) {
+ globalbits = (buf[4] & 0x07) + 1;
+ fread(globalmap,3,1<<globalbits,infile);
+ }
+}
+
+int
+readgifimage(char* mode)
+{
+ unsigned char buf[9];
+ int local, interleaved;
+ unsigned char localmap[256][3];
+ int localbits;
+ int status;
+
+ if (fread(buf, 1, 9, infile) == 0) {
+ perror(filename);
+ return (0);
+ }
+ width = buf[4] + (buf[5] << 8);
+ height = buf[6] + (buf[7] << 8);
+ local = buf[8] & 0x80;
+ interleaved = buf[8] & 0x40;
+
+ if (local == 0 && global == 0) {
+ fprintf(stderr, "no colormap present for image\n");
+ return (0);
+ }
+ if ((raster = (unsigned char*) _TIFFmalloc(width*height+EXTRAFUDGE)) == NULL) {
+ fprintf(stderr, "not enough memory for image\n");
+ return (0);
+ }
+ if (local) {
+ localbits = (buf[8] & 0x7) + 1;
+
+ fprintf(stderr, " local colors: %d\n", 1<<localbits);
+
+ fread(localmap, 3, 1<<localbits, infile);
+ initcolors(localmap, 1<<localbits);
+ } else if (global) {
+ initcolors(globalmap, 1<<globalbits);
+ }
+ if ((status = readraster()))
+ rasterize(interleaved, mode);
+ _TIFFfree(raster);
+ return status;
+}
+
+/*
+ * readextension -
+ * Read a GIF extension block (and do nothing with it).
+ *
+ */
+void
+readextension(void)
+{
+ int count;
+ char buf[255];
+
+ (void) getc(infile);
+ while ((count = getc(infile)))
+ fread(buf, 1, count, infile);
+}
+
+/*
+ * readraster -
+ * Decode a raster image
+ *
+ */
+int
+readraster(void)
+{
+ unsigned char *fill = raster;
+ unsigned char buf[255];
+ register int bits=0;
+ register unsigned long datum=0;
+ register unsigned char *ch;
+ register int count, code;
+ int status = 1;
+
+ datasize = getc(infile);
+ clear = 1 << datasize;
+ eoi = clear + 1;
+ avail = clear + 2;
+ oldcode = -1;
+ codesize = datasize + 1;
+ codemask = (1 << codesize) - 1;
+ for (code = 0; code < clear; code++) {
+ prefix[code] = 0;
+ suffix[code] = code;
+ }
+ stackp = stack;
+ for (count = getc(infile); count > 0; count = getc(infile)) {
+ fread(buf,1,count,infile);
+ for (ch=buf; count-- > 0; ch++) {
+ datum += (unsigned long) *ch << bits;
+ bits += 8;
+ while (bits >= codesize) {
+ code = datum & codemask;
+ datum >>= codesize;
+ bits -= codesize;
+ if (code == eoi) { /* This kludge put in */
+ goto exitloop; /* because some GIF files*/
+ } /* aren't standard */
+ if (!process(code, &fill)) {
+ status = 0;
+ goto exitloop;
+ }
+ }
+ }
+ if (fill >= raster + width*height) {
+ fprintf(stderr, "raster full before eoi code\n");
+ break;
+ }
+ }
+exitloop:
+ if (fill != raster + width*height) {
+ fprintf(stderr, "warning: wrong rastersize: %ld bytes\n",
+ (long) (fill-raster));
+ fprintf(stderr, " instead of %ld bytes\n",
+ (long) width*height);
+ }
+ return status;
+}
+
+/*
+ * process -
+ * Process a compression code. "clear" resets the code table.
+ * Otherwise make a new code table entry, and output the bytes
+ * associated with the code.
+ */
+int
+process(register int code, unsigned char** fill)
+{
+ int incode;
+ static unsigned char firstchar;
+
+ if (code == clear) {
+ codesize = datasize + 1;
+ codemask = (1 << codesize) - 1;
+ avail = clear + 2;
+ oldcode = -1;
+ return 1;
+ }
+
+ if (oldcode == -1) {
+ *(*fill)++ = suffix[code];
+ firstchar = oldcode = code;
+ return 1;
+ }
+ if (code > avail) {
+ fprintf(stderr, "code %d too large for %d\n", code, avail);
+ return 0;
+ }
+
+ incode = code;
+ if (code == avail) { /* the first code is always < avail */
+ *stackp++ = firstchar;
+ code = oldcode;
+ }
+ while (code > clear) {
+ *stackp++ = suffix[code];
+ code = prefix[code];
+ }
+
+ *stackp++ = firstchar = suffix[code];
+ prefix[avail] = oldcode;
+ suffix[avail] = firstchar;
+ avail++;
+
+ if (((avail & codemask) == 0) && (avail < 4096)) {
+ codesize++;
+ codemask += avail;
+ }
+ oldcode = incode;
+ do {
+ *(*fill)++ = *--stackp;
+ } while (stackp > stack);
+ return 1;
+}
+
+/*
+ * initcolors -
+ * Convert a color map (local or global) to arrays with R, G and B
+ * values.
+ *
+ */
+void
+initcolors(unsigned char colormap[COLSIZE][3], int ncolors)
+{
+ register int i;
+
+ for (i = 0; i < ncolors; i++) {
+ red[i] = gamtab[colormap[i][0]];
+ green[i] = gamtab[colormap[i][1]];
+ blue[i] = gamtab[colormap[i][2]];
+ }
+}
+
+void
+rasterize(int interleaved, char* mode)
+{
+ register unsigned long row;
+ unsigned char *newras;
+ unsigned char *ras;
+ TIFF *tif;
+ tstrip_t strip;
+ tsize_t stripsize;
+
+ if ((newras = (unsigned char*) _TIFFmalloc(width*height+EXTRAFUDGE)) == NULL) {
+ fprintf(stderr, "not enough memory for image\n");
+ return;
+ }
+#define DRAWSEGMENT(offset, step) { \
+ for (row = offset; row < height; row += step) { \
+ _TIFFmemcpy(newras + row*width, ras, width);\
+ ras += width; \
+ } \
+ }
+ ras = raster;
+ if (interleaved) {
+ DRAWSEGMENT(0, 8);
+ DRAWSEGMENT(4, 8);
+ DRAWSEGMENT(2, 4);
+ DRAWSEGMENT(1, 2);
+ } else
+ DRAWSEGMENT(0, 1);
+#undef DRAWSEGMENT
+
+ tif = TIFFOpen(imagename, mode);
+ if (!tif) {
+ TIFFError(imagename,"Can not open output image");
+ exit(-1);
+ }
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) width);
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32) height);
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,
+ rowsperstrip = TIFFDefaultStripSize(tif, rowsperstrip));
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(tif, TIFFTAG_COLORMAP, red, green, blue);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ strip = 0;
+ stripsize = TIFFStripSize(tif);
+ for (row=0; row<height; row += rowsperstrip) {
+ if (TIFFWriteEncodedStrip(tif, strip, newras+row*width, stripsize) < 0)
+ break;
+ strip++;
+ }
+ TIFFClose(tif);
+
+ _TIFFfree(newras);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/pal2rgb.c b/tiff/tools/pal2rgb.c
new file mode 100644
index 0000000..ea5803f
--- /dev/null
+++ b/tiff/tools/pal2rgb.c
@@ -0,0 +1,431 @@
+/* $Id: pal2rgb.c,v 1.10.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+static void usage(void);
+static void cpTags(TIFF* in, TIFF* out);
+
+static int
+checkcmap(int n, uint16* r, uint16* g, uint16* b)
+{
+ while (n-- > 0)
+ if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+ return (16);
+ fprintf(stderr, "Warning, assuming 8-bit colormap.\n");
+ return (8);
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+
+static uint16 compression = (uint16) -1;
+static uint16 predictor = 0;
+static int quality = 75; /* JPEG quality */
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int processCompressOptions(char*);
+
+int
+main(int argc, char* argv[])
+{
+ uint16 bitspersample, shortv;
+ uint32 imagewidth, imagelength;
+ uint16 config = PLANARCONFIG_CONTIG;
+ uint32 rowsperstrip = (uint32) -1;
+ uint16 photometric = PHOTOMETRIC_RGB;
+ uint16 *rmap, *gmap, *bmap;
+ uint32 row;
+ int cmap = -1;
+ TIFF *in, *out;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "C:c:p:r:")) != -1)
+ switch (c) {
+ case 'C': /* force colormap interpretation */
+ cmap = atoi(optarg);
+ break;
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ config = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ config = PLANARCONFIG_CONTIG;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+ in = TIFFOpen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &shortv) ||
+ shortv != PHOTOMETRIC_PALETTE) {
+ fprintf(stderr, "%s: Expecting a palette image.\n",
+ argv[optind]);
+ return (-1);
+ }
+ if (!TIFFGetField(in, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
+ fprintf(stderr,
+ "%s: No colormap (not a valid palette image).\n",
+ argv[optind]);
+ return (-1);
+ }
+ bitspersample = 0;
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8) {
+ fprintf(stderr, "%s: Sorry, can only handle 8-bit images.\n",
+ argv[optind]);
+ return (-1);
+ }
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-2);
+ cpTags(in, out);
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
+ if (compression != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ else
+ TIFFGetField(in, TIFFTAG_COMPRESSION, &compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ else
+ photometric = PHOTOMETRIC_RGB;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip));
+ (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
+ if (cmap == -1)
+ cmap = checkcmap(1<<bitspersample, rmap, gmap, bmap);
+ if (cmap == 16) {
+ /*
+ * Convert 16-bit colormap to 8-bit.
+ */
+ int i;
+
+ for (i = (1<<bitspersample)-1; i >= 0; i--) {
+#define CVT(x) (((x) * 255) / ((1L<<16)-1))
+ rmap[i] = CVT(rmap[i]);
+ gmap[i] = CVT(gmap[i]);
+ bmap[i] = CVT(bmap[i]);
+ }
+ }
+ { unsigned char *ibuf, *obuf;
+ register unsigned char* pp;
+ register uint32 x;
+ ibuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(in));
+ obuf = (unsigned char*)_TIFFmalloc(TIFFScanlineSize(out));
+ switch (config) {
+ case PLANARCONFIG_CONTIG:
+ for (row = 0; row < imagelength; row++) {
+ if (!TIFFReadScanline(in, ibuf, row, 0))
+ goto done;
+ pp = obuf;
+ for (x = 0; x < imagewidth; x++) {
+ *pp++ = (unsigned char) rmap[ibuf[x]];
+ *pp++ = (unsigned char) gmap[ibuf[x]];
+ *pp++ = (unsigned char) bmap[ibuf[x]];
+ }
+ if (!TIFFWriteScanline(out, obuf, row, 0))
+ goto done;
+ }
+ break;
+ case PLANARCONFIG_SEPARATE:
+ for (row = 0; row < imagelength; row++) {
+ if (!TIFFReadScanline(in, ibuf, row, 0))
+ goto done;
+ for (pp = obuf, x = 0; x < imagewidth; x++)
+ *pp++ = (unsigned char) rmap[ibuf[x]];
+ if (!TIFFWriteScanline(out, obuf, row, 0))
+ goto done;
+ for (pp = obuf, x = 0; x < imagewidth; x++)
+ *pp++ = (unsigned char) gmap[ibuf[x]];
+ if (!TIFFWriteScanline(out, obuf, row, 0))
+ goto done;
+ for (pp = obuf, x = 0; x < imagewidth; x++)
+ *pp++ = (unsigned char) bmap[ibuf[x]];
+ if (!TIFFWriteScanline(out, obuf, row, 0))
+ goto done;
+ }
+ break;
+ }
+ _TIFFfree(ibuf);
+ _TIFFfree(obuf);
+ }
+done:
+ (void) TIFFClose(in);
+ (void) TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+#undef CopyField4
+#undef CopyField3
+#undef CopyField2
+#undef CopyField
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_IMAGEWIDTH, 1, TIFF_LONG },
+ { TIFFTAG_IMAGELENGTH, 1, TIFF_LONG },
+ { TIFFTAG_BITSPERSAMPLE, 1, TIFF_SHORT },
+ { TIFFTAG_COMPRESSION, 1, TIFF_SHORT },
+ { TIFFTAG_FILLORDER, 1, TIFF_SHORT },
+ { TIFFTAG_ROWSPERSTRIP, 1, TIFF_LONG },
+ { TIFFTAG_GROUP3OPTIONS, 1, TIFF_LONG },
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_ORIENTATION, 1, TIFF_SHORT },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_PAGENUMBER, 2, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, 1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_BADFAXLINES, 1, TIFF_LONG },
+ { TIFFTAG_CLEANFAXDATA, 1, TIFF_SHORT },
+ { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_INKNAMES, 1, TIFF_ASCII },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+static void
+cpTags(TIFF* in, TIFF* out)
+{
+ struct cpTag *p;
+ for (p = tags; p < &tags[NTAGS]; p++)
+ cpTag(in, out, p->tag, p->count, p->type);
+}
+#undef NTAGS
+
+char* stuff[] = {
+"usage: pal2rgb [options] input.tif output.tif",
+"where options are:",
+" -p contig pack samples contiguously (e.g. RGBRGB...)",
+" -p separate store samples separately (e.g. RRR...GGG...BBB...)",
+" -r # make each strip have no more than # rows",
+" -C 8 assume 8-bit colormap values (instead of 16-bit)",
+" -C 16 assume 16-bit colormap values",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/ppm2tiff.c b/tiff/tools/ppm2tiff.c
new file mode 100644
index 0000000..6078459
--- /dev/null
+++ b/tiff/tools/ppm2tiff.c
@@ -0,0 +1,362 @@
+/* $Id: ppm2tiff.c,v 1.13.2.2 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+static uint16 compression = COMPRESSION_PACKBITS;
+static uint16 predictor = 0;
+static int quality = 75; /* JPEG quality */
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static uint32 g3opts;
+
+static void usage(void);
+static int processCompressOptions(char*);
+
+static void
+BadPPM(char* file)
+{
+ fprintf(stderr, "%s: Not a PPM file.\n", file);
+ exit(-2);
+}
+
+int
+main(int argc, char* argv[])
+{
+ uint16 photometric = 0;
+ uint32 rowsperstrip = (uint32) -1;
+ double resolution = -1;
+ unsigned char *buf = NULL;
+ tsize_t linebytes = 0;
+ uint16 spp = 1;
+ uint16 bpp = 8;
+ TIFF *out;
+ FILE *in;
+ unsigned int w, h, prec, row;
+ char *infile;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ if (argc < 2) {
+ fprintf(stderr, "%s: Too few arguments\n", argv[0]);
+ usage();
+ }
+ while ((c = getopt(argc, argv, "c:r:R:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'R': /* resolution */
+ resolution = atof(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+
+ if (optind + 2 < argc) {
+ fprintf(stderr, "%s: Too many arguments\n", argv[0]);
+ usage();
+ }
+
+ /*
+ * If only one file is specified, read input from
+ * stdin; otherwise usage is: ppm2tiff input output.
+ */
+ if (argc - optind > 1) {
+ infile = argv[optind++];
+ in = fopen(infile, "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: Can not open.\n", infile);
+ return (-1);
+ }
+ } else {
+ infile = "<stdin>";
+ in = stdin;
+#if defined(HAVE_SETMODE) && defined(O_BINARY)
+ setmode(fileno(stdin), O_BINARY);
+#endif
+ }
+
+ if (fgetc(in) != 'P')
+ BadPPM(infile);
+ switch (fgetc(in)) {
+ case '4': /* it's a PBM file */
+ bpp = 1;
+ spp = 1;
+ photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ case '5': /* it's a PGM file */
+ bpp = 8;
+ spp = 1;
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case '6': /* it's a PPM file */
+ bpp = 8;
+ spp = 3;
+ photometric = PHOTOMETRIC_RGB;
+ if (compression == COMPRESSION_JPEG &&
+ jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ break;
+ default:
+ BadPPM(infile);
+ }
+
+ /* Parse header */
+ while(1) {
+ if (feof(in))
+ BadPPM(infile);
+ c = fgetc(in);
+ /* Skip whitespaces (blanks, TABs, CRs, LFs) */
+ if (strchr(" \t\r\n", c))
+ continue;
+
+ /* Check for comment line */
+ if (c == '#') {
+ do {
+ c = fgetc(in);
+ } while(!(strchr("\r\n", c) || feof(in)));
+ continue;
+ }
+
+ ungetc(c, in);
+ break;
+ }
+ switch (bpp) {
+ case 1:
+ if (fscanf(in, " %u %u", &w, &h) != 2)
+ BadPPM(infile);
+ if (fgetc(in) != '\n')
+ BadPPM(infile);
+ break;
+ case 8:
+ if (fscanf(in, " %u %u %u", &w, &h, &prec) != 3)
+ BadPPM(infile);
+ if (fgetc(in) != '\n' || prec != 255)
+ BadPPM(infile);
+ break;
+ }
+ out = TIFFOpen(argv[optind], "w");
+ if (out == NULL)
+ return (-4);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) w);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) h);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, spp);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, bpp);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ case COMPRESSION_CCITTFAX3:
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts);
+ break;
+ }
+ switch (bpp) {
+ case 1:
+ linebytes = (spp * w + (8 - 1)) / 8;
+ if (rowsperstrip == (uint32) -1) {
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, h);
+ } else {
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ }
+ break;
+ case 8:
+ linebytes = spp * w;
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ break;
+ }
+ if (TIFFScanlineSize(out) > linebytes)
+ buf = (unsigned char *)_TIFFmalloc(linebytes);
+ else
+ buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));
+ if (resolution > 0) {
+ TIFFSetField(out, TIFFTAG_XRESOLUTION, resolution);
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, resolution);
+ TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ }
+ for (row = 0; row < h; row++) {
+ if (fread(buf, linebytes, 1, in) != 1) {
+ fprintf(stderr, "%s: scanline %lu: Read error.\n",
+ infile, (unsigned long) row);
+ break;
+ }
+ if (TIFFWriteScanline(out, buf, row, 0) < 0)
+ break;
+ }
+ (void) TIFFClose(out);
+ if (buf)
+ _TIFFfree(buf);
+ return (0);
+}
+
+static void
+processG3Options(char* cp)
+{
+ g3opts = 0;
+ if( (cp = strchr(cp, ':')) ) {
+ do {
+ cp++;
+ if (strneq(cp, "1d", 2))
+ g3opts &= ~GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "2d", 2))
+ g3opts |= GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "fill", 4))
+ g3opts |= GROUP3OPT_FILLBITS;
+ else
+ usage();
+ } while( (cp = strchr(cp, ':')) );
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while (cp)
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "g3", 2)) {
+ processG3Options(opt);
+ compression = COMPRESSION_CCITTFAX3;
+ } else if (streq(opt, "g4")) {
+ compression = COMPRESSION_CCITTFAX4;
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+char* stuff[] = {
+"usage: ppm2tiff [options] input.ppm output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+" -R # set x&y resolution (dpi)",
+"",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding (the default)",
+" -c g3[:opts] compress output with CCITT Group 3 encoding",
+" -c g4 compress output with CCITT Group 4 encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/ras2tiff.c b/tiff/tools/ras2tiff.c
new file mode 100644
index 0000000..e108b94
--- /dev/null
+++ b/tiff/tools/ras2tiff.c
@@ -0,0 +1,306 @@
+/* $Id: ras2tiff.c,v 1.15.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "rasterfile.h"
+#include "tiffio.h"
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+static uint16 compression = (uint16) -1;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+static uint16 predictor = 0;
+
+static void usage(void);
+static int processCompressOptions(char*);
+
+int
+main(int argc, char* argv[])
+{
+ unsigned char* buf;
+ long row;
+ tsize_t linebytes, scanline;
+ TIFF *out;
+ FILE *in;
+ struct rasterfile h;
+ uint16 photometric;
+ uint16 config = PLANARCONFIG_CONTIG;
+ uint32 rowsperstrip = (uint32) -1;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:r:h")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'h':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+ in = fopen(argv[optind], "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: Can not open.\n", argv[optind]);
+ return (-1);
+ }
+ if (fread(&h, sizeof (h), 1, in) != 1) {
+ fprintf(stderr, "%s: Can not read header.\n", argv[optind]);
+ return (-2);
+ }
+ if (strcmp(h.ras_magic, RAS_MAGIC) == 0) {
+#ifndef WORDS_BIGENDIAN
+ TIFFSwabLong((uint32 *)&h.ras_width);
+ TIFFSwabLong((uint32 *)&h.ras_height);
+ TIFFSwabLong((uint32 *)&h.ras_depth);
+ TIFFSwabLong((uint32 *)&h.ras_length);
+ TIFFSwabLong((uint32 *)&h.ras_type);
+ TIFFSwabLong((uint32 *)&h.ras_maptype);
+ TIFFSwabLong((uint32 *)&h.ras_maplength);
+#endif
+ } else if (strcmp(h.ras_magic, RAS_MAGIC_INV) == 0) {
+#ifdef WORDS_BIGENDIAN
+ TIFFSwabLong((uint32 *)&h.ras_width);
+ TIFFSwabLong((uint32 *)&h.ras_height);
+ TIFFSwabLong((uint32 *)&h.ras_depth);
+ TIFFSwabLong((uint32 *)&h.ras_length);
+ TIFFSwabLong((uint32 *)&h.ras_type);
+ TIFFSwabLong((uint32 *)&h.ras_maptype);
+ TIFFSwabLong((uint32 *)&h.ras_maplength);
+#endif
+ } else {
+ fprintf(stderr, "%s: Not a rasterfile.\n", argv[optind]);
+ return (-3);
+ }
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-4);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) h.ras_width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) h.ras_height);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, h.ras_depth > 8 ? 3 : 1);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, h.ras_depth > 1 ? 8 : 1);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ if (h.ras_maptype != RMT_NONE) {
+ uint16* red;
+ register uint16* map;
+ register int i, j;
+ int mapsize;
+
+ buf = (unsigned char *)_TIFFmalloc(h.ras_maplength);
+ if (buf == NULL) {
+ fprintf(stderr, "No space to read in colormap.\n");
+ return (-5);
+ }
+ if (fread(buf, h.ras_maplength, 1, in) != 1) {
+ fprintf(stderr, "%s: Read error on colormap.\n",
+ argv[optind]);
+ return (-6);
+ }
+ mapsize = 1<<h.ras_depth;
+ if (h.ras_maplength > mapsize*3) {
+ fprintf(stderr,
+ "%s: Huh, %ld colormap entries, should be %d?\n",
+ argv[optind], h.ras_maplength, mapsize*3);
+ return (-7);
+ }
+ red = (uint16*)_TIFFmalloc(mapsize * 3 * sizeof (uint16));
+ if (red == NULL) {
+ fprintf(stderr, "No space for colormap.\n");
+ return (-8);
+ }
+ map = red;
+ for (j = 0; j < 3; j++) {
+#define SCALE(x) (((x)*((1L<<16)-1))/255)
+ for (i = h.ras_maplength/3; i-- > 0;)
+ *map++ = SCALE(*buf++);
+ if ((i = h.ras_maplength/3) < mapsize) {
+ i = mapsize - i;
+ _TIFFmemset(map, 0, i*sizeof (uint16));
+ map += i;
+ }
+ }
+ TIFFSetField(out, TIFFTAG_COLORMAP,
+ red, red + mapsize, red + 2*mapsize);
+ photometric = PHOTOMETRIC_PALETTE;
+ if (compression == (uint16) -1)
+ compression = COMPRESSION_PACKBITS;
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ } else {
+ /* XXX this is bogus... */
+ photometric = h.ras_depth == 24 ?
+ PHOTOMETRIC_RGB : PHOTOMETRIC_MINISBLACK;
+ if (compression == (uint16) -1)
+ compression = COMPRESSION_LZW;
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ }
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ linebytes = ((h.ras_depth*h.ras_width+15) >> 3) &~ 1;
+ scanline = TIFFScanlineSize(out);
+ if (scanline > linebytes) {
+ buf = (unsigned char *)_TIFFmalloc(scanline);
+ _TIFFmemset(buf+linebytes, 0, scanline-linebytes);
+ } else
+ buf = (unsigned char *)_TIFFmalloc(linebytes);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ for (row = 0; row < h.ras_height; row++) {
+ if (fread(buf, linebytes, 1, in) != 1) {
+ fprintf(stderr, "%s: scanline %ld: Read error.\n",
+ argv[optind], row);
+ break;
+ }
+ if (h.ras_type == RT_STANDARD && h.ras_depth == 24) {
+ tsize_t cc = h.ras_width;
+ unsigned char* cp = buf;
+#define SWAP(a,b) { unsigned char t = (a); (a) = (b); (b) = t; }
+ do {
+ SWAP(cp[0], cp[2]);
+ cp += 3;
+ } while (--cc);
+ }
+ if (TIFFWriteScanline(out, buf, row, 0) < 0)
+ break;
+ }
+ (void) TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+char* stuff[] = {
+"usage: ras2tiff [options] input.ras output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+" -h this help message",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/rasterfile.h b/tiff/tools/rasterfile.h
new file mode 100644
index 0000000..7f214a5
--- /dev/null
+++ b/tiff/tools/rasterfile.h
@@ -0,0 +1,49 @@
+/* $Header: /cvs/maptools/cvsroot/libtiff/tools/rasterfile.h,v 1.3.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Description of header for files containing raster images
+ */
+struct rasterfile {
+ char ras_magic[4]; /* magic number */
+ long ras_width; /* width (pixels) of image */
+ long ras_height; /* height (pixels) of image */
+ long ras_depth; /* depth (1, 8, or 24 bits) of pixel */
+ long ras_length; /* length (bytes) of image */
+ long ras_type; /* type of file; see RT_* below */
+ long ras_maptype; /* type of colormap; see RMT_* below */
+ long ras_maplength; /* length (bytes) of following map */
+ /* color map follows for ras_maplength bytes, followed by image */
+};
+#define RAS_MAGIC "\x59\xa6\x6a\x95"
+#define RAS_MAGIC_INV "\x95\x6a\xa6\x59"
+
+ /* Sun supported ras_type's */
+#define RT_OLD 0 /* Raw pixrect image in 68000 byte order */
+#define RT_STANDARD 1 /* Raw pixrect image in 68000 byte order */
+#define RT_BYTE_ENCODED 2 /* Run-length compression of bytes */
+#define RT_EXPERIMENTAL 0xffff /* Reserved for testing */
+
+ /* Sun registered ras_maptype's */
+#define RMT_RAW 2
+ /* Sun supported ras_maptype's */
+#define RMT_NONE 0 /* ras_maplength is expected to be 0 */
+#define RMT_EQUAL_RGB 1 /* red[ras_maplength/3],green[],blue[] */
+
+/*
+ * NOTES:
+ * Each line of the image is rounded out to a multiple of 16 bits.
+ * This corresponds to the rounding convention used by the memory pixrect
+ * package (/usr/include/pixrect/memvar.h) of the SunWindows system.
+ * The ras_encoding field (always set to 0 by Sun's supported software)
+ * was renamed to ras_length in release 2.0. As a result, rasterfiles
+ * of type 0 generated by the old software claim to have 0 length; for
+ * compatibility, code reading rasterfiles must be prepared to compute the
+ * true length from the width, height, and depth fields.
+ */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/raw2tiff.c b/tiff/tools/raw2tiff.c
new file mode 100644
index 0000000..17eb0e4
--- /dev/null
+++ b/tiff/tools/raw2tiff.c
@@ -0,0 +1,647 @@
+/* $Id: raw2tiff.c,v 1.23.2.1 2010-06-08 18:50:44 bfriesen Exp $
+ *
+ * Project: libtiff tools
+ * Purpose: Convert raw byte sequences in TIFF images
+ * Author: Andrey Kiselev, dron@ak4719.spb.edu
+ *
+ ******************************************************************************
+ * Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <math.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+typedef enum {
+ PIXEL,
+ BAND
+} InterleavingType;
+
+static uint16 compression = (uint16) -1;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+static uint16 predictor = 0;
+
+static void swapBytesInScanline(void *, uint32, TIFFDataType);
+static int guessSize(int, TIFFDataType, off_t, uint32, int,
+ uint32 *, uint32 *);
+static double correlation(void *, void *, uint32, TIFFDataType);
+static void usage(void);
+static int processCompressOptions(char*);
+
+int
+main(int argc, char* argv[])
+{
+ uint32 width = 0, length = 0, linebytes, bufsize;
+ uint32 nbands = 1; /* number of bands in input image*/
+ off_t hdr_size = 0; /* size of the header to skip */
+ TIFFDataType dtype = TIFF_BYTE;
+ int16 depth = 1; /* bytes per pixel in input image */
+ int swab = 0; /* byte swapping flag */
+ InterleavingType interleaving = 0; /* interleaving type flag */
+ uint32 rowsperstrip = (uint32) -1;
+ uint16 photometric = PHOTOMETRIC_MINISBLACK;
+ uint16 config = PLANARCONFIG_CONTIG;
+ uint16 fillorder = FILLORDER_LSB2MSB;
+ int fd;
+ char *outfilename = NULL;
+ TIFF *out;
+
+ uint32 row, col, band;
+ int c;
+ unsigned char *buf = NULL, *buf1 = NULL;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:r:H:w:l:b:d:LMp:si:o:h")) != -1) {
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'H': /* size of input image file header */
+ hdr_size = atoi(optarg);
+ break;
+ case 'w': /* input image width */
+ width = atoi(optarg);
+ break;
+ case 'l': /* input image length */
+ length = atoi(optarg);
+ break;
+ case 'b': /* number of bands in input image */
+ nbands = atoi(optarg);
+ break;
+ case 'd': /* type of samples in input image */
+ if (strncmp(optarg, "byte", 4) == 0)
+ dtype = TIFF_BYTE;
+ else if (strncmp(optarg, "short", 5) == 0)
+ dtype = TIFF_SHORT;
+ else if (strncmp(optarg, "long", 4) == 0)
+ dtype = TIFF_LONG;
+ else if (strncmp(optarg, "sbyte", 5) == 0)
+ dtype = TIFF_SBYTE;
+ else if (strncmp(optarg, "sshort", 6) == 0)
+ dtype = TIFF_SSHORT;
+ else if (strncmp(optarg, "slong", 5) == 0)
+ dtype = TIFF_SLONG;
+ else if (strncmp(optarg, "float", 5) == 0)
+ dtype = TIFF_FLOAT;
+ else if (strncmp(optarg, "double", 6) == 0)
+ dtype = TIFF_DOUBLE;
+ else
+ dtype = TIFF_BYTE;
+ depth = TIFFDataWidth(dtype);
+ break;
+ case 'L': /* input has lsb-to-msb fillorder */
+ fillorder = FILLORDER_LSB2MSB;
+ break;
+ case 'M': /* input has msb-to-lsb fillorder */
+ fillorder = FILLORDER_MSB2LSB;
+ break;
+ case 'p': /* photometric interpretation */
+ if (strncmp(optarg, "miniswhite", 10) == 0)
+ photometric = PHOTOMETRIC_MINISWHITE;
+ else if (strncmp(optarg, "minisblack", 10) == 0)
+ photometric = PHOTOMETRIC_MINISBLACK;
+ else if (strncmp(optarg, "rgb", 3) == 0)
+ photometric = PHOTOMETRIC_RGB;
+ else if (strncmp(optarg, "cmyk", 4) == 0)
+ photometric = PHOTOMETRIC_SEPARATED;
+ else if (strncmp(optarg, "ycbcr", 5) == 0)
+ photometric = PHOTOMETRIC_YCBCR;
+ else if (strncmp(optarg, "cielab", 6) == 0)
+ photometric = PHOTOMETRIC_CIELAB;
+ else if (strncmp(optarg, "icclab", 6) == 0)
+ photometric = PHOTOMETRIC_ICCLAB;
+ else if (strncmp(optarg, "itulab", 6) == 0)
+ photometric = PHOTOMETRIC_ITULAB;
+ else
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 's': /* do we need to swap bytes? */
+ swab = 1;
+ break;
+ case 'i': /* type of interleaving */
+ if (strncmp(optarg, "pixel", 4) == 0)
+ interleaving = PIXEL;
+ else if (strncmp(optarg, "band", 6) == 0)
+ interleaving = BAND;
+ else
+ interleaving = 0;
+ break;
+ case 'o':
+ outfilename = optarg;
+ break;
+ case 'h':
+ usage();
+ default:
+ break;
+ }
+ }
+
+ if (argc - optind < 2)
+ usage();
+
+ fd = open(argv[optind], O_RDONLY|O_BINARY, 0);
+ if (fd < 0) {
+ fprintf(stderr, "%s: %s: Cannot open input file.\n",
+ argv[0], argv[optind]);
+ return (-1);
+ }
+
+ if (guessSize(fd, dtype, hdr_size, nbands, swab, &width, &length) < 0)
+ return 1;
+
+ if (outfilename == NULL)
+ outfilename = argv[optind+1];
+ out = TIFFOpen(outfilename, "w");
+ if (out == NULL) {
+ fprintf(stderr, "%s: %s: Cannot open file for output.\n",
+ argv[0], outfilename);
+ return (-1);
+ }
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, nbands);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, depth * 8);
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ switch (dtype) {
+ case TIFF_BYTE:
+ case TIFF_SHORT:
+ case TIFF_LONG:
+ TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ break;
+ case TIFF_SBYTE:
+ case TIFF_SSHORT:
+ case TIFF_SLONG:
+ TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT);
+ break;
+ case TIFF_FLOAT:
+ case TIFF_DOUBLE:
+ TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
+ break;
+ default:
+ TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_VOID);
+ break;
+ }
+ if (compression == (uint16) -1)
+ compression = COMPRESSION_PACKBITS;
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB
+ && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ switch(interleaving) {
+ case BAND: /* band interleaved data */
+ linebytes = width * depth;
+ buf = (unsigned char *)_TIFFmalloc(linebytes);
+ break;
+ case PIXEL: /* pixel interleaved data */
+ default:
+ linebytes = width * nbands * depth;
+ break;
+ }
+ bufsize = width * nbands * depth;
+ buf1 = (unsigned char *)_TIFFmalloc(bufsize);
+
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ if (rowsperstrip > length) {
+ rowsperstrip = length;
+ }
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip );
+
+ lseek(fd, hdr_size, SEEK_SET); /* Skip the file header */
+ for (row = 0; row < length; row++) {
+ switch(interleaving) {
+ case BAND: /* band interleaved data */
+ for (band = 0; band < nbands; band++) {
+ lseek(fd,
+ hdr_size + (length*band+row)*linebytes,
+ SEEK_SET);
+ if (read(fd, buf, linebytes) < 0) {
+ fprintf(stderr,
+ "%s: %s: scanline %lu: Read error.\n",
+ argv[0], argv[optind],
+ (unsigned long) row);
+ break;
+ }
+ if (swab) /* Swap bytes if needed */
+ swapBytesInScanline(buf, width, dtype);
+ for (col = 0; col < width; col++)
+ memcpy(buf1 + (col*nbands+band)*depth,
+ buf + col * depth, depth);
+ }
+ break;
+ case PIXEL: /* pixel interleaved data */
+ default:
+ if (read(fd, buf1, bufsize) < 0) {
+ fprintf(stderr,
+ "%s: %s: scanline %lu: Read error.\n",
+ argv[0], argv[optind],
+ (unsigned long) row);
+ break;
+ }
+ if (swab) /* Swap bytes if needed */
+ swapBytesInScanline(buf1, width, dtype);
+ break;
+ }
+
+ if (TIFFWriteScanline(out, buf1, row, 0) < 0) {
+ fprintf(stderr, "%s: %s: scanline %lu: Write error.\n",
+ argv[0], outfilename, (unsigned long) row);
+ break;
+ }
+ }
+ if (buf)
+ _TIFFfree(buf);
+ if (buf1)
+ _TIFFfree(buf1);
+ TIFFClose(out);
+ return (0);
+}
+
+static void
+swapBytesInScanline(void *buf, uint32 width, TIFFDataType dtype)
+{
+ switch (dtype) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*)buf,
+ (unsigned long)width);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ TIFFSwabArrayOfLong((uint32*)buf,
+ (unsigned long)width);
+ break;
+ /* case TIFF_FLOAT: */ /* FIXME */
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*)buf,
+ (unsigned long)width);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+guessSize(int fd, TIFFDataType dtype, off_t hdr_size, uint32 nbands,
+ int swab, uint32 *width, uint32 *length)
+{
+ const float longt = 40.0; /* maximum possible height/width ratio */
+ char *buf1, *buf2;
+ struct stat filestat;
+ uint32 w, h, scanlinesize, imagesize;
+ uint32 depth = TIFFDataWidth(dtype);
+ float cor_coef = 0, tmp;
+
+ fstat(fd, &filestat);
+
+ if (filestat.st_size < hdr_size) {
+ fprintf(stderr, "Too large header size specified.\n");
+ return -1;
+ }
+
+ imagesize = (filestat.st_size - hdr_size) / nbands / depth;
+
+ if (*width != 0 && *length == 0) {
+ fprintf(stderr, "Image height is not specified.\n");
+
+ *length = imagesize / *width;
+
+ fprintf(stderr, "Height is guessed as %lu.\n",
+ (unsigned long)*length);
+
+ return 1;
+ } else if (*width == 0 && *length != 0) {
+ fprintf(stderr, "Image width is not specified.\n");
+
+ *width = imagesize / *length;
+
+ fprintf(stderr, "Width is guessed as %lu.\n",
+ (unsigned long)*width);
+
+ return 1;
+ } else if (*width == 0 && *length == 0) {
+ fprintf(stderr, "Image width and height are not specified.\n");
+
+ for (w = (uint32) sqrt(imagesize / longt);
+ w < sqrt(imagesize * longt);
+ w++) {
+ if (imagesize % w == 0) {
+ scanlinesize = w * depth;
+ buf1 = _TIFFmalloc(scanlinesize);
+ buf2 = _TIFFmalloc(scanlinesize);
+ h = imagesize / w;
+ lseek(fd, hdr_size + (int)(h/2)*scanlinesize,
+ SEEK_SET);
+ read(fd, buf1, scanlinesize);
+ read(fd, buf2, scanlinesize);
+ if (swab) {
+ swapBytesInScanline(buf1, w, dtype);
+ swapBytesInScanline(buf2, w, dtype);
+ }
+ tmp = (float) fabs(correlation(buf1, buf2,
+ w, dtype));
+ if (tmp > cor_coef) {
+ cor_coef = tmp;
+ *width = w, *length = h;
+ }
+
+ _TIFFfree(buf1);
+ _TIFFfree(buf2);
+ }
+ }
+
+ fprintf(stderr,
+ "Width is guessed as %lu, height is guessed as %lu.\n",
+ (unsigned long)*width, (unsigned long)*length);
+
+ return 1;
+ } else {
+ if (filestat.st_size<(off_t)(hdr_size+(*width)*(*length)*nbands*depth)) {
+ fprintf(stderr, "Input file too small.\n");
+ return -1;
+ }
+ }
+
+ return 1;
+}
+
+/* Calculate correlation coefficient between two numeric vectors */
+static double
+correlation(void *buf1, void *buf2, uint32 n_elem, TIFFDataType dtype)
+{
+ double X, Y, M1 = 0.0, M2 = 0.0, D1 = 0.0, D2 = 0.0, K = 0.0;
+ uint32 i;
+
+ switch (dtype) {
+ case TIFF_BYTE:
+ default:
+ for (i = 0; i < n_elem; i++) {
+ X = ((unsigned char *)buf1)[i];
+ Y = ((unsigned char *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_SBYTE:
+ for (i = 0; i < n_elem; i++) {
+ X = ((signed char *)buf1)[i];
+ Y = ((signed char *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_SHORT:
+ for (i = 0; i < n_elem; i++) {
+ X = ((uint16 *)buf1)[i];
+ Y = ((uint16 *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_SSHORT:
+ for (i = 0; i < n_elem; i++) {
+ X = ((int16 *)buf1)[i];
+ Y = ((int16 *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_LONG:
+ for (i = 0; i < n_elem; i++) {
+ X = ((uint32 *)buf1)[i];
+ Y = ((uint32 *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_SLONG:
+ for (i = 0; i < n_elem; i++) {
+ X = ((int32 *)buf1)[i];
+ Y = ((int32 *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_FLOAT:
+ for (i = 0; i < n_elem; i++) {
+ X = ((float *)buf1)[i];
+ Y = ((float *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ case TIFF_DOUBLE:
+ for (i = 0; i < n_elem; i++) {
+ X = ((double *)buf1)[i];
+ Y = ((double *)buf2)[i];
+ M1 += X, M2 += Y;
+ D1 += X * X, D2 += Y * Y;
+ K += X * Y;
+ }
+ break;
+ }
+
+ M1 /= n_elem;
+ M2 /= n_elem;
+ D1 -= M1 * M1 * n_elem;
+ D2 -= M2 * M2 * n_elem;
+ K = (K - M1 * M2 * n_elem) / sqrt(D1 * D2);
+
+ return K;
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (strcmp(opt, "none") == 0)
+ compression = COMPRESSION_NONE;
+ else if (strcmp(opt, "packbits") == 0)
+ compression = COMPRESSION_PACKBITS;
+ else if (strncmp(opt, "jpeg", 4) == 0) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strncmp(opt, "lzw", 3) == 0) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strncmp(opt, "zip", 3) == 0) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+static char* stuff[] = {
+"raw2tiff --- tool for converting raw byte sequences in TIFF images",
+"usage: raw2tiff [options] input.raw output.tif",
+"where options are:",
+" -L input data has LSB2MSB bit order (default)",
+" -M input data has MSB2LSB bit order",
+" -r # make each strip have no more than # rows",
+" -H # size of input image file header in bytes (0 by default)",
+" -w # width of input image in pixels",
+" -l # length of input image in lines",
+" -b # number of bands in input image (1 by default)",
+"",
+" -d data_type type of samples in input image",
+"where data_type may be:",
+" byte 8-bit unsigned integer (default)",
+" short 16-bit unsigned integer",
+" long 32-bit unsigned integer",
+" sbyte 8-bit signed integer",
+" sshort 16-bit signed integer",
+" slong 32-bit signed integer",
+" float 32-bit IEEE floating point",
+" double 64-bit IEEE floating point",
+"",
+" -p photo photometric interpretation (color space) of the input image",
+"where photo may be:",
+" miniswhite white color represented with 0 value",
+" minisblack black color represented with 0 value (default)",
+" rgb image has RGB color model",
+" cmyk image has CMYK (separated) color model",
+" ycbcr image has YCbCr color model",
+" cielab image has CIE L*a*b color model",
+" icclab image has ICC L*a*b color model",
+" itulab image has ITU L*a*b color model",
+"",
+" -s swap bytes fetched from input file",
+"",
+" -i config type of samples interleaving in input image",
+"where config may be:",
+" pixel pixel interleaved data (default)",
+" band band interleaved data",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+" -o out.tif write output to out.tif",
+" -h this help message",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/rgb2ycbcr.c b/tiff/tools/rgb2ycbcr.c
new file mode 100644
index 0000000..0b30b51
--- /dev/null
+++ b/tiff/tools/rgb2ycbcr.c
@@ -0,0 +1,382 @@
+/* $Id: rgb2ycbcr.c,v 1.9.2.2 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffiop.h"
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define roundup(x, y) (howmany(x,y)*((uint32)(y)))
+
+#define LumaRed ycbcrCoeffs[0]
+#define LumaGreen ycbcrCoeffs[1]
+#define LumaBlue ycbcrCoeffs[2]
+
+uint16 compression = COMPRESSION_PACKBITS;
+uint32 rowsperstrip = (uint32) -1;
+
+uint16 horizSubSampling = 2; /* YCbCr horizontal subsampling */
+uint16 vertSubSampling = 2; /* YCbCr vertical subsampling */
+float ycbcrCoeffs[3] = { .299F, .587F, .114F };
+/* default coding range is CCIR Rec 601-1 with no headroom/footroom */
+float refBlackWhite[6] = { 0.F, 255.F, 128.F, 255.F, 128.F, 255.F };
+
+static int tiffcvt(TIFF* in, TIFF* out);
+static void usage(int code);
+static void setupLumaTables(void);
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *in, *out;
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "c:h:r:v:z")) != -1)
+ switch (c) {
+ case 'c':
+ if (streq(optarg, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(optarg, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (streq(optarg, "lzw"))
+ compression = COMPRESSION_LZW;
+ else if (streq(optarg, "jpeg"))
+ compression = COMPRESSION_JPEG;
+ else if (streq(optarg, "zip"))
+ compression = COMPRESSION_ADOBE_DEFLATE;
+ else
+ usage(-1);
+ break;
+ case 'h':
+ horizSubSampling = atoi(optarg);
+ break;
+ case 'v':
+ vertSubSampling = atoi(optarg);
+ break;
+ case 'r':
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'z': /* CCIR Rec 601-1 w/ headroom/footroom */
+ refBlackWhite[0] = 16.;
+ refBlackWhite[1] = 235.;
+ refBlackWhite[2] = 128.;
+ refBlackWhite[3] = 240.;
+ refBlackWhite[4] = 128.;
+ refBlackWhite[5] = 240.;
+ break;
+ case '?':
+ usage(0);
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage(-1);
+ out = TIFFOpen(argv[argc-1], "w");
+ if (out == NULL)
+ return (-2);
+ setupLumaTables();
+ for (; optind < argc-1; optind++) {
+ in = TIFFOpen(argv[optind], "r");
+ if (in != NULL) {
+ do {
+ if (!tiffcvt(in, out) ||
+ !TIFFWriteDirectory(out)) {
+ (void) TIFFClose(out);
+ return (1);
+ }
+ } while (TIFFReadDirectory(in));
+ (void) TIFFClose(in);
+ }
+ }
+ (void) TIFFClose(out);
+ return (0);
+}
+
+float *lumaRed;
+float *lumaGreen;
+float *lumaBlue;
+float D1, D2;
+int Yzero;
+
+static float*
+setupLuma(float c)
+{
+ float *v = (float *)_TIFFmalloc(256 * sizeof (float));
+ int i;
+ for (i = 0; i < 256; i++)
+ v[i] = c * i;
+ return (v);
+}
+
+static unsigned
+V2Code(float f, float RB, float RW, int CR)
+{
+ unsigned int c = (unsigned int)((((f)*(RW-RB)/CR)+RB)+.5);
+ return (c > 255 ? 255 : c);
+}
+
+static void
+setupLumaTables(void)
+{
+ lumaRed = setupLuma(LumaRed);
+ lumaGreen = setupLuma(LumaGreen);
+ lumaBlue = setupLuma(LumaBlue);
+ D1 = 1.F/(2.F - 2.F*LumaBlue);
+ D2 = 1.F/(2.F - 2.F*LumaRed);
+ Yzero = V2Code(0, refBlackWhite[0], refBlackWhite[1], 255);
+}
+
+static void
+cvtClump(unsigned char* op, uint32* raster, uint32 ch, uint32 cw, uint32 w)
+{
+ float Y, Cb = 0, Cr = 0;
+ uint32 j, k;
+ /*
+ * Convert ch-by-cw block of RGB
+ * to YCbCr and sample accordingly.
+ */
+ for (k = 0; k < ch; k++) {
+ for (j = 0; j < cw; j++) {
+ uint32 RGB = (raster - k*w)[j];
+ Y = lumaRed[TIFFGetR(RGB)] +
+ lumaGreen[TIFFGetG(RGB)] +
+ lumaBlue[TIFFGetB(RGB)];
+ /* accumulate chrominance */
+ Cb += (TIFFGetB(RGB) - Y) * D1;
+ Cr += (TIFFGetR(RGB) - Y) * D2;
+ /* emit luminence */
+ *op++ = V2Code(Y,
+ refBlackWhite[0], refBlackWhite[1], 255);
+ }
+ for (; j < horizSubSampling; j++)
+ *op++ = Yzero;
+ }
+ for (; k < vertSubSampling; k++) {
+ for (j = 0; j < horizSubSampling; j++)
+ *op++ = Yzero;
+ }
+ /* emit sampled chrominance values */
+ *op++ = V2Code(Cb / (ch*cw), refBlackWhite[2], refBlackWhite[3], 127);
+ *op++ = V2Code(Cr / (ch*cw), refBlackWhite[4], refBlackWhite[5], 127);
+}
+#undef LumaRed
+#undef LumaGreen
+#undef LumaBlue
+#undef V2Code
+
+/*
+ * Convert a strip of RGB data to YCbCr and
+ * sample to generate the output data.
+ */
+static void
+cvtStrip(unsigned char* op, uint32* raster, uint32 nrows, uint32 width)
+{
+ uint32 x;
+ int clumpSize = vertSubSampling * horizSubSampling + 2;
+ uint32 *tp;
+
+ for (; nrows >= vertSubSampling; nrows -= vertSubSampling) {
+ tp = raster;
+ for (x = width; x >= horizSubSampling; x -= horizSubSampling) {
+ cvtClump(op, tp,
+ vertSubSampling, horizSubSampling, width);
+ op += clumpSize;
+ tp += horizSubSampling;
+ }
+ if (x > 0) {
+ cvtClump(op, tp, vertSubSampling, x, width);
+ op += clumpSize;
+ }
+ raster -= vertSubSampling*width;
+ }
+ if (nrows > 0) {
+ tp = raster;
+ for (x = width; x >= horizSubSampling; x -= horizSubSampling) {
+ cvtClump(op, tp, nrows, horizSubSampling, width);
+ op += clumpSize;
+ tp += horizSubSampling;
+ }
+ if (x > 0)
+ cvtClump(op, tp, nrows, x, width);
+ }
+}
+
+static int
+cvtRaster(TIFF* tif, uint32* raster, uint32 width, uint32 height)
+{
+ uint32 y;
+ tstrip_t strip = 0;
+ tsize_t cc, acc;
+ unsigned char* buf;
+ uint32 rwidth = roundup(width, horizSubSampling);
+ uint32 rheight = roundup(height, vertSubSampling);
+ uint32 nrows = (rowsperstrip > rheight ? rheight : rowsperstrip);
+ uint32 rnrows = roundup(nrows,vertSubSampling);
+
+ cc = rnrows*rwidth +
+ 2*((rnrows*rwidth) / (horizSubSampling*vertSubSampling));
+ buf = (unsigned char*)_TIFFmalloc(cc);
+ for (y = height; (int32) y > 0; y -= nrows) {
+ uint32 nr = (y > nrows ? nrows : y);
+ cvtStrip(buf, raster + (y-1)*width, nr, width);
+ nr = roundup(nr, vertSubSampling);
+ acc = nr*rwidth +
+ 2*((nr*rwidth)/(horizSubSampling*vertSubSampling));
+ if (!TIFFWriteEncodedStrip(tif, strip++, buf, acc)) {
+ _TIFFfree(buf);
+ return (0);
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+}
+
+static int
+tiffcvt(TIFF* in, TIFF* out)
+{
+ uint32 width, height; /* image width & height */
+ uint32* raster; /* retrieve RGBA image */
+ uint16 shortv;
+ float floatv;
+ char *stringv;
+ uint32 longv;
+
+ size_t pixel_count;
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+ pixel_count = width * height;
+
+ /* XXX: Check the integer overflow. */
+ if (!width || !height || pixel_count / width != height) {
+ TIFFError(TIFFFileName(in),
+ "Malformed input file; "
+ "can't allocate buffer for raster of %lux%lu size",
+ (unsigned long)width, (unsigned long)height);
+ return 0;
+ }
+
+ raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32),
+ "raster buffer");
+ if (raster == 0) {
+ TIFFError(TIFFFileName(in),
+ "Requested buffer size is %lu elements %lu each",
+ (unsigned long)pixel_count,
+ (unsigned long)sizeof(uint32));
+ return (0);
+ }
+
+ if (!TIFFReadRGBAImage(in, width, height, raster, 0)) {
+ _TIFFfree(raster);
+ return (0);
+ }
+
+ CopyField(TIFFTAG_SUBFILETYPE, longv);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ if (compression == COMPRESSION_JPEG)
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
+ CopyField(TIFFTAG_FILLORDER, shortv);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ { char buf[2048];
+ char *cp = strrchr(TIFFFileName(in), '/');
+ sprintf(buf, "YCbCr conversion of %s", cp ? cp+1 : TIFFFileName(in));
+ TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, buf);
+ }
+ TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
+ CopyField(TIFFTAG_DOCUMENTNAME, stringv);
+
+ TIFFSetField(out, TIFFTAG_REFERENCEBLACKWHITE, refBlackWhite);
+ TIFFSetField(out, TIFFTAG_YCBCRSUBSAMPLING,
+ horizSubSampling, vertSubSampling);
+ TIFFSetField(out, TIFFTAG_YCBCRPOSITIONING, YCBCRPOSITION_CENTERED);
+ TIFFSetField(out, TIFFTAG_YCBCRCOEFFICIENTS, ycbcrCoeffs);
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ return (cvtRaster(out, raster, width, height));
+}
+
+char* stuff[] = {
+ "usage: rgb2ycbcr [-c comp] [-r rows] [-h N] [-v N] input... output\n",
+ "where comp is one of the following compression algorithms:\n",
+ " jpeg\t\tJPEG encoding\n",
+ " lzw\t\tLempel-Ziv & Welch encoding\n",
+ " zip\t\tdeflate encoding\n",
+ " packbits\tPackBits encoding (default)\n",
+ " none\t\tno compression\n",
+ "and the other options are:\n",
+ " -r\trows/strip\n",
+ " -h\thorizontal sampling factor (1,2,4)\n",
+ " -v\tvertical sampling factor (1,2,4)\n",
+ NULL
+};
+
+static void
+usage(int code)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(code);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/sgi2tiff.c b/tiff/tools/sgi2tiff.c
new file mode 100644
index 0000000..2a495e1
--- /dev/null
+++ b/tiff/tools/sgi2tiff.c
@@ -0,0 +1,335 @@
+/* $Id: sgi2tiff.c,v 1.5.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gl/image.h>
+#include <ctype.h>
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+static short config = PLANARCONFIG_CONTIG;
+static uint16 compression = COMPRESSION_PACKBITS;
+static uint16 predictor = 0;
+static uint16 fillorder = 0;
+static uint32 rowsperstrip = (uint32) -1;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+static uint16 photometric;
+
+static void usage(void);
+static int cpContig(IMAGE*, TIFF*);
+static int cpSeparate(IMAGE*, TIFF*);
+static int processCompressOptions(char*);
+
+/* XXX image library has no prototypes */
+extern IMAGE* iopen(const char*, const char*);
+extern void iclose(IMAGE*);
+extern void getrow(IMAGE*, short*, int, int);
+
+int
+main(int argc, char* argv[])
+{
+ IMAGE *in;
+ TIFF *out;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:p:r:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'f': /* fill order */
+ if (streq(optarg, "lsb2msb"))
+ fillorder = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ fillorder = FILLORDER_MSB2LSB;
+ else
+ usage();
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ config = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ config = PLANARCONFIG_CONTIG;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+ in = iopen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-2);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) in->xsize);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) in->ysize);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ if (in->zsize == 1)
+ photometric = PHOTOMETRIC_MINISBLACK;
+ else
+ photometric = PHOTOMETRIC_RGB;
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, photometric);
+ if (fillorder != 0)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, in->zsize);
+ if (in->zsize > 3) {
+ uint16 v[1];
+ v[0] = EXTRASAMPLE_UNASSALPHA;
+ TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v);
+ }
+ TIFFSetField(out, TIFFTAG_MINSAMPLEVALUE, (uint16) in->min);
+ TIFFSetField(out, TIFFTAG_MAXSAMPLEVALUE, (uint16) in->max);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ if (config != PLANARCONFIG_SEPARATE)
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ else /* force 1 row/strip for library limitation */
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, 1L);
+ if (in->name[0] != '\0')
+ TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, in->name);
+ if (config == PLANARCONFIG_CONTIG)
+ cpContig(in, out);
+ else
+ cpSeparate(in, out);
+ (void) iclose(in);
+ (void) TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ defcompression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+static int
+cpContig(IMAGE* in, TIFF* out)
+{
+ tdata_t buf = _TIFFmalloc(TIFFScanlineSize(out));
+ short *r = NULL;
+ int x, y;
+
+ if (in->zsize == 3) {
+ short *g, *b;
+
+ r = (short *)_TIFFmalloc(3 * in->xsize * sizeof (short));
+ g = r + in->xsize;
+ b = g + in->xsize;
+ for (y = in->ysize-1; y >= 0; y--) {
+ uint8* pp = (uint8*) buf;
+
+ getrow(in, r, y, 0);
+ getrow(in, g, y, 1);
+ getrow(in, b, y, 2);
+ for (x = 0; x < in->xsize; x++) {
+ pp[0] = r[x];
+ pp[1] = g[x];
+ pp[2] = b[x];
+ pp += 3;
+ }
+ if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0)
+ goto bad;
+ }
+ } else if (in->zsize == 4) {
+ short *g, *b, *a;
+
+ r = (short *)_TIFFmalloc(4 * in->xsize * sizeof (short));
+ g = r + in->xsize;
+ b = g + in->xsize;
+ a = b + in->xsize;
+ for (y = in->ysize-1; y >= 0; y--) {
+ uint8* pp = (uint8*) buf;
+
+ getrow(in, r, y, 0);
+ getrow(in, g, y, 1);
+ getrow(in, b, y, 2);
+ getrow(in, a, y, 3);
+ for (x = 0; x < in->xsize; x++) {
+ pp[0] = r[x];
+ pp[1] = g[x];
+ pp[2] = b[x];
+ pp[3] = a[x];
+ pp += 4;
+ }
+ if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0)
+ goto bad;
+ }
+ } else {
+ uint8* pp = (uint8*) buf;
+
+ r = (short *)_TIFFmalloc(in->xsize * sizeof (short));
+ for (y = in->ysize-1; y >= 0; y--) {
+ getrow(in, r, y, 0);
+ for (x = in->xsize-1; x >= 0; x--)
+ pp[x] = r[x];
+ if (TIFFWriteScanline(out, buf, in->ysize-y-1, 0) < 0)
+ goto bad;
+ }
+ }
+ if (r)
+ _TIFFfree(r);
+ _TIFFfree(buf);
+ return (1);
+bad:
+ if (r)
+ _TIFFfree(r);
+ _TIFFfree(buf);
+ return (0);
+}
+
+static int
+cpSeparate(IMAGE* in, TIFF* out)
+{
+ tdata_t buf = _TIFFmalloc(TIFFScanlineSize(out));
+ short *r = (short *)_TIFFmalloc(in->xsize * sizeof (short));
+ uint8* pp = (uint8*) buf;
+ int x, y, z;
+
+ for (z = 0; z < in->zsize; z++) {
+ for (y = in->ysize-1; y >= 0; y--) {
+ getrow(in, r, y, z);
+ for (x = 0; x < in->xsize; x++)
+ pp[x] = r[x];
+ if (TIFFWriteScanline(out, buf, in->ysize-y-1, z) < 0)
+ goto bad;
+ }
+ }
+ _TIFFfree(r);
+ _TIFFfree(buf);
+ return (1);
+bad:
+ _TIFFfree(r);
+ _TIFFfree(buf);
+ return (0);
+}
+
+char* stuff[] = {
+"usage: sgi2tiff [options] input.rgb output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+"",
+" -p contig pack samples contiguously (e.g. RGBRGB...)",
+" -p separate store samples separately (e.g. RRR...GGG...BBB...)",
+"",
+" -f lsb2msb force lsb-to-msb FillOrder for output",
+" -f msb2lsb force msb-to-lsb FillOrder for output",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts]compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/sgisv.c b/tiff/tools/sgisv.c
new file mode 100644
index 0000000..75f1022
--- /dev/null
+++ b/tiff/tools/sgisv.c
@@ -0,0 +1,316 @@
+/* $Id: sgisv.c,v 1.5.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1990-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gl.h>
+#include <ctype.h>
+
+#include "tiffio.h"
+
+typedef unsigned char unsigned char;
+typedef unsigned long uint32;
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+uint32 rowsperstrip = (uint32) -1;
+uint16 compression = COMPRESSION_PACKBITS;
+uint16 config = PLANARCONFIG_CONTIG;
+uint16 predictor = 0;
+int xmaxscreen;
+int ymaxscreen;
+uint16 photometric = PHOTOMETRIC_RGB;
+int jpegcolormode = JPEGCOLORMODE_RGB;
+int quality = 75; /* JPEG quality */
+
+static void usage(void);
+static void tiffsv(char*, int, int, int, int);
+
+int
+main(int argc, char* argv[])
+{
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "c:p:r:")) != -1)
+ switch (c) {
+ case 'b': /* save as b&w */
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 'c': /* compression scheme */
+ if (streq(optarg, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(optarg, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(optarg, "jpeg", 4)) {
+ char* cp = strchr(optarg, ':');
+ if (cp && isdigit(cp[1]))
+ quality = atoi(cp+1);
+ if (cp && strchr(cp, 'r'))
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ compression = COMPRESSION_JPEG;
+ } else if (strneq(optarg, "lzw", 3)) {
+ char* cp = strchr(optarg, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else
+ usage();
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ config = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ config = PLANARCONFIG_CONTIG;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 1 && argc - optind != 5)
+ usage();
+ xmaxscreen = getgdesc(GD_XPMAX)-1;
+ ymaxscreen = getgdesc(GD_YPMAX)-1;
+ foreground();
+ noport();
+ winopen("tiffsv");
+ if (argc - optind == 5)
+ tiffsv(argv[optind],
+ atoi(argv[optind+1]), atoi(argv[optind+2]),
+ atoi(argv[optind+3]), atoi(argv[optind+4]));
+ else
+ tiffsv(argv[optind], 0, xmaxscreen, 0, ymaxscreen);
+ return (0);
+}
+
+char* stuff[] = {
+"usage: tiffsv [options] outimage.tif [x1 x2 y1 y2] [-b]",
+"where options are:",
+" -p contig pack samples contiguously (e.g. RGBRGB...)",
+" -p separate store samples separately (e.g. RRR...GGG...BBB...)",
+"",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c jpeg[:opts]compress output with JPEG encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"",
+"LZW options:",
+" # set predictor value for Lempel-Ziv & Welch encoding",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+static void
+svRGBSeparate(TIFF* tif, uint32* ss, int xsize, int ysize)
+{
+ tsize_t stripsize = TIFFStripSize(tif);
+ unsigned char *rbuf = (unsigned char *)_TIFFmalloc(3*stripsize);
+ unsigned char *gbuf = rbuf + stripsize;
+ unsigned char *bbuf = gbuf + stripsize;
+ register int y;
+
+ for (y = 0; y <= ysize; y += rowsperstrip) {
+ unsigned char *rp, *gp, *bp;
+ register int x;
+ register uint32 n;
+
+ n = rowsperstrip;
+ if (n > ysize-y+1)
+ n = ysize-y+1;
+ rp = rbuf; gp = gbuf; bp = bbuf;
+ do {
+ for (x = 0; x <= xsize; x++) {
+ uint32 v = ss[x];
+ rp[x] = v;
+ gp[x] = v >> 8;
+ bp[x] = v >> 16;
+ }
+ rp += xsize+1, gp += xsize+1, bp += xsize+1;
+ ss += xsize+1;
+ } while (--n);
+ if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,0),
+ rbuf, stripsize) < 0)
+ break;
+ if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,1),
+ gbuf, stripsize) < 0)
+ break;
+ if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,2),
+ bbuf, stripsize) < 0)
+ break;
+ }
+ _TIFFfree(rbuf);
+}
+
+static void
+svRGBContig(TIFF* tif, uint32* ss, int xsize, int ysize)
+{
+ register int x, y;
+ tsize_t stripsize = TIFFStripSize(tif);
+ unsigned char *strip = (unsigned char *)_TIFFmalloc(stripsize);
+
+ for (y = 0; y <= ysize; y += rowsperstrip) {
+ register unsigned char *pp = strip;
+ register uint32 n;
+
+ n = rowsperstrip;
+ if (n > ysize-y+1)
+ n = ysize-y+1;
+ do {
+ for (x = 0; x <= xsize; x++) {
+ uint32 v = ss[x];
+ pp[0] = v;
+ pp[1] = v >> 8;
+ pp[2] = v >> 16;
+ pp += 3;
+ }
+ ss += xsize+1;
+ } while (--n);
+ if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,0),
+ strip, stripsize) < 0)
+ break;
+ }
+ _TIFFfree(strip);
+}
+
+#undef RED
+#undef GREEN
+#undef BLUE
+#define CVT(x) (((x)*255)/100)
+#define RED CVT(28) /* 28% */
+#define GREEN CVT(59) /* 59% */
+#define BLUE CVT(11) /* 11% */
+
+static void
+svGrey(TIFF* tif, uint32* ss, int xsize, int ysize)
+{
+ register int x, y;
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif));
+
+ for (y = 0; y <= ysize; y++) {
+ for (x = 0; x <= xsize; x++) {
+ unsigned char *cp = (unsigned char *)&ss[x];
+ buf[x] = (RED*cp[3] + GREEN*cp[2] + BLUE*cp[1]) >> 8;
+ }
+ if (TIFFWriteScanline(tif, buf, (uint32) y, 0) < 0)
+ break;
+ ss += xsize+1;
+ }
+ _TIFFfree(buf);
+}
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define ABS(x) ((x)<0?-(x):(x))
+
+static void
+tiffsv(char* name, int x1, int x2, int y1, int y2)
+{
+ TIFF *tif;
+ int xsize, ysize;
+ int xorg, yorg;
+ uint32 *scrbuf;
+
+ xorg = MIN(x1,x2);
+ yorg = MIN(y1,y2);
+ if (xorg<0)
+ xorg = 0;
+ if (yorg<0)
+ yorg = 0;
+ xsize = ABS(x2-x1);
+ ysize = ABS(y2-y1);
+ if (xorg+xsize > xmaxscreen)
+ xsize = xmaxscreen-xorg;
+ if (yorg+ysize > ymaxscreen)
+ ysize = ymaxscreen-yorg;
+ tif = TIFFOpen(name, "w");
+ TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32) (xsize+1));
+ TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32) (ysize+1));
+ TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL,
+ photometric == PHOTOMETRIC_RGB ? 3 : 1);
+ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, config);
+ TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (photometric == PHOTOMETRIC_RGB && jpegcolormode == JPEGCOLORMODE_RGB)
+ photometric = PHOTOMETRIC_YCBCR;
+ TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ if (predictor != 0)
+ TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
+ TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_BOTLEFT);
+ rowsperstrip = TIFFDefaultStripSize(tif, rowsperstrip);
+ TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ scrbuf = (uint32 *)_TIFFmalloc((xsize+1)*(ysize+1)*sizeof (uint32));
+ readdisplay(xorg, yorg, xorg+xsize, yorg+ysize, scrbuf, RD_FREEZE);
+ if (photometric == PHOTOMETRIC_RGB) {
+ if (config == PLANARCONFIG_SEPARATE)
+ svRGBSeparate(tif, scrbuf, xsize, ysize);
+ else
+ svRGBContig(tif, scrbuf, xsize, ysize);
+ } else
+ svGrey(tif, scrbuf, xsize, ysize);
+ (void) TIFFClose(tif);
+ _TIFFfree((char *)scrbuf);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/thumbnail.c b/tiff/tools/thumbnail.c
new file mode 100644
index 0000000..e9e51a3
--- /dev/null
+++ b/tiff/tools/thumbnail.c
@@ -0,0 +1,639 @@
+/* $Id: thumbnail.c,v 1.9.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1994-1997 Sam Leffler
+ * Copyright (c) 1994-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+
+#ifndef TIFFhowmany8
+# define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
+#endif
+
+typedef enum {
+ EXP50,
+ EXP60,
+ EXP70,
+ EXP80,
+ EXP90,
+ EXP,
+ LINEAR
+} Contrast;
+
+static uint32 tnw = 216; /* thumbnail width */
+static uint32 tnh = 274; /* thumbnail height */
+static Contrast contrast = LINEAR; /* current contrast */
+static uint8* thumbnail;
+
+static int cpIFD(TIFF*, TIFF*);
+static int generateThumbnail(TIFF*, TIFF*);
+static void initScale();
+static void usage(void);
+
+extern char* optarg;
+extern int optind;
+
+int
+main(int argc, char* argv[])
+{
+ TIFF* in;
+ TIFF* out;
+ int c;
+
+ while ((c = getopt(argc, argv, "w:h:c:")) != -1) {
+ switch (c) {
+ case 'w': tnw = strtoul(optarg, NULL, 0); break;
+ case 'h': tnh = strtoul(optarg, NULL, 0); break;
+ case 'c': contrast = streq(optarg, "exp50") ? EXP50 :
+ streq(optarg, "exp60") ? EXP60 :
+ streq(optarg, "exp70") ? EXP70 :
+ streq(optarg, "exp80") ? EXP80 :
+ streq(optarg, "exp90") ? EXP90 :
+ streq(optarg, "exp") ? EXP :
+ streq(optarg, "linear")? LINEAR :
+ EXP;
+ break;
+ default: usage();
+ }
+ }
+ if (argc-optind != 2)
+ usage();
+
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return 2;
+ in = TIFFOpen(argv[optind], "r");
+
+ thumbnail = (uint8*) _TIFFmalloc(tnw * tnh);
+ if (!thumbnail) {
+ TIFFError(TIFFFileName(in),
+ "Can't allocate space for thumbnail buffer.");
+ return 1;
+ }
+
+ if (in != NULL) {
+ initScale();
+ do {
+ if (!generateThumbnail(in, out))
+ goto bad;
+ if (!cpIFD(in, out) || !TIFFWriteDirectory(out))
+ goto bad;
+ } while (TIFFReadDirectory(in));
+ (void) TIFFClose(in);
+ }
+ (void) TIFFClose(out);
+ return 0;
+bad:
+ (void) TIFFClose(out);
+ return 1;
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+#undef CopyField4
+#undef CopyField3
+#undef CopyField2
+#undef CopyField
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_IMAGEWIDTH, 1, TIFF_LONG },
+ { TIFFTAG_IMAGELENGTH, 1, TIFF_LONG },
+ { TIFFTAG_BITSPERSAMPLE, 1, TIFF_SHORT },
+ { TIFFTAG_COMPRESSION, 1, TIFF_SHORT },
+ { TIFFTAG_FILLORDER, 1, TIFF_SHORT },
+ { TIFFTAG_SAMPLESPERPIXEL, 1, TIFF_SHORT },
+ { TIFFTAG_ROWSPERSTRIP, 1, TIFF_LONG },
+ { TIFFTAG_PLANARCONFIG, 1, TIFF_SHORT },
+ { TIFFTAG_GROUP3OPTIONS, 1, TIFF_LONG },
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_PHOTOMETRIC, 1, TIFF_SHORT },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_ORIENTATION, 1, TIFF_SHORT },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_PAGENUMBER, 2, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, 1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_BADFAXLINES, 1, TIFF_LONG },
+ { TIFFTAG_CLEANFAXDATA, 1, TIFF_SHORT },
+ { TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_INKNAMES, 1, TIFF_ASCII },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_EXTRASAMPLES, (uint16) -1, TIFF_SHORT },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+static void
+cpTags(TIFF* in, TIFF* out)
+{
+ struct cpTag *p;
+ for (p = tags; p < &tags[NTAGS]; p++)
+ cpTag(in, out, p->tag, p->count, p->type);
+}
+#undef NTAGS
+
+static int
+cpStrips(TIFF* in, TIFF* out)
+{
+ tsize_t bufsize = TIFFStripSize(in);
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
+
+ if (buf) {
+ tstrip_t s, ns = TIFFNumberOfStrips(in);
+ tsize_t *bytecounts;
+
+ TIFFGetField(in, TIFFTAG_STRIPBYTECOUNTS, &bytecounts);
+ for (s = 0; s < ns; s++) {
+ if (bytecounts[s] > bufsize) {
+ buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[s]);
+ if (!buf)
+ goto bad;
+ bufsize = bytecounts[s];
+ }
+ if (TIFFReadRawStrip(in, s, buf, bytecounts[s]) < 0 ||
+ TIFFWriteRawStrip(out, s, buf, bytecounts[s]) < 0) {
+ _TIFFfree(buf);
+ return 0;
+ }
+ }
+ _TIFFfree(buf);
+ return 1;
+ }
+
+bad:
+ TIFFError(TIFFFileName(in),
+ "Can't allocate space for strip buffer.");
+ return 0;
+}
+
+static int
+cpTiles(TIFF* in, TIFF* out)
+{
+ tsize_t bufsize = TIFFTileSize(in);
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
+
+ if (buf) {
+ ttile_t t, nt = TIFFNumberOfTiles(in);
+ tsize_t *bytecounts;
+
+ TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts);
+ for (t = 0; t < nt; t++) {
+ if (bytecounts[t] > bufsize) {
+ buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[t]);
+ if (!buf)
+ goto bad;
+ bufsize = bytecounts[t];
+ }
+ if (TIFFReadRawTile(in, t, buf, bytecounts[t]) < 0 ||
+ TIFFWriteRawTile(out, t, buf, bytecounts[t]) < 0) {
+ _TIFFfree(buf);
+ return 0;
+ }
+ }
+ _TIFFfree(buf);
+ return 1;
+ }
+
+bad:
+ TIFFError(TIFFFileName(in),
+ "Can't allocate space for tile buffer.");
+ return (0);
+}
+
+static int
+cpIFD(TIFF* in, TIFF* out)
+{
+ cpTags(in, out);
+ if (TIFFIsTiled(in)) {
+ if (!cpTiles(in, out))
+ return (0);
+ } else {
+ if (!cpStrips(in, out))
+ return (0);
+ }
+ return (1);
+}
+
+static uint16 photometric; /* current photometric of raster */
+static uint16 filterWidth; /* filter width in pixels */
+static uint32 stepSrcWidth; /* src image stepping width */
+static uint32 stepDstWidth; /* dest stepping width */
+static uint8* src0; /* horizontal bit stepping (start) */
+static uint8* src1; /* horizontal bit stepping (middle) */
+static uint8* src2; /* horizontal bit stepping (end) */
+static uint32* rowoff; /* row offset for stepping */
+static uint8 cmap[256]; /* colormap indexes */
+static uint8 bits[256]; /* count of bits set */
+
+static void
+setupBitsTables()
+{
+ int i;
+ for (i = 0; i < 256; i++) {
+ int n = 0;
+ if (i&0x01) n++;
+ if (i&0x02) n++;
+ if (i&0x04) n++;
+ if (i&0x08) n++;
+ if (i&0x10) n++;
+ if (i&0x20) n++;
+ if (i&0x40) n++;
+ if (i&0x80) n++;
+ bits[i] = n;
+ }
+}
+
+static int clamp(float v, int low, int high)
+ { return (v < low ? low : v > high ? high : (int)v); }
+
+#ifndef M_E
+#define M_E 2.7182818284590452354
+#endif
+
+static void
+expFill(float pct[], uint32 p, uint32 n)
+{
+ uint32 i;
+ uint32 c = (p * n) / 100;
+ for (i = 1; i < c; i++)
+ pct[i] = (float) (1-exp(i/((double)(n-1)))/ M_E);
+ for (; i < n; i++)
+ pct[i] = 0.;
+}
+
+static void
+setupCmap()
+{
+ float pct[256]; /* known to be large enough */
+ uint32 i;
+ pct[0] = 1; /* force white */
+ switch (contrast) {
+ case EXP50: expFill(pct, 50, 256); break;
+ case EXP60: expFill(pct, 60, 256); break;
+ case EXP70: expFill(pct, 70, 256); break;
+ case EXP80: expFill(pct, 80, 256); break;
+ case EXP90: expFill(pct, 90, 256); break;
+ case EXP: expFill(pct, 100, 256); break;
+ case LINEAR:
+ for (i = 1; i < 256; i++)
+ pct[i] = 1-((float)i)/(256-1);
+ break;
+ }
+ switch (photometric) {
+ case PHOTOMETRIC_MINISWHITE:
+ for (i = 0; i < 256; i++)
+ cmap[i] = clamp(255*pct[(256-1)-i], 0, 255);
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ for (i = 0; i < 256; i++)
+ cmap[i] = clamp(255*pct[i], 0, 255);
+ break;
+ }
+}
+
+static void
+initScale()
+{
+ src0 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
+ src1 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
+ src2 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
+ rowoff = (uint32*) _TIFFmalloc(sizeof (uint32) * tnw);
+ filterWidth = 0;
+ stepDstWidth = stepSrcWidth = 0;
+ setupBitsTables();
+}
+
+/*
+ * Calculate the horizontal accumulation parameteres
+ * according to the widths of the src and dst images.
+ */
+static void
+setupStepTables(uint32 sw)
+{
+ if (stepSrcWidth != sw || stepDstWidth != tnw) {
+ int step = sw;
+ int limit = tnw;
+ int err = 0;
+ uint32 sx = 0;
+ uint32 x;
+ int fw;
+ uint8 b;
+ for (x = 0; x < tnw; x++) {
+ uint32 sx0 = sx;
+ err += step;
+ while (err >= limit) {
+ err -= limit;
+ sx++;
+ }
+ rowoff[x] = sx0 >> 3;
+ fw = sx - sx0; /* width */
+ b = (fw < 8) ? 0xff<<(8-fw) : 0xff;
+ src0[x] = b >> (sx0&7);
+ fw -= 8 - (sx0&7);
+ if (fw < 0)
+ fw = 0;
+ src1[x] = fw >> 3;
+ fw -= (fw>>3)<<3;
+ src2[x] = 0xff << (8-fw);
+ }
+ stepSrcWidth = sw;
+ stepDstWidth = tnw;
+ }
+}
+
+static void
+setrow(uint8* row, uint32 nrows, const uint8* rows[])
+{
+ uint32 x;
+ uint32 area = nrows * filterWidth;
+ for (x = 0; x < tnw; x++) {
+ uint32 mask0 = src0[x];
+ uint32 fw = src1[x];
+ uint32 mask1 = src1[x];
+ uint32 off = rowoff[x];
+ uint32 acc = 0;
+ uint32 y, i;
+ for (y = 0; y < nrows; y++) {
+ const uint8* src = rows[y] + off;
+ acc += bits[*src++ & mask0];
+ switch (fw) {
+ default:
+ for (i = fw; i > 8; i--)
+ acc += bits[*src++];
+ /* fall thru... */
+ case 8: acc += bits[*src++];
+ case 7: acc += bits[*src++];
+ case 6: acc += bits[*src++];
+ case 5: acc += bits[*src++];
+ case 4: acc += bits[*src++];
+ case 3: acc += bits[*src++];
+ case 2: acc += bits[*src++];
+ case 1: acc += bits[*src++];
+ case 0: break;
+ }
+ acc += bits[*src & mask1];
+ }
+ *row++ = cmap[(255*acc)/area];
+ }
+}
+
+/*
+ * Install the specified image. The
+ * image is resized to fit the display page using
+ * a box filter. The resultant pixels are mapped
+ * with a user-selectable contrast curve.
+ */
+static void
+setImage1(const uint8* br, uint32 rw, uint32 rh)
+{
+ int step = rh;
+ int limit = tnh;
+ int err = 0;
+ int bpr = TIFFhowmany8(rw);
+ int sy = 0;
+ uint8* row = thumbnail;
+ uint32 dy;
+ for (dy = 0; dy < tnh; dy++) {
+ const uint8* rows[256];
+ uint32 nrows = 1;
+ fprintf(stderr, "bpr=%d, sy=%d, bpr*sy=%d\n", bpr, sy, bpr*sy);
+ rows[0] = br + bpr*sy;
+ err += step;
+ while (err >= limit) {
+ err -= limit;
+ sy++;
+ if (err >= limit)
+ rows[nrows++] = br + bpr*sy;
+ }
+ setrow(row, nrows, rows);
+ row += tnw;
+ }
+}
+
+static void
+setImage(const uint8* br, uint32 rw, uint32 rh)
+{
+ filterWidth = (uint16) ceil((double) rw / (double) tnw);
+ setupStepTables(rw);
+ setImage1(br, rw, rh);
+}
+
+static int
+generateThumbnail(TIFF* in, TIFF* out)
+{
+ unsigned char* raster;
+ unsigned char* rp;
+ uint32 sw, sh, rps;
+ uint16 bps, spp;
+ tsize_t rowsize, rastersize;
+ tstrip_t s, ns = TIFFNumberOfStrips(in);
+ uint32 diroff[1];
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &sw);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &sh);
+ TIFFGetFieldDefaulted(in, TIFFTAG_BITSPERSAMPLE, &bps);
+ TIFFGetFieldDefaulted(in, TIFFTAG_SAMPLESPERPIXEL, &spp);
+ TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rps);
+ if (spp != 1 || bps != 1)
+ return 0;
+ rowsize = TIFFScanlineSize(in);
+ rastersize = sh * rowsize;
+ fprintf(stderr, "rastersize=%u\n", (unsigned int)rastersize);
+ raster = (unsigned char*)_TIFFmalloc(rastersize);
+ if (!raster) {
+ TIFFError(TIFFFileName(in),
+ "Can't allocate space for raster buffer.");
+ return 0;
+ }
+ rp = raster;
+ for (s = 0; s < ns; s++) {
+ (void) TIFFReadEncodedStrip(in, s, rp, -1);
+ rp += rps * rowsize;
+ }
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric);
+ setupCmap();
+ setImage(raster, sw, sh);
+ _TIFFfree(raster);
+
+ TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) tnw);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) tnh);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (uint16) 8);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (uint16) 1);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ cpTag(in, out, TIFFTAG_SOFTWARE, (uint16) -1, TIFF_ASCII);
+ cpTag(in, out, TIFFTAG_IMAGEDESCRIPTION, (uint16) -1, TIFF_ASCII);
+ cpTag(in, out, TIFFTAG_DATETIME, (uint16) -1, TIFF_ASCII);
+ cpTag(in, out, TIFFTAG_HOSTCOMPUTER, (uint16) -1, TIFF_ASCII);
+ diroff[0] = 0;
+ TIFFSetField(out, TIFFTAG_SUBIFD, 1, diroff);
+ return (TIFFWriteEncodedStrip(out, 0, thumbnail, tnw*tnh) != -1 &&
+ TIFFWriteDirectory(out) != -1);
+}
+
+char* stuff[] = {
+"usage: thumbnail [options] input.tif output.tif",
+"where options are:",
+" -h # specify thumbnail image height (default is 274)",
+" -w # specify thumbnail image width (default is 216)",
+"",
+" -c linear use linear contrast curve",
+" -c exp50 use 50% exponential contrast curve",
+" -c exp60 use 60% exponential contrast curve",
+" -c exp70 use 70% exponential contrast curve",
+" -c exp80 use 80% exponential contrast curve",
+" -c exp90 use 90% exponential contrast curve",
+" -c exp use pure exponential contrast curve",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiff2bw.c b/tiff/tools/tiff2bw.c
new file mode 100644
index 0000000..9e1e23a
--- /dev/null
+++ b/tiff/tools/tiff2bw.c
@@ -0,0 +1,467 @@
+/* $Id: tiff2bw.c,v 1.12.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+/* x% weighting -> fraction of full color */
+#define PCT(x) (((x)*255+127)/100)
+int RED = PCT(30); /* 30% */
+int GREEN = PCT(59); /* 59% */
+int BLUE = PCT(11); /* 11% */
+
+static void usage(void);
+static int processCompressOptions(char*);
+
+static void
+compresscontig(unsigned char* out, unsigned char* rgb, uint32 n)
+{
+ register int v, red = RED, green = GREEN, blue = BLUE;
+
+ while (n-- > 0) {
+ v = red*(*rgb++);
+ v += green*(*rgb++);
+ v += blue*(*rgb++);
+ *out++ = v>>8;
+ }
+}
+
+static void
+compresssep(unsigned char* out,
+ unsigned char* r, unsigned char* g, unsigned char* b, uint32 n)
+{
+ register uint32 red = RED, green = GREEN, blue = BLUE;
+
+ while (n-- > 0)
+ *out++ = (unsigned char)
+ ((red*(*r++) + green*(*g++) + blue*(*b++)) >> 8);
+}
+
+static int
+checkcmap(TIFF* tif, int n, uint16* r, uint16* g, uint16* b)
+{
+ while (n-- > 0)
+ if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+ return (16);
+ TIFFWarning(TIFFFileName(tif), "Assuming 8-bit colormap");
+ return (8);
+}
+
+static void
+compresspalette(unsigned char* out, unsigned char* data, uint32 n, uint16* rmap, uint16* gmap, uint16* bmap)
+{
+ register int v, red = RED, green = GREEN, blue = BLUE;
+
+ while (n-- > 0) {
+ unsigned int ix = *data++;
+ v = red*rmap[ix];
+ v += green*gmap[ix];
+ v += blue*bmap[ix];
+ *out++ = v>>8;
+ }
+}
+
+static uint16 compression = (uint16) -1;
+static uint16 predictor = 0;
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static int quality = 75; /* JPEG quality */
+
+static void cpTags(TIFF* in, TIFF* out);
+
+int
+main(int argc, char* argv[])
+{
+ uint32 rowsperstrip = (uint32) -1;
+ TIFF *in, *out;
+ uint32 w, h;
+ uint16 samplesperpixel;
+ uint16 bitspersample;
+ uint16 config;
+ uint16 photometric;
+ uint16* red;
+ uint16* green;
+ uint16* blue;
+ tsize_t rowsize;
+ register uint32 row;
+ register tsample_t s;
+ unsigned char *inbuf, *outbuf;
+ char thing[1024];
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "c:r:R:G:B:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case 'R':
+ RED = PCT(atoi(optarg));
+ break;
+ case 'G':
+ GREEN = PCT(atoi(optarg));
+ break;
+ case 'B':
+ BLUE = PCT(atoi(optarg));
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage();
+ in = TIFFOpen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ photometric = 0;
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric);
+ if (photometric != PHOTOMETRIC_RGB && photometric != PHOTOMETRIC_PALETTE ) {
+ fprintf(stderr,
+ "%s: Bad photometric; can only handle RGB and Palette images.\n",
+ argv[optind]);
+ return (-1);
+ }
+ TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (samplesperpixel != 1 && samplesperpixel != 3) {
+ fprintf(stderr, "%s: Bad samples/pixel %u.\n",
+ argv[optind], samplesperpixel);
+ return (-1);
+ }
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8) {
+ fprintf(stderr,
+ " %s: Sorry, only handle 8-bit samples.\n", argv[optind]);
+ return (-1);
+ }
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config);
+
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-1);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, w);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, h);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ cpTags(in, out);
+ if (compression != (uint16) -1) {
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ }
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
+ sprintf(thing, "B&W version of %s", argv[optind]);
+ TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, thing);
+ TIFFSetField(out, TIFFTAG_SOFTWARE, "tiff2bw");
+ outbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(out));
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+
+#define pack(a,b) ((a)<<8 | (b))
+ switch (pack(photometric, config)) {
+ case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_CONTIG):
+ case pack(PHOTOMETRIC_PALETTE, PLANARCONFIG_SEPARATE):
+ TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue);
+ /*
+ * Convert 16-bit colormap to 8-bit (unless it looks
+ * like an old-style 8-bit colormap).
+ */
+ if (checkcmap(in, 1<<bitspersample, red, green, blue) == 16) {
+ int i;
+#define CVT(x) (((x) * 255L) / ((1L<<16)-1))
+ for (i = (1<<bitspersample)-1; i >= 0; i--) {
+ red[i] = CVT(red[i]);
+ green[i] = CVT(green[i]);
+ blue[i] = CVT(blue[i]);
+ }
+#undef CVT
+ }
+ inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ for (row = 0; row < h; row++) {
+ if (TIFFReadScanline(in, inbuf, row, 0) < 0)
+ break;
+ compresspalette(outbuf, inbuf, w, red, green, blue);
+ if (TIFFWriteScanline(out, outbuf, row, 0) < 0)
+ break;
+ }
+ break;
+ case pack(PHOTOMETRIC_RGB, PLANARCONFIG_CONTIG):
+ inbuf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ for (row = 0; row < h; row++) {
+ if (TIFFReadScanline(in, inbuf, row, 0) < 0)
+ break;
+ compresscontig(outbuf, inbuf, w);
+ if (TIFFWriteScanline(out, outbuf, row, 0) < 0)
+ break;
+ }
+ break;
+ case pack(PHOTOMETRIC_RGB, PLANARCONFIG_SEPARATE):
+ rowsize = TIFFScanlineSize(in);
+ inbuf = (unsigned char *)_TIFFmalloc(3*rowsize);
+ for (row = 0; row < h; row++) {
+ for (s = 0; s < 3; s++)
+ if (TIFFReadScanline(in,
+ inbuf+s*rowsize, row, s) < 0)
+ return (-1);
+ compresssep(outbuf,
+ inbuf, inbuf+rowsize, inbuf+2*rowsize, w);
+ if (TIFFWriteScanline(out, outbuf, row, 0) < 0)
+ break;
+ }
+ break;
+ }
+#undef pack
+ TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ compression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+#undef CopyField4
+#undef CopyField3
+#undef CopyField2
+#undef CopyField
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, 1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES,(uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_EXTRASAMPLES, (uint16) -1, TIFF_SHORT },
+ { TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_STONITS, 1, TIFF_DOUBLE },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+static void
+cpTags(TIFF* in, TIFF* out)
+{
+ struct cpTag *p;
+ for (p = tags; p < &tags[NTAGS]; p++)
+ cpTag(in, out, p->tag, p->count, p->type);
+}
+#undef NTAGS
+
+char* stuff[] = {
+"usage: tiff2bw [options] input.tif output.tif",
+"where options are:",
+" -R % use #% from red channel",
+" -G % use #% from green channel",
+" -B % use #% from blue channel",
+"",
+" -r # make each strip have no more than # rows",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c g3[:opts] compress output with CCITT Group 3 encoding",
+" -c g4 compress output with CCITT Group 4 encoding",
+" -c none use no compression algorithm on output",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiff2pdf.c b/tiff/tools/tiff2pdf.c
new file mode 100644
index 0000000..b1886c6
--- /dev/null
+++ b/tiff/tools/tiff2pdf.c
@@ -0,0 +1,5405 @@
+/* $Id: tiff2pdf.c,v 1.37.2.10 2010-06-13 19:18:41 fwarmerdam Exp $
+ *
+ * tiff2pdf - converts a TIFF image to a PDF document
+ *
+ * Copyright (c) 2003 Ross Finlayson
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the name of
+ * Ross Finlayson may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Ross Finlayson.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL ROSS FINLAYSON BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define TIFF2PDF_MODULE "tiff2pdf"
+
+#define PS_UNIT_SIZE 72.0F
+
+/* This type is of PDF color spaces. */
+typedef enum {
+ T2P_CS_BILEVEL = 0x01, /* Bilevel, black and white */
+ T2P_CS_GRAY = 0x02, /* Single channel */
+ T2P_CS_RGB = 0x04, /* Three channel tristimulus RGB */
+ T2P_CS_CMYK = 0x08, /* Four channel CMYK print inkset */
+ T2P_CS_LAB = 0x10, /* Three channel L*a*b* color space */
+ T2P_CS_PALETTE = 0x1000,/* One of the above with a color map */
+ T2P_CS_CALGRAY = 0x20, /* Calibrated single channel */
+ T2P_CS_CALRGB = 0x40, /* Calibrated three channel tristimulus RGB */
+ T2P_CS_ICCBASED = 0x80 /* ICC profile color specification */
+} t2p_cs_t;
+
+/* This type is of PDF compression types. */
+typedef enum{
+ T2P_COMPRESS_NONE=0x00
+#ifdef CCITT_SUPPORT
+ , T2P_COMPRESS_G4=0x01
+#endif
+#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
+ , T2P_COMPRESS_JPEG=0x02
+#endif
+#ifdef ZIP_SUPPORT
+ , T2P_COMPRESS_ZIP=0x04
+#endif
+} t2p_compress_t;
+
+/* This type is whether TIFF image data can be used in PDF without transcoding. */
+typedef enum{
+ T2P_TRANSCODE_RAW=0x01, /* The raw data from the input can be used without recompressing */
+ T2P_TRANSCODE_ENCODE=0x02 /* The data from the input is perhaps unencoded and reencoded */
+} t2p_transcode_t;
+
+/* This type is of information about the data samples of the input image. */
+typedef enum{
+ T2P_SAMPLE_NOTHING=0x0000, /* The unencoded samples are normal for the output colorspace */
+ T2P_SAMPLE_ABGR_TO_RGB=0x0001, /* The unencoded samples are the result of ReadRGBAImage */
+ T2P_SAMPLE_RGBA_TO_RGB=0x0002, /* The unencoded samples are contiguous RGBA */
+ T2P_SAMPLE_RGBAA_TO_RGB=0x0004, /* The unencoded samples are RGBA with premultiplied alpha */
+ T2P_SAMPLE_YCBCR_TO_RGB=0x0008,
+ T2P_SAMPLE_YCBCR_TO_LAB=0x0010,
+ T2P_SAMPLE_REALIZE_PALETTE=0x0020, /* The unencoded samples are indexes into the color map */
+ T2P_SAMPLE_SIGNED_TO_UNSIGNED=0x0040, /* The unencoded samples are signed instead of unsignd */
+ T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED=0x0040, /* The L*a*b* samples have a* and b* signed */
+ T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG=0x0100 /* The unencoded samples are separate instead of contiguous */
+} t2p_sample_t;
+
+/* This type is of error status of the T2P struct. */
+typedef enum{
+ T2P_ERR_OK = 0, /* This is the value of t2p->t2p_error when there is no error */
+ T2P_ERR_ERROR = 1 /* This is the value of t2p->t2p_error when there was an error */
+} t2p_err_t;
+
+/* This struct defines a logical page of a TIFF. */
+typedef struct {
+ tdir_t page_directory;
+ uint32 page_number;
+ ttile_t page_tilecount;
+ uint32 page_extra;
+} T2P_PAGE;
+
+/* This struct defines a PDF rectangle's coordinates. */
+typedef struct {
+ float x1;
+ float y1;
+ float x2;
+ float y2;
+ float mat[9];
+} T2P_BOX;
+
+/* This struct defines a tile of a PDF. */
+typedef struct {
+ T2P_BOX tile_box;
+} T2P_TILE;
+
+/* This struct defines information about the tiles on a PDF page. */
+typedef struct {
+ ttile_t tiles_tilecount;
+ uint32 tiles_tilewidth;
+ uint32 tiles_tilelength;
+ uint32 tiles_tilecountx;
+ uint32 tiles_tilecounty;
+ uint32 tiles_edgetilewidth;
+ uint32 tiles_edgetilelength;
+ T2P_TILE* tiles_tiles;
+} T2P_TILES;
+
+/* This struct is the context of a function to generate PDF from a TIFF. */
+typedef struct {
+ t2p_err_t t2p_error;
+ T2P_PAGE* tiff_pages;
+ T2P_TILES* tiff_tiles;
+ tdir_t tiff_pagecount;
+ uint16 tiff_compression;
+ uint16 tiff_photometric;
+ uint16 tiff_fillorder;
+ uint16 tiff_bitspersample;
+ uint16 tiff_samplesperpixel;
+ uint16 tiff_planar;
+ uint32 tiff_width;
+ uint32 tiff_length;
+ float tiff_xres;
+ float tiff_yres;
+ uint16 tiff_orientation;
+ toff_t tiff_dataoffset;
+ tsize_t tiff_datasize;
+ uint16 tiff_resunit;
+ uint16 pdf_centimeters;
+ uint16 pdf_overrideres;
+ uint16 pdf_overridepagesize;
+ float pdf_defaultxres;
+ float pdf_defaultyres;
+ float pdf_xres;
+ float pdf_yres;
+ float pdf_defaultpagewidth;
+ float pdf_defaultpagelength;
+ float pdf_pagewidth;
+ float pdf_pagelength;
+ float pdf_imagewidth;
+ float pdf_imagelength;
+ T2P_BOX pdf_mediabox;
+ T2P_BOX pdf_imagebox;
+ uint16 pdf_majorversion;
+ uint16 pdf_minorversion;
+ uint32 pdf_catalog;
+ uint32 pdf_pages;
+ uint32 pdf_info;
+ uint32 pdf_palettecs;
+ uint16 pdf_fitwindow;
+ uint32 pdf_startxref;
+ unsigned char* pdf_fileid;
+ unsigned char* pdf_datetime;
+ unsigned char* pdf_creator;
+ unsigned char* pdf_author;
+ unsigned char* pdf_title;
+ unsigned char* pdf_subject;
+ unsigned char* pdf_keywords;
+ t2p_cs_t pdf_colorspace;
+ uint16 pdf_colorspace_invert;
+ uint16 pdf_switchdecode;
+ uint16 pdf_palettesize;
+ unsigned char* pdf_palette;
+ int pdf_labrange[4];
+ t2p_compress_t pdf_defaultcompression;
+ uint16 pdf_defaultcompressionquality;
+ t2p_compress_t pdf_compression;
+ uint16 pdf_compressionquality;
+ uint16 pdf_nopassthrough;
+ t2p_transcode_t pdf_transcode;
+ t2p_sample_t pdf_sample;
+ uint32* pdf_xrefoffsets;
+ uint32 pdf_xrefcount;
+ tdir_t pdf_page;
+#ifdef OJPEG_SUPPORT
+ tdata_t pdf_ojpegdata;
+ uint32 pdf_ojpegdatalength;
+ uint32 pdf_ojpegiflength;
+#endif
+ float tiff_whitechromaticities[2];
+ float tiff_primarychromaticities[6];
+ float tiff_referenceblackwhite[2];
+ float* tiff_transferfunction[3];
+ int pdf_image_interpolate; /* 0 (default) : do not interpolate,
+ 1 : interpolate */
+ uint16 tiff_transferfunctioncount;
+ uint32 pdf_icccs;
+ uint32 tiff_iccprofilelength;
+ tdata_t tiff_iccprofile;
+
+ /* fields for custom read/write procedures */
+ FILE *outputfile;
+ int outputdisable;
+ tsize_t outputwritten;
+} T2P;
+
+/* These functions are called by main. */
+
+void tiff2pdf_usage(void);
+int tiff2pdf_match_paper_size(float*, float*, char*);
+
+/* These functions are used to generate a PDF from a TIFF. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+T2P* t2p_init(void);
+void t2p_validate(T2P*);
+tsize_t t2p_write_pdf(T2P*, TIFF*, TIFF*);
+void t2p_free(T2P*);
+
+#ifdef __cplusplus
+}
+#endif
+
+void t2p_read_tiff_init(T2P*, TIFF*);
+int t2p_cmp_t2p_page(const void*, const void*);
+void t2p_read_tiff_data(T2P*, TIFF*);
+void t2p_read_tiff_size(T2P*, TIFF*);
+void t2p_read_tiff_size_tile(T2P*, TIFF*, ttile_t);
+int t2p_tile_is_right_edge(T2P_TILES, ttile_t);
+int t2p_tile_is_bottom_edge(T2P_TILES, ttile_t);
+int t2p_tile_is_edge(T2P_TILES, ttile_t);
+int t2p_tile_is_corner_edge(T2P_TILES, ttile_t);
+tsize_t t2p_readwrite_pdf_image(T2P*, TIFF*, TIFF*);
+tsize_t t2p_readwrite_pdf_image_tile(T2P*, TIFF*, TIFF*, ttile_t);
+#ifdef OJPEG_SUPPORT
+int t2p_process_ojpeg_tables(T2P*, TIFF*);
+#endif
+#ifdef JPEG_SUPPORT
+int t2p_process_jpeg_strip(unsigned char*, tsize_t*, unsigned char*, tsize_t*, tstrip_t, uint32);
+#endif
+void t2p_tile_collapse_left(tdata_t, tsize_t, uint32, uint32, uint32);
+void t2p_write_advance_directory(T2P*, TIFF*);
+tsize_t t2p_sample_planar_separate_to_contig(T2P*, unsigned char*, unsigned char*, tsize_t);
+tsize_t t2p_sample_realize_palette(T2P*, unsigned char*);
+tsize_t t2p_sample_abgr_to_rgb(tdata_t, uint32);
+tsize_t t2p_sample_rgba_to_rgb(tdata_t, uint32);
+tsize_t t2p_sample_rgbaa_to_rgb(tdata_t, uint32);
+tsize_t t2p_sample_lab_signed_to_unsigned(tdata_t, uint32);
+tsize_t t2p_write_pdf_header(T2P*, TIFF*);
+tsize_t t2p_write_pdf_obj_start(uint32, TIFF*);
+tsize_t t2p_write_pdf_obj_end(TIFF*);
+tsize_t t2p_write_pdf_name(unsigned char*, TIFF*);
+tsize_t t2p_write_pdf_string(unsigned char*, TIFF*);
+tsize_t t2p_write_pdf_stream(tdata_t, tsize_t, TIFF*);
+tsize_t t2p_write_pdf_stream_start(TIFF*);
+tsize_t t2p_write_pdf_stream_end(TIFF*);
+tsize_t t2p_write_pdf_stream_dict(tsize_t, uint32, TIFF*);
+tsize_t t2p_write_pdf_stream_dict_start(TIFF*);
+tsize_t t2p_write_pdf_stream_dict_end(TIFF*);
+tsize_t t2p_write_pdf_stream_length(tsize_t, TIFF*);
+tsize_t t2p_write_pdf_catalog(T2P*, TIFF*);
+tsize_t t2p_write_pdf_info(T2P*, TIFF*, TIFF*);
+void t2p_pdf_currenttime(T2P*);
+void t2p_pdf_tifftime(T2P*, TIFF*);
+tsize_t t2p_write_pdf_pages(T2P*, TIFF*);
+tsize_t t2p_write_pdf_page(uint32, T2P*, TIFF*);
+void t2p_compose_pdf_page(T2P*);
+void t2p_compose_pdf_page_orient(T2P_BOX*, uint16);
+void t2p_compose_pdf_page_orient_flip(T2P_BOX*, uint16);
+tsize_t t2p_write_pdf_page_content(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_stream_dict(ttile_t, T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_cs(T2P*, TIFF*);
+tsize_t t2p_write_pdf_transfer(T2P*, TIFF*);
+tsize_t t2p_write_pdf_transfer_dict(T2P*, TIFF*, uint16);
+tsize_t t2p_write_pdf_transfer_stream(T2P*, TIFF*, uint16);
+tsize_t t2p_write_pdf_xobject_calcs(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_icccs(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_icccs_dict(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_icccs_stream(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_cs_stream(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_decode(T2P*, TIFF*);
+tsize_t t2p_write_pdf_xobject_stream_filter(ttile_t, T2P*, TIFF*);
+tsize_t t2p_write_pdf_xreftable(T2P*, TIFF*);
+tsize_t t2p_write_pdf_trailer(T2P*, TIFF*);
+
+static void
+t2p_disable(TIFF *tif)
+{
+ T2P *t2p = (T2P*) TIFFClientdata(tif);
+ t2p->outputdisable = 1;
+}
+
+static void
+t2p_enable(TIFF *tif)
+{
+ T2P *t2p = (T2P*) TIFFClientdata(tif);
+ t2p->outputdisable = 0;
+}
+
+/*
+ * Procs for TIFFClientOpen
+ */
+
+static tsize_t
+t2pReadFile(TIFF *tif, tdata_t data, tsize_t size)
+{
+ thandle_t client = TIFFClientdata(tif);
+ TIFFReadWriteProc proc = TIFFGetReadProc(tif);
+ if (proc)
+ return proc(client, data, size);
+ return -1;
+}
+
+static tsize_t
+t2pWriteFile(TIFF *tif, tdata_t data, tsize_t size)
+{
+ thandle_t client = TIFFClientdata(tif);
+ TIFFReadWriteProc proc = TIFFGetWriteProc(tif);
+ if (proc)
+ return proc(client, data, size);
+ return -1;
+}
+
+static toff_t
+t2pSeekFile(TIFF *tif, toff_t offset, int whence)
+{
+ thandle_t client = TIFFClientdata(tif);
+ TIFFSeekProc proc = TIFFGetSeekProc(tif);
+ if (proc)
+ return proc(client, offset, whence);
+ return -1;
+}
+
+static tsize_t
+t2p_readproc(thandle_t handle, tdata_t data, tsize_t size)
+{
+ (void) handle, (void) data, (void) size;
+ return -1;
+}
+
+static tsize_t
+t2p_writeproc(thandle_t handle, tdata_t data, tsize_t size)
+{
+ T2P *t2p = (T2P*) handle;
+ if (t2p->outputdisable <= 0 && t2p->outputfile) {
+ tsize_t written = fwrite(data, 1, size, t2p->outputfile);
+ t2p->outputwritten += written;
+ return written;
+ }
+ return size;
+}
+
+static toff_t
+t2p_seekproc(thandle_t handle, toff_t offset, int whence)
+{
+ T2P *t2p = (T2P*) handle;
+ if (t2p->outputdisable <= 0 && t2p->outputfile)
+ return fseek(t2p->outputfile, offset, whence);
+ return offset;
+}
+
+static int
+t2p_closeproc(thandle_t handle)
+{
+ (void) handle;
+ return 0;
+}
+
+static toff_t
+t2p_sizeproc(thandle_t handle)
+{
+ (void) handle;
+ return -1;
+}
+
+static int
+t2p_mapproc(thandle_t handle, tdata_t *data, toff_t *offset)
+{
+ (void) handle, (void) data, (void) offset;
+ return -1;
+}
+
+static void
+t2p_unmapproc(thandle_t handle, tdata_t data, toff_t offset)
+{
+ (void) handle, (void) data, (void) offset;
+}
+
+/*
+
+ This is the main function.
+
+ The program converts one TIFF file to one PDF file, including multiple page
+ TIFF files, tiled TIFF files, black and white. grayscale, and color TIFF
+ files that contain data of TIFF photometric interpretations of bilevel,
+ grayscale, RGB, YCbCr, CMYK separation, and ICC L*a*b* as supported by
+ libtiff and PDF.
+
+ If you have multiple TIFF files to convert into one PDF file then use tiffcp
+ or other program to concatenate the files into a multiple page TIFF file.
+ If the input TIFF file is of huge dimensions (greater than 10000 pixels height
+ or width) convert the input image to a tiled TIFF if it is not already.
+
+ The standard output is standard output. Set the output file name with the
+ "-o output.pdf" option.
+
+ All black and white files are compressed into a single strip CCITT G4 Fax
+ compressed PDF, unless tiled, where tiled black and white images are
+ compressed into tiled CCITT G4 Fax compressed PDF, libtiff CCITT support
+ is assumed.
+
+ Color and grayscale data can be compressed using either JPEG compression,
+ ITU-T T.81, or Zip/Deflate LZ77 compression, per PNG 1.2 and RFC 1951. Set
+ the compression type using the -j or -z options. JPEG compression support
+ requires that libtiff be configured with JPEG support, and Zip/Deflate
+ compression support requires that libtiff is configured with Zip support,
+ in tiffconf.h. Use only one or the other of -j and -z. The -q option
+ sets the image compression quality, that is 1-100 with libjpeg JPEG
+ compression and one of 1, 10, 11, 12, 13, 14, or 15 for PNG group compression
+ predictor methods, add 100, 200, ..., 900 to set zlib compression quality 1-9.
+ PNG Group differencing predictor methods are not currently implemented.
+
+ If the input TIFF contains single strip CCITT G4 Fax compressed information,
+ then that is written to the PDF file without transcoding, unless the options
+ of no compression and no passthrough are set, -d and -n.
+
+ If the input TIFF contains JPEG or single strip Zip/Deflate compressed
+ information, and they are configured, then that is written to the PDF file
+ without transcoding, unless the options of no compression and no passthrough
+ are set.
+
+ The default page size upon which the TIFF image is placed is determined by
+ the resolution and extent of the image data. Default values for the TIFF
+ image resolution can be set using the -x and -y options. The page size can
+ be set using the -p option for paper size, or -w and -l for paper width and
+ length, then each page of the TIFF image is centered on its page. The
+ distance unit for default resolution and page width and length can be set
+ by the -u option, the default unit is inch.
+
+ Various items of the output document information can be set with the -e, -c,
+ -a, -t, -s, and -k tags. Setting the argument of the option to "" for these
+ tags causes the relevant document information field to be not written. Some
+ of the document information values otherwise get their information from the
+ input TIFF image, the software, author, document name, and image description.
+
+ The output PDF file conforms to the PDF 1.1 specification or PDF 1.2 if using
+ Zip/Deflate compression.
+
+ The Portable Document Format (PDF) specification is copyrighted by Adobe
+ Systems, Incorporated. Todos derechos reservados.
+
+ Here is a listing of the usage example and the options to the tiff2pdf
+ program that is part of the libtiff distribution. Options followed by
+ a colon have a required argument.
+
+ usage: tiff2pdf [options] input.tif
+
+ options:
+ -o: output to file name
+
+ -j: compress with JPEG (requires libjpeg configured with libtiff)
+ -z: compress with Zip/Deflate (requires zlib configured with libtiff)
+ -q: compression quality
+ -n: no compressed data passthrough
+ -d: do not compress (decompress)
+ -i: invert colors
+ -u: set distance unit, 'i' for inch, 'm' for centimeter
+ -x: set x resolution default
+ -y: set y resolution default
+ -w: width in units
+ -l: length in units
+ -r: 'd' for resolution default, 'o' for resolution override
+ -p: paper size, eg "letter", "legal", "a4"
+ -f: set pdf "fit window" user preference
+ -b: set PDF "Interpolate" user preference
+ -e: date, overrides image or current date/time default, YYYYMMDDHHMMSS
+ -c: creator, overrides image software default
+ -a: author, overrides image artist default
+ -t: title, overrides image document name default
+ -s: subject, overrides image image description default
+ -k: keywords
+
+ -h: usage
+
+ examples:
+
+ tiff2pdf -o output.pdf input.tiff
+
+ The above example would generate the file output.pdf from input.tiff.
+
+ tiff2pdf input.tiff
+
+ The above example would generate PDF output from input.tiff and write it
+ to standard output.
+
+ tiff2pdf -j -p letter -o output.pdf input.tiff
+
+ The above example would generate the file output.pdf from input.tiff,
+ putting the image pages on a letter sized page, compressing the output
+ with JPEG.
+
+ Please report bugs through:
+
+ http://bugzilla.remotesensing.org/buglist.cgi?product=libtiff
+
+ See also libtiff.3t, tiffcp.
+ */
+
+int main(int argc, char** argv){
+
+ extern char *optarg;
+ extern int optind;
+ const char *outfilename = NULL;
+ T2P *t2p = NULL;
+ TIFF *input = NULL, *output = NULL;
+ tsize_t written = 0;
+ int c;
+
+ t2p = t2p_init();
+
+ if (t2p == NULL){
+ TIFFError(TIFF2PDF_MODULE, "Can't initialize context");
+ goto fail;
+ }
+
+ while (argv &&
+ (c = getopt(argc, argv,
+ "o:q:u:x:y:w:l:r:p:e:c:a:t:s:k:jzndifbh")) != -1){
+ switch (c) {
+ case 'o':
+ outfilename = optarg;
+ break;
+#ifdef JPEG_SUPPORT
+ case 'j':
+ t2p->pdf_defaultcompression=T2P_COMPRESS_JPEG;
+ break;
+#endif
+#ifndef JPEG_SUPPORT
+ case 'j':
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "JPEG support in libtiff required for JPEG compression, ignoring option");
+ break;
+#endif
+#ifdef ZIP_SUPPORT
+ case 'z':
+ t2p->pdf_defaultcompression=T2P_COMPRESS_ZIP;
+ break;
+#endif
+#ifndef ZIP_SUPPORT
+ case 'z':
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "Zip support in libtiff required for Zip compression, ignoring option");
+ break;
+#endif
+ case 'q':
+ t2p->pdf_defaultcompressionquality=atoi(optarg);
+ break;
+ case 'n':
+ t2p->pdf_nopassthrough=1;
+ break;
+ case 'd':
+ t2p->pdf_defaultcompression=T2P_COMPRESS_NONE;
+ break;
+ case 'u':
+ if(optarg[0]=='m'){
+ t2p->pdf_centimeters=1;
+ }
+ break;
+ case 'x':
+ t2p->pdf_defaultxres =
+ (float)atof(optarg) / (t2p->pdf_centimeters?2.54F:1.0F);
+ break;
+ case 'y':
+ t2p->pdf_defaultyres =
+ (float)atof(optarg) / (t2p->pdf_centimeters?2.54F:1.0F);
+ break;
+ case 'w':
+ t2p->pdf_overridepagesize=1;
+ t2p->pdf_defaultpagewidth =
+ ((float)atof(optarg) * PS_UNIT_SIZE) / (t2p->pdf_centimeters?2.54F:1.0F);
+ break;
+ case 'l':
+ t2p->pdf_overridepagesize=1;
+ t2p->pdf_defaultpagelength =
+ ((float)atof(optarg) * PS_UNIT_SIZE) / (t2p->pdf_centimeters?2.54F:1.0F);
+ break;
+ case 'r':
+ if(optarg[0]=='o'){
+ t2p->pdf_overrideres=1;
+ }
+ break;
+ case 'p':
+ if(tiff2pdf_match_paper_size(
+ &(t2p->pdf_defaultpagewidth),
+ &(t2p->pdf_defaultpagelength),
+ optarg)){
+ t2p->pdf_overridepagesize=1;
+ } else {
+ TIFFWarning(TIFF2PDF_MODULE,
+ "Unknown paper size %s, ignoring option",
+ optarg);
+ }
+ break;
+ case 'i':
+ t2p->pdf_colorspace_invert=1;
+ break;
+ case 'f':
+ t2p->pdf_fitwindow=1;
+ break;
+ case 'e':
+ t2p->pdf_datetime =
+ (unsigned char*)_TIFFmalloc(17);
+ if(t2p->pdf_datetime==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ 17);
+ goto fail;
+ }
+ if(strlen(optarg)==0){
+ t2p->pdf_datetime[0] = 0;
+ } else {
+ if(strlen(optarg)>14){optarg[14]=0;}
+ t2p->pdf_datetime[0] = 'D';
+ t2p->pdf_datetime[1] = ':';
+ strcpy((char *)t2p->pdf_datetime + 2,
+ optarg);
+ }
+ break;
+ case 'c':
+ t2p->pdf_creator = (unsigned char *)
+ _TIFFmalloc(strlen(optarg) + 1);
+ if(t2p->pdf_creator==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg) + 1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_creator, optarg);
+ t2p->pdf_creator[strlen(optarg)] = 0;
+ break;
+ case 'a':
+ t2p->pdf_author = (unsigned char *)
+ _TIFFmalloc(strlen(optarg) + 1);
+ if(t2p->pdf_author==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg) + 1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_author, optarg);
+ t2p->pdf_author[strlen(optarg)]=0;
+ break;
+ case 't':
+ t2p->pdf_title = (unsigned char*)
+ _TIFFmalloc(strlen(optarg)+1);
+ if(t2p->pdf_title==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg) + 1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_title, optarg);
+ t2p->pdf_title[strlen(optarg)] = 0;
+ break;
+ case 's':
+ t2p->pdf_subject = (unsigned char*)
+ _TIFFmalloc(strlen(optarg) + 1);
+ if(t2p->pdf_subject==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg)+1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_subject, optarg);
+ t2p->pdf_subject[strlen(optarg)]=0;
+ break;
+ case 'k':
+ t2p->pdf_keywords = (unsigned char*)
+ _TIFFmalloc(strlen(optarg) + 1);
+ if(t2p->pdf_keywords==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for main",
+ strlen(optarg) + 1);
+ goto fail;
+ }
+ strcpy((char *)t2p->pdf_keywords, optarg);
+ t2p->pdf_keywords[strlen(optarg)] = 0;
+ break;
+ case 'b':
+ t2p->pdf_image_interpolate = 1;
+ break;
+ case 'h':
+ case '?':
+ tiff2pdf_usage();
+ goto success;
+ break;
+ }
+ }
+
+ /*
+ * Input
+ */
+ if(argc > optind) {
+ input = TIFFOpen(argv[optind++], "r");
+ if (input==NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't open input file %s for reading",
+ argv[optind-1]);
+ goto fail;
+ }
+ } else {
+ TIFFError(TIFF2PDF_MODULE, "No input file specified");
+ tiff2pdf_usage();
+ goto fail;
+ }
+
+ if(argc > optind) {
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for multiple input files");
+ tiff2pdf_usage();
+ goto fail;
+ }
+
+ /*
+ * Output
+ */
+ t2p->outputdisable = 0;
+ if (outfilename) {
+ t2p->outputfile = fopen(outfilename, "wb");
+ if (t2p->outputfile == NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't open output file %s for writing",
+ outfilename);
+ goto fail;
+ }
+ } else {
+ outfilename = "-";
+ t2p->outputfile = stdout;
+ }
+
+ output = TIFFClientOpen(outfilename, "w", (thandle_t) t2p,
+ t2p_readproc, t2p_writeproc, t2p_seekproc,
+ t2p_closeproc, t2p_sizeproc,
+ t2p_mapproc, t2p_unmapproc );
+ if (output == NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't initialize output descriptor");
+ goto fail;
+ }
+
+ /*
+ * Validate
+ */
+ t2p_validate(t2p);
+ t2pSeekFile(output, (toff_t) 0, SEEK_SET);
+
+ /*
+ * Write
+ */
+ written = t2p_write_pdf(t2p, input, output);
+ if (t2p->t2p_error != 0) {
+ TIFFError(TIFF2PDF_MODULE,
+ "An error occurred creating output PDF file");
+ goto fail;
+ }
+
+success:
+ if (output != NULL)
+ TIFFClose(output);
+ if (t2p != NULL)
+ t2p_free(t2p);
+ return(EXIT_SUCCESS);
+
+fail:
+ if(input != NULL)
+ TIFFClose(input);
+ if (output != NULL)
+ TIFFClose(output);
+ if (t2p != NULL)
+ t2p_free(t2p);
+ return(EXIT_FAILURE);
+
+}
+
+void tiff2pdf_usage(){
+ char* lines[]={
+ "usage: tiff2pdf [options] input.tiff",
+ "options:",
+ " -o: output to file name",
+#ifdef JPEG_SUPPORT
+ " -j: compress with JPEG",
+#endif
+#ifdef ZIP_SUPPORT
+ " -z: compress with Zip/Deflate",
+#endif
+ " -q: compression quality",
+ " -n: no compressed data passthrough",
+ " -d: do not compress (decompress)",
+ " -i: invert colors",
+ " -u: set distance unit, 'i' for inch, 'm' for centimeter",
+ " -x: set x resolution default in dots per unit",
+ " -y: set y resolution default in dots per unit",
+ " -w: width in units",
+ " -l: length in units",
+ " -r: 'd' for resolution default, 'o' for resolution override",
+ " -p: paper size, eg \"letter\", \"legal\", \"A4\"",
+ " -f: set PDF \"Fit Window\" user preference",
+ " -e: date, overrides image or current date/time default, YYYYMMDDHHMMSS",
+ " -c: sets document creator, overrides image software default",
+ " -a: sets document author, overrides image artist default",
+ " -t: sets document title, overrides image document name default",
+ " -s: sets document subject, overrides image image description default",
+ " -k: sets document keywords",
+ " -b: set PDF \"Interpolate\" user preference",
+ " -h: usage",
+ NULL
+ };
+ int i=0;
+
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i=0;lines[i]!=NULL;i++){
+ fprintf(stderr, "%s\n", lines[i]);
+ }
+
+ return;
+}
+
+int tiff2pdf_match_paper_size(float* width, float* length, char* papersize){
+
+ size_t i, len;
+ const char* sizes[]={
+ "LETTER", "A4", "LEGAL",
+ "EXECUTIVE", "LETTER", "LEGAL", "LEDGER", "TABLOID",
+ "A", "B", "C", "D", "E", "F", "G", "H", "J", "K",
+ "A10", "A9", "A8", "A7", "A6", "A5", "A4", "A3", "A2", "A1", "A0",
+ "2A0", "4A0", "2A", "4A",
+ "B10", "B9", "B8", "B7", "B6", "B5", "B4", "B3", "B2", "B1", "B0",
+ "JISB10", "JISB9", "JISB8", "JISB7", "JISB6", "JISB5", "JISB4",
+ "JISB3", "JISB2", "JISB1", "JISB0",
+ "C10", "C9", "C8", "C7", "C6", "C5", "C4", "C3", "C2", "C1", "C0",
+ "RA2", "RA1", "RA0", "SRA4", "SRA3", "SRA2", "SRA1", "SRA0",
+ "A3EXTRA", "A4EXTRA",
+ "STATEMENT", "FOLIO", "QUARTO",
+ NULL
+ } ;
+ const int widths[]={
+ 612, 595, 612,
+ 522, 612,612,792,792,
+ 612,792,1224,1584,2448,2016,792,2016,2448,2880,
+ 74,105,147,210,298,420,595,842,1191,1684,2384,3370,4768,3370,4768,
+ 88,125,176,249,354,499,709,1001,1417,2004,2835,
+ 91,128,181,258,363,516,729,1032,1460,2064,2920,
+ 79,113,162,230,323,459,649,918,1298,1298,2599,
+ 1219,1729,2438,638,907,1276,1814,2551,
+ 914,667,
+ 396, 612, 609,
+ 0
+ };
+ const int lengths[]={
+ 792,842,1008,
+ 756,792,1008,1224,1224,
+ 792,1224,1584,2448,3168,2880,6480,10296,12672,10296,
+ 105,147,210,298,420,595,842,1191,1684,2384,3370,4768,6741,4768,6741,
+ 125,176,249,354,499,709,1001,1417,2004,2835,4008,
+ 128,181,258,363,516,729,1032,1460,2064,2920,4127,
+ 113,162,230,323,459,649,918,1298,1837,1837,3677,
+ 1729,2438,3458,907,1276,1814,2551,3628,
+ 1262,914,
+ 612, 936, 780,
+ 0
+ };
+
+ len=strlen(papersize);
+ for(i=0;i<len;i++){
+ papersize[i]=toupper(papersize[i]);
+ }
+ for(i=0;sizes[i]!=NULL; i++){
+ if (strcmp( (const char*)papersize, sizes[i])==0){
+ *width=(float)widths[i];
+ *length=(float)lengths[i];
+ return(1);
+ }
+ }
+
+ return(0);
+}
+
+/*
+ This function allocates and initializes a T2P context struct pointer.
+*/
+
+T2P* t2p_init(){
+
+ T2P* t2p = (T2P*) _TIFFmalloc(sizeof(T2P));
+ if(t2p==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_init",
+ sizeof(T2P));
+ return( (T2P*) NULL );
+ }
+ _TIFFmemset(t2p, 0x00, sizeof(T2P));
+ t2p->pdf_majorversion=1;
+ t2p->pdf_minorversion=1;
+ t2p->pdf_defaultxres=300.0;
+ t2p->pdf_defaultyres=300.0;
+ t2p->pdf_defaultpagewidth=612.0;
+ t2p->pdf_defaultpagelength=792.0;
+ t2p->pdf_xrefcount=3; /* Catalog, Info, Pages */
+
+ return(t2p);
+}
+
+/*
+ This function frees a T2P context struct pointer and any allocated data fields of it.
+*/
+
+void t2p_free(T2P* t2p){
+
+ int i=0;
+
+ if(t2p != NULL){
+ if(t2p->pdf_xrefoffsets != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_xrefoffsets);
+ }
+ if(t2p->tiff_pages != NULL){
+ _TIFFfree( (tdata_t) t2p->tiff_pages);
+ }
+ for(i=0;i<t2p->tiff_pagecount;i++){
+ if(t2p->tiff_tiles[i].tiles_tiles != NULL){
+ _TIFFfree( (tdata_t) t2p->tiff_tiles[i].tiles_tiles);
+ }
+ }
+ if(t2p->tiff_tiles != NULL){
+ _TIFFfree( (tdata_t) t2p->tiff_tiles);
+ }
+ if(t2p->pdf_palette != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_palette);
+ }
+ if(t2p->pdf_fileid != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_fileid);
+ }
+ if(t2p->pdf_datetime != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_datetime);
+ }
+ if(t2p->pdf_creator != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_creator);
+ }
+ if(t2p->pdf_author != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_author);
+ }
+ if(t2p->pdf_title != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_title);
+ }
+ if(t2p->pdf_subject != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_subject);
+ }
+ if(t2p->pdf_keywords != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_keywords);
+ }
+#ifdef OJPEG_SUPPORT
+ if(t2p->pdf_ojpegdata != NULL){
+ _TIFFfree( (tdata_t) t2p->pdf_ojpegdata);
+ }
+#endif
+ _TIFFfree( (tdata_t) t2p );
+ }
+
+ return;
+}
+
+/*
+ This function validates the values of a T2P context struct pointer
+ before calling t2p_write_pdf with it.
+*/
+
+void t2p_validate(T2P* t2p){
+
+#ifdef JPEG_SUPPORT
+ if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
+ if(t2p->pdf_defaultcompressionquality>100 ||
+ t2p->pdf_defaultcompressionquality<1){
+ t2p->pdf_defaultcompressionquality=0;
+ }
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if(t2p->pdf_defaultcompression==T2P_COMPRESS_ZIP){
+ uint16 m=t2p->pdf_defaultcompressionquality%100;
+ if(t2p->pdf_defaultcompressionquality/100 > 9 ||
+ (m>1 && m<10) || m>15){
+ t2p->pdf_defaultcompressionquality=0;
+ }
+ if(t2p->pdf_defaultcompressionquality%100 !=0){
+ t2p->pdf_defaultcompressionquality/=100;
+ t2p->pdf_defaultcompressionquality*=100;
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "PNG Group predictor differencing not implemented, assuming compression quality %u",
+ t2p->pdf_defaultcompressionquality);
+ }
+ t2p->pdf_defaultcompressionquality%=100;
+ if(t2p->pdf_minorversion<2){t2p->pdf_minorversion=2;}
+ }
+#endif
+ (void)0;
+
+ return;
+}
+
+
+/*
+ This function scans the input TIFF file for pages. It attempts
+ to determine which IFD's of the TIFF file contain image document
+ pages. For each, it gathers some information that has to do
+ with the output of the PDF document as a whole.
+*/
+
+void t2p_read_tiff_init(T2P* t2p, TIFF* input){
+
+ tdir_t directorycount=0;
+ tdir_t i=0;
+ uint16 pagen=0;
+ uint16 paged=0;
+ uint16 xuint16=0;
+
+ directorycount=TIFFNumberOfDirectories(input);
+ t2p->tiff_pages = (T2P_PAGE*) _TIFFmalloc(directorycount * sizeof(T2P_PAGE));
+ if(t2p->tiff_pages==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for tiff_pages array, %s",
+ directorycount * sizeof(T2P_PAGE),
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ _TIFFmemset( t2p->tiff_pages, 0x00, directorycount * sizeof(T2P_PAGE));
+ t2p->tiff_tiles = (T2P_TILES*) _TIFFmalloc(directorycount * sizeof(T2P_TILES));
+ if(t2p->tiff_tiles==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for tiff_tiles array, %s",
+ directorycount * sizeof(T2P_TILES),
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ _TIFFmemset( t2p->tiff_tiles, 0x00, directorycount * sizeof(T2P_TILES));
+ for(i=0;i<directorycount;i++){
+ uint32 subfiletype = 0;
+
+ if(!TIFFSetDirectory(input, i)){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't set directory %u of input file %s",
+ i,
+ TIFFFileName(input));
+ return;
+ }
+ if(TIFFGetField(input, TIFFTAG_PAGENUMBER, &pagen, &paged)){
+ if((pagen>paged) && (paged != 0)){
+ t2p->tiff_pages[t2p->tiff_pagecount].page_number =
+ paged;
+ } else {
+ t2p->tiff_pages[t2p->tiff_pagecount].page_number =
+ pagen;
+ }
+ goto ispage2;
+ }
+ if(TIFFGetField(input, TIFFTAG_SUBFILETYPE, &subfiletype)){
+ if ( ((subfiletype & FILETYPE_PAGE) != 0)
+ || (subfiletype == 0)){
+ goto ispage;
+ } else {
+ goto isnotpage;
+ }
+ }
+ if(TIFFGetField(input, TIFFTAG_OSUBFILETYPE, &subfiletype)){
+ if ((subfiletype == OFILETYPE_IMAGE)
+ || (subfiletype == OFILETYPE_PAGE)
+ || (subfiletype == 0) ){
+ goto ispage;
+ } else {
+ goto isnotpage;
+ }
+ }
+ ispage:
+ t2p->tiff_pages[t2p->tiff_pagecount].page_number=t2p->tiff_pagecount;
+ ispage2:
+ t2p->tiff_pages[t2p->tiff_pagecount].page_directory=i;
+ if(TIFFIsTiled(input)){
+ t2p->tiff_pages[t2p->tiff_pagecount].page_tilecount =
+ TIFFNumberOfTiles(input);
+ }
+ t2p->tiff_pagecount++;
+ isnotpage:
+ (void)0;
+ }
+
+ qsort((void*) t2p->tiff_pages, t2p->tiff_pagecount,
+ sizeof(T2P_PAGE), t2p_cmp_t2p_page);
+
+ for(i=0;i<t2p->tiff_pagecount;i++){
+ t2p->pdf_xrefcount += 5;
+ TIFFSetDirectory(input, t2p->tiff_pages[i].page_directory );
+ if((TIFFGetField(input, TIFFTAG_PHOTOMETRIC, &xuint16)
+ && (xuint16==PHOTOMETRIC_PALETTE))
+ || TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)) {
+ t2p->tiff_pages[i].page_extra++;
+ t2p->pdf_xrefcount++;
+ }
+#ifdef ZIP_SUPPORT
+ if (TIFFGetField(input, TIFFTAG_COMPRESSION, &xuint16)) {
+ if( (xuint16== COMPRESSION_DEFLATE ||
+ xuint16== COMPRESSION_ADOBE_DEFLATE) &&
+ ((t2p->tiff_pages[i].page_tilecount != 0)
+ || TIFFNumberOfStrips(input)==1) &&
+ (t2p->pdf_nopassthrough==0) ){
+ if(t2p->pdf_minorversion<2){t2p->pdf_minorversion=2;}
+ }
+ }
+#endif
+ if (TIFFGetField(input, TIFFTAG_TRANSFERFUNCTION,
+ &(t2p->tiff_transferfunction[0]),
+ &(t2p->tiff_transferfunction[1]),
+ &(t2p->tiff_transferfunction[2]))) {
+ if(t2p->tiff_transferfunction[1] !=
+ t2p->tiff_transferfunction[0]) {
+ t2p->tiff_transferfunctioncount = 3;
+ t2p->tiff_pages[i].page_extra += 4;
+ t2p->pdf_xrefcount += 4;
+ } else {
+ t2p->tiff_transferfunctioncount = 1;
+ t2p->tiff_pages[i].page_extra += 2;
+ t2p->pdf_xrefcount += 2;
+ }
+ if(t2p->pdf_minorversion < 2)
+ t2p->pdf_minorversion = 2;
+ } else {
+ t2p->tiff_transferfunctioncount=0;
+ }
+ if( TIFFGetField(
+ input,
+ TIFFTAG_ICCPROFILE,
+ &(t2p->tiff_iccprofilelength),
+ &(t2p->tiff_iccprofile)) != 0){
+ t2p->tiff_pages[i].page_extra++;
+ t2p->pdf_xrefcount++;
+ if(t2p->pdf_minorversion<3){t2p->pdf_minorversion=3;}
+ }
+ t2p->tiff_tiles[i].tiles_tilecount=
+ t2p->tiff_pages[i].page_tilecount;
+ if( (TIFFGetField(input, TIFFTAG_PLANARCONFIG, &xuint16) != 0)
+ && (xuint16 == PLANARCONFIG_SEPARATE ) ){
+ TIFFGetField(input, TIFFTAG_SAMPLESPERPIXEL, &xuint16);
+ t2p->tiff_tiles[i].tiles_tilecount/= xuint16;
+ }
+ if( t2p->tiff_tiles[i].tiles_tilecount > 0){
+ t2p->pdf_xrefcount +=
+ (t2p->tiff_tiles[i].tiles_tilecount -1)*2;
+ TIFFGetField(input,
+ TIFFTAG_TILEWIDTH,
+ &( t2p->tiff_tiles[i].tiles_tilewidth) );
+ TIFFGetField(input,
+ TIFFTAG_TILELENGTH,
+ &( t2p->tiff_tiles[i].tiles_tilelength) );
+ t2p->tiff_tiles[i].tiles_tiles =
+ (T2P_TILE*) _TIFFmalloc(
+ t2p->tiff_tiles[i].tiles_tilecount
+ * sizeof(T2P_TILE) );
+ if( t2p->tiff_tiles[i].tiles_tiles == NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_read_tiff_init, %s",
+ t2p->tiff_tiles[i].tiles_tilecount * sizeof(T2P_TILE),
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ }
+ }
+
+ return;
+}
+
+/*
+ * This function is used by qsort to sort a T2P_PAGE* array of page structures
+ * by page number.
+ */
+
+int t2p_cmp_t2p_page(const void* e1, const void* e2){
+
+ return( ((T2P_PAGE*)e1)->page_number - ((T2P_PAGE*)e2)->page_number );
+}
+
+/*
+ This function sets the input directory to the directory of a given
+ page and determines information about the image. It checks
+ the image characteristics to determine if it is possible to convert
+ the image data into a page of PDF output, setting values of the T2P
+ struct for this page. It determines what color space is used in
+ the output PDF to represent the image.
+
+ It determines if the image can be converted as raw data without
+ requiring transcoding of the image data.
+*/
+
+void t2p_read_tiff_data(T2P* t2p, TIFF* input){
+
+ int i=0;
+ uint16* r;
+ uint16* g;
+ uint16* b;
+ uint16* a;
+ uint16 xuint16;
+ uint16* xuint16p;
+ float* xfloatp;
+
+ t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
+ t2p->pdf_sample = T2P_SAMPLE_NOTHING;
+ t2p->pdf_switchdecode = t2p->pdf_colorspace_invert;
+
+
+ TIFFSetDirectory(input, t2p->tiff_pages[t2p->pdf_page].page_directory);
+
+ TIFFGetField(input, TIFFTAG_IMAGEWIDTH, &(t2p->tiff_width));
+ if(t2p->tiff_width == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with zero width",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+
+ TIFFGetField(input, TIFFTAG_IMAGELENGTH, &(t2p->tiff_length));
+ if(t2p->tiff_length == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with zero length",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+
+ if(TIFFGetField(input, TIFFTAG_COMPRESSION, &(t2p->tiff_compression)) == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with no compression tag",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+
+ }
+ if( TIFFIsCODECConfigured(t2p->tiff_compression) == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with compression type %u: not configured",
+ TIFFFileName(input),
+ t2p->tiff_compression
+ );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+
+ }
+
+ TIFFGetFieldDefaulted(input, TIFFTAG_BITSPERSAMPLE, &(t2p->tiff_bitspersample));
+ switch(t2p->tiff_bitspersample){
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ case 0:
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "Image %s has 0 bits per sample, assuming 1",
+ TIFFFileName(input));
+ t2p->tiff_bitspersample=1;
+ break;
+ default:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with %u bits per sample",
+ TIFFFileName(input),
+ t2p->tiff_bitspersample);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+
+ TIFFGetFieldDefaulted(input, TIFFTAG_SAMPLESPERPIXEL, &(t2p->tiff_samplesperpixel));
+ if(t2p->tiff_samplesperpixel>4){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with %u samples per pixel",
+ TIFFFileName(input),
+ t2p->tiff_samplesperpixel);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ if(t2p->tiff_samplesperpixel==0){
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "Image %s has 0 samples per pixel, assuming 1",
+ TIFFFileName(input));
+ t2p->tiff_samplesperpixel=1;
+ }
+
+ if(TIFFGetField(input, TIFFTAG_SAMPLEFORMAT, &xuint16) != 0 ){
+ switch(xuint16){
+ case 0:
+ case 1:
+ case 4:
+ break;
+ default:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with sample format %u",
+ TIFFFileName(input),
+ xuint16);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ break;
+ }
+ }
+
+ TIFFGetFieldDefaulted(input, TIFFTAG_FILLORDER, &(t2p->tiff_fillorder));
+
+ if(TIFFGetField(input, TIFFTAG_PHOTOMETRIC, &(t2p->tiff_photometric)) == 0){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with no photometric interpretation tag",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+
+ }
+
+ switch(t2p->tiff_photometric){
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ if (t2p->tiff_bitspersample==1){
+ t2p->pdf_colorspace=T2P_CS_BILEVEL;
+ if(t2p->tiff_photometric==PHOTOMETRIC_MINISWHITE){
+ t2p->pdf_switchdecode ^= 1;
+ }
+ } else {
+ t2p->pdf_colorspace=T2P_CS_GRAY;
+ if(t2p->tiff_photometric==PHOTOMETRIC_MINISWHITE){
+ t2p->pdf_switchdecode ^= 1;
+ }
+ }
+ break;
+ case PHOTOMETRIC_RGB:
+ t2p->pdf_colorspace=T2P_CS_RGB;
+ if(t2p->tiff_samplesperpixel == 3){
+ break;
+ }
+ if(TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)){
+ if(xuint16==1)
+ goto photometric_palette;
+ }
+ if(t2p->tiff_samplesperpixel > 3) {
+ if(t2p->tiff_samplesperpixel == 4) {
+ t2p->pdf_colorspace = T2P_CS_RGB;
+ if(TIFFGetField(input,
+ TIFFTAG_EXTRASAMPLES,
+ &xuint16, &xuint16p)
+ && xuint16 == 1) {
+ if(xuint16p[0] == EXTRASAMPLE_ASSOCALPHA){
+ t2p->pdf_sample=T2P_SAMPLE_RGBAA_TO_RGB;
+ break;
+ }
+ if(xuint16p[0] == EXTRASAMPLE_UNASSALPHA){
+ t2p->pdf_sample=T2P_SAMPLE_RGBA_TO_RGB;
+ break;
+ }
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "RGB image %s has 4 samples per pixel, assuming RGBA",
+ TIFFFileName(input));
+ break;
+ }
+ t2p->pdf_colorspace=T2P_CS_CMYK;
+ t2p->pdf_switchdecode ^= 1;
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "RGB image %s has 4 samples per pixel, assuming inverse CMYK",
+ TIFFFileName(input));
+ break;
+ } else {
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for RGB image %s with %u samples per pixel",
+ TIFFFileName(input),
+ t2p->tiff_samplesperpixel);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ break;
+ }
+ } else {
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for RGB image %s with %u samples per pixel",
+ TIFFFileName(input),
+ t2p->tiff_samplesperpixel);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ break;
+ }
+ case PHOTOMETRIC_PALETTE:
+ photometric_palette:
+ if(t2p->tiff_samplesperpixel!=1){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for palettized image %s with not one sample per pixel",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ t2p->pdf_colorspace=T2P_CS_RGB | T2P_CS_PALETTE;
+ t2p->pdf_palettesize=0x0001<<t2p->tiff_bitspersample;
+ if(!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b)){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Palettized image %s has no color map",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ if(t2p->pdf_palette != NULL){
+ _TIFFfree(t2p->pdf_palette);
+ t2p->pdf_palette=NULL;
+ }
+ t2p->pdf_palette = (unsigned char*)
+ _TIFFmalloc(t2p->pdf_palettesize*3);
+ if(t2p->pdf_palette==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_read_tiff_image, %s",
+ t2p->pdf_palettesize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ for(i=0;i<t2p->pdf_palettesize;i++){
+ t2p->pdf_palette[(i*3)] = (unsigned char) (r[i]>>8);
+ t2p->pdf_palette[(i*3)+1]= (unsigned char) (g[i]>>8);
+ t2p->pdf_palette[(i*3)+2]= (unsigned char) (b[i]>>8);
+ }
+ t2p->pdf_palettesize *= 3;
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ if(TIFFGetField(input, TIFFTAG_INDEXED, &xuint16)){
+ if(xuint16==1){
+ goto photometric_palette_cmyk;
+ }
+ }
+ if( TIFFGetField(input, TIFFTAG_INKSET, &xuint16) ){
+ if(xuint16 != INKSET_CMYK){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s because its inkset is not CMYK",
+ TIFFFileName(input) );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ }
+ if(t2p->tiff_samplesperpixel==4){
+ t2p->pdf_colorspace=T2P_CS_CMYK;
+ } else {
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s because it has %u samples per pixel",
+ TIFFFileName(input),
+ t2p->tiff_samplesperpixel);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ break;
+ photometric_palette_cmyk:
+ if(t2p->tiff_samplesperpixel!=1){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for palettized CMYK image %s with not one sample per pixel",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ t2p->pdf_colorspace=T2P_CS_CMYK | T2P_CS_PALETTE;
+ t2p->pdf_palettesize=0x0001<<t2p->tiff_bitspersample;
+ if(!TIFFGetField(input, TIFFTAG_COLORMAP, &r, &g, &b, &a)){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Palettized image %s has no color map",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ if(t2p->pdf_palette != NULL){
+ _TIFFfree(t2p->pdf_palette);
+ t2p->pdf_palette=NULL;
+ }
+ t2p->pdf_palette = (unsigned char*)
+ _TIFFmalloc(t2p->pdf_palettesize*4);
+ if(t2p->pdf_palette==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_read_tiff_image, %s",
+ t2p->pdf_palettesize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ for(i=0;i<t2p->pdf_palettesize;i++){
+ t2p->pdf_palette[(i*4)] = (unsigned char) (r[i]>>8);
+ t2p->pdf_palette[(i*4)+1]= (unsigned char) (g[i]>>8);
+ t2p->pdf_palette[(i*4)+2]= (unsigned char) (b[i]>>8);
+ t2p->pdf_palette[(i*4)+3]= (unsigned char) (a[i]>>8);
+ }
+ t2p->pdf_palettesize *= 4;
+ break;
+ case PHOTOMETRIC_YCBCR:
+ t2p->pdf_colorspace=T2P_CS_RGB;
+ if(t2p->tiff_samplesperpixel==1){
+ t2p->pdf_colorspace=T2P_CS_GRAY;
+ t2p->tiff_photometric=PHOTOMETRIC_MINISBLACK;
+ break;
+ }
+ t2p->pdf_sample=T2P_SAMPLE_YCBCR_TO_RGB;
+#ifdef JPEG_SUPPORT
+ if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
+ t2p->pdf_sample=T2P_SAMPLE_NOTHING;
+ }
+#endif
+ break;
+ case PHOTOMETRIC_CIELAB:
+ t2p->pdf_labrange[0]= -127;
+ t2p->pdf_labrange[1]= 127;
+ t2p->pdf_labrange[2]= -127;
+ t2p->pdf_labrange[3]= 127;
+ t2p->pdf_sample=T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
+ t2p->pdf_colorspace=T2P_CS_LAB;
+ break;
+ case PHOTOMETRIC_ICCLAB:
+ t2p->pdf_labrange[0]= 0;
+ t2p->pdf_labrange[1]= 255;
+ t2p->pdf_labrange[2]= 0;
+ t2p->pdf_labrange[3]= 255;
+ t2p->pdf_colorspace=T2P_CS_LAB;
+ break;
+ case PHOTOMETRIC_ITULAB:
+ t2p->pdf_labrange[0]=-85;
+ t2p->pdf_labrange[1]=85;
+ t2p->pdf_labrange[2]=-75;
+ t2p->pdf_labrange[3]=124;
+ t2p->pdf_sample=T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED;
+ t2p->pdf_colorspace=T2P_CS_LAB;
+ break;
+ case PHOTOMETRIC_LOGL:
+ case PHOTOMETRIC_LOGLUV:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with photometric interpretation LogL/LogLuv",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ default:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with photometric interpretation %u",
+ TIFFFileName(input),
+ t2p->tiff_photometric);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+
+ if(TIFFGetField(input, TIFFTAG_PLANARCONFIG, &(t2p->tiff_planar))){
+ switch(t2p->tiff_planar){
+ case 0:
+ TIFFWarning(
+ TIFF2PDF_MODULE,
+ "Image %s has planar configuration 0, assuming 1",
+ TIFFFileName(input));
+ t2p->tiff_planar=PLANARCONFIG_CONTIG;
+ case PLANARCONFIG_CONTIG:
+ break;
+ case PLANARCONFIG_SEPARATE:
+ t2p->pdf_sample=T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG;
+ if(t2p->tiff_bitspersample!=8){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with separated planar configuration and %u bits per sample",
+ TIFFFileName(input),
+ t2p->tiff_bitspersample);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ break;
+ default:
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with planar configuration %u",
+ TIFFFileName(input),
+ t2p->tiff_planar);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ }
+
+ TIFFGetFieldDefaulted(input, TIFFTAG_ORIENTATION,
+ &(t2p->tiff_orientation));
+ if(t2p->tiff_orientation>8){
+ TIFFWarning(TIFF2PDF_MODULE,
+ "Image %s has orientation %u, assuming 0",
+ TIFFFileName(input), t2p->tiff_orientation);
+ t2p->tiff_orientation=0;
+ }
+
+ if(TIFFGetField(input, TIFFTAG_XRESOLUTION, &(t2p->tiff_xres) ) == 0){
+ t2p->tiff_xres=0.0;
+ }
+ if(TIFFGetField(input, TIFFTAG_YRESOLUTION, &(t2p->tiff_yres) ) == 0){
+ t2p->tiff_yres=0.0;
+ }
+ TIFFGetFieldDefaulted(input, TIFFTAG_RESOLUTIONUNIT,
+ &(t2p->tiff_resunit));
+ if(t2p->tiff_resunit == RESUNIT_CENTIMETER) {
+ t2p->tiff_xres *= 2.54F;
+ t2p->tiff_yres *= 2.54F;
+ } else if (t2p->tiff_resunit != RESUNIT_INCH
+ && t2p->pdf_centimeters != 0) {
+ t2p->tiff_xres *= 2.54F;
+ t2p->tiff_yres *= 2.54F;
+ }
+
+ t2p_compose_pdf_page(t2p);
+
+ t2p->pdf_transcode = T2P_TRANSCODE_ENCODE;
+ if(t2p->pdf_nopassthrough==0){
+#ifdef CCITT_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_CCITTFAX4
+ ){
+ if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
+ t2p->pdf_transcode = T2P_TRANSCODE_RAW;
+ t2p->pdf_compression=T2P_COMPRESS_G4;
+ }
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if(t2p->tiff_compression== COMPRESSION_ADOBE_DEFLATE
+ || t2p->tiff_compression==COMPRESSION_DEFLATE){
+ if(TIFFIsTiled(input) || (TIFFNumberOfStrips(input)==1) ){
+ t2p->pdf_transcode = T2P_TRANSCODE_RAW;
+ t2p->pdf_compression=T2P_COMPRESS_ZIP;
+ }
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_OJPEG){
+ t2p->pdf_transcode = T2P_TRANSCODE_RAW;
+ t2p->pdf_compression=T2P_COMPRESS_JPEG;
+ t2p_process_ojpeg_tables(t2p, input);
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_JPEG){
+ t2p->pdf_transcode = T2P_TRANSCODE_RAW;
+ t2p->pdf_compression=T2P_COMPRESS_JPEG;
+ }
+#endif
+ (void)0;
+ }
+
+ if(t2p->pdf_transcode!=T2P_TRANSCODE_RAW){
+ t2p->pdf_compression = t2p->pdf_defaultcompression;
+ }
+
+#ifdef JPEG_SUPPORT
+ if(t2p->pdf_defaultcompression==T2P_COMPRESS_JPEG){
+ if(t2p->pdf_colorspace & T2P_CS_PALETTE){
+ t2p->pdf_sample|=T2P_SAMPLE_REALIZE_PALETTE;
+ t2p->pdf_colorspace ^= T2P_CS_PALETTE;
+ t2p->tiff_pages[t2p->pdf_page].page_extra--;
+ }
+ }
+ if(t2p->tiff_compression==COMPRESSION_JPEG){
+ if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with JPEG compression and separated planar configuration",
+ TIFFFileName(input));
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return;
+ }
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_OJPEG){
+ if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "No support for %s with OJPEG compression and separated planar configuration",
+ TIFFFileName(input));
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return;
+ }
+ }
+#endif
+
+ if(t2p->pdf_sample & T2P_SAMPLE_REALIZE_PALETTE){
+ if(t2p->pdf_colorspace & T2P_CS_CMYK){
+ t2p->tiff_samplesperpixel=4;
+ t2p->tiff_photometric=PHOTOMETRIC_SEPARATED;
+ } else {
+ t2p->tiff_samplesperpixel=3;
+ t2p->tiff_photometric=PHOTOMETRIC_RGB;
+ }
+ }
+
+ if (TIFFGetField(input, TIFFTAG_TRANSFERFUNCTION,
+ &(t2p->tiff_transferfunction[0]),
+ &(t2p->tiff_transferfunction[1]),
+ &(t2p->tiff_transferfunction[2]))) {
+ if(t2p->tiff_transferfunction[1] !=
+ t2p->tiff_transferfunction[0]) {
+ t2p->tiff_transferfunctioncount=3;
+ } else {
+ t2p->tiff_transferfunctioncount=1;
+ }
+ } else {
+ t2p->tiff_transferfunctioncount=0;
+ }
+ if(TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp)!=0){
+ t2p->tiff_whitechromaticities[0]=xfloatp[0];
+ t2p->tiff_whitechromaticities[1]=xfloatp[1];
+ if(t2p->pdf_colorspace & T2P_CS_GRAY){
+ t2p->pdf_colorspace |= T2P_CS_CALGRAY;
+ }
+ if(t2p->pdf_colorspace & T2P_CS_RGB){
+ t2p->pdf_colorspace |= T2P_CS_CALRGB;
+ }
+ }
+ if(TIFFGetField(input, TIFFTAG_PRIMARYCHROMATICITIES, &xfloatp)!=0){
+ t2p->tiff_primarychromaticities[0]=xfloatp[0];
+ t2p->tiff_primarychromaticities[1]=xfloatp[1];
+ t2p->tiff_primarychromaticities[2]=xfloatp[2];
+ t2p->tiff_primarychromaticities[3]=xfloatp[3];
+ t2p->tiff_primarychromaticities[4]=xfloatp[4];
+ t2p->tiff_primarychromaticities[5]=xfloatp[5];
+ if(t2p->pdf_colorspace & T2P_CS_RGB){
+ t2p->pdf_colorspace |= T2P_CS_CALRGB;
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_LAB){
+ if(TIFFGetField(input, TIFFTAG_WHITEPOINT, &xfloatp) != 0){
+ t2p->tiff_whitechromaticities[0]=xfloatp[0];
+ t2p->tiff_whitechromaticities[1]=xfloatp[1];
+ } else {
+ t2p->tiff_whitechromaticities[0]=0.3457F; /* 0.3127F; */
+ t2p->tiff_whitechromaticities[1]=0.3585F; /* 0.3290F; */
+ }
+ }
+ if(TIFFGetField(input,
+ TIFFTAG_ICCPROFILE,
+ &(t2p->tiff_iccprofilelength),
+ &(t2p->tiff_iccprofile))!=0){
+ t2p->pdf_colorspace |= T2P_CS_ICCBASED;
+ } else {
+ t2p->tiff_iccprofilelength=0;
+ t2p->tiff_iccprofile=NULL;
+ }
+
+#ifdef CCITT_SUPPORT
+ if( t2p->tiff_bitspersample==1 &&
+ t2p->tiff_samplesperpixel==1){
+ t2p->pdf_compression = T2P_COMPRESS_G4;
+ }
+#endif
+
+
+ return;
+}
+
+/*
+ This function returns the necessary size of a data buffer to contain the raw or
+ uncompressed image data from the input TIFF for a page.
+*/
+
+void t2p_read_tiff_size(T2P* t2p, TIFF* input){
+
+ uint32* sbc=NULL;
+#if defined(JPEG_SUPPORT) || defined (OJPEG_SUPPORT)
+ unsigned char* jpt=NULL;
+ tstrip_t i=0;
+ tstrip_t stripcount=0;
+#endif
+#ifdef OJPEG_SUPPORT
+ tsize_t k = 0;
+#endif
+
+ if(t2p->pdf_transcode == T2P_TRANSCODE_RAW){
+#ifdef CCITT_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_G4 ){
+ TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc);
+ t2p->tiff_datasize=sbc[0];
+ return;
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_ZIP){
+ TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc);
+ t2p->tiff_datasize=sbc[0];
+ return;
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_OJPEG){
+ if(!TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Input file %s missing field: TIFFTAG_STRIPBYTECOUNTS",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ k += sbc[i];
+ }
+ if(TIFFGetField(input, TIFFTAG_JPEGIFOFFSET, &(t2p->tiff_dataoffset))){
+ if(t2p->tiff_dataoffset != 0){
+ if(TIFFGetField(input, TIFFTAG_JPEGIFBYTECOUNT, &(t2p->tiff_datasize))!=0){
+ if(t2p->tiff_datasize < k) {
+ t2p->pdf_ojpegiflength=t2p->tiff_datasize;
+ t2p->tiff_datasize+=k;
+ t2p->tiff_datasize+=6;
+ t2p->tiff_datasize+=2*stripcount;
+ TIFFWarning(TIFF2PDF_MODULE,
+ "Input file %s has short JPEG interchange file byte count",
+ TIFFFileName(input));
+ return;
+ }
+ return;
+ }else {
+ TIFFError(TIFF2PDF_MODULE,
+ "Input file %s missing field: TIFFTAG_JPEGIFBYTECOUNT",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ }
+ }
+ t2p->tiff_datasize+=k;
+ t2p->tiff_datasize+=2*stripcount;
+ t2p->tiff_datasize+=2048;
+ return;
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_JPEG) {
+ uint32 count = 0;
+ if(TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0 ){
+ if(count > 4){
+ t2p->tiff_datasize += count;
+ t2p->tiff_datasize -= 2; /* don't use EOI of header */
+ }
+ } else {
+ t2p->tiff_datasize = 2; /* SOI for first strip */
+ }
+ stripcount=TIFFNumberOfStrips(input);
+ if(!TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Input file %s missing field: TIFFTAG_STRIPBYTECOUNTS",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ for(i=0;i<stripcount;i++){
+ t2p->tiff_datasize += sbc[i];
+ t2p->tiff_datasize -=4; /* don't use SOI or EOI of strip */
+ }
+ t2p->tiff_datasize +=2; /* use EOI of last strip */
+ return;
+ }
+#endif
+ (void) 0;
+ }
+ t2p->tiff_datasize=TIFFScanlineSize(input) * t2p->tiff_length;
+ if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
+ t2p->tiff_datasize*= t2p->tiff_samplesperpixel;
+ }
+
+ return;
+}
+
+/*
+ This function returns the necessary size of a data buffer to contain the raw or
+ uncompressed image data from the input TIFF for a tile of a page.
+*/
+
+void t2p_read_tiff_size_tile(T2P* t2p, TIFF* input, ttile_t tile){
+
+ uint32* tbc = NULL;
+ uint16 edge=0;
+#ifdef JPEG_SUPPORT
+ unsigned char* jpt;
+#endif
+
+ edge |= t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
+ edge |= t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
+
+ if(t2p->pdf_transcode==T2P_TRANSCODE_RAW){
+ if(edge
+#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
+ && !(t2p->pdf_compression==T2P_COMPRESS_JPEG)
+#endif
+ ){
+ t2p->tiff_datasize=TIFFTileSize(input);
+ return;
+ } else {
+ TIFFGetField(input, TIFFTAG_TILEBYTECOUNTS, &tbc);
+ t2p->tiff_datasize=tbc[tile];
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_OJPEG){
+ t2p->tiff_datasize+=2048;
+ return;
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression==COMPRESSION_JPEG) {
+ uint32 count = 0;
+ if(TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt)!=0){
+ if(count > 4){
+ t2p->tiff_datasize += count;
+ t2p->tiff_datasize -= 4; /* don't use EOI of header or SOI of tile */
+ }
+ }
+ }
+#endif
+ return;
+ }
+ }
+ t2p->tiff_datasize=TIFFTileSize(input);
+ if(t2p->tiff_planar==PLANARCONFIG_SEPARATE){
+ t2p->tiff_datasize*= t2p->tiff_samplesperpixel;
+ }
+
+ return;
+}
+
+/*
+ * This functions returns a non-zero value when the tile is on the right edge
+ * and does not have full imaged tile width.
+ */
+
+int t2p_tile_is_right_edge(T2P_TILES tiles, ttile_t tile){
+
+ if( ((tile+1) % tiles.tiles_tilecountx == 0)
+ && (tiles.tiles_edgetilewidth != 0) ){
+ return(1);
+ } else {
+ return(0);
+ }
+}
+
+/*
+ * This functions returns a non-zero value when the tile is on the bottom edge
+ * and does not have full imaged tile length.
+ */
+
+int t2p_tile_is_bottom_edge(T2P_TILES tiles, ttile_t tile){
+
+ if( ((tile+1) > (tiles.tiles_tilecount-tiles.tiles_tilecountx) )
+ && (tiles.tiles_edgetilelength != 0) ){
+ return(1);
+ } else {
+ return(0);
+ }
+}
+
+/*
+ * This function returns a non-zero value when the tile is a right edge tile
+ * or a bottom edge tile.
+ */
+
+int t2p_tile_is_edge(T2P_TILES tiles, ttile_t tile){
+
+ return(t2p_tile_is_right_edge(tiles, tile) | t2p_tile_is_bottom_edge(tiles, tile) );
+}
+
+/*
+ This function returns a non-zero value when the tile is a right edge tile and a bottom
+ edge tile.
+*/
+
+int t2p_tile_is_corner_edge(T2P_TILES tiles, ttile_t tile){
+
+ return(t2p_tile_is_right_edge(tiles, tile) & t2p_tile_is_bottom_edge(tiles, tile) );
+}
+
+
+/*
+ This function reads the raster image data from the input TIFF for an image and writes
+ the data to the output PDF XObject image dictionary stream. It returns the amount written
+ or zero on error.
+*/
+
+tsize_t t2p_readwrite_pdf_image(T2P* t2p, TIFF* input, TIFF* output){
+
+ tsize_t written=0;
+ unsigned char* buffer=NULL;
+ unsigned char* samplebuffer=NULL;
+ tsize_t bufferoffset=0;
+ tsize_t samplebufferoffset=0;
+ tsize_t read=0;
+ tstrip_t i=0;
+ tstrip_t j=0;
+ tstrip_t stripcount=0;
+ tsize_t stripsize=0;
+ tsize_t sepstripcount=0;
+ tsize_t sepstripsize=0;
+#ifdef OJPEG_SUPPORT
+ toff_t inputoffset=0;
+ uint16 h_samp=1;
+ uint16 v_samp=1;
+ uint16 ri=1;
+ uint32 rows=0;
+#endif
+#ifdef JPEG_SUPPORT
+ unsigned char* jpt;
+ float* xfloatp;
+ uint32* sbc;
+ unsigned char* stripbuffer;
+ tsize_t striplength=0;
+ uint32 max_striplength=0;
+#endif
+
+ if(t2p->pdf_transcode == T2P_TRANSCODE_RAW){
+#ifdef CCITT_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_G4){
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if (buffer == NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ TIFFReadRawStrip(input, 0, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ if (t2p->tiff_fillorder==FILLORDER_LSB2MSB){
+ /*
+ * make sure is lsb-to-msb
+ * bit-endianness fill order
+ */
+ TIFFReverseBits(buffer,
+ t2p->tiff_datasize);
+ }
+ t2pWriteFile(output, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if (t2p->pdf_compression == T2P_COMPRESS_ZIP) {
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer == NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ TIFFReadRawStrip(input, 0, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ if (t2p->tiff_fillorder==FILLORDER_LSB2MSB) {
+ TIFFReverseBits(buffer,
+ t2p->tiff_datasize);
+ }
+ t2pWriteFile(output, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_OJPEG) {
+
+ if(t2p->tiff_dataoffset != 0) {
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer == NULL) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ if(t2p->pdf_ojpegiflength==0){
+ inputoffset=t2pSeekFile(input, 0,
+ SEEK_CUR);
+ t2pSeekFile(input,
+ t2p->tiff_dataoffset,
+ SEEK_SET);
+ t2pReadFile(input, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ t2pSeekFile(input, inputoffset,
+ SEEK_SET);
+ t2pWriteFile(output, (tdata_t) buffer,
+ t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ } else {
+ inputoffset=t2pSeekFile(input, 0,
+ SEEK_CUR);
+ t2pSeekFile(input,
+ t2p->tiff_dataoffset,
+ SEEK_SET);
+ bufferoffset = t2pReadFile(input,
+ (tdata_t) buffer,
+ t2p->pdf_ojpegiflength);
+ t2p->pdf_ojpegiflength = 0;
+ t2pSeekFile(input, inputoffset,
+ SEEK_SET);
+ TIFFGetField(input,
+ TIFFTAG_YCBCRSUBSAMPLING,
+ &h_samp, &v_samp);
+ buffer[bufferoffset++]= 0xff;
+ buffer[bufferoffset++]= 0xdd;
+ buffer[bufferoffset++]= 0x00;
+ buffer[bufferoffset++]= 0x04;
+ h_samp*=8;
+ v_samp*=8;
+ ri=(t2p->tiff_width+h_samp-1) / h_samp;
+ TIFFGetField(input,
+ TIFFTAG_ROWSPERSTRIP,
+ &rows);
+ ri*=(rows+v_samp-1)/v_samp;
+ buffer[bufferoffset++]= (ri>>8) & 0xff;
+ buffer[bufferoffset++]= ri & 0xff;
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ if(i != 0 ){
+ buffer[bufferoffset++]=0xff;
+ buffer[bufferoffset++]=(0xd0 | ((i-1)%8));
+ }
+ bufferoffset+=TIFFReadRawStrip(input,
+ i,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset]),
+ -1);
+ }
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ }
+ } else {
+ if(! t2p->pdf_ojpegdata){
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for OJPEG image %s with bad tables",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ _TIFFmemcpy(buffer, t2p->pdf_ojpegdata, t2p->pdf_ojpegdatalength);
+ bufferoffset=t2p->pdf_ojpegdatalength;
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ if(i != 0){
+ buffer[bufferoffset++]=0xff;
+ buffer[bufferoffset++]=(0xd0 | ((i-1)%8));
+ }
+ bufferoffset+=TIFFReadRawStrip(input,
+ i,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset]),
+ -1);
+ }
+ if( ! ( (buffer[bufferoffset-1]==0xd9) && (buffer[bufferoffset-2]==0xff) ) ){
+ buffer[bufferoffset++]=0xff;
+ buffer[bufferoffset++]=0xd9;
+ }
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for OJPEG image %s with no JPEG File Interchange offset",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_JPEG) {
+ uint32 count = 0;
+ buffer = (unsigned char*)
+ _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ if (TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0) {
+ if(count > 4) {
+ _TIFFmemcpy(buffer, jpt, count);
+ bufferoffset += count - 2;
+ }
+ }
+ stripcount=TIFFNumberOfStrips(input);
+ TIFFGetField(input, TIFFTAG_STRIPBYTECOUNTS, &sbc);
+ for(i=0;i<stripcount;i++){
+ if(sbc[i]>max_striplength) max_striplength=sbc[i];
+ }
+ stripbuffer = (unsigned char*)
+ _TIFFmalloc(max_striplength);
+ if(stripbuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ max_striplength,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ for(i=0;i<stripcount;i++){
+ striplength=TIFFReadRawStrip(input, i, (tdata_t) stripbuffer, -1);
+ if(!t2p_process_jpeg_strip(
+ stripbuffer,
+ &striplength,
+ buffer,
+ &bufferoffset,
+ i,
+ t2p->tiff_length)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't process JPEG data in input file %s",
+ TIFFFileName(input));
+ _TIFFfree(samplebuffer);
+ _TIFFfree(buffer);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ }
+ buffer[bufferoffset++]=0xff;
+ buffer[bufferoffset++]=0xd9;
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(stripbuffer);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ }
+#endif
+ (void)0;
+ }
+
+ if(t2p->pdf_sample==T2P_SAMPLE_NOTHING){
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ stripsize=TIFFStripSize(input);
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ read =
+ TIFFReadEncodedStrip(input,
+ i,
+ (tdata_t) &buffer[bufferoffset],
+ stripsize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding strip %u of %s",
+ i,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ bufferoffset+=read;
+ }
+ } else {
+ if(t2p->pdf_sample & T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG){
+
+ sepstripsize=TIFFStripSize(input);
+ sepstripcount=TIFFNumberOfStrips(input);
+
+ stripsize=sepstripsize*t2p->tiff_samplesperpixel;
+ stripcount=sepstripcount/t2p->tiff_samplesperpixel;
+
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ samplebuffer = (unsigned char*) _TIFFmalloc(stripsize);
+ if(samplebuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ for(i=0;i<stripcount;i++){
+ samplebufferoffset=0;
+ for(j=0;j<t2p->tiff_samplesperpixel;j++){
+ read =
+ TIFFReadEncodedStrip(input,
+ i + j*stripcount,
+ (tdata_t) &(samplebuffer[samplebufferoffset]),
+ sepstripsize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding strip %u of %s",
+ i + j*stripcount,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ samplebufferoffset+=read;
+ }
+ t2p_sample_planar_separate_to_contig(
+ t2p,
+ &(buffer[bufferoffset]),
+ samplebuffer,
+ samplebufferoffset);
+ bufferoffset+=samplebufferoffset;
+ }
+ _TIFFfree(samplebuffer);
+ goto dataready;
+ }
+
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ memset(buffer, 0, t2p->tiff_datasize);
+ stripsize=TIFFStripSize(input);
+ stripcount=TIFFNumberOfStrips(input);
+ for(i=0;i<stripcount;i++){
+ read =
+ TIFFReadEncodedStrip(input,
+ i,
+ (tdata_t) &buffer[bufferoffset],
+ stripsize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding strip %u of %s",
+ i,
+ TIFFFileName(input));
+ _TIFFfree(samplebuffer);
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ bufferoffset+=read;
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_REALIZE_PALETTE){
+ samplebuffer=(unsigned char*)_TIFFrealloc(
+ (tdata_t) buffer,
+ t2p->tiff_datasize * t2p->tiff_samplesperpixel);
+ if(samplebuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ _TIFFfree(buffer);
+ } else {
+ buffer=samplebuffer;
+ t2p->tiff_datasize *= t2p->tiff_samplesperpixel;
+ }
+ t2p_sample_realize_palette(t2p, buffer);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_RGBA_TO_RGB){
+ t2p->tiff_datasize=t2p_sample_rgba_to_rgb(
+ (tdata_t)buffer,
+ t2p->tiff_width*t2p->tiff_length);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_RGBAA_TO_RGB){
+ t2p->tiff_datasize=t2p_sample_rgbaa_to_rgb(
+ (tdata_t)buffer,
+ t2p->tiff_width*t2p->tiff_length);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_YCBCR_TO_RGB){
+ samplebuffer=(unsigned char*)_TIFFrealloc(
+ (tdata_t)buffer,
+ t2p->tiff_width*t2p->tiff_length*4);
+ if(samplebuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ _TIFFfree(buffer);
+ return(0);
+ } else {
+ buffer=samplebuffer;
+ }
+ if(!TIFFReadRGBAImageOriented(
+ input,
+ t2p->tiff_width,
+ t2p->tiff_length,
+ (uint32*)buffer,
+ ORIENTATION_TOPLEFT,
+ 0)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't use TIFFReadRGBAImageOriented to extract RGB image from %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ t2p->tiff_datasize=t2p_sample_abgr_to_rgb(
+ (tdata_t) buffer,
+ t2p->tiff_width*t2p->tiff_length);
+
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED){
+ t2p->tiff_datasize=t2p_sample_lab_signed_to_unsigned(
+ (tdata_t)buffer,
+ t2p->tiff_width*t2p->tiff_length);
+ }
+ }
+
+dataready:
+
+ t2p_disable(output);
+ TIFFSetField(output, TIFFTAG_PHOTOMETRIC, t2p->tiff_photometric);
+ TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, t2p->tiff_bitspersample);
+ TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, t2p->tiff_samplesperpixel);
+ TIFFSetField(output, TIFFTAG_IMAGEWIDTH, t2p->tiff_width);
+ TIFFSetField(output, TIFFTAG_IMAGELENGTH, t2p->tiff_length);
+ TIFFSetField(output, TIFFTAG_ROWSPERSTRIP, t2p->tiff_length);
+ TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(output, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+
+ switch(t2p->pdf_compression){
+ case T2P_COMPRESS_NONE:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ break;
+#ifdef CCITT_SUPPORT
+ case T2P_COMPRESS_G4:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
+ break;
+#endif
+#ifdef JPEG_SUPPORT
+ case T2P_COMPRESS_JPEG:
+ if(t2p->tiff_photometric==PHOTOMETRIC_YCBCR) {
+ uint16 hor = 0, ver = 0;
+ if (TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &hor, &ver) !=0 ) {
+ if(hor != 0 && ver != 0){
+ TIFFSetField(output, TIFFTAG_YCBCRSUBSAMPLING, hor, ver);
+ }
+ }
+ if(TIFFGetField(input, TIFFTAG_REFERENCEBLACKWHITE, &xfloatp)!=0){
+ TIFFSetField(output, TIFFTAG_REFERENCEBLACKWHITE, xfloatp);
+ }
+ }
+ if(TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_JPEG)==0){
+ TIFFError(TIFF2PDF_MODULE,
+ "Unable to use JPEG compression for input %s and output %s",
+ TIFFFileName(input),
+ TIFFFileName(output));
+ _TIFFfree(buffer);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ TIFFSetField(output, TIFFTAG_JPEGTABLESMODE, 0);
+
+ if(t2p->pdf_colorspace & (T2P_CS_RGB | T2P_CS_LAB)){
+ TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ if(t2p->tiff_photometric != PHOTOMETRIC_YCBCR){
+ TIFFSetField(output, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ } else {
+ TIFFSetField(output, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_GRAY){
+ (void)0;
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CMYK){
+ (void)0;
+ }
+ if(t2p->pdf_defaultcompressionquality != 0){
+ TIFFSetField(output,
+ TIFFTAG_JPEGQUALITY,
+ t2p->pdf_defaultcompressionquality);
+ }
+
+ break;
+#endif
+#ifdef ZIP_SUPPORT
+ case T2P_COMPRESS_ZIP:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
+ if(t2p->pdf_defaultcompressionquality%100 != 0){
+ TIFFSetField(output,
+ TIFFTAG_PREDICTOR,
+ t2p->pdf_defaultcompressionquality % 100);
+ }
+ if(t2p->pdf_defaultcompressionquality/100 != 0){
+ TIFFSetField(output,
+ TIFFTAG_ZIPQUALITY,
+ (t2p->pdf_defaultcompressionquality / 100));
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ t2p_enable(output);
+ t2p->outputwritten = 0;
+#ifdef JPEG_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_JPEG
+ && t2p->tiff_photometric == PHOTOMETRIC_YCBCR){
+ bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t)0,
+ buffer,
+ stripsize * stripcount);
+ } else
+#endif
+ {
+ bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t)0,
+ buffer,
+ t2p->tiff_datasize);
+ }
+ if (buffer != NULL) {
+ _TIFFfree(buffer);
+ buffer=NULL;
+ }
+
+ if (bufferoffset == (tsize_t)-1) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Error writing encoded strip to output PDF %s",
+ TIFFFileName(output));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+
+ written = t2p->outputwritten;
+ return(written);
+}
+
+/*
+ * This function reads the raster image data from the input TIFF for an image
+ * tile and writes the data to the output PDF XObject image dictionary stream
+ * for the tile. It returns the amount written or zero on error.
+ */
+
+tsize_t t2p_readwrite_pdf_image_tile(T2P* t2p, TIFF* input, TIFF* output, ttile_t tile){
+
+ uint16 edge=0;
+ tsize_t written=0;
+ unsigned char* buffer=NULL;
+ tsize_t bufferoffset=0;
+ unsigned char* samplebuffer=NULL;
+ tsize_t samplebufferoffset=0;
+ tsize_t read=0;
+ uint16 i=0;
+ ttile_t tilecount=0;
+ tsize_t tilesize=0;
+ ttile_t septilecount=0;
+ tsize_t septilesize=0;
+#ifdef JPEG_SUPPORT
+ unsigned char* jpt;
+ float* xfloatp;
+ uint32 xuint32=0;
+#endif
+
+ edge |= t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
+ edge |= t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile);
+
+ if( (t2p->pdf_transcode == T2P_TRANSCODE_RAW) && ((edge == 0)
+#if defined(JPEG_SUPPORT) || defined(OJPEG_SUPPORT)
+ || (t2p->pdf_compression == T2P_COMPRESS_JPEG)
+#endif
+ )
+ ){
+#ifdef CCITT_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_G4){
+ buffer= (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ TIFFReadRawTile(input, tile, (tdata_t) buffer, t2p->tiff_datasize);
+ if (t2p->tiff_fillorder==FILLORDER_LSB2MSB){
+ TIFFReverseBits(buffer, t2p->tiff_datasize);
+ }
+ t2pWriteFile(output, (tdata_t) buffer, t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef ZIP_SUPPORT
+ if(t2p->pdf_compression == T2P_COMPRESS_ZIP){
+ buffer= (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ TIFFReadRawTile(input, tile, (tdata_t) buffer, t2p->tiff_datasize);
+ if (t2p->tiff_fillorder==FILLORDER_LSB2MSB){
+ TIFFReverseBits(buffer, t2p->tiff_datasize);
+ }
+ t2pWriteFile(output, (tdata_t) buffer, t2p->tiff_datasize);
+ _TIFFfree(buffer);
+ return(t2p->tiff_datasize);
+ }
+#endif
+#ifdef OJPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_OJPEG){
+ if(! t2p->pdf_ojpegdata){
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for OJPEG image %s with "
+ "bad tables",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ buffer=(unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ _TIFFmemcpy(buffer, t2p->pdf_ojpegdata, t2p->pdf_ojpegdatalength);
+ if(edge!=0){
+ if(t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile)){
+ buffer[7]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength >> 8) & 0xff;
+ buffer[8]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength ) & 0xff;
+ }
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile)){
+ buffer[9]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth >> 8) & 0xff;
+ buffer[10]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth ) & 0xff;
+ }
+ }
+ bufferoffset=t2p->pdf_ojpegdatalength;
+ bufferoffset+=TIFFReadRawTile(input,
+ tile,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset]),
+ -1);
+ ((unsigned char*)buffer)[bufferoffset++]=0xff;
+ ((unsigned char*)buffer)[bufferoffset++]=0xd9;
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ }
+#endif
+#ifdef JPEG_SUPPORT
+ if(t2p->tiff_compression == COMPRESSION_JPEG){
+ unsigned char table_end[2];
+ uint32 count = 0;
+ buffer= (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(TIFFGetField(input, TIFFTAG_JPEGTABLES, &count, &jpt) != 0) {
+ if (count > 0) {
+ _TIFFmemcpy(buffer, jpt, count);
+ bufferoffset += count - 2;
+ table_end[0] = buffer[bufferoffset-2];
+ table_end[1] = buffer[bufferoffset-1];
+ }
+ if (count > 0) {
+ xuint32 = bufferoffset;
+ bufferoffset += TIFFReadRawTile(
+ input,
+ tile,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset-2]),
+ -1);
+ buffer[xuint32-2]=table_end[0];
+ buffer[xuint32-1]=table_end[1];
+ } else {
+ bufferoffset += TIFFReadRawTile(
+ input,
+ tile,
+ (tdata_t) &(((unsigned char*)buffer)[bufferoffset]),
+ -1);
+ }
+ }
+ t2pWriteFile(output, (tdata_t) buffer, bufferoffset);
+ _TIFFfree(buffer);
+ return(bufferoffset);
+ }
+#endif
+ (void)0;
+ }
+
+ if(t2p->pdf_sample==T2P_SAMPLE_NOTHING){
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for "
+ "t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+
+ read = TIFFReadEncodedTile(
+ input,
+ tile,
+ (tdata_t) &buffer[bufferoffset],
+ t2p->tiff_datasize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding tile %u of %s",
+ tile,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+
+ } else {
+
+ if(t2p->pdf_sample == T2P_SAMPLE_PLANAR_SEPARATE_TO_CONTIG){
+ septilesize=TIFFTileSize(input);
+ septilecount=TIFFNumberOfTiles(input);
+ tilesize=septilesize*t2p->tiff_samplesperpixel;
+ tilecount=septilecount/t2p->tiff_samplesperpixel;
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ samplebuffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(samplebuffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ samplebufferoffset=0;
+ for(i=0;i<t2p->tiff_samplesperpixel;i++){
+ read =
+ TIFFReadEncodedTile(input,
+ tile + i*tilecount,
+ (tdata_t) &(samplebuffer[samplebufferoffset]),
+ septilesize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding tile %u of %s",
+ tile + i*tilecount,
+ TIFFFileName(input));
+ _TIFFfree(samplebuffer);
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ samplebufferoffset+=read;
+ }
+ t2p_sample_planar_separate_to_contig(
+ t2p,
+ &(buffer[bufferoffset]),
+ samplebuffer,
+ samplebufferoffset);
+ bufferoffset+=samplebufferoffset;
+ _TIFFfree(samplebuffer);
+ }
+
+ if(buffer==NULL){
+ buffer = (unsigned char*) _TIFFmalloc(t2p->tiff_datasize);
+ if(buffer==NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory "
+ "for t2p_readwrite_pdf_image_tile, %s",
+ t2p->tiff_datasize,
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ read = TIFFReadEncodedTile(
+ input,
+ tile,
+ (tdata_t) &buffer[bufferoffset],
+ t2p->tiff_datasize);
+ if(read==-1){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error on decoding tile %u of %s",
+ tile,
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error=T2P_ERR_ERROR;
+ return(0);
+ }
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_RGBA_TO_RGB){
+ t2p->tiff_datasize=t2p_sample_rgba_to_rgb(
+ (tdata_t)buffer,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth
+ *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_RGBAA_TO_RGB){
+ t2p->tiff_datasize=t2p_sample_rgbaa_to_rgb(
+ (tdata_t)buffer,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth
+ *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_YCBCR_TO_RGB){
+ TIFFError(TIFF2PDF_MODULE,
+ "No support for YCbCr to RGB in tile for %s",
+ TIFFFileName(input));
+ _TIFFfree(buffer);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+
+ if(t2p->pdf_sample & T2P_SAMPLE_LAB_SIGNED_TO_UNSIGNED){
+ t2p->tiff_datasize=t2p_sample_lab_signed_to_unsigned(
+ (tdata_t)buffer,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth
+ *t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+ }
+
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile) != 0){
+ t2p_tile_collapse_left(
+ buffer,
+ TIFFTileRowSize(input),
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+
+
+ t2p_disable(output);
+ TIFFSetField(output, TIFFTAG_PHOTOMETRIC, t2p->tiff_photometric);
+ TIFFSetField(output, TIFFTAG_BITSPERSAMPLE, t2p->tiff_bitspersample);
+ TIFFSetField(output, TIFFTAG_SAMPLESPERPIXEL, t2p->tiff_samplesperpixel);
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile) == 0){
+ TIFFSetField(
+ output,
+ TIFFTAG_IMAGEWIDTH,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
+ } else {
+ TIFFSetField(
+ output,
+ TIFFTAG_IMAGEWIDTH,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
+ }
+ if(t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile) == 0){
+ TIFFSetField(
+ output,
+ TIFFTAG_IMAGELENGTH,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ TIFFSetField(
+ output,
+ TIFFTAG_ROWSPERSTRIP,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ } else {
+ TIFFSetField(
+ output,
+ TIFFTAG_IMAGELENGTH,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
+ TIFFSetField(
+ output,
+ TIFFTAG_ROWSPERSTRIP,
+ t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
+ }
+ TIFFSetField(output, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(output, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+
+ switch(t2p->pdf_compression){
+ case T2P_COMPRESS_NONE:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ break;
+#ifdef CCITT_SUPPORT
+ case T2P_COMPRESS_G4:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
+ break;
+#endif
+#ifdef JPEG_SUPPORT
+ case T2P_COMPRESS_JPEG:
+ if (t2p->tiff_photometric==PHOTOMETRIC_YCBCR) {
+ uint16 hor = 0, ver = 0;
+ if (TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &hor, &ver)!=0) {
+ if (hor != 0 && ver != 0) {
+ TIFFSetField(output, TIFFTAG_YCBCRSUBSAMPLING, hor, ver);
+ }
+ }
+ if(TIFFGetField(input, TIFFTAG_REFERENCEBLACKWHITE, &xfloatp)!=0){
+ TIFFSetField(output, TIFFTAG_REFERENCEBLACKWHITE, xfloatp);
+ }
+ }
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
+ TIFFSetField(output, TIFFTAG_JPEGTABLESMODE, 0); /* JPEGTABLESMODE_NONE */
+ if(t2p->pdf_colorspace & (T2P_CS_RGB | T2P_CS_LAB)){
+ TIFFSetField(output, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ if(t2p->tiff_photometric != PHOTOMETRIC_YCBCR){
+ TIFFSetField(output, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ } else {
+ TIFFSetField(output, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RAW);
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_GRAY){
+ (void)0;
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CMYK){
+ (void)0;
+ }
+ if(t2p->pdf_defaultcompressionquality != 0){
+ TIFFSetField(output,
+ TIFFTAG_JPEGQUALITY,
+ t2p->pdf_defaultcompressionquality);
+ }
+ break;
+#endif
+#ifdef ZIP_SUPPORT
+ case T2P_COMPRESS_ZIP:
+ TIFFSetField(output, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
+ if(t2p->pdf_defaultcompressionquality%100 != 0){
+ TIFFSetField(output,
+ TIFFTAG_PREDICTOR,
+ t2p->pdf_defaultcompressionquality % 100);
+ }
+ if(t2p->pdf_defaultcompressionquality/100 != 0){
+ TIFFSetField(output,
+ TIFFTAG_ZIPQUALITY,
+ (t2p->pdf_defaultcompressionquality / 100));
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ t2p_enable(output);
+ t2p->outputwritten = 0;
+ bufferoffset = TIFFWriteEncodedStrip(output, (tstrip_t) 0, buffer,
+ TIFFStripSize(output));
+ if (buffer != NULL) {
+ _TIFFfree(buffer);
+ buffer = NULL;
+ }
+ if (bufferoffset == -1) {
+ TIFFError(TIFF2PDF_MODULE,
+ "Error writing encoded tile to output PDF %s",
+ TIFFFileName(output));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+
+ written = t2p->outputwritten;
+
+ return(written);
+}
+
+#ifdef OJPEG_SUPPORT
+int t2p_process_ojpeg_tables(T2P* t2p, TIFF* input){
+ uint16 proc=0;
+ void* q;
+ uint32 q_length=0;
+ void* dc;
+ uint32 dc_length=0;
+ void* ac;
+ uint32 ac_length=0;
+ uint16* lp;
+ uint16* pt;
+ uint16 h_samp=1;
+ uint16 v_samp=1;
+ unsigned char* ojpegdata;
+ uint16 table_count;
+ uint32 offset_table;
+ uint32 offset_ms_l;
+ uint32 code_count;
+ uint32 i=0;
+ uint32 dest=0;
+ uint16 ri=0;
+ uint32 rows=0;
+
+ if(!TIFFGetField(input, TIFFTAG_JPEGPROC, &proc)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGProc field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(proc!=JPEGPROC_BASELINE && proc!=JPEGPROC_LOSSLESS){
+ TIFFError(TIFF2PDF_MODULE,
+ "Bad JPEGProc field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(!TIFFGetField(input, TIFFTAG_JPEGQTABLES, &q_length, &q)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGQTables field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(q_length < (64U * t2p->tiff_samplesperpixel)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Bad JPEGQTables field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(!TIFFGetField(input, TIFFTAG_JPEGDCTABLES, &dc_length, &dc)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGDCTables field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(proc==JPEGPROC_BASELINE){
+ if(!TIFFGetField(input, TIFFTAG_JPEGACTABLES, &ac_length, &ac)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGACTables field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ } else {
+ if(!TIFFGetField(input, TIFFTAG_JPEGLOSSLESSPREDICTORS, &lp)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGLosslessPredictors field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ if(!TIFFGetField(input, TIFFTAG_JPEGPOINTTRANSFORM, &pt)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Missing JPEGPointTransform field in OJPEG image %s",
+ TIFFFileName(input));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ }
+ if(!TIFFGetField(input, TIFFTAG_YCBCRSUBSAMPLING, &h_samp, &v_samp)){
+ h_samp=1;
+ v_samp=1;
+ }
+ if(t2p->pdf_ojpegdata != NULL){
+ _TIFFfree(t2p->pdf_ojpegdata);
+ t2p->pdf_ojpegdata=NULL;
+ }
+ t2p->pdf_ojpegdata = _TIFFmalloc(2048);
+ if(t2p->pdf_ojpegdata == NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_process_ojpeg_tables, %s",
+ 2048,
+ TIFFFileName(input));
+ return(0);
+ }
+ _TIFFmemset(t2p->pdf_ojpegdata, 0x00, 2048);
+ t2p->pdf_ojpegdatalength = 0;
+ table_count=t2p->tiff_samplesperpixel;
+ if(proc==JPEGPROC_BASELINE){
+ if(table_count>2) table_count=2;
+ }
+ ojpegdata=(unsigned char*)t2p->pdf_ojpegdata;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xd8;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ if(proc==JPEGPROC_BASELINE){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xc0;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xc3;
+ }
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=(8 + 3*t2p->tiff_samplesperpixel);
+ ojpegdata[t2p->pdf_ojpegdatalength++]=(t2p->tiff_bitspersample & 0xff);
+ if(TIFFIsTiled(input)){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength >> 8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength ) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth >> 8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth ) & 0xff;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_length >> 8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_length ) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_width >> 8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=
+ (t2p->tiff_width ) & 0xff;
+ }
+ ojpegdata[t2p->pdf_ojpegdatalength++]=(t2p->tiff_samplesperpixel & 0xff);
+ for(i=0;i<t2p->tiff_samplesperpixel;i++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=i;
+ if(i==0){
+ ojpegdata[t2p->pdf_ojpegdatalength] |= h_samp<<4 & 0xf0;;
+ ojpegdata[t2p->pdf_ojpegdatalength++] |= v_samp & 0x0f;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++]= 0x11;
+ }
+ ojpegdata[t2p->pdf_ojpegdatalength++]=i;
+ }
+ for(dest=0;dest<t2p->tiff_samplesperpixel;dest++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xdb;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x43;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=dest;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength++]),
+ &(((unsigned char*)q)[64*dest]), 64);
+ t2p->pdf_ojpegdatalength+=64;
+ }
+ offset_table=0;
+ for(dest=0;dest<table_count;dest++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xc4;
+ offset_ms_l=t2p->pdf_ojpegdatalength;
+ t2p->pdf_ojpegdatalength+=2;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=dest & 0x0f;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength]),
+ &(((unsigned char*)dc)[offset_table]), 16);
+ code_count=0;
+ offset_table+=16;
+ for(i=0;i<16;i++){
+ code_count+=ojpegdata[t2p->pdf_ojpegdatalength++];
+ }
+ ojpegdata[offset_ms_l]=((19+code_count)>>8) & 0xff;
+ ojpegdata[offset_ms_l+1]=(19+code_count) & 0xff;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength]),
+ &(((unsigned char*)dc)[offset_table]), code_count);
+ offset_table+=code_count;
+ t2p->pdf_ojpegdatalength+=code_count;
+ }
+ if(proc==JPEGPROC_BASELINE){
+ offset_table=0;
+ for(dest=0;dest<table_count;dest++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xc4;
+ offset_ms_l=t2p->pdf_ojpegdatalength;
+ t2p->pdf_ojpegdatalength+=2;
+ ojpegdata[t2p->pdf_ojpegdatalength] |= 0x10;
+ ojpegdata[t2p->pdf_ojpegdatalength++] |=dest & 0x0f;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength]),
+ &(((unsigned char*)ac)[offset_table]), 16);
+ code_count=0;
+ offset_table+=16;
+ for(i=0;i<16;i++){
+ code_count+=ojpegdata[t2p->pdf_ojpegdatalength++];
+ }
+ ojpegdata[offset_ms_l]=((19+code_count)>>8) & 0xff;
+ ojpegdata[offset_ms_l+1]=(19+code_count) & 0xff;
+ _TIFFmemcpy( &(ojpegdata[t2p->pdf_ojpegdatalength]),
+ &(((unsigned char*)ac)[offset_table]), code_count);
+ offset_table+=code_count;
+ t2p->pdf_ojpegdatalength+=code_count;
+ }
+ }
+ if(TIFFNumberOfStrips(input)>1){
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xdd;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x04;
+ h_samp*=8;
+ v_samp*=8;
+ ri=(t2p->tiff_width+h_samp-1) / h_samp;
+ TIFFGetField(input, TIFFTAG_ROWSPERSTRIP, &rows);
+ ri*=(rows+v_samp-1)/v_samp;
+ ojpegdata[t2p->pdf_ojpegdatalength++]= (ri>>8) & 0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]= ri & 0xff;
+ }
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xff;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0xda;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x00;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=(6 + 2*t2p->tiff_samplesperpixel);
+ ojpegdata[t2p->pdf_ojpegdatalength++]=t2p->tiff_samplesperpixel & 0xff;
+ for(i=0;i<t2p->tiff_samplesperpixel;i++){
+ ojpegdata[t2p->pdf_ojpegdatalength++]= i & 0xff;
+ if(proc==JPEGPROC_BASELINE){
+ ojpegdata[t2p->pdf_ojpegdatalength] |=
+ ( ( (i>(table_count-1U)) ? (table_count-1U) : i) << 4U) & 0xf0;
+ ojpegdata[t2p->pdf_ojpegdatalength++] |=
+ ( (i>(table_count-1U)) ? (table_count-1U) : i) & 0x0f;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++] = (i << 4) & 0xf0;
+ }
+ }
+ if(proc==JPEGPROC_BASELINE){
+ t2p->pdf_ojpegdatalength++;
+ ojpegdata[t2p->pdf_ojpegdatalength++]=0x3f;
+ t2p->pdf_ojpegdatalength++;
+ } else {
+ ojpegdata[t2p->pdf_ojpegdatalength++]= (lp[0] & 0xff);
+ t2p->pdf_ojpegdatalength++;
+ ojpegdata[t2p->pdf_ojpegdatalength++]= (pt[0] & 0x0f);
+ }
+
+ return(1);
+}
+#endif
+
+#ifdef JPEG_SUPPORT
+int t2p_process_jpeg_strip(
+ unsigned char* strip,
+ tsize_t* striplength,
+ unsigned char* buffer,
+ tsize_t* bufferoffset,
+ tstrip_t no,
+ uint32 height){
+
+ tsize_t i=0;
+ uint16 ri =0;
+ uint16 v_samp=1;
+ uint16 h_samp=1;
+ int j=0;
+
+ i++;
+
+ while(i<(*striplength)){
+ switch( strip[i] ){
+ case 0xd8:
+ /* SOI - start of image */
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), 2);
+ *bufferoffset+=2;
+ i+=2;
+ break;
+ case 0xc0:
+ case 0xc1:
+ case 0xc3:
+ case 0xc9:
+ case 0xca:
+ if(no==0){
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), strip[i+2]+2);
+ for(j=0;j<buffer[*bufferoffset+9];j++){
+ if( (buffer[*bufferoffset+11+(2*j)]>>4) > h_samp)
+ h_samp = (buffer[*bufferoffset+11+(2*j)]>>4);
+ if( (buffer[*bufferoffset+11+(2*j)] & 0x0f) > v_samp)
+ v_samp = (buffer[*bufferoffset+11+(2*j)] & 0x0f);
+ }
+ v_samp*=8;
+ h_samp*=8;
+ ri=((( ((uint16)(buffer[*bufferoffset+5])<<8) |
+ (uint16)(buffer[*bufferoffset+6]) )+v_samp-1)/
+ v_samp);
+ ri*=((( ((uint16)(buffer[*bufferoffset+7])<<8) |
+ (uint16)(buffer[*bufferoffset+8]) )+h_samp-1)/
+ h_samp);
+ buffer[*bufferoffset+5]=
+ (unsigned char) ((height>>8) & 0xff);
+ buffer[*bufferoffset+6]=
+ (unsigned char) (height & 0xff);
+ *bufferoffset+=strip[i+2]+2;
+ i+=strip[i+2]+2;
+
+ buffer[(*bufferoffset)++]=0xff;
+ buffer[(*bufferoffset)++]=0xdd;
+ buffer[(*bufferoffset)++]=0x00;
+ buffer[(*bufferoffset)++]=0x04;
+ buffer[(*bufferoffset)++]=(ri >> 8) & 0xff;
+ buffer[(*bufferoffset)++]= ri & 0xff;
+ } else {
+ i+=strip[i+2]+2;
+ }
+ break;
+ case 0xc4:
+ case 0xdb:
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), strip[i+2]+2);
+ *bufferoffset+=strip[i+2]+2;
+ i+=strip[i+2]+2;
+ break;
+ case 0xda:
+ if(no==0){
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), strip[i+2]+2);
+ *bufferoffset+=strip[i+2]+2;
+ i+=strip[i+2]+2;
+ } else {
+ buffer[(*bufferoffset)++]=0xff;
+ buffer[(*bufferoffset)++]=
+ (unsigned char)(0xd0 | ((no-1)%8));
+ i+=strip[i+2]+2;
+ }
+ _TIFFmemcpy(&(buffer[*bufferoffset]), &(strip[i-1]), (*striplength)-i-1);
+ *bufferoffset+=(*striplength)-i-1;
+ return(1);
+ default:
+ i+=strip[i+2]+2;
+ }
+ }
+
+
+ return(0);
+}
+#endif
+
+/*
+ This functions converts a tilewidth x tilelength buffer of samples into an edgetilewidth x
+ tilelength buffer of samples.
+*/
+void t2p_tile_collapse_left(
+ tdata_t buffer,
+ tsize_t scanwidth,
+ uint32 tilewidth,
+ uint32 edgetilewidth,
+ uint32 tilelength){
+
+ uint32 i=0;
+ tsize_t edgescanwidth=0;
+
+ edgescanwidth = (scanwidth * edgetilewidth + (tilewidth - 1))/ tilewidth;
+ for(i=i;i<tilelength;i++){
+ _TIFFmemcpy(
+ &(((char*)buffer)[edgescanwidth*i]),
+ &(((char*)buffer)[scanwidth*i]),
+ edgescanwidth);
+ }
+
+ return;
+}
+
+
+/*
+ * This function calls TIFFWriteDirectory on the output after blanking its
+ * output by replacing the read, write, and seek procedures with empty
+ * implementations, then it replaces the original implementations.
+ */
+
+void
+t2p_write_advance_directory(T2P* t2p, TIFF* output)
+{
+ t2p_disable(output);
+ if(!TIFFWriteDirectory(output)){
+ TIFFError(TIFF2PDF_MODULE,
+ "Error writing virtual directory to output PDF %s",
+ TIFFFileName(output));
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ t2p_enable(output);
+ return;
+}
+
+tsize_t t2p_sample_planar_separate_to_contig(
+ T2P* t2p,
+ unsigned char* buffer,
+ unsigned char* samplebuffer,
+ tsize_t samplebuffersize){
+
+ tsize_t stride=0;
+ tsize_t i=0;
+ tsize_t j=0;
+
+ stride=samplebuffersize/t2p->tiff_samplesperpixel;
+ for(i=0;i<stride;i++){
+ for(j=0;j<t2p->tiff_samplesperpixel;j++){
+ buffer[i*t2p->tiff_samplesperpixel + j] = samplebuffer[i + j*stride];
+ }
+ }
+
+ return(samplebuffersize);
+}
+
+tsize_t t2p_sample_realize_palette(T2P* t2p, unsigned char* buffer){
+
+ uint32 sample_count=0;
+ uint16 component_count=0;
+ uint32 palette_offset=0;
+ uint32 sample_offset=0;
+ uint32 i=0;
+ uint32 j=0;
+ sample_count=t2p->tiff_width*t2p->tiff_length;
+ component_count=t2p->tiff_samplesperpixel;
+
+ for(i=sample_count;i>0;i--){
+ palette_offset=buffer[i-1] * component_count;
+ sample_offset= (i-1) * component_count;
+ for(j=0;j<component_count;j++){
+ buffer[sample_offset+j]=t2p->pdf_palette[palette_offset+j];
+ }
+ }
+
+ return(0);
+}
+
+/*
+ This functions converts in place a buffer of ABGR interleaved data
+ into RGB interleaved data, discarding A.
+*/
+
+tsize_t t2p_sample_abgr_to_rgb(tdata_t data, uint32 samplecount)
+{
+ uint32 i=0;
+ uint32 sample=0;
+
+ for(i=0;i<samplecount;i++){
+ sample=((uint32*)data)[i];
+ ((char*)data)[i*3]= (char) (sample & 0xff);
+ ((char*)data)[i*3+1]= (char) ((sample>>8) & 0xff);
+ ((char*)data)[i*3+2]= (char) ((sample>>16) & 0xff);
+ }
+
+ return(i*3);
+}
+
+/*
+ * This functions converts in place a buffer of RGBA interleaved data
+ * into RGB interleaved data, discarding A.
+ */
+
+tsize_t
+t2p_sample_rgbaa_to_rgb(tdata_t data, uint32 samplecount)
+{
+ uint32 i;
+
+ for(i = 0; i < samplecount; i++)
+ memcpy((uint8*)data + i * 3, (uint8*)data + i * 4, 3);
+
+ return(i * 3);
+}
+
+/*
+ * This functions converts in place a buffer of RGBA interleaved data
+ * into RGB interleaved data, adding 255-A to each component sample.
+ */
+
+tsize_t
+t2p_sample_rgba_to_rgb(tdata_t data, uint32 samplecount)
+{
+ uint32 i = 0;
+ uint32 sample = 0;
+ uint8 alpha = 0;
+
+ for (i = 0; i < samplecount; i++) {
+ sample=((uint32*)data)[i];
+ alpha=(uint8)((255 - (sample & 0xff)));
+ ((uint8 *)data)[i * 3] = (uint8) ((sample >> 24) & 0xff) + alpha;
+ ((uint8 *)data)[i * 3 + 1] = (uint8) ((sample >> 16) & 0xff) + alpha;
+ ((uint8 *)data)[i * 3 + 2] = (uint8) ((sample >> 8) & 0xff) + alpha;
+
+ }
+
+ return (i * 3);
+}
+
+/*
+ This function converts the a and b samples of Lab data from signed
+ to unsigned.
+*/
+
+tsize_t t2p_sample_lab_signed_to_unsigned(tdata_t buffer, uint32 samplecount){
+
+ uint32 i=0;
+
+ for(i=0;i<samplecount;i++){
+ if( (((unsigned char*)buffer)[(i*3)+1] & 0x80) !=0){
+ ((unsigned char*)buffer)[(i*3)+1] =
+ (unsigned char)(0x80 + ((char*)buffer)[(i*3)+1]);
+ } else {
+ ((unsigned char*)buffer)[(i*3)+1] |= 0x80;
+ }
+ if( (((unsigned char*)buffer)[(i*3)+2] & 0x80) !=0){
+ ((unsigned char*)buffer)[(i*3)+2] =
+ (unsigned char)(0x80 + ((char*)buffer)[(i*3)+2]);
+ } else {
+ ((unsigned char*)buffer)[(i*3)+2] |= 0x80;
+ }
+ }
+
+ return(samplecount*3);
+}
+
+/*
+ This function writes the PDF header to output.
+*/
+
+tsize_t t2p_write_pdf_header(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ buflen=sprintf(buffer, "%%PDF-%u.%u ", t2p->pdf_majorversion&0xff, t2p->pdf_minorversion&0xff);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t)"\n%\342\343\317\323\n", 7);
+
+ return(written);
+}
+
+/*
+ This function writes the beginning of a PDF object to output.
+*/
+
+tsize_t t2p_write_pdf_obj_start(uint32 number, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ buflen=sprintf(buffer, "%lu", (unsigned long)number);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen );
+ written += t2pWriteFile(output, (tdata_t) " 0 obj\n", 7);
+
+ return(written);
+}
+
+/*
+ This function writes the end of a PDF object to output.
+*/
+
+tsize_t t2p_write_pdf_obj_end(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) "endobj\n", 7);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF name object to output.
+*/
+
+tsize_t t2p_write_pdf_name(unsigned char* name, TIFF* output){
+
+ tsize_t written=0;
+ uint32 i=0;
+ char buffer[64];
+ uint16 nextchar=0;
+ uint32 namelen=0;
+
+ namelen = strlen((char *)name);
+ if (namelen>126) {
+ namelen=126;
+ }
+ written += t2pWriteFile(output, (tdata_t) "/", 1);
+ for (i=0;i<namelen;i++){
+ if ( ((unsigned char)name[i]) < 0x21){
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ nextchar=1;
+ }
+ if ( ((unsigned char)name[i]) > 0x7E){
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ nextchar=1;
+ }
+ if (nextchar==0){
+ switch (name[i]){
+ case 0x23:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x25:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x28:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x29:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x2F:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x3C:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x3E:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x5B:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x5D:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x7B:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ case 0x7D:
+ sprintf(buffer, "#%.2X", name[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 3);
+ break;
+ default:
+ written += t2pWriteFile(output, (tdata_t) &name[i], 1);
+ }
+ }
+ nextchar=0;
+ }
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF string object to output.
+*/
+
+tsize_t t2p_write_pdf_string(unsigned char* pdfstr, TIFF* output){
+
+ tsize_t written = 0;
+ uint32 i = 0;
+ char buffer[64];
+ uint32 len = 0;
+
+ len = strlen((char *)pdfstr);
+ written += t2pWriteFile(output, (tdata_t) "(", 1);
+ for (i=0; i<len; i++) {
+ if((pdfstr[i]&0x80) || (pdfstr[i]==127) || (pdfstr[i]<32)){
+ sprintf(buffer, "\\%.3hho", pdfstr[i]);
+ buffer[sizeof(buffer) - 1] = '\0';
+ written += t2pWriteFile(output, (tdata_t) buffer, 4);
+ } else {
+ switch (pdfstr[i]){
+ case 0x08:
+ written += t2pWriteFile(output, (tdata_t) "\\b", 2);
+ break;
+ case 0x09:
+ written += t2pWriteFile(output, (tdata_t) "\\t", 2);
+ break;
+ case 0x0A:
+ written += t2pWriteFile(output, (tdata_t) "\\n", 2);
+ break;
+ case 0x0C:
+ written += t2pWriteFile(output, (tdata_t) "\\f", 2);
+ break;
+ case 0x0D:
+ written += t2pWriteFile(output, (tdata_t) "\\r", 2);
+ break;
+ case 0x28:
+ written += t2pWriteFile(output, (tdata_t) "\\(", 2);
+ break;
+ case 0x29:
+ written += t2pWriteFile(output, (tdata_t) "\\)", 2);
+ break;
+ case 0x5C:
+ written += t2pWriteFile(output, (tdata_t) "\\\\", 2);
+ break;
+ default:
+ written += t2pWriteFile(output, (tdata_t) &pdfstr[i], 1);
+ }
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) ") ", 1);
+
+ return(written);
+}
+
+
+/*
+ This function writes a buffer of data to output.
+*/
+
+tsize_t t2p_write_pdf_stream(tdata_t buffer, tsize_t len, TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) buffer, len);
+
+ return(written);
+}
+
+/*
+ This functions writes the beginning of a PDF stream to output.
+*/
+
+tsize_t t2p_write_pdf_stream_start(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) "stream\n", 7);
+
+ return(written);
+}
+
+/*
+ This function writes the end of a PDF stream to output.
+*/
+
+tsize_t t2p_write_pdf_stream_end(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) "\nendstream\n", 11);
+
+ return(written);
+}
+
+/*
+ This function writes a stream dictionary for a PDF stream to output.
+*/
+
+tsize_t t2p_write_pdf_stream_dict(tsize_t len, uint32 number, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "/Length ", 8);
+ if(len!=0){
+ written += t2p_write_pdf_stream_length(len, output);
+ } else {
+ buflen=sprintf(buffer, "%lu", (unsigned long)number);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
+ }
+
+ return(written);
+}
+
+/*
+ This functions writes the beginning of a PDF stream dictionary to output.
+*/
+
+tsize_t t2p_write_pdf_stream_dict_start(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) "<< \n", 4);
+
+ return(written);
+}
+
+/*
+ This function writes the end of a PDF stream dictionary to output.
+*/
+
+tsize_t t2p_write_pdf_stream_dict_end(TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2pWriteFile(output, (tdata_t) " >>\n", 4);
+
+ return(written);
+}
+
+/*
+ This function writes a number to output.
+*/
+
+tsize_t t2p_write_pdf_stream_length(tsize_t len, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ buflen=sprintf(buffer, "%lu", (unsigned long)len);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+
+ return(written);
+}
+
+/*
+ This function writes the PDF Catalog structure to output.
+*/
+
+tsize_t t2p_write_pdf_catalog(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output,
+ (tdata_t)"<< \n/Type /Catalog \n/Pages ",
+ 27);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_pages);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen );
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
+ if(t2p->pdf_fitwindow){
+ written += t2pWriteFile(output,
+ (tdata_t) "/ViewerPreferences <</FitWindow true>>\n",
+ 39);
+ }
+ written += t2pWriteFile(output, (tdata_t)">>\n", 3);
+
+ return(written);
+}
+
+/*
+ This function writes the PDF Info structure to output.
+*/
+
+tsize_t t2p_write_pdf_info(T2P* t2p, TIFF* input, TIFF* output){
+
+ tsize_t written = 0;
+ unsigned char* info;
+ char buffer[512];
+ int buflen = 0;
+
+ if(t2p->pdf_datetime==NULL){
+ t2p_pdf_tifftime(t2p, input);
+ }
+ if(strlen((char *)t2p->pdf_datetime) > 0){
+ written += t2pWriteFile(output, (tdata_t) "<< \n/CreationDate ", 18);
+ written += t2p_write_pdf_string(t2p->pdf_datetime, output);
+ written += t2pWriteFile(output, (tdata_t) "\n/ModDate ", 10);
+ written += t2p_write_pdf_string(t2p->pdf_datetime, output);
+ }
+ written += t2pWriteFile(output, (tdata_t) "\n/Producer ", 11);
+ _TIFFmemset((tdata_t)buffer, 0x00, sizeof(buffer));
+ buflen = sprintf(buffer, "libtiff / tiff2pdf - %d", TIFFLIB_VERSION);
+ written += t2p_write_pdf_string((unsigned char*)buffer, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ if(t2p->pdf_creator != NULL){
+ if(strlen((char *)t2p->pdf_creator)>0){
+ if(strlen((char *)t2p->pdf_creator) > 511) {
+ t2p->pdf_creator[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Creator ", 9);
+ written += t2p_write_pdf_string(t2p->pdf_creator, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ } else{
+ if( TIFFGetField(input, TIFFTAG_SOFTWARE, &info) != 0){
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Creator ", 9);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ if(t2p->pdf_author != NULL) {
+ if(strlen((char *)t2p->pdf_author) > 0) {
+ if(strlen((char *)t2p->pdf_author) > 511) {
+ t2p->pdf_author[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Author ", 8);
+ written += t2p_write_pdf_string(t2p->pdf_author, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ } else{
+ if( TIFFGetField(input, TIFFTAG_ARTIST, &info) != 0){
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Author ", 8);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ } else if ( TIFFGetField(input, TIFFTAG_COPYRIGHT, &info) != 0){
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Author ", 8);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ if(t2p->pdf_title != NULL) {
+ if(strlen((char *)t2p->pdf_title) > 0) {
+ if(strlen((char *)t2p->pdf_title) > 511) {
+ t2p->pdf_title[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Title ", 7);
+ written += t2p_write_pdf_string(t2p->pdf_title, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ } else{
+ if( TIFFGetField(input, TIFFTAG_DOCUMENTNAME, &info) != 0){
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Title ", 7);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ if(t2p->pdf_subject != NULL) {
+ if(strlen((char *)t2p->pdf_subject) > 0) {
+ if(strlen((char *)t2p->pdf_subject) > 511) {
+ t2p->pdf_subject[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Subject ", 9);
+ written += t2p_write_pdf_string(t2p->pdf_subject, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ } else {
+ if(TIFFGetField(input, TIFFTAG_IMAGEDESCRIPTION, &info) != 0) {
+ if(strlen((char *)info) > 511) {
+ info[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Subject ", 9);
+ written += t2p_write_pdf_string(info, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ if(t2p->pdf_keywords != NULL) {
+ if(strlen((char *)t2p->pdf_keywords) > 0) {
+ if(strlen((char *)t2p->pdf_keywords) > 511) {
+ t2p->pdf_keywords[512] = '\0';
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Keywords ", 10);
+ written += t2p_write_pdf_string(t2p->pdf_keywords, output);
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) ">> \n", 4);
+
+ return(written);
+}
+
+/*
+ * This function fills a string of a T2P struct with the current time as a PDF
+ * date string, it is called by t2p_pdf_tifftime.
+ */
+
+void t2p_pdf_currenttime(T2P* t2p)
+{
+
+ struct tm* currenttime;
+ time_t timenow;
+
+ timenow=time(0);
+ currenttime=localtime(&timenow);
+ sprintf((char *)t2p->pdf_datetime, "D:%.4d%.2d%.2d%.2d%.2d%.2d",
+ (currenttime->tm_year+1900) % 65536,
+ (currenttime->tm_mon+1) % 256,
+ (currenttime->tm_mday) % 256,
+ (currenttime->tm_hour) % 256,
+ (currenttime->tm_min) % 256,
+ (currenttime->tm_sec) % 256);
+
+ return;
+}
+
+/*
+ * This function fills a string of a T2P struct with the date and time of a
+ * TIFF file if it exists or the current time as a PDF date string.
+ */
+
+void t2p_pdf_tifftime(T2P* t2p, TIFF* input){
+
+ char* datetime;
+
+ t2p->pdf_datetime = (unsigned char*) _TIFFmalloc(19);
+ if(t2p->pdf_datetime == NULL){
+ TIFFError(TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_pdf_tiff_time", 17);
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return;
+ }
+ t2p->pdf_datetime[16] = '\0';
+ if( TIFFGetField(input, TIFFTAG_DATETIME, &datetime) != 0
+ && (strlen(datetime) >= 19) ){
+ t2p->pdf_datetime[0]='D';
+ t2p->pdf_datetime[1]=':';
+ t2p->pdf_datetime[2]=datetime[0];
+ t2p->pdf_datetime[3]=datetime[1];
+ t2p->pdf_datetime[4]=datetime[2];
+ t2p->pdf_datetime[5]=datetime[3];
+ t2p->pdf_datetime[6]=datetime[5];
+ t2p->pdf_datetime[7]=datetime[6];
+ t2p->pdf_datetime[8]=datetime[8];
+ t2p->pdf_datetime[9]=datetime[9];
+ t2p->pdf_datetime[10]=datetime[11];
+ t2p->pdf_datetime[11]=datetime[12];
+ t2p->pdf_datetime[12]=datetime[14];
+ t2p->pdf_datetime[13]=datetime[15];
+ t2p->pdf_datetime[14]=datetime[17];
+ t2p->pdf_datetime[15]=datetime[18];
+ } else {
+ t2p_pdf_currenttime(t2p);
+ }
+
+ return;
+}
+
+/*
+ * This function writes a PDF Pages Tree structure to output.
+ */
+
+tsize_t t2p_write_pdf_pages(T2P* t2p, TIFF* output)
+{
+ tsize_t written=0;
+ tdir_t i=0;
+ char buffer[16];
+ int buflen=0;
+
+ int page=0;
+ written += t2pWriteFile(output,
+ (tdata_t) "<< \n/Type /Pages \n/Kids [ ", 26);
+ page = t2p->pdf_pages+1;
+ for (i=0;i<t2p->tiff_pagecount;i++){
+ buflen=sprintf(buffer, "%d", page);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ if ( ((i+1)%8)==0 ) {
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ page +=3;
+ page += t2p->tiff_pages[i].page_extra;
+ if(t2p->tiff_pages[i].page_tilecount>0){
+ page += (2 * t2p->tiff_pages[i].page_tilecount);
+ } else {
+ page +=2;
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) "] \n/Count ", 10);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%d", t2p->tiff_pagecount);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " \n>> \n", 6);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Page structure to output.
+*/
+
+tsize_t t2p_write_pdf_page(uint32 object, T2P* t2p, TIFF* output){
+
+ unsigned int i=0;
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "<<\n/Type /Page \n/Parent ", 24);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_pages);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
+ written += t2pWriteFile(output, (tdata_t) "/MediaBox [", 11);
+ buflen=sprintf(buffer, "%.4f",t2p->pdf_mediabox.x1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen=sprintf(buffer, "%.4f",t2p->pdf_mediabox.y1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen=sprintf(buffer, "%.4f",t2p->pdf_mediabox.x2);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen=sprintf(buffer, "%.4f",t2p->pdf_mediabox.y2);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "] \n", 3);
+ written += t2pWriteFile(output, (tdata_t) "/Contents ", 10);
+ buflen=sprintf(buffer, "%lu", (unsigned long)(object + 1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n", 6);
+ written += t2pWriteFile(output, (tdata_t) "/Resources << \n", 15);
+ if( t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount != 0 ){
+ written += t2pWriteFile(output, (tdata_t) "/XObject <<\n", 12);
+ for(i=0;i<t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount;i++){
+ written += t2pWriteFile(output, (tdata_t) "/Im", 3);
+ buflen = sprintf(buffer, "%u", t2p->pdf_page+1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "_", 1);
+ buflen = sprintf(buffer, "%u", i+1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen = sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)(object+3+(2*i)+t2p->tiff_pages[t2p->pdf_page].page_extra));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ if(i%4==3){
+ written += t2pWriteFile(output, (tdata_t) "\n", 1);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/XObject <<\n", 12);
+ written += t2pWriteFile(output, (tdata_t) "/Im", 3);
+ buflen = sprintf(buffer, "%u", t2p->pdf_page+1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ buflen = sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)(object+3+(2*i)+t2p->tiff_pages[t2p->pdf_page].page_extra));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
+ }
+ if(t2p->tiff_transferfunctioncount != 0) {
+ written += t2pWriteFile(output, (tdata_t) "/ExtGState <<", 13);
+ t2pWriteFile(output, (tdata_t) "/GS1 ", 5);
+ buflen = sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)(object + 3));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ written += t2pWriteFile(output, (tdata_t) ">> \n", 4);
+ }
+ written += t2pWriteFile(output, (tdata_t) "/ProcSet [ ", 11);
+ if(t2p->pdf_colorspace == T2P_CS_BILEVEL
+ || t2p->pdf_colorspace == T2P_CS_GRAY
+ ){
+ written += t2pWriteFile(output, (tdata_t) "/ImageB ", 8);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/ImageC ", 8);
+ if(t2p->pdf_colorspace & T2P_CS_PALETTE){
+ written += t2pWriteFile(output, (tdata_t) "/ImageI ", 8);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) "]\n>>\n>>\n", 8);
+
+ return(written);
+}
+
+/*
+ This function composes the page size and image and tile locations on a page.
+*/
+
+void t2p_compose_pdf_page(T2P* t2p){
+
+ uint32 i=0;
+ uint32 i2=0;
+ T2P_TILE* tiles=NULL;
+ T2P_BOX* boxp=NULL;
+ uint32 tilecountx=0;
+ uint32 tilecounty=0;
+ uint32 tilewidth=0;
+ uint32 tilelength=0;
+ int istiled=0;
+ float f=0;
+
+ t2p->pdf_xres = t2p->tiff_xres;
+ t2p->pdf_yres = t2p->tiff_yres;
+ if(t2p->pdf_overrideres) {
+ t2p->pdf_xres = t2p->pdf_defaultxres;
+ t2p->pdf_yres = t2p->pdf_defaultyres;
+ }
+ if(t2p->pdf_xres == 0.0)
+ t2p->pdf_xres = t2p->pdf_defaultxres;
+ if(t2p->pdf_yres == 0.0)
+ t2p->pdf_yres = t2p->pdf_defaultyres;
+ if (t2p->tiff_resunit != RESUNIT_CENTIMETER /* RESUNIT_NONE and */
+ && t2p->tiff_resunit != RESUNIT_INCH) { /* other cases */
+ t2p->pdf_imagewidth = ((float)(t2p->tiff_width))/t2p->pdf_xres;
+ t2p->pdf_imagelength = ((float)(t2p->tiff_length))/t2p->pdf_yres;
+ } else {
+ t2p->pdf_imagewidth =
+ ((float)(t2p->tiff_width))*PS_UNIT_SIZE/t2p->pdf_xres;
+ t2p->pdf_imagelength =
+ ((float)(t2p->tiff_length))*PS_UNIT_SIZE/t2p->pdf_yres;
+ }
+ if(t2p->pdf_overridepagesize != 0) {
+ t2p->pdf_pagewidth = t2p->pdf_defaultpagewidth;
+ t2p->pdf_pagelength = t2p->pdf_defaultpagelength;
+ } else {
+ t2p->pdf_pagewidth = t2p->pdf_imagewidth;
+ t2p->pdf_pagelength = t2p->pdf_imagelength;
+ }
+ t2p->pdf_mediabox.x1=0.0;
+ t2p->pdf_mediabox.y1=0.0;
+ t2p->pdf_mediabox.x2=t2p->pdf_pagewidth;
+ t2p->pdf_mediabox.y2=t2p->pdf_pagelength;
+ t2p->pdf_imagebox.x1=0.0;
+ t2p->pdf_imagebox.y1=0.0;
+ t2p->pdf_imagebox.x2=t2p->pdf_imagewidth;
+ t2p->pdf_imagebox.y2=t2p->pdf_imagelength;
+ if(t2p->pdf_overridepagesize!=0){
+ t2p->pdf_imagebox.x1+=((t2p->pdf_pagewidth-t2p->pdf_imagewidth)/2.0F);
+ t2p->pdf_imagebox.y1+=((t2p->pdf_pagelength-t2p->pdf_imagelength)/2.0F);
+ t2p->pdf_imagebox.x2+=((t2p->pdf_pagewidth-t2p->pdf_imagewidth)/2.0F);
+ t2p->pdf_imagebox.y2+=((t2p->pdf_pagelength-t2p->pdf_imagelength)/2.0F);
+ }
+ if(t2p->tiff_orientation > 4){
+ f=t2p->pdf_mediabox.x2;
+ t2p->pdf_mediabox.x2=t2p->pdf_mediabox.y2;
+ t2p->pdf_mediabox.y2=f;
+ }
+ istiled=((t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount==0) ? 0 : 1;
+ if(istiled==0){
+ t2p_compose_pdf_page_orient(&(t2p->pdf_imagebox), t2p->tiff_orientation);
+ return;
+ } else {
+ tilewidth=(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilewidth;
+ tilelength=(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilelength;
+ tilecountx=(t2p->tiff_width +
+ tilewidth -1)/
+ tilewidth;
+ (t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecountx=tilecountx;
+ tilecounty=(t2p->tiff_length +
+ tilelength -1)/
+ tilelength;
+ (t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecounty=tilecounty;
+ (t2p->tiff_tiles[t2p->pdf_page]).tiles_edgetilewidth=
+ t2p->tiff_width % tilewidth;
+ (t2p->tiff_tiles[t2p->pdf_page]).tiles_edgetilelength=
+ t2p->tiff_length % tilelength;
+ tiles=(t2p->tiff_tiles[t2p->pdf_page]).tiles_tiles;
+ for(i2=0;i2<tilecounty-1;i2++){
+ for(i=0;i<tilecountx-1;i++){
+ boxp=&(tiles[i2*tilecountx+i].tile_box);
+ boxp->x1 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * i * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->x2 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * (i+1) * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->y1 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * (i2+1) * tilelength)
+ / (float)t2p->tiff_length);
+ boxp->y2 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * i2 * tilelength)
+ / (float)t2p->tiff_length);
+ }
+ boxp=&(tiles[i2*tilecountx+i].tile_box);
+ boxp->x1 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * i * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->x2 = t2p->pdf_imagebox.x2;
+ boxp->y1 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * (i2+1) * tilelength)
+ / (float)t2p->tiff_length);
+ boxp->y2 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * i2 * tilelength)
+ / (float)t2p->tiff_length);
+ }
+ for(i=0;i<tilecountx-1;i++){
+ boxp=&(tiles[i2*tilecountx+i].tile_box);
+ boxp->x1 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * i * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->x2 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * (i+1) * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->y1 = t2p->pdf_imagebox.y1;
+ boxp->y2 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * i2 * tilelength)
+ / (float)t2p->tiff_length);
+ }
+ boxp=&(tiles[i2*tilecountx+i].tile_box);
+ boxp->x1 =
+ t2p->pdf_imagebox.x1
+ + ((float)(t2p->pdf_imagewidth * i * tilewidth)
+ / (float)t2p->tiff_width);
+ boxp->x2 = t2p->pdf_imagebox.x2;
+ boxp->y1 = t2p->pdf_imagebox.y1;
+ boxp->y2 =
+ t2p->pdf_imagebox.y2
+ - ((float)(t2p->pdf_imagelength * i2 * tilelength)
+ / (float)t2p->tiff_length);
+ }
+ if(t2p->tiff_orientation==0 || t2p->tiff_orientation==1){
+ for(i=0;i<(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount;i++){
+ t2p_compose_pdf_page_orient( &(tiles[i].tile_box) , 0);
+ }
+ return;
+ }
+ for(i=0;i<(t2p->tiff_tiles[t2p->pdf_page]).tiles_tilecount;i++){
+ boxp=&(tiles[i].tile_box);
+ boxp->x1 -= t2p->pdf_imagebox.x1;
+ boxp->x2 -= t2p->pdf_imagebox.x1;
+ boxp->y1 -= t2p->pdf_imagebox.y1;
+ boxp->y2 -= t2p->pdf_imagebox.y1;
+ if(t2p->tiff_orientation==2 || t2p->tiff_orientation==3){
+ boxp->x1 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x1;
+ boxp->x2 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x2;
+ }
+ if(t2p->tiff_orientation==3 || t2p->tiff_orientation==4){
+ boxp->y1 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y1;
+ boxp->y2 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y2;
+ }
+ if(t2p->tiff_orientation==8 || t2p->tiff_orientation==5){
+ boxp->y1 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y1;
+ boxp->y2 = t2p->pdf_imagebox.y2 - t2p->pdf_imagebox.y1 - boxp->y2;
+ }
+ if(t2p->tiff_orientation==5 || t2p->tiff_orientation==6){
+ boxp->x1 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x1;
+ boxp->x2 = t2p->pdf_imagebox.x2 - t2p->pdf_imagebox.x1 - boxp->x2;
+ }
+ if(t2p->tiff_orientation > 4){
+ f=boxp->x1;
+ boxp->x1 = boxp->y1;
+ boxp->y1 = f;
+ f=boxp->x2;
+ boxp->x2 = boxp->y2;
+ boxp->y2 = f;
+ t2p_compose_pdf_page_orient_flip(boxp, t2p->tiff_orientation);
+ } else {
+ t2p_compose_pdf_page_orient(boxp, t2p->tiff_orientation);
+ }
+
+ }
+
+ return;
+}
+
+void t2p_compose_pdf_page_orient(T2P_BOX* boxp, uint16 orientation){
+
+ float m1[9];
+ float f=0.0;
+
+ if( boxp->x1 > boxp->x2){
+ f=boxp->x1;
+ boxp->x1=boxp->x2;
+ boxp->x2 = f;
+ }
+ if( boxp->y1 > boxp->y2){
+ f=boxp->y1;
+ boxp->y1=boxp->y2;
+ boxp->y2 = f;
+ }
+ boxp->mat[0]=m1[0]=boxp->x2-boxp->x1;
+ boxp->mat[1]=m1[1]=0.0;
+ boxp->mat[2]=m1[2]=0.0;
+ boxp->mat[3]=m1[3]=0.0;
+ boxp->mat[4]=m1[4]=boxp->y2-boxp->y1;
+ boxp->mat[5]=m1[5]=0.0;
+ boxp->mat[6]=m1[6]=boxp->x1;
+ boxp->mat[7]=m1[7]=boxp->y1;
+ boxp->mat[8]=m1[8]=1.0;
+ switch(orientation){
+ case 0:
+ case 1:
+ break;
+ case 2:
+ boxp->mat[0]=0.0F-m1[0];
+ boxp->mat[6]+=m1[0];
+ break;
+ case 3:
+ boxp->mat[0]=0.0F-m1[0];
+ boxp->mat[4]=0.0F-m1[4];
+ boxp->mat[6]+=m1[0];
+ boxp->mat[7]+=m1[4];
+ break;
+ case 4:
+ boxp->mat[4]=0.0F-m1[4];
+ boxp->mat[7]+=m1[4];
+ break;
+ case 5:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=0.0F-m1[0];
+ boxp->mat[3]=0.0F-m1[4];
+ boxp->mat[4]=0.0F;
+ boxp->mat[6]+=m1[4];
+ boxp->mat[7]+=m1[0];
+ break;
+ case 6:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=0.0F-m1[0];
+ boxp->mat[3]=m1[4];
+ boxp->mat[4]=0.0F;
+ boxp->mat[7]+=m1[0];
+ break;
+ case 7:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=m1[0];
+ boxp->mat[3]=m1[4];
+ boxp->mat[4]=0.0F;
+ break;
+ case 8:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=m1[0];
+ boxp->mat[3]=0.0F-m1[4];
+ boxp->mat[4]=0.0F;
+ boxp->mat[6]+=m1[4];
+ break;
+ }
+
+ return;
+}
+
+void t2p_compose_pdf_page_orient_flip(T2P_BOX* boxp, uint16 orientation){
+
+ float m1[9];
+ float f=0.0;
+
+ if( boxp->x1 > boxp->x2){
+ f=boxp->x1;
+ boxp->x1=boxp->x2;
+ boxp->x2 = f;
+ }
+ if( boxp->y1 > boxp->y2){
+ f=boxp->y1;
+ boxp->y1=boxp->y2;
+ boxp->y2 = f;
+ }
+ boxp->mat[0]=m1[0]=boxp->x2-boxp->x1;
+ boxp->mat[1]=m1[1]=0.0F;
+ boxp->mat[2]=m1[2]=0.0F;
+ boxp->mat[3]=m1[3]=0.0F;
+ boxp->mat[4]=m1[4]=boxp->y2-boxp->y1;
+ boxp->mat[5]=m1[5]=0.0F;
+ boxp->mat[6]=m1[6]=boxp->x1;
+ boxp->mat[7]=m1[7]=boxp->y1;
+ boxp->mat[8]=m1[8]=1.0F;
+ switch(orientation){
+ case 5:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=0.0F-m1[4];
+ boxp->mat[3]=0.0F-m1[0];
+ boxp->mat[4]=0.0F;
+ boxp->mat[6]+=m1[0];
+ boxp->mat[7]+=m1[4];
+ break;
+ case 6:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=0.0F-m1[4];
+ boxp->mat[3]=m1[0];
+ boxp->mat[4]=0.0F;
+ boxp->mat[7]+=m1[4];
+ break;
+ case 7:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=m1[4];
+ boxp->mat[3]=m1[0];
+ boxp->mat[4]=0.0F;
+ break;
+ case 8:
+ boxp->mat[0]=0.0F;
+ boxp->mat[1]=m1[4];
+ boxp->mat[3]=0.0F-m1[0];
+ boxp->mat[4]=0.0F;
+ boxp->mat[6]+=m1[0];
+ break;
+ }
+
+ return;
+}
+
+/*
+ This function writes a PDF Contents stream to output.
+*/
+
+tsize_t t2p_write_pdf_page_content_stream(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ ttile_t i=0;
+ char buffer[512];
+ int buflen=0;
+ T2P_BOX box;
+
+ if(t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount>0){
+ for(i=0;i<t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount; i++){
+ box=t2p->tiff_tiles[t2p->pdf_page].tiles_tiles[i].tile_box;
+ buflen=sprintf(buffer,
+ "q %s %.4f %.4f %.4f %.4f %.4f %.4f cm /Im%d_%ld Do Q\n",
+ t2p->tiff_transferfunctioncount?"/GS1 gs ":"",
+ box.mat[0],
+ box.mat[1],
+ box.mat[3],
+ box.mat[4],
+ box.mat[6],
+ box.mat[7],
+ t2p->pdf_page + 1,
+ (long)(i + 1));
+ written += t2p_write_pdf_stream(buffer, buflen, output);
+ }
+ } else {
+ box=t2p->pdf_imagebox;
+ buflen=sprintf(buffer,
+ "q %s %.4f %.4f %.4f %.4f %.4f %.4f cm /Im%d Do Q\n",
+ t2p->tiff_transferfunctioncount?"/GS1 gs ":"",
+ box.mat[0],
+ box.mat[1],
+ box.mat[3],
+ box.mat[4],
+ box.mat[6],
+ box.mat[7],
+ t2p->pdf_page+1);
+ written += t2p_write_pdf_stream(buffer, buflen, output);
+ }
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject stream dictionary to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_stream_dict(ttile_t tile,
+ T2P* t2p,
+ TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2p_write_pdf_stream_dict(0, t2p->pdf_xrefcount+1, output);
+ written += t2pWriteFile(output,
+ (tdata_t) "/Type /XObject \n/Subtype /Image \n/Name /Im",
+ 42);
+ buflen=sprintf(buffer, "%u", t2p->pdf_page+1);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ if(tile != 0){
+ written += t2pWriteFile(output, (tdata_t) "_", 1);
+ buflen=sprintf(buffer, "%lu", (unsigned long)tile);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ }
+ written += t2pWriteFile(output, (tdata_t) "\n/Width ", 8);
+ _TIFFmemset((tdata_t)buffer, 0x00, 16);
+ if(tile==0){
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->tiff_width);
+ } else {
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile-1)!=0){
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
+ } else {
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "\n/Height ", 9);
+ _TIFFmemset((tdata_t)buffer, 0x00, 16);
+ if(tile==0){
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->tiff_length);
+ } else {
+ if(t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile-1)!=0){
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
+ } else {
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ }
+ }
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "\n/BitsPerComponent ", 19);
+ _TIFFmemset((tdata_t)buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%u", t2p->tiff_bitspersample);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "\n/ColorSpace ", 13);
+ written += t2p_write_pdf_xobject_cs(t2p, output);
+ if (t2p->pdf_image_interpolate)
+ written += t2pWriteFile(output,
+ (tdata_t) "\n/Interpolate true", 18);
+ if( (t2p->pdf_switchdecode != 0)
+#ifdef CCITT_SUPPORT
+ && ! (t2p->pdf_colorspace == T2P_CS_BILEVEL
+ && t2p->pdf_compression == T2P_COMPRESS_G4)
+#endif
+ ){
+ written += t2p_write_pdf_xobject_decode(t2p, output);
+ }
+ written += t2p_write_pdf_xobject_stream_filter(tile, t2p, output);
+
+ return(written);
+}
+
+/*
+ * This function writes a PDF Image XObject Colorspace name to output.
+ */
+
+
+tsize_t t2p_write_pdf_xobject_cs(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[128];
+ int buflen=0;
+
+ float X_W=1.0;
+ float Y_W=1.0;
+ float Z_W=1.0;
+
+ if( (t2p->pdf_colorspace & T2P_CS_ICCBASED) != 0){
+ written += t2p_write_pdf_xobject_icccs(t2p, output);
+ return(written);
+ }
+ if( (t2p->pdf_colorspace & T2P_CS_PALETTE) != 0){
+ written += t2pWriteFile(output, (tdata_t) "[ /Indexed ", 11);
+ t2p->pdf_colorspace ^= T2P_CS_PALETTE;
+ written += t2p_write_pdf_xobject_cs(t2p, output);
+ t2p->pdf_colorspace |= T2P_CS_PALETTE;
+ buflen=sprintf(buffer, "%u", (0x0001 << t2p->tiff_bitspersample)-1 );
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " ", 1);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_palettecs );
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ]\n", 7);
+ return(written);
+ }
+ if(t2p->pdf_colorspace & T2P_CS_BILEVEL){
+ written += t2pWriteFile(output, (tdata_t) "/DeviceGray \n", 13);
+ }
+ if(t2p->pdf_colorspace & T2P_CS_GRAY){
+ if(t2p->pdf_colorspace & T2P_CS_CALGRAY){
+ written += t2p_write_pdf_xobject_calcs(t2p, output);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/DeviceGray \n", 13);
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_RGB){
+ if(t2p->pdf_colorspace & T2P_CS_CALRGB){
+ written += t2p_write_pdf_xobject_calcs(t2p, output);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/DeviceRGB \n", 12);
+ }
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CMYK){
+ written += t2pWriteFile(output, (tdata_t) "/DeviceCMYK \n", 13);
+ }
+ if(t2p->pdf_colorspace & T2P_CS_LAB){
+ written += t2pWriteFile(output, (tdata_t) "[/Lab << \n", 10);
+ written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
+ X_W = t2p->tiff_whitechromaticities[0];
+ Y_W = t2p->tiff_whitechromaticities[1];
+ Z_W = 1.0F - (X_W + Y_W);
+ X_W /= Y_W;
+ Z_W /= Y_W;
+ Y_W = 1.0F;
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f] \n", X_W, Y_W, Z_W);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ X_W = 0.3457F; /* 0.3127F; */ /* D50, commented D65 */
+ Y_W = 0.3585F; /* 0.3290F; */
+ Z_W = 1.0F - (X_W + Y_W);
+ X_W /= Y_W;
+ Z_W /= Y_W;
+ Y_W = 1.0F;
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f] \n", X_W, Y_W, Z_W);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Range ", 7);
+ buflen=sprintf(buffer, "[%d %d %d %d] \n",
+ t2p->pdf_labrange[0],
+ t2p->pdf_labrange[1],
+ t2p->pdf_labrange[2],
+ t2p->pdf_labrange[3]);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) ">>] \n", 5);
+
+ }
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_transfer(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "<< /Type /ExtGState \n/TR ", 25);
+ if(t2p->tiff_transferfunctioncount == 1){
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)(t2p->pdf_xrefcount + 1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "[ ", 2);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)(t2p->pdf_xrefcount + 1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)(t2p->pdf_xrefcount + 2));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)(t2p->pdf_xrefcount + 3));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R ", 5);
+ written += t2pWriteFile(output, (tdata_t) "/Identity ] ", 12);
+ }
+
+ written += t2pWriteFile(output, (tdata_t) " >> \n", 5);
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_transfer_dict(T2P* t2p, TIFF* output, uint16 i){
+
+ tsize_t written=0;
+ char buffer[32];
+ int buflen=0;
+ (void)i; // XXX
+
+ written += t2pWriteFile(output, (tdata_t) "/FunctionType 0 \n", 17);
+ written += t2pWriteFile(output, (tdata_t) "/Domain [0.0 1.0] \n", 19);
+ written += t2pWriteFile(output, (tdata_t) "/Range [0.0 1.0] \n", 18);
+ buflen=sprintf(buffer, "/Size [%u] \n", (1<<t2p->tiff_bitspersample));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/BitsPerSample 16 \n", 19);
+ written += t2p_write_pdf_stream_dict(1<<(t2p->tiff_bitspersample+1), 0, output);
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_transfer_stream(T2P* t2p, TIFF* output, uint16 i){
+
+ tsize_t written=0;
+
+ written += t2p_write_pdf_stream(
+ t2p->tiff_transferfunction[i],
+ (1<<(t2p->tiff_bitspersample+1)),
+ output);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject Colorspace array to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_calcs(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[128];
+ int buflen=0;
+
+ float X_W=0.0;
+ float Y_W=0.0;
+ float Z_W=0.0;
+ float X_R=0.0;
+ float Y_R=0.0;
+ float Z_R=0.0;
+ float X_G=0.0;
+ float Y_G=0.0;
+ float Z_G=0.0;
+ float X_B=0.0;
+ float Y_B=0.0;
+ float Z_B=0.0;
+ float x_w=0.0;
+ float y_w=0.0;
+ float z_w=0.0;
+ float x_r=0.0;
+ float y_r=0.0;
+ float x_g=0.0;
+ float y_g=0.0;
+ float x_b=0.0;
+ float y_b=0.0;
+ float R=1.0;
+ float G=1.0;
+ float B=1.0;
+
+ written += t2pWriteFile(output, (tdata_t) "[", 1);
+ if(t2p->pdf_colorspace & T2P_CS_CALGRAY){
+ written += t2pWriteFile(output, (tdata_t) "/CalGray ", 9);
+ X_W = t2p->tiff_whitechromaticities[0];
+ Y_W = t2p->tiff_whitechromaticities[1];
+ Z_W = 1.0F - (X_W + Y_W);
+ X_W /= Y_W;
+ Z_W /= Y_W;
+ Y_W = 1.0F;
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CALRGB){
+ written += t2pWriteFile(output, (tdata_t) "/CalRGB ", 8);
+ x_w = t2p->tiff_whitechromaticities[0];
+ y_w = t2p->tiff_whitechromaticities[1];
+ x_r = t2p->tiff_primarychromaticities[0];
+ y_r = t2p->tiff_primarychromaticities[1];
+ x_g = t2p->tiff_primarychromaticities[2];
+ y_g = t2p->tiff_primarychromaticities[3];
+ x_b = t2p->tiff_primarychromaticities[4];
+ y_b = t2p->tiff_primarychromaticities[5];
+ z_w = y_w * ((x_g - x_b)*y_r - (x_r-x_b)*y_g + (x_r-x_g)*y_b);
+ Y_R = (y_r/R) * ((x_g-x_b)*y_w - (x_w-x_b)*y_g + (x_w-x_g)*y_b) / z_w;
+ X_R = Y_R * x_r / y_r;
+ Z_R = Y_R * (((1-x_r)/y_r)-1);
+ Y_G = ((0.0F-(y_g))/G) * ((x_r-x_b)*y_w - (x_w-x_b)*y_r + (x_w-x_r)*y_b) / z_w;
+ X_G = Y_G * x_g / y_g;
+ Z_G = Y_G * (((1-x_g)/y_g)-1);
+ Y_B = (y_b/B) * ((x_r-x_g)*y_w - (x_w-x_g)*y_r + (x_w-x_r)*y_g) / z_w;
+ X_B = Y_B * x_b / y_b;
+ Z_B = Y_B * (((1-x_b)/y_b)-1);
+ X_W = (X_R * R) + (X_G * G) + (X_B * B);
+ Y_W = (Y_R * R) + (Y_G * G) + (Y_B * B);
+ Z_W = (Z_R * R) + (Z_G * G) + (Z_B * B);
+ X_W /= Y_W;
+ Z_W /= Y_W;
+ Y_W = 1.0;
+ }
+ written += t2pWriteFile(output, (tdata_t) "<< \n", 4);
+ if(t2p->pdf_colorspace & T2P_CS_CALGRAY){
+ written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f] \n", X_W, Y_W, Z_W);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Gamma 2.2 \n", 12);
+ }
+ if(t2p->pdf_colorspace & T2P_CS_CALRGB){
+ written += t2pWriteFile(output, (tdata_t) "/WhitePoint ", 12);
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f] \n", X_W, Y_W, Z_W);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Matrix ", 8);
+ buflen=sprintf(buffer, "[%.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f %.4f] \n",
+ X_R, Y_R, Z_R,
+ X_G, Y_G, Z_G,
+ X_B, Y_B, Z_B);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Gamma [2.2 2.2 2.2] \n", 22);
+ }
+ written += t2pWriteFile(output, (tdata_t) ">>] \n", 5);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject Colorspace array to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_icccs(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "[/ICCBased ", 11);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_icccs);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " 0 R] \n", 7);
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_xobject_icccs_dict(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ written += t2pWriteFile(output, (tdata_t) "/N ", 3);
+ buflen=sprintf(buffer, "%u \n", t2p->tiff_samplesperpixel);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) "/Alternate ", 11);
+ t2p->pdf_colorspace ^= T2P_CS_ICCBASED;
+ written += t2p_write_pdf_xobject_cs(t2p, output);
+ t2p->pdf_colorspace |= T2P_CS_ICCBASED;
+ written += t2p_write_pdf_stream_dict(t2p->tiff_iccprofilelength, 0, output);
+
+ return(written);
+}
+
+tsize_t t2p_write_pdf_xobject_icccs_stream(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2p_write_pdf_stream(
+ (tdata_t) t2p->tiff_iccprofile,
+ (tsize_t) t2p->tiff_iccprofilelength,
+ output);
+
+ return(written);
+}
+
+/*
+ This function writes a palette stream for an indexed color space to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_palettecs_stream(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+
+ written += t2p_write_pdf_stream(
+ (tdata_t) t2p->pdf_palette,
+ (tsize_t) t2p->pdf_palettesize,
+ output);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject Decode array to output.
+*/
+
+tsize_t t2p_write_pdf_xobject_decode(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ int i=0;
+
+ written += t2pWriteFile(output, (tdata_t) "/Decode [ ", 10);
+ for (i=0;i<t2p->tiff_samplesperpixel;i++){
+ written += t2pWriteFile(output, (tdata_t) "1 0 ", 4);
+ }
+ written += t2pWriteFile(output, (tdata_t) "]\n", 2);
+
+ return(written);
+}
+
+/*
+ This function writes a PDF Image XObject stream filter name and parameters to
+ output.
+*/
+
+tsize_t t2p_write_pdf_xobject_stream_filter(ttile_t tile, T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[16];
+ int buflen=0;
+
+ if(t2p->pdf_compression==T2P_COMPRESS_NONE){
+ return(written);
+ }
+ written += t2pWriteFile(output, (tdata_t) "/Filter ", 8);
+ switch(t2p->pdf_compression){
+#ifdef CCITT_SUPPORT
+ case T2P_COMPRESS_G4:
+ written += t2pWriteFile(output, (tdata_t) "/CCITTFaxDecode ", 16);
+ written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
+ written += t2pWriteFile(output, (tdata_t) "<< /K -1 ", 9);
+ if(tile==0){
+ written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)t2p->tiff_width);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
+ buflen=sprintf(buffer, "%lu",
+ (unsigned long)t2p->tiff_length);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ } else {
+ if(t2p_tile_is_right_edge(t2p->tiff_tiles[t2p->pdf_page], tile-1)==0){
+ written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_tilewidth);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) "/Columns ", 9);
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilewidth);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ }
+ if(t2p_tile_is_bottom_edge(t2p->tiff_tiles[t2p->pdf_page], tile-1)==0){
+ written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_tilelength);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ } else {
+ written += t2pWriteFile(output, (tdata_t) " /Rows ", 7);
+ buflen=sprintf(
+ buffer,
+ "%lu",
+ (unsigned long)t2p->tiff_tiles[t2p->pdf_page].tiles_edgetilelength);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ }
+ }
+ if(t2p->pdf_switchdecode == 0){
+ written += t2pWriteFile(output, (tdata_t) " /BlackIs1 true ", 16);
+ }
+ written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
+ break;
+#endif
+#ifdef JPEG_SUPPORT
+ case T2P_COMPRESS_JPEG:
+ written += t2pWriteFile(output, (tdata_t) "/DCTDecode ", 11);
+
+ if(t2p->tiff_photometric != PHOTOMETRIC_YCBCR) {
+ written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
+ written += t2pWriteFile(output, (tdata_t) "<< /ColorTransform 0 >>\n", 24);
+ }
+ break;
+#endif
+#ifdef ZIP_SUPPORT
+ case T2P_COMPRESS_ZIP:
+ written += t2pWriteFile(output, (tdata_t) "/FlateDecode ", 13);
+ if(t2p->pdf_compressionquality%100){
+ written += t2pWriteFile(output, (tdata_t) "/DecodeParms ", 13);
+ written += t2pWriteFile(output, (tdata_t) "<< /Predictor ", 14);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%u", t2p->pdf_compressionquality%100);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " /Columns ", 10);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen = sprintf(buffer, "%lu",
+ (unsigned long)t2p->tiff_width);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " /Colors ", 9);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%u", t2p->tiff_samplesperpixel);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " /BitsPerComponent ", 19);
+ _TIFFmemset(buffer, 0x00, 16);
+ buflen=sprintf(buffer, "%u", t2p->tiff_bitspersample);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) ">>\n", 3);
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return(written);
+}
+
+/*
+ This function writes a PDF xref table to output.
+*/
+
+tsize_t t2p_write_pdf_xreftable(T2P* t2p, TIFF* output){
+
+ tsize_t written=0;
+ char buffer[21];
+ int buflen=0;
+ uint32 i=0;
+
+ written += t2pWriteFile(output, (tdata_t) "xref\n0 ", 7);
+ buflen=sprintf(buffer, "%lu", (unsigned long)(t2p->pdf_xrefcount + 1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ written += t2pWriteFile(output, (tdata_t) " \n0000000000 65535 f \n", 22);
+ for (i=0;i<t2p->pdf_xrefcount;i++){
+ sprintf(buffer, "%.10lu 00000 n \n",
+ (unsigned long)t2p->pdf_xrefoffsets[i]);
+ written += t2pWriteFile(output, (tdata_t) buffer, 20);
+ }
+
+ return(written);
+}
+
+/*
+ * This function writes a PDF trailer to output.
+ */
+
+tsize_t t2p_write_pdf_trailer(T2P* t2p, TIFF* output)
+{
+
+ tsize_t written = 0;
+ char buffer[32];
+ int buflen = 0;
+ char fileidbuf[16];
+ int i = 0;
+
+ ((int*)fileidbuf)[0] = rand();
+ ((int*)fileidbuf)[1] = rand();
+ ((int*)fileidbuf)[2] = rand();
+ ((int*)fileidbuf)[3] = rand();
+ t2p->pdf_fileid = (unsigned char*)_TIFFmalloc(33);
+ if(t2p->pdf_fileid == NULL) {
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_write_pdf_trailer",
+ 33 );
+ t2p->t2p_error = T2P_ERR_ERROR;
+ return(0);
+ }
+ _TIFFmemset(t2p->pdf_fileid, 0x00, 33);
+ for (i = 0; i < 16; i++) {
+ sprintf((char *)t2p->pdf_fileid + 2 * i,
+ "%.2hhX", fileidbuf[i]);
+ }
+ written += t2pWriteFile(output, (tdata_t) "trailer\n<<\n/Size ", 17);
+ buflen = sprintf(buffer, "%lu", (unsigned long)(t2p->pdf_xrefcount+1));
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ _TIFFmemset(buffer, 0x00, 32);
+ written += t2pWriteFile(output, (tdata_t) "\n/Root ", 7);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_catalog);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ _TIFFmemset(buffer, 0x00, 32);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n/Info ", 12);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_info);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ _TIFFmemset(buffer, 0x00, 32);
+ written += t2pWriteFile(output, (tdata_t) " 0 R \n/ID[<", 11);
+ written += t2pWriteFile(output, (tdata_t) t2p->pdf_fileid, 32);
+ written += t2pWriteFile(output, (tdata_t) "><", 2);
+ written += t2pWriteFile(output, (tdata_t) t2p->pdf_fileid, 32);
+ written += t2pWriteFile(output, (tdata_t) ">]\n>>\nstartxref\n", 16);
+ buflen=sprintf(buffer, "%lu", (unsigned long)t2p->pdf_startxref);
+ written += t2pWriteFile(output, (tdata_t) buffer, buflen);
+ _TIFFmemset(buffer, 0x00, 32);
+ written += t2pWriteFile(output, (tdata_t) "\n%%EOF\n", 7);
+
+ return(written);
+}
+
+/*
+
+ This function writes a PDF to a file given a pointer to a TIFF.
+
+ The idea with using a TIFF* as output for a PDF file is that the file
+ can be created with TIFFClientOpen for memory-mapped use within the TIFF
+ library, and TIFFWriteEncodedStrip can be used to write compressed data to
+ the output. The output is not actually a TIFF file, it is a PDF file.
+
+ This function uses only t2pWriteFile and TIFFWriteEncodedStrip to write to
+ the output TIFF file. When libtiff would otherwise be writing data to the
+ output file, the write procedure of the TIFF structure is replaced with an
+ empty implementation.
+
+ The first argument to the function is an initialized and validated T2P
+ context struct pointer.
+
+ The second argument to the function is the TIFF* that is the input that has
+ been opened for reading and no other functions have been called upon it.
+
+ The third argument to the function is the TIFF* that is the output that has
+ been opened for writing. It has to be opened so that it hasn't written any
+ data to the output. If the output is seekable then it's OK to seek to the
+ beginning of the file. The function only writes to the output PDF and does
+ not seek. See the example usage in the main() function.
+
+ TIFF* output = TIFFOpen("output.pdf", "w");
+ assert(output != NULL);
+
+ if(output->tif_seekproc != NULL){
+ t2pSeekFile(output, (toff_t) 0, SEEK_SET);
+ }
+
+ This function returns the file size of the output PDF file. On error it
+ returns zero and the t2p->t2p_error variable is set to T2P_ERR_ERROR.
+
+ After this function completes, call t2p_free on t2p, TIFFClose on input,
+ and TIFFClose on output.
+*/
+
+tsize_t t2p_write_pdf(T2P* t2p, TIFF* input, TIFF* output){
+
+ tsize_t written=0;
+ ttile_t i2=0;
+ tsize_t streamlen=0;
+ uint16 i=0;
+
+ t2p_read_tiff_init(t2p, input);
+ if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
+ t2p->pdf_xrefoffsets= (uint32*) _TIFFmalloc(t2p->pdf_xrefcount * sizeof(uint32) );
+ if(t2p->pdf_xrefoffsets==NULL){
+ TIFFError(
+ TIFF2PDF_MODULE,
+ "Can't allocate %u bytes of memory for t2p_write_pdf",
+ t2p->pdf_xrefcount * sizeof(uint32) );
+ return(written);
+ }
+ t2p->pdf_xrefcount=0;
+ t2p->pdf_catalog=1;
+ t2p->pdf_info=2;
+ t2p->pdf_pages=3;
+ written += t2p_write_pdf_header(t2p, output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_catalog=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_catalog(t2p, output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_info=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_info(t2p, input, output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_pages=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_pages(t2p, output);
+ written += t2p_write_pdf_obj_end(output);
+ for(t2p->pdf_page=0;t2p->pdf_page<t2p->tiff_pagecount;t2p->pdf_page++){
+ t2p_read_tiff_data(t2p, input);
+ if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_page(t2p->pdf_xrefcount, t2p, output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_stream_dict(0, t2p->pdf_xrefcount+1, output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ written += t2p_write_pdf_page_content_stream(t2p, output);
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_length(streamlen, output);
+ written += t2p_write_pdf_obj_end(output);
+ if(t2p->tiff_transferfunctioncount != 0){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_transfer(t2p, output);
+ written += t2p_write_pdf_obj_end(output);
+ for(i=0; i < t2p->tiff_transferfunctioncount; i++){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_transfer_dict(t2p, output, i);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ written += t2p_write_pdf_transfer_stream(t2p, output, i);
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ }
+ if( (t2p->pdf_colorspace & T2P_CS_PALETTE) != 0){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_palettecs=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_stream_dict(t2p->pdf_palettesize, 0, output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ written += t2p_write_pdf_xobject_palettecs_stream(t2p, output);
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ if( (t2p->pdf_colorspace & T2P_CS_ICCBASED) != 0){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ t2p->pdf_icccs=t2p->pdf_xrefcount;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_xobject_icccs_dict(t2p, output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ written += t2p_write_pdf_xobject_icccs_stream(t2p, output);
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ if(t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount !=0){
+ for(i2=0;i2<t2p->tiff_tiles[t2p->pdf_page].tiles_tilecount;i2++){
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_xobject_stream_dict(
+ i2+1,
+ t2p,
+ output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ t2p_read_tiff_size_tile(t2p, input, i2);
+ written += t2p_readwrite_pdf_image_tile(t2p, input, output, i2);
+ t2p_write_advance_directory(t2p, output);
+ if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_length(streamlen, output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ } else {
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_dict_start(output);
+ written += t2p_write_pdf_xobject_stream_dict(
+ 0,
+ t2p,
+ output);
+ written += t2p_write_pdf_stream_dict_end(output);
+ written += t2p_write_pdf_stream_start(output);
+ streamlen=written;
+ t2p_read_tiff_size(t2p, input);
+ written += t2p_readwrite_pdf_image(t2p, input, output);
+ t2p_write_advance_directory(t2p, output);
+ if(t2p->t2p_error!=T2P_ERR_OK){return(0);}
+ streamlen=written-streamlen;
+ written += t2p_write_pdf_stream_end(output);
+ written += t2p_write_pdf_obj_end(output);
+ t2p->pdf_xrefoffsets[t2p->pdf_xrefcount++]=written;
+ written += t2p_write_pdf_obj_start(t2p->pdf_xrefcount, output);
+ written += t2p_write_pdf_stream_length(streamlen, output);
+ written += t2p_write_pdf_obj_end(output);
+ }
+ }
+ t2p->pdf_startxref = written;
+ written += t2p_write_pdf_xreftable(t2p, output);
+ written += t2p_write_pdf_trailer(t2p, output);
+ t2p_disable(output);
+
+ return(written);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiff2ps.c b/tiff/tools/tiff2ps.c
new file mode 100644
index 0000000..e16aa7f
--- /dev/null
+++ b/tiff/tools/tiff2ps.c
@@ -0,0 +1,2370 @@
+/* $Id: tiff2ps.c,v 1.35.2.4 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h> /* for atof */
+#include <math.h>
+#include <time.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+/*
+ * Revision history
+ *
+ * 2005-June-3
+ * Richard Nolde: Added support for rotations of 90, 180, 270
+ * and auto using -r <90|180|270|auto>. Auto picks the best
+ * fit for the image on the specified paper size (eg portrait
+ * or landscape) if -h or -w is specified. Rotation is in
+ * degrees counterclockwise since that is how Postscript does
+ * it. Auto rotates 90 degrees ccw to produce landscape.
+ *
+ * Added maxPageWidth option using -W flag. MaxPageHeight and
+ * MaxPageWidth are mutually exclusive since the aspect ratio
+ * cannot be maintained if you set both.
+ * Rewrote PlaceImage to allow maxPageHeight and maxPageWidth
+ * options to work with values smaller or larger than the
+ * physical paper size and still preserve the aspect ratio.
+ * This is accomplished by creating multiple pages across
+ * as well as down if need be.
+ *
+ * 2001-Mar-21
+ * I (Bruce A. Mallett) added this revision history comment ;)
+ *
+ * Fixed PS_Lvl2page() code which outputs non-ASCII85 raw
+ * data. Moved test for when to output a line break to
+ * *after* the output of a character. This just serves
+ * to fix an eye-nuisance where the first line of raw
+ * data was one character shorter than subsequent lines.
+ *
+ * Added an experimental ASCII85 encoder which can be used
+ * only when there is a single buffer of bytes to be encoded.
+ * This version is much faster at encoding a straight-line
+ * buffer of data because it can avoid alot of the loop
+ * overhead of the byte-by-bye version. To use this version
+ * you need to define EXP_ASCII85ENCODER (experimental ...).
+ *
+ * Added bug fix given by Michael Schmidt to PS_Lvl2page()
+ * in which an end-of-data marker ('>') was not being output
+ * when producing non-ASCII85 encoded PostScript Level 2
+ * data.
+ *
+ * Fixed PS_Lvl2colorspace() so that it no longer assumes that
+ * a TIFF having more than 2 planes is a CMYK. This routine
+ * no longer looks at the samples per pixel but instead looks
+ * at the "photometric" value. This change allows support of
+ * CMYK TIFFs.
+ *
+ * Modified the PostScript L2 imaging loop so as to test if
+ * the input stream is still open before attempting to do a
+ * flushfile on it. This was done because some RIPs close
+ * the stream after doing the image operation.
+ *
+ * Got rid of the realloc() being done inside a loop in the
+ * PSRawDataBW() routine. The code now walks through the
+ * byte-size array outside the loop to determine the largest
+ * size memory block that will be needed.
+ *
+ * Added "-m" switch to ask tiff2ps to, where possible, use the
+ * "imagemask" operator instead of the "image" operator.
+ *
+ * Added the "-i #" switch to allow interpolation to be disabled.
+ *
+ * Unrolled a loop or two to improve performance.
+ */
+
+/*
+ * Define EXP_ASCII85ENCODER if you want to use an experimental
+ * version of the ASCII85 encoding routine. The advantage of
+ * using this routine is that tiff2ps will convert to ASCII85
+ * encoding at between 3 and 4 times the speed as compared to
+ * using the old (non-experimental) encoder. The disadvantage
+ * is that you will be using a new (and unproven) encoding
+ * routine. So user beware, you have been warned!
+ */
+
+#define EXP_ASCII85ENCODER
+
+/*
+ * NB: this code assumes uint32 works with printf's %l[ud].
+ */
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define HORIZONTAL 1
+#define VERTICAL 2
+
+int ascii85 = FALSE; /* use ASCII85 encoding */
+int interpolate = TRUE; /* interpolate level2 image */
+int level2 = FALSE; /* generate PostScript level 2 */
+int level3 = FALSE; /* generate PostScript level 3 */
+int printAll = FALSE; /* print all images in file */
+int generateEPSF = TRUE; /* generate Encapsulated PostScript */
+int PSduplex = FALSE; /* enable duplex printing */
+int PStumble = FALSE; /* enable top edge binding */
+int PSavoiddeadzone = TRUE; /* enable avoiding printer deadzone */
+double maxPageHeight = 0; /* maximum height to select from image and print per page */
+double maxPageWidth = 0; /* maximum width to select from image and print per page */
+double splitOverlap = 0; /* amount for split pages to overlag */
+int rotate = FALSE; /* rotate image by angle 90, 180, 270 degrees */
+int rotation = 0; /* optional value for rotation angle */
+char *filename; /* input filename */
+int useImagemask = FALSE; /* Use imagemask instead of image operator */
+uint16 res_unit = 0; /* Resolution units: 2 - inches, 3 - cm */
+
+/*
+ * ASCII85 Encoding Support.
+ */
+unsigned char ascii85buf[10];
+int ascii85count;
+int ascii85breaklen;
+
+int TIFF2PS(FILE*, TIFF*, double, double, double, double, int);
+void PSpage(FILE*, TIFF*, uint32, uint32);
+void PSColorContigPreamble(FILE*, uint32, uint32, int);
+void PSColorSeparatePreamble(FILE*, uint32, uint32, int);
+void PSDataColorContig(FILE*, TIFF*, uint32, uint32, int);
+void PSDataColorSeparate(FILE*, TIFF*, uint32, uint32, int);
+void PSDataPalette(FILE*, TIFF*, uint32, uint32);
+void PSDataBW(FILE*, TIFF*, uint32, uint32);
+void PSRawDataBW(FILE*, TIFF*, uint32, uint32);
+void Ascii85Init(void);
+void Ascii85Put(unsigned char code, FILE* fd);
+void Ascii85Flush(FILE* fd);
+void PSHead(FILE*, TIFF*, uint32, uint32, double, double, double, double);
+void PSTail(FILE*, int);
+
+#if defined( EXP_ASCII85ENCODER)
+int Ascii85EncodeBlock( uint8 * ascii85_p, unsigned f_eod, const uint8 * raw_p, int raw_l );
+#endif
+
+static void usage(int);
+
+int
+main(int argc, char* argv[])
+{
+ int dirnum = -1, c, np = 0;
+ int centered = 0;
+ double bottommargin = 0;
+ double leftmargin = 0;
+ double pageWidth = 0;
+ double pageHeight = 0;
+ uint32 diroff = 0;
+ extern char *optarg;
+ extern int optind;
+ FILE* output = stdout;
+
+ while ((c = getopt(argc, argv, "b:d:h:H:W:L:i:w:l:o:O:r:acelmxyzps1238DT")) != -1)
+ switch (c) {
+ case 'b':
+ bottommargin = atof(optarg);
+ break;
+ case 'c':
+ centered = 1;
+ break;
+ case 'd':
+ dirnum = atoi(optarg);
+ break;
+ case 'D':
+ PSduplex = TRUE;
+ break;
+ case 'i':
+ interpolate = atoi(optarg) ? TRUE:FALSE;
+ break;
+ case 'T':
+ PStumble = TRUE;
+ break;
+ case 'e':
+ PSavoiddeadzone = FALSE;
+ generateEPSF = TRUE;
+ break;
+ case 'h':
+ pageHeight = atof(optarg);
+ break;
+ case 'H':
+ maxPageHeight = atof(optarg);
+ if (pageHeight==0) pageHeight = maxPageHeight;
+ break;
+ case 'W':
+ maxPageWidth = atof(optarg);
+ if (pageWidth==0) pageWidth = maxPageWidth;
+ break;
+ case 'L':
+ splitOverlap = atof(optarg);
+ break;
+ case 'm':
+ useImagemask = TRUE;
+ break;
+ case 'o':
+ diroff = (uint32) strtoul(optarg, NULL, 0);
+ break;
+ case 'O': /* XXX too bad -o is already taken */
+ output = fopen(optarg, "w");
+ if (output == NULL) {
+ fprintf(stderr,
+ "%s: %s: Cannot open output file.\n",
+ argv[0], optarg);
+ exit(-2);
+ }
+ break;
+ case 'l':
+ leftmargin = atof(optarg);
+ break;
+ case 'a':
+ printAll = TRUE;
+ /* fall thru... */
+ case 'p':
+ generateEPSF = FALSE;
+ break;
+ case 'r':
+ rotate = TRUE;
+ if (strcmp (optarg, "auto") == 0)
+ rotation = 0;
+ else
+ rotation = atoi(optarg);
+ switch (rotation)
+ {
+ case 0:
+ case 90:
+ case 180:
+ case 270:
+ break;
+ default:
+ fprintf (stderr, "Rotation angle must be 90, 180, 270 (degrees ccw) or auto\n");
+ exit (-2);
+ }
+ break;
+ case 's':
+ printAll = FALSE;
+ break;
+ case 'w':
+ pageWidth = atof(optarg);
+ break;
+ case 'z':
+ PSavoiddeadzone = FALSE;
+ break;
+ case '1':
+ level2 = FALSE;
+ level3 = FALSE;
+ ascii85 = FALSE;
+ break;
+ case '2':
+ level2 = TRUE;
+ ascii85 = TRUE; /* default to yes */
+ break;
+ case '3':
+ level3 = TRUE;
+ ascii85 = TRUE; /* default to yes */
+ break;
+ case '8':
+ ascii85 = FALSE;
+ break;
+ case 'x':
+ res_unit = RESUNIT_CENTIMETER;
+ break;
+ case 'y':
+ res_unit = RESUNIT_INCH;
+ break;
+ case '?':
+ usage(-1);
+ }
+ for (; argc - optind > 0; optind++) {
+ TIFF* tif = TIFFOpen(filename = argv[optind], "r");
+ if (tif != NULL) {
+ if (dirnum != -1
+ && !TIFFSetDirectory(tif, (tdir_t)dirnum))
+ return (-1);
+ else if (diroff != 0 &&
+ !TIFFSetSubDirectory(tif, diroff))
+ return (-1);
+ np = TIFF2PS(output, tif, pageWidth, pageHeight,
+ leftmargin, bottommargin, centered);
+ TIFFClose(tif);
+ }
+ }
+ if (np)
+ PSTail(output, np);
+ else
+ usage(-1);
+ if (output != stdout)
+ fclose(output);
+ return (0);
+}
+
+static uint16 samplesperpixel;
+static uint16 bitspersample;
+static uint16 planarconfiguration;
+static uint16 photometric;
+static uint16 compression;
+static uint16 extrasamples;
+static int alpha;
+
+static int
+checkImage(TIFF* tif)
+{
+ switch (photometric) {
+ case PHOTOMETRIC_YCBCR:
+ if ((compression == COMPRESSION_JPEG || compression == COMPRESSION_OJPEG)
+ && planarconfiguration == PLANARCONFIG_CONTIG) {
+ /* can rely on libjpeg to convert to RGB */
+ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE,
+ JPEGCOLORMODE_RGB);
+ photometric = PHOTOMETRIC_RGB;
+ } else {
+ if (level2 || level3)
+ break;
+ TIFFError(filename, "Can not handle image with %s",
+ "PhotometricInterpretation=YCbCr");
+ return (0);
+ }
+ /* fall thru... */
+ case PHOTOMETRIC_RGB:
+ if (alpha && bitspersample != 8) {
+ TIFFError(filename,
+ "Can not handle %d-bit/sample RGB image with alpha",
+ bitspersample);
+ return (0);
+ }
+ /* fall thru... */
+ case PHOTOMETRIC_SEPARATED:
+ case PHOTOMETRIC_PALETTE:
+ case PHOTOMETRIC_MINISBLACK:
+ case PHOTOMETRIC_MINISWHITE:
+ break;
+ case PHOTOMETRIC_LOGL:
+ case PHOTOMETRIC_LOGLUV:
+ if (compression != COMPRESSION_SGILOG &&
+ compression != COMPRESSION_SGILOG24) {
+ TIFFError(filename,
+ "Can not handle %s data with compression other than SGILog",
+ (photometric == PHOTOMETRIC_LOGL) ?
+ "LogL" : "LogLuv"
+ );
+ return (0);
+ }
+ /* rely on library to convert to RGB/greyscale */
+ TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT);
+ photometric = (photometric == PHOTOMETRIC_LOGL) ?
+ PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB;
+ bitspersample = 8;
+ break;
+ case PHOTOMETRIC_CIELAB:
+ /* fall thru... */
+ default:
+ TIFFError(filename,
+ "Can not handle image with PhotometricInterpretation=%d",
+ photometric);
+ return (0);
+ }
+ switch (bitspersample) {
+ case 1: case 2:
+ case 4: case 8:
+ case 16:
+ break;
+ default:
+ TIFFError(filename, "Can not handle %d-bit/sample image",
+ bitspersample);
+ return (0);
+ }
+ if (planarconfiguration == PLANARCONFIG_SEPARATE && extrasamples > 0)
+ TIFFWarning(filename, "Ignoring extra samples");
+ return (1);
+}
+
+#define PS_UNIT_SIZE 72.0F
+#define PSUNITS(npix,res) ((npix) * (PS_UNIT_SIZE / (res)))
+
+static char RGBcolorimage[] = "\
+/bwproc {\n\
+ rgbproc\n\
+ dup length 3 idiv string 0 3 0\n\
+ 5 -1 roll {\n\
+ add 2 1 roll 1 sub dup 0 eq {\n\
+ pop 3 idiv\n\
+ 3 -1 roll\n\
+ dup 4 -1 roll\n\
+ dup 3 1 roll\n\
+ 5 -1 roll put\n\
+ 1 add 3 0\n\
+ } { 2 1 roll } ifelse\n\
+ } forall\n\
+ pop pop pop\n\
+} def\n\
+/colorimage where {pop} {\n\
+ /colorimage {pop pop /rgbproc exch def {bwproc} image} bind def\n\
+} ifelse\n\
+";
+
+/*
+ * Adobe Photoshop requires a comment line of the form:
+ *
+ * %ImageData: <cols> <rows> <depth> <main channels> <pad channels>
+ * <block size> <1 for binary|2 for hex> "data start"
+ *
+ * It is claimed to be part of some future revision of the EPS spec.
+ */
+static void
+PhotoshopBanner(FILE* fd, uint32 w, uint32 h, int bs, int nc, char* startline)
+{
+ fprintf(fd, "%%ImageData: %ld %ld %d %d 0 %d 2 \"",
+ (long) w, (long) h, bitspersample, nc, bs);
+ fprintf(fd, startline, nc);
+ fprintf(fd, "\"\n");
+}
+
+/*
+ * pw : image width in pixels
+ * ph : image height in pixels
+ * pprw : image width in PS units (72 dpi)
+ * pprh : image height in PS units (72 dpi)
+ */
+static void
+setupPageState(TIFF* tif, uint32* pw, uint32* ph, double* pprw, double* pprh)
+{
+ float xres = 0.0F, yres = 0.0F;
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, pw);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, ph);
+ if (res_unit == 0)
+ TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &res_unit);
+ /*
+ * Calculate printable area.
+ */
+ if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres)
+ || fabs(xres) < 0.0000001)
+ xres = PS_UNIT_SIZE;
+ if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres)
+ || fabs(yres) < 0.0000001)
+ yres = PS_UNIT_SIZE;
+ switch (res_unit) {
+ case RESUNIT_CENTIMETER:
+ xres *= 2.54F, yres *= 2.54F;
+ break;
+ case RESUNIT_INCH:
+ break;
+ case RESUNIT_NONE:
+ default:
+ /*
+ * check that the resolution is not inches before scaling it
+ */
+ if (xres != PS_UNIT_SIZE || yres != PS_UNIT_SIZE)
+ xres *= PS_UNIT_SIZE, yres *= PS_UNIT_SIZE;
+ break;
+ }
+ *pprh = PSUNITS(*ph, yres);
+ *pprw = PSUNITS(*pw, xres);
+}
+
+static int
+isCCITTCompression(TIFF* tif)
+{
+ uint16 compress;
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
+ return (compress == COMPRESSION_CCITTFAX3 ||
+ compress == COMPRESSION_CCITTFAX4 ||
+ compress == COMPRESSION_CCITTRLE ||
+ compress == COMPRESSION_CCITTRLEW);
+}
+
+static tsize_t tf_bytesperrow;
+static tsize_t ps_bytesperrow;
+static tsize_t tf_rowsperstrip;
+static tsize_t tf_numberstrips;
+static char *hex = "0123456789abcdef";
+
+/*
+ * imagewidth & imageheight are 1/72 inches
+ * pagewidth & pageheight are inches
+ */
+int
+PlaceImage(TIFF *tif, FILE *fp, int *npages, uint32 w, uint32 h,
+ double pagewidth, double pageheight,
+ double imagewidth, double imageheight,
+ int splitpage, double lm, double bm, int cnt)
+{
+ int i = 0;
+ int ximages = 0;
+ int splitaxis = 0;
+ double xtran = 0;
+ double ytran = 0;
+ double xscale = 1;
+ double yscale = 1;
+ double left_margin = 0;
+ double bottom_margin = 0;
+ double left_offset = lm * PS_UNIT_SIZE;
+ double bottom_offset = bm * PS_UNIT_SIZE;
+ double splitwidth = 0;
+ double splitheight = 0;
+ double subimageheight = 0;
+ double subimagewidth = 0;
+ double overlap = 0;
+ double overlapspace = 0;
+
+ pagewidth *= PS_UNIT_SIZE;
+ pageheight *= PS_UNIT_SIZE;
+
+ splitheight = maxPageHeight * PS_UNIT_SIZE;
+ splitwidth = maxPageWidth * PS_UNIT_SIZE;
+ overlap = splitOverlap * PS_UNIT_SIZE;
+ /* These have to be mutually exclusive to maintain the aspect ratio */
+ if (splitheight != 0)
+ splitaxis = VERTICAL;
+ else {
+ if (splitwidth != 0)
+ splitaxis = HORIZONTAL;
+ else {
+ fprintf (stderr, "You must specify either a maximum page height or width\n");
+ return (0);
+ }
+ }
+
+ if (splitaxis == VERTICAL) {
+ if (imageheight <= splitheight) {
+ /* Simple case, no splitting or scaling for image height */
+ yscale = imageheight;
+ ytran = pageheight - imageheight;
+ } else { /* imageheight > splitheight */
+ subimageheight = imageheight - ((splitheight - overlap) * splitpage);
+
+ yscale = imageheight * (pageheight / splitheight);
+ ytran = pageheight - subimageheight * (pageheight / splitheight);
+
+ if (subimageheight > splitheight) {
+ splitpage++;
+ } else {
+ splitpage = 0;
+ }
+ }
+ bottom_offset += ytran / (cnt?2:1);
+ left_margin = left_offset / (cnt ? 2 : 1);
+ /*
+ * WIDTH: We can't rescale height based on width so we need to make multiple
+ * pages from each horizontal segment if the image is wider than pagewidth
+ */
+
+ ximages = ceil (imagewidth / pagewidth);
+ overlapspace = (ximages - 1) * overlap;
+ if (((imagewidth + overlapspace) * (pageheight / splitheight)) > (ximages * pagewidth)) {
+ ximages++;
+ overlapspace += overlap;
+ }
+ xscale = (imagewidth + overlapspace) * (pageheight / splitheight);
+ if (imagewidth <= pagewidth) {
+ left_offset = left_margin;
+ bottom_offset = bottom_margin;
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+ } else {
+ for (i = 0; i < ximages; i++) {
+ xtran = i * (pagewidth - ((i > 0) ? overlap : 0));
+ left_offset = -xtran + left_margin;
+
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+
+ if ( i < (ximages - 1)) {
+ PSpage(fp, tif, w, h);
+ fprintf(fp, "end\n");
+ fprintf(fp, "grestore\n");
+ fprintf(fp, "showpage\n");
+ (*npages)++;
+ fprintf(fp, "%%%%Page: %d %d\n", (*npages), (*npages));
+ fprintf(fp, "gsave\n");
+ fprintf(fp, "100 dict begin\n");
+ }
+ }
+ }
+ } else { /* splitaxis is HORIZONTAL */
+ ximages = ceil (imagewidth / splitwidth);
+ overlapspace = (ximages - 1) * overlap;
+ if (((imagewidth + overlapspace) * (pagewidth / splitwidth)) > (ximages * pagewidth)) {
+ ximages++;
+ overlapspace += overlap;
+ }
+ if (ximages == 1) {
+ /* Simple case, no splitting or scaling for image width */
+ xscale = imagewidth;
+ xtran = 0;
+ splitpage = 0;
+ } else {
+ subimagewidth = imagewidth - ((splitwidth - overlap) * splitpage);
+
+ xscale = imagewidth * (pagewidth / splitwidth);
+ xtran = imagewidth - (subimagewidth * (pagewidth / splitwidth));
+
+ splitheight = pageheight;
+ subimageheight = imageheight - ((splitheight - overlap) * splitpage);
+ yscale = (imageheight + overlapspace);
+ ytran = pageheight - subimageheight + (overlapspace * (pagewidth / splitwidth));
+
+ if (subimageheight > splitheight) {
+ splitpage++;
+ } else {
+ splitpage = 0;
+ }
+ }
+ bottom_margin = bottom_offset / (cnt ? 2 : 1);
+ bottom_offset = bottom_margin + ytran;
+ left_margin = left_offset / (cnt ? 2 : 1);
+ if (imagewidth <= pagewidth) {
+ left_offset = left_margin;
+ bottom_offset = bottom_margin;
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+ } else {
+ for (i = 0; i < ximages; i++) {
+ xtran = i * (pagewidth - ((i > 0) ? overlap : 0));
+ left_offset = left_margin - xtran;
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+ if ( i < (ximages - 1)) {
+ PSpage(fp, tif, w, h);
+ fprintf(fp, "end\n");
+ fprintf(fp, "grestore\n");
+ fprintf(fp, "showpage\n");
+ (*npages)++;
+ fprintf(fp, "%%%%Page: %d %d\n", (*npages), (*npages));
+ fprintf(fp, "gsave\n");
+ fprintf(fp, "100 dict begin\n");
+ }
+ }
+ }
+ }
+
+ if (rotate)
+ {
+ if (rotation == 180 )
+ {
+ fprintf(fp, "%f %f translate\n", left_offset, bottom_offset);
+ fprintf(fp, "%f %f scale\n", xscale, yscale);
+ }
+ else
+ {
+ fprintf(fp, "%f %f translate\n", bottom_offset, left_offset);
+ fprintf(fp, "%f %f scale\n", yscale, xscale);
+ }
+ fprintf (fp, "1 1 translate %d rotate\n", rotation);
+ }
+
+ return splitpage;
+}
+
+/* returns the sequence number of the page processed */
+int
+TIFF2PS(FILE* fd, TIFF* tif,
+ double pw, double ph, double lm, double bm, int cnt)
+{
+ uint32 w = 0, h = 0;
+ float ox, oy;
+ double maxsource, maxtarget; /* Used for auto rotations */
+ double hcenter, vcenter; /* Used for centering */
+ double prw, prh; /* Original Image width and height in Postscript points */
+ double psw, psh; /* Scaled image width and height in Postscript points */
+ double xscale = 1.0, yscale = 1.0, scale = 1.0;
+ double left_offset = lm * PS_UNIT_SIZE;
+ double bottom_offset = bm * PS_UNIT_SIZE;
+ uint32 subfiletype;
+ uint16* sampleinfo;
+ static int npages = 0;
+ int split;
+
+ if (!TIFFGetField(tif, TIFFTAG_XPOSITION, &ox))
+ ox = 0;
+ if (!TIFFGetField(tif, TIFFTAG_YPOSITION, &oy))
+ oy = 0;
+ do {
+ tf_numberstrips = TIFFNumberOfStrips(tif);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP,
+ &tf_rowsperstrip);
+ setupPageState(tif, &w, &h, &prw, &prh);
+ if (pw != 0) {
+ psw = pw * PS_UNIT_SIZE;
+ if (res_unit == RESUNIT_CENTIMETER)
+ psw *= 2.54F;
+ }
+ else
+ psw = prw;
+
+ if (ph != 0) {
+ psh = ph * PS_UNIT_SIZE;
+ if (res_unit == RESUNIT_CENTIMETER)
+ psh *= 2.54F;
+ }
+ else
+ psh = prh;
+
+ /* auto rotate for best fit */
+ if (rotate && rotation == 0) {
+ maxsource = (prw >= prh) ? prw : prh;
+ maxtarget = (psw >= psh) ? psw : psh;
+ if (((maxsource == prw) && (maxtarget != psw)) ||
+ ((maxsource == prh) && (maxtarget != psh))) {
+ rotation = 90;
+ }
+ }
+
+ /* scaling depends on rotation and new page size */
+ switch (rotation) {
+ case 0:
+ case 180:
+ xscale = (psw - left_offset)/prw;
+ yscale = (psh - bottom_offset)/prh;
+ if (!npages)
+ PSHead(fd, tif, w, h, psw, psh, ox, oy);
+ break;
+ case 90:
+ case 270:
+ xscale = (psw - bottom_offset) /prh;
+ yscale = (psh - left_offset) /prw;
+ if (!npages)
+ PSHead(fd, tif, w, h, psh, psw, oy, ox);
+ break;
+ }
+ TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE,
+ &bitspersample);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL,
+ &samplesperpixel);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG,
+ &planarconfiguration);
+ TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
+ &extrasamples, &sampleinfo);
+ alpha = (extrasamples == 1 &&
+ sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA);
+ if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) {
+ switch (samplesperpixel - extrasamples) {
+ case 1:
+ if (isCCITTCompression(tif))
+ photometric = PHOTOMETRIC_MINISWHITE;
+ else
+ photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case 3:
+ photometric = PHOTOMETRIC_RGB;
+ break;
+ case 4:
+ photometric = PHOTOMETRIC_SEPARATED;
+ break;
+ }
+ }
+ if (checkImage(tif)) {
+ tf_bytesperrow = TIFFScanlineSize(tif);
+ npages++;
+ fprintf(fd, "%%%%Page: %d %d\n", npages, npages);
+ if (!generateEPSF && ( level2 || level3 )) {
+ fprintf(fd,
+ "1 dict begin /PageSize [ %f %f ] def currentdict end setpagedevice\n",
+ psw, psh);
+ fputs(
+ "<<\n /Policies <<\n /PageSize 3\n >>\n>> setpagedevice\n",
+ fd);
+ }
+ fprintf(fd, "gsave\n");
+ fprintf(fd, "100 dict begin\n");
+ /* N.B. Setting maxPageHeight also sets ph if not set explicitly */
+ if (pw != 0 || ph != 0) {
+ if (maxPageHeight || maxPageWidth) { /* used -H or -W options */
+ split = PlaceImage(tif,fd,&npages,w,h,pw,ph,prw,prh,
+ 0,lm,bm,cnt);
+ while( split ) {
+ PSpage(fd, tif, w, h);
+ fprintf(fd, "end\n");
+ fprintf(fd, "grestore\n");
+ fprintf(fd, "showpage\n");
+ npages++;
+ fprintf(fd, "%%%%Page: %d %d\n",
+ npages, npages);
+ fprintf(fd, "gsave\n");
+ fprintf(fd, "100 dict begin\n");
+ split = PlaceImage(tif,fd,&npages,w,h,pw,ph,prw,prh,
+ split,lm,bm,cnt);
+ }
+ }
+ else {
+ /* NB: maintain image aspect ratio */
+ scale = (xscale < yscale) ? xscale : yscale;
+ if (scale > 1.0)
+ scale = 1.0;
+
+ /* Adjust offsets for centering */
+ if (cnt) {
+ switch (rotation) {
+ case 90:
+ case 270:
+ hcenter = (psw - prh * scale) / 2;
+ vcenter = (psh - prw * scale) / 2;
+ break;
+ case 0:
+ case 180:
+ default:
+ hcenter = (psw - prw * scale) / 2;
+ vcenter = (psh - prh * scale) / 2;
+ break;
+ }
+ }
+ else
+ hcenter = 0.0, vcenter = 0.0;
+ if (cnt)
+ fprintf (fd, "%f %f translate\n", hcenter, vcenter);
+ switch (rotation) {
+ case 0:
+ fprintf (fd, "%f %f scale\n", prw * scale, prh * scale);
+ break;
+ case 90:
+ fprintf (fd, "%f %f scale\n1 0 translate 90 rotate\n", prh * scale, prw * scale);
+ break;
+ case 180:
+ fprintf (fd, "%f %f scale\n1 1 translate 180 rotate\n", prw * scale, prh * scale);
+ break;
+ case 270:
+ fprintf (fd, "%f %f scale\n0 1 translate 270 rotate\n", prh * scale, prw * scale);
+ break;
+ default:
+ fprintf (stderr, "Unsupported angle. No rotation\n");
+ fprintf (fd, "%f %f scale\n", prw * scale, prh * scale);
+ break;
+ }
+ }
+ } else {
+ if (rotate)
+ {
+ /* Width and height have already been enchanged for 90/270 rotations */
+ switch (rotation) {
+ case 0:
+ fprintf (fd, "%f %f scale\n", prw, prh);
+ case 90:
+ fprintf (fd, "%f %f scale\n1 0 translate 90 rotate\n", prw, prh);
+ break;
+ case 180:
+ fprintf (fd, "%f %f scale\n1 1 translate 180 rotate\n", prw, prh);
+ break;
+ case 270:
+ fprintf (fd, "%f %f scale\n0 1 translate 270 rotate\n", prw, prh);
+ break;
+ default:
+ fprintf (stderr, "Unsupported angle. No rotation\n");
+ fprintf( fd, "%f %f scale\n", prw, prh);
+ break;
+ }
+ }
+ else
+ {
+ /* fprintf (stderr, "No rotation\n"); */
+ fprintf (fd, "%f %f scale\n", prw, prh);
+ }
+ }
+ PSpage(fd, tif, w, h);
+ fprintf(fd, "end\n");
+ fprintf(fd, "grestore\n");
+ fprintf(fd, "showpage\n");
+ }
+ if (generateEPSF)
+ break;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_SUBFILETYPE, &subfiletype);
+ } while (((subfiletype & FILETYPE_PAGE) || printAll) &&
+ TIFFReadDirectory(tif));
+
+ return(npages);
+}
+
+static char DuplexPreamble[] = "\
+%%BeginFeature: *Duplex True\n\
+systemdict begin\n\
+ /languagelevel where { pop languagelevel } { 1 } ifelse\n\
+ 2 ge { 1 dict dup /Duplex true put setpagedevice }\n\
+ { statusdict /setduplex known { statusdict begin setduplex true end } if\n\
+ } ifelse\n\
+end\n\
+%%EndFeature\n\
+";
+
+static char TumblePreamble[] = "\
+%%BeginFeature: *Tumble True\n\
+systemdict begin\n\
+ /languagelevel where { pop languagelevel } { 1 } ifelse\n\
+ 2 ge { 1 dict dup /Tumble true put setpagedevice }\n\
+ { statusdict /settumble known { statusdict begin true settumble end } if\n\
+ } ifelse\n\
+end\n\
+%%EndFeature\n\
+";
+
+static char AvoidDeadZonePreamble[] = "\
+gsave newpath clippath pathbbox grestore\n\
+ 4 2 roll 2 copy translate\n\
+ exch 3 1 roll sub 3 1 roll sub exch\n\
+ currentpagedevice /PageSize get aload pop\n\
+ exch 3 1 roll div 3 1 roll div abs exch abs\n\
+ 2 copy gt { exch } if pop\n\
+ dup 1 lt { dup scale } { pop } ifelse\n\
+";
+
+void
+PSHead(FILE *fd, TIFF *tif, uint32 w, uint32 h,
+ double pw, double ph, double ox, double oy)
+{
+ time_t t;
+
+ (void) tif; (void) w; (void) h;
+ t = time(0);
+ fprintf(fd, "%%!PS-Adobe-3.0%s\n", generateEPSF ? " EPSF-3.0" : "");
+ fprintf(fd, "%%%%Creator: tiff2ps\n");
+ fprintf(fd, "%%%%Title: %s\n", filename);
+ fprintf(fd, "%%%%CreationDate: %s", ctime(&t));
+ fprintf(fd, "%%%%DocumentData: Clean7Bit\n");
+ fprintf(fd, "%%%%Origin: %ld %ld\n", (long) ox, (long) oy);
+ /* NB: should use PageBoundingBox */
+ if (rotate && (rotation == 90 || rotation == 270))
+ fprintf(fd, "%%%%BoundingBox: 0 0 %ld %ld\n",
+ (long) ceil(ph), (long) ceil(pw));
+ else
+ fprintf(fd, "%%%%BoundingBox: 0 0 %ld %ld\n",
+ (long) ceil(pw), (long) ceil(ph));
+
+ fprintf(fd, "%%%%LanguageLevel: %d\n", (level3 ? 3 : (level2 ? 2 : 1)));
+ fprintf(fd, "%%%%Pages: (atend)\n");
+ fprintf(fd, "%%%%EndComments\n");
+ fprintf(fd, "%%%%BeginSetup\n");
+ if (PSduplex)
+ fprintf(fd, "%s", DuplexPreamble);
+ if (PStumble)
+ fprintf(fd, "%s", TumblePreamble);
+ if (PSavoiddeadzone && (level2 || level3))
+ fprintf(fd, "%s", AvoidDeadZonePreamble);
+ fprintf(fd, "%%%%EndSetup\n");
+}
+
+void
+PSTail(FILE *fd, int npages)
+{
+ fprintf(fd, "%%%%Trailer\n");
+ fprintf(fd, "%%%%Pages: %d\n", npages);
+ fprintf(fd, "%%%%EOF\n");
+}
+
+static int
+checkcmap(TIFF* tif, int n, uint16* r, uint16* g, uint16* b)
+{
+ (void) tif;
+ while (n-- > 0)
+ if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
+ return (16);
+ TIFFWarning(filename, "Assuming 8-bit colormap");
+ return (8);
+}
+
+static void
+PS_Lvl2colorspace(FILE* fd, TIFF* tif)
+{
+ uint16 *rmap, *gmap, *bmap;
+ int i, num_colors;
+ const char * colorspace_p;
+
+ switch ( photometric )
+ {
+ case PHOTOMETRIC_SEPARATED:
+ colorspace_p = "CMYK";
+ break;
+
+ case PHOTOMETRIC_RGB:
+ colorspace_p = "RGB";
+ break;
+
+ default:
+ colorspace_p = "Gray";
+ }
+
+ /*
+ * Set up PostScript Level 2 colorspace according to
+ * section 4.8 in the PostScript refenence manual.
+ */
+ fputs("% PostScript Level 2 only.\n", fd);
+ if (photometric != PHOTOMETRIC_PALETTE) {
+ if (photometric == PHOTOMETRIC_YCBCR) {
+ /* MORE CODE HERE */
+ }
+ fprintf(fd, "/Device%s setcolorspace\n", colorspace_p );
+ return;
+ }
+
+ /*
+ * Set up an indexed/palette colorspace
+ */
+ num_colors = (1 << bitspersample);
+ if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
+ TIFFError(filename,
+ "Palette image w/o \"Colormap\" tag");
+ return;
+ }
+ if (checkcmap(tif, num_colors, rmap, gmap, bmap) == 16) {
+ /*
+ * Convert colormap to 8-bits values.
+ */
+#define CVT(x) (((x) * 255) / ((1L<<16)-1))
+ for (i = 0; i < num_colors; i++) {
+ rmap[i] = CVT(rmap[i]);
+ gmap[i] = CVT(gmap[i]);
+ bmap[i] = CVT(bmap[i]);
+ }
+#undef CVT
+ }
+ fprintf(fd, "[ /Indexed /DeviceRGB %d", num_colors - 1);
+ if (ascii85) {
+ Ascii85Init();
+ fputs("\n<~", fd);
+ ascii85breaklen -= 2;
+ } else
+ fputs(" <", fd);
+ for (i = 0; i < num_colors; i++) {
+ if (ascii85) {
+ Ascii85Put((unsigned char)rmap[i], fd);
+ Ascii85Put((unsigned char)gmap[i], fd);
+ Ascii85Put((unsigned char)bmap[i], fd);
+ } else {
+ fputs((i % 8) ? " " : "\n ", fd);
+ fprintf(fd, "%02x%02x%02x",
+ rmap[i], gmap[i], bmap[i]);
+ }
+ }
+ if (ascii85)
+ Ascii85Flush(fd);
+ else
+ fputs(">\n", fd);
+ fputs("] setcolorspace\n", fd);
+}
+
+static int
+PS_Lvl2ImageDict(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ int use_rawdata;
+ uint32 tile_width, tile_height;
+ uint16 predictor, minsamplevalue, maxsamplevalue;
+ int repeat_count;
+ char im_h[64], im_x[64], im_y[64];
+ char * imageOp = "image";
+
+ if ( useImagemask && (bitspersample == 1) )
+ imageOp = "imagemask";
+
+ (void)strcpy(im_x, "0");
+ (void)sprintf(im_y, "%lu", (long) h);
+ (void)sprintf(im_h, "%lu", (long) h);
+ tile_width = w;
+ tile_height = h;
+ if (TIFFIsTiled(tif)) {
+ repeat_count = TIFFNumberOfTiles(tif);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
+ if (tile_width > w || tile_height > h ||
+ (w % tile_width) != 0 || (h % tile_height != 0)) {
+ /*
+ * The tiles does not fit image width and height.
+ * Set up a clip rectangle for the image unit square.
+ */
+ fputs("0 0 1 1 rectclip\n", fd);
+ }
+ if (tile_width < w) {
+ fputs("/im_x 0 def\n", fd);
+ (void)strcpy(im_x, "im_x neg");
+ }
+ if (tile_height < h) {
+ fputs("/im_y 0 def\n", fd);
+ (void)sprintf(im_y, "%lu im_y sub", (unsigned long) h);
+ }
+ } else {
+ repeat_count = tf_numberstrips;
+ tile_height = tf_rowsperstrip;
+ if (tile_height > h)
+ tile_height = h;
+ if (repeat_count > 1) {
+ fputs("/im_y 0 def\n", fd);
+ fprintf(fd, "/im_h %lu def\n",
+ (unsigned long) tile_height);
+ (void)strcpy(im_h, "im_h");
+ (void)sprintf(im_y, "%lu im_y sub", (unsigned long) h);
+ }
+ }
+
+ /*
+ * Output start of exec block
+ */
+ fputs("{ % exec\n", fd);
+
+ if (repeat_count > 1)
+ fprintf(fd, "%d { %% repeat\n", repeat_count);
+
+ /*
+ * Output filter options and image dictionary.
+ */
+ if (ascii85)
+ fputs(" /im_stream currentfile /ASCII85Decode filter def\n",
+ fd);
+ fputs(" <<\n", fd);
+ fputs(" /ImageType 1\n", fd);
+ fprintf(fd, " /Width %lu\n", (unsigned long) tile_width);
+ /*
+ * Workaround for some software that may crash when last strip
+ * of image contains fewer number of scanlines than specified
+ * by the `/Height' variable. So for stripped images with multiple
+ * strips we will set `/Height' as `im_h', because one is
+ * recalculated for each strip - including the (smaller) final strip.
+ * For tiled images and images with only one strip `/Height' will
+ * contain number of scanlines in tile (or image height in case of
+ * one-stripped image).
+ */
+ if (TIFFIsTiled(tif) || tf_numberstrips == 1)
+ fprintf(fd, " /Height %lu\n", (unsigned long) tile_height);
+ else
+ fprintf(fd, " /Height im_h\n");
+
+ if (planarconfiguration == PLANARCONFIG_SEPARATE && samplesperpixel > 1)
+ fputs(" /MultipleDataSources true\n", fd);
+ fprintf(fd, " /ImageMatrix [ %lu 0 0 %ld %s %s ]\n",
+ (unsigned long) w, - (long)h, im_x, im_y);
+ fprintf(fd, " /BitsPerComponent %d\n", bitspersample);
+ fprintf(fd, " /Interpolate %s\n", interpolate ? "true" : "false");
+
+ switch (samplesperpixel - extrasamples) {
+ case 1:
+ switch (photometric) {
+ case PHOTOMETRIC_MINISBLACK:
+ fputs(" /Decode [0 1]\n", fd);
+ break;
+ case PHOTOMETRIC_MINISWHITE:
+ switch (compression) {
+ case COMPRESSION_CCITTRLE:
+ case COMPRESSION_CCITTRLEW:
+ case COMPRESSION_CCITTFAX3:
+ case COMPRESSION_CCITTFAX4:
+ /*
+ * Manage inverting with /Blackis1 flag
+ * since there migth be uncompressed parts
+ */
+ fputs(" /Decode [0 1]\n", fd);
+ break;
+ default:
+ /*
+ * ERROR...
+ */
+ fputs(" /Decode [1 0]\n", fd);
+ break;
+ }
+ break;
+ case PHOTOMETRIC_PALETTE:
+ TIFFGetFieldDefaulted(tif, TIFFTAG_MINSAMPLEVALUE,
+ &minsamplevalue);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_MAXSAMPLEVALUE,
+ &maxsamplevalue);
+ fprintf(fd, " /Decode [%u %u]\n",
+ minsamplevalue, maxsamplevalue);
+ break;
+ default:
+ /*
+ * ERROR ?
+ */
+ fputs(" /Decode [0 1]\n", fd);
+ break;
+ }
+ break;
+ case 3:
+ switch (photometric) {
+ case PHOTOMETRIC_RGB:
+ fputs(" /Decode [0 1 0 1 0 1]\n", fd);
+ break;
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ default:
+ /*
+ * ERROR??
+ */
+ fputs(" /Decode [0 1 0 1 0 1]\n", fd);
+ break;
+ }
+ break;
+ case 4:
+ /*
+ * ERROR??
+ */
+ fputs(" /Decode [0 1 0 1 0 1 0 1]\n", fd);
+ break;
+ }
+ fputs(" /DataSource", fd);
+ if (planarconfiguration == PLANARCONFIG_SEPARATE &&
+ samplesperpixel > 1)
+ fputs(" [", fd);
+ if (ascii85)
+ fputs(" im_stream", fd);
+ else
+ fputs(" currentfile /ASCIIHexDecode filter", fd);
+
+ use_rawdata = TRUE;
+ switch (compression) {
+ case COMPRESSION_NONE: /* 1: uncompressed */
+ break;
+ case COMPRESSION_CCITTRLE: /* 2: CCITT modified Huffman RLE */
+ case COMPRESSION_CCITTRLEW: /* 32771: #1 w/ word alignment */
+ case COMPRESSION_CCITTFAX3: /* 3: CCITT Group 3 fax encoding */
+ case COMPRESSION_CCITTFAX4: /* 4: CCITT Group 4 fax encoding */
+ fputs("\n\t<<\n", fd);
+ if (compression == COMPRESSION_CCITTFAX3) {
+ uint32 g3_options;
+
+ fputs("\t /EndOfLine true\n", fd);
+ fputs("\t /EndOfBlock false\n", fd);
+ if (!TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS,
+ &g3_options))
+ g3_options = 0;
+ if (g3_options & GROUP3OPT_2DENCODING)
+ fprintf(fd, "\t /K %s\n", im_h);
+ if (g3_options & GROUP3OPT_UNCOMPRESSED)
+ fputs("\t /Uncompressed true\n", fd);
+ if (g3_options & GROUP3OPT_FILLBITS)
+ fputs("\t /EncodedByteAlign true\n", fd);
+ }
+ if (compression == COMPRESSION_CCITTFAX4) {
+ uint32 g4_options;
+
+ fputs("\t /K -1\n", fd);
+ TIFFGetFieldDefaulted(tif, TIFFTAG_GROUP4OPTIONS,
+ &g4_options);
+ if (g4_options & GROUP4OPT_UNCOMPRESSED)
+ fputs("\t /Uncompressed true\n", fd);
+ }
+ if (!(tile_width == w && w == 1728U))
+ fprintf(fd, "\t /Columns %lu\n",
+ (unsigned long) tile_width);
+ fprintf(fd, "\t /Rows %s\n", im_h);
+ if (compression == COMPRESSION_CCITTRLE ||
+ compression == COMPRESSION_CCITTRLEW) {
+ fputs("\t /EncodedByteAlign true\n", fd);
+ fputs("\t /EndOfBlock false\n", fd);
+ }
+ if (photometric == PHOTOMETRIC_MINISBLACK)
+ fputs("\t /BlackIs1 true\n", fd);
+ fprintf(fd, "\t>> /CCITTFaxDecode filter");
+ break;
+ case COMPRESSION_LZW: /* 5: Lempel-Ziv & Welch */
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PREDICTOR, &predictor);
+ if (predictor == 2) {
+ fputs("\n\t<<\n", fd);
+ fprintf(fd, "\t /Predictor %u\n", predictor);
+ fprintf(fd, "\t /Columns %lu\n",
+ (unsigned long) tile_width);
+ fprintf(fd, "\t /Colors %u\n", samplesperpixel);
+ fprintf(fd, "\t /BitsPerComponent %u\n",
+ bitspersample);
+ fputs("\t>>", fd);
+ }
+ fputs(" /LZWDecode filter", fd);
+ break;
+ case COMPRESSION_DEFLATE: /* 5: ZIP */
+ case COMPRESSION_ADOBE_DEFLATE:
+ if ( level3 ) {
+ TIFFGetFieldDefaulted(tif, TIFFTAG_PREDICTOR, &predictor);
+ if (predictor > 1) {
+ fprintf(fd, "\t %% PostScript Level 3 only.");
+ fputs("\n\t<<\n", fd);
+ fprintf(fd, "\t /Predictor %u\n", predictor);
+ fprintf(fd, "\t /Columns %lu\n",
+ (unsigned long) tile_width);
+ fprintf(fd, "\t /Colors %u\n", samplesperpixel);
+ fprintf(fd, "\t /BitsPerComponent %u\n",
+ bitspersample);
+ fputs("\t>>", fd);
+ }
+ fputs(" /FlateDecode filter", fd);
+ } else {
+ use_rawdata = FALSE ;
+ }
+ break;
+ case COMPRESSION_PACKBITS: /* 32773: Macintosh RLE */
+ fputs(" /RunLengthDecode filter", fd);
+ use_rawdata = TRUE;
+ break;
+ case COMPRESSION_OJPEG: /* 6: !6.0 JPEG */
+ case COMPRESSION_JPEG: /* 7: %JPEG DCT compression */
+#ifdef notdef
+ /*
+ * Code not tested yet
+ */
+ fputs(" /DCTDecode filter", fd);
+ use_rawdata = TRUE;
+#else
+ use_rawdata = FALSE;
+#endif
+ break;
+ case COMPRESSION_NEXT: /* 32766: NeXT 2-bit RLE */
+ case COMPRESSION_THUNDERSCAN: /* 32809: ThunderScan RLE */
+ case COMPRESSION_PIXARFILM: /* 32908: Pixar companded 10bit LZW */
+ case COMPRESSION_JBIG: /* 34661: ISO JBIG */
+ use_rawdata = FALSE;
+ break;
+ case COMPRESSION_SGILOG: /* 34676: SGI LogL or LogLuv */
+ case COMPRESSION_SGILOG24: /* 34677: SGI 24-bit LogLuv */
+ use_rawdata = FALSE;
+ break;
+ default:
+ /*
+ * ERROR...
+ */
+ use_rawdata = FALSE;
+ break;
+ }
+ if (planarconfiguration == PLANARCONFIG_SEPARATE &&
+ samplesperpixel > 1) {
+ uint16 i;
+
+ /*
+ * NOTE: This code does not work yet...
+ */
+ for (i = 1; i < samplesperpixel; i++)
+ fputs(" dup", fd);
+ fputs(" ]", fd);
+ }
+
+ fprintf( fd, "\n >> %s\n", imageOp );
+ if (ascii85)
+ fputs(" im_stream status { im_stream flushfile } if\n", fd);
+ if (repeat_count > 1) {
+ if (tile_width < w) {
+ fprintf(fd, " /im_x im_x %lu add def\n",
+ (unsigned long) tile_width);
+ if (tile_height < h) {
+ fprintf(fd, " im_x %lu ge {\n",
+ (unsigned long) w);
+ fputs(" /im_x 0 def\n", fd);
+ fprintf(fd, " /im_y im_y %lu add def\n",
+ (unsigned long) tile_height);
+ fputs(" } if\n", fd);
+ }
+ }
+ if (tile_height < h) {
+ if (tile_width >= w) {
+ fprintf(fd, " /im_y im_y %lu add def\n",
+ (unsigned long) tile_height);
+ if (!TIFFIsTiled(tif)) {
+ fprintf(fd, " /im_h %lu im_y sub",
+ (unsigned long) h);
+ fprintf(fd, " dup %lu gt { pop",
+ (unsigned long) tile_height);
+ fprintf(fd, " %lu } if def\n",
+ (unsigned long) tile_height);
+ }
+ }
+ }
+ fputs("} repeat\n", fd);
+ }
+ /*
+ * End of exec function
+ */
+ fputs("}\n", fd);
+
+ return(use_rawdata);
+}
+
+/* Flip the byte order of buffers with 16 bit samples */
+static void
+PS_FlipBytes(unsigned char* buf, int count)
+{
+ int i;
+ unsigned char temp;
+
+ if (count <= 0 || bitspersample <= 8) {
+ return;
+ }
+
+ count--;
+
+ for (i = 0; i < count; i += 2) {
+ temp = buf[i];
+ buf[i] = buf[i + 1];
+ buf[i + 1] = temp;
+ }
+}
+
+#define MAXLINE 36
+
+int
+PS_Lvl2page(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ uint16 fillorder;
+ int use_rawdata, tiled_image, breaklen = MAXLINE;
+ uint32 chunk_no, num_chunks, *bc;
+ unsigned char *buf_data, *cp;
+ tsize_t chunk_size, byte_count;
+
+#if defined( EXP_ASCII85ENCODER )
+ int ascii85_l; /* Length, in bytes, of ascii85_p[] data */
+ uint8 * ascii85_p = 0; /* Holds ASCII85 encoded data */
+#endif
+
+ PS_Lvl2colorspace(fd, tif);
+ use_rawdata = PS_Lvl2ImageDict(fd, tif, w, h);
+
+/* See http://bugzilla.remotesensing.org/show_bug.cgi?id=80 */
+#ifdef ENABLE_BROKEN_BEGINENDDATA
+ fputs("%%BeginData:\n", fd);
+#endif
+ fputs("exec\n", fd);
+
+ tiled_image = TIFFIsTiled(tif);
+ if (tiled_image) {
+ num_chunks = TIFFNumberOfTiles(tif);
+ TIFFGetField(tif, TIFFTAG_TILEBYTECOUNTS, &bc);
+ } else {
+ num_chunks = TIFFNumberOfStrips(tif);
+ TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
+ }
+
+ if (use_rawdata) {
+ chunk_size = (tsize_t) bc[0];
+ for (chunk_no = 1; chunk_no < num_chunks; chunk_no++)
+ if ((tsize_t) bc[chunk_no] > chunk_size)
+ chunk_size = (tsize_t) bc[chunk_no];
+ } else {
+ if (tiled_image)
+ chunk_size = TIFFTileSize(tif);
+ else
+ chunk_size = TIFFStripSize(tif);
+ }
+ buf_data = (unsigned char *)_TIFFmalloc(chunk_size);
+ if (!buf_data) {
+ TIFFError(filename, "Can't alloc %u bytes for %s.",
+ chunk_size, tiled_image ? "tiles" : "strips");
+ return(FALSE);
+ }
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85 ) {
+ /*
+ * Allocate a buffer to hold the ASCII85 encoded data. Note
+ * that it is allocated with sufficient room to hold the
+ * encoded data (5*chunk_size/4) plus the EOD marker (+8)
+ * and formatting line breaks. The line breaks are more
+ * than taken care of by using 6*chunk_size/4 rather than
+ * 5*chunk_size/4.
+ */
+
+ ascii85_p = _TIFFmalloc( (chunk_size+(chunk_size/2)) + 8 );
+
+ if ( !ascii85_p ) {
+ _TIFFfree( buf_data );
+
+ TIFFError( filename, "Cannot allocate ASCII85 encoding buffer." );
+ return ( FALSE );
+ }
+ }
+#endif
+
+ TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
+ for (chunk_no = 0; chunk_no < num_chunks; chunk_no++) {
+ if (ascii85)
+ Ascii85Init();
+ else
+ breaklen = MAXLINE;
+ if (use_rawdata) {
+ if (tiled_image)
+ byte_count = TIFFReadRawTile(tif, chunk_no,
+ buf_data, chunk_size);
+ else
+ byte_count = TIFFReadRawStrip(tif, chunk_no,
+ buf_data, chunk_size);
+ if (fillorder == FILLORDER_LSB2MSB)
+ TIFFReverseBits(buf_data, byte_count);
+ } else {
+ if (tiled_image)
+ byte_count = TIFFReadEncodedTile(tif,
+ chunk_no, buf_data,
+ chunk_size);
+ else
+ byte_count = TIFFReadEncodedStrip(tif,
+ chunk_no, buf_data,
+ chunk_size);
+ }
+ if (byte_count < 0) {
+ TIFFError(filename, "Can't read %s %d.",
+ tiled_image ? "tile" : "strip", chunk_no);
+ if (ascii85)
+ Ascii85Put('\0', fd);
+ }
+ /*
+ * for 16 bits, the two bytes must be most significant
+ * byte first
+ */
+ if (bitspersample == 16 && !TIFFIsBigEndian(tif)) {
+ PS_FlipBytes(buf_data, byte_count);
+ }
+ /*
+ * For images with alpha, matte against a white background;
+ * i.e. Cback * (1 - Aimage) where Cback = 1. We will fill the
+ * lower part of the buffer with the modified values.
+ *
+ * XXX: needs better solution
+ */
+ if (alpha) {
+ int adjust, i, j = 0;
+ int ncomps = samplesperpixel - extrasamples;
+ for (i = 0; i < byte_count; i+=samplesperpixel) {
+ adjust = 255 - buf_data[i + ncomps];
+ switch (ncomps) {
+ case 1:
+ buf_data[j++] = buf_data[i] + adjust;
+ break;
+ case 2:
+ buf_data[j++] = buf_data[i] + adjust;
+ buf_data[j++] = buf_data[i+1] + adjust;
+ break;
+ case 3:
+ buf_data[j++] = buf_data[i] + adjust;
+ buf_data[j++] = buf_data[i+1] + adjust;
+ buf_data[j++] = buf_data[i+2] + adjust;
+ break;
+ }
+ }
+ byte_count -= j;
+ }
+
+ if (ascii85) {
+#if defined( EXP_ASCII85ENCODER )
+ ascii85_l = Ascii85EncodeBlock(ascii85_p, 1, buf_data, byte_count );
+
+ if ( ascii85_l > 0 )
+ fwrite( ascii85_p, ascii85_l, 1, fd );
+#else
+ for (cp = buf_data; byte_count > 0; byte_count--)
+ Ascii85Put(*cp++, fd);
+#endif
+ }
+ else
+ {
+ for (cp = buf_data; byte_count > 0; byte_count--) {
+ putc(hex[((*cp)>>4)&0xf], fd);
+ putc(hex[(*cp)&0xf], fd);
+ cp++;
+
+ if (--breaklen <= 0) {
+ putc('\n', fd);
+ breaklen = MAXLINE;
+ }
+ }
+ }
+
+ if ( !ascii85 ) {
+ if ( level2 || level3 )
+ putc( '>', fd );
+ putc('\n', fd);
+ }
+#if !defined( EXP_ASCII85ENCODER )
+ else
+ Ascii85Flush(fd);
+#endif
+ }
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85_p )
+ _TIFFfree( ascii85_p );
+#endif
+
+ _TIFFfree(buf_data);
+#ifdef ENABLE_BROKEN_BEGINENDDATA
+ fputs("%%EndData\n", fd);
+#endif
+ return(TRUE);
+}
+
+void
+PSpage(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ char * imageOp = "image";
+
+ if ( useImagemask && (bitspersample == 1) )
+ imageOp = "imagemask";
+
+ if ((level2 || level3) && PS_Lvl2page(fd, tif, w, h))
+ return;
+ ps_bytesperrow = tf_bytesperrow - (extrasamples * bitspersample / 8)*w;
+ switch (photometric) {
+ case PHOTOMETRIC_RGB:
+ if (planarconfiguration == PLANARCONFIG_CONTIG) {
+ fprintf(fd, "%s", RGBcolorimage);
+ PSColorContigPreamble(fd, w, h, 3);
+ PSDataColorContig(fd, tif, w, h, 3);
+ } else {
+ PSColorSeparatePreamble(fd, w, h, 3);
+ PSDataColorSeparate(fd, tif, w, h, 3);
+ }
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ /* XXX should emit CMYKcolorimage */
+ if (planarconfiguration == PLANARCONFIG_CONTIG) {
+ PSColorContigPreamble(fd, w, h, 4);
+ PSDataColorContig(fd, tif, w, h, 4);
+ } else {
+ PSColorSeparatePreamble(fd, w, h, 4);
+ PSDataColorSeparate(fd, tif, w, h, 4);
+ }
+ break;
+ case PHOTOMETRIC_PALETTE:
+ fprintf(fd, "%s", RGBcolorimage);
+ PhotoshopBanner(fd, w, h, 1, 3, "false 3 colorimage");
+ fprintf(fd, "/scanLine %ld string def\n",
+ (long) ps_bytesperrow * 3L);
+ fprintf(fd, "%lu %lu 8\n",
+ (unsigned long) w, (unsigned long) h);
+ fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n",
+ (unsigned long) w, (unsigned long) h, (unsigned long) h);
+ fprintf(fd, "{currentfile scanLine readhexstring pop} bind\n");
+ fprintf(fd, "false 3 colorimage\n");
+ PSDataPalette(fd, tif, w, h);
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ case PHOTOMETRIC_MINISWHITE:
+ PhotoshopBanner(fd, w, h, 1, 1, imageOp);
+ fprintf(fd, "/scanLine %ld string def\n",
+ (long) ps_bytesperrow);
+ fprintf(fd, "%lu %lu %d\n",
+ (unsigned long) w, (unsigned long) h, bitspersample);
+ fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n",
+ (unsigned long) w, (unsigned long) h, (unsigned long) h);
+ fprintf(fd,
+ "{currentfile scanLine readhexstring pop} bind\n");
+ fprintf(fd, "%s\n", imageOp);
+ PSDataBW(fd, tif, w, h);
+ break;
+ }
+ putc('\n', fd);
+}
+
+void
+PSColorContigPreamble(FILE* fd, uint32 w, uint32 h, int nc)
+{
+ ps_bytesperrow = nc * (tf_bytesperrow / samplesperpixel);
+ PhotoshopBanner(fd, w, h, 1, nc, "false %d colorimage");
+ fprintf(fd, "/line %ld string def\n", (long) ps_bytesperrow);
+ fprintf(fd, "%lu %lu %d\n",
+ (unsigned long) w, (unsigned long) h, bitspersample);
+ fprintf(fd, "[%lu 0 0 -%lu 0 %lu]\n",
+ (unsigned long) w, (unsigned long) h, (unsigned long) h);
+ fprintf(fd, "{currentfile line readhexstring pop} bind\n");
+ fprintf(fd, "false %d colorimage\n", nc);
+}
+
+void
+PSColorSeparatePreamble(FILE* fd, uint32 w, uint32 h, int nc)
+{
+ int i;
+
+ PhotoshopBanner(fd, w, h, ps_bytesperrow, nc, "true %d colorimage");
+ for (i = 0; i < nc; i++)
+ fprintf(fd, "/line%d %ld string def\n",
+ i, (long) ps_bytesperrow);
+ fprintf(fd, "%lu %lu %d\n",
+ (unsigned long) w, (unsigned long) h, bitspersample);
+ fprintf(fd, "[%lu 0 0 -%lu 0 %lu] \n",
+ (unsigned long) w, (unsigned long) h, (unsigned long) h);
+ for (i = 0; i < nc; i++)
+ fprintf(fd, "{currentfile line%d readhexstring pop}bind\n", i);
+ fprintf(fd, "true %d colorimage\n", nc);
+}
+
+#define DOBREAK(len, howmany, fd) \
+ if (((len) -= (howmany)) <= 0) { \
+ putc('\n', fd); \
+ (len) = MAXLINE-(howmany); \
+ }
+#define PUTHEX(c,fd) putc(hex[((c)>>4)&0xf],fd); putc(hex[(c)&0xf],fd)
+
+void
+PSDataColorContig(FILE* fd, TIFF* tif, uint32 w, uint32 h, int nc)
+{
+ uint32 row;
+ int breaklen = MAXLINE, cc, es = samplesperpixel - nc;
+ unsigned char *tf_buf;
+ unsigned char *cp, c;
+
+ (void) w;
+ tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for scanline buffer");
+ return;
+ }
+ for (row = 0; row < h; row++) {
+ if (TIFFReadScanline(tif, tf_buf, row, 0) < 0)
+ break;
+ cp = tf_buf;
+ /*
+ * for 16 bits, the two bytes must be most significant
+ * byte first
+ */
+ if (bitspersample == 16 && !HOST_BIGENDIAN) {
+ PS_FlipBytes(cp, tf_bytesperrow);
+ }
+ if (alpha) {
+ int adjust;
+ cc = 0;
+ for (; cc < tf_bytesperrow; cc += samplesperpixel) {
+ DOBREAK(breaklen, nc, fd);
+ /*
+ * For images with alpha, matte against
+ * a white background; i.e.
+ * Cback * (1 - Aimage)
+ * where Cback = 1.
+ */
+ adjust = 255 - cp[nc];
+ switch (nc) {
+ case 4: c = *cp++ + adjust; PUTHEX(c,fd);
+ case 3: c = *cp++ + adjust; PUTHEX(c,fd);
+ case 2: c = *cp++ + adjust; PUTHEX(c,fd);
+ case 1: c = *cp++ + adjust; PUTHEX(c,fd);
+ }
+ cp += es;
+ }
+ } else {
+ cc = 0;
+ for (; cc < tf_bytesperrow; cc += samplesperpixel) {
+ DOBREAK(breaklen, nc, fd);
+ switch (nc) {
+ case 4: c = *cp++; PUTHEX(c,fd);
+ case 3: c = *cp++; PUTHEX(c,fd);
+ case 2: c = *cp++; PUTHEX(c,fd);
+ case 1: c = *cp++; PUTHEX(c,fd);
+ }
+ cp += es;
+ }
+ }
+ }
+ _TIFFfree((char *) tf_buf);
+}
+
+void
+PSDataColorSeparate(FILE* fd, TIFF* tif, uint32 w, uint32 h, int nc)
+{
+ uint32 row;
+ int breaklen = MAXLINE, cc;
+ tsample_t s, maxs;
+ unsigned char *tf_buf;
+ unsigned char *cp, c;
+
+ (void) w;
+ tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for scanline buffer");
+ return;
+ }
+ maxs = (samplesperpixel > nc ? nc : samplesperpixel);
+ for (row = 0; row < h; row++) {
+ for (s = 0; s < maxs; s++) {
+ if (TIFFReadScanline(tif, tf_buf, row, s) < 0)
+ break;
+ for (cp = tf_buf, cc = 0; cc < tf_bytesperrow; cc++) {
+ DOBREAK(breaklen, 1, fd);
+ c = *cp++;
+ PUTHEX(c,fd);
+ }
+ }
+ }
+ _TIFFfree((char *) tf_buf);
+}
+
+#define PUTRGBHEX(c,fd) \
+ PUTHEX(rmap[c],fd); PUTHEX(gmap[c],fd); PUTHEX(bmap[c],fd)
+
+void
+PSDataPalette(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ uint16 *rmap, *gmap, *bmap;
+ uint32 row;
+ int breaklen = MAXLINE, cc, nc;
+ unsigned char *tf_buf;
+ unsigned char *cp, c;
+
+ (void) w;
+ if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) {
+ TIFFError(filename, "Palette image w/o \"Colormap\" tag");
+ return;
+ }
+ switch (bitspersample) {
+ case 8: case 4: case 2: case 1:
+ break;
+ default:
+ TIFFError(filename, "Depth %d not supported", bitspersample);
+ return;
+ }
+ nc = 3 * (8 / bitspersample);
+ tf_buf = (unsigned char *) _TIFFmalloc(tf_bytesperrow);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for scanline buffer");
+ return;
+ }
+ if (checkcmap(tif, 1<<bitspersample, rmap, gmap, bmap) == 16) {
+ int i;
+#define CVT(x) ((unsigned short) (((x) * 255) / ((1U<<16)-1)))
+ for (i = (1<<bitspersample)-1; i >= 0; i--) {
+ rmap[i] = CVT(rmap[i]);
+ gmap[i] = CVT(gmap[i]);
+ bmap[i] = CVT(bmap[i]);
+ }
+#undef CVT
+ }
+ for (row = 0; row < h; row++) {
+ if (TIFFReadScanline(tif, tf_buf, row, 0) < 0)
+ break;
+ for (cp = tf_buf, cc = 0; cc < tf_bytesperrow; cc++) {
+ DOBREAK(breaklen, nc, fd);
+ switch (bitspersample) {
+ case 8:
+ c = *cp++; PUTRGBHEX(c, fd);
+ break;
+ case 4:
+ c = *cp++; PUTRGBHEX(c&0xf, fd);
+ c >>= 4; PUTRGBHEX(c, fd);
+ break;
+ case 2:
+ c = *cp++; PUTRGBHEX(c&0x3, fd);
+ c >>= 2; PUTRGBHEX(c&0x3, fd);
+ c >>= 2; PUTRGBHEX(c&0x3, fd);
+ c >>= 2; PUTRGBHEX(c, fd);
+ break;
+ case 1:
+ c = *cp++; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c&0x1, fd);
+ c >>= 1; PUTRGBHEX(c, fd);
+ break;
+ }
+ }
+ }
+ _TIFFfree((char *) tf_buf);
+}
+
+void
+PSDataBW(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ int breaklen = MAXLINE;
+ unsigned char* tf_buf;
+ unsigned char* cp;
+ tsize_t stripsize = TIFFStripSize(tif);
+ tstrip_t s;
+
+#if defined( EXP_ASCII85ENCODER )
+ int ascii85_l; /* Length, in bytes, of ascii85_p[] data */
+ uint8 *ascii85_p = 0; /* Holds ASCII85 encoded data */
+#endif
+
+ (void) w; (void) h;
+ tf_buf = (unsigned char *) _TIFFmalloc(stripsize);
+ memset(tf_buf, 0, stripsize);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for scanline buffer");
+ return;
+ }
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85 ) {
+ /*
+ * Allocate a buffer to hold the ASCII85 encoded data. Note
+ * that it is allocated with sufficient room to hold the
+ * encoded data (5*stripsize/4) plus the EOD marker (+8)
+ * and formatting line breaks. The line breaks are more
+ * than taken care of by using 6*stripsize/4 rather than
+ * 5*stripsize/4.
+ */
+
+ ascii85_p = _TIFFmalloc( (stripsize+(stripsize/2)) + 8 );
+
+ if ( !ascii85_p ) {
+ _TIFFfree( tf_buf );
+
+ TIFFError( filename, "Cannot allocate ASCII85 encoding buffer." );
+ return;
+ }
+ }
+#endif
+
+ if (ascii85)
+ Ascii85Init();
+
+ for (s = 0; s < TIFFNumberOfStrips(tif); s++) {
+ int cc = TIFFReadEncodedStrip(tif, s, tf_buf, stripsize);
+ if (cc < 0) {
+ TIFFError(filename, "Can't read strip");
+ break;
+ }
+ cp = tf_buf;
+ if (photometric == PHOTOMETRIC_MINISWHITE) {
+ for (cp += cc; --cp >= tf_buf;)
+ *cp = ~*cp;
+ cp++;
+ }
+ /*
+ * for 16 bits, the two bytes must be most significant
+ * byte first
+ */
+ if (bitspersample == 16 && !HOST_BIGENDIAN) {
+ PS_FlipBytes(cp, cc);
+ }
+ if (ascii85) {
+#if defined( EXP_ASCII85ENCODER )
+ if (alpha) {
+ int adjust, i;
+ for (i = 0; i < cc; i+=2) {
+ adjust = 255 - cp[i + 1];
+ cp[i / 2] = cp[i] + adjust;
+ }
+ cc /= 2;
+ }
+
+ ascii85_l = Ascii85EncodeBlock( ascii85_p, 1, cp, cc );
+
+ if ( ascii85_l > 0 )
+ fwrite( ascii85_p, ascii85_l, 1, fd );
+#else
+ while (cc-- > 0)
+ Ascii85Put(*cp++, fd);
+#endif /* EXP_ASCII85_ENCODER */
+ } else {
+ unsigned char c;
+
+ if (alpha) {
+ int adjust;
+ while (cc-- > 0) {
+ DOBREAK(breaklen, 1, fd);
+ /*
+ * For images with alpha, matte against
+ * a white background; i.e.
+ * Cback * (1 - Aimage)
+ * where Cback = 1.
+ */
+ adjust = 255 - cp[1];
+ c = *cp++ + adjust; PUTHEX(c,fd);
+ cp++, cc--;
+ }
+ } else {
+ while (cc-- > 0) {
+ c = *cp++;
+ DOBREAK(breaklen, 1, fd);
+ PUTHEX(c, fd);
+ }
+ }
+ }
+ }
+
+ if ( !ascii85 )
+ {
+ if ( level2 || level3)
+ fputs(">\n", fd);
+ }
+#if !defined( EXP_ASCII85ENCODER )
+ else
+ Ascii85Flush(fd);
+#else
+ if ( ascii85_p )
+ _TIFFfree( ascii85_p );
+#endif
+
+ _TIFFfree(tf_buf);
+}
+
+void
+PSRawDataBW(FILE* fd, TIFF* tif, uint32 w, uint32 h)
+{
+ uint32 *bc;
+ uint32 bufsize;
+ int breaklen = MAXLINE, cc;
+ uint16 fillorder;
+ unsigned char *tf_buf;
+ unsigned char *cp, c;
+ tstrip_t s;
+
+#if defined( EXP_ASCII85ENCODER )
+ int ascii85_l; /* Length, in bytes, of ascii85_p[] data */
+ uint8 * ascii85_p = 0; /* Holds ASCII85 encoded data */
+#endif
+
+ (void) w; (void) h;
+ TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder);
+ TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &bc);
+
+ /*
+ * Find largest strip:
+ */
+
+ bufsize = bc[0];
+
+ for ( s = 0; ++s < (tstrip_t)tf_numberstrips; ) {
+ if ( bc[s] > bufsize )
+ bufsize = bc[s];
+ }
+
+ tf_buf = (unsigned char*) _TIFFmalloc(bufsize);
+ if (tf_buf == NULL) {
+ TIFFError(filename, "No space for strip buffer");
+ return;
+ }
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85 ) {
+ /*
+ * Allocate a buffer to hold the ASCII85 encoded data. Note
+ * that it is allocated with sufficient room to hold the
+ * encoded data (5*bufsize/4) plus the EOD marker (+8)
+ * and formatting line breaks. The line breaks are more
+ * than taken care of by using 6*bufsize/4 rather than
+ * 5*bufsize/4.
+ */
+
+ ascii85_p = _TIFFmalloc( (bufsize+(bufsize/2)) + 8 );
+
+ if ( !ascii85_p ) {
+ _TIFFfree( tf_buf );
+
+ TIFFError( filename, "Cannot allocate ASCII85 encoding buffer." );
+ return;
+ }
+ }
+#endif
+
+ for (s = 0; s < (tstrip_t) tf_numberstrips; s++) {
+ cc = TIFFReadRawStrip(tif, s, tf_buf, bc[s]);
+ if (cc < 0) {
+ TIFFError(filename, "Can't read strip");
+ break;
+ }
+ if (fillorder == FILLORDER_LSB2MSB)
+ TIFFReverseBits(tf_buf, cc);
+ if (!ascii85) {
+ for (cp = tf_buf; cc > 0; cc--) {
+ DOBREAK(breaklen, 1, fd);
+ c = *cp++;
+ PUTHEX(c, fd);
+ }
+ fputs(">\n", fd);
+ breaklen = MAXLINE;
+ } else {
+ Ascii85Init();
+#if defined( EXP_ASCII85ENCODER )
+ ascii85_l = Ascii85EncodeBlock( ascii85_p, 1, tf_buf, cc );
+
+ if ( ascii85_l > 0 )
+ fwrite( ascii85_p, ascii85_l, 1, fd );
+#else
+ for (cp = tf_buf; cc > 0; cc--)
+ Ascii85Put(*cp++, fd);
+ Ascii85Flush(fd);
+#endif /* EXP_ASCII85ENCODER */
+ }
+ }
+ _TIFFfree((char *) tf_buf);
+
+#if defined( EXP_ASCII85ENCODER )
+ if ( ascii85_p )
+ _TIFFfree( ascii85_p );
+#endif
+}
+
+void
+Ascii85Init(void)
+{
+ ascii85breaklen = 2*MAXLINE;
+ ascii85count = 0;
+}
+
+static char*
+Ascii85Encode(unsigned char* raw)
+{
+ static char encoded[6];
+ uint32 word;
+
+ word = (((raw[0]<<8)+raw[1])<<16) + (raw[2]<<8) + raw[3];
+ if (word != 0L) {
+ uint32 q;
+ uint16 w1;
+
+ q = word / (85L*85*85*85); /* actually only a byte */
+ encoded[0] = (char) (q + '!');
+
+ word -= q * (85L*85*85*85); q = word / (85L*85*85);
+ encoded[1] = (char) (q + '!');
+
+ word -= q * (85L*85*85); q = word / (85*85);
+ encoded[2] = (char) (q + '!');
+
+ w1 = (uint16) (word - q*(85L*85));
+ encoded[3] = (char) ((w1 / 85) + '!');
+ encoded[4] = (char) ((w1 % 85) + '!');
+ encoded[5] = '\0';
+ } else
+ encoded[0] = 'z', encoded[1] = '\0';
+ return (encoded);
+}
+
+void
+Ascii85Put(unsigned char code, FILE* fd)
+{
+ ascii85buf[ascii85count++] = code;
+ if (ascii85count >= 4) {
+ unsigned char* p;
+ int n;
+
+ for (n = ascii85count, p = ascii85buf; n >= 4; n -= 4, p += 4) {
+ char* cp;
+ for (cp = Ascii85Encode(p); *cp; cp++) {
+ putc(*cp, fd);
+ if (--ascii85breaklen == 0) {
+ putc('\n', fd);
+ ascii85breaklen = 2*MAXLINE;
+ }
+ }
+ }
+ _TIFFmemcpy(ascii85buf, p, n);
+ ascii85count = n;
+ }
+}
+
+void
+Ascii85Flush(FILE* fd)
+{
+ if (ascii85count > 0) {
+ char* res;
+ _TIFFmemset(&ascii85buf[ascii85count], 0, 3);
+ res = Ascii85Encode(ascii85buf);
+ fwrite(res[0] == 'z' ? "!!!!" : res, ascii85count + 1, 1, fd);
+ }
+ fputs("~>\n", fd);
+}
+#if defined( EXP_ASCII85ENCODER)
+
+#define A85BREAKCNTR ascii85breaklen
+#define A85BREAKLEN (2*MAXLINE)
+
+/*****************************************************************************
+*
+* Name: Ascii85EncodeBlock( ascii85_p, f_eod, raw_p, raw_l )
+*
+* Description: This routine will encode the raw data in the buffer described
+* by raw_p and raw_l into ASCII85 format and store the encoding
+* in the buffer given by ascii85_p.
+*
+* Parameters: ascii85_p - A buffer supplied by the caller which will
+* contain the encoded ASCII85 data.
+* f_eod - Flag: Nz means to end the encoded buffer with
+* an End-Of-Data marker.
+* raw_p - Pointer to the buffer of data to be encoded
+* raw_l - Number of bytes in raw_p[] to be encoded
+*
+* Returns: (int) < 0 Error, see errno
+* >= 0 Number of bytes written to ascii85_p[].
+*
+* Notes: An external variable given by A85BREAKCNTR is used to
+* determine when to insert newline characters into the
+* encoded data. As each byte is placed into ascii85_p this
+* external is decremented. If the variable is decrement to
+* or past zero then a newline is inserted into ascii85_p
+* and the A85BREAKCNTR is then reset to A85BREAKLEN.
+* Note: for efficiency reasons the A85BREAKCNTR variable
+* is not actually checked on *every* character
+* placed into ascii85_p but often only for every
+* 5 characters.
+*
+* THE CALLER IS RESPONSIBLE FOR ENSURING THAT ASCII85_P[] IS
+* SUFFICIENTLY LARGE TO THE ENCODED DATA!
+* You will need at least 5 * (raw_l/4) bytes plus space for
+* newline characters and space for an EOD marker (if
+* requested). A safe calculation is to use 6*(raw_l/4) + 8
+* to size ascii85_p.
+*
+*****************************************************************************/
+
+int Ascii85EncodeBlock( uint8 * ascii85_p, unsigned f_eod, const uint8 * raw_p, int raw_l )
+
+{
+ char ascii85[5]; /* Encoded 5 tuple */
+ int ascii85_l; /* Number of bytes written to ascii85_p[] */
+ int rc; /* Return code */
+ uint32 val32; /* Unencoded 4 tuple */
+
+ ascii85_l = 0; /* Nothing written yet */
+
+ if ( raw_p )
+ {
+ --raw_p; /* Prepare for pre-increment fetches */
+
+ for ( ; raw_l > 3; raw_l -= 4 )
+ {
+ val32 = *(++raw_p) << 24;
+ val32 += *(++raw_p) << 16;
+ val32 += *(++raw_p) << 8;
+ val32 += *(++raw_p);
+
+ if ( val32 == 0 ) /* Special case */
+ {
+ ascii85_p[ascii85_l] = 'z';
+ rc = 1;
+ }
+
+ else
+ {
+ ascii85[4] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[3] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[2] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[1] = (char) ((val32 % 85) + 33);
+ ascii85[0] = (char) ((val32 / 85) + 33);
+
+ _TIFFmemcpy( &ascii85_p[ascii85_l], ascii85, sizeof(ascii85) );
+ rc = sizeof(ascii85);
+ }
+
+ ascii85_l += rc;
+
+ if ( (A85BREAKCNTR -= rc) <= 0 )
+ {
+ ascii85_p[ascii85_l] = '\n';
+ ++ascii85_l;
+ A85BREAKCNTR = A85BREAKLEN;
+ }
+ }
+
+ /*
+ * Output any straggler bytes:
+ */
+
+ if ( raw_l > 0 )
+ {
+ int len; /* Output this many bytes */
+
+ len = raw_l + 1;
+ val32 = *++raw_p << 24; /* Prime the pump */
+
+ if ( --raw_l > 0 ) val32 += *(++raw_p) << 16;
+ if ( --raw_l > 0 ) val32 += *(++raw_p) << 8;
+
+ val32 /= 85;
+
+ ascii85[3] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[2] = (char) ((val32 % 85) + 33);
+ val32 /= 85;
+
+ ascii85[1] = (char) ((val32 % 85) + 33);
+ ascii85[0] = (char) ((val32 / 85) + 33);
+
+ _TIFFmemcpy( &ascii85_p[ascii85_l], ascii85, len );
+ ascii85_l += len;
+ }
+ }
+
+ /*
+ * If requested add an ASCII85 End Of Data marker:
+ */
+
+ if ( f_eod )
+ {
+ ascii85_p[ascii85_l++] = '~';
+ ascii85_p[ascii85_l++] = '>';
+ ascii85_p[ascii85_l++] = '\n';
+ }
+
+ return ( ascii85_l );
+
+} /* Ascii85EncodeBlock() */
+
+#endif /* EXP_ASCII85ENCODER */
+
+
+char* stuff[] = {
+"usage: tiff2ps [options] input.tif ...",
+"where options are:",
+" -1 generate PostScript Level 1 (default)",
+" -2 generate PostScript Level 2",
+" -3 generate PostScript Level 3",
+" -8 disable use of ASCII85 encoding with PostScript Level 2/3",
+" -a convert all directories in file (default is first)",
+" -b # set the bottom margin to # inches",
+" -c center image (-b and -l still add to this)",
+" -d # convert directory number #",
+" -D enable duplex printing (two pages per sheet of paper)",
+" -e generate Encapsulated PostScript (EPS) (implies -z)",
+" -h # assume printed page height is # inches (default 11)",
+" -w # assume printed page width is # inches (default 8.5)",
+" -H # split image if height is more than # inches",
+" -W # split image if width is more than # inches",
+" -L # overLap split images by # inches",
+" -i # enable/disable (Nz/0) pixel interpolation (default: enable)",
+" -l # set the left margin to # inches",
+" -m use \"imagemask\" operator instead of \"image\"",
+" -o # convert directory at file offset #",
+" -O file write PostScript to file instead of standard output",
+" -p generate regular PostScript",
+" -r # or auto rotate by 90, 180, 270 degrees or auto",
+" -s generate PostScript for a single image",
+" -T print pages for top edge binding",
+" -x override resolution units as centimeters",
+" -y override resolution units as inches",
+" -z enable printing in the deadzone (only for PostScript Level 2/3)",
+NULL
+};
+
+static void
+usage(int code)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(code);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiff2rgba.c b/tiff/tools/tiff2rgba.c
new file mode 100644
index 0000000..9ba2877
--- /dev/null
+++ b/tiff/tools/tiff2rgba.c
@@ -0,0 +1,548 @@
+/* $Id: tiff2rgba.c,v 1.13.2.3 2010-06-12 02:55:16 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1991-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffiop.h"
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#define roundup(x, y) (howmany(x,y)*((uint32)(y)))
+
+uint16 compression = COMPRESSION_PACKBITS;
+uint32 rowsperstrip = (uint32) -1;
+int process_by_block = 0; /* default is whole image at once */
+int no_alpha = 0;
+
+
+static int tiffcvt(TIFF* in, TIFF* out);
+static void usage(int code);
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *in, *out;
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "c:r:t:bn")) != -1)
+ switch (c) {
+ case 'b':
+ process_by_block = 1;
+ break;
+
+ case 'c':
+ if (streq(optarg, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(optarg, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (streq(optarg, "lzw"))
+ compression = COMPRESSION_LZW;
+ else if (streq(optarg, "jpeg"))
+ compression = COMPRESSION_JPEG;
+ else if (streq(optarg, "zip"))
+ compression = COMPRESSION_DEFLATE;
+ else
+ usage(-1);
+ break;
+
+ case 'r':
+ rowsperstrip = atoi(optarg);
+ break;
+
+ case 't':
+ rowsperstrip = atoi(optarg);
+ break;
+
+ case 'n':
+ no_alpha = 1;
+ break;
+
+ case '?':
+ usage(0);
+ /*NOTREACHED*/
+ }
+
+ if (argc - optind < 2)
+ usage(-1);
+
+ out = TIFFOpen(argv[argc-1], "w");
+ if (out == NULL)
+ return (-2);
+
+ for (; optind < argc-1; optind++) {
+ in = TIFFOpen(argv[optind], "r");
+ if (in != NULL) {
+ do {
+ if (!tiffcvt(in, out) ||
+ !TIFFWriteDirectory(out)) {
+ (void) TIFFClose(out);
+ return (1);
+ }
+ } while (TIFFReadDirectory(in));
+ (void) TIFFClose(in);
+ }
+ }
+ (void) TIFFClose(out);
+ return (0);
+}
+
+#define multiply(a,b) TIFFSafeMultiply(tsize_t,a,b)
+
+static int
+cvt_by_tile( TIFF *in, TIFF *out )
+
+{
+ uint32* raster; /* retrieve RGBA image */
+ uint32 width, height; /* image width & height */
+ uint32 tile_width, tile_height;
+ uint32 row, col;
+ uint32 *wrk_line;
+ tsize_t raster_size;
+ int ok = 1;
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+
+ if( !TIFFGetField(in, TIFFTAG_TILEWIDTH, &tile_width)
+ || !TIFFGetField(in, TIFFTAG_TILELENGTH, &tile_height) ) {
+ TIFFError(TIFFFileName(in), "Source image not tiled");
+ return (0);
+ }
+
+ TIFFSetField(out, TIFFTAG_TILEWIDTH, tile_width );
+ TIFFSetField(out, TIFFTAG_TILELENGTH, tile_height );
+
+ /*
+ * Allocate tile buffer
+ */
+ raster_size = multiply(multiply(tile_width, tile_height), sizeof (uint32));
+ if (!raster_size) {
+ TIFFError(TIFFFileName(in),
+ "Can't allocate buffer for raster of size %lux%lu",
+ (unsigned long) tile_width, (unsigned long) tile_height);
+ return (0);
+ }
+ raster = (uint32*)_TIFFmalloc(raster_size);
+ if (raster == 0) {
+ TIFFError(TIFFFileName(in), "No space for raster buffer");
+ return (0);
+ }
+
+ /*
+ * Allocate a scanline buffer for swapping during the vertical
+ * mirroring pass. (Request can't overflow given prior checks.)
+ */
+ wrk_line = (uint32*)_TIFFmalloc(tile_width * sizeof (uint32));
+ if (!wrk_line) {
+ TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
+ ok = 0;
+ }
+
+ /*
+ * Loop over the tiles.
+ */
+ for( row = 0; ok && row < height; row += tile_height )
+ {
+ for( col = 0; ok && col < width; col += tile_width )
+ {
+ uint32 i_row;
+
+ /* Read the tile into an RGBA array */
+ if (!TIFFReadRGBATile(in, col, row, raster)) {
+ ok = 0;
+ break;
+ }
+
+
+ /*
+ * XXX: raster array has 4-byte unsigned integer type, that is why
+ * we should rearrange it here.
+ */
+#if HOST_BIGENDIAN
+ TIFFSwabArrayOfLong(raster, tile_width * tile_height);
+#endif
+
+ /*
+ * For some reason the TIFFReadRGBATile() function chooses the
+ * lower left corner as the origin. Vertically mirror scanlines.
+ */
+ for( i_row = 0; i_row < tile_height / 2; i_row++ )
+ {
+ uint32 *top_line, *bottom_line;
+
+ top_line = raster + tile_width * i_row;
+ bottom_line = raster + tile_width * (tile_height-i_row-1);
+
+ _TIFFmemcpy(wrk_line, top_line, 4*tile_width);
+ _TIFFmemcpy(top_line, bottom_line, 4*tile_width);
+ _TIFFmemcpy(bottom_line, wrk_line, 4*tile_width);
+ }
+
+ /*
+ * Write out the result in a tile.
+ */
+
+ if( TIFFWriteEncodedTile( out,
+ TIFFComputeTile( out, col, row, 0, 0),
+ raster,
+ 4 * tile_width * tile_height ) == -1 )
+ {
+ ok = 0;
+ break;
+ }
+ }
+ }
+
+ _TIFFfree( raster );
+ _TIFFfree( wrk_line );
+
+ return ok;
+}
+
+static int
+cvt_by_strip( TIFF *in, TIFF *out )
+
+{
+ uint32* raster; /* retrieve RGBA image */
+ uint32 width, height; /* image width & height */
+ uint32 row;
+ uint32 *wrk_line;
+ tsize_t raster_size;
+ int ok = 1;
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+
+ if( !TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip) ) {
+ TIFFError(TIFFFileName(in), "Source image not in strips");
+ return (0);
+ }
+
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ /*
+ * Allocate strip buffer
+ */
+ raster_size = multiply(multiply(width, rowsperstrip), sizeof (uint32));
+ if (!raster_size) {
+ TIFFError(TIFFFileName(in),
+ "Can't allocate buffer for raster of size %lux%lu",
+ (unsigned long) width, (unsigned long) rowsperstrip);
+ return (0);
+ }
+ raster = (uint32*)_TIFFmalloc(raster_size);
+ if (raster == 0) {
+ TIFFError(TIFFFileName(in), "No space for raster buffer");
+ return (0);
+ }
+
+ /*
+ * Allocate a scanline buffer for swapping during the vertical
+ * mirroring pass. (Request can't overflow given prior checks.)
+ */
+ wrk_line = (uint32*)_TIFFmalloc(width * sizeof (uint32));
+ if (!wrk_line) {
+ TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
+ ok = 0;
+ }
+
+ /*
+ * Loop over the strips.
+ */
+ for( row = 0; ok && row < height; row += rowsperstrip )
+ {
+ int rows_to_write, i_row;
+
+ /* Read the strip into an RGBA array */
+ if (!TIFFReadRGBAStrip(in, row, raster)) {
+ ok = 0;
+ break;
+ }
+
+ /*
+ * XXX: raster array has 4-byte unsigned integer type, that is why
+ * we should rearrange it here.
+ */
+#if HOST_BIGENDIAN
+ TIFFSwabArrayOfLong(raster, width * rowsperstrip);
+#endif
+
+ /*
+ * Figure out the number of scanlines actually in this strip.
+ */
+ if( row + rowsperstrip > height )
+ rows_to_write = height - row;
+ else
+ rows_to_write = rowsperstrip;
+
+ /*
+ * For some reason the TIFFReadRGBAStrip() function chooses the
+ * lower left corner as the origin. Vertically mirror scanlines.
+ */
+
+ for( i_row = 0; i_row < rows_to_write / 2; i_row++ )
+ {
+ uint32 *top_line, *bottom_line;
+
+ top_line = raster + width * i_row;
+ bottom_line = raster + width * (rows_to_write-i_row-1);
+
+ _TIFFmemcpy(wrk_line, top_line, 4*width);
+ _TIFFmemcpy(top_line, bottom_line, 4*width);
+ _TIFFmemcpy(bottom_line, wrk_line, 4*width);
+ }
+
+ /*
+ * Write out the result in a strip
+ */
+
+ if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster,
+ 4 * rows_to_write * width ) == -1 )
+ {
+ ok = 0;
+ break;
+ }
+ }
+
+ _TIFFfree( raster );
+ _TIFFfree( wrk_line );
+
+ return ok;
+}
+
+/*
+ * cvt_whole_image()
+ *
+ * read the whole image into one big RGBA buffer and then write out
+ * strips from that. This is using the traditional TIFFReadRGBAImage()
+ * API that we trust.
+ */
+
+static int
+cvt_whole_image( TIFF *in, TIFF *out )
+
+{
+ uint32* raster; /* retrieve RGBA image */
+ uint32 width, height; /* image width & height */
+ uint32 row;
+ size_t pixel_count;
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+ pixel_count = width * height;
+
+ /* XXX: Check the integer overflow. */
+ if (!width || !height || pixel_count / width != height) {
+ TIFFError(TIFFFileName(in),
+ "Malformed input file; can't allocate buffer for raster of %lux%lu size",
+ (unsigned long)width, (unsigned long)height);
+ return 0;
+ }
+
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+
+ raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32), "raster buffer");
+ if (raster == 0) {
+ TIFFError(TIFFFileName(in), "Requested buffer size is %lu elements %lu each",
+ (unsigned long)pixel_count, (unsigned long)sizeof(uint32));
+ return (0);
+ }
+
+ /* Read the image in one chunk into an RGBA array */
+ if (!TIFFReadRGBAImageOriented(in, width, height, raster,
+ ORIENTATION_TOPLEFT, 0)) {
+ _TIFFfree(raster);
+ return (0);
+ }
+
+ /*
+ * XXX: raster array has 4-byte unsigned integer type, that is why
+ * we should rearrange it here.
+ */
+#if HOST_BIGENDIAN
+ TIFFSwabArrayOfLong(raster, width * height);
+#endif
+
+ /*
+ * Do we want to strip away alpha components?
+ */
+ if (no_alpha)
+ {
+ size_t count = pixel_count;
+ unsigned char *src, *dst;
+
+ src = dst = (unsigned char *) raster;
+ while (count > 0)
+ {
+ *(dst++) = *(src++);
+ *(dst++) = *(src++);
+ *(dst++) = *(src++);
+ src++;
+ count--;
+ }
+ }
+
+ /*
+ * Write out the result in strips
+ */
+ for (row = 0; row < height; row += rowsperstrip)
+ {
+ unsigned char * raster_strip;
+ int rows_to_write;
+ int bytes_per_pixel;
+
+ if (no_alpha)
+ {
+ raster_strip = ((unsigned char *) raster) + 3 * row * width;
+ bytes_per_pixel = 3;
+ }
+ else
+ {
+ raster_strip = (unsigned char *) (raster + row * width);
+ bytes_per_pixel = 4;
+ }
+
+ if( row + rowsperstrip > height )
+ rows_to_write = height - row;
+ else
+ rows_to_write = rowsperstrip;
+
+ if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster_strip,
+ bytes_per_pixel * rows_to_write * width ) == -1 )
+ {
+ _TIFFfree( raster );
+ return 0;
+ }
+ }
+
+ _TIFFfree( raster );
+
+ return 1;
+}
+
+
+static int
+tiffcvt(TIFF* in, TIFF* out)
+{
+ uint32 width, height; /* image width & height */
+ uint16 shortv;
+ float floatv;
+ char *stringv;
+ uint32 longv;
+ uint16 v[1];
+
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
+
+ CopyField(TIFFTAG_SUBFILETYPE, longv);
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+
+ CopyField(TIFFTAG_FILLORDER, shortv);
+ TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+
+ if( no_alpha )
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
+ else
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 4);
+
+ if( !no_alpha )
+ {
+ v[0] = EXTRASAMPLE_ASSOCALPHA;
+ TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v);
+ }
+
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
+ CopyField(TIFFTAG_DOCUMENTNAME, stringv);
+
+ if( process_by_block && TIFFIsTiled( in ) )
+ return( cvt_by_tile( in, out ) );
+ else if( process_by_block )
+ return( cvt_by_strip( in, out ) );
+ else
+ return( cvt_whole_image( in, out ) );
+}
+
+static char* stuff[] = {
+ "usage: tiff2rgba [-c comp] [-r rows] [-b] input... output",
+ "where comp is one of the following compression algorithms:",
+ " jpeg\t\tJPEG encoding",
+ " zip\t\tLempel-Ziv & Welch encoding",
+ " lzw\t\tLempel-Ziv & Welch encoding",
+ " packbits\tPackBits encoding",
+ " none\t\tno compression",
+ "and the other options are:",
+ " -r\trows/strip",
+ " -b (progress by block rather than as a whole image)",
+ " -n don't emit alpha component.",
+ NULL
+};
+
+static void
+usage(int code)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(code);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffcmp.c b/tiff/tools/tiffcmp.c
new file mode 100644
index 0000000..9f73236
--- /dev/null
+++ b/tiff/tools/tiffcmp.c
@@ -0,0 +1,640 @@
+/* $Id: tiffcmp.c,v 1.13.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+static int stopondiff = 1;
+static int stoponfirsttag = 1;
+static uint16 bitspersample = 1;
+static uint16 samplesperpixel = 1;
+static uint16 sampleformat = SAMPLEFORMAT_UINT;
+static uint32 imagewidth;
+static uint32 imagelength;
+
+static void usage(void);
+static int tiffcmp(TIFF*, TIFF*);
+static int cmptags(TIFF*, TIFF*);
+static int ContigCompare(int, uint32, unsigned char*, unsigned char*, int);
+static int SeparateCompare(int, int, uint32, unsigned char*, unsigned char*);
+static void PrintIntDiff(uint32, int, uint32, uint32, uint32);
+static void PrintFloatDiff(uint32, int, uint32, double, double);
+
+static void leof(const char*, uint32, int);
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *tif1, *tif2;
+ int c, dirnum;
+ extern int optind;
+ extern char* optarg;
+
+ while ((c = getopt(argc, argv, "ltz:")) != -1)
+ switch (c) {
+ case 'l':
+ stopondiff = 0;
+ break;
+ case 'z':
+ stopondiff = atoi(optarg);
+ break;
+ case 't':
+ stoponfirsttag = 0;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage();
+ tif1 = TIFFOpen(argv[optind], "r");
+ if (tif1 == NULL)
+ return (-1);
+ tif2 = TIFFOpen(argv[optind+1], "r");
+ if (tif2 == NULL)
+ return (-2);
+ dirnum = 0;
+ while (tiffcmp(tif1, tif2)) {
+ if (!TIFFReadDirectory(tif1)) {
+ if (!TIFFReadDirectory(tif2))
+ break;
+ printf("No more directories for %s\n",
+ TIFFFileName(tif1));
+ return (1);
+ } else if (!TIFFReadDirectory(tif2)) {
+ printf("No more directories for %s\n",
+ TIFFFileName(tif2));
+ return (1);
+ }
+ printf("Directory %d:\n", ++dirnum);
+ }
+
+ TIFFClose(tif1);
+ TIFFClose(tif2);
+ return (0);
+}
+
+char* stuff[] = {
+"usage: tiffcmp [options] file1 file2",
+"where options are:",
+" -l list each byte of image data that differs between the files",
+" -z # list specified number of bytes that differs between the files",
+" -t ignore any differences in directory tags",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+#define checkEOF(tif, row, sample) { \
+ leof(TIFFFileName(tif), row, sample); \
+ goto bad; \
+}
+
+static int CheckShortTag(TIFF*, TIFF*, int, char*);
+static int CheckShort2Tag(TIFF*, TIFF*, int, char*);
+static int CheckShortArrayTag(TIFF*, TIFF*, int, char*);
+static int CheckLongTag(TIFF*, TIFF*, int, char*);
+static int CheckFloatTag(TIFF*, TIFF*, int, char*);
+static int CheckStringTag(TIFF*, TIFF*, int, char*);
+
+static int
+tiffcmp(TIFF* tif1, TIFF* tif2)
+{
+ uint16 config1, config2;
+ tsize_t size1;
+ uint32 row;
+ tsample_t s;
+ unsigned char *buf1, *buf2;
+
+ if (!CheckShortTag(tif1, tif2, TIFFTAG_BITSPERSAMPLE, "BitsPerSample"))
+ return (0);
+ if (!CheckShortTag(tif1, tif2, TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel"))
+ return (0);
+ if (!CheckLongTag(tif1, tif2, TIFFTAG_IMAGEWIDTH, "ImageWidth"))
+ return (0);
+ if (!cmptags(tif1, tif2))
+ return (1);
+ (void) TIFFGetField(tif1, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ (void) TIFFGetField(tif1, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ (void) TIFFGetField(tif1, TIFFTAG_SAMPLEFORMAT, &sampleformat);
+ (void) TIFFGetField(tif1, TIFFTAG_IMAGEWIDTH, &imagewidth);
+ (void) TIFFGetField(tif1, TIFFTAG_IMAGELENGTH, &imagelength);
+ (void) TIFFGetField(tif1, TIFFTAG_PLANARCONFIG, &config1);
+ (void) TIFFGetField(tif2, TIFFTAG_PLANARCONFIG, &config2);
+ buf1 = (unsigned char *)_TIFFmalloc(size1 = TIFFScanlineSize(tif1));
+ buf2 = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif2));
+ if (buf1 == NULL || buf2 == NULL) {
+ fprintf(stderr, "No space for scanline buffers\n");
+ exit(-1);
+ }
+ if (config1 != config2 && bitspersample != 8 && samplesperpixel > 1) {
+ fprintf(stderr,
+"Can't handle different planar configuration w/ different bits/sample\n");
+ goto bad;
+ }
+#define pack(a,b) ((a)<<8)|(b)
+ switch (pack(config1, config2)) {
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG):
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
+ checkEOF(tif2, row, -1)
+ for (s = 0; s < samplesperpixel; s++) {
+ if (TIFFReadScanline(tif1, buf1, row, s) < 0)
+ checkEOF(tif1, row, s)
+ if (SeparateCompare(1, s, row, buf2, buf1) < 0)
+ goto bad1;
+ }
+ }
+ break;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE):
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
+ checkEOF(tif1, row, -1)
+ for (s = 0; s < samplesperpixel; s++) {
+ if (TIFFReadScanline(tif2, buf2, row, s) < 0)
+ checkEOF(tif2, row, s)
+ if (SeparateCompare(0, s, row, buf1, buf2) < 0)
+ goto bad1;
+ }
+ }
+ break;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE):
+ for (s = 0; s < samplesperpixel; s++)
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(tif1, buf1, row, s) < 0)
+ checkEOF(tif1, row, s)
+ if (TIFFReadScanline(tif2, buf2, row, s) < 0)
+ checkEOF(tif2, row, s)
+ if (ContigCompare(s, row, buf1, buf2, size1) < 0)
+ goto bad1;
+ }
+ break;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG):
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(tif1, buf1, row, 0) < 0)
+ checkEOF(tif1, row, -1)
+ if (TIFFReadScanline(tif2, buf2, row, 0) < 0)
+ checkEOF(tif2, row, -1)
+ if (ContigCompare(-1, row, buf1, buf2, size1) < 0)
+ goto bad1;
+ }
+ break;
+ }
+ if (buf1) _TIFFfree(buf1);
+ if (buf2) _TIFFfree(buf2);
+ return (1);
+bad:
+ if (stopondiff)
+ exit(1);
+bad1:
+ if (buf1) _TIFFfree(buf1);
+ if (buf2) _TIFFfree(buf2);
+ return (0);
+}
+
+#define CmpShortField(tag, name) \
+ if (!CheckShortTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpShortField2(tag, name) \
+ if (!CheckShort2Tag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpLongField(tag, name) \
+ if (!CheckLongTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpFloatField(tag, name) \
+ if (!CheckFloatTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpStringField(tag, name) \
+ if (!CheckStringTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+#define CmpShortArrayField(tag, name) \
+ if (!CheckShortArrayTag(tif1, tif2, tag, name) && stoponfirsttag) return (0)
+
+static int
+cmptags(TIFF* tif1, TIFF* tif2)
+{
+ CmpLongField(TIFFTAG_SUBFILETYPE, "SubFileType");
+ CmpLongField(TIFFTAG_IMAGEWIDTH, "ImageWidth");
+ CmpLongField(TIFFTAG_IMAGELENGTH, "ImageLength");
+ CmpShortField(TIFFTAG_BITSPERSAMPLE, "BitsPerSample");
+ CmpShortField(TIFFTAG_COMPRESSION, "Compression");
+ CmpShortField(TIFFTAG_PREDICTOR, "Predictor");
+ CmpShortField(TIFFTAG_PHOTOMETRIC, "PhotometricInterpretation");
+ CmpShortField(TIFFTAG_THRESHHOLDING, "Thresholding");
+ CmpShortField(TIFFTAG_FILLORDER, "FillOrder");
+ CmpShortField(TIFFTAG_ORIENTATION, "Orientation");
+ CmpShortField(TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel");
+ CmpShortField(TIFFTAG_MINSAMPLEVALUE, "MinSampleValue");
+ CmpShortField(TIFFTAG_MAXSAMPLEVALUE, "MaxSampleValue");
+ CmpShortField(TIFFTAG_SAMPLEFORMAT, "SampleFormat");
+ CmpFloatField(TIFFTAG_XRESOLUTION, "XResolution");
+ CmpFloatField(TIFFTAG_YRESOLUTION, "YResolution");
+ CmpLongField(TIFFTAG_GROUP3OPTIONS, "Group3Options");
+ CmpLongField(TIFFTAG_GROUP4OPTIONS, "Group4Options");
+ CmpShortField(TIFFTAG_RESOLUTIONUNIT, "ResolutionUnit");
+ CmpShortField(TIFFTAG_PLANARCONFIG, "PlanarConfiguration");
+ CmpLongField(TIFFTAG_ROWSPERSTRIP, "RowsPerStrip");
+ CmpFloatField(TIFFTAG_XPOSITION, "XPosition");
+ CmpFloatField(TIFFTAG_YPOSITION, "YPosition");
+ CmpShortField(TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit");
+ CmpShortField(TIFFTAG_COLORRESPONSEUNIT, "ColorResponseUnit");
+#ifdef notdef
+ { uint16 *graycurve;
+ CmpField(TIFFTAG_GRAYRESPONSECURVE, graycurve);
+ }
+ { uint16 *red, *green, *blue;
+ CmpField3(TIFFTAG_COLORRESPONSECURVE, red, green, blue);
+ }
+ { uint16 *red, *green, *blue;
+ CmpField3(TIFFTAG_COLORMAP, red, green, blue);
+ }
+#endif
+ CmpShortField2(TIFFTAG_PAGENUMBER, "PageNumber");
+ CmpStringField(TIFFTAG_ARTIST, "Artist");
+ CmpStringField(TIFFTAG_IMAGEDESCRIPTION,"ImageDescription");
+ CmpStringField(TIFFTAG_MAKE, "Make");
+ CmpStringField(TIFFTAG_MODEL, "Model");
+ CmpStringField(TIFFTAG_SOFTWARE, "Software");
+ CmpStringField(TIFFTAG_DATETIME, "DateTime");
+ CmpStringField(TIFFTAG_HOSTCOMPUTER, "HostComputer");
+ CmpStringField(TIFFTAG_PAGENAME, "PageName");
+ CmpStringField(TIFFTAG_DOCUMENTNAME, "DocumentName");
+ CmpShortField(TIFFTAG_MATTEING, "Matteing");
+ CmpShortArrayField(TIFFTAG_EXTRASAMPLES,"ExtraSamples");
+ return (1);
+}
+
+static int
+ContigCompare(int sample, uint32 row,
+ unsigned char* p1, unsigned char* p2, int size)
+{
+ uint32 pix;
+ int ppb = 8 / bitspersample;
+ int samples_to_test;
+
+ if (memcmp(p1, p2, size) == 0)
+ return 0;
+
+ samples_to_test = (sample == -1) ? samplesperpixel : 1;
+
+ switch (bitspersample) {
+ case 1: case 2: case 4: case 8:
+ {
+ unsigned char *pix1 = p1, *pix2 = p2;
+
+ for (pix = 0; pix < imagewidth; pix += ppb) {
+ int s;
+
+ for(s = 0; s < samples_to_test; s++) {
+ if (*pix1 != *pix2) {
+ if( sample == -1 )
+ PrintIntDiff(row, s, pix, *pix1, *pix2);
+ else
+ PrintIntDiff(row, sample, pix, *pix1, *pix2);
+ }
+
+ pix1++;
+ pix2++;
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+ uint16 *pix1 = (uint16 *)p1, *pix2 = (uint16 *)p2;
+
+ for (pix = 0; pix < imagewidth; pix++) {
+ int s;
+
+ for(s = 0; s < samples_to_test; s++) {
+ if (*pix1 != *pix2)
+ PrintIntDiff(row, sample, pix, *pix1, *pix2);
+
+ pix1++;
+ pix2++;
+ }
+ }
+ break;
+ }
+ case 32:
+ if (sampleformat == SAMPLEFORMAT_UINT
+ || sampleformat == SAMPLEFORMAT_INT) {
+ uint32 *pix1 = (uint32 *)p1, *pix2 = (uint32 *)p2;
+
+ for (pix = 0; pix < imagewidth; pix++) {
+ int s;
+
+ for(s = 0; s < samples_to_test; s++) {
+ if (*pix1 != *pix2) {
+ PrintIntDiff(row, sample, pix,
+ *pix1, *pix2);
+ }
+
+ pix1++;
+ pix2++;
+ }
+ }
+ } else if (sampleformat == SAMPLEFORMAT_IEEEFP) {
+ float *pix1 = (float *)p1, *pix2 = (float *)p2;
+
+ for (pix = 0; pix < imagewidth; pix++) {
+ int s;
+
+ for(s = 0; s < samples_to_test; s++) {
+ if (fabs(*pix1 - *pix2) < 0.000000000001) {
+ PrintFloatDiff(row, sample, pix,
+ *pix1, *pix2);
+ }
+
+ pix1++;
+ pix2++;
+ }
+ }
+ } else {
+ fprintf(stderr, "Sample format %d is not supported.\n",
+ sampleformat);
+ return -1;
+ }
+ break;
+ default:
+ fprintf(stderr, "Bit depth %d is not supported.\n", bitspersample);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+PrintIntDiff(uint32 row, int sample, uint32 pix, uint32 w1, uint32 w2)
+{
+ if (sample < 0)
+ sample = 0;
+ switch (bitspersample) {
+ case 1:
+ case 2:
+ case 4:
+ {
+ int32 mask1, mask2, s;
+
+ mask1 = ~((-1) << bitspersample);
+ s = (8 - bitspersample);
+ mask2 = mask1 << s;
+ for (; mask2 && pix < imagewidth;
+ mask2 >>= bitspersample, s -= bitspersample, pix++) {
+ if ((w1 & mask2) ^ (w2 & mask2)) {
+ printf(
+ "Scanline %lu, pixel %lu, sample %d: %01x %01x\n",
+ (unsigned long) row,
+ (unsigned long) pix,
+ sample,
+ (unsigned int)((w1 >> s) & mask1),
+ (unsigned int)((w2 >> s) & mask1));
+ if (--stopondiff == 0)
+ exit(1);
+ }
+ }
+ break;
+ }
+ case 8:
+ printf("Scanline %lu, pixel %lu, sample %d: %02x %02x\n",
+ (unsigned long) row, (unsigned long) pix, sample,
+ (unsigned int) w1, (unsigned int) w2);
+ if (--stopondiff == 0)
+ exit(1);
+ break;
+ case 16:
+ printf("Scanline %lu, pixel %lu, sample %d: %04x %04x\n",
+ (unsigned long) row, (unsigned long) pix, sample,
+ (unsigned int) w1, (unsigned int) w2);
+ if (--stopondiff == 0)
+ exit(1);
+ break;
+ case 32:
+ printf("Scanline %lu, pixel %lu, sample %d: %08x %08x\n",
+ (unsigned long) row, (unsigned long) pix, sample,
+ (unsigned int) w1, (unsigned int) w2);
+ if (--stopondiff == 0)
+ exit(1);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+PrintFloatDiff(uint32 row, int sample, uint32 pix, double w1, double w2)
+{
+ if (sample < 0)
+ sample = 0;
+ switch (bitspersample) {
+ case 32:
+ printf("Scanline %lu, pixel %lu, sample %d: %g %g\n",
+ (long) row, (long) pix, sample, w1, w2);
+ if (--stopondiff == 0)
+ exit(1);
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+SeparateCompare(int reversed, int sample, uint32 row,
+ unsigned char* cp1, unsigned char* p2)
+{
+ uint32 npixels = imagewidth;
+ int pixel;
+
+ cp1 += sample;
+ for (pixel = 0; npixels-- > 0; pixel++, cp1 += samplesperpixel, p2++) {
+ if (*cp1 != *p2) {
+ printf("Scanline %lu, pixel %lu, sample %ld: ",
+ (long) row, (long) pixel, (long) sample);
+ if (reversed)
+ printf("%02x %02x\n", *p2, *cp1);
+ else
+ printf("%02x %02x\n", *cp1, *p2);
+ if (--stopondiff == 0)
+ exit(1);
+ }
+ }
+
+ return 0;
+}
+
+static int
+checkTag(TIFF* tif1, TIFF* tif2, int tag, char* name, void* p1, void* p2)
+{
+
+ if (TIFFGetField(tif1, tag, p1)) {
+ if (!TIFFGetField(tif2, tag, p2)) {
+ printf("%s tag appears only in %s\n",
+ name, TIFFFileName(tif1));
+ return (0);
+ }
+ return (1);
+ } else if (TIFFGetField(tif2, tag, p2)) {
+ printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
+ return (0);
+ }
+ return (-1);
+}
+
+#define CHECK(cmp, fmt) { \
+ switch (checkTag(tif1,tif2,tag,name,&v1,&v2)) { \
+ case 1: if (cmp) \
+ case -1: return (1); \
+ printf(fmt, name, v1, v2); \
+ } \
+ return (0); \
+}
+
+static int
+CheckShortTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ uint16 v1, v2;
+ CHECK(v1 == v2, "%s: %u %u\n");
+}
+
+static int
+CheckShort2Tag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ uint16 v11, v12, v21, v22;
+
+ if (TIFFGetField(tif1, tag, &v11, &v12)) {
+ if (!TIFFGetField(tif2, tag, &v21, &v22)) {
+ printf("%s tag appears only in %s\n",
+ name, TIFFFileName(tif1));
+ return (0);
+ }
+ if (v11 == v21 && v12 == v22)
+ return (1);
+ printf("%s: <%u,%u> <%u,%u>\n", name, v11, v12, v21, v22);
+ } else if (TIFFGetField(tif2, tag, &v21, &v22))
+ printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
+ else
+ return (1);
+ return (0);
+}
+
+static int
+CheckShortArrayTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ uint16 n1, *a1;
+ uint16 n2, *a2;
+
+ if (TIFFGetField(tif1, tag, &n1, &a1)) {
+ if (!TIFFGetField(tif2, tag, &n2, &a2)) {
+ printf("%s tag appears only in %s\n",
+ name, TIFFFileName(tif1));
+ return (0);
+ }
+ if (n1 == n2) {
+ char* sep;
+ uint16 i;
+
+ if (memcmp(a1, a2, n1 * sizeof(uint16)) == 0)
+ return (1);
+ printf("%s: value mismatch, <%u:", name, n1);
+ sep = "";
+ for (i = 0; i < n1; i++)
+ printf("%s%u", sep, a1[i]), sep = ",";
+ printf("> and <%u: ", n2);
+ sep = "";
+ for (i = 0; i < n2; i++)
+ printf("%s%u", sep, a2[i]), sep = ",";
+ printf(">\n");
+ } else
+ printf("%s: %u items in %s, %u items in %s", name,
+ n1, TIFFFileName(tif1),
+ n2, TIFFFileName(tif2)
+ );
+ } else if (TIFFGetField(tif2, tag, &n2, &a2))
+ printf("%s tag appears only in %s\n", name, TIFFFileName(tif2));
+ else
+ return (1);
+ return (0);
+}
+
+static int
+CheckLongTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ uint32 v1, v2;
+ CHECK(v1 == v2, "%s: %u %u\n");
+}
+
+static int
+CheckFloatTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ float v1, v2;
+ CHECK(v1 == v2, "%s: %g %g\n");
+}
+
+static int
+CheckStringTag(TIFF* tif1, TIFF* tif2, int tag, char* name)
+{
+ char *v1, *v2;
+ CHECK(strcmp(v1, v2) == 0, "%s: \"%s\" \"%s\"\n");
+}
+
+static void
+leof(const char* name, uint32 row, int s)
+{
+
+ printf("%s: EOF at scanline %lu", name, (unsigned long)row);
+ if (s >= 0)
+ printf(", sample %d", s);
+ printf("\n");
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffcp.c b/tiff/tools/tiffcp.c
new file mode 100644
index 0000000..48319fa
--- /dev/null
+++ b/tiff/tools/tiffcp.c
@@ -0,0 +1,1770 @@
+/* $Id: tiffcp.c,v 1.37.2.8 2010-06-11 20:50:55 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Revised: 2/18/01 BAR -- added syntax for extracting single images from
+ * multi-image TIFF files.
+ *
+ * New syntax is: sourceFileName,image#
+ *
+ * image# ranges from 0..<n-1> where n is the # of images in the file.
+ * There may be no white space between the comma and the filename or
+ * image number.
+ *
+ * Example: tiffcp source.tif,1 destination.tif
+ *
+ * Copies the 2nd image in source.tif to the destination.
+ *
+ *****
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ctype.h>
+#include <assert.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#if defined(VMS)
+# define unlink delete
+#endif
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+#define TRUE 1
+#define FALSE 0
+
+static int outtiled = -1;
+static uint32 tilewidth;
+static uint32 tilelength;
+
+static uint16 config;
+static uint16 compression;
+static uint16 predictor;
+static uint16 fillorder;
+static uint16 orientation;
+static uint32 rowsperstrip;
+static uint32 g3opts;
+static int ignore = FALSE; /* if true, ignore read errors */
+static uint32 defg3opts = (uint32) -1;
+static int quality = 75; /* JPEG quality */
+static int jpegcolormode = JPEGCOLORMODE_RGB;
+static uint16 defcompression = (uint16) -1;
+static uint16 defpredictor = (uint16) -1;
+
+static int tiffcp(TIFF*, TIFF*);
+static int processCompressOptions(char*);
+static void usage(void);
+
+static char comma = ','; /* (default) comma separator character */
+static TIFF* bias = NULL;
+static int pageNum = 0;
+static int pageInSeq = 0;
+
+static int nextSrcImage (TIFF *tif, char **imageSpec)
+/*
+ seek to the next image specified in *imageSpec
+ returns 1 if success, 0 if no more images to process
+ *imageSpec=NULL if subsequent images should be processed in sequence
+*/
+{
+ if (**imageSpec == comma) { /* if not @comma, we've done all images */
+ char *start = *imageSpec + 1;
+ tdir_t nextImage = (tdir_t)strtol(start, imageSpec, 0);
+ if (start == *imageSpec) nextImage = TIFFCurrentDirectory (tif);
+ if (**imageSpec)
+ {
+ if (**imageSpec == comma) {
+ /* a trailing comma denotes remaining images in sequence */
+ if ((*imageSpec)[1] == '\0') *imageSpec = NULL;
+ }else{
+ fprintf (stderr,
+ "Expected a %c separated image # list after %s\n",
+ comma, TIFFFileName (tif));
+ exit (-4); /* syntax error */
+ }
+ }
+ if (TIFFSetDirectory (tif, nextImage)) return 1;
+ fprintf (stderr, "%s%c%d not found!\n",
+ TIFFFileName(tif), comma, (int) nextImage);
+ }
+ return 0;
+}
+
+
+static TIFF* openSrcImage (char **imageSpec)
+/*
+ imageSpec points to a pointer to a filename followed by optional ,image#'s
+ Open the TIFF file and assign *imageSpec to either NULL if there are
+ no images specified, or a pointer to the next image number text
+*/
+{
+ TIFF *tif;
+ char *fn = *imageSpec;
+ *imageSpec = strchr (fn, comma);
+ if (*imageSpec) { /* there is at least one image number specifier */
+ **imageSpec = '\0';
+ tif = TIFFOpen (fn, "r");
+ /* but, ignore any single trailing comma */
+ if (!(*imageSpec)[1]) {*imageSpec = NULL; return tif;}
+ if (tif) {
+ **imageSpec = comma; /* replace the comma */
+ if (!nextSrcImage(tif, imageSpec)) {
+ TIFFClose (tif);
+ tif = NULL;
+ }
+ }
+ }else
+ tif = TIFFOpen (fn, "r");
+ return tif;
+}
+
+
+int
+main(int argc, char* argv[])
+{
+ uint16 defconfig = (uint16) -1;
+ uint16 deffillorder = 0;
+ uint32 deftilewidth = (uint32) -1;
+ uint32 deftilelength = (uint32) -1;
+ uint32 defrowsperstrip = (uint32) 0;
+ uint32 diroff = 0;
+ TIFF* in;
+ TIFF* out;
+ char mode[10];
+ char* mp = mode;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ *mp++ = 'w';
+ *mp = '\0';
+ while ((c = getopt(argc, argv, ",:b:c:f:l:o:z:p:r:w:aistBLMCx")) != -1)
+ switch (c) {
+ case ',':
+ if (optarg[0] != '=') usage();
+ comma = optarg[1];
+ break;
+ case 'b': /* this file is bias image subtracted from others */
+ if (bias) {
+ fputs ("Only 1 bias image may be specified\n", stderr);
+ exit (-2);
+ }
+ {
+ uint16 samples = (uint16) -1;
+ char **biasFn = &optarg;
+ bias = openSrcImage (biasFn);
+ if (!bias) exit (-5);
+ if (TIFFIsTiled (bias)) {
+ fputs ("Bias image must be organized in strips\n", stderr);
+ exit (-7);
+ }
+ TIFFGetField(bias, TIFFTAG_SAMPLESPERPIXEL, &samples);
+ if (samples != 1) {
+ fputs ("Bias image must be monochrome\n", stderr);
+ exit (-7);
+ }
+ }
+ break;
+ case 'a': /* append to output */
+ mode[0] = 'a';
+ break;
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'f': /* fill order */
+ if (streq(optarg, "lsb2msb"))
+ deffillorder = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ deffillorder = FILLORDER_MSB2LSB;
+ else
+ usage();
+ break;
+ case 'i': /* ignore errors */
+ ignore = TRUE;
+ break;
+ case 'l': /* tile length */
+ outtiled = TRUE;
+ deftilelength = atoi(optarg);
+ break;
+ case 'o': /* initial directory offset */
+ diroff = strtoul(optarg, NULL, 0);
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ defconfig = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ defconfig = PLANARCONFIG_CONTIG;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ defrowsperstrip = atol(optarg);
+ break;
+ case 's': /* generate stripped output */
+ outtiled = FALSE;
+ break;
+ case 't': /* generate tiled output */
+ outtiled = TRUE;
+ break;
+ case 'w': /* tile width */
+ outtiled = TRUE;
+ deftilewidth = atoi(optarg);
+ break;
+ case 'B':
+ *mp++ = 'b'; *mp = '\0';
+ break;
+ case 'L':
+ *mp++ = 'l'; *mp = '\0';
+ break;
+ case 'M':
+ *mp++ = 'm'; *mp = '\0';
+ break;
+ case 'C':
+ *mp++ = 'c'; *mp = '\0';
+ break;
+ case 'x':
+ pageInSeq = 1;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage();
+ out = TIFFOpen(argv[argc-1], mode);
+ if (out == NULL)
+ return (-2);
+ if ((argc - optind) == 2)
+ pageNum = -1;
+ for (; optind < argc-1 ; optind++) {
+ char *imageCursor = argv[optind];
+ in = openSrcImage (&imageCursor);
+ if (in == NULL) {
+ (void) TIFFClose(out);
+ return (-3);
+ }
+ if (diroff != 0 && !TIFFSetSubDirectory(in, diroff)) {
+ TIFFError(TIFFFileName(in),
+ "Error, setting subdirectory at %#x", diroff);
+ (void) TIFFClose(in);
+ (void) TIFFClose(out);
+ return (1);
+ }
+ for (;;) {
+ config = defconfig;
+ compression = defcompression;
+ predictor = defpredictor;
+ fillorder = deffillorder;
+ rowsperstrip = defrowsperstrip;
+ tilewidth = deftilewidth;
+ tilelength = deftilelength;
+ g3opts = defg3opts;
+ if (!tiffcp(in, out) || !TIFFWriteDirectory(out)) {
+ (void) TIFFClose(in);
+ (void) TIFFClose(out);
+ return (1);
+ }
+ if (imageCursor) { /* seek next image directory */
+ if (!nextSrcImage(in, &imageCursor)) break;
+ }else
+ if (!TIFFReadDirectory(in)) break;
+ }
+ (void) TIFFClose(in);
+ }
+
+ (void) TIFFClose(out);
+ return (0);
+}
+
+
+static void
+processG3Options(char* cp)
+{
+ if( (cp = strchr(cp, ':')) ) {
+ if (defg3opts == (uint32) -1)
+ defg3opts = 0;
+ do {
+ cp++;
+ if (strneq(cp, "1d", 2))
+ defg3opts &= ~GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "2d", 2))
+ defg3opts |= GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "fill", 4))
+ defg3opts |= GROUP3OPT_FILLBITS;
+ else
+ usage();
+ } while( (cp = strchr(cp, ':')) );
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none")) {
+ defcompression = COMPRESSION_NONE;
+ } else if (streq(opt, "packbits")) {
+ defcompression = COMPRESSION_PACKBITS;
+ } else if (strneq(opt, "jpeg", 4)) {
+ char* cp = strchr(opt, ':');
+
+ defcompression = COMPRESSION_JPEG;
+ while( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else
+ usage();
+
+ cp = strchr(cp+1,':');
+ }
+ } else if (strneq(opt, "g3", 2)) {
+ processG3Options(opt);
+ defcompression = COMPRESSION_CCITTFAX3;
+ } else if (streq(opt, "g4")) {
+ defcompression = COMPRESSION_CCITTFAX4;
+ } else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ defpredictor = atoi(cp+1);
+ defcompression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ defpredictor = atoi(cp+1);
+ defcompression = COMPRESSION_ADOBE_DEFLATE;
+ } else if (strneq(opt, "jbig", 4)) {
+ defcompression = COMPRESSION_JBIG;
+ } else
+ return (0);
+ return (1);
+}
+
+char* stuff[] = {
+"usage: tiffcp [options] input... output",
+"where options are:",
+" -a append to output instead of overwriting",
+" -o offset set initial directory offset",
+" -p contig pack samples contiguously (e.g. RGBRGB...)",
+" -p separate store samples separately (e.g. RRR...GGG...BBB...)",
+" -s write output in strips",
+" -t write output in tiles",
+" -i ignore read errors",
+" -b file[,#] bias (dark) monochrome image to be subtracted from all others",
+" -,=% use % rather than , to separate image #'s (per Note below)",
+"",
+" -r # make each strip have no more than # rows",
+" -w # set output tile width (pixels)",
+" -l # set output tile length (pixels)",
+"",
+" -f lsb2msb force lsb-to-msb FillOrder for output",
+" -f msb2lsb force msb-to-lsb FillOrder for output",
+"",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c jbig compress output with ISO JBIG encoding",
+" -c packbits compress output with packbits encoding",
+" -c g3[:opts] compress output with CCITT Group 3 encoding",
+" -c g4 compress output with CCITT Group 4 encoding",
+" -c none use no compression algorithm on output",
+"",
+"Group 3 options:",
+" 1d use default CCITT Group 3 1D-encoding",
+" 2d use optional CCITT Group 3 2D-encoding",
+" fill byte-align EOL codes",
+"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
+"",
+"JPEG options:",
+" # set compression quality level (0-100, default 75)",
+" r output color image as RGB rather than YCbCr",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+"",
+"Note that input filenames may be of the form filename,x,y,z",
+"where x, y, and z specify image numbers in the filename to copy.",
+"example: tiffcp -c none -b esp.tif,1 esp.tif,0 test.tif",
+" subtract 2nd image in esp.tif from 1st yielding uncompressed result test.tif",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, (uint16) -1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES,(uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_EXTRASAMPLES, (uint16) -1, TIFF_SHORT },
+ { TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_STONITS, 1, TIFF_DOUBLE },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+#define CopyTag(tag, count, type) cpTag(in, out, tag, count, type)
+
+typedef int (*copyFunc)
+ (TIFF* in, TIFF* out, uint32 l, uint32 w, uint16 samplesperpixel);
+static copyFunc pickCopyFunc(TIFF*, TIFF*, uint16, uint16);
+
+static int
+tiffcp(TIFF* in, TIFF* out)
+{
+ uint16 bitspersample, samplesperpixel;
+ uint16 input_compression, input_photometric;
+ copyFunc cf;
+ uint32 width, length;
+ struct cpTag* p;
+
+ CopyField(TIFFTAG_IMAGEWIDTH, width);
+ CopyField(TIFFTAG_IMAGELENGTH, length);
+ CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample);
+ CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
+ if (compression != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ else
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ TIFFGetFieldDefaulted(in, TIFFTAG_COMPRESSION, &input_compression);
+ TIFFGetFieldDefaulted(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
+ if (input_compression == COMPRESSION_JPEG) {
+ /* Force conversion to RGB */
+ TIFFSetField(in, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ } else if (input_photometric == PHOTOMETRIC_YCBCR) {
+ /* Otherwise, can't handle subsampled input */
+ uint16 subsamplinghor,subsamplingver;
+
+ TIFFGetFieldDefaulted(in, TIFFTAG_YCBCRSUBSAMPLING,
+ &subsamplinghor, &subsamplingver);
+ if (subsamplinghor!=1 || subsamplingver!=1) {
+ fprintf(stderr, "tiffcp: %s: Can't copy/convert subsampled image.\n",
+ TIFFFileName(in));
+ return FALSE;
+ }
+ }
+ if (compression == COMPRESSION_JPEG) {
+ if (input_photometric == PHOTOMETRIC_RGB &&
+ jpegcolormode == JPEGCOLORMODE_RGB)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
+ }
+ else if (compression == COMPRESSION_SGILOG
+ || compression == COMPRESSION_SGILOG24)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC,
+ samplesperpixel == 1 ?
+ PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
+ else
+ CopyTag(TIFFTAG_PHOTOMETRIC, 1, TIFF_SHORT);
+ if (fillorder != 0)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ else
+ CopyTag(TIFFTAG_FILLORDER, 1, TIFF_SHORT);
+ /*
+ * Will copy `Orientation' tag from input image
+ */
+ TIFFGetFieldDefaulted(in, TIFFTAG_ORIENTATION, &orientation);
+ switch (orientation) {
+ case ORIENTATION_BOTRIGHT:
+ case ORIENTATION_RIGHTBOT: /* XXX */
+ TIFFWarning(TIFFFileName(in), "using bottom-left orientation");
+ orientation = ORIENTATION_BOTLEFT;
+ /* fall thru... */
+ case ORIENTATION_LEFTBOT: /* XXX */
+ case ORIENTATION_BOTLEFT:
+ break;
+ case ORIENTATION_TOPRIGHT:
+ case ORIENTATION_RIGHTTOP: /* XXX */
+ default:
+ TIFFWarning(TIFFFileName(in), "using top-left orientation");
+ orientation = ORIENTATION_TOPLEFT;
+ /* fall thru... */
+ case ORIENTATION_LEFTTOP: /* XXX */
+ case ORIENTATION_TOPLEFT:
+ break;
+ }
+ TIFFSetField(out, TIFFTAG_ORIENTATION, orientation);
+ /*
+ * Choose tiles/strip for the output image according to
+ * the command line arguments (-tiles, -strips) and the
+ * structure of the input image.
+ */
+ if (outtiled == -1)
+ outtiled = TIFFIsTiled(in);
+ if (outtiled) {
+ /*
+ * Setup output file's tile width&height. If either
+ * is not specified, use either the value from the
+ * input image or, if nothing is defined, use the
+ * library default.
+ */
+ if (tilewidth == (uint32) -1)
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);
+ if (tilelength == (uint32) -1)
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);
+ TIFFDefaultTileSize(out, &tilewidth, &tilelength);
+ TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);
+ TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);
+ } else {
+ /*
+ * RowsPerStrip is left unspecified: use either the
+ * value from the input image or, if nothing is defined,
+ * use the library default.
+ */
+ if (rowsperstrip == (uint32) 0) {
+ if (!TIFFGetField(in, TIFFTAG_ROWSPERSTRIP,
+ &rowsperstrip)) {
+ rowsperstrip =
+ TIFFDefaultStripSize(out, rowsperstrip);
+ }
+ if (rowsperstrip > length && rowsperstrip != (uint32)-1)
+ rowsperstrip = length;
+ }
+ else if (rowsperstrip == (uint32) -1)
+ rowsperstrip = length;
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ }
+ if (config != (uint16) -1)
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ else
+ CopyField(TIFFTAG_PLANARCONFIG, config);
+ if (samplesperpixel <= 4)
+ CopyTag(TIFFTAG_TRANSFERFUNCTION, 4, TIFF_SHORT);
+ CopyTag(TIFFTAG_COLORMAP, 4, TIFF_SHORT);
+/* SMinSampleValue & SMaxSampleValue */
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode);
+ break;
+ case COMPRESSION_JBIG:
+ CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
+ CopyTag(TIFFTAG_FAXDCS, 1, TIFF_ASCII);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_ADOBE_DEFLATE:
+ case COMPRESSION_DEFLATE:
+ if (predictor != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ else
+ CopyField(TIFFTAG_PREDICTOR, predictor);
+ break;
+ case COMPRESSION_CCITTFAX3:
+ case COMPRESSION_CCITTFAX4:
+ if (compression == COMPRESSION_CCITTFAX3) {
+ if (g3opts != (uint32) -1)
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS,
+ g3opts);
+ else
+ CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);
+ } else
+ CopyTag(TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_BADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CLEANFAXDATA, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
+ break;
+ }
+ { uint32 len32;
+ void** data;
+ if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &len32, &data))
+ TIFFSetField(out, TIFFTAG_ICCPROFILE, len32, data);
+ }
+ { uint16 ninks;
+ const char* inknames;
+ if (TIFFGetField(in, TIFFTAG_NUMBEROFINKS, &ninks)) {
+ TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks);
+ if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) {
+ int inknameslen = strlen(inknames) + 1;
+ const char* cp = inknames;
+ while (ninks > 1) {
+ cp = strchr(cp, '\0');
+ if (cp) {
+ cp++;
+ inknameslen += (strlen(cp) + 1);
+ }
+ ninks--;
+ }
+ TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames);
+ }
+ }
+ }
+ {
+ unsigned short pg0, pg1;
+ if(pageInSeq == 1) {
+ if (pageNum < 0) /* only one input file */ {
+ if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1))
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
+ } else
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
+ } else
+ if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1)) {
+ if (pageNum < 0) /* only one input file */
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
+ else
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
+ }
+ }
+
+ for (p = tags; p < &tags[NTAGS]; p++)
+ CopyTag(p->tag, p->count, p->type);
+
+ cf = pickCopyFunc(in, out, bitspersample, samplesperpixel);
+ return (cf ? (*cf)(in, out, length, width, samplesperpixel) : FALSE);
+}
+
+/*
+ * Copy Functions.
+ */
+#define DECLAREcpFunc(x) \
+static int x(TIFF* in, TIFF* out, \
+ uint32 imagelength, uint32 imagewidth, tsample_t spp)
+
+#define DECLAREreadFunc(x) \
+static int x(TIFF* in, \
+ uint8* buf, uint32 imagelength, uint32 imagewidth, tsample_t spp)
+typedef int (*readFunc)(TIFF*, uint8*, uint32, uint32, tsample_t);
+
+#define DECLAREwriteFunc(x) \
+static int x(TIFF* out, \
+ uint8* buf, uint32 imagelength, uint32 imagewidth, tsample_t spp)
+typedef int (*writeFunc)(TIFF*, uint8*, uint32, uint32, tsample_t);
+
+/*
+ * Contig -> contig by scanline for rows/strip change.
+ */
+DECLAREcpFunc(cpContig2ContigByRow)
+{
+ tdata_t buf = _TIFFmalloc(TIFFScanlineSize(in));
+ uint32 row;
+
+ (void) imagewidth; (void) spp;
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, buf, row, 0) < 0 && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ if (TIFFWriteScanline(out, buf, row, 0) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+ _TIFFfree(buf);
+ return 1;
+bad:
+ _TIFFfree(buf);
+ return 0;
+}
+
+
+typedef void biasFn (void *image, void *bias, uint32 pixels);
+
+#define subtract(bits) \
+static void subtract##bits (void *i, void *b, uint32 pixels)\
+{\
+ uint##bits *image = i;\
+ uint##bits *bias = b;\
+ while (pixels--) {\
+ *image = *image > *bias ? *image-*bias : 0;\
+ image++, bias++; \
+ } \
+}
+
+subtract(8)
+subtract(16)
+subtract(32)
+
+static biasFn *lineSubtractFn (unsigned bits)
+{
+ switch (bits) {
+ case 8: return subtract8;
+ case 16: return subtract16;
+ case 32: return subtract32;
+ }
+ return NULL;
+}
+
+/*
+ * Contig -> contig by scanline while subtracting a bias image.
+ */
+DECLAREcpFunc(cpBiasedContig2Contig)
+{
+ if (spp == 1) {
+ tsize_t biasSize = TIFFScanlineSize(bias);
+ tsize_t bufSize = TIFFScanlineSize(in);
+ tdata_t buf, biasBuf;
+ uint32 biasWidth = 0, biasLength = 0;
+ TIFFGetField(bias, TIFFTAG_IMAGEWIDTH, &biasWidth);
+ TIFFGetField(bias, TIFFTAG_IMAGELENGTH, &biasLength);
+ if (biasSize == bufSize &&
+ imagelength == biasLength && imagewidth == biasWidth) {
+ uint16 sampleBits = 0;
+ biasFn *subtractLine;
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &sampleBits);
+ subtractLine = lineSubtractFn (sampleBits);
+ if (subtractLine) {
+ uint32 row;
+ buf = _TIFFmalloc(bufSize);
+ biasBuf = _TIFFmalloc(bufSize);
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, buf, row, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ if (TIFFReadScanline(bias, biasBuf, row, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read biased scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ subtractLine (buf, biasBuf, imagewidth);
+ if (TIFFWriteScanline(out, buf, row, 0) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+
+ _TIFFfree(buf);
+ _TIFFfree(biasBuf);
+ TIFFSetDirectory(bias,
+ TIFFCurrentDirectory(bias)); /* rewind */
+ return 1;
+bad:
+ _TIFFfree(buf);
+ _TIFFfree(biasBuf);
+ return 0;
+ } else {
+ TIFFError(TIFFFileName(in),
+ "No support for biasing %d bit pixels\n",
+ sampleBits);
+ return 0;
+ }
+ }
+ TIFFError(TIFFFileName(in),
+ "Bias image %s,%d\nis not the same size as %s,%d\n",
+ TIFFFileName(bias), TIFFCurrentDirectory(bias),
+ TIFFFileName(in), TIFFCurrentDirectory(in));
+ return 0;
+ } else {
+ TIFFError(TIFFFileName(in),
+ "Can't bias %s,%d as it has >1 Sample/Pixel\n",
+ TIFFFileName(in), TIFFCurrentDirectory(in));
+ return 0;
+ }
+
+}
+
+
+/*
+ * Strip -> strip for change in encoding.
+ */
+DECLAREcpFunc(cpDecodedStrips)
+{
+ tsize_t stripsize = TIFFStripSize(in);
+ tdata_t buf = _TIFFmalloc(stripsize);
+
+ (void) imagewidth; (void) spp;
+ if (buf) {
+ tstrip_t s, ns = TIFFNumberOfStrips(in);
+ uint32 row = 0;
+ for (s = 0; s < ns; s++) {
+ tsize_t cc = (row + rowsperstrip > imagelength) ?
+ TIFFVStripSize(in, imagelength - row) : stripsize;
+ if (TIFFReadEncodedStrip(in, s, buf, cc) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read strip %lu",
+ (unsigned long) s);
+ goto bad;
+ }
+ if (TIFFWriteEncodedStrip(out, s, buf, cc) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write strip %lu",
+ (unsigned long) s);
+ goto bad;
+ }
+ row += rowsperstrip;
+ }
+ _TIFFfree(buf);
+ return 1;
+ } else {
+ TIFFError(TIFFFileName(in),
+ "Error, can't allocate memory buffer of size %lu "
+ "to read strips", (unsigned long) stripsize);
+ return 0;
+ }
+
+bad:
+ _TIFFfree(buf);
+ return 0;
+}
+
+/*
+ * Separate -> separate by row for rows/strip change.
+ */
+DECLAREcpFunc(cpSeparate2SeparateByRow)
+{
+ tdata_t buf = _TIFFmalloc(TIFFScanlineSize(in));
+ uint32 row;
+ tsample_t s;
+
+ (void) imagewidth;
+ for (s = 0; s < spp; s++) {
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, buf, row, s) < 0 && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ if (TIFFWriteScanline(out, buf, row, s) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+ }
+ _TIFFfree(buf);
+ return 1;
+bad:
+ _TIFFfree(buf);
+ return 0;
+}
+
+/*
+ * Contig -> separate by row.
+ */
+DECLAREcpFunc(cpContig2SeparateByRow)
+{
+ tdata_t inbuf = _TIFFmalloc(TIFFScanlineSize(in));
+ tdata_t outbuf = _TIFFmalloc(TIFFScanlineSize(out));
+ register uint8 *inp, *outp;
+ register uint32 n;
+ uint32 row;
+ tsample_t s;
+
+ /* unpack channels */
+ for (s = 0; s < spp; s++) {
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, inbuf, row, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ inp = ((uint8*)inbuf) + s;
+ outp = (uint8*)outbuf;
+ for (n = imagewidth; n-- > 0;) {
+ *outp++ = *inp;
+ inp += spp;
+ }
+ if (TIFFWriteScanline(out, outbuf, row, s) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+ }
+ if (inbuf) _TIFFfree(inbuf);
+ if (outbuf) _TIFFfree(outbuf);
+ return 1;
+bad:
+ if (inbuf) _TIFFfree(inbuf);
+ if (outbuf) _TIFFfree(outbuf);
+ return 0;
+}
+
+/*
+ * Separate -> contig by row.
+ */
+DECLAREcpFunc(cpSeparate2ContigByRow)
+{
+ tdata_t inbuf = _TIFFmalloc(TIFFScanlineSize(in));
+ tdata_t outbuf = _TIFFmalloc(TIFFScanlineSize(out));
+ register uint8 *inp, *outp;
+ register uint32 n;
+ uint32 row;
+ tsample_t s;
+
+ for (row = 0; row < imagelength; row++) {
+ /* merge channels */
+ for (s = 0; s < spp; s++) {
+ if (TIFFReadScanline(in, inbuf, row, s) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ inp = (uint8*)inbuf;
+ outp = ((uint8*)outbuf) + s;
+ for (n = imagewidth; n-- > 0;) {
+ *outp = *inp++;
+ outp += spp;
+ }
+ }
+ if (TIFFWriteScanline(out, outbuf, row, 0) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write scanline %lu",
+ (unsigned long) row);
+ goto bad;
+ }
+ }
+ if (inbuf) _TIFFfree(inbuf);
+ if (outbuf) _TIFFfree(outbuf);
+ return 1;
+bad:
+ if (inbuf) _TIFFfree(inbuf);
+ if (outbuf) _TIFFfree(outbuf);
+ return 0;
+}
+
+static void
+cpStripToTile(uint8* out, uint8* in,
+ uint32 rows, uint32 cols, int outskew, int inskew)
+{
+ while (rows-- > 0) {
+ uint32 j = cols;
+ while (j-- > 0)
+ *out++ = *in++;
+ out += outskew;
+ in += inskew;
+ }
+}
+
+static void
+cpContigBufToSeparateBuf(uint8* out, uint8* in,
+ uint32 rows, uint32 cols, int outskew, int inskew, tsample_t spp,
+ int bytes_per_sample )
+{
+ while (rows-- > 0) {
+ uint32 j = cols;
+ while (j-- > 0)
+ {
+ int n = bytes_per_sample;
+
+ while( n-- ) {
+ *out++ = *in++;
+ }
+ in += (spp-1) * bytes_per_sample;
+ }
+ out += outskew;
+ in += inskew;
+ }
+}
+
+static void
+cpSeparateBufToContigBuf(uint8* out, uint8* in,
+ uint32 rows, uint32 cols, int outskew, int inskew, tsample_t spp,
+ int bytes_per_sample)
+{
+ while (rows-- > 0) {
+ uint32 j = cols;
+ while (j-- > 0) {
+ int n = bytes_per_sample;
+
+ while( n-- ) {
+ *out++ = *in++;
+ }
+ out += (spp-1)*bytes_per_sample;
+ }
+ out += outskew;
+ in += inskew;
+ }
+}
+
+static int
+cpImage(TIFF* in, TIFF* out, readFunc fin, writeFunc fout,
+ uint32 imagelength, uint32 imagewidth, tsample_t spp)
+{
+ int status = 0;
+ tdata_t buf = NULL;
+ tsize_t scanlinesize = TIFFRasterScanlineSize(in);
+ tsize_t bytes = scanlinesize * (tsize_t)imagelength;
+ /*
+ * XXX: Check for integer overflow.
+ */
+ if (scanlinesize
+ && imagelength
+ && bytes / (tsize_t)imagelength == scanlinesize) {
+ buf = _TIFFmalloc(bytes);
+ if (buf) {
+ if ((*fin)(in, (uint8*)buf, imagelength,
+ imagewidth, spp)) {
+ status = (*fout)(out, (uint8*)buf,
+ imagelength, imagewidth, spp);
+ }
+ _TIFFfree(buf);
+ } else {
+ TIFFError(TIFFFileName(in),
+ "Error, can't allocate space for image buffer");
+ }
+ } else {
+ TIFFError(TIFFFileName(in), "Error, no space for image buffer");
+ }
+
+ return status;
+}
+
+DECLAREreadFunc(readContigStripsIntoBuffer)
+{
+ tsize_t scanlinesize = TIFFScanlineSize(in);
+ uint8* bufp = buf;
+ uint32 row;
+
+ (void) imagewidth; (void) spp;
+ for (row = 0; row < imagelength; row++) {
+ if (TIFFReadScanline(in, (tdata_t) bufp, row, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ return 0;
+ }
+ bufp += scanlinesize;
+ }
+
+ return 1;
+}
+
+DECLAREreadFunc(readSeparateStripsIntoBuffer)
+{
+ int status = 1;
+ tsize_t scanlinesize = TIFFScanlineSize(in);
+ tdata_t scanline = _TIFFmalloc(scanlinesize);
+ if (!scanlinesize)
+ return 0;
+
+ (void) imagewidth;
+ if (scanline) {
+ uint8* bufp = (uint8*) buf;
+ uint32 row;
+ tsample_t s;
+ for (row = 0; row < imagelength; row++) {
+ /* merge channels */
+ for (s = 0; s < spp; s++) {
+ uint8* bp = bufp + s;
+ tsize_t n = scanlinesize;
+ uint8* sbuf = scanline;
+
+ if (TIFFReadScanline(in, scanline, row, s) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read scanline %lu",
+ (unsigned long) row);
+ status = 0;
+ goto done;
+ }
+ while (n-- > 0)
+ *bp = *sbuf++, bp += spp;
+ }
+ bufp += scanlinesize * spp;
+ }
+ }
+
+done:
+ _TIFFfree(scanline);
+ return status;
+}
+
+DECLAREreadFunc(readContigTilesIntoBuffer)
+{
+ int status = 1;
+ tdata_t tilebuf = _TIFFmalloc(TIFFTileSize(in));
+ uint32 imagew = TIFFScanlineSize(in);
+ uint32 tilew = TIFFTileRowSize(in);
+ int iskew = imagew - tilew;
+ uint8* bufp = (uint8*) buf;
+ uint32 tw, tl;
+ uint32 row;
+
+ (void) spp;
+ if (tilebuf == 0)
+ return 0;
+ (void) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
+ (void) TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
+
+ for (row = 0; row < imagelength; row += tl) {
+ uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
+ uint32 colb = 0;
+ uint32 col;
+
+ for (col = 0; col < imagewidth; col += tw) {
+ if (TIFFReadTile(in, tilebuf, col, row, 0, 0) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read tile at %lu %lu",
+ (unsigned long) col,
+ (unsigned long) row);
+ status = 0;
+ goto done;
+ }
+ if (colb + tilew > imagew) {
+ uint32 width = imagew - colb;
+ uint32 oskew = tilew - width;
+ cpStripToTile(bufp + colb,
+ tilebuf, nrow, width,
+ oskew + iskew, oskew );
+ } else
+ cpStripToTile(bufp + colb,
+ tilebuf, nrow, tilew,
+ iskew, 0);
+ colb += tilew;
+ }
+ bufp += imagew * nrow;
+ }
+done:
+ _TIFFfree(tilebuf);
+ return status;
+}
+
+DECLAREreadFunc(readSeparateTilesIntoBuffer)
+{
+ int status = 1;
+ uint32 imagew = TIFFRasterScanlineSize(in);
+ uint32 tilew = TIFFTileRowSize(in);
+ int iskew = imagew - tilew*spp;
+ tdata_t tilebuf = _TIFFmalloc(TIFFTileSize(in));
+ uint8* bufp = (uint8*) buf;
+ uint32 tw, tl;
+ uint32 row;
+ uint16 bps, bytes_per_sample;
+
+ if (tilebuf == 0)
+ return 0;
+ (void) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
+ (void) TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
+ (void) TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bps);
+ assert( bps % 8 == 0 );
+ bytes_per_sample = bps/8;
+
+ for (row = 0; row < imagelength; row += tl) {
+ uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
+ uint32 colb = 0;
+ uint32 col;
+
+ for (col = 0; col < imagewidth; col += tw) {
+ tsample_t s;
+
+ for (s = 0; s < spp; s++) {
+ if (TIFFReadTile(in, tilebuf, col, row, 0, s) < 0
+ && !ignore) {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read tile at %lu %lu, "
+ "sample %lu",
+ (unsigned long) col,
+ (unsigned long) row,
+ (unsigned long) s);
+ status = 0;
+ goto done;
+ }
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ if (colb + tilew*spp > imagew) {
+ uint32 width = imagew - colb;
+ int oskew = tilew*spp - width;
+ cpSeparateBufToContigBuf(
+ bufp+colb+s*bytes_per_sample,
+ tilebuf, nrow,
+ width/(spp*bytes_per_sample),
+ oskew + iskew,
+ oskew/spp, spp,
+ bytes_per_sample);
+ } else
+ cpSeparateBufToContigBuf(
+ bufp+colb+s*bytes_per_sample,
+ tilebuf, nrow, tw,
+ iskew, 0, spp,
+ bytes_per_sample);
+ }
+ colb += tilew*spp;
+ }
+ bufp += imagew * nrow;
+ }
+done:
+ _TIFFfree(tilebuf);
+ return status;
+}
+
+DECLAREwriteFunc(writeBufferToContigStrips)
+{
+ uint32 row, rowsperstrip;
+ tstrip_t strip = 0;
+
+ (void) imagewidth; (void) spp;
+ (void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ for (row = 0; row < imagelength; row += rowsperstrip) {
+ uint32 nrows = (row+rowsperstrip > imagelength) ?
+ imagelength-row : rowsperstrip;
+ tsize_t stripsize = TIFFVStripSize(out, nrows);
+ if (TIFFWriteEncodedStrip(out, strip++, buf, stripsize) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write strip %u", strip - 1);
+ return 0;
+ }
+ buf += stripsize;
+ }
+ return 1;
+}
+
+DECLAREwriteFunc(writeBufferToSeparateStrips)
+{
+ uint32 rowsize = imagewidth * spp;
+ uint32 rowsperstrip;
+ tdata_t obuf = _TIFFmalloc(TIFFStripSize(out));
+ tstrip_t strip = 0;
+ tsample_t s;
+
+ if (obuf == NULL)
+ return (0);
+ (void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ for (s = 0; s < spp; s++) {
+ uint32 row;
+ for (row = 0; row < imagelength; row += rowsperstrip) {
+ uint32 nrows = (row+rowsperstrip > imagelength) ?
+ imagelength-row : rowsperstrip;
+ tsize_t stripsize = TIFFVStripSize(out, nrows);
+
+ cpContigBufToSeparateBuf(
+ obuf, (uint8*) buf + row*rowsize + s,
+ nrows, imagewidth, 0, 0, spp, 1);
+ if (TIFFWriteEncodedStrip(out, strip++, obuf, stripsize) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write strip %u",
+ strip - 1);
+ _TIFFfree(obuf);
+ return 0;
+ }
+ }
+ }
+ _TIFFfree(obuf);
+ return 1;
+
+}
+
+DECLAREwriteFunc(writeBufferToContigTiles)
+{
+ uint32 imagew = TIFFScanlineSize(out);
+ uint32 tilew = TIFFTileRowSize(out);
+ int iskew = imagew - tilew;
+ tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
+ uint8* bufp = (uint8*) buf;
+ uint32 tl, tw;
+ uint32 row;
+
+ (void) spp;
+ if (obuf == NULL)
+ return 0;
+ (void) TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
+ (void) TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
+ for (row = 0; row < imagelength; row += tilelength) {
+ uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
+ uint32 colb = 0;
+ uint32 col;
+
+ for (col = 0; col < imagewidth; col += tw) {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ if (colb + tilew > imagew) {
+ uint32 width = imagew - colb;
+ int oskew = tilew - width;
+ cpStripToTile(obuf, bufp + colb, nrow, width,
+ oskew, oskew + iskew);
+ } else
+ cpStripToTile(obuf, bufp + colb, nrow, tilew,
+ 0, iskew);
+ if (TIFFWriteTile(out, obuf, col, row, 0, 0) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write tile at %lu %lu",
+ (unsigned long) col,
+ (unsigned long) row);
+ _TIFFfree(obuf);
+ return 0;
+ }
+ colb += tilew;
+ }
+ bufp += nrow * imagew;
+ }
+ _TIFFfree(obuf);
+ return 1;
+}
+
+DECLAREwriteFunc(writeBufferToSeparateTiles)
+{
+ uint32 imagew = TIFFScanlineSize(out);
+ tsize_t tilew = TIFFTileRowSize(out);
+ uint32 iimagew = TIFFRasterScanlineSize(out);
+ int iskew = iimagew - tilew*spp;
+ tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
+ uint8* bufp = (uint8*) buf;
+ uint32 tl, tw;
+ uint32 row;
+ uint16 bps, bytes_per_sample;
+
+ if (obuf == NULL)
+ return 0;
+ (void) TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
+ (void) TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
+ (void) TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
+ assert( bps % 8 == 0 );
+ bytes_per_sample = bps/8;
+
+ for (row = 0; row < imagelength; row += tl) {
+ uint32 nrow = (row+tl > imagelength) ? imagelength-row : tl;
+ uint32 colb = 0;
+ uint32 col;
+
+ for (col = 0; col < imagewidth; col += tw) {
+ tsample_t s;
+ for (s = 0; s < spp; s++) {
+ /*
+ * Tile is clipped horizontally. Calculate
+ * visible portion and skewing factors.
+ */
+ if (colb + tilew > imagew) {
+ uint32 width = (imagew - colb);
+ int oskew = tilew - width;
+
+ cpContigBufToSeparateBuf(obuf,
+ bufp + (colb*spp) + s,
+ nrow, width/bytes_per_sample,
+ oskew, (oskew*spp)+iskew, spp,
+ bytes_per_sample);
+ } else
+ cpContigBufToSeparateBuf(obuf,
+ bufp + (colb*spp) + s,
+ nrow, tilewidth,
+ 0, iskew, spp,
+ bytes_per_sample);
+ if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0) {
+ TIFFError(TIFFFileName(out),
+ "Error, can't write tile at %lu %lu "
+ "sample %lu",
+ (unsigned long) col,
+ (unsigned long) row,
+ (unsigned long) s);
+ _TIFFfree(obuf);
+ return 0;
+ }
+ }
+ colb += tilew;
+ }
+ bufp += nrow * iimagew;
+ }
+ _TIFFfree(obuf);
+ return 1;
+}
+
+/*
+ * Contig strips -> contig tiles.
+ */
+DECLAREcpFunc(cpContigStrips2ContigTiles)
+{
+ return cpImage(in, out,
+ readContigStripsIntoBuffer,
+ writeBufferToContigTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig strips -> separate tiles.
+ */
+DECLAREcpFunc(cpContigStrips2SeparateTiles)
+{
+ return cpImage(in, out,
+ readContigStripsIntoBuffer,
+ writeBufferToSeparateTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate strips -> contig tiles.
+ */
+DECLAREcpFunc(cpSeparateStrips2ContigTiles)
+{
+ return cpImage(in, out,
+ readSeparateStripsIntoBuffer,
+ writeBufferToContigTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate strips -> separate tiles.
+ */
+DECLAREcpFunc(cpSeparateStrips2SeparateTiles)
+{
+ return cpImage(in, out,
+ readSeparateStripsIntoBuffer,
+ writeBufferToSeparateTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig strips -> contig tiles.
+ */
+DECLAREcpFunc(cpContigTiles2ContigTiles)
+{
+ return cpImage(in, out,
+ readContigTilesIntoBuffer,
+ writeBufferToContigTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig tiles -> separate tiles.
+ */
+DECLAREcpFunc(cpContigTiles2SeparateTiles)
+{
+ return cpImage(in, out,
+ readContigTilesIntoBuffer,
+ writeBufferToSeparateTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate tiles -> contig tiles.
+ */
+DECLAREcpFunc(cpSeparateTiles2ContigTiles)
+{
+ return cpImage(in, out,
+ readSeparateTilesIntoBuffer,
+ writeBufferToContigTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate tiles -> separate tiles (tile dimension change).
+ */
+DECLAREcpFunc(cpSeparateTiles2SeparateTiles)
+{
+ return cpImage(in, out,
+ readSeparateTilesIntoBuffer,
+ writeBufferToSeparateTiles,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig tiles -> contig tiles (tile dimension change).
+ */
+DECLAREcpFunc(cpContigTiles2ContigStrips)
+{
+ return cpImage(in, out,
+ readContigTilesIntoBuffer,
+ writeBufferToContigStrips,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Contig tiles -> separate strips.
+ */
+DECLAREcpFunc(cpContigTiles2SeparateStrips)
+{
+ return cpImage(in, out,
+ readContigTilesIntoBuffer,
+ writeBufferToSeparateStrips,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate tiles -> contig strips.
+ */
+DECLAREcpFunc(cpSeparateTiles2ContigStrips)
+{
+ return cpImage(in, out,
+ readSeparateTilesIntoBuffer,
+ writeBufferToContigStrips,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Separate tiles -> separate strips.
+ */
+DECLAREcpFunc(cpSeparateTiles2SeparateStrips)
+{
+ return cpImage(in, out,
+ readSeparateTilesIntoBuffer,
+ writeBufferToSeparateStrips,
+ imagelength, imagewidth, spp);
+}
+
+/*
+ * Select the appropriate copy function to use.
+ */
+static copyFunc
+pickCopyFunc(TIFF* in, TIFF* out, uint16 bitspersample, uint16 samplesperpixel)
+{
+ uint16 shortv;
+ uint32 w, l, tw, tl;
+ int bychunk;
+
+ (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv);
+ if (shortv != config && bitspersample != 8 && samplesperpixel > 1) {
+ fprintf(stderr,
+"%s: Cannot handle different planar configuration w/ bits/sample != 8\n",
+ TIFFFileName(in));
+ return (NULL);
+ }
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &l);
+ if (!(TIFFIsTiled(out) || TIFFIsTiled(in))) {
+ uint32 irps = (uint32) -1L;
+ TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &irps);
+ /* if biased, force decoded copying to allow image subtraction */
+ bychunk = !bias && (rowsperstrip == irps);
+ }else{ /* either in or out is tiled */
+ if (bias) {
+ fprintf(stderr,
+"%s: Cannot handle tiled configuration w/bias image\n",
+ TIFFFileName(in));
+ return (NULL);
+ }
+ if (TIFFIsTiled(out)) {
+ if (!TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw))
+ tw = w;
+ if (!TIFFGetField(in, TIFFTAG_TILELENGTH, &tl))
+ tl = l;
+ bychunk = (tw == tilewidth && tl == tilelength);
+ } else { /* out's not, so in must be tiled */
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
+ bychunk = (tw == w && tl == rowsperstrip);
+ }
+ }
+#define T 1
+#define F 0
+#define pack(a,b,c,d,e) ((long)(((a)<<11)|((b)<<3)|((c)<<2)|((d)<<1)|(e)))
+ switch(pack(shortv,config,TIFFIsTiled(in),TIFFIsTiled(out),bychunk)) {
+/* Strips -> Tiles */
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,T,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,T,T):
+ return cpContigStrips2ContigTiles;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,T,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,T,T):
+ return cpContigStrips2SeparateTiles;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,T,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,T,T):
+ return cpSeparateStrips2ContigTiles;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,T):
+ return cpSeparateStrips2SeparateTiles;
+/* Tiles -> Tiles */
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,T,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,T,T):
+ return cpContigTiles2ContigTiles;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,T,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,T,T):
+ return cpContigTiles2SeparateTiles;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,T,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,T,T):
+ return cpSeparateTiles2ContigTiles;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,T):
+ return cpSeparateTiles2SeparateTiles;
+/* Tiles -> Strips */
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,F,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,F,T):
+ return cpContigTiles2ContigStrips;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,F,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,F,T):
+ return cpContigTiles2SeparateStrips;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,F,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,F,T):
+ return cpSeparateTiles2ContigStrips;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,T):
+ return cpSeparateTiles2SeparateStrips;
+/* Strips -> Strips */
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,F,F):
+ return bias ? cpBiasedContig2Contig : cpContig2ContigByRow;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,F,T):
+ return cpDecodedStrips;
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,F,F):
+ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,F,T):
+ return cpContig2SeparateByRow;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,F,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,F,T):
+ return cpSeparate2ContigByRow;
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,F):
+ case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,T):
+ return cpSeparate2SeparateByRow;
+ }
+#undef pack
+#undef F
+#undef T
+ fprintf(stderr, "tiffcp: %s: Don't know how to copy/convert image.\n",
+ TIFFFileName(in));
+ return (NULL);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffcrop.c b/tiff/tools/tiffcrop.c
new file mode 100644
index 0000000..fa057c5
--- /dev/null
+++ b/tiff/tools/tiffcrop.c
@@ -0,0 +1,9012 @@
+/* $Id: tiffcrop.c,v 1.3.2.12 2010-06-11 22:24:23 bfriesen Exp $ */
+
+/* tiffcrop.c -- a port of tiffcp.c extended to include manipulations of
+ * the image data through additional options listed below
+ *
+ * Original code:
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ * Additions (c) Richard Nolde 2006-2009
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS OR ANY OTHER COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL
+ * DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
+ * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
+ * OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Some portions of the current code are derived from tiffcp, primarly in
+ * the areas of lowlevel reading and writing of TAGS, scanlines and tiles though
+ * some of the original functions have been extended to support arbitrary bit
+ * depths. These functions are presented at the top of this file.
+ *
+ * Add support for the options below to extract sections of image(s)
+ * and to modify the whole image or selected portions of each image by
+ * rotations, mirroring, and colorscale/colormap inversion of selected
+ * types of TIFF images when appropriate. Some color model dependent
+ * functions are restricted to bilevel or 8 bit per sample data.
+ * See the man page for the full explanations.
+ *
+ * New Options:
+ * -h Display the syntax guide.
+ * -v Report the version and last build date for tiffcrop and libtiff.
+ * -z x1,y1,x2,y2:x3,y3,x4,y4:..xN,yN,xN + 1, yN + 1
+ * Specify a series of coordinates to define rectangular
+ * regions by the top left and lower right corners.
+ * -e c|d|i|m|s export mode for images and selections from input images
+ * combined All images and selections are written to a single file (default)
+ * with multiple selections from one image combined into a single image
+ * divided All images and selections are written to a single file
+ * with each selection from one image written to a new image
+ * image Each input image is written to a new file (numeric filename sequence)
+ * with multiple selections from the image combined into one image
+ * multiple Each input image is written to a new file (numeric filename sequence)
+ * with each selection from the image written to a new image
+ * separated Individual selections from each image are written to separate files
+ * -U units [in, cm, px ] inches, centimeters or pixels
+ * -H # Set horizontal resolution of output images to #
+ * -V # Set vertical resolution of output images to #
+ * -J # Horizontal margin of output page to # expressed in current
+ * units when sectioning image into columns x rows
+ * using the -S cols:rows option.
+ * -K # Vertical margin of output page to # expressed in current
+ * units when sectioning image into columns x rows
+ * using the -S cols:rows option.
+ * -X # Horizontal dimension of region to extract expressed in current
+ * units
+ * -Y # Vertical dimension of region to extract expressed in current
+ * units
+ * -O orient Orientation for output image, portrait, landscape, auto
+ * -P page Page size for output image segments, eg letter, legal, tabloid,
+ * etc.
+ * -S cols:rows Divide the image into equal sized segments using cols across
+ * and rows down
+ * -E t|l|r|b Edge to use as origin
+ * -m #,#,#,# Margins from edges for selection: top, left, bottom, right
+ * (commas separated)
+ * -Z #:#,#:# Zones of the image designated as zone X of Y,
+ * eg 1:3 would be first of three equal portions measured
+ * from reference edge
+ * -N odd|even|#,#-#,#|last
+ * Select sequences and/or ranges of images within file
+ * to process. The words odd or even may be used to specify
+ * all odd or even numbered images the word last may be used
+ * in place of a number in the sequence to indicate the final
+ * image in the file without knowing how many images there are.
+ * -R # Rotate image or crop selection by 90,180,or 270 degrees
+ * clockwise
+ * -F h|v Flip (mirror) image or crop selection horizontally
+ * or vertically
+ * -I [black|white|data|both]
+ * Invert color space, eg dark to light for bilevel and grayscale images
+ * If argument is white or black, set the PHOTOMETRIC_INTERPRETATION
+ * tag to MinIsBlack or MinIsWhite without altering the image data
+ * If the argument is data or both, the image data are modified:
+ * both inverts the data and the PHOTOMETRIC_INTERPRETATION tag,
+ * data inverts the data but not the PHOTOMETRIC_INTERPRETATION tag
+ * -D input:<filename1>,output:<filename2>,format:<raw|txt>,level:N,debug:N
+ * Dump raw data for input and/or output images to individual files
+ * in raw (binary) format or text (ASCII) representing binary data
+ * as strings of 1s and 0s. The filename arguments are used as stems
+ * from which individual files are created for each image. Text format
+ * includes annotations for image parameters and scanline info. Level
+ * selects which functions dump data, with higher numbers selecting
+ * lower level, scanline level routines. Debug reports a limited set
+ * of messages to monitor progess without enabling dump logs.
+ */
+
+static char tiffcrop_version_id[] = "2.2";
+static char tiffcrop_rev_date[] = "11-03-2009";
+
+#include "tif_config.h"
+#include "tiffiop.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#include "tiffio.h"
+
+#if defined(VMS)
+# define unlink delete
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#ifndef streq
+#define streq(a,b) (strcmp((a),(b)) == 0)
+#endif
+#define strneq(a,b,n) (strncmp((a),(b),(n)) == 0)
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * Definitions and data structures required to support cropping and image
+ * manipulations.
+ */
+
+#define EDGE_TOP 1
+#define EDGE_LEFT 2
+#define EDGE_BOTTOM 3
+#define EDGE_RIGHT 4
+#define EDGE_CENTER 5
+
+#define MIRROR_HORIZ 1
+#define MIRROR_VERT 2
+#define MIRROR_BOTH 3
+#define ROTATECW_90 8
+#define ROTATECW_180 16
+#define ROTATECW_270 32
+#define ROTATE_ANY ROTATECW_90 || ROTATECW_180 || ROTATECW_270
+
+#define CROP_NONE 0
+#define CROP_MARGINS 1
+#define CROP_WIDTH 2
+#define CROP_LENGTH 4
+#define CROP_ZONES 8
+#define CROP_REGIONS 16
+#define CROP_ROTATE 32
+#define CROP_MIRROR 64
+#define CROP_INVERT 128
+
+/* Modes for writing out images and selections */
+#define ONE_FILE_COMPOSITE 0 /* One file, sections combined sections */
+#define ONE_FILE_SEPARATED 1 /* One file, sections to new IFDs */
+#define FILE_PER_IMAGE_COMPOSITE 2 /* One file per image, combined sections */
+#define FILE_PER_IMAGE_SEPARATED 3 /* One file per input image */
+#define FILE_PER_SELECTION 4 /* One file per selection */
+
+#define COMPOSITE_IMAGES 0 /* Selections combined into one image */
+#define SEPARATED_IMAGES 1 /* Selections saved to separate images */
+
+#define STRIP 1
+#define TILE 2
+
+#define MAX_REGIONS 8 /* number of regions to extract from a single page */
+#define MAX_OUTBUFFS 8 /* must match larger of zones or regions */
+#define MAX_SECTIONS 32 /* number of sections per page to write to output */
+#define MAX_IMAGES 2048 /* number of images in descrete list, not in the file */
+#define MAX_SAMPLES 8 /* maximum number of samples per pixel supported */
+#define MAX_BITS_PER_SAMPLE 64 /* maximum bit depth supported */
+
+#define DUMP_NONE 0
+#define DUMP_TEXT 1
+#define DUMP_RAW 2
+
+/* Offsets into buffer for margins and fixed width and length segments */
+struct offset {
+ uint32 tmargin;
+ uint32 lmargin;
+ uint32 bmargin;
+ uint32 rmargin;
+ uint32 crop_width;
+ uint32 crop_length;
+ uint32 startx;
+ uint32 endx;
+ uint32 starty;
+ uint32 endy;
+};
+
+/* Description of a zone within the image. Position 1 of 3 zones would be
+ * the first third of the image. These are computed after margins and
+ * width/length requests are applied so that you can extract multiple
+ * zones from within a larger region for OCR or barcode recognition.
+ */
+
+struct buffinfo {
+ uint32 size; /* size of this buffer */
+ unsigned char *buffer; /* address of the allocated buffer */
+};
+
+struct zone {
+ int position; /* ordinal of segment to be extracted */
+ int total; /* total equal sized divisions of crop area */
+ };
+
+struct pageseg {
+ uint32 x1; /* index of left edge */
+ uint32 x2; /* index of right edge */
+ uint32 y1; /* index of top edge */
+ uint32 y2; /* index of bottom edge */
+ int position; /* ordinal of segment to be extracted */
+ int total; /* total equal sized divisions of crop area */
+ uint32 buffsize; /* size of buffer needed to hold the cropped zone */
+};
+
+struct coordpairs {
+ double X1; /* index of left edge in current units */
+ double X2; /* index of right edge in current units */
+ double Y1; /* index of top edge in current units */
+ double Y2; /* index of bottom edge in current units */
+};
+
+struct region {
+ uint32 x1; /* pixel offset of left edge */
+ uint32 x2; /* pixel offset of right edge */
+ uint32 y1; /* pixel offset of top edge */
+ uint32 y2; /* picel offset of bottom edge */
+ uint32 width; /* width in pixels */
+ uint32 length; /* length in pixels */
+ uint32 buffsize; /* size of buffer needed to hold the cropped region */
+ unsigned char *buffptr; /* address of start of the region */
+};
+
+/* Cropping parameters from command line and image data
+ * Note: This should be renamed to proc_opts and expanded to include all current globals
+ * if possible, but each function that accesses global variables will have to be redone.
+ */
+struct crop_mask {
+ double width; /* Selection width for master crop region in requested units */
+ double length; /* Selection length for master crop region in requesed units */
+ double margins[4]; /* Top, left, bottom, right margins */
+ float xres; /* Horizontal resolution read from image*/
+ float yres; /* Vertical resolution read from image */
+ uint32 combined_width; /* Width of combined cropped zones */
+ uint32 combined_length; /* Length of combined cropped zones */
+ uint32 bufftotal; /* Size of buffer needed to hold all the cropped region */
+ uint16 img_mode; /* Composite or separate images created from zones or regions */
+ uint16 exp_mode; /* Export input images or selections to one or more files */
+ uint16 crop_mode; /* Crop options to be applied */
+ uint16 res_unit; /* Resolution unit for margins and selections */
+ uint16 edge_ref; /* Reference edge for sections extraction and combination */
+ uint16 rotation; /* Clockwise rotation of the extracted region or image */
+ uint16 mirror; /* Mirror extracted region or image horizontally or vertically */
+ uint16 invert; /* Invert the color map of image or region */
+ uint16 photometric; /* Status of photometric interpretation for inverted image */
+ uint16 selections; /* Number of regions or zones selected */
+ uint16 regions; /* Number of regions delimited by corner coordinates */
+ struct region regionlist[MAX_REGIONS]; /* Regions within page or master crop region */
+ uint16 zones; /* Number of zones delimited by Ordinal:Total requested */
+ struct zone zonelist[MAX_REGIONS]; /* Zones indices to define a region */
+ struct coordpairs corners[MAX_REGIONS]; /* Coordinates of upper left and lower right corner */
+};
+
+#define MAX_PAPERNAMES 49
+#define MAX_PAPERNAME_LENGTH 15
+#define DEFAULT_RESUNIT RESUNIT_INCH
+#define DEFAULT_PAGE_HEIGHT 14.0
+#define DEFAULT_PAGE_WIDTH 8.5
+#define DEFAULT_RESOLUTION 300
+#define DEFAULT_PAPER_SIZE "legal"
+
+#define ORIENTATION_NONE 0
+#define ORIENTATION_PORTRAIT 1
+#define ORIENTATION_LANDSCAPE 2
+#define ORIENTATION_SEASCAPE 4
+#define ORIENTATION_AUTO 16
+
+#define PAGE_MODE_NONE 0
+#define PAGE_MODE_RESOLUTION 1
+#define PAGE_MODE_PAPERSIZE 2
+#define PAGE_MODE_MARGINS 4
+#define PAGE_MODE_ROWSCOLS 8
+
+#define INVERT_DATA_ONLY 10
+#define INVERT_DATA_AND_TAG 11
+
+struct paperdef {
+ char name[MAX_PAPERNAME_LENGTH];
+ double width;
+ double length;
+ double asratio;
+ };
+
+/* European page sizes corrected from update sent by
+ * thomas . jarosch @ intra2net . com on 5/7/2010
+ * Paper Size Width Length Aspect Ratio */
+struct paperdef PaperTable[MAX_PAPERNAMES] = {
+ {"default", 8.500, 14.000, 0.607},
+ {"pa4", 8.264, 11.000, 0.751},
+ {"letter", 8.500, 11.000, 0.773},
+ {"legal", 8.500, 14.000, 0.607},
+ {"half-letter", 8.500, 5.514, 1.542},
+ {"executive", 7.264, 10.528, 0.690},
+ {"tabloid", 11.000, 17.000, 0.647},
+ {"11x17", 11.000, 17.000, 0.647},
+ {"ledger", 17.000, 11.000, 1.545},
+ {"archa", 9.000, 12.000, 0.750},
+ {"archb", 12.000, 18.000, 0.667},
+ {"archc", 18.000, 24.000, 0.750},
+ {"archd", 24.000, 36.000, 0.667},
+ {"arche", 36.000, 48.000, 0.750},
+ {"csheet", 17.000, 22.000, 0.773},
+ {"dsheet", 22.000, 34.000, 0.647},
+ {"esheet", 34.000, 44.000, 0.773},
+ {"superb", 11.708, 17.042, 0.687},
+ {"commercial", 4.139, 9.528, 0.434},
+ {"monarch", 3.889, 7.528, 0.517},
+ {"envelope-dl", 4.333, 8.681, 0.499},
+ {"envelope-c5", 6.389, 9.028, 0.708},
+ {"europostcard", 4.139, 5.833, 0.710},
+ {"a0", 33.110, 46.811, 0.707},
+ {"a1", 23.386, 33.110, 0.706},
+ {"a2", 16.535, 23.386, 0.707},
+ {"a3", 11.693, 16.535, 0.707},
+ {"a4", 8.268, 11.693, 0.707},
+ {"a5", 5.827, 8.268, 0.705},
+ {"a6", 4.134, 5.827, 0.709},
+ {"a7", 2.913, 4.134, 0.705},
+ {"a8", 2.047, 2.913, 0.703},
+ {"a9", 1.457, 2.047, 0.712},
+ {"a10", 1.024, 1.457, 0.703},
+ {"b0", 39.370, 55.669, 0.707},
+ {"b1", 27.835, 39.370, 0.707},
+ {"b2", 19.685, 27.835, 0.707},
+ {"b3", 13.898, 19.685, 0.706},
+ {"b4", 9.843, 13.898, 0.708},
+ {"b5", 6.929, 9.843, 0.704},
+ {"b6", 4.921, 6.929, 0.710},
+ {"c0", 36.102, 51.063, 0.707},
+ {"c1", 25.512, 36.102, 0.707},
+ {"c2", 18.031, 25.512, 0.707},
+ {"c3", 12.756, 18.031, 0.707},
+ {"c4", 9.016, 12.756, 0.707},
+ {"c5", 6.378, 9.016, 0.707},
+ {"c6", 4.488, 6.378, 0.704},
+ {"", 0.000, 0.000, 1.000},
+};
+
+/* Structure to define in input image parameters */
+struct image_data {
+ float xres;
+ float yres;
+ uint32 width;
+ uint32 length;
+ uint16 res_unit;
+ uint16 bps;
+ uint16 spp;
+ uint16 planar;
+ uint16 photometric;
+ uint16 orientation;
+ uint16 adjustments;
+};
+
+/* Structure to define the output image modifiers */
+struct pagedef {
+ char name[16];
+ double width; /* width in pixels */
+ double length; /* length in pixels */
+ double hmargin; /* margins to subtract from width of sections */
+ double vmargin; /* margins to subtract from height of sections */
+ double hres; /* horizontal resolution for output */
+ double vres; /* vertical resolution for output */
+ uint32 mode; /* bitmask of modifiers to page format */
+ uint16 res_unit; /* resolution unit for output image */
+ unsigned int rows; /* number of section rows */
+ unsigned int cols; /* number of section cols */
+ unsigned int orient; /* portrait, landscape, seascape, auto */
+};
+
+struct dump_opts {
+ int debug;
+ int format;
+ int level;
+ char mode[4];
+ char infilename[PATH_MAX + 1];
+ char outfilename[PATH_MAX + 1];
+ FILE *infile;
+ FILE *outfile;
+ };
+
+/* globals */
+static int outtiled = -1;
+static uint32 tilewidth = 0;
+static uint32 tilelength = 0;
+
+static uint16 config = 0;
+static uint16 compression = 0;
+static uint16 predictor = 0;
+static uint16 fillorder = 0;
+static uint32 rowsperstrip = 0;
+static uint32 g3opts = 0;
+static int ignore = FALSE; /* if true, ignore read errors */
+static uint32 defg3opts = (uint32) -1;
+static int quality = 100; /* JPEG quality */
+static int jpegcolormode = -1; /* was JPEGCOLORMODE_RGB; */
+static uint16 defcompression = (uint16) -1;
+static uint16 defpredictor = (uint16) -1;
+static int pageNum = 0;
+static int little_endian = 1;
+
+/* Functions adapted from tiffcp with additions or significant modifications */
+static int readContigStripsIntoBuffer (TIFF*, uint8*);
+static int readSeparateStripsIntoBuffer (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
+static int readContigTilesIntoBuffer (TIFF*, uint8*, uint32, uint32, uint32, uint32, tsample_t, uint16);
+static int readSeparateTilesIntoBuffer (TIFF*, uint8*, uint32, uint32, uint32, uint32, tsample_t, uint16);
+static int writeBufferToContigStrips (TIFF*, uint8*, uint32);
+static int writeBufferToContigTiles (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
+static int writeBufferToSeparateStrips (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
+static int writeBufferToSeparateTiles (TIFF*, uint8*, uint32, uint32, tsample_t, struct dump_opts *);
+static int extractContigSamplesToBuffer (uint8 *, uint8 *, uint32, uint32, tsample_t,
+ uint16, uint16, struct dump_opts *);
+static int processCompressOptions(char*);
+static void usage(void);
+
+/* All other functions by Richard Nolde, not found in tiffcp */
+static void initImageData (struct image_data *);
+static void initCropMasks (struct crop_mask *);
+static void initPageSetup (struct pagedef *, struct pageseg *, struct buffinfo []);
+static void initDumpOptions(struct dump_opts *);
+
+/* Command line and file naming functions */
+void process_command_opts (int, char *[], char *, char *, uint32 *,
+ uint16 *, uint16 *, uint32 *, uint32 *, uint32 *,
+ struct crop_mask *, struct pagedef *,
+ struct dump_opts *,
+ unsigned int *, unsigned int *);
+static int update_output_file (TIFF **, char *, int, char *, unsigned int *);
+
+
+/* * High level functions for whole image manipulation */
+static int get_page_geometry (char *, struct pagedef*);
+static int computeInputPixelOffsets(struct crop_mask *, struct image_data *,
+ struct offset *);
+static int computeOutputPixelOffsets (struct crop_mask *, struct image_data *,
+ struct pagedef *, struct pageseg *,
+ struct dump_opts *);
+static int loadImage(TIFF *, struct image_data *, struct dump_opts *, unsigned char **);
+static int correct_orientation(struct image_data *, unsigned char **);
+static int getCropOffsets(struct image_data *, struct crop_mask *, struct dump_opts *);
+static int processCropSelections(struct image_data *, struct crop_mask *,
+ unsigned char **, struct buffinfo []);
+static int writeSelections(TIFF *, TIFF **, struct crop_mask *, struct image_data *,
+ struct dump_opts *, struct buffinfo [],
+ char *, char *, unsigned int*, unsigned int);
+
+/* Section functions */
+static int createImageSection(uint32, unsigned char **);
+static int extractImageSection(struct image_data *, struct pageseg *,
+ unsigned char *, unsigned char *);
+static int writeSingleSection(TIFF *, TIFF *, struct image_data *,
+ struct dump_opts *, uint32, uint32,
+ double, double, unsigned char *);
+static int writeImageSections(TIFF *, TIFF *, struct image_data *,
+ struct pagedef *, struct pageseg *,
+ struct dump_opts *, unsigned char *,
+ unsigned char **);
+/* Whole image functions */
+static int createCroppedImage(struct image_data *, struct crop_mask *,
+ unsigned char **, unsigned char **);
+static int writeCroppedImage(TIFF *, TIFF *, struct image_data *image,
+ struct dump_opts * dump,
+ uint32, uint32, unsigned char *, int, int);
+
+/* Image manipulation functions */
+static int rotateContigSamples8bits(uint16, uint16, uint16, uint32,
+ uint32, uint32, uint8 *, uint8 *);
+static int rotateContigSamples16bits(uint16, uint16, uint16, uint32,
+ uint32, uint32, uint8 *, uint8 *);
+static int rotateContigSamples24bits(uint16, uint16, uint16, uint32,
+ uint32, uint32, uint8 *, uint8 *);
+static int rotateContigSamples32bits(uint16, uint16, uint16, uint32,
+ uint32, uint32, uint8 *, uint8 *);
+static int rotateImage(uint16, struct image_data *, uint32 *, uint32 *,
+ unsigned char **);
+static int mirrorImage(uint16, uint16, uint16, uint32, uint32,
+ unsigned char *);
+static int invertImage(uint16, uint16, uint16, uint32, uint32,
+ unsigned char *);
+
+/* Functions to reverse the sequence of samples in a scanline */
+static int reverseSamples8bits (uint16, uint16, uint32, uint8 *, uint8 *);
+static int reverseSamples16bits (uint16, uint16, uint32, uint8 *, uint8 *);
+static int reverseSamples24bits (uint16, uint16, uint32, uint8 *, uint8 *);
+static int reverseSamples32bits (uint16, uint16, uint32, uint8 *, uint8 *);
+static int reverseSamplesBytes (uint16, uint16, uint32, uint8 *, uint8 *);
+
+/* Functions for manipulating individual samples in an image */
+static int extractSeparateRegion(struct image_data *, struct crop_mask *,
+ unsigned char *, unsigned char *, int);
+static int extractCompositeRegions(struct image_data *, struct crop_mask *,
+ unsigned char *, unsigned char *);
+static int extractContigSamples8bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamples16bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamples24bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamples32bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamplesBytes (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32);
+static int extractContigSamplesShifted8bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32,
+ int);
+static int extractContigSamplesShifted16bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32,
+ int);
+static int extractContigSamplesShifted24bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32,
+ int);
+static int extractContigSamplesShifted32bits (uint8 *, uint8 *, uint32,
+ tsample_t, uint16, uint16,
+ tsample_t, uint32, uint32,
+ int);
+static int extractContigSamplesToTileBuffer(uint8 *, uint8 *, uint32, uint32,
+ uint32, uint32, tsample_t, uint16,
+ uint16, uint16, struct dump_opts *);
+
+/* Functions to combine separate planes into interleaved planes */
+static int combineSeparateSamples8bits (uint8 *[], uint8 *, uint32, uint32,
+ uint16, uint16, FILE *, int, int);
+static int combineSeparateSamples16bits (uint8 *[], uint8 *, uint32, uint32,
+ uint16, uint16, FILE *, int, int);
+static int combineSeparateSamples24bits (uint8 *[], uint8 *, uint32, uint32,
+ uint16, uint16, FILE *, int, int);
+static int combineSeparateSamples32bits (uint8 *[], uint8 *, uint32, uint32,
+ uint16, uint16, FILE *, int, int);
+static int combineSeparateSamplesBytes (unsigned char *[], unsigned char *,
+ uint32, uint32, tsample_t, uint16,
+ FILE *, int, int);
+
+static int combineSeparateTileSamples8bits (uint8 *[], uint8 *, uint32, uint32,
+ uint32, uint32, uint16, uint16,
+ FILE *, int, int);
+static int combineSeparateTileSamples16bits (uint8 *[], uint8 *, uint32, uint32,
+ uint32, uint32, uint16, uint16,
+ FILE *, int, int);
+static int combineSeparateTileSamples24bits (uint8 *[], uint8 *, uint32, uint32,
+ uint32, uint32, uint16, uint16,
+ FILE *, int, int);
+static int combineSeparateTileSamples32bits (uint8 *[], uint8 *, uint32, uint32,
+ uint32, uint32, uint16, uint16,
+ FILE *, int, int);
+static int combineSeparateTileSamplesBytes (unsigned char *[], unsigned char *,
+ uint32, uint32, uint32, uint32,
+ tsample_t, uint16, FILE *, int, int);
+
+/* Dump functions for debugging */
+static void dump_info (FILE *, int, char *, char *, ...);
+static int dump_data (FILE *, int, char *, unsigned char *, uint32);
+static int dump_byte (FILE *, int, char *, unsigned char);
+static int dump_short (FILE *, int, char *, uint16);
+static int dump_long (FILE *, int, char *, uint32);
+static int dump_wide (FILE *, int, char *, uint64);
+static int dump_buffer (FILE *, int, uint32, uint32, uint32, unsigned char *);
+
+/* End function declarations */
+/* Functions derived in whole or in part from tiffcp */
+/* The following functions are taken largely intact from tiffcp */
+
+static char* stuff[] = {
+"usage: tiffcrop [options] source1 ... sourceN destination",
+"where options are:",
+" -h Print this syntax listing",
+" -v Print tiffcrop version identifier and last revision date",
+" ",
+" -a Append to output instead of overwriting",
+" -d offset Set initial directory offset, counting first image as one, not zero",
+" -p contig Pack samples contiguously (e.g. RGBRGB...)",
+" -p separate Store samples separately (e.g. RRR...GGG...BBB...)",
+" -s Write output in strips",
+" -t Write output in tiles",
+" -i Ignore read errors",
+" ",
+" -r # Make each strip have no more than # rows",
+" -w # Set output tile width (pixels)",
+" -l # Set output tile length (pixels)",
+" ",
+" -f lsb2msb Force lsb-to-msb FillOrder for output",
+" -f msb2lsb Force msb-to-lsb FillOrder for output",
+"",
+" -c lzw[:opts] Compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] Compress output with deflate encoding",
+" -c jpeg[:opts] compress output with JPEG encoding",
+" -c packbits Compress output with packbits encoding",
+" -c g3[:opts] Compress output with CCITT Group 3 encoding",
+" -c g4 Compress output with CCITT Group 4 encoding",
+" -c none Use no compression algorithm on output",
+" ",
+"Group 3 options:",
+" 1d Use default CCITT Group 3 1D-encoding",
+" 2d Use optional CCITT Group 3 2D-encoding",
+" fill Byte-align EOL codes",
+"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
+" ",
+"JPEG options:",
+" # Set compression quality level (0-100, default 100)",
+" r Output color image as raw RGB rather than YCbCr",
+" a Output color image as RGB or YCbCr with auto detection",
+"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
+" ",
+"LZW and deflate options:",
+" # Set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+" ",
+"Page and selection options:",
+" -N odd|even|#,#-#,#|last sequences and ranges of images within file to process",
+" The words odd or even may be used to specify all odd or even numbered images.",
+" The word last may be used in place of a number in the sequence to indicate.",
+" The final image in the file without knowing how many images there are.",
+" Numbers are counted from one even though TIFF IFDs are counted from zero.",
+" ",
+" -E t|l|r|b edge to use as origin for width and length of crop region",
+" -U units [in, cm, px ] inches, centimeters or pixels",
+" ",
+" -m #,#,#,# margins from edges for selection: top, left, bottom, right separated by commas",
+" -X # horizontal dimension of region to extract expressed in current units",
+" -Y # vertical dimension of region to extract expressed in current units",
+" -Z #:#,#:# zones of the image designated as position X of Y,",
+" eg 1:3 would be first of three equal portions measured from reference edge",
+" -z x1,y1,x2,y2:...:xN,yN,xN+1,yN+1",
+" regions of the image designated by upper left and lower right coordinates",
+"",
+"Export grouping options:",
+" -e c|d|i|m|s export mode for images and selections from input images.",
+" When exporting a composite image from multiple zones or regions",
+" (combined and image modes), the selections must have equal sizes",
+" for the axis perpendicular to the edge specified with -E.",
+" c|combined All images and selections are written to a single file (default).",
+" with multiple selections from one image combined into a single image.",
+" d|divided All images and selections are written to a single file",
+" with each selection from one image written to a new image.",
+" i|image Each input image is written to a new file (numeric filename sequence)",
+" with multiple selections from the image combined into one image.",
+" m|multiple Each input image is written to a new file (numeric filename sequence)",
+" with each selection from the image written to a new image.",
+" s|separated Individual selections from each image are written to separate files.",
+"",
+"Output options:",
+" -H # Set horizontal resolution of output images to #",
+" -V # Set vertical resolution of output images to #",
+" -J # Set horizontal margin of output page to # expressed in current units",
+" when sectioning image into columns x rows using the -S cols:rows option",
+" -K # Set verticalal margin of output page to # expressed in current units",
+" when sectioning image into columns x rows using the -S cols:rows option",
+" ",
+" -O orient orientation for output image, portrait, landscape, auto",
+" -P page page size for output image segments, eg letter, legal, tabloid, etc",
+" use #.#x#.# to specify a custom page size in the currently defined units",
+" where #.# represents the width and length",
+" -S cols:rows Divide the image into equal sized segments using cols across and rows down.",
+" ",
+" -F hor|vert|both",
+" flip (mirror) image or region horizontally, vertically, or both",
+" -R # [90,180,or 270] degrees clockwise rotation of image or extracted region",
+" -I [black|white|data|both]",
+" invert color space, eg dark to light for bilevel and grayscale images",
+" If argument is white or black, set the PHOTOMETRIC_INTERPRETATION ",
+" tag to MinIsBlack or MinIsWhite without altering the image data",
+" If the argument is data or both, the image data are modified:",
+" both inverts the data and the PHOTOMETRIC_INTERPRETATION tag,",
+" data inverts the data but not the PHOTOMETRIC_INTERPRETATION tag",
+" ",
+"-D opt1:value1,opt2:value2,opt3:value3:opt4:value4",
+" Debug/dump program progress and/or data to non-TIFF files.",
+" Options include the following and must be joined as a comma",
+" separate list. The use of this option is generally limited to",
+" program debugging and development of future options.",
+" ",
+" debug:N Display limited program progress indicators where larger N",
+" increase the level of detail. Note: Tiffcrop may be compiled with",
+" -DDEVELMODE to enable additional very low level debug reporting.",
+"",
+" Format:txt|raw Format any logged data as ASCII text or raw binary ",
+" values. ASCII text dumps include strings of ones and zeroes",
+" representing the binary values in the image data plus identifying headers.",
+" ",
+" level:N Specify the level of detail presented in the dump files.",
+" This can vary from dumps of the entire input or output image data to dumps",
+" of data processed by specific functions. Current range of levels is 1 to 3.",
+" ",
+" input:full-path-to-directory/input-dumpname",
+" ",
+" output:full-path-to-directory/output-dumpnaem",
+" ",
+" When dump files are being written, each image will be written to a separate",
+" file with the name built by adding a numeric sequence value to the dumpname",
+" and an extension of .txt for ASCII dumps or .bin for binary dumps.",
+" ",
+" The four debug/dump options are independent, though it makes little sense to",
+" specify a dump file without specifying a detail level.",
+" ",
+NULL
+};
+
+/* This function could be modified to pass starting sample offset
+ * and number of samples as args to select fewer than spp
+ * from input image. These would then be passed to individual
+ * extractContigSampleXX routines.
+ */
+static int readContigTilesIntoBuffer (TIFF* in, uint8* buf,
+ uint32 imagelength,
+ uint32 imagewidth,
+ uint32 tw, uint32 tl,
+ tsample_t spp, uint16 bps)
+ {
+ int status = 1;
+ tsample_t sample = 0;
+ tsample_t count = spp;
+ uint32 row, col, trow;
+ uint32 nrow, ncol;
+ uint32 dst_rowsize, shift_width;
+ uint32 bytes_per_sample, bytes_per_pixel;
+ uint32 trailing_bits, prev_trailing_bits;
+ uint32 tile_rowsize = TIFFTileRowSize(in);
+ uint32 src_offset, dst_offset;
+ uint32 row_offset, col_offset;
+ uint8 *bufp = (uint8*) buf;
+ unsigned char *src = NULL;
+ unsigned char *dst = NULL;
+ tsize_t tbytes = 0, tile_buffsize = 0;
+ tsize_t tilesize = TIFFTileSize(in);
+ unsigned char *tilebuf = NULL;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+
+ if ((bps % 8) == 0)
+ shift_width = 0;
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+
+ tile_buffsize = tilesize;
+
+ if (tilesize < (tsize_t)(tl * tile_rowsize))
+ {
+#ifdef DEBUG2
+ TIFFError("readContigTilesIntoBuffer",
+ "Tilesize %lu is too small, using alternate calculation %u",
+ tilesize, tl * tile_rowsize);
+#endif
+ tile_buffsize = tl * tile_rowsize;
+ }
+
+ tilebuf = _TIFFmalloc(tile_buffsize);
+ if (tilebuf == 0)
+ return 0;
+
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ for (row = 0; row < imagelength; row += tl)
+ {
+ nrow = (row + tl > imagelength) ? imagelength - row : tl;
+ for (col = 0; col < imagewidth; col += tw)
+ {
+ tbytes = TIFFReadTile(in, tilebuf, col, row, 0, 0);
+ if (tbytes < tilesize && !ignore)
+ {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read tile at row %lu col %lu, Read %lu bytes of %lu",
+ (unsigned long) col, (unsigned long) row, (unsigned long)tbytes,
+ (unsigned long)tilesize);
+ status = 0;
+ _TIFFfree(tilebuf);
+ return status;
+ }
+
+ row_offset = row * dst_rowsize;
+ col_offset = ((col * bps * spp) + 7)/ 8;
+ bufp = buf + row_offset + col_offset;
+
+ if (col + tw > imagewidth)
+ ncol = imagewidth - col;
+ else
+ ncol = tw;
+
+ /* Each tile scanline will start on a byte boundary but it
+ * has to be merged into the scanline for the entire
+ * image buffer and the previous segment may not have
+ * ended on a byte boundary
+ */
+ /* Optimization for common bit depths, all samples */
+ if (((bps % 8) == 0) && (count == spp))
+ {
+ for (trow = 0; trow < nrow; trow++)
+ {
+ src_offset = trow * tile_rowsize;
+ _TIFFmemcpy (bufp, tilebuf + src_offset, (ncol * spp * bps) / 8);
+ bufp += (imagewidth * bps * spp) / 8;
+ }
+ }
+ else
+ {
+ /* Bit depths not a multiple of 8 and/or extract fewer than spp samples */
+ prev_trailing_bits = trailing_bits = 0;
+ trailing_bits = (ncol * bps * spp) % 8;
+
+ /* for (trow = 0; tl < nrow; trow++) */
+ for (trow = 0; trow < nrow; trow++)
+ {
+ src_offset = trow * tile_rowsize;
+ src = tilebuf + src_offset;
+ dst_offset = (row + trow) * dst_rowsize;
+ dst = buf + dst_offset + col_offset;
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, ncol, sample,
+ spp, bps, count, 0, ncol))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamplesShifted8bits (src, dst, ncol,
+ sample, spp,
+ bps, count,
+ 0, ncol,
+ prev_trailing_bits))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ }
+ else
+ if (extractContigSamplesShifted16bits (src, dst, ncol,
+ sample, spp,
+ bps, count,
+ 0, ncol,
+ prev_trailing_bits))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ case 2: if (extractContigSamplesShifted24bits (src, dst, ncol,
+ sample, spp,
+ bps, count,
+ 0, ncol,
+ prev_trailing_bits))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamplesShifted32bits (src, dst, ncol,
+ sample, spp,
+ bps, count,
+ 0, ncol,
+ prev_trailing_bits))
+ {
+ TIFFError("readContigTilesIntoBuffer",
+ "Unable to extract row %d from tile %lu",
+ row, (unsigned long)TIFFCurrentTile(in));
+ return 1;
+ }
+ break;
+ default: TIFFError("readContigTilesIntoBuffer", "Unsupported bit depth %d", bps);
+ return 1;
+ }
+ }
+ prev_trailing_bits += trailing_bits;
+ if (prev_trailing_bits > 7)
+ prev_trailing_bits-= 8;
+ }
+ }
+ }
+
+ _TIFFfree(tilebuf);
+ return status;
+ }
+
+static int readSeparateTilesIntoBuffer (TIFF* in, uint8 *obuf,
+ uint32 imagelength, uint32 imagewidth,
+ uint32 tw, uint32 tl,
+ uint16 spp, uint16 bps)
+ {
+ int i, status = 1, sample;
+ int shift_width, bytes_per_pixel;
+ uint16 bytes_per_sample;
+ uint32 row, col; /* Current row and col of image */
+ uint32 nrow, ncol; /* Number of rows and cols in current tile */
+ uint32 row_offset, col_offset; /* Output buffer offsets */
+ tsize_t tbytes = 0, tilesize = TIFFTileSize(in);
+ tsample_t s;
+ uint8* bufp = (uint8*)obuf;
+ unsigned char *srcbuffs[MAX_SAMPLES];
+ unsigned char *tbuff = NULL;
+
+ bytes_per_sample = (bps + 7) / 8;
+
+ for (sample = 0; (sample < spp) && (sample < MAX_SAMPLES); sample++)
+ {
+ srcbuffs[sample] = NULL;
+ tbuff = (unsigned char *)_TIFFmalloc(tilesize + 8);
+ if (!tbuff)
+ {
+ TIFFError ("readSeparateTilesIntoBuffer",
+ "Unable to allocate tile read buffer for sample %d", sample);
+ for (i = 0; i < sample; i++)
+ _TIFFfree (srcbuffs[i]);
+ return 0;
+ }
+ srcbuffs[sample] = tbuff;
+ }
+ /* Each tile contains only the data for a single plane
+ * arranged in scanlines of tw * bytes_per_sample bytes.
+ */
+ for (row = 0; row < imagelength; row += tl)
+ {
+ nrow = (row + tl > imagelength) ? imagelength - row : tl;
+ for (col = 0; col < imagewidth; col += tw)
+ {
+ for (s = 0; s < spp; s++)
+ { /* Read each plane of a tile set into srcbuffs[s] */
+ tbytes = TIFFReadTile(in, srcbuffs[s], col, row, 0, s);
+ if (tbytes < 0 && !ignore)
+ {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read tile for row %lu col %lu, "
+ "sample %lu",
+ (unsigned long) col, (unsigned long) row,
+ (unsigned long) s);
+ status = 0;
+ for (sample = 0; (sample < spp) && (sample < MAX_SAMPLES); sample++)
+ {
+ tbuff = srcbuffs[sample];
+ if (tbuff != NULL)
+ _TIFFfree(tbuff);
+ }
+ return status;
+ }
+ }
+ /* Tiles on the right edge may be padded out to tw
+ * which must be a multiple of 16.
+ * Ncol represents the visible (non padding) portion.
+ */
+ if (col + tw > imagewidth)
+ ncol = imagewidth - col;
+ else
+ ncol = tw;
+
+ row_offset = row * (((imagewidth * spp * bps) + 7) / 8);
+ col_offset = ((col * spp * bps) + 7) / 8;
+ bufp = obuf + row_offset + col_offset;
+
+ if ((bps % 8) == 0)
+ {
+ if (combineSeparateTileSamplesBytes(srcbuffs, bufp, ncol, nrow, imagewidth,
+ tw, spp, bps, NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ }
+ else
+ {
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ switch (shift_width)
+ {
+ case 1: if (combineSeparateTileSamples8bits (srcbuffs, bufp, ncol, nrow,
+ imagewidth, tw, spp, bps,
+ NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ break;
+ case 2: if (combineSeparateTileSamples16bits (srcbuffs, bufp, ncol, nrow,
+ imagewidth, tw, spp, bps,
+ NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ break;
+ case 3: if (combineSeparateTileSamples24bits (srcbuffs, bufp, ncol, nrow,
+ imagewidth, tw, spp, bps,
+ NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8: if (combineSeparateTileSamples32bits (srcbuffs, bufp, ncol, nrow,
+ imagewidth, tw, spp, bps,
+ NULL, 0, 0))
+ {
+ status = 0;
+ break;
+ }
+ break;
+ default: TIFFError ("readSeparateTilesIntoBuffer", "Unsupported bit depth: %d", bps);
+ status = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ for (sample = 0; (sample < spp) && (sample < MAX_SAMPLES); sample++)
+ {
+ tbuff = srcbuffs[sample];
+ if (tbuff != NULL)
+ _TIFFfree(tbuff);
+ }
+
+ return status;
+ }
+
+static int writeBufferToContigStrips(TIFF* out, uint8* buf, uint32 imagelength)
+ {
+ uint32 row, nrows, rowsperstrip;
+ tstrip_t strip = 0;
+ tsize_t stripsize;
+
+ TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ for (row = 0; row < imagelength; row += rowsperstrip)
+ {
+ nrows = (row + rowsperstrip > imagelength) ?
+ imagelength - row : rowsperstrip;
+ stripsize = TIFFVStripSize(out, nrows);
+ if (TIFFWriteEncodedStrip(out, strip++, buf, stripsize) < 0)
+ {
+ TIFFError(TIFFFileName(out), "Error, can't write strip %u", strip - 1);
+ return 1;
+ }
+ buf += stripsize;
+ }
+
+ return 0;
+ }
+
+/* Abandon plans to modify code so that plannar orientation separate images
+ * do not have all samples for each channel written before all samples
+ * for the next channel have been abandoned.
+ * Libtiff internals seem to depend on all data for a given sample
+ * being contiguous within a strip or tile when PLANAR_CONFIG is
+ * separate. All strips or tiles of a given plane are written
+ * before any strips or tiles of a different plane are stored.
+ */
+static int
+writeBufferToSeparateStrips (TIFF* out, uint8* buf,
+ uint32 length, uint32 width, uint16 spp,
+ struct dump_opts *dump)
+ {
+ uint8 *src;
+ uint16 bps;
+ uint32 row, nrows, rowsize, rowsperstrip;
+ uint32 bytes_per_sample;
+ tsample_t s;
+ tstrip_t strip = 0;
+ tsize_t stripsize = TIFFStripSize(out);
+ tsize_t rowstripsize, scanlinesize = TIFFScanlineSize(out);
+ tsize_t total_bytes = 0;
+ tdata_t obuf;
+
+ (void) TIFFGetFieldDefaulted(out, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ (void) TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
+ bytes_per_sample = (bps + 7) / 8;
+ rowsize = ((bps * spp * width) + 7) / 8; /* source has interleaved samples */
+ rowstripsize = rowsperstrip * bytes_per_sample * (width + 1);
+
+ obuf = _TIFFmalloc (rowstripsize);
+ if (obuf == NULL)
+ return 1;
+
+ for (s = 0; s < spp; s++)
+ {
+ for (row = 0; row < length; row += rowsperstrip)
+ {
+ nrows = (row + rowsperstrip > length) ? length - row : rowsperstrip;
+
+ stripsize = TIFFVStripSize(out, nrows);
+ src = buf + (row * rowsize);
+ total_bytes += stripsize;
+ memset (obuf, '\0', rowstripsize);
+ if (extractContigSamplesToBuffer(obuf, src, nrows, width, s, spp, bps, dump))
+ {
+ _TIFFfree(obuf);
+ return 1;
+ }
+ if ((dump->outfile != NULL) && (dump->level == 1))
+ {
+ dump_info(dump->outfile, dump->format,"",
+ "Sample %2d, Strip: %2d, bytes: %4d, Row %4d, bytes: %4d, Input offset: %6d",
+ s + 1, strip + 1, stripsize, row + 1, scanlinesize, src - buf);
+ dump_buffer(dump->outfile, dump->format, nrows, scanlinesize, row, obuf);
+ }
+
+ if (TIFFWriteEncodedStrip(out, strip++, obuf, stripsize) < 0)
+ {
+ TIFFError(TIFFFileName(out), "Error, can't write strip %u", strip - 1);
+ _TIFFfree(obuf);
+ return 1;
+ }
+ }
+ }
+
+ _TIFFfree(obuf);
+ return 0;
+}
+
+/* Extract all planes from contiguous buffer into a single tile buffer
+ * to be written out as a tile.
+ */
+static int writeBufferToContigTiles (TIFF* out, uint8* buf, uint32 imagelength,
+ uint32 imagewidth, tsample_t spp,
+ struct dump_opts* dump)
+ {
+ uint16 bps;
+ uint32 tl, tw;
+ uint32 row, col, nrow, ncol;
+ uint32 src_rowsize, col_offset;
+ uint32 tile_rowsize = TIFFTileRowSize(out);
+ uint8* bufp = (uint8*) buf;
+ tsize_t tile_buffsize = 0;
+ tsize_t tilesize = TIFFTileSize(out);
+ unsigned char *tilebuf = NULL;
+
+ TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
+ TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
+
+ tile_buffsize = tilesize;
+ if (tilesize < (tsize_t)(tl * tile_rowsize))
+ {
+#ifdef DEBUG2
+ TIFFError("writeBufferToContigTiles",
+ "Tilesize %lu is too small, using alternate calculation %u",
+ tilesize, tl * tile_rowsize);
+#endif
+ tile_buffsize = tl * tile_rowsize;
+ }
+
+ tilebuf = _TIFFmalloc(tile_buffsize);
+ if (tilebuf == 0)
+ return 1;
+
+ src_rowsize = ((imagewidth * spp * bps) + 7) / 8;
+ for (row = 0; row < imagelength; row += tl)
+ {
+ nrow = (row + tl > imagelength) ? imagelength - row : tl;
+ for (col = 0; col < imagewidth; col += tw)
+ {
+ /* Calculate visible portion of tile. */
+ if (col + tw > imagewidth)
+ ncol = imagewidth - col;
+ else
+ ncol = tw;
+
+ col_offset = (((col * bps * spp) + 7) / 8);
+ bufp = buf + (row * src_rowsize) + col_offset;
+ if (extractContigSamplesToTileBuffer(tilebuf, bufp, nrow, ncol, imagewidth,
+ tw, 0, spp, spp, bps, dump) > 0)
+ {
+ TIFFError("writeBufferToContigTiles",
+ "Unable to extract data to tile for row %lu, col %lu",
+ (unsigned long) row, (unsigned long)col);
+ _TIFFfree(tilebuf);
+ return 1;
+ }
+
+ if (TIFFWriteTile(out, tilebuf, col, row, 0, 0) < 0)
+ {
+ TIFFError("writeBufferToContigTiles",
+ "Cannot write tile at %lu %lu",
+ (unsigned long) col, (unsigned long) row);
+ _TIFFfree(tilebuf);
+ return 1;
+ }
+ }
+ }
+ _TIFFfree(tilebuf);
+
+ return 0;
+ } /* end writeBufferToContigTiles */
+
+/* Extract each plane from contiguous buffer into a single tile buffer
+ * to be written out as a tile.
+ */
+static int writeBufferToSeparateTiles (TIFF* out, uint8* buf, uint32 imagelength,
+ uint32 imagewidth, tsample_t spp,
+ struct dump_opts * dump)
+ {
+ tdata_t obuf = _TIFFmalloc(TIFFTileSize(out));
+ uint32 tl, tw;
+ uint32 row, col, nrow, ncol;
+ uint32 src_rowsize, col_offset;
+ uint16 bps;
+ tsample_t s;
+ uint8* bufp = (uint8*) buf;
+
+ if (obuf == NULL)
+ return 1;
+
+ TIFFGetField(out, TIFFTAG_TILELENGTH, &tl);
+ TIFFGetField(out, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(out, TIFFTAG_BITSPERSAMPLE, &bps);
+ src_rowsize = ((imagewidth * spp * bps) + 7) / 8;
+
+ for (row = 0; row < imagelength; row += tl)
+ {
+ nrow = (row + tl > imagelength) ? imagelength - row : tl;
+ for (col = 0; col < imagewidth; col += tw)
+ {
+ /* Calculate visible portion of tile. */
+ if (col + tw > imagewidth)
+ ncol = imagewidth - col;
+ else
+ ncol = tw;
+
+ col_offset = (((col * bps * spp) + 7) / 8);
+ bufp = buf + (row * src_rowsize) + col_offset;
+
+ for (s = 0; s < spp; s++)
+ {
+ if (extractContigSamplesToTileBuffer(obuf, bufp, nrow, ncol, imagewidth,
+ tw, s, 1, spp, bps, dump) > 0)
+ {
+ TIFFError("writeBufferToSeparateTiles",
+ "Unable to extract data to tile for row %lu, col %lu sample %d",
+ (unsigned long) row, (unsigned long)col, (int)s);
+ _TIFFfree(obuf);
+ return 1;
+ }
+
+ if (TIFFWriteTile(out, obuf, col, row, 0, s) < 0)
+ {
+ TIFFError("writeBufferToseparateTiles",
+ "Cannot write tile at %lu %lu sample %lu",
+ (unsigned long) col, (unsigned long) row,
+ (unsigned long) s);
+ _TIFFfree(obuf);
+ return 1;
+ }
+ }
+ }
+ }
+ _TIFFfree(obuf);
+
+ return 0;
+ } /* end writeBufferToSeparateTiles */
+
+static void
+processG3Options(char* cp)
+{
+ if( (cp = strchr(cp, ':')) ) {
+ if (defg3opts == (uint32) -1)
+ defg3opts = 0;
+ do {
+ cp++;
+ if (strneq(cp, "1d", 2))
+ defg3opts &= ~GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "2d", 2))
+ defg3opts |= GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "fill", 4))
+ defg3opts |= GROUP3OPT_FILLBITS;
+ else
+ usage();
+ } while( (cp = strchr(cp, ':')) );
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+ {
+ char* cp = NULL;
+
+ if (strneq(opt, "none",4))
+ {
+ defcompression = COMPRESSION_NONE;
+ /* DELETE ME: This should not be needed */
+ cp = strchr(opt, ':');
+ if (cp)
+ {
+ if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else if (cp[1] == 'a' )
+ jpegcolormode = JPEGCOLORMODE_RGB;
+ }
+ /* end DELETE ME: */
+ }
+ else if (streq(opt, "packbits"))
+ {
+ defcompression = COMPRESSION_PACKBITS;
+ }
+ else if (strneq(opt, "jpeg", 4))
+ {
+ cp = strchr(opt, ':');
+ defcompression = COMPRESSION_JPEG;
+ while ( cp )
+ {
+ if (isdigit((int)cp[1]))
+ quality = atoi(cp+1);
+ else if (cp[1] == 'r' )
+ jpegcolormode = JPEGCOLORMODE_RAW;
+ else if (cp[1] == 'a' )
+ jpegcolormode = JPEGCOLORMODE_RGB;
+ else
+ usage();
+ cp = strchr(cp+1,':');
+ }
+ }
+ else if (strneq(opt, "g3", 2))
+ {
+ processG3Options(opt);
+ defcompression = COMPRESSION_CCITTFAX3;
+ }
+ else if (streq(opt, "g4"))
+ {
+ defcompression = COMPRESSION_CCITTFAX4;
+ }
+ else if (strneq(opt, "lzw", 3))
+ {
+ cp = strchr(opt, ':');
+ if (cp)
+ defpredictor = atoi(cp+1);
+ defcompression = COMPRESSION_LZW;
+ }
+ else if (strneq(opt, "zip", 3))
+ {
+ cp = strchr(opt, ':');
+ if (cp)
+ defpredictor = atoi(cp+1);
+ defcompression = COMPRESSION_ADOBE_DEFLATE;
+ }
+ else
+ return (0);
+
+ return (1);
+ }
+
+static void
+usage(void)
+ {
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "\n%s\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+ }
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+#define CopyField4(tag, v1, v2, v3, v4) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
+
+static void
+cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
+{
+ switch (type) {
+ case TIFF_SHORT:
+ if (count == 1) {
+ uint16 shortv;
+ CopyField(tag, shortv);
+ } else if (count == 2) {
+ uint16 shortv1, shortv2;
+ CopyField2(tag, shortv1, shortv2);
+ } else if (count == 4) {
+ uint16 *tr, *tg, *tb, *ta;
+ CopyField4(tag, tr, tg, tb, ta);
+ } else if (count == (uint16) -1) {
+ uint16 shortv1;
+ uint16* shortav;
+ CopyField2(tag, shortv1, shortav);
+ }
+ break;
+ case TIFF_LONG:
+ { uint32 longv;
+ CopyField(tag, longv);
+ }
+ break;
+ case TIFF_RATIONAL:
+ if (count == 1) {
+ float floatv;
+ CopyField(tag, floatv);
+ } else if (count == (uint16) -1) {
+ float* floatav;
+ CopyField(tag, floatav);
+ }
+ break;
+ case TIFF_ASCII:
+ { char* stringv;
+ CopyField(tag, stringv);
+ }
+ break;
+ case TIFF_DOUBLE:
+ if (count == 1) {
+ double doublev;
+ CopyField(tag, doublev);
+ } else if (count == (uint16) -1) {
+ double* doubleav;
+ CopyField(tag, doubleav);
+ }
+ break;
+ default:
+ TIFFError(TIFFFileName(in),
+ "Data type %d is not supported, tag %d skipped.",
+ tag, type);
+ }
+}
+
+static struct cpTag {
+ uint16 tag;
+ uint16 count;
+ TIFFDataType type;
+} tags[] = {
+ { TIFFTAG_SUBFILETYPE, 1, TIFF_LONG },
+ { TIFFTAG_THRESHHOLDING, 1, TIFF_SHORT },
+ { TIFFTAG_DOCUMENTNAME, 1, TIFF_ASCII },
+ { TIFFTAG_IMAGEDESCRIPTION, 1, TIFF_ASCII },
+ { TIFFTAG_MAKE, 1, TIFF_ASCII },
+ { TIFFTAG_MODEL, 1, TIFF_ASCII },
+ { TIFFTAG_MINSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_MAXSAMPLEVALUE, 1, TIFF_SHORT },
+ { TIFFTAG_XRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YRESOLUTION, 1, TIFF_RATIONAL },
+ { TIFFTAG_PAGENAME, 1, TIFF_ASCII },
+ { TIFFTAG_XPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_YPOSITION, 1, TIFF_RATIONAL },
+ { TIFFTAG_RESOLUTIONUNIT, 1, TIFF_SHORT },
+ { TIFFTAG_SOFTWARE, 1, TIFF_ASCII },
+ { TIFFTAG_DATETIME, 1, TIFF_ASCII },
+ { TIFFTAG_ARTIST, 1, TIFF_ASCII },
+ { TIFFTAG_HOSTCOMPUTER, 1, TIFF_ASCII },
+ { TIFFTAG_WHITEPOINT, (uint16) -1, TIFF_RATIONAL },
+ { TIFFTAG_PRIMARYCHROMATICITIES,(uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_HALFTONEHINTS, 2, TIFF_SHORT },
+ { TIFFTAG_INKSET, 1, TIFF_SHORT },
+ { TIFFTAG_DOTRANGE, 2, TIFF_SHORT },
+ { TIFFTAG_TARGETPRINTER, 1, TIFF_ASCII },
+ { TIFFTAG_SAMPLEFORMAT, 1, TIFF_SHORT },
+ { TIFFTAG_YCBCRCOEFFICIENTS, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_YCBCRSUBSAMPLING, 2, TIFF_SHORT },
+ { TIFFTAG_YCBCRPOSITIONING, 1, TIFF_SHORT },
+ { TIFFTAG_REFERENCEBLACKWHITE, (uint16) -1,TIFF_RATIONAL },
+ { TIFFTAG_EXTRASAMPLES, (uint16) -1, TIFF_SHORT },
+ { TIFFTAG_SMINSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_SMAXSAMPLEVALUE, 1, TIFF_DOUBLE },
+ { TIFFTAG_STONITS, 1, TIFF_DOUBLE },
+};
+#define NTAGS (sizeof (tags) / sizeof (tags[0]))
+
+#define CopyTag(tag, count, type) cpTag(in, out, tag, count, type)
+
+/* Functions written by Richard Nolde, with exceptions noted. */
+void process_command_opts (int argc, char *argv[], char *mp, char *mode, uint32 *dirnum,
+ uint16 *defconfig, uint16 *deffillorder, uint32 *deftilewidth,
+ uint32 *deftilelength, uint32 *defrowsperstrip,
+ struct crop_mask *crop_data, struct pagedef *page,
+ struct dump_opts *dump,
+ unsigned int *imagelist, unsigned int *image_count )
+ {
+ int c, good_args = 0;
+ char *opt_offset = NULL; /* Position in string of value sought */
+ char *opt_ptr = NULL; /* Pointer to next token in option set */
+ char *sep = NULL; /* Pointer to a token separator */
+ unsigned int i, j, start, end;
+ extern int optind;
+ extern char* optarg;
+
+ *mp++ = 'w';
+ *mp = '\0';
+ while ((c = getopt(argc, argv,
+ "ac:d:e:f:hil:m:p:r:stvw:z:BCD:E:F:H:I:J:K:LMN:O:P:R:S:U:V:X:Y:Z:")) != -1)
+ {
+ good_args++;
+ switch (c) {
+ case 'a': mode[0] = 'a'; /* append to output */
+ break;
+ case 'c': if (!processCompressOptions(optarg)) /* compression scheme */
+ {
+ TIFFError ("Unknown compression option", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'd': start = strtoul(optarg, NULL, 0); /* initial IFD offset */
+ if (start == 0)
+ {
+ TIFFError ("","Directory offset must be greater than zero");
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ *dirnum = start - 1;
+ break;
+ case 'e': switch (tolower(optarg[0])) /* image export modes*/
+ {
+ case 'c': crop_data->exp_mode = ONE_FILE_COMPOSITE;
+ crop_data->img_mode = COMPOSITE_IMAGES;
+ break; /* Composite */
+ case 'd': crop_data->exp_mode = ONE_FILE_SEPARATED;
+ crop_data->img_mode = SEPARATED_IMAGES;
+ break; /* Divided */
+ case 'i': crop_data->exp_mode = FILE_PER_IMAGE_COMPOSITE;
+ crop_data->img_mode = COMPOSITE_IMAGES;
+ break; /* Image */
+ case 'm': crop_data->exp_mode = FILE_PER_IMAGE_SEPARATED;
+ crop_data->img_mode = SEPARATED_IMAGES;
+ break; /* Multiple */
+ case 's': crop_data->exp_mode = FILE_PER_SELECTION;
+ crop_data->img_mode = SEPARATED_IMAGES;
+ break; /* Sections */
+ default: TIFFError ("Unknown export mode","%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'f': if (streq(optarg, "lsb2msb")) /* fill order */
+ *deffillorder = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ *deffillorder = FILLORDER_MSB2LSB;
+ else
+ {
+ TIFFError ("Unknown fill order", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'h': usage();
+ break;
+ case 'i': ignore = TRUE; /* ignore errors */
+ break;
+ case 'l': outtiled = TRUE; /* tile length */
+ *deftilelength = atoi(optarg);
+ break;
+ case 'p': /* planar configuration */
+ if (streq(optarg, "separate"))
+ *defconfig = PLANARCONFIG_SEPARATE;
+ else if (streq(optarg, "contig"))
+ *defconfig = PLANARCONFIG_CONTIG;
+ else
+ {
+ TIFFError ("Unkown planar configuration", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'r': /* rows/strip */
+ *defrowsperstrip = atol(optarg);
+ break;
+ case 's': /* generate stripped output */
+ outtiled = FALSE;
+ break;
+ case 't': /* generate tiled output */
+ outtiled = TRUE;
+ break;
+ case 'v': TIFFError("Library Release", "%s", TIFFGetVersion());
+ TIFFError ("Tiffcrop version", "%s, last updated: %s",
+ tiffcrop_version_id, tiffcrop_rev_date);
+ TIFFError ("Tiffcp code", "Copyright (c) 1988-1997 Sam Leffler");
+ TIFFError (" ", "Copyright (c) 1991-1997 Silicon Graphics, Inc");
+ TIFFError ("Tiffcrop additions", "Copyright (c) 2007-2009 Richard Nolde");
+ exit (0);
+ break;
+ case 'w': /* tile width */
+ outtiled = TRUE;
+ *deftilewidth = atoi(optarg);
+ break;
+ case 'z': /* regions of an image specified as x1,y1,x2,y2:x3,y3,x4,y4 etc */
+ crop_data->crop_mode |= CROP_REGIONS;
+ for (i = 0, opt_ptr = strtok (optarg, ":");
+ ((opt_ptr != NULL) && (i < MAX_REGIONS));
+ (opt_ptr = strtok (NULL, ":")), i++)
+ {
+ crop_data->regions++;
+ if (sscanf(opt_ptr, "%lf,%lf,%lf,%lf",
+ &crop_data->corners[i].X1, &crop_data->corners[i].Y1,
+ &crop_data->corners[i].X2, &crop_data->corners[i].Y2) != 4)
+ {
+ TIFFError ("Unable to parse coordinates for region", "%d %s", i, optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ }
+ /* check for remaining elements over MAX_REGIONS */
+ if ((opt_ptr != NULL) && (i >= MAX_REGIONS))
+ {
+ TIFFError ("Region list exceeds limit of", "%d regions %s", MAX_REGIONS, optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);;
+ }
+ break;
+ /* options for file open modes */
+ case 'B': *mp++ = 'b'; *mp = '\0';
+ break;
+ case 'L': *mp++ = 'l'; *mp = '\0';
+ break;
+ case 'M': *mp++ = 'm'; *mp = '\0';
+ break;
+ case 'C': *mp++ = 'c'; *mp = '\0';
+ break;
+ /* options for Debugging / data dump */
+ case 'D': for (i = 0, opt_ptr = strtok (optarg, ",");
+ (opt_ptr != NULL);
+ (opt_ptr = strtok (NULL, ",")), i++)
+ {
+ opt_offset = strpbrk(opt_ptr, ":=");
+ /*
+ opt_offset = strchr(opt_ptr, ':');
+ */
+ if (opt_offset == NULL)
+ {
+ TIFFError("Invalid dump option", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+
+ *opt_offset = '\0';
+ /* convert option to lowercase */
+ end = strlen (opt_ptr);
+ for (i = 0; i < end; i++)
+ *(opt_ptr + i) = tolower(*(opt_ptr + i));
+ /* Look for dump format specification */
+ if (strncmp(opt_ptr, "for", 3) == 0)
+ {
+ /* convert value to lowercase */
+ end = strlen (opt_offset + 1);
+ for (i = 1; i <= end; i++)
+ *(opt_offset + i) = tolower(*(opt_offset + i));
+ /* check dump format value */
+ if (strncmp (opt_offset + 1, "txt", 3) == 0)
+ {
+ dump->format = DUMP_TEXT;
+ strcpy (dump->mode, "w");
+ }
+ else
+ {
+ if (strncmp(opt_offset + 1, "raw", 3) == 0)
+ {
+ dump->format = DUMP_RAW;
+ strcpy (dump->mode, "wb");
+ }
+ else
+ {
+ TIFFError("parse_command_opts", "Unknown dump format %s", opt_offset + 1);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ }
+ }
+ else
+ { /* Look for dump level specification */
+ if (strncmp (opt_ptr, "lev", 3) == 0)
+ dump->level = atoi(opt_offset + 1);
+ /* Look for input data dump file name */
+ if (strncmp (opt_ptr, "in", 2) == 0)
+ strncpy (dump->infilename, opt_offset + 1, PATH_MAX - 20);
+ /* Look for output data dump file name */
+ if (strncmp (opt_ptr, "out", 3) == 0)
+ strncpy (dump->outfilename, opt_offset + 1, PATH_MAX - 20);
+ if (strncmp (opt_ptr, "deb", 3) == 0)
+ dump->debug = atoi(opt_offset + 1);
+ }
+ }
+ if ((strlen(dump->infilename)) || (strlen(dump->outfilename)))
+ {
+ if (dump->level == 1)
+ TIFFError("","Defaulting to dump level 1, no data.");
+ if (dump->format == DUMP_NONE)
+ {
+ TIFFError("", "You must specify a dump format for dump files");
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ }
+ break;
+
+ /* image manipulation routine options */
+ case 'm': /* margins to exclude from selection, uppercase M was already used */
+ /* order of values must be TOP, LEFT, BOTTOM, RIGHT */
+ crop_data->crop_mode |= CROP_MARGINS;
+ for (i = 0, opt_ptr = strtok (optarg, ",:");
+ ((opt_ptr != NULL) && (i < 4));
+ (opt_ptr = strtok (NULL, ",:")), i++)
+ {
+ crop_data->margins[i] = atof(opt_ptr);
+ }
+ break;
+ case 'E': /* edge reference */
+ switch (tolower(optarg[0]))
+ {
+ case 't': crop_data->edge_ref = EDGE_TOP;
+ break;
+ case 'b': crop_data->edge_ref = EDGE_BOTTOM;
+ break;
+ case 'l': crop_data->edge_ref = EDGE_LEFT;
+ break;
+ case 'r': crop_data->edge_ref = EDGE_RIGHT;
+ break;
+ default: TIFFError ("Edge reference must be top, bottom, left, or right", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'F': /* flip eg mirror image or cropped segment, M was already used */
+ crop_data->crop_mode |= CROP_MIRROR;
+ switch (tolower(optarg[0]))
+ {
+ case 'h': crop_data->mirror = MIRROR_HORIZ;
+ break;
+ case 'v': crop_data->mirror = MIRROR_VERT;
+ break;
+ case 'b': crop_data->mirror = MIRROR_BOTH;
+ break;
+ default: TIFFError ("Flip mode must be horiz, vert, or both", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'H': /* set horizontal resolution to new value */
+ page->hres = atof (optarg);
+ page->mode |= PAGE_MODE_RESOLUTION;
+ break;
+ case 'I': /* invert the color space, eg black to white */
+ crop_data->crop_mode |= CROP_INVERT;
+ /* The PHOTOMETIC_INTERPRETATION tag may be updated */
+ if (streq(optarg, "black"))
+ {
+ crop_data->photometric = PHOTOMETRIC_MINISBLACK;
+ continue;
+ }
+ if (streq(optarg, "white"))
+ {
+ crop_data->photometric = PHOTOMETRIC_MINISWHITE;
+ continue;
+ }
+ if (streq(optarg, "data"))
+ {
+ crop_data->photometric = INVERT_DATA_ONLY;
+ continue;
+ }
+ if (streq(optarg, "both"))
+ {
+ crop_data->photometric = INVERT_DATA_AND_TAG;
+ continue;
+ }
+
+ TIFFError("Missing or unknown option for inverting PHOTOMETRIC_INTERPRETATION", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ break;
+ case 'J': /* horizontal margin for sectioned ouput pages */
+ page->hmargin = atof(optarg);
+ page->mode |= PAGE_MODE_MARGINS;
+ break;
+ case 'K': /* vertical margin for sectioned ouput pages*/
+ page->vmargin = atof(optarg);
+ page->mode |= PAGE_MODE_MARGINS;
+ break;
+ case 'N': /* list of images to process */
+ for (i = 0, opt_ptr = strtok (optarg, ",");
+ ((opt_ptr != NULL) && (i < MAX_IMAGES));
+ (opt_ptr = strtok (NULL, ",")))
+ { /* We do not know how many images are in file yet
+ * so we build a list to include the maximum allowed
+ * and follow it until we hit the end of the file.
+ * Image count is not accurate for odd, even, last
+ * so page numbers won't be valid either.
+ */
+ if (streq(opt_ptr, "odd"))
+ {
+ for (j = 1; j <= MAX_IMAGES; j += 2)
+ imagelist[i++] = j;
+ *image_count = (MAX_IMAGES - 1) / 2;
+ break;
+ }
+ else
+ {
+ if (streq(opt_ptr, "even"))
+ {
+ for (j = 2; j <= MAX_IMAGES; j += 2)
+ imagelist[i++] = j;
+ *image_count = MAX_IMAGES / 2;
+ break;
+ }
+ else
+ {
+ if (streq(opt_ptr, "last"))
+ imagelist[i++] = MAX_IMAGES;
+ else /* single value between commas */
+ {
+ sep = strpbrk(opt_ptr, ":-");
+ if (!sep)
+ imagelist[i++] = atoi(opt_ptr);
+ else
+ {
+ *sep = '\0';
+ start = atoi (opt_ptr);
+ if (!strcmp((sep + 1), "last"))
+ end = MAX_IMAGES;
+ else
+ end = atoi (sep + 1);
+ for (j = start; j <= end && j - start + i < MAX_IMAGES; j++)
+ imagelist[i++] = j;
+ }
+ }
+ }
+ }
+ }
+ *image_count = i;
+ break;
+ case 'O': /* page orientation */
+ switch (tolower(optarg[0]))
+ {
+ case 'a': page->orient = ORIENTATION_AUTO;
+ break;
+ case 'p': page->orient = ORIENTATION_PORTRAIT;
+ break;
+ case 'l': page->orient = ORIENTATION_LANDSCAPE;
+ break;
+ default: TIFFError ("Orientation must be portrait, landscape, or auto.", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'P': /* page size selection */
+ if (sscanf(optarg, "%lfx%lf", &page->width, &page->length) == 2)
+ {
+ strcpy (page->name, "Custom");
+ page->mode |= PAGE_MODE_PAPERSIZE;
+ break;
+ }
+ if (get_page_geometry (optarg, page))
+ {
+ if (!strcmp(optarg, "list"))
+ {
+ TIFFError("", "Name Width Length (in inches)");
+ for (i = 0; i < MAX_PAPERNAMES - 1; i++)
+ TIFFError ("", "%-15.15s %5.2f %5.2f",
+ PaperTable[i].name, PaperTable[i].width,
+ PaperTable[i].length);
+ exit (-1);
+ }
+
+ TIFFError ("Invalid paper size", "%s", optarg);
+ TIFFError ("", "Select one of:");
+ TIFFError("", "Name Width Length (in inches)");
+ for (i = 0; i < MAX_PAPERNAMES - 1; i++)
+ TIFFError ("", "%-15.15s %5.2f %5.2f",
+ PaperTable[i].name, PaperTable[i].width,
+ PaperTable[i].length);
+ exit (-1);
+ }
+ else
+ {
+ page->mode |= PAGE_MODE_PAPERSIZE;
+ }
+ break;
+ case 'R': /* rotate image or cropped segment */
+ crop_data->crop_mode |= CROP_ROTATE;
+ switch (strtoul(optarg, NULL, 0))
+ {
+ case 90: crop_data->rotation = (uint16)90;
+ break;
+ case 180: crop_data->rotation = (uint16)180;
+ break;
+ case 270: crop_data->rotation = (uint16)270;
+ break;
+ default: TIFFError ("Rotation must be 90, 180, or 270 degrees clockwise", "%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'S': /* subdivide into Cols:Rows sections, eg 3:2 would be 3 across and 2 down */
+ sep = strpbrk(optarg, ",:");
+ if (sep)
+ {
+ *sep = '\0';
+ page->cols = atoi(optarg);
+ page->rows = atoi(sep +1);
+ }
+ else
+ {
+ page->cols = atoi(optarg);
+ page->rows = atoi(optarg);
+ }
+ if ((page->cols * page->rows) > MAX_SECTIONS)
+ {
+ TIFFError ("Limit for subdivisions, ie rows x columns, exceeded", "%d", MAX_SECTIONS);
+ exit (-1);
+ }
+ page->mode |= PAGE_MODE_ROWSCOLS;
+ break;
+ case 'U': /* units for measurements and offsets */
+ if (streq(optarg, "in"))
+ {
+ crop_data->res_unit = RESUNIT_INCH;
+ page->res_unit = RESUNIT_INCH;
+ }
+ else if (streq(optarg, "cm"))
+ {
+ crop_data->res_unit = RESUNIT_CENTIMETER;
+ page->res_unit = RESUNIT_CENTIMETER;
+ }
+ else if (streq(optarg, "px"))
+ {
+ crop_data->res_unit = RESUNIT_NONE;
+ page->res_unit = RESUNIT_NONE;
+ }
+ else
+ {
+ TIFFError ("Illegal unit of measure","%s", optarg);
+ TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ }
+ break;
+ case 'V': /* set vertical resolution to new value */
+ page->vres = atof (optarg);
+ page->mode |= PAGE_MODE_RESOLUTION;
+ break;
+ case 'X': /* selection width */
+ crop_data->crop_mode |= CROP_WIDTH;
+ crop_data->width = atof(optarg);
+ break;
+ case 'Y': /* selection length */
+ crop_data->crop_mode |= CROP_LENGTH;
+ crop_data->length = atof(optarg);
+ break;
+ case 'Z': /* zones of an image X:Y read as zone X of Y */
+ crop_data->crop_mode |= CROP_ZONES;
+ for (i = 0, opt_ptr = strtok (optarg, ",");
+ ((opt_ptr != NULL) && (i < MAX_REGIONS));
+ (opt_ptr = strtok (NULL, ",")), i++)
+ {
+ crop_data->zones++;
+ opt_offset = strchr(opt_ptr, ':');
+ *opt_offset = '\0';
+ crop_data->zonelist[i].position = atoi(opt_ptr);
+ crop_data->zonelist[i].total = atoi(opt_offset + 1);
+ }
+ /* check for remaining elements over MAX_REGIONS */
+ if ((opt_ptr != NULL) && (i >= MAX_REGIONS))
+ {
+ TIFFError("Zone list exceeds region limit", "%d", MAX_REGIONS);
+ exit (-1);
+ }
+ break;
+ case '?': TIFFError ("For valid options type", "tiffcrop -h");
+ exit (-1);
+ /*NOTREACHED*/
+ }
+ }
+ } /* end process_command_opts */
+
+/* Start a new output file if one has not been previously opened or
+ * autoindex is set to non-zero. Update page and file counters
+ * so TIFFTAG PAGENUM will be correct in image.
+ */
+static int
+update_output_file (TIFF **tiffout, char *mode, int autoindex,
+ char *outname, unsigned int *page)
+ {
+ static int findex = 0; /* file sequence indicator */
+ char *sep;
+ char filenum[16];
+ char export_ext[16];
+ char exportname[PATH_MAX];
+
+ strcpy (export_ext, ".tiff");
+ if (autoindex && (*tiffout != NULL))
+ {
+ /* Close any export file that was previously opened */
+ TIFFClose (*tiffout);
+ *tiffout = NULL;
+ }
+
+ strncpy (exportname, outname, PATH_MAX - 15);
+ if (*tiffout == NULL) /* This is a new export file */
+ {
+ if (autoindex)
+ { /* create a new filename for each export */
+ findex++;
+ if ((sep = strstr(exportname, ".tif")) || (sep = strstr(exportname, ".TIF")))
+ {
+ strncpy (export_ext, sep, 5);
+ *sep = '\0';
+ }
+ else
+ strncpy (export_ext, ".tiff", 5);
+ export_ext[5] = '\0';
+
+ sprintf (filenum, "-%03d%s", findex, export_ext);
+ filenum[15] = '\0';
+ strncat (exportname, filenum, 14);
+ }
+
+ *tiffout = TIFFOpen(exportname, mode);
+ if (*tiffout == NULL)
+ {
+ TIFFError("update_output_file", "Unable to open output file %s\n", exportname);
+ return 1;
+ }
+ *page = 0;
+
+ return 0;
+ }
+ else
+ (*page)++;
+
+ return 0;
+ } /* end update_output_file */
+
+
+int
+main(int argc, char* argv[])
+ {
+ extern int optind;
+ uint16 defconfig = (uint16) -1;
+ uint16 deffillorder = 0;
+ uint32 deftilewidth = (uint32) 0;
+ uint32 deftilelength = (uint32) 0;
+ uint32 defrowsperstrip = (uint32) 0;
+ uint32 dirnum = 0;
+
+ TIFF *in = NULL;
+ TIFF *out = NULL;
+ char mode[10];
+ char *mp = mode;
+
+ /** RJN additions **/
+ struct image_data image; /* Image parameters for one image */
+ struct crop_mask crop; /* Cropping parameters for all images */
+ struct pagedef page; /* Page definition for output pages */
+ struct pageseg sections[MAX_SECTIONS]; /* Sections of one output page */
+ struct buffinfo seg_buffs[MAX_SECTIONS]; /* Segment buffer sizes and pointers */
+ struct dump_opts dump; /* Data dump options */
+ unsigned char *read_buff = NULL; /* Input image data buffer */
+ unsigned char *crop_buff = NULL; /* Crop area buffer */
+ unsigned char *sect_buff = NULL; /* Image section buffer */
+ unsigned char *sect_src = NULL; /* Image section buffer pointer */
+ unsigned int imagelist[MAX_IMAGES + 1]; /* individually specified images */
+ unsigned int image_count = 0;
+ unsigned int dump_images = 0;
+ unsigned int next_image = 0;
+ unsigned int next_page = 0;
+ unsigned int total_pages = 0;
+ unsigned int total_images = 0;
+ unsigned int end_of_input = FALSE;
+ int seg, length;
+ char temp_filename[PATH_MAX + 1];
+ memset (temp_filename, '\0', PATH_MAX + 1);
+ little_endian = *((unsigned char *)&little_endian) & '1';
+
+ initImageData(&image);
+ initCropMasks(&crop);
+ initPageSetup(&page, sections, seg_buffs);
+ initDumpOptions(&dump);
+
+ process_command_opts (argc, argv, mp, mode, &dirnum, &defconfig,
+ &deffillorder, &deftilewidth, &deftilelength, &defrowsperstrip,
+ &crop, &page, &dump, imagelist, &image_count);
+
+ if (argc - optind < 2)
+ usage();
+
+ if ((argc - optind) == 2)
+ pageNum = -1;
+ else
+ total_images = 0;
+ /* read multiple input files and write to output file(s) */
+ while (optind < argc - 1)
+ {
+ in = TIFFOpen (argv[optind], "r");
+ if (in == NULL)
+ return (-3);
+
+ /* If only one input file is specified, we can use directory count */
+ total_images = TIFFNumberOfDirectories(in);
+ if (image_count == 0)
+ {
+ dirnum = 0;
+ total_pages = total_images; /* Only valid with single input file */
+ }
+ else
+ {
+ dirnum = (tdir_t)(imagelist[next_image] - 1);
+ next_image++;
+
+ /* Total pages only valid for enumerated list of pages not derived
+ * using odd, even, or last keywords.
+ */
+ if (image_count > total_images)
+ image_count = total_images;
+
+ total_pages = image_count;
+ }
+
+ /* MAX_IMAGES is used for special case "last" in selection list */
+ if (dirnum == (MAX_IMAGES - 1))
+ dirnum = total_images - 1;
+
+ if (dirnum > (total_images))
+ {
+ TIFFError (TIFFFileName(in),
+ "Invalid image number %d, File contains only %d images",
+ (int)dirnum + 1, total_images);
+ if (out != NULL)
+ (void) TIFFClose(out);
+ return (1);
+ }
+
+ if (dirnum != 0 && !TIFFSetDirectory(in, (tdir_t)dirnum))
+ {
+ TIFFError(TIFFFileName(in),"Error, setting subdirectory at %d", dirnum);
+ if (out != NULL)
+ (void) TIFFClose(out);
+ return (1);
+ }
+
+ end_of_input = FALSE;
+ while (end_of_input == FALSE)
+ {
+ config = defconfig;
+ compression = defcompression;
+ predictor = defpredictor;
+ fillorder = deffillorder;
+ rowsperstrip = defrowsperstrip;
+ tilewidth = deftilewidth;
+ tilelength = deftilelength;
+ g3opts = defg3opts;
+
+ if (dump.format != DUMP_NONE)
+ {
+ /* manage input and/or output dump files here */
+ dump_images++;
+ length = strlen(dump.infilename);
+ if (length > 0)
+ {
+ if (dump.infile != NULL)
+ fclose (dump.infile);
+
+ sprintf (temp_filename, "%s-read-%03d.%s", dump.infilename, dump_images,
+ (dump.format == DUMP_TEXT) ? "txt" : "raw");
+ if ((dump.infile = fopen(temp_filename, dump.mode)) == NULL)
+ {
+ TIFFError ("Unable to open dump file for writing", "%s", temp_filename);
+ exit (-1);
+ }
+ dump_info(dump.infile, dump.format, "Reading image","%d from %s",
+ dump_images, TIFFFileName(in));
+ }
+ length = strlen(dump.outfilename);
+ if (length > 0)
+ {
+ if (dump.outfile != NULL)
+ fclose (dump.outfile);
+
+ sprintf (temp_filename, "%s-write-%03d.%s", dump.outfilename, dump_images,
+ (dump.format == DUMP_TEXT) ? "txt" : "raw");
+ if ((dump.outfile = fopen(temp_filename, dump.mode)) == NULL)
+ {
+ TIFFError ("Unable to open dump file for writing", "%s", temp_filename);
+ exit (-1);
+ }
+ dump_info(dump.outfile, dump.format, "Writing image","%d from %s",
+ dump_images, TIFFFileName(in));
+ }
+ }
+
+ if (dump.debug)
+ TIFFError("main", "Reading image %4d of %4d total pages.", dirnum + 1, total_pages);
+
+ if (loadImage(in, &image, &dump, &read_buff))
+ {
+ TIFFError("main", "Unable to load source image");
+ exit (-1);
+ }
+
+ /* Correct the image orientation if it was not ORIENTATION_TOPLEFT.
+ */
+ if (image.adjustments != 0)
+ {
+ if (correct_orientation(&image, &read_buff))
+ TIFFError("main", "Unable to correct image orientation");
+ }
+
+ if (getCropOffsets(&image, &crop, &dump))
+ {
+ TIFFError("main", "Unable to define crop regions");
+ exit (-1);
+ }
+
+ if (crop.selections > 0)
+ {
+ if (processCropSelections(&image, &crop, &read_buff, seg_buffs))
+ {
+ TIFFError("main", "Unable to process image selections");
+ exit (-1);
+ }
+ }
+ else /* Single image segment without zones or regions */
+ {
+ if (createCroppedImage(&image, &crop, &read_buff, &crop_buff))
+ {
+ TIFFError("main", "Unable to create output image");
+ exit (-1);
+ }
+ }
+ if (page.mode == PAGE_MODE_NONE)
+ { /* Whole image or sections not based on output page size */
+ if (crop.selections > 0)
+ {
+ writeSelections(in, &out, &crop, &image, &dump, seg_buffs,
+ mp, argv[argc - 1], &next_page, total_pages);
+ }
+ else /* One file all images and sections */
+ {
+ if (update_output_file (&out, mp, crop.exp_mode, argv[argc - 1],
+ &next_page))
+ exit (1);
+ if (writeCroppedImage(in, out, &image, &dump,crop.combined_width,
+ crop.combined_length, crop_buff, next_page, total_pages))
+ {
+ TIFFError("main", "Unable to write new image");
+ exit (-1);
+ }
+ }
+ }
+ else
+ {
+ /* If we used a crop buffer, our data is there, otherwise it is
+ * in the read_buffer
+ */
+ if (crop_buff != NULL)
+ sect_src = crop_buff;
+ else
+ sect_src = read_buff;
+ /* Break input image into pages or rows and columns */
+ if (computeOutputPixelOffsets(&crop, &image, &page, sections, &dump))
+ {
+ TIFFError("main", "Unable to compute output section data");
+ exit (-1);
+ }
+ /* If there are multiple files on the command line, the final one is assumed
+ * to be the output filename into which the images are written.
+ */
+ if (update_output_file (&out, mp, crop.exp_mode, argv[argc - 1], &next_page))
+ exit (1);
+
+ if (writeImageSections(in, out, &image, &page, sections, &dump, sect_src, &sect_buff))
+ {
+ TIFFError("main", "Unable to write image sections");
+ exit (-1);
+ }
+ }
+
+ /* No image list specified, just read the next image */
+ if (image_count == 0)
+ dirnum++;
+ else
+ {
+ dirnum = (tdir_t)(imagelist[next_image] - 1);
+ next_image++;
+ }
+
+ if (dirnum == MAX_IMAGES - 1)
+ dirnum = TIFFNumberOfDirectories(in) - 1;
+
+ if (!TIFFSetDirectory(in, (tdir_t)dirnum))
+ end_of_input = TRUE;
+ }
+ TIFFClose(in);
+ optind++;
+ }
+
+ /* If we did not use the read buffer as the crop buffer */
+ if (read_buff)
+ _TIFFfree(read_buff);
+
+ if (crop_buff)
+ _TIFFfree(crop_buff);
+
+ if (sect_buff)
+ _TIFFfree(sect_buff);
+
+ /* Clean up any segment buffers used for zones or regions */
+ for (seg = 0; seg < crop.selections; seg++)
+ _TIFFfree (seg_buffs[seg].buffer);
+
+ if (dump.format != DUMP_NONE)
+ {
+ if (dump.infile != NULL)
+ fclose (dump.infile);
+
+ if (dump.outfile != NULL)
+ {
+ dump_info (dump.outfile, dump.format, "", "Completed run for %s", TIFFFileName(out));
+ fclose (dump.outfile);
+ }
+ }
+
+ TIFFClose(out);
+
+ return (0);
+ } /* end main */
+
+
+/* Debugging functions */
+static int dump_data (FILE *dumpfile, int format, char *dump_tag, unsigned char *data, uint32 count)
+ {
+ int j, k;
+ uint32 i;
+ char dump_array[10];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (i = 0; i < count; i++)
+ {
+ for (j = 0, k = 7; j < 8; j++, k--)
+ {
+ bitset = (*(data + i)) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ }
+ dump_array[8] = '\0';
+ fprintf (dumpfile," %s", dump_array);
+ }
+ fprintf (dumpfile,"\n");
+ }
+ else
+ {
+ if ((fwrite (data, 1, count, dumpfile)) != count)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+
+static int dump_byte (FILE *dumpfile, int format, char *dump_tag, unsigned char data)
+ {
+ int j, k;
+ char dump_array[10];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (j = 0, k = 7; j < 8; j++, k--)
+ {
+ bitset = data & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ }
+ dump_array[8] = '\0';
+ fprintf (dumpfile," %s\n", dump_array);
+ }
+ else
+ {
+ if ((fwrite (&data, 1, 1, dumpfile)) != 1)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+
+static int dump_short (FILE *dumpfile, int format, char *dump_tag, uint16 data)
+ {
+ int j, k;
+ char dump_array[20];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (j = 0, k = 15; k >= 0; j++, k--)
+ {
+ bitset = data & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ if ((k % 8) == 0)
+ sprintf(&dump_array[++j], " ");
+ }
+ dump_array[17] = '\0';
+ fprintf (dumpfile," %s\n", dump_array);
+ }
+ else
+ {
+ if ((fwrite (&data, 2, 1, dumpfile)) != 2)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+
+static int dump_long (FILE *dumpfile, int format, char *dump_tag, uint32 data)
+ {
+ int j, k;
+ char dump_array[40];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (j = 0, k = 31; k >= 0; j++, k--)
+ {
+ bitset = data & (((uint32)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ if ((k % 8) == 0)
+ sprintf(&dump_array[++j], " ");
+ }
+ dump_array[35] = '\0';
+ fprintf (dumpfile," %s\n", dump_array);
+ }
+ else
+ {
+ if ((fwrite (&data, 4, 1, dumpfile)) != 4)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+ return (0);
+ }
+
+static int dump_wide (FILE *dumpfile, int format, char *dump_tag, uint64 data)
+ {
+ int j, k;
+ char dump_array[80];
+ unsigned char bitset;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ if (format == DUMP_TEXT)
+ {
+ fprintf (dumpfile," %s ", dump_tag);
+ for (j = 0, k = 63; k >= 0; j++, k--)
+ {
+ bitset = data & (((uint64)1 << k)) ? 1 : 0;
+ sprintf(&dump_array[j], (bitset) ? "1" : "0");
+ if ((k % 8) == 0)
+ sprintf(&dump_array[++j], " ");
+ }
+ dump_array[71] = '\0';
+ fprintf (dumpfile," %s\n", dump_array);
+ }
+ else
+ {
+ if ((fwrite (&data, 8, 1, dumpfile)) != 8)
+ {
+ TIFFError ("", "Unable to write binary data to dump file\n");
+ return (1);
+ }
+ }
+
+ return (0);
+ }
+
+static void dump_info(FILE *dumpfile, int format, char *prefix, char *msg, ...)
+ {
+ if (format == DUMP_TEXT)
+ {
+ va_list ap;
+ va_start(ap, msg);
+ fprintf(dumpfile, "%s ", prefix);
+ vfprintf(dumpfile, msg, ap);
+ fprintf(dumpfile, "\n");
+ }
+ }
+
+static int dump_buffer (FILE* dumpfile, int format, uint32 rows, uint32 width,
+ uint32 row, unsigned char *buff)
+ {
+ int j, k;
+ uint32 i;
+ unsigned char * dump_ptr;
+
+ if (dumpfile == NULL)
+ {
+ TIFFError ("", "Invalid FILE pointer for dump file\n");
+ return (1);
+ }
+
+ for (i = 0; i < rows; i++)
+ {
+ dump_ptr = buff + (i * width);
+ if (format == DUMP_TEXT)
+ dump_info (dumpfile, format, "",
+ "Row %4d, %d bytes at offset %d",
+ row + i + 1, width, row * width);
+
+ for (j = 0, k = width; k >= 10; j += 10, k -= 10, dump_ptr += 10)
+ dump_data (dumpfile, format, "", dump_ptr, 10);
+ if (k > 0)
+ dump_data (dumpfile, format, "", dump_ptr, k);
+ }
+ return (0);
+ }
+
+/* Extract one or more samples from an interleaved buffer. If count == 1,
+ * only the sample plane indicated by sample will be extracted. If count > 1,
+ * count samples beginning at sample will be extracted. Portions of a
+ * scanline can be extracted by specifying a start and end value.
+ */
+
+static int
+extractContigSamplesBytes (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int i, bytes_per_sample, sindex;
+ uint32 col, dst_rowsize, bit_offset;
+ uint32 src_byte, src_bit;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamplesBytes","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesBytes",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesBytes",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ dst_rowsize = (bps * (end - start) * count) / 8;
+
+ bytes_per_sample = (bps + 7) / 8;
+ /* Optimize case for copying all samples */
+ if (count == spp)
+ {
+ src = in + (start * spp * bytes_per_sample);
+ _TIFFmemcpy (dst, src, dst_rowsize);
+ }
+ else
+ {
+ for (col = start; col < end; col++)
+ {
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ bit_offset = col * bps * spp;
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+ src = in + src_byte;
+ for (i = 0; i < bytes_per_sample; i++)
+ *dst++ = *src++;
+ }
+ }
+ }
+
+ return (0);
+ } /* end extractContigSamplesBytes */
+
+static int
+extractContigSamples8bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint8 maskbits = 0, matchbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamples8bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamples8bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamples8bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = 0;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+ buff1 = buff2 = 0;
+ for (col = start; col < end; col++)
+ { /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (8 - src_bit - bps);
+ buff1 = ((*src) & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ }
+ else
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ ready_bits += bps;
+ }
+ }
+
+ while (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamples8bits */
+
+static int
+extractContigSamples16bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint16 maskbits = 0, matchbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamples16bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamples16bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamples16bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = 0;
+ maskbits = (uint16)-1 >> (16 - bps);
+
+ for (col = start; col < end; col++)
+ { /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (16 - src_bit - bps);
+
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+ if (ready_bits < 8) /* add another bps bits to the buffer */
+ {
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamples16bits */
+
+
+static int
+extractContigSamples24bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint32 maskbits = 0, matchbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((in == NULL) || (out == NULL))
+ {
+ TIFFError("extractContigSamples24bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamples24bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamples24bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = 0;
+ maskbits = (uint32)-1 >> ( 32 - bps);
+ for (col = start; col < end; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (32 - src_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ if (ready_bits < 16) /* add another bps bits to the buffer */
+ {
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamples24bits */
+
+static int
+extractContigSamples32bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end)
+ {
+ int ready_bits = 0, sindex = 0, shift_width = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((in == NULL) || (out == NULL))
+ {
+ TIFFError("extractContigSamples32bits","Invalid input or output buffer");
+ return (1);
+ }
+
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamples32bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamples32bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ shift_width = ((bps + 7) / 8) + 1;
+ ready_bits = 0;
+ maskbits = (uint64)-1 >> ( 64 - bps);
+ for (col = start; col < end; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (64 - src_bit - bps);
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 32)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamples32bits */
+
+static int
+extractContigSamplesShifted8bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end,
+ int shift)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint8 maskbits = 0, matchbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamplesShifted8bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesShifted8bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesShifted8bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = shift;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+ buff1 = buff2 = 0;
+ for (col = start; col < end; col++)
+ { /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (8 - src_bit - bps);
+ buff1 = ((*src) & matchbits) << (src_bit);
+ if ((col == start) && (sindex == sample))
+ buff2 = *src & ((uint8)-1) << (shift);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ |= buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ }
+ else
+ buff2 = buff2 | (buff1 >> ready_bits);
+ ready_bits += bps;
+ }
+ }
+
+ while (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamplesShifted8bits */
+
+static int
+extractContigSamplesShifted16bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end,
+ int shift)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint16 maskbits = 0, matchbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("extractContigSamplesShifted16bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesShifted16bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesShifted16bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = shift;
+ maskbits = (uint16)-1 >> (16 - bps);
+ for (col = start; col < end; col++)
+ { /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (16 - src_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+
+ if ((col == start) && (sindex == sample))
+ buff2 = buff1 & ((uint16)-1) << (8 - shift);
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ if (ready_bits < 8) /* add another bps bits to the buffer */
+ buff2 = buff2 | (buff1 >> ready_bits);
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ }
+
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamplesShifted16bits */
+
+
+static int
+extractContigSamplesShifted24bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end,
+ int shift)
+ {
+ int ready_bits = 0, sindex = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint32 maskbits = 0, matchbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((in == NULL) || (out == NULL))
+ {
+ TIFFError("extractContigSamplesShifted24bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesShifted24bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesShifted24bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ ready_bits = shift;
+ maskbits = (uint32)-1 >> ( 32 - bps);
+ for (col = start; col < end; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (32 - src_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+
+ if ((col == start) && (sindex == sample))
+ buff2 = buff1 & ((uint32)-1) << (16 - shift);
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ if (ready_bits < 16) /* add another bps bits to the buffer */
+ {
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamplesShifted24bits */
+
+static int
+extractContigSamplesShifted32bits (uint8 *in, uint8 *out, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ tsample_t count, uint32 start, uint32 end,
+ int shift)
+ {
+ int ready_bits = 0, sindex = 0, shift_width = 0;
+ uint32 col, src_byte, src_bit, bit_offset;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ uint8 *src = in;
+ uint8 *dst = out;
+
+ if ((in == NULL) || (out == NULL))
+ {
+ TIFFError("extractContigSamplesShifted32bits","Invalid input or output buffer");
+ return (1);
+ }
+
+
+ if ((start > end) || (start > cols))
+ {
+ TIFFError ("extractContigSamplesShifted32bits",
+ "Invalid start column value %d ignored", start);
+ start = 0;
+ }
+ if ((end == 0) || (end > cols))
+ {
+ TIFFError ("extractContigSamplesShifted32bits",
+ "Invalid end column value %d ignored", end);
+ end = cols;
+ }
+
+ shift_width = ((bps + 7) / 8) + 1;
+ ready_bits = shift;
+ maskbits = (uint64)-1 >> ( 64 - bps);
+ for (col = start; col < end; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps * spp;
+ for (sindex = sample; (sindex < spp) && (sindex < (sample + count)); sindex++)
+ {
+ if (sindex == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sindex * bps)) / 8;
+ src_bit = (bit_offset + (sindex * bps)) % 8;
+ }
+
+ src = in + src_byte;
+ matchbits = maskbits << (64 - src_bit - bps);
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ if ((col == start) && (sindex == sample))
+ buff2 = buff3 & ((uint64)-1) << (32 - shift);
+
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ if (ready_bits < 32)
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end extractContigSamplesShifted32bits */
+
+static int
+extractContigSamplesToBuffer(uint8 *out, uint8 *in, uint32 rows, uint32 cols,
+ tsample_t sample, uint16 spp, uint16 bps,
+ struct dump_opts *dump)
+ {
+ int shift_width, bytes_per_sample, bytes_per_pixel;
+ uint32 src_rowsize, src_offset, row, first_col = 0;
+ uint32 dst_rowsize, dst_offset;
+ tsample_t count = 1;
+ uint8 *src, *dst;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if ((bps % 8) == 0)
+ shift_width = 0;
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+ src_rowsize = ((bps * spp * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols) + 7) / 8;
+
+ if ((dump->outfile != NULL) && (dump->level == 4))
+ {
+ dump_info (dump->outfile, dump->format, "extractContigSamplesToBuffer",
+ "Sample %d, %d rows", sample + 1, rows + 1);
+ }
+ for (row = 0; row < rows; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = row * dst_rowsize;
+ src = in + src_offset;
+ dst = out + dst_offset;
+
+ /* pack the data into the scanline */
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamples8bits (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ }
+ else
+ if (extractContigSamples16bits (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ case 2: if (extractContigSamples24bits (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamples32bits (src, dst, cols, sample,
+ spp, bps, count, first_col, cols))
+ return (1);
+ break;
+ default: TIFFError ("extractContigSamplesToBuffer", "Unsupported bit depth: %d", bps);
+ return (1);
+ }
+ if ((dump->outfile != NULL) && (dump->level == 4))
+ dump_buffer(dump->outfile, dump->format, 1, dst_rowsize, row, dst);
+ }
+
+ return (0);
+ } /* end extractContigSamplesToBuffer */
+
+static int
+extractContigSamplesToTileBuffer(uint8 *out, uint8 *in, uint32 rows, uint32 cols,
+ uint32 imagewidth, uint32 tilewidth, tsample_t sample,
+ uint16 count, uint16 spp, uint16 bps, struct dump_opts *dump)
+ {
+ int shift_width, bytes_per_sample, bytes_per_pixel;
+ uint32 src_rowsize, src_offset, row;
+ uint32 dst_rowsize, dst_offset;
+ uint8 *src, *dst;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if ((bps % 8) == 0)
+ shift_width = 0;
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+
+ if ((dump->outfile != NULL) && (dump->level == 4))
+ {
+ dump_info (dump->outfile, dump->format, "extractContigSamplesToTileBuffer",
+ "Sample %d, %d rows", sample + 1, rows + 1);
+ }
+
+ src_rowsize = ((bps * spp * imagewidth) + 7) / 8;
+ dst_rowsize = ((bps * tilewidth * count) + 7) / 8;
+
+ for (row = 0; row < rows; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = row * dst_rowsize;
+ src = in + src_offset;
+ dst = out + dst_offset;
+
+ /* pack the data into the scanline */
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamples8bits (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ }
+ else
+ if (extractContigSamples16bits (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ case 2: if (extractContigSamples24bits (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamples32bits (src, dst, cols, sample,
+ spp, bps, count, 0, cols))
+ return (1);
+ break;
+ default: TIFFError ("extractContigSamplesToTileBuffer", "Unsupported bit depth: %d", bps);
+ return (1);
+ }
+ if ((dump->outfile != NULL) && (dump->level == 4))
+ dump_buffer(dump->outfile, dump->format, 1, dst_rowsize, row, dst);
+ }
+
+ return (0);
+ } /* end extractContigSamplesToTileBuffer */
+
+static int readContigStripsIntoBuffer (TIFF* in, uint8* buf)
+ {
+ uint8* bufp = buf;
+ int32 bytes_read = 0;
+ uint16 strip, nstrips = TIFFNumberOfStrips(in);
+ uint32 stripsize = TIFFStripSize(in);
+ uint32 rows = 0;
+ uint32 rps = TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rps);
+ tsize_t scanline_size = TIFFScanlineSize(in);
+
+ for (strip = 0; strip < nstrips; strip++)
+ {
+ bytes_read = TIFFReadEncodedStrip (in, strip, bufp, -1);
+ rows = bytes_read / scanline_size;
+ if ((strip < (nstrips - 1)) && (bytes_read != (int32)stripsize))
+ TIFFError("", "Strip %d: read %lu bytes, strip size %lu",
+ (int)strip + 1, (unsigned long) bytes_read, (unsigned long)stripsize);
+
+ if (bytes_read < 0 && !ignore)
+ {
+ TIFFError("", "Error reading strip %lu after %lu rows",
+ (unsigned long) strip, (unsigned long)rows);
+ return 0;
+ }
+ bufp += bytes_read;
+ }
+
+ return 1;
+ } /* end readContigStripsIntoBuffer */
+
+static int
+combineSeparateSamplesBytes (unsigned char *srcbuffs[], unsigned char *out,
+ uint32 cols, uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int i, bytes_per_sample;
+ uint32 row, col, col_offset, src_rowsize, dst_rowsize, row_offset;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t s;
+
+ src = srcbuffs[0];
+ dst = out;
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamplesBytes","Invalid buffer address");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * spp * cols) + 7) / 8;
+ for (row = 0; row < rows; row++)
+ {
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ for (s = 0; s < spp; s++)
+ {
+ dump_info (dumpfile, format, "combineSeparateSamplesBytes","Input data, Sample %d", s);
+ dump_buffer(dumpfile, format, 1, cols, row, srcbuffs[s] + (row * src_rowsize));
+ }
+ }
+ dst = out + (row * dst_rowsize);
+ row_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ col_offset = row_offset + (col * (bps / 8));
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ src = srcbuffs[s] + col_offset;
+ for (i = 0; i < bytes_per_sample; i++)
+ *(dst + i) = *(src + i);
+ src += bytes_per_sample;
+ dst += bytes_per_sample;
+ }
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamplesBytes","Output data, combined samples");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamplesBytes */
+
+static int
+combineSeparateSamples8bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0;
+ int bytes_per_sample = 0;
+ uint32 src_rowsize, dst_rowsize, src_offset;
+ uint32 bit_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint8 maskbits = 0, matchbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[32];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamples8bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols * spp) + 7) / 8;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (8 - src_bit - bps);
+ /* load up next sample from each plane */
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ buff1 = ((*src) & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ strcpy (action, "Flush");
+ }
+ else
+ {
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Match bits", matchbits);
+ dump_byte (dumpfile, format, "Src bits", *src);
+ dump_byte (dumpfile, format, "Buff1 bits", buff1);
+ dump_byte (dumpfile, format, "Buff2 bits", buff2);
+ dump_info (dumpfile, format, "","%s", action);
+ }
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Final bits", buff1);
+ }
+ }
+
+ if ((dumpfile != NULL) && (level >= 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamples8bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamples8bits */
+
+static int
+combineSeparateSamples16bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0, bytes_per_sample = 0;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 bit_offset, src_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint16 maskbits = 0, matchbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamples16bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols * spp) + 7) / 8;
+ maskbits = (uint16)-1 >> (16 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (16 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+
+ dump_short (dumpfile, format, "Match bits", matchbits);
+ dump_data (dumpfile, format, "Src bits", src, 2);
+ dump_short (dumpfile, format, "Buff1 bits", buff1);
+ dump_short (dumpfile, format, "Buff2 bits", buff2);
+ dump_byte (dumpfile, format, "Write byte", bytebuff);
+ dump_info (dumpfile, format, "","Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ if (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Final bits", bytebuff);
+ }
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamples16bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamples16bits */
+
+static int
+combineSeparateSamples24bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0, bytes_per_sample = 0;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 bit_offset, src_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint32 maskbits = 0, matchbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamples24bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols * spp) + 7) / 8;
+ maskbits = (uint32)-1 >> ( 32 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (32 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 16)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "","Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "", "Ready bits: %2d", ready_bits);
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamples24bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamples24bits */
+
+static int
+combineSeparateSamples32bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0, bytes_per_sample = 0, shift_width = 0;
+ uint32 src_rowsize, dst_rowsize, bit_offset, src_offset;
+ uint32 src_byte = 0, src_bit = 0;
+ uint32 row, col;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateSamples32bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * cols) + 7) / 8;
+ dst_rowsize = ((bps * cols * spp) + 7) / 8;
+ maskbits = (uint64)-1 >> ( 64 - bps);
+ shift_width = ((bps + 7) / 8) + 1;
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (64 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 32)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Sample %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_wide (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 8);
+ dump_wide (dumpfile, format, "Buff1 bits ", buff1);
+ dump_wide (dumpfile, format, "Buff2 bits ", buff2);
+ dump_info (dumpfile, format, "", "Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "", "Ready bits: %2d", ready_bits);
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateSamples32bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out);
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateSamples32bits */
+
+static int
+combineSeparateTileSamplesBytes (unsigned char *srcbuffs[], unsigned char *out,
+ uint32 cols, uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int i, bytes_per_sample;
+ uint32 row, col, col_offset, src_rowsize, dst_rowsize, src_offset;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t s;
+
+ src = srcbuffs[0];
+ dst = out;
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamplesBytes","Invalid buffer address");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = imagewidth * bytes_per_sample * spp;
+ for (row = 0; row < rows; row++)
+ {
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ for (s = 0; s < spp; s++)
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamplesBytes","Input data, Sample %d", s);
+ dump_buffer(dumpfile, format, 1, cols, row, srcbuffs[s] + (row * src_rowsize));
+ }
+ }
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+#ifdef DEVELMODE
+ TIFFError("","Tile row %4d, Src offset %6d Dst offset %6d",
+ row, src_offset, dst - out);
+#endif
+ for (col = 0; col < cols; col++)
+ {
+ col_offset = src_offset + (col * (bps / 8));
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ src = srcbuffs[s] + col_offset;
+ for (i = 0; i < bytes_per_sample; i++)
+ *(dst + i) = *(src + i);
+ dst += bytes_per_sample;
+ }
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamplesBytes","Output data, combined samples");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamplesBytes */
+
+static int
+combineSeparateTileSamples8bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0;
+ uint32 src_rowsize, dst_rowsize, src_offset;
+ uint32 bit_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint8 maskbits = 0, matchbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[32];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamples8bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (8 - src_bit - bps);
+ /* load up next sample from each plane */
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ buff1 = ((*src) & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ strcpy (action, "Flush");
+ }
+ else
+ {
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Match bits", matchbits);
+ dump_byte (dumpfile, format, "Src bits", *src);
+ dump_byte (dumpfile, format, "Buff1 bits", buff1);
+ dump_byte (dumpfile, format, "Buff2 bits", buff2);
+ dump_info (dumpfile, format, "","%s", action);
+ }
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Final bits", buff1);
+ }
+ }
+
+ if ((dumpfile != NULL) && (level >= 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamples8bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamples8bits */
+
+static int
+combineSeparateTileSamples16bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 bit_offset, src_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint16 maskbits = 0, matchbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamples16bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ maskbits = (uint16)-1 >> (16 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (16 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+
+ dump_short (dumpfile, format, "Match bits", matchbits);
+ dump_data (dumpfile, format, "Src bits", src, 2);
+ dump_short (dumpfile, format, "Buff1 bits", buff1);
+ dump_short (dumpfile, format, "Buff2 bits", buff2);
+ dump_byte (dumpfile, format, "Write byte", bytebuff);
+ dump_info (dumpfile, format, "","Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ if (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+ dump_byte (dumpfile, format, "Final bits", bytebuff);
+ }
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamples16bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamples16bits */
+
+static int
+combineSeparateTileSamples24bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 bit_offset, src_offset;
+ uint32 row, col, src_byte = 0, src_bit = 0;
+ uint32 maskbits = 0, matchbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamples24bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ maskbits = (uint32)-1 >> ( 32 - bps);
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (32 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 16)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Samples %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "","Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "", "Ready bits: %2d", ready_bits);
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamples24bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out + (row * dst_rowsize));
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamples24bits */
+
+static int
+combineSeparateTileSamples32bits (uint8 *in[], uint8 *out, uint32 cols,
+ uint32 rows, uint32 imagewidth,
+ uint32 tw, uint16 spp, uint16 bps,
+ FILE *dumpfile, int format, int level)
+ {
+ int ready_bits = 0, shift_width = 0;
+ uint32 src_rowsize, dst_rowsize, bit_offset, src_offset;
+ uint32 src_byte = 0, src_bit = 0;
+ uint32 row, col;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ tsample_t s;
+ unsigned char *src = in[0];
+ unsigned char *dst = out;
+ char action[8];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("combineSeparateTileSamples32bits","Invalid input or output buffer");
+ return (1);
+ }
+
+ src_rowsize = ((bps * tw) + 7) / 8;
+ dst_rowsize = ((imagewidth * bps * spp) + 7) / 8;
+ maskbits = (uint64)-1 >> ( 64 - bps);
+ shift_width = ((bps + 7) / 8) + 1;
+
+ for (row = 0; row < rows; row++)
+ {
+ ready_bits = 0;
+ buff1 = buff2 = 0;
+ dst = out + (row * dst_rowsize);
+ src_offset = row * src_rowsize;
+ for (col = 0; col < cols; col++)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = col * bps;
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+
+ matchbits = maskbits << (64 - src_bit - bps);
+ for (s = 0; s < spp; s++)
+ {
+ src = in[s] + src_offset + src_byte;
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 32)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ strcpy (action, "Flush");
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ strcpy (action, "Update");
+ }
+ ready_bits += bps;
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Sample %d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, s, src_byte, src_bit, dst - out);
+ dump_wide (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 8);
+ dump_wide (dumpfile, format, "Buff1 bits ", buff1);
+ dump_wide (dumpfile, format, "Buff2 bits ", buff2);
+ dump_info (dumpfile, format, "", "Ready bits: %d, %s", ready_bits, action);
+ }
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ if ((dumpfile != NULL) && (level == 3))
+ {
+ dump_info (dumpfile, format, "",
+ "Row %3d, Col %3d, Src byte offset %3d bit offset %2d Dst offset %3d",
+ row + 1, col + 1, src_byte, src_bit, dst - out);
+
+ dump_long (dumpfile, format, "Match bits ", matchbits);
+ dump_data (dumpfile, format, "Src bits ", src, 4);
+ dump_long (dumpfile, format, "Buff1 bits ", buff1);
+ dump_long (dumpfile, format, "Buff2 bits ", buff2);
+ dump_byte (dumpfile, format, "Write bits1", bytebuff1);
+ dump_byte (dumpfile, format, "Write bits2", bytebuff2);
+ dump_info (dumpfile, format, "", "Ready bits: %2d", ready_bits);
+ }
+
+ if ((dumpfile != NULL) && (level == 2))
+ {
+ dump_info (dumpfile, format, "combineSeparateTileSamples32bits","Output data");
+ dump_buffer(dumpfile, format, 1, dst_rowsize, row, out);
+ }
+ }
+
+ return (0);
+ } /* end combineSeparateTileSamples32bits */
+
+
+static int readSeparateStripsIntoBuffer (TIFF *in, uint8 *obuf, uint32 length,
+ uint32 width, uint16 spp,
+ struct dump_opts *dump)
+ {
+ int i, j, bytes_per_sample, bytes_per_pixel, shift_width, result = 1;
+ int32 bytes_read = 0;
+ uint16 bps, nstrips, planar, strips_per_sample;
+ uint32 src_rowsize, dst_rowsize, rows_processed, rps;
+ uint32 rows_this_strip = 0;
+ tsample_t s;
+ tstrip_t strip;
+ tsize_t scanlinesize = TIFFScanlineSize(in);
+ tsize_t stripsize = TIFFStripSize(in);
+ unsigned char *srcbuffs[MAX_SAMPLES];
+ unsigned char *buff = NULL;
+ unsigned char *dst = NULL;
+
+ if (obuf == NULL)
+ {
+ TIFFError("readSeparateStripsIntoBuffer","Invalid buffer argument");
+ return (0);
+ }
+
+ memset (srcbuffs, '\0', sizeof(srcbuffs));
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bps);
+ TIFFGetFieldDefaulted(in, TIFFTAG_PLANARCONFIG, &planar);
+ TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rps);
+ if (rps > length)
+ rps = length;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ src_rowsize = ((bps * width) + 7) / 8;
+ dst_rowsize = ((bps * width * spp) + 7) / 8;
+ dst = obuf;
+
+ if ((dump->infile != NULL) && (dump->level == 3))
+ {
+ dump_info (dump->infile, dump->format, "",
+ "Image width %d, length %d, Scanline size, %4d bytes",
+ width, length, scanlinesize);
+ dump_info (dump->infile, dump->format, "",
+ "Bits per sample %d, Samples per pixel %d, Shift width %d",
+ bps, spp, shift_width);
+ }
+
+ /* Libtiff seems to assume/require that data for separate planes are
+ * written one complete plane after another and not interleaved in any way.
+ * Multiple scanlines and possibly strips of the same plane must be
+ * written before data for any other plane.
+ */
+ nstrips = TIFFNumberOfStrips(in);
+ strips_per_sample = nstrips /spp;
+
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ srcbuffs[s] = NULL;
+ buff = _TIFFmalloc(stripsize);
+ if (!buff)
+ {
+ TIFFError ("readSeparateStripsIntoBuffer",
+ "Unable to allocate strip read buffer for sample %d", s);
+ for (i = 0; i < s; i++)
+ _TIFFfree (srcbuffs[i]);
+ return 0;
+ }
+ srcbuffs[s] = buff;
+ }
+
+ rows_processed = 0;
+ for (j = 0; (j < strips_per_sample) && (result == 1); j++)
+ {
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ buff = srcbuffs[s];
+ strip = (s * strips_per_sample) + j;
+ bytes_read = TIFFReadEncodedStrip (in, strip, buff, stripsize);
+ rows_this_strip = bytes_read / src_rowsize;
+ if (bytes_read < 0 && !ignore)
+ {
+ TIFFError(TIFFFileName(in),
+ "Error, can't read strip %lu for sample %d",
+ (unsigned long) strip, s + 1);
+ result = 0;
+ break;
+ }
+#ifdef DEVELMODE
+ TIFFError("", "Strip %2d, read %5d bytes for %4d scanlines, shift width %d",
+ strip, bytes_read, rows_this_strip, shift_width);
+#endif
+ }
+
+ if (rps > rows_this_strip)
+ rps = rows_this_strip;
+ dst = obuf + (dst_rowsize * rows_processed);
+ if ((bps % 8) == 0)
+ {
+ if (combineSeparateSamplesBytes (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ }
+ else
+ {
+ switch (shift_width)
+ {
+ case 1: if (combineSeparateSamples8bits (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ break;
+ case 2: if (combineSeparateSamples16bits (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ break;
+ case 3: if (combineSeparateSamples24bits (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8: if (combineSeparateSamples32bits (srcbuffs, dst, width, rps,
+ spp, bps, dump->infile,
+ dump->format, dump->level))
+ {
+ result = 0;
+ break;
+ }
+ break;
+ default: TIFFError ("readSeparateStripsIntoBuffer", "Unsupported bit depth: %d", bps);
+ result = 0;
+ break;
+ }
+ }
+
+ if ((rows_processed + rps) > length)
+ {
+ rows_processed = length;
+ rps = length - rows_processed;
+ }
+ else
+ rows_processed += rps;
+ }
+
+ /* free any buffers allocated for each plane or scanline and
+ * any temporary buffers
+ */
+ for (s = 0; (s < spp) && (s < MAX_SAMPLES); s++)
+ {
+ buff = srcbuffs[s];
+ if (buff != NULL)
+ _TIFFfree(buff);
+ }
+
+ return (result);
+ } /* end readSeparateStripsIntoBuffer */
+
+static int
+get_page_geometry (char *name, struct pagedef *page)
+ {
+ char *ptr;
+ int n;
+
+ for (ptr = name; *ptr; ptr++)
+ *ptr = (char)tolower((int)*ptr);
+
+ for (n = 0; n < MAX_PAPERNAMES; n++)
+ {
+ if (strcmp(name, PaperTable[n].name) == 0)
+ {
+ page->width = PaperTable[n].width;
+ page->length = PaperTable[n].length;
+ strncpy (page->name, PaperTable[n].name, 15);
+ page->name[15] = '\0';
+ return (0);
+ }
+ }
+
+ return (1);
+ }
+
+
+static void
+initPageSetup (struct pagedef *page, struct pageseg *pagelist,
+ struct buffinfo seg_buffs[])
+ {
+ int i;
+
+ strcpy (page->name, "");
+ page->mode = PAGE_MODE_NONE;
+ page->res_unit = RESUNIT_NONE;
+ page->hres = 0.0;
+ page->vres = 0.0;
+ page->width = 0.0;
+ page->length = 0.0;
+ page->hmargin = 0.0;
+ page->vmargin = 0.0;
+ page->rows = 0;
+ page->cols = 0;
+ page->orient = ORIENTATION_NONE;
+
+ for (i = 0; i < MAX_SECTIONS; i++)
+ {
+ pagelist[i].x1 = (uint32)0;
+ pagelist[i].x2 = (uint32)0;
+ pagelist[i].y1 = (uint32)0;
+ pagelist[i].y2 = (uint32)0;
+ pagelist[i].buffsize = (uint32)0;
+ pagelist[i].position = 0;
+ pagelist[i].total = 0;
+ }
+
+ for (i = 0; i < MAX_OUTBUFFS; i++)
+ {
+ seg_buffs[i].size = 0;
+ seg_buffs[i].buffer = NULL;
+ }
+ }
+
+static void
+initImageData (struct image_data *image)
+ {
+ image->xres = 0.0;
+ image->yres = 0.0;
+ image->width = 0;
+ image->length = 0;
+ image->res_unit = RESUNIT_NONE;
+ image->bps = 0;
+ image->spp = 0;
+ image->planar = 0;
+ image->photometric = 0;
+ image->orientation = 0;
+ image->adjustments = 0;
+ }
+
+static void
+initCropMasks (struct crop_mask *cps)
+ {
+ int i;
+
+ cps->crop_mode = CROP_NONE;
+ cps->res_unit = RESUNIT_NONE;
+ cps->edge_ref = EDGE_TOP;
+ cps->width = 0;
+ cps->length = 0;
+ for (i = 0; i < 4; i++)
+ cps->margins[i] = 0.0;
+ cps->bufftotal = (uint32)0;
+ cps->combined_width = (uint32)0;
+ cps->combined_length = (uint32)0;
+ cps->rotation = (uint16)0;
+ cps->photometric = INVERT_DATA_AND_TAG;
+ cps->mirror = (uint16)0;
+ cps->invert = (uint16)0;
+ cps->zones = (uint32)0;
+ cps->regions = (uint32)0;
+ for (i = 0; i < MAX_REGIONS; i++)
+ {
+ cps->corners[i].X1 = 0.0;
+ cps->corners[i].X2 = 0.0;
+ cps->corners[i].Y1 = 0.0;
+ cps->corners[i].Y2 = 0.0;
+ cps->regionlist[i].x1 = 0;
+ cps->regionlist[i].x2 = 0;
+ cps->regionlist[i].y1 = 0;
+ cps->regionlist[i].y2 = 0;
+ cps->regionlist[i].width = 0;
+ cps->regionlist[i].length = 0;
+ cps->regionlist[i].buffsize = 0;
+ cps->regionlist[i].buffptr = NULL;
+ cps->zonelist[i].position = 0;
+ cps->zonelist[i].total = 0;
+ }
+ cps->exp_mode = ONE_FILE_COMPOSITE;
+ cps->img_mode = COMPOSITE_IMAGES;
+ }
+
+static void initDumpOptions(struct dump_opts *dump)
+ {
+ dump->debug = 0;
+ dump->format = DUMP_NONE;
+ dump->level = 1;
+ sprintf (dump->mode, "w");
+ memset (dump->infilename, '\0', PATH_MAX + 1);
+ memset (dump->outfilename, '\0',PATH_MAX + 1);
+ dump->infile = NULL;
+ dump->outfile = NULL;
+ }
+
+/* Compute pixel offsets into the image for margins and fixed regions */
+static int
+computeInputPixelOffsets(struct crop_mask *crop, struct image_data *image,
+ struct offset *off)
+ {
+ double scale;
+ float xres, yres;
+ /* Values for these offsets are in pixels from start of image, not bytes,
+ * and are indexed from zero to width - 1 or length - 1 */
+ uint32 tmargin, bmargin, lmargin, rmargin;
+ uint32 startx, endx; /* offsets of first and last columns to extract */
+ uint32 starty, endy; /* offsets of first and last row to extract */
+ uint32 width, length, crop_width, crop_length;
+ uint32 i, max_width, max_length, zwidth, zlength, buffsize;
+ uint32 x1, x2, y1, y2;
+
+ if (image->res_unit != RESUNIT_INCH && image->res_unit != RESUNIT_CENTIMETER)
+ {
+ xres = 1.0;
+ yres = 1.0;
+ }
+ else
+ {
+ if (((image->xres == 0) || (image->yres == 0)) &&
+ (crop->res_unit != RESUNIT_NONE) &&
+ ((crop->crop_mode & CROP_REGIONS) || (crop->crop_mode & CROP_MARGINS) ||
+ (crop->crop_mode & CROP_LENGTH) || (crop->crop_mode & CROP_WIDTH)))
+ {
+ TIFFError("computeInputPixelOffsets", "Cannot compute margins or fixed size sections without image resolution");
+ TIFFError("computeInputPixelOffsets", "Specify units in pixels and try again");
+ return (-1);
+ }
+ xres = image->xres;
+ yres = image->yres;
+ }
+
+ /* Translate user units to image units */
+ scale = 1.0;
+ switch (crop->res_unit) {
+ case RESUNIT_CENTIMETER:
+ if (image->res_unit == RESUNIT_INCH)
+ scale = 1.0/2.54;
+ break;
+ case RESUNIT_INCH:
+ if (image->res_unit == RESUNIT_CENTIMETER)
+ scale = 2.54;
+ break;
+ case RESUNIT_NONE: /* Dimensions in pixels */
+ default:
+ break;
+ }
+
+ if (crop->crop_mode & CROP_REGIONS)
+ {
+ max_width = max_length = 0;
+ for (i = 0; i < crop->regions; i++)
+ {
+ if ((crop->res_unit == RESUNIT_INCH) || (crop->res_unit == RESUNIT_CENTIMETER))
+ {
+ x1 = (uint32) (crop->corners[i].X1 * scale * xres);
+ x2 = (uint32) (crop->corners[i].X2 * scale * xres);
+ y1 = (uint32) (crop->corners[i].Y1 * scale * yres);
+ y2 = (uint32) (crop->corners[i].Y2 * scale * yres);
+ }
+ else
+ {
+ x1 = (uint32) (crop->corners[i].X1);
+ x2 = (uint32) (crop->corners[i].X2);
+ y1 = (uint32) (crop->corners[i].Y1);
+ y2 = (uint32) (crop->corners[i].Y2);
+ }
+ if (x1 < 1)
+ crop->regionlist[i].x1 = 0;
+ else
+ crop->regionlist[i].x1 = (uint32) (x1 - 1);
+
+ if (x2 > image->width - 1)
+ crop->regionlist[i].x2 = image->width - 1;
+ else
+ crop->regionlist[i].x2 = (uint32) (x2 - 1);
+ zwidth = crop->regionlist[i].x2 - crop->regionlist[i].x1 + 1;
+
+ if (y1 < 1)
+ crop->regionlist[i].y1 = 0;
+ else
+ crop->regionlist[i].y1 = (uint32) (y1 - 1);
+
+ if (y2 > image->length - 1)
+ crop->regionlist[i].y2 = image->length - 1;
+ else
+ crop->regionlist[i].y2 = (uint32) (y2 - 1);
+
+ zlength = crop->regionlist[i].y2 - crop->regionlist[i].y1 + 1;
+
+ if (zwidth > max_width)
+ max_width = zwidth;
+ if (zlength > max_length)
+ max_length = zlength;
+
+ buffsize = (uint32)
+ (((zwidth * image->bps * image->spp + 7 ) / 8) * (zlength + 1));
+
+ crop->regionlist[i].buffsize = buffsize;
+ crop->bufftotal += buffsize;
+ if (crop->img_mode == COMPOSITE_IMAGES)
+ {
+ switch (crop->edge_ref)
+ {
+ case EDGE_LEFT:
+ case EDGE_RIGHT:
+ crop->combined_length = zlength;
+ crop->combined_width += zwidth;
+ break;
+ case EDGE_BOTTOM:
+ case EDGE_TOP: /* width from left, length from top */
+ default:
+ crop->combined_width = zwidth;
+ crop->combined_length += zlength;
+ break;
+ }
+ }
+ }
+ return (0);
+ }
+
+ /* Convert crop margins into offsets into image
+ * Margins are expressed as pixel rows and columns, not bytes
+ */
+ if (crop->crop_mode & CROP_MARGINS)
+ {
+ if (crop->res_unit != RESUNIT_INCH && crop->res_unit != RESUNIT_CENTIMETER)
+ { /* User has specified pixels as reference unit */
+ tmargin = (uint32)(crop->margins[0]);
+ lmargin = (uint32)(crop->margins[1]);
+ bmargin = (uint32)(crop->margins[2]);
+ rmargin = (uint32)(crop->margins[3]);
+ }
+ else
+ { /* inches or centimeters specified */
+ tmargin = (uint32)(crop->margins[0] * scale * yres);
+ lmargin = (uint32)(crop->margins[1] * scale * xres);
+ bmargin = (uint32)(crop->margins[2] * scale * yres);
+ rmargin = (uint32)(crop->margins[3] * scale * xres);
+ }
+
+ if ((lmargin + rmargin) > image->width)
+ {
+ TIFFError("computeInputPixelOffsets", "Combined left and right margins exceed image width");
+ lmargin = (uint32) 0;
+ rmargin = (uint32) 0;
+ return (-1);
+ }
+ if ((tmargin + bmargin) > image->length)
+ {
+ TIFFError("computeInputPixelOffsets", "Combined top and bottom margins exceed image length");
+ tmargin = (uint32) 0;
+ bmargin = (uint32) 0;
+ return (-1);
+ }
+ }
+ else
+ { /* no margins requested */
+ tmargin = (uint32) 0;
+ lmargin = (uint32) 0;
+ bmargin = (uint32) 0;
+ rmargin = (uint32) 0;
+ }
+
+ /* Width, height, and margins are expressed as pixel offsets into image */
+ if (crop->res_unit != RESUNIT_INCH && crop->res_unit != RESUNIT_CENTIMETER)
+ {
+ if (crop->crop_mode & CROP_WIDTH)
+ width = (uint32)crop->width;
+ else
+ width = image->width - lmargin - rmargin;
+
+ if (crop->crop_mode & CROP_LENGTH)
+ length = (uint32)crop->length;
+ else
+ length = image->length - tmargin - bmargin;
+ }
+ else
+ {
+ if (crop->crop_mode & CROP_WIDTH)
+ width = (uint32)(crop->width * scale * image->xres);
+ else
+ width = image->width - lmargin - rmargin;
+
+ if (crop->crop_mode & CROP_LENGTH)
+ length = (uint32)(crop->length * scale * image->yres);
+ else
+ length = image->length - tmargin - bmargin;
+ }
+
+ off->tmargin = tmargin;
+ off->bmargin = bmargin;
+ off->lmargin = lmargin;
+ off->rmargin = rmargin;
+
+ /* Calculate regions defined by margins, width, and length.
+ * Coordinates expressed as 0 to imagewidth - 1, imagelength - 1,
+ * since they are used to compute offsets into buffers */
+ switch (crop->edge_ref) {
+ case EDGE_BOTTOM:
+ startx = lmargin;
+ if ((startx + width) >= (image->width - rmargin))
+ endx = image->width - rmargin - 1;
+ else
+ endx = startx + width - 1;
+
+ endy = image->length - bmargin - 1;
+ if ((endy - length) <= tmargin)
+ starty = tmargin;
+ else
+ starty = endy - length + 1;
+ break;
+ case EDGE_RIGHT:
+ endx = image->width - rmargin - 1;
+ if ((endx - width) <= lmargin)
+ startx = lmargin;
+ else
+ startx = endx - width + 1;
+
+ starty = tmargin;
+ if ((starty + length) >= (image->length - bmargin))
+ endy = image->length - bmargin - 1;
+ else
+ endy = starty + length - 1;
+ break;
+ case EDGE_TOP: /* width from left, length from top */
+ case EDGE_LEFT:
+ default:
+ startx = lmargin;
+ if ((startx + width) >= (image->width - rmargin))
+ endx = image->width - rmargin - 1;
+ else
+ endx = startx + width - 1;
+
+ starty = tmargin;
+ if ((starty + length) >= (image->length - bmargin))
+ endy = image->length - bmargin - 1;
+ else
+ endy = starty + length - 1;
+ break;
+ }
+ off->startx = startx;
+ off->starty = starty;
+ off->endx = endx;
+ off->endy = endy;
+
+ crop_width = endx - startx + 1;
+ crop_length = endy - starty + 1;
+
+ if (crop_width <= 0)
+ {
+ TIFFError("computeInputPixelOffsets",
+ "Invalid left/right margins and /or image crop width requested");
+ return (-1);
+ }
+ if (crop_width > image->width)
+ crop_width = image->width;
+
+ if (crop_length <= 0)
+ {
+ TIFFError("computeInputPixelOffsets",
+ "Invalid top/bottom margins and /or image crop length requested");
+ return (-1);
+ }
+ if (crop_length > image->length)
+ crop_length = image->length;
+
+ off->crop_width = crop_width;
+ off->crop_length = crop_length;
+
+ return (0);
+ } /* end computeInputPixelOffsets */
+
+/*
+ * Translate crop options into pixel offsets for one or more regions of the image.
+ * Options are applied in this order: margins, specific width and length, zones,
+ * but all are optional. Margins are relative to each edge. Width, length and
+ * zones are relative to the specified reference edge. Zones are expressed as
+ * X:Y where X is the ordinal value in a set of Y equal sized portions. eg.
+ * 2:3 would indicate the middle third of the region qualified by margins and
+ * any explicit width and length specified. Regions are specified by coordinates
+ * of the top left and lower right corners with range 1 to width or height.
+ */
+
+static int
+getCropOffsets(struct image_data *image, struct crop_mask *crop, struct dump_opts *dump)
+ {
+ struct offset offsets;
+ int i;
+ int32 test2;
+ uint32 test, seg, total, need_buff = 0;
+ uint32 buffsize;
+ uint32 zwidth, zlength;
+
+ memset(&offsets, '\0', sizeof(struct offset));
+ crop->bufftotal = 0;
+ crop->combined_width = (uint32)0;
+ crop->combined_length = (uint32)0;
+ crop->selections = 0;
+
+ /* Compute pixel offsets if margins or fixed width or length specified */
+ if ((crop->crop_mode & CROP_MARGINS) ||
+ (crop->crop_mode & CROP_REGIONS) ||
+ (crop->crop_mode & CROP_LENGTH) ||
+ (crop->crop_mode & CROP_WIDTH))
+ {
+ if (computeInputPixelOffsets(crop, image, &offsets))
+ {
+ TIFFError ("getCropOffsets", "Unable to compute crop margins");
+ return (-1);
+ }
+ need_buff = TRUE;
+ crop->selections = crop->regions;
+ /* Regions are only calculated from top and left edges with no margins */
+ if (crop->crop_mode & CROP_REGIONS)
+ return (0);
+ }
+ else
+ { /* cropped area is the full image */
+ offsets.tmargin = 0;
+ offsets.lmargin = 0;
+ offsets.bmargin = 0;
+ offsets.rmargin = 0;
+ offsets.crop_width = image->width;
+ offsets.crop_length = image->length;
+ offsets.startx = 0;
+ offsets.endx = image->width - 1;
+ offsets.starty = 0;
+ offsets.endy = image->length - 1;
+ need_buff = FALSE;
+ }
+
+ if (dump->outfile != NULL)
+ {
+ dump_info (dump->outfile, dump->format, "", "Margins: Top: %d Left: %d Bottom: %d Right: %d",
+ offsets.tmargin, offsets.lmargin, offsets.bmargin, offsets.rmargin);
+ dump_info (dump->outfile, dump->format, "", "Crop region within margins: Adjusted Width: %6d Length: %6d",
+ offsets.crop_width, offsets.crop_length);
+ }
+
+ if (!(crop->crop_mode & CROP_ZONES)) /* no crop zones requested */
+ {
+ if (need_buff == FALSE) /* No margins or fixed width or length areas */
+ {
+ crop->selections = 0;
+ crop->combined_width = image->width;
+ crop->combined_length = image->length;
+ return (0);
+ }
+ else
+ {
+ /* Use one region for margins and fixed width or length areas
+ * even though it was not formally declared as a region.
+ */
+ crop->selections = 1;
+ crop->zones = 1;
+ crop->zonelist[0].total = 1;
+ crop->zonelist[0].position = 1;
+ }
+ }
+ else
+ crop->selections = crop->zones;
+
+ for (i = 0; i < crop->zones; i++)
+ {
+ seg = crop->zonelist[i].position;
+ total = crop->zonelist[i].total;
+
+ switch (crop->edge_ref)
+ {
+ case EDGE_LEFT: /* zones from left to right, length from top */
+ zlength = offsets.crop_length;
+ crop->regionlist[i].y1 = offsets.starty;
+ crop->regionlist[i].y2 = offsets.endy;
+
+ crop->regionlist[i].x1 = offsets.startx +
+ (uint32)(offsets.crop_width * 1.0 * (seg - 1) / total);
+ test = offsets.startx +
+ (uint32)(offsets.crop_width * 1.0 * seg / total);
+ if (test > image->width - 1)
+ crop->regionlist[i].x2 = image->width - 1;
+ else
+ crop->regionlist[i].x2 = test - 1;
+ zwidth = crop->regionlist[i].x2 - crop->regionlist[i].x1 + 1;
+
+ /* This is passed to extractCropZone or extractCompositeZones */
+ crop->combined_length = (uint32)zlength;
+ if (crop->exp_mode == COMPOSITE_IMAGES)
+ crop->combined_width += (uint32)zwidth;
+ else
+ crop->combined_width = (uint32)zwidth;
+ break;
+ case EDGE_BOTTOM: /* width from left, zones from bottom to top */
+ zwidth = offsets.crop_width;
+ crop->regionlist[i].x1 = offsets.startx;
+ crop->regionlist[i].x2 = offsets.endx;
+
+ test2 = offsets.endy - (uint32)(offsets.crop_length * 1.0 * seg / total);
+ if (test2 < 1 )
+ crop->regionlist[i].y1 = 0;
+ else
+ crop->regionlist[i].y1 = test2 + 1;
+
+ test = offsets.endy - (uint32)(offsets.crop_length * 1.0 * (seg - 1) / total);
+ if (test > (image->length - 1))
+ crop->regionlist[i].y2 = image->length - 1;
+ else
+ crop->regionlist[i].y2 = test;
+ zlength = crop->regionlist[i].y2 - crop->regionlist[i].y1 + 1;
+
+ /* This is passed to extractCropZone or extractCompositeZones */
+ if (crop->exp_mode == COMPOSITE_IMAGES)
+ crop->combined_length += (uint32)zlength;
+ else
+ crop->combined_length = (uint32)zlength;
+ crop->combined_width = (uint32)zwidth;
+ break;
+ case EDGE_RIGHT: /* zones from right to left, length from top */
+ zlength = offsets.crop_length;
+ crop->regionlist[i].y1 = offsets.starty;
+ crop->regionlist[i].y2 = offsets.endy;
+
+ crop->regionlist[i].x1 = offsets.startx +
+ (uint32)(offsets.crop_width * (total - seg) * 1.0 / total);
+ test = offsets.startx +
+ (uint32)(offsets.crop_width * (total - seg + 1) * 1.0 / total);
+
+ if (test > image->width - 1)
+ crop->regionlist[i].x2 = image->width - 1;
+ else
+ crop->regionlist[i].x2 = test - 1;
+ zwidth = crop->regionlist[i].x2 - crop->regionlist[i].x1 + 1;
+
+ /* This is passed to extractCropZone or extractCompositeZones */
+ crop->combined_length = (uint32)zlength;
+ if (crop->exp_mode == COMPOSITE_IMAGES)
+ crop->combined_width += (uint32)zwidth;
+ else
+ crop->combined_width = (uint32)zwidth;
+ break;
+ case EDGE_TOP: /* width from left, zones from top to bottom */
+ default:
+ zwidth = offsets.crop_width;
+ crop->regionlist[i].x1 = offsets.startx;
+ crop->regionlist[i].x2 = offsets.endx;
+
+ crop->regionlist[i].y1 = offsets.starty + (uint32)(offsets.crop_length * 1.0 * (seg - 1) / total);
+ test = offsets.starty + (uint32)(offsets.crop_length * 1.0 * seg / total);
+ if (test > image->length - 1)
+ crop->regionlist[i].y2 = image->length - 1;
+ else
+ crop->regionlist[i].y2 = test - 1;
+ zlength = crop->regionlist[i].y2 - crop->regionlist[i].y1 + 1;
+
+ /* This is passed to extractCropZone or extractCompositeZones */
+ if (crop->exp_mode == COMPOSITE_IMAGES)
+ crop->combined_length += (uint32)zlength;
+ else
+ crop->combined_length = (uint32)zlength;
+ crop->combined_width = (uint32)zwidth;
+ break;
+ } /* end switch statement */
+
+ buffsize = (uint32)
+ ((((zwidth * image->bps * image->spp) + 7 ) / 8) * (zlength + 1));
+ crop->regionlist[i].width = (uint32) zwidth;
+ crop->regionlist[i].length = (uint32) zlength;
+ crop->regionlist[i].buffsize = buffsize;
+ crop->bufftotal += buffsize;
+
+
+ if (dump->outfile != NULL)
+ dump_info (dump->outfile, dump->format, "", "Zone %d, width: %4d, length: %4d, x1: %4d x2: %4d y1: %4d y2: %4d",
+ i + 1, (uint32)zwidth, (uint32)zlength,
+ crop->regionlist[i].x1, crop->regionlist[i].x2,
+ crop->regionlist[i].y1, crop->regionlist[i].y2);
+ }
+
+ return (0);
+ } /* end getCropOffsets */
+
+
+static int
+computeOutputPixelOffsets (struct crop_mask *crop, struct image_data *image,
+ struct pagedef *page, struct pageseg *sections,
+ struct dump_opts* dump)
+ {
+ double scale;
+ double pwidth, plength; /* Output page width and length in user units*/
+ uint32 iwidth, ilength; /* Input image width and length in pixels*/
+ uint32 owidth, olength; /* Output image width and length in pixels*/
+ uint32 orows, ocols; /* rows and cols for output */
+ uint32 hmargin, vmargin; /* Horizontal and vertical margins */
+ uint32 x1, x2, y1, y2, line_bytes;
+ unsigned int orientation;
+ uint32 i, j, k;
+
+ scale = 1.0;
+ if (page->res_unit == RESUNIT_NONE)
+ page->res_unit = image->res_unit;
+
+ switch (image->res_unit) {
+ case RESUNIT_CENTIMETER:
+ if (page->res_unit == RESUNIT_INCH)
+ scale = 1.0/2.54;
+ break;
+ case RESUNIT_INCH:
+ if (page->res_unit == RESUNIT_CENTIMETER)
+ scale = 2.54;
+ break;
+ case RESUNIT_NONE: /* Dimensions in pixels */
+ default:
+ break;
+ }
+
+ /* get width, height, resolutions of input image selection */
+ if (crop->combined_width > 0)
+ iwidth = crop->combined_width;
+ else
+ iwidth = image->width;
+ if (crop->combined_length > 0)
+ ilength = crop->combined_length;
+ else
+ ilength = image->length;
+
+ if (page->hres <= 1.0)
+ page->hres = image->xres;
+ if (page->vres <= 1.0)
+ page->vres = image->yres;
+
+ if ((page->hres < 1.0) || (page->vres < 1.0))
+ {
+ TIFFError("computeOutputPixelOffsets",
+ "Invalid horizontal or vertical resolution specified or read from input image");
+ return (1);
+ }
+
+ /* If no page sizes are being specified, we just use the input image size to
+ * calculate maximum margins that can be taken from image.
+ */
+ if (page->width <= 0)
+ pwidth = iwidth;
+ else
+ pwidth = page->width;
+
+ if (page->length <= 0)
+ plength = ilength;
+ else
+ plength = page->length;
+
+ if (dump->debug)
+ {
+ TIFFError("", "Page size: %s, Vres: %3.2f, Hres: %3.2f, "
+ "Hmargin: %3.2f, Vmargin: %3.2f\n",
+ page->name, page->vres, page->hres,
+ page->hmargin, page->vmargin);
+ TIFFError("", "Res_unit: %d, Scale: %3.2f, Page width: %3.2f, length: %3.2f\n",
+ page->res_unit, scale, pwidth, plength);
+ }
+
+ /* compute margins at specified unit and resolution */
+ if (page->mode & PAGE_MODE_MARGINS)
+ {
+ if (page->res_unit == RESUNIT_INCH || page->res_unit == RESUNIT_CENTIMETER)
+ { /* inches or centimeters specified */
+ hmargin = (uint32)(page->hmargin * scale * page->hres * ((image->bps + 7)/ 8));
+ vmargin = (uint32)(page->vmargin * scale * page->vres * ((image->bps + 7)/ 8));
+ }
+ else
+ { /* Otherwise user has specified pixels as reference unit */
+ hmargin = (uint32)(page->hmargin * scale * ((image->bps + 7)/ 8));
+ vmargin = (uint32)(page->vmargin * scale * ((image->bps + 7)/ 8));
+ }
+
+ if ((hmargin * 2.0) > (pwidth * page->hres))
+ {
+ TIFFError("computeOutputPixelOffsets",
+ "Combined left and right margins exceed page width");
+ hmargin = (uint32) 0;
+ return (-1);
+ }
+ if ((vmargin * 2.0) > (plength * page->vres))
+ {
+ TIFFError("computeOutputPixelOffsets",
+ "Combined top and bottom margins exceed page length");
+ vmargin = (uint32) 0;
+ return (-1);
+ }
+ }
+ else
+ {
+ hmargin = 0;
+ vmargin = 0;
+ }
+
+ if (page->mode & PAGE_MODE_ROWSCOLS )
+ {
+ /* Maybe someday but not for now */
+ if (page->mode & PAGE_MODE_MARGINS)
+ TIFFError("computeOutputPixelOffsets",
+ "Output margins cannot be specified with rows and columns");
+
+ owidth = TIFFhowmany(iwidth, page->cols);
+ olength = TIFFhowmany(ilength, page->rows);
+ }
+ else
+ {
+ if (page->mode & PAGE_MODE_PAPERSIZE )
+ {
+ owidth = (uint32)((pwidth * page->hres) - (hmargin * 2));
+ olength = (uint32)((plength * page->vres) - (vmargin * 2));
+ }
+ else
+ {
+ owidth = (uint32)(iwidth - (hmargin * 2 * page->hres));
+ olength = (uint32)(ilength - (vmargin * 2 * page->vres));
+ }
+ }
+
+ if (owidth > iwidth)
+ owidth = iwidth;
+ if (olength > ilength)
+ olength = ilength;
+
+ /* Compute the number of pages required for Portrait or Landscape */
+ switch (page->orient)
+ {
+ case ORIENTATION_NONE:
+ case ORIENTATION_PORTRAIT:
+ ocols = TIFFhowmany(iwidth, owidth);
+ orows = TIFFhowmany(ilength, olength);
+ orientation = ORIENTATION_PORTRAIT;
+ break;
+
+ case ORIENTATION_LANDSCAPE:
+ ocols = TIFFhowmany(iwidth, olength);
+ orows = TIFFhowmany(ilength, owidth);
+ x1 = olength;
+ olength = owidth;
+ owidth = x1;
+ orientation = ORIENTATION_LANDSCAPE;
+ break;
+
+ case ORIENTATION_AUTO:
+ default:
+ x1 = TIFFhowmany(iwidth, owidth);
+ x2 = TIFFhowmany(ilength, olength);
+ y1 = TIFFhowmany(iwidth, olength);
+ y2 = TIFFhowmany(ilength, owidth);
+
+ if ( (x1 * x2) < (y1 * y2))
+ { /* Portrait */
+ ocols = x1;
+ orows = x2;
+ orientation = ORIENTATION_PORTRAIT;
+ }
+ else
+ { /* Landscape */
+ ocols = y1;
+ orows = y2;
+ x1 = olength;
+ olength = owidth;
+ owidth = x1;
+ orientation = ORIENTATION_LANDSCAPE;
+ }
+ }
+
+ if (ocols < 1)
+ ocols = 1;
+ if (orows < 1)
+ orows = 1;
+
+ /* If user did not specify rows and cols, set them from calcuation */
+ if (page->rows < 1)
+ page->rows = orows;
+ if (page->cols < 1)
+ page->cols = ocols;
+
+ line_bytes = TIFFhowmany8(owidth * image->bps) * image->spp;
+
+ if ((page->rows * page->cols) > MAX_SECTIONS)
+ {
+ TIFFError("computeOutputPixelOffsets",
+ "Rows and Columns exceed maximum sections\nIncrease resolution or reduce sections");
+ return (-1);
+ }
+
+ /* build the list of offsets for each output section */
+ for (k = 0, i = 0 && k <= MAX_SECTIONS; i < orows; i++)
+ {
+ y1 = (uint32)(olength * i);
+ y2 = (uint32)(olength * (i + 1) - 1);
+ if (y2 >= ilength)
+ y2 = ilength - 1;
+ for (j = 0; j < ocols; j++, k++)
+ {
+ x1 = (uint32)(owidth * j);
+ x2 = (uint32)(owidth * (j + 1) - 1);
+ if (x2 >= iwidth)
+ x2 = iwidth - 1;
+ sections[k].x1 = x1;
+ sections[k].x2 = x2;
+ sections[k].y1 = y1;
+ sections[k].y2 = y2;
+ sections[k].buffsize = line_bytes * olength;
+ sections[k].position = k + 1;
+ sections[k].total = orows * ocols;
+ }
+ }
+ return (0);
+ } /* end computeOutputPixelOffsets */
+
+static int
+loadImage(TIFF* in, struct image_data *image, struct dump_opts *dump, unsigned char **read_ptr)
+ {
+ uint32 i;
+ float xres = 0.0, yres = 0.0;
+ uint16 nstrips = 0, ntiles = 0, planar = 0;
+ uint16 bps = 0, spp = 0, res_unit = 0;
+ uint16 photometric = 0, orientation = 0, input_compression = 0;
+ uint32 width = 0, length = 0;
+ uint32 stsize = 0, tlsize = 0, buffsize = 0, scanlinesize = 0;
+ uint32 tw = 0, tl = 0; /* Tile width and length */
+ uint32 tile_rowsize = 0;
+ unsigned char *read_buff = NULL;
+ unsigned char *new_buff = NULL;
+ int readunit = 0;
+ static uint32 prev_readsize = 0;
+
+ TIFFGetFieldDefaulted(in, TIFFTAG_BITSPERSAMPLE, &bps);
+ TIFFGetFieldDefaulted(in, TIFFTAG_SAMPLESPERPIXEL, &spp);
+ TIFFGetFieldDefaulted(in, TIFFTAG_PLANARCONFIG, &planar);
+ TIFFGetFieldDefaulted(in, TIFFTAG_ORIENTATION, &orientation);
+ if (! TIFFGetFieldDefaulted(in, TIFFTAG_PHOTOMETRIC, &photometric))
+ TIFFError("loadImage","Image lacks Photometric interpreation tag");
+ if (! TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width))
+ TIFFError("loadimage","Image lacks image width tag");
+ if(! TIFFGetField(in, TIFFTAG_IMAGELENGTH, &length))
+ TIFFError("loadimage","Image lacks image length tag");
+ TIFFGetFieldDefaulted(in, TIFFTAG_XRESOLUTION, &xres);
+ TIFFGetFieldDefaulted(in, TIFFTAG_YRESOLUTION, &yres);
+ if (!TIFFGetFieldDefaulted(in, TIFFTAG_RESOLUTIONUNIT, &res_unit))
+ res_unit = RESUNIT_INCH;
+ if (!TIFFGetField(in, TIFFTAG_COMPRESSION, &input_compression))
+ input_compression = COMPRESSION_NONE;
+
+#ifdef DEBUG2
+ char compressionid[16];
+
+ switch (compression)
+ {
+ case COMPRESSION_NONE: /* 1 dump mode */
+ stcrcpy ("None/dump", compressionid);
+ break;
+ case COMPRESSION_CCITTRLE: /* 2 CCITT modified Huffman RLE */
+ stcrcpy ("Huffman RLE", compressionid);
+ break;
+ case COMPRESSION_CCITTFAX3: /* 3 CCITT Group 3 fax encoding */
+ case COMPRESSION_CCITT_T4: /* 3 CCITT T.4 (TIFF 6 name) */
+ stcrcpy ("Group3 Fax", compressionid);
+ break;
+ case COMPRESSION_CCITTFAX4: /* 4 CCITT Group 4 fax encoding */
+ case COMPRESSION_CCITT_T6: /* 4 CCITT T.6 (TIFF 6 name) */
+ stcrcpy ("Group4 Fax", compressionid);
+ break;
+ case COMPRESSION_LZW: /* 5 Lempel-Ziv & Welch */
+ stcrcpy ("LZW", compressionid);
+ break;
+ case COMPRESSION_OJPEG: /* 6 !6.0 JPEG */
+ stcrcpy ("Old Jpeg", compressionid);
+ break;
+ case COMPRESSION_JPEG: /* 7 %JPEG DCT compression */
+ stcrcpy ("New Jpeg", compressionid);
+ break;
+ case COMPRESSION_NEXT: /* 32766 NeXT 2-bit RLE */
+ stcrcpy ("Next RLE", compressionid);
+ break;
+ case COMPRESSION_CCITTRLEW: /* 32771 #1 w/ word alignment */
+ stcrcpy ("CITTRLEW", compressionid);
+ break;
+ case COMPRESSION_PACKBITS: /* 32773 Macintosh RLE */
+ stcrcpy ("Mac Packbits", compressionid);
+ break;
+ case COMPRESSION_THUNDERSCAN: /* 32809 ThunderScan RLE */
+ stcrcpy ("Thunderscan", compressionid);
+ break;
+ case COMPRESSION_IT8CTPAD: /* 32895 IT8 CT w/padding */
+ stcrcpy ("IT8 padded", compressionid);
+ break;
+ case COMPRESSION_IT8LW: /* 32896 IT8 Linework RLE */
+ stcrcpy ("IT8 RLE", compressionid);
+ break;
+ case COMPRESSION_IT8MP: /* 32897 IT8 Monochrome picture */
+ stcrcpy ("IT8 mono", compressionid);
+ break;
+ case COMPRESSION_IT8BL: /* 32898 IT8 Binary line art */
+ stcrcpy ("IT8 lineart", compressionid);
+ break;
+ case COMPRESSION_PIXARFILM: /* 32908 Pixar companded 10bit LZW */
+ stcrcpy ("Pixar 10 bit", compressionid);
+ break;
+ case COMPRESSION_PIXARLOG: /* 32909 Pixar companded 11bit ZIP */
+ stcrcpy ("Pixar 11bit", compressionid);
+ break;
+ case COMPRESSION_DEFLATE: /* 32946 Deflate compression */
+ stcrcpy ("Deflate", compressionid);
+ break;
+ case COMPRESSION_ADOBE_DEFLATE: /* 8 Deflate compression */
+ stcrcpy ("Adobe deflate", compressionid);
+ break;
+ default:
+ stcrcpy ("None/unknown", compressionid);
+ break;
+ }
+#endif
+ scanlinesize = TIFFScanlineSize(in);
+ image->bps = bps;
+ image->spp = spp;
+ image->planar = planar;
+ image->width = width;
+ image->length = length;
+ image->xres = xres;
+ image->yres = yres;
+ image->res_unit = res_unit;
+ image->photometric = photometric;
+
+#ifdef DEBUG2
+ char photmetricid[12];
+
+ switch (photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ strcpy (photometricid, "MinIsWhite");
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ strcpy (photometricid, "MinIsBlack");
+ break;
+ case PHOTOMETRIC_RGB:
+ strcpy (photometricid, "RGB");
+ break;
+ case PHOTOMETRIC_PALETTE:
+ strcpy (photometricid, "Palette");
+ break;
+ case PHOTOMETRIC_MASK:
+ strcpy (photometricid, "Mask");
+ break;
+ case PHOTOMETRIC_SEPARATED:
+ strcpy (photometricid, "Separated");
+ break;
+ case PHOTOMETRIC_YCBCR:
+ strcpy (photometricid, "YCBCR");
+ break;
+ case PHOTOMETRIC_CIELAB:
+ strcpy (photometricid, "CIELab");
+ break;
+ case PHOTOMETRIC_ICCLAB:
+ strcpy (photometricid, "ICCLab");
+ break;
+ case PHOTOMETRIC_ITULAB:
+ strcpy (photometricid, "ITULab");
+ break;
+ case PHOTOMETRIC_LOGL:
+ strcpy (photometricid, "LogL");
+ break;
+ case PHOTOMETRIC_LOGLUV:
+ strcpy (photometricid, "LOGLuv");
+ break;
+ default:
+ strcpy (photometricid, "Unknown");
+ break;
+ }
+ TIFFError("loadImage", "Input photometric interpretation %s", photometricid);
+#endif
+
+ image->orientation = orientation;
+ switch (orientation)
+ {
+ case 0:
+ case ORIENTATION_TOPLEFT:
+ image->adjustments = 0;
+ break;
+ case ORIENTATION_TOPRIGHT:
+ image->adjustments = MIRROR_HORIZ;
+ break;
+ case ORIENTATION_BOTRIGHT:
+ image->adjustments = ROTATECW_180;
+ break;
+ case ORIENTATION_BOTLEFT:
+ image->adjustments = MIRROR_VERT;
+ break;
+ case ORIENTATION_LEFTTOP:
+ image->adjustments = MIRROR_VERT | ROTATECW_90;
+ break;
+ case ORIENTATION_RIGHTTOP:
+ image->adjustments = ROTATECW_90;
+ break;
+ case ORIENTATION_RIGHTBOT:
+ image->adjustments = MIRROR_VERT | ROTATECW_270;
+ break;
+ case ORIENTATION_LEFTBOT:
+ image->adjustments = ROTATECW_270;
+ break;
+ default:
+ image->adjustments = 0;
+ image->orientation = ORIENTATION_TOPLEFT;
+ }
+
+ if ((bps == 0) || (spp == 0))
+ {
+ TIFFError("loadImage", "Invalid samples per pixel (%d) or bits per sample (%d)",
+ spp, bps);
+ return (-1);
+ }
+
+ if (TIFFIsTiled(in))
+ {
+ readunit = TILE;
+ tlsize = TIFFTileSize(in);
+ ntiles = TIFFNumberOfTiles(in);
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tl);
+
+ tile_rowsize = TIFFTileRowSize(in);
+ buffsize = tlsize * ntiles;
+
+ if (buffsize < (uint32)(ntiles * tl * tile_rowsize))
+ {
+ buffsize = ntiles * tl * tile_rowsize;
+#ifdef DEBUG2
+ TIFFError("loadImage",
+ "Tilesize %u is too small, using ntiles * tilelength * tilerowsize %lu",
+ tlsize, (unsigned long)buffsize);
+#endif
+ }
+
+ if (dump->infile != NULL)
+ dump_info (dump->infile, dump->format, "",
+ "Tilesize: %u, Number of Tiles: %u, Tile row size: %u",
+ tlsize, ntiles, tile_rowsize);
+ }
+ else
+ {
+ readunit = STRIP;
+ TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ stsize = TIFFStripSize(in);
+ nstrips = TIFFNumberOfStrips(in);
+ buffsize = stsize * nstrips;
+ if (buffsize < (uint32) (((length * width * spp * bps) + 7) / 8))
+ {
+ buffsize = ((length * width * spp * bps) + 7) / 8;
+#ifdef DEBUG2
+ TIFFError("loadImage",
+ "Stripsize %u is too small, using imagelength * width * spp * bps / 8 = %lu",
+ stsize, (unsigned long)buffsize);
+#endif
+ }
+
+ if (dump->infile != NULL)
+ dump_info (dump->infile, dump->format, "",
+ "Stripsize: %u, Number of Strips: %u, Rows per Strip: %u, Scanline size: %u",
+ stsize, nstrips, rowsperstrip, scanlinesize);
+ }
+
+ if (input_compression == COMPRESSION_JPEG)
+ {
+ jpegcolormode = JPEGCOLORMODE_RGB;
+ TIFFSetField(in, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ }
+
+ read_buff = *read_ptr;
+ if (!read_buff)
+ read_buff = (unsigned char *)_TIFFmalloc(buffsize);
+ else
+ {
+ if (prev_readsize < buffsize)
+ {
+ new_buff = _TIFFrealloc(read_buff, buffsize);
+ if (!new_buff)
+ {
+ free (read_buff);
+ read_buff = (unsigned char *)_TIFFmalloc(buffsize);
+ }
+ else
+ read_buff = new_buff;
+ }
+ }
+
+ if (!read_buff)
+ {
+ TIFFError("loadImage", "Unable to allocate/reallocate read buffer");
+ return (-1);
+ }
+
+ prev_readsize = buffsize;
+ *read_ptr = read_buff;
+
+ /* N.B. The read functions used copy separate plane data into a buffer as interleaved
+ * samples rather than separate planes so the same logic works to extract regions
+ * regardless of the way the data are organized in the input file.
+ */
+ switch (readunit) {
+ case STRIP:
+ if (planar == PLANARCONFIG_CONTIG)
+ {
+ if (!(readContigStripsIntoBuffer(in, read_buff)))
+ {
+ TIFFError("loadImage", "Unable to read contiguous strips into buffer");
+ return (-1);
+ }
+ }
+ else
+ {
+ if (!(readSeparateStripsIntoBuffer(in, read_buff, length, width, spp, dump)))
+ {
+ TIFFError("loadImage", "Unable to read separate strips into buffer");
+ return (-1);
+ }
+ }
+ break;
+
+ case TILE:
+ if (planar == PLANARCONFIG_CONTIG)
+ {
+ if (!(readContigTilesIntoBuffer(in, read_buff, length, width, tw, tl, spp, bps)))
+ {
+ TIFFError("loadImage", "Unable to read contiguous tiles into buffer");
+ return (-1);
+ }
+ }
+ else
+ {
+ if (!(readSeparateTilesIntoBuffer(in, read_buff, length, width, tw, tl, spp, bps)))
+ {
+ TIFFError("loadImage", "Unable to read separate tiles into buffer");
+ return (-1);
+ }
+ }
+ break;
+ default: TIFFError("loadImage", "Unsupported image file format");
+ return (-1);
+ break;
+ }
+ if ((dump->infile != NULL) && (dump->level == 2))
+ {
+ dump_info (dump->infile, dump->format, "loadImage",
+ "Image width %d, length %d, Raw image data, %4d bytes",
+ width, length, buffsize);
+ dump_info (dump->infile, dump->format, "",
+ "Bits per sample %d, Samples per pixel %d", bps, spp);
+
+ for (i = 0; i < length; i++)
+ dump_buffer(dump->infile, dump->format, 1, scanlinesize,
+ i, read_buff + (i * scanlinesize));
+ }
+ return (0);
+ } /* end loadImage */
+
+static int correct_orientation(struct image_data *image, unsigned char **work_buff_ptr)
+ {
+ uint16 mirror, rotation;
+ unsigned char *work_buff;
+
+ work_buff = *work_buff_ptr;
+ if ((image == NULL) || (work_buff == NULL))
+ {
+ TIFFError ("correct_orientatin", "Invalid image or buffer pointer");
+ return (-1);
+ }
+
+ if ((image->adjustments & MIRROR_HORIZ) || (image->adjustments & MIRROR_VERT))
+ {
+ mirror = (uint16)(image->adjustments & MIRROR_BOTH);
+ if (mirrorImage(image->spp, image->bps, mirror,
+ image->width, image->length, work_buff))
+ {
+ TIFFError ("correct_orientation", "Unable to mirror image");
+ return (-1);
+ }
+ }
+
+ if (image->adjustments & ROTATE_ANY)
+ {
+ if (image->adjustments & ROTATECW_90)
+ rotation = (uint16) 90;
+ else
+ if (image->adjustments & ROTATECW_180)
+ rotation = (uint16) 180;
+ else
+ if (image->adjustments & ROTATECW_270)
+ rotation = (uint16) 270;
+ else
+ {
+ TIFFError ("correct_orientation", "Invalid rotation value: %d",
+ image->adjustments & ROTATE_ANY);
+ return (-1);
+ }
+
+ if (rotateImage(rotation, image, &image->width, &image->length, work_buff_ptr))
+ {
+ TIFFError ("correct_orientation", "Unable to rotate image");
+ return (-1);
+ }
+ image->orientation = ORIENTATION_TOPLEFT;
+ }
+
+ return (0);
+ } /* end correct_orientation */
+
+
+/* Extract multiple zones from an image and combine into a single composite image */
+static int
+extractCompositeRegions(struct image_data *image, struct crop_mask *crop,
+ unsigned char *read_buff, unsigned char *crop_buff)
+ {
+ int shift_width, bytes_per_sample, bytes_per_pixel;
+ uint32 i, trailing_bits, prev_trailing_bits;
+ uint32 row, first_row, last_row, first_col, last_col;
+ uint32 src_rowsize, dst_rowsize, src_offset, dst_offset;
+ uint32 crop_width, crop_length, img_width, img_length;
+ uint32 prev_length, prev_width, composite_width;
+ uint16 bps, spp;
+ uint8 *src, *dst;
+ tsample_t count, sample = 0; /* Update to extract one or more samples */
+
+ img_width = image->width;
+ img_length = image->length;
+ bps = image->bps;
+ spp = image->spp;
+ count = spp;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if ((bps % 8) == 0)
+ shift_width = 0;
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+ src = read_buff;
+ dst = crop_buff;
+
+ /* These are setup for adding additional sections */
+ prev_width = prev_length = 0;
+ prev_trailing_bits = trailing_bits = 0;
+ composite_width = crop->combined_width;
+ crop->combined_width = 0;
+ crop->combined_length = 0;
+
+ for (i = 0; i < crop->selections; i++)
+ {
+ /* rows, columns, width, length are expressed in pixels */
+ first_row = crop->regionlist[i].y1;
+ last_row = crop->regionlist[i].y2;
+ first_col = crop->regionlist[i].x1;
+ last_col = crop->regionlist[i].x2;
+
+ crop_width = last_col - first_col + 1;
+ crop_length = last_row - first_row + 1;
+
+ /* These should not be needed for composite images */
+ crop->regionlist[i].width = crop_width;
+ crop->regionlist[i].length = crop_length;
+ crop->regionlist[i].buffptr = crop_buff;
+
+ src_rowsize = ((img_width * bps * spp) + 7) / 8;
+ dst_rowsize = (((crop_width * bps * count) + 7) / 8);
+
+ switch (crop->edge_ref)
+ {
+ default:
+ case EDGE_TOP:
+ case EDGE_BOTTOM:
+ if ((i > 0) && (crop_width != crop->regionlist[i - 1].width))
+ {
+ TIFFError ("extractCompositeRegions",
+ "Only equal width regions can be combined for -E top or bottom");
+ return (1);
+ }
+
+ crop->combined_width = crop_width;
+ crop->combined_length += crop_length;
+
+ for (row = first_row; row <= last_row; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = (row - first_row) * dst_rowsize;
+ src = read_buff + src_offset;
+ dst = crop_buff + dst_offset + (prev_length * dst_rowsize);
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, img_width, sample,
+ spp, bps, count, first_col,
+ last_col + 1))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamplesShifted8bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ }
+ else
+ if (extractContigSamplesShifted16bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 2: if (extractContigSamplesShifted24bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamplesShifted32bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ default: TIFFError("extractCompositeRegions", "Unsupported bit depth %d", bps);
+ return (1);
+ }
+ }
+ prev_length += crop_length;
+ break;
+ case EDGE_LEFT: /* splice the pieces of each row together, side by side */
+ case EDGE_RIGHT:
+ if ((i > 0) && (crop_length != crop->regionlist[i - 1].length))
+ {
+ TIFFError ("extractCompositeRegions",
+ "Only equal length regions can be combined for -E left or right");
+ return (1);
+ }
+ crop->combined_width += crop_width;
+ crop->combined_length = crop_length;
+ dst_rowsize = (((composite_width * bps * count) + 7) / 8);
+ trailing_bits = (crop_width * bps * count) % 8;
+ for (row = first_row; row <= last_row; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = (row - first_row) * dst_rowsize;
+ src = read_buff + src_offset;
+ dst = crop_buff + dst_offset + prev_width;
+
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamplesShifted8bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ }
+ else
+ if (extractContigSamplesShifted16bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 2: if (extractContigSamplesShifted24bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamplesShifted32bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractCompositeRegions",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ default: TIFFError("extractCompositeRegions", "Unsupported bit depth %d", bps);
+ return (1);
+ }
+ }
+ prev_width += (crop_width * bps * count) / 8;
+ prev_trailing_bits += trailing_bits;
+ if (prev_trailing_bits > 7)
+ prev_trailing_bits-= 8;
+ break;
+ }
+ }
+ if (crop->combined_width != composite_width)
+ TIFFError("combineSeparateRegions","Combined width does not match composite width");
+
+ return (0);
+ } /* end extractCompositeRegions */
+
+/* Copy a single region of input buffer to an output buffer.
+ * The read functions used copy separate plane data into a buffer
+ * as interleaved samples rather than separate planes so the same
+ * logic works to extract regions regardless of the way the data
+ * are organized in the input file. This function can be used to
+ * extract one or more samples from the input image by updating the
+ * parameters for starting sample and number of samples to copy in the
+ * fifth and eighth arguments of the call to extractContigSamples.
+ * They would be passed as new elements of the crop_mask struct.
+ */
+
+static int
+extractSeparateRegion(struct image_data *image, struct crop_mask *crop,
+ unsigned char *read_buff, unsigned char *crop_buff,
+ int region)
+ {
+ int shift_width, prev_trailing_bits = 0;
+ uint32 bytes_per_sample, bytes_per_pixel;
+ uint32 src_rowsize, dst_rowsize;
+ uint32 row, first_row, last_row, first_col, last_col;
+ uint32 src_offset, dst_offset;
+ uint32 crop_width, crop_length, img_width, img_length;
+ uint16 bps, spp;
+ uint8 *src, *dst;
+ tsample_t count, sample = 0; /* Update to extract more or more samples */
+
+ img_width = image->width;
+ img_length = image->length;
+ bps = image->bps;
+ spp = image->spp;
+ count = spp;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if ((bps % 8) == 0)
+ shift_width = 0; /* Byte aligned data only */
+ else
+ {
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+ }
+
+ /* rows, columns, width, length are expressed in pixels */
+ first_row = crop->regionlist[region].y1;
+ last_row = crop->regionlist[region].y2;
+ first_col = crop->regionlist[region].x1;
+ last_col = crop->regionlist[region].x2;
+
+ crop_width = last_col - first_col + 1;
+ crop_length = last_row - first_row + 1;
+
+ crop->regionlist[region].width = crop_width;
+ crop->regionlist[region].length = crop_length;
+ crop->regionlist[region].buffptr = crop_buff;
+
+ src = read_buff;
+ dst = crop_buff;
+ src_rowsize = ((img_width * bps * spp) + 7) / 8;
+ dst_rowsize = (((crop_width * bps * spp) + 7) / 8);
+
+ for (row = first_row; row <= last_row; row++)
+ {
+ src_offset = row * src_rowsize;
+ dst_offset = (row - first_row) * dst_rowsize;
+ src = read_buff + src_offset;
+ dst = crop_buff + dst_offset;
+
+ switch (shift_width)
+ {
+ case 0: if (extractContigSamplesBytes (src, dst, img_width, sample,
+ spp, bps, count, first_col,
+ last_col + 1))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 1: if (bps == 1)
+ {
+ if (extractContigSamplesShifted8bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ }
+ else
+ if (extractContigSamplesShifted16bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 2: if (extractContigSamplesShifted24bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (extractContigSamplesShifted32bits (src, dst, img_width,
+ sample, spp, bps, count,
+ first_col, last_col + 1,
+ prev_trailing_bits))
+ {
+ TIFFError("extractSeparateRegion",
+ "Unable to extract row %d", row);
+ return (1);
+ }
+ break;
+ default: TIFFError("extractSeparateRegion", "Unsupported bit depth %d", bps);
+ return (1);
+ }
+ }
+
+ return (0);
+ } /* end extractSeparateRegion */
+
+static int
+extractImageSection(struct image_data *image, struct pageseg *section,
+ unsigned char *src_buff, unsigned char *sect_buff)
+ {
+ unsigned char bytebuff1, bytebuff2;
+ unsigned char *src, *dst;
+
+ uint32 img_width, img_length, img_rowsize;
+ uint32 j, shift1, shift2, trailing_bits;
+ uint32 row, first_row, last_row, first_col, last_col;
+ uint32 src_offset, dst_offset, row_offset, col_offset;
+ uint32 offset1, offset2, full_bytes;
+ uint32 sect_width, sect_length;
+ uint16 bps, spp;
+
+#ifdef DEVELMODE
+ int k;
+ unsigned char bitset;
+ static char *bitarray = NULL;
+#endif
+
+ img_width = image->width;
+ img_length = image->length;
+ bps = image->bps;
+ spp = image->spp;
+
+ src = src_buff;
+ dst = sect_buff;
+ src_offset = 0;
+ dst_offset = 0;
+
+#ifdef DEVELMODE
+ if (bitarray == NULL)
+ {
+ if ((bitarray = (char *)malloc(img_width)) == NULL)
+ {
+ TIFFError ("", "DEBUG: Unable to allocate debugging bitarray\n");
+ return (-1);
+ }
+ }
+#endif
+
+ /* rows, columns, width, length are expressed in pixels */
+ first_row = section->y1;
+ last_row = section->y2;
+ first_col = section->x1;
+ last_col = section->x2;
+
+ sect_width = last_col - first_col + 1;
+ sect_length = last_row - first_row + 1;
+ img_rowsize = ((img_width * bps + 7) / 8) * spp;
+ full_bytes = (sect_width * spp * bps) / 8; /* number of COMPLETE bytes per row in section */
+ trailing_bits = (sect_width * bps) % 8;
+
+#ifdef DEVELMODE
+ TIFFError ("", "First row: %d, last row: %d, First col: %d, last col: %d\n",
+ first_row, last_row, first_col, last_col);
+ TIFFError ("", "Image width: %d, Image length: %d, bps: %d, spp: %d\n",
+ img_width, img_length, bps, spp);
+ TIFFError ("", "Sect width: %d, Sect length: %d, full bytes: %d trailing bits %d\n",
+ sect_width, sect_length, full_bytes, trailing_bits);
+#endif
+
+ if ((bps % 8) == 0)
+ {
+ col_offset = first_col * spp * bps / 8;
+ for (row = first_row; row <= last_row; row++)
+ {
+ /* row_offset = row * img_width * spp * bps / 8; */
+ row_offset = row * img_rowsize;
+ src_offset = row_offset + col_offset;
+
+#ifdef DEVELMODE
+ TIFFError ("", "Src offset: %8d, Dst offset: %8d\n", src_offset, dst_offset);
+#endif
+ _TIFFmemcpy (sect_buff + dst_offset, src_buff + src_offset, full_bytes);
+ dst_offset += full_bytes;
+ }
+ }
+ else
+ { /* bps != 8 */
+ shift1 = spp * ((first_col * bps) % 8);
+ shift2 = spp * ((last_col * bps) % 8);
+ for (row = first_row; row <= last_row; row++)
+ {
+ /* pull out the first byte */
+ row_offset = row * img_rowsize;
+ offset1 = row_offset + (first_col * bps / 8);
+ offset2 = row_offset + (last_col * bps / 8);
+
+#ifdef DEVELMODE
+ for (j = 0, k = 7; j < 8; j++, k--)
+ {
+ bitset = *(src_buff + offset1) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ sprintf(&bitarray[8], " ");
+ sprintf(&bitarray[9], " ");
+ for (j = 10, k = 7; j < 18; j++, k--)
+ {
+ bitset = *(src_buff + offset2) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[18] = '\0';
+ TIFFError ("", "Row: %3d Offset1: %d, Shift1: %d, Offset2: %d, Shift2: %d\n",
+ row, offset1, shift1, offset2, shift2);
+#endif
+
+ bytebuff1 = bytebuff2 = 0;
+ if (shift1 == 0) /* the region is byte and sample alligned */
+ {
+ _TIFFmemcpy (sect_buff + dst_offset, src_buff + offset1, full_bytes);
+
+#ifdef DEVELMODE
+ TIFFError ("", " Alligned data src offset1: %8d, Dst offset: %8d\n", offset1, dst_offset);
+ sprintf(&bitarray[18], "\n");
+ sprintf(&bitarray[19], "\t");
+ for (j = 20, k = 7; j < 28; j++, k--)
+ {
+ bitset = *(sect_buff + dst_offset) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[28] = ' ';
+ bitarray[29] = ' ';
+#endif
+ dst_offset += full_bytes;
+
+ if (trailing_bits != 0)
+ {
+ bytebuff2 = src_buff[offset2] & ((unsigned char)255 << (7 - shift2));
+ sect_buff[dst_offset] = bytebuff2;
+#ifdef DEVELMODE
+ TIFFError ("", " Trailing bits src offset: %8d, Dst offset: %8d\n",
+ offset2, dst_offset);
+ for (j = 30, k = 7; j < 38; j++, k--)
+ {
+ bitset = *(sect_buff + dst_offset) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[38] = '\0';
+ TIFFError ("", "\tFirst and last bytes before and after masking:\n\t%s\n\n", bitarray);
+#endif
+ dst_offset++;
+ }
+ }
+ else /* each destination byte will have to be built from two source bytes*/
+ {
+#ifdef DEVELMODE
+ TIFFError ("", " Unalligned data src offset: %8d, Dst offset: %8d\n", offset1 , dst_offset);
+#endif
+ for (j = 0; j <= full_bytes; j++)
+ {
+ bytebuff1 = src_buff[offset1 + j] & ((unsigned char)255 >> shift1);
+ bytebuff2 = src_buff[offset1 + j + 1] & ((unsigned char)255 << (7 - shift1));
+ sect_buff[dst_offset + j] = (bytebuff1 << shift1) | (bytebuff2 >> (8 - shift1));
+ }
+#ifdef DEVELMODE
+ sprintf(&bitarray[18], "\n");
+ sprintf(&bitarray[19], "\t");
+ for (j = 20, k = 7; j < 28; j++, k--)
+ {
+ bitset = *(sect_buff + dst_offset) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[28] = ' ';
+ bitarray[29] = ' ';
+#endif
+ dst_offset += full_bytes;
+
+ if (trailing_bits != 0)
+ {
+#ifdef DEVELMODE
+ TIFFError ("", " Trailing bits src offset: %8d, Dst offset: %8d\n", offset1 + full_bytes, dst_offset);
+#endif
+ if (shift2 > shift1)
+ {
+ bytebuff1 = src_buff[offset1 + full_bytes] & ((unsigned char)255 << (7 - shift2));
+ bytebuff2 = bytebuff1 & ((unsigned char)255 << shift1);
+ sect_buff[dst_offset] = bytebuff2;
+#ifdef DEVELMODE
+ TIFFError ("", " Shift2 > Shift1\n");
+#endif
+ }
+ else
+ {
+ if (shift2 < shift1)
+ {
+ bytebuff2 = ((unsigned char)255 << (shift1 - shift2 - 1));
+ sect_buff[dst_offset] &= bytebuff2;
+#ifdef DEVELMODE
+ TIFFError ("", " Shift2 < Shift1\n");
+#endif
+ }
+#ifdef DEVELMODE
+ else
+ TIFFError ("", " Shift2 == Shift1\n");
+#endif
+ }
+ }
+#ifdef DEVELMODE
+ sprintf(&bitarray[28], " ");
+ sprintf(&bitarray[29], " ");
+ for (j = 30, k = 7; j < 38; j++, k--)
+ {
+ bitset = *(sect_buff + dst_offset) & (((unsigned char)1 << k)) ? 1 : 0;
+ sprintf(&bitarray[j], (bitset) ? "1" : "0");
+ }
+ bitarray[38] = '\0';
+ TIFFError ("", "\tFirst and last bytes before and after masking:\n\t%s\n\n", bitarray);
+#endif
+ dst_offset++;
+ }
+ }
+ }
+
+ return (0);
+ } /* end extractImageSection */
+
+static int
+writeSelections(TIFF *in, TIFF **out, struct crop_mask *crop,
+ struct image_data *image, struct dump_opts *dump,
+ struct buffinfo seg_buffs[], char *mp, char *filename,
+ unsigned int *page, unsigned int total_pages)
+ {
+ int i, page_count;
+ int autoindex = 0;
+ unsigned char *crop_buff = NULL;
+
+ /* Where we open a new file depends on the export mode */
+ switch (crop->exp_mode)
+ {
+ case ONE_FILE_COMPOSITE: /* Regions combined into single image */
+ autoindex = 0;
+ crop_buff = seg_buffs[0].buffer;
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+ page_count = total_pages;
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->combined_width,
+ crop->combined_length,
+ crop_buff, *page, total_pages))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ break;
+ case ONE_FILE_SEPARATED: /* Regions as separated images */
+ autoindex = 0;
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+ page_count = crop->selections * total_pages;
+ for (i = 0; i < crop->selections; i++)
+ {
+ crop_buff = seg_buffs[i].buffer;
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->regionlist[i].width,
+ crop->regionlist[i].length,
+ crop_buff, *page, page_count))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ }
+ break;
+ case FILE_PER_IMAGE_COMPOSITE: /* Regions as composite image */
+ autoindex = 1;
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+
+ crop_buff = seg_buffs[0].buffer;
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->combined_width,
+ crop->combined_length,
+ crop_buff, *page, total_pages))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ break;
+ case FILE_PER_IMAGE_SEPARATED: /* Regions as separated images */
+ autoindex = 1;
+ page_count = crop->selections;
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+
+ for (i = 0; i < crop->selections; i++)
+ {
+ crop_buff = seg_buffs[i].buffer;
+ /* Write the current region to the current file */
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->regionlist[i].width,
+ crop->regionlist[i].length,
+ crop_buff, *page, page_count))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ }
+ break;
+ case FILE_PER_SELECTION:
+ autoindex = 1;
+ page_count = 1;
+ for (i = 0; i < crop->selections; i++)
+ {
+ if (update_output_file (out, mp, autoindex, filename, page))
+ return (1);
+
+ crop_buff = seg_buffs[i].buffer;
+ /* Write the current region to the current file */
+ if (writeCroppedImage(in, *out, image, dump,
+ crop->regionlist[i].width,
+ crop->regionlist[i].length,
+ crop_buff, *page, page_count))
+ {
+ TIFFError("writeRegions", "Unable to write new image");
+ return (-1);
+ }
+ }
+ break;
+ default: return (1);
+ }
+
+ return (0);
+ } /* end writeRegions */
+
+static int
+writeImageSections(TIFF *in, TIFF *out, struct image_data *image,
+ struct pagedef *page, struct pageseg *sections,
+ struct dump_opts * dump, unsigned char *src_buff,
+ unsigned char **sect_buff_ptr)
+ {
+ double hres, vres;
+ uint32 i, k, width, length, sectsize;
+ unsigned char *sect_buff = *sect_buff_ptr;
+
+ hres = page->hres;
+ vres = page->vres;
+
+ k = page->cols * page->rows;
+ if ((k < 1) || (k > MAX_SECTIONS))
+ {
+ TIFFError("writeImageSections",
+ "%d Rows and Columns exceed maximum sections\nIncrease resolution or reduce sections", k);
+ return (-1);
+ }
+
+ for (i = 0; i < k; i++)
+ {
+ width = sections[i].x2 - sections[i].x1 + 1;
+ length = sections[i].y2 - sections[i].y1 + 1;
+ sectsize = (uint32)
+ ceil((width * image->bps + 7) / (double)8) * image->spp * length;
+ /* allocate a buffer if we don't have one already */
+ if (createImageSection(sectsize, sect_buff_ptr))
+ {
+ TIFFError("writeImageSections", "Unable to allocate section buffer");
+ exit (-1);
+ }
+ sect_buff = *sect_buff_ptr;
+
+ if (extractImageSection (image, &sections[i], src_buff, sect_buff))
+ {
+ TIFFError("writeImageSections", "Unable to extract image sections");
+ exit (-1);
+ }
+
+ /* call the write routine here instead of outside the loop */
+ if (writeSingleSection(in, out, image, dump, width, length, hres, vres, sect_buff))
+ {
+ TIFFError("writeImageSections", "Unable to write image section");
+ exit (-1);
+ }
+ }
+
+ return (0);
+ } /* end writeImageSections */
+
+/* Code in this function is heavily indebted to code in tiffcp
+ * with modifications by Richard Nolde to handle orientation correctly.
+ * It will have to be updated significantly if support is added to
+ * extract one or more samples from original image since the
+ * original code assumes we are always copying all samples.
+ */
+static int
+writeSingleSection(TIFF *in, TIFF *out, struct image_data *image,
+ struct dump_opts *dump, uint32 width, uint32 length,
+ double hres, double vres,
+ unsigned char *sect_buff)
+ {
+ uint16 bps, spp;
+ uint16 input_compression, input_photometric;
+ uint16 input_jpeg_colormode, input_planar;
+ struct cpTag* p;
+
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &spp);
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &bps);
+
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
+
+ CopyField(TIFFTAG_BITSPERSAMPLE, bps);
+ CopyField(TIFFTAG_SAMPLESPERPIXEL, spp);
+
+
+ TIFFGetField(in, TIFFTAG_COMPRESSION, &input_compression);
+ /* This is the global variable compression which is set
+ * if the user has specified a command line option for
+ * a compression option. Should be passed around in one
+ * of the parameters instead of as a global. If no user
+ * option specified it will still be (uint16) -1. */
+ if (compression != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ else
+ { /* OJPEG is no longer supported for writing so upgrade to JPEG */
+ if (input_compression == COMPRESSION_OJPEG)
+ {
+ TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
+ compression = COMPRESSION_JPEG;
+ }
+ else /* Use the compression from the input file */
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ }
+
+ TIFFGetField(in, TIFFTAG_JPEGCOLORMODE, &input_jpeg_colormode);
+#ifdef DEBUG2
+ TIFFError("writeSingleSection", "Input compression: %s",
+ (input_compression == COMPRESSION_OJPEG) ? "Old Jpeg" :
+ ((input_compression == COMPRESSION_JPEG) ? "New Jpeg" : "Non Jpeg"));
+#endif
+ if (compression == COMPRESSION_JPEG)
+ {
+ if ((input_photometric == PHOTOMETRIC_PALETTE) || /* color map indexed */
+ (input_photometric == PHOTOMETRIC_MASK)) /* $holdout mask */
+ {
+ TIFFError ("writeSingleSection",
+ "JPEG compression cannot be used with %s image data",
+ (input_photometric == PHOTOMETRIC_PALETTE) ?
+ "palette" : "mask");
+ return (-1);
+ }
+ if (input_photometric == PHOTOMETRIC_RGB)
+ {
+ if (jpegcolormode == JPEGCOLORMODE_RGB)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ }
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
+ }
+ else
+ {
+ if (compression == COMPRESSION_SGILOG || compression == COMPRESSION_SGILOG24)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, spp == 1 ?
+ PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, image->photometric);
+ }
+
+#ifdef DEBUG2
+ TIFFError("writeSingleSection", "Input photometric: %s",
+ (input_photmetric == PHOTMETRIC_RGB) ? "RGB" :
+ ((input_photometric == PHOTOMETRIC_YCBCR) ? "YCbCr" : "Not RGB or YCrCr"));
+#endif
+
+ if (((input_photometric == PHOTOMETRIC_LOGL) ||
+ (input_photometric == PHOTOMETRIC_LOGLUV)) &&
+ ((compression != COMPRESSION_SGILOG) &&
+ (compression != COMPRESSION_SGILOG24)))
+ {
+ TIFFError("writeCroppedImage",
+ "LogL and LogLuv source data require SGI_LOG or SGI_LOG24 compression");
+ return (-1);
+ }
+
+ if (fillorder != 0)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ else
+ CopyTag(TIFFTAG_FILLORDER, 1, TIFF_SHORT);
+
+ /* The loadimage function reads input orientation and sets
+ * image->orientation. The correct_image_orientation function
+ * applies the required rotation and mirror operations to
+ * present the data in TOPLEFT orientation and updates
+ * image->orientation if any transforms are performed,
+ * as per EXIF standard.
+ */
+ TIFFSetField(out, TIFFTAG_ORIENTATION, image->orientation);
+
+ /*
+ * Choose tiles/strip for the output image according to
+ * the command line arguments (-tiles, -strips) and the
+ * structure of the input image.
+ */
+ if (outtiled == -1)
+ outtiled = TIFFIsTiled(in);
+ if (outtiled) {
+ /*
+ * Setup output file's tile width&height. If either
+ * is not specified, use either the value from the
+ * input image or, if nothing is defined, use the
+ * library default.
+ */
+ if (tilewidth == (uint32) 0)
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);
+ if (tilelength == (uint32) 0)
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);
+
+ if (tilewidth == 0 || tilelength == 0)
+ TIFFDefaultTileSize(out, &tilewidth, &tilelength);
+ TIFFDefaultTileSize(out, &tilewidth, &tilelength);
+ TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);
+ TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);
+ } else {
+ /*
+ * RowsPerStrip is left unspecified: use either the
+ * value from the input image or, if nothing is defined,
+ * use the library default.
+ */
+ if (rowsperstrip == (uint32) 0)
+ {
+ if (!TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip))
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ if (compression != COMPRESSION_JPEG)
+ {
+ if (rowsperstrip > length)
+ rowsperstrip = length;
+ }
+ }
+ else
+ if (rowsperstrip == (uint32) -1)
+ rowsperstrip = length;
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ }
+
+ TIFFGetFieldDefaulted(in, TIFFTAG_PLANARCONFIG, &input_planar);
+ if (config != (uint16) -1)
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ else
+ CopyField(TIFFTAG_PLANARCONFIG, config);
+ if (spp <= 4)
+ CopyTag(TIFFTAG_TRANSFERFUNCTION, 4, TIFF_SHORT);
+ CopyTag(TIFFTAG_COLORMAP, 4, TIFF_SHORT);
+
+/* SMinSampleValue & SMaxSampleValue */
+ switch (compression) {
+ /* These are references to GLOBAL variables set by defaults
+ * and /or the compression flag
+ */
+ case COMPRESSION_JPEG:
+ if (((bps % 8) == 0) || ((bps % 12) == 0))
+ {
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ }
+ else
+ {
+ TIFFError("writeCroppedImage",
+ "JPEG compression requires 8 or 12 bits per sample");
+ return (-1);
+ }
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_ADOBE_DEFLATE:
+ case COMPRESSION_DEFLATE:
+ if (predictor != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ else
+ CopyField(TIFFTAG_PREDICTOR, predictor);
+ break;
+ case COMPRESSION_CCITTFAX3:
+ case COMPRESSION_CCITTFAX4:
+ if (compression == COMPRESSION_CCITTFAX3) {
+ if (g3opts != (uint32) -1)
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts);
+ else
+ CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);
+ } else
+ CopyTag(TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_BADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CLEANFAXDATA, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
+ break;
+ }
+ { uint32 len32;
+ void** data;
+ if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &len32, &data))
+ TIFFSetField(out, TIFFTAG_ICCPROFILE, len32, data);
+ }
+ { uint16 ninks;
+ const char* inknames;
+ if (TIFFGetField(in, TIFFTAG_NUMBEROFINKS, &ninks)) {
+ TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks);
+ if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) {
+ int inknameslen = strlen(inknames) + 1;
+ const char* cp = inknames;
+ while (ninks > 1) {
+ cp = strchr(cp, '\0');
+ if (cp) {
+ cp++;
+ inknameslen += (strlen(cp) + 1);
+ }
+ ninks--;
+ }
+ TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames);
+ }
+ }
+ }
+ {
+ unsigned short pg0, pg1;
+ if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1)) {
+ if (pageNum < 0) /* only one input file */
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pg0, pg1);
+ else
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pageNum++, 0);
+ }
+ }
+
+ for (p = tags; p < &tags[NTAGS]; p++)
+ CopyTag(p->tag, p->count, p->type);
+
+ /* Update these since they are overwritten from input res by loop above */
+ TIFFSetField(out, TIFFTAG_XRESOLUTION, (float)hres);
+ TIFFSetField(out, TIFFTAG_YRESOLUTION, (float)vres);
+
+ /* Compute the tile or strip dimensions and write to disk */
+ if (outtiled)
+ {
+ if (config == PLANARCONFIG_CONTIG)
+ writeBufferToContigTiles (out, sect_buff, length, width, spp, dump);
+ else
+ writeBufferToSeparateTiles (out, sect_buff, length, width, spp, dump);
+ }
+ else
+ {
+ if (config == PLANARCONFIG_CONTIG)
+ writeBufferToContigStrips (out, sect_buff, length);
+ else
+ writeBufferToSeparateStrips(out, sect_buff, length, width, spp, dump);
+ }
+
+ if (!TIFFWriteDirectory(out))
+ {
+ TIFFClose(out);
+ return (-1);
+ }
+
+ return (0);
+ } /* end writeSingleSection */
+
+
+/* Create a buffer to write one section at a time */
+static int
+createImageSection(uint32 sectsize, unsigned char **sect_buff_ptr)
+ {
+ unsigned char *sect_buff = NULL;
+ unsigned char *new_buff = NULL;
+ static uint32 prev_sectsize = 0;
+
+ sect_buff = *sect_buff_ptr;
+
+ if (!sect_buff)
+ {
+ sect_buff = (unsigned char *)_TIFFmalloc(sectsize);
+ *sect_buff_ptr = sect_buff;
+ _TIFFmemset(sect_buff, 0, sectsize);
+ }
+ else
+ {
+ if (prev_sectsize < sectsize)
+ {
+ new_buff = _TIFFrealloc(sect_buff, sectsize);
+ if (!new_buff)
+ {
+ free (sect_buff);
+ sect_buff = (unsigned char *)_TIFFmalloc(sectsize);
+ }
+ else
+ sect_buff = new_buff;
+
+ _TIFFmemset(sect_buff, 0, sectsize);
+ }
+ }
+
+ if (!sect_buff)
+ {
+ TIFFError("createImageSection", "Unable to allocate/reallocate section buffer");
+ return (-1);
+ }
+ prev_sectsize = sectsize;
+ *sect_buff_ptr = sect_buff;
+
+ return (0);
+ } /* end createImageSection */
+
+
+/* Process selections defined by regions, zones, margins, or fixed sized areas */
+static int
+processCropSelections(struct image_data *image, struct crop_mask *crop,
+ unsigned char **read_buff_ptr, struct buffinfo seg_buffs[])
+ {
+ int i;
+ uint32 width, length, total_width, total_length;
+ tsize_t cropsize;
+ unsigned char *crop_buff = NULL;
+ unsigned char *read_buff = NULL;
+ unsigned char *next_buff = NULL;
+ tsize_t prev_cropsize = 0;
+
+ read_buff = *read_buff_ptr;
+
+ if (crop->img_mode == COMPOSITE_IMAGES)
+ {
+ cropsize = crop->bufftotal;
+ crop_buff = seg_buffs[0].buffer;
+ if (!crop_buff)
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ else
+ {
+ prev_cropsize = seg_buffs[0].size;
+ if (prev_cropsize < cropsize)
+ {
+ next_buff = _TIFFrealloc(crop_buff, cropsize);
+ if (! next_buff)
+ {
+ _TIFFfree (crop_buff);
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ }
+ else
+ crop_buff = next_buff;
+ }
+ }
+
+ if (!crop_buff)
+ {
+ TIFFError("processCropSelections", "Unable to allocate/reallocate crop buffer");
+ return (-1);
+ }
+
+ _TIFFmemset(crop_buff, 0, cropsize);
+ seg_buffs[0].buffer = crop_buff;
+ seg_buffs[0].size = cropsize;
+
+ /* Checks for matching width or length as required */
+ if (extractCompositeRegions(image, crop, read_buff, crop_buff) != 0)
+ return (1);
+
+ if (crop->crop_mode & CROP_INVERT)
+ {
+ switch (crop->photometric)
+ {
+ /* Just change the interpretation */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = crop->photometric;
+ break;
+ case INVERT_DATA_ONLY:
+ case INVERT_DATA_AND_TAG:
+ if (invertImage(image->photometric, image->spp, image->bps,
+ crop->combined_width, crop->combined_length, crop_buff))
+ {
+ TIFFError("processCropSelections",
+ "Failed to invert colorspace for composite regions");
+ return (-1);
+ }
+ if (crop->photometric == INVERT_DATA_AND_TAG)
+ {
+ switch (image->photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ image->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+
+ /* Mirror and Rotate will not work with multiple regions unless they are the same width */
+ if (crop->crop_mode & CROP_MIRROR)
+ {
+ if (mirrorImage(image->spp, image->bps, crop->mirror,
+ crop->combined_width, crop->combined_length, crop_buff))
+ {
+ TIFFError("processCropSelections", "Failed to mirror composite regions %s",
+ (crop->rotation == MIRROR_HORIZ) ? "horizontally" : "vertically");
+ return (-1);
+ }
+ }
+
+ if (crop->crop_mode & CROP_ROTATE) /* rotate should be last as it can reallocate the buffer */
+ {
+ if (rotateImage(crop->rotation, image, &crop->combined_width,
+ &crop->combined_length, &crop_buff))
+ {
+ TIFFError("processCropSelections",
+ "Failed to rotate composite regions by %d degrees", crop->rotation);
+ return (-1);
+ }
+ seg_buffs[0].buffer = crop_buff;
+ seg_buffs[0].size = (((crop->combined_width * image->bps + 7 ) / 8)
+ * image->spp) * crop->combined_length;
+ }
+ }
+ else /* Separated Images */
+ {
+ total_width = total_length = 0;
+ for (i = 0; i < crop->selections; i++)
+ {
+ cropsize = crop->bufftotal;
+ crop_buff = seg_buffs[i].buffer;
+ if (!crop_buff)
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ else
+ {
+ prev_cropsize = seg_buffs[0].size;
+ if (prev_cropsize < cropsize)
+ {
+ next_buff = _TIFFrealloc(crop_buff, cropsize);
+ if (! next_buff)
+ {
+ _TIFFfree (crop_buff);
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ }
+ else
+ crop_buff = next_buff;
+ }
+ }
+
+ if (!crop_buff)
+ {
+ TIFFError("processCropSelections", "Unable to allocate/reallocate crop buffer");
+ return (-1);
+ }
+
+ _TIFFmemset(crop_buff, 0, cropsize);
+ seg_buffs[i].buffer = crop_buff;
+ seg_buffs[i].size = cropsize;
+
+ if (extractSeparateRegion(image, crop, read_buff, crop_buff, i))
+ {
+ TIFFError("processCropSelections", "Unable to extract cropped region %d from image", i);
+ return (-1);
+ }
+
+ width = crop->regionlist[i].width;
+ length = crop->regionlist[i].length;
+
+ if (crop->crop_mode & CROP_INVERT)
+ {
+ switch (crop->photometric)
+ {
+ /* Just change the interpretation */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = crop->photometric;
+ break;
+ case INVERT_DATA_ONLY:
+ case INVERT_DATA_AND_TAG:
+ if (invertImage(image->photometric, image->spp, image->bps,
+ width, length, crop_buff))
+ {
+ TIFFError("processCropSelections",
+ "Failed to invert colorspace for region");
+ return (-1);
+ }
+ if (crop->photometric == INVERT_DATA_AND_TAG)
+ {
+ switch (image->photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ image->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (crop->crop_mode & CROP_MIRROR)
+ {
+ if (mirrorImage(image->spp, image->bps, crop->mirror,
+ width, length, crop_buff))
+ {
+ TIFFError("processCropSelections", "Failed to mirror crop region %s",
+ (crop->rotation == MIRROR_HORIZ) ? "horizontally" : "vertically");
+ return (-1);
+ }
+ }
+
+ if (crop->crop_mode & CROP_ROTATE) /* rotate should be last as it can reallocate the buffer */
+ {
+ if (rotateImage(crop->rotation, image, &crop->regionlist[i].width,
+ &crop->regionlist[i].length, &crop_buff))
+ {
+ TIFFError("processCropSelections",
+ "Failed to rotate crop region by %d degrees", crop->rotation);
+ return (-1);
+ }
+ total_width += crop->regionlist[i].width;
+ total_length += crop->regionlist[i].length;
+ crop->combined_width = total_width;
+ crop->combined_length = total_length;
+ seg_buffs[i].buffer = crop_buff;
+ seg_buffs[i].size = (((crop->regionlist[i].width * image->bps + 7 ) / 8)
+ * image->spp) * crop->regionlist[i].length;
+ }
+ }
+ }
+ return (0);
+ } /* end processCropSelections */
+
+/* Copy the crop section of the data from the current image into a buffer
+ * and adjust the IFD values to reflect the new size. If no cropping is
+ * required, use the origial read buffer as the crop buffer.
+ *
+ * There is quite a bit of redundancy between this routine and the more
+ * specialized processCropSelections, but this provides
+ * the most optimized path when no Zones or Regions are required.
+ */
+static int
+createCroppedImage(struct image_data *image, struct crop_mask *crop,
+ unsigned char **read_buff_ptr, unsigned char **crop_buff_ptr)
+ {
+ tsize_t cropsize;
+ unsigned char *read_buff = NULL;
+ unsigned char *crop_buff = NULL;
+ unsigned char *new_buff = NULL;
+ static tsize_t prev_cropsize = 0;
+
+ read_buff = *read_buff_ptr;
+
+ /* process full image, no crop buffer needed */
+ crop_buff = read_buff;
+ *crop_buff_ptr = read_buff;
+ crop->combined_width = image->width;
+ crop->combined_length = image->length;
+
+ cropsize = crop->bufftotal;
+ crop_buff = *crop_buff_ptr;
+ if (!crop_buff)
+ {
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ *crop_buff_ptr = crop_buff;
+ _TIFFmemset(crop_buff, 0, cropsize);
+ prev_cropsize = cropsize;
+ }
+ else
+ {
+ if (prev_cropsize < cropsize)
+ {
+ new_buff = _TIFFrealloc(crop_buff, cropsize);
+ if (!new_buff)
+ {
+ free (crop_buff);
+ crop_buff = (unsigned char *)_TIFFmalloc(cropsize);
+ }
+ else
+ crop_buff = new_buff;
+ _TIFFmemset(crop_buff, 0, cropsize);
+ }
+ }
+
+ if (!crop_buff)
+ {
+ TIFFError("createCroppedImage", "Unable to allocate/reallocate crop buffer");
+ return (-1);
+ }
+ *crop_buff_ptr = crop_buff;
+
+ if (crop->crop_mode & CROP_INVERT)
+ {
+ switch (crop->photometric)
+ {
+ /* Just change the interpretation */
+ case PHOTOMETRIC_MINISWHITE:
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = crop->photometric;
+ break;
+ case INVERT_DATA_ONLY:
+ case INVERT_DATA_AND_TAG:
+ if (invertImage(image->photometric, image->spp, image->bps,
+ crop->combined_width, crop->combined_length, crop_buff))
+ {
+ TIFFError("createCroppedImage",
+ "Failed to invert colorspace for image or cropped selection");
+ return (-1);
+ }
+ if (crop->photometric == INVERT_DATA_AND_TAG)
+ {
+ switch (image->photometric)
+ {
+ case PHOTOMETRIC_MINISWHITE:
+ image->photometric = PHOTOMETRIC_MINISBLACK;
+ break;
+ case PHOTOMETRIC_MINISBLACK:
+ image->photometric = PHOTOMETRIC_MINISWHITE;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (crop->crop_mode & CROP_MIRROR)
+ {
+ if (mirrorImage(image->spp, image->bps, crop->mirror,
+ crop->combined_width, crop->combined_length, crop_buff))
+ {
+ TIFFError("createCroppedImage", "Failed to mirror image or cropped selection %s",
+ (crop->rotation == MIRROR_HORIZ) ? "horizontally" : "vertically");
+ return (-1);
+ }
+ }
+
+ if (crop->crop_mode & CROP_ROTATE) /* rotate should be last as it can reallocate the buffer */
+ {
+ if (rotateImage(crop->rotation, image, &crop->combined_width,
+ &crop->combined_length, crop_buff_ptr))
+ {
+ TIFFError("createCroppedImage",
+ "Failed to rotate image or cropped selection by %d degrees", crop->rotation);
+ return (-1);
+ }
+ }
+
+ if (crop_buff == read_buff) /* we used the read buffer for the crop buffer */
+ *read_buff_ptr = NULL; /* so we don't try to free it later */
+
+ return (0);
+ } /* end createCroppedImage */
+
+
+/* Code in this function is heavily indebted to code in tiffcp
+ * with modifications by Richard Nolde to handle orientation correctly.
+ * It will have to be updated significantly if support is added to
+ * extract one or more samples from original image since the
+ * original code assumes we are always copying all samples.
+ * Use of global variables for config, compression and others
+ * should be replaced by addition to the crop_mask struct (which
+ * will be renamed to proc_opts indicating that is controlls
+ * user supplied processing options, not just cropping) and
+ * then passed in as an argument.
+ */
+static int
+writeCroppedImage(TIFF *in, TIFF *out, struct image_data *image,
+ struct dump_opts *dump, uint32 width, uint32 length,
+ unsigned char *crop_buff, int pagenum, int total_pages)
+ {
+ uint16 bps, spp;
+ uint16 input_compression, input_photometric;
+ uint16 input_jpeg_colormode, input_planar;
+ struct cpTag* p;
+
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &input_photometric);
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &spp);
+ TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &bps);
+
+ TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, length);
+
+ CopyField(TIFFTAG_BITSPERSAMPLE, bps);
+ CopyField(TIFFTAG_SAMPLESPERPIXEL, spp);
+
+ TIFFGetField(in, TIFFTAG_COMPRESSION, &input_compression);
+ if (compression != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ else
+ {
+ if (input_compression == COMPRESSION_OJPEG)
+ {
+ TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_JPEG);
+ compression = COMPRESSION_JPEG;
+ }
+ else
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ }
+
+ TIFFGetField(in, TIFFTAG_JPEGCOLORMODE, &input_jpeg_colormode);
+#ifdef DEBUG2
+ TIFFError("writeCroppedImage", "Input compression: %s",
+ (input_compression == COMPRESSION_OJPEG) ? "Old Jpeg" :
+ ((input_compression == COMPRESSION_JPEG) ? "New Jpeg" : "Non Jpeg"));
+#endif
+ if (compression == COMPRESSION_JPEG)
+ {
+ if ((input_photometric == PHOTOMETRIC_PALETTE) || /* color map indexed */
+ (input_photometric == PHOTOMETRIC_MASK)) /* $holdout mask */
+ {
+ TIFFError ("writeCroppedImage",
+ "JPEG compression cannot be used with %s image data",
+ (input_photometric == PHOTOMETRIC_PALETTE) ?
+ "palette" : "mask");
+ return (-1);
+ }
+ if (input_photometric == PHOTOMETRIC_RGB)
+ {
+ if (jpegcolormode == JPEGCOLORMODE_RGB)
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR);
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ }
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, input_photometric);
+ }
+ else
+ {
+ if (compression == COMPRESSION_SGILOG || compression == COMPRESSION_SGILOG24)
+ {
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, spp == 1 ?
+ PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
+ }
+ else
+ {
+ if (input_compression == COMPRESSION_SGILOG ||
+ input_compression == COMPRESSION_SGILOG24)
+ {
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, spp == 1 ?
+ PHOTOMETRIC_LOGL : PHOTOMETRIC_LOGLUV);
+ }
+ else
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, image->photometric);
+ }
+ }
+
+ if (((input_photometric == PHOTOMETRIC_LOGL) ||
+ (input_photometric == PHOTOMETRIC_LOGLUV)) &&
+ ((compression != COMPRESSION_SGILOG) &&
+ (compression != COMPRESSION_SGILOG24)))
+ {
+ TIFFError("writeCroppedImage",
+ "LogL and LogLuv source data require SGI_LOG or SGI_LOG24 compression");
+ return (-1);
+ }
+
+ if (fillorder != 0)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ else
+ CopyTag(TIFFTAG_FILLORDER, 1, TIFF_SHORT);
+
+ /* The loadimage function reads input orientation and sets
+ * image->orientation. The correct_image_orientation function
+ * applies the required rotation and mirror operations to
+ * present the data in TOPLEFT orientation and updates
+ * image->orientation if any transforms are performed,
+ * as per EXIF standard.
+ */
+ TIFFSetField(out, TIFFTAG_ORIENTATION, image->orientation);
+
+ /*
+ * Choose tiles/strip for the output image according to
+ * the command line arguments (-tiles, -strips) and the
+ * structure of the input image.
+ */
+ if (outtiled == -1)
+ outtiled = TIFFIsTiled(in);
+ if (outtiled) {
+ /*
+ * Setup output file's tile width&height. If either
+ * is not specified, use either the value from the
+ * input image or, if nothing is defined, use the
+ * library default.
+ */
+ if (tilewidth == (uint32) 0)
+ TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth);
+ if (tilelength == (uint32) 0)
+ TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength);
+
+ if (tilewidth == 0 || tilelength == 0)
+ TIFFDefaultTileSize(out, &tilewidth, &tilelength);
+ TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth);
+ TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength);
+ } else {
+ /*
+ * RowsPerStrip is left unspecified: use either the
+ * value from the input image or, if nothing is defined,
+ * use the library default.
+ */
+ if (rowsperstrip == (uint32) 0)
+ {
+ if (!TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip))
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ if (compression != COMPRESSION_JPEG)
+ {
+ if (rowsperstrip > length)
+ rowsperstrip = length;
+ }
+ }
+ else
+ if (rowsperstrip == (uint32) -1)
+ rowsperstrip = length;
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ }
+
+ TIFFGetFieldDefaulted(in, TIFFTAG_PLANARCONFIG, &input_planar);
+ if (config != (uint16) -1)
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, config);
+ else
+ CopyField(TIFFTAG_PLANARCONFIG, config);
+ if (spp <= 4)
+ CopyTag(TIFFTAG_TRANSFERFUNCTION, 4, TIFF_SHORT);
+ CopyTag(TIFFTAG_COLORMAP, 4, TIFF_SHORT);
+
+/* SMinSampleValue & SMaxSampleValue */
+ switch (compression) {
+ case COMPRESSION_JPEG:
+ if (((bps % 8) == 0) || ((bps % 12) == 0))
+ {
+ TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality);
+ TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+ }
+ else
+ {
+ TIFFError("writeCroppedImage",
+ "JPEG compression requires 8 or 12 bits per sample");
+ return (-1);
+ }
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_ADOBE_DEFLATE:
+ case COMPRESSION_DEFLATE:
+ if (predictor != (uint16)-1)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ else
+ CopyField(TIFFTAG_PREDICTOR, predictor);
+ break;
+ case COMPRESSION_CCITTFAX3:
+ case COMPRESSION_CCITTFAX4:
+ if (bps != 1)
+ {
+ TIFFError("writeCroppedImage",
+ "Group 3/4 compression is not usable with bps > 1");
+ return (-1);
+ }
+ if (compression == COMPRESSION_CCITTFAX3) {
+ if (g3opts != (uint32) -1)
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts);
+ else
+ CopyField(TIFFTAG_GROUP3OPTIONS, g3opts);
+ } else
+ CopyTag(TIFFTAG_GROUP4OPTIONS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_BADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CLEANFAXDATA, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_CONSECUTIVEBADFAXLINES, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVPARAMS, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXRECVTIME, 1, TIFF_LONG);
+ CopyTag(TIFFTAG_FAXSUBADDRESS, 1, TIFF_ASCII);
+ break;
+ case COMPRESSION_NONE:
+ break;
+ default: break;
+ }
+ { uint32 len32;
+ void** data;
+ if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &len32, &data))
+ TIFFSetField(out, TIFFTAG_ICCPROFILE, len32, data);
+ }
+ { uint16 ninks;
+ const char* inknames;
+ if (TIFFGetField(in, TIFFTAG_NUMBEROFINKS, &ninks)) {
+ TIFFSetField(out, TIFFTAG_NUMBEROFINKS, ninks);
+ if (TIFFGetField(in, TIFFTAG_INKNAMES, &inknames)) {
+ int inknameslen = strlen(inknames) + 1;
+ const char* cp = inknames;
+ while (ninks > 1) {
+ cp = strchr(cp, '\0');
+ if (cp) {
+ cp++;
+ inknameslen += (strlen(cp) + 1);
+ }
+ ninks--;
+ }
+ TIFFSetField(out, TIFFTAG_INKNAMES, inknameslen, inknames);
+ }
+ }
+ }
+ {
+ unsigned short pg0, pg1;
+ if (TIFFGetField(in, TIFFTAG_PAGENUMBER, &pg0, &pg1)) {
+ TIFFSetField(out, TIFFTAG_PAGENUMBER, pagenum, total_pages);
+ }
+ }
+
+ for (p = tags; p < &tags[NTAGS]; p++)
+ CopyTag(p->tag, p->count, p->type);
+
+ /* Compute the tile or strip dimensions and write to disk */
+ if (outtiled)
+ {
+ if (config == PLANARCONFIG_CONTIG)
+ {
+ if (writeBufferToContigTiles (out, crop_buff, length, width, spp, dump))
+ TIFFError("","Unable to write contiguous tile data for page %d", pagenum);
+ }
+ else
+ {
+ if (writeBufferToSeparateTiles (out, crop_buff, length, width, spp, dump))
+ TIFFError("","Unable to write separate tile data for page %d", pagenum);
+ }
+ }
+ else
+ {
+ if (config == PLANARCONFIG_CONTIG)
+ {
+ if (writeBufferToContigStrips (out, crop_buff, length))
+ TIFFError("","Unable to write contiguous strip data for page %d", pagenum);
+ }
+ else
+ {
+ if (writeBufferToSeparateStrips(out, crop_buff, length, width, spp, dump))
+ TIFFError("","Unable to write separate strip data for page %d", pagenum);
+ }
+ }
+
+ if (!TIFFWriteDirectory(out))
+ {
+ TIFFError("","Failed to write IFD for page number %d", pagenum);
+ TIFFClose(out);
+ return (-1);
+ }
+
+ return (0);
+ } /* end writeCroppedImage */
+
+static int
+rotateContigSamples8bits(uint16 rotation, uint16 spp, uint16 bps, uint32 width,
+ uint32 length, uint32 col, uint8 *src, uint8 *dst)
+ {
+ int ready_bits = 0;
+ uint32 src_byte = 0, src_bit = 0;
+ uint32 row, rowsize = 0, bit_offset = 0;
+ uint8 matchbits = 0, maskbits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ uint8 *next;
+ tsample_t sample;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("rotateContigSamples8bits","Invalid src or destination buffer");
+ return (1);
+ }
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ ready_bits = 0;
+ maskbits = (uint8)-1 >> ( 8 - bps);
+ buff1 = buff2 = 0;
+
+ for (row = 0; row < length ; row++)
+ {
+ bit_offset = col * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ switch (rotation)
+ {
+ case 90: next = src + src_byte - (row * rowsize);
+ break;
+ case 270: next = src + src_byte + (row * rowsize);
+ break;
+ default: TIFFError("rotateContigSamples8bits", "Invalid rotation %d", rotation);
+ return (1);
+ }
+ matchbits = maskbits << (8 - src_bit - bps);
+ buff1 = ((*next) & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ }
+ else
+ {
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ }
+
+ return (0);
+ } /* end rotateContigSamples8bits */
+
+
+static int
+rotateContigSamples16bits(uint16 rotation, uint16 spp, uint16 bps, uint32 width,
+ uint32 length, uint32 col, uint8 *src, uint8 *dst)
+ {
+ int ready_bits = 0;
+ uint32 row, rowsize, bit_offset;
+ uint32 src_byte = 0, src_bit = 0;
+ uint16 matchbits = 0, maskbits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ uint8 *next;
+ tsample_t sample;
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("rotateContigSamples16bits","Invalid src or destination buffer");
+ return (1);
+ }
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ ready_bits = 0;
+ maskbits = (uint16)-1 >> (16 - bps);
+ buff1 = buff2 = 0;
+ for (row = 0; row < length; row++)
+ {
+ bit_offset = col * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ switch (rotation)
+ {
+ case 90: next = src + src_byte - (row * rowsize);
+ break;
+ case 270: next = src + src_byte + (row * rowsize);
+ break;
+ default: TIFFError("rotateContigSamples8bits", "Invalid rotation %d", rotation);
+ return (1);
+ }
+ matchbits = maskbits << (16 - src_bit - bps);
+ if (little_endian)
+ buff1 = (next[0] << 8) | next[1];
+ else
+ buff1 = (next[1] << 8) | next[0];
+
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 8)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ }
+
+ return (0);
+ } /* end rotateContigSamples16bits */
+
+static int
+rotateContigSamples24bits(uint16 rotation, uint16 spp, uint16 bps, uint32 width,
+ uint32 length, uint32 col, uint8 *src, uint8 *dst)
+ {
+ int ready_bits = 0;
+ uint32 row, rowsize, bit_offset;
+ uint32 src_byte = 0, src_bit = 0;
+ uint32 matchbits = 0, maskbits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ uint8 *next;
+ tsample_t sample;
+
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("rotateContigSamples24bits","Invalid src or destination buffer");
+ return (1);
+ }
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ ready_bits = 0;
+ maskbits = (uint32)-1 >> (32 - bps);
+ buff1 = buff2 = 0;
+ for (row = 0; row < length; row++)
+ {
+ bit_offset = col * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ switch (rotation)
+ {
+ case 90: next = src + src_byte - (row * rowsize);
+ break;
+ case 270: next = src + src_byte + (row * rowsize);
+ break;
+ default: TIFFError("rotateContigSamples8bits", "Invalid rotation %d", rotation);
+ return (1);
+ }
+ matchbits = maskbits << (32 - src_bit - bps);
+ if (little_endian)
+ buff1 = (next[0] << 24) | (next[1] << 16) | (next[2] << 8) | next[3];
+ else
+ buff1 = (next[3] << 24) | (next[2] << 16) | (next[1] << 8) | next[0];
+ buff1 = (buff1 & matchbits) << (src_bit);
+
+ /* If we have a full buffer's worth, write it out */
+ if (ready_bits >= 16)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ }
+ else
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end rotateContigSamples24bits */
+
+static int
+rotateContigSamples32bits(uint16 rotation, uint16 spp, uint16 bps, uint32 width,
+ uint32 length, uint32 col, uint8 *src, uint8 *dst)
+ {
+ int ready_bits = 0, shift_width = 0;
+ int bytes_per_sample, bytes_per_pixel;
+ uint32 row, rowsize, bit_offset;
+ uint32 src_byte, src_bit;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 maskbits = 0, matchbits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ uint8 *next;
+ tsample_t sample;
+
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("rotateContigSamples24bits","Invalid src or destination buffer");
+ return (1);
+ }
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ ready_bits = 0;
+ maskbits = (uint64)-1 >> (64 - bps);
+ buff1 = buff2 = 0;
+ for (row = 0; row < length; row++)
+ {
+ bit_offset = col * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ switch (rotation)
+ {
+ case 90: next = src + src_byte - (row * rowsize);
+ break;
+ case 270: next = src + src_byte + (row * rowsize);
+ break;
+ default: TIFFError("rotateContigSamples8bits", "Invalid rotation %d", rotation);
+ return (1);
+ }
+ matchbits = maskbits << (64 - src_bit - bps);
+ if (little_endian)
+ {
+ longbuff1 = (next[0] << 24) | (next[1] << 16) | (next[2] << 8) | next[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (next[3] << 24) | (next[2] << 16) | (next[1] << 8) | next[0];
+ longbuff2 = longbuff1;
+ }
+
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & matchbits) << (src_bit);
+
+ if (ready_bits < 32)
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end rotateContigSamples32bits */
+
+
+/* Rotate an image by a multiple of 90 degrees clockwise */
+static int
+rotateImage(uint16 rotation, struct image_data *image, uint32 *img_width,
+ uint32 *img_length, unsigned char **ibuff_ptr)
+ {
+ int shift_width;
+ uint32 bytes_per_pixel, bytes_per_sample;
+ uint32 row, rowsize, src_offset, dst_offset;
+ uint32 i, col, width, length;
+ uint32 colsize, buffsize, col_offset, pix_offset;
+ unsigned char *ibuff;
+ unsigned char *src;
+ unsigned char *dst;
+ uint16 spp, bps;
+ float res_temp;
+ unsigned char *rbuff = NULL;
+
+ width = *img_width;
+ length = *img_length;
+ spp = image->spp;
+ bps = image->bps;
+
+ rowsize = ((bps * spp * width) + 7) / 8;
+ colsize = ((bps * spp * length) + 7) / 8;
+ if ((colsize * width) > (rowsize * length))
+ buffsize = (colsize + 1) * width;
+ else
+ buffsize = (rowsize + 1) * length;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ switch (rotation)
+ {
+ case 0:
+ case 360: return (0);
+ case 90:
+ case 180:
+ case 270: break;
+ default: TIFFError("rotateImage", "Invalid rotation angle %d", rotation);
+ return (-1);
+ }
+
+ if (!(rbuff = (unsigned char *)_TIFFmalloc(buffsize)))
+ {
+ TIFFError("rotateImage", "Unable to allocate rotation buffer of %1u bytes", buffsize);
+ return (-1);
+ }
+ _TIFFmemset(rbuff, '\0', buffsize);
+
+ ibuff = *ibuff_ptr;
+ switch (rotation)
+ {
+ case 180: if ((bps % 8) == 0) /* byte alligned data */
+ {
+ src = ibuff;
+ pix_offset = (spp * bps) / 8;
+ for (row = 0; row < length; row++)
+ {
+ dst_offset = (length - row - 1) * rowsize;
+ for (col = 0; col < width; col++)
+ {
+ col_offset = (width - col - 1) * pix_offset;
+ dst = rbuff + dst_offset + col_offset;
+
+ for (i = 0; i < bytes_per_pixel; i++)
+ *dst++ = *src++;
+ }
+ }
+ }
+ else
+ { /* non 8 bit per sample data */
+ for (row = 0; row < length; row++)
+ {
+ src_offset = row * rowsize;
+ dst_offset = (length - row - 1) * rowsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ switch (shift_width)
+ {
+ case 1: if (bps == 1)
+ {
+ if (reverseSamples8bits(spp, bps, width, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ }
+ if (reverseSamples16bits(spp, bps, width, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 2: if (reverseSamples24bits(spp, bps, width, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (reverseSamples32bits(spp, bps, width, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ default: TIFFError("rotateImage","Unsupported bit depth %d", bps);
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ }
+ }
+ _TIFFfree(ibuff);
+ *(ibuff_ptr) = rbuff;
+ break;
+
+ case 90: if ((bps % 8) == 0) /* byte aligned data */
+ {
+ for (col = 0; col < width; col++)
+ {
+ src_offset = ((length - 1) * rowsize) + (col * bytes_per_pixel);
+ dst_offset = col * colsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ for (row = length; row > 0; row--)
+ {
+ for (i = 0; i < bytes_per_pixel; i++)
+ *dst++ = *(src + i);
+ src -= rowsize;
+ }
+ }
+ }
+ else
+ { /* non 8 bit per sample data */
+ for (col = 0; col < width; col++)
+ {
+ src_offset = (length - 1) * rowsize;
+ dst_offset = col * colsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ switch (shift_width)
+ {
+ case 1: if (bps == 1)
+ {
+ if (rotateContigSamples8bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ }
+ if (rotateContigSamples16bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 2: if (rotateContigSamples24bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (rotateContigSamples32bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ default: TIFFError("rotateImage","Unsupported bit depth %d", bps);
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ }
+ }
+ _TIFFfree(ibuff);
+ *(ibuff_ptr) = rbuff;
+
+ *img_width = length;
+ *img_length = width;
+ image->width = length;
+ image->length = width;
+ res_temp = image->xres;
+ image->xres = image->yres;
+ image->yres = res_temp;
+ break;
+
+ case 270: if ((bps % 8) == 0) /* byte aligned data */
+ {
+ for (col = 0; col < width; col++)
+ {
+ src_offset = col * bytes_per_pixel;
+ dst_offset = (width - col - 1) * colsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ for (row = length; row > 0; row--)
+ {
+ for (i = 0; i < bytes_per_pixel; i++)
+ *dst++ = *(src + i);
+ src += rowsize;
+ }
+ }
+ }
+ else
+ { /* non 8 bit per sample data */
+ for (col = 0; col < width; col++)
+ {
+ src_offset = 0;
+ dst_offset = (width - col - 1) * colsize;
+ src = ibuff + src_offset;
+ dst = rbuff + dst_offset;
+ switch (shift_width)
+ {
+ case 1: if (bps == 1)
+ {
+ if (rotateContigSamples8bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ }
+ if (rotateContigSamples16bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 2: if (rotateContigSamples24bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ case 3:
+ case 4:
+ case 5: if (rotateContigSamples32bits(rotation, spp, bps, width,
+ length, col, src, dst))
+ {
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ break;
+ default: TIFFError("rotateImage","Unsupported bit depth %d", bps);
+ _TIFFfree(rbuff);
+ return (-1);
+ }
+ }
+ }
+ _TIFFfree(ibuff);
+ *(ibuff_ptr) = rbuff;
+
+ *img_width = length;
+ *img_length = width;
+ image->width = length;
+ image->length = width;
+ res_temp = image->xres;
+ image->xres = image->yres;
+ image->yres = res_temp;
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+ } /* end rotateImage */
+
+static int
+reverseSamples8bits (uint16 spp, uint16 bps, uint32 width,
+ uint8 *ibuff, uint8 *obuff)
+ {
+ int ready_bits = 0;
+ uint32 col;
+ uint32 src_byte, src_bit;
+ uint32 bit_offset = 0;
+ uint8 match_bits = 0, mask_bits = 0;
+ uint8 buff1 = 0, buff2 = 0;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t sample;
+
+ if ((ibuff == NULL) || (obuff == NULL))
+ {
+ TIFFError("reverseSamples8bits","Invalid image or work buffer");
+ return (1);
+ }
+
+ ready_bits = 0;
+ mask_bits = (uint8)-1 >> ( 8 - bps);
+ dst = obuff;
+ for (col = width; col > 0; col--)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = (col - 1) * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ src_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ src_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ src = ibuff + src_byte;
+ match_bits = mask_bits << (8 - src_bit - bps);
+ buff1 = ((*src) & match_bits) << (src_bit);
+
+ if (ready_bits < 8)
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ else /* If we have a full buffer's worth, write it out */
+ {
+ *dst++ = buff2;
+ buff2 = buff1;
+ ready_bits -= 8;
+ }
+ ready_bits += bps;
+ }
+ }
+ if (ready_bits > 0)
+ {
+ buff1 = (buff2 & ((unsigned int)255 << (8 - ready_bits)));
+ *dst++ = buff1;
+ }
+
+ return (0);
+ } /* end reverseSamples8bits */
+
+
+static int
+reverseSamples16bits (uint16 spp, uint16 bps, uint32 width,
+ uint8 *ibuff, uint8 *obuff)
+ {
+ int ready_bits = 0;
+ uint32 col;
+ uint32 src_byte = 0, high_bit = 0;
+ uint32 bit_offset = 0;
+ uint16 match_bits = 0, mask_bits = 0;
+ uint16 buff1 = 0, buff2 = 0;
+ uint8 bytebuff = 0;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t sample;
+
+ if ((ibuff == NULL) || (obuff == NULL))
+ {
+ TIFFError("reverseSample16bits","Invalid image or work buffer");
+ return (1);
+ }
+
+ ready_bits = 0;
+ mask_bits = (uint16)-1 >> (16 - bps);
+ dst = obuff;
+ for (col = width; col > 0; col--)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = (col - 1) * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ high_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ high_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ src = ibuff + src_byte;
+ match_bits = mask_bits << (16 - high_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 8) | src[1];
+ else
+ buff1 = (src[1] << 8) | src[0];
+ buff1 = (buff1 & match_bits) << (high_bit);
+
+ if (ready_bits < 8)
+ { /* add another bps bits to the buffer */
+ bytebuff = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ ready_bits -= 8;
+ /* shift in new bits */
+ buff2 = ((buff2 << 8) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ if (ready_bits > 0)
+ {
+ bytebuff = (buff2 >> 8);
+ *dst++ = bytebuff;
+ }
+
+ return (0);
+ } /* end reverseSamples16bits */
+
+static int
+reverseSamples24bits (uint16 spp, uint16 bps, uint32 width,
+ uint8 *ibuff, uint8 *obuff)
+ {
+ int ready_bits = 0;
+ uint32 col;
+ uint32 src_byte = 0, high_bit = 0;
+ uint32 bit_offset = 0;
+ uint32 match_bits = 0, mask_bits = 0;
+ uint32 buff1 = 0, buff2 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t sample;
+
+ if ((ibuff == NULL) || (obuff == NULL))
+ {
+ TIFFError("reverseSamples24bits","Invalid image or work buffer");
+ return (1);
+ }
+
+ ready_bits = 0;
+ mask_bits = (uint32)-1 >> (32 - bps);
+ dst = obuff;
+ for (col = width; col > 0; col--)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = (col - 1) * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ high_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ high_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ src = ibuff + src_byte;
+ match_bits = mask_bits << (32 - high_bit - bps);
+ if (little_endian)
+ buff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ else
+ buff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ buff1 = (buff1 & match_bits) << (high_bit);
+
+ if (ready_bits < 16)
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 16);
+ *dst++ = bytebuff2;
+ ready_bits -= 16;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 16) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+
+ /* catch any trailing bits at the end of the line */
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 24);
+ *dst++ = bytebuff1;
+
+ buff2 = (buff2 << 8);
+ bytebuff2 = bytebuff1;
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end reverseSamples24bits */
+
+
+static int
+reverseSamples32bits (uint16 spp, uint16 bps, uint32 width,
+ uint8 *ibuff, uint8 *obuff)
+ {
+ int ready_bits = 0, shift_width = 0;
+ int bytes_per_sample, bytes_per_pixel;
+ uint32 bit_offset;
+ uint32 src_byte = 0, high_bit = 0;
+ uint32 col;
+ uint32 longbuff1 = 0, longbuff2 = 0;
+ uint64 mask_bits = 0, match_bits = 0;
+ uint64 buff1 = 0, buff2 = 0, buff3 = 0;
+ uint8 bytebuff1 = 0, bytebuff2 = 0, bytebuff3 = 0, bytebuff4 = 0;
+ unsigned char *src;
+ unsigned char *dst;
+ tsample_t sample;
+
+ if ((ibuff == NULL) || (obuff == NULL))
+ {
+ TIFFError("reverseSamples32bits","Invalid image or work buffer");
+ return (1);
+ }
+
+ ready_bits = 0;
+ mask_bits = (uint64)-1 >> (64 - bps);
+ dst = obuff;
+
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ for (col = width; col > 0; col--)
+ {
+ /* Compute src byte(s) and bits within byte(s) */
+ bit_offset = (col - 1) * bps * spp;
+ for (sample = 0; sample < spp; sample++)
+ {
+ if (sample == 0)
+ {
+ src_byte = bit_offset / 8;
+ high_bit = bit_offset % 8;
+ }
+ else
+ {
+ src_byte = (bit_offset + (sample * bps)) / 8;
+ high_bit = (bit_offset + (sample * bps)) % 8;
+ }
+
+ src = ibuff + src_byte;
+ match_bits = mask_bits << (64 - high_bit - bps);
+ if (little_endian)
+ {
+ longbuff1 = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
+ longbuff2 = longbuff1;
+ }
+ else
+ {
+ longbuff1 = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
+ longbuff2 = longbuff1;
+ }
+ buff3 = ((uint64)longbuff1 << 32) | longbuff2;
+ buff1 = (buff3 & match_bits) << (high_bit);
+
+ if (ready_bits < 32)
+ { /* add another bps bits to the buffer */
+ bytebuff1 = bytebuff2 = bytebuff3 = bytebuff4 = 0;
+ buff2 = (buff2 | (buff1 >> ready_bits));
+ }
+ else /* If we have a full buffer's worth, write it out */
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ bytebuff2 = (buff2 >> 48);
+ *dst++ = bytebuff2;
+ bytebuff3 = (buff2 >> 40);
+ *dst++ = bytebuff3;
+ bytebuff4 = (buff2 >> 32);
+ *dst++ = bytebuff4;
+ ready_bits -= 32;
+
+ /* shift in new bits */
+ buff2 = ((buff2 << 32) | (buff1 >> ready_bits));
+ }
+ ready_bits += bps;
+ }
+ }
+ while (ready_bits > 0)
+ {
+ bytebuff1 = (buff2 >> 56);
+ *dst++ = bytebuff1;
+ buff2 = (buff2 << 8);
+ ready_bits -= 8;
+ }
+
+ return (0);
+ } /* end reverseSamples32bits */
+
+static int
+reverseSamplesBytes (uint16 spp, uint16 bps, uint32 width,
+ uint8 *src, uint8 *dst)
+ {
+ int i;
+ uint32 col, bytes_per_pixel, col_offset;
+ uint8 bytebuff1;
+ unsigned char swapbuff[32];
+
+ if ((src == NULL) || (dst == NULL))
+ {
+ TIFFError("reverseSamplesBytes","Invalid input or output buffer");
+ return (1);
+ }
+
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ switch (bps / 8)
+ {
+ case 8: /* Use memcpy for multiple bytes per sample data */
+ case 4:
+ case 3:
+ case 2: for (col = 0; col < (width / 2); col++)
+ {
+ col_offset = col * bytes_per_pixel;
+ _TIFFmemcpy (swapbuff, src + col_offset, bytes_per_pixel);
+ _TIFFmemcpy (src + col_offset, dst - col_offset - bytes_per_pixel, bytes_per_pixel);
+ _TIFFmemcpy (dst - col_offset - bytes_per_pixel, swapbuff, bytes_per_pixel);
+ }
+ break;
+ case 1: /* Use byte copy only for single byte per sample data */
+ for (col = 0; col < (width / 2); col++)
+ {
+ for (i = 0; i < spp; i++)
+ {
+ bytebuff1 = *src;
+ *src++ = *(dst - spp + i);
+ *(dst - spp + i) = bytebuff1;
+ }
+ dst -= spp;
+ }
+ break;
+ default: TIFFError("reverseSamplesBytes","Unsupported bit depth %d", bps);
+ return (1);
+ }
+ return (0);
+ } /* end reverseSamplesBytes */
+
+
+/* Mirror an image horizontally or vertically */
+static int
+mirrorImage(uint16 spp, uint16 bps, uint16 mirror, uint32 width, uint32 length, unsigned char *ibuff)
+ {
+ int shift_width;
+ uint32 bytes_per_pixel, bytes_per_sample;
+ uint32 row, rowsize, row_offset;
+ unsigned char *line_buff = NULL;
+ unsigned char *src;
+ unsigned char *dst;
+
+ src = ibuff;
+ rowsize = ((width * bps * spp) + 7) / 8;
+ switch (mirror)
+ {
+ case MIRROR_BOTH:
+ case MIRROR_VERT:
+ line_buff = (unsigned char *)_TIFFmalloc(rowsize);
+ if (line_buff == NULL)
+ {
+ TIFFError ("mirrorImage", "Unable to allocate mirror line buffer of %1u bytes", rowsize);
+ return (-1);
+ }
+
+ dst = ibuff + (rowsize * (length - 1));
+ for (row = 0; row < length / 2; row++)
+ {
+ _TIFFmemcpy(line_buff, src, rowsize);
+ _TIFFmemcpy(src, dst, rowsize);
+ _TIFFmemcpy(dst, line_buff, rowsize);
+ src += (rowsize);
+ dst -= (rowsize);
+ }
+ if (line_buff)
+ _TIFFfree(line_buff);
+ if (mirror == MIRROR_VERT)
+ break;
+ case MIRROR_HORIZ :
+ if ((bps % 8) == 0) /* byte alligned data */
+ {
+ for (row = 0; row < length; row++)
+ {
+ row_offset = row * rowsize;
+ src = ibuff + row_offset;
+ dst = ibuff + row_offset + rowsize;
+ if (reverseSamplesBytes(spp, bps, width, src, dst))
+ {
+ return (-1);
+ }
+ }
+ }
+ else
+ { /* non 8 bit per sample data */
+ if (!(line_buff = (unsigned char *)_TIFFmalloc(rowsize + 1)))
+ {
+ TIFFError("mirrorImage", "Unable to allocate mirror line buffer");
+ return (-1);
+ }
+ bytes_per_sample = (bps + 7) / 8;
+ bytes_per_pixel = ((bps * spp) + 7) / 8;
+ if (bytes_per_pixel < (bytes_per_sample + 1))
+ shift_width = bytes_per_pixel;
+ else
+ shift_width = bytes_per_sample + 1;
+
+ for (row = 0; row < length; row++)
+ {
+ row_offset = row * rowsize;
+ src = ibuff + row_offset;
+ _TIFFmemset (line_buff, '\0', rowsize);
+ switch (shift_width)
+ {
+ case 1: if (reverseSamples16bits(spp, bps, width, src, line_buff))
+ {
+ _TIFFfree(line_buff);
+ return (-1);
+ }
+ _TIFFmemcpy (src, line_buff, rowsize);
+ break;
+ case 2: if (reverseSamples24bits(spp, bps, width, src, line_buff))
+ {
+ _TIFFfree(line_buff);
+ return (-1);
+ }
+ _TIFFmemcpy (src, line_buff, rowsize);
+ break;
+ case 3:
+ case 4:
+ case 5: if (reverseSamples32bits(spp, bps, width, src, line_buff))
+ {
+ _TIFFfree(line_buff);
+ return (-1);
+ }
+ _TIFFmemcpy (src, line_buff, rowsize);
+ break;
+ default: TIFFError("mirrorImage","Unsupported bit depth %d", bps);
+ _TIFFfree(line_buff);
+ return (-1);
+ }
+ }
+ if (line_buff)
+ _TIFFfree(line_buff);
+ }
+ break;
+
+ default: TIFFError ("mirrorImage", "Invalid mirror axis %d", mirror);
+ return (-1);
+ break;
+ }
+
+ return (0);
+ }
+
+/* Invert the light and dark values for a bilevel or grayscale image */
+static int
+invertImage(uint16 photometric, uint16 spp, uint16 bps, uint32 width, uint32 length, unsigned char *work_buff)
+ {
+ uint32 row, col;
+ unsigned char bytebuff1, bytebuff2, bytebuff3, bytebuff4;
+ unsigned char *src;
+ uint16 *src_uint16;
+ uint32 *src_uint32;
+
+ if (spp != 1)
+ {
+ TIFFError("invertImage", "Image inversion not supported for more than one sample per pixel");
+ return (-1);
+ }
+
+ if (photometric != PHOTOMETRIC_MINISWHITE && photometric != PHOTOMETRIC_MINISBLACK)
+ {
+ TIFFError("invertImage", "Only black and white and grayscale images can be inverted");
+ return (-1);
+ }
+
+ src = work_buff;
+ if (src == NULL)
+ {
+ TIFFError ("invertImage", "Invalid crop buffer passed to invertImage");
+ return (-1);
+ }
+
+ switch (bps)
+ {
+ case 32: src_uint32 = (uint32 *)src;
+ for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ *src_uint32 = (uint32)0xFFFFFFFF - *src_uint32;
+ src_uint32++;
+ }
+ break;
+ case 16: src_uint16 = (uint16 *)src;
+ for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ *src_uint16 = (uint16)0xFFFF - *src_uint16;
+ src_uint16++;
+ }
+ break;
+ case 8: for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ *src = (uint8)255 - *src;
+ src++;
+ }
+ break;
+ case 4: for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ bytebuff1 = 16 - (uint8)(*src & 240 >> 4);
+ bytebuff2 = 16 - (*src & 15);
+ *src = bytebuff1 << 4 & bytebuff2;
+ src++;
+ }
+ break;
+ case 2: for (row = 0; row < length; row++)
+ for (col = 0; col < width; col++)
+ {
+ bytebuff1 = 4 - (uint8)(*src & 192 >> 6);
+ bytebuff2 = 4 - (uint8)(*src & 48 >> 4);
+ bytebuff3 = 4 - (uint8)(*src & 12 >> 2);
+ bytebuff4 = 4 - (uint8)(*src & 3);
+ *src = (bytebuff1 << 6) || (bytebuff2 << 4) || (bytebuff3 << 2) || bytebuff4;
+ src++;
+ }
+ break;
+ case 1: for (row = 0; row < length; row++)
+ for (col = 0; col < width; col += 8 /(spp * bps))
+ {
+ *src = ~(*src);
+ src++;
+ }
+ break;
+ default: TIFFError("invertImage", "Unsupported bit depth %d", bps);
+ return (-1);
+ }
+
+ return (0);
+ }
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffdither.c b/tiff/tools/tiffdither.c
new file mode 100644
index 0000000..dee2a02
--- /dev/null
+++ b/tiff/tools/tiffdither.c
@@ -0,0 +1,332 @@
+/* $Id: tiffdither.c,v 1.9.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+
+uint32 imagewidth;
+uint32 imagelength;
+int threshold = 128;
+
+static void usage(void);
+
+/*
+ * Floyd-Steinberg error propragation with threshold.
+ * This code is stolen from tiffmedian.
+ */
+static void
+fsdither(TIFF* in, TIFF* out)
+{
+ unsigned char *outline, *inputline, *inptr;
+ short *thisline, *nextline, *tmpptr;
+ register unsigned char *outptr;
+ register short *thisptr, *nextptr;
+ register uint32 i, j;
+ uint32 imax, jmax;
+ int lastline, lastpixel;
+ int bit;
+ tsize_t outlinesize;
+
+ imax = imagelength - 1;
+ jmax = imagewidth - 1;
+ inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ thisline = (short *)_TIFFmalloc(imagewidth * sizeof (short));
+ nextline = (short *)_TIFFmalloc(imagewidth * sizeof (short));
+ outlinesize = TIFFScanlineSize(out);
+ outline = (unsigned char *) _TIFFmalloc(outlinesize);
+
+ /*
+ * Get first line
+ */
+ if (TIFFReadScanline(in, inputline, 0, 0) <= 0)
+ return;
+ inptr = inputline;
+ nextptr = nextline;
+ for (j = 0; j < imagewidth; ++j)
+ *nextptr++ = *inptr++;
+ for (i = 1; i < imagelength; ++i) {
+ tmpptr = thisline;
+ thisline = nextline;
+ nextline = tmpptr;
+ lastline = (i == imax);
+ if (TIFFReadScanline(in, inputline, i, 0) <= 0)
+ break;
+ inptr = inputline;
+ nextptr = nextline;
+ for (j = 0; j < imagewidth; ++j)
+ *nextptr++ = *inptr++;
+ thisptr = thisline;
+ nextptr = nextline;
+ _TIFFmemset(outptr = outline, 0, outlinesize);
+ bit = 0x80;
+ for (j = 0; j < imagewidth; ++j) {
+ register int v;
+
+ lastpixel = (j == jmax);
+ v = *thisptr++;
+ if (v < 0)
+ v = 0;
+ else if (v > 255)
+ v = 255;
+ if (v > threshold) {
+ *outptr |= bit;
+ v -= 255;
+ }
+ bit >>= 1;
+ if (bit == 0) {
+ outptr++;
+ bit = 0x80;
+ }
+ if (!lastpixel)
+ thisptr[0] += v * 7 / 16;
+ if (!lastline) {
+ if (j != 0)
+ nextptr[-1] += v * 3 / 16;
+ *nextptr++ += v * 5 / 16;
+ if (!lastpixel)
+ nextptr[0] += v / 16;
+ }
+ }
+ if (TIFFWriteScanline(out, outline, i-1, 0) < 0)
+ break;
+ }
+ _TIFFfree(inputline);
+ _TIFFfree(thisline);
+ _TIFFfree(nextline);
+ _TIFFfree(outline);
+}
+
+static uint16 compression = COMPRESSION_PACKBITS;
+static uint16 predictor = 0;
+static uint32 group3options = 0;
+
+static void
+processG3Options(char* cp)
+{
+ if ((cp = strchr(cp, ':'))) {
+ do {
+ cp++;
+ if (strneq(cp, "1d", 2))
+ group3options &= ~GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "2d", 2))
+ group3options |= GROUP3OPT_2DENCODING;
+ else if (strneq(cp, "fill", 4))
+ group3options |= GROUP3OPT_FILLBITS;
+ else
+ usage();
+ } while ((cp = strchr(cp, ':')));
+ }
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "g3", 2)) {
+ processG3Options(opt);
+ compression = COMPRESSION_CCITTFAX3;
+ } else if (streq(opt, "g4"))
+ compression = COMPRESSION_CCITTFAX4;
+ else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *in, *out;
+ uint16 samplesperpixel, bitspersample = 1, shortv;
+ float floatv;
+ char thing[1024];
+ uint32 rowsperstrip = (uint32) -1;
+ int onestrip = 0;
+ uint16 fillorder = 0;
+ int c;
+ extern int optind;
+ extern char *optarg;
+
+ while ((c = getopt(argc, argv, "c:f:r:t:")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'f': /* fill order */
+ if (streq(optarg, "lsb2msb"))
+ fillorder = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ fillorder = FILLORDER_MSB2LSB;
+ else
+ usage();
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ onestrip = 0;
+ break;
+ case 't':
+ threshold = atoi(optarg);
+ if (threshold < 0)
+ threshold = 0;
+ else if (threshold > 255)
+ threshold = 255;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind < 2)
+ usage();
+ in = TIFFOpen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (samplesperpixel != 1) {
+ fprintf(stderr, "%s: Not a b&w image.\n", argv[0]);
+ return (-1);
+ }
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8) {
+ fprintf(stderr,
+ " %s: Sorry, only handle 8-bit samples.\n", argv[0]);
+ return (-1);
+ }
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-1);
+ CopyField(TIFFTAG_IMAGEWIDTH, imagewidth);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
+ TIFFSetField(out, TIFFTAG_IMAGELENGTH, imagelength-1);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 1);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 1);
+ TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ if (fillorder)
+ TIFFSetField(out, TIFFTAG_FILLORDER, fillorder);
+ else
+ CopyField(TIFFTAG_FILLORDER, shortv);
+ sprintf(thing, "Dithered B&W version of %s", argv[optind]);
+ TIFFSetField(out, TIFFTAG_IMAGEDESCRIPTION, thing);
+ CopyField(TIFFTAG_PHOTOMETRIC, shortv);
+ CopyField(TIFFTAG_ORIENTATION, shortv);
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ if (onestrip)
+ rowsperstrip = imagelength-1;
+ else
+ rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
+ switch (compression) {
+ case COMPRESSION_CCITTFAX3:
+ TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, group3options);
+ break;
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ fsdither(in, out);
+ TIFFClose(in);
+ TIFFClose(out);
+ return (0);
+}
+
+char* stuff[] = {
+"usage: tiffdither [options] input.tif output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+" -f lsb2msb force lsb-to-msb FillOrder for output",
+" -f msb2lsb force msb-to-lsb FillOrder for output",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c g3[:opts] compress output with CCITT Group 3 encoding",
+" -c g4 compress output with CCITT Group 4 encoding",
+" -c none use no compression algorithm on output",
+"",
+"Group 3 options:",
+" 1d use default CCITT Group 3 1D-encoding",
+" 2d use optional CCITT Group 3 2D-encoding",
+" fill byte-align EOL codes",
+"For example, -c g3:2d:fill to get G3-2D-encoded data with byte-aligned EOLs",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffdump.c b/tiff/tools/tiffdump.c
new file mode 100644
index 0000000..5161189
--- /dev/null
+++ b/tiff/tools/tiffdump.c
@@ -0,0 +1,785 @@
+/* $Id: tiffdump.c,v 1.13.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+char* appname;
+char* curfile;
+int swabflag;
+int bigendian;
+int typeshift[14]; /* data type shift counts */
+long typemask[14]; /* data type masks */
+uint32 maxitems = 24; /* maximum indirect data items to print */
+
+char* bytefmt = "%s%#02x"; /* BYTE */
+char* sbytefmt = "%s%d"; /* SBYTE */
+char* shortfmt = "%s%u"; /* SHORT */
+char* sshortfmt = "%s%d"; /* SSHORT */
+char* longfmt = "%s%lu"; /* LONG */
+char* slongfmt = "%s%ld"; /* SLONG */
+char* rationalfmt = "%s%g"; /* RATIONAL */
+char* srationalfmt = "%s%g"; /* SRATIONAL */
+char* floatfmt = "%s%g"; /* FLOAT */
+char* doublefmt = "%s%g"; /* DOUBLE */
+char* ifdfmt = "%s%#04x"; /* IFD offset */
+
+static void dump(int, off_t);
+extern int optind;
+extern char* optarg;
+
+void
+usage()
+{
+ fprintf(stderr, "usage: %s [-h] [-o offset] [-m maxitems] file.tif ...\n", appname);
+ exit(-1);
+}
+
+int
+main(int argc, char* argv[])
+{
+ int one = 1, fd;
+ int multiplefiles = (argc > 1);
+ int c;
+ uint32 diroff = (uint32) 0;
+ bigendian = (*(char *)&one == 0);
+
+ appname = argv[0];
+ while ((c = getopt(argc, argv, "m:o:h")) != -1) {
+ switch (c) {
+ case 'h': /* print values in hex */
+ shortfmt = "%s%#x";
+ sshortfmt = "%s%#x";
+ longfmt = "%s%#lx";
+ slongfmt = "%s%#lx";
+ break;
+ case 'o':
+ diroff = (uint32) strtoul(optarg, NULL, 0);
+ break;
+ case 'm':
+ maxitems = strtoul(optarg, NULL, 0);
+ break;
+ default:
+ usage();
+ }
+ }
+ if (optind >= argc)
+ usage();
+ for (; optind < argc; optind++) {
+ fd = open(argv[optind], O_RDONLY|O_BINARY, 0);
+ if (fd < 0) {
+ perror(argv[0]);
+ return (-1);
+ }
+ if (multiplefiles)
+ printf("%s:\n", argv[optind]);
+ curfile = argv[optind];
+ swabflag = 0;
+ dump(fd, diroff);
+ close(fd);
+ }
+ return (0);
+}
+
+static TIFFHeader hdr;
+
+#define ord(e) ((int)e)
+
+/*
+ * Initialize shift & mask tables and byte
+ * swapping state according to the file
+ * byte order.
+ */
+static void
+InitByteOrder(int magic)
+{
+ typemask[0] = 0;
+ typemask[ord(TIFF_BYTE)] = 0xff;
+ typemask[ord(TIFF_SBYTE)] = 0xff;
+ typemask[ord(TIFF_UNDEFINED)] = 0xff;
+ typemask[ord(TIFF_SHORT)] = 0xffff;
+ typemask[ord(TIFF_SSHORT)] = 0xffff;
+ typemask[ord(TIFF_LONG)] = 0xffffffff;
+ typemask[ord(TIFF_SLONG)] = 0xffffffff;
+ typemask[ord(TIFF_IFD)] = 0xffffffff;
+ typemask[ord(TIFF_RATIONAL)] = 0xffffffff;
+ typemask[ord(TIFF_SRATIONAL)] = 0xffffffff;
+ typemask[ord(TIFF_FLOAT)] = 0xffffffff;
+ typemask[ord(TIFF_DOUBLE)] = 0xffffffff;
+ typeshift[0] = 0;
+ typeshift[ord(TIFF_LONG)] = 0;
+ typeshift[ord(TIFF_SLONG)] = 0;
+ typeshift[ord(TIFF_IFD)] = 0;
+ typeshift[ord(TIFF_RATIONAL)] = 0;
+ typeshift[ord(TIFF_SRATIONAL)] = 0;
+ typeshift[ord(TIFF_FLOAT)] = 0;
+ typeshift[ord(TIFF_DOUBLE)] = 0;
+ if (magic == TIFF_BIGENDIAN || magic == MDI_BIGENDIAN) {
+ typeshift[ord(TIFF_BYTE)] = 24;
+ typeshift[ord(TIFF_SBYTE)] = 24;
+ typeshift[ord(TIFF_SHORT)] = 16;
+ typeshift[ord(TIFF_SSHORT)] = 16;
+ swabflag = !bigendian;
+ } else {
+ typeshift[ord(TIFF_BYTE)] = 0;
+ typeshift[ord(TIFF_SBYTE)] = 0;
+ typeshift[ord(TIFF_SHORT)] = 0;
+ typeshift[ord(TIFF_SSHORT)] = 0;
+ swabflag = bigendian;
+ }
+}
+
+static off_t ReadDirectory(int, unsigned, off_t);
+static void ReadError(char*);
+static void Error(const char*, ...);
+static void Fatal(const char*, ...);
+
+static void
+dump(int fd, off_t diroff)
+{
+ unsigned i;
+
+ lseek(fd, (off_t) 0, 0);
+ if (read(fd, (char*) &hdr, sizeof (hdr)) != sizeof (hdr))
+ ReadError("TIFF header");
+ /*
+ * Setup the byte order handling.
+ */
+ if (hdr.tiff_magic != TIFF_BIGENDIAN && hdr.tiff_magic != TIFF_LITTLEENDIAN &&
+#if HOST_BIGENDIAN
+ // MDI is sensitive to the host byte order, unlike TIFF
+ MDI_BIGENDIAN != hdr.tiff_magic )
+#else
+ MDI_LITTLEENDIAN != hdr.tiff_magic )
+#endif
+ Fatal("Not a TIFF or MDI file, bad magic number %u (%#x)",
+ hdr.tiff_magic, hdr.tiff_magic);
+ InitByteOrder(hdr.tiff_magic);
+ /*
+ * Swap header if required.
+ */
+ if (swabflag) {
+ TIFFSwabShort(&hdr.tiff_version);
+ TIFFSwabLong(&hdr.tiff_diroff);
+ }
+ /*
+ * Now check version (if needed, it's been byte-swapped).
+ * Note that this isn't actually a version number, it's a
+ * magic number that doesn't change (stupid).
+ */
+ if (hdr.tiff_version != TIFF_VERSION)
+ Fatal("Not a TIFF file, bad version number %u (%#x)",
+ hdr.tiff_version, hdr.tiff_version);
+ printf("Magic: %#x <%s-endian> Version: %#x\n",
+ hdr.tiff_magic,
+ hdr.tiff_magic == TIFF_BIGENDIAN ? "big" : "little",
+ hdr.tiff_version);
+ if (diroff == 0)
+ diroff = hdr.tiff_diroff;
+ for (i = 0; diroff != 0; i++) {
+ if (i > 0)
+ putchar('\n');
+ diroff = ReadDirectory(fd, i, diroff);
+ }
+}
+
+static int datawidth[] = {
+ 0, /* nothing */
+ 1, /* TIFF_BYTE */
+ 1, /* TIFF_ASCII */
+ 2, /* TIFF_SHORT */
+ 4, /* TIFF_LONG */
+ 8, /* TIFF_RATIONAL */
+ 1, /* TIFF_SBYTE */
+ 1, /* TIFF_UNDEFINED */
+ 2, /* TIFF_SSHORT */
+ 4, /* TIFF_SLONG */
+ 8, /* TIFF_SRATIONAL */
+ 4, /* TIFF_FLOAT */
+ 8, /* TIFF_DOUBLE */
+ 4 /* TIFF_IFD */
+};
+#define NWIDTHS (sizeof (datawidth) / sizeof (datawidth[0]))
+static int TIFFFetchData(int, TIFFDirEntry*, void*);
+static void PrintTag(FILE*, uint16);
+static void PrintType(FILE*, uint16);
+static void PrintData(FILE*, uint16, uint32, unsigned char*);
+static void PrintByte(FILE*, const char*, TIFFDirEntry*);
+static void PrintShort(FILE*, const char*, TIFFDirEntry*);
+static void PrintLong(FILE*, const char*, TIFFDirEntry*);
+
+/*
+ * Read the next TIFF directory from a file
+ * and convert it to the internal format.
+ * We read directories sequentially.
+ */
+static off_t
+ReadDirectory(int fd, unsigned ix, off_t off)
+{
+ register TIFFDirEntry *dp;
+ register unsigned int n;
+ TIFFDirEntry *dir = 0;
+ uint16 dircount;
+ int space;
+ uint32 nextdiroff = 0;
+
+ if (off == 0) /* no more directories */
+ goto done;
+ if (lseek(fd, (off_t) off, 0) != off) {
+ Fatal("Seek error accessing TIFF directory");
+ goto done;
+ }
+ if (read(fd, (char*) &dircount, sizeof (uint16)) != sizeof (uint16)) {
+ ReadError("directory count");
+ goto done;
+ }
+ if (swabflag)
+ TIFFSwabShort(&dircount);
+ dir = (TIFFDirEntry *)_TIFFmalloc(dircount * sizeof (TIFFDirEntry));
+ if (dir == NULL) {
+ Fatal("No space for TIFF directory");
+ goto done;
+ }
+ n = read(fd, (char*) dir, dircount*sizeof (*dp));
+ if (n != dircount*sizeof (*dp)) {
+ n /= sizeof (*dp);
+ Error(
+ "Could only read %u of %u entries in directory at offset %#lx",
+ n, dircount, (unsigned long) off);
+ dircount = n;
+ }
+ if (read(fd, (char*) &nextdiroff, sizeof (uint32)) != sizeof (uint32))
+ nextdiroff = 0;
+ if (swabflag)
+ TIFFSwabLong(&nextdiroff);
+ printf("Directory %u: offset %lu (%#lx) next %lu (%#lx)\n", ix,
+ (unsigned long)off, (unsigned long)off,
+ (unsigned long)nextdiroff, (unsigned long)nextdiroff);
+ for (dp = dir, n = dircount; n > 0; n--, dp++) {
+ if (swabflag) {
+ TIFFSwabArrayOfShort(&dp->tdir_tag, 2);
+ TIFFSwabArrayOfLong(&dp->tdir_count, 2);
+ }
+ PrintTag(stdout, dp->tdir_tag);
+ putchar(' ');
+ PrintType(stdout, dp->tdir_type);
+ putchar(' ');
+ printf("%lu<", (unsigned long) dp->tdir_count);
+ if (dp->tdir_type >= NWIDTHS) {
+ printf(">\n");
+ continue;
+ }
+ space = dp->tdir_count * datawidth[dp->tdir_type];
+ if (space <= 0) {
+ printf(">\n");
+ Error("Invalid count for tag %u", dp->tdir_tag);
+ continue;
+ }
+ if (space <= 4) {
+ switch (dp->tdir_type) {
+ case TIFF_FLOAT:
+ case TIFF_UNDEFINED:
+ case TIFF_ASCII: {
+ unsigned char data[4];
+ _TIFFmemcpy(data, &dp->tdir_offset, 4);
+ if (swabflag)
+ TIFFSwabLong((uint32*) data);
+ PrintData(stdout,
+ dp->tdir_type, dp->tdir_count, data);
+ break;
+ }
+ case TIFF_BYTE:
+ PrintByte(stdout, bytefmt, dp);
+ break;
+ case TIFF_SBYTE:
+ PrintByte(stdout, sbytefmt, dp);
+ break;
+ case TIFF_SHORT:
+ PrintShort(stdout, shortfmt, dp);
+ break;
+ case TIFF_SSHORT:
+ PrintShort(stdout, sshortfmt, dp);
+ break;
+ case TIFF_LONG:
+ PrintLong(stdout, longfmt, dp);
+ break;
+ case TIFF_SLONG:
+ PrintLong(stdout, slongfmt, dp);
+ break;
+ case TIFF_IFD:
+ PrintLong(stdout, ifdfmt, dp);
+ break;
+ }
+ } else {
+ unsigned char *data = (unsigned char *)_TIFFmalloc(space);
+ if (data) {
+ if (TIFFFetchData(fd, dp, data)) {
+ if (dp->tdir_count > maxitems) {
+ PrintData(stdout, dp->tdir_type,
+ maxitems, data);
+ printf(" ...");
+ } else
+ PrintData(stdout, dp->tdir_type,
+ dp->tdir_count, data);
+ }
+ _TIFFfree(data);
+ } else
+ Error("No space for data for tag %u",
+ dp->tdir_tag);
+ }
+ printf(">\n");
+ }
+done:
+ if (dir)
+ _TIFFfree((char *)dir);
+ return (nextdiroff);
+}
+
+static struct tagname {
+ uint16 tag;
+ char* name;
+} tagnames[] = {
+ { TIFFTAG_SUBFILETYPE, "SubFileType" },
+ { TIFFTAG_OSUBFILETYPE, "OldSubFileType" },
+ { TIFFTAG_IMAGEWIDTH, "ImageWidth" },
+ { TIFFTAG_IMAGELENGTH, "ImageLength" },
+ { TIFFTAG_BITSPERSAMPLE, "BitsPerSample" },
+ { TIFFTAG_COMPRESSION, "Compression" },
+ { TIFFTAG_PHOTOMETRIC, "Photometric" },
+ { TIFFTAG_THRESHHOLDING, "Threshholding" },
+ { TIFFTAG_CELLWIDTH, "CellWidth" },
+ { TIFFTAG_CELLLENGTH, "CellLength" },
+ { TIFFTAG_FILLORDER, "FillOrder" },
+ { TIFFTAG_DOCUMENTNAME, "DocumentName" },
+ { TIFFTAG_IMAGEDESCRIPTION, "ImageDescription" },
+ { TIFFTAG_MAKE, "Make" },
+ { TIFFTAG_MODEL, "Model" },
+ { TIFFTAG_STRIPOFFSETS, "StripOffsets" },
+ { TIFFTAG_ORIENTATION, "Orientation" },
+ { TIFFTAG_SAMPLESPERPIXEL, "SamplesPerPixel" },
+ { TIFFTAG_ROWSPERSTRIP, "RowsPerStrip" },
+ { TIFFTAG_STRIPBYTECOUNTS, "StripByteCounts" },
+ { TIFFTAG_MINSAMPLEVALUE, "MinSampleValue" },
+ { TIFFTAG_MAXSAMPLEVALUE, "MaxSampleValue" },
+ { TIFFTAG_XRESOLUTION, "XResolution" },
+ { TIFFTAG_YRESOLUTION, "YResolution" },
+ { TIFFTAG_PLANARCONFIG, "PlanarConfig" },
+ { TIFFTAG_PAGENAME, "PageName" },
+ { TIFFTAG_XPOSITION, "XPosition" },
+ { TIFFTAG_YPOSITION, "YPosition" },
+ { TIFFTAG_FREEOFFSETS, "FreeOffsets" },
+ { TIFFTAG_FREEBYTECOUNTS, "FreeByteCounts" },
+ { TIFFTAG_GRAYRESPONSEUNIT, "GrayResponseUnit" },
+ { TIFFTAG_GRAYRESPONSECURVE,"GrayResponseCurve" },
+ { TIFFTAG_GROUP3OPTIONS, "Group3Options" },
+ { TIFFTAG_GROUP4OPTIONS, "Group4Options" },
+ { TIFFTAG_RESOLUTIONUNIT, "ResolutionUnit" },
+ { TIFFTAG_PAGENUMBER, "PageNumber" },
+ { TIFFTAG_COLORRESPONSEUNIT,"ColorResponseUnit" },
+ { TIFFTAG_TRANSFERFUNCTION, "TransferFunction" },
+ { TIFFTAG_SOFTWARE, "Software" },
+ { TIFFTAG_DATETIME, "DateTime" },
+ { TIFFTAG_ARTIST, "Artist" },
+ { TIFFTAG_HOSTCOMPUTER, "HostComputer" },
+ { TIFFTAG_PREDICTOR, "Predictor" },
+ { TIFFTAG_WHITEPOINT, "Whitepoint" },
+ { TIFFTAG_PRIMARYCHROMATICITIES,"PrimaryChromaticities" },
+ { TIFFTAG_COLORMAP, "Colormap" },
+ { TIFFTAG_HALFTONEHINTS, "HalftoneHints" },
+ { TIFFTAG_TILEWIDTH, "TileWidth" },
+ { TIFFTAG_TILELENGTH, "TileLength" },
+ { TIFFTAG_TILEOFFSETS, "TileOffsets" },
+ { TIFFTAG_TILEBYTECOUNTS, "TileByteCounts" },
+ { TIFFTAG_BADFAXLINES, "BadFaxLines" },
+ { TIFFTAG_CLEANFAXDATA, "CleanFaxData" },
+ { TIFFTAG_CONSECUTIVEBADFAXLINES, "ConsecutiveBadFaxLines" },
+ { TIFFTAG_SUBIFD, "SubIFD" },
+ { TIFFTAG_INKSET, "InkSet" },
+ { TIFFTAG_INKNAMES, "InkNames" },
+ { TIFFTAG_NUMBEROFINKS, "NumberOfInks" },
+ { TIFFTAG_DOTRANGE, "DotRange" },
+ { TIFFTAG_TARGETPRINTER, "TargetPrinter" },
+ { TIFFTAG_EXTRASAMPLES, "ExtraSamples" },
+ { TIFFTAG_SAMPLEFORMAT, "SampleFormat" },
+ { TIFFTAG_SMINSAMPLEVALUE, "SMinSampleValue" },
+ { TIFFTAG_SMAXSAMPLEVALUE, "SMaxSampleValue" },
+ { TIFFTAG_JPEGPROC, "JPEGProcessingMode" },
+ { TIFFTAG_JPEGIFOFFSET, "JPEGInterchangeFormat" },
+ { TIFFTAG_JPEGIFBYTECOUNT, "JPEGInterchangeFormatLength" },
+ { TIFFTAG_JPEGRESTARTINTERVAL,"JPEGRestartInterval" },
+ { TIFFTAG_JPEGLOSSLESSPREDICTORS,"JPEGLosslessPredictors" },
+ { TIFFTAG_JPEGPOINTTRANSFORM,"JPEGPointTransform" },
+ { TIFFTAG_JPEGTABLES, "JPEGTables" },
+ { TIFFTAG_JPEGQTABLES, "JPEGQTables" },
+ { TIFFTAG_JPEGDCTABLES, "JPEGDCTables" },
+ { TIFFTAG_JPEGACTABLES, "JPEGACTables" },
+ { TIFFTAG_YCBCRCOEFFICIENTS,"YCbCrCoefficients" },
+ { TIFFTAG_YCBCRSUBSAMPLING, "YCbCrSubsampling" },
+ { TIFFTAG_YCBCRPOSITIONING, "YCbCrPositioning" },
+ { TIFFTAG_REFERENCEBLACKWHITE, "ReferenceBlackWhite" },
+ { TIFFTAG_REFPTS, "IgReferencePoints (Island Graphics)" },
+ { TIFFTAG_REGIONTACKPOINT, "IgRegionTackPoint (Island Graphics)" },
+ { TIFFTAG_REGIONWARPCORNERS,"IgRegionWarpCorners (Island Graphics)" },
+ { TIFFTAG_REGIONAFFINE, "IgRegionAffine (Island Graphics)" },
+ { TIFFTAG_MATTEING, "OBSOLETE Matteing (Silicon Graphics)" },
+ { TIFFTAG_DATATYPE, "OBSOLETE DataType (Silicon Graphics)" },
+ { TIFFTAG_IMAGEDEPTH, "ImageDepth (Silicon Graphics)" },
+ { TIFFTAG_TILEDEPTH, "TileDepth (Silicon Graphics)" },
+ { 32768, "OLD BOGUS Matteing tag" },
+ { TIFFTAG_COPYRIGHT, "Copyright" },
+ { TIFFTAG_ICCPROFILE, "ICC Profile" },
+ { TIFFTAG_JBIGOPTIONS, "JBIG Options" },
+ { TIFFTAG_STONITS, "StoNits" },
+};
+#define NTAGS (sizeof (tagnames) / sizeof (tagnames[0]))
+
+static void
+PrintTag(FILE* fd, uint16 tag)
+{
+ register struct tagname *tp;
+
+ for (tp = tagnames; tp < &tagnames[NTAGS]; tp++)
+ if (tp->tag == tag) {
+ fprintf(fd, "%s (%u)", tp->name, tag);
+ return;
+ }
+ fprintf(fd, "%u (%#x)", tag, tag);
+}
+
+static void
+PrintType(FILE* fd, uint16 type)
+{
+ static char *typenames[] = {
+ "0",
+ "BYTE",
+ "ASCII",
+ "SHORT",
+ "LONG",
+ "RATIONAL",
+ "SBYTE",
+ "UNDEFINED",
+ "SSHORT",
+ "SLONG",
+ "SRATIONAL",
+ "FLOAT",
+ "DOUBLE"
+ };
+#define NTYPES (sizeof (typenames) / sizeof (typenames[0]))
+
+ if (type < NTYPES)
+ fprintf(fd, "%s (%u)", typenames[type], type);
+ else
+ fprintf(fd, "%u (%#x)", type, type);
+}
+#undef NTYPES
+
+static void
+PrintByte(FILE* fd, const char* fmt, TIFFDirEntry* dp)
+{
+ char* sep = "";
+
+ if (hdr.tiff_magic == TIFF_BIGENDIAN) {
+ switch ((int)dp->tdir_count) {
+ case 4: fprintf(fd, fmt, sep, dp->tdir_offset&0xff);
+ sep = " ";
+ case 3: fprintf(fd, fmt, sep, (dp->tdir_offset>>8)&0xff);
+ sep = " ";
+ case 2: fprintf(fd, fmt, sep, (dp->tdir_offset>>16)&0xff);
+ sep = " ";
+ case 1: fprintf(fd, fmt, sep, dp->tdir_offset>>24);
+ }
+ } else {
+ switch ((int)dp->tdir_count) {
+ case 4: fprintf(fd, fmt, sep, dp->tdir_offset>>24);
+ sep = " ";
+ case 3: fprintf(fd, fmt, sep, (dp->tdir_offset>>16)&0xff);
+ sep = " ";
+ case 2: fprintf(fd, fmt, sep, (dp->tdir_offset>>8)&0xff);
+ sep = " ";
+ case 1: fprintf(fd, fmt, sep, dp->tdir_offset&0xff);
+ }
+ }
+}
+
+static void
+PrintShort(FILE* fd, const char* fmt, TIFFDirEntry* dp)
+{
+ char *sep = "";
+
+ if (hdr.tiff_magic == TIFF_BIGENDIAN) {
+ switch (dp->tdir_count) {
+ case 2: fprintf(fd, fmt, sep, dp->tdir_offset&0xffff);
+ sep = " ";
+ case 1: fprintf(fd, fmt, sep, dp->tdir_offset>>16);
+ }
+ } else {
+ switch (dp->tdir_count) {
+ case 2: fprintf(fd, fmt, sep, dp->tdir_offset>>16);
+ sep = " ";
+ case 1: fprintf(fd, fmt, sep, dp->tdir_offset&0xffff);
+ }
+ }
+}
+
+static void
+PrintLong(FILE* fd, const char* fmt, TIFFDirEntry* dp)
+{
+ fprintf(fd, fmt, "", (long) dp->tdir_offset);
+}
+
+#include <ctype.h>
+
+static void
+PrintASCII(FILE* fd, uint32 cc, const unsigned char* cp)
+{
+ for (; cc > 0; cc--, cp++) {
+ const char* tp;
+
+ if (isprint(*cp)) {
+ fputc(*cp, fd);
+ continue;
+ }
+ for (tp = "\tt\bb\rr\nn\vv"; *tp; tp++)
+ if (*tp++ == *cp)
+ break;
+ if (*tp)
+ fprintf(fd, "\\%c", *tp);
+ else if (*cp)
+ fprintf(fd, "\\%03o", *cp);
+ else
+ fprintf(fd, "\\0");
+ }
+}
+
+static void
+PrintData(FILE* fd, uint16 type, uint32 count, unsigned char* data)
+{
+ char* sep = "";
+
+ switch (type) {
+ case TIFF_BYTE:
+ while (count-- > 0)
+ fprintf(fd, bytefmt, sep, *data++), sep = " ";
+ break;
+ case TIFF_SBYTE:
+ while (count-- > 0)
+ fprintf(fd, sbytefmt, sep, *(char *)data++), sep = " ";
+ break;
+ case TIFF_UNDEFINED:
+ while (count-- > 0)
+ fprintf(fd, bytefmt, sep, *data++), sep = " ";
+ break;
+ case TIFF_ASCII:
+ PrintASCII(fd, count, data);
+ break;
+ case TIFF_SHORT: {
+ uint16 *wp = (uint16*)data;
+ while (count-- > 0)
+ fprintf(fd, shortfmt, sep, *wp++), sep = " ";
+ break;
+ }
+ case TIFF_SSHORT: {
+ int16 *wp = (int16*)data;
+ while (count-- > 0)
+ fprintf(fd, sshortfmt, sep, *wp++), sep = " ";
+ break;
+ }
+ case TIFF_LONG: {
+ uint32 *lp = (uint32*)data;
+ while (count-- > 0) {
+ fprintf(fd, longfmt, sep, (unsigned long) *lp++);
+ sep = " ";
+ }
+ break;
+ }
+ case TIFF_SLONG: {
+ int32 *lp = (int32*)data;
+ while (count-- > 0)
+ fprintf(fd, slongfmt, sep, (long) *lp++), sep = " ";
+ break;
+ }
+ case TIFF_RATIONAL: {
+ uint32 *lp = (uint32*)data;
+ while (count-- > 0) {
+ if (lp[1] == 0)
+ fprintf(fd, "%sNan (%lu/%lu)", sep,
+ (unsigned long) lp[0],
+ (unsigned long) lp[1]);
+ else
+ fprintf(fd, rationalfmt, sep,
+ (double)lp[0] / (double)lp[1]);
+ sep = " ";
+ lp += 2;
+ }
+ break;
+ }
+ case TIFF_SRATIONAL: {
+ int32 *lp = (int32*)data;
+ while (count-- > 0) {
+ if (lp[1] == 0)
+ fprintf(fd, "%sNan (%ld/%ld)", sep,
+ (long) lp[0], (long) lp[1]);
+ else
+ fprintf(fd, srationalfmt, sep,
+ (double)lp[0] / (double)lp[1]);
+ sep = " ";
+ lp += 2;
+ }
+ break;
+ }
+ case TIFF_FLOAT: {
+ float *fp = (float *)data;
+ while (count-- > 0)
+ fprintf(fd, floatfmt, sep, *fp++), sep = " ";
+ break;
+ }
+ case TIFF_DOUBLE: {
+ double *dp = (double *)data;
+ while (count-- > 0)
+ fprintf(fd, doublefmt, sep, *dp++), sep = " ";
+ break;
+ }
+ case TIFF_IFD: {
+ uint32 *lp = (uint32*)data;
+ while (count-- > 0) {
+ fprintf(fd, ifdfmt, sep, (unsigned long) *lp++);
+ sep = " ";
+ }
+ break;
+ }
+ }
+}
+
+/*
+ * Fetch a contiguous directory item.
+ */
+static int
+TIFFFetchData(int fd, TIFFDirEntry* dir, void* cp)
+{
+ int cc, w;
+
+ w = (dir->tdir_type < NWIDTHS ? datawidth[dir->tdir_type] : 0);
+ cc = dir->tdir_count * w;
+ if (lseek(fd, (off_t)dir->tdir_offset, 0) != (off_t)-1
+ && read(fd, cp, cc) != -1) {
+ if (swabflag) {
+ switch (dir->tdir_type) {
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ TIFFSwabArrayOfShort((uint16*) cp,
+ dir->tdir_count);
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ case TIFF_IFD:
+ TIFFSwabArrayOfLong((uint32*) cp,
+ dir->tdir_count);
+ break;
+ case TIFF_RATIONAL:
+ TIFFSwabArrayOfLong((uint32*) cp,
+ 2*dir->tdir_count);
+ break;
+ case TIFF_DOUBLE:
+ TIFFSwabArrayOfDouble((double*) cp,
+ dir->tdir_count);
+ break;
+ }
+ }
+ return (cc);
+ }
+ Error("Error while reading data for tag %u", dir->tdir_tag);
+ return (0);
+}
+
+static void
+ReadError(char* what)
+{
+ Fatal("Error while reading %s", what);
+}
+
+#include <stdarg.h>
+
+static void
+vError(FILE* fd, const char* fmt, va_list ap)
+{
+ fprintf(fd, "%s: ", curfile);
+ vfprintf(fd, fmt, ap);
+ fprintf(fd, ".\n");
+}
+
+static void
+Error(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vError(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static void
+Fatal(const char* fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vError(stderr, fmt, ap);
+ va_end(ap);
+ exit(-1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffgt.c b/tiff/tools/tiffgt.c
new file mode 100644
index 0000000..ea9c3b1
--- /dev/null
+++ b/tiff/tools/tiffgt.c
@@ -0,0 +1,462 @@
+/* $Id: tiffgt.c,v 1.7.2.2 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ * Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if HAVE_APPLE_OPENGL_FRAMEWORK
+# include <OpenGL/gl.h>
+# include <GLUT/glut.h>
+#else
+# include <GL/gl.h>
+# include <GL/glut.h>
+#endif
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+static uint32 width = 0, height = 0; /* window width & height */
+static uint32* raster = NULL; /* displayable image */
+static TIFFRGBAImage img;
+static int order0 = 0, order;
+static uint16 photo0 = (uint16) -1, photo;
+static int stoponerr = 0; /* stop on read error */
+static int verbose = 0;
+#define TITLE_LENGTH 1024
+static char title[TITLE_LENGTH]; /* window title line */
+static uint32 xmax, ymax;
+static char** filelist = NULL;
+static int fileindex;
+static int filenum;
+static TIFFErrorHandler oerror;
+static TIFFErrorHandler owarning;
+
+static void cleanup_and_exit(void);
+static int initImage(void);
+static int prevImage(void);
+static int nextImage(void);
+static void setWindowSize(void);
+static void usage(void);
+static uint16 photoArg(const char*);
+static void raster_draw(void);
+static void raster_reshape(int, int);
+static void raster_keys(unsigned char, int, int);
+static void raster_special(int, int, int);
+
+extern char* optarg;
+extern int optind;
+static TIFF* tif = NULL;
+
+int
+main(int argc, char* argv[])
+{
+ int c;
+ int dirnum = -1;
+ uint32 diroff = 0;
+
+ oerror = TIFFSetErrorHandler(NULL);
+ owarning = TIFFSetWarningHandler(NULL);
+ while ((c = getopt(argc, argv, "d:o:p:eflmsvw?")) != -1)
+ switch (c) {
+ case 'd':
+ dirnum = atoi(optarg);
+ break;
+ case 'e':
+ oerror = TIFFSetErrorHandler(oerror);
+ break;
+ case 'l':
+ order0 = FILLORDER_LSB2MSB;
+ break;
+ case 'm':
+ order0 = FILLORDER_MSB2LSB;
+ break;
+ case 'o':
+ diroff = strtoul(optarg, NULL, 0);
+ break;
+ case 'p':
+ photo0 = photoArg(optarg);
+ break;
+ case 's':
+ stoponerr = 1;
+ break;
+ case 'w':
+ owarning = TIFFSetWarningHandler(owarning);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ filenum = argc - optind;
+ if ( filenum < 1)
+ usage();
+
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
+
+ /*
+ * Get the screen size
+ */
+ xmax = glutGet(GLUT_SCREEN_WIDTH);
+ ymax = glutGet(GLUT_SCREEN_HEIGHT);
+
+ /*
+ * Use 90% of the screen size
+ */
+ xmax = xmax - xmax / 10.0;
+ ymax = ymax - ymax / 10.0;
+
+ filelist = (char **) _TIFFmalloc(filenum * sizeof(char*));
+ if (!filelist) {
+ TIFFError(argv[0], "Can not allocate space for the file list.");
+ return 1;
+ }
+ _TIFFmemcpy(filelist, argv + optind, filenum * sizeof(char*));
+ fileindex = -1;
+ if (nextImage() < 0) {
+ _TIFFfree(filelist);
+ return 2;
+ }
+ /*
+ * Set initial directory if user-specified
+ * file was opened successfully.
+ */
+ if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum))
+ TIFFError(argv[0], "Error, seeking to directory %d", dirnum);
+ if (diroff != 0 && !TIFFSetSubDirectory(tif, diroff))
+ TIFFError(argv[0], "Error, setting subdirectory at %#x", diroff);
+ order = order0;
+ photo = photo0;
+ if (initImage() < 0){
+ _TIFFfree(filelist);
+ return 3;
+ }
+ /*
+ * Create a new window or reconfigure an existing
+ * one to suit the image to be displayed.
+ */
+ glutInitWindowSize(width, height);
+ snprintf(title, TITLE_LENGTH - 1, "%s [%u]", filelist[fileindex],
+ (unsigned int) TIFFCurrentDirectory(tif));
+ glutCreateWindow(title);
+ glutDisplayFunc(raster_draw);
+ glutReshapeFunc(raster_reshape);
+ glutKeyboardFunc(raster_keys);
+ glutSpecialFunc(raster_special);
+ glutMainLoop();
+
+ cleanup_and_exit();
+ return 0;
+}
+
+static void
+cleanup_and_exit(void)
+{
+ TIFFRGBAImageEnd(&img);
+ if (filelist != NULL)
+ _TIFFfree(filelist);
+ if (raster != NULL)
+ _TIFFfree(raster);
+ if (tif != NULL)
+ TIFFClose(tif);
+ exit(0);
+}
+
+static int
+initImage(void)
+{
+ uint32 w, h;
+
+ if (order)
+ TIFFSetField(tif, TIFFTAG_FILLORDER, order);
+ if (photo != (uint16) -1)
+ TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photo);
+ if (!TIFFRGBAImageBegin(&img, tif, stoponerr, title)) {
+ TIFFError(filelist[fileindex], "%s", title);
+ TIFFClose(tif);
+ tif = NULL;
+ return -1;
+ }
+
+ /*
+ * Setup the image raster as required.
+ */
+ h = img.height;
+ w = img.width;
+ if (h > ymax) {
+ w = (int)(w * ((float)ymax / h));
+ h = ymax;
+ }
+ if (w > xmax) {
+ h = (int)(h * ((float)xmax / w));
+ w = xmax;
+ }
+
+ if (w != width || h != height) {
+ if (raster != NULL)
+ _TIFFfree(raster), raster = NULL;
+ raster = (uint32*) _TIFFmalloc(img.width * img.height * sizeof (uint32));
+ if (raster == NULL) {
+ width = height = 0;
+ TIFFError(filelist[fileindex], "No space for raster buffer");
+ cleanup_and_exit();
+ }
+ width = w;
+ height = h;
+ }
+ TIFFRGBAImageGet(&img, raster, img.width, img.height);
+#if HOST_BIGENDIAN
+ TIFFSwabArrayOfLong(raster,img.width*img.height);
+#endif
+ return 0;
+}
+
+static int
+prevImage(void)
+{
+ if (fileindex > 0)
+ fileindex--;
+ else if (tif)
+ return fileindex;
+ if (tif)
+ TIFFClose(tif);
+ tif = TIFFOpen(filelist[fileindex], "r");
+ if (tif == NULL)
+ return -1;
+ return fileindex;
+}
+
+static int
+nextImage(void)
+{
+ if (fileindex < filenum - 1)
+ fileindex++;
+ else if (tif)
+ return fileindex;
+ if (tif)
+ TIFFClose(tif);
+ tif = TIFFOpen(filelist[fileindex], "r");
+ if (tif == NULL)
+ return -1;
+ return fileindex;
+}
+
+static void
+setWindowSize(void)
+{
+ glutReshapeWindow(width, height);
+}
+
+static void
+raster_draw(void)
+{
+ glDrawPixels(img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *) raster);
+}
+
+static void
+raster_reshape(int win_w, int win_h)
+{
+ GLfloat xratio = (GLfloat)win_w/img.width;
+ GLfloat yratio = (GLfloat)win_h/img.height;
+ int ratio = (int)(((xratio > yratio)?xratio:yratio) * 100);
+
+ glPixelZoom(xratio, yratio);
+ glViewport(0, 0, win_w, win_h);
+ snprintf(title, 1024, "%s [%u] %d%%", filelist[fileindex],
+ (unsigned int) TIFFCurrentDirectory(tif), ratio);
+ glutSetWindowTitle(title);
+}
+
+static void
+raster_keys(unsigned char key, int x, int y)
+{
+ switch (key) {
+ case 'b': /* photometric MinIsBlack */
+ photo = PHOTOMETRIC_MINISBLACK;
+ initImage();
+ break;
+ case 'l': /* lsb-to-msb FillOrder */
+ order = FILLORDER_LSB2MSB;
+ initImage();
+ break;
+ case 'm': /* msb-to-lsb FillOrder */
+ order = FILLORDER_MSB2LSB;
+ initImage();
+ break;
+ case 'w': /* photometric MinIsWhite */
+ photo = PHOTOMETRIC_MINISWHITE;
+ initImage();
+ break;
+ case 'W': /* toggle warnings */
+ owarning = TIFFSetWarningHandler(owarning);
+ initImage();
+ break;
+ case 'E': /* toggle errors */
+ oerror = TIFFSetErrorHandler(oerror);
+ initImage();
+ break;
+ case 'z': /* reset to defaults */
+ case 'Z':
+ order = order0;
+ photo = photo0;
+ if (owarning == NULL)
+ owarning = TIFFSetWarningHandler(NULL);
+ if (oerror == NULL)
+ oerror = TIFFSetErrorHandler(NULL);
+ initImage();
+ break;
+ case 'q': /* exit */
+ case '\033':
+ cleanup_and_exit();
+ }
+ glutPostRedisplay();
+}
+
+static void
+raster_special(int key, int x, int y)
+{
+ switch (key) {
+ case GLUT_KEY_PAGE_UP: /* previous logical image */
+ if (TIFFCurrentDirectory(tif) > 0) {
+ if (TIFFSetDirectory(tif,
+ TIFFCurrentDirectory(tif)-1)) {
+ initImage();
+ setWindowSize();
+ }
+ } else {
+ TIFFRGBAImageEnd(&img);
+ prevImage();
+ initImage();
+ setWindowSize();
+ }
+ break;
+ case GLUT_KEY_PAGE_DOWN: /* next logical image */
+ if (!TIFFLastDirectory(tif)) {
+ if (TIFFReadDirectory(tif)) {
+ initImage();
+ setWindowSize();
+ }
+ } else {
+ TIFFRGBAImageEnd(&img);
+ nextImage();
+ initImage();
+ setWindowSize();
+ }
+ break;
+ case GLUT_KEY_HOME: /* 1st image in current file */
+ if (TIFFSetDirectory(tif, 0)) {
+ TIFFRGBAImageEnd(&img);
+ initImage();
+ setWindowSize();
+ }
+ break;
+ case GLUT_KEY_END: /* last image in current file */
+ TIFFRGBAImageEnd(&img);
+ while (!TIFFLastDirectory(tif))
+ TIFFReadDirectory(tif);
+ initImage();
+ setWindowSize();
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+
+char* stuff[] = {
+"usage: tiffgt [options] file.tif",
+"where options are:",
+" -c use colormap visual",
+" -d dirnum set initial directory (default is 0)",
+" -e enable display of TIFF error messages",
+" -l force lsb-to-msb FillOrder",
+" -m force msb-to-lsb FillOrder",
+" -o offset set initial directory offset",
+" -p photo override photometric interpretation",
+" -r use fullcolor visual",
+" -s stop decoding on first error (default is ignore errors)",
+" -v enable verbose mode",
+" -w enable display of TIFF warning messages",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+static uint16
+photoArg(const char* arg)
+{
+ if (strcmp(arg, "miniswhite") == 0)
+ return (PHOTOMETRIC_MINISWHITE);
+ else if (strcmp(arg, "minisblack") == 0)
+ return (PHOTOMETRIC_MINISBLACK);
+ else if (strcmp(arg, "rgb") == 0)
+ return (PHOTOMETRIC_RGB);
+ else if (strcmp(arg, "palette") == 0)
+ return (PHOTOMETRIC_PALETTE);
+ else if (strcmp(arg, "mask") == 0)
+ return (PHOTOMETRIC_MASK);
+ else if (strcmp(arg, "separated") == 0)
+ return (PHOTOMETRIC_SEPARATED);
+ else if (strcmp(arg, "ycbcr") == 0)
+ return (PHOTOMETRIC_YCBCR);
+ else if (strcmp(arg, "cielab") == 0)
+ return (PHOTOMETRIC_CIELAB);
+ else if (strcmp(arg, "logl") == 0)
+ return (PHOTOMETRIC_LOGL);
+ else if (strcmp(arg, "logluv") == 0)
+ return (PHOTOMETRIC_LOGLUV);
+ else
+ return ((uint16) -1);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffinfo.c b/tiff/tools/tiffinfo.c
new file mode 100644
index 0000000..4d4ae64
--- /dev/null
+++ b/tiff/tools/tiffinfo.c
@@ -0,0 +1,456 @@
+/* $Id: tiffinfo.c,v 1.8.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1988-1997 Sam Leffler
+ * Copyright (c) 1991-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define streq(a,b) (strcasecmp(a,b) == 0)
+
+int showdata = 0; /* show data */
+int rawdata = 0; /* show raw/decoded data */
+int showwords = 0; /* show data as bytes/words */
+int readdata = 0; /* read data in file */
+int stoponerr = 1; /* stop on first read error */
+
+static void usage(void);
+static void tiffinfo(TIFF*, uint16, long);
+
+int
+main(int argc, char* argv[])
+{
+ int dirnum = -1, multiplefiles, c;
+ uint16 order = 0;
+ TIFF* tif;
+ extern int optind;
+ extern char* optarg;
+ long flags = 0;
+ uint32 diroff = 0;
+ int chopstrips = 0; /* disable strip chopping */
+
+ while ((c = getopt(argc, argv, "f:o:cdDSjilmrsvwz0123456789")) != -1)
+ switch (c) {
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ case '8': case '9':
+ dirnum = atoi(&argv[optind-1][1]);
+ break;
+ case 'd':
+ showdata++;
+ /* fall thru... */
+ case 'D':
+ readdata++;
+ break;
+ case 'c':
+ flags |= TIFFPRINT_COLORMAP | TIFFPRINT_CURVES;
+ break;
+ case 'f': /* fill order */
+ if (streq(optarg, "lsb2msb"))
+ order = FILLORDER_LSB2MSB;
+ else if (streq(optarg, "msb2lsb"))
+ order = FILLORDER_MSB2LSB;
+ else
+ usage();
+ break;
+ case 'i':
+ stoponerr = 0;
+ break;
+ case 'o':
+ diroff = strtoul(optarg, NULL, 0);
+ break;
+ case 'j':
+ flags |= TIFFPRINT_JPEGQTABLES |
+ TIFFPRINT_JPEGACTABLES |
+ TIFFPRINT_JPEGDCTABLES;
+ break;
+ case 'r':
+ rawdata = 1;
+ break;
+ case 's':
+ flags |= TIFFPRINT_STRIPS;
+ break;
+ case 'w':
+ showwords = 1;
+ break;
+ case 'z':
+ chopstrips = 1;
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (optind >= argc)
+ usage();
+ multiplefiles = (argc - optind > 1);
+ for (; optind < argc; optind++) {
+ if (multiplefiles)
+ printf("%s:\n", argv[optind]);
+ tif = TIFFOpen(argv[optind], chopstrips ? "rC" : "rc");
+ if (tif != NULL) {
+ if (dirnum != -1) {
+ if (TIFFSetDirectory(tif, (tdir_t) dirnum))
+ tiffinfo(tif, order, flags);
+ } else if (diroff != 0) {
+ if (TIFFSetSubDirectory(tif, diroff))
+ tiffinfo(tif, order, flags);
+ } else {
+ do {
+ uint32 offset;
+
+ tiffinfo(tif, order, flags);
+ if (TIFFGetField(tif, TIFFTAG_EXIFIFD,
+ &offset)) {
+ if (TIFFReadEXIFDirectory(tif, offset))
+ tiffinfo(tif, order, flags);
+ }
+ } while (TIFFReadDirectory(tif));
+ }
+ TIFFClose(tif);
+ }
+ }
+ return (0);
+}
+
+char* stuff[] = {
+"usage: tiffinfo [options] input...",
+"where options are:",
+" -D read data",
+" -i ignore read errors",
+" -c display data for grey/color response curve or colormap",
+" -d display raw/decoded image data",
+" -f lsb2msb force lsb-to-msb FillOrder for input",
+" -f msb2lsb force msb-to-lsb FillOrder for input",
+" -j show JPEG tables",
+" -o offset set initial directory offset",
+" -r read/display raw image data instead of decoded data",
+" -s display strip offsets and byte counts",
+" -w display raw data in words rather than bytes",
+" -z enable strip chopping",
+" -# set initial directory (first directory is # 0)",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+static void
+ShowStrip(tstrip_t strip, unsigned char* pp, uint32 nrow, tsize_t scanline)
+{
+ register tsize_t cc;
+
+ printf("Strip %lu:\n", (unsigned long) strip);
+ while (nrow-- > 0) {
+ for (cc = 0; cc < scanline; cc++) {
+ printf(" %02x", *pp++);
+ if (((cc+1) % 24) == 0)
+ putchar('\n');
+ }
+ putchar('\n');
+ }
+}
+
+void
+TIFFReadContigStripData(TIFF* tif)
+{
+ unsigned char *buf;
+ tsize_t scanline = TIFFScanlineSize(tif);
+
+ buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
+ if (buf) {
+ uint32 row, h;
+ uint32 rowsperstrip = (uint32)-1;
+
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ for (row = 0; row < h; row += rowsperstrip) {
+ uint32 nrow = (row+rowsperstrip > h ?
+ h-row : rowsperstrip);
+ tstrip_t strip = TIFFComputeStrip(tif, row, 0);
+ if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
+ if (stoponerr)
+ break;
+ } else if (showdata)
+ ShowStrip(strip, buf, nrow, scanline);
+ }
+ _TIFFfree(buf);
+ }
+}
+
+void
+TIFFReadSeparateStripData(TIFF* tif)
+{
+ unsigned char *buf;
+ tsize_t scanline = TIFFScanlineSize(tif);
+
+ buf = (unsigned char *)_TIFFmalloc(TIFFStripSize(tif));
+ if (buf) {
+ uint32 row, h;
+ uint32 rowsperstrip = (uint32)-1;
+ tsample_t s, samplesperpixel;
+
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
+ TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ for (row = 0; row < h; row += rowsperstrip) {
+ for (s = 0; s < samplesperpixel; s++) {
+ uint32 nrow = (row+rowsperstrip > h ?
+ h-row : rowsperstrip);
+ tstrip_t strip = TIFFComputeStrip(tif, row, s);
+ if (TIFFReadEncodedStrip(tif, strip, buf, nrow*scanline) < 0) {
+ if (stoponerr)
+ break;
+ } else if (showdata)
+ ShowStrip(strip, buf, nrow, scanline);
+ }
+ }
+ _TIFFfree(buf);
+ }
+}
+
+static void
+ShowTile(uint32 row, uint32 col, tsample_t sample,
+ unsigned char* pp, uint32 nrow, uint32 rowsize)
+{
+ uint32 cc;
+
+ printf("Tile (%lu,%lu", (unsigned long) row, (unsigned long) col);
+ if (sample != (tsample_t) -1)
+ printf(",%u", sample);
+ printf("):\n");
+ while (nrow-- > 0) {
+ for (cc = 0; cc < rowsize; cc++) {
+ printf(" %02x", *pp++);
+ if (((cc+1) % 24) == 0)
+ putchar('\n');
+ }
+ putchar('\n');
+ }
+}
+
+void
+TIFFReadContigTileData(TIFF* tif)
+{
+ unsigned char *buf;
+ tsize_t rowsize = TIFFTileRowSize(tif);
+
+ buf = (unsigned char *)_TIFFmalloc(TIFFTileSize(tif));
+ if (buf) {
+ uint32 tw, th, w, h;
+ uint32 row, col;
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+ for (row = 0; row < h; row += th) {
+ for (col = 0; col < w; col += tw) {
+ if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0) {
+ if (stoponerr)
+ break;
+ } else if (showdata)
+ ShowTile(row, col, (tsample_t) -1, buf, th, rowsize);
+ }
+ }
+ _TIFFfree(buf);
+ }
+}
+
+void
+TIFFReadSeparateTileData(TIFF* tif)
+{
+ unsigned char *buf;
+ tsize_t rowsize = TIFFTileRowSize(tif);
+
+ buf = (unsigned char *)_TIFFmalloc(TIFFTileSize(tif));
+ if (buf) {
+ uint32 tw, th, w, h;
+ uint32 row, col;
+ tsample_t s, samplesperpixel;
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
+ TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
+ TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
+ TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ for (row = 0; row < h; row += th) {
+ for (col = 0; col < w; col += tw) {
+ for (s = 0; s < samplesperpixel; s++) {
+ if (TIFFReadTile(tif, buf, col, row, 0, s) < 0) {
+ if (stoponerr)
+ break;
+ } else if (showdata)
+ ShowTile(row, col, s, buf, th, rowsize);
+ }
+ }
+ }
+ _TIFFfree(buf);
+ }
+}
+
+void
+TIFFReadData(TIFF* tif)
+{
+ uint16 config;
+
+ TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config);
+ if (TIFFIsTiled(tif)) {
+ if (config == PLANARCONFIG_CONTIG)
+ TIFFReadContigTileData(tif);
+ else
+ TIFFReadSeparateTileData(tif);
+ } else {
+ if (config == PLANARCONFIG_CONTIG)
+ TIFFReadContigStripData(tif);
+ else
+ TIFFReadSeparateStripData(tif);
+ }
+}
+
+static void
+ShowRawBytes(unsigned char* pp, uint32 n)
+{
+ uint32 i;
+
+ for (i = 0; i < n; i++) {
+ printf(" %02x", *pp++);
+ if (((i+1) % 24) == 0)
+ printf("\n ");
+ }
+ putchar('\n');
+}
+
+static void
+ShowRawWords(uint16* pp, uint32 n)
+{
+ uint32 i;
+
+ for (i = 0; i < n; i++) {
+ printf(" %04x", *pp++);
+ if (((i+1) % 15) == 0)
+ printf("\n ");
+ }
+ putchar('\n');
+}
+
+void
+TIFFReadRawData(TIFF* tif, int bitrev)
+{
+ tstrip_t nstrips = TIFFNumberOfStrips(tif);
+ const char* what = TIFFIsTiled(tif) ? "Tile" : "Strip";
+ uint32* stripbc;
+
+ TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &stripbc);
+ if (nstrips > 0) {
+ uint32 bufsize = stripbc[0];
+ tdata_t buf = _TIFFmalloc(bufsize);
+ tstrip_t s;
+
+ for (s = 0; s < nstrips; s++) {
+ if (stripbc[s] > bufsize) {
+ buf = _TIFFrealloc(buf, stripbc[s]);
+ bufsize = stripbc[s];
+ }
+ if (buf == NULL) {
+ fprintf(stderr,
+ "Cannot allocate buffer to read strip %lu\n",
+ (unsigned long) s);
+ break;
+ }
+ if (TIFFReadRawStrip(tif, s, buf, stripbc[s]) < 0) {
+ fprintf(stderr, "Error reading strip %lu\n",
+ (unsigned long) s);
+ if (stoponerr)
+ break;
+ } else if (showdata) {
+ if (bitrev) {
+ TIFFReverseBits(buf, stripbc[s]);
+ printf("%s %lu: (bit reversed)\n ",
+ what, (unsigned long) s);
+ } else
+ printf("%s %lu:\n ", what,
+ (unsigned long) s);
+ if (showwords)
+ ShowRawWords((uint16*) buf, stripbc[s]>>1);
+ else
+ ShowRawBytes((unsigned char*) buf, stripbc[s]);
+ }
+ }
+ if (buf != NULL)
+ _TIFFfree(buf);
+ }
+}
+
+static void
+tiffinfo(TIFF* tif, uint16 order, long flags)
+{
+ TIFFPrintDirectory(tif, stdout, flags);
+ if (!readdata)
+ return;
+ if (rawdata) {
+ if (order) {
+ uint16 o;
+ TIFFGetFieldDefaulted(tif,
+ TIFFTAG_FILLORDER, &o);
+ TIFFReadRawData(tif, o != order);
+ } else
+ TIFFReadRawData(tif, 0);
+ } else {
+ if (order)
+ TIFFSetField(tif, TIFFTAG_FILLORDER, order);
+ TIFFReadData(tif);
+ }
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffmedian.c b/tiff/tools/tiffmedian.c
new file mode 100644
index 0000000..be45a2e
--- /dev/null
+++ b/tiff/tools/tiffmedian.c
@@ -0,0 +1,902 @@
+/* $Id: tiffmedian.c,v 1.8.2.1 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Apply median cut on an image.
+ *
+ * tiffmedian [-c n] [-f] input output
+ * -C n - set colortable size. Default is 256.
+ * -f - use Floyd-Steinberg dithering.
+ * -c lzw - compress output with LZW
+ * -c none - use no compression on output
+ * -c packbits - use packbits compression on output
+ * -r n - create output with n rows/strip of data
+ * (by default the compression scheme and rows/strip are taken
+ * from the input file)
+ *
+ * Notes:
+ *
+ * [1] Floyd-Steinberg dither:
+ * I should point out that the actual fractions we used were, assuming
+ * you are at X, moving left to right:
+ *
+ * X 7/16
+ * 3/16 5/16 1/16
+ *
+ * Note that the error goes to four neighbors, not three. I think this
+ * will probably do better (at least for black and white) than the
+ * 3/8-3/8-1/4 distribution, at the cost of greater processing. I have
+ * seen the 3/8-3/8-1/4 distribution described as "our" algorithm before,
+ * but I have no idea who the credit really belongs to.
+
+ * Also, I should add that if you do zig-zag scanning (see my immediately
+ * previous message), it is sufficient (but not quite as good) to send
+ * half the error one pixel ahead (e.g. to the right on lines you scan
+ * left to right), and half one pixel straight down. Again, this is for
+ * black and white; I've not tried it with color.
+ * --
+ * Lou Steinberg
+ *
+ * [2] Color Image Quantization for Frame Buffer Display, Paul Heckbert,
+ * Siggraph '82 proceedings, pp. 297-307
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tiffio.h"
+
+#define MAX_CMAP_SIZE 256
+
+#define streq(a,b) (strcmp(a,b) == 0)
+#define strneq(a,b,n) (strncmp(a,b,n) == 0)
+
+#define COLOR_DEPTH 8
+#define MAX_COLOR 256
+
+#define B_DEPTH 5 /* # bits/pixel to use */
+#define B_LEN (1L<<B_DEPTH)
+
+#define C_DEPTH 2
+#define C_LEN (1L<<C_DEPTH) /* # cells/color to use */
+
+#define COLOR_SHIFT (COLOR_DEPTH-B_DEPTH)
+
+typedef struct colorbox {
+ struct colorbox *next, *prev;
+ int rmin, rmax;
+ int gmin, gmax;
+ int bmin, bmax;
+ uint32 total;
+} Colorbox;
+
+typedef struct {
+ int num_ents;
+ int entries[MAX_CMAP_SIZE][2];
+} C_cell;
+
+uint16 rm[MAX_CMAP_SIZE], gm[MAX_CMAP_SIZE], bm[MAX_CMAP_SIZE];
+int num_colors;
+uint32 histogram[B_LEN][B_LEN][B_LEN];
+Colorbox *freeboxes;
+Colorbox *usedboxes;
+C_cell **ColorCells;
+TIFF *in, *out;
+uint32 rowsperstrip = (uint32) -1;
+uint16 compression = (uint16) -1;
+uint16 bitspersample = 1;
+uint16 samplesperpixel;
+uint32 imagewidth;
+uint32 imagelength;
+uint16 predictor = 0;
+
+static void get_histogram(TIFF*, Colorbox*);
+static void splitbox(Colorbox*);
+static void shrinkbox(Colorbox*);
+static void map_colortable(void);
+static void quant(TIFF*, TIFF*);
+static void quant_fsdither(TIFF*, TIFF*);
+static Colorbox* largest_box(void);
+
+static void usage(void);
+static int processCompressOptions(char*);
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+
+int
+main(int argc, char* argv[])
+{
+ int i, dither = 0;
+ uint16 shortv, config, photometric;
+ Colorbox *box_list, *ptr;
+ float floatv;
+ uint32 longv;
+ int c;
+ extern int optind;
+ extern char* optarg;
+
+ num_colors = MAX_CMAP_SIZE;
+ while ((c = getopt(argc, argv, "c:C:r:f")) != -1)
+ switch (c) {
+ case 'c': /* compression scheme */
+ if (!processCompressOptions(optarg))
+ usage();
+ break;
+ case 'C': /* set colormap size */
+ num_colors = atoi(optarg);
+ if (num_colors > MAX_CMAP_SIZE) {
+ fprintf(stderr,
+ "-c: colormap too big, max %d\n",
+ MAX_CMAP_SIZE);
+ usage();
+ }
+ break;
+ case 'f': /* dither */
+ dither = 1;
+ break;
+ case 'r': /* rows/strip */
+ rowsperstrip = atoi(optarg);
+ break;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+ if (argc - optind != 2)
+ usage();
+ in = TIFFOpen(argv[optind], "r");
+ if (in == NULL)
+ return (-1);
+ TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth);
+ TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
+ TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (bitspersample != 8 && bitspersample != 16) {
+ fprintf(stderr, "%s: Image must have at least 8-bits/sample\n",
+ argv[optind]);
+ return (-3);
+ }
+ if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) ||
+ photometric != PHOTOMETRIC_RGB || samplesperpixel < 3) {
+ fprintf(stderr, "%s: Image must have RGB data\n", argv[optind]);
+ return (-4);
+ }
+ TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config);
+ if (config != PLANARCONFIG_CONTIG) {
+ fprintf(stderr, "%s: Can only handle contiguous data packing\n",
+ argv[optind]);
+ return (-5);
+ }
+
+ /*
+ * STEP 1: create empty boxes
+ */
+ usedboxes = NULL;
+ box_list = freeboxes = (Colorbox *)_TIFFmalloc(num_colors*sizeof (Colorbox));
+ freeboxes[0].next = &freeboxes[1];
+ freeboxes[0].prev = NULL;
+ for (i = 1; i < num_colors-1; ++i) {
+ freeboxes[i].next = &freeboxes[i+1];
+ freeboxes[i].prev = &freeboxes[i-1];
+ }
+ freeboxes[num_colors-1].next = NULL;
+ freeboxes[num_colors-1].prev = &freeboxes[num_colors-2];
+
+ /*
+ * STEP 2: get histogram, initialize first box
+ */
+ ptr = freeboxes;
+ freeboxes = ptr->next;
+ if (freeboxes)
+ freeboxes->prev = NULL;
+ ptr->next = usedboxes;
+ usedboxes = ptr;
+ if (ptr->next)
+ ptr->next->prev = ptr;
+ get_histogram(in, ptr);
+
+ /*
+ * STEP 3: continually subdivide boxes until no more free
+ * boxes remain or until all colors assigned.
+ */
+ while (freeboxes != NULL) {
+ ptr = largest_box();
+ if (ptr != NULL)
+ splitbox(ptr);
+ else
+ freeboxes = NULL;
+ }
+
+ /*
+ * STEP 4: assign colors to all boxes
+ */
+ for (i = 0, ptr = usedboxes; ptr != NULL; ++i, ptr = ptr->next) {
+ rm[i] = ((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2;
+ gm[i] = ((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2;
+ bm[i] = ((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2;
+ }
+
+ /* We're done with the boxes now */
+ _TIFFfree(box_list);
+ freeboxes = usedboxes = NULL;
+
+ /*
+ * STEP 5: scan histogram and map all values to closest color
+ */
+ /* 5a: create cell list as described in Heckbert[2] */
+ ColorCells = (C_cell **)_TIFFmalloc(C_LEN*C_LEN*C_LEN*sizeof (C_cell*));
+ _TIFFmemset(ColorCells, 0, C_LEN*C_LEN*C_LEN*sizeof (C_cell*));
+ /* 5b: create mapping from truncated pixel space to color
+ table entries */
+ map_colortable();
+
+ /*
+ * STEP 6: scan image, match input values to table entries
+ */
+ out = TIFFOpen(argv[optind+1], "w");
+ if (out == NULL)
+ return (-2);
+
+ CopyField(TIFFTAG_SUBFILETYPE, longv);
+ CopyField(TIFFTAG_IMAGEWIDTH, longv);
+ TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (short)COLOR_DEPTH);
+ if (compression != (uint16)-1) {
+ TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
+ switch (compression) {
+ case COMPRESSION_LZW:
+ case COMPRESSION_DEFLATE:
+ if (predictor != 0)
+ TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
+ break;
+ }
+ } else
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ TIFFSetField(out, TIFFTAG_PHOTOMETRIC, (short)PHOTOMETRIC_PALETTE);
+ CopyField(TIFFTAG_ORIENTATION, shortv);
+ TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (short)1);
+ CopyField(TIFFTAG_PLANARCONFIG, shortv);
+ TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
+ TIFFDefaultStripSize(out, rowsperstrip));
+ CopyField(TIFFTAG_MINSAMPLEVALUE, shortv);
+ CopyField(TIFFTAG_MAXSAMPLEVALUE, shortv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_XPOSITION, floatv);
+ CopyField(TIFFTAG_YPOSITION, floatv);
+
+ if (dither)
+ quant_fsdither(in, out);
+ else
+ quant(in, out);
+ /*
+ * Scale colormap to TIFF-required 16-bit values.
+ */
+#define SCALE(x) (((x)*((1L<<16)-1))/255)
+ for (i = 0; i < MAX_CMAP_SIZE; ++i) {
+ rm[i] = SCALE(rm[i]);
+ gm[i] = SCALE(gm[i]);
+ bm[i] = SCALE(bm[i]);
+ }
+ TIFFSetField(out, TIFFTAG_COLORMAP, rm, gm, bm);
+ (void) TIFFClose(out);
+ return (0);
+}
+
+static int
+processCompressOptions(char* opt)
+{
+ if (streq(opt, "none"))
+ compression = COMPRESSION_NONE;
+ else if (streq(opt, "packbits"))
+ compression = COMPRESSION_PACKBITS;
+ else if (strneq(opt, "lzw", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_LZW;
+ } else if (strneq(opt, "zip", 3)) {
+ char* cp = strchr(opt, ':');
+ if (cp)
+ predictor = atoi(cp+1);
+ compression = COMPRESSION_DEFLATE;
+ } else
+ return (0);
+ return (1);
+}
+
+char* stuff[] = {
+"usage: tiffmedian [options] input.tif output.tif",
+"where options are:",
+" -r # make each strip have no more than # rows",
+" -C # create a colormap with # entries",
+" -f use Floyd-Steinberg dithering",
+" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
+" -c zip[:opts] compress output with deflate encoding",
+" -c packbits compress output with packbits encoding",
+" -c none use no compression algorithm on output",
+"",
+"LZW and deflate options:",
+" # set predictor value",
+"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
+NULL
+};
+
+static void
+usage(void)
+{
+ char buf[BUFSIZ];
+ int i;
+
+ setbuf(stderr, buf);
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ for (i = 0; stuff[i] != NULL; i++)
+ fprintf(stderr, "%s\n", stuff[i]);
+ exit(-1);
+}
+
+static void
+get_histogram(TIFF* in, Colorbox* box)
+{
+ register unsigned char *inptr;
+ register int red, green, blue;
+ register uint32 j, i;
+ unsigned char *inputline;
+
+ inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ if (inputline == NULL) {
+ fprintf(stderr, "No space for scanline buffer\n");
+ exit(-1);
+ }
+ box->rmin = box->gmin = box->bmin = 999;
+ box->rmax = box->gmax = box->bmax = -1;
+ box->total = imagewidth * imagelength;
+
+ { register uint32 *ptr = &histogram[0][0][0];
+ for (i = B_LEN*B_LEN*B_LEN; i-- > 0;)
+ *ptr++ = 0;
+ }
+ for (i = 0; i < imagelength; i++) {
+ if (TIFFReadScanline(in, inputline, i, 0) <= 0)
+ break;
+ inptr = inputline;
+ for (j = imagewidth; j-- > 0;) {
+ red = *inptr++ >> COLOR_SHIFT;
+ green = *inptr++ >> COLOR_SHIFT;
+ blue = *inptr++ >> COLOR_SHIFT;
+ if (red < box->rmin)
+ box->rmin = red;
+ if (red > box->rmax)
+ box->rmax = red;
+ if (green < box->gmin)
+ box->gmin = green;
+ if (green > box->gmax)
+ box->gmax = green;
+ if (blue < box->bmin)
+ box->bmin = blue;
+ if (blue > box->bmax)
+ box->bmax = blue;
+ histogram[red][green][blue]++;
+ }
+ }
+ _TIFFfree(inputline);
+}
+
+static Colorbox *
+largest_box(void)
+{
+ register Colorbox *p, *b;
+ register uint32 size;
+
+ b = NULL;
+ size = 0;
+ for (p = usedboxes; p != NULL; p = p->next)
+ if ((p->rmax > p->rmin || p->gmax > p->gmin ||
+ p->bmax > p->bmin) && p->total > size)
+ size = (b = p)->total;
+ return (b);
+}
+
+static void
+splitbox(Colorbox* ptr)
+{
+ uint32 hist2[B_LEN];
+ int first=0, last=0;
+ register Colorbox *new;
+ register uint32 *iptr, *histp;
+ register int i, j;
+ register int ir,ig,ib;
+ register uint32 sum, sum1, sum2;
+ enum { RED, GREEN, BLUE } axis;
+
+ /*
+ * See which axis is the largest, do a histogram along that
+ * axis. Split at median point. Contract both new boxes to
+ * fit points and return
+ */
+ i = ptr->rmax - ptr->rmin;
+ if (i >= ptr->gmax - ptr->gmin && i >= ptr->bmax - ptr->bmin)
+ axis = RED;
+ else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)
+ axis = GREEN;
+ else
+ axis = BLUE;
+ /* get histogram along longest axis */
+ switch (axis) {
+ case RED:
+ histp = &hist2[ptr->rmin];
+ for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+ *histp = 0;
+ for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+ iptr = &histogram[ir][ig][ptr->bmin];
+ for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
+ *histp += *iptr++;
+ }
+ histp++;
+ }
+ first = ptr->rmin;
+ last = ptr->rmax;
+ break;
+ case GREEN:
+ histp = &hist2[ptr->gmin];
+ for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+ *histp = 0;
+ for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+ iptr = &histogram[ir][ig][ptr->bmin];
+ for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
+ *histp += *iptr++;
+ }
+ histp++;
+ }
+ first = ptr->gmin;
+ last = ptr->gmax;
+ break;
+ case BLUE:
+ histp = &hist2[ptr->bmin];
+ for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
+ *histp = 0;
+ for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+ iptr = &histogram[ir][ptr->gmin][ib];
+ for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+ *histp += *iptr;
+ iptr += B_LEN;
+ }
+ }
+ histp++;
+ }
+ first = ptr->bmin;
+ last = ptr->bmax;
+ break;
+ }
+ /* find median point */
+ sum2 = ptr->total / 2;
+ histp = &hist2[first];
+ sum = 0;
+ for (i = first; i <= last && (sum += *histp++) < sum2; ++i)
+ ;
+ if (i == first)
+ i++;
+
+ /* Create new box, re-allocate points */
+ new = freeboxes;
+ freeboxes = new->next;
+ if (freeboxes)
+ freeboxes->prev = NULL;
+ if (usedboxes)
+ usedboxes->prev = new;
+ new->next = usedboxes;
+ usedboxes = new;
+
+ histp = &hist2[first];
+ for (sum1 = 0, j = first; j < i; j++)
+ sum1 += *histp++;
+ for (sum2 = 0, j = i; j <= last; j++)
+ sum2 += *histp++;
+ new->total = sum1;
+ ptr->total = sum2;
+
+ new->rmin = ptr->rmin;
+ new->rmax = ptr->rmax;
+ new->gmin = ptr->gmin;
+ new->gmax = ptr->gmax;
+ new->bmin = ptr->bmin;
+ new->bmax = ptr->bmax;
+ switch (axis) {
+ case RED:
+ new->rmax = i-1;
+ ptr->rmin = i;
+ break;
+ case GREEN:
+ new->gmax = i-1;
+ ptr->gmin = i;
+ break;
+ case BLUE:
+ new->bmax = i-1;
+ ptr->bmin = i;
+ break;
+ }
+ shrinkbox(new);
+ shrinkbox(ptr);
+}
+
+static void
+shrinkbox(Colorbox* box)
+{
+ register uint32 *histp;
+ register int ir, ig, ib;
+
+ if (box->rmax > box->rmin) {
+ for (ir = box->rmin; ir <= box->rmax; ++ir)
+ for (ig = box->gmin; ig <= box->gmax; ++ig) {
+ histp = &histogram[ir][ig][box->bmin];
+ for (ib = box->bmin; ib <= box->bmax; ++ib)
+ if (*histp++ != 0) {
+ box->rmin = ir;
+ goto have_rmin;
+ }
+ }
+ have_rmin:
+ if (box->rmax > box->rmin)
+ for (ir = box->rmax; ir >= box->rmin; --ir)
+ for (ig = box->gmin; ig <= box->gmax; ++ig) {
+ histp = &histogram[ir][ig][box->bmin];
+ ib = box->bmin;
+ for (; ib <= box->bmax; ++ib)
+ if (*histp++ != 0) {
+ box->rmax = ir;
+ goto have_rmax;
+ }
+ }
+ }
+have_rmax:
+ if (box->gmax > box->gmin) {
+ for (ig = box->gmin; ig <= box->gmax; ++ig)
+ for (ir = box->rmin; ir <= box->rmax; ++ir) {
+ histp = &histogram[ir][ig][box->bmin];
+ for (ib = box->bmin; ib <= box->bmax; ++ib)
+ if (*histp++ != 0) {
+ box->gmin = ig;
+ goto have_gmin;
+ }
+ }
+ have_gmin:
+ if (box->gmax > box->gmin)
+ for (ig = box->gmax; ig >= box->gmin; --ig)
+ for (ir = box->rmin; ir <= box->rmax; ++ir) {
+ histp = &histogram[ir][ig][box->bmin];
+ ib = box->bmin;
+ for (; ib <= box->bmax; ++ib)
+ if (*histp++ != 0) {
+ box->gmax = ig;
+ goto have_gmax;
+ }
+ }
+ }
+have_gmax:
+ if (box->bmax > box->bmin) {
+ for (ib = box->bmin; ib <= box->bmax; ++ib)
+ for (ir = box->rmin; ir <= box->rmax; ++ir) {
+ histp = &histogram[ir][box->gmin][ib];
+ for (ig = box->gmin; ig <= box->gmax; ++ig) {
+ if (*histp != 0) {
+ box->bmin = ib;
+ goto have_bmin;
+ }
+ histp += B_LEN;
+ }
+ }
+ have_bmin:
+ if (box->bmax > box->bmin)
+ for (ib = box->bmax; ib >= box->bmin; --ib)
+ for (ir = box->rmin; ir <= box->rmax; ++ir) {
+ histp = &histogram[ir][box->gmin][ib];
+ ig = box->gmin;
+ for (; ig <= box->gmax; ++ig) {
+ if (*histp != 0) {
+ box->bmax = ib;
+ goto have_bmax;
+ }
+ histp += B_LEN;
+ }
+ }
+ }
+have_bmax:
+ ;
+}
+
+static C_cell *
+create_colorcell(int red, int green, int blue)
+{
+ register int ir, ig, ib, i;
+ register C_cell *ptr;
+ int mindist, next_n;
+ register int tmp, dist, n;
+
+ ir = red >> (COLOR_DEPTH-C_DEPTH);
+ ig = green >> (COLOR_DEPTH-C_DEPTH);
+ ib = blue >> (COLOR_DEPTH-C_DEPTH);
+ ptr = (C_cell *)_TIFFmalloc(sizeof (C_cell));
+ *(ColorCells + ir*C_LEN*C_LEN + ig*C_LEN + ib) = ptr;
+ ptr->num_ents = 0;
+
+ /*
+ * Step 1: find all colors inside this cell, while we're at
+ * it, find distance of centermost point to furthest corner
+ */
+ mindist = 99999999;
+ for (i = 0; i < num_colors; ++i) {
+ if (rm[i]>>(COLOR_DEPTH-C_DEPTH) != ir ||
+ gm[i]>>(COLOR_DEPTH-C_DEPTH) != ig ||
+ bm[i]>>(COLOR_DEPTH-C_DEPTH) != ib)
+ continue;
+ ptr->entries[ptr->num_ents][0] = i;
+ ptr->entries[ptr->num_ents][1] = 0;
+ ++ptr->num_ents;
+ tmp = rm[i] - red;
+ if (tmp < (MAX_COLOR/C_LEN/2))
+ tmp = MAX_COLOR/C_LEN-1 - tmp;
+ dist = tmp*tmp;
+ tmp = gm[i] - green;
+ if (tmp < (MAX_COLOR/C_LEN/2))
+ tmp = MAX_COLOR/C_LEN-1 - tmp;
+ dist += tmp*tmp;
+ tmp = bm[i] - blue;
+ if (tmp < (MAX_COLOR/C_LEN/2))
+ tmp = MAX_COLOR/C_LEN-1 - tmp;
+ dist += tmp*tmp;
+ if (dist < mindist)
+ mindist = dist;
+ }
+
+ /*
+ * Step 3: find all points within that distance to cell.
+ */
+ for (i = 0; i < num_colors; ++i) {
+ if (rm[i] >> (COLOR_DEPTH-C_DEPTH) == ir &&
+ gm[i] >> (COLOR_DEPTH-C_DEPTH) == ig &&
+ bm[i] >> (COLOR_DEPTH-C_DEPTH) == ib)
+ continue;
+ dist = 0;
+ if ((tmp = red - rm[i]) > 0 ||
+ (tmp = rm[i] - (red + MAX_COLOR/C_LEN-1)) > 0 )
+ dist += tmp*tmp;
+ if ((tmp = green - gm[i]) > 0 ||
+ (tmp = gm[i] - (green + MAX_COLOR/C_LEN-1)) > 0 )
+ dist += tmp*tmp;
+ if ((tmp = blue - bm[i]) > 0 ||
+ (tmp = bm[i] - (blue + MAX_COLOR/C_LEN-1)) > 0 )
+ dist += tmp*tmp;
+ if (dist < mindist) {
+ ptr->entries[ptr->num_ents][0] = i;
+ ptr->entries[ptr->num_ents][1] = dist;
+ ++ptr->num_ents;
+ }
+ }
+
+ /*
+ * Sort color cells by distance, use cheap exchange sort
+ */
+ for (n = ptr->num_ents - 1; n > 0; n = next_n) {
+ next_n = 0;
+ for (i = 0; i < n; ++i)
+ if (ptr->entries[i][1] > ptr->entries[i+1][1]) {
+ tmp = ptr->entries[i][0];
+ ptr->entries[i][0] = ptr->entries[i+1][0];
+ ptr->entries[i+1][0] = tmp;
+ tmp = ptr->entries[i][1];
+ ptr->entries[i][1] = ptr->entries[i+1][1];
+ ptr->entries[i+1][1] = tmp;
+ next_n = i;
+ }
+ }
+ return (ptr);
+}
+
+static void
+map_colortable(void)
+{
+ register uint32 *histp = &histogram[0][0][0];
+ register C_cell *cell;
+ register int j, tmp, d2, dist;
+ int ir, ig, ib, i;
+
+ for (ir = 0; ir < B_LEN; ++ir)
+ for (ig = 0; ig < B_LEN; ++ig)
+ for (ib = 0; ib < B_LEN; ++ib, histp++) {
+ if (*histp == 0) {
+ *histp = -1;
+ continue;
+ }
+ cell = *(ColorCells +
+ (((ir>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
+ ((ig>>(B_DEPTH-C_DEPTH)) << C_DEPTH) +
+ (ib>>(B_DEPTH-C_DEPTH))));
+ if (cell == NULL )
+ cell = create_colorcell(
+ ir << COLOR_SHIFT,
+ ig << COLOR_SHIFT,
+ ib << COLOR_SHIFT);
+ dist = 9999999;
+ for (i = 0; i < cell->num_ents &&
+ dist > cell->entries[i][1]; ++i) {
+ j = cell->entries[i][0];
+ d2 = rm[j] - (ir << COLOR_SHIFT);
+ d2 *= d2;
+ tmp = gm[j] - (ig << COLOR_SHIFT);
+ d2 += tmp*tmp;
+ tmp = bm[j] - (ib << COLOR_SHIFT);
+ d2 += tmp*tmp;
+ if (d2 < dist) {
+ dist = d2;
+ *histp = j;
+ }
+ }
+ }
+}
+
+/*
+ * straight quantization. Each pixel is mapped to the colors
+ * closest to it. Color values are rounded to the nearest color
+ * table entry.
+ */
+static void
+quant(TIFF* in, TIFF* out)
+{
+ unsigned char *outline, *inputline;
+ register unsigned char *outptr, *inptr;
+ register uint32 i, j;
+ register int red, green, blue;
+
+ inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ outline = (unsigned char *)_TIFFmalloc(imagewidth);
+ for (i = 0; i < imagelength; i++) {
+ if (TIFFReadScanline(in, inputline, i, 0) <= 0)
+ break;
+ inptr = inputline;
+ outptr = outline;
+ for (j = 0; j < imagewidth; j++) {
+ red = *inptr++ >> COLOR_SHIFT;
+ green = *inptr++ >> COLOR_SHIFT;
+ blue = *inptr++ >> COLOR_SHIFT;
+ *outptr++ = (unsigned char)histogram[red][green][blue];
+ }
+ if (TIFFWriteScanline(out, outline, i, 0) < 0)
+ break;
+ }
+ _TIFFfree(inputline);
+ _TIFFfree(outline);
+}
+
+#define SWAP(type,a,b) { type p; p = a; a = b; b = p; }
+
+#define GetInputLine(tif, row, bad) \
+ if (TIFFReadScanline(tif, inputline, row, 0) <= 0) \
+ bad; \
+ inptr = inputline; \
+ nextptr = nextline; \
+ for (j = 0; j < imagewidth; ++j) { \
+ *nextptr++ = *inptr++; \
+ *nextptr++ = *inptr++; \
+ *nextptr++ = *inptr++; \
+ }
+#define GetComponent(raw, cshift, c) \
+ cshift = raw; \
+ if (cshift < 0) \
+ cshift = 0; \
+ else if (cshift >= MAX_COLOR) \
+ cshift = MAX_COLOR-1; \
+ c = cshift; \
+ cshift >>= COLOR_SHIFT;
+
+static void
+quant_fsdither(TIFF* in, TIFF* out)
+{
+ unsigned char *outline, *inputline, *inptr;
+ short *thisline, *nextline;
+ register unsigned char *outptr;
+ register short *thisptr, *nextptr;
+ register uint32 i, j;
+ uint32 imax, jmax;
+ int lastline, lastpixel;
+
+ imax = imagelength - 1;
+ jmax = imagewidth - 1;
+ inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
+ thisline = (short *)_TIFFmalloc(imagewidth * 3 * sizeof (short));
+ nextline = (short *)_TIFFmalloc(imagewidth * 3 * sizeof (short));
+ outline = (unsigned char *) _TIFFmalloc(TIFFScanlineSize(out));
+
+ GetInputLine(in, 0, goto bad); /* get first line */
+ for (i = 1; i <= imagelength; ++i) {
+ SWAP(short *, thisline, nextline);
+ lastline = (i >= imax);
+ if (i <= imax)
+ GetInputLine(in, i, break);
+ thisptr = thisline;
+ nextptr = nextline;
+ outptr = outline;
+ for (j = 0; j < imagewidth; ++j) {
+ int red, green, blue;
+ register int oval, r2, g2, b2;
+
+ lastpixel = (j == jmax);
+ GetComponent(*thisptr++, r2, red);
+ GetComponent(*thisptr++, g2, green);
+ GetComponent(*thisptr++, b2, blue);
+ oval = histogram[r2][g2][b2];
+ if (oval == -1) {
+ int ci;
+ register int cj, tmp, d2, dist;
+ register C_cell *cell;
+
+ cell = *(ColorCells +
+ (((r2>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
+ ((g2>>(B_DEPTH-C_DEPTH)) << C_DEPTH ) +
+ (b2>>(B_DEPTH-C_DEPTH))));
+ if (cell == NULL)
+ cell = create_colorcell(red,
+ green, blue);
+ dist = 9999999;
+ for (ci = 0; ci < cell->num_ents && dist > cell->entries[ci][1]; ++ci) {
+ cj = cell->entries[ci][0];
+ d2 = (rm[cj] >> COLOR_SHIFT) - r2;
+ d2 *= d2;
+ tmp = (gm[cj] >> COLOR_SHIFT) - g2;
+ d2 += tmp*tmp;
+ tmp = (bm[cj] >> COLOR_SHIFT) - b2;
+ d2 += tmp*tmp;
+ if (d2 < dist) {
+ dist = d2;
+ oval = cj;
+ }
+ }
+ histogram[r2][g2][b2] = oval;
+ }
+ *outptr++ = oval;
+ red -= rm[oval];
+ green -= gm[oval];
+ blue -= bm[oval];
+ if (!lastpixel) {
+ thisptr[0] += blue * 7 / 16;
+ thisptr[1] += green * 7 / 16;
+ thisptr[2] += red * 7 / 16;
+ }
+ if (!lastline) {
+ if (j != 0) {
+ nextptr[-3] += blue * 3 / 16;
+ nextptr[-2] += green * 3 / 16;
+ nextptr[-1] += red * 3 / 16;
+ }
+ nextptr[0] += blue * 5 / 16;
+ nextptr[1] += green * 5 / 16;
+ nextptr[2] += red * 5 / 16;
+ if (!lastpixel) {
+ nextptr[3] += blue / 16;
+ nextptr[4] += green / 16;
+ nextptr[5] += red / 16;
+ }
+ nextptr += 3;
+ }
+ }
+ if (TIFFWriteScanline(out, outline, i-1, 0) < 0)
+ break;
+ }
+bad:
+ _TIFFfree(inputline);
+ _TIFFfree(thisline);
+ _TIFFfree(nextline);
+ _TIFFfree(outline);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffset.c b/tiff/tools/tiffset.c
new file mode 100644
index 0000000..eb68924
--- /dev/null
+++ b/tiff/tools/tiffset.c
@@ -0,0 +1,325 @@
+/******************************************************************************
+ * $Id: tiffset.c,v 1.12.2.1 2010-06-08 18:50:44 bfriesen Exp $
+ *
+ * Project: libtiff tools
+ * Purpose: Mainline for setting metadata in existing TIFF files.
+ * Author: Frank Warmerdam, warmerdam@pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2000, Frank Warmerdam
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ ******************************************************************************
+ *
+ * $Log: tiffset.c,v $
+ * Revision 1.12.2.1 2010-06-08 18:50:44 bfriesen
+ * * Add an emacs formatting mode footer to all source files so that
+ * emacs can be effectively used.
+ *
+ * Revision 1.12 2007/02/24 17:14:14 dron
+ * Properly handle tags with TIFF_VARIABLE writecount. As per bug
+ * http://bugzilla.remotesensing.org/show_bug.cgi?id=1350
+ *
+ * Revision 1.11 2005/09/13 14:13:42 dron
+ * Avoid warnings.
+ *
+ * Revision 1.10 2005/02/24 14:47:11 fwarmerdam
+ * Updated header.
+ *
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "tiffio.h"
+
+static char* usageMsg[] = {
+"usage: tiffset [options] filename",
+"where options are:",
+" -s <tagname> [count] <value>... set the tag value",
+" -sf <tagname> <filename> read the tag value from file (for ASCII tags only)",
+NULL
+};
+
+static void
+usage(void)
+{
+ int i;
+ for (i = 0; usageMsg[i]; i++)
+ fprintf(stderr, "%s\n", usageMsg[i]);
+ exit(-1);
+}
+
+static const TIFFFieldInfo *
+GetField(TIFF *tiff, const char *tagname)
+{
+ const TIFFFieldInfo *fip;
+
+ if( atoi(tagname) > 0 )
+ fip = TIFFFieldWithTag(tiff, (ttag_t)atoi(tagname));
+ else
+ fip = TIFFFieldWithName(tiff, tagname);
+
+ if (!fip) {
+ fprintf( stderr, "Field name %s not recognised.\n", tagname );
+ return (TIFFFieldInfo *)NULL;
+ }
+
+ return fip;
+}
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *tiff;
+ int arg_index;
+
+ if (argc < 2)
+ usage();
+
+ tiff = TIFFOpen(argv[argc-1], "r+");
+ if (tiff == NULL)
+ return 2;
+
+ for( arg_index = 1; arg_index < argc-1; arg_index++ ) {
+ if (strcmp(argv[arg_index],"-s") == 0 && arg_index < argc-3) {
+ const TIFFFieldInfo *fip;
+ const char *tagname;
+
+ arg_index++;
+ tagname = argv[arg_index];
+ fip = GetField(tiff, tagname);
+
+ if (!fip)
+ return 3;
+
+ arg_index++;
+ if (fip->field_type == TIFF_ASCII) {
+ if (TIFFSetField(tiff, fip->field_tag, argv[arg_index]) != 1)
+ fprintf( stderr, "Failed to set %s=%s\n",
+ fip->field_name, argv[arg_index] );
+ } else if (fip->field_writecount > 0
+ || fip->field_writecount == TIFF_VARIABLE) {
+ int ret = 1;
+ short wc;
+
+ if (fip->field_writecount == TIFF_VARIABLE)
+ wc = atoi(argv[arg_index++]);
+ else
+ wc = fip->field_writecount;
+
+ if (argc - arg_index < wc) {
+ fprintf( stderr,
+ "Number of tag values is not enough. "
+ "Expected %d values for %s tag, got %d\n",
+ wc, fip->field_name, argc - arg_index);
+ return 4;
+ }
+
+ if (wc > 1) {
+ int i, size;
+ void *array;
+
+ switch (fip->field_type) {
+ /*
+ * XXX: We can't use TIFFDataWidth()
+ * to determine the space needed to store
+ * the value. For TIFF_RATIONAL values
+ * TIFFDataWidth() returns 8, but we use 4-byte
+ * float to represent rationals.
+ */
+ case TIFF_BYTE:
+ case TIFF_ASCII:
+ case TIFF_SBYTE:
+ case TIFF_UNDEFINED:
+ default:
+ size = 1;
+ break;
+
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ size = 2;
+ break;
+
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_FLOAT:
+ case TIFF_IFD:
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ size = 4;
+ break;
+
+ case TIFF_DOUBLE:
+ size = 8;
+ break;
+ }
+
+ array = _TIFFmalloc(wc * size);
+ if (!array) {
+ fprintf(stderr, "No space for %s tag\n",
+ tagname);
+ return 4;
+ }
+
+ switch (fip->field_type) {
+ case TIFF_BYTE:
+ for (i = 0; i < wc; i++)
+ ((uint8 *)array)[i] = atoi(argv[arg_index+i]);
+ break;
+ case TIFF_SHORT:
+ for (i = 0; i < wc; i++)
+ ((uint16 *)array)[i] = atoi(argv[arg_index+i]);
+ break;
+ case TIFF_SBYTE:
+ for (i = 0; i < wc; i++)
+ ((int8 *)array)[i] = atoi(argv[arg_index+i]);
+ break;
+ case TIFF_SSHORT:
+ for (i = 0; i < wc; i++)
+ ((int16 *)array)[i] = atoi(argv[arg_index+i]);
+ break;
+ case TIFF_LONG:
+ for (i = 0; i < wc; i++)
+ ((uint32 *)array)[i] = atol(argv[arg_index+i]);
+ break;
+ case TIFF_SLONG:
+ case TIFF_IFD:
+ for (i = 0; i < wc; i++)
+ ((uint32 *)array)[i] = atol(argv[arg_index+i]);
+ break;
+ case TIFF_DOUBLE:
+ for (i = 0; i < wc; i++)
+ ((double *)array)[i] = atof(argv[arg_index+i]);
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ for (i = 0; i < wc; i++)
+ ((float *)array)[i] = (float)atof(argv[arg_index+i]);
+ break;
+ default:
+ break;
+ }
+
+ if (fip->field_passcount) {
+ ret = TIFFSetField(tiff, fip->field_tag,
+ wc, array);
+ } else {
+ ret = TIFFSetField(tiff, fip->field_tag,
+ array);
+ }
+
+ _TIFFfree(array);
+ } else {
+ switch (fip->field_type) {
+ case TIFF_BYTE:
+ case TIFF_SHORT:
+ case TIFF_SBYTE:
+ case TIFF_SSHORT:
+ ret = TIFFSetField(tiff, fip->field_tag,
+ atoi(argv[arg_index++]));
+ break;
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_IFD:
+ ret = TIFFSetField(tiff, fip->field_tag,
+ atol(argv[arg_index++]));
+ break;
+ case TIFF_DOUBLE:
+ ret = TIFFSetField(tiff, fip->field_tag,
+ atof(argv[arg_index++]));
+ break;
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_FLOAT:
+ ret = TIFFSetField(tiff, fip->field_tag,
+ (float)atof(argv[arg_index++]));
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (ret != 1)
+ fprintf(stderr, "Failed to set %s\n", fip->field_name);
+ arg_index += wc;
+ }
+ } else if (strcmp(argv[arg_index],"-sf") == 0 && arg_index < argc-3) {
+ FILE *fp;
+ const TIFFFieldInfo *fip;
+ char *text;
+ int len;
+
+ arg_index++;
+ fip = GetField(tiff, argv[arg_index]);
+
+ if (!fip)
+ return 3;
+
+ if (fip->field_type != TIFF_ASCII) {
+ fprintf( stderr,
+ "Only ASCII tags can be set from file. "
+ "%s is not ASCII tag.\n", fip->field_name );
+ return 5;
+ }
+
+ arg_index++;
+ fp = fopen( argv[arg_index], "rt" );
+ if(fp == NULL) {
+ perror( argv[arg_index] );
+ continue;
+ }
+
+ text = (char *) malloc(1000000);
+ len = fread( text, 1, 999999, fp );
+ text[len] = '\0';
+
+ fclose( fp );
+
+ if(TIFFSetField( tiff, fip->field_tag, text ) != 1) {
+ fprintf(stderr, "Failed to set %s from file %s\n",
+ fip->field_name, argv[arg_index]);
+ }
+
+ _TIFFfree( text );
+ arg_index++;
+ } else {
+ fprintf(stderr, "Unrecognised option: %s\n",
+ argv[arg_index]);
+ usage();
+ }
+ }
+
+ TIFFRewriteDirectory(tiff);
+ TIFFClose(tiff);
+ return 0;
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/tiffsplit.c b/tiff/tools/tiffsplit.c
new file mode 100644
index 0000000..58288cd
--- /dev/null
+++ b/tiff/tools/tiffsplit.c
@@ -0,0 +1,297 @@
+/* $Id: tiffsplit.c,v 1.14.2.4 2010-06-08 18:50:44 bfriesen Exp $ */
+
+/*
+ * Copyright (c) 1992-1997 Sam Leffler
+ * Copyright (c) 1992-1997 Silicon Graphics, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that (i) the above copyright notices and this permission notice appear in
+ * all copies of the software and related documentation, and (ii) the names of
+ * Sam Leffler and Silicon Graphics may not be used in any advertising or
+ * publicity relating to the software without the specific, prior written
+ * permission of Sam Leffler and Silicon Graphics.
+ *
+ * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+ * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+ * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+ * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+ * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include "tif_config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tiffio.h"
+
+#ifndef HAVE_GETOPT
+extern int getopt(int, char**, char*);
+#endif
+
+#define CopyField(tag, v) \
+ if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
+#define CopyField2(tag, v1, v2) \
+ if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
+#define CopyField3(tag, v1, v2, v3) \
+ if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
+
+#define PATH_LENGTH 8192
+
+static const char TIFF_SUFFIX[] = ".tif";
+
+static char fname[PATH_LENGTH];
+
+static int tiffcp(TIFF*, TIFF*);
+static void newfilename(void);
+static int cpStrips(TIFF*, TIFF*);
+static int cpTiles(TIFF*, TIFF*);
+
+int
+main(int argc, char* argv[])
+{
+ TIFF *in, *out;
+
+ if (argc < 2) {
+ fprintf(stderr, "%s\n\n", TIFFGetVersion());
+ fprintf(stderr, "usage: tiffsplit input.tif [prefix]\n");
+ return (-3);
+ }
+ if (argc > 2) {
+ strncpy(fname, argv[2], sizeof(fname));
+ fname[sizeof(fname) - 1] = '\0';
+ }
+ in = TIFFOpen(argv[1], "r");
+ if (in != NULL) {
+ do {
+ size_t path_len;
+ char *path;
+
+ newfilename();
+
+ path_len = strlen(fname) + sizeof(TIFF_SUFFIX);
+ path = (char *) _TIFFmalloc(path_len);
+ strncpy(path, fname, path_len);
+ path[path_len - 1] = '\0';
+ strncat(path, TIFF_SUFFIX, path_len - strlen(path) - 1);
+ out = TIFFOpen(path, TIFFIsBigEndian(in)?"wb":"wl");
+ _TIFFfree(path);
+
+ if (out == NULL)
+ return (-2);
+ if (!tiffcp(in, out))
+ return (-1);
+ TIFFClose(out);
+ } while (TIFFReadDirectory(in));
+ (void) TIFFClose(in);
+ }
+ return (0);
+}
+
+static void
+newfilename(void)
+{
+ static int first = 1;
+ static long lastTurn;
+ static long fnum;
+ static short defname;
+ static char *fpnt;
+
+ if (first) {
+ if (fname[0]) {
+ fpnt = fname + strlen(fname);
+ defname = 0;
+ } else {
+ fname[0] = 'x';
+ fpnt = fname + 1;
+ defname = 1;
+ }
+ first = 0;
+ }
+#define MAXFILES 17576
+ if (fnum == MAXFILES) {
+ if (!defname || fname[0] == 'z') {
+ fprintf(stderr, "tiffsplit: too many files.\n");
+ exit(1);
+ }
+ fname[0]++;
+ fnum = 0;
+ }
+ if (fnum % 676 == 0) {
+ if (fnum != 0) {
+ /*
+ * advance to next letter every 676 pages
+ * condition for 'z'++ will be covered above
+ */
+ fpnt[0]++;
+ } else {
+ /*
+ * set to 'a' if we are on the very first file
+ */
+ fpnt[0] = 'a';
+ }
+ /*
+ * set the value of the last turning point
+ */
+ lastTurn = fnum;
+ }
+ /*
+ * start from 0 every 676 times (provided by lastTurn)
+ * this keeps us within a-z boundaries
+ */
+ fpnt[1] = (char)((fnum - lastTurn) / 26) + 'a';
+ /*
+ * cycle last letter every file, from a-z, then repeat
+ */
+ fpnt[2] = (char)(fnum % 26) + 'a';
+ fnum++;
+}
+
+static int
+tiffcp(TIFF* in, TIFF* out)
+{
+ uint16 bitspersample, samplesperpixel, compression, shortv, *shortav;
+ uint32 w, l;
+ float floatv;
+ char *stringv;
+ uint32 longv;
+
+ CopyField(TIFFTAG_SUBFILETYPE, longv);
+ CopyField(TIFFTAG_TILEWIDTH, w);
+ CopyField(TIFFTAG_TILELENGTH, l);
+ CopyField(TIFFTAG_IMAGEWIDTH, w);
+ CopyField(TIFFTAG_IMAGELENGTH, l);
+ CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample);
+ CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
+ CopyField(TIFFTAG_COMPRESSION, compression);
+ if (compression == COMPRESSION_JPEG) {
+ uint16 count = 0;
+ void *table = NULL;
+ if (TIFFGetField(in, TIFFTAG_JPEGTABLES, &count, &table)
+ && count > 0 && table) {
+ TIFFSetField(out, TIFFTAG_JPEGTABLES, count, table);
+ }
+ }
+ CopyField(TIFFTAG_PHOTOMETRIC, shortv);
+ CopyField(TIFFTAG_PREDICTOR, shortv);
+ CopyField(TIFFTAG_THRESHHOLDING, shortv);
+ CopyField(TIFFTAG_FILLORDER, shortv);
+ CopyField(TIFFTAG_ORIENTATION, shortv);
+ CopyField(TIFFTAG_MINSAMPLEVALUE, shortv);
+ CopyField(TIFFTAG_MAXSAMPLEVALUE, shortv);
+ CopyField(TIFFTAG_XRESOLUTION, floatv);
+ CopyField(TIFFTAG_YRESOLUTION, floatv);
+ CopyField(TIFFTAG_GROUP3OPTIONS, longv);
+ CopyField(TIFFTAG_GROUP4OPTIONS, longv);
+ CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
+ CopyField(TIFFTAG_PLANARCONFIG, shortv);
+ CopyField(TIFFTAG_ROWSPERSTRIP, longv);
+ CopyField(TIFFTAG_XPOSITION, floatv);
+ CopyField(TIFFTAG_YPOSITION, floatv);
+ CopyField(TIFFTAG_IMAGEDEPTH, longv);
+ CopyField(TIFFTAG_TILEDEPTH, longv);
+ CopyField(TIFFTAG_SAMPLEFORMAT, shortv);
+ CopyField2(TIFFTAG_EXTRASAMPLES, shortv, shortav);
+ { uint16 *red, *green, *blue;
+ CopyField3(TIFFTAG_COLORMAP, red, green, blue);
+ }
+ { uint16 shortv2;
+ CopyField2(TIFFTAG_PAGENUMBER, shortv, shortv2);
+ }
+ CopyField(TIFFTAG_ARTIST, stringv);
+ CopyField(TIFFTAG_IMAGEDESCRIPTION, stringv);
+ CopyField(TIFFTAG_MAKE, stringv);
+ CopyField(TIFFTAG_MODEL, stringv);
+ CopyField(TIFFTAG_SOFTWARE, stringv);
+ CopyField(TIFFTAG_DATETIME, stringv);
+ CopyField(TIFFTAG_HOSTCOMPUTER, stringv);
+ CopyField(TIFFTAG_PAGENAME, stringv);
+ CopyField(TIFFTAG_DOCUMENTNAME, stringv);
+ CopyField(TIFFTAG_BADFAXLINES, longv);
+ CopyField(TIFFTAG_CLEANFAXDATA, longv);
+ CopyField(TIFFTAG_CONSECUTIVEBADFAXLINES, longv);
+ CopyField(TIFFTAG_FAXRECVPARAMS, longv);
+ CopyField(TIFFTAG_FAXRECVTIME, longv);
+ CopyField(TIFFTAG_FAXSUBADDRESS, stringv);
+ CopyField(TIFFTAG_FAXDCS, stringv);
+ if (TIFFIsTiled(in))
+ return (cpTiles(in, out));
+ else
+ return (cpStrips(in, out));
+}
+
+static int
+cpStrips(TIFF* in, TIFF* out)
+{
+ tsize_t bufsize = TIFFStripSize(in);
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
+
+ if (buf) {
+ tstrip_t s, ns = TIFFNumberOfStrips(in);
+ uint32 *bytecounts;
+
+ TIFFGetField(in, TIFFTAG_STRIPBYTECOUNTS, &bytecounts);
+ for (s = 0; s < ns; s++) {
+ if (bytecounts[s] > (uint32)bufsize) {
+ buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[s]);
+ if (!buf)
+ return (0);
+ bufsize = bytecounts[s];
+ }
+ if (TIFFReadRawStrip(in, s, buf, bytecounts[s]) < 0 ||
+ TIFFWriteRawStrip(out, s, buf, bytecounts[s]) < 0) {
+ _TIFFfree(buf);
+ return (0);
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+cpTiles(TIFF* in, TIFF* out)
+{
+ tsize_t bufsize = TIFFTileSize(in);
+ unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
+
+ if (buf) {
+ ttile_t t, nt = TIFFNumberOfTiles(in);
+ uint32 *bytecounts;
+
+ TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts);
+ for (t = 0; t < nt; t++) {
+ if (bytecounts[t] > (uint32) bufsize) {
+ buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[t]);
+ if (!buf)
+ return (0);
+ bufsize = bytecounts[t];
+ }
+ if (TIFFReadRawTile(in, t, buf, bytecounts[t]) < 0 ||
+ TIFFWriteRawTile(out, t, buf, bytecounts[t]) < 0) {
+ _TIFFfree(buf);
+ return (0);
+ }
+ }
+ _TIFFfree(buf);
+ return (1);
+ }
+ return (0);
+}
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/tiff/tools/ycbcr.c b/tiff/tools/ycbcr.c
new file mode 100644
index 0000000..8f72447
--- /dev/null
+++ b/tiff/tools/ycbcr.c
@@ -0,0 +1,168 @@
+float ycbcrCoeffs[3] = { .299, .587, .114 };
+/* default coding range is CCIR Rec 601-1 with no headroom/footroom */
+unsigned long refBlackWhite[6] = { 0, 255, 128, 255, 128, 255 };
+
+#define LumaRed ycbcrCoeffs[0]
+#define LumaGreen ycbcrCoeffs[1]
+#define LumaBlue ycbcrCoeffs[2]
+
+long eRtotal = 0;
+long eGtotal = 0;
+long eBtotal = 0;
+long preveRtotal = 0;
+long preveGtotal = 0;
+long preveBtotal = 0;
+unsigned long AbseRtotal = 0;
+unsigned long AbseGtotal = 0;
+unsigned long AbseBtotal = 0;
+unsigned long eCodes = 0;
+unsigned long preveCodes = 0;
+unsigned long eBits = 0;
+unsigned long preveBits = 0;
+
+static void setupLumaTables();
+static int abs(int v) { return (v < 0 ? -v : v); }
+static double pct(int v,double range) { return (v*100. / range); }
+static void check(int R, int G, int B);
+
+float D1, D2;
+float D3, D4;
+float D5, D6;
+
+int
+main(int argc, char** argv)
+{
+ int R, G, B;
+
+ if (argc > 1) {
+ refBlackWhite[0] = 16;
+ refBlackWhite[1] = 235;
+ refBlackWhite[2] = 128;
+ refBlackWhite[3] = 240;
+ refBlackWhite[4] = 128;
+ refBlackWhite[5] = 240;
+ }
+ D3 = 2 - 2*LumaRed;
+ D4 = 2 - 2*LumaBlue;
+ D1 = 1. / D3;
+ D2 = 1. / D4;
+ D5 = D3*LumaRed / LumaGreen;
+ D6 = D4*LumaBlue / LumaGreen;
+ setupLumaTables();
+ for (R = 0; R < 256; R++) {
+ for (G = 0; G < 256; G++)
+ for (B = 0; B < 256; B++)
+ check(R, G, B);
+ printf("[%3u] c %u/%u b %u/%u (R %u/%d/%u G %u/%d/%u B %u/%d/%u)\n"
+ , R
+ , eCodes - preveCodes, eCodes
+ , eBits - preveBits, eBits
+ , abs(AbseRtotal - preveRtotal), eRtotal , AbseRtotal
+ , abs(AbseGtotal - preveGtotal), eGtotal , AbseGtotal
+ , abs(AbseBtotal - preveBtotal), eBtotal , AbseBtotal
+ );
+ preveRtotal = AbseRtotal;
+ preveGtotal = AbseGtotal;
+ preveBtotal = AbseBtotal;
+ preveCodes = eCodes;
+ preveBits = eBits;
+ }
+ printf("%u total codes\n", 256*256*256);
+ printf("total error: %u codes %u bits (R %d/%u G %d/%u B %d/%u)\n"
+ , eCodes
+ , eBits
+ , eRtotal , AbseRtotal
+ , eGtotal , AbseGtotal
+ , eBtotal , AbseBtotal
+ );
+ return (0);
+}
+
+float *lumaRed;
+float *lumaGreen;
+float *lumaBlue;
+
+static float*
+setupLuma(float c)
+{
+ float *v = (float *)_TIFFmalloc(256 * sizeof (float));
+ int i;
+ for (i = 0; i < 256; i++)
+ v[i] = c * i;
+ return (v);
+}
+
+static void
+setupLumaTables(void)
+{
+ lumaRed = setupLuma(LumaRed);
+ lumaGreen = setupLuma(LumaGreen);
+ lumaBlue = setupLuma(LumaBlue);
+}
+
+static unsigned
+V2Code(float f, unsigned long RB, unsigned long RW, int CR)
+{
+ unsigned int c = (unsigned int)((((f)*(RW-RB)/CR)+RB)+.5);
+ return (c > 255 ? 255 : c);
+}
+
+#define Code2V(c, RB, RW, CR) ((((c)-(int)RB)*(float)CR)/(float)(RW-RB))
+
+#define CLAMP(f,min,max) \
+ (int)((f)+.5 < (min) ? (min) : (f)+.5 > (max) ? (max) : (f)+.5)
+
+static
+void
+check(int R, int G, int B)
+{
+ float Y, Cb, Cr;
+ int iY, iCb, iCr;
+ float rY, rCb, rCr;
+ float rR, rG, rB;
+ int eR, eG, eB;
+
+ Y = lumaRed[R] + lumaGreen[G] + lumaBlue[B];
+ Cb = (B - Y)*D2;
+ Cr = (R - Y)*D1;
+ iY = V2Code(Y, refBlackWhite[0], refBlackWhite[1], 255);
+ iCb = V2Code(Cb, refBlackWhite[2], refBlackWhite[3], 127);
+ iCr = V2Code(Cr, refBlackWhite[4], refBlackWhite[5], 127);
+ rCb = Code2V(iCb, refBlackWhite[2], refBlackWhite[3], 127);
+ rCr = Code2V(iCr, refBlackWhite[4], refBlackWhite[5], 127);
+ rY = Code2V(iY, refBlackWhite[0], refBlackWhite[1], 255);
+ rR = rY + rCr*D3;
+ rB = rY + rCb*D4;
+ rG = rY - rCb*D6 - rCr*D5;
+ eR = R - CLAMP(rR,0,255);
+ eG = G - CLAMP(rG,0,255);
+ eB = B - CLAMP(rB,0,255);
+ if (abs(eR) > 1 || abs(eG) > 1 || abs(eB) > 1) {
+ printf("R %u G %u B %u", R, G, B);
+ printf(" Y %g Cb %g Cr %g", Y, Cb, Cr);
+ printf(" iY %u iCb %u iCr %u", iY, iCb, iCr);
+ printf("\n -> Y %g Cb %g Cr %g", rY, rCb, rCr);
+ printf(" R %g (%u) G %g (%u) B %g (%u) E=[%d %d %d])\n"
+ , rR, CLAMP(rR,0,255)
+ , rG, CLAMP(rG,0,255)
+ , rB, CLAMP(rB,0,255)
+ , eR, eG, eB
+ );
+ }
+ eRtotal += eR;
+ eGtotal += eG;
+ eBtotal += eB;
+ AbseRtotal += abs(eR);
+ AbseGtotal += abs(eG);
+ AbseBtotal += abs(eB);
+ if (eR | eG | eB)
+ eCodes++;
+ eBits += abs(eR) + abs(eG) + abs(eB);
+}
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */
diff --git a/ttbd.txt b/ttbd.txt
new file mode 100644
index 0000000..925047a
--- /dev/null
+++ b/ttbd.txt
@@ -0,0 +1,327 @@
+Argyll - Things To Be Done (in no particular priority)
+--------------------------
+
+Categories:
+
+1) Active list
+2) General
+3) Documentation
+4) Charts
+5) Readings/Instruments
+6) Profiles
+6a) icclib
+7) Linking, gamut mapping
+7a) Profile/Link speedups
+8) Raster conversion
+9) Scanin
+10) Calibration
+11) Bugs
+
+--------------------------------------------------------
+ To be added:
+
+ add filtered mode for tiffgamut
+
+ add dispcal option to set white point to closest point
+ on the white locus to RBB 1 1 1
+
+ add option to dark cal spectro's evern N readings in dispsup.
+
+
+--------------------------------------------------------
+
+*) Add some i1pro RevE UV support for improved FWA
+
+*) Add "single pixel chart" mode to printtarg and scanin.
+
+--------------------------------------------------------
+1) List 2
+
+
+1a) Candidate list:
+
+* Get optimised separations working for CMY->CMYK & smoothed sep. option
+
+* Implement ICC V4
+
+* Add monochrome suppport
+
+* Fix plot to have seperate thread etc, and
+ add "save spectrum support" in spotread.
+
+* Fix xmatrix.c to allow for curve offset - this will
+ improve quality of non-calibrated display matrix profiles greatly.
+
+
+2) General:
+
+* Add full support for use as DLL/SO libraries
+
+* Check all executables & libraries with valgrind, and
+ clean up leaks and unitialised memory.
+
+* Merge changes from Rhett Sutphin into iccdump that support
+ dumping embeded profiles from known file formats.
+
+* Create a utility for converting color profiles to monochrome.
+ ie. CMYK -> K only, RGB -> R=G=B profile.
+ Have option for forcing the profile to be a color profile
+ but monochrome output.
+ Have an option for outputing a clut based or ICC monochrome profile.
+
+* Add support for ink-subset profiling, e.g.
+ Monochrome like inks only (light + K etc.).
+ For full support, would have to support gamut mapping
+ of 2D colorspaces.
+
+* Add support for an Argyll private ICC tag, and use it to
+ convey the device ink limit, and other profile creation
+ information for improved linking checking and convenience.
+
+* Add support for a (private tag) real gamut clut as a 3D
+ surface in profile.
+
+* Add > 4 color device optimised separations creation support.
+
+* Add optimised separations handling for CMYK profile generation option.
+
+* Switch to balltree acceleration for gamut and rspl rev code.
+
+* Switch to ball tree for targen spatial acceleration ??
+
+* Re-code all of argyll to be a consistent set of APIs,
+ to make it a full "library". Python interface ?
+
+* Fixup error and allocation code in all the Argyll libraries.
+ Add a better error reporting mechanism ?
+
+* Write utilities to convert ICC profiles into PostScript CSD and
+ CRD's.
+
+* Define an open operating system color service API, and reate
+ an example implementation with Argyll.
+
+* Make printspot more flexible - load spectrums, compare them
+ etc. - similar to Xrites DTP41 utility.
+
+* Create a device "linearity" measure utlity. Read in a CLUT
+ profile and compute the first and second differences of the grid.
+ Report grid res. scaled average & maximums ?
+ (What about input and output curve effects ? - sample overall
+ chacateristics ??)
+
+3) Documentation:
+
+* Add page on viewing condition parameters and typical values,
+ to link to from colprof, collink etc.
+
+* Add help in generating greyscale test charts into targen doco.(-f0 etc.)
+
+* Add doco on intependent verification of profile accuracy.
+
+* Document icclib api (Do this with V4 release!)
+
+* Document cgatslib api
+
+* Add "advanced scenarios" section to Argyll, to explain custom lighting,
+ FWA, proofing fine tuning, etc.
+
+
+
+4) Charts:
+
+* Fix i1pro chart to allow for arbitrary long paper.
+
+* Create a test chart specifically for establishing an ink limit ?
+
+* Should create a .ti2 template file for some standard charts,
+ such as an IT8.7/3, ECI2002 random and non-random etc.
+ Scanner recognition files too ??
+
+* Add an option to targen, that allows generation of
+ test points down the neutral axis (how does this work
+ for CMYK, since there are many possible values ?? -
+ use ppoint with 1D target and 2D device ??)
+ - try enhancing current CIE94 effect ??
+ + other memory colors like skin tones etc.
+
+* Started work on tiffsamp.c, but not complete.
+ Utility for creating representativ test points
+ from sample device images.
+
+* Create tool workflow to allow creating a "worst case"
+ verification chart based on the veronoi locations of
+ a chart used to create the profile needing verifying.
+
+
+5) Readings & Instruments:
+
+* In chartread, add RGB and Monochrome "generic"
+ profiles, so that bad readings can be recognised (??)
+
+* Create utility that translates between an XYZ only .ti3 and
+ an estimated spectral .ti3, based on a spectral .mpp,
+ to allow applying WFA compensation using non-spectral
+ instruments. (is this technically feasible ?)
+
+6) Profiles:
+
+* Determine typical statistical distribution of errors
+ in relation to Lab space, and use per sample point
+ weightings to apply more uncertaintly specific smoothing
+ factors.
+
+* Add option to use XYZ as PCS, and matrix in B2A table
+ to improve efficiency of B2A conversion (hence acuracy).
+
+* Investigate why using a black ink limit slows inversion down so much,
+ and see if the performance can be improved. Shift black ink limit
+ to be a calibration function ??
+
+* Add support in ICC profile for embedding the .ti3 CGATS data within
+ the profile. Add support for extracting it again in profile.
+
+* Add a custom tag that can encode a spectral A2B profile,
+ to support illunimant specification at link time ?
+
+* Add xicc support for creating monochrome profiles from
+ raw data.
+
+* Add support for regenerating perceptual and saturation
+ B2A tables in revfix. Rename utility ?
+
+* Can FWA compensation be improved in accuracy ? It seems to
+ over estimate FWA effect at high density of inks.
+ Is this due to scattering effects, asymetry in the filtering
+ effects of the colorant, or due to errors in estimating the
+ colorants filtering effects into the UV region ?
+
+* Modify rspl thin plate spines to have a "simplex" data
+ interpolation mode, rather than its "n-linear" one, for better
+ correspondence with how data is interpolated within the grid ?
+ (Is this really worth it ?)
+
+* Add smoothing for K locus generation for transtion to
+ ink limiting. Need to detect region near ink limit,
+ and then generate non-limited and limited values,
+ and then regenerate reverse value with blended K locus
+ target. Probably not important since ink limiting region
+ is often very dark, and optimised separations could be used as
+ an alternative mechanism.
+ [ Use optimized separations to fix this. ]
+
+* Add an option for input (and display ??) profiles to
+ include both matrix and Lut tables by default. (What PCS
+ should it use, XYZ for the matrix, or Lab for the
+ best quality Lut ?? What other CMS need such things ?)
+
+* Modify the rspl simplex code (and possibly imdi code)
+ to orient the simplexes in each cell to minimse the
+ expected curvature error at the center of each cell.
+ [ Partially implemented, but not complete.
+ Optimized separations is more important. ]
+
+
+6a) Icclib:
+
+* Re-architect icclib to allow for unknown datatypes,
+ dynamic custom tags, and full ICC V4 support.
+ [ In progress. icclib now supports unknown data types,
+ after back porting code from icclib4.]
+
+* Add full spot color library support
+
+* Change iccdump of Luts to dump PCS values as well as
+ normalised integer values (table entries and indexes ?)
+
+
+7) Linking, gamut mapping:
+
+* Add optimized per channel input/output curves
+ generation, rather than relying on the per channel
+ curves provided by the profiles (ie. xicc.c approach).
+
+* Would be nice to be able to weigh L errors more in
+ gamut clipping. Would have to introduce scaling factors
+ in rspl values to fake this without changing the
+ insides of RSPL.
+
+* Fix xicc library to handle matrix/shaper profile inversion
+ correctly, when the target is out of gamut. Don't clip in
+ device space, clip to nearest in CAM space ! (Fix after
+ iccV4 changes ?)
+
+* Fix xicc library to do better clipping for inputs that
+ are out of range of the core ICC lookup mechanisms.
+
+* Add flag to work with "preserve black" that forces K only
+ input to map to pure K only output, to suite use on press
+ re-targeting. How about creating a gamut mapping to do
+ this for arbatrary colorants ? - Can use "weak default mapping"
+ to help curve shape ? How to handle resulting gamut shape change ??
+
+* Add proper support for a "filtering" mode of black generation,
+ that smooths the black colorant target to take into account
+ gamut boundary issues. ie. revisit auxsmth.c ? Use optimised
+ separations mechansim instead ??
+
+* Add support in collink for linking with monochrome in and out
+ profiles. Gamut mapping needs to have monochrome bypass of
+ 3D mapping.
+
+* Add support for setting arbitrary colorant constraints
+ (ie. min/max/target, sum combinations)
+ This is linked with the ideas of culling the gamut to
+ avoid CMYK+ aliasing problems.
+
+7a) Profile/Link speedups
+
+* Investigate why rev_nnfind() is so slow. Can it be
+ improved ?
+
+* Add adaptive sampling reverse interpolation mode, to speedup
+ high res inverse tables. Look at approach Done Bone used
+ in adaptively measuring samples.
+
+* Add support in collink and colprof, for multi-threading
+ the reverse interpolation calculations. This will allow
+ great speedups when more than one processor is available.
+ Simplest approach is to have multiple instances of rspl,
+ and partition the problem into separate spaces (not interleaved).
+ Cache contents shouldn't duplicate then.
+ Multi-threading within rspl/rev would be complicated, and
+ may be slow due to contentions.
+
+
+8) Raster conversion:
+
+* Add support in IMDI for an auxiliary "calibration" or
+ "linearisation" table as a parameter to the setup.
+ [Calibration creation should allow for arbitrary curve
+ manipulation, such as limiting maximums (to replace
+ max K function), and other arbitrary curves.]
+
+* Add optimized per channel input/output curves
+ generation, rather than relying on the per channel
+ curves provided by the profiles (ie. xicc.c approach).
+
+9) Scanin
+
+* Add check in scanin that prints warning message if
+ patch variance is too high (probable faulty read).
+
+* Add spectral fix options to scanin code to allow compensation
+ for scanner and media errors when using a scanned image to
+ measure color.
+ This means figuring out how it will work, as well as creating
+ to tools to create the spectral fix data (or just add general
+ tweak/abstract profile support ?).
+
+* Modify scanin reference .cht format to be more robust (ie. CGATS)
+
+
+10) Bugs
+
+* filmtarg doesn't work any more with latest .ti1 data format.
+ Need to fix it.
+
diff --git a/tweak/Jamfile b/tweak/Jamfile
new file mode 100644
index 0000000..ec5beba
--- /dev/null
+++ b/tweak/Jamfile
@@ -0,0 +1,26 @@
+# JAM style makefile for tweak tools
+
+PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+#PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCPROFFLAG) ; # Profile flags
+#PREF_LINKFLAGS += $(LINKPROFFLAG) ; # Profile flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Link debugging flags
+
+#Products
+Executables = refine ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+
+HDRS = ../h ../icc ../cgats ../xicc ../spectro ../gamut
+ ../rspl ../numlib ../plot ;
+LINKLIBS = ../icc/libicc ../xicc/libxicc
+ ../spectro/libinsttypes ../gamut/libgamut
+ ../gamut/libgammap ../rspl/librspl
+ ../cgats/libcgats ../numlib/libnum
+ ../plot/libplot ../plot/libvrml $(LibWin) ;
+
+# Profile refiner
+Main refine : refine.c ;
+
diff --git a/tweak/License.txt b/tweak/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/tweak/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/tweak/Makefile.am b/tweak/Makefile.am
new file mode 100644
index 0000000..4cb59ba
--- /dev/null
+++ b/tweak/Makefile.am
@@ -0,0 +1,11 @@
+include $(top_srcdir)/Makefile.shared
+
+LDADD = ../spectro/libinsttypes.la ../gamut/libgamut.la \
+ ../gamut/libgammap.la ../plot/libvrml.la ../xicc/libxutils.la \
+ ../xicc/libxicc.la ../rspl/librspl.la ../gamut/libgamut.la \
+ ../gamut/libgammap.la $(ICC_LIBS) ../cgats/libcgats.la \
+ ../numlib/libargyllnum.la $(TIFF_LIBS)
+
+bin_PROGRAMS = refine
+
+EXTRA_DIST = License.txt Readme.txt
diff --git a/tweak/Readme.txt b/tweak/Readme.txt
new file mode 100644
index 0000000..a409b90
--- /dev/null
+++ b/tweak/Readme.txt
@@ -0,0 +1,5 @@
+This direcory holds general profile and device link
+tweaking, refining & adjustment code.
+
+refine allows the colorimetric B2A table of a profile to be refined
+ in the light of target and measured patch values.
diff --git a/tweak/afiles b/tweak/afiles
new file mode 100644
index 0000000..e455547
--- /dev/null
+++ b/tweak/afiles
@@ -0,0 +1,5 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+refine.c
diff --git a/tweak/refine.c b/tweak/refine.c
new file mode 100644
index 0000000..2d931ca
--- /dev/null
+++ b/tweak/refine.c
@@ -0,0 +1,1269 @@
+
+/*
+ * Create/modify an abstract ICC transformation that will
+ * correct measured color inacuracies of a proof reproduction.
+ * Input is a list of target and actual CIE values.
+ *
+ * Author: Graeme W. Gill
+ * Date: 12/5/05
+ * Version: 1.00
+ *
+ * Copyright 2005, 2008 Graeme W. Gill
+ * Please refer to License.txt file for details.
+ */
+
+/* TTBD:
+ *
+ */
+
+/* Basic idea:
+
+ Given to .ti3 files (or equivalent CGATS files), one containing a
+ spread of target patch values (XYZ, Lab or spectral), and the
+ other containing the corresponding measured values, a PCS->PCS
+ correction RSPL mapping is created to adjust for any innacuracy
+ in the B2A table, which is then used to refine an existing abstract
+ correction profile. (Any device values in the .ti3 tables are ignored.)
+
+ The refined abstract profile can then be used to create an adjusted
+ device profile, or an adjusted device link.
+
+ Complications are:
+
+ Measurements are absolute, while an abstract profile
+ is relative.
+ - use flag to mark this when abstract is used, or mark in profile header ?
+
+ Corrections shouldn't go outside the target devices gamut, or
+ they will lead to out of control regions on the gamut surface.
+ - need output profile to clip changes to gamut surface.
+
+ Refinement feedback could go unstable.
+ - use a damping factor to improve stability.
+
+ Currently the way out of gamut value are handled is to
+ allow a full attempt at correction for the first round,
+ and then constrain any subsequent corrections to be
+ of no greater magnitude than that first correction.
+ Subsequent corrections can change the direction of
+ correction, but cannot increase its magnitude. This
+ seems to work OK with light out of gamut colors,
+ but dark CMYK out of gamut colors sometimes regress at
+ the first step, possibly because of the gamut boundary
+ topolgy in those regions.
+
+ Interestingly, for CMYK the results are most stable (in simulation)
+ when applied to the simple linked device link, and tends to
+ be slightly unstable when applied to inverse A2B lookups
+ that are used in profile and icclink -G. This could be a symptom
+ of the black generation non-uniformity problem causing instability
+ in the black inversion. Moving to optimised separation CMYK
+ profile generation might overcome this problem.
+
+ NOTE:- the current value for the rspl weak default weight seems OK
+ for a reasonable number of points, but if refine was to be used for
+ arbitrary tweaking, it should probably be made a tunable parameter
+ that affects the radius of influence of each adjustment point.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "rspl.h"
+#include "xicc.h"
+#include "xicc.h"
+
+#define COMPLOOKUP /* Compound with previous in ICM lookup rather than rspl */
+#undef WARN_CLUT_CLIPPING /* [Undef] Print warning if setting clut clips */
+#undef DEBUG1 /* Print each correction value */
+#undef DEBUG2 /* Print each value changed */
+#undef DEBUG3 /* Trace history of particular points */
+
+#define verbo stdout
+
+#define RSPLFLAGS (0 /* | RSPL_2PASSSMTH | RSPL_EXTRAFIT2 */)
+
+#define DEF_DAMP1 0.95 /* Initial */
+#define DEF_DAMP2 0.70 /* Subsequent */
+#define DEF_CLUTRES 33
+#define GAMRES 10.0
+#define SMOOTHF 0.3 /* RSPL smoothing factor */
+#define AVGDEV 0.003 /* Average deviation of input values */
+#define WWEIGHT 1.0 /* weak default function weight */
+#define WHITEWEIGHT 5.0 /* Weight to put on discovered white correction */
+
+#ifdef DEBUG3
+/* Debug points of interest */
+int poi[] = {
+ 8,
+ 15,
+ 10,
+ 14,
+ 380,
+ 274,
+ 562,
+ 172,
+ 510,
+ 331,
+ 297,
+ 494,
+ 102,
+ 18,
+ 13,
+ 6,
+ 305,
+ 61,
+ 455,
+ 63,
+ 461,
+ 68,
+ 7,
+ 369,
+ 211,
+ 42,
+ 427,
+ 113,
+ 204,
+ 224,
+ 334,
+ 28,
+ 175,
+ 330,
+ 273,
+ 376,
+ 318,
+ 44,
+ 57,
+ 469,
+ 9,
+ 85,
+ 278,
+ 414,
+ 124,
+ -1
+};
+
+#endif /* DEBUG3 */
+
+void usage(char *diag, ...) {
+ fprintf(stderr,"Create abstract correction profile given table of absolute CIE correction values, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: refine [-options] cietarget ciecurrent [outdevicc] [inabs] outabs\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -c Create initial abstract correction profile\n");
+ fprintf(stderr," -g Don't impose output device gamut limit\n");
+ fprintf(stderr," -r res Set abstract profile clut resolution (default %d)\n",DEF_CLUTRES);
+ fprintf(stderr," -d factor Override default damping factor (default %f, then %f)\n",DEF_DAMP1,DEF_DAMP2);
+ fprintf(stderr," -R Aim for white point relative match rather than absolute\n");
+ 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");
+ 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," cietarget Target CIE or spectral values, CGATS file (e.g. .ti3)\n");
+ fprintf(stderr," ciecurrent Actual CIE or spectral values, CGATS file (e.g. .ti3)\n");
+ fprintf(stderr," [outdevicc] Output device ICC profile to set gamut limit (not used if -g)\n");
+ fprintf(stderr," [inabs] Previous abstract correction ICC profile (not used if -c)\n");
+ fprintf(stderr," outabs Created/refined abstract correction ICC profile\n");
+ exit(1);
+}
+
+/* ------------------------------------------- */
+/* structure to support icc Lut initialisation/modification calbacks */
+
+struct _callback {
+ int verb; /* Verbosity */
+ int total, count, last; /* Progress count information */
+ rspl *r; /* correction transform */
+ icmLuBase *rd_luo; /* Existing abstract profile (NULL if none) */
+ gamut *dev_gam; /* Gamut of output device (NULL if none) */
+}; typedef struct _callback callback;
+
+
+/* - - - - */
+/* clut */
+
+/* New CLUT table */
+/* Correct for PCS errors */
+void PCSp_PCSp(void *cntx, double *out, double *in) {
+ callback *p = (callback *)cntx;
+ co pp;
+
+#ifdef DEBUG2
+ printf("Got Lab in %f %f %f\n",in[0],in[1],in[2]);
+#endif
+
+ pp.p[0] = in[0];
+ pp.p[1] = in[1];
+ pp.p[2] = in[2];
+ p->r->interp(p->r, &pp); /* This correction */
+ out[0] = pp.v[0];
+ out[1] = pp.v[1];
+ out[2] = pp.v[2];
+
+#ifdef COMPLOOKUP
+ /* Compound with previous correction */
+ if (p->rd_luo != NULL) {
+ p->rd_luo->lookup(p->rd_luo, out, out); /* Previous correction */
+ }
+#endif
+
+#ifdef DEBUG2
+ printf("Got Lab out %f %f %f\n",out[0],out[1],out[2]);
+ printf("\n");
+#endif
+
+ if (p->verb) { /* Output percent intervals */
+ int pc;
+ p->count++;
+ pc = p->count * 100.0/p->total + 0.5;
+ if (pc != p->last) {
+ printf("%c%2d%%",cr_char,pc), fflush(stdout);
+ p->last = pc;
+ }
+ }
+}
+
+/* ------------------------------------------- */
+
+/* Patch value type */
+typedef struct {
+ char sid[50]; /* sample id */
+ double v[3]; /* CIE value */
+ double de; /* Delta E */
+} pval;
+
+/* Weak default function */
+static void wfunc(void *cbntx, double *out, double *in) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ struct {
+ char name[MAXNAMEL+1]; /* Patch filename */
+ int npat; /* Number of patches */
+ pval *pat; /* patch values */
+ } cg[2]; /* Target and current patch file information */
+ char dev_name[MAXNAMEL+1]; /* Output device ICC filename for gamut */
+ char rd_name[MAXNAMEL+1]; /* Abstract profile ICC to modify */
+ char wr_name[MAXNAMEL+1]; /* Modified/created abstract profile ICC */
+
+ int dorel = 0; /* Do white point relative match */
+ int *match; /* Array mapping first list indexes to corresponding second */
+ int fwacomp = 0; /* FWA compensation on spectral ? */
+ int spec = 0; /* Use spectral data flag */
+ icxIllumeType tillum = icxIT_none; /* Target/simulated instrument illuminant */
+ xspect cust_tillum, *tillump = NULL; /* Custom target/simulated illumination spectrum */
+ icxIllumeType illum = icxIT_D50; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxObserverType observ = icxOT_Judd_Voss_2;
+ callback cb; /* Callback support stucture for setting abstract profile */
+
+ icmFile *rd_fp = NULL; /* Existing abstract profile to modify */
+ icc *rd_icc = NULL;
+
+ icmFile *wr_fp; /* Modified/created abstract profile to write */
+ icc *wr_icc;
+
+ int verb = 0;
+ int nogamut = 0; /* Don't impose a gamut limit */
+ int docreate = 0; /* Create an initial abstract correction profile */
+ int clutres = DEF_CLUTRES; /* Output abstract profile clut resolution */
+ double damp1 = DEF_DAMP1; /* Initial damping factor */
+ double damp2 = DEF_DAMP2; /* Subsequent damping factor */
+ double smoothf = SMOOTHF; /* RSPL Smoothing factor */
+ double avgdev[MXDO]; /* RSPL Average Deviation */
+ double wweight = WWEIGHT; /* weak default function weight */
+ int whitepatch = -1; /* Index of white patch */
+ double merr = 0.0, aerr = 0.0; /* Stats on color change */
+ int i, j, e, n, rv = 0;
+
+ error_program = argv[0];
+ check_if_not_interactive();
+
+ if (argc < 6)
+ usage("Too few arguments");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Usage requested");
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v') {
+ verb = 1;
+ }
+ /* Create initial abstract correction profile */
+ else if (argv[fa][1] == 'c') {
+ docreate = 1;
+ }
+ /* Don't impose a gamut limit */
+ else if (argv[fa][1] == 'g') {
+ nogamut = 1;
+ }
+ /* Override the correction clut resolution */
+ else if (argv[fa][1] == 'r') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -r");
+ clutres = atoi(na);
+ }
+ /* Override the damping factor */
+ else if (argv[fa][1] == 'd') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -d");
+ damp2 = atof(na);
+ }
+ /* Aim for white point relative match */
+ else if (argv[fa][1] == 'R') {
+ dorel = 1;
+ }
+
+ /* FWA compensation */
+ else if (argv[fa][1] == 'f') {
+ fwacomp = 1;
+
+ if (na != NULL) { /* Argument is present - target/simulated instr. illum. */
+ fa = nfa;
+ if (strcmp(na, "A") == 0
+ || strcmp(na, "M0") == 0) {
+ spec = 1;
+ tillum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ tillum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0
+ || strcmp(na, "M1") == 0) {
+ spec = 1;
+ tillum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0
+ || strcmp(na, "M2") == 0) {
+ spec = 1;
+ tillum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ tillum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ tillum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ tillum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ tillum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ tillum = icxIT_custom;
+ if (read_xspect(&cust_tillum, na) != 0)
+ usage("Unable to read custom spectrum '%s'",na);
+ }
+ }
+ }
+
+ /* Spectral to CIE Illuminant type */
+ else if (argv[fa][1] == 'i') {
+ fa = nfa;
+ if (na == NULL) usage("Expect argument to -i");
+ if (strcmp(na, "A") == 0) {
+ spec = 1;
+ illum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ illum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0) {
+ spec = 1;
+ illum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0) {
+ spec = 1;
+ illum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ illum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ illum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ illum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ illum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ illum = icxIT_custom;
+ if (read_xspect(&cust_illum, na) != 0)
+ usage("Unable to read custom spectrum '%s'",na);
+ }
+ }
+
+ /* Spectral Observer type */
+ else if (argv[fa][1] == 'o') {
+ fa = nfa;
+ if (na == NULL) usage("Expected argument to -o");
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ spec = 1;
+ observ = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ spec = 1;
+ observ = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ spec = 1;
+ observ = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ spec = 1;
+ observ = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ spec = 1;
+ observ = icxOT_Shaw_Fairchild_2;
+ } else
+ usage("Unrecogised argument '%s' to -o",na);
+ }
+
+ else
+ usage("Unrecognised flag -%c",argv[fa][1]);
+ } else
+ break;
+ }
+
+ /* Grab all the filenames: */
+
+ /* The two CIE value files */
+ if (fa >= argc || argv[fa][0] == '-') usage("Expected cietarget file argument");
+ strncpy(cg[0].name,argv[fa++],MAXNAMEL); cg[0].name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Expected ciecurrent file argument");
+ strncpy(cg[1].name,argv[fa++],MAXNAMEL); cg[1].name[MAXNAMEL] = '\000';
+
+ /* Optional output device name */
+ if (nogamut == 0) {
+ if (fa >= argc || argv[fa][0] == '-') usage("Expected outdevicc file argument");
+ strncpy(dev_name,argv[fa++],MAXNAMEL); dev_name[MAXNAMEL] = '\000';
+ }
+
+ /* Optional input abstract profile name */
+ if (docreate == 0) {
+ if (fa >= argc || argv[fa][0] == '-') usage("Expected inabs file argument");
+ strncpy(rd_name,argv[fa++],MAXNAMEL); rd_name[MAXNAMEL] = '\000';
+ }
+
+ /* Output abstract profile name */
+ if (fa >= argc || argv[fa][0] == '-') usage("Expected outabs file argument");
+ strncpy(wr_name,argv[fa++],MAXNAMEL); wr_name[MAXNAMEL] = '\000';
+
+ /* ======================= */
+ /* Open up each CIE 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 xix, yix, zix;
+
+ /* Open CIE target values */
+ cgf = new_cgats(); /* Create a CGATS structure */
+ cgf->add_other(cgf, ""); /* Allow any signature file */
+
+ if (cgf->read_name(cgf, cg[n].name))
+ error("CGATS file '%s' read error : %s",cg[n].name,cgf->err);
+
+ if (cgf->ntables < 1)
+ error ("Input file '%s' doesn't contain at least one table",cg[n].name);
+
+ /* Check if the file is suitable */
+ if (!spec
+ && cgf->find_field(cgf, 0, "LAB_L") < 0
+ && cgf->find_field(cgf, 0, "XYZ_X") < 0) {
+
+ if (cgf->find_kword(cgf, 0, "SPECTRAL_BANDS") < 0)
+ error ("Neither CIE nor spectral data found in file '%s'",cg[n].name);
+
+ /* Switch to using spectral information */
+ if (verb)
+ printf("No CIE data found, switching to spectral with standard observer & D50 for file '%s'\n",cg[n].name);
+ spec = 1;
+ illum = icxIT_D50;
+ observ = icxOT_CIE_1931_2;
+ }
+ if (spec && cgf->find_kword(cgf, 0, "SPECTRAL_BANDS") < 0)
+ error ("No spectral data data found in file '%s' when spectral expected",cg[n].name);
+
+ if (!spec && cgf->find_field(cgf, 0, "LAB_L") >= 0)
+ isLab = 1;
+
+ cg[n].npat = cgf->t[0].nsets; /* Number of patches */
+
+ /* Read all the target patches */
+ if (cg[n].npat <= 0)
+ error("No sets of data in file '%s'",cg[n].name);
+
+ if (verb && n == 0) {
+ fprintf(verbo,"No of test patches = %d\n",cg[n].npat);
+ }
+
+ /* Allocate arrays to hold test patch input and output values */
+ if ((cg[n].pat = (pval *)malloc(sizeof(pval) * cg[n].npat)) == NULL)
+ error("Malloc failed - pat[]");
+
+ /* Read in the CGATs fields */
+ if ((sidx = cgf->find_field(cgf, 0, "SAMPLE_ID")) < 0
+ && (sidx = cgf->find_field(cgf, 0, "SampleName")) < 0
+ && (sidx = cgf->find_field(cgf, 0, "Sample_Name")) < 0
+ && (sidx = cgf->find_field(cgf, 0, "SAMPLE_NAME")) < 0
+ && (sidx = cgf->find_field(cgf, 0, "SAMPLE_LOC")) < 0)
+ error("Input file '%s' doesn't contain field SAMPLE_ID, SampleName, Sample_Name, SAMPLE_NAME or SAMPLE_LOC",cg[n].name);
+ if (cgf->t[0].ftype[sidx] != nqcs_t
+ && cgf->t[0].ftype[sidx] != cs_t)
+ error("Sample ID/Name field isn't a quoted or non quoted character string");
+
+ if (spec == 0) { /* Using instrument tristimulous value */
+
+ if (isLab) { /* Expect Lab */
+ if ((xix = cgf->find_field(cgf, 0, "LAB_L")) < 0)
+ error("Input file '%s' doesn't contain field LAB_L",cg[n].name);
+ if (cgf->t[0].ftype[xix] != r_t)
+ error("Field LAB_L is wrong type");
+ if ((yix = cgf->find_field(cgf, 0, "LAB_A")) < 0)
+ error("Input file '%s' doesn't contain field LAB_A",cg[n].name);
+ if (cgf->t[0].ftype[yix] != r_t)
+ error("Field LAB_A is wrong type");
+ if ((zix = cgf->find_field(cgf, 0, "LAB_B")) < 0)
+ error("Input file '%s' doesn't contain field LAB_B",cg[n].name);
+ if (cgf->t[0].ftype[zix] != r_t)
+ error("Field LAB_B is wrong type");
+
+ } else { /* Expect XYZ */
+ if ((xix = cgf->find_field(cgf, 0, "XYZ_X")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_X",cg[n].name);
+ if (cgf->t[0].ftype[xix] != r_t)
+ error("Field XYZ_X is wrong type");
+ if ((yix = cgf->find_field(cgf, 0, "XYZ_Y")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Y",cg[n].name);
+ if (cgf->t[0].ftype[yix] != r_t)
+ error("Field XYZ_Y is wrong type");
+ if ((zix = cgf->find_field(cgf, 0, "XYZ_Z")) < 0)
+ error("Input file '%s' doesn't contain field XYZ_Z",cg[n].name);
+ if (cgf->t[0].ftype[zix] != r_t)
+ error("Field XYZ_Z is wrong type");
+ }
+
+ 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) {
+ cg[n].pat[i].v[0] /= 100.0; /* Normalise XYZ to range 0.0 - 1.0 */
+ cg[n].pat[i].v[1] /= 100.0;
+ cg[n].pat[i].v[2] /= 100.0;
+ }
+ if (!isLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
+ icmXYZ2Lab(&icmD50, cg[n].pat[i].v, cg[n].pat[i].v);
+ }
+ }
+
+ } else { /* Using spectral data */
+ int ii;
+ xspect sp;
+ char buf[100];
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xsp2cie *sp2cie; /* Spectral conversion object */
+
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ sp.spec_n = atoi(cgf->t[0].kdata[ii]);
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ sp.spec_wl_short = atof(cgf->t[0].kdata[ii]);
+ if ((ii = cgf->find_kword(cgf, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ sp.spec_wl_long = atof(cgf->t[0].kdata[ii]);
+ sp.norm = 100.0;
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = cgf->find_field(cgf, 0, buf)) < 0)
+ error("Input file doesn't contain field %s",buf);
+ }
+
+ /* Figure out what sort of device it is */
+ {
+ int ti;
+
+ 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) {
+ illum = icxIT_none; /* Displays are assumed to be self luminous */
+ }
+ }
+
+ /* Create a spectral conversion object */
+ if ((sp2cie = new_xsp2cie(illum, illum == icxIT_none ? NULL : &cust_illum,
+ observ, NULL, icSigLabData, icxClamp)) == NULL)
+ error("Creation of spectral conversion object failed");
+
+ if (fwacomp) {
+ int ti;
+ xspect mwsp; /* Medium spectrum */
+ instType itype; /* Spectral instrument type */
+ xspect insp; /* Instrument illuminant */
+
+ mwsp = sp; /* Struct copy */
+
+ if ((ti = cgf->find_kword(cgf, 0, "TARGET_INSTRUMENT")) < 0)
+ error ("Can't find target instrument in '%s' needed for FWA compensation",cg[n].name);
+
+ if ((itype = inst_enum(cgf->t[0].kdata[ti])) == instUnknown)
+ error ("Unrecognised target instrument '%s'", cgf->t[0].kdata[ti]);
+
+ if (inst_illuminant(&insp, itype) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+
+ /* Determine a media white spectral reflectance */
+ for (j = 0; j < mwsp.spec_n; j++)
+ mwsp.spec[j] = 0.0;
+
+ /* Track the maximum reflectance for any band to determine white. */
+ /* This might silently fail, if there isn't white in the sampe set. */
+ for (i = 0; i < cg[0].npat; i++) {
+ for (j = 0; j < mwsp.spec_n; j++) {
+ double rv = *((double *)cgf->t[0].fdata[i][spi[j]]);
+ if (rv > mwsp.spec[j])
+ mwsp.spec[j] = rv;
+ }
+ }
+
+ /* If we are setting a specific simulated instrument illuminant */
+ if (tillum != icxIT_none) {
+ tillump = &cust_tillum;
+ if (tillum != icxIT_custom) {
+ if (standardIlluminant(tillump, tillum, 0.0)) {
+ error("simulated inst. illum. not recognised");
+ }
+ }
+ }
+
+ if (sp2cie->set_fwa(sp2cie, &insp, tillump, &mwsp))
+ error ("Set FWA on sp2cie failed");
+ }
+
+ for (i = 0; i < cg[0].npat; i++) {
+
+ strcpy(cg[n].pat[i].sid, (char *)cgf->t[0].fdata[i][sidx]);
+
+ /* Read the spectral values for this patch */
+ for (j = 0; j < sp.spec_n; j++) {
+ sp.spec[j] = *((double *)cgf->t[0].fdata[i][spi[j]]);
+ }
+
+ /* Convert it to CIE space */
+ sp2cie->convert(sp2cie, cg[n].pat[i].v, &sp);
+ }
+
+ sp2cie->del(sp2cie); /* Done with this */
+
+ } /* End of reading in CGATs file */
+ cgf->del(cgf); /* Clean up */
+ }
+
+ /* Check that the number of test patches matches */
+ if (cg[0].npat != cg[1].npat)
+ error("Number of patches between '%s' and '%s' doesn't match",cg[0].name,cg[1].name);
+
+ /* Create a list to map the second list (measured) of patches to the first (target) */
+ if ((match = (int *)malloc(sizeof(int) * cg[0].npat)) == NULL)
+ error("Malloc failed - match[]");
+ for (i = 0; i < cg[0].npat; i++) {
+ for (j = 0; j < cg[1].npat; j++) {
+ if (strcmp(cg[0].pat[i].sid, cg[1].pat[j].sid) == 0)
+ break; /* Found it */
+ }
+ if (j < cg[1].npat) {
+ match[i] = j;
+ } else {
+ error("Failed to find matching patch to '%s'",cg[0].pat[i].sid);
+ }
+ }
+
+ /* Try and figure out which is the white patch */
+ {
+ double hL = -1.0;
+ for (i = 0; i < cg[0].npat; i++) {
+ if (cg[0].pat[i].v[0] > hL) {
+ hL = cg[0].pat[i].v[0];
+ whitepatch = i;
+ }
+ }
+ }
+
+ /* If we are aiming for a white point relative match, adjust the */
+ /* measured and target values to have a D50 white point */
+ if (dorel) {
+ for (n = 0; n < 2; n++) {
+ int wpix; /* White patch index */
+ double wp_xyz[3];
+ icmXYZNumber wp; /* White value */
+ double mat[3][3]; /* Chromatic transform */
+
+ if (n == 0)
+ wpix = whitepatch;
+ else
+ wpix = match[whitepatch];
+
+
+ /* Compute a chromatic correction matrix */
+ icmLab2XYZ(&icmD50, wp_xyz, cg[n].pat[wpix].v);
+ icmAry2XYZ(wp, wp_xyz);
+
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, wp, mat);
+
+ for (i = 0; i < cg[n].npat; i++) {
+ icmLab2XYZ(&icmD50, cg[n].pat[i].v, cg[n].pat[i].v);
+ icmMulBy3x3(cg[n].pat[i].v, mat, cg[n].pat[i].v);
+ icmXYZ2Lab(&icmD50, cg[n].pat[i].v, cg[n].pat[i].v);
+//printf("Table %d, patch %d, Lab %f %f %f\n",n,i,cg[n].pat[i].v[0],cg[n].pat[i].v[1],cg[n].pat[i].v[2]);
+ }
+ }
+ }
+
+ /* Compute the delta E's just for information */
+ for (i = 0; i < cg[0].npat; i++) {
+ double de = icmLabDE(cg[0].pat[i].v, cg[1].pat[match[i]].v);
+ cg[0].pat[i].de = de;
+ if (de > merr)
+ merr = de;
+ aerr += de;
+ }
+ if (cg[0].npat > 0)
+ aerr /= (double)cg[0].npat;
+
+ if (verb) {
+ fprintf(verbo,"No of correction patches = %d\n",cg[0].npat);
+ fprintf(verbo,"Average dE = %f, Maximum dE = %f\n",aerr,merr);
+ fprintf(verbo,"White patch assumed to be patch %s\n",cg[0].pat[whitepatch].sid);
+ }
+
+ /* ======================= */
+ /* Possible limiting gamut */
+ if (nogamut == 0) {
+ icmFile *dev_fp;
+ icc *dev_icc;
+ xicc *dev_xicc;
+ icxLuBase *dev_luo;
+ icxInk ink; /* Ink parameters */
+
+ /* Open up the device ICC profile, so that we can create a gamut */
+ /* and get an absolute PCS->device conversion */
+ if ((dev_fp = new_icmFileStd_name(dev_name,"r")) == NULL)
+ error ("Can't open file '%s'",dev_name);
+
+ if ((dev_icc = new_icc()) == NULL)
+ error("Creation of ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = dev_icc->read(dev_icc,dev_fp,0)) != 0)
+ error("Reading profile '%s' failed: %d, %s",dev_name,rv,dev_icc->err);
+
+ /* Check that the profile is appropriate */
+ if (dev_icc->header->deviceClass != icSigInputClass
+ && dev_icc->header->deviceClass != icSigDisplayClass
+ && dev_icc->header->deviceClass != icSigOutputClass)
+ error("Device Profile '%s' isn't a device profile",dev_name);
+
+ ink.tlimit = -1.0; /* No ink limit by default */
+ ink.klimit = -1.0;
+
+ /* Wrap with an expanded icc */
+ if ((dev_xicc = new_xicc(dev_icc)) == NULL)
+ error ("Creation of xicc failed");
+
+ /* Use a heuristic to guess the ink limit */
+ icxGetLimits(dev_xicc, &ink.tlimit, &ink.klimit);
+ ink.tlimit += 0.05; /* allow a slight margine */
+
+ if (verb)
+ printf("Estimated Total inklimit is %f%%, Black %f%% \n",100.0 * ink.tlimit,ink.klimit < 0.0 ? 100.0 : 100.0 * ink.klimit);
+
+ /* Get a expanded color conversion object suitable for gamut */
+ if ((dev_luo = dev_xicc->get_luobj(dev_xicc, ICX_CLIP_NEAREST, icmFwd,
+ dorel ? icRelativeColorimetric : icAbsoluteColorimetric,
+ icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
+ error ("%d, %s",dev_xicc->errc, dev_xicc->err);
+
+ /* Creat a gamut surface */
+ if ((cb.dev_gam = dev_luo->get_gamut(dev_luo, GAMRES)) == NULL)
+ error ("%d, %s",dev_xicc->errc, dev_xicc->err);
+
+ dev_luo->del(dev_luo);
+ dev_xicc->del(dev_xicc);
+ dev_icc->del(dev_icc);
+ dev_fp->del(dev_fp);
+ } else {
+ cb.dev_gam = NULL;
+ }
+
+ /* ======================= */
+ /* Open up the existing abstract profile that is to be refined. */
+ if (docreate == 0) {
+ if ((rd_fp = new_icmFileStd_name(rd_name,"r")) == NULL)
+ error ("Can't open file '%s'",rd_name);
+
+ if ((rd_icc = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = rd_icc->read(rd_icc,rd_fp,0)) != 0)
+ error ("%d, %s",rv,rd_icc->err);
+
+ if (rd_icc->header->deviceClass != icSigAbstractClass)
+ error("Input Profile '%s' isn't abstract type",rd_name);
+
+ if ((cb.rd_luo = rd_icc->get_luobj(rd_icc, icmFwd,
+ dorel ? icRelativeColorimetric : icAbsoluteColorimetric,
+ icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icc->errc, rd_icc->err);
+ } else {
+ cb.rd_luo = NULL;
+ }
+
+ /* ======================= */
+ /* Create refining rspl */
+ {
+ cow *rp; /* rspl setup points */
+ int npnts = 0; /* Total number of test points */
+ int gres[MXDI]; /* rspl grid resolution */
+ double damp;
+ datai mn, mx;
+
+ if ((rp = (cow *)malloc(sizeof(cow) * cg[0].npat)) == NULL)
+ error("Malloc failed - rp[]");
+
+ /* Create mapping points */
+ for (i = 0; i < cg[0].npat; i++) {
+ double temp[3];
+ double ccor[3], cmag; /* Current correction vector */
+ double ncor[3], nmag; /* New correction vector */
+
+ /* Input is target [0] */
+ for (j = 0; j < 3; j++)
+ rp[i].p[j] = cg[0].pat[i].v[j];
+
+ /* Cull out of range points */
+ if (rp[i].p[0] < 0.0 || rp[i].p[0] > 100.0
+ || rp[i].p[1] < -127.0 || rp[i].p[1] > 127.0
+ || rp[i].p[2] < -127.0 || rp[i].p[2] > 127.0) {
+#ifdef DEBUG1
+ printf("Ignoring %f %f %f\n",rp[i].p[0],rp[i].p[1],rp[i].p[2]);
+#endif
+ continue;
+ }
+
+#ifdef DEBUG1
+ printf("%d: Target %f %f %f\n",i,rp[i].p[0],rp[i].p[1],rp[i].p[2]);
+#endif
+
+ damp = cb.rd_luo != NULL ? damp2 : damp1;
+ ccor[0] = ccor[1] = ccor[2] = 0.0;
+ cmag = 0.0;
+
+ /* Lookup the current correction applied to the target */
+ if (cb.rd_luo != NULL) { /* Subsequent pass */
+ double corval[3];
+ cb.rd_luo->lookup(cb.rd_luo, corval, cg[0].pat[i].v);
+ icmSub3(ccor, corval, cg[0].pat[i].v);
+ cmag = icmNorm3(ccor);
+#ifdef DEBUG1
+ printf("%d: ccor %f %f %f, mag %f\n",i, ccor[0],ccor[1],ccor[2],cmag);
+#endif
+ }
+
+ /* Create a trial 100% full correction point */
+ for (j = 0; j < 3; j++)
+ rp[i].v[j] = ccor[j] + 2.0 * cg[0].pat[i].v[j] - cg[1].pat[match[i]].v[j];
+
+ /* If a first pass and the target or the correction are out of gamut, */
+ /* use a damping factor of 1.0 */
+ if (cb.rd_luo == NULL
+ && cb.dev_gam != NULL
+ && cb.dev_gam->nradial(cb.dev_gam, temp, rp[i].p) > 1.0
+ && cb.dev_gam->nradial(cb.dev_gam, temp, rp[i].v) > 1.0) {
+ damp = 1.0;
+ }
+
+#ifdef DEBUG1
+ printf("%d: damp = %f\n",i, damp);
+#endif
+
+ /* Create a new correction that does a damped correction to the current error */
+ /* [0] = target, [1] = measured */
+ for (j = 0; j < 3; j++)
+ ncor[j] = ccor[j] + damp * (cg[0].pat[i].v[j] - cg[1].pat[match[i]].v[j]);
+ nmag = icmNorm3(ncor);
+
+#ifdef DEBUG1
+ printf("%d: ncor %f %f %f, mag %f\n",i, ncor[0],ncor[1],ncor[2],nmag);
+#endif
+
+ /* If this is not the first pass, limit the new correction */
+ /* to be 1 + damp as big as the previous correction */
+ if (cb.rd_luo != NULL) {
+ if ((nmag/cmag) > (1.0 + damp2)) {
+#ifdef DEBUG1
+ printf("%d: Limited cor mag from %f to %f\n",i, nmag, (1.0 + damp2) * cmag);
+#endif
+ icmScale3(ncor, ncor, (1.0 + damp2) * cmag/nmag);
+ }
+ }
+
+ /* Create correction point */
+ for (j = 0; j < 3; j++)
+ rp[i].v[j] = cg[0].pat[i].v[j] + ncor[j];
+
+ /* If the target point or corrected point is likely to be outside */
+ /* the gamut, limit the magnitude of the correction to be the same */
+ /* as the previous correction. */
+ if (cb.rd_luo != NULL && cb.dev_gam != NULL) {
+ if (cb.dev_gam->nradial(cb.dev_gam, temp, rp[i].p) > 1.0
+ || cb.dev_gam->nradial(cb.dev_gam, temp, rp[i].v) > 1.0) {
+#ifdef DEBUG1
+ printf("%d: Limited cor mag from %f to %f\n",i, nmag, cmag);
+#endif
+ icmScale3(ncor, ncor, cmag/nmag);
+ }
+ /* Create correction point again */
+ for (j = 0; j < 3; j++)
+ rp[i].v[j] = cg[0].pat[i].v[j] + ncor[j];
+ }
+
+#ifdef DEBUG1
+ printf("%d: Was %f %f %f\n",i, cg[1].pat[match[i]].v[0], cg[1].pat[match[i]].v[1], cg[1].pat[match[i]].v[2]);
+ printf("%d: Correction to %f %f %f\n",i, rp[i].v[0], rp[i].v[1], rp[i].v[2]);
+#endif
+
+#ifdef COMPLOOKUP
+ /* Remove current correction from new change */
+ for (j = 0; j < 3; j++)
+ rp[i].v[j] -= ccor[j];
+#endif
+ /* Set weighting */
+ if (i == whitepatch)
+ rp[i].w = WHITEWEIGHT;
+ else
+ rp[i].w = 1.0;
+ npnts++;
+
+#ifdef DEBUG3
+ {
+ char fname[50], tmp[50];
+ FILE *lf;
+ int mi = match[i];
+ double tig, cig, rig;
+ double vv[3], temp[3];
+ double del[3], delt;
+ double corrdel[3], corrdelt;
+ double pcval[3], pcorrdel[3], pcorrdelt;
+
+ for (j = 0;; j++) {
+ if (poi[j] == (i+1) || poi[j] < 0)
+ break;
+ }
+ if (poi[j] < 0) {
+ continue;
+ }
+
+#ifdef COMPLOOKUP
+ /* Compute total correction point */
+ for (j = 0; j < 3; j++)
+ vv[j] = rp[i].v[j] + ccor[j];
+#else
+ for (j = 0; j < 3; j++)
+ vv[j] = rp[i].v[j];
+#endif
+ sprintf(fname,"patch%04d.log",i+1);
+ if ((lf = fopen(fname, "a")) == NULL)
+ error("Unable to open debug3 log file '%s'\n",fname);
+
+ cig = cb.dev_gam->nradial(cb.dev_gam, temp, cg[1].pat[mi].v) - 1.0;
+ if (cig > 0.0)
+ sprintf(tmp, " OUT %f",cig);
+ else
+ sprintf(tmp, "");
+ fprintf(lf,"Currently %f %f %f%s\n", cg[1].pat[mi].v[0], cg[1].pat[mi].v[1], cg[1].pat[mi].v[2], tmp);
+
+ tig = cb.dev_gam->nradial(cb.dev_gam, temp, cg[0].pat[i].v) - 1.0;
+ if (tig > 0.0)
+ sprintf(tmp, " OUT %f",tig);
+ else
+ sprintf(tmp, "");
+ fprintf(lf,"Target %f %f %f%s\n", cg[0].pat[i].v[0], cg[0].pat[i].v[1], cg[0].pat[i].v[2], tmp);
+
+ icmSub3(del, cg[1].pat[mi].v, cg[0].pat[i].v);
+ delt = icmNorm3(del);
+ fprintf(lf,"DE %f %f %f (%f)\n", del[0], del[1], del[2], delt);
+
+ rig = cb.dev_gam->nradial(cb.dev_gam, temp, vv) - 1.0;
+ if (rig > 0.0)
+ sprintf(tmp, " OUT %f",rig);
+ else
+ sprintf(tmp, "");
+ fprintf(lf,"Correction %f %f %f%s\n", vv[0], vv[1], vv[2], tmp);
+ icmSub3(corrdel, vv, cg[0].pat[i].v);
+ corrdelt = icmNorm3(corrdel);
+ fprintf(lf,"CorrDelta %f %f %f (%f)\n", corrdel[0], corrdel[1], corrdel[2], corrdelt);
+ /* Note the previous correction we're compunded with */
+ if (cb.rd_luo != NULL) {
+ cb.rd_luo->lookup(cb.rd_luo, pcval, cg[0].pat[i].v);
+ icmSub3(pcorrdel, pcval, cg[0].pat[i].v);
+ pcorrdelt = icmNorm3(pcorrdel);
+ fprintf(lf,"PrevCorrDelta %f %f %f (%f)\n", pcorrdel[0], pcorrdel[1], pcorrdel[2], pcorrdelt);
+ }
+ fprintf(lf,"\n");
+
+ fclose(lf);
+ }
+#endif /* DEBUG3 */
+ }
+
+ /* Create refining rspl */
+ mn[0] = 0.0, mn[1] = mn[2] = -128.0; /* Allow for 16 bit grid range */
+ mx[0] = 100.0, mx[1] = mx[2] = (65535.0 * 255.0)/65280.0 - 128.0;
+ cb.verb = verb;
+ if ((cb.r = new_rspl(RSPL_NOFLAGS, 3, 3)) == NULL)
+ error("new_rspl failed");
+
+ for (e = 0; e < 3; e++)
+ gres[e] = clutres;
+ for (e = 0; e < 3; e++)
+ avgdev[e] = AVGDEV;
+
+ cb.r->fit_rspl_w_df(cb.r,
+ RSPLFLAGS /* Extra flags */
+ | verb ? RSPL_VERBOSE : 0,
+ rp, /* Test points */
+ npnts, /* Number of test points */
+ mn, mx, gres, /* Low, high, resolution of grid */
+ NULL, NULL, /* Default data scale */
+ smoothf, /* Smoothing */
+ avgdev, /* Average Deviation */
+ NULL, /* Grid width */
+ wweight, /* weak default function weight */
+ NULL, /* No context */
+ wfunc /* Weak function */
+ );
+ if (verb) printf("\n");
+
+ /* Report how good the fit is */
+ if (verb) {
+ co tco; /* Test point */
+ double maxe = -1e6, avge = 0.0;
+
+ for (i = 0; i < npnts; i++) {
+ double de;
+
+ icmAry2Ary(tco.p, rp[i].p);
+ cb.r->interp(cb.r, &tco);
+
+ de = icmLabDE(tco.v, rp[i].v);
+ if (de > maxe)
+ maxe = de;
+ avge += de;
+ }
+ avge /= (double)npnts;
+ printf("Refining transform has error to defining points avg: %f, max %f\n",avge,maxe);
+ }
+ free(rp);
+ }
+
+ /* ======================= */
+ /* Create new abstract ICC profile */
+ if ((wr_fp = new_icmFileStd_name(wr_name,"w")) == NULL)
+ error ("Can't open file '%s' for writing",wr_name);
+
+ if ((wr_icc = new_icc()) == NULL)
+ error ("Creation of write ICC object failed");
+
+ /* Add all the tags required */
+
+ /* The header: */
+ {
+ icmHeader *wh = wr_icc->header;
+
+ /* Values that must be set before writing */
+ wh->deviceClass = icSigAbstractClass;
+ wh->colorSpace = icSigLabData;
+ wh->pcs = icSigLabData;
+ if (dorel)
+ wh->renderingIntent = icRelativeColorimetric; /* White point relative */
+ else
+ wh->renderingIntent = icAbsoluteColorimetric; /* Instrument reading based */
+ }
+ /* Profile Description Tag: */
+ {
+ icmTextDescription *wo;
+ char *dst = "Argyll refine output";
+ if ((wo = (icmTextDescription *)wr_icc->add_tag(
+ wr_icc, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->size = strlen(dst)+1; /* Allocated and used size of desc, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->desc, dst); /* Copy the string in */
+ }
+ /* Copyright Tag: */
+ {
+ icmText *wo;
+ char *crt = "Copyright the user who created it";
+ if ((wo = (icmText *)wr_icc->add_tag(
+ wr_icc, icSigCopyrightTag, icSigTextType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->size = strlen(crt)+1; /* Allocated and used size of text, inc null */
+ wo->allocate((icmBase *)wo);/* Allocate space */
+ strcpy(wo->data, crt); /* Copy the text in */
+ }
+ /* White Point Tag: */
+ {
+ icmXYZArray *wo;
+ /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */
+ if ((wo = (icmXYZArray *)wr_icc->add_tag(
+ wr_icc, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0] = icmD50; /* So absolute/relative rendering is the same */
+ }
+ /* 16 bit pcs -> pcs lut: */
+ {
+ icmLut *wo;
+ int flags = ICM_CLUT_SET_EXACT; /* Assume we're setting from RSPL's */
+
+ /* Intent 0 = default/perceptual */
+ if ((wo = (icmLut *)wr_icc->add_tag(
+ wr_icc, icSigAToB0Tag, icSigLut16Type)) == NULL)
+ error("add_tag failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ wo->inputChan = 3;
+ wo->outputChan = 3;
+ wo->clutPoints = clutres;
+ wo->inputEnt = 256; /* Not actually used */
+ wo->outputEnt = 256;
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* The matrix is only applicable to XYZ input space, */
+ /* so it is not used here. */
+
+ /* Use helper function to do the hard work. */
+ if (cb.verb) {
+ int extra;
+ for (cb.total = 1, i = 0; i < 3; i++, cb.total *= wo->clutPoints)
+ ;
+ /* Add in cell center points */
+ for (extra = 1, i = 0; i < wo->inputChan; i++, extra *= (wo->clutPoints-1))
+ ;
+ cb.total += extra;
+ cb.count = 0;
+ cb.last = -1;
+ printf(" 0%%"), fflush(stdout);
+ }
+
+#ifdef COMPLOOKUP
+ /* Compound with previous correction */
+ if (cb.rd_luo != NULL)
+ flags = ICM_CLUT_SET_APXLS; /* Won't be least squares, so do extra sampling */
+#endif
+
+ if (wo->set_tables(wo,
+ flags,
+ &cb,
+ icSigLabData, /* Input color space */
+ icSigLabData, /* Output color space */
+ NULL, /* Linear input transform Lab->Lab' (NULL = default) */
+ NULL, NULL, /* Use default Maximum range of Lab' values */
+ PCSp_PCSp, /* Lab' -> Lab' transfer function */
+ NULL, NULL, /* Use default Maximum range of Lab' values */
+ NULL /* Linear output transform Lab'->Lab */
+ ) != 0)
+ error("Setting 16 bit Lab->Lab Lut failed: %d, %s",wr_icc->errc,wr_icc->err);
+
+ if (verb)
+ printf("\n");
+#ifdef WARN_CLUT_CLIPPING
+ if (wr_icc->warnc)
+ warning("Values clipped in setting abstract LUT");
+#endif /* WARN_CLUT_CLIPPING */
+ if (verb)
+ printf("Done filling abstract table\n");
+ }
+ /* Write the file out */
+ if ((rv = wr_icc->write(wr_icc,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,wr_icc->err);
+
+ /* ======================================= */
+
+ /* Clean everything up */
+ wr_icc->del(wr_icc);
+ wr_fp->del(wr_fp);
+
+ if (docreate == 0) {
+ cb.rd_luo->del(cb.rd_luo);
+ rd_icc->del(rd_icc);
+ rd_fp->del(rd_fp);
+ }
+
+ if (nogamut == 0) {
+ cb.dev_gam->del(cb.dev_gam);
+ }
+
+ cb.r->del(cb.r);
+
+ free(match);
+ free(cg[0].pat);
+ free(cg[1].pat);
+
+ return 0;
+}
+
diff --git a/ucmm/Jamfile b/ucmm/Jamfile
new file mode 100644
index 0000000..5805272
--- /dev/null
+++ b/ucmm/Jamfile
@@ -0,0 +1,26 @@
+
+# JAM style makefile for yajl
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags
+
+#Products
+Libraries = libucmm ;
+Executables = ;
+Headers = ucmm.h ;
+
+#Install
+#InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+HDRS = ../jcnf ../spectro ../icc ;
+
+# config parser based on yajl
+Library libucmm : ucmm.c ;
+
+
+
+
diff --git a/ucmm/Makefile.am b/ucmm/Makefile.am
new file mode 100644
index 0000000..0140619
--- /dev/null
+++ b/ucmm/Makefile.am
@@ -0,0 +1,9 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libucmm.la
+privatelibdir = $(pkglibdir)
+
+libucmm_la_SOURCES = ucmm.h ucmm.c
+libucmm_la_LIBADD = $(ICC_LIBS) ../jcnf/libjcnf.la ../spectro/libconv.la
+
+LDADD = libucmm.la
diff --git a/ucmm/afiles b/ucmm/afiles
new file mode 100644
index 0000000..3204a05
--- /dev/null
+++ b/ucmm/afiles
@@ -0,0 +1,4 @@
+Jamfile
+afiles
+ucmm.h
+ucmm.c
diff --git a/ucmm/ucmm.c b/ucmm/ucmm.c
new file mode 100644
index 0000000..dc5598f
--- /dev/null
+++ b/ucmm/ucmm.c
@@ -0,0 +1,1086 @@
+
+/*
+ * Unix micro-cmm to manage X11 display
+ * calibration and profile loading.
+ */
+
+/*************************************************************************
+ Copyright 2008 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+/* We use libjcnf to store the ICC profile association with particular displays */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <signal.h>
+#ifndef NT
+# include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "icc.h"
+#include "xdg_bds.h"
+#include "jcnf.h"
+#include "ucmm.h"
+
+#undef DEBUG
+
+#define CONFIG_FILE "color.jcnf"
+#define PROFILE_DIR "color/icc/devices/display"
+
+#ifdef DEBUG
+# define errout stderr
+# define debug(xx) fprintf(errout, xx )
+# define debug2(xx) fprintf xx
+#else
+# define debug(xx)
+# define debug2(xx)
+#endif
+
+static unsigned int fnv_32_buf(void *buf, size_t len);
+
+#ifdef NT
+
+/* Given the path to a file, ensure that all the parent directories */
+/* are created. return nz on error */
+static int mkdirs(char *path) {
+ struct _stat sbuf;
+ char *pp = path;
+
+ if (*pp != '\000' /* Skip drive number */
+ && ((*pp >= 'a' && *pp <= 'z') || (*pp >= 'A' && *pp <= 'Z'))
+ && pp[1] == ':')
+ pp += 2;
+ if (*pp == '/')
+ pp++; /* Skip root directory */
+ for (;pp != NULL && *pp != '\000';) {
+ if ((pp = strchr(pp, '/')) != NULL) {
+ *pp = '\000';
+ if (_stat(path,&sbuf) != 0)
+ {
+ if (_mkdir(path) != 0)
+ return 1;
+ }
+ *pp = '/';
+ pp++;
+ }
+ }
+ return 0;
+}
+
+#else
+
+/* Given the path to a file, ensure that all the parent directories */
+/* are created. return nz on error */
+static int mkpdirs(char *path) {
+ struct stat sbuf;
+ char *pp = path;
+ mode_t mode = 0700; /* Default directory mode */
+
+ if (*pp == '/')
+ pp++; /* Skip root directory */
+ for (;pp != NULL && *pp != '\000';) {
+ if ((pp = strchr(pp, '/')) != NULL) {
+ *pp = '\000';
+ if (stat(path,&sbuf) != 0) {
+ if (mkdir(path, mode) != 0)
+ return 1;
+ } else
+ mode = sbuf.st_mode;
+ *pp = '/';
+ pp++;
+ }
+ }
+ return 0;
+}
+#endif /* !NT */
+
+/* Given a block of binary, convert it to upper case hexadecimal, */
+/* with a 0x prefix. Free the buffer returned. */
+/* Return NULL on error */
+static char *buf2hex(unsigned char *buf, int len) {
+ char *s;
+ int i;
+
+ char hex[17] = "0123456789ABCDEF";
+
+ if ((s = malloc(len * 2 + 3)) == NULL)
+ return NULL;
+
+ s[0] = '0';
+ s[1] = 'x';
+
+ for (i = 0; i < len; i++) {
+ s[2 + i * 2 + 0] = hex[(buf[i] >> 4) & 0xf];
+ s[2 + i * 2 + 1] = hex[buf[i] & 0xf];
+ }
+ s[2 + i * 2 + 0] = '\000';
+
+ return s;
+}
+
+
+/* Install a profile for a given monitor */
+/* Either EDID or display_name may be NULL, but not both. */
+/* Any existing association is overwritten. Installed profiles */
+/* are not deleted. */
+ucmm_error ucmm_install_monitor_profile(
+ ucmm_scope scope, /* Scope of instalation */
+ unsigned char *edid, /* Primary device identifier, NULL if none. */
+ int edid_len, /* Length of edid data */
+ char *display_name, /* Fall back device association, */
+ /* the X11 display name */
+ char *profile /* Path to profile to be installed. */
+) {
+ char *config_file = CONFIG_FILE;
+ char *profile_dir = PROFILE_DIR;
+ char *conf_name = NULL; /* Configuration path to use */
+ char *data_name = NULL; /* Data path to use */
+ char *dprof = NULL; /* Destination for profile */
+ unsigned int edid_hash = 0;
+
+ if (edid != NULL)
+ edid_hash = fnv_32_buf(edid, edid_len);
+
+ debug2((errout,"ucmm_install_monitor_profile called with profile '%s', edid 0x%x, disp '%s'\n",profile,edid_hash,display_name));
+
+ /* Verify that we've been given a suitable ICC profile */
+ /* And read it into a memory buffer */
+ {
+ icmFile *fp;
+ icc *icco;
+
+ if ((fp = new_icmFileStd_name(profile,"r")) == NULL) {
+ debug2((errout,"Unable to ope file '%s'\n",profile));
+ return ucmm_invalid_profile;
+ }
+
+ if ((icco = new_icc()) == NULL) {
+ debug2((errout,"new_icc() failed\n"));
+ fp->del(fp);
+ return ucmm_invalid_profile;
+ }
+
+ if (icco->read(icco,fp,0) != 0) {
+ debug2((errout,"icc read of '%s' failed\n",profile));
+ icco->del(icco);
+ fp->del(fp);
+ return ucmm_invalid_profile;
+ }
+
+ if (icco->header->deviceClass != icSigDisplayClass
+ || icco->header->colorSpace != icSigRgbData) {
+ debug2((errout,"profile '%s' isn't an RGB display profile\n",profile));
+ icco->del(icco);
+ fp->del(fp);
+ return ucmm_invalid_profile;
+ }
+ icco->del(icco);
+ fp->del(fp);
+ }
+
+ debug2((errout,"verified profile OK\n"));
+
+ /* Locate the directories where the config file is, */
+ /* and where we should copy the profile to. */
+ {
+ int npaths;
+ xdg_error er;
+ char *data_pathfile; /* Path & name of destination */
+ char **paths;
+ char *tt;
+
+ if (npaths = xdg_bds(&er, &paths, xdg_conf, xdg_write,
+ scope == ucmm_local_system ? xdg_local : xdg_user,
+ config_file) == 0) {
+ return ucmm_open_config;
+ }
+ if ((conf_name = strdup(paths[0])) == NULL) {
+ xdg_free(paths, npaths);
+ return ucmm_resource;
+ }
+ xdg_free(paths, npaths);
+
+ /* Combined sub-path and profile name */
+ if ((data_pathfile = malloc(strlen(profile_dir) + 1 + strlen(profile))) == NULL)
+ return ucmm_resource;
+ strcpy(data_pathfile, profile_dir);
+
+ if (strlen(data_pathfile) > 1 && data_pathfile[strlen(data_pathfile)-1] != '/')
+ strcat(data_pathfile, "/");
+
+ if ((tt = strrchr(profile, '/')) != NULL) /* Get base name of profile */
+ tt++;
+ else
+ tt = profile;
+ strcat(data_pathfile, tt);
+
+ if (npaths = xdg_bds(&er, &paths, xdg_conf, xdg_write,
+ scope == ucmm_local_system ? xdg_local : xdg_user,
+ data_pathfile) == 0) {
+ free(data_pathfile);
+ free(conf_name);
+ return ucmm_open_config;
+ }
+ free(data_pathfile);
+ if ((data_name = strdup(paths[0])) == NULL) {
+ free(conf_name);
+ xdg_free(paths, npaths);
+ return ucmm_resource;
+ }
+ xdg_free(paths, npaths);
+ }
+
+ debug2((errout,"config file = '%s'\n",conf_name));
+ debug2((errout,"data file = '%s'\n",data_name));
+
+ /* Copy the profile to the destination */
+ {
+ FILE *fp;
+ unsigned char *pdata;
+ unsigned long psize;
+
+ /* Read in the ICC profile, then set the X11 atom value */
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(profile,"rb")) == NULL)
+#else
+ if ((fp = fopen(profile,"r")) == NULL)
+#endif
+ {
+ debug2((errout,"Can't open file '%s'\n",profile));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+
+ /* Figure out how big it is */
+ if (fseek(fp, 0, SEEK_END)) {
+ debug2((errout,"Seek '%s' to EOF failed\n",profile));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+ psize = (unsigned long)ftell(fp);
+
+ if (fseek(fp, 0, SEEK_SET)) {
+ debug2((errout,"Seek '%s' to SOF failed\n",profile));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+
+ if ((pdata = (unsigned char *)malloc(psize)) == NULL) {
+ debug2((errout,"Failed to allocate buffer for profile '%s'\n",profile));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+
+ if (fread(pdata, 1, psize, fp) != psize) {
+ debug2((errout,"Failed to read profile '%s' into buffer\n",profile));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+
+ fclose(fp);
+
+ /* Write the profile to its location */
+ if (mkpdirs(data_name)) {
+ debug2((errout,"Can't create directories for file '%s'\n",data_name));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((fp = fopen(data_name,"wb")) == NULL)
+#else
+ if ((fp = fopen(data_name,"w")) == NULL)
+#endif
+ {
+ debug2((errout,"Can't create file '%s'\n",data_name));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+
+ if (fwrite(pdata, 1, psize, fp) != psize) {
+ debug2((errout,"Failed to write profile '%s' into buffer\n",data_name));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+
+ if (fclose(fp) != 0) {
+ debug2((errout,"Failed to close profile '%s' into buffer\n",data_name));
+ free(conf_name);
+ free(data_name);
+ return ucmm_profile_copy;
+ }
+ }
+
+ debug2((errout,"profile copied OK\n"));
+
+ /* Update the config file */
+ {
+ jc_error ev;
+ jcnf *jc;
+ char keyn1[100];
+ char keyn2[100];
+ char *mname; /* Name of key to match to */
+ char *mval; /* Value to match */
+ int ix = 0;
+ int recno = -1; /* Number of the last record read */
+
+ /* Open the configuration file for modification */
+ if (mkpdirs(conf_name)) {
+ debug2((errout,"Can't create directories for file '%s'\n",conf_name));
+ free(conf_name);
+ free(data_name);
+ return ucmm_open_config;
+ }
+
+ if ((jc = new_jcnf(&ev, conf_name, jc_modify, jc_create)) == NULL) {
+ debug2((errout,"new_jcnf '%s' failed with error %d\n",conf_name,ev));
+ free(conf_name);
+ free(data_name);
+ return ucmm_open_config;
+ }
+
+ /* if EDID supplied, Locate a matching EDID */
+ if (edid != NULL) {
+ mname = "EDID";
+ if ((mval = buf2hex(edid, edid_len)) == NULL) {
+ jc->del(jc);
+ free(conf_name);
+ free(data_name);
+ return ucmm_resource;
+ }
+
+ /* Else fall back to X11 display name and screen */
+ } else {
+ if (display_name == NULL) {
+ jc->del(jc);
+ free(conf_name);
+ free(data_name);
+ return ucmm_no_edid_or_display;
+ }
+ mname = "NAME";
+ if ((mval = strdup(display_name)) == NULL) {
+ jc->del(jc);
+ free(conf_name);
+ free(data_name);
+ return ucmm_resource;
+ }
+ }
+
+ debug2((errout,"Searching for %s = '%s'\n",mname,mval));
+ for (;;ix++) {
+ char *key, *pp;
+ jc_type type;
+ unsigned char *data;
+ size_t dataSize;
+ int ii;
+
+ if ((ev = jc->locate_key(jc, &ix, "devices/display/", 0, 0)) != jc_ok
+ || (ev = jc->get_key(jc, ix, &key, &type, &data, &dataSize, NULL)) != jc_ok) {
+ if (ev == jc_ix_oorange) {
+ break;
+ }
+ debug2((errout,"jcnf locate/get_key failed with error %d\n",ev));
+ free(mval);
+ jc->del(jc);
+ free(conf_name);
+ free(data_name);
+ return ucmm_open_config;
+ }
+
+ if ((pp = jc_get_nth_elem(key, 2)) == NULL) {
+ continue;
+ }
+ if ((ii = atoi(pp)) == 0) {
+ free(pp);
+ continue;
+ }
+ if (ii > recno) /* Track biggest, so we know what to create next */
+ recno = ii;
+ if ((pp = jc_get_nth_elem(key, 3)) != NULL && strcmp(pp, mname) == 0 && type == jc_string && strcmp(data, mval) == 0) {
+ /* Found matching record */
+ free(pp);
+ break;
+ }
+ if (pp != NULL)
+ free(pp);
+ }
+
+ /* Create a new record */
+ if (ev == jc_ix_oorange) {
+ recno++; /* Make it the next index */
+ if (recno <= 0)
+ recno = 1;
+ debug2((errout, "Adding a new record %d\n",recno));
+ } else {
+ debug2((errout, "Replacing record %d\n",recno));
+ }
+
+ /* Write the record */
+ sprintf(keyn1, "devices/display/%d/%s", recno, mname);
+ sprintf(keyn2, "devices/display/%d/ICC_PROFILE", recno);
+ if ((ev = jc->set_key(jc, -1, keyn1, jc_string, mval, strlen(mval)+1, NULL)) != jc_ok
+ || (ev = jc->set_key(jc, -1, keyn2, jc_string, data_name, strlen(data_name)+1, NULL)) != jc_ok) {
+ debug2((errout,"jcnf set_key failed with error %d\n",ev));
+ free(mval);
+ jc->del(jc);
+ free(conf_name);
+ free(data_name);
+ return ucmm_set_config;
+ }
+ free(mval);
+
+ /* write to record the EDID or display name and the profile path */
+ if ((ev = jc->update(jc)) != 0) {
+ debug2((errout,"jcnf write to '%s' failed with error %d\n",conf_name,ev));
+ jc->del(jc);
+ free(conf_name);
+ free(data_name);
+ return ucmm_save_config;
+ }
+ debug2((errout,"Updated config file '%s'\n",conf_name));
+
+ /* We're done with this */
+ jc->del(jc);
+ free(conf_name);
+ free(data_name);
+ }
+ debug2((errout,"ucmm done profile install\n"));
+ return ucmm_ok;
+}
+
+/* Un-install a profile for a given monitor. */
+/* Either EDID or display_name may be NULL, but not both. */
+/* The monitor is left with no profile association. If a profile */
+/* name is provided and matches the one that was associated with */
+/* the monitor, and has no other association, then it will be deleted */
+/* from the data directory. */
+/* Return an error code */
+ucmm_error ucmm_uninstall_monitor_profile(
+ ucmm_scope scope, /* Scope of instalation */
+ unsigned char *edid, /* Primary device identifier, NULL if none. */
+ int edid_len, /* Length of edid data */
+ char *display_name, /* Fall back device association, */
+ char *profile /* Base name of profile to be deleted. NULL if not to be deleted. */
+) {
+ char *config_file = CONFIG_FILE;
+ char *profile_dir = PROFILE_DIR;
+ char *conf_name = NULL; /* Configuration path to use */
+ char *data_name = NULL; /* Data path to use */
+ char *dprof = NULL; /* Destination for profile */
+ unsigned int edid_hash = 0;
+
+ if (edid != NULL)
+ edid_hash = fnv_32_buf(edid, edid_len);
+
+ debug2((errout,"ucmm_uninstall_monitor_profile called with profile '%s', edid 0x%x, disp '%s'\n",profile,edid_hash,display_name));
+
+ /* Locate the directories where the config file is, */
+ /* and where the profile should be too. */
+ {
+ int npaths;
+ xdg_error er;
+ char *data_pathfile; /* Path & name of destination */
+ char **paths;
+ char *tt;
+
+ if (npaths = xdg_bds(&er, &paths, xdg_conf, xdg_read,
+ scope == ucmm_local_system ? xdg_local : xdg_user,
+ config_file) == 0) {
+ return ucmm_open_config;
+ }
+ if ((conf_name = strdup(paths[0])) == NULL) {
+ xdg_free(paths, npaths);
+ return ucmm_resource;
+ }
+ xdg_free(paths, npaths);
+
+ if (profile != NULL) {
+ /* Combined sub-path and profile name */
+ if ((data_pathfile = malloc(strlen(profile_dir) + 1 + strlen(profile))) == NULL)
+ return ucmm_resource;
+ strcpy(data_pathfile, profile_dir);
+
+ if (strlen(data_pathfile) > 1 && data_pathfile[strlen(data_pathfile)-1] != '/')
+ strcat(data_pathfile, "/");
+
+ if ((tt = strrchr(profile, '/')) != NULL) /* Get base name of profile */
+ tt++;
+ else
+ tt = profile;
+ strcat(data_pathfile, tt);
+
+ if (npaths = xdg_bds(&er, &paths, xdg_conf, xdg_read,
+ scope == ucmm_local_system ? xdg_local : xdg_user,
+ data_pathfile) == 0) {
+ free(data_pathfile);
+ free(conf_name);
+ return ucmm_open_config;
+ }
+ free(data_pathfile);
+ if ((data_name = strdup(paths[0])) == NULL) {
+ free(conf_name);
+ xdg_free(paths, npaths);
+ return ucmm_resource;
+ }
+ xdg_free(paths, npaths);
+ }
+ }
+
+ debug2((errout,"config file = '%s'\n",conf_name));
+ if (data_name != NULL)
+ debug2((errout,"data file = '%s'\n",data_name));
+
+ /* Get the config file */
+ {
+ jc_error ev;
+ jcnf *jc;
+ char keyn1[100];
+ char *mname; /* Name of key to match to */
+ char *mval; /* Value to match */
+ int ix;
+ int recno = -1; /* Number of the last record read */
+
+ /* Open the configuration file for modification */
+ if (mkpdirs(conf_name)) {
+ debug2((errout,"Can't create directories for file '%s'\n",conf_name));
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_open_config;
+ }
+
+ if ((jc = new_jcnf(&ev, conf_name, jc_modify, jc_create)) == NULL) {
+ debug2((errout,"new_jcnf '%s' failed with error %d\n",conf_name,ev));
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_open_config;
+ }
+
+ /* if EDID supplied, Locate a matching EDID */
+ if (edid != NULL) {
+ mname = "EDID";
+ if ((mval = buf2hex(edid, edid_len)) == NULL) {
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_resource;
+ }
+
+ /* Else fall back to X11 display name and screen */
+ } else {
+ if (display_name == NULL) {
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_no_edid_or_display;
+ }
+ mname = "NAME";
+ if ((mval = strdup(display_name)) == NULL) {
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_resource;
+ }
+ }
+
+ debug2((errout,"Searching for %s = '%s'\n",mname,mval));
+ for (ix = 0;;ix++) {
+ char *key, *pp;
+ jc_type type;
+ unsigned char *data;
+ size_t dataSize;
+ int ii;
+
+ if ((ev = jc->locate_key(jc, &ix, "devices/display/", 0, 0)) != jc_ok
+ || (ev = jc->get_key(jc, ix, &key, &type, &data, &dataSize, NULL)) != jc_ok) {
+ if (ev == jc_ix_oorange) {
+ break;
+ }
+ debug2((errout,"jcnf locate/get_key failed with error %d\n",ev));
+ free(mval);
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_open_config;
+ }
+
+ if ((pp = jc_get_nth_elem(key, 2)) == NULL) {
+ continue;
+ }
+ if ((ii = atoi(pp)) == 0) {
+ free(pp);
+ continue;
+ }
+ if (ii > recno) /* Track biggest, so we know what to create next */
+ recno = ii;
+ if ((pp = jc_get_nth_elem(key, 3)) != NULL && strcmp(pp, mname) == 0 && type == jc_string && strcmp(data, mval) == 0) {
+ /* Found matching record */
+ free(pp);
+ break;
+ }
+ if (pp != NULL)
+ free(pp);
+ }
+
+ if (ev == jc_ix_oorange) {
+ debug2((errout,"No matching display was found\n"));
+ free(mval);
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_monitor_not_found;
+ /* (Should we delete the file anyway ???) */
+ }
+ free(mval);
+
+ debug2((errout,"Deleting record %d key '%s'\n",recno,keyn1));
+
+ /* Delete the record */
+ sprintf(keyn1, "devices/display/%d/", recno);
+
+ for (ix = -1;;ix--) {
+ if ((ev = jc->locate_key(jc, &ix, keyn1, 0, 1)) == jc_ok) {
+ if ((ev = jc->delete_key(jc, ix, NULL)) != jc_ok) {
+ debug2((errout,"jcnf delete_key failed with error %d\n",ev));
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_delete_key;
+ }
+ } else {
+ if (ev == jc_ix_oorange) {
+ break;
+ }
+ debug2((errout,"jcnf locate/get_key failed with error %d\n",ev));
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_open_config;
+ }
+ }
+
+ if (data_name != NULL) {
+ /* See if the profile is used by any other device */
+
+ debug2((errout, "Searching for any reference to profile '%s'\n",data_name));
+ for (ix = 0;;ix++) {
+ char *key, *pp;
+ jc_type type;
+ unsigned char *data;
+ size_t dataSize;
+
+ if ((ev = jc->locate_key(jc, &ix, "devices/display/", 0, 0)) != jc_ok
+ || (ev = jc->get_key(jc, ix, &key, &type, &data, &dataSize, NULL)) != jc_ok) {
+ if (ev == jc_ix_oorange) {
+ break;
+ }
+ debug2((errout,"jcnf locate/get_key failed with error %d\n",ev));
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_access_config;
+ }
+ if ((pp = jc_get_nth_elem(key, 3)) == NULL)
+ continue;
+ if (strcmp(pp,"ICC_PROFILE") != 0
+ || type != jc_string
+ || strcmp(data, data_name) != 0) {
+ free(pp);
+ continue;
+ }
+ free(pp);
+ break;
+ }
+ /* If not, delete the file */
+ if (ev == jc_ix_oorange) {
+ debug2((errout,"Deleting profile '%s'\n",data_name));
+ if (unlink(data_name) != 0) {
+ debug2((errout,"ucmm unlink '%s' failed\n",data_name));
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_access_config;
+ }
+ }
+ }
+
+ /* Update the config */
+ if ((ev = jc->update(jc)) != 0) {
+ debug2((errout,"jcnf write to '%s' failed with error %d\n",conf_name,ev));
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ return ucmm_save_config;
+ }
+ debug2((errout,"Updated config file '%s'\n",conf_name));
+
+ /* We're done with this */
+ jc->del(jc);
+ free(conf_name);
+ if (data_name != NULL)
+ free(data_name);
+ }
+ debug2((errout,"ucmm done profile un-install\n"));
+ return ucmm_ok;
+}
+
+/* Get an associated monitor profile. */
+/* Return ucmm_no_profile if there is no installed profile for this */
+/* monitor. */
+/* Return an error code */
+ucmm_error ucmm_get_monitor_profile(
+ unsigned char *edid, /* Primary device identifier, NULL if none. */
+ int edid_len, /* Length of edid data */
+ char *display_name, /* Fall back device association, */
+ char **profile /* Return path to profile. free() afterwards. */
+) {
+ int scope;
+ char *config_file = "color.jcnf";
+ char *conf_name = NULL; /* Configuration path to use */
+ unsigned int edid_hash = 0;
+
+ if (edid != NULL)
+ edid_hash = fnv_32_buf(edid, edid_len);
+
+ debug2((errout,"ucmm_get_monitor_profile called edid 0x%x, disp '%s'\n",edid_hash,display_name));
+
+ /* Look at user then local system scope */
+ for (scope = 0; scope < 2; scope++) {
+
+ /* Locate the directories where the config file is, */
+ {
+ int npaths;
+ xdg_error er;
+ char **paths;
+ char *tt;
+
+ if (npaths = xdg_bds(&er, &paths, xdg_conf, xdg_read,
+ scope == ucmm_local_system ? xdg_local : xdg_user,
+ config_file) == 0) {
+ continue;
+ }
+ if ((conf_name = strdup(paths[0])) == NULL) {
+ xdg_free(paths, npaths);
+ return ucmm_resource;
+ }
+ xdg_free(paths, npaths);
+ }
+
+ /* Get the config file */
+ {
+ jc_error ev;
+ jcnf *jc;
+ char keyn1[100];
+ char *mname; /* Name of key to match to */
+ char *mval; /* Value to match */
+ int ix;
+ int recno = -1; /* Number of the last record read */
+ char *key, *pp;
+ jc_type type;
+ unsigned char *data;
+ size_t dataSize;
+
+ /* Open the configuration file for reading */
+ if ((jc = new_jcnf(&ev, conf_name, jc_read, jc_no_create)) == NULL) {
+ debug2((errout,"new_jcnf '%s' failed with error %d\n",conf_name,ev));
+ continue; /* Try the next scope */
+ }
+
+ /* if EDID supplied, Locate a matching EDID */
+ if (edid != NULL) {
+ mname = "EDID";
+ if ((mval = buf2hex(edid, edid_len)) == NULL) {
+ debug2((errout,"buf2jex failed\n"));
+ jc->del(jc);
+ free(conf_name);
+ return ucmm_resource;
+ }
+
+ /* Else fall back to X11 display name and screen */
+ } else {
+ if (display_name == NULL) {
+ debug2((errout,"No EDID and display name failed\n"));
+ jc->del(jc);
+ free(conf_name);
+ return ucmm_no_edid_or_display;
+ }
+ mname = "NAME";
+ if ((mval = strdup(display_name)) == NULL) {
+ debug2((errout,"strdup failed\n"));
+ jc->del(jc);
+ free(conf_name);
+ return ucmm_resource;
+ }
+ }
+
+ debug2((errout,"Searching for %s = '%s'\n",mname,mval));
+ for (ix = 0;;ix++) {
+ int ii;
+
+ if ((ev = jc->locate_key(jc, &ix, "devices/display/", 0, 0)) != jc_ok
+ || (ev = jc->get_key(jc, ix, &key, &type, &data, &dataSize, NULL)) != jc_ok) {
+ if (ev == jc_ix_oorange) {
+ break;
+ }
+ debug2((errout,"jcnf locate/get_key failed with error %d\n",ev));
+ free(mval);
+ jc->del(jc);
+ free(conf_name);
+ return ucmm_open_config;
+ }
+
+ if ((pp = jc_get_nth_elem(key, 2)) == NULL) {
+ continue;
+ }
+ if ((ii = atoi(pp)) == 0) {
+ free(pp);
+ continue;
+ }
+ if (ii > recno) /* Track biggest, so we know what to create next */
+ recno = ii;
+ if ((pp = jc_get_nth_elem(key, 3)) != NULL && strcmp(pp, mname) == 0 && type == jc_string
+ && strcmp(data, mval) == 0) {
+ /* Found matching record */
+ free(pp);
+ break;
+ }
+ if (pp != NULL)
+ free(pp);
+ }
+
+ if (ev == jc_ix_oorange) {
+ debug2((errout,"No matching display was found\n"));
+ continue; /* On to the next scope */
+ }
+ free(mval);
+
+ /* Get the profile path from the record */
+ sprintf(keyn1, "devices/display/%d/ICC_PROFILE", recno);
+ key = keyn1;
+ debug2((errout,"Looking up record %d key '%s'\n",recno,keyn1));
+
+ if ((ev = jc->get_key(jc, -1, &key, &type, &data, &dataSize, NULL)) != jc_ok
+ || type != jc_string) {
+ debug2((errout,"jcnf locate/get_key failed with error %d\n",ev));
+ jc->del(jc);
+ free(conf_name);
+ if (ev == jc_ix_oorange) {
+ continue; /* try the next config */
+ }
+ return ucmm_access_config;
+ }
+ if ((*profile = strdup(data)) == NULL) {
+ debug2((errout,"jcnf get_key malloc failed\n"));
+ jc->del(jc);
+ free(conf_name);
+ return ucmm_resource;
+ }
+
+ /* We're done with this */
+ jc->del(jc);
+ free(conf_name);
+ return ucmm_ok;
+ debug2((errout,"Returning current profile '%s'\n",data));
+ }
+ }
+ debug2((errout,"Failed to find a current profile\n"));
+
+ return ucmm_no_profile;
+}
+
+
+/* Return an ASCII error message string interpretation of an error number */
+char *ucmm_error_string(ucmm_error erno) {
+
+ switch (erno) {
+ case ucmm_ok:
+ return "OK";
+ case ucmm_resource:
+ return "Resource failure (e.g. out of memory)";
+ case ucmm_invalid_profile:
+ return "Profile is not a valid display ICC profile";
+ case ucmm_no_profile:
+ return "There is no associated profile";
+ case ucmm_no_home:
+ return "There is no HOME environment variable defined";
+ case ucmm_no_edid_or_display:
+ return "There is no edid or display name";
+ case ucmm_profile_copy:
+ return "There was an error copying the profile";
+ case ucmm_open_config:
+ return "There was an error opening the config file";
+ case ucmm_access_config:
+ return "There was an error accessing the config information";
+ case ucmm_set_config:
+ return "There was an error setting the config file";
+ case ucmm_save_config:
+ return "There was an error saving the config file";
+ case ucmm_monitor_not_found:
+ return "The EDID or display wasn't matched";
+ case ucmm_delete_key:
+ return "Delete_key failed";
+ case ucmm_delete_profile:
+ return "Delete_key failed";
+ }
+ return "Unknown error number";
+}
+
+
+/* ============================================================= */
+
+/*
+ * hash_32 - 32 bit Fowler/Noll/Vo hash code
+ *
+ * @(#) $Revision: 1.8 $
+ * @(#) $Id: hash_32.c,v 1.8 2003/10/03 20:38:13 chongo Exp $
+ * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_32.c,v $
+ *
+ ***
+ *
+ * Fowler/Noll/Vo hash
+ *
+ * The basis of this hash algorithm was taken from an idea sent
+ * as reviewer comments to the IEEE POSIX P1003.2 committee by:
+ *
+ * Phong Vo (http://www.research.att.com/info/kpv/)
+ * Glenn Fowler (http://www.research.att.com/~gsf/)
+ *
+ * In a subsequent ballot round:
+ *
+ * Landon Curt Noll (http://www.isthe.com/chongo/)
+ *
+ * improved on their algorithm. Some people tried this hash
+ * and found that it worked rather well. In an EMail message
+ * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash.
+ *
+ * FNV hashes are designed to be fast while maintaining a low
+ * collision rate. The FNV speed allows one to quickly hash lots
+ * of data while maintaining a reasonable collision rate. See:
+ *
+ * http://www.isthe.com/chongo/tech/comp/fnv/index.html
+ *
+ * for more details as well as other forms of the FNV hash.
+ ***
+ *
+ * NOTE: The FNV-0 historic hash is not recommended. One should use
+ * the FNV-1 hash instead.
+ *
+ * To use the 32 bit FNV-0 historic hash, pass FNV0_32_INIT as the
+ * unsigned int hashval argument to fnv_32_buf() or fnv_32_str().
+ *
+ * To use the recommended 32 bit FNV-1 hash, pass FNV1_32_INIT as the
+ * unsigned int hashval argument to fnv_32_buf() or fnv_32_str().
+ *
+ ***
+ *
+ * Please do not copyright this code. This code is in the public domain.
+ *
+ * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * By:
+ * chongo <Landon Curt Noll> /\oo/\
+ * http://www.isthe.com/chongo/
+ *
+ * Share and Enjoy! :-)
+ */
+
+/*
+ * 32 bit magic FNV-0 and FNV-1 prime
+ */
+#define FNV_32_PRIME ((unsigned int)0x01000193)
+
+#define FNV1_32_INIT ((unsigned int)0x811c9dc5)
+
+/*
+ * fnv_32_buf - perform a 32 bit Fowler/Noll/Vo hash on a buffer
+ *
+ * input:
+ * buf - start of buffer to hash
+ * len - length of buffer in octets
+ * hval - previous hash value or 0 if first call
+ *
+ * returns:
+ * 32 bit hash as a static hash type
+ *
+ * NOTE: To use the recommended 32 bit FNV-1 hash, use FNV1_32_INIT as the hval
+ * argument on the first call to either fnv_32_buf() or fnv_32_str().
+ */
+static unsigned int
+fnv_32_buf_cont(void *buf, size_t len, unsigned int hval)
+{
+ unsigned char *bp = (unsigned char *)buf; /* start of buffer */
+ unsigned char *be = bp + len; /* beyond end of buffer */
+
+ /*
+ * FNV-1 hash each octet in the buffer
+ */
+ while (bp < be) {
+
+ /* multiply by the 32 bit FNV magic prime mod 2^32 */
+#if defined(NO_FNV_GCC_OPTIMIZATION)
+ hval *= FNV_32_PRIME;
+#else
+ hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
+#endif
+
+ /* xor the bottom with the current octet */
+ hval ^= (unsigned int)*bp++;
+ }
+
+ /* return our new hash value */
+ return hval;
+}
+
+static unsigned int
+fnv_32_buf(void *buf, size_t len) {
+ return fnv_32_buf_cont(buf, len, FNV1_32_INIT);
+}
+
diff --git a/ucmm/ucmm.h b/ucmm/ucmm.h
new file mode 100644
index 0000000..fc08ca1
--- /dev/null
+++ b/ucmm/ucmm.h
@@ -0,0 +1,98 @@
+
+#ifndef UCMM_H
+#define UCMM_H
+
+/*
+ * Unix micro-cmm to manage X11 display
+ * calibration and profile loading.
+ */
+
+/*************************************************************************
+ Copyright 2008 Graeme W. Gill
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+
+ *************************************************************************/
+
+typedef enum {
+ ucmm_ok = 0,
+ ucmm_resource, /* Resource failure (e.g. out of memory) */
+ ucmm_invalid_profile, /* Profile is not a valid display ICC profile */
+ ucmm_no_profile, /* There is no associated profile */
+ ucmm_no_home, /* There is no HOME environment variable defined */
+ ucmm_no_edid_or_display, /* There is no edid or display name */
+ ucmm_profile_copy, /* There was an error copying the profile */
+ ucmm_open_config, /* There was an error opening the config file */
+ ucmm_access_config, /* There was an error accessing the config information */
+ ucmm_set_config, /* There was an error setting the config file */
+ ucmm_save_config, /* There was an error saving the config file */
+ ucmm_monitor_not_found, /* The EDID or display wasn't matched */
+ ucmm_delete_key, /* Delete_key failed */
+ ucmm_delete_profile, /* Delete_key failed */
+} ucmm_error;
+
+/* Install scope */
+typedef enum {
+ ucmm_user,
+ ucmm_local_system
+} ucmm_scope;
+
+/* Install a profile for a given monitor */
+/* Either EDID or display_name may be NULL, but not both. */
+/* Any existing association is overwritten. Installed profiles */
+/* are not deleted. */
+ucmm_error ucmm_install_monitor_profile(
+ ucmm_scope scope, /* Scope of instalation */
+ unsigned char *edid, /* Primary device identifier, NULL if none. */
+ int edid_len, /* Length of edid data */
+ char *display_name, /* Fall back device association, */
+ /* the X11 display name */
+ char *profile /* Path to profile to be installed. */
+);
+
+/* Un-install a profile for a given monitor. */
+/* Either EDID or display_name may be NULL, but not both. */
+/* The monitor is left with no profile association. If a profile */
+/* name is provided and matches the one that was associated with */
+/* the monitor, and has no other association, then it will be deleted */
+/* from the data directory. */
+/* Return an error code */
+ucmm_error ucmm_uninstall_monitor_profile(
+ ucmm_scope scope, /* Scope of instalation */
+ unsigned char *edid, /* Primary device identifier, NULL if none. */
+ int edid_len, /* Length of edid data */
+ char *display_name, /* Fall back device association, */
+ char *profile /* Base name of profile to be deleted, NULL if not to be deleted. */
+);
+
+/* Get an associated monitor profile. */
+/* Return ucmm_no_profile if there is no installed profile for this */
+/* monitor. */
+/* Return an error code */
+ucmm_error ucmm_get_monitor_profile(
+ unsigned char *edid, /* Primary device identifier, NULL if none. */
+ int edid_len, /* Length of edid data */
+ char *display_name, /* Fall back device association, */
+ char **profile /* Return path to profile. free() afterwards. */
+);
+
+/* Return an ASCII error message string interpretation of an error number */
+char *ucmm_error_string(ucmm_error erno);
+
+#endif /* UCMM_H */
diff --git a/usb/45-Argyll.rules b/usb/45-Argyll.rules
new file mode 100644
index 0000000..3f89f69
--- /dev/null
+++ b/usb/45-Argyll.rules
@@ -0,0 +1,62 @@
+# udev rule to change permissions so that the USB instruments can be accessed by Argyll
+# where the udev is old and doesn't understand the more modern syntax in 55-Argyll.rules.
+# Copy to /etc/udev/rules.d/45-Argyll.rules
+
+# Colorimtre HCFR
+SYSFS{idVendor}=="04db", SYSFS{idProduct}=="005b", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# MonacoOPTIX (Same as i1 Display 1)
+SYSFS{idVendor}=="0670", SYSFS{idProduct}=="0001", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+
+# Huey (Lenovo W70DS Laptop ?)
+SYSFS{idVendor}=="0765", SYSFS{idProduct}=="5001", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# Huey (Lenovo W530 Laptop ?)
+SYSFS{idVendor}=="0765", SYSFS{idProduct}=="5010", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# i1Display 3
+SYSFS{idVendor}=="0765", SYSFS{idProduct}=="5020", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# ColorMunki Smile
+SYSFS{idVendor}=="0765", SYSFS{idProduct}=="6003", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# DTP20
+SYSFS{idVendor}=="0765", SYSFS{idProduct}=="d020", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# DTP92Q - not tested
+SYSFS{idVendor}=="0765", SYSFS{idProduct}=="d092", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# DTP94
+SYSFS{idVendor}=="0765", SYSFS{idProduct}=="d094", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# Spyder 1
+SYSFS{idVendor}=="085c", SYSFS{idProduct}=="0100", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# Spyder 2
+SYSFS{idVendor}=="085c", SYSFS{idProduct}=="0200", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# Spyder 3
+SYSFS{idVendor}=="085c", SYSFS{idProduct}=="0300", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# Spyder 4
+SYSFS{idVendor}=="085c", SYSFS{idProduct}=="0400", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# i1Pro
+SYSFS{idVendor}=="0971", SYSFS{idProduct}=="2000", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# i1Monitor
+SYSFS{idVendor}=="0971", SYSFS{idProduct}=="2001", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# i1Display
+SYSFS{idVendor}=="0971", SYSFS{idProduct}=="2003", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# Huey
+SYSFS{idVendor}=="0971", SYSFS{idProduct}=="2005", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# ColorMunki
+SYSFS{idVendor}=="0971", SYSFS{idProduct}=="2007", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+
+# ColorHug
+SYSFS{idVendor}=="04d8", SYSFS{idProduct}=="f8da", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
+SYSFS{idVendor}=="273f", SYSFS{idProduct}=="1001", PROGRAM="/bin/sh -c 'K=%k; K=$${K#usbdev}; printf bus/usb/%%03i/%%03i $${K%%%%.*} $${K#*.}'", NAME="%c", MODE="660", GROUP="plugdev"
diff --git a/usb/55-Argyll.rules b/usb/55-Argyll.rules
new file mode 100644
index 0000000..9e083dc
--- /dev/null
+++ b/usb/55-Argyll.rules
@@ -0,0 +1,90 @@
+# udev rule to recognize instruments and make them accessible to user applications.
+# Copy this to /etc/udev/rules.d/55-Argyll.rules
+
+# Skip all this to speed things up if it'a not a usb add.
+ACTION!="add", GOTO="argyll_rules_end"
+SUBSYSTEM!="usb", GOTO="argyll_rules_end"
+
+# Recognize the color measurement devices
+
+# Colorimtre HCFR
+ATTRS{idVendor}=="04db", ATTRS{idProduct}=="005b", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# MonacoOPTIX (Same as i1 Display 1)
+ATTRS{idVendor}=="0670", ATTRS{idProduct}=="0001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# HueyL (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# HueyL (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5010", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Display 3
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="5020", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# ColorMunki Smile
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="6003", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP20
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d020", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP92Q (not tested)
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d092", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# DTP94
+ATTRS{idVendor}=="0765", ATTRS{idProduct}=="d094", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# i1Pro
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2000", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Monitor
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1Display
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2003", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1 io table (not tested)
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2004", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Huey
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2005", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# i1 iSis (not tested)
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2006", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# ColorMunki
+ATTRS{idVendor}=="0971", ATTRS{idProduct}=="2007", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# Spyder 1
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0100", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 2
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0200", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 3
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0300", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+# Spyder 4
+ATTRS{idVendor}=="085c", ATTRS{idProduct}=="0400", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# ColorHug, old and new
+ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="f8da", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1001", ENV{COLOR_MEASUREMENT_DEVICE}="1"
+
+
+# Let users access these devices
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", TAG+="uaccess"
+
+# Otherwise, restrict access to members of the plugdev group,
+# which the user may have to add to the system.
+ENV{COLOR_MEASUREMENT_DEVICE}=="*?", MODE="660", GROUP="plugdev"
+
+# Set ID_VENDOR and ID_MODEL acording to VID and PID
+IMPORT{builtin}="hwdb --subsystem=usb"
+
+LABEL="argyll_rules_end"
diff --git a/usb/Argyll b/usb/Argyll
new file mode 100644
index 0000000..b16d929
--- /dev/null
+++ b/usb/Argyll
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Copy to /etc/hotplug/usb/Argyll
+#
+# Argyll hotplug script. Adds the USB devices to the plugdev group.
+if [ "${ACTION}" = "add" ] && [ -f "${DEVICE}" ]
+then
+ chgrp plugdev "${DEVICE}"
+ chmod 660 "${DEVICE}"
+fi
diff --git a/usb/Argyll.kext/Info.plist b/usb/Argyll.kext/Info.plist
new file mode 100644
index 0000000..754e6d5
--- /dev/null
+++ b/usb/Argyll.kext/Info.plist
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key> <string>English</string>
+ <key>CFBundleGetInfoString</key> <string>Libusb USB device Shield</string>
+ <key>CFBundleIdentifier</key> <string>com.libusb.USB_Shield</string>
+ <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
+ <key>CFBundleName</key> <string>Libusb USB device Shield</string>
+ <key>CFBundlePackageType</key> <string>KEXT</string>
+ <key>CFBundleSignature</key> <string>????</string>
+ <key>CFBundleVersion</key> <string>6.0</string>
+ <key>IOKitPersonalities</key>
+ <dict>
+ <key>HCFR</key>
+ <dict>
+ <key>CFBundleIdentifier</key> <string>com.apple.driver.AppleUSBComposite</string>
+ <key>IOClass</key> <string>AppleUSBComposite</string>
+ <key>IOProviderClass</key> <string>IOUSBDevice</string>
+ <key>idVendor</key> <integer>1243</integer>
+ <key>idProduct</key> <integer>91</integer>
+ </dict>
+ </dict>
+ <key>OSBundleCompatibleVersion</key> <string>1.8</string>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kernel.iokit</key> <string>6.0</string>
+ </dict>
+</dict>
+</plist>
diff --git a/usb/Argyll.usermap b/usb/Argyll.usermap
new file mode 100644
index 0000000..00a350c
--- /dev/null
+++ b/usb/Argyll.usermap
@@ -0,0 +1,53 @@
+# hotplug device mapping to handling script.
+# Copy this to /etc/hotplug/usb/Argyll.usermap
+#
+# Detect instruments by their USB VID and PID
+#
+# DTP20
+Argyll 0x0003 0x0765 0xd020 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# DTP92Q - not tested
+Argyll 0x0003 0x0765 0xd092 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# DTP94
+Argyll 0x0003 0x0765 0xd094 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# MonacoOPTIX (Same as i1 Display 1)
+Argyll 0x0003 0x0670 0x0001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# i1 Display
+Argyll 0x0003 0x0971 0x2003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# i1 Display 3
+Argyll 0x0003 0x0765 0x5020 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# i1 Monitor
+Argyll 0x0003 0x0971 0x2001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# i1 Pro
+Argyll 0x0003 0x0971 0x2000 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# ColorMunki
+Argyll 0x0003 0x0971 0x2007 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# ColorMunki Smile
+Argyll 0x0003 0x0765 0x6003 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# Colorimtre HCFR
+Argyll 0x0003 0x04DB 0x005B 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# Spyder 2
+Argyll 0x0003 0x085C 0x0200 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# Spyder 3
+Argyll 0x0003 0x085C 0x0300 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# Spyder 4
+Argyll 0x0003 0x085C 0x0400 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# Huey
+Argyll 0x0003 0x0971 0x2005 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+#
+# ColorHug
+Argyll 0x0003 0x04D8 0xF8DA 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
+Argyll 0x0003 0x273F 0x1001 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x00000000
diff --git a/usb/ArgyllCMS.cat b/usb/ArgyllCMS.cat
new file mode 100644
index 0000000..d401490
--- /dev/null
+++ b/usb/ArgyllCMS.cat
@@ -0,0 +1,3 @@
+This file will contain the digital signature of the files to be installed
+on the system.
+This file will be provided by Microsoft upon certification of your drivers.
diff --git a/usb/ArgyllCMS.inf b/usb/ArgyllCMS.inf
new file mode 100644
index 0000000..64f5eca
--- /dev/null
+++ b/usb/ArgyllCMS.inf
@@ -0,0 +1,213 @@
+;--------------------------------------------------------------------------
+; Copyright 2012 Graeme W. Gill.
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this file, to deal
+; in this file without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of this file, and to permit persons to whom this file is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of this file.
+;
+; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
+; THIS FILE.
+;--------------------------------------------------------------------------
+
+; ==== Strings ====
+
+[Strings]
+
+DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
+
+Date = "01/17/2012" ; MM/DD/YYYY
+libusb0ver = "1.2.6.0"
+
+Libusb_ClassName = "Argyll LibUSB-win32 devices"
+Libusb_DiskName = "LibUSB-win32 Device Install Disk"
+
+libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
+
+; ==== Version ====
+
+[Version]
+Signature = "$Windows NT$"
+DriverVer = %Date%,%libusb0ver%
+Provider = "ArgyllCMS"
+
+; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
+Class = %Libusb_ClassName%
+ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
+CatalogFile = "ArgyllCMS.cat"
+CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
+
+[ClassInstall32]
+AddReg=class_install_add_reg
+
+[class_install_add_reg]
+HKR,,,,%Libusb_ClassName%
+HKR,,Icon,,"-20" ; -20 is for the USB icon
+
+; ==== Files Sources and Destinations ====
+
+[SourceDisksNames]
+1 = %Libusb_DiskName%
+
+[SourceDisksFiles]
+libusb0.sys = 1,\bin\x86,
+
+[SourceDisksFiles.amd64]
+libusb0.sys = 1,\bin\amd64,
+
+[DestinationDirs]
+libusb0_files_sys = 10,system32\drivers
+
+; ==== libusb0 Device driver ====
+
+[libusb0_files_sys]
+libusb0.sys,libusb0.sys
+
+; For each one of these, there must be one for Services !!!
+[LIBUSB0_DEV]
+CopyFiles = Libusb0_files_sys
+
+[LIBUSB0_DEV.HW]
+AddReg = libusb0_add_reg_hw
+
+[libusb0_add_reg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,libusb0.sys
+
+[libusb0_add_reg_hw]
+HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
+HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
+
+[LIBUSB0_DEV.Services]
+AddService = libusb0, 0x00000002, libusb0_add_service
+
+[libusb0_add_service]
+DisplayName = %libusb0_SvcDesc%
+ServiceType = 1
+StartType = 3
+ErrorControl = 0
+ServiceBinary = %12%\libusb0.sys
+
+; ==== Manufacturers ====
+
+[Manufacturer]
+"HCFR Association"=HCFR_Devices,NTx86,NTamd64
+"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
+"X-Rite"=X_Rite_Devices,NTx86,NTamd64
+"ColorVision"=ColorVision_Devices,NTx86,NTamd64
+"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
+"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
+
+; ==== Devices ====
+
+[HCFR_Devices]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+
+[GM_X_Rite_Devices]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices]
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+
+[HCFR_Devices.NTx86]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices.NTx86]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices.NTx86]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices.NTx86]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+
+[GM_X_Rite_Devices.NTx86]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices.NTx86]
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
+
+[HCFR_Devices.NTamd64]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices.NTamd64]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices.NTamd64]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices.NTamd64]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+
+[GM_X_Rite_Devices.NTamd64]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices.NTamd64]
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
diff --git a/usb/ArgyllCMS.inf.d b/usb/ArgyllCMS.inf.d
new file mode 100644
index 0000000..cb7eb5d
--- /dev/null
+++ b/usb/ArgyllCMS.inf.d
@@ -0,0 +1,34 @@
+
+[HCFR_Devices#PLAT#]
+"Colorimtre HCFR V3.1 (Argyll)" = LIBUSB0_DEV, USB\VID_04DB&PID_005B
+"Colorimtre HCFR V4.0 (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_FE17
+
+[Sequel_Devices#PLAT#]
+"Eye-One Display 1 (Argyll)" = LIBUSB0_DEV, USB\VID_0670&PID_0001
+
+[X_Rite_Devices#PLAT#]
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5001
+"HueyL (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5010
+"Eye-One Display 3 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_5020
+"ColorMunki Smile (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_6003
+"DTP20 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D020
+"DTP92Q (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D092
+"DTP94 (Argyll)" = LIBUSB0_DEV, USB\VID_0765&PID_D094
+
+[ColorVision_Devices#PLAT#]
+"Spyder1 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0100
+"Spyder2 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0200
+"Spyder3 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0300
+"Spyder4 (Argyll)" = LIBUSB0_DEV, USB\VID_085C&PID_0400
+
+[GM_X_Rite_Devices#PLAT#]
+"Eye-One Pro (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2000
+"Eye-One Monitor (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2001
+"Eye-One Display 2 (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2003
+"Huey (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2005
+"ColorMunki (Argyll)" = LIBUSB0_DEV, USB\VID_0971&PID_2007
+
+[Hughski_Devices#PLAT#]
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_273F&PID_1001
+"ColorHug (Argyll)" = LIBUSB0_DEV, USB\VID_04D8&PID_F8DA
+
diff --git a/usb/ArgyllCMS.inf.t b/usb/ArgyllCMS.inf.t
new file mode 100644
index 0000000..d810d4f
--- /dev/null
+++ b/usb/ArgyllCMS.inf.t
@@ -0,0 +1,111 @@
+;--------------------------------------------------------------------------
+; Copyright 2012 Graeme W. Gill.
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this file, to deal
+; in this file without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of this file, and to permit persons to whom this file is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of this file.
+;
+; THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN
+; THIS FILE.
+;--------------------------------------------------------------------------
+
+; ==== Strings ====
+
+[Strings]
+
+DeviceGUID = {247e32a0-32f9-11df-aacc-0002a5d5c51b}
+
+Date = "01/17/2012" ; MM/DD/YYYY
+libusb0ver = "1.2.6.0"
+
+Libusb_ClassName = "Argyll LibUSB-win32 devices"
+Libusb_DiskName = "LibUSB-win32 Device Install Disk"
+
+libusb0_SvcDesc = "LibUSB-win32 libusb0 - Kernel Driver 2012/1/17, 1.2.6.0"
+
+; ==== Version ====
+
+[Version]
+Signature = "$Windows NT$"
+DriverVer = %Date%,%libusb0ver%
+Provider = "ArgyllCMS"
+
+; (Note the ClassGuid must not be quoted or a string substitution to work on Win2K)
+Class = %Libusb_ClassName%
+ClassGuid = {817cffe0-328b-11df-9b9f-0002a5d5c51b} ; LibUSB-win32 ClassGUID
+CatalogFile = "ArgyllCMS.cat"
+CatalogFile.NTAMD64 = "ArgyllCMS_x64.cat"
+
+[ClassInstall32]
+AddReg=class_install_add_reg
+
+[class_install_add_reg]
+HKR,,,,%Libusb_ClassName%
+HKR,,Icon,,"-20" ; -20 is for the USB icon
+
+; ==== Files Sources and Destinations ====
+
+[SourceDisksNames]
+1 = %Libusb_DiskName%
+
+[SourceDisksFiles]
+libusb0.sys = 1,\bin\x86,
+
+[SourceDisksFiles.amd64]
+libusb0.sys = 1,\bin\amd64,
+
+[DestinationDirs]
+libusb0_files_sys = 10,system32\drivers
+
+; ==== libusb0 Device driver ====
+
+[libusb0_files_sys]
+libusb0.sys,libusb0.sys
+
+; For each one of these, there must be one for Services !!!
+[LIBUSB0_DEV]
+CopyFiles = Libusb0_files_sys
+
+[LIBUSB0_DEV.HW]
+AddReg = libusb0_add_reg_hw
+
+[libusb0_add_reg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,libusb0.sys
+
+[libusb0_add_reg_hw]
+HKR,,DeviceInterfaceGUIDs,0x10000,%DeviceGUID%
+HKR,,SurpriseRemovalOK,0x00010001,1 ; Device properties
+
+[LIBUSB0_DEV.Services]
+AddService = libusb0, 0x00000002, libusb0_add_service
+
+[libusb0_add_service]
+DisplayName = %libusb0_SvcDesc%
+ServiceType = 1
+StartType = 3
+ErrorControl = 0
+ServiceBinary = %12%\libusb0.sys
+
+; ==== Manufacturers ====
+
+[Manufacturer]
+"HCFR Association"=HCFR_Devices,NTx86,NTamd64
+"Sequel Imaging"=Sequel_Devices,NTx86,NTamd64
+"X-Rite"=X_Rite_Devices,NTx86,NTamd64
+"ColorVision"=ColorVision_Devices,NTx86,NTamd64
+"Gretag Macbeth/X-Rite"=GM_X_Rite_Devices,NTx86,NTamd64
+"Hughski Ltd"=Hughski_Devices,NTx86,NTamd64
+
+; ==== Devices ====
diff --git a/usb/ArgyllCMS_x64.cat b/usb/ArgyllCMS_x64.cat
new file mode 100644
index 0000000..d401490
--- /dev/null
+++ b/usb/ArgyllCMS_x64.cat
@@ -0,0 +1,3 @@
+This file will contain the digital signature of the files to be installed
+on the system.
+This file will be provided by Microsoft upon certification of your drivers.
diff --git a/usb/Jamfile b/usb/Jamfile
new file mode 100644
index 0000000..403e3f2
--- /dev/null
+++ b/usb/Jamfile
@@ -0,0 +1,52 @@
+
+# JAM style makefile for libusb-win32, to create .inf files.
+
+# This doesn't make the drivers themselves.
+# (you need the Server 2003 DDK 64 & 32 bit build enironmantes,
+# and then run ddk_build.cmd. This will then run
+# build in libusb/os. )
+
+#PREF_CCFLAGS = $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS = $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS = $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS = $(LINKDEBUGFLAG) ; # Link debugging flags
+
+#Products
+#Libraries = ;
+#Executables = ;
+#Headers = ;
+
+#Install
+#InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+if [ GLOB $(PATH) : sed sed.exe ] {
+ Echo "sed seems to be available" ;
+ CREATE_INFS = true ;
+} else {
+ CREATE_INFS = false ;
+}
+
+# Create ArgyllCMS.inf from the template and device list
+if $(CREATE_INFS) = true {
+ local _i _t _d ;
+ NDepends files : ArgyllCMS.inf ;
+ NDepends install : ArgyllCMS.inf ArgyllCMS.cat ArgyllCMS_x64.cat ;
+
+ _i = [ NormPaths ArgyllCMS.inf ] ;
+ _t = [ NormPaths ArgyllCMS.inf.t ] ;
+ _d = [ NormPaths ArgyllCMS.inf.d ] ;
+
+ File ArgyllCMS.inf : ArgyllCMS.inf.t ;
+ GenFileNND ArgyllCMS.inf : "sed s/#PLAT#// $(_d) >> $(_i)" : ArgyllCMS.inf.t ArgyllCMS.inf.d ;
+ GenFileNND ArgyllCMS.inf : "sed s/#PLAT#/.NTx86/ $(_d) >> $(_i)" : ArgyllCMS.inf.t ArgyllCMS.inf.d ;
+ GenFileNND ArgyllCMS.inf : "sed s/#PLAT#/.NTamd64/ $(_d) >> $(_i)" : ArgyllCMS.inf.t ArgyllCMS.inf.d ;
+}
+
+
+
+
+
+
+
diff --git a/usb/Readme.txt b/usb/Readme.txt
new file mode 100644
index 0000000..999db32
--- /dev/null
+++ b/usb/Readme.txt
@@ -0,0 +1,8 @@
+
+Here are the necessary files to install the MSWin
+instrument device drivers, and build the spectro/usbio_nt
+library that uses the device drivers.
+
+The source to the kernel driver is here, but not built with
+Argyll. The pre-built, signed drivers are used.
+
diff --git a/usb/afiles b/usb/afiles
new file mode 100644
index 0000000..fe1116b
--- /dev/null
+++ b/usb/afiles
@@ -0,0 +1,60 @@
+afiles
+binfiles.msw
+binfiles.osx
+binfiles.lx
+Readme.txt
+Jamfile
+45-Argyll.rules
+55-Argyll.rules
+Argyll
+Argyll.usermap
+Argyll.kext/Info.plist
+install_kext.sh
+ArgyllCMS.inf
+ArgyllCMS.cat
+ArgyllCMS_x64.cat
+ArgyllCMS.inf.t
+ArgyllCMS.inf.d
+bin/libusb-win32-bin-README.txt
+bin/amd64/libusb0.sys
+bin/ia64/libusb0.sys
+bin/x86/libusb0.sys
+driver/libusb-win32-README-1.2.6.0.txt
+driver/LICENSE.txt
+driver/README.txt
+driver/AUTHORS.txt
+driver/COPYING_GPL.txt
+driver/Makefile
+driver/abort_endpoint.c
+driver/claim_interface.c
+driver/clear_feature.c
+driver/dispatch.c
+driver/driver_api.h
+driver/driver_debug.c
+driver/driver_debug.h
+driver/driver_registry.c
+driver/get_configuration.c
+driver/get_descriptor.c
+driver/get_interface.c
+driver/get_status.c
+driver/ioctl.c
+driver/libusb_driver.c
+driver/libusb_driver.h
+driver/libusb_driver_rc.rc
+driver/lusb_defdi_guids.h
+driver/pnp.c
+driver/power.c
+driver/release_interface.c
+driver/reset_device.c
+driver/reset_endpoint.c
+driver/set_configuration.c
+driver/set_descriptor.c
+driver/set_feature.c
+driver/set_interface.c
+driver/transfer.c
+driver/usbd.def
+driver/usbdlib_gcc.h
+driver/vendor_request.c
+
+
+
diff --git a/usb/bin/amd64/libusb0.sys b/usb/bin/amd64/libusb0.sys
new file mode 100644
index 0000000..0718dfb
--- /dev/null
+++ b/usb/bin/amd64/libusb0.sys
Binary files differ
diff --git a/usb/bin/ia64/libusb0.sys b/usb/bin/ia64/libusb0.sys
new file mode 100644
index 0000000..f17914b
--- /dev/null
+++ b/usb/bin/ia64/libusb0.sys
Binary files differ
diff --git a/usb/bin/libusb-win32-bin-README.txt b/usb/bin/libusb-win32-bin-README.txt
new file mode 100644
index 0000000..455eb6b
--- /dev/null
+++ b/usb/bin/libusb-win32-bin-README.txt
@@ -0,0 +1,27 @@
+libusb-win32-bin v1.2.6.0 (01/17/2012) - [Package Information]
+
+ALL ARCHITECTURES:
+ x86\libusb0_x86.dll: x86 32-bit library. Must be renamed to libusb0.dll
+ On 64 bit, Installs to Windows\syswow64\libusb0.dll.
+ On 32 bit, Installs to Windows\system32\libusb0.dll.
+
+ x86\inf-wizard.exe: inf-wizard application with embedded libusb-win32
+ v1.2.6.0 binaries.
+
+X86 ONLY ARCHITECTURES:
+ x86\libusb0.sys: x86 32-bit driver.
+ Installs to Windows\system32\drivers\libusb0.sys
+
+AMD64-INTEL64 ONLY ARCHITECTURES:
+ amd64\libusb0.sys: x64 64-bit driver.
+ Installs to Windows\system32\drivers\libusb0.sys
+
+ amd64\libusb0.dll: x64 64-bit library.
+ Installs to Windows\system32\libusb0.dll
+
+IA64 ONLY ARCHITECTURES:
+ ia64\libusb0.sys: IA64 64-bit driver.
+ Installs to Windows\system32\drivers\libusb0.sys
+
+ ia64\libusb0.dll: IA64 64-bit library.
+ Installs to Windows\system32\libusb0.dll
diff --git a/usb/bin/x86/libusb0.sys b/usb/bin/x86/libusb0.sys
new file mode 100644
index 0000000..5322e5b
--- /dev/null
+++ b/usb/bin/x86/libusb0.sys
Binary files differ
diff --git a/usb/binfiles.lx b/usb/binfiles.lx
new file mode 100644
index 0000000..7dd8767
--- /dev/null
+++ b/usb/binfiles.lx
@@ -0,0 +1,4 @@
+45-Argyll.rules
+55-Argyll.rules
+Argyll
+Argyll.usermap
diff --git a/usb/binfiles.msw b/usb/binfiles.msw
new file mode 100644
index 0000000..f498d92
--- /dev/null
+++ b/usb/binfiles.msw
@@ -0,0 +1,6 @@
+bin/libusb-win32-bin-README.txt
+bin/x86/libusb0.sys
+bin/amd64/libusb0.sys
+ArgyllCMS.cat
+ArgyllCMS.inf
+ArgyllCMS_x64.cat
diff --git a/usb/binfiles.osx b/usb/binfiles.osx
new file mode 100644
index 0000000..60ed4ec
--- /dev/null
+++ b/usb/binfiles.osx
@@ -0,0 +1,2 @@
+Argyll.kext/Info.plist
+install_kext.sh
diff --git a/usb/driver/AUTHORS.txt b/usb/driver/AUTHORS.txt
new file mode 100644
index 0000000..375ec6c
--- /dev/null
+++ b/usb/driver/AUTHORS.txt
@@ -0,0 +1,16 @@
+
+Library, Test Programs:
+
+Stephan Meyer, <ste_meyer@web.de>
+Johannes Erdfelt, <johannes@erdfelt.com>
+Thomas Sailer, <sailer@ife.ee.ethz.ch>
+
+Drivers, Installer:
+
+Stephan Meyer, <ste_meyer@web.de>
+Travis Robinson, <libusbdotnet@gmail.com>
+
+Testing, Technical support:
+
+Xiaofan Chen, <xiaofanc@gmail.com>
+
diff --git a/usb/driver/COPYING_GPL.txt b/usb/driver/COPYING_GPL.txt
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/usb/driver/COPYING_GPL.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/usb/driver/LICENSE.txt b/usb/driver/LICENSE.txt
new file mode 100644
index 0000000..d8dd99d
--- /dev/null
+++ b/usb/driver/LICENSE.txt
@@ -0,0 +1,9 @@
+
+The library (DLL) is distributed under the terms of the GNU Lesser General Public License (LGPL).
+
+All other components (drivers, services, installer) are distributed under the terms of the GNU General Public License (GPL).
+
+This license combination explicitly allows the use of this library in commercial, non Open Source applications. Read the licenses carefully and apply all of their requirements before including this library in a commercial application!
+
+[ Taken from the libsub-win32 web page <http://libusb-win32.sourceforge.net./#license>
+ on the 14th of December 2007 - GWG ]
diff --git a/usb/driver/Makefile b/usb/driver/Makefile
new file mode 100644
index 0000000..18937ab
--- /dev/null
+++ b/usb/driver/Makefile
@@ -0,0 +1,261 @@
+# LIBUSB-WIN32, Generic Windows USB Library
+# Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+# Copyright (c) 2010 Travis Robinson <libusbdotnet@gmail.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+# Supported arugments: all, dll, filter, infwizard, test, testwin, driver
+#
+#
+
+# If you're cross-compiling and your mingw32 tools are called
+# i586-mingw32msvc-gcc and so on, then you can compile libusb-win32
+# by running
+# make host_prefix=i586-mingw32msvc all
+
+ifdef host_prefix
+ override host_prefix := $(host_prefix)-
+endif
+ifdef host_prefix_x86
+ override host_prefix_x86 := $(host_prefix_x86)-
+endif
+ifdef cflags
+ DBG_DEFINE = $(cflags)
+endif
+
+CC = $(host_prefix)gcc
+LD = $(host_prefix)ld
+WINDRES = $(host_prefix)windres
+DLLTOOL = $(host_prefix)dlltool
+
+CC86 = $(host_prefix_x86)gcc
+LD86 = $(host_prefix_x86)ld
+WINDRES86 = windres
+DLLTOOL86 = dlltool
+
+MAKE = make
+CP = cp
+CD = cd
+MV = mv
+RM = -rm -fr
+TAR = tar
+ISCC = iscc
+INSTALL = install
+LIB = lib
+IMPLIB = implib
+UNIX2DOS = unix2dos
+
+TARGET = libusb
+DLL_TARGET = $(TARGET)0
+LIB_TARGET = $(TARGET)
+DRIVER_TARGET = $(TARGET)0.sys
+INSTALL_DIR = /usr
+VPATH = .:./src:./src/driver:./tests
+
+LIBWDI_DIR = ./projects/additional/libwdi/libwdi
+SRC_DIR = ./src
+DRIVER_SRC_DIR = $(SRC_DIR)/driver
+
+LIBWDI_CONFIG_H = -DWDF_VER=\"01009\" -DUSER_DIR=\"\" -DOPT_M32 -DWINVER=0x500
+
+DRIVER_OBJECTS = abort_endpoint.o claim_interface.o clear_feature.o \
+ dispatch.o get_configuration.o \
+ get_descriptor.o get_interface.o get_status.o \
+ ioctl.o libusb_driver.o pnp.o release_interface.o reset_device.o \
+ reset_endpoint.o set_configuration.o set_descriptor.o \
+ set_feature.o set_interface.o transfer.o vendor_request.o \
+ power.o driver_registry.o error.o libusb_driver_rc.o
+
+LIBWDI_OBJECTS = $(LIBWDI_DIR)/logging.5.o \
+ $(LIBWDI_DIR)/tokenizer.5.o \
+ $(LIBWDI_DIR)/vid_data.5.o \
+ $(LIBWDI_DIR)/libwdi_dlg.5.o \
+ $(LIBWDI_DIR)/libwdi.5.o
+
+
+INCLUDES = -I./src -I./src/driver -I.
+
+CFLAGS = -O2 -Wall -DWINVER=0x500 $(DBG_DEFINE)
+WIN_CFLAGS = $(CFLAGS) -mwindows
+
+WINDRES_FLAGS = -I$(SRC_DIR)
+
+STDC_LD_LIBS=-lkernel32 \
+ -luser32 \
+ -lgdi32 \
+ -lwinspool \
+ -lcomdlg32 \
+ -ladvapi32 \
+ -lshell32 \
+ -lole32 \
+ -loleaut32 \
+ -luuid \
+ -lodbc32 \
+ -lodbccp32
+
+LDFLAGS = -s -L. -lusb -lgdi32 -luser32 -lcfgmgr32 -lsetupapi -lcomctl32
+TEST_WIN_LDFLAGS = -s -L. -lusb -lkernel32 -lgdi32 -luser32 -lnewdev -lsetupapi -lcomctl32 -lole32 -mwindows
+WIN_LDFLAGS = -s -L. -lkernel32 -lgdi32 -luser32 -lnewdev -lsetupapi -lcomctl32 -lole32 -mwindows
+DLL_LDFLAGS = -s -mdll \
+ -Wl,--kill-at \
+ -Wl,--out-implib,$(LIB_TARGET).a \
+ -Wl,--enable-stdcall-fixup \
+ -L. -lcfgmgr32 -lsetupapi -lgdi32
+
+LIBWDI_DLL_LDFLAGS = -s -shared \
+ -Wl,--kill-at \
+ -Wl,--out-implib,libwdi.a \
+ -Wl,--enable-stdcall-fixup \
+ -L. -lnewdev -lsetupapi -lole32
+
+DRIVER_LDFLAGS = -s -shared -Wl,--entry,_DriverEntry@8 \
+ -nostartfiles -nostdlib -L. -lusbd -lntoskrnl -lhal
+
+
+.PHONY: all
+all: dll filter test testwin
+
+.PHONY: dll
+dll: DLL_CFLAGS = $(CFLAGS) -DLOG_APPNAME=\"$(DLL_TARGET)-dll\" -DTARGETTYPE=DYNLINK
+dll: $(DLL_TARGET).dll
+
+$(DLL_TARGET).dll: usb.2.o error.2.o descriptors.2.o windows.2.o install.2.o registry.2.o resource.2.o
+ $(CC) $(DLL_CFLAGS) -o $@ -I./src $^ $(DLL_TARGET).def $(DLL_LDFLAGS)
+
+%.2.o: %.c libusb_driver.h driver_api.h error.h
+ $(CC) $(DLL_CFLAGS) -c $< -o $@ $(CPPFLAGS) $(INCLUDES)
+
+%.2.o: %.rc
+ $(WINDRES) $(CPPFLAGS) $(WINDRES_FLAGS) $< -o $@
+
+.PHONY: filter
+filter: FILTER_CFLAGS = $(CFLAGS) -DLOG_APPNAME=\"install-filter\" -DTARGETTYPE=PROGRAMconsole -DLOG_STYLE_SHORT
+filter: FILTER_LDFLAGS = -s -L. -lgdi32 -luser32 -lcfgmgr32 -lsetupapi
+filter: install-filter.exe
+
+
+install-filter.exe: install_filter.1.o error.1.o install.1.o registry.1.o install_filter_rc.1.o
+ $(CC) $(FILTER_CFLAGS) -o $@ -I./src $^ $(FILTER_LDFLAGS)
+
+%.1.o: %.c libusb_driver.h driver_api.h error.h
+ $(CC) $(FILTER_CFLAGS) -c $< -o $@ $(CPPFLAGS) $(INCLUDES)
+
+%.1.o: %.rc
+ $(WINDRES) $(CPPFLAGS) $(WINDRES_FLAGS) $< -o $@
+
+.PHONY: test
+test: dll
+test: TEST_CFLAGS = $(CFLAGS) -DLOG_APPNAME=\"testlibusb\" -DTARGETTYPE=PROGRAMconsole
+test: testlibusb.exe
+
+testlibusb.exe: testlibusb.3.o
+ $(CC) $(TEST_CFLAGS) -o $@ -I./src $^ $(LDFLAGS)
+
+%.3.o: %.c libusb_driver.h driver_api.h error.h
+ $(CC) -c $< -o $@ $(TEST_CFLAGS) $(CPPFLAGS) $(INCLUDES)
+
+.PHONY: testwin
+testwin: dll
+testwin: TESTWIN_CFLAGS = $(CFLAGS) -DLOG_APPNAME=\"testlibusb-win\" -DTARGETTYPE=PROGRAMwindows
+testwin: testlibusb-win.exe
+
+testlibusb-win.exe: testlibusb_win.4.o testlibusb_win_rc.4.o
+ $(CC) $(TESTWIN_CFLAGS) -o $@ -I./src $^ $(TEST_WIN_LDFLAGS)
+
+%.4.o: %.c libusb_driver.h driver_api.h error.h
+ $(CC) -c $< -o $@ $(TESTWIN_CFLAGS) $(CPPFLAGS) $(INCLUDES)
+
+%.4.o: %.rc
+ $(WINDRES) $(CPPFLAGS) $(WINDRES_FLAGS) $< -o $@
+
+#
+# LIBWDI installer_x86
+#
+.PHONY: installer_x86
+installer_x86: INSTALLER_CFLAGS = $(CFLAGS) -DLOG_APPNAME=\"installer_x86\" -DTARGETTYPE=PROGRAMconsole $(LIBWDI_CONFIG_H)
+installer_x86: INSTALLER_LDFLAGS = -s -L. -ladvapi32 -lnewdev -lsetupapi
+installer_x86: installer_x86.exe
+
+installer_x86.exe: $(LIBWDI_DIR)/installer.6.o
+ $(CC86) $(INSTALLER_CFLAGS) -o $@ -I$(LIBWDI_DIR) $^ $(INSTALLER_LDFLAGS)
+ $(CP) $(LIBWDI_DIR)/../msvc/config.h $(LIBWDI_DIR)
+
+%.6.o: %.c $(LIBWDI_DIR)/installer.h
+ $(CC86) -c $< -o $@ $(INSTALLER_CFLAGS) $(CPPFLAGS) -DWINVER=0x500 -I$(LIBWDI_DIR)
+
+#
+# LIBWDI embedder
+#
+.PHONY: embedder
+embedder: installer_x86
+embedder: EMBEDDER_CFLAGS = $(CFLAGS) -DLOG_APPNAME=\"embedder\" -DTARGETTYPE=PROGRAMconsole $(LIBWDI_CONFIG_H)
+embedder: EMBEDDER_LDFLAGS = -s -L. -luser32 -lversion
+embedder: embedder.exe
+
+embedder.exe: $(LIBWDI_DIR)/embedder.7.o
+ $(CC86) $(EMBEDDER_CFLAGS) -o $@ -I$(LIBWDI_DIR) $^ $(EMBEDDER_LDFLAGS)
+ $(CP) -u $(LIBWDI_DIR)/winusb.inf.in ./
+ $(CP) -u $(LIBWDI_DIR)/libusb-win32.inf.in ./
+ ./embedder.exe embedded.h
+
+%.7.o: %.c $(LIBWDI_DIR)/embedder.h
+ $(CC86) -c $< -o $@ $(EMBEDDER_CFLAGS) $(CPPFLAGS) -DWINVER=0x500 -I$(LIBWDI_DIR)
+
+.PHONY: infwizard
+infwizard: embedder
+infwizard: INFWIZARD_CFLAGS = $(CFLAGS) -DLOG_APPNAME=\"infwizard\" -DTARGETTYPE=PROGRAMwindows
+infwizard: inf-wizard.exe
+
+inf-wizard.exe: inf_wizard.5.o inf_wizard_rc.5.o $(LIBWDI_OBJECTS)
+ $(CC86) $(WIN_CFLAGS) -o $@ -I./src -I$(LIBWDI_DIR) $^ $(WIN_LDFLAGS)
+
+%.5.o: %.c libusb-win32_version.h $(LIBWDI_DIR)/libwdi.h
+ $(CC86) -c $< -o $@ -I$(LIBWDI_DIR) $(INFWIZARD_CFLAGS) $(CPPFLAGS) $(INCLUDES)
+
+%.5.o: %.rc
+ $(WINDRES86) $(CPPFLAGS) $(WINDRES_FLAGS) $< -o $@
+
+.PHONY: driver
+driver: DRIVER_CFLAGS = $(CFLAGS) -DLOG_APPNAME=\"$(DLL_TARGET)-sys\" -DTARGETTYPE=DRIVER
+driver: $(DRIVER_TARGET)
+
+$(DRIVER_TARGET): libusbd.a $(DRIVER_OBJECTS)
+ $(CC) -o $@ $(DRIVER_OBJECTS) $(DLL_TARGET)_drv.def $(DRIVER_LDFLAGS)
+
+libusbd.a:
+ $(DLLTOOL) --dllname usbd.sys --add-underscore --def ./src/driver/usbd.def --output-lib libusbd.a
+
+%.o: %.c libusb_driver.h driver_api.h error.h
+ $(CC) -c $< -o $@ $(DRIVER_CFLAGS) $(CPPFLAGS) $(INCLUDES)
+
+%.o: %.rc
+ $(WINDRES) $(CPPFLAGS) $(WINDRES_FLAGS) $< -o $@
+
+.PHONY: cleantemp
+cleantemp:
+ $(RM) *.o *.a *.exp *.tar.gz *~ *.iss *.rc *.h
+ $(RM) $(LIBWDI_DIR)/*.o
+ $(RM) $(LIBWDI_DIR)/config.h
+ $(RM) ./src/*~ *.log
+ $(RM) $(DRIVER_SRC_DIR)/*~
+ $(RM) README.txt
+ $(RM) winusb.inf.in
+ $(RM) libusb-win32.inf.in
+ $(RM) inf_wizard.ico
+
+.PHONY: clean
+clean: cleantemp
+ $(RM) *.dll *.lib *.exe *.sys
diff --git a/usb/driver/README.txt b/usb/driver/README.txt
new file mode 100644
index 0000000..0dc3ac0
--- /dev/null
+++ b/usb/driver/README.txt
@@ -0,0 +1,12 @@
+
+This is libusb-win32 (http://libusb-win32.sourceforge.net) version 1.2.6.0.
+Libusb-win32 is a library that allows userspace application to access USB
+devices on Windows operation systems (Win2k, WinXP, Vista, Win7).
+It is derived from and fully API compatible to libusb available at
+http://libusb.sourceforge.net.
+
+For more information visit the project's web site at:
+
+http://libusb-win32.sourceforge.net
+http://sourceforge.net/projects/libusb-win32
+
diff --git a/usb/driver/abort_endpoint.c b/usb/driver/abort_endpoint.c
new file mode 100644
index 0000000..3ec46e9
--- /dev/null
+++ b/usb/driver/abort_endpoint.c
@@ -0,0 +1,56 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS abort_endpoint(libusb_device_t *dev, int endpoint, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ USBMSG("endpoint: 0x%02x timeout: %d\n", endpoint, timeout);
+
+ memset(&urb, 0, sizeof(struct _URB_PIPE_REQUEST));
+
+ if (!dev->config.value)
+ {
+ USBERR0("invalid configuration 0\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ if (!get_pipe_handle(dev, endpoint, &urb.UrbPipeRequest.PipeHandle))
+ {
+ USBERR0("getting endpoint pipe failed\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST);
+ urb.UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("request failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ }
+
+ return status;
+}
diff --git a/usb/driver/claim_interface.c b/usb/driver/claim_interface.c
new file mode 100644
index 0000000..9ec0fe5
--- /dev/null
+++ b/usb/driver/claim_interface.c
@@ -0,0 +1,89 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS claim_interface(libusb_device_t *dev, FILE_OBJECT *file_object,
+ int interface)
+{
+ USBMSG("interface %d\n", interface);
+
+ if (!dev->config.value)
+ {
+ USBERR0("device is not configured\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ if (interface >= LIBUSB_MAX_NUMBER_OF_INTERFACES)
+ {
+ USBERR("interface number %d too high\n",
+ interface);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!dev->config.interfaces[interface].valid)
+ {
+ USBERR("interface %d does not exist\n", interface);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (dev->config.interfaces[interface].file_object == file_object)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ if (dev->config.interfaces[interface].file_object)
+ {
+ USBERR("could not claim interface %d, interface is already claimed\n", interface);
+ return STATUS_DEVICE_BUSY;
+ }
+
+ dev->config.interfaces[interface].file_object = file_object;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS claim_interface_ex(libusb_device_t *dev,
+ FILE_OBJECT *file_object,
+ interface_request_t* interface_request)
+{
+ PUSB_INTERFACE_DESCRIPTOR interface_descriptor;
+
+ USBMSG("interface-%s=%d\n",
+ interface_request->intf_use_index ? "index" : "number",
+ interface_request->intf_use_index ? interface_request->interface_index : interface_request->interface_number);
+
+ if (!dev->config.value || !dev->config.descriptor)
+ {
+ USBERR0("device is not configured\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ interface_request->altsetting_index=FIND_INTERFACE_INDEX_ANY;
+ interface_descriptor = find_interface_desc_ex(dev->config.descriptor,dev->config.total_size,interface_request,NULL);
+ if (!interface_descriptor)
+ {
+ return STATUS_NO_MORE_ENTRIES;
+ }
+
+ return claim_interface(dev, file_object, interface_descriptor->bInterfaceNumber);
+}
diff --git a/usb/driver/clear_feature.c b/usb/driver/clear_feature.c
new file mode 100644
index 0000000..c3b5c24
--- /dev/null
+++ b/usb/driver/clear_feature.c
@@ -0,0 +1,64 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+NTSTATUS clear_feature(libusb_device_t *dev,
+ int recipient, int index, int feature, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ USBMSG("recipient: %02d index: %04d feature: %04d timeout: %d\n",
+ recipient,index,feature,timeout);
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
+
+ switch (recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ urb.UrbHeader.Function = URB_FUNCTION_CLEAR_FEATURE_TO_OTHER;
+ break;
+ default:
+ USBERR0("invalid recipient\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_FEATURE_REQUEST);
+ urb.UrbControlFeatureRequest.FeatureSelector = (USHORT)feature;
+ urb.UrbControlFeatureRequest.Index = (USHORT)index;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("clearing feature failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ }
+
+ return status;
+}
diff --git a/usb/driver/dispatch.c b/usb/driver/dispatch.c
new file mode 100644
index 0000000..8eccb21
--- /dev/null
+++ b/usb/driver/dispatch.c
@@ -0,0 +1,99 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+NTSTATUS DDKAPI dispatch(DEVICE_OBJECT *device_object, IRP *irp)
+{
+ libusb_device_t *dev = device_object->DeviceExtension;
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+
+ switch (stack_location->MajorFunction)
+ {
+ case IRP_MJ_PNP:
+ return dispatch_pnp(dev, irp);
+
+ case IRP_MJ_POWER:
+ // ID: 2960644 (farthen)
+ // You can't set the power state if the device is not handled at all
+ if(!dev->next_stack_device)
+ {
+ return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+ return dispatch_power(dev, irp);
+ }
+
+ /* since this driver may run as an upper filter we have to check whether */
+ /* the IRP is sent to this device object or to the lower one */
+ if (accept_irp(dev, irp))
+ {
+ switch (stack_location->MajorFunction)
+ {
+ case IRP_MJ_DEVICE_CONTROL:
+
+ if (dev->is_started)
+ {
+ return dispatch_ioctl(dev, irp);
+ }
+ else /* not started yet */
+ {
+ return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ case IRP_MJ_CREATE:
+
+ if (dev->is_started)
+ {
+ // only one driver can act as power policy owner and
+ // power_set_device_state() can only be issued by the PPO.
+ // disallow_power_control is set to true for drivers which
+ // we know cause a BSOD on any attempt to request power irps.
+ if (dev->power_state.DeviceState != PowerDeviceD0 && !dev->disallow_power_control)
+ {
+ /* power up the device, block until the call */
+ /* completes */
+ power_set_device_state(dev, PowerDeviceD0, TRUE);
+ }
+ return complete_irp(irp, STATUS_SUCCESS, 0);
+ }
+ else /* not started yet */
+ {
+ return complete_irp(irp, STATUS_INVALID_DEVICE_STATE, 0);
+ }
+
+ case IRP_MJ_CLOSE:
+
+ /* release all interfaces bound to this file object */
+ release_all_interfaces(dev, stack_location->FileObject);
+ return complete_irp(irp, STATUS_SUCCESS, 0);
+
+ case IRP_MJ_CLEANUP:
+
+ return complete_irp(irp, STATUS_SUCCESS, 0);
+
+ default:
+ return complete_irp(irp, STATUS_NOT_SUPPORTED, 0);
+ }
+ }
+ else /* the IRP is for the lower device object */
+ {
+ return pass_irp_down(dev, irp, NULL, NULL);
+ }
+}
+
diff --git a/usb/driver/driver_api.h b/usb/driver/driver_api.h
new file mode 100644
index 0000000..5339a81
--- /dev/null
+++ b/usb/driver/driver_api.h
@@ -0,0 +1,400 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __DRIVER_API_H__
+#define __DRIVER_API_H__
+
+enum
+{
+ LIBUSB_DEBUG_OFF,
+ LIBUSB_DEBUG_ERR,
+ LIBUSB_DEBUG_WRN,
+ LIBUSB_DEBUG_MSG,
+
+ LIBUSB_DEBUG_MAX = 0xff,
+};
+
+
+/* 64k */
+#define LIBUSB_MAX_READ_WRITE 0x10000
+
+#define LIBUSB_MAX_NUMBER_OF_DEVICES 256
+#define LIBUSB_MAX_NUMBER_OF_CHILDREN 32
+
+#define LIBUSB_IOCTL_SET_CONFIGURATION CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_GET_CONFIGURATION CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_SET_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_GET_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x804, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_SET_FEATURE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_CLEAR_FEATURE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x806, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_GET_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x807, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_SET_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x808, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_GET_DESCRIPTOR CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x809, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80A, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80B, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_VENDOR_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80C, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_VENDOR_READ CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80D, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_RESET_ENDPOINT CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80E, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_ABORT_ENDPOINT CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x80F, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_RESET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_SET_DEBUG_LEVEL CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x811, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x812, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_ISOCHRONOUS_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x813, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_ISOCHRONOUS_READ CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x814, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_CLAIM_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x815, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_RELEASE_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x816, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/////////////////////////////////////////////////////////////////////////////
+// supported after 0.1.12.2
+/////////////////////////////////////////////////////////////////////////////
+
+// [trobinso] adds support for querying device properties
+#define LIBUSB_IOCTL_GET_DEVICE_PROPERTY CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x900, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_GET_CUSTOM_REG_PROPERTY CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x901, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////
+// supported after 1.2.0.0
+/////////////////////////////////////////////////////////////////////////////
+#define LIBUSB_IOCTL_GET_CACHED_CONFIGURATION CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x902, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////
+// supported after 1.2.2.0
+/////////////////////////////////////////////////////////////////////////////
+#define LIBUSB_IOCTL_GET_OBJECT_NAME CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x8FF, METHOD_BUFFERED, FILE_ANY_ACCESS)
+/////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////
+// supported after 1.2.3.0
+/////////////////////////////////////////////////////////////////////////////
+#define LIBUSB_IOCTL_QUERY_DEVICE_INFORMATION CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x904, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_SET_PIPE_POLICY CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x906, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_GET_PIPE_POLICY CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x907, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_SET_POWER_POLICY CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x908, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_GET_POWER_POLICY CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x909, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_CONTROL_WRITE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x90A, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_CONTROL_READ CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x90B, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#define LIBUSB_IOCTL_FLUSH_PIPE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x90C, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSBK_IOCTL_CLAIM_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x90D, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSBK_IOCTL_RELEASE_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x90E, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSBK_IOCTL_RELEASE_ALL_INTERFACES CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x90F, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSBK_IOCTL_SET_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x910, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define LIBUSBK_IOCTL_GET_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN,\
+ 0x911, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/////////////////////////////////////////////////////////////////////////////
+// supported after 1.2.4.8 (libusb0.sys only)
+/////////////////////////////////////////////////////////////////////////////
+#define LIBUSB_IOCTL_RESET_DEVICE_EX CTL_CODE(FILE_DEVICE_UNKNOWN,\
+0x817, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#include <pshpack1.h>
+
+enum LIBUSB0_TRANSFER_FLAGS
+{
+ TRANSFER_FLAGS_SHORT_NOT_OK = 1 << 0,
+ TRANSFER_FLAGS_ISO_SET_START_FRAME = 1 << 30,
+ TRANSFER_FLAGS_ISO_ADD_LATENCY = 1 << 31,
+};
+
+/*
+typedef struct
+{
+ unsigned int timeout;
+ union
+ {
+ struct
+ {
+ unsigned int configuration;
+ } configuration;
+ struct
+ {
+ unsigned int interface;
+ unsigned int altsetting;
+ } interface;
+ struct
+ {
+ unsigned int endpoint;
+ unsigned int packet_size;
+
+ // TODO: max_transfer_size, short transfer not ok, use iso_start_frame
+ unsigned int max_transfer_size;
+ unsigned int transfer_flags;
+ unsigned int iso_start_frame_latency;
+ } endpoint;
+ struct
+ {
+ unsigned int type;
+ unsigned int recipient;
+ unsigned int request;
+ unsigned int value;
+ unsigned int index;
+ } vendor;
+ struct
+ {
+ unsigned int recipient;
+ unsigned int feature;
+ unsigned int index;
+ } feature;
+ struct
+ {
+ unsigned int recipient;
+ unsigned int index;
+ unsigned int status;
+ } status;
+ struct
+ {
+ unsigned int type;
+ unsigned int index;
+ unsigned int language_id;
+ unsigned int recipient;
+ } descriptor;
+ struct
+ {
+ unsigned int level;
+ } debug;
+ struct
+ {
+ unsigned int major;
+ unsigned int minor;
+ unsigned int micro;
+ unsigned int nano;
+ unsigned int mod_value;
+ } version;
+ struct
+ {
+ unsigned int property;
+ } device_property;
+ struct
+ {
+ unsigned int key_type;
+ unsigned int name_offset;
+ unsigned int value_offset;
+ unsigned int value_length;
+ } device_registry_key;
+ struct
+ {
+ // 0 - device plug and play registry key pathname
+ unsigned int objname_index;
+ } objname;
+ };
+} libusb_request;
+*/
+
+#pragma warning(disable:4201)
+
+typedef struct
+{
+ unsigned int interface_number;
+ unsigned int altsetting_number;
+
+ unsigned char intf_use_index:1; // libusbK Only
+ unsigned char altf_use_index:1; // libusbK Only
+ unsigned char:6;
+
+ short interface_index; // libusbK Only
+ short altsetting_index; // libusbK Only
+}interface_request_t;
+
+typedef struct
+{
+ unsigned int timeout;
+ union
+ {
+ struct
+ {
+ unsigned int configuration;
+ } configuration;
+
+ interface_request_t intf;
+
+ struct
+ {
+ unsigned int endpoint;
+ unsigned int packet_size;
+
+ // TODO: max_transfer_size, short transfer not ok, use iso_start_frame
+ unsigned int max_transfer_size;
+ unsigned int transfer_flags;
+ unsigned int iso_start_frame_latency;
+ } endpoint;
+ struct
+ {
+ unsigned int type;
+ unsigned int recipient;
+ unsigned int request;
+ unsigned int value;
+ unsigned int index;
+ } vendor;
+ struct
+ {
+ unsigned int recipient;
+ unsigned int feature;
+ unsigned int index;
+ } feature;
+ struct
+ {
+ unsigned int recipient;
+ unsigned int index;
+ unsigned int status;
+ } status;
+ struct
+ {
+ unsigned int type;
+ unsigned int index;
+ unsigned int language_id;
+ unsigned int recipient;
+ } descriptor;
+ struct
+ {
+ unsigned int level;
+ } debug;
+ struct
+ {
+ unsigned int major;
+ unsigned int minor;
+ unsigned int micro;
+ unsigned int nano;
+ unsigned int mod_value;
+ } version;
+ struct
+ {
+ unsigned int property;
+ } device_property;
+ struct
+ {
+ unsigned int key_type;
+ unsigned int name_offset;
+ unsigned int value_offset;
+ unsigned int value_length;
+ } device_registry_key;
+ struct
+ {
+ // 0 - device plug and play registry key pathname
+ unsigned int objname_index;
+ } objname;
+ struct
+ {
+ ULONG information_type;
+ } query_device;
+ struct
+ {
+ unsigned int interface_index;
+ unsigned int pipe_id;
+ unsigned int policy_type;
+ } pipe_policy;
+ struct
+ {
+ unsigned int policy_type;
+ } power_policy;
+ struct
+ {
+ unsigned int reset_type;
+ } reset_ex;
+
+ // WDF_USB_CONTROL_SETUP_PACKET control;
+ struct
+ {
+ UCHAR RequestType;
+ UCHAR Request;
+ USHORT Value;
+ USHORT Index;
+ USHORT Length;
+ } control;
+ };
+} libusb_request;
+#pragma warning(default:4201)
+
+#include <poppack.h>
+
+#endif
diff --git a/usb/driver/driver_debug.c b/usb/driver/driver_debug.c
new file mode 100644
index 0000000..49f1878
--- /dev/null
+++ b/usb/driver/driver_debug.c
@@ -0,0 +1,75 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+int debug_level = LIBUSB_DEBUG_MSG;
+
+void DEBUG_PRINT_NL()
+{
+#ifdef DBG
+ if (debug_level >= LIBUSB_DEBUG_MSG)
+ DbgPrint(("\n"));
+#endif
+}
+
+void DEBUG_SET_LEVEL(int level)
+{
+#ifdef DBG
+ debug_level = level;
+#endif
+}
+
+void DEBUG_MESSAGE(const char *format, ...)
+{
+#ifdef DBG
+
+ char tmp[256];
+
+ if (debug_level >= LIBUSB_DEBUG_MSG)
+ {
+ va_list args;
+ va_start(args, format);
+ _vsnprintf(tmp, sizeof(tmp) - 1, format, args);
+ va_end(args);
+
+ DbgPrint("LIBUSB-DRIVER - %s", tmp);
+ }
+#endif
+}
+
+void DEBUG_ERROR(const char *format, ...)
+{
+#ifdef DBG
+
+ char tmp[256];
+
+ if (debug_level >= LIBUSB_DEBUG_ERR)
+ {
+ va_list args;
+ va_start(args, format);
+ _vsnprintf(tmp, sizeof(tmp) - 1, format, args);
+ va_end(args);
+
+ DbgPrint("LIBUSB-DRIVER - %s", tmp);
+ }
+#endif
+}
diff --git a/usb/driver/driver_debug.h b/usb/driver/driver_debug.h
new file mode 100644
index 0000000..a4f396f
--- /dev/null
+++ b/usb/driver/driver_debug.h
@@ -0,0 +1,30 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __LIBUSB_DEBUG_H__
+#define __LIBUSB_DEBUG_H__
+
+
+void DEBUG_PRINT_NL();
+void DEBUG_SET_LEVEL(int level);
+void DEBUG_MESSAGE(const char *format, ...);
+void DEBUG_ERROR(const char *format, ...);
+
+
+#endif
diff --git a/usb/driver/driver_registry.c b/usb/driver/driver_registry.c
new file mode 100644
index 0000000..3b0c67d
--- /dev/null
+++ b/usb/driver/driver_registry.c
@@ -0,0 +1,376 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+#include "lusb_defdi_guids.h"
+
+/* missing in mingw's ddk headers */
+#ifndef PLUGPLAY_REGKEY_DEVICE
+#define PLUGPLAY_REGKEY_DEVICE 1
+#endif
+
+#define LIBUSB_REG_SURPRISE_REMOVAL_OK L"SurpriseRemovalOK"
+#define LIBUSB_REG_INITIAL_CONFIG_VALUE L"InitialConfigValue"
+#define LIBUSB_REG_DEVICE_INTERFACE_GUIDS L"DeviceInterfaceGUIDs"
+
+static bool_t reg_get_property(DEVICE_OBJECT *physical_device_object,
+ int property, char *data, int size);
+
+static bool_t reg_get_property(DEVICE_OBJECT *physical_device_object,
+ int property, char *data, int size)
+{
+ WCHAR tmp[512];
+ ULONG ret;
+ ULONG i;
+
+ if (!physical_device_object || !data || !size)
+ {
+ return FALSE;
+ }
+
+ memset(data, 0, size);
+ memset(tmp, 0, sizeof(tmp));
+
+ if (NT_SUCCESS(IoGetDeviceProperty(physical_device_object,
+ property,
+ sizeof(tmp) - 2,
+ tmp,
+ &ret)) && ret)
+ {
+ /* convert unicode string to normal character string */
+ for (i = 0; (i < ret/2) && (i < ((ULONG)size - 1)); i++)
+ {
+ data[i] = (char)tmp[i];
+ }
+
+ _strlwr(data);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+bool_t reg_get_properties(libusb_device_t *dev)
+{
+ HANDLE key = NULL;
+ PVOID keyObject = NULL;
+ NTSTATUS status;
+ UNICODE_STRING surprise_removal_ok_name;
+ UNICODE_STRING initial_config_value_name;
+ UNICODE_STRING device_interface_guids;
+ UNICODE_STRING device_interface_guid_value;
+ KEY_VALUE_FULL_INFORMATION *info;
+ ULONG pool_length;
+ ULONG length;
+ ULONG val;
+ LPWSTR valW;
+
+ if (!dev->physical_device_object)
+ {
+ return FALSE;
+ }
+
+ /* default settings */
+ dev->surprise_removal_ok = FALSE;
+ dev->is_filter = TRUE;
+ dev->initial_config_value = SET_CONFIG_ACTIVE_CONFIG;
+
+ status = IoOpenDeviceRegistryKey(dev->physical_device_object,
+ PLUGPLAY_REGKEY_DEVICE,
+ STANDARD_RIGHTS_ALL,
+ &key);
+ if (NT_SUCCESS(status))
+ {
+ RtlInitUnicodeString(&surprise_removal_ok_name,
+ LIBUSB_REG_SURPRISE_REMOVAL_OK);
+
+ RtlInitUnicodeString(&initial_config_value_name,
+ LIBUSB_REG_INITIAL_CONFIG_VALUE);
+
+ RtlInitUnicodeString(&device_interface_guids,
+ LIBUSB_REG_DEVICE_INTERFACE_GUIDS);
+
+ pool_length = sizeof(KEY_VALUE_FULL_INFORMATION) + 512;
+
+ info = ExAllocatePool(NonPagedPool, pool_length);
+ if (!info)
+ {
+ ZwClose(key);
+ USBERR("ExAllocatePool failed allocating %d bytes\n", pool_length);
+ return FALSE;
+ }
+
+
+ // get surprise_removal_ok
+ // get is_filter
+ length = pool_length;
+ memset(info, 0, length);
+
+ status = ZwQueryValueKey(key, &surprise_removal_ok_name,
+ KeyValueFullInformation, info, length, &length);
+
+ if (NT_SUCCESS(status) && (info->Type == REG_DWORD))
+ {
+ val = *((ULONG *)(((char *)info) + info->DataOffset));
+
+ dev->surprise_removal_ok = val ? TRUE : FALSE;
+ dev->is_filter = FALSE;
+ }
+
+ if (!dev->is_filter)
+ {
+ // get device interface guid
+ length = pool_length;
+ memset(info, 0, length);
+
+ status = ZwQueryValueKey(key, &device_interface_guids,
+ KeyValueFullInformation, info, length, &length);
+
+ if (NT_SUCCESS(status) && (info->Type == REG_MULTI_SZ))
+ {
+ valW = ((LPWSTR)(((char *)info) + info->DataOffset));
+ RtlInitUnicodeString(&device_interface_guid_value,valW);
+ status = RtlGUIDFromString(&device_interface_guid_value, &dev->device_interface_guid);
+ if (NT_SUCCESS(status))
+ {
+ if (IsEqualGUID(&dev->device_interface_guid, &LibusbKDeviceGuid))
+ {
+ USBWRN0("libusbK default device DeviceInterfaceGUID found. skippng..\n");
+ RtlInitUnicodeString(&device_interface_guid_value,Libusb0DeviceGuidW);
+ }
+ else if (IsEqualGUID(&dev->device_interface_guid, &Libusb0FilterGuid))
+ {
+ USBWRN0("libusb0 filter DeviceInterfaceGUID found. skippng..\n");
+ RtlInitUnicodeString(&device_interface_guid_value,Libusb0DeviceGuidW);
+ }
+ else if (IsEqualGUID(&dev->device_interface_guid, &Libusb0DeviceGuid))
+ {
+ USBWRN0("libusb0 device DeviceInterfaceGUID found. skippng..\n");
+ RtlInitUnicodeString(&device_interface_guid_value,Libusb0DeviceGuidW);
+ }
+ else
+ {
+ USBMSG0("found user specified device interface guid.\n");
+ dev->device_interface_in_use = TRUE;
+ }
+ }
+ else
+ {
+ USBERR0("invalid user specified device interface guid.");
+ }
+ }
+ if (!dev->device_interface_in_use)
+ {
+ RtlInitUnicodeString(&device_interface_guid_value,Libusb0DeviceGuidW);
+ }
+ }
+ else
+ {
+ RtlInitUnicodeString(&device_interface_guid_value,Libusb0FilterGuidW);
+ }
+
+ if (!dev->device_interface_in_use)
+ {
+ status = RtlGUIDFromString(&device_interface_guid_value, &dev->device_interface_guid);
+ if (NT_SUCCESS(status))
+ {
+ USBMSG0("using default device interface guid.\n");
+ dev->device_interface_in_use = TRUE;
+ }
+ else
+ {
+ USBERR0("failed using default device interface guid.\n");
+ }
+ }
+
+ // get initial_config_value
+ length = pool_length;
+ memset(info, 0, length);
+
+ status = ZwQueryValueKey(key, &initial_config_value_name,
+ KeyValueFullInformation, info, length, &length);
+
+ if (NT_SUCCESS(status) && (info->Type == REG_DWORD))
+ {
+ val = *((ULONG *)(((char *)info) + info->DataOffset));
+ dev->initial_config_value = (int)val;
+ }
+
+ status = ObReferenceObjectByHandle(key, KEY_READ, NULL, KernelMode, &keyObject, NULL);
+ if (NT_SUCCESS(status))
+ {
+ length = pool_length;
+ memset(info, 0, length);
+ status = ObQueryNameString(keyObject, (POBJECT_NAME_INFORMATION)info, length, &length);
+ if (NT_SUCCESS(status))
+ {
+ PWSTR nameW =((POBJECT_NAME_INFORMATION)info)->Name.Buffer;
+ PSTR nameA = dev->objname_plugplay_registry_key;
+
+ val=0;
+ while (nameW[val] && val < (length/2))
+ {
+ *nameA=(char)nameW[val];
+ nameA++;
+ val++;
+ }
+ *nameA='\0';
+
+ USBDBG("reg-key-name=%s\n",dev->objname_plugplay_registry_key);
+ }
+ else
+ {
+ USBERR("ObQueryNameString failed. status=%Xh\n",status);
+ }
+
+ ObDereferenceObject(keyObject);
+ }
+ else
+ {
+ USBERR("ObReferenceObjectByHandle failed. status=%Xh\n",status);
+ }
+
+ ZwClose(key);
+ ExFreePool(info);
+ }
+
+ return TRUE;
+}
+
+bool_t reg_get_hardware_id(DEVICE_OBJECT *physical_device_object,
+ char *data, int size)
+{
+ if (!physical_device_object || !data || !size)
+ {
+ return FALSE;
+ }
+
+ return reg_get_property(physical_device_object, DevicePropertyHardwareID,
+ data, size);
+}
+
+bool_t reg_get_compatible_id(DEVICE_OBJECT *physical_device_object,
+ char *data, int size)
+{
+ if (!physical_device_object || !data || !size)
+ {
+ return FALSE;
+ }
+
+ return reg_get_property(physical_device_object, DevicePropertyCompatibleIDs,
+ data, size);
+}
+/*
+Gets a device property for the device_object.
+
+Returns: NTSTATUS code from IoGetDeviceProperty
+ STATUS_INVALID_PARAMETER
+*/
+NTSTATUS reg_get_device_property(PDEVICE_OBJECT device_object,
+ int property,
+ char* data_buffer,
+ int data_length,
+ int* actual_length)
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ if (!device_object || !data_buffer || !data_length || !actual_length)
+ return status;
+
+ // clear data
+ memset(data_buffer, 0, data_length);
+ *actual_length=0;
+
+ // get device property
+ status = IoGetDeviceProperty(
+ device_object, property, data_length, data_buffer, (PULONG)actual_length);
+
+ return status;
+}
+
+/*
+Gets a property from the device registry key of the device_object.
+
+Returns: NTSTATUS from ZwQueryValueKey
+ NTSTATUS from IoOpenDeviceRegistryKey if the device registry
+ key could not be opened.
+*/
+NTSTATUS reg_get_custom_property(PDEVICE_OBJECT device_object,
+ char *data_buffer,
+ unsigned int data_length,
+ unsigned int name_offset,
+ int* actual_length)
+{
+ HANDLE key = NULL;
+ NTSTATUS status;
+ UNICODE_STRING name;
+ KEY_VALUE_FULL_INFORMATION *info;
+ ULONG length;
+
+ status = IoOpenDeviceRegistryKey(device_object, PLUGPLAY_REGKEY_DEVICE, KEY_READ, &key);
+ if (NT_SUCCESS(status))
+ {
+ RtlInitUnicodeString(&name, (WCHAR*)(&data_buffer[name_offset]));
+ length = sizeof(KEY_VALUE_FULL_INFORMATION) + name.MaximumLength + data_length;
+ info = ExAllocatePool(NonPagedPool, length);
+ if (info)
+ {
+ memset(info, 0, length);
+ status = ZwQueryValueKey(key, &name, KeyValueFullInformation, info, length, &length);
+ if (NT_SUCCESS(status))
+ {
+ data_length = (info->DataLength > data_length) ? data_length : info->DataLength;
+ memcpy(data_buffer, (((char *)info) + info->DataOffset),data_length);
+ *actual_length=data_length;
+ }
+ ExFreePool(info);
+ }
+ ZwClose(key);
+ }
+ return status;
+}
+
+VOID set_filter_interface_key(libusb_device_t *dev, ULONG id)
+{
+ if (dev->device_interface_in_use)
+ {
+ HANDLE hKey=NULL;
+ if (NT_SUCCESS(IoOpenDeviceInterfaceRegistryKey(&dev->device_interface_name,KEY_ALL_ACCESS,&hKey)))
+ {
+ UNICODE_STRING valueName;
+ RtlInitUnicodeString(&valueName, L"LUsb0");
+
+ if (NT_SUCCESS(ZwSetValueKey(hKey,&valueName, 0, REG_DWORD, &id,sizeof(ULONG))))
+ {
+ USBMSG("updated interface registry with LUsb0 direct-access symbolic link. id=%d\n",id);
+ }
+ else
+ {
+ USBERR0("IoOpenDeviceInterfaceRegistryKey:ZwSetValueKey failed\n");
+ }
+ ZwClose(hKey);
+ }
+ else
+ {
+ USBERR0("IoOpenDeviceInterfaceRegistryKey failed\n");
+ }
+ }
+} \ No newline at end of file
diff --git a/usb/driver/get_configuration.c b/usb/driver/get_configuration.c
new file mode 100644
index 0000000..fa9b522
--- /dev/null
+++ b/usb/driver/get_configuration.c
@@ -0,0 +1,56 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS get_configuration(libusb_device_t *dev,
+ unsigned char *configuration, int *ret,
+ int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ USBMSG("timeout: %d\n", timeout);
+
+ memset(&urb, 0, sizeof(URB));
+
+ urb.UrbHeader.Function = URB_FUNCTION_GET_CONFIGURATION;
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_CONFIGURATION_REQUEST);
+ urb.UrbControlGetConfigurationRequest.TransferBufferLength = 1;
+ urb.UrbControlGetConfigurationRequest.TransferBuffer = configuration;
+
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("getting configuration failed: status: 0x%x, urb-status: 0x%x\n",
+ status, urb.UrbHeader.Status);
+ *ret = 0;
+ }
+ else
+ {
+ USBMSG("current configuration is: %d\n",
+ *configuration);
+ *ret = urb.UrbControlGetConfigurationRequest.TransferBufferLength;
+ }
+
+ return status;
+}
diff --git a/usb/driver/get_descriptor.c b/usb/driver/get_descriptor.c
new file mode 100644
index 0000000..2b5172e
--- /dev/null
+++ b/usb/driver/get_descriptor.c
@@ -0,0 +1,289 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS get_descriptor(libusb_device_t *dev,
+ void *buffer, int size, int type, int recipient,
+ int index, int language_id, int *received, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ USBMSG("buffer size: %d type: %04d recipient: %04d index: %04d language id: %04d timeout: %d\n",
+ size, type, recipient, index, language_id, timeout);
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+ switch (recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT;
+ break;
+ default:
+ USBERR0("invalid recipient\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+ urb.UrbControlDescriptorRequest.TransferBufferLength = size;
+ urb.UrbControlDescriptorRequest.TransferBuffer = buffer;
+ urb.UrbControlDescriptorRequest.DescriptorType = (UCHAR)type;
+ urb.UrbControlDescriptorRequest.Index = (UCHAR)index;
+ urb.UrbControlDescriptorRequest.LanguageId = (USHORT)language_id;
+
+ // the device and active config descriptors are cached. If the request
+ // is for one of these and we have already retrieved it, then this is
+ // a non-blocking non-i/o call.
+
+ if (type == USB_DEVICE_DESCRIPTOR_TYPE &&
+ recipient == USB_RECIP_DEVICE &&
+ index == 0 &&
+ language_id == 0 &&
+ size >= sizeof(USB_DEVICE_DESCRIPTOR))
+ {
+ // this is a device descriptor request.
+ if (dev->device_descriptor.bLength == 0)
+ {
+ // this is the first request made for the device descriptor.
+ // Cache it now and forever
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+ if (NT_SUCCESS(status) && urb.UrbControlDescriptorRequest.TransferBufferLength < sizeof(USB_DEVICE_DESCRIPTOR))
+ {
+ USBERR("Invalid device decriptor length %d\n", urb.UrbControlDescriptorRequest.TransferBufferLength);
+ status = STATUS_BAD_DEVICE_TYPE;
+ *received = 0;
+ goto Done;
+ }
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("getting descriptor failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ *received = 0;
+ goto Done;
+ }
+
+ // valid device descriptor
+ size = sizeof(USB_DEVICE_DESCRIPTOR);
+ RtlCopyMemory(&dev->device_descriptor, buffer, size);
+ *received = size;
+
+ }
+ else
+ {
+ // device descriptor is already cached.
+ size = sizeof(USB_DEVICE_DESCRIPTOR);
+ RtlCopyMemory(buffer, &dev->device_descriptor, size);
+ *received = size;
+ }
+
+ goto Done;
+ }
+
+ if (type == USB_CONFIGURATION_DESCRIPTOR_TYPE &&
+ recipient == USB_RECIP_DEVICE &&
+ language_id == 0 &&
+ size >= sizeof(USB_CONFIGURATION_DESCRIPTOR))
+ {
+ if (dev->device_descriptor.bLength != 0 && index >=dev->device_descriptor.bNumConfigurations)
+ {
+ USBWRN("config descriptor index %d out of range.\n", index);
+ status = STATUS_NO_MORE_ENTRIES;
+ *received = 0;
+ goto Done;
+ }
+
+ // this is a config descriptor request.
+ if (!dev->config.descriptor || dev->config.index != index)
+ {
+ // this is either:
+ // * The first request made for a config descriptor.
+ // * A request for a config descriptor other than the cached index.
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("getting descriptor failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ *received = 0;
+ goto Done;
+ }
+
+ if (!dev->config.descriptor &&
+ urb.UrbControlDescriptorRequest.TransferBufferLength >= ((PUSB_CONFIGURATION_DESCRIPTOR)buffer)->wTotalLength)
+ {
+ //
+ // This is a special case scenario where we cache the first
+ // config deescriptor requested when dev->config.descriptor == NULL
+ // and this was a request for the *entire* descriptor.
+ //
+ // Nearly all windows USB devices will only have one configuration.
+ // In the case a the filter driver, it does *not* auto configure the
+ // device which is where the *active* config descriptor caching occurs.
+ //
+ // This code ensures the first config descriptor requested is always cached
+ // even if the device is not configured yet.
+ //
+
+ PUSB_CONFIGURATION_DESCRIPTOR config_desc;
+ size = ((PUSB_CONFIGURATION_DESCRIPTOR)buffer)->wTotalLength;
+
+ if (!( config_desc = ExAllocatePool(NonPagedPool, size)))
+ {
+ USBERR0("memory allocation error\n");
+ status = STATUS_NO_MEMORY;
+ goto Done;
+ }
+
+ dev->config.descriptor=config_desc;
+
+ RtlCopyMemory(dev->config.descriptor,buffer,size);
+ dev->config.value=0;
+ dev->config.total_size=size;
+ dev->config.index=index;
+
+ *received = size;
+ }
+ else
+ {
+ *received = urb.UrbControlDescriptorRequest.TransferBufferLength;
+ }
+ goto Done;
+ }
+ else
+ {
+ // This is a request for the active configuration descriptor.
+ // This is only updated upon a successful set_configuration().
+ size = (size > dev->config.descriptor->wTotalLength) ? dev->config.descriptor->wTotalLength : size;
+ RtlCopyMemory(buffer, dev->config.descriptor, size);
+
+ *received = size;
+ goto Done;
+ }
+ }
+
+ // this is not a device or config descriptor reequest
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("getting descriptor failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ *received = 0;
+ }
+ else
+ {
+ *received = urb.UrbControlDescriptorRequest.TransferBufferLength;
+ }
+
+Done:
+ return status;
+}
+
+PUSB_CONFIGURATION_DESCRIPTOR get_config_descriptor(
+ libusb_device_t *dev,
+ int value,
+ int *size,
+ int* index)
+{
+ NTSTATUS status;
+ USB_CONFIGURATION_DESCRIPTOR *desc = NULL;
+ USB_DEVICE_DESCRIPTOR device_descriptor;
+ int i;
+ volatile int desc_size;
+
+ *index = 0;
+
+ status = get_descriptor(dev, &device_descriptor,
+ sizeof(USB_DEVICE_DESCRIPTOR),
+ USB_DEVICE_DESCRIPTOR_TYPE,
+ USB_RECIP_DEVICE,
+ 0, 0, size, LIBUSB_DEFAULT_TIMEOUT);
+
+ if (!NT_SUCCESS(status) || *size != sizeof(USB_DEVICE_DESCRIPTOR))
+ {
+ USBERR0("getting device descriptor failed\n");
+ return NULL;
+ }
+
+ if (!(desc = ExAllocatePool(NonPagedPool,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR))))
+ {
+ USBERR0("memory allocation error\n");
+ return NULL;
+ }
+
+ for (i = 0; i < device_descriptor.bNumConfigurations; i++)
+ {
+
+ if (!NT_SUCCESS(get_descriptor(dev, desc,
+ sizeof(USB_CONFIGURATION_DESCRIPTOR),
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ USB_RECIP_DEVICE,
+ i, 0, size, LIBUSB_DEFAULT_TIMEOUT)))
+ {
+ USBERR0("getting configuration descriptor failed\n");
+ break;
+ }
+
+ // if value is negative, get the descriptor by index
+ // if positive, get it by value.
+ if ((value > 0 && desc->bConfigurationValue == value) ||
+ (value < 0 && -(i+1) == (value)))
+ {
+ desc_size = desc->wTotalLength;
+ ExFreePool(desc);
+
+ if (!(desc = ExAllocatePool(NonPagedPool, desc_size)))
+ {
+ USBERR0("memory allocation error\n");
+ break;
+ }
+
+ if (!NT_SUCCESS(get_descriptor(dev, desc, desc_size,
+ USB_CONFIGURATION_DESCRIPTOR_TYPE,
+ USB_RECIP_DEVICE,
+ i, 0, size, LIBUSB_DEFAULT_TIMEOUT)))
+ {
+ USBERR0("getting configuration descriptor failed\n");
+ break;
+ }
+ else
+ {
+ *index = i;
+ }
+
+ return desc;
+ }
+ }
+
+ if (desc)
+ {
+ ExFreePool(desc);
+ }
+
+ return NULL;
+}
diff --git a/usb/driver/get_interface.c b/usb/driver/get_interface.c
new file mode 100644
index 0000000..b218281
--- /dev/null
+++ b/usb/driver/get_interface.c
@@ -0,0 +1,109 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS get_interface(libusb_device_t *dev,
+ int interface_number,
+ unsigned char *altsetting,
+ int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+ PUSB_INTERFACE_DESCRIPTOR interface_descriptor;
+
+ USBMSG("interface: %d timeout: %d\n", interface_number, timeout);
+
+ if (!dev->config.value)
+ {
+ USBERR0("invalid configuration 0\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ memset(&urb, 0, sizeof(URB));
+
+ urb.UrbHeader.Function = URB_FUNCTION_GET_INTERFACE;
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_INTERFACE_REQUEST);
+ urb.UrbControlGetInterfaceRequest.TransferBufferLength = 1;
+ urb.UrbControlGetInterfaceRequest.TransferBuffer = altsetting;
+ urb.UrbControlGetInterfaceRequest.Interface = (USHORT)interface_number;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("getting interface failed: status: 0x%x, urb-status: 0x%x\n",
+ status, urb.UrbHeader.Status);
+ }
+ else
+ {
+ USBMSG("current altsetting is %d\n", *altsetting);
+ }
+
+ return status;
+}
+
+NTSTATUS get_interface_ex(libusb_device_t *dev,
+ interface_request_t* interface_request,
+ int timeout)
+{
+ unsigned char alt_number;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ USB_INTERFACE_DESCRIPTOR *interface_descriptor = NULL;
+
+ USBMSG("interface-%s=%d timeout=%d\n",
+ interface_request->intf_use_index ? "index" : "number",
+ interface_request->intf_use_index ? interface_request->interface_index : interface_request->interface_number,
+ timeout);
+
+ if (!dev->config.value || !dev->config.descriptor)
+ {
+ USBERR0("device is not configured\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ interface_request->altsetting_index=FIND_INTERFACE_INDEX_ANY;
+ interface_descriptor = find_interface_desc_ex(dev->config.descriptor,dev->config.total_size,interface_request,NULL);
+ if (!interface_descriptor)
+ {
+ return STATUS_NO_MORE_ENTRIES;
+ }
+
+ status = get_interface(dev,interface_descriptor->bInterfaceNumber, &alt_number, timeout);
+ if (!NT_SUCCESS(status))
+ {
+ return STATUS_NO_MORE_ENTRIES;
+ }
+
+ interface_request->interface_number=interface_descriptor->bInterfaceNumber;
+ interface_request->altsetting_number=alt_number;
+ interface_request->altf_use_index=0;
+ interface_request->intf_use_index=0;
+
+ interface_descriptor = find_interface_desc_ex(dev->config.descriptor,dev->config.total_size,interface_request,NULL);
+ if (!interface_descriptor)
+ {
+ return STATUS_NO_MORE_ENTRIES;
+ }
+
+ return status;
+}
diff --git a/usb/driver/get_status.c b/usb/driver/get_status.c
new file mode 100644
index 0000000..2e77f91
--- /dev/null
+++ b/usb/driver/get_status.c
@@ -0,0 +1,74 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS get_status(libusb_device_t *dev, int recipient,
+ int index, char *status, int *ret, int timeout)
+{
+ NTSTATUS _status = STATUS_SUCCESS;
+ URB urb;
+
+ USBMSG("recipient: %02d index: %04d timeout: %d\n",
+ recipient, index, timeout);
+
+ memset(&urb, 0, sizeof(URB));
+
+ switch (recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ urb.UrbHeader.Function = URB_FUNCTION_GET_STATUS_FROM_OTHER;
+ break;
+ default:
+ USBERR0("invalid recipient\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST);
+ urb.UrbControlGetStatusRequest.TransferBufferLength = 2;
+ urb.UrbControlGetStatusRequest.TransferBuffer = status;
+ urb.UrbControlGetStatusRequest.Index = (USHORT)index;
+
+ _status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(_status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("getting status failed: status: 0x%x, urb-status: 0x%x\n",
+ _status, urb.UrbHeader.Status);
+ *ret = 0;
+ }
+ else
+ {
+ *ret = urb.UrbControlGetStatusRequest.TransferBufferLength;
+ }
+
+ return _status;
+}
+
diff --git a/usb/driver/ioctl.c b/usb/driver/ioctl.c
new file mode 100644
index 0000000..f059175
--- /dev/null
+++ b/usb/driver/ioctl.c
@@ -0,0 +1,795 @@
+/* libusb-win32, Generic Windows USB Library
+* Copyright (c) 2010 Travis Robinson <libusbdotnet@gmail.com>
+* Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "libusb_driver.h"
+#include "libusb-win32_version.h"
+
+// used but all transfer functions to get a valid libusb_endpoint_t *
+// for the request.
+//
+#define TRANSFER_IOCTL_GET_PIPEINFO() \
+ /* check if the pipe exists and get the pipe information */ \
+ if (!get_pipe_info(dev, request->endpoint.endpoint,&pipe_info)) \
+ { \
+ USBERR("%s: failed getting pipe info for endpoint: %02Xh\n", \
+ dispCtlCode, request->endpoint.endpoint); \
+ status = STATUS_INVALID_PARAMETER; \
+ goto IOCTL_Done; \
+ }
+
+// warns if receive buffer is not an interval of the maximum packet size.
+#define TRANSFER_IOCTL_CHECK_READ_BUFFER() \
+ /* read buffer lengthd must be equal to or an interval of the max */ \
+ /* packet size */ \
+ if (!pipe_info->maximum_packet_size) \
+ { \
+ USBWRN("%s: wMaxPacketSize=0 for endpoint %02Xh.\n", \
+ dispCtlCode, request->endpoint.endpoint); \
+ status = STATUS_INVALID_PARAMETER; \
+ goto IOCTL_Done; \
+ } \
+ else if (transfer_buffer_length % pipe_info->maximum_packet_size) \
+ { \
+ USBWRN("%s: buffer length %d is not an interval wMaxPacketSize " \
+ "for endpoint %02Xh.\n", \
+ dispCtlCode, transfer_buffer_length, request->endpoint.endpoint); \
+ }
+
+// validates the urb function and direction against libusb_endpoint_t
+#define TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION() \
+ if (urbFunction != UrbFunctionFromEndpoint(pipe_info) || \
+ usbdDirection != UsbdDirectionFromEndpoint(pipe_info)) \
+ { \
+ USBERR("%s: not compatible with endpoint %02Xh.\n" \
+ "\turbFunction =%Xh usbdDirection =%Xh\n" \
+ "\tpipeFunction =%Xh pipeDirection =%Xh\n", \
+ dispCtlCode, \
+ pipe_info->address, \
+ urbFunction,usbdDirection, \
+ UrbFunctionFromEndpoint(pipe_info), \
+ UsbdDirectionFromEndpoint(pipe_info)); \
+ status = STATUS_INVALID_PARAMETER; \
+ goto IOCTL_Done; \
+ }
+
+// calls the transfer function and returns NTSTATUS
+#define TRANSFER_IOCTL_EXECUTE() \
+ if (transfer_buffer_length > (ULONG)(maxTransferSize)) \
+ /* split large transfers */ \
+ return large_transfer(dev, irp, \
+ usbdDirection, \
+ urbFunction, \
+ pipe_info, \
+ request->endpoint.packet_size, \
+ maxTransferSize, \
+ request->endpoint.transfer_flags, \
+ request->endpoint.iso_start_frame_latency, \
+ transfer_buffer_mdl, \
+ transfer_buffer_length); \
+ else \
+ /* normal transfer */ \
+ return transfer(dev, irp, \
+ usbdDirection, \
+ urbFunction, \
+ pipe_info, \
+ request->endpoint.packet_size, \
+ request->endpoint.transfer_flags, \
+ request->endpoint.iso_start_frame_latency, \
+ transfer_buffer_mdl, \
+ transfer_buffer_length);
+
+NTSTATUS dispatch_ioctl(libusb_device_t *dev, IRP *irp)
+{
+ int maxTransferSize;
+ int ret = 0;
+ NTSTATUS status = STATUS_SUCCESS;
+
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+
+ ULONG control_code = stack_location->Parameters.DeviceIoControl.IoControlCode;
+
+ ULONG input_buffer_length = stack_location->Parameters.DeviceIoControl.InputBufferLength;
+ ULONG output_buffer_length = stack_location->Parameters.DeviceIoControl.OutputBufferLength;
+ ULONG transfer_buffer_length = stack_location->Parameters.DeviceIoControl.OutputBufferLength;
+
+ libusb_request *request = (libusb_request *)irp->AssociatedIrp.SystemBuffer;
+ char *output_buffer = (char *)irp->AssociatedIrp.SystemBuffer;
+ char *input_buffer = (char *)irp->AssociatedIrp.SystemBuffer;
+ MDL *transfer_buffer_mdl = irp->MdlAddress;
+ libusb_endpoint_t* pipe_info = NULL;
+ const char* dispCtlCode = NULL;
+ int urbFunction = -1;
+ int usbdDirection = -1;
+
+ status = remove_lock_acquire(dev);
+
+ if (!NT_SUCCESS(status))
+ {
+ status = complete_irp(irp, status, 0);
+ remove_lock_release(dev);
+ return status;
+ }
+
+ ///////////////////////////////////
+ // DIRECT control codes //
+ ///////////////////////////////////
+ switch(control_code)
+ {
+ case LIBUSB_IOCTL_INTERRUPT_OR_BULK_READ:
+
+ dispCtlCode = "INTERRUPT_OR_BULK_READ";
+
+ // check if the request and buffer is valid
+ if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
+ {
+ USBERR("%s: invalid transfer request\n",
+ dispCtlCode);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ }
+
+ // check if the pipe exists and get the pipe information
+ TRANSFER_IOCTL_GET_PIPEINFO();
+
+ // must be a bulk or interrupt pipe
+ if (!IS_BULK_PIPE(pipe_info) && !IS_INTR_PIPE(pipe_info))
+ {
+ goto IoctlIsochronousRead;
+ /*
+ USBERR("%s: incorrect pipe type: %02Xh\n",
+ dispCtlCode, pipe_info->pipe_type);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ */
+ }
+
+ // read buffer length must be equal to or an interval of the max packet size
+ TRANSFER_IOCTL_CHECK_READ_BUFFER();
+
+ urbFunction = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
+ usbdDirection = USBD_TRANSFER_DIRECTION_IN;
+ maxTransferSize = GetMaxTransferSize(pipe_info, request->endpoint.max_transfer_size);
+
+ // ensure that the urb function and direction we set matches the
+ // pipe information
+ //
+ TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
+
+ // calls the transfer function and returns NTSTATUS
+ TRANSFER_IOCTL_EXECUTE();
+
+ case LIBUSB_IOCTL_INTERRUPT_OR_BULK_WRITE:
+
+ dispCtlCode = "INTERRUPT_OR_BULK_WRITE";
+
+ /* we don't check 'transfer_buffer_mdl' here because it might be NULL */
+ /* if the DLL requests to send a zero-length packet */
+ if (!request || input_buffer_length < sizeof(libusb_request))
+ {
+ USBERR("%s: invalid transfer request\n", dispCtlCode);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ }
+
+ // check if the pipe exists and get the pipe information
+ TRANSFER_IOCTL_GET_PIPEINFO();
+
+ // must be a bulk or interrupt pipe
+ if (!IS_BULK_PIPE(pipe_info) && !IS_INTR_PIPE(pipe_info))
+ {
+ goto IoctlIsochronousWrite;
+ /*
+ USBERR("%s: incorrect pipe type: %02Xh\n",
+ dispCtlCode, pipe_info->pipe_type);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ */
+ }
+
+ urbFunction = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
+ usbdDirection = USBD_TRANSFER_DIRECTION_OUT;
+ maxTransferSize = GetMaxTransferSize(pipe_info, request->endpoint.max_transfer_size);
+
+ // ensure that the urb function and direction we set matches the
+ // pipe information
+ //
+ //TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
+
+ // calls the transfer function and returns NTSTATUS
+ TRANSFER_IOCTL_EXECUTE();
+
+ case LIBUSB_IOCTL_ISOCHRONOUS_READ:
+
+ dispCtlCode = "ISOCHRONOUS_READ";
+
+ // check if the request and buffer is valid
+ if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
+ {
+ USBERR("%s: invalid transfer request\n", dispCtlCode);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ }
+
+ // check if the pipe exists and get the pipe information
+ TRANSFER_IOCTL_GET_PIPEINFO();
+
+IoctlIsochronousRead:
+ dispCtlCode = "ISOCHRONOUS_READ";
+ // must be an isochronous endpoint
+ if (!IS_ISOC_PIPE(pipe_info))
+ {
+ USBERR("%s: incorrect pipe type: %02Xh\n",
+ dispCtlCode, pipe_info->pipe_type);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ }
+
+ // read buffer length must be equal to or an interval of the max packet size
+ TRANSFER_IOCTL_CHECK_READ_BUFFER();
+
+ urbFunction = URB_FUNCTION_ISOCH_TRANSFER;
+ usbdDirection = USBD_TRANSFER_DIRECTION_IN;
+
+ // Do not use large transfers/splitting for ISO.
+ maxTransferSize = 0x7fffffff;
+
+ // ensure that the urb function and direction we set matches the
+ // pipe information
+ //
+ TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
+
+ // calls the transfer function and returns NTSTATUS
+ TRANSFER_IOCTL_EXECUTE();
+
+ case LIBUSB_IOCTL_ISOCHRONOUS_WRITE:
+
+ dispCtlCode = "ISOCHRONOUS_WRITE";
+
+ // check if the request and buffer is valid
+ if (!transfer_buffer_mdl || !request || input_buffer_length < sizeof(libusb_request))
+ {
+ USBERR("%s: invalid transfer request\n", dispCtlCode);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ }
+
+ // check if the pipe exists and get the pipe information
+ TRANSFER_IOCTL_GET_PIPEINFO();
+
+IoctlIsochronousWrite:
+ dispCtlCode = "ISOCHRONOUS_WRITE";
+ // must be an isochronous endpoint
+ if (!IS_ISOC_PIPE(pipe_info))
+ {
+ USBERR("%s: incorrect pipe type: %02Xh\n",
+ dispCtlCode, pipe_info->pipe_type);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ }
+
+ urbFunction = URB_FUNCTION_ISOCH_TRANSFER;
+ usbdDirection = USBD_TRANSFER_DIRECTION_OUT;
+ TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
+
+ // Do not use large transfers/splitting for ISO.
+ maxTransferSize = 0x7fffffff;
+
+ // ensure that the urb function and direction we set matches the
+ // pipe information
+ //
+ TRANSFER_IOCTL_CHECK_FUNCTION_AND_DIRECTION();
+
+ TRANSFER_IOCTL_EXECUTE();
+ }
+
+ ///////////////////////////////////
+ // METHOD_BUFFERED control codes //
+ ///////////////////////////////////
+ if (!request || input_buffer_length < sizeof(libusb_request)
+ || input_buffer_length > LIBUSB_MAX_READ_WRITE
+ || output_buffer_length > LIBUSB_MAX_READ_WRITE
+ || transfer_buffer_length > LIBUSB_MAX_READ_WRITE)
+ {
+ USBERR0("invalid input or output buffer\n");
+
+ status = complete_irp(irp, STATUS_INVALID_PARAMETER, 0);
+ remove_lock_release(dev);
+ return status;
+ }
+
+ switch(control_code)
+ {
+ case LIBUSB_IOCTL_SET_CONFIGURATION:
+
+ status = set_configuration(dev,
+ request->configuration.configuration,
+ request->timeout);
+ break;
+
+ case LIBUSB_IOCTL_GET_CACHED_CONFIGURATION:
+ case LIBUSB_IOCTL_GET_CONFIGURATION:
+
+ if (!output_buffer || output_buffer_length < 1)
+ {
+ USBERR0("get_configuration: invalid output buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ if (control_code == LIBUSB_IOCTL_GET_CACHED_CONFIGURATION)
+ {
+ ret = 0;
+ if (dev->config.value >= 0)
+ {
+ *output_buffer = (char)dev->config.value;
+ ret = 1;
+ }
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ status = get_configuration(dev, output_buffer, &ret, request->timeout);
+ }
+ break;
+
+ case LIBUSB_IOCTL_SET_INTERFACE:
+
+ status = set_interface(
+ dev,
+ request->intf.interface_number,
+ request->intf.altsetting_number,
+ request->timeout);
+
+ break;
+
+ case LIBUSB_IOCTL_GET_INTERFACE:
+
+ if (!output_buffer || output_buffer_length < 1)
+ {
+ USBERR0("get_interface: invalid output buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = get_interface(
+ dev,
+ request->intf.interface_number,
+ output_buffer,
+ request->timeout);
+
+ if (NT_SUCCESS(status))
+ ret = 1;
+
+ break;
+
+ case LIBUSB_IOCTL_SET_FEATURE:
+
+ status = set_feature(dev, request->feature.recipient,
+ request->feature.index, request->feature.feature,
+ request->timeout);
+
+ break;
+
+ case LIBUSB_IOCTL_CLEAR_FEATURE:
+
+ status = clear_feature(dev, request->feature.recipient,
+ request->feature.index, request->feature.feature,
+ request->timeout);
+
+ break;
+
+ case LIBUSB_IOCTL_GET_STATUS:
+
+ if (!output_buffer || output_buffer_length < 2)
+ {
+ USBERR0("get_status: invalid output buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = get_status(dev, request->status.recipient,
+ request->status.index, output_buffer,
+ &ret, request->timeout);
+
+ break;
+
+ case LIBUSB_IOCTL_SET_DESCRIPTOR:
+
+ if (input_buffer_length <= sizeof(libusb_request))
+ {
+ USBERR0("set_descriptor: invalid input buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = set_descriptor(dev,
+ input_buffer + sizeof(libusb_request),
+ input_buffer_length - sizeof(libusb_request),
+ request->descriptor.type,
+ request->descriptor.recipient,
+ request->descriptor.index,
+ request->descriptor.language_id,
+ &ret, request->timeout);
+
+ break;
+
+ case LIBUSB_IOCTL_GET_DESCRIPTOR:
+
+ if (!output_buffer || !output_buffer_length)
+ {
+ USBERR0("get_descriptor: invalid output buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = get_descriptor(dev, output_buffer,
+ output_buffer_length,
+ request->descriptor.type,
+ request->descriptor.recipient,
+ request->descriptor.index,
+ request->descriptor.language_id,
+ &ret, request->timeout);
+
+ break;
+
+ case LIBUSB_IOCTL_VENDOR_READ:
+
+ if (output_buffer_length && !output_buffer)
+ {
+ USBERR0("vendor_read: invalid output buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ status = vendor_class_request(dev,
+ request->vendor.type,
+ request->vendor.recipient,
+ request->vendor.request,
+ request->vendor.value,
+ request->vendor.index,
+ output_buffer,
+ output_buffer_length,
+ USBD_TRANSFER_DIRECTION_IN,
+ &ret, request->timeout);
+ break;
+
+ case LIBUSB_IOCTL_VENDOR_WRITE:
+
+ status =
+ vendor_class_request(dev,
+ request->vendor.type,
+ request->vendor.recipient,
+ request->vendor.request,
+ request->vendor.value,
+ request->vendor.index,
+ input_buffer_length == sizeof(libusb_request) ?
+NULL : input_buffer + sizeof(libusb_request),
+ input_buffer_length - sizeof(libusb_request),
+ USBD_TRANSFER_DIRECTION_OUT,
+ &ret, request->timeout);
+ break;
+
+ case LIBUSB_IOCTL_RESET_ENDPOINT:
+
+ status = reset_endpoint(dev, request->endpoint.endpoint,
+ request->timeout);
+ break;
+
+ case LIBUSB_IOCTL_ABORT_ENDPOINT:
+
+ status = abort_endpoint(dev, request->endpoint.endpoint,
+ request->timeout);
+ break;
+
+ case LIBUSB_IOCTL_RESET_DEVICE:
+
+ status = reset_device(dev, request->timeout);
+ break;
+
+ case LIBUSB_IOCTL_RESET_DEVICE_EX:
+
+ status = reset_device_ex(dev, request->timeout, request->reset_ex.reset_type);
+ break;
+
+ case LIBUSB_IOCTL_SET_DEBUG_LEVEL:
+ usb_log_set_level(request->debug.level);
+ break;
+
+ case LIBUSB_IOCTL_GET_VERSION:
+
+ if (!request || output_buffer_length < sizeof(libusb_request))
+ {
+ USBERR0("get_version: invalid output buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ request->version.major = VERSION_MAJOR;
+ request->version.minor = VERSION_MINOR;
+ request->version.micro = VERSION_MICRO;
+ request->version.nano = VERSION_NANO;
+ request->version.mod_value = 1;
+
+ ret = sizeof(libusb_request);
+ break;
+
+ case LIBUSB_IOCTL_CLAIM_INTERFACE:
+ status = claim_interface(dev, stack_location->FileObject,
+ request->intf.interface_number);
+ break;
+
+ case LIBUSB_IOCTL_RELEASE_INTERFACE:
+ status = release_interface(dev, stack_location->FileObject,
+ request->intf.interface_number);
+ break;
+
+ case LIBUSB_IOCTL_GET_DEVICE_PROPERTY:
+ if (!request || output_buffer_length < sizeof(libusb_request))
+ {
+ USBERR0("get_device_property: invalid output buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ status = reg_get_device_property(
+ dev->physical_device_object,
+ request->device_property.property,
+ output_buffer,
+ output_buffer_length, &ret);
+ break;
+
+ case LIBUSB_IOCTL_GET_CUSTOM_REG_PROPERTY:
+ if (!input_buffer || (input_buffer_length < sizeof(libusb_request)))
+ {
+ USBERR0("get_custom_reg_property: invalid buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ status=reg_get_custom_property(
+ dev->physical_device_object,
+ input_buffer,
+ output_buffer_length,
+ request->device_registry_key.name_offset,
+ &ret);
+ break;
+
+ case LIBUSB_IOCTL_GET_OBJECT_NAME:
+ if (!request || output_buffer_length < 2)
+ {
+ USBERR0("get_object_name: invalid output buffer\n");
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ switch (request->objname.objname_index)
+ {
+ case 0:
+ ret = (int)strlen(dev->objname_plugplay_registry_key)+1;
+ ret = ret > (int)output_buffer_length ? (int)output_buffer_length : ret;
+ RtlCopyMemory(output_buffer, dev->objname_plugplay_registry_key,(SIZE_T) (ret-1));
+ output_buffer[ret-1]='\0';
+ break;
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ }
+ break;
+
+ case LIBUSB_IOCTL_QUERY_DEVICE_INFORMATION: // METHOD_BUFFERED (QUERY_DEVICE_INFORMATION)
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case LIBUSB_IOCTL_SET_PIPE_POLICY: // METHOD_BUFFERED (SET_PIPE_POLICY)
+ if (!request || !input_buffer || (input_buffer_length <= sizeof(libusb_request)))
+ {
+ USBERR0("set_pipe_policy: invalid output buffer\n");
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+ input_buffer+=sizeof(libusb_request);
+ input_buffer_length-=sizeof(libusb_request);
+ if (request->pipe_policy.policy_type==PIPE_TRANSFER_TIMEOUT)
+ {
+ if (input_buffer_length < sizeof(ULONG))
+ {
+ USBERR0("set_pipe_policy:pipe_transfer_timeout: invalid input buffer\n");
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+ if (request->pipe_policy.pipe_id & USB_ENDPOINT_ADDRESS_MASK)
+ {
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (request->pipe_policy.pipe_id & USB_ENDPOINT_DIR_MASK)
+ dev->control_read_timeout=*((PULONG)input_buffer);
+ else
+ dev->control_write_timeout=*((PULONG)input_buffer);
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+
+ break;
+
+ case LIBUSB_IOCTL_GET_PIPE_POLICY: // METHOD_BUFFERED (GET_PIPE_POLICY)
+ if (!request || input_buffer_length < sizeof(libusb_request) || !output_buffer || (output_buffer_length < 1))
+ {
+ USBERR0("get_pipe_policy: invalid output buffer\n");
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+ if (request->pipe_policy.policy_type==PIPE_TRANSFER_TIMEOUT)
+ {
+ if (output_buffer_length < sizeof(ULONG))
+ {
+ USBERR0("get_pipe_policy:pipe_transfer_timeout: invalid output buffer\n");
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+ if (request->pipe_policy.pipe_id & USB_ENDPOINT_ADDRESS_MASK)
+ {
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+ if (request->pipe_policy.pipe_id & USB_ENDPOINT_DIR_MASK)
+ *((PULONG)output_buffer) = dev->control_read_timeout;
+ else
+ *((PULONG)output_buffer) = dev->control_write_timeout;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+ break;
+
+ case LIBUSB_IOCTL_SET_POWER_POLICY: // METHOD_BUFFERED (SET_POWER_POLICY)
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case LIBUSB_IOCTL_GET_POWER_POLICY: // METHOD_BUFFERED (GET_POWER_POLICY)
+ status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case LIBUSB_IOCTL_CONTROL_WRITE: // METHOD_IN_DIRECT (CONTROL_WRITE)
+ // check if the request and buffer is valid
+ if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
+ {
+ USBERR("%s: invalid transfer request\n", dispCtlCode);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ }
+
+ status = control_transfer(
+ dev,
+ irp,
+ transfer_buffer_mdl,
+ transfer_buffer_length,
+ USBD_TRANSFER_DIRECTION_OUT,
+ &ret,
+ dev->control_write_timeout,
+ request->control.RequestType,
+ request->control.Request,
+ request->control.Value,
+ request->control.Index,
+ request->control.Length);
+
+ break;
+
+ case LIBUSB_IOCTL_CONTROL_READ: // METHOD_OUT_DIRECT (CONTROL_READ)
+ // check if the request and buffer is valid
+ if (!request || !transfer_buffer_mdl || input_buffer_length < sizeof(libusb_request))
+ {
+ USBERR("%s: invalid transfer request\n", dispCtlCode);
+ status = STATUS_INVALID_PARAMETER;
+ goto IOCTL_Done;
+ }
+
+ status = control_transfer(
+ dev,
+ irp,
+ transfer_buffer_mdl,
+ transfer_buffer_length,
+ USBD_TRANSFER_DIRECTION_IN,
+ &ret,
+ dev->control_read_timeout,
+ request->control.RequestType,
+ request->control.Request,
+ request->control.Value,
+ request->control.Index,
+ request->control.Length);
+
+ break;
+
+ case LIBUSB_IOCTL_FLUSH_PIPE: // METHOD_BUFFERED (FLUSH_PIPE)
+
+ status = STATUS_SUCCESS;
+ break;
+
+
+ case LIBUSBK_IOCTL_CLAIM_INTERFACE: // METHOD_BUFFERED (CLAIM_INTERFACE)
+ if (!request || output_buffer_length < sizeof(libusb_request))
+ {
+ USBERR0("claim_interfaceK: invalid output buffer\n");
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = claim_interface_ex(dev, stack_location->FileObject, &request->intf);
+ if (NT_SUCCESS(status))
+ {
+ ret = sizeof(libusb_request);
+ }
+ break;
+
+ case LIBUSBK_IOCTL_RELEASE_INTERFACE: // METHOD_BUFFERED (RELEASE_INTERFACE)
+
+ if (!request || output_buffer_length < sizeof(libusb_request))
+ {
+ USBERR0("release_interfaceK: invalid output buffer\n");
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = release_interface_ex(dev, stack_location->FileObject, &request->intf);
+ if (NT_SUCCESS(status))
+ {
+ ret = sizeof(libusb_request);
+ }
+ break;
+
+ case LIBUSBK_IOCTL_SET_INTERFACE: // METHOD_BUFFERED (SET_INTERFACE)
+
+ if (!request || output_buffer_length < sizeof(libusb_request))
+ {
+ USBERR0("set_interfaceK: invalid output buffer\n");
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = set_interface_ex(dev, &request->intf, request->timeout);
+ if (NT_SUCCESS(status))
+ {
+ ret = sizeof(libusb_request);
+ }
+ break;
+
+ case LIBUSBK_IOCTL_GET_INTERFACE: // METHOD_BUFFERED (GET_INTERFACE)
+
+ if (!request || output_buffer_length < sizeof(libusb_request))
+ {
+ USBERR0("get_interfaceK: invalid output buffer\n");
+ status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
+
+ status = get_interface_ex(dev, &request->intf, request->timeout);
+ if (NT_SUCCESS(status))
+ {
+ ret = sizeof(libusb_request);
+ }
+ break;
+
+ default:
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+IOCTL_Done:
+ status = complete_irp(irp, status, ret);
+ remove_lock_release(dev);
+
+ return status;
+}
diff --git a/usb/driver/libusb-win32-README-1.2.6.0.txt b/usb/driver/libusb-win32-README-1.2.6.0.txt
new file mode 100644
index 0000000..99445f7
--- /dev/null
+++ b/usb/driver/libusb-win32-README-1.2.6.0.txt
@@ -0,0 +1,239 @@
+LibUsb-Win32 Change Log
+V1.2.6.0 (01/17/2012)
+==============================================
+* Official release.
+
+* Removed ISO maximum transfer size restrictions/transfer spltting.
+
+* Fixed inf-wizard device notification issue.
+
+V1.2.5.0 (07/23/2011)
+==============================================
+* Official release.
+
+V1.2.4.9 (07/13/2011) - SNAPSHOT RELEASE
+==============================================
+* Updated GCC lib file 'libusb.a'
+
+V1.2.4.8 (07/12/2011) - SNAPSHOT RELEASE
+==============================================
+* Added new public api function 'usb_reset_ex'. This is an extended
+ device reset function which allows developers to specify a port reset, a
+ port cycle, or both.
+
+* Added new public defines 'USB_RESET_TYPE_XXX' for 'usb_reset_ex'
+ function.
+
+V1.2.4.7 (07/02/2011) - SNAPSHOT RELEASE
+==============================================
+* Sync transfers which specify a zero (0) timeout are now considered to be
+ INFINITE.
+
+V1.2.4.6 (05/12/2011) - SNAPSHOT RELEASE
+==============================================
+* Added device interface registration. This provides identical
+ functionality to the "DeviceInterfaceGUIDs" supported by WinUSB and
+ libusbK. A device interface guid can be specified in the .inf file. They
+ can be used to quickly locate a usb device or set of USB devices using
+ the setup api as well as device notification registration.
+
+* New IOCTL codes added to for native libusbK/WinUSB compatibility.
+ NOTE: These IOCTLs are currently used only by libusbK.dll.
+ o LIBUSB_IOCTL_QUERY_DEVICE_INFORMATION
+ o LIBUSB_IOCTL_SET_PIPE_POLICY
+ o LIBUSB_IOCTL_GET_PIPE_POLICY
+ o LIBUSB_IOCTL_SET_POWER_POLICY
+ o LIBUSB_IOCTL_GET_POWER_POLICY
+ o LIBUSB_IOCTL_CONTROL_WRITE
+ o LIBUSB_IOCTL_CONTROL_READ
+ o LIBUSB_IOCTL_FLUSH_PIPE
+ o LIBUSBK_IOCTL_CLAIM_INTERFACE
+ o LIBUSBK_IOCTL_RELEASE_INTERFACE
+ o LIBUSBK_IOCTL_RELEASE_ALL_INTERFACES
+ o LIBUSBK_IOCTL_SET_INTERFACE
+ o LIBUSBK_IOCTL_GET_INTERFACE
+
+* Renamed main header file (usb.h) to lusb0_usb.h. This eliminates
+ conflicts with the main WDK usb include as well as making the
+ libusb-win32 header more distinguishable from other usb library header
+ files.
+
+* Added device descriptor caching and active/first config descriptor
+ caching. Descriptor caching prevents unnecessary control requests from
+ interrupting devices that could potentially be in-use. It also makes
+ libusb0.sys more compliant with usb libraries targeting platform where
+ descriptor caching is done automatically. (linux/mac)
+
+* Upgraded to libwdi v1.1.1
+ o Zadig UI improvements
+ o wdi-simple now handles certificate related operations
+ o New NSIS (Nullsoft Scriptable Install System) script sample
+ o improved INNO Setup script sample
+ o libusbK support
+ o autogeneration and self-signing of a .cat file, to prevent further security
+ prompts during driver installation on Vista and later.
+ for more information, see http://libwdi-cps.akeo.ie
+ o disable restore point creation during installation
+ o Visual Studio 2010 support and overall MS file cleanup
+ o use of the Kerberos/e2fsprogs parser in Zadig instead of libconfig
+
+V1.2.4.0 (04/11/2011)
+=======================
+* Removed get configuration request from the core driver
+ set_configuration function. This caused problems with
+ some non-compliant usb devices.
+
+* Added device descriptor dump to test applications.
+
+V1.2.3.0 (03/16/2011)
+=======================
+* Fixed bug-id 3117686 reported by Tim Schuerewegen.
+
+* Added LIBUSB_IOCTL_GET_OBJECT_NAME. This new IOCTL code retrieves object
+ from the driver. The only valid object name index is 0. Index 0 is
+ returns the devices plug and play registry key pathname.
+
+* Removed maximum timeout restriction for vendor class requests.
+
+V1.2.2.0 (10/02/2010)
+=======================
+* Added install-filter-win.exe. A gui installer for device filters.
+
+* Added new libusb0.dll function usb_install_np_rundll(). This function
+ is designed for rundll32.exe and takes the same parameters as
+ install-filter.exe.
+
+* Updated install-filter.exe. This application has several new features.
+ Type "install-filter --help" for more details.
+
+* Updated libusb-win32-devel-filter package. This package is once again
+ available for download as a setup.exe.
+
+* Updated libusb-win32 "bin" package format. inf-wizard.exe has been moved
+ up one directory.
+
+* Updated driver_installer_template.iss example. This is an Inno Setup
+ Script showing how to create your own setup.exe for installing your
+ application and driver.
+
+* Fixed missing byte order marker in inf-wizard.exe .inf files. (libwdi)
+
+* Fixed auto-configuration issue when there is more than one driver in the
+ stack.
+
+* Fixed BSOD when using the filter driver with devices that are auto
+ suspended by other drivers in the stack.
+
+* Fixed BSOD for devices with endpoints that have '0' for wMaxPacketSize.
+
+* Fixed BSOD when cancelling large transfers on high speed devices.
+
+
+V1.2.1.0 (07/28/2010)
+=======================
+* Updated bulk.c to include async i/o example code.
+
+* Fixed usb_install_driver_np() issue with inf-wizard generated infs.
+
+* Fixed inf2cat.exe issue with inf-wizard generated infs.
+
+* Added 'Install Now' feature to inf-wizard. (libwdi)
+
+* Added embedded libusb-win32 binaries to inf-wizard. (libwdi)
+
+* Added libwdi (http://www.libusb.org/wiki/libwdi) to inf-wizard.
+
+* Added get cached configuration request to usb_open(). This is a new
+ control code that involves no device i/o and allows
+ usb_set_configuration() to be omitted if the driver has already
+ configured it.
+
+* Fixed set_configuration() failure for devices that do not properly
+ support get_configuration().
+
+V1.2.0.0 (07/07/2010)
+=======================
+* First signed driver release! The libusb-win32 kernel driver (libusb0.sys)
+ can now be used on x64 Windows machines that require signed drivers.
+
+* Fixed 2128187 reported by Tim Green. usb_get_descriptor() can fail
+ because the given buffer of 8 bytes is too small.
+
+* Fixed 2928293 reported by Tim Green. Sometimes the call to
+ usb_fetch_and_parse_descriptors() in usb_find_devices() can fail. This
+ patch moves the LIST_ADD to after a successful read of the device's
+ configuration descriptors.
+
+* Fixed issue causing libusb-win32 to not act as power policy owner
+ when it should.
+
+* Fixed issue in which on rare occasion, a libusb-win32 filter device could
+ run as a "normal" device.
+
+* Fixed filter driver issue for device using wudfr.sys.
+
+* Added large transfer splitting to driver (bulk, int, iso). NOTE:
+ The dll continues to break transfers in the same manner it always has.
+
+
+V1.1.14.3 (06/12/2010)
+=======================
+* Remove get_configuration() request from usb_open(). This caused claim
+ interface to fail when used as a filter driver.
+
+V1.1.14.0 (06/01/2010)
+=======================
+* Updated logging functions and standardized log message display format.
+
+* Updated inf-wizard to use the new directory format for the libusb-win32
+ binaries.
+
+* Updated package directories to reflect the winddk BUILDARCH env variable.
+ (i64 := ia64, x64 := amd64)
+
+* Added request to get the current configuration in usb_open().
+
+* Fixed 2960644 (reported by farthen) crash on shutdown with x64 based
+ systems while using inf files for each libusb device.
+
+* Added additional log message only included in debug/chk builds.
+
+* Updated default log levels to highest verbose level for debug builds.
+
+* Added test signing support to the libusb-win32 make.cmd. This allows
+ libusb0.sys and libusb0.dll to be signed with a digital signature.
+ (see make.cmd for mmore details)
+
+* Added MSVC 2008 project files
+
+* Moved version defines to an include file (libusb_version.h)
+ This file is generated from libusb_version_h.in with "make.cmd makever"
+
+* Removed all "dist" commands from cyg/mingw makefile. Instead use "make.cmd"
+ in the "ddk_make" directory.
+
+* Fixed filter setup not running in 64bit mode
+
+* Fixed 64bit inf-wizard, testlibusb-win builds
+
+* Added set initial config value #1 when the driver is not a filter.
+ optionally, the initial configuration value can be specified in the inf
+ file: HKR,,"InitialConfigValue",0x00010001,<your config value>
+
+* Added support for querying device registry keys
+ (LIBUSB_IOCTL_GET_CUSTOM_REG_PROPERTY)
+
+* Added support for querying device properties
+ (LIBUSB_IOCTL_GET_DEVICE_PROPERTY)
+
+* Fixed possible race condition in kernel add_device()
+
+* Updated default ddk build version number to 1.1.14.0 to facilitate
+ Microsoft WHQL submission.
+
+* Added DDK build distribution system. Official libusb-win32 releases
+ (after 0.1.12.2) are built using Microsoft's WinDDK. (see make.cmd)
+
+* Fixed 2658937 (reported by Tim Roberts) The libusb-win32 driver always
+ acts as a power policy owner.
+
diff --git a/usb/driver/libusb_driver.c b/usb/driver/libusb_driver.c
new file mode 100644
index 0000000..61ebf77
--- /dev/null
+++ b/usb/driver/libusb_driver.c
@@ -0,0 +1,971 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#define __LIBUSB_DRIVER_C__
+
+#include "libusb_driver.h"
+#include "libusb-win32_version.h"
+
+// Device objects with an attached device using the
+// driver names listed here skipped in the add_device() routine.
+//
+const char* attached_driver_skip_list[] =
+{
+ "\\driver\\picopp",
+ "\\driver\\libusb0",
+ NULL
+};
+
+// Device objects with an attached device using the
+// driver names listed here have wdf below them. Special
+// restrictions apply to these devices.
+//
+const char* attached_driver_wdf_list[] =
+{
+ "\\driver\\winusb",
+ "\\driver\\wudfrd",
+ NULL
+};
+
+static bool_t match_driver(PDEVICE_OBJECT deviceObject, const char* driverString);
+
+
+#ifdef DBG
+
+static void debug_show_devices(PDEVICE_OBJECT deviceObject, int index, bool_t showNextDevice)
+{
+ ANSI_STRING driverName;
+
+ if (index > 16) return;
+
+ if (deviceObject)
+ {
+ if (deviceObject->DriverObject)
+ {
+ if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&driverName, &deviceObject->DriverObject->DriverName, TRUE)))
+ {
+ USBDBG("[%s #%d] %s\n",
+ (showNextDevice ? "NextDevice" : "AttachedDevice"),
+ index, driverName.Buffer);
+ RtlFreeAnsiString(&driverName);
+ }
+ }
+ if (deviceObject->AttachedDevice && !showNextDevice)
+ debug_show_devices(deviceObject->AttachedDevice, index+1, showNextDevice);
+ if (deviceObject->NextDevice && showNextDevice)
+ debug_show_devices(deviceObject->NextDevice, index+1, showNextDevice);
+ }
+}
+#endif
+
+static bool_t match_driver(PDEVICE_OBJECT deviceObject, const char* driverString)
+{
+ ANSI_STRING driverName;
+ bool_t ret = FALSE;
+
+ if (deviceObject)
+ {
+ if (deviceObject->DriverObject)
+ {
+ if (NT_SUCCESS(RtlUnicodeStringToAnsiString(&driverName, &deviceObject->DriverObject->DriverName, TRUE)))
+ {
+ _strlwr(driverName.Buffer);
+
+ if (strstr(driverName.Buffer,driverString))
+ {
+ ret = TRUE;
+ }
+ RtlFreeAnsiString(&driverName);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void DDKAPI unload(DRIVER_OBJECT *driver_object);
+static NTSTATUS DDKAPI on_usbd_complete(DEVICE_OBJECT *device_object,
+ IRP *irp,
+ void *context);
+
+NTSTATUS DDKAPI DriverEntry(DRIVER_OBJECT *driver_object,
+ UNICODE_STRING *registry_path)
+{
+ int i;
+
+ USBMSG("[loading-driver] v%d.%d.%d.%d\n",
+ VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO, VERSION_NANO);
+
+ /* initialize the driver object's dispatch table */
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ {
+ driver_object->MajorFunction[i] = dispatch;
+ }
+
+ driver_object->DriverExtension->AddDevice = add_device;
+ driver_object->DriverUnload = unload;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS DDKAPI add_device(DRIVER_OBJECT *driver_object,
+ DEVICE_OBJECT *physical_device_object)
+{
+ NTSTATUS status;
+ DEVICE_OBJECT *device_object = NULL;
+ libusb_device_t *dev;
+ ULONG device_type;
+ UNICODE_STRING nt_device_name;
+ UNICODE_STRING symbolic_link_name;
+ WCHAR tmp_name_0[128];
+ WCHAR tmp_name_1[128];
+ char id[256];
+ char compat_id[256];
+ int i;
+ DEVICE_OBJECT* attached_device;
+ bool_t has_wdf = FALSE;
+
+ /* get the hardware ID from the registry */
+ if (!reg_get_hardware_id(physical_device_object, id, sizeof(id)))
+ {
+ USBERR0("unable to read registry\n");
+ return STATUS_SUCCESS;
+ }
+
+ /* only attach the (filter) driver to USB devices, skip hubs */
+ if (!strstr(id, "usb\\") ||
+ strstr(id, "hub") ||
+ !strstr(id, "vid_") ||
+ !strstr(id, "pid_"))
+ {
+ USBDBG("skipping non-usb device or hub %s\n",id);
+ return STATUS_SUCCESS;
+ }
+
+ if (!reg_get_compatible_id(physical_device_object, compat_id, sizeof(compat_id)))
+ {
+ USBERR0("unable to read registry\n");
+ return STATUS_SUCCESS;
+ }
+ // Don't attach to usb device hubs
+ if (strstr(compat_id, "class_09"))
+ {
+ USBDBG("skipping usb device hub (%s) %s\n",compat_id, id);
+ return STATUS_SUCCESS;
+ }
+
+#ifdef DBG
+ debug_show_devices(physical_device_object->AttachedDevice, 0, FALSE);
+#endif
+
+ attached_device = physical_device_object->AttachedDevice;
+ while (attached_device)
+ {
+ // make sure this device isn't already using a driver that is
+ // incompatible with libusb-win32.
+ for (i=0; attached_driver_skip_list[i] != NULL; i++)
+ {
+ if (match_driver(attached_device, attached_driver_skip_list[i]))
+ {
+ USBDBG("skipping device %s\n", id);
+ return STATUS_SUCCESS;
+ }
+ }
+
+ // look for wdf
+ for (i=0; attached_driver_wdf_list[i] != NULL; i++)
+ {
+ if (match_driver(attached_device, attached_driver_wdf_list[i]))
+ {
+ has_wdf = TRUE;
+ }
+ }
+
+ attached_device=attached_device->AttachedDevice;
+ }
+
+ device_object = IoGetAttachedDeviceReference(physical_device_object);
+ if (device_object)
+ {
+ device_type = device_object->DeviceType;
+ ObDereferenceObject(device_object);
+ }
+ else
+ {
+ device_type = FILE_DEVICE_UNKNOWN;
+ }
+
+ /* try to create a new device object */
+ for (i = 1; i < LIBUSB_MAX_NUMBER_OF_DEVICES; i++)
+ {
+ /* initialize some unicode strings */
+ _snwprintf(tmp_name_0, sizeof(tmp_name_0)/sizeof(WCHAR), L"%s%04d",
+ LIBUSB_NT_DEVICE_NAME, i);
+ _snwprintf(tmp_name_1, sizeof(tmp_name_1)/sizeof(WCHAR), L"%s%04d",
+ LIBUSB_SYMBOLIC_LINK_NAME, i);
+
+ RtlInitUnicodeString(&nt_device_name, tmp_name_0);
+ RtlInitUnicodeString(&symbolic_link_name, tmp_name_1);
+
+ /* create the object */
+ status = IoCreateDevice(driver_object,
+ sizeof(libusb_device_t),
+ &nt_device_name, device_type, 0, FALSE,
+ &device_object);
+
+ if (NT_SUCCESS(status))
+ {
+ USBMSG("device #%d created for %s\n", i, id);
+ break;
+ }
+
+ device_object = NULL;
+
+ /* continue until an unused device name is found */
+ }
+
+ if (!device_object)
+ {
+ USBERR0("creating device failed\n");
+ return status;
+ }
+
+ status = IoCreateSymbolicLink(&symbolic_link_name, &nt_device_name);
+
+ if (!NT_SUCCESS(status))
+ {
+ USBERR0("creating symbolic link failed\n");
+ IoDeleteDevice(device_object);
+ return status;
+ }
+
+ /* setup the "device object" */
+ dev = device_object->DeviceExtension;
+
+ memset(dev, 0, sizeof(libusb_device_t));
+
+ // [trobinso] See patch: 2873573 (Tim Green)
+ dev->self = device_object;
+ dev->physical_device_object = physical_device_object;
+ dev->id = i;
+
+ // store the device id in the device extentions
+ RtlCopyMemory(dev->device_id, id, sizeof(dev->device_id));
+
+ /* set initial power states */
+ dev->power_state.DeviceState = PowerDeviceD0;
+ dev->power_state.SystemState = PowerSystemWorking;
+
+ dev->disallow_power_control = has_wdf;
+
+ /* get device properties from the registry */
+ if (!reg_get_properties(dev))
+ {
+ USBERR0("getting device properties failed\n");
+ IoDeleteSymbolicLink(&symbolic_link_name);
+ IoDeleteDevice(device_object);
+ return STATUS_SUCCESS;
+ }
+
+ if (dev->is_filter && !physical_device_object->AttachedDevice)
+ {
+ USBWRN("[FILTER-MODE-MISMATCH] device is reporting itself as filter when there are no attached device(s).\n%s\n", id);
+ }
+ else if (!dev->is_filter && physical_device_object->AttachedDevice)
+ {
+ USBWRN("[FILTER-MODE-MISMATCH] device is reporting itself as normal when there are already attached device(s).\n%s\n", id);
+ //dev->is_filter = TRUE;
+ }
+
+ clear_pipe_info(dev);
+
+ remove_lock_initialize(dev);
+
+ if (dev->device_interface_in_use)
+ {
+ status = IoRegisterDeviceInterface(physical_device_object,
+ (LPGUID)&dev->device_interface_guid,
+ NULL,
+ &dev->device_interface_name);
+ if (!NT_SUCCESS (status))
+ {
+ dev->device_interface_name.Buffer = NULL;
+
+ USBERR0("creating device interface failed\n");
+ IoDeleteSymbolicLink(&symbolic_link_name);
+ IoDeleteDevice(device_object);
+ return status;
+ }
+ else
+ {
+ set_filter_interface_key(dev,dev->id);
+ if (dev->device_interface_in_use)
+ {
+ HANDLE hKey=NULL;
+ if (NT_SUCCESS(IoOpenDeviceInterfaceRegistryKey(&dev->device_interface_name,KEY_ALL_ACCESS,&hKey)))
+ {
+ UNICODE_STRING valueName;
+ RtlInitUnicodeString(&valueName, L"LUsb0");
+
+ if (NT_SUCCESS(ZwSetValueKey(hKey,&valueName, 0, REG_DWORD, &dev->id,sizeof(ULONG))))
+ {
+ USBMSG("updated interface registry with LUsb0 direct-access symbolic link. id=%04d\n",dev->id);
+ }
+ else
+ {
+ USBERR0("IoOpenDeviceInterfaceRegistryKey:ZwSetValueKey failed\n");
+ }
+ ZwClose(hKey);
+ }
+ else
+ {
+ USBERR0("IoOpenDeviceInterfaceRegistryKey failed\n");
+ }
+ }
+ }
+ }
+ // make sure the the devices can't be removed
+ // before we are done adding it.
+ if (!NT_SUCCESS(remove_lock_acquire(dev)))
+ {
+ USBERR0("remove_lock_acquire failed\n");
+ IoDeleteSymbolicLink(&symbolic_link_name);
+ IoDeleteDevice(device_object);
+ return STATUS_SUCCESS;
+ }
+
+ /* attach the newly created device object to the stack */
+ dev->next_stack_device = IoAttachDeviceToDeviceStack(device_object, physical_device_object);
+
+ if (!dev->next_stack_device)
+ {
+ USBERR("attaching %s to device stack failed\n", id);
+ IoDeleteSymbolicLink(&symbolic_link_name);
+ IoDeleteDevice(device_object);
+ remove_lock_release(dev); // always release acquired locks
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ if (dev->is_filter)
+ {
+ USBDBG("[filter-mode] id=#%d %s\n",dev->id, dev->device_id);
+
+ /* send all USB requests to the PDO in filter driver mode */
+ dev->target_device = dev->physical_device_object;
+
+ /* use the same flags as the underlying object */
+ device_object->Flags |= dev->next_stack_device->Flags
+ & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
+
+ // use the same DeviceType as the underlying object
+ device_object->DeviceType = dev->next_stack_device->DeviceType;
+
+ // use the same Characteristics as the underlying object
+ device_object->Characteristics = dev->next_stack_device->Characteristics;
+ }
+ else
+ {
+ USBDBG("[normal-mode] id=#%d %s\n",dev->id, dev->device_id);
+
+ /* send all USB requests to the lower object in device driver mode */
+ dev->target_device = dev->next_stack_device;
+ device_object->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
+ }
+
+ UpdateContextConfigDescriptor(dev,NULL,0,0,-1);
+
+ device_object->Flags &= ~DO_DEVICE_INITIALIZING;
+ remove_lock_release(dev);
+
+ USBMSG("complete status=%08X\n",status);
+ return status;
+}
+
+
+VOID DDKAPI unload(DRIVER_OBJECT *driver_object)
+{
+ USBMSG("[unloading-driver] v%d.%d.%d.%d\n",
+ VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO, VERSION_NANO);
+}
+
+NTSTATUS complete_irp(IRP *irp, NTSTATUS status, ULONG info)
+{
+ irp->IoStatus.Status = status;
+ irp->IoStatus.Information = info;
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+NTSTATUS call_usbd_ex(libusb_device_t *dev, void *urb, ULONG control_code,
+ int timeout, int max_timeout)
+{
+ KEVENT event;
+ NTSTATUS status;
+ IRP *irp;
+ IO_STACK_LOCATION *next_irp_stack;
+ LARGE_INTEGER _timeout;
+ IO_STATUS_BLOCK io_status;
+
+ if (max_timeout > 0 && timeout > max_timeout)
+ {
+ timeout = max_timeout;
+ }
+ if (timeout <= 0)
+ timeout = LIBUSB_MAX_CONTROL_TRANSFER_TIMEOUT;
+
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ irp = IoBuildDeviceIoControlRequest(control_code, dev->target_device,
+ NULL, 0, NULL, 0, TRUE,
+ NULL, &io_status);
+
+ if (!irp)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ next_irp_stack = IoGetNextIrpStackLocation(irp);
+ next_irp_stack->Parameters.Others.Argument1 = urb;
+ next_irp_stack->Parameters.Others.Argument2 = NULL;
+
+ IoSetCompletionRoutine(irp, on_usbd_complete, &event, TRUE, TRUE, TRUE);
+
+ status = IoCallDriver(dev->target_device, irp);
+ if(status == STATUS_PENDING)
+ {
+ _timeout.QuadPart = -(timeout * 10000);
+
+ if(KeWaitForSingleObject(&event, Executive, KernelMode,
+ FALSE, &_timeout) == STATUS_TIMEOUT)
+ {
+ USBERR0("request timed out\n");
+ IoCancelIrp(irp);
+ }
+ }
+
+ /* wait until completion routine is called */
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+
+ status = irp->IoStatus.Status;
+
+ /* complete the request */
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+
+ USBDBG("status = %08Xh\n",status);
+ return status;
+}
+
+static NTSTATUS DDKAPI on_usbd_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context)
+{
+ KeSetEvent((KEVENT *) context, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+
+NTSTATUS pass_irp_down(libusb_device_t *dev, IRP *irp,
+ PIO_COMPLETION_ROUTINE completion_routine,
+ void *context)
+{
+ if (completion_routine)
+ {
+ IoCopyCurrentIrpStackLocationToNext(irp);
+ IoSetCompletionRoutine(irp, completion_routine, context,
+ TRUE, TRUE, TRUE);
+ }
+ else
+ {
+ IoSkipCurrentIrpStackLocation(irp);
+ }
+
+ return IoCallDriver(dev->next_stack_device, irp);
+}
+/*
+bool_t accept_irp(libusb_device_t *dev, IRP *irp)
+{
+ if (irp->Tail.Overlay.OriginalFileObject)
+ {
+ return irp->Tail.Overlay.OriginalFileObject->DeviceObject
+ == dev->self ? TRUE : FALSE;
+ }
+
+ return FALSE;
+}
+*/
+bool_t accept_irp(libusb_device_t *dev, IRP *irp)
+{
+ /* check if the IRP is sent to libusb's device object or to */
+ /* the lower one. This check is necessary since the device object */
+ /* might be a filter */
+ if(!irp->Tail.Overlay.OriginalFileObject)
+ return FALSE;
+ if (irp->Tail.Overlay.OriginalFileObject->DeviceObject == dev->self)
+ return TRUE;
+
+ /* cover the cases when access is made by using device interfaces */
+ if (!dev->is_filter &&
+ dev->device_interface_in_use &&
+ (irp->Tail.Overlay.OriginalFileObject->DeviceObject == dev->physical_device_object))
+ return TRUE;
+
+ return FALSE;
+}
+
+bool_t get_pipe_handle(libusb_device_t *dev, int endpoint_address,
+ USBD_PIPE_HANDLE *pipe_handle)
+{
+ int i, j;
+
+ *pipe_handle = NULL;
+
+ for (i = 0; i < LIBUSB_MAX_NUMBER_OF_INTERFACES; i++)
+ {
+ if (dev->config.interfaces[i].valid)
+ {
+ for (j = 0; j < LIBUSB_MAX_NUMBER_OF_ENDPOINTS; j++)
+ {
+ if (dev->config.interfaces[i].endpoints[j].address
+ == endpoint_address)
+ {
+ *pipe_handle = dev->config.interfaces[i].endpoints[j].handle;
+
+ return !*pipe_handle ? FALSE : TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+bool_t get_pipe_info(libusb_device_t *dev, int endpoint_address,
+ libusb_endpoint_t** pipe_info)
+{
+ int i, j;
+
+ *pipe_info = NULL;
+
+ for (i = 0; i < LIBUSB_MAX_NUMBER_OF_INTERFACES; i++)
+ {
+ if (dev->config.interfaces[i].valid)
+ {
+ for (j = 0; j < LIBUSB_MAX_NUMBER_OF_ENDPOINTS; j++)
+ {
+ if (dev->config.interfaces[i].endpoints[j].address
+ == endpoint_address)
+ {
+ *pipe_info = &dev->config.interfaces[i].endpoints[j];
+
+ return !*pipe_info ? FALSE : TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+void clear_pipe_info(libusb_device_t *dev)
+{
+ memset(dev->config.interfaces, 0 , sizeof(dev->config.interfaces));
+}
+
+bool_t update_pipe_info(libusb_device_t *dev,
+ USBD_INTERFACE_INFORMATION *interface_info)
+{
+ int i;
+ int number;
+ int maxTransferSize;
+ int maxPacketSize;
+
+ if (!interface_info)
+ {
+ return FALSE;
+ }
+
+ number = interface_info->InterfaceNumber;
+
+ if (interface_info->InterfaceNumber >= LIBUSB_MAX_NUMBER_OF_INTERFACES)
+ {
+ return FALSE;
+ }
+
+ USBMSG("interface %d\n", number);
+
+ dev->config.interfaces[number].valid = TRUE;
+
+ for (i = 0; i < LIBUSB_MAX_NUMBER_OF_ENDPOINTS; i++)
+ {
+ dev->config.interfaces[number].endpoints[i].address = 0;
+ dev->config.interfaces[number].endpoints[i].handle = NULL;
+ }
+
+ if (interface_info)
+ {
+ for (i = 0; i < (int)interface_info->NumberOfPipes
+ && i < LIBUSB_MAX_NUMBER_OF_ENDPOINTS; i++)
+ {
+ maxPacketSize = interface_info->Pipes[i].MaximumPacketSize;
+ maxTransferSize = interface_info->Pipes[i].MaximumTransferSize;
+
+ USBMSG("EP%02Xh maximum-packet-size=%d maximum-transfer-size=%d\n",
+ interface_info->Pipes[i].EndpointAddress,
+ maxPacketSize,
+ maxTransferSize);
+
+ dev->config.interfaces[number].endpoints[i].handle = interface_info->Pipes[i].PipeHandle;
+ dev->config.interfaces[number].endpoints[i].address = interface_info->Pipes[i].EndpointAddress;
+ dev->config.interfaces[number].endpoints[i].maximum_packet_size = maxPacketSize;
+ dev->config.interfaces[number].endpoints[i].interval = interface_info->Pipes[i].Interval;
+ dev->config.interfaces[number].endpoints[i].pipe_type = interface_info->Pipes[i].PipeType;
+ dev->config.interfaces[number].endpoints[i].pipe_flags = interface_info->Pipes[i].PipeFlags;
+
+ if (maxPacketSize)
+ {
+ // set max the maximum transfer size default to an interval of max packet size.
+ maxTransferSize = maxTransferSize - (maxTransferSize % maxPacketSize);
+ if (maxTransferSize < maxPacketSize)
+ {
+ maxTransferSize = LIBUSB_MAX_READ_WRITE;
+ }
+ else if (maxTransferSize > LIBUSB_MAX_READ_WRITE)
+ {
+ maxTransferSize = LIBUSB_MAX_READ_WRITE - (LIBUSB_MAX_READ_WRITE % maxPacketSize);
+ }
+
+ if (maxTransferSize != interface_info->Pipes[i].MaximumTransferSize)
+ {
+ USBWRN("overriding EP%02Xh maximum-transfer-size=%d\n",
+ dev->config.interfaces[number].endpoints[i].address,
+ maxTransferSize);
+ }
+ }
+ else
+ {
+ if (!maxTransferSize)
+ {
+ // use the libusb-win32 default
+ maxTransferSize = LIBUSB_MAX_READ_WRITE;
+ }
+ }
+ dev->config.interfaces[number].endpoints[i].maximum_transfer_size = maxTransferSize;
+ }
+ }
+ return TRUE;
+}
+
+
+void remove_lock_initialize(libusb_device_t *dev)
+{
+ KeInitializeEvent(&dev->remove_lock.event, NotificationEvent, FALSE);
+ dev->remove_lock.usage_count = 1;
+ dev->remove_lock.remove_pending = FALSE;
+}
+
+
+NTSTATUS remove_lock_acquire(libusb_device_t *dev)
+{
+ InterlockedIncrement(&dev->remove_lock.usage_count);
+
+ if (dev->remove_lock.remove_pending)
+ {
+ if (InterlockedDecrement(&dev->remove_lock.usage_count) == 0)
+ {
+ KeSetEvent(&dev->remove_lock.event, 0, FALSE);
+ }
+ return STATUS_DELETE_PENDING;
+ }
+ return STATUS_SUCCESS;
+}
+
+
+void remove_lock_release(libusb_device_t *dev)
+{
+ if (InterlockedDecrement(&dev->remove_lock.usage_count) == 0)
+ {
+ KeSetEvent(&dev->remove_lock.event, 0, FALSE);
+ }
+}
+
+
+void remove_lock_release_and_wait(libusb_device_t *dev)
+{
+ dev->remove_lock.remove_pending = TRUE;
+ remove_lock_release(dev);
+ remove_lock_release(dev);
+ KeWaitForSingleObject(&dev->remove_lock.event, Executive, KernelMode,
+ FALSE, NULL);
+}
+
+
+USB_INTERFACE_DESCRIPTOR *
+find_interface_desc(USB_CONFIGURATION_DESCRIPTOR *config_desc,
+ unsigned int size, int interface_number, int altsetting)
+{
+ usb_descriptor_header_t *desc = (usb_descriptor_header_t *)config_desc;
+ char *p = (char *)desc;
+ USB_INTERFACE_DESCRIPTOR *if_desc = NULL;
+
+ if (!config_desc || (size < config_desc->wTotalLength))
+ return NULL;
+
+ while (size && desc->length <= size)
+ {
+ if (desc->type == USB_INTERFACE_DESCRIPTOR_TYPE)
+ {
+ if_desc = (USB_INTERFACE_DESCRIPTOR *)desc;
+
+ if ((if_desc->bInterfaceNumber == (UCHAR)interface_number)
+ && (if_desc->bAlternateSetting == (UCHAR)altsetting))
+ {
+ return if_desc;
+ }
+ }
+
+ size -= desc->length;
+ p += desc->length;
+ desc = (usb_descriptor_header_t *)p;
+ }
+
+ return NULL;
+}
+
+USB_INTERFACE_DESCRIPTOR* find_interface_desc_ex(USB_CONFIGURATION_DESCRIPTOR *config_desc,
+ unsigned int size,
+ interface_request_t* intf,
+ unsigned int* size_left)
+{
+#define INTF_FIELD 0
+#define ALTF_FIELD 1
+
+ usb_descriptor_header_t *desc = (usb_descriptor_header_t *)config_desc;
+ char *p = (char *)desc;
+ int lastInfNumber, lastAltNumber;
+ int currentInfIndex;
+ short InterfacesByIndex[LIBUSB_MAX_NUMBER_OF_INTERFACES][2];
+
+ USB_INTERFACE_DESCRIPTOR *if_desc = NULL;
+
+ memset(InterfacesByIndex,0xFF,sizeof(InterfacesByIndex));
+
+ if (!config_desc)
+ return NULL;
+
+ size = size > config_desc->wTotalLength ? config_desc->wTotalLength : size;
+
+ while (size && desc->length <= size)
+ {
+ if (desc->type == USB_INTERFACE_DESCRIPTOR_TYPE)
+ {
+ // this is a new interface or alternate interface
+ if_desc = (USB_INTERFACE_DESCRIPTOR *)desc;
+ for (currentInfIndex=0; currentInfIndex<LIBUSB_MAX_NUMBER_OF_INTERFACES;currentInfIndex++)
+ {
+ if (InterfacesByIndex[currentInfIndex][INTF_FIELD]==-1)
+ {
+ // this is a new interface
+ InterfacesByIndex[currentInfIndex][INTF_FIELD]=if_desc->bInterfaceNumber;
+ InterfacesByIndex[currentInfIndex][ALTF_FIELD]=0;
+ break;
+ }
+ else if (InterfacesByIndex[currentInfIndex][INTF_FIELD]==if_desc->bInterfaceNumber)
+ {
+ // this is a new alternate interface
+ InterfacesByIndex[currentInfIndex][ALTF_FIELD]++;
+ break;
+ }
+ }
+
+ // if the interface index is -1, then we don't care;
+ // i.e. any interface number or index
+ if (intf->interface_index!=FIND_INTERFACE_INDEX_ANY)
+ {
+ if (intf->intf_use_index)
+ {
+ // looking for a particular interface index; if this is not it then continue on.
+ if (intf->interface_index != currentInfIndex)
+ goto NextInterface;
+ }
+ else
+ {
+ // looking for a particular interface number; if this is not it then continue on.
+ if (intf->interface_number != if_desc->bInterfaceNumber)
+ goto NextInterface;
+ }
+ }
+
+ if (intf->altsetting_index!=FIND_INTERFACE_INDEX_ANY)
+ {
+ if (intf->altf_use_index)
+ {
+ // looking for a particular alternate interface index; if this is not it then continue on.
+ if (intf->altsetting_index != InterfacesByIndex[currentInfIndex][ALTF_FIELD])
+ goto NextInterface;
+ }
+ else
+ {
+ // looking for a particular alternate interface number; if this is not it then continue on.
+ if (intf->altsetting_number != if_desc->bAlternateSetting)
+ goto NextInterface;
+ }
+ }
+
+ // found a match
+ intf->interface_index = (unsigned char)currentInfIndex;
+ intf->altsetting_index = (unsigned char)InterfacesByIndex[currentInfIndex][ALTF_FIELD];
+ intf->interface_number = if_desc->bInterfaceNumber;
+ intf->altsetting_number = if_desc->bAlternateSetting;
+
+ if (size_left)
+ {
+ *size_left=size;
+ }
+ return if_desc;
+
+ }
+
+NextInterface:
+ size -= desc->length;
+ p += desc->length;
+ desc = (usb_descriptor_header_t *)p;
+ }
+
+ return NULL;
+}
+
+USB_ENDPOINT_DESCRIPTOR *
+find_endpoint_desc_by_index(USB_INTERFACE_DESCRIPTOR *interface_desc,
+ unsigned int size, int pipe_index)
+{
+ usb_descriptor_header_t *desc = (usb_descriptor_header_t *)interface_desc;
+ char *p = (char *)desc;
+ int currentPipeIndex;
+ short PipesByIndex[LIBUSB_MAX_NUMBER_OF_ENDPOINTS];
+
+ USB_ENDPOINT_DESCRIPTOR *ep_desc = NULL;
+ memset(PipesByIndex,0xFF,sizeof(PipesByIndex));
+
+ if (size && desc->length <= size)
+ {
+ size -= desc->length;
+ p += desc->length;
+ desc = (usb_descriptor_header_t *)p;
+ }
+
+ while (size && desc->length <= size)
+ {
+ if (desc->type == USB_ENDPOINT_DESCRIPTOR_TYPE)
+ {
+ ep_desc = (USB_ENDPOINT_DESCRIPTOR *)desc;
+ for (currentPipeIndex=0; currentPipeIndex<LIBUSB_MAX_NUMBER_OF_ENDPOINTS;currentPipeIndex++)
+ {
+ if (PipesByIndex[currentPipeIndex]==-1)
+ {
+ PipesByIndex[currentPipeIndex]=ep_desc->bEndpointAddress;
+ break;
+ }
+ else if (PipesByIndex[currentPipeIndex]==ep_desc->bEndpointAddress)
+ {
+ // the pipe is defined twice in the same interface
+ USBWRN("invalid endpoint descriptor at pipe index=%d\n",currentPipeIndex);
+ break;
+ }
+ }
+
+ if (pipe_index == currentPipeIndex)
+ {
+ return ep_desc;
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ size -= desc->length;
+ p += desc->length;
+ desc = (usb_descriptor_header_t *)p;
+ }
+
+ return NULL;
+}
+
+
+ULONG get_current_frame(IN PDEVICE_EXTENSION deviceExtension, IN PIRP Irp)
+/*++
+
+Routine Description:
+
+ This routine send an irp/urb pair with
+ function code URB_FUNCTION_GET_CURRENT_FRAME_NUMBER
+ to fetch the current frame
+
+Arguments:
+
+ DeviceObject - pointer to device object
+ PIRP - I/O request packet
+
+Return Value:
+
+ Current frame
+
+--*/
+{
+ KEVENT event;
+ PIO_STACK_LOCATION nextStack;
+ struct _URB_GET_CURRENT_FRAME_NUMBER urb;
+
+ //
+ // initialize the urb
+ //
+
+ urb.Hdr.Function = URB_FUNCTION_GET_CURRENT_FRAME_NUMBER;
+ urb.Hdr.Length = sizeof(urb);
+ urb.FrameNumber = (ULONG) -1;
+
+ nextStack = IoGetNextIrpStackLocation(Irp);
+ nextStack->Parameters.Others.Argument1 = (PVOID) &urb;
+ nextStack->Parameters.DeviceIoControl.IoControlCode =
+ IOCTL_INTERNAL_USB_SUBMIT_URB;
+ nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+
+ KeInitializeEvent(&event,
+ NotificationEvent,
+ FALSE);
+
+ IoSetCompletionRoutine(Irp,
+ on_usbd_complete,
+ &event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+
+ IoCallDriver(deviceExtension->target_device, Irp);
+
+ KeWaitForSingleObject((PVOID) &event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ return urb.FrameNumber;
+}
diff --git a/usb/driver/libusb_driver.h b/usb/driver/libusb_driver.h
new file mode 100644
index 0000000..e0a5d3c
--- /dev/null
+++ b/usb/driver/libusb_driver.h
@@ -0,0 +1,429 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef __LIBUSB_DRIVER_H__
+#define __LIBUSB_DRIVER_H__
+
+//#define SKIP_CONFIGURE_NORMAL_DEVICES
+//#define SKIP_DEVICES_WINUSB
+//#define SKIP_DEVICES_PICOPP
+
+#ifdef __GNUC__
+#include <ddk/usb100.h>
+#include <ddk/usbdi.h>
+#include <ddk/winddk.h>
+#include "usbdlib_gcc.h"
+#else
+#include <ntifs.h>
+#include <wdm.h>
+#include "usbdi.h"
+#include "usbdlib.h"
+#endif
+
+#include <wchar.h>
+#include <initguid.h>
+
+#undef interface
+
+#include "driver_debug.h"
+#include "error.h"
+#include "driver_api.h"
+
+/* some missing defines */
+#ifdef __GNUC__
+
+#define USBD_TRANSFER_DIRECTION_OUT 0
+#define USBD_TRANSFER_DIRECTION_BIT 0
+#define USBD_TRANSFER_DIRECTION_IN (1 << USBD_TRANSFER_DIRECTION_BIT)
+#define USBD_SHORT_TRANSFER_OK_BIT 1
+#define USBD_SHORT_TRANSFER_OK (1 << USBD_SHORT_TRANSFER_OK_BIT)
+#define USBD_START_ISO_TRANSFER_ASAP_BIT 2
+#define USBD_START_ISO_TRANSFER_ASAP (1 << USBD_START_ISO_TRANSFER_ASAP_BIT)
+
+#endif
+
+#define SET_CONFIG_ACTIVE_CONFIG -258
+
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+#define USB_TYPE_STANDARD 0x00
+#define USB_TYPE_CLASS 0x01
+#define USB_TYPE_VENDOR 0x02
+
+
+#define LIBUSB_NT_DEVICE_NAME L"\\Device\\libusb0"
+#define LIBUSB_SYMBOLIC_LINK_NAME L"\\DosDevices\\libusb0-"
+
+#define LIBUSB_MAX_NUMBER_OF_ENDPOINTS 32
+#define LIBUSB_MAX_NUMBER_OF_INTERFACES 32
+
+
+#define LIBUSB_DEFAULT_TIMEOUT 5000
+#define LIBUSB_MAX_CONTROL_TRANSFER_TIMEOUT 5000
+
+
+#ifndef __GNUC__
+#define DDKAPI
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!(FALSE))
+#endif
+
+typedef int bool_t;
+
+#define POOL_TAG (ULONG) '0BSU'
+#undef ExAllocatePool
+#define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, POOL_TAG)
+
+#define IS_PIPE_TYPE(pipeInfo, pipeType) ((((pipeInfo->pipe_type & 3)==pipeType))?TRUE:FALSE)
+
+#define IS_CTRL_PIPE(pipeInfo) IS_PIPE_TYPE(pipeInfo,UsbdPipeTypeControl)
+#define IS_ISOC_PIPE(pipeInfo) IS_PIPE_TYPE(pipeInfo,UsbdPipeTypeIsochronous)
+#define IS_BULK_PIPE(pipeInfo) IS_PIPE_TYPE(pipeInfo,UsbdPipeTypeBulk)
+#define IS_INTR_PIPE(pipeInfo) IS_PIPE_TYPE(pipeInfo,UsbdPipeTypeInterrupt)
+
+#define GetMaxTransferSize(pipeInfo, reqMaxTransferSize) ((reqMaxTransferSize) ? reqMaxTransferSize : pipeInfo->maximum_transfer_size)
+
+#define UrbFunctionFromEndpoint(PipeInfo) ((IS_ISOC_PIPE(PipeInfo)) ? URB_FUNCTION_ISOCH_TRANSFER : URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER)
+#define UsbdDirectionFromEndpoint(PipeInfo) ((PipeInfo->address & 0x80) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT)
+
+#define UpdateContextConfigDescriptor(DeviceContext, Descriptor, Size, Value, Index) \
+{ \
+ if (DeviceContext->config.descriptor && DeviceContext->config.descriptor!=(Descriptor)) \
+ ExFreePool(DeviceContext->config.descriptor); \
+ DeviceContext->config.descriptor=(Descriptor); \
+ DeviceContext->config.total_size=(Size); \
+ DeviceContext->config.value=(Value); \
+ DeviceContext->config.index=(Index); \
+}
+
+#ifndef __WUSBIO_H__
+
+// Pipe policy types
+
+// The default value is zero. To set a time-out value, in Value pass the address of a caller-allocated ULONG variable that contains the time-out interval.
+// The PIPE_TRANSFER_TIMEOUT value specifies the time-out interval, in milliseconds. The host controller cancels transfers that do not complete within the specified time-out interval.
+// A value of zero (default) indicates that transfers do not time out because the host controller never cancels the transfer.
+#define PIPE_TRANSFER_TIMEOUT 0x03
+
+// Device Information types
+#define DEVICE_SPEED 0x01
+
+// Device Speeds
+#define LowSpeed 0x01
+#define FullSpeed 0x02
+#define HighSpeed 0x03
+
+#endif
+
+#define USB_ENDPOINT_ADDRESS_MASK 0x0F
+#define USB_ENDPOINT_DIR_MASK 0x80
+#define LBYTE(w) (w & 0xFF)
+#define HBYTE(w) ((w>>8) & 0xFF)
+
+
+#include <pshpack1.h>
+
+typedef struct
+{
+ unsigned char length;
+ unsigned char type;
+} usb_descriptor_header_t;
+
+#include <poppack.h>
+
+
+typedef struct
+{
+ long usage_count;
+ int remove_pending;
+ KEVENT event;
+} libusb_remove_lock_t;
+
+typedef struct
+{
+ int address;
+ USBD_PIPE_HANDLE handle;
+ int maximum_packet_size; // Maximum packet size for this pipe
+ int interval; // Polling interval in ms if interrupt pipe
+ USBD_PIPE_TYPE pipe_type; // PipeType identifies type of transfer valid for this pipe
+
+ //
+ // INPUT
+ // These fields are filled in by the client driver
+ //
+ int maximum_transfer_size; // Maximum size for a single request
+ // in bytes.
+ int pipe_flags;
+} libusb_endpoint_t;
+
+typedef struct
+{
+ bool_t valid;
+ FILE_OBJECT *file_object; /* file object this interface is bound to */
+ libusb_endpoint_t endpoints[LIBUSB_MAX_NUMBER_OF_ENDPOINTS];
+
+} libusb_interface_t;
+
+typedef struct
+{
+ DEVICE_OBJECT *self;
+ DEVICE_OBJECT *physical_device_object;
+ DEVICE_OBJECT *next_stack_device;
+ DEVICE_OBJECT *target_device;
+ libusb_remove_lock_t remove_lock;
+ bool_t is_filter;
+ bool_t is_started;
+ bool_t surprise_removal_ok;
+ int id;
+ USB_DEVICE_DESCRIPTOR device_descriptor;
+ struct
+ {
+ USBD_CONFIGURATION_HANDLE handle;
+ int value;
+ int index;
+ libusb_interface_t interfaces[LIBUSB_MAX_NUMBER_OF_INTERFACES];
+ PUSB_CONFIGURATION_DESCRIPTOR descriptor;
+ int total_size;
+ } config;
+ POWER_STATE power_state;
+ DEVICE_POWER_STATE device_power_states[PowerSystemMaximum];
+ int initial_config_value;
+ char device_id[256];
+ bool_t disallow_power_control;
+ char objname_plugplay_registry_key[512];
+ GUID device_interface_guid;
+ bool_t device_interface_in_use;
+ UNICODE_STRING device_interface_name;
+ int control_read_timeout;
+ int control_write_timeout;
+} libusb_device_t, DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+
+NTSTATUS DDKAPI add_device(DRIVER_OBJECT *driver_object,
+ DEVICE_OBJECT *physical_device_object);
+
+NTSTATUS DDKAPI dispatch(DEVICE_OBJECT *device_object, IRP *irp);
+NTSTATUS dispatch_pnp(libusb_device_t *dev, IRP *irp);
+NTSTATUS dispatch_power(libusb_device_t *dev, IRP *irp);
+NTSTATUS dispatch_ioctl(libusb_device_t *dev, IRP *irp);
+
+NTSTATUS complete_irp(IRP *irp, NTSTATUS status, ULONG info);
+
+#define call_usbd(dev, urb, control_code, timeout) \
+ call_usbd_ex(dev, urb, control_code, timeout, LIBUSB_MAX_CONTROL_TRANSFER_TIMEOUT)
+
+NTSTATUS call_usbd_ex(libusb_device_t *dev,
+ void *urb,
+ ULONG control_code,
+ int timeout,
+ int max_timeout);
+
+NTSTATUS pass_irp_down(libusb_device_t *dev, IRP *irp,
+ PIO_COMPLETION_ROUTINE completion_routine,
+ void *context);
+
+bool_t accept_irp(libusb_device_t *dev, IRP *irp);
+
+bool_t get_pipe_handle(libusb_device_t *dev, int endpoint_address,
+ USBD_PIPE_HANDLE *pipe_handle);
+
+bool_t get_pipe_info(libusb_device_t *dev, int endpoint_address,
+ libusb_endpoint_t** pipe_info);
+
+void clear_pipe_info(libusb_device_t *dev);
+bool_t update_pipe_info(libusb_device_t *dev,
+ USBD_INTERFACE_INFORMATION *interface_info);
+
+void remove_lock_initialize(libusb_device_t *dev);
+NTSTATUS remove_lock_acquire(libusb_device_t *dev);
+void remove_lock_release(libusb_device_t *dev);
+void remove_lock_release_and_wait(libusb_device_t *dev);
+
+NTSTATUS set_configuration(libusb_device_t *dev,
+ int configuration, int timeout);
+NTSTATUS auto_configure(libusb_device_t *dev);
+
+NTSTATUS get_configuration(libusb_device_t *dev,
+ unsigned char *configuration, int *ret,
+ int timeout);
+
+NTSTATUS set_feature(libusb_device_t *dev,
+ int recipient, int index, int feature, int timeout);
+NTSTATUS clear_feature(libusb_device_t *dev,
+ int recipient, int index, int feature, int timeout);
+NTSTATUS get_status(libusb_device_t *dev, int recipient,
+ int index, char *status, int *ret, int timeout);
+NTSTATUS set_descriptor(libusb_device_t *dev,
+ void *buffer, int size,
+ int type, int recipient, int index, int language_id,
+ int *sent, int timeout);
+NTSTATUS get_descriptor(libusb_device_t *dev, void *buffer, int size,
+ int type, int recipient, int index, int language_id,
+ int *received, int timeout);
+
+PUSB_CONFIGURATION_DESCRIPTOR get_config_descriptor(
+ libusb_device_t *dev,
+ int value,
+ int *size,
+ int* index);
+
+NTSTATUS vendor_class_request(libusb_device_t *dev,
+ int type, int recipient,
+ int request, int value, int index,
+ void *buffer, int size, int direction,
+ int *ret, int timeout);
+
+NTSTATUS abort_endpoint(libusb_device_t *dev, int endpoint, int timeout);
+NTSTATUS reset_endpoint(libusb_device_t *dev, int endpoint, int timeout);
+NTSTATUS reset_device(libusb_device_t *dev, int timeout);
+
+#define USB_RESET_TYPE_RESET_PORT (1 << 0)
+#define USB_RESET_TYPE_CYCLE_PORT (1 << 1)
+#define USB_RESET_TYPE_FULL_RESET (USB_RESET_TYPE_CYCLE_PORT | USB_RESET_TYPE_RESET_PORT)
+NTSTATUS reset_device_ex(libusb_device_t *dev, int timeout, unsigned int reset_type);
+
+bool_t reg_get_hardware_id(DEVICE_OBJECT *physical_device_object,
+ char *data, int size);
+bool_t reg_get_compatible_id(DEVICE_OBJECT *physical_device_object,
+ char *data, int size);
+
+bool_t reg_get_properties(libusb_device_t *dev);
+
+
+void power_set_device_state(libusb_device_t *dev,
+ DEVICE_POWER_STATE device_state, bool_t block);
+
+USB_INTERFACE_DESCRIPTOR *
+find_interface_desc(USB_CONFIGURATION_DESCRIPTOR *config_desc,
+ unsigned int size, int interface_number, int altsetting);
+
+#define FIND_INTERFACE_INDEX_ANY (-1)
+USB_INTERFACE_DESCRIPTOR* find_interface_desc_ex(USB_CONFIGURATION_DESCRIPTOR *config_desc,
+ unsigned int size,
+ interface_request_t* intf,
+ unsigned int* size_left);
+
+USB_ENDPOINT_DESCRIPTOR *
+find_endpoint_desc_by_index(USB_INTERFACE_DESCRIPTOR *interface_desc,
+ unsigned int size, int pipe_index);
+
+/*
+Gets a device property for the device_object.
+
+Returns: NTSTATUS code from IoGetDeviceProperty
+ STATUS_INVALID_PARAMETER
+*/
+NTSTATUS reg_get_device_property(PDEVICE_OBJECT device_object,
+ int property,
+ char* data_buffer,
+ int data_length,
+ int* actual_length);
+
+NTSTATUS reg_get_custom_property(PDEVICE_OBJECT device_object,
+ char *data_buffer,
+ unsigned int data_length,
+ unsigned int name_offset,
+ int* actual_length);
+
+
+NTSTATUS transfer(libusb_device_t* dev,
+ IN PIRP irp,
+ IN int direction,
+ IN int urbFunction,
+ IN libusb_endpoint_t* endpoint,
+ IN int packetSize,
+ IN int transferFlags,
+ IN int isoLatency,
+ IN PMDL mdlAddress,
+ IN int totalLength);
+
+NTSTATUS large_transfer(IN libusb_device_t* dev,
+ IN PIRP irp,
+ IN int direction,
+ IN int urbFunction,
+ IN libusb_endpoint_t* endpoint,
+ IN int packetSize,
+ IN int maxTransferSize,
+ IN int transferFlags,
+ IN int isoLatency,
+ IN PMDL mdlAddress,
+ IN int totalLength);
+
+ULONG get_current_frame(IN PDEVICE_EXTENSION dev, IN PIRP Irp);
+
+
+NTSTATUS control_transfer(libusb_device_t* dev,
+ PIRP irp,
+ PMDL mdl,
+ int size,
+ int usbd_direction,
+ int *ret,
+ int timeout,
+ UCHAR request_type,
+ UCHAR request,
+ USHORT value,
+ USHORT index,
+ USHORT length);
+
+NTSTATUS claim_interface(libusb_device_t *dev, FILE_OBJECT *file_object,
+ int interface);
+
+NTSTATUS claim_interface_ex(libusb_device_t *dev,
+ FILE_OBJECT *file_object,
+ interface_request_t* interface_request);
+
+NTSTATUS release_all_interfaces(libusb_device_t *dev,
+ FILE_OBJECT *file_object);
+
+NTSTATUS release_interface(libusb_device_t *dev, FILE_OBJECT *file_object,
+ int interface);
+
+NTSTATUS release_interface_ex(libusb_device_t *dev,
+ FILE_OBJECT *file_object,
+ interface_request_t* interface_request);
+
+NTSTATUS set_interface(libusb_device_t *dev,
+ int interface_number,
+ int alt_interface_number,
+ int timeout);
+
+NTSTATUS set_interface_ex(libusb_device_t *dev,
+ interface_request_t* interface_request,
+ int timeout);
+
+NTSTATUS get_interface(libusb_device_t *dev,
+ int interface_number,
+ unsigned char *altsetting,
+ int timeout);
+
+NTSTATUS get_interface_ex(libusb_device_t *dev,
+ interface_request_t* interface_request,
+ int timeout);
+
+VOID set_filter_interface_key(libusb_device_t *dev, ULONG id);
+#endif
diff --git a/usb/driver/libusb_driver_rc.rc b/usb/driver/libusb_driver_rc.rc
new file mode 100644
index 0000000..b0affc8
--- /dev/null
+++ b/usb/driver/libusb_driver_rc.rc
@@ -0,0 +1,25 @@
+/* LIBUSB-WIN32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define RC_FILE_TYPE VFT_DRV
+#define RC_FILE_SUB_TYPE VFT2_DRV_SYSTEM
+#define RC_PRODUCT_STR "LibUSB-Win32 - Kernel Driver"
+#define RC_FILE_NAME_STR "libusb0.sys"
+
+#include "libusb-win32_version.rc"
+
diff --git a/usb/driver/lusb_defdi_guids.h b/usb/driver/lusb_defdi_guids.h
new file mode 100644
index 0000000..99833b0
--- /dev/null
+++ b/usb/driver/lusb_defdi_guids.h
@@ -0,0 +1,45 @@
+#ifndef __LUSB_DEFDI_GUIDS_
+#define __LUSB_DEFDI_GUIDS_
+
+#ifndef DEFINE_TO_STR
+#define _DEFINE_TO_STR(x) #x
+#define DEFINE_TO_STR(x) _DEFINE_TO_STR(x)
+#endif
+
+#ifndef DEFINE_TO_STRW
+#define _DEFINE_TO_STRW(x) L#x
+#define DEFINE_TO_STRW(x) _DEFINE_TO_STRW(x)
+#endif
+
+#define DEFINE_DEVICE_INTERFACE_GUID(BaseFieldName,BaseGuidName,L1,W1,W2,B1,B2,B3,B4,B5,B6,B7,B8) \
+ const GUID BaseFieldName##Guid = { L1, W1, W2, { B1, B2, B3, B4, B5, B6, B7, B8 } }; \
+ const CHAR* BaseFieldName##GuidA = DEFINE_TO_STR(BaseGuidName); \
+ const WCHAR* BaseFieldName##GuidW = DEFINE_TO_STRW(BaseGuidName)
+
+#define _DefRawDeviceGuid {A5DCBF10-6530-11D2-901F-00C04FB951ED}
+#define _DefLibusb0FilterGuid {F9F3FF14-AE21-48A0-8A25-8011A7A931D9}
+#define _DefLibusb0DeviceGuid {20343A29-6DA1-4DB8-8A3C-16E774057BF5}
+#define _DefLibusbKDeviceGuid {6C696275-7362-2D77-696E-33322D574446}
+
+// USB Raw Device Interface GUID (DO NOT USE IN INF FILE)
+DEFINE_DEVICE_INTERFACE_GUID(RawDevice, \
+ _DefRawDeviceGuid, \
+ 0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
+
+// libusb0 Filter Device Interface GUID (DO NOT USE IN INF FILE)
+DEFINE_DEVICE_INTERFACE_GUID(Libusb0Filter,
+ _DefLibusb0FilterGuid, \
+ 0xF9F3FF14, 0xAE21, 0x48A0, 0x8A, 0x25, 0x80, 0x11, 0xA7, 0xA9, 0x31, 0xD9);
+
+// libusb0 Default Device Interface GUID (DO NOT USE IN INF FILE)
+DEFINE_DEVICE_INTERFACE_GUID(Libusb0Device,
+ _DefLibusb0DeviceGuid, \
+ 0x20343A29, 0x6DA1, 0x4DB8, 0x8A, 0x3C, 0x16, 0xE7, 0x74, 0x05, 0x7B, 0xF5);
+
+// libusbK Default Device Interface GUID (DO NOT USE IN INF FILE)
+DEFINE_DEVICE_INTERFACE_GUID(LibusbKDevice,
+ _DefLibusbKDeviceGuid, \
+ 0x6C696275, 0x7362, 0x2D77, 0x69, 0x6E, 0x33, 0x32, 0x2D, 0x57, 0x44, 0x46);
+
+
+#endif
diff --git a/usb/driver/pnp.c b/usb/driver/pnp.c
new file mode 100644
index 0000000..b103650
--- /dev/null
+++ b/usb/driver/pnp.c
@@ -0,0 +1,302 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+static NTSTATUS DDKAPI
+on_start_complete(DEVICE_OBJECT *device_object, IRP *irp,
+ void *context);
+
+static NTSTATUS DDKAPI
+on_device_usage_notification_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context);
+
+static NTSTATUS DDKAPI
+on_query_capabilities_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context);
+
+
+NTSTATUS dispatch_pnp(libusb_device_t *dev, IRP *irp)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+ UNICODE_STRING symbolic_link_name;
+ WCHAR tmp_name[128];
+
+ status = remove_lock_acquire(dev);
+
+ if (!NT_SUCCESS(status))
+ {
+ USBDBG("device %s is pending removal\n",dev->device_id);
+ return complete_irp(irp, status, 0);
+ }
+
+ switch (stack_location->MinorFunction)
+ {
+ case IRP_MN_REMOVE_DEVICE:
+
+ USBMSG("IRP_MN_REMOVE_DEVICE: is-filter=%c %s\n",
+ dev->is_filter ? 'Y' : 'N',
+ dev->device_id);
+
+ if (dev->device_interface_in_use && dev->is_started)
+ {
+ set_filter_interface_key(dev,(ULONG)-1);
+
+ status = IoSetDeviceInterfaceState(&dev->device_interface_name, FALSE);
+ if (!NT_SUCCESS(status))
+ {
+ USBERR0("IRP_MN_REMOVE_DEVICE: disabling device interface failed\n");
+ }
+ }
+
+ dev->is_started = FALSE;
+
+ /* wait until all outstanding requests are finished */
+ remove_lock_release_and_wait(dev);
+
+ status = pass_irp_down(dev, irp, NULL, NULL);
+
+ USBMSG("deleting device #%d %s\n", dev->id, dev->device_id);
+
+ _snwprintf(tmp_name, sizeof(tmp_name)/sizeof(WCHAR), L"%s%04d",
+ LIBUSB_SYMBOLIC_LINK_NAME, dev->id);
+
+ /* delete the symbolic link */
+ RtlInitUnicodeString(&symbolic_link_name, tmp_name);
+ IoDeleteSymbolicLink(&symbolic_link_name);
+
+ if (dev->device_interface_in_use && dev->device_interface_name.Buffer)
+ {
+ RtlFreeUnicodeString(&dev->device_interface_name);
+ }
+ UpdateContextConfigDescriptor(dev,NULL,0,0,-1);
+
+ /* delete the device object */
+ IoDetachDevice(dev->next_stack_device);
+ IoDeleteDevice(dev->self);
+
+ return status;
+
+ case IRP_MN_SURPRISE_REMOVAL:
+
+ dev->is_started = FALSE;
+ USBMSG("IRP_MN_SURPRISE_REMOVAL: is-filter=%c %s\n",
+ dev->is_filter ? 'Y' : 'N',
+ dev->device_id);
+
+ if (dev->device_interface_in_use)
+ {
+ set_filter_interface_key(dev,(ULONG)-1);
+ IoSetDeviceInterfaceState(&dev->device_interface_name, FALSE);
+ dev->device_interface_in_use=FALSE;
+ if (dev->device_interface_name.Buffer)
+ {
+ RtlFreeUnicodeString(&dev->device_interface_name);
+ dev->device_interface_name.Buffer = NULL;
+ }
+ }
+ UpdateContextConfigDescriptor(dev,NULL,0,0,-1);
+ status = STATUS_SUCCESS;
+
+ break;
+
+ case IRP_MN_START_DEVICE:
+ USBMSG("IRP_MN_START_DEVICE: is-filter=%c %s\n",
+ dev->is_filter ? 'Y' : 'N',
+ dev->device_id);
+
+ // A driver calls this routine after receiving a device set-power
+ // request and before calling PoStartNextPowerIrp. When handling a
+ // PnP IRP_MN_START_DEVICE request, the driver should call
+ // PoSetPowerState to notify the power manager that the device is
+ // in the D0 state.
+ //
+ PoSetPowerState(dev->self, DevicePowerState, dev->power_state);
+ if (dev->device_interface_in_use)
+ {
+ status = IoSetDeviceInterfaceState(&dev->device_interface_name, TRUE);
+ if (!NT_SUCCESS(status))
+ {
+ USBERR0("IRP_MN_START_DEVICE: enabling device interface failed\n");
+ }
+ }
+ return pass_irp_down(dev, irp, on_start_complete, NULL);
+
+ case IRP_MN_STOP_DEVICE:
+ dev->is_started = FALSE;
+ USBDBG("IRP_MN_STOP_DEVICE: is-filter=%c %s\n",
+ dev->is_filter ? 'Y' : 'N',
+ dev->device_id);
+ break;
+
+ case IRP_MN_DEVICE_USAGE_NOTIFICATION:
+ USBDBG("IRP_MN_DEVICE_USAGE_NOTIFICATION: is-filter=%c %s\n",
+ dev->is_filter ? 'Y' : 'N',
+ dev->device_id);
+
+ if (!dev->self->AttachedDevice
+ || (dev->self->AttachedDevice->Flags & DO_POWER_PAGABLE))
+ {
+ dev->self->Flags |= DO_POWER_PAGABLE;
+ }
+
+ return pass_irp_down(dev, irp, on_device_usage_notification_complete, NULL);
+
+ case IRP_MN_QUERY_CAPABILITIES:
+ USBDBG("IRP_MN_QUERY_CAPABILITIES: is-filter=%c %s\n",
+ dev->is_filter ? 'Y' : 'N',
+ dev->device_id);
+
+ if (!dev->is_filter)
+ {
+ /* apply registry setting */
+ stack_location->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = dev->surprise_removal_ok;
+ }
+
+ return pass_irp_down(dev, irp, on_query_capabilities_complete, NULL);
+
+ default:
+ break;
+
+ }
+
+ remove_lock_release(dev);
+ return pass_irp_down(dev, irp, NULL, NULL);
+}
+
+static NTSTATUS DDKAPI
+on_start_complete(DEVICE_OBJECT *device_object, IRP *irp, void *context)
+{
+ libusb_device_t *dev = device_object->DeviceExtension;
+
+ if (irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ USBDBG("is-filter=%c %s\n",
+ dev->is_filter ? 'Y' : 'N',
+ dev->device_id);
+
+ if (dev->next_stack_device->Characteristics & FILE_REMOVABLE_MEDIA)
+ {
+ device_object->Characteristics |= FILE_REMOVABLE_MEDIA;
+ }
+#ifndef SKIP_CONFIGURE_NORMAL_DEVICES
+ // select initial configuration if not a filter
+ if (!dev->is_filter && !dev->is_started)
+ {
+ // optionally, the initial configuration value can be specified
+ // in the inf file. See reg_get_properties()
+ // HKR,,"InitialConfigValue",0x00010001,<your config value>
+
+ // If initial_config_value is negative, the configuration will
+ // only be set if the device is not already configured.
+ if (dev->initial_config_value)
+ {
+ if (dev->initial_config_value == SET_CONFIG_ACTIVE_CONFIG)
+ {
+ USBDBG("applying active configuration for %s\n",
+ dev->device_id);
+ }
+ else
+ {
+ USBDBG("applying InitialConfigValue %d for %s\n",
+ dev->initial_config_value, dev->device_id);
+ }
+
+ if(!NT_SUCCESS(set_configuration(dev, dev->initial_config_value, LIBUSB_DEFAULT_TIMEOUT)))
+ {
+ // we should always be able to apply the active configuration,
+ // even in the case of composite devices.
+ if (dev->initial_config_value == SET_CONFIG_ACTIVE_CONFIG)
+ {
+ USBERR("failed applying active configuration for %s\n",
+ dev->device_id);
+ }
+ else
+ {
+ USBERR("failed applying InitialConfigValue %d for %s\n",
+ dev->initial_config_value, dev->device_id);
+ }
+ }
+ }
+ }
+#endif
+ dev->is_started = TRUE;
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS DDKAPI
+on_device_usage_notification_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context)
+{
+ libusb_device_t *dev = device_object->DeviceExtension;
+
+ if (irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if (!(dev->next_stack_device->Flags & DO_POWER_PAGABLE))
+ {
+ device_object->Flags &= ~DO_POWER_PAGABLE;
+ }
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS DDKAPI
+on_query_capabilities_complete(DEVICE_OBJECT *device_object,
+ IRP *irp, void *context)
+{
+ libusb_device_t *dev = device_object->DeviceExtension;
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+
+ if (irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if (NT_SUCCESS(irp->IoStatus.Status))
+ {
+ if (!dev->is_filter)
+ {
+ /* apply registry setting */
+ stack_location->Parameters.DeviceCapabilities.Capabilities
+ ->SurpriseRemovalOK = dev->surprise_removal_ok;
+ }
+
+ /* save supported device power states */
+ memcpy(dev->device_power_states, stack_location
+ ->Parameters.DeviceCapabilities.Capabilities->DeviceState,
+ sizeof(dev->device_power_states));
+ }
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
diff --git a/usb/driver/power.c b/usb/driver/power.c
new file mode 100644
index 0000000..d29dd9b
--- /dev/null
+++ b/usb/driver/power.c
@@ -0,0 +1,269 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+static NTSTATUS DDKAPI
+on_power_state_complete(DEVICE_OBJECT *device_object,
+ IRP *irp,
+ void *context);
+
+static NTSTATUS DDKAPI
+on_filter_power_state_complete(DEVICE_OBJECT *device_object,
+ IRP *irp,
+ void *context);
+
+static void DDKAPI
+on_power_set_device_state_complete(DEVICE_OBJECT *device_object,
+ UCHAR minor_function,
+ POWER_STATE power_state,
+ void *context,
+ IO_STATUS_BLOCK *io_status);
+
+/* [trobinso MOD 4/16/2010]
+ * If running as a filter, do not act as power policy owner.
+ */
+NTSTATUS dispatch_power(libusb_device_t *dev, IRP *irp)
+{
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+ POWER_STATE power_state;
+ NTSTATUS status;
+
+ status = remove_lock_acquire(dev);
+
+ if (!NT_SUCCESS(status))
+ {
+ irp->IoStatus.Status = status;
+ PoStartNextPowerIrp(irp);
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+ return status;
+ }
+
+ if (stack_location->MinorFunction == IRP_MN_SET_POWER)
+ {
+ power_state = stack_location->Parameters.Power.State;
+
+ if (stack_location->Parameters.Power.Type == SystemPowerState)
+ {
+ USBMSG("IRP_MN_SET_POWER: S%d %s\n",
+ power_state.SystemState - PowerSystemWorking, dev->device_id);
+ }
+ else
+ {
+ USBMSG("IRP_MN_SET_POWER: D%d %s\n",
+ power_state.DeviceState - PowerDeviceD0, dev->device_id);
+
+ if (power_state.DeviceState > dev->power_state.DeviceState)
+ {
+ /* device is powered down, report device state to the */
+ /* Power Manager before sending the IRP down */
+ /* (power up is handled by the completion routine) */
+ PoSetPowerState(dev->self, DevicePowerState, power_state);
+ }
+ }
+
+ /* TODO: should PoStartNextPowerIrp() be called here or from the */
+ /* completion routine? */
+ PoStartNextPowerIrp(irp);
+
+ IoCopyCurrentIrpStackLocationToNext(irp);
+ if (!dev->is_filter && !dev->disallow_power_control)
+ {
+ IoSetCompletionRoutine(irp,
+ on_power_state_complete,
+ dev,
+ TRUE, /* on success */
+ TRUE, /* on error */
+ TRUE);/* on cancel */
+ }
+ else
+ {
+ IoSetCompletionRoutine(irp,
+ on_filter_power_state_complete,
+ dev,
+ TRUE, /* on success */
+ TRUE, /* on error */
+ TRUE);/* on cancel */
+ }
+
+ return PoCallDriver(dev->next_stack_device, irp);
+ }
+ else
+ {
+ /* pass all other power IRPs down without setting a completion routine */
+ PoStartNextPowerIrp(irp);
+ IoSkipCurrentIrpStackLocation(irp);
+ status = PoCallDriver(dev->next_stack_device, irp);
+ remove_lock_release(dev);
+
+ return status;
+ }
+}
+
+
+static NTSTATUS DDKAPI
+on_power_state_complete(DEVICE_OBJECT *device_object,
+ IRP *irp,
+ void *context)
+{
+ libusb_device_t *dev = context;
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+ POWER_STATE power_state = stack_location->Parameters.Power.State;
+ DEVICE_POWER_STATE dev_power_state;
+
+ if (irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if (NT_SUCCESS(irp->IoStatus.Status))
+ {
+ if (stack_location->Parameters.Power.Type == SystemPowerState)
+ {
+ USBMSG("S%d %s\n",
+ power_state.SystemState - PowerSystemWorking, dev->device_id);
+
+ /* save current system state */
+ dev->power_state.SystemState = power_state.SystemState;
+
+ /* get supported device power state from the array reported by */
+ /* IRP_MN_QUERY_CAPABILITIES */
+ dev_power_state = dev->device_power_states[power_state.SystemState];
+
+ /* set the device power state, but don't block the thread */
+ power_set_device_state(dev, dev_power_state, FALSE);
+ }
+ else /* DevicePowerState */
+ {
+ USBMSG("D%d %s\n",
+ power_state.DeviceState - PowerDeviceD0, dev->device_id);
+
+ if (power_state.DeviceState <= dev->power_state.DeviceState)
+ {
+ /* device is powered up, */
+ /* report device state to Power Manager */
+ PoSetPowerState(dev->self, DevicePowerState, power_state);
+ }
+ /* save current device state */
+ dev->power_state.DeviceState = power_state.DeviceState;
+ }
+ }
+ else
+ {
+ USBMSG0("failed\n");
+ }
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS DDKAPI
+on_filter_power_state_complete(DEVICE_OBJECT *device_object,
+ IRP *irp,
+ void *context)
+{
+ libusb_device_t *dev = context;
+ IO_STACK_LOCATION *stack_location = IoGetCurrentIrpStackLocation(irp);
+ POWER_STATE power_state = stack_location->Parameters.Power.State;
+
+ if (NT_SUCCESS(irp->IoStatus.Status))
+ {
+ if (stack_location->Parameters.Power.Type == SystemPowerState)
+ {
+ USBMSG("S%d\n",
+ power_state.SystemState - PowerSystemWorking);
+
+ /* save current system state */
+ dev->power_state.SystemState = power_state.SystemState;
+
+
+ }
+ else /* DevicePowerState */
+ {
+ USBMSG("D%d\n",
+ power_state.DeviceState - PowerDeviceD0);
+
+ if (power_state.DeviceState <= dev->power_state.DeviceState)
+ {
+ /* device is powered up, */
+ /* report device state to Power Manager */
+ PoSetPowerState(dev->self, DevicePowerState, power_state);
+ }
+
+ /* save current device state */
+ dev->power_state.DeviceState = power_state.DeviceState;
+ }
+ }
+ else
+ {
+ USBMSG0("failed\n");
+ }
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+static void DDKAPI
+on_power_set_device_state_complete(DEVICE_OBJECT *device_object,
+ UCHAR minor_function,
+ POWER_STATE power_state,
+ void *context,
+ IO_STATUS_BLOCK *io_status)
+{
+ KeSetEvent((KEVENT *)context, EVENT_INCREMENT, FALSE);
+}
+
+
+void power_set_device_state(libusb_device_t *dev,
+ DEVICE_POWER_STATE device_state, bool_t block)
+{
+ NTSTATUS status;
+ KEVENT event;
+ POWER_STATE power_state;
+
+ power_state.DeviceState = device_state;
+
+ USBMSG("setting device power state to D%d %s\n",
+ power_state.DeviceState - PowerDeviceD0, dev->device_id);
+
+ if (block) /* wait for IRP to complete */
+ {
+ KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+ /* set the device power state and wait for completion */
+ status = PoRequestPowerIrp(dev->physical_device_object,
+ IRP_MN_SET_POWER,
+ power_state,
+ on_power_set_device_state_complete,
+ &event, NULL);
+
+ if (status == STATUS_PENDING)
+ {
+ KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+ }
+ }
+ else
+ {
+ PoRequestPowerIrp(dev->physical_device_object, IRP_MN_SET_POWER,
+ power_state, NULL, NULL, NULL);
+ }
+}
diff --git a/usb/driver/release_interface.c b/usb/driver/release_interface.c
new file mode 100644
index 0000000..bcd483c
--- /dev/null
+++ b/usb/driver/release_interface.c
@@ -0,0 +1,105 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS release_interface(libusb_device_t *dev, FILE_OBJECT *file_object,
+ int interface)
+{
+ USBMSG("interface %d\n", interface);
+
+ if (!dev->config.value)
+ {
+ USBERR0("device is not configured\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ if (interface >= LIBUSB_MAX_NUMBER_OF_INTERFACES)
+ {
+ USBERR("interface number %d too high\n",
+ interface);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!dev->config.interfaces[interface].valid)
+ {
+ USBERR("invalid interface %02d\n", interface);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (!dev->config.interfaces[interface].file_object)
+ {
+ USBERR("could not release interface %d, interface is not claimed\n", interface);
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ if (dev->config.interfaces[interface].file_object != file_object)
+ {
+ USBERR("could not release interface %d, interface is not bound to this file object\n", interface);
+ return STATUS_DEVICE_BUSY;
+ }
+
+ dev->config.interfaces[interface].file_object = NULL;
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS release_interface_ex(libusb_device_t *dev,
+ FILE_OBJECT *file_object,
+ interface_request_t* interface_request)
+{
+ PUSB_INTERFACE_DESCRIPTOR interface_descriptor;
+
+ USBMSG("interface-%s=%d\n",
+ interface_request->intf_use_index ? "index" : "number",
+ interface_request->intf_use_index ? interface_request->interface_index : interface_request->interface_number);
+
+ if (!dev->config.value || !dev->config.descriptor)
+ {
+ USBERR0("device is not configured\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ interface_request->altsetting_index=FIND_INTERFACE_INDEX_ANY;
+ interface_descriptor = find_interface_desc_ex(dev->config.descriptor,dev->config.total_size,interface_request,NULL);
+ if (!interface_descriptor)
+ {
+ return STATUS_NO_MORE_ENTRIES;
+ }
+ return release_interface(dev, file_object, interface_descriptor->bInterfaceNumber);
+}
+
+NTSTATUS release_all_interfaces(libusb_device_t *dev, FILE_OBJECT *file_object)
+{
+ int i;
+
+ USBMSG("releasing all interfaces bound to file object 0x%x\n", file_object);
+
+ for (i = 0; i < LIBUSB_MAX_NUMBER_OF_INTERFACES; i++)
+ {
+ if (dev->config.interfaces[i].file_object == file_object)
+ {
+ dev->config.interfaces[i].file_object = NULL;
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
diff --git a/usb/driver/reset_device.c b/usb/driver/reset_device.c
new file mode 100644
index 0000000..a0fd97b
--- /dev/null
+++ b/usb/driver/reset_device.c
@@ -0,0 +1,56 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS reset_device(libusb_device_t *dev, int timeout)
+{
+ return reset_device_ex(dev, timeout, USB_RESET_TYPE_FULL_RESET);
+}
+
+NTSTATUS reset_device_ex(libusb_device_t *dev, int timeout, unsigned int reset_type)
+{
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+ USBMSG0("resetting device\n");
+
+ if (reset_type & USB_RESET_TYPE_RESET_PORT)
+ {
+ status = call_usbd(dev, NULL, IOCTL_INTERNAL_USB_RESET_PORT, timeout);
+
+ if (!NT_SUCCESS(status))
+ {
+ USBERR("IOCTL_INTERNAL_USB_RESET_PORT failed: status: 0x%x\n", status);
+ }
+ }
+
+ if (reset_type & USB_RESET_TYPE_CYCLE_PORT)
+ {
+ status = call_usbd(dev, NULL, IOCTL_INTERNAL_USB_CYCLE_PORT, timeout);
+
+ if (!NT_SUCCESS(status))
+ {
+ USBERR("IOCTL_INTERNAL_USB_CYCLE_PORT failed: status: 0x%x\n", status);
+ }
+ }
+
+ UpdateContextConfigDescriptor(dev, NULL, 0, 0, -1);
+ return status;
+}
diff --git a/usb/driver/reset_endpoint.c b/usb/driver/reset_endpoint.c
new file mode 100644
index 0000000..3396b93
--- /dev/null
+++ b/usb/driver/reset_endpoint.c
@@ -0,0 +1,56 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS reset_endpoint(libusb_device_t *dev, int endpoint, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ USBMSG("endpoint: 0x%02x timeout: %d\n", endpoint, timeout);
+
+ if (!dev->config.value)
+ {
+ USBERR0("invalid configuration 0\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ memset(&urb, 0, sizeof(struct _URB_PIPE_REQUEST));
+
+ urb.UrbHeader.Length = (USHORT) sizeof(struct _URB_PIPE_REQUEST);
+ urb.UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
+
+ if (!get_pipe_handle(dev, endpoint, &urb.UrbPipeRequest.PipeHandle))
+ {
+ USBERR0("getting endpoint pipe failed\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("request failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ }
+
+ return status;
+}
diff --git a/usb/driver/set_configuration.c b/usb/driver/set_configuration.c
new file mode 100644
index 0000000..9f2fac1
--- /dev/null
+++ b/usb/driver/set_configuration.c
@@ -0,0 +1,205 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+#include <stdlib.h>
+
+
+NTSTATUS set_configuration(libusb_device_t *dev,
+ int configuration,
+ int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb, *urb_ptr = NULL;
+ USB_CONFIGURATION_DESCRIPTOR *configuration_descriptor = NULL;
+ USB_INTERFACE_DESCRIPTOR *interface_descriptor = NULL;
+ USBD_INTERFACE_LIST_ENTRY *interfaces = NULL;
+ int i, j, interface_number, desc_size, config_index, ret;
+
+ // check if this config value is already set
+ if ((configuration > 0) && dev->config.value == configuration)
+ {
+ return STATUS_SUCCESS;
+ }
+
+ // check if this config index is already set
+ if ((configuration < 0) && dev->config.value && dev->config.index == (abs(configuration)-1))
+ {
+ return STATUS_SUCCESS;
+ }
+
+ memset(&urb, 0, sizeof(URB));
+
+ if (configuration == 0)
+ {
+ urb.UrbHeader.Function = URB_FUNCTION_SELECT_CONFIGURATION;
+ urb.UrbHeader.Length = sizeof(struct _URB_SELECT_CONFIGURATION);
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("setting configuration %d failed: status: 0x%x, urb-status: 0x%x\n",
+ configuration, status, urb.UrbHeader.Status);
+ return status;
+ }
+
+ dev->config.handle = urb.UrbSelectConfiguration.ConfigurationHandle;
+ dev->config.value = 0;
+
+ clear_pipe_info(dev);
+
+ return status;
+ }
+
+ if (configuration <= SET_CONFIG_ACTIVE_CONFIG)
+ {
+ // note: as of v1.2.4.0, the active/default configuration is
+ // always the first configuration the device returns. (index 0)
+ configuration=-1;
+ }
+
+ USBMSG("setting configuration %s %d timeout=%d",
+ (configuration < 0) ? "index" : "value",
+ (configuration < 0) ? abs(configuration) - 1 : configuration,
+ timeout);
+
+
+ // If configuration is negative, it is retrieved by index.
+ //
+ configuration_descriptor = get_config_descriptor(dev, configuration,
+ &desc_size, &config_index);
+ if (!configuration_descriptor)
+ {
+ USBERR0("getting configuration descriptor failed");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ // if we passed an index in we can check here to see
+ // if the device is already configured with this value
+ if (dev->config.value == configuration_descriptor->bConfigurationValue)
+ {
+ UpdateContextConfigDescriptor(
+ dev,
+ configuration_descriptor,
+ desc_size,
+ configuration_descriptor->bConfigurationValue,
+ config_index);
+
+ status = STATUS_SUCCESS;
+ goto SetConfigurationDone;
+ }
+
+ // MEMORY ALLOCATION BEGINS
+ interfaces =
+ ExAllocatePool(NonPagedPool,(configuration_descriptor->bNumInterfaces + 1)
+ * sizeof(USBD_INTERFACE_LIST_ENTRY));
+
+ if (!interfaces)
+ {
+ USBERR0("memory allocation failed\n");
+ status = STATUS_NO_MEMORY;
+ ExFreePool(configuration_descriptor);
+ goto SetConfigurationDone;
+ }
+
+ memset(interfaces, 0, (configuration_descriptor->bNumInterfaces + 1)
+ * sizeof(USBD_INTERFACE_LIST_ENTRY));
+
+ interface_number = 0;
+
+ for (i = 0; i < configuration_descriptor->bNumInterfaces; i++)
+ {
+ for (j = interface_number; j < LIBUSB_MAX_NUMBER_OF_INTERFACES; j++)
+ {
+ interface_descriptor =
+ find_interface_desc(configuration_descriptor, desc_size, j, 0);
+ if (interface_descriptor)
+ {
+ interface_number = ++j;
+ break;
+ }
+ }
+
+ if (!interface_descriptor)
+ {
+ USBERR("unable to find interface descriptor at index %d\n", i);
+ status = STATUS_INVALID_PARAMETER;
+ ExFreePool(configuration_descriptor);
+ goto SetConfigurationDone;
+ }
+ else
+ {
+ USBMSG("found interface %d\n",
+ interface_descriptor->bInterfaceNumber);
+ interfaces[i].InterfaceDescriptor = interface_descriptor;
+ }
+ }
+
+ urb_ptr = USBD_CreateConfigurationRequestEx(configuration_descriptor, interfaces);
+ if (!urb_ptr)
+ {
+ USBERR0("memory allocation failed\n");
+ status = STATUS_NO_MEMORY;
+ ExFreePool(configuration_descriptor);
+ goto SetConfigurationDone;
+ }
+
+ for (i = 0; i < configuration_descriptor->bNumInterfaces; i++)
+ {
+ for (j = 0; j < (int)interfaces[i].Interface->NumberOfPipes; j++)
+ {
+ interfaces[i].Interface->Pipes[j].MaximumTransferSize = LIBUSB_MAX_READ_WRITE;
+ }
+ }
+
+ USBDBG("#%d %s passing configuration request to target-device.",
+ dev->id, dev->device_id);
+
+ status = call_usbd(dev, urb_ptr, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb_ptr->UrbHeader.Status))
+ {
+ USBERR("setting configuration %d failed: status: 0x%x, urb-status: 0x%x\n",
+ configuration, status, urb_ptr->UrbHeader.Status);
+ if (NT_SUCCESS(status)) status = urb_ptr->UrbHeader.Status;
+
+ ExFreePool(configuration_descriptor);
+ goto SetConfigurationDone;
+ }
+
+ dev->config.handle = urb_ptr->UrbSelectConfiguration.ConfigurationHandle;
+
+ clear_pipe_info(dev);
+
+ for (i = 0; i < configuration_descriptor->bNumInterfaces; i++)
+ {
+ update_pipe_info(dev, interfaces[i].Interface);
+ }
+ UpdateContextConfigDescriptor(dev, configuration_descriptor, desc_size, configuration_descriptor->bConfigurationValue, config_index);
+
+SetConfigurationDone:
+ if (interfaces)
+ ExFreePool(interfaces);
+
+ if (urb_ptr)
+ ExFreePool(urb_ptr);
+
+ return status;
+}
diff --git a/usb/driver/set_descriptor.c b/usb/driver/set_descriptor.c
new file mode 100644
index 0000000..46bbad7
--- /dev/null
+++ b/usb/driver/set_descriptor.c
@@ -0,0 +1,71 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS set_descriptor(libusb_device_t *dev,
+ void *buffer, int size, int type, int recipient,
+ int index, int language_id, int *sent, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ USBMSG("buffer size: %d type: %04d recipient: %04d index: %04d language id: %04d timeout: %d\n",
+ size,type,recipient,index,language_id,timeout);
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
+
+
+ switch (recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT;
+ break;
+ default:
+ USBERR0("invalid recipient\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
+ urb.UrbControlDescriptorRequest.TransferBufferLength = size;
+ urb.UrbControlDescriptorRequest.TransferBuffer = buffer;
+ urb.UrbControlDescriptorRequest.DescriptorType = (UCHAR)type;
+ urb.UrbControlDescriptorRequest.Index = (UCHAR)index;
+ urb.UrbControlDescriptorRequest.LanguageId = (USHORT)language_id;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("setting descriptor failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ }
+ else
+ {
+ *sent = urb.UrbControlDescriptorRequest.TransferBufferLength;
+ }
+ return status;
+}
diff --git a/usb/driver/set_feature.c b/usb/driver/set_feature.c
new file mode 100644
index 0000000..12e7745
--- /dev/null
+++ b/usb/driver/set_feature.c
@@ -0,0 +1,67 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+
+NTSTATUS set_feature(libusb_device_t *dev, int recipient, int index,
+ int feature, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ USBMSG("recipient: %02d index: %04d feature %04d timeout: %d\n",
+ recipient,index,feature,timeout);
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_FEATURE_REQUEST));
+
+ switch (recipient)
+ {
+ case USB_RECIP_DEVICE:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ urb.UrbHeader.Function = URB_FUNCTION_SET_FEATURE_TO_OTHER;
+ urb.UrbControlFeatureRequest.Index = 0;
+ break;
+ default:
+ USBERR0("invalid recipient\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_FEATURE_REQUEST);
+ urb.UrbControlFeatureRequest.FeatureSelector = (USHORT)feature;
+ urb.UrbControlFeatureRequest.Index = (USHORT)index;
+
+ status = call_usbd(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("setting feature failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ }
+
+ return status;
+}
diff --git a/usb/driver/set_interface.c b/usb/driver/set_interface.c
new file mode 100644
index 0000000..840600e
--- /dev/null
+++ b/usb/driver/set_interface.c
@@ -0,0 +1,124 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS set_interface(libusb_device_t *dev,
+ int interface_number,
+ int alt_interface_number,
+ int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB *urb;
+ int i, tmp_size;
+
+ USB_INTERFACE_DESCRIPTOR *interface_descriptor = NULL;
+ USBD_INTERFACE_INFORMATION *interface_information = NULL;
+
+
+ USBMSG("interface-number=%d alt-number=%d timeout=%d\n",
+ interface_number,alt_interface_number,timeout);
+
+ if (!dev->config.value || !dev->config.descriptor)
+ {
+ USBERR0("device is not configured\n");
+ return STATUS_INVALID_DEVICE_STATE;
+ }
+
+ interface_descriptor = find_interface_desc(dev->config.descriptor, dev->config.total_size, interface_number, alt_interface_number);
+
+ if (!interface_descriptor)
+ {
+ USBERR("interface-number=%d alt-number=%d does not exists.\n",
+ interface_number,alt_interface_number,timeout);
+
+ return STATUS_NO_MORE_ENTRIES;
+ }
+
+ tmp_size = sizeof(struct _URB_SELECT_INTERFACE) + interface_descriptor->bNumEndpoints * sizeof(USBD_PIPE_INFORMATION);
+
+ urb = ExAllocatePool(NonPagedPool, tmp_size);
+
+ if (!urb)
+ {
+ USBERR0("memory_allocation error\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ memset(urb, 0, tmp_size);
+
+ urb->UrbHeader.Function = URB_FUNCTION_SELECT_INTERFACE;
+ urb->UrbHeader.Length = (USHORT)tmp_size;
+
+ urb->UrbSelectInterface.ConfigurationHandle = dev->config.handle;
+ urb->UrbSelectInterface.Interface.Length = sizeof(struct _USBD_INTERFACE_INFORMATION);
+ urb->UrbSelectInterface.Interface.NumberOfPipes = interface_descriptor->bNumEndpoints;
+ urb->UrbSelectInterface.Interface.Length += interface_descriptor->bNumEndpoints * sizeof(struct _USBD_PIPE_INFORMATION);
+
+ urb->UrbSelectInterface.Interface.InterfaceNumber = (UCHAR)interface_descriptor->bInterfaceNumber;
+ urb->UrbSelectInterface.Interface.AlternateSetting = (UCHAR)interface_descriptor->bAlternateSetting;
+
+ interface_information = &urb->UrbSelectInterface.Interface;
+
+ for (i = 0; i < interface_descriptor->bNumEndpoints; i++)
+ {
+ interface_information->Pipes[i].MaximumTransferSize = LIBUSB_MAX_READ_WRITE;
+ }
+
+ status = call_usbd(dev, urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout);
+
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb->UrbHeader.Status))
+ {
+ USBERR("setting interface failed: status: 0x%x, urb-status: 0x%x\n", status, urb->UrbHeader.Status);
+ ExFreePool(urb);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ update_pipe_info(dev, interface_information);
+
+ ExFreePool(urb);
+
+ return status;
+}
+
+NTSTATUS set_interface_ex(libusb_device_t *dev,
+ interface_request_t* interface_request,
+ int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ USB_INTERFACE_DESCRIPTOR *interface_descriptor = NULL;
+
+ USBMSG("interface-%s=%d alt-%s=%d timeout=%d\n",
+ interface_request->intf_use_index ? "index" : "number",
+ interface_request->intf_use_index ? interface_request->interface_index : interface_request->interface_number,
+ interface_request->altf_use_index ? "index" : "number",
+ interface_request->altf_use_index ? interface_request->altsetting_index : interface_request->altsetting_number,
+ timeout);
+
+ interface_descriptor = find_interface_desc_ex(dev->config.descriptor,dev->config.total_size,interface_request,NULL);
+ if (!interface_descriptor)
+ {
+ return STATUS_NO_MORE_ENTRIES;
+ }
+
+ return set_interface(dev,interface_descriptor->bInterfaceNumber, interface_descriptor->bAlternateSetting, timeout);
+}
diff --git a/usb/driver/transfer.c b/usb/driver/transfer.c
new file mode 100644
index 0000000..0a02aa1
--- /dev/null
+++ b/usb/driver/transfer.c
@@ -0,0 +1,1493 @@
+/* libusb-win32, Generic Windows USB Library
+* Copyright (c) 2010 Travis Robinson <libusbdotnet@gmail.com>
+* Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include "libusb_driver.h"
+
+typedef struct
+{
+ URB *urb;
+ int sequence;
+} context_t;
+
+static LONG sequence = 0;
+
+static const char* read_pipe_display_names[] = {"ctrl-read", "iso-read", "bulk-read", "int-read"};
+static const char* write_pipe_display_names[] = {"ctrl-write","iso-write","bulk-write","int-write"};
+
+
+typedef struct _MAIN_REQUEST_CONTEXT
+{
+ // List of all sub requests (SUB_REQUEST_CONTEXT structures) that
+ // are allocated to handle the original main request irp.
+ //
+ LIST_ENTRY SubRequestList;
+ LONG sequenceID;
+ const char* dispTransfer;
+} MAIN_REQUEST_CONTEXT, *PMAIN_REQUEST_CONTEXT;
+
+// The MAIN_REQUEST_CONTEXT structure is overlaid on top of the main
+// request irp Tail.Overlay.DriverContext structure instead of being
+// allocated separately. Make sure it fits!
+//
+C_ASSERT(sizeof(MAIN_REQUEST_CONTEXT) <= sizeof(((PIRP)0)->Tail.Overlay.DriverContext));
+
+typedef struct _SUB_REQUEST_CONTEXT
+{
+ // Main request irp that caused this sub request to be allocated.
+ //
+ PIRP MainIrp;
+
+ // List entry that links this sub request into the main request irp
+ // context SubRequestList. The sub request will be inserted into
+ // the list as long as the sub request is outstanding. The sub
+ // request is only removed from the list by the sub request
+ // completion routine.
+ //
+ LIST_ENTRY ListEntry;
+
+ // List entry that is used only by the main request irp cancel
+ // routine to build a list of all currently outstanding sub
+ // requests in order to cancel them.
+ //
+ LIST_ENTRY CancelListEntry;
+
+ // Reference count incremented (set to one) before calling the sub
+ // request down the driver stack, decremented by the sub request
+ // completion routine, and incremented/decremented by the main
+ // request irp cancl routine. This is used to prevent the sub
+ // request from being freed by either the sub request completion
+ // routine or the main request irp cancel routine while the sub
+ // request is simultaneously being accessed by the other routine.
+ // The sub request is freed by the routine that last accesses the
+ // sub request and decrements the reference count to zero.
+ //
+ LONG ReferenceCount;
+
+ // irp, Urb, and Mdl allocated to send the sub request down the
+ // driver stack.
+ //
+ PIRP SubIrp;
+ PURB SubUrb;
+ PMDL SubMdl;
+
+ ULONG startOffset;
+
+} SUB_REQUEST_CONTEXT, *PSUB_REQUEST_CONTEXT;
+
+static const char* GetPipeDisplayName(libusb_endpoint_t* endpoint);
+
+NTSTATUS DDKAPI transfer_complete(DEVICE_OBJECT* device_object,
+ IRP *irp,
+ void *context);
+
+static NTSTATUS create_urb(libusb_device_t *dev,
+ URB **urb,
+ int direction,
+ int urbFunction,
+ libusb_endpoint_t* endpoint,
+ int packetSize,
+ MDL *buffer,
+ int size);
+
+VOID large_transfer_cancel_routine(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp);
+VOID large_transfer_cancel(IN PIRP irp, BOOLEAN releaseCancelSpinlock);
+
+NTSTATUS large_transfer_complete(IN PDEVICE_OBJECT DeviceObjectIsNULL,
+ IN PIRP irp,
+ IN PVOID Context);
+
+static int get_iso_stagesize(int totalLength, int packetSize, int maxTransferSize);
+
+static NTSTATUS allocate_suburb(USHORT urbFunction,
+ int stageSize,
+ int packetSize,
+ ULONG* nPackets,
+ PURB* subUrbRef);
+
+void set_urb_transfer_flags(libusb_device_t* dev,
+ PIRP irp,
+ PURB subUrb,
+ int transfer_flags,
+ int isoLatency);
+
+NTSTATUS transfer(libusb_device_t* dev,
+ IN PIRP irp,
+ IN int direction,
+ IN int urbFunction,
+ IN libusb_endpoint_t* endpoint,
+ IN int packetSize,
+ IN int transferFlags,
+ IN int isoLatency,
+ IN PMDL mdlAddress,
+ IN int totalLength)
+{
+ IO_STACK_LOCATION *stack_location = NULL;
+ context_t *context;
+ NTSTATUS status = STATUS_SUCCESS;
+ int sequenceID = InterlockedIncrement(&sequence);
+ const char* dispTransfer = GetPipeDisplayName(endpoint);
+
+ // TODO: reset pipe flag
+ // status = reset_endpoint(dev,endpoint->address, LIBUSB_DEFAULT_TIMEOUT);
+ //
+ if (!packetSize)
+ packetSize = endpoint->maximum_packet_size;
+
+ if (urbFunction == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ USBMSG("[%s #%d] EP%02Xh packet-size=%d length=%d reset-status=%08Xh\n",
+ dispTransfer, sequenceID, endpoint->address, packetSize, totalLength, status);
+ }
+ else
+ {
+ USBMSG("[%s #%d] EP%02Xh length %d\n",
+ dispTransfer, sequenceID, endpoint->address, totalLength);
+ }
+ context = ExAllocatePool(NonPagedPool, sizeof(context_t));
+
+ if (!context)
+ {
+ remove_lock_release(dev);
+ return complete_irp(irp, STATUS_NO_MEMORY, 0);
+ }
+
+ status = create_urb(dev, &context->urb, direction, urbFunction,
+ endpoint, packetSize, mdlAddress, totalLength);
+
+ if (!NT_SUCCESS(status))
+ {
+ ExFreePool(context);
+ remove_lock_release(dev);
+ return complete_irp(irp, status, 0);
+ }
+
+
+ context->sequence = sequenceID;
+
+ stack_location = IoGetNextIrpStackLocation(irp);
+
+ stack_location->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+ stack_location->Parameters.Others.Argument1 = context->urb;
+ stack_location->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(irp, transfer_complete, context, TRUE, TRUE, TRUE);
+
+ // Set the transfer flags just before we call the irp down.
+ // If this is an iso transfer, set_urb_transfer_flags() might need
+ // to get the start frame and set latency.
+ //
+ set_urb_transfer_flags(dev, irp, context->urb, transferFlags, isoLatency);
+
+ return IoCallDriver(dev->target_device, irp);
+}
+
+
+NTSTATUS DDKAPI transfer_complete(DEVICE_OBJECT *device_object, IRP *irp,
+ void *context)
+{
+ context_t *c = (context_t *)context;
+ int transmitted = 0;
+ libusb_device_t *dev = device_object->DeviceExtension;
+
+ if (irp->PendingReturned)
+ {
+ IoMarkIrpPending(irp);
+ }
+
+ if (NT_SUCCESS(irp->IoStatus.Status)
+ && USBD_SUCCESS(c->urb->UrbHeader.Status))
+ {
+ if (c->urb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ transmitted = c->urb->UrbIsochronousTransfer.TransferBufferLength;
+ }
+ if (c->urb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER)
+ {
+ transmitted
+ = c->urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+ }
+
+ USBMSG("sequence %d: %d bytes transmitted\n",
+ c->sequence, transmitted);
+ }
+ else
+ {
+ if (irp->IoStatus.Status == STATUS_CANCELLED)
+ {
+ USBERR("sequence %d: timeout error\n",
+ c->sequence);
+ }
+ else
+ {
+ USBERR("sequence %d: transfer failed: status: 0x%x, urb-status: 0x%x\n",
+ c->sequence, irp->IoStatus.Status,
+ c->urb->UrbHeader.Status);
+ }
+ }
+
+ ExFreePool(c->urb);
+ ExFreePool(c);
+
+ irp->IoStatus.Information = transmitted;
+
+ remove_lock_release(dev);
+
+ return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS create_urb(libusb_device_t *dev, URB **urb, int direction,
+ int urbFunction, libusb_endpoint_t* endpoint, int packetSize,
+ MDL *buffer, int size)
+{
+ USBD_PIPE_HANDLE pipe_handle = NULL;
+ int num_packets = 0;
+ int i, urb_size;
+
+ *urb = NULL;
+
+ pipe_handle = endpoint->handle;
+
+ /* isochronous transfer */
+ if (urbFunction == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ if (packetSize <= 0)
+ {
+ USBERR("invalid packet size=%d\n", packetSize);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ num_packets = size / packetSize;
+
+ if (num_packets <= 0)
+ {
+ USBERR("invalid number of packets=%d\n",
+ num_packets);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ if (num_packets > 255)
+ {
+ USBERR0("transfer size too large\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ urb_size = sizeof(struct _URB_ISOCH_TRANSFER)
+ + sizeof(USBD_ISO_PACKET_DESCRIPTOR) * num_packets;
+ }
+ else /* bulk or interrupt transfer */
+ {
+ urb_size = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
+ }
+
+ *urb = ExAllocatePool(NonPagedPool, urb_size);
+
+ if (!*urb)
+ {
+ USBERR0("memory allocation error\n");
+ return STATUS_NO_MEMORY;
+ }
+
+ memset(*urb, 0, urb_size);
+
+ (*urb)->UrbHeader.Length = (USHORT)urb_size;
+ (*urb)->UrbHeader.Function = (USHORT)urbFunction;
+
+ /* isochronous transfer */
+ if (urbFunction == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ (*urb)->UrbIsochronousTransfer.PipeHandle = pipe_handle;
+ (*urb)->UrbIsochronousTransfer.TransferFlags = direction;
+ (*urb)->UrbIsochronousTransfer.TransferBufferLength = size;
+ (*urb)->UrbIsochronousTransfer.TransferBufferMDL = buffer;
+ (*urb)->UrbIsochronousTransfer.NumberOfPackets = num_packets;
+
+ for (i = 0; i < num_packets; i++)
+ {
+ (*urb)->UrbIsochronousTransfer.IsoPacket[i].Offset = i * packetSize;
+ (*urb)->UrbIsochronousTransfer.IsoPacket[i].Length = packetSize;
+ }
+ }
+ /* bulk or interrupt transfer */
+ else
+ {
+ (*urb)->UrbBulkOrInterruptTransfer.PipeHandle = pipe_handle;
+ (*urb)->UrbBulkOrInterruptTransfer.TransferFlags = direction;
+ (*urb)->UrbBulkOrInterruptTransfer.TransferBufferLength = size;
+ (*urb)->UrbBulkOrInterruptTransfer.TransferBufferMDL = buffer;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/*-----------------------------------------------------------------------------
+Routine Description:
+This routine splits up a main transfer request into one or more sub
+requests as necessary.
+
+[ISOCHRONOUS TRANSFERS]
+Each isoch irp/urb pair can span at most 255 packets.
+Each isoch irp/urb pair can request at the most 65536 bytes.
+
+[BULK OR INTERRUPT TRANSFERS]
+Each bulk/interrupt irp/urb pair can request at the most 65536 bytes.
+
+1. It creates a SUB_REQUEST_CONTEXT for each irp/urb pair and
+attaches it to the main request irp.
+
+2. It intializes all of the sub request irp/urb pairs, and sub mdls
+too.
+
+3. It passes down the driver stack all of the sub request irps.
+
+4. It leaves the completion of the main request irp as the
+responsibility of the sub request irp completion routine, except
+in the exception case where the main request irp is canceled
+prior to passing any of the the sub request irps down the driver
+stack.
+
+Arguments:
+
+dev - pointer to device object
+irp - I/O request packet
+direction - URB I/O direction (IN/OUT)
+urbFunction - urb transfer function
+endpoint - libusb_endpoint_t*
+packetSize - isochronous packet size
+maxTransferSize,
+transferFlags,
+isoLatency -
+mdlAddress - transfer mdl buffer
+totalLength - no. of bytes to be transferred
+
+Return Value:
+
+NT status value
+*/
+NTSTATUS large_transfer(IN libusb_device_t* dev,
+ IN PIRP irp,
+ IN int direction,
+ IN int urbFunction,
+ IN libusb_endpoint_t* endpoint,
+ IN int packetSize,
+ IN int maxTransferSize,
+ IN int transferFlags,
+ IN int isoLatency,
+ IN PMDL mdlAddress,
+ IN int totalLength)
+{
+ PIO_STACK_LOCATION irpStack;
+ BOOLEAN read;
+ ULONG stageSize;
+ ULONG numIrps;
+ PMAIN_REQUEST_CONTEXT mainRequestContext;
+ PSUB_REQUEST_CONTEXT * subRequestContextArray;
+ PSUB_REQUEST_CONTEXT subRequestContext;
+ CCHAR stackSize;
+ PUCHAR virtualAddress;
+ ULONG i;
+ ULONG j;
+ NTSTATUS ntStatus;
+ PIO_STACK_LOCATION nextStack;
+ USBD_PIPE_HANDLE pipeHandle;
+
+ LONG sequenceID;
+ const char* dispTransfer;
+ int startOffset;
+
+ // TODO: reset pipe flag
+ // if (urbFunction != URB_FUNCTION_ISOCH_TRANSFER && pipe_flags & RESET)
+ // status = reset_endpoint(dev,endpoint->address, LIBUSB_DEFAULT_TIMEOUT);
+ //
+ //reset the pipe (if irps are pending this will fail)
+ //
+ //if (urbFunction == URB_FUNCTION_ISOCH_TRANSFER)
+ // reset_endpoint(dev,endpoint->address,LIBUSB_DEFAULT_TIMEOUT);
+
+ //
+ // initialize vars
+ //
+ irpStack = IoGetCurrentIrpStackLocation(irp);
+ sequenceID = InterlockedIncrement(&sequence);
+ subRequestContextArray = NULL;
+
+ if (!maxTransferSize)
+ maxTransferSize = endpoint->maximum_transfer_size;
+
+ if (!packetSize)
+ packetSize = endpoint->maximum_packet_size;
+
+ startOffset = 0;
+
+ read = (direction == USBD_TRANSFER_DIRECTION_IN) ? TRUE : FALSE;
+ dispTransfer = GetPipeDisplayName(endpoint);
+ pipeHandle = endpoint->handle;
+
+ // defaults
+ stageSize = totalLength;
+ numIrps = 1;
+
+ // Full speed ISO note:
+ // There is an inherent limit on the number of packets that can be
+ // passed down the stack with each irp/urb pair (255)
+ //
+ // If the number of required packets is > 255, we shall create
+ // "(required-packets / 255) [+ 1]" number of irp/urb pairs.
+ //
+ // Each irp/urb pair transfer is also called a stage transfer.
+ //
+
+ // TODO: detect and optimize for high speed devices.
+ //
+ if (urbFunction == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ stageSize = get_iso_stagesize(totalLength, packetSize, maxTransferSize);
+ numIrps = (totalLength + stageSize - 1) / stageSize;
+ USBMSG("[%s #%d] EP%02Xh total-size=%d stage-size=%d IRPs=%d packet-size=%d\n",
+ dispTransfer, sequenceID, endpoint->address, totalLength, stageSize, numIrps, packetSize);
+ }
+ else
+ {
+ if (totalLength > (maxTransferSize))
+ stageSize = maxTransferSize;
+ numIrps = (totalLength + stageSize - 1) / stageSize;
+ USBMSG("[%s #%d] EP%02Xh total-size=%d stage-size=%d IRPs=%d\n",
+ dispTransfer, sequenceID, endpoint->address, totalLength, stageSize, numIrps);
+ }
+
+ // Initialize the main request irp read/write context, which is
+ // overlaid on top of irp->Tail.Overlay.DriverContext.
+ //
+ mainRequestContext = (PMAIN_REQUEST_CONTEXT)irp->Tail.Overlay.DriverContext;
+
+ mainRequestContext->dispTransfer = dispTransfer;
+ mainRequestContext->sequenceID = sequenceID;
+
+ InitializeListHead(&mainRequestContext->SubRequestList);
+
+ stackSize = dev->target_device->StackSize;
+
+ virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(mdlAddress);
+ if (!virtualAddress)
+ {
+ USBERR("[%s #%d] MmGetMdlVirtualAddress failed\n",
+ dispTransfer, sequenceID);
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+ goto transfer_Free;
+ }
+
+ // Allocate an array to keep track of the sub requests that will be
+ // allocated below. This array exists only during the execution of
+ // this routine and is used only to keep track of the sub requests
+ // before calling them down the driver stack.
+ //
+ subRequestContextArray = (PSUB_REQUEST_CONTEXT *)
+ ExAllocatePool(NonPagedPool,
+ numIrps * sizeof(PSUB_REQUEST_CONTEXT));
+
+ if (subRequestContextArray == NULL)
+ {
+ USBERR("[%s #%d] failed allocating sub request context array\n",
+ dispTransfer, sequenceID);
+
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ goto transfer_Free;
+ }
+
+ RtlZeroMemory(subRequestContextArray, numIrps * sizeof(PSUB_REQUEST_CONTEXT));
+
+ //
+ // Allocate the sub requests
+ //
+ for (i = 0; i < numIrps; i++)
+ {
+ PIRP subIrp;
+ PURB subUrb;
+ PMDL subMdl;
+ // ULONG urbSize;
+ ULONG offset;
+ ULONG nPackets=0;
+
+ // The following outer scope variables are updated during each
+ // iteration of the loop: virtualAddress, totalLength, stageSize
+
+ //
+ // For every stage of transfer we need to do the following
+ // tasks:
+ //
+ // 1. Allocate a sub request context (SUB_REQUEST_CONTEXT).
+ // 2. Allocate a sub request irp.
+ // 3. Allocate a sub request urb.
+ // 4. Allocate a sub request mdl.
+ // 5. Initialize the above allocations.
+ //
+
+ //
+ // 1. Allocate a Sub Request Context (SUB_REQUEST_CONTEXT)
+ //
+
+ subRequestContext = (PSUB_REQUEST_CONTEXT)
+ ExAllocatePool(NonPagedPool, sizeof(SUB_REQUEST_CONTEXT));
+
+ if (subRequestContext == NULL)
+ {
+ USBERR("[%s #%d] failed allocating sub request context\n",
+ dispTransfer, sequenceID);
+
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ goto transfer_Free;
+ }
+
+ RtlZeroMemory(subRequestContext, sizeof(SUB_REQUEST_CONTEXT));
+
+ // Attach it to the main request irp.
+ //
+ InsertTailList(&mainRequestContext->SubRequestList, &subRequestContext->ListEntry);
+
+ // Remember it independently so we can refer to it later without
+ // walking the sub request list.
+ //
+ subRequestContextArray[i] = subRequestContext;
+
+ // Set the master irp that all the sub-requests originated from.
+ subRequestContext->MainIrp = irp;
+
+ // Remember the start offset
+ subRequestContext->startOffset = startOffset;
+
+ // The reference count on the sub request prevents it from being
+ // freed until the completion routine for the sub request
+ // executes.
+ //
+ subRequestContext->ReferenceCount = 1;
+
+ //
+ // 2. Allocate a sub request irp
+ //
+ subIrp = IoAllocateIrp(stackSize, FALSE);
+
+ if (subIrp == NULL)
+ {
+ USBERR("[%s #%d] failed allocating subIrp\n", dispTransfer, sequenceID);
+
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ goto transfer_Free;
+ }
+
+ subRequestContext->SubIrp = subIrp;
+
+ ntStatus = allocate_suburb((USHORT)urbFunction, stageSize, packetSize, &nPackets, &subUrb);
+ if (!NT_SUCCESS(ntStatus))
+ {
+ USBERR("[%s #%d] failed allocating subUrb\n", dispTransfer, sequenceID);
+ goto transfer_Free;
+ }
+ else
+ {
+ USBDBG("[%s #%d] packets=%d irp-urb = #%d\n",
+ dispTransfer, sequenceID, nPackets, i);
+ }
+
+ subRequestContext->SubUrb = subUrb;
+
+ //
+ // 4. Allocate a sub request mdl.
+ //
+ subMdl = IoAllocateMdl((PVOID) virtualAddress,
+ stageSize,
+ FALSE,
+ FALSE,
+ NULL);
+
+ if (subMdl == NULL)
+ {
+ USBERR("[%s #%d] failed allocating subMdl\n", dispTransfer, sequenceID);
+
+ ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+
+ goto transfer_Free;
+ }
+
+ subRequestContext->SubMdl = subMdl;
+
+ IoBuildPartialMdl(irp->MdlAddress,
+ subMdl,
+ (PVOID)virtualAddress,
+ stageSize);
+
+ // Update loop variables for next iteration.
+ //
+ virtualAddress += stageSize;
+
+ totalLength -= stageSize;
+
+ //
+ // Initialize the sub request urb.
+ //
+ if (urbFunction == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ USBDBG("[%s #%d] stage-size=%d nPackets=%d\n",
+ dispTransfer, sequenceID, stageSize, nPackets);
+
+ subUrb->UrbIsochronousTransfer.PipeHandle = pipeHandle;
+
+ // The direction is set here, other flags are set in the
+ // set_urb_transfer_flags() function.
+ //
+ subUrb->UrbIsochronousTransfer.TransferFlags = direction;
+
+ subUrb->UrbIsochronousTransfer.TransferBufferLength = stageSize;
+ subUrb->UrbIsochronousTransfer.TransferBufferMDL = subMdl;
+
+ //
+ // when the client driver sets the ASAP flag, it basically
+ // guarantees that it will make data available to the HC
+ // and that the HC should transfer it in the next transfer frame
+ // for the endpoint.(The HC maintains a next transfer frame
+ // state variable for each endpoint). By resetting the pipe,
+ // we make the pipe as virgin. If the data does not get to the HC
+ // fast enough, the USBD_ISO_PACKET_DESCRIPTOR - Status is
+ // USBD_STATUS_BAD_START_FRAME on uhci. On ohci it is 0xC000000E.
+ //
+
+ subUrb->UrbIsochronousTransfer.NumberOfPackets = nPackets;
+ //
+ // Set the offsets for every packet for reads/writes
+ //
+ if (read)
+ {
+ offset = 0;
+
+ for (j = 0; j < nPackets; j++)
+ {
+ subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
+
+ if (stageSize > (ULONG)packetSize)
+ {
+ subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
+ offset += packetSize;
+ stageSize -= packetSize;
+ }
+ else
+ {
+ subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = 0;
+ offset += stageSize;
+ stageSize = 0;
+ }
+ }
+ }
+ else
+ {
+ offset = 0;
+
+ for (j = 0; j < nPackets; j++)
+ {
+ subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset = offset;
+
+ if (stageSize > (ULONG)packetSize)
+ {
+ subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = packetSize;
+ offset += packetSize;
+ stageSize -= packetSize;
+ }
+ else
+ {
+ subUrb->UrbIsochronousTransfer.IsoPacket[j].Length = stageSize;
+ offset += stageSize;
+ stageSize = 0;
+ /*
+ ASSERT(offset == (subUrb->UrbIsochronousTransfer.IsoPacket[j].Length +
+ subUrb->UrbIsochronousTransfer.IsoPacket[j].Offset));
+ */
+ }
+ }
+ }
+ }
+ else
+ {
+ USBDBG("[%s #%d] stage-size=%d\n",dispTransfer, sequenceID, stageSize);
+
+ subUrb->UrbBulkOrInterruptTransfer.PipeHandle = pipeHandle;
+
+ subUrb->UrbBulkOrInterruptTransfer.TransferFlags = direction;
+
+ subUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageSize;
+ subUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = subMdl;
+ }
+ // Initialize the sub irp stack location
+ //
+ nextStack = IoGetNextIrpStackLocation(subIrp);
+
+ nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
+
+ nextStack->Parameters.Others.Argument1 = (PVOID) subUrb;
+
+ nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
+
+ IoSetCompletionRoutine(subIrp,
+ (PIO_COMPLETION_ROUTINE)large_transfer_complete,
+ (PVOID)subRequestContext,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ // Update loop variables for next iteration.
+ //
+ if (urbFunction == URB_FUNCTION_ISOCH_TRANSFER)
+ stageSize = get_iso_stagesize(totalLength, packetSize, maxTransferSize);
+ else
+ {
+ if (totalLength > (maxTransferSize))
+ stageSize = maxTransferSize;
+ else
+ stageSize = totalLength;
+ }
+ startOffset += stageSize;
+ }
+
+ //
+ // While we were busy create subsidiary irp/urb pairs..
+ // the main read/write irp may have been cancelled !!
+ //
+
+ if (!irp->Cancel)
+ {
+ //
+ // normal processing
+ //
+
+ USBDBG("[%s #%d] normal processing\n", dispTransfer, sequenceID);
+
+ IoMarkIrpPending(irp);
+
+ // The cancel routine might run simultaneously as soon as it is
+ // set. Do not access the main request irp in any way after
+ // setting the cancel routine.
+ //
+ // Note that it is still safe to access the sub requests up to
+ // the point where each sub request is called down the driver
+ // stack due to the sub request reference count which must be
+ // decremented by the completion routine. Do not access a sub
+ // request in any way after it is called down the driver stack.
+ //
+ // After setting the main request irp cancel routine we are
+ // committed to calling each of the sub requests down the
+ // driver stack.
+ //
+ IoSetCancelRoutine(irp, large_transfer_cancel_routine);
+
+ for (i = 0; i < numIrps; i++)
+ {
+ subRequestContext = subRequestContextArray[i];
+
+ USBDBG("[%s #%d] IoCallDriver subIrp %d\n", dispTransfer, sequenceID, i);
+
+ // Set the transfer flags just before we call the irp down.
+ // If this is an iso transfer, set_urb_transfer_flags() might need
+ // to get the start frame and set latency.
+ //
+ set_urb_transfer_flags(dev,irp, subRequestContext->SubUrb, transferFlags, isoLatency);
+
+ IoCallDriver(dev->target_device, subRequestContext->SubIrp);
+ }
+
+ // The sub requests are freed in either the sub request
+ // completion routine or in the main request irp cancel routine.
+ //
+ // Main request irp is completed only in sub request completion
+ // routine.
+
+ ExFreePool(subRequestContextArray);
+
+ return STATUS_PENDING;
+ }
+ else
+ {
+ //
+ // The Cancel flag for the irp has been set.
+ //
+ USBDBG("[%s #%d] Cancel flag set\n", dispTransfer, sequenceID);
+
+ ntStatus = STATUS_CANCELLED;
+ }
+
+ //
+ // Resource allocation failure, or the main request irp was
+ // cancelled before the cancel routine was set. Free any resource
+ // allocations and complete the main request irp.
+ //
+ // No sub requests were ever called down the driver stack in this
+ // case.
+ //
+
+transfer_Free:
+
+ if (subRequestContextArray != NULL)
+ {
+ for (i = 0; i < numIrps; i++)
+ {
+ subRequestContext = subRequestContextArray[i];
+
+ if (subRequestContext != NULL)
+ {
+ if (subRequestContext->SubIrp != NULL)
+ {
+ IoFreeIrp(subRequestContext->SubIrp);
+ }
+
+ if (subRequestContext->SubUrb != NULL)
+ {
+ ExFreePool(subRequestContext->SubUrb);
+ }
+
+ if (subRequestContext->SubMdl != NULL)
+ {
+ IoFreeMdl(subRequestContext->SubMdl);
+ }
+
+ ExFreePool(subRequestContext);
+ }
+ }
+
+ ExFreePool(subRequestContextArray);
+ }
+
+ irp->IoStatus.Status = ntStatus;
+ irp->IoStatus.Information = 0;
+
+ IoCompleteRequest(irp, IO_NO_INCREMENT);
+
+ USBERR("[%s #%d] ntStatus=%Xh\n",
+ dispTransfer, sequenceID, ntStatus);
+
+ remove_lock_release(dev);
+
+ return ntStatus;
+}
+
+/*-----------------------------------------------------------------------------
+Routine Description:
+
+This routine handles the completion of a Sub Request irp that was
+created to handle part (or all) of the transfer for a Main Request
+irp.
+
+It updates the transfer length (IoStatus.Information) of the Main
+Request irp, and completes the Main Request irp if this Sub Request
+irp is the final outstanding one.
+
+The Sub Request irp and Sub Request Context may either be freed
+here, or by large_transfer_cancel(), according to which routine is
+the last one to reference the Sub Request irp.
+
+Arguments:
+
+DeviceObject - NULL as this Sub Request irp was allocated without a
+stack location for this driver to use itself.
+
+irp - Sub Request irp
+
+Context - Sub Request Context (PSUB_REQUEST_CONTEXT)
+
+Return Value:
+
+STATUS_MORE_PROCESSING_REQUIRED - Tells IoMgr not to free the Sub
+Request irp as it is either explicitly freed here, or by
+large_transfer_cancel()
+
+*/
+NTSTATUS large_transfer_complete(IN PDEVICE_OBJECT DeviceObjectIsNULL,
+ IN PIRP irp,
+ IN PVOID Context)
+{
+ PSUB_REQUEST_CONTEXT subRequestContext;
+ PURB subUrb;
+ PIRP mainIrp;
+ PMAIN_REQUEST_CONTEXT mainRequestContext;
+ PDEVICE_OBJECT deviceObject;
+ NTSTATUS ntStatus;
+ ULONG information;
+ ULONG i;
+ KIRQL irql;
+ BOOLEAN completeMainRequest;
+ int subRequestByteOffset;
+ int subRequestByteCount;
+
+ LONG sequenceID;
+ const char* dispTransfer;
+ PUCHAR outBuffer;
+ BOOLEAN needs_cancelled = FALSE;
+
+ UNREFERENCED_PARAMETER( DeviceObjectIsNULL );
+ subRequestContext = (PSUB_REQUEST_CONTEXT)Context;
+
+ subUrb = subRequestContext->SubUrb;
+ mainIrp = subRequestContext->MainIrp;
+
+ // The main request irp context is overlaid on top of
+ // irp->Tail.Overlay.DriverContext. Get a pointer to it.
+ //
+ mainRequestContext = (PMAIN_REQUEST_CONTEXT)
+ mainIrp->Tail.Overlay.DriverContext;
+
+ sequenceID = mainRequestContext->sequenceID;
+ dispTransfer = mainRequestContext->dispTransfer;
+
+ subRequestByteCount = 0;
+
+ deviceObject = IoGetCurrentIrpStackLocation(mainIrp)->DeviceObject;
+
+ ntStatus = irp->IoStatus.Status;
+
+ if (NT_SUCCESS(ntStatus) && USBD_SUCCESS(subUrb->UrbHeader.Status))
+ {
+ if (subUrb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ information = subUrb->UrbIsochronousTransfer.TransferBufferLength;
+ USBDBG("[%s #%d] transferred=%d\n",
+ dispTransfer,
+ sequenceID,
+ information);
+
+ for (i = 0; i < subUrb->UrbIsochronousTransfer.NumberOfPackets; i++)
+ {
+ if (subUrb->UrbIsochronousTransfer.IsoPacket[i].Status != 0)
+ {
+ USBDBG("[%s #%d] IsoPacket[%d].Length=%d IsoPacket[%d].Status=%08Xh\n",
+ dispTransfer,
+ sequenceID,
+ i,
+ subUrb->UrbIsochronousTransfer.IsoPacket[i].Length,
+ i,
+ subUrb->UrbIsochronousTransfer.IsoPacket[i].Status);
+ }
+ }
+ }
+ else
+ {
+ subRequestByteCount = MmGetMdlByteCount(subUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
+ subRequestByteOffset = MmGetMdlByteOffset(subUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL);
+ information = subUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
+ USBDBG("[%s #%d] offset=%d requested=%d transferred=%d\n",
+ dispTransfer,
+ sequenceID,
+ subRequestByteOffset,
+ subRequestByteCount,
+ information);
+ }
+
+ }
+ else
+ {
+ information = 0;
+
+ if (ntStatus == STATUS_CANCELLED)
+ {
+ USBDBG("[%s #%d] cancelled\n",
+ dispTransfer,
+ sequenceID);
+ }
+ else
+ {
+ USBERR("[%s #%d] failed. status=%Xh urb-status=%Xh\n",
+ dispTransfer,
+ sequenceID,
+ ntStatus,
+ subUrb->UrbHeader.Status);
+ }
+ }
+
+ // Prevent the cancel routine from executing simultaneously
+ //
+ IoAcquireCancelSpinLock(&irql);
+
+ if (subUrb->UrbHeader.Function == URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER)
+ {
+ /*
+ USBDBG("[%s #%d] MdlAddress:0x%x Function:0x%x TransferFlags:0x%x information:%d srcOffset:%d dstOffset:%d\n",
+ dispTransfer,
+ sequenceID,
+ mainIrp->MdlAddress,
+ subUrb->UrbHeader.Function,
+ subUrb->UrbBulkOrInterruptTransfer.TransferFlags,
+ information,
+ mainIrp->IoStatus.Information,
+ subRequestContext->startOffset);
+ */
+
+ // If this bulk read was valid, returned a length > 0 and a
+ // previous sub irp/urb pair in this batch was short then the
+ // data was written to the wrong offset in the output buffer.
+ // We need to move this data to the correct location in the
+ // output buffer.
+ //
+ if ((mainIrp->MdlAddress) &&
+ ((subUrb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN) == USBD_TRANSFER_DIRECTION_IN) &&
+ (information > 0))
+ {
+ if (mainIrp->IoStatus.Information < subRequestContext->startOffset)
+ {
+ // Translate a virtual address range described in the MDL for a user buffer
+ // to a system-space address range.
+ //
+ outBuffer = MmGetSystemAddressForMdlSafe(mainIrp->MdlAddress, HighPagePriority);
+
+ if (!outBuffer)
+ {
+ information = 0;
+
+ USBERR("[%s #%d] failed translating a virtual address range\n",
+ dispTransfer,sequenceID);
+ }
+ else
+ {
+ USBDBG("[%s #%d] adjusting outBuffer old-offset %d to new-offset %d (length=%d)\n",
+ dispTransfer,
+ sequenceID,
+ subRequestContext->startOffset,
+ mainIrp->IoStatus.Information,
+ information);
+
+ // move the data this subirp just put in the output buffer to the correct
+ // location.
+ //
+ RtlMoveMemory(outBuffer+mainIrp->IoStatus.Information,
+ outBuffer+subRequestContext->startOffset,
+ information);
+ }
+ }
+ else if (information < (ULONG)subRequestByteCount)
+ {
+ needs_cancelled = TRUE;
+ }
+ }
+ }
+
+ // add the sub transfer length to the main transfer length.
+ //
+ mainIrp->IoStatus.Information += information;
+
+ // Remove the sub request from the main request sub request list.
+ //
+ RemoveEntryList(&subRequestContext->ListEntry);
+
+ // If the sub request list is now empty clear the main request
+ // cancel routine and note that the main request should be
+ // completed.
+ //
+ if (IsListEmpty(&mainRequestContext->SubRequestList))
+ {
+ completeMainRequest = TRUE;
+ needs_cancelled = FALSE;
+ IoSetCancelRoutine(mainIrp, NULL);
+ }
+ else
+ {
+ completeMainRequest = FALSE;
+
+ // If this is a bulk/interrupt transfer and we transmit less
+ // bytes then what we requested, cancel the pending subIrps.
+ // If the subirp(s) cannot be cancelled, any data they return
+ // must be moved to the correct location in the output buffer.
+ //
+ if (needs_cancelled)
+ {
+ // IoSetCancelRoutine returns the previous value of
+ // mainIrp->CancelRoutine. If no Cancel routine was previously
+ // set, or if IRP cancellation is already in progress,
+ // IoSetCancelRoutine returns NULL.
+ needs_cancelled = (IoSetCancelRoutine(mainIrp, NULL) == NULL) ? FALSE : TRUE;
+ }
+
+ }
+
+ // The cancel routine may now execute simultaneously, unless of
+ // course the cancel routine was just cleared above.
+ //
+ // Do not access the main irp or the mainRequestContext in any way
+ // beyond this point, unless this is the single instance of the sub
+ // request completion routine which will complete the main irp.
+ //
+ IoReleaseCancelSpinLock(irql);
+
+ // needs_cancelled is set for the first subrequest that returns "short".
+ // provided it is not the final subrequest.
+ if (needs_cancelled)
+ {
+ // we can only do this (after IoReleaseCancelSpinLock) because the
+ // cancel routine for mainIrp was removed above.
+ large_transfer_cancel(mainIrp, FALSE);
+ }
+
+ if (InterlockedDecrement(&subRequestContext->ReferenceCount) == 0)
+ {
+ // If the reference count is now zero then the cancel routine
+ // will not free the sub request. (Either the cancel routine
+ // ran and accessed the sub request and incremented the
+ // reference count and then decremented it again without freeing
+ // the sub request, or the cancel routine did not access the
+ // sub request and can no longer access it because it has been
+ // removed from the main request sub request list.)
+ //
+ IoFreeIrp(subRequestContext->SubIrp);
+
+ ExFreePool(subRequestContext->SubUrb);
+
+ IoFreeMdl(subRequestContext->SubMdl);
+
+ ExFreePool(subRequestContext);
+ }
+ else
+ {
+ // In this case the cancel routine for the main request must be
+ // executing and is accessing the sub request after
+ // incrementing its reference count. When the cancel routine
+ // decrements the reference count again it will take care of
+ // freeing the sub request.
+ }
+
+ if (completeMainRequest)
+ {
+ // The final sub request for the main request has completed so
+ // now complete the main request.
+ //
+ USBMSG("[%s #%d] done. total transferred=%d\n",
+ dispTransfer,
+ sequenceID,
+ mainIrp->IoStatus.Information);
+
+ mainIrp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCompleteRequest(mainIrp, IO_NO_INCREMENT);
+
+ // the remove lock was referenced in dispatch_ioctl() when the main irp
+ // was first submitted.
+ remove_lock_release(deviceObject->DeviceExtension);
+ }
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/*++
+
+Routine Description:
+
+This is the cancellation routine for the main read/write irp.
+
+It cancels all currently outstanding sub requests for the main
+request.
+
+Completing the main request is the responsibility of the sub
+request completion routine after all outstanding sub requests have
+completed.
+
+Return Value:
+
+None
+
+--*/
+VOID large_transfer_cancel_routine(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp)
+{
+ large_transfer_cancel(irp, TRUE);
+}
+
+/*++
+
+Routine Description:
+
+Cancels all currently outstanding sub requests for the main
+request.
+
+Completing the main request is the responsibility of the sub
+request completion routine after all outstanding sub requests have
+completed.
+
+Return Value:
+
+None
+
+--*/
+VOID large_transfer_cancel(IN PIRP irp, BOOLEAN releaseCancelSpinlock)
+{
+ PMAIN_REQUEST_CONTEXT mainRequestContext;
+ LIST_ENTRY cancelList;
+ PLIST_ENTRY subRequestEntry;
+ PSUB_REQUEST_CONTEXT subRequestContext;
+
+ // The main request irp context is overlaid on top of
+ // irp->Tail.Overlay.DriverContext. Get a pointer to it.
+ //
+ mainRequestContext = (PMAIN_REQUEST_CONTEXT)
+ irp->Tail.Overlay.DriverContext;
+
+ // The mainRequestContext SubRequestList cannot be simultaneously
+ // changed by anything else as long as the cancel spin lock is still
+ // held, but can be changed immediately by the completion routine
+ // after the cancel spin lock is released.
+ //
+ // Iterate over the mainRequestContext SubRequestList and add all of
+ // the currently outstanding sub requests to the list of sub
+ // requests to be cancelled.
+ //
+ InitializeListHead(&cancelList);
+
+ subRequestEntry = mainRequestContext->SubRequestList.Flink;
+
+ while (subRequestEntry != &mainRequestContext->SubRequestList)
+ {
+ subRequestContext = CONTAINING_RECORD(subRequestEntry,
+ SUB_REQUEST_CONTEXT,
+ ListEntry);
+
+ // Prevent the sub request from being freed as soon as the
+ // cancel spin lock is released by incrementing the reference
+ // count on the sub request.
+ //
+ InterlockedIncrement(&subRequestContext->ReferenceCount);
+
+ InsertTailList(&cancelList, &subRequestContext->CancelListEntry);
+
+ subRequestEntry = subRequestEntry->Flink;
+ }
+
+ USBDBG("[%s #%d] cancel-reason=%s\n",
+ mainRequestContext->dispTransfer,
+ mainRequestContext->sequenceID,
+ releaseCancelSpinlock?"User":"ShortTransfer");
+
+ if (releaseCancelSpinlock)
+ {
+
+ // The main read/write irp can be completed immediately after
+ // releasing the cancel spin lock. Do not access the main
+ // read/write irp or the mainRequestContext in any way beyond this
+ // point.
+ //
+ IoReleaseCancelSpinLock(irp->CancelIrql);
+ }
+
+ // Iterate over the list that was built of sub requests to cancel
+ // and cancel each sub request.
+ //
+ while (!IsListEmpty(&cancelList))
+ {
+ subRequestEntry = RemoveHeadList(&cancelList);
+
+ subRequestContext = CONTAINING_RECORD(subRequestEntry,
+ SUB_REQUEST_CONTEXT,
+ CancelListEntry);
+
+ if (!subRequestContext->SubIrp->Cancel)
+ {
+ IoCancelIrp(subRequestContext->SubIrp);
+ }
+
+ if (InterlockedDecrement(&subRequestContext->ReferenceCount) == 0)
+ {
+ // If the reference count is now zero then the completion
+ // routine already ran for the sub request but did not free
+ // the sub request so it can be freed now.
+ //
+ IoFreeIrp(subRequestContext->SubIrp);
+
+ ExFreePool(subRequestContext->SubUrb);
+
+ IoFreeMdl(subRequestContext->SubMdl);
+
+ ExFreePool(subRequestContext);
+ }
+ else
+ {
+ // The completion routine for the sub request has not yet
+ // executed and decremented the sub request reference count.
+ // Do not free the sub request here. It will be freed when
+ // the sub request completion routine executes.
+ }
+ }
+}
+
+static int get_iso_stagesize(int totalLength, int packetSize, int maxTransferSize)
+{
+ int stageSize;
+
+ if (totalLength > (packetSize * 255) || totalLength > maxTransferSize)
+ {
+ stageSize = packetSize * 255;
+ if (stageSize > maxTransferSize)
+ stageSize = maxTransferSize;
+
+ // stageSize = stageSize - (stageSize % packetSize);
+
+ }
+ else
+ {
+ stageSize = totalLength;
+ }
+
+ return stageSize;
+}
+
+static NTSTATUS allocate_suburb(USHORT urbFunction,
+ int stageSize,
+ int packetSize,
+ ULONG* nPackets,
+ PURB* subUrbRef)
+{
+ int urbSize;
+ //
+ // 3. Allocate a sub request urb.
+ //
+ if (urbFunction == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ *nPackets = (stageSize + packetSize - 1) / packetSize;
+ urbSize = GET_ISO_URB_SIZE(*nPackets);
+ }
+ else
+ {
+ *nPackets = 0;
+ urbSize = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
+ }
+
+ *subUrbRef = (PURB)ExAllocatePool(NonPagedPool, urbSize);
+
+ if ((*subUrbRef) == NULL)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ RtlZeroMemory(*subUrbRef, urbSize);
+
+ (*subUrbRef)->UrbHeader.Length = (USHORT)urbSize;
+ (*subUrbRef)->UrbHeader.Function = urbFunction;
+
+ return STATUS_SUCCESS;
+}
+
+static const char* GetPipeDisplayName(libusb_endpoint_t* endpoint)
+{
+ if (endpoint->address & 0x80)
+ return read_pipe_display_names[(endpoint->pipe_type & 3)];
+ else
+ return write_pipe_display_names[(endpoint->pipe_type & 3)];
+}
+
+void set_urb_transfer_flags(libusb_device_t* dev, PIRP irp, PURB subUrb,int transfer_flags, int isoLatency)
+{
+ if (subUrb->UrbHeader.Function == URB_FUNCTION_ISOCH_TRANSFER)
+ {
+ // only keep the direction bit
+ subUrb->UrbIsochronousTransfer.TransferFlags &= 1;
+
+ // If true, allow short tranfers.
+ if (!(transfer_flags & TRANSFER_FLAGS_SHORT_NOT_OK))
+ subUrb->UrbIsochronousTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
+
+ if (!(transfer_flags & TRANSFER_FLAGS_ISO_SET_START_FRAME))
+ subUrb->UrbIsochronousTransfer.TransferFlags |= USBD_START_ISO_TRANSFER_ASAP;
+ else
+ {
+ subUrb->UrbIsochronousTransfer.StartFrame = get_current_frame(dev, irp);
+ if (transfer_flags & TRANSFER_FLAGS_ISO_ADD_LATENCY)
+ subUrb->UrbIsochronousTransfer.StartFrame += isoLatency;
+ }
+ }
+
+ else if (subUrb->UrbHeader.Function == URB_FUNCTION_CONTROL_TRANSFER)
+ {
+ // TODO: large control transfers
+
+ // only keep the direction bit
+ subUrb->UrbControlTransfer.TransferFlags &= 1;
+ if (!(transfer_flags & TRANSFER_FLAGS_SHORT_NOT_OK))
+ subUrb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
+
+ }
+ else
+ {
+ // Default is bulk or interrupt.
+
+ // only keep the direction bit
+ subUrb->UrbBulkOrInterruptTransfer.TransferFlags &= 1;
+
+ // If true, allow short tranfers.
+ if (!(transfer_flags & TRANSFER_FLAGS_SHORT_NOT_OK))
+ subUrb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
+ }
+}
+
+NTSTATUS control_transfer(libusb_device_t* dev,
+ PIRP irp,
+ PMDL mdl,
+ int size,
+ int usbd_direction,
+ int *ret,
+ int timeout,
+ UCHAR request_type,
+ UCHAR request,
+ USHORT value,
+ USHORT index,
+ USHORT length)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ *ret = 0;
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_TRANSFER));
+ urb.UrbControlTransfer.SetupPacket[0]=request_type;
+ urb.UrbControlTransfer.SetupPacket[1]=request;
+
+ urb.UrbControlTransfer.SetupPacket[2]=LBYTE(value);
+ urb.UrbControlTransfer.SetupPacket[3]=HBYTE(value);
+
+ urb.UrbControlTransfer.SetupPacket[4]=LBYTE(index);
+ urb.UrbControlTransfer.SetupPacket[5]=HBYTE(index);
+
+ urb.UrbControlTransfer.SetupPacket[6]=LBYTE(length);
+ urb.UrbControlTransfer.SetupPacket[7]=HBYTE(length);
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER);
+ urb.UrbHeader.Function=URB_FUNCTION_CONTROL_TRANSFER;
+ urb.UrbControlTransfer.TransferFlags=usbd_direction | USBD_DEFAULT_PIPE_TRANSFER | USBD_SHORT_TRANSFER_OK;
+ urb.UrbControlTransfer.TransferBufferLength = size;
+ urb.UrbControlTransfer.TransferBufferMDL = mdl;
+ urb.UrbControlTransfer.TransferBuffer = NULL;
+
+ USBMSG("[%s] timeout=%d request_type=%02Xh request=%02Xh value=%04Xh index=%04Xh length=%04Xh\n",
+ (usbd_direction==USBD_TRANSFER_DIRECTION_IN) ? "read" : "write",
+ timeout, request_type, request, value, index, length);
+
+ // no maximum timeout check for control request.
+ status = call_usbd_ex(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout, 0);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("request failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ }
+ else
+ {
+ *ret = urb.UrbControlTransfer.TransferBufferLength;
+ USBMSG("%d bytes transmitted\n",
+ urb.UrbControlTransfer.TransferBufferLength);
+ }
+
+ return status;
+}
diff --git a/usb/driver/usbd.def b/usb/driver/usbd.def
new file mode 100644
index 0000000..5c283bb
--- /dev/null
+++ b/usb/driver/usbd.def
@@ -0,0 +1,35 @@
+
+EXPORTS
+USBD_AllocateDeviceName
+USBD_CalculateUsbBandwidth
+USBD_CompleteRequest
+USBD_CreateConfigurationRequest
+USBD_CreateConfigurationRequestEx
+USBD_CreateDevice
+USBD_Debug_GetHeap
+USBD_Debug_LogEntry
+USBD_Debug_RetHeap
+USBD_Dispatch
+USBD_FreeDeviceMutex
+USBD_FreeDeviceName
+USBD_GetDeviceInformation
+USBD_GetInterfaceLength
+USBD_GetPdoRegistryParameter
+USBD_GetSuspendPowerState
+USBD_GetUSBDIVersion
+USBD_InitializeDevice
+USBD_MakePdoName
+USBD_ParseConfigurationDescriptor
+USBD_ParseConfigurationDescriptorEx
+USBD_ParseDescriptors
+USBD_QueryBusTime
+USBD_RegisterHcDeviceCapabilities
+USBD_RegisterHcFilter
+USBD_RegisterHostController
+USBD_RemoveDevice
+USBD_RestoreDevice
+USBD_SetSuspendPowerState
+USBD_WaitDeviceMutex
+USBD_CreateConfigurationRequestEx@8=_USBD_CreateConfigurationRequestEx@8
+USBD_ParseConfigurationDescriptorEx@28=_USBD_ParseConfigurationDescriptorEx@28
+USBD_ParseDescriptors@16=_USBD_ParseDescriptors@16
diff --git a/usb/driver/usbdlib_gcc.h b/usb/driver/usbdlib_gcc.h
new file mode 100644
index 0000000..5dec851
--- /dev/null
+++ b/usb/driver/usbdlib_gcc.h
@@ -0,0 +1,310 @@
+
+#ifndef __USBDLIB_H
+#define __USBDLIB_H
+
+#if __GNUC__ >=3
+#pragma GCC system_header
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#pragma pack(push,4)
+
+
+ typedef struct _USBD_INTERFACE_LIST_ENTRY
+ {
+ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
+ PUSBD_INTERFACE_INFORMATION Interface;
+ } USBD_INTERFACE_LIST_ENTRY, *PUSBD_INTERFACE_LIST_ENTRY;
+
+
+#define URB_STATUS(urb) ((urb)->UrbHeader.Status)
+
+#define GET_SELECT_CONFIGURATION_REQUEST_SIZE(totalInterfaces, totalPipes) \
+ (sizeof(struct _URB_SELECT_CONFIGURATION) \
+ + ((totalInterfaces - 1) * sizeof(USBD_INTERFACE_INFORMATION)) \
+ + ((totalPipes - 1) * sizeof(USBD_PIPE_INFORMATION)))
+
+#define GET_SELECT_INTERFACE_REQUEST_SIZE(totalPipes) \
+ (sizeof(struct _URB_SELECT_INTERFACE) \
+ + ((totalPipes - 1) * sizeof(USBD_PIPE_INFORMATION)))
+
+#define GET_USBD_INTERFACE_SIZE(numEndpoints) \
+ (sizeof(USBD_INTERFACE_INFORMATION) \
+ + (sizeof(USBD_PIPE_INFORMATION)*(numEndpoints)) \
+ - sizeof(USBD_PIPE_INFORMATION))
+
+#define GET_ISO_URB_SIZE(n) (sizeof(struct _URB_ISOCH_TRANSFER) \
+ + sizeof(USBD_ISO_PACKET_DESCRIPTOR) * n)
+
+
+#define UsbBuildInterruptOrBulkTransferRequest(urb, \
+ length, \
+ pipeHandle, \
+ transferBuffer, \
+ transferBufferMDL, \
+ transferBufferLength, \
+ transferFlags, \
+ link) { \
+ (urb)->UrbHeader.Function = \
+ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbBulkOrInterruptTransfer.PipeHandle = (pipeHandle); \
+ (urb)->UrbBulkOrInterruptTransfer.TransferBufferLength = \
+ (transferBufferLength); \
+ (urb)->UrbBulkOrInterruptTransfer.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbBulkOrInterruptTransfer.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbBulkOrInterruptTransfer.TransferFlags = \
+ (transferFlags); \
+ (urb)->UrbBulkOrInterruptTransfer.UrbLink = (link); }
+
+
+#define UsbBuildGetDescriptorRequest(urb, \
+ length, \
+ descriptorType, \
+ descriptorIndex, \
+ languageId, \
+ transferBuffer, \
+ transferBufferMDL, \
+ transferBufferLength, \
+ link) { \
+ (urb)->UrbHeader.Function = \
+ URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbControlDescriptorRequest.TransferBufferLength = \
+ (transferBufferLength); \
+ (urb)->UrbControlDescriptorRequest.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbControlDescriptorRequest.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbControlDescriptorRequest.DescriptorType = \
+ (descriptorType); \
+ (urb)->UrbControlDescriptorRequest.Index = (descriptorIndex); \
+ (urb)->UrbControlDescriptorRequest.LanguageId = (languageId); \
+ (urb)->UrbControlDescriptorRequest.UrbLink = (link); }
+
+
+
+#define UsbBuildGetStatusRequest(urb, \
+ op, \
+ index, \
+ transferBuffer, \
+ transferBufferMDL, \
+ link) { \
+ (urb)->UrbHeader.Function = (op); \
+ (urb)->UrbHeader.Length = \
+ sizeof(struct _URB_CONTROL_GET_STATUS_REQUEST); \
+ (urb)->UrbControlGetStatusRequest.TransferBufferLength = \
+ sizeof(USHORT); \
+ (urb)->UrbControlGetStatusRequest.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbControlGetStatusRequest.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbControlGetStatusRequest.Index = (index); \
+ (urb)->UrbControlGetStatusRequest.UrbLink = (link); }
+
+
+#define UsbBuildFeatureRequest(urb, \
+ op, \
+ featureSelector, \
+ index, \
+ link) { \
+ (urb)->UrbHeader.Function = (op); \
+ (urb)->UrbHeader.Length = \
+ sizeof(struct _URB_CONTROL_FEATURE_REQUEST); \
+ (urb)->UrbControlFeatureRequest.FeatureSelector = \
+ (featureSelector); \
+ (urb)->UrbControlFeatureRequest.Index = (index); \
+ (urb)->UrbControlFeatureRequest.UrbLink = (link); }
+
+
+
+#define UsbBuildSelectConfigurationRequest(urb, \
+ length, \
+ configurationDescriptor) { \
+ (urb)->UrbHeader.Function = URB_FUNCTION_SELECT_CONFIGURATION; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbSelectConfiguration.ConfigurationDescriptor = \
+ (configurationDescriptor); }
+
+#define UsbBuildSelectInterfaceRequest(urb, \
+ length, \
+ configurationHandle, \
+ interfaceNumber, \
+ alternateSetting) { \
+ (urb)->UrbHeader.Function = URB_FUNCTION_SELECT_INTERFACE; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbSelectInterface.Interface.AlternateSetting = \
+ (alternateSetting); \
+ (urb)->UrbSelectInterface.Interface.InterfaceNumber = \
+ (interfaceNumber); \
+ (urb)->UrbSelectInterface.ConfigurationHandle = \
+ (configurationHandle); }
+
+
+#define UsbBuildVendorRequest(urb, \
+ cmd, \
+ length, \
+ transferFlags, \
+ reservedbits, \
+ request, \
+ value, \
+ index, \
+ transferBuffer, \
+ transferBufferMDL, \
+ transferBufferLength, \
+ link) { \
+ (urb)->UrbHeader.Function = cmd; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbControlVendorClassRequest.TransferBufferLength = \
+ (transferBufferLength); \
+ (urb)->UrbControlVendorClassRequest.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbControlVendorClassRequest.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbControlVendorClassRequest.RequestTypeReservedBits = \
+ (reservedbits); \
+ (urb)->UrbControlVendorClassRequest.Request = (request); \
+ (urb)->UrbControlVendorClassRequest.Value = (value); \
+ (urb)->UrbControlVendorClassRequest.Index = (index); \
+ (urb)->UrbControlVendorClassRequest.TransferFlags = \
+ (transferFlags); \
+ (urb)->UrbControlVendorClassRequest.UrbLink = (link); }
+
+
+#define UsbBuildOsFeatureDescriptorRequest(urb, \
+ length, \
+ interface, \
+ index, \
+ transferBuffer, \
+ transferBufferMDL, \
+ transferBufferLength, \
+ link) { \
+ (urb)->UrbHeader.Function = \
+ URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR; \
+ (urb)->UrbHeader.Length = (length); \
+ (urb)->UrbOSFeatureDescriptorRequest.TransferBufferLength = \
+ (transferBufferLength); \
+ (urb)->UrbOSFeatureDescriptorRequest.TransferBufferMDL = \
+ (transferBufferMDL); \
+ (urb)->UrbOSFeatureDescriptorRequest.TransferBuffer = \
+ (transferBuffer); \
+ (urb)->UrbOSFeatureDescriptorRequest.InterfaceNumber = \
+ (interface); \
+ (urb)->UrbOSFeatureDescriptorRequest.MS_FeatureDescriptorIndex = \
+ (index); \
+ (urb)->UrbOSFeatureDescriptorRequest.UrbLink = (link); }
+
+
+ VOID
+ DDKAPI
+ USBD_Debug_LogEntry(
+ IN CHAR *Name,
+ IN ULONG Info1,
+ IN ULONG Info2,
+ IN ULONG Info3
+ );
+
+ VOID
+ DDKAPI
+ USBD_GetUSBDIVersion(
+ PUSBD_VERSION_INFORMATION VersionInformation
+ );
+
+
+ PUSB_INTERFACE_DESCRIPTOR
+ DDKAPI
+ USBD_ParseConfigurationDescriptor(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+ IN UCHAR InterfaceNumber,
+ IN UCHAR AlternateSetting
+ );
+
+ PURB
+ DDKAPI
+ USBD_CreateConfigurationRequest(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+ IN OUT PUSHORT Siz
+ );
+
+ PUSB_COMMON_DESCRIPTOR
+ DDKAPI
+ USBD_ParseDescriptors(
+ IN PVOID DescriptorBuffer,
+ IN ULONG TotalLength,
+ IN PVOID StartPosition,
+ IN LONG DescriptorType
+ );
+
+ PUSB_INTERFACE_DESCRIPTOR
+ DDKAPI
+ USBD_ParseConfigurationDescriptorEx(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+ IN PVOID StartPosition,
+ IN LONG InterfaceNumber,
+ IN LONG AlternateSetting,
+ IN LONG InterfaceClass,
+ IN LONG InterfaceSubClass,
+ IN LONG InterfaceProtocol
+ );
+
+ PURB
+ DDKAPI
+ USBD_CreateConfigurationRequestEx(
+ IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+ IN PUSBD_INTERFACE_LIST_ENTRY InterfaceList
+ );
+
+ ULONG
+ DDKAPI
+ USBD_GetInterfaceLength(
+ IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
+ IN PUCHAR BufferEnd
+ );
+
+ VOID
+ DDKAPI
+ USBD_RegisterHcFilter(
+ PDEVICE_OBJECT DeviceObject,
+ PDEVICE_OBJECT FilterDeviceObject
+ );
+
+ NTSTATUS
+ DDKAPI
+ USBD_GetPdoRegistryParameter(
+ IN PDEVICE_OBJECT PhysicalDeviceObject,
+ IN OUT PVOID Parameter,
+ IN ULONG ParameterLength,
+ IN PWCHAR KeyName,
+ IN ULONG KeyNameLength
+ );
+
+ NTSTATUS
+ DDKAPI
+ USBD_QueryBusTime(
+ IN PDEVICE_OBJECT RootHubPdo,
+ IN PULONG CurrentFrame
+ );
+
+ ULONG
+ DDKAPI
+ USBD_CalculateUsbBandwidth(
+ ULONG MaxPacketSize,
+ UCHAR EndpointType,
+ BOOLEAN LowSpeed
+ );
+
+
+#pragma pack(pop)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USBDLIB_H */
+
diff --git a/usb/driver/vendor_request.c b/usb/driver/vendor_request.c
new file mode 100644
index 0000000..f3a898b
--- /dev/null
+++ b/usb/driver/vendor_request.c
@@ -0,0 +1,143 @@
+/* libusb-win32, Generic Windows USB Library
+ * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "libusb_driver.h"
+
+
+NTSTATUS vendor_class_request(libusb_device_t *dev,
+ int type, int recipient,
+ int request, int value, int index,
+ void *buffer, int size, int direction,
+ int *ret, int timeout)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ URB urb;
+
+ *ret = 0;
+
+ memset(&urb, 0, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+
+ switch (type)
+ {
+ case USB_TYPE_CLASS:
+ USBMSG0("type: class\n");
+ switch (recipient)
+ {
+ case USB_RECIP_DEVICE:
+ USBMSG0("recipient: device\n");
+ urb.UrbHeader.Function = URB_FUNCTION_CLASS_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ USBMSG0("recipient: interface\n");
+ urb.UrbHeader.Function = URB_FUNCTION_CLASS_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ USBMSG0("recipient: endpoint\n");
+ urb.UrbHeader.Function = URB_FUNCTION_CLASS_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ USBMSG0("recipient: other\n");
+ urb.UrbHeader.Function = URB_FUNCTION_CLASS_OTHER;
+ break;
+ default:
+ USBERR0("invalid recipient\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+ break;
+ case USB_TYPE_VENDOR:
+ USBMSG0("type: vendor\n");
+ switch (recipient)
+ {
+ case USB_RECIP_DEVICE:
+ USBMSG0("recipient: device\n");
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
+ break;
+ case USB_RECIP_INTERFACE:
+ USBMSG0("recipient: interface\n");
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_INTERFACE;
+ break;
+ case USB_RECIP_ENDPOINT:
+ USBMSG0("recipient: endpoint\n");
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_ENDPOINT;
+ break;
+ case USB_RECIP_OTHER:
+ USBMSG0("recipient: other\n");
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_OTHER;
+ break;
+ default:
+ // [Kevin Timmerman Patch]
+ USBMSG("recipient: reserved (0x%02x)\n", recipient);
+ urb.UrbHeader.Function = URB_FUNCTION_VENDOR_DEVICE;
+ urb.UrbControlVendorClassRequest.RequestTypeReservedBits = (UCHAR)recipient;
+ break;
+ /*
+ USBERR0("invalid recipient\n");
+ return STATUS_INVALID_PARAMETER;
+ */
+ }
+ break;
+ default:
+ USBERR0("invalid type\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ USBMSG("request: 0x%02x\n", request);
+ USBMSG("value: 0x%04x\n", value);
+ USBMSG("index: 0x%04x\n", index);
+ USBMSG("size: %d\n", size);
+
+ if (direction == USBD_TRANSFER_DIRECTION_IN)
+ {
+ USBMSG0("direction: in\n");
+ }
+ else
+ {
+ USBMSG0("direction: out\n");
+ }
+
+ USBMSG("timeout: %d\n", timeout);
+
+ urb.UrbHeader.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
+ urb.UrbControlVendorClassRequest.TransferFlags
+ = direction | USBD_SHORT_TRANSFER_OK ;
+ urb.UrbControlVendorClassRequest.TransferBufferLength = size;
+ urb.UrbControlVendorClassRequest.TransferBufferMDL = NULL;
+ urb.UrbControlVendorClassRequest.TransferBuffer = buffer;
+ urb.UrbControlVendorClassRequest.Request = (UCHAR)request;
+ urb.UrbControlVendorClassRequest.Value = (USHORT)value;
+ urb.UrbControlVendorClassRequest.Index = (USHORT)index;
+
+ // no maximum timeout check for vendor request.
+ status = call_usbd_ex(dev, &urb, IOCTL_INTERNAL_USB_SUBMIT_URB, timeout, 0);
+
+ if (!NT_SUCCESS(status) || !USBD_SUCCESS(urb.UrbHeader.Status))
+ {
+ USBERR("request failed: status: 0x%x, urb-status: 0x%x\n", status, urb.UrbHeader.Status);
+ }
+ else
+ {
+ if (direction == USBD_TRANSFER_DIRECTION_IN)
+ *ret = urb.UrbControlVendorClassRequest.TransferBufferLength;
+ USBMSG("%d bytes transmitted\n",
+ urb.UrbControlVendorClassRequest.TransferBufferLength);
+ }
+
+ return status;
+}
+
diff --git a/usb/install_kext.sh b/usb/install_kext.sh
new file mode 100644
index 0000000..22c181a
--- /dev/null
+++ b/usb/install_kext.sh
@@ -0,0 +1,6 @@
+# Install OS X HCFR codeless kernel extension
+echo "Installing OS X HCFR codeless kernel extension"
+sudo cp -R Argyll.kext /System/Library/Extensions/
+sudo chown -R root:wheel /System/Library/Extensions/Argyll.kext
+sudo kextload -t /System/Library/Extensions/Argyll.kext
+echo "Reboot to finish installation"
diff --git a/xicc/Jamfile b/xicc/Jamfile
new file mode 100644
index 0000000..58e5051
--- /dev/null
+++ b/xicc/Jamfile
@@ -0,0 +1,172 @@
+
+#PREF_CCFLAGS += $(CCOPTFLAG) ; # Turn optimisation on
+PREF_CCFLAGS += $(CCDEBUGFLAG) ; # Debugging flags
+#PREF_CCFLAGS += $(CCHEAPDEBUG) ; # Heap Debugging flags
+PREF_LINKFLAGS += $(LINKDEBUGFLAG) ; # Link debugging flags
+
+#Products
+Libraries = libxicc libxcolorants libxutils ;
+Executables = fakeCMY iccgamut mpplu revfix tiffgamut xicclu extracticc extractttag specplot ;
+Headers = xicc.h ;
+Samples = License.txt ;
+
+#Install
+InstallBin $(DESTDIR)$(PREFIX)/bin : $(Executables) ;
+InstallFile $(DESTDIR)$(PREFIX)/bin : $(Samples) ;
+#InstallFile $(DESTDIR)$(PREFIX)/h : $(Headers) ;
+#InstallLib $(DESTDIR)$(PREFIX)/lib : $(Libraries) ;
+
+HDRS = ../h ../icc ../rspl ../cgats ../numlib ../gamut ../spectro ../profile
+ ../plot ../render $(TIFFINC) $(JPEGINC) $(LibWinH) ;
+
+# XICC library
+Library libxicc : xicc.c xlutfix.c xspect.c xcolorants.c xutils.c iccjpeg.c xdevlin.c
+ xcam.c cam97s3.c cam02.c mpp.c ccmx.c ccss.c xfit.c xdgb.c moncurve.c xcal.c ;
+
+# colorant library. Use instead of libxicc
+Object xcolorants2 : xcolorants.c ;
+LibraryFromObjects libxcolorants : xcolorants2 ;
+
+# standalone utilities library. Use instead of libxicc
+Object xutils2 : xutils.c ;
+Object iccjpeg2 : iccjpeg.c ;
+LibraryFromObjects libxutils : xutils2 iccjpeg2 ;
+
+# Utilities / test programs
+
+LINKLIBS = libxicc ../spectro/libinsttypes ../gamut/libgamut ../rspl/librspl
+ ../cgats/libcgats ../icc/libicc ../plot/libplot ../plot/libvrml ../numlib/libnum
+ $(TIFFLIB) $(JPEGLIB) ;
+
+# Not created yet
+#Main xicctest : xicctest.c ;
+
+# Not created yet
+#Main xlutest : xlutest.c ;
+
+# expanded version of icclu
+Main xicclu : xicclu.c ;
+
+# expanded version of iccgamut - does Jab and ink limiting
+Main iccgamut : iccgamut.c ;
+
+# tiff file gamut utility
+Main tiffgamut : tiffgamut.c : : : $(TIFFINC) $(JPEGINC) : : ;
+
+# diagnostic utility
+if [ GLOB . : tiffgmts.c ] {
+ Main tiffgmts : tiffgmts.c : : : $(TIFFINC) $(JPEGINC) : : ../plot/libvrml ;
+}
+
+# Reverse profile fixer
+Main revfix : revfix.c ;
+
+# MPP lookup test utility
+Main mpplu : mpplu.c ;
+
+# Embedded ICC profile extractor
+Main extracticc : extracticc.c : : : $(TIFFINC) $(JPEGINC) : : ;
+
+# Text tag from ICC profile extracto
+Main extractttag : extractttag.c : : : $(TIFFINC) $(JPEGINC) : : ;
+
+# xcolorant lookup test
+Main xcolorantslu : xcolorantslu.c ;
+
+#test program for viewing inverse algorithm
+#Should be in JUNK ??
+Main fbview : fbview.c ;
+
+Main fakeCMY : fakeCMY.c : : : ../target ;
+
+Main xfbview : xfbview.c ;
+
+Main icheck : icheck.c ;
+
+# Test FWA in xspect
+Main spectest : spectest.c ;
+
+# Test FWA in xspect 2
+Main spectest2 : spectest2.c : : : : : ../spectro/libinsttypes ;
+
+# Spectral plotting and CCT test
+Main ccttest : ccttest.c ;
+
+# transfer curve plotting
+Main transplot : transplot.c ;
+
+# CGATS .ti3 plotting
+Main cgatsplot : cgatsplot.c ;
+
+# per channel curve testing
+Main cv : cv.c ;
+
+# per channel curve fitting testing
+Main cvtest : cvtest.c ;
+
+# per channel curve fitting testing
+Main cvtest : cvtest.c ;
+
+# Generate sub sampled illuminants or observers */
+Main specsubsamp : specsubsamp.c ;
+
+# Plot spectrum and test CCT spectrum code and illuminant utility
+Main specplot : specplot.c ;
+
+# CAM test routines
+Main cam97test : cam97test.c ;
+Main cam02test : cam02test.c ;
+
+# Test utility for moncurve
+Main monctest : monctest.c ;
+
+#Main cam02vecplot : cam02vecplot.c : : : : : ../plot/libvrml ;
+
+#Home = ' d:\usr\graeme ' and PWD = ' /src/argyll/xicc '
+if $(HOME) = "d:\\usr\\graeme" && $(PWD) = "/src/argyll/xicc" {
+ #Create test TIFF file for cam02 conversion
+ Main cam02plot : cam02plot.c : : : $(TIFFINC) $(JPEGINC) : : ;
+ Main cam02logplot : cam02logplot.c : : : $(TIFFINC) $(JPEGINC) : : ;
+ Main cam02delplot : cam02delplot.c : : : $(TIFFINC) $(JPEGINC) : : ;
+ Main cam02vecplot : cam02vecplot.c : : : : : ../plot/libvrml ;
+}
+
+#Main t : t.c ;
+
+if $(BUILD_JUNK) {
+
+ LINKLIBS += ../render/librender ;
+
+ Main slocustest : slocustest.c ;
+
+ MainsFromSources t1.c t2.c t22.c t23.c t24.c t3.c ;
+
+ Main test : test.c ;
+
+ Main t : t.c ;
+
+ # CAM97s3 matrix inversion calc
+ Main cammatrix : cammatrix.c ;
+
+ # test matrix deriv version
+ Main t : t.c ;
+
+ # Develop conjgrad version of code for profile
+ Main tt3 : tt3.c ;
+
+ # test icx_icc_cv_to_colorant_comb()
+ Main tcc : tcc.c ;
+
+ # Develop conjgrad version of code for profile
+ Main tt4 : tt4.c ;
+
+ # Test viewing conditions extractor
+ Main vctest : vctest.c ;
+
+ # ~~~ test code
+ Main lseptest : lseptest.c ;
+
+ # ~~~ test code
+ Main llseptest : llseptest.c ;
+}
+
diff --git a/xicc/License.txt b/xicc/License.txt
new file mode 100644
index 0000000..a871fcf
--- /dev/null
+++ b/xicc/License.txt
@@ -0,0 +1,662 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
+
diff --git a/xicc/Makefile.am b/xicc/Makefile.am
new file mode 100644
index 0000000..67b34f9
--- /dev/null
+++ b/xicc/Makefile.am
@@ -0,0 +1,28 @@
+include $(top_srcdir)/Makefile.shared
+
+privatelib_LTLIBRARIES = libxicc.la libxutils.la
+privatelibdir = $(pkglibdir)
+
+libxicc_la_SOURCES = xicc.c xlutfix.c xspect.c xcolorants.c \
+ xutils.c iccjpeg.c xdevlin.c xcam.c cam97s3.c cam02.c mpp.c \
+ ccmx.c ccss.c xfit.c xdgb.c moncurve.c xcal.c
+libxicc_la_LIBADD = $(ICC_LIBS) ../gamut/libgamut.la \
+ ../numlib/libargyllnum.la ../spectro/libinsttypes.la \
+ ../cgats/libcgats.la ../rspl/librspl.la ../libargyll.la -ljpeg $(TIFF_LIBS)
+
+libxutils_la_SOURCES = xutils.h xutils.c iccjpeg.c iccjpeg.h
+libxutils_la_LIBADD = $(TIFF_LIBS) $(ICC_LIBS) -ljpeg
+
+LDADD = ./libxicc.la ./libxutils.la ../rspl/librspl.la \
+ ../numlib/libargyllnum.la ../gamut/libgamut.la \
+ ../gamut/libgammap.la ../spectro/libinsttypes.la $(ICC_LIBS) \
+ ../cgats/libcgats.la ../plot/libvrml.la ../plot/libplot.la \
+ $(TIFF_LIBS) $(X_LIBS) ../libargyll.la -ljpeg
+
+bin_PROGRAMS = fakeCMY iccgamut mpplu revfix tiffgamut xicclu \
+ extracticc extractttag specplot ccttest
+
+fakeCMY_DEPENDENCIES = ../spectro/libinsttypes.la \
+ ../gamut/libgammap.la ../target/libtarget.la
+
+EXTRA_DIST = xmono.c xmatrix.c xlut.c
diff --git a/xicc/Readme.txt b/xicc/Readme.txt
new file mode 100644
index 0000000..f4a303a
--- /dev/null
+++ b/xicc/Readme.txt
@@ -0,0 +1,15 @@
+This directory holds the "expansion" icc libraries.
+
+These suplement the base icc library with enhanced
+profile functionality, such as smoothed interpolation,
+reverse interpolation, table creation from scattered
+data etc.
+
+Most of this functionality is based on the rspl and icc libraries.
+This is where ink limiting and black generation policies
+for CMYK devices is implemented.
+
+xicclu.exe is the analog of the icclib utility icclu, but
+ expands the capability to reverse lookup the
+ Lut tables.
+
diff --git a/xicc/afiles b/xicc/afiles
new file mode 100644
index 0000000..8b4341a
--- /dev/null
+++ b/xicc/afiles
@@ -0,0 +1,68 @@
+Readme.txt
+License.txt
+afiles
+Jamfile
+xicc.h
+xicc.c
+xmono.c
+xmatrix.c
+xlut.c
+xlutfix.c
+xcal.h
+xcal.c
+mpp.h
+mpp.c
+mpplu.c
+ccmx.h
+ccmx.c
+ccss.h
+ccss.c
+xcolorants.h
+xcolorants.c
+xcolorantslu.c
+xutils.h
+xutils.c
+iccjpeg.h
+iccjpeg.c
+xfit.h
+xfit.c
+xdgb.h
+xdgb.c
+xspect.h
+xspect.c
+specplot.c
+specsubsamp.c
+xdevlin.h
+xdevlin.c
+example.sp
+xicclu.c
+iccgamut.c
+tiffgamut.c
+tiffgmts.c
+revfix.c
+fakeCMY.c
+xcam.h
+xcam.c
+cam97s3.c
+cam97s3.h
+cam97test.c
+cam02.c
+cam02.h
+cam02ref.h
+cam02test.c
+cam02plot.c
+moncurve.c
+moncurve.h
+monctest.c
+fbview.c
+xfbview.c
+icheck.c
+transplot.c
+cgatsplot.c
+spectest.c
+spectest2.c
+ccttest.c
+cv.c
+cvtest.c
+extracticc.c
+extractttag.c
diff --git a/xicc/cam02.c b/xicc/cam02.c
new file mode 100644
index 0000000..1ab6abc
--- /dev/null
+++ b/xicc/cam02.c
@@ -0,0 +1,1279 @@
+
+/*
+ * cam02
+ *
+ * Color Appearance Model, based on
+ * CIECAM02, "The CIECAM02 Color Appearance Model"
+ * by Nathan Moroney, Mark D. Fairchild, Robert W.G. Hunt, Changjun Li,
+ * M. Ronnier Luo and Todd Newman, IS&T/SID Tenth Color Imaging
+ * Conference, with the addition of the Viewing Flare
+ * model described on page 487 of "Digital Color Management",
+ * by Edward Giorgianni and Thomas Madden, and the
+ * Helmholtz-Kohlraush effect, using the equation from
+ * the Bradford-Hunt 96C model as detailed in Mark Fairchild's
+ * book "Color Appearance Models".
+ * The Slight modification to the Hunt-Pointer-Estevez matrix
+ * recommended by Kuo, Zeis and Lai in IS&T/SID 14th Color Imaging
+ * Conference "Robust CIECAM02 Implementation and Numerical
+ * Experiment within an ICC Workflow", page 215, together with
+ * their matrix formulation of inversion has been adopted.
+ *
+ * In addition the algorithm has unique extensions to allow
+ * it to operate reasonably over an unbounded domain.
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/1/2004
+ * Version: 1.00
+ *
+ * This file is based on cam97s3.c by Graeme Gill.
+ *
+ * Copyright 2004 - 2011 Graeme W. Gill
+ * Please refer to COPYRIGHT file for details.
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+/* Note that XYZ values are normalised to 1.0 consistent */
+/* with the ICC convention (not 100.0 as assumed by the CIECAM spec.) */
+/* Note that all whites are assumed to be normalised (ie. Y = 1.0) */
+
+/*
+ Various additions and changes have been made to allow the CAM
+ conversions to and from an unbounded range of XYZ and Jab values,
+ in a (somewhat) geometrically consistent maner. This is because
+ such values arise in the process of gamut mapping, and in scanning through
+ the grid of PCS values needed to fill in the A2B table of an
+ ICC profile. Such values have no correlation to a real color
+ value, but none the less need to be handled without causing an
+ exception, in a geometrically consistent and reversible
+ fashion.
+
+ The changes are:
+
+ The Hunt-Pointer-Estevez matrix has been increased in precission by
+ 1 digit [Kuo, Zeise & Lai, IS&T/SID 14th Color Imaging Conference pp. 215-219]
+
+ The sharpened cone response matrix third row has been changed from
+ [0.0030, 0.0136, 0.9834] to [0.0000, 0.0000, 1.0000]
+ [Susstrunk & Brill, IS&T/SID 14th Color Imaging Conference Late Breaking News sublement]
+
+ To prevent wild Jab values as the rgb' values approach zero, a region close to each
+ primary ground plane is compressed. This expands the region of reasonable
+ behaviour to encompass XYZ values that are found in practice (ie. ProPhotoRGB).
+
+ To prevent excessive curvature of hue in high saturation blue regions
+ due to the non-linearity exagerating the difference between
+ r & b values, a heuristic is introduced that blends the r & b
+ values, reducing this effect. This degrades the agreement
+ with the reference CIECAM implementation by about 1DE in this region,
+ but greatly improves the behaviour in mapping and clipping from
+ highly saturated blues (ie. ProPhotoRGB).
+
+ The post-adaptation non-linearity response has had a straight
+ line negative linear extension added.
+ The positive region has a tangential linear extension added, so
+ that the range of values is not limited.
+ An adaptive threshold for the low level linear extension,
+ to avoid coordinates blowing up when one of the cone responses
+ is large, while the others become negative.
+
+ Re-arrange ss equation into separated effects,
+ k1, k2, k3, and then limit these to avoid divide by zero
+ and sign change errors in fwd and bwd converson, as well
+ as avoiding the blue saturation doubling back for low
+ luminance levels.
+
+ To avoid chroma and hue angle information being lost when the
+ J value used to scale the chroma is 0, and to ensure
+ that J = 0, a,b != 0 values have a valid mapping into
+ XYZ space, the J value used to multiply Chroma, is limited
+ to be equivalent to not less than A == 0.1.
+
+ The Helmholtz-Kohlraush effect is crafted to have resonable
+ effects over the range of J from 0 to 100, and have more
+ moderate effects outside this range.
+
+*/
+
+#include <copyright.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "icc.h"
+#include "xcam.h"
+#include "cam02.h"
+#include "numlib.h"
+
+#define ENABLE_COMPR /* [Def] Enable XYZ compression */
+#define ENABLE_BLUE_ANGLE_FIX /* [Def] Limit maximum blue angle */
+#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) */
+
+#undef ENTRACE /* [Undef] Enable internal value runtime tracing if s->trace != 0 */
+#undef DOTRACE /* [Undef] Trace anyway (ie. set s->trace = 1) */
+#undef DIAG1 /* [Undef] Print internal value diagnostics for conditions setup */
+#undef DIAG2 /* [Undef] Print internal value diagnostics for each conversion */
+#undef TRACKMINMAX /* [Undef] Track min/max DD & SS limits (run with locus cam02test) */
+#undef DISABLE_MATRIX /* Debug - disable matrix & non-lin, wire XYZ to rgba */
+#undef DISABLE_SCR /* Debug - disable Sharpened Cone Response matrix */
+#undef DISABLE_HPE /* Debug - disable just Hunt-Pointer_Estevez matrix */
+#undef DISABLE_NONLIN /* Debug - wire rgbp to rgba */
+#undef DISABLE_TTD /* Debug - disable ttd vector 'tilt' */
+#undef DISABLE_HHKR /* Debug - disable Helmholtz-Kohlraush */
+
+#ifdef ENABLE_COMPR
+# define BC_WHMINY 0.3 /* [0.3] Compression direction minimum Y value */
+# define BC_RANGE_R 0.01 /* [0.01] Set compression range as prop. of distance to neutral - red */
+# define BC_RANGE_G 0.05 /* [0.05] Set compression range as prop. of distance to neutral - green*/
+# define BC_RANGE_B 0.10 /* [0.10] Set compression range as prop. of distance to neutral - blue */
+# define BC_MAXRANGE 0.13 /* [0.13] Maximum compression range */
+# define BC_LIMIT 0.7 /* [0.7] Correction limit (abs. rgbp distance shift) */
+#endif /* ENABLE_COMPR */
+
+#ifdef ENABLE_BLUE_ANGLE_FIX
+# define BLUE_BL_MAX 0.9 /* [0.9] Sets ultimate blue angle, higher = less angle */
+# define BLUE_BL_POW 3.5 /* [3.5] Sets rate at which blue angle is limited */
+#endif
+
+#define NLDLIMIT 0.00001 /* [0.00001] Non-linearity minimum lower crossover to straight line */
+#define NLDICEPT -0.18 /* [-0.18] Input intercept of straight line with 0.1 output */
+
+#define NLULIMIT 1e5 /* Non-linearity upper crossover to straight line */
+
+#ifdef ENABLE_SS /* [Undef] */
+# define SSLLIMIT 0.22 /* Overall ab scale lower limit */
+# define SSULIMIT 580.0 /* Overall ab scale upper limit */
+#endif /* ENABLE_SS */
+
+#define SYMETRICJ /* [Undef] Use symetric power about zero, else straigt line -ve */
+
+#define DDLLIMIT 0.55 /* [0.55] ab component -k3:k2 ratio limit (must be < 1.0) */
+//#define DDULIMIT 0.9993 /* [0.9993] ab component k3:k1 ratio limit (must be < 1.0) */
+#define DDULIMIT 0.34 /* [0.34] ab component k3:k1 ratio limit (must be < 1.0) */
+#define SSMINcJ 0.005 /* [0.005] ab scale cJ minimum value */
+#define JLIMIT 0.005 /* [0.005] J encoding cutover point straight line (0 - 1.0 range) */
+#define HKLIMIT 0.7 /* [0.7] Maximum Helmholtz-Kohlraush lift */
+
+#ifdef TRACKMINMAX
+double minss = 1e60;
+double maxss = -1e60;
+double minlrat = 0.0;
+double maxurat = 0.0;
+#define noslots 103
+double slotsd[noslots];
+double slotsu[noslots];
+double minj = 1e38, maxj = -1e38;
+#endif /* TRACKMINMAX */
+
+#if defined(ENTRACE) || defined(DOTRACE)
+#define TRACE(xxxx) if (s->trace) printf xxxx ;
+#else
+#define TRACE(xxxx)
+#endif
+
+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 Fxyz[3],
+ int hk);
+static int XYZ_to_cam(struct _cam02 *s, double *Jab, double *xyz);
+static int cam_to_XYZ(struct _cam02 *s, double *xyz, double *Jab);
+
+static double spow(double val, double pp) {
+ if (val < 0.0)
+ return -pow(-val, pp);
+ else
+ return pow(val, 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");
+ exit(-1);
+ }
+
+ /* Initialise methods */
+ s->del = cam_free;
+ s->set_view = set_view;
+ s->XYZ_to_cam = XYZ_to_cam;
+ s->cam_to_XYZ = cam_to_XYZ;
+
+ /* Set default range handling limits */
+ s->nldlimit = NLDLIMIT;
+ s->nldicept = NLDICEPT;
+ s->nlulimit = NLULIMIT;
+ s->ddllimit = DDLLIMIT;
+ s->ddulimit = DDULIMIT;
+ s->ssmincj = SSMINcJ;
+ s->jlimit = JLIMIT;
+ s->hklimit = 1.0 / HKLIMIT;
+
+ /* Set a default viewing condition ?? */
+ /* set_view(s, vc_average, D50, 33, 0.2, 0.0, 0.0, D50, 0); */
+
+#ifdef DOTRACE
+ s->trace = 1;
+#endif
+
+#ifdef TRACKMINMAX
+ {
+ int i;
+ for (i = 0; i < noslots; i++) {
+ slotsd[i] = 0.0;
+ slotsu[i] = 0.0;
+ }
+ }
+#endif /* TRACKMINMAX */
+
+ return s;
+}
+
+static void cam_free(cam02 *s) {
+
+#ifdef TRACKMINMAX
+ {
+ int i;
+ for (i = 0; i < noslots; i++) {
+ printf("Slot %d = %f, %f\n",i,slotsd[i], slotsu[i]);
+ }
+ printf("minj = %f, maxj = %f\n",minj,maxj);
+
+ printf("minss = %f\n",minss);
+ printf("maxss = %f\n",maxss);
+ printf("minlrat = %f\n",minlrat);
+ printf("maxurat = %f\n",maxurat);
+ }
+#endif /* TRACKMINMAX */
+
+ if (s != NULL)
+ free(s);
+}
+
+/* Return value is always 0 */
+static int set_view(
+cam02 *s,
+ViewingCondition Ev, /* Enumerated Viewing Condition */
+double Wxyz[3], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+double La, /* Adapting/Surround Luminance cd/m^2 */
+double Yb, /* Relative Luminance of Background to reference white (range 0.0 .. 1.0) */
+double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set to other than vc_none */
+double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+double Fxyz[3], /* The Flare white coordinates (typically the Ambient color) */
+int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+) {
+ double tt, t1, t2;
+ double tm[3][3];
+ int i;
+
+ if (Ev == vc_none) {
+ /* Compute the internal parameters by interpolation */
+ int i;
+ double r, bf;
+ /* Dark, dim, average, above average */
+ double t_C[4] = { 0.525, 0.59, 0.69, 1.0 };
+ double t_Nc[4] = { 0.800, 0.95, 1.00, 1.0 };
+ double t_F[4] = { 0.800, 0.90, 1.00, 1.0 };
+
+ if (La < 1e-10) /* Hmm. */
+ La = 1e-10;
+ r = La/Lv;
+ if (r < 0.0)
+ r = 0.0;
+ else if (r > 1.0)
+ r = 1.0;
+
+ if (r < 0.1) { /* Dark to Dim */
+ i = 0;
+ bf = r/0.1;
+ } else if (r < 0.2) { /* Dim to Average */
+ i = 1;
+ bf = (r - 0.1)/0.1;
+ } else { /* Average to above average */
+ i = 2;
+ bf = (r - 0.2)/0.8;
+ }
+ s->C = t_C[i] * (1.0 - bf) + t_C[i+1] * bf;
+ s->Nc = t_Nc[i] * (1.0 - bf) + t_Nc[i+1] * bf;
+ s->F = t_F[i] * (1.0 - bf) + t_F[i+1] * bf;
+ } else {
+ /* Compute the internal parameters by category */
+ switch(Ev) {
+ case vc_dark:
+ s->C = 0.525;
+ s->Nc = 0.8;
+ s->F = 0.8;
+ break;
+ case vc_dim:
+ s->C = 0.59;
+ s->Nc = 0.95;
+ s->F = 0.9;
+ break;
+ case vc_cut_sheet:
+ s->C = 0.41;
+ s->Nc = 0.8;
+ s->F = 0.8;
+ break;
+ default: /* average */
+ s->C = 0.69;
+ s->Nc = 1.0;
+ s->F = 1.0;
+ break;
+ }
+ }
+
+ /* Transfer parameters to the object */
+ s->Ev = Ev;
+ s->Wxyz[0] = Wxyz[0];
+ s->Wxyz[1] = Wxyz[1];
+ s->Wxyz[2] = Wxyz[2];
+ s->Yb = Yb > 0.005 ? Yb : 0.005; /* Set minimum to avoid divide by 0.0 */
+ s->La = La;
+ s->Yf = Yf;
+ s->Fxyz[0] = Fxyz[0];
+ s->Fxyz[1] = Fxyz[1];
+ s->Fxyz[2] = Fxyz[2];
+ s->hk = hk;
+
+ /* The rgba vectors */
+ s->Va[0] = 1.0;
+ s->Va[1] = -12.0/11.0;
+ s->Va[2] = 1.0/11.0;
+
+ s->Vb[0] = 1.0/9.0;
+ s->Vb[1] = 1.0/9.0;
+ s->Vb[2] = -2.0/9.0;
+
+ s->VttA[0] = 2.0;
+ s->VttA[1] = 1.0;
+ s->VttA[2] = 1.0/20.0;
+
+ /* (Not used) */
+ s->Vttd[0] = 1.0;
+ s->Vttd[1] = 1.0;
+ s->Vttd[2] = 21.0/20.0;
+
+ /* Vttd in terms of the VttA, Va and Vb vectors */
+ s->dcomp[0] = 1.0;
+ s->dcomp[1] = -11.0/23.0;
+ s->dcomp[2] = -108.0/23.0;
+
+ /* Compute values that only change with viewing parameters */
+
+ /* Figure out the Flare contribution to the flareless XYZ input */
+ tt = s->Yf * s->Wxyz[1]/s->Fxyz[1];
+ s->Fsxyz[0] = tt * s->Fxyz[0];
+ s->Fsxyz[1] = tt * s->Fxyz[1];
+ s->Fsxyz[2] = tt * s->Fxyz[2];
+
+ /* Rescale so that the sum of the flare and the input doesn't exceed white */
+ s->Fsc = s->Wxyz[1]/(s->Fsxyz[1] + s->Wxyz[1]);
+ s->Fsxyz[0] *= s->Fsc;
+ s->Fsxyz[1] *= s->Fsc;
+ s->Fsxyz[2] *= s->Fsc;
+ s->Fisc = 1.0/s->Fsc;
+
+#ifndef DISABLE_SCR
+ /* Sharpened cone response white values */
+ s->rgbW[0] = 0.7328 * s->Wxyz[0] + 0.4296 * s->Wxyz[1] - 0.1624 * s->Wxyz[2];
+ s->rgbW[1] = -0.7036 * s->Wxyz[0] + 1.6975 * s->Wxyz[1] + 0.0061 * s->Wxyz[2];
+ s->rgbW[2] = 0.0000 * s->Wxyz[0] + 0.0000 * s->Wxyz[1] + 1.0000 * s->Wxyz[2];
+#else
+ s->rgbW[0] = s->Wxyz[0];
+ s->rgbW[1] = s->Wxyz[1];
+ s->rgbW[2] = s->Wxyz[2];
+#endif
+
+ /* Degree of chromatic adaptation */
+ s->D = s->F * (1.0 - exp((-s->La - 42.0)/92.0)/3.6);
+
+ /* Precompute Chromatic transform values */
+ s->Drgb[0] = s->D * (s->Wxyz[1]/s->rgbW[0]) + 1.0 - s->D;
+ s->Drgb[1] = s->D * (s->Wxyz[1]/s->rgbW[1]) + 1.0 - s->D;
+ s->Drgb[2] = s->D * (s->Wxyz[1]/s->rgbW[2]) + 1.0 - s->D;
+
+ /* Chromaticaly transformed white value */
+ s->rgbcW[0] = s->Drgb[0] * s->rgbW[0];
+ s->rgbcW[1] = s->Drgb[1] * s->rgbW[1];
+ s->rgbcW[2] = s->Drgb[2] * s->rgbW[2];
+
+#ifndef DISABLE_HPE
+ /* Transform from spectrally sharpened, to Hunt-Pointer_Estevez cone space */
+ s->rgbpW[0] = 0.7409744840453773 * s->rgbcW[0]
+ + 0.2180245944753982 * s->rgbcW[1]
+ + 0.0410009214792244 * s->rgbcW[2];
+ s->rgbpW[1] = 0.2853532916858801 * s->rgbcW[0]
+ + 0.6242015741188157 * s->rgbcW[1]
+ + 0.0904451341953042 * s->rgbcW[2];
+ s->rgbpW[2] = -0.0096276087384294 * s->rgbcW[0]
+ - 0.0056980312161134 * s->rgbcW[1]
+ + 1.0153256399545427 * s->rgbcW[2];
+#else
+ s->rgbpW[0] = s->rgbcW[0];
+ s->rgbpW[1] = s->rgbcW[1];
+ s->rgbpW[2] = s->rgbcW[2];
+#endif /* DISABLE_HPE */
+
+#ifndef DISABLE_SCR
+ /* Create combined cone and chromatic transform matrix: */
+ /* Spectrally sharpened cone responses matrix */
+ s->cc[0][0] = 0.7328; s->cc[0][1] = 0.4296; s->cc[0][2] = -0.1624;
+ s->cc[1][0] = -0.7036; s->cc[1][1] = 1.6975; s->cc[1][2] = 0.0061;
+ s->cc[2][0] = 0.0000; s->cc[2][1] = 0.0000; s->cc[2][2] = 1.0000;
+#else
+ s->cc[0][0] = 1.0; s->cc[0][1] = 0.0; s->cc[0][2] = 0.0;
+ s->cc[1][0] = 0.0; s->cc[1][1] = 1.0; s->cc[1][2] = 0.0;
+ s->cc[2][0] = 0.0; s->cc[2][1] = 0.0; s->cc[2][2] = 1.0;
+#endif
+
+ /* Chromaticaly transformed sample value */
+ icmSetUnity3x3(tm);
+ tm[0][0] = s->Drgb[0];
+ tm[1][1] = s->Drgb[1];
+ tm[2][2] = s->Drgb[2];
+ icmMul3x3(s->cc, tm);
+
+#ifndef DISABLE_HPE
+ /* Transform from spectrally sharpened, to Hunt-Pointer_Estevez cone space */
+ tm[0][0] = 0.7409744840453773;
+ tm[0][1] = 0.2180245944753982;
+ tm[0][2] = 0.0410009214792244;
+ tm[1][0] = 0.2853532916858801;
+ tm[1][1] = 0.6242015741188157;
+ tm[1][2] = 0.0904451341953042;
+ tm[2][0] = -0.0096276087384294;
+ tm[2][1] = -0.0056980312161134;
+ tm[2][2] = 1.0153256399545427;
+ icmMul3x3(s->cc, tm);
+#endif /* DISABLE_HPE */
+
+ /* Create inverse combined cone and chromatic transform matrix: */
+ icmInverse3x3(s->icc, s->cc); /* Hmm. we assume it cannot fail */
+
+#ifdef ENABLE_COMPR
+ /* Compression ranges */
+ s->crange[0] = BC_RANGE_R;
+ s->crange[1] = BC_RANGE_G;
+ s->crange[2] = BC_RANGE_B;
+#endif /* ENABLE_COMPR */
+
+ /* Background induction factor */
+ s->n = s->Yb/ s->Wxyz[1];
+ s->nn = pow(1.64 - pow(0.29, s->n), 0.73); /* Pre computed value */
+
+ /* Lightness contrast factor ?? */
+ {
+ double k;
+
+ k = 1.0 / (5.0 * s->La + 1.0);
+ s->Fl = 0.2 * pow(k , 4.0) * 5.0 * s->La
+ + 0.1 * pow(1.0 - pow(k , 4.0) , 2.0) * pow(5.0 * s->La , 1.0/3.0);
+ }
+
+ /* Background and Chromatic brightness induction factors */
+ s->Nbb = 0.725 * pow(1.0/s->n, 0.2);
+ s->Ncb = s->Nbb;
+
+ /* Base exponential nonlinearity */
+ s->z = 1.48 + pow(s->n , 0.5);
+
+ /* Post-adapted cone response of white */
+ tt = pow(s->Fl * s->rgbpW[0], 0.42);
+ s->rgbaW[0] = 400.0 * tt / (tt + 27.13) + 0.1;
+ tt = pow(s->Fl * s->rgbpW[1], 0.42);
+ s->rgbaW[1] = 400.0 * tt / (tt + 27.13) + 0.1;
+ tt = pow(s->Fl * s->rgbpW[2], 0.42);
+ s->rgbaW[2] = 400.0 * tt / (tt + 27.13) + 0.1;
+
+ /* Achromatic response of white */
+ s->Aw = (s->VttA[0] * s->rgbaW[0]
+ + s->VttA[1] * s->rgbaW[1]
+ + s->VttA[2] * s->rgbaW[2] - 0.305) * s->Nbb;
+
+ /* Non-linearity lower crossover output value */
+ tt = pow(s->Fl * s->nldlimit, 0.42);
+ s->nldxval = 400.0 * tt / (tt + 27.13) + 0.1;
+
+ /* Non-linearity lower crossover slope from lower crossover */
+ /* to intercept with 0.1 output */
+ s->nldxslope = (s->nldxval - 0.1)/(s->nldlimit - s->nldicept);
+
+ /* Non-linearity upper crossover value */
+ tt = pow(s->Fl * s->nlulimit, 0.42);
+ s->nluxval = 400.0 * tt / (tt + 27.13) + 0.1;
+
+ /* Non-linearity upper crossover slope, set to asymtope */
+ t1 = s->Fl * s->nlulimit;
+ t2 = pow(t1, 0.42) + 27.13;
+ s->nluxslope = 0.42 * s->Fl * 400.0 * 27.13 / (pow(t1,0.58) * t2 * t2);
+
+
+ /* Limited A value at J = JLIMIT */
+ s->lA = pow(s->jlimit, 1.0/(s->C * s->z)) * s->Aw;
+
+#ifdef DIAG1
+ printf("Scene parameters:\n");
+ printf("Viewing condition Ev = %d\n",s->Ev);
+ printf("Ref white Wxyz = %f %f %f\n", s->Wxyz[0], s->Wxyz[1], s->Wxyz[2]);
+ printf("Relative liminance of background Yb = %f\n", s->Yb);
+ printf("Adapting liminance La = %f\n", s->La);
+ printf("Flare Yf = %f\n", s->Yf);
+ printf("Flare color Fxyz = %f %f %f\n", s->Fxyz[0], s->Fxyz[1], s->Fxyz[2]);
+
+ printf("Internal parameters:\n");
+ printf("Surround Impact C = %f\n", s->C);
+ printf("Chromatic Induction Nc = %f\n", s->Nc);
+ printf("Adaptation Degree F = %f\n", s->F);
+
+ printf("Pre-computed values\n");
+ printf("Sharpened cone white rgbW = %f %f %f\n", s->rgbW[0], s->rgbW[1], s->rgbW[2]);
+ printf("Degree of chromatic adaptation D = %f\n", s->D);
+ printf("Chromatic transform values Drgb = %f %f %f\n", s->Drgb[0], s->Drgb[1], s->Drgb[2]);
+ printf("Chromatically transformed white rgbcW = %f %f %f\n", s->rgbcW[0], s->rgbcW[1], s->rgbcW[2]);
+ printf("Hunter-P-E cone response white rgbpW = %f %f %f\n", s->rgbpW[0], s->rgbpW[1], s->rgbpW[2]);
+ printf("Background induction factor n = %f\n", s->n);
+ printf(" nn = %f\n", s->nn);
+ printf("Lightness contrast factor Fl = %f\n", s->Fl);
+ printf("Background brightness induction factor Nbb = %f\n", s->Nbb);
+ printf("Chromatic brightness induction factor Ncb = %f\n", s->Ncb);
+ printf("Base exponential nonlinearity z = %f\n", s->z);
+ printf("Post adapted cone response white rgbaW = %f %f %f\n", s->rgbaW[0], s->rgbaW[1], s->rgbaW[2]);
+ printf("Achromatic response of white Aw = %f\n", s->Aw);
+ printf("\n");
+#endif
+ return 0;
+}
+
+/* Conversions. Return values are always 0 */
+static int XYZ_to_cam(
+struct _cam02 *s,
+double Jab[3],
+double XYZ[3]
+) {
+ int i;
+ double xyz[3], rgbp[3], rgba[3];
+ double a, b, ja, jb, J, JJ, C, h, e, A, ss;
+ double ttA, rS, cJ, tt;
+ double k1, k2, k3;
+ int clip = 0;
+
+#ifdef DIAG2 /* Incase in == out */
+ double XYZi[3];
+
+ XYZi[0] = XYZ[0];
+ XYZi[1] = XYZ[1];
+ XYZi[2] = XYZ[2];
+#endif
+
+ TRACE(("\nForward conversion:\n"))
+ TRACE(("XYZ = %f %f %f\n",XYZ[0], XYZ[1], XYZ[2]))
+
+#ifdef DISABLE_MATRIX
+
+ rgba[0] = XYZ[0];
+ rgba[1] = XYZ[1];
+ rgba[2] = XYZ[2];
+
+#else /* !DISABLE_MATRIX */
+
+ /* Add in flare */
+ xyz[0] = s->Fsc * XYZ[0] + s->Fsxyz[0];
+ xyz[1] = s->Fsc * XYZ[1] + s->Fsxyz[1];
+ xyz[2] = s->Fsc * XYZ[2] + s->Fsxyz[2];
+
+ TRACE(("XYZ inc flare = %f %f %f\n",xyz[0], xyz[1], xyz[2]))
+
+ /* Spectrally sharpened cone responses, */
+ /* Chromaticaly transformed sample value, */
+ /* Transform from spectrally sharpened, to Hunt-Pointer_Estevez cone space. */
+ icmMulBy3x3(rgbp, s->cc, xyz);
+
+ TRACE(("rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]))
+
+#ifdef ENABLE_COMPR
+ /* Try and prevent crazy out of cam02 gamut behaviour, by compressing */
+ /* the rgbp so as to prevent it becoming less than zero. */
+ {
+ double tt; /* Temporary */
+ double wrgb[3]; /* White target */
+
+ /* Make white target white point with same Y value */
+ tt = xyz[1] > BC_WHMINY ? xyz[1] : BC_WHMINY; /* Limit to minimum Y */
+ icmScale3(wrgb, s->rgbpW, tt/s->Wxyz[1]); /* White target at same Y */
+ TRACE(("wrgb %f %f %f\n", wrgb[0], wrgb[1], wrgb[2]))
+
+ /* Compress r,g,b in turn */
+ for (i = 0; i < 3; i++) {
+ double cv; /* Compression value */
+ double ctv; /* Compression target value */
+ double cd; /* Compression displacement needed */
+ double cvec[3]; /* Normalized correction vector */
+ double isec[3]; /* Intersection with plane */
+ double offs; /* Offset of point from orgin*/
+ double range; /* Threshold to start compression */
+ double asym; /* Compression asymtope */
+
+ /* Compute compression direction as vector towards white */
+ /* (We did try correcting in a blend of limit plane normal and white, */
+ /* but compressing towards white seems to be the best.) */
+ icmSub3(cvec, wrgb, rgbp); /* Direction of white target */
+
+ TRACE(("rgbp %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]))
+ TRACE(("cvec %f %f %f\n", cvec[0], cvec[1], cvec[2]))
+
+ if (cvec[i] < 1e-9) { /* compression direction can't correct this coord */
+ TRACE(("Intersection with limit plane failed\n"))
+ continue;
+ }
+
+ /* Scale compression vector to make it move a unit in normal direction */
+ icmScale3(cvec, cvec, 1.0/cvec[i]); /* Normalized vector to white */
+ TRACE(("cvec %f %f %f\n", cvec[0], cvec[1], cvec[2]))
+
+ /* Compute intersection of correction direction with this limit plane */
+ /* (This corresponds with finding displacement of rgbp by cvec */
+ /* such that the current coord value = 0) */
+ icmScale3(isec, cvec, -rgbp[i]); /* (since cvec[i] == 1.0) */
+ icmAdd3(isec, isec, rgbp);
+ TRACE(("isec %f %f %f\n", isec[0], isec[1], isec[2]))
+
+ /* Compute distance from intersection to origin */
+ offs = pow(icmNorm3(isec), 0.85);
+
+ range = s->crange[i] * offs; /* Scale range by distance to origin */
+ if (range > BC_MAXRANGE) /* so that it tapers down as we approach it */
+ range = BC_MAXRANGE; /* and limit maximum */
+
+ /* Aiming above plane when far from origin, */
+ /* but below plane at the origin, so that black isn't affected. */
+ asym = range - 0.2 * (range + (0.01 * s->crange[i]));
+
+ ctv = cv = rgbp[i]; /* Distance above/below limit plane */
+
+ TRACE(("ch %d, offs %f, range %f asym %f, cv %f\n",i, offs,range,asym,cv))
+ if (cv < (range - 1e-12)) { /* Need to compress */
+ double aa, bb;
+ aa = 1.0/(range - cv);
+ bb = 1.0/(range - asym);
+ ctv = range - 1.0/(aa + bb);
+
+ cd = ctv - cv; /* Displacement needed */
+ if (cd > BC_LIMIT)
+ cd = BC_LIMIT;
+ TRACE(("ch %d cd = %f, scaled cd %f\n",i,cd,cd))
+
+ /* Apply correction */
+ icmScale3(cvec, cvec, cd); /* Compression vector */
+ icmAdd3(rgbp, rgbp, cvec); /* Compress by displacement */
+ TRACE(("rgbp after comp. = %f %f %f\n",rgbp[0], rgbp[1], rgbp[2]))
+ }
+ }
+ }
+#endif /* ENABLE_COMPR */
+
+#ifdef ENABLE_BLUE_ANGLE_FIX
+ ss = rgbp[0] + rgbp[1] + rgbp[2];
+ if (ss < 1e-9) {
+ ss = 0.0;
+ } else {
+ ss = (rgbp[2]/ss - 1.0/3.0) * 3.0/2.0;
+ if (ss > 0.0)
+ ss = BLUE_BL_MAX * pow(ss, BLUE_BL_POW);
+ }
+ if (ss < 0.0)
+ ss = 0.0;
+ else if (ss > 1.0)
+ ss = 1.0;
+ tt = 0.5 * (rgbp[0] + rgbp[1]);
+ 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]))
+#endif
+
+#ifdef DISABLE_NONLIN
+ for (i = 0; i < 3; i++) {
+ rgba[i] = 400.0/27.13 * rgbp[i];
+ }
+#else /* !DISABLE_NONLIN */
+ /* Post-adapted cone response of sample. */
+ /* rgba[] has a minimum value of 0.1 for XYZ[] = 0 and no flare. */
+ /* We add a negative linear region, plus a linear segment at */
+ /* the end of the +ve conversion to allow numerical handling of a */
+ /* very wide range of values. */
+
+ for (i = 0; i < 3; i++) {
+ if (rgbp[i] < s->nldlimit) {
+ rgba[i] = s->nldxval + s->nldxslope * (rgbp[i] - s->nldlimit);
+ } else {
+ if (rgbp[i] <= s->nlulimit) {
+ tt = pow(s->Fl * rgbp[i], 0.42);
+ rgba[i] = 400.0 * tt / (tt + 27.13) + 0.1;
+ } else {
+ rgba[i] = s->nluxval + s->nluxslope * (rgbp[i] - s->nlulimit);
+ }
+ }
+ }
+#endif /* !DISABLE_NONLIN */
+
+//tt = 0.5 * (rgba[0] + rgba[1]);
+//rgba[0] = (rgba[0] - ss * tt)/(1.0 - ss);
+//rgba[1] = (rgba[1] - ss * tt)/(1.0 - ss);
+
+#endif /* !DISABLE_MATRIX */
+
+ /* Note that the minimum values of rgba[] for XYZ = 0 is 0.1, */
+ /* hence magic 0.305 below comes from the following weighting of rgba[], */
+ /* to base A at 0.0 */
+ /* Deal with the core rgb to A, S & h conversion: */
+
+ TRACE(("rgba = %f %f %f\n", rgba[0], rgba[1], rgba[2]))
+
+ /* Preliminary Acromatic response */
+ ttA = s->VttA[0] * rgba[0] + s->VttA[1] * rgba[1] + s->VttA[2] * rgba[2];
+
+ /* Achromatic response */
+ A = (ttA - 0.305) * s->Nbb;
+
+ /* Preliminary red-green & yellow-blue opponent dimensions */
+ /* a, b & ttd form an (almost) orthogonal coordinate set. */
+ /* ttA is in a different direction */
+ a = s->Va[0] * rgba[0] + s->Va[1] * rgba[1] + s->Va[2] * rgba[2];
+ b = s->Vb[0] * rgba[0] + s->Vb[1] * rgba[1] + s->Vb[2] * rgba[2];
+
+ /* restricted Saturation to stop divide by zero */
+ /* (The exact value isn't important because the numerator dominates as a,b aproach 0 */
+ rS = sqrt(a * a + b * b);
+ if (rS < DBL_EPSILON)
+ rS = DBL_EPSILON;
+ TRACE(("ttA = %f, a = %f, b = %f, rS = %f, A = %f\n", ttA,a,b,rS,A))
+
+ /* Lightness J, Derived directly from Acromatic response. */
+ /* Cuttover to a straight line segment when J < 0.005, */
+#ifndef SYMETRICJ /* Cut to a straight line */
+ if (A >= s->lA) {
+ J = pow(A/s->Aw, s->C * s->z); /* J/100 - keep Sign */
+ } else {
+ J = s->jlimit/s->lA * A; /* Straight line */
+ TRACE(("limited Acromatic to straight line\n"))
+ }
+#else /* Symetric */
+ if (A >= 0.0) {
+ J = pow(A/s->Aw, s->C * s->z); /* J/100 - keep Sign */
+ } else {
+ J = -pow(-A/s->Aw, s->C * s->z); /* J/100 - keep Sign */
+ TRACE(("symetric Acromatic\n"))
+ }
+#endif
+
+ /* Constraied (+ve, non-zero) J */
+ if (A > 0.0) {
+ cJ = pow(A/s->Aw, s->C * s->z);
+ if (cJ < s->ssmincj)
+ cJ = s->ssmincj;
+ } else {
+ cJ = s->ssmincj;
+ }
+
+ TRACE(("J = %f, cJ = %f\n",J,cJ))
+
+ /* Final hue angle */
+ h = (180.0/DBL_PI) * atan2(b,a);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ /* Eccentricity factor */
+ e = (12500.0/13.0 * s->Nc * s->Ncb * (cos(h * DBL_PI/180.0 + 2.0) + 3.8));
+
+ /* ab scale components */
+ k1 = pow(s->nn, 1.0/0.9) * e * pow(cJ, 1.0/1.8)/pow(rS, 1.0/9.0);
+ k2 = pow(cJ, 1.0/(s->C * s->z)) * s->Aw/s->Nbb + 0.305;
+ k3 = s->dcomp[1] * a + s->dcomp[2] * b;
+
+ TRACE(("Raw k1 = %f, k2 = %f, k3 = %f, raw ss = %f\n",k1, k2, k3, pow(k1/(k2 + k3), 0.9)))
+
+#ifdef TRACKMINMAX
+ {
+ int sno;
+ double lrat, urat;
+
+ ss = pow(k1/(k2 + k3), 0.9);
+
+ if (ss < minss)
+ minss = ss;
+ if (ss > maxss)
+ maxss = ss;
+
+ lrat = -k3/k2;
+ urat = k3 * pow(ss, 10.0/9.0) / k1;
+ if (lrat > minlrat)
+ minlrat = lrat;
+ if (urat > maxurat)
+ maxurat = urat;
+
+ /* Record distribution of ss min/max vs. J for */
+ /* regions outside a,b == 0 */
+
+ sno = (int)(J * 100.0 + 0.5);
+ if (sno < 0) {
+ sno = 101;
+ if (J < minj)
+ minj = J;
+ } else if (sno > 100) {
+ sno = 102;
+ if (J > maxj)
+ maxj = J;
+ }
+ if (slotsd[sno] < lrat)
+ slotsd[sno] = lrat;
+ if (slotsu[sno] < urat)
+ slotsu[sno] = urat;
+ }
+#endif /* TRACKMINMAX */
+
+#ifdef ENABLE_DDL
+
+ /* Limit ratio of k3 to k2 to stop zero or -ve ss */
+ if (k3 < -k2 * s->ddllimit) {
+ k3 = -k2 * s->ddllimit;
+ TRACE(("k3 limited to %f due to k3:k2 ratio, ss = %f\n",k3,pow(k1/(k2 + k3), 0.9)))
+ clip = 1;
+ }
+
+ /* See if there is going to be a problem in bwd, and limit k3 if there is */
+ if (k3 > (k2 * s->ddulimit/(1.0 - s->ddulimit))) {
+ k3 = (k2 * s->ddulimit/(1.0 - s->ddulimit));
+ TRACE(("k3 limited to %f to allow for bk3:bk1 bwd limit\n",k3))
+ clip = 1;
+ }
+
+#endif /* !ENABLE_DDL */
+
+#ifdef DISABLE_TTD
+
+ ss = pow((k1/k2), 0.9);
+
+#else /* !TRACKMINMAX */
+
+ /* Compute the ab scale factor */
+ ss = pow(k1/(k2 + k3), 0.9);
+
+#endif /* !ENABLE_DDL */
+
+#ifdef ENABLE_SS
+ if (ss < SSLLIMIT)
+ ss = SSLLIMIT;
+ else if (ss > SSULIMIT)
+ ss = SSULIMIT;
+#endif /* ENABLE_SS */
+
+#ifdef NEVER
+// -------------------------------------------
+ /* Show ss components */
+ if (s->retss) {
+ Jab[0] = 1.0;
+ if (clip)
+ Jab[0] = 0.0;
+ Jab[1] = (log10(ss) - +1.5)/(2.0 - +1.5);
+ Jab[2] = (log10(ss) - +1.0)/(2.5 - +1.0);
+
+ for (i = 0; i < 3; i++) {
+ if (Jab[i] < 0.0)
+ Jab[i] = 0.0;
+ else if (Jab[i] > 1.0)
+ Jab[i] = 1.0;
+ }
+ return 0;
+ }
+// -------------------------------------------
+#endif /* NEVER */
+
+ ja = a * ss;
+ jb = b * ss;
+
+ /* Chroma - always +ve, used just for HHKR */
+ C = sqrt(ja * ja + jb * jb);
+
+ TRACE(("ss = %f, A = %f, J = %f, C = %f, h = %f\n",ss,A,J,C,h))
+
+ JJ = J;
+#ifndef DISABLE_HHKR
+ /* Helmholtz-Kohlraush effect */
+ if (s->hk && J < 1.0) {
+ double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ if (kk > 1e-6) /* Limit kk to a reasonable range */
+ kk = 1.0/(s->hklimit + 1.0/kk);
+ JJ = J + (1.0 - (J > 0.0 ? J : 0.0)) * kk;
+ TRACE(("JJ = %f from J = %f, kk = %f\n",JJ,J,kk))
+ }
+#endif /* DISABLE_HHKR */
+
+ JJ *= 100.0; /* Scale J */
+
+ /* Compute Jab value */
+ Jab[0] = JJ;
+ Jab[1] = ja;
+ Jab[2] = jb;
+
+#ifdef NEVER /* Brightness/Colorfulness */
+ {
+ double M, Q;
+
+ Q = (4.0/s->C) * sqrt(JJ/100.0) * (s->Aw + 4.0) * pow(s->Fl, 0.25);
+ M = C * pow(s->Fl, 0.25);
+
+ printf("Lightness = %f, Chroma = %f\n",J,C);
+ printf("Brightness = %f, Colorfulness = %f\n",M,Q);
+ }
+#endif /* NEVER */
+
+ TRACE(("Jab %f %f %f\n",Jab[0], Jab[1], Jab[2]))
+ TRACE(("\n"))
+
+#ifdef DIAG2
+ printf("Processing XYZ->Jab:\n");
+ printf("XYZ = %f %f %f\n", XYZi[0], XYZi[1], XYZi[2]);
+ printf("Including flare XYZ = %f %f %f\n", xyz[0], xyz[1], xyz[2]);
+ printf("Huntpace rgbpP-E cone space rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]);
+ printf("Post adapted cone response rgba = %f %f %f\n", rgba[0], rgba[1], rgba[2]);
+ printf("Prelim red green a = %f, b = %f\n", a, b);
+ printf("Hue angle h = %f\n", h);
+ printf("Eccentricity factor e = %f\n", e);
+ printf("Achromatic response A = %f\n", A);
+ printf("Lightness J = %f, H.K. Lightness = %f\n", J * 100, JJ);
+ printf("Prelim Saturation ss = %f\n", ss);
+ printf("Chroma C = %f\n", C);
+ printf("Jab = %f %f %f\n", Jab[0], Jab[1], Jab[2]);
+ printf("\n");
+#endif
+ return 0;
+}
+
+static int cam_to_XYZ(
+struct _cam02 *s,
+double XYZ[3],
+double Jab[3]
+) {
+ int i;
+ double xyz[3], rgbp[3], rgba[3];
+ double a, b, ja, jb, J, JJ, C, rC, h, e, A, ss;
+ double tt, cJ, ttA;
+ double k1, k2, k3; /* (k1 & k3 are different to the fwd k1 & k3) */
+
+#ifdef DIAG2 /* Incase in == out */
+ double Jabi[3];
+
+ Jabi[0] = Jab[0];
+ Jabi[1] = Jab[1];
+ Jabi[2] = Jab[2];
+
+#endif
+
+ TRACE(("\nReverse conversion:\n"))
+ TRACE(("Jab %f %f %f\n",Jab[0], Jab[1], Jab[2]))
+
+ JJ = Jab[0] * 0.01; /* J/100 */
+ ja = Jab[1];
+ jb = Jab[2];
+
+ /* Convert Jab to core A, S & h values: */
+
+ /* Compute hue angle */
+ h = (180.0/DBL_PI) * atan2(jb, ja);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ /* Compute chroma value */
+ C = sqrt(ja * ja + jb * jb); /* Must be Always +ve, Can be NZ even if J == 0 */
+
+ /* Preliminary Restricted chroma, always +ve and NZ */
+ /* (The exact value isn't important because the numerator dominates as a,b aproach 0) */
+ rC = C;
+ if (rC < DBL_EPSILON)
+ rC = DBL_EPSILON;
+
+ J = JJ;
+#ifndef DISABLE_HHKR
+ /* Undo Helmholtz-Kohlraush effect */
+ if (s->hk && J < 1.0) {
+ double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ if (kk > 1e-6) /* Limit kk to a reasonable range */
+ kk = 1.0/(s->hklimit + 1.0/kk);
+ J = (JJ - kk)/(1.0 - kk);
+ if (J < 0.0)
+ J = JJ - kk;
+ TRACE(("J = %f from JJ = %f, kk = %f\n",J,JJ,kk))
+ }
+#endif /* DISABLE_HHKR */
+
+ /* Achromatic response */
+#ifndef SYMETRICJ /* Cut to a straight line */
+ if (J >= s->jlimit) {
+ A = pow(J, 1.0/(s->C * s->z)) * s->Aw;
+ } else { /* In the straight line segment */
+ A = s->lA/s->jlimit * J;
+ TRACE(("Undo Acromatic straight line\n"))
+ }
+#else /* Symetric */
+ if (J >= 0.0) {
+ A = pow(J, 1.0/(s->C * s->z)) * s->Aw;
+ } else { /* In the straight line segment */
+ A = -pow(-J, 1.0/(s->C * s->z)) * s->Aw;
+ TRACE(("Undo symetric Acromatic\n"))
+ }
+#endif
+
+ /* Preliminary Acromatic response +ve */
+ ttA = (A/s->Nbb)+0.305;
+
+ if (A > 0.0) {
+ cJ = pow(A/s->Aw, s->C * s->z);
+ if (cJ < s->ssmincj)
+ cJ = s->ssmincj;
+ } else {
+ cJ = s->ssmincj;
+ }
+ TRACE(("C = %f, A = %f from J = %f, cJ = %f\n",C, A,J,cJ))
+
+ /* Eccentricity factor */
+ e = (12500.0/13.0 * s->Nc * s->Ncb * (cos(h * DBL_PI/180.0 + 2.0) + 3.8));
+
+ /* ab scale components */
+ k1 = pow(s->nn, 1.0/0.9) * e * pow(cJ, 1.0/1.8)/pow(rC, 1.0/9.0);
+ k2 = pow(cJ, 1.0/(s->C * s->z)) * s->Aw/s->Nbb + 0.305;
+ k3 = s->dcomp[1] * ja + s->dcomp[2] * jb;
+
+ TRACE(("Raw k1 = %f, k2 = %f, k3 = %f, raw ss = %f\n",k1, k2, k3, (k1 - k3)/k2))
+
+#ifdef ENABLE_DDL
+
+ /* Limit ratio of k3 to k1 to stop zero or -ve ss */
+ if (k3 > (k1 * s->ddulimit)) {
+ k3 = k1 * s->ddulimit;
+ TRACE(("k3 limited to %f due to k3:k1 ratio, ss = %f\n",k3,(k1 - k3)/k2))
+ }
+
+ /* See if there is going to be a problem in fwd */
+ if (k3 < -k1 * s->ddllimit/(1.0 - s->ddllimit)) {
+ /* Adjust ss to allow for fwd limitd computation */
+ k3 = -k1 * s->ddllimit/(1.0 - s->ddllimit);
+ TRACE(("k3 set to %f to allow for fk3:fk2 fwd limit\n",k3))
+ }
+
+#endif /* ENABLE_DDL */
+
+#ifdef DISABLE_TTD
+
+ ss = k1/k2;
+
+#else /* !DISABLE_TTD */
+
+ /* Compute the ab scale factor */
+ ss = (k1 - k3)/k2;
+
+#endif /* !DISABLE_TTD */
+
+#ifdef ENABLE_SS
+ if (ss < SSLLIMIT)
+ ss = SSLLIMIT;
+ else if (ss > SSULIMIT)
+ ss = SSULIMIT;
+#endif /* ENABLE_SS */
+
+ /* Unscale a and b */
+ a = ja / ss;
+ b = jb / ss;
+
+ TRACE(("ss = %f, ttA = %f, a = %f, b = %f\n",ss,ttA,a,b))
+
+ /* Solve for post-adapted cone response of sample */
+ /* using inverse matrix on ttA, a, b */
+ rgba[0] = (20.0/61.0) * ttA
+ + ((41.0 * 11.0)/(61.0 * 23.0)) * a
+ + ((288.0 * 1.0)/(61.0 * 23.0)) * b;
+ rgba[1] = (20.0/61.0) * ttA
+ - ((81.0 * 11.0)/(61.0 * 23.0)) * a
+ - ((261.0 * 1.0)/(61.0 * 23.0)) * b;
+ rgba[2] = (20.0/61.0) * ttA
+ - ((20.0 * 11.0)/(61.0 * 23.0)) * a
+ - ((20.0 * 315.0)/(61.0 * 23.0)) * b;
+
+ TRACE(("rgba %f %f %f\n",rgba[0], rgba[1], rgba[2]))
+
+#ifdef DISABLE_MATRIX
+
+ XYZ[0] = rgba[0];
+ XYZ[1] = rgba[1];
+ XYZ[2] = rgba[2];
+
+#else /* !DISABLE_MATRIX */
+
+#ifdef DISABLE_NONLIN
+ rgbp[0] = 27.13/400.0 * rgba[0];
+ rgbp[1] = 27.13/400.0 * rgba[1];
+ rgbp[2] = 27.13/400.0 * rgba[2];
+#else /* !DISABLE_NONLIN */
+
+ /* Hunt-Pointer_Estevez cone space */
+ /* (with linear segment at the +ve end) */
+ for (i = 0; i < 3; i++) {
+ if (rgba[i] < s->nldxval) {
+ rgbp[i] = s->nldlimit + (rgba[i] - s->nldxval)/s->nldxslope;
+ } else if (rgba[i] <= s->nluxval) {
+ tt = rgba[i] - 0.1;
+ rgbp[i] = pow((27.13 * tt)/(400.0 - tt), 1.0/0.42)/s->Fl;
+// rgbp[i] = pow((27.13 * tt)/(400.0 - tt), 1.0/1.0)/s->Fl;
+ } else {
+ rgbp[i] = s->nlulimit + (rgba[i] - s->nluxval)/s->nluxslope;
+ }
+ }
+#endif /* !DISABLE_NONLIN */
+
+ TRACE(("rgbp %f %f %f\n",rgbp[0], rgbp[1], rgbp[2]))
+
+#ifdef ENABLE_BLUE_ANGLE_FIX
+ ss = rgbp[0] + rgbp[1] + rgbp[2];
+ if (ss < 1e-9)
+ ss = 0.0;
+ else {
+ ss = (rgbp[2]/ss - 1.0/3.0) * 3.0/2.0;
+ if (ss > 0.0)
+ ss = BLUE_BL_MAX * pow(ss, BLUE_BL_POW);
+ }
+ if (ss < 0.0)
+ ss = 0.0;
+ else if (ss > 1.0)
+ ss = 1.0;
+ tt = 0.5 * (rgbp[0] + rgbp[1]);
+ rgbp[0] = (rgbp[0] - ss * tt)/(1.0 - ss);
+ rgbp[1] = (rgbp[1] - ss * tt)/(1.0 - ss);
+
+ TRACE(("rgbp after blue fix %f = %f %f %f\n",ss,rgbp[0], rgbp[1], rgbp[2]))
+#endif
+
+
+#ifdef ENABLE_COMPR
+ /* Undo soft limiting */
+ {
+ double tt; /* Temporary */
+ double wrgb[3]; /* White target */
+
+ /* Make white target white point with same Y value */
+ tt = rgbp[0] * s->icc[1][0] + rgbp[1] * s->icc[1][1] + rgbp[2] * s->icc[1][2];
+ tt = tt > BC_WHMINY ? tt : BC_WHMINY; /* Limit to minimum Y */
+ icmScale3(wrgb, s->rgbpW, tt/s->Wxyz[1]); /* White target at same Y */
+ TRACE(("wrgb %f %f %f\n", wrgb[0], wrgb[1], wrgb[2]))
+
+ /* Un-limit b,g,r in turn */
+ for (i = 2; i >= 0; i--) {
+ double cv; /* Compression value */
+ double ctv; /* Compression target value */
+ double cd; /* Compression displacement needed */
+ double cvec[3]; /* Normalized correction vector */
+ double isec[3]; /* Intersection with plane */
+ double offs; /* Offset of point from orgin*/
+ double range; /* Threshold to start compression */
+ double asym; /* Compression asymtope */
+
+ /* Compute compression direction as vector towards white */
+ /* (We did try correcting in a blend of limit plane normal and white, */
+ /* but compressing towards white seems to be the best.) */
+ icmSub3(cvec, wrgb, rgbp); /* Direction of white target */
+
+ TRACE(("rgbp %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]))
+ TRACE(("cvec %f %f %f\n", cvec[0], cvec[1], cvec[2]))
+
+ if (cvec[i] < 1e-9) { /* compression direction can't correct this coord */
+ TRACE(("Intersection with limit plane failed\n"))
+ continue;
+ }
+
+ /* Scale compression vector to make it move a unit in normal direction */
+ icmScale3(cvec, cvec, 1.0/cvec[i]); /* Normalized vector to white */
+ TRACE(("cvec %f %f %f\n", cvec[0], cvec[1], cvec[2]))
+
+ /* Compute intersection of correction direction with this limit plane */
+ /* (This corresponds with finding displacement of rgbp by cvec */
+ /* such that the current coord value = 0) */
+ icmScale3(isec, cvec, -rgbp[i]); /* (since cvec[i] == 1.0) */
+ icmAdd3(isec, isec, rgbp);
+ TRACE(("isec %f %f %f\n", isec[0], isec[1], isec[2]))
+
+ /* Compute distance from intersection to origin */
+ offs = pow(icmNorm3(isec), 0.85);
+
+ range = s->crange[i] * offs; /* Scale range by distance to origin */
+ if (range > BC_MAXRANGE) /* so that it tapers down as we approach it */
+ range = BC_MAXRANGE; /* and limit maximum */
+
+ /* Aiming above plane when far from origin, */
+ /* but below plane at the origin, so that black isn't affected. */
+ asym = range - 0.2 * (range + (0.01 * s->crange[i]));
+
+ ctv = cv = rgbp[i]; /* Distance above/below limit plane */
+
+ TRACE(("ch %d, offs %f, range %f asym %f, cv %f\n",i, offs,range,asym,cv))
+
+ if (ctv < (range - 1e-12)) { /* Need to expand */
+
+ if (ctv <= asym) {
+ cd = BC_LIMIT;
+ TRACE(("ctv %f < asym %f\n",ctv,asym))
+ } else {
+ double aa, bb;
+ aa = 1.0/(range - ctv);
+ bb = 1.0/(range - asym);
+ if (aa > (bb + 1e-12))
+ cv = range - 1.0/(aa - bb);
+ cd = ctv - cv; /* Displacement needed */
+ }
+ if (cd > BC_LIMIT)
+ cd = BC_LIMIT;
+ TRACE(("ch %d cd = %f, scaled cd %f\n",i,cd,cd))
+
+ if (cd > 1e-9) {
+ icmScale3(cvec, cvec, -cd); /* Compression vector */
+ icmAdd3(rgbp, rgbp, cvec); /* Compress by displacement */
+ TRACE(("rgbp after decomp. = %f %f %f\n",rgbp[0], rgbp[1], rgbp[2]))
+ }
+ }
+ }
+ }
+#endif /* ENABLE_COMPR */
+
+ /* Chromaticaly transformed sample value */
+ /* Spectrally sharpened cone responses */
+ /* XYZ values */
+ icmMulBy3x3(xyz, s->icc, rgbp);
+
+ TRACE(("XYZ = %f %f %f\n",xyz[0], xyz[1], xyz[2]))
+
+ /* Subtract flare */
+ XYZ[0] = s->Fisc * (xyz[0] - s->Fsxyz[0]);
+ XYZ[1] = s->Fisc * (xyz[1] - s->Fsxyz[1]);
+ XYZ[2] = s->Fisc * (xyz[2] - s->Fsxyz[2]);
+
+#endif /* !DISABLE_MATRIX */
+
+ TRACE(("XYZ after flare = %f %f %f\n",XYZ[0], XYZ[1], XYZ[2]))
+ TRACE(("\n"))
+
+#ifdef DIAG2
+ printf("Processing:\n");
+ printf("Jab = %f %f %f\n", Jabi[0], Jabi[1], Jabi[2]);
+ printf("Chroma C = %f\n", C);
+ printf("Preliminary Saturation ss = %f\n", ss);
+ printf("Lightness J = %f, H.K. Lightness = %f\n", J * 100, JJ * 100);
+ printf("Achromatic response A = %f\n", A);
+ printf("Eccentricity factor e = %f\n", e);
+ printf("Hue angle h = %f\n", h);
+ printf("Post adapted cone response rgba = %f %f %f\n", rgba[0], rgba[1], rgba[2]);
+ printf("Hunundeft-P-E cone space rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]);
+ printf("Including flare XYZ = %f %f %f\n", xyz[0], xyz[1], xyz[2]);
+ printf("XYZ = %f %f %f\n", XYZ[0], XYZ[1], XYZ[2]);
+ printf("\n");
+#endif
+ return 0;
+}
+
diff --git a/xicc/cam02.h b/xicc/cam02.h
new file mode 100644
index 0000000..9491572
--- /dev/null
+++ b/xicc/cam02.h
@@ -0,0 +1,208 @@
+
+/*
+ * cam02
+ *
+ * Color Appearance Model, based on
+ * CIECAM02, "The CIECAM02 Color Appearance Model"
+ * by Nathan Moroney, Mark D. Fairchild, Robert W.G. Hunt, Changjun Li,
+ * M. Ronnier Luo and Todd Newman, IS&T/SID Tenth Color Imaging
+ * Conference, with the addition of the Viewing Flare
+ * model described on page 487 of "Digital Color Management",
+ * by Edward Giorgianni and Thomas Madden, and the
+ * Helmholtz-Kohlraush effect, using the equation
+ * the Bradford-Hunt 96C model as detailed in Mark Fairchilds
+ * book "Color Appearance Models".
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/1/2004
+ * Version: 1.00
+ *
+ * This file is based on cam97s3.h by Graeme Gill.
+ *
+ * Copyright 2004 - 2011 Graeme W. Gill
+ * Please refer to COPYRIGHT file for details.
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/* Definitions assumed here:
+
+ Stimulus field is the 2 degrees field of view of the sample
+ being characterised.
+
+ Viewing/Scene/Image field is the area of the whole image or
+ display surface that the stimulus is part of.
+
+ Background field is 10-12 degree field immediately surrounding the stimulus field.
+ This may be within, overlap or encompass the Viewing/Scene/Image field.
+
+ Visual field is the 130 degree angular field that is seen by the eyes.
+
+ Surround/Adapting field is the visual field minus the background field,
+ and is what is assumed to be setting the viewers light adaptation level.
+
+ Ambient field is the whole surrounding environmental light field.
+
+ Illuminating field is the field that illuminates the reflective
+ Scene/Image. It may be the same as the Ambient field or it could
+ be a specific light source that is directed to the viewing scene..
+
+ NOTE: In "Digital Color Management", Giorgianni and Madden use the term
+ "Surround" to mean the same thing as "Background" in the CIECAM02 terminology.
+ The ICC standard doesn't define what it means by "Surround illumination".
+
+*/
+
+/* Rules of Thumb: */
+
+/* Ambient Luminance (Lamb, cd/m^2) is Ambient Illuminance (Eamb, Lux) divided by PI. */
+/* i.e. Lamb = Eamb/PI */ /* (1 foot candle = 0.0929 lux) */
+
+/* Illuminating field Luminance (Li, cd/m^2) is the Illuminating field Illuminance (Ei, Lux) */
+/* divide by PI. i.e. Li = Ei/PI */
+
+/* The Adapting/Surround Luminance is La often taken to be */
+/* the 20% of the Ambient Luminance (gray world, 50% perceptual) */
+/* i.e. La = Lamb/5 = Eamb/15.7 */
+/* If the Illuminating field covers the Adapting/surround, the it will be 20% of the */
+/* Illuminating field. */
+
+/* For a reflective print, the Viewing/Scene/Image luminance (Lv, cd/m^2), */
+/* will be the Illuminating Luminance (Li, cd/m^2) or the Ambient Luminance (Lamb, cd/m^2) */
+/* reflected by the media white point (Yw) */
+
+/* If there is no special illumination for a reflective print, */
+/* then the Illuminating Luminance (Li) will be the Ambient Luminance (Lamb) */
+
+/* An emisive display will have an independently determined Lv. */
+
+/* The classification of the type of surround is */
+/* determined by comparing the Adapting/Surround luminance (La, cd/m^2) */
+/* with the average luminance of the Viewing/Scene/Image field (Lv, cd/m^2) */
+
+/* La/Lv == 0%, dark */
+/* La/Lv 0 - 20%, dim */
+/* La/Lv > 20%, average */
+/* special, cut sheet */
+
+/* The Background relative luminance Yb is typically assumed to */
+/* be 0.18 .. 0.2, and is assumed to be grey. */
+
+/* The source of flare light depends on the type of display system. */
+/* For a CRT, it will be the Ambient light reflecting off the glass surface. */
+/* (This implies Yf = Lamb * reflectance/Lv) */
+/* For a reflection print, it will be the Illuminant or Ambient reflecting from the media */
+/* surface. (Yf = Li * reflectance) */
+/* For a projected image, it will be stray projector light, scattered by the */
+/* surround, screen and air particles. (Yf = Li * reflectance_and_scattering) */
+
+/*
+
+Typical adapting field luminances and white luminance in reflective setup:
+
+E = illuminance in Lux
+Lv = White luminance assuming 100% reflectance
+La = Adapting field luminance in cd/m^2, assuming 20% reflectance from surround
+
+ E La Lv Condition
+ 11 0.7 4 Twilight
+ 32 2 10 Subdued indoor lighting
+ 64 4 20 Less than typical office light; sometimes recommended for
+ display-only workplaces (sRGB)
+ 350 22 111 Typical Office (sRGB annex D)
+ 500 32 160 Practical print evaluationa (ISO-3664 P2)
+ 1000 64 318 Good Print evaluation (CIE 116-1995)
+ 1000 64 318 Television Studio lighting
+ 1000 64 318 Overcast Outdoors
+ 2000 127 637 Critical print evaluation (ISO-3664 P1)
+ 10000 637 3183 Typical outdoors, full daylight
+ 50000 3185 15915 Bright summers day
+
+*/
+
+/* ---------------------------------- */
+
+struct _cam02 {
+/* Public: */
+ void (*del)(struct _cam02 *s); /* We're done with it */
+
+ int (*set_view)(
+ struct _cam02 *s,
+ ViewingCondition Ev, /* Enumerated Viewing Condition */
+ double Wxyz[3], /* Reference/Adapted White XYZ (Y scale 1.0) */
+ double La, /* Adapting/Surround Luminance cd/m^2 */
+ double Yb, /* Luminance of Background relative to reference white (range 0.0 .. 1.0) */
+ double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set */
+ double Yf, /* Flare as a fraction of the reference white (range 0.0 .. 1.0) */
+ double Fxyz[3], /* The Flare white coordinates (typically the Ambient color) */
+ int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+ );
+
+ /* Conversions. Return nz on error */
+ int (*XYZ_to_cam)(struct _cam02 *s, double *out, double *in);
+ int (*cam_to_XYZ)(struct _cam02 *s, double *out, double *in);
+
+/* Private: */
+ /* Scene parameters */
+ ViewingCondition Ev; /* Enumerated Viewing Condition */
+ double La; /* Adapting/Surround Luminance cd/m^2 */
+ double Wxyz[3]; /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ double Yb; /* Relative Luminance of Background to reference white (Y range 0.0 .. 1.0) */
+ double Yf; /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ double Fxyz[3]; /* The Flare white coordinates (typically the Ambient color) */
+
+ /* Internal parameters */
+ double C; /* Surround Impact */
+ double Nc; /* Chromatic Induction */
+ double F; /* Adaptation Degree */
+
+ /* Pre-computed values */
+ double cc[3][3]; /* Forward cone and chromatic transform */
+ double icc[3][3]; /* Reverse cone and chromatic transform */
+ double crange[3]; /* ENABLE_COMPR compression range */
+ double Va[3], Vb[3], VttA[3], Vttd[3]; /* rgba vectors */
+ double dcomp[3]; /* Vttd in terms of VttA, Va, Vb */
+ double Fsc; /* Flare scale */
+ double Fisc; /* Inverse flare scale */
+ double Fsxyz[3]; /* Scaled Flare color coordinates */
+ double rgbW[3]; /* Sharpened cone response white values */
+ double D; /* Degree of chromatic adaption */
+ double Drgb[3]; /* Chromatic transformation value */
+ double rgbcW[3]; /* Chromatically transformed white value */
+ double rgbpW[3]; /* Hunt-Pointer-Estevez cone response space white */
+ double n; /* Background induction factor */
+ double nn; /* Precomuted function of n */
+ double Fl; /* Lightness contrast factor ?? */
+ double Nbb; /* Background brightness induction factors */
+ double Ncb; /* Chromatic brightness induction factors */
+ double z; /* Base exponential nonlinearity */
+ double rgbaW[3]; /* Post-adapted cone response of white */
+ double Aw; /* Achromatic response of white */
+ double nldxval; /* Non-linearity output value at lower crossover to linear */
+ double nldxslope; /* Non-linearity slope at lower crossover to linear */
+ double nluxval; /* Non-linearity value at upper crossover to linear */
+ double nluxslope; /* Non-linearity slope at upper crossover to linear */
+ double lA; /* JLIMIT Limited A */
+
+ /* Option flags, code not always enabled */
+ int hk; /* Use Helmholtz-Kohlraush effect */
+ int trace; /* Trace values through computation */
+ int retss; /* Return ss rather than Jab */
+ int range; /* (for cam02ref.h) return on range error */
+
+ double nldlimit; /* value of NLDLIMIT, sets non-linearity lower limit */
+ double nldicept; /* value of NLDLICEPT, sets straight line intercept with 0.1 output */
+ double nlulimit; /* value of NLULIMIT, sets non-linearity upper limit (tangent) */
+ double ddllimit; /* value of DDLLIMIT, sets fwd k3 to k2 limit */
+ double ddulimit; /* value of DDULIMIT, sets bwd k3 to k1 limit */
+ double ssmincj; /* value of SSMINJ, sets cJ minimum value */
+ double jlimit; /* value of JLIMIT, sets cutover to straight line for J point */
+ double hklimit; /* value of HKLIMIT, sets HK factor upper limit */
+
+}; typedef struct _cam02 cam02;
+
+
+/* Create a cam02 conversion class, with default viewing conditions */
+cam02 *new_cam02(void);
+
diff --git a/xicc/cam02plot.c b/xicc/cam02plot.c
new file mode 100644
index 0000000..ca68b52
--- /dev/null
+++ b/xicc/cam02plot.c
@@ -0,0 +1,845 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 11/11/2004
+ * Version: 1.00
+ *
+ * Copyright 2000-2004 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.
+ *
+ */
+
+/*
+ * This is some test code to test the CIECAM02 continuity.
+ * This test creates file "cam02plot.tif" containing values that
+ * have been converted to and back from CIECAM02 space.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xcam.h"
+#include "cam02.h"
+#include "tiffio.h"
+#include "cam02ref.h"
+
+#define DEFRES 100 /* Default cube resolution */
+
+
+#define NORMAL_XYZ2RGB
+#undef NIEVE_XYZ2RGB
+#undef COMPLEX_XYZ2RGB
+
+#define SCALE 1.0 /* Compress RGB by scale towards grey */
+
+#ifndef _isnan
+#define _isnan(x) ((x) != (x))
+#define _finite(x) ((x) == 0.0 || (x) * 1.0000001 != (x))
+#endif
+
+static void
+Lab2XYZ(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ out[0] = x * 0.9642;
+ out[1] = y * 1.0000;
+ out[2] = z * 0.8249;
+}
+
+/* CIE XYZ to perceptual Lab */
+static void
+XYZ2Lab(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/0.9642;
+ y = Y/1.0000;
+ z = Z/0.8249;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+#ifdef NORMAL_XYZ2RGB
+
+static double sign(double x) {
+ if (x < 0.0)
+ return -1.0;
+ else
+ return 1.0;
+}
+
+/* Version with reasonable clipping. Converts to Lab, */
+/* clips the Lab an then converts to sRGB */
+/* Convert from XYZ to sRGB */
+void XYZ2sRGB(double *out, double *in, int trace) {
+ double lab[3];
+ double tmp[3];
+ double scale = SCALE; /* Scale RGB towards grey */
+ double mat[3][3] =
+ {
+ { 3.2410, -1.5374, -0.4986 },
+ { -0.9692, 1.8760, 0.0416 },
+ { 0.0556, -0.2040, 1.0570 }
+ };
+ int i;
+
+// ~~999
+ trace = 0;
+
+ /* Copy from input */
+ for(i = 0; i < 3; i++)
+ tmp[i] = in[i];
+
+ if (trace) printf("XYZ to RGB\n");
+ if (trace) printf("input XYZ %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+ /* Clip to reasonable range */
+// if (tmp[1] <= 0.0)
+// tmp[0] = tmp[2] = 0.0;
+ XYZ2Lab(lab, tmp);
+ if (trace) printf("Lab %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+ icmClipLab(lab, lab);
+ if (trace) printf("Clipped Lab %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* We're going to assume that L == 0 is always black */
+ if (lab[0] <= 0.0) {
+ lab[1] = lab[2] = 0.0;
+ }
+ if (trace) printf("Clipped Lab2 %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+ Lab2XYZ(tmp, lab);
+ if (trace) printf("XYZ %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+ icmClipXYZ(tmp, tmp);
+ if (trace) printf("clipped XYZ %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Now convert to sRGB assuming D50 (??) white point */
+ icmMulBy3x3(tmp, mat, tmp);
+
+ /* Scale */
+ for(i = 0; i < 3; i++) {
+ tmp[i] = ((tmp[i] - 0.5) * scale) + 0.5;
+ }
+
+ if (trace) printf("raw RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Apply gamma */
+ for(i = 0; i < 3; i++) {
+ if (tmp[i] < 0.00304) {
+ tmp[i] = tmp[i] * 12.92;
+ } else {
+ tmp[i] = 1.055 * pow(tmp[i], 1.0/2.4) - 0.055;
+ }
+ }
+
+ if (trace) printf("gamma corrected RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+#ifndef NEVER
+ /* Clip to nearest */
+ for(i = 0; i < 3; i++) {
+ if (tmp[i] < 0.0)
+ tmp[i] = 0.0;
+ else if (tmp[i] > 1.0)
+ tmp[i] = 1.0;
+ }
+#else
+ /* Clip towards center */
+ {
+ double biggest = -100.0;
+ for(i = 0; i < 3; i++) {
+ tmp[i] -= 0.5;
+ if (fabs(tmp[i]) > biggest)
+ biggest = fabs(tmp[i]);
+ }
+ for(i = 0; i < 3; i++) {
+ if (biggest > 0.5)
+ tmp[i] *= 0.5/biggest;
+ tmp[i] += 0.5;
+ }
+ }
+#endif
+ if (trace) printf("output clipped RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Copy to output */
+ for(i = 0; i < 3; i++)
+ out[i] = tmp[i];
+
+}
+
+#endif /* NORMAL_XYZ2RGB */
+
+#ifdef NIEVE_XYZ2RGB
+
+/* Nieve version with RGB clipping */
+/* Convert from XYZ to sRGB */
+void XYZ2sRGB(double *out, double *in, int trace) {
+ double tmp[3];
+ double scale = SCALE; /* Scale RGB towards grey */
+ double mat[3][3] =
+ {
+ { 3.2410, -1.5374, -0.4986 },
+ { -0.9692, 1.8760, 0.0416 },
+ { 0.0556, -0.2040, 1.0570 }
+ };
+ int i;
+
+ if (trace) printf("XYZ to RGB\n");
+ if (trace) printf("input XYZ %f %f %f\n",in[0],in[1],in[2]);
+
+ /* Now convert to sRGB assuming D50 (??) white point */
+ icmMulBy3x3(tmp, mat, in);
+
+ /* Scale */
+ for(i = 0; i < 3; i++) {
+ tmp[i] = ((tmp[i] - 0.5) * scale) + 0.5;
+ }
+
+ if (trace) printf("raw RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Clip to nearest */
+ for(i = 0; i < 3; i++) {
+ if (tmp[i] < 0.0)
+ tmp[i] = 0.0;
+ else if (tmp[i] > 1.0)
+ tmp[i] = 1.0;
+ }
+
+ if (trace) printf("clipped RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Apply gamma */
+ for(i = 0; i < 3; i++) {
+ if (tmp[i] < 0.00304) {
+ tmp[i] = tmp[i] * 12.92;
+ } else {
+ tmp[i] = 1.055 * pow(tmp[i], 1.0/2.4) - 0.055;
+ }
+ }
+
+ if (trace) printf("output gamma corrected RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Copy to output */
+ for(i = 0; i < 3; i++)
+ out[i] = tmp[i];
+}
+
+#endif /* NIEVE_XYZ2RGB */
+
+#ifdef COMPLEX_XYZ2RGB
+
+/* Complex version using powell to ensure good clipping */
+/* Callback context */
+typedef struct {
+ double scale;
+ double lab[3];
+ double imat[3][3];
+} ctx;
+
+double clipf(void *fdata, double tp[]) {
+ ctx *x = (ctx *)fdata;
+ double lab[3], tmp[3], tt;
+ int k;
+ double rv = 0.0;
+
+//printf("\n");
+//printf("~1 clipf got %f %f %f\n",tp[0],tp[1],tp[2]);
+
+ /* Penalize for being out of gamut */
+ for (k = 0; k < 3; k++) {
+ if (tp[k] < 0.0) {
+ tt = 100000.0 * (0.0 - tp[k]);
+ rv += tt * tt;
+ } else if (tp[k] > 1.0) {
+ tt = 100000.0 * (tp[k] - 1.0);
+ rv += tt * tt;
+ }
+ }
+//printf("~1 rv out of gamut = %f\n",rv);
+
+ /* Unscale it */
+ for(k = 0; k < 3; k++)
+ tmp[k] = ((tp[k] - 0.5) / x->scale) + 0.5;
+//printf("~1 unscale %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ icmMulBy3x3(tmp, x->imat, tmp); /* To XYZ */
+//printf("~1 xyz %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+ XYZ2Lab(lab, tmp); /* To Lab */
+//printf("~1 lab = %f %f %f\n",lab[0],lab[1],lab[2]);
+//printf("~1 target = %f %f %f\n",x->lab[0],x->lab[1],x->lab[2]);
+
+ /* Compute an error to the goal */
+ tt = 10000.0 * (lab[0] - x->lab[0]);
+ rv += tt * tt;
+
+ tt = 1.0 * (lab[1] - x->lab[1]);
+ rv += tt * tt;
+ tt = 1.0 * (lab[2] - x->lab[2]);
+ rv += tt * tt;
+
+//printf("~1 rv = %f\n",rv);
+
+ return rv;
+}
+
+/* Convert from XYZ to sRGB */
+void XYZ2sRGB(double *out, double *in, int trace) {
+ double lab[3], tmp[3];
+ double scale = SCALE; /* Scale RGB towards grey */
+ double mat[3][3] =
+ {
+ { 3.2410, -1.5374, -0.4986 },
+ { -0.9692, 1.8760, 0.0416 },
+ { 0.0556, -0.2040, 1.0570 }
+ };
+ int i;
+
+ /* Copy from input */
+ for(i = 0; i < 3; i++)
+ tmp[i] = in[i];
+
+ if (trace) printf("XYZ to RGB\n");
+
+ if (trace) printf("input XYZ %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ XYZ2Lab(lab, tmp);
+
+ if (trace) printf("Lab %f %f %f\n",lab[0],lab[1],lab[2]);
+
+ icmClipLab(lab, lab);
+
+ if (trace) printf("Clipped Lab %f %f %f\n",lab[0],lab[1],lab[2]);
+
+ /* Now convert to sRGB assuming D50 (??) white point */
+ Lab2XYZ(tmp, lab);
+ icmMulBy3x3(tmp, mat, tmp);
+
+ /* Scale */
+ for(i = 0; i < 3; i++) {
+ tmp[i] = ((tmp[i] - 0.5) * scale) + 0.5;
+ }
+
+ if (trace) printf("raw RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* See if it need clipping */
+ for(i = 0; i < 3; i++) {
+ if (tmp[i] < 0.0 || tmp[i] > 1.0)
+ break;
+ }
+ /* It needs more clipping */
+ if (i < 3) {
+ ctx x;
+ double ss[3] = { 0.1, 0.1, 0.1 };
+ x.lab[0] = lab[0];
+ x.lab[1] = lab[1];
+ x.lab[2] = lab[2];
+ x.scale = scale;
+ icmInverse3x3(x.imat, mat);
+
+ if (powell(NULL, 3, tmp, ss, 1e-6, 1000, clipf, (void *)&x) < 0.0)
+ error("RGB clip failed");
+ }
+ if (trace) printf("RGB clip %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Clip to nearest */
+ for(i = 0; i < 3; i++) {
+ if (tmp[i] < 0.0)
+ tmp[i] = 0.0;
+ else if (tmp[i] > 1.0)
+ tmp[i] = 1.0;
+ }
+ if (trace) printf("clip to nearest RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Apply gamma */
+ for(i = 0; i < 3; i++) {
+ if (tmp[i] < 0.00304) {
+ tmp[i] = tmp[i] * 12.92;
+ } else {
+ tmp[i] = 1.055 * pow(tmp[i], 1.0/2.4) - 0.055;
+ }
+ }
+ if (trace) printf("gamma corrected RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]);
+
+ /* Copy to output */
+ for(i = 0; i < 3; i++)
+ out[i] = tmp[i];
+
+}
+#endif /* COMPLEX_XYZ2RGB */
+
+void usage(char *diag) {
+ fprintf(stderr,"Create a 3D slice plot of XYZ/Lab <-> Jab, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL)
+ fprintf(stderr,"Diagnostic '%s'\n",diag);
+ fprintf(stderr,"usage: cam02plot [-options] x y\n");
+ fprintf(stderr,"'cam02plot -l -o' shows problem best\n");
+ fprintf(stderr," -v level Verbosity level 0 - 2 (default = 1)\n");
+ fprintf(stderr," -n Don't use Helmholtz-Kohlraush flag\n");
+ fprintf(stderr," -f Use the reference CIECAM transform\n");
+ fprintf(stderr," -r res Resolution (default %d)\n",DEFRES);
+ fprintf(stderr," -l Lab source cube (default XYZ source cube)\n");
+ fprintf(stderr," -i XYZ/Lab -> Jab (default XYZ/Lab -> Lab)\n");
+ fprintf(stderr," -o Jab -> XYZ -> RGB (defult Lab -> XYZ -> RGB\n");
+ fprintf(stderr," -s XYZ/Lab -> ab scale as RGB\n");
+ fprintf(stderr," -x Cross section plots\n");
+ fprintf(stderr," x y Return input color for this coordinate\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char *tiffname = "cam02plot.tif";
+ TIFF *wh = NULL;
+ uint16 resunits = RESUNIT_INCH;
+ float resx = 75.0, resy = 75.0;
+ tdata_t *obuf;
+ unsigned char *ob;
+ int verb = 0;
+ int transl = 0; /* Translate x,y into input color */
+ int tx = 0, ty = 0; /* coordinate to translate */
+ int use_hk = 1; /* Use Helmholtz-Kohlraush flag */
+ int use_ref = 0; /* Use reference transform rather than working code */
+ int lab_plot = 0; /* Lab <-> Jab plot, else XYZ <-> Jab */
+ int to_jab = 0; /* Convert to Jab, else convert to Lab */
+ int from_jab = 0; /* Convert from Jab, else convert from Lab */
+ int to_ss = 0; /* Convert from XYZ/Lab to abs scale ss */
+ int xsect = 0; /* Cross section plots */
+
+ double white[9][3] = {
+ { 0.964242, 1.000000, 0.825124 }, /* 0: D50 */
+ { 1.098494, 1.000000, 0.355908 }, /* 1: A */
+ { 0.908731, 1.000000, 0.987233 }, /* 2: F5 */
+ { 1.128981, 1.000000, 0.305862 }, /* 3: D25 */
+ { 0.950471, 1.000000, 1.088828 }, /* 4: D65 */
+ { 0.949662, 1.000000, 1.160438 }, /* 5: D80 */
+ { 0.949662, 1.000000, 1.160438 }, /* 6: D80 */
+ { 0.951297, 1.000000, 1.338196 }, /* 7: D85 */
+ { 0.952480, 1.000000, 1.386693 } /* 8: D90 */
+ };
+
+#ifdef NEVER
+ double La[6] = { 10.0, 31.83, 100.0, 318.31, 1000.83, 3183.1 };
+
+ ViewingCondition Vc[4] = {
+ vc_average,
+ vc_dark,
+ vc_dim,
+ vc_cut_sheet
+ };
+#endif /* NEVER */
+
+ int i, j, k, m;
+ double xyz[3], Jab[3], rgb[3];
+ cam02 *cam1, *cam2;
+
+ int res = DEFRES; /* Resolution of scan through space */
+ int ares; /* Array of 2d sub-rasters */
+ int w, h; /* Width and height of raster */
+ int x, y;
+ int sp = 5; /* Spacing beween resxres sub-images */
+
+ error_program = argv[0];
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Requested usage");
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ fa = nfa;
+ if (na == NULL)
+ verb = 2;
+ else {
+ if (na[0] == '0')
+ verb = 0;
+ else if (na[0] == '1')
+ verb = 1;
+ else if (na[0] == '2')
+ verb = 2;
+ else
+ usage("Illegal verbosity level");
+ }
+ }
+
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL)
+ usage("Need resolution after -r");
+ res = atoi(na);
+ if (res < 2 || res > 1000)
+ usage("Resolution is out of range");
+ }
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ use_hk = 0;
+ }
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ use_ref = 1;
+ }
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') {
+ lab_plot = 1;
+ }
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ to_jab = 1;
+ }
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ from_jab = 1;
+ }
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ to_ss = 1;
+ }
+ else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ xsect = 1;
+ }
+ else
+ usage("Unknown flag");
+ } else
+ break;
+ }
+
+ if ((fa+1) < argc) {
+ tx = atoi(argv[fa]);
+ ty = atoi(argv[fa+1]);
+ transl = 1;
+ }
+
+
+ /* Setup cam to convert to Jab */
+ if (use_ref)
+ cam1 = new_cam02ref();
+ else
+ cam1 = new_cam02();
+ cam1->set_view(
+ cam1,
+ vc_average, /* Enumerated Viewing Condition */
+ white[4], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ 1000.0, /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[4], /* The Flare color coordinates (typically the Ambient color) */
+ use_hk /* use Helmholtz-Kohlraush flag */
+ );
+
+ /* Setup cam to convert from Jab */
+ if (use_ref)
+ cam2 = new_cam02ref();
+ else
+ cam2 = new_cam02();
+ cam2->set_view(
+ cam2,
+ vc_average, /* Enumerated Viewing Condition */
+ white[4], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ 1000.0, /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[4], /* The Flare color coordinates (typically the Ambient color) */
+ use_hk /* use Helmholtz-Kohlraush flag */
+ );
+
+ /* Figure out the size of the raster */
+ ares = (int)ceil(sqrt((double)res));
+ if (verb)
+ printf("For res %d, ares = %d\n",res,ares);
+
+ w = ares * res + sp * (ares+1);
+ h = ares * res + sp * (ares+1);
+
+ if (to_ss) {
+ cam1->retss = 1;
+ }
+
+ if (transl) {
+ int ix,iy,iz;
+ double dx,dy,dz;
+ double tmp[3], lab[3];
+
+ cam1->trace = 1;
+ cam2->trace = 1;
+
+//printf("~1 translate %d %d\n",tx,ty);
+ tx -= sp; /* Border at base */
+ ty -= sp;
+
+//printf("~1 offset %d %d\n",tx,ty);
+ ix = tx % (res + sp);
+ iy = ty % (res + sp);
+ iz = (ty / (res + sp)) * ares + (tx / (res + sp));
+
+//printf("~1 x y z = %d %d %d\n", ix,iy,iz);
+
+ dx = ix/(res-1.0);
+ dy = iy/(res-1.0);
+ dz = iz/((ares * ares)-1.0);
+
+//printf("~1 X Y Z = %f %f %f\n", dx,dy,dz);
+
+ /* Source range is extended L*a*b* type */
+ if (lab_plot) {
+ if (xsect) {
+ lab[0] = 180.0 * dz - 40.0;
+ lab[1] = 300.0 * dy - 150.0;
+ lab[2] = 300.0 * dx - 150.0;
+ } else {
+ lab[0] = 180.0 * dx - 40.0;
+ lab[1] = 300.0 * dy - 150.0;
+ lab[2] = 300.0 * dz - 150.0;
+ }
+//printf("~1 Lab = %f %f %f\n", lab[0],lab[1],lab[2]);
+ Lab2XYZ(tmp, lab);
+ printf("======================================================\n");
+ printf("%d,%d -> Lab %f %f %f\n", tx+sp, ty+sp, lab[0],lab[1],lab[2]);
+ printf(" == XYZ %f %f %f\n", tmp[0],tmp[1],tmp[2]);
+
+ /* Else source range is extended XYZ type */
+ } else {
+ if (xsect) {
+ tmp[0] = 1.4 * dz - 0.2;
+ tmp[1] = 1.4 * dy - 0.2;
+ tmp[2] = 1.6 * dx - 0.2;
+ } else {
+ tmp[0] = 1.4 * dx - 0.2;
+ tmp[1] = 1.4 * dy - 0.2;
+ tmp[2] = 1.6 * dz - 0.2;
+ }
+ printf("%d,%d -> Input color XYZ %f %f %f\n", tx, ty, tmp[0],tmp[1],tmp[2]);
+ }
+
+ if (to_ss) {
+ cam1->XYZ_to_cam(cam1, Jab, tmp);
+ printf(" XYZ -> ss %f %f %f\n", Jab[0],Jab[1],Jab[2]);
+
+ /* Convert XYZ through cam and back, then to RGB */
+ } else if (to_jab) {
+ cam1->XYZ_to_cam(cam1, Jab, tmp);
+ if (to_ss) {
+ printf(" XYZ -> ss %f %f %f\n", Jab[0],Jab[1],Jab[2]);
+ } else {
+ printf(" XYZ -> ss %f %f %f\n", Jab[0],Jab[1],Jab[2]);
+ }
+
+ /* Else convert XYZ to L*a*b* */
+ } else {
+ XYZ2Lab(Jab, tmp);
+ printf(" XYZ -> Lab %f %f %f\n", Jab[0],Jab[1],Jab[2]);
+ }
+
+ /* Convert from Jab back to XYZ */
+ if (from_jab) {
+ cam2->cam_to_XYZ(cam2, rgb, Jab);
+ printf(" Jab -> XYZ %f %f %f\n", rgb[0],rgb[1],rgb[2]);
+
+ /* Else convert from Lab back to XYZ */
+ } else {
+ Lab2XYZ(rgb, Jab);
+ printf(" Lab -> XYZ %f %f %f\n", rgb[0],rgb[1],rgb[2]);
+ }
+
+ XYZ2Lab(tmp, rgb);
+ printf(" == Lab %f %f %f\n", tmp[0],tmp[1],tmp[2]);
+
+ /* Interpret XYZ as RGB color */
+ XYZ2sRGB(rgb, rgb, 1);
+ printf(" XYZ -> RGB %f %f %f\n", rgb[0],rgb[1],rgb[2]);
+
+ cam1->trace = 0;
+ cam2->trace = 0;
+
+ printf("\n");
+ exit(0);
+ }
+
+ if (verb)
+ printf("Raster width = %d, height = %d\n",w,h);
+
+ /* Setup the tiff file */
+ if ((wh = TIFFOpen(tiffname, "w")) == NULL)
+ error("Can\'t create TIFF file '%s'!",tiffname);
+
+ TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, w);
+ TIFFSetField(wh, TIFFTAG_IMAGELENGTH, h);
+ TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, 8);
+ TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, resunits);
+ TIFFSetField(wh, TIFFTAG_XRESOLUTION, resx);
+ TIFFSetField(wh, TIFFTAG_YRESOLUTION, resy);
+ TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, "cam02plot");
+
+ obuf = _TIFFmalloc(TIFFScanlineSize(wh));
+ ob = (unsigned char *)obuf;
+
+ y = 0;
+
+ /* Fill sp lines with black */
+ for (x = 0, m = 0; m < w; m++) {
+ ob[x] = ob[x+1] = ob[x+2] = 0;
+ x += 3;
+ }
+ for (j = 0; j < sp; j++, y++) {
+ TIFFWriteScanline(wh, ob, y, 0);
+ }
+
+ for (i = 0; i < ares; i++) { /* Vertical blocks (rows) */
+ for (j = 0; j < res; j++, y++) { /* Vertical in block (y = Y/a*) */
+ xyz[1] = j/(res-1.0);
+ x = 0;
+
+ /* Fill sp pixels with black */
+ for (m = 0; m < sp; m++) {
+ ob[x] = ob[x+1] = ob[x+2] = 0;
+ x += 3;
+ }
+ for (k = 0; k < ares; k++) { /* Horizontal blocks (columns) */
+ int zv = i * ares + k;
+ if (zv >= res) {
+ /* Fill res pixels with black */
+ for (m = 0; m < res; m++) {
+ ob[x] = ob[x+1] = ob[x+2] = 0;
+ x += 3;
+ }
+ } else {
+ xyz[2] = zv/(res-1.0); /* z = block = Z/b* */
+ for (m = 0; m < res; m++) { /* Horizontal in block (x = X/L*) */
+ double tmp[3], xyz2[3];
+ xyz[0] = m/(res-1.0);
+
+ if (lab_plot) {
+ if (xsect) {
+ tmp[0] = 180.0 * xyz[2] - 40.0;
+ tmp[1] = 300.0 * xyz[1] - 150.0;
+ tmp[2] = 300.0 * xyz[0] - 150.0;
+ } else {
+ tmp[0] = 180.0 * xyz[0] - 40.0;
+ tmp[1] = 300.0 * xyz[1] - 150.0;
+ tmp[2] = 300.0 * xyz[2] - 150.0;
+ }
+ Lab2XYZ(tmp, tmp);
+
+ } else {
+ if (xsect) {
+ tmp[0] = 1.4 * xyz[2] - 0.2;
+ tmp[1] = 1.4 * xyz[1] - 0.2;
+ tmp[2] = 1.6 * xyz[0] - 0.2;
+ } else {
+ tmp[0] = 1.4 * xyz[0] - 0.2;
+ tmp[1] = 1.4 * xyz[1] - 0.2;
+ tmp[2] = 1.6 * xyz[2] - 0.2;
+ }
+ }
+
+ /* Convert XYZ through cam and back, then to RGB */
+ if (to_jab || to_ss)
+ cam1->XYZ_to_cam(cam1, Jab, tmp);
+ else
+ XYZ2Lab(Jab, tmp);
+
+ if (to_ss) {
+ rgb[0] = Jab[0];
+ rgb[1] = Jab[1];
+ rgb[2] = Jab[2];
+ } else {
+ if (from_jab)
+ cam2->cam_to_XYZ(cam2, xyz2, Jab);
+ else
+ Lab2XYZ(xyz2, Jab);
+
+ XYZ2sRGB(rgb, xyz2, 0);
+ }
+
+ /* Fill with pixel value */
+ ob[x+0] = (int)(rgb[0] * 255.0 + 0.5);
+ ob[x+1] = (int)(rgb[1] * 255.0 + 0.5);
+ ob[x+2] = (int)(rgb[2] * 255.0 + 0.5);
+ x += 3;
+ }
+ }
+ /* Fill sp pixels with black */
+ for (m = 0; m < sp; m++) {
+ ob[x] = ob[x+1] = ob[x+2] = 0;
+ x += 3;
+ }
+ }
+ TIFFWriteScanline(wh, ob, y, 0);
+ }
+ /* Fill sp lines with black */
+ for (x = m = 0; m < w; m++) {
+ ob[x] = ob[x+1] = ob[x+2] = 0;
+ x += 3;
+ }
+ for (j = 0; j < sp; j++, y++) {
+ TIFFWriteScanline(wh, ob, y, 0);
+ }
+ }
+
+ cam1->del(cam1);
+ cam2->del(cam2);
+
+ /* Write TIFF file */
+ TIFFClose(wh);
+
+ return 0;
+}
+
diff --git a/xicc/cam02ref.h b/xicc/cam02ref.h
new file mode 100644
index 0000000..de75f6b
--- /dev/null
+++ b/xicc/cam02ref.h
@@ -0,0 +1,621 @@
+
+/*
+ * cam02, unoptimised, untweaked reference version for testing.
+ * with optional trace/range error flags.
+ *
+ * Color Appearance Model.
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/1/2004
+ * Version: 1.00
+ *
+ * This file is based on cam97s3.c by Graeme Gill.
+ *
+ * Copyright 2004, 2007 Graeme W. Gill
+ * Please refer to COPYRIGHT file for details.
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+
+/* Note that XYZ values are normalised to 1.0 consistent */
+/* with the ICC convention (not 100.0 as assumed by the CIECAM spec.) */
+/* Note that all whites are assumed to be normalised (ie. Y = 1.0) */
+
+#undef DIAG /* Print internal value diagnostics for each conversion */
+
+/* ---------------------------------- */
+
+#ifdef NEVER
+
+struct _cam02ref {
+/* Public: */
+ void (*del)(struct _cam02ref *s); /* We're done with it */
+
+ int (*set_view)(
+ struct _cam02ref *s,
+ ViewingCondition Ev, /* Enumerated Viewing Condition */
+ double Wxyz[3], /* Reference/Adapted White XYZ (Y scale 1.0) */
+ double La, /* Adapting/Surround Luminance cd/m^2 */
+ double Yb, /* Luminance of Background relative to reference white (range 0.0 .. 1.0) */
+ double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set */
+ double Yf, /* Flare as a fraction of the reference white (range 0.0 .. 1.0) */
+ double Fxyz[3], /* The Flare white coordinates (typically the Ambient color) */
+ int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+ );
+
+ /* Conversions */
+ int (*XYZ_to_cam)(struct _cam02ref *s, double *out, double *in);
+
+/* Private: */
+ /* Scene parameters */
+ ViewingCondition Ev; /* Enumerated Viewing Condition */
+ double Wxyz[3]; /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ double Yb; /* Relative Luminance of Background to reference white (Y range 0.0 .. 1.0) */
+ double La; /* Adapting/Surround Luminance cd/m^2 */
+ double Yf; /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ double Fxyz[3]; /* The Flare white coordinates (typically the Ambient color) */
+
+ /* Internal parameters */
+ double C; /* Surround Impact */
+ double Nc; /* Chromatic Induction */
+ double F; /* Adaptation Degree */
+
+ /* Pre-computed values */
+ double Fsc; /* Flare scale */
+ double Fisc; /* Inverse flare scale */
+ double Fsxyz[3]; /* Scaled Flare color coordinates */
+ double rgbW[3]; /* Sharpened cone response white values */
+ double D; /* Degree of chromatic adaption */
+ double Drgb[3]; /* Chromatic transformation value */
+ double rgbcW[3]; /* Chromatically transformed white value */
+ double rgbpW[3]; /* Hunt-Pointer-Estevez cone response space white */
+ double n; /* Background induction factor */
+ double nn; /* Precomuted function of n */
+ double Fl; /* Lightness contrast factor ?? */
+ double Nbb; /* Background brightness induction factors */
+ double Ncb; /* Chromatic brightness induction factors */
+ double z; /* Base exponential nonlinearity */
+ double rgbaW[3]; /* Post-adapted cone response of white */
+ double Aw; /* Achromatic response of white */
+
+ /* Option flags */
+ int hk; /* Use Helmholtz-Kohlraush effect */
+ int trace; /* Trace internal values */
+ double range; /* Return error if there is a range error */
+ double nldlimit; /* range error if nlinear is less than this */
+ double jlimit; /* range error if J is less than this */
+
+}; typedef struct _cam02ref cam02ref;
+
+#else
+
+typedef struct _cam02 cam02ref;
+
+#endif
+
+/* ---------------------------------- */
+
+/* Utility function */
+/* Return a viewing condition enumeration from the given Ambient and */
+/* Adapting/Surround Luminance. */
+static ViewingCondition cam02ref_Ambient2VC(
+double La, /* Ambient Luminence (cd/m^2) */
+double Lv /* Luminence of white in the Viewing/Scene/Image field (cd/m^2) */
+) {
+ double r;
+
+ if (fabs(La) < 1e-10) /* Hmm. */
+ r = 1.0;
+ else
+ r = La/Lv;
+
+ if (r < 0.01)
+ return vc_dark;
+ if (r < 0.2)
+ return vc_dim;
+ return vc_average;
+}
+
+static void cam02ref_free(cam02ref *s);
+static int cam02ref_set_view(cam02ref *s, ViewingCondition Ev, double Wxyz[3],
+ double Yb, double La, double Lv, double Yf, double Fxyz[3], int hk);
+static int cam02ref_XYZ_to_cam(cam02ref *s, double *Jab, double *xyz);
+static int cam02ref_cam_to_XYZ(cam02ref *s, double XYZ[3], double Jab[3]);
+
+/* Create a cam02 conversion object, with default viewing conditions */
+cam02ref *new_cam02ref(void) {
+ cam02ref *s;
+
+ if ((s = (cam02ref *)malloc(sizeof(cam02ref))) == NULL) {
+ fprintf(stderr,"cam02: malloc failed allocating object\n");
+ exit(-1);
+ }
+
+ /* Initialise methods */
+ s->del = cam02ref_free;
+ s->set_view = cam02ref_set_view;
+ s->XYZ_to_cam = cam02ref_XYZ_to_cam;
+ s->cam_to_XYZ = cam02ref_cam_to_XYZ;
+
+ return s;
+}
+
+static void cam02ref_free(cam02ref *s) {
+ if (s != NULL)
+ free(s);
+}
+
+static int cam02ref_set_view(
+cam02ref *s,
+ViewingCondition Ev, /* Enumerated Viewing Condition */
+double Wxyz[3], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+double La, /* Adapting/Surround Luminance cd/m^2 */
+double Yb, /* Relative Luminence of Background to reference white */
+double Lv, /* Luminence of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set to other than vc_none */
+double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+double Fxyz[3], /* The Flare white coordinates (typically the Ambient color) */
+int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+) {
+ double tt;
+
+ if (Ev == vc_none) /* Compute enumerated viewing condition */
+ Ev = cam02ref_Ambient2VC(La, Lv);
+ /* Transfer parameters to the object */
+ s->Ev = Ev;
+ s->Wxyz[0] = Wxyz[0];
+ s->Wxyz[1] = Wxyz[1];
+ s->Wxyz[2] = Wxyz[2];
+ s->Yb = Yb > 0.005 ? Yb : 0.005; /* Set minimum to avoid divide by 0.0 */
+ s->La = La;
+ s->Yf = Yf;
+ s->Fxyz[0] = Fxyz[0];
+ s->Fxyz[1] = Fxyz[1];
+ s->Fxyz[2] = Fxyz[2];
+ s->hk = hk;
+
+ /* Compute the internal parameters by category */
+ switch(s->Ev) {
+ case vc_dark:
+ s->C = 0.525;
+ s->Nc = 0.8;
+ s->F = 0.8;
+ break;
+ case vc_dim:
+ s->C = 0.59;
+ s->Nc = 0.95;
+ s->F = 0.9;
+ break;
+ case vc_cut_sheet:
+ s->C = 0.41;
+ s->Nc = 0.8;
+ s->F = 0.8;
+ break;
+ default: /* average */
+ s->C = 0.69;
+ s->Nc = 1.0;
+ s->F = 1.0;
+ break;
+ }
+
+ /* Compute values that only change with viewing parameters */
+
+ /* Figure out the Flare contribution to the flareless XYZ input */
+ tt = s->Yf * s->Wxyz[1]/s->Fxyz[1];
+ s->Fsxyz[0] = tt * s->Fxyz[0];
+ s->Fsxyz[1] = tt * s->Fxyz[1];
+ s->Fsxyz[2] = tt * s->Fxyz[2];
+
+ /* Rescale so that the sum of the flare and the input doesn't exceed white */
+ s->Fsc = s->Wxyz[1]/(s->Fsxyz[1] + s->Wxyz[1]);
+ s->Fsxyz[0] *= s->Fsc;
+ s->Fsxyz[1] *= s->Fsc;
+ s->Fsxyz[2] *= s->Fsc;
+ s->Fisc = 1.0/s->Fsc;
+
+ /* Sharpened cone response white values */
+ s->rgbW[0] = 0.7328 * s->Wxyz[0] + 0.4296 * s->Wxyz[1] - 0.1624 * s->Wxyz[2];
+ s->rgbW[1] = -0.7036 * s->Wxyz[0] + 1.6975 * s->Wxyz[1] + 0.0061 * s->Wxyz[2];
+ s->rgbW[2] = 0.0000 * s->Wxyz[0] + 0.0000 * s->Wxyz[1] + 1.0000 * s->Wxyz[2];
+
+ /* Degree of chromatic adaption */
+ s->D = s->F * (1.0 - exp((-s->La - 42.0)/92.0)/3.6);
+
+ /* Precompute Chromatic transform values */
+ s->Drgb[0] = s->D * (s->Wxyz[1]/s->rgbW[0]) + 1.0 - s->D;
+ s->Drgb[1] = s->D * (s->Wxyz[1]/s->rgbW[1]) + 1.0 - s->D;
+ s->Drgb[2] = s->D * (s->Wxyz[1]/s->rgbW[2]) + 1.0 - s->D;
+
+ /* Chromaticaly transformed white value */
+ s->rgbcW[0] = s->Drgb[0] * s->rgbW[0];
+ s->rgbcW[1] = s->Drgb[1] * s->rgbW[1];
+ s->rgbcW[2] = s->Drgb[2] * s->rgbW[2];
+
+ /* Transform from spectrally sharpened, to Hunt-Pointer_Estevez cone space */
+ s->rgbpW[0] = 0.7409744840453773 * s->rgbcW[0]
+ + 0.2180245944753982 * s->rgbcW[1]
+ + 0.0410009214792244 * s->rgbcW[2];
+ s->rgbpW[1] = 0.2853532916858801 * s->rgbcW[0]
+ + 0.6242015741188157 * s->rgbcW[1]
+ + 0.0904451341953042 * s->rgbcW[2];
+ s->rgbpW[2] = -0.0096276087384294 * s->rgbcW[0]
+ - 0.0056980312161134 * s->rgbcW[1]
+ + 1.0153256399545427 * s->rgbcW[2];
+
+
+ /* Background induction factor */
+ s->n = s->Yb/ s->Wxyz[1];
+ s->nn = pow(1.64 - pow(0.29, s->n), 0.73); /* Pre computed value */
+
+ /* Lightness contrast factor ?? */
+ {
+ double k;
+
+ k = 1.0 / (5.0 * s->La + 1.0);
+ s->Fl = 0.2 * pow(k , 4.0) * 5.0 * s->La
+ + 0.1 * pow(1.0 - pow(k , 4.0) , 2.0) * pow(5.0 * s->La , 1.0/3.0);
+ }
+
+ /* Background and Chromatic brightness induction factors */
+ s->Nbb = 0.725 * pow(1.0/s->n, 0.2);
+ s->Ncb = s->Nbb;
+
+ /* Base exponential nonlinearity */
+ s->z = 1.48 + pow(s->n , 0.5);
+
+ /* Post-adapted cone response of white */
+ tt = pow(s->Fl * s->rgbpW[0], 0.42);
+ s->rgbaW[0] = (400.1 * tt + 2.713) / (tt + 27.13);
+ tt = pow(s->Fl * s->rgbpW[1], 0.42);
+ s->rgbaW[1] = (400.1 * tt + 2.713) / (tt + 27.13);
+ tt = pow(s->Fl * s->rgbpW[2], 0.42);
+ s->rgbaW[2] = (400.1 * tt + 2.713) / (tt + 27.13);
+
+ /* Achromatic response of white */
+ s->Aw = (2.0 * s->rgbaW[0] + s->rgbaW[1] + (1.0/20.0) * s->rgbaW[2] - 0.305) * s->Nbb;
+
+#ifdef DIAG
+ printf("Ref. Scene parameters:\n");
+ printf("Viewing condition Ev = %d\n",s->Ev);
+ printf("Ref white Wxyz = %f %f %f\n", s->Wxyz[0], s->Wxyz[1], s->Wxyz[2]);
+ printf("Relative liminance of background Yb = %f\n", s->Yb);
+ printf("Adapting liminance La = %f\n", s->La);
+ printf("Flare Yf = %f\n", s->Yf);
+ printf("Flare color Fxyz = %f %f %f\n", s->Fxyz[0], s->Fxyz[1], s->Fxyz[2]);
+
+ printf("Internal parameters:\n");
+ printf("Surround Impact C = %f\n", s->C);
+ printf("Chromatic Induction Nc = %f\n", s->Nc);
+ printf("Adaption Degree F = %f\n", s->F);
+
+ printf("Pre-computed values\n");
+ printf("Sharpened cone white rgbW = %f %f %f\n", s->rgbW[0], s->rgbW[1], s->rgbW[2]);
+ printf("Degree of chromatic adaption D = %f\n", s->D);
+ printf("Chromatic transform values Drgb = %f %f %f\n", s->Drgb[0], s->Drgb[1], s->Drgb[2]);
+ printf("Chromatically transformed white rgbcW = %f %f %f\n", s->rgbcW[0], s->rgbcW[1], s->rgbcW[2]);
+ printf("Hunter-P-E cone response white rgbpW = %f %f %f\n", s->rgbpW[0], s->rgbpW[1], s->rgbpW[2]);
+ printf("Background induction factor n = %f\n", s->n);
+ printf("Lightness contrast factor Fl = %f\n", s->Fl);
+ printf("Background brightness induction factor Nbb = %f\n", s->Nbb);
+ printf("Chromatic brightness induction factor Ncb = %f\n", s->Ncb);
+ printf("Base exponential nonlinearity z = %f\n", s->z);
+ printf("Post adapted cone response white rgbaW = %f %f %f\n", s->rgbaW[0], s->rgbaW[1], s->rgbaW[2]);
+ printf("Achromatic response of white Aw = %f\n", s->Aw);
+ printf("\n");
+#endif
+ return 0;
+}
+
+/* A version of the pow() function that preserves the */
+/* sign of its first argument. */
+static double spow(double x, double y) {
+ return x < 0.0 ? -pow(-x,y) : pow(x,y);
+}
+
+
+#define REFTRACE(xxxx) if (s->trace) printf xxxx ;
+
+/* Conversion. Returns NZ and -1, -1, -1 if input is out of range */
+static int cam02ref_XYZ_to_cam(
+cam02ref *s,
+double Jab[3],
+double XYZ[3]
+) {
+ int i;
+ double xyz[3], rgb[3], rgbp[3], rgba[3], rgbaW[3], rgbc[3], rgbcW[3];
+ double a, b, rS, J, C, h, e, A, ss;
+ double ttd, tt;
+
+ REFTRACE(("\nReference forward conversion:\n"))
+ REFTRACE(("XYZ %f %f %f\n",XYZ[0], XYZ[1], XYZ[2]))
+
+ /* Add in flare */
+ xyz[0] = s->Fsc * XYZ[0] + s->Fsxyz[0];
+ xyz[1] = s->Fsc * XYZ[1] + s->Fsxyz[1];
+ xyz[2] = s->Fsc * XYZ[2] + s->Fsxyz[2];
+
+ REFTRACE(("Including flare XYZ = %f %f %f\n", xyz[0], xyz[1], xyz[2]))
+
+ /* Spectrally sharpened cone responses */
+ rgb[0] = 0.7328 * xyz[0] + 0.4296 * xyz[1] - 0.1624 * xyz[2];
+ rgb[1] = -0.7036 * xyz[0] + 1.6975 * xyz[1] + 0.0061 * xyz[2];
+ rgb[2] = 0.0000 * xyz[0] + 0.0000 * xyz[1] + 1.0000 * xyz[2];
+
+ REFTRACE(("Sharpened cone sample rgb = %f %f %f\n", rgb[0], rgb[1], rgb[2]))
+
+ /* Chromaticaly transformed sample value */
+ rgbc[0] = s->Drgb[0] * rgb[0];
+ rgbc[1] = s->Drgb[1] * rgb[1];
+ rgbc[2] = s->Drgb[2] * rgb[2];
+
+ REFTRACE(("Chromatically transformed sample value rgbc = %f %f %f\n", rgb[0], rgb[1], rgb[2]))
+
+ /* Transform from spectrally sharpened, to Hunt-Pointer_Estevez cone space */
+ rgbp[0] = 0.7409744840453773 * rgbc[0]
+ + 0.2180245944753982 * rgbc[1]
+ + 0.0410009214792244 * rgbc[2];
+ rgbp[1] = 0.2853532916858801 * rgbc[0]
+ + 0.6242015741188157 * rgbc[1]
+ + 0.0904451341953042 * rgbc[2];
+ rgbp[2] = -0.0096276087384294 * rgbc[0]
+ - 0.0056980312161134 * rgbc[1]
+ + 1.0153256399545427 * rgbc[2];
+
+ REFTRACE(("rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]))
+
+ /* Post-adapted cone response of sample. */
+ /* rgba[] has a minimum value of 0.1 for XYZ[] = 0 and no flare. */
+ /* We add a symetric negative compression region */
+ for (i = 0; i < 3; i++) {
+ if (s->range && (rgbp[i] < 0.0 || rgbp[i] < s->nldlimit)) {
+ Jab[0] = Jab[1] = Jab[2] = -1.0;
+ return 1;
+ }
+ if (rgbp[i] < 0.0) {
+ tt = pow(s->Fl * -rgbp[i], 0.42);
+ rgba[i] = (2.713 - 397.387 * tt) / (tt + 27.13);
+
+ } else {
+ tt = pow(s->Fl * rgbp[i], 0.42);
+ rgba[i] = (400.1 * tt + 2.713) / (tt + 27.13);
+ }
+ }
+
+ REFTRACE(("rgba = %f %f %f\n", rgba[0], rgba[1], rgba[2]))
+
+ /* Preliminary red-green & yellow-blue opponent dimensions */
+ a = rgba[0] - 12.0 * rgba[1]/11.0 + rgba[2]/11.0;
+ b = (1.0/9.0) * (rgba[0] + rgba[1] - 2.0 * rgba[2]);
+ rS = sqrt(a * a + b * b); /* Normalised a, b */
+
+ /* Preliminary Saturation */
+ /* Note that the minimum values for rgba[] for XYZ = 0 is 0.1 */
+ /* Hence magic 0.305 below comes from the following weighting of rgba[] */
+ ttd = rgba[0] + rgba[1] + (21.0/20.0) * rgba[2];
+
+ /* Achromatic response */
+ /* Note that the minimum values of rgba[] for XYZ = 0 is 0.1, */
+ /* hence magic 0.305 below comes from the following weighting of rgba[], */
+ /* to base A at 0.0 */
+ A = (2.0 * rgba[0] + rgba[1] + (1.0/20.0) * rgba[2] - 0.305) * s->Nbb;
+
+ REFTRACE(("a = %f, b = %f, ttd = %f, rS = %f, A = %f\n", a, b, ttd, rS, A))
+
+ /* Lightness */
+ J = pow(A/s->Aw, s->C * s->z); /* J/100 - keep Sign */
+
+ /* Hue angle */
+ h = (180.0/DBL_PI) * atan2(b,a);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ /* Eccentricity factor */
+ e = (cos(h * DBL_PI/180.0 + 2.0) + 3.8);
+
+ if (s->range && (J < DBL_EPSILON || J < s->jlimit || ttd < DBL_EPSILON)) {
+ REFTRACE(("J = %f, ttd = %f, exit with error\n", J, ttd))
+ Jab[0] = Jab[1] = Jab[2] = -1.0;
+ return 1;
+ }
+
+ ss = (12500.0/13.0 * s->Nc * s->Ncb * rS * e) / ttd;
+
+ /* Chroma */
+ C = pow(ss, 0.9) * sqrt(J) * s->nn;
+
+ REFTRACE(("ss = %f, C = %f\n", ss, C))
+
+ /* Helmholtz-Kohlraush effect */
+ if (s->hk && J < 1.0) {
+ double JJ, kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ if (kk > 0.9) /* Limit kk to a reasonable range */
+ kk = 0.9;
+ JJ = J + (1.0 - J) * kk;
+ REFTRACE(("JJ = %f from J = %f, kk = %f\n",JJ,J,kk))
+ J = JJ;
+ }
+
+ J *= 100.0; /* Scale J */
+
+ /* Compute Jab value */
+ Jab[0] = J;
+ if (rS >= DBL_EPSILON) {
+ Jab[1] = C * a/rS;
+ Jab[2] = C * b/rS;
+ } else {
+ Jab[1] = 0.0;
+ Jab[2] = 0.0;
+ }
+
+ REFTRACE(("Returning Jab %f %f %f\n", Jab[0],Jab[1],Jab[2]))
+
+#ifdef DIAG
+ printf("Processing:\n");
+ printf("XYZ = %f %f %f\n", XYZ[0], XYZ[1], XYZ[2]);
+ printf("Including flare XYZ = %f %f %f\n", xyz[0], xyz[1], xyz[2]);
+ printf("Sharpened cone sample rgb = %f %f %f\n", rgb[0], rgb[1], rgb[2]);
+ printf("Chromatically transformed sample value rgbc = %f %f %f\n", rgbc[0], rgbc[1], rgbc[2]);
+ printf("Hunt-P-E cone space rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]);
+ printf("Post adapted cone response rgba = %f %f %f\n", rgba[0], rgba[1], rgba[2]);
+ printf("Prelim red green a = %f, b = %f\n", a, b);
+ printf("Hue angle h = %f\n", h);
+ printf("Eccentricity factor e = %f\n", e);
+ printf("Achromatic response A = %f\n", A);
+ printf("Lightness J = %f\n", J);
+ printf("Prelim Saturation ss = %f\n", ss);
+ printf("Chroma C = %f\n", C);
+ printf("Jab = %f %f %f\n", Jab[0], Jab[1], Jab[2]);
+ printf("\n");
+#endif
+ return 0;
+}
+
+static int cam02ref_cam_to_XYZ(
+cam02ref *s,
+double XYZ[3],
+double Jab[3]
+) {
+ int i;
+ double xyz[3], rgb[3], rgbp[3], rgba[3], rgbaW[3], rgbc[3], rgbcW[3];
+ double ja, jb, aa, ab, a, b, J, C, h, e, A, ss;
+ double tt, ttA, tte;
+
+ J = Jab[0] * 0.01; /* J/100 */
+ ja = Jab[1];
+ jb = Jab[2];
+
+ /* Compute hue angle */
+ h = (180.0/DBL_PI) * atan2(jb, ja);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ /* Compute chroma value */
+ C = sqrt(ja * ja + jb * jb); /* Must be Always +ve */
+
+ /* Helmholtz-Kohlraush effect */
+ if (s->hk && J < 1.0) {
+ double kk = C/300.0 * sin(DBL_PI * fabs(0.5 * (h - 90.0))/180.0);
+ if (kk > 0.9) /* Limit kk to a reasonable range */
+ kk = 0.9;
+ J = (J - kk)/(1.0 - kk);
+ }
+
+ /* Eccentricity factor */
+ e = (cos(h * DBL_PI/180.0 + 2.0) + 3.8);
+
+ /* Achromatic response */
+ A = spow(J, 1.0/(s->C * s->z)) * s->Aw; /* Keep sign of J */
+
+ /* Preliminary Saturation - keep +ve */
+ tt = fabs(J);
+ ss = pow(C/(sqrt(tt) * s->nn), 1.0/0.9); /* keep +ve */
+
+ /* Compute a & b, taking care of numerical problems */
+ aa = fabs(ja);
+ ab = fabs(jb);
+ ttA = (A/s->Nbb)+0.305; /* Common factor */
+ tte = 12500.0/13.0 * e * s->Nc * s->Ncb; /* Common factor */
+
+ if (aa < 1e-10 && ab < 1e-10) {
+ a = ja;
+ b = jb;
+ } else if (aa > ab) {
+ double tanh = jb/ja;
+ double sign = (h > 90.0 && h <= 270.0) ? -1.0 : 1.0;
+
+ if (ttA < 0.0)
+ sign = -sign;
+
+ a = (ss * ttA)
+ / (sign * sqrt(1.0 + tanh * tanh) * tte + (ss * (11.0/23.0 + (108.0/23.0) * tanh)));
+ b = a * tanh;
+
+ } else { /* ab > aa */
+ double itanh = ja/jb;
+ double sign = (h > 180.0 && h <= 360.0) ? -1.0 : 1.0;
+
+ if (ttA < 0.0)
+ sign = -sign;
+
+ b = (ss * ttA)
+ / (sign * sqrt(1.0 + itanh * itanh) * tte + (ss * (108.0/23.0 + (11.0/23.0) * itanh)));
+ a = b * itanh;
+ }
+
+ /* Post-adapted cone response of sample */
+ rgba[0] = (20.0/61.0) * ttA
+ + ((41.0 * 11.0)/(61.0 * 23.0)) * a
+ + ((288.0 * 1.0)/(61.0 * 23.0)) * b;
+ rgba[1] = (20.0/61.0) * ttA
+ - ((81.0 * 11.0)/(61.0 * 23.0)) * a
+ - ((261.0 * 1.0)/(61.0 * 23.0)) * b;
+ rgba[2] = (20.0/61.0) * ttA
+ - ((20.0 * 11.0)/(61.0 * 23.0)) * a
+ - ((20.0 * 315.0)/(61.0 * 23.0)) * b;
+
+ /* Hunt-Pointer_Estevez cone space */
+ tt = 1.0/s->Fl;
+ for (i = 0; i < 3; i++) {
+ if (rgba[i] < 0.1) {
+ double ta = rgba[i] > -396.387 ? rgba[i] : -396.387;
+ rgbp[i] = -tt * pow((2.713 - 27.13 * rgba[i] )/(397.387 + ta), 1.0/0.42);
+ } else {
+ double ta = rgba[i] < 399.1 ? rgba[i] : 399.1;
+ rgbp[i] = tt * pow((27.13 * rgba[i] -2.713)/(400.1 - ta), 1.0/0.42);
+ }
+ }
+
+ /* Chromaticaly transformed sample value */
+ rgbc[0] = 1.5591523979049677 * rgbp[0]
+ - 0.5447226796590880 * rgbp[1]
+ - 0.0144453097698588 * rgbp[2];
+ rgbc[1] = -0.7143267176368630 * rgbp[0]
+ + 1.8503099728895096 * rgbp[1]
+ - 0.1359761119854705 * rgbp[2];
+ rgbc[2] = 0.0107755117023383 * rgbp[0]
+ + 0.0052187662221759 * rgbp[1]
+ + 0.9840056143203700 * rgbp[2];
+
+ /* Spectrally sharpened cone responses */
+ rgb[0] = rgbc[0]/s->Drgb[0];
+ rgb[1] = rgbc[1]/s->Drgb[1];
+ rgb[2] = rgbc[2]/s->Drgb[2];
+
+ /* XYZ values */
+ xyz[0] = 1.0961238208355140 * rgb[0]
+ - 0.2788690002182872 * rgb[1]
+ + 0.1827451793827730 * rgb[2];
+ xyz[1] = 0.4543690419753590 * rgb[0]
+ + 0.4735331543074120 * rgb[1]
+ + 0.0720978037172291 * rgb[2];
+ xyz[2] = -0.0096276087384294 * rgb[0]
+ - 0.0056980312161134 * rgb[1]
+ + 1.0153256399545427 * rgb[2];
+
+ /* Subtract flare */
+ XYZ[0] = s->Fisc * (xyz[0] - s->Fsxyz[0]);
+ XYZ[1] = s->Fisc * (xyz[1] - s->Fsxyz[1]);
+ XYZ[2] = s->Fisc * (xyz[2] - s->Fsxyz[2]);
+
+#ifdef DIAG
+ printf("Processing:\n");
+ printf("Jab = %f %f %f\n", Jab[0], Jab[1], Jab[2]);
+ printf("Chroma C = %f\n", C);
+ printf("Preliminary Saturation ss = %f\n", ss);
+ printf("Lightness J = %f\n", J * 100.0);
+ printf("Achromatic response A = %f\n", A);
+ printf("Eccentricity factor e = %f\n", e);
+ printf("Hue angle h = %f\n", h);
+ printf("Prelim red green a = %f, b = %f\n", a, b);
+ printf("Post adapted cone response rgba = %f %f %f\n", rgba[0], rgba[1], rgba[2]);
+ printf("Hunt-P-E cone space rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]);
+ printf("Chromatically transformed sample value rgbc = %f %f %f\n", rgbc[0], rgbc[1], rgbc[2]);
+ printf("Sharpened cone sample rgb = %f %f %f\n", rgb[0], rgb[1], rgb[2]);
+ printf("Including flare XYZ = %f %f %f\n", xyz[0], xyz[1], xyz[2]);
+ printf("XYZ = %f %f %f\n", XYZ[0], XYZ[1], XYZ[2]);
+ printf("\n");
+#endif
+ return 0;
+}
+
+
diff --git a/xicc/cam02test.c b/xicc/cam02test.c
new file mode 100644
index 0000000..3dafc9c
--- /dev/null
+++ b/xicc/cam02test.c
@@ -0,0 +1,1325 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 18/1/2004
+ * Version: 1.00
+ *
+ * Copyright 2000-2011 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.
+ *
+ */
+
+/*
+ * This is some test code to test the CIECAM02 functionality.
+ */
+
+
+#include <stdio.h>
+#include <math.h>
+#include "icc.h"
+#include "xcam.h"
+#include "cam02.h"
+#include "numlib.h"
+#include "cam02ref.h"
+
+ /* ** = usual tests */
+
+#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 TROUBLE /* Test trouble spot colors XYZ -> Jab -> XYZ */
+#undef TROUBLE2 /* Test trouble spot colors Jab -> XYZ -> Jab */
+#undef SPECIAL /* Special exploration code */
+
+#undef LOCUSTEST /* [def] ** Test spectrum locus points */
+#undef LOCUSRAND /* [def] ** Test random spectrum locus points */
+
+#define INVTEST /* [def] ** -100 -> 100 XYZ cube to Jab to XYZ */
+#undef INVTEST1 /* [undef] Single value */
+#undef INVTEST2 /* [undef] Powell search for invers */
+
+#define TESTINV /* [def] ** Jab cube to XYZ to Jab */
+#undef TESTINV1 /* [undef] Single Jab value */
+#undef TESTINV2 /* [undef] J = 0 test values */
+
+//#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 */
+
+//#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 */
+
+#ifndef _isnan
+#define _isnan(x) ((x) != (x))
+#define _finite(x) ((x) == 0.0 || (x) * 1.0000001 != (x))
+#endif
+
+
+#ifdef INVTEST1
+static void
+Lab2XYZ(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ out[0] = x * 0.9642;
+ out[1] = y * 1.0000;
+ out[2] = z * 0.8249;
+}
+#endif /* INVTEST1 */
+
+/* CIE XYZ to perceptual Lab */
+static void
+XYZ2Lab(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/0.9642; /* D50 ? */
+ y = Y/1.0000;
+ z = Z/0.8249;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+
+/* Return maximum difference */
+double maxdiff(double in1[3], double in2[3]) {
+ int i;
+ double tt, rv = 0.0;
+
+ /* Deal with the possibility that we have nan's */
+ for (i = 0; i < 3; i++) {
+ tt = fabs(in1[i] - in2[i]);
+ if (!_finite(tt))
+ return tt;
+ if (tt > rv)
+ rv = tt;
+ }
+ return rv;
+}
+
+/* Return absolute difference */
+double absdiff(double in1[3], double in2[3]) {
+ double tt, rv = 0.0;
+ tt = in1[0] - in2[0];
+ rv += tt * tt;
+ tt = in1[1] - in2[1];
+ rv += tt * tt;
+ tt = in1[2] - in2[2];
+ rv += tt * tt;
+ return sqrt(rv);
+}
+
+/* Return maximum Lab difference of XYZ */
+double maxxyzdiff(double i1[3], double i2[3]) {
+ int i;
+ double tt, rv = 0.0;
+ double in1[3], in2[3];
+
+ XYZ2Lab(in1, i1);
+ XYZ2Lab(in2, i2);
+
+ /* Deal with the possibility that we have nan's */
+ for (i = 0; i < 3; i++) {
+ tt = fabs(in1[i] - in2[i]);
+ if (!_finite(tt))
+ return tt;
+ if (tt > rv)
+ rv = tt;
+ }
+ return rv;
+}
+
+#ifdef INVTEST2
+
+/* Powell callback function and struct */
+typedef struct {
+ cam02 *cam;
+ double Jab[3];
+} cntx;
+
+static double opt1(void *fdata, double tp[]) {
+ cntx *x = (cntx *)fdata;
+ double Jab[3];
+ double tt, rv = 0.0;
+
+ x->cam->XYZ_to_cam(x->cam, Jab, tp);
+
+ tt = Jab[0] - x->Jab[0];
+ rv += tt * tt;
+ tt = Jab[1] - x->Jab[1];
+ rv += tt * tt;
+ tt = Jab[2] - x->Jab[2];
+ rv += tt * tt;
+ return rv;
+}
+
+#endif /* INVTEST2 */
+
+/* 2 degree spectrum locus in xy coordinates */
+/* nm, x, y, Y CMC */
+double sl[65][4] = {
+ { 380, 0.1741, 0.0050, 0.000039097450 },
+ { 385, 0.1740, 0.0050, 0.000065464490 },
+ { 390, 0.1738, 0.0049, 0.000121224052 },
+ { 395, 0.1736, 0.0049, 0.000221434140 },
+ { 400, 0.1733, 0.0048, 0.000395705080 },
+ { 405, 0.1730, 0.0048, 0.000656030940 },
+ { 410, 0.1726, 0.0048, 0.001222776600 },
+ { 415, 0.1721, 0.0048, 0.002210898200 },
+ { 420, 0.1714, 0.0051, 0.004069952000 },
+ { 425, 0.1703, 0.0058, 0.007334133400 },
+ { 430, 0.1689, 0.0069, 0.011637600000 },
+ { 435, 0.1669, 0.0086, 0.016881322000 },
+ { 440, 0.1644, 0.0109, 0.023015402000 },
+ { 445, 0.1611, 0.0138, 0.029860866000 },
+ { 450, 0.1566, 0.0177, 0.038072300000 },
+ { 455, 0.1510, 0.0227, 0.048085078000 },
+ { 460, 0.1440, 0.0297, 0.060063754000 },
+ { 465, 0.1355, 0.0399, 0.074027114000 },
+ { 470, 0.1241, 0.0578, 0.091168598000 },
+ { 475, 0.1096, 0.0868, 0.112811680000 },
+ { 480, 0.0913, 0.1327, 0.139122260000 },
+ { 485, 0.0686, 0.2007, 0.169656160000 },
+ { 490, 0.0454, 0.2950, 0.208513180000 },
+ { 495, 0.0235, 0.4127, 0.259083420000 },
+ { 500, 0.0082, 0.5384, 0.323943280000 },
+ { 505, 0.0039, 0.6548, 0.407645120000 },
+ { 510, 0.0139, 0.7502, 0.503483040000 },
+ { 515, 0.0389, 0.8120, 0.608101540000 },
+ { 520, 0.0743, 0.8338, 0.709073280000 },
+ { 525, 0.1142, 0.8262, 0.792722560000 },
+ { 530, 0.1547, 0.8059, 0.861314320000 },
+ { 535, 0.1929, 0.7816, 0.914322820000 },
+ { 540, 0.2296, 0.7543, 0.953482260000 },
+ { 545, 0.2658, 0.7243, 0.979818740000 },
+ { 550, 0.3016, 0.6923, 0.994576720000 },
+ { 555, 0.3373, 0.6589, 0.999604300000 },
+ { 560, 0.3731, 0.6245, 0.994513460000 },
+ { 565, 0.4087, 0.5896, 0.978204680000 },
+ { 570, 0.4441, 0.5547, 0.951588260000 },
+ { 575, 0.4788, 0.5202, 0.915060800000 },
+ { 580, 0.5125, 0.4866, 0.869647940000 },
+ { 585, 0.5448, 0.4544, 0.816076000000 },
+ { 590, 0.5752, 0.4242, 0.756904640000 },
+ { 595, 0.6029, 0.3965, 0.694818180000 },
+ { 600, 0.6270, 0.3725, 0.630997820000 },
+ { 605, 0.6482, 0.3514, 0.566802360000 },
+ { 610, 0.6658, 0.3340, 0.503096860000 },
+ { 615, 0.6801, 0.3197, 0.441279360000 },
+ { 620, 0.6915, 0.3083, 0.380961920000 },
+ { 625, 0.7006, 0.2993, 0.321156580000 },
+ { 630, 0.7079, 0.2920, 0.265374180000 },
+ { 635, 0.7140, 0.2859, 0.217219520000 },
+ { 640, 0.7190, 0.2809, 0.175199900000 },
+ { 645, 0.7230, 0.2770, 0.138425720000 },
+ { 650, 0.7260, 0.2740, 0.107242628000 },
+ { 655, 0.7283, 0.2717, 0.081786794000 },
+ { 660, 0.7300, 0.2700, 0.061166218000 },
+ { 665, 0.7311, 0.2689, 0.044729418000 },
+ { 670, 0.7320, 0.2680, 0.032160714000 },
+ { 675, 0.7327, 0.2673, 0.023307860000 },
+ { 680, 0.7334, 0.2666, 0.017028548000 },
+ { 685, 0.7340, 0.2660, 0.011981432000 },
+ { 690, 0.7344, 0.2656, 0.008259734600 },
+ { 695, 0.7346, 0.2654, 0.005758363200 },
+ { 700, 0.7347, 0.2653, 0.004117206200 }
+};
+
+int
+main(void) {
+ int ok = 1;
+
+#define NO_WHITES 9
+ double white[9][3] = {
+ { 0.964242, 1.000000, 0.825124 }, /* 0: D50 */
+ { 1.098494, 1.000000, 0.355908 }, /* 1: A */
+ { 0.908731, 1.000000, 0.987233 }, /* 2: F5 */
+ { 1.128981, 1.000000, 0.305862 }, /* 3: D25 */
+ { 0.950471, 1.000000, 1.088828 }, /* 4: D65 */
+ { 0.949662, 1.000000, 1.160438 }, /* 5: D80 */
+ { 0.949662, 1.000000, 1.160438 }, /* 6: D80 */
+ { 0.951297, 1.000000, 1.338196 }, /* 7: D85 */
+ { 0.952480, 1.000000, 1.386693 } /* 8: D90 */
+ };
+#define NO_LAS 6
+ double La[6] = { 10.0, 31.83, 100.0, 318.31, 1000.83, 3183.1 };
+
+#define NO_VCS 4
+
+ ViewingCondition Vc[4] = {
+ vc_average,
+ vc_dark,
+ vc_dim,
+ vc_cut_sheet
+ };
+
+#ifdef SPOTTEST
+#define NO_SPOTS 5
+ double sp_white[6][3] = {
+ { 0.9505, 1.000, 1.0888 },
+ { 0.9505, 1.000, 1.0888 },
+ { 1.0985, 1.000, 0.3558 },
+ { 1.0985, 1.000, 0.3558 },
+ { 0.9505, 1.000, 1.0888 },
+ { 0.9642, 1.000, 0.8249 } /* D50 for inversion tests */
+ };
+ double sp_La[6] = { 318.31, 31.83, 318.31, 31.83, 318.31, 150.0 };
+
+ double sample[5][3] = {
+ { 0.1901, 0.2000, 0.2178 },
+ { 0.5706, 0.4306, 0.3196 },
+ { 0.0353, 0.0656, 0.0214 },
+ { 0.1901, 0.2000, 0.2178 },
+ { 0.9505, 1.000, 1.0888 } /* Check white */
+ };
+
+ /* Reference values (NOT correct anymore, as HK params have changed!!!) */
+#if USE_HK == 1
+ double correct[5][4] = { /* Hue range is last two */
+ { 41.75, 0.10, 217.0, 219.0 },
+ { 69.11, 48.60, 19.9, 19.91 },
+ { 30.22, 46.94, 177.1, 177.2 },
+ { 52.64, 53.07, 249.5, 249.6 },
+ { 100.00, 0.14, 0.0, 360.0 }
+ };
+#else
+ double correct[5][4] = { /* Hue range is last two */
+ { 41.73, 0.10, 217.0, 219.0 },
+ { 65.94, 48.60, 19.90, 19.91 },
+ { 21.79, 46.94, 177.1, 177.2 },
+ { 42.66, 53.07, 249.5, 249.6 },
+ { 100.0, 0.14, 0.0, 360.0 } /* Check white */
+ };
+#endif /* USE_HK */
+// Original values
+//#if USE_HK == 1
+// double correct[5][4] = { /* Hue range is last two */
+// { 41.75, 0.10, 217.0, 219.0 },
+// { 69.13, 48.57, 19.56, 19.56 },
+// { 30.22, 46.94, 177.1, 177.1 },
+// { 52.31, 51.92, 248.9, 248.9 },
+// { 100.00, 0.14, 0.0, 360.0 }
+// };
+#//else
+// double correct[5][4] = { /* Hue range is last two */
+// { 41.73, 0.10, 217.0, 219.0 },
+// { 65.96, 48.57, 19.6, 19.6 },
+// { 21.79, 46.94, 177.1, 177.1 },
+// { 42.53, 51.92, 248.9, 248.9 },
+// { 100.0, 0.14, 0.0, 360.0 } /* Check white */
+// };
+//#endif /* USE_HK */
+#endif /* SPOTTEST */
+
+#if defined(TROUBLE) || defined(TROUBLE2) || defined(SPECIAL)
+#define NO_TROUBLE 1
+ double twhite[3][3] = {
+ { 0.9642, 1.000, 0.8249 }, /* D50 */
+ { 0.949662, 1.000000, 1.160438 }, /* 5: D80 */
+ { 0.9642, 1.000, 0.8249 } /* D50 */
+ };
+ ViewingCondition tVc[3] = { vc_average, vc_average, vc_average };
+ double tLa[3] = { 10.0, 3183.1, 50.0 };
+ double tFlair[3] = { 0.00, 0.01, 0.01 };
+ double tsample[4][3] = {
+ { -1.0, -1.0, -1.0 }, /* Inv Problem */
+ { 34.485160, 0.982246, 164.621489 }, /* Inv Problem */
+ { 0.031339, 0.000000, 0.824895 }, /* ProPhoto Blue - OK */
+ { 0.041795, 0.006211, 0.652597 } /* ProPhoto nearly Blue - fails */
+ };
+ double tsample2[1][3] = {
+ { 3.625000, -121.600000, -64.000000, } /* Inv Problem */
+ };
+#endif /* TROUBLE || TROUBLE2 */
+
+ cam02ref *camr;
+ cam02 *cam;
+ int c, d, e;
+
+ cam = new_cam02();
+ camr = new_cam02ref();
+ camr->range = 1; /* Return on range error */
+#ifdef VERBOSE
+ cam->trace = 1;
+ camr->trace = 1;
+#endif
+
+ /* ================= Trouble colors ===================== */
+#if defined(TROUBLE) || defined(TROUBLE2) || defined(SPECIAL)
+ for (c = 0; c < NO_TROUBLE; c++) {
+
+#ifdef DIAG
+ printf("Case %d:\n",c);
+#endif /* DIAG */
+ camr->set_view(
+ camr,
+ tVc[c], /* Enumerated Viewing Condition */
+ twhite[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ tLa[c], /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ tFlair[c], /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ twhite[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK /* use Helmholtz-Kohlraush flag */
+ );
+ cam->set_view(
+ cam,
+ tVc[c], /* Enumerated Viewing Condition */
+ twhite[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ tLa[c], /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ tFlair[c], /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ twhite[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK /* use Helmholtz-Kohlraush flag */
+ );
+ camr->nldlimit = cam->nldlimit;
+ camr->jlimit = cam->jlimit;
+
+#ifdef DIAG
+ printf("\n");
+#endif /* DIAG */
+
+#ifdef SPECIAL
+ /* See what happens as we approach a neutral color */
+ {
+ double j1[3] = { 50, +0.1, +0.1 }, x1[3];
+ double j2[3] = { 0, +0.1, +0.1 }, x2[3];
+ double Jab[3], xyz[3];
+ double rr = 1.0;
+ int i;
+
+ /* Establish the XYZ */
+ cam->cam_to_XYZ(cam, x1, j1);
+ cam->cam_to_XYZ(cam, x2, j2);
+
+ cam->trace = 1;
+
+ /* Approach it by halves */
+ for (i = 0; i < 100; i++, rr *= 0.5) {
+ xyz[0] = rr * x1[0] + (1.0 - rr) * x2[0];
+ xyz[1] = rr * x1[1] + (1.0 - rr) * x2[1];
+ xyz[2] = rr * x1[2] + (1.0 - rr) * x2[2];
+
+ cam->XYZ_to_cam(cam, Jab, xyz);
+
+ printf("XYZ %f %f %f -> Jab is %f %f %f\n",
+ xyz[0], xyz[1], xyz[2],
+ Jab[0], Jab[1], Jab[2]);
+ }
+ exit(0);
+ }
+#endif /* SPECIAL */
+
+#ifdef TROUBLE
+ {
+ double Jab[3], jabr[3], xyz[3];
+
+ cam->XYZ_to_cam(cam, Jab, tsample[c]);
+
+ if (camr->XYZ_to_cam(camr, jabr, tsample[c])) {
+#ifdef DIAG
+ printf("Reference XYZ2Jab returned error from XYZ %f %f %f\n",tsample[c][0],tsample[c][1],tsample[c][2]);
+#endif /* DIAG */
+ } else if (maxdiff(Jab, jabr) > MAX_REF_ERR) {
+ printf("Spottest: Excessive error to reference for %f %f %f\n",tsample[c][0],tsample[c][1],tsample[c][2]);
+ printf("Spottest: Error %f, Got %f %f %f\n expected %f %f %f\n", maxdiff(Jab, jabr), Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+
+
+#ifdef DIAG
+ printf("XYZ %f %f %f -> Jab is %f %f %f\n",
+ tsample[c][0], tsample[c][1], tsample[c][2],
+ Jab[0], Jab[1], Jab[2]);
+#endif /* DIAG */
+
+ cam->cam_to_XYZ(cam, xyz, Jab);
+
+#ifdef DIAG
+ printf("XYZ %f %f %f -> Jab is %f %f %f\n",
+ Jab[0], Jab[1], Jab[2],
+ xyz[0], xyz[1], xyz[2]);
+#endif /* DIAG */
+
+ if (maxdiff(tsample[c], xyz) > 1e-5) {
+ printf("Spottest trouble 1: Excessive error in inversion %f\n",maxdiff(tsample[c], xyz));
+ printf("Is %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+ printf("Should be %f %f %f\n",tsample[c][0],tsample[c][1],tsample[c][2]);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+ }
+#endif /* TROUBLE */
+
+#ifdef TROUBLE2
+ {
+ double Jab[3], xyz[3];
+
+ cam->cam_to_XYZ(cam, xyz, tsample2[c]);
+
+#ifdef DIAG
+ printf("Lab %f %f %f -> XYZ is %f %f %f\n",
+ tsample2[c][0], tsample2[c][1], tsample2[c][2],
+ xyz[0], xyz[1], xyz[2]);
+#endif /* DIAG */
+
+ cam->XYZ_to_cam(cam, Jab, xyz);
+
+#ifdef DIAG
+ printf("XYZ %f %f %f -> Jab is %f %f %f\n",
+ xyz[0], xyz[1], xyz[2],
+ Jab[0], Jab[1], Jab[2]);
+#endif /* DIAG */
+
+ if (maxdiff(tsample2[c], Jab) > 1e-3) {
+ printf("Spottest trouble2: Excessive error in inversion %f\n",maxdiff(tsample2[c], Jab));
+ printf("Is %f %f %f\n",Jab[0],Jab[1],Jab[2]);
+ printf("Should be %f %f %f\n",tsample2[c][0],tsample2[c][1],tsample2[c][2]);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+ }
+#endif /* TROUBLE2 */
+ }
+#endif /* TROUBLE || TROUBLE 2 */
+ /* =============================================== */
+
+ /* ================= SpotTest ===================== */
+#ifdef SPOTTEST
+ {
+ double mrerr = 0.0, mxerr = 0.0;
+ for (c = 0; c < NO_SPOTS; c++) {
+
+#ifdef DIAG
+ printf("Case %d:\n",c);
+#endif /* DIAG */
+ camr->set_view(
+ camr,
+ vc_average, /* Enumerated Viewing Condition */
+ sp_white[c],/* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ sp_La[c], /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ sp_white[c],/* The Flare color coordinates (typically the Ambient color) */
+ USE_HK /* use Helmholtz-Kohlraush flag */
+ );
+
+ cam->set_view(
+ cam,
+ vc_average, /* Enumerated Viewing Condition */
+ sp_white[c],/* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ sp_La[c], /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ sp_white[c],/* The Flare color coordinates (typically the Ambient color) */
+ USE_HK /* use Helmholtz-Kohlraush flag */
+ );
+
+ camr->nldlimit = cam->nldlimit;
+ camr->jlimit = cam->jlimit;
+
+#ifdef DIAG
+ printf("\n");
+#endif /* DIAG */
+
+ {
+ double Jab[3], JCh[3], jabr[3], res[3], target[3];
+ double mde;
+
+ cam->XYZ_to_cam(cam, Jab, sample[c]);
+
+ if (camr->XYZ_to_cam(camr, jabr, sample[c]))
+ printf("Reference XYZ2Jab returned error\n");
+ else if ((mde = maxdiff(Jab, jabr)) > MAX_REF_ERR) {
+ printf("Spottest: Excessive error to reference for %f %f %f\n",sample[c][0],sample[c][1],sample[c][2]);
+ printf("Spottest: Error %f, Got %f %f %f\n expected %f %f %f\n",maxdiff(Jab, jabr),
+ Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ camr->trace = 1;
+ camr->XYZ_to_cam(camr, jabr, sample[c]);
+ camr->trace = 0;
+ cam->trace = 1;
+ cam->XYZ_to_cam(cam, Jab, sample[c]);
+ cam->trace = 0;
+ fflush(stdout);
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+ if (mde > mrerr)
+ mrerr = mde;
+
+ /* Convert to JCh for checking */
+ JCh[0] = Jab[0];
+
+ /* Compute hue angle */
+ JCh[2] = (180.0/3.14159265359) * atan2(Jab[2], Jab[1]);
+ JCh[2] = (JCh[2] < 0.0) ? JCh[2] + 360.0 : JCh[2];
+
+ /* Compute chroma value */
+ JCh[1] = sqrt(Jab[1] * Jab[1] + Jab[2] * Jab[2]);
+
+ target[0] = correct[c][0];
+ target[1] = correct[c][1];
+ if (JCh[2] >= correct[c][2] && JCh[2] <= correct[c][3]) {
+ target[2] = JCh[2];
+ } else {
+ if (fabs(JCh[2] - correct[c][2]) < fabs(JCh[2] - correct[c][3]))
+ target[2] = correct[c][2];
+ else
+ target[2] = correct[c][3];
+ }
+
+ if ((mde = maxdiff(JCh, target)) > MAX_SPOT_ERR) {
+ printf("Spottest: Excessive error for %f %f %f\n",sample[c][0],sample[c][1],sample[c][2]);
+ printf("Spottest: Excessive error in conversion to CAM %f\n",maxdiff(JCh, target));
+ printf("Jab is %f %f %f\nJch is %f %f %f\n",
+ Jab[0], Jab[1], Jab[2],
+ JCh[0], JCh[1], JCh[2]);
+
+ printf("JCh should be %f %f %f - %f\n",
+ correct[c][0], correct[c][1], correct[c][2], correct[c][3]);
+
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+ if (mde > mxerr)
+ mxerr = mde;
+
+ cam->cam_to_XYZ(cam, res, Jab);
+
+ if (maxdiff(sample[c], res) > 1e-5) {
+ printf("Spottest: Excessive error in inversion %f\n",maxdiff(sample[c], res));
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ cam->trace = 1;
+ cam->XYZ_to_cam(cam, Jab, sample[c]);
+ cam->cam_to_XYZ(cam, res, Jab);
+ cam->trace = 0;
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+#ifdef DIAG
+ printf("Jab is %f %f %f\nJch is %f %f %f\n",
+ Jab[0], Jab[1], Jab[2],
+ JCh[0], JCh[1], JCh[2]);
+
+ printf("JCh should be %f %f %f - %f\n",
+ correct[c][0], correct[c][1], correct[c][2], correct[c][3]);
+
+ printf("XYZ is %f %f %f\n",res[0], res[1], res[2]);
+ printf("Inversion error = %f\n",maxdiff(sample[c], res));
+ printf("\n\n");
+#endif /* DIAG */
+ }
+ }
+ if (ok == 0) {
+ printf("Spottest testing FAILED\n");
+ } else {
+ printf("Spottest testing OK\n");
+ printf("Spottest maximum DE to ref = %f, to expected = %f\n",mrerr,mxerr);
+ }
+ }
+#endif /* SPOTTEST */
+ /* =============================================== */
+
+ /* ================= LocusTest ===================== */
+#ifdef LOCUSTEST
+#define LT_YRES 30
+ {
+ double mxlocde = -100.0; /* maximum locus test delta E */
+
+ for (c = 0; c < NO_WHITES; c++) {
+ printf("Locus: next white reference\n");
+ for (d = 0; d < NO_LAS; d++) {
+ for (e = 0; e < NO_VCS; e++) {
+ int i, j;
+ double Yxy[3], xyz[3], Jab[3], jabr[3], checkxyz[3];
+ double mxd; /* Maximum delta of Lab any component */
+ double ltde; /* Locus test delta E */
+
+ camr->set_view(
+ camr,
+ Vc[e], /* Enumerated Viewing Condition */
+ white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
+ La[d], /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK /* use Helmholtz-Kohlraush flag */
+ );
+
+ cam->set_view(
+ cam,
+ Vc[e], /* Enumerated Viewing Condition */
+ white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
+ La[d], /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK /* use Helmholtz-Kohlraush flag */
+ );
+
+ /* Make reference return error where it's going to disagree with implementation */
+ camr->nldlimit = cam->nldlimit;
+ camr->jlimit = cam->jlimit;
+
+ /* The monochromic boundary with a unit energy monochromic source */
+ for (j = 0; j < LT_YRES; j++) {
+ double Y = j/(LT_YRES - 1.0);
+
+ Y = Y * Y * 0.999 + 0.001;
+
+ for (i = 0; i < 65; i++) {
+ Yxy[0] = Y * sl[i][3];
+ Yxy[1] = sl[i][1];
+ Yxy[2] = sl[i][2];
+
+ icmYxy2XYZ(xyz, Yxy);
+
+ cam->XYZ_to_cam(cam, Jab, xyz);
+
+ if (camr->XYZ_to_cam(camr, jabr, xyz)) {
+#ifdef DIAG
+ printf("Reference XYZ2Jab returned error from XYZ %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+#endif /* DIAG */
+ } else if (maxdiff(Jab, jabr) > MAX_REF_ERR) {
+ printf("Locustest1: Excessive error to reference for %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+ printf("Locustest1: Error %f, Got %f %f %f\n expected %f %f %f\n",maxdiff(Jab, jabr),
+ Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+
+ cam->cam_to_XYZ(cam, checkxyz, Jab);
+
+#ifdef DIAG
+ printf("Inversion error = %f\n",maxdiff(checkxyz, xyz));
+#endif /* DIAG */
+
+ /* Check the result */
+ ltde = icmXYZLabDE(&icmD50, checkxyz, xyz);
+ if (ltde > mxlocde)
+ mxlocde = ltde;
+ mxd = maxxyzdiff(checkxyz, xyz);
+ if (mxd > 0.05) {
+ printf("XYZ %f %f %f\n ->",xyz[0],xyz[1],xyz[2]);
+ printf("Jab %f %f %f\n ->",Jab[0],Jab[1],Jab[2]);
+ printf("XYZ %f %f %f\n",checkxyz[0],checkxyz[1],checkxyz[2]);
+ printf("Locustest1: Excessive roundtrip error %f\n",mxd);
+ printf("c = %d, d = %d, e = %d\n",c,d,e);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+ }
+
+ /* Do the purple line */
+ for (i = 0; i < 20; i++) {
+ double b = i/(20 - 1.0);
+
+ Yxy[0] = (b * sl[0][3] + (1.0 - b) * sl[64][3]) * Y;
+ Yxy[1] = b * sl[0][1] + (1.0 - b) * sl[64][1];
+ Yxy[2] = b * sl[0][2] + (1.0 - b) * sl[64][2];
+ icmYxy2XYZ(xyz, Yxy);
+
+ cam->XYZ_to_cam(cam, Jab, xyz);
+
+ if (camr->XYZ_to_cam(camr, jabr, xyz)) {
+#ifdef DIAG
+ printf("Reference XYZ2Jab returned error from XYZ %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+#endif /* DIAG */
+ } else if (maxdiff(Jab, jabr) > MAX_REF_ERR) {
+ printf("Locustest2: Excessive error to reference for %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+ printf("Locustest2: Error %f, Got %f %f %f,\n expected %f %f %f\n",maxdiff(Jab, jabr),
+ Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+
+ cam->cam_to_XYZ(cam, checkxyz, Jab);
+
+#ifdef DIAG
+ printf("Inversion error = %f\n",maxdiff(checkxyz, xyz));
+#endif /* DIAG */
+
+ /* Check the result */
+ ltde = icmXYZLabDE(&icmD50, checkxyz, xyz);
+ if (ltde > mxlocde)
+ mxlocde = ltde;
+ mxd = maxxyzdiff(checkxyz, xyz);
+ if (mxd > 0.05) {
+ printf("XYZ %f %f %f\n ->",xyz[0],xyz[1],xyz[2]);
+ printf("Jab %f %f %f\n ->",Jab[0],Jab[1],Jab[2]);
+ printf("XYZ %f %f %f\n",checkxyz[0],checkxyz[1],checkxyz[2]);
+ printf("Locustest2: Excessive roundtrip error %f\n",mxd);
+ printf("c = %d, d = %d, e = %d\n",c,d,e);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+ }
+ }
+
+#ifdef LOCUSRAND
+ for (i = 0; i < 20000 ; i++) {
+// for (i = 0; i < 1000000 ; i++) {
+ int i1, i2, i3;
+ double Y, bb1, bb2, bb3;
+
+ i1 = i_rand(0, 64);
+ i2 = i_rand(0, 64);
+ i3 = i_rand(0, 64);
+ bb1 = d_rand(0.0, 1.0);
+ bb2 = d_rand(0.0, 1.0 - bb1);
+ bb3 = 1.0 - bb1 - bb2;
+ Y = d_rand(0.001, 1.0);
+//printf("~1 i1 = %d, i2 = %d, i3 = %d\n",i1,i2,i3);
+//printf("~1 bb1 = %f, bb2 = %f, bb3 = %f\n",bb1,bb2,bb3);
+//printf("~1 Y = %f\n",Y);
+
+ Yxy[0] = bb1 * sl[i1][3] + bb2 * sl[i2][3] + bb3 * sl[i3][3];
+ Yxy[1] = bb1 * sl[i1][1] + bb2 * sl[i2][1] + bb3 * sl[i3][1];
+ Yxy[2] = bb1 * sl[i1][2] + bb2 * sl[i2][2] + bb3 * sl[i3][2];
+ Yxy[0] = Y; /* ??? */
+ icmYxy2XYZ(xyz, Yxy);
+
+ Yxy[0] = (bb1 * sl[i1][3] + bb2 * sl[i2][3] + bb3 * sl[i3][3]) * Y;
+//printf("~1 xyz = %f %f %f\n", xyz[0], xyz[1], xyz[2]);
+
+ cam->XYZ_to_cam(cam, Jab, xyz);
+
+ if (camr->XYZ_to_cam(camr, jabr, xyz)) {
+#ifdef DIAG
+ printf("Reference XYZ2Jab returned error from XYZ %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+#endif /* DIAG */
+ } else if (maxdiff(Jab, jabr) > MAX_REF_ERR) {
+ printf("Locustest3: Excessive error to reference for %f %f %f\n",xyz[0],xyz[1],xyz[2]);
+ printf("Locustest3: Error %f, Got %f %f %f, expected %f %f %f\n",maxdiff(Jab, jabr),
+ Jab[0], Jab[1], Jab[2], jabr[0], jabr[1], jabr[2]);
+ printf("c = %d, d = %d, e = %d\n",c,d,e);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+
+ cam->cam_to_XYZ(cam, checkxyz, Jab);
+
+#ifdef DIAG
+ printf("Inversion error = %f\n",maxdiff(checkxyz, xyz));
+#endif /* DIAG */
+
+ /* Check the result */
+ ltde = icmXYZLabDE(&icmD50, checkxyz, xyz);
+ if (ltde > mxlocde)
+ mxlocde = ltde;
+ mxd = maxxyzdiff(checkxyz, xyz);
+ if (mxd > 0.05) {
+ printf("XYZ %f %f %f\n ->",xyz[0],xyz[1],xyz[2]);
+ printf("Jab %f %f %f\n ->",Jab[0],Jab[1],Jab[2]);
+ printf("XYZ %f %f %f\n",checkxyz[0],checkxyz[1],checkxyz[2]);
+ printf("Locustest3: Excessive roundtrip error %f\n",mxd);
+ printf("c = %d, d = %d, e = %d\n",c,d,e);
+ ok = 0;
+#ifdef EXIT_ON_ERROR
+ fflush(stdout);
+ exit(-1);
+#endif /* EXIT_ON_ERROR */
+ }
+ }
+#endif
+
+ } /* Viewing condition */
+ } /* Luninence */
+ } /* Whites */
+ if (ok == 0) {
+ printf("Locustest FAILED\n");
+ } else {
+ printf("Locustest OK, max DE = %e\n",mxlocde);
+ }
+ }
+#endif /* LOCUSTEST */
+ /* =============================================== */
+
+ /* ================= XYZ->Jab->XYZ ================== */
+#if defined(INVTEST) || defined(INVTEST1) || defined(INVTEST2)
+ {
+ /* Get the range of Jab values */
+ double xmin[3] = { 1e38, 1e38, 1e38 };
+ double xmax[3] = { -1e38, -1e38, -1e38 };
+ double jmin[3] = { 1e38, 1e38, 1e38 };
+ double jmax[3] = { -1e38, -1e38, -1e38 };
+ double merr = 0.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];
+ double mxd;
+
+
+ cam->set_view(
+ cam,
+ vc_average, /* Enumerated Viewing Condition */
+ white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
+ 34.0, /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.01, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK /* use Helmholtz-Kohlraush flag */
+ );
+
+#ifdef INVTEST1
+ /* Test case */
+ Lab[0] = 0.0; Lab[1] = -128.0; Lab[2] = 36.571429;
+ Lab2XYZ(xyz, Lab);
+ cam->XYZ_to_cam(cam, Jab, xyz);
+ cam->cam_to_XYZ(cam, checkxyz, Jab);
+
+ /* Check the result */
+ mxd = maxxyzdiff(checkxyz, xyz);
+ if (_finite(merr) && (!_finite(mxd) || mxd > merr))
+ merr = mxd;
+#ifdef DIAG
+#ifndef VERBOSE
+ if (!_finite(mxd) || mxd > 0.1)
+#endif /* VERBOSE */
+ {
+ printf("\n");
+ printf("c = %d, #### Lab = %f %f %f\n",c, Lab[0], Lab[1], Lab[2]);
+ printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
+ xyz[0],xyz[1],xyz[2],Jab[0],Jab[1],Jab[2],
+ checkxyz[0],checkxyz[1],checkxyz[2],
+ maxxyzdiff(checkxyz, xyz));
+#ifdef EXIT_ON_ERROR
+ if (!_finite(mxd) || mxd > 0.1) {
+ fflush(stdout);
+ exit(-1);
+ }
+#endif /* EXIT_ON_ERROR */
+ }
+#endif /* DIAG */
+
+#endif /* INVTEST1 */
+
+#ifdef INVTEST2
+ {
+ int rv;
+ cntx x;
+ double xyz[3], ss[3], Jab[3];
+
+ x.cam = cam;
+ x.Jab[0] = 0.0;
+ x.Jab[1] = -50.0;
+ x.Jab[2] = -50.0;
+
+ xyz[0] = -0.3;
+ xyz[1] = -0.3;
+ xyz[2] = -0.3;
+
+ ss[0] = 0.3;
+ ss[1] = 0.3;
+ ss[2] = 0.3;
+
+ rv = powell(NULL, 3, xyz, ss, 1e-12, 10000, opt1, (void *)&x);
+ if (rv)
+ printf("Powell failed\n");
+ else {
+ printf("XYZ %f %f %f\n",xyz[0], xyz[1], xyz[2]);
+ }
+ cam->cam_to_XYZ(cam, xyz, x.Jab);
+ printf("Inverted XYZ %f %f %f\n",xyz[0], xyz[1], xyz[2]);
+ cam->XYZ_to_cam(cam, Jab, xyz);
+ printf("Check Jab %f %f %f\n",Jab[0], Jab[1], Jab[2]);
+ c = 6;
+ }
+#endif /* INVTEST2 */
+
+#ifdef INVTEST
+ /* itterate through -20 to +120 XYZ cube space */
+ for (co0 = 0; co0 < TRES; co0++) {
+ xyz[0] = co0/(TRES-1.0);
+ xyz[0] = xyz[0] * 1.4 - 0.2;
+ for (co1 = 0; co1 < TRES; co1++) {
+ xyz[1] = co1/(TRES-1.0);
+ xyz[1] = xyz[1] * 1.4 - 0.2;
+ for (co2 = 0; co2 < TRES; co2++) {
+ int i;
+ xyz[2] = co2/(TRES-1.0);
+ xyz[2] = xyz[2] * 1.4 - 0.2;
+
+ for (i = 0; i < 3; i++) {
+ if (xyz[i] < xmin[i])
+ xmin[i] = xyz[i];
+ if (xyz[i] > xmax[i])
+ xmax[i] = xyz[i];
+ }
+ cam->XYZ_to_cam(cam, Jab, xyz);
+
+ for (i = 0; i < 3; i++) {
+ if (Jab[i] < jmin[i])
+ jmin[i] = Jab[i];
+ if (Jab[i] > jmax[i])
+ jmax[i] = Jab[i];
+ }
+ cam->cam_to_XYZ(cam, checkxyz, Jab);
+
+ /* Check the result */
+ mxd = maxxyzdiff(checkxyz, xyz);
+ if (_finite(merr) && (!_finite(mxd) || mxd > merr))
+ merr = mxd;
+
+#if defined(DIAG) || defined(VERBOSE) || defined(EXIT_ON_ERROR)
+
+#if defined(DIAG) || defined(EXIT_ON_ERROR)
+ if (!_finite(mxd) || mxd > 0.5) /* Delta E */
+#endif /* DIAG || EXIT_ON_ERROR */
+ {
+ double oLab[3];
+
+ printf("\n");
+ printf("#### XYZ = %f %f %f -> %f %f %f\n",
+ xyz[0], xyz[1], xyz[2], checkxyz[0], checkxyz[1], checkxyz[2]);
+ printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
+ xyz[0],xyz[1],xyz[2],Jab[0],Jab[1],Jab[2],
+ checkxyz[0],checkxyz[1],checkxyz[2],
+ maxxyzdiff(checkxyz, xyz));
+ printf("c = %d\n",c);
+#ifdef EXIT_ON_ERROR
+ if (!_finite(mxd) || mxd > 0.1) {
+ cam->trace = 1;
+ cam->XYZ_to_cam(cam, Jab, xyz);
+ cam->cam_to_XYZ(cam, checkxyz, Jab);
+ cam->trace = 0;
+ fflush(stdout);
+ exit(-1);
+ }
+#endif /* EXIT_ON_ERROR */
+ }
+#endif /* DIAG || VERBOSE || EXIT_ON_ERROR */
+ }
+ }
+ }
+#endif /* INVTEST */
+ }
+ if (!_finite(merr) || merr > 0.15) {
+ printf("INVTEST: Excessive error in roundtrip check %f DE\n",merr);
+ ok = 0;
+ }
+ printf("\n");
+ printf("XYZ -> Jab -> XYZ\n");
+ printf("Inversion check complete, peak error = %e DE\n",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]);
+ printf("Z: %f -> %f\n", xmin[2], xmax[2]);
+ 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]);
+ printf("b: %f -> %f\n", jmin[2], jmax[2]);
+ }
+#endif /* INVTEST || INVTEST1 || INVTEST2 */
+ /* =============================================== */
+
+ /* ===================Jab->XYX->Jab ============================ */
+ /* Note that this is expected to fail if BLUECOMPR is enabled */
+#if defined(TESTINV) || defined(TESTINV1) || defined(TESTINV2)
+ {
+ /* Get the range of XYZ values */
+ double xmin[3] = { 1e38, 1e38, 1e38 };
+ double xmax[3] = { -1e38, -1e38, -1e38 };
+ double jmin[3] = { 1e38, 1e38, 1e38 };
+ double jmax[3] = { -1e38, -1e38, -1e38 };
+ double merr = 0.0;
+
+ for (c = 0; c < 6; c++) {
+ int i, j;
+ int co0, co1, co2; /* (using co[3] triggers compiler bug) */
+ double xyz[3], Jab[3], checkJab[3];
+ double mxd;
+
+ cam->set_view(
+ cam,
+ vc_average, /* Enumerated Viewing Condition */
+ white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
+ 34.0, /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.01, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK /* use Helmholtz-Kohlraush flag */
+ );
+
+#ifdef TESTINV1
+ /* Double sample test case */
+ for (j = 0; j < 2; j++) {
+ if (j == 0) {
+// Jab[0] = -2.5; Jab[1] = 128.0; Jab[2] = 128.0;
+ Jab[0] = 0.0; Jab[1] = -7.683075; Jab[2] = -7.683075;
+ } else {
+// Jab[0] = -2.5; Jab[1] = -128.0; Jab[2] = -128.0;
+ Jab[0] = 0.0; Jab[1] = -128.0; Jab[2] = -128.0;
+ }
+// Jab[0] = 21.25; Jab[1] = 0.0; Jab[2] = -64.0;
+// Jab[0] = 1.05; Jab[1] = 0.0; Jab[2] = -64.0;
+// Jab[0] = 0.0; Jab[1] = -128.0; Jab[2] = -128.0;
+
+ for (i = 0; i < 3; i++) {
+ if (Jab[i] < jmin[i])
+ jmin[i] = Jab[i];
+ if (Jab[i] > jmax[i])
+ jmax[i] = Jab[i];
+ }
+ cam->cam_to_XYZ(cam, xyz, Jab);
+ for (i = 0; i < 3; i++) {
+ if (xyz[i] < xmin[i])
+ xmin[i] = xyz[i];
+ if (xyz[i] > xmax[i])
+ xmax[i] = xyz[i];
+ }
+ cam->XYZ_to_cam(cam, checkJab, xyz);
+
+ /* Check the result */
+ mxd = maxdiff(checkJab, Jab);
+ if (_finite(merr) && (!_finite(mxd) || mxd > merr))
+ merr = mxd;
+#ifdef DIAG
+#ifndef VERBOSE
+ if (!_finite(mxd) || mxd > 0.1)
+#endif /* VERBOSE */
+ {
+ printf("\n");
+ printf("#### Jab = %f %f %f\n",Jab[0], Jab[1], Jab[2]);
+ printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
+ Jab[0],Jab[1],Jab[2], xyz[0],xyz[1],xyz[2],
+ checkJab[0],checkJab[1],checkJab[2],
+ maxdiff(checkJab, Jab));
+ printf("c = %d\n",c);
+#ifdef EXIT_ON_ERROR
+ if (!_finite(mxd) || mxd > 0.1) {
+ fflush(stdout);
+ exit(-1);
+ }
+#endif /* EXIT_ON_ERROR */
+ }
+#endif /* DIAG */
+ }
+#endif /* TESTINV1 */
+
+#ifdef TESTINV2
+ { /* J = 0 test cases */
+ int i;
+ for (i = 1; i < 128; i++) {
+ Jab[0] = 0.0;
+ Jab[1] = (double)i/2;
+ Jab[2] = (double)i;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+
+ Jab[0] = 0.0;
+ Jab[1] = (double)-i/2;
+ Jab[2] = (double)i;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+
+ Jab[0] = 0.0;
+ Jab[1] = (double)i/2;
+ Jab[2] = (double)-i;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+
+ Jab[0] = 0.0;
+ Jab[1] = (double)-i/2;
+ Jab[2] = (double)-i;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+
+ Jab[0] = 0.0;
+ Jab[1] = (double)i;
+ Jab[2] = (double)i/2;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+
+ Jab[0] = 0.0;
+ Jab[1] = (double)-i;
+ Jab[2] = (double)i/2;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+
+ Jab[0] = 0.0;
+ Jab[1] = (double)i;
+ Jab[2] = (double)-i/2;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+
+ Jab[0] = 0.0;
+ Jab[1] = (double)-i;
+ Jab[2] = (double)-i/2;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+ }
+ }
+#endif /* TESTINV2 */
+
+#ifdef TESTINV
+ /* itterate through Jab space */
+ for (co0 = 0; co0 < TRES; co0++) {
+ Jab[0] = co0/(TRES-1.0);
+ Jab[0] = -50.0 + Jab[0] * 165.0;
+ for (co1 = 0; co1 < TRES; co1++) {
+ Jab[1] = co1/(TRES-1.0);
+ Jab[1] = (Jab[1] - 0.5) * 256.0;
+ for (co2 = 0; co2 < TRES; co2++) {
+ int i;
+ Jab[2] = co2/(TRES-1.0);
+ Jab[2] = (Jab[2] - 0.5) * 256.0;
+
+ for (i = 0; i < 3; i++) {
+ if (Jab[i] < jmin[i])
+ jmin[i] = Jab[i];
+ if (Jab[i] > jmax[i])
+ jmax[i] = Jab[i];
+ }
+ cam->cam_to_XYZ(cam, xyz, Jab);
+ for (i = 0; i < 3; i++) {
+ if (xyz[i] < xmin[i])
+ xmin[i] = xyz[i];
+ if (xyz[i] > xmax[i])
+ xmax[i] = xyz[i];
+ }
+ cam->XYZ_to_cam(cam, checkJab, xyz);
+
+ /* Check the result */
+ mxd = maxdiff(checkJab, Jab);
+ if (_finite(merr) && (!_finite(mxd) || mxd > merr))
+ merr = mxd;
+#if defined(DIAG) || defined(VERBOSE) || defined(EXIT_ON_ERROR)
+
+#if defined(DIAG) || defined(EXIT_ON_ERROR)
+ if (!_finite(mxd) || mxd > 0.1)
+#endif /* DIAG || EXIT_ON_ERROR */
+ {
+ printf("\n");
+ printf("#### Jab = %f %f %f\n",Jab[0], Jab[1], Jab[2]);
+ printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
+ Jab[0],Jab[1],Jab[2], xyz[0],xyz[1],xyz[2],
+ checkJab[0],checkJab[1],checkJab[2],
+ maxdiff(checkJab, Jab));
+ printf("c = %d\n",c);
+#ifdef EXIT_ON_ERROR
+ if (!_finite(mxd) || mxd > 0.1) {
+ cam->trace = 1;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+ cam->XYZ_to_cam(cam, checkJab, xyz);
+ cam->trace = 0;
+ fflush(stdout);
+ exit(-1);
+ }
+#endif /* EXIT_ON_ERROR */
+ }
+#endif /* DIAG || VERBOSE || EXIT_ON_ERROR */
+ }
+ }
+ }
+#endif /* TESTINV */
+ }
+ if (!_finite(merr) || merr > 1.0) {
+ printf("TESTINV: Excessive error in roundtrip check %f\n",merr);
+ ok = 0;
+ }
+ printf("\n");
+ printf("Jab -> XYX -> Jab\n");
+ printf("Inversion check 2 complete, peak error = %e DE Jab\n",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]);
+ printf("b: %f -> %f\n", jmin[2], jmax[2]);
+ 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]);
+ printf("Z: %f -> %f\n", xmin[2], xmax[2]);
+ }
+#endif /* TESTINV || TESTINV1 TESTINV2 */
+ /* =============================================== */
+
+ printf("\n");
+ if (ok == 0) {
+ printf("Cam testing FAILED\n");
+ } else {
+ printf("Cam testing OK\n");
+ }
+
+ cam->del(cam);
+
+ return 0;
+}
+
diff --git a/xicc/cam97s3.c b/xicc/cam97s3.c
new file mode 100644
index 0000000..d75b33e
--- /dev/null
+++ b/xicc/cam97s3.c
@@ -0,0 +1,596 @@
+
+/*
+ * cam97s3hk
+ *
+ * Color Appearance Model, based on
+ * CIECAM97, "Revision for Practical Applications"
+ * by Mark D. Fairchild, with the addition of the Viewing Flare
+ * model described on page 487 of "Digital Color Management",
+ * by Edward Giorgianni and Thomas Madden, and the
+ * Helmholtz-Kohlraush effect, using the equation
+ * the Bradford-Hunt 96C model as detailed in Mark Fairchilds
+ * book "Color Appearance Models".
+ *
+ * Author: Graeme W. Gill
+ * Date: 5/10/00
+ * Version: 1.20
+ *
+ * Copyright 2000, 2002 Graeme W. Gill
+ * Please refer to COPYRIGHT file for details.
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/* Note that XYZ values are normalised to 1.0 consistent */
+/* with the ICC convention (not 100.0 as assumed by the CIECAM spec.) */
+/* Note that all whites are assumed to be normalised (ie. Y = 1.0) */
+
+/* Various changes have been made to allow the CAM conversions to */
+/* function over a much greater range of XYZ and Jab values that */
+/* the functions are described in the above references. This is */
+/* because such values arise in the process of gamut mapping, and */
+/* in scanning through the grid of PCS values needed to fill in */
+/* the A2B table of an ICC profile. Such values have no correlation */
+/* to a real color value, but none the less need to be handled without */
+/* causing an exception, in a geometrically consistent and reversible */
+/* fashion. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "xcam.h"
+#include "cam97s3.h"
+
+#undef DIAG /* Print internal value diagnostics for each conversion */
+
+#define CAM_PI 3.14159265359
+
+/* Utility function */
+/* Return a viewing condition enumeration from the given Ambient and */
+/* Adapting/Surround Luminance. */
+static ViewingCondition cam97_Ambient2VC(
+double La, /* Ambient Luminance (cd/m^2) */
+double Lv /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+) {
+ double r;
+
+ if (fabs(La) < 1e-10) /* Hmm. */
+ r = 1.0;
+ else
+ r = La/Lv;
+
+ if (r < 0.01)
+ return vc_dark;
+ if (r < 0.2)
+ return vc_dim;
+ return vc_average;
+}
+
+static void cam_free(cam97s3 *s);
+static int set_view(struct _cam97s3 *s, ViewingCondition Ev, double Wxyz[3],
+ double La, double Yb, double Lv, double Yf, double Fxyz[3],
+ int hk);
+static int XYZ_to_cam(struct _cam97s3 *s, double *Jab, double *xyz);
+static int cam_to_XYZ(struct _cam97s3 *s, double *xyz, double *Jab);
+
+/* Create a cam97s3 conversion object, with default viewing conditions */
+cam97s3 *new_cam97s3(void) {
+ cam97s3 *s;
+// double D50[3] = { 0.9642, 1.0000, 0.8249 };
+
+ if ((s = (cam97s3 *)calloc(1, sizeof(cam97s3))) == NULL) {
+ fprintf(stderr,"cam97s3: malloc failed allocating object\n");
+ exit(-1);
+ }
+
+ /* Initialise methods */
+ s->del = cam_free;
+ s->set_view = set_view;
+ s->XYZ_to_cam = XYZ_to_cam;
+ s->cam_to_XYZ = cam_to_XYZ;
+
+ /* Set a default viewing condition ?? */
+ /* set_view(s, vc_average, D50, 33.0, 0.2, 0.0, 0.0, D50, 0); */
+
+ return s;
+}
+
+static void cam_free(cam97s3 *s) {
+ if (s != NULL)
+ free(s);
+}
+
+/* A version of the pow() function that preserves the */
+/* sign of its first argument. */
+static double spow(double x, double y) {
+ return x < 0.0 ? -pow(-x,y) : pow(x,y);
+}
+
+static int set_view(
+cam97s3 *s,
+ViewingCondition Ev, /* Enumerated Viewing Condition */
+double Wxyz[3], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+double La, /* Adapting/Surround Luminance cd/m^2 */
+double Yb, /* Relative Luminance of Background to reference white */
+double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set to other than vc_none */
+double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+double Fxyz[3], /* The Flare white coordinates (typically the Ambient color) */
+int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+) {
+ double tt;
+
+ if (Ev == vc_none) /* Compute enumerated viewing condition */
+ Ev = cam97_Ambient2VC(La, Lv);
+ /* Transfer parameters to the object */
+ s->Ev = Ev;
+ s->Wxyz[0] = Wxyz[0];
+ s->Wxyz[1] = Wxyz[1];
+ s->Wxyz[2] = Wxyz[2];
+ s->Yb = Yb > 0.005 ? Yb : 0.005; /* Set minimum to avoid divide by 0.0 */
+ s->La = La;
+ s->Yf = Yf;
+ s->Fxyz[0] = Fxyz[0];
+ s->Fxyz[1] = Fxyz[1];
+ s->Fxyz[2] = Fxyz[2];
+ s->hk = hk;
+
+ /* Compute the internal parameters by category */
+ switch(s->Ev) {
+ case vc_dark:
+ s->C = 0.525;
+ s->Nc = 0.8;
+ s->F = 0.9;
+ break;
+ case vc_dim:
+ s->C = 0.59;
+ s->Nc = 0.95;
+ s->F = 0.9;
+ break;
+ case vc_cut_sheet:
+ s->C = 0.41;
+ s->Nc = 0.8;
+ s->F = 0.9;
+ break;
+ default: /* average */
+ s->C = 0.69;
+ s->Nc = 1.0;
+ s->F = 1.0;
+ break;
+ }
+
+ /* Compute values that only change with viewing parameters */
+
+ /* Figure out the Flare contribution to the flareless XYZ input */
+ tt = s->Yf * s->Wxyz[1]/s->Fxyz[1];
+ s->Fsxyz[0] = tt * s->Fxyz[0];
+ s->Fsxyz[1] = tt * s->Fxyz[1];
+ s->Fsxyz[2] = tt * s->Fxyz[2];
+
+ /* Rescale so that the sum of the flare and the input doesn't exceed white */
+ s->Fsc = s->Wxyz[1]/(s->Fsxyz[1] + s->Wxyz[1]);
+ s->Fsxyz[0] *= s->Fsc;
+ s->Fsxyz[1] *= s->Fsc;
+ s->Fsxyz[2] *= s->Fsc;
+ s->Fisc = 1.0/s->Fsc;
+
+ /* Sharpened cone response white values */
+ s->rgbW[0] = 0.8562 * s->Wxyz[0] + 0.3372 * s->Wxyz[1] - 0.1934 * s->Wxyz[2];
+ s->rgbW[1] = -0.8360 * s->Wxyz[0] + 1.8327 * s->Wxyz[1] + 0.0033 * s->Wxyz[2];
+ s->rgbW[2] = 0.0357 * s->Wxyz[0] - 0.0469 * s->Wxyz[1] + 1.0112 * s->Wxyz[2];
+
+ /* Degree of chromatic adaptation */
+ s->D = s->F - (s->F / (1.0 + 2.0 * pow(s->La, 0.25) + s->La * s->La / 300.0) );
+
+ /* Chromaticaly transformed white value */
+ s->rgbcW[0] = (s->D * (1.0/s->rgbW[0]) + 1.0 - s->D ) * s->rgbW[0];
+ s->rgbcW[1] = (s->D * (1.0/s->rgbW[1]) + 1.0 - s->D ) * s->rgbW[1];
+ s->rgbcW[2] = (s->D * (1.0/s->rgbW[2]) + 1.0 - s->D ) * s->rgbW[2];
+
+ /* Transform from spectrally sharpened, to Hunt-Pointer_Estevez cone space */
+ s->rgbpW[0] = 0.6962394300923847 * s->rgbcW[0]
+ + 0.2492311682812913 * s->rgbcW[1]
+ + 0.0545394016263241 * s->rgbcW[2];
+ s->rgbpW[1] = 0.3054822636273227 * s->rgbcW[0]
+ + 0.5921282520433844 * s->rgbcW[1]
+ + 0.1023894843292929 * s->rgbcW[2];
+ s->rgbpW[2] = -0.0139683251072516 * s->rgbcW[0]
+ + 0.0278065725014340 * s->rgbcW[1]
+ + 0.9861617526058175 * s->rgbcW[2];
+
+ /* Background induction factor */
+ s->n = s->Yb/ s->Wxyz[1];
+ s->nn = pow((1.64 - pow(0.29, s->n)), 1.41); /* Pre computed value */
+
+ /* Lightness contrast factor ?? */
+ {
+ double k;
+
+ k = 1.0 / (5.0 * s->La + 1.0);
+ s->Fl = 0.2 * pow(k , 4.0) * 5.0 * s->La
+ + 0.1 * pow(1.0 - pow(k , 4.0) , 2.0) * pow(5.0 * s->La , 1.0/3.0);
+ }
+
+ /* Background and Chromatic brightness induction factors */
+ s->Nbb = 0.725 * pow(1.0/s->n, 0.2);
+ s->Ncb = s->Nbb;
+
+ /* Base exponential nonlinearity */
+ s->z = 1.0 + pow(s->n , 0.5);
+
+ /* Post-adapted cone response of white */
+ tt = pow(s->Fl * s->rgbpW[0], 0.73);
+ s->rgbaW[0] = (40.0 * tt / (tt + 2.0)) + 1.0;
+ tt = pow(s->Fl * s->rgbpW[1], 0.73);
+ s->rgbaW[1] = (40.0 * tt / (tt + 2.0)) + 1.0;
+ tt = pow(s->Fl * s->rgbpW[2], 0.73);
+ s->rgbaW[2] = (40.0 * tt / (tt + 2.0)) + 1.0;
+
+ /* Achromatic response of white */
+ s->Aw = (2.0 * s->rgbaW[0] + s->rgbaW[1] + (1.0/20.0) * s->rgbaW[2] - 3.05) * s->Nbb;
+
+#ifdef DIAG
+ printf("Scene parameters:\n");
+ printf("Viewing condition Ev = %d\n",s->Ev);
+ printf("Ref white Wxyz = %f %f %f\n", s->Wxyz[0], s->Wxyz[1], s->Wxyz[2]);
+ printf("Relative liminance of background Yb = %f\n", s->Yb);
+ printf("Adapting liminance La = %f\n", s->La);
+ printf("Flare Yf = %f\n", s->Yf);
+ printf("Flare color Fxyz = %f %f %f\n", s->Fxyz[0], s->Fxyz[1], s->Fxyz[2]);
+
+ printf("Internal parameters:\n");
+ printf("Surround Impact C = %f\n", s->C);
+ printf("Chromatic Induction Nc = %f\n", s->Nc);
+ printf("Adaptation Degree F = %f\n", s->F);
+
+ printf("Pre-computed values\n");
+ printf("Sharpened cone white rgbW = %f %f %f\n", s->rgbW[0], s->rgbW[1], s->rgbW[2]);
+ printf("Degree of chromatic adaptation D = %f\n", s->D);
+ printf("Chromatically transformed white rgbcW = %f %f %f\n", s->rgbcW[0], s->rgbcW[1], s->rgbcW[2]);
+ printf("Hunter-P-E cone response white rgbpW = %f %f %f\n", s->rgbpW[0], s->rgbpW[1], s->rgbpW[2]);
+ printf("Background induction factor n = %f\n", s->n);
+ printf("Lightness contrast factor Fl = %f\n", s->Fl);
+ printf("Background brightness induction factor Nbb = %f\n", s->Nbb);
+ printf("Chromatic brightness induction factor Ncb = %f\n", s->Ncb);
+ printf("Base exponential nonlinearity z = %f\n", s->z);
+ printf("Post adapted cone response white rgbaW = %f %f %f\n", s->rgbaW[0], s->rgbaW[1], s->rgbaW[2]);
+ printf("Achromatic response of white Aw = %f\n", s->Aw);
+#endif
+ return 0;
+}
+
+/* Conversions */
+static int XYZ_to_cam(
+struct _cam97s3 *s,
+double Jab[3],
+double XYZ[3]
+) {
+ int i;
+ double xyz[3], rgb[3], rgbp[3], rgba[3], rgbc[3];
+ double a, b, nab, J, C, h, e, A, ss;
+ double ttd, tt;
+
+ /* Add in flare */
+ xyz[0] = s->Fsc * XYZ[0] + s->Fsxyz[0];
+ xyz[1] = s->Fsc * XYZ[1] + s->Fsxyz[1];
+ xyz[2] = s->Fsc * XYZ[2] + s->Fsxyz[2];
+
+ /* Spectrally sharpened cone responses */
+ rgb[0] = 0.8562 * xyz[0] + 0.3372 * xyz[1] - 0.1934 * xyz[2];
+ rgb[1] = -0.8360 * xyz[0] + 1.8327 * xyz[1] + 0.0033 * xyz[2];
+ rgb[2] = 0.0357 * xyz[0] - 0.0469 * xyz[1] + 1.0112 * xyz[2];
+
+ /* Chromaticaly transformed sample value */
+ rgbc[0] = (s->D * (1.0/s->rgbW[0]) + 1.0 - s->D ) * rgb[0];
+ rgbc[1] = (s->D * (1.0/s->rgbW[1]) + 1.0 - s->D ) * rgb[1];
+ rgbc[2] = (s->D * (1.0/s->rgbW[2]) + 1.0 - s->D ) * rgb[2];
+
+ /* Transform from spectrally sharpened, to Hunt-Pointer_Estevez cone space */
+ rgbp[0] = 0.6962394300923847 * rgbc[0]
+ + 0.2492311682812913 * rgbc[1]
+ + 0.0545394016263241 * rgbc[2];
+ rgbp[1] = 0.3054822636273227 * rgbc[0]
+ + 0.5921282520433844 * rgbc[1]
+ + 0.1023894843292929 * rgbc[2];
+ rgbp[2] = -0.0139683251072516 * rgbc[0]
+ + 0.0278065725014340 * rgbc[1]
+ + 0.9861617526058175 * rgbc[2];
+
+ /* Post-adapted cone response of sample. */
+ /* rgba[] has a minimum value of 1.0 for XYZ[] = 0 and no flare. */
+ /* We add linear segments at the ends of this conversion to */
+ /* allow numerical handling of a wider range of values */
+ for (i = 0; i < 3; i++) {
+ if (rgbp[i] < 0.0) {
+ tt = pow(s->Fl * -rgbp[i], 0.73);
+ if (tt < 78.0)
+ rgba[i] = (2.0 - 39.0 * tt) / (tt + 2.0);
+ else
+ rgba[i] = (2.0 - tt) / 2.0;
+
+ } else {
+ tt = pow(s->Fl * rgbp[i], 0.73);
+ if (tt < 78.0)
+ rgba[i] = (41.0 * tt + 2.0) / (tt + 2.0);
+ else
+ rgba[i] = (tt + 2.0) / 2.0;
+ }
+ }
+
+ /* Preliminary red-green & yellow-blue opponent dimensions */
+ a = rgba[0] - 12.0 * rgba[1]/11.0 + rgba[2]/11.0;
+ b = (1.0/9.0) * (rgba[0] + rgba[1] - 2.0 * rgba[2]);
+ nab = sqrt(a * a + b * b); /* Normalised a, b */
+
+ /* Hue angle */
+ h = (180.0/CAM_PI) * atan2(b,a);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ /* Eccentricity factor */
+ {
+ double r, e1, e2, h1, h2;
+
+ if (h <= 20.14)
+ e1 = 0.8565, e2 = 0.8, h1 = 0.0, h2 = 20.14;
+ else if (h <= 90.0)
+ e1 = 0.8, e2 = 0.7, h1 = 20.14, h2 = 90.0;
+ else if (h <= 164.25)
+ e1 = 0.7, e2 = 1.0, h1 = 90.0, h2 = 164.25;
+ else if (h <= 237.53)
+ e1 = 1.0, e2 = 1.2, h1 = 164.25, h2 = 237.53;
+ else
+ e1 = 1.2, e2 = 0.8565, h1 = 237.53, h2 = 360.0;
+
+ r = (h-h1)/(h2-h1);
+#ifdef CIECAM97S3_SPLINE_E
+ r = r * r * (3.0 - 2.0 * r);
+#endif
+ e = e1 + r * (e2-e1);
+ }
+
+ /* Achromatic response */
+ /* Note that the minimum values of rgba[] for XYZ = 0 is 1.0, */
+ /* hence magic 3.05 below comes from the following weighting of rgba[], */
+ /* to base A at 0.0 */
+ A = (2.0 * rgba[0] + rgba[1] + (1.0/20.0) * rgba[2] - 3.05) * s->Nbb;
+
+ /* Lightness */
+ J = spow(A/s->Aw, s->C * s->z); /* J/100 - keep Sign */
+
+ /* Saturation */
+ /* Note that the minimum values for rgba[] for XYZ = 0 is 1.0 */
+ /* Hence magic 3.05 below comes from the following weighting of rgba[] */
+ ttd = rgba[0] + rgba[1] + (21.0/20.0) * rgba[2];
+ ttd = fabs(ttd);
+ if (ttd < 3.05) { /* If not physically realisable, limit denominator */
+ ttd = 3.05; /* hence limit max ss value */
+ }
+ ss = (50000.0/13.0 * s->Nc * s->Ncb * nab * e) / ttd;
+
+ /* Chroma - Keep C +ve and make sure J doesn't force it to 0 */
+ tt = fabs(J);
+ if (tt < 0.01)
+ tt = 0.01;
+ C = 0.7487 * pow(ss, 0.973) * pow(tt, 0.945 * s->n) * s->nn;
+
+ /* Helmholtz-Kohlraush effect */
+ if (s->hk) {
+ double kk = C/300.0 * sin(CAM_PI * fabs(0.5 * (h - 90.0))/180.0);
+ if (kk > 0.9) /* Limit kk to a reasonable range */
+ kk = 0.9;
+ J = J + (1.0 - J) * kk;
+ }
+
+ J *= 100.0; /* Scale J */
+
+ /* Compute Jab value */
+ Jab[0] = J;
+ if (nab > 1e-10) {
+ Jab[1] = C * a/nab;
+ Jab[2] = C * b/nab;
+ } else {
+ Jab[1] = 0.0;
+ Jab[2] = 0.0;
+ }
+
+#ifdef DIAG
+ printf("Processing:\n");
+ printf("XYZ = %f %f %f\n", XYZ[0], XYZ[1], XYZ[2]);
+ printf("Including flare XYZ = %f %f %f\n", xyz[0], xyz[1], xyz[2]);
+ printf("Sharpened cone sample rgb = %f %f %f\n", rgb[0], rgb[1], rgb[2]);
+ printf("Chromatically transformed sample value rgbc = %f %f %f\n", rgbc[0], rgbc[1], rgbc[2]);
+ printf("Hunt-P-E cone space rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]);
+ printf("Post adapted cone response rgba = %f %f %f\n", rgba[0], rgba[1], rgba[2]);
+ printf("Prelim red green a = %f, b = %f\n", a, b);
+ printf("Hue angle h = %f\n", h);
+ printf("Eccentricity factor e = %f\n", e);
+ printf("Achromatic response A = %f\n", A);
+ printf("Lightness J = %f\n", J);
+ printf("Saturation ss = %f\n", ss);
+ printf("Chroma C = %f\n", C);
+ printf("Jab = %f %f %f\n", Jab[0], Jab[1], Jab[2]);
+#endif
+ return 0;
+}
+
+static int cam_to_XYZ(
+struct _cam97s3 *s,
+double XYZ[3],
+double Jab[3]
+) {
+ int i;
+ double xyz[3], rgb[3], rgbp[3], rgba[3], rgbc[3];
+ double ja, jb, aa, ab, a, b, J, C, h, e, A, ss;
+ double tt, ttA, tte;
+
+ J = Jab[0] * 0.01; /* J/100 */
+ ja = Jab[1];
+ jb = Jab[2];
+
+ /* Compute hue angle */
+ h = (180.0/CAM_PI) * atan2(jb, ja);
+ h = (h < 0.0) ? h + 360.0 : h;
+
+ /* Compute chroma value */
+ C = sqrt(ja * ja + jb * jb); /* Must be Always +ve */
+
+ /* Helmholtz-Kohlraush effect */
+ if (s->hk) {
+ double kk = C/300.0 * sin(CAM_PI * fabs(0.5 * (h - 90.0))/180.0);
+ if (kk > 0.9) /* Limit kk to a reasonable range */
+ kk = 0.9;
+ J = (J - kk)/(1.0 - kk);
+ }
+
+ /* Eccentricity factor */
+ {
+ double r, e1, e2, h1, h2;
+
+ if (h <= 20.14)
+ e1 = 0.8565, e2 = 0.8, h1 = 0.0, h2 = 20.14;
+ else if (h <= 90.0)
+ e1 = 0.8, e2 = 0.7, h1 = 20.14, h2 = 90.0;
+ else if (h <= 164.25)
+ e1 = 0.7, e2 = 1.0, h1 = 90.0, h2 = 164.25;
+ else if (h <= 237.53)
+ e1 = 1.0, e2 = 1.2, h1 = 164.25, h2 = 237.53;
+ else
+ e1 = 1.2, e2 = 0.8565, h1 = 237.53, h2 = 360.0;
+
+ r = (h-h1)/(h2-h1);
+#ifdef CIECAM97S3_SPLINE_E
+ r = r * r * (3.0 - 2.0 * r);
+#endif
+ e = e1 + r * (e2-e1);
+ }
+
+ /* Achromatic response */
+ A = spow(J, 1.0/(s->C * s->z)) * s->Aw; /* Keep sign of J */
+
+ /* Saturation - keep +ve and make sure J = 0 doesn't blow it up. */
+ tt = fabs(J);
+ if (tt < 0.01)
+ tt = 0.01;
+ ss = pow(C/(0.7487 * pow(tt, 0.945 * s->n) * s->nn), 1.0/0.973); /* keep +ve */
+
+ /* Compute a & b, taking care of numerical problems */
+ aa = fabs(ja);
+ ab = fabs(jb);
+ ttA = (A/s->Nbb)+3.05; /* Common factor */
+ tte = 50000.0/13.0 * e * s->Nc * s->Ncb; /* Common factor */
+
+ if (aa < 1e-10 && ab < 1e-10) {
+ a = ja;
+ b = jb;
+ } else if (aa > ab) {
+ double tanh = jb/ja;
+ double sign = (h > 90.0 && h <= 270.0) ? -1.0 : 1.0;
+
+ if (ttA < 0.0)
+ sign = -sign;
+
+ a = (ss * ttA)
+ / (sign * sqrt(1.0 + tanh * tanh) * tte + (ss * (11.0/23.0 + (108.0/23.0) * tanh)));
+ b = a * tanh;
+
+ } else { /* ab > aa */
+ double itanh = ja/jb;
+ double sign = (h > 180.0 && h <= 360.0) ? -1.0 : 1.0;
+
+ if (ttA < 0.0)
+ sign = -sign;
+
+ b = (ss * ttA)
+ / (sign * sqrt(1.0 + itanh * itanh) * tte + (ss * (108.0/23.0 + (11.0/23.0) * itanh)));
+ a = b * itanh;
+ }
+
+ { /* Check if we have a limited saturation because it is non-realisable */
+ double tts;
+ double nab = sqrt(a * a + b * b); /* Normalised a, b */
+ tts = (nab * tte) / 3.05; /* Limited saturation number */
+ if (tts < ss) { /* Saturation exceeds it anyway so must have limited denom. */
+ a *= ss/tts; /* Rescale a & b to account for extra ss */
+ b *= ss/tts; /* even though denom was limited (since nab was in numerator). */
+ }
+ }
+
+ /* Post-adapted cone response of sample */
+ rgba[0] = (20.0/61.0) * ttA
+ + ((41.0 * 11.0)/(61.0 * 23.0)) * a
+ + ((288.0 * 1.0)/(61.0 * 23.0)) * b;
+ rgba[1] = (20.0/61.0) * ttA
+ - ((81.0 * 11.0)/(61.0 * 23.0)) * a
+ - ((261.0 * 1.0)/(61.0 * 23.0)) * b;
+ rgba[2] = (20.0/61.0) * ttA
+ - ((20.0 * 11.0)/(61.0 * 23.0)) * a
+ - ((20.0 * 315.0)/(61.0 * 23.0)) * b;
+
+ /* Hunt-Pointer_Estevez cone space */
+ /* (with linear segments at the ends0 */
+ tt = 1.0/s->Fl;
+ for (i = 0; i < 3; i++) {
+ if (rgba[i] < 1.0) {
+ double ta = rgba[i] > -38.0 ? rgba[i] : -38.0;
+ rgbp[i] = -tt * pow((2.0 - 2.0 * rgba[i] )/(39.0+ ta), 1.0/0.73);
+ } else {
+ double ta = rgba[i] < 40.0 ? rgba[i] : 40.0;
+ rgbp[i] = tt * pow((2.0 * rgba[i] -2.0)/(41.0 - ta), 1.0/0.73);
+ }
+ }
+
+ /* Chromaticaly transformed sample value */
+ rgbc[0] = 1.7605948990728097 * rgbp[0]
+ - 0.7400833814121892 * rgbp[1]
+ - 0.0205291236096116 * rgbp[2];
+ rgbc[1] = -0.9170843265341294 * rgbp[0]
+ + 2.0826033118941054 * rgbp[1]
+ - 0.1655098145167107 * rgbp[2];
+ rgbc[2] = 0.0507964678367941 * rgbp[0]
+ - 0.0692054676442407 * rgbp[1]
+ + 1.0184084918427683 * rgbp[2];
+
+ /* Spectrally sharpened cone responses */
+ rgb[0] = rgbc[0]/(s->D * (1.0/s->rgbW[0]) + 1.0 - s->D);
+ rgb[1] = rgbc[1]/(s->D * (1.0/s->rgbW[1]) + 1.0 - s->D);
+ rgb[2] = rgbc[2]/(s->D * (1.0/s->rgbW[2]) + 1.0 - s->D);
+
+ /* XYZ values */
+ xyz[0] = 0.9873999149199270 * rgb[0]
+ - 0.1768250198556842 * rgb[1]
+ + 0.1894251049357572 * rgb[2];
+ xyz[1] = 0.4504351090445316 * rgb[0]
+ + 0.4649328977527109 * rgb[1]
+ + 0.0846319932027575 * rgb[2];
+ xyz[2] = -0.0139683251072516 * rgb[0]
+ + 0.0278065725014340 * rgb[1]
+ + 0.9861617526058175 * rgb[2];
+
+ /* Subtract flare */
+ XYZ[0] = s->Fisc * (xyz[0] - s->Fsxyz[0]);
+ XYZ[1] = s->Fisc * (xyz[1] - s->Fsxyz[1]);
+ XYZ[2] = s->Fisc * (xyz[2] - s->Fsxyz[2]);
+
+#ifdef DIAG
+ printf("Processing:\n");
+ printf("Jab = %f %f %f\n", Jab[0], Jab[1], Jab[2]);
+ printf("Chroma C = %f\n", C);
+ printf("Saturation ss = %f\n", ss);
+ printf("Lightness J = %f\n", J * 100.0);
+ printf("Achromatic response A = %f\n", A);
+ printf("Eccentricity factor e = %f\n", e);
+ printf("Hue angle h = %f\n", h);
+ printf("Prelim red green a = %f, b = %f\n", a, b);
+ printf("Post adapted cone response rgba = %f %f %f\n", rgba[0], rgba[1], rgba[2]);
+ printf("Hunt-P-E cone space rgbp = %f %f %f\n", rgbp[0], rgbp[1], rgbp[2]);
+ printf("Chromatically transformed sample value rgbc = %f %f %f\n", rgbc[0], rgbc[1], rgbc[2]);
+ printf("Sharpened cone sample rgb = %f %f %f\n", rgb[0], rgb[1], rgb[2]);
+ printf("Including flare XYZ = %f %f %f\n", xyz[0], xyz[1], xyz[2]);
+ printf("XYZ = %f %f %f\n", XYZ[0], XYZ[1], XYZ[2]);
+#endif
+ return 0;
+}
+
+
+
+
diff --git a/xicc/cam97s3.h b/xicc/cam97s3.h
new file mode 100644
index 0000000..9893ea4
--- /dev/null
+++ b/xicc/cam97s3.h
@@ -0,0 +1,169 @@
+
+/*
+ * cam97s3
+ *
+ * Color Appearance Model, based on
+ * CIECAM97, "Revision for Practical Applications"
+ * by Mark D. Fairchild, with the addition of the Viewing Flare
+ * model described on page 487 of "Digital Color Management",
+ * by Edward Giorgianni and Thomas Madden, and the
+ * Helmholtz-Kohlraush effect, using the equation
+ * the Bradford-Hunt 96C model as detailed in Mark Fairchilds
+ * book "Color Appearance Models".
+ *
+ * Author: Graeme W. Gill
+ * Date: 5/10/00
+ * Version: 1.20
+ *
+ * Copyright 2000 Graeme W. Gill
+ * Please refer to COPYRIGHT file for details.
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/* Algorithm tweaks */
+#define CIECAM97S3_SPLINE_E /* Use spline interpolation for eccentricity factor */
+
+/* Definitions assumed here:
+
+ Stimulus field is the 2 degrees field of view of the sample
+ being characterised.
+
+ Viewing/Scene/Image field is the area of the whole image or
+ display surface that the stimulus is part of.
+
+ Background field is 10-12 degree field surrounding the stimulus field.
+ This may be within, overlap or encompass the Viewing/Scene/Image field.
+
+ Surround/Adapting field is the visual field minus the background field.
+
+ Visual field is the 130 degree angular field that is seen by the eyes.
+
+ Illuminating field is the field that illuminates the reflective
+ Scene/Image. It may be the same as the Ambient field.
+
+ Ambient field is the whole surrounding environmental light field.
+
+ NOTE: In "Digital Color Management", Giorgianni and Madden use the term
+ "Surround" to mean the same thing as "Background" in the CIECAM97 terminology.
+ The ICC standard doesn't define what it means by "Surround illumination".
+
+*/
+
+/* Rules of Thumb: */
+/* Ambient Luminance (Lat, cd/m^2) is Ambient Illuminance (Lux) divided by PI. */
+/* i.e. Lat = Iat/PI */ /* (1 foot candle = 0.0929 lux) */
+
+/* The Adapting/Surround Luminance is often taken to be */
+/* the 20% of the Ambient Luminance. (gray world) */
+/* i.e. La = Lat/5 = Iat/15.7 */
+
+/* For a reflective print, the Viewing/Scene/Image luminance (Lv, cd/m^2), */
+/* will be the Illuminating Luminance (Li, cd/m^2) reflected by the */
+/* media white point (Yw) */
+
+/* If there is no special illumination for a reflective print, */
+/* then the Illuminating Luminance (Li) will be the Ambient Luminance (Lat) */
+
+/* An emisive display will have an independently determined Lv. */
+
+/* The classification of the type of surround is */
+/* determined by comparing the Adapting/Surround luminance (La, cd/m^2) */
+/* with the average luminance of the Viewing/Scene/Image field (Lv, cd/m^2) */
+
+/* La/Lv == 0%, dark */
+/* La/Lv 0 - 20%, dim */
+/* La/Lv > 20%, average */
+/* special, cut sheet */
+
+/* The Background relative luminance Yb is typically assumed to */
+/* be 0.18 .. 0.2, and is assumed to be grey. */
+
+/* The source of flare light depends on the type of display system. */
+/* For a CRT, it will be the Ambient light reflecting off the glass surface. */
+/* (This implies Yf = Lat * reflectance/Lv) */
+/* For a reflection print, it will be the Illuminant reflecting from the media */
+/* surface. (Yf = Li * reflectance) */
+/* For a projected image, it will be stray projector light, scattered by the */
+/* surround, screen and air particles. (Yf = Li * reflectance_and_scattering) */
+
+/*
+
+ Typical Ambient Illuminance brightness
+ (Lux) La Condition
+ 11 1 Twilight
+ 32 2 Subdued indoor lighting
+ 64 4 Less than typical office light; sometimes recommended for
+ display-only workplaces (sRGB)
+ 350 22 Typical Office (sRGB annex D)
+ 500 32 Practical print evaluationa (ISO-3664 P2)
+ 1000 64 Good Print evaluation (CIE 116-1995)
+ 1000 64 Overcast Outdoors
+ 2000 127 Critical print evaluation (ISO-3664 P1)
+ 10000 637 Typical outdoors, full daylight
+ 50000 3185 Bright summers day
+
+*/
+
+/* ---------------------------------- */
+struct _cam97s3 {
+/* Public: */
+ void (*del)(struct _cam97s3 *s); /* We're done with it */
+
+ int (*set_view)(
+ struct _cam97s3 *s,
+ ViewingCondition Ev, /* Enumerated Viewing Condition */
+ double Wxyz[3], /* Reference/Adapted White XYZ (Y scale 1.0) */
+ double La, /* Adapting/Surround Luminance cd/m^2 */
+ double Yb, /* Luminance of Background relative to reference white (range 0.0 .. 1.0) */
+ double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set */
+ double Yf, /* Flare as a fraction of the reference white (range 0.0 .. 1.0) */
+ double Fxyz[3], /* The Flare white coordinates (typically the Ambient color) */
+ int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+ );
+
+ /* Conversions */
+ int (*XYZ_to_cam)(struct _cam97s3 *s, double *out, double *in);
+ int (*cam_to_XYZ)(struct _cam97s3 *s, double *out, double *in);
+
+/* Private: */
+ /* Scene parameters */
+ ViewingCondition Ev; /* Enumerated Viewing Condition */
+ double Wxyz[3]; /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ double Yb; /* Relative Luminance of Background to reference white (Y range 0.0 .. 1.0) */
+ double La; /* Adapting/Surround Luminance cd/m^2 */
+ double Yf; /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ double Fxyz[3]; /* The Flare white coordinates (typically the Ambient color) */
+
+ /* Internal parameters */
+ double C; /* Surround Impact */
+ double Nc; /* Chromatic Induction */
+ double F; /* Adaptation Degree */
+
+ /* Pre-computed values */
+ double Fsc; /* Flare scale */
+ double Fisc; /* Inverse flare scale */
+ double Fsxyz[3]; /* Scaled Flare color coordinates */
+ double rgbW[3]; /* Sharpened cone response white values */
+ double D; /* Degree of chromatic adaption */
+ double rgbcW[3]; /* Chromatically transformed white value */
+ double rgbpW[3]; /* Hunt-Pointer-Estevez cone response space white */
+ double n; /* Background induction factor */
+ double nn; /* Precomuted function of n */
+ double Fl; /* Lightness contrast factor ?? */
+ double Nbb; /* Background brightness induction factors */
+ double Ncb; /* Chromatic brightness induction factors */
+ double z; /* Base exponential nonlinearity */
+ double rgbaW[3]; /* Post-adapted cone response of white */
+ double Aw; /* Achromatic response of white */
+
+ /* Flags */
+ int hk; /* If NZ, use Helmholtz-Kohlraush effect */
+ int trace; /* Trace values through computation */
+}; typedef struct _cam97s3 cam97s3;
+
+
+/* Create a cam97s3 conversion class, with default viewing conditions */
+cam97s3 *new_cam97s3(void);
+
diff --git a/xicc/cam97test.c b/xicc/cam97test.c
new file mode 100644
index 0000000..ff71bc8
--- /dev/null
+++ b/xicc/cam97test.c
@@ -0,0 +1,456 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 1/5/01
+ * Version: 1.20
+ *
+ * Copyright 2000-2004 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.
+ *
+ */
+
+/*
+ * This is some test code to test the CIECAM97s3 functionality.
+ */
+
+
+#include <stdio.h>
+#include <math.h>
+#include "xcam.h"
+#include "cam97s3.h"
+
+#define DIAG /* Print internal value diagnostics for each conversion */
+#define SPOTTEST /* Test known spot colors */
+#undef INVTEST /* Lab cube to XYZ to Jab to XYZ */
+#undef INVTEST2 /* Jab cube to XYZ to Jab */
+#define TRES 33
+#define USE_HK 0 /* Use Helmholtz-Kohlraush */
+#define NOCAMCLIP 1 /* Don't clip before XYZ2Jab */
+
+#ifndef _isnan
+#define _isnan(x) ((x) != (x))
+#define _finite(x) ((x) == (x))
+#endif
+
+static void
+Lab2XYZ(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ out[0] = x * 0.9642;
+ out[1] = y * 1.0000;
+ out[2] = z * 0.8249;
+}
+
+/* CIE XYZ to perceptual Lab */
+static void
+XYZ2Lab(double *out, double *in) {
+ double X = in[0], Y = in[1], Z = in[2];
+ double x,y,z,fx,fy,fz;
+
+ x = X/0.9642;
+ y = Y/1.0000;
+ z = Z/0.8249;
+
+ if (x > 0.008856451586)
+ fx = pow(x,1.0/3.0);
+ else
+ fx = 7.787036979 * x + 16.0/116.0;
+
+ if (y > 0.008856451586)
+ fy = pow(y,1.0/3.0);
+ else
+ fy = 7.787036979 * y + 16.0/116.0;
+
+ if (z > 0.008856451586)
+ fz = pow(z,1.0/3.0);
+ else
+ fz = 7.787036979 * z + 16.0/116.0;
+
+ out[0] = 116.0 * fy - 16.0;
+ out[1] = 500.0 * (fx - fy);
+ out[2] = 200.0 * (fy - fz);
+}
+
+
+/* Return maximum difference */
+double maxdiff(double in1[3], double in2[3]) {
+ int i;
+ double tt, rv = 0.0;
+
+ /* Deal with the possibility that we have nan's */
+ for (i = 0; i < 3; i++) {
+ tt = fabs(in1[i] - in2[i]);
+ if (_isnan(tt))
+ return tt;
+ if (tt > rv)
+ rv = tt;
+ }
+ return rv;
+}
+
+/* Return absolute difference */
+double absdiff(double in1[3], double in2[3]) {
+ double tt, rv = 0.0;
+ tt = in1[0] - in2[0];
+ rv += tt * tt;
+ tt = in1[1] - in2[1];
+ rv += tt * tt;
+ tt = in1[2] - in2[2];
+ rv += tt * tt;
+ return sqrt(rv);
+}
+
+/* Return maximum Lab difference of XYZ */
+double maxxyzdiff(double i1[3], double i2[3]) {
+ int i;
+ double tt, rv = 0.0;
+ double in1[3], in2[3];
+
+ XYZ2Lab(in1, i1);
+ XYZ2Lab(in2, i2);
+
+ /* Deal with the possibility that we have nan's */
+ for (i = 0; i < 3; i++) {
+ tt = fabs(in1[i] - in2[i]);
+ if (_isnan(tt))
+ return tt;
+ if (tt > rv)
+ rv = tt;
+ }
+ return rv;
+}
+
+int
+main(void) {
+ int ok = 1;
+ double white[6][3] = {
+ { 0.9505, 1.000, 1.0888 },
+ { 0.9505, 1.000, 1.0888 },
+ { 1.0985, 1.000, 0.3558 },
+ { 1.0985, 1.000, 0.3558 },
+ { 0.9505, 1.000, 1.0888 },
+ { 0.9642, 1.000, 0.8249 } /* D50 for inversion tests */
+ };
+ double La[6] = { 318.31, 31.83, 318.31, 31.83, 318.31, 150.0 };
+ double sample[5][3] = {
+ { 0.1901, 0.2000, 0.2178 },
+ { 0.5706, 0.4306, 0.3196 },
+ { 0.0353, 0.0656, 0.0214 },
+ { 0.1901, 0.2000, 0.2178 },
+ { 0.9505, 1.000, 1.0888 } /* Check white */
+ };
+
+#ifdef CIECAM97S3_HK
+#ifdef CIECAM97S3_SPLINE_E
+ double correct[5][4] = { /* Hue range is last two */
+ { 41.14, 0.06, 225.3, 251.9 },
+ { 69.04, 71.04, 19.4, 19.4 },
+ { 35.09, 87.15, 175.3, 175.3 },
+ { 55.64, 82.43, 252.5, 252.5 },
+ { 100.00000, 0.0, 0.0, 360.0 }
+ };
+#else
+ double correct[5][4] = { /* Hue range is last two */
+ { 41.14, 0.06, 225.3, 251.9 },
+ { 69.056048, 71.20763, 19.4, 19.4 },
+ { 35.365009, 88.65238, 175.3, 175.3 },
+ { 55.266184, 80.55128, 252.5, 252.5 },
+ { 100.00000, 0.0, 0.0, 360.0 }
+ };
+#endif
+#else
+ double correct[5][4] = { /* Hue range is last two */
+ { 41.13, 0.05, 225.3, 251.9 },
+ { 64.14, 71.22, 19.4, 19.4 },
+ { 19.18, 88.64, 175.3, 175.3 },
+ { 39.11, 80.55, 252.5, 252.5 },
+ { 100.0, 0.00, 0.0, 360.0 } /* Check white */
+ };
+#endif
+
+ double Jab[3];
+ double res[3];
+ cam97s3 *cam;
+ int c;
+
+ cam = new_cam97s3();
+
+#ifdef SPOTTEST
+ for (c = 0; c < 5; c++) {
+
+#ifdef DIAG
+ printf("Case %d:\n",c);
+#endif /* DIAG */
+ cam->set_view(
+ cam,
+ vc_average, /* Enumerated Viewing Condition */
+ white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ La[c], /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK
+ );
+#ifdef DIAG
+ printf("\n");
+#endif /* DIAG */
+
+ {
+ double JCh[3], target[3];
+ cam->XYZ_to_cam(cam, Jab, sample[c]);
+
+ /* Convert to JCh for checking */
+ JCh[0] = Jab[0];
+
+ /* Compute hue angle */
+ JCh[2] = (180.0/3.14159265359) * atan2(Jab[2], Jab[1]);
+ JCh[2] = (JCh[2] < 0.0) ? JCh[2] + 360.0 : JCh[2];
+
+ /* Compute chroma value */
+ JCh[1] = sqrt(Jab[1] * Jab[1] + Jab[2] * Jab[2]);
+
+ target[0] = correct[c][0];
+ target[1] = correct[c][1];
+ if (JCh[2] >= correct[c][2] && JCh[2] <= correct[c][3]) {
+ target[2] = JCh[2];
+ } else {
+ if (fabs(JCh[2] - correct[c][2]) < fabs(JCh[2] - correct[c][3]))
+ target[2] = correct[c][2];
+ else
+ target[2] = correct[c][3];
+ }
+
+ cam->cam_to_XYZ(cam, res, Jab);
+
+ if (maxdiff(JCh, target) > 0.05) {
+ printf("Spottest: Excesive error in conversion to CAM %f\n",maxdiff(JCh, target));
+ ok = 0;
+ }
+ if (maxdiff(sample[c], res) > 1e-5) {
+ printf("Spottest: Excessive error in inversion %f\n",maxdiff(sample[c], res));
+ ok = 0;
+ }
+#ifdef DIAG
+ printf("Jab is %f %f %f, Jch is %f %f %f\n",
+ Jab[0], Jab[1], Jab[2],
+ JCh[0], JCh[1], JCh[2]);
+
+ printf("Error to expected value = %f\n",maxdiff(JCh, target));
+
+ printf("XYZ is %f %f %f\n",res[0], res[1], res[2]);
+ printf("Inversion error = %f\n",maxdiff(sample[c], res));
+#endif /* DIAG */
+ }
+ }
+#endif /* SPOTTEST */
+
+#ifdef INVTEST
+ for (c = 5; c < 6; c++) {
+ /* Get the range of Jab values */
+ double min[3] = { 1e6, 1e6, 1e6 };
+ double max[3] = { -1e6, -1e6, -1e6 };
+
+ cam->set_view(
+ cam,
+ vc_average, /* Enumerated Viewing Condition */
+ white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
+ 34.0, /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.01, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK
+ );
+
+ {
+ int co0, co1, co2; /* (using co[3] triggers compiler bug) */
+ double merr = 0.0;
+ double xyz[3], Lab[3], Jab[3], checkxyz[3];
+
+
+#ifdef NEVER
+ /* Test case */
+ Lab[0] = 0.0;
+ Lab[1] = -180.0;
+ Lab[2] = -180.0;
+ Lab2XYZ(xyz, Lab);
+ cam->XYZ_to_cam(cam, Jab, xyz);
+ cam->cam_to_XYZ(cam, checkxyz, Jab);
+
+#else /* !NEVER */
+
+ /* itterate through Lab space */
+ for (co0 = 0; co0 < TRES; co0++) {
+ Lab[0] = co0/(TRES-1.0);
+ Lab[0] = Lab[0] * 100.0;
+ for (co1 = 0; co1 < TRES; co1++) {
+ Lab[1] = co1/(TRES-1.0);
+ Lab[1] = (Lab[1] - 0.5) * 256.0;
+ for (co2 = 0; co2 < TRES; co2++) {
+ double mxd;
+ int i;
+ Lab[2] = co2/(TRES-1.0);
+ Lab[2] = (Lab[2] - 0.5) * 256.0;
+
+ Lab2XYZ(xyz, Lab);
+ cam->XYZ_to_cam(cam, Jab, xyz);
+ for (i = 0; i < 3; i++) {
+ if (Jab[i] < min[i])
+ min[i] = Jab[i];
+ if (Jab[i] > max[i])
+ max[i] = Jab[i];
+ }
+ cam->cam_to_XYZ(cam, checkxyz, Jab);
+
+ /* Check the result */
+ mxd = maxxyzdiff(checkxyz, xyz);
+ if (_finite(merr) && (_isnan(mxd) || mxd > merr))
+ merr = mxd;
+#ifdef DIAG
+ if (_isnan(mxd) || mxd > 0.1) {
+ printf("\n");
+ printf("Lab = %f %f %f\n",Lab[0], Lab[1], Lab[2]);
+ printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
+ xyz[0],xyz[1],xyz[2],Jab[0],Jab[1],Jab[2],
+ checkxyz[0],checkxyz[1],checkxyz[2],
+ maxxyzdiff(checkxyz, xyz));
+ }
+#endif /* DIAG */
+ }
+ }
+ }
+ if (_isnan(merr) || merr > 0.1) {
+ printf("Excessive error in inversion check %f\n",merr);
+ ok = 0;
+ }
+#ifdef DIAG
+ printf("Inversion check complete, peak error = %f\n",merr);
+#endif /* !NEVER */
+
+#endif /* DIAG */
+ printf("\n");
+ printf("Range of Jab values was:\n");
+ printf("J: %f -> %f\n", min[0], max[0]);
+ printf("a: %f -> %f\n", min[1], max[1]);
+ printf("b: %f -> %f\n", min[2], max[2]);
+ }
+ }
+#endif /* INVTEST */
+
+#ifdef INVTEST2
+ for (c = 5; c < 6; c++) {
+ cam->set_view(
+ cam,
+ vc_average, /* Enumerated Viewing Condition */
+ white[c], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) = D50 */
+ 34.0, /* Adapting/Surround Luminance cd/m^2 */
+ 0.20, /* Relative Luminance of Background to reference white */
+ 0.0, /* Luminance of white in image - not used */
+ 0.01, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ white[c], /* The Flare color coordinates (typically the Ambient color) */
+ USE_HK
+ );
+
+ {
+ int co0, co1, co2; /* (using co[3] triggers compiler bug) */
+ double merr = 0.0;
+ double xyz[3], Jab[3], checkJab[3];
+
+#ifdef NEVER
+ /* Test case */
+#ifdef NEVER
+ Jab[0] = 0.0;
+ Jab[1] = -180.0;
+ Jab[2] = -180.0;
+ cam->cam_to_XYZ(cam, xyz, Jab);
+ cam->XYZ_to_cam(cam, checkJab, xyz);
+#else
+ xyz[0] = 555.365115;
+ xyz[1] = -518.091908;
+ xyz[2] = -1591.731701;
+ cam->XYZ_to_cam(cam, Jab, xyz);
+ cam->cam_to_XYZ(cam, xyz, Jab);
+#endif
+
+#else /* !NEVER */
+
+ /* itterate through Jab space */
+ for (co0 = 0; co0 < TRES; co0++) {
+ Jab[0] = co0/(TRES-1.0);
+ Jab[0] = 0.0 + Jab[0] * 100.0;
+ for (co1 = 0; co1 < TRES; co1++) {
+ Jab[1] = co1/(TRES-1.0);
+ Jab[1] = (Jab[1] - 0.5) * 256.0;
+ for (co2 = 0; co2 < TRES; co2++) {
+ double mxd;
+ Jab[2] = co2/(TRES-1.0);
+ Jab[2] = (Jab[2] - 0.5) * 256.0;
+
+ cam->cam_to_XYZ(cam, xyz, Jab);
+ cam->XYZ_to_cam(cam, checkJab, xyz);
+
+ /* Check the result */
+ mxd = maxdiff(checkJab, Jab);
+ if (_finite(merr) && (_isnan(mxd) || mxd > merr))
+ merr = mxd;
+#ifdef DIAG
+ if (_isnan(mxd) || mxd > 0.1) {
+ printf("\n");
+ printf("Jab = %f %f %f\n",Jab[0], Jab[1], Jab[2]);
+ printf("%f %f %f -> %f %f %f -> %f %f %f [%f]\n",
+ Jab[0],Jab[1],Jab[2], xyz[0],xyz[1],xyz[2],
+ checkJab[0],checkJab[1],checkJab[2],
+ maxdiff(checkJab, Jab));
+ }
+#endif /* DIAG */
+ }
+ }
+ }
+ if (_isnan(merr) || merr > 1.0) {
+ printf("Excessive error in inversion check 2 %f\n",merr);
+ ok = 0;
+ }
+#ifdef DIAG
+ printf("Inversion check 2 complete, peak error = %f\n",merr);
+#endif /* DIAG */
+#endif /* !NEVER */
+ }
+ }
+#endif /* INVTEST2 */
+
+ printf("\n");
+ if (ok == 0) {
+ printf("Cam testing FAILED\n");
+ } else {
+ printf("Cam testing OK\n");
+ }
+
+ return 0;
+}
+
diff --git a/xicc/ccmx.c b/xicc/ccmx.c
new file mode 100644
index 0000000..b1244af
--- /dev/null
+++ b/xicc/ccmx.c
@@ -0,0 +1,766 @@
+
+/*
+ * Argyll Color Correction System
+ * Colorimeter Correction Matrix
+ *
+ * Author: Graeme W. Gill
+ * Date: 19/8/2010
+ *
+ * Copyright 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * NOTE though that if SALONEINSTLIB is not defined, that this file depends
+ * on other libraries that are licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3.
+ */
+
+/*
+ * TTBD:
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#ifndef SALONEINSTLIB
+#include "numlib.h"
+#include "icc.h"
+#else
+#include "numsup.h"
+#include "conv.h"
+#endif
+#include "cgats.h"
+#include "ccmx.h"
+
+#ifdef NT /* You'd think there might be some standards.... */
+# ifndef __BORLANDC__
+# define stricmp _stricmp
+# endif
+#else
+# define stricmp strcasecmp
+#endif
+
+/* Forward declarations */
+
+/* Utilities */
+
+/* Method implimentations */
+
+/* Write out the ccmx to a CGATS format .ccmx file */
+/* Return nz on error */
+static int create_ccmx_cgats(
+ccmx *p, /* This */
+cgats **pocg /* return CGATS structure */
+) {
+ int i, j, n;
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats *ocg; /* CGATS structure */
+ char buf[100];
+
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CCMX"); /* our special type is Colorimeter Correction Matrix */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ if (p->desc != NULL)
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", p->desc,NULL);
+ ocg->add_kword(ocg, 0, "INSTRUMENT",p->inst, NULL);
+ if (p->disp != NULL)
+ ocg->add_kword(ocg, 0, "DISPLAY",p->disp, NULL);
+ if (p->tech != NULL)
+ ocg->add_kword(ocg, 0, "TECHNOLOGY",p->tech, NULL);
+ if (p->disp == NULL && p->tech == NULL) {
+#ifdef DEBUG
+ fprintf(stdout, "write_ccmx: ccmx doesn't contain display or techology strings");
+#endif
+ sprintf(p->err, "write_ccmx: ccmx doesn't contain display or techology strings");
+ ocg->del(ocg);
+ return 1;
+ }
+ if (p->cbid != 0) {
+ sprintf(buf, "%d", p->cbid);
+ ocg->add_kword(ocg, 0, "DISPLAY_TYPE_BASE_ID", buf, NULL);
+ }
+ if (p->refrmode >= 0)
+ ocg->add_kword(ocg, 0, "DISPLAY_TYPE_REFRESH", p->refrmode ? "YES" : "NO", NULL);
+ if (p->sel != NULL)
+ ocg->add_kword(ocg, 0, "UI_SELECTORS", p->sel, NULL);
+ if (p->ref != NULL)
+ ocg->add_kword(ocg, 0, "REFERENCE",p->ref, NULL);
+
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll ccmx", NULL);
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ ocg->add_kword(ocg, 0, "COLOR_REP", "XYZ", NULL);
+
+ /* Add fields for the matrix */
+ ocg->add_field(ocg, 0, "XYZ_X", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Y", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Z", r_t);
+
+ /* Write out the matrix values */
+ for (i = 0; i < 3; i++) {
+ ocg->add_set(ocg, 0, p->matrix[i][0], p->matrix[i][1], p->matrix[i][2]);
+ }
+
+ if (pocg != NULL)
+ *pocg = ocg;
+
+ return 0;
+}
+
+/* Write out the ccmx to a CGATS format .ccmx file */
+/* Return nz on error */
+static int write_ccmx(
+ccmx *p, /* This */
+char *outname /* Filename to write to */
+) {
+ int rv;
+ cgats *ocg; /* CGATS structure */
+
+ /* Create CGATS elements */
+ if ((rv = create_ccmx_cgats(p, &ocg)) != 0) {
+ return rv;
+ }
+
+ /* Write it to file */
+ if (ocg->write_name(ocg, outname)) {
+ strcpy(p->err, ocg->err);
+ ocg->del(ocg); /* Clean up */
+ return 1;
+ }
+ ocg->del(ocg); /* Clean up */
+
+ return 0;
+}
+
+/* write to a CGATS .ccmx file to a memory buffer. */
+/* return nz on error, with message in err[] */
+static int buf_write_ccmx(
+ccmx *p,
+unsigned char **buf, /* Return allocated buffer */
+int *len /* Return length */
+) {
+ int rv;
+ cgats *ocg; /* CGATS structure */
+ cgatsFile *fp;
+
+ /* Create CGATS elements */
+ if ((rv = create_ccmx_cgats(p, &ocg)) != 0) {
+ return rv;
+ }
+
+ if ((fp = new_cgatsFileMem(NULL, 0)) == NULL) {
+ strcpy(p->err, "new_cgatsFileMem failed");
+ return 2;
+ }
+
+ /* Write it to file */
+ if (ocg->write(ocg, fp)) {
+ strcpy(p->err, ocg->err);
+ ocg->del(ocg); /* Clean up */
+ fp->del(fp);
+ return 1;
+ }
+
+ /* Get the buffer the ccmx has been written to */
+ if (fp->get_buf(fp, buf, (size_t *)len)) {
+ strcpy(p->err, "cgatsFileMem get_buf failed");
+ return 2;
+ }
+
+ ocg->del(ocg); /* Clean up */
+ fp->del(fp);
+
+ return 0;
+}
+
+/* Read in the ccmx CGATS .ccmx file */
+/* Return nz on error */
+static int read_ccmx_cgats(
+ccmx *p, /* This */
+cgats *icg /* input cgats structure */
+) {
+ int i, j, n, ix;
+ int ti; /* Temporary CGATs index */
+ int spi[3]; /* CGATS indexes for each band */
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0) {
+ sprintf(p->err, "read_ccmx: Input file isn't a CCMX format file");
+ icg->del(icg);
+ return 1;
+ }
+ if (icg->ntables != 1) {
+ sprintf(p->err, "Input file doesn't contain exactly one table");
+ icg->del(icg);
+ return 1;
+ }
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0) {
+ sprintf(p->err, "read_ccmx: Input file doesn't contain keyword COLOR_REP");
+ icg->del(icg);
+ return 1;
+ }
+
+ if (strcmp(icg->t[0].kdata[ti],"XYZ") != 0) {
+ sprintf(p->err, "read_ccmx: Input file doesn't have COLOR_REP of XYZ");
+ icg->del(icg);
+ return 1;
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "DESCRIPTOR")) >= 0) {
+ if ((p->desc = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccmx: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "INSTRUMENT")) < 0) {
+ sprintf(p->err, "read_ccmx: Input file doesn't contain keyword INSTRUMENT");
+ icg->del(icg);
+ return 1;
+ }
+ if ((p->inst = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccmx: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "DISPLAY")) >= 0) {
+ if ((p->disp = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccmx: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+ if ((ti = icg->find_kword(icg, 0, "TECHNOLOGY")) >= 0) {
+ if ((p->tech = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccmx: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+ if (p->disp == NULL && p->tech == NULL) {
+ sprintf(p->err, "read_ccmx: Input file doesn't contain keyword DISPLAY or TECHNOLOGY");
+ icg->del(icg);
+ return 1;
+ }
+ if ((ti = icg->find_kword(icg, 0, "DISPLAY_TYPE_REFRESH")) >= 0) {
+ if (stricmp(icg->t[0].kdata[ti], "YES") == 0)
+ p->refrmode = 1;
+ else if (stricmp(icg->t[0].kdata[ti], "NO") == 0)
+ p->refrmode = 0;
+ } else {
+ p->refrmode = -1;
+ }
+ if ((ti = icg->find_kword(icg, 0, "DISPLAY_TYPE_BASE_ID")) >= 0) {
+ p->cbid = atoi(icg->t[0].kdata[ti]);
+ } else {
+ p->cbid = 0;
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "UI_SELECTORS")) >= 0) {
+ if ((p->sel = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccmx: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "REFERENCE")) >= 0) {
+ if ((p->ref = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccmx: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+
+ /* Locate the fields */
+ for (i = 0; i < 3; i++) { /* XYZ fields */
+ if ((spi[i] = icg->find_field(icg, 0, xyzfname[i])) < 0) {
+ sprintf(p->err, "read_ccmx: Input file doesn't contain field %s", xyzfname[i]);
+ icg->del(icg);
+ return 1;
+ }
+ if (icg->t[0].ftype[spi[i]] != r_t) {
+ sprintf(p->err, "read_ccmx: Input file field %s is wrong type", xyzfname[i]);
+ icg->del(icg);
+ return 1;
+ }
+ }
+
+ if (icg->t[0].nsets != 3) {
+ sprintf(p->err, "read_ccmx: Input file doesn't have exactly 3 sets");
+ icg->del(icg);
+ return 1;
+ }
+
+ /* Read the matrix values */
+ for (ix = 0; ix < icg->t[0].nsets; ix++) {
+ p->matrix[ix][0] = *((double *)icg->t[0].fdata[ix][spi[0]]);
+ p->matrix[ix][1] = *((double *)icg->t[0].fdata[ix][spi[1]]);
+ p->matrix[ix][2] = *((double *)icg->t[0].fdata[ix][spi[2]]);
+ }
+
+ return 0;
+}
+
+/* Read in the ccmx CGATS .ccmx file */
+/* Return nz on error */
+static int read_ccmx(
+ccmx *p, /* This */
+char *inname /* Filename to read from */
+) {
+ int rv;
+ cgats *icg; /* input cgats structure */
+
+ /* Open and look at the .ccmx */
+ if ((icg = new_cgats()) == NULL) { /* Create a CGATS structure */
+ sprintf(p->err, "read_ccmx: new_cgats() failed");
+ return 2;
+ }
+ icg->add_other(icg, "CCMX"); /* our special type is Model Printer Profile */
+
+ if (icg->read_name(icg, inname)) {
+ strcpy(p->err, icg->err);
+ icg->del(icg);
+ return 1;
+ }
+
+ if ((rv = read_ccmx_cgats(p, icg)) != 0) {
+ icg->del(icg);
+ return rv;
+ }
+
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+/* Read in the ccmx CGATS .ccmx file from a memory buffer */
+/* Return nz on error */
+static int buf_read_ccmx(
+ccmx *p, /* This */
+unsigned char *buf,
+int len
+) {
+ int rv;
+ cgatsFile *fp;
+ cgats *icg; /* input cgats structure */
+
+ if ((fp = new_cgatsFileMem(buf, len)) == NULL) {
+ strcpy(p->err, "new_cgatsFileMem failed");
+ return 2;
+ }
+
+ /* Open and look at the .ccmx file */
+ if ((icg = new_cgats()) == NULL) { /* Create a CGATS structure */
+ sprintf(p->err, "read_ccmx: new_cgats() failed");
+ fp->del(fp);
+ return 2;
+ }
+ icg->add_other(icg, "CCMX"); /* our special type is Model Printer Profile */
+
+ if (icg->read(icg, fp)) {
+ strcpy(p->err, icg->err);
+ icg->del(icg);
+ fp->del(fp);
+ return 1;
+ }
+ fp->del(fp);
+
+ if ((rv = read_ccmx_cgats(p, icg)) != 0) {
+ icg->del(icg); /* Clean up */
+ return rv;
+ }
+
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+/* Lookup an XYZ or Lab color */
+static void xform(
+ccmx *p, /* This */
+double *out, /* Output XYZ */
+double *in /* Input XYZ */
+) {
+ icmMulBy3x3(out, p->matrix, in);
+}
+
+
+/* Set the contents of the ccmx. return nz on error. */
+static int set_ccmx(ccmx *p,
+char *desc, /* General description (optional) */
+char *inst, /* Instrument description to copy from */
+char *disp, /* Display make and model (optional if tech) */
+char *tech, /* Display technology description (optional if disp) */
+int refrmode, /* Display refresh mode, -1 = unknown, 0 = n, 1 = yes */
+int cbid, /* Display type calibration base ID, 0 = unknown */
+char *sel, /* UI selector characters - NULL for none */
+char *refd, /* Reference spectrometer description (optional) */
+double mtx[3][3] /* Transform matrix to copy from */
+) {
+ if ((p->desc = desc) != NULL && (p->desc = strdup(desc)) == NULL) {
+ sprintf(p->err, "set_ccmx: malloc failed");
+ return 2;
+ }
+ if ((p->inst = inst) != NULL && (p->inst = strdup(inst)) == NULL) {
+ sprintf(p->err, "set_ccmx: malloc failed");
+ return 2;
+ }
+ if ((p->disp = disp) != NULL && (p->disp = strdup(disp)) == NULL) {
+ sprintf(p->err, "set_ccmx: malloc failed");
+ return 2;
+ }
+ if ((p->tech = tech) != NULL && (p->tech = strdup(tech)) == NULL) {
+ sprintf(p->err, "set_ccmx: malloc failed");
+ return 2;
+ }
+
+ p->refrmode = refrmode;
+ p->cbid = cbid;
+
+ if (sel != NULL) {
+ if ((p->sel = strdup(sel)) == NULL) {
+ sprintf(p->err, "set_ccmx: malloc sel failed");
+ return 2;
+ }
+ }
+ if ((p->ref = refd) != NULL && (p->ref = strdup(refd)) == NULL) {
+ sprintf(p->err, "set_ccmx: malloc failed");
+ return 2;
+ }
+
+ icmCpy3x3(p->matrix, mtx);
+
+ return 0;
+}
+
+#ifndef SALONEINSTLIB
+
+/* ------------------------------------------- */
+/* Modified version that de-weights Luminance errors by 5: */
+/* Return the CIE94 Delta E color difference measure, squared */
+static double wCIE94sq(double Lab0[3], double Lab1[3]) {
+ double desq, dhsq;
+ double dlsq, dcsq;
+ double c12;
+
+ {
+ double dl, da, db;
+ dl = Lab0[0] - Lab1[0];
+ dlsq = dl * dl; /* dl squared */
+ da = Lab0[1] - Lab1[1];
+ db = Lab0[2] - Lab1[2];
+
+ /* Compute normal Lab delta E squared */
+ desq = dlsq + da * da + db * db;
+ }
+
+ {
+ double c1, c2, dc;
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ c2 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ c12 = sqrt(c1 * c2); /* Symetric chromanance */
+
+ /* delta chromanance squared */
+ dc = c2 - c1;
+ dcsq = dc * dc;
+ }
+
+ /* Compute delta hue squared */
+ if ((dhsq = desq - dlsq - dcsq) < 0.0)
+ dhsq = 0.0;
+ {
+ double sc, sh;
+
+ /* Weighting factors for delta chromanance & delta hue */
+ sc = 1.0 + 0.048 * c12;
+ sh = 1.0 + 0.014 * c12;
+ return 0.2 * 0.2 * dlsq + dcsq/(sc * sc) + dhsq/(sh * sh);
+ }
+}
+
+/* ------------------------------------------- */
+
+/* Context for optimisation callback */
+typedef struct {
+ int npat;
+ double (*refs)[3]; /* Array of XYZ values from spectrometer */
+ double (*cols)[3]; /* Array of XYZ values from colorimeter */
+ int wix; /* White index */
+ icmXYZNumber wh; /* White reference */
+} cntx;
+
+
+/* Optimisation function */
+/* Compute the sum of delta E's squared for the */
+/* tp will be the 9 matrix values */
+/* It's not clear if the white weighting is advantagous or not. */
+double optf(void *fdata, double *tp) {
+ cntx *cx = (cntx *)fdata;
+ int i;
+ double de;
+ double m[3][3];
+
+ m[0][0] = tp[0];
+ m[0][1] = tp[1];
+ m[0][2] = tp[2];
+ m[1][0] = tp[3];
+ m[1][1] = tp[4];
+ m[1][2] = tp[5];
+ m[2][0] = tp[6];
+ m[2][1] = tp[7];
+ m[2][2] = tp[8];
+
+ for (de = 0.0, i = 0; i < cx->npat; i++) {
+ double tlab[3], xyz[3], lab[3];
+ icmXYZ2Lab(&cx->wh, tlab, cx->refs[i]);
+
+ icmMulBy3x3(xyz, m, cx->cols[i]);
+ icmXYZ2Lab(&cx->wh, lab, xyz);
+
+ if (i == cx->wix)
+ de += cx->npat/4.0 * wCIE94sq(tlab, lab); /* Make white weight = 1/4 all others */
+ else
+ de += wCIE94sq(tlab, lab);
+//printf("~1 %d: txyz %f %f %f, tlab %f %f %f\n", i,cx->refs[i][0], cx->refs[i][1], cx->refs[i][2], tlab[0], tlab[1], tlab[2]);
+//printf("~1 %d: xyz %f %f %f\n", i,cx->cols[i][0], cx->cols[i][1], cx->cols[i][2]);
+//printf("~1 %d: mxyz %f %f %f, lab %f %f %f\n", i,xyz[0], xyz[1], xyz[2], lab[0], lab[1], lab[2]);
+//printf("~1 %d: de %f\n", i,wCIE94(tlab, lab));
+ }
+
+ de /= cx->npat;
+#ifdef DEBUG
+// printf("~1 return values = %f\n",de);
+#endif
+
+ return de;
+}
+
+/* Create a ccmx from measurements. return nz on error. */
+static int create_ccmx(ccmx *p,
+char *desc, /* General description (optional) */
+char *inst, /* Instrument description to copy from */
+char *disp, /* Display make and model (optional if tech) */
+char *tech, /* Display technology description (optional if disp) */
+int refrmode, /* Display refresh mode, -1 = unknown, 0 = n, 1 = yes */
+int cbid, /* Display type calibration base index, 0 = unknown */
+char *sel, /* UI selector characters - NULL for none */
+char *refd, /* Reference spectrometer description (optional) */
+int npat, /* Number of samples in following arrays */
+double (*refs)[3], /* Array of XYZ values from spectrometer */
+double (*cols)[3] /* Array of XYZ values from colorimeter */
+) {
+ int i, mxix;
+ double maxy = -1e6;
+ cntx cx;
+ double cp[9], sa[9];
+
+ if ((p->desc = desc) != NULL && (p->desc = strdup(desc)) == NULL) {
+ sprintf(p->err, "create_ccmx: malloc failed");
+ return 2;
+ }
+ if ((p->inst = inst) != NULL && (p->inst = strdup(inst)) == NULL) {
+ sprintf(p->err, "create_ccmx: malloc failed");
+ return 2;
+ }
+ if ((p->disp = disp) != NULL && (p->disp = strdup(disp)) == NULL) {
+ sprintf(p->err, "create_ccmx: malloc failed");
+ return 2;
+ }
+ if ((p->tech = tech) != NULL && (p->tech = strdup(tech)) == NULL) {
+ sprintf(p->err, "create_ccmx: malloc failed");
+ return 2;
+ }
+ p->refrmode = refrmode;
+ p->cbid = cbid;
+
+ if (sel != NULL) {
+ if ((p->sel = strdup(sel)) == NULL) {
+ sprintf(p->err, "create_ccmx: malloc sel failed");
+ return 2;
+ }
+ }
+ if ((p->ref = refd) != NULL && (p->ref = strdup(refd)) == NULL) {
+ sprintf(p->err, "create_ccmx: malloc failed");
+ return 2;
+ }
+
+ /* Find the white patch */
+
+ cx.npat = npat;
+ cx.refs = refs;
+ cx.cols = cols;
+
+ for (i = 0; i < npat; i++) {
+ if (refs[i][1] > maxy) {
+ maxy = refs[i][1];
+ cx.wix = i;
+ }
+ }
+#ifdef DEBUG
+ printf("white = %f %f %f\n",refs[cx.wix][0],refs[cx.wix][1],refs[cx.wix][1]);
+#endif
+ cx.wh.X = refs[cx.wix][0];
+ cx.wh.Y = refs[cx.wix][1];
+ cx.wh.Z = refs[cx.wix][2];
+
+ /* Starting matrix */
+ cp[0] = 1.0; cp[1] = 0.0; cp[2] = 0.0;
+ cp[3] = 0.0; cp[4] = 1.0; cp[5] = 0.0;
+ cp[6] = 0.0; cp[7] = 0.0; cp[8] = 1.0;
+
+ for (i = 0; i < 9; i++)
+ sa[i] = 0.1;
+
+ if (powell(NULL, 9, cp, sa, 1e-6, 2000, optf, &cx, NULL, NULL) < 0.0) {
+ sprintf(p->err, "create_ccmx: powell() failed");
+ return 1;
+ }
+
+ p->matrix[0][0] = cp[0];
+ p->matrix[0][1] = cp[1];
+ p->matrix[0][2] = cp[2];
+ p->matrix[1][0] = cp[3];
+ p->matrix[1][1] = cp[4];
+ p->matrix[1][2] = cp[5];
+ p->matrix[2][0] = cp[6];
+ p->matrix[2][1] = cp[7];
+ p->matrix[2][2] = cp[8];
+
+ /* Compute the average and max errors */
+ p->av_err = p->mx_err = 0.0;
+ for (i = 0; i < npat; i++) {
+ double tlab[3], xyz[3], lab[3], de;
+ icmXYZ2Lab(&cx.wh, tlab, cx.refs[i]);
+ icmMulBy3x3(xyz, p->matrix, cx.cols[i]);
+ icmXYZ2Lab(&cx.wh, lab, xyz);
+ de = icmCIE94(tlab, lab);
+ p->av_err += de;
+ if (de > p->mx_err) {
+ p->mx_err = de;
+ mxix = i;
+ }
+//printf("~1 %d: de %f, tlab %f %f %f, lab %f %f %f\n",i,de,tlab[0], tlab[1], tlab[2], lab[0], lab[1], lab[2]);
+ }
+ p->av_err /= (double)npat;
+
+//printf("~1 max error is index %d\n",mxix);
+
+#ifdef DEBUG
+ printf("Average error %f, max %f\n",p->av_err,p->mx_err);
+ printf("Correction matrix is:\n");
+ printf(" %f %f %f\n", cp[0], cp[1], cp[2]);
+ printf(" %f %f %f\n", cp[3], cp[4], cp[5]);
+ printf(" %f %f %f\n", cp[6], cp[7], cp[8]);
+#endif
+
+ return 0;
+}
+
+#else /* SALONEINSTLIB */
+
+/* Create a ccmx from measurements. return nz on error. */
+static int create_ccmx(ccmx *p,
+char *desc, /* General description (optional) */
+char *inst, /* Instrument description to copy from */
+char *disp, /* Display make and model (optional if tech) */
+char *tech, /* Display technology description (optional if disp) */
+int refrmode, /* Display refresh mode, -1 = unknown, 0 = n, 1 = yes */
+int cbid, /* Display type calibration base ID, 0 = unknown */
+char *sel, /* UI selector characters - NULL for none */
+char *refd, /* Reference spectrometer description (optional) */
+int npat, /* Number of samples in following arrays */
+double (*refs)[3], /* Array of XYZ values from spectrometer */
+double (*cols)[3] /* Array of XYZ values from colorimeter */
+) {
+ sprintf(p->err, "create_ccmx: not implemented in ccmx.c");
+ return 1;
+}
+
+#endif /* SALONEINSTLIB */
+
+/* Delete it */
+static void del_ccmx(ccmx *p) {
+ if (p != NULL) {
+ if (p->desc != NULL)
+ free(p->desc);
+ if (p->inst != NULL)
+ free(p->inst);
+ if (p->disp != NULL)
+ free(p->disp);
+ if (p->tech != NULL)
+ free(p->tech);
+ if (p->sel != NULL)
+ free(p->sel);
+ if (p->ref != NULL)
+ free(p->ref);
+ free(p);
+ }
+}
+
+/* Allocate a new, uninitialised ccmx */
+/* Note thate black and white points aren't allocated */
+ccmx *new_ccmx(void) {
+ ccmx *p;
+
+ if ((p = (ccmx *)calloc(1, sizeof(ccmx))) == NULL)
+ return NULL;
+
+ p->refrmode = -1;
+ p->cbid = 0;
+
+ /* Init method pointers */
+ p->del = del_ccmx;
+ p->set_ccmx = set_ccmx;
+ p->create_ccmx = create_ccmx;
+ p->write_ccmx = write_ccmx;
+ p->buf_write_ccmx = buf_write_ccmx;
+ p->read_ccmx = read_ccmx;
+ p->buf_read_ccmx = buf_read_ccmx;
+ p->xform = xform;
+
+ return p;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/ccmx.h b/xicc/ccmx.h
new file mode 100644
index 0000000..b0ca01a
--- /dev/null
+++ b/xicc/ccmx.h
@@ -0,0 +1,120 @@
+#ifndef CCMX_H
+#define CCMX_H
+
+/*
+ * Argyll Color Correction System
+ * Colorimeter Correction Matrix support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 19/8/2010
+ *
+ * Copyright 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * NOTE though that if SALONEINSTLIB is not defined, that this file depends
+ * on other libraries that are licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3.
+ *
+ */
+
+/*
+ * This object provides storage and application of a 3x3 XYZ
+ * corretion matrix suitable for corrected a particular
+ * display colorimeter for a particular display.
+ */
+
+/* ------------------------------------------------------------------------------ */
+
+struct _ccmx {
+
+ /* Public: */
+ void (*del)(struct _ccmx *p);
+
+ /* Set the contents of the ccmx. return nz on error. */
+ int (*set_ccmx)(struct _ccmx *p, char *desc, char *inst, char *disp, char *tech,
+ int refrmode, int cbid, char *sel, char *refd, double mtx[3][3]);
+
+ /* Create a ccmx from measurements. return nz on error. */
+ int (*create_ccmx)(struct _ccmx *p, char *desc, char *inst, char *disp, char *tech,
+ int refrmode, int cbid, char *sel, char *refd,
+ int nsamples, double refs[][3], double cols[][3]);
+
+ /* write to a CGATS .ccmx file */
+ int (*write_ccmx)(struct _ccmx *p, char *filename);
+
+ /* write a CGATS .ccmx file to a memory buffer. */
+ /* return nz on error, with message in err[] */
+ int (*buf_write_ccmx)(struct _ccmx *p, unsigned char **buf, int *len);
+
+ /* read from a CGATS .ccmx file */
+ int (*read_ccmx)(struct _ccmx *p, char *filename);
+
+ /* read from a CGATS .ccmx file from a memory buffer. */
+ int (*buf_read_ccmx)(struct _ccmx *p, unsigned char *buf, int len);
+
+ /* Correct an XYZ value */
+ void (*xform) (struct _ccmx *p,
+ double *out, /* Output XYZ */
+ double *in); /* Input XYZ */
+
+ /* Private: */
+ /* (All char * are owned by ccmx) */
+ char *desc; /* Desciption (optional) */
+ char *inst; /* Name of colorimeter instrument */
+ char *disp; /* Name of display (optional if tech) */
+ char *tech; /* Technology (CRT, LCD + backlight type etc.) (optional if disp) */
+ int cbid; /* Calibration display type base ID, 0 if not known */
+ int refrmode; /* Refresh mode, -1 if unknown, 0 of no, 1 if yes */
+ char *sel; /* Optional UI selector characters. May be NULL */
+ char *ref; /* Name of spectrometer instrument (optional) */
+ double matrix[3][3]; /* Transform matrix */
+ double av_err; /* Average error of fit */
+ double mx_err; /* Maximum error of fit */
+
+ /* Houskeeping */
+ int errc; /* Error code */
+ char err[200]; /* Error message */
+}; typedef struct _ccmx ccmx;
+
+/* Create a new, uninitialised ccmx */
+ccmx *new_ccmx(void);
+
+#endif /* CCMX_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/ccss.c b/xicc/ccss.c
new file mode 100644
index 0000000..cd9b4e4
--- /dev/null
+++ b/xicc/ccss.c
@@ -0,0 +1,636 @@
+
+/*
+ * Argyll Color Correction System
+ * Colorimeter Correction Matrix
+ *
+ * Author: Graeme W. Gill
+ * Date: 1r9/8/2010
+ *
+ * Copyright 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ * TTBD:
+ */
+
+#undef DEBUG
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#ifndef SALONEINSTLIB
+#include "numlib.h"
+#include "icc.h"
+#else
+#include "numsup.h"
+#include "conv.h"
+#endif
+#include "cgats.h"
+#include "xspect.h"
+#include "ccss.h"
+
+#ifdef NT /* You'd think there might be some standards.... */
+# ifndef __BORLANDC__
+# define stricmp _stricmp
+# endif
+#else
+# define stricmp strcasecmp
+#endif
+
+/* Forward declarations */
+static void free_ccss(ccss *p);
+
+/* Utilities */
+
+/* Method implimentations */
+
+/* Write out the ccss to a CGATS format object */
+/* Return nz on error */
+static int create_ccss_cgats(
+ccss *p, /* This */
+cgats **pocg /* return CGATS structure */
+) {
+ int i, j;
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats *ocg; /* CGATS structure */
+ int nsetel = 0;
+ cgats_set_elem *setel; /* Array of set value elements */
+ char buf[100];
+
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CCSS"); /* Type is Colorimeter Calibration Spectral Set */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ if (p->desc != NULL)
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", p->desc,NULL);
+
+ if (p->orig != NULL)
+ ocg->add_kword(ocg, 0, "ORIGINATOR", p->orig, NULL);
+ else
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll ccss", NULL);
+ if (p->crdate != NULL)
+ ocg->add_kword(ocg, 0, "CREATED",p->crdate, NULL);
+ else
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ if (p->disp)
+ ocg->add_kword(ocg, 0, "DISPLAY",p->disp, NULL);
+ if (p->tech)
+ ocg->add_kword(ocg, 0, "TECHNOLOGY", p->tech,NULL);
+ if (p->disp == NULL && p->tech == NULL) {
+ sprintf(p->err, "write_ccss: ccss doesn't contain display or techology strings");
+ ocg->del(ocg);
+ return 1;
+ }
+ if (p->refrmode >= 0)
+ ocg->add_kword(ocg, 0, "DISPLAY_TYPE_REFRESH", p->refrmode ? "YES" : "NO", NULL);
+ if (p->sel != NULL)
+ ocg->add_kword(ocg, 0, "UI_SELECTORS", p->sel, NULL);
+ if (p->ref != NULL)
+ ocg->add_kword(ocg, 0, "REFERENCE",p->ref, NULL);
+
+ sprintf(buf,"%d", p->samples[0].spec_n);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+ sprintf(buf,"%f", p->samples[0].spec_wl_short);
+ ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
+ sprintf(buf,"%f", p->samples[0].spec_wl_long);
+ ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);
+ sprintf(buf,"%f", p->samples[0].norm);
+ ocg->add_kword(ocg, 0, "SPECTRAL_NORM",buf, NULL);
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+ nsetel += 1; /* For id */
+
+ /* Generate fields for spectral values */
+ for (i = 0; i < p->samples[0].spec_n; i++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(p->samples[0].spec_wl_short + ((double)i/(p->samples[0].spec_n-1.0))
+ * (p->samples[0].spec_wl_long - p->samples[0].spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+ ocg->add_field(ocg, 0, buf, r_t);
+ }
+ nsetel += p->samples[0].spec_n; /* Spectral values */
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL) {
+ strcpy(p->err, "Malloc failed!");
+ ocg->del(ocg); /* Clean up */
+ return 2;
+ }
+
+ /* Write out the patch info to the output CGATS file */
+ for (i = 0; i < p->no_samp; i++) {
+ int k = 0;
+
+ sprintf(buf,"%d",i+1);
+ setel[k++].c = buf;
+
+ for (j = 0; j < p->samples[i].spec_n; j++)
+ setel[k++].d = p->samples[i].spec[j];
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+ free(setel);
+
+ if (pocg != NULL)
+ *pocg = ocg;
+
+ return 0;
+}
+
+/* Write out the ccss to a CGATS format .ccss file */
+/* Return nz on error */
+static int write_ccss(
+ccss *p, /* This */
+char *outname /* Filename to write to */
+) {
+ int rv;
+ cgats *ocg; /* CGATS structure */
+
+ if (p->no_samp < 3) {
+ strcpy(p->err, "Need at least three spectral samples");
+ return 1;
+ }
+
+ /* Create CGATS elements */
+ if ((rv = create_ccss_cgats(p, &ocg)) != 0) {
+ return rv;
+ }
+
+ /* Write it to file */
+ if (ocg->write_name(ocg, outname)) {
+ strcpy(p->err, ocg->err);
+ ocg->del(ocg); /* Clean up */
+ return 1;
+ }
+ ocg->del(ocg); /* Clean up */
+
+ return 0;
+}
+
+/* write to a CGATS .ccss file to a memory buffer. */
+/* return nz on error, with message in err[] */
+static int buf_write_ccss(
+ccss *p,
+unsigned char **buf, /* Return allocated buffer */
+int *len /* Return length */
+) {
+ int rv;
+ cgats *ocg; /* CGATS structure */
+ cgatsFile *fp;
+
+ if (p->no_samp < 3) {
+ strcpy(p->err, "Need at least three spectral samples");
+ return 1;
+ }
+
+ /* Create CGATS elements */
+ if ((rv = create_ccss_cgats(p, &ocg)) != 0) {
+ return rv;
+ }
+
+ if ((fp = new_cgatsFileMem(NULL, 0)) == NULL) {
+ strcpy(p->err, "new_cgatsFileMem failed");
+ return 2;
+ }
+
+ /* Write it to file */
+ if (ocg->write(ocg, fp)) {
+ strcpy(p->err, ocg->err);
+ ocg->del(ocg); /* Clean up */
+ fp->del(fp);
+ return 1;
+ }
+
+ /* Get the buffer the ccss has been written to */
+ if (fp->get_buf(fp, buf, (size_t *)len)) {
+ strcpy(p->err, "cgatsFileMem get_buf failed");
+ return 2;
+ }
+
+ ocg->del(ocg); /* Clean up */
+ fp->del(fp);
+
+ return 0;
+}
+
+/* Read in the ccss CGATS .ccss file from cgats */
+/* Return nz on error */
+static int read_ccss_cgats(
+ccss *p, /* This */
+cgats *icg /* input cgats structure */
+) {
+ int i, j;
+ int ti, ii; /* Temporary CGATs index */
+ int spi[XSPECT_MAX_BANDS]; /* CGATS indexes for each wavelength */
+ xspect sp;
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0) {
+ sprintf(p->err, "read_ccss: Input file isn't a CCSS format file");
+ icg->del(icg);
+ return 1;
+ }
+ if (icg->ntables != 1) {
+ sprintf(p->err, "Input file doesn't contain exactly one table");
+ icg->del(icg);
+ return 1;
+ }
+
+ free_ccss(p);
+
+ if ((ti = icg->find_kword(icg, 0, "DESCRIPTOR")) >= 0) {
+ if ((p->desc = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccss: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+ if ((ti = icg->find_kword(icg, 0, "ORIGINATOR")) >= 0) {
+ if ((p->orig = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccss: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+ if ((ti = icg->find_kword(icg, 0, "CREATED")) >= 0) {
+ if ((p->crdate = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccss: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "DISPLAY")) >= 0) {
+ if ((p->disp = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccss: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+ if ((ti = icg->find_kword(icg, 0, "TECHNOLOGY")) >= 0) {
+ if ((p->tech = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccss: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+ if (p->disp == NULL && p->tech == NULL) {
+ sprintf(p->err, "read_ccss: Input file doesn't contain keyword DISPLAY or TECHNOLOGY");
+ icg->del(icg);
+ return 1;
+ }
+ if ((ti = icg->find_kword(icg, 0, "DISPLAY_TYPE_REFRESH")) >= 0) {
+ if (stricmp(icg->t[0].kdata[ti], "YES") == 0)
+ p->refrmode = 1;
+ else if (stricmp(icg->t[0].kdata[ti], "NO") == 0)
+ p->refrmode = 0;
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "UI_SELECTORS")) >= 0) {
+ if ((p->sel = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccss: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "REFERENCE")) >= 0) {
+ if ((p->ref = strdup(icg->t[0].kdata[ti])) == NULL) {
+ sprintf(p->err, "read_ccss: malloc failed");
+ icg->del(icg);
+ return 2;
+ }
+ }
+
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0) {
+ sprintf(p->err,"Input file doesn't contain keyword SPECTRAL_BANDS");
+ icg->del(icg);
+ return 1;
+ }
+ sp.spec_n = atoi(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0) {
+ sprintf(p->err,"Input file doesn't contain keyword SPECTRAL_START_NM");
+ icg->del(icg);
+ return 1;
+ }
+ sp.spec_wl_short = atof(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0) {
+ sprintf(p->err,"Input file doesn't contain keyword SPECTRAL_END_NM");
+ icg->del(icg);
+ return 1;
+ }
+ sp.spec_wl_long = atof(icg->t[0].kdata[ii]);
+
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_NORM")) < 0) {
+ sp.norm = 1.0; /* Older versions don't have SPECTRAL_NORM */
+ } else {
+ sp.norm = atof(icg->t[0].kdata[ii]);
+ }
+
+ /* Find the fields for spectral values */
+ for (j = 0; j < sp.spec_n; j++) {
+ char buf[100];
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(sp.spec_wl_short + ((double)j/(sp.spec_n-1.0))
+ * (sp.spec_wl_long - sp.spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[j] = icg->find_field(icg, 0, buf)) < 0) {
+ sprintf(p->err,"Input file doesn't contain field %s",buf);
+ icg->del(icg);
+ return 1;
+ }
+ }
+
+ if ((p->no_samp = icg->t[0].nsets) < 3) {
+ sprintf(p->err, "Input file doesn't contain at least three spectral samples");
+ p->no_samp = 0;
+ icg->del(icg); /* Clean up */
+ return 1;
+ }
+
+ /* Allocate spectral array */
+ if ((p->samples = (xspect *)malloc(sizeof(xspect) * p->no_samp)) == NULL) {
+ strcpy(p->err, "Malloc failed!");
+ p->no_samp = 0;
+ icg->del(icg); /* Clean up */
+ return 2;
+ }
+
+ /* Fill sample array with the data */
+ for (i = 0; i < p->no_samp; i++) {
+
+ XSPECT_COPY_INFO(&p->samples[i], &sp);
+
+ /* Read the spectral values for this patch */
+ for (j = 0; j < sp.spec_n; j++) {
+ p->samples[i].spec[j] = *((double *)icg->t[0].fdata[i][spi[j]]);
+ }
+ }
+
+ return 0;
+}
+
+/* Read in the ccss CGATS .ccss file */
+/* Return nz on error */
+static int read_ccss(
+ccss *p, /* This */
+char *inname /* Filename to read from */
+) {
+ int rv;
+ cgats *icg; /* input cgats structure */
+
+ /* Open and look at the .ccss file */
+ if ((icg = new_cgats()) == NULL) { /* Create a CGATS structure */
+ sprintf(p->err, "read_ccss: new_cgats() failed");
+ return 2;
+ }
+ icg->add_other(icg, "CCSS"); /* our special type is Model Printer Profile */
+
+ if (icg->read_name(icg, inname)) {
+ strcpy(p->err, icg->err);
+ icg->del(icg);
+ return 1;
+ }
+
+ if ((rv = read_ccss_cgats(p, icg)) != 0) {
+ icg->del(icg); /* Clean up */
+ return rv;
+ }
+
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+/* Read in the ccss CGATS .ccss file from a memory buffer */
+/* Return nz on error */
+static int buf_read_ccss(
+ccss *p, /* This */
+unsigned char *buf,
+int len
+) {
+ int rv;
+ cgatsFile *fp;
+ cgats *icg; /* input cgats structure */
+
+ if ((fp = new_cgatsFileMem(buf, len)) == NULL) {
+ strcpy(p->err, "new_cgatsFileMem failed");
+ return 2;
+ }
+
+ /* Open and look at the .ccss file */
+ if ((icg = new_cgats()) == NULL) { /* Create a CGATS structure */
+ sprintf(p->err, "read_ccss: new_cgats() failed");
+ fp->del(fp);
+ return 2;
+ }
+ icg->add_other(icg, "CCSS"); /* our special type is Model Printer Profile */
+
+ if (icg->read(icg, fp)) {
+ strcpy(p->err, icg->err);
+ icg->del(icg);
+ fp->del(fp);
+ return 1;
+ }
+ fp->del(fp);
+
+ if ((rv = read_ccss_cgats(p, icg)) != 0) {
+ icg->del(icg); /* Clean up */
+ return rv;
+ }
+
+ icg->del(icg); /* Clean up */
+
+ return 0;
+}
+
+/* Set the contents of the ccss. return nz on error. */
+/* (Copy all the values) */
+static int set_ccss(ccss *p,
+char *orig, /* Originator (May be NULL) */
+char *crdate, /* Creation date in ctime() format (May be NULL) */
+char *desc, /* General description (optional) */
+char *disp, /* Display make and model (optional if tech) */
+char *tech, /* Display technology description (optional if disp) */
+int refrmode, /* Display refresh mode, -1 = unknown, 0 = n, 1 = yes */
+char *sel, /* UI selector characters - NULL for none */
+char *refd, /* Reference spectrometer description (optional) */
+xspect *samples, /* Arry of spectral samples. All assumed to be same dim as first */
+int no_samp /* Number of spectral samples */
+) {
+ int i;
+
+ free_ccss(p);
+ if (orig != NULL) {
+ if ((p->orig = strdup(orig)) == NULL) {
+ sprintf(p->err, "set_ccss: malloc orig failed");
+ return 2;
+ }
+ }
+ if (desc != NULL) {
+ if ((p->desc = strdup(desc)) == NULL) {
+ sprintf(p->err, "set_ccss: malloc desc failed");
+ return 2;
+ }
+ }
+ if (crdate != NULL) {
+ if ((p->crdate = strdup(crdate)) == NULL) {
+ sprintf(p->err, "set_ccss: malloc crdate failed");
+ return 2;
+ }
+ }
+ if (disp != NULL) {
+ if ((p->disp = strdup(disp)) == NULL) {
+ sprintf(p->err, "set_ccss: malloc disp failed");
+ return 2;
+ }
+ }
+ if (tech != NULL) {
+ if ((p->tech = strdup(tech)) == NULL) {
+ sprintf(p->err, "set_ccss: malloc tech failed");
+ return 2;
+ }
+ }
+ p->refrmode = refrmode;
+ if (sel != NULL) {
+ if ((p->sel = strdup(sel)) == NULL) {
+ sprintf(p->err, "set_ccss: malloc sel failed");
+ return 2;
+ }
+ }
+ if (refd != NULL) {
+ if ((p->ref = strdup(refd)) == NULL) {
+ sprintf(p->err, "set_ccss: malloc ref failed");
+ return 2;
+ }
+ }
+
+ if (p->samples != NULL) {
+ free(p->samples);
+ p->samples = NULL;
+ }
+
+ if ((p->no_samp = no_samp) < 3) {
+ strcpy(p->err, "Must be at least three spectral samples");
+ p->no_samp = 0;
+ return 1;
+ }
+
+ /* Allocate spectral array */
+ if ((p->samples = (xspect *)malloc(sizeof(xspect) * p->no_samp)) == NULL) {
+ strcpy(p->err, "Malloc failed!");
+ p->no_samp = 0;
+ return 2;
+ }
+
+ /* And copy all the values */
+ for (i = 0; i < p->no_samp; i++) {
+ p->samples[i] = samples[i];
+ }
+
+ return 0;
+}
+
+/* Free the contents */
+static void free_ccss(ccss *p) {
+ if (p != NULL) {
+ if (p->desc != NULL)
+ free(p->desc);
+ p->desc = NULL;
+ if (p->orig != NULL)
+ free(p->orig);
+ p->orig = NULL;
+ if (p->crdate != NULL)
+ free(p->crdate);
+ p->crdate = NULL;
+ if (p->disp != NULL)
+ free(p->disp);
+ p->disp = NULL;
+ if (p->tech != NULL)
+ free(p->tech);
+ p->tech = NULL;
+ if (p->sel != NULL)
+ free(p->sel);
+ p->sel = NULL;
+ if (p->ref != NULL)
+ free(p->ref);
+ p->ref = NULL;
+ if (p->samples != NULL)
+ free(p->samples);
+ p->samples = NULL;
+ p->no_samp = 0;
+ }
+}
+
+/* Delete it */
+static void del_ccss(ccss *p) {
+ if (p != NULL) {
+ free_ccss(p);
+ free(p);
+ }
+}
+
+/* Allocate a new, uninitialised ccss */
+/* Note thate black and white points aren't allocated */
+ccss *new_ccss(void) {
+ ccss *p;
+
+ if ((p = (ccss *)calloc(1, sizeof(ccss))) == NULL)
+ return NULL;
+
+ /* Init method pointers */
+ p->del = del_ccss;
+ p->set_ccss = set_ccss;
+ p->write_ccss = write_ccss;
+ p->buf_write_ccss = buf_write_ccss;
+ p->read_ccss = read_ccss;
+ p->buf_read_ccss = buf_read_ccss;
+
+ return p;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/ccss.h b/xicc/ccss.h
new file mode 100644
index 0000000..0d2e128
--- /dev/null
+++ b/xicc/ccss.h
@@ -0,0 +1,112 @@
+#ifndef CCSS_H
+#define CCSS_H
+
+/*
+ * Argyll Color Correction System
+ * Colorimeter Calibration Spectral Set support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 18/8/2011
+ *
+ * Copyright 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Based on ccmx.h
+ */
+
+/*
+ * This object provides storage and application of emisive spectral
+ * samples that can be used to compute calibration for suitable
+ * colorimeters (such as the i1d3) tuned for particular types of displays.
+ */
+
+/* ------------------------------------------------------------------------------ */
+
+struct _ccss {
+
+ /* Public: */
+ void (*del)(struct _ccss *p);
+
+ /* Set the contents of the ccss. return nz on error. */
+ /* (Makes copies of all parameters) */
+ int (*set_ccss)(struct _ccss *p, char *orig, char *cdate,
+ char *desc, char *disp, char *tech, int refrmode, char *sel,
+ char *ref, xspect *samples, int no_samp);
+
+ /* write to a CGATS .ccss file */
+ /* return nz on error, with message in err[] */
+ int (*write_ccss)(struct _ccss *p, char *filename);
+
+ /* write a CGATS .ccss file to a memory buffer. */
+ /* return nz on error, with message in err[] */
+ int (*buf_write_ccss)(struct _ccss *p, unsigned char **buf, int *len);
+
+ /* read from a CGATS .ccss file */
+ /* return nz on error, with message in err[] */
+ int (*read_ccss)(struct _ccss *p, char *filename);
+
+ /* read from a CGATS .ccss file from a memory buffer. */
+ /* return nz on error, with message in err[] */
+ int (*buf_read_ccss)(struct _ccss *p, unsigned char *buf, int len);
+
+ /* Private: */
+ /* (All char * are owned by ccss) */
+ char *orig; /* Originator. May be NULL */
+ char *crdate; /* Creation date (in ctime() format). May be NULL */
+ char *desc; /* General Description (optional) */
+ char *disp; /* Description of the display (Manfrr and Model No) (optional if tech) */
+ char *tech; /* Technology (CRT, LCD + backlight type etc.) (optional if disp) */
+ int refrmode; /* Refresh mode, -1 if unknown, 0 of no, 1 if yes */
+ char *sel; /* Optional UI selector characters. May be NULL */
+ char *ref; /* Name of reference spectrometer instrument (optional) */
+ xspect *samples; /* Set of spectral samples */
+ int no_samp; /* Number of samples */
+
+ /* Houskeeping - should switch this to a1log ? */
+ int errc; /* Error code */
+ char err[200]; /* Error message */
+}; typedef struct _ccss ccss;
+
+/* Create a new, uninitialised ccss */
+ccss *new_ccss(void);
+
+#endif /* CCSS_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/ccttest.c b/xicc/ccttest.c
new file mode 100644
index 0000000..9662678
--- /dev/null
+++ b/xicc/ccttest.c
@@ -0,0 +1,306 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/5/9
+ * Version: 1.00
+ *
+ * Copyright 2006 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.
+ *
+ */
+
+/*
+ * This is some test code to test the Daylight and Plankian spectra,
+ * Correlated and Visual Color Temperatures, and CRI.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "xspect.h"
+#include "numlib.h"
+#include "plot.h"
+
+#define PLANKIAN
+#define XRES 500
+
+
+#ifdef PLANKIAN
+#define BBTYPE icxIT_Ptemp
+#else
+#define BBTYPE icxIT_Dtemp
+#endif
+
+static int do_spec(char *name, xspect *sp) {
+ int i;
+ double xyz[3]; /* Color temperature */
+ double Yxy[3];
+ double xx[XRES];
+ double y1[XRES];
+ double cct, vct;
+ double cct_xyz[3], vct_xyz[3];
+ double cct_lab[3], vct_lab[3];
+ icmXYZNumber wp;
+ double de;
+
+ printf("\n");
+
+ /* Compute XYZ of illuminant */
+ if (icx_ill_sp2XYZ(xyz, icxOT_CIE_1931_2, NULL, icxIT_custom, 0, sp) != 0)
+ error ("icx_sp_temp2XYZ returned error");
+
+ icmXYZ2Yxy(Yxy, xyz);
+
+ printf("Type = %s\n",name);
+ printf("XYZ = %f %f %f, x,y = %f %f\n", xyz[0], xyz[1], xyz[2], Yxy[1], Yxy[2]);
+
+ /* Compute CCT */
+ if ((cct = icx_XYZ2ill_ct(cct_xyz, BBTYPE, icxOT_CIE_1931_2, NULL, xyz, NULL, 0)) < 0)
+ error ("Got bad cct\n");
+
+ /* Compute VCT */
+ if ((vct = icx_XYZ2ill_ct(vct_xyz, BBTYPE, icxOT_CIE_1931_2, NULL, xyz, NULL, 1)) < 0)
+ error ("Got bad vct\n");
+
+#ifdef PLANKIAN
+ printf("CCT = %f, VCT = %f\n",cct, vct);
+#else
+ printf("CDT = %f, VDT = %f\n",cct, vct);
+#endif
+
+ {
+ int invalid = 0;
+ double cri;
+ cri = icx_CIE1995_CRI(&invalid, sp);
+ printf("CRI = %.1f%s\n",cri,invalid ? " (Invalid)" : "");
+ }
+
+ /* Use modern color difference - gives a better visual match */
+ icmAry2XYZ(wp, vct_xyz);
+ icmXYZ2Lab(&wp, cct_lab, cct_xyz);
+ icmXYZ2Lab(&wp, vct_lab, vct_xyz);
+ de = icmCIE2K(cct_lab, vct_lab);
+ printf("CIEDE2000 Delta E = %f\n",de);
+
+ /* Plot spectrum out */
+ for (i = 0; i < XRES; i++) {
+ double ww;
+
+ ww = (sp->spec_wl_long - sp->spec_wl_short)
+ * ((double)i/(XRES-1.0)) + sp->spec_wl_short;
+
+ xx[i] = ww;
+ y1[i] = value_xspect(sp, ww);
+ }
+ do_plot(xx,y1,NULL,NULL,i);
+
+ return 0;
+}
+
+
+void usage(void) {
+ fprintf(stderr,"Plot spectrum and calculate CCT and VCT\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: ccttest [infile.sp]\n");
+ fprintf(stderr," [infile.sp] spectrum to plot\n");
+ fprintf(stderr," default is all built in illuminants\n");
+ exit(1);
+}
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int k;
+ int verb = 0;
+ char in_name[100] = { '\000' }; /* Spectrum name */
+ double temp;
+ xspect sp; /* Spectra */
+ icxIllumeType ilType;
+ char buf[200];
+
+ error_program = argv[0];
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ } else {
+ usage();
+ }
+ }
+ else
+ break;
+ }
+
+ if (fa < argc && argv[fa][0] != '-')
+ strcpy(in_name,argv[fa]);
+
+#ifndef NEVER /* hack test */
+ {
+#define NTESTS 5
+ int i;
+ double cct, vct;
+ double de1, de2;
+ double xyz[NTESTS][3] = {
+ { 92.250000, 97.750000, 89.650000 }, /* Rogers spotread verification result */
+ { 94.197915, 97.686362, 80.560411, }, /* Rogers target */
+ { 93.51, 97.12, 80.86 }, /* Rogers test ? */
+ { 75.31, 78.20, 64.59 }, /* Mac LCD test */
+ { 42.98, 44.62, 36.95 } /* Hitachie CRT test */
+ };
+ double axyz[3];
+ double lab[3], alab[3];
+
+ for (i = 0; i < NTESTS; i++) {
+ /* Compute CCT */
+ if ((cct = icx_XYZ2ill_ct(axyz, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, xyz[i], NULL, 0)) < 0)
+ error ("Got bad cct\n");
+
+ axyz[0] /= axyz[1];
+ axyz[2] /= axyz[1];
+ axyz[1] /= axyz[1];
+ icmXYZ2Lab(&icmD50, alab, axyz);
+ axyz[0] = xyz[i][0] / xyz[i][1];
+ axyz[2] = xyz[i][2] / xyz[i][1];
+ axyz[1] = xyz[i][1] / xyz[i][1];
+ icmXYZ2Lab(&icmD50, lab, axyz);
+ de1 = icmCIE2K(lab, alab);
+
+ /* Compute VCT */
+ if ((vct = icx_XYZ2ill_ct(axyz, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, xyz[i], NULL, 1)) < 0)
+ error ("Got bad vct\n");
+ axyz[0] /= axyz[1];
+ axyz[2] /= axyz[1];
+ axyz[1] /= axyz[1];
+ icmXYZ2Lab(&icmD50, alab, axyz);
+ axyz[0] = xyz[i][0] / xyz[i][1];
+ axyz[2] = xyz[i][2] / xyz[i][1];
+ axyz[1] = xyz[i][1] / xyz[i][1];
+ icmXYZ2Lab(&icmD50, lab, axyz);
+ de2 = icmCIE2K(lab, alab);
+
+ printf("XYZ %f %f %f, CCT = %f de %f, VCT = %f de %f\n",xyz[i][0], xyz[i][1], xyz[i][2], cct, de1, vct, de1);
+
+ /* Compute CCT */
+ if ((cct = icx_XYZ2ill_ct(axyz, icxIT_Dtemp, icxOT_CIE_1931_2, NULL, xyz[i], NULL, 0)) < 0)
+ error ("Got bad cct\n");
+ axyz[0] /= axyz[1];
+ axyz[2] /= axyz[1];
+ axyz[1] /= axyz[1];
+ icmXYZ2Lab(&icmD50, alab, axyz);
+ axyz[0] = xyz[i][0] / xyz[i][1];
+ axyz[2] = xyz[i][2] / xyz[i][1];
+ axyz[1] = xyz[i][1] / xyz[i][1];
+ icmXYZ2Lab(&icmD50, lab, axyz);
+ de1 = icmCIE2K(lab, alab);
+
+ /* Compute VCT */
+ if ((vct = icx_XYZ2ill_ct(axyz, icxIT_Dtemp, icxOT_CIE_1931_2, NULL, xyz[i], NULL, 1)) < 0)
+ error ("Got bad vct\n");
+
+ axyz[0] /= axyz[1];
+ axyz[2] /= axyz[1];
+ axyz[1] /= axyz[1];
+ icmXYZ2Lab(&icmD50, alab, axyz);
+ axyz[0] = xyz[i][0] / xyz[i][1];
+ axyz[2] = xyz[i][2] / xyz[i][1];
+ axyz[1] = xyz[i][1] / xyz[i][1];
+ icmXYZ2Lab(&icmD50, lab, axyz);
+ de2 = icmCIE2K(lab, alab);
+
+ printf("XYZ %f %f %f, CDT = %f de %f, VDT = %f de %f\n",xyz[i][0], xyz[i][1], xyz[i][2], cct, de1, vct, de2);
+ }
+ }
+#endif
+
+ if (in_name[0] != '\000') {
+ if (read_xspect(&sp, in_name) != 0)
+ error ("Unable to read custom spectrum '%s'",in_name);
+
+ sprintf(buf, "File '%s'",in_name);
+
+ do_spec(buf, &sp);
+
+ } else {
+
+ /* For each standard illuminant */
+ for (ilType = icxIT_A; ilType <= icxIT_F10; ilType++) {
+ char *inm = NULL;
+
+ switch (ilType) {
+ case icxIT_A:
+ inm = "A"; break;
+ case icxIT_C:
+ inm = "C"; break;
+ case icxIT_D50:
+ inm = "D50"; break;
+ case icxIT_D50M2:
+ inm = "D50M2"; break;
+ case icxIT_D65:
+ inm = "D65"; break;
+ case icxIT_F5:
+ inm = "F5"; break;
+ case icxIT_F8:
+ inm = "F8"; break;
+ case icxIT_F10:
+ inm = "F10"; break;
+ default:
+ inm = "Unknown"; break;
+ break;
+ }
+
+ if (standardIlluminant(&sp, ilType, 0) != 0)
+ error ("standardIlluminant returned error");
+
+ do_spec(inm, &sp);
+ }
+
+ /* For each material and illuminant */
+ for (temp = 2500; temp <= 9000; temp += 500) {
+
+ for (k = 0; k < 2; k++) {
+
+ ilType = k == 0 ? icxIT_Dtemp : icxIT_Ptemp;
+
+ if (standardIlluminant(&sp, ilType, temp) != 0)
+ error ("standardIlluminant returned error");
+
+ sprintf(buf, "%s at %f", k == 0 ? "Daylight" : "Black body", temp);
+
+ do_spec(buf, &sp);
+ }
+ }
+
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/xicc/cgatsplot.c b/xicc/cgatsplot.c
new file mode 100644
index 0000000..9fadf89
--- /dev/null
+++ b/xicc/cgatsplot.c
@@ -0,0 +1,248 @@
+
+/*
+ * Very simple, dumb plot of .ti3 data.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2005/10/12
+ * Version: 1.0
+ *
+ * Copyright 2000 - 2005 Graeme W. Gill
+ * Please refer to License.txt file for details.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "numlib.h"
+#include "icc.h"
+#include "cgats.h"
+#include "plot.h"
+#include "xcolorants.h"
+#include "sort.h"
+
+void usage(void) {
+ fprintf(stderr,"Simple 2D plot of CGATS .ti3 data\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: cgatssplot [-v] infile\n");
+ fprintf(stderr," -v verbose\n");
+ fprintf(stderr," -0 .. -9 Choose channel to plot against\n");
+ exit(1);
+}
+
+/* Patch value type */
+typedef struct {
+ double d[ICX_MXINKS]; /* Device values */
+ double v[3]; /* CIE value */
+} pval;
+
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int chan = 0; /* Chosen channel to plot against */
+ char in_name[100];
+
+ char *buf, *outc;
+ int ti;
+ cgats *cgf = NULL; /* cgats file data */
+ int isLab = 0; /* cgats output is Lab, else XYZ */
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+ char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
+ int npat; /* Number of patches */
+ inkmask nmask; /* Device inkmask */
+ int nchan; /* Number of input chanels */
+ char *bident; /* Base ident */
+ int chix[ICX_MXINKS]; /* Device chanel indexes */
+ int pcsix[3]; /* Device chanel indexes */
+ pval *pat; /* patch values */
+ int i, j;
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ else if (argv[fa][1] >= '0' && argv[fa][1] <= '9') {
+ chan = argv[fa][1] - '0';
+ }
+ else if (argv[fa][1] == '?')
+ usage();
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa]);
+
+ /* Open CIE target values */
+ cgf = new_cgats(); /* Create a CGATS structure */
+ cgf->add_other(cgf, "CTI3");/* our special input type is Calibration Target Information 3 */
+ if (cgf->read_name(cgf, in_name))
+ error("CGATS file read error %s on file '%s'",cgf->err, in_name);
+
+ if (cgf->ntables == 0 || cgf->t[0].tt != tt_other || cgf->t[0].oi != 0)
+ error ("Profile file '%s' isn't a CTI3 format file",in_name);
+
+ if (cgf->ntables < 1)
+ error ("Input file '%s' doesn't contain at least one table",in_name);
+
+ if ((ti = cgf->find_kword(cgf, 0, "COLOR_REP")) < 0)
+ error("Input file doesn't contain keyword COLOR_REPS");
+
+ if ((buf = strdup(cgf->t[0].kdata[ti])) == NULL)
+ error("Malloc failed");
+
+ /* Split COLOR_REP into device and PCS space */
+ if ((outc = strchr(buf, '_')) == NULL)
+ error("COLOR_REP '%s' invalid", cgf->t[0].kdata[ti]);
+ *outc++ = '\000';
+
+ if (strcmp(outc, "XYZ") == 0) {
+ isLab = 0;
+ } else if (strcmp(outc, "LAB") == 0) {
+ isLab = 1;
+ } else
+ error("COLOR_REP '%s' invalid (Neither XYZ nor LAB)", cgf->t[0].kdata[ti]);
+
+ if ((nmask = icx_char2inkmask(buf)) == 0) {
+ error ("File '%s' keyword COLOR_REPS has unknown device value '%s'",in_name,buf);
+ }
+
+ free(buf);
+
+ nchan = icx_noofinks(nmask);
+ bident = icx_inkmask2char(nmask, 0); /* Base ident (No possible 'i') */
+
+ /* Find device fields */
+ for (j = 0; j < nchan; j++) {
+ int ii, imask;
+ char fname[100];
+
+ imask = icx_index2ink(nmask, j);
+ sprintf(fname,"%s_%s",nmask == ICX_W || nmask == ICX_K ? "GRAY" : bident,
+ icx_ink2char(imask));
+
+ if ((ii = cgf->find_field(cgf, 0, fname)) < 0)
+ error ("Input file doesn't contain field %s",fname);
+ if (cgf->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",fname);
+ chix[j] = ii;
+ }
+
+ /* Find PCS fields */
+ for (j = 0; j < 3; j++) {
+ int ii;
+
+ if ((ii = cgf->find_field(cgf, 0, isLab ? labfname[j] : xyzfname[j])) < 0)
+ error ("Input file doesn't contain field %s",isLab ? labfname[j] : xyzfname[j]);
+ if (cgf->t[0].ftype[ii] != r_t)
+ error ("Field %s is wrong type",isLab ? labfname[j] : xyzfname[j]);
+ pcsix[j] = ii;
+ }
+
+ npat = cgf->t[0].nsets; /* Number of patches */
+
+ if (npat <= 0)
+ error("No sets of data in file '%s'",in_name);
+
+ /* Allocate arrays to hold test patch input and output values */
+ if ((pat = (pval *)malloc(sizeof(pval) * npat)) == NULL)
+ error("Malloc failed - pat[]");
+
+ /* Grab all the values */
+ for (i = 0; i < npat; i++) {
+ pat[i].v[0] = *((double *)cgf->t[0].fdata[i][pcsix[0]]);
+ pat[i].v[1] = *((double *)cgf->t[0].fdata[i][pcsix[1]]);
+ pat[i].v[2] = *((double *)cgf->t[0].fdata[i][pcsix[2]]);
+ if (!isLab) {
+ pat[i].v[0] /= 100.0; /* Normalise XYZ to range 0.0 - 1.0 */
+ pat[i].v[1] /= 100.0;
+ pat[i].v[2] /= 100.0;
+ }
+ if (!isLab) { /* Convert test patch result XYZ to PCS (D50 Lab) */
+ icmXYZ2Lab(&icmD50, pat[i].v, pat[i].v);
+ }
+ for (j = 0; j < nchan; j++) {
+ pat[i].d[j] = *((double *)cgf->t[0].fdata[i][chix[j]]);
+ }
+ }
+
+ /* Sort by the selected channel */
+#define HEAP_COMPARE(A,B) (A.d[chan] < B.d[chan])
+ HEAPSORT(pval, pat, npat);
+#undef HEAP_COMPARE
+
+ /* Create the plot */
+ {
+ int i;
+ double *xx;
+ double *y0;
+ double *y1;
+ double *y2;
+
+ if ((xx = (double *)malloc(sizeof(double) * npat)) == NULL)
+ error("Malloc failed - xx[]");
+ if ((y0 = (double *)malloc(sizeof(double) * npat)) == NULL)
+ error("Malloc failed - y0[]");
+ if ((y1 = (double *)malloc(sizeof(double) * npat)) == NULL)
+ error("Malloc failed - y1[]");
+ if ((y2 = (double *)malloc(sizeof(double) * npat)) == NULL)
+ error("Malloc failed - y2[]");
+
+ for (i = 0; i < npat; i++) {
+ xx[i] = pat[i].d[chan];
+ y0[i] = pat[i].v[0];
+ y1[i] = 50 + pat[i].v[1]/2.0;
+ y2[i] = 50 + pat[i].v[2]/2.0;
+
+// printf("~1 %d: xx = %f, y = %f %f %f\n",i,xx[i],y0[i],y1[i],y2[i]);
+ }
+ do_plot6(xx,y0,y1,NULL,NULL,y2,NULL,npat);
+
+ free(y2);
+ free(y1);
+ free(y0);
+ free(xx);
+ }
+
+ free(pat);
+ cgf->del(cgf);
+
+ return 0;
+}
diff --git a/xicc/cv.c b/xicc/cv.c
new file mode 100644
index 0000000..5271bc4
--- /dev/null
+++ b/xicc/cv.c
@@ -0,0 +1,136 @@
+
+/**********************************************************/
+/* Investigate Graphics GEMS transfer curve function parameters */
+/**********************************************************/
+
+/* Author: Graeme Gill
+ * Date: 2003/12/1
+ *
+ * Copyright 2003 Graeme W. Gill
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <numlib.h>
+#include "plot.h"
+
+void usage(void);
+
+#define XRES 100 /* Plot resolution */
+
+/* Per transfer function */
+static double tfunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Curve order n..MPP_MXTCORD */
+double vv /* Source of value */
+) {
+ double g;
+ int ord;
+
+ if (vv < 0.0)
+ vv = 0.0;
+ else if (vv > 1.0)
+ vv = 1.0;
+
+ /* Process all the shaper orders from high to low. */
+ /* [These shapers were inspired by a Graphics Gem idea */
+ /* (Gems IV, VI.3, "Fast Alternatives to Perlin's Bias and */
+ /* Gain Functions, pp 401). */
+ /* They have the nice properties that they are smooth, and */
+ /* can't be non-monotonic. The control parameter has been */
+ /* altered to have a range from -oo to +oo rather than 0.0 to 1.0 */
+ /* so that the search space is less non-linear. ] */
+ for (ord = luord-1; ord >= 0; ord--) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+// nsec = 1 << ord; /* Double sections for each order */
+ nsec = ord + 1; /* Sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ return vv;
+}
+
+
+#define MAX_PARM 10
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int np = 0; /* Current number of input parameters */
+ double params[MAX_PARM] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ int i;
+ double x;
+ double xx[XRES];
+ double y1[XRES];
+
+ error_program = "cv";
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (np >= MAX_PARM)
+ break;
+
+ params[np++] = atof(argv[fa]);
+ }
+
+ if (np == 0)
+ np = 1;
+
+ printf("There are %d parameters:\n",np); fflush(stdout);
+ for (i = 0; i < np; i++) {
+ printf("Paramter %d = %f\n",i, params[i]); fflush(stdout);
+ }
+
+ /* Display the result */
+ for (i = 0; i < XRES; i++) {
+ x = i/(double)(XRES-1);
+
+ xx[i] = x;
+ y1[i] = tfunc(params, np, x);
+
+ if (y1[i] < -0.2)
+ y1[i] = -0.2;
+ else if (y1[i] > 1.2)
+ y1[i] = 1.2;
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+
+ return 0;
+}
+
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+void
+usage(void) {
+ puts("usage: cv param0 [param1] [param2] ... ");
+ exit(1);
+}
+
+
+
+
+
diff --git a/xicc/cvtest.c b/xicc/cvtest.c
new file mode 100644
index 0000000..6d24572
--- /dev/null
+++ b/xicc/cvtest.c
@@ -0,0 +1,411 @@
+
+/**********************************************************/
+/* Investigate GEMS transfer curve function approximation */
+/**********************************************************/
+
+/* Standard test + Random testing */
+
+/* Author: Graeme Gill
+ * Date: 2003/12/1
+ *
+ * Copyright 2003 Graeme W. Gill
+ * Parts derived from rspl/c1.c
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+#undef DIAG
+#undef TEST_SYM /* Test forcing center to zero (a*, b* constraint) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "numlib.h"
+#include "plot.h"
+
+#define MAX_PARM 40 /* Make > SHAPE_ORDS */
+
+#define POWTOL 1e-5
+#define MAXITS 10000
+
+/* SHAPE_BASE doesn't seem extremely critical. It is centered in +/- 1 magnitude */
+/* 10 x more filters out noise reasonably heaviliy, 10 x less gives noticable */
+/* overshoot Range 0.00001 .. 0.001 */
+/* SHAPE_HBASE is more critical. */
+/* Range 0.00005 .. 0.001 */
+//#define SHAPE_BASE 0.00001 /* 0 & 1 harmonic weight */
+//#define SHAPE_HBASE 0.0002 /* 2nd and higher additional weight */
+//#define SHAPE_ORDS 20
+#define SHAPE_BASE 0.00001 /* 0 & 1 harmonic weight */
+#define SHAPE_HBASE 0.0001 /* 2nd and higher additional weight */
+#define SHAPE_ORDS 20
+
+/* Interface coordinate value */
+typedef struct {
+ double p; /* coordinate position */
+ double v; /* function values */
+} co;
+
+double lin(double x, double xa[], double ya[], int n);
+static double tfunc(double *v, int luord, double vv);
+void fit(double *params, int np, co *test_points, int pnts);
+void usage(void);
+
+#define TRIALS 40 /* Number of random trials */
+#define SKIP 0 /* Number of random trials to skip */
+
+#define ABS_MAX_PNTS 100
+
+#define MIN_PNTS 2
+#define MAX_PNTS 20
+
+#define MIN_RES 20
+#define MAX_RES 500
+
+double xa[ABS_MAX_PNTS];
+double ya[ABS_MAX_PNTS];
+
+#define XRES 100
+
+#define TSETS 4
+#define PNTS 11
+#define GRES 100
+int t1p[TSETS] = {
+ 4,
+ 11,
+ 11,
+ 11
+};
+
+double t1xa[TSETS][PNTS] = {
+ { 0.0, 0.2, 0.8, 1.0 },
+ { 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 },
+ { 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 },
+ { 0.0, 0.25, 0.30, 0.35, 0.40, 0.44, 0.48, 0.51, 0.64, 0.75, 1.0 }
+};
+
+double t1ya[TSETS][PNTS] = {
+ { 0.0, 0.5, 0.6, 1.0 },
+ { 0.0, 0.10, 0.22, 0.35, 0.52, 0.65, 0.78, 0.91, 1.0, 0.9, 0.85 },
+ { 0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.8, 1.0, 1.0, 1.0 },
+ { 0.0, 0.35, 0.4, 0.41, 0.42, 0.46, 0.5, 0.575, 0.48, 0.75, 1.0 }
+};
+
+
+co test_points[ABS_MAX_PNTS];
+
+double lin(double x, double xa[], double ya[], int n);
+
+int main(void) {
+ int i, n;
+ double x;
+ double xx[XRES];
+ double y1[XRES];
+ double y2[XRES];
+ int np = SHAPE_ORDS; /* Number of harmonics */
+ double params[MAX_PARM]; /* Harmonic parameters */
+
+ error_program = "Curve1";
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+ for (n = 0; n < TRIALS; n++) {
+ double lrand; /* Amount of level randomness */
+ int pnts;
+
+ if (n < TSETS) /* Standard versions */ {
+ pnts = t1p[n];
+ for (i = 0; i < pnts; i++) {
+ xa[i] = t1xa[n][i];
+ ya[i] = t1ya[n][i];
+ }
+ } else if (n == TSETS) { /* Exponential function aproximation */
+ double ex = 2.2;
+ pnts = MAX_PNTS;
+
+ printf("Trial %d, no points = %d, exponential %f\n",n,pnts,ex);
+
+ /* Create X values */
+ for (i = 0; i < pnts; i++)
+ xa[i] = i/(pnts-1.0);
+
+ for (i = 0; i < pnts; i++)
+ ya[i] = pow(xa[i], ex);
+
+ } else if (n == (TSETS+1)) { /* Exponential function aproximation */
+ double ex = 1.0/2.2;
+ pnts = MAX_PNTS;
+
+ printf("Trial %d, no points = %d, exponential %f\n",n,pnts,ex);
+
+ /* Create X values */
+ for (i = 0; i < pnts; i++)
+ xa[i] = i/(pnts-1.0);
+
+ for (i = 0; i < pnts; i++)
+ ya[i] = pow(xa[i], ex);
+
+ } else { /* Random versions */
+ lrand = d_rand(0.0,0.2); /* Amount of level randomness */
+ lrand *= lrand;
+ pnts = i_rand(MIN_PNTS,MAX_PNTS);
+
+ printf("Trial %d, no points = %d, level randomness = %f\n",n,pnts,lrand);
+
+ /* Create X values */
+ xa[0] = 0.0;
+ for (i = 1; i < pnts; i++)
+ xa[i] = xa[i-1] + d_rand(0.5,1.0);
+ for (i = 0; i < pnts; i++) /* Divide out */
+ xa[i] = (xa[i]/xa[pnts-1]);
+
+ /* Create y values */
+ ya[0] = xa[0];
+ for (i = 1; i < pnts; i++)
+ ya[i] = ya[i-1] + d_rand(0.1,1.0) + d_rand(-0.1,0.4) + d_rand(-0.4,0.5);
+ for (i = 0; i < pnts; i++) { /* Divide out */
+ ya[i] = (ya[i]/ya[pnts-1]);
+ if (ya[i] < 0.0)
+ ya[i] = 0.0;
+ else if (ya[i] > 1.0)
+ ya[i] = 1.0;
+ }
+ }
+
+ if (n < SKIP)
+ continue;
+
+ for (i = 0; i < pnts; i++) {
+ test_points[i].p = xa[i];
+ test_points[i].v = ya[i];
+ }
+
+ for (np = 2; np <= SHAPE_ORDS; np++) {
+
+ /* Fit to scattered data */
+ fit(params, /* Parameters to return */
+ np, /* Number of parameters */
+ test_points, /* Test points */
+ pnts /* Number of test points */
+ );
+
+ printf("Number params = %d\n",np);
+ for (i = 0; i < np; i++) {
+ printf("Param %d = %f\n",i,params[i]);
+ }
+
+ /* Display the result */
+ for (i = 0; i < XRES; i++) {
+ x = i/(double)(XRES-1);
+ xx[i] = x;
+ y1[i] = lin(x,xa,ya,pnts);
+ y2[i] = tfunc(params, np, x);
+ if (y2[i] < -0.2)
+ y2[i] = -0.2;
+ else if (y2[i] > 1.2)
+ y2[i] = 1.2;
+ }
+
+ do_plot(xx,y1,y2,NULL,XRES);
+ }
+
+ } /* next trial */
+ return 0;
+}
+
+
+double lin(
+double x,
+double xa[],
+double ya[],
+int n) {
+ int i;
+ double y;
+
+ if (x < xa[0])
+ return ya[0];
+ else if (x > xa[n-1])
+ return ya[n-1];
+
+ for (i = 0; i < (n-1); i++)
+ if (x >=xa[i] && x <= xa[i+1])
+ break;
+
+ x = (x - xa[i])/(xa[i+1] - xa[i]);
+
+ y = ya[i] + (ya[i+1] - ya[i]) * x;
+
+ return y;
+ }
+
+
+/******************************************************************/
+/* Error/debug output routines */
+/******************************************************************/
+
+void
+usage(void) {
+ puts("usage: curve");
+ exit(1);
+ }
+
+/*******************************************************************/
+/* Grapic gems based, monotonic 1D function transfer curve. */
+
+/* Per transfer function */
+static double tfunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Curve order n..MPP_MXTCORD */
+double vv /* Source of value */
+) {
+ double g;
+ int ord;
+
+ if (vv < 0.0)
+ vv = 0.0;
+ else if (vv > 1.0)
+ vv = 1.0;
+
+ /* Process all the shaper orders from high to low. */
+ /* [These shapers were inspired by a Graphics Gem idea */
+ /* (Gems IV, VI.3, "Fast Alternatives to Perlin's Bias and */
+ /* Gain Functions, pp 401). */
+ /* They have the nice properties that they are smooth, and */
+ /* can't be non-monotonic. The control parameter has been */
+ /* altered to have a range from -oo to +oo rather than 0.0 to 1.0 */
+ /* so that the search space is less non-linear. ] */
+ for (ord = 0; ord < luord; ord++) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ return vv;
+}
+
+/* return the sum of the squares of the current shaper parameters */
+static double shapmag(
+double *v, /* Pointer to first parameter */
+int luord
+) {
+ double tt, w, tparam = 0.0;
+ int f;
+
+ for (f = 0; f < luord; f++) {
+ tt = v[f];
+ tt *= tt;
+
+ /* Weigh to suppress ripples */
+ if (f <= 1)
+ w = SHAPE_BASE;
+ else {
+ w = SHAPE_BASE + (f-1) * SHAPE_HBASE;
+ }
+
+ tparam += w * tt;
+ }
+ return tparam;
+}
+
+/* Context for optimising function fit */
+typedef struct {
+ int luord; /* shaper order */
+ co *points; /* List of test points */
+ int nodp; /* Number of data points */
+} luopt;
+
+/* Shaper+Matrix optimisation function handed to powell() */
+static double luoptfunc(void *edata, double *v) {
+ luopt *p = (luopt *)edata;
+ double rv = 0.0, smv;
+ double out;
+ int i;
+
+ /* For all our data points */
+ for (i = 0; i < p->nodp; i++) {
+ double ev;
+
+ /* Apply our function */
+ out = tfunc(v, p->luord, p->points[i].p);
+
+ ev = out - p->points[i].v;
+
+#ifdef NEVER
+ ev = fabs(ev);
+ rv += ev * ev * ev;
+#else
+ rv += ev * ev;
+#endif
+
+ }
+
+ /* Normalise error to be an average delta E squared */
+ rv /= (double)p->nodp;
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles" */
+ smv = shapmag(v, p->luord);
+ rv += smv;
+
+#ifdef TEST_SYM
+ {
+ double tt;
+ tt = tfunc(v, p->luord, 0.5) - 0.5;
+ tt *= tt;
+ rv += 200.0 * tt;
+ }
+#endif
+
+ printf("~1 rv = %f (%f)\n",rv,smv);
+ return rv;
+}
+
+/* Fitting function */
+void fit(
+double *params, /* Parameters to return */
+int np, /* Number of parameters */
+co *test_points, /* Test points */
+int pnts /* Number of test points */
+) {
+ int i;
+ double sa[MAX_PARM]; /* Search area */
+ luopt os;
+
+ os.luord = np;
+ os.points= test_points;
+ os.nodp = pnts;
+
+ for (i = 0; i < np; i++) {
+ sa[i] = 0.5;
+ params[i] = 0.0;
+ }
+
+ if (powell(NULL, np, params, sa, POWTOL, MAXITS, luoptfunc, (void *)&os, NULL, NULL) != 0)
+ error ("Powell failed");
+}
+
diff --git a/xicc/example.sp b/xicc/example.sp
new file mode 100644
index 0000000..57cfcfc
--- /dev/null
+++ b/xicc/example.sp
@@ -0,0 +1,130 @@
+SPECT
+
+DESCRIPTOR "Argyll Example Spectral power/reflectance information (D50)"
+ORIGINATOR "Argyll CMS"
+CREATED "Fri Jul 06 17:49:57 2001"
+KEYWORD "SPECTRAL_BANDS"
+SPECTRAL_BANDS "107"
+KEYWORD "SPECTRAL_START_NM"
+SPECTRAL_START_NM "300.000000"
+KEYWORD "SPECTRAL_END_NM"
+SPECTRAL_END_NM "830.000000"
+KEYWORD "SPECTRAL_NORM"
+SPECTRAL_NORM "100.000000"
+
+KEYWORD "SPEC_300"
+KEYWORD "SPEC_305"
+KEYWORD "SPEC_310"
+KEYWORD "SPEC_315"
+KEYWORD "SPEC_320"
+KEYWORD "SPEC_325"
+KEYWORD "SPEC_330"
+KEYWORD "SPEC_335"
+KEYWORD "SPEC_340"
+KEYWORD "SPEC_345"
+KEYWORD "SPEC_350"
+KEYWORD "SPEC_355"
+KEYWORD "SPEC_360"
+KEYWORD "SPEC_365"
+KEYWORD "SPEC_370"
+KEYWORD "SPEC_375"
+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"
+KEYWORD "SPEC_785"
+KEYWORD "SPEC_790"
+KEYWORD "SPEC_795"
+KEYWORD "SPEC_800"
+KEYWORD "SPEC_805"
+KEYWORD "SPEC_810"
+KEYWORD "SPEC_815"
+KEYWORD "SPEC_820"
+KEYWORD "SPEC_825"
+KEYWORD "SPEC_830"
+NUMBER_OF_FIELDS 107
+BEGIN_DATA_FORMAT
+SPEC_300 SPEC_305 SPEC_310 SPEC_315 SPEC_320 SPEC_325 SPEC_330 SPEC_335 SPEC_340 SPEC_345 SPEC_350 SPEC_355 SPEC_360 SPEC_365 SPEC_370 SPEC_375 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 SPEC_785 SPEC_790 SPEC_795 SPEC_800 SPEC_805 SPEC_810 SPEC_815 SPEC_820 SPEC_825 SPEC_830
+END_DATA_FORMAT
+
+NUMBER_OF_SETS 1
+BEGIN_DATA
+0.020000 1.0300 2.0500 4.9100 7.7800 11.260 14.750 16.350 17.950 19.480 21.010 22.480 23.940 25.450 26.960 25.720 24.490 27.180 29.870 39.590 49.310 52.910 56.510 58.270 60.030 58.930 57.820 66.320 74.820 81.040 87.250 88.930 90.610 90.990 91.370 93.240 95.110 93.540 91.960 93.840 95.720 96.170 96.610 96.870 97.130 99.610 102.10 101.43 100.75 101.54 102.32 101.16 100.00 98.870 97.740 98.330 98.920 96.210 93.500 95.590 97.690 98.480 99.270 99.160 99.040 97.380 95.720 97.290 98.860 97.260 95.670 96.930 98.190 100.60 103.00 101.07 99.130 93.260 87.380 89.490 91.600 92.250 92.890 84.870 76.850 81.680 86.510 89.550 92.580 85.400 78.230 67.960 57.690 70.310 82.920 80.600 78.270 78.910 79.550 76.480 73.400 68.660 63.920 67.350 70.780 72.610 74.440
+END_DATA
diff --git a/xicc/extracticc.c b/xicc/extracticc.c
new file mode 100644
index 0000000..5fc24af
--- /dev/null
+++ b/xicc/extracticc.c
@@ -0,0 +1,219 @@
+
+/*
+ * Extract an ICC profile from a TIFF file.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/5/18
+ * Version: 1.00
+ *
+ * Copyright 2008 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.
+ */
+
+/*
+ * TTBD:
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <string.h>
+#include <math.h>
+#include "numlib.h"
+#include "tiffio.h"
+#include "jpeglib.h"
+#include "iccjpeg.h"
+#include "copyright.h"
+#include "aconfig.h"
+#include "icc.h"
+
+
+void usage(char *diag, ...) {
+ int i;
+ fprintf(stderr,"Extract an ICC profile from a TIFF or JPEG file, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: extracticc [-v] infile.tif/jpg outfile%s\n",ICC_FILE_EXT);
+ fprintf(stderr," -v Verbose\n");
+ exit(1);
+}
+
+/* ------------------------------------------------------ */
+
+/* JPEG error information */
+typedef struct {
+ jmp_buf env; /* setjmp/longjmp environment */
+ char message[JMSG_LENGTH_MAX];
+} jpegerrorinfo;
+
+/* JPEG error handler */
+static void jpeg_error(j_common_ptr cinfo) {
+ jpegerrorinfo *p = (jpegerrorinfo *)cinfo->client_data;
+ (*cinfo->err->format_message) (cinfo, p->message);
+ longjmp(p->env, 1);
+}
+
+/* ------------------------------------------------------ */
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char in_name[MAXNAMEL+1]; /* TIFF input name */
+ char out_name[MAXNAMEL+1]; /* ICC output name */
+ int verb = 0;
+ TIFFErrorHandler olderrh, oldwarnh;
+ TIFFErrorHandlerExt olderrhx, oldwarnhx;
+ TIFF *rh;
+ int size = 0;
+ void *buf = NULL;
+ icmFile *fp;
+ int rv = 0;
+
+ error_program = argv[0];
+
+ if (argc < 3)
+ usage("Too few parameters");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage(NULL);
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ else
+ usage("Unknown flag '%c'",argv[fa][1]);
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing input TIFF file");
+ strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing output ICC profile");
+ strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
+
+ /* - - - - - - - - - - - - - - - */
+ /* Open up input tiff file ready for reading */
+ /* Got arguments, so setup to process the file */
+ olderrh = TIFFSetErrorHandler(NULL);
+ oldwarnh = TIFFSetWarningHandler(NULL);
+ olderrhx = TIFFSetErrorHandlerExt(NULL);
+ oldwarnhx = TIFFSetWarningHandlerExt(NULL);
+ if ((rh = TIFFOpen(in_name, "r")) != NULL) {
+ TIFFSetErrorHandler(olderrh);
+ TIFFSetWarningHandler(oldwarnh);
+ TIFFSetErrorHandlerExt(olderrhx);
+ TIFFSetWarningHandlerExt(oldwarnhx);
+
+ if (TIFFGetField(rh, TIFFTAG_ICCPROFILE, &size, &buf) == 0 || size == 0) {
+ error("unable to find ICC profile tag in TIFF file '%s'",in_name);
+ }
+
+ if ((fp = new_icmFileStd_name(out_name, "w")) == NULL) {
+ error("unable to open output ICC profile '%s'",out_name);
+ }
+
+ if (fp->write(fp, buf, 1, size) != size) {
+ error("error writing file '%s'",out_name);
+ }
+
+ if (fp->del(fp) != 0) {
+ error("error closing file '%s'",out_name);
+ }
+
+ TIFFClose(rh); /* Close Input file and free field buffer */
+
+ } else {
+ jpegerrorinfo jpeg_rerr;
+ FILE *rf = NULL;
+ struct jpeg_decompress_struct rj;
+ struct jpeg_error_mgr jerr;
+
+ TIFFSetErrorHandler(olderrh);
+ TIFFSetWarningHandler(oldwarnh);
+ TIFFSetErrorHandlerExt(olderrhx);
+ TIFFSetWarningHandlerExt(oldwarnhx);
+
+ /* We cope with the horrible ijg jpeg library error handling */
+ /* by using a setjmp/longjmp. */
+ jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+ if (setjmp(jpeg_rerr.env)) {
+ jpeg_destroy_decompress(&rj);
+ fclose(rf);
+ error("error opening read file '%s'",in_name);
+ }
+
+ rj.err = &jerr;
+ rj.client_data = &jpeg_rerr;
+ jpeg_create_decompress(&rj);
+
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((rf = fopen(in_name,"rb")) == NULL)
+#else
+ if ((rf = fopen(in_name,"r")) == NULL)
+#endif
+ {
+ jpeg_destroy_decompress(&rj);
+ error("error opening read file '%s'",in_name);
+ }
+
+ jpeg_stdio_src(&rj, rf);
+ setup_read_icc_profile(&rj);
+
+ /* we'll longjmp on error */
+ jpeg_read_header(&rj, TRUE);
+
+ if (!read_icc_profile(&rj, (unsigned char **)&buf, (unsigned int *)&size)) {
+ jpeg_destroy_decompress(&rj);
+ fclose(rf);
+ error("unable to find ICC profile marker in JPEG file '%s'",in_name);
+ }
+ jpeg_destroy_decompress(&rj);
+ fclose(rf);
+
+ if ((fp = new_icmFileStd_name(out_name, "w")) == NULL) {
+ error("unable to open output ICC profile '%s'",out_name);
+ }
+
+ if (fp->write(fp, buf, 1, size) != size) {
+ error("error writing file '%s'",out_name);
+ }
+
+ if (fp->del(fp) != 0) {
+ error("error closing file '%s'",out_name);
+ }
+ free(buf);
+ }
+ return 0;
+}
diff --git a/xicc/extractttag.c b/xicc/extractttag.c
new file mode 100644
index 0000000..79b4085
--- /dev/null
+++ b/xicc/extractttag.c
@@ -0,0 +1,203 @@
+
+/*
+ * Extract a CGATS file from an ICC profile tag.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/5/18
+ * Version: 1.00
+ *
+ * Copyright 2008 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.
+ */
+
+/*
+ * TTBD:
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xicc.h"
+
+#define MXTGNMS 30
+
+void usage(char *diag, ...) {
+ int i;
+ fprintf(stderr,"Extract a text tag from an ICC profile, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ if (diag != NULL) {
+ va_list args;
+ fprintf(stderr,"Diagnostic: ");
+ va_start(args, diag);
+ vfprintf(stderr, diag, args);
+ va_end(args);
+ fprintf(stderr,"\n");
+ }
+ fprintf(stderr,"usage: extractttag [-v] infile%s outfile\n",ICC_FILE_EXT);
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -t tag Extract this tag rather than default 'targ'\n");
+ fprintf(stderr," -c Extract calibration file from 'targ' tag\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char in_name[MAXNAMEL+1]; /* TIFF input name */
+ char out_name[MAXNAMEL+1]; /* ICC output name */
+ char tag_name[MXTGNMS] = { 't','a','r','g' };
+ int docal = 0;
+ icc *icco;
+ icTagSignature sig;
+ icmText *ro;
+ icmFile *ifp, *ofp;
+ int verb = 0;
+ int size = 0;
+ void *buf = NULL;
+ int rv = 0;
+
+ error_program = argv[0];
+
+ if (argc < 3)
+ usage("Too few parameters");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage(NULL);
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ /* Tag name */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage("Expect tag name after -t");
+ strncpy(tag_name,na,4);
+ tag_name[4] = '\000';
+ }
+
+ /* Calibration */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ docal = 1;
+ }
+
+ else
+ usage("Unknown flag '%c'",argv[fa][1]);
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing input ICC profile");
+ strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Missing output filename");
+ strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
+
+ /* - - - - - - - - - - - - - - - */
+
+ /* Open up the file for reading */
+ if ((ifp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Can't open file '%s'",in_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ if ((rv = icco->read(icco,ifp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ sig = str2tag(tag_name);
+
+ if ((ro = (icmText *)icco->read_tag(icco, sig)) == NULL)
+ error("%d, %s",icco->errc, icco->err);
+
+ if (ro->ttype != icSigTextType) {
+ error("Tag isn't TextType");
+ }
+
+ if (docal) {
+ cgatsFile *cgf;
+ cgats *icg;
+ int tab, oi;
+ xcal *cal;
+
+ if ((icg = new_cgats()) == NULL) {
+ error("new_cgats() failed");
+ }
+ if ((cgf = new_cgatsFileMem(ro->data, ro->size)) == NULL) {
+ error("new_cgatsFileMem() failed");
+ }
+ icg->add_other(icg, "CTI3");
+ oi = icg->add_other(icg, "CAL");
+
+ if (icg->read(icg, cgf) != 0) {
+ error("failed to parse tag contents as a CGATS file");
+ }
+
+ for (tab = 0; tab < icg->ntables; tab++) {
+ if (icg->t[tab].tt == tt_other && icg->t[tab].oi == oi) {
+ break;
+ }
+ }
+ if (tab >= icg->ntables) {
+ error("Failed to locate CAL table in CGATS");
+ }
+
+ if ((cal = new_xcal()) == NULL) {
+ error("new_xcal() failed");
+ }
+ if (cal->read_cgats(cal, icg, tab, in_name) != 0) {
+ error("Parsing CAL table failed");
+ }
+ icg->del(icg);
+ cgf->del(cgf);
+
+ if (cal->write(cal, out_name) != 0) {
+ error("writing to file '%s' failed\n",out_name);
+ }
+ } else {
+ if ((ofp = new_icmFileStd_name(out_name, "w")) == NULL) {
+ error("unable to open output file '%s'",out_name);
+ }
+
+ if (ofp->write(ofp, ro->data, 1, ro->size-1) != (ro->size-1)) {
+ error("writing to file '%s' failed",out_name);
+ }
+
+ if (ofp->del(ofp) != 0) {
+ error("closing file '%s' failed",out_name);
+ }
+ }
+
+ icco->del(icco);
+ ifp->del(ifp);
+
+ return 0;
+}
diff --git a/xicc/fakeCMY.c b/xicc/fakeCMY.c
new file mode 100644
index 0000000..4387cd8
--- /dev/null
+++ b/xicc/fakeCMY.c
@@ -0,0 +1,493 @@
+
+/*
+ * Create a synthetic .ti3 file for a CMY "device",
+ * that exactly maps to the surface points and neutral
+ * axis of the CMYK profile it is derived from.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2004/6/27
+ * Version: 1.00
+ *
+ * Copyright 2004 Graeme W. Gill
+ * Please refer to License.txt file for details.
+ */
+
+/* TTBD:
+ *
+ * Add a flag to create RGB instead, by simply inverting the CMY values
+ * when writing to the .ti3 file.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xicc.h"
+#include "cgats.h"
+#include "targen.h"
+
+#define EXTRA_NEUTRAL 50 /* Crude way of increasing weighting */
+
+/* ---------------------------------------- */
+
+void usage(char *diag) {
+ fprintf(stderr,"Create a fake CMY data file from a CMYK profile, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: fakeCMY [option] profile.icm fake.ti3\n");
+ if (diag != NULL)
+ fprintf(stderr,"Diagnostic: %s\n",diag);
+ fprintf(stderr," -v verbose\n");
+ fprintf(stderr," -r res set surface point resolution (default 3)\n");
+ fprintf(stderr," -l tlimit set total ink limit, 0 - 400%% (estimate by default)\n");
+ fprintf(stderr," -L klimit set black ink limit, 0 - 100%% (estimate by default)\n");
+ exit(1);
+}
+
+/* Fake up a vector direction clip in Lab space */
+static void visect(
+ icxLuBase *luo, /* xicc lookup object */
+ double *pout, /* PCS result (may be NULL) */
+ double *dout, /* Device result (may be NULL) */
+ double *orig, /* Origin of vector (PCS) */
+ double *vec /* Input vector (PCS) */
+) {
+ int i;
+ int rv;
+ double sum, step, inc[3]; /* 1 Delta E increment */
+ double try[3]; /* Trial PCS */
+ double res[4]; /* Trial result device values */
+
+ for (sum = 0.0, i = 0; i < 3; i++) {
+ double tt = vec[i] - orig[i];
+ sum += tt * tt;
+ }
+ sum = sqrt(sum);
+ for (i = 0; i < 3; i++) {
+ inc[i] = (vec[i] - orig[i])/sum;
+ }
+//printf("~1 orig %f %f %f, vec %f %f %f\n",orig[0],orig[1],orig[2],vec[0],vec[1],vec[3]);
+//printf("~1 inc %f %f %f\n",inc[0],inc[1],inc[2]);
+
+ /* Increment in vector direction until we clip */
+ for (i = 0; i < 3; i++)
+ try[i] = 0.5 * (orig[i] + vec[i]);
+
+ for (step = 20.0;;) {
+ rv = luo->inv_lookup(luo, res, try);
+ if (rv > 1)
+ error ("inv_lookup failed");
+//printf("~1 trial %f %f %f returned %d\n",try[0],try[1],try[2],rv);
+ if (rv == 1) {
+ if (step <= 0.1)
+ break;
+ /* Back off, and use smaller steps */
+ for (i = 0; i < 3; i++)
+ try[i] -= step * inc[i];
+ step *= 0.5;
+ }
+ for (i = 0; i < 3; i++)
+ try[i] += step * inc[i];
+ }
+
+ if (dout != NULL)
+ for (i = 0; i < 3; i++)
+ dout[i] = res[i];
+
+ /* Lookup the clipped PCS */
+ if (pout != NULL)
+ luo->lookup(luo, pout, res);
+}
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ double tlimit = -1.0; /* Total ink limit */
+ double klimit = -1.0; /* Black ink limit */
+ int tres = 3; /* Resolution of suface grid */
+ int gres = tres+2; /* Resolution of grey points */
+ char in_name[100];
+ char out_name[100];
+ icmFile *rd_fp;
+ icc *rd_icco;
+ int rv = 0;
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ xicc *xicco;
+ icxLuBase *luo;
+ icxInk ink; /* Ink parameters */
+ fxpos *fxlist = NULL; /* Fixed point list for full spread */
+ int fxlist_a = 0; /* Fixed point list allocation */
+ int fxno = 0; /* The number of fixed points */
+ int gc[MXTD]; /* Grid coordinate */
+
+ cgats *ocg; /* output cgats structure */
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+
+ int i, j;
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage("Not enough arguments");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ /* Ink limits */
+ else if (argv[fa][1] == 'l') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -l");
+ tlimit = atoi(na)/100.0;
+ }
+
+ else if (argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -L");
+ klimit = atoi(na)/100.0;
+ }
+
+ /* Resolution */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -r");
+ tres = atoi(na);
+ }
+
+ else if (argv[fa][1] == '?')
+ usage(NULL);
+ else
+ usage("Unknown flag");
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Expected input profile name");
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Expected output .ti3 name");
+ strcpy(out_name,argv[fa++]);
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+
+ /* Wrap with an expanded icc */
+ if ((xicco = new_xicc(rd_icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ /* Setup ink limit */
+
+ /* Set the default ink limits if not set on command line */
+ icxDefaultLimits(xicco, &ink.tlimit, tlimit, &ink.klimit, klimit);
+
+ if (verb) {
+ if (ink.tlimit >= 0.0)
+ printf("Total ink limit assumed is %3.0f%%\n",100.0 * ink.tlimit);
+ if (ink.klimit >= 0.0)
+ printf("Black ink limit assumed is %3.0f%%\n",100.0 * ink.klimit);
+ }
+
+ ink.c.Ksmth = ICXINKDEFSMTH; /* Default smoothing */
+ ink.c.Kskew = ICXINKDEFSKEW; /* default curve skew */
+ ink.c.Kstle = 0.5; /* Min K at white end */
+ ink.c.Kstpo = 0.5; /* Start of transition is at white */
+ ink.c.Kenle = 0.5; /* Max K at black end */
+ ink.c.Kenpo = 0.5; /* End transition at black */
+ ink.c.Kshap = 1.0; /* Linear transition */
+
+ gres = tres + 2;
+
+ /* Get a Device to PCS conversion object */
+ if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmFwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+ /* Get details of conversion */
+ luo->spaces(luo, &ins, NULL, &outs, NULL, NULL, NULL, NULL, NULL);
+
+ if (ins != icSigCmykData) {
+ error("Expecting CMYK device");
+ }
+
+ /* Make a default allocation */
+ fxlist_a = 4;
+ if ((fxlist = (fxpos *)malloc(sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+
+ /* init coords */
+ for (j = 0; j < 3; j++)
+ gc[j] = 0;
+
+ for (;;) { /* For all grid points */
+
+ /* Check if this position is on the CMY surface */
+ for (j = 0; j < 3; j++) {
+ if (gc[j] == 0 || gc[j] == (tres-1))
+ break;
+ }
+ if (j < 3) { /* On the surface */
+
+ /* Make sure there is room */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (j = 0; j < 3; j++)
+ fxlist[fxno].p[j] = gc[j]/(tres-1.0);
+ fxlist[fxno].p[3] = 0.0;
+ fxno++;
+ }
+
+ /* Increment grid index and position */
+ for (j = 0; j < 3; j++) {
+ gc[j]++;
+ if (gc[j] < tres)
+ break; /* No carry */
+ gc[j] = 0;
+ }
+ if (j >= 3)
+ break; /* Done grid */
+ }
+
+ for (i = 1; i < ((EXTRA_NEUTRAL * gres)-1); i++) { /* For all grey axis points */
+
+ /* Make sure there is room */
+ if (fxno >= fxlist_a) {
+ fxlist_a *= 2;
+ if ((fxlist = (fxpos *)realloc(fxlist, sizeof(fxpos) * fxlist_a)) == NULL)
+ error ("Failed to malloc fxlist");
+ }
+ for (j = 0; j < 3; j++)
+ fxlist[fxno].p[j] = i/((EXTRA_NEUTRAL * gres)-1.0);
+ fxlist[fxno].p[3] = 0.0;
+ fxno++;
+ }
+
+ /* Convert CMY values into CMY0 Lab values */
+ for (i = 0; i < fxno; i++) {
+ if ((rv = luo->lookup(luo, fxlist[i].v, fxlist[i].p)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+//printf("~1 initial lookup %f %f %f -> %f %f %f\n", fxlist[i].p[0], fxlist[i].p[1], fxlist[i].p[2], fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
+ }
+
+ /* Figure out the general scale at the black end */
+ {
+ double dval[4];
+ double wt[3] = { 100.0, 0, 0 }; /* Approximate white PCS */
+ double ac[3] = { 50.0, 0, 0 }; /* Adjustment center */
+
+ double lab_wt[3]; /* Media Whitepoint PCS */
+ double xyz_wt[3]; /* Media Whitepoint PCS */
+ icmXYZNumber XYZ_WT;
+ double k_bk[3]; /* K black PCS */
+ double cmyk_bk[3]; /* CMYK black PCS */
+ double toAbs[3][3];
+ double fromAbs[3][3];
+
+ /* Discover the Lab of the CMYK media */
+ for (j = 0; j < 4; j++)
+ dval[j] = 0.0;
+ luo->lookup(luo, lab_wt, dval);
+ icmLab2XYZ(&icmD50, xyz_wt, lab_wt);
+ icmAry2XYZ(XYZ_WT, xyz_wt);
+
+ /* Create the XYZ chromatic transform from relative to absolute and back */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, XYZ_WT, icmD50, toAbs);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, XYZ_WT, fromAbs);
+
+ /* Discover the Lab of the CMY black and CMYK black */
+ for (j = 0; j < 3; j++)
+ dval[j] = 0.0;
+ dval[j] = 1.0;
+ luo->lookup(luo, k_bk, dval);
+ visect(luo, cmyk_bk, NULL, wt, k_bk);
+ if (verb)
+ printf("K black %f %f %f, CMYK black %f %f %f\n", k_bk[0], k_bk[1], k_bk[2], cmyk_bk[0], cmyk_bk[1], cmyk_bk[2]);
+
+ /* Scale the CMY values that will be influenced by the K component to a darker */
+ /* black. */
+
+ for (i = 0; i < fxno; i++) {
+
+ /* Treat grey axis points differently */
+ if (fxlist[i].p[0] != 0.0
+ && fxlist[i].p[0] == fxlist[i].p[1]
+ && fxlist[i].p[0] == fxlist[i].p[2]) {
+ double xyz[3]; /* Temporary */
+ double lab[3]; /* Temporary */
+
+//printf("~1 scaled neutral L value from %f",fxlist[i].v[0]);
+
+ /* Scale L value from K to CMYK black */
+ fxlist[i].v[0] = lab_wt[0] + (fxlist[i].v[0] - lab_wt[0]) *
+ (cmyk_bk[0] - lab_wt[0])/(k_bk[0] - lab_wt[0]);
+//printf(" to %f\n",fxlist[i].v[0]);
+
+#ifdef NEVER
+ /* Make a & b values same as CMYK black */
+ /* Pivot around white point */
+ fxlist[i].v[1] = wt[1] + (cmyk_bk[1] - wt[1]) *
+ (fxlist[i].v[0] - wt[0])/(cmyk_bk[0] - wt[0]);
+ fxlist[i].v[2] = wt[2] + (cmyk_bk[2] - wt[2]) *
+ (fxlist[i].v[0] - wt[0])/(cmyk_bk[0] - wt[0]);
+#else
+ /* Convert absolute target Lab to relative Lab */
+ icmLab2XYZ(&icmD50, xyz, fxlist[i].v);
+ icmMulBy3x3(xyz, fromAbs, xyz);
+ icmXYZ2Lab(&icmD50, lab, xyz);
+
+ /* Make sure the equivalent relative value is neutral */
+ lab[1] = lab[2] = 0.0;
+
+ /* Convert back to absolute Lab */
+ icmLab2XYZ(&icmD50, xyz, lab);
+ icmMulBy3x3(xyz, toAbs, xyz);
+ icmXYZ2Lab(&icmD50, lab, xyz);
+
+//printf("~1 corrected neutral value from Lab %f %f %f to %f %f %f\n", fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2], lab[0], lab[1], lab[2]);
+
+ for (j = 0; j < 3; j++)
+ fxlist[i].v[j] = lab[j];
+#endif
+
+ } else {
+
+ for (j = 0; j < 3; j++) {
+ if (fxlist[i].p[j] == 0.0)
+ break; /* Not a dark color */
+ }
+ if (j >= 3) {
+ /* Scale by CMYK/K black vector */
+ for (j = 0; j < 3; j++) {
+ fxlist[i].v[j] = lab_wt[j] + (fxlist[i].v[j] - lab_wt[j]) *
+ (cmyk_bk[j] - lab_wt[j])/(k_bk[j] - lab_wt[j]);
+ }
+ }
+
+//printf("[%4.2f %4.2f %4.2f] %f %f %f becomes",
+//fxlist[i].p[0], fxlist[i].p[1], fxlist[i].p[2], fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
+ /* Now clip non-neutrals to the gamut surface */
+ visect(luo, fxlist[i].v, NULL, ac, fxlist[i].v);
+//printf("%f %f %f\n", fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
+ }
+ }
+ }
+
+ if (verb) {
+ for (i = 0; i < fxno; i++) {
+ printf("Point %d = %f %f %f -> %f %f %f\n",i,
+ fxlist[i].p[0], fxlist[i].p[1], fxlist[i].p[2],
+ fxlist[i].v[0], fxlist[i].v[1], fxlist[i].v[2]);
+ }
+ }
+
+ /* Setup output cgats file */
+ {
+ char buf[1000];
+ cgats_set_elem *setel; /* Array of set value elements */
+
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "CTI3"); /* our special type is Calibration Target Information 3 */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Calibration Target chart information 3",NULL);
+ ocg->add_kword(ocg, 0, NULL, NULL, "Fake CMY device data for CMY->CMYK link");
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll fakeCMY", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL);
+
+ ocg->add_kword(ocg, 0, "COLOR_REP","CMY_LAB", NULL);
+
+ if (tlimit >= 0) {
+ sprintf(buf,"%.0f",tlimit);
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT",buf, NULL);
+ }
+
+ if (klimit >= 0) {
+ sprintf(buf,"%.0f",klimit);
+ ocg->add_kword(ocg, 0, "BLACK_INK_LIMIT",buf, NULL);
+ }
+
+ /* Fields we want */
+ ocg->add_field(ocg, 0, "SAMPLE_ID", nqcs_t);
+ ocg->add_field(ocg, 0, "CMY_C", r_t);
+ ocg->add_field(ocg, 0, "CMY_M", r_t);
+ ocg->add_field(ocg, 0, "CMY_Y", r_t);
+ ocg->add_field(ocg, 0, "LAB_L", r_t);
+ ocg->add_field(ocg, 0, "LAB_A", r_t);
+ ocg->add_field(ocg, 0, "LAB_B", r_t);
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * 7)) == NULL)
+ error("Malloc failed!");
+
+ /* Write out test values. */
+ for (i = 0; i < fxno; i++) {
+
+ sprintf(buf, "%d", i+1);
+ setel[0].c = buf;
+
+ setel[1].d = 100.0 * fxlist[i].p[0];
+ setel[2].d = 100.0 * fxlist[i].p[1];
+ setel[3].d = 100.0 * fxlist[i].p[2];
+ setel[4].d = fxlist[i].v[0];
+ setel[5].d = fxlist[i].v[1];
+ setel[6].d = fxlist[i].v[2];
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ free(setel);
+ if (ocg->write_name(ocg, out_name))
+ error("Write error : %s",ocg->err);
+ ocg->del(ocg);
+ }
+
+ luo->del(luo);
+ xicco->del(xicco);
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ return 0;
+}
+
diff --git a/xicc/fbview.c b/xicc/fbview.c
new file mode 100644
index 0000000..53da99e
--- /dev/null
+++ b/xicc/fbview.c
@@ -0,0 +1,312 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * View the gamut clipping implemented by the bwd profile.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2000/12/8
+ * Version: 1.23
+ *
+ * Copyright 2000 Graeme W. Gill
+ * Please refer to License.txt file for details.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+
+#define TRES 43
+
+/* - - - - - - - - - - - - - */
+
+/* Return maximum difference */
+double maxdiff(double in1[3], double in2[3]) {
+ double tt, rv = 0.0;
+ if ((tt = fabs(in1[0] - in2[0])) > rv)
+ rv = tt;
+ if ((tt = fabs(in1[1] - in2[1])) > rv)
+ rv = tt;
+ if ((tt = fabs(in1[2] - in2[2])) > rv)
+ rv = tt;
+ return rv;
+}
+
+/* Return absolute difference */
+double absdiff(double in1[3], double in2[3]) {
+ double tt, rv = 0.0;
+ tt = in1[0] - in2[0];
+ rv += tt * tt;
+ tt = in1[1] - in2[1];
+ rv += tt * tt;
+ tt = in1[2] - in2[2];
+ rv += tt * tt;
+ return sqrt(rv);
+}
+
+/* ---------------------------------------- */
+
+void usage(void) {
+ fprintf(stderr,"View bwd table clipping of an ICC file, , Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: fbtest [-v] infile\n");
+ fprintf(stderr," -v verbose\n");
+ exit(1);
+}
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int doaxes = 0;
+ char in_name[100];
+ char *xl, out_name[100];
+ icmFile *rd_fp;
+ icc *rd_icco;
+ int rv = 0;
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+
+ /* Check variables */
+ int co[4];
+ double in[4], out[4], check[4], temp[4];
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ else if (argv[fa][1] == '?')
+ usage();
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa]);
+
+ strcpy(out_name, in_name);
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".wrl");
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Run the target Lab values through the bwd and fwd tables, */
+ /* to compute the overall error. */
+ {
+#define GAMUT_LCENT 50.0
+ double merr = 0.0;
+ double aerr = 0.0;
+ double nsamps = 0.0;
+ icmLuBase *luo1, *luo2;
+ FILE *wrl;
+ struct {
+ double x, y, z;
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+ int i, j;
+
+
+ /* Get a Device to PCS conversion object */
+ if ((luo1 = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((luo1 = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+ /* Get details of conversion */
+ luo1->spaces(luo1, &ins, NULL, &outs, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ if (ins != icSigCmykData) {
+ error("Expecting CMYK device");
+ }
+
+ /* Get a PCS to Device conversion object */
+ if ((luo2 = rd_icco->get_luobj(rd_icco, icmBwd, icAbsoluteColorimetric,
+ icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((luo2 = rd_icco->get_luobj(rd_icco, icmBwd, icmDefaultIntent,
+ icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ if ((wrl = fopen(out_name,"w")) == NULL) {
+ fprintf(stderr,"Error opening output file '%s'\n",out_name);
+ return 2;
+ }
+
+ /* Spit out a VRML 2 Object surface of gamut */
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ fprintf(wrl,"# Lab axes as boxes:\n");
+ for (i = 0; i < 5; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape{\n");
+ fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
+ axes[i].wx, axes[i].wy, axes[i].wz);
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"\n");
+ }
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+
+ i = 0;
+// for (co[0] = 0; co[0] < TRES; co[0]++) {
+ for (co[1] = 0; co[1] < TRES; co[1]++) {
+ for (co[2] = 0; co[2] < TRES; co[2]++) {
+ int rv1, rv2;
+ double mxd, absd;
+
+// temp[0] = co[0]/(TRES-1.0);
+ temp[1] = co[1]/(TRES-1.0);
+ temp[2] = co[2]/(TRES-1.0);
+
+// in[0] = temp[0] * 100.0;
+ in[0] = 0.0;
+ in[1] = 200.0 * temp[1] -100.0;
+ in[2] = 200.0 * temp[2] -100.0;
+
+
+ /* PCS -> Device */
+ if ((rv2 = luo2->lookup(luo2, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Device -> PCS */
+ if ((rv1 = luo1->lookup(luo1, check, out)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (verb) {
+ printf("%f %f %f -> %f %f %f %f -> %f %f %f [%f]\n",
+ in[0],in[1],in[2],out[0],out[1],out[2],out[3],check[0],check[1],check[2],
+ maxdiff(check, in));
+ }
+
+ /* Check the result */
+ mxd = maxdiff(check, in);
+ if (mxd > merr)
+ merr = mxd;
+
+ nsamps++;
+ absd = absdiff(check, in);
+ aerr += absd;
+
+ if (absd > 3.0) {
+ fprintf(wrl,"%f %f %f,\n",in[1], in[2], in[0]-GAMUT_LCENT);
+ fprintf(wrl,"%f %f %f,\n",check[1], check[2], check[0]-GAMUT_LCENT);
+ i++;
+ }
+ }
+ }
+// }
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (j = 0; j < i; j++) {
+ fprintf(wrl,"%d, %d, -1,\n", j * 2, j * 2 + 1);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0) {
+ fprintf(stderr,"Error closing output file '%s'\n",out_name);
+ return 2;
+ }
+
+ printf("bwd to fwd check complete, peak err = %f, avg err = %f\n",merr,aerr/nsamps);
+
+ /* Done with lookup object */
+ luo1->del(luo1);
+ luo2->del(luo2);
+ }
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ return 0;
+}
+
diff --git a/xicc/iccgamut.c b/xicc/iccgamut.c
new file mode 100644
index 0000000..7bd3b4c
--- /dev/null
+++ b/xicc/iccgamut.c
@@ -0,0 +1,811 @@
+
+/*
+ * iccgamut
+ *
+ * Produce color surface gamut of an ICC profile.
+ *
+ * Author: Graeme W. Gill
+ * Date: 19/3/00
+ * Version: 1.00
+ *
+ * Copyright 2000 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.
+ */
+
+
+/*
+ * TTBD:
+ * To support CIACAM02 properly, need to cope with viewing parameters ?
+ */
+
+#define SURFACE_ONLY
+#define GAMRES 10.0 /* Default surface resolution */
+
+#define USE_CAM_CLIP_OPT /* Use CAM space to clip in */
+
+#define RGBRES 33 /* 33 */
+#define CMYKRES 17 /* 17 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xicc.h"
+#include "gamut.h"
+#include "counters.h"
+
+static void diag_gamut(icxLuBase *p, double detail, int doaxes,
+ double tlimit, double klimit, char *outname);
+
+void usage(char *diag) {
+ int i;
+ fprintf(stderr,"Create Lab/Jab gamut plot Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: iccgamut [options] profile\n");
+ if (diag != NULL)
+ fprintf(stderr,"Diagnostic: %s\n",diag);
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -d sres Surface resolution details 1.0 - 50.0\n");
+ fprintf(stderr," -w emit VRML .wrl file as well as CGATS .gam file\n");
+ fprintf(stderr," -n Don't add VRML axes or white/black point\n");
+ fprintf(stderr," -k Add VRML markers for prim. & sec. \"cusp\" points\n");
+ fprintf(stderr," -f function f = forward*, b = backwards\n");
+ fprintf(stderr," -i intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute (default), d = profile default\n");
+// fprintf(stderr," P = absolute perceptual, S = absolute saturation\n");
+ fprintf(stderr," -p oride l = Lab_PCS (default), j = %s Appearance Jab\n",icxcam_description(cam_default));
+ fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
+ fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
+ fprintf(stderr," -l tlimit set total ink limit, 0 - 400%% (estimate by default)\n");
+ fprintf(stderr," -L klimit set black ink limit, 0 - 100%% (estimate by default)\n");
+ fprintf(stderr," -c viewcond set viewing conditions for %s,\n",icxcam_description(cam_default));
+ fprintf(stderr," either an enumerated choice, or a series of parameter:value changes\n");
+ for (i = 0; ; i++) {
+ icxViewCond vc;
+ if (xicc_enum_viewcond(NULL, &vc, i, NULL, 1, NULL) == -999)
+ break;
+
+ fprintf(stderr," %s\n",vc.desc);
+ }
+ fprintf(stderr," s:surround n = auto, a = average, m = dim, d = dark,\n");
+ fprintf(stderr," c = transparency (default average)\n");
+ fprintf(stderr," w:X:Y:Z Adapted white point as XYZ (default media white)\n");
+ fprintf(stderr," w:x:y Adapted white point as x, y\n");
+ fprintf(stderr," a:adaptation Adaptation luminance in cd.m^2 (default 50.0)\n");
+ fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
+ fprintf(stderr," l:scenewhite Scene white in cd.m^2 if surround = auto (default 250)\n");
+ fprintf(stderr," f:flare Flare light %% of image luminance (default 1)\n");
+ fprintf(stderr," f:X:Y:Z Flare color as XYZ (default media white)\n");
+ fprintf(stderr," f:x:y Flare color as x, y\n");
+ fprintf(stderr," -s Create special cube surface topology plot\n");
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char prof_name[100];
+ char *xl, out_name[100];
+ icmFile *fp;
+ icc *icco;
+ xicc *xicco;
+ gamut *gam;
+ int verb = 0;
+ int rv = 0;
+ int vrml = 0;
+ int doaxes = 1;
+ int docusps = 0;
+ double gamres = GAMRES; /* Surface resolution */
+ int special = 0; /* Special surface plot */
+ int fl = 0; /* luobj flags */
+ icxInk ink; /* Ink parameters */
+ int tlimit = -1; /* Total ink limit as a % */
+ int klimit = -1; /* Black ink limit as a % */
+ icxViewCond vc; /* Viewing Condition for CIECAM */
+ int vc_e = -1; /* Enumerated viewing condition */
+ int vc_s = -1; /* Surround override */
+ double vc_wXYZ[3] = {-1.0, -1.0, -1.0}; /* Adapted white override in XYZ */
+ double vc_wxy[2] = {-1.0, -1.0}; /* Adapted white override in x,y */
+ double vc_a = -1.0; /* Adapted luminance */
+ double vc_b = -1.0; /* Background % overide */
+ double vc_l = -1.0; /* Scene luminance override */
+ double vc_f = -1.0; /* Flare % overide */
+ double vc_fXYZ[3] = {-1.0, -1.0, -1.0}; /* Flare color override in XYZ */
+ double vc_fxy[2] = {-1.0, -1.0}; /* Flare color override in x,y */
+
+ icxLuBase *luo;
+
+ /* Lookup parameters */
+ icmLookupFunc func = icmFwd; /* Default */
+ icRenderingIntent intent = -1; /* Default */
+ icColorSpaceSignature pcsor = icSigLabData; /* Default */
+ icmLookupOrder order = icmLuOrdNorm; /* Default */
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage("Too few parameters");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage(NULL);
+
+ /* function */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -f");
+ switch (na[0]) {
+ case 'f':
+ case 'F':
+ func = icmFwd;
+ break;
+ case 'b':
+ case 'B':
+ func = icmBwd;
+ break;
+ default:
+ usage("Unrecognised parameter after flag -f");
+ }
+ }
+
+ /* Intent */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -i");
+ switch (na[0]) {
+ case 'd':
+ intent = icmDefaultIntent;
+ break;
+ case 'a':
+ intent = icAbsoluteColorimetric;
+ break;
+ case 'p':
+ intent = icPerceptual;
+ break;
+ case 'r':
+ intent = icRelativeColorimetric;
+ break;
+ case 's':
+ intent = icSaturation;
+ break;
+ /* Argyll special intents to check spaces underlying */
+ /* icxPerceptualAppearance & icxSaturationAppearance */
+ case 'P':
+ intent = icmAbsolutePerceptual;
+ break;
+ case 'S':
+ intent = icmAbsoluteSaturation;
+ break;
+ default:
+ usage("Unrecognised parameter after flag -i");
+ }
+ }
+
+ /* Search order */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -o");
+ switch (na[0]) {
+ case 'n':
+ case 'N':
+ order = icmLuOrdNorm;
+ break;
+ case 'r':
+ case 'R':
+ order = icmLuOrdRev;
+ break;
+ default:
+ usage("Unrecognised parameter after flag -o");
+ }
+ }
+
+ /* PCS override */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -p");
+ switch (na[0]) {
+ case 'l':
+ pcsor = icSigLabData;
+ break;
+ case 'j':
+ pcsor = icxSigJabData;
+ break;
+ default:
+ usage("Unrecognised parameter after flag -p");
+ }
+ }
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ /* VRML output */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ vrml = 1;
+ }
+ /* No axis output in vrml */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ doaxes = 0;
+ }
+ /* Do cusp markers in vrml */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ docusps = 1;
+ }
+ /* Special */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ special = 1;
+ }
+ /* Ink limit */
+ else if (argv[fa][1] == 'l') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -l");
+ tlimit = atoi(na);
+ }
+
+ else if (argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -L");
+ klimit = atoi(na);
+ }
+
+
+ /* Surface Detail */
+ else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -d");
+ gamres = atof(na);
+ if (gamres < 0.1 || gamres > 50.0)
+ usage("Parameter after flag -d seems out of range");
+ }
+
+ /* Viewing conditions */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -c");
+#ifdef NEVER
+ if (na[0] >= '0' && na[0] <= '9') {
+ vc_e = atoi(na);
+ } else
+#endif
+ if (na[1] != ':') {
+ if ((vc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
+ usage("Urecognised Enumerated Viewing conditions");
+ } else if (na[0] == 's' || na[0] == 'S') {
+ if (na[1] != ':')
+ usage("Unrecognised parameters after -cs");
+ if (na[2] == 'n' || na[2] == 'N') {
+ vc_s = vc_none; /* Automatic from Lv */
+ } else if (na[2] == 'a' || na[2] == 'A') {
+ vc_s = vc_average;
+ } else if (na[2] == 'm' || na[2] == 'M') {
+ vc_s = vc_dim;
+ } else if (na[2] == 'd' || na[2] == 'D') {
+ vc_s = vc_dark;
+ } else if (na[2] == 'c' || na[2] == 'C') {
+ vc_s = vc_cut_sheet;
+ } else
+ usage("Unrecognised parameters after -cs:");
+ } else if (na[0] == 'w' || na[0] == 'W') {
+ double x, y, z;
+ if (sscanf(na+1,":%lf:%lf:%lf",&x,&y,&z) == 3) {
+ vc_wXYZ[0] = x; vc_wXYZ[1] = y; vc_wXYZ[2] = z;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc_wxy[0] = x; vc_wxy[1] = y;
+ } else
+ usage("Unrecognised parameters after -cw");
+ } else if (na[0] == 'a' || na[0] == 'A') {
+ if (na[1] != ':')
+ usage("Unrecognised parameters after -ca");
+ vc_a = atof(na+2);
+ } else if (na[0] == 'b' || na[0] == 'B') {
+ if (na[1] != ':')
+ usage("Unrecognised parameters after -cb");
+ vc_b = atof(na+2);
+ } else if (na[0] == 'l' || na[0] == 'L') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-[cd]l) missing ':'");
+ vc_l = atof(na+2);
+ } else if (na[0] == 'f' || na[0] == 'F') {
+ 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;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc_fxy[0] = x; vc_fxy[1] = y;
+ } else if (sscanf(na+1,":%lf",&x) == 1) {
+ vc_f = x;
+ } else
+ usage("Unrecognised parameters after -cf");
+ } else
+ usage("Unrecognised parameters after -c");
+ }
+ else
+ usage("Unknown flag");
+ } else
+ break;
+ }
+
+ if (intent == -1) {
+ if (pcsor == icxSigJabData)
+ intent = icRelativeColorimetric; /* Default to icxAppearance */
+ else
+ intent = icAbsoluteColorimetric; /* Default to icAbsoluteColorimetric */
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Expected profile name");
+ strcpy(prof_name,argv[fa]);
+
+ /* Open up the profile for reading */
+ if ((fp = new_icmFileStd_name(prof_name,"r")) == NULL)
+ error ("Can't open file '%s'",prof_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ if ((rv = icco->read(icco,fp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ if (verb) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ icco->header->dump(icco->header, op, 1);
+ op->del(op);
+ }
+
+ /* Wrap with an expanded icc */
+ if ((xicco = new_xicc(icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ /* Set the ink limits */
+ icxDefaultLimits(xicco, &ink.tlimit, tlimit/100.0, &ink.klimit, klimit/100.0);
+
+ if (verb) {
+ if (ink.tlimit >= 0.0)
+ printf("Total ink limit assumed is %3.0f%%\n",100.0 * ink.tlimit);
+ if (ink.klimit >= 0.0)
+ printf("Black ink limit assumed is %3.0f%%\n",100.0 * ink.klimit);
+ }
+
+ /* Setup a safe ink generation (not used) */
+ ink.KonlyLmin = 0; /* Use normal black Lmin for locus */
+ ink.k_rule = icxKluma5k;
+ ink.c.Ksmth = ICXINKDEFSMTH; /* Default smoothing */
+ ink.c.Kskew = ICXINKDEFSKEW; /* default curve skew */
+ ink.c.Kstle = 0.0; /* Min K at white end */
+ ink.c.Kstpo = 0.0; /* Start of transition is at white */
+ ink.c.Kenle = 1.0; /* Max K at black end */
+ ink.c.Kenpo = 1.0; /* End transition at black */
+ ink.c.Kshap = 1.0; /* Linear transition */
+
+ /* Setup the default viewing conditions */
+ if (xicc_enum_viewcond(xicco, &vc, -1, NULL, 0, NULL) == -2)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ if (vc_e != -1)
+ if (xicc_enum_viewcond(xicco, &vc, vc_e, NULL, 0, NULL) == -2)
+ error ("%d, %s",xicco->errc, xicco->err);
+ if (vc_s >= 0)
+ vc.Ev = vc_s;
+ if (vc_wXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Wxyz[0] = vc_wXYZ[0]/vc_wXYZ[1] * vc.Wxyz[1];
+ vc.Wxyz[2] = vc_wXYZ[2]/vc_wXYZ[1] * vc.Wxyz[1];
+ }
+ if (vc_wxy[0] >= 0.0) {
+ double x = vc_wxy[0];
+ double y = vc_wxy[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
+ double z = 1.0 - x - y;
+ vc.Wxyz[0] = x/y * vc.Wxyz[1];
+ vc.Wxyz[2] = z/y * vc.Wxyz[1];
+ }
+ if (vc_a >= 0.0)
+ vc.La = vc_a;
+ if (vc_b >= 0.0)
+ vc.Yb = vc_b/100.0;
+ if (vc_l >= 0.0)
+ vc.Lv = vc_l;
+ if (vc_f >= 0.0)
+ vc.Yf = vc_f/100.0;
+ if (vc_fXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Fxyz[0] = vc_fXYZ[0]/vc_fXYZ[1] * vc.Fxyz[1];
+ vc.Fxyz[2] = vc_fXYZ[2]/vc_fXYZ[1] * vc.Fxyz[1];
+ }
+ if (vc_fxy[0] >= 0.0) {
+ double x = vc_fxy[0];
+ double y = vc_fxy[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];
+ }
+
+ fl |= ICX_CLIP_NEAREST; /* Don't setup rev uncessarily */
+
+#ifdef USE_CAM_CLIP_OPT
+ fl |= ICX_CAM_CLIP;
+#endif
+
+#ifdef NEVER
+ printf("~1 output space flags = 0x%x\n",fl);
+ printf("~1 output space intent = %s\n",icx2str(icmRenderingIntent,intent));
+ printf("~1 output space pcs = %s\n",icx2str(icmColorSpaceSignature,pcsor));
+ printf("~1 output space viewing conditions =\n"); xicc_dump_viewcond(&vc);
+ printf("~1 output space inking =\n"); xicc_dump_inking(&ink);
+#endif
+
+ strcpy(out_name, prof_name);
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+
+ strcpy(xl,".gam");
+
+ /* Get a expanded color conversion object */
+ if ((luo = xicco->get_luobj(xicco, fl, func, intent, pcsor, order, &vc, &ink)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ if (special) {
+ if (func != icmFwd)
+ error("Must be forward direction for special plot");
+ strcpy(xl,".wrl");
+ diag_gamut(luo, gamres, doaxes, tlimit/100.0, klimit/100.0, out_name);
+ } else {
+ /* Creat a gamut surface */
+ if ((gam = luo->get_gamut(luo, gamres)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ if (gam->write_gam(gam,out_name))
+ error ("write gamut failed on '%s'",out_name);
+
+ if (vrml) {
+ strcpy(xl,".wrl");
+ if (gam->write_vrml(gam,out_name, doaxes, docusps))
+ error ("write vrml failed on '%s'",out_name);
+ }
+
+ if (verb) {
+ printf("Total volume of gamut is %f cubic colorspace units\n",gam->volume(gam));
+ }
+ gam->del(gam);
+ }
+
+ luo->del(luo); /* Done with lookup object */
+
+ xicco->del(xicco); /* Expansion wrapper */
+ icco->del(icco); /* Icc */
+ fp->del(fp);
+
+
+ return 0;
+}
+
+/* -------------------------------------------- */
+/* Code for special gamut surface plot */
+
+#define GAMUT_LCENT 50
+
+/* Create a diagnostic gamut, illustrating */
+/* device space "fold-over" */
+static void diag_gamut(
+icxLuBase *p, /* Lookup object */
+double detail, /* Gamut resolution detail */
+int doaxes, /* Do Lab axes */
+double tlimit, /* Total ink limit */
+double klimit, /* K ink limit */
+char *outname /* Output VRML file */
+) {
+ int i, j;
+ FILE *wrl;
+ struct {
+ double x, y, z;
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+ int vix; /* Vertex index */
+ DCOUNT(coa, MXDI, p->inputChan, 0, 0, 2);
+
+ double col[1 << MXDI][3]; /* Color asigned to each major vertex */
+ int res;
+
+ if (tlimit < 0.0)
+ tlimit = p->inputChan;
+ if (klimit < 0.0)
+ klimit = 1.0;
+
+ /* Asign some colors to the combination nodes */
+ for (i = 0; i < (1 << p->inputChan); i++) {
+ int a, b, c, j;
+ double h;
+
+ j = (i ^ 0x5a5a5a5a) % (1 << p->inputChan);
+ h = (double)j/((1 << p->inputChan)-1);
+
+ /* Make fully saturated with chosen hue */
+ if (h < 1.0/3.0) {
+ a = 0;
+ b = 1;
+ c = 2;
+ } else if (h < 2.0/3.0) {
+ a = 1;
+ b = 2;
+ c = 0;
+ h -= 1.0/3.0;
+ } else {
+ a = 2;
+ b = 0;
+ c = 1;
+ h -= 2.0/3.0;
+ }
+ h *= 3.0;
+
+ col[i][a] = (1.0 - h);
+ col[i][b] = h;
+ col[i][c] = d_rand(0.0, 1.0);
+ }
+
+ if (detail > 0.0)
+ res = (int)(100.0/detail); /* Establish an appropriate sampling density */
+ else
+ res = 4;
+
+ if (res < 2)
+ res = 2;
+
+ if ((wrl = fopen(outname,"w")) == NULL)
+ error("Error opening wrl output file '%s'",outname);
+
+ /* Spit out a VRML 2 Object surface of gamut */
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ fprintf(wrl,"# Lab axes as boxes:\n");
+ for (i = 0; i < 5; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape{\n");
+ fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
+ axes[i].wx, axes[i].wy, axes[i].wz);
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"\n");
+ }
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation 0 0 0\n");
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry IndexedFaceSet {\n");
+ fprintf(wrl," solid FALSE\n"); /* Don't back face cull */
+ fprintf(wrl," convex TRUE\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [ # Verticy coordinates\n");
+
+
+ /* Itterate over all the faces in the device space */
+ /* generating the vertx positions. */
+ DC_INIT(coa);
+ vix = 0;
+ while(!DC_DONE(coa)) {
+ int e, m1, m2;
+ double in[MXDI];
+ double inl[MXDI];
+ double out[3];
+ double sum;
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < p->inputChan; m1++) {
+ if (coa[m1] != 0)
+ continue;
+
+ for (m2 = m1 + 1; m2 < p->inputChan; m2++) {
+ int x, y;
+
+ if (coa[m2] != 0)
+ continue;
+
+ for (e = 0; e < p->inputChan; e++)
+ in[e] = (double)coa[e]; /* Base value */
+
+ /* Scan over 2D device space face */
+ for (x = 0; x < res; x++) { /* step over surface */
+ in[m1] = x/(res - 1.0);
+ for (y = 0; y < res; y++) {
+ in[m2] = y/(res - 1.0);
+
+ for (sum = 0.0, e = 0; e < p->inputChan; e++) {
+ sum += inl[e] = in[e];
+ }
+ if (sum >= tlimit) {
+ for (e = 0; e < p->inputChan; e++)
+ inl[e] *= tlimit/sum;
+ }
+ if (p->inputChan >= 3 && inl[3] >= klimit)
+ inl[3] = klimit;
+ p->lookup(p, out, inl);
+ fprintf(wrl,"%f %f %f,\n",out[1], out[2], out[0]-50.0);
+ vix++;
+ }
+ }
+ }
+ }
+ /* Increment index within block */
+ DC_INC(coa);
+ }
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coordIndex [ # Indexes of poligon Verticies \n");
+
+ /* Itterate over all the faces in the device space */
+ /* generating the quadrilateral indexes. */
+ DC_INIT(coa);
+ vix = 0;
+ while(!DC_DONE(coa)) {
+ int e, m1, m2;
+ double in[MXDI];
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < p->inputChan; m1++) {
+ if (coa[m1] != 0)
+ continue;
+
+ for (m2 = m1 + 1; m2 < p->inputChan; m2++) {
+ int x, y;
+
+ if (coa[m2] != 0)
+ continue;
+
+ for (e = 0; e < p->inputChan; e++)
+ in[e] = (double)coa[e]; /* Base value */
+
+ /* Scan over 2D device space face */
+ /* Only output quads under the total ink limit */
+ /* Scan over 2D device space face */
+ for (x = 0; x < res; x++) { /* step over surface */
+ for (y = 0; y < res; y++) {
+ if (x < (res-1) && y < (res-1)) {
+ fprintf(wrl,"%d, %d, %d, %d, -1\n",
+ vix, vix + 1, vix + 1 + res, vix + res);
+ }
+ vix++;
+ }
+ }
+ }
+ }
+ /* Increment index within block */
+ DC_INC(coa);
+ }
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ /* Itterate over all the faces in the device space */
+ /* generating the vertx colors. */
+ DC_INIT(coa);
+ vix = 0;
+ while(!DC_DONE(coa)) {
+ int e, m1, m2;
+ double in[MXDI];
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < p->inputChan; m1++) {
+ if (coa[m1] != 0)
+ continue;
+
+ for (m2 = m1 + 1; m2 < p->inputChan; m2++) {
+ int x, y;
+
+ if (coa[m2] != 0)
+ continue;
+
+ for (e = 0; e < p->inputChan; e++)
+ in[e] = (double)coa[e]; /* Base value */
+
+ /* Scan over 2D device space face */
+ for (x = 0; x < res; x++) { /* step over surface */
+ double xb = x/(res - 1.0);
+ for (y = 0; y < res; y++) {
+ int v0, v1, v2, v3;
+ double yb = y/(res - 1.0);
+ double rgb[3];
+
+ for (v0 = 0, e = 0; e < p->inputChan; e++)
+ v0 |= coa[e] ? (1 << e) : 0; /* Binary index */
+
+ v1 = v0 | (1 << m2); /* Y offset */
+ v2 = v0 | (1 << m2) | (1 << m1); /* X+Y offset */
+ v3 = v0 | (1 << m1); /* Y offset */
+
+ /* Linear interp between the main verticies */
+ for (j = 0; j < 3; j++) {
+ rgb[j] = (1.0 - yb) * (1.0 - xb) * col[v0][j]
+ + yb * (1.0 - xb) * col[v1][j]
+ + (1.0 - yb) * xb * col[v3][j]
+ + yb * xb * col[v2][j];
+ }
+ fprintf(wrl,"%f %f %f,\n",rgb[1], rgb[2], rgb[0]);
+ vix++;
+ }
+ }
+ }
+ }
+ /* Increment index within block */
+ DC_INC(coa);
+ }
+
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," appearance Appearance { \n");
+ fprintf(wrl," material Material {\n");
+ fprintf(wrl," transparency 0.0\n");
+ fprintf(wrl," ambientIntensity 0.3\n");
+ fprintf(wrl," shininess 0.5\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," } # end Shape\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0)
+ error("Error closing output file '%s'",outname);
+}
+
diff --git a/xicc/iccjpeg.c b/xicc/iccjpeg.c
new file mode 100644
index 0000000..13d4e25
--- /dev/null
+++ b/xicc/iccjpeg.c
@@ -0,0 +1,271 @@
+
+/*
+
+Little CMS
+Copyright (c) 1998-2010 Marti Maria Saguer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and as
+sociated documentation files (the "Software"), to deal in the Software without restriction, includin
+g without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subj
+ect to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial
+ portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NO
+T LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABI
+LITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WIT
+H THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+/*
+ * iccjpeg.c
+ *
+ * This file provides code to read and write International Color Consortium
+ * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has
+ * defined a standard format for including such data in JPEG "APP2" markers.
+ * The code given here does not know anything about the internal structure
+ * of the ICC profile data; it just knows how to put the profile data into
+ * a JPEG file being written, or get it back out when reading.
+ *
+ * This code depends on new features added to the IJG JPEG library as of
+ * IJG release 6b; it will not compile or work with older IJG versions.
+ *
+ * NOTE: this code would need surgery to work on 16-bit-int machines
+ * with ICC profiles exceeding 64K bytes in size. If you need to do that,
+ * change all the "unsigned int" variables to "INT32". You'll also need
+ * to find a malloc() replacement that can allocate more than 64K.
+ */
+
+#include "iccjpeg.h"
+#include <stdlib.h> /* define malloc() */
+
+
+/*
+ * Since an ICC profile can be larger than the maximum size of a JPEG marker
+ * (64K), we need provisions to split it into multiple markers. The format
+ * defined by the ICC specifies one or more APP2 markers containing the
+ * following data:
+ * Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
+ * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte)
+ * Number of markers Total number of APP2's used (1 byte)
+ * Profile data (remainder of APP2 data)
+ * Decoders should use the marker sequence numbers to reassemble the profile,
+ * rather than assuming that the APP2 markers appear in the correct sequence.
+ */
+
+#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
+#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
+#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
+#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
+
+
+/*
+ * This routine writes the given ICC profile data into a JPEG file.
+ * It *must* be called AFTER calling jpeg_start_compress() and BEFORE
+ * the first call to jpeg_write_scanlines().
+ * (This ordering ensures that the APP2 marker(s) will appear after the
+ * SOI and JFIF or Adobe markers, but before all else.)
+ */
+
+void
+write_icc_profile (j_compress_ptr cinfo,
+ const JOCTET *icc_data_ptr,
+ unsigned int icc_data_len)
+{
+ unsigned int num_markers; /* total number of markers we'll write */
+ int cur_marker = 1; /* per spec, counting starts at 1 */
+ unsigned int length; /* number of bytes to write in this marker */
+
+ /* Calculate the number of markers we'll need, rounding up of course */
+ num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER;
+ if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len)
+ num_markers++;
+
+ while (icc_data_len > 0) {
+ /* length of profile to put in this marker */
+ length = icc_data_len;
+ if (length > MAX_DATA_BYTES_IN_MARKER)
+ length = MAX_DATA_BYTES_IN_MARKER;
+ icc_data_len -= length;
+
+ /* Write the JPEG marker header (APP2 code and marker length) */
+ jpeg_write_m_header(cinfo, ICC_MARKER,
+ (unsigned int) (length + ICC_OVERHEAD_LEN));
+
+ /* Write the marker identifying string "ICC_PROFILE" (null-terminated).
+ * We code it in this less-than-transparent way so that the code works
+ * even if the local character set is not ASCII.
+ */
+ jpeg_write_m_byte(cinfo, 0x49);
+ jpeg_write_m_byte(cinfo, 0x43);
+ jpeg_write_m_byte(cinfo, 0x43);
+ jpeg_write_m_byte(cinfo, 0x5F);
+ jpeg_write_m_byte(cinfo, 0x50);
+ jpeg_write_m_byte(cinfo, 0x52);
+ jpeg_write_m_byte(cinfo, 0x4F);
+ jpeg_write_m_byte(cinfo, 0x46);
+ jpeg_write_m_byte(cinfo, 0x49);
+ jpeg_write_m_byte(cinfo, 0x4C);
+ jpeg_write_m_byte(cinfo, 0x45);
+ jpeg_write_m_byte(cinfo, 0x0);
+
+ /* Add the sequencing info */
+ jpeg_write_m_byte(cinfo, cur_marker);
+ jpeg_write_m_byte(cinfo, (int) num_markers);
+
+ /* Add the profile data */
+ while (length--) {
+ jpeg_write_m_byte(cinfo, *icc_data_ptr);
+ icc_data_ptr++;
+ }
+ cur_marker++;
+ }
+}
+
+
+/*
+ * Prepare for reading an ICC profile
+ */
+
+void
+setup_read_icc_profile (j_decompress_ptr cinfo)
+{
+ /* Tell the library to keep any APP2 data it may find */
+ jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF);
+}
+
+
+/*
+ * Handy subroutine to test whether a saved marker is an ICC profile marker.
+ */
+
+static boolean
+marker_is_icc (jpeg_saved_marker_ptr marker)
+{
+ return
+ marker->marker == ICC_MARKER &&
+ marker->data_length >= ICC_OVERHEAD_LEN &&
+ /* verify the identifying string */
+ GETJOCTET(marker->data[0]) == 0x49 &&
+ GETJOCTET(marker->data[1]) == 0x43 &&
+ GETJOCTET(marker->data[2]) == 0x43 &&
+ GETJOCTET(marker->data[3]) == 0x5F &&
+ GETJOCTET(marker->data[4]) == 0x50 &&
+ GETJOCTET(marker->data[5]) == 0x52 &&
+ GETJOCTET(marker->data[6]) == 0x4F &&
+ GETJOCTET(marker->data[7]) == 0x46 &&
+ GETJOCTET(marker->data[8]) == 0x49 &&
+ GETJOCTET(marker->data[9]) == 0x4C &&
+ GETJOCTET(marker->data[10]) == 0x45 &&
+ GETJOCTET(marker->data[11]) == 0x0;
+}
+
+
+/*
+ * See if there was an ICC profile in the JPEG file being read;
+ * if so, reassemble and return the profile data.
+ *
+ * TRUE is returned if an ICC profile was found, FALSE if not.
+ * If TRUE is returned, *icc_data_ptr is set to point to the
+ * returned data, and *icc_data_len is set to its length.
+ *
+ * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
+ * and must be freed by the caller with free() when the caller no longer
+ * needs it. (Alternatively, we could write this routine to use the
+ * IJG library's memory allocator, so that the data would be freed implicitly
+ * at jpeg_finish_decompress() time. But it seems likely that many apps
+ * will prefer to have the data stick around after decompression finishes.)
+ *
+ * NOTE: if the file contains invalid ICC APP2 markers, we just silently
+ * return FALSE. You might want to issue an error message instead.
+ */
+
+boolean
+read_icc_profile (j_decompress_ptr cinfo,
+ JOCTET **icc_data_ptr,
+ unsigned int *icc_data_len)
+{
+ jpeg_saved_marker_ptr marker;
+ int num_markers = 0;
+ int seq_no;
+ JOCTET *icc_data;
+ unsigned int total_length;
+#define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */
+ char marker_present[MAX_SEQ_NO+1]; /* 1 if marker found */
+ unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
+ unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
+
+ *icc_data_ptr = NULL; /* avoid confusion if FALSE return */
+ *icc_data_len = 0;
+
+ /* This first pass over the saved markers discovers whether there are
+ * any ICC markers and verifies the consistency of the marker numbering.
+ */
+
+ for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
+ marker_present[seq_no] = 0;
+
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker_is_icc(marker)) {
+ if (num_markers == 0)
+ num_markers = GETJOCTET(marker->data[13]);
+ else if (num_markers != GETJOCTET(marker->data[13]))
+ return FALSE; /* inconsistent num_markers fields */
+ seq_no = GETJOCTET(marker->data[12]);
+ if (seq_no <= 0 || seq_no > num_markers)
+ return FALSE; /* bogus sequence number */
+ if (marker_present[seq_no])
+ return FALSE; /* duplicate sequence numbers */
+ marker_present[seq_no] = 1;
+ data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
+ }
+ }
+
+ if (num_markers == 0)
+ return FALSE;
+
+ /* Check for missing markers, count total space needed,
+ * compute offset of each marker's part of the data.
+ */
+
+ total_length = 0;
+ for (seq_no = 1; seq_no <= num_markers; seq_no++) {
+ if (marker_present[seq_no] == 0)
+ return FALSE; /* missing sequence number */
+ data_offset[seq_no] = total_length;
+ total_length += data_length[seq_no];
+ }
+
+ if (total_length <= 0)
+ return FALSE; /* found only empty markers? */
+
+ /* Allocate space for assembled data */
+ icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
+ if (icc_data == NULL)
+ return FALSE; /* oops, out of memory */
+
+ /* and fill it in */
+ for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) {
+ if (marker_is_icc(marker)) {
+ JOCTET FAR *src_ptr;
+ JOCTET *dst_ptr;
+ unsigned int length;
+ seq_no = GETJOCTET(marker->data[12]);
+ dst_ptr = icc_data + data_offset[seq_no];
+ src_ptr = marker->data + ICC_OVERHEAD_LEN;
+ length = data_length[seq_no];
+ while (length--) {
+ *dst_ptr++ = *src_ptr++;
+ }
+ }
+ }
+
+ *icc_data_ptr = icc_data;
+ *icc_data_len = total_length;
+
+ return TRUE;
+}
diff --git a/xicc/iccjpeg.h b/xicc/iccjpeg.h
new file mode 100644
index 0000000..5e1888d
--- /dev/null
+++ b/xicc/iccjpeg.h
@@ -0,0 +1,73 @@
+/*
+ * iccprofile.h
+ *
+ * This file provides code to read and write International Color Consortium
+ * (ICC) device profiles embedded in JFIF JPEG image files. The ICC has
+ * defined a standard format for including such data in JPEG "APP2" markers.
+ * The code given here does not know anything about the internal structure
+ * of the ICC profile data; it just knows how to put the profile data into
+ * a JPEG file being written, or get it back out when reading.
+ *
+ * This code depends on new features added to the IJG JPEG library as of
+ * IJG release 6b; it will not compile or work with older IJG versions.
+ *
+ * NOTE: this code would need surgery to work on 16-bit-int machines
+ * with ICC profiles exceeding 64K bytes in size. See iccprofile.c
+ * for details.
+ */
+
+#include <stdio.h> /* needed to define "FILE", "NULL" */
+#include "jpeglib.h"
+
+
+/*
+ * This routine writes the given ICC profile data into a JPEG file.
+ * It *must* be called AFTER calling jpeg_start_compress() and BEFORE
+ * the first call to jpeg_write_scanlines().
+ * (This ordering ensures that the APP2 marker(s) will appear after the
+ * SOI and JFIF or Adobe markers, but before all else.)
+ */
+
+extern void write_icc_profile JPP((j_compress_ptr cinfo,
+ const JOCTET *icc_data_ptr,
+ unsigned int icc_data_len));
+
+
+/*
+ * Reading a JPEG file that may contain an ICC profile requires two steps:
+ *
+ * 1. After jpeg_create_decompress() but before jpeg_read_header(),
+ * call setup_read_icc_profile(). This routine tells the IJG library
+ * to save in memory any APP2 markers it may find in the file.
+ *
+ * 2. After jpeg_read_header(), call read_icc_profile() to find out
+ * whether there was a profile and obtain it if so.
+ */
+
+
+/*
+ * Prepare for reading an ICC profile
+ */
+
+extern void setup_read_icc_profile JPP((j_decompress_ptr cinfo));
+
+
+/*
+ * See if there was an ICC profile in the JPEG file being read;
+ * if so, reassemble and return the profile data.
+ *
+ * TRUE is returned if an ICC profile was found, FALSE if not.
+ * If TRUE is returned, *icc_data_ptr is set to point to the
+ * returned data, and *icc_data_len is set to its length.
+ *
+ * IMPORTANT: the data at **icc_data_ptr has been allocated with malloc()
+ * and must be freed by the caller with free() when the caller no longer
+ * needs it. (Alternatively, we could write this routine to use the
+ * IJG library's memory allocator, so that the data would be freed implicitly
+ * at jpeg_finish_decompress() time. But it seems likely that many apps
+ * will prefer to have the data stick around after decompression finishes.)
+ */
+
+extern boolean read_icc_profile JPP((j_decompress_ptr cinfo,
+ JOCTET **icc_data_ptr,
+ unsigned int *icc_data_len));
diff --git a/xicc/icheck.c b/xicc/icheck.c
new file mode 100644
index 0000000..ed3c6e5
--- /dev/null
+++ b/xicc/icheck.c
@@ -0,0 +1,532 @@
+
+/*
+ * Argyll.
+ *
+ * Check for B2A table PCS->Device interpolation faults
+ *
+ * Author: Graeme W. Gill
+ * Date: 2000/12/11
+ * Version: 1.00
+ *
+ * Copyright 2000 Graeme W. Gill
+ * Please refer to License.txt file for details.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "numlib.h"
+#include "copyright.h"
+#include "aconfig.h"
+#include "icc.h"
+
+void usage(void) {
+ fprintf(stderr,"Check PCS->Device Interpolation faults of ICC file, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: icheck [-v] [-w] infile\n");
+ fprintf(stderr," -v verbose\n");
+ fprintf(stderr," -w create VRML visualisation\n");
+ fprintf(stderr," -x Use VRML axies\n");
+ exit(1);
+}
+
+FILE *start_vrml(char *name, int doaxes);
+void start_line_set(FILE *wrl);
+void add_vertex(FILE *wrl, double pp[3]);
+void make_lines(FILE *wrl, int ppset);
+void end_vrml(FILE *wrl);
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int dovrml = 0;
+ int doaxes = 0;
+ char in_name[100];
+ char out_name[100], *xl;
+ icmFile *rd_fp;
+ icc *rd_icco;
+ int rv = 0;
+
+ /* Check variables */
+ icmLuBase *luof, *luob; /* A2B and B2A table lookups */
+ icmLuLut *lluof, *lluob; /* Lookup Lut type object */
+ int gres; /* Grid resolution of B2A */
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int inn; /* Number of input chanels */
+ icmLuAlgType alg;
+ FILE *wrl = NULL;
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ /* VRML */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ dovrml = 1;
+ }
+ /* Axes */
+ else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ doaxes = 1;
+ }
+ else if (argv[fa][1] == '?')
+ usage();
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa]);
+
+ strcpy(out_name, in_name);
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".wrl");
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Get a Device to PCS conversion object */
+ if ((luof = rd_icco->get_luobj(rd_icco, icmFwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((luof = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ /* Get a PCS to Device conversion object */
+ if ((luob = rd_icco->get_luobj(rd_icco, icmBwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((luob = rd_icco->get_luobj(rd_icco, icmBwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ /* Get details of conversion (for B2A direction) */
+ luob->spaces(luob, &outs, NULL, &ins, &inn, &alg, NULL, NULL, NULL, NULL);
+
+ if (alg != icmLutType) {
+ error("Expecting Lut based profile");
+ }
+
+ if (outs != icSigLabData) {
+ error("Expecting Lab PCS");
+ }
+
+ lluof = (icmLuLut *)luof; /* Lookup Lut type object */
+ lluob = (icmLuLut *)luob; /* Lookup Lut type object */
+
+ gres = lluob->lut->clutPoints;
+
+ if (dovrml) {
+ wrl = start_vrml(out_name, doaxes);
+ start_line_set(wrl);
+ }
+
+ {
+ double aerr = 0.0;
+ double ccount = 0.0;
+ double merr = 0.0;
+ double tcount = 0.0;
+ int co[3]; /* PCS grid counter */
+
+ /* Itterate throught the PCS clut grid cells */
+ for (co[2] = 0; co[2] < (gres-1); co[2]++) {
+ for (co[1] = 0; co[1] < (gres-1); co[1]++) {
+ for (co[0] = 0; co[0] < (gres-1); co[0]++) {
+ int j, k, m;
+ int cc[3]; /* Cube corner offsets */
+ double pcs[8][3], wpcsd;
+ double apcs[3];
+ double adev[MAX_CHAN];
+ double check[3]; /* Check PCS */
+ double ier; /* Interpolation error */
+
+ apcs[0] = apcs[1] = apcs[2] = 0.0;
+ for (k = 0; k < inn; k++)
+ adev[k] = 0.0;
+
+ /* For each corner of the PCS grid based at the current point, */
+ /* average the PCS and Device values */
+ m = 0;
+ for (cc[2] = 0; cc[2] < 2; cc[2]++, m++) {
+ for (cc[1] = 0; cc[1] < 2; cc[1]++) {
+ for (cc[0] = 0; cc[0] < 2; cc[0]++) {
+ double dev[MAX_CHAN];
+
+ pcs[m][0] = (co[0] + cc[0])/(gres - 1.0);
+ pcs[m][1] = (co[1] + cc[1])/(gres - 1.0);
+ pcs[m][2] = (co[2] + cc[2])/(gres - 1.0);
+
+ /* Match icclib settable() range */
+ pcs[m][0] = pcs[m][0] * 100.0;
+ pcs[m][1] = (pcs[m][1] * 254.0) - 127.0;
+ pcs[m][2] = (pcs[m][2] * 254.0) - 127.0;
+
+//printf("Input PCS %f %f %f\n", pcs[m][0], pcs[m][1], pcs[m][2]);
+
+ /* PCS to (cliped) Device */
+ if ((rv = lluob->clut(lluob, dev, pcs[m])) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* (clipped) Device to (clipped) PCS */
+ if ((rv = lluof->clut(lluof, pcs[m], dev)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ apcs[0] += pcs[m][0];
+ apcs[1] += pcs[m][1];
+ apcs[2] += pcs[m][2];
+
+//printf("Corner PCS %f %f %f -> %f %f %f %f\n",
+//pcs[m][0], pcs[m][1], pcs[m][2], dev[0], dev[1], dev[2], dev[3]);
+
+ for (k = 0; k < inn; k++)
+ adev[k] += dev[k];
+ }
+ }
+ }
+
+ for (j = 0; j < 3; j++)
+ apcs[j] /= 8.0;
+
+ for (k = 0; k < inn; k++)
+ adev[k] /= 8.0;
+
+ /* Compute worst case distance of PCS corners to average PCS */
+ wpcsd = 0.0;
+ for (m = 0; m < 8; m++) {
+ double ss;
+ for (ss = 0.0, j = 0; j < 3; j++) {
+ double tt = pcs[m][j] - apcs[j];
+ ss += tt * tt;
+ }
+ ss = sqrt(ss);
+ if (ss > wpcsd)
+ wpcsd = ss;
+ }
+ wpcsd *= 0.75; /* Set threshold at 75% of most distant corner */
+ /* Set a worst case */
+ if (wpcsd < 1.0)
+ wpcsd = 1.0;
+
+// else if (wpcsd > 3.0)
+// wpcsd = 3.0;
+
+
+//printf("Average PCS %f %f %f, Average Device %f %f %f %f\n",
+//apcs[0], apcs[1], apcs[2], adev[0], adev[1], adev[2], adev[3]);
+
+ /* Average Device to PCS */
+ if ((rv = lluof->clut(lluof, check, adev)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+//printf("Check PCS %f %f %f\n",
+//check[0], check[1], check[2]);
+
+ /* Compute error in PCS vs. Device interpolation */
+ for (ier = 0.0, j = 0; j < 3; j++) {
+ double tt = apcs[j] - check[j];
+ ier += tt * tt;
+ }
+ ier = sqrt(ier);
+
+//printf("Average PCS %f %f %f, Check PCS %f %f %f, error %f\n",
+//apcs[0], apcs[1], apcs[2], check[0], check[1], check[2], ier);
+
+ aerr += ier;
+ ccount++;
+ if (ier > merr)
+ merr = ier;
+
+ if (ier > wpcsd) {
+ tcount++;
+
+ printf("ier = %f, Dev = %f %f %f %f\n",
+ ier, adev[0], adev[1], adev[2], adev[3]);
+ if (dovrml) {
+ add_vertex(wrl, apcs);
+ add_vertex(wrl, check);
+ }
+ }
+
+//printf("~1 ier = %f\n",ier);
+//printf("\n");
+
+
+ if (verb)
+ printf("."), fflush(stdout);
+ }
+ }
+ }
+
+ if (dovrml) {
+ make_lines(wrl, 2);
+ end_vrml(wrl);
+ }
+
+ aerr /= ccount;
+
+ printf("Average interpolation error %f, maximum %f\n",aerr, merr);
+ printf("Number outside corner radius = %f%%\n",tcount * 100.0/ccount);
+ }
+
+ /* Done with lookup objects */
+ luof->del(luof);
+ luob->del(luob);
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ return 0;
+}
+
+/* ------------------------------------------------ */
+/* Some simple functions to do basix VRML work */
+
+#define GAMUT_LCENT 50.0
+static int npoints = 0;
+static int paloc = 0;
+static struct { double pp[3]; } *pary;
+
+static void Lab2RGB(double *out, double *in);
+
+FILE *start_vrml(char *name, int doaxes) {
+ FILE *wrl;
+ struct {
+ double x, y, z;
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+ int i;
+
+ if ((wrl = fopen(name,"w")) == NULL)
+ error("Error opening VRML file '%s'\n",name);
+
+ npoints = 0;
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ fprintf(wrl,"# Lab axes as boxes:\n");
+ for (i = 0; i < 5; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape{\n");
+ fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
+ axes[i].wx, axes[i].wy, axes[i].wz);
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"\n");
+ }
+
+ return wrl;
+}
+
+void
+start_line_set(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+}
+
+void add_vertex(FILE *wrl, double pp[3]) {
+
+ fprintf(wrl,"%f %f %f,\n",pp[1], pp[2], pp[0]-GAMUT_LCENT);
+
+ if (paloc < (npoints+1)) {
+ paloc = (paloc + 10) * 2;
+ if (pary == NULL)
+ pary = malloc(paloc * 3 * sizeof(double));
+ else
+ pary = realloc(pary, paloc * 3 * sizeof(double));
+
+ if (pary == NULL)
+ error ("Malloc failed");
+ }
+ pary[npoints].pp[0] = pp[0];
+ pary[npoints].pp[1] = pp[1];
+ pary[npoints].pp[2] = pp[2];
+ npoints++;
+}
+
+
+void make_lines(FILE *wrl, int ppset) {
+ int i, j;
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (i = 0; i < npoints;) {
+ for (j = 0; j < ppset; j++, i++) {
+ fprintf(wrl,"%d, ", i);
+ }
+ fprintf(wrl,"-1,\n");
+ }
+ fprintf(wrl," ]\n");
+
+ /* Color */
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ for (i = 0; i < npoints; i++) {
+ double rgb[3], Lab[3];
+ Lab[0] = pary[i].pp[0];
+ Lab[1] = pary[i].pp[1];
+ Lab[2] = pary[i].pp[2];
+ Lab2RGB(rgb, Lab);
+ fprintf(wrl," %f %f %f,\n", rgb[0], rgb[1], rgb[2]);
+ }
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ /* End color */
+
+ fprintf(wrl," }\n");
+ fprintf(wrl,"} # end shape\n");
+
+}
+
+void end_vrml(FILE *wrl) {
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0)
+ error("Error closing VRML file\n");
+}
+
+
+/* Convert a gamut Lab value to an RGB value for display purposes */
+static void
+Lab2RGB(double *out, double *in) {
+ double L = in[0], a = in[1], b = in[2];
+ double x,y,z,fx,fy,fz;
+ double R, G, B;
+
+ /* Scale so that black is visible */
+ L = L * (100 - 40.0)/100.0 + 40.0;
+
+ /* First convert to XYZ using D50 white point */
+ if (L > 8.0) {
+ fy = (L + 16.0)/116.0;
+ y = pow(fy,3.0);
+ } else {
+ y = L/903.2963058;
+ fy = 7.787036979 * y + 16.0/116.0;
+ }
+
+ fx = a/500.0 + fy;
+ if (fx > 24.0/116.0)
+ x = pow(fx,3.0);
+ else
+ x = (fx - 16.0/116.0)/7.787036979;
+
+ fz = fy - b/200.0;
+ if (fz > 24.0/116.0)
+ z = pow(fz,3.0);
+ else
+ z = (fz - 16.0/116.0)/7.787036979;
+
+ x *= 0.9642; /* Multiply by white point, D50 */
+ y *= 1.0;
+ z *= 0.8249;
+
+ /* Now convert to sRGB values */
+ R = x * 3.2410 + y * -1.5374 + z * -0.4986;
+ G = x * -0.9692 + y * 1.8760 + z * 0.0416;
+ B = x * 0.0556 + y * -0.2040 + z * 1.0570;
+
+ if (R < 0.0)
+ R = 0.0;
+ else if (R > 1.0)
+ R = 1.0;
+
+ if (G < 0.0)
+ G = 0.0;
+ else if (G > 1.0)
+ G = 1.0;
+
+ if (B < 0.0)
+ B = 0.0;
+ else if (B > 1.0)
+ B = 1.0;
+
+ R = pow(R, 1.0/2.2);
+ G = pow(G, 1.0/2.2);
+ B = pow(B, 1.0/2.2);
+
+ out[0] = R;
+ out[1] = G;
+ out[2] = B;
+}
+
diff --git a/xicc/monctest.c b/xicc/monctest.c
new file mode 100644
index 0000000..29c9298
--- /dev/null
+++ b/xicc/monctest.c
@@ -0,0 +1,278 @@
+
+/*
+ * Author: Graeme Gill
+ * Date: 30/10/2005
+ *
+ * Copyright 2005 Graeme W. Gill
+ * Parts derived from rspl/c1.c, cv.c etc.
+ *
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ *
+ * Test monocurve class.
+ *
+ */
+
+#undef DIAG
+#undef TEST_SYM
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "plot.h"
+#include "moncurve.h"
+
+double lin(double x, double xa[], double ya[], int n);
+void usage(void);
+
+#define TRIALS 30 /* Number of random trials */
+#define SKIP 0 /* Number of random trials to skip */
+#undef NORMONLY /* Defined to use 0.0 - 1.0 limited curve */
+
+#undef ORDER_STEP /* Step orders from 2 to SHAPE_ORDERS */
+#define SHAPE_ORDS 30 /* Number of order to use */
+
+#define ABS_MAX_PNTS 100
+
+#define MIN_PNTS 2
+#define MAX_PNTS 20
+
+#define MIN_RES 20
+#define MAX_RES 500
+
+double xa[ABS_MAX_PNTS];
+double ya[ABS_MAX_PNTS];
+
+#define XRES 100
+
+#define TSETS 3
+#define PNTS 11
+#define GRES 100
+int t1p[TSETS] = {
+ 4,
+ 11,
+ 11
+};
+
+double t1xa[TSETS][PNTS] = {
+ { 0.0, 0.2, 0.8, 1.0 },
+ { 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0 },
+ { 0.0, 0.25, 0.30, 0.35, 0.40, 0.44, 0.48, 0.51, 0.64, 0.75, 1.0 }
+};
+
+double t1ya[TSETS][PNTS] = {
+ { 0.0, 0.5, 0.6, 1.0 },
+ { 0.0, 0.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.8, 1.0, 1.0, 1.0 },
+ { 0.0, 0.35, 0.4, 0.41, 0.42, 0.46, 0.5, 0.575, 0.48, 0.75, 1.0 }
+};
+
+
+mcvco test_points[ABS_MAX_PNTS];
+
+double lin(double x, double xa[], double ya[], int n);
+
+void
+usage(void) {
+ puts("usage: monctest");
+ exit(1);
+}
+
+int main() {
+ mcv *p;
+ int i, n;
+ double x, y;
+ double xx[XRES];
+ double y1[XRES];
+ double y2[XRES];
+ int np = SHAPE_ORDS; /* Number of harmonics */
+
+ error_program = "monctest";
+
+#if defined(__IBMC__)
+ _control87(EM_UNDERFLOW, EM_UNDERFLOW);
+ _control87(EM_OVERFLOW, EM_OVERFLOW);
+#endif
+
+#ifdef NORMONLY
+ if ((p = new_mcv_noos()) == NULL)
+#else
+ if ((p = new_mcv()) == NULL)
+#endif
+ error("new_mcv failed");
+
+ for (n = 0; n < TRIALS; n++) {
+ double lrand; /* Amount of level randomness */
+ int pnts;
+
+#ifdef NEVER
+ if (n < TSETS) /* Standard versions */ {
+ pnts = t1p[n];
+ for (i = 0; i < pnts; i++) {
+ xa[i] = t1xa[n][i];
+ ya[i] = t1ya[n][i];
+ }
+ } else if (n == TSETS) { /* Exponential function aproximation */
+ double ex = 2.4;
+ pnts = MAX_PNTS;
+
+ printf("Trial %d, no points = %d, exponential %f\n",n,pnts,ex);
+
+ /* Create X values */
+ for (i = 0; i < pnts; i++)
+ xa[i] = i/(pnts-1.0);
+
+ for (i = 0; i < pnts; i++)
+ ya[i] = pow(xa[i], ex);
+
+#else /* Put exponenial first */
+ if (n == 0) { /* Exponential function aproximation */
+ double ex = 2.4;
+ pnts = MAX_PNTS;
+
+ printf("Trial %d, no points = %d, exponential %f\n",n,pnts,ex);
+
+ /* Create X values */
+ for (i = 0; i < pnts; i++)
+ xa[i] = i/(pnts-1.0);
+
+ for (i = 0; i < pnts; i++)
+ ya[i] = pow(xa[i], ex);
+
+ } else if (n < (TSETS+1)) /* Standard versions */ {
+ pnts = t1p[n-1];
+ for (i = 0; i < pnts; i++) {
+ xa[i] = t1xa[n-1][i];
+ ya[i] = t1ya[n-1][i];
+ }
+#endif
+
+ } else { /* Random versions */
+ double ymax;
+ lrand = d_rand(0.0,0.2); /* Amount of level randomness */
+ lrand *= lrand;
+ pnts = i_rand(MIN_PNTS,MAX_PNTS);
+
+ printf("Trial %d, no points = %d, level randomness = %f\n",n,pnts,lrand);
+
+ /* Create X values */
+ xa[0] = 0.0;
+ for (i = 1; i < pnts; i++)
+ xa[i] = xa[i-1] + d_rand(0.5,1.0);
+ for (i = 0; i < pnts; i++) /* Divide out */
+ xa[i] = (xa[i]/xa[pnts-1]);
+
+ /* Create y values */
+ ya[0] = xa[0] + d_rand(-0.1, 0.5);
+ for (i = 1; i < pnts; i++)
+ ya[i] = ya[i-1] + d_rand(0.1,1.0) + d_rand(-0.1,0.4) + d_rand(-0.4,0.5);
+
+ ymax = d_rand(0.6, 10.2); /* Scale target */
+ for (i = 0; i < pnts; i++) {
+ ya[i] = ymax * (ya[i]/ya[pnts-1]);
+// if (ya[i] < 0.0)
+// ya[i] = 0.0;
+// else if (ya[i] > 1.0)
+// ya[i] = 1.0;
+ }
+ }
+
+ if (n < SKIP)
+ continue;
+
+ for (i = 0; i < pnts; i++) {
+ test_points[i].p = xa[i];
+ test_points[i].v = ya[i];
+ test_points[i].w = 1.0;
+ }
+ /* Test weighting */
+ test_points[pnts-1].w = 1.0;
+
+#ifdef ORDER_STEP
+ for (np = 2; np <= SHAPE_ORDS; np++) {
+#else /* Full number of orders */
+ for (np = SHAPE_ORDS; np <= SHAPE_ORDS; np++) {
+#endif
+
+ /* Fit to scattered data */
+ p->fit(p,
+ 1, /* Vebose */
+ np, /* Number of parameters */
+ test_points, /* Test points */
+ pnts, /* Number of test points */
+ 1.0 /* Smoothing */
+ );
+
+ printf("Residual = %f\n",p->resid);
+ printf("Number params = %d\n",np);
+ for (i = 0; i < p->luord; i++) {
+ printf("Param %d = %f\n",i,p->pms[i]);
+ }
+
+ /* Display the result */
+ for (i = 0; i < XRES; i++) {
+ x = i/(double)(XRES-1);
+ xx[i] = x;
+ y1[i] = lin(x,xa,ya,pnts);
+ y2[i] = p->interp(p, x);
+ y = p->inv_interp(p, y2[i]);
+ if (fabs(x - y) > 0.00001)
+ printf("Inverse mismatch: %f -> %f -> %f\n",x,y2[i],y);
+// if (y2[i] < -0.2)
+// y2[i] = -0.2;
+// else if (y2[i] > 1.2)
+// y2[i] = 1.2;
+ }
+ do_plot(xx,y1,y2,NULL,XRES);
+ }
+
+ } /* next trial */
+
+ p->del(p);
+
+ return 0;
+}
+
+double lin(
+double x,
+double xa[],
+double ya[],
+int n) {
+ int i;
+ double y;
+
+ if (x < xa[0])
+ return ya[0];
+ else if (x > xa[n-1])
+ return ya[n-1];
+
+ for (i = 0; i < (n-1); i++)
+ if (x >=xa[i] && x <= xa[i+1])
+ break;
+
+ x = (x - xa[i])/(xa[i+1] - xa[i]);
+
+ y = ya[i] + (ya[i+1] - ya[i]) * x;
+
+ return y;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/moncurve.c b/xicc/moncurve.c
new file mode 100644
index 0000000..b904420
--- /dev/null
+++ b/xicc/moncurve.c
@@ -0,0 +1,668 @@
+
+/*
+ * Argyll Color Correction System
+ * Monotonic curve class for display calibration.
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/10/2005
+ *
+ * Copyright 2005 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.
+ *
+ * This is based on the monotonic curve equations used elsewhere,
+ * but currently intended to support the display calibration process.
+ * moncurve is not currently general, missing:
+ *
+ * input scaling
+ * output scaling
+ */
+
+#undef DEBUG /* Input points */
+#undef DEBUG2 /* Detailed progress */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "moncurve.h"
+
+#define POWTOL 1e-5 /* Powell optimiser tollerance (was 1e-5 ?) */
+#define MAXITS 10000
+
+#undef TEST_PDE /* Ckeck partial derivative calcs */
+
+/* Normalization factors for an average data point error squared, scale 100 */
+#define HW01 0.002 /* 0 & 1 harmonic weights */
+#define HBREAK 4 /* Harmonic that has HWBR */
+#define HWBR 0.8 /* Base weight of harmonics HBREAK up */
+#define HWINC 0.5 /* Increase in weight for each harmonic above HWBR */
+
+static void mcv_del(mcv *p);
+static void mcv_fit(mcv *p, int verb, int order, mcvco *d, int ndp, double smooth);
+static void mcv_force_0(mcv *p, double target);
+static void mcv_force_1(mcv *p, double target);
+static void mcv_force_scale(mcv *p, double target);
+static int mcv_get_params(mcv *p, double **rp);
+static double mcv_interp(struct _mcv *p, double in);
+static double mcv_inv_interp(struct _mcv *p, double in);
+
+static double mcv_interp_p(struct _mcv *p, double *pms, double in);
+static double mcv_shweight_p(mcv *p, double *v, double smooth);
+double mcv_dinterp_p(mcv *p, double *pms, double *dv, double vv);
+static double mcv_dshweight_p(mcv *p, double *v, double *dv, double smooth);
+
+/* Create a new, uninitialised mcv that will fit with offset and scale */
+/* (Note thate black and white points aren't allocated) */
+mcv *new_mcv(void) {
+ mcv *p;
+
+ if ((p = (mcv *)calloc(1, sizeof(mcv))) == NULL)
+ return NULL;
+
+ /* Init method pointers */
+ p->del = mcv_del;
+ p->fit = mcv_fit;
+ p->force_0 = mcv_force_0;
+ p->force_1 = mcv_force_1;
+ p->force_scale = mcv_force_scale;
+ p->get_params = mcv_get_params;
+ p->interp = mcv_interp;
+ p->inv_interp = mcv_inv_interp;
+ p->interp_p = mcv_interp_p;
+ p->shweight_p = mcv_shweight_p;
+ p->dinterp_p = mcv_dinterp_p;
+ p->dshweight_p = mcv_dshweight_p;
+
+ p->luord = 0;
+ p->pms = NULL;
+ return p;
+}
+
+/* Create a new, uninitialised mcv without offset and scale parameters. */
+/* Note thate black and white points aren't allocated */
+mcv *new_mcv_noos(void) {
+ mcv *p;
+
+ if ((p = new_mcv()) == NULL)
+ return p;
+
+ p->noos = 2;
+ return p;
+}
+
+/* Create a new mcv initiated with the given curve parameters */
+/* (Assuming parameters always includes offset and scale) */
+mcv *new_mcv_p(double *pp, int np) {
+ int i;
+ mcv *p;
+
+ if ((p = new_mcv()) == NULL)
+ return p;
+
+ p->luord = np;
+ if ((p->pms = (double *)calloc(p->luord, sizeof(double))) == NULL)
+ error ("Malloc failed");
+
+ for (i = 0; i < np; i++)
+ p->pms[i] = *pp++;
+
+ return p;
+}
+
+/* Delete an mcv */
+static void mcv_del(mcv *p) {
+ if (p->pms != NULL)
+ free(p->pms);
+ free(p);
+}
+
+#ifdef TEST_PDE
+#define mcv_opt_func mcv_opt_func_
+#endif
+
+/* Shaper+Matrix optimisation function handed to powell() */
+static double mcv_opt_func(void *edata, double *v) {
+ mcv *p = (mcv *)edata;
+ double totw = 0.0;
+ double ev = 0.0, rv, smv;
+ double out;
+ int i;
+
+#ifdef DEBUG2
+ printf("params =");
+ for (i = 0; i < p->luord-p->noos; i++)
+ printf(" %f",v[i]);
+ printf("\n");
+ printf("ndp = %d\n",p->ndp);
+#endif
+
+ /* For all our data points */
+ for (i = 0; i < p->ndp; i++) {
+ double del;
+
+ /* Apply our function */
+ out = p->interp_p(p, v, p->d[i].p);
+
+ del = out - p->d[i].v;
+
+ ev += p->d[i].w * del * del;
+ totw += p->d[i].w;
+ }
+
+ /* Normalise error to be an average delta E squared */
+ totw = (100.0 * 100.0)/(p->dra * p->dra * totw);
+ ev *= totw;
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles" */
+ smv = mcv_shweight_p(p, v, p->smooth);
+ rv = ev + smv;
+
+#ifdef DEBUG2
+ printf("rv = %f (er %f + sm %f)\n",rv,ev,smv);
+#endif
+ return rv;
+}
+
+/* Shaper+Matrix optimisation function handed to conjgrad() */
+static double mcv_dopt_func(void *edata, double *dv, double *v) {
+ mcv *p = (mcv *)edata;
+ double totw = 0.0;
+ double ev = 0.0, rv, smv;
+ double out;
+ int i, j;
+
+#ifdef DEBUG2
+ printf("params =");
+ for (i = 0; i < (p->luord-p->noos); i++)
+ printf(" %f",v[i]);
+ printf("\n");
+#endif
+
+ /* Zero the dv's */
+ for (j = 0; j < (p->luord-p->noos); j++)
+ dv[j] = 0.0;
+
+ /* For all our data points */
+ for (i = 0; i < p->ndp; i++) {
+ double del;
+
+ /* Apply our function with dv's */
+ out = p->dinterp_p(p, v, p->dv, p->d[i].p);
+//printf("~1 point %d: p %f, v %f, func %f\n",i,p->d[i].p,p->d[i].v,out);
+
+ del = out - p->d[i].v;
+ ev += p->d[i].w * del * del;
+//printf("~1 del %f, ev %f\n",del,ev);
+
+ /* Sum the dv's */
+ for (j = 0; j < (p->luord-p->noos); j++) {
+ dv[j] += p->d[i].w * 2.0 * del * p->dv[j];
+//printf("~1 dv[%d] = %f\n",j,dv[j]);
+ }
+
+ totw += p->d[i].w;
+ }
+
+//printf("~1 totw = %f, dra = %f\n",totw, p->dra);
+ /* Normalise error to be an average delta E squared */
+ totw = (100.0 * 100.0)/(p->dra * p->dra * totw);
+ ev *= totw;
+ for (j = 0; j < (p->luord-p->noos); j++) {
+ dv[j] *= totw;
+//printf("~1 norm dv[%d] = %f\n",j,dv[j]);
+ }
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles", */
+ /* with partial derivatives */
+ smv = mcv_dshweight_p(p, v, dv, p->smooth);
+ rv = ev + smv;
+
+#ifdef DEBUG2
+ printf("drv = %f (er %f + sm %f)\n",rv,ev,smv);
+#endif
+ return rv;
+}
+
+#ifdef TEST_PDE
+/* Check partial derivative function */
+
+#undef mcv_opt_func
+
+static double mcv_opt_func(void *edata, double *v) {
+ mcv *p = (mcv *)edata;
+ int i;
+ double dv[500];
+ double rv, drv;
+ double trv;
+
+ rv = mcv_opt_func_(edata, v);
+ drv = mcv_dopt_func(edata, dv, v);
+
+ if (fabs(rv - drv) > 1e-6)
+ printf("######## RV MISMATCH is %f should be %f ########\n",rv,drv);
+
+ /* Check each parameter delta */
+ for (i = 0; i < (p->luord-p->noos); i++) {
+ double del;
+
+ v[i] += 1e-7;
+ trv = mcv_opt_func_(edata, v);
+ v[i] -= 1e-7;
+
+ /* Check that del is correct */
+ del = (trv - rv)/1e-7;
+ if (fabs(dv[i] - del) > 0.04) {
+//printf("~1 del = %f from (trv %f - rv %f)/0.1\n",del,trv,rv);
+ printf("######## EXCESSIVE at v[%d] is %f should be %f ########\n",i,dv[i],del);
+ }
+ }
+ return rv;
+}
+#endif /* TEST_PDE */
+
+/* Fit the curve to the given points */
+static void mcv_fit(mcv *p,
+ int verb, /* Vebosity level, 0 = none */
+ int order, /* Number of curve orders, 1..MCV_MAXORDER */
+ mcvco *d, /* Array holding scattered initialisation data */
+ int ndp, /* Number of data points */
+ double smooth /* Degree of smoothing, 1.0 = normal */
+) {
+ int i;
+ double *sa; /* Search area */
+ double *pms; /* Parameters to optimise */
+ double min, max;
+
+ p->verb = verb;
+ p->smooth = smooth;
+ p->luord = order+2; /* Add two for offset and scale */
+
+ if (p->pms != NULL)
+ free(p->pms);
+ if ((p->pms = (double *)calloc(p->luord, sizeof(double))) == NULL)
+ error ("Malloc failed");
+ if ((pms = (double *)calloc(p->luord, sizeof(double))) == NULL)
+ error ("Malloc failed");
+ if ((sa = (double *)calloc(p->luord, sizeof(double))) == NULL)
+ error ("Malloc failed");
+ if ((p->dv = (double *)calloc(p->luord, sizeof(double))) == NULL)
+ error ("Malloc failed");
+
+#ifdef DEBUG
+ printf("mcv_fit with %d points (noos = %d)\n",ndp,p->noos);
+#endif
+ /* Establish the range of data values */
+ min = 1e38; /* Locate min, and make that offset */
+ max = -1e38; /* Locate max */
+ for (i = 0; i < ndp; i++) {
+ if (d[i].v < min)
+ min = d[i].v;
+ if (d[i].v > max)
+ max = d[i].v;
+#ifdef DEBUG
+ printf("point %d is %f %f\n",i,d[i].p,d[i].v);
+#endif
+ }
+
+ if (p->noos) {
+ p->pms[0] = min = 0.0;
+ p->pms[1] = max = 1.0;
+ } else {
+ /* Set offset and scale to reasonable values */
+ p->pms[0] = min;
+ p->pms[1] = max - min;
+ }
+ p->dra = max - min;
+ if (p->dra <= 1e-12)
+ error("Mcv max - min %e too small",p->dra);
+
+ /* Use powell to minimise the sum of the squares of the */
+ /* input points to the curvem, plus a parameter damping factor. */
+ p->d = d;
+ p->ndp = ndp;
+
+ for (i = 0; i < p->luord; i++)
+ sa[i] = 0.2;
+
+#ifdef NEVER
+ if (powell(&p->resid, p->luord-p->noos, p->pms+p->noos, sa+p->noos, POWTOL, MAXITS,
+ mcv_opt_func, (void *)p, NULL, NULL) != 0)
+ error ("Mcv fit powell failed");
+#else
+ if (conjgrad(&p->resid, p->luord-p->noos, p->pms+p->noos, sa+p->noos, POWTOL, MAXITS,
+ mcv_opt_func, mcv_dopt_func, (void *)p, NULL, NULL) != 0) {
+#ifndef NEVER
+ fprintf(stderr,"Mcv fit conjgrad failed with %d points:\n",ndp);
+ for (i = 0; i < ndp; i++) {
+ fprintf(stderr," %d: %f -> %f\n",i,d->p, d->v);
+ }
+#endif
+ error ("Mcv fit conjgrad failed");
+ }
+#endif
+
+ free(p->dv);
+ p->dv = NULL;
+ free(sa);
+ free(pms);
+}
+
+/* The native values from the curve parameters are 0 - 1.0, */
+/* then the scale is applied, then the offset added, so the */
+/* output always ranges from (offset) to (offset + scale). */
+
+/* Offset the the output so that the value for input 0.0, */
+/* is the given value. Don't change the output for 1.0 */
+void mcv_force_0(
+ mcv *p,
+ double target /* Target output value */
+) {
+ if (p->luord > 0) {
+ target -= p->pms[0]; /* Change */
+ if (p->luord > 1)
+ p->pms[1] -= target; /* Adjust scale to leave 1.0 output untouched */
+ p->pms[0] += target; /* Adjust offset */
+ }
+}
+
+/* Scale the the output so that the value for input 1.0, */
+/* is the given target value. Don't change the output for 0.0 */
+static void mcv_force_1(
+ mcv *p,
+ double target /* Target output value */
+) {
+ if (p->luord > 1) {
+ target -= p->pms[0]; /* Offset */
+ p->pms[1] = target; /* Scale */
+ }
+}
+
+/* Scale the the output so that the value for input 1.0, */
+/* is the given target value. Scale the value for 0 in proportion. */
+static void mcv_force_scale(
+ mcv *p,
+ double target /* Target output value */
+) {
+ if (p->luord > 1) {
+ p->pms[0] *= target/(p->pms[0] + p->pms[1]); /* Offset */
+ p->pms[1] = target - p->pms[0]; /* Scale */
+ }
+}
+
+/* Return the number of parameters and the parameters in */
+/* an allocated array. free() when done. */
+/* The parameters are the offset, scale, then all the other parameters */
+static int mcv_get_params(mcv *p, double **rp) {
+ double *pp;
+ int np, i;
+
+ np = p->luord;
+
+ if ((pp = (double *)malloc(np * sizeof(double))) == NULL)
+ error("mcb_get_params malloc failed");
+
+ *rp = pp;
+
+ for (i = 0; i < np; i++)
+ *pp++ = p->pms[i];
+
+ return np;
+}
+
+/* Translate a value through the curve */
+/* using the currently set pms */
+static double mcv_interp(struct _mcv *p,
+ double vv /* Input value */
+) {
+ return mcv_interp_p(p, p->pms + p->noos, vv);
+}
+
+/* Translate a value through backwards the curve */
+static double mcv_inv_interp(struct _mcv *p,
+ double vv /* Input value */
+) {
+ double g;
+ int ord;
+
+ /* Process everything in reverse order to mcv_interp */
+
+ if (p->noos == 0) {
+ /* Do order 0 & 1, the offset and scale */
+ if (p->luord > 0)
+ vv -= p->pms[0];
+
+ if (p->luord > 1)
+ vv /= p->pms[1];
+ }
+
+ for (ord = p->luord-1; ord > 1; ord--) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = -p->pms[ord]; /* Inverse parameter */
+
+ nsec = ord-1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ return vv;
+}
+
+/* Translate a value through the curve */
+/* using the given parameters */
+static double mcv_interp_p(
+ mcv *p,
+ double *pms, /* Parameters to use - may exclude offset and scale */
+ double vv /* Input value */
+) {
+ double g;
+ int ord;
+
+ /* Process all the shaper orders from low to high. */
+ /* [These shapers were inspired by a Graphics Gem idea */
+ /* (Gems IV, VI.3, "Fast Alternatives to Perlin's Bias and */
+ /* Gain Functions, pp 401). */
+ /* They have the nice properties that they are smooth, and */
+ /* are monotonic. The control parameter has been */
+ /* altered to have a range from -oo to +oo rather than 0.0 to 1.0 */
+ /* so that the search space is less non-linear. */
+ for (ord = (2 - p->noos); ord < (p->luord - p->noos); ord++) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = pms[ord]; /* Parameter */
+
+ nsec = ord-1+p->noos; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ if (p->noos == 0) {
+ /* Do order 0 & 1 */
+ if (p->luord > 1)
+ vv *= pms[1]; /* Scale */
+
+ if (p->luord > 0)
+ vv += pms[0]; /* Offset */
+ }
+
+ return vv;
+}
+
+/* Return the shaper parameters regularizing weight */
+static double mcv_shweight_p(
+mcv *p,
+double *pms, /* Parameters to use - may exclude offset and scale */
+double smooth) {
+
+ double smv;
+ int i;
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles" */
+ /* Note:- we start at 2, to skip offset and scale. */
+ /* ?? Should these have a weight too ?? */
+ smv = 0.0;
+ for (i = (2-p->noos); i < (p->luord-p->noos); i++) {
+ double w, tt;
+ int cx; /* Curve index (skips offset & scale) */
+
+ cx = i - 2 + p->noos;
+ tt = pms[i];
+
+ /* Weigh to suppress ripples */
+ if (cx <= 1) {
+ w = HW01;
+ } else if (cx <= HBREAK) {
+ double bl = (cx - 1.0)/(HBREAK - 1.0);
+ w = (1.0 - bl) * HW01 + bl * HWBR;
+ } else {
+ w = HWBR + (cx-HBREAK) * HWINC * smooth;
+ }
+ tt *= tt;
+ smv += w * tt;
+ }
+ return smv;
+}
+
+/* Transfer function with partial derivative */
+/* with respect to the given parameters. */
+double mcv_dinterp_p(mcv *p,
+double *pms, /* Parameters to use - may exclude offset and scale */
+double *dv, /* Return derivative wrt each parameter - may exclude offset and scale */
+double vv /* Source of value */
+) {
+ double g;
+ int i, ord;
+
+ /* Process all the shaper orders from low to high. */
+ for (ord = (2-p->noos); ord < (p->luord-p->noos); ord++) {
+ double dsv; /* del for del in g */
+ double ddv; /* del for del in vv */
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = pms[ord]; /* Parameter */
+
+ nsec = ord-1+p->noos; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1) {
+ g = -g; /* Alternate action in each section */
+ }
+ vv -= sec;
+ if (g >= 0.0) {
+ double tt = g - g * vv + 1.0;
+ dsv = (vv * vv - vv)/(tt * tt);
+ ddv = (g + 1.0)/(tt * tt);
+ vv = vv/tt;
+ } else {
+ double tt = 1.0 - g * vv;
+ dsv = (vv * vv - vv)/(tt * tt);
+ ddv = (1.0 - g)/(tt * tt);
+ vv = (vv - g * vv)/tt;
+ }
+
+ vv += sec;
+ vv /= (double)nsec;
+ dsv /= (double)nsec;
+ if (((int)sec) & 1)
+ dsv = -dsv;
+
+ dv[ord] = dsv;
+ for (i = ord - 1; i >= (2-p->noos); i--)
+ dv[i] *= ddv;
+ }
+
+ if (p->noos == 0) {
+ /* Do order 0, the scale */
+ if (p->luord > 1) {
+ dv[1] = vv;
+ vv *= pms[1];
+ }
+ if (p->luord > 0) {
+ dv[0] = 1.0;
+ vv += pms[0]; /* Offset */
+ }
+ }
+
+ return vv;
+}
+
+/* Return the shaper parameters regularizing weight, */
+/* and add in partial derivatives. */
+/* Weight error and derivatrive by wht */
+static double mcv_dshweight_p(
+mcv *p,
+double *pms, /* Parameters to use - may exclude offset and scale */
+double *dpms,
+double smooth) {
+ double smv;
+ int i;
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles", */
+ /* with partial derivatives */
+ smv = 0.0;
+ for (i = (2-p->noos); i < (p->luord-p->noos); i++) {
+ double w, tt;
+ int cx;
+
+ cx = i - 2 + p->noos;
+ tt = pms[i];
+
+ /* Weigh to suppress ripples */
+ if (cx <= 1) { /* First or second curves */
+ w = HW01;
+ } else if (cx <= HBREAK) { /* First or second curves */
+ double bl = (cx - 1.0)/(HBREAK - 1.0);
+ w = (1.0 - bl) * HW01 + bl * HWBR;
+ } else {
+ w = HWBR + (cx-HBREAK) * HWINC * smooth;
+ }
+ dpms[i] += w * 2.0 * tt;
+ tt *= tt;
+ smv += w * tt;
+ }
+
+ return smv;
+}
+
+
diff --git a/xicc/moncurve.h b/xicc/moncurve.h
new file mode 100644
index 0000000..5510c7d
--- /dev/null
+++ b/xicc/moncurve.h
@@ -0,0 +1,121 @@
+
+#ifndef MCV_H
+#define MCV_H
+
+/*
+ * Argyll Color Correction System
+ * Monotonic curve class for display calibration.
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/10/2005
+ *
+ * Copyright 2005 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.
+ *
+ * This is based on the monotonic curve equations used elsewhere,
+ * but currently intended to support the display calibration process.
+ * moncurve is not currently general, missing:
+ *
+ * input scaling
+ * output scaling
+ *
+ * The nominal input and output ranges are 0.0 to 1.0,
+ */
+
+/* A test patch value */
+typedef struct {
+ double p; /* Position */
+ double v; /* Value */
+ double w; /* Weighting, nominally 1.0 */
+} mcvco;
+
+struct _mcv {
+
+ /* Public: */
+ void (*del)(struct _mcv *p);
+
+ /* Fit the curve to the given points */
+ void (*fit) (struct _mcv *p,
+ int verb, /* Vebosity level, 0 = none */
+ int order, /* Number of curve orders, 1..MCV_MAXORDER */
+ mcvco *d, /* Array holding scattered initialisation data */
+ int ndp, /* Number of data points */
+ double smooth /* Degree of smoothing, 1.0 = normal */
+ );
+
+ /* Offset the the output so that the value for input 0.0, */
+ /* is the given value. Don't change the 1.0 output */
+ void (*force_0) (struct _mcv *p,
+ double target /* Target output value */
+ );
+
+ /* Scale the the output so that the value for input 1.0, */
+ /* is the given value. Don't change the 0.0 output */
+ void (*force_1) (struct _mcv *p,
+ double target /* Target output value */
+ );
+
+ /* Scale the the output so that the value for input 1.0, */
+ /* is the given target value. Scale the value for 0.0 too. */
+ void (*force_scale) (struct _mcv *p,
+ double target /* Target output value */
+ );
+
+ /* Return the number of parameters and the parameters in */
+ /* an allocated array. free() when done. */
+ /* The parameters are the offset, scale, then all the other parameters */
+ int (*get_params)(struct _mcv *p, double **rp);
+
+ /* Translate a value through the current curve */
+ double (*interp) (struct _mcv *p,
+ double in); /* Input value */
+
+ /* Translate a value backwards through the current curve */
+ double (*inv_interp) (struct _mcv *p,
+ double in); /* Input value */
+
+
+ /* Translate a value given the parametrs */
+ double (*interp_p) (struct _mcv *p,
+ double *pms, double in); /* Input value */
+
+ /* return the shaper parameters normalising weight */
+ double (*shweight_p)(struct _mcv *p, double *v, double smooth);
+
+ /* Translate a value given the parametrs, with partial derivatives */
+ double (*dinterp_p) (struct _mcv *p, double *pms, double *dv, double vv);
+
+ /* return the shaper parameters normalising weight, with partial derivatives */
+ double (*dshweight_p)(struct _mcv *p, double *v, double *dv, double smooth);
+
+
+ /* Private: */
+ int verb; /* Verbose */
+ int noos; /* flag, 2 = offset and scale not fitted */
+ int luord; /* Lookup order including offset and scale */
+ double *pms; /* Allocated curve parameters */
+ double *dv; /* Work space for dv's during optimisation */
+ double resid; /* Residual fit error */
+
+ mcvco *d; /* Array holding scattered initialisation data */
+ int ndp; /* Number of data points */
+ double dra; /* Data range */
+
+ double smooth; /* Smoothing factor */
+
+}; typedef struct _mcv mcv;
+
+/* Create a new, uninitialised mcv that will fit with offset and scale */
+mcv *new_mcv(void);
+
+/* Create a new mcv initiated with the given curve parameters */
+mcv *new_mcv_p(double *pp, int np);
+
+/* Create a new, uninitialised mcv with offset and scale not to be fitted, */
+/* and defaulting to 0.0 and 1.0 */
+mcv *new_mcv_noos(void);
+
+#endif /* MCV */
+
diff --git a/xicc/mpp.c b/xicc/mpp.c
new file mode 100644
index 0000000..02b3019
--- /dev/null
+++ b/xicc/mpp.c
@@ -0,0 +1,4446 @@
+
+/*
+ * Argyll Color Correction System
+ * Model Printer Profile object.
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/2/2002
+ *
+ * Copyright 2003 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.
+ */
+
+/* This version (based on mpp_x1) has n * 2^(n-1) shape params, */
+/* used for linear interpolation of the shaping correction. */
+
+/*
+ * This program takes in the scattered test chart
+ * points, and creates a model based forward printer profile
+ * (Device -> CIE + spectral), based on heuristic extensions to
+ * the Neugenbauer model.
+ * It is designed to handle an arbitrary number of colorants,
+ * and in the future, (optionaly) create an aproximate ink overlap/mixing model
+ * to allow synthesis of a forward model for a hyperthetical
+ * similar printing process with additional inks.
+ *
+ * The model is as follows:
+ *
+ * A per input channel transfer curve, that models
+ * per channel dot gain, transfer curve processing etc.
+ *
+ * A per input channel shape modification model.
+ * Each transfer curve adjusted value is further
+ * adjusted in a way that depends on the combination
+ * of value of all the other input channels.
+ * This allows for ink interaction effects in a way
+ * that should allow good conformance to all combinations
+ * of input values at 50% values.
+ *
+ * An n-linear interpolation between all combination of
+ * the 0 and 100% colorant primary combinations (Neugenbauer).
+ *
+ * The model making can be rather slow, particularly if high
+ * quality, large number of colorants, large number of sample
+ * points.
+ *
+ * This code is based on profile.c, sprof.c and xlut.c
+ *
+ */
+
+/*
+ * TTBD:
+ *
+ * !!!! Should change device transfer model to include offset & scale,
+ * to better match display & other devices !!!!
+ *
+ * Should add Jab pcs mode, so that Jab gamuts can be
+ * written.
+ *
+ * Remove #ifndef DEBUG & replace with verbose progress bars.
+ *
+ * Add support for extra profile details to create() to support
+ * profxinf like stuff.
+ *
+ * Add ink order and overlay modeling stuff back in, with
+ * new ink overlay model (see mpprof0.c).
+ *
+ * Rather than computing XYZ based versios of the print model
+ * and ink mixing models, should compute spectrally sharpened
+ * equivalents to XYZ ?? (The spectral CIE base values don't
+ * seem much more accurate than XYZ, so perhaps remove SHARPEN code ?).
+ *
+ * Need to cleanup error handling.
+ */
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef TESTDFUNC /* Check delta functions */
+#undef NODDV /* Use (very slow) non d/dv powell */
+#undef DOPLOT /* Plot the device curves */
+
+#undef NOPROCESS /* Define to skip all fitting */
+#define MULTIPASS /* Fit passes by parts (normal mode) */
+#undef BIGBANG /* Define to fit all parameters at once */
+#undef ISHAPE /* define to try SVD init of shape parameters */
+#undef SHARPEN /* use sharpened XYZ values for modeling */
+ /* (Wrecks derivative lookup at the moment, and makes */
+ /* accuracy worse!) */
+
+ /* Transfer curve parameter (wiggle) minimisation weight */
+#define TRANS_BASE 0.2 /* 0 & 1 harmonic parameter weight */
+#define TRANS_HBASE 0.8 /* 2nd harmonic and above base parameter weight */
+#define SHAPE_PMW 0.2 /* Shape parameter (wiggle) minimisation weight */
+#define COMB_PMW 0.008 /* Primary combination anchor point distance weight */
+
+#define verbo stdout
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "numlib.h"
+#include "cgats.h"
+#include "icc.h"
+#include "xicc.h" /* Spectral support */
+#include "xspect.h" /* Spectral support */
+#include "xcolorants.h" /* Known colorants support */
+#include "insttypes.h"
+#include "gamut.h"
+#include "mpp.h"
+#ifdef DOPLOT
+#include "plot.h"
+#endif /* DOPLOT */
+
+/* Forward declarations */
+static double bandval(mpp *p, int band, double *dev);
+static double dbandval(mpp *p, double *dv, int band, double *dev);
+static void forward(mpp *p, double *spec, double *Lab, double *XYZ, double *dev);
+static int create(mpp *p, int verb, int quality, int display, double limit, inkmask devmask,
+ int spec_n, double spec_wl_short, double spec_wl_long,
+ double norm, instType itype, int nodp, mppcol *points);
+static void compute_wb(mpp *p);
+static void init_shape(mpp *p);
+
+/* Utilities */
+
+#ifdef SHARPEN
+/* Convert from XYZ to spectrally sharpened response */
+/* (Can this generate -ve values for real colors ??) */
+static void XYZ2sharp(double *a, double *b, double *c) {
+ double xyz[3], rgb[3];
+
+ xyz[0] = *a;
+ xyz[1] = *b;
+ xyz[2] = *c;
+
+ rgb[0] = 0.8562 * xyz[0] + 0.3372 * xyz[1] - 0.1934 * xyz[2];
+ rgb[1] = -0.8360 * xyz[0] + 1.8327 * xyz[1] + 0.0033 * xyz[2];
+ rgb[2] = 0.0357 * xyz[0] - 0.0469 * xyz[1] + 1.0112 * xyz[2];
+
+ *a = rgb[0];
+ *b = rgb[1];
+ *c = rgb[2];
+}
+
+/* Convert from spectrally sharpened response to XYZ */
+static void sharp2XYZ(double *a, double *b, double *c) {
+ double xyz[3], rgb[3];
+
+ rgb[0] = *a;
+ rgb[1] = *b;
+ rgb[2] = *c;
+
+ xyz[0] = 0.9873999149199270 * rgb[0]
+ - 0.1768250198556842 * rgb[1]
+ + 0.1894251049357572 * rgb[2];
+ xyz[1] = 0.4504351090445316 * rgb[0]
+ + 0.4649328977527109 * rgb[1]
+ + 0.0846319932027575 * rgb[2];
+ xyz[2] = -0.0139683251072516 * rgb[0]
+ + 0.0278065725014340 * rgb[1]
+ + 0.9861617526058175 * rgb[2];
+
+ *a = xyz[0];
+ *b = xyz[1];
+ *c = xyz[2];
+}
+#endif /* SHARPEN */
+
+
+/* Method implimentations */
+
+/* Write out the mpp to a CGATS format .mpp file */
+/* Return nz on error */
+static int write_mpp(
+mpp *p, /* This */
+char *outname, /* Filename to write to */
+int dolab /* If NZ, write Lab values rather than XYZ */
+) {
+ int i, j, n;
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats *ocg; /* CGATS structure */
+ char *ident = icx_inkmask2char(p->imask, 1);
+ int nsetel = 0;
+ cgats_set_elem *setel; /* Array of set value elements */
+ char buf[100];
+
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ ocg->add_other(ocg, "MPP"); /* our special type is Model Printer Profile */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Model Printer Profile, Colorant linearisation",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll mpp", NULL);
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+ if (p->display)
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","DISPLAY", NULL); /* What sort of device this is */
+ else {
+ ocg->add_kword(ocg, 0, "DEVICE_CLASS","OUTPUT", NULL); /* What sort of device this is */
+
+ /* Note what instrument the chart was read with, in case we */
+ /* want to apply FWA when converting spectral data to CIE */
+ ocg->add_kword(ocg, 0, "TARGET_INSTRUMENT", inst_name(p->itype) , NULL);
+
+ sprintf(buf,"%5.1f",p->limit * 100.0);
+ ocg->add_kword(ocg, 0, "TOTAL_INK_LIMIT", buf, NULL);
+ }
+
+ ocg->add_kword(ocg, 0, "COLOR_REP", ident, NULL);
+
+ /* Record how many factors are used in device channel transfer curve */
+ sprintf(buf,"%d",p->cord);
+ ocg->add_kword(ocg, 0, "TRANSFER_ORDERS", buf, NULL);
+
+ /* Record if shaper parameters are being used */
+ if (p->useshape) {
+ ocg->add_kword(ocg, 0, "USE_SHAPER", "YES", NULL);
+ } else {
+ ocg->add_kword(ocg, 0, "USE_SHAPER", "NO", NULL);
+ }
+
+ /* Setup the table, which holds all the model parameters. */
+ /* There is always a parameter per X Y Z or spectral band */
+ ocg->add_field(ocg, 0, "PARAMETER", nqcs_t);
+ if (dolab) {
+ ocg->add_field(ocg, 0, "LAB_L", r_t);
+ ocg->add_field(ocg, 0, "LAB_A", r_t);
+ ocg->add_field(ocg, 0, "LAB_B", r_t);
+ } else {
+ ocg->add_field(ocg, 0, "XYZ_X", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Y", r_t);
+ ocg->add_field(ocg, 0, "XYZ_Z", r_t);
+ }
+ nsetel = 1 + 3;
+
+ /* Add fields for spectral values */
+ if (p->spec_n > 0) {
+
+ nsetel += p->spec_n; /* Spectral values */
+ sprintf(buf,"%d", p->spec_n);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+ sprintf(buf,"%f", p->spec_wl_short);
+ ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
+ sprintf(buf,"%f", p->spec_wl_long);
+ ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);
+ sprintf(buf,"%f", p->norm * 100.0);
+ ocg->add_kword(ocg, 0, "SPECTRAL_NORM",buf, NULL);
+
+ /* Generate fields for spectral values */
+ for (i = 0; i < p->spec_n; i++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(p->spec_wl_short + ((double)i/(p->spec_n-1.0))
+ * (p->spec_wl_long - p->spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+ ocg->add_field(ocg, 0, buf, r_t);
+ }
+ }
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL) {
+ free(ident);
+ sprintf(p->err,"write_mpp: malloc of setel failed");
+ return 1;
+ }
+
+ /* Write out the transfer curve values */
+ for (i = 0; i < p->n; i++) { /* each colorant */
+ for (j = 0; j < p->cord; j++) { /* curve order values */
+
+ sprintf(buf,"t_%d_%d",i,j);
+ setel[0].c = buf; /* Parameter identifier */
+
+ for (n = 0; n < (3+p->spec_n); n++)
+ setel[1+n].d = p->tc[i][n][j];
+ ocg->add_setarr(ocg, 0, setel);
+ }
+ }
+
+ if (p->useshape) {
+
+ /* Write out the shaper values */
+ for (i = 0; i < p->nnn2; i++) { /* For all shaper values */
+ int m = p->c2f[i].ink;
+ int k = p->c2f[i].comb;
+
+ sprintf(buf,"s_%d_%d",m, k);
+ setel[0].c = buf; /* Parameter identifier */
+
+ for (n = 0; n < (3+p->spec_n); n++)
+ setel[1+n].d = p->shape[m][k][n];
+
+ ocg->add_setarr(ocg, 0, setel);
+ }
+ }
+
+ /* Write out the colorant combination values */
+ for (i = 0; i < p->nn; i++) {
+
+ sprintf(buf,"c_%d",i);
+ setel[0].c = buf; /* Parameter identifier */
+
+ for (n = 0; n < (3+p->spec_n); n++)
+ setel[1+n].d = p->pc[i][n];
+
+#ifdef SHARPEN
+ sharp2XYZ(&setel[1+0].d, &setel[1+1].d, &setel[1+2].d);
+#endif
+ if (dolab) {
+ double ttt[3];
+ ttt[0] = setel[1+0].d, ttt[1] = setel[1+1].d, ttt[2] = setel[1+2].d;
+ icmXYZ2Lab(&icmD50, ttt, ttt);
+ setel[1+0].d = ttt[0], setel[1+1].d = ttt[1], setel[1+2].d = ttt[2];
+ }
+ ocg->add_setarr(ocg, 0, setel);
+ }
+ free(setel);
+ free(ident);
+
+ /* Write it */
+ if (ocg->write_name(ocg, outname)) {
+ strcpy(p->err, ocg->err);
+ return 1;
+ }
+
+ ocg->del(ocg); /* Clean up */
+
+ return 0;
+}
+
+/* Read in the mpp CGATS .mpp file */
+/* Return nz on error */
+static int read_mpp(
+mpp *p, /* This */
+char *inname /* Filename to read from */
+) {
+ int i, j, n, ix;
+ cgats *icg; /* input cgats structure */
+ int ti; /* Temporary CGATs index */
+ int islab = 0; /* nz if Lab parameters */
+
+ /* Open and look at the .mpp model printer profile */
+ if ((icg = new_cgats()) == NULL) { /* Create a CGATS structure */
+ sprintf(p->err, "read_mpp: new_cgats() failed");
+ return 2;
+ }
+ icg->add_other(icg, "MPP"); /* our special type is Model Printer Profile */
+
+ if (icg->read_name(icg, inname)) {
+ strcpy(p->err, icg->err);
+ icg->del(icg);
+ return 1;
+ }
+
+ if (icg->ntables == 0 || icg->t[0].tt != tt_other || icg->t[0].oi != 0) {
+ sprintf(p->err, "read_mpp: Input file '%s' isn't a MPP format file",inname);
+ icg->del(icg);
+ return 1;
+ }
+ if (icg->ntables != 1) {
+ sprintf(p->err, "Input file '%s' doesn't contain exactly one table",inname);
+ icg->del(icg);
+ return 1;
+ }
+ if ((ti = icg->find_kword(icg, 0, "COLOR_REP")) < 0) {
+ sprintf(p->err, "read_mpp: Input file '%s' doesn't contain keyword COLOR_REP",inname);
+ icg->del(icg);
+ return 1;
+ }
+
+ p->imask = icx_char2inkmask(icg->t[0].kdata[ti]);
+ p->n = icx_noofinks(p->imask);
+ p->nn = 1 << p->n;
+ p->nnn2 = p->n * p->nn/2;
+
+ if (p->n == 0) {
+ sprintf(p->err, "read_mpp: COLOR_REP '%s' invalid from file '%s' (No matching devmask)",
+ icg->t[0].kdata[ti], inname);
+ icg->del(icg);
+ return 1;
+ }
+
+ /* See if it is the expected device class */
+ if ((ti = icg->find_kword(icg, 0, "DEVICE_CLASS")) < 0) {
+ sprintf(p->err, "read_mpp: Input file '%s' doesn't contain keyword DEVICE_CLASS",inname);
+ icg->del(icg);
+ return 1;
+ }
+ if (strcmp(icg->t[0].kdata[ti],"OUTPUT") == 0) {
+
+ if ((ti = icg->find_kword(icg, 0, "TOTAL_INK_LIMIT")) >= 0) {
+ double imax;
+ imax = atof(icg->t[0].kdata[ti]);
+ p->limit = imax/100.0;
+ } else {
+ p->limit = 0.0; /* Don't use ink limit */
+ }
+
+ if ((ti = icg->find_kword(icg, 0, "TARGET_INSTRUMENT")) < 0) {
+ sprintf(p->err, "read_mpp: Can't find keyword TARGET_INSTRUMENT in file '%s'", inname);
+ icg->del(icg);
+ return 1;
+ }
+
+ if ((p->itype = inst_enum(icg->t[0].kdata[ti])) == instUnknown
+ && icg->find_kword(icg, 0, "SPECTRAL_BANDS") >= 0) {
+ sprintf(p->err, "read_mpp: Unrecognised target instrument '%s' in file '%s'",
+ icg->t[0].kdata[ti], inname);
+ icg->del(icg);
+ return 1;
+ }
+
+ p->display = 0;
+
+ } else if (strcmp(icg->t[0].kdata[ti],"DISPLAY") == 0) {
+
+ p->display = 1;
+ p->itype = instUnknown;
+ p->limit = p->n;
+
+ } else {
+ /* Don't know anything else at the moment */
+ sprintf(p->err, "read_mpp: Input file '%s' has unknown DEVICE_CLASS '%s'",
+ inname, icg->t[0].kdata[ti]);
+ icg->del(icg);
+ return 1;
+ }
+
+ /* Read the number of device linearisation orders */
+ if ((ti = icg->find_kword(icg, 0, "TRANSFER_ORDERS")) < 0) {
+ sprintf(p->err, "read_mpp: Input file '%s' doesn't contain keyword TRANSFER_ORDERS",
+ inname);
+ icg->del(icg);
+ return 1;
+ }
+ p->cord = atoi(icg->t[0].kdata[ti]);
+ if (p->cord < 1 || p->cord > MPP_MXTCORD) {
+ sprintf(p->err, "read_mpp: Input file '%s' has out of range TRANSFER_ORDERS %d",
+ inname, p->cord);
+ icg->del(icg);
+ return 1;
+ }
+
+ /* See if shaper parameters are used */
+ p->useshape = 0;
+ if ((ti = icg->find_kword(icg, 0, "USE_SHAPER")) >= 0) {
+ if(strcmp(icg->t[0].kdata[ti], "YES") == 0)
+ p->useshape = 1;
+ }
+
+ /* Read the model parameters */
+ {
+ int ci; /* Parameter dentified index */
+ int spi[3+MPP_MXBANDS]; /* CGATS indexes for each band */
+ char *xyzfname[3] = { "XYZ_X", "XYZ_Y", "XYZ_Z" };
+ char *labfname[3] = { "LAB_L", "LAB_A", "LAB_B" };
+ char buf[100];
+
+ /* See if we have spectral information available */
+ if (icg->find_kword(icg, 0, "SPECTRAL_BANDS") < 0) {
+ p->spec_n = 0; /* None */
+ } else {
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_BANDS");
+ p->spec_n = atoi(icg->t[0].kdata[ti]);
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_START_NM");
+ p->spec_wl_short = atof(icg->t[0].kdata[ti]);
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_END_NM");
+ p->spec_wl_long = atof(icg->t[0].kdata[ti]);
+ if ((ti = icg->find_kword(icg, 0, "SPECTRAL_NORM")) < 0)
+ error ("Input file doesn't contain keyword SPECTRAL_NORM");
+ p->norm = atof(icg->t[0].kdata[ti])/100.0;
+ }
+
+ if ((new_mppcol(&p->white, p->n, p->spec_n)) != 0) {
+ error("Malloc failed!");
+ }
+ if ((new_mppcol(&p->black, p->n, p->spec_n)) != 0) {
+ error("Malloc failed!");
+ }
+ if ((new_mppcol(&p->kblack, p->n, p->spec_n)) != 0) {
+ error("Malloc failed!");
+ }
+ init_shape(p); /* Allocate and init shape related parameter space */
+
+ /* Get the field indexes */
+ if ((ci = icg->find_field(icg, 0, "PARAMETER")) < 0) {
+ sprintf(p->err, "read_mpp: Input file '%s' doesn't contain field PARAMETER",
+ inname);
+ icg->del(icg);
+ return 1;
+ }
+ if (icg->t[0].ftype[ci] != nqcs_t) {
+ sprintf(p->err, "read_mpp: Input file '%s' field PARAMETER is wrong type",
+ inname);
+ icg->del(icg);
+ return 1;
+ }
+
+ for (i = 0; i < 3; i++) { /* XYZ fields */
+ if ((spi[i] = icg->find_field(icg, 0, xyzfname[i])) < 0) {
+ break;
+ }
+ if (icg->t[0].ftype[spi[i]] != r_t) {
+ sprintf(p->err, "read_mpp: Input file '%s' field %s is wrong type",
+ inname, buf);
+ icg->del(icg);
+ return 1;
+ }
+ }
+
+ if (i < 3) {
+ islab = 1;
+ for (i = 0; i < 3; i++) { /* XYZ fields */
+ if ((spi[i] = icg->find_field(icg, 0, labfname[i])) < 0) {
+ sprintf(p->err, "read_mpp: Input file '%s' doesn't contain field %s or %s",
+ inname, xyzfname[i], labfname[i]);
+ icg->del(icg);
+ return 1;
+ }
+ if (icg->t[0].ftype[spi[i]] != r_t) {
+ sprintf(p->err, "read_mpp: Input file '%s' field %s is wrong type",
+ inname, buf);
+ icg->del(icg);
+ return 1;
+ }
+ }
+ }
+
+ /* Find the fields for spectral values */
+ if (p->spec_n > 0) {
+ for (j = 0; j < p->spec_n; j++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(p->spec_wl_short + ((double)j/(p->spec_n-1.0))
+ * (p->spec_wl_long - p->spec_wl_short) + 0.5);
+
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((spi[3+j] = icg->find_field(icg, 0, buf)) < 0) {
+ sprintf(p->err, "read_mpp: Input file '%s' doesn't contain field %s",
+ buf,inname);
+ icg->del(icg);
+ return 1;
+ }
+ if (icg->t[0].ftype[spi[3+j]] != r_t) {
+ sprintf(p->err, "read_mpp: Input file '%s' field %s is wrong type",
+ inname, buf);
+ icg->del(icg);
+ return 1;
+ }
+ }
+ }
+
+ /* Read the transfer curve values */
+ for (i = 0; i < p->n; i++) { /* each colorant */
+ for (j = 0; j < p->cord; j++) { /* curve order values */
+
+ sprintf(buf,"t_%d_%d",i,j);
+
+ /* Find the right parameter */
+ for (ix = 0; ix < icg->t[0].nsets; ix++) {
+
+ if (strcmp((char *)icg->t[0].fdata[ix][ci], buf) == 0) {
+ for (n = 0; n < (3+p->spec_n); n++)
+ p->tc[i][n][j] = *((double *)icg->t[0].fdata[ix][spi[n]]);
+ break;
+ }
+ }
+ }
+ }
+
+ if (p->useshape) {
+
+ /* Read the shaper values */
+ for (i = 0; i < p->nnn2; i++) { /* For all shaper values */
+ int m = p->c2f[i].ink;
+ int k = p->c2f[i].comb;
+
+ sprintf(buf,"s_%d_%d",m, k);
+
+ /* Find the right parameter */
+ for (ix = 0; ix < icg->t[0].nsets; ix++) {
+
+ if (strcmp((char *)icg->t[0].fdata[ix][ci], buf) == 0) {
+ for (n = 0; n < (3+p->spec_n); n++)
+ p->shape[m][k][n] = *((double *)icg->t[0].fdata[ix][spi[n]]);
+
+ break;
+ }
+ }
+ }
+ }
+
+ /* Read the combination values */
+ for (i = 0; i < p->nn; i++) {
+
+ sprintf(buf,"c_%d",i);
+
+
+ /* Find the right parameter */
+ for (ix = 0; ix < icg->t[0].nsets; ix++) {
+
+ if (strcmp((char *)icg->t[0].fdata[ix][ci], buf) == 0) {
+ for (n = 0; n < (3+p->spec_n); n++)
+ p->pc[i][n] = *((double *)icg->t[0].fdata[ix][spi[n]]);
+ if (islab) {
+ double tt[3];
+ tt[0] = p->pc[i][0], tt[1] = p->pc[i][1], tt[2] = p->pc[i][2];
+ icmLab2XYZ(&icmD50, tt, tt);
+ p->pc[i][0] = tt[0], p->pc[i][1] = tt[1], p->pc[i][2] = tt[2];
+ }
+#ifdef SHARPEN
+ XYZ2sharp(&p->pc[i][0], &p->pc[i][1], &p->pc[i][2]);
+#endif
+ break;
+ }
+ }
+ }
+ }
+
+ icg->del(icg); /* Clean up */
+
+ /* Figure out the white and black points */
+ compute_wb(p);
+
+ return 0;
+}
+
+/* Get various types of information about the mpp */
+static void get_info(
+mpp *p, /* This */
+inkmask *imask, /* Inkmask, describing device colorspace */
+int *nodchan, /* Number of device channels */
+double *limit, /* Total ink limit (0.0 .. devchan) */
+int *spec_n, /* Number of spectral bands, 0 if none */
+double *spec_wl_short, /* First reading wavelength in nm (shortest) */
+double *spec_wl_long, /* Last reading wavelength in nm (longest) */
+instType *itype, /* Instrument type */
+int *display /* Return nz if display type */
+) {
+ if (imask != NULL)
+ *imask = p->imask;
+ if (nodchan != NULL)
+ *nodchan = p->n;
+ if (limit != NULL)
+ *limit = p->limit;
+ if (spec_n != NULL)
+ *spec_n = p->spec_n;
+ if (spec_wl_short != NULL)
+ *spec_wl_short = p->spec_wl_short;
+ if (spec_wl_long != NULL)
+ *spec_wl_long = p->spec_wl_long;
+ if (itype != NULL)
+ *itype = p->itype;
+ if (display != NULL)
+ *display = p->display;
+}
+
+/* Set an illuminant and observer to use spectral model */
+/* for CIE lookup with optional FWA. Set both to default for XYZ mpp model. */
+/* return 0 on OK, 1 on spectral not supported, 2 on other error */
+/* If the model is for a display, the illuminant will be ignored. */
+static int set_ilob(
+mpp *p,
+icxIllumeType ilType, /* Illuminant type (icxIT_default for none) */
+xspect *custIllum, /* Custom illuminant (NULL for none) */
+icxObserverType obType, /* Observer type (icxOT_default for none) */
+xspect custObserver[3], /* Custom observer (NULL for none) */
+icColorSpaceSignature rcs, /* Return color space, icSigXYZData or icSigLabData */
+int use_fwa /* NZ to involke FWA. */
+) {
+
+ /* Get rid of any existing conversion object */
+ if (p->spc != NULL) {
+ p->spc->del(p->spc);
+ p->spc = NULL;
+ }
+
+ p->pcs = rcs;
+
+ if (ilType == icxIT_default && obType == icxOT_default && use_fwa == 0)
+ return 0;
+
+ if (p->spec_n == 0) {
+ p->errc = 1;
+ sprintf(p->err,"No Spectral Data in MPP");
+ return 1;
+ }
+
+ if (p->display) {
+ ilType = icxIT_none;
+ custIllum = NULL;
+ }
+
+ if ((p->spc = new_xsp2cie(ilType, custIllum, obType, custObserver, rcs, 1)) == NULL)
+ error("mpp->set_ilob, new_xsp2cie failed");
+
+ if (use_fwa) {
+ int j;
+ xspect white, inst;
+
+ white.norm = p->norm;
+ white.spec_n = p->spec_n;
+ white.spec_wl_short = p->spec_wl_short;
+ white.spec_wl_long = p->spec_wl_long;
+ for (j = 0; j < p->spec_n; j++)
+ white.spec[j] = p->white.band[3+j];
+
+ if (inst_illuminant(&inst, p->itype) != 0)
+ error ("mpp->set_ilob, instrument doesn't have an FWA illuminent");
+
+ if (p->spc->set_fwa(p->spc, &inst, NULL, &white))
+ error ("mpp->set_ilob, set_fwa faild");
+ }
+
+ return 0;
+}
+
+/* Lookup an XYZ or Lab color */
+static void lookup(
+mpp *p, /* This */
+double *out, /* Returned XYZ or Lab */
+double *in /* Input device values */
+) {
+ if (p->spc == NULL) {
+ double *Lab;
+ double *XYZ;
+
+ if (p->pcs == icSigLabData) {
+ Lab = out;
+ XYZ = NULL;
+ } else {
+ Lab = NULL;
+ XYZ = out;
+ }
+
+ forward(p, NULL, Lab, XYZ, in);
+
+ return;
+ } else {
+ xspect tspec;
+
+ p->lookup_spec(p, &tspec, in);
+ p->spc->convert(p->spc, out, &tspec);
+ }
+}
+
+/* Lookup an XYZ or Lab color, plus the partial derivative. */
+/* This is useful if the lookup is being used within */
+/* a minimisation routine */
+static void dlookup(
+mpp *p,
+double *out, /* Return the XYZ or Lab */
+double **dout, /* Return the partial derivative dout[3][n] */
+double *dev) {
+ int i, j, k;
+
+#ifdef SHARPEN
+ /* Can't handle this without converting from sharpened derivative */
+ /* to XYZ derivative. ~~~~~~ */
+#endif
+ /* We can't handle derivative using FWA, so */
+ /* always compute from the XYZ model values. */
+ for (j = 0; j < 3; j++) { /* Compute each bands value */
+ out[j] = dbandval(p, dout[j], j, dev);
+ }
+ if (p->pcs == icSigLabData) {
+ double dlab[3][3];
+
+ icxdXYZ2Lab(&icmD50, out, dlab, out);
+
+ /* Apply Lab deriv to dout */
+ for (i = 0; i < p->n; i++) {
+ double tt[3];
+
+ for (k = 0; k < 3; k++)
+ tt[k] = dout[k][i];
+
+ for (j = 0; j < 3; j++) {
+ dout[j][i] = 0.0;
+
+ for (k = 0; k < 3; k++) {
+ dout[j][i] += dlab[j][k] * tt[k];
+ }
+ }
+ }
+ }
+}
+
+
+/* Get the white and black points */
+static void get_wb(
+mpp *p, /* This */
+double *white,
+double *black,
+double *kblack /* K only black */
+) {
+ if (white != NULL) {
+ if (p->spc == NULL) {
+ white[0] = p->white.band[0];
+ white[1] = p->white.band[1];
+ white[2] = p->white.band[2];
+#ifdef SHARPEN
+ sharp2XYZ(&white[0], &white[1], &white[2]);
+#endif
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&icmD50, white, white);
+ } else {
+ int j;
+ xspect ispect;
+
+ ispect.norm = p->norm;
+ ispect.spec_n = p->spec_n;
+ ispect.spec_wl_short = p->spec_wl_short;
+ ispect.spec_wl_long = p->spec_wl_long;
+ for (j = 0; j < p->spec_n; j++)
+ ispect.spec[j] = p->white.band[3+j];
+
+ p->spc->convert(p->spc, white, &ispect);
+ }
+ }
+ if (black != NULL) {
+ if (p->spc == NULL) {
+ black[0] = p->black.band[0];
+ black[1] = p->black.band[1];
+ black[2] = p->black.band[2];
+#ifdef SHARPEN
+ sharp2XYZ(&black[0], &black[1], &black[2]);
+#endif
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&icmD50, black, black);
+ } else {
+ int j;
+ xspect ispect;
+
+ ispect.norm = p->norm;
+ ispect.spec_n = p->spec_n;
+ ispect.spec_wl_short = p->spec_wl_short;
+ ispect.spec_wl_long = p->spec_wl_long;
+ for (j = 0; j < p->spec_n; j++)
+ ispect.spec[j] = p->black.band[3+j];
+
+ p->spc->convert(p->spc, black, &ispect);
+ }
+ }
+
+ if (kblack != NULL) {
+ if (p->spc == NULL) {
+ kblack[0] = p->kblack.band[0];
+ kblack[1] = p->kblack.band[1];
+ kblack[2] = p->kblack.band[2];
+#ifdef SHARPEN
+ sharp2XYZ(&kblack[0], &kblack[1], &kblack[2]);
+#endif
+ if (p->pcs == icSigLabData)
+ icmXYZ2Lab(&icmD50, kblack, kblack);
+ } else {
+ int j;
+ xspect ispect;
+
+ ispect.norm = p->norm;
+ ispect.spec_n = p->spec_n;
+ ispect.spec_wl_short = p->spec_wl_short;
+ ispect.spec_wl_long = p->spec_wl_long;
+ for (j = 0; j < p->spec_n; j++)
+ ispect.spec[j] = p->kblack.band[3+j];
+
+ p->spc->convert(p->spc, kblack, &ispect);
+ }
+ }
+}
+
+/* Lookup an XYZ value. */
+/* (Note that this is never FWA compensated) */
+static void lookup_xyz(
+mpp *p, /* This */
+double *out, /* Returned XYZ value */
+double *in /* Input device values */
+) {
+ forward(p, NULL, NULL, out, in);
+}
+
+/* Lookup a spectral value. */
+/* (Note that this is never FWA compensated) */
+static void lookup_spec(
+mpp *p, /* This */
+xspect *out, /* Returned spectral value */
+double *in /* Input device values */
+) {
+ int j;
+
+ out->norm = p->norm;
+ out->spec_n = p->spec_n;
+ out->spec_wl_short = p->spec_wl_short;
+ out->spec_wl_long = p->spec_wl_long;
+
+ forward(p, out->spec, NULL, NULL, in);
+
+ for (j = 0; j < p->spec_n; j++)
+ out->spec[j] *= out->norm;
+}
+
+/* Macros for an arbitrary dimensional counter */
+/* Declare the counter name nn, dimensions di, & count */
+
+#define DCOUNT(nn, di, start, reset, count) \
+ int nn[MAX_CHAN]; /* counter value */ \
+ int nn##_di = (di); /* Number of dimensions */ \
+ int nn##_stt = (start); /* start count value */ \
+ int nn##_rst = (reset); /* reset on carry value */ \
+ int nn##_res = (count); /* last count +1 */ \
+ int nn##_e /* dimension index */
+
+/* Set the counter value to 0 */
+#define DC_INIT(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) \
+ nn[nn##_e] = nn##_stt; \
+ nn##_e = 0; \
+}
+
+/* Increment the counter value */
+#define DC_INC(nn) \
+{ \
+ for (nn##_e = 0; nn##_e < nn##_di; nn##_e++) { \
+ nn[nn##_e]++; \
+ if (nn[nn##_e] < nn##_res) \
+ break; /* No carry */ \
+ nn[nn##_e] = nn##_rst; \
+ } \
+}
+
+/* After increment, expression is TRUE if counter is done */
+#define DC_DONE(nn) \
+ (nn##_e >= nn##_di)
+
+/* Create a gamut */
+/* (This will be in the current PCS) */
+static gamut *mpp_gamut(
+mpp *p, /* This */
+double detail /* gamut detail level, 0.0 = def */
+) {
+ gamut *gam;
+ int res; /* Sample point resolution */
+ double white[3], black[3], kblack[3];
+ DCOUNT(co, p->n, 0, 0, 2);
+
+ if (detail == 0.0)
+ detail = 10.0;
+
+ gam = new_gamut(detail, 0, 0); /* Lab only at the moment */
+
+ /* Explore the gamut by itterating through */
+ /* it with sample points in device space. */
+
+ res = (int)(100.0/detail); /* Establish an appropriate sampling density */
+
+ if (res < 3)
+ res = 3;
+
+ DC_INIT(co);
+
+ /* Itterate over all the 2 faces in the device space. */
+ /* We're assuming in practice that only colors lying */
+ /* on such faces contribute to the gamut volume. */
+ /* The total number of faces explored will be */
+ /* (dim * (dim-1))/2 * 2 ^ (dim-2) */
+ /* It seems possible that a number of these faces could */
+ /* be cheaply culled by examining the PCS corner values */
+ /* for each 2^(dim-2) combinations, and skiping those. */
+ /* that cannot possibly expand the gamut ? */
+ /* ie. that they are clearly contained by other face combinations. */
+ while(!DC_DONE(co)) {
+ int e, m1, m2;
+ double in[MAX_CHAN];
+ double out[3];
+ double sum;
+
+ /* Check the ink limit */
+ for (sum = 0.0, e = 0; e < p->n; e++)
+ sum += (double)co[e];
+
+ if (p->limit > 1e-4 && (sum - 1.0) > p->limit) {
+ DC_INC(co);
+ continue; /* Skip points really over limit */
+ }
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < p->n; m1++) {
+ if (co[m1] != 0)
+ continue;
+ for (m2 = m1 + 1; m2 < p->n; m2++) {
+ int x, y;
+
+ if (co[m2] != 0)
+ continue;
+
+ for (e = 0; e < p->n; e++)
+ in[e] = (double)co[e]; /* Base value */
+
+ for (x = 0; x < res; x++) { /* step over surface */
+ in[m1] = x/(res - 1.0);
+ for (y = 0; y < res; y++) {
+ double ssum, iin[MAX_CHAN];
+ in[m2] = y/(res - 1.0);
+ ssum = sum + in[m1] + in[m2];
+ if (p->limit > 1e-4 && (ssum - 1.0) > p->limit) {
+ continue;
+ }
+
+ for (e = 0; e < p->n; e++)
+ iin[e] = in[e]; /* Scalable copy */
+
+ /* Apply ink limit by simple scaling */
+ if (p->limit > 1e-4 && ssum > p->limit) {
+ for (e = 0; e < p->n; e++)
+ iin[e] *= p->limit/ssum;
+ }
+
+ forward(p, NULL, out, NULL, iin);
+ gam->expand(gam, out);
+ }
+ }
+ }
+ }
+
+ /* Increment index within block */
+ DC_INC(co);
+ }
+
+ /* set the white and black points */
+ p->get_wb(p, white, black, kblack);
+ gam->setwb(gam, white, black, kblack);
+
+ /* Set the cusp points */
+ /* Do this by scanning just 0 & 100% colorant combinations */
+
+ res = 2;
+ gam->setcusps(gam, 0, NULL);
+ DC_INIT(co);
+
+ /* Itterate over all the faces in the device space */
+ while(!DC_DONE(co)) {
+ int e, m1, m2;
+ double in[MAX_CHAN];
+ double out[3];
+ double sum;
+
+ /* Check the ink limit */
+ for (sum = 0.0, e = 0; e < p->n; e++)
+ sum += (double)co[e];
+
+ if (p->limit > 1e-4 && (sum - 1.0) > p->limit) {
+ DC_INC(co);
+ continue; /* Skip points really over limit */
+ }
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < p->n; m1++) {
+ if (co[m1] != 0)
+ continue;
+ for (m2 = m1 + 1; m2 < p->n; m2++) {
+ int x, y;
+
+ if (co[m2] != 0)
+ continue;
+
+ for (e = 0; e < p->n; e++)
+ in[e] = (double)co[e]; /* Base value */
+
+ for (x = 0; x < res; x++) { /* step over surface */
+ in[m1] = x/(res - 1.0);
+ for (y = 0; y < res; y++) {
+ double ssum, iin[MAX_CHAN];
+ in[m2] = y/(res - 1.0);
+ ssum = sum + in[m1] + in[m2];
+ if (p->limit > 1e-4 && (ssum - 1.0) > p->limit) {
+ continue;
+ }
+
+ for (e = 0; e < p->n; e++)
+ iin[e] = in[e]; /* Scalable copy */
+
+ /* Apply ink limit by simple scaling */
+ if (p->limit > 1e-4 && ssum > p->limit) {
+ for (e = 0; e < p->n; e++)
+ iin[e] *= p->limit/ssum;
+ }
+
+ forward(p, NULL, out, NULL, iin);
+ gam->setcusps(gam, 1, out);
+ }
+ }
+ }
+ }
+
+ /* Increment index within block */
+ DC_INC(co);
+ }
+ gam->setcusps(gam, 2, NULL);
+
+ return gam;
+}
+
+/* Delete it */
+static void del_mpp(mpp *p) {
+ if (p != NULL) {
+ del_mppcol(&p->white, p->n, p->spec_n);
+ del_mppcol(&p->black, p->n, p->spec_n);
+ del_mppcol(&p->kblack, p->n, p->spec_n);
+ del_mppcols(p->cols, p->nodp, p->n, p->spec_n); /* Delete array of target points */
+ if (p->spc != NULL)
+ p->spc->del(p->spc);
+
+ /* Delete shape parameters */
+ if (p->shape != NULL) {
+ int i, j;
+ for (j = 0; j < p->n; j++) {
+ if (p->shape[j] != NULL) {
+ for (i = 0; i < p->nn; i++) {
+ if (p->shape[j][i] != NULL)
+ free(p->shape[j][i]);
+ }
+ free(p->shape[j]);
+ }
+ }
+ free(p->shape);
+ }
+ free(p);
+ }
+}
+
+/* Allocate a new, uninitialised mpp */
+/* Note thate black and white points aren't allocated */
+mpp *new_mpp(void) {
+ mpp *p;
+
+ if ((p = (mpp *)calloc(1, sizeof(mpp))) == NULL)
+ return NULL;
+
+ p->pcs = icSigXYZData;
+
+ /* Init method pointers */
+ p->del = del_mpp;
+ p->create = create;
+ p->get_gamut = mpp_gamut;
+ p->write_mpp = write_mpp;
+ p->read_mpp = read_mpp;
+ p->get_info = get_info;
+ p->set_ilob = set_ilob;
+ p->get_wb = get_wb;
+ p->lookup = lookup;
+ p->dlookup = dlookup;
+ p->lookup_xyz = lookup_xyz;
+ p->lookup_spec = lookup_spec;
+
+ return p;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Utility functions */
+
+/* Allocate the data portion of an mppcol */
+/* Return NZ if malloc error */
+int new_mppcol(
+mppcol *p, /* mppcol to allocate */
+int n, /* Number of inks */
+int nb /* Number of spectral bands */
+) {
+ int nn = (1 << n); /* Number of ink combinations */
+
+ if ((p->nv = (double *)malloc(sizeof(double) * n)) == NULL) {
+ del_mppcol(p, n, nb);
+ return 1;
+ }
+ if ((p->band = (double *)malloc(sizeof(double) * (3 + nb))) == NULL) {
+ del_mppcol(p, n, nb);
+ return 1;
+ }
+ if ((p->lband = (double *)malloc(sizeof(double) * (3 + nb))) == NULL) {
+ del_mppcol(p, n, nb);
+ return 1;
+ }
+ if ((p->tcnv = (double *)calloc(n, sizeof(double))) == NULL) {
+ del_mppcol(p, n, nb);
+ return 1;
+ }
+ if ((p->scnv = (double *)calloc(n, sizeof(double))) == NULL) {
+ del_mppcol(p, n, nb);
+ return 1;
+ }
+ if ((p->pcnv = (double *)malloc(nn * sizeof(double))) == NULL) {
+ del_mppcol(p, n, nb);
+ return 1;
+ }
+ if ((p->fcnv = (double *)malloc(n * nn/2 * sizeof(double))) == NULL) {
+ del_mppcol(p, n, nb);
+ return 1;
+ }
+ return 0;
+}
+
+/* Copy the contents of one mppcol to another */
+void copy_mppcol(
+mppcol *d, /* Destination */
+mppcol *s, /* Source */
+int n, /* Number of inks */
+int nb /* Number of spectral bands */
+) {
+ mppcol al;
+ int nn = (1 << n); /* Number of ink combinations */
+ int i, j;
+
+ al = *d; /* Copy destinations allocations */
+ *d = *s; /* Copy source contents & pointers */
+
+ /* Now fixup allocation addresses */
+ d->nv = al.nv;
+ d->band = al.band;
+ d->lband = al.lband;
+ d->tcnv = al.tcnv;
+ d->scnv = al.scnv;
+ d->pcnv = al.pcnv;
+ d->fcnv = al.fcnv;
+
+ /* Copy contents of allocated data */
+ for (j = 0; j < n; j++)
+ d->nv[j] = s->nv[j];
+
+ for (j = 0; j < (3+nb); j++)
+ d->band[j] = s->band[j];
+
+ for (j = 0; j < (3+nb); j++)
+ d->lband[j] = s->lband[j];
+
+ for (i = 0; i < n; i++)
+ d->tcnv[i] = s->tcnv[i];
+
+ for (i = 0; i < n; i++)
+ d->scnv[i] = s->scnv[i];
+
+ for (i = 0; i < nn; i++)
+ d->pcnv[i] = s->pcnv[i];
+
+ for (i = 0; i < (n * nn/2); i++)
+ d->fcnv[i] = s->fcnv[i];
+}
+
+
+/* Free the data allocation of an mppcol */
+void del_mppcol(
+mppcol *p,
+int n, /* Number of inks */
+int nb /* Number of spectral bands */
+) {
+ if (p != NULL) {
+ if (p->nv != NULL)
+ free (p->nv);
+
+ if (p->band != NULL)
+ free (p->band);
+
+ if (p->lband != NULL)
+ free (p->lband);
+
+ if (p->tcnv != NULL)
+ free (p->tcnv);
+
+ if (p->scnv != NULL)
+ free (p->scnv);
+
+ if (p->pcnv != NULL)
+ free (p->pcnv);
+
+ if (p->fcnv != NULL)
+ free (p->fcnv);
+ }
+}
+
+/* Allocate an array of mppcol */
+/* Return NULL if malloc error */
+mppcol *new_mppcols(
+int no, /* Number in array */
+int n, /* Number of inks */
+int nb /* Number of spectral bands */
+) {
+ mppcol *p;
+ int i;
+
+ if ((p = (mppcol *)calloc(no, sizeof(mppcol))) == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < no; i++) {
+ if (new_mppcol(&p[i], n, nb) != 0) {
+ del_mppcols(p, no, n, nb);
+ return NULL;
+ }
+ }
+
+ return p;
+}
+
+/* Free an array of mppcol */
+void del_mppcols(
+mppcol *p,
+int no, /* Number in array */
+int n, /* Number of inks */
+int nb /* Number of spectral bands */
+) {
+ if (p != NULL) {
+ int i;
+
+ for (i = 0; i < no; i++)
+ del_mppcol(&p[i], n, nb);
+ free (p);
+ }
+}
+
+/* Allocate and setup the extra shape parameters combinations */
+static void init_shape(mpp *p) {
+ int i, j, k;
+ int ix[MPP_MXINKS];
+
+ /* First allocate the shape parameter array */
+
+ if ((p->shape = (double ***)malloc(p->n * sizeof(double **))) == NULL)
+ error("Malloc failed (mpp shape)!");
+ for (j = 0; j < p->n; j++) {
+ if ((p->shape[j] = (double **)malloc(p->nn * sizeof(double *))) == NULL)
+ error("Malloc failed (mpp shape)!");
+ for (i = 0; i < p->nn; i++) {
+ if ((i & (1 << j)) == 0) { /* Valid combo for this ink */
+ if ((p->shape[j][i] = (double *)malloc((3+p->spec_n) * sizeof(double))) == NULL)
+ error("Malloc failed (mpp shape)!");
+ for (k = 0; k < (3+p->spec_n); k++)
+ p->shape[j][i][k] = 0.0; /* Initial shape value */
+ } else {
+ p->shape[j][i] = NULL;
+ }
+ }
+ }
+
+ /* Setup sparse to full and back indexing lookup */
+ for (j = 0; j < p->n; j++)
+ ix[j] = 0;
+
+ for (i = 0; i < p->nn; i++) {
+ for (j = 0; j < p->n; j++) {
+ p->f2c[j][i] = j * p->nn/2 + ix[j];
+ if ((i & (1 << j)) == 0) {
+ p->c2f[j * p->nn/2 + ix[j]].ink = j;
+ p->c2f[j * p->nn/2 + ix[j]].comb = i;
+ ix[j]++;
+ }
+ }
+ }
+
+#ifdef NEVER
+ /* Print result */
+ for (j = 0; j < p->n; j++) {
+ for (i = 0; i < p->nn; i++) {
+ printf("f2c[%d][%d] = %d\n", j,i,p->f2c[j][i]);
+ }
+ for (i = 0; i < p->nn/2; i++) {
+ printf("c2f[%d].ink,comb = %d, %d\n",
+ j * p->nn/2 + i,p->c2f[j * p->nn/2 + i].ink,
+ p->c2f[j * p->nn/2 + i].comb);
+ }
+ }
+#endif /* NEVER */
+}
+
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Creation helper functions */
+
+/* Per band error metric */
+
+/* Convert argument to L* like scale */
+#define lDE(aa) ((aa) > 0.008856451586 ? 116.0 * pow((aa),1.0/3.0) - 16.0 : (aa) * 903.2962896)
+
+/* Function to approximate visible difference in an XYZ or spectral difference */
+static double DEsq(double aa, double bb) {
+ double dd;
+
+ /* Convert input to L* like value */
+ aa = lDE(aa);
+ bb = lDE(bb);
+
+ dd = aa - bb;
+
+ return dd * dd;
+}
+
+/* Convert argument to the derivative of the DEsq function at that value */
+#define dDE(aa) ((aa) > 0.008856451586 ? 38.666667 * pow((aa), -2.0/3.0) : 903.2962896)
+
+
+/* Given a device value, return the given bands value */
+/* according to the current model. */
+static double bandval(mpp *p, int band, double *dev) {
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int m, k;
+ double ov;
+ int j = band;
+
+ /* Compute the tranfer corrected device values */
+ for (m = 0; m < p->n; m++) {
+ tcnv[m] = icxTransFunc(p->tc[m][j], p->cord, dev[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ }
+
+ if (p->useshape) {
+
+ for (m = 0; m < p->n; m++)
+ ww[m] = 0.0;
+
+ /* Lookup the shape values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ for (m = 0; m < p->n; m++) {
+ ww[m] += p->shape[m][k & ~(1<<m)][j] * vv;
+ /* Apply weighting to shape vertex value */
+ }
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double vv = tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ tcnv[m] = vv;
+ tcnv1[m] = 1.0 - vv;
+ }
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double vv = p->pc[k][j];
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ return ov;
+}
+
+/* Given a device value, return the given bands value */
+/* according to the current model, as well as the partial */
+/* derivative wrt the device values. */
+static double dbandval(mpp *p, double *dv, int band, double *dev) {
+
+ double dtcnv_ddev[MPP_MXINKS]; /* Del in tcnv[m] due to del dev[m] */
+ double dww_dtcnv[MPP_MXINKS][MPP_MXINKS]; /* Del in ww[m] due to del in tcnv[m] */
+ double dtcnv_tc[MPP_MXINKS]; /* Del in tcnv'[m] due to del in tcnv[m] */
+ double dtcnv_ww[MPP_MXINKS]; /* Del in tcnv'[m] due to del in ww[m] */
+ double dov[MPP_MXINKS]; /* Del of ov due to del in tcnv'[m] */
+
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int m, k;
+ double ov;
+ int j = band;
+
+ /* Compute the tranfer corrected device values */
+ for (m = 0; m < p->n; m++) {
+ tcnv[m] = icxdiTransFunc(p->tc[m][j], &dtcnv_ddev[m], p->cord, dev[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ ww[m] = 0.0;
+ }
+
+ /* Lookup the shape values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ for (m = 0; m < p->n; m++) {
+ ww[m] += p->shape[m][k & ~(1<<m)][j] * vv;
+ /* Apply weighting to shape vertex value */
+ }
+ }
+
+ /* Compute del ww[m][m] for del tcnv[m] */
+ for (m = 0; m < p->n; m++) { /* For each input channel were doing del of */
+ int mo;
+ for (mo = 0; mo < p->n; mo++)
+ dww_dtcnv[mo][m] = 0.0;
+ for (k = 0; k < p->nn; k++) {
+ int mm;
+ double vv = 1.0;
+ for (mm = 0; mm < p->n; mm++) { /* Compute weight for node k */
+ if (m == mm)
+ continue;
+ if (k & (1 << mm))
+ vv *= tcnv[mm];
+ else
+ vv *= tcnv1[mm];
+ }
+ for (mo = 0; mo < p->n; mo++) { /* For each output channel */
+ double vvv = vv * p->shape[mo][k & ~(1<<mo)][j];
+ if (k & (1 << m))
+ dww_dtcnv[mo][m] += vvv;
+ else
+ dww_dtcnv[mo][m] -= vvv;
+ }
+ }
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double tt;
+ double gg = ww[m]; /* Curve adjustment */
+ double sv, dsv, vv = tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ tt = gg - gg * vv + 1.0;
+ sv = vv/tt;
+ dsv = (gg + 1.0)/(tt * tt);
+ } else {
+ tt = 1.0 - gg * vv;
+ sv = (vv - gg * vv)/tt;
+ dsv = (1.0 - gg)/(tt * tt);
+ }
+ tcnv[m] = sv;
+ tcnv1[m] = 1.0 - sv;
+ dtcnv_tc[m] = dsv; /* del in tcnv[m] due to del in tcnv[m] */
+ dtcnv_ww[m] = (vv * vv - vv)/(tt * tt); /* del in tcnv[m] due to del in ww[m] */
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double vv = p->pc[k][j];
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ /* Compute del ov for del tcnv[m] */
+ for (m = 0; m < p->n; m++) {
+ for (dov[m] = 0.0, k = 0; k < p->nn; k++) {
+ int mm;
+ double vv = p->pc[k][j];
+ for (mm = 0; mm < p->n; mm++) {
+ if (m == mm)
+ continue;
+ if (k & (1 << mm))
+ vv *= tcnv[mm];
+ else
+ vv *= tcnv1[mm];
+ }
+ if (k & (1 << m))
+ dov[m] += vv;
+ else
+ dov[m] -= vv;
+ }
+ }
+
+ /* Accumulate delta from input value to output */
+ for (m = 0; m < p->n; m++) {
+ double ttt;
+ int mm;
+
+ /* delta via dww */
+ for (ttt = 0.0, mm = 0; mm < p->n; mm++)
+ ttt += dov[mm] * dtcnv_ww[mm] * dww_dtcnv[mm][m] * dtcnv_ddev[m];
+
+ /* delta direct */
+ dv[m] = ttt + dov[m] * dtcnv_tc[m] * dtcnv_ddev[m];
+ }
+
+ return ov;
+}
+
+/* Given a device value, return the XYZ, Lab and spectral */
+/* values according to the current model. */
+/* Pointer may be NULL if result is not needed */
+static void forward(mpp *p, double *spec, double *Lab, double *XYZ, double *dev) {
+ double tXYZ[3];
+ int sb = 3, eb = 3; /* Start and end bands to compute */
+ int j;
+
+ if (XYZ != NULL || Lab != NULL)
+ sb = 0;
+ if (spec != NULL)
+ eb = 3 + p->spec_n;
+
+ for (j = sb; j < eb; j++) { /* Compute each bands value */
+ double ov;
+
+ ov = bandval(p, j, dev);
+
+ if (j < 3)
+ tXYZ[j] = ov;
+ else
+ spec[j-3] = ov;
+ }
+
+#ifdef SHARPEN
+ if (sb == 0)
+ sharp2XYZ(&tXYZ[0], &tXYZ[1], &tXYZ[2]);
+#endif
+ if (XYZ != NULL) {
+ XYZ[0] = tXYZ[0];
+ XYZ[1] = tXYZ[1];
+ XYZ[2] = tXYZ[2];
+ }
+ if (Lab != NULL) {
+ icmXYZ2Lab(&icmD50, Lab, tXYZ); /* Convert D50 Lab */
+ }
+}
+
+/* Return the specified bands current average error */
+static void banderr(
+mpp *p,
+double *avese, /* Return average Error from spectral bands */
+double *maxse, /* Return maximum Error from spectral bands */
+int band
+) {
+ double serr = 0.0, smax = 0.0;
+ int i;
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ double spv;
+ mppcol *c = &p->cols[i];
+
+ /* Compute models output */
+ spv = bandval(p, band, c->nv);
+ spv = sqrt(DEsq(c->band[band], spv));
+
+ if (spv > smax)
+ smax = spv;
+ serr += spv;
+ }
+
+ if (avese != NULL)
+ *avese = serr/((double)p->nodp);
+ if (maxse != NULL)
+ *maxse = smax;
+}
+
+/* Figure out what the current model errors are and return them */
+static void deltae(
+mpp *p,
+double *avede, /* Return average Delta E from XYZ bands */
+double *maxde, /* Return maximum Delta E from XYZ bands */
+double *avese, /* Return average Error from spectral bands */
+double *maxse /* Return maximum Error from spectral bands */
+) {
+ double spec[MPP_MXBANDS]; /* spectral value for each point */
+ double Lab[3];
+ double err = 0.0, max = 0.0; /* Delta E */
+ double serr = 0.0, smax = 0.0; /* Delta S */
+ int i, j;
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ double ee;
+ mppcol *c = &p->cols[i];
+
+ /* Compute models output */
+ forward(p, p->spec_n > 0 ? spec : NULL, Lab, c->cXYZ, c->nv);
+
+ /* Track the Delta E */
+ c->err = icmLabDEsq(Lab, c->Lab);
+ ee = sqrt(c->err);
+ if (ee > max)
+ max = ee;
+ err += ee;
+
+ /* Track the spectral error */
+ for (j = 0; j < p->spec_n; j++) {
+ ee = DEsq(c->band[3+j], spec[j]);
+ ee = sqrt(ee);
+ if (ee > smax)
+ smax = ee;
+ serr += ee;
+ }
+ }
+
+ if (avede != NULL)
+ *avede = err/((double)p->nodp);
+ if (maxde != NULL)
+ *maxde = max;
+
+ if (p->spec_n > 0 && avese != NULL)
+ *avese = serr/(((double)p->nodp) * ((double)p->spec_n));
+ if (maxse != NULL)
+ *maxse = smax;
+}
+
+/* - - - - - - - - - - - - - - - */
+/* Powell optimisation callbacks */
+
+/* Progress reporter for mpp powell/conjgrad */
+static void mppprog(void *pdata, int perc) {
+ mpp *p = (mpp *)pdata;
+
+ if (p->verb) {
+ printf("%c% 3d%%",cr_char,perc);
+ if (perc == 100)
+ printf("\n");
+ fflush(stdout);
+ }
+}
+
+#ifdef NEVER // Skip efunc1 passes for now.
+
+/* Setup test point data ready for efunc1 on the given och and oba */
+static void sfunc1(mpp *p) {
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ int k = p->och; /* Channel being optimised */
+ int j = p->oba; /* Band being optimised */
+ int i, m;
+
+ /* Pre-compute combination weighting and colorant combination values */
+ /* for this band, without this device channels contribution. */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ int kk;
+
+ /* Compute the tranfer corrected device values */
+ for (m = 0; m < p->n; m++) {
+ tcnv[m] = icxTransFunc(p->tc[m][j], p->cord, c->nv[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ }
+
+ /* Compute the test point primary combination values */
+ c->tpcnv = c->tpcnv1 = 0.0;
+ for (kk = 0; kk < p->nn; kk++) { /* Combination value */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) {
+ if (m == k)
+ continue; /* Multiply this in efunc1 */
+ if (kk & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ if (kk & (1 << k))
+ c->tpcnv += vv * p->pc[kk][j];
+ else
+ c->tpcnv1 += vv * p->pc[kk][j];
+ }
+ }
+}
+
+#endif /* NEVER */
+
+#ifdef NEVER // Skip efunc1 passes for now.
+/* Optimise a device transfer curve to minimise a particular bands error */
+/* (Assume no shape parameters) */
+static double efunc1(void *adata, double pv[]) {
+ mpp *p = (mpp *)adata;
+ double smv, rv = 0.0;
+ double tcnv; /* Transfer curve corrected device values */
+ int k = p->och; /* Channel being optimised */
+ int j = p->oba; /* Band being optimised */
+ int pc, m, i;
+
+ /* For each test point */
+ for (pc = m = 0; m < p->nodp; m++) {
+ mppcol *c = &p->cols[m];
+ double vv;
+
+ if (c->w < 1e-6)
+ continue; /* Skip zero weighted points */
+
+ /* Compute the tranfer corrected device values */
+ tcnv = icxTransFunc(pv, p->cord, c->nv[k]);
+
+ /* Compute band value */
+ vv = tcnv * c->tpcnv + (1.0 - tcnv) * c->tpcnv1;
+
+ /* Compute the band value error */
+ vv = lDE(vv) - c->lband[j];
+ rv += c->w * vv * vv;
+ pc++;
+ }
+ rv /= (double)pc;
+
+ /* Compute average magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ for (smv = 0.0, m = 0; m < p->cord; m++) {
+ smv += pv[m] * pv[m];
+ }
+ smv /= (double)(p->cord);
+ rv += 0.01 * smv;
+
+#ifdef DEBUG
+ printf("efunc1 itt %d/%d chan %d band %d k0 %f returning %f\n",p->oit,p->ott,k,j,pv[0],rv);
+#endif
+ return rv;
+}
+#endif /* NEVER */
+
+/* Optimise all transfer curves simultaniously to minimise a particular bands error */
+static double efunc2(void *adata, double pv[]) {
+ mpp *p = (mpp *)adata;
+ double smv, rv = 0.0;
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int j = p->oba; /* Band being optimised */
+ int i, m, k;
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double ov;
+
+ /* Compute the tranfer corrected device values */
+ for (m = 0; m < p->n; m++) {
+ tcnv[m] = icxTransFunc(&pv[m * p->cord], p->cord, c->nv[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ }
+
+ if (p->useshape) {
+
+ for (m = 0; m < p->n; m++)
+ ww[m] = 0.0;
+
+ /* Lookup the shape values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ for (m = 0; m < p->n; m++) {
+ ww[m] += p->shape[m][k & ~(1<<m)][j] * vv;
+ /* Apply weighting to shape vertex value */
+ }
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double vv = tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ tcnv[m] = vv;
+ tcnv1[m] = 1.0 - vv;
+ }
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double vv = p->pc[k][j];
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ /* Compute the band value error */
+ ov = lDE(ov) - c->lband[j];
+ rv += ov * ov;
+ }
+
+ rv /= (double)p->nodp;
+
+ /* Compute weighted magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ for (smv = 0.0, m = 0; m < p->n; m++) {
+ double w;
+ for (k = 0; k < p->cord; k++) {
+ i = m * p->cord + k;
+ w = (k < 2) ? TRANS_BASE : k * TRANS_HBASE; /* Increase weight with harmonics */
+ smv += w * pv[i] * pv[i];
+ }
+ }
+ smv /= (double)(p->n);
+ rv += smv;
+
+#ifdef DEBUG
+ printf("efunc2 itt %d/%d band %d returning %f\n",p->oit,p->ott,j,rv);
+#endif
+ return rv;
+}
+
+/* Return the gradient of the minimisation function at the given location, */
+/* as well as the function value at this location. */
+static double dfunc2(void *adata, double dv[], double pv[]) {
+ mpp *p = (mpp *)adata;
+ double smv, tt, rv = 0.0;
+ double dtcnv_dpv[MPP_MXINKS][MPP_MXTCORD]; /* Del in tcnv[m] due to del in parameter */
+ double dww_dtcnv[MPP_MXINKS][MPP_MXINKS]; /* Del in ww[m] due to del in tcnv[m] */
+ double dtcnv_tc[MPP_MXINKS]; /* Del in tcnv'[m] due to del in tcnv[m] */
+ double dtcnv_ww[MPP_MXINKS]; /* Del in tcnv'[m] due to del in ww[m] */
+ double dov[MPP_MXINKS]; /* Del of ov due to del in tcnv'[m] */
+ double ddov; /* Del in final ov due to del in raw ov */
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int j = p->oba; /* Band being optimised */
+ int i, m, k;
+
+ for (k = 0; k < (p->n * p->cord); k++)
+ dv[k] = 0.0;
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ int mo;
+ mppcol *c = &p->cols[i];
+ double ov;
+
+ /* Compute the tranfer corrected device values */
+ /* and del in these values due to del in input parameters */
+ for (m = 0; m < p->n; m++) {
+ tcnv[m] = icxdpTransFunc(&pv[m * p->cord], dtcnv_dpv[m], p->cord, c->nv[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ }
+
+#ifdef NEVER
+{
+for (m = 0; m < p->n; m++) {
+ int ii;
+ double ttt;
+
+ for (ii = 0; ii < p->cord; ii++) {
+ pv[m * p->cord + ii] += 1e-6;
+ ttt = (icxTransFunc(&pv[m * p->cord], p->cord, c->nv[m]) - tcnv[m])/1e-6;
+ pv[m * p->cord + ii] -= 1e-6;
+ printf("~1 chan %d cord %d is %f ref %f\n",m,ii,dtcnv_dpv[m][ii],ttt);
+ }
+}
+}
+#endif
+ for (m = 0; m < p->n; m++)
+ ww[m] = 0.0;
+
+ /* Lookup the shape values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ for (m = 0; m < p->n; m++) {
+ ww[m] += p->shape[m][k & ~(1<<m)][j] * vv;
+ /* Apply weighting to shape vertex value */
+ }
+ }
+
+ /* Compute del ww[m][m] for del tcnv[m] */
+ for (m = 0; m < p->n; m++) { /* For each input channel were doing del of */
+ for (mo = 0; mo < p->n; mo++)
+ dww_dtcnv[mo][m] = 0.0;
+ for (k = 0; k < p->nn; k++) {
+ int mm;
+ double vv = 1.0;
+ for (mm = 0; mm < p->n; mm++) { /* Compute weight for node k */
+ if (m == mm)
+ continue;
+ if (k & (1 << mm))
+ vv *= tcnv[mm];
+ else
+ vv *= tcnv1[mm];
+ }
+ for (mo = 0; mo < p->n; mo++) { /* For each output channel */
+ double vvv = vv * p->shape[mo][k & ~(1<<mo)][j];
+ if (k & (1 << m))
+ dww_dtcnv[mo][m] += vvv;
+ else
+ dww_dtcnv[mo][m] -= vvv;
+ }
+ }
+ }
+
+#ifdef NEVER
+{
+ int mm;
+ double tww[MPP_MXINKS][MPP_MXINKS];
+
+ for (mm = 0; mm < p->n; mm++) { /* For del in each input value */
+ tcnv[mm] += 1e-6;
+
+ for (m = 0; m < p->n; m++)
+ tww[m][mm] = 0.0;
+
+ /* Lookup the shape values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= (1.0 - tcnv[m]);
+ }
+ for (m = 0; m < p->n; m++) {
+ tww[m][mm] += p->shape[m][k & ~(1<<m)][j] * vv;
+ /* Apply weighting to shape vertex value */
+ }
+ }
+
+ tcnv[mm] -= 1e-6;
+ for (m = 0; m < p->n; m++) {
+ tww[m][mm] = (tww[m][mm] - ww[m])/1e-6;
+ }
+ }
+
+ for (mm = 0; mm < p->n; mm++) {
+ for (m = 0; m < p->n; m++) {
+ printf("~1 ww[%d][%d] %f should be %f\n",mm, m, dww_dtcnv[mm][m],tww[mm][m]);
+ }
+ }
+}
+#endif /* NEVER */
+
+#ifdef NEVER
+{
+ double itc[MPP_MXINKS];
+ double ttc[MPP_MXINKS];
+ double tww[MPP_MXINKS];
+
+ for (m = 0; m < p->n; m++) {
+ itc[m] = tcnv[m];
+ }
+#endif /* NEVER */
+
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double sv, dsv, vv = tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ tt = gg - gg * vv + 1.0;
+ sv = vv/tt;
+ dsv = (gg + 1.0)/(tt * tt);
+ } else {
+ tt = 1.0 - gg * vv;
+ sv = (vv - gg * vv)/tt;
+ dsv = (1.0 - gg)/(tt * tt);
+ }
+ tcnv[m] = sv;
+ tcnv1[m] = 1.0 - sv;
+ dtcnv_tc[m] = dsv; /* del in tcnv[m] due to del in tcnv[m] */
+ dtcnv_ww[m] = (vv * vv - vv)/(tt * tt); /* del in tcnv[m] due to del in ww[m] */
+ }
+
+
+#ifdef NEVER
+ /* Check derivatives */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double vv = itc[m]; /* Input value to be tweaked */
+
+ vv += 1e-6;
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ ttc[m] = (vv - tcnv[m])/1e-6;
+ }
+
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double vv = itc[m]; /* Input value to be tweaked */
+
+ gg += 1e-6;
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ tww[m] = (vv - tcnv[m])/1e-6;
+ }
+
+
+ for (m = 0; m < p->n; m++) {
+ printf("~1 dtcnv_tc[%d] is %f should be %f\n",m, dtcnv_tc[m], ttc[m]);
+ }
+ for (m = 0; m < p->n; m++) {
+ printf("~1 dtcnv_ww[%d] is %f should be %f\n",m, dtcnv_ww[m], tww[m]);
+ }
+}
+#endif /* NEVER */
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double vv = p->pc[k][j];
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ /* Compute del ov for del tcnv[m] */
+ for (m = 0; m < p->n; m++) {
+ for (dov[m] = 0.0, k = 0; k < p->nn; k++) {
+ int mm;
+ double vv = p->pc[k][j];
+ for (mm = 0; mm < p->n; mm++) {
+ if (m == mm)
+ continue;
+ if (k & (1 << mm))
+ vv *= tcnv[mm];
+ else
+ vv *= tcnv1[mm];
+ }
+ if (k & (1 << m))
+ dov[m] += vv;
+ else
+ dov[m] -= vv;
+ }
+ }
+
+#ifdef NEVER
+{
+ int mm;
+ double tdov[MPP_MXINKS];
+
+ for (mm = 0; mm < p->n; mm++) {
+ tcnv[mm] += 1e-6;
+
+ for (tdov[mm] = 0.0, k = 0; k < p->nn; k++) {
+ double vv = p->pc[k][j];
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= (1.0 - tcnv[m]);
+ }
+ tdov[mm] += vv;
+ }
+ tcnv[mm] -= 1e-6;
+ tdov[mm] = (tdov[mm] - ov)/1e-6;
+ }
+
+ for (m = 0; m < p->n; m++) {
+ printf("~1 dov[%d] is %f should be %f\n",m, tdov[m], dov[m]);
+ }
+}
+#endif /* NEVER */
+
+ /* Compute the band value error */
+ ddov = dDE(ov);
+ ov = lDE(ov) - c->lband[j];
+
+ ddov *= 2.0 * ov; /* del in final ov due to del in raw ov */
+ rv += ov * ov;
+
+ /* Accumulate delta from input params to output */
+ for (m = 0; m < p->n; m++) {
+ for (k = 0; k < p->cord; k++) {
+ double ttt;
+ int mm;
+
+ /* delta via dww */
+ for (ttt = 0.0, mm = 0; mm < p->n; mm++)
+ ttt += dov[mm] * dtcnv_ww[mm] * dww_dtcnv[mm][m] * dtcnv_dpv[m][k];
+
+ /* delta direct */
+ dv[m * p->cord + k] += ddov * (ttt + dov[m] * dtcnv_tc[m] * dtcnv_dpv[m][k]);
+ }
+ }
+ }
+
+ rv /= (double)p->nodp;
+ for (k = 0; k < (p->n * p->cord); k++)
+ dv[k] /= (double)p->nodp;
+
+ /* Compute weighted magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ tt = 2.0/(double)(p->n); /* Common factor */
+ for (smv = 0.0, m = 0; m < p->n; m++) {
+ double w;
+ for (k = 0; k < p->cord; k++) {
+ i = m * p->cord + k;
+ w = (k < 2) ? TRANS_BASE : k * TRANS_HBASE; /* Increase weight with harmonics */
+ dv[i] += w * tt * pv[i]; /* Del in rv due to del in pv */
+ smv += w * pv[i] * pv[i];
+ }
+ }
+ smv /= (double)(p->n);
+ rv += smv;
+
+#ifdef DEBUG
+ printf("dfunc2 itt %d/%d band %d returning %f\n",p->oit,p->ott,j,rv);
+#endif
+ return rv;
+}
+
+#ifdef TESTDFUNC
+/* Check that dfunc2 returns the right values */
+static void test_dfunc2(
+mpp *p,
+int nparms,
+double *pv
+) {
+ int i, j, k;
+ double refov;
+ double refdv[MPP_MXINKS * MPP_MXTCORD];
+ double ov;
+ double dv[MPP_MXINKS * MPP_MXTCORD];
+
+ /* Create reference dvs */
+ refov = efunc2((void *)p, pv);
+ for (i = 0; i < nparms; i++) {
+ pv[i] += 1e-6;
+ refdv[i] = (efunc2((void *)p, pv) - refov)/1e-6;
+ pv[i] -= 1e-6;
+ }
+
+ /* Check dfunc2 */
+ ov = dfunc2((void *)p, dv, pv);
+
+ printf("~#############################################\n");
+ printf("~! Check dfunc2, ov %f, refov %f\n",ov, refov);
+ for (i = 0; i < nparms; i++) {
+ printf("~1 Parm %d val %f, ref %f\n",i,dv[i],refdv[i]);
+ }
+}
+#endif /* TESTDFUNC */
+
+
+/* Setup test point data ready for efunc3 on the given oba */
+static void sfunc3(mpp *p) {
+ double pcnv[MPP_MXCCOMB]; /* Interpolation combination values */
+ int j = p->oba; /* Band being optimised */
+ int i, k, m;
+
+ /* Setup the correct per patch value fcnv values */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+
+ /* Compute the tranfer corrected device values */
+ for (m = 0; m < p->n; m++)
+ c->tcnv[m] = icxTransFunc(p->tc[m][j], p->cord, c->nv[m]);
+
+ /* Compute combination values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= c->tcnv[m];
+ else
+ vv *= (1.0 - c->tcnv[m]);
+ }
+ pcnv[k] = vv;
+ }
+
+ /* Compute shape weighting values */
+ for (k = 0; k < p->nnn2; k++) {
+ int m = p->c2f[k].ink;
+ int n = p->c2f[k].comb;
+ /* Compress full interpolation one dimension to */
+ /* exclude ink value being tweaked by shape */
+ c->fcnv[k] = pcnv[n & ~(1<<m)] + pcnv[n | (1<<m)];
+ }
+ }
+}
+
+
+/* Optimise all shape parameters simultaniously to minimise a particular bands error */
+/* Assume test point tcnv and pcnv are setup for pre-shape values */
+static double efunc3(void *adata, double pv[]) {
+ mpp *p = (mpp *)adata;
+ double smv, rv = 0.0;
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int j = p->oba; /* Band being optimised */
+ int n1 = p->n - 1;
+ int i, m, k;
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double ov;
+
+ for (m = 0; m < p->n; m++)
+ ww[m] = 0.0;
+
+ /* Interpolate the per ink shape values for this set of input values */
+ for (k = 0; k < p->nnn2; k++) { /* For each ink & interp vertex */
+ m = k >> n1; /* Corresponding ink channel */
+ ww[m] += pv[k] * c->fcnv[k]; /* Apply weighting to shape vertex value */
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double vv = c->tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ tcnv[m] = vv;
+ tcnv1[m] = 1.0 - vv;
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double vv = p->pc[k][j];
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ /* Compute the band value error */
+ ov = lDE(ov) - c->lband[j];
+ rv += ov * ov;
+ }
+
+ rv /= (double)p->nodp;
+
+ /* Compute average magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ for (smv = 0.0, m = 0; m < p->nnn2; m++) {
+ smv += pv[m] * pv[m];
+ }
+ smv /= (double)(p->nnn2);
+ rv += SHAPE_PMW * smv;
+
+#ifdef DEBUG
+ printf("efunc3 itt %d/%d band %d (smv %f) returning %f\n",p->oit,p->ott,j,smv,rv);
+#endif
+ return rv;
+}
+
+/* Return the gradient of the minimisation function at the given location, */
+/* as well as the function value at this location. */
+static double dfunc3(void *adata, double dv[], double pv[]) {
+ mpp *p = (mpp *)adata;
+ double smv, tt, rv = 0.0;
+ double dtcnv[MPP_MXINKS]; /* Derivative of transfer curve corrected device values */
+ double dov[MPP_MXINKS]; /* Derivative of output interpolation device values */
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int j = p->oba; /* Band being optimised */
+ int n1 = p->n - 1;
+ int i, m, k;
+
+ for (k = 0; k < p->nnn2; k++)
+ dv[k] = 0.0; /* Start with 0 delta */
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double ov, ddov;
+
+ for (m = 0; m < p->n; m++)
+ ww[m] = 0.0;
+
+ /* Interpolate the per ink shape values for this set of input values */
+ for (k = 0; k < p->nnn2; k++) {
+ m = k >> n1; /* Corresponding ink channel */
+ ww[m] += pv[k] * c->fcnv[k]; /* Apply weighting to shape vertex value */
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double sv, vv = c->tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ tt = gg - gg * vv + 1.0;
+ sv = vv/tt;
+ } else {
+ tt = 1.0 - gg * vv;
+ sv = (vv - gg * vv)/tt;
+ }
+ tcnv[m] = sv;
+ tcnv1[m] = 1.0 - sv;
+ dtcnv[m] = (vv * vv - vv)/(tt * tt); /* del in tcnv[m] due to del in ww[m] */
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double vv = p->pc[k][j];
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ /* Compute del ov[m] for del tcnv[m] */
+ for (m = 0; m < p->n; m++) {
+ for (dov[m] = 0.0, k = 0; k < p->nn; k++) {
+ int mm;
+ double vv = p->pc[k][j];
+ for (mm = 0; mm < p->n; mm++) {
+ if (m == mm)
+ continue;
+ if (k & (1 << mm))
+ vv *= tcnv[mm];
+ else
+ vv *= tcnv1[mm];
+ }
+ if (k & (1 << m))
+ dov[m] += vv;
+ else
+ dov[m] -= vv;
+ }
+ dov[m] *= dtcnv[m]; /* del ov[m] due to del in ww[m] */
+ }
+
+ /* Compute the band value error */
+ ddov = dDE(ov);
+ ov = lDE(ov) - c->lband[j];
+
+ ddov *= 2.0 * ov; /* del in final ov due to del in raw ov */
+ rv += ov * ov;
+
+ for (k = 0; k < p->nnn2; k++) {
+ m = k >> n1; /* Corresponding ink channel */
+ dv[k] += ddov * dov[m] * c->fcnv[k];
+ }
+ }
+
+ rv /= ((double)p->nodp);
+
+ for (k = 0; k < p->nnn2; k++)
+ dv[k] /= ((double)p->nodp);
+
+ /* Compute average magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ tt = SHAPE_PMW * 2.0/(double)(p->nnn2); /* Common factor */
+ for (smv = 0.0, k = 0; k < p->nnn2; k++) {
+ dv[k] += tt * pv[k]; /* del rv due to del pv[k] */
+ smv += pv[k] * pv[k];
+ }
+ smv /= (double)(p->nnn2);
+ rv += SHAPE_PMW * smv;
+
+#ifdef DEBUG
+ printf("dfunc3 itt %d/%d band %d (smv %f) returning %f\n",p->oit,p->ott,j,smv,rv);
+#endif
+ return rv;
+}
+
+#ifdef TESTDFUNC
+/* Check that dfunc3 returns the right values */
+static void test_dfunc3(
+mpp *p,
+int nparms,
+double *pv
+) {
+ int i, j, k;
+ double refov;
+ double refdv[MPP_MXINKS * MPP_MXCCOMB/2];
+ double ov;
+ double dv[MPP_MXINKS * MPP_MXCCOMB/2];
+
+ /* Create reference dvs */
+ refov = efunc3((void *)p, pv);
+ for (k = 0; k < nparms; k++) {
+ pv[k] += 1e-6;
+ dv[k] = (efunc3((void *)p, pv) - refov)/1e-6;
+ pv[k] -= 1e-6;
+ }
+
+ /* Check dfunc3 */
+ ov = dfunc3((void *)p, dv, pv);
+
+ printf("~#############################################\n");
+ printf("~! Check dfunc3, ov %f, refov %f\n",ov, refov);
+ for (i = 0; i < nparms; i++) {
+ printf("~1 Parm %d val %f, ref %f\n",i,dv[i],refdv[i]);
+ }
+}
+#endif /* TESTDFUNC */
+
+
+/* Setup test point data ready for efunc4 on the given oba */
+static void sfunc4(mpp *p) {
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int j = p->oba; /* Band being optimised */
+ int i, k, m;
+
+ /* Setup the correct per patch value fcnv values */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+
+ /* Compute the tranfer corrected device values */
+ for (m = 0; m < p->n; m++) {
+ tcnv[m] = icxTransFunc(p->tc[m][j], p->cord, c->nv[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ }
+
+ for (m = 0; m < p->n; m++)
+ ww[m] = 0.0;
+
+ /* Lookup the interpolated shape values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ for (m = 0; m < p->n; m++) {
+ ww[m] += p->shape[m][k & ~(1<<m)][j] * vv;
+ /* Apply weighting to shape vertex value */
+ }
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double vv = tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ tcnv[m] = vv;
+ tcnv1[m] = 1.0 - vv;
+ }
+
+ /* Compute the shape adjusted primary combination values */
+ for (k = 0; k < p->nn; k++) {
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ c->pcnv[k] = vv;
+ }
+ }
+}
+
+/* Optimise all vertex values simultaniously to minimise a particular bands error */
+/* Assume test point tcnv and pcnv are setup for post-shape values */
+static double efunc4(void *adata, double pv[]) {
+ mpp *p = (mpp *)adata;
+ double smv = 0.0, rv = 0.0;
+ int j = p->oba; /* Band being optimised */
+ int i, k;
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double ov = 0.0;
+
+ for (k = 0; k < p->nn; k++) {
+ double pp = pv[k];
+
+ if (pp < 0.0) /* Stop non-real values */
+ rv += -5000.0 * pp;
+ ov += c->pcnv[k] * pp;
+ }
+
+ /* Compute the band value error */
+ ov = lDE(ov) - c->lband[j];
+ rv += ov * ov;
+ }
+
+ rv /= p->nodp;
+
+ /* Compute anchor point error */
+ for (smv = 0.0, i = 0; i < p->nn; i++) {
+ double tt = lDE(pv[i]) - p->lpca[i][j];
+ smv += tt * tt;
+ }
+ smv /= (double)p->nn;
+
+//printf("~1 anchor error = %f\n",smv);
+ rv += COMB_PMW * smv;
+
+#ifdef DEBUG
+ printf("efunc4 itt %d/%d band %d returning %f\n",p->oit,p->ott,j,rv);
+#endif
+ return rv;
+}
+
+/* Return the gradient of the minimisation function at the given location, */
+/* as well as the function value at this location. */
+static double dfunc4(void *adata, double dv[], double pv[]) {
+ mpp *p = (mpp *)adata;
+ double smv = 0.0, rv = 0.0;
+ double drv[MPP_MXCCOMB]; /* Delta in rv */
+ int j = p->oba; /* Band being optimised */
+ int i, k;
+
+ for (k = 0; k < p->nn; k++) {
+ dv[k] = 0.0;
+ drv[k] = 0.0;
+ }
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double ov = 0.0, ddov;
+
+ for (k = 0; k < p->nn; k++) {
+ double pp = pv[k];
+
+ if (pp < 0.0) { /* Stop non-real values */
+ rv += -5000.0 * pp;
+ drv[k] += -5000.0;
+ }
+ ov += c->pcnv[k] * pp;
+ }
+
+ /* Compute the band value error */
+ ddov = dDE(ov);
+ ov = lDE(ov) - c->lband[j];
+
+ ddov *= 2.0 * ov; /* del in final ov due to del in raw ov */
+ rv += ov * ov;
+
+ for (k = 0; k < p->nn; k++) {
+ dv[k] += ddov * c->pcnv[k];
+ }
+ }
+
+ rv /= p->nodp;
+ for (k = 0; k < p->nn; k++)
+ dv[k] /= ((double)p->nodp);
+
+ /* Compute anchor point error */
+ for (smv = 0.0, k = 0; k < p->nn; k++) {
+ double tt, ddov;
+ ddov = dDE(pv[k]);
+ tt = lDE(pv[k]) - p->lpca[k][j];
+ ddov *= COMB_PMW * 2.0 * tt/(double)p->nn;
+ dv[k] += ddov;
+ smv += tt * tt;
+ }
+ smv /= (double)p->nn;
+
+//printf("~1 anchor error = %f\n",smv);
+ rv += COMB_PMW * smv;
+
+ for (k = 0; k < p->nn; k++) /* Add any < 0 contribution */
+ dv[k] += drv[k];
+
+#ifdef DEBUG
+ printf("dfunc4 itt %d/%d band %d returning %f\n",p->oit,p->ott,j,rv);
+#endif
+ return rv;
+}
+
+#ifdef TESTDFUNC
+/* Check that dfunc4 returns the right values */
+static void test_dfunc4(
+mpp *p,
+int nparms,
+double *pv
+) {
+ int i, j, k;
+ double refov;
+ double refdv[MPP_MXCCOMB];
+ double ov;
+ double dv[MPP_MXCCOMB];
+
+ /* Create reference dvs */
+ refov = efunc4((void *)p, pv);
+ for (i = 0; i < nparms; i++) {
+ pv[i] += 1e-9;
+ refdv[i] = (efunc4((void *)p, pv) - refov)/1e-9;
+ pv[i] -= 1e-9;
+ }
+
+ /* Check dfunc4 */
+ ov = dfunc4((void *)p, dv, pv);
+
+ printf("~#############################################\n");
+ printf("~! Check dfunc4, ov %f, refov %f\n",ov, refov);
+ for (i = 0; i < nparms; i++) {
+ printf("~1 Parm %d val %f, ref %f\n",i,dv[i],refdv[i]);
+ }
+}
+#endif /* TESTDFUNC */
+
+/* ---------------------------------------------------- */
+/* Optimise whole model in one go */
+
+#ifdef BIGBANG
+
+/* Optimise all parameters simultaniously to minimise a particular bands error */
+static double efunc0(void *adata, double pv[]) {
+ mpp *p = (mpp *)adata;
+ double *pv2, *pv3, *pv4; /* Pointers to each group of parameters */
+ double smv, rv = 0.0;
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int j = p->oba; /* Band being optimised */
+ int i, m, k;
+
+ pv2 = pv;
+ pv3 = pv + (p->n * p->cord);
+ pv4 = pv + (p->n * p->cord) + p->nnn2;
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double ov;
+
+ /* Compute the tranfer corrected device values */
+ for (m = 0; m < p->n; m++) {
+ tcnv[m] = icxTransFunc(&pv2[m * p->cord], p->cord, c->nv[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ }
+
+ for (m = 0; m < p->n; m++)
+ ww[m] = 0.0;
+
+ /* Lookup the shape values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ for (m = 0; m < p->n; m++) {
+ ww[m] += pv3[p->f2c[m][k & ~(1<<m)]] * vv;
+ /* Apply weighting to shape vertex value */
+ }
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double vv = tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ tcnv[m] = vv;
+ tcnv1[m] = 1.0 - vv;
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double vv = pv4[k];
+ if (vv < 0.0) /* Stop non-real values */
+ rv += -5000.0 * vv;
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ /* Compute the band value error */
+ ov = lDE(ov) - c->lband[j];
+ rv += ov * ov;
+ }
+
+ rv /= (double)p->nodp;
+
+ /* Compute weighted magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ for (smv = 0.0, m = 0; m < p->n; m++) {
+ double w;
+ for (k = 0; k < p->cord; k++) {
+ i = m * p->cord + k;
+ w = (k < 2) ? TRANS_BASE : k * TRANS_HBASE; /* Increase weight with harmonics */
+ smv += w * pv2[i] * pv2[i];
+ }
+ }
+ smv /= (double)(p->n);
+ rv += smv;
+
+ /* Compute average magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ for (smv = 0.0, m = 0; m < p->nnn2; m++) {
+ smv += pv3[m] * pv3[m];
+ }
+ smv /= (double)(p->nnn2);
+ rv += SHAPE_PMW * smv;
+
+ /* Compute anchor point error */
+ for (smv = 0.0, i = 0; i < p->nn; i++) {
+ double tt = lDE(pv4[i]) - p->lpca[i][j];
+ smv += tt * tt;
+ }
+ smv /= (double)p->nn;
+ rv += COMB_PMW * smv;
+
+#ifdef DEBUG
+ printf("efunc0 itt %d/%d band %d returning %f\n",p->oit,p->ott,j,rv);
+#endif
+ return rv;
+}
+
+/* Return the gradient of the minimisation function at the given location, */
+/* as well as the function value at this location. */
+static double dfunc0(void *adata, double dv[], double pv[]) {
+ mpp *p = (mpp *)adata;
+ double *pv2, *pv3, *pv4; /* Pointers to each group of parameters */
+ double *dv2, *dv3, *dv4; /* Pointers to each group of derivatives */
+ double smv, tt, rv = 0.0;
+
+ double dtcnv_dpv2[MPP_MXINKS][MPP_MXTCORD]; /* Del in tcnv[m] due to del in pv2 */
+ double dww_dpv3[MPP_MXINKS][MPP_MXINKS * MPP_MXCCOMB/2]; /* Del in ww[m] due to del in pv3 */
+ double dov_dpv4[MPP_MXCCOMB]; /* Delta in ov due to delta in pv4 */
+ double drv4[MPP_MXCCOMB]; /* Delta in rv due to error in pv4 */
+
+ double dww_dtcnv[MPP_MXINKS][MPP_MXINKS]; /* Del in ww[m] due to del in tcnv[m] */
+ double dtcnv_tc[MPP_MXINKS]; /* Del in tcnv'[m] due to del in tcnv[m] */
+ double dtcnv_ww[MPP_MXINKS]; /* Del in tcnv'[m] due to del in ww[m] */
+ double dov_dcnv[MPP_MXINKS]; /* Del of ov due to del in tcnv'[m] */
+ double ddov; /* Del in final ov due to del in raw ov */
+
+ double tcnv[MPP_MXINKS]; /* Transfer curve corrected device values */
+ double tcnv1[MPP_MXINKS]; /* 1.0 - Transfer curve corrected device values */
+ double ww[MPP_MXINKS]; /* Interpolated tweak params for each channel */
+ int j = p->oba; /* Band being optimised */
+ int i, m, k;
+
+ pv2 = pv;
+ pv3 = pv + (p->n * p->cord);
+ pv4 = pv + (p->n * p->cord) + p->nnn2;
+ dv2 = dv;
+ dv3 = dv + (p->n * p->cord);
+ dv4 = dv + (p->n * p->cord) + p->nnn2;
+
+ for (k = 0; k < (p->n * p->cord); k++)
+ dv2[k] = 0.0;
+ for (k = 0; k < p->nnn2; k++)
+ dv3[k] = 0.0;
+ for (k = 0; k < p->nn; k++)
+ dv4[k] += 0.0;
+
+ /* For each test point */
+ for (i = 0; i < p->nodp; i++) {
+ int mo;
+ mppcol *c = &p->cols[i];
+ double ov;
+
+
+ /* Compute the tranfer corrected device values */
+ /* and del in these values due to del in input parameters */
+ for (m = 0; m < p->n; m++) {
+ tcnv[m] = icxdpTransFunc(&pv2[m * p->cord], dtcnv_dpv2[m], p->cord, c->nv[m]);
+ tcnv1[m] = 1.0 - tcnv[m];
+ }
+
+ for (m = 0; m < p->n; m++) {
+ ww[m] = 0.0;
+ for (k = 0; k < p->nnn2; k++)
+ dww_dpv3[m][k] = 0.0;
+ }
+
+ /* Lookup the shape values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ for (m = 0; m < p->n; m++) {
+ int pix = p->f2c[m][k & ~(1<<m)];
+ ww[m] += pv3[pix] * vv; /* Apply weighting to shape vertex value */
+ dww_dpv3[m][pix] += vv; /* Delta to ww[m] from del in pv3[pix] */
+ }
+ }
+
+ /* Compute del ww[m][m] for del tcnv[m] */
+ for (m = 0; m < p->n; m++) { /* For each input channel were doing del of */
+ for (mo = 0; mo < p->n; mo++)
+ dww_dtcnv[mo][m] = 0.0;
+ for (k = 0; k < p->nn; k++) {
+ int mm;
+ double vv = 1.0;
+ for (mm = 0; mm < p->n; mm++) { /* Compute weight for node k */
+ if (m == mm)
+ continue;
+ if (k & (1 << mm))
+ vv *= tcnv[mm];
+ else
+ vv *= tcnv1[mm];
+ }
+ for (mo = 0; mo < p->n; mo++) { /* For each output channel */
+ double vvv = vv * pv3[p->f2c[mo][k & ~(1<<mo)]];
+ if (k & (1 << m))
+ dww_dtcnv[mo][m] += vvv;
+ else
+ dww_dtcnv[mo][m] -= vvv;
+ }
+ }
+ }
+
+ /* Apply the shape values to adjust the primaries */
+ for (m = 0; m < p->n; m++) {
+ double gg = ww[m]; /* Curve adjustment */
+ double sv, dsv, vv = tcnv[m]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ tt = gg - gg * vv + 1.0;
+ sv = vv/tt;
+ dsv = (gg + 1.0)/(tt * tt);
+ } else {
+ tt = 1.0 - gg * vv;
+ sv = (vv - gg * vv)/tt;
+ dsv = (1.0 - gg)/(tt * tt);
+ }
+ tcnv[m] = sv;
+ tcnv1[m] = 1.0 - sv;
+ dtcnv_tc[m] = dsv; /* del in tcnv[m] due to del in tcnv[m] */
+ dtcnv_ww[m] = (vv * vv - vv)/(tt * tt); /* del in tcnv[m] due to del in ww[m] */
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double pp, vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ dov_dpv4[k] = vv;
+
+ pp = pv4[k];
+ if (pp < 0.0) { /* Stop non-real values */
+ rv += -5000.0 * pp;
+ drv4[k] += -5000.0;
+ }
+ ov += vv * pp;
+ }
+
+ /* Compute del ov for del tcnv[m] */
+ for (m = 0; m < p->n; m++) {
+ for (dov_dcnv[m] = 0.0, k = 0; k < p->nn; k++) {
+ int mm;
+ double vv = p->pc[k][j];
+ for (mm = 0; mm < p->n; mm++) {
+ if (m == mm)
+ continue;
+ if (k & (1 << mm))
+ vv *= tcnv[mm];
+ else
+ vv *= tcnv1[mm];
+ }
+ if (k & (1 << m))
+ dov_dcnv[m] += vv;
+ else
+ dov_dcnv[m] -= vv;
+ }
+ }
+
+ /* Compute the band value error */
+ ddov = dDE(ov);
+ ov = lDE(ov) - c->lband[j];
+
+ ddov *= 2.0 * ov; /* del in final ov due to del in raw ov */
+ rv += ov * ov;
+
+ /* Accumulate delta from input params to output */
+ for (m = 0; m < p->n; m++) {
+ for (k = 0; k < p->cord; k++) {
+ double ttt;
+ int mm;
+
+ /* delta via dww */
+ for (ttt = 0.0, mm = 0; mm < p->n; mm++)
+ ttt += dov_dcnv[mm] * dtcnv_ww[mm] * dww_dtcnv[mm][m] * dtcnv_dpv2[m][k];
+
+ /* delta direct */
+ dv2[m * p->cord + k] += ddov * (ttt + dov_dcnv[m] * dtcnv_tc[m] * dtcnv_dpv2[m][k]);
+ }
+ }
+ for (k = 0; k < p->nnn2; k++) {
+ double ttt;
+
+ /* delta via dww */
+ for (ttt = 0.0, m = 0; m < p->n; m++)
+ ttt += dov_dcnv[m] * dtcnv_ww[m] * dww_dpv3[m][k];
+ dv3[k] += ddov * ttt;
+ }
+ for (k = 0; k < p->nn; k++) {
+ dv4[k] += ddov * dov_dpv4[k];
+ }
+ }
+
+ rv /= (double)p->nodp;
+ for (k = 0; k < (p->n * p->cord); k++)
+ dv2[k] /= (double)p->nodp;
+ for (k = 0; k < p->nnn2; k++)
+ dv3[k] /= ((double)p->nodp);
+ for (k = 0; k < p->nn; k++)
+ dv4[k] /= ((double)p->nodp);
+
+ /* Compute weighted magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ tt = 2.0/(double)(p->n); /* Common factor */
+ for (smv = 0.0, m = 0; m < p->n; m++) {
+ double w;
+ for (k = 0; k < p->cord; k++) {
+ i = m * p->cord + k;
+ w = (k < 2) ? TRANS_BASE : k * TRANS_HBASE; /* Increase weight with harmonics */
+ dv2[i] += w * tt * pv2[i]; /* Del in rv due to del in pv */
+ smv += w * pv2[i] * pv2[i];
+ }
+ }
+ smv /= (double)(p->n);
+ rv += smv;
+
+ /* Compute average magnitude of shaper parameters squared */
+ /* to minimise unconstrained "wiggles" */
+ tt = SHAPE_PMW * 2.0/(double)(p->nnn2); /* Common factor */
+ for (smv = 0.0, k = 0; k < p->nnn2; k++) {
+ dv3[k] += tt * pv3[k]; /* del rv due to del pv[k] */
+ smv += pv3[k] * pv3[k];
+ }
+ smv /= (double)(p->nnn2);
+ rv += SHAPE_PMW * smv;
+
+ /* Compute anchor point error */
+ for (smv = 0.0, k = 0; k < p->nn; k++) {
+ double tt, ddov;
+ ddov = dDE(pv4[k]);
+ tt = lDE(pv4[k]) - p->lpca[k][j];
+ ddov *= COMB_PMW * 2.0 * tt/(double)p->nn;
+ dv4[k] += ddov;
+ smv += tt * tt;
+ }
+ smv /= (double)p->nn;
+ rv += COMB_PMW * smv;
+
+ for (k = 0; k < p->nn; k++) /* Add any < 0 contribution */
+ dv4[k] += drv4[k];
+
+#ifdef DEBUG
+ printf("dfunc0 itt %d/%d band %d returning %f\n",p->oit,p->ott,j,rv);
+#endif
+ return rv;
+}
+
+#ifdef TESTDFUNC
+/* Check that dfunc0 returns the right values */
+static void test_dfunc0(
+mpp *p,
+int nparms,
+double *pv
+) {
+ int i, j, k;
+ double refov;
+ double refdv[MPP_MXPARMS];
+ double ov;
+ double dv[MPP_MXPARMS];
+
+ /* Create reference dvs */
+ refov = efunc0((void *)p, pv);
+ for (i = 0; i < nparms; i++) {
+ pv[i] += 1e-9;
+ refdv[i] = (efunc0((void *)p, pv) - refov)/1e-9;
+ pv[i] -= 1e-9;
+ }
+
+ /* Check dfunc0 */
+ ov = dfunc0((void *)p, dv, pv);
+
+ printf("~#############################################\n");
+ printf("~! Check dfunc0, ov %f, refov %f\n",ov, refov);
+ for (i = 0; i < nparms; i++) {
+ printf("~1 Parm %d val %f, ref %f\n",i,dv[i],refdv[i]);
+ }
+}
+#endif /* TESTDFUNC */
+#endif /* BIGBANG */
+
+#ifdef ISHAPE
+/* ----------------------------------------------------- */
+/* Create an initial solution for shape parameters */
+/* by solving least squares using SVD */
+
+/* Optimise device values to match test points Lab */
+/* while minimising the difference between the device */
+/* values and the current model device values in tcnv */
+static double efuncS(void *adata, double pv[]) {
+ double tcnv[MPP_MXINKS]; /* Shape tweaked input values */
+ double tcnv1[MPP_MXINKS];
+ mpp *p = (mpp *)adata;
+ double smv, rv = 0.0;
+ mppcol *c = p->otp;
+ int j = p->oba;
+ int k, m;
+
+ double ov;
+
+ for (k = 0; k < p->n; k++) {
+ double gg = pv[k]; /* Curve adjustment */
+ double vv = c->tcnv[k]; /* Input value to be tweaked */
+ if (gg >= 0.0) {
+ vv = vv/(gg - gg * vv + 1.0);
+ } else {
+ vv = (vv - gg * vv)/(1.0 - gg * vv);
+ }
+ tcnv[k] = vv;
+ tcnv1[k] = 1.0 - vv;
+ }
+
+ /* Compute the primary combination values */
+ for (ov = 0.0, k = 0; k < p->nn; k++) {
+ double vv = p->pc[k][j];
+ for (m = 0; m < p->n; m++) {
+ if (k & (1 << m))
+ vv *= tcnv[m];
+ else
+ vv *= tcnv1[m];
+ }
+ ov += vv;
+ }
+
+ /* Compute the band value error */
+ ov = lDE(ov) - c->lband[j];
+ rv += ov * ov;
+
+ /* Compute magnitude of shape params */
+ for (smv = 0.0, k = 0; k < p->n; k++) {
+ smv += pv[k] * pv[k];
+ }
+ rv += SHAPE_PMW * 0.1 * smv/(double)p->n; /* Don't worry about this here - SVD will cope */
+
+//printf("~1 efuncS %f %f %f %f returning %f\n",pv[0],pv[1],pv[2],pv[3],rv);
+ return rv;
+}
+
+
+static void ishape(
+mpp *p,
+int j /* Band being initialised */
+) {
+ int i, k, m;
+ double **a; /* A[0..m-1][0..n-1] input A[][], will return U[][] */
+ double *b; /* B[0..m-1] Right hand side of equation, return solution */
+
+ p->oba = j;
+
+ if (p->nodp < (p->nn/2)) /* Nicer to return error ?? */
+ error ("Not enough data points to solve shaper parameters");
+
+//printf("~1 ishape called for band %d\n",j);
+
+ /* First step is to compute the ideal shape values */
+ /* for each test point. */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double pv[MPP_MXINKS]; /* Parameter values */
+ double sr[MPP_MXINKS]; /* search radius */
+
+ p->otp = c;
+
+//printf("~1 setting up point %d\n",i);
+
+ /* Compute the tranfer corrected device values */
+ for (m = 0; m < p->n; m++)
+ c->tcnv[m] = icxTransFunc(p->tc[m][j], p->cord, c->nv[m]);
+
+ /* Compute pre-shape combination values */
+ for (k = 0; k < p->nn; k++) { /* For each interp vertex */
+ double vv;
+ for (vv = 1.0, m = 0; m < p->n; m++) { /* Compute weighting */
+ if (k & (1 << m))
+ vv *= c->tcnv[m];
+ else
+ vv *= (1.0 - c->tcnv[m]);
+ }
+ c->pcnv[k] = vv;
+ }
+
+ /* Do reverse lookup to find ideal post transfer device */
+ /* shape values that are minimal, but will give the desired */
+ /* band value */
+ for (k = 0; k < p->n; k++) {
+ pv[k] = 0.0;
+ sr[k] = 0.5;
+ }
+
+ if (powell(NULL, p->n, pv, sr, 0.001, 300, efuncS, (void *)p, NULL, NULL) != 0) {
+//printf("~1 ishape Powell failed at point %d\n",i);
+ for (k = 0; k < p->n; k++)
+ pv[k] = 0.0;
+ }
+
+//printf("~1 got uncorrected device vals %f %f %f %f\n",c->nv[0],c->nv[1],c->nv[2],c->nv[3]);
+//printf("~1 got shape target values %f %f %f %f\n",pv[0],pv[1],pv[2],pv[3]);
+
+ /* put them leave them in scnv */
+ for (k = 0; k < p->n; k++) {
+ c->scnv[k] = pv[k];
+ }
+ }
+
+ /* The second step is to use SVD to compute the per colorant */
+ /* interpolation corner values that are the best least squares */
+ /* solution to providing those shape parameters at each point. */
+
+ /* Allocate our SVD matricies */
+ a = dmatrix(0, p->nodp-1 + p->nn/2, 0, p->nn/2-1);
+ b = dvector(0, p->nodp-1 + p->nn/2);
+
+ for (m = 0; m < p->n; m++) { /* For each channel */
+ int kk;
+
+ /* Setup our matricies for the test point */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double ss; /* Weighting factor */
+
+ /* The theoretically correct weighting to get */
+ /* better alighment with DEsq() measure is */
+ /* ss = dDE(c->band[j]);, but this doesn't seem */
+ /* to work well in practice. */
+
+ /* I don't quite understand why this weighting */
+ /* seems to give a good result. */
+ ss = c->tcnv[m] * (1.0 - c->tcnv[m]); /* Don't understand why this is so good */
+
+ for (kk = k = 0; k < p->nn; k++) {
+ if (k & (1<<m))
+ continue; /* Invalid comb for this channel */
+
+ a[i][kk++] = ss * (c->pcnv[k] + c->pcnv[k | (1<<m)]);
+ }
+ b[i] = ss * c->scnv[m];
+ }
+
+ /* Add extra fake "data points" to weight the minimisation of */
+ /* the shape parameter values */
+ {
+ int ii;
+ double ss;
+
+ /* We want the relative weight to be similar to that */
+ /* aimed for in efunc3 */
+
+ // ~~~ 0.1 seems about right for 1150 ???
+ // 1.0 for roland8 ??
+// ss = (double)p->nodp/((double)(p->nn/2)) * 1.0 * SHAPE_PMW;
+ ss = (double)p->nodp * 0.05 * SHAPE_PMW;
+
+ for (ii = 0; ii < p->nn/2; ii++) {
+ for (kk = k = 0; k < p->nn; k++) {
+ if (k & (1<<m))
+ continue; /* Invalid comb for this channel */
+
+ if (kk == ii) /* Weights only on diagonals */
+ a[i+ii][kk] = ss;
+ else
+ a[i+ii][kk] = 0.0;
+ kk++;
+ }
+ b[i+ii] = 0.0;
+ }
+ }
+
+ /* Solve the equation A.x = b using SVD */
+ if (svdsolve(a, b, p->nodp + p->nn/2, p->nn/2) != 0)
+ error("ishape: SVD failed");
+
+ /* Copy the solution back */
+ for (kk = k = 0; k < p->nn; k++) {
+ if (k & (1<<m))
+ continue; /* Invalid comb for this channel */
+
+//printf("~1 Calculated shape[%d][%d] = %f\n",m,k,b[kk]);
+ p->shape[m][k][j] = b[kk++];
+ }
+ }
+
+ free_dvector(b, 0, p->nodp-1 + p->nn/2);
+ free_dmatrix(a, 0, p->nodp-1 + p->nn/2, 0, p->nn/2-1);
+//printf("~1 ishape is done for band %d\n",j);
+
+}
+#endif /* ISHAPE */
+
+
+/* ----------------------------------------------------- */
+/* Routine to figure out a suitable black point */
+
+/* Structure to hold optimisation information */
+typedef struct {
+ mpp *p; /* Lookup object */
+ int n; /* Number of device channels */
+ double ilimit; /* Ink limit */
+ double p1[3]; /* white pivot point */
+ double p2[3]; /* Point on vector towards black */
+} bfinds;
+
+/* Optimise device values to minimise L, while remaining */
+/* within the ink limit, and staying in line between p1 and p2 */
+static double efunc6(void *adata, double pv[]) {
+ bfinds *b = (bfinds *)adata;
+ double rv = 0.0;
+ double dv[MPP_MXINKS];
+ double Lab[3];
+ double lr, ta, tb, terr; /* L ratio, target a, target b, target error */
+ double sum, ovr;
+ int j;
+
+ /* See if over ink limit or outside device range */
+ for (ovr = sum = 0.0, j = 0; j < b->n; j++) {
+ dv[j] = pv[j];
+ if (dv[j] < 0.0) {
+ if (-dv[j] > ovr)
+ ovr = -dv[j];
+ dv[j] = 0.0;
+ } else if (dv[j] > 1.0) {
+ if ((dv[j] - 1.0) > ovr)
+ ovr = dv[j] - 1.0;
+ dv[j] = 1.0;
+ }
+ sum += dv[j];
+ }
+
+ if (b->ilimit > 1e-4) {
+ sum -= b->ilimit;
+ if (sum < 0.0)
+ sum = 0.0;
+ } else {
+ sum = 0.0;
+ }
+
+ /* Compute Lab value */
+ forward(b->p, NULL, Lab, NULL, dv);
+
+#ifdef DEBUG
+ printf("p1 = %f %f %f, p2 = %f %f %f\n",b->p1[0],b->p1[1],b->p1[2],b->p2[0],b->p2[1],b->p2[2]);
+ printf("device value %f %f %f %f, Lab = %f %f %f\n",dv[0],dv[1],dv[2],dv[3],Lab[0],Lab[1],Lab[2]);
+#endif
+
+ /* Primary is to minimise L value */
+ rv = Lab[0];
+
+ /* See how out of line from p1 to p2 we are */
+ lr = (Lab[0] - b->p1[0])/(b->p2[0] - b->p1[0]); /* Distance towards p2 from p1 */
+ ta = lr * (b->p2[1] - b->p1[1]) + b->p1[1]; /* Target a value */
+ tb = lr * (b->p2[2] - b->p1[2]) + b->p1[2]; /* Target b value */
+
+ terr = (ta - Lab[1]) * (ta - Lab[1])
+ + (tb - Lab[2]) * (tb - Lab[2]);
+
+#ifdef DEBUG
+ printf("target error %f\n",terr);
+#endif
+ rv += 100.0 * terr;
+
+#ifdef DEBUG
+ printf("out of range error %f\n",ovr);
+ printf("over limit error %f\n",sum);
+#endif
+ rv += 200 * (ovr + sum);
+
+#ifdef DEBUG
+ printf("black find tc ret %f\n",rv);
+#endif
+ return rv;
+}
+
+static void compute_wb(
+mpp *p
+) {
+ int j;
+
+ /* Figure out the white and black points */
+ if (p->imask & ICX_ADDITIVE) { /* Assume additive doesn't have an ink limit */
+
+ /* Simply lookup values from min and max device. */
+ /* If we have ICX_WHITE, should this be treated the same as */
+ /* subtractive black ???? */
+ for (j = 0; j < p->n; j++)
+ p->white.nv[j] = 1.0;
+ forward(p, &p->white.band[3], NULL, p->white.band, p->white.nv);
+
+ for (j = 0; j < p->n; j++)
+ p->black.nv[j] = 0.0;
+ forward(p, &p->black.band[3], NULL, p->black.band, p->black.nv);
+
+ for (j = 0; j < p->n; j++)
+ p->kblack.nv[j] = 0.0;
+ forward(p, &p->kblack.band[3], NULL, p->kblack.band, p->kblack.nv);
+
+ } else { /* Subtractive */
+ bfinds bfs;
+ double sr[MPP_MXINKS]; /* search radius */
+ double tt[MPP_MXINKS]; /* temporary */
+ int trial;
+ double rv, brv;
+ int kbset = 0;
+
+ /* Lookup white directly */
+ for (j = 0; j < p->n; j++)
+ p->white.nv[j] = 0.0;
+ forward(p, &p->white.band[3], bfs.p1, p->white.band, p->white.nv);
+
+ /* Choose a black direction */
+ if (p->imask & ICX_BLACK) {
+ int bix;
+ bix = icx_ink2index(p->imask, ICX_BLACK);
+
+ for (j = 0; j < p->n; j++) {
+ if (j == bix)
+ p->kblack.nv[j] = 1.0;
+ else
+ p->kblack.nv[j] = 0.0;
+ }
+ forward(p, &p->kblack.band[3], bfs.p2, p->kblack.band, p->kblack.nv);
+ kbset = 1;
+
+ } else if ((p->imask & (ICX_CYAN | ICX_MAGENTA | ICX_YELLOW))
+ == (ICX_CYAN | ICX_MAGENTA | ICX_YELLOW)) {
+ int cix, mix, yix;
+ cix = icx_ink2index(p->imask, ICX_CYAN);
+ mix = icx_ink2index(p->imask, ICX_MAGENTA);
+ yix = icx_ink2index(p->imask, ICX_YELLOW);
+
+ for (j = 0; j < p->n; j++) {
+ if (j == cix)
+ p->kblack.nv[j] = 1.0;
+ else if (j == mix)
+ p->kblack.nv[j] = 1.0;
+ else if (j == yix)
+ p->kblack.nv[j] = 1.0;
+ else
+ p->kblack.nv[j] = 0.0;
+ }
+ forward(p, NULL, bfs.p2, NULL, p->kblack.nv);
+
+ } else { /* Make direction parallel to L axis */
+ bfs.p2[0] = 0.0;
+ bfs.p2[1] = bfs.p1[1];
+ bfs.p2[2] = bfs.p1[2];
+ }
+ bfs.p = p;
+ bfs.n = p->n;
+ bfs.ilimit = p->limit;
+
+ /* Find the black point */
+ /* Do several trials to avoid local minima */
+ for (j = 0; j < p->n; j++) {
+ tt[j] = p->black.nv[j] = 0.5; /* Starting point */
+ sr[j] = 0.1;
+ }
+ brv = 1e38;
+ for (trial = 0; trial < 20; trial++) {
+
+ if (powell(&rv, p->n, tt, sr, 0.00001, 500, efunc6, (void *)&bfs, NULL, NULL) == 0) {
+ if (rv < brv) {
+ brv = rv;
+ for (j = 0; j < p->n; j++)
+ p->black.nv[j] = tt[j];
+ }
+ }
+ for (j = 0; j < p->n; j++) {
+ tt[j] = p->black.nv[j] + d_rand(-0.3, 0.3);
+ if (tt[j] < 0.0)
+ tt[j] = 0.0;
+ else if (tt[j] > 1.0)
+ tt[j] = 1.0;
+ }
+ }
+ if (brv > 1000.0)
+ error ("mpp: Black point powell failed");
+
+ for (j = 0; j < p->n; j++) { /* Make sure device values are in range */
+ if (p->black.nv[j] < 0.0)
+ p->black.nv[j] = 0.0;
+ else if (p->black.nv[j] > 1.0)
+ p->black.nv[j] = 1.0;
+ }
+
+ /* Set black value */
+ forward(p, &p->black.band[3], NULL, p->black.band, p->black.nv);
+
+ /* Set K only if device doesn't have a K channel */
+ if (kbset == 0) {
+ for (j = 0; j < p->n; j++)
+ p->kblack.nv[j] = p->black.nv[j];
+ forward(p, &p->kblack.band[3], NULL, p->kblack.band, p->kblack.nv);
+ }
+
+ if (p->verb) {
+ double Lab[3];
+
+ icmXYZ2Lab(&icmD50, Lab, p->white.band);
+ printf("White point %f %f %f [Lab %f %f %f]\n",
+ p->white.band[0],p->white.band[1],p->white.band[2],
+ Lab[0], Lab[1], Lab[2]);
+
+ icmXYZ2Lab(&icmD50, Lab, p->black.band);
+ printf("Black point %f %f %f [Lab %f %f %f]\n",
+ p->black.band[0],p->black.band[1],p->black.band[2],
+ Lab[0], Lab[1], Lab[2]);
+
+ icmXYZ2Lab(&icmD50, Lab, p->kblack.band);
+ printf("K only Black point %f %f %f [Lab %f %f %f]\n",
+ p->kblack.band[0],p->kblack.band[1],p->kblack.band[2],
+ Lab[0], Lab[1], Lab[2]);
+ }
+ }
+}
+
+/* ===================================== */
+
+/* Create the mpp from scattered data points */
+/* Returns nz on error */
+static int create(
+ mpp *p, /* This */
+ int verb, /* Vebosity level, 0 = none */
+ int quality, /* Profile quality, 0..3 */
+ int display, /* non-zero if display device */
+ double limit, /* Total ink limit (if not display) */
+ inkmask devmask, /* Inkmask describing device colorspace */
+ int spec_n, /* Number of spectral bands, 0 if not valid */
+ double spec_wl_short, /* First reading wavelength in nm (shortest) */
+ double spec_wl_long, /* Last reading wavelength in nm (longest) */
+ double norm, /* Normalising scale value for spectral values */
+ instType itype, /* Spectral instrument type (if not display) */
+ int nodp, /* Number of points */
+ mppcol *points /* Array of input points */
+) {
+ int it, i, j, k;
+ double de, mxde; /* Average Delta E and maximum Delta E */
+ double sde, mxsde; /* Average Spectral error and maximum spectral error */
+ int mxtcord; /* maximum transfer curve order */
+ int maxit; /* Maximum number of tuning itterations */
+ double thr; /* Powell threshold multiplier at each tuning pass */
+ int useshape; /* Make use of shaping parameters */
+ int mode; /* Band scanning mode */
+
+ /* Convert quality into operation counts */
+ switch (quality) {
+ case 0: /* Low */
+ useshape = 0;
+ mxtcord = 3;
+ maxit = 2;
+ break;
+ case 1:
+ default: /* Medium */
+ useshape = 1;
+ mxtcord = 4;
+ maxit = 2;
+ break;
+ case 2: /* High */
+ useshape = 1;
+ mxtcord = 5;
+ maxit = 3;
+ break;
+ case 3: /* Ultra high */
+ useshape = 1;
+ mxtcord = 10; /* Is more actually better ? */
+ maxit = 8;
+ break;
+ case 99: /* Special, simple model */
+ useshape = 0;
+ mxtcord = 1;
+ maxit = 4;
+ break;
+ }
+
+ /* Setup the basic mpp information */
+ p->verb = verb;
+ p->imask = devmask;
+ p->n = icx_noofinks(devmask);
+ p->nn = 1 << p->n;
+ p->nnn2 = p->n * p->nn/2;
+
+ if (display) {
+ p->display = 1;
+ p->limit = p->n;
+ p->itype = instUnknown;
+ } else {
+ p->display = 0;
+ p->limit = limit; /* Record it here */
+ p->itype = itype;
+ }
+ p->spec_n = spec_n;
+ p->spec_wl_short = spec_wl_short;
+ p->spec_wl_long = spec_wl_long;
+ p->nodp = nodp;
+
+ /* MPP limit is less than XICC */
+ if (p->n > MPP_MXINKS) {
+ p->errc = 1;
+ sprintf(p->err,"MPP Can't handle %d colorants",p->n);
+ return 1;
+ }
+
+ /* MPP limit is less than XSPECT */
+ if (spec_n > MPP_MXBANDS) {
+ p->errc = 1;
+ sprintf(p->err,"MPP Can't handle %d spectral bands",spec_n);
+ return 1;
+ }
+
+ /* Take a copy of the data points */
+ if ((p->cols = new_mppcols(p->nodp, p->n, p->spec_n)) == NULL) {
+ error("Malloc failed!");
+ }
+ if ((new_mppcol(&p->white, p->n, p->spec_n)) != 0) {
+ error("Malloc failed!");
+ }
+ if ((new_mppcol(&p->black, p->n, p->spec_n)) != 0) {
+ error("Malloc failed!");
+ }
+ if ((new_mppcol(&p->kblack, p->n, p->spec_n)) != 0) {
+ error("Malloc failed!");
+ }
+
+ p->spmax = -1e6;
+ for (i = 0; i < p->nodp; i++) {
+ copy_mppcol(&p->cols[i], &points[i], p->n, p->spec_n); /* Copy structure */
+
+ /* Create Lab version */
+ icmXYZ2Lab(&icmD50, p->cols[i].Lab, p->cols[i].band);
+
+#ifdef SHARPEN
+ XYZ2sharp(&p->cols[i].band[0], &p->cols[i].band[1], &p->cols[i].band[2]);
+#endif
+ /* Normalise spectral values */
+ for (j = 0; j < p->spec_n; j++) {
+ p->cols[i].band[3+j] /= norm; /* Normalise spectral value to range 0..1 */
+
+ if (p->cols[i].band[3+j] > p->spmax) /* Track maximum value */
+ p->spmax = p->cols[i].band[3+j];
+ }
+
+ /* Compute L* type band target values */
+ for (j = 0; j < (3+p->spec_n); j++) {
+ p->cols[i].lband[j] = lDE(p->cols[i].band[j]);
+ }
+ }
+ p->norm = 1.0; /* Internal norm is 1.0 */
+
+ /* Compute L* type band target values */
+ for (i = 0; i < p->nodp; i++) {
+ for (j = 0; j < (3+p->spec_n); j++) {
+ p->cols[i].lband[j] = lDE(p->cols[i].band[j]);
+ }
+ }
+ /* Init transfer curve parameters of model */
+ for (k = 0; k < p->n; k++) { /* For each ink */
+ for (j = 0; j < (p->spec_n+3); j++) { /* For each band */
+ for (i = 0; i < mxtcord; i++) { /* For each curve order */
+ if (i == 0)
+ p->tc[k][j][i] = -1.6; /* Typical starting value */
+ else
+ p->tc[k][j][i] = 0.0; /* Straight transfer curve */
+ }
+ }
+ }
+
+
+ /* Initialise the primary colorant values */
+ for (i = -1; i < p->n; i++) {
+ int ii, bk = 0;
+ double bdif = 1e6;
+
+ if (i < 0)
+ ii = 0;
+ else
+ ii = 1 << i;
+
+ /* Search the patch list to find the one closest to this colorant combination */
+ for (k = 0; k < p->nodp; k++) {
+ double dif = 0.0;
+ for (j = 0; j < p->n; j++) {
+ double tt;
+ if (i == j)
+ tt = 1.0 - p->cols[k].nv[j];
+ else
+ tt = p->cols[k].nv[j];
+ dif += tt * tt;
+ }
+ if (dif < bdif) { /* best so far */
+ bdif = dif;
+ bk = k;
+ if (dif < 0.001)
+ break; /* Don't bother looking further */
+ }
+ }
+
+ /* Put that sample patch in place as initial value */
+ for (j = 0; j < (3+p->spec_n); j++)
+ p->pc[ii][j] = p->cols[bk].band[j];
+#ifdef DEBUG
+ printf("comb 0x%x XYZ is %f %f %f\n", ii, p->pc[ii][0], p->pc[ii][1], p->pc[ii][2]);
+#endif
+ }
+
+ /* Estimate primary combination values from primary values */
+ {
+ double sm[3+MPP_MXBANDS]; /* Smallest reflection sample in this band */
+ double ink[3+MPP_MXBANDS];
+
+ /* Search the patch list to find the smallest values for each band */
+ /* we'll use this as a guide to the freznell reflection from the surface */
+ for (j = 0; j < (3+p->spec_n); j++) {
+
+ sm[j] = 1e6;
+ for (k = 0; k < p->nodp; k++) {
+ if (sm[j] > p->cols[k].band[j]) {
+ int m;
+ sm[j] = p->cols[k].band[j];
+ ink[j] = 0.0;
+ for (m = 0; m < p->n; m++)
+ ink[j] += p->cols[k].nv[m];
+ }
+ }
+ /* Adjust for error in freznell was estimated from */
+ /* a low ink coverage */
+ if (ink[j] < 4.0) {
+ sm[j] *= pow(0.775, 4.0 - ink[j]);
+ }
+#ifdef DEBUG
+ printf("smallest value in band %d = %f from total ink %f\n",j,sm[j],ink[j]);
+#endif
+ }
+
+ for (i = 3; i < p->nn; i++) {
+
+ if ((i & (i-1)) == 0)
+ continue; /* Skip primaries */
+ for (j = 0; j < (3+p->spec_n); j++) {
+ int k;
+ double wh = p->pc[0][j]; /* white */
+ double tr = 1.0; /* Trapping coefficient */
+ if (wh < 0.01)
+ wh = 0.01; /* Guard against silliness */
+ p->pc[i][j] = wh; /* Start with white */
+ for (k = 0; k < p->n; k++) {
+ if (i & (1<<k)) {
+ double co = p->pc[1 << k][j]; /* colorant + paper reflectance */
+ co = (co - sm[j])/wh; /* Colorant reflectance */
+ co /= tr; /* Trapping reduction */
+ if (co > 1.0)
+ co = 1.0;
+ else if (co < 0.0)
+ co = 0.0;
+ p->pc[i][j] *= co; /* Estimated combined reflectivity */
+
+ tr *= 0.90; /* Next inks effectiveness due to trapping */
+ }
+ }
+ p->pc[i][j] = p->pc[i][j];
+ p->pc[i][j] += sm[j]; /* Add freznell back in */
+ }
+#ifdef DEBUG
+ printf("comb 0x%x estimated XYZ = %f %f %f\n",i, p->pc[i][0], p->pc[i][1], p->pc[i][2]);
+#endif
+ }
+ }
+
+ /* Override the estimated primary combination values, if actual readings are available */
+ for (i = 3; i < p->nn; i++) {
+ int k, bk = 0;
+ double bdif = 1e6;
+
+ if ((i & (i-1)) == 0)
+ continue; /* Skip primaries */
+
+ /* Search the patch list to find the one closest to this colorant combination */
+ for (k = 0; k < p->nodp; k++) {
+ double dif = 0.0;
+ for (j = 0; j < p->n; j++) {
+ double tt;
+ if (i & (1<<j))
+ tt = 1.0 - p->cols[k].nv[j];
+ else
+ tt = p->cols[k].nv[j];
+ dif += tt * tt;
+ }
+ if (dif < bdif) { /* best so far */
+ bdif = dif;
+ bk = k;
+ if (dif < 0.001)
+ break; /* Don't bother looking further */
+ }
+ }
+
+ if (bdif < 0.02) {
+
+ /* Override the estimated combination values with the real values */
+ for (j = 0; j < (3+p->spec_n); j++) {
+#ifdef DEBUG
+ printf("comb 0x%x band %d was %f ",i, j, p->pc[i][j]);
+#endif
+ p->pc[i][j] = p->cols[bk].band[j];
+#ifdef DEBUG
+ printf("best %d now %f\n",bk, p->pc[i][j]);
+#endif
+ }
+ }
+ }
+
+ /* These initial primary combination values become the anchors during optimisation */
+ for (i = 0; i < p->nn; i++) {
+ for (j = 0; j < (3+p->spec_n); j++)
+ p->lpca[i][j] = lDE(p->pc[i][j]);
+ }
+
+ /* Allocate and init shape related parameter space */
+ init_shape(p);
+
+ p->cord = 1; /* Start with only 1 order */
+
+#ifndef DEBUG
+ if (p->verb)
+#endif /* !DEBUG */
+ {
+ deltae(p, &de, &mxde, &sde, &mxsde);
+ printf("Before optimising model have average dE of %f, max %f\n", de, mxde);
+ if (p->spec_n > 0) printf("and average spectral E of %f, max %f\n",sde, mxsde);
+ }
+
+ /* - - - - - - - - - - - - - - - - - */
+
+#ifndef NOPROCESS
+#ifdef NEVER // Skip efunc1 passes for now.
+ /* Do initial fast pass of optimisations */
+ /* using only first transfer curve order */
+ for (it = 0, p->ott = 3; it < p->ott; it++) {
+ double resid;
+
+ p->oit = it+1;
+
+ /* First optimise each input channels transfer curve */
+ for (k = 0; k < p->n; k++) { /* For each input channel */
+ double tw = 0.0; /* Total weight */
+
+ p->och = k; /* device channel being optimised */
+
+ /* Setup the appropriate weights */
+ for (i = 0; i < p->nodp; i++) {
+ mppcol *c = &p->cols[i];
+ double ww;
+ int kk;
+
+ for (ww = 0.0, kk = 0; kk < p->n; kk++) {
+ if (kk == k)
+ continue; /* Channel of interest can have any value */
+ ww += c->nv[kk] * c->nv[kk];
+ }
+ c->w = 1.0 - ww;
+ if (c->w < 0.0)
+ c->w = 0.0;
+ tw += c->w;
+
+//printf("~1 chan %d point %d weight %f\n",k,i,c->w);
+ }
+
+ if (tw < 3.0)
+ error ("MPP - not enough weighted point");
+
+ for (j = 0; j < (3+p->spec_n); j++) { /* For all bands */
+ double pv[MPP_MXTCORD]; /* Parameter values */
+ double sr[MPP_MXTCORD]; /* search radius */
+
+ p->oba = j; /* Band being optimised */
+
+ if (p->verb) {
+ printf("Optimising device transfer curves channel %d band %d:\n",k,j);
+ }
+
+ /* Get the current values */
+ for (i = 0; i < p->cord; i++) {
+ pv[i] = p->tc[k][j][i];
+ sr[i] = 0.05;
+ }
+
+ sfunc1(p); /* Setup test point values for this chan and band */
+
+ if (powell(&resid, p->cord, pv, sr, 0.001, 100, efunc1, (void *)p, mppprog, (void *)p) != 0)
+ error ("Powell failed");
+
+ /* Put results back into place */
+ for (i = 0; i < p->cord; i++) {
+ p->tc[k][j][i] = pv[i];
+ }
+ }
+#ifndef DEBUG
+ if (p->verb)
+#endif /* !DEBUG */
+ {
+ deltae(p, &de, &mxde, &sde, &mxsde);
+ printf("\nNow got avg dE of %f, max %f\n",de, mxde);
+ if (p->spec_n > 0)
+ printf("and avgerage spectral E of %f, max %f\n",sde, mxsde);
+ }
+ }
+ }
+#endif /* NEVER */
+
+ p->cord = mxtcord;
+
+ /* - - - - - - - - - - - - - - - - - */
+ /* Fine tune all parameters in the model */
+ for (mode = 0;;) {
+ double pv[MPP_MXPARMS]; /* Parameter values */
+ double sr[MPP_MXPARMS]; /* search radius */
+ int lj, yj = 0; /* Last band, peak Y band */
+
+ /* Decide which band to do next */
+ if (mode == 0) { /* Start at the beginning */
+ lj = -1;
+ if (p->spec_n == 0) {
+ mode = 3; /* Switch to doing Y values */
+ j = 1;
+ } else {
+ /* Start at the peak Y bandwidth */
+ j = (int)(p->spec_n * (555.0 - p->spec_wl_short)
+ /(p->spec_wl_long - p->spec_wl_short) + 0.5);
+ if (j < 0)
+ j = 0;
+ else if (j >= p->spec_n)
+ j = p->spec_n-1;
+ j += 3;
+ yj = j;
+ mode = 1; /* Switch to incrementing j */
+ }
+ } else if (mode == 1) { /* Increment j */
+ lj = j;
+ j++;
+ if (j >= (3+p->spec_n)) { /* We're finished moving up */
+ lj = yj;
+ j = yj-1;
+ mode = 2;
+ if (j < 3) { /* Just in case */
+ lj = yj;
+ j = 1;
+ mode = 3;
+ }
+ }
+ } else if (mode == 2) { /* Decrement j */
+ lj = j;
+ j--;
+ if (j < 3) {
+ lj = yj; /* We know that spect is valid */
+ j = 1;
+ mode = 3; /* Switch to Y mode */
+ }
+ } else if (mode == 3) { /* Doing Y mode */
+ if (spec_n > 0) {
+ /* Use spec at the peak X bandwidth */
+ lj = (int)(p->spec_n * (600.0 - p->spec_wl_short)
+ /(p->spec_wl_long - p->spec_wl_short) + 0.5);
+ if (lj < 0)
+ lj = 0;
+ else if (lj >= p->spec_n)
+ lj = p->spec_n-1;
+ lj += 3;
+ } else {
+ lj = 1;
+ }
+ j = 0; /* Doing X mode */
+ mode = 4;
+ } else if (mode == 4) { /* Doing X mode */
+ if (spec_n > 0) {
+ /* Use spec at the peak Z bandwidth */
+ lj = (int)(p->spec_n * (445.0 - p->spec_wl_short)
+ /(p->spec_wl_long - p->spec_wl_short) + 0.5);
+ if (lj < 0)
+ lj = 0;
+ else if (lj >= p->spec_n)
+ lj = p->spec_n-1;
+ lj += 3;
+ } else {
+ lj = 1;
+ }
+ j = 2; /* Doing Z mode */
+ mode = 5;
+ } else {
+ break; /* we're now done */
+ }
+
+ p->oba = j; /* Band being optimised */
+
+ if (p->verb)
+ printf("Doing band %d, last band %d\n",j,lj);
+
+ /* See if the last bands values are a good place to start */
+ if (lj >= 0) {
+ double cval, pval, p0val;
+
+ banderr(p, &cval, NULL, j); /* Current error */
+
+ /* Copy previous band transfer and shape into current band */
+ for (k = 0; k < p->n; k++)
+ for (i = 0; i < p->cord; i++) {
+ pv[k * p->cord + i] = p->tc[k][j][i]; /* Save current for restore */
+ p->tc[k][j][i] = p->tc[k][lj][i];
+ }
+ for (i = 0; i < p->nnn2; i++) {
+ int m = p->c2f[i].ink;
+ int n = p->c2f[i].comb;
+
+ sr[i] = p->shape[m][n][j];
+ p->shape[m][n][j] = p->shape[m][n][lj];
+ }
+ banderr(p, &pval, NULL, j);
+
+ /* Try out the urrent order 0 transfer values with rest of transfer and shape */
+ for (k = 0; k < p->n; k++)
+ p->tc[k][j][0] = pv[k * p->cord];
+ banderr(p, &p0val, NULL, j);
+
+ /* See which was best out of the three */
+ if (pval >= cval && p0val >= pval) { /* Original was the best */
+ for (k = 0; k < p->n; k++)
+ for (i = 0; i < p->cord; i++)
+ p->tc[k][j][i] = pv[k * p->cord + i]; /* Restore previous values */
+ for (i = 0; i < p->nnn2; i++) {
+ int m = p->c2f[i].ink;
+ int n = p->c2f[i].comb;
+ p->shape[m][n][j] = sr[i]; /* Restore previous value */
+ }
+//printf("~1 Starting values were best (%f && %f > %f)\n",pval,p0val,cval);
+ } else if (p0val >= pval) { /* Copying all was best */
+
+ for (k = 0; k < p->n; k++)
+ p->tc[k][j][0] = p->tc[k][lj][0]; /* Back to order 0 values */
+
+//printf("~1 copying all previous bands values was best (%f < %f && %f)\n",pval,cval,p0val);
+ } else {
+//printf("~1 copying except order 0 values was best (%f < %f && %f)\n",p0val,cval,pval);
+ }
+ }
+
+#ifdef MULTIPASS /* Multipass in parts */
+ for (it = 0, p->ott = maxit, thr = 1.0; it < maxit; it++, thr *= 0.2) {
+ double sde, mxsde;
+ double resid;
+
+ p->oit = it+1;
+
+ /* Optimise main transfer curve to minimise each bands error */
+ /* Initially using only first transfer curve order */
+
+ if (p->verb)
+ printf("Fine tuning device transfer curves itteration %d\n",it);
+
+ /* Get the current values */
+ for (k = 0; k < p->n; k++) {
+ for (i = 0; i < p->cord; i++) {
+ pv[k * p->cord + i] = p->tc[k][j][i];
+ sr[k * p->cord + i] = 0.05;
+ }
+ }
+#ifdef TESTDFUNC
+ test_dfunc2(p, p->n * p->cord, pv);
+#endif /* TESTDFUNC */
+#ifdef NODDV
+ if (powell(&resid, p->n * p->cord, pv, sr, thr * 0.01, 200,
+ efunc2, (void *)p, mppprog, (void *)p) != 0)
+ error ("Powell failed");
+#else /* !NODDV */
+ if (conjgrad(&resid, p->n * p->cord, pv, sr, thr * 0.01, 200,
+ efunc2, dfunc2, (void *)p, mppprog, (void *)p)!= 0)
+ error ("ConjGrad failed");
+#endif /* !NODDV */
+
+ /* Put results back into place */
+ for (k = 0; k < p->n; k++) {
+ for (i = 0; i < p->cord; i++)
+ p->tc[k][j][i] = pv[k * p->cord + i];
+ }
+
+#ifndef DEBUG
+ if (p->verb)
+#endif /* !DEBUG */
+ {
+ banderr(p, &sde, &mxsde, j); /* Current error */
+ printf("\nNow got avg E of %f, max %f for this band\n",sde, mxsde);
+ }
+
+ p->cord = mxtcord; /* maximum transfer curve order after very first run */
+
+ /* Tune the shaping parameters */
+ if (useshape) {
+
+ if (p->verb)
+ printf("Tuning detailed shaping parameters itteration %d\n",it);
+
+ sfunc3(p); /* Setup test point values for this band */
+
+ /* Get the current values */
+ for (i = 0; i < p->nnn2; i++) {
+ int m = p->c2f[i].ink;
+ int n = p->c2f[i].comb;
+
+ pv[i] = p->shape[m][n][j];
+ sr[i] = 0.01;
+ }
+
+#ifdef TESTDFUNC
+ test_dfunc3(p, p->nnn2, pv);
+#endif /* TESTDFUNC */
+#ifdef NODDV
+ if (powell(&resid, p->nnn2, pv, sr, thr * 0.05, 2000,
+ efunc3, (void *)p, mppprog, (void *)p) != 0)
+ error ("Powell failed");
+
+#else /* !NODDV */
+ if (conjgrad(&resid, p->nnn2, pv, sr, thr * 0.05, 2000,
+ efunc3, dfunc3, (void *)p, mppprog, (void *)p) != 0.0)
+ error ("ConjGrad failed");
+#endif /* !NODDV */
+
+ /* Put results back into place */
+ for (i = 0; i < p->nnn2; i++) {
+ int m = p->c2f[i].ink;
+ int n = p->c2f[i].comb;
+
+ p->shape[m][n][j] = pv[i];
+//printf("~1 shape[%d][%d] = %f\n",m,n,pv[i]);
+ }
+
+#ifndef DEBUG
+ if (p->verb)
+#endif /* !DEBUG */
+ {
+ banderr(p, &sde, &mxsde, j); /* Current error */
+ printf("\nNow got avg E of %f, max %f for this band\n",sde, mxsde);
+ }
+#ifdef DEBUG
+ dump_shape(p, 0, "After efunc3:");
+#endif /* DEBUG */
+
+ p->useshape = 1; /* Would be nice to flag this on a per band basis */
+ }
+
+ /* Tune the vertex parameters */
+
+ if (p->verb)
+ printf("Optimising device combination values itteration %d\n",it);
+
+ sfunc4(p); /* Setup test point values for this band */
+
+ /* Get the current values */
+ for (k = 0; k < p->nn; k++) {
+ pv[k] = p->pc[k][j];
+ sr[k] = 0.01;
+ }
+
+#ifdef TESTDFUNC
+ test_dfunc4(p, p->nn, pv);
+#endif /* TESTDFUNC */
+#ifdef NODDV
+ if (powell(&resid, p->nn, pv, sr, thr * 0.01, 500,
+ efunc4, (void *)p, mppprog, (void *)p) != 0)
+ error ("Powell failed");
+#else /* !NODDV */
+ if (conjgrad(&resid, p->nn, pv, sr, thr * 0.01, 500,
+ efunc4, dfunc4, (void *)p, mppprog, (void *)p) != 0)
+ error ("ConjGrad failed");
+#endif /* !NODDV */
+
+ /* Put results back into place */
+ for (k = 0; k < p->nn; k++) {
+ double pp = pv[k];
+ if (pp < 0.0)
+ pp = 0.0;
+ p->pc[k][j] = pp;
+ }
+
+#ifndef DEBUG
+ if (p->verb)
+#endif /* !DEBUG */
+ {
+ banderr(p, &sde, &mxsde, j); /* Current error */
+ printf("\nNow got avg E of %f, max %f for this band\n",sde, mxsde);
+ }
+ }
+#endif /* MULTIPASS */
+
+#ifdef BIGBANG
+ /* Do optimisation with one big bang */
+ {
+ double resid;
+ double *pv2, *pv3, *pv4; /* Pointers to each group of parameters */
+ double *sr2, *sr3, *sr4; /* Pointers to each group of search radius */
+ int tparms = p->n * p->cord + p->nnn2 + p->nn;
+
+ pv2 = pv;
+ pv3 = pv + (p->n * p->cord);
+ pv4 = pv + (p->n * p->cord) + p->nnn2;
+ sr2 = sr;
+ sr3 = sr + (p->n * p->cord);
+ sr4 = sr + (p->n * p->cord) + p->nnn2;
+
+ /* Get the current transfer values */
+ for (k = 0; k < p->n; k++) {
+ for (i = 0; i < p->cord; i++) {
+ pv2[k * p->cord + i] = p->tc[k][j][i];
+ sr2[k * p->cord + i] = 0.005;
+ }
+ }
+ /* Get the current shaper values */
+ for (i = 0; i < p->nnn2; i++) {
+ int m = p->c2f[i].ink;
+ int n = p->c2f[i].comb;
+
+ pv3[i] = p->shape[m][n][j];
+ sr3[i] = 0.005;
+ }
+ /* Get the current device combination values */
+ for (k = 0; k < p->nn; k++) {
+ pv4[k] = p->pc[k][j];
+ sr4[k] = 0.005;
+ }
+
+#ifdef TESTDFUNC
+ test_dfunc0(p, tparms, pv);
+#endif /* TESTDFUNC */
+
+ if (conjgrad(&resid, tparms, pv, sr, 0.001, 4000, efunc0, dfunc0, (void *)p,
+ mppprog, (void *)p) != 0)
+ error ("ConjGrad failed");
+
+ /* Put results back into place */
+ for (k = 0; k < p->n; k++) {
+ for (i = 0; i < p->cord; i++)
+ p->tc[k][j][i] = pv2[k * p->cord + i];
+ }
+ for (i = 0; i < p->nnn2; i++) {
+ int m = p->c2f[i].ink;
+ int n = p->c2f[i].comb;
+
+ p->shape[m][n][j] = pv3[i];
+ }
+ for (k = 0; k < p->nn; k++) {
+ double pp = pv4[k];
+ if (pp < 0.0)
+ pp = 0.0;
+ p->pc[k][j] = pp;
+ }
+
+#ifndef DEBUG
+ if (p->verb)
+#endif /* !DEBUG */
+ {
+ banderr(p, &sde, &mxsde, j); /* Current error */
+ printf("\nNow got avg E of %f, max %f for this band\n",sde, mxsde);
+ }
+ }
+#endif /* BIGBANG */
+ }
+#endif /* NOPROCESS */
+
+#ifdef DEBUG
+ if (p->verb)
+#endif /* !DEBUG */
+ {
+ double de, mxde;
+ deltae(p, &de, &mxde, &sde, &mxsde);
+ printf("\nNow got avg dE of %f, max %f\n",de, mxde);
+ if (p->spec_n > 0)
+ printf("and avgerage spectral E of %f, max %f\n",sde, mxsde);
+ }
+
+#ifdef DOPLOT /* Plot the device curves */
+ {
+#define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+
+ for (i = 0; i < (3+p->spec_n); i++) {
+ printf("Band %d:\n",i);
+ for (j = 0; j < p->n; j++) {
+ printf("Ink %d:\n",j);
+
+ for (k = 0; k < XRES; k++) {
+ double x;
+ x = k/(double)(XRES-1);
+ xx[k] = x;
+ y1[k] = icxTransFunc(p->tc[j][i], p->cord, x);
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+ }
+ }
+#endif /* DOPLOT */
+
+ /* Figure out the white and black points */
+ compute_wb(p);
+
+ /* Done with our copy of the input points */
+ free (p->cols);
+ p->nodp = 0;
+ p->cols = NULL;
+
+ return 0;
+}
+
+
+#ifdef DEBUG
+
+/* Dump current shape params to a file */
+static void dump_shape(mpp *p, int first, char *title) {
+ int i,j,k;
+ FILE *df;
+ /* Some debug code */
+
+ if (first) {
+ if ((df = fopen("debug.txt","w")) == NULL)
+ error ("Failed to open debug.txt");
+ } else {
+ if ((df = fopen("debug.txt","a")) == NULL)
+ error ("Failed to open debug.txt");
+ }
+
+ fprintf(df,"%s\n",title);
+
+ for (i = 0; i < (3+p->spec_n); i++) {
+ fprintf(df,"Band %d:\n",i);
+ for (j = 0; j < p->n; j++) {
+ fprintf(df,"Ink %d:\n",j);
+
+ for (k = 0; k < p->nn; k++) {
+ if ((k & (1<<j)) == 0) {
+ int m, n;
+ double val = 0.0;
+ fprintf(df,"Comb %d = %f\n", k, p->shape[j][k][i]);
+ }
+ }
+ fprintf(df,"\n");
+ }
+ fprintf(df,"\n");
+ }
+ fclose(df);
+}
+
+/* Combine two first order shapers coefficients together */
+static double comb(double n1, double n2) {
+ double nn;
+ if (n1 > 0.0)
+ n1 = (n1+1.0);
+ else
+ n1 = 1.0/(1.0-n1);
+
+ if (n2 > 0.0)
+ n2 = (n2+1.0);
+ else
+ n2 = 1.0/(1.0-n2);
+
+ nn = n1 * n2;
+
+ if (nn >= 1.0)
+ nn -= 1.0;
+ else
+ nn = 1.0-(1.0/nn);
+
+ return nn;
+}
+
+#endif /* DEBUG */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/mpp.h b/xicc/mpp.h
new file mode 100644
index 0000000..0becaad
--- /dev/null
+++ b/xicc/mpp.h
@@ -0,0 +1,268 @@
+#ifndef MPP_H
+#define MPP_H
+
+/*
+ * Argyll Color Correction System
+ * Model Printer Profile object.
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/2/2002
+ *
+ * Copyright 2002 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.
+ *
+ */
+
+/* This version (based on mpp_x1) has n * 2^(n-1) shape params, */
+/* used for linear interpolation of the shaping correction. */
+
+/*
+ * This object provides a model based printer forward profile
+ * functionality, to support forward profiling and optimised
+ * separation of printing devices with more than 4 inks.
+ */
+
+/* ------------------------------------------------------------------------------ */
+
+#define MPP_MXINKS 8 /* Would like to be ICX_MXINKS but need more dynamic allocation */
+#define MPP_MXTCORD 10 /* Maxkimum shaper harmonic orders to use */
+#define MPP_MXCCOMB (1 << MPP_MXINKS) /* Maximum number of primary combinations */
+#define MPP_MXPARMS (MPP_MXINKS * MPP_MXTCORD + (MPP_MXINKS * MPP_MXCCOMB/2) + MPP_MXCCOMB)
+ /* Maximum total parameters for a band */
+#define MPP_MXBANDS 61 /* Maximum number of spectral bands (enought for 10nm) */
+
+/* A test patch value */
+typedef struct {
+ /* public: */
+ double *nv; /* [MPP_MXINKS] Device values */
+ double *band; /* [3+MPP_MXBANDS]; Target XYZ & Spectral reflectance values */
+
+ /* private: */
+ double w; /* Weight for this pass */
+ double *lband; /* [3+MPP_MXBANDS]; L* scale Target XYZ & Spectral reflectance values */
+ double Lab[3]; /* Target Lab value */
+ double tpcnv, tpcnv1; /* Intermediate values for band oba without channel och */
+ double *tcnv; /* [MPP_MXINKS] Transfer curve corrected device values */
+ double *scnv; /* [MPP_MXINKS] Ideal shape correction values for device input */
+ double *pcnv; /* [MPP_MXCCOMB] Primary combination values (pre or post shape) */
+ double *fcnv; /* [MPP_MXINKS * MPP_MXCCOMB/2] shape interpolation weights for och */
+ double cXYZ[3]; /* Current model XYZ value */
+ double err; /* Delta E squared */
+} mppcol;
+
+struct _mpp {
+
+ /* Public: */
+ void (*del)(struct _mpp *p);
+
+
+ /* Create the mpp from scattered data points */
+ /* Returns nz on error */
+ int (*create) (struct _mpp *p,
+ int verb, /* Vebosity level, 0 = none */
+ int quality, /* Profile quality, 0..3 */
+ int display, /* non-zero if display device */
+ double limit, /* Total ink limit (not %) (if not display) */
+ inkmask imask, /* Inkmask describing device colorspace */
+ int spec_n, /* Number of spectral bands, 0 if not valid */
+ double spec_wl_short, /* First reading wavelength in nm (shortest) */
+ double spec_wl_long, /* Last reading wavelength in nm (longest) */
+ double norm, /* Normalising scale value */
+ instType itype, /* Spectral instrument type (if not display) */
+ int no, /* Number of points */
+ mppcol *points); /* Array of input points */
+
+ int (*write_mpp)(struct _mpp *p, char *filename, int lab); /* write to a CGATS .mpp file */
+ int (*read_mpp)(struct _mpp *p, char *filename); /* read from a CGATS .mpp file */
+
+ /* Get various types of information about the mpp */
+ void (*get_info) (struct _mpp *p,
+ inkmask *imask, /* Inkmask, describing device colorspace */
+ int *nodchan, /* Number of device channels */
+ double *limit, /* Total ink limit (0.0 .. devchan) */
+ int *spec_n, /* Number of spectral bands, 0 if none */
+ double *spec_wl_short,/* First reading wavelength in nm (shortest) */
+ double *spec_wl_long, /* Last reading wavelength in nm (longest) */
+ instType *itype, /* Instrument type */
+ int *display); /* NZ if display type */
+
+ /* Set an illuminant and observer to use spectral model */
+ /* for CIE lookup with optional FWA. Set both to default for XYZ mpp model. */
+ /* Return 0 on OK, 1 on spectral not supported */
+ /* If the model is for a display, the illuminant will be ignored. */
+ int (*set_ilob) (struct _mpp *p,
+ icxIllumeType ilType, /* Illuminant type (icxIT_default for none) */
+ xspect *custIllum, /* Custom illuminant (NULL for none) */
+ icxObserverType obType, /* Observer type (icxOT_default for none) */
+ xspect custObserver[3], /* Custom observer (NULL for none) */
+ icColorSpaceSignature rcs, /* Return color space, icSigXYZData or icSigLabData */
+ int use_fwa /* NZ to involke FWA. */
+ );
+
+ /* Get the white and black points for this profile (default XYZ) */
+ void (*get_wb) (struct _mpp *p,
+ double *white,
+ double *black,
+ double *kblack);
+
+
+ /* Lookup an XYZ or Lab color (default XYZ) */
+ /* [will use spectral and FWA if configured] */
+ void (*lookup) (struct _mpp *p,
+ double *out, /* Returned XYZ or Lab */
+ double *in); /* Input device values */
+
+ /* Lookup an XYZ or Lab color with its partial derivative. */
+ /* [will ignore spectral and FWA even if configured] */
+ void (*dlookup)(struct _mpp *p,
+ double *out, /* Return the XYZ or Lab */
+ double **dout, /* Return the partial derivative dout[3][n] */
+ double *dev);
+
+ /* Lookup an XYZ value. (never FWA corrected) */
+ void (*lookup_xyz) (struct _mpp *p,
+ double *out, /* Returned XYZ value */
+ double *in); /* Input device values */
+
+ /* Lookup a spectral value. (never FWA corrected) */
+ void (*lookup_spec) (struct _mpp *p,
+ xspect *out, /* Returned spectral value */
+ double *in); /* Input device values */
+
+ /* Return a gamut object, return NULL on error */
+ gamut *(*get_gamut)(struct _mpp *p, double detail); /* detail level 0.0 = default */
+
+ /* Private: */
+ int verb; /* Verbose */
+
+ /* General model information */
+ int display; /* Non-zero if display profile rather than output */
+ inkmask imask; /* Inkmask describing device space */
+ double limit; /* Total ink limit (If output device) */
+ int spec_n; /* Number of spectral bands, 0 if not valid */
+ double spec_wl_short; /* First reading wavelength in nm (shortest) */
+ double spec_wl_long; /* Last reading wavelength in nm (longest) */
+ double norm; /* Normalising scale value (will be 1.0) */
+ instType itype; /* Spectral instrument type (If output device) */
+ mppcol white, black; /* White and black points */
+ mppcol kblack; /* K only black point */
+
+ /* Foward model parameters */
+ int n; /* Number of chanels */
+ int nn; /* Number of primary combinations = 1 << n */
+ int nnn2; /* Total shape combinations = n * nn/2 */
+
+ int cord; /* Device transfer curve order (must be 1 <= cord <= MPP_MXTCORD) */
+ double tc[MPP_MXINKS][3+MPP_MXBANDS][MPP_MXTCORD]; /* Device transfer curve parameters */
+ int useshape; /* Flag, NZ if shape parameters are being used */
+ double ***shape; /* [MPP_MXINKS][MPP_MXCCOMB][3+MPP_MXBANDS] Extra shaping parameters */
+ double pc[MPP_MXCCOMB][3+MPP_MXBANDS]; /* Primary overlay combinations color values */
+
+ /* Model housekeeping */
+ /* Translate sparse shape color combo to compacted parameters and back */
+ int f2c[MPP_MXINKS][MPP_MXCCOMB]; /* Full to Compact */
+ struct { int ink; int comb; } c2f[MPP_MXINKS * MPP_MXCCOMB/2]; /* Compact to Full */
+
+ /* Optimisation state */
+ mppcol *otp; /* Optimisation test point */
+ int oit, ott; /* Optimisation itteration and total itterations */
+ int och; /* Optimisation device channel 0..n-1 */
+ int oba; /* Optimisation band, 0..2 are XYZ, 3..spec_n+3 are spectral */
+ double lpca[MPP_MXCCOMB][MPP_MXBANDS]; /* Primary combinations anchor L* band values */
+ int nodp; /* Number of device data points */
+ mppcol *cols; /* List of test points */
+ double spmax; /* Maximum spectral value of any sample and band */
+
+ /* Lookup */
+ icColorSpaceSignature pcs; /* PCS to return, XYZ, Lab */
+ xsp2cie *spc; /* Spectral to CIE converter (NULL if using XYZ model) */
+
+ /* Houskeeping */
+ int errc; /* Error code */
+ char err[200]; /* Error message */
+}; typedef struct _mpp mpp;
+
+/* Create a new, uninitialised mpp */
+mpp *new_mpp(void);
+
+
+/* - - - - - - - - - - - - - */
+/* mppcol utility functions */
+/* Allocate the data portion of an mppcol */
+/* Return NZ if malloc error */
+int new_mppcol(
+mppcol *p, /* mppcol to allocate */
+int n, /* Number of inks */
+int nb /* Number of spectral bands */
+);
+
+/* Free the data allocation of an mppcol */
+void del_mppcol(
+mppcol *p, /* mppcol to free */
+int n, /* Number of inks */
+int nb /* Number of spectral bands */
+);
+
+/* Copy the contents of one mppcol to another */
+void copy_mppcol(
+ mppcol *d, /* Destination */
+ mppcol *s, /* Source */
+ int n, /* Number of inks */
+ int nb /* Number of spectral bands */
+);
+
+/* Allocate an array of mppcol, */
+/* Return NULL if malloc error */
+mppcol *new_mppcols(
+ int no, /* Number in array */
+ int n, /* Number of inks */
+ int nb /* Number of spectral bands */
+);
+
+/* Free an array of mppcol */
+void del_mppcols(
+ mppcol *p, /* mppcol array to be free'd */
+ int no, /* Number in array */
+ int n, /* Number of inks */
+ int nb /* Number of spectral bands */
+);
+
+#endif /* MPP_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/mpplu.c b/xicc/mpplu.c
new file mode 100644
index 0000000..dcbd1c3
--- /dev/null
+++ b/xicc/mpplu.c
@@ -0,0 +1,1355 @@
+
+/*
+ * Model Printer Profile Lookup test utility.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2002/12/30
+ * Version: 1.00
+ *
+ * Copyright 2002, 2003 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.
+ *
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "numlib.h"
+#include "xicc.h"
+#include "counters.h"
+
+void usage(void) {
+ fprintf(stderr,"Translate colors through an MPP profile, V1.00\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: mpplu [-v] [-f func] [-i intent] [-o order] profile\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -f function f = forward, b = backwards\n");
+ fprintf(stderr," -p oride x = XYZ_PCS, l = Lab_PCS, y = Yxy, s = spectral,\n");
+ fprintf(stderr," -l limit override default ink limit, 1 - N00%%\n");
+ fprintf(stderr," -i illum Choose illuminant for print/transparency spectral data:\n");
+ fprintf(stderr," A, C, D50 (def.), D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf(stderr," -o observ Choose CIE Observer for spectral data:\n");
+ fprintf(stderr," 1931_2 (def), 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
+ fprintf(stderr," -u Use Fluorescent Whitening Agent compensation\n");
+ fprintf(stderr," -g Create gamut output\n");
+ fprintf(stderr," -w Create gamut VRML as well\n");
+ fprintf(stderr," -n Don't add VRML axes\n");
+ fprintf(stderr," -a n Gamut transparency level\n");
+ fprintf(stderr," -d n Gamut surface detail level\n");
+ fprintf(stderr," -t num Invoke debugging test code \"num\" 1..n\n");
+ fprintf(stderr," 1 - check partial derivative for device input\n");
+ fprintf(stderr," 2 - create overlap diagnostic VRML gamut surface\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr," The colors to be translated should be fed into stdin,\n");
+ fprintf(stderr," one input color per line, white space separated.\n");
+ fprintf(stderr," A line starting with a # will be ignored.\n");
+ fprintf(stderr," A line not starting with a number will terminate the program.\n");
+ exit(1);
+}
+
+static void diag_gamut(mpp *p, double gamres, int doaxes, double trans, char *outname);
+static void mpp_rev(mpp *mppo, double limit, double *out, double *in);
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char prof_name[100];
+ mpp *mppo;
+ int verb = 0;
+ int test = 0; /* special test code */
+ int dogam = 0; /* Create gamut */
+ int dowrl = 0; /* Create VRML gamut */
+ int doaxes = 1; /* Create VRML axes */
+ double trans = 0.0; /* Transparency */
+ double gamres = 0.0; /* Gamut resolution */
+ int repYxy = 0; /* Report Yxy */
+ int repSpec = 0; /* Report Spectral */
+ int bwd = 0; /* Do reverse lookup */
+ double dlimit; /* Device ink limit */
+ double limit = -1.0; /* Used ink limit */
+ int display = 0; /* NZ if display type */
+ int spec = 0; /* Use spectral data flag */
+ int spec_n; /* Number of spectral bands, 0 if not valid */
+ double spec_wl_short; /* First reading wavelength in nm (shortest) */
+ double spec_wl_long; /* Last reading wavelength in nm (longest) */
+ int fwacomp = 0; /* FWA compensation */
+ icxIllumeType illum = icxIT_default; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxObserverType observ = icxOT_default;
+ char buf[200];
+ double in[MAX_CHAN], out[MAX_CHAN];
+ int rv = 0;
+
+ inkmask imask; /* Device Ink mask */
+ char *ident = NULL; /* Device colorspec description */
+ icColorSpaceSignature pcss; /* Type of PCS space */
+ int devn, pcsn; /* Number of components */
+
+ icColorSpaceSignature pcsor = icSigLabData; /* Default */
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ /* function */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'f':
+ case 'F':
+ bwd = 0;
+ break;
+ case 'b':
+ case 'B':
+ bwd = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* PCS override */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'x':
+ case 'X':
+ pcsor = icSigXYZData;
+ repYxy = repSpec = 0;
+ break;
+ case 'l':
+ case 'L':
+ pcsor = icSigLabData;
+ repYxy = repSpec = 0;
+ break;
+ case 'y':
+ case 'Y':
+ pcsor = icSigXYZData;
+ repYxy = 1;
+ repSpec = 0;
+ break;
+ case 's':
+ case 'S':
+ pcsor = icSigXYZData;
+ repYxy = 0;
+ repSpec = 1;
+ spec = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Ink Limit */
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage();
+ limit = atof(na);
+ }
+
+ /* Spectral Illuminant type */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "A") == 0) {
+ spec = 1;
+ illum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ spec = 1;
+ illum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0) {
+ spec = 1;
+ illum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0) {
+ spec = 1;
+ illum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ spec = 1;
+ illum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ spec = 1;
+ illum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ spec = 1;
+ illum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ spec = 1;
+ illum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ spec = 1;
+ illum = icxIT_custom;
+ if (read_xspect(&cust_illum, na) != 0)
+ usage();
+ }
+ }
+
+ /* Spectral Observer type */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ spec = 1;
+ observ = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ spec = 1;
+ observ = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ spec = 1;
+ observ = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ spec = 1;
+ observ = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ spec = 1;
+ observ = icxOT_Shaw_Fairchild_2;
+ } else
+ usage();
+ }
+
+ /* Fluerescent Whitner compensation */
+ else if (argv[fa][1] == 'u' || argv[fa][1] == 'U')
+ fwacomp = 1;
+
+ /* Gamut plot */
+ else if (argv[fa][1] == 'g' || argv[fa][1] == 'G')
+ dogam = 1;
+
+ /* VRML plot */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ dogam = 1;
+ dowrl = 1;
+ }
+
+ /* No VRML axes */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ doaxes = 0;
+ }
+
+ /* Transparency */
+ else if (argv[fa][1] == 'a' || argv[fa][1] == 'A') {
+ fa = nfa;
+ if (na == NULL) usage();
+ trans = atof(na);
+ }
+
+ /* Surface Detail */
+ else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ fa = nfa;
+ if (na == NULL) usage();
+ gamres = atof(na);
+ dogam = 1;
+ }
+
+ /* Test code */
+ else if (argv[fa][1] == 't' || argv[fa][1] == 'T') {
+ fa = nfa;
+ if (na == NULL) usage();
+ test = atoi(na);
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(prof_name,argv[fa]);
+
+ if ((mppo = new_mpp()) == NULL)
+ error ("Creation of MPP object failed");
+
+ if ((rv = mppo->read_mpp(mppo,prof_name)) != 0)
+ error ("%d, %s",rv,mppo->err);
+
+ mppo->get_info(mppo, &imask, &devn, &dlimit, &spec_n, &spec_wl_short, &spec_wl_long, NULL, &display);
+ ident = icx_inkmask2char(imask, 1);
+
+ if (verb) {
+ printf("MPP profile with %d colorants, type %s, TAC %f\n",devn,ident, dlimit);
+ if (display)
+ printf("MPP profile is for a display type device\n");
+ }
+
+ if (limit <= 0.0 || dlimit < limit)
+ limit = dlimit;
+
+ pcss = pcsor;
+ pcsn = 3;
+
+ if (spec && spec_n == 0) {
+ error("Spectral profile needed for spectral result, custom illuminant, observer or FWA");
+ }
+
+ /* Select CIE return value details */
+ if ((rv = mppo->set_ilob(mppo, illum, &cust_illum, observ, NULL, pcss, fwacomp)) != 0) {
+ if (rv == 1)
+ error("Spectral profile needed for custom illuminant, observer or FWA");
+ error("Error setting illuminant, observer, or FWA");
+ }
+
+ if (test != 0) {
+ printf("!!!!! Running special test code no %d !!!!!\n",test);
+
+ if (test == 1) {
+ double **dv, **rdv;
+
+ dv = dmatrix(0, pcsn-1, 0, devn-1);
+ rdv = dmatrix(0, pcsn-1, 0, devn-1);
+
+ printf("Checking partial derivative at each input value\n");
+ /* Process colors to translate */
+ for (;;) {
+ int i,j;
+ char *bp, *nbp;
+ double tout[MAX_CHAN];
+
+ /* Read in the next line */
+ if (fgets(buf, 200, stdin) == NULL)
+ break;
+ if (buf[0] == '#') {
+ fprintf(stdout,"%s\n",buf);
+ continue;
+ }
+ /* For each input number */
+ for (bp = buf-1, nbp = buf, i = 0; i < MAX_CHAN; i++) {
+ bp = nbp;
+ in[i] = strtod(bp, &nbp);
+ if (nbp == bp)
+ break; /* Failed */
+ }
+ if (i == 0)
+ break;
+
+ /* Do conversion */
+ mppo->lookup(mppo, out, in);
+ mppo->dlookup(mppo, out, dv, in);
+
+ for (j = 0; j < devn; j++) {
+ double del = 1e-9;
+
+ if (in[j] > 0.5)
+ del = -del;
+
+ in[j] += del;
+ mppo->lookup(mppo, tout, in);
+ in[j] -= del;
+
+ for (i = 0; i < pcsn; i++) {
+ rdv[i][j] = (tout[i] - out[i])/del;
+ }
+ }
+
+ /* Output the results */
+ for (j = 0; j < devn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",in[j]);
+ else
+ fprintf(stdout,"%f",in[j]);
+ }
+ printf(" [%s] -> ", ident);
+
+ for (j = 0; j < pcsn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",out[j]);
+ else
+ fprintf(stdout,"%f",out[j]);
+ }
+ printf(" [%s]\n", icm2str(icmColorSpaceSignature, pcss));
+
+ /* Print the derivatives */
+ for (i = 0; i < pcsn; i++) {
+
+ printf("Output chan %d: ",i);
+ for (j = 0; j < devn; j++) {
+ if (j < (devn-1))
+ fprintf(stdout,"%f ref %f, ",dv[i][j], rdv[i][j]);
+ else
+ fprintf(stdout,"%f ref %f\n",dv[i][j], rdv[i][j]);
+ }
+ }
+ }
+
+ free_dmatrix(dv, 0, pcsn-1, 0, devn-1);
+ free_dmatrix(rdv, 0, pcsn-1, 0, devn-1);
+
+ } else if (test == 2) {
+ char *xl, gam_name[100];
+
+ strcpy(gam_name, prof_name);
+ if ((xl = strrchr(gam_name, '.')) == NULL) /* Figure where extention is */
+ xl = gam_name + strlen(gam_name);
+
+ strcpy(xl,".wrl");
+ diag_gamut(mppo, gamres, doaxes, trans, gam_name);
+
+ } else {
+ printf("Unknown test!\n");
+ }
+
+ } else if (dogam) {
+ gamut *gam;
+ char *xl, gam_name[100];
+ int docusps = 1;
+
+ if ((gam = mppo->get_gamut(mppo, gamres)) == NULL)
+ error("get_gamut failed\n");
+
+ strcpy(gam_name, prof_name);
+ if ((xl = strrchr(gam_name, '.')) == NULL) /* Figure where extention is */
+ xl = gam_name + strlen(gam_name);
+
+ strcpy(xl,".gam");
+ if (gam->write_gam(gam,gam_name))
+ error ("write gamut failed on '%s'",gam_name);
+
+ if (dowrl) {
+ strcpy(xl,".wrl");
+ if (gam->write_vrml(gam,gam_name, doaxes, docusps))
+ error ("write vrml failed on '%s'",gam_name);
+ }
+
+ gam->del(gam);
+
+ } else {
+ /* Normal color lookup */
+
+ if (repYxy) { /* report Yxy rather than XYZ */
+ if (pcss == icSigXYZData)
+ pcss = icSigYxyData;
+ }
+
+ /* Process colors to translate */
+ for (;;) {
+ int i,j;
+ char *bp, *nbp;
+
+ /* Read in the next line */
+ if (fgets(buf, 200, stdin) == NULL)
+ break;
+ if (buf[0] == '#') {
+ fprintf(stdout,"%s\n",buf);
+ continue;
+ }
+ /* For each input number */
+ for (bp = buf-1, nbp = buf, i = 0; i < MAX_CHAN; i++) {
+ bp = nbp;
+ in[i] = strtod(bp, &nbp);
+ if (nbp == bp)
+ break; /* Failed */
+ }
+ if (i == 0)
+ break;
+
+ if (!bwd) {
+
+ if (repSpec) {
+ xspect ospec;
+
+ /* Do lookup of spectrum */
+ mppo->lookup_spec(mppo, &ospec, in);
+
+ /* Output the results */
+ for (j = 0; j < devn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",in[j]);
+ else
+ fprintf(stdout,"%f",in[j]);
+ }
+ printf(" [%s] -> ", ident);
+
+ for (j = 0; j < spec_n; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",ospec.spec[j]);
+ else
+ fprintf(stdout,"%f",ospec.spec[j]);
+ }
+
+ printf(" [%3.0f .. %3.0f nm]\n", spec_wl_short, spec_wl_long);
+
+ } else {
+
+ /* Do conversion */
+ mppo->lookup(mppo, out, in);
+
+ /* Output the results */
+ for (j = 0; j < devn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",in[j]);
+ else
+ fprintf(stdout,"%f",in[j]);
+ }
+ printf(" [%s] -> ", ident);
+
+ if (repYxy && pcss == icSigYxyData) {
+ double X = out[0];
+ double Y = out[1];
+ double Z = out[2];
+ double sum = X + Y + Z;
+ if (sum < 1e-6) {
+ out[0] = out[1] = out[2] = 0.0;
+ } else {
+ out[0] = Y;
+ out[1] = X/sum;
+ out[2] = Y/sum;
+ }
+ }
+ for (j = 0; j < pcsn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",out[j]);
+ else
+ fprintf(stdout,"%f",out[j]);
+ }
+
+ printf(" [%s]\n", icm2str(icmColorSpaceSignature, pcss));
+ }
+
+ } else { /* Do a reverse lookup */
+
+ if (repYxy && pcss == icSigYxyData) {
+ double Y = in[0];
+ double x = in[1];
+ double y = in[2];
+ double z = 1.0 - x - y;
+ double sum;
+ if (y < 1e-6) {
+ in[0] = in[1] = in[2] = 0.0;
+ } else {
+ sum = Y/y;
+ in[0] = x * sum;
+ in[1] = Y;
+ in[2] = z * sum;
+ }
+ }
+
+ /* Do conversion */
+ mpp_rev(mppo, limit, out, in);
+
+ /* Output the results */
+ for (j = 0; j < pcsn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",in[j]);
+ else
+ fprintf(stdout,"%f",in[j]);
+ }
+ printf(" [%s] -> ", icm2str(icmColorSpaceSignature, pcss));
+
+ for (j = 0; j < devn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",out[j]);
+ else
+ fprintf(stdout,"%f",out[j]);
+ }
+
+ printf(" [%s]\n", ident);
+ }
+ }
+ }
+
+ free(ident);
+ mppo->del(mppo);
+
+ return 0;
+}
+
+
+/* -------------------------------------------- */
+/* Code for special gamut surface plot */
+
+#define GAMUT_LCENT 50
+
+/* Create a diagnostic gamut, illustrating */
+/* device space "fold-over" */
+/* (This will be in the current PCS, but assumed to be Lab) */
+static void diag_gamut(
+mpp *p, /* This */
+double detail, /* Gamut resolution detail */
+int doaxes,
+double trans, /* Transparency */
+char *outname /* Output VRML file */
+) {
+ int i, j;
+ FILE *wrl;
+ struct {
+ double x, y, z;
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+ int vix; /* Vertex index */
+ DCOUNT(coa, MAX_CHAN, p->n, 0, 0, 2);
+ double col[MPP_MXCCOMB][3]; /* Color asigned to each major vertex */
+ int res;
+
+ /* Asign some colors to the combination nodes */
+ for (i = 0; i < p->nn; i++) {
+ int a, b, c, j;
+ double h;
+
+ j = (i ^ 0x5a5a5a5a) % p->nn;
+ h = (double)j/(p->nn-1);
+
+ /* Make fully saturated with chosen hue */
+ if (h < 1.0/3.0) {
+ a = 0;
+ b = 1;
+ c = 2;
+ } else if (h < 2.0/3.0) {
+ a = 1;
+ b = 2;
+ c = 0;
+ h -= 1.0/3.0;
+ } else {
+ a = 2;
+ b = 0;
+ c = 1;
+ h -= 2.0/3.0;
+ }
+ h *= 3.0;
+
+ col[i][a] = (1.0 - h);
+ col[i][b] = h;
+ col[i][c] = d_rand(0.0, 1.0);
+ }
+
+ if (detail > 0.0)
+ res = (int)(100.0/detail); /* Establish an appropriate sampling density */
+ else
+ res = 4;
+
+ if (res < 2)
+ res = 2;
+
+ if ((wrl = fopen(outname,"w")) == NULL)
+ error("Error opening wrl output file '%s'",outname);
+
+ /* Spit out a VRML 2 Object surface of gamut */
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ fprintf(wrl,"# Lab axes as boxes:\n");
+ for (i = 0; i < 5; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape{\n");
+ fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
+ axes[i].wx, axes[i].wy, axes[i].wz);
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"\n");
+ }
+ fprintf(wrl," Transform {\n");
+ fprintf(wrl," translation 0 0 0\n");
+ fprintf(wrl," children [\n");
+ fprintf(wrl," Shape { \n");
+ fprintf(wrl," geometry IndexedFaceSet {\n");
+ fprintf(wrl," solid FALSE\n"); /* Don't back face cull */
+ fprintf(wrl," convex TRUE\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [ # Verticy coordinates\n");
+
+
+ /* Itterate over all the faces in the device space */
+ /* generating the vertx positions. */
+ DC_INIT(coa);
+ vix = 0;
+ while(!DC_DONE(coa)) {
+ int e, m1, m2;
+ double in[MAX_CHAN];
+ double out[3];
+ double sum;
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < p->n; m1++) {
+ if (coa[m1] != 0)
+ continue;
+
+ for (m2 = m1 + 1; m2 < p->n; m2++) {
+ int x, y;
+
+ if (coa[m2] != 0)
+ continue;
+
+ for (sum = 0.0, e = 0; e < p->n; e++)
+ in[e] = (double)coa[e]; /* Base value */
+
+ /* Scan over 2D device space face */
+ for (x = 0; x < res; x++) { /* step over surface */
+ in[m1] = x/(res - 1.0);
+ for (y = 0; y < res; y++) {
+ in[m2] = y/(res - 1.0);
+
+ p->lookup(p, out, in);
+ fprintf(wrl,"%f %f %f,\n",out[1], out[2], out[0]-50.0);
+ vix++;
+ }
+ }
+ }
+ }
+ /* Increment index within block */
+ DC_INC(coa);
+ }
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," coordIndex [ # Indexes of poligon Verticies \n");
+
+ /* Itterate over all the faces in the device space */
+ /* generating the quadrilateral indexes. */
+ DC_INIT(coa);
+ vix = 0;
+ while(!DC_DONE(coa)) {
+ int e, m1, m2;
+ double in[MAX_CHAN];
+ double sum;
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < p->n; m1++) {
+ if (coa[m1] != 0)
+ continue;
+
+ for (m2 = m1 + 1; m2 < p->n; m2++) {
+ int x, y;
+
+ if (coa[m2] != 0)
+ continue;
+
+ for (sum = 0.0, e = 0; e < p->n; e++)
+ in[e] = (double)coa[e]; /* Base value */
+
+ /* Scan over 2D device space face */
+ for (x = 0; x < res; x++) { /* step over surface */
+ for (y = 0; y < res; y++) {
+
+ if (x < (res-1) && y < (res-1)) {
+ fprintf(wrl,"%d, %d, %d, %d, -1\n",
+ vix, vix + 1, vix + 1 + res, vix + res);
+ }
+ vix++;
+ }
+ }
+ }
+ }
+ /* Increment index within block */
+ DC_INC(coa);
+ }
+
+ fprintf(wrl," ]\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," colorPerVertex TRUE\n");
+ fprintf(wrl," color Color {\n");
+ fprintf(wrl," color [ # RGB colors of each vertex\n");
+
+ /* Itterate over all the faces in the device space */
+ /* generating the vertx colors. */
+ DC_INIT(coa);
+ vix = 0;
+ while(!DC_DONE(coa)) {
+ int e, m1, m2;
+ double in[MAX_CHAN];
+ double sum;
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < p->n; m1++) {
+ if (coa[m1] != 0)
+ continue;
+
+ for (m2 = m1 + 1; m2 < p->n; m2++) {
+ int x, y;
+
+ if (coa[m2] != 0)
+ continue;
+
+ for (sum = 0.0, e = 0; e < p->n; e++)
+ in[e] = (double)coa[e]; /* Base value */
+
+ /* Scan over 2D device space face */
+ for (x = 0; x < res; x++) { /* step over surface */
+ double xb = x/(res - 1.0);
+ for (y = 0; y < res; y++) {
+ int v0, v1, v2, v3;
+ double yb = y/(res - 1.0);
+ double rgb[3];
+
+ for (v0 = 0, e = 0; e < p->n; e++)
+ v0 |= coa[e] ? (1 << e) : 0; /* Binary index */
+
+ v1 = v0 | (1 << m2); /* Y offset */
+ v2 = v0 | (1 << m2) | (1 << m1); /* X+Y offset */
+ v3 = v0 | (1 << m1); /* Y offset */
+
+ /* Linear interp between the main verticies */
+ for (j = 0; j < 3; j++) {
+ rgb[j] = (1.0 - yb) * (1.0 - xb) * col[v0][j]
+ + yb * (1.0 - xb) * col[v1][j]
+ + (1.0 - yb) * xb * col[v3][j]
+ + yb * xb * col[v2][j];
+ }
+ fprintf(wrl,"%f %f %f,\n",rgb[1], rgb[2], rgb[0]);
+ vix++;
+ }
+ }
+ }
+ }
+ /* Increment index within block */
+ DC_INC(coa);
+ }
+
+ fprintf(wrl," ] \n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," appearance Appearance { \n");
+ fprintf(wrl," material Material {\n");
+ fprintf(wrl," transparency %f\n",trans);
+ fprintf(wrl," ambientIntensity 0.3\n");
+ fprintf(wrl," shininess 0.5\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," } # end Shape\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0)
+ error("Error closing output file '%s'",outname);
+}
+
+/* -------------------------------------------- */
+/* Reverse lookup support */
+/* This is for developing the appropriate reverse lookup */
+/* code for xsep.c */
+
+/*
+ * TTBD:
+ * Not handlink rule or separate black
+ * Not handling linearisation callback for ink limit.
+ * Not allowing for other possible secondary limits/goals/tunings.
+ */
+
+/*
+ * Descriptionr:
+ *
+ * The primary reverse lookup optimisation goals are to remain within
+ * the device gamut, and to match the target PCS.
+ *
+ * The secondary optimisation goals for solving this under constrained
+ * problem can be chosen to a achieve a wide variety of possible aims.
+ *
+ * 1) One that is applicable to screened devices might be to use the extra
+ * inks to minimise the visiblility of screening. For screening resolutions
+ * above 50 lpi (equivalent to 100 dpi stocastic screens) only luminance
+ * contrast will be relavant, so priority to the inks closest to paper white
+ * measured purely by L distance is appropriate. (In practice I've used
+ * a measure that adds a small color distance component.)
+ *
+ * 2) Another possible goal would be to optimise fit to a desired spectral
+ * profile, if spectral information is avaiable as an aim. The goal would
+ * be best fit weighted to the visual sensitivity curve.
+ *
+ * 3) Another possible secondary goal might be to minimise the total
+ * amount of ink used, to minimise cost, drying time, media ink loading.
+ *
+ * 4) A fourth possible secondary goal might be to choose ink combinations
+ * that are the most robust given an error in device values.
+ *
+ * In practice these secondary goals need not be entirely exclusive,
+ * but the overall secondary goal could be a weighted blending between
+ * these goals. Overall the ink limit (TAC) is extremely important,
+ * since this will be the primary thing that stops large amounds of
+ * light ink being used at all times.
+ *
+ * Numerous other tweaks, limits or goals (such as secondary combination
+ * ink limits, exclusions such as Cyan/Oraange, Magenta/Green)
+ * could also be applied in the reverse optimisation routine.
+ *
+ */
+
+
+#ifdef NEVER
+/* These weights are the "theoreticaly correct" weightings, since */
+/* at 50 lpi or higher, the color contrast sensitivity should be close to 0 */
+# define L_WEIGHT 1.0
+# define a_WEIGHT 0.0
+# define b_WEIGHT 0.0
+#else
+/* These weights give us our "expected" ink ordering of */
+/* Yellow, light Cyan/Magenta, Orange/Green, Cyan/Magenta, Black. */
+# define L_WEIGHT 1.0
+# define a_WEIGHT 0.4
+# define b_WEIGHT 0.2
+#endif
+
+/* Start array entry */
+typedef struct {
+ double dev[MAX_CHAN]; /* Device value */
+ double Lab[3]; /* Lab value */
+ double oerr; /* Order error */
+} saent;
+
+/* Context for reverse lookup */
+typedef struct {
+ int pass;
+ int di; /* Number of device channels */
+ double Lab[3]; /* Lab target value */
+ void (*dev2lab) (mpp *d2lcntx, double *out, double *in); /* Device to Lab callback */
+ mpp *d2lcntx; /* dev2lab callback context */
+ double ilimit; /* Total limit */
+ int sord[MAX_CHAN]; /* Sorted order index */
+ double oweight[MAX_CHAN]; /* Order weighting (not used ?) */
+} revlus;
+
+/* Return the largest distance of the point outside the device gamut. */
+/* This will be 0 if inside the gamut, and > 0 if outside. */
+static double
+dist2gamut(revlus *s, double *d) {
+ int e;
+ int di = s->di;
+ double tt, dd = 0.0;
+ double ss = 0.0;
+
+ for (e = 0; e < di; e++) {
+ ss += d[e];
+
+ tt = 0.0 - d[e];
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ tt = d[e] - 1.0;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ }
+ tt = ss - s->ilimit;
+ if (tt > 0.0) {
+ if (tt > dd)
+ dd = tt;
+ }
+ return dd;
+}
+
+/* Snap a point to the device gamut boundary. */
+/* Return nz if it has been snapped. */
+static int snap2gamut(revlus *s, double *d) {
+ int e;
+ int di = s->di;
+ double dd; /* Smallest distance */
+ double ss; /* Sum */
+ int rv = 0;
+
+ /* Snap to ink limit first */
+ for (ss = 0.0, e = 0; e < di; e++)
+ ss += d[e];
+ dd = fabs(ss - s->ilimit);
+
+ if (dd < 0.0) {
+ int j;
+ for (j = 0; j < di; j++)
+ d[j] *= s->ilimit/ss; /* Snap to ink limit */
+ rv = 1;
+ }
+
+ /* Now snap to any other dimension */
+ for (e = 0; e < di; e++) {
+
+ dd = fabs(d[e] - 0.0);
+ if (dd < 0.0) {
+ d[e] = 0.0; /* Snap to orthogonal boundary */
+ rv = 1;
+ }
+ dd = fabs(1.0 - d[e]);
+ if (dd < 0.0) {
+ d[e] = 1.0; /* Snap to orthogonal boundary */
+ rv = 1;
+ }
+ }
+
+ return rv;
+}
+
+/* Reverse optimisation function handed to powell() */
+static double revoptfunc(void *edata, double *v) {
+ revlus *s = (revlus *)edata;
+ double rv;
+
+printf("~1 target %f %f %f\n",s->Lab[0],s->Lab[1],s->Lab[2]);
+
+ if ((rv = (dist2gamut(s, v))) > 0.0) {
+// rv = rv * 1000.0 + 45000.0; /* Discourage being out of gamut */
+ rv = rv * 5e6; /* Discourage being out of gamut */
+
+ }
+printf("~1 out of gamut error = %f\n",rv);
+ {
+ int j;
+ double oerr;
+ double Lab[3];
+ double tot;
+
+ /* Convert device to Lab */
+ s->dev2lab(s->d2lcntx, Lab, v);
+
+ /* Accumulate total delta E squared */
+ for (j = 0; j < 3; j++) {
+ double tt = s->Lab[j] - Lab[j];
+ rv += tt * tt;
+ }
+
+printf("~1 Delta E squared = %f\n",rv);
+
+ /* Skip first 3 colorants */
+ oerr = tot = 0.0;
+printf("oerr = %f\n",oerr);
+ for (j = 3; j < s->di; j++) {
+ int ix = s->sord[j]; /* Sorted order index */
+ double vv = v[ix];
+ double we = (double)j - 2.0; /* Increasing weight */
+
+printf("Comp %d value %f\n",ix,vv);
+ if (vv > 0.0001) {
+ oerr += tot + we * vv;
+printf("Added %f + %f to give oerr %f\n",tot,we * vv,oerr);
+ }
+ tot += we;
+ }
+ oerr /= tot;
+ if (s->pass == 0)
+ oerr *= 2000.0;
+ else
+ oerr *= 1.0;
+printf("Final after div by %f oerr = %f\n",tot,oerr);
+
+printf("~1 Order error %f\n",oerr);
+ rv += oerr;
+ }
+
+printf("~1 Returning total error %f\n",rv);
+ return rv;
+}
+
+
+/* Do a reverse lookup on the mpp */
+static void mpp_rev(
+mpp *mppo,
+double limit, /* Ink limit */
+double *out, /* Device value */
+double *in /* Lab target */
+) {
+ int i, j;
+ inkmask imask; /* Device Ink mask */
+ int inn;
+ revlus rs; /* Reverse lookup structure */
+ double sr[MAX_CHAN]; /* Search radius */
+ double tt;
+ /* !!! This needs to be cached elsewhere !!!! */
+ static saent *start = NULL; /* Start array */
+ static int nisay = 0; /* Number in start array */
+
+ mppo->get_info(mppo, &imask, &inn, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ rs.di = inn; /* Number of device channels */
+
+ rs.Lab[0] = in[0]; /* Target PCS value */
+ rs.Lab[1] = in[1];
+ rs.Lab[2] = in[2];
+
+ rs.dev2lab = mppo->lookup; /* Dev->PCS Lookup function and context */
+ rs.d2lcntx = (void *)mppo;
+
+ rs.ilimit = limit; /* Total ink limit */
+
+ {
+ double Labw[3]; /* Lab value of white */
+ double Lab[MAX_CHAN][3]; /* Lab value of device primaries */
+ double min, max;
+
+ /* Lookup the L value of all the device primaries */
+ for (j = 0; j < inn; j++)
+ out[j] = 0.0;
+
+ mppo->lookup(mppo, Labw, out);
+
+ for (i = 0; i < inn; i++) {
+ double tt;
+ double de;
+
+ out[i] = 1.0;
+ mppo->lookup(mppo, Lab[i], out);
+
+ /* Use DE measure heavily weighted towards L only */
+ tt = L_WEIGHT * (Labw[0] - Lab[i][0]);
+ de = tt * tt;
+ tt = 0.4 * (Labw[1] - Lab[i][1]);
+ de += tt * tt;
+ tt = 0.2 * (Labw[2] - Lab[i][2]);
+ de += tt * tt;
+ rs.oweight[i] = sqrt(de);
+ out[i] = 0.0;
+ }
+
+ /* Normalise weights from 0 .. 1.0 */
+ min = 1e6, max = 0.0;
+ for (j = 0; j < inn; j++) {
+ if (rs.oweight[j] < min)
+ min = rs.oweight[j];
+ if (rs.oweight[j] > max)
+ max = rs.oweight[j];
+ }
+ for (j = 0; j < inn; j++)
+ rs.oweight[j] = (rs.oweight[j] - min)/(max - min);
+
+ {
+ for (j = 0; j < inn; j++)
+ rs.sord[j] = j;
+
+ for (i = 0; i < (inn-1); i++) {
+ for (j = i+1; j < inn; j++) {
+ if (rs.oweight[rs.sord[i]] > rs.oweight[rs.sord[j]]) {
+ int xx;
+ xx = rs.sord[i];
+ rs.sord[i] = rs.sord[j];
+ rs.sord[j] = xx;
+ }
+ }
+ }
+ }
+
+for (j = 0; j < inn; j++)
+printf("~1 oweight[%d] = %f\n",j,rs.oweight[j]);
+for (j = 0; j < inn; j++)
+printf("~1 sorted oweight[%d] = %f\n",j,rs.oweight[rs.sord[j]]);
+ }
+
+ /* Initialise the start point array */
+ if (start == NULL) {
+ int mxstart;
+ int steps = 4;
+
+ DCOUNT(dix, MAX_CHAN, inn, 0, 0, steps);
+
+printf("~1 initing start point array\n");
+ for (mxstart = 1, j = 0; j < inn; j++) /* Compute maximum entries */
+ mxstart *= steps;
+
+printf("~1 mxstart = %d\n",mxstart);
+ if ((start = malloc(sizeof(saent) * mxstart)) == NULL)
+ error("mpp_rev malloc of start array failed\n");
+
+ nisay = 0;
+ DC_INIT(dix);
+
+ while(!DC_DONE(dix)) {
+ double sum = 0.0;
+
+ /* Figure device values */
+ for (j = 0; j < inn; j++) {
+ sum += start[nisay].dev[j] = dix[j]/(steps-1.0);
+ }
+
+ if (sum <= limit) { /* Within ink limit */
+ double oerr;
+ double tot;
+
+ /* Compute Lab */
+ mppo->lookup(mppo, start[nisay].Lab, start[nisay].dev);
+
+ /* Compute order error */
+ /* Skip first 3 colorants */
+ oerr = tot = 0.0;
+ for (j = 3; j < inn; j++) {
+ int ix = rs.sord[j]; /* Sorted order index */
+ double vv = start[nisay].dev[ix];
+ double we = (double)j - 2.0; /* Increasing weight */
+
+ if (vv > 0.0001) {
+ oerr += tot + we * vv;
+ }
+ tot += we;
+ }
+ oerr /= tot;
+ start[nisay].oerr = oerr;
+
+ nisay++;
+ }
+
+ DC_INC(dix);
+ }
+printf("~1 start point array done, %d out of %d valid\n",nisay,mxstart);
+ }
+
+ /* Search the start array for closest matching point */
+ {
+ double bde = 1e38;
+ int bix = 0;
+
+ for (i = 0; i < nisay; i++) {
+ double de;
+
+ /* Compute delta E */
+ for (de = 0.0, j = 0; j < 3; j++) {
+ double tt = rs.Lab[j] - start[i].Lab[j];
+ de += tt * tt;
+ }
+ de += 0.0 * start[i].oerr;
+ if (de < bde) {
+ bde = de;
+ bix = i;
+ }
+ }
+
+printf("Start point at index %d, bde = %f, dev = ",bix,bde);
+for (j = 0; j < inn; j++) {
+printf("%f",start[bix].dev[j]);
+if (j < (inn-1))
+printf(" ");
+}
+printf("\n");
+
+ for (j = 0; j < inn; j++) {
+ out[j] = start[bix].dev[j];
+ sr[j] = 0.1;
+ }
+ }
+
+#ifdef NEVER
+ out[0] = 0.0;
+ out[1] = 0.0;
+ out[2] = 0.45;
+ out[3] = 0.0;
+ out[4] = 0.0;
+ out[5] = 0.0;
+ out[6] = 0.6;
+ out[7] = 1.0;
+#endif
+
+#ifdef NEVER
+ out[0] = 1.0;
+ out[1] = 0.0;
+ out[2] = 0.0;
+ out[3] = 0.0;
+ out[4] = 0.0;
+ out[5] = 0.0;
+ out[6] = 0.0;
+ out[7] = 0.0;
+#endif
+
+#ifdef NEVER
+ rs.pass = 0;
+ if (powell(&tt, inn, out, sr, 0.001, 5000, revoptfunc, (void *)&rs) != 0) {
+ error("Powell failed inside mpp_rev()");
+ }
+printf("\n\n\n\n\n\n#############################################\n");
+printf("~1 after first pass got ");
+for (j = 0; j < inn; j++) {
+printf("%f",out[j]);
+if (j < (inn-1))
+printf(" ");
+}
+printf("\n");
+printf("#############################################\n\n\n\n\n\n\n\n");
+#endif
+
+#ifndef NEVER
+ out[0] = 0.0;
+ out[1] = 0.0;
+ out[2] = 0.0;
+ out[3] = 0.0;
+ out[4] = 0.0;
+ out[5] = 1.0;
+ out[6] = 0.0;
+ out[7] = 0.0;
+#endif
+#ifndef NEVER
+ rs.pass = 1;
+ if (powell(&tt, inn, out, sr, 0.00001, 5000, revoptfunc, (void *)&rs, NULL, NULL) != 0) {
+ error("Powell failed inside mpp_rev()");
+ }
+#endif
+
+ snap2gamut(&rs, out);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/revfix.c b/xicc/revfix.c
new file mode 100644
index 0000000..59fdd0e
--- /dev/null
+++ b/xicc/revfix.c
@@ -0,0 +1,796 @@
+
+/*
+ * ICC reprocess to give true BtoA1 by inverting
+ * the AtoB1 table, and also correct the neutral
+ * axis of the BtoA0 and BtoA2 tables.
+ *
+ *
+ * Author: Graeme W. Gill
+ * Date: 9/7/00
+ * Version: 1.00
+ *
+ * Copyright 2000 Graeme W. Gill
+ * Please refer to License.txt file for details.
+ */
+
+/* TTBD:
+ *
+ * Add support for proper gamut mapping, just like profile,
+ * or deprecate revfix by modifying profile to work from
+ * an existing profile ?
+ *
+ * Remove the auxiliary fixup stuff when we have implemented
+ * optimised separations.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "xicc.h"
+
+#define USE_CAM_CLIP_OPT /* Clip in CAM Jab space rather than Lab */
+#undef DEBUG /* Print each value changed */
+
+void usage(void) {
+ fprintf(stderr,"Invert AtoB1 to make BtoA1 for CMYK profiles, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: revfix [-options] iccin iccout\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -0 Process perceptual\n");
+ fprintf(stderr," -1 Process absolute/relative colorimetric\n");
+ fprintf(stderr," -2 Process saturation\n");
+ fprintf(stderr," -r res Override BtoA1 Clut res\n");
+ fprintf(stderr," -k [ezhxr] e = same K as existing BtoA table (def)\n");
+ fprintf(stderr," z = zero, h = 0.5 K, x = max K, r = ramp K\n");
+ fprintf(stderr," -k p stle stpo enle enpo shape\n");
+ fprintf(stderr," p = curve parameters\n");
+ fprintf(stderr," stle: K level at White 0.0 - 1.0\n");
+ fprintf(stderr," stpo: start point of transition Wh 0.0 - Bk 1.0\n");
+ fprintf(stderr," enpo: End point of transition Wh 0.0 - Bk 1.0\n");
+ fprintf(stderr," enle: K level at Black 0.0 - 1.0\n");
+ fprintf(stderr," shape: 1.0 = straight, 0.0-1.0 concave, 1.0-2.0 convex\n");
+ fprintf(stderr," -K parameters Same as -k, but target is K locus rather than K value itself\n");
+ fprintf(stderr," -l tlimit set total ink limit, 0 - 400%% (estimate by default)\n");
+ fprintf(stderr," -L klimit set black ink limit, 0 - 100%% (estimate by default)\n");
+ fprintf(stderr," -p absprof Include abstract profile in output tables\n");
+// fprintf(stderr," -s Use internal optimized separation for CMYK\n");
+ exit(1);
+}
+
+/* ------------------------------------------- */
+/* structure to support icc Lut initialisation calbacks */
+
+/* ~~~Note that we're not coping with a matrix or XYZ PCS properly here. */
+
+struct _callback {
+ int verb; /* Verbosity */
+ int total, count, last; /* Progress count information */
+ icColorSpaceSignature pcsspace;
+ int inking; /* k inking algorithm */
+ icxLuLut *BtoA; /* BtoA of table being processed */
+ icxLuLut *AtoB; /* AtoB of table being processed */
+ icxLuLut *AtoB1; /* AtoB of colorimetric table */
+
+ icRenderingIntent abs_intent; /* Desired abstract profile rendering intent */
+ icxLuBase *abs_luo; /* abstract profile tranform in PCS, NULL if none */
+
+}; typedef struct _callback callback;
+
+
+/* Utility to handle abstract profile application to PCS */
+/* PCS in creating output table is always XYZ or Lab relative colorimetric, */
+/* and abstract profile is absolute or relative, and will be */
+/* XYZ if absolute, and PCS if relative. */
+static void do_abstract(callback *p, double out[3], double in[3]) {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+
+//printf("~1 do_abstract got %f %f %f\n",in[0],in[1],in[2]);
+
+ if (p->abs_intent == icAbsoluteColorimetric) {
+ if (p->pcsspace == icSigLabData) {
+ icmLab2XYZ(&icmD50, out, out);
+//printf("~1 after Lab 2 XYZ got %f %f %f\n",out[0],out[1],out[2]);
+ }
+ p->AtoB1->plu->XYZ_Rel2Abs(p->AtoB1->plu, out, out);
+//printf("~1 after rel to abs got %f %f %f\n",out[0],out[1],out[2]);
+ }
+
+ p->abs_luo->lookup(p->abs_luo, out, out);
+//printf("~1 after abs_luo got %f %f %f\n",out[0],out[1],out[2]);
+
+ if (p->abs_intent == icAbsoluteColorimetric) {
+ p->AtoB1->plu->XYZ_Abs2Rel(p->AtoB1->plu, out, out);
+//printf("~1 after abs2rel got %f %f %f\n",out[0],out[1],out[2]);
+ if (p->pcsspace == icSigLabData) {
+ icmXYZ2Lab(&icmD50, out, out);
+//printf("~1 after XYZ to Lab got %f %f %f\n",out[0],out[1],out[2]);
+ }
+ }
+//printf("~1 returning %f %f %f\n\n",out[0],out[1],out[2]);
+}
+
+/* - - - - - - - - - */
+/* New input table */
+void Lab_Labp(void *cntx, double out[3], double in[3]) {
+ callback *p = (callback *)cntx;
+
+#ifdef DEBUG
+ printf("Got Lab %f %f %f\n",in[0],in[1],in[2]);
+#endif
+ if (p->AtoB != p->AtoB1) {
+ /* Non-colorimetric, use existing input table */
+ if (p->BtoA->input(p->BtoA, out, in) > 1)
+ error ("%d, %s",p->BtoA->pp->errc,p->BtoA->pp->err);
+ } else {
+ /* Colorimetric, use inverse AtoB output */
+ if (p->AtoB1->inv_output(p->AtoB1, out, in) > 1)
+ error ("%d, %s",p->AtoB1->pp->errc,p->AtoB1->pp->err);
+ }
+#ifdef DEBUG
+ printf("New Lab' %f %f %f\n",out[0],out[1],out[2]);
+#endif
+}
+
+/* - - - - */
+/* clut */
+
+/* Normal CLUT routine */
+void Labp_CMYKp(void *cntx, double out[4], double in[3]) {
+ double temp[4], targetk = 0.0;
+ int rv;
+ callback *p = (callback *)cntx;
+
+#ifdef DEBUG
+ printf("Got Lab' %f %f %f\n",in[0],in[1],in[2]);
+#endif
+
+ if (p->inking == 0) { /* If we are copying existing K value */
+
+ /* Figure out what K value was previously here */
+ if (p->AtoB != p->AtoB1) {
+ /* Simple because BtoA input & output tables don't change */
+ /* Figure out what DEV' K value the BtoA table currently has for this PCS' */
+ if (p->BtoA->clut(p->BtoA, temp, in) > 1)
+ error ("%d, %s",p->BtoA->pp->errc,p->BtoA->pp->err);
+
+ /* Convert DEV' to DEV */
+ if (p->BtoA->output(p->BtoA, temp, temp) > 1)
+ error ("%d, %s",p->BtoA->pp->errc,p->AtoB->pp->err);
+ } else {
+ /* More complicated because old BtoA in/out tables are different */
+ /* from the new ones. */
+ /* We know that new BtoA in/out tables are inverse of AtoB in/out, */
+ /* so we don't have to use BtoA1->inv_input, & BtoA1->inv_output */
+ /* Convert PCS' to PCS */
+ if (p->AtoB->output(p->AtoB, temp, in) > 1)
+ error ("%d, %s",p->AtoB->pp->errc,p->AtoB->pp->err);
+
+ /* Figure out what DEV K value the BtoA table currently has for this PCS */
+ if (((icxLuBase *)p->BtoA)->lookup((icxLuBase *)p->BtoA, temp, temp) > 1)
+ error ("%d, %s",p->BtoA->pp->errc,p->BtoA->pp->err);
+ }
+ targetk = temp[3];
+#ifdef DEBUG
+ printf("Got existing CMYK %f %f %f %f\n",temp[0],temp[1],temp[2],temp[3]);
+#endif
+ }
+
+ /* Copy the Lab in */
+ temp[0] = in[0];
+ temp[1] = in[1];
+ temp[2] = in[2];
+
+ if (p->AtoB != p->AtoB1) {
+ double tt[4];
+
+ /* Can't assume B2A in/out tables are inverses of AtoB */
+ /* Convert PCS' -> PCS for this table */
+ if (p->BtoA->inv_input(p->BtoA, temp, temp) > 1)
+ error ("%d, %s",p->BtoA->pp->errc,p->BtoA->pp->err);
+ /* Convert PCS -> PCS' for colorimetric */
+ if (p->AtoB1->inv_output(p->AtoB1, temp, temp) > 1)
+ error ("%d, %s",p->AtoB->pp->errc,p->AtoB->pp->err);
+ }
+
+ /* Abstract profile applied before inversion */
+ if (p->abs_luo != NULL) {
+ do_abstract(p, temp, temp);
+ }
+
+ /* Invert AtoB1 clut, using set inking policy */
+ out[3] = targetk;
+
+ /* PCS' -> DEV' colorimetric (aux target is DEV space) */
+ if ((rv = p->AtoB1->inv_clut(p->AtoB1, out, temp)) > 1)
+ error ("%d, %s",p->AtoB1->pp->errc,p->AtoB1->pp->err);
+
+ /* ~~~ Note that the ink limit will be wrong for non-colorimetric, */
+ /* since AtoB1->inv_clut will be assuming A->toB1->inv_input as the output table, */
+ /* while we will actually be using BtoA->output ~~~~ */
+ /* Need to override ink limit computation function in icx for non-colorimetric. */
+
+//#ifdef DEBUG
+// if (rv != 0) {
+// printf("Inversion clipped\n");
+// }
+//#endif
+ if (p->AtoB != p->AtoB1) {
+ /* Can't assume B2A in/out tables are inverses of AtoB */
+ /* Converts DEV' -> DEV colorimetric */
+ if (p->AtoB1->inv_input(p->AtoB1, out, out) > 1)
+ error ("%d, %s",p->AtoB->pp->errc,p->AtoB->pp->err);
+ /* Convert DEV -> DEV' for this table */
+ if (p->BtoA->inv_output(p->BtoA, out, out) > 1)
+ error ("%d, %s",p->BtoA->pp->errc,p->BtoA->pp->err);
+ }
+#ifdef DEBUG
+ printf("New CMYK' %f %f %f %f\n",out[0],out[1],out[2],out[3]);
+ printf("\n");
+#endif
+
+ if (p->verb) { /* Output percent intervals */
+ int pc;
+ p->count++;
+ pc = (int)(p->count * 100.0/p->total + 0.5);
+ if (pc != p->last) {
+ printf("%c%2d%%",cr_char,pc), fflush(stdout);
+ p->last = pc;
+ }
+ }
+}
+
+/* - - - - - - - - - */
+/* New output table */
+void CMYKp_CMYK(void *cntx, double out[4], double in[4]) {
+ callback *p = (callback *)cntx;
+
+#ifdef DEBUG
+ printf("Got CMYK' %f %f %f %f\n",in[0],in[1],in[2],in[3]);
+#endif
+ if (p->AtoB != p->AtoB1) {
+ /* Non-colorimetric, use existing output table */
+ if (p->BtoA->output(p->BtoA, out, in) > 1)
+ error ("%d, %s",p->BtoA->pp->errc,p->BtoA->pp->err);
+ } else {
+ /* Colorimetric, use inverse AtoB input */
+ if (p->AtoB1->inv_input(p->AtoB1, out, in) > 1)
+ error ("%d, %s",p->AtoB1->pp->errc,p->AtoB1->pp->err);
+ }
+#ifdef DEBUG
+ printf("New CMYK %f %f %f %f\n",out[0],out[1],out[2],out[3]);
+#endif
+}
+
+
+/* ------------------------------------------- */
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char in_name[MAXNAMEL+1];
+ char out_name[MAXNAMEL+1];
+ char abs_name[MAXNAMEL+1] = "\000"; /* Abstract profile name */
+ icmFile *rd_fp, *wr_fp;
+ icc *icco;
+ int verb = 0;
+ int clutres = 0;
+ int do0 = 0;
+ int do1 = 0;
+ int do2 = 0;
+ int inking = 0; /* Default copy from existing */
+ int locus = 0; /* Default K value target */
+ double Kstle = 0.0, Kstpo = 0.0, Kenle = 0.0, Kenpo = 0.0, Kshap = 0.0;
+ double tlimit = -1.0; /* Total ink limit */
+ double klimit = -1.0; /* Black ink limit */
+ int intsep = 0; /* Not implimented in xicc yet ??? */
+ int rv = 0;
+
+ error_program = argv[0];
+ check_if_not_interactive();
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ else if (argv[fa][1] == '0') {
+ do0 = 1;
+ }
+ else if (argv[fa][1] == '1') {
+ do1 = 1;
+ }
+ else if (argv[fa][1] == '2') {
+ do2 = 1;
+ }
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ clutres = atoi(na);
+ }
+
+ /* Inking rule */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (argv[fa][1] == 'k')
+ locus = 0; /* K value target */
+ else
+ locus = 1; /* K locus target */
+ switch (na[0]) {
+ case 'e':
+ case 'E':
+ inking = 0; /* Use existing table as guide */
+ break;
+ case 'z':
+ case 'Z':
+ inking = 1; /* Use minimum k */
+ break;
+ case 'h':
+ case 'H':
+ inking = 2; /* Use 0.5 k */
+ break;
+ case 'x':
+ case 'X':
+ inking = 3; /* Use maximum k */
+ break;
+ case 'r':
+ case 'R':
+ inking = 4; /* Use ramp */
+ break;
+ case 'p':
+ case 'P':
+ inking = 5; /* Use curve parameter */
+ ++fa;
+ if (fa >= argc) usage();
+ Kstle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage();
+ Kstpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ Kenpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage();
+ Kenle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ Kshap = atof(argv[fa]);
+ break;
+ default:
+ usage();
+ }
+ }
+ else if (argv[fa][1] == 'l') {
+ fa = nfa;
+ if (na == NULL) usage();
+ tlimit = atoi(na)/100.0;
+ }
+ else if (argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage();
+ klimit = atoi(na)/100.0;
+ }
+
+ /* Use internal separation */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ intsep = 1;
+ }
+
+ /* Abstract profile */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ if (na == NULL) usage();
+ fa = nfa;
+ strncpy(abs_name,na,MAXNAMEL); abs_name[MAXNAMEL] = '\000';
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
+
+ /* Open up the profile for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Can't open file '%s'",in_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = icco->read(icco,rd_fp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ /* Read every tag */
+ if (icco->read_all_tags(icco) != 0) {
+ error("Unable to read all tags: %d, %s",icco->errc,icco->err);
+ }
+
+ rd_fp->del(rd_fp);
+
+ /* ======================= */
+ /* Check that it is a suitable icc */
+ {
+ icmHeader *rh = icco->header;
+
+ if (rh->deviceClass != icSigOutputClass)
+ error("Profile isn't an output device profile");
+
+ if (rh->colorSpace != icSigCmykData)
+ error("Profile isn't for a CMYK device");
+
+ if (rh->pcs != icSigLabData)
+ error("Profile is not using a PCS of Lab - can't cope with this yet");
+ }
+
+ if (verb && inking == 5) {
+ double tL;
+ printf("K parameters are are %f %f %f %f %f\n",Kstle, Kstpo, Kenpo, Kenle, Kshap);
+ for (tL = 100.0; tL >= 0.0; tL -= 10.0) {
+ double rv, L;
+
+ L = 0.01 * tL;
+
+ /* Code from xlut.c: */
+ /* Invert sense of L, so that 0.0 = white, 1.0 = black */
+ L = 1.0 - L;
+
+ if (L <= Kstpo && L <= Kenpo) {
+ /* We are at white level */
+ rv = Kstle;
+ } else if (L >= Kstpo && L >= Kenpo) {
+ /* We are at black level */
+ rv = Kenle;
+ } else {
+ double g;
+ /* We must be on the curve from start to end levels */
+
+ if (Kstpo > Kenpo) {
+ rv = (L - Kenpo)/(Kstpo - Kenpo);
+ } else {
+ rv = (L - Kstpo)/(Kenpo - Kstpo);
+ }
+
+ g = Kshap/2.0;
+
+ /* A value of 0.5 will be tranlated to g */
+ rv = rv/((1.0/g - 2.0) * (1.0 - rv) + 1.0);
+
+ /* Transition between start end end levels */
+ rv = rv * (Kenle - Kstle) + Kstle;
+ }
+
+ /* To be safe */
+ if (rv < 0.0)
+ rv = 0.0;
+ else if (rv > 1.0)
+ rv = 1.0;
+
+ printf("L = %f, K %s = %f\n",tL, locus ? "locus" : "value", rv);
+ }
+ }
+
+ /* ======================= */
+ {
+ int ii; /* Current intent */
+ icmLut *done[3]; /* record pointers to done Luts here */
+ icRenderingIntent intent = 0;
+ icTagSignature sig = 0;
+ xicc *xicco;
+ callback cb; /* Callback support stucture */
+ icxInk ink; /* Ink parameters */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ icmFile *abs_fp = NULL; /* Abstract profile transform: */
+ icc *abs_icc = NULL;
+ xicc *abs_xicc = NULL;
+
+ /* Wrap with an expanded icc */
+ if ((xicco = new_xicc(icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ /* Setup CMYK -> Lab conversion (Fwd) object */
+
+ /* Set the default ink limits if not set on command line */
+ icxDefaultLimits(xicco, &ink.tlimit, tlimit, &ink.klimit, klimit);
+
+ if (verb) {
+ if (!do0 && !do1 && !do2)
+ printf("WARNING: nothing to do!\n");
+ if (ink.tlimit >= 0.0)
+ printf("Total ink limit assumed is %3.0f%%\n",100.0 * ink.tlimit);
+ if (ink.klimit >= 0.0)
+ printf("Black ink limit assumed is %3.0f%%\n",100.0 * ink.klimit);
+ }
+
+ ink.KonlyLmin = 0; /* Use normal black Lmin for locus */
+
+ ink.c.Ksmth = ICXINKDEFSMTH; /* Default curve smoothing */
+ ink.c.Kskew = ICXINKDEFSKEW; /* default curve skew */
+ ink.x.Ksmth = ICXINKDEFSMTH;
+ ink.x.Kskew = ICXINKDEFSKEW;
+
+ if (inking == 0) {
+ ink.k_rule = icxKvalue; /* K is auxiliary target */
+
+ } else if (inking == 1) { /* Use minimum */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = 0.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 0.0;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 2) { /* Use 0.5 */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = 0.5;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 0.5;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 3) { /* Use maximum */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = 1.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 1.0;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 4) { /* Use ramp */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = 0.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 1.0;
+ ink.c.Kshap = 1.0;
+ } else { /* Use specified curve */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k;
+ ink.c.Kstle = Kstle;
+ ink.c.Kstpo = Kstpo;
+ ink.c.Kenpo = Kenpo;
+ ink.c.Kenle = Kenle;
+ ink.c.Kshap = Kshap;
+ }
+
+ cb.verb = verb;
+ cb.count = 0;
+ cb.last = -1;
+ cb.inking = inking;
+
+ /* Setup our access to the device characteristic */
+ if ((cb.AtoB1 = (icxLuLut *)xicco->get_luobj(xicco,
+ ICX_CLIP_NEAREST
+#ifdef USE_CAM_CLIP_OPT
+ | ICX_CAM_CLIP
+#endif
+ | (intsep ? ICX_INT_SEPARATE : 0),
+ icmFwd, icRelativeColorimetric,
+ icmSigDefaultData, icmLuOrdNorm, NULL, &ink)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ cb.AtoB1->spaces((icxLuBase *)cb.AtoB1, NULL, NULL, NULL, NULL, &alg,
+ NULL, NULL, &cb.pcsspace);
+ if (alg != icmLutType)
+ error("Forward conversion is not a Lut");
+
+ /* Open up the abstract profile if supplied, and setup luo */
+ if (abs_name[0] != '\000') {
+ if ((abs_fp = new_icmFileStd_name(abs_name,"r")) == NULL)
+ error ("Can't open abstract profile file '%s'",abs_name);
+
+ if ((abs_icc = new_icc()) == NULL)
+ error ("Creation of Abstract profile ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = abs_icc->read(abs_icc,abs_fp,0)) != 0)
+ error ("%d, %s",rv,abs_icc->err);
+
+ if (abs_icc->header->deviceClass != icSigAbstractClass)
+ error("Abstract profile isn't an abstract profile");
+
+ /* Take intended abstract intent from profile itself */
+ if ((cb.abs_intent = abs_icc->header->renderingIntent) != icAbsoluteColorimetric)
+ cb.abs_intent = icRelativeColorimetric;
+
+ /* Wrap with an expanded icc */
+ if ((abs_xicc = new_xicc(abs_icc)) == NULL)
+ error ("Creation of abstract profile xicc failed");
+
+ /* The abstract profile intent is assumed to determine how it gets applied. */
+ /* Make abstract PCS XYZ if icAbsoluteColorimetric is needed. */
+ if ((cb.abs_luo = abs_xicc->get_luobj(abs_xicc, ICX_CLIP_NEAREST, icmFwd, cb.abs_intent,
+ (cb.pcsspace == icSigLabData && cb.abs_intent == icRelativeColorimetric)
+ ? icSigLabData : icSigXYZData,
+ icmLuOrdNorm, NULL, NULL)) == NULL)
+ error ("%d, %s",abs_icc->errc, abs_icc->err);
+ } else {
+ cb.abs_luo = NULL;
+ }
+
+ /* for all intents, and not already processed */
+ for (ii = 0; ii <= 2; ii++) {
+ int i;
+ icmLut *wo;
+
+ switch(ii) {
+ case 0:
+ intent = icRelativeColorimetric;
+ sig = icSigBToA1Tag;
+ if (do1 == 0)
+ continue;
+ break;
+ case 1:
+ intent = icPerceptual;
+ sig = icSigBToA0Tag;
+ if (do0 == 0)
+ continue;
+ break;
+ case 2:
+ intent = icSaturation;
+ sig = icSigBToA2Tag;
+ if (do2 == 0)
+ continue;
+ break;
+ }
+
+ if (intent == icRelativeColorimetric) {
+ cb.AtoB = cb.AtoB1;
+ } else {
+ /* Setup CMYK -> Lab conversion (Fwd) object */
+ if ((cb.AtoB = (icxLuLut *)xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmFwd, intent,
+ icmSigDefaultData, icmLuOrdNorm, NULL, NULL)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ cb.AtoB->spaces((icxLuBase *)cb.AtoB, NULL, NULL, NULL, NULL, &alg, NULL, NULL, NULL);
+ if (alg != icmLutType)
+ error("Forwards conversion is not a Lut");
+ }
+
+ /* Setup Lab -> CMYK conversion (Bwd) object */
+ if ((cb.BtoA = (icxLuLut *)xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, intent,
+ icmSigDefaultData, icmLuOrdNorm, NULL, NULL)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ cb.BtoA->spaces((icxLuBase *)cb.BtoA, NULL, NULL, NULL, NULL, &alg, NULL, NULL, NULL);
+ if (alg != icmLutType)
+ error("Backwards conversion is not a Lut");
+
+ /* Try and read the tag from the file */
+ wo = (icmLut *)icco->read_tag(icco, sig);
+ if (wo == NULL)
+ error("Can't find %s", icm2str(icmRenderingIntent, intent));
+
+ /* Need to check that the cast is appropriate. */
+ if (wo->ttype != icSigLut16Type && wo->ttype != icSigLut8Type)
+ error("Lut table isn't Lut8 or Lut16 Type");
+
+ /* Set reverse input table resolution to same as fwd output */
+ wo->inputEnt = cb.AtoB->lut->outputEnt;
+
+ /* Let user override for BtoA1 */
+ if (sig == icSigBToA1Tag && clutres > 0) {
+ if (verb)
+ printf("Overriding existing clut resolution %d with %d\n",wo->clutPoints,clutres);
+ wo->clutPoints = clutres;
+ }
+ /* If Lut8, make sure the input and output tables have 256 enries. */
+ if (wo->ttype == icSigLut8Type) {
+ wo->inputEnt = 256;
+ wo->outputEnt = 256;
+ }
+ wo->allocate((icmBase *)wo);/* Allocate space */
+
+ /* Make sure that we don't process a table twice */
+ done[ii] = wo;
+ for (i = ii-1; i >= 0; i--) {
+ if (done[i] == wo) {
+ break;
+ }
+ }
+ if (i >= 0) {
+ if (verb)
+ printf("Skipping %s table - already done\n", icm2str(icmRenderingIntent, intent));
+
+ } else {
+
+ if (verb)
+ printf("About to start processing %s\n", icm2str(icmRenderingIntent, intent));
+
+ if (cb.verb) {
+ unsigned int ui;
+ int extra;
+ for (cb.total = 1, ui = 0; ui < wo->inputChan; ui++, cb.total *= wo->clutPoints)
+ ;
+ /* Add in cell center points */
+ for (extra = 1, ui = 0; ui < wo->inputChan; ui++, extra *= (wo->clutPoints-1))
+ ;
+ cb.total += extra;
+ printf(" 0%%"), fflush(stdout);
+ }
+ /* Use helper function to do the hard work. */
+ if (wo->set_tables(wo,
+ ICM_CLUT_SET_APXLS,
+ &cb, /* Context */
+ icSigLabData, /* Input color space */
+ icSigCmykData, /* Output color space */
+ Lab_Labp, /* Linear input transform Lab->Lab' */
+ NULL, NULL, /* Use default Lab' range */
+ Labp_CMYKp, /* Lab' -> CMYK' transfer function */
+ NULL, NULL, /* Use default CMYK' range */
+ CMYKp_CMYK) != 0) /* Output transfer function, CMYK'->CMYK (NULL = deflt) */
+ error("Setting 16 bit Lab->CMYK Lut failed: %d, %s",icco->errc,icco->err);
+
+ if (verb)
+ printf("\nDone processing %s\n", icm2str(icmRenderingIntent, intent));
+
+ }
+
+ /* Done with this intents lookup object */
+ cb.BtoA->del((icxLuBase *)cb.BtoA);
+ if (cb.AtoB != cb.AtoB1)
+ cb.AtoB->del((icxLuBase *)cb.AtoB);
+ }
+ /* Done with colorimetric intents AtoB1 lookup objects, and xicc */
+ cb.AtoB1->del((icxLuBase *)cb.AtoB1);
+ xicco->del(xicco);
+
+ if (cb.abs_luo != NULL) { /* Free up abstract transform */
+ cb.abs_luo->del(cb.abs_luo);
+ abs_xicc->del(abs_xicc);
+ abs_icc->del(abs_icc);
+ abs_fp->del(abs_fp);
+ }
+
+ }
+ /* ======================================= */
+
+ /* Open up the other profile for writing */
+ if ((wr_fp = new_icmFileStd_name(out_name,"w")) == NULL)
+ error ("Can't open file '%s'",out_name);
+
+ if ((rv = icco->write(icco,wr_fp,0)) != 0)
+ error ("Write file: %d, %s",rv,icco->err);
+
+ wr_fp->del(wr_fp);
+ icco->del(icco);
+
+ return 0;
+}
+
diff --git a/xicc/specplot.c b/xicc/specplot.c
new file mode 100644
index 0000000..b2baf05
--- /dev/null
+++ b/xicc/specplot.c
@@ -0,0 +1,370 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 2006/5/9
+ * Version: 1.00
+ *
+ * Copyright 2006 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.
+ *
+ */
+
+/*
+ * This is some test code to test the Daylight and Plankian spectra,
+ * Correlated and Visual Color Temperatures, and CRI.
+ * and plot a spectrum, CMF or CCSS.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "xspect.h"
+#include "numlib.h"
+#include "plot.h"
+
+#define PLANKIAN
+#define XRES 500
+
+#define MAXGRAPHS 10
+
+#ifdef PLANKIAN
+#define BBTYPE icxIT_Ptemp
+#else
+#define BBTYPE icxIT_Dtemp
+#endif
+
+/* Display a spectrum etc. */
+/* We are guaranteed that the x range/increments are identical, */
+/* and that there is only one spectrum if douv */
+static int do_spec(
+ char name[MAXGRAPHS][200],
+ xspect *sp,
+ int nsp, /* Number of sp */
+ int dozero, /* Include zero in the range */
+ int douv, /* Do variation of added UV test */
+ double uvmin,
+ double uvmax
+) {
+ int n, i, j, k, m;
+ double wl_short, wl_long; /* Common range */
+ double xyz[3]; /* Color temperature */
+ double Yxy[3];
+ double Lab[3]; /* D50 Lab value */
+ double xx[XRES];
+ double yy[10][XRES];
+ double *yp[10];
+ double cct, vct;
+ double cct_xyz[3], vct_xyz[3];
+ double cct_lab[3], vct_lab[3];
+ icmXYZNumber wp;
+ double de;
+ double uv = uvmin;
+ double step = 0.1;
+ xspect tsp; /* Spectrum with possible UV added */
+ char *color[] = {
+ "Black", "Red", "Green", "Blue", "Yellow", "Purple", "Brown", "Orange", "Grey", "Magenta"
+ };
+
+ printf("\n");
+
+ for (j = 0; j < 10; j++)
+ yp[j] = NULL;
+
+ if (nsp > 10)
+ nsp = 10;
+
+ m = 0; /* offset in output array */
+ n = 1;
+
+ wl_short = 1e6;
+ wl_long = -1e6;
+ for (k = 0; k < nsp; k++) {
+ if (sp[k].spec_wl_long > wl_long)
+ wl_long = sp[k].spec_wl_long;
+ if (sp[k].spec_wl_short < wl_short)
+ wl_short = sp[k].spec_wl_short;
+ }
+
+ if (douv) {
+ n = 1 + (int)(0.5 + (uvmax-uvmin)/0.1);
+ if (n > 9)
+ n = 9; /* Don't use white */
+ if (n > 1)
+ step = (uvmax-uvmin)/(n-1.0);
+ }
+
+ for (k = 0; k < nsp; k++) {
+ tsp = sp[k];
+ for (uv = uvmax, j = 0; j < n; j++, uv -= step) {
+
+ if (douv) {
+ printf("UV level = %f\n",uv);
+ xsp_setUV(&tsp, &sp[k], uv);
+ }
+
+ /* Compute XYZ of illuminant */
+ if (icx_ill_sp2XYZ(xyz, icxOT_CIE_1931_2, NULL, icxIT_custom, 0, &tsp) != 0)
+ error ("icx_sp_temp2XYZ returned error");
+
+ icmXYZ2Yxy(Yxy, xyz);
+ icmXYZ2Lab(&icmD50, Lab, xyz);
+
+ printf("Type = %s [%s]\n",name[k], color[k]);
+ printf("XYZ = %f %f %f, x,y = %f %f\n", xyz[0], xyz[1], xyz[2], Yxy[1], Yxy[2]);
+ printf("D50 L*a*b* = %f %f %f\n", Lab[0], Lab[1], Lab[2]);
+
+#ifndef NEVER
+ /* Test density */
+ {
+ double dens[4];
+
+ xsp_Tdensity(dens, &tsp);
+
+ printf("CMYV density = %f %f %f %f\n", dens[0], dens[1], dens[2], dens[3]);
+ }
+#endif
+
+ /* Compute CCT */
+ if ((cct = icx_XYZ2ill_ct(cct_xyz, BBTYPE, icxOT_CIE_1931_2, NULL, xyz, NULL, 0)) < 0)
+ error ("Got bad cct\n");
+
+ /* Compute VCT */
+ if ((vct = icx_XYZ2ill_ct(vct_xyz, BBTYPE, icxOT_CIE_1931_2, NULL, xyz, NULL, 1)) < 0)
+ error ("Got bad vct\n");
+
+#ifdef PLANKIAN
+ printf("CCT = %f, VCT = %f\n",cct, vct);
+#else
+ printf("CDT = %f, VDT = %f\n",cct, vct);
+#endif
+
+ {
+ int invalid = 0;
+ double cri;
+ cri = icx_CIE1995_CRI(&invalid, &tsp);
+ printf("CRI = %.1f%s\n",cri,invalid ? " (Invalid)" : "");
+ }
+
+ /* Use modern color difference - gives a better visual match */
+ icmAry2XYZ(wp, vct_xyz);
+ icmXYZ2Lab(&wp, cct_lab, cct_xyz);
+ icmXYZ2Lab(&wp, vct_lab, vct_xyz);
+ de = icmCIE2K(cct_lab, vct_lab);
+ printf("CIEDE2000 Delta E = %f\n",de);
+
+ /* Plot spectrum out */
+ for (i = 0; i < XRES; i++) {
+ double ww;
+
+ ww = (wl_long - wl_short)
+ * ((double)i/(XRES-1.0)) + wl_short;
+
+ xx[i] = ww;
+ yy[(m + k + j) % 10][i] = value_xspect(&tsp, ww);
+ }
+ yp[(m + k + j) % 10] = &yy[(m + k + j) % 10][0];
+ }
+ }
+ do_plot10(xx, yp[0], yp[1], yp[2], yp[3], yp[4], yp[5], yp[6], yp[7], yp[8], yp[9], XRES, dozero);
+
+
+ return 0;
+}
+
+
+void usage(void) {
+ fprintf(stderr,"Plot spectrum and calculate CCT and VCT\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: specplot [infile.sp]\n");
+ fprintf(stderr," -v verbose\n");
+ fprintf(stderr," -c combine multiple files into one plot\n");
+ fprintf(stderr," -z don't make range cover zero\n");
+ fprintf(stderr," -u level plot effect of adding estimated UV level\n");
+ fprintf(stderr," -U plot effect of adding range of estimated UV level\n");
+ fprintf(stderr," [infile.sp ...] spectrum files to plot\n");
+ fprintf(stderr," default is all built in illuminants\n");
+ exit(1);
+}
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa, nfa; /* argument we're looking at */
+ int k;
+ int verb = 0;
+ int comb = 0;
+ int zero = 1;
+ double temp;
+ xspect sp[MAXGRAPHS];
+ icxIllumeType ilType;
+ int douv = 0;
+ double uvmin = -1.0, uvmax = 1.0;
+ char buf[MAXGRAPHS][200];
+
+ error_program = argv[0];
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Show added UV */
+ if (argv[fa][1] == 'u') {
+ douv = 1;
+
+ fa = nfa;
+ if (na == NULL)
+ usage();
+
+ uvmin = uvmax = atof(na);
+ if (uvmin < -10.0 || uvmax > 10.0)
+ usage();
+ }
+
+ else if (argv[fa][1] == 'U') {
+ douv = 1;
+ }
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+
+ } else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ comb = 1;
+
+ } else if (argv[fa][1] == 'z' || argv[fa][1] == 'Z') {
+ zero = 0;
+
+ } else {
+ usage();
+ }
+ }
+ else
+ break;
+ }
+
+ if (fa < argc && argv[fa][0] != '-') { /* Got file arguments */
+ int nsp = 0; /* Current number in sp[] */
+ int soff = 0; /* Offset within file */
+ int maxgraphs = MAXGRAPHS;
+ int eof;
+
+ if (douv)
+ maxgraphs = 1;
+
+ nsp = 0;
+
+ /* Until we run out */
+ for (;;) {
+ int i, nret, nreq;
+
+ /* If we've got to the limit of each plot, */
+ /* or at least one and there are no more files, */
+ /* or at least one and we're not combining files and at start of a new file */
+ if (nsp >= MAXGRAPHS || (nsp > 0 && ((!comb && soff == 0) || fa >= argc))) {
+ /* Plot what we've got */
+ do_spec(buf, sp, nsp, zero, douv, uvmin, uvmax);
+ nsp = 0;
+ }
+
+ if (fa >= argc) /* No more files */
+ break;
+
+ /* Read as many spectra from the file as possible */
+ nreq = MAXGRAPHS - nsp;
+ if (read_nxspect(&sp[nsp], argv[fa], &nret, soff, nreq, 0) != 0) {
+ error ("Unable to read custom spectrum, CMF or CCSS '%s'",argv[fa]);
+ }
+ for (i = 0; i < nret; i++) {
+ xspect_denorm(&sp[nsp + i]);
+ sprintf(buf[nsp + i],"File '%s' spect %d",argv[fa], soff + i);
+ }
+ nsp += nret;
+ soff += nret;
+ if (nret < nreq) { /* We're done with this file */
+ fa++;
+ soff = 0;
+ }
+ }
+
+ } else {
+
+ /* For each standard illuminant */
+ for (ilType = icxIT_A; ilType <= icxIT_F10; ilType++) {
+ char *inm = NULL;
+
+ switch (ilType) {
+ case icxIT_A:
+ inm = "A"; break;
+ case icxIT_C:
+ inm = "C"; break;
+ case icxIT_D50:
+ inm = "D50"; break;
+ case icxIT_D50M2:
+ inm = "D50M2"; break;
+ case icxIT_D65:
+ inm = "D65"; break;
+ case icxIT_E:
+ inm = "E"; break;
+ case icxIT_F5:
+ inm = "F5"; break;
+ case icxIT_F8:
+ inm = "F8"; break;
+ case icxIT_F10:
+ inm = "F10"; break;
+ default:
+ inm = "Unknown"; break;
+ break;
+ }
+
+ if (standardIlluminant(&sp[0], ilType, 0) != 0)
+ error ("standardIlluminant returned error");
+
+ strcpy(buf[0],inm);
+ do_spec(buf, sp, 1, zero, douv, uvmin, uvmax);
+ }
+
+ /* For each material and illuminant */
+ for (temp = 2500; temp <= 9000; temp += 500) {
+
+ for (k = 0; k < 2; k++) {
+
+ ilType = k == 0 ? icxIT_Dtemp : icxIT_Ptemp;
+
+ if (standardIlluminant(&sp[0], ilType, temp) != 0)
+ error ("standardIlluminant returned error");
+
+ sprintf(buf[0], "%s at %f", k == 0 ? "Daylight" : "Black body", temp);
+
+ do_spec(buf, sp, 1, zero, douv, uvmin, uvmax);
+ }
+ }
+
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/xicc/specsubsamp.c b/xicc/specsubsamp.c
new file mode 100644
index 0000000..b13ad94
--- /dev/null
+++ b/xicc/specsubsamp.c
@@ -0,0 +1,232 @@
+
+/*
+ * Author: Graeme W. Gill
+ * Date: 2007/3/21
+ * Version: 1.00
+ *
+ * Copyright 2007 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.
+ *
+ */
+
+/*
+ * This is some utility code to subsample the 1 and 5nm spectral
+ * data in xspect to wider spacings using ANSI-CGATS the recommended
+ * triangular filter.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "xspect.h"
+#include "numlib.h"
+
+
+void usage(void) {
+ fprintf(stderr,"Downsample spectral data\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: specsubsamp -options\n");
+ fprintf(stderr," -i illum Choose illuminant for print/transparency spectral data:\n");
+ fprintf(stderr," A, C, D50, D50M2, D65, F5, F8, F10 or file.sp\n");
+ fprintf(stderr," -o observ Choose CIE Observer for spectral data:\n");
+ fprintf(stderr," 1931_2, 1964_10, S&B 1955_2, shaw, J&V 1978_2\n");
+ fprintf(stderr," -w st,en,sp Output start, end and spacing nm\n");
+ fprintf(stderr," -5 Commenf output wavelegths every 5\n");
+ exit(1);
+}
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ icxIllumeType illum = icxIT_D50; /* Spectral defaults */
+ xspect cust_illum; /* Custom illumination spectrum */
+ icxObserverType observ = icxOT_CIE_1931_2;
+ int obs = 0; /* If nz output observer */
+ double wl_short = 380.0, wl_long = 730.0, wl_width = 10.0;
+ int wl_n = 0;
+ int evy5 = 0;
+
+ error_program = argv[0];
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Spectral Illuminant type */
+ if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "A") == 0) {
+ illum = icxIT_A;
+ } else if (strcmp(na, "C") == 0) {
+ illum = icxIT_C;
+ } else if (strcmp(na, "D50") == 0) {
+ illum = icxIT_D50;
+ } else if (strcmp(na, "D50M2") == 0) {
+ illum = icxIT_D50M2;
+ } else if (strcmp(na, "D65") == 0) {
+ illum = icxIT_D65;
+ } else if (strcmp(na, "F5") == 0) {
+ illum = icxIT_F5;
+ } else if (strcmp(na, "F8") == 0) {
+ illum = icxIT_F8;
+ } else if (strcmp(na, "F10") == 0) {
+ illum = icxIT_F10;
+ } else { /* Assume it's a filename */
+ illum = icxIT_custom;
+ if (read_xspect(&cust_illum, na) != 0)
+ usage();
+ }
+ }
+
+ /* Spectral Observer type */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (strcmp(na, "1931_2") == 0) { /* Classic 2 degree */
+ obs = 1;
+ observ = icxOT_CIE_1931_2;
+ } else if (strcmp(na, "1964_10") == 0) { /* Classic 10 degree */
+ obs = 1;
+ observ = icxOT_CIE_1964_10;
+ } else if (strcmp(na, "1955_2") == 0) { /* Stiles and Burch 1955 2 degree */
+ obs = 1;
+ observ = icxOT_Stiles_Burch_2;
+ } else if (strcmp(na, "1978_2") == 0) { /* Judd and Voss 1978 2 degree */
+ obs = 1;
+ observ = icxOT_Judd_Voss_2;
+ } else if (strcmp(na, "shaw") == 0) { /* Shaw and Fairchilds 1997 2 degree */
+ obs = 1;
+ observ = icxOT_Shaw_Fairchild_2;
+ } else
+ usage();
+ }
+
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ fa = nfa;
+ if (na == NULL) usage();
+ if (sscanf(na, " %lf,%lf,%lf ",&wl_short,&wl_long,&wl_width) != 3)
+
+ if (wl_short > wl_long)
+ usage();
+ }
+
+ else if (argv[fa][1] == '5') {
+ evy5 = 1;
+ }
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ } else {
+ usage();
+ }
+ }
+ else
+ break;
+ }
+
+ wl_n = (int)((wl_long - wl_short)/wl_width + 1.5);
+
+ if ((fabs(wl_short + (wl_n - 1.0) * wl_width) - wl_long) > 0.001)
+ error("Not an integer number of output samples");
+
+
+ if (obs) {
+ int i, j, k;
+ xspect *sp[3];
+
+ if (standardObserver(sp, observ) != 0)
+ error ("standardObserver returned error");
+ printf("/* %f - %f, %f spacing, %d samples */\n",wl_short,wl_long,wl_width,wl_n);
+ printf("{\n");
+ for (k = 0; k < 3; k++) {
+
+ printf(" {\n");
+ for (i = 0; i < wl_n; i++) {
+ double cwl, swl, sw, tw, outv;
+ int ns;
+
+ cwl = XSPECT_WL(wl_short, wl_long, wl_n, i);
+ ns = (int)(wl_width/0.1 + 0.5);
+ tw = outv = 0.0;
+ for (j = -ns; j <= ns; j++) {
+ swl = cwl + (j * wl_width)/ns;
+ sw = (ns - abs(j))/(double)ns;
+ tw += sw;
+ outv += sw * value_xspect(sp[k], swl);
+ }
+ outv /= tw;
+ if (!evy5 || i % 5 == 0)
+ printf(" /* %3.1f */ %1.10f%s\n",cwl,outv, i < (wl_n-1) ? "," : "");
+ else
+ printf(" %1.10f%s\n",outv, i < (wl_n-1) ? "," : "");
+ }
+ printf(" }%s\n",k < (3-1) ? "," : "");
+ }
+ printf("}\n");
+
+ } else {
+ int i, j;
+ xspect sp;
+
+ if (illum == icxIT_custom)
+ sp = cust_illum;
+ else {
+ if (standardIlluminant(&sp, illum, 0) != 0)
+ error ("standardIlluminant returned error");
+ }
+
+ printf("/* %f - %f, %f spacing, %d samples */\n",wl_short,wl_long,wl_width,wl_n);
+ printf("{\n");
+ for (i = 0; i < wl_n; i++) {
+ double cwl, swl, sw, tw, outv;
+ int ns;
+
+ cwl = XSPECT_WL(wl_short, wl_long, wl_n, i);
+//printf("~1 output %f\n",cwl);
+ ns = (int)(wl_width/0.1 + 0.5);
+ tw = outv = 0.0;
+ for (j = -ns; j <= ns; j++) {
+ swl = cwl + (j * wl_width)/ns;
+ sw = (ns - abs(j))/(double)ns;
+ tw += sw;
+//printf("~1 sample %f weight %f\n",swl,sw);
+ outv += sw * value_xspect(&sp, swl);
+ }
+ outv /= tw;
+ if (!evy5 || i % 5 == 0)
+ printf(" /* %3.1f */ %1.10f%s\n",cwl,outv, i < (wl_n-1) ? "," : "");
+ else
+ printf(" %1.10f%s\n",outv, i < (wl_n-1) ? "," : "");
+ }
+ printf("}\n");
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/xicc/spectest.c b/xicc/spectest.c
new file mode 100644
index 0000000..1c92df4
--- /dev/null
+++ b/xicc/spectest.c
@@ -0,0 +1,750 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 8/5/2002
+ * Version: 1.00
+ *
+ * Copyright 2002 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.
+ *
+ */
+
+/*
+ * This is some test code to test the FWA compensation
+ * feature of the spectal to CIE conversion.
+ *
+ */
+
+#define FILTERED_D65 /* Use Spectrolino filtered D65 instead of ideal D65 */
+
+#define DOPLOT /* Graphs: Black = target curve */
+ /* Red = uncorrected curve */
+ /* Green = corrected curve */
+
+#define DATAFILE /* Write the plot data to a data file */
+
+#include <stdio.h>
+#include <math.h>
+#include "xspect.h"
+#include "numlib.h"
+#ifdef DOPLOT
+#include "plot.h"
+#endif
+
+
+/* Spectrolino filter "D65" illuminant */
+static xspect il_sod65 = {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 17.42, 29.51, 36.54, 38.39, 38.15,
+ 39.68, 44.7, 53.6, 64.26, 74.01,
+ 82.39, 89.9, 93.45, 94.05, 91.59,
+ 89.4, 93.69, 100.85, 99.66, 87.12,
+ 78.34, 82.95, 91.31, 98.18, 99.99,
+ 104.38, 120.06, 145.35, 172.8, 190.38,
+ 192.46, 181.28, 163.7, 143.14, 123.57,
+ 104.67
+ }
+};
+
+/* Material/illuminant record */
+struct {
+ char *media; /* Media/process identifier */
+ char *illum; /* Primary illuminant identifier */
+ icxIllumeType ill; /* Illuminant used to get reflectance spectrum */
+ xspect white; /* Media on its own spectrum */
+ xspect black; /* Media with maximum colorant */
+ struct {
+ char *pdesc; /* Description of sample */
+ xspect s; /* Spectrum of it */
+ } patches[6];
+
+} matilum[2][2] = { /* [Cromalin, Epson 10K] [A, D65] */
+ {
+ {
+ "Cromalin", /* Paper measured */
+ "Illuminant A", /* Illuminant measured under */
+ icxIT_A,
+ { /* White */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0376, 0.0217, 0.0325, 0.1779, 0.5891,
+ 0.9366, 1.0307, 1.0241, 0.9996, 0.9738,
+ 0.9521, 0.9355, 0.9245, 0.9174, 0.9147,
+ 0.9113, 0.9112, 0.9118, 0.9111, 0.9148,
+ 0.9147, 0.9162, 0.9172, 0.9185, 0.9197,
+ 0.9194, 0.9213, 0.9239, 0.9259, 0.9257,
+ 0.9259, 0.9250, 0.9271, 0.9293, 0.9296, 0.9310
+ }
+ },
+ { /* Black */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000
+ }
+ },
+ {
+ {
+ "30% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0274, 0.0161, 0.0218, 0.1072, 0.3077,
+ 0.4280, 0.4532, 0.4530, 0.4508, 0.4498,
+ 0.4585, 0.5019, 0.6137, 0.7716, 0.8680,
+ 0.8939, 0.9000, 0.8999, 0.9015, 0.9098,
+ 0.9153, 0.9193, 0.9212, 0.9230, 0.9245,
+ 0.9247, 0.9267, 0.9294, 0.9317, 0.9315,
+ 0.9317, 0.9317, 0.9331, 0.9354, 0.9357, 0.9366
+ }
+ }
+ },
+ {
+ "60% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0225, 0.0130, 0.0169, 0.0613, 0.1512,
+ 0.1951, 0.2039, 0.2059, 0.2095, 0.2149,
+ 0.2301, 0.2850, 0.4283, 0.6585, 0.8249,
+ 0.8767, 0.8878, 0.8860, 0.8887, 0.9017,
+ 0.9115, 0.9181, 0.9202, 0.9219, 0.9232,
+ 0.9229, 0.9247, 0.9269, 0.9289, 0.9283,
+ 0.9280, 0.9277, 0.9292, 0.9307, 0.9305, 0.9315
+ }
+ }
+ },
+ {
+ "90% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0195, 0.0114, 0.0140, 0.0314, 0.0568,
+ 0.0664, 0.0691, 0.0708, 0.0760, 0.0836,
+ 0.1003, 0.1571, 0.3087, 0.5728, 0.7861,
+ 0.8602, 0.8759, 0.8737, 0.8781, 0.8952,
+ 0.9094, 0.9185, 0.9215, 0.9234, 0.9250,
+ 0.9248, 0.9267, 0.9292, 0.9312, 0.9307,
+ 0.9305, 0.9300, 0.9313, 0.9328, 0.9321, 0.9339
+ }
+ }
+ },
+ {
+ "30% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0163, 0.0117, 0.0181, 0.1018, 0.3029,
+ 0.4324, 0.4585, 0.4539, 0.4437, 0.4330,
+ 0.4247, 0.4180, 0.4140, 0.4113, 0.4108,
+ 0.4095, 0.4097, 0.4101, 0.4100, 0.4117,
+ 0.4119, 0.4126, 0.4133, 0.4141, 0.4152,
+ 0.4156, 0.4169, 0.4187, 0.4200, 0.4206,
+ 0.4211, 0.4214, 0.4224, 0.4240, 0.4243, 0.4256
+ }
+ }
+ },
+ {
+ "60% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0087, 0.0070, 0.0138, 0.0539, 0.1378,
+ 0.1802, 0.1872, 0.1840, 0.1794, 0.1748,
+ 0.1711, 0.1686, 0.1669, 0.1661, 0.1659,
+ 0.1656, 0.1657, 0.1661, 0.1660, 0.1670,
+ 0.1670, 0.1675, 0.1680, 0.1686, 0.1693,
+ 0.1700, 0.1707, 0.1720, 0.1728, 0.1735,
+ 0.1740, 0.1745, 0.1749, 0.1761, 0.1759, 0.1779
+ }
+ }
+ },
+ {
+ "90% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0044, 0.0040, 0.0090, 0.0243, 0.0430,
+ 0.0503, 0.0508, 0.0485, 0.0460, 0.0440,
+ 0.0423, 0.0412, 0.0406, 0.0404, 0.0404,
+ 0.0404, 0.0407, 0.0409, 0.0411, 0.0415,
+ 0.0418, 0.0422, 0.0424, 0.0429, 0.0434,
+ 0.0440, 0.0444, 0.0452, 0.0459, 0.0465,
+ 0.0469, 0.0473, 0.0477, 0.0483, 0.0489, 0.0496
+ }
+ }
+ }
+ }
+ },
+ {
+ "Cromalin",
+ "Illuminant filtered D65",
+ icxIT_D65,
+ { /* White */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0096, 0.0082, 0.0242, 0.1791, 0.6547,
+ 1.0944, 1.2012, 1.1545, 1.0891, 1.0388,
+ 1.0009, 0.9725, 0.9552, 0.9442, 0.9384,
+ 0.9313, 0.9266, 0.9235, 0.9213, 0.9250,
+ 0.9249, 0.9247, 0.9239, 0.9248, 0.9253,
+ 0.9249, 0.9267, 0.9293, 0.9310, 0.9308,
+ 0.9307, 0.9311, 0.9309, 0.9335, 0.9263, 0.8774
+ }
+ },
+ { /* Black */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000
+ }
+ },
+ {
+ {
+ "30% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0054, 0.0050, 0.0157, 0.1084, 0.3443,
+ 0.4998, 0.5278, 0.5108, 0.4915, 0.4802,
+ 0.4823, 0.5221, 0.6331, 0.7929, 0.8894,
+ 0.9116, 0.9134, 0.9095, 0.9097, 0.9176,
+ 0.9222, 0.9245, 0.9251, 0.9267, 0.9278,
+ 0.9275, 0.9293, 0.9323, 0.9344, 0.9346,
+ 0.9348, 0.9346, 0.9344, 0.9354, 0.9252, 0.8748
+ }
+ }
+ },
+ {
+ "60% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0039, 0.0042, 0.0117, 0.0632, 0.1733,
+ 0.2333, 0.2430, 0.2364, 0.2315, 0.2315,
+ 0.2440, 0.2976, 0.4421, 0.6777, 0.8461,
+ 0.8950, 0.9014, 0.8967, 0.8971, 0.9095,
+ 0.9187, 0.9234, 0.9242, 0.9263, 0.9270,
+ 0.9257, 0.9280, 0.9303, 0.9326, 0.9322,
+ 0.9315, 0.9317, 0.9314, 0.9306, 0.9169, 0.8664
+ }
+ }
+ },
+ {
+ "90% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0032, 0.0038, 0.0099, 0.0342, 0.0716,
+ 0.0889, 0.0918, 0.0884, 0.0887, 0.0931,
+ 0.1086, 0.1652, 0.3190, 0.5892, 0.8060,
+ 0.8777, 0.8891, 0.8839, 0.8863, 0.9022,
+ 0.9158, 0.9230, 0.9259, 0.9269, 0.9283,
+ 0.9266, 0.9304, 0.9327, 0.9350, 0.9344,
+ 0.9342, 0.9336, 0.9328, 0.9323, 0.9175, 0.8589
+ }
+ }
+ },
+ {
+ "30% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0047, 0.0049, 0.0153, 0.1046, 0.3404,
+ 0.5036, 0.5317, 0.5102, 0.4828, 0.4620,
+ 0.4468, 0.4358, 0.4293, 0.4249, 0.4232,
+ 0.4207, 0.4191, 0.4181, 0.4172, 0.4188,
+ 0.4190, 0.4194, 0.4191, 0.4196, 0.4203,
+ 0.4204, 0.4218, 0.4236, 0.4251, 0.4255,
+ 0.4258, 0.4259, 0.4267, 0.4276, 0.4249, 0.4031
+ }
+ }
+ },
+ {
+ "60% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0042, 0.0047, 0.0126, 0.0586, 0.1584,
+ 0.2146, 0.2206, 0.2101, 0.1978, 0.1885,
+ 0.1820, 0.1774, 0.1748, 0.1730, 0.1726,
+ 0.1714, 0.1710, 0.1703, 0.1704, 0.1712,
+ 0.1709, 0.1717, 0.1713, 0.1724, 0.1730,
+ 0.1732, 0.1738, 0.1753, 0.1759, 0.1768,
+ 0.1766, 0.1778, 0.1774, 0.1775, 0.1774, 0.1707
+ }
+ }
+ },
+ {
+ "90% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0018, 0.0039, 0.0103, 0.0293, 0.0560,
+ 0.0677, 0.0676, 0.0611, 0.0551, 0.0505,
+ 0.0475, 0.0452, 0.0441, 0.0434, 0.0430,
+ 0.0430, 0.0428, 0.0428, 0.0427, 0.0433,
+ 0.0433, 0.0434, 0.0441, 0.0438, 0.0448,
+ 0.0457, 0.0453, 0.0468, 0.0471, 0.0477,
+ 0.0483, 0.0483, 0.0487, 0.0486, 0.0492, 0.0500
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ {
+ "Epson10K",
+ "Illuminant A",
+ icxIT_A,
+ { /* White */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.4561, 0.4677, 0.5052, 0.6477, 0.8785,
+ 0.9929, 1.0127, 0.9909, 0.9676, 0.9539,
+ 0.9420, 0.9330, 0.9277, 0.9246, 0.9236,
+ 0.9205, 0.9200, 0.9191, 0.9172, 0.9198,
+ 0.9184, 0.9185, 0.9181, 0.9189, 0.9204,
+ 0.9207, 0.9228, 0.9256, 0.9277, 0.9276,
+ 0.9284, 0.9286, 0.9304, 0.9332, 0.9321, 0.9349
+ }
+ },
+ { /* Black */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000
+ }
+ },
+ {
+ {
+ "30% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.3650, 0.3689, 0.3908, 0.4912, 0.6549,
+ 0.7395, 0.7667, 0.7745, 0.7868, 0.8103,
+ 0.8385, 0.8663, 0.8869, 0.8983, 0.9037,
+ 0.9028, 0.9031, 0.9024, 0.9006, 0.9030,
+ 0.9018, 0.9016, 0.9007, 0.9011, 0.9013,
+ 0.9002, 0.9015, 0.9032, 0.9048, 0.9043,
+ 0.9040, 0.9038, 0.9050, 0.9073, 0.9062, 0.9082
+ }
+ }
+ },
+ {
+ "60% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.2376, 0.2286, 0.2349, 0.2856, 0.3740,
+ 0.4290, 0.4642, 0.5005, 0.5513, 0.6172,
+ 0.6959, 0.7750, 0.8340, 0.8683, 0.8848,
+ 0.8884, 0.8901, 0.8900, 0.8884, 0.8906,
+ 0.8892, 0.8893, 0.8884, 0.8885, 0.8886,
+ 0.8875, 0.8885, 0.8903, 0.8917, 0.8910,
+ 0.8911, 0.8908, 0.8924, 0.8951, 0.8940, 0.8962
+ }
+ }
+ },
+ {
+ "90% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0482, 0.0362, 0.0314, 0.0323, 0.0373,
+ 0.0448, 0.0570, 0.0829, 0.1310, 0.2130,
+ 0.3465, 0.5227, 0.6838, 0.7871, 0.8409,
+ 0.8622, 0.8713, 0.8749, 0.8752, 0.8787,
+ 0.8783, 0.8787, 0.8781, 0.8784, 0.8784,
+ 0.8773, 0.8780, 0.8794, 0.8802, 0.8789,
+ 0.8783, 0.8773, 0.8778, 0.8794, 0.8775, 0.8779
+ }
+ }
+ },
+ {
+ "30% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.3304, 0.3398, 0.3632, 0.4562, 0.6018,
+ 0.6702, 0.6808, 0.6663, 0.6520, 0.6434,
+ 0.6362, 0.6311, 0.6285, 0.6272, 0.6269,
+ 0.6253, 0.6253, 0.6253, 0.6247, 0.6274,
+ 0.6280, 0.6301, 0.6320, 0.6351, 0.6385,
+ 0.6414, 0.6464, 0.6530, 0.6593, 0.6643,
+ 0.6692, 0.6727, 0.6770, 0.6811, 0.6826, 0.6856
+ }
+ }
+ },
+ {
+ "60% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.1735, 0.1784, 0.1886, 0.2295, 0.2936,
+ 0.3232, 0.3279, 0.3227, 0.3177, 0.3152,
+ 0.3133, 0.3126, 0.3126, 0.3131, 0.3141,
+ 0.3142, 0.3151, 0.3160, 0.3169, 0.3195,
+ 0.3217, 0.3251, 0.3287, 0.3335, 0.3386,
+ 0.3439, 0.3511, 0.3599, 0.3692, 0.3775,
+ 0.3853, 0.3919, 0.3982, 0.4036, 0.4068, 0.4109
+ }
+ }
+ },
+ {
+ "90% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0197, 0.0198, 0.0201, 0.0201, 0.0208,
+ 0.0207, 0.0204, 0.0202, 0.0200, 0.0197,
+ 0.0194, 0.0194, 0.0193, 0.0192, 0.0191,
+ 0.0191, 0.0190, 0.0190, 0.0190, 0.0192,
+ 0.0194, 0.0198, 0.0205, 0.0212, 0.0221,
+ 0.0230, 0.0244, 0.0261, 0.0282, 0.0304,
+ 0.0326, 0.0346, 0.0366, 0.0383, 0.0396, 0.0412
+ }
+ }
+ }
+ }
+ },
+ {
+ "Epson10K",
+ "Illuminant filtered D65",
+ icxIT_D65,
+ { /* White */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.4452, 0.4631, 0.5041, 0.6692, 0.9582,
+ 1.1083, 1.1289, 1.0717, 1.0191, 0.9929,
+ 0.9721, 0.9560, 0.9483, 0.9439, 0.9419,
+ 0.9374, 0.9357, 0.9337, 0.9313, 0.9340,
+ 0.9330, 0.9329, 0.9320, 0.9328, 0.9341,
+ 0.9339, 0.9366, 0.9387, 0.9406, 0.9405,
+ 0.9404, 0.9405, 0.9414, 0.9455, 0.9369, 0.9289
+ }
+ },
+ { /* Black */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
+ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000
+ }
+ },
+ {
+ {
+ "30% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.3538, 0.3632, 0.3888, 0.5058, 0.7111,
+ 0.8221, 0.8512, 0.8334, 0.8251, 0.8392,
+ 0.8609, 0.8832, 0.9013, 0.9113, 0.9157,
+ 0.9137, 0.9128, 0.9113, 0.9086, 0.9111,
+ 0.9103, 0.9094, 0.9091, 0.9083, 0.9085,
+ 0.9080, 0.9091, 0.9104, 0.9118, 0.9104,
+ 0.9099, 0.9099, 0.9094, 0.9111, 0.9054, 0.8793
+ }
+ }
+ },
+ {
+ "60% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.2220, 0.2209, 0.2299, 0.2901, 0.4010,
+ 0.4716, 0.5092, 0.5337, 0.5732, 0.6337,
+ 0.7095, 0.7848, 0.8422, 0.8755, 0.8907,
+ 0.8933, 0.8938, 0.8927, 0.8909, 0.8929,
+ 0.8922, 0.8912, 0.8897, 0.8902, 0.8900,
+ 0.8893, 0.8896, 0.8915, 0.8932, 0.8918,
+ 0.8921, 0.8915, 0.8921, 0.8939, 0.8825, 0.8575
+ }
+ }
+ },
+ {
+ "90% Y",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0326, 0.0287, 0.0269, 0.0295, 0.0376,
+ 0.0469, 0.0605, 0.0862, 0.1343, 0.2162,
+ 0.3503, 0.5257, 0.6862, 0.7889, 0.8420,
+ 0.8632, 0.8719, 0.8753, 0.8753, 0.8784,
+ 0.8776, 0.8778, 0.8778, 0.8783, 0.8775,
+ 0.8772, 0.8777, 0.8791, 0.8808, 0.8793,
+ 0.8784, 0.8770, 0.8758, 0.8757, 0.8626, 0.8106
+ }
+ }
+ },
+ {
+ "30% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.3243, 0.3369, 0.3635, 0.4708, 0.6532,
+ 0.7439, 0.7542, 0.7167, 0.6839, 0.6673,
+ 0.6546, 0.6454, 0.6412, 0.6387, 0.6380,
+ 0.6357, 0.6351, 0.6341, 0.6334, 0.6363,
+ 0.6367, 0.6388, 0.6400, 0.6431, 0.6465,
+ 0.6491, 0.6532, 0.6591, 0.6656, 0.6699,
+ 0.6743, 0.6778, 0.6816, 0.6859, 0.6815, 0.6758
+ }
+ }
+ },
+ {
+ "60% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.1707, 0.1772, 0.1895, 0.2374, 0.3174,
+ 0.3566, 0.3616, 0.3464, 0.3329, 0.3272,
+ 0.3228, 0.3201, 0.3196, 0.3198, 0.3208,
+ 0.3203, 0.3207, 0.3217, 0.3221, 0.3249,
+ 0.3269, 0.3295, 0.3339, 0.3375, 0.3427,
+ 0.3483, 0.3545, 0.3635, 0.3726, 0.3808,
+ 0.3881, 0.3949, 0.4003, 0.4053, 0.4052, 0.3962
+ }
+ }
+ },
+ {
+ "90% K",
+ {
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.0206, 0.0205, 0.0202, 0.0205, 0.0213,
+ 0.0217, 0.0210, 0.0207, 0.0202, 0.0199,
+ 0.0198, 0.0197, 0.0197, 0.0195, 0.0196,
+ 0.0193, 0.0192, 0.0194, 0.0194, 0.0194,
+ 0.0197, 0.0198, 0.0204, 0.0214, 0.0223,
+ 0.0236, 0.0242, 0.0265, 0.0283, 0.0306,
+ 0.0330, 0.0347, 0.0370, 0.0389, 0.0394, 0.0383
+ }
+ }
+ }
+ }
+ }
+ }
+};
+
+/* ---------------------------------------------------------- */
+
+int
+main(void) {
+ int m, ps, ss, pn;
+#ifdef DATAFILE
+ FILE *df;
+#endif
+
+ printf("Hi there\n");
+
+#ifdef DATAFILE
+ if ((df = fopen("spectest.dat", "w")) == NULL)
+ error ("Unable to open data file '%s'","spectest.dat");
+#endif
+ /* For each material and illuminant */
+ for (m = 0; m < 2; m++) {
+
+ printf("Material '%s'\n", matilum[m][0].media);
+
+ /* For each light source as primary (target/check), other as secondary (instrument) */
+ for (ps = 0; ps < 2; ps++) {
+ xsp2cie *pcon, *scon; /* Conversions */
+ xspect pill, sill; /* Illuminants */
+
+ ss = 1 - ps; /* Opposite */
+
+#ifdef FILTERED_D65
+ if (matilum[m][ps].ill == icxIT_D65)
+ pill = il_sod65;
+ else
+#endif
+ standardIlluminant(&pill, matilum[m][ps].ill, 0); /* Target/check */
+
+#ifdef FILTERED_D65
+ if (matilum[m][ss].ill == icxIT_D65)
+ sill = il_sod65;
+ else
+#endif
+ standardIlluminant(&sill, matilum[m][ss].ill, 0); /* Instrument */
+
+ /* Create two conversions for the target/check illuminant */
+ if ((pcon = new_xsp2cie(icxIT_custom, &pill, icxOT_Shaw_Fairchild_2,
+ NULL, icSigLabData, 1)) == NULL)
+ error ("Creating conversion failed");
+
+ if ((scon = new_xsp2cie(icxIT_custom, &pill, icxOT_Shaw_Fairchild_2,
+ NULL, icSigLabData, 1)) == NULL)
+ error ("Creating conversion failed");
+
+ /* Tell the secondary conversion to allow for instrument illuminant */
+ if (scon->set_fwa(scon, &sill, NULL, &matilum[m][ss].white))
+ error ("Setting FWA compensation failed");
+
+ printf("Primary (Target/Check) '%s', Secondary (Instrument)'%s'\n",
+ matilum[m][ps].illum, matilum[m][ss].illum);
+
+ /* For each test patch */
+ for (pn = 0; pn < 6; pn++) {
+ int i, j;
+ double plab[3];
+ double slab[3];
+ double sclab[3];
+ xspect psp; /* Reference spectrum */
+ xspect ssp; /* un-compensated spectrum */
+ xspect scsp; /* Compensated spectrum */
+ double de, cde;
+#ifdef DOPLOT
+#define XRES 400
+ double xx[XRES];
+ double y1[XRES];
+ double y2[XRES];
+ double y3[XRES];
+#endif /* DOPLOT */
+
+
+ /* Compute reference value for target illuminant */
+ pcon->sconvert(pcon, &psp, plab, &matilum[m][ps].patches[pn].s);
+
+ /* Compute uncompensated value for target illuminant */
+ pcon->sconvert(pcon, &ssp, slab, &matilum[m][ss].patches[pn].s);
+
+ /* Compute compensated value for target illuminant */
+ scon->sconvert(scon, &scsp, sclab, &matilum[m][ss].patches[pn].s);
+
+ de = 0.0;
+ for (j = 0; j < 3; j++) {
+ double tt = plab[j] - slab[j];
+ de += tt * tt;
+ }
+ de = sqrt(de);
+
+ printf("Patch '%s', Ref %f %f %f, Other %f %f %f DE %f\n",
+ matilum[m][ps].patches[pn].pdesc, plab[0], plab[1], plab[2],
+ slab[0], slab[1], slab[2], de);
+
+ cde = 0.0;
+ for (j = 0; j < 3; j++) {
+ double tt = plab[j] - sclab[j];
+ cde += tt * tt;
+ }
+ cde = sqrt(cde);
+
+ printf("Patch '%s', Ref %f %f %f, COther %f %f %f DE %f\n",
+ matilum[m][ps].patches[pn].pdesc, plab[0], plab[1], plab[2],
+ sclab[0], sclab[1], sclab[2], cde);
+ printf("DE change %f\n",cde - de);
+ printf("\n");
+
+#ifdef DOPLOT
+ for (i = 0; i < psp.spec_n; i++) {
+ double ww;
+
+ ww = (psp.spec_wl_long - psp.spec_wl_short)
+ * ((double)i/(psp.spec_n-1.0)) + psp.spec_wl_short;
+
+ xx[i] = ww;
+ y1[i] = ssp.spec[i]; /* Black - Input */
+ y2[i] = scsp.spec[i]; /* Red - Estimate */
+ y3[i] = psp.spec[i]; /* Green - Target */
+ }
+ do_plot(xx,y1,y2,y3,i);
+#endif /* DOPLOT */
+#ifdef DATAFILE
+ fprintf(df,"\nPrimary (Target/Check) '%s', Secondary (Instrument)'%s'\n",
+ matilum[m][ps].illum, matilum[m][ss].illum);
+ fprintf(df,"Patch '%s', Ref %f %f %f, Other %f %f %f DE %f\n",
+ matilum[m][ps].patches[pn].pdesc, plab[0], plab[1], plab[2],
+ slab[0], slab[1], slab[2], de);
+ fprintf(df,"Patch '%s', Ref %f %f %f, COther %f %f %f DE %f\n",
+ matilum[m][ps].patches[pn].pdesc, plab[0], plab[1], plab[2],
+ sclab[0], sclab[1], sclab[2], cde);
+ fprintf(df,"NM Ref. Un-comp. Comp.\n");
+ for (i = 0; i < psp.spec_n; i++) {
+ double ww;
+
+ ww = (psp.spec_wl_long - psp.spec_wl_short)
+ * ((double)i/(psp.spec_n-1.0)) + psp.spec_wl_short;
+
+ fprintf(df,"%d %f %f %f\n",((int)ww), psp.spec[i], ssp.spec[i], scsp.spec[i]);
+ }
+#endif /* DATAFILE */
+ }
+ pcon->del(pcon);
+ scon->del(scon);
+ }
+ }
+#ifdef DATAFILE
+ fclose(df);
+#endif
+
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/xicc/spectest2.c b/xicc/spectest2.c
new file mode 100644
index 0000000..e9c1754
--- /dev/null
+++ b/xicc/spectest2.c
@@ -0,0 +1,270 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/3/2007
+ * Version: 1.00
+ *
+ * Copyright 2002 - 2007 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.
+ *
+ */
+
+/*
+ * This is some more test code to test the FWA compensation
+ * feature of the spectal to CIE conversion.
+ * Check how well the FWA is estimated from some paper samples.
+ */
+
+#define DOPLOT /* Graphs: Black = target curve */
+ /* Red = uncorrected curve */
+ /* Green = corrected curve */
+
+#include <stdio.h>
+#include <math.h>
+#include "xspect.h"
+#include "insttypes.h"
+//#include "inst.h"
+#include "numlib.h"
+#ifdef DOPLOT
+#include "plot.h"
+#endif
+
+
+/* Normal 'A' spectra, then UV filtered version */
+
+xspect mat[2][20] = {
+ /* 'A' illuminant */
+ {
+ { /* 1 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 14.267, 15.584, 20.723, 41.993, 84.338, 104.728, 108.065, 104.009, 98.717, 95.746, 93.079, 90.568, 88.689, 87.157, 85.795, 84.303, 83.109, 81.981, 80.966, 80.685, 80.361, 80.369, 80.530, 81.249, 82.823, 85.006, 87.685, 90.146, 91.902, 92.799, 93.246, 93.458, 93.767, 94.212, 94.372, 94.651
+ }
+ },
+ { /* 2 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 14.983, 16.831, 22.426, 43.716, 84.430, 105.538, 109.685, 105.582, 100.060, 96.944, 94.119, 91.251, 88.909, 86.894, 84.962, 83.264, 82.636, 82.203, 81.208, 80.950, 81.420, 82.457, 83.033, 83.040, 83.033, 83.700, 85.422, 87.339, 88.728, 89.234, 89.152, 88.913, 89.203, 89.990, 90.613, 91.301
+ }
+ },
+ { /* 3 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 24.488, 29.581, 37.749, 69.706, 94.472, 100.591, 100.273, 98.291, 97.532, 96.351, 95.134, 94.261, 93.428, 92.569, 91.950, 91.181, 90.660, 90.115, 89.426, 89.326, 89.147, 89.154, 89.151, 89.321, 89.636, 89.984, 90.717, 91.607, 92.478, 93.171, 93.867, 94.470, 95.044, 95.638, 95.840, 96.071
+ }
+ },
+ { /* 4 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 44.123, 45.345, 46.333, 52.603, 77.805, 95.763, 102.401, 99.326, 95.610, 95.188, 94.009, 92.570, 92.002, 91.687, 91.396, 90.911, 90.662, 90.464, 90.104, 90.172, 89.881, 89.799, 89.690, 89.664, 89.708, 89.679, 89.894, 90.203, 90.473, 90.556, 90.720, 90.841, 91.078, 91.416, 91.445, 91.559
+ }
+ },
+ { /* 5 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 59.175, 67.893, 72.295, 79.833, 89.531, 92.976, 93.994, 93.660, 93.322, 93.028, 92.527, 91.913, 91.195, 90.494, 89.974, 89.258, 88.761, 88.208, 87.470, 87.222, 86.769, 86.608, 86.590, 86.842, 87.344, 87.956, 88.924, 90.036, 91.088, 91.870, 92.720, 93.474, 94.280, 95.064, 95.370, 95.685
+ }
+ },
+ { /* 6 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 37.749, 42.672, 50.439, 75.066, 95.496, 97.450, 98.295, 95.268, 93.331, 92.634, 91.847, 91.403, 91.410, 91.538, 91.791, 91.771, 91.955, 92.073, 91.974, 92.312, 92.335, 92.575, 92.698, 92.835, 93.066, 93.277, 93.761, 94.294, 94.661, 94.719, 94.749, 94.757, 95.001, 95.429, 95.619, 95.931
+ }
+ },
+ { /* 7 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 57.122, 62.955, 67.576, 72.801, 76.460, 78.437, 79.846, 80.856, 81.509, 82.098, 82.427, 82.523, 82.718, 82.593, 82.345, 82.122, 82.183, 82.198, 82.035, 82.353, 82.618, 83.188, 83.512, 83.549, 83.583, 84.044, 85.291, 86.585, 87.429, 87.476, 87.439, 87.590, 88.241, 89.077, 89.530, 90.008
+ }
+ },
+ { /* 8 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 58.637, 64.082, 68.830, 73.651, 76.911, 78.772, 80.309, 81.192, 82.121, 82.541, 82.893, 83.226, 83.147, 83.038, 83.058, 82.702, 82.727, 83.025, 82.982, 83.281, 83.705, 84.410, 84.663, 84.619, 84.804, 85.372, 86.410, 87.352, 88.013, 88.340, 88.616, 88.753, 89.031, 89.572, 89.914, 90.712
+ }
+ },
+ { /* 9 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 32.774, 38.428, 47.037, 72.668, 97.391, 102.330, 102.404, 99.655, 97.093, 95.368, 93.825, 92.567, 91.674, 90.957, 90.507, 89.992, 89.784, 89.565, 89.259, 89.610, 89.881, 90.199, 90.325, 90.465, 90.671, 90.878, 91.428, 92.051, 92.507, 92.607, 92.842, 93.236, 93.963, 94.682, 94.942, 95.146
+ }
+ },
+ { /* 10 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 66.797, 69.934, 72.229, 74.822, 76.630, 78.036, 78.706, 79.021, 79.371, 79.281, 79.175, 79.144, 79.095, 79.119, 79.272, 79.143, 79.064, 78.924, 78.588, 78.615, 78.296, 78.132, 77.969, 77.909, 77.943, 77.812, 77.925, 78.115, 78.213, 78.133, 78.181, 78.345, 78.757, 79.268, 79.782, 80.318
+ }
+ },
+ { /* 11 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 29.478, 33.585, 40.588, 60.658, 85.350, 92.218, 93.564, 91.366, 88.913, 87.742, 86.793, 86.094, 85.874, 85.915, 86.117, 86.130, 86.333, 86.510, 86.589, 87.051, 87.157, 87.444, 87.677, 88.083, 88.545, 88.907, 89.442, 90.002, 90.440, 90.591, 90.787, 91.029, 91.434, 91.878, 92.014, 92.373
+ }
+ },
+ { /* 12 */
+ 0, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 0.0
+ }
+ }
+ },
+
+ /* UV filtered */
+ {
+ { /* 1 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 28.419, 33.018, 42.215, 51.413, 69.808, 85.626, 88.515, 88.544, 88.433, 88.268, 87.971, 87.553, 86.919, 86.138, 85.337, 84.207, 83.249, 82.288, 81.393, 81.182, 80.923, 80.961, 81.138, 81.828, 83.388, 85.583, 88.212, 90.650, 92.373, 93.250, 93.633, 93.778, 94.089, 94.424, 94.498, 94.910
+ }
+ },
+ { /* 2 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 28.104, 32.711, 41.924, 51.137, 69.563, 85.811, 89.046, 89.203, 89.062, 88.799, 88.455, 87.735, 86.713, 85.504, 84.103, 82.802, 82.413, 82.146, 81.252, 81.067, 81.568, 82.671, 83.263, 83.214, 83.248, 83.963, 85.592, 87.499, 88.976, 89.428, 89.257, 89.095, 89.302, 90.015, 90.578, 91.308
+ }
+ },
+ { /* 3 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 70.653, 72.514, 76.238, 79.961, 87.407, 92.047, 92.848, 93.040, 93.369, 93.389, 93.257, 93.088, 92.713, 92.239, 91.847, 91.231, 90.837, 90.378, 89.765, 89.702, 89.530, 89.587, 89.577, 89.724, 90.020, 90.395, 91.115, 91.948, 92.866, 93.526, 94.160, 94.800, 95.340, 95.785, 96.001, 96.205
+ }
+ },
+ { /* 4 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 39.580, 43.280, 50.681, 58.081, 72.882, 86.792, 90.031, 90.136, 90.086, 90.403, 90.619, 90.769, 90.883, 90.942, 91.074, 90.832, 90.758, 90.656, 90.367, 90.489, 90.233, 90.180, 90.049, 90.013, 90.100, 90.021, 90.238, 90.576, 90.811, 90.900, 91.031, 91.114, 91.314, 91.537, 91.438, 91.634
+ }
+ },
+ { /* 5 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 77.775, 78.760, 80.729, 82.698, 86.637, 89.962, 90.821, 91.214, 91.679, 91.804, 91.748, 91.501, 91.059, 90.523, 90.154, 89.541, 89.136, 88.644, 87.956, 87.743, 87.265, 87.155, 87.163, 87.349, 87.809, 88.407, 89.293, 90.340, 91.417, 92.181, 92.880, 93.690, 94.331, 94.912, 95.209, 95.549
+ }
+ },
+ { /* 6 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 70.130, 71.508, 74.263, 77.018, 82.527, 85.915, 86.959, 87.455, 88.211, 88.869, 89.502, 90.186, 90.813, 91.367, 91.951, 92.170, 92.518, 92.720, 92.703, 93.117, 93.192, 93.453, 93.621, 93.771, 94.057, 94.262, 94.695, 95.157, 95.508, 95.572, 95.574, 95.771, 96.080, 96.418, 96.573, 96.865
+ }
+ },
+ { /* 7 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 70.903, 71.374, 72.316, 73.259, 75.144, 77.016, 78.664, 79.797, 80.774, 81.501, 81.859, 82.236, 82.471, 82.309, 82.265, 82.050, 82.044, 82.123, 82.052, 82.288, 82.492, 83.143, 83.510, 83.466, 83.495, 84.034, 85.312, 86.528, 87.301, 87.403, 87.410, 87.697, 88.149, 88.800, 89.108, 89.670
+ }
+ },
+ { /* 8 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 71.356, 71.858, 72.862, 73.867, 75.875, 77.895, 79.391, 80.476, 81.601, 82.106, 82.559, 83.048, 83.056, 83.041, 83.107, 82.713, 82.781, 83.133, 83.088, 83.355, 83.790, 84.538, 84.821, 84.683, 84.892, 85.550, 86.553, 87.512, 88.192, 88.505, 88.733, 88.959, 89.162, 89.539, 89.868, 90.603
+ }
+ },
+ { /* 9 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 68.893, 70.690, 74.285, 77.880, 85.070, 89.766, 90.646, 90.753, 90.971, 90.955, 90.895, 90.798, 90.641, 90.406, 90.284, 89.991, 89.943, 89.840, 89.591, 89.991, 90.279, 90.608, 90.760, 90.860, 91.096, 91.360, 91.836, 92.435, 92.923, 93.002, 93.227, 93.684, 94.312, 94.851, 95.151, 95.382
+ }
+ },
+ { /* 10 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 71.725, 72.140, 72.969, 73.798, 75.457, 76.827, 77.511, 78.066, 78.560, 78.621, 78.659, 78.711, 78.736, 78.759, 78.905, 78.808, 78.824, 78.662, 78.369, 78.382, 78.062, 77.906, 77.778, 77.756, 77.796, 77.681, 77.606, 77.754, 77.733, 77.637, 77.658, 77.616, 77.867, 78.183, 78.446, 78.888
+ }
+ },
+ { /* 11 */
+ 36, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 56.723, 58.809, 62.983, 67.157, 75.504, 81.580, 82.970, 83.489, 84.048, 84.454, 84.913, 85.415, 85.885, 86.365, 86.852, 87.052, 87.381, 87.634, 87.777, 88.262, 88.371, 88.665, 88.885, 89.250, 89.674, 89.930, 90.462, 90.913, 91.339, 91.367, 91.548, 91.681, 92.032, 92.466, 92.440, 92.765
+ }
+ },
+ { /* 12 */
+ 0, 380.0, 730.0, /* 36 bands from 380 to 730 in 10nm steps */
+ 100.0, /* Scale factor */
+ {
+ 0.0
+ }
+ }
+ }
+};
+
+int
+main(void) {
+ int m, i;
+ xspect insp;
+ double xx[500],y1[500],y2[500],y3[500];
+
+ if (inst_illuminant(&insp, instSpectrolino) != 0)
+ error ("Instrument doesn't have an FWA illuminent");
+
+ printf("Hi there\n");
+
+ /* For each material */
+ for (m = 0; ; m++) {
+ xsp2cie *con; /* Conversions */
+
+ if (mat[0][m].spec_n == 0)
+ break;
+
+ printf("Material %d\n", m+1);
+
+ /* Create two conversions for the target/check illuminant */
+ if ((con = new_xsp2cie(icxIT_D50, NULL, icxOT_CIE_1931_2,
+ NULL, icSigLabData, 1)) == NULL)
+ error ("Creating conversion failed");
+
+ if (con->set_fwa(con, &insp, NULL, &mat[0][m]))
+ error ("Setting FWA compensation failed");
+
+ for (i = 0; i < mat[0][m].spec_n; i++) {
+ double ww;
+
+ ww = (mat[0][m].spec_wl_long - mat[0][m].spec_wl_short)
+ * ((double)i/(mat[0][m].spec_n-1.0)) + mat[0][m].spec_wl_short;
+
+ xx[i] = ww;
+ y1[i] = mat[0][m].spec[i]; /* 'A' Black = Input Measurement */
+ y2[i] = con->media.spec[i] * 100.0; /* Red = Estimated media */
+ y3[i] = mat[1][m].spec[i]; /* Green = Target Measurement with UV */
+ }
+// do_plot(xx,y1,y2,y3,i);
+ do_plot_x(xx,y1,y2,y3,i,
+ 1, 370.0, 740.0, 0.0, 120.0, 2.0);
+ con->del(con);
+ }
+ return 0;
+}
+
+
+
+
+
+
+
+
diff --git a/xicc/tiffgamut.c b/xicc/tiffgamut.c
new file mode 100644
index 0000000..e3e34e8
--- /dev/null
+++ b/xicc/tiffgamut.c
@@ -0,0 +1,1300 @@
+
+/*
+ * Create a visualisation of the gamut of a TIFF or JPEG file.
+ *
+ * Author: Graeme W. Gill
+ * Date: 00/9/20
+ * Version: 1.00
+ *
+ * Copyright 2000, 2002, 2012 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.
+ */
+
+/*
+ * TTBD:
+ *
+ * Should record abs/relative intent, PCS space used together
+ * with viewing conditions, so that a mismatch within
+ * icclink can be detected or allowed for.
+ *
+ * Need to cope with profile not having black point.
+ *
+ * How to cope with no profile, therefore no white or black point ?
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "tiffio.h"
+#include "jpeglib.h"
+#include "iccjpeg.h"
+#include "icc.h"
+#include "gamut.h"
+#include "xicc.h"
+#include "sort.h"
+
+#undef NOCAMGAM_CLIP /* No clip to CAM gamut before CAM lookup */
+#undef DEBUG /* Dump filter cell contents */
+
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+
+void set_fminmax(double min[3], double max[3]);
+void reset_filter();
+void add_fpixel(double val[3]);
+void flush_filter(int verb, gamut *gam, double filtperc);
+void del_filter();
+
+void usage(void) {
+ int i;
+ fprintf(stderr,"Create VRML image of the gamut surface of a TIFF or JPEG, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: tiffgamut [-v level] [profile.icm | embedded.tif/jpg] infile1.tif/jpg [infile2.tif/jpg ...] \n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -d sres Surface resolution details 1.0 - 50.0\n");
+ fprintf(stderr," -w emit VRML .wrl file as well as CGATS .gam file\n");
+ fprintf(stderr," -n Don't add VRML axes or white/black point\n");
+ fprintf(stderr," -k Add markers for prim. & sec. \"cusp\" points\n");
+ fprintf(stderr," -f perc Filter by popularity, perc = percent to use\n");
+ fprintf(stderr," -i intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute (default), d = profile default\n");
+// fprintf(stderr," P = absolute perceptual, S = absolute saturation\n");
+ fprintf(stderr," -p oride l = Lab_PCS (default), j = %s Appearance Jab\n",icxcam_description(cam_default));
+ fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
+ fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
+ fprintf(stderr," -c viewcond set appearance mode and viewing conditions for %s,\n",icxcam_description(cam_default));
+ fprintf(stderr," either an enumerated choice, or a parameter:value changes\n");
+ for (i = 0; ; i++) {
+ icxViewCond vc;
+ if (xicc_enum_viewcond(NULL, &vc, i, NULL, 1, NULL) == -999)
+ break;
+
+ fprintf(stderr," %s\n",vc.desc);
+ }
+ fprintf(stderr," s:surround n = auto, a = average, m = dim, d = dark,\n");
+ fprintf(stderr," c = transparency (default average)\n");
+ fprintf(stderr," w:X:Y:Z Adapted white point as XYZ (default media white)\n");
+ fprintf(stderr," w:x:y Adapted white point as x, y\n");
+ fprintf(stderr," a:adaptation Adaptation luminance in cd.m^2 (default 50.0)\n");
+ fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
+ fprintf(stderr," l:scenewhite Scene white in cd.m^2 if surround = auto (default 250)\n");
+ fprintf(stderr," f:flare Flare light %% of image luminance (default 1)\n");
+ fprintf(stderr," f:X:Y:Z Flare color as XYZ (default media white)\n");
+ fprintf(stderr," f:x:y Flare color as x, y\n");
+ fprintf(stderr," -O outputfile Override the default output filename.\n");
+ exit(1);
+}
+
+#define GAMRES 10.0 /* Default surface resolution */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Conversion functions from direct binary 0..n^2-1 == 0.0 .. 1.0 range */
+/* to ICC luo input range. */
+/* It is assumed that the binary has been sign corrected to be */
+/* contiguous (ie CIELab). */
+
+/* TIFF 8 bit CIELAB to standard L*a*b* */
+/* Assume that a & b have been converted from signed to offset */
+static void cvt_CIELAB8_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = in[1] * 255.0 - 128.0;
+ out[2] = in[2] * 255.0 - 128.0;
+}
+
+/* TIFF 16 bit CIELAB to standard L*a*b* */
+/* Assume that a & b have been converted from signed to offset */
+static void cvt_CIELAB16_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = (in[1] - 32768.0/65535.0) * 256.0;
+ out[2] = (in[2] - 32768.0/65535.0) * 256.0;
+}
+
+/* TIFF 8 bit ICCLAB to standard L*a*b* */
+static void cvt_ICCLAB8_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = (in[1] * 255.0) - 128.0;
+ out[2] = (in[2] * 255.0) - 128.0;
+}
+
+/* TIFF 16 bit ICCLAB to standard L*a*b* */
+static void cvt_ICCLAB16_to_Lab(double *out, double *in) {
+ out[0] = in[0] * (100.0 * 65535.0)/65280.0;
+ out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0;
+ out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Convert a TIFF Photometric tag to an ICC colorspace. */
+/* return 0 if not possible or applicable. */
+icColorSpaceSignature
+TiffPhotometric2ColorSpaceSignature(
+void (**icvt)(double *out, double *in), /* Return read conversion function, NULL if none */
+int *smsk, /* Return signed handling mask, 0x0 if none */
+int pmtc, /* Input TIFF photometric */
+int bps, /* Input Bits per sample */
+int spp, /* Input Samples per pixel */
+int extra /* Extra Samples per pixel, if any */
+) {
+ if (icvt != NULL)
+ *icvt = NULL; /* Default return values */
+ if (smsk != NULL)
+ *smsk = 0x0;
+
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE: /* Subtractive Gray */
+ return icSigGrayData;
+
+ case PHOTOMETRIC_MINISBLACK: /* Additive Gray */
+ return icSigGrayData;
+
+ case PHOTOMETRIC_RGB:
+ return icSigRgbData;
+
+ case PHOTOMETRIC_PALETTE:
+ return 0x0;
+
+ case PHOTOMETRIC_MASK:
+ return 0x0;
+
+ case PHOTOMETRIC_SEPARATED:
+ /* Should look at the colorant names to figure out if this is CMY, CMYK */
+ /* Should at least return both Cmy/3 or Cmyk/4 ! */
+ switch(spp) {
+ case 2:
+ return icSig2colorData;
+ case 3:
+// return icSig3colorData;
+ return icSigCmyData;
+ case 4:
+// return icSig4colorData;
+ return icSigCmykData;
+ case 5:
+ return icSig5colorData;
+ case 6:
+ return icSig6colorData;
+ case 7:
+ return icSig7colorData;
+ case 8:
+ return icSig8colorData;
+ case 9:
+ return icSig9colorData;
+ case 10:
+ return icSig10colorData;
+ case 11:
+ return icSig11colorData;
+ case 12:
+ return icSig12colorData;
+ case 13:
+ return icSig13colorData;
+ case 14:
+ return icSig14colorData;
+ case 15:
+ return icSig15colorData;
+ }
+
+ case PHOTOMETRIC_YCBCR:
+ return icSigYCbCrData;
+
+ case PHOTOMETRIC_CIELAB:
+ if (bps == 8) {
+ if (icvt != NULL)
+ *icvt = cvt_CIELAB8_to_Lab;
+ } else {
+ if (icvt != NULL)
+ *icvt = cvt_CIELAB16_to_Lab;
+ }
+ *smsk = 0x6; /* Treat a & b as signed */
+ return icSigLabData;
+
+ case PHOTOMETRIC_ICCLAB:
+ if (bps == 8) {
+ if (icvt != NULL)
+ *icvt = cvt_ICCLAB8_to_Lab;
+ } else {
+ if (icvt != NULL)
+ *icvt = cvt_ICCLAB16_to_Lab;
+ }
+ return icSigLabData;
+
+ case PHOTOMETRIC_ITULAB:
+ return 0x0; /* Could add this with a conversion function */
+ /* but have to allow for variable ITU gamut */
+ /* (Tag 433, "Decode") */
+
+ case PHOTOMETRIC_LOGL:
+ return 0x0; /* Could add this with a conversion function */
+
+ case PHOTOMETRIC_LOGLUV:
+ return 0x0; /* Could add this with a conversion function */
+ }
+ return 0x0;
+}
+
+
+char *
+Photometric2str(
+int pmtc
+) {
+ static char buf[80];
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE:
+ return "Subtractive Gray";
+ case PHOTOMETRIC_MINISBLACK:
+ return "Additive Gray";
+ case PHOTOMETRIC_RGB:
+ return "RGB";
+ case PHOTOMETRIC_PALETTE:
+ return "Indexed";
+ case PHOTOMETRIC_MASK:
+ return "Transparency Mask";
+ case PHOTOMETRIC_SEPARATED:
+ return "Separated";
+ case PHOTOMETRIC_YCBCR:
+ return "YCbCr";
+ case PHOTOMETRIC_CIELAB:
+ return "CIELab";
+ case PHOTOMETRIC_ICCLAB:
+ return "ICCLab";
+ case PHOTOMETRIC_ITULAB:
+ return "ITULab";
+ case PHOTOMETRIC_LOGL:
+ return "CIELog2L";
+ case PHOTOMETRIC_LOGLUV:
+ return "CIELog2Luv";
+ }
+ sprintf(buf,"Unknown Photometric Tag %d",pmtc);
+ return buf;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* JPEG error information */
+typedef struct {
+ jmp_buf env; /* setjmp/longjmp environment */
+ char message[JMSG_LENGTH_MAX];
+} jpegerrorinfo;
+
+/* JPEG error handler */
+static void jpeg_error(j_common_ptr cinfo) {
+ jpegerrorinfo *p = (jpegerrorinfo *)cinfo->client_data;
+ (*cinfo->err->format_message) (cinfo, p->message);
+ longjmp(p->env, 1);
+}
+
+static char *
+JPEG_cspace2str(
+J_COLOR_SPACE cspace
+) {
+ static char buf[80];
+ switch (cspace) {
+ case JCS_UNKNOWN:
+ return "Unknown";
+ case JCS_GRAYSCALE:
+ return "Monochrome";
+ case JCS_RGB:
+ return "RGB";
+ case JCS_YCbCr:
+ return "YCbCr";
+ case JCS_CMYK:
+ return "CMYK";
+ case JCS_YCCK:
+ return "YCCK";
+ }
+ sprintf(buf,"Unknown JPEG colorspace %d",cspace);
+ return buf;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int ffa, lfa; /* First, last input file argument */
+ char prof_name[MAXNAMEL+1] = { '\000' }; /* ICC profile name, "" if none */
+ char in_name[MAXNAMEL+1]; /* TIFF input file */
+ char *xl = NULL, out_name[MAXNAMEL+4+1] = { '\000' }; /* VRML output file */
+ int verb = 0;
+ int vrml = 0;
+ int doaxes = 1;
+ int docusps = 0;
+ int filter = 0;
+ double filtperc = 100.0;
+ int rv = 0;
+
+ icc *icco = NULL;
+ xicc *xicco = NULL;
+ icxcam *cam = NULL; /* Separate CAM used for Lab TIFF files */
+ icxViewCond vc; /* Viewing Condition for CIECAM */
+ int vc_e = -1; /* Enumerated viewing condition */
+ int vc_s = -1; /* Surround override */
+ double vc_wXYZ[3] = {-1.0, -1.0, -1.0}; /* Adapted white override in XYZ */
+ double vc_wxy[2] = {-1.0, -1.0}; /* Adapted white override in x,y */
+ double vc_a = -1.0; /* Adapted luminance */
+ double vc_b = -1.0; /* Background % overid */
+ double vc_l = -1.0; /* Scene luminance override */
+ double vc_f = -1.0; /* Flare % overid */
+ double vc_fXYZ[3] = {-1.0, -1.0, -1.0}; /* Flare color override in XYZ */
+ double vc_fxy[2] = {-1.0, -1.0}; /* Flare color override in x,y */
+ icxLuBase *luo = NULL; /* Generic lookup object */
+ icColorSpaceSignature ins = icSigLabData, outs; /* Type of input and output spaces */
+ int inn, outn; /* Number of components */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ icmLookupFunc func = icmFwd; /* Must be */
+ icRenderingIntent intent = -1; /* Default */
+ icColorSpaceSignature pcsor = icSigLabData; /* Default */
+ icmLookupOrder order = icmLuOrdNorm; /* Default */
+
+ /* TIFF */
+ TIFFErrorHandler olderrh, oldwarnh;
+ TIFFErrorHandlerExt olderrhx, oldwarnhx;
+ TIFF *rh = NULL;
+ int x, y, width, height; /* Size of image */
+ uint16 samplesperpixel, bitspersample;
+ uint16 pconfig, photometric, pmtc;
+ tdata_t *inbuf;
+ int inbpix; /* Number of pixels in jpeg in buf */
+ void (*cvt)(double *out, double *in) = NULL; /* TIFF conversion function, NULL if none */
+ icColorSpaceSignature tcs; /* TIFF colorspace */
+ uint16 extrasamples; /* Extra "alpha" samples */
+ uint16 *extrainfo; /* Info about extra samples */
+ int sign_mask; /* Handling of encoding sign */
+
+ /* JPEG */
+ jpegerrorinfo jpeg_rerr;
+ FILE *rf = NULL;
+ struct jpeg_decompress_struct rj;
+ struct jpeg_error_mgr jerr;
+ int iinv; /* Invert the input */
+
+ double gamres = GAMRES; /* Surface resolution */
+ gamut *gam;
+
+ double apcsmin[3], apcsmax[3]; /* Actual PCS range */
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ /* Intent */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'd':
+ intent = icmDefaultIntent;
+ break;
+ case 'a':
+ intent = icAbsoluteColorimetric;
+ break;
+ case 'p':
+ intent = icPerceptual;
+ break;
+ case 'r':
+ intent = icRelativeColorimetric;
+ break;
+ case 's':
+ intent = icSaturation;
+ break;
+ /* Argyll special intents to check spaces underlying */
+ /* icxPerceptualAppearance & icxSaturationAppearance */
+ case 'P':
+ intent = icmAbsolutePerceptual;
+ break;
+ case 'S':
+ intent = icmAbsoluteSaturation;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Search order */
+ else if (argv[fa][1] == 'o') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'n':
+ case 'N':
+ order = icmLuOrdNorm;
+ break;
+ case 'r':
+ case 'R':
+ order = icmLuOrdRev;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* PCS override */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'l':
+ pcsor = icSigLabData;
+ break;
+ case 'j':
+ pcsor = icxSigJabData;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Viewing conditions */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage();
+
+ /* Switch to Jab automatically */
+ pcsor = icxSigJabData;
+
+ /* Set the viewing conditions */
+ if (na[1] != ':') {
+ if ((vc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
+ usage();
+ } else if (na[0] == 's' || na[0] == 'S') {
+ if (na[1] != ':')
+ usage();
+ if (na[2] == 'n' || na[2] == 'N') {
+ vc_s = vc_none; /* Automatic */
+ } else if (na[2] == 'a' || na[2] == 'A') {
+ vc_s = vc_average;
+ } else if (na[2] == 'm' || na[2] == 'M') {
+ vc_s = vc_dim;
+ } else if (na[2] == 'd' || na[2] == 'D') {
+ vc_s = vc_dark;
+ } else if (na[2] == 'c' || na[2] == 'C') {
+ vc_s = vc_cut_sheet;
+ } else
+ usage();
+ } else if (na[0] == 'w' || na[0] == 'W') {
+ double x, y, z;
+ if (sscanf(na+1,":%lf:%lf:%lf",&x,&y,&z) == 3) {
+ vc_wXYZ[0] = x; vc_wXYZ[1] = y; vc_wXYZ[2] = z;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc_wxy[0] = x; vc_wxy[1] = y;
+ } else
+ usage();
+ } else if (na[0] == 'a' || na[0] == 'A') {
+ if (na[1] != ':')
+ usage();
+ vc_a = atof(na+2);
+ } else if (na[0] == 'b' || na[0] == 'B') {
+ if (na[1] != ':')
+ usage();
+ vc_b = atof(na+2);
+ } else if (na[0] == 'l' || na[0] == 'L') {
+ if (na[1] != ':')
+ usage();
+ vc_l = atof(na+2);
+ } else if (na[0] == 'f' || na[0] == 'F') {
+ 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;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc_fxy[0] = x; vc_fxy[1] = y;
+ } else if (sscanf(na+1,":%lf",&x) == 1) {
+ vc_f = x;
+ } else
+ usage();
+ } else
+ usage();
+ }
+
+ /* VRML output */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ vrml = 1;
+ }
+ /* No axis output */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ doaxes = 0;
+ }
+ /* Do cusp markers */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ docusps = 1;
+ }
+ /* Surface Detail */
+ else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ fa = nfa;
+ if (na == NULL) usage();
+ gamres = atof(na);
+ }
+ /* Filtering */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage();
+ filtperc = atof(na);
+ if (filtperc < 0.0 || filtperc> 100.0)
+ usage();
+ filter = 1;
+ }
+
+ /* Output file name */
+ else if (argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ strncpy(out_name,na,MAXNAMEL); out_name[MAXNAMEL] = '\000';
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ if (fa < (argc-1))
+ strncpy(prof_name,argv[fa++],MAXNAMEL); prof_name[MAXNAMEL] = '\000';
+
+ for (ffa = fa; fa < argc; fa++)
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ lfa = fa-1;
+ if (verb)
+ printf("There are %d raster files to process\n",lfa - ffa + 1);
+
+ if (out_name[0] == '\000') {
+ strncpy(out_name,argv[lfa],MAXNAMEL); out_name[MAXNAMEL] = '\000';
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".gam");
+ } else {
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ }
+
+ if (verb)
+ printf("Gamut output files is '%s'\n",out_name);
+
+ if (intent == -1) {
+ if (pcsor == icxSigJabData)
+ intent = icRelativeColorimetric; /* Default to icxAppearance */
+ else
+ intent = icAbsoluteColorimetric; /* Default to icAbsoluteColorimetric */
+ }
+
+ /* - - - - - - - - - - - - - - - - */
+ /* If we were provided an ICC profile to use */
+ if (prof_name[0] != '\000') {
+
+ /* Open up the profile or TIFF embedded profile for reading */
+ if ((icco = read_embedded_icc(prof_name)) == NULL)
+ error ("Can't open profile in file '%s'",prof_name);
+
+ if (verb) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ icco->header->dump(icco->header, op, 1);
+ op->del(op);
+ }
+
+ /* Check that the profile is appropriate */
+ if (icco->header->deviceClass != icSigInputClass
+ && icco->header->deviceClass != icSigDisplayClass
+ && icco->header->deviceClass != icSigOutputClass
+ && icco->header->deviceClass != icSigColorSpaceClass)
+ error("Profile type isn't device or colorspace");
+
+ /* Wrap with an expanded icc */
+ if ((xicco = new_xicc(icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ /* Setup the default viewing conditions */
+ if (xicc_enum_viewcond(xicco, &vc, -1, NULL, 0, NULL) == -999)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ if (vc_e != -1)
+ if (xicc_enum_viewcond(xicco, &vc, vc_e, NULL, 0, NULL) == -999)
+ error ("%d, %s",xicco->errc, xicco->err);
+ if (vc_s >= 0)
+ vc.Ev = vc_s;
+ if (vc_wXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Wxyz[0] = vc_wXYZ[0]/vc_wXYZ[1] * vc.Wxyz[1];
+ vc.Wxyz[2] = vc_wXYZ[2]/vc_wXYZ[1] * vc.Wxyz[1];
+ }
+ if (vc_wxy[0] >= 0.0) {
+ double x = vc_wxy[0];
+ double y = vc_wxy[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
+ double z = 1.0 - x - y;
+ vc.Wxyz[0] = x/y * vc.Wxyz[1];
+ vc.Wxyz[2] = z/y * vc.Wxyz[1];
+ }
+ if (vc_a >= 0.0)
+ vc.La = vc_a;
+ if (vc_b >= 0.0)
+ vc.Yb = vc_b/100.0;
+ if (vc_l >= 0.0)
+ vc.Lv = vc_l;
+ if (vc_f >= 0.0)
+ vc.Yf = vc_f/100.0;
+ if (vc_fXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Fxyz[0] = vc_fXYZ[0]/vc_fXYZ[1] * vc.Fxyz[1];
+ vc.Fxyz[2] = vc_fXYZ[2]/vc_fXYZ[1] * vc.Fxyz[1];
+ }
+ if (vc_fxy[0] >= 0.0) {
+ double x = vc_fxy[0];
+ double y = vc_fxy[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];
+ }
+
+ /* Get a expanded color conversion object */
+ if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST
+#ifdef NOCAMGAM_CLIP
+ | ICX_CAM_NOGAMCLIP
+#endif
+ , func, intent, pcsor, order, &vc, NULL)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ luo->spaces(luo, &ins, &inn, &outs, &outn, &alg, NULL, NULL, NULL);
+
+ /* Else if the image is in Lab space, and we want Jab */
+ } else if (pcsor == icxSigJabData) {
+ double wp[3]; /* D50 white point */
+
+ wp[0] = icmD50.X;
+ wp[1] = icmD50.Y;
+ wp[2] = icmD50.Z;
+
+ /* Setup the default viewing conditions */
+ if (xicc_enum_viewcond(NULL, &vc, -1, NULL, 0, wp) == -999)
+ error("Failed to locate a default viewing condition");
+
+ if (vc_e != -1)
+ if (xicc_enum_viewcond(NULL, &vc, vc_e, NULL, 0, wp) == -999)
+ error("Failed to enumerate viewing condition %d",vc_e);
+ if (vc_s >= 0)
+ vc.Ev = vc_s;
+ if (vc_wXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Wxyz[0] = vc_wXYZ[0]/vc_wXYZ[1] * vc.Wxyz[1];
+ vc.Wxyz[2] = vc_wXYZ[2]/vc_wXYZ[1] * vc.Wxyz[1];
+ }
+ if (vc_wxy[0] >= 0.0) {
+ double x = vc_wxy[0];
+ double y = vc_wxy[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
+ double z = 1.0 - x - y;
+ vc.Wxyz[0] = x/y * vc.Wxyz[1];
+ vc.Wxyz[2] = z/y * vc.Wxyz[1];
+ }
+ if (vc_a >= 0.0)
+ vc.La = vc_a;
+ if (vc_b >= 0.0)
+ vc.Yb = vc_b/100.0;
+ if (vc_f >= 0.0)
+ vc.Yf = vc_f/100.0;
+ if (vc_fXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Fxyz[0] = vc_fXYZ[0]/vc_fXYZ[1] * vc.Fxyz[1];
+ vc.Fxyz[2] = vc_fXYZ[2]/vc_fXYZ[1] * vc.Fxyz[1];
+ }
+ if (vc_fxy[0] >= 0.0) {
+ double x = vc_fxy[0];
+ double y = vc_fxy[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];
+ }
+
+ if ((cam = new_icxcam(cam_default)) == NULL)
+ error("new_icxcam failed");
+
+ cam->set_view(cam, vc.Ev, vc.Wxyz, vc.La, vc.Yb, vc.Lv, vc.Yf, vc.Fxyz,
+ XICC_USE_HK);
+ }
+
+ /* Establish the PCS range if we are filtering */
+ if (filter) {
+ double pcsmin[3], pcsmax[3]; /* PCS range for filter stats array */
+
+ if (luo) {
+ gamut *csgam;
+
+ if ((csgam = luo->get_gamut(luo, 20.0)) == NULL)
+ error("Getting the gamut of the source colorspace failed");
+
+ csgam->getrange(csgam, pcsmin, pcsmax);
+ csgam->del(csgam);
+ } else {
+ pcsmin[0] = -10.0;
+ pcsmax[0] = 110.0;
+ pcsmin[1] = -138.0;
+ pcsmax[1] = 138.0;
+ pcsmin[2] = -138.0;
+ pcsmax[2] = 138.0;
+
+#ifdef NEVER /* Does this make any sense ?? */
+ if (cam) {
+ icmLab2XYZ(&icmD50, pcsmin, pcsmin);
+ cam->XYZ_to_cam(cam, pcsmin, pcsmin);
+
+ icmLab2XYZ(&icmD50, pcsmax, pcsmax);
+ cam->XYZ_to_cam(cam, pcsmax, pcsmax);
+ }
+#endif
+ }
+
+ if (verb)
+ printf("PCS range = %f..%f, %f..%f. %f..%f\n\n", pcsmin[0], pcsmax[0], pcsmin[1], pcsmax[1], pcsmin[2], pcsmax[2]);
+
+ /* Allocate and initialize the filter */
+ set_fminmax(pcsmin, pcsmax);
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Creat a raster gamut surface */
+ gam = new_gamut(gamres, pcsor == icxSigJabData, 1);
+
+ apcsmin[0] = apcsmin[1] = apcsmin[2] = 1e6;
+ apcsmax[0] = apcsmax[1] = apcsmax[2] = -1e6;
+
+ /* Process all the tiff files */
+ for (fa = ffa; fa <= lfa; fa++) {
+
+ /* - - - - - - - - - - - - - - - */
+ /* Open up input tiff/jpeg file ready for reading */
+ /* Got arguments, so setup to process the file */
+ strncpy(in_name,argv[fa],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ olderrh = TIFFSetErrorHandler(NULL);
+ oldwarnh = TIFFSetWarningHandler(NULL);
+ olderrhx = TIFFSetErrorHandlerExt(NULL);
+ oldwarnhx = TIFFSetWarningHandlerExt(NULL);
+
+ if ((rh = TIFFOpen(in_name, "r")) != NULL) {
+ TIFFSetErrorHandler(olderrh);
+ TIFFSetWarningHandler(oldwarnh);
+ TIFFSetErrorHandlerExt(olderrhx);
+ TIFFSetWarningHandlerExt(oldwarnhx);
+
+ TIFFGetField(rh, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);
+
+ TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8 && bitspersample != 16)
+ error("TIFF Input file must be 8 or 16 bits/channel");
+
+ TIFFGetFieldDefaulted(rh, TIFFTAG_EXTRASAMPLES, &extrasamples, &extrainfo);
+ TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &photometric);
+
+ if (luo != NULL) {
+ if (inn != (samplesperpixel-extrasamples))
+ error("TIFF Input file has %d input chanels and is mismatched to colorspace '%s'",
+ samplesperpixel, icm2str(icmColorSpaceSignature, ins));
+ }
+
+ if ((tcs = TiffPhotometric2ColorSpaceSignature(&cvt, &sign_mask, photometric,
+ bitspersample, samplesperpixel, extrasamples)) == 0)
+ error("Can't handle TIFF file photometric %s", Photometric2str(photometric));
+
+ if (tcs != ins) {
+ if (luo != NULL)
+ error("TIFF photometric '%s' doesn't match ICC input colorspace '%s' !",
+ Photometric2str(photometric), icm2str(icmColorSpaceSignature,ins));
+ else
+ error("No profile provided and TIFF photometric '%s' isn't Lab !",
+ Photometric2str(photometric));
+ }
+
+ TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
+ if (pconfig != PLANARCONFIG_CONTIG)
+ error("TIFF Input file must be planar");
+
+ if (verb) {
+ printf("Input TIFF file '%s'\n",in_name);
+ printf("TIFF file photometric is %s\n",Photometric2str(photometric));
+ printf("TIFF file colorspace is %s\n",icm2str(icmColorSpaceSignature,tcs));
+ printf("File size %d x %d pixels\n",width,height);
+ printf("\n");
+ }
+
+ } else {
+ TIFFSetErrorHandler(olderrh);
+ TIFFSetWarningHandler(oldwarnh);
+ TIFFSetErrorHandlerExt(olderrhx);
+ TIFFSetWarningHandlerExt(oldwarnhx);
+
+ /* We cope with the horrible ijg jpeg library error handling */
+ /* by using a setjmp/longjmp. */
+ jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+ if (setjmp(jpeg_rerr.env)) {
+ jpeg_destroy_decompress(&rj);
+ fclose(rf);
+ error("Unable to read JPEG file '%s'\n",in_name);
+ }
+
+ rj.err = &jerr;
+ rj.client_data = &jpeg_rerr;
+ jpeg_create_decompress(&rj);
+
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((rf = fopen(in_name,"rb")) == NULL)
+#else
+ if ((rf = fopen(in_name,"r")) == NULL)
+#endif
+ {
+ jpeg_destroy_decompress(&rj);
+ error("Unable to open input file '%s'\n",in_name);
+ }
+
+ jpeg_stdio_src(&rj, rf);
+ jpeg_read_header(&rj, TRUE); /* we'll longjmp on error */
+
+ bitspersample = rj.data_precision;
+ if (bitspersample != 8 && bitspersample != 16) {
+ error("JPEG Input file must be 8 or 16 bit/channel");
+ }
+
+ /* No extra samples */
+ extrasamples = 0;
+ iinv = 0;
+
+ switch (rj.jpeg_color_space) {
+ case JCS_GRAYSCALE:
+ rj.out_color_space = JCS_GRAYSCALE;
+ tcs = icSigGrayData;
+ samplesperpixel = 1;
+ break;
+
+ case JCS_YCbCr: /* get libjpg to convert to RGB */
+ rj.out_color_space = JCS_RGB;
+ tcs = icSigRgbData;
+ samplesperpixel = 3;
+ break;
+
+ case JCS_RGB:
+ rj.out_color_space = JCS_RGB;
+ tcs = icSigRgbData;
+ samplesperpixel = 3;
+ break;
+
+ case JCS_YCCK: /* libjpg to convert to CMYK */
+ rj.out_color_space = JCS_CMYK;
+ tcs = icSigCmykData;
+ samplesperpixel = 4;
+ if (rj.saw_Adobe_marker)
+ iinv = 1;
+ break;
+
+ case JCS_CMYK:
+ rj.out_color_space = JCS_CMYK;
+ tcs = icSigCmykData;
+ samplesperpixel = 4;
+ if (rj.saw_Adobe_marker) /* Adobe inverts CMYK */
+ iinv = 1;
+ break;
+
+ default:
+ error("Can't handle JPEG file '%s' colorspace 0x%x", in_name, rj.jpeg_color_space);
+ }
+
+ if (luo != NULL) {
+ if (inn != samplesperpixel)
+ error ("JPEG Input file has %d input chanels and is mismatched to colorspace '%s'",
+ samplesperpixel, icm2str(icmColorSpaceSignature, ins));
+ }
+
+ if (tcs != ins) {
+ if (luo != NULL)
+ error("JPEG colorspace '%s' doesn't match ICC input colorspace '%s' !",
+ icm2str(icmColorSpaceSignature, tcs), icm2str(icmColorSpaceSignature,ins));
+ else
+ error("No profile provided and JPEG colorspace '%s' isn't Lab !",
+ icm2str(icmColorSpaceSignature, tcs));
+ }
+ jpeg_calc_output_dimensions(&rj);
+ width = rj.output_width;
+ height = rj.output_height;
+
+ if (verb) {
+ printf("Input JPEG file '%s'\n",in_name);
+ printf("JPEG file original colorspace is %s\n",JPEG_cspace2str(rj.jpeg_color_space));
+ printf("JPEG file colorspace is %s\n",icm2str(icmColorSpaceSignature,tcs));
+ printf("File size %d x %d pixels\n",width,height);
+ printf("\n");
+ }
+ jpeg_start_decompress(&rj);
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Process colors to translate */
+ /* (Should fix this to process a group of lines at a time ?) */
+
+ if (rh != NULL)
+ inbuf = _TIFFmalloc(TIFFScanlineSize(rh));
+ else {
+ inbpix = rj.output_width * rj.num_components;
+ if ((inbuf = (tdata_t *)malloc(inbpix)) == NULL)
+ error("Malloc failed on input line buffer");
+
+ if (setjmp(jpeg_rerr.env)) {
+ /* Something went wrong with reading the file */
+ jpeg_destroy_decompress(&rj);
+ error("failed to read JPEG line of file '%s' [%s]",in_name, jpeg_rerr.message);
+ }
+ }
+
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (rh) {
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+ } else {
+ jpeg_read_scanlines(&rj, (JSAMPARRAY)&inbuf, 1);
+ if (iinv) {
+ unsigned char *cp, *ep = (unsigned char *)inbuf + inbpix;
+ for (cp = (unsigned char *)inbuf; cp < ep; cp++)
+ *cp = ~*cp;
+ }
+ }
+
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+ if (bitspersample == 8) {
+ for (i = 0; i < samplesperpixel; i++) {
+ int v = ((unsigned char *)inbuf)[x * samplesperpixel + i];
+ if (sign_mask & (1 << i)) /* Treat input as signed */
+ v = (v & 0x80) ? v - 0x80 : v + 0x80;
+ in[i] = v/255.0;
+ }
+ } else {
+ for (i = 0; i < samplesperpixel; i++) {
+ int v = ((unsigned short *)inbuf)[x * samplesperpixel + i];
+ if (sign_mask & (1 << i)) /* Treat input as signed */
+ v = (v & 0x8000) ? v - 0x8000 : v + 0x8000;
+ in[i] = v/65535.0;
+ }
+ }
+ if (cvt != NULL) { /* Undo TIFF encoding */
+ cvt(in, in);
+ }
+ /* ICC profile to convert RGB to Lab or Jab */
+ if (luo != NULL) {
+//printf("~1 RGB in value = %f %f %f\n",in[0],in[1],in[2]);
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+//printf("~1 after luo = %f %f %f\n",out[0],out[1],out[2]);
+
+ if (outs == icSigXYZData) { /* Convert to Lab */
+ icmXYZ2Lab(&icco->header->illuminant, out, out);
+//printf("~1 after XYZ2Lab = %f %f %f\n",out[0],out[1],out[2]);
+ }
+ /* Lab TIFF - may need to convert to Jab */
+ } else if (cam != NULL) {
+//printf("~1 Lab in value = %f %f %f\n",in[0],in[1],in[2]);
+ icmLab2XYZ(&icmD50, out, in);
+//printf("~1 XYZ = %f %f %f\n",out[0],out[1],out[2]);
+ cam->XYZ_to_cam(cam, out, out);
+//printf("~1 Jab = %f %f %f\n",out[0],out[1],out[2]);
+
+ } else {
+//printf("~1 Lab value = %f %f %f\n",in[0],in[1],in[2]);
+ for (i = 0; i < samplesperpixel; i++)
+ out[i] = in[i];
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (out[i] < apcsmin[i])
+ apcsmin[i] = out[i];
+ if (out[i] > apcsmax[i])
+ apcsmax[i] = out[i];
+ }
+ if (filter)
+ add_fpixel(out);
+ else
+ gam->expand(gam, out);
+ }
+ }
+
+ /* Release buffers and close files */
+ if (rh != NULL) {
+ if (inbuf != NULL)
+ _TIFFfree(inbuf);
+ TIFFClose(rh); /* Close Input file */
+ } else {
+ jpeg_finish_decompress(&rj);
+ jpeg_destroy_decompress(&rj);
+ if (inbuf != NULL)
+ free(inbuf);
+ if (fclose(rf))
+ error("Error closing JPEG input file '%s'\n",in_name);
+ }
+
+ /* If filtering, flush filtered points to the gamut */
+ if (filter) {
+ flush_filter(verb, gam, filtperc);
+ }
+ }
+
+ if (verb)
+ printf("Actual PCS range = %f..%f, %f..%f. %f..%f\n\n", apcsmin[0], apcsmax[0], apcsmin[1], apcsmax[1], apcsmin[2], apcsmax[2]);
+
+ if (filter)
+ del_filter();
+
+ /* Get White and Black points from the profile, and set them in the gamut. */
+ if (luo != NULL) {
+ double wp[3], bp[3], kp[3];
+
+ luo->efv_wh_bk_points(luo, wp, bp,kp);
+ gam->setwb(gam, wp, bp, kp);
+ } else {
+ double wp[3] = { 100.0, 0.0, 0.0 };
+ double bp[3] = { 0.0, 0.0, 0.0 };
+ gam->setwb(gam, wp, bp, bp);
+ }
+
+ /* Done with lookup object */
+ if (luo != NULL) {
+ luo->del(luo);
+ xicco->del(xicco); /* Expansion wrapper */
+ icco->del(icco); /* Icc */
+ }
+ if (cam != NULL) {
+ cam->del(cam);
+ }
+
+ if (verb)
+ printf("Output Gamut file '%s'\n",out_name);
+
+ /* Create the VRML file */
+ if (gam->write_gam(gam,out_name))
+ error ("write gamut failed on '%s'",out_name);
+
+ if (vrml) {
+
+ strcpy(xl,".wrl");
+ printf("Output vrml file '%s'\n",out_name);
+ if (gam->write_vrml(gam,out_name, doaxes, docusps))
+ error ("write vrml failed on '%s'",out_name);
+ }
+
+ if (verb) {
+ printf("Total volume of gamut is %f cubic colorspace units\n",gam->volume(gam));
+ }
+ gam->del(gam);
+
+ return 0;
+}
+
+
+/* ============================================================================= */
+/* A pixel value filter module. We quantize the pixel values and keep statistics */
+/* on them, so as to filter out low frequency colors. */
+
+#define FILTBITS 6 /* Total = 2 ^ (3 * FILTBITS) entries = 33Mbytes*/
+#define FILTSIZE (1 << FILTBITS)
+
+/* A filtered cell entry */
+typedef struct {
+ int count; /* Count of pixels that fall in this cell */
+ float pcs[3]; /* Most extreme PCS value that fell in this cell */
+} fent;
+
+struct _ffilter {
+ double min[3], max[3]; /* PCS range */
+
+ fent cells[FILTSIZE][FILTSIZE][FILTSIZE]; /* Quantized pixels stats */
+ fent *scells[FILTSIZE * FILTSIZE * FILTSIZE]; /* Sorted order */
+
+}; typedef struct _ffilter ffilter;
+
+
+
+/* Use a global object */
+ffilter *ff = NULL;
+
+/* Set the min and max values and init the filter */
+void set_fminmax(double min[3], double max[3]) {
+
+ if (ff == NULL) {
+ if ((ff = (ffilter *) calloc(1,sizeof(ffilter))) == NULL)
+ error("ffilter: calloc failed");
+ }
+
+ ff->min[0] = min[0];
+ ff->min[1] = min[1];
+ ff->min[2] = min[2];
+ ff->max[0] = max[0];
+ ff->max[1] = max[1];
+ ff->max[2] = max[2];
+}
+
+/* Add another pixel to the filter */
+void add_fpixel(double val[3]) {
+ int j;
+ int qv[3];
+ fent *fe;
+ double cent[3] = { 50.0, 0.0, 0.0 }; /* Assumed center */
+ double tt, cdist, ndist;
+
+ if (ff == NULL)
+ error("ffilter not initialized");
+
+ /* Quantize the values */
+ for (j = 0; j < 3; j++) {
+ double vv;
+
+ vv = (val[j] - ff->min[j])/(ff->max[j] - ff->min[j]);
+ qv[j] = (int)(vv * (FILTSIZE - 1) + 0.5);
+ if (qv[j] < 0)
+ qv[j] = 0;
+ else if (qv[j] >= FILTSIZE)
+ qv[j] = FILTSIZE-1;
+ }
+
+//printf("~1 color %f %f %f -> Cell %d %d %d\n", val[0], val[1], val[2], qv[0], qv[1], qv[2]);
+
+ /* Find the appropriate cell */
+ fe = &ff->cells[qv[0]][qv[1]][qv[2]];
+
+ /* See if this is the new most distant value in this cell */
+ for (cdist = ndist = 0.0, j = 0; j < 3; j++) {
+ tt = fe->pcs[j] - cent[j];
+ cdist += tt * tt;
+ tt = val[j] - cent[j];
+ ndist += tt * tt;
+ }
+ if (fe->count == 0 || ndist > cdist) {
+ fe->pcs[0] = val[0];
+ fe->pcs[1] = val[1];
+ fe->pcs[2] = val[2];
+//printf("Updated pcs to %f %f %f\n", val[0],val[1],val[2]);
+ }
+ fe->count++;
+//printf("Cell count = %d\n",fe->count);
+}
+
+/* Flush the filter contents to the gamut, and then reset it */
+void flush_filter(int verb, gamut *gam, double filtperc) {
+ int i, j;
+ int totcells = FILTSIZE * FILTSIZE * FILTSIZE;
+ int used, hasone;
+ double cuml, avgcnt;
+
+ if (ff == NULL)
+ error("ffilter not initialized");
+
+ /* Sort the cells by popularity from most to least */
+ for (used = hasone = avgcnt = i = 0; i < totcells; i++) {
+ ff->scells[i] = (fent *)ff->cells + i;
+ if (ff->scells[i]->count > 0) {
+ used++;
+ if (ff->scells[i]->count == 1)
+ hasone++;
+ avgcnt += ff->scells[i]->count;
+ }
+ }
+ avgcnt /= used;
+
+#define HEAP_COMPARE(A,B) A->count > B->count
+ HEAPSORT(fent *,ff->scells, totcells)
+
+#ifdef DEBUG
+ for (i = 0; i < totcells; i++) {
+ if (ff->scells[i]->count > 0) {
+ printf("Cell %d at %f %f %f count %d\n",
+ i,
+ ff->scells[i]->pcs[0],
+ ff->scells[i]->pcs[1],
+ ff->scells[i]->pcs[2],
+ ff->scells[i]->count);
+ }
+ }
+#endif
+ if (verb) {
+ printf("Total of %d cells out of %d were hit (%.1f%%)\n",used,totcells,used * 100.0/totcells);
+ printf("%.1f%% have a count of 1\n",hasone * 100.0/used);
+ printf("Average cell count = %f\n",avgcnt);
+ printf("\n");
+ }
+
+ /* Add the populated cells in order */
+ filtperc /= 100.0;
+ for (cuml = 0.0, i = j = 0; cuml < filtperc && i < totcells; i++) {
+
+ if (ff->scells[i]->count > 0) {
+ double val[3];
+ val[0] = ff->scells[i]->pcs[0]; /* float -> double */
+ val[1] = ff->scells[i]->pcs[1];
+ val[2] = ff->scells[i]->pcs[2];
+#ifdef DEBUG
+ printf("Adding %d: %f %f %f count %d to gamut\n", i, val[0], val[1], val[2],ff->scells[i]->count);
+#endif
+ gam->expand(gam, val);
+ j++;
+ cuml = j/(used-1.0);
+ }
+
+ }
+
+ /* Reset it to empty */
+ {
+ double min[3], max[3];
+
+ for (j = 0; j < 3; j++) {
+ min[j] = ff->min[j];
+ max[j] = ff->max[j];
+ }
+ memset(ff, 0, sizeof(ffilter));
+ for (j = 0; j < 3; j++) {
+ ff->min[j] = min[j];
+ ff->max[j] = max[j];
+ }
+ }
+}
+
+/* Free up the filter structure */
+void del_filter() {
+
+ free(ff);
+}
diff --git a/xicc/tiffgmts.c b/xicc/tiffgmts.c
new file mode 100644
index 0000000..9d21d36
--- /dev/null
+++ b/xicc/tiffgmts.c
@@ -0,0 +1,1187 @@
+
+/*
+ * Create a gamut mapping test set from a TIFF file.
+ *
+ * Author: Graeme W. Gill
+ * Date: 08/10/14
+ * Version: 1.00
+ *
+ * Copyright 2000, 2008 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.
+ *
+ * Derived from tiffgamut.c
+ *
+ * This program creates a locus of test values that spans the
+ * volume of colors ocupied by the pixels of the TIFF file.
+ * The direction that spans the greatest distance is
+ * turned into a line of source test points, that can
+ * then be used by gammap to illustrate how the gamut mapping
+ * alters the locus.
+ */
+
+/*
+ * TTBD:
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "tiffio.h"
+#include "icc.h"
+#include "gamut.h"
+#include "xicc.h"
+#include "vrml.h"
+#include "sort.h"
+
+#define DE_SPACE 3 /* Delta E of spacing for output points */
+#undef DEBUG_PLOT
+
+void usage(void) {
+ int i;
+ fprintf(stderr,"Create locus of test points that spans the range of colors a TIFF, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: tiffgmts [-v level] [profile.icm | embedded.tif] infile.tif\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -w emit VRML .wrl file as well as CGATS .ts file\n");
+ fprintf(stderr," -n Don't add VRML axes or white/black point\n");
+ fprintf(stderr," -i intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute (default), d = profile default\n");
+// fprintf(stderr," P = absolute perceptual, S = absolute saturation\n");
+ fprintf(stderr," -p oride l = Lab_PCS (default), j = %s Appearance Jab\n",icxcam_description(cam_default),icxcam_description(cam_default));
+ fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
+ fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
+ fprintf(stderr," -c viewcond set appearance mode and viewing conditions for %s,\n",icxcam_description(cam_default));
+ fprintf(stderr," either an enumerated choice, or a parameter:value changes\n");
+ for (i = 0; ; i++) {
+ icxViewCond vc;
+ if (xicc_enum_viewcond(NULL, &vc, i, NULL, 1, NULL) == -999)
+ break;
+
+ fprintf(stderr," %s\n",vc.desc);
+ }
+ fprintf(stderr," s:surround a = average, m = dim, d = dark,\n");
+ fprintf(stderr," c = transparency (default average)\n");
+ fprintf(stderr," w:X:Y:Z Adapted white point as XYZ (default media white)\n");
+ fprintf(stderr," w:x:y Adapted white point as x, y\n");
+ fprintf(stderr," a:adaptation Adaptation luminance in cd.m^2 (default 50.0)\n");
+ fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
+ fprintf(stderr," f:flare Flare light %% of image luminance (default 1)\n");
+ fprintf(stderr," f:X:Y:Z Flare color as XYZ (default media white)\n");
+ fprintf(stderr," f:x:y Flare color as x, y\n");
+ fprintf(stderr," -V L,a,b Overide normal vector direction for span\n");
+ fprintf(stderr," -O outputfile Override the default output filename (locus.ts)\n");
+ fprintf(stderr," infile.tif File to create test value from\n");
+ exit(1);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Conversion functions from direct binary 0..n^2-1 == 0.0 .. 1.0 range */
+/* to ICC luo input range. */
+/* It is assumed that the binary has been sign corrected to be */
+/* contiguous (ie CIELab). */
+
+/* TIFF 8 bit CIELAB to standard L*a*b* */
+/* Assume that a & b have been converted from signed to offset */
+static void cvt_CIELAB8_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = in[1] * 255.0 - 128.0;
+ out[2] = in[2] * 255.0 - 128.0;
+}
+
+/* TIFF 16 bit CIELAB to standard L*a*b* */
+/* Assume that a & b have been converted from signed to offset */
+static void cvt_CIELAB16_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = (in[1] - 32768.0/65535.0) * 256.0;
+ out[2] = (in[2] - 32768.0/65535.0) * 256.0;
+}
+
+/* TIFF 8 bit ICCLAB to standard L*a*b* */
+static void cvt_ICCLAB8_to_Lab(double *out, double *in) {
+ out[0] = in[0] * 100.0;
+ out[1] = (in[1] * 255.0) - 128.0;
+ out[2] = (in[2] * 255.0) - 128.0;
+}
+
+/* TIFF 16 bit ICCLAB to standard L*a*b* */
+static void cvt_ICCLAB16_to_Lab(double *out, double *in) {
+ out[0] = in[0] * (100.0 * 65535.0)/65280.0;
+ out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0;
+ out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Convert a TIFF Photometric tag to an ICC colorspace. */
+/* return 0 if not possible or applicable. */
+icColorSpaceSignature
+TiffPhotometric2ColorSpaceSignature(
+void (**icvt)(double *out, double *in), /* Return read conversion function, NULL if none */
+int *smsk, /* Return signed handling mask, 0x0 if none */
+int pmtc, /* Input TIFF photometric */
+int bps, /* Input Bits per sample */
+int spp, /* Input Samples per pixel */
+int extra /* Extra Samples per pixel, if any */
+) {
+ if (icvt != NULL)
+ *icvt = NULL; /* Default return values */
+ if (smsk != NULL)
+ *smsk = 0x0;
+
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE: /* Subtractive Gray */
+ return icSigGrayData;
+
+ case PHOTOMETRIC_MINISBLACK: /* Additive Gray */
+ return icSigGrayData;
+
+ case PHOTOMETRIC_RGB:
+ return icSigRgbData;
+
+ case PHOTOMETRIC_PALETTE:
+ return 0x0;
+
+ case PHOTOMETRIC_MASK:
+ return 0x0;
+
+ case PHOTOMETRIC_SEPARATED:
+ /* Should look at the colorant names to figure out if this is CMY, CMYK */
+ /* Should at least return both Cmy/3 or Cmyk/4 ! */
+ switch(spp) {
+ case 2:
+ return icSig2colorData;
+ case 3:
+// return icSig3colorData;
+ return icSigCmyData;
+ case 4:
+// return icSig4colorData;
+ return icSigCmykData;
+ case 5:
+ return icSig5colorData;
+ case 6:
+ return icSig6colorData;
+ case 7:
+ return icSig7colorData;
+ case 8:
+ return icSig8colorData;
+ case 9:
+ return icSig9colorData;
+ case 10:
+ return icSig10colorData;
+ case 11:
+ return icSig11colorData;
+ case 12:
+ return icSig12colorData;
+ case 13:
+ return icSig13colorData;
+ case 14:
+ return icSig14colorData;
+ case 15:
+ return icSig15colorData;
+ }
+
+ case PHOTOMETRIC_YCBCR:
+ return icSigYCbCrData;
+
+ case PHOTOMETRIC_CIELAB:
+ if (bps == 8) {
+ if (icvt != NULL)
+ *icvt = cvt_CIELAB8_to_Lab;
+ } else {
+ if (icvt != NULL)
+ *icvt = cvt_CIELAB16_to_Lab;
+ }
+ *smsk = 0x6; /* Treat a & b as signed */
+ return icSigLabData;
+
+ case PHOTOMETRIC_ICCLAB:
+ if (bps == 8) {
+ if (icvt != NULL)
+ *icvt = cvt_ICCLAB8_to_Lab;
+ } else {
+ if (icvt != NULL)
+ *icvt = cvt_ICCLAB16_to_Lab;
+ }
+ return icSigLabData;
+
+ case PHOTOMETRIC_ITULAB:
+ return 0x0; /* Could add this with a conversion function */
+ /* but have to allow for variable ITU gamut */
+ /* (Tag 433, "Decode") */
+
+ case PHOTOMETRIC_LOGL:
+ return 0x0; /* Could add this with a conversion function */
+
+ case PHOTOMETRIC_LOGLUV:
+ return 0x0; /* Could add this with a conversion function */
+ }
+ return 0x0;
+}
+
+
+char *
+Photometric2str(
+int pmtc
+) {
+ static char buf[80];
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE:
+ return "Subtractive Gray";
+ case PHOTOMETRIC_MINISBLACK:
+ return "Additive Gray";
+ case PHOTOMETRIC_RGB:
+ return "RGB";
+ case PHOTOMETRIC_PALETTE:
+ return "Indexed";
+ case PHOTOMETRIC_MASK:
+ return "Transparency Mask";
+ case PHOTOMETRIC_SEPARATED:
+ return "Separated";
+ case PHOTOMETRIC_YCBCR:
+ return "YCbCr";
+ case PHOTOMETRIC_CIELAB:
+ return "CIELab";
+ case PHOTOMETRIC_ICCLAB:
+ return "ICCLab";
+ case PHOTOMETRIC_ITULAB:
+ return "ITULab";
+ case PHOTOMETRIC_LOGL:
+ return "CIELog2L";
+ case PHOTOMETRIC_LOGLUV:
+ return "CIELog2Luv";
+ }
+ sprintf(buf,"Unknown Photometric Tag %d",pmtc);
+ return buf;
+}
+
+void set_fminmax(double min[3], double max[3]);
+void reset_filter();
+void add_fpixel(double val[3]);
+int flush_filter(int verb, double filtperc);
+void get_filter(co *inp);
+void del_filter();
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char prof_name[MAXNAMEL+1] = { '\000' }; /* ICC profile name, "" if none */
+ char in_name[MAXNAMEL+1]; /* TIFF input file */
+ char *xl = NULL, out_name[MAXNAMEL+4+1] = "locus.ts"; /* locus output file */
+ int verb = 0;
+ int dovrml = 0;
+ int doaxes = 1;
+ int usevec = 0;
+ double vec[3];
+ int rv = 0;
+
+ icc *icco = NULL;
+ xicc *xicco = NULL;
+ icxViewCond vc; /* Viewing Condition for CIECAM */
+ int vc_e = -1; /* Enumerated viewing condition */
+ int vc_s = -1; /* Surround override */
+ double vc_wXYZ[3] = {-1.0, -1.0, -1.0}; /* Adapted white override in XYZ */
+ double vc_wxy[2] = {-1.0, -1.0}; /* Adapted white override in x,y */
+ double vc_a = -1.0; /* Adapted luminance */
+ double vc_b = -1.0; /* Background % overid */
+ double vc_f = -1.0; /* Flare % overid */
+ double vc_fXYZ[3] = {-1.0, -1.0, -1.0}; /* Flare color override in XYZ */
+ double vc_fxy[2] = {-1.0, -1.0}; /* Flare color override in x,y */
+ icxLuBase *luo = NULL; /* Generic lookup object */
+ icColorSpaceSignature ins = icSigLabData, outs; /* Type of input and output spaces */
+ int inn, outn; /* Number of components */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ icmLookupFunc func = icmFwd; /* Must be */
+ icRenderingIntent intent = -1; /* Default */
+ icColorSpaceSignature pcsor = icSigLabData; /* Default */
+ icmLookupOrder order = icmLuOrdNorm; /* Default */
+
+ TIFF *rh = NULL;
+ int x, y, width, height; /* Size of image */
+ uint16 samplesperpixel, bitspersample;
+ uint16 pconfig, photometric, pmtc;
+ uint16 resunits;
+ float resx, resy;
+ tdata_t *inbuf;
+ void (*cvt)(double *out, double *in); /* TIFF conversion function, NULL if none */
+ icColorSpaceSignature tcs; /* TIFF colorspace */
+ uint16 extrasamples; /* Extra "alpha" samples */
+ uint16 *extrainfo; /* Info about extra samples */
+ int sign_mask; /* Handling of encoding sign */
+
+ int i, j;
+ int nipoints = 0; /* Number of raster sample points */
+ co *inp = NULL; /* Input point values */
+ double tdel = 0.0; /* Total delta along locus */
+ rspl *rr = NULL;
+ int nopoints = 0; /* Number of raster sample points */
+ co *outp = NULL;
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v') {
+ verb = 1;
+ }
+
+ /* Intent */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'd':
+ intent = icmDefaultIntent;
+ break;
+ case 'a':
+ intent = icAbsoluteColorimetric;
+ break;
+ case 'p':
+ intent = icPerceptual;
+ break;
+ case 'r':
+ intent = icRelativeColorimetric;
+ break;
+ case 's':
+ intent = icSaturation;
+ break;
+ /* Argyll special intents to check spaces underlying */
+ /* icxPerceptualAppearance & icxSaturationAppearance */
+ case 'P':
+ intent = icmAbsolutePerceptual;
+ break;
+ case 'S':
+ intent = icmAbsoluteSaturation;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Search order */
+ else if (argv[fa][1] == 'o') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'n':
+ case 'N':
+ order = icmLuOrdNorm;
+ break;
+ case 'r':
+ case 'R':
+ order = icmLuOrdRev;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* PCS override */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'l':
+ pcsor = icSigLabData;
+ break;
+ case 'j':
+ pcsor = icxSigJabData;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Viewing conditions */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ fa = nfa;
+ if (na == NULL) usage();
+
+ /* Switch to Jab automatically */
+ pcsor = icxSigJabData;
+
+ /* Set the viewing conditions */
+ if (na[1] != ':') {
+ if ((vc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
+ usage();
+ } else if (na[0] == 's' || na[0] == 'S') {
+ if (na[1] != ':')
+ usage();
+ if (na[2] == 'a' || na[2] == 'A') {
+ vc_s = vc_average;
+ } else if (na[2] == 'm' || na[2] == 'M') {
+ vc_s = vc_dim;
+ } else if (na[2] == 'd' || na[2] == 'D') {
+ vc_s = vc_dark;
+ } else if (na[2] == 'c' || na[2] == 'C') {
+ vc_s = vc_cut_sheet;
+ } else
+ usage();
+ } else if (na[0] == 'w' || na[0] == 'W') {
+ double x, y, z;
+ if (sscanf(na+1,":%lf:%lf:%lf",&x,&y,&z) == 3) {
+ vc_wXYZ[0] = x; vc_wXYZ[1] = y; vc_wXYZ[2] = z;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc_wxy[0] = x; vc_wxy[1] = y;
+ } else
+ usage();
+ } else if (na[0] == 'a' || na[0] == 'A') {
+ if (na[1] != ':')
+ usage();
+ vc_a = atof(na+2);
+ } else if (na[0] == 'b' || na[0] == 'B') {
+ if (na[1] != ':')
+ usage();
+ vc_b = atof(na+2);
+ } else if (na[0] == 'f' || na[0] == 'F') {
+ 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;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc_fxy[0] = x; vc_fxy[1] = y;
+ } else if (sscanf(na+1,":%lf",&x) == 1) {
+ vc_f = x;
+ } else
+ usage();
+ } else
+ usage();
+ }
+
+ /* VRML output */
+ else if (argv[fa][1] == 'w' || argv[fa][1] == 'W') {
+ dovrml = 1;
+ }
+ /* No axis output */
+ else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
+ doaxes = 0;
+ }
+ /* Vector direction for span */
+ else if (argv[fa][1] == 'V') {
+ usevec = 1;
+ if (na == NULL) usage();
+ fa = nfa;
+ if (sscanf(na, " %lf , %lf , %lf ",&vec[0], &vec[1], &vec[2]) != 3)
+ usage();
+ }
+ /* Output file name */
+ else if (argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ strncpy(out_name,na,MAXNAMEL); out_name[MAXNAMEL] = '\000';
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ if (fa < (argc-1))
+ strncpy(prof_name,argv[fa++],MAXNAMEL); prof_name[MAXNAMEL] = '\000';
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strncpy(in_name,argv[fa],MAXNAMEL); in_name[MAXNAMEL] = '\000';
+
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+
+ if (verb) {
+ printf("Profile = '%s'\n",prof_name);
+ printf("Input TIFF = '%s'\n",in_name);
+ printf("Output file = '%s'\n",out_name);
+ }
+
+ if (intent == -1) {
+ if (pcsor == icxSigJabData)
+ intent = icRelativeColorimetric; /* Default to icxAppearance */
+ else
+ intent = icAbsoluteColorimetric; /* Default to icAbsoluteColorimetric */
+ }
+
+ /* - - - - - - - - - - - - - - - - */
+ /* If we were provided an ICC profile to use */
+ if (prof_name[0] != '\000') {
+
+ /* Open up the profile or TIFF embedded profile for reading */
+ if ((icco = read_embedded_icc(prof_name)) == NULL)
+ error ("Can't open profile in file '%s'",prof_name);
+
+ if (verb) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ icco->header->dump(icco->header, op, 1);
+ op->del(op);
+ }
+
+ /* Check that the profile is appropriate */
+ if (icco->header->deviceClass != icSigInputClass
+ && icco->header->deviceClass != icSigDisplayClass
+ && icco->header->deviceClass != icSigOutputClass
+ && icco->header->deviceClass != icSigColorSpaceClass)
+ error("Profile type isn't device or colorspace");
+
+ /* Wrap with an expanded icc */
+ if ((xicco = new_xicc(icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ /* Setup the default viewing conditions */
+ if (xicc_enum_viewcond(xicco, &vc, -1, NULL, 0, NULL) == -999)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ if (vc_e != -1)
+ if (xicc_enum_viewcond(xicco, &vc, vc_e, NULL, 0, NULL) == -999)
+ error ("%d, %s",xicco->errc, xicco->err);
+ if (vc_s >= 0)
+ vc.Ev = vc_s;
+ if (vc_wXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Wxyz[0] = vc_wXYZ[0]/vc_wXYZ[1] * vc.Wxyz[1];
+ vc.Wxyz[2] = vc_wXYZ[2]/vc_wXYZ[1] * vc.Wxyz[1];
+ }
+ if (vc_wxy[0] >= 0.0) {
+ double x = vc_wxy[0];
+ double y = vc_wxy[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
+ double z = 1.0 - x - y;
+ vc.Wxyz[0] = x/y * vc.Wxyz[1];
+ vc.Wxyz[2] = z/y * vc.Wxyz[1];
+ }
+ if (vc_a >= 0.0)
+ vc.La = vc_a;
+ if (vc_b >= 0.0)
+ vc.Yb = vc_b/100.0;
+ if (vc_f >= 0.0)
+ vc.Yf = vc_f/100.0;
+ if (vc_fXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Fxyz[0] = vc_fXYZ[0]/vc_fXYZ[1] * vc.Fxyz[1];
+ vc.Fxyz[2] = vc_fXYZ[2]/vc_fXYZ[1] * vc.Fxyz[1];
+ }
+ if (vc_fxy[0] >= 0.0) {
+ double x = vc_fxy[0];
+ double y = vc_fxy[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];
+ }
+
+ /* Get a expanded color conversion object */
+ if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST
+ , func, intent, pcsor, order, &vc, NULL)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ luo->spaces(luo, &ins, &inn, &outs, &outn, &alg, NULL, NULL, NULL);
+
+ }
+
+ /* Establish the PCS range if we are filtering */
+ {
+ double pcsmin[3], pcsmax[3]; /* PCS range for filter stats array */
+
+ if (luo) {
+ gamut *csgam;
+
+ if ((csgam = luo->get_gamut(luo, 20.0)) == NULL)
+ error("Getting the gamut of the source colorspace failed");
+
+ csgam->getrange(csgam, pcsmin, pcsmax);
+ csgam->del(csgam);
+ } else {
+ pcsmin[0] = 0.0;
+ pcsmax[0] = 100.0;
+ pcsmin[1] = -128.0;
+ pcsmax[1] = 128.0;
+ pcsmin[2] = -128.0;
+ pcsmax[2] = 128.0;
+ }
+
+ if (verb)
+ printf("PCS range = %f..%f, %f..%f. %f..%f\n\n", pcsmin[0], pcsmax[0], pcsmin[1], pcsmax[1], pcsmin[2], pcsmax[2]);
+
+ /* Allocate and initialize the filter */
+ set_fminmax(pcsmin, pcsmax);
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Open up input tiff file ready for reading */
+ /* Got arguments, so setup to process the file */
+
+ if ((rh = TIFFOpen(in_name, "r")) == NULL)
+ error("error opening read file '%s'",in_name);
+
+ TIFFGetField(rh, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);
+
+ TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8 && bitspersample != 16)
+ error("TIFF Input file must be 8 bit/channel");
+
+ TIFFGetFieldDefaulted(rh, TIFFTAG_EXTRASAMPLES, &extrasamples, &extrainfo);
+ TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &photometric);
+
+ if (inn != (samplesperpixel-extrasamples))
+ error ("TIFF Input file has %d input chanels mismatched to colorspace '%s'",
+ samplesperpixel, icm2str(icmColorSpaceSignature, ins));
+
+ if ((tcs = TiffPhotometric2ColorSpaceSignature(&cvt, &sign_mask, photometric,
+ bitspersample, samplesperpixel, extrasamples)) == 0)
+ error("Can't handle TIFF file photometric %s", Photometric2str(photometric));
+
+ if (tcs != ins) {
+ if (luo != NULL)
+ error("TIFF photometric '%s' doesn't match ICC input colorspace '%s' !",
+ Photometric2str(photometric), icm2str(icmColorSpaceSignature,ins));
+ else
+ error("No profile provided and TIFF photometric '%s' isn't Lab !",
+ Photometric2str(photometric));
+ }
+
+ TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
+ if (pconfig != PLANARCONFIG_CONTIG)
+ error ("TIFF Input file must be planar");
+
+ TIFFGetField(rh, TIFFTAG_RESOLUTIONUNIT, &resunits);
+ TIFFGetField(rh, TIFFTAG_XRESOLUTION, &resx);
+ TIFFGetField(rh, TIFFTAG_YRESOLUTION, &resy);
+
+ if (verb) {
+ printf("Input TIFF file '%s'\n",in_name);
+ printf("TIFF file colorspace is %s\n",icm2str(icmColorSpaceSignature,tcs));
+ printf("TIFF file photometric is %s\n",Photometric2str(photometric));
+ printf("\n");
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Process colors to translate */
+ /* (Should fix this to process a group of lines at a time ?) */
+
+ nipoints = width * height;
+
+// if ((inp = malloc(sizeof(co) * nipoints)) == NULL)
+// error("Unable to allocate co array");
+
+ inbuf = _TIFFmalloc(TIFFScanlineSize(rh));
+
+ for (i = y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int e;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+ if (bitspersample == 8) {
+ for (e = 0; e < samplesperpixel; e++) {
+ int v = ((unsigned char *)inbuf)[x * samplesperpixel + e];
+ if (sign_mask & (1 << i)) /* Treat input as signed */
+ v = (v & 0x80) ? v - 0x80 : v + 0x80;
+ in[e] = v/255.0;
+ }
+ } else {
+ for (e = 0; e < samplesperpixel; e++) {
+ int v = ((unsigned short *)inbuf)[x * samplesperpixel + e];
+ if (sign_mask & (1 << i)) /* Treat input as signed */
+ v = (v & 0x8000) ? v - 0x8000 : v + 0x8000;
+ in[e] = v/65535.0;
+ }
+ }
+ if (cvt != NULL) { /* Undo TIFF encoding */
+ cvt(in, in);
+ }
+ if (luo != NULL) {
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ if (outs == icSigXYZData) /* Convert to Lab */
+ icmXYZ2Lab(&icco->header->illuminant, out, out);
+ } else {
+ for (e = 0; e < samplesperpixel; e++)
+ out[e] = in[e];
+ }
+
+//printf("~1 %f %f %f -> %f %f %f\n", in[0], in[1], in[2], out[0], out[1], out[2]);
+
+ add_fpixel(out);
+
+#ifdef NEVER
+ /* Store PCS value in array */
+ inp[i].v[0] = out[0];
+ inp[i].v[1] = out[1];
+ inp[i].v[2] = out[2];
+ i++;
+#endif
+ }
+ }
+
+ _TIFFfree(inbuf);
+
+ TIFFClose(rh); /* Close Input file */
+
+ /* Done with lookup object */
+ if (luo != NULL) {
+ luo->del(luo);
+ xicco->del(xicco); /* Expansion wrapper */
+ icco->del(icco); /* Icc */
+ }
+
+
+ nipoints = flush_filter(verb, 80.0);
+
+ if ((inp = malloc(sizeof(co) * nipoints)) == NULL)
+ error("Unable to allocate co array");
+
+ get_filter(inp);
+
+printf("~1 There are %d points\n",nipoints);
+//for (i = 0; i < nipoints; i++)
+//printf("~1 point %d = %f %f %f\n", i, inp[i].v[0], inp[i].v[1], inp[i].v[2]);
+
+ del_filter();
+
+ /* Create the locus */
+ {
+ double s0[3], s1[3];
+ double t0[3], t1[3];
+ double mm[3][4];
+ double im[3][4];
+ int gres[MXDI] = { 256 } ;
+
+ if (usevec) {
+ double max = -1e6;
+ double min = 1e6;
+ double dist;
+
+ icmScale3(vec, vec, 1.0/icmNorm3(vec));
+
+ /* Locate the two furthest distant points measured along the vector */
+ for (i = 0; i < nipoints; i++) {
+ double tt;
+ tt = icmDot3(vec, inp[i].v);
+ if (tt > max) {
+ max = tt;
+ icmAry2Ary(s1, inp[i].v);
+ }
+ if (tt < min) {
+ min = tt;
+ icmAry2Ary(s0, inp[i].v);
+ }
+ }
+ dist = icmNorm33sq(s0, s1);
+
+printf("~1 most distant in vector %f %f %f = %f %f %f -> %f %f %f dist %f\n",
+vec[0], vec[1], vec[2], s0[0], s0[1], s0[2], s1[0], s1[1], s1[2], sqrt(dist));
+
+ t0[0] = 0.0;
+ t0[1] = 0.0;
+ t0[2] = 0.0;
+ t1[0] = sqrt(dist);
+ t1[1] = 0.0;
+ t1[2] = 0.0;
+
+ } else {
+ double dist = 0.0;
+
+ /* Locate the two furthest distant points (brute force) */
+ for (i = 0; i < (nipoints-1); i++) {
+ for (j = i+1; j < nipoints; j++) {
+ double tt;
+ if ((tt = icmNorm33sq(inp[i].v, inp[j].v)) > dist) {
+ dist = tt;
+ icmAry2Ary(s0, inp[i].v);
+ icmAry2Ary(s1, inp[j].v);
+ }
+ }
+ }
+printf("~1 most distant = %f %f %f -> %f %f %f dist %f\n",
+s0[0], s0[1], s0[2], s1[0], s1[1], s1[2], sqrt(dist));
+
+ t0[0] = 0.0;
+ t0[1] = 0.0;
+ t0[2] = 0.0;
+ t1[0] = sqrt(dist);
+ t1[1] = 0.0;
+ t1[2] = 0.0;
+ }
+
+ /* Transform our direction vector to the L* axis, and create inverse too */
+ icmVecRotMat(mm, s1, s0, t1, t0);
+ icmVecRotMat(im, t1, t0, s1, s0);
+
+ /* Setup for rspl to create smoothed locus */
+ for (i = 0; i < nipoints; i++) {
+ icmMul3By3x4(inp[i].v, mm, inp[i].v);
+ inp[i].p[0] = inp[i].v[0];
+ inp[i].v[0] = inp[i].v[1];
+ inp[i].v[1] = inp[i].v[2];
+//printf("~1 point %d = %f -> %f %f\n", i, inp[i].p[0], inp[i].v[0], inp[i].v[1]);
+ }
+
+ /* Create rspl */
+ if ((rr = new_rspl(RSPL_NOFLAGS, 1, 2)) == NULL)
+ error("Creating rspl failed");
+
+ rr->fit_rspl(rr, RSPL_NOFLAGS,inp, nipoints, NULL, NULL, gres, NULL, NULL, 5.0, NULL, NULL);
+#ifdef DEBUG_PLOT
+ {
+#define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+ double y2[XRES];
+
+ for (i = 0; i < XRES; i++) {
+ co pp;
+ double x;
+ x = i/(double)(XRES-1);
+ xx[i] = x * (t1[0] - t0[0]);
+ pp.p[0] = xx[i];
+ rr->interp(rr, &pp);
+ y1[i] = pp.v[0];
+ y2[i] = pp.v[1];
+ }
+ do_plot(xx,y1,y2,NULL,XRES);
+ }
+#endif /* DEBUG_PLOT */
+
+ free(inp);
+
+ nopoints = t1[0] / DE_SPACE;
+ if (nopoints < 2)
+ nopoints = 2;
+
+ /* Create the output points */
+ if ((outp = malloc(sizeof(co) * nopoints)) == NULL)
+ error("Unable to allocate co array");
+
+ /* Setup initial division of locus */
+ for (i = 0; i < nopoints; i++) {
+ double xx;
+
+ xx = i/(double)(nopoints-1);
+ xx *= (t1[0] - t0[0]);
+
+ outp[i].p[0] = xx;
+//printf("~1 div %d = %f\n",i,outp[i].p[0]);
+ }
+ for (i = 0; i < (nopoints-1); i++) {
+ outp[i].p[1] = outp[i+1].p[0] - outp[i].p[0];
+//printf("~1 del div %d = %f\n",i,outp[i].p[1]);
+ }
+
+ /* Itterate until the delta between samples is even */
+ for (j = 0; j < 10; j++) {
+ double alen, minl, maxl;
+ double tdiv;
+
+ alen = 0.0;
+ minl = 1e38;
+ maxl = -1.0;
+ for (i = 0; i < nopoints; i++) {
+ rr->interp(rr, &outp[i]);
+ outp[i].v[2] = outp[i].v[1];
+ outp[i].v[1] = outp[i].v[0];
+ outp[i].v[0] = outp[i].p[0];
+ icmMul3By3x4(outp[i].v, im, outp[i].v);
+
+//printf("~1 locus pnt %d = %f %f %f\n", i,outp[i].v[0],outp[i].v[1],outp[i].v[1]);
+
+ if (i > 0) {
+ double tt[3], len;
+ icmSub3(tt, outp[i].v, outp[i-1].v);
+ len = icmNorm3(tt);
+ outp[i-1].p[2] = len;
+ if (len > maxl)
+ maxl = len;
+ if (len < minl)
+ minl = len;
+ alen += len;
+ }
+ }
+ alen /= (nopoints-1.0);
+printf("~1 itter %d, alen = %f, minl = %f, maxl = %f\n",j,alen,minl,maxl);
+
+ /* Adjust spacing */
+ tdiv = 0.0;
+ for (i = 0; i < (nopoints-1); i++) {
+ outp[i].p[1] *= pow(alen/outp[i].p[2], 1.0);
+ tdiv += outp[i].p[1];
+ }
+//printf("~1 tdiv = %f\n",tdiv);
+ for (i = 0; i < (nopoints-1); i++) {
+ outp[i].p[1] *= (t1[0] - t0[0])/tdiv;
+//printf("~1 del div %d = %f\n",i,outp[i].p[1]);
+ }
+ tdiv = 0.0;
+ for (i = 0; i < (nopoints-1); i++) {
+ tdiv += outp[i].p[1];
+ }
+//printf("~1 tdiv now = %f\n",tdiv);
+ for (i = 1; i < nopoints; i++) {
+ outp[i].p[0] = outp[i-1].p[0] + outp[i-1].p[1];
+//printf("~1 div %d = %f\n",i,outp[i].p[0]);
+ }
+ }
+
+ /* Write the CGATS file */
+ {
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats *pp;
+
+ pp = new_cgats(); /* Create a CGATS structure */
+ pp->add_other(pp, "TS"); /* Test Set */
+
+ pp->add_table(pp, tt_other, 0); /* Add the first table for target points */
+ pp->add_kword(pp, 0, "DESCRIPTOR", "Argyll Test Point set",NULL);
+ pp->add_kword(pp, 0, "ORIGINATOR", "Argyll tiffgmts", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ pp->add_kword(pp, 0, "CREATED",atm, NULL);
+
+ pp->add_field(pp, 0, "SAMPLE_ID", cs_t);
+ pp->add_field(pp, 0, "LAB_L", r_t);
+ pp->add_field(pp, 0, "LAB_A", r_t);
+ pp->add_field(pp, 0, "LAB_B", r_t);
+
+ for (i = 0; i < nopoints; i++) {
+ char buf[100];
+ cgats_set_elem ary[1 + 3];
+
+ sprintf(buf,"%d",i+1);
+ ary[0].c = buf;
+ ary[1 + 0].d = outp[i].v[0];
+ ary[1 + 1].d = outp[i].v[1];
+ ary[1 + 2].d = outp[i].v[2];
+
+ pp->add_setarr(pp, 0, ary);
+ }
+
+ if (pp->write_name(pp, out_name))
+ error("Write error : %s",pp->err);
+ }
+
+ /* Create the VRML file */
+ if (dovrml) {
+ vrml *vv;
+
+ strcpy(xl,".wrl");
+ printf("Output vrml file '%s'\n",out_name);
+ if ((vv = new_vrml(out_name, doaxes, 0)) == NULL)
+ error ("Creating VRML object failed");
+
+#ifdef NEVER
+ vv->start_line_set(vv);
+ for (i = 0; i < nopoints; i++) {
+ vv->add_vertex(vv, outp[i].v);
+ }
+ vv->make_lines(vv, nopoints);
+#else
+ for (i = 1; i < nopoints; i++) {
+ vv->add_cone(vv, outp[i-1].v, outp[i].v, NULL, 0.5);
+ }
+#endif
+
+ vv->del(vv);
+ }
+ free(outp);
+ }
+
+ rr->del(rr);
+
+ return 0;
+}
+
+/* ------------------------------------------ */
+/* A pixel value filter module. We quantize the pixel values and keep statistics */
+/* on them, so as to filter out low frequency colors. */
+
+#define FILTBITS 5 /* Total = 2 ^ (3 * FILTBITS) entries = 33Mbytes*/
+#define FILTSIZE (1 << FILTBITS)
+
+/* A filtered cell entry */
+typedef struct {
+ int count; /* Count of pixels that fall in this cell */
+ float pcs[3]; /* Sum of PCS value that fall in this cell */
+} fent;
+
+struct _ffilter {
+ double min[3], max[3]; /* PCS range */
+ double filtperc;
+ int used;
+
+ fent cells[FILTSIZE][FILTSIZE][FILTSIZE]; /* Quantized pixels stats */
+ fent *scells[FILTSIZE * FILTSIZE * FILTSIZE]; /* Sorted order */
+
+}; typedef struct _ffilter ffilter;
+
+
+
+/* Use a global object */
+ffilter *ff = NULL;
+
+/* Set the min and max values and init the filter */
+void set_fminmax(double min[3], double max[3]) {
+
+ if (ff == NULL) {
+ if ((ff = (ffilter *) calloc(1,sizeof(ffilter))) == NULL)
+ error("ffilter: calloc failed");
+ }
+
+ ff->min[0] = min[0];
+ ff->min[1] = min[1];
+ ff->min[2] = min[2];
+ ff->max[0] = max[0];
+ ff->max[1] = max[1];
+ ff->max[2] = max[2];
+}
+
+/* Add another pixel to the filter */
+void add_fpixel(double val[3]) {
+ int j;
+ int qv[3];
+ fent *fe;
+ double cent[3] = { 50.0, 0.0, 0.0 }; /* Assumed center */
+ double tt, cdist, ndist;
+
+ if (ff == NULL)
+ error("ffilter not initialized");
+
+ /* Quantize the values */
+ for (j = 0; j < 3; j++) {
+ double vv;
+
+ vv = (val[j] - ff->min[j])/(ff->max[j] - ff->min[j]);
+ qv[j] = (int)(vv * (FILTSIZE - 1) + 0.5);
+ }
+
+//printf("~1 color %f %f %f -> Cell %d %d %d\n", val[0], val[1], val[2], qv[0], qv[1], qv[2]);
+
+ /* Find the appropriate cell */
+ fe = &ff->cells[qv[0]][qv[1]][qv[2]];
+
+ fe->pcs[0] += val[0];
+ fe->pcs[1] += val[1];
+ fe->pcs[2] += val[2];
+//printf("Updated pcs to %f %f %f\n", val[0],val[1],val[2]);
+ fe->count++;
+//printf("Cell count = %d\n",fe->count);
+}
+
+/* Flush the filter contents, and return the number of filtered values */
+int flush_filter(int verb, double filtperc) {
+ int i, j;
+ int totcells = FILTSIZE * FILTSIZE * FILTSIZE;
+ int used, hasone;
+ double cuml, avgcnt;
+
+ if (ff == NULL)
+ error("ffilter not initialized");
+
+ /* Sort the cells by popularity from most to least */
+ for (used = hasone = avgcnt = i = 0; i < totcells; i++) {
+ ff->scells[i] = (fent *)ff->cells + i;
+ if (ff->scells[i]->count > 0) {
+ used++;
+ if (ff->scells[i]->count == 1)
+ hasone++;
+ avgcnt += ff->scells[i]->count;
+ }
+ }
+ avgcnt /= used;
+
+#define HEAP_COMPARE(A,B) A->count > B->count
+ HEAPSORT(fent *,ff->scells, totcells)
+
+ if (verb) {
+ printf("Total of %d cells out of %d were hit (%.1f%%)\n",used,totcells,used * 100.0/totcells);
+ printf("%.1f%% have a count of 1\n",hasone * 100.0/used);
+ printf("Average cell count = %f\n",avgcnt);
+ printf("\n");
+ }
+
+ /* Add the populated cells in order */
+ filtperc /= 100.0;
+ for (cuml = 0.0, i = j = 0; cuml < filtperc && i < totcells; i++) {
+
+ if (ff->scells[i]->count > 0) {
+ double val[3];
+ ff->scells[i]->pcs[0] /= ff->scells[i]->count;
+ ff->scells[i]->pcs[1] /= ff->scells[i]->count;
+ ff->scells[i]->pcs[2] /= ff->scells[i]->count;
+ j++;
+ cuml = j/(used-1.0);
+ }
+ }
+ ff->used = used;
+ ff->filtperc = filtperc;
+
+ return j;
+}
+
+/* Add the points to the array */
+void get_filter(co *inp) {
+ int i, j;
+ int totcells = FILTSIZE * FILTSIZE * FILTSIZE;
+ double cuml, filtperc;
+ int used;
+
+ used = ff->used;
+ filtperc = ff->filtperc;
+
+ for (cuml = 0.0, i = j = 0; cuml < filtperc && i < totcells; i++) {
+
+ if (ff->scells[i]->count > 0) {
+ double val[3];
+ inp[j].v[0] = ff->scells[i]->pcs[0]; /* float -> double */
+ inp[j].v[1] = ff->scells[i]->pcs[1];
+ inp[j].v[2] = ff->scells[i]->pcs[2];
+//printf("~1 adding %f %f %f to gamut\n", val[0], val[1], val[2]);
+ j++;
+ cuml = j/(used-1.0);
+ }
+
+ }
+}
+
+/* Free up the filter structure */
+void del_filter() {
+
+ free(ff);
+}
+
diff --git a/xicc/transplot.c b/xicc/transplot.c
new file mode 100644
index 0000000..e196544
--- /dev/null
+++ b/xicc/transplot.c
@@ -0,0 +1,279 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * Check various aspects of CMYK device link,
+ * and RGB/CMYK profile transfer characteristics.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2003/9/7
+ * Version: 1.0
+ *
+ * Copyright 2000 - 2003 Graeme W. Gill
+ * Please refer to License.txt file for details.
+ */
+
+/* TTBD:
+ *
+ * Make general device input, not just CMYK
+ *
+ * Allow specifying a vector in the range space.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+#include "numlib.h"
+#include "plot.h"
+
+void usage(void) {
+ fprintf(stderr,"Check CMYK/RGB/PCS->PCS/CMYK/RGB transfer response\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: transplot [-v] infile\n");
+ fprintf(stderr," -v verbose\n");
+ fprintf(stderr," -c -m -y -k Check Cyan and/or Magenta and/or Yellow and/or Black input\n");
+ fprintf(stderr," -r -g -b Check Red and/or Green and/or Blue input\n");
+ fprintf(stderr," -L -A -B Check L and/or a* and/or b* input\n");
+ exit(1);
+}
+
+#define XRES 256
+//#define XRES 11
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int chans[4] = { 0, 0, 0, 0 }; /* Flags indicating which channels to plot against */
+ char in_name[100];
+ icmFile *rd_fp;
+ icc *rd_icco; /* Keep object separate */
+ int rv = 0;
+
+ /* Check variables */
+ icmLuBase *luo;
+ icmLuLut *luluto; /* Lookup xLut type object */
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int inn; /* Number of input chanels */
+ icmLuAlgType alg;
+ int labin = 0; /* Flag */
+ int rgbin = 0; /* Flag */
+ int labout = 0; /* Flag */
+ int rgbout = 0; /* Flag */
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ /* Cyan, Red */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C'
+ || argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ chans[0] = 1;
+ }
+ /* Magenta, Green, a* */
+ else if (argv[fa][1] == 'm' || argv[fa][1] == 'M'
+ || argv[fa][1] == 'g' || argv[fa][1] == 'G') {
+ chans[1] = 1;
+ }
+ /* Yellow, Blue, b* */
+ else if (argv[fa][1] == 'y' || argv[fa][1] == 'Y'
+ || argv[fa][1] == 'b') {
+ chans[2] = 1;
+ }
+ /* L* */
+ else if (argv[fa][1] == 'L') {
+ chans[0] = 1;
+ labin = 1;
+ }
+ /* a* */
+ else if (argv[fa][1] == 'A') {
+ chans[1] = 1;
+ labin = 1;
+ }
+ /* Yellow, Blue, b* */
+ else if (argv[fa][1] == 'B') {
+ chans[2] = 1;
+ labin = 1;
+ }
+ /* Black */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ chans[3] = 1;
+ }
+ else if (argv[fa][1] == '?')
+ usage();
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa]);
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ if (labin) {
+ /* Get a Device to PCS conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmBwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ } else {
+ /* Get a PCS to Device conversion object */
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm)) == NULL) {
+ if ((luo = rd_icco->get_luobj(rd_icco, icmFwd, icmDefaultIntent, icmSigDefaultData, icmLuOrdNorm)) == NULL) {
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+ }
+ }
+
+ /* Get details of conversion */
+ luo->spaces(luo, &ins, &inn, &outs, NULL, &alg, NULL, NULL, NULL, NULL);
+
+ if (labin) {
+ chans[3] = 0;
+
+ if (outs != icSigCmykData && outs != icSigRgbData) {
+ error("Expecting CMYK or RGB output space");
+ }
+
+ if (outs == icSigRgbData) {
+ rgbout = 1;
+ }
+
+ } else {
+ if (ins != icSigCmykData && ins != icSigRgbData) {
+ error("Expecting CMYK or RGB input space");
+ }
+
+ if (ins == icSigRgbData) {
+ rgbin = 1;
+ chans[3] = 0;
+ }
+
+ if (outs != icSigCmykData && outs != icSigLabData) {
+ error("Expecting Lab or CMYK output space");
+ }
+
+ if (outs == icSigLabData)
+ labout = 1;
+ }
+
+
+ luluto = (icmLuLut *)luo; /* Lookup xLut type object */
+
+ {
+ int i, j;
+ double xx[XRES];
+ double y0[XRES];
+ double y1[XRES];
+ double y2[XRES];
+ double y3[XRES];
+
+ for (i = 0; i < XRES; i++) {
+ double ival = (double)i/(XRES-1.0);
+ double in[4];
+ double out[4];
+
+ for (j = 0; j < 4; j++)
+ in[j] = 0.0;
+
+ if (labin) {
+ in[0] = 0.5;
+ in[1] = 0.5;
+ in[2] = 0.5;
+ }
+
+ if (chans[0])
+ in[0] = ival;
+ if (chans[1])
+ in[1] = ival;
+ if (chans[2])
+ in[2] = ival;
+ if (chans[3])
+ in[3] = ival;
+
+ if (labin) {
+ in[0] = in[0] * 100.0;
+ in[1] = (in[1] - 0.5) * 254.0;
+ in[2] = (in[2] - 0.5) * 254.0;
+ }
+
+ /* Do the conversion */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (labout) {
+//printf("~1 in %f %f %f %f, out %f %f %f\n",in[0],in[1],in[2],in[3],out[0],out[1],out[2]);
+ xx[i] = ival;
+ y0[i] = out[0]/1.0;
+ y1[i] = 50.0 + out[1]/2.0;
+ y2[i] = 50.0 + out[2]/2.0;
+ if (y1[i] < 0.0)
+ y1[i] = 0.0;
+ if (y1[i] > 100.0)
+ y1[i] = 100.0;
+ if (y2[i] < 0.0)
+ y2[i] = 0.0;
+ if (y2[i] > 100.0)
+ y2[i] = 100.0;
+ } else {
+ xx[i] = ival;
+ y0[i] = out[0];
+ y1[i] = out[1];
+ y2[i] = out[2];
+ y3[i] = out[3];
+ }
+
+ }
+ if (labout)
+ do_plot6(xx,y0,y1,NULL,NULL,y2,NULL,XRES);
+ else
+ do_plot6(xx,y3,y1,NULL,y0,y2,NULL,XRES);
+ }
+
+ /* Done with lookup object */
+ luo->del(luo);
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ return 0;
+}
diff --git a/xicc/xcal.c b/xicc/xcal.c
new file mode 100644
index 0000000..97a3086
--- /dev/null
+++ b/xicc/xcal.c
@@ -0,0 +1,496 @@
+
+/*
+ * Argyll Color Correction System
+ * Calibration curve class.
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/10/2005
+ *
+ * Copyright 2005 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.
+ *
+ * This class allows reading and using a calibration file.
+ * Creation is currently left up to specialized programs (dispcal, printcal).
+ * This class doesn't handle the extra table that dispcal creates/uses.
+ *
+ */
+
+#undef DEBUG /* Input points */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <math.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "xicc.h"
+
+#ifdef NT /* You'd think there might be some standards.... */
+# ifndef __BORLANDC__
+# define stricmp _stricmp
+# endif
+#else
+# define stricmp strcasecmp
+#endif
+
+/* rspl setting functions */
+static void xcal_rsplset(void *cbntx, double *out, double *in) {
+ co *dpoints = (co *)cbntx;
+ int ix;
+
+ ix = *((int*)&in[-0-1]); /* Get grid index being looked up */
+ out[0] = dpoints[ix].v[0];
+}
+
+/* Read a calibration file from a cgats table */
+/* Return nz if this fails */
+static int xcal_read_cgats(xcal *p, cgats *tcg, int table, char *filename) {
+ int oi;
+ int i, j, ti;
+ char *ident;
+ char *bident;
+ int spi[1+MAX_CHAN]; /* CGATS indexes for each field */
+ char buf[100];
+
+ if ((oi = tcg->get_oi(tcg, "CAL")) < 0) {
+ sprintf(p->err, "Input file '%s' can't be a CAL format file", filename);
+ return p->errc = 1;
+ }
+
+ if (tcg->t[table].tt != tt_other || tcg->t[table].oi != oi) {
+ sprintf(p->err, "Input file '%s' isn't a CAL format file", filename);
+ return p->errc = 1;
+ }
+
+ /* See what sort of device type this calibration is for */
+ if ((ti = tcg->find_kword(tcg, table, "DEVICE_CLASS")) < 0) {
+ sprintf(p->err, "Calibration file '%s'doesn't contain keyword DEVICE_CLASS",filename);
+ return p->errc = 1;
+ }
+ if (strcmp(tcg->t[table].kdata[ti],"INPUT") == 0) {
+ p->devclass = icSigInputClass;
+ } else if (strcmp(tcg->t[table].kdata[ti],"OUTPUT") == 0) {
+ p->devclass = icSigOutputClass;
+ } else if (strcmp(tcg->t[table].kdata[ti],"DISPLAY") == 0) {
+ p->devclass = icSigDisplayClass;
+ } else {
+ sprintf(p->err,"Calibration file '%s' contain unknown DEVICE_CLASS '%s'",
+ filename,tcg->t[table].kdata[ti]);
+ return p->errc = 1;
+ }
+
+ if ((ti = tcg->find_kword(tcg, table, "COLOR_REP")) < 0) {
+ /* Be backwards compatible with V1.0.4 display calibration files */
+ if (p->devclass != icSigDisplayClass) {
+ sprintf(p->err, "Calibration file '%s'doesn't contain keyword COLOR_REP",filename);
+ return p->errc = 1;
+ }
+ warning("\n *** Calibration file '%s'doesn't contain keyword COLOR_REP, assuming RGB ***",filename);
+ if ((p->devmask = icx_char2inkmask("RGB") ) == 0) {
+ sprintf(p->err, "Calibration file '%s' has unrecognized COLOR_REP '%s'",
+ filename,tcg->t[table].kdata[ti]);
+ return p->errc = 1;
+ }
+ } else {
+ if ((p->devmask = icx_char2inkmask(tcg->t[table].kdata[ti]) ) == 0) {
+ sprintf(p->err, "Calibration file '%s' has unrecognized COLOR_REP '%s'",
+ filename,tcg->t[table].kdata[ti]);
+ return p->errc = 1;
+ }
+ }
+
+ if ((ti = tcg->find_kword(tcg, table, "VIDEO_LUT_CALIBRATION_POSSIBLE")) >= 0) {
+ if (stricmp(tcg->t[table].kdata[ti], "NO") == 0)
+ p->noramdac = 1;
+ }
+
+ p->colspace = icx_colorant_comb_to_icc(p->devmask); /* 0 if none */
+ p->devchan = icx_noofinks(p->devmask);
+ ident = icx_inkmask2char(p->devmask, 1);
+ bident = icx_inkmask2char(p->devmask, 0);
+
+ /* Grab any descriptive information */
+ if ((ti = tcg->find_kword(tcg, table, "MANUFACTURER")) >= 0)
+ p->xpi.deviceMfgDesc = strdup(tcg->t[table].kdata[ti]);
+ if ((ti = tcg->find_kword(tcg, table, "MODEL")) >= 0)
+ p->xpi.modelDesc = strdup(tcg->t[table].kdata[ti]);
+ if ((ti = tcg->find_kword(tcg, table, "DESCRIPTION")) >= 0)
+ p->xpi.profDesc = strdup(tcg->t[table].kdata[ti]);
+ if ((ti = tcg->find_kword(tcg, table, "COPYRIGHT")) >= 0)
+ p->xpi.copyright = strdup(tcg->t[table].kdata[ti]);
+
+ if (tcg->t[table].nsets <= 0) {
+ sprintf(p->err, "Calibration file '%s' has too few entries %d",
+ filename,tcg->t[table].nsets);
+ return p->errc = 1;
+ }
+
+ /* Figure out the indexes of all the fields */
+ sprintf(buf, "%s_I",bident);
+ if ((spi[0] = tcg->find_field(tcg, table, buf)) < 0) {
+ sprintf(p->err,"Calibration file '%s' doesn't contain field '%s'", filename,buf);
+ return p->errc = 1;
+ }
+
+ for (j = 0; j < p->devchan; j++) {
+ inkmask imask = icx_index2ink(p->devmask, j);
+ sprintf(buf, "%s_%s",bident,icx_ink2char(imask));
+ if ((spi[1+j] = tcg->find_field(tcg, table, buf)) < 0) {
+ sprintf(p->err,"Calibration file '%s' doesn't contain field '%s'", filename,buf);
+ return p->errc = 1;
+ }
+ }
+
+ /* Read in each channels values and put them in a rspl */
+ for (j = 0; j < p->devchan; j++) {
+ datai low,high;
+ int gres[MXDI];
+ double smooth = 1.0;
+ co *dpoints;
+
+ low[0] = 0.0;
+ high[0] = 1.0;
+ gres[0] = tcg->t[table].nsets;
+
+ if ((p->cals[j] = new_rspl(RSPL_NOFLAGS,1, 1)) == NULL) {
+ sprintf(p->err,"new_rspl() failed");
+ return p->errc = 2;
+ }
+
+ if ((dpoints = malloc(sizeof(co) * gres[0])) == NULL) {
+ sprintf(p->err,"malloc dpoints[%d] failed",gres[0]);
+ return p->errc = 2;
+ }
+
+ /* Copy the points to our array */
+ for (i = 0; i < gres[0]; i++) {
+ dpoints[i].p[0] = i/(double)(gres[0]-1);
+ dpoints[i].v[0] = *((double *)tcg->t[table].fdata[i][spi[1+j]]);
+ }
+
+ /* Set the rspl */
+ p->cals[j]->set_rspl(p->cals[j],
+ 0,
+ (void *)dpoints, /* Read points */
+ xcal_rsplset, /* Setting function */
+ low, high, gres, /* Low, high, resolution of grid */
+ NULL, NULL /* Default data scale */
+ );
+ free(dpoints);
+ }
+ free(ident);
+ free(bident);
+
+ return 0;
+}
+
+/* Read a calibration file */
+/* Return nz if this fails */
+static int xcal_read(xcal *p, char *filename) {
+ cgats *tcg; /* .cal file */
+ int table = 0;
+ int rv;
+
+ if ((tcg = new_cgats()) == NULL) {
+ sprintf(p->err, "new_cgats() failed");
+ return p->errc = 2;
+ }
+
+ tcg->add_other(tcg, "CAL"); /* our special input type is Calibration Target */
+
+ if (tcg->read_name(tcg, filename)) {
+ strcpy(p->err, tcg->err);
+ p->errc = tcg->errc;
+ tcg->del(tcg);
+ return p->errc;
+ }
+
+ rv = xcal_read_cgats(p, tcg, table, filename);
+
+ tcg->del(tcg);
+
+ return rv;
+}
+
+/* Write a calibration to a new cgats table */
+/* Return nz if this fails */
+static int xcal_write_cgats(xcal *p, cgats *tcg) {
+ int oi;
+ int table;
+ int i, j, ti;
+ char *ident, *bident;
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ char buf[100];
+ cgats_set_elem *setel; /* Array of set value elements */
+ int nsetel = 0;
+ int calres;
+
+ oi = tcg->add_other(tcg, "CAL"); /* our special type is Calibration Target */
+
+ table = tcg->add_table(tcg, tt_other, oi); /* Add a table for calibration */
+
+ tcg->add_kword(tcg, table, "DESCRIPTOR", "Argyll Device Calibration Curves",NULL);
+ tcg->add_kword(tcg, table, "ORIGINATOR", "Argyll", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ tcg->add_kword(tcg, table, "CREATED",atm, NULL);
+
+ if (p->devclass == icSigInputClass)
+ tcg->add_kword(tcg, table, "DEVICE_CLASS","INPUT", NULL);
+ else if (p->devclass == icSigOutputClass)
+ tcg->add_kword(tcg, table, "DEVICE_CLASS","OUTPUT", NULL);
+ else if (p->devclass == icSigDisplayClass)
+ tcg->add_kword(tcg, table, "DEVICE_CLASS","DISPLAY", NULL);
+ else {
+ sprintf(p->err,"Unknown device class '%s'",icm2str(icmProfileClassSignature,p->devclass));
+ return p->errc = 1;
+ }
+
+ /* Colorspace */
+ ident = icx_inkmask2char(p->devmask, 1);
+ bident = icx_inkmask2char(p->devmask, 0);
+ tcg->add_kword(tcg, table, "COLOR_REP", ident, NULL);
+
+ /* Grab any descriptive information */
+ if (p->xpi.deviceMfgDesc != NULL)
+ tcg->add_kword(tcg, table, "MANUFACTURER",p->xpi.deviceMfgDesc, NULL);
+ if (p->xpi.modelDesc != NULL)
+ tcg->add_kword(tcg, table, "MODEL",p->xpi.modelDesc, NULL);
+ if (p->xpi.profDesc != NULL)
+ tcg->add_kword(tcg, table, "DESCRIPTION",p->xpi.profDesc, NULL);
+ if (p->xpi.copyright != NULL)
+ tcg->add_kword(tcg, table, "COPYRIGHT",p->xpi.copyright, NULL);
+
+ sprintf(buf, "%s_I",bident);
+ tcg->add_field(tcg, table, buf, r_t);
+ nsetel++;
+ for (j = 0; j < p->devchan; j++) {
+ inkmask imask = icx_index2ink(p->devmask, j);
+ sprintf(buf, "%s_%s",bident,icx_ink2char(imask));
+ tcg->add_field(tcg, table, buf, r_t);
+ nsetel++;
+ }
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * nsetel)) == NULL) {
+ sprintf(p->err,"Malloc failed");
+ return p->errc = 2;
+ }
+
+ calres = p->cals[0]->g.res[0];
+
+ for (i = 0; i < calres; i++) {
+ double vv = i/(calres-1.0);
+ co tp;
+
+ setel[0].d = vv;
+ for (j = 0; j < p->devchan; j++) {
+ tp.p[0] = vv;
+ p->cals[j]->interp(p->cals[j], &tp);
+ setel[j+1].d = tp.v[0];
+ }
+
+ tcg->add_setarr(tcg, table, setel);
+ }
+
+ free(setel);
+ free(ident);
+ free(bident);
+
+ return 0;
+}
+
+/* Write a calibration file */
+/* Return nz if this fails */
+static int xcal_write(xcal *p, char *filename) {
+ cgats *tcg; /* .cal file */
+ int table = 0;
+ int rv;
+
+ if ((tcg = new_cgats()) == NULL) {
+ sprintf(p->err, "new_cgats() failed");
+ return p->errc = 2;
+ }
+
+ if ((rv = xcal_write_cgats(p, tcg)) != 0) {
+ strcpy(p->err, tcg->err);
+ p->errc = tcg->errc;
+ tcg->del(tcg);
+ return p->errc;
+ }
+
+ if (tcg->write_name(tcg, filename)) {
+ strcpy(p->err, tcg->err);
+ p->errc = tcg->errc;
+ tcg->del(tcg);
+ return p->errc;
+ }
+
+ tcg->del(tcg);
+
+ return rv;
+}
+
+/* Translate values through the curves. */
+static void xcal_interp(xcal *p, double *out, double *in) {
+ int j;
+ co tp;
+
+ for (j = 0; j < p->devchan; j++) {
+ tp.p[0] = in[j];
+ p->cals[j]->interp(p->cals[j], &tp);
+ out[j] = tp.v[0];
+ }
+}
+
+#define MAX_INVSOLN 10 /* Rspl maximum reverse solutions */
+
+/* Translate a value backwards through the curves. */
+/* Return nz if the inversion fails */
+static int xcal_inv_interp(xcal *p, double *out, double *in) {
+ int nsoln; /* Number of solutions found */
+ co pp[MAX_INVSOLN]; /* Room for all the solutions found */
+ int j, k; /* Chosen solution */
+ double dir = 0.5; /* target if multiple solutions */
+ int rv = 0;
+
+ for (j = 0; j < p->devchan; j++) {
+ pp[0].v[0] = in[j];
+
+ nsoln = p->cals[j]->rev_interp (
+ p->cals[j], /* this */
+ RSPL_NEARCLIP, /* Clip to nearest (faster than vector) */
+ MAX_INVSOLN, /* Maximum number of solutions allowed for */
+ NULL, /* No auxiliary input targets */
+ NULL, /* Clip vector direction and length */
+ pp); /* Input and output values */
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln == 1) { /* Exactly one solution */
+ k = 0;
+ } else if (nsoln == 0) { /* Zero solutions. This is unexpected. */
+ rv = 1;
+ return -1.0;
+ } else { /* Multiple solutions */
+ double bdist = 1e300;
+ int bsoln = 0;
+ for (k = 0; k < nsoln; k++) {
+ double tt;
+ tt = pp[k].p[0] - dir;
+ tt *= tt;
+ if (tt < bdist) { /* Better solution */
+ bdist = tt;
+ bsoln = k;
+ }
+ }
+ k = bsoln;
+ }
+ out[j] = pp[k].p[0];
+ }
+
+ return rv;
+}
+
+/* Translate a value through one of the curves */
+static double xcal_interp_ch(xcal *p, int ch, double in) {
+ co tp;
+
+ if (ch < 0 || ch >= p->devchan)
+ return -1.0;
+
+ tp.p[0] = in;
+ p->cals[ch]->interp(p->cals[ch], &tp);
+ return tp.v[0];
+}
+
+/* Translate a value backwards through one of the curves */
+/* Return -1.0 if the inversion fails */
+static double xcal_inv_interp_ch(xcal *p, int ch, double in) {
+ int nsoln; /* Number of solutions found */
+ co pp[MAX_INVSOLN]; /* Room for all the solutions found */
+ int k; /* Chosen solution */
+ double dir = 0.5; /* target if multiple solutions */
+
+ if (ch < 0 || ch >= p->devchan)
+ return -1.0;
+
+ pp[0].v[0] = in;
+
+ nsoln = p->cals[ch]->rev_interp (
+ p->cals[ch], /* this */
+ RSPL_NEARCLIP, /* Clip to nearest (faster than vector) */
+ MAX_INVSOLN, /* Maximum number of solutions allowed for */
+ NULL, /* No auxiliary input targets */
+ NULL, /* Clip vector direction and length */
+ pp); /* Input and output values */
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln == 1) { /* Exactly one solution */
+ k = 0;
+ } else if (nsoln == 0) { /* Zero solutions. This is unexpected. */
+ return -1.0;
+ } else { /* Multiple solutions */
+ double bdist = 1e300;
+ int bsoln = 0;
+ for (k = 0; k < nsoln; k++) {
+ double tt;
+ tt = pp[k].p[0] - dir;
+ tt *= tt;
+ if (tt < bdist) { /* Better solution */
+ bdist = tt;
+ bsoln = k;
+ }
+ }
+ k = bsoln;
+ }
+ return pp[k].p[0];
+}
+
+/* Delete an xcal */
+static void xcal_del(xcal *p) {
+ int j;
+
+ if (p->xpi.deviceMfgDesc != NULL)
+ free(p->xpi.deviceMfgDesc);
+ if (p->xpi.modelDesc != NULL)
+ free(p->xpi.modelDesc);
+ if (p->xpi.profDesc != NULL)
+ free(p->xpi.profDesc);
+ if (p->xpi.copyright != NULL)
+ free(p->xpi.copyright);
+
+ for (j = 0; j < p->devchan; j++) {
+ if (p->cals[j] != NULL)
+ p->cals[j]->del(p->cals[j]);
+ }
+ free(p);
+}
+
+/* Create a new, uninitialised xcal */
+xcal *new_xcal(void) {
+ xcal *p;
+
+ if ((p = (xcal *)calloc(1, sizeof(xcal))) == NULL)
+ return NULL;
+
+ /* Init method pointers */
+ p->del = xcal_del;
+ p->read_cgats = xcal_read_cgats;
+ p->read = xcal_read;
+ p->write_cgats = xcal_write_cgats;
+ p->write = xcal_write;
+ p->interp = xcal_interp;
+ p->inv_interp = xcal_inv_interp;
+ p->interp_ch = xcal_interp_ch;
+ p->inv_interp_ch = xcal_inv_interp_ch;
+
+ return p;
+}
+
diff --git a/xicc/xcal.h b/xicc/xcal.h
new file mode 100644
index 0000000..99f1c9c
--- /dev/null
+++ b/xicc/xcal.h
@@ -0,0 +1,78 @@
+
+#ifndef XCAL_H
+#define XCAL_H
+
+/*
+ * Argyll Color Correction System
+ * Calibration curve class.
+ *
+ * Author: Graeme W. Gill
+ * Date: 30/10/2005
+ *
+ * Copyright 2005 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.
+ *
+ * This class allows reading and using a calibration file.
+ * Creation is currently left up to specialized programs (dispcal, printcal).
+ * This is also used by xicc to automatically take calibration into account
+ * when computing ink limits.
+ */
+
+struct _xcal {
+
+ /* Public: */
+ void (*del)(struct _xcal *p);
+
+ /* Read a calibration file from a CGATS table */
+ /* Return nz if this fails (filename is for error messages) */
+ int (*read_cgats) (struct _xcal *p, cgats *cg, int table, char *filename);
+
+ /* Read a calibration file */
+ /* Return nz if this fails */
+ int (*read) (struct _xcal *p, char *filename);
+
+ /* Write a calibration to a new cgats table */
+ /* Return nz if this fails */
+ int (*write_cgats)(struct _xcal *p, cgats *tcg);
+
+ /* Write a calibration file */
+ /* Return nz if this fails */
+ int (*write)(struct _xcal *p, char *filename);
+
+ /* Translate values through the curves curves. */
+ void (*interp) (struct _xcal *p, double *out, double *in);
+
+ /* Translate a value backwards through the curves. */
+ /* Return nz if the inversion fails */
+ int (*inv_interp) (struct _xcal *p, double *out, double *in);
+
+ /* Translate a value through one of the curves */
+ double (*interp_ch) (struct _xcal *p, int ch, double in);
+
+ /* Translate a value backwards through one of the curves */
+ /* Return -1.0 if the inversion fails */
+ double (*inv_interp_ch) (struct _xcal *p, int ch, double in);
+
+ int noramdac; /* Set to nz if there was no VideoLUT access */
+
+ /* Private: */
+ icProfileClassSignature devclass; /* Type of device */
+ inkmask devmask; /* ICX ink mask of device space */
+ icColorSpaceSignature colspace; /* Corresponding ICC device space sig (0 if none) */
+ int devchan; /* Number of chanels in device space */
+ profxinf xpi; /* Extra calibration description information */
+
+ char err[CGATS_ERRM_LENGTH]; /* Error message */
+ int errc; /* Error code */
+
+ rspl *cals[MAX_CHAN];
+
+}; typedef struct _xcal xcal;
+
+/* Create a new, uninitialised xcal */
+xcal *new_xcal(void);
+
+#endif /* XCAL */
+
diff --git a/xicc/xcam.c b/xicc/xcam.c
new file mode 100644
index 0000000..99f3c67
--- /dev/null
+++ b/xicc/xcam.c
@@ -0,0 +1,214 @@
+
+/*
+ * Abstract interface to color appearance model transforms.
+ *
+ * This is to allow the rest of Argyll to use a default CAM.
+ *
+ * Author: Graeme W. Gill
+ * Date: 25/7/2004
+ * Version: 1.00
+ *
+ * Copyright 2004 Graeme W. Gill
+ * Please refer to COPYRIGHT file for details.
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "xcam.h"
+#include "cam97s3.h"
+#include "cam02.h"
+
+static void icx_cam_free(icxcam *s);
+static int icx_set_view(icxcam *s, ViewingCondition Ev, double Wxyz[3],
+ double La, double Yb, double Lv, double Yf, double Fxyz[3],
+ int hk);
+static int icx_XYZ_to_cam(struct _icxcam *s, double Jab[3], double XYZ[3]);
+static int icx_cam_to_XYZ(struct _icxcam *s, double XYZ[3], double Jab[3]);
+static void settrace(struct _icxcam *s, int tracev);
+
+/* Return the default CAM */
+icxCAM icxcam_default(void) {
+// return cam_CIECAM97s3;
+ return cam_CIECAM02;
+}
+
+/* Return a string describing the given CAM */
+char *icxcam_description(icxCAM which) {
+ if (which == cam_default)
+ which = icxcam_default();
+
+ switch(which) {
+ case cam_CIECAM97s3:
+ return "CIECAM97s3";
+ case cam_CIECAM02:
+ return "CIECAM02";
+ default:
+ break;
+ }
+ return "Unknown CAM";
+}
+
+/* Create a cam conversion object */
+icxcam *new_icxcam(icxCAM which) {
+ icxcam *s;
+
+ if ((s = (icxcam *)calloc(1, sizeof(icxcam))) == NULL) {
+ fprintf(stderr,"icxcam: malloc failed allocating object\n");
+ return NULL;
+ }
+
+ /* Initialise methods */
+ s->del = icx_cam_free;
+ s->set_view = icx_set_view;
+ s->XYZ_to_cam = icx_XYZ_to_cam;
+ s->cam_to_XYZ = icx_cam_to_XYZ;
+ s->settrace = settrace;
+
+ /* We set the default CAM here */
+ if (which == cam_default)
+ which = icxcam_default();
+
+ s->tag = which;
+
+ switch(which) {
+ case cam_CIECAM97s3:
+ if ((s->p = (void *)new_cam97s3()) == NULL) {
+ fprintf(stderr,"icxcam: malloc failed allocating object\n");
+ free(s);
+ return NULL;
+ }
+ break;
+ case cam_CIECAM02:
+ if ((s->p = (void *)new_cam02()) == NULL) {
+ fprintf(stderr,"icxcam: malloc failed allocating object\n");
+ free(s);
+ return NULL;
+ }
+ break;
+
+ default:
+ fprintf(stderr,"icxcam: unknown CAM type\n");
+ free(s);
+ return NULL;
+ }
+ return s;
+}
+
+static void icx_cam_free(icxcam *s) {
+ if (s != NULL) {
+ switch(s->tag) {
+ case cam_CIECAM97s3: {
+ cam97s3 *pp = (cam97s3 *)s->p;
+ pp->del(pp);
+ break;
+ }
+ case cam_CIECAM02: {
+ cam02 *pp = (cam02 *)s->p;
+ pp->del(pp);
+ break;
+ }
+ default:
+ break;
+ }
+ free(s);
+ }
+}
+
+static int icx_set_view(
+icxcam *s,
+ViewingCondition Ev, /* Enumerated Viewing Condition */
+double Wxyz[3], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+double La, /* Adapting/Surround Luminance cd/m^2 */
+double Yb, /* Relative Luminance of Background to reference white */
+double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set to other than vc_none */
+double Yf, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+double Fxyz[3], /* The Flare white coordinates (typically the Ambient color) */
+int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+) {
+ s->Wxyz[0] = Wxyz[0];
+ s->Wxyz[1] = Wxyz[1];
+ s->Wxyz[2] = Wxyz[2];
+
+ switch(s->tag) {
+ case cam_CIECAM97s3: {
+ cam97s3 *pp = (cam97s3 *)s->p;
+ return pp->set_view(pp, Ev, Wxyz, La, Yb, Lv, Yf, Fxyz, hk);
+ }
+ case cam_CIECAM02: {
+ cam02 *pp = (cam02 *)s->p;
+ return pp->set_view(pp, Ev, Wxyz, La, Yb, Lv, Yf, Fxyz, hk);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* Conversions */
+static int icx_XYZ_to_cam(
+struct _icxcam *s,
+double Jab[3],
+double XYZ[3]
+) {
+ switch(s->tag) {
+ case cam_CIECAM97s3: {
+ cam97s3 *pp = (cam97s3 *)s->p;
+ return pp->XYZ_to_cam(pp, Jab, XYZ);
+ }
+ case cam_CIECAM02: {
+ cam02 *pp = (cam02 *)s->p;
+ return pp->XYZ_to_cam(pp, Jab, XYZ);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int icx_cam_to_XYZ(
+struct _icxcam *s,
+double XYZ[3],
+double Jab[3]
+) {
+ switch(s->tag) {
+ case cam_CIECAM97s3: {
+ cam97s3 *pp = (cam97s3 *)s->p;
+ return pp->cam_to_XYZ(pp, XYZ, Jab);
+ }
+ case cam_CIECAM02: {
+ cam02 *pp = (cam02 *)s->p;
+ return pp->cam_to_XYZ(pp, XYZ, Jab);
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* Debug */
+static void settrace(
+struct _icxcam *s,
+int tracev
+) {
+ switch(s->tag) {
+ case cam_CIECAM97s3: {
+ cam97s3 *pp = (cam97s3 *)s->p;
+ pp->trace = tracev;
+ }
+ case cam_CIECAM02: {
+ cam02 *pp = (cam02 *)s->p;
+ pp->trace = tracev;
+ }
+ default:
+ break;
+ }
+}
+
+
+
+
+
diff --git a/xicc/xcam.h b/xicc/xcam.h
new file mode 100644
index 0000000..d4f4857
--- /dev/null
+++ b/xicc/xcam.h
@@ -0,0 +1,82 @@
+
+#ifndef _XCAM_H_
+
+/*
+ * Abstract interface to color appearance model transforms.
+ *
+ * This is to allow the rest of Argyll to use a default CAM.
+ *
+ * Author: Graeme W. Gill
+ * Date: 25/7/2004
+ * Version: 1.00
+ *
+ * Copyright 2004 Graeme W. Gill
+ * Please refer to COPYRIGHT file for details.
+ * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ */
+
+/* ---------------------------------- */
+
+/* The range of CAMs supported */
+typedef enum {
+ cam_default = 0, /* Default CAM */
+ cam_CIECAM97s3 = 1, /* CIECAM97, version 3 */
+ cam_CIECAM02 = 2 /* CIECAM02 */
+} icxCAM;
+
+/* The enumerated viewing conditions: */
+typedef enum {
+ vc_notset = -1,
+ vc_none = 0, /* Figure out from Lv and La */
+ vc_dark = 1,
+ vc_dim = 2,
+ vc_average = 3,
+ vc_cut_sheet = 4 /* Transparencies on a Light Box */
+} ViewingCondition;
+
+struct _icxcam {
+/* Public: */
+ void (*del)(struct _icxcam *s); /* We're done with it */
+
+ /* Always returns 0 */
+ int (*set_view)(
+ struct _icxcam *s,
+ ViewingCondition Ev, /* Enumerated Viewing Condition */
+ double Wxyz[3], /* Reference/Adapted White XYZ (Y scale 1.0) */
+ double La, /* Adapting/Surround Luminance cd/m^2 */
+ double Yb, /* Luminance of Background relative to reference white (range 0.0 .. 1.0) */
+ double Lv, /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set */
+ double Yf, /* Flare as a fraction of the reference white (range 0.0 .. 1.0) */
+ double Fxyz[3], /* The Flare white coordinates (typically the Ambient color) */
+ int hk /* Flag, NZ to use Helmholtz-Kohlraush effect */
+ );
+
+ /* Conversions */
+ int (*XYZ_to_cam)(struct _icxcam *s, double *out, double *in);
+ int (*cam_to_XYZ)(struct _icxcam *s, double *out, double *in);
+
+ /* Debug */
+ void (*settrace)(struct _icxcam *s, int tracev);
+
+/* Private: */
+ icxCAM tag; /* Type */
+ void *p; /* Pointer to implementation */
+ double Wxyz[3]; /* Copy of Wxyz */
+
+}; typedef struct _icxcam icxcam;
+
+/* Create a new CAM conversion object */
+icxcam *new_icxcam(icxCAM which);
+
+/* Return the default CAM */
+icxCAM icxcam_default();
+
+/* Return a string describing the given CAM */
+char *icxcam_description(icxCAM ct);
+
+#define _XCAM_H_
+#endif /* _XCAM_H_ */
+
+
diff --git a/xicc/xcolorants.c b/xicc/xcolorants.c
new file mode 100644
index 0000000..84a7720
--- /dev/null
+++ b/xicc/xcolorants.c
@@ -0,0 +1,768 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ * Known colorants support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/2/2002
+ * Version: 1.00
+ *
+ * Copyright 2002 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.
+ *
+ */
+
+/* TTBD:
+ Would like to have some short string way of defining whether
+ the ink combination is additive or subtractive, instead
+ of just guessing.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+#include "xcolorants.h"
+#include "sort.h"
+
+/* Colorant table for N color device characterisation. */
+/* This is ordered to match the ICC colorspace convention. */
+/* NOTE:- need to keep these in same order as ink mask */
+/* enumeration (lsb to msb), or strange things result! */
+static struct {
+ inkmask m; /* Mask value */
+ char *c; /* 1/2 Character name */
+ char *s; /* Everyday name */
+ char *ps; /* Postscript colorant name */
+ double aXYZ[3]; /* Rough XYZ values (0..1) for that additive colorant */
+ double sXYZ[3]; /* Rough XYZ values (0..1) for that subtractive colorant */
+} icx_ink_table[] = {
+ { ICX_CYAN, ICX_C_CYAN, ICX_S_CYAN, ICX_PS_CYAN,
+ { 0.12, 0.18, 0.48 },
+ { 0.12, 0.18, 0.48 } },
+ { ICX_MAGENTA, ICX_C_MAGENTA, ICX_S_MAGENTA, ICX_PS_MAGENTA,
+ { 0.38, 0.19, 0.20 },
+ { 0.38, 0.19, 0.20 } },
+ { ICX_YELLOW, ICX_C_YELLOW, ICX_S_YELLOW, ICX_PS_YELLOW,
+ { 0.76, 0.81, 0.11 },
+ { 0.76, 0.81, 0.11 } },
+ { ICX_BLACK, ICX_C_BLACK, ICX_S_BLACK, ICX_PS_BLACK,
+ { 0.01, 0.01, 0.01 },
+ { 0.04, 0.04, 0.04 } },
+ { ICX_ORANGE, ICX_C_ORANGE, ICX_S_ORANGE, ICX_PS_ORANGE,
+ { 0.59, 0.41, 0.03 },
+ { 0.59, 0.41, 0.05 } },
+ { ICX_RED, ICX_C_RED, ICX_S_RED, ICX_PS_RED,
+ { 0.412414, 0.212642, 0.019325 },
+ { 0.40, 0.21, 0.05 } },
+ { ICX_GREEN, ICX_C_GREEN, ICX_S_GREEN, ICX_PS_GREEN,
+ { 0.357618, 0.715136, 0.119207 },
+ { 0.11, 0.27, 0.21 } },
+ { ICX_BLUE, ICX_C_BLUE, ICX_S_BLUE, ICX_PS_BLUE,
+ { 0.180511, 0.072193, 0.950770 },
+ { 0.11, 0.27, 0.47 } },
+ { ICX_WHITE, ICX_C_WHITE, ICX_S_WHITE, ICX_PS_WHITE,
+ { 0.950543, 1.0, 1.089303 }, /* D65 ? */
+ { 0.9642, 1.00, 0.8249 } }, /* D50 */
+ { ICX_LIGHT_CYAN, ICX_C_LIGHT_CYAN, ICX_S_LIGHT_CYAN, ICX_PS_LIGHT_CYAN,
+ { 0.76, 0.89, 1.08 },
+ { 0.76, 0.89, 1.08 } },
+ { ICX_LIGHT_MAGENTA, ICX_C_LIGHT_MAGENTA, ICX_S_LIGHT_MAGENTA, ICX_PS_LIGHT_MAGENTA,
+ { 0.83, 0.74, 1.02 },
+ { 0.83, 0.74, 1.02 } },
+ { ICX_LIGHT_YELLOW, ICX_C_LIGHT_YELLOW, ICX_S_LIGHT_YELLOW, ICX_PS_LIGHT_YELLOW,
+ { 0.88, 0.97, 0.72 },
+ { 0.88, 0.97, 0.72 } },
+ { ICX_LIGHT_BLACK, ICX_C_LIGHT_BLACK, ICX_S_LIGHT_BLACK, ICX_PS_LIGHT_BLACK,
+ { 0.56, 0.60, 0.65 },
+ { 0.56, 0.60, 0.65 } },
+ { ICX_MEDIUM_CYAN, ICX_C_MEDIUM_CYAN, ICX_S_MEDIUM_CYAN, ICX_PS_MEDIUM_CYAN,
+ { 0.61, 0.81, 1.07 },
+ { 0.61, 0.81, 1.07 } },
+ { ICX_MEDIUM_MAGENTA, ICX_C_MEDIUM_MAGENTA, ICX_S_MEDIUM_MAGENTA, ICX_PS_MEDIUM_MAGENTA,
+ { 0.74, 0.53, 0.97 },
+ { 0.74, 0.53, 0.97 } },
+ { ICX_MEDIUM_YELLOW, ICX_C_MEDIUM_YELLOW, ICX_S_MEDIUM_YELLOW, ICX_PS_MEDIUM_YELLOW,
+ { 0.82, 0.93, 0.40 },
+ { 0.82, 0.93, 0.40 } },
+ { ICX_MEDIUM_BLACK, ICX_C_MEDIUM_BLACK, ICX_S_MEDIUM_BLACK, ICX_PS_MEDIUM_BLACK,
+ { 0.27, 0.29, 0.31 },
+ { 0.27, 0.29, 0.31 } },
+ { ICX_LIGHT_LIGHT_BLACK, ICX_C_LIGHT_LIGHT_BLACK, ICX_S_LIGHT_LIGHT_BLACK, ICX_PS_LIGHT_LIGHT_BLACK,
+ { 0.76, 0.72, 0.65 }, /* Very rough - should substiture real numbers */
+ { 0.76, 0.72, 0.65 } },
+ { 0, "", "", "", { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }
+};
+
+
+/* Colorant table for N color device characterisation */
+static struct {
+ inkmask m; /* Mask combination */
+ inkmask rm; /* Light ink reduced mask combination */
+ icColorSpaceSignature psig; /* Appropriate primary ICC signature */
+ icColorSpaceSignature ssig; /* Appropriate secondary ICC signature */
+ char *desc; /* Description */
+} icx_colcomb_table[] = {
+ { ICX_K, ICX_K, icSigGrayData, icSigGrayData,
+ "Print grey" },
+ { ICX_W, ICX_W, icSigGrayData, icSigGrayData,
+ "Video grey" },
+ { ICX_IRGB, ICX_IRGB, icSigRgbData, icSigRgbData,
+ "Print RGB" },
+ { ICX_RGB, ICX_RGB, icSigRgbData, icSigRgbData,
+ "Video RGB" },
+ { ICX_CMYK, ICX_CMYK, icSigCmykData, icSigCmykData,
+ "CMYK" },
+ { ICX_CMY, ICX_CMY, icSigCmyData, icSigCmyData,
+ "CMY" },
+ { ICX_CMYKcm, ICX_CMYK, icSig6colorData, icSigMch6Data,
+ "CMYK + Light CM" },
+ { ICX_CMYKcmk, ICX_CMYK, icSig7colorData, icSig7colorData,
+ "CMYK + Light CMK" },
+ { ICX_CMYKRB, ICX_W, icSig6colorData, icSigMch6Data,
+ "CMYK + Red + Blue" },
+ { ICX_CMYKOG, ICX_W, icSig6colorData, icSigMch6Data,
+ "CMYK + Orange + Green" },
+ { ICX_CMYKcmk1k, ICX_CMYK, icSig8colorData, icSigMch8Data,
+ "CMYK + Light CMK + Light Light K" },
+ { ICX_CMYKOGcm, ICX_CMYKOG, icSig8colorData, icSigMch8Data,
+ "CMYK + Orange + Green + Light CM" },
+ { ICX_CMYKcm2c2m, ICX_CMYK, icSig8colorData, icSigMch8Data,
+ "CMYK + Light CM + Medium CM" },
+ { 0, 0, 0, 0, "" }
+};
+
+
+/* Given an ink combination mask, return the number of recognised inks in it */
+int icx_noofinks(inkmask mask) {
+ int i, count = 0;
+
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+ if (mask & icx_ink_table[i].m) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/* Given an ink combination mask, return the 1-2 character based string */
+/* If winv is nz, include ICX_INVERTED indicator if set */
+/* Return NULL on error. free() after use */
+char *icx_inkmask2char(inkmask mask, int winv) {
+ int i;
+ char *rv;
+
+ if ((rv = malloc(2 * ICX_MXINKS + 1)) == NULL)
+ return NULL;
+
+ *rv = '\000';
+
+ if (winv && (mask & ICX_INVERTED))
+ strcat(rv, "i");
+
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+ if (mask & icx_ink_table[i].m) {
+ strcat(rv, icx_ink_table[i].c);
+ }
+ }
+
+ return rv;
+}
+
+/* Given the 1-2 character string, return the ink combination mask */
+/* Note that ICX_ADDITIVE will be guessed */
+/* Return 0 if unrecognised character in string */
+inkmask icx_char2inkmask(char *chstring) {
+ inkmask mask = 0;
+ int k, i;
+ char *cp;
+
+ cp = chstring;
+
+ for (k = 0; ; k++) {
+
+ if (*cp == '\000') {
+ break;
+ }
+
+ /* "Inverted" prefix ? */
+ if (k == 0 && *cp == 'i') {
+ mask |= ICX_INVERTED;
+ cp++;
+ continue;
+ }
+ /* Colorant ? */
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+
+ if (strncmp(cp, icx_ink_table[i].c, strlen(icx_ink_table[i].c)) == 0) {
+ mask |= icx_ink_table[i].m;
+ cp += strlen(icx_ink_table[i].c);
+ break;
+ }
+ }
+ if (icx_ink_table[i].m == 0) { /* oops - unrecognised character */
+ return 0;
+ }
+ }
+
+ /* Check it out againts known combinations to guess additive */
+ for (i = 0; icx_colcomb_table[i].m != 0; i++) {
+ if ((icx_colcomb_table[i].m & ~ICX_ADDITIVE) == mask) {
+ mask = icx_colcomb_table[i].m;
+ break;
+ }
+ }
+
+ return mask;
+}
+
+/* Given an ink combination mask that may contain light inks, */
+/* return the corresponding ink mask without light inks. */
+/* Return 0 if ink combination not recognised. */
+inkmask icx_ink2primary_ink(inkmask mask) {
+ int i;
+ for (i = 0; icx_colcomb_table[i].m != 0; i++) {
+ if (mask == icx_colcomb_table[i].m) {
+ return icx_colcomb_table[i].rm;
+ }
+ }
+ return 0;
+}
+
+
+/* Given an ink combination mask and a single ink mask, */
+/* return the index number for that ink. */
+/* Return -1 if mask1 not in mask */
+int icx_ink2index(inkmask mask, inkmask mask1) {
+ int i, count = 0;
+
+ if ((mask1 & mask) == 0)
+ return -1;
+
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+ if (mask1 == icx_ink_table[i].m) {
+ return count;
+ }
+ if (mask & icx_ink_table[i].m) {
+ count++;
+ }
+ }
+
+ return -1;
+}
+
+/* Given an ink combination mask and a index number, */
+/* return the single ink mask. */
+/* Return 0 if there are no inks at that index */
+inkmask icx_index2ink(inkmask mask, int ixno) {
+ int i, count = 0;
+
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+ if (mask & icx_ink_table[i].m) {
+ if (ixno == count)
+ return icx_ink_table[i].m;
+ count++;
+ }
+ }
+ return 0;
+}
+
+
+/* Given a single ink mask, */
+/* return its string representation */
+char *icx_ink2string(inkmask mask) {
+ int i;
+
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+ if (mask == icx_ink_table[i].m)
+ return icx_ink_table[i].s;
+ }
+ return NULL;
+}
+
+/* Given a single ink mask, */
+/* return its 1-2 character representation */
+char *icx_ink2char(inkmask mask) {
+ int i;
+
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+ if (mask == icx_ink_table[i].m)
+ return icx_ink_table[i].c;
+ }
+ return NULL;
+}
+
+/* Given a single ink mask, */
+/* return its Postscript string representation */
+char *icx_ink2psstring(inkmask mask) {
+ int i;
+
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+ if (mask == icx_ink_table[i].m)
+ return icx_ink_table[i].ps;
+ }
+ return NULL;
+}
+
+
+/* Return an enumerated single colorant description */
+/* Return 0 if no such enumeration, single colorant mask if there is */
+inkmask icx_enum_colorant(
+int no, /* Enumeration mask index */
+char **desc /* Return enumeration description */
+) {
+ int i;
+
+ for (i = 0; icx_ink_table[i].m != 0; i++) {
+ if (i == no) {
+ if (desc != NULL)
+ *desc = icx_ink_table[i].s;
+ return icx_ink_table[i].m;
+ }
+ }
+ return 0;
+}
+
+/* Return an enumerated colorant combination */
+/* Return 0 if no such enumeration, colorant combination mask if there is */
+inkmask icx_enum_colorant_comb(
+int no, /* Enumeration mask index */
+char **desc /* Return enumeration description */
+) {
+ int i;
+
+ for (i = 0; icx_colcomb_table[i].m != 0; i++) {
+ if (i == no) {
+ if (desc != NULL)
+ *desc = icx_colcomb_table[i].desc;
+ return icx_colcomb_table[i].m;
+ }
+ }
+ return 0;
+}
+
+
+/* Given an colorant combination mask, */
+/* check if it matches the given ICC colorspace signature. */
+/* return NZ if it does. */
+/* (We don't check colorant colors for multi-colorant devices though) */
+int icx_colorant_comb_match_icc(
+inkmask mask, /* Colorant combination mask */
+icColorSpaceSignature sig /* ICC signature */
+) {
+ int i;
+ for (i = 0; icx_colcomb_table[i].m != 0; i++) {
+ if (mask == icx_colcomb_table[i].m) {
+ if (sig == icx_colcomb_table[i].psig
+ || sig == icx_colcomb_table[i].ssig) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Given an ICC colorspace signature, return the appropriate */
+/* colorant combination mask. Return 0 if ambiguous signature. */
+inkmask icx_icc_to_colorant_comb(icColorSpaceSignature sig, icProfileClassSignature deviceClass) {
+ switch (sig) {
+ case icSigGrayData:
+ if (deviceClass == icSigOutputClass)
+ return ICX_K;
+ return ICX_W;
+
+ case icSigCmyData:
+ return ICX_CMY;
+
+ case icSigRgbData:
+ if (deviceClass == icSigOutputClass)
+ return ICX_IRGB;
+ return ICX_RGB;
+
+ case icSigCmykData:
+ return ICX_CMYK;
+
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* Given an ICC colorspace signature, and a matching list */
+/* of the D50 L*a*b* colors of the colorants, return the best matching */
+/* colorant combination mask. Return 0 if not an applicable colorspace. */
+/* (Note we're not dealing with colorant order here.) */
+inkmask icx_icc_cv_to_colorant_comb(
+icColorSpaceSignature sig, /* Input ICC colorspace signature */
+icProfileClassSignature deviceClass, /* Device class */
+double cvals[][3] /* Input L*a*b* colorant values */
+) {
+ int i, j;
+ int imask;
+ int ninks, ncol;
+ double slab[ICX_MXINKS][3];
+ double alab[ICX_MXINKS][3];
+ typedef struct { int x; double v; } mchstr;
+ mchstr mch[MAX_CHAN][ICX_MXINKS]; /* match index */
+ int used[ICX_MXINKS];
+ int co[ICX_MXINKS]; /* Combination counter */
+ double cmv; /* Combination match value */
+ int bco[ICX_MXINKS]; /* Best Combinat */
+ double bcmv; /* Best Match value */
+ int order[MAX_CHAN]; /* Place holder, not currently used - return ink order */
+
+ switch (sig) {
+ case icSigXYZData:
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYCbCrData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSigNamedData:
+ return 0;
+
+ case icSigGrayData:
+ if (deviceClass == icSigOutputClass)
+ return ICX_K;
+ return ICX_W;
+
+ case icSigCmyData:
+ return ICX_CMY;
+
+ case icSigRgbData:
+ if (deviceClass == icSigOutputClass)
+ return ICX_IRGB;
+ return ICX_RGB;
+
+ case icSigCmykData:
+ return ICX_CMYK;
+
+ default:
+ break;
+
+ }
+#ifdef NEVER /* Rely on device class (above) */
+ if (sig == icSigGrayData) {
+ /* This only works reliably if we got the Lab data from a non-ICC */
+ /* conformant monochrome profile (one that doesn't force device 0 */
+ /* input of the grayTRTC to black), or uses a LUT based monochrome */
+ /* profile. */
+ /* It also won't work if someone uses a monochrome profile for a */
+ /* device with a non grey colorant. */
+ /* Really ICC should have icSigWhiteData, icSigBlackData, icSig1colorData ? */
+ if (cvals[0][0] > 50.0) {
+ return ICX_W;
+ } else {
+ return ICX_K;
+ }
+ }
+#endif /* NEVER */
+
+ /* Compute Lab values of stock inks, and count them */
+ for (ninks = 0; ninks < ICX_MXINKS; ninks++) {
+ if (icx_ink_table[ninks].m == 0)
+ break;
+ icmXYZ2Lab(&icmD50, slab[ninks], icx_ink_table[ninks].sXYZ);
+ icmXYZ2Lab(&icmD50, alab[ninks], icx_ink_table[ninks].aXYZ);
+ }
+
+ ncol = icmCSSig2nchan(sig); /* Number of colorants */
+
+ /* Compute ideal matching of device colorants to stock inks */
+ for (i = 0; i < ncol; i++) {
+ for (j = 0; j < ninks; j++) {
+ double tt;
+ mch[i][j].x = j;
+ mch[i][j].v = icmCIE94sq(cvals[i], slab[j]);
+ tt = icmCIE94sq(cvals[i], alab[j]);
+ if (tt < mch[i][j].v)
+ mch[i][j].v = tt;
+ }
+ /* Sort the matches for this colorant */
+#define HEAP_COMPARE(A,B) (A.v < B.v)
+ HEAPSORT(mchstr, mch[i], ninks)
+#undef HEAP_COMPARE
+
+//printf("\n~1 Colorant %d has best matches\n",i);
+//for (j = 0; j < ninks; j++)
+//printf("~1 ix %d color = '%s' dE %f\n",j, icx_ink_table[mch[i][j].x].s, mch[i][j].v);
+ }
+
+ /* Do exaustive combination search, using early */
+ /* out to keep combination count down.*/
+
+ /* Reset the combination counter */
+ for (j = 0; j < ninks; j++) /* Reset ink used flag */
+ used[j] = 0;
+ cmv = 0.0;
+ for (i = ncol-1; i >= 0; i--) {
+ for (j = 0; j < ninks; j++) { /* Set to lowest usable number */
+ if (used[mch[i][j].x] == 0) { /* Can use this one */
+ used[mch[i][j].x] = 1; /* Now it's matched */
+ cmv += mch[i][j].v;
+ co[i] = j;
+ break; /* we assume ncol < ninks */
+ }
+ }
+ }
+
+//printf("\n~1 Initial combination has cmv = %f\n",cmv);
+//for (i = 0; i < ncol; i++)
+//printf("~1 Chan %d color = '%s'\n",i, icx_ink_table[mch[i][co[i]].x].s);
+
+ /* Set this as the best initial match */
+ for (i = 0; i < ncol; i++)
+ bco[i] = co[i];
+ bcmv = cmv;
+
+ /* Now go through all other combinations */
+ for (;;) {
+
+ /* Increment counter */
+ for (i = 0;;) {
+
+ /* Work up the digits, incrementing each one */
+ for (; i < ncol; i++) {
+ j = co[i];
+ used[mch[i][j].x] = 0;
+ cmv -= mch[i][j].v;
+ while (++j < ninks && (used[mch[i][j].x] != 0 || (cmv + mch[i][j].v) >= bcmv)) {
+ };
+ if (j < ninks) { /* No carry */
+ used[mch[i][j].x] = 1;
+ cmv += mch[i][j].v;
+ co[i] = j;
+ break;
+ }
+ /* Carry to next colorant */
+ }
+ if (i >= ncol)
+ break; /* Run out of digits to increment */
+
+ /* Now work down again, resetting digit */
+ for (--i; i >= 0; i--) {
+ for (j = 0; j < ninks; j++) { /* Set to lowest usable number */
+ if (used[mch[i][j].x] == 0 && (cmv + mch[i][j].v) < bcmv) {
+ /* Can use this one */
+ used[mch[i][j].x] = 1; /* Now it's matched */
+ cmv += mch[i][j].v;
+ co[i] = j;
+ break;
+ }
+ }
+ if (j >= ninks) { /* No combination is feasible */
+ i++; /* Go back to incrementing next highest digit */
+ break;
+ }
+ }
+ if (i < 0) /* We reset all the lower digits */
+ break; /* We're at a good combination, so done. */
+ }
+ if (i >= ncol)
+ break; /* We're done all combinations */
+
+//printf("\n~1 New combination has cmv = %f\n",cmv);
+//for (i = 0; i < ncol; i++)
+//printf("~1 Chan %d color = '%s'\n",i, icx_ink_table[mch[i][co[i]].x].s);
+
+ /* See if this is better (it always should be !) */
+ if (cmv < bcmv) {
+ for (i = 0; i < ncol; i++)
+ bco[i] = co[i];
+ bcmv = cmv;
+ }
+ }
+
+ /* Compile the result */
+ for (imask = 0, i = 0; i < ncol; i++) {
+ imask |= icx_ink_table[mch[i][bco[i]].x].m;
+ order[i] = bco[i]; /* icx ink_table index corresponding to channel */
+ }
+
+ /* Slight hack to recognise some additive combinations */
+ if (imask == ICX_WHITE)
+ imask = ICX_W;
+ else if (imask == (ICX_RED | ICX_GREEN | ICX_BLUE))
+ imask = ICX_RGB;
+
+ return imask;
+}
+
+/* Given a colorant combination mask */
+/* return the primary matching ICC colorspace signature. */
+/* return 0 if there is no match */
+icColorSpaceSignature icx_colorant_comb_to_icc(
+inkmask mask /* Colorant combination mask */
+) {
+ int i;
+
+ for (i = 0; icx_colcomb_table[i].m != 0; i++) {
+ if (mask == icx_colcomb_table[i].m)
+ return icx_colcomb_table[i].psig;
+ }
+ return 0;
+}
+
+
+
+/* - - - - - - - - - - - - - - - - - */
+/* Approximate device colorant model */
+
+/* Given device values, return an estimate of the XYZ value for that color. */
+static void icxColorantLu_to_XYZ(
+icxColorantLu *s,
+double XYZ[3], /* Output */
+double d[ICX_MXINKS] /* Input */
+) {
+ int e, j;
+
+ if (s->mask & ICX_ADDITIVE ) {
+ /* We assume a simple additive model with gamma */
+
+ XYZ[0] = XYZ[1] = XYZ[2] = 0.0;
+
+ for (e = 0; e < s->di; e++) {
+ double v = d[e];
+
+ if (v < 0.0)
+ v = 0.0;
+ else if (v > 1.0)
+ v = 1.0;
+ if (v <= 0.03928)
+ v /= 12.92;
+ else
+ v = pow((0.055 + v)/1.055, 2.4); /* Gamma */
+
+ for (j = 0; j < 3; j++)
+ XYZ[j] += v * icx_ink_table[s->iix[e]].aXYZ[j];
+ }
+
+ /* Normalise Y to 1.0, & add black glare */
+ for (j = 0; j < 3; j++) {
+ XYZ[j] *= s->Ynorm;
+ XYZ[j] = XYZ[j] * (1.0 - icx_ink_table[s->bkix].aXYZ[j]) + icx_ink_table[s->bkix].aXYZ[j];
+ }
+
+ } else {
+ /* We assume a simple screened subtractive filter model, with dot gain */
+
+ /* start with white */
+ XYZ[0] = icx_ink_table[s->whix].sXYZ[0];
+ XYZ[1] = icx_ink_table[s->whix].sXYZ[1];
+ XYZ[2] = icx_ink_table[s->whix].sXYZ[2];
+
+ /* And filter it out for each component */
+ for (e = 0; e < s->di; e++) {
+ double v = d[e];
+
+ if (v < 0.0)
+ v = 0.0;
+ else if (v > 1.0)
+ v = 1.0;
+ v = 1.0 - pow(1.0 - v, 2.2); /* Compute dot gain */
+
+ for (j = 0; j < 3; j++) {
+ double fv;
+
+ /* Normalise filtering effect of this colorant */
+ fv = icx_ink_table[s->iix[e]].aXYZ[j]/icx_ink_table[s->whix].sXYZ[j];
+
+ /* Compute screened filtering effect */
+ fv = (1.0 - v) + v * fv;
+
+ /* Apply filter to our current value */
+ XYZ[j] *= fv;
+ }
+ }
+ }
+}
+
+/* Given device values, return an estimate of the */
+/* relative Lab value for that color. */
+static void icxColorantLu_to_rLab(
+icxColorantLu *s,
+double Lab[3], /* Output */
+double d[ICX_MXINKS] /* Input */
+) {
+
+ icxColorantLu_to_XYZ(s, Lab, d); /* Compute XYZ */
+ icmXYZ2Lab(&s->wp, Lab, Lab); /* Convert from XYZ to Lab */
+}
+
+/* We're done with aproximate device model */
+static void icxColorantLu_del(icxColorantLu *s) {
+
+ if (s != NULL) {
+ free(s);
+ }
+}
+
+/* Given an ink definition, return an aproximate */
+/* device to CIE color converted object. */
+icxColorantLu *new_icxColorantLu(inkmask mask) {
+ int i, e;
+ icxColorantLu *s;
+
+ if ((s = (icxColorantLu *)malloc(sizeof(icxColorantLu))) == NULL) {
+ fprintf(stderr,"icxColorantLu: malloc failed allocating object\n");
+ exit(-1);
+ }
+
+ /* Initialise methods */
+ s->del = icxColorantLu_del;
+ s->dev_to_XYZ = icxColorantLu_to_XYZ;
+ s->dev_to_rLab = icxColorantLu_to_rLab;
+
+ /* Init */
+ s->mask = mask;
+
+ for (e = i = 0; icx_ink_table[i].m != 0; i++) {
+ if (ICX_WHITE == icx_ink_table[i].m)
+ s->whix = i;
+ if (ICX_BLACK == icx_ink_table[i].m)
+ s->bkix = i;
+ if (mask & icx_ink_table[i].m)
+ s->iix[e++] = i;
+ }
+ s->di = e;
+
+
+ s->Ynorm = 0.0;
+ if (mask & ICX_ADDITIVE ) {
+ for (e = 0; e < s->di; e++)
+ s->Ynorm += icx_ink_table[s->iix[e]].aXYZ[1];
+ s->Ynorm = 1.0/s->Ynorm;
+ icmAry2XYZ(s->wp, icx_ink_table[s->whix].aXYZ);
+ } else {
+ icmAry2XYZ(s->wp, icx_ink_table[s->whix].sXYZ);
+ }
+
+ return s;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xcolorants.h b/xicc/xcolorants.h
new file mode 100644
index 0000000..460c4b0
--- /dev/null
+++ b/xicc/xcolorants.h
@@ -0,0 +1,326 @@
+#ifndef XCOLORANTS_H
+#define XCOLORANTS_H
+/*
+ * International Color Consortium color transform expanded support
+ * Known colorant definitions.
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/2/2002
+ * Version: 1.00
+ *
+ * Copyright 2002 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.
+ *
+ */
+
+/* Some standard defines for known generic ink colors */
+
+/*
+ Note that we don't handle the issue of an arbitrary ink order,
+ and we are only partially coping with multi-ink ICC profiles
+ mapping to xcolorants and back. This is supported by mapping
+ inkmask to ICC ColorantTable names and back (if needed),
+ or by guessing colorants to match profile (icx_icc_cv_to_colorant_comb()).
+
+ default xcolorant order matches the concrete ICC order, but
+ ICC icSigXXcolorData could be in any order, and xcolorants
+ currently doesn't handle it.
+
+ One way of encapsulating things would be to change inkmask to:
+
+ struct {
+ unsigned int attr; // Attributes (ie. Additive)
+ unsigned int mask[(ICX_MXINKS + 31)/32]; // Ink masks
+ int inks[MAX_CHAN]; // icx_ink_table[] index
+ } inkmask;
+
+ Then add appropriate macros & functions to replace current bit mask logic.
+
+ Would it be easier to make all Argyll internal handling conform
+ to the standard xcolorants order, and translate in the ICC file I/O ?
+ MPP and .ti? files are assumed/made to conform to xcolorants order.
+
+ Another change would be to make xcolorants an object,
+ with dynamic colorant and colorant combination values.
+ These would be initialised to defaults, but could then
+ be added to at run time.
+
+ Handling the "colorant" of non-device type color channels
+ is also a challenge (ie., Lab, Hsv etc.)
+
+ */
+
+/* Maximum number of simultanious inks allowed for */
+#define ICX_MXINKS 31
+
+/* Note that new inks need to be added to icx_ink_table[] in xcolorants.c ! */
+
+/* The type of the inkmask (allow for expansion) */
+typedef unsigned int inkmask;
+
+/* The ink mask enumeration */
+#define ICX_ADDITIVE 0x80000000 /* Special flag indicating addive colorants */
+#define ICX_INVERTED 0x40000000 /* Special flag indicating actual device is */
+ /* the inverse of the perported additive/subtractive */
+#define ICX_CYAN 0x00000001
+#define ICX_MAGENTA 0x00000002
+#define ICX_YELLOW 0x00000004
+#define ICX_BLACK 0x00000008
+#define ICX_ORANGE 0x00000010
+#define ICX_RED 0x00000020
+#define ICX_GREEN 0x00000040
+#define ICX_BLUE 0x00000080
+#define ICX_WHITE 0x00000100
+#define ICX_LIGHT_CYAN 0x00010000
+#define ICX_LIGHT_MAGENTA 0x00020000
+#define ICX_LIGHT_YELLOW 0x00040000
+#define ICX_LIGHT_BLACK 0x00080000
+#define ICX_MEDIUM_CYAN 0x00100000
+#define ICX_MEDIUM_MAGENTA 0x00200000
+#define ICX_MEDIUM_YELLOW 0x00400000
+#define ICX_MEDIUM_BLACK 0x00800000
+#define ICX_LIGHT_LIGHT_BLACK 0x01000000
+
+/* Character representation */
+#define ICX_C_CYAN "C"
+#define ICX_C_MAGENTA "M"
+#define ICX_C_YELLOW "Y"
+#define ICX_C_BLACK "K"
+#define ICX_C_ORANGE "O"
+#define ICX_C_RED "R"
+#define ICX_C_GREEN "G"
+#define ICX_C_BLUE "B"
+#define ICX_C_WHITE "W"
+#define ICX_C_LIGHT_CYAN "c"
+#define ICX_C_LIGHT_MAGENTA "m"
+#define ICX_C_LIGHT_YELLOW "y"
+#define ICX_C_LIGHT_BLACK "k"
+#define ICX_C_MEDIUM_CYAN "2c"
+#define ICX_C_MEDIUM_MAGENTA "2m"
+#define ICX_C_MEDIUM_YELLOW "2y"
+#define ICX_C_MEDIUM_BLACK "2k"
+#define ICX_C_LIGHT_LIGHT_BLACK "1k"
+
+/* Everyday String representation (max 31 chars) */
+#define ICX_S_CYAN "Cyan"
+#define ICX_S_MAGENTA "Magenta"
+#define ICX_S_YELLOW "Yellow"
+#define ICX_S_BLACK "Black"
+#define ICX_S_ORANGE "Orange"
+#define ICX_S_RED "Red"
+#define ICX_S_GREEN "Green"
+#define ICX_S_BLUE "Blue"
+#define ICX_S_WHITE "White"
+#define ICX_S_LIGHT_CYAN "Light Cyan"
+#define ICX_S_LIGHT_MAGENTA "Light Magenta"
+#define ICX_S_LIGHT_YELLOW "Light Yellow"
+#define ICX_S_LIGHT_BLACK "Light Black"
+#define ICX_S_MEDIUM_CYAN "Medium Cyan"
+#define ICX_S_MEDIUM_MAGENTA "Medium Magenta"
+#define ICX_S_MEDIUM_YELLOW "Medium Yellow"
+#define ICX_S_MEDIUM_BLACK "Medium Black"
+#define ICX_S_LIGHT_LIGHT_BLACK "Light Light Black"
+
+/* Postscript string representation */
+#define ICX_PS_CYAN "Cyan"
+#define ICX_PS_MAGENTA "Magenta"
+#define ICX_PS_YELLOW "Yellow"
+#define ICX_PS_BLACK "Black"
+#define ICX_PS_ORANGE "Orange"
+#define ICX_PS_RED "Red"
+#define ICX_PS_GREEN "Green"
+#define ICX_PS_BLUE "Blue"
+#define ICX_PS_WHITE "White"
+#define ICX_PS_LIGHT_CYAN "LightCyan"
+#define ICX_PS_LIGHT_MAGENTA "LightMagenta"
+#define ICX_PS_LIGHT_YELLOW "LightYellow"
+#define ICX_PS_LIGHT_BLACK "LightBlack"
+#define ICX_PS_MEDIUM_CYAN "MediumCyan"
+#define ICX_PS_MEDIUM_MAGENTA "MediumMagenta"
+#define ICX_PS_MEDIUM_YELLOW "MediumYellow"
+#define ICX_PS_MEDIUM_BLACK "MediumBlack"
+#define ICX_PS_LIGHT_LIGHT_BLACK "LightLightBlack"
+
+/* Common colorant combinations */
+#define ICX_W /* Video style "grey" */ \
+ (ICX_ADDITIVE | ICX_WHITE)
+
+#define ICX_RGB /* Classic video RGB */ \
+ (ICX_ADDITIVE | ICX_RED | ICX_GREEN | ICX_BLUE)
+
+#define ICX_K /* Printer style "grey" */ \
+ (ICX_BLACK)
+
+#define ICX_CMY /* Classic printing CMY */ \
+ (ICX_CYAN | ICX_MAGENTA | ICX_YELLOW)
+
+#define ICX_IRGB /* Fake printer RGB (== Inverted CMY) */ \
+ (ICX_ADDITIVE | ICX_INVERTED | ICX_RED | ICX_GREEN | ICX_BLUE)
+
+#define ICX_CMYK /* Classic printing CMYK */ \
+ (ICX_CYAN | ICX_MAGENTA | ICX_YELLOW | ICX_BLACK)
+
+#define ICX_CMYKcm /* Your bog standard "6 color" printers */ \
+ ( ICX_CYAN | ICX_MAGENTA | ICX_YELLOW | ICX_BLACK \
+ | ICX_LIGHT_CYAN | ICX_LIGHT_MAGENTA)
+
+#define ICX_CMYKcmk /* A more unusual "7 color" printer */ \
+ ( ICX_CYAN | ICX_MAGENTA | ICX_YELLOW | ICX_BLACK \
+ | ICX_LIGHT_CYAN | ICX_LIGHT_MAGENTA | ICX_LIGHT_BLACK)
+
+#define ICX_CMYKcmk1k /* A more unusual "8 color" printer */ \
+ ( ICX_CYAN | ICX_MAGENTA | ICX_YELLOW | ICX_BLACK \
+ | ICX_LIGHT_CYAN | ICX_LIGHT_MAGENTA | ICX_LIGHT_BLACK \
+ | ICX_LIGHT_LIGHT_BLACK)
+
+#define ICX_CMYKOG /* A "hexachrome" style extended gamut printer */ \
+ ( ICX_CYAN | ICX_MAGENTA | ICX_YELLOW | ICX_BLACK \
+ | ICX_ORANGE | ICX_GREEN)
+
+#define ICX_CMYKRB /* A 6 color printer with red and blue. */ \
+ ( ICX_CYAN | ICX_MAGENTA | ICX_YELLOW | ICX_BLACK \
+ | ICX_RED | ICX_BLUE)
+
+#define ICX_CMYKOGcm /* An 8 color extended gamut printer */ \
+ ( ICX_CYAN | ICX_MAGENTA | ICX_YELLOW | ICX_BLACK \
+ | ICX_ORANGE | ICX_GREEN | ICX_LIGHT_CYAN | ICX_LIGHT_MAGENTA)
+
+#define ICX_CMYKcm2c2m /* An 8 color printer that wishes it had variable dot size */ \
+ ( ICX_CYAN | ICX_MAGENTA | ICX_YELLOW | ICX_BLACK \
+ | ICX_LIGHT_CYAN | ICX_LIGHT_MAGENTA | ICX_MEDIUM_CYAN | ICX_MEDIUM_MAGENTA)
+
+/* ------------------------------------------ */
+
+/* Given an ink combination mask, return the number of recognised inks in it */
+int icx_noofinks(inkmask mask);
+
+/* Given an ink combination mask, return the 1-2 character based string */
+/* If winv is nz, include ICX_INVERTED indicator if set */
+/* Return NULL on error. free() after use */
+char *icx_inkmask2char(inkmask mask, int winv);
+
+/* Given the 1-2 character based string, return the ink combination mask */
+/* Note that ICX_ADDITIVE will be guessed */
+/* Return 0 if unrecognised character in string */
+inkmask icx_char2inkmask(char *chstring);
+
+/* Given an ink combination mask that may contain light inks, */
+/* return the corresponding ink mask without light inks. */
+/* Return 0 if ink combination not recognised. */
+inkmask icx_ink2primary_ink(inkmask mask);
+
+
+/* Given an ink combination mask and a single ink mask, */
+/* return the index number for that ink. */
+/* Return -1 if mask1 not in mask */
+int icx_ink2index(inkmask mask, inkmask mask1);
+
+/* Given an ink combination mask and a index number, */
+/* return the single ink mask. */
+/* Return 0 if there are no inks at that index */
+inkmask icx_index2ink(inkmask mask, int ixno);
+
+
+/* Given a single ink mask, */
+/* return its string representation */
+char *icx_ink2string(inkmask mask);
+
+/* Given a single ink mask, */
+/* return its 1-2 character representation */
+char *icx_ink2char(inkmask mask);
+
+/* Given a single ink mask, */
+/* return its Postscript string representation */
+char *icx_ink2psstring(inkmask mask);
+
+
+/* Return an enumerated single colorant description */
+/* Return 0 if no such enumeration, single colorant mask if there is */
+inkmask icx_enum_colorant(int no, char **desc);
+
+/* Return an enumerated colorant combination inkmask and description */
+/* Return 0 if no such enumeration, colorant combination mask if there is */
+inkmask icx_enum_colorant_comb(int no, char **desc);
+
+
+/* Given an colorant combination mask, */
+/* check if it matches the given ICC colorspace signature. */
+/* return NZ if it does. */
+int icx_colorant_comb_match_icc(inkmask mask, icColorSpaceSignature sig);
+
+/* Given an ICC colorspace signature, return the appropriate */
+/* colorant combination mask. Return 0 if ambiguous signature. */
+inkmask icx_icc_to_colorant_comb(icColorSpaceSignature sig, icProfileClassSignature deviceClass);
+
+/* Given an ICC colorspace signature, and a matching list */
+/* of the D50 L*a*b* colors of the colorants, return the best matching */
+/* colorant combination mask. Return 0 if not applicable to colorspace. */
+inkmask icx_icc_cv_to_colorant_comb(icColorSpaceSignature sig, icProfileClassSignature deviceClass,
+ double cvals[][3]);
+
+/* Given an colorant combination mask */
+/* return the primary matching ICC colorspace signature. */
+/* return 0 if there is no match */
+icColorSpaceSignature icx_colorant_comb_to_icc(inkmask mask);
+
+/* --------------------------------------------------------- */
+/* An aproximate device colorant model object lookup object: */
+
+struct _icxColorantLu {
+/* Public: */
+ void (*del)(struct _icxColorantLu *s); /* We're done with it */
+
+ /* Conversions */
+ void (*dev_to_XYZ)(struct _icxColorantLu *s, double *out, double *in); /* Absolute */
+ void (*dev_to_rLab)(struct _icxColorantLu *s, double *out, double *in); /* Relative */
+
+/* Private: */
+ inkmask mask; /* Colorant mask for this instance */
+ int di; /* Dimensionality */
+ int whix, bkix; /* White and Black Indexes into icx_inkTable[] */
+ icmXYZNumber wp; /* White point XYZ value */
+ int iix[ICX_MXINKS]; /* Device Indexes into icx_inkTable[] */
+ double Ynorm; /* Y normalisation factor for Additive */
+}; typedef struct _icxColorantLu icxColorantLu;
+
+/* Create a icxColorantLu conversion object */
+icxColorantLu *new_icxColorantLu(inkmask mask);
+
+#endif /* XCOLORANTS_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xcolorantslu.c b/xicc/xcolorantslu.c
new file mode 100644
index 0000000..6c537dc
--- /dev/null
+++ b/xicc/xcolorantslu.c
@@ -0,0 +1,228 @@
+
+/*
+ * xcolorant lookup/test utility
+ *
+ * Author: Graeme W. Gill
+ * Date: 24/4/2002
+ * Version: 1.00
+ *
+ * Copyright 2002 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.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+#include "xcolorants.h"
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+void usage(void) {
+ fprintf(stderr,"Translate colors through xcolorant model, V1.00\n");
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: xcolorantlu \n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -a Additive model (default subtractive)\n");
+ fprintf(stderr," -m mask Colorant mask combination, from:\n");
+ fprintf(stderr," C Cyan\n");
+ fprintf(stderr," M Magenta\n");
+ fprintf(stderr," Y Yellow\n");
+ fprintf(stderr," K Black\n");
+ fprintf(stderr," O Orange\n");
+ fprintf(stderr," R Red\n");
+ fprintf(stderr," G Green\n");
+ fprintf(stderr," B Blue\n");
+ fprintf(stderr," W White\n");
+ fprintf(stderr," c Light Cyan\n");
+ fprintf(stderr," m Light Magenta\n");
+ fprintf(stderr," y Light Yellow\n");
+ fprintf(stderr," k Light Black\n");
+ fprintf(stderr," 2c Medium Cyan\n");
+ fprintf(stderr," 2m Medium Magenta\n");
+ fprintf(stderr," 2y Medium Yellow\n");
+ fprintf(stderr," 2k Medium Black\n");
+ fprintf(stderr," -x XYZ output (default L*a*b*)\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr," The colors to be translated should be fed into stdin,\n");
+ fprintf(stderr," one input color per line, white space separated.\n");
+ fprintf(stderr," A line starting with a # will be ignored.\n");
+ fprintf(stderr," A line not starting with a number will terminate the program.\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int rv = 0;
+ int mask = 0;
+ int xyz = 0;
+ char buf[200];
+ double in[MAX_CHAN], out[MAX_CHAN];
+ int inn, outn = 3;
+ icxColorantLu *luo;
+ char *ident;
+ char *odent;
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage();
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+
+ /* Additive */
+ else if (argv[fa][1] == 'a' || argv[fa][1] == 'A') {
+ mask ^= ICX_ADDITIVE;
+ }
+
+ /* XYZ output */
+ else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') {
+ verb = 1;
+ }
+
+ /* Mask */
+ else if (argv[fa][1] == 'm' || argv[fa][1] == 'm') {
+ int tm;
+ fa = nfa;
+ if (na == NULL) usage();
+ if ((tm = icx_char2inkmask(na)) == 0)
+ usage();
+ mask ^= tm;
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ inn = icx_noofinks(mask);
+
+ /* Create a icxColorantLu conversion object */
+ if ((luo = new_icxColorantLu(mask)) == NULL)
+ error ("Creating xcolorant lookup failed\n");
+
+ ident = icx_inkmask2char(mask, 1);
+ if (xyz)
+ odent = "XYZ";
+ else
+ odent = "Lab";
+
+ /* Process colors to translate */
+ for (;;) {
+ int i,j;
+ char *bp, *nbp;
+
+ /* Read in the next line */
+ if (fgets(buf, 200, stdin) == NULL)
+ break;
+ if (buf[0] == '#') {
+ fprintf(stdout,"%s\n",buf);
+ continue;
+ }
+ /* For each input number */
+ for (bp = buf-1, nbp = buf, i = 0; i < MAX_CHAN; i++) {
+ bp = nbp;
+ in[i] = strtod(bp, &nbp);
+ if (nbp == bp)
+ break; /* Failed */
+ }
+ if (i == 0)
+ break;
+
+ /* Do conversion */
+ if (xyz)
+ luo->dev_to_XYZ(luo, out, in);
+ else
+ luo->dev_to_rLab(luo, out, in);
+
+ /* Output the results */
+ for (j = 0; j < inn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",in[j]);
+ else
+ fprintf(stdout,"%f",in[j]);
+ }
+ printf(" [%s] -> ", ident);
+
+ for (j = 0; j < outn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",out[j]);
+ else
+ fprintf(stdout,"%f",out[j]);
+ }
+ printf(" [%s]", odent);
+
+ if (rv == 0)
+ fprintf(stdout,"\n");
+ else
+ fprintf(stdout," (clip)\n");
+
+ }
+
+ /* Done with lookup object */
+ luo->del(luo);
+ free(ident);
+
+ return 0;
+}
+
+
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icclu: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icclu: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
diff --git a/xicc/xdevlin.c b/xicc/xdevlin.c
new file mode 100644
index 0000000..a5f7bd6
--- /dev/null
+++ b/xicc/xdevlin.c
@@ -0,0 +1,299 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 8/9/01
+ * Version: 1.00
+ *
+ * Copyright 2001 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.
+ *
+ */
+
+/* TTBD:
+ *
+ * Should switch this over to the linearisation used in
+ * the current xlut.c (== xlut2.c), rather than linearise
+ * w.r.t. the Y value.
+ */
+
+/*
+ * This class handles the creation of device chanel linearisation
+ * curves, given a callback function that maps the device chanels
+ * to the value that should be linearised.
+ *
+ * This class is independent of other icc or icx classes.
+ *
+ * Its usual use is to create an Lab linerisation curve
+ * for native XYZ profiles.
+ */
+
+#undef DEBUG /* Plot 1d Luts */
+
+#include <sys/types.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#include "numlib.h"
+#include "rspl.h"
+#include "xdevlin.h" /* definitions for this class */
+
+#ifdef DEBUG
+#include "plot.h"
+#endif
+
+/* Free up the xdevlin */
+static void xdevlin_del(struct _xdevlin *p) {
+ int e;
+ for (e = 0; e < p->di; e++) {
+ if (p->curves[e] != NULL)
+ p->curves[e]->del(p->curves[e]);
+ }
+ free (p);
+}
+
+/* Return the linearisation values given the device values */
+static void xdevlin_lin(
+struct _xdevlin *p, /* this */
+double *out, /* di input */
+double *in /* di output */
+) {
+ co tc;
+ int e;
+ for (e = 0; e < p->di; e++) {
+ tc.p[0] = in[e];
+ p->curves[e]->interp(p->curves[e], &tc);
+ out[e] = tc.v[0];
+ }
+}
+
+#define MAX_INVSOLN 5
+
+/* Return the inverse linearisation */
+static void xdevlin_invlin(
+struct _xdevlin *p, /* this */
+double *out, /* di input */
+double *in /* di output */
+) {
+ int i, j;
+ int nsoln; /* Number of solutions found */
+ co pp[MAX_INVSOLN]; /* Room for all the solutions found */
+ double cdir;
+
+ for (i = 0; i < p->di; i++) {
+ pp[0].p[0] = p->clipc[i];
+ pp[0].v[0] = in[i];
+ cdir = p->clipc[i] - in[i]; /* Clip towards output range */
+
+ nsoln = p->curves[i]->rev_interp (
+ p->curves[i], /* this */
+ 0, /* No flags */
+ MAX_INVSOLN, /* Maximum number of solutions allowed for */
+ NULL, /* No auxiliary input targets */
+ &cdir, /* Clip vector direction and length */
+ pp); /* Input and output values */
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln == 1) { /* Exactly one solution */
+ j = 0;
+ } else if (nsoln == 0) { /* Zero solutions. This is unexpected. */
+ error("~~~1 Unexpected failure to find reverse solution for linearisation curve");
+ return;
+ } else { /* Multiple solutions */
+ /* Use a simple minded resolution - choose the one closest to the center */
+ double bdist = 1e300;
+ int bsoln = 0;
+/* Don't expect this - 1D luts are meant to be monotonic */
+printf("~~~1 got %d reverse solutions\n",nsoln);
+printf("~~~1 solution 0 = %f\n",pp[0].p[0]);
+printf("~~~1 solution 1 = %f\n",pp[1].p[0]);
+ for (j = 0; j < nsoln; j++) {
+ double tt;
+ tt = pp[i].p[0] - p->clipc[i];
+ tt *= tt;
+ if (tt < bdist) { /* Better solution */
+ bdist = tt;
+ bsoln = j;
+ }
+ }
+ j = bsoln;
+ }
+ out[i] = pp[j].p[0];
+ }
+}
+
+/* Callback function that is used to set each chanels grid value */
+static void set_curve(void *cbntx, double *out, double *in) {
+ xdevlin *p = (xdevlin *)cbntx;
+ int e, ee = p->setch;
+ double tin[MXDI], tout[MXDO];
+ double tt;
+
+ /* setup input value */
+ for (e = 0; e < p->di; e++)
+ tin[e] = p->pol ? p->max[e] : p->min[e];
+ tin[ee] = in[0];
+
+ p->lookup(p->lucntx, tout, tin);
+
+ tt = (tout[0] - p->lmin)/(p->lmax - p->lmin); /* Normalise from L */
+
+ out[0] = tt * (p->max[ee] - p->min[ee]) + p->min[ee]; /* Back to device range */
+}
+
+/* Create an appropriate linearisation from the callback */
+/* This code is very similar to that in xlut.c when creating */
+/* a device profiles linearisation curves. */
+xdevlin *new_xdevlin(
+int di, /* Device dimenstionality */
+double *min, double *max, /* Min & max range of device values, NULL = 0.0 - 1.0 */
+void *lucntx, /* Context for callback */
+void (*lookup) (void *lucntx, double *lin, double *dev)
+) {
+ int ee, e;
+ xdevlin *p;
+
+ /* Do the basic class initialisation */
+ if ((p = (xdevlin *) calloc(1,sizeof(xdevlin))) == NULL)
+ return NULL;
+ p->del = xdevlin_del;
+ p->lin = xdevlin_lin;
+ p->invlin = xdevlin_invlin;
+
+ /* And then set it up */
+ p->di = di;
+ p->lucntx = lucntx;
+ p->lookup = lookup;
+
+ /* Setup the clipping center */
+ for (e = 0; e < p->di; e++) {
+ p->min[e] = min[e];
+ p->max[e] = max[e];
+ p->clipc[e] = 0.5 * (min[e] + max[e]);
+ }
+
+ /* Determine what level to set the chanels we're not interested in */
+ {
+ double tin[MXDI], tout[MXDO];
+ double l00, l01, l10, l11; /* Resulting levels */
+
+ for (e = 0; e < p->di; e++)
+ tin[e] = min[e];
+ lookup(lucntx, tout, tin);
+ l00 = tout[0]; /* All minimum */
+
+ tin[0] = max[0];
+ lookup(lucntx, tout, tin);
+ l01 = tout[0]; /* First chanel max, rest min */
+
+ for (e = 0; e < p->di; e++)
+ tin[e] = max[e];
+ lookup(lucntx, tout, tin);
+ l11 = tout[0]; /* All maximum */
+
+ tin[0] = min[0];
+ lookup(lucntx, tout, tin);
+ l10 = tout[0]; /* First chanel min, rest max */
+
+ if (fabs(l11 - l10) > fabs(l00 - l01))
+ p->pol = 1; /* Set other chanels to max */
+ else
+ p->pol = 0; /* Set other chanels to min */
+ }
+
+ /* For each chanel, create an rspl */
+
+ for (ee = 0; ee < p->di; ee++) {
+ double tin[MXDI], tout[MXDO];
+ int gres = 100; // 4096
+#ifdef DEBUG
+ #define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+#endif /* DEBUG */
+
+ if ((p->curves[ee] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ error("Creation of rspl failed in xdevlin");
+ }
+
+ p->setch = ee;
+
+ /* Figure the L min and max */
+ for (e = 0; e < p->di; e++)
+ tin[e] = p->pol ? max[e] : min[e];
+ tin[ee] = min[ee];
+ lookup(lucntx, tout, tin);
+ p->lmin = tout[0];
+ tin[ee] = max[ee];
+ lookup(lucntx, tout, tin);
+ p->lmax = tout[0];
+
+ p->curves[ee]->set_rspl(
+ p->curves[ee],
+ 0,
+ p, /* Opaque function context */
+ set_curve, /* Function to set from */
+ min, max, /* Grid low scale, grid high scale */
+ &gres, /* Grid resolution */
+ min, max /* Data value normalsie low and high */
+ );
+
+#ifdef DEBUG
+ {
+ int i;
+ /* Display the result curve */
+ for (i = 0; i < XRES; i++) {
+ double x;
+ co c;
+ x = i/(double)(XRES-1);
+ xx[i] = x;
+ c.p[0] = x;
+ p->curves[ee]->interp(p->curves[ee], &c);
+ y1[i] = c.v[0];
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+#endif /* DEBUG */
+
+ }
+
+ p->lookup = NULL; /* Not valid after function return */
+ return p;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xdevlin.h b/xicc/xdevlin.h
new file mode 100644
index 0000000..7e51e40
--- /dev/null
+++ b/xicc/xdevlin.h
@@ -0,0 +1,96 @@
+#ifndef XDEVLIN_H
+#define XDEVLIN_H
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 29/8/01
+ * Version: 1.00
+ *
+ * Copyright 2001 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.
+ *
+ */
+
+/*
+ * This class handles the creation of device chanel linearisation
+ * curves, given a callback function that maps the device chanels
+ * to the value that should be linearised.
+ *
+ * This class is independent of other icc or icx classes.
+ *
+ * Its usual use is to create an Lab linerisation curve
+ * for native XYZ profiles.
+ */
+
+/* The device linearisation class */
+struct _xdevlin {
+
+ /* Private: */
+ int di; /* Device dimentionality */
+ rspl *curves[MXDI]; /* di Linearisation curves */
+ double clipc[MXDI]; /* center of device range */
+ double min[MXDI], max[MXDI]; /* Device chanel min/max */
+ int pol; /* Polarity, 0 for minimise other chanels */
+ int setch; /* Chanel to set */
+ double lmin, lmax; /* Linear min & max to rescale */
+ void *lucntx; /* Lookup context */
+ void (*lookup) (void *lucntx, double *lin, double *dev); /* Callback function */
+
+ /* Public: */
+ void (*del)(struct _xdevlin *p);
+
+ /* Return the linearisation values given the device values */
+ void (*lin)(struct _xdevlin *p, double *out, double *in);
+
+ /* Return the inverse linearisation */
+ void (*invlin)(struct _xdevlin *p, double *out, double *in);
+
+}; typedef struct _xdevlin xdevlin;
+
+xdevlin *new_xdevlin(
+ int di, /* Device dimenstionality */
+ double *min, double *max, /* Min & max range of device values, NULL = 0.0 - 1.0 */
+ void *cntx, /* Context for callback */
+ void (*lookup) (void *cntx, double lin[MXDO], double dev[MXDI])
+ /* Callback function, return linear parameter as lin[0] */
+);
+
+#endif /* XDEVLIN_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xdgb.c b/xicc/xdgb.c
new file mode 100644
index 0000000..80914b8
--- /dev/null
+++ b/xicc/xdgb.c
@@ -0,0 +1,109 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ * eXpanded Device Gamut Boundary support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/11/17
+ * Version: 1.00
+ *
+ * Copyright 2008 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.
+ */
+
+/*
+ * This module provides device gamut boundary functionality used to
+ * locate the non-monotonic device boundary surface, enabling
+ * fast and accurate PCS gamut boundary plotting as well (for CMYK)
+ * as allowing the location of device boundary overlaps, so that they
+ * can be eliminated. This also allows rapid K min/max finding,
+ * and rapid smoothed K map creation.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "rspl.h"
+#include "xicc.h"
+#include "plot.h"
+#include "xdgb.h"
+#include "sort.h"
+
+
+/*
+ * TTBD:
+ *
+ */
+
+#undef DEBUG /* Verbose debug information */
+
+/* - - - - - - - - - - - - - - - - - */
+
+/* Diagnostic */
+static void plot_xdgb(
+xdgb *p
+) {
+}
+
+/* - - - - - - - - - */
+
+/* - - - - - - - - - */
+/* create the device surface points. */
+/* return nz on error */
+int xdgb_fit(
+ struct _xdgb *p,
+ int flags, /* Flag values */
+ int di, /* Input dimensions */
+ int fdi /* Output dimensions */
+) {
+ int i, e, f;
+ double *b; /* Base of parameters for this section */
+ int poff;
+
+ p->flags = flags;
+ if (flags & XDGB_VERB)
+ p->verb = 1;
+ else
+ p->verb = 0;
+ p->di = di;
+ p->fdi = fdi;
+
+#ifdef DEBUG
+ printf("xdgbc called with flags = 0x%x, di = %d, fdi = %d\n",flags,di,fdi);
+#endif
+
+ return 0;
+}
+
+/* We're done with an xdgb */
+static void xdgb_del(xdgb *p) {
+ free(p);
+}
+
+/* Create a transform fitting object */
+/* return NULL on error */
+xdgb *new_xdgb(
+) {
+ xdgb *p;
+
+ if ((p = (xdgb *)calloc(1, sizeof(xdgb))) == NULL) {
+ return NULL;
+ }
+
+ /* Set method pointers */
+ p->del = xdgb_del;
+
+ return p;
+}
+
+
+
diff --git a/xicc/xdgb.h b/xicc/xdgb.h
new file mode 100644
index 0000000..bfb1752
--- /dev/null
+++ b/xicc/xdgb.h
@@ -0,0 +1,71 @@
+
+#ifndef XDGB_H
+#define XDGB_H
+
+/*
+ * International Color Consortium color transform expanded support
+ * eXpanded Device Gamut Boundary support.
+ *
+ * Author: Graeme W. Gill
+ * Date: 2008/11/17
+ * Version: 1.00
+ *
+ * Copyright 2008 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.
+ */
+
+/* Flag values */
+#define XDGB_VERB 0x0001 /* Verbose output during fitting */
+
+
+/* Object holding device gamut representation */
+struct _xdgb {
+ int verb; /* Verbose */
+ int flags; /* Behaviour flags */
+ int di, fdi; /* Dimensionaluty of input and output */
+
+ /* Methods */
+ void (*del)(struct _xdgb *p);
+
+}; typedef struct _xdgb xdgb;
+
+xdgb *new_xdgb();
+
+#endif /* XDGB_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xfbview.c b/xicc/xfbview.c
new file mode 100644
index 0000000..6abf176
--- /dev/null
+++ b/xicc/xfbview.c
@@ -0,0 +1,703 @@
+
+/*
+ * View inv fwd table device interp of an ICC file, V1.23\n");
+ *
+ * Author: Graeme W. Gill
+ * Date: 2000/12/8
+ * Version: 1.23
+ *
+ * Copyright 2000 Graeme W. Gill
+ * Please refer to License.txt file for details.
+ */
+
+/* TTBD:
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "xicc.h"
+
+#define RW 0.5 /* Device Delta */
+
+/* - - - - - - - - - - - - - */
+
+/* Return maximum difference */
+double maxdiff(double in1[3], double in2[3]) {
+ double tt, rv = 0.0;
+ if ((tt = fabs(in1[0] - in2[0])) > rv)
+ rv = tt;
+ if ((tt = fabs(in1[1] - in2[1])) > rv)
+ rv = tt;
+ if ((tt = fabs(in1[2] - in2[2])) > rv)
+ rv = tt;
+ return rv;
+}
+
+/* Return absolute difference */
+double absdiff(double in1[3], double in2[3]) {
+ double tt, rv = 0.0;
+ tt = in1[0] - in2[0];
+ rv += tt * tt;
+ tt = in1[1] - in2[1];
+ rv += tt * tt;
+ tt = in1[2] - in2[2];
+ rv += tt * tt;
+ return sqrt(rv);
+}
+
+/* ---------------------------------------- */
+
+void usage(void) {
+ fprintf(stderr,"View inv fwd table device interp of an ICC file, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: fbtest [options] infile\n");
+ fprintf(stderr," -v verbose\n");
+ fprintf(stderr," -f Show PCS target -> reference clipped PCS vectors\n");
+ fprintf(stderr," -d Show PCS target -> average of device ref clippped PCS\n");
+ fprintf(stderr," -b Show PCS target -> B2A lookup clipped PCS\n");
+ fprintf(stderr," -e Show reference cliped PCS -> B2A lookup clipped PCS\n");
+ fprintf(stderr," -r res Resolution of test grid\n");
+ fprintf(stderr," -g Do full grid, not just L = 0\n");
+ fprintf(stderr," -c Do all values, not just clipped ones\n");
+ fprintf(stderr," -l tlimit set total ink limit, 0 - 400%% (estimate by default)\n");
+ fprintf(stderr," -L klimit set black ink limit, 0 - 100%% (estimate by default)\n");
+ exit(1);
+}
+
+int
+main(
+ int argc,
+ char *argv[]
+) {
+ int fa,nfa; /* argument we're looking at */
+ int verb = 0;
+ int doaxes = 0;
+ double tlimit = -1.0; /* Total ink limit */
+ double klimit = -1.0; /* Black ink limit */
+ int tres = 33;
+ int doref = 0; /* Show reference lookups */
+ int dodelta = 0; /* Show device interp delta variation */
+ int dob2a = 0; /* Show B2A lookups */
+ int doeee = 0; /* Show clipped ref PCS to B2A clipped PCS */
+ int dilzero = 1; /* Do just L = 0 plane */
+ int doclip = 1; /* Do just clipped values */
+ char in_name[100];
+ char *xl, out_name[100];
+ icmFile *rd_fp;
+ icc *rd_icco;
+ int rv = 0;
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage();
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ /* Verbosity */
+ if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ verb = 1;
+ }
+ /* Show reference */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ doref = 1;
+ }
+ /* Show device delta variation */
+ else if (argv[fa][1] == 'd' || argv[fa][1] == 'D') {
+ dodelta = 1;
+ }
+ /* Show B2A table lookup */
+ else if (argv[fa][1] == 'b' || argv[fa][1] == 'B') {
+ dob2a = 1;
+ }
+ /* Show reference clipped PCS to clipped B2A PCS */
+ else if (argv[fa][1] == 'e' || argv[fa][1] == 'E') {
+ doeee = 1;
+ }
+ /* Do the full grid, not just L = 0 */
+ else if (argv[fa][1] == 'g' || argv[fa][1] == 'G') {
+ dilzero = 0;
+ }
+ /* Do all values, not just clipped ones */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ doclip = 0;
+ }
+ /* Ink limit */
+ else if (argv[fa][1] == 'l') {
+ fa = nfa;
+ if (na == NULL) usage();
+ tlimit = atoi(na)/100.0;
+ }
+ else if (argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage();
+ klimit = atoi(na)/100.0;
+ }
+
+ /* Resolution */
+ else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') {
+ fa = nfa;
+ if (na == NULL) usage();
+ tres = atoi(na);
+ }
+
+ else if (argv[fa][1] == '?')
+ usage();
+ else
+ usage();
+ }
+ else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa]);
+
+ strcpy(out_name, in_name);
+ if ((xl = strrchr(out_name, '.')) == NULL) /* Figure where extention is */
+ xl = out_name + strlen(out_name);
+ strcpy(xl,".wrl");
+
+ /* Open up the file for reading */
+ if ((rd_fp = new_icmFileStd_name(in_name,"r")) == NULL)
+ error ("Read: Can't open file '%s'",in_name);
+
+ if ((rd_icco = new_icc()) == NULL)
+ error ("Read: Creation of ICC object failed");
+
+ /* Read the header and tag list */
+ if ((rv = rd_icco->read(rd_icco,rd_fp,0)) != 0)
+ error ("Read: %d, %s",rv,rd_icco->err);
+
+ /* Run the target Lab values through the bwd and fwd tables, */
+ /* to compute the overall error. */
+ {
+#define GAMUT_LCENT 50.0
+ xicc *xicco;
+ icxLuBase *luo;
+ icxInk ink; /* Ink parameters */
+ FILE *wrl;
+ struct {
+ double x, y, z;
+ double wx, wy, wz;
+ double r, g, b;
+ } axes[5] = {
+ { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */
+ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */
+ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */
+ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */
+ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */
+ };
+ int coa[4];
+ int i, j;
+
+ /* Wrap with an expanded icc */
+ if ((xicco = new_xicc(rd_icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ /* Set the default ink limits if not set on command line */
+ icxDefaultLimits(xicco, &ink.tlimit, tlimit, &ink.klimit, klimit);
+
+ if (verb) {
+ if (ink.tlimit >= 0.0)
+ printf("Total ink limit assumed is %3.0f%%\n",100.0 * ink.tlimit);
+ if (ink.klimit >= 0.0)
+ printf("Black ink limit assumed is %3.0f%%\n",100.0 * ink.klimit);
+ }
+
+ ink.c.Ksmth = ICXINKDEFSMTH; /* Default smoothing */
+ ink.c.Kskew = ICXINKDEFSKEW; /* default curve skew */
+ ink.c.Kstle = 0.5; /* Min K at white end */
+ ink.c.Kstpo = 0.5; /* Start of transition is at white */
+ ink.c.Kenle = 0.5; /* Max K at black end */
+ ink.c.Kenpo = 0.5; /* End transition at black */
+ ink.c.Kshap = 1.0; /* Linear transition */
+
+ /* Get a Device to PCS conversion object */
+ if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmFwd, icAbsoluteColorimetric, icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
+ if ((luo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmFwd, icmDefaultIntent, icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+ /* Get details of conversion */
+ luo->spaces(luo, &ins, NULL, &outs, NULL, NULL, NULL, NULL, NULL);
+
+ if (ins != icSigCmykData) {
+ error("Expecting CMYK device");
+ }
+
+ if ((wrl = fopen(out_name,"w")) == NULL) {
+ fprintf(stderr,"Error opening output file '%s'\n",out_name);
+ return 2;
+ }
+
+ /* Spit out a VRML 2 Object surface of gamut */
+
+ fprintf(wrl,"#VRML V2.0 utf8\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl,"# Created by the Argyll CMS\n");
+ fprintf(wrl,"Transform {\n");
+ fprintf(wrl,"children [\n");
+ fprintf(wrl," NavigationInfo {\n");
+ fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n");
+ fprintf(wrl," } # We'll add our own light\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," DirectionalLight {\n");
+ fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n");
+ fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ fprintf(wrl," Viewpoint {\n");
+ fprintf(wrl," position 0 0 340 # Position we view from\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"\n");
+ if (doaxes != 0) {
+ fprintf(wrl,"# Lab axes as boxes:\n");
+ for (i = 0; i < 5; i++) {
+ fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z);
+ fprintf(wrl,"\tchildren [\n");
+ fprintf(wrl,"\t\tShape{\n");
+ fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n",
+ axes[i].wx, axes[i].wy, axes[i].wz);
+ fprintf(wrl,"\t\t\tappearance Appearance { material Material ");
+ fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b);
+ fprintf(wrl,"\t\t}\n");
+ fprintf(wrl,"\t]\n");
+ fprintf(wrl,"}\n");
+ }
+ fprintf(wrl,"\n");
+ }
+
+ /* ---------------------------------------------- */
+ /* The PCS target -> Reference clipped vectors */
+
+ if (doref) {
+ if (verb)
+ printf("Doing PCS target to reference clipped PCS Vectors\n");
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+
+ i = 0;
+ for (coa[0] = 0; coa[0] < tres; coa[0]++) {
+ for (coa[1] = 0; coa[1] < tres; coa[1]++) {
+ for (coa[2] = 0; coa[2] < tres; coa[2]++) {
+ double in[4], dev[4], out[4];
+ double temp[4];
+ int rv1, rv2;
+
+ temp[0] = coa[0]/(tres-1.0);
+ temp[1] = coa[1]/(tres-1.0);
+ temp[2] = coa[2]/(tres-1.0);
+
+ /* PCS values */
+ in[0] = temp[0] * 100.0;
+ in[1] = 200.0 * temp[1] -100.0;
+ in[2] = 200.0 * temp[2] -100.0;
+
+ /* Do reference lookup */
+
+ /* PCS -> Device */
+ if ((rv2 = luo->inv_lookup(luo, dev, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (doclip && rv2 != 1) /* Not clip */
+ continue;
+
+ /* Device -> PCS */
+ if ((rv1 = luo->lookup(luo, out, dev)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (verb)
+ printf("."), fflush(stdout);
+
+ /* Input PCS to ideal (Inverse AtoB) clipped PCS values */
+ fprintf(wrl,"%f %f %f,\n",in[1], in[2], in[0]-GAMUT_LCENT);
+ fprintf(wrl,"%f %f %f,\n",out[1], out[2], out[0]-GAMUT_LCENT);
+ i++;
+ }
+ }
+ if (dilzero)
+ break;
+ }
+
+ if (verb)
+ printf("\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (j = 0; j < i; j++) {
+ fprintf(wrl,"%d, %d, -1,\n", j * 2, j * 2 + 1);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"appearance Appearance { material Material { emissiveColor 1.0 0.1 0.1} }\n");
+ fprintf(wrl,"} # end shape\n");
+ }
+
+ /* ---------------------------------------------- */
+ /* The Device Delta lines */
+ /* The PCS target -> clipped from average of surrounding device values, vectors */
+
+ if (dodelta) {
+ if (verb)
+ printf("Doing target PCS to average of 4 surrounding device to PCS Vectors\n");
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+
+ i = 0;
+ for (coa[0] = 0; coa[0] < tres; coa[0]++) {
+ for (coa[1] = 0; coa[1] < tres; coa[1]++) {
+ for (coa[2] = 0; coa[2] < tres; coa[2]++) {
+ double in[4], dev[4], out[4];
+ double in4[4], check[4];
+ double temp[4], adev[4];
+ double dev0[4], dev1[4], dev2[4], dev3[4];
+ int rv1, rv2;
+
+ temp[0] = coa[0]/(tres-1.0);
+ temp[1] = coa[1]/(tres-1.0);
+ temp[2] = coa[2]/(tres-1.0);
+
+ in[0] = temp[0] * 100.0;
+ in[1] = 200.0 * temp[1] -100.0;
+ in[2] = 200.0 * temp[2] -100.0;
+
+ /* Do reference lookup */
+
+ /* PCS -> ideal Device */
+ if ((rv2 = luo->inv_lookup(luo, dev, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (doclip && rv2 != 1) /* Not clip */
+ continue;
+
+ /* Device -> PCS check value */
+ if ((rv1 = luo->lookup(luo, check, dev)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* - - - - - - - - - - - - - - - */
+ /* Now do average in device space of two points */
+ temp[0] = coa[0]/(tres-1.0);
+ temp[1] = (coa[1]-RW)/(tres-1.0);
+ temp[2] = (coa[2]-RW)/(tres-1.0);
+
+ in4[0] = temp[0] * 100.0;
+ in4[1] = 200.0 * temp[1] -100.0;
+ in4[2] = 200.0 * temp[2] -100.0;
+
+ /* PCS -> Device */
+ if ((rv2 = luo->inv_lookup(luo, dev0, in4)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ adev[0] = 0.25 * dev0[0];
+ adev[1] = 0.25 * dev0[1];
+ adev[2] = 0.25 * dev0[2];
+ adev[3] = 0.25 * dev0[3];
+
+ temp[0] = coa[0]/(tres-1.0);
+ temp[1] = (coa[1]+RW)/(tres-1.0);
+ temp[2] = (coa[2]-RW)/(tres-1.0);
+
+ in4[0] = temp[0] * 100.0;
+ in4[1] = 200.0 * temp[1] -100.0;
+ in4[2] = 200.0 * temp[2] -100.0;
+
+ /* PCS -> Device */
+ if ((rv2 = luo->inv_lookup(luo, dev1, in4)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ adev[0] += 0.25 * dev1[0];
+ adev[1] += 0.25 * dev1[1];
+ adev[2] += 0.25 * dev1[2];
+ adev[3] += 0.25 * dev1[3];
+
+ temp[0] = coa[0]/(tres-1.0);
+ temp[1] = (coa[1]-RW)/(tres-1.0);
+ temp[2] = (coa[2]+RW)/(tres-1.0);
+
+ in4[0] = temp[0] * 100.0;
+ in4[1] = 200.0 * temp[1] -100.0;
+ in4[2] = 200.0 * temp[2] -100.0;
+
+ /* PCS -> Device */
+ if ((rv2 = luo->inv_lookup(luo, dev2, in4)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ adev[0] += 0.25 * dev2[0];
+ adev[1] += 0.25 * dev2[1];
+ adev[2] += 0.25 * dev2[2];
+ adev[3] += 0.25 * dev2[3];
+
+ temp[0] = coa[0]/(tres-1.0);
+ temp[1] = (coa[1]+RW)/(tres-1.0);
+ temp[2] = (coa[2]+RW)/(tres-1.0);
+
+ in4[0] = temp[0] * 100.0;
+ in4[1] = 200.0 * temp[1] -100.0;
+ in4[2] = 200.0 * temp[2] -100.0;
+
+ /* PCS -> Device */
+ if ((rv2 = luo->inv_lookup(luo, dev3, in4)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ adev[0] += 0.25 * dev3[0];
+ adev[1] += 0.25 * dev3[1];
+ adev[2] += 0.25 * dev3[2];
+ adev[3] += 0.25 * dev3[3];
+
+ /* Device -> PCS */
+ if ((rv1 = luo->lookup(luo, out, adev)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (verb)
+ printf("."), fflush(stdout);
+
+ fprintf(wrl,"%f %f %f,\n",in[1], in[2], in[0]-GAMUT_LCENT);
+ fprintf(wrl,"%f %f %f,\n",out[1], out[2], out[0]-GAMUT_LCENT);
+ i++;
+ }
+ }
+ if (dilzero)
+ break;
+ }
+
+ if (verb)
+ printf("\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (j = 0; j < i; j++) {
+ fprintf(wrl,"%d, %d, -1,\n", j * 2, j * 2 + 1);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"appearance Appearance { material Material { emissiveColor 0.9 0.9 0.9} }\n");
+ fprintf(wrl,"} # end shape\n");
+
+ }
+
+ /* ---------------------------------------------- */
+ /* The target PCS -> clipped PCS using B2A table vectore */
+
+ if (dob2a) {
+ icxLuBase *luoB;
+
+ /* Get a PCS to Device conversion object */
+ if ((luoB = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icAbsoluteColorimetric,
+ icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
+ if ((luoB = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icmDefaultIntent,
+ icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ if (verb)
+ printf("Doing target PCS to B2A clipped PCS Vectors\n");
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+
+ i = 0;
+ for (coa[0] = 0; coa[0] < tres; coa[0]++) {
+ for (coa[1] = 0; coa[1] < tres; coa[1]++) {
+ for (coa[2] = 0; coa[2] < tres; coa[2]++) {
+ double in[4], dev[4], out[4];
+ double temp[4];
+ int rv1, rv2;
+
+ temp[0] = coa[0]/(tres-1.0);
+ temp[1] = coa[1]/(tres-1.0);
+ temp[2] = coa[2]/(tres-1.0);
+
+ in[0] = temp[0] * 100.0;
+ in[1] = 200.0 * temp[1] -100.0;
+ in[2] = 200.0 * temp[2] -100.0;
+
+ /* PCS -> Device */
+ if ((rv2 = luoB->lookup(luoB, dev, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (doclip && rv2 != 1) /* Not clip */
+ continue;
+
+ /* Device -> PCS */
+ if ((rv1 = luo->lookup(luo, out, dev)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (verb)
+ printf("."), fflush(stdout);
+
+ fprintf(wrl,"%f %f %f,\n",in[1], in[2], in[0]-GAMUT_LCENT);
+ fprintf(wrl,"%f %f %f,\n",out[1], out[2], out[0]-GAMUT_LCENT);
+ i++;
+ }
+ }
+ if (dilzero)
+ break;
+ }
+
+ if (verb)
+ printf("\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (j = 0; j < i; j++) {
+ fprintf(wrl,"%d, %d, -1,\n", j * 2, j * 2 + 1);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"appearance Appearance { material Material { emissiveColor 0.9 0.9 0.9} }\n");
+ fprintf(wrl,"} # end shape\n");
+
+ luoB->del(luoB);
+ }
+
+ /* ---------------------------------------------- */
+ /* The reference clipped PCS -> B2A clipped PCS vectore */
+
+ if (doeee) {
+ icxLuBase *luoB;
+
+ /* Get a PCS to Device conversion object */
+ if ((luoB = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icAbsoluteColorimetric,
+ icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL) {
+ if ((luoB = xicco->get_luobj(xicco, ICX_CLIP_NEAREST, icmBwd, icmDefaultIntent,
+ icSigLabData, icmLuOrdNorm, NULL, &ink)) == NULL)
+ error ("%d, %s",rd_icco->errc, rd_icco->err);
+ }
+
+ if (verb)
+ printf("Doing reference clipped PCS to B2A table clipped PCS Vectors\n");
+
+ fprintf(wrl,"\n");
+ fprintf(wrl,"Shape {\n");
+ fprintf(wrl," geometry IndexedLineSet { \n");
+ fprintf(wrl," coord Coordinate { \n");
+ fprintf(wrl," point [\n");
+
+ i = 0;
+ for (coa[0] = 0; coa[0] < tres; coa[0]++) {
+ for (coa[1] = 0; coa[1] < tres; coa[1]++) {
+ for (coa[2] = 0; coa[2] < tres; coa[2]++) {
+ double in[4], dev[4], out[4];
+ double check[4];
+ double temp[4];
+ int rv1, rv2;
+
+ temp[0] = coa[0]/(tres-1.0);
+ temp[1] = coa[1]/(tres-1.0);
+ temp[2] = coa[2]/(tres-1.0);
+
+ in[0] = temp[0] * 100.0;
+ in[1] = 200.0 * temp[1] -100.0;
+ in[2] = 200.0 * temp[2] -100.0;
+
+ /* Do reference lookup */
+ /* PCS -> Device */
+ if ((rv1 = luo->inv_lookup(luo, dev, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Device -> PCS */
+ if (luo->lookup(luo, check, dev) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Do B2A table lookup */
+ /* PCS -> Device */
+ if ((rv2 = luoB->lookup(luoB, dev, in)) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ /* Device -> PCS */
+ if (luo->lookup(luo, out, dev) > 1)
+ error ("%d, %s",rd_icco->errc,rd_icco->err);
+
+ if (doclip && rv1 != 1 && rv2 != 1) /* Not clip */
+ continue;
+
+ if (verb)
+ printf("."), fflush(stdout);
+
+ fprintf(wrl,"%f %f %f,\n",check[1], check[2], check[0]-GAMUT_LCENT);
+ fprintf(wrl,"%f %f %f,\n",out[1], out[2], out[0]-GAMUT_LCENT);
+ i++;
+ }
+ }
+ if (dilzero)
+ break;
+ }
+
+ if (verb)
+ printf("\n");
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl," coordIndex [\n");
+
+ for (j = 0; j < i; j++) {
+ fprintf(wrl,"%d, %d, -1,\n", j * 2, j * 2 + 1);
+ }
+ fprintf(wrl," ]\n");
+ fprintf(wrl," }\n");
+ fprintf(wrl,"appearance Appearance { material Material { emissiveColor 0.9 0.9 0.9} }\n");
+ fprintf(wrl,"} # end shape\n");
+
+ luoB->del(luoB);
+ }
+
+ /* ---------------------------------------------- */
+
+ fprintf(wrl,"\n");
+ fprintf(wrl," ] # end of children for world\n");
+ fprintf(wrl,"}\n");
+
+ if (fclose(wrl) != 0) {
+ fprintf(stderr,"Error closing output file '%s'\n",out_name);
+ return 2;
+ }
+
+ /* Done with lookup object */
+ luo->del(luo);
+ xicco->del(xicco);
+ }
+
+ rd_icco->del(rd_icco);
+ rd_fp->del(rd_fp);
+
+ return 0;
+}
+
diff --git a/xicc/xfit.c b/xicc/xfit.c
new file mode 100644
index 0000000..50916b3
--- /dev/null
+++ b/xicc/xfit.c
@@ -0,0 +1,2829 @@
+
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 2/7/00
+ * Version: 1.00
+ *
+ * Copyright 2000 - 2007 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.
+ *
+ * Based on the xlut.c code.
+ */
+
+/*
+ * TTBD:
+ *
+ * Need to use this for B2A tables rather than inverting
+ * A2B curves. Need to add grid sizing to cover just gamut range
+ * (including level axis gamut, but watch out for devices that
+ * have values below the black point), 3x3 matrix optimization,
+ * and white point to grid node mapping for B2A.
+ *
+ * Currently the Lab A2B output tables are adjusted for ab symetry
+ * to make the B2A white point land on a grid point, given that
+ * the icc code forces a symetric ab range. This only works
+ * because the B2A is using the same per channel curves.
+ * Done properly, it should be possible to know where grid
+ * points land within the range, and to modify the B2A input curves
+ * to make the white point land on a grid point.
+ * (For B2A the pseudo least squares adjustment needs to be turned
+ * off for that grid point too.)
+ *
+ * Note that one quandry is that the curve fitting doesn't
+ * fit well when the input data has an offset and/or plateaus.
+ */
+
+/*
+ * This module provides curve and matrix fitting functionality used to
+ * create per channel input and/or output curves for clut profiles,
+ * and optionally creates the rspl to fit the data as well.
+ *
+ * The approach used is to initialy creating input and output shaper
+ * curves that minimize the overall delta E of the test point set,
+ * when a linear matrix is substituted for a clut is used.
+ * (This is the same as pre-V0.70 approach. )
+ *
+ * The residual error between the test point set and the shaper/matrix/shaper
+ * model is then computed, and mapped against each input channel, and
+ * a positioning mapping curve created that aims to map rspl grid
+ * locations more densly where residual errors are high, and more
+ * sparsely where they are low.
+ * The input shaper and positioning curves are then combined together,
+ * so that the positioning curve determines which input values map
+ * to rspl grid points, and the shaper curve determines the mapping
+ * between the grid points. The width of the grid cells is computed
+ * in the shaper mapped input space, and then fed to the rspl fitting
+ * code, so that its smoothness evaluation function can take account
+ * of the non-uniform spacing of the grid points.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "icc.h"
+#include "rspl.h"
+#include "xicc.h"
+#include "plot.h"
+#include "xfit.h"
+#include "sort.h"
+
+
+#undef DEBUG /* Verbose debug information */
+#undef DEBUG_PLOT /* Plot in & out curves */
+#undef SPECIAL_FORCE /* Check rspl nodes against linear XYZ model */
+#undef SPECIAL_FORCE_GAMMA /* Force correct gamma shaper curves */
+#undef SPECIAL_TEST_GAMMA /* Use gamma on reference model */
+#undef SPECIAL_TEST_LAB
+
+#define RSPLFLAGS (0 /* | RSPL_2PASSSMTH */ /* | RSPL_EXTRAFIT2 */)
+
+#undef EXTEND_GRID /* [Undef] Use extended RSPL grid around interpolation */
+#define EXTEND_GRID_BYN 2 /* Rows to extend grid. */
+
+#undef NODDV /* Use slow non d/dv powell else use conjgrad */
+#define CURVEPOW 1.0 /* Power to raise deltaE squared to in setting in/out curves */
+ /* This provides a means of punishing high maximum errors. */
+
+#define POWTOL 1e-4 /* Shaper Powell optimiser tollerance in delta E squared ^ CURVEPOW */
+#define MAXITS 2000 /* Shaper number of itterations before giving up */
+#define PDDEL 1e-6 /* Fake partial derivative del */
+
+/* Weights for shaper in/out curve parameters, to minimise unconstrained "wiggles" */
+#define SHAPE_WEIGHT 1.0 /* Overal shaper weight contribution - err on side of smoothness */
+#define SHAPE_HW01 0.002 /* 0 & 1 harmonic weights */
+#define SHAPE_HBREAK 4 /* Harmonic that has HWBR */
+#define SHAPE_HWBR 20.0 /* Base weight of harmonics HBREAK up */
+#define SHAPE_HWINC 60.0 /* Increase in weight for each harmonic above HWBR */
+
+/* Weights for the positioning curve parameters */
+#define PSHAPE_MINE 0.02 /* Minum background residual error level */
+#define PSHAPE_DIST 1.0 /* Agressivness of grid distribution */
+
+/* - - - - - - - - - - - - - - - - - */
+
+#ifdef DEBUG
+static void dump_xfit(xfit *p);
+#endif
+
+#ifdef DEBUG_PLOT /* Not currently used in runtime code*/
+
+/* Lookup a value though an input position curve */
+static double xfit_poscurve(xfit *p, double in, int chan) {
+ double rv = in;
+ if (p->tcomb & oc_p)
+ rv = icxSTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], rv,
+ p->in_min[chan], p->in_max[chan]);
+ return rv;
+}
+
+/* Lookup di values though the input position curves */
+static void xfit_poscurves(xfit *p, double *out, double *in) {
+ int e;
+
+ for (e = 0; e < p->di; e++) {
+ double val = in[e];
+ if (p->tcomb & oc_i)
+ val = icxSTransFunc(p->v + p->pos_offs[e], p->iluord[e], val,
+ p->in_min[e], p->in_max[e]);
+ out[e] = val;
+ }
+}
+
+/* Inverse Lookup a value though an input position curve */
+static double xfit_invposcurve(xfit *p, double in, int chan) {
+ double rv = in;
+ if (p->tcomb & oc_i)
+ rv = icxInvSTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], rv,
+ p->in_min[chan], p->in_max[chan]);
+ return rv;
+}
+
+/* Inverse Lookup di values though input position curves */
+static void xfit_invposcurves(xfit *p, double *out, double *in) {
+ int e;
+
+ for (e = 0; e < p->di; e++) {
+ double val = in[e];
+ if (p->tcomb & oc_i)
+ val = icxInvSTransFunc(p->v + p->pos_offs[e], p->iluord[e], val,
+ p->in_min[e], p->in_max[e]);
+ out[e] = val;
+ }
+}
+#endif /* DEBUG_PLOT */
+
+/* - - - - - - - - - - - - - - - - - */
+/* Lookup a value though input shape curve */
+static double xfit_shpcurve(xfit *p, double in, int chan) {
+ double rv = in;
+
+ if (p->tcomb & oc_i) {
+#ifdef SPECIAL_FORCE_GAMMA
+ double gam;
+ if (chan == 0)
+ gam = 1.9;
+ else if (chan == 1)
+ gam = 2.0;
+ else if (chan == 2)
+ gam = 2.1;
+ else
+ gam = 1.0;
+ rv = pow(in, gam);
+#else
+ rv = icxSTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], rv,
+ p->in_min[chan], p->in_max[chan]);
+#endif
+ }
+ return rv;
+}
+
+#ifdef NEVER /* Not currently used */
+/* Lookup a value though shape curves */
+static void xfit_shpcurves(xfit *p, double *out, double *in) {
+ int e;
+
+ for (e = 0; e < p->di; e++) {
+ double val = in[e];
+ if (p->tcomb & oc_i)
+ val = icxSTransFunc(p->v + p->shp_offs[e], p->iluord[e], val,
+ p->in_min[e], p->in_max[e]);
+ out[e] = val;
+ }
+}
+#endif /* NEVER */
+
+/* Inverse Lookup a value though a shape curve */
+static double xfit_invshpcurve(xfit *p, double in, int chan) {
+ double rv = in;
+
+ if (p->tcomb & oc_i) {
+#ifdef SPECIAL_FORCE_GAMMA
+ double gam;
+ if (chan == 0)
+ gam = 1.9;
+ else if (chan == 1)
+ gam = 2.0;
+ else if (chan == 2)
+ gam = 2.1;
+ else
+ gam = 1.0;
+ rv = pow(rv, 1.0/gam);
+#else
+ rv = icxInvSTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], rv,
+ p->in_min[chan], p->in_max[chan]);
+#endif
+ }
+ return rv;
+}
+
+#ifdef NEVER /* Not currently used */
+/* Inverse Lookup a value though shape curves */
+static void xfit_invshpcurves(xfit *p, double *out, double *in) {
+ int e;
+
+ for (e = 0; e < p->di; e++) {
+ double val = in[e];
+ if (p->tcomb & oc_i)
+ val = icxInvSTransFunc(p->v + p->shp_offs[e], p->iluord[e], val,
+ p->in_min[e], p->in_max[e]);
+ out[e] = val;
+ }
+}
+#endif /* NEVER */
+
+/* - - - - - - - - - - - - - - - - - */
+
+/* Lookup values through the shaper/matrix/shaper model */
+static void xfit_shmatsh(xfit *p, double *out, double *in) {
+ double tin[MXDI];
+ int e, f;
+
+ for (e = 0; e < p->di; e++)
+ tin[e] = icxSTransFunc(p->v + p->shp_offs[e], p->iluord[e], in[e],
+ p->in_min[e], p->in_max[e]);
+
+ icxCubeInterp(p->v + p->mat_off, p->fdi, p->di, out, tin);
+
+ for (f = 0; f < p->fdi; f++)
+ out[f] = icxSTransFunc(p->v + p->out_offs[f], p->oluord[f], out[f],
+ p->out_min[f], p->out_max[f]);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - */
+/* Combined input positioning & shaper transfer curve functions */
+
+//int db = 0;
+
+/* Lookup a value though the input positioning and shaper curves */
+static double xfit_inpscurve(xfit *p, double in, int chan) {
+ double rv;
+ /* Just shaper curve */
+ if ((p->tcomb & oc_ip) == oc_i) {
+ rv = icxSTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], in,
+ p->in_min[chan], p->in_max[chan]);
+
+ /* shaper and positioning */
+ } else if ((p->tcomb & oc_ip) == oc_ip) {
+ double nin, npind; /* normalized in, normalized position in' */
+ int six; /* Span index */
+ double npind0, npind1; /* normalized position in' span values */
+ double npin0, npin1; /* normalized position in span values */
+ double nsind0, nsind1; /* normalized shaper in' span values */
+ double nsind; /* normalised shaper in' value */
+
+ /* Normalize */
+ nin = (in - p->in_min[chan])/(p->in_max[chan] - p->in_min[chan]);
+
+//if (db) printf("\n~1 inpscurve: cha %d, input value %f, norm %f\n",chan,in,nin);
+
+ /* Locate the span the input point will be in after positioning lookup */
+ npind = icxTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], nin);
+
+ /* Quantize position space value to grid */
+ six = (int)floor(npind * (p->gres[chan]-1.0));
+ if (six > (p->gres[chan]-2))
+ six = (p->gres[chan]-2);
+
+ /* Compute span position position in' values */
+ npind0 = six / (p->gres[chan]-1.0);
+ npind1 = (six + 1.0) / (p->gres[chan]-1.0);
+
+//if (db) printf("~1 npind %f, six %d, npind0 %f, npind1 %f\n",npind,six,npind0,npind1);
+
+ /* Compute span in values */
+ npin0 = icxInvTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], npind0);
+ npin1 = icxInvTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], npind1);
+
+//if (db) printf("~1 npin0 %f, npin1 %f\n",npin0,npin1);
+
+ /* Compute shaper space values of in' and spane */
+#ifdef NEVER
+ nsind = icxTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], nin);
+ nsind0 = icxTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], npin0);
+ nsind1 = icxTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], npin1);
+#else
+ nsind = xfit_shpcurve(p, nin, chan);
+ nsind0 = xfit_shpcurve(p, npin0, chan);
+ nsind1 = xfit_shpcurve(p, npin1, chan);
+#endif
+
+//if (db) printf("~1 nsind %f, nsind0 %f, nsind1 %f\n",nsind,nsind0,nsind1);
+
+ /* Offset and scale shaper in' value to match position span */
+ rv = (nsind - nsind0)/(nsind1 - nsind0) * (npind1 - npind0) + npind0;
+
+//if (db) printf("~1 scale offset ind %f\n",rv);
+
+ /* de-normalize */
+ rv = rv * (p->in_max[chan] - p->in_min[chan]) + p->in_min[chan];
+//if (db) printf("~1 returning %d\n",rv);
+
+ /* Just positioning curve */
+ } else if ((p->tcomb & oc_ip) == oc_p) {
+ rv = icxSTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], in,
+ p->in_min[chan], p->in_max[chan]);
+ } else {
+ rv = in;
+ }
+ return rv;
+}
+
+/* Lookup di values though the input positioning and shaper curves */
+static void xfit_inpscurves(xfit *p, double *out, double *in) {
+ int e;
+
+ for (e = 0; e < p->di; e++)
+ out[e] = xfit_inpscurve(p, in[e], e);
+}
+
+/* Inverse Lookup a value though the input positioning and shaper curves */
+static double xfit_invinpscurve(xfit *p, double in, int chan) {
+ double rv;
+ /* Just shaper curve */
+ if ((p->tcomb & oc_ip) == oc_i) {
+ rv = icxInvSTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], in,
+ p->in_min[chan], p->in_max[chan]);
+
+ /* shaper and positioning */
+ } else if ((p->tcomb & oc_ip) == oc_ip) {
+ double nind, nin; /* normalized in', normalized in */
+ int six; /* Span index */
+ double npind0, npind1; /* normalized position in' span values */
+ double npin0, npin1; /* normalized position in span values */
+ double nsind0, nsind1; /* normalized shaper in' span values */
+ double nsind; /* normalized shaper in' value */
+
+ /* Normalize */
+ nind = (in - p->in_min[chan])/(p->in_max[chan] - p->in_min[chan]);
+
+//if (db) printf("\n~1 invinpscurve: cha %d, input value %f, norm %f\n",chan,in,nind);
+
+ /* Quantize to grid */
+ six = (int)floor(nind * (p->gres[chan]-1.0));
+ if (six > (p->gres[chan]-2))
+ six = (p->gres[chan]-2);
+
+ /* Compute span in' values */
+ npind0 = six / (p->gres[chan]-1.0);
+ npind1 = (six + 1.0) / (p->gres[chan]-1.0);
+
+//if (db) printf("~1 six %d, npind0 %f, npind1 %f\n",six,npind0,npind1);
+
+ /* Lookup span in values through position curve */
+ npin0 = icxInvTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], npind0);
+ npin1 = icxInvTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], npind1);
+
+//if (db) printf("~1 npin0 %f, npin1 %f\n",npin0,npin1);
+
+ /* Compute span shaper in' values */
+#ifdef NEVER
+ nsind0 = icxTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], npin0);
+ nsind1 = icxTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], npin1);
+#else
+ nsind0 = xfit_shpcurve(p, npin0, chan);
+ nsind1 = xfit_shpcurve(p, npin1, chan);
+#endif
+
+ /* Offset and scale position in' value to match shaper span */
+ nsind = (nind - npind0)/(npind1 - npind0) * (nsind1 - nsind0) + nsind0;
+
+//if (db) printf("~1 nsind %f, nsind0 %f, nsind1 %f\n",nsind,nsind0,nsind1);
+
+ /* Invert through shaper curve */
+#ifdef NEVER
+ nin = icxInvTransFunc(p->v + p->shp_offs[chan], p->iluord[chan], nsind);
+#else
+ nin = xfit_invshpcurve(p, nsind, chan);
+#endif
+
+ /* de-normalize */
+ rv = nin * (p->in_max[chan] - p->in_min[chan]) + p->in_min[chan];
+
+//if (db) printf("\n~1 nin = %f, returning %f\n",nin,rv);
+
+ /* Just positioning curve */
+ } else if ((p->tcomb & oc_ip) == oc_p) {
+ rv = icxInvSTransFunc(p->v + p->pos_offs[chan], p->iluord[chan], in,
+ p->in_min[chan], p->in_max[chan]);
+ } else {
+ rv = in;
+ }
+ return rv;
+}
+
+#ifdef NEVER
+/* Check that inverse is working */
+static double _xfit_inpscurve(xfit *p, double in, int chan) {
+ double inv, rv, iinv;
+
+ inv = in;
+ rv = xfit_inpscurve(p, in, chan);
+ iinv = xfit_invinpscurve(p, rv, chan);
+
+ if (fabs(in - iinv) > 1e-5)
+ warning("xfit_inpscurve check, got %f, should be %f\n",iinv,in);
+
+ return rv;
+}
+#define xfit_inpscurve _xfit_inpscurve
+#endif /* NEVER */
+
+/* Inverse Lookup di values though the input positioning and shaper curves */
+static void xfit_invinpscurves(xfit *p, double *out, double *in) {
+ int e;
+
+ for (e = 0; e < p->di; e++)
+ out[e] = xfit_invinpscurve(p, in[e], e);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - */
+/* Combined output transfer curve functions */
+
+/* Lookup a value though an output curve */
+static double xfit_outcurve(xfit *p, double in, int chan) {
+ double rv;
+ if (p->tcomb & oc_o)
+ rv = icxSTransFunc(p->v + p->out_offs[chan], p->oluord[chan], in,
+ p->out_min[chan], p->out_max[chan]);
+ else
+ rv = in;
+ return rv;
+}
+
+/* Lookup fdi values though the output curves */
+static void xfit_outcurves(xfit *p, double *out, double *in) {
+ int f;
+
+ for (f = 0; f < p->fdi; f++) {
+ double val = in[f];
+ if (p->tcomb & oc_o)
+ val = icxSTransFunc(p->v + p->out_offs[f], p->oluord[f], val,
+ p->out_min[f], p->out_max[f]);
+ out[f] = val;
+ }
+}
+
+/* Inverse Lookup a value though an output curve */
+static double xfit_invoutcurve(xfit *p, double in, int chan) {
+ double rv;
+ if (p->tcomb & oc_o)
+ rv = icxInvSTransFunc(p->v + p->out_offs[chan], p->oluord[chan], in,
+ p->out_min[chan], p->out_max[chan]);
+ else
+ rv = in;
+ return rv;
+}
+
+/* Inverse Lookup fdi values though output curves */
+static void xfit_invoutcurves(xfit *p, double *out, double *in) {
+ int f;
+
+ for (f = 0; f < p->fdi; f++) {
+ double val = in[f];
+ if (p->tcomb & oc_o)
+ val = icxInvSTransFunc(p->v + p->out_offs[f], p->oluord[f], val,
+ p->out_min[f], p->out_max[f]);
+ out[f] = val;
+ }
+}
+
+/* - - - - - - - - - */
+
+/* Convert an output value from absolute */
+/* to relative using the current white point. */
+static void xfit_abs_to_rel(xfit *p, double *out, double *in) {
+ if (p->flags & XFIT_OUT_WP_REL) {
+ if (p->flags & XFIT_OUT_LAB) {
+ icmLab2XYZ(&icmD50, out, in);
+ icmMulBy3x3(out, p->fromAbs, out);
+ icmXYZ2Lab(&icmD50, out, out);
+ } else {
+ icmMulBy3x3(out, p->fromAbs, in);
+ }
+ } else {
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ }
+}
+
+/* - - - - - - - - - */
+
+/* return a weighting for the magnitude of the in and out */
+/* shaping parameters squared. This is to reduce unconstrained "wiggles" */
+static double shapmag(
+xfit *p /* Base of optimisation structure */
+) {
+ double tt, w;
+ double *b; /* Base of parameters for this section */
+ int di = p->di;
+ int fdi = p->fdi;
+ int e, f, k;
+ double iparam = 0.0;
+ double oparam = 0.0;
+ double dd;
+
+ if (p->opt_msk & oc_i) {
+ dd = SHAPE_WEIGHT/(double)(di);
+ b = p->v + p->shp_off;
+ for (e = 0; e < di; e++) {
+ for (k = 0; k < p->iluord[e]; k++) {
+ if (k <= 1) {
+ w = SHAPE_HW01;
+ } else if (k <= SHAPE_HBREAK) {
+ double bl = (k - 1.0)/(SHAPE_HBREAK - 1.0);
+ w = (1.0 - bl) * SHAPE_HW01 + bl * SHAPE_HWBR;
+ w *= p->shp_smooth[e];
+ } else {
+ w = SHAPE_HWBR + (k-SHAPE_HBREAK) * SHAPE_HWINC;
+ w *= p->shp_smooth[e];
+ }
+ tt = *b++;
+ tt *= tt; /* Squared */
+ iparam += w * tt;
+ }
+ }
+ iparam *= dd;
+ }
+
+ if (p->opt_msk & oc_o) {
+ dd = SHAPE_WEIGHT/(double)(fdi);
+ b = p->v + p->out_off;
+ for (f = 0; f < fdi; f++) {
+ for (k = 0; k < p->oluord[f]; k++) {
+ if (k <= 1) {
+ w = SHAPE_HW01;
+ } else if (k <= SHAPE_HBREAK) {
+ double bl = (k - 1.0)/(SHAPE_HBREAK - 1.0);
+ w = (1.0 - bl) * SHAPE_HW01 + bl * SHAPE_HWBR;
+ w *= p->out_smooth[f];
+ } else {
+ w = SHAPE_HWBR + (k-SHAPE_HBREAK) * SHAPE_HWINC;
+ w *= p->out_smooth[f];
+ }
+ tt = *b++;
+ tt *= tt; /* Squared */
+ oparam += w * tt;
+ }
+ }
+ oparam *= dd;
+ }
+ return iparam + oparam;
+}
+
+/* return a weighting for the magnitude of the in and out */
+/* shaping parameters. This is to reduce unconstrained "wiggles" */
+/* Also sum the partial derivative for the parameters involved */
+static double dshapmag(
+xfit *p, /* Base of optimisation structure */
+double *dav /* Sum del's */
+) {
+ double tt, w;
+ double *b, *c; /* Base of parameters for this section */
+ int di = p->di;
+ int fdi = p->fdi;
+ int e, f, k;
+ double iparam = 0.0;
+ double oparam = 0.0;
+ double dd;
+
+ if (p->opt_msk & oc_i) {
+ dd = SHAPE_WEIGHT/(double)(di);
+ b = p->v + p->shp_off;
+ c = dav + p->shp_off;
+ for (e = 0; e < di; e++) {
+ for (k = 0; k < p->iluord[e]; k++) {
+ if (k <= 1) {
+ w = SHAPE_HW01;
+ } else if (k <= SHAPE_HBREAK) {
+ double bl = (k - 1.0)/(SHAPE_HBREAK - 1.0);
+ w = (1.0 - bl) * SHAPE_HW01 + bl * SHAPE_HWBR;
+ w *= p->shp_smooth[e];
+ } else {
+ w = SHAPE_HWBR + (k-SHAPE_HBREAK) * SHAPE_HWINC;
+ w *= p->shp_smooth[e];
+ }
+ tt = *b++;
+ *c++ += 2.0 * dd * w * tt;
+ tt *= tt; /* Squared */
+ iparam += w * tt;
+
+ }
+ }
+ iparam *= dd;
+ }
+
+ if (p->opt_msk & oc_o) {
+ dd = SHAPE_WEIGHT/(double)(fdi);
+ b = p->v + p->out_off;
+ c = dav + p->out_off;
+ for (f = 0; f < fdi; f++) {
+ for (k = 0; k < p->oluord[f]; k++) {
+ if (k <= 1) {
+ w = SHAPE_HW01;
+ } else if (k <= SHAPE_HBREAK) {
+ double bl = (k - 1.0)/(SHAPE_HBREAK - 1.0);
+ w = (1.0 - bl) * SHAPE_HW01 + bl * SHAPE_HWBR;
+ w *= p->out_smooth[f];
+ } else {
+ w = SHAPE_HWBR + (k-SHAPE_HBREAK) * SHAPE_HWINC;
+ w *= p->out_smooth[f];
+ }
+ tt = *b++;
+ *c++ += 2.0 * dd * w * tt;
+ tt *= tt; /* Squared */
+ oparam += w * tt;
+ }
+ }
+ oparam *= dd;
+ }
+ return iparam + oparam;
+}
+
+/* Scale the shaper derivatives */
+static void dshapscale(
+xfit *p, /* Base of optimisation structure */
+double *dav, /* del's */
+double scale /* Scale factor */
+) {
+ double tt, w;
+ double *b, *c; /* Base of parameters for this section */
+ int di = p->di;
+ int fdi = p->fdi;
+ int e, f, k;
+
+ if (p->opt_msk & oc_i) {
+ c = dav + p->shp_off;
+ for (e = 0; e < di; e++) {
+ for (k = 0; k < p->iluord[e]; k++) {
+ *c++ *= scale;
+ }
+ }
+ }
+
+ if (p->opt_msk & oc_o) {
+ c = dav + p->out_off;
+ for (f = 0; f < fdi; f++) {
+ for (k = 0; k < p->oluord[f]; k++) {
+ *c++ *= scale;
+ }
+ }
+ }
+}
+
+/* Progress function */
+static void xfitprog(void *pdata, int perc) {
+ xfit *p = (xfit *)pdata;
+
+ if (p->verb) {
+ printf("%c% 3d%%",cr_char,perc);
+ if (perc == 100)
+ printf("\n");
+ fflush(stdout);
+ }
+}
+
+
+int xfitfunc_trace = 1;
+
+/* Shaper+Matrix optimisation function handed to powell() */
+/* We simply minimize the total delta E squared, consistent with smoothness */
+static double xfitfunc(void *edata, double *v) {
+ xfit *p = (xfit *)edata;
+ double tw = 0.0; /* Total weight */
+ double ev = 0.0, rv, smv;
+ double tin[MXDI], out[MXDO];
+ int di = p->di;
+ int fdi = p->fdi;
+ int i, e, f;
+
+ /* Copy the parameters being optimised into xfit structure */
+
+ /* Special case - a single shaper curve. The first sm_iluord params */
+ /* are the common curve parameters, and the remainder are the matrix onwards */
+ if (p->opt_ssch) {
+
+ for (e = 0; e < di; e++) { /* Duplicate and extend to per channel curve params */
+ for (i = 0; i < p->sm_iluord; i++)
+ p->v[p->shp_offs[e] + i] = v[i];
+ for (; i < p->iluord[e]; i++)
+ p->v[p->shp_offs[e] + i] = 0.0;
+ }
+ for (i = p->sm_iluord; i < p->opt_cnt; i++)
+ p->v[p->mat_off + i - p->sm_iluord] = v[i];
+ } else {
+ for (i = 0; i < p->opt_cnt; i++) {
+//printf("~1 param %d = %f\n",i,v[i]);
+ p->v[p->opt_off + i] = v[i];
+ }
+ }
+
+ /* For all our data points */
+ for (i = 0; i < p->nodp; i++) {
+ double del;
+
+ /* Apply input shaper channel curves */
+ for (e = 0; e < di; e++)
+ tin[e] = icxSTransFunc(p->v + p->shp_offs[e], p->iluord[e], p->rpoints[i].p[e],
+ p->in_min[e], p->in_max[e]);
+
+ /* Apply matrix cube interpolation */
+ icxCubeInterp(p->v + p->mat_off, fdi, di, out, tin);
+
+ /* Apply output channel curves */
+ for (f = 0; f < fdi; f++)
+ out[f] = icxSTransFunc(p->v + p->out_offs[f], p->oluord[f], out[f],
+ p->out_min[f], p->out_max[f]);
+
+ /* Evaluate the error squared */
+ if (p->flags & XFIT_FM_INPUT) {
+ double pp[MXDI];
+ for (e = 0; e < di; e++)
+ pp[e] = p->rpoints[i].p[e];
+ for (f = 0; f < fdi; f++) {
+ double t1 = p->rpoints[i].v[f] - out[f]; /* Error in output */
+
+ /* Create input point offset by equivalent delta to output point */
+ /* error, in proportion to the partial derivatives for that output. */
+ for (e = 0; e < di; e++)
+ pp[e] += t1 * p->piv[i].ide[f][e];
+ }
+ del = p->to_de2(p->cntx2, pp, p->rpoints[i].p);
+ } else {
+ del = p->to_de2(p->cntx2, out, p->rpoints[i].v);
+ }
+ if (CURVEPOW > 1.0)
+ del = pow(del, CURVEPOW);
+ tw += p->rpoints[i].w;
+ ev += p->rpoints[i].w * del;
+ }
+
+ /* Normalise error to be an average delta E squared */
+ ev /= tw;
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles" */
+ smv = shapmag(p);
+ if (CURVEPOW > 1.0)
+ smv = pow(smv, CURVEPOW);
+ rv = ev + smv;
+
+#ifdef DEBUG
+if (xfitfunc_trace)
+fprintf(stdout,"~1(sm %f, ev %f)xfitfunc returning %f\n",smv,ev,rv);
+#endif
+
+ return rv;
+}
+
+/* Shaper+Matrix optimisation function with partial derivatives, */
+/* handed to conjgrad() */
+static double dxfitfunc(void *edata, double *dv, double *v) {
+ xfit *p = (xfit *)edata;
+ double tw = 0.0; /* Total weight */
+ double ev = 0.0, rv, smv;
+ double tin[MXDI], out[MXDO];
+
+ double dav[MXPARMS]; /* Overall del due to del param vals */
+ double sdav[MXPARMS]; /* Overall del due to del smooth param vals */
+
+ double dtin_iv[MXDI * MXLUORD]; /* Del in itrans out due to del itrans param vals */
+ double dmato_mv[1 << MXDI]; /* Del in mat out due to del in matrix param vals */
+ double dmato_tin[MXDO * MXDI]; /* Del in mat out due to del in matrix input values */
+ double dout_ov[MXDO * MXLUORD]; /* Del in otrans out due to del in otrans param values */
+ double dout_mato[MXDO]; /* Del in otrans out due to del in otrans input values */
+
+ double dout_de[2][MXDIDO]; /* Del in DE due to two output values */
+
+ int di = p->di;
+ int fdi = p->fdi;
+ int i, jj, k, e, ee, f, ff;
+
+ /* Copy the parameters being optimised into xfit structure */
+
+ /* Special case - a single shaper curve. The first sm_iluord params */
+ /* are the common curve parameters, and the remainder are the matrix onwards */
+ if (p->opt_ssch) {
+ for (e = 0; e < di; e++) { /* Duplicate and extend to per channel curve params */
+ for (i = 0; i < p->sm_iluord; i++)
+ p->v[p->shp_offs[e] + i] = v[i];
+ for (; i < p->iluord[e]; i++)
+ p->v[p->shp_offs[e] + i] = 0.0;
+ }
+ for (i = p->sm_iluord; i < p->opt_cnt; i++)
+ p->v[p->mat_off + i - p->sm_iluord] = v[i];
+
+ } else {
+ for (i = 0; i < p->opt_cnt; i++) {
+//printf("~1 param %d = %f\n",i,v[i]);
+ p->v[p->opt_off + i] = v[i];
+ }
+ }
+
+ /* Zero the accumulated partial derivatives */
+ /* We compute deriv for all parameters (not just current optimised) */
+ for (i = 0; i < p->tot_cnt; i++)
+ dav[i] = 0.0;
+
+ /* For all our data points */
+ for (i = 0; i < p->nodp; i++) {
+ double del;
+
+ /* Apply input channel curves */
+ for (e = 0; e < di; e++)
+ tin[e] = icxdpSTransFunc(p->v + p->shp_offs[e], &dtin_iv[p->shp_offs[e] - p->shp_off],
+ p->iluord[e], p->rpoints[i].p[e], p->in_min[e], p->in_max[e]);
+
+ /* Apply matrix cube interpolation */
+ icxdpdiCubeInterp(p->v + p->mat_off, dmato_mv, dmato_tin, fdi, di, out, tin);
+
+ /* Apply output channel curves */
+ for (f = 0; f < fdi; f++)
+ out[f] = icxdpdiSTransFunc(p->v + p->out_offs[f],
+ &dout_ov[p->out_offs[f] - p->out_off], &dout_mato[f],
+ p->oluord[f], out[f], p->out_min[f], p->out_max[f]);
+
+
+ /* Convert to Delta E and compute pde's into dout_de squared */
+ if (p->flags & XFIT_FM_INPUT) {
+ double tdout_de[2][MXDIDO];
+ double pp[MXDI];
+ for (e = 0; e < di; e++)
+ pp[e] = p->rpoints[i].p[e];
+ for (f = 0; f < fdi; f++) {
+ double t1 = p->rpoints[i].v[f] - out[f]; /* Error in output */
+
+ /* Create input point offset by equivalent delta to output point */
+ /* error, in proportion to the partial derivatives for that output. */
+ for (e = 0; e < di; e++)
+ pp[e] += t1 * p->piv[i].ide[f][e];
+ }
+ del = p->to_dde2(p->cntx2, tdout_de, pp, p->rpoints[i].p);
+ if (CURVEPOW > 1.0) {
+ double dadj;
+ dadj = CURVEPOW * pow(del, CURVEPOW - 1.0); /* Adjust derivative accordingly */
+ del = pow(del, CURVEPOW);
+ for (e = 0; e < di; e++)
+ tdout_de[0][e] *= dadj;
+ }
+
+ /* Compute partial derivative */
+ for (e = 0; e < di; e++) {
+ dout_de[0][e] = 0.0;
+ for (f = 0; f < fdi; f++) {
+ dout_de[0][e] += tdout_de[0][e] * p->piv[i].ide[f][e];
+ }
+ }
+ } else {
+ del = p->to_dde2(p->cntx2, dout_de, out, p->rpoints[i].v);
+ if (CURVEPOW > 1.0) {
+ double dadj;
+ dadj = CURVEPOW * pow(del, CURVEPOW - 1.0); /* Adjust derivative accordingly */
+ del = pow(del, CURVEPOW);
+ for (f = 0; f < fdi; f++)
+ dout_de[0][f] *= dadj;
+ }
+ }
+
+ /* Accumulate total weighted delta E squared */
+ tw += p->rpoints[i].w;
+ ev += p->rpoints[i].w * del;
+
+ /* Compute and accumulate partial difference values for each parameter value */
+ if (p->opt_msk & oc_i) {
+ /* Input transfer parameters */
+ for (ee = 0; ee < di; ee++) { /* Parameter input chanel */
+ for (k = 0; k < p->iluord[ee]; k++) { /* Param within channel */
+ double vv = 0.0;
+ jj = p->shp_offs[ee] - p->shp_off + k; /* Overall input trans param */
+
+// for (ff = 0; ff < 3; ff++) { /* Lab channels */
+ for (ff = 0; ff < fdi; ff++) { /* Output channels */
+ vv += dout_de[0][ff] * dout_mato[ff]
+ * dmato_tin[ff * di + ee] * dtin_iv[jj];
+ }
+ dav[p->shp_off + jj] += p->rpoints[i].w * vv;
+ }
+ }
+ }
+
+ if (p->opt_msk & oc_m) {
+ /* Matrix parameters */
+ for (ff = 0; ff < fdi; ff++) { /* Parameter output chanel */
+ for (ee = 0; ee < (1 << di); ee++) { /* Matrix input combination chanel */
+ double vv = 0.0;
+ jj = ff * (1 << di) + ee; /* Matrix Parameter index */
+
+ vv += dout_de[0][ff] * dout_mato[ff] * dmato_mv[ee];
+ dav[p->mat_off + jj] += p->rpoints[i].w * vv;
+ }
+ }
+ }
+
+ if (p->opt_msk & oc_o) {
+ /* Output transfer parameters */
+ for (ff = 0; ff < fdi; ff++) { /* Parameter output chanel */
+ for (k = 0; k < p->oluord[ff]; k++) { /* Param within channel */
+ double vv = 0.0;
+ jj = p->out_offs[ff] - p->out_off + k; /* Overall output trans param */
+
+ vv += dout_de[0][ff] * dout_ov[jj];
+ dav[p->out_off + jj] += p->rpoints[i].w * vv;
+ }
+ }
+ }
+ }
+
+ /* Normalise error to be an average delta E squared */
+ ev /= tw;
+ for (i = 0; i < p->tot_cnt; i++) {
+ dav[i] /= tw;
+ sdav[i] = 0.0;
+ }
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles" */
+ /* Compute partial derivative wrt those parameters too */
+ smv = dshapmag(p, sdav);
+ if (CURVEPOW > 1.0) {
+ double dadj;
+ dadj = CURVEPOW * pow(smv, CURVEPOW - 1.0); /* Adjust derivative accordingly */
+ smv = pow(smv, CURVEPOW);
+ dshapscale(p, sdav, dadj); /* Scale the partial derivatives */
+ }
+ rv = ev + smv;
+
+ /* Sum the del for parameters being optimised and copy to return array */
+
+ if (p->opt_ssch) {
+ for (i = 0; i < p->sm_iluord; i++)
+ dv[i] = 0.0;
+ for (e = 0; e < di; e++) { /* Combine per channel curve de's */
+ for (i = 0; i < p->sm_iluord; i++)
+ dv[i] += dav[p->shp_offs[e] + i] = sdav[p->shp_offs[e] + i];
+ }
+ for (i = p->sm_iluord; i < p->opt_cnt; i++) /* matrix and rest de's */
+ dv[i] = dav[p->mat_off + i - p->sm_iluord] + sdav[p->mat_off + i - p->sm_iluord];
+
+ } else {
+ for (i = 0; i < p->opt_cnt; i++)
+ dv[i] = dav[p->opt_off + i] + sdav[p->opt_off + i];
+ }
+
+#ifdef DEBUG
+fprintf(stdout,"~1(sm %f, ev %f)dxfitfunc returning %f\n",smv,ev,rv);
+#endif
+
+ return rv;
+}
+
+#ifdef NEVER
+/* Check partial derivative function within xfitfunc() [Intensive check] */
+
+static double _xfitfunc(void *edata, double *v) {
+ xfit *p = (xfit *)edata;
+ int i;
+ double dv[MXPARMS];
+ double rv, drv;
+ double trv;
+ int verb;
+
+ rv = xfitfunc(edata, v);
+ verb = p->verb;
+ p->verb = 0;
+ drv = dxfitfunc(edata, dv, v);
+ p->verb = verb;
+
+ if (fabs(rv - drv) > 1e-6)
+ printf("######## RV MISMATCH is %f should be %f ########\n",rv,drv);
+
+ /* Check each parameter delta */
+ xfitfunc_trace = 0;
+ for (i = 0; i < p->opt_cnt; i++) {
+ double del;
+
+ v[i] += 1e-7;
+ trv = xfitfunc(edata, v);
+ v[i] -= 1e-7;
+
+ /* Check that del is correct */
+ del = (trv - rv)/1e-7;
+ if (fabs(dv[i] - del) > 0.04) {
+//printf("~1 del = %f from (trv %f - rv %f)/0.1\n",del,trv,rv);
+ printf("######## EXCESSIVE at v[%d] is %f should be %f ########\n",i,dv[i],del);
+ }
+ }
+ xfitfunc_trace = 1;
+ return rv;
+}
+
+#define xfitfunc _xfitfunc
+#endif /* NEVER */
+
+#ifdef NEVER
+/* Check partial derivative function within dxfitfunc() [Less intensive check] */
+
+static double _dxfitfunc(void *edata, double *dv, double *v) {
+ xfit *p = (xfit *)edata;
+ int i;
+ double rv, drv;
+ double trv;
+ int verb;
+ int exec = 0;
+
+ rv = xfitfunc(edata, v);
+ verb = p->verb;
+ p->verb = 0;
+ drv = dxfitfunc(edata, dv, v);
+ p->verb = verb;
+
+ if (fabs(rv - drv) > 1e-6)
+ printf("######## RV MISMATCH is %f should be %f ########\n",rv,drv);
+
+ /* Check each parameter delta */
+ xfitfunc_trace = 0;
+ for (i = 0; i < p->opt_cnt; i++) {
+ double del;
+
+ v[i] += 1e-7;
+ trv = xfitfunc(edata, v);
+ v[i] -= 1e-7;
+
+ /* Check that del is correct */
+ del = (trv - rv)/1e-7;
+ if (fabs(dv[i] - del) > 0.04) {
+//printf("~1 del = %f from (trv %f - rv %f)/0.1\n",del,trv,rv);
+ printf("######## EXCESSIVE at v[%d] is %f should be %f ########\n",i,dv[i],del);
+ exec = 1;
+ }
+ }
+#ifdef NEVER
+ if (exec) {
+ printf("~1 parameters are:\n");
+ for (i = 0; i < p->opt_cnt; i++)
+ printf("p->wv[%d] = %f;\n",i,v[i]);
+ exit(1);
+ }
+#endif
+ xfitfunc_trace = 1;
+ return rv;
+}
+
+#define dxfitfunc _dxfitfunc
+#endif /* NEVER */
+
+/* - - - - - - - - - */
+
+/* Output curve symetry optimisation function handed to powell() */
+/* Just the order 0 value will be adjusted */
+static double symoptfunc(void *edata, double *v) {
+ xfit *p = (xfit *)edata;
+ double out[1], in[1] = { 0.0 };
+ int ch = p->opt_ch; /* Output channel being adjusted for symetry */
+ double rv;
+
+ /* Copy the parameter being tested back into xfit */
+ p->v[p->out_offs[ch]] = v[0];
+ *out = icxSTransFunc(p->v + p->out_offs[ch], p->oluord[ch], *in,
+ p->out_min[ch], p->out_max[ch]);
+
+ rv = out[0] * out[0];
+
+#ifdef DEBUG
+printf("~1symoptfunc returning %f\n",rv);
+#endif
+ return rv;
+}
+
+/* - - - - - - - - - */
+
+/* Set up for an optimisation run: */
+/* Figure out parameters being optimised, */
+/* copy them to start values, */
+/* init and scale the search radius */
+static void setup_xfit(
+xfit *p,
+double *wv, /* Return parameters to hand to optimiser */
+double *sa, /* Return search radius to hand to optimiser */
+double transrad,/* Nominal transfer curve radius, 0.0 - 3.0 */
+double matrad /* Nominal matrix radius, 0.0 - 1.0 */
+) {
+ int i;
+ p->opt_off = -1;
+ p->opt_cnt = 0;
+
+ if (p->opt_msk & oc_i) {
+
+ if (p->opt_ssch) { /* Special case - should only be used first, */
+ /* Fitting a sigle common input shaper curve. */
+ if (p->opt_off < 0)
+ p->opt_off = p->mat_off - p->sm_iluord; /* Shouldn't be used... */
+ p->opt_cnt += p->sm_iluord;
+
+ for (i = 0; i < p->sm_iluord; i++) {
+ *wv++ = 0.0;
+ *sa++ = transrad;
+ }
+
+ } else { /* Initial or continuing fitting of all the curves */
+ if (p->opt_off < 0)
+ p->opt_off = p->shp_off;
+ p->opt_cnt += p->shp_cnt;
+
+ for (i = 0; i < p->shp_cnt; i++) {
+ *wv++ = p->v[p->shp_off + i];
+ *sa++ = transrad;
+ }
+ }
+ }
+ if (p->opt_msk & oc_m) {
+ if (p->opt_off < 0)
+ p->opt_off = p->mat_off;
+ p->opt_cnt += p->mat_cnt;
+
+ for (i = 0; i < p->mat_cnt; i++) {
+ *wv++ = p->v[p->mat_off + i];
+ *sa++ = matrad;
+ }
+ }
+ if (p->opt_msk & oc_o) {
+ if (p->opt_off < 0)
+ p->opt_off = p->out_off;
+ p->opt_cnt += p->out_cnt;
+
+ for (i = 0; i < p->out_cnt; i++) {
+ *wv++ = p->v[p->out_off + i];
+ *sa++ = transrad;
+ }
+ }
+ if (p->opt_cnt > MXPARMS)
+ error("setup_xfit: asert, %d exceeded MXPARMS %d",p->opt_cnt,MXPARMS);
+
+#ifdef DEBUG
+ printf("setup_xfit() got opt_msk 0x%x, opt_off %d, opt_cnt = %d\n",
+ p->opt_msk,p->opt_off,p->opt_cnt);
+#endif /* DEBUG */
+}
+
+#ifdef DEBUG
+/* Diagnostic */
+static void dump_xfit(
+xfit *p
+) {
+ int i, e, f;
+ double *b; /* Base of parameters for this section */
+ int di, fdi;
+ di = p->di;
+ fdi = p->fdi;
+
+ /* Input positioning curve */
+ b = p->v + p->pos_off;
+ for (e = 0; e < di; b += p->iluord[e], e++) {
+ printf("pos %d = ",e);
+ for (i = 0; i < p->iluord[e]; i++)
+ printf("%f ",b[i]);
+ printf("\n");
+ }
+
+ /* Input shaper curve */
+ b = p->v + p->shp_off;
+ for (e = 0; e < di; b += p->iluord[e], e++) {
+ printf("shp %d = ",e);
+ for (i = 0; i < p->iluord[e]; i++)
+ printf("%f ",b[i]);
+ printf("\n");
+ }
+
+ /* Matrix */
+ b = p->v + p->mat_off;
+ for (e = 0; e < (1 << di); e++) {
+ printf("mx %d = ",e);
+ for (f = 0; f < fdi; f++)
+ printf("%f ",*b++);
+ printf("\n");
+ }
+
+ /* Output curve */
+ b = p->v + p->out_off;
+ for (f = 0; f < fdi; b += p->oluord[f], f++) {
+ printf("out %d = ",f);
+ for (i = 0; i < p->oluord[f]; i++)
+ printf("%f ",b[i]);
+ printf("\n");
+ }
+}
+#endif /* DEBUG */
+
+/* - - - - - - - - - */
+
+/* Setup the pseudo inverse information for each test point, */
+/* using the current model. */
+static void setup_piv(xfit *p) {
+ int di = p->di;
+ int fdi = p->fdi;
+ int i, e, f;
+
+ /* Estimate in -> out partial derivatives */
+ for (i = 0; i < p->nodp; i++) {
+ double pd[MXDO][MXDI];
+ double pp[MXDI];
+ double vv[MXDIDO];
+
+ /* Estimate in -> out partial derivatives */
+ for (e = 0; e < di; e++)
+ pp[e] = p->ipoints[i].p[e];
+
+ /* Apply input shaper channel curves */
+ for (e = 0; e < di; e++)
+ vv[e] = icxSTransFunc(p->v + p->shp_offs[e], p->iluord[e], pp[e],
+ p->in_min[e], p->in_max[e]);
+
+ /* Apply matrix cube interpolation */
+ icxCubeInterp(p->v + p->mat_off, fdi, di, vv, vv);
+
+ /* Apply output channel curves */
+ for (f = 0; f < fdi; f++)
+ vv[f] = icxSTransFunc(p->v + p->out_offs[f], p->oluord[f], vv[f],
+ p->out_min[f], p->out_max[f]);
+
+
+ for (e = 0; e < di; e++) {
+ double tt[MXDIDO];
+
+ pp[e] += 1e-4;
+
+ /* Apply input shaper channel curves */
+ for (e = 0; e < di; e++)
+ tt[e] = icxSTransFunc(p->v + p->shp_offs[e], p->iluord[e], pp[e],
+ p->in_min[e], p->in_max[e]);
+
+ /* Apply matrix cube interpolation */
+ icxCubeInterp(p->v + p->mat_off, fdi, di, tt, tt);
+
+ /* Apply output channel curves */
+ for (f = 0; f < fdi; f++)
+ tt[f] = icxSTransFunc(p->v + p->out_offs[f], p->oluord[f], tt[f],
+ p->out_min[f], p->out_max[f]);
+
+
+ for (f = 0; f < p->fdi; f++)
+ pd[f][e] = (tt[f] - vv[f])/1e-4;
+
+ pp[e] -= 1e-4;
+ }
+
+ /* Compute a psudo inverse matrix to map rout delta E to */
+ /* in delta E in proportion to the pd magnitude. */
+ for (f = 0; f < fdi; f++) {
+ double ss = 0.0;
+
+ for (e = 0; e < di; e++) /* Sum of pd's ^4 */
+ ss += pd[f][e] * pd[f][e] * pd[f][e] * pd[f][e];
+ ss = sqrt(ss);
+ if (ss > 1e-8) {
+ for (e = 0; e < di; e++)
+ p->piv[i].ide[f][e] = pd[f][e]/ss;
+ } else { /* Hmm. */
+ for (e = 0; e < di; e++)
+ p->piv[i].ide[f][e] = 0.0;
+ }
+ }
+ }
+}
+
+/* - - - - - - - - - */
+
+/* Function to pass to rspl to re-set output values, */
+/* to account for skeleton model offset. */
+static void
+skm_rspl_out(
+ void *pp, /* relativectx structure */
+ double *out, /* output value */
+ double *in /* input value */
+) {
+ xfit *p = (xfit *)pp;
+ int f, fdi = p->fdi;
+ double inval[MXDI];
+ double skval[MXDO];
+
+ /* Look up the skeleton value for this grid point */
+ xfit_invinpscurves(p, inval, in); /* Back to input values */
+ p->skm->lookup(p->skm, skval, inval); /* Skm */
+ xfit_abs_to_rel(p, skval, skval);
+ xfit_invoutcurves(p, skval, skval);
+
+ for (f = 0; f < fdi; f++)
+ out[f] += skval[f]; /* Add it back */
+}
+
+/* Weak function rspl callback (not used) */
+void skm_weak(void *cbntx, double *out, double *in) {
+ xfit *p = (xfit *)cbntx;
+
+#ifndef NEVER
+ int f, fdi = p->fdi;
+
+ for (f = 0; f < fdi; f++)
+ out[f] = 0.0; /* Deviation from skeleton should tend to zero */
+
+#else /* Skeleton as weak atractor */
+ int f, fdi = p->fdi;
+ double inval[MXDI];
+
+ /* Look up the skeleton value for this grid point */
+ xfit_invinpscurves(p, inval, in); /* Back to input values */
+ p->skm->lookup(p->skm, out, inval); /* Skm */
+ xfit_abs_to_rel(p, out, out);
+ xfit_invoutcurves(p, out, out);
+
+#endif
+}
+
+/* - - - - - - - - - */
+
+/* Function to pass to rspl to re-set output values, */
+/* to make them relative to the white and black points */
+static void
+conv_rspl_out(
+ void *pp, /* relativectx structure */
+ double *out, /* output value */
+ double *in /* input value */
+) {
+ xfit *p = (xfit *)pp;
+ double tt[3];
+
+ /* Convert the clut values to output values */
+ xfit_outcurves(p, tt, out);
+
+ if (p->flags & XFIT_OUT_LAB) {
+ icmLab2XYZ(&icmD50, tt, tt);
+ icmMulBy3x3(out, p->cmat, tt);
+ icmXYZ2Lab(&icmD50, out, out);
+
+ } else { /* We are all in XYZ */
+ icmMulBy3x3(out, p->cmat, tt);
+ }
+
+ /* And then convert them back to clut values */
+ xfit_invoutcurves(p, out, out);
+}
+
+/* Function to pass to rspl to re-set output values, */
+/* to clip any with Y over 1.0 to D50 */
+static void
+clip_rspl_out(
+ void *pp, /* relativectx structure */
+ double *out, /* output value */
+ double *in /* input value */
+) {
+ xfit *p = (xfit *)pp;
+ double tt[3];
+
+ /* Convert the clut values to output values */
+ xfit_outcurves(p, tt, out);
+
+ if (p->flags & XFIT_OUT_LAB) {
+ if (tt[0] > 100.0)
+ icmCpy3(out, p->cmat[0]);
+ } else {
+ if (tt[1] > 1.0)
+ icmCpy3(out, p->cmat[0]);
+ }
+}
+
+//#ifdef SPECIAL_TEST
+/* - - - - - - - - - */
+
+/* Execute the linear XYZ device model */
+static void domodel(double *out, double *in) {
+ double tmp[3];
+ int i, j;
+ double col[3][3]; /* sRGB additive colorant values in XYZ :- [out][in] */
+
+ col[0][0] = 0.412424; /* X from R */
+ col[0][1] = 0.357579; /* X from G */
+ col[0][2] = 0.180464; /* X from B */
+ col[1][0] = 0.212656; /* Y from R */
+ col[1][1] = 0.715158; /* Y from G */
+ col[1][2] = 0.0721856; /* Y from B */
+ col[2][0] = 0.0193324; /* Z from R */
+ col[2][1] = 0.119193; /* Z from G */
+ col[2][2] = 0.950444; /* Z from B */
+
+#ifdef SPECIAL_TEST_GAMMA
+ tmp[0] = pow(in[0], 1.9);
+ tmp[1] = pow(in[1], 2.0);
+ tmp[2] = pow(in[2], 2.1);
+#else
+ tmp[0] = in[0];
+ tmp[1] = in[1];
+ tmp[2] = in[2];
+#endif
+
+ for (j = 0; j < 3; j++) {
+ out[j] = 0.0;
+ for (i = 0; i < 3; i++)
+ out[j] += col[j][i] * tmp[i];
+ }
+}
+
+#ifdef SPECIAL_FORCE
+/* Function to pass to rspl to set nodes against */
+/* synthetic model. */
+static void
+set_rspl_out1(
+ void *pp, /* relativectx structure */
+ double *out, /* output value */
+ double *in /* input value */
+) {
+ xfit *p = (xfit *)pp;
+ double tt[3], tout[3];
+
+ /* Convert the input' values to input values */
+ xfit_invinpscurves(p, tt, in);
+
+ /* Synthetic linear rgb->XYZ model */
+ domodel(tout, tt);
+
+ /* Apply abs->rel white point adjustment */
+ icmMulBy3x3(tout, p->cmat, tout);
+
+#ifdef SPECIAL_TEST_LAB
+ icmXYZ2Lab(&icmD50, tout, tout);
+#endif
+ /* And then convert them back to clut values */
+ xfit_invoutcurves(p, tout, tout);
+
+#ifdef DEBUG
+printf("~1 changing %f %f %f -> %f %f %f\n", out[0], out[1], out[2], tout[0], tout[1], tout[2]);
+#endif
+
+ out[0] = tout[0];
+ out[1] = tout[1];
+ out[2] = tout[2];
+}
+
+#endif /* SPECIAL_FORCE */
+
+/* - - - - - - - - - */
+/* Do the fitting. */
+/* return nz on error */
+/* 1 = malloc or other error */
+int xfit_fit(
+ struct _xfit *p,
+ int flags, /* Flag values */
+ int di, /* Input dimensions */
+ int fdi, /* Output dimensions */
+ int rsplflags, /* clut rspl creation flags */
+ double *wp, /* if flags & XFIT_OUT_WP_REL or XFIT_OUT_WP_REL_US, */
+ /* Initial white point, returns final wp */
+ double *dw, /* Device white value to adjust to be D50 */
+ double wpscale, /* If >= 0.0 scale final wp */
+ double *dgw, /* Device space gamut boundary white for XFIT_OUT_WP_REL_US */
+ /* (ie. RGB 1,1,1 CMYK 0,0,0,0, etc) */
+ cow *ipoints, /* Array of data points to fit - referece taken */
+ int nodp, /* Number of data points */
+ icxMatrixModel *skm, /* Optional skeleton model (used for input profiles) */
+ double in_min[MXDI], /* Input value scaling/domain minimum */
+ double in_max[MXDI], /* Input value scaling/domain maximum */
+ int gres[MXDI], /* clut resolutions being optimised for/returned */
+ double out_min[MXDO], /* Output value scaling/range minimum */
+ double out_max[MXDO], /* Output value scaling/range maximum */
+ double smooth, /* clut rspl smoothing factor */
+ double oavgdev[MXDO], /* Average output value deviation */
+ int iord[], /* Order of input pos/shaper curve for each dimension */
+ int sord[], /* Order of input sub-grid shaper curve (not used) */
+ int oord[], /* Order of output shaper curve for each dimension */
+ double shp_smooth[MXDI],/* Smoothing factors for each curve, nom = 1.0 */
+ double out_smooth[MXDO],
+ optcomb tcomb, /* Flag - target elements to fit. */
+ void *cntx2, /* Context of callbacks */
+ /* Callback to convert two fit values delta E squared */
+ double (*to_de2)(void *cntx, double *in1, double *in2),
+ /* Same as above, with partial derivatives */
+ double (*to_dde2)(void *cntx, double dout[2][MXDIDO], double *in1, double *in2)
+) {
+ int i, e, f;
+ double *b; /* Base of parameters for this section */
+ int poff;
+
+ if (tcomb & oc_io) /* If we're doing anything, we need the matrix */
+ tcomb |= oc_m;
+
+ p->flags = flags;
+ if (flags & XFIT_VERB)
+ p->verb = 1;
+ else
+ p->verb = 0;
+ p->di = di;
+ p->fdi = fdi;
+ p->wp = wp; /* Take reference, so modified wp can be returned */
+ p->dw = dw;
+ p->nodp = nodp;
+ p->skm = skm; /* This isn't current used by profin, because it doesn't help.. */
+ p->ipoints = ipoints;
+ p->tcomb = tcomb;
+ p->cntx2 = cntx2;
+ for (e = 0; e < di; e++)
+ p->gres[e] = gres[e];
+ p->to_de2 = to_de2;
+ p->to_dde2 = to_dde2;
+
+#ifdef DEBUG
+ printf("xfit_fit called with flags = 0x%x, di = %d, fdi = %d, nodp = %d, tcomb = 0x%x\n",flags,di,fdi,nodp,tcomb);
+#endif
+
+//printf("~1 out min = %f %f %f max = %f %f %f\n", out_min[0], out_min[1], out_min[2], out_max[0], out_max[1], out_max[2]);
+
+ /* Sanity protect shaper orders */
+ /* and save scaling and smoothness factors. */
+ p->sm_iluord = MXLUORD+1;
+ for (e = 0; e < di; e++) {
+ if (iord[e] > MXLUORD)
+ p->iluord[e] = MXLUORD;
+ else
+ p->iluord[e] = iord[e];
+ if (p->iluord[e] < p->sm_iluord)
+ p->sm_iluord = p->iluord[e];
+ p->in_min[e] = in_min[e];
+ p->in_max[e] = in_max[e];
+ p->shp_smooth[e] = shp_smooth[e];
+ }
+ for (f = 0; f < fdi; f++) {
+ if (oord[f] > MXLUORD)
+ p->oluord[f] = MXLUORD;
+ else
+ p->oluord[f] = oord[f];
+ p->out_min[f] = out_min[f];
+ p->out_max[f] = out_max[f];
+ p->out_smooth[f] = out_smooth[f];
+ }
+
+
+ /* Compute parameter offset and count information */
+ p->shp_off = 0;
+ for (poff = p->shp_off, p->shp_cnt = 0, e = 0; e < di; e++) {
+ p->shp_offs[e] = poff;
+ p->shp_cnt += p->iluord[e];
+ poff += p->iluord[e];
+ }
+
+ p->mat_off = p->shp_off + p->shp_cnt;
+ for (poff = p->mat_off, p->mat_cnt = 0, f = 0; f < fdi; f++) {
+ p->mat_offs[f] = poff;
+ p->mat_cnt += (1 << di);
+ poff += (1 << di);
+ }
+
+ p->out_off = p->mat_off + p->mat_cnt;
+ for (poff = p->out_off, p->out_cnt = 0, f = 0; f < fdi; f++) {
+ p->out_offs[f] = poff;
+ p->out_cnt += p->oluord[f];
+ poff += p->oluord[f];
+ }
+
+ p->pos_off = p->out_off + p->out_cnt;
+ for (poff = p->pos_off, p->pos_cnt = 0, e = 0; e < di; e++) {
+ p->pos_offs[e] = poff;
+ p->pos_cnt += p->iluord[e];
+ poff += p->iluord[e];
+ }
+
+ p->tot_cnt = p->shp_cnt + p->mat_cnt + p->out_cnt + p->pos_cnt;
+ if (p->tot_cnt > MXPARMS)
+ error("xfit_fit: assert tot_cnt exceeds MXPARMS");
+
+ /* Allocate space for parameter values */
+ if (p->v != NULL) {
+ free(p->v);
+ p->v = NULL;
+ }
+ if (p->wv != NULL) {
+ free(p->wv);
+ p->wv = NULL;
+ }
+ if (p->sa != NULL) {
+ free(p->sa);
+ p->sa = NULL;
+ }
+ if ((p->v = (double *)calloc(p->tot_cnt, sizeof(double))) == NULL)
+ return 1;
+ if ((p->wv = (double *)calloc(p->tot_cnt, sizeof(double))) == NULL)
+ return 1;
+ if ((p->sa = (double *)calloc(p->tot_cnt, sizeof(double))) == NULL)
+ return 1;
+
+ /* Setup initial white point abs->rel conversions */
+ if ((p->flags & XFIT_OUT_WP_REL) != 0) {
+ icmXYZNumber _wp;
+
+ icmAry2XYZ(_wp, p->wp);
+
+ /* Absolute->Aprox. Relative Adaptation matrix */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->fromAbs);
+
+ /* Aproximate relative to absolute conversion matrix */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, _wp, icmD50, p->toAbs);
+
+ if (p->verb) {
+ double lab[3];
+ icmXYZ2Lab(&icmD50, lab, p->wp);
+ printf("Initial White Point XYZ %f %f %f, Lab %f %f %f\n",
+ p->wp[0], p->wp[1], p->wp[2], lab[0], lab[1], lab[2]);
+ }
+ } else {
+ icmSetUnity3x3(p->fromAbs);
+ icmSetUnity3x3(p->toAbs);
+ }
+
+ /* Setup input position/shape curves to be linear initially */
+ b = p->v + p->shp_off;
+ for (e = 0; e < di; b += p->iluord[e], e++) {
+ for (i = 0; i < p->iluord[e]; i++) {
+ b[i] = 0.0;
+ }
+ }
+
+ /* Setup matrix to be pure colorant' values initially */
+ b = p->v + p->mat_off;
+ for (e = 0; e < (1 << di); e++) { /* For each colorant combination */
+ int j, k, bk = 0;
+ double bdif = 1e6;
+ double ov[MXDO];
+
+ /* Search the patch list to find the one closest to this input combination */
+ for (k = 0; k < p->nodp; k++) {
+ double dif = 0.0;
+ for (j = 0; j < di; j++) {
+ double tt;
+ if (e & (1 << j))
+ tt = p->in_max[j] - p->ipoints[k].p[j];
+ else
+ tt = p->in_min[j] - p->ipoints[k].p[j];
+ dif += tt * tt;
+ }
+ if (dif < bdif) { /* best so far */
+ bdif = dif;
+ bk = k;
+ if (dif < 0.001)
+ break; /* Don't bother looking further */
+ }
+ }
+ xfit_abs_to_rel(p, ov, p->ipoints[bk].v);
+
+ for (f = 0; f < fdi; f++)
+ b[f * (1 << di) + e] = ov[f];
+ }
+
+ /* Setup output curves to be linear initially */
+ b = p->v + p->out_off;
+ for (f = 0; f < fdi; b += p->oluord[f], f++) {
+ for (i = 0; i < p->oluord[f]; i++) {
+ b[i] = 0.0;
+ }
+ }
+
+ /* Setup positioning curves to be linear initially */
+ b = p->v + p->pos_off;
+ for (e = 0; e < di; b += p->iluord[e], e++) {
+ for (i = 0; i < p->iluord[e]; i++) {
+ b[i] = 0.0;
+ }
+ }
+
+ /* Create copy of input points with output converted to white relative */
+ if (p->rpoints == NULL) {
+ if ((p->rpoints = (cow *)malloc(p->nodp * sizeof(cow))) == NULL)
+ return 1;
+ }
+ for (i = 0; i < p->nodp; i++) {
+ p->rpoints[i].w = p->ipoints[i].w;
+ for (e = 0; e < di; e++)
+ p->rpoints[i].p[e] = p->ipoints[i].p[e];
+ for (f = 0; f < fdi; f++)
+ p->rpoints[i].v[f] = p->ipoints[i].v[f];
+
+ /* out -> rout */
+ xfit_abs_to_rel(p, p->rpoints[i].v, p->rpoints[i].v);
+ }
+
+ /* Allocate array of pseudo-inverse matricies */
+ if ((p->flags & XFIT_FM_INPUT) != 0 && p->piv == NULL) {
+ if ((p->piv = (xfit_piv *)malloc(p->nodp * sizeof(xfit_piv))) == NULL)
+ return 1;
+ }
+
+ /* Allocate array of span DE's for current opt channel */
+ {
+ int lres = 0;
+ for (e = 0; e < di; e++) {
+ if (p->gres[e] > lres)
+ lres = p->gres[e];
+ }
+ if ((p->uerrv = (double *)malloc(lres * sizeof(double))) == NULL)
+ return 1;
+ }
+
+ /* Do the fitting one part at a time, then together */
+ /* Shaper curves are created if position or shaper curves are requested */
+
+ /* Fit just the matrix */
+ if ((p->tcomb & oc_ipo) != 0
+ && (p->tcomb & oc_m) == oc_m) { /* Only bother with matrix if in and/or out */
+ double rerr;
+
+ if (p->verb)
+ printf("About to optimise temporary matrix\n");
+
+ /* Setup pseudo-inverse if we need it */
+ if (p->flags & XFIT_FM_INPUT)
+ setup_piv(p);
+
+#ifdef DEBUG
+printf("\nBefore matrix opt:\n");
+dump_xfit(p);
+#endif
+ /* Optimise matrix on its own */
+ p->opt_ssch = 0;
+ p->opt_ch = -1;
+ p->opt_msk = oc_m;
+ setup_xfit(p, p->wv, p->sa, 0.0, 0.5);
+
+#ifdef NODDV
+ if (powell(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, (void *)p, xfitprog, (void *)p) != 0)
+ warning("xfit_fit: Powell failed to converge, residual error = %f",rerr);
+#else
+ if (conjgrad(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, dxfitfunc, (void *)p, xfitprog, (void *)p) != 0)
+ warning("xfit_fit: Conjgrad failed to converge, residual error = %f", rerr);
+#endif
+ for (i = 0; i < p->opt_cnt; i++) /* Copy optimised values back */
+ p->v[p->opt_off + i] = p->wv[i];
+
+#ifdef DEBUG
+printf("\nAfter matrix opt:\n");
+dump_xfit(p);
+#endif
+ }
+
+ /* Optimise input and matrix together */
+ if ((p->tcomb & oc_im) == oc_im) {
+ double rerr;
+
+ if (p->verb)
+ printf("About to optimise a common input curve and matrix\n");
+
+ /* Setup pseudo-inverse if we need it */
+ if (p->flags & XFIT_FM_INPUT)
+ setup_piv(p);
+
+ p->opt_ssch = 1;
+ p->opt_ch = -1;
+ p->opt_msk = oc_im;
+ setup_xfit(p, p->wv, p->sa, 0.5, 0.3);
+
+#ifdef NODDV
+ if (powell(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, (void *)p, xfitprog, (void *)p) != 0) {
+#ifdef DEBUG
+ warning("xfit_fit: Powell failed to converge, residual error = %f",rerr);
+#endif
+ }
+#else
+ if (conjgrad(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, dxfitfunc, (void *)p, xfitprog, (void *)p) != 0) {
+#ifdef DEBUG
+ warning("xfit_fit: Conjgrad failed to converge, residual error = %f",rerr);
+#endif
+ }
+#endif /* !NODDV */
+ for (e = 0; e < di; e++) { /* Copy optimised values back */
+ for (i = 0; i < p->sm_iluord; i++)
+ p->v[p->shp_offs[e] + i] = p->wv[i];
+ for (; i < p->iluord[e]; i++)
+ p->v[p->shp_offs[e] + i] = 0.0;
+ }
+ for (i = p->sm_iluord; i < p->opt_cnt; i++)
+ p->v[p->mat_off + i - p->sm_iluord] = p->wv[i];
+#ifdef DEBUG
+printf("\nAfter input and matrix opt:\n");
+dump_xfit(p);
+#endif
+
+ /* - - - - - - - - - - - */
+ if (p->verb)
+ printf("About to optimise input curves and matrix\n");
+
+ /* Setup pseudo-inverse if we need it */
+ if (p->flags & XFIT_FM_INPUT)
+ setup_piv(p);
+
+ p->opt_ssch = 0;
+ p->opt_ch = -1;
+ p->opt_msk = oc_im;
+ setup_xfit(p, p->wv, p->sa, 0.5, 0.3);
+ /* Suppress the warnings the first time through - it's better to cut off the */
+ /* itterations and move on to the output curve, and worry about it not */
+ /* converging the second time through. */
+#ifdef NODDV
+ if (powell(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, (void *)p, xfitprog, (void *)p) != 0) {
+#ifdef DEBUG
+ warning("xfit_fit: Powell failed to converge, residual error = %f",rerr);
+#endif
+ }
+#else
+ if (conjgrad(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, dxfitfunc, (void *)p, xfitprog, (void *)p) != 0) {
+#ifdef DEBUG
+ warning("xfit_fit: Conjgrad failed to converge, residual error = %f",rerr);
+#endif
+ }
+#endif /* !NODDV */
+ for (i = 0; i < p->opt_cnt; i++) /* Copy optimised values back */
+ p->v[p->opt_off + i] = p->wv[i];
+#ifdef DEBUG
+printf("\nAfter input and matrix opt:\n");
+dump_xfit(p);
+#endif
+ }
+
+ /* Optimise the matrix and output curves together */
+ if ((p->tcomb & oc_mo) == oc_mo) {
+ double rerr;
+
+ if (p->verb)
+ printf("About to optimise output curves and matrix\n");
+
+ /* Setup pseudo-inverse if we need it */
+ if (p->flags & XFIT_FM_INPUT)
+ setup_piv(p);
+
+ p->opt_ssch = 0;
+ p->opt_ch = -1;
+ p->opt_msk = oc_mo;
+ setup_xfit(p, p->wv, p->sa, 0.3, 0.3);
+#ifdef NODDV
+ if (powell(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, (void *)p, xfitprog, (void *)p) != 0)
+ warning("xfit_fit: Powell failed to converge, residual error = %f",rerr);
+#else
+ if (conjgrad(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS, xfitfunc,
+ dxfitfunc, (void *)p, xfitprog, (void *)p) != 0)
+ warning("xfit_fit: Conjgrad failed to converge, residual error = %f",rerr);
+#endif
+ for (i = 0; i < p->opt_cnt; i++) /* Copy optimised values back */
+ p->v[p->opt_off + i] = p->wv[i];
+#ifdef DEBUG
+printf("\nAfter output opt:\n");
+dump_xfit(p);
+#endif
+
+ /* Optimise input and matrix together again, after altering matrix */
+ if ((p->tcomb & oc_im) == oc_im) {
+
+ if (p->verb)
+ printf("About to optimise input curves and matrix again\n");
+
+ /* Setup pseudo-inverse if we need it */
+ if (p->flags & XFIT_FM_INPUT)
+ setup_piv(p);
+
+ p->opt_ssch = 0;
+ p->opt_ch = -1;
+ p->opt_msk = oc_im;
+ setup_xfit(p, p->wv, p->sa, 0.2, 0.2);
+#ifdef NODDV
+ if (powell(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, (void *)p, xfitprog, (void *)p) != 0)
+ warning("xfit_fit: Powell failed to converge, residual error = %f",rerr);
+#else
+ if (conjgrad(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, dxfitfunc, (void *)p, xfitprog, (void *)p) != 0)
+ warning("xfit_fit: Conjgrad failed to converge, residual error = %f",rerr);
+#endif
+ for (i = 0; i < p->opt_cnt; i++) /* Copy optimised values back */
+ p->v[p->opt_off + i] = p->wv[i];
+ }
+#ifdef DEBUG
+printf("\nAfter 2nd input and matrix opt:\n");
+dump_xfit(p);
+#endif
+
+#ifndef NODDV
+ /* Optimise all together */
+ if ((p->tcomb & oc_imo) == oc_imo) {
+
+ if (p->verb)
+ printf("About to optimise input, matrix and output together\n");
+
+ /* Setup pseudo-inverse if we need it */
+ if (p->flags & XFIT_FM_INPUT)
+ setup_piv(p);
+
+ p->opt_ssch = 0;
+ p->opt_ch = -1;
+ p->opt_msk = oc_imo;
+ setup_xfit(p, p->wv, p->sa, 0.1, 0.1);
+ if (conjgrad(&rerr, p->opt_cnt, p->wv, p->sa, POWTOL, MAXITS,
+ xfitfunc, dxfitfunc, (void *)p, xfitprog, (void *)p) != 0)
+ warning("xfit_fit: Conjgrad failed to converge, residual error = %f",rerr);
+ for (i = 0; i < p->opt_cnt; i++) /* Copy optimised values back */
+ p->v[p->opt_off + i] = p->wv[i];
+
+ /* Setup final pseudo-inverse from shaper/matrix/out */
+ if (p->flags & XFIT_FM_INPUT)
+ setup_piv(p);
+ }
+
+#ifdef DEBUG
+printf("\nAfter all together opt:\n");
+dump_xfit(p);
+#endif
+
+#endif /* !NODDV */
+
+ /* Adjust output curve white point. */
+ /* This is for the benefit of the B2A table */
+ if (p->flags & XFIT_OUT_ZERO) {
+
+ if (p->verb)
+ printf("About to adjust a and b output curves for white point\n");
+
+ for (f = 1; f < 3 && f < p->fdi; f++) {
+ p->opt_ch = f;
+ p->wv[0] = p->v[p->out_offs[f]]; /* Current parameter value */
+ p->sa[0] = 0.1; /* Search radius */
+ if (powell(&rerr, 1, p->wv, p->sa, 0.0000001, 1000,
+ symoptfunc, (void *)p, NULL, NULL) != 0)
+ error("xfit_fit: Powell failed to converge, residual error = %f",rerr);
+ p->v[p->out_offs[f]] = p->wv[0]; /* Copy results back */
+ }
+ }
+ }
+
+ /* In case we don't generate position curves, */
+ /* copy the input curves to the position, so that */
+ /* ipos is computed correctly */
+ {
+ double *bb;
+
+ b = p->v + p->shp_off;
+ bb = p->v + p->pos_off;
+ for (e = 0; e < di; b += p->iluord[e], bb += p->iluord[e], e++) {
+ for (i = 0; i < p->iluord[e]; i++) {
+ bb[i] = b[i];
+ }
+ }
+ }
+
+
+ /* If we want position curves, generate them */
+ /* (This could possibly be improved by using some sort */
+ /* of optimization drivel approach rather than the predictive */
+ /* method used here.) */
+ if (p->tcomb & oc_p) {
+ int ee;
+
+ if (p->verb)
+ printf("About to create grid position input curves\n");
+
+ /* Allocate in->rout duplicate point set */
+ if (p->rpoints == NULL) {
+ if ((p->rpoints = (cow *)malloc(p->nodp * sizeof(cow))) == NULL)
+ return 1;
+ }
+
+ /* Create a set of 1D rspl setup points that contains */
+ /* the residual error */
+ for (i = 0; i < p->nodp; i++) {
+ double tv[MXDO]; /* Target output value */
+ double mv[MXDO]; /* Model output value */
+ double ev;
+
+ xfit_abs_to_rel(p, tv, p->ipoints[i].v);
+ xfit_shmatsh(p, mv, p->ipoints[i].p);
+
+ /* Evaluate the error squared */
+ if (p->flags & XFIT_FM_INPUT) {
+ double pp[MXDI];
+ for (e = 0; e < di; e++)
+ pp[e] = p->ipoints[i].p[e];
+ for (f = 0; f < fdi; f++) {
+ double t1 = tv[f] - mv[f]; /* Error in output */
+
+ /* Create input point offset by equivalent delta to output point */
+ /* error, in proportion to the partial derivatives for that output. */
+ for (e = 0; e < di; e++)
+ pp[e] += t1 * p->piv[i].ide[f][e];
+ }
+ ev = p->to_de2(p->cntx2, pp, p->ipoints[i].p);
+ } else {
+ ev = p->to_de2(p->cntx2, mv, tv);
+ }
+ p->rpoints[i].v[0] = ev;
+ p->rpoints[i].w = p->ipoints[i].w;
+ }
+
+ /* Do each input axis in turn */
+ for (ee = 0; ee < p->di; ee++) {
+ rspl *resid;
+ double imin[1],imax[1],omin[1],omax[1];
+ int resres[1] = { 1024 };
+#define NPGP 100
+ mcv *posc;
+ mcvco pgp[NPGP];
+ double vo, vs;
+ double *pms;
+
+ /* Create a rspl that plots the residual error */
+ /* vs the axis value */
+ for (i = 0; i < p->nodp; i++)
+ p->rpoints[i].p[0] = p->ipoints[i].p[ee];
+
+ imin[0] = in_min[ee];
+ imax[0] = in_max[ee];
+ omin[0] = 0.0;
+ omax[0] = 0.0;
+
+ if ((resid = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL)
+ return 1;
+
+ resid->fit_rspl_w(resid, RSPLFLAGS, p->rpoints, p->nodp, imin, imax, resres,
+ omin, omax, 2.0, NULL, NULL);
+
+#ifdef DEBUG_PLOT
+ {
+#define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+
+ printf("Input residual error channel %d\n",ee);
+ for (i = 0; i < XRES; i++) {
+ co pp;
+ double x;
+ x = i/(double)(XRES-1);
+ xx[i] = x = x * (imax[0] - imin[0]) + imin[0];
+ pp.p[0] = xx[i];
+ resid->interp(resid, &pp);
+ y1[i] = pp.v[0];
+ if (y1[i] < 0.0)
+ y1[i] = 0.0;
+ y1[i] = pow(y1[i], 0.5); /* Convert from error^2 to error */
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+#endif /* DEBUG_PLOT */
+
+ /* Create a set of guide points that contain */
+ /* the accumulated residual error vs. the axis value */
+ for (i = 0; i < NPGP; i++) {
+ co pp;
+ double vv;
+
+ pp.p[0] = i/(NPGP-1.0);
+ resid->interp(resid, &pp);
+
+ pgp[i].p = (pp.p[0] - in_min[ee])/(in_max[ee] - in_min[ee]);
+ pgp[i].w = 1.0;
+
+ vv = pp.v[0];
+ if (vv < 0.0)
+ vv = 0.0;
+ vv = pow(vv, 0.5); /* Convert from error^2 to error */
+ vv += PSHAPE_MINE; /* In case error is near zero */
+ vv = pow(vv, PSHAPE_DIST); /* Agressivness of grid distribution */
+
+ if (i == 0)
+ pgp[i].v = vv;
+ else
+ pgp[i].v = pgp[i-1].v + vv;
+ }
+ resid->del(resid);
+
+ /* Normalize the output range */
+ vo = pgp[0].v;
+ vs = pgp[NPGP-1].v - vo;
+
+ for (i = 0; i < NPGP; i++) {
+ pgp[i].v = (pgp[i].v - vo)/vs;
+
+//printf("~1 guide point %d: %f -> %f\n",i,pgp[i].p,pgp[i].v);
+ }
+ /* Fit the non-monotonic parameters to the guide points */
+ if ((posc = new_mcv_noos()) == NULL)
+ return 1;
+
+ posc->fit(posc, 0, p->iluord[ee], pgp, NPGP, 0.1); // ~~99
+
+#ifdef DEBUG_PLOT
+ {
+#define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+
+ printf("Position curve %d\n",ee);
+ for (i = 0; i < XRES; i++) {
+ xx[i] = i/(double)(XRES-1);
+ y1[i] = posc->interp(posc, xx[i]);
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+#endif /* DEBUG_PLOT */
+
+ /* Transfer parameters to xfit pos (skip offset and scale) */
+ posc->get_params(posc, &pms);
+
+ for (i = 0; i < p->iluord[ee]; i++) {
+ p->v[p->pos_offs[ee] + i] = pms[i+2];
+ }
+//p->v[p->in_offs[ee]] = -1.5;
+
+ free(pms);
+ posc->del(posc);
+ }
+ }
+
+#ifdef DEBUG
+printf("Final parameters:\n");
+dump_xfit(p);
+#endif
+
+#ifdef DEBUG_PLOT
+ {
+#define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+
+ for (e = 0; e < p->di; e++) {
+ printf("Input position curve channel %d\n",e);
+ for (i = 0; i < XRES; i++) {
+ double x;
+ x = i/(double)(XRES-1);
+ xx[i] = x = x * (p->in_max[e] - p->in_min[e]) + p->in_min[e];
+ y1[i] = xfit_poscurve(p, x, e);
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+
+ for (e = 0; e < p->di; e++) {
+ printf("Input shape curve channel %d\n",e);
+ for (i = 0; i < XRES; i++) {
+ double x;
+ x = i/(double)(XRES-1);
+ xx[i] = x = x * (p->in_max[e] - p->in_min[e]) + p->in_min[e];
+ y1[i] = xfit_shpcurve(p, x, e);
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+
+ for (e = 0; e < p->di; e++) {
+ printf("Combined input curve channel %d\n",e);
+ for (i = 0; i < XRES; i++) {
+ double x;
+ x = i/(double)(XRES-1);
+ xx[i] = x = x * (p->in_max[e] - p->in_min[e]) + p->in_min[e];
+ y1[i] = p->incurve(p, x, e);
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+
+ for (f = 0; f < p->fdi; f++) {
+ printf("Output curve channel %d\n",f);
+ for (i = 0; i < XRES; i++) {
+ double x;
+ x = i/(double)(XRES-1);
+ xx[i] = x = x * (p->out_max[f] - p->out_min[f]) + p->out_min[f];
+ y1[i] = p->outcurve(p, x, f);
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+ }
+#endif /* DEBUG_PLOT */
+
+ /* Create final clut rspl using the established pos/shape/output curves */
+ /* and white point */
+ if (flags & XFIT_MAKE_CLUT) {
+ double *ipos[MXDI];
+
+ /* Create an in' -> rout' scattered test point set */
+ if (p->rpoints == NULL) {
+ if ((p->rpoints = (cow *)malloc(p->nodp * sizeof(cow))) == NULL)
+ return 1;
+ }
+ for (i = 0; i < p->nodp; i++) {
+ p->rpoints[i].w = p->ipoints[i].w;
+ xfit_inpscurves(p, p->rpoints[i].p, p->ipoints[i].p);
+ for (f = 0; f < fdi; f++)
+ p->rpoints[i].v[f] = p->ipoints[i].v[f];
+ xfit_abs_to_rel(p, p->rpoints[i].v, p->rpoints[i].v);
+ xfit_invoutcurves(p, p->rpoints[i].v, p->rpoints[i].v);
+
+ if (p->skm) {
+ /* Look up the skeleton value */
+ double skval[MXDO];
+ p->skm->lookup(p->skm, skval, p->ipoints[i].p);
+ xfit_abs_to_rel(p, skval, skval);
+ xfit_invoutcurves(p, skval, skval);
+
+//printf("~1 point %d at %f %f %f, targ %f %f %f skm %f %f %f\n",
+//i,p->ipoints[i].p[0],p->ipoints[i].p[1],p->ipoints[i].p[2],
+//p->rpoints[i].v[0],p->rpoints[i].v[1],p->rpoints[i].v[2],
+//skval[0], skval[1], skval[2]);
+ /* Subtract it from value at this point, */
+ /* so rspl will fit difference to skeleton model */
+ for (f = 0; f < fdi; f++)
+ p->rpoints[i].v[f] -= skval[f];
+ }
+//printf("~1 point %d, w %f, %f %f %f %f -> %f %f %f\n",
+//i,p->rpoints[i].w,p->rpoints[i].p[0], p->rpoints[i].p[1], p->rpoints[i].p[2], p->rpoints[i].p[3],
+//p->rpoints[i].v[0], p->rpoints[i].v[1], p->rpoints[i].v[2]);
+ }
+
+ /* Create ipos[] arrays, that hold the shaper space */
+ /* grid position due to the positioning curves. */
+ /* This tells the rspl scattered data interpolator */
+ /* the grid spacing that smoothness should be */
+ /* measured against. */
+#ifdef DEBUG
+printf("~1 about to setup ipos\n");
+#endif
+ for (e = 0; e < p->di; e++) {
+//printf("~1 e = %d\n",e);
+ if ((ipos[e] = (double *)malloc((p->gres[e]) * sizeof(double))) == NULL)
+ return 1;
+//printf("~1 about to do %d spans\n",p->gres[e]);
+ for (i = 0; i < p->gres[e]; i++) {
+ double cv;
+ cv = (double)i/p->gres[e];
+
+//printf("~1 i = %d, pos space = %f\n",i,cv);
+ /* Inverse lookup grid position through positioning curve */
+ /* to give device space type value */
+ cv = icxInvTransFunc(p->v + p->pos_offs[e], p->iluord[e], cv);
+
+//printf("~1 dev space = %f\n",cv);
+ /* Forward lookup device type value through the shaper curve */
+ /* to give value in shape linearized space. */
+ cv = icxTransFunc(p->v + p->shp_offs[e], p->iluord[e], cv);
+//printf("~1 shape space = %f\n",cv);
+ ipos[e][i] = cv;
+#ifdef DEBUG
+printf("~1 ipos[%d][%d] = %f\n",e,i,cv);
+#endif
+ }
+ }
+
+ if (p->clut != NULL)
+ p->clut->del(p->clut);
+ if ((p->clut = new_rspl(RSPL_NOFLAGS, di, fdi)) == NULL)
+ return 1;
+
+ if (p->verb)
+ printf("Create final clut from scattered data\n");
+
+#ifdef EXTEND_GRID
+#define XN EXTEND_GRID_BYN
+ /* Try increasing the grid by one row all around */
+ {
+#pragma message("!!!!!!!!!!!! Experimental rspl fitting resolution !!!!!!!!!")
+ double xin_min[MXDI];
+ double xin_max[MXDI];
+ int xgres[MXDI];
+ double del;
+ double *xipos[MXDI];
+
+ for (e = 0; e < p->di; e++) {
+ del = (in_max[e] - in_min[e])/(gres[e]-1.0); /* Extension */
+ xin_min[e] = in_min[e] - XN * del;
+ xin_max[e] = in_max[e] + XN * del;
+ xgres[e] = gres[e] + 2 * XN;
+//printf("~1 xgres %d, gres %d\n",xgres[e], gres[e]);
+
+ if ((xipos[e] = (double *)malloc((xgres[e]) * sizeof(double))) == NULL)
+ return 1;
+ for (i = 0; i < xgres[e]; i++) {
+ if (i < XN) { /* Extrapolate bottom */
+ xipos[e][i] = ipos[e][0] - (XN - i) * (ipos[e][1] - ipos[e][0]);
+//printf("~1 xipos[%d] %f from ipos[%d] %f and ipos[%d] %f\n",i,xipos[e][i],0,ipos[e][0],1,ipos[e][1]);
+ } else if (i >= (xgres[e]-XN)) { /* Extrapolate top */
+ xipos[e][i] = ipos[e][gres[e]-1] + (i - xgres[e] + XN + 1) * (ipos[e][gres[e]-1] - ipos[e][gres[e]-2]);
+//printf("~1 xipos[%d] %f from ipos[%d] %f and ipos[%d] %f\n",i,xipos[e][i],gres[e]-1,ipos[e][gres[e]-1],gres[e]-2,ipos[e][gres[e]-2]);
+ } else {
+ xipos[e][i] = ipos[e][i-XN];
+//printf("~1 xipos[%d] %f from ipos[%d] %f\n",i,xipos[e][i],i-XN,ipos[e][i-XN]);
+ }
+ }
+ }
+
+ p->clut->fit_rspl_w(p->clut, rsplflags, p->rpoints, p->nodp, xin_min, xin_max, xgres,
+ out_min, out_max, smooth, oavgdev, xipos);
+
+ for (e = 0; e < p->di; e++) {
+ free(xipos[e]);
+ }
+ }
+#undef XN
+#else
+// if (p->skm) {
+// /* This doesn't seem to work as well as some explicit neutral axis points.. */
+// p->clut->fit_rspl_w_df(p->clut, rsplflags, p->rpoints, p->nodp, in_min, in_max, gres,
+// out_min, out_max, smooth, oavgdev, ipos, 1.0, (void *)p, skm_weak);
+// } else
+ p->clut->fit_rspl_w(p->clut, rsplflags, p->rpoints, p->nodp, in_min, in_max, gres,
+ out_min, out_max, smooth, oavgdev, ipos);
+#endif
+ if (p->verb)
+ printf("\n");
+
+ for (e = 0; e < p->di; e++)
+ free(ipos[e]);
+
+ /* If we used a skeleton model, add it into the resulting rspl values */
+ if (p->skm) {
+
+ /* Undo the input point change to allow diagnostic code to work */
+ for (i = 0; i < p->nodp; i++) {
+ /* Look up the skeleton value */
+ double skval[MXDO];
+ p->skm->lookup(p->skm, skval, p->ipoints[i].p);
+ xfit_abs_to_rel(p, skval, skval);
+ xfit_invoutcurves(p, skval, skval);
+
+ /* Subtract it from value at this point, */
+ /* so rspl will fit difference to skeleton model */
+ for (f = 0; f < fdi; f++)
+ p->rpoints[i].v[f] += skval[f];
+ }
+
+ /* Undo the skm from the resultant rspl */
+ p->clut->re_set_rspl(
+ p->clut, /* this */
+ 0, /* Combination of flags */
+ (void *)p, /* Opaque function context */
+ skm_rspl_out /* Function to set from */
+ );
+
+ }
+
+ /* The overall device to absolute conversion is now what we want */
+ /* (as dictated by the points, weighting and best fit), */
+ /* but we need to adjust the device to relative conversion */
+ /* to make device white map exactly to D50, without touching */
+ /* the overall absolute behaviour. */
+ if (p->flags & XFIT_OUT_WP_REL) {
+ co wcc; /* device white + aprox rel. white */
+ icmXYZNumber _wp; /* Uncorrected dw maps to _wp */
+
+ if (p->verb)
+ printf("Doing White point fine tune:\n");
+
+ /* See what the relative and absolute white point has turned out to be, */
+ /* by looking up the device white in the current conversion */
+ xfit_inpscurves(p, wcc.p, dw);
+ p->clut->interp(p->clut, &wcc);
+ xfit_outcurves(p, wcc.v, wcc.v);
+ if (p->flags & XFIT_OUT_LAB)
+ icmLab2XYZ(&icmD50, wcc.v, wcc.v);
+
+ if (p->verb) {
+ double labwp[3];
+ icmXYZ2Lab(&icmD50, labwp, wcc.v);
+ printf("Before fine tune, rel WP = XYZ %f %f %f, Lab %f %f %f\n",
+ wcc.v[0], wcc.v[1],wcc.v[2], labwp[0], labwp[1], labwp[2]);
+ }
+
+ /* Matrix needed to correct approx rel wp to target D50 */
+ icmAry2XYZ(_wp, wcc.v); /* Aprox relative target white point */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->cmat); /* Correction */
+
+ /* Compute the actual white point, and return it to caller */
+ icmMulBy3x3(wp, p->toAbs, wcc.v);
+ icmAry2Ary(p->wp, wp);
+
+ /* Apply correction to fine tune rspl data. */
+ /* NOTE: this doesn't always give us a perfect D50 white for */
+ /* Lab PCS input profiles because the dev white may land */
+ /* within a cell, and the clipping of Lab PCS values in the grid */
+ /* may introduce errors in the interpolated value. */
+ p->clut->re_set_rspl(
+ p->clut, /* this */
+ 0, /* Combination of flags */
+ (void *)p, /* Opaque function context */
+ conv_rspl_out /* Function to set from */
+ );
+
+ /* Fix absolute conversions to leave absolute response unchanged. */
+ icmAry2XYZ(_wp, wp); /* Actual white point */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->fromAbs);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, _wp, icmD50, p->toAbs);
+
+ if (p->verb) {
+ double labwp[3];
+
+ /* Lookup white again */
+ xfit_inpscurves(p, wcc.p, dw);
+ p->clut->interp(p->clut, &wcc);
+ xfit_outcurves(p, wcc.v, wcc.v);
+ if (p->flags & XFIT_OUT_LAB)
+ icmLab2XYZ(&icmD50, wcc.v, wcc.v);
+ icmXYZ2Lab(&icmD50, labwp, wcc.v);
+ printf("After fine tune, rel WP = XYZ %f %f %f, Lab %f %f %f\n",
+ wcc.v[0], wcc.v[1], wcc.v[2], labwp[0], labwp[1], labwp[2]);
+ printf(" abs WP = XYZ %s, Lab %s\n", icmPdv(3, wp), icmPLab(wp));
+ }
+ }
+
+ /* Create default wpscale */
+ if (wpscale < 0.0) {
+ wpscale = 1.0;
+ } else {
+ if (p->verb) {
+ printf("White manual point scale %f\n", wpscale);
+ }
+ }
+
+ /* If we are going to auto scale the WP to avoid clipping */
+ /* cLUT values above the WP: */
+ if ((p->flags & XFIT_OUT_WP_REL_US) == XFIT_OUT_WP_REL_US) {
+ co wcc;
+ double bw[3];
+ icmXYZNumber _wp;
+ double uswpscale = 1.0;
+ double mxd, mxY;
+ double ndw[3];
+
+ /* See what device space gamut boundary white (ie. 1,1,1) maps to */
+ xfit_inpscurves(p, wcc.p, dgw);
+ p->clut->interp(p->clut, &wcc);
+ xfit_outcurves(p, wcc.v, wcc.v);
+ if (p->flags & XFIT_OUT_LAB)
+ icmLab2XYZ(&icmD50, wcc.v, wcc.v);
+ icmMulBy3x3(wcc.v, p->toAbs, wcc.v); /* Convert to absolute */
+
+ mxY = wcc.v[1];
+ icmCpy3(bw, wcc.v);
+//printf("~1 1,1,1 Y = %f\n",wcc.v[1]);
+
+ /* See what the device white point value scaled to 1 produces */
+ mxd = -1.0;
+ for (e = 0; e < p->di; e++) {
+ if (dw[e] > mxd)
+ mxd = dw[e];
+ }
+ for (e = 0; e < p->di; e++)
+ ndw[e] = dw[e]/mxd;
+
+ xfit_inpscurves(p, wcc.p, ndw);
+ p->clut->interp(p->clut, &wcc);
+ xfit_outcurves(p, wcc.v, wcc.v);
+ if (p->flags & XFIT_OUT_LAB)
+ icmLab2XYZ(&icmD50, wcc.v, wcc.v);
+ icmMulBy3x3(wcc.v, p->toAbs, wcc.v); /* Convert to absolute */
+
+//printf("~1 ndw = %f %f %f Y = %f\n",ndw[0],ndw[1],ndw[2],wcc.v[1]);
+ if (wcc.v[1] > mxY) {
+ mxY = wcc.v[1];
+ icmCpy3(bw, wcc.v);
+ }
+
+ /* Compute WP scale factor needed to fit mxY */
+ if (mxY > wp[1]) {
+ uswpscale = mxY/wp[1];
+ wpscale *= uswpscale;
+ if (p->verb) {
+ printf("Dev boundary white XYZ %s, scale WP by %f, total WP scale %f\n",
+ icmPdv(3, bw), uswpscale, wpscale);
+ }
+ }
+ }
+
+ /* If the scaled WP would have Y > 1.0, clip it to 1.0 */
+ if (p->flags & XFIT_CLIP_WP) {
+
+ if ((wp[1] * wpscale) > 1.0) {
+ wpscale = 1.0/wp[1]; /* Make wp Y = 1.0 */
+ if (p->verb) {
+ printf("WP Y would ve > 1.0. scale by %f to clip it\n",wpscale);
+ }
+ }
+ }
+
+ /* Apply our total wp scale factor */
+ if (wpscale != 1.0) {
+ icmXYZNumber _wp;
+
+ /* Create inverse scaling matrix for relative rspl data */
+ icmSetUnity3x3(p->cmat);
+ icmScale3x3(p->cmat, p->cmat, 1.0/wpscale);
+
+ /* Inverse scale the rspl */
+ p->clut->re_set_rspl(
+ p->clut, /* this */
+ 0, /* Combination of flags */
+ (void *)p, /* Opaque function context */
+ conv_rspl_out /* Function to set from */
+ );
+
+ /* Scale the WP */
+ icmScale3(wp, wp, wpscale);
+
+ /* return scaled white point to caller */
+ icmAry2Ary(p->wp, wp);
+
+ /* Fix absolute conversions to leave absolute response unchanged. */
+ icmAry2XYZ(_wp, wp); /* Actual white point */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->fromAbs);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, _wp, icmD50, p->toAbs);
+ }
+
+ /* Clip any values in the grid over D50 L to D50 */
+ if ((p->flags & XFIT_OUT_WP_REL_C) == XFIT_OUT_WP_REL_C) {
+
+ /* Compute the rspl D50 value to avoid calc in clip_rspl_out() */
+ if (p->flags & XFIT_OUT_LAB) {
+ p->cmat[0][0] = 100.0;
+ p->cmat[0][1] = 0.0;
+ p->cmat[0][2] = 0.0;
+ } else {
+ icmXYZ2Ary(p->cmat[0], icmD50);
+ }
+ xfit_invoutcurves(p, p->cmat[0], p->cmat[0]);
+
+ if (p->verb)
+ printf("Clipping any cLUT grid points with Y > 1 to D50\n");
+
+ p->clut->re_set_rspl(
+ p->clut, /* this */
+ 0, /* Combination of flags */
+ (void *)p, /* Opaque function context */
+ clip_rspl_out /* Function to set from */
+ );
+ }
+
+#ifdef SPECIAL_FORCE
+ /* Replace the rspl nodes with ones directly computed */
+ /* from the synthetic linear RGB->XYZ model */
+ {
+ double twp[3];
+ icmXYZNumber _wp;
+
+ /* See what current device white maps to */
+ twp[0] = twp[1] = twp[2] = 1.0;
+ domodel(twp, twp);
+
+ icmAry2XYZ(_wp, twp);
+
+ /* Matrix needed to correct to D50 */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, p->cmat);
+
+ p->clut->re_set_rspl(
+ p->clut, /* this */
+ 0, /* Combination of flags */
+ (void *)p, /* Opaque function context */
+ set_rspl_out1 /* Function to set from */
+ );
+ }
+#endif /* SPECIAL_FORCE */
+
+ /* Evaluate the residual error now, with the rspl in place */
+#ifdef DEBUG_PLOT
+ {
+ int ee;
+ double maxe = 0.0;
+ double avee = 0.0;
+
+ /* Allocate in->rout duplicate point set */
+ if (p->rpoints == NULL) {
+ if ((p->rpoints = (cow *)malloc(p->nodp * sizeof(cow))) == NULL)
+ return 1;
+ }
+
+ /* Create a set of 1D rspl setup points that contains */
+ /* the residual error */
+ for (i = 0; i < p->nodp; i++) {
+ double tv[MXDO]; /* Target output value */
+ double mv[MXDO]; /* Model output value */
+ co pp;
+ double ev;
+
+ xfit_abs_to_rel(p, tv, p->ipoints[i].v);
+
+ for (e = 0; e < p->di; e++)
+ pp.p[e] = p->ipoints[i].p[e];
+
+ xfit_inpscurves(p, pp.p, pp.p);
+ p->clut->interp(p->clut, &pp);
+ xfit_outcurves(p, pp.v, pp.v);
+
+ for (f = 0; f < p->fdi; f++)
+ mv[f] = pp.v[f];
+
+ /* Evaluate the residual error suqared */
+ if (p->flags & XFIT_FM_INPUT) {
+ double pp[MXDI];
+ for (e = 0; e < di; e++)
+ pp[e] = p->ipoints[i].p[e];
+ for (f = 0; f < fdi; f++) {
+ double t1 = tv[f] - mv[f]; /* Error in output */
+
+ /* Create input point offset by equivalent delta to output point */
+ /* error, in proportion to the partial derivatives for that output. */
+ for (e = 0; e < di; e++)
+ pp[e] += t1 * p->piv[i].ide[f][e];
+ }
+ ev = p->to_de2(p->cntx2, pp, p->ipoints[i].p);
+ } else {
+ ev = p->to_de2(p->cntx2, mv, tv);
+ }
+//printf("~1 point %d, loc %f %f %f %f\n",i, p->rpoints[i].p[0], p->rpoints[i].p[1], p->rpoints[i].p[2], p->rpoints[i].p[3]);
+//printf(" targ %f %f %f, is %f %f %f\n", tv[0], tv[1], tv[2], mv[0], mv[1], mv[2]);
+
+ p->rpoints[i].v[0] = ev;
+ p->rpoints[i].w = p->ipoints[i].w;
+
+ ev = sqrt(ev);
+ if (ev > maxe)
+ maxe = ev;
+ avee += ev;
+ }
+ printf("Max resid err = %f, avg err = %f\n",maxe, avee/(double)p->nodp);
+
+ /* Evaluate each input axis in turn */
+ for (ee = 0; ee < p->di; ee++) {
+ rspl *resid;
+ double imin[1],imax[1],omin[1],omax[1];
+ int resres[1] = { 1024 };
+
+ /* Create a rspl that gives the residual error squared */
+ /* vs. the axis value */
+ for (i = 0; i < p->nodp; i++)
+ p->rpoints[i].p[0] = p->ipoints[i].p[ee];
+
+ imin[0] = in_min[ee];
+ imax[0] = in_max[ee];
+ omin[0] = 0.0;
+ omax[0] = 0.0;
+
+ if ((resid = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL)
+ return 1;
+
+ resid->fit_rspl_w(resid, RSPLFLAGS, p->rpoints, p->nodp, imin, imax, resres,
+ omin, omax, 2.0, NULL, NULL);
+
+ {
+#define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+
+ printf("Finale residual error vs. input channel %d\n",ee);
+ for (i = 0; i < XRES; i++) {
+ co pp;
+ double x;
+ x = i/(double)(XRES-1);
+ xx[i] = x = x * (imax[0] - imin[0]) + imin[0];
+ pp.p[0] = xx[i];
+ resid->interp(resid, &pp);
+ y1[i] = sqrt(fabs(pp.v[0]));
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+ resid->del(resid);
+ }
+ }
+#endif /* DEBUG_PLOT */
+
+ /* Special test code to figure out what's wrong with position curves */
+#ifdef NEVER
+ {
+ double rgb[3], xyz[3];
+ co pp;
+
+extern int rspldb;
+db = 1;
+rspldb = 1;
+ printf("~1 gres = %d %d %d\n", gres[0], gres[1], gres[2]);
+ for (i = 0; i < 3; i++) {
+
+ if (i == 0) {
+ /* Test point on a grid point */
+ printf("\n~1 ##########################################\n");
+ printf("~1 testing input at first diagonal grid point\n");
+
+ rgb[0] = 1.0/(gres[0]-1.0);
+ rgb[1] = 1.0/(gres[0]-1.0);
+ rgb[2] = 1.0/(gres[0]-1.0);
+
+ printf("~1 target rgb' = %f %f %f\n", rgb[0], rgb[1], rgb[2]);
+ xfit_invinpscurves(p, rgb, rgb);
+
+ } else if (i == 1) {
+ /* Test point half way through a grid point */
+ printf("\n~1 ##########################################\n");
+ printf("\n~1 testing half way through diagonal grid point\n");
+
+ rgb[0] = 0.5/(gres[0]-1.0);
+ rgb[1] = 0.5/(gres[0]-1.0);
+ rgb[2] = 0.5/(gres[0]-1.0);
+
+ printf("~1 target rgb' = %f %f %f\n", rgb[0], rgb[1], rgb[2]);
+ xfit_invinpscurves(p, rgb, rgb);
+
+ } else {
+ printf("\n~1 ##########################################\n");
+ printf("\n~1 testing worst case point\n");
+
+ rgb[0] = 0.039915;
+ rgb[1] = 0.053148;
+ rgb[2] = 0.230610;
+ }
+
+ pp.p[0] = rgb[0];
+ pp.p[1] = rgb[1];
+ pp.p[2] = rgb[2];
+
+ printf("~1 rgb = %f %f %f\n", pp.p[0], pp.p[1], pp.p[2]);
+
+ xfit_inpscurves(p, pp.p, pp.p);
+
+ printf("~1 rgb' = %f %f %f\n", pp.p[0], pp.p[1], pp.p[2]);
+
+ p->clut->interp(p->clut, &pp);
+
+ printf("~1 xyz' = %f %f %f\n", pp.v[0], pp.v[1], pp.v[2]);
+
+ xfit_outcurves(p, pp.v, pp.v);
+
+ printf("~1 xyz = %f %f %f\n", pp.v[0], pp.v[1], pp.v[2]);
+
+ /* Synthetic linear rgb->XYZ model */
+ domodel(xyz, rgb);
+
+ /* Apply abs->rel white point adjustment */
+ icmMulBy3x3(xyz, p->mat, xyz);
+
+ printf("~1 ref = %f %f %f, de = %f\n", xyz[0], xyz[1], xyz[2],icmXYZLabDE(&icmD50,xyz,pp.v));
+ }
+
+db = 0;
+rspldb = 0;
+// exit(0);
+ }
+#endif /* NEVER */
+
+ }
+ return 0;
+}
+
+/* We're done with an xfit */
+static void xfit_del(xfit *p) {
+ if (p->v != NULL)
+ free(p->v);
+ if (p->wv != NULL)
+ free(p->wv);
+ if (p->sa != NULL)
+ free(p->sa);
+ if (p->rpoints != NULL)
+ free(p->rpoints);
+ if (p->piv != NULL)
+ free(p->piv);
+ if (p->uerrv != NULL)
+ free(p->uerrv);
+ free(p);
+}
+
+/* Create a transform fitting object */
+/* return NULL on error */
+xfit *new_xfit(
+) {
+ xfit *p;
+
+ if ((p = (xfit *)calloc(1, sizeof(xfit))) == NULL) {
+ return NULL;
+ }
+
+ /* Set method pointers */
+ p->fit = xfit_fit;
+ p->incurve = xfit_inpscurve;
+ p->invincurve = xfit_invinpscurve;
+ p->outcurve = xfit_outcurve;
+ p->invoutcurve = xfit_invoutcurve;
+ p->del = xfit_del;
+
+ return p;
+}
+
+
+
diff --git a/xicc/xfit.h b/xicc/xfit.h
new file mode 100644
index 0000000..f9f3233
--- /dev/null
+++ b/xicc/xfit.h
@@ -0,0 +1,239 @@
+
+#ifndef XFIT_H
+#define XFIT_H
+
+/*
+ * Clut per channel curve fitting
+ *
+ * Author: Graeme W. Gill
+ * Date: 27/5/2007
+ * Version: 1.00
+ *
+ * Copyright 2000 - 2007 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.
+ *
+ * Based on the rspl.c and xlut.c code.
+ */
+
+#define MXLUORD 60 /* Maximum possible shaper harmonic orders to use */
+
+#define PCSD 3 /* PCS dimensions */
+
+#define MXPARMS (2 * MXDI * MXLUORD + (1 << MXDI) * MXDO + MXDO * MXLUORD)
+
+#define MAX_NTP 11 /* Maximum test points within spans */
+
+/* Optimisation mask legal combinations */
+typedef enum {
+ oc_i = 1, /* Input Shaper curve */
+ oc_p = 2, /* Input Positioning curve */
+ oc_m = 4, /* Temporary matrix */
+ oc_o = 8, /* Output */
+
+ oc_io = oc_i + oc_o,
+ oc_im = oc_i + oc_m,
+ oc_mo = oc_m + oc_o,
+ oc_imo = oc_i + oc_m + oc_o,
+
+ oc_pm = oc_p + oc_m,
+ oc_pmo = oc_p + oc_m + oc_o,
+
+ oc_ip = oc_i + oc_p,
+ oc_ipo = oc_i + oc_p + oc_o
+} optcomb;
+
+/* Flag values */
+#define XFIT_VERB 0x0001 /* Verbose output during fitting */
+
+#define XFIT_FM_INPUT 0x0002 /* Use input space for fit metric (default is output) */
+
+#define XFIT_IN_ZERO 0x0004 /* Adjust input curves 1 & 2 for zero (~~not impd. yet) */
+#define XFIT_OPTGRID_RANGE 0x0008 /* Optimize inner grid around used range (~~not impd. yet) */
+
+#define XFIT_OUT_WP_REL 0x0010 /* Extract the white point and make output relative */
+#define XFIT_OUT_WP_REL_US 0x0030 /* Same as above but scale to avoid clipping above WP */
+#define XFIT_OUT_WP_REL_C 0x0050 /* Same as above but clip any cLUT values over D50 */
+#define XFIT_CLIP_WP 0x0080 /* Clip white point to have Y <= 1.0 (conflict with above) */
+#define XFIT_OUT_LAB 0x0100 /* Output space is LAB else XYZ for reading WP */
+
+#define XFIT_OUT_ZERO 0x0200 /* Adjust output curves 1 & 2 for zero */
+
+#define XFIT_MAKE_CLUT 0x1000 /* Create rspl clut, even if not needed */
+
+
+/* xfit reverse transform information for each test point */
+typedef struct {
+ double ide[MXDO][MXDI]; /* pseudo inverse: rout -> in */
+} xfit_piv;
+
+/* Context for optimising input and output luts */
+struct _xfit {
+ int verb; /* Verbose */
+ int flags; /* Behaviour flags */
+ int di, fdi; /* Dimensionaluty of input and output */
+ optcomb tcomb; /* Target 1D curve elements to fit */
+
+ icxMatrixModel *skm; /* Optional skeleton model (used for input profiles) */
+
+ double *wp; /* Ref. to current white point if XFIT_OUT_WP_REL */
+ double *dw; /* Ref. to device value that should map to D50 if XFIT_OUT_WP_REL */
+ double fromAbs[3][3]; /* From abs to relative (used by caller) */
+ double toAbs[3][3]; /* To abs from relative (used by caller) */
+ int gres[MXDI]; /* clut resolutions being optimised for */
+ rspl *clut; /* final rspl clut */
+
+ void *cntx2; /* Context of callback */
+ double (*to_de2)(void *cntx, double *in1, double *in2);
+ /* callback to convert in or out value to fit metric squared */
+ double (*to_dde2)(void *cntx, double dout[2][MXDIDO], double *in1, double *in2);
+ /* Same, but with partial derivatives */
+
+ int iluord[MXDI]; /* Input Shaper order actualy used (must be <= MXLUORD) */
+ int sm_iluord; /* Smallest Input Shaper order used */
+ int oluord[MXDO]; /* Output Shaper order actualy used (must be <= MXLUORD) */
+ int sluord[MXDI]; /* Sub-grid shaper order */
+ double in_min[MXDI]; /* Input value scaling minimum */
+ double in_max[MXDI]; /* Input value scaling maximum */
+ double out_min[MXDO]; /* Output value scaling minimum */
+ double out_max[MXDO]; /* Output value scaling maximum */
+
+ int shp_off; /* Input parameters offset */
+ int shp_offs[MXDI]; /* Input parameter offsets for each in channel from v[0] */
+ int shp_cnt; /* Input parameters count */
+ int mat_off; /* Matrix parameters offset from v[0] */
+ int mat_offs[MXDO]; /* Matrix parameter offsets for each out channel from v[0] */
+ int mat_cnt; /* Matrix parameters count */
+ int out_off; /* Output parameters offset from v[0] */
+ int out_offs[MXDO]; /* Output parameter offsets for each out channel from v[0] */
+ int out_cnt; /* Output parameters count */
+ int pos_off; /* Position parameters offset */
+ int pos_offs[MXDI]; /* Position parameter offsets for each in channel from v[0] */
+ int pos_cnt; /* Position parameters count */
+ int tot_cnt; /* Total parameter count */
+
+ double *v; /* Holder for parameters */
+ /* Optimisation parameters are layed out: */
+ /* */
+ /* Input pos or shape curves:, di groups of iluord[e] parameters */
+ /* */
+ /* (temp) Matrix: fdi groups of 2 ^ di parameters */
+ /* */
+ /* Output curves:, fdi groups of oluord[f] parameters */
+ /* */
+ /* Shaper curves:, di groups of iluord[e] parameters */
+ /* */
+
+ int nodp; /* Number of data points */
+ cow *ipoints; /* Reference to test points as in->out */
+ cow *rpoints; /* Modified version of ipoints */
+ xfit_piv *piv; /* Point inverse information for XFIT_FM_INPUT */
+ double *uerrv; /* Array holding span width in DE for current opt chan */
+
+ double mat[3][3]; /* XYZ White point aprox relative to accurate relative matrix */
+ double cmat[3][3]; /* Final rspl correction matrix */
+
+ double shp_smooth[MXDI];/* Smoothing factors for each input shape curve, nom = 1.0 */
+ double out_smooth[MXDO];
+
+ /* Optimisation state */
+ optcomb opt_msk; /* Optimisation mask: 3 = i+m, 2 = m, 6 = m+o, 7 = i+m+o */
+ int opt_ssch; /* Single shaper channel mode flag */
+ int opt_off; /* Optimisation parameters offset from v[0] */
+ int opt_cnt; /* Optimisation parameters count */
+ double *wv; /* Parameters being optimised */
+ double *sa; /* Search area */
+ int opt_ch; /* Channel being optimized */
+
+ /* Methods */
+ void (*del)(struct _xfit *p);
+
+ /* Do the fitting. Return nz on error */
+ int (*fit)(
+ struct _xfit *p,
+ int flags, /* Xfit flag values */
+ int di, /* Input dimensions */
+ int fdi, /* Output dimensions */
+ int rsplflags, /* clut rspl creation flags */
+ double *wp, /* if flags & XFIT_OUT_WP_REL, */
+ /* Initial white point, returns final wp */
+ double *dw, /* Device white value to adjust to be D50 */
+ double wpscale, /* If >= 0.0 scale final wp */
+ double *dgw, /* Device space gamut boundary white for XFIT_OUT_WP_REL_US */
+ /* (ie. RGB 1,1,1 CMYK 0,0,0,0, etc) */
+ cow *ipoints, /* Array of data points to fit - referece taken */
+ int nodp, /* Number of data points */
+ icxMatrixModel *skm, /* Optional skeleton model (used for input profiles) */
+ double in_min[MXDI], /* Input value scaling/domain minimum */
+ double in_max[MXDI], /* Input value scaling/domain maximum */
+ int gres[MXDI], /* clut resolutions being optimised for/returned */
+ double out_min[MXDO], /* Output value scaling/range minimum */
+ double out_max[MXDO], /* Output value scaling/range maximum */
+ double smooth, /* clut rspl smoothing factor */
+ double oavgdev[MXDO], /* Average output value deviation */
+ int iord[], /* Order of input positioning/shaper curve for each dimension */
+ int sord[], /* Order of input sub-grid shaper curve (not used) */
+ int oord[], /* Order of output shaper curve for each dimension */
+ double shp_smooth[MXDI],/* Smoothing factors for each curve, nom = 1.0 */
+ double out_smooth[MXDO],
+ optcomb tcomb, /* Flag - target elements to fit. */
+ void *cntx2, /* Context of callbacks */
+ /* Callback to convert two fit values delta E squared */
+ double (*to_de2)(void *cntx, double *in1, double *in2),
+ /* Same as above, with partial derivatives */
+ double (*to_dde2)(void *cntx, double dout[2][MXDIDO], double *in1, double *in2)
+ );
+
+ /* Lookup a value though a combined input positioning and shaper curves */
+ double (*incurve)(struct _xfit *p, double in, int chan);
+
+ /* Inverse Lookup a value though a combined input positioning and shaper curves */
+ double (*invincurve)(struct _xfit *p, double in, int chan);
+
+ /* Lookup a value though an output curve */
+ double (*outcurve)(struct _xfit *p, double in, int chan);
+
+ /* Inverse Lookup a value though an output curve */
+ double (*invoutcurve)(struct _xfit *p, double in, int chan);
+
+}; typedef struct _xfit xfit;
+
+xfit *new_xfit();
+
+#endif /* XFIT_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xicc.c b/xicc/xicc.c
new file mode 100644
index 0000000..9b6d867
--- /dev/null
+++ b/xicc/xicc.c
@@ -0,0 +1,3607 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 2/7/00
+ * Version: 1.00
+ *
+ * Copyright 2000, 2001 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.
+ *
+ * Based on the old iccXfm class.
+ */
+
+/*
+ * This module expands the basic icclib functionality,
+ * providing more functionality in exercising.
+ * The implementation for the three different types
+ * of profile representation, are in their own source files.
+ */
+
+/*
+ * TTBD:
+ * Some of the error handling is crude. Shouldn't use
+ * error(), should return status.
+ *
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "numlib.h"
+#include "counters.h"
+#include "plot.h"
+#include "../h/sort.h"
+#include "xicc.h" /* definitions for this library */
+
+#define USE_CAM /* Use CIECAM02 for clipping and gamut mapping, else use Lab */
+
+#undef DEBUG /* Plot 1d Luts */
+
+#ifdef DEBUG
+#include "plot.h"
+#endif
+
+#define MAX_INVSOLN 4
+
+static void xicc_del(xicc *p);
+icxLuBase * xicc_get_luobj(xicc *p, int flags, icmLookupFunc func, icRenderingIntent intent,
+ icColorSpaceSignature pcsor, icmLookupOrder order,
+ icxViewCond *vc, icxInk *ink);
+static icxLuBase *xicc_set_luobj(xicc *p, icmLookupFunc func, icRenderingIntent intent,
+ icmLookupOrder order, int flags, int no, int nobw, cow *points,
+ icxMatrixModel *skm,
+ double dispLuminance, double wpscale, double smooth, double avgdev,
+ icxViewCond *vc, icxInk *ink, xcal *cal, int quality);
+static void icxLutSpaces(icxLuBase *p, icColorSpaceSignature *ins, int *inn,
+ icColorSpaceSignature *outs, int *outn,
+ icColorSpaceSignature *pcs);
+static void icxLuSpaces(icxLuBase *p, icColorSpaceSignature *ins, int *inn,
+ icColorSpaceSignature *outs, int *outn,
+ icmLuAlgType *alg, icRenderingIntent *intt,
+ icmLookupFunc *fnc, icColorSpaceSignature *pcs);
+static void icxLu_get_native_ranges (icxLuBase *p,
+ double *inmin, double *inmax, double *outmin, double *outmax);
+static void icxLu_get_ranges (icxLuBase *p,
+ double *inmin, double *inmax, double *outmin, double *outmax);
+static void icxLuEfv_wh_bk_points(icxLuBase *p, double *wht, double *blk, double *kblk);
+int xicc_get_viewcond(xicc *p, icxViewCond *vc);
+
+/* The different profile types are in their own source filesm */
+/* and are included to keep their functions private. (static) */
+#include "xmono.c"
+#include "xmatrix.c"
+#include "xlut.c" /* New xfit3 in & out optimising based profiles */
+//#include "xlut1.c" /* Old xfit1 device curve based profiles */
+
+#ifdef NT /* You'd think there might be some standards.... */
+# ifndef __BORLANDC__
+# define stricmp _stricmp
+# endif
+#else
+# define stricmp strcasecmp
+#endif
+/* Utilities */
+
+/* Return a string description of the given enumeration value */
+const char *icx2str(icmEnumType etype, int enumval) {
+
+ if (etype == icmColorSpaceSignature) {
+ if (((icColorSpaceSignature)enumval) == icxSigJabData)
+ return "Jab";
+ else if (((icColorSpaceSignature)enumval) == icxSigJChData)
+ return "JCh";
+ else if (((icColorSpaceSignature)enumval) == icxSigLChData)
+ return "LCh";
+ } else if (etype == icmRenderingIntent) {
+ if (((icRenderingIntent)enumval) == icxAppearance)
+ return "icxAppearance";
+ else if (((icRenderingIntent)enumval) == icxAbsAppearance)
+ return "icxAbsAppearance";
+ else if (((icRenderingIntent)enumval) == icxPerceptualAppearance)
+ return "icxPerceptualAppearance";
+ else if (((icRenderingIntent)enumval) == icxAbsPerceptualAppearance)
+ return "icxAbsPerceptualAppearance";
+ else if (((icRenderingIntent)enumval) == icxSaturationAppearance)
+ return "icxSaturationAppearance";
+ else if (((icRenderingIntent)enumval) == icxAbsSaturationAppearance)
+ return "icxAbsSaturationAppearance";
+ }
+ return icm2str(etype, enumval);
+}
+
+/* Common xicc stuff */
+
+/* Return information about the native lut in/out colorspaces. */
+/* Any pointer may be NULL if value is not to be returned */
+static void
+icxLutSpaces(
+ icxLuBase *p, /* This */
+ icColorSpaceSignature *ins, /* Return input color space */
+ int *inn, /* Return number of input components */
+ icColorSpaceSignature *outs, /* Return output color space */
+ int *outn, /* Return number of output components */
+ icColorSpaceSignature *pcs /* Return PCS color space */
+) {
+ p->plu->lutspaces(p->plu, ins, inn, outs, outn, pcs);
+}
+
+/* Return information about the overall lookup in/out colorspaces, */
+/* including allowance for any PCS override. */
+/* Any pointer may be NULL if value is not to be returned */
+static void
+icxLuSpaces(
+ icxLuBase *p, /* This */
+ icColorSpaceSignature *ins, /* Return input color space */
+ int *inn, /* Return number of input components */
+ icColorSpaceSignature *outs, /* Return output color space */
+ int *outn, /* Return number of output components */
+ icmLuAlgType *alg, /* Return type of lookup algorithm used */
+ icRenderingIntent *intt, /* Return the intent implemented */
+ icmLookupFunc *fnc, /* Return the profile function being implemented */
+ icColorSpaceSignature *pcs /* Return the effective PCS */
+) {
+ icmLookupFunc function;
+ icColorSpaceSignature npcs; /* Native PCS */
+
+ p->plu->spaces(p->plu, NULL, inn, NULL, outn, alg, NULL, &function, &npcs, NULL);
+
+ if (intt != NULL)
+ *intt = p->intent;
+
+ if (fnc != NULL)
+ *fnc = function;
+
+ if (ins != NULL)
+ *ins = p->ins;
+
+ if (outs != NULL)
+ *outs = p->outs;
+
+ if (pcs != NULL)
+ *pcs = p->pcs;
+}
+
+/* Return the native (internaly visible) colorspace value ranges */
+static void
+icxLu_get_native_ranges (
+icxLuBase *p,
+double *inmin, double *inmax, /* Return maximum range of inspace values */
+double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ int i;
+ if (inmin != NULL) {
+ for (i = 0; i < p->inputChan; i++)
+ inmin[i] = p->ninmin[i];
+ }
+ if (inmax != NULL) {
+ for (i = 0; i < p->inputChan; i++)
+ inmax[i] = p->ninmax[i];
+ }
+ if (outmin != NULL) {
+ for (i = 0; i < p->outputChan; i++)
+ outmin[i] = p->noutmin[i];
+ }
+ if (outmax != NULL) {
+ for (i = 0; i < p->outputChan; i++)
+ outmax[i] = p->noutmax[i];
+ }
+}
+
+/* Return the effective (externaly visible) colorspace value ranges */
+static void
+icxLu_get_ranges (
+icxLuBase *p,
+double *inmin, double *inmax, /* Return maximum range of inspace values */
+double *outmin, double *outmax /* Return maximum range of outspace values */
+) {
+ int i;
+ if (inmin != NULL) {
+ for (i = 0; i < p->inputChan; i++)
+ inmin[i] = p->inmin[i];
+ }
+ if (inmax != NULL) {
+ for (i = 0; i < p->inputChan; i++)
+ inmax[i] = p->inmax[i];
+ }
+ if (outmin != NULL) {
+ for (i = 0; i < p->outputChan; i++)
+ outmin[i] = p->outmin[i];
+ }
+ if (outmax != NULL) {
+ for (i = 0; i < p->outputChan; i++)
+ outmax[i] = p->outmax[i];
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Routine to figure out a suitable black point for CMYK */
+
+/* Structure to hold optimisation information */
+typedef struct {
+ icmLuBase *p;
+ int kch; /* K channel, -1 if none */
+ double tlimit, klimit; /* Ink limit values */
+ int inn; /* Number of input channels */
+ icColorSpaceSignature outs; /* Output space */
+ double p1[3]; /* white pivot point in abs Lab */
+ double p2[3]; /* Point on vector towards black in abs Lab */
+ double toll; /* Tollerance of black direction */
+} bpfind;
+
+/* Optimise device values to minimise L, while remaining */
+/* within the ink limit, and staying in line between p1 (white) and p2 (black dir) */
+static double bpfindfunc(void *adata, double pv[]) {
+ bpfind *b = (bpfind *)adata;
+ double rv = 0.0;
+ double Lab[3];
+ double lr, ta, tb, terr; /* L ratio, target a, target b, target error */
+ double ovr = 0.0;
+ int e;
+
+ /* Compute amount outside total limit */
+ if (b->tlimit >= 0.0) {
+ double sum;
+ for (sum = 0.0, e = 0; e < b->inn; e++)
+ sum += pv[e];
+ if (sum > b->tlimit) {
+ ovr = sum - b->tlimit;
+#ifdef DEBUG
+ printf("~1 total ink ovr = %f\n",ovr);
+#endif
+ }
+ }
+
+ /* Compute amount outside black limit */
+ if (b->klimit >= 0.0 && b->kch >= 0) {
+ double kval = pv[b->kch] - b->klimit;
+ if (kval > ovr) {
+ ovr = kval;
+#ifdef DEBUG
+ printf("~1 black ink ovr = %f\n",ovr);
+#endif
+ }
+ }
+ /* Compute amount outside device value limits 0.0 - 1.0 */
+ {
+ double dval;
+ for (dval = -1.0, e = 0; e < b->inn; e++) {
+ if (pv[e] < 0.0) {
+ if (-pv[e] > dval)
+ dval = -pv[e];
+ } else if (pv[e] > 1.0) {
+ if ((pv[e] - 1.0) > dval)
+ dval = pv[e] - 1.0;
+ }
+ }
+ if (dval > ovr)
+ ovr = dval;
+ }
+
+ /* Compute the Lab value: */
+ b->p->lookup(b->p, Lab, pv);
+ if (b->outs == icSigXYZData)
+ icmXYZ2Lab(&icmD50, Lab, Lab);
+
+#ifdef DEBUG
+ printf("~1 p1 = %f %f %f, p2 = %f %f %f\n",b->p1[0],b->p1[1],b->p1[2],b->p2[0],b->p2[1],b->p2[2]);
+ printf("~1 device value %f %f %f %f, Lab = %f %f %f\n",pv[0],pv[1],pv[2],pv[3],Lab[0],Lab[1],Lab[2]);
+#endif
+
+ /* Primary aim is to minimise L value */
+ rv = Lab[0];
+
+ /* See how out of line from p1 to p2 we are */
+ lr = (Lab[0] - b->p1[0])/(b->p2[0] - b->p1[0]); /* Distance towards p2 from p1 */
+ ta = lr * (b->p2[1] - b->p1[1]) + b->p1[1]; /* Target a value */
+ tb = lr * (b->p2[2] - b->p1[2]) + b->p1[2]; /* Target b value */
+
+ terr = (ta - Lab[1]) * (ta - Lab[1])
+ + (tb - Lab[2]) * (tb - Lab[2]);
+
+ if (terr < b->toll) /* Tollerance error doesn't count until it's over tollerance */
+ terr = 0.0;
+
+#ifdef DEBUG
+ printf("~1 target error %f\n",terr);
+#endif
+ rv += XICC_BLACK_FIND_ABERR_WEIGHT * terr; /* Make ab match more important than min. L */
+
+#ifdef DEBUG
+ printf("~1 out of range error %f\n",ovr);
+#endif
+ rv += 200 * ovr;
+
+#ifdef DEBUG
+ printf("~1 black find tc ret %f\n",rv);
+#endif
+ return rv;
+}
+
+/* Try and compute a real black point in XYZ given an iccLu, */
+/* and also return the K only black or the normal black if the device doesn't have K */
+/* black[] will be unchanged if black cannot be computed. */
+/* Note that the black point will be in the space of the Lu */
+/* converted to XYZ, so will have the Lu's intent etc. */
+/* (Note that this is duplicated in xlut.c set_icxLuLut() !!!) */
+static void icxLu_comp_bk_point(
+icxLuBase *x,
+int gblk, /* If nz, compute black if possible. */
+double *white, /* XYZ Input, used for computing black */
+double *black, /* XYZ Input & Output. Set if gblk NZ and can be computed */
+double *kblack /* XYZ Output. Looked up if possible or set to black[] otherwise */
+) {
+ icmLuBase *p = x->plu;
+ icmLuBase *op = p; /* Original icmLu, in case we replace p */
+ icc *icco = p->icp;
+ icmHeader *h = icco->header;
+ icColorSpaceSignature ins, outs;
+ int inn, outn;
+ icmLuAlgType alg;
+ icRenderingIntent intt;
+ icmLookupFunc fnc;
+ icmLookupOrder ord;
+ int kch = -1;
+ double dblack[MAX_CHAN]; /* device black value */
+ int e;
+
+#ifdef DEBUG
+ printf("~1 icxLu_comp_bk_point() called, gblk %d, white = %s, black = %s\n",gblk,icmPdv(3, white),icmPdv(3,black));
+#endif
+ /* Default return incoming black as K only black */
+ kblack[0] = black[0];
+ kblack[1] = black[1];
+ kblack[2] = black[2];
+
+ /* Get the effective characteristics of the Lu */
+ p->spaces(p, &ins, &inn, &outs, &outn, &alg, &intt, &fnc, NULL, &ord);
+
+ if (fnc == icmBwd) { /* Hmm. We've got PCS to device, and we want device to PCS. */
+
+ /* Strictly speaking this is a dubious approach, since for a cLut profile */
+ /* the B2A table could make the effective white and black points */
+ /* anything it likes, and they don't have to match what the corresponding */
+ /* A2B table does. In our usage it's probably OK, since we tend */
+ /* to use colorimetric B2A */
+#ifdef DEBUG
+ printf("~1 getting icmFwd\n");
+#endif
+ if ((p = icco->get_luobj(icco, icmFwd, intt, ins, ord)) == NULL)
+ error("icxLu_comp_bk_point: assert: getting Fwd Lookup failed!");
+
+ p->spaces(p, &ins, &inn, &outs, &outn, &alg, &intt, &fnc, NULL, &ord);
+ }
+
+ if (outs != icSigXYZData && outs != icSigLabData) {
+ error("icxLu_comp_bk_point: assert: icc Lu output is not XYZ or Lab!, outs = 0x%x, ");
+ }
+
+#ifdef DEBUG
+ printf("~1 icxLu_comp_bk_point called for inn = %d, ins = %s\n", inn, icx2str(icmColorSpaceSignature,ins));
+#endif
+
+ switch (ins) {
+
+ case icSigXYZData:
+ case icSigLabData:
+ case icSigLuvData:
+ case icSigYxyData:
+#ifdef DEBUG
+ printf("~1 Assuming CIE colorspace black is 0.0\n");
+#endif
+ if (gblk) {
+ for (e = 0; e < inn; e++)
+ black[0] = 0.0;
+ }
+ kblack[0] = black[0];
+ kblack[1] = black[1];
+ kblack[2] = black[2];
+ return;
+
+ case icSigRgbData:
+#ifdef DEBUG
+ printf("~1 RGB:\n");
+#endif
+ for (e = 0; e < inn; e++)
+ dblack[e] = 0.0;
+ break;
+
+ case icSigGrayData: { /* Could be additive or subtractive */
+ double dval[1];
+ double minv[3], maxv[3];
+#ifdef DEBUG
+ printf("~1 Gray:\n");
+#endif
+ /* Check out 0 and 100% colorant */
+ dval[0] = 0.0;
+ p->lookup(p, minv, dval);
+ if (outs == icSigXYZData)
+ icmXYZ2Lab(&icmD50, minv, minv);
+ dval[0] = 1.0;
+ p->lookup(p, maxv, dval);
+ if (outs == icSigXYZData)
+ icmXYZ2Lab(&icmD50, maxv, maxv);
+
+ if (minv[0] < maxv[0])
+ dblack[0] = 0.0;
+ else
+ dblack[0] = 1.0;
+ }
+ break;
+
+ case icSigCmyData:
+ for (e = 0; e < inn; e++)
+ dblack[e] = 1.0;
+ break;
+
+ case icSigCmykData:
+#ifdef DEBUG
+ printf("~1 CMYK:\n");
+#endif
+ kch = 3;
+ dblack[0] = 0.0;
+ dblack[1] = 0.0;
+ dblack[2] = 0.0;
+ dblack[3] = 1.0;
+ if (alg == icmLutType) {
+ icxLuLut *pp = (icxLuLut *)x;
+
+ if (pp->ink.tlimit >= 0.0)
+ dblack[kch] = pp->ink.tlimit;
+ };
+ break;
+
+ /* Use a heursistic. */
+ /* This duplicates code in icxGetLimits() :-( */
+ /* Colorant guessing should go in icclib ? */
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSig6colorData:
+ case icSig7colorData:
+ case icSig8colorData:
+ case icSig9colorData:
+ case icSig10colorData:
+ case icSig11colorData:
+ case icSig12colorData:
+ case icSig13colorData:
+ case icSig14colorData:
+ case icSig15colorData:
+ case icSigMch5Data:
+ case icSigMch6Data:
+ case icSigMch7Data:
+ case icSigMch8Data: {
+ double dval[MAX_CHAN];
+ double ncval[3];
+ double cvals[MAX_CHAN][3];
+ int nlighter, ndarker;
+
+ /* Decide if the colorspace is additive or subtractive */
+#ifdef DEBUG
+ printf("~1 N channel:\n");
+#endif
+
+ /* First the no colorant value */
+ for (e = 0; e < inn; e++)
+ dval[e] = 0.0;
+ p->lookup(p, ncval, dval);
+ if (outs == icSigXYZData)
+ icmXYZ2Lab(&icmD50, ncval, ncval);
+
+ /* Then all the colorants */
+ nlighter = ndarker = 0;
+ for (e = 0; e < inn; e++) {
+ dval[e] = 1.0;
+ p->lookup(p, cvals[e], dval);
+ if (outs == icSigXYZData)
+ icmXYZ2Lab(&icmD50, cvals[e], cvals[e]);
+ dval[e] = 0.0;
+ if (fabs(cvals[e][0] - ncval[0]) > 5.0) {
+ if (cvals[e][0] > ncval[0])
+ nlighter++;
+ else
+ ndarker++;
+ }
+ }
+ if (ndarker == 0 && nlighter > 0) { /* Assume additive */
+ for (e = 0; e < inn; e++)
+ dblack[e] = 0.0;
+#ifdef DEBUG
+ printf("~1 N channel is additive:\n");
+#endif
+
+ } else if (ndarker > 0 && nlighter == 0) { /* Assume subtractive. */
+ double pbk[3] = { 0.0,0.0,0.0 }; /* Perfect black */
+ double smd = 1e10; /* Smallest distance */
+
+#ifdef DEBUG
+ printf("~1 N channel is subtractive:\n");
+#endif
+ /* See if we can guess the black channel */
+ for (e = 0; e < inn; e++) {
+ double tt;
+ tt = icmNorm33sq(pbk, cvals[e]);
+ if (tt < smd) {
+ smd = tt;
+ kch = e;
+ }
+ }
+ /* See if the black seems sane */
+ if (cvals[kch][0] > 40.0
+ || fabs(cvals[kch][1]) > 10.0
+ || fabs(cvals[kch][2]) > 10.0) {
+ if (p != op)
+ p->del(p);
+#ifdef DEBUG
+ printf("~1 black doesn't look sanem so assume nothing\n");
+#endif
+ return; /* Assume nothing */
+ }
+
+ /* Chosen kch as black */
+ for (e = 0; e < inn; e++)
+ dblack[e] = 0.0;
+ dblack[kch] = 1.0;
+ if (alg == icmLutType) {
+ icxLuLut *pp = (icxLuLut *)x;
+
+ if (pp->ink.tlimit >= 0.0)
+ dblack[kch] = pp->ink.tlimit;
+ };
+#ifdef DEBUG
+ printf("~1 N channel K = chan %d\n",kch);
+#endif
+ } else {
+ if (p != op)
+ p->del(p);
+#ifdef DEBUG
+ printf("~1 can't figure if additive or subtractive, so assume nothing\n");
+#endif
+ return; /* Assume nothing */
+ }
+ }
+ break;
+
+ default:
+#ifdef DEBUG
+ printf("~1 unhandled colorspace, so assume nothing\n");
+#endif
+ if (p != op)
+ p->del(p);
+ return; /* Don't do anything */
+ }
+
+ /* Lookup the K only value */
+ if (kch >= 0) {
+ p->lookup(p, kblack, dblack);
+
+ /* We always return XYZ */
+ if (outs == icSigLabData)
+ icmLab2XYZ(&icmD50, kblack, kblack);
+ }
+
+ if (gblk == 0) { /* That's all we have to do */
+#ifdef DEBUG
+ printf("~1 gblk == 0, so only return kblack\n");
+#endif
+ if (p != op)
+ p->del(p);
+ return;
+ }
+
+ /* Lookup the device black or K only value as a default */
+ p->lookup(p, black, dblack); /* May be XYZ or Lab */
+#ifdef DEBUG
+ printf("~1 Got default lu black %f %f %f, kch = %d\n", black[0],black[1],black[2],kch);
+#endif
+
+ /* !!! Hmm. For CMY and RGB we are simply using the device */
+ /* combination values as the black point. In reality we might */
+ /* want to have the option of using a neutral black point, */
+ /* just like CMYK ?? */
+
+ if (kch >= 0) { /* The space is subtractive with a K channel. */
+ /* If XICC_NEUTRAL_CMYK_BLACK then locate the darkest */
+ /* CMYK within limits with the same chromaticity as the white point, */
+ /* otherwise locate the device value within the ink limits that is */
+ /* in the direction of the K channel */
+ bpfind bfs; /* Callback context */
+ double sr[MXDO]; /* search radius */
+ double tt[MXDO]; /* Temporary */
+ double rs0[MXDO], rs1[MXDO]; /* Random start candidates */
+ int trial;
+ double brv;
+
+ /* Setup callback function context */
+ bfs.p = p;
+ bfs.inn = inn;
+ bfs.outs = outs;
+
+ bfs.kch = kch;
+ bfs.tlimit = -1.0;
+ bfs.klimit = -1.0;
+ bfs.toll = XICC_BLACK_POINT_TOLL;
+
+ if (alg == icmLutType) {
+ icxLuLut *pp = (icxLuLut *)x;
+
+ pp->kch = kch;
+ bfs.tlimit = pp->ink.tlimit;
+ bfs.klimit = pp->ink.klimit;
+#ifdef DEBUG
+ printf("~1 tlimit = %f, klimit = %f\n",bfs.tlimit,bfs.klimit);
+#endif
+ };
+
+#ifdef XICC_NEUTRAL_CMYK_BLACK
+#ifdef DEBUG
+ printf("~1 Searching for neutral black\n");
+#endif
+ /* white has been given to us in XYZ */
+ icmXYZ2Lab(&icmD50, bfs.p1, white); /* pivot Lab */
+ icmCpy3(bfs.p2, white); /* temp white XYZ */
+ icmScale3(bfs.p2, bfs.p2, 0.02); /* Scale white XYZ towards 0,0,0 */
+ icmXYZ2Lab(&icmD50, bfs.p2, bfs.p2); /* Convert black direction to Lab */
+
+#else /* Use K directin black */
+#ifdef DEBUG
+ printf("~1 Searching for K direction black\n");
+#endif
+ icmXYZ2Lab(&icmD50, bfs.p1, white); /* Pivot */
+
+ /* Now figure abs Lab value of K only, as the direction */
+ /* to use for the rich black. */
+ for (e = 0; e < inn; e++)
+ dblack[e] = 0.0;
+ if (bfs.klimit < 0.0)
+ dblack[kch] = 1.0;
+ else
+ dblack[kch] = bfs.klimit; /* K value */
+
+ p->lookup(p, black, dblack);
+
+ if (outs == icSigXYZData) {
+ icmXYZ2Lab(&icmD50, bfs.p2, black); /* K direction */
+ } else {
+ icmAry2Ary(bfs.p2, black);
+ }
+#endif
+
+#ifdef DEBUG
+ printf("~1 Lab pivot %f %f %f, Lab K direction %f %f %f\n",bfs.p1[0],bfs.p1[1],bfs.p1[2],bfs.p2[0],bfs.p2[1],bfs.p2[2]);
+#endif
+ /* Start with the K only as the current best value */
+ brv = bpfindfunc((void *)&bfs, dblack);
+#ifdef DEBUG
+ printf("~1 initial brv for K only = %f\n",brv);
+#endif
+
+ /* Set the random start 0 location as 000K */
+ /* and the random start 1 location as CMY0 */
+ {
+ double tt;
+
+ for (e = 0; e < inn; e++)
+ dblack[e] = rs0[e] = 0.0;
+ if (bfs.klimit < 0.0)
+ dblack[kch] = rs0[kch] = 1.0;
+ else
+ dblack[kch] = rs0[kch] = bfs.klimit; /* K value */
+
+ if (bfs.tlimit < 0.0)
+ tt = 1.0;
+ else
+ tt = bfs.tlimit/(inn - 1.0);
+ for (e = 0; e < inn; e++)
+ rs1[e] = tt;
+ rs1[kch] = 0.0; /* K value */
+ }
+
+ /* Find the device black point using optimization */
+ /* Do several trials to avoid local minima. */
+ rand32(0x12345678); /* Make trial values deterministic */
+ for (trial = 0; trial < 200; trial++) {
+ double rv; /* Temporary */
+
+ /* Start first trial at 000K */
+ if (trial == 0) {
+ for (e = 0; e < inn; e++) {
+ tt[e] = rs0[e];
+ sr[e] = 0.1;
+ }
+
+ } else {
+ /* Base is random between 000K and CMY0: */
+ if (trial < 100) {
+ rv = d_rand(0.0, 1.0);
+ for (e = 0; e < inn; e++) {
+ tt[e] = rv * rs0[e] + (1.0 - rv) * rs1[e];
+ sr[e] = 0.1;
+ }
+ /* Base on current best */
+ } else {
+ for (e = 0; e < inn; e++) {
+ tt[e] = dblack[e];
+ sr[e] = 0.1;
+ }
+ }
+
+ /* Then add random start offset */
+ for (rv = 0.0, e = 0; e < inn; e++) {
+ tt[e] += d_rand(-0.5, 0.5);
+ if (tt[e] < 0.0)
+ tt[e] = 0.0;
+ else if (tt[e] > 1.0)
+ tt[e] = 1.0;
+ }
+ }
+
+ /* Clip black */
+ if (bfs.klimit >= 0.0 && tt[kch] > bfs.klimit)
+ tt[kch] = bfs.klimit;
+
+ /* Compute amount outside total limit */
+ if (bfs.tlimit >= 0.0) {
+ for (rv = 0.0, e = 0; e < inn; e++)
+ rv += tt[e];
+
+ if (rv > bfs.tlimit) {
+ rv /= (double)inn;
+ for (e = 0; e < inn; e++)
+ tt[e] -= rv;
+ }
+ }
+
+ if (powell(&rv, inn, tt, sr, 0.000001, 1000, bpfindfunc,
+ (void *)&bfs, NULL, NULL) == 0) {
+#ifdef DEBUG
+ printf("~1 trial %d, rv %f bp %f %f %f %f\n",trial,rv,tt[0],tt[1],tt[2],tt[3]);
+#endif
+ if (rv < brv) {
+#ifdef DEBUG
+ printf("~1 new best\n");
+#endif
+ brv = rv;
+ for (e = 0; e < inn; e++)
+ dblack[e] = tt[e];
+ }
+ }
+ }
+ if (brv > 1000.0)
+ error("icxLu_comp_bk_point: Black point powell failed");
+
+ for (e = 0; e < inn; e++) { /* Make sure device values are in range */
+ if (dblack[e] < 0.0)
+ dblack[e] = 0.0;
+ else if (dblack[e] > 1.0)
+ dblack[e] = 1.0;
+ }
+ /* Now have device black in dblack[] */
+#ifdef DEBUG
+ printf("~1 got device black %f %f %f %f\n",dblack[0], dblack[1], dblack[2], dblack[3]);
+#endif
+
+ p->lookup(p, black, dblack); /* Convert to PCS */
+ }
+
+ if (p != op)
+ p->del(p);
+
+ /* We always return XYZ */
+ if (outs == icSigLabData)
+ icmLab2XYZ(&icmD50, black, black);
+
+#ifdef DEBUG
+ printf("~1 returning %f %f %f\n", black[0], black[1], black[2]);
+#endif
+
+ return;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return the media white and black points */
+/* in the xlu effective PCS colorspace. Pointers may be NULL. */
+/* (ie. these will be relative values for relative intent etc.) */
+static void icxLuEfv_wh_bk_points(
+icxLuBase *p,
+double *wht,
+double *blk,
+double *kblk /* K only black */
+) {
+ double white[3], black[3], kblack[3];
+
+ /* Get the Lu PCS converted to XYZ icc black and white points in XYZ */
+ if (p->plu->lu_wh_bk_points(p->plu, white, black)) {
+ /* Black point is assumed. We should determine one instead. */
+ /* Lookup K only black too */
+ icxLu_comp_bk_point(p, 1, white, black, kblack);
+
+ } else {
+ /* Lookup a possible K only black */
+ icxLu_comp_bk_point(p, 0, white, black, kblack);
+ }
+
+//printf("~1 white %f %f %f, black %f %f %f, kblack %f %f %f\n",white[0],white[1],white[2],black[0],black[1],black[2],kblack[0],kblack[1],kblack[2]);
+ /* Convert to possibl xicc override PCS */
+ switch (p->pcs) {
+ case icSigXYZData:
+ break; /* Don't have to do anyting */
+ case icSigLabData:
+ icmXYZ2Lab(&icmD50, white, white); /* Convert from XYZ to Lab */
+ icmXYZ2Lab(&icmD50, black, black);
+ icmXYZ2Lab(&icmD50, kblack, kblack);
+ break;
+ case icxSigJabData:
+ p->cam->XYZ_to_cam(p->cam, white, white); /* Convert from XYZ to Jab */
+ p->cam->XYZ_to_cam(p->cam, black, black);
+ p->cam->XYZ_to_cam(p->cam, kblack, kblack);
+ break;
+ default:
+ break;
+ }
+
+//printf("~1 icxLuEfv_wh_bk_points: pcsor %s White %f %f %f, Black %f %f %f\n", icx2str(icmColorSpaceSignature,p->pcs), white[0], white[1], white[2], black[0], black[1], black[2]);
+ if (wht != NULL) {
+ wht[0] = white[0];
+ wht[1] = white[1];
+ wht[2] = white[2];
+ }
+
+ if (blk != NULL) {
+ blk[0] = black[0];
+ blk[1] = black[1];
+ blk[2] = black[2];
+ }
+
+ if (kblk != NULL) {
+ kblk[0] = kblack[0];
+ kblk[1] = kblack[1];
+ kblk[2] = kblack[2];
+ }
+}
+
+/* Create an instance of an xicc object */
+xicc *new_xicc(
+icc *picc /* icc we are expanding */
+) {
+ xicc *p;
+ if ((p = (xicc *) calloc(1,sizeof(xicc))) == NULL)
+ return NULL;
+ p->pp = picc;
+ p->del = xicc_del;
+ p->get_luobj = xicc_get_luobj;
+ p->set_luobj = xicc_set_luobj;
+ p->get_viewcond = xicc_get_viewcond;
+
+ /* Create an xcal if there is the right tag in the profile */
+ p->cal = xiccReadCalTag(p->pp);
+ p->nodel_cal = 0; /* We created it, we will delete it */
+
+ return p;
+}
+
+/* Do away with the xicc (but not the icc!) */
+static void xicc_del(
+xicc *p
+) {
+ if (p->cal != NULL && p->nodel_cal == 0)
+ p->cal->del(p->cal);
+ free (p);
+}
+
+
+/* Return an expanded lookup object, initialised */
+/* from the icc. */
+/* Return NULL on error, check errc+err for reason. */
+/* Set the pcsor & intent to consistent and values if */
+/* Jab and/or icxAppearance has been requested. */
+/* Create the underlying icm lookup object that is used */
+/* to create and implement the icx one. The icm will be used */
+/* to translate from native to effective PCS, unless the */
+/* effective PCS is Jab, in which case the icm will be set to */
+/* have an effective PCS of XYZ. Since native<->effecive PCS conversion */
+/* is done at the to/from_abs() stage, none of this affects the individual */
+/* conversion steps, which will all talk the native PCS (unless merged). */
+icxLuBase *xicc_get_luobj(
+xicc *p, /* this */
+int flags, /* clip, merge flags */
+icmLookupFunc func, /* Functionality */
+icRenderingIntent intent, /* Intent */
+icColorSpaceSignature pcsor,/* PCS override (0 = def) */
+icmLookupOrder order, /* Search Order */
+icxViewCond *vc, /* Viewing Condition (may be NULL if pcsor is not CIECAM) */
+icxInk *ink /* inking details (NULL for default) */
+) {
+ icmLuBase *plu;
+ icxLuBase *xplu;
+ icmLuAlgType alg;
+ icRenderingIntent n_intent = intent; /* Native Intent to request */
+ icColorSpaceSignature n_pcs = icmSigDefaultData; /* Native PCS to request */
+
+//printf("~1 xicc_get_luobj got intent %s and pcsor %s\n",icx2str(icmRenderingIntent,intent),icx2str(icmColorSpaceSignature,pcsor));
+
+ /* Ensure that appropriate PCS is slected for an appearance intent */
+ if (intent == icxAppearance
+ || intent == icxAbsAppearance
+ || intent == icxPerceptualAppearance
+ || intent == icxAbsPerceptualAppearance
+ || intent == icxSaturationAppearance
+ || intent == icxAbsSaturationAppearance) {
+ pcsor = icxSigJabData;
+
+ /* Translate non-Jab intents to the equivalent appearance "intent" if pcsor == Jab. */
+ /* This is how we get these when the UI's don't list all the apperances intents, */
+ /* we select the analogous non-apperance intent with pcsor = Jab. */
+ /* Note that Abs/non-abs selects between Apperance and AbsAppearance. */
+ } else if (pcsor == icxSigJabData) {
+ if (intent == icRelativeColorimetric)
+ intent = icxAppearance;
+ else if (intent == icAbsoluteColorimetric)
+ intent = icxAbsAppearance;
+ else if (intent == icPerceptual)
+ intent = icxPerceptualAppearance;
+ else if (intent == icmAbsolutePerceptual)
+ intent = icxAbsPerceptualAppearance;
+ else if (intent == icSaturation)
+ intent = icxSaturationAppearance;
+ else if (intent == icmAbsoluteSaturation)
+ intent = icxAbsSaturationAppearance;
+ else
+ intent = icxAppearance;
+ }
+
+ /* Translate intent asked for into intent needed in icclib */
+ if (intent == icxAppearance
+ || intent == icxAbsAppearance)
+ n_intent = icAbsoluteColorimetric;
+ else if (intent == icxPerceptualAppearance
+ || intent == icxAbsPerceptualAppearance)
+ n_intent = icmAbsolutePerceptual;
+ else if (intent == icxSaturationAppearance
+ || intent == icxAbsSaturationAppearance)
+ n_intent = icmAbsoluteSaturation;
+
+ if (pcsor != icmSigDefaultData)
+ n_pcs = pcsor; /* There is an icclib override */
+
+ if (pcsor == icxSigJabData) /* xicc override */
+ n_pcs = icSigXYZData; /* Translate to XYZ */
+
+//printf("~1 xicc_get_luobj processed intent %s and pcsor %s\n",icx2str(icmRenderingIntent,intent),icx2str(icmColorSpaceSignature,pcsor));
+//printf("~1 xicc_get_luobj icclib intent %s and pcsor %s\n",icx2str(icmRenderingIntent,n_intent),icx2str(icmColorSpaceSignature,n_pcs));
+ /* Get icclib lookup object */
+ if ((plu = p->pp->get_luobj(p->pp, func, n_intent, n_pcs, order)) == NULL) {
+ p->errc = p->pp->errc; /* Copy error */
+ strcpy(p->err, p->pp->err);
+ return NULL;
+ }
+
+ /* Figure out what the algorithm is */
+ plu->spaces(plu, NULL, NULL, NULL, NULL, &alg, NULL, NULL, &n_pcs, NULL);
+
+ /* make sure its "Abs CAM" */
+ if (vc!= NULL
+ && (intent == icxAbsAppearance
+ || intent == icxAbsPerceptualAppearance
+ || intent == icxAbsSaturationAppearance)) { /* make sure its "Abs CAM" */
+ /* Set white point and flare color to D50 */
+ /* (Hmm. This doesn't match what happens within collink with absolute intent!!) */
+ vc->Wxyz[0] = icmD50.X/icmD50.Y;
+ vc->Wxyz[1] = icmD50.Y/icmD50.Y; // Normalise white reference to Y = 1 ?
+ vc->Wxyz[2] = icmD50.Z/icmD50.Y;
+
+ vc->Fxyz[0] = icmD50.X;
+ vc->Fxyz[1] = icmD50.Y;
+ vc->Fxyz[2] = icmD50.Z;
+ }
+
+ /* Call xiccLu wrapper creation */
+ switch (alg) {
+ case icmMonoFwdType:
+ xplu = new_icxLuMono(p, flags, plu, func, intent, pcsor, vc, 0);
+ break;
+ case icmMonoBwdType:
+ xplu = new_icxLuMono(p, flags, plu, func, intent, pcsor, vc, 1);
+ break;
+ case icmMatrixFwdType:
+ xplu = new_icxLuMatrix(p, flags, plu, func, intent, pcsor, vc, 0);
+ break;
+ case icmMatrixBwdType:
+ xplu = new_icxLuMatrix(p, flags, plu, func, intent, pcsor, vc, 1);
+ break;
+ case icmLutType:
+ xplu = new_icxLuLut(p, flags, plu, func, intent, pcsor, vc, ink);
+ break;
+ default:
+ xplu = NULL;
+ break;
+ }
+
+ return xplu;
+}
+
+
+/* Return an expanded lookup object, initialised */
+/* from the icc, and then overwritten by a conversion */
+/* created from the supplied scattered data points. */
+/* The Lut is assumed to be a device -> native PCS profile. */
+/* If the SET_WHITE and/or SET_BLACK flags are set, */
+/* discover the white/black point, set it in the icc, */
+/* and make the Lut relative to them. */
+/* Return NULL on error, check errc+err for reason */
+static icxLuBase *xicc_set_luobj(
+xicc *p, /* this */
+icmLookupFunc func, /* Functionality */
+icRenderingIntent intent, /* Intent */
+icmLookupOrder order, /* Search Order */
+int flags, /* white/black point, verbose flags etc. */
+int no, /* Number of points */
+int nobw, /* Number of points to look for white & black patches in */
+cow *points, /* Array of input points in target PCS space */
+icxMatrixModel *skm, /* Optional skeleton model (used for input profiles) */
+double dispLuminance, /* > 0.0 if display luminance value and is known */
+double wpscale, /* > 0.0 if input white point is to be scaled */
+double smooth, /* RSPL smoothing factor, -ve if raw */
+double avgdev, /* reading Average Deviation as a proportion of the input range */
+icxViewCond *vc, /* Viewing Condition (NULL if not using CAM) */
+icxInk *ink, /* inking details (NULL for default) */
+xcal *cal, /* Optional cal, will override any existing (not deleted with xicc)*/
+int quality /* Quality metric, 0..3 */
+) {
+ icmLuBase *plu;
+ icxLuBase *xplu = NULL;
+ icmLuAlgType alg;
+
+ if (cal != NULL) {
+ if (p->cal != NULL && p->nodel_cal == 0)
+ p->cal->del(p->cal);
+ p->cal = cal;
+ p->nodel_cal = 1; /* We were given it, so don't delete it */
+ }
+
+ if (func != icmFwd) {
+ p->errc = 1;
+ sprintf(p->err,"Can only create Device->PCS profiles from scattered data.");
+ xplu = NULL;
+ return xplu;
+ }
+
+ /* Get icclib lookup object */
+ if ((plu = p->pp->get_luobj(p->pp, func, intent, 0, order)) == NULL) {
+ p->errc = p->pp->errc; /* Copy error */
+ strcpy(p->err, p->pp->err);
+ return NULL;
+ }
+
+ /* Figure out what the algorithm is */
+ plu->spaces(plu, NULL, NULL, NULL, NULL, &alg, NULL, NULL, NULL, NULL);
+
+ /* Call xiccLu wrapper creation */
+ switch (alg) {
+ case icmMonoFwdType:
+ p->errc = 1;
+ sprintf(p->err,"Setting Monochrome Fwd profile from scattered data not supported.");
+ plu->del(plu);
+ xplu = NULL; /* Not supported yet */
+ break;
+
+ case icmMatrixFwdType:
+ if (smooth < 0.0)
+ smooth = -smooth;
+ xplu = set_icxLuMatrix(p, plu, flags, no, nobw, points, skm, dispLuminance, wpscale, quality, smooth);
+ break;
+
+ case icmLutType:
+ /* ~~~ Should add check that it is a fwd profile ~~~ */
+ xplu = set_icxLuLut(p, plu, func, intent, flags, no, nobw, points, skm, dispLuminance, wpscale, smooth, avgdev, vc, ink, quality);
+ break;
+
+ default:
+ break;
+ }
+
+ return xplu;
+}
+
+/* ------------------------------------------------------ */
+/* Viewing Condition Parameter stuff */
+
+#ifdef NEVER /* Not currently used */
+
+/* Guess viewing parameters from the technology signature */
+static void guess_from_techsig(
+icTechnologySignature tsig,
+double *Ybp
+) {
+double Yb = -1.0;
+
+ switch (tsig) {
+ /* These are all inputing either a representation of */
+ /* a natural scene captured on another medium, or are assuming */
+ /* that the medium is the original. A _good_ system would */
+ /* let the user indicate which is the case. */
+ case icSigReflectiveScanner:
+ case icSigFilmScanner:
+ Yb = 0.2;
+ break;
+
+ /* Direct scene to value devices. */
+ case icSigDigitalCamera:
+ case icSigVideoCamera:
+ Yb = 0.2;
+ break;
+
+ /* Emmisive displays. */
+ /* We could try tweaking the white point on the assumption */
+ /* that the viewer will be adapted to a combination of both */
+ /* the CRT white point, and the ambient light. */
+ case icSigVideoMonitor:
+ case icSigCRTDisplay:
+ case icSigPMDisplay:
+ case icSigAMDisplay:
+ Yb = 0.2;
+ break;
+
+ /* Photo CD has its own viewing definitions */
+ /* (It represents original scene colors) */
+ case icSigPhotoCD:
+ Yb = 0.2;
+ break;
+
+ /* Projection devices, either direct, or */
+ /* via another intermediate medium. */
+ case icSigProjectionTelevision:
+ Yb = 0.1; /* Assume darkened room, little background */
+ break;
+ case icSigFilmWriter:
+ Yb = 0.0; /* Assume a dark room - no background */
+ break;
+
+ /* Printed media devices. */
+ case icSigInkJetPrinter:
+ case icSigThermalWaxPrinter:
+ case icSigElectrophotographicPrinter:
+ case icSigElectrostaticPrinter:
+ case icSigDyeSublimationPrinter:
+ case icSigPhotographicPaperPrinter:
+ case icSigPhotoImageSetter:
+ case icSigGravure:
+ case icSigOffsetLithography:
+ case icSigSilkscreen:
+ case icSigFlexography:
+ Yb = 0.2;
+ break;
+
+ default:
+ Yb = 0.2;
+ }
+
+ if (Ybp != NULL)
+ *Ybp = Yb;
+}
+
+#endif /* NEVER */
+
+
+/* See if we can read or guess the viewing conditions */
+/* for an ICC profile. */
+/* Return value 0 if it is well defined */
+/* Return value 1 if it is a guess */
+/* Return value 2 if it is not possible/appropriate */
+int xicc_get_viewcond(
+xicc *p, /* Expanded profile we're working with */
+icxViewCond *vc /* Viewing parameters to return */
+) {
+ icc *pp = p->pp; /* Base ICC */
+
+ /* Numbers we're trying to find */
+ ViewingCondition Ev = vc_none;
+ double Wxyz[3] = {-1.0, -1.0, -1.0}; /* Adapting white color */
+ double La = -1.0; /* Adapting luminance */
+ double Ixyz[3] = {-1.0, -1.0, -1.0}; /* Illuminant color */
+ double Li = -1.0; /* Illuminant luminance */
+ double Lb = -1.0; /* Backgrount luminance */
+ double Yb = -1.0; /* Background relative luminance to Lv */
+ double Lve = -1.0; /* Emissive device image luminance */
+ double Lvr = -1.0; /* Reflective device image luminance */
+ double Lv = -1.0; /* device image luminance */
+ double Yf = -1.0; /* Flare relative luminance to Lv */
+ double Fxyz[3] = {-1.0, -1.0, -1.0}; /* Flare color */
+ icTechnologySignature tsig = icMaxEnumTechnology; /* Technology Signature */
+ icProfileClassSignature devc = icMaxEnumClass;
+ int trans = -1; /* Set to 0 if not transparency, 1 if it is */
+
+ /* Collect all the information we can find */
+
+ /* Emmisive devices image white luminance */
+ {
+ icmXYZArray *luminanceTag;
+
+ if ((luminanceTag = (icmXYZArray *)pp->read_tag(pp, icSigLuminanceTag)) != NULL
+ && luminanceTag->ttype == icSigXYZType && luminanceTag->size >= 1) {
+ Lve = luminanceTag->data[0].Y; /* Copy structure */
+ }
+ }
+
+ /* Flare: */
+ {
+ icmMeasurement *ro;
+
+ if ((ro = (icmMeasurement *)pp->read_tag(pp, icSigMeasurementTag)) != NULL
+ && ro->ttype == icSigMeasurementType) {
+
+ Yf = ro->flare;
+ /* ro->illuminant ie D50, D65, D93, A etc. */
+ }
+ }
+
+ /* Media White Point */
+ {
+ icmXYZArray *whitePointTag;
+
+ if ((whitePointTag = (icmXYZArray *)pp->read_tag(pp, icSigMediaWhitePointTag)) != NULL
+ && whitePointTag->ttype == icSigXYZType && whitePointTag->size >= 1) {
+ Wxyz[0] = whitePointTag->data[0].X;
+ Wxyz[1] = whitePointTag->data[0].Y;
+ Wxyz[2] = whitePointTag->data[0].Z;
+ }
+ }
+
+ /* ViewingConditions: */
+ {
+ icmViewingConditions *ro;
+
+ if ((ro = (icmViewingConditions *)pp->read_tag(pp, icSigViewingConditionsTag)) != NULL
+ && ro->ttype == icSigViewingConditionsType) {
+
+ /* ro->illuminant.X */
+ /* ro->illuminant.Z */
+
+ Li = ro->illuminant.Y;
+
+ /* Reflect illuminant off the media white */
+ Lvr = Li * Wxyz[1];
+
+ /* Illuminant color */
+ Ixyz[0] = ro->illuminant.X/ro->illuminant.Y;
+ Ixyz[1] = 1.0;
+ Ixyz[2] = ro->illuminant.Z/ro->illuminant.Y;
+
+ /* Assume ICC surround is CICAM97 background */
+ /* ro->surround.X */
+ /* ro->surround.Z */
+ La = ro->surround.Y;
+
+ /* ro->stdIlluminant ie D50, D65, D93, A etc. */
+ }
+ }
+
+ /* Stuff we might need */
+
+ /* Technology: */
+ {
+ icmSignature *ro;
+
+ /* Try and read the tag from the file */
+ if ((ro = (icmSignature *)pp->read_tag(pp, icSigTechnologyTag)) != NULL
+ && ro->ttype != icSigSignatureType) {
+
+ tsig = ro->sig;
+ }
+ }
+
+ devc = pp->header->deviceClass; /* Type of profile */
+ if (devc == icSigLinkClass
+ || devc == icSigAbstractClass
+ || devc == icSigColorSpaceClass
+ || devc == icSigNamedColorClass)
+ return 2;
+
+ /*
+ icSigInputClass
+ icSigDisplayClass
+ icSigOutputClass
+ */
+
+ if ((pp->header->flags & icTransparency) != 0)
+ trans = 1;
+ else
+ trans = 0;
+
+
+ /* figure Lv if we have the information */
+ if (Lve >= 0.0)
+ Lv = Lve; /* Emmisive image white luminance */
+ else
+ Lv = Lvr; /* Reflectance image white luminance */
+
+ /* Fudge the technology signature */
+ if (tsig == icMaxEnumTechnology) {
+ if (devc == icSigDisplayClass)
+ tsig = icSigCRTDisplay;
+ }
+
+#ifndef NEVER
+ printf("Enumeration = %d\n", Ev);
+ printf("Viewing Conditions:\n");
+ printf("White adaptation color %f %f %f\n",Wxyz[0], Wxyz[1], Wxyz[2]);
+ printf("Adapting Luminance La = %f\n",La);
+ printf("Illuminant color %f %f %f\n",Ixyz[0], Ixyz[1], Ixyz[2]);
+ printf("Illuminant Luminance Li = %f\n",Li);
+ printf("Background Luminance Lb = %f\n",Lb);
+ printf("Relative Background Yb = %f\n",Yb);
+ printf("Emissive Image White Lve = %f\n",Lve);
+ printf("Reflective Image White Lvr = %f\n",Lvr);
+ printf("Device Image White Lv = %f\n",Lv);
+ printf("Relative Flare Yf = %f\n",Yf);
+ printf("Flare color %f %f %f\n",Fxyz[0], Fxyz[1], Fxyz[2]);
+ printf("Technology = %s\n",tag2str(tsig));
+ printf("deviceClass = %s\n",tag2str(devc));
+ printf("Transparency = %d\n",trans);
+#endif
+
+ /* See if the viewing conditions are completely defined as ICC can do it */
+ if (Wxyz[0] >= 0.0 && Wxyz[1] >= 0.0 && Wxyz[2] >= 0.0
+ && La >= 0.0
+ && Yb >= 0.0
+ && Lv >= 0.0
+ && Yf >= 0.0
+ && Fxyz[0] >= 0.0 && Fxyz[1] >= 0.0 && Fxyz[2] >= 0.0) {
+
+ vc->Ev = vc_none;
+ vc->Wxyz[0] = Wxyz[0];
+ vc->Wxyz[1] = Wxyz[1];
+ vc->Wxyz[2] = Wxyz[2];
+ vc->La = La;
+ vc->Yb = Yb;
+ vc->Lv = Lv;
+ vc->Yf = Yf;
+ vc->Fxyz[0] = Fxyz[0];
+ vc->Fxyz[1] = Fxyz[1];
+ vc->Fxyz[2] = Fxyz[2];
+ return 0;
+ }
+
+ /* Hmm. We didn't get all the info an ICC can contain. */
+ /* We will try to guess some reasonable defaults */
+
+ /* Have we at least got an adaptation white point ? */
+ if (Wxyz[0] < 0.0 || Wxyz[1] < 0.0 || Wxyz[2] < 0.0)
+ return 2; /* No */
+
+ /* Have we got the technology ? */
+ if (tsig == icMaxEnumTechnology)
+ return 2; /* Hopeless */
+
+ /* Guess from the technology */
+ switch (tsig) {
+
+ /* This is inputing either a representation of */
+ /* a natural scene captured on another a print medium, or */
+ /* are is assuming that the medium is the original. */
+ /* We will assume that the print is the original. */
+ case icSigReflectiveScanner:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 34.0; /* Use a practical print evaluation number */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.2; /* Assume grey world */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_average; /* Assume average viewing conditions */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.01; /* Assume 1% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+
+ /* This is inputing either a representation of */
+ /* a natural scene captured on another a photo medium, or */
+ /* are is assuming that the medium is the original. */
+ /* We will assume a compromise media original, natural scene */
+ case icSigFilmScanner:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 50.0; /* Use bright indoors, dull outdoors */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.2; /* Assume grey world */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_average; /* Assume average viewing conditions */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.005; /* Assume 0.5% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+
+ /* Direct scene to value devices. */
+ case icSigDigitalCamera:
+ case icSigVideoCamera:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 110.0; /* Use very bright indoors, usual outdoors */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.2; /* Assume grey world */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_average; /* Assume average viewing conditions */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.0; /* Assume 0% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+
+ /* Emmisive displays. */
+ /* Assume a video monitor is in a darker environment than a CRT */
+ case icSigVideoMonitor:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 4.0; /* Darkened work environment */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.2; /* Assume grey world */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_dim; /* Assume dim viewing conditions */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.01; /* Assume 1% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+
+
+ /* Assume a typical work environment */
+ case icSigCRTDisplay:
+ case icSigPMDisplay:
+ case icSigAMDisplay:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 33.0; /* Typical work environment */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.2; /* Assume grey world */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_average; /* Assume average viewing conditions */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.02; /* Assume 2% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+
+ /* Photo CD has its own viewing definitions */
+ /* (It represents original scene colors) */
+ case icSigPhotoCD:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 320.0; /* Bright outdoors */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.2; /* Assume grey world */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_average; /* Assume average viewing conditions */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.00; /* Assume 0% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+
+ /* Projection devices, either direct, or */
+ /* via another intermediate medium. */
+ /* Assume darkened room, little background */
+ case icSigProjectionTelevision:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 7.0; /* Dark environment */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.1; /* Assume little background */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_dim; /* Dim environment */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.01; /* Assume 1% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+ /* Assume very darkened room, no background */
+ case icSigFilmWriter:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 7.0; /* Dark environment */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.0; /* Assume no background */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_dark; /* Dark environment */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.01; /* Assume 1% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+
+ /* Printed media devices. */
+ /* Assume a normal print viewing environment */
+ case icSigInkJetPrinter:
+ case icSigThermalWaxPrinter:
+ case icSigElectrophotographicPrinter:
+ case icSigElectrostaticPrinter:
+ case icSigDyeSublimationPrinter:
+ case icSigPhotographicPaperPrinter:
+ case icSigPhotoImageSetter:
+ case icSigGravure:
+ case icSigOffsetLithography:
+ case icSigSilkscreen:
+ case icSigFlexography:
+ {
+ if (La < 0.0) /* No adapting luminance */
+ La = 40.0; /* Use a practical print evaluation number */
+ if (Yb < 0.0) /* No background relative luminance */
+ Yb = 0.2; /* Assume grey world */
+ if (Lv < 0.0) /* No device image luminance */
+ Ev = vc_average; /* Assume average viewing conditions */
+ if (Yf < 0.0) /* No flare figure */
+ Yf = 0.01; /* Assume 1% flare */
+ if (Fxyz[0] < 0.0 || Fxyz[1] < 0.0 || Fxyz[2] < 0.0) /* No flare color */
+ Fxyz[0] = Wxyz[0], Fxyz[1] = Wxyz[1], Fxyz[2] = Wxyz[2];
+ break;
+ }
+
+ default:
+ {
+ return 2;
+ }
+ }
+
+ return 1;
+}
+
+/* Write our viewing conditions to the underlying ICC profile, */
+/* using a private tag. */
+void xicc_set_viewcond(
+xicc *p, /* Expanded profile we're working with */
+icxViewCond *vc /* Viewing parameters to return */
+) {
+ //icc *pp = p->pp; /* Base ICC */
+
+ // ~~1 Not implemented yet
+}
+
+
+
+/* Return an enumerated viewing condition */
+/* Return enumeration if OK, -999 if there is no such enumeration. */
+/* xicc may be NULL if just the description is wanted, */
+/* or an explicit white point is provided. */
+int xicc_enum_viewcond(
+xicc *p, /* Expanded profile to get white point (May be NULL if desc NZ) */
+icxViewCond *vc, /* Viewing parameters to return, May be NULL if desc is nz */
+int no, /* Enumeration to return, -1 for default, -2 for none */
+char *as, /* String alias to number, NULL if none */
+int desc, /* NZ - Just return a description of this enumeration in vc */
+double *wp /* Provide white point if xicc is NULL */
+) {
+
+ if (desc == 0) { /* We're setting the viewing condition */
+ icc *pp; /* Base ICC */
+ icmXYZArray *whitePointTag;
+
+ if (vc == NULL)
+ return -999;
+
+ if (p == NULL) {
+ if (wp == NULL)
+ return -999;
+ vc->Wxyz[0] = wp[0];
+ vc->Wxyz[1] = wp[1];
+ vc->Wxyz[2] = wp[2];
+ } else {
+
+ pp = p->pp;
+ if ((whitePointTag = (icmXYZArray *)pp->read_tag(pp, icSigMediaWhitePointTag)) != NULL
+ && whitePointTag->ttype == icSigXYZType && whitePointTag->size >= 1) {
+ vc->Wxyz[0] = whitePointTag->data[0].X;
+ vc->Wxyz[1] = whitePointTag->data[0].Y;
+ vc->Wxyz[2] = whitePointTag->data[0].Z;
+ } else {
+ if (wp == NULL) {
+ sprintf(p->err,"Enum VC: Failed to read Media White point");
+ p->errc = 2;
+ return -999;
+ }
+ vc->Wxyz[0] = wp[0];
+ vc->Wxyz[1] = wp[1];
+ vc->Wxyz[2] = wp[2];
+ }
+ }
+
+ /* Set a default flare color */
+ vc->Fxyz[0] = vc->Wxyz[0];
+ vc->Fxyz[1] = vc->Wxyz[1];
+ vc->Fxyz[2] = vc->Wxyz[2];
+ }
+
+ /*
+
+ Typical adapting field luminances and white luminance in reflective setup:
+
+ E = illuminance in Lux
+ Lv = White luminance assuming 100% reflectance
+ La = Adapting field luminance in cd/m^2, assuming 20% reflectance from surround
+
+ E La Lv Condition
+ 11 0.7 4 Twilight
+ 32 2 10 Subdued indoor lighting
+ 64 4 20 Less than typical office light; sometimes recommended for
+ display-only workplaces (sRGB)
+ 350 22 111 Typical Office (sRGB annex D)
+ 500 32 160 Practical print evaluationa (ISO-3664 P2)
+ 1000 64 318 Good Print evaluation (CIE 116-1995)
+ 1000 64 318 Television Studio lighting
+ 1000 64 318 Overcast Outdoors
+ 2000 127 637 Critical print evaluation (ISO-3664 P1)
+ 10000 637 3183 Typical outdoors, full daylight
+ 50000 3185 15915 Bright summers day
+
+ */
+
+ if (no == -1
+ || (as != NULL && stricmp(as,"d") == 0)) {
+
+ no = -1;
+ if (vc != NULL) {
+ vc->desc = " d - Default Viewing Condition";
+ vc->Ev = vc_average; /* Average viewing conditions */
+ vc->La = 50.0; /* Practical to Good lighting */
+ vc->Lv = 250.0; /* Average viewing conditions ratio */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.01; /* 1% flare */
+ }
+ }
+ else if (no == 0
+ || (as != NULL && stricmp(as,"pp") == 0)) {
+
+ no = 0;
+ if (vc != NULL) {
+ vc->desc = " pp - Practical Reflection Print (ISO-3664 P2)";
+ vc->Ev = vc_average; /* Average viewing conditions */
+ vc->La = 32.0; /* Use a practical print evaluation number */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.01; /* 1% flare */
+ }
+ }
+ else if (no == 1
+ || (as != NULL && stricmp(as,"pe") == 0)) {
+
+ no = 1;
+ if (vc != NULL) {
+ vc->desc = " pe - Print evaluation environment (CIE 116-1995)";
+ vc->Ev = vc_average; /* Average viewing conditions */
+ vc->La = 64.0; /* Good */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.01; /* 1% flare */
+ }
+ }
+ else if (no == 2
+ || (as != NULL && stricmp(as,"pc") == 0)) {
+
+ no = 2;
+ if (vc != NULL) {
+ vc->desc = " pc - Critical print evaluation environment (ISO-3664 P1)";
+ vc->Ev = vc_average; /* Average viewing conditions */
+ vc->La = 127.0; /* Critical */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.01; /* 1% flare */
+ }
+ }
+ else if (no == 3
+ || (as != NULL && stricmp(as,"mt") == 0)) {
+
+ no = 3;
+ if (vc != NULL) {
+ vc->desc = " mt - Monitor in typical work environment";
+ vc->Ev = vc_average; /* Average viewing conditions */
+ vc->La = 22.0; /* Typical work environment */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.02; /* 2% flare */
+ }
+ }
+ else if (no == 4
+ || (as != NULL && stricmp(as,"mb") == 0)) {
+
+ no = 4;
+ if (vc != NULL) {
+ vc->desc = " mb - Bright monitor in bright work environment";
+ vc->Ev = vc_average; /* Average viewing conditions */
+ vc->La = 42.0; /* Bright work environment */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.02; /* 2% flare */
+ }
+ }
+ else if (no == 5
+ || (as != NULL && stricmp(as,"md") == 0)) {
+
+ no = 5;
+ if (vc != NULL) {
+ vc->desc = " md - Monitor in darkened work environment";
+ vc->Ev = vc_dim; /* Dim viewing conditions */
+ vc->La = 4.0; /* Darkened work environment */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.01; /* 1% flare */
+ }
+ }
+ else if (no == 6
+ || (as != NULL && stricmp(as,"jm") == 0)) {
+
+ no = 6;
+ if (vc != NULL) {
+ vc->desc = " jm - Projector in dim environment";
+ vc->Ev = vc_dim; /* Dim viewing conditions */
+ vc->La = 10.0; /* Adaptation is from display */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.01; /* 1% flare */
+ }
+ }
+ else if (no == 7
+ || (as != NULL && stricmp(as,"jd") == 0)) {
+
+ no = 7;
+ if (vc != NULL) {
+ vc->desc = " jd - Projector in dark environment";
+ vc->Ev = vc_dark; /* Dark viewing conditions */
+ vc->La = 10.0; /* Adaptation is from display */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.01; /* 1% flare ? */
+ }
+ }
+ else if (no == 8
+ || (as != NULL && stricmp(as,"pcd") == 0)) {
+
+ no = 8;
+ if (vc != NULL) {
+ vc->desc = "pcd - Photo CD - original scene outdoors";
+ vc->Ev = vc_average; /* Average viewing conditions */
+ vc->La = 320.0; /* Typical outdoors, 1600 cd/m^2 */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.00; /* 0% flare */
+ }
+ }
+ else if (no == 9
+ || (as != NULL && stricmp(as,"ob") == 0)) {
+
+ no = 9;
+ if (vc != NULL) {
+ vc->desc = " ob - Original scene - Bright Outdoors";
+ vc->Ev = vc_average; /* Average viewing conditions */
+ vc->La = 2000.0; /* Bright Outdoors */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.00; /* 0% flare */
+ }
+ }
+ else if (no == 10
+ || (as != NULL && stricmp(as,"cx") == 0)) {
+
+ no = 10;
+ if (vc != NULL) {
+ vc->desc = " cx - Cut Sheet Transparencies on a viewing box";
+ vc->Ev = vc_cut_sheet; /* Cut sheet viewing conditions */
+ vc->La = 53.0; /* Dim, adapted to slide ? */
+ vc->Yb = 0.2; /* Grey world */
+ vc->Yf = 0.01; /* 1% flare ? */
+ }
+ }
+ else {
+ if (p != NULL) {
+ sprintf(p->err,"Enum VC: Unrecognised enumeration %d",no);
+ p->errc = 1;
+ }
+ return -999;
+ }
+
+ return no;
+}
+
+/* Debug: dump a Viewing Condition to standard out */
+void xicc_dump_viewcond(
+icxViewCond *vc
+) {
+ printf("Viewing Condition:\n");
+ if (vc->Ev == vc_dark)
+ printf(" Surround to Image: Dark\n");
+ else if (vc->Ev == vc_dim)
+ printf(" Surround to Image: Dim\n");
+ else if (vc->Ev == vc_average)
+ printf(" Surround to Image: Average\n");
+ else if (vc->Ev == vc_cut_sheet)
+ printf(" Transparency on Light box\n");
+ printf(" Adapted white = %f %f %f\n",vc->Wxyz[0], vc->Wxyz[1], vc->Wxyz[2]);
+ printf(" Adapted luminance = %f cd/m^2\n",vc->La);
+ printf(" Background to image ratio = %f\n",vc->Yb);
+ if (vc->Ev == vc_none)
+ printf(" Image luminance = %f cd/m^2\n",vc->Lv);
+ printf(" Flare to image ratio = %f\n",vc->Yf);
+ printf(" Flare color = %f %f %f\n",vc->Fxyz[0], vc->Fxyz[1], vc->Fxyz[2]);
+}
+
+
+/* Debug: dump an Inking setup to standard out */
+void xicc_dump_inking(icxInk *ik) {
+ printf("Inking settings:\n");
+ if (ik->tlimit < 0.0)
+ printf("No total limit\n");
+ else
+ printf("Total limit = %f%%\n",ik->tlimit * 100.0);
+
+ if (ik->klimit < 0.0)
+ printf("No black limit\n");
+ else
+ printf("Black limit = %f%%\n",ik->klimit * 100.0);
+
+ if (ik->KonlyLmin)
+ printf("K only black as locus Lmin\n");
+ else
+ printf("Normal black as locus Lmin\n");
+
+ if (ik->k_rule == icxKvalue) {
+ printf("Inking rule is a fixed K target\n");
+ } if (ik->k_rule == icxKlocus) {
+ printf("Inking rule is a fixed locus target\n");
+ } if (ik->k_rule == icxKluma5 || ik->k_rule == icxKluma5k) {
+ if (ik->k_rule == icxKluma5)
+ printf("Inking rule is a 5 parameter locus function of L\n");
+ else
+ printf("Inking rule is a 5 parameter K function of L\n");
+ printf("Ksmth = %f\n",ik->c.Ksmth);
+ printf("Kskew = %f\n",ik->c.Kskew);
+ printf("Kstle = %f\n",ik->c.Kstle);
+ printf("Kstpo = %f\n",ik->c.Kstpo);
+ printf("Kenpo = %f\n",ik->c.Kenpo);
+ printf("Kenle = %f\n",ik->c.Kenle);
+ printf("Kshap = %f\n",ik->c.Kshap);
+ } if (ik->k_rule == icxKl5l || ik->k_rule == icxKl5lk) {
+ if (ik->k_rule == icxKl5l)
+ printf("Inking rule is a 2x5 parameter locus function of L and K aux\n");
+ else
+ printf("Inking rule is a 2x5 parameter K function of L and K aux\n");
+ printf("Min Ksmth = %f\n",ik->c.Ksmth);
+ printf("Min Kskew = %f\n",ik->c.Kskew);
+ printf("Min Kstle = %f\n",ik->c.Kstle);
+ printf("Min Kstpo = %f\n",ik->c.Kstpo);
+ printf("Min Kenpo = %f\n",ik->c.Kenpo);
+ printf("Min Kenle = %f\n",ik->c.Kenle);
+ printf("Min Kshap = %f\n",ik->c.Kshap);
+ printf("Max Ksmth = %f\n",ik->x.Ksmth);
+ printf("Max Kskew = %f\n",ik->x.Kskew);
+ printf("Max Kstle = %f\n",ik->x.Kstle);
+ printf("Max Kstpo = %f\n",ik->x.Kstpo);
+ printf("Max Kenpo = %f\n",ik->x.Kenpo);
+ printf("Max Kenle = %f\n",ik->x.Kenle);
+ printf("Max Kshap = %f\n",ik->x.Kshap);
+ }
+}
+
+/* ------------------------------------------------------ */
+/* Gamut Mapping Intent stuff */
+
+/* Return an enumerated gamut mapping intent */
+/* Return enumeration if OK, icxIllegalGMIntent if there is no such enumeration. */
+int xicc_enum_gmapintent(
+icxGMappingIntent *gmi, /* Gamut Mapping parameters to return */
+int no, /* Enumeration selected, icxNoGMIntent for none */
+char *as /* Alias string selector, NULL for none */
+) {
+#ifdef USE_CAM
+ int colccas = 0x2; /* Use cas clipping for colorimetric style intents */
+ int perccas = 0x1; /* Use cas for perceptual style intents */
+#else
+ int colccas = 0x0; /* Use Lab for colorimetric style intents */
+ int perccas = 0x0; /* Use Lab for perceptual style intents */
+ fprintf(stderr,"!!!!!! Warning, USE_CAM is off in xicc.c !!!!!!\n");
+#endif
+
+ /* Assert default if no guidance given */
+ if (no == icxNoGMIntent && as == NULL)
+ no = icxDefaultGMIntent;
+
+ if (no == 0
+ || no == icxAbsoluteGMIntent
+ || (as != NULL && stricmp(as,"a") == 0)) {
+ /* Map Absolute appearance space Jab to Jab and clip out of gamut */
+ no = 0;
+ gmi->as = "a";
+ gmi->desc = " a - Absolute Colorimetric (in Jab) [ICC Absolute Colorimetric]";
+ gmi->icci = icAbsoluteColorimetric;
+ gmi->usecas = colccas; /* Use absolute appearance space */
+ gmi->usemap = 0; /* Don't use gamut mapping */
+ gmi->greymf = 0.0;
+ gmi->glumwcpf = 0.0;
+ gmi->glumwexf = 0.0;
+ gmi->glumbcpf = 0.0;
+ gmi->glumbexf = 0.0;
+ gmi->glumknf = 0.0;
+ gmi->gamcpf = 0.0;
+ gmi->gamexf = 0.0;
+ gmi->gamcknf = 0.0;
+ gmi->gamxknf = 0.0;
+ gmi->gampwf = 0.0;
+ gmi->gamswf = 0.0;
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 1
+ || (as != NULL && stricmp(as,"aw") == 0)) {
+
+ /* I'm not sure how often this intent is useful. It's less likely than */
+ /* I though that a printer white point won't fit within the gamut */
+ /* of a display profile, since the display white always has Y = 1.0, */
+ /* and no paper has better than about 95% reflectance. */
+ /* Perhaps it may be more useful for targeting printer profiles ? */
+
+ /* Map Absolute Jab to Jab and scale source to avoid clipping the white point */
+ no = 1;
+ gmi->as = "aw";
+ gmi->desc = "aw - Absolute Colorimetric (in Jab) with scaling to fit white point";
+ gmi->icci = icAbsoluteColorimetric;
+ gmi->usecas = 0x100 | colccas; /* Absolute Appearance space with scaling */
+ /* to avoid clipping the source white point */
+ gmi->usemap = 0; /* Don't use gamut mapping */
+ gmi->greymf = 0.0;
+ gmi->glumwcpf = 0.0;
+ gmi->glumwexf = 0.0;
+ gmi->glumbcpf = 0.0;
+ gmi->glumbexf = 0.0;
+ gmi->glumknf = 0.0;
+ gmi->gamcpf = 0.0;
+ gmi->gamexf = 0.0;
+ gmi->gamcknf = 0.0;
+ gmi->gamxknf = 0.0;
+ gmi->gampwf = 0.0;
+ gmi->gamswf = 0.0;
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 2
+ || (as != NULL && stricmp(as,"aa") == 0)) {
+
+ /* Map appearance space Jab to Jab and clip out of gamut */
+ no = 2;
+ gmi->as = "aa";
+ gmi->desc = "aa - Absolute Appearance";
+ gmi->icci = icRelativeColorimetric;
+ gmi->usecas = perccas; /* Appearance space */
+ gmi->usemap = 0; /* Don't use gamut mapping */
+ gmi->greymf = 0.0;
+ gmi->glumwcpf = 0.0;
+ gmi->glumwexf = 0.0;
+ gmi->glumbcpf = 0.0;
+ gmi->glumbexf = 0.0;
+ gmi->glumknf = 0.0;
+ gmi->gamcpf = 0.0;
+ gmi->gamexf = 0.0;
+ gmi->gamcknf = 0.0;
+ gmi->gamxknf = 0.0;
+ gmi->gampwf = 0.0;
+ gmi->gamswf = 0.0;
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 3
+ || no == icxRelativeGMIntent
+ || (as != NULL && stricmp(as,"r") == 0)) {
+
+ /* Align neutral axes and linearly map white point, then */
+ /* map appearance space Jab to Jab and clip out of gamut */
+ no = 3;
+ gmi->as = "r";
+ gmi->desc = " r - White Point Matched Appearance [ICC Relative Colorimetric]";
+ gmi->icci = icRelativeColorimetric;
+ gmi->usecas = perccas; /* Appearance space */
+ gmi->usemap = 1; /* Use gamut mapping */
+ gmi->greymf = 1.0; /* Fully align grey axis */
+ gmi->glumwcpf = 1.0; /* Fully compress grey axis at white end */
+ gmi->glumwexf = 1.0; /* Fully expand grey axis at white end */
+ gmi->glumbcpf = 0.0; /* No compression at black end */
+ gmi->glumbexf = 0.0; /* No expansion at black end */
+ gmi->glumknf = 0.0;
+ gmi->gamcpf = 0.0;
+ gmi->gamexf = 0.0;
+ gmi->gamcknf = 0.0;
+ gmi->gamxknf = 0.0;
+ gmi->gampwf = 0.0;
+ gmi->gamswf = 0.0;
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 4
+ || (as != NULL && stricmp(as,"la") == 0)) {
+
+ /* Align neutral axes and linearly map white and black points, then */
+ /* map appearance space Jab to Jab and clip out of gamut */
+ no = 4;
+ gmi->as = "la";
+ gmi->desc = "la - Luminance axis matched Appearance";
+ gmi->icci = icRelativeColorimetric;
+ gmi->usecas = perccas; /* Appearance space */
+ gmi->usemap = 1; /* Use gamut mapping */
+ gmi->greymf = 1.0; /* Fully align grey axis */
+ gmi->glumwcpf = 1.0; /* Fully compress grey axis at white end */
+ gmi->glumwexf = 1.0; /* Fully expand grey axis at white end */
+ gmi->glumbcpf = 1.0; /* Fully compress grey axis at black end */
+ gmi->glumbexf = 1.0; /* Fully expand grey axis at black end */
+ gmi->glumknf = 0.0; /* No knee on grey mapping */
+ gmi->gamcpf = 0.0; /* No gamut compression */
+ gmi->gamexf = 0.0; /* No gamut expansion */
+ gmi->gamcknf = 0.0; /* No knee in gamut compress */
+ gmi->gamxknf = 0.0; /* No knee in gamut expand */
+ gmi->gampwf = 0.0; /* No Perceptual surface weighting factor */
+ gmi->gamswf = 0.0; /* No Saturation surface weighting factor */
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 5
+ || no == icxDefaultGMIntent
+ || no == icxPerceptualGMIntent
+ || (as != NULL && stricmp(as,"p") == 0)) {
+
+ /* Align neutral axes and perceptually map white and black points, */
+ /* perceptually compress out of gamut and map appearance space Jab to Jab. */
+ no = 5;
+ gmi->as = "p";
+ gmi->desc = " p - Perceptual (Preferred) (Default) [ICC Perceptual]";
+ gmi->icci = icPerceptual;
+ gmi->usecas = perccas; /* Appearance space */
+ gmi->usemap = 1; /* Use gamut mapping */
+ gmi->greymf = 1.0; /* Fully align grey axis */
+ gmi->glumwcpf = 1.0; /* Fully compress grey axis at white end */
+ gmi->glumwexf = 1.0; /* Fully expand grey axis at white end */
+ gmi->glumbcpf = 1.0; /* Fully compress grey axis at black end */
+ gmi->glumbexf = 1.0; /* Fully expand grey axis at black end */
+ gmi->glumknf = 1.0; /* Sigma knee in grey compress/expand */
+ gmi->gamcpf = 1.0; /* Full gamut compression */
+ gmi->gamexf = 0.0; /* No gamut expansion */
+ gmi->gamcknf = 0.8; /* High Sigma knee in gamut compress */
+ gmi->gamxknf = 0.0; /* No knee in gamut expand */
+ gmi->gampwf = 1.0; /* Full Perceptual surface weighting factor */
+ gmi->gamswf = 0.0; /* No Saturation surface weighting factor */
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 6
+ || (as != NULL && stricmp(as,"pa") == 0)) {
+
+ /* Don't align neutral axes, but perceptually compress out of gamut */
+ /* and map appearance space Jab to Jab. */
+ no = 5;
+ gmi->as = "pa";
+ gmi->desc = "pa - Perceptual Apperance ";
+ gmi->icci = icPerceptual;
+ gmi->usecas = perccas; /* Appearance space */
+ gmi->usemap = 1; /* Use gamut mapping */
+ gmi->greymf = 0.0; /* Don't align grey axis */
+ gmi->glumwcpf = 1.0; /* Fully compress grey axis at white end */
+ gmi->glumwexf = 1.0; /* Fully expand grey axis at white end */
+ gmi->glumbcpf = 1.0; /* Fully compress grey axis at black end */
+ gmi->glumbexf = 1.0; /* Fully expand grey axis at black end */
+ gmi->glumknf = 1.0; /* Sigma knee in grey compress/expand */
+ gmi->gamcpf = 1.0; /* Full gamut compression */
+ gmi->gamexf = 0.0; /* No gamut expansion */
+ gmi->gamcknf = 0.8; /* High Sigma knee in gamut compress */
+ gmi->gamxknf = 0.0; /* No knee in gamut expand */
+ gmi->gampwf = 1.0; /* Full Perceptual surface weighting factor */
+ gmi->gamswf = 0.0; /* No Saturation surface weighting factor */
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 7
+ || (as != NULL && stricmp(as,"ms") == 0)) {
+
+ /* Align neutral axes and perceptually map white and black points, */
+ /* perceptually compress and expand to match gamuts and map Jab to Jab. */
+ no = 6;
+ gmi->as = "ms";
+ gmi->desc = "ms - Saturation";
+ gmi->icci = icSaturation;
+ gmi->usecas = perccas; /* Appearance space */
+ gmi->usemap = 1; /* Use gamut mapping */
+ gmi->greymf = 1.0; /* Fully align grey axis */
+ gmi->glumwcpf = 1.0; /* Fully compress grey axis at white end */
+ gmi->glumwexf = 1.0; /* Fully expand grey axis at white end */
+ gmi->glumbcpf = 1.0; /* Fully compress grey axis at black end */
+ gmi->glumbexf = 1.0; /* Fully expand grey axis at black end */
+ gmi->glumknf = 1.0; /* Sigma knee in grey compress/expand */
+ gmi->gamcpf = 1.0; /* Full gamut compression */
+ gmi->gamexf = 1.0; /* Full gamut expansion */
+ gmi->gamcknf = 1.0; /* High Sigma knee in gamut compress/expand */
+ gmi->gamxknf = 0.4; /* Moderate Sigma knee in gamut compress/expand */
+ gmi->gampwf = 0.2; /* Slight perceptual surface weighting factor */
+ gmi->gamswf = 0.8; /* Most saturation surface weighting factor */
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 8
+ || no == icxSaturationGMIntent
+ || (as != NULL && stricmp(as,"s") == 0)) {
+
+ /* Same as "ms" but enhance saturation */
+ no = 7;
+ gmi->as = "s";
+ gmi->desc = " s - Enhanced Saturation [ICC Saturation]";
+ gmi->icci = icSaturation;
+ gmi->usecas = perccas; /* Appearance space */
+ gmi->usemap = 1; /* Use gamut mapping */
+ gmi->greymf = 1.0; /* Fully align grey axis */
+ gmi->glumwcpf = 1.0; /* Fully compress grey axis at white end */
+ gmi->glumwexf = 1.0; /* Fully expand grey axis at white end */
+ gmi->glumbcpf = 1.0; /* Fully compress grey axis at black end */
+ gmi->glumbexf = 1.0; /* Fully expand grey axis at black end */
+ gmi->glumknf = 1.0; /* Sigma knee in grey compress/expand */
+ gmi->gamcpf = 1.0; /* Full gamut compression */
+ gmi->gamexf = 1.0; /* Full gamut expansion */
+ gmi->gamcknf = 1.0; /* High sigma knee in gamut compress */
+ gmi->gamxknf = 0.5; /* Moderate sigma knee in gamut expand */
+ gmi->gampwf = 0.0; /* No Perceptual surface weighting factor */
+ gmi->gamswf = 1.0; /* Full Saturation surface weighting factor */
+ gmi->satenh = 0.9; /* Medium saturation enhancement */
+ }
+ else if (no == 9
+ || (as != NULL && stricmp(as,"al") == 0)) {
+
+ /* Map absolute L*a*b* to L*a*b* and clip out of gamut */
+ no = 8;
+ gmi->as = "al";
+ gmi->desc = "al - Absolute Colorimetric (Lab)";
+ gmi->icci = icAbsoluteColorimetric;
+ gmi->usecas = 0x0; /* Don't use appearance space, use L*a*b* */
+ gmi->usemap = 0; /* Don't use gamut mapping */
+ gmi->greymf = 0.0;
+ gmi->glumwcpf = 0.0;
+ gmi->glumwexf = 0.0;
+ gmi->glumbcpf = 0.0;
+ gmi->glumbexf = 0.0;
+ gmi->glumknf = 0.0;
+ gmi->gamcpf = 0.0;
+ gmi->gamexf = 0.0;
+ gmi->gamcknf = 0.0;
+ gmi->gamxknf = 0.0;
+ gmi->gampwf = 0.0;
+ gmi->gamswf = 0.0;
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else if (no == 10
+ || (as != NULL && stricmp(as,"rl") == 0)) {
+
+ /* Align neutral axes and linearly map white point, then */
+ /* map L*a*b* to L*a*b* and clip out of gamut */
+ no = 3;
+ gmi->as = "rl";
+ gmi->desc = "rl - White Point Matched Appearance (Lab)";
+ gmi->icci = icRelativeColorimetric;
+ gmi->usecas = 0x0; /* Don't use appearance space, use L*a*b* */
+ gmi->usemap = 1; /* Use gamut mapping */
+ gmi->greymf = 1.0; /* And linearly map white point */
+ gmi->glumwcpf = 1.0;
+ gmi->glumwexf = 1.0;
+ gmi->glumbcpf = 0.0;
+ gmi->glumbexf = 0.0;
+ gmi->glumknf = 0.0;
+ gmi->gamcpf = 0.0;
+ gmi->gamexf = 0.0;
+ gmi->gamcknf = 0.0;
+ gmi->gamxknf = 0.0;
+ gmi->gampwf = 0.0;
+ gmi->gamswf = 0.0;
+ gmi->satenh = 0.0; /* No saturation enhancement */
+ }
+ else { /* icxIllegalGMIntent */
+ return icxIllegalGMIntent;
+ }
+
+ return no;
+}
+
+
+/* Debug: dump a Gamut Mapping specification */
+void xicc_dump_gmi(
+icxGMappingIntent *gmi /* Gamut Mapping parameters to return */
+) {
+ printf(" Gamut Mapping Specification:\n");
+ if (gmi->desc != NULL)
+ printf(" Description = '%s'\n",gmi->desc);
+ printf(" Closest ICC intent = '%s'\n",icm2str(icmRenderingIntent,gmi->icci));
+
+ if ((gmi->usecas & 0xff) == 0)
+ printf(" Not using Color Apperance Space\n");
+ else if ((gmi->usecas & 0xff) == 1)
+ printf(" Using Color Apperance Space\n");
+ else if ((gmi->usecas & 0xff) == 2)
+ printf(" Using Absolute Color Apperance Space\n");
+
+ if ((gmi->usecas & 0x100) != 0)
+ printf(" Scaling source to avoid white point clipping\n");
+
+ if (gmi->usemap == 0)
+ printf(" Not using Mapping\n");
+ else {
+ printf(" Using Mapping with parameters:\n");
+ printf(" Grey axis alignment factor %f\n", gmi->greymf);
+ printf(" Grey axis white compression factor %f\n", gmi->glumwcpf);
+ printf(" Grey axis white expansion factor %f\n", gmi->glumwexf);
+ printf(" Grey axis black compression factor %f\n", gmi->glumbcpf);
+ printf(" Grey axis black expansion factor %f\n", gmi->glumbexf);
+ printf(" Grey axis knee factor %f\n", gmi->glumknf);
+ printf(" Gamut compression factor %f\n", gmi->gamcpf);
+ printf(" Gamut expansion factor %f\n", gmi->gamexf);
+ printf(" Gamut compression knee factor %f\n", gmi->gamcknf);
+ printf(" Gamut expansion knee factor %f\n", gmi->gamxknf);
+ printf(" Gamut Perceptual mapping weighting factor %f\n", gmi->gampwf);
+ printf(" Gamut Saturation mapping weighting factor %f\n", gmi->gamswf);
+ printf(" Saturation enhancement factor %f\n", gmi->satenh);
+ }
+}
+
+/* ------------------------------------------------------ */
+/* Turn xicc xcal into limit calibration callback */
+
+/* Given an icc profile, try and create an xcal */
+/* Return NULL on error or no cal */
+xcal *xiccReadCalTag(icc *p) {
+ xcal *cal = NULL;
+ icTagSignature sig = icmMakeTag('t','a','r','g');
+ icmText *ro;
+ int oi, tab;
+
+//printf("~1 about to look for CAL in profile\n");
+ if ((ro = (icmText *)p->read_tag(p, sig)) != NULL) {
+ cgatsFile *cgf;
+ cgats *icg;
+
+ if (ro->ttype != icSigTextType)
+ return NULL;
+
+//printf("~1 found 'targ' tag\n");
+ if ((icg = new_cgats()) == NULL) {
+ return NULL;
+ }
+ if ((cgf = new_cgatsFileMem(ro->data, ro->size)) != NULL) {
+ icg->add_other(icg, "CTI3");
+ oi = icg->add_other(icg, "CAL");
+
+//printf("~1 created cgats object from 'targ' tag\n");
+ if (icg->read(icg, cgf) == 0) {
+
+ for (tab = 0; tab < icg->ntables; tab++) {
+ if (icg->t[tab].tt == tt_other && icg->t[tab].oi == oi) {
+ break;
+ }
+ }
+ if (tab < icg->ntables) {
+//printf("~1 found CAL table\n");
+
+ if ((cal = new_xcal()) == NULL) {
+ icg->del(icg);
+ cgf->del(cgf);
+ return NULL;
+ }
+ if (cal->read_cgats(cal, icg, tab, "'targ' tag") != 0) {
+#ifdef DEBUG
+ printf("read_cgats on cal tag failed\n");
+#endif
+ cal->del(cal);
+ cal = NULL;
+ }
+//else printf("~1 read CAL and creaded xcal object OK\n");
+ }
+ }
+ cgf->del(cgf);
+ }
+ icg->del(icg);
+ }
+ return cal;
+}
+
+/* A callback that uses an xcal, that can be used with icc get_tac */
+void xiccCalCallback(void *cntx, double *out, double *in) {
+ xcal *cal = (xcal *)cntx;
+
+ cal->interp(cal, out, in);
+}
+
+/* ---------------------------------------------- */
+
+/* Utility function - given an open icc profile, */
+/* guess which channel is the black. */
+/* Return -1 if there is no black channel or it can't be guessed */
+int icxGuessBlackChan(icc *p) {
+ int kch = -1;
+
+ switch (p->header->colorSpace) {
+ case icSigCmykData:
+ kch = 3;
+ break;
+
+ /* Use a heuristic to detect the black channel. */
+ /* This duplicates code in icxLu_comp_bk_point() :-( */
+ /* Colorant guessing should go in icclib ? */
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSig6colorData:
+ case icSig7colorData:
+ case icSig8colorData:
+ case icSig9colorData:
+ case icSig10colorData:
+ case icSig11colorData:
+ case icSig12colorData:
+ case icSig13colorData:
+ case icSig14colorData:
+ case icSig15colorData:
+ case icSigMch5Data:
+ case icSigMch6Data:
+ case icSigMch7Data:
+ case icSigMch8Data: {
+ icmLuBase *lu;
+ double dval[MAX_CHAN];
+ double ncval[3];
+ double cvals[MAX_CHAN][3];
+ int inn, e, nlighter, ndarker;
+
+ /* Grab a lookup object */
+ if ((lu = p->get_luobj(p, icmFwd, icRelativeColorimetric, icSigLabData, icmLuOrdNorm)) == NULL)
+ error("icxGetLimits: assert: getting Fwd Lookup failed!");
+
+ lu->spaces(lu, NULL, &inn, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ /* Decide if the colorspace is aditive or subtractive */
+
+ /* First the no colorant value */
+ for (e = 0; e < inn; e++)
+ dval[e] = 0.0;
+ lu->lookup(lu, ncval, dval);
+
+ /* Then all the colorants */
+ nlighter = ndarker = 0;
+ for (e = 0; e < inn; e++) {
+ dval[e] = 1.0;
+ lu->lookup(lu, cvals[e], dval);
+ dval[e] = 0.0;
+ if (fabs(cvals[e][0] - ncval[0]) > 5.0) {
+ if (cvals[e][0] > ncval[0])
+ nlighter++;
+ else
+ ndarker++;
+ }
+ }
+
+ if (ndarker > 0 && nlighter == 0) { /* Assume subtractive. */
+ double pbk[3] = { 0.0,0.0,0.0 }; /* Perfect black */
+ double smd = 1e10; /* Smallest distance */
+
+ /* Guess the black channel */
+ for (e = 0; e < inn; e++) {
+ double tt;
+ tt = icmNorm33sq(pbk, cvals[e]);
+ if (tt < smd) {
+ smd = tt;
+ kch = e;
+ }
+ }
+ /* See if the black seems sane */
+ if (cvals[kch][0] > 40.0
+ || fabs(cvals[kch][1]) > 10.0
+ || fabs(cvals[kch][2]) > 10.0) {
+ kch = -1;
+ }
+ }
+ lu->del(lu);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return kch;
+}
+
+/* Utility function - given an open icc profile, */
+/* estmate the total ink limit and black ink limit. */
+/* Note that this is rather rough, because ICC profiles */
+/* don't have a tag for this information, and ICC profiles */
+/* don't have any straightforward way of identifying particular */
+/* color channels for > 4 color. */
+/* If there are no limits, or they are not discoverable or */
+/* applicable, return values of -1.0 */
+
+void icxGetLimits(
+xicc *xp,
+double *tlimit,
+double *klimit
+) {
+ icc *p = xp->pp;
+ int nch;
+ double max[MAX_CHAN]; /* Max of each channel */
+ double total;
+
+ total = p->get_tac(p, max, xp->cal != NULL ? xiccCalCallback : NULL, (void *)xp->cal);
+
+ if (total < 0.0) { /* Not valid */
+ if (tlimit != NULL)
+ *tlimit = -1.0;
+ if (klimit != NULL)
+ *klimit = -1.0;
+ return;
+ }
+
+ nch = icmCSSig2nchan(p->header->colorSpace);
+
+ /* No effective limit */
+ if (tlimit != NULL) {
+ if (total >= (double)nch) {
+ *tlimit = -1.0;
+ } else {
+ *tlimit = total;
+ }
+ }
+
+ if (klimit != NULL) {
+ int kch;
+
+ kch = icxGuessBlackChan(p);
+
+ if (kch < 0 || max[kch] >= 1.0) {
+ *klimit = -1.0;
+ } else {
+ *klimit = max[kch];
+ }
+ }
+}
+
+/* Replace a non-set limit (ie. < 0.0) with the heuristic from */
+/* the given profile. */
+void icxDefaultLimits(
+xicc *xp,
+double *tlout,
+double tlin,
+double *klout,
+double klin
+) {
+ if (tlin < 0.0 || klin < 0.0) {
+ double tl, kl;
+
+ icxGetLimits(xp, &tl, &kl);
+
+ if (tlin < 0.0)
+ tlin = tl;
+
+ if (klin < 0.0)
+ klin = kl;
+ }
+
+ if (tlout != NULL)
+ *tlout = tlin;
+
+ if (klout != NULL)
+ *klout = klin;
+}
+
+/* Structure to hold optimisation information */
+typedef struct {
+ xcal *cal;
+ double ilimit;
+ double uilimit;
+} ulimctx;
+
+/* Callback to find equivalent underlying total limit */
+/* and try and maximize it while remaining within gamut */
+static double ulimitfunc(void *cntx, double pv[]) {
+ ulimctx *cx = (ulimctx *)cntx;
+ xcal *cal = cx->cal;
+ int devchan = cal->devchan;
+ int i;
+ double dv, odv;
+ double og = 0.0, rv = 0.0;
+
+ double usum = 0.0, sum = 0.0;
+
+ /* Comute calibrated sum of channels except last */
+ for (i = 0; i < (devchan-1); i++) {
+ double dv = pv[i]; /* Underlying (pre-calibration) device value */
+ usum += dv; /* Underlying sum */
+ if (dv < 0.0) {
+ og += -dv;
+ dv = 0.0;
+ } else if (dv > 1.0) {
+ og += dv - 1.0;
+ dv = 1.0;
+ } else
+ dv = cal->interp_ch(cal, i, dv); /* Calibrated device value */
+ sum += dv; /* Calibrated device sum */
+ }
+ /* Compute the omitted channel value */
+ dv = cx->ilimit - sum; /* Omitted calibrated device value */
+ if (dv < 0.0) {
+ og += -dv;
+ dv = 0.0;
+ } else if (dv > 1.0) {
+ og += dv - 1.0;
+ dv = 1.0;
+ } else
+ dv = cal->inv_interp_ch(cal, i, dv); /* Omitted underlying device value */
+ usum += dv; /* Underlying sum */
+ cx->uilimit = usum;
+
+ rv = 10000.0 * og - usum; /* Penalize out of gamut, maximize underlying sum */
+
+//printf("~1 returning %f from %f %f %f %f\n",rv,pv[0],pv[1],pv[2],dv);
+ return rv;
+}
+
+/* Given a calibrated total ink limit and an xcal, return the */
+/* equivalent underlying (pre-calibration) total ink limit. */
+/* This is the maximum equivalent, that makes sure that */
+/* the calibrated limit is met or exceeded. */
+double icxMaxUnderlyingLimit(xcal *cal, double ilimit) {
+ ulimctx cx;
+ int i;
+ double dv[MAX_CHAN];
+ double sr[MAX_CHAN];
+ double rv; /* Residual value */
+
+ if (cal->devchan <= 1) {
+ return cal->inv_interp_ch(cal, 0, ilimit);
+ }
+
+ cx.cal = cal;
+ cx.ilimit = ilimit;
+
+ for (i = 0; i < (cal->devchan-1); i++) {
+ sr[i] = 0.05;
+ dv[i] = 0.1;
+ }
+ if (powell(&rv, cal->devchan-1, dv, sr, 0.000001, 1000, ulimitfunc,
+ (void *)&cx, NULL, NULL) != 0) {
+ warning("icxUnderlyingLimit() failed for chan %d, ilimit %f\n",cal->devchan,ilimit);
+ return ilimit;
+ }
+ ulimitfunc((void *)&cx, dv);
+
+ return cx.uilimit;
+}
+
+/* ------------------------------------------------------ */
+/* Conversion and deltaE formular that include partial */
+/* derivatives, for use within fit parameter optimisations. */
+
+/* CIE XYZ to perceptual Lab with partial derivatives. */
+void icxdXYZ2Lab(icmXYZNumber *w, double *out, double dout[3][3], double *in) {
+ double wp[3], tin[3], dtin[3];
+ int i;
+
+ wp[0] = w->X, wp[1] = w->Y, wp[2] = w->Z;
+
+ for (i = 0; i < 3; i++) {
+ tin[i] = in[i]/wp[i];
+ dtin[i] = 1.0/wp[i];
+
+ if (tin[i] > 0.008856451586) {
+ dtin[i] *= pow(tin[i], -2.0/3.0) / 3.0;
+ tin[i] = pow(tin[i],1.0/3.0);
+ } else {
+ dtin[i] *= 7.787036979;
+ tin[i] = 7.787036979 * tin[i] + 16.0/116.0;
+ }
+ }
+
+ out[0] = 116.0 * tin[1] - 16.0;
+ dout[0][0] = 0.0;
+ dout[0][1] = 116.0 * dtin[1];
+ dout[0][2] = 0.0;
+
+ out[1] = 500.0 * (tin[0] - tin[1]);
+ dout[1][0] = 500.0 * dtin[0];
+ dout[1][1] = 500.0 * -dtin[1];
+ dout[1][2] = 0.0;
+
+ out[2] = 200.0 * (tin[1] - tin[2]);
+ dout[2][0] = 0.0;
+ dout[2][1] = 200.0 * dtin[1];
+ dout[2][2] = 200.0 * -dtin[2];
+}
+
+
+/* Return the normal Delta E squared, given two Lab values, */
+/* including partial derivatives. */
+double icxdLabDEsq(double dout[2][3], double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ dout[0][0] = 2.0 * tt;
+ dout[1][0] = -2.0 * tt;
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ dout[0][1] = 2.0 * tt;
+ dout[1][1] = -2.0 * tt;
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ dout[0][2] = 2.0 * tt;
+ dout[1][2] = -2.0 * tt;
+ rv += tt * tt;
+ return rv;
+}
+
+/* Return the CIE94 Delta E color difference measure, squared */
+/* including partial derivatives. */
+double icxdCIE94sq(double dout[2][3], double Lab0[3], double Lab1[3]) {
+ double desq, _desq[2][3];
+ double dlsq;
+ double dcsq, _dcsq[2][2]; /* == [x][1,2] */
+ double c12, _c12[2][2]; /* == [x][1,2] */
+ double dhsq, _dhsq[2][2]; /* == [x][1,2] */
+ double rv;
+
+ {
+ double dl, da, db;
+
+ dl = Lab0[0] - Lab1[0];
+ dlsq = dl * dl; /* dl squared */
+ da = Lab0[1] - Lab1[1];
+ db = Lab0[2] - Lab1[2];
+
+
+ /* Compute normal Lab delta E squared */
+ desq = dlsq + da * da + db * db;
+ _desq[0][0] = 2.0 * dl;
+ _desq[1][0] = -2.0 * dl;
+ _desq[0][1] = 2.0 * da;
+ _desq[1][1] = -2.0 * da;
+ _desq[0][2] = 2.0 * db;
+ _desq[1][2] = -2.0 * db;
+ }
+
+ {
+ double c1, c2, dc, tt;
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ c2 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ c12 = sqrt(c1 * c2); /* Symetric chromanance */
+
+ tt = 0.5 * (pow(c2, 0.5) + 1e-12)/(pow(c1, 1.5) + 1e-12);
+ _c12[0][0] = Lab0[1] * tt;
+ _c12[0][1] = Lab0[2] * tt;
+ tt = 0.5 * (pow(c1, 0.5) + 1e-12)/(pow(c2, 1.5) + 1e-12);
+ _c12[1][0] = Lab1[1] * tt;
+ _c12[1][1] = Lab1[2] * tt;
+
+ /* delta chromanance squared */
+ dc = c2 - c1;
+ dcsq = dc * dc;
+ if (c1 < 1e-12 || c2 < 1e-12) {
+ c1 += 1e-12;
+ c2 += 1e-12;
+ }
+ _dcsq[0][0] = -2.0 * Lab0[1] * (c2 - c1)/c1;
+ _dcsq[0][1] = -2.0 * Lab0[2] * (c2 - c1)/c1;
+ _dcsq[1][0] = 2.0 * Lab1[1] * (c2 - c1)/c2;
+ _dcsq[1][1] = 2.0 * Lab1[2] * (c2 - c1)/c2;
+ }
+
+ /* Compute delta hue squared */
+ dhsq = desq - dlsq - dcsq;
+ if (dhsq >= 0.0) {
+ _dhsq[0][0] = _desq[0][1] - _dcsq[0][0];
+ _dhsq[0][1] = _desq[0][2] - _dcsq[0][1];
+ _dhsq[1][0] = _desq[1][1] - _dcsq[1][0];
+ _dhsq[1][1] = _desq[1][2] - _dcsq[1][1];
+ } else {
+ dhsq = 0.0;
+ _dhsq[0][0] = 0.0;
+ _dhsq[0][1] = 0.0;
+ _dhsq[1][0] = 0.0;
+ _dhsq[1][1] = 0.0;
+ }
+
+ {
+ double sc, scsq, scf;
+ double sh, shsq, shf;
+
+ /* Weighting factors for delta chromanance & delta hue */
+ sc = 1.0 + 0.048 * c12;
+ scsq = sc * sc;
+
+ sh = 1.0 + 0.014 * c12;
+ shsq = sh * sh;
+
+ rv = dlsq + dcsq/scsq + dhsq/shsq;
+
+ scf = 0.048 * -2.0 * dcsq/(scsq * sc);
+ shf = 0.014 * -2.0 * dhsq/(shsq * sh);
+ dout[0][0] = _desq[0][0];
+ dout[0][1] = _dcsq[0][0]/scsq + _c12[0][0] * scf
+ + _dhsq[0][0]/shsq + _c12[0][0] * shf;
+ dout[0][2] = _dcsq[0][1]/scsq + _c12[0][1] * scf
+ + _dhsq[0][1]/shsq + _c12[0][1] * shf;
+ dout[1][0] = _desq[1][0];
+ dout[1][1] = _dcsq[1][0]/scsq + _c12[1][0] * scf
+ + _dhsq[1][0]/shsq + _c12[1][0] * shf;
+ dout[1][2] = _dcsq[1][1]/scsq + _c12[1][1] * scf
+ + _dhsq[1][1]/shsq + _c12[1][1] * shf;
+ return rv;
+ }
+}
+
+// ~~99 not sure if these are correct:
+
+/* Return the normal Delta E given two Lab values, */
+/* including partial derivatives. */
+double icxdLabDE(double dout[2][3], double *Lab0, double *Lab1) {
+ double rv = 0.0, tt;
+
+ tt = Lab0[0] - Lab1[0];
+ dout[0][0] = 1.0 * tt;
+ dout[1][0] = -1.0 * tt;
+ rv += tt * tt;
+ tt = Lab0[1] - Lab1[1];
+ dout[0][1] = 1.0 * tt;
+ dout[1][1] = -1.0 * tt;
+ rv += tt * tt;
+ tt = Lab0[2] - Lab1[2];
+ dout[0][2] = 1.0 * tt;
+ dout[1][2] = -1.0 * tt;
+ rv += tt * tt;
+ return sqrt(rv);
+}
+
+/* Return the CIE94 Delta E color difference measure */
+/* including partial derivatives. */
+double icxdCIE94(double dout[2][3], double Lab0[3], double Lab1[3]) {
+ double desq, _desq[2][3];
+ double dlsq;
+ double dcsq, _dcsq[2][2]; /* == [x][1,2] */
+ double c12, _c12[2][2]; /* == [x][1,2] */
+ double dhsq, _dhsq[2][2]; /* == [x][1,2] */
+ double rv;
+
+ {
+ double dl, da, db;
+
+ dl = Lab0[0] - Lab1[0];
+ dlsq = dl * dl; /* dl squared */
+ da = Lab0[1] - Lab1[1];
+ db = Lab0[2] - Lab1[2];
+
+
+ /* Compute normal Lab delta E squared */
+ desq = dlsq + da * da + db * db;
+ _desq[0][0] = 1.0 * dl;
+ _desq[1][0] = -1.0 * dl;
+ _desq[0][1] = 1.0 * da;
+ _desq[1][1] = -1.0 * da;
+ _desq[0][2] = 1.0 * db;
+ _desq[1][2] = -1.0 * db;
+ }
+
+ {
+ double c1, c2, dc, tt;
+
+ /* Compute chromanance for the two colors */
+ c1 = sqrt(Lab0[1] * Lab0[1] + Lab0[2] * Lab0[2]);
+ c2 = sqrt(Lab1[1] * Lab1[1] + Lab1[2] * Lab1[2]);
+ c12 = sqrt(c1 * c2); /* Symetric chromanance */
+
+ tt = 0.5 * (pow(c2, 0.5) + 1e-12)/(pow(c1, 1.5) + 1e-12);
+ _c12[0][0] = Lab0[1] * tt;
+ _c12[0][1] = Lab0[2] * tt;
+ tt = 0.5 * (pow(c1, 0.5) + 1e-12)/(pow(c2, 1.5) + 1e-12);
+ _c12[1][0] = Lab1[1] * tt;
+ _c12[1][1] = Lab1[2] * tt;
+
+ /* delta chromanance squared */
+ dc = c2 - c1;
+ dcsq = dc * dc;
+ if (c1 < 1e-12 || c2 < 1e-12) {
+ c1 += 1e-12;
+ c2 += 1e-12;
+ }
+ _dcsq[0][0] = -1.0 * Lab0[1] * (c2 - c1)/c1;
+ _dcsq[0][1] = -1.0 * Lab0[2] * (c2 - c1)/c1;
+ _dcsq[1][0] = 1.0 * Lab1[1] * (c2 - c1)/c2;
+ _dcsq[1][1] = 1.0 * Lab1[2] * (c2 - c1)/c2;
+ }
+
+ /* Compute delta hue squared */
+ dhsq = desq - dlsq - dcsq;
+ if (dhsq >= 0.0) {
+ _dhsq[0][0] = _desq[0][1] - _dcsq[0][0];
+ _dhsq[0][1] = _desq[0][2] - _dcsq[0][1];
+ _dhsq[1][0] = _desq[1][1] - _dcsq[1][0];
+ _dhsq[1][1] = _desq[1][2] - _dcsq[1][1];
+ } else {
+ dhsq = 0.0;
+ _dhsq[0][0] = 0.0;
+ _dhsq[0][1] = 0.0;
+ _dhsq[1][0] = 0.0;
+ _dhsq[1][1] = 0.0;
+ }
+
+ {
+ double sc, scsq, scf;
+ double sh, shsq, shf;
+
+ /* Weighting factors for delta chromanance & delta hue */
+ sc = 1.0 + 0.048 * c12;
+ scsq = sc * sc;
+
+ sh = 1.0 + 0.014 * c12;
+ shsq = sh * sh;
+
+ rv = dlsq + dcsq/scsq + dhsq/shsq;
+
+ scf = 0.048 * -1.0 * dcsq/(scsq * sc);
+ shf = 0.014 * -1.0 * dhsq/(shsq * sh);
+ dout[0][0] = _desq[0][0];
+ dout[0][1] = _dcsq[0][0]/scsq + _c12[0][0] * scf
+ + _dhsq[0][0]/shsq + _c12[0][0] * shf;
+ dout[0][2] = _dcsq[0][1]/scsq + _c12[0][1] * scf
+ + _dhsq[0][1]/shsq + _c12[0][1] * shf;
+ dout[1][0] = _desq[1][0];
+ dout[1][1] = _dcsq[1][0]/scsq + _c12[1][0] * scf
+ + _dhsq[1][0]/shsq + _c12[1][0] * shf;
+ dout[1][2] = _dcsq[1][1]/scsq + _c12[1][1] * scf
+ + _dhsq[1][1]/shsq + _c12[1][1] * shf;
+ return sqrt(rv);
+ }
+}
+
+/* ------------------------------------------------------ */
+/* A power-like function, based on Graphics Gems adjustment curve. */
+/* Avoids "toe" problem of pure power. */
+/* Adjusted so that "power" 2 and 0.5 agree with real power at 0.5 */
+
+double icx_powlike(double vv, double pp) {
+ double tt, g;
+
+ if (pp >= 1.0) {
+ g = 2.0 * (pp - 1.0);
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ g = 2.0 - 2.0/pp;
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+
+ return vv;
+}
+
+/* Compute the necessary aproximate power, to transform */
+/* the given value from src to dst. They are assumed to be */
+/* in the range 0.0 .. 1.0 */
+double icx_powlike_needed(double src, double dst) {
+ double pp, g;
+
+ if (dst <= src) {
+ g = -((src - dst)/(dst * src - dst));
+ pp = (0.5 * g) + 1.0;
+ } else {
+ g = -((src - dst)/((dst - 1.0) * src));
+ pp = 1.0/(1.0 - 0.5 * g);
+ }
+
+ return pp;
+}
+
+/* ------------------------------------------------------ */
+/* Parameterized transfer/dot gain function. */
+/* Used for device modelling. Including partial */
+/* derivative for input and parameters. */
+
+/* NOTE that clamping the input values seems to cause */
+/* conjgrad() problems. */
+
+/* Transfer function */
+double icxTransFunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+) {
+ double g;
+ int ord;
+
+ /* Process all the shaper orders from low to high. */
+ /* [These shapers were inspired by a Graphics Gem idea */
+ /* (Gems IV, VI.3, "Fast Alternatives to Perlin's Bias and */
+ /* Gain Functions, pp 401). */
+ /* They have the nice properties that they are smooth, and */
+ /* are monotonic. The control parameter has been */
+ /* altered to have a range from -oo to +oo rather than 0.0 to 1.0 */
+ /* so that the search space is less non-linear. */
+ for (ord = 0; ord < luord; ord++) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ return vv;
+}
+
+/* Inverse transfer function */
+double icxInvTransFunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+) {
+ double g;
+ int ord;
+
+ /* Process the shaper orders in reverse from high to low. */
+ /* [These shapers were inspired by a Graphics Gem idea */
+ /* (Gems IV, VI.3, "Fast Alternatives to Perlin's Bias and */
+ /* Gain Functions, pp 401). */
+ /* They have the nice properties that they are smooth, and */
+ /* are monotonic. The control parameter has been */
+ /* altered to have a range from -oo to +oo rather than 0.0 to 1.0 */
+ /* so that the search space is less non-linear. */
+ for (ord = luord-1; ord >= 0; ord--) {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = -v[ord]; /* Inverse parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ return vv;
+}
+
+/* Transfer function with offset and scale */
+double icxSTransFunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+) {
+ max -= min;
+
+ vv = (vv - min)/max;
+ vv = icxTransFunc(v, luord, vv);
+ vv = (vv * max) + min;
+ return vv;
+}
+
+/* Inverse Transfer function with offset and scale */
+double icxInvSTransFunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+) {
+ max -= min;
+
+ vv = (vv - min)/max;
+ vv = icxInvTransFunc(v, luord, vv);
+ vv = (vv * max) + min;
+ return vv;
+}
+
+/* Transfer function with partial derivative */
+/* with respect to the parameters. */
+double icxdpTransFunc(
+double *v, /* Pointer to first parameter */
+double *dv, /* Return derivative wrt each parameter */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+) {
+ double g;
+ int i, ord;
+
+ /* Process all the shaper orders from high to low. */
+ for (ord = 0; ord < luord; ord++) {
+ double dsv; /* del for del in g */
+ double ddv; /* del for del in vv */
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1) {
+ g = -g; /* Alternate action in each section */
+ }
+ vv -= sec;
+ if (g >= 0.0) {
+ double tt = g - g * vv + 1.0;
+ dsv = (vv * vv - vv)/(tt * tt);
+ ddv = (g + 1.0)/(tt * tt);
+ vv = vv/tt;
+ } else {
+ double tt = 1.0 - g * vv;
+ dsv = (vv * vv - vv)/(tt * tt);
+ ddv = (1.0 - g)/(tt * tt);
+ vv = (vv - g * vv)/tt;
+ }
+
+ vv += sec;
+ vv /= (double)nsec;
+ dsv /= (double)nsec;
+ if (((int)sec) & 1)
+ dsv = -dsv;
+
+ dv[ord] = dsv;
+ for (i = ord - 1; i >= 0; i--)
+ dv[i] *= ddv;
+ }
+
+ return vv;
+}
+
+/* Transfer function with offset and scale, and */
+/* partial derivative with respect to the parameters. */
+double icxdpSTransFunc(
+double *v, /* Pointer to first parameter */
+double *dv, /* Return derivative wrt each parameter */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+) {
+ int i;
+ max -= min;
+
+ vv = (vv - min)/max;
+ vv = icxdpTransFunc(v, dv, luord, vv);
+ vv = (vv * max) + min;
+ for (i = 0; i < luord; i++)
+ dv[i] *= max;
+ return vv;
+}
+
+
+/* Transfer function with partial derivative */
+/* with respect to the input value. */
+double icxdiTransFunc(
+double *v, /* Pointer to first parameter */
+double *pdin, /* Return derivative wrt source value */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+) {
+ double g, din;
+ int ord;
+
+#ifdef NEVER
+ if (vv < 0.0 || vv > 1.0) {
+ if (vv < 0.0)
+ vv = 0.0;
+ else
+ vv = 1.0;
+
+ *pdin = 0.0;
+ return vv;
+ }
+#endif
+ din = 1.0;
+
+ /* Process all the shaper orders from high to low. */
+ for (ord = 0; ord < luord; ord++) {
+ double ddv; /* del for del in vv */
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1) {
+ g = -g; /* Alternate action in each section */
+ }
+ vv -= sec;
+ if (g >= 0.0) {
+ double tt = g - g * vv + 1.0;
+ ddv = (g + 1.0)/(tt * tt);
+ vv = vv/tt;
+ } else {
+ double tt = 1.0 - g * vv;
+ ddv = (1.0 - g)/(tt * tt);
+ vv = (vv - g * vv)/tt;
+ }
+
+ vv += sec;
+ vv /= (double)nsec;
+ din *= ddv;
+ }
+
+ *pdin = din;
+ return vv;
+}
+
+/* Transfer function with offset and scale, and */
+/* partial derivative with respect to the input value. */
+double icxdiSTransFunc(
+double *v, /* Pointer to first parameter */
+double *pdv, /* Return derivative wrt source value */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+) {
+ max -= min;
+
+ vv = (vv - min)/max;
+ vv = icxdiTransFunc(v, pdv, luord, vv);
+ vv = (vv * max) + min;
+ return vv;
+}
+
+
+/* Transfer function with partial derivative */
+/* with respect to the parameters and the input value. */
+double icxdpdiTransFunc(
+double *v, /* Pointer to first parameter */
+double *dv, /* Return derivative wrt each parameter */
+double *pdin, /* Return derivative wrt source value */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+) {
+ double g, din;
+ int i, ord;
+
+#ifdef NEVER
+ if (vv < 0.0 || vv > 1.0) {
+ if (vv < 0.0)
+ vv = 0.0;
+ else
+ vv = 1.0;
+
+ for (ord = 0; ord < luord; ord++)
+ dv[ord] = 0.0;
+ *pdin = 0.0;
+ return vv;
+ }
+#endif
+ din = 1.0;
+
+ /* Process all the shaper orders from high to low. */
+ for (ord = 0; ord < luord; ord++) {
+ double dsv; /* del for del in g */
+ double ddv; /* del for del in vv */
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+
+ g = v[ord]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1) {
+ g = -g; /* Alternate action in each section */
+ }
+ vv -= sec;
+ if (g >= 0.0) {
+ double tt = g - g * vv + 1.0;
+ dsv = (vv * vv - vv)/(tt * tt);
+ ddv = (g + 1.0)/(tt * tt);
+ vv = vv/tt;
+ } else {
+ double tt = 1.0 - g * vv;
+ dsv = (vv * vv - vv)/(tt * tt);
+ ddv = (1.0 - g)/(tt * tt);
+ vv = (vv - g * vv)/tt;
+ }
+
+ vv += sec;
+ vv /= (double)nsec;
+ dsv /= (double)nsec;
+ if (((int)sec) & 1)
+ dsv = -dsv;
+
+ dv[ord] = dsv;
+ for (i = ord - 1; i >= 0; i--)
+ dv[i] *= ddv;
+ din *= ddv;
+ }
+
+ *pdin = din;
+ return vv;
+}
+
+/* Transfer function with offset and scale, and */
+/* partial derivative with respect to the */
+/* parameters and the input value. */
+double icxdpdiSTransFunc(
+double *v, /* Pointer to first parameter */
+double *dv, /* Return derivative wrt each parameter */
+double *pdin, /* Return derivative wrt source value */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+) {
+ int i;
+ max -= min;
+
+ vv = (vv - min)/max;
+ vv = icxdpdiTransFunc(v, dv, pdin, luord, vv);
+ vv = (vv * max) + min;
+ for (i = 0; i < luord; i++)
+ dv[i] *= max;
+ return vv;
+}
+
+/* ------------------------------------------------------ */
+/* Multi-plane interpolation, used for device modelling. */
+/* Including partial derivative for input and parameters. */
+/* A simple flat plane is used for each output. */
+
+/* Multi-plane interpolation - uses base + di slope values. */
+/* Parameters are assumed to be fdi groups of di + 1 parameters. */
+void icxPlaneInterp(
+double *v, /* Pointer to first parameter [fdi * (di + 1)] */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+) {
+ int e, f;
+
+ for (f = 0; f < fdi; f++) {
+ for (out[f] = 0.0, e = 0; e < di; e++, v++) {
+ out[f] += in[e] * *v;
+ }
+ out[f] += *v;
+ }
+}
+
+
+/* Multii-plane interpolation with partial derivative */
+/* with respect to the input and parameters. */
+void icxdpdiPlaneInterp(
+double *v, /* Pointer to first parameter value [fdi * (di + 1)] */
+double *dv, /* Return [1 + di] deriv. wrt each parameter v */
+double *din, /* Return [fdi * di] deriv. wrt each input value */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+) {
+ int e, ee, f, g;
+ int dip2 = (di + 1); /* Output dim increment through parameters */
+
+ /* Compute the output values */
+ for (f = 0; f < fdi; f++) {
+ for (out[f] = 0.0, e = 0; e < di; e++)
+ out[f] += in[e] * v[f * dip2 + e];
+ out[f] += v[f * dip2 + e];
+ }
+
+ /* Since interpolation is verys simple, derivative are also simple */
+
+ /* Copy del for parameter to return array */
+ for (e = 0; e < di; e++)
+ dv[e] = in[e];
+ dv[e] = 1.0;
+
+ /* Compute del of out[] from in[] */
+ for (f = 0; f < fdi; f++) {
+ for (e = 0; e < di; e++) {
+ din[f * di + e] = v[f * dip2 + e];
+ }
+ }
+}
+
+/* ------------------------------------------------------ */
+/* Matrix cube interpolation, used for device modelling. */
+/* Including partial derivative for input and parameters. */
+
+/* Matrix cube interpolation - interpolate between 2^di output corner values. */
+/* Parameters are assumed to be fdi groups of 2^di parameters. */
+void icxCubeInterp(
+double *v, /* Pointer to first parameter */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+) {
+ int e, f, g;
+ double gw[1 << MXDI]; /* weight for each matrix grid cube corner */
+
+ /* Compute corner weights needed for interpolation */
+ gw[0] = 1.0;
+ for (e = 0, g = 1; e < di; e++, g *= 2) {
+ int i;
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * in[e];
+ gw[i] *= (1.0 - in[e]);
+ }
+ }
+
+ /* Now compute the output values */
+ for (f = 0; f < fdi; f++) {
+ out[f] = 0.0; /* For each output value */
+ for (e = 0; e < (1 << di); e++) { /* For all corners of cube */
+ out[f] += gw[e] * *v;
+ v++;
+ }
+ }
+}
+
+
+/* Matrix cube interpolation. with partial derivative */
+/* with respect to the input and parameters. */
+void icxdpdiCubeInterp(
+double *v, /* Pointer to first parameter value [fdi * 2^di] */
+double *dv, /* Return [2^di] deriv. wrt each parameter v */
+double *din, /* Return [fdi * di] deriv. wrt each input value */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+) {
+ int e, ee, f, g;
+ int dip2 = (1 << di);
+ double gw[1 << MXDI]; /* weight for each matrix grid cube corner */
+
+ /* Compute corner weights needed for interpolation */
+ gw[0] = 1.0;
+ for (e = 0, g = 1; e < di; e++, g *= 2) {
+ int i;
+ for (i = 0; i < g; i++) {
+ gw[g+i] = gw[i] * in[e];
+ gw[i] *= (1.0 - in[e]);
+ }
+ }
+
+ /* Now compute the output values */
+ for (f = 0; f < fdi; f++) {
+ out[f] = 0.0; /* For each output value */
+ for (ee = 0; ee < dip2; ee++) { /* For all corners of cube */
+ out[f] += gw[ee] * v[f * dip2 + ee];
+ }
+ }
+
+ /* Copy del for parameter to return array */
+ for (ee = 0; ee < dip2; ee++) { /* For all other corners of cube */
+ dv[ee] = gw[ee]; /* del from parameter */
+ }
+
+ /* Compute del from in[] value we want */
+ for (e = 0; e < di; e++) { /* For input we want del wrt */
+
+ for (f = 0; f < fdi; f++)
+ din[f * di + e] = 0.0; /* Zero del ready of accumulation */
+
+ for (ee = 0; ee < dip2; ee++) { /* For all corners of cube weights, */
+ int e2; /* accumulate del from in[] we want. */
+ double vv = 1.0;
+
+ /* Compute in[] weighted cube corners for all except del of in[] we want */
+ for (e2 = 0; e2 < di; e2++) { /* const from non del inputs */
+ if (e2 == e)
+ continue;
+ if (ee & (1 << e2))
+ vv *= in[e2];
+ else
+ vv *= (1.0 - in[e2]);
+ }
+
+ /* Accumulate contribution of in[] we want for corner to out[] we want */
+ if (ee & (1 << e)) {
+ for (f = 0; f < fdi; f++)
+ din[f * di + e] += v[f * dip2 + ee] * vv;
+ } else {
+ for (f = 0; f < fdi; f++)
+ din[f * di + e] -= v[f * dip2 + ee] * vv;
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------ */
+/* Matrix cube simplex interpolation, used for device modelling. */
+
+/* Matrix cube simplex interpolation - interpolate between 2^di output corner values. */
+/* Parameters are assumed to be fdi groups of 2^di parameters. */
+void icxCubeSxInterp(
+double *v, /* Pointer to first parameter */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+) {
+ int si[MAX_CHAN]; /* in[] Sort index, [0] = smalest */
+
+//{
+// double tout[MXDO];
+//
+// icxCubeInterp(v, fdi, di, tout, in);
+//printf("\n~1 Cube interp result = %f\n",tout[0]);
+//}
+
+//printf("~1 icxCubeSxInterp: %f %f %f\n", in[0], in[1], in[2]);
+ /* Do insertion sort on coordinates, smallest to largest. */
+ {
+ int ff, vf;
+ unsigned int e;
+ double v;
+ for (e = 0; e < di; e++)
+ si[e] = e; /* Initial unsorted indexes */
+
+ for (e = 1; e < di; e++) {
+ ff = e;
+ v = in[si[ff]];
+ vf = ff;
+ while (ff > 0 && in[si[ff-1]] > v) {
+ si[ff] = si[ff-1];
+ ff--;
+ }
+ si[ff] = vf;
+ }
+ }
+//printf("~1 sort order %d %d %d\n", si[0], si[1], si[2]);
+//printf(" from %f %f %f\n", in[si[0]], in[si[1]], in[si[2]]);
+
+ /* Now compute the weightings, simplex vertices and output values */
+ {
+ unsigned int e, f;
+ double w; /* Current vertex weight */
+
+ w = 1.0 - in[si[di-1]]; /* Vertex at base of cell */
+ for (f = 0; f < fdi; f++) {
+ out[f] = w * v[f * (1 << di)];
+//printf("~1 out[%d] = %f = %f * %f\n",f,out[f],w,v[f * (1 << di)]);
+ }
+
+ for (e = di-1; e > 0; e--) { /* Middle verticies */
+ w = in[si[e]] - in[si[e-1]];
+ v += (1 << si[e]); /* Move to top of cell in next largest dimension */
+ for (f = 0; f < fdi; f++) {
+ out[f] += w * v[f * (1 << di)];
+//printf("~1 out[%d] = %f += %f * %f\n",f,out[f],w,v[f * (1 << di)]);
+ }
+ }
+
+ w = in[si[0]];
+ v += (1 << si[0]); /* Far corner from base of cell */
+ for (f = 0; f < fdi; f++) {
+ out[f] += w * v[f * (1 << di)];
+//printf("~1 out[%d] = %f += %f * %f\n",f,out[f],w,v[f * (1 << di)]);
+ }
+ }
+}
+
+/* ------------------------------------------------------ */
+/* Matrix multiplication, used for device modelling. */
+/* Including partial derivative for input and parameters. */
+
+
+/* 3x3 matrix multiplication, with the matrix in a 1D array */
+/* with respect to the input and parameters. */
+void icxMulBy3x3Parm(
+ double out[3], /* Return input multiplied by matrix */
+ double mat[9], /* Matrix organised in [slow][fast] order */
+ double in[3] /* Input values */
+) {
+ double *v = mat, ov[3];
+ int e, f;
+
+ /* Compute the output values */
+ for (f = 0; f < 3; f++) {
+ ov[f] = 0.0; /* For each output value */
+ for (e = 0; e < 3; e++) {
+ ov[f] += *v++ * in[e];
+ }
+ }
+ out[0] = ov[0];
+ out[1] = ov[1];
+ out[2] = ov[2];
+}
+
+
+/* 3x3 matrix multiplication, with partial derivatives */
+/* with respect to the input and parameters. */
+void icxdpdiMulBy3x3Parm(
+ double out[3], /* Return input multiplied by matrix */
+ double dv[3][9], /* Return deriv for each [output] with respect to [param] */
+ double din[3][3], /* Return deriv for each [output] with respect to [input] */
+ double mat[9], /* Matrix organised in [slow][fast] order */
+ double in[3] /* Input values */
+) {
+ double *v, ov[3];
+ int e, f;
+
+ /* Compute the output values */
+ v = mat;
+ for (f = 0; f < 3; f++) {
+ ov[f] = 0.0; /* For each output value */
+ for (e = 0; e < 3; e++) {
+ ov[f] += *v++ * in[e];
+ }
+ }
+
+ /* Compute deriv. with respect to the matrix parameter % 3 */
+ /* This is pretty simple for a matrix ... */
+ for (f = 0; f < 3; f++) {
+ for (e = 0; e < 9; e++) {
+ if (e/3 == f)
+ dv[f][e] = in[e % 3];
+ else
+ dv[f][e] = 0.0;
+ }
+ }
+
+ /* Compute deriv. with respect to the input values */
+ /* This is pretty simple for a matrix ... */
+ v = mat;
+ for (f = 0; f < 3; f++)
+ for (e = 0; e < 3; e++)
+ din[f][e] = *v++;
+
+ out[0] = ov[0];
+ out[1] = ov[1];
+ out[2] = ov[2];
+}
+
+#undef stricmp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xicc.h b/xicc/xicc.h
new file mode 100644
index 0000000..3969ebe
--- /dev/null
+++ b/xicc/xicc.h
@@ -0,0 +1,945 @@
+#ifndef XICC_H
+#define XICC_H
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/6/00
+ * Version: 1.00
+ *
+ * Copyright 2000, 2011 Graeme W. Gill
+ * All rights reserved.
+ * This material is licenced under the GNU AFFERO GENERAL PUB LICENSE Version 3 :-
+ * see the License.txt file for licencing details.
+ *
+ * Based on the old iccXfm class.
+ */
+
+/*
+ * This library expands the icclib functionality,
+ * particularly in creating and exercising color transforms.
+ *
+ * For the moment, this support is concentrated around the
+ * Lut and Matrix subsets of the ICC profile tranforms.
+ *
+ * It is intended to allow color transformation, storage and retrieval
+ * of ICC profiles, while permitting inititialization from scattered
+ * data, reversing of the transform, and specific manipulations of
+ * the internal processing elements.
+ *
+ * This class bases much of it's functionality on that of the
+ * underlying icclib icmLuBase.
+ */
+
+#include "icc.h" /* icclib ICC definitions */
+#include "cgats.h" /* CGAT format */
+#include "rspl.h" /* rspllib thin plate spline definitions */
+#include "gamut.h" /* gamut definitions */
+#include "xutils.h" /* Utility functions */
+#include "xcam.h" /* CAM definitions */
+#include "xspect.h" /* Spectral conversion object */
+#include "xcolorants.h" /* Known colorants support */
+#include "insttypes.h" /* Instrument type support */
+#include "mpp.h" /* model printer profile support */
+#include "moncurve.h" /* monotonic curve support */
+ /* (more at the end) */
+
+#define XICC_USE_HK 1 /* [Set] Set to 1 to use Helmholtz-Kohlraush in all CAM conversions */
+#define XICC_NEUTRAL_CMYK_BLACK /* Use neutral axis black, else use K direction black. */
+#define XICC_BLACK_POINT_TOLL 0.5 /* Tollerance of CMYK black point location */
+#define XICC_BLACK_FIND_ABERR_WEIGHT 10.0 /* Weight of ab error against min L in BP */
+
+/* ------------------------------------------------------------------------------ */
+
+/* The "effective" PCS colorspace is the one specified by the PCS override, and */
+/* visible in the overal profile conversion. The "native" PCS colorspace is the one */
+/* that the underlying tags actually represent, and the PCS that the individual */
+/* stages within each profile type handle (unless the ICX_MERGED flag is set, in which */
+/* case the clut == native PCS appears to be the effective one). The conversion between */
+/* the native and effective PCS is generally done in the to/from_abs() conversions. */
+
+/* ------------------------------------------------------------------------------ */
+
+/* Pseudo intents, valid as parameter to xicc get_luobj(): */
+
+/* Default Color Appearance Space, based on absolute colorimetric */
+#define icxAppearance ((icRenderingIntent)994)
+
+/* Represents icAbsoluteColorimetric, converted to Color Appearance space */
+#define icxAbsAppearance ((icRenderingIntent)995) /* Fixed D50 white point */
+
+/* Special Color Appearance Space, based on "absolute" perceptual */
+#define icxPerceptualAppearance ((icRenderingIntent)996)
+
+/* Default Color Appearance Space, based on "absolute" saturation */
+#define icxSaturationAppearance ((icRenderingIntent)997)
+
+/* These two are for completeness, they are unlikely to be useful: */
+/* Special Color Appearance Space, based on "absolute" perceptual */
+#define icxAbsPerceptualAppearance ((icRenderingIntent)998)
+
+/* Default Color Appearance Space, based on "absolute" saturation */
+#define icxAbsSaturationAppearance ((icRenderingIntent)999)
+
+
+/* Pseudo PCS colospace returned as PCS for intent icxAppearanceJab */
+#define icxSigJabData ((icColorSpaceSignature) icmMakeTag('J','a','b',' '))
+
+/* Pseudo PCS colospace returned as PCS for intent icxAppearanceJCh */
+#define icxSigJChData ((icColorSpaceSignature) icmMakeTag('J','C','h',' '))
+
+/* Pseudo PCS colospace returned as PCS */
+#define icxSigLChData ((icColorSpaceSignature) icmMakeTag('L','C','h',' '))
+
+/* Return a string description of the given enumeration value */
+const char *icx2str(icmEnumType etype, int enumval);
+
+
+/* ------------------------------------------------------------------------------ */
+
+/* A 3x3 matrix model */
+struct _icxMatrixModel {
+ void *imp; /* Opaque implementation */
+
+ int isLab; /* Convert lookup to Lab */
+
+ void (*force) (struct _icxMatrixModel *p, double *targ, double *in);
+ void (*lookup) (struct _icxMatrixModel *p, double *out, double *in);
+ void (*del) (struct _icxMatrixModel *p);
+
+}; typedef struct _icxMatrixModel icxMatrixModel;
+
+/* Create a matrix model of a set of points, and return an object to lookup */
+/* points from the model. Return NULL on error. */
+icxMatrixModel *new_MatrixModel(
+int verb, /* NZ if verbose */
+int nodp, /* Number of points */
+cow *ipoints, /* Array of input points in XYZ space */
+int isLab, /* nz if data points are Lab */
+int quality, /* Quality metric, 0..3 (-1 == 2 orders only) */
+int isLinear, /* NZ if pure linear, gamma = 1.0 */
+int isGamma, /* NZ if gamma rather than shaper */
+int isShTRC, /* NZ if shared TRCs */
+int shape0gam, /* NZ if zero'th order shaper should be gamma function */
+int clipbw, /* Prevent white > 1 and -ve black */
+int clipprims, /* Prevent primaries going -ve */
+double smooth, /* Smoothing factor (nominal 1.0) */
+double scale /* Scale device values */
+);
+
+/* ------------------------------------------------------------------------------ */
+/* Basic class keeps extra state for an icc, and provides the */
+/* expanded set of methods. */
+
+/* Black generation rule */
+/* The rule is all in terms of device K and L* values */
+typedef enum {
+ icxKvalue = 0, /* K is specified as output K target by PCS auxiliary */
+ icxKlocus = 1, /* K is specified as proportion of K locus by PCS auxiliary */
+ icxKluma5 = 2, /* K is specified as locus by 5 parameters as a function of L */
+ icxKluma5k = 3, /* K is specified as K value by 5 parameters as a function of L */
+ icxKl5l = 4, /* K is specified as locus by 2x5 parameters as a function of L and K locus aux */
+ icxKl5lk = 5 /* K is specified as K value by 2x5 parameters as a function of L and K value aux */
+} icxKrule;
+
+/* Curve parameters */
+typedef struct {
+ double Ksmth; /* K smoothing filter extent */
+ double Kstle; /* K start level at white end (0.0 - 1.0)*/
+ double Kstpo; /* K start point as prop. of L locus (0.0 - 1.0) */
+ double Kenpo; /* K end point as prop. of L locus (0.0 - 1.0) */
+ double Kenle; /* K end level at Black end (0.0 - 1.0) */
+ double Kshap; /* K transition shape, 0.0-1.0 concave, 1.0-2.0 convex */
+ double Kskew; /* K transition shape skew, 1.0 = even */
+} icxInkCurve;
+
+/* Default black generation smoothing value */
+#define ICXINKDEFSMTH 0.09 /* Transition window of +/- ICXINKDEFSMTH */
+#define ICXINKDEFSKEW 2.0 /* Curve shape skew (matches typical device behaviour) */
+
+/* Structure to convey inking details */
+typedef struct {
+ double tlimit; /* Total ink limit, > 0.0 to < inputChan, < 0.0 == off */
+ double klimit; /* Black limit, > 0.0 to < 1.0, < 0.0 == off */
+ icxKrule k_rule; /* type of K generation rule */
+ int KonlyLmin; /* Use K only black Locus Lmin */
+ icxInkCurve c; /* K curve, or locus minimum curve */
+ icxInkCurve x; /* locus maximum curve if icxKl5l */
+} icxInk;
+
+/* Structure to convey inverse lookup clip handling details */
+struct _icxClip {
+ int nearclip; /* Flag - use near clipping not vector */
+ int LabLike; /* Flag Its an Lab like colorspace */
+ int fdi; /* Dimentionality of clip vector */
+ double ocent[MXDO]; /* base of center of clut output gamut */
+ double ocentv[MXDO]; /* vector direction of clut output clip target line */
+ double ocentl; /* clip target line length */
+}; typedef struct _icxClip icxClip;
+
+/* Structure to convey viewing conditions */
+typedef struct {
+ ViewingCondition Ev;/* Enumerated Viewing Condition */
+ double Wxyz[3]; /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
+ double La; /* Adapting/Surround Luminance cd/m^2 */
+ double Yb; /* Relative Luminance of Background to reference white */
+ double Lv; /* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
+ /* Ignored if Ev is set to other than vc_none */
+ double Yf; /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
+ double Fxyz[3]; /* The Flare white coordinates (typically the Ambient color) */
+ /* Will be taken from Wxyz if Fxyz == 0.0 */
+ char *desc; /* Possible description of this VC */
+} icxViewCond;
+
+/* Structure to convey gamut mapping intent */
+typedef struct {
+ int usecas; /* 0x0 Use Lab space */
+ /* 0x1 Use Color Appearance Space */
+ /* 0x2 Use Absolute Color Appearance Space */
+ /* 0x101 Use Color Appearance Space with luminence scaling */
+ int usemap; /* NZ if Gamut mapping should be used, else clip */
+ double greymf; /* Grey axis hue matching factor, 0.0 - 1.0 */
+ double glumwcpf; /* Grey axis luminance white compression factor, 0.0 - 1.0 */
+ double glumwexf; /* Grey axis luminance white expansion factor, 0.0 - 1.0 */
+ double glumbcpf; /* Grey axis luminance black compression factor, 0.0 - 1.0 */
+ double glumbexf; /* Grey axis luminance black expansion factor, 0.0 - 1.0 */
+ double glumknf; /* Grey axis luminance knee factor, 0.0 - 1.0 */
+ double gamcpf; /* Gamut compression factor, 0.0 - 1.0 */
+ double gamexf; /* Gamut expansion factor, 0.0 - 1.0 */
+ double gamcknf; /* Gamut compression knee factor, 0.0 - 1.0 */
+ double gamxknf; /* Gamut expansion knee factor, 0.0 - 1.0 */
+ double gampwf; /* Gamut Perceptual Map weighting factor, 0.0 - 1.0 */
+ double gamswf; /* Gamut Saturation Map weighting factor, 0.0 - 1.0 */
+ double satenh; /* Saturation enhancement value, 0.0 - Inf */
+ char *as; /* Alias string (option name) */
+ char *desc; /* Possible description of this VC */
+ icRenderingIntent icci; /* Closest ICC intent */
+} icxGMappingIntent;
+
+struct _xicc {
+ /* Private: */
+ icc *pp; /* ICC profile we expand */
+
+ struct _xcal *cal; /* Optional device cal, NULL if none */
+ int nodel_cal; /* Flag, nz if cal was provided externally and shouldn't be deleted */
+
+ /* Public: */
+ void (*del)(struct _xicc *p);
+
+ /* "use" flags */
+#define ICX_CLIP_VECTOR 0x0000 /* If clipping is needed, clip in vector direction (default) */
+#define ICX_CLIP_NEAREST 0x0010 /* If clipping is needed, clip to nearest */
+#define ICX_MERGE_CLUT 0x0020 /* Merge the output() and out_abs() into the clut(), */
+ /* for improved performance on reading, and */
+ /* clipping in effective output space on inverse lookup. */
+ /* Reduces accuracy noticably though. */
+ /* Output output() and out_abs() become NOPs */
+#define ICX_CAM_CLIP 0x0100 /* Use CAM space during invfwd clipping lookup, */
+ /* irrespective of the native or effective PCS. */
+ /* Ignored if MERGE_CLUT is set or vector clip is used. */
+ /* May halve the inverse lookup performance! */
+#define ICX_INT_SEPARATE 0x0400 /* Handle 4 dimensional devices with fixed inking rules */
+ /* with an optimised internal separation pass, rather */
+ /* than a point by point inverse locus lookup . */
+ /* NOT IMPLEMENTED YET */
+#define ICX_FAST_SETUP 0x0800 /* Improve initial setup speed at the cost of throughput */
+#define ICX_VERBOSE 0x8000 /* Turn on verboseness during creation */
+
+ /* Returm a lookup object from the icc */
+ struct _icxLuBase * (*get_luobj) (struct _xicc *p,
+ int flags, /* clip, merge flags */
+ icmLookupFunc func, /* Functionality */
+ icRenderingIntent intent,/* Intent */
+ icColorSpaceSignature pcsor, /* PCS override (0 = def) */
+ icmLookupOrder order, /* Search Order */
+ icxViewCond *vc, /* Viewing Condition - only */
+ /* used if pcsor == CIECAM. */
+ /* or ICX_CAM_CLIP flag. */
+ icxInk *ink); /* inking details (NULL = def) */
+
+
+ /* Set a xluobj and icc table from scattered data */
+ /* Return appropriate lookup object */
+ /* NULL on error, check errc+err for reason */
+ /* "create" flags */
+#define ICX_SET_WHITE 0x00010000 /* find, set and make relative to the white point */
+#define ICX_SET_WHITE_US 0x00030000 /* find, set and make relative to the white point hue, */
+ /* but not scale to W L value, to avoid input clipping */
+#define ICX_SET_WHITE_C 0x00050000 /* find, set and make relative to the white point hue, */
+ /* and clip any cLUT values over D50 to D50 */
+#define ICX_SET_BLACK 0x00080000 /* find and set the black point */
+#define ICX_WRITE_WBL 0x00100000 /* Matrix: write White, Black & Luminance tags */
+#define ICX_CLIP_WB 0x00200000 /* Clip white and black to be < 1 and > 0 respectively */
+#define ICX_CLIP_PRIMS 0x00400000 /* Clip matrix primaries to be > 0 */
+#define ICX_NO_IN_SHP_LUTS 0x00800000 /* Lut/Mtx: Don't create input (Device) shaper curves. */
+#define ICX_NO_IN_POS_LUTS 0x01000000 /* LuLut: Don't create input (Device) postion curves. */
+#define ICX_NO_OUT_LUTS 0x02000000 /* LuLut: Don't create output (PCS) curves. */
+//#define ICX_2PASSSMTH 0x04000000 /* If LuLut: Use Gaussian smoothing */
+//#define ICX_EXTRA_FIT 0x08000000 /* If LuLut: Counteract scat data point errors. */
+/* And ICX_VERBOSE Turn on verboseness during creation */
+ struct _icxLuBase * (*set_luobj) (struct _xicc *p,
+ icmLookupFunc func, /* Functionality to set */
+ icRenderingIntent intent, /* Intent to set */
+ icmLookupOrder order, /* Search Order */
+ int flags, /* white/black point flags */
+ int no, /* Total Number of points */
+ int nobw, /* Number of points to look */
+ /* for white & black patches in */
+ cow *points, /* Array of input points */
+ icxMatrixModel *skm, /* Optional skeleton model */
+ double dispLuminance, /* > 0.0 if display luminance */
+ /* value and is known */
+ double wpscale, /* > 0.0 if input white pt is */
+ /* is to be scaled */
+ double smooth, /* RSPL smoothing factor, */
+ /* -ve if raw */
+ double avgdev, /* Avge Dev. of points */
+ icxViewCond *vc, /* Viewing Condition - only */
+ /* used if pcsor == CIECAM. */
+ /* or ICX_CAM_CLIP flag. */
+ icxInk *ink, /* inking details */
+ struct _xcal *cal, /* Optional cal Will override any */
+ /* existing, not deltd with xicc. */
+ int quality); /* Quality metric, 0..3 */
+
+
+ /* Return the devices viewing conditions. */
+ /* Return value 0 if it is well defined */
+ /* Return value 1 if it is a guess */
+ /* Return value 2 if it is not possible/appropriate */
+ int (*get_viewcond)(struct _xicc *p, icxViewCond *vc);
+
+ char err[512]; /* Error message */
+ int errc; /* Error code */
+}; typedef struct _xicc xicc;
+
+/* ~~~~~ */
+/* Might be good to add a slow but very precise vector and closest "clip to gamut" */
+/* function for use in setting white and black points. Use this in profile. */
+
+xicc *new_xicc(icc *picc);
+
+/* ------------------------------------------------------------------------------ */
+/* Expanded lookup object support */
+#define XLU_BASE_MEMBERS \
+ /* Private: */ \
+ int trace; /* Optional run time tracing flag */ \
+ struct _xicc *pp; /* Pointer to XICC we're a part of */ \
+ icmLuBase *plu; /* Pointer to icm Lu we are expanding */ \
+ int flags; /* Flags passed to get_luobj */ \
+ icmLookupFunc func; /* Function passed to get_luobj */ \
+ icRenderingIntent intent; /* Effective/External Intent */ \
+ /* "in" and "out" are in reference to */ \
+ /* the requested lookup direction. */ \
+ icColorSpaceSignature ins; /* Effective/External Clr space of input */ \
+ icColorSpaceSignature outs; /* Effective/External Clr space of output */\
+ icColorSpaceSignature pcs; /* Effective/External PCS */ \
+ icColorSpaceSignature natis; /* Native input Clr space */ \
+ icColorSpaceSignature natos; /* Native output Clr space */ \
+ icColorSpaceSignature natpcs; /* Native PCS Clr space */ \
+ int inputChan; /* Num of input channels */ \
+ int outputChan; /* Num of output channels */ \
+ double ninmin[MXDI]; /* icc Native Input color space minimum */ \
+ double ninmax[MXDI]; /* icc Native Input color space maximum */ \
+ double noutmin[MXDO]; /* icc Native Output color space minimum */ \
+ double noutmax[MXDO]; /* icc Native Output color space maximum */ \
+ double inmin[MXDI]; /* icx Effective Input color space minimum */ \
+ double inmax[MXDI]; /* icx Effective Input color space maximum */ \
+ double outmin[MXDO]; /* icx Effective Output color space minimum */ \
+ double outmax[MXDO]; /* icx Effective Output color space maximum */ \
+ icxViewCond vc; /* Viewing Condition for CIECAM97s */ \
+ icxcam *cam; /* CAM conversion */ \
+ \
+ /* Attributes inhereted by ixcLu's */ \
+ int noisluts; /* Flag - If LuLut: Don't create input (Device) shaper curves. */ \
+ int noipluts; /* Flag - If LuLut: Don't create input (Device) position curves. */ \
+ int nooluts; /* Flag - If LuLut: Don't create output (PCS) curves. */ \
+ int nearclip; /* Flag - If clipping occurs, return the nearest solution, */ \
+ int mergeclut; /* Flag - If LuLut: Merge output() and out_abs() into clut(). */ \
+ int camclip; /* Flag - If LuLut: Use CIECAM for clut reverse lookup clipping */ \
+ int intsep; /* Flag - If LuLut: Do internal separation for 4d device */ \
+ int fastsetup; /* Flag - If LuLut: Do fast setup at cost of slower throughput */ \
+ \
+ /* Public: */ \
+ void (*del)(struct _icxLuBase *p); \
+ \
+ /* Return Internal native colorspaces */ \
+ void (*lutspaces) (struct _icxLuBase *p, icColorSpaceSignature *ins, int *inn, \
+ icColorSpaceSignature *outs, int *outn, \
+ icColorSpaceSignature *pcs); \
+ \
+ /* External effective colorspaces */ \
+ void (*spaces) (struct _icxLuBase *p, icColorSpaceSignature *ins, int *inn, \
+ icColorSpaceSignature *outs, int *outn, \
+ icmLuAlgType *alg, icRenderingIntent *intt, \
+ icmLookupFunc *fnc, icColorSpaceSignature *pcs); \
+ \
+ /* Get the Native input space and output space ranges */ \
+ void (*get_native_ranges) (struct _icxLuBase *p, \
+ double *inmin, double *inmax, /* Maximum range of inspace values */ \
+ double *outmin, double *outmax); /* Maximum range of outspace values */ \
+ \
+ \
+ /* Get the Effective input space and output space ranges */ \
+ void (*get_ranges) (struct _icxLuBase *p, \
+ double *inmin, double *inmax, /* Maximum range of inspace values */ \
+ double *outmin, double *outmax); /* Maximum range of outspace values */ \
+ \
+ \
+ /* Return the media white and black points */ \
+ /* in the effective PCS colorspace. */ \
+ /* (ie. these will be relative values for relative intent etc.) */ \
+ void (*efv_wh_bk_points)(struct _icxLuBase *p, double *wht, double *blk, double *kblk); \
+ \
+ /* Translate color values through profile */ \
+ /* 0 = success */ \
+ /* 1 = warning: clipping occured */ \
+ /* 2 = fatal: other error */ \
+ \
+ /* (Note that clipping is not a reliable means of detecting out of gamut in the */ \
+ /* lookup(bwd) call for clut based profiles, but is for inv_lookup() calls.) */ \
+ \
+ int (*lookup) (struct _icxLuBase *p, double *out, double *in); \
+ /* Requested conversion */ \
+ int (*inv_lookup) (struct _icxLuBase *p, double *out, double *in); \
+ /* Inverse conversion */ \
+ \
+ /* Given an xicc lookup object, returm a gamut object. */ \
+ /* Note that the Effective PCS must be Lab or Jab */ \
+ /* A icxLuLut type must be icmFwd or icmBwd, */ \
+ /* and for icmFwd, the ink limit (if supplied) */ \
+ /* will be applied. */ \
+ /* Return NULL on error, check xicc errc+err for reason */ \
+ gamut * (*get_gamut) (struct _icxLuBase *plu, /* xicc lookup object */ \
+ double detail); /* gamut detail level, 0.0 = def */ \
+ \
+ /* The following two functions expose the relative colorimetric native ICC PCS */ \
+ /* <--> absolute/CAM space transform, so that CAM based gamut compression */ \
+ /* can be applied in creating the ICC Lut tabls in profout.c. */ \
+ \
+ /* Given a native ICC relative XYZ or Lab PCS value, convert in the fwd */ \
+ /* direction into the nominated Effective output PCS (ie. Absolute, Jab etc.) */ \
+ void (*fwd_relpcs_outpcs) (struct _icxLuBase *p, icColorSpaceSignature is, \
+ double *out, double *in); \
+ \
+ /* Given a nominated Effective output PCS (ie. Absolute, Jab etc.), convert it */ \
+ /* in the bwd direction into a native ICC relative XYZ or Lab PCS value */ \
+ void (*bwd_outpcs_relpcs) (struct _icxLuBase *p, icColorSpaceSignature os, \
+ double *out, double *in); \
+ \
+
+
+/* Base xlookup object */
+struct _icxLuBase {
+ XLU_BASE_MEMBERS
+}; typedef struct _icxLuBase icxLuBase;
+
+/* Monochrome Fwd & Bwd type object */
+struct _icxLuMono {
+ XLU_BASE_MEMBERS
+
+ /* Overall lookups */
+ int (*fwd_lookup) (struct _icxLuBase *p, double *out, double *in);
+ int (*bwd_lookup) (struct _icxLuBase *p, double *out, double *in);
+
+ /* Components of Device to PCS lookup */
+ int (*fwd_curve) (struct _icxLuMono *p, double *out, double *in);
+ int (*fwd_map) (struct _icxLuMono *p, double *out, double *in);
+ int (*fwd_abs) (struct _icxLuMono *p, double *out, double *in);
+
+ /* Components of PCS to Device lookup */
+ int (*bwd_abs) (struct _icxLuMono *p, double *out, double *in);
+ int (*bwd_map) (struct _icxLuMono *p, double *out, double *in);
+ int (*bwd_curve) (struct _icxLuMono *p, double *out, double *in);
+
+}; typedef struct _icxLuMono icxLuMono;
+
+/* 3D Matrix Fwd & Bwd type object */
+struct _icxLuMatrix {
+ XLU_BASE_MEMBERS
+
+ /* Overall lookups */
+ int (*fwd_lookup) (struct _icxLuBase *p, double *out, double *in);
+ int (*bwd_lookup) (struct _icxLuBase *p, double *out, double *in);
+
+ /* Components of Device to PCS lookup */
+ int (*fwd_curve) (struct _icxLuMatrix *p, double *out, double *in);
+ int (*fwd_matrix) (struct _icxLuMatrix *p, double *out, double *in);
+ int (*fwd_abs) (struct _icxLuMatrix *p, double *out, double *in);
+
+ /* Components of PCS to Device lookup */
+ int (*bwd_abs) (struct _icxLuMatrix *p, double *out, double *in);
+ int (*bwd_matrix) (struct _icxLuMatrix *p, double *out, double *in);
+ int (*bwd_curve) (struct _icxLuMatrix *p, double *out, double *in);
+
+}; typedef struct _icxLuMatrix icxLuMatrix;
+
+/* Multi-D. Lut type object */
+struct _icxLuLut {
+ XLU_BASE_MEMBERS
+
+ /* private: */
+ icmLut *lut; /* ICC Lut that is being used */
+ rspl *inputTable[MXDI]; /* The input lookups */
+ rspl *clutTable; /* The multi dimention lookup */
+ rspl *cclutTable; /* Alternate multi dimention lookup in CAM space */
+ rspl *outputTable[MXDO]; /* The output lookups */
+
+ /* Inverted RSPLs used to speed ink limit calculation */
+ /* input' -> input */
+ rspl *revinputTable[MXDI];
+
+ /* In/Out lookup flags used for rspl init. callback */
+ int iol_out; /* Non-zero if output lookup */
+ int iol_ch; /* Channel */
+
+ /* In/Out inversion support */
+ double inputClipc[MXDI]; /* The input lookups clip center */
+ double outputClipc[MXDO]; /* The output lookups clip center */
+
+ /* clut inversion support */
+ double icent[MXDI]; /* center of input gamut */
+ double licent[MXDI]; /* last icent value used */
+
+ icxClip clip; /* Clip setup information */
+
+ int kch; /* Black ink channel if discovered */
+ /* -1 if not known or applicable */
+ /* (Only set by icxLu_comp_bk_point()) */
+ icxInk ink; /* inking details */
+ double Lmin, Lmax; /* L min/max for inking rule */
+
+ /* Auxiliary parameter flags, non-zero for inputs that will be */
+ /* used as auxiliary parameters the rspl input */
+ /* dimensionality exceeds the output dimension (i.e. CMYK->Lab) */
+ int auxm[MXDI];
+
+ /* Auxiliar linearization function - NULL if none */
+ /* Only the used auxiliary chanels need be calculated. */
+ /* ~~ not implimented yet ~~~ */
+// void (*auxlinf)(void *auxlinf_ctx, double inout[MXDI]);
+
+ /* Opaque context for auxlin */
+// void *auxlinf_ctx;
+
+ /* Temporary icm fwd abs XYZ LuLut used for setting up icx clut */
+ icmLuBase *absxyzlu;
+
+ /* Optional function to compute the input chanel */
+ /* sum from the raw rspl input values. NULL if not used. */
+ /* Use this to take account of any transformation beyond */
+ /* the input space, or 6 color masquerading as 4 etc. */
+ double (*limitf)(void *limitf_ctx, float in[MXDI]); /* ~~ not implimented yet */
+
+ /* Opaque context for limitf */
+ void *limitf_ctx;
+
+ /* Input space sum limit. Points with a limitf() over */
+ /* this number will not be considered in gamut. Valid if gt 0 */
+ double slimit;
+
+ /* public: */
+
+ /* Note that black inking rules are always defined and provided */
+ /* in dev[] and pcs[] space, even for component functions */
+ /* (ie. the implementation of the inking rule deals with */
+ /* the dev<->dev' and pcs<->pcs' conversions) */
+
+ /* Requested direction component lookup */
+ int (*in_abs) (struct _icxLuLut *p, double *out, double *in);
+ int (*matrix) (struct _icxLuLut *p, double *out, double *in);
+ int (*input) (struct _icxLuLut *p, double *out, double *in);
+ int (*clut) (struct _icxLuLut *p, double *out, double *in);
+ int (*clut_aux)(struct _icxLuLut *p, double *out, double *olimit,
+ double *auxv, double *in);
+ int (*output) (struct _icxLuLut *p, double *out, double *in);
+ int (*out_abs) (struct _icxLuLut *p, double *out, double *in);
+
+ /* Inverse direction component lookup (in reverse order) */
+ int (*inv_out_abs) (struct _icxLuLut *p, double *out, double *in);
+ int (*inv_output) (struct _icxLuLut *p, double *out, double *in);
+ int (*inv_clut) (struct _icxLuLut *p, double *out, double *in);
+ int (*inv_clut_aux)(struct _icxLuLut *p, double *out, double *auxv,
+ double *auxr, double *auxt, double *clipd, double *in);
+ int (*inv_input) (struct _icxLuLut *p, double *out, double *in);
+ int (*inv_matrix) (struct _icxLuLut *p, double *out, double *in);
+ int (*inv_in_abs) (struct _icxLuLut *p, double *out, double *in);
+
+ /* Get locus information for a clut (see xlut.c for details) */
+ int (*clut_locus) (struct _icxLuLut *p, double *locus, double *out, double *in);
+
+ /* Get various types of information about the LuLut */
+ void (*get_info) (struct _icxLuLut *p, icmLut **lutp,
+ icmXYZNumber *pcswhtp, icmXYZNumber *whitep,
+ icmXYZNumber *blackp);
+
+ /* Get the matrix contents */
+ void (*get_matrix) (struct _icxLuLut *p, double m[3][3]);
+
+}; typedef struct _icxLuLut icxLuLut;
+
+/* ------------------------------------------------------------------------------ */
+/* Utility declarations and functions */
+
+/* Profile Creation Suplimental Information structure */
+struct _profxinf {
+ icmSig manufacturer; /* Device manufacturer ICC Sig, 0 for default */
+ char *deviceMfgDesc; /* Manufacturer text description, NULL for none */
+
+ icmSig model; /* Device model ICC Sig, 0 for default */
+ char *modelDesc; /* Model text description, NULL for none */
+
+ icmSig creator; /* Profile creator ICC Sig, 0 for default */
+
+ char *profDesc; /* Text profile description, NULL for default */
+
+ char *copyright; /* Copyrigh text, NULL for default */
+
+ /* Attribute flags */
+ int transparency; /* NZ for Trasparency, else Reflective */
+ int matte; /* NZ for Matte, else Glossy */
+ int negative; /* NZ for Negative, else Positive */
+ int blackandwhite; /* NZ for BlackAndWhite, else Color */
+
+ /* Default intent */
+ icRenderingIntent default_ri; /* Default rendering intent */
+
+ /* Other stuff ICC ?? */
+
+}; typedef struct _profxinf profxinf;
+
+/* Set an icc's Lut tables, and take care of auxiliary continuity problems. */
+/* Only useful if there are auxiliary device output chanels to be set. */
+int icxLut_set_tables_auxfix(
+icmLut *p, /* Pointer to icmLut object */
+void *cbctx, /* Opaque callback context pointer value */
+icColorSpaceSignature insig, /* Input color space */
+icColorSpaceSignature outsig, /* Output color space */
+void (*infunc)(void *cbctx, double *out, double *in),
+ /* Input transfer function, inspace->inspace' (NULL = default) */
+double *inmin, double *inmax, /* Maximum range of inspace' values */
+ /* (NULL = default) */
+void (*clutfunc)(void *cbntx, double *out, double *aux, double *auxr, double *pcs, double *in),
+ /* inspace' -> outspace' transfer function, also */
+ /* return the internal target PCS and the (packed) auxiliary locus */
+ /* range as [min0, max0, min1, max1...], and the actual auxiliary */
+ /* target used. */
+void (*clutpcsfunc)(void *cbntx, double *out, double *aux, double *pcs),
+ /* Internal PCS + actual aux_target -> outspace' transfer function */
+void (*clutipcsfunc)(void *cbntx, double *pcs, double *olimit, double *auxv, double *in),
+ /* outspace' -> Internal PCS + auxv check function */
+double *clutmin, double *clutmax, /* Maximum range of outspace' values */
+ /* (NULL = default) */
+void (*outfunc)(void *cbntx, double *out, double *in)
+ /* Output transfer function, outspace'->outspace (NULL = deflt) */
+);
+
+
+/* Return an enumerated viewing condition */
+/* Return enumeration if OK, -999 if there is no such enumeration. */
+/* xicc may be NULL if just the description is wanted, */
+/* or an explicit white point is provided. */
+int xicc_enum_viewcond(
+xicc *p, /* Expanded profile to get white point (May be NULL if desc NZ) */
+icxViewCond *vc, /* Viewing parameters to return, May be NULL if desc is nz */
+int no, /* Enumeration to return, -1 for default, -2 for none */
+char *as, /* String alias to number, NULL if none */
+int desc, /* NZ - Just return a description of this enumeration in vc */
+double *wp /* Provide white point if xicc is NULL */
+);
+
+/* Debug: dump a Viewing Condition to standard out */
+void xicc_dump_viewcond(icxViewCond *vc);
+
+/* Debug: dump an Inking setup to standard out */
+void xicc_dump_inking(icxInk *ik);
+
+/* Return enumerated gamut mapping intents */
+/* Return 0 if OK, 1 if there is no such enumeration. */
+/* Note the following fixed numbers meanings: */
+#define icxNoGMIntent -1
+#define icxDefaultGMIntent -2
+#define icxAbsoluteGMIntent -3
+#define icxRelativeGMIntent -4
+#define icxPerceptualGMIntent -5
+#define icxSaturationGMIntent -6
+#define icxIllegalGMIntent -999
+int xicc_enum_gmapintent(icxGMappingIntent *gmi, int no, char *as);
+void xicc_dump_gmi(icxGMappingIntent *gmi);
+
+/* - - - - - - - - - - */
+/* Utility functions: */
+
+/* Given an open icc profile, */
+/* guess which channel is the black. */
+/* Return -1 if there is no black channel or it can't be guessed */
+int icxGuessBlackChan(icc *p);
+
+/* Given an icc profile, try and create an xcal */
+/* Return NULL on error or no cal */
+struct _xcal *xiccReadCalTag(icc *p);
+
+/* A callback that uses an xcal, that can be used with icc get_tac */
+void xiccCalCallback(void *cntx, double *out, double *in);
+
+/* Given an xicc icc profile, estmate the total ink limit and black ink limit. */
+void icxGetLimits(xicc *p, double *tlimit, double *klimit);
+
+/* Using the above function, set default total and black ink values */
+void icxDefaultLimits(xicc *p, double *tlout, double tlin, double *klout, double klin);
+
+/* Given a calibrated total ink limit and an xcal, return the */
+/* equivalent underlying (pre-calibration) total ink limit. */
+/* This is the maximum equivalent, that makes sure that */
+/* the calibrated limit is met or exceeded. */
+double icxMaxUnderlyingLimit(struct _xcal *cal, double ilimit);
+
+/* - - - - - - - - - - */
+
+/* Utility function - compute the clip vector direction. */
+/* return NULL if vector clip isn't used. */
+double *icxClipVector(
+icxClip *p, /* Clipping setup information */
+double *in, /* Target point */
+double *cdirv /* Space for returned clip vector */
+);
+
+/* - - - - - - - - - - */
+
+/* CIE XYZ to perceptual Lab with partial derivatives. */
+void icxdXYZ2Lab(icmXYZNumber *w, double *out, double dout[3][3], double *in);
+
+/* Return the normal Delta E squared, given two Lab values, */
+/* including partial derivatives. */
+double icxdLabDEsq(double dout[2][3], double *Lab0, double *Lab1);
+
+/* Return the CIE94 Delta E color difference measure, squared */
+/* including partial derivatives. */
+double icxdCIE94sq(double dout[2][3], double Lab0[3], double Lab1[3]);
+
+/* Return the normal Delta E given two Lab values, */
+/* including partial derivatives. */
+double icxdLabDE(double dout[2][3], double *Lab0, double *Lab1);
+
+/* Return the CIE94 Delta E color difference measure */
+/* including partial derivatives. */
+double icxdCIE94(double dout[2][3], double Lab0[3], double Lab1[3]);
+
+/* - - - - - - - - - - */
+/* Power like function, based on Graphics Gems adjustment curve. */
+/* Avoids "toe" problem of pure power. */
+/* Adjusted so that "power" 2 and 0.5 agree with real power at 0.5 */
+double icx_powlike(double vv, double pp);
+
+/* Compute the necessary aproximate power, to transform */
+/* the given value from src to dst. They are assumed to be */
+/* in the range 0.0 .. 1.0 */
+double icx_powlike_needed(double src, double dst);
+
+/* - - - - - - - - - - */
+
+/* Transfer function */
+double icxTransFunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+);
+
+/* Inverse Transfer function */
+double icxInvTransFunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+);
+
+/* Transfer function with scaling */
+double icxSTransFunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+);
+
+/* Inverse Transfer function with scaling */
+double icxInvSTransFunc(
+double *v, /* Pointer to first parameter */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+);
+
+/* Transfer function with partial derivative */
+/* with respect to the parameters. */
+double icxdpTransFunc(
+double *v, /* Pointer to first parameter */
+double *dv, /* Return derivative wrt each parameter [luord] */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+);
+
+/* Transfer function with scaling and */
+/* partial derivative with respect to the parameters. */
+double icxdpSTransFunc(
+double *v, /* Pointer to first parameter */
+double *dv, /* Return derivative wrt each parameter [luord] */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+);
+
+/* Transfer function with partial derivative */
+/* with respect to the input value. */
+double icxdiTransFunc(
+double *v, /* Pointer to first parameter */
+double *pdv, /* Return derivative wrt source value [1] */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+);
+
+/* Transfer function with scaling and */
+/* partial derivative with respect to the input value. */
+double icxdiSTransFunc(
+double *v, /* Pointer to first parameter */
+double *pdv, /* Return derivative wrt source value [1] */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+);
+
+/* Transfer function with partial derivative */
+/* with respect to the parameters and the input value. */
+double icxdpdiTransFunc(
+double *v, /* Pointer to first parameter */
+double *dv, /* Return derivative wrt each parameter [luord] */
+double *pdin, /* Return derivative wrt source value [1] */
+int luord, /* Number of parameters */
+double vv /* Source of value */
+);
+
+/* Transfer function with scaling and */
+/* partial derivative with respect to the */
+/* parameters and the input value. */
+double icxdpdiSTransFunc(
+double *v, /* Pointer to first parameter */
+double *dv, /* Return derivative wrt each parameter [luord] */
+double *pdin, /* Return derivative wrt source value [1] */
+int luord, /* Number of parameters */
+double vv, /* Source of value */
+double min, /* Scale values */
+double max
+);
+
+/* Should add/move the spectro/moncurve stuff in here, */
+/* since it has offset and scaling. */
+
+/* - - - - - - - - - - */
+/* Multi-plane interpolation - uses base + di slope values. */
+/* Parameters are assumed to be fdi groups of di + 1 parameters. */
+void icxPlaneInterp(
+double *v, /* Pointer to first parameter [fdi * (di + 1)] */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+);
+
+/* Matrix cube interpolation. with partial derivative */
+/* with respect to the input and parameters. */
+void icxdpdiPlaneInterp(
+double *v, /* Pointer to first parameter value [fdi * (di + 1)] */
+double *dv, /* Return [1 + di] deriv. wrt each parameter v */
+double *din, /* Return [fdi * di] deriv. wrt each input value */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+);
+
+/* - - - - - - - - - - */
+
+/* Matrix cube interpolation - interpolate between 2^di output corner values. */
+/* Parameters are assumed to be fdi groups of 2^di parameters. */
+void icxCubeInterp(
+double *v, /* Pointer to first parameter */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+);
+
+/* Matrix cube interpolation. with partial derivative */
+/* with respect to the input and parameters. */
+void icxdpdiCubeInterp(
+double *v, /* Pointer to first parameter value */
+double *dv, /* Return [fdi * 2^di] deriv wrt each parameter v */
+double *din, /* Return [fdi * di] deriv wrt each input value */
+int fdi, /* Number of output channels */
+int di, /* Number of input channels */
+double *out, /* Resulting fdi values */
+double *in /* Input di values */
+);
+
+/* - - - - - - - - - - */
+
+/* 3x3 matrix multiplication, with the matrix in a 1D array */
+/* with respect to the input and parameters. */
+void icxMulBy3x3Parm(
+ double out[3], /* Return input multiplied by matrix */
+ double mat[9], /* Matrix organised in [slow][fast] order */
+ double in[3] /* Input values */
+);
+
+/* 3x3 matrix multiplication, with partial derivatives */
+/* with respect to the input and parameters. */
+void icxdpdiMulBy3x3Parm(
+ double out[3], /* Return input multiplied by matrix */
+ double dv[3][9], /* Return deriv for each [output] with respect to [param] */
+ double din[3][3], /* Return deriv for each [output] with respect to [input] */
+ double mat[9], /* Matrix organised in [slow][fast] order */
+ double in[3] /* Input values */
+);
+
+/* - - - - - - - - - - */
+
+#include "xcal.h"
+
+#endif /* XICC_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xicclu.c b/xicc/xicclu.c
new file mode 100644
index 0000000..aa4a452
--- /dev/null
+++ b/xicc/xicclu.c
@@ -0,0 +1,1149 @@
+
+/*
+ * xicc lookup/test utility
+ *
+ * This program is the analog of icclu, but allows reverse lookup
+ * of transforms by making use of xicc interpolation code.
+ * (Based on the old xfmlu.c)
+ *
+ * Author: Graeme W. Gill
+ * Date: 8/7/00
+ * Version: 1.00
+ *
+ * Copyright 1999, 2000 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.
+ */
+
+/* TTBD:
+
+ Can -ff and -fif be made to work with device link files ?
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "copyright.h"
+#include "aconfig.h"
+#include "numlib.h"
+#include "plot.h"
+#include "xicc.h"
+
+#undef SPTEST /* Test rspl gamut surface code */
+
+#define USE_NEARCLIP /* Our usual expectation */
+#define XRES 128 /* Plotting resolution */
+
+void usage(char *diag) {
+ int i;
+ fprintf(stderr,"Translate colors through an xicc, Version %s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
+ fprintf(stderr,"usage: xicclu [-options] profile\n");
+ if (diag != NULL)
+ fprintf(stderr,"Diagnostic: %s\n",diag);
+ fprintf(stderr," -v level Verbosity level 0 - 2 (default = 1)\n");
+ fprintf(stderr," -g Plot slice instead of looking colors up. (Default white to black)\n");
+ fprintf(stderr," -G s:L:a:b Override plot slice start with Lab or Jab co-ordinate \n");
+ fprintf(stderr," -G e:L:a:b Override plot slice end with Lab or Jab co-ordinate \n");
+ fprintf(stderr," -f function f = forward, b = backwards, g = gamut, p = preview\n");
+ fprintf(stderr," if = inverted forward, ib = inverted backwards\n");
+ fprintf(stderr," -i intent a = absolute, r = relative colorimetric\n");
+ fprintf(stderr," p = perceptual, s = saturation\n");
+// fprintf(stderr," P = absolute perceptual, S = absolute saturation\n");
+ fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
+ fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
+ fprintf(stderr," -p oride x = XYZ_PCS, X = XYZ * 100, l = Lab_PCS, L = LCh, y = Yxy\n");
+ fprintf(stderr," j = %s Appearance Jab, J = %s Appearance JCh\n",icxcam_description(cam_default),icxcam_description(cam_default));
+ fprintf(stderr," -s scale Scale device range 0.0 - scale rather than 0.0 - 1.0\n");
+ fprintf(stderr," -k [zhxrlv] Black value target: z = zero K,\n");
+ fprintf(stderr," h = 0.5 K, x = max K, r = ramp K (def.)\n");
+ fprintf(stderr," l = extra PCS input is portion of K locus\n");
+ fprintf(stderr," v = extra PCS input is K target value\n");
+ fprintf(stderr," -k p stle stpo enpo enle shape\n");
+ fprintf(stderr," stle: K level at White 0.0 - 1.0\n");
+ fprintf(stderr," stpo: start point of transition Wh 0.0 - Bk 1.0\n");
+ fprintf(stderr," enpo: End point of transition Wh 0.0 - Bk 1.0\n");
+ fprintf(stderr," enle: K level at Black 0.0 - 1.0\n");
+ fprintf(stderr," shape: 1.0 = straight, 0.0-1.0 concave, 1.0-2.0 convex\n");
+ fprintf(stderr," -k q stle0 stpo0 enpo0 enle0 shape0 stle2 stpo2 enpo2 enle2 shape2\n");
+ fprintf(stderr," Transfer extra PCS input to dual curve limits\n");
+ fprintf(stderr," -K parameters Same as -k, but target is K locus rather than K value itself\n");
+ fprintf(stderr," -l tlimit set total ink limit, 0 - 400%% (estimate by default)\n");
+ fprintf(stderr," -L klimit set black ink limit, 0 - 100%% (estimate by default)\n");
+ fprintf(stderr," -a show actual target values if clipped\n");
+ fprintf(stderr," -u warn if output PCS is outside the spectrum locus\n");
+ fprintf(stderr," -m merge output processing into clut\n");
+ fprintf(stderr," -b use CAM Jab for clipping\n");
+// fprintf(stderr," -S Use internal optimised separation for inverse 4d [NOT IMPLEMENTED]\n");
+
+#ifdef SPTEST
+ fprintf(stderr," -w special gamut surface test PCS space\n");
+ fprintf(stderr," -W special gamut surface test, PCS' space\n");
+#endif
+ fprintf(stderr," -c viewcond set viewing conditions for CIECAM97s,\n");
+ fprintf(stderr," either an enumerated choice, or a parameter:value changes\n");
+ for (i = 0; ; i++) {
+ icxViewCond vc;
+ if (xicc_enum_viewcond(NULL, &vc, i, NULL, 1, NULL) == -999)
+ break;
+
+ fprintf(stderr," %s\n",vc.desc);
+ }
+
+ fprintf(stderr," s:surround n = auto, a = average, m = dim, d = dark,\n");
+ fprintf(stderr," c = transparency (default average)\n");
+ fprintf(stderr," w:X:Y:Z Adapted white point as XYZ (default media white, Abs: D50)\n");
+ fprintf(stderr," w:x:y Adapted white point as x, y\n");
+ fprintf(stderr," a:adaptation Adaptation luminance in cd.m^2 (default 50.0)\n");
+ fprintf(stderr," b:background Background %% of image luminance (default 20)\n");
+ fprintf(stderr," l:scenewhite Scene white in cd.m^2 if surround = auto (default 250)\n");
+ fprintf(stderr," f:flare Flare light %% of image luminance (default 1)\n");
+ fprintf(stderr," f:X:Y:Z Flare color as XYZ (default media white, Abs: D50)\n");
+ fprintf(stderr," f:x:y Flare color as x, y\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr," The colors to be translated should be fed into standard in,\n");
+ fprintf(stderr," one input color per line, white space separated.\n");
+ fprintf(stderr," A line starting with a # will be ignored.\n");
+ fprintf(stderr," A line not starting with a number will terminate the program.\n");
+ fprintf(stderr," Use -v0 for just output colors.\n");
+ exit(1);
+}
+
+#ifdef SPTEST
+
+#pragma message("!!!!!!!!!!!! Experimental gamut boundary test !!!!!!!!!")
+
+/* Output curve function */
+void spoutf(void *cbntx, double *out, double *in) {
+ icxLuLut *clu = (icxLuLut *)cbntx;
+
+ clu->output(clu, out, in);
+ clu->out_abs(clu, out, out);
+}
+
+/* Inverse output curve function */
+void spioutf(void *cbntx, double *out, double *in) {
+ icxLuLut *clu = (icxLuLut *)cbntx;
+
+ clu->inv_out_abs(clu, out, in);
+ clu->inv_output(clu, out, out);
+}
+
+
+#endif /* SPTEST */
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char prof_name[MAXNAMEL+1];
+ icmFile *fp;
+ icc *icco;
+ xicc *xicco;
+ int doplot = 0; /* Do grey axis plot */
+ double pstart[3] = { -1000.0 }; /* Plot Lab/Jab PCS start point = white */
+ double pend[3] = { -1000.0 }; /* Plot Lab/Jab PCS end point = black */
+ icxInk ink; /* Ink parameters */
+ double tlimit = -1.0; /* Total ink limit */
+ double klimit = -1.0; /* Black ink limit */
+ int intsep = 0;
+ icxViewCond vc; /* Viewing Condition for CIECAM97s */
+ int vc_e = -1; /* Enumerated viewing condition */
+ int vc_s = -1; /* Surround override */
+ double vc_wXYZ[3] = {-1.0, -1.0, -1.0}; /* Adapted white override in XYZ */
+ double vc_wxy[2] = {-1.0, -1.0}; /* Adapted white override in x,y */
+ double vc_a = -1.0; /* Adapted luminance */
+ double vc_b = -1.0; /* Background % overid */
+ double vc_l = -1.0; /* Scene luminance override */
+ double vc_f = -1.0; /* Flare % overid */
+ double vc_fXYZ[3] = {-1.0, -1.0, -1.0}; /* Flare color override in XYZ */
+ double vc_fxy[2] = {-1.0, -1.0}; /* Flare color override in x,y */
+ int verb = 1;
+ int actual = 0;
+ int slocwarn = 0;
+ int merge = 0;
+ int camclip = 0;
+ int repYxy = 0; /* Report Yxy */
+ int repJCh = 0; /* Report JCh */
+ int repLCh = 0; /* Report LCh */
+ int repXYZ100 = 0; /* Scale XYZ by 10 */
+ double scale = 0.0; /* Device value scale factor */
+ int rv = 0;
+ char buf[200];
+ double uin[MAX_CHAN], in[MAX_CHAN], out[MAX_CHAN], uout[MAX_CHAN];
+
+ icxLuBase *luo, *aluo = NULL;
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int inn, outn; /* Number of components */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+
+ /* Lookup parameters */
+ icmLookupFunc func = icmFwd; /* Default */
+ icRenderingIntent intent = icmDefaultIntent; /* Default */
+ icColorSpaceSignature pcsor = icmSigDefaultData; /* Default */
+ icmLookupOrder order = icmLuOrdNorm; /* Default */
+ int inking = 3; /* Default is ramp */
+ int locus = 0; /* Default is K value */
+ /* K curve params */
+ double Kstle = 0.0, Kstpo = 0.0, Kenle = 0.0, Kenpo = 0.0, Kshap = 0.0;
+ /* K curve params (max) */
+ double Kstle1 = 0.0, Kstpo1 = 0.0, Kenle1 = 0.0, Kenpo1 = 0.0, Kshap1 = 0.0;
+ int invert = 0;
+
+#ifdef SPTEST
+ int sptest = 0;
+ warning("xicc/xicclu.c !!!! special rspl gamut sest code is compiled in !!!!\n");
+#endif
+
+ error_program = argv[0];
+
+ if (argc < 2)
+ usage("Too few arguments");
+
+ /* Process the arguments */
+ for(fa = 1;fa < argc;fa++) {
+ nfa = fa; /* skip to nfa if next argument is used */
+ if (argv[fa][0] == '-') { /* Look for any flags */
+ char *na = NULL; /* next argument after flag, null if none */
+
+ if (argv[fa][2] != '\000')
+ na = &argv[fa][2]; /* next is directly after flag */
+ else {
+ if ((fa+1) < argc) {
+ if (argv[fa+1][0] != '-') {
+ nfa = fa + 1;
+ na = argv[nfa]; /* next is seperate non-flag argument */
+ }
+ }
+ }
+
+ if (argv[fa][1] == '?')
+ usage("Requested usage");
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ fa = nfa;
+ if (na == NULL)
+ verb = 2;
+ else {
+ if (na[0] == '0')
+ verb = 0;
+ else if (na[0] == '1')
+ verb = 1;
+ else if (na[0] == '2')
+ verb = 2;
+ else
+ usage("Illegal verbosity level");
+ }
+ }
+
+ /* Locus plot */
+ else if (argv[fa][1] == 'g') {
+ doplot = 1;
+ }
+ /* Plot start or end override */
+ else if (argv[fa][1] == 'G') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -G");
+ if (na[0] == 's' || na[0] == 'S') {
+ if (sscanf(na+1,":%lf:%lf:%lf",&pstart[0],&pstart[1],&pstart[2]) != 3)
+ usage("Unrecognised parameters after -Gs");
+ } else if (na[0] == 'e' || na[0] == 'E') {
+ if (sscanf(na+1,":%lf:%lf:%lf",&pend[0],&pend[1],&pend[2]) != 3)
+ usage("Unrecognised parameters after -Ge");
+ } else
+ usage("Unrecognised parameters after -G");
+ }
+ /* Actual target values */
+ else if (argv[fa][1] == 'a') {
+ actual = 1;
+ }
+ /* Warn if output is outside the spectrum locus */
+ else if (argv[fa][1] == 'u') {
+ slocwarn = 1;
+ }
+ /* Merge output */
+ else if (argv[fa][1] == 'm') {
+ merge = 1;
+ }
+ /* Use CAM Jab for clipping on reverse lookup */
+ else if (argv[fa][1] == 'b') {
+ camclip = 1;
+ }
+ /* Use optimised internal separation */
+ else if (argv[fa][1] == 'S') {
+ intsep = 1;
+ }
+ /* Device scale */
+ else if (argv[fa][1] == 's') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -s");
+ scale = atof(na);
+ if (scale <= 0.0) usage("Illegal scale value");
+ }
+ /* function */
+ else if (argv[fa][1] == 'f') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -f");
+ switch (na[0]) {
+ case 'f':
+ case 'F':
+ func = icmFwd;
+ break;
+ case 'b':
+ case 'B':
+ func = icmBwd;
+ break;
+ case 'g':
+ case 'G':
+ func = icmGamut;
+ break;
+ case 'p':
+ case 'P':
+ func = icmPreview;
+ break;
+ case 'i':
+ case 'I':
+ invert = 1;
+ if (na[1] == 'f' || na[1] == 'F')
+ func = icmFwd;
+ else if (na[1] == 'b' || na[1] == 'B')
+ func = icmBwd;
+ else
+ usage("Unknown parameter after flag -fi");
+ break;
+ default:
+ usage("Unknown parameter after flag -f");
+ }
+ }
+
+ /* Intent */
+ else if (argv[fa][1] == 'i') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -i");
+ switch (na[0]) {
+ case 'p':
+ intent = icPerceptual;
+ break;
+ case 'r':
+ intent = icRelativeColorimetric;
+ break;
+ case 's':
+ intent = icSaturation;
+ break;
+ case 'a':
+ intent = icAbsoluteColorimetric;
+ break;
+ /* Argyll special intents to check spaces underlying */
+ /* icxPerceptualAppearance & icxSaturationAppearance */
+ case 'P':
+ intent = icmAbsolutePerceptual;
+ break;
+ case 'S':
+ intent = icmAbsoluteSaturation;
+ break;
+ default:
+ usage("Unknown parameter after flag -i");
+ }
+ }
+
+ /* PCS override */
+ else if (argv[fa][1] == 'p') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -i");
+ switch (na[0]) {
+ case 'x':
+ pcsor = icSigXYZData;
+ repYxy = 0;
+ repLCh = 0;
+ repJCh = 0;
+ repXYZ100 = 0;
+ break;
+ case 'X':
+ pcsor = icSigXYZData;
+ repYxy = 0;
+ repLCh = 0;
+ repJCh = 0;
+ repXYZ100 = 1;
+ break;
+ case 'l':
+ pcsor = icSigLabData;
+ repYxy = 0;
+ repLCh = 0;
+ repJCh = 0;
+ break;
+ case 'L':
+ pcsor = icSigLabData;
+ repYxy = 0;
+ repLCh = 1;
+ repJCh = 0;
+ break;
+ case 'y':
+ case 'Y':
+ pcsor = icSigXYZData;
+ repYxy = 1;
+ repLCh = 0;
+ repJCh = 0;
+ break;
+ case 'j':
+ pcsor = icxSigJabData;
+ repYxy = 0;
+ repLCh = 0;
+ repJCh = 0;
+ break;
+ case 'J':
+ pcsor = icxSigJabData;
+ repYxy = 0;
+ repLCh = 0;
+ repJCh = 1;
+ break;
+ default:
+ usage("Unknown parameter after flag -i");
+ }
+ }
+
+ /* Search order */
+ else if (argv[fa][1] == 'o') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -o");
+ switch (na[0]) {
+ case 'n':
+ case 'N':
+ order = icmLuOrdNorm;
+ break;
+ case 'r':
+ case 'R':
+ order = icmLuOrdRev;
+ break;
+ default:
+ usage("Unknown parameter after flag -o");
+ }
+ }
+
+ /* Inking rule */
+ else if (argv[fa][1] == 'k') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -k");
+ if (argv[fa][1] == 'k')
+ locus = 0; /* K value target */
+ else
+ locus = 1; /* K locus target */
+ switch (na[0]) {
+ case 'z':
+ case 'Z':
+ inking = 0; /* Use minimum k */
+ break;
+ case 'h':
+ case 'H':
+ inking = 1; /* Use 0.5 k */
+ break;
+ case 'x':
+ case 'X':
+ inking = 2; /* Use maximum k */
+ break;
+ case 'r':
+ case 'R':
+ inking = 3; /* Use ramping K */
+ break;
+ case 'l':
+ case 'L':
+ inking = 4; /* Extra param is locus */
+ break;
+ case 'v':
+ case 'V':
+ inking = 5; /* Extra param is K target */
+ break;
+ case 'p':
+ case 'P':
+ case 'q':
+ case 'Q':
+ inking = 6; /* Use curve parameter */
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kp) expects more parameters");
+ Kstle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kp) expects more parameters");
+ Kstpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kp) expects more parameters");
+ Kenpo = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kp) expects more parameters");
+ Kenle = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kp) expects more parameters");
+ Kshap = atof(argv[fa]);
+
+ if (na[0] == 'q' || na[0] == 'Q') {
+ inking = 7; /* Use transfer to dual curve parameter */
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kq) expects more parameters");
+ Kstle1 = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kq) expects more parameters");
+ Kstpo1 = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kq) expects more parameters");
+ Kenpo1 = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc) usage("Inking rule (-kq) expects more parameters");
+ Kenle1 = atof(argv[fa]);
+
+ ++fa;
+ if (fa >= argc || argv[fa][0] == '-') usage("Inking rule (-kq) expects more parameters");
+ Kshap1 = atof(argv[fa]);
+
+ }
+ break;
+ default:
+ usage("Unknown parameter after flag -k");
+ }
+ }
+
+ else if (argv[fa][1] == 'l') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -l");
+ tlimit = atoi(na)/100.0;
+ }
+
+ else if (argv[fa][1] == 'L') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -L");
+ klimit = atoi(na)/100.0;
+ }
+
+#ifdef SPTEST
+ else if (argv[fa][1] == 'w') {
+ sptest = 1;
+ }
+ else if (argv[fa][1] == 'W') {
+ sptest = 2;
+ }
+#endif
+ /* Viewing conditions */
+ else if (argv[fa][1] == 'c') {
+ fa = nfa;
+ if (na == NULL) usage("No parameter after flag -c");
+#ifdef NEVER
+ if (na[0] >= '0' && na[0] <= '9') {
+ vc_e = atoi(na);
+ } else
+#endif
+ if (na[1] != ':') {
+ if ((vc_e = xicc_enum_viewcond(NULL, NULL, -2, na, 1, NULL)) == -999)
+ usage("Urecognised Enumerated Viewing conditions");
+ } else if (na[0] == 's' || na[0] == 'S') {
+ if (na[1] != ':')
+ usage("Unrecognised parameters after -cs");
+ if (na[2] == 'n' || na[2] == 'N') {
+ vc_s = vc_none; /* Automatic using Lv */
+ } else if (na[2] == 'a' || na[2] == 'A') {
+ vc_s = vc_average;
+ } else if (na[2] == 'm' || na[2] == 'M') {
+ vc_s = vc_dim;
+ } else if (na[2] == 'd' || na[2] == 'D') {
+ vc_s = vc_dark;
+ } else if (na[2] == 'c' || na[2] == 'C') {
+ vc_s = vc_cut_sheet;
+ } else
+ usage("Unrecognised parameters after -cs:");
+ } else if (na[0] == 'w' || na[0] == 'W') {
+ double x, y, z;
+ if (sscanf(na+1,":%lf:%lf:%lf",&x,&y,&z) == 3) {
+ vc_wXYZ[0] = x; vc_wXYZ[1] = y; vc_wXYZ[2] = z;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc_wxy[0] = x; vc_wxy[1] = y;
+ } else
+ usage("Unrecognised parameters after -cw");
+ } else if (na[0] == 'a' || na[0] == 'A') {
+ if (na[1] != ':')
+ usage("Unrecognised parameters after -ca");
+ vc_a = atof(na+2);
+ } else if (na[0] == 'b' || na[0] == 'B') {
+ if (na[1] != ':')
+ usage("Unrecognised parameters after -cb");
+ vc_b = atof(na+2);
+ } else if (na[0] == 'l' || na[0] == 'L') {
+ if (na[1] != ':')
+ usage("Viewing conditions (-[cd]l) missing ':'");
+ vc_l = atof(na+2);
+ } else if (na[0] == 'f' || na[0] == 'F') {
+ 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;
+ } else if (sscanf(na+1,":%lf:%lf",&x,&y) == 2) {
+ vc_fxy[0] = x; vc_fxy[1] = y;
+ } else if (sscanf(na+1,":%lf",&x) == 1) {
+ vc_f = x;
+ } else
+ usage("Unrecognised parameters after -cf");
+ } else
+ usage("Unrecognised parameters after -c");
+ }
+
+ else
+ usage("Unknown flag");
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage("Expecting profile file name");
+ strncpy(prof_name,argv[fa],MAXNAMEL); prof_name[MAXNAMEL] = '\000';
+
+ if (doplot) {
+
+ /* Force PCS to be Lab or Jab */
+ repJCh = 0;
+ repLCh = 0;
+ if (pcsor != icxSigJabData)
+ pcsor = icSigLabData;
+
+ if ((invert == 0 && func != icmBwd)
+ || (invert != 0 && func != icmFwd))
+ error("Must use -fb or -fif for grey axis plot");
+ }
+
+ /* Open up the profile for reading */
+ if ((fp = new_icmFileStd_name(prof_name,"r")) == NULL)
+ error ("Can't open file '%s'",prof_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ if ((rv = icco->read(icco,fp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ if (doplot) {
+ if (icco->header->deviceClass != icSigInputClass
+ && icco->header->deviceClass != icSigDisplayClass
+ && icco->header->deviceClass != icSigOutputClass)
+ error("Profile must be a device profile to plot neutral axis");
+ }
+
+ if (verb > 1) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ icco->header->dump(icco->header, op, 1);
+ op->del(op);
+ }
+
+ /* Wrap with an expanded icc */
+ if ((xicco = new_xicc(icco)) == NULL)
+ error ("Creation of xicc failed");
+
+ /* Set the default ink limits if not set on command line */
+ icxDefaultLimits(xicco, &ink.tlimit, tlimit, &ink.klimit, klimit);
+
+ if (verb > 1) {
+ if (ink.tlimit >= 0.0)
+ printf("Total ink limit assumed is %3.0f%%\n",100.0 * ink.tlimit);
+ if (ink.klimit >= 0.0)
+ printf("Black ink limit assumed is %3.0f%%\n",100.0 * ink.klimit);
+ }
+
+ ink.KonlyLmin = 0; /* Use normal black as locus Lmin */
+
+ ink.c.Ksmth = ICXINKDEFSMTH; /* Default curve smoothing */
+ ink.c.Kskew = ICXINKDEFSKEW; /* default curve skew */
+ ink.x.Ksmth = ICXINKDEFSMTH;
+ ink.x.Kskew = ICXINKDEFSKEW;
+
+ if (inking == 0) { /* Use minimum */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k; /* Locus or value target */
+ ink.c.Kstle = 0.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 0.0;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 1) { /* Use 0.5 */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k; /* Locus or value target */
+ ink.c.Kstle = 0.5;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 0.5;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 2) { /* Use maximum */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k; /* Locus or value target */
+ ink.c.Kstle = 1.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 1.0;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 3) { /* Use ramp */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k; /* Locus or value target */
+ ink.c.Kstle = 0.0;
+ ink.c.Kstpo = 0.0;
+ ink.c.Kenpo = 1.0;
+ ink.c.Kenle = 1.0;
+ ink.c.Kshap = 1.0;
+ } else if (inking == 4) { /* Use locus */
+ ink.k_rule = icxKlocus;
+ } else if (inking == 5) { /* Use K target */
+ ink.k_rule = icxKvalue;
+ } else if (inking == 6) { /* Use specified curve */
+ ink.k_rule = locus ? icxKluma5 : icxKluma5k; /* Locus or value target */
+ ink.c.Kstle = Kstle;
+ ink.c.Kstpo = Kstpo;
+ ink.c.Kenpo = Kenpo;
+ ink.c.Kenle = Kenle;
+ ink.c.Kshap = Kshap;
+ } else { /* Use dual curves */
+ ink.k_rule = locus ? icxKl5l : icxKl5lk; /* Locus or value target */
+ ink.c.Kstle = Kstle;
+ ink.c.Kstpo = Kstpo;
+ ink.c.Kenpo = Kenpo;
+ ink.c.Kenle = Kenle;
+ ink.c.Kshap = Kshap;
+ ink.x.Kstle = Kstle1;
+ ink.x.Kstpo = Kstpo1;
+ ink.x.Kenpo = Kenpo1;
+ ink.x.Kenle = Kenle1;
+ ink.x.Kshap = Kshap1;
+ }
+
+ /* Setup the viewing conditions */
+ if (xicc_enum_viewcond(xicco, &vc, -1, NULL, 0, NULL) == -999)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+//xicc_dump_viewcond(&vc);
+ if (vc_e != -1)
+ if (xicc_enum_viewcond(xicco, &vc, vc_e, NULL, 0, NULL) == -999)
+ error ("%d, %s",xicco->errc, xicco->err);
+ if (vc_s >= 0)
+ vc.Ev = vc_s;
+ if (vc_wXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Wxyz[0] = vc_wXYZ[0]/vc_wXYZ[1] * vc.Wxyz[1];
+ vc.Wxyz[2] = vc_wXYZ[2]/vc_wXYZ[1] * vc.Wxyz[1];
+ }
+ if (vc_wxy[0] >= 0.0) {
+ double x = vc_wxy[0];
+ double y = vc_wxy[1]; /* If Y == 1.0, then X+Y+Z = 1/y */
+ double z = 1.0 - x - y;
+ vc.Wxyz[0] = x/y * vc.Wxyz[1];
+ vc.Wxyz[2] = z/y * vc.Wxyz[1];
+ }
+ if (vc_a >= 0.0)
+ vc.La = vc_a;
+ if (vc_b >= 0.0)
+ vc.Yb = vc_b/100.0;
+ if (vc_l >= 0.0)
+ vc.Lv = vc_l;
+ if (vc_f >= 0.0)
+ vc.Yf = vc_f/100.0;
+ if (vc_fXYZ[1] > 0.0) {
+ /* Normalise it to current media white */
+ vc.Fxyz[0] = vc_fXYZ[0]/vc_fXYZ[1] * vc.Fxyz[1];
+ vc.Fxyz[2] = vc_fXYZ[2]/vc_fXYZ[1] * vc.Fxyz[1];
+ }
+ if (vc_fxy[0] >= 0.0) {
+ double x = vc_fxy[0];
+ double y = vc_fxy[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];
+ }
+//xicc_dump_viewcond(&vc);
+
+ /* Get a expanded color conversion object */
+ if ((luo = xicco->get_luobj(xicco, 0
+#ifdef USE_NEARCLIP
+ | ICX_CLIP_NEAREST
+#endif
+ | (intsep ? ICX_INT_SEPARATE : 0)
+ | (merge ? ICX_MERGE_CLUT : 0)
+ | (camclip ? ICX_CAM_CLIP : 0)
+ | ICX_FAST_SETUP
+ , func, intent, pcsor, order, &vc, &ink)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ if (invert)
+ luo->spaces(luo, &outs, &outn, &ins, &inn, &alg, NULL, NULL, NULL);
+ else
+ luo->spaces(luo, &ins, &inn, &outs, &outn, &alg, NULL, NULL, NULL);
+
+ /* If we can do check on clipped values */
+ if (actual != 0) {
+ if (invert == 0) {
+ if (func == icmFwd || func == icmBwd) {
+ if ((aluo = xicco->get_luobj(xicco, ICX_CLIP_NEAREST,
+ func == icmFwd ? icmBwd : icmFwd, intent, pcsor, order, &vc, &ink)) == NULL)
+ error ("%d, %s",xicco->errc, xicco->err);
+ }
+ } else {
+ aluo = luo; /* We can use the same one */
+ }
+ }
+
+ /* More information */
+ if (verb > 1) {
+ int j;
+ double inmin[MAX_CHAN], inmax[MAX_CHAN];
+ double outmin[MAX_CHAN], outmax[MAX_CHAN];
+
+ luo->get_native_ranges(luo, inmin, inmax, outmin,outmax);
+ printf("Internal input value range: ");
+ for (j = 0; j < inn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f..%f",inmin[j], inmax[j]);
+ else
+ fprintf(stdout,"%f..%f",inmin[j], inmax[j]);
+ }
+ printf("\nInternal output value range: ");
+ for (j = 0; j < outn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f..%f",outmin[j], outmax[j]);
+ else
+ fprintf(stdout,"%f..%f",outmin[j], outmax[j]);
+ }
+
+ luo->get_ranges(luo, inmin, inmax, outmin,outmax);
+ printf("\nInput value range: ");
+ for (j = 0; j < inn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f..%f",inmin[j], inmax[j]);
+ else
+ fprintf(stdout,"%f..%f",inmin[j], inmax[j]);
+ }
+ printf("\nOutput value range: ");
+ for (j = 0; j < outn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f..%f",outmin[j], outmax[j]);
+ else
+ fprintf(stdout,"%f..%f",outmin[j], outmax[j]);
+ }
+ printf("\n");
+ }
+
+ if (repYxy) { /* report Yxy rather than XYZ */
+ if (ins == icSigXYZData)
+ ins = icSigYxyData;
+ if (outs == icSigXYZData)
+ outs = icSigYxyData;
+ }
+
+ if (repJCh) { /* report JCh rather than Jab */
+ if (ins == icxSigJabData)
+ ins = icxSigJChData;
+ if (outs == icxSigJabData)
+ outs = icxSigJChData;
+ }
+ if (repLCh) { /* report LCh rather than Lab */
+ if (ins == icSigLabData)
+ ins = icxSigLChData;
+ if (outs == icSigLabData)
+ outs = icxSigLChData;
+ }
+
+#ifdef SPTEST
+ if (sptest) {
+ icxLuLut *clu;
+ double cent[3] = { 50.0, 0.0, 0.0 };
+
+ if (luo->plu->ttype != icmLutType)
+ error("Special test only works on CLUT profiles");
+
+ clu = (icxLuLut *)luo;
+
+ clu->clutTable->comp_gamut(clu->clutTable, cent, NULL, spoutf, clu, spioutf, clu);
+ rspl_gam_plot(clu->clutTable, "sp_test.wrl", sptest-1);
+ exit(0);
+ }
+#endif
+
+ if (doplot) {
+ int i, j;
+ double xx[XRES];
+ double yy[6][XRES];
+ double start[3], end[3];
+
+ /* Plot from white to black by default */
+ luo->efv_wh_bk_points(luo, start, end, NULL);
+
+ if (pstart[0] == -1000.0)
+ icmCpy3(pstart, start);
+
+ if (pend[0] == -1000.0)
+ icmCpy3(pend, end);
+
+ if (verb) {
+ printf("Plotting from white %f %f %f to black %f %f %f\n",
+ pstart[0], pstart[1], pstart[2], pend[0], pend[1], pend[2]);
+ }
+ for (i = 0; i < XRES; i++) {
+ double ival = (double)i/(XRES-1.0);
+
+ /* Input is always Jab or Lab */
+ in[0] = ival * pend[0] + (1.0 - ival) * pstart[0];
+ in[1] = ival * pend[1] + (1.0 - ival) * pstart[1];
+ in[2] = ival * pend[2] + (1.0 - ival) * pstart[2];
+//in[1] = in[2] = 0.0;
+
+ /* Do the conversion */
+ if (invert) {
+ if ((rv = luo->inv_lookup(luo, out, in)) > 1)
+ error ("%d, %s",xicco->errc,xicco->err);
+//printf("~1 %f: %f %f %f -> %f %f %f %f\n", ival, in[0], in[1], in[2], out[0], out[1], out[2], out[3]);
+ } else {
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",xicco->errc,xicco->err);
+ }
+
+ xx[i] = 100.0 * ival;
+ for (j = 0; j < outn; j++)
+ yy[j][i] = 100.0 * out[j];
+ }
+//fflush(stdout);
+
+ /* plot order: Black Red Green Blue Yellow Purple */
+ if (outs == icSigRgbData) {
+ do_plot6(xx, NULL, yy[0], yy[1], yy[2], NULL, NULL, XRES);
+
+ } else if (outs == icSigCmykData) {
+ do_plot6(xx, yy[3], yy[1], NULL, yy[0], yy[2], NULL, XRES);
+
+ } else {
+
+ switch(outn) {
+ case 1:
+ do_plot6(xx, yy[0], NULL, NULL, NULL, NULL, NULL, XRES);
+ break;
+ case 2:
+ do_plot6(xx, yy[0], yy[1], NULL, NULL, NULL, NULL, XRES);
+ break;
+ case 3:
+ do_plot6(xx, yy[0], yy[1], yy[2], NULL, NULL, NULL, XRES);
+ break;
+ case 4:
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], NULL, NULL, XRES);
+ break;
+ case 5:
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], NULL, XRES);
+ break;
+ case 6:
+ do_plot6(xx, yy[0], yy[1], yy[2], yy[3], yy[4], yy[5], XRES);
+ break;
+ }
+ }
+
+
+ } else {
+
+ if (slocwarn && outs != icSigXYZData
+ && outs != icSigYxyData
+ && outs != icSigLabData
+ && outs != icxSigLChData) {
+ error("Can't warn if outside spectrum locus unless XYZ like space");
+ }
+
+ /* Process colors to translate */
+ for (;;) {
+ int i,j;
+ char *bp, *nbp;
+ int outsloc = 0;
+
+ /* Read in the next line */
+ if (fgets(buf, 200, stdin) == NULL)
+ break;
+ if (buf[0] == '#') {
+ if (verb > 0)
+ fprintf(stdout,"%s\n",buf);
+ continue;
+ }
+ /* For each input number */
+ for (bp = buf-1, nbp = buf, i = 0; i < MAX_CHAN; i++) {
+ bp = nbp;
+ uout[i] = out[i] = in[i] = uin[i] = strtod(bp, &nbp);
+ if (nbp == bp)
+ break; /* Failed */
+ }
+ if (i == 0)
+ break;
+
+ /* If device data and scale */
+ if(scale > 0.0
+ && ins != icxSigJabData
+ && ins != icxSigJChData
+ && ins != icSigXYZData
+ && ins != icSigLabData
+ && ins != icxSigLChData
+ && ins != icSigLuvData
+ && ins != icSigYCbCrData
+ && ins != icSigYxyData
+ && ins != icSigHsvData
+ && ins != icSigHlsData) {
+ for (i = 0; i < MAX_CHAN; i++) {
+ in[i] /= scale;
+ }
+ }
+
+ if (repXYZ100 && ins == icSigXYZData) {
+ in[0] /= 100.0;
+ in[1] /= 100.0;
+ in[2] /= 100.0;
+ }
+
+ if (repYxy && ins == icSigYxyData) {
+ icmXYZ2Yxy(in, in);
+ }
+
+ /* JCh -> Jab & LCh -> Lab */
+ if ((repJCh && ins == icxSigJChData)
+ || (repLCh && ins == icxSigLChData)) {
+ double C = in[1];
+ double h = in[2];
+ in[1] = C * cos(3.14159265359/180.0 * h);
+ in[2] = C * sin(3.14159265359/180.0 * h);
+ }
+
+ /* Do conversion */
+ if (invert) {
+ for (j = 0; j < MAX_CHAN; j++)
+ out[j] = in[j]; /* Carry any auxiliary value to out for lookup */
+ if ((rv = luo->inv_lookup(luo, out, in)) > 1)
+ error ("%d, %s",xicco->errc,xicco->err);
+ } else {
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",xicco->errc,xicco->err);
+ }
+
+ if (slocwarn) {
+ double xyz[3];
+
+ if (outs == icSigLabData || outs == icxSigLChData)
+ icmLab2XYZ(&icmD50, out, xyz);
+ else
+ icmCpy3(xyz, out);
+
+ outsloc = icx_outside_spec_locus(xyz, icxOT_CIE_1931_2);
+ }
+
+ /* Copy conversion out value so that we can create user values */
+ for (i = 0; i < MAX_CHAN; i++)
+ uout[i] = out[i];
+
+ if (repXYZ100 && outs == icSigXYZData) {
+ uout[0] *= 100.0;
+ uout[1] *= 100.0;
+ uout[2] *= 100.0;
+ }
+
+ if (repYxy && outs == icSigYxyData) {
+ icmXYZ2Yxy(out, out);
+ }
+
+ /* Jab -> JCh and Lab -> LCh */
+ if ((repJCh && outs == icxSigJChData)
+ || (repLCh && outs == icxSigLChData)) {
+ double a = uout[1];
+ double b = uout[2];
+ uout[1] = sqrt(a * a + b * b);
+ uout[2] = (180.0/3.14159265359) * atan2(b, a);
+ uout[2] = (uout[2] < 0.0) ? uout[2] + 360.0 : uout[2];
+ }
+
+ /* If device data and scale */
+ if(scale > 0.0
+ && outs != icxSigJabData
+ && outs != icxSigJChData
+ && outs != icSigXYZData
+ && outs != icSigLabData
+ && outs != icxSigLChData
+ && outs != icSigLuvData
+ && outs != icSigYCbCrData
+ && outs != icSigYxyData
+ && outs != icSigHsvData
+ && outs != icSigHlsData) {
+ for (i = 0; i < MAX_CHAN; i++) {
+ uout[i] *= scale;
+ }
+ }
+
+ /* Output the results */
+ if (verb > 0) {
+ for (j = 0; j < inn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",uin[j]);
+ else
+ fprintf(stdout,"%f",uin[j]);
+ }
+ printf(" [%s] -> %s -> ", icx2str(icmColorSpaceSignature, ins),
+ icm2str(icmLuAlg, alg));
+ }
+
+ for (j = 0; j < outn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",uout[j]);
+ else
+ fprintf(stdout,"%f",uout[j]);
+ }
+ if (verb > 0)
+ printf(" [%s]", icx2str(icmColorSpaceSignature, outs));
+
+ if (verb > 0 && tlimit >= 0) {
+ double tot;
+ for (tot = 0.0, j = 0; j < outn; j++) {
+ tot += out[j];
+ }
+ printf(" Lim %f",tot);
+ }
+ if (outsloc)
+ fprintf(stdout,"(Imaginary)");
+
+ if (verb == 0 || rv == 0)
+ fprintf(stdout,"\n");
+ else {
+ fprintf(stdout," (clip)\n");
+
+ /* This probably isn't right - we need to convert */
+ /* in[] to Lab to Jab if it is not in that space, */
+ /* so we can do a delta E on it. */
+ if (actual && aluo != NULL) {
+ double cin[MAX_CHAN], de;
+ if ((rv = aluo->lookup(aluo, cin, out)) > 1)
+ error ("%d, %s",xicco->errc,xicco->err);
+
+ for (de = 0.0, j = 0; j < inn; j++) {
+ de += (cin[j] - in[j]) * (cin[j] - in[j]);
+ }
+ de = sqrt(de);
+ printf("[Actual ");
+ for (j = 0; j < inn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",cin[j]);
+ else
+ fprintf(stdout,"%f",cin[j]);
+ }
+ printf(", deltaE %f]\n",de);
+ }
+ }
+ }
+ }
+
+ /* Done with lookup object */
+ if (aluo != NULL && aluo != luo)
+ luo->del(aluo);
+ luo->del(luo);
+
+ xicco->del(xicco); /* Expansion wrapper */
+ icco->del(icco); /* Icc */
+ fp->del(fp);
+
+ return 0;
+}
+
diff --git a/xicc/xlut.c b/xicc/xlut.c
new file mode 100644
index 0000000..21c286e
--- /dev/null
+++ b/xicc/xlut.c
@@ -0,0 +1,4271 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 2/7/00
+ * Version: 1.00
+ *
+ * Copyright 2000, 2001 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.
+ *
+ * This is the third major version of xlut.c (originally called xlut2.c)
+ * Based on the old xlut.c code (preserved as xlut1.c)
+ * This version uses xfit.c to do the curve and rspl fitting.
+ */
+
+/*
+ * This module provides the expanded icclib functionality
+ * for lut based profiles.
+ * This file is #included in xicc.c, to keep its functions private.
+ *
+ * This version creates both input and output 1D luts by
+ * optimising the accuracy of the profile for a linear clut.
+ *
+ */
+
+/*
+ TTBD:
+
+ See gamut/gammap.c for notes on the desirability of
+ a non-minimum delta E colorimetric intent as the default.
+
+ Should fix gamut's so that they have enough information
+ to spefify a gamut mapping without the need for
+ a source colorspace profile, and fix the code
+ to work with just a gamut. This would take us further
+ towards supporting the PRMG reference gamut interoperability
+ as an option.
+
+ Should the input profile white point determination
+ be made a bit smarter about determining the chromaticity ?
+ ie. not take on the tint of the whitest patch, but an
+ average of neutral patches ?
+
+ Should xlutfix.c be revived (also adding ICM_CLUT_SET_APXLS support),
+ to improve "bumpy black" problem ?
+ */
+
+/*
+
+ NOTE :- an alternative to the way display profile absolute is handled here
+ would be to always chromatically adapt the illuminant to D50, and encode
+ that in the Chromatic adapation tag. To make absolute colorimetric
+ do anything useful though, the chromatic adapation tag would
+ have to be used for absolute intent.
+ This may be the way of improving compatibility with other systems,
+ but would break compatibility with existing Argyll profiles,
+ unless special measures are taken:
+
+ ie.
+
+ 1) if (display profile & using chromatic adaptation tag)
+ Create Bradford chromatic adapation matrix and store it in tag
+ Adapt all the readings using Bradford
+ Create white point and store it in tag (white point will be D50)
+ Adapt all the readings to the white point using wrong Von-Kries (no change)
+ Store relative colorimetric cLUT
+ Set version >= 2.4
+
+ else
+ 2) if (display scheme A or using Argyll historical printer scheme)
+ Create white point and store it in tag
+ Adapt all the readings to the white point using Bradford
+ Store relative colorimetric tag
+ Set version < 2.4 for V2 profile
+ Add private Absolute Transform Matrix (labels V4 profile)
+
+ 3) else (display scheme B or strict ICC printer compatibility)
+ Create white point and store it in tag
+ Adapt all the readings to the white point using Wrong Von-Kries
+ Store relative colorimetric tag
+ Set version >= 2.4
+
+
+ Argyll Processing for each type
+
+ 1) if display and chromatic adapation matrix
+ Un-adapt matrix or cLUT using wrong Von-Kries from white point
+ Un-adapt matrix or cLUT using chromatic matrix
+ Un-adapt apparant white point & black point using chromatic transform
+
+ if (not absolute intent)
+ Create Bradford transfor from white to PCS D50
+ Adapt all matrix or cLUT
+ else
+ 2) if (display scheme A or using Argyll < V2.4. profile
+ or find Absolute Transform Matrix)
+ if (absolute intent)
+ Un-adapt matrix or cLUT using Bradford from white point
+
+ 3) else (display scheme B or !Argyll profile or ( >= V2.4 profile
+ and !Absolute Transform Matrix))
+ Un-adapt matrix or cLUT using wrong Von-Kries from white point
+
+ if (not absolute intent)
+ Create Bradford transfor from white to PCS D50
+ Adapt all matrix or cLUT to white
+
+
+ The problem with this is that it wouldn't do the right thing on old Argyll
+ type profiles that weren't labeled or recognized.
+
+ Is there a way of recognizing Bradford Absolute transform Matricies if
+ the color chromaticities are given ?
+
+ */
+
+/*
+ A similar condrum is that it seems that an unwritten convention for
+ V2 profiles is to scale the black point of the perceptual and
+ saturation tables to 0 (Part of the V4 spec is to scale to Y = 3.1373).
+
+ To get better gamut mapping we should therefore unscale the perceptual
+ and saturation A2B table to have the same black point as the colorimetric
+ table before computing the gamut mapping, and then apply the opposite
+ transform to our perceptual B2A and A2B tables.
+
+ */
+
+/*
+ There is interesting behaviour for Jab 0,0,0 in, in that
+ it gets mapped to (something like) Lab -1899.019855 -213.574625 -231.914285
+ which after per-component clipping of the inv out tables looks like
+ 0, -128, -128, which may be mapped to (say) RGB 0.085455 1.000000 0.936951,
+ which is not black.
+
+ */
+
+#include "xfit.h"
+
+#undef USE_CIE94_DE /* [Undef] Use CIE94 delta E measure when creating in/out curves */
+ /* Don't use CIE94 because it makes peak error worse ? */
+
+#undef DEBUG /* [Undef] Verbose debug information */
+#undef CNDTRACE /* [Undef] Enable xicc->trace conditional verbosity */
+#undef DEBUG_OLUT /* [Undef] Print steps in overall fwd & rev lookups */
+#undef DEBUG_RLUT /* [Undef] Print values being reverse lookup up */
+#undef DEBUG_SPEC /* [Undef] Debug some specific cases */
+#undef INK_LIMIT_TEST /* [Undef] Turn off input tables for ink limit testing */
+#undef CHECK_ILIMIT /* [Undef] Do sanity checks on meeting ink limit */
+#undef WARN_CLUT_CLIPPING /* [Undef] Print warning if setting clut clips */
+#undef DISABLE_KCURVE_FILTER /* [Undef] don't filter the Kcurve */
+#undef REPORT_LOCUS_SEGMENTS /* [Undef[ Examine how many segments there are in aux inversion */
+
+#define SHP_SMOOTH 1.0 /* Input shaper curve smoothing */
+#define OUT_SMOOTH1 1.0 /* Output shaper curve smoothing for L*, X,Y,Z */
+#define OUT_SMOOTH2 1.0 /* Output shaper curve smoothing for a*, b* */
+
+#define CAMCLIPTRANS 1.0 /* [1.0] Cam clipping transition region Delta E */
+#define USECAMCLIPSPLINE /* [def] use spline blend */
+
+/*
+ * TTBD:
+ *
+ * Reverse lookup of Lab
+ * Make NEARCLIP the default ??
+ *
+ * XYZ vector clipping isn't implemented.
+ *
+ * Some of the error handling is crude. Shouldn't use
+ * error(), should return status.
+ */
+
+#ifndef _CAT2
+#define _CAT2(n1,n2) n1 ## n2
+#define CAT2(n1,n2) _CAT2(n1,n2)
+#endif
+
+
+
+static double icxLimitD(icxLuLut *p, double *in); /* For input' */
+#define icxLimitD_void ((double (*)(void *, double *))icxLimitD) /* Cast with void 1st arg */
+static double icxLimit(icxLuLut *p, double *in); /* For input */
+static int icxLuLut_init_clut_camclip(icxLuLut *p);
+
+/* Debug overall lookup */
+#ifdef DEBUG_OLUT
+#undef DBOL
+#ifdef CNDTRACE
+#define DBOL(xxx) if (p->trace) printf xxx ;
+#else
+#define DBOL(xxx) printf xxx ;
+#endif
+#else
+#undef DBOL
+#define DBOL(xxx)
+#endif
+
+/* Debug reverse lookup */
+#ifdef DEBUG_RLUT
+#undef DBR
+#ifdef CNDTRACE
+#define DBR(xxx) if (p->trace) printf xxx ;
+#else
+#define DBR(xxx) printf xxx ;
+#endif
+#else
+#undef DBR
+#define DBR(xxx)
+#endif
+
+/* Debug some specific cases (fwd_relpcs_outpcs, bwd_outpcs_relpcs) */
+#ifdef DEBUG_SPEC
+# undef DBS
+# ifdef CNDTRACE
+# define DBS(xxx) if (p->trace) printf xxx ;
+# else
+# define DBS(xxx) printf xxx ;
+# endif
+#else
+# undef DBS
+# define DBS(xxx)
+#endif
+
+/* ========================================================== */
+/* xicc lookup code. */
+/* ========================================================== */
+
+/* Forward and Backward Multi-Dimensional Interpolation type conversion */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* Components of overall lookup, in order */
+
+int icxLuLut_in_abs(icxLuLut *p, double *out, double *in) {
+ int rv = 0;
+
+ if (p->ins == icxSigJabData) {
+ DBOL(("xlut in_abs: CAM in = %s\n", icmPdv(p->inputChan, in)));
+ p->cam->cam_to_XYZ(p->cam, out, in);
+ DBOL(("xlut in_abs: XYZ = %s\n", icmPdv(p->inputChan, out)));
+ /* Hack to prevent CAM02 weirdness being amplified by inv_abs() */
+ /* or any later per channel clipping. */
+ /* Limit -Y to non-stupid values by scaling */
+ if (out[1] < -0.1) {
+ out[0] *= -0.1/out[1];
+ out[2] *= -0.1/out[1];
+ out[1] = -0.1;
+ DBOL(("xlut in_abs: after clipping -Y %s\n",icmPdv(p->outputChan, out)));
+ }
+ rv |= ((icmLuLut *)p->plu)->in_abs((icmLuLut *)p->plu, out, out);
+ DBOL(("xlut in_abs: XYZ out = %s\n", icmPdv(p->inputChan, out)));
+ } else {
+ DBOL(("xlut in_abs: PCS in = %s\n", icmPdv(p->inputChan, in)));
+ rv |= ((icmLuLut *)p->plu)->in_abs((icmLuLut *)p->plu, out, in);
+ DBOL(("xlut in_abs: PCS out = %s\n", icmPdv(p->inputChan, out)));
+ }
+
+ return rv;
+}
+
+/* Possible matrix lookup */
+/* input->input (not distinguishing matrix altered input values) */
+int icxLuLut_matrix(icxLuLut *p, double *out, double *in) {
+ int rv = 0;
+ rv |= ((icmLuLut *)p->plu)->matrix((icmLuLut *)p->plu, out, in);
+ return rv;
+}
+
+/* Do input -> input' lookup */
+int icxLuLut_input(icxLuLut *p, double *out, double *in) {
+#ifdef NEVER
+ return ((icmLuLut *)p->plu)->input((icmLuLut *)p->plu, out, in);
+#else
+ int rv = 0;
+ co tc;
+ int i;
+ for (i = 0; i < p->inputChan; i++) {
+ tc.p[0] = in[i];
+ rv |= p->inputTable[i]->interp(p->inputTable[i], &tc);
+ out[i] = tc.v[0];
+ }
+ return rv;
+#endif
+}
+
+/* Do input'->output' lookup, with aux' return */
+/* (The aux' is just extracted from the in' values) */
+int icxLuLut_clut_aux(icxLuLut *p,
+double *out, /* output' value */
+double *oink, /* If not NULL, return amount input is over the ink limit, 0 if not */
+double *auxv, /* If not NULL, return aux value used (packed) */
+double *in /* input' value */
+) {
+ int rv = 0;
+ co tc;
+ int i;
+
+ for (i = 0; i < p->inputChan; i++)
+ tc.p[i] = in[i];
+ rv |= p->clutTable->interp(p->clutTable, &tc);
+ for (i = 0; i < p->outputChan; i++)
+ out[i] = tc.v[i];
+
+ if (auxv != NULL) {
+ int ee = 0;
+ for (i = 0; i < p->clutTable->di; i++) {
+ double v = in[i];
+ if (p->auxm[i] != 0) {
+ auxv[ee] = v;
+ ee++;
+ }
+ }
+ }
+
+ if (oink != NULL) {
+ double lim = 0.0;
+
+ if (p->ink.tlimit >= 0.0 || p->ink.klimit >= 0.0) {
+ lim = icxLimitD(p, in);
+ if (lim < 0.0)
+ lim = 0.0;
+ }
+ *oink = lim;
+ }
+
+ return rv;
+}
+
+/* Do input'->output' lookup */
+int icxLuLut_clut(icxLuLut *p, double *out, double *in) {
+#ifdef NEVER
+ return ((icmLuLut *)p->plu)->clut((icmLuLut *)p->plu, out, in);
+#else
+ return icxLuLut_clut_aux(p, out, NULL, NULL, in);
+#endif
+}
+
+/* Do output'->output lookup */
+int icxLuLut_output(icxLuLut *p, double *out, double *in) {
+ int rv = 0;
+
+ if (p->mergeclut == 0) {
+#ifdef NEVER
+ rv = ((icmLuLut *)p->plu)->output((icmLuLut *)p->plu, out, in);
+#else
+ co tc;
+ int i;
+ for (i = 0; i < p->outputChan; i++) {
+ tc.p[0] = in[i];
+ rv |= p->outputTable[i]->interp(p->outputTable[i], &tc);
+ out[i] = tc.v[0];
+ }
+#endif
+ } else {
+ int i;
+ for (i = 0; i < p->outputChan; i++)
+ out[i] = in[i];
+ }
+ return rv;
+}
+
+/* Relative to absolute conversion + PCS to PCS override (Effective PCS) conversion */
+int icxLuLut_out_abs(icxLuLut *p, double *out, double *in) {
+ int rv = 0;
+ if (p->mergeclut == 0) {
+ DBOL(("xlut out_abs: PCS in = %s\n", icmPdv(p->outputChan, in)));
+
+ rv |= ((icmLuLut *)p->plu)->out_abs((icmLuLut *)p->plu, out, in);
+
+ DBOL(("xlut out_abs: ABS PCS out = %s\n", icmPdv(p->outputChan, out)));
+
+ if (p->outs == icxSigJabData) {
+ p->cam->XYZ_to_cam(p->cam, out, out);
+
+ DBOL(("xlut out_abs: CAM out = %s\n", icmPdv(p->outputChan, out)));
+ }
+ } else {
+ int i;
+ for (i = 0; i < p->outputChan; i++)
+ out[i] = in[i];
+ }
+
+ return rv;
+}
+
+/* Overall lookup */
+static int
+icxLuLut_lookup (
+icxLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ icxLuLut *p = (icxLuLut *)pp;
+ int rv = 0;
+ double temp[MAX_CHAN];
+
+ DBOL(("xicclu: in = %s\n", icmPdv(p->inputChan, in)));
+ rv |= p->in_abs (p, temp, in);
+ DBOL(("xicclu: after abs = %s\n", icmPdv(p->inputChan, temp)));
+ rv |= p->matrix (p, temp, temp);
+ DBOL(("xicclu: after matrix = %s\n", icmPdv(p->inputChan, temp)));
+ rv |= p->input (p, temp, temp);
+ DBOL(("xicclu: after inout = %s\n", icmPdv(p->inputChan, temp)));
+ rv |= p->clut (p, out, temp);
+ DBOL(("xicclu: after clut = %s\n", icmPdv(p->outputChan, out)));
+ if (p->mergeclut == 0) {
+ rv |= p->output (p, out, out);
+ DBOL(("xicclu: after output = %s\n", icmPdv(p->outputChan, out)));
+ rv |= p->out_abs (p, out, out);
+ DBOL(("xicclu: after outabs = %s\n", icmPdv(p->outputChan, out)));
+ }
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given a relative XYZ or Lab PCS value, convert in the fwd direction into */
+/* the nominated output PCS (ie. Absolute, Jab etc.) */
+/* (This is used in generating gamut compression in B2A tables) */
+void icxLuLut_fwd_relpcs_outpcs(
+icxLuBase *pp,
+icColorSpaceSignature is, /* Input space, XYZ or Lab */
+double *out, double *in) {
+ icxLuLut *p = (icxLuLut *)pp;
+
+
+ /* Convert to the ICC PCS */
+ if (is == icSigLabData && p->natpcs == icSigXYZData) {
+ DBS(("fwd_relpcs_outpcs: Lab in = %s\n", icmPdv(p->inputChan, in)));
+ icmLab2XYZ(&icmD50, out, in);
+ DBS(("fwd_relpcs_outpcs: XYZ = %s\n", icmPdv(p->inputChan, out)));
+ } else if (is == icSigXYZData && p->natpcs == icSigLabData) {
+ DBS(("fwd_relpcs_outpcs: XYZ in = %s\n", icmPdv(p->inputChan, in)));
+ icmXYZ2Lab(&icmD50, out, in);
+ DBS(("fwd_relpcs_outpcs: Lab = %s\n", icmPdv(p->inputChan, out)));
+ } else {
+ DBS(("fwd_relpcs_outpcs: PCS in = %s\n", icmPdv(p->inputChan, in)));
+ icmCpy3(out, in);
+ }
+
+ /* Convert to absolute */
+ ((icmLuLut *)p->plu)->out_abs((icmLuLut *)p->plu, out, out);
+
+ DBS(("fwd_relpcs_outpcs: abs PCS = %s\n", icmPdv(p->inputChan, out)));
+
+ if (p->outs == icxSigJabData) {
+
+ /* Convert to CAM */
+ p->cam->XYZ_to_cam(p->cam, out, out);
+
+ DBS(("fwd_relpcs_outpcs: Jab = %s\n", icmPdv(p->inputChan, out)));
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Components of inverse lookup, in order */
+
+/* Utility function - compute the clip vector direction. */
+/* return NULL if vector clip isn't used. */
+double *icxClipVector(
+icxClip *p, /* Clipping setup information */
+double *in, /* Target point */
+double *cdirv /* Space for returned clip vector */
+) {
+ int f;
+ if (p->nearclip != 0)
+ return NULL; /* Doing nearest clipping, not vector */
+
+ /* Default is simple vector clip */
+ for (f = 0; f < p->fdi; f++)
+ cdirv[f] = p->ocent[f] - in[f]; /* Clip towards output gamut center */
+
+ if (p->ocentl != 0.0) { /* Graduated vector clip */
+ double cvl, nll;
+
+ /* Compute (negative) clip vector length */
+ for (cvl = 0.0, f = 0; f < p->fdi; f++) {
+ cvl += cdirv[f] * cdirv[f];
+ }
+ cvl = sqrt(cvl);
+ if (cvl > 1e-8) {
+ /* Dot product of clip vector and clip center line */
+ for (nll = 0.0, f = 0; f < p->fdi; f++)
+ nll -= cdirv[f] * p->ocentv[f]; /* (Fix -ve clip vector) */
+ nll /= (p->ocentl * p->ocentl); /* Normalised location along line */
+
+ /* Limit to line */
+ if (nll < 0.0)
+ nll = 0.0;
+ else if (nll > 1.0)
+ nll = 1.0;
+
+ if (p->LabLike) {
+ /* Aim more towards center for saturated targets */
+ double sat = sqrt(in[1] * in[1] + in[2] * in[2]);
+ nll += sat/150.0 * (0.5 - nll);
+ }
+
+ /* Compute target clip direction */
+ for (f = 0; f < p->fdi; f++)
+ cdirv[f] = p->ocent[f] + nll * p->ocentv[f] - in[f];
+ }
+ }
+
+ return cdirv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Typically inv is used to invert a device->PCS table, */
+/* so it is doing a PCS->device conversion. */
+/* This doesn't always have to be the case though. */
+
+/* PCS override (Effective PCS) to PCS conversion + absolute to relative conversion */
+int icxLuLut_inv_out_abs(icxLuLut *p, double *out, double *in) {
+ int rv = 0;
+
+ DBR(("\nicxLuLut_inv_out_abs got PCS %s\n",icmPdv(p->outputChan, in)));
+
+ if (p->mergeclut == 0) {
+ if (p->outs == icxSigJabData) {
+ p->cam->cam_to_XYZ(p->cam, out, in);
+ DBR(("icxLuLut_inv_out_abs after cam2XYZ %s\n",icmPdv(p->outputChan, out)));
+ /* Hack to prevent CAM02 weirdness being amplified by inv_out_abs() */
+ /* or per channel clipping. */
+ /* Limit -Y to non-stupid values by scaling */
+ if (out[1] < -0.1) {
+ out[0] *= -0.1/out[1];
+ out[2] *= -0.1/out[1];
+ out[1] = -0.1;
+ DBR(("icxLuLut_inv_out_abs after clipping -Y %s\n",icmPdv(p->outputChan, out)));
+ }
+ rv |= ((icmLuLut *)p->plu)->inv_out_abs((icmLuLut *)p->plu, out, out);
+ DBR(("icxLuLut_inv_out_abs after icmLut inv_out_abs %s\n",icmPdv(p->outputChan, out)));
+ } else {
+ rv |= ((icmLuLut *)p->plu)->inv_out_abs((icmLuLut *)p->plu, out, in);
+ DBR(("icxLuLut_inv_out_abs after icmLut inv_out_abs %s\n",icmPdv(p->outputChan, out)));
+ }
+ } else {
+ int i;
+ for (i = 0; i < p->outputChan; i++)
+ out[i] = in[i];
+ }
+ DBR(("icxLuLut_inv_out_abs returning PCS %f %f %f\n",out[0],out[1],out[2]))
+ return rv;
+}
+
+/* Do output->output' inverse lookup */
+int icxLuLut_inv_output(icxLuLut *p, double *out, double *in) {
+ int rv = 0;
+ DBR(("icxLuLut_inv_output got PCS %f %f %f\n",in[0],in[1],in[2]))
+ if (p->mergeclut == 0) {
+#ifdef NEVER
+ rv = ((icmLuLut *)p->plu)->inv_output((icmLuLut *)p->plu, out, in);
+#else
+ int i,j;
+ int nsoln; /* Number of solutions found */
+ co pp[MAX_INVSOLN]; /* Room for all the solutions found */
+ double cdir;
+
+ for (i = 0; i < p->outputChan; i++) {
+ pp[0].p[0] = p->outputClipc[i];
+ pp[0].v[0] = in[i];
+ cdir = p->outputClipc[i] - in[i]; /* Clip towards output range */
+
+ nsoln = p->outputTable[i]->rev_interp (
+ p->outputTable[i], /* this */
+ RSPL_NEARCLIP, /* Clip to nearest (faster than vector) */
+ MAX_INVSOLN, /* Maximum number of solutions allowed for */
+ NULL, /* No auxiliary input targets */
+ &cdir, /* Clip vector direction and length */
+ pp); /* Input and output values */
+
+ if (nsoln & RSPL_DIDCLIP)
+ rv = 1;
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln == 1) { /* Exactly one solution */
+ j = 0;
+ } else if (nsoln == 0) { /* Zero solutions. This is unexpected. */
+ error("xlut: Unexpected failure to find reverse solution for output table");
+ return 2;
+ } else { /* Multiple solutions */
+ /* Use a simple minded resolution - choose the one closest to the center */
+ double bdist = 1e300;
+ int bsoln = 0;
+ /* Don't expect this - 1D luts are meant to be monotonic */
+ warning("1D lut inversion got %d reverse solutions\n",nsoln);
+ warning("solution 0 = %f\n",pp[0].p[0]);
+ warning("solution 1 = %f\n",pp[1].p[0]);
+ for (j = 0; j < nsoln; j++) {
+ double tt;
+ tt = pp[i].p[0] - p->outputClipc[i];
+ tt *= tt;
+ if (tt < bdist) { /* Better solution */
+ bdist = tt;
+ bsoln = j;
+ }
+ }
+ j = bsoln;
+ }
+ out[i] = pp[j].p[0];
+ }
+
+#endif /* NEVER */
+ } else {
+ int i;
+ for (i = 0; i < p->outputChan; i++)
+ out[i] = in[i];
+ }
+ DBR(("icxLuLut_inv_output returning PCS' %f %f %f\n",out[0],out[1],out[2]))
+ return rv;
+}
+
+/* Ink limit+gamut limit calculation function for xLuLut. */
+/* Returns < 0.0 if input value is within limits, */
+/* > 0.0 if outside limits. Value is proportinal to distance to limits. */
+/* We implement device gamut check to improve utility outside rspl, */
+/* in optimisation routines. */
+/* The limits are assumed to be post calibrated device values (ie. real */
+/* final device values) */
+static double icxLimit(
+icxLuLut *p,
+double *in
+) {
+ double cin[MAX_CHAN]; /* Calibrated input values */
+ double tlim, klim;
+ double ovr, val;
+ int e;
+
+ if (p->pp->cal != NULL) { /* We have device calibration information */
+ p->pp->cal->interp(p->pp->cal, cin, in);
+ } else {
+ for (e = 0; e < p->inputChan; e++)
+ cin[e] = in[e];
+ }
+
+ if ((tlim = p->ink.tlimit) < 0.0)
+ tlim = (double)p->inputChan; /* Default is no limit */
+
+ if ((klim = p->ink.klimit) < 0.0)
+ klim = 1.0;
+
+ /* Compute amount outside total limit */
+ { /* No calibration */
+ double sum;
+ for (sum = 0.0, e = 0; e < p->inputChan; e++)
+ sum += cin[e];
+ val = sum - tlim;
+ }
+
+ /* Compute amount outside black limit */
+ if (p->ink.klimit >= 0.0) {
+ double kval = 0.0;
+ switch(p->natis) {
+ case icSigCmykData:
+ kval = cin[3] - klim;
+ break;
+ default:
+ /* NOTE !!! p->kch isn't being initialized !!! */
+ if (p->kch >= 0) {
+ kval = cin[p->kch] - klim;
+ } else {
+ error("xlut: Unknown colorspace when black limit specified");
+ }
+ }
+ if (kval > val)
+ val = kval;
+ }
+ /* Compute amount outside device value limits 0.0 - 1.0 */
+ for (ovr = -1.0, e = 0; e < p->inputChan; e++) {
+ if (in[e] < 0.0) { /* ! Not cin[] */
+ if (-in[e] > ovr)
+ ovr = -in[e];
+ } else if (in[e] > 1.0) {
+ if ((in[e] - 1.0) > ovr)
+ ovr = in[e] - 1.0;
+ }
+ }
+ if (ovr > val)
+ val = ovr;
+
+ return val;
+}
+
+/* Same as above, but works with input' values */
+/* (If an ink limit is being used we assume that the */
+/* input space is not PCS, hence inv_in_abs() is doing nothing) */
+static double icxLimitD(
+icxLuLut *p,
+double *ind
+) {
+ double in[MAX_CHAN];
+ co tc;
+ int e;
+
+ /* Convert input' to input through revinput Luts (for speed) */
+ for (e = 0; e < p->inputChan; e++) {
+ tc.p[0] = ind[e];
+ p->revinputTable[e]->interp(p->revinputTable[e], &tc);
+ in[e] = tc.v[0];
+ }
+
+ return icxLimit(p, in);
+}
+
+/* Ink limit+gamut limit clipping function for xLuLut (CMYK). */
+/* Return nz if there was clipping */
+static int icxDoLimit(
+icxLuLut *p,
+double *out,
+double *in
+) {
+ double tlim, klim = -1.0;
+ double sum;
+ int clip = 0, e;
+ int kch = -1;
+
+ for (e = 0; e < p->inputChan; e++)
+ out[e] = in[e];
+
+ if ((tlim = p->ink.tlimit) < 0.0)
+ tlim = (double)p->inputChan;
+
+ if ((klim = p->ink.klimit) < 0.0)
+ klim = 1.0;
+
+ /* Clip black */
+ if (p->natis == icSigCmykData)
+ kch = 3;
+ else
+ kch = p->kch;
+
+ if (kch >= 0) {
+ if (out[p->kch] > klim) {
+ out[p->kch] = klim;
+ clip = 1;
+ }
+ }
+
+ /* Compute amount outside total limit */
+ for (sum = 0.0, e = 0; e < p->inputChan; e++)
+ sum += out[e];
+
+ if (sum > tlim) {
+ clip = 1;
+ sum /= (double)p->inputChan;
+ for (e = 0; e < p->inputChan; e++)
+ out[e] -= sum;
+ }
+ return clip;
+}
+
+#ifdef NEVER
+#undef DBK
+#define DBK(xxx) printf xxx ;
+#else
+#undef DBK
+#define DBK(xxx)
+#endif
+
+/* helper function that creates our standard K locus curve value, */
+/* given the curve parameters, and the normalised L 0.0 - 1.0 value. */
+/* No filtering version. */
+/* !!! Should add K limit in here so that smoothing takes it into account !!! */
+static double icxKcurveNF(double L, icxInkCurve *c) {
+ double Kstpo, Kenpo, Kstle, Kenle;
+ double rv;
+
+ DBK(("icxKcurve got L = %f, smth %f skew %f, Parms %f %f %f %f %f\n",L, c->Ksmth, c->Kskew, c->Kstle, c->Kstpo, c->Kenpo, c->Kenle, c->Kshap));
+
+ /* Invert sense of L, so that 0.0 = white, 1.0 = black */
+ L = 1.0 - L;
+
+ /* Clip L, just in case */
+ if (L < 0.0) {
+ L = 0.0;
+ } else if (L > 1.0) {
+ L = 1.0;
+ }
+ DBK(("Clipped inverted L = %f\n",L));
+
+ /* Make sure breakpoints are ordered */
+ if (c->Kstpo < c->Kenpo) {
+ Kstle = c->Kstle;
+ Kstpo = c->Kstpo;
+ Kenpo = c->Kenpo;
+ Kenle = c->Kenle;
+ } else { /* They're swapped */
+ Kstle = c->Kenle;
+ Kstpo = c->Kenpo;
+ Kenpo = c->Kstpo;
+ Kenle = c->Kstle;
+ }
+
+ if (L <= Kstpo) {
+ /* We are at white level */
+ rv = Kstle;
+ DBK(("At white level %f\n",rv));
+ } else if (L >= Kenpo) {
+ /* We are at black level */
+ rv = Kenle;
+ DBK(("At black level %f\n",rv));
+ } else {
+ double Lp, g;
+ /* We must be on the curve from start to end levels */
+
+ Lp = (L - Kstpo)/(Kenpo - Kstpo);
+
+ DBK(("Curve position %f\n",Lp));
+
+ Lp = pow(Lp, c->Kskew);
+
+ DBK(("Skewed curve position %f\n",Lp));
+
+ g = c->Kshap/2.0;
+ DBK(("Curve bf %f, g %g\n",Lp,g));
+
+ /* A value of 0.5 will be tranlated to g */
+ Lp = Lp/((1.0/g - 2.0) * (1.0 - Lp) + 1.0);
+
+ DBK(("Skewed shaped %f\n",Lp));
+
+ Lp = pow(Lp, 1.0/c->Kskew);
+
+ DBK(("Shaped %f\n",Lp));
+
+ /* Transition between start end end levels */
+ rv = Lp * (Kenle - Kstle) + Kstle;
+
+ DBK(("Scaled to start and end levele %f\n",rv));
+ }
+
+ DBK(("Returning %f\n",rv));
+ return rv;
+}
+
+#ifdef DBK
+#undef DBK
+#define DBK(xxx)
+#endif
+
+
+#ifdef NEVER
+#undef DBK
+#define DBK(xxx) printf xxx ;
+#else
+#undef DBK
+#define DBK(xxx)
+#endif
+
+/* Same as above, but implement transition filters accross inflection points. */
+/* (The convolultion filter previously used could be */
+/* re-instituted if something was done about compressing */
+/* the filter at the boundaries so that the levels are met.) */
+static double icxKcurve(double L, icxInkCurve *c) {
+
+#ifdef DISABLE_KCURVE_FILTER
+ return icxKcurveNF(L, c);
+
+#else /* !DISABLE_KCURVE_FILTER */
+
+ double Kstpo, Kenpo, Kstle, Kenle, Ksmth;
+ double rv;
+
+ DBK(("icxKcurve got L = %f, smth %f skew %f, Parms %f %f %f %f %f\n",L, c->Ksmth, c->Kskew, c->Kstle, c->Kstpo, c->Kenpo, c->Kenle, c->Kshap));
+
+ /* Invert sense of L, so that 0.0 = white, 1.0 = black */
+ L = 1.0 - L;
+
+ /* Clip L, just in case */
+ if (L < 0.0) {
+ L = 0.0;
+ } else if (L > 1.0) {
+ L = 1.0;
+ }
+ DBK(("Clipped inverted L = %f\n",L));
+
+ /* Make sure breakpoints are ordered */
+ if (c->Kstpo < c->Kenpo) {
+ Kstle = c->Kstle;
+ Kstpo = c->Kstpo;
+ Kenpo = c->Kenpo;
+ Kenle = c->Kenle;
+ } else { /* They're swapped */
+ Kstle = c->Kenle;
+ Kstpo = c->Kenpo;
+ Kenpo = c->Kstpo;
+ Kenle = c->Kstle;
+ }
+ Ksmth = c->Ksmth;
+
+ /* Curve value at point */
+ rv = icxKcurveNF(1.0 - L, c);
+
+ DBK(("Raw output at iL = %f, rv\n",L));
+
+ /* Create filtered value */
+ {
+ double wbs, wbe; /* White transitioin start, end */
+ double wbl, wfv; /* White blend factor, value at filter band */
+
+ double mt; /* Middle of the two transitions */
+
+ double bbs, bbe; /* Black transitioin start, end */
+ double bbl, bfv; /* Black blend factor, value at filter band */
+
+ wbs = Kstpo - Ksmth;
+ wbe = Kstpo + Ksmth;
+
+ bbs = Kenpo - 1.0 * Ksmth;
+ bbe = Kenpo + 1.0 * Ksmth;
+
+ mt = 0.5 * (wbe + bbs);
+
+ /* Make sure that the whit & black transition regions */
+ /* don't go out of bounts or overlap */
+ if (wbs < 0.0) {
+ wbe += wbs;
+ wbs = 0.0;
+ }
+ if (bbe > 1.0) {
+ bbs += (bbe - 1.0);
+ bbe = 1.0;
+ }
+
+ if (wbe > mt) {
+ wbs += (wbe - mt);
+ wbe = mt;
+ }
+
+ if (bbs < mt) {
+ bbe += (mt - bbs);
+ bbs = mt;
+ }
+
+ DBK(("Transition windows %f - %f, %f - %f\n",wbs, wbe, bbw, bbe));
+ if (wbs < wbe) {
+ wbl = (L - wbe)/(wbs - wbe);
+
+ if (wbl > 0.0 && wbl < 1.0) {
+ wfv = icxKcurveNF(1.0 - wbe, c);
+ DBK(("iL = %f, wbl = %f, wfv = %f\n",L,Kstpo,wbl,wfv));
+
+ wbl = 1.0 - pow(1.0 - wbl, 2.0);
+ rv = wbl * Kstle + (1.0 - wbl) * wfv;
+ }
+ }
+ if (bbs < bbe) {
+ bbl = (L - bbe)/(bbs - bbe);
+
+ if (bbl > 0.0 && bbl < 1.0) {
+ bfv = icxKcurveNF(1.0 - bbs, c);
+ DBK(("iL = %f, bbl = %f, bfv = %f\n",L,Kstpo,bbl,bfv));
+
+ bbl = pow(bbl, 2.0);
+ rv = bbl * bfv + (1.0 - bbl) * Kenle;
+ }
+ }
+ }
+
+ /* To be safe */
+ if (rv < 0.0)
+ rv = 0.0;
+ else if (rv > 1.0)
+ rv = 1.0;
+
+ DBK(("Returning %f\n",rv));
+ return rv;
+#endif /* !DISABLE_KCURVE_FILTER */
+}
+
+#ifdef DBK
+#undef DBK
+#define DBK(xxx)
+#endif
+
+/* Do output'->input' lookup with aux details. */
+/* Note that out[] will be used as the inking value if icxKrule is */
+/* icxKvalue, icxKlocus, icxKl5l or icxKl5lk, and that the auxiliar values, PCS ranges */
+/* and icxKrule value will all be evaluated in output->input space (not ' space). */
+/* Note that the ink limit will be computed after converting input' to input, auxt */
+/* will override the inking rule, and auxr[] reflects the available auxiliary range */
+/* that the locus was to choose from, and auxv[] was the actual auxiliary used. */
+/* Returns clip status. */
+int icxLuLut_inv_clut_aux(
+icxLuLut *p,
+double *out, /* Function return values, plus aux value or locus target input if auxt == NULL */
+double *auxv, /* If not NULL, return aux value used (packed) */
+double *auxr, /* If not NULL, return aux locus range (packed, 2 at a time) */
+double *auxt, /* If not NULL, specify the aux target for this lookup (override ink) */
+double *clipd, /* If not NULL, return DE to gamut on clipi, 0 for not clip */
+double *in /* Function input values to invert (== clut output' values) */
+) {
+ co pp[MAX_INVSOLN]; /* Room for all the solutions found */
+ int nsoln; /* Number of solutions found */
+ double *cdir, cdirv[MXDO]; /* Clip vector direction and length */
+ int e,f,i;
+ int fdi = p->clutTable->fdi;
+ int flags = 0; /* reverse interp flags */
+ int xflags = 0; /* extra clip/noclip flags */
+ double tin[MXDO]; /* PCS value to be inverted */
+ double cdist = 0.0; /* clip DE */
+ int crv = 0; /* Return value - set to 1 if clipped */
+
+ if (p->nearclip != 0)
+ flags |= RSPL_NEARCLIP; /* Use nearest clipping rather than clip vector */
+
+ DBR(("inv_clut_aux input is %f %f %f\n",in[0], in[1], in[2]))
+
+ if (auxr != NULL) { /* Set a default locus range */
+ int ee = 0;
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ auxr[ee++] = 1e60;
+ auxr[ee++] = -1e60;
+ }
+ }
+ }
+
+ /* Setup for reverse lookup */
+ for (f = 0; f < fdi; f++)
+ pp[0].v[f] = in[f]; /* Target value */
+
+ /* Compute clip vector, if any */
+ cdir = icxClipVector(&p->clip, in, cdirv);
+
+ if (p->clutTable->di > fdi) { /* ie. CMYK->Lab, there will be ambiguity */
+ double min[MXDI], max[MXDI]; /* Auxiliary locus range */
+
+#ifdef REPORT_LOCUS_SEGMENTS /* Examine how many segments there are */
+ { /* ie. CMYK->Lab, there will be ambiguity */
+ double smin[10][MXRI], smax[10][MXRI]; /* Auxiliary locus segment ranges */
+ double min[MXRI], max[MXRI]; /* Auxiliary min and max locus range */
+
+ nsoln = p->clutTable->rev_locus_segs(
+ p->clutTable, /* rspl object */
+ p->auxm, /* Auxiliary mask */
+ pp, /* Input target and output solutions */
+ 10, /* Maximum number of solutions to return */
+ smin, smax); /* Returned locus of valid auxiliary values */
+
+ if (nsoln != 0) {
+ /* Convert the locuses from input' -> input space */
+ /* and get overall min/max locus range */
+ for (e = 0; e < p->clutTable->di; e++) {
+ co tc;
+ /* (Is speed more important than precision ?) */
+ if (p->auxm[e] != 0) {
+ for (i = 0; i < nsoln; i++) {
+ tc.p[0] = smin[i][e];
+ p->revinputTable[e]->interp(p->revinputTable[e], &tc);
+ smin[i][e] = tc.v[0];
+ tc.p[0] = smax[i][e];
+ p->revinputTable[e]->interp(p->revinputTable[e], &tc);
+ smax[i][e] = tc.v[0];
+ printf(" Locus seg %d:[%d] %f -> %f\n",i, e, smin[i][e], smax[i][e]);
+ }
+ }
+ }
+ }
+ }
+#endif /* REPORT_LOCUS_SEGMENTS */
+
+ /* Compute auxiliary locus on the fly. This is in dev' == input' space. */
+ nsoln = p->clutTable->rev_locus(
+ p->clutTable, /* rspl object */
+ p->auxm, /* Auxiliary mask */
+ pp, /* Input target and output solutions */
+ min, max); /* Returned locus of valid auxiliary values */
+
+ if (nsoln == 0) {
+ xflags |= RSPL_WILLCLIP; /* No valid locus, so we expect to have to clip */
+#ifdef DEBUG_RLUT
+ printf("inv_clut_aux: no valid locus, expect clip\n");
+#endif
+ /* Make sure that the auxiliar value is initialized, */
+ /* even though it won't have any effect. */
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ pp[0].p[e] = 0.5;
+ }
+ }
+
+ } else { /* Got a valid locus */
+
+ /* Convert the locuses from input' -> input space */
+ for (e = 0; e < p->clutTable->di; e++) {
+ co tc;
+ /* (Is speed more important than precision ?) */
+ if (p->auxm[e] != 0) {
+ tc.p[0] = min[e];
+ p->revinputTable[e]->interp(p->revinputTable[e], &tc);
+ min[e] = tc.v[0];
+ tc.p[0] = max[e];
+ p->revinputTable[e]->interp(p->revinputTable[e], &tc);
+ max[e] = tc.v[0];
+ }
+ }
+
+ if (auxr != NULL) { /* Report the locus range */
+ int ee = 0;
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ auxr[ee++] = min[e];
+ auxr[ee++] = max[e];
+ }
+ }
+ }
+
+ if (auxt != NULL) { /* overiding auxiliary target */
+ int ee = 0;
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ double iv = auxt[ee++];
+ if (iv < min[e])
+ iv = min[e];
+ else if (iv > max[e])
+ iv = max[e];
+ pp[0].p[e] = iv;
+ }
+ }
+ DBR(("inv_clut_aux: aux %f from auxt[] %f\n",pp[0].p[3],auxt[0]))
+ } else if (p->ink.k_rule == icxKvalue) {
+ /* Implement the auxiliary inking rule */
+ /* Target auxiliary values are provided in out[] K value */
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ double iv = out[e]; /* out[] holds aux target value */
+ if (iv < min[e])
+ iv = min[e];
+ else if (iv > max[e])
+ iv = max[e];
+ pp[0].p[e] = iv;
+ }
+ }
+ DBR(("inv_clut_aux: aux %f from out[0] K target %f min %f max %f\n",pp[0].p[3],out[3],min[3],max[3]))
+ } else if (p->ink.k_rule == icxKlocus) {
+ /* Set target auxliary input values from values in out[] and locus */
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ double ii, iv;
+ ii = out[e]; /* Input ink locus */
+ iv = min[e] + ii * (max[e] - min[e]); /* Output ink from locus */
+ if (iv < min[e])
+ iv = min[e];
+ else if (iv > max[e])
+ iv = max[e];
+ pp[0].p[e] = iv;
+ }
+ }
+ DBR(("inv_clut_aux: aux %f from out[0] locus %f min %f max %f\n",pp[0].p[3],out[3],min[3],max[3]))
+ } else { /* p->ink.k_rule == icxKluma5 || icxKluma5k || icxKl5l || icxKl5lk */
+ /* Auxiliaries are driven by a rule and the output values */
+ double rv, L;
+
+ /* If we've got a mergeclut, then the PCS' is the same as the */
+ /* effective PCS, and we need to convert to native PCS */
+ if (p->mergeclut) {
+ p->mergeclut = 0; /* Hack to be able to use inv_out_abs() */
+ icxLuLut_inv_out_abs(p, tin, in);
+ p->mergeclut = 1;
+
+ } else {
+ /* Convert native PCS' to native PCS values */
+ p->output(p, tin, in);
+ }
+
+ /* Figure out Luminance number */
+ if (p->natos == icSigXYZData) {
+ icmXYZ2Lab(&icmD50, tin, tin);
+ } else if (p->natos != icSigLabData) { /* Hmm. that's unexpected */
+ error("Assert: xlut K locus, unexpected native pcs of 0x%x\n",p->natos);
+ }
+ L = 0.01 * tin[0];
+ DBR(("inv_clut_aux: aux from Luminance, raw L = %f\n",L));
+
+ /* Normalise L to its possible range from min to max */
+ L = (L - p->Lmin)/(p->Lmax - p->Lmin);
+ DBR(("inv_clut_aux: Normalize L = %f\n",L));
+
+ /* Convert L to curve value */
+ rv = icxKcurve(L, &p->ink.c);
+ DBR(("inv_clut_aux: icxKurve lookup returns = %f\n",rv));
+
+ if (p->ink.k_rule == icxKluma5) { /* Curve is locus value */
+
+ /* Set target black as K fraction within locus */
+
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ pp[0].p[e] = min[e] + rv * (max[e] - min[e]);
+ }
+ }
+ DBR(("inv_clut_aux: aux %f from locus %f min %f max %f\n",pp[0].p[3],rv,min[3],max[3]))
+
+ } else if (p->ink.k_rule == icxKluma5k) { /* Curve is K value */
+
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ double iv = rv;
+ if (iv < min[e]) /* Clip to locus */
+ iv = min[e];
+ else if (iv > max[e])
+ iv = max[e];
+ pp[0].p[e] = iv;
+ }
+ }
+ DBR(("inv_clut_aux: aux %f from out[0] K target %f min %f max %f\n",pp[0].p[3],rv,min[3],max[3]))
+
+ } else { /* icxKl5l || icxKl5lk */
+ /* Create second curve, and use input locus to */
+ /* blend between */
+
+ double rv2; /* Upper limit */
+
+ /* Convert L to max curve value */
+ rv2 = icxKcurve(L, &p->ink.x);
+
+ if (rv2 < rv) { /* Ooops - better swap. */
+ double tt;
+ tt = rv;
+ rv = rv2;
+ rv2 = tt;
+ }
+
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ if (p->ink.k_rule == icxKl5l) {
+ double ii;
+ ii = out[e]; /* Input K locus */
+ if (ii < 0.0)
+ ii = 0.0;
+ else if (ii > 1.0)
+ ii = 1.0;
+ ii = (1.0 - ii) * rv + ii * rv2;/* Blend between locus rule curves */
+ /* Out ink from output locus */
+ pp[0].p[e] = min[e] + ii * (max[e] - min[e]);
+ } else {
+ double iv;
+ iv = out[e]; /* Input K level */
+ if (iv < rv) /* Constrain to curves */
+ iv = rv;
+ else if (iv > rv2)
+ iv = rv2;
+ pp[0].p[e] = iv;
+ }
+ }
+ }
+ DBR(("inv_clut_aux: aux %f from 2 curves\n",pp[0].p[3]))
+ }
+ }
+
+ /* Convert to input/dev aux target to input'/dev' space for rspl inversion */
+ for (e = 0; e < p->clutTable->di; e++) {
+ double tv, bv = 0.0, bd = 1e6;
+ co tc;
+ if (p->auxm[e] != 0) {
+ tv = pp[0].p[e];
+ /* Clip to overall locus range (belt and braces) */
+ if (tv < min[e])
+ tv = min[e];
+ if (tv > max[e])
+ tv = max[e];
+ tc.p[0] = tv;
+ p->inputTable[e]->interp(p->inputTable[e], &tc);
+ pp[0].p[e] = tc.v[0];
+ }
+ }
+
+ xflags |= RSPL_EXACTAUX; /* Since we confine aux to locus */
+
+#ifdef DEBUG_RLUT
+ printf("inv_clut_aux computed aux values ");
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0)
+ printf("%d: %f ",e,pp[0].p[e]);
+ }
+ printf("\n");
+#endif /* DEBUG_RLUT */
+ }
+
+ if (clipd != NULL) { /* Copy pp.v[] to compute clip DE */
+ for (f = 0; f < fdi; f++)
+ tin[f] = pp[0].v[f];
+ }
+
+ /* Find reverse solution with target auxiliaries */
+ /* We choose the closest aux at or above the target */
+ /* to try and avoid glitches near black due to */
+ /* possible forked black locuses. */
+ nsoln = p->clutTable->rev_interp(
+ p->clutTable, /* rspl object */
+ RSPL_MAXAUX | flags | xflags, /* Combine all the flags */
+ MAX_INVSOLN, /* Maxumum solutions to return */
+ p->auxm, /* Auxiliary input chanel mask */
+ cdir, /* Clip vector direction and length */
+ pp); /* Input target and output solutions */
+ /* returned solutions in pp[0..retval-1].p[] */
+
+ } else {
+ DBR(("inv_clut_aux needs no aux value\n"))
+
+ if (clipd != NULL) { /* Copy pp.v[] to compute clip DE */
+ for (f = 0; f < fdi; f++)
+ tin[f] = pp[0].v[f];
+ }
+
+ /* Color spaces don't need auxiliaries to choose from solution locus */
+ nsoln = p->clutTable->rev_interp(
+ p->clutTable, /* rspl object */
+ flags, /* No extra flags */
+ MAX_INVSOLN, /* Maxumum solutions to return */
+ NULL, /* No auxiliary input targets */
+ cdir, /* Clip vector direction and length */
+ pp); /* Input target and output solutions */
+ /* returned solutions in pp[0..retval-1].p[] */
+ }
+ if (nsoln & RSPL_DIDCLIP)
+ crv = 1; /* Clipped on PCS inverse lookup */
+
+ if (crv && clipd != NULL) {
+
+ /* Compute the clip DE */
+ for (cdist = 0.0, f = 0; f < fdi; f++) {
+ double tt;
+ tt = pp[0].v[f] - tin[f];
+ cdist += tt * tt;
+ }
+ cdist = sqrt(cdist);
+ }
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ DBR(("inv_clut_aux got %d rev_interp solutions, clipflag = %d\n",nsoln,crv))
+
+ /* If we clipped and we should clip in CAM Jab space, compute reverse */
+ /* clip solution using our additional CAM space. */
+ /* (Note that we don't support vector clip in CAM space at the moment) */
+ if (crv != 0 && p->camclip && p->nearclip) {
+ co cpp; /* Alternate CAM space solution */
+ double bf; /* Blend factor */
+
+ DBR(("inv_clut_aux got clip, compute CAM clip\n"))
+
+ if (nsoln != 1) { /* This would be unexpected */
+ error("Unexpected failure to return 1 solution on clip for input to output table");
+ }
+
+ if (p->cclutTable == NULL) { /* we haven't created this yet, so do so */
+ if (icxLuLut_init_clut_camclip(p))
+ error("Creating CAM rspl for camclip failed");
+ }
+
+ /* Setup for reverse lookup */
+ DBR(("inv_clut_aux cam clip PCS in %f %f %f\n",in[0],in[1],in[2]))
+
+ /* Convert from PCS' to (XYZ) PCS */
+ ((icmLuLut *)p->absxyzlu)->output((icmLuLut *)p->absxyzlu, tin, in);
+ DBR(("inv_clut_aux cam clip PCS' -> PCS %f %f %f\n",tin[0],tin[1],tin[2]))
+
+ ((icmLuLut *)p->absxyzlu)->out_abs((icmLuLut *)p->absxyzlu, tin, tin);
+ DBR(("inv_clut_aux cam clip abs XYZ PCS %f %f %f\n",tin[0],tin[1],tin[2]))
+
+ p->cam->XYZ_to_cam(p->cam, tin, tin);
+ DBR(("inv_clut_aux cam clip PCS after XYZtoCAM %f %f %f\n",tin[0],tin[1],tin[2]))
+
+ for (f = 0; f < fdi; f++) /* Transfer CAM targ */
+ cpp.v[f] = tin[f];
+
+ /* Make sure that the auxiliar value is initialized, */
+ /* even though it shouldn't have any effect, since should clipp. */
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ cpp.p[e] = 0.5;
+ }
+ }
+
+ if (p->clutTable->di > fdi) { /* ie. CMYK->Lab, there will be ambiguity */
+
+ nsoln = p->cclutTable->rev_interp(
+ p->cclutTable, /* rspl object */
+ flags | xflags | RSPL_WILLCLIP, /* Combine all the flags + clip ?? */
+ 1, /* Maximum solutions to return */
+ p->auxm, /* Auxiliary input chanel mask */
+ cdir, /* Clip vector direction and length */
+ &cpp); /* Input target and output solutions */
+
+ } else {
+ nsoln = p->cclutTable->rev_interp(
+ p->cclutTable, /* rspl object */
+ flags | RSPL_WILLCLIP, /* Because we know it will clip ?? */
+ 1, /* Maximum solutions to return */
+ NULL, /* No auxiliary input targets */
+ cdir, /* Clip vector direction and length */
+ &cpp); /* Input target and output solutions */
+ }
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln != 1) { /* This would be unexpected */
+ error("Unexpected failure to return 1 solution on CAM clip for input to output table");
+ }
+
+ /* Compute the CAM clip distances */
+ for (cdist = 0.0, f = 0; f < fdi; f++) {
+ double tt;
+ tt = cpp.v[f] - tin[f];
+ cdist += tt * tt;
+ }
+ cdist = sqrt(cdist);
+
+ /* Use magic number to set blend distance, and compute a blend factor. */
+ /* Blend over 1 delta E, otherwise the Lab & CAM02 divergence can result */
+ /* in reversals. */
+ bf = cdist/CAMCLIPTRANS; /* 0.0 for PCS result, 1.0 for CAM result */
+ if (bf > 1.0)
+ bf = 1.0;
+#ifdef USECAMCLIPSPLINE
+ bf = bf * bf * (3.0 - 2.0 * bf); /* Convert to spline blend */
+#endif
+ DBR(("cdist %f, spline blend %f\n",cdist,bf))
+
+ /* Blend between solution values for PCS and CAM clip result. */
+ /* We're hoping that the solutions are close, and expect them to be */
+ /* that way when we're close to the gamut surface (since the cell */
+ /* vertex values should be exact, irrespective of which space they're */
+ /* in), but weird things could happen away from the surface. Weird */
+ /* things can happen anyway with "clip to nearest", since this is not */
+ /* guaranteed to be a smooth function, depending on the gamut surface */
+ /* geometry, without taking some precaution such as clipping to a */
+ /* convex hull "wrapper" to create a clip vector, which we're not */
+ /* current doing. */
+ DBR(("Clip blend between device:\n"))
+ DBR(("Lab: %f %f %f and\n",pp[0].p[0], pp[0].p[1], pp[0].p[2]))
+ DBR(("Jab: %f %f %f\n",cpp.p[0], cpp.p[1], cpp.p[2]))
+
+ for (e = 0; e < p->clutTable->di; e++) {
+ out[e] = (1.0 - bf) * pp[0].p[e] + bf * cpp.p[e];
+ }
+
+ /* Not CAM clip case */
+ } else {
+
+ if (nsoln == 1) { /* Exactly one solution */
+ i = 0;
+ } else if (nsoln == 0) { /* Zero solutions. This is unexpected. */
+ double in_v[MXDO];
+ p->output(p, in_v, pp[0].v); /* Get ICC inverse input values */
+ p->out_abs(p, in_v, in_v);
+ error("Unexpected failure to find reverse solution for input to output table for value %f %f %f (ICC input %f %f %f)",pp[0].v[0],pp[0].v[1],pp[0].v[2], in_v[0], in_v[1], in_v[2]);
+ return 2;
+ } else { /* Multiple solutions */
+ /* Use a simple minded resolution - choose the one closest to the center */
+ double bdist = 1e300;
+ int bsoln = 0;
+ DBR(("got multiple reverse solutions\n"));
+ for (i = 0; i < nsoln; i++) {
+ double ss;
+
+ for (ss = 0.0, e = 0; e < p->clutTable->di; e++) {
+ double tt;
+ tt = pp[i].p[e] - p->licent[e];
+ tt *= tt;
+ if (tt < bdist) { /* Better solution */
+ bdist = tt;
+ bsoln = i;
+ }
+ }
+ }
+//printf("~1 chose %d\n",bsoln);
+ i = bsoln;
+ }
+ for (e = 0; e < p->clutTable->di; e++) {
+ /* Save solution as atractor for next one, on the basis */
+ /* that it might have better continuity given pesudo-hilbert inversion path. */
+ p->licent[e] = out[e] = pp[i].p[e]; /* Solution */
+ }
+ }
+
+ /* Sanitise auxiliary locus range and auxiliary value return */
+ if (auxr != NULL || auxv != NULL) {
+ int ee = 0;
+ for (e = 0; e < p->clutTable->di; e++) {
+ double v = out[e]; /* Solution */
+ if (p->auxm[e] != 0) {
+ if (auxr != NULL) { /* Make sure locus encloses actual value */
+ if (auxr[2 * ee] > v)
+ auxr[2 * ee] = v;
+ if (auxr[2 * ee + 1] < v)
+ auxr[2 * ee + 1] = v;
+ }
+ if (auxv != NULL) {
+ auxv[ee] = v;
+ }
+ ee++;
+ }
+ }
+ }
+
+#ifdef CHECK_ILIMIT /* Do sanity checks on meeting ink limit */
+if (p->ink.tlimit >= 0.0 || p->ink.klimit >= 0.0) {
+ double sum = icxLimitD(p, out);
+ if (sum > 0.0)
+ printf("xlut assert%s: icxLuLut_inv_clut returned outside limits by %f > tlimit %f\n",crv ? " (clip)" : "", sum, p->ink.tlimit);
+}
+#endif
+
+ if (clipd != NULL) {
+ *clipd = cdist;
+ DBR(("inv_clut_aux returning clip DE %f\n",cdist))
+ }
+
+ DBR(("inv_clut_aux returning %f %f %f %f\n",out[0],out[1],out[2],out[3]))
+ return crv;
+}
+
+/* Do output'->input' lookup, simple version */
+/* Note than out[] will carry inking value if icxKrule is icxKvalue of icxKlocus */
+/* and that the icxKrule value will be in the input (NOT input') space. */
+/* Note that the ink limit will be computed after converting input' to input */
+int icxLuLut_inv_clut(icxLuLut *p, double *out, double *in) {
+ return icxLuLut_inv_clut_aux(p, out, NULL, NULL, NULL, NULL, in);
+}
+
+/* Given the proposed auxiliary input values in in[di], */
+/* and the target output' (ie. PCS') values in out[fdi], */
+/* return the auxiliary input (NOT input' space) values as a proportion of their */
+/* possible locus in locus[di]. */
+/* This is generally used on a source CMYK profile to convey the black intent */
+/* to destination CMYK profile. */
+int icxLuLut_clut_aux_locus(icxLuLut *p, double *locus, double *out, double *in) {
+ co pp[1]; /* Room for all the solutions found */
+ int nsoln; /* Number of solutions found */
+ int e,f;
+
+ if (p->clutTable->di > p->clutTable->fdi) { /* ie. CMYK->Lab, there will be ambiguity */
+ double min[MXDI], max[MXDI]; /* Auxiliary locus range */
+
+ /* Setup for auxiliary locus lookup */
+ for (f = 0; f < p->clutTable->fdi; f++) {
+ pp[0].v[f] = out[f]; /* Target output' (i.e. PCS) value */
+ }
+
+ /* Compute auxiliary locus */
+ nsoln = p->clutTable->rev_locus(
+ p->clutTable, /* rspl object */
+ p->auxm, /* Auxiliary mask */
+ pp, /* Input target and output solutions */
+ min, max); /* Returned locus of valid auxiliary values */
+
+ if (nsoln == 0) {
+ for (e = 0; e < p->clutTable->di; e++)
+ locus[e] = 0.0; /* Return some safe values */
+ } else { /* Got a valid locus */
+
+ /* Convert the locus from input' -> input space */
+ for (e = 0; e < p->clutTable->di; e++) {
+ co tc;
+ /* (Is speed more important than precision ?) */
+ if (p->auxm[e] != 0) {
+ tc.p[0] = min[e];
+ p->revinputTable[e]->interp(p->revinputTable[e], &tc);
+ min[e] = tc.v[0];
+ tc.p[0] = max[e];
+ p->revinputTable[e]->interp(p->revinputTable[e], &tc);
+ max[e] = tc.v[0];
+ }
+ }
+
+ /* Figure out the proportion of the locus */
+ for (e = 0; e < p->clutTable->di; e++) {
+ if (p->auxm[e] != 0) {
+ double iv = in[e];
+ if (iv <= min[e])
+ locus[e] = 0.0;
+ else if (iv >= max[e])
+ locus[e] = 1.0;
+ else {
+ double lpl = max[e] - min[e]; /* Locus path length */
+ if (lpl > 1e-6)
+ locus[e] = (iv - min[e])/lpl;
+ else
+ locus[e] = 0.0;
+ }
+ }
+ }
+ }
+ } else {
+ /* There should be no auxiliaries */
+ for (e = 0; e < p->clutTable->di; e++)
+ locus[e] = 0.0; /* Return some safe values */
+ }
+ return 0;
+}
+
+/* Do input' -> input inverse lookup */
+int icxLuLut_inv_input(icxLuLut *p, double *out, double *in) {
+#ifdef NEVER
+ return ((icmLuLut *)p->plu)->inv_input((icmLuLut *)p->plu, out, in);
+#else
+ int rv = 0;
+ int i,j;
+ int nsoln; /* Number of solutions found */
+ co pp[MAX_INVSOLN]; /* Room for all the solutions found */
+ double cdir;
+
+ DBR(("inv_input got DEV' %f %f %f %f\n",in[0],in[1],in[2],in[3]))
+
+ for (i = 0; i < p->inputChan; i++) {
+ pp[0].p[0] = p->inputClipc[i];
+ pp[0].v[0] = in[i];
+ cdir = p->inputClipc[i] - in[i]; /* Clip towards output range */
+
+ nsoln = p->inputTable[i]->rev_interp (
+ p->inputTable[i], /* this */
+ RSPL_NEARCLIP, /* Clip to nearest (faster than vector) */
+ MAX_INVSOLN, /* Maximum number of solutions allowed for */
+ NULL, /* No auxiliary input targets */
+ &cdir, /* Clip vector direction and length */
+ pp); /* Input and output values */
+
+ if (nsoln & RSPL_DIDCLIP)
+ rv = 1;
+
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln == 1) { /* Exactly one solution */
+ j = 0;
+ } else if (nsoln == 0) { /* Zero solutions. This is unexpected. */
+ error("Unexpected failure to find reverse solution for input table");
+ return 2;
+ } else { /* Multiple solutions */
+ /* Use a simple minded resolution - choose the one closest to the center */
+ double bdist = 1e300;
+ int bsoln = 0;
+ /* Don't expect this - 1D luts are meant to be monotonic */
+ warning("1D lut inversion got %d reverse solutions\n",nsoln);
+ warning("solution 0 = %f\n",pp[0].p[0]);
+ warning("solution 1 = %f\n",pp[1].p[0]);
+ for (j = 0; j < nsoln; j++) {
+ double tt;
+ tt = pp[i].p[0] - p->inputClipc[i];
+ tt *= tt;
+ if (tt < bdist) { /* Better solution */
+ bdist = tt;
+ bsoln = j;
+ }
+ }
+ j = bsoln;
+ }
+ out[i] = pp[j].p[0];
+ }
+
+ DBR(("inv_input returning DEV %f %f %f %f\n",out[0],out[1],out[2],out[3]))
+ return rv;
+#endif /* NEVER */
+}
+
+/* Possible inverse matrix lookup */
+/* (Will do nothing if input is device space) */
+int icxLuLut_inv_matrix(icxLuLut *p, double *out, double *in) {
+ int rv = 0;
+ rv |= ((icmLuLut *)p->plu)->inv_matrix((icmLuLut *)p->plu, out, in);
+ return rv;
+}
+
+/* Inverse input absolute intent conversion */
+/* (Will do nothing if input is device space) */
+int icxLuLut_inv_in_abs(icxLuLut *p, double *out, double *in) {
+ int rv = 0;
+ rv |= ((icmLuLut *)p->plu)->inv_in_abs((icmLuLut *)p->plu, out, in);
+
+ if (p->ins == icxSigJabData) {
+ p->cam->XYZ_to_cam(p->cam, out, out);
+ }
+
+ return rv;
+}
+
+/* Overall inverse lookup */
+/* Note that all auxiliary values are in input (NOT input') space */
+static int
+icxLuLut_inv_lookup(
+icxLuBase *pp, /* This */
+double *out, /* Vector of output values/input auxiliary values */
+double *in /* Vector of input values */
+) {
+ icxLuLut *p = (icxLuLut *)pp;
+ int rv = 0;
+ int i;
+ double temp[MAX_CHAN];
+
+ DBOL(("xiccilu: input = %s\n", icmPdv(p->outputChan, in)));
+ if (p->mergeclut == 0) { /* Do this if it's not merger with clut */
+ rv |= p->inv_out_abs (p, temp, in);
+ DBOL(("xiccilu: after inv abs = %s\n", icmPdv(p->outputChan, temp)));
+ rv |= p->inv_output (p, temp, temp);
+ DBOL(("xiccilu: after inv out = %s\n", icmPdv(p->outputChan, temp)));
+ } else {
+ for (i = 0; i < p->outputChan; i++)
+ temp[i] = in[i];
+ }
+ DBOL(("xiccilu: aux targ = %s\n", icmPdv(p->inputChan,out)));
+ rv |= p->inv_clut (p, out, temp);
+ DBOL(("xiccilu: after inv clut = %s\n", icmPdv(p->inputChan,out)));
+ rv |= p->inv_input (p, out, out);
+ DBOL(("xiccilu: after inv input = %s\n", icmPdv(p->inputChan,out)));
+ rv |= p->inv_matrix (p, out, out);
+ DBOL(("xiccilu: after inv matrix = %s\n", icmPdv(p->inputChan,out)));
+ rv |= p->inv_in_abs (p, out, out);
+ DBOL(("xiccilu: after inv abs = %s\n", icmPdv(p->inputChan,out)));
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given a nominated output PCS (ie. Absolute, Jab etc.), convert it in the bwd */
+/* direction into a relative XYZ or Lab PCS value */
+/* (This is used in generating gamut compression in B2A tables) */
+void icxLuLut_bwd_outpcs_relpcs(
+icxLuBase *pp,
+icColorSpaceSignature os, /* Output space, XYZ or Lab */
+double *out, double *in) {
+ icxLuLut *p = (icxLuLut *)pp;
+
+ if (p->outs == icxSigJabData) {
+ DBS(("bwd_outpcs_relpcs: Jab in = %s\n", icmPdv(3, in)));
+ p->cam->cam_to_XYZ(p->cam, out, in);
+ DBS(("bwd_outpcs_relpcs: abs XYZ = %s\n", icmPdv(3, out)));
+ /* Hack to prevent CAM02 weirdness being amplified by */
+ /* per channel clipping. */
+ /* Limit -Y to non-stupid values by scaling */
+ if (out[1] < -0.1) {
+ out[0] *= -0.1/out[1];
+ out[2] *= -0.1/out[1];
+ out[1] = -0.1;
+ DBS(("bwd_outpcs_relpcs: after clipping -Y %s\n",icmPdv(p->outputChan, out)));
+ }
+ } else {
+ DBS(("bwd_outpcs_relpcs: abs PCS in = %s\n", icmPdv(3, out)));
+ icmCpy3(out, in);
+ }
+
+ ((icmLuLut *)p->plu)->inv_out_abs((icmLuLut *)p->plu, out, out);
+ DBS(("bwd_outpcs_relpcs: rel PCS = %s\n", icmPdv(3, out)));
+
+ if (os == icSigXYZData && p->natpcs == icSigLabData) {
+ icmLab2XYZ(&icmD50, out, out);
+ DBS(("bwd_outpcs_relpcs: rel XYZ = %s\n", icmPdv(3, out)));
+ } else if (os == icSigXYZData && p->natpcs == icSigLabData) {
+ icmXYZ2Lab(&icmD50, out, out);
+ DBS(("bwd_outpcs_relpcs: rel Lab = %s\n", icmPdv(3, out)));
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Return LuLut information */
+static void icxLuLut_get_info(
+ icxLuLut *p, /* this */
+ icmLut **lutp, /* Pointer to icc lut type return value */
+ icmXYZNumber *pcswhtp, /* Pointer to profile PCS white point return value */
+ icmXYZNumber *whitep, /* Pointer to profile absolute white point return value */
+ icmXYZNumber *blackp /* Pointer to profile absolute black point return value */
+) {
+ ((icmLuLut *)p->plu)->get_info((icmLuLut *)p->plu, lutp, pcswhtp, whitep, blackp);
+}
+
+/* Return the underlying Lut matrix */
+static void
+icxLuLut_get_matrix (
+ icxLuLut *p,
+ double m[3][3]
+) {
+ ((icmLuLut *)p->plu)->get_matrix((icmLuLut *)p->plu, m);
+}
+
+static void
+icxLuLut_free(
+icxLuBase *pp
+) {
+ icxLuLut *p = (icxLuLut *)pp;
+ int i;
+
+ for (i = 0; i < p->inputChan; i++) {
+ if (p->inputTable[i] != NULL)
+ p->inputTable[i]->del(p->inputTable[i]);
+ if (p->revinputTable[i] != NULL)
+ p->revinputTable[i]->del(p->revinputTable[i]);
+ }
+
+ if (p->clutTable != NULL)
+ p->clutTable->del(p->clutTable);
+
+ if (p->cclutTable != NULL)
+ p->cclutTable->del(p->cclutTable);
+
+ for (i = 0; i < p->outputChan; i++) {
+ if (p->outputTable[i] != NULL)
+ p->outputTable[i]->del(p->outputTable[i]);
+ }
+
+ if (p->plu != NULL)
+ p->plu->del(p->plu);
+
+ if (p->cam != NULL)
+ p->cam->del(p->cam);
+
+ if (p->absxyzlu != NULL)
+ p->absxyzlu->del(p->absxyzlu);
+
+ free(p);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+static gamut *icxLuLutGamut(icxLuBase *plu, double detail);
+
+/* Do the basic icxLuLut creation and initialisation */
+static icxLuLut *
+alloc_icxLuLut(
+ xicc *xicp,
+ icmLuBase *plu, /* Pointer to Lu we are expanding (ours) */
+ int flags /* clip, merge flags */
+) {
+ icxLuLut *p; /* Object being created */
+ icmLuLut *luluto = (icmLuLut *)plu; /* Lookup Lut type object */
+
+ if ((p = (icxLuLut *) calloc(1,sizeof(icxLuLut))) == NULL)
+ return NULL;
+
+ p->pp = xicp;
+ p->plu = plu;
+ p->del = icxLuLut_free;
+ p->lutspaces = icxLutSpaces;
+ p->spaces = icxLuSpaces;
+ p->get_native_ranges = icxLu_get_native_ranges;
+ p->get_ranges = icxLu_get_ranges;
+ p->efv_wh_bk_points = icxLuEfv_wh_bk_points;
+ p->get_gamut = icxLuLutGamut;
+ p->fwd_relpcs_outpcs = icxLuLut_fwd_relpcs_outpcs;
+ p->bwd_outpcs_relpcs = icxLuLut_bwd_outpcs_relpcs;
+ p->nearclip = 0; /* Set flag defaults */
+ p->mergeclut = 0;
+ p->noisluts = 0;
+ p->noipluts = 0;
+ p->nooluts = 0;
+ p->intsep = 0;
+
+ p->lookup = icxLuLut_lookup;
+ p->in_abs = icxLuLut_in_abs;
+ p->matrix = icxLuLut_matrix;
+ p->input = icxLuLut_input;
+ p->clut = icxLuLut_clut;
+ p->clut_aux = icxLuLut_clut_aux;
+ p->output = icxLuLut_output;
+ p->out_abs = icxLuLut_out_abs;
+
+ p->inv_lookup = icxLuLut_inv_lookup;
+ p->inv_in_abs = icxLuLut_inv_in_abs;
+ p->inv_matrix = icxLuLut_inv_matrix;
+ p->inv_input = icxLuLut_inv_input;
+ p->inv_clut = icxLuLut_inv_clut;
+ p->inv_clut_aux = icxLuLut_inv_clut_aux;
+ p->inv_output = icxLuLut_inv_output;
+ p->inv_out_abs = icxLuLut_inv_out_abs;
+
+ p->clut_locus = icxLuLut_clut_aux_locus;
+
+ p->get_info = icxLuLut_get_info;
+ p->get_matrix = icxLuLut_get_matrix;
+
+ /* Setup all the rspl analogs of the icc Lut */
+ /* NOTE: We assume that none of this relies on the flag settings, */
+ /* since they will be set on our return. */
+
+ /* Get details of underlying, native icc color space */
+ p->plu->lutspaces(p->plu, &p->natis, NULL, &p->natos, NULL, &p->natpcs);
+
+ /* Get other details of conversion */
+ p->plu->spaces(p->plu, NULL, &p->inputChan, NULL, &p->outputChan, NULL, NULL, NULL, NULL, NULL);
+
+ /* Remember flags */
+ p->flags = flags;
+
+ /* Sanity check */
+ if (p->inputChan > MXDI) {
+ sprintf(p->pp->err,"xicc can only handle input channels of %d or less",MXDI);
+ p->inputChan = MXDI; /* Avoid going outside array bounds */
+ p->pp->errc = 1;
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ if (p->outputChan > MXDO) {
+ sprintf(p->pp->err,"xicc can only handle output channels of %d or less",MXDO);
+ p->outputChan = MXDO; /* Avoid going outside array bounds */
+ p->pp->errc = 1;
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ /* Get pointer to icmLut */
+ luluto->get_info(luluto, &p->lut, NULL, NULL, NULL);
+
+ return p;
+}
+
+/* Initialise the clut ink limiting and black */
+/* generation information. */
+/* return 0 or error code */
+static int
+setup_ink_icxLuLut(
+icxLuLut *p, /* Object being initialised */
+icxInk *ink, /* inking details (NULL for default) */
+int setLminmax /* Figure the L locus for inking rule */
+) {
+ int devchan = p->func == icmFwd ? p->inputChan : p->outputChan;
+
+ if (ink) {
+ p->ink = *ink; /* Copy the structure */
+ } else {
+ p->ink.tlimit = 3.0; /* default ink limit of 300% */
+ p->ink.klimit = -1.0; /* default no black limit */
+ p->ink.KonlyLmin = 0; /* default don't use K only black as Locus Lmin */
+ p->ink.k_rule = icxKluma5; /* default K generation rule */
+ p->ink.c.Ksmth = ICXINKDEFSMTH; /* Default smoothing */
+ p->ink.c.Kskew = ICXINKDEFSKEW; /* Default shape skew */
+ p->ink.c.Kstle = 0.0; /* Min K at white end */
+ p->ink.c.Kstpo = 0.0; /* Start of transition is at white */
+ p->ink.c.Kenle = 1.0; /* Max K at black end */
+ p->ink.c.Kenpo = 1.0; /* End transition at black */
+ p->ink.c.Kshap = 1.0; /* Linear transition */
+ }
+
+ /* Normalise total and black ink limits */
+ if (p->ink.tlimit <= 1e-4 || p->ink.tlimit >= (double)devchan)
+ p->ink.tlimit = -1.0; /* Turn ink limit off if not effective */
+ if (devchan < 4 || p->ink.klimit < 0.0 || p->ink.klimit >= 1.0)
+ p->ink.klimit = -1.0; /* Turn black limit off if not effective */
+
+ /* Set the ink limit information for any reverse interpolation. */
+ /* Calling this will clear the reverse interpolaton cache. */
+ p->clutTable->rev_set_limit(
+ p->clutTable, /* this */
+ p->ink.tlimit >= 0.0 || p->ink.klimit >= 0.0 ? icxLimitD_void : NULL,
+ /* Optional input space limit() function. */
+ /* Function should evaluate in[0..di-1], and return */
+ /* number that is not to exceed 0.0. NULL if not used. */
+ (void *)p, /* Context passed to limit() */
+ 0.0 /* Value that limit() is not to exceed */
+ );
+
+ /* Duplicate in the CAM clip rspl if it exists */
+ if (p->cclutTable != NULL) {
+ p->cclutTable->rev_set_limit(
+ p->cclutTable, /* this */
+ p->ink.tlimit >= 0.0 || p->ink.klimit >= 0.0 ? icxLimitD_void : NULL,
+ /* Optional input space limit() function. */
+ /* Function should evaluate in[0..di-1], and return */
+ /* number that is not to exceed 0.0. NULL if not used. */
+ (void *)p, /* Context passed to limit() */
+ 0.0 /* Value that limit() is not to exceed */
+ );
+ }
+
+ /* Figure Lmin and Lmax for icxKluma5 curve basis */
+ if (setLminmax
+ && p->clutTable->di > p->clutTable->fdi) { /* If K generation makes sense */
+ double wh[3], bk[3], kk[3];
+ int mergeclut; /* Save/restore mergeclut value */
+
+ /* Get white/black in effective xlu PCS space */
+ p->efv_wh_bk_points((icxLuBase *)p, wh, bk, kk);
+
+ /* Convert from effective PCS (ie. Jab) to native XYZ or Lab PCS */
+ mergeclut = p->mergeclut; /* Hack to be able to use inv_out_abs() */
+ p->mergeclut = 0; /* if mergeclut is active. */
+ icxLuLut_inv_out_abs(p, wh, wh);
+ icxLuLut_inv_out_abs(p, bk, bk);
+ icxLuLut_inv_out_abs(p, kk, kk);
+ p->mergeclut = mergeclut; /* Restore */
+
+ /* Convert to Lab PCS */
+ if (p->natos == icSigXYZData) { /* Always do K rule in L space */
+ icmXYZ2Lab(&icmD50, wh, wh);
+ icmXYZ2Lab(&icmD50, bk, bk);
+ icmXYZ2Lab(&icmD50, kk, kk);
+ }
+ p->Lmax = 0.01 * wh[0];
+ if (p->ink.KonlyLmin != 0)
+ p->Lmin = 0.01 * kk[0];
+ else
+ p->Lmin = 0.01 * bk[0];
+ } else {
+
+ /* Some sane defaults */
+ p->Lmax = 1.0;
+ p->Lmin = 0.0;
+ }
+
+ return 0;
+}
+
+
+/* Initialise the clut clipping information, ink limiting */
+/* and auxiliary parameter settings for all the rspl. */
+/* return 0 or error code */
+static int
+setup_clip_icxLuLut(
+icxLuLut *p /* Object being initialised */
+) {
+ double tmin[MXDIDO], tmax[MXDIDO];
+ int i;
+
+ /* Setup for inversion of multi-dim clut */
+
+ p->kch = -1; /* Not known yet */
+
+ /* Set auxiliaries */
+ for (i = 0; i < p->inputChan; i++)
+ p->auxm[i] = 0;
+
+ if (p->inputChan > p->outputChan) {
+ switch(p->natis) {
+ case icSigCmykData:
+ /* Should fix icm/xicc to remember K channel */
+ p->auxm[3] = 1; /* K is the auxiliary channel */
+ break;
+ default:
+ if (p->kch >= 0) /* It's been discovered */
+ p->auxm[p->kch] = 1;
+ else {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Unknown colorspace %s when setting auxliaries",
+ icm2str(icmColorSpaceSignature, p->natis));
+ return p->pp->errc;
+ }
+ break;
+ }
+ }
+
+// p->auxlinf = NULL; /* Input space auxiliary linearisation function - not implemented */
+// p->auxlinf_ctx = NULL; /* Opaque context for auxliliary linearisation function */
+
+ /* Aproximate center of clut input gamut - used for */
+ /* resolving multiple reverse solutions. */
+ p->clutTable->get_in_range(p->clutTable, tmin, tmax);
+ for (i = 0; i < p->clutTable->di; i++) {
+ p->licent[i] = p->icent[i] = (tmin[i] + tmax[i])/2.0;
+ }
+
+ /* Compute clip setup information relating to clut output gamut. */
+ if (p->nearclip != 0 /* Near clip requested */
+ || p->inputChan == 1) { /* or vector clip won't work */
+ p->clip.nearclip = 1;
+
+ } else { /* Vector clip */
+ /* !!!! NOTE NOTE NOTE !!!! */
+ /* We should re-write this to avoid calling p->clutTable->rev_interp(), */
+ /* since this sets up all the rev acceleration tables for two calls, */
+ /* if this lut is being setup from scattered data, and never used */
+ /* for rev lookup */
+ icColorSpaceSignature clutos = p->natos;
+
+ fprintf(stderr, "!!!!! setup_clip_icxLuLut with vector clip - possibly unnecessary rev setup !!!!\n");
+ p->clip.nearclip = 0;
+ p->clip.LabLike = 0;
+ p->clip.fdi = p->clutTable->fdi;
+
+ switch(clutos) {
+ case icxSigJabData:
+ case icSigLabData: {
+ co pp; /* Room for all the solutions found */
+ int nsoln; /* Number of solutions found */
+ double cdir[MXDO]; /* Clip vector direction and length */
+
+ p->clip.LabLike = 1;
+
+ /* Find high clip target */
+ for (i = 0; i < p->inputChan; i++)
+ pp.p[i] = 0.0; /* Set aux values */
+ pp.v[0] = 105.0; pp.v[1] = pp.v[2] = 0.0; /* PCS Target value */
+ cdir[0] = cdir[1] = cdir[2] = 0.0; /* Clip Target */
+
+ p->inv_output(p, pp.v, pp.v); /* Compensate for output curve */
+ p->inv_output(p, cdir, cdir);
+
+ cdir[0] -= pp.v[0]; /* Clip vector */
+ cdir[1] -= pp.v[1];
+ cdir[2] -= pp.v[2];
+
+ /* PCS -> Device with clipping */
+ nsoln = p->clutTable->rev_interp(
+ p->clutTable, /* rspl object */
+ 0, /* No hint flags - might be in gamut, might vector clip */
+ 1, /* Maxumum solutions to return */
+ p->auxm, /* Auxiliary input targets */
+ cdir, /* Clip vector direction and length */
+ &pp); /* Input target and output solutions */
+ /* returned solutions in pp[0..retval-1].p[] */
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+
+ if (nsoln != 1) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Failed to find high clip target for Lab space");
+ return p->pp->errc;
+ }
+
+ p->clip.ocent[0] = pp.v[0] - 0.001; /* Got main target */
+ p->clip.ocent[1] = pp.v[1];
+ p->clip.ocent[2] = pp.v[2];
+
+ /* Find low clip target */
+ pp.v[0] = -5.0; pp.v[1] = pp.v[2] = 0.0; /* PCS Target value */
+ cdir[0] = 100.0; cdir[1] = cdir[2] = 0.0; /* Clip Target */
+
+ p->inv_output(p, pp.v, pp.v); /* Compensate for output curve */
+ p->inv_output(p, cdir, cdir);
+ cdir[0] -= pp.v[0]; /* Clip vector */
+ cdir[1] -= pp.v[1];
+ cdir[2] -= pp.v[2];
+
+ /* PCS -> Device with clipping */
+ nsoln = p->clutTable->rev_interp(
+ p->clutTable, /* rspl object */
+ RSPL_WILLCLIP, /* Since there was no locus, we expect to have to clip */
+ 1, /* Maxumum solutions to return */
+ NULL, /* No auxiliary input targets */
+ cdir, /* Clip vector direction and length */
+ &pp); /* Input target and output solutions */
+ /* returned solutions in pp[0..retval-1].p[] */
+ nsoln &= RSPL_NOSOLNS; /* Get number of solutions */
+ if (nsoln != 1) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Failed to find low clip target for Lab space");
+ return p->pp->errc;
+ }
+
+ p->clip.ocentv[0] = pp.v[0] + 0.001 - p->clip.ocent[0]; /* Raw line vector */
+ p->clip.ocentv[1] = pp.v[1] - p->clip.ocent[1];
+ p->clip.ocentv[2] = pp.v[2] - p->clip.ocent[2];
+
+ /* Compute vectors length */
+ for (p->clip.ocentl = 0.0, i = 0; i < 3; i++)
+ p->clip.ocentl += p->clip.ocentv[i] * p->clip.ocentv[i];
+ p->clip.ocentl = sqrt(p->clip.ocentl);
+ if (p->clip.ocentl <= 1e-8)
+ p->clip.ocentl = 0.0;
+
+ break;
+ }
+ case icSigXYZData:
+ // ~~~~~~1 need to add this.
+
+ default:
+ /* Do a crude approximation, that may not work. */
+ p->clutTable->get_out_range(p->clutTable, tmin, tmax);
+ for (i = 0; i < p->clutTable->fdi; i++) {
+ p->clip.ocent[i] = (tmin[i] + tmax[i])/2.0;
+ }
+ p->clip.ocentl = 0.0;
+ break;
+ }
+ }
+ return 0;
+}
+
+/* Function to pass to rspl to set secondary input/output transfer functions */
+static void
+icxLuLut_inout_func(
+ void *pp, /* icxLuLut */
+ double *out, /* output value */
+ double *in /* inut value */
+) {
+ icxLuLut *p = (icxLuLut *)pp; /* this */
+ icmLuLut *luluto = (icmLuLut *)p->plu; /* Get icmLuLut object */
+ double tin[MAX_CHAN];
+ double tout[MAX_CHAN];
+ int i;
+
+ if (p->iol_out == 0) { /* fwd input */
+#ifdef INK_LIMIT_TEST
+ tout[p->iol_ch] = in[0];
+#else
+ for (i = 0; i < p->inputChan; i++)
+ tin[i] = 0.0;
+ tin[p->iol_ch] = in[0];
+ luluto->input(luluto, tout, tin);
+#endif
+ } else if (p->iol_out == 1) { /* fwd output */
+ for (i = 0; i < p->outputChan; i++)
+ tin[i] = 0.0;
+ tin[p->iol_ch] = in[0];
+ luluto->output(luluto, tout, tin);
+ } else { /* bwd input */
+#ifdef INK_LIMIT_TEST
+ tout[p->iol_ch] = in[0];
+#else
+ for (i = 0; i < p->inputChan; i++)
+ tin[i] = 0.0;
+ tin[p->iol_ch] = in[0];
+ luluto->inv_input(luluto, tout, tin);
+ /* This won't be valid if matrix is used or there is a PCS conversion !!! */
+ /* Shouldn't be a problem because this is only used for inverting dev->PCS ? */
+ luluto->inv_in_abs(luluto, tout, tout);
+#endif
+ }
+ out[0] = tout[p->iol_ch];
+}
+
+/* Function to pass to rspl to set clut up, when mergeclut is set */
+static void
+icxLuLut_clut_merge_func(
+ void *pp, /* icxLuLut */
+ double *out, /* output value */
+ double *in /* input value */
+) {
+ icxLuLut *p = (icxLuLut *)pp; /* this */
+ icmLuLut *luluto = (icmLuLut *)p->plu; /* Get icmLuLut object */
+
+ luluto->clut(luluto, out, in);
+ luluto->output(luluto, out, out);
+ luluto->out_abs(luluto, out, out);
+
+ if (p->outs == icxSigJabData) {
+ p->cam->XYZ_to_cam(p->cam, out, out);
+ }
+}
+
+/* Implimenation of Lut create from icc. */
+/* Note that xicc_get_luobj() will have set the pcsor & */
+/* intent to consistent values if Jab and/or icxAppearance */
+/* has been requested. */
+/* It will also have created the underlying icm lookup object */
+/* that is used to create and implement the icx one. The icm */
+/* will be used to translate from native to effective PCS, unless */
+/* the effective PCS is Jab, in which case the icm will be set to */
+/* have an effective PCS of XYZ. Since native<->effecive PCS conversion */
+/* is done at the to/from_abs() stage, none of it affects the individual */
+/* conversion steps, which will all talk the native PCS (unless merged). */
+static icxLuBase *
+new_icxLuLut(
+xicc *xicp,
+int flags, /* clip, merge flags */
+icmLuBase *plu, /* Pointer to Lu we are expanding (ours) */
+icmLookupFunc func, /* Functionality requested */
+icRenderingIntent intent, /* Rendering intent */
+icColorSpaceSignature pcsor, /* PCS override (0 = def) */
+icxViewCond *vc, /* Viewing Condition (NULL if not using CAM) */
+icxInk *ink /* inking details (NULL for default) */
+) {
+ icxLuLut *p; /* Object being created */
+ icmLuLut *luluto = (icmLuLut *)plu; /* Lookup Lut type object */
+
+ int i;
+
+ /* Do basic creation and initialisation */
+ if ((p = alloc_icxLuLut(xicp, plu, flags)) == NULL)
+ return NULL;
+
+ p->func = func;
+
+ /* Set LuLut "use" specific creation flags: */
+ if (flags & ICX_CLIP_NEAREST)
+ p->nearclip = 1;
+
+ if (flags & ICX_MERGE_CLUT)
+ p->mergeclut = 1;
+
+ if (flags & ICX_FAST_SETUP)
+ p->fastsetup = 1;
+
+ /* We're only implementing this under specific conditions. */
+ if (flags & ICX_CAM_CLIP
+ && func == icmFwd
+ && !(p->mergeclut != 0 && pcsor == icxSigJabData)) /* Don't need camclip if merged Jab */
+ p->camclip = 1;
+
+ if (flags & ICX_INT_SEPARATE) {
+fprintf(stderr,"~1 Internal optimised 4D separations not yet implemented!\n");
+ p->intsep = 1;
+ }
+
+ /* Init the CAM model if it will be used */
+ if (pcsor == icxSigJabData || p->camclip) {
+ if (vc != NULL) /* One has been provided */
+ p->vc = *vc; /* Copy the structure */
+ else
+ xicc_enum_viewcond(xicp, &p->vc, -1, NULL, 0, NULL); /* Use a default */
+ p->cam = new_icxcam(cam_default);
+ p->cam->set_view(p->cam, p->vc.Ev, p->vc.Wxyz, p->vc.La, p->vc.Yb, p->vc.Lv, p->vc.Yf,
+ p->vc.Fxyz, XICC_USE_HK);
+ } else {
+ p->cam = NULL;
+ }
+
+ /* Remember the effective intent */
+ p->intent = intent;
+
+ /* Get the effective spaces of underlying icm */
+ plu->spaces(plu, &p->ins, NULL, &p->outs, NULL, NULL, NULL, NULL, &p->pcs, NULL);
+
+ /* Override with pcsor */
+ /* We assume that any profile that has a CIE color as a "device" color */
+ /* intends it to stay that way, and not be overridden. */
+ if (pcsor == icxSigJabData) {
+ p->pcs = pcsor;
+
+ if (xicp->pp->header->deviceClass == icSigAbstractClass) {
+ p->ins = pcsor;
+ p->outs = pcsor;
+
+ } else if (xicp->pp->header->deviceClass != icSigLinkClass) {
+ if (func == icmBwd || func == icmGamut || func == icmPreview)
+ p->ins = pcsor;
+ if (func == icmFwd || func == icmPreview)
+ p->outs = pcsor;
+ }
+ }
+
+ /* In general the native and effective ranges of the icx will be the same as the */
+ /* underlying icm lookup object. */
+ p->plu->get_lutranges(p->plu, p->ninmin, p->ninmax, p->noutmin, p->noutmax);
+ p->plu->get_ranges(p->plu, p->inmin, p->inmax, p->outmin, p->outmax);
+
+ /* If we have a Jab PCS override, reflect this in the effective icx range. */
+ /* Note that the ab ranges are nominal. They will exceed this range */
+ /* for colors representable in L*a*b* PCS */
+ if (p->ins == icxSigJabData) {
+ p->inmin[0] = 0.0; p->inmax[0] = 100.0;
+ p->inmin[1] = -128.0; p->inmax[1] = 128.0;
+ p->inmin[2] = -128.0; p->inmax[2] = 128.0;
+ } else if (p->outs == icxSigJabData) {
+ p->outmin[0] = 0.0; p->outmax[0] = 100.0;
+ p->outmin[1] = -128.0; p->outmax[1] = 128.0;
+ p->outmin[2] = -128.0; p->outmax[2] = 128.0;
+ }
+
+ /* If we have a merged clut, reflect this in the icx native PCS range. */
+ /* Merging merges output processing (irrespective of whether we are using */
+ /* the forward or backward cluts) */
+ if (p->mergeclut != 0) {
+ int i;
+ for (i = 0; i < p->outputChan; i++) {
+ p->noutmin[i] = p->outmin[i];
+ p->noutmax[i] = p->outmax[i];
+ }
+ }
+
+ /* ------------------------------- */
+ /* Create rspl based input lookups */
+ for (i = 0; i < p->inputChan; i++) {
+ if ((p->inputTable[i] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of input table rspl failed");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ p->iol_out = 0; /* Input lookup */
+ p->iol_ch = i; /* Chanel */
+ p->inputTable[i]->set_rspl(p->inputTable[i], RSPL_NOFLAGS,
+ (void *)p, icxLuLut_inout_func,
+ &p->ninmin[i], &p->ninmax[i], (int *)&p->lut->inputEnt, &p->ninmin[i], &p->ninmax[i]);
+ }
+
+ /* Setup center clip target for inversion */
+ for (i = 0; i < p->inputChan; i++) {
+ p->inputClipc[i] = (p->ninmin[i] + p->ninmax[i])/2.0;
+ }
+
+ /* Create rspl based reverse input lookups used in ink limit and locus range functions. */
+ for (i = 0; i < p->inputChan; i++) {
+ int gres = p->inputTable[i]->g.mres; /* Same res as curve being inverted */
+ if (gres < 256)
+ gres = 256;
+ if ((p->revinputTable[i] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of reverse input table rspl failed");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ p->iol_out = 2; /* Input lookup */
+ p->iol_ch = i; /* Chanel */
+ p->revinputTable[i]->set_rspl(p->revinputTable[i], RSPL_NOFLAGS,
+ (void *)p, icxLuLut_inout_func,
+ &p->ninmin[i], &p->ninmax[i], &gres, &p->ninmin[i], &p->ninmax[i]);
+ }
+
+ /* ------------------------------- */
+ {
+ int gres[MXDI];
+
+ for (i = 0; i < p->inputChan; i++)
+ gres[i] = p->lut->clutPoints;
+
+ /* Create rspl based multi-dim table */
+ if ((p->clutTable = new_rspl((p->fastsetup ? RSPL_FASTREVSETUP : RSPL_NOFLAGS)
+ | (flags & ICX_VERBOSE ? RSPL_VERBOSE : RSPL_NOFLAGS),
+ p->inputChan, p->outputChan)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of clut table rspl failed");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ if (p->mergeclut == 0) { /* Do this if it's not merged with clut, */
+ p->clutTable->set_rspl(p->clutTable, RSPL_NOFLAGS,
+ (void *)luluto, (void (*)(void *, double *, double *))luluto->clut,
+ p->ninmin, p->ninmax, gres, p->noutmin, p->noutmax);
+
+ } else { /* If mergeclut */
+ p->clutTable->set_rspl(p->clutTable, RSPL_NOFLAGS,
+ (void *)p, icxLuLut_clut_merge_func,
+ p->ninmin, p->ninmax, gres, p->noutmin, p->noutmax);
+
+ }
+
+ /* clut clipping is setup separately */
+ }
+
+ /* ------------------------------- */
+ /* Create rspl based output lookups */
+ for (i = 0; i < p->outputChan; i++) {
+ if ((p->outputTable[i] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of output table rspl failed");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ p->iol_out = 1; /* Output lookup */
+ p->iol_ch = i; /* Chanel */
+ p->outputTable[i]->set_rspl(p->outputTable[i], RSPL_NOFLAGS,
+ (void *)p, icxLuLut_inout_func,
+ &p->noutmin[i], &p->noutmax[i], (int *)&p->lut->outputEnt, &p->noutmin[i], &p->noutmax[i]);
+ }
+
+ /* Setup center clip target for inversion */
+ for (i = 0; i < p->outputChan; i++) {
+ p->outputClipc[i] = (p->noutmin[i] + p->noutmax[i])/2.0;
+ }
+
+ /* ------------------------------- */
+
+ /* Setup all the clipping, ink limiting and auxiliary stuff, */
+ /* in case a reverse call is used. Only do this if we know */
+ /* the reverse stuff isn't going to fail due to channel limits. */
+ if (p->clutTable->within_restrictedsize(p->clutTable)) {
+
+ if (setup_ink_icxLuLut(p, ink, 1) != 0) {
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ if (setup_clip_icxLuLut(p) != 0) {
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ }
+
+ return (icxLuBase *)p;
+}
+
+
+/* Function to pass to rspl to set clut up, when camclip is going to be used. */
+/* We use the temporary icm fwd absolute xyz lookup, then convert to CAM Jab. */
+static void
+icxLuLut_clut_camclip_func(
+ void *pp, /* icxLuLut */
+ double *out, /* output value */
+ double *in /* inut value */
+) {
+ icxLuLut *p = (icxLuLut *)pp; /* this */
+ icmLuLut *luluto = (icmLuLut *)p->absxyzlu;
+
+ luluto->clut(luluto, out, in);
+ luluto->output(luluto, out, out);
+ luluto->out_abs(luluto, out, out);
+ p->cam->XYZ_to_cam(p->cam, out, out);
+}
+
+/* Initialise the additional CAM space clut rspl, used to compute */
+/* reverse lookup CAM clipping results when the camclip flag is set. */
+/* return error code. */
+static int
+icxLuLut_init_clut_camclip(
+icxLuLut *p) {
+ int e, gres[MXDI];
+
+ /* Setup so clut contains transform to CAM Jab */
+ /* (camclip is only used in fwd or invfwd direction lookup) */
+ double cmin[3], cmax[3];
+ cmin[0] = 0.0; cmax[0] = 100.0; /* Nominal Jab output ranges */
+ cmin[1] = -128.0; cmax[1] = 128.0;
+ cmin[2] = -128.0; cmax[2] = 128.0;
+
+ /* Get icm lookup we need for seting up and using CAM icx clut */
+ if ((p->absxyzlu = p->pp->pp->get_luobj(p->pp->pp, icmFwd, icAbsoluteColorimetric,
+ icSigXYZData, icmLuOrdNorm)) == NULL) {
+ p->pp->errc = p->pp->pp->errc; /* Copy error to xicc */
+ strcpy(p->pp->err, p->pp->pp->err);
+ return p->pp->errc;
+ }
+
+ /* Create CAM rspl based multi-dim table */
+ if ((p->cclutTable = new_rspl((p->fastsetup ? RSPL_FASTREVSETUP : RSPL_NOFLAGS)
+ | (p->flags & ICX_VERBOSE ? RSPL_VERBOSE : RSPL_NOFLAGS),
+ p->inputChan, p->outputChan)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of clut table rspl failed");
+ return p->pp->errc;
+ }
+
+ for (e = 0; e < p->inputChan; e++)
+ gres[e] = p->lut->clutPoints;
+
+ /* Setup our special CAM space rspl */
+ p->cclutTable->set_rspl(p->cclutTable, RSPL_NOFLAGS, (void *)p,
+ icxLuLut_clut_camclip_func,
+ p->ninmin, p->ninmax, gres, cmin, cmax);
+
+ /* Duplicate the ink limit information for any reverse interpolation. */
+ p->cclutTable->rev_set_limit(
+ p->cclutTable, /* this */
+ p->ink.tlimit >= 0.0 || p->ink.klimit >= 0.0 ? icxLimitD_void : NULL,
+ /* Optional input space limit() function. */
+ /* Function should evaluate in[0..di-1], and return */
+ /* number that is not to exceed 0.0. NULL if not used. */
+ (void *)p, /* Context passed to limit() */
+ 0.0 /* Value that limit() is not to exceed */
+ );
+ return 0;
+}
+
+/* ========================================================== */
+/* xicc creation code */
+/* ========================================================== */
+
+/* Callback for computing delta E squared for two output (PCS) */
+/* values, passed as a callback to xfit */
+static double xfit_to_de2(void *cntx, double *in1, double *in2) {
+ icxLuLut *p = (icxLuLut *)cntx;
+ double rv;
+
+ if (p->pcs == icSigLabData) {
+#ifdef USE_CIE94_DE
+ rv = icmCIE94sq(in1, in2);
+#else
+ rv = icmLabDEsq(in1, in2);
+#endif
+ } else {
+ double lab1[3], lab2[3];
+ icmXYZ2Lab(&icmD50, lab1, in1);
+ icmXYZ2Lab(&icmD50, lab2, in2);
+#ifdef USE_CIE94_DE
+ rv = icmCIE94sq(lab1, lab2);
+#else
+ rv = icmLabDEsq(lab1, lab2);
+#endif
+ }
+ return rv;
+}
+
+/* Same as above plus partial derivatives */
+static double xfit_to_dde2(void *cntx, double dout[2][MXDIDO], double *in1, double *in2) {
+ icxLuLut *p = (icxLuLut *)cntx;
+ double rv;
+
+ if (p->pcs == icSigLabData) {
+ int j,k;
+ double tdout[2][3];
+#ifdef USE_CIE94_DE
+ rv = icxdCIE94sq(tdout, in1, in2);
+#else
+ rv = icxdLabDEsq(tdout, in1, in2);
+#endif
+ for (k = 0; k < 2; k++) {
+ for (j = 0; j < 3; j++)
+ dout[k][j] = tdout[k][j];
+ }
+ } else {
+ double lab1[3], lab2[3];
+ double dout12[2][3][3];
+ double tdout[2][3];
+ int i,j,k;
+
+ icxdXYZ2Lab(&icmD50, lab1, dout12[0], in1);
+ icxdXYZ2Lab(&icmD50, lab2, dout12[1], in2);
+#ifdef USE_CIE94_DE
+ rv = icxdCIE94sq(tdout, lab1, lab2);
+#else
+ rv = icxdLabDEsq(tdout, lab1, lab2);
+#endif
+ /* Compute partial derivative (is this correct ??) */
+ for (k = 0; k < 2; k++) {
+ for (j = 0; j < 3; j++) {
+ dout[k][j] = 0.0;
+ for (i = 0; i < 3; i++) {
+ dout[k][j] += tdout[k][i] * dout12[k][i][j];
+ }
+ }
+ }
+ }
+ return rv;
+}
+
+#ifdef NEVER
+/* Check partial derivative function within xfit_to_dde2() */
+
+static double _xfit_to_dde2(void *cntx, double dout[2][MXDIDO], double *in1, double *in2) {
+ icxLuLut *pp = (icxLuLut *)cntx;
+ int k, i;
+ double rv, drv;
+ double trv;
+
+ rv = xfit_to_de2(cntx, in1, in2);
+ drv = xfit_to_dde2(cntx, dout, in1, in2);
+
+ if (fabs(rv - drv) > 1e-6)
+ printf("######## DDE2: RV MISMATCH is %f should be %f ########\n",rv,drv);
+
+ /* Check each parameter delta */
+ for (k = 0; k < 2; k++) {
+ for (i = 0; i < 3; i++) {
+ double *in;
+ double del;
+
+ if (k == 0)
+ in = in1;
+ else
+ in = in2;
+
+ in[i] += 1e-9;
+ trv = xfit_to_de2(cntx, in1, in2);
+ in[i] -= 1e-9;
+
+ /* Check that del is correct */
+ del = (trv - rv)/1e-9;
+ if (fabs(dout[k][i] - del) > 0.04) {
+ printf("######## DDE2: EXCESSIVE at in[%d][%d] is %f should be %f ########\n",k,i,dout[k][i],del);
+ }
+ }
+ }
+ return rv;
+}
+
+#define xfit_to_dde2 _xfit_to_dde2
+
+#endif
+
+/* Context for rspl setting input and output curves */
+typedef struct {
+ int iix;
+ int oix;
+ xfit *xf; /* Optimisation structure */
+} curvectx;
+
+/* Function to pass to rspl to set input and output */
+/* transfer function for xicc lookup function */
+static void
+set_linfunc(
+ void *cc, /* curvectx structure */
+ double *out, /* Device output value */
+ double *in /* Device input value */
+) {
+ curvectx *c = (curvectx *)cc; /* this */
+ xfit *p = c->xf;
+
+ if (c->iix >= 0) { /* Input curve */
+ *out = p->incurve(p, *in, c->iix);
+ } else if (c->oix >= 0) { /* Output curve */
+ *out = p->outcurve(p, *in, c->oix);
+ }
+}
+
+/* Function to pass to rspl to set inverse input transfer function, */
+/* used for ink limiting calculation. */
+static void
+icxLuLut_invinput_func(
+ void *cc, /* curvectx structure */
+ double *out, /* Device output value */
+ double *in /* Device input value */
+) {
+ curvectx *c = (curvectx *)cc; /* this */
+ xfit *p = c->xf;
+
+ *out = p->invincurve(p, *in, c->iix);
+}
+
+
+/* Functions to pass to icc settables() to setup icc A2B Lut: */
+
+/* Input table */
+static void set_input(void *cntx, double *out, double *in) {
+ icxLuLut *p = (icxLuLut *)cntx;
+
+ if (p->noisluts != 0 && p->noipluts != 0) { /* Input table must be linear */
+ int i;
+ for (i = 0; i < p->inputChan; i++)
+ out[i] = in[i];
+ } else {
+ if (p->input(p, out, in) > 1)
+ error ("%d, %s",p->pp->errc,p->pp->err);
+ }
+}
+
+/* clut */
+static void set_clut(void *cntx, double *out, double *in) {
+ icxLuLut *p = (icxLuLut *)cntx;
+ int f;
+
+ if (p->clut(p, out, in) > 1)
+ error ("%d, %s",p->pp->errc,p->pp->err);
+
+ /* Convert from efective pcs to natural pcs */
+ if (p->pcs != p->plu->icp->header->pcs) {
+ if (p->pcs == icSigLabData)
+ icmLab2XYZ(&icmD50, out, out);
+ else
+ icmXYZ2Lab(&icmD50, out, out);
+ }
+}
+
+/* output */
+static void set_output(void *cntx, double *out, double *in) {
+ icxLuLut *p = (icxLuLut *)cntx;
+
+ if (p->nooluts != 0) { /* Output table must be linear */
+ int i;
+ for (i = 0; i < p->outputChan; i++)
+ out[i] = in[i];
+ } else {
+ if (p->output(p, out, in) > 1)
+ error ("%d, %s",p->pp->errc,p->pp->err);
+ }
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Routine to figure out a suitable black point for CMYK */
+
+/* Structure to hold optimisation information */
+typedef struct {
+ icxLuLut *p; /* Object being created */
+ double toAbs[3][3]; /* To abs from aprox relative */
+ double p1[3]; /* white pivot point in abs Lab */
+ double p2[3]; /* Point on vector towards black */
+ double toll; /* Tollerance of black direction */
+} bfinds;
+
+/* Optimise device values to minimise L, while remaining */
+/* within the ink limit, and staying in line between p1 (white) and p2 (black dir) */
+static double bfindfunc(void *adata, double pv[]) {
+ bfinds *b = (bfinds *)adata;
+ double rv = 0.0;
+ double tt[3], Lab[3];
+ co bcc;
+ double lr, ta, tb, terr; /* L ratio, target a, target b, target error */
+ double ovr;
+
+//printf("~1 bfindfunc got %f %f %f %f\n", pv[0], pv[1], pv[2], pv[3]);
+ /* See if over ink limit or outside device range */
+ ovr = icxLimit(b->p, pv); /* > 0.0 if outside device gamut or ink limit */
+ if (ovr < 0.0)
+ ovr = 0.0;
+//printf("~1 bfindfunc got ovr %f\n", ovr);
+
+ /* Compute the absolute Lab value: */
+ b->p->input(b->p, bcc.p, pv); /* Through input tables */
+ b->p->clutTable->interp(b->p->clutTable, &bcc); /* Through clut */
+ b->p->output(b->p, bcc.v, bcc.v); /* Through the output tables */
+
+ if (b->p->pcs != icSigXYZData) /* Convert PCS to XYZ */
+ icmLab2XYZ(&icmD50, bcc.v, bcc.v);
+
+ /* Convert from relative to Absolute colorimetric */
+ icmMulBy3x3(tt, b->toAbs, bcc.v);
+ icmXYZ2Lab(&icmD50, Lab, tt); /* Convert to Lab */
+
+#ifdef DEBUG
+printf("~1 p1 = %f %f %f, p2 = %f %f %f\n",b->p1[0],b->p1[1],b->p1[2],b->p2[0],b->p2[1],b->p2[2]);
+printf("~1 device value %f %f %f %f, Lab = %f %f %f\n",pv[0],pv[1],pv[2],pv[3],Lab[0],Lab[1],Lab[2]);
+#endif
+
+ /* Primary aim is to minimise L value */
+ rv = Lab[0];
+
+ /* See how out of line from p1 to p2 we are */
+ lr = (Lab[0] - b->p1[0])/(b->p2[0] - b->p1[0]); /* Distance towards p2 from p1 */
+ ta = lr * (b->p2[1] - b->p1[1]) + b->p1[1]; /* Target a value */
+ tb = lr * (b->p2[2] - b->p1[2]) + b->p1[2]; /* Target b value */
+
+ terr = (ta - Lab[1]) * (ta - Lab[1])
+ + (tb - Lab[2]) * (tb - Lab[2]);
+
+ if (terr < b->toll) /* Tollerance error doesn't count until it's over tollerance */
+ terr = 0.0;
+
+#ifdef DEBUG
+printf("~1 target error %f\n",terr);
+#endif
+ rv += XICC_BLACK_FIND_ABERR_WEIGHT * terr; /* Make ab match more important than min. L */
+
+#ifdef DEBUG
+printf("~1 out of range error %f\n",ovr);
+#endif
+ rv += 200 * ovr;
+
+#ifdef DEBUG
+printf("~1 black find tc ret %f\n",rv);
+#endif
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Create icxLuLut and underlying fwd Lut from scattered data */
+/* The scattered data is assumed to map Device -> native PCS */
+/* NOTE:- in theory once this icxLuLut is setup, it can be */
+/* called to translate color values. In practice I suspect */
+/* that the icxLuLut hasn't been setup completely enough to allows this. */
+/* Might be easier to close it and re-open it ? */
+static icxLuBase *
+set_icxLuLut(
+xicc *xicp,
+icmLuBase *plu, /* Pointer to Lu we are expanding (ours) */
+icmLookupFunc func, /* Functionality requested */
+icRenderingIntent intent, /* Rendering intent */
+int flags, /* white/black point flags etc. */
+int nodp, /* Number of points */
+int nodpbw, /* Number of points to look for white & black patches in */
+cow *ipoints, /* Array of input points (Lab or XYZ normalized to 1.0) */
+icxMatrixModel *skm, /* Optional skeleton model (used for input profiles) */
+double dispLuminance, /* > 0.0 if display luminance value and is known */
+double wpscale, /* > 0.0 if white point is to be scaled */
+double smooth, /* RSPL smoothing factor, -ve if raw */
+double avgdev, /* reading Average Deviation as a prop. of the input range */
+icxViewCond *vc, /* Viewing Condition (NULL if not using CAM) */
+icxInk *ink, /* inking details (NULL for default) */
+int quality /* Quality metric, 0..3 */
+) {
+ icxLuLut *p; /* Object being created */
+ icc *icco = xicp->pp; /* Underlying icc object */
+ int luflags = 0; /* icxLuLut alloc clip, merge flags */
+ int pcsy; /* Effective PCS L or Y chanel index */
+ double pcsymax; /* Effective PCS L or Y maximum value */
+ icmHeader *h = icco->header; /* Pointer to icc header */
+ int maxchan; /* max(inputChan, outputChan) */
+ int rsplflags = RSPL_NOFLAGS; /* Flags for scattered data rspl */
+ int e, f, i, j;
+ double dwhite[MXDI], dblack[MXDI]; /* Device white and black values */
+ double wp[3]; /* Absolute White point in XYZ */
+ double bp[3]; /* Absolute Black point in XYZ */
+ double dgwhite[MXDI]; /* Device space gamut boundary white (ie. RGB 1,1,1) */
+ double oavgdev[MXDO]; /* Average output value deviation */
+ int gres[MXDI]; /* RSPL/CLUT resolution */
+ xfit *xf = NULL; /* Curve fitting class instance */
+
+ if (flags & ICX_VERBOSE)
+ rsplflags |= RSPL_VERBOSE;
+
+// if (flags & ICX_2PASSSMTH)
+// rsplflags |= RSPL_2PASSSMTH; /* Smooth data using Gaussian */
+
+// if (flags & ICX_EXTRA_FIT)
+// rsplflags |= RSPL_EXTRAFIT2; /* Try extra hard to fit data */
+
+ luflags = flags; /* Transfer straight though ? */
+
+ /* Do basic creation and initialisation */
+ if ((p = alloc_icxLuLut(xicp, plu, luflags)) == NULL)
+ return NULL;
+
+ p->func = func;
+
+ /* Set LuLut "use" specific creation flags: */
+ if (flags & ICX_CLIP_NEAREST)
+ p->nearclip = 1;
+
+ /* Set LuLut "create" specific flags: */
+ if (flags & ICX_NO_IN_SHP_LUTS)
+ p->noisluts = 1;
+
+ if (flags & ICX_NO_IN_POS_LUTS)
+ p->noipluts = 1;
+
+ if (flags & ICX_NO_OUT_LUTS)
+ p->nooluts = 1;
+
+ /* Get the effective spaces of underlying icm, and set icx the same */
+ plu->spaces(plu, &p->ins, NULL, &p->outs, NULL, NULL, &p->intent, NULL, &p->pcs, NULL);
+
+ /* For set_icx the effective pcs has to be the same as the native pcs */
+
+ if (p->pcs == icSigXYZData) {
+ pcsy = 1; /* Y of XYZ */
+ pcsymax = 1.0;
+ } else {
+ pcsy = 0; /* L or Lab */
+ pcsymax = 100.0;
+ }
+
+ maxchan = p->inputChan > p->outputChan ? p->inputChan : p->outputChan;
+
+ /* Translate overall average deviation into output channel deviation */
+ /* (This is for rspl scattered data fitting smoothness adjustment) */
+ /* (This could do with more tuning) */
+
+ /* For some unknown reason XYZ seems masively under-smoothed, so bump it up */
+ if (p->pcs == icSigXYZData) {
+ oavgdev[0] = 1.0 * 0.60 * avgdev;
+ oavgdev[1] = 1.0 * 1.00 * avgdev;
+ oavgdev[2] = 1.0 * 0.60 * avgdev;
+ } else if (p->pcs == icSigLabData) {
+ oavgdev[0] = 1.00 * avgdev;
+ oavgdev[1] = 0.60 * avgdev;
+ oavgdev[2] = 0.60 * avgdev;
+ } else { /* Hmmm */
+ for (f = 0; f < p->outputChan; f++)
+ oavgdev[f] = avgdev;
+ }
+
+ /* In general the native and effective ranges of the icx will be the same as the */
+ /* underlying icm lookup object. */
+ p->plu->get_lutranges(p->plu, p->ninmin, p->ninmax, p->noutmin, p->noutmax);
+ p->plu->get_ranges(p->plu, p->inmin, p->inmax, p->outmin, p->outmax);
+
+ /* ??? Does this ever happen with set_icxLuLut() ??? */
+ /* If we have a Jab PCS override, reflect this in the effective icx range. */
+ /* Note that the ab ranges are nominal. They will exceed this range */
+ /* for colors representable in L*a*b* PCS */
+ if (p->ins == icxSigJabData) {
+ p->inmin[0] = 0.0; p->inmax[0] = 100.0;
+ p->inmin[1] = -128.0; p->inmax[1] = 128.0;
+ p->inmin[2] = -128.0; p->inmax[2] = 128.0;
+ } else if (p->outs == icxSigJabData) {
+ p->outmin[0] = 0.0; p->outmax[0] = 100.0;
+ p->outmin[1] = -128.0; p->outmax[1] = 128.0;
+ p->outmin[2] = -128.0; p->outmax[2] = 128.0;
+ }
+
+ /* ------------------------------- */
+
+ if (flags & ICX_VERBOSE)
+ printf("Estimating white point\n");
+
+ icmXYZ2Ary(wp, icmD50); /* Set a default value - D50 */
+ icmXYZ2Ary(bp, icmBlack); /* Set a default value - absolute black */
+
+ {
+ /* Figure out as best we can the device white and black points */
+
+ /* Compute device white and black points as if */
+ /* we are doing an Output or Display device */
+ {
+ switch (h->colorSpace) {
+
+ case icSigCmykData:
+ for (e = 0; e < p->inputChan; e++) {
+ dwhite[e] = 0.0;
+ dblack[e] = 1.0;
+ }
+ break;
+ case icSigCmyData:
+ for (e = 0; e < p->inputChan; e++) {
+ dwhite[e] = 0.0;
+ dblack[e] = 1.0;
+ }
+ break;
+ case icSigRgbData:
+ for (e = 0; e < p->inputChan; e++) {
+ dwhite[e] = 1.0;
+ dblack[e] = 0.0;
+ }
+ break;
+
+ case icSigGrayData: { /* Could be additive or subtractive */
+ double maxY, minY; /* Y min and max */
+ double maxd, mind; /* Corresponding device values */
+
+ maxY = -1e8, minY = 1e8;
+
+ /* Figure out if it's additive or subtractive */
+ for (i = 0; i < nodpbw; i++) {
+ double Y;
+ if (p->pcs != icSigXYZData) { /* Convert white point to XYZ */
+ double xyz[3];
+ icmLab2XYZ(&icmD50, xyz, ipoints[i].v);
+ Y = xyz[1];
+ } else {
+ Y = ipoints[i].v[1];
+ }
+
+ if (Y > maxY) {
+ maxY = Y;
+ maxd = ipoints[i].p[0];
+ }
+ if (Y < minY) {
+ minY = Y;
+ mind = ipoints[i].p[0];
+ }
+ }
+ if (maxd < mind) { /* Subtractive */
+ for (e = 0; e < p->inputChan; e++) {
+ dwhite[e] = 0.0;
+ dblack[e] = 1.0;
+ }
+ } else { /* Additive */
+ for (e = 0; e < p->inputChan; e++) {
+ dwhite[e] = 1.0;
+ dblack[e] = 0.0;
+ }
+ }
+ break;
+ }
+ default:
+ xicp->errc = 1;
+ sprintf(xicp->err,"set_icxLuLut: can't handle color space %s",
+ icm2str(icmColorSpaceSignature, h->colorSpace));
+ p->del((icxLuBase *)p);
+ return NULL;
+ break;
+ }
+ }
+ /* dwhite is what we want for dgwhite[], used for XFIT_OUT_WP_REL_US */
+ for (e = 0; e < p->inputChan; e++)
+ dgwhite[e] = dwhite[e];
+
+ /* If this is actuall an input device, lookup wp & bp */
+ /* and override dwhite & dblack */
+ if (h->deviceClass == icSigInputClass) {
+ double wpy = -1e60, bpy = 1e60;
+ int wix = -1, bix = -1;
+ /* We assume that the input target is well behaved, */
+ /* and that it includes a white and black point patch, */
+ /* and that they have the extreme L/Y values */
+
+ /*
+ NOTE that this may not be the best approach !
+ It may be better to average the chromaticity
+ of all the neutral seeming patches, since
+ the whitest patch may have (for instance)
+ a blue tint.
+ */
+
+ /* Discover the white and black patches */
+ for (i = 0; i < nodpbw; i++) {
+ double labv[3], yv;
+
+ /* Create D50 Lab to allow some chromatic sensitivity */
+ /* in picking the white point */
+ if (p->pcs == icSigXYZData)
+ icmXYZ2Lab(&icmD50, labv, ipoints[i].v);
+ else
+ icmCpy3(labv,ipoints[i].v);
+
+#ifdef NEVER
+ /* Choose largest Y or L* */
+ if (ipoints[i].v[pcsy] > wpy) {
+ wp[0] = ipoints[i].v[0];
+ wp[1] = ipoints[i].v[1];
+ wp[2] = ipoints[i].v[2];
+ for (e = 0; e < p->inputChan; e++)
+ dwhite[e] = ipoints[i].p[e];
+ wpy = ipoints[i].v[pcsy];
+ wix = i;
+ }
+#else
+
+ /* Tilt things towards D50 neutral white patches */
+ yv = labv[0] - 0.3 * sqrt(labv[1] * labv[1] + labv[2] * labv[2]);
+//printf("~1 patch %d Lab = %s, yv = %f\n",i+1,icmPdv(3,labv),yv);
+ if (yv > wpy) {
+//printf("~1 best so far\n");
+ wp[0] = ipoints[i].v[0];
+ wp[1] = ipoints[i].v[1];
+ wp[2] = ipoints[i].v[2];
+ for (e = 0; e < p->inputChan; e++)
+ dwhite[e] = ipoints[i].p[e];
+ wpy = yv;
+ wix = i;
+ }
+#endif
+ if (ipoints[i].v[pcsy] < bpy) {
+ bp[0] = ipoints[i].v[0];
+ bp[1] = ipoints[i].v[1];
+ bp[2] = ipoints[i].v[2];
+ for (e = 0; e < p->inputChan; e++)
+ dblack[e] = ipoints[i].p[e];
+ bpy = ipoints[i].v[pcsy];
+ bix = i;
+ }
+ }
+ /* Make sure values are XYZ */
+ if (p->pcs != icSigXYZData) {
+ icmLab2XYZ(&icmD50, wp, wp);
+ icmLab2XYZ(&icmD50, bp, bp);
+ }
+
+ if (flags & ICX_VERBOSE) {
+ printf("Picked white patch %d with dev = %s\n XYZ = %s, Lab = %s\n",
+ wix+1, icmPdv(p->inputChan, dwhite), icmPdv(3, wp), icmPLab(wp));
+ printf("Picked black patch %d with dev = %s\n XYZ = %s, Lab = %s\n",
+ bix+1, icmPdv(p->inputChan, dblack), icmPdv(3, bp), icmPLab(bp));
+ }
+
+ /* else Output or Display device */
+ } else {
+ /* We assume that the output target is well behaved, */
+ /* and that it includes a white point patch. */
+ int nw = 0;
+
+ wp[0] = wp[1] = wp[2] = 0.0;
+
+ switch (h->colorSpace) {
+
+ case icSigCmykData:
+ for (i = 0; i < nodpbw; i++) {
+ if (ipoints[i].p[0] < 0.001
+ && ipoints[i].p[1] < 0.001
+ && ipoints[i].p[2] < 0.001
+ && ipoints[i].p[3] < 0.001) {
+ wp[0] += ipoints[i].v[0];
+ wp[1] += ipoints[i].v[1];
+ wp[2] += ipoints[i].v[2];
+ nw++;
+ }
+ }
+ break;
+ case icSigCmyData:
+ for (i = 0; i < nodpbw; i++) {
+ if (ipoints[i].p[0] < 0.001
+ && ipoints[i].p[1] < 0.001
+ && ipoints[i].p[2] < 0.001) {
+ wp[0] += ipoints[i].v[0];
+ wp[1] += ipoints[i].v[1];
+ wp[2] += ipoints[i].v[2];
+ nw++;
+ }
+ }
+ break;
+ case icSigRgbData:
+ for (i = 0; i < nodpbw; i++) {
+ if (ipoints[i].p[0] > 0.999
+ && ipoints[i].p[1] > 0.999
+ && ipoints[i].p[2] > 0.999) {
+ wp[0] += ipoints[i].v[0];
+ wp[1] += ipoints[i].v[1];
+ wp[2] += ipoints[i].v[2];
+ nw++;
+ }
+ }
+ break;
+
+ case icSigGrayData: { /* Could be additive or subtractive */
+ double minwp[3], maxwp[3];
+ int nminwp = 0, nmaxwp = 0;
+
+ minwp[0] = minwp[1] = minwp[2] = 0.0;
+ maxwp[0] = maxwp[1] = maxwp[2] = 0.0;
+
+ /* Look for both */
+ for (i = 0; i < nodpbw; i++) {
+ if (ipoints[i].p[0] < 0.001)
+ minwp[0] += ipoints[i].v[0];
+ minwp[1] += ipoints[i].v[1];
+ minwp[2] += ipoints[i].v[2]; {
+ nminwp++;
+ }
+ if (ipoints[i].p[0] > 0.999)
+ maxwp[0] += ipoints[i].v[0];
+ maxwp[1] += ipoints[i].v[1];
+ maxwp[2] += ipoints[i].v[2]; {
+ nmaxwp++;
+ }
+ }
+ if (nminwp > 0) { /* Subtractive */
+ wp[0] = minwp[0];
+ wp[1] = minwp[1];
+ wp[2] = minwp[2];
+ nw = nminwp;
+ if (minwp[pcsy]/nminwp < (0.5 * pcsymax))
+ nw = 0; /* Looks like a mistake */
+ }
+ if (nmaxwp > 0 /* Additive */
+ && (nminwp == 0 || maxwp[pcsy]/nmaxwp > minwp[pcsy]/nminwp)) {
+ wp[0] = maxwp[0];
+ wp[1] = maxwp[1];
+ wp[2] = maxwp[2];
+ nw = nmaxwp;
+ if (maxwp[pcsy]/nmaxwp < (0.5 * pcsymax))
+ nw = 0; /* Looks like a mistake */
+ }
+ break;
+ }
+
+ default:
+ xicp->errc = 1;
+ sprintf(xicp->err,"set_icxLuLut: can't handle color space %s",
+ icm2str(icmColorSpaceSignature, h->colorSpace));
+ p->del((icxLuBase *)p);
+ return NULL;
+ break;
+ }
+
+ if (nw == 0) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"set_icxLuLut: can't handle test points without a white patch");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ wp[0] /= (double)nw;
+ wp[1] /= (double)nw;
+ wp[2] /= (double)nw;
+ if (p->pcs != icSigXYZData) /* Convert white point to XYZ */
+ icmLab2XYZ(&icmD50, wp, wp);
+ }
+
+ if (flags & ICX_VERBOSE) {
+ printf("Approximate White point XYZ = %s, Lab = %s\n", icmPdv(3,wp),icmPLab(wp));
+ }
+ }
+
+ if (h->colorSpace == icSigGrayData) { /* Don't use device or PCS curves for monochrome */
+ p->noisluts = p->noipluts = p->nooluts = 1;
+ }
+
+ if ((flags & ICX_VERBOSE) && (p->noisluts == 0 || p->noipluts == 0 || p->nooluts == 0))
+ printf("Creating optimised per channel curves\n");
+
+ /* Set the target CLUT grid resolution so in/out curves can be optimised for it */
+ for (e = 0; e < p->inputChan; e++)
+ gres[e] = p->lut->clutPoints;
+
+ /* Setup and then create xfit object that does most of the work */
+ {
+ int xfflags = 0; /* xfit flags */
+ double in_min[MXDI]; /* Input value scaling minimum */
+ double in_max[MXDI]; /* Input value scaling maximum */
+ double out_min[MXDO]; /* Output value scaling minimum */
+ double out_max[MXDO]; /* Output value scaling maximum */
+ int iluord, sluord, oluord;
+ int iord[MXDI]; /* Input curve orders */
+ int sord[MXDI]; /* Input sub-grid curve orders */
+ int oord[MXDO]; /* Output curve orders */
+ double shp_smooth[MXDI];/* Smoothing factors for each curve, nom = 1.0 */
+ double out_smooth[MXDO];
+
+ optcomb tcomb = oc_ipo; /* Create all by default */
+
+ if ((xf = CAT2(new_, xfit)()) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of xfit object failed");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ /* Setup for optimising run */
+ if (p->noisluts)
+ tcomb &= ~oc_i;
+
+ if (p->noipluts)
+ tcomb &= ~oc_p;
+
+ if (p->nooluts)
+ tcomb &= ~oc_o;
+
+ if (flags & ICX_VERBOSE)
+ xfflags |= XFIT_VERB;
+
+ if (flags & ICX_SET_WHITE) {
+
+ xfflags |= XFIT_OUT_WP_REL;
+ if ((flags & ICX_SET_WHITE_C) == ICX_SET_WHITE_C) {
+ xfflags |= XFIT_OUT_WP_REL_C;
+ }
+ else if ((flags & ICX_SET_WHITE_US) == ICX_SET_WHITE_US)
+ xfflags |= XFIT_OUT_WP_REL_US;
+
+ if (p->pcs != icSigXYZData)
+ xfflags |= XFIT_OUT_LAB;
+ }
+
+ /* If asked, clip the absolute white point to have Y <= 1.0 ? */
+ if (flags & ICX_CLIP_WB)
+ xfflags |= XFIT_CLIP_WP;
+
+ /* With current B2A code, make sure a & b curves */
+ /* pass through zero. */
+ if (p->pcs == icSigLabData) {
+ xfflags |= XFIT_OUT_ZERO;
+ }
+
+ /* Let xfit create the clut */
+ xfflags |= XFIT_MAKE_CLUT;
+
+ /* Set the curve orders for input (device) and output (PCS) */
+ if (quality >= 3) { /* Ultra high */
+ iluord = 25;
+ sluord = 4;
+ oluord = 25;
+ } else if (quality == 2) { /* High */
+ iluord = 20;
+ sluord = 3;
+ oluord = 20;
+ } else if (quality == 1) { /* Medium */
+ iluord = 17;
+ sluord = 2;
+ oluord = 17;
+ } else { /* Low */
+ iluord = 10;
+ sluord = 1;
+ oluord = 10;
+ }
+ for (e = 0; e < p->inputChan; e++) {
+ iord[e] = iluord;
+ sord[e] = sluord;
+ in_min[e] = p->inmin[e];
+ in_max[e] = p->inmax[e];
+ shp_smooth[e] = SHP_SMOOTH;
+ }
+
+ for (f = 0; f < p->outputChan; f++) {
+ oord[f] = oluord;
+ out_min[f] = p->outmin[f];
+ out_max[f] = p->outmax[f];
+
+ /* Hack to prevent a convex L curve pushing */
+ /* the clut L values above the maximum value */
+ /* that can be represented, causing clipping. */
+ /* Do this by making sure that the L curve pivots */
+ /* through 100.0 to 100.0 */
+ if (f == 0 && p->pcs == icSigLabData) {
+ if (out_min[f] < 0.0001 && out_max[f] > 100.0) {
+ out_max[f] = 100.0;
+ }
+ }
+ out_smooth[f] = OUT_SMOOTH1;
+ if (f != 0 && p->pcs == icSigLabData) /* a* & b* */
+ out_smooth[f] = OUT_SMOOTH2;
+ }
+
+//printf("~1 wp before xfit %f %f %f\n", wp[0], wp[1], wp[2]);
+ /* Create input, sub and output per channel curves (if configured), */
+ /* adjust for white point to make relative (if configured), */
+ /* and create clut rspl using xfit class. */
+ /* The true white point for the returned curves and rspl is returned. */
+ if (xf->fit(xf, xfflags, p->inputChan, p->outputChan,
+ rsplflags, wp, dwhite, wpscale, dgwhite,
+ ipoints, nodp, skm, in_min, in_max, gres, out_min, out_max,
+ smooth, oavgdev, iord, sord, oord, shp_smooth, out_smooth, tcomb,
+ (void *)p, xfit_to_de2, xfit_to_dde2) != 0) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"xfit fitting failed");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+//printf("~1 wp after xfit %f %f %f\n", wp[0], wp[1], wp[2]);
+
+ /* - - - - - - - - - - - - - - - */
+ /* Set the xicc input curve rspl */
+ for (e = 0; e < p->inputChan; e++) {
+ curvectx cx;
+
+ cx.xf = xf;
+ cx.oix = -1;
+ cx.iix = e;
+
+ if ((p->inputTable[e] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of input table rspl failed");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ p->inputTable[e]->set_rspl(p->inputTable[e], RSPL_NOFLAGS,
+ (void *)&cx, set_linfunc,
+ &p->ninmin[e], &p->ninmax[e],
+ (int *)&p->lut->inputEnt,
+ &p->ninmin[e], &p->ninmax[e]);
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Set the xicc output curve rspl */
+ for (f = 0; f < p->outputChan; f++) {
+ curvectx cx;
+
+ cx.xf = xf;
+ cx.iix = -1;
+ cx.oix = f;
+
+ if ((p->outputTable[f] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of output table rspl failed");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ p->outputTable[f]->set_rspl(p->outputTable[f], RSPL_NOFLAGS,
+ (void *)&cx, set_linfunc,
+ &p->noutmin[f], &p->noutmax[f],
+ (int *)&p->lut->outputEnt,
+ &p->noutmin[f], &p->noutmax[f]);
+
+ }
+ }
+
+ if (flags & ICX_VERBOSE)
+ printf("Creating fast inverse input lookups\n");
+
+ /* Create rspl based reverse input lookups used in ink limit function. */
+ for (e = 0; e < p->inputChan; e++) {
+ int res = 256;
+ curvectx cx;
+
+ cx.xf = xf;
+ cx.oix = -1;
+ cx.iix = e;
+
+ if ((p->revinputTable[e] = new_rspl(RSPL_NOFLAGS, 1, 1)) == NULL) {
+ p->pp->errc = 2;
+ sprintf(p->pp->err,"Creation of reverse input table rspl failed");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ p->revinputTable[e]->set_rspl(p->revinputTable[e], RSPL_NOFLAGS,
+ (void *)&cx, icxLuLut_invinput_func,
+ &p->ninmin[e], &p->ninmax[e], &res, &p->ninmin[e], &p->ninmax[e]);
+ }
+
+
+ /* ------------------------------- */
+ /* Set clut lookup table from xfit */
+ p->clutTable = xf->clut;
+ xf->clut = NULL;
+
+ /* Setup all the clipping, ink limiting and auxiliary stuff, */
+ /* in case a reverse call is used. Need to avoid relying on inking */
+ /* stuff that makes use of the white/black points, since they haven't */
+ /* been set up properly yet. */
+ if (setup_ink_icxLuLut(p, ink, 0) != 0) {
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ /* Deal with finalizing white/black points */
+ {
+
+ if ((flags & ICX_SET_WHITE) && (flags & ICX_VERBOSE)) {
+ printf("White point XYZ = %s, Lab = %s\n", icmPdv(3,wp),icmPLab(wp));
+ }
+
+ /* Lookup the black point */
+ { /* Black Point Tag: */
+ co bcc;
+
+ if (flags & ICX_VERBOSE)
+ printf("Find black point\n");
+
+ /* !!! Hmm. For CMY and RGB we are simply using the device */
+ /* combination values as the black point. In reality we might */
+ /* want to have the option of using a neutral black point, */
+ /* just like CMYK ?? */
+
+ /* For CMYK devices, we choose a black that has minumum L within */
+ /* the ink limits, and if XICC_NEUTRAL_CMYK_BLACK it will in the direction */
+ /* that has the same chromaticity as the white point, else choose the same */
+ /* Lab vector direction as K, with the minimum L value. */
+ /* (Note this is duplicated in xicc.c icxLu_comp_bk_point() !!!) */
+ if (h->deviceClass != icSigInputClass
+ && h->colorSpace == icSigCmykData) {
+ bfinds bfs; /* Callback context */
+ double sr[MXDO]; /* search radius */
+ double tt[MXDO]; /* Temporary */
+ double rs0[MXDO], rs1[MXDO]; /* Random start candidates */
+ int trial;
+ double brv;
+ int kch = 3;
+
+ /* Setup callback function context */
+ bfs.p = p;
+ bfs.toll = XICC_BLACK_POINT_TOLL;
+
+ /* !!! we should use an accessor funcion of xfit !!! */
+ for (i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ bfs.toAbs[i][j] = xf->toAbs[i][j];
+ }
+ }
+
+ /* Lookup abs Lab value of white point */
+ icmXYZ2Lab(&icmD50, bfs.p1, wp);
+
+#ifdef XICC_NEUTRAL_CMYK_BLACK
+ icmScale3(tt, wp, 0.02); /* Scale white XYZ towards 0,0,0 */
+ icmXYZ2Lab(&icmD50, bfs.p2, tt); /* Convert black direction to Lab */
+ if (flags & ICX_VERBOSE)
+ printf("Neutral black direction (Lab) = %f %f %f\n",bfs.p2[0], bfs.p2[1], bfs.p2[2]);
+
+#else /* K direction black */
+ /* Now figure abs Lab value of K only, as the direction */
+ /* to use for the rich black. */
+ for (e = 0; e < p->inputChan; e++)
+ bcc.p[e] = 0.0;
+ if (p->ink.klimit < 0.0)
+ bcc.p[kch] = 1.0;
+ else
+ bcc.p[kch] = p->ink.klimit; /* K value */
+
+ p->input(p, bcc.p, bcc.p); /* Through input tables */
+ p->clutTable->interp(p->clutTable, &bcc); /* Through clut */
+ p->output(p, bcc.v, bcc.v); /* Through the output tables */
+
+ if (p->pcs != icSigXYZData) /* Convert PCS to XYZ */
+ icmLab2XYZ(&icmD50, bcc.v, bcc.v);
+
+ /* Convert from relative to Absolute colorimetric */
+ icmMulBy3x3(tt, xf->toAbs, bcc.v);
+ icmXYZ2Lab(&icmD50, bfs.p2, tt); /* Convert K only black point to Lab */
+
+ if (flags & ICX_VERBOSE)
+ printf("K only black direction (Lab) = %f %f %f\n",bfs.p2[0], bfs.p2[1], bfs.p2[2]);
+#endif
+ /* Start with the K only as the current best value */
+ brv = bfindfunc((void *)&bfs, bcc.p);
+//printf("~1 initial brv for K only = %f\n",brv);
+
+ /* Set the random start 0 location as 000K */
+ /* and the random start 1 location as CMY0 */
+ {
+ double tv;
+
+ for (e = 0; e < p->inputChan; e++)
+ rs0[e] = 0.0;
+ if (p->ink.klimit < 0.0)
+ rs0[kch] = 1.0;
+ else
+ rs0[kch] = p->ink.klimit; /* K value */
+
+ if (p->ink.tlimit < 0.0)
+ tv = 1.0;
+ else
+ tv = p->ink.tlimit/(p->inputChan - 1.0);
+ for (e = 0; e < p->inputChan; e++)
+ rs1[e] = tv;
+ rs1[kch] = 0.0; /* K value */
+ }
+
+ /* Find the device black point using optimization */
+ /* Do several trials to avoid local minima. */
+ rand32(0x12345678); /* Make trial values deterministic */
+ for (trial = 0; trial < 200; trial++) {
+ double rv; /* Temporary */
+
+ /* Start first trial at 000K */
+ if (trial == 0) {
+ for (j = 0; j < p->inputChan; j++) {
+ tt[j] = rs0[j];
+ sr[j] = 0.1;
+ }
+
+ } else {
+ /* Base is random between 000K and CMY0: */
+ if (trial < 100) {
+ rv = d_rand(0.0, 1.0);
+ for (j = 0; j < p->inputChan; j++) {
+ tt[j] = rv * rs0[j] + (1.0 - rv) * rs1[j];
+ sr[j] = 0.1;
+ }
+ /* Base on current best */
+ } else {
+ for (j = 0; j < p->inputChan; j++) {
+ tt[j] = bcc.p[j];
+ sr[j] = 0.1;
+ }
+ }
+
+ /* Then add random start offset */
+ for (rv = 0.0, j = 0; j < p->inputChan; j++) {
+ tt[j] += d_rand(-0.5, 0.5);
+ if (tt[j] < 0.0)
+ tt[j] = 0.0;
+ else if (tt[j] > 1.0)
+ tt[j] = 1.0;
+ }
+ }
+
+ /* Clip to be within ink limit */
+ icxDoLimit(p, tt, tt);
+
+ if (powell(&rv, p->inputChan, tt, sr, 0.000001, 1000,
+ bfindfunc, (void *)&bfs, NULL, NULL) == 0) {
+//printf("~1 trial %d, rv %f bp %f %f %f %f\n",trial,rv,tt[0],tt[1],tt[2],tt[3]);
+ if (rv < brv) {
+//printf("~1 new best\n");
+ brv = rv;
+ for (j = 0; j < p->inputChan; j++)
+ bcc.p[j] = tt[j];
+ }
+ }
+ }
+ if (brv > 1000.0)
+ error ("set_icxLuLut: Black point powell failed");
+
+ /* Make sure resulting device values are strictly in range */
+ for (j = 0; j < p->inputChan; j++) {
+ if (bcc.p[j] < 0.0)
+ bcc.p[j] = 0.0;
+ else if (bcc.p[j] > 1.0)
+ bcc.p[j] = 1.0;
+ }
+ /* Now have device black in bcc.p[] */
+//printf("~1 Black point is CMYK %f %f %f %f\n", bcc.p[0], bcc.p[1], bcc.p[2], bcc.p[3]);
+
+ /* Else not a CMYK output device, */
+ /* use the previously determined device black value. */
+ } else {
+ for (e = 0; e < p->inputChan; e++)
+ bcc.p[e] = dblack[e];
+ }
+
+ /* Lookup the PCS for the device black: */
+ p->input(p, bcc.p, bcc.p); /* Through input tables */
+ p->clutTable->interp(p->clutTable, &bcc); /* Through clut */
+ p->output(p, bcc.v, bcc.v); /* Through the output tables */
+
+ if (p->pcs != icSigXYZData) /* Convert PCS to XYZ */
+ icmLab2XYZ(&icmD50, bcc.v, bcc.v);
+
+ /* Convert from relative to Absolute colorimetric */
+ icmMulBy3x3(bp, xf->toAbs, bcc.v);
+
+ /* Got XYZ black point in bp[] */
+ if (flags & ICX_VERBOSE) {
+ printf("Black point XYZ = %s, Lab = %s\n", icmPdv(3,bp),icmPLab(bp));
+ }
+
+ /* Some ICC sw gets upset if the bp is at all -ve. */
+ /* Clip it if this is the case */
+ /* (Or we could get xfit to rescale the rspl instead ??) */
+ if ((flags & ICX_CLIP_WB)
+ && (bp[0] < 0.0 || bp[1] < 0.0 || bp[2] < 0.0)) {
+ if (bp[0] < 0.0)
+ bp[0] = 0.0;
+ if (bp[1] < 0.0)
+ bp[1] = 0.0;
+ if (bp[2] < 0.0)
+ bp[2] = 0.0;
+ if (flags & ICX_VERBOSE) {
+ printf("Black point clipped to XYZ = %s, Lab = %s\n",icmPdv(3,bp),icmPLab(bp));
+ }
+ }
+ }
+
+ /* If this is a display, adjust the white point to be */
+ /* exactly Y = 1.0, and compensate the dispLuminance */
+ /* and black point accordingly. The Lut is already set to */
+ /* assume device white maps to perfect PCS white. */
+ if (h->deviceClass == icSigDisplayClass) {
+ double scale = 1.0/wp[1];
+ int i;
+
+ dispLuminance /= scale;
+
+ for (i = 0; i < 3; i++) {
+ wp[i] *= scale;
+ bp[i] *= scale;
+ }
+ }
+
+ if (h->deviceClass == icSigDisplayClass
+ && dispLuminance > 0.0) {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)icco->read_tag(
+ icco, icSigLuminanceTag)) == NULL) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_luminance: couldn't find luminance tag");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ if (wo->ttype != icSigXYZArrayType) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"luminance: tag has wrong type");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.0;
+ wo->data[0].Y = dispLuminance * wp[1];
+ wo->data[0].Z = 0.0;
+
+ if (flags & ICX_VERBOSE)
+ printf("Display Luminance = %f\n", wo->data[0].Y);
+ }
+
+ /* Write white and black points */
+ if (flags & ICX_SET_WHITE) { /* White Point Tag: */
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)icco->read_tag(
+ icco, icSigMediaWhitePointTag)) == NULL) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_white_black: couldn't find white tag");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ if (wo->ttype != icSigXYZArrayType) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_white_black: white tag has wrong type");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = wp[0];
+ wo->data[0].Y = wp[1];
+ wo->data[0].Z = wp[2];
+ }
+ if (flags & ICX_SET_BLACK) { /* Black Point Tag: */
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)icco->read_tag(
+ icco, icSigMediaBlackPointTag)) == NULL) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_white_black: couldn't find black tag");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ if (wo->ttype != icSigXYZArrayType) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_white_black: black tag has wrong type");
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = bp[0];
+ wo->data[0].Y = bp[1];
+ wo->data[0].Z = bp[2];
+ }
+ if ((flags & ICX_SET_WHITE) || (flags & ICX_SET_BLACK)) {
+ /* Make sure ICC white/black point lookup notices the new white and black points */
+ p->plu->init_wh_bk(p->plu);
+ }
+
+ /* Setup the clut clipping, ink limiting and auxiliary stuff again */
+ /* since re_set_rspl will have invalidated */
+ if (setup_ink_icxLuLut(p, ink, 1) != 0) {
+ xf->del(xf);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ }
+
+ /* Done with xfit now */
+ xf->del(xf);
+ xf = NULL;
+
+ if (setup_clip_icxLuLut(p) != 0) {
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ /* ------------------------------- */
+
+//Debugging clipping of clut
+//printf("~1 xlut.c: noutmin = %f %f %f\n", p->noutmin[0], p->noutmin[1], p->noutmin[2]);
+//printf("~1 xlut.c: noutmax = %f %f %f\n", p->noutmax[0], p->noutmax[1], p->noutmax[2]);
+//printf("~1 xlut.c: outmin = %f %f %f\n", p->outmin[0], p->outmin[1], p->outmin[2]);
+//printf("~1 xlut.c: outmax = %f %f %f\n", p->outmax[0], p->outmax[1], p->outmax[2]);
+
+ /* Do a specific test for out of Lab encoding range RGB primaries */
+ /* (A more general check seems to get false positives - why ??) */
+ if (h->pcs == icSigLabData
+ && ( h->deviceClass == icSigDisplayClass
+ || h->deviceClass == icSigOutputClass)
+ && h->colorSpace == icSigRgbData) {
+ double dev[3] = { 0.0, 0.0, 0.0 };
+ double pcs[3];
+ double clip = 0;
+
+ for (i = 0; i < 3; i++) {
+ dev[i] = 1.0;
+
+ if (p->clut(p, pcs, dev) > 1)
+ error ("%d, %s",p->pp->errc,p->pp->err);
+
+ /* Convert from efective pcs to natural pcs */
+ if (p->pcs != icSigLabData)
+ icmXYZ2Lab(&icmD50, pcs, pcs);
+
+ if (pcs[1] < -128.0 || pcs[1] > 128.0
+ || pcs[2] < -128.0 || pcs[2] > 128.0) {
+ warning("\n *** %s primary value can't be encoded in L*a*b* PCS (%f %f %f)",
+ i == 0 ? "Red" : i == 1 ? "Green" : "Blue", pcs[0],pcs[1],pcs[2]);
+ clip = 1;
+ }
+ dev[i] = 0.0;
+ }
+ if (clip)
+ a1logw(g_log," *** Try switching to XYZ PCS ***\n");
+ }
+
+ /* Use our rspl's to set the icc Lut AtoB table values. */
+ /* Use helper function to do the hard work. */
+ if (p->lut->set_tables(p->lut, ICM_CLUT_SET_EXACT, (void *)p,
+ h->colorSpace, /* Input color space */
+ h->pcs, /* Output color space */
+ set_input, /* Input transfer function, Dev->Dev' */
+ NULL, NULL, /* Use default Maximum range of Dev' values */
+ set_clut, /* Dev' -> PCS' transfer function */
+ NULL, NULL, /* Use default Maximum range of PCS' values */
+ set_output /* Linear output transform PCS'->PCS */
+ ) != 0)
+ error("Setting 16 bit %s->%s Lut failed: %d, %s",
+ icm2str(icmColorSpaceSignature, h->colorSpace),
+ icm2str(icmColorSpaceSignature, h->pcs),
+ p->pp->pp->errc,p->pp->pp->err);
+
+#ifdef WARN_CLUT_CLIPPING
+ if (p->pp->pp->warnc) {
+ warning("Values clipped in setting A2B LUT!");
+ if (p->pp->pp->warnc == 2 && h->pcs == icSigLabData) {
+ a1logw(g_log,"*** Try switching to XYZ PCS ***\n");
+ }
+ }
+#endif /* WARN_CLUT_CLIPPING */
+
+ /* Init a CAM model in case it will be used (ie. in profile with camclip flag) */
+ if (vc != NULL) /* One has been provided */
+ p->vc = *vc; /* Copy the structure */
+ else
+ xicc_enum_viewcond(xicp, &p->vc, -1, NULL, 0, NULL); /* Use a default */
+ p->cam = new_icxcam(cam_default);
+ p->cam->set_view(p->cam, p->vc.Ev, p->vc.Wxyz, p->vc.La, p->vc.Yb, p->vc.Lv, p->vc.Yf,
+ p->vc.Fxyz, XICC_USE_HK);
+
+ if (flags & ICX_VERBOSE)
+ printf("Done A to B table creation\n");
+
+ return (icxLuBase *)p;
+}
+
+/* ========================================================== */
+/* Gamut boundary code. */
+/* ========================================================== */
+
+
+/* Context for creating gamut boundary points fro, xicc */
+typedef struct {
+ gamut *g; /* Gamut being created */
+ icxLuLut *x; /* xLut we are working from */
+ icxLuBase *flu; /* Forward xlookup */
+ double in[MAX_CHAN]; /* Device input values */
+} lutgamctx;
+
+/* Function to hand to zbrent to find a clut input' value at the ink limit */
+/* Returns value < 0.0 when within gamut, > 0.0 when out of gamut */
+static double icxLimitFind(void *fdata, double tp) {
+ int i;
+ double in[MAX_CHAN];
+ lutgamctx *p = (lutgamctx *)fdata;
+ double tt;
+
+ for (i = 0; i < p->x->inputChan; i++) {
+ in[i] = tp * p->in[i]; /* Scale given input value */
+ }
+
+ tt = icxLimitD(p->x, in);
+
+ return tt;
+}
+
+/* Function to pass to rspl to create gamut boundary from */
+/* forward xLut transform grid points. */
+static void
+lutfwdgam_func(
+ void *pp, /* lutgamctx structure */
+ double *out, /* output' value at clut grid point (ie. PCS' value) */
+ double *in /* input' value at clut grid point (ie. device' value) */
+) {
+ lutgamctx *p = (lutgamctx *)pp;
+ double pcso[3]; /* PCS output value */
+
+ /* Figure if we are over the ink limit. */
+ if ( (p->x->ink.tlimit >= 0.0 || p->x->ink.klimit >= 0.0)
+ && icxLimitD(p->x, in) > 0.0) {
+ int i;
+ double sf;
+
+ /* We are, so use the bracket search to discover a scale */
+ /* for the clut input' value that will put us on the ink limit. */
+
+ for (i = 0; i < p->x->inputChan; i++)
+ p->in[i] = in[i];
+
+ if (zbrent(&sf, 0.0, 1.0, 1e-4, icxLimitFind, pp) != 0) {
+ return; /* Give up */
+ }
+
+ /* Compute ink limit value */
+ for (i = 0; i < p->x->inputChan; i++)
+ p->in[i] = sf * in[i];
+
+ /* Compute the clut output for this clut input */
+ p->x->clut(p->x, pcso, p->in);
+ p->x->output(p->x, pcso, pcso);
+ p->x->out_abs(p->x, pcso, pcso);
+ } else { /* No ink limiting */
+ /* Convert the clut PCS' values to PCS output values */
+ p->x->output(p->x, pcso, out);
+ p->x->out_abs(p->x, pcso, pcso);
+ }
+
+ /* Expand the gamut surface with this point */
+ p->g->expand(p->g, pcso);
+
+ /* Leave out[] unchanged */
+}
+
+
+/* Function to pass to rspl to create gamut boundary from */
+/* backwards Lut transform. This is called for every node in the */
+/* B2A grid. */
+static void
+lutbwdgam_func(
+ void *pp, /* lutgamctx structure */
+ double *out, /* output value */
+ double *in /* input value */
+) {
+ lutgamctx *p = (lutgamctx *)pp;
+ double devo[MAX_CHAN]; /* Device output value */
+ double pcso[3]; /* PCS output value */
+
+ /* Convert the clut values to device output values */
+ p->x->output(p->x, devo, out); /* (Device never uses out_abs()) */
+
+ /* Convert from device values to PCS values */
+ p->flu->lookup(p->flu, pcso, devo);
+
+ /* Expand the gamut surface with this point */
+ p->g->expand(p->g, pcso);
+
+ /* Leave out[] unchanged */
+}
+
+/* Given an xicc lookup object, return a gamut object. */
+/* Note that the PCS must be Lab or Jab */
+/* An icxLuLut type must be icmFwd or icmBwd, */
+/* and for icmFwd, the ink limit (if supplied) will be applied. */
+/* Return NULL on error, check errc+err for reason */
+static gamut *icxLuLutGamut(
+icxLuBase *plu, /* this */
+double detail /* gamut detail level, 0.0 = def */
+) {
+ xicc *p = plu->pp; /* parent xicc */
+ icxLuLut *luluto = (icxLuLut *)plu; /* Lookup xLut type object */
+ icColorSpaceSignature ins, pcs, outs;
+ icmLookupFunc func;
+ icRenderingIntent intent;
+ double white[3], black[3], kblack[3];
+ int inn, outn;
+ gamut *gam;
+
+ /* get some details */
+ plu->spaces(plu, &ins, &inn, &outs, &outn, NULL, &intent, &func, &pcs);
+
+ if (func != icmFwd && func != icmBwd) {
+ p->errc = 1;
+ sprintf(p->err,"Creating Gamut surface for anything other than Device <-> PCS is not supported.");
+ return NULL;
+ }
+
+ if (pcs != icSigLabData && pcs != icxSigJabData) {
+ p->errc = 1;
+ sprintf(p->err,"Creating Gamut surface PCS of other than Lab or Jab is not supported.");
+ return NULL;
+ }
+
+ if (func == icmFwd) {
+ lutgamctx cx;
+
+ cx.g = gam = new_gamut(detail, pcs == icxSigJabData, 0);
+ cx.x = luluto;
+
+ /* Scan through grid. */
+ /* (Note this can give problems for a strange input space - ie. Lab */
+ /* and a low grid resolution - ie. 2) */
+ luluto->clutTable->scan_rspl(
+ luluto->clutTable, /* this */
+ RSPL_NOFLAGS, /* Combination of flags */
+ (void *)&cx, /* Opaque function context */
+ lutfwdgam_func /* Function to set from */
+ );
+
+ /* Make sure the white and point goes in too, if it isn't in the grid */
+ plu->efv_wh_bk_points(plu, white, NULL, NULL);
+ gam->expand(gam, white);
+
+ if (detail == 0.0)
+ detail = 10.0;
+
+ /* If the gamut is more than cursary, add some more detail surface points */
+ if (detail < 20.0 || luluto->clutTable->g.mres < 4) {
+ int res;
+ DCOUNT(co, MAX_CHAN, inn, 0, 0, 2);
+
+ res = (int)(500.0/detail); /* Establish an appropriate sampling density */
+ if (res < 10)
+ res = 10;
+
+ /* Itterate over all the faces in the device space */
+ DC_INIT(co);
+ while(!DC_DONE(co)) { /* Count through the corners of hyper cube */
+ int e, m1, m2;
+ double in[MAX_CHAN];
+ double out[3];
+
+ for (e = 0; e < inn; e++) { /* Base value */
+ in[e] = (double)co[e]; /* Base value */
+ in[e] = in[e] * (luluto->inmax[e] - luluto->inmin[e])
+ + luluto->inmin[e];
+ }
+
+ /* Figure if we are over the ink limit. */
+ if ((luluto->ink.tlimit >= 0.0 || luluto->ink.klimit >= 0.0)
+ && icxLimit(luluto, in) > 0.0) {
+ DC_INC(co);
+ continue; /* Skip points over limit */
+ }
+
+ /* Scan only device surface */
+ for (m1 = 0; m1 < inn; m1++) { /* Choose first coord to scan */
+ if (co[m1] != 0)
+ continue; /* Not at lower corner */
+ for (m2 = m1 + 1; m2 < inn; m2++) { /* Choose second coord to scan */
+ int x, y;
+
+ if (co[m2] != 0)
+ continue; /* Not at lower corner */
+
+ for (x = 0; x < res; x++) { /* step over surface */
+ in[m1] = x/(res - 1.0);
+ in[m1] = in[m1] * (luluto->inmax[m1] - luluto->inmin[m1])
+ + luluto->inmin[m1];
+ for (y = 0; y < res; y++) {
+ in[m2] = y/(res - 1.0);
+ in[m2] = in[m2] * (luluto->inmax[m2] - luluto->inmin[m2])
+ + luluto->inmin[m2];
+
+ /* Figure if we are over the ink limit. */
+ if ( (luluto->ink.tlimit >= 0.0 || luluto->ink.klimit >= 0.0)
+ && icxLimit(luluto, in) > 0.0) {
+ continue; /* Skip points over limit */
+ }
+
+ luluto->lookup((icxLuBase *)luluto, out, in);
+ gam->expand(gam, out);
+ }
+ }
+ }
+ }
+ /* Increment index within block */
+ DC_INC(co);
+ }
+ }
+
+ /* Now set the cusp points by itterating through colorant 0 & 100% combinations */
+ /* If we know what sort of space it is: */
+ if (ins == icSigRgbData || ins == icSigCmyData || ins == icSigCmykData) {
+ DCOUNT(co, 3, 3, 0, 0, 2);
+
+ gam->setcusps(gam, 0, NULL);
+ DC_INIT(co);
+ while(!DC_DONE(co)) {
+ int e;
+ double in[MAX_CHAN];
+ double out[3];
+
+ if (!(co[0] == 0 && co[1] == 0 && co[2] == 0)
+ && !(co[0] == 1 && co[1] == 1 && co[2] == 1)) { /* Skip white and black */
+ for (e = 0; e < 3; e++)
+ in[e] = (double)co[e];
+ in[e] = 0; /* K */
+
+ /* Always use the device->PCS conversion */
+ if (luluto->lookup((icxLuBase *)luluto, out, in) > 1)
+ error ("%d, %s",p->errc,p->err);
+ gam->setcusps(gam, 3, out);
+ }
+
+ DC_INC(co);
+ }
+ gam->setcusps(gam, 2, NULL);
+
+ /* Do all ink combinations and hope we can sort it out */
+ /* (This may not be smart, since bodgy cusp values will cause gamut mapping to fail...) */
+ } else if (ins != icSigXYZData
+ && ins != icSigLabData
+ && ins != icSigLuvData
+ && ins != icSigYxyData) {
+ DCOUNT(co, MAX_CHAN, inn, 0, 0, 2);
+
+ gam->setcusps(gam, 0, NULL);
+ DC_INIT(co);
+ while(!DC_DONE(co)) {
+ int e;
+ double in[MAX_CHAN];
+ double out[3];
+
+ for (e = 0; e < inn; e++) {
+ in[e] = (double)co[e];
+ in[e] = in[e] * (luluto->inmax[e] - luluto->inmin[e])
+ + luluto->inmin[e];
+ }
+
+ /* Figure if we are over the ink limit. */
+ if ((luluto->ink.tlimit >= 0.0 || luluto->ink.klimit >= 0.0)
+ && icxLimit(luluto, in) > 0.0) {
+ DC_INC(co);
+ continue; /* Skip points over limit */
+ }
+
+ luluto->lookup((icxLuBase *)luluto, out, in);
+ gam->setcusps(gam, 1, out);
+
+ DC_INC(co);
+ }
+ gam->setcusps(gam, 2, NULL);
+ }
+
+ } else { /* Must be icmBwd */
+ lutgamctx cx;
+
+ /* Get an appropriate device to PCS conversion for the fwd conversion */
+ /* we use after bwd conversion in lutbwdgam_func() */
+ switch (intent) {
+ /* If it is relative */
+ case icmDefaultIntent: /* Shouldn't happen */
+ case icPerceptual:
+ case icRelativeColorimetric:
+ case icSaturation:
+ intent = icRelativeColorimetric; /* Choose relative */
+ break;
+ /* If it is absolute */
+ case icAbsoluteColorimetric:
+ case icxAppearance:
+ case icxAbsAppearance:
+ break; /* Leave unchanged */
+ default:
+ break;
+ }
+ if ((cx.flu = p->get_luobj(p, ICX_CLIP_NEAREST , icmFwd, intent, pcs, icmLuOrdNorm,
+ &plu->vc, NULL)) == NULL) {
+ return NULL; /* oops */
+ }
+
+ cx.g = gam = new_gamut(detail, pcs == icxSigJabData, 0);
+
+ cx.x = luluto;
+
+ luluto->clutTable->scan_rspl(
+ luluto->clutTable, /* this */
+ RSPL_NOFLAGS, /* Combination of flags */
+ (void *)&cx, /* Opaque function context */
+ lutbwdgam_func /* Function to set from */
+ );
+
+ /* Now set the cusp points by using the fwd conversion and */
+ /* itterating through colorant 0 & 100% combinations. */
+ /* If we know what sort of space it is: */
+ if (outs == icSigRgbData || outs == icSigCmyData || outs == icSigCmykData) {
+ DCOUNT(co, 3, 3, 0, 0, 2);
+
+ gam->setcusps(gam, 0, NULL);
+ DC_INIT(co);
+ while(!DC_DONE(co)) {
+ int e;
+ double in[MAX_CHAN];
+ double out[3];
+
+ if (!(co[0] == 0 && co[1] == 0 && co[2] == 0)
+ && !(co[0] == 1 && co[1] == 1 && co[2] == 1)) { /* Skip white and black */
+ for (e = 0; e < 3; e++)
+ in[e] = (double)co[e];
+ in[e] = 0; /* K */
+
+ /* Always use the device->PCS conversion */
+ if (cx.flu->lookup((icxLuBase *)cx.flu, out, in) > 1)
+ error ("%d, %s",p->errc,p->err);
+ gam->setcusps(gam, 3, out);
+ }
+
+ DC_INC(co);
+ }
+ gam->setcusps(gam, 2, NULL);
+
+ /* Do all ink combinations and hope we can sort it out */
+ /* (This may not be smart, since bodgy cusp values will cause gamut mapping to fail...) */
+ } else if (ins != icSigXYZData
+ && ins != icSigLabData
+ && ins != icSigLuvData
+ && ins != icSigYxyData) {
+ DCOUNT(co, MAX_CHAN, inn, 0, 0, 2);
+
+ gam->setcusps(gam, 0, NULL);
+ DC_INIT(co);
+ while(!DC_DONE(co)) {
+ int e;
+ double in[MAX_CHAN];
+ double out[3];
+
+ for (e = 0; e < inn; e++) {
+ in[e] = (double)co[e];
+ in[e] = in[e] * (luluto->inmax[e] - luluto->inmin[e])
+ + luluto->inmin[e];
+ }
+
+ /* Figure if we are over the ink limit. */
+ if ((luluto->ink.tlimit >= 0.0 || luluto->ink.klimit >= 0.0)
+ && icxLimit(luluto, in) > 0.0) {
+ DC_INC(co);
+ continue; /* Skip points over limit */
+ }
+
+ cx.flu->lookup((icxLuBase *)cx.flu, out, in);
+ gam->setcusps(gam, 1, out);
+
+ DC_INC(co);
+ }
+ gam->setcusps(gam, 2, NULL);
+ }
+ cx.flu->del(cx.flu); /* Done with the fwd conversion */
+ }
+
+ /* Set the white and black points */
+ plu->efv_wh_bk_points(plu, white, black, kblack);
+ gam->setwb(gam, white, black, kblack);
+
+//printf("~1 icxLuLutGamut: set black %f %f %f and kblack %f %f %f\n", black[0], black[1], black[2], kblack[0], kblack[1], kblack[2]);
+
+#ifdef NEVER /* Not sure if this is a good idea ?? */
+ /* Since we know this is a profile, force the space and gamut points to be the same */
+ gam->getwb(gam, NULL, NULL, white, black, kblack); /* Get the actual gamut white and black points */
+ gam->setwb(gam, white, black, kblack); /* Put it back as colorspace one */
+#endif
+
+ return gam;
+}
+
+/* ----------------------------------------------- */
+#ifdef DEBUG
+#undef DEBUG /* Limit extent to this file */
+#endif
+
+
+
+
+
+
diff --git a/xicc/xlutfix.c b/xicc/xlutfix.c
new file mode 100644
index 0000000..6497688
--- /dev/null
+++ b/xicc/xlutfix.c
@@ -0,0 +1,1306 @@
+/*
+ * International Color Consortium color transform expanded support
+ * Set Lut table values and do auxiliary chanel interpolation continuity fixups.
+ *
+ * Author: Graeme W. Gill
+ * Date: 17/12/00
+ * Version: 1.00
+ *
+ * Copyright 2000 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.
+ *
+ */
+
+/*
+ * This module provides additional xicc functionality
+ * for CMYK lut based profiles.
+ *
+ * This is essentially a test of one approach to fixing
+ * auxiliary parameter induced interpolation errors.
+ */
+
+/*
+ * TTBD:
+ *
+ * Remove this code when the optimised separation code is working.
+ *
+ * Some of the error handling is crude. Shouldn't use
+ * error(), should return status.
+ *
+ */
+
+/* Description:
+
+ In all the clut based color systems, there are various
+ stages where the multi-dimenional profile functions are
+ resampled from one respresentation to another. As in all
+ sampling, aliasing may be an issue. The standard
+ methods for dealing with aliasing involve band limiting and
+ over-sampling. In dealing with color, anything other than
+ point sampling is often too slow to consider, meaning that
+ over sampling, or on-the-fly filtering is impractical.
+
+ Band limiting the function to be sampled is therefore the
+ most practical approach, but there are still sever tradoffs.
+ For accurately representing the sampled characteristics
+ of a device, a high resolution grid, with band limited
+ sample points is desirable. 3 or 4 dimension grids however,
+ quickly consume memory, and generaly show an exponential
+ decline in access and manipulation speed with grid resolution.
+ To maintain accuracy therefore, the minimum grid resolution,
+ and the minimum level of filtering is often employed.
+
+ The routines in this file are to deal with an aditional
+ subtlety when dealing with devices that have extra
+ degrees of freedom (ie. CMYK devices). In theory, the
+ aditional degrees of freedom can be set abitrarily, and
+ are often chosen to follow a "rule", designed to acheive
+ a goal such as minimising the amount of black used
+ in the highlights of bitonal devices (to minimise
+ "black dot" visibility), or to maximise black usage
+ for minimum ink costs, to resduce grey axis sensitivity
+ to the CMY values, to reduce the total ink loading,
+ or to pass through the inking values of a similar
+ input colorspace. In Argyll, these extra degrees of
+ freedom are refered to as auxiliary chanels.
+
+ Because the final representation of the color correction
+ transform is often a multi-dimensional interpolation lookup
+ table (clut), there is an aditional hidden requirement for
+ any auxiliary input chanels, and that is that there be
+ a reasonable degree of interpolation continuity between
+ the sampled grid points. If this continuity requirement
+ is not met, then the accuracy of the interpolation within
+ each grid cell can be wildly inacurate, even though the
+ accuracy of the grid points themselves is good.
+
+ For instance, if we have two grid points of a Lab->CMYK
+ interpolation grid:
+
+ 1) 50 0 0 -> .0 .0 .0 .3 -> 50 0 0
+ 2) 50 0 10 -> .2 .2 .4 .0 -> 50 0 10
+
+ Now if an input PCS value of 50 0 5 is used to
+ lookup the device values that should be used, a typical
+ interpolation might return:
+
+ 50 0 5 -> .1 .1 .2 .15 -> 40 -5 6
+
+ This is a small change in PCS space, but bevcause the
+ two device points are at opposite extremes of the possible
+ auxliary locus for each point, the device values are
+ far appart in device space. The accuracy of the
+ device space interpolation is therefore not guaranteed
+ to be accurate, and might in this case, mean that
+ the device actually reproduces an unexpectedly inaccurate PCS value.
+ Even worse, at the gamut boundaries the locus shrinks to zero,
+ and particularly in the dark end of the gamut, there
+ may be a multitude of different Device values that overlap
+ at the gamut boundary, causing abrupt or even chaotic
+ device values at spacings well above the sampling spacing
+ of the interpolation grid being created.
+
+ An additional challenge is that the locus of valid auxiliary
+ values may be discontinuous, (typically bifurcated), particularly
+ when an ink limit is imposed - the limit often removing a segment
+ of the auxiliary locus from the gamut. So ideally, a contiguous
+ auxiliary region needs to be mapped out, and any holes
+ patched over or removed from the gamut in a way that
+ doesn't introduce discontinuities.
+
+ In Argyll, we want to maintain the freedom to set arbitrary
+ auxiliary rules, yet we need to avoid the gross loss of
+ accuracy abrupt transitions in auxiliary values can cause.
+
+ The approach I've taken here involves a number of steps. The
+ first step sets up the clut in the usual maner, but records
+ various internal values for each point. In the second step, these
+ grid values are examined to locate cells which are "at risk" of
+ auxiliary interpolation errors. In the third step, the grid points
+ around the "at risk" cells have their auxiliary target values
+ adjusted to new target values, by using a simple smoothing filter
+ to reduce abrupt transitions. In the fourth step, new device values
+ are searched for, that have the same target PCS for the grid point,
+ but the smoothed auxiliary value. In cases where there is no scope
+ for meeting the new auxiliary target, because it is already at one
+ extreme of its possible locus for the target PCS, a tradoff is then
+ made between reduced target PCS accuracy, and an improved auxiliary
+ accuracy. In the final step, the new grid values replace the old
+ in the ICC.
+
+*/
+
+#include "icc.h"
+#include "numlib.h"
+#include "xicc.h"
+
+/* NOTE:- that we only implement support for CMYK output here !!! */
+
+#define CHECK_FUNCS /* Sanity check the callback functions */
+#define DO_STATS
+#undef SAVE_TRACE /* Save the values returned by the clut callback function */
+#undef USE_TRACE /* Use the trace file instead of the clut callback function */
+
+#define TRACENAME "D:/usr/argyll/xicc/xlutfix.xxx" /* So it will work in the debugger */
+
+#define MAX_PASSES 7
+#define MAX_FILTERS 20
+#define THRESH 0.55 /* Fix Threshold, ratio of mean to maximum PCS point */
+#define MINTHRESH 2.0 /* Set minimum interp error threshold. Don't fix if below this */
+#define AUXWHT 3.0 /* Auxiliary tradeoff weight and increment */
+#undef WIDEFILTER /* Alter 4x4 neighborhood */
+
+/* ========================================================== */
+
+/* Return maximum difference */
+static double maxdiffn(int n, double *in1, double *in2) {
+ double tt, rv = 0.0;
+ int i;
+ for (i = 0; i < n; i++) {
+ if ((tt = fabs(in1[i] - in2[i])) > rv)
+ rv = tt;
+ }
+ return rv;
+}
+
+/* Return absolute difference */
+static double absdiffn(int n, double *in1, double *in2) {
+ double tt, rv = 0.0;
+ int i;
+ for (i = 0; i < n; i++) {
+ tt = in1[i] - in2[i];
+ rv += tt * tt;
+ }
+ return sqrt(rv);
+}
+
+/* ========================================================== */
+/* Callback functions used by icc set_tables */
+/* ========================================================== */
+
+/* Context for set_tables callbacks */
+
+typedef struct {
+ int dofix;
+ void *cbctx;
+ void (*infunc)(void *cbctx, double *out, double *in);
+ void (*clutfunc)(void *cbctx, double *out, double *aux, double *auxr, double *pcs, double *in);
+ void (*clutpcsfunc)(void *cbctx, double *out, double *auxv, double *pcs);
+ void (*clutipcsfunc)(void *cbctx, double *pcs, double *olimit, double *auxv, double *in);
+ void (*outfunc)(void *cbctx, double *out, double *in);
+
+ float *g; /* Base of grid */
+ int res; /* Grid resolution */
+ int fn; /* Number of floats in grid */
+ int n; /* Number of entries in grid */
+ int fesz; /* Entry size in floats */
+ int fci[MXDI]; /* float increment for each input dimension into latice */
+ int cmin[MXDI]; /* Fixup area bounding box minimum */
+ int cmax[MXDI]; /* Fixup area bounding box maximum +1 */
+ /* One float for flags */
+ int din; /* Number of input (ie. grid) dimensions */
+ int daux; /* Number of auxiliary dimensions */
+ int dout; /* Number of output dimensions */
+ int oauxr; /* Offset to start of aux range entries */
+ int oauxv; /* Offset to start of aux value entries */
+ int oauxvv; /* Offset to start of aux new value entries */
+ int opcs; /* Offset to start of PCS value entries */
+ int oout; /* Offset to start of output value entries */
+ int nhi; /* Number of corners in an input grid cube */
+ int *fhi; /* nhi grid cube corner offsets in floats */
+
+ /* Minimiser info */
+ double m_auxw; /* Auxiliary error weighting factor (ie. 5 - 100) */
+ double m_auxv[MAX_CHAN];/* Auxiliary target value */
+ double m_pcs[3]; /* PCS target value */
+
+#if defined(SAVE_TRACE) || defined(USE_TRACE)
+ FILE *tf;
+#endif
+} xifs;
+
+/* Macros to access flag values */
+#define XLF_FLAGV(fp) (*((unsigned int *)(fp)))
+#define XLF_TOFIX 0x0001 /* Grid point to be fixed flag */
+#define XLF_UPDATE 0x0002 /* Grid point to be updated flag */
+#define XLF_HARDER 0x0004 /* Compromise PCS to improve result */
+
+/* Functions to pass to icc settables() to setup icc Lut */
+/* Input table. input -> input' space. */
+static void xif_set_input(void *cntx, double *out, double *in) {
+ xifs *p = (xifs *)cntx;
+
+ p->infunc(p->cbctx, out, in);
+}
+
+
+/* clut, input' -> output' space */
+static void xif_set_clut(void *cntx, double *out, double *in) {
+ xifs *p = (xifs *)cntx;
+
+ if (p->dofix == 0) { /* No fixups */
+ p->clutfunc(p->cbctx, out, NULL, NULL, NULL, in);
+
+ } else if (p->dofix == 1) { /* First pass */
+ int e, f;
+ float *fp, *ep;
+ double pcs[MAX_CHAN], auxv[MAX_CHAN], auxr[MAX_CHAN * 2];
+
+ /* the icclib set_tables() supplies us the grid indexes */
+ /* as integer in the double locations at in[-e-1] */
+
+#if defined(USE_TRACE)
+ if (fread(pcs, sizeof(double), 3, p->tf) != 3
+ || fread(auxr, sizeof(double), 2 * p->daux, p->tf) != (2 * p->daux)
+ || fread(auxv, sizeof(double), p->daux, p->tf) != p->daux
+ || fread(out, sizeof(double), p->dout, p->tf) != p->dout) {
+ fprintf(stderr,"mark_cells: read of trace failed\n");
+ exit(-1);
+ }
+#else /* !USE_TRACE */
+ p->clutfunc(p->cbctx, out, auxv, auxr, pcs, in);
+
+#if defined(SAVE_TRACE)
+ if (fwrite(pcs, sizeof(double), 3, p->tf) != 3
+ || fwrite(auxr, sizeof(double), 2 * p->daux, p->tf) != (2 * p->daux)
+ || fwrite(auxv, sizeof(double), p->daux, p->tf) != p->daux
+ || fwrite(out, sizeof(double), p->dout, p->tf) != p->dout) {
+ fprintf(stderr,"mark_cells: write of trace failed\n");
+ exit(-1);
+ }
+#endif /* SAVE_TRACE */
+#endif /* !USE_TRACE */
+
+ /* Figure grid pointer to grid entry */
+ for (fp = p->g, e = 0; e < p->din; e++)
+ fp += *((int *)&in[-e-1]) * p->fci[e];
+
+ XLF_FLAGV(fp) = 0; /* Clear flags */
+
+ ep = fp + p->opcs;
+ for (f = 0; f < 3; f++) /* Save PCS values */
+ ep[f] = (float)pcs[f];
+
+ ep = fp + p->oauxr;
+ for (f = 0; f < (2 * p->daux); f++) /* Save auxiliary range values */
+ ep[f] = (float)auxr[f];
+
+ ep = fp + p->oauxv;
+ for (f = 0; f < p->daux; f++) /* Save auxiliary values */
+ ep[f] = (float)auxv[f];
+
+ ep = fp + p->oout;
+ for (f = 0; f < p->dout; f++) /* Save the output values */
+ ep[f] = (float)out[f];
+
+ } else { /* Second pass */
+ int e, f;
+ float *fp, *ep;
+
+ /* Figure grid pointer to grid entry */
+ for (fp = p->g, e = 0; e < p->din; e++)
+ fp += *((int *)&in[-e-1]) * p->fci[e];
+
+ ep = fp + p->oout;
+ for (f = 0; f < p->dout; f++) /* Return the fixed output values */
+ out[f] = (double)ep[f];
+ }
+}
+
+/* output output' -> output space */
+static void xif_set_output(void *cntx, double *out, double *in) {
+ xifs *p = (xifs *)cntx;
+
+ p->outfunc(p->cbctx, out, in);
+}
+
+static int mark_cells(xifs *p);
+static int filter_grid(xifs *p, int tharder);
+static void fix_grid(xifs *p, double auxw);
+static int comp_pcs(xifs *p, double auxw, double *auxrv, double *auxv, double *pcs, double *dev);
+
+/* Helper function to setup the three tables contents, and the underlying icc. */
+/* Only useful if there are auxiliary device output chanels to be set, */
+/* as this takes care of auxiliary interpolation continuity fixups. */
+int icxLut_set_tables_auxfix(
+icmLut *p, /* Pointer to icmLut object */
+void *cbctx, /* Opaque callback context pointer value */
+icColorSpaceSignature insig, /* Input color space */
+icColorSpaceSignature outsig, /* Output color space */
+void (*infunc)(void *cbctx, double *out, double *in),
+ /* Input transfer function, inspace->inspace' (NULL = default) */
+double *inmin, double *inmax, /* Maximum range of inspace' values */
+ /* (NULL = default) */
+void (*clutfunc)(void *cbctx, double *out, double *aux, double *auxr, double *pcs, double *in),
+ /* inspace' -> outspace' transfer function, also */
+ /* return the target PCS and the (packed) auxiliary locus range, */
+ /* as [min0, max0, min1, max1...], the auxiliary chosen. */
+void (*clutpcsfunc)(void *cbctx, double *out, double *aux, double *pcs),
+ /* PCS + aux_target -> outspace' transfer function */
+void (*clutipcsfunc)(void *cbctx, double *pcs, double *olimit, double *auxv, double *in),
+ /* outspace' -> PCS + auxv check function */
+double *clutmin, double *clutmax, /* Maximum range of outspace' values */
+ /* (NULL = default) */
+void (*outfunc)(void *cbctx, double *out, double *in)
+ /* Output transfer function, outspace'->outspace (NULL = deflt) */
+) {
+ int rv, g, e, jj, kk;
+ double auxw; /* Auxiliary weight factor */
+ xifs xcs; /* Our context structure */
+
+ /* Simply pass this on to the icc set_table() */
+ xcs.dofix = 0; /* Assume we won't attempt fix */
+ xcs.cbctx = cbctx;
+ xcs.infunc = infunc;
+ xcs.clutfunc = clutfunc;
+ xcs.clutpcsfunc = clutpcsfunc;
+ xcs.clutipcsfunc = clutipcsfunc;
+ xcs.outfunc = outfunc;
+
+ if (outsig != icSigCmykData) { /* Don'y know how/if to fix this */
+ rv = p->set_tables(p,
+ ICM_CLUT_SET_APXLS,
+ (void *)&xcs,
+ insig, outsig,
+ xif_set_input,
+ inmin, inmax,
+ xif_set_clut,
+ clutmin, clutmax,
+ xif_set_output);
+
+ return rv;
+ }
+
+#ifdef CHECK_FUNCS
+ if (insig == icSigLabData) {
+ double in[3], out[MAX_CHAN];
+ double aux[1], auxr[2], pcs[3];
+ double out_check[MAX_CHAN];
+ double apcs[3], pcs_check[3];
+
+ /* Pick a sample input value */
+ in[0] = 50.0; in[1] = 0.0; in[2] = 0.0;
+
+ /* Test the in->out function */
+ clutfunc(cbctx, out, aux, auxr, pcs, in);
+
+printf("~1 %f %f %f -> pcs %f %f %f,\n auxr %f - %f, auxv %f, dev %f %f %f %f\n",
+ in[0], in[1], in[2], pcs[0], pcs[1], pcs[2], auxr[0], auxr[1], aux[0],
+ out[0], out[1], out[2], out[3]);
+
+ /* Check that we get the same result for the pcs function */
+ clutpcsfunc(cbctx, out_check, aux, pcs);
+
+ if (maxdiffn(p->outputChan, out, out_check) > 1e-6) {
+ fprintf(stderr,"set_tables_auxfix: pcsfunc check failed\n");
+printf("~1 is %f %f %f %f, should be %f %f %f %f\n",
+out_check[0], out_check[1], out_check[2], out_check[3],
+out[0], out[1], out[2], out[3]);
+ }
+printf("~1 PCS version gives %f %f %f %f\n",
+out_check[0], out_check[1], out_check[2], out_check[3]);
+
+ /* Checkout the reverse function */
+ clutipcsfunc(cbctx, apcs, NULL, NULL, out); /* Device -> clipped PCS */
+
+printf("~1 clipped PCS = %f %f %f\n", apcs[0], apcs[1], apcs[2]);
+ clutpcsfunc(cbctx, out_check, aux, apcs); /* clipped PCS -> Device */
+ clutipcsfunc(cbctx, pcs_check, NULL, NULL, out_check); /* Device -> PCS */
+printf("~1 check PCS = %f %f %f\n", pcs_check[0], pcs_check[1], pcs_check[2]);
+
+ if (maxdiffn(3, apcs, pcs_check) > 1e-5) {
+ fprintf(stderr,"set_tables_auxfix: ipcsfunc check failed\n");
+ printf("~1 is %f %f %f, should be %f %f %f\n",
+ pcs_check[0], pcs_check[1], pcs_check[2],
+ pcs[0], pcs[1], pcs[2]);
+ }
+
+ } else {
+ fprintf(stderr,"Sanity check of %s not implemented!\n",
+ icm2str(icmColorSpaceSignature,insig));
+ }
+#endif /* CHECK_FUNCS */
+
+ /* Allocate an array to hold all the results */
+ xcs.res = p->clutPoints;
+ xcs.din = p->inputChan;
+ xcs.dout = p->outputChan;
+ xcs.daux = xcs.dout - 3; /* Number of auxiliary values */
+ xcs.fesz = 1 + 3 + xcs.dout + 4 * xcs.daux; /* Entry size in floats */
+
+ /* Compute total number of entries, and offsets in each dimension */
+ xcs.n = xcs.res;
+ xcs.fci[0] = xcs.fesz;
+ for (e = 1; e < xcs.din; e++) {
+ xcs.n *= xcs.res;
+ xcs.fci[e] = xcs.fci[e-1] * xcs.res;
+ }
+ xcs.fn = xcs.n * xcs.fesz;
+
+printf("~1 fci = %d %d %d\n",
+xcs.fci[0], xcs.fci[1], xcs.fci[2]);
+
+ /* Setup offset list to grid cube corners */
+ xcs.nhi = 1 << xcs.din;
+ if ((xcs.fhi = (int *)malloc(sizeof(int) * xcs.nhi)) == NULL) {
+ sprintf(p->icp->err,"icxLut_set_tables: malloc() failed");
+ return p->icp->errc = 2;
+ }
+ for (g = 0; g < xcs.nhi; g++) {
+ xcs.fhi[g] = 0;
+ for (e = 0; e < xcs.din; e++) {
+ if (g & (1 << e))
+ xcs.fhi[g] += xcs.fci[e];
+ }
+
+ }
+printf("~1 nhi = %dd\n",xcs.nhi);
+
+ /* Offsets into each entry */
+ xcs.opcs = 1; /* Allow 1 flag float */
+ xcs.oout = xcs.opcs + 3; /* dpcs floats */
+ xcs.oauxr = xcs.oout + xcs.dout; /* dout floats */
+ xcs.oauxv = xcs.oauxr + xcs.daux * 2; /* 2 daux floats */
+ xcs.oauxvv = xcs.oauxv + xcs.daux; /* daux floats */
+ /* daux floats */
+
+printf("~1 res %d, entry size = %d floats, total floats needed = %d\n",xcs.res,xcs.fesz,xcs.fn);
+
+printf("~1 opcs = %d, oout = %d, oauxr = %d, oauxv = %d\n",
+ xcs.opcs, xcs.oout, xcs.oauxr, xcs.oauxv);
+
+ /* Allocate the grid */
+ if ((xcs.g = (float *)malloc(sizeof(float) * xcs.fn)) == NULL) {
+ sprintf(p->icp->err,"icxLut_set_tables: malloc() failed");
+ return p->icp->errc = 2;
+ }
+
+#if defined(SAVE_TRACE) || defined(USE_TRACE)
+ {
+ char *tname = TRACENAME;
+
+#if defined(SAVE_TRACE)
+ if ((xcs.tf = fopen(tname,"w")) == NULL) {
+#else
+ if ((xcs.tf = fopen(tname,"r")) == NULL) {
+#endif
+ fprintf(stderr,"mark_cells: Can't open file '%s'\n",tname);
+ exit(-1);
+ }
+#if defined(O_BINARY)
+#if defined(SAVE_TRACE)
+ xcs.tf = freopen(tname,"wb",xcs.tf);
+#else
+ xcs.tf = freopen(tname,"rb",xcs.tf);
+#endif
+#endif
+ }
+#endif /* SAVE_TRACE || USE_TRACE */
+
+#ifdef NEVER
+// ~9 check function
+{
+ int rv;
+ double auxv[1], rauxv[1];
+ double pcs[3], rpcs[3];
+ double dev[4];
+
+ auxv[0] = 0.5;
+ pcs[0] = 60.0;
+ pcs[1] = 0.0;
+ pcs[2] = 0.0;
+
+ dev[0] = 0.5;
+ dev[1] = 0.1;
+ dev[2] = 0.1;
+ dev[3] = 0.1;
+
+ rv = comp_pcs(&xcs, 20.0, NULL, auxv, pcs, dev);
+
+ printf("~9 comp_pcs returned %d, device %f %f %f %f\n",rv, dev[0], dev[1], dev[2], dev[3]);
+
+ xcs.clutipcsfunc(xcs.cbctx, rpcs, NULL, rauxv, dev);
+
+ printf("~9 comp_pcs pcs %f %f %f, aux %f\n", rpcs[0], rpcs[1], rpcs[2], rauxv[0]);
+
+ return 0;
+}
+#endif
+
+printf("~1 doing the first pass\n");
+ /* First pass */
+ xcs.dofix = 1;
+ rv = p->set_tables(p,
+ ICM_CLUT_SET_APXLS,
+ (void *)&xcs,
+ insig, outsig,
+ xif_set_input,
+ inmin, inmax,
+ xif_set_clut,
+ clutmin, clutmax,
+ xif_set_output);
+
+#if defined(SAVE_TRACE) || defined(USE_TRACE)
+ fclose(xcs.tf);
+#endif /* SAVE_TRACE || USE_TRACE */
+
+ if (rv != 0) {
+ free(xcs.fhi);
+ free(xcs.g);
+ return rv;
+ }
+
+printf("~1 doing the fixups\n");
+
+ /* Try three passes */
+ for(jj = 0, auxw = AUXWHT; jj < MAX_PASSES; jj++, auxw += AUXWHT) {
+ int lrv;
+
+ /* Figure out which cells need fixing */
+ rv = mark_cells(&xcs);
+printf("~1 cells that need fixing = %d\n", rv);
+
+ if (rv == 0)
+ break;
+
+ /* Filter the grid values that need fixing */
+printf("~1 about to filter grid points\n");
+ for (kk = 0, lrv = 0, rv = 1; kk < MAX_FILTERS && rv > 0 && rv != lrv; kk++) {
+ lrv = rv;
+ rv = filter_grid(&xcs, 1);
+ }
+
+ if (rv == 0)
+ break;
+
+ /* Lookup device values for grid points with changed auxiliary targets */
+printf("~1 about to fix grid points\n");
+ fix_grid(&xcs, auxw);
+ };
+
+rv = mark_cells(&xcs);
+printf("~1 faulty cells remaining = %d\n", rv);
+
+printf("~1 updatding the icc\n");
+ /* Second pass */
+ xcs.dofix = 2;
+ rv = p->set_tables(p,
+ ICM_CLUT_SET_APXLS,
+ (void *)&xcs,
+ insig, outsig,
+ xif_set_input,
+ inmin, inmax,
+ xif_set_clut,
+ clutmin, clutmax,
+ xif_set_output);
+
+ free(xcs.fhi);
+ free(xcs.g);
+
+printf("~1 done\n");
+
+ return rv;
+}
+
+
+
+
+/* ----------------------------------------- */
+/* Mark cells that need fixing */
+/* Return number of cells that need fixing */
+static int mark_cells(xifs *p) {
+ int e, f;
+ int coa[MAX_CHAN], ce; /* grid counter */
+ int tcount = 0;
+#ifdef DO_STATS
+ double aerr = 0.0;
+ double merr = 0.0;
+ double ccount = 0.0;
+#endif
+
+ /* Get ready to track fixup area bounding box */
+ for (e = 0; e < p->din; e++) {
+ p->cmin[e] = 99999;
+ p->cmax[e] = -1;
+ }
+
+ /* Init the grid counter */
+ for (ce = 0; ce < p->din; ce++)
+ coa[ce] = 0;
+ ce = 0;
+
+ /* Itterate throught the PCS clut grid cells */
+ while (ce < p->din) {
+ int j, m;
+ float *gp; /* Grid pointer */
+ float *ep, *fp; /* Temporary grid pointers */
+ double wpcsd; /* Worst case PCS distance */
+ double apcs[3]; /* Average PCS value */
+ double aout[MAX_CHAN]; /* Average output value */
+ double check[3]; /* Check PCS */
+ double ier; /* Interpolation error */
+ int markcell = 0; /* Mark the cell */
+
+ /* Compute base of cell pointer */
+ gp = p->g; /* Grid pointer */
+ for (e = 0; e < p->din; e++)
+ gp += coa[e] * p->fci[e];
+
+ /* - - - - - - - - - - - - - - - - - */
+ /* Full surrounding Cell calculation */
+
+ /* Init averaging accumulators */
+ for (j = 0; j < 3; j++)
+ apcs[j] = 0.0;
+ for (f = 0; f < p->dout; f++)
+ aout[f] = 0.0;
+
+ /* For each corner of the PCS grid based at the current point, */
+ /* average the PCS and Device values */
+ for (m = 0; m < p->nhi; m++) {
+ double pcs[3];
+ double dev[MAX_CHAN];
+
+ fp = gp + p->fhi[m];
+
+//ep = fp + p->opcs;
+//printf("Input PCS %f %f %f\n", ep[0], ep[1], ep[2]);
+
+ ep = fp + p->oout; /* base of device values */
+ for (f = 0; f < p->dout; f++) {
+ double v = (double)ep[f];
+ dev[f] = v;
+ aout[f] += v;
+ }
+
+ /* Device to clipped PCS */
+ p->clutipcsfunc(p->cbctx, pcs, NULL, NULL, dev);
+
+ for (j = 0; j < 3; j++)
+ apcs[j] += pcs[j];
+
+//printf("Corner PCS %f %f %f -> ", pcs[0], pcs[1], pcs[2]);
+//printf("%f %f %f %f\n", dev[0], dev[1], dev[2], dev[3]);
+ }
+
+ for (j = 0; j < 3; j++)
+ apcs[j] /= (double)p->nhi;
+
+ for (f = 0; f < p->dout; f++)
+ aout[f] /= (double)p->nhi;
+
+ /* Compute worst case distance of PCS corners to average PCS */
+ wpcsd = 0.0;
+ for (m = 0; m < p->nhi; m++) {
+ double ss;
+
+ fp = gp + p->fhi[m] + p->opcs;
+ for (ss = 0.0, j = 0; j < 3; j++) {
+ double tt = (double)fp[j] - apcs[j];
+ ss += tt * tt;
+ }
+ ss = sqrt(ss);
+ if (ss > wpcsd)
+ wpcsd = ss;
+ }
+ wpcsd *= THRESH; /* Set threshold as proportion of most distant corner */
+ if (wpcsd < MINTHRESH) /* Set a minimum threshold */
+ wpcsd = MINTHRESH;
+
+//printf("Average PCS %f %f %f, Average Device %f %f %f %f\n",
+//apcs[0], apcs[1], apcs[2], aout[0], aout[1], aout[2], aout[3]);
+
+ /* Average Device to PCS */
+ p->clutipcsfunc(p->cbctx, check, NULL, NULL, aout);
+
+//printf("Check PCS %f %f %f\n",
+//check[0], check[1], check[2]);
+
+ /* Compute error in PCS vs. Device interpolation */
+ ier = absdiffn(3, apcs, check);
+
+//printf("Average PCS %f %f %f, Check PCS %f %f %f, error %f\n",
+//apcs[0], apcs[1], apcs[2], check[0], check[1], check[2], ier);
+
+#ifdef DO_STATS
+ aerr += ier;
+ ccount++;
+ if (ier > merr)
+ merr = ier;
+#endif /* STATS */
+
+ if (ier > wpcsd) {
+ markcell = 1;
+printf("~1 ier = %f, wpcsd = %f, Dev = %f %f %f %f\n", ier, wpcsd, aout[0], aout[1], aout[2], aout[3]);
+ }
+
+ /* - - - - - - - - - - - - - */
+ /* Point pair calculations */
+
+ if (markcell == 0) { /* Don't bother testing if already marked */
+
+ /* Get the base point values */
+ ep = gp + p->oout; /* base of device values (assumes fhi[0] == 0) */
+
+ for (f = 0; f < p->dout; f++)
+ aout[f] = (double)ep[f];
+
+ p->clutipcsfunc(p->cbctx, apcs, NULL, NULL, aout);
+
+ /* For each other corner of the PCS grid based at the */
+ /* current point, compute the interpolation error */
+ for (m = 1; m < p->nhi; m++) {
+ double pcs[3]; /* Average PCS */
+ double dpcs[3]; /* PCS of averaged device */
+ double dev[MAX_CHAN];
+
+ fp = gp + p->fhi[m]; /* Other point point */
+ ep = fp + p->oout; /* base of device values */
+
+ for (f = 0; f < p->dout; f++)
+ dev[f] = (double)ep[f];
+
+ /* Device to clipped PCS */
+ p->clutipcsfunc(p->cbctx, pcs, NULL, NULL, dev);
+
+ for (j = 0; j < 3; j++)
+ pcs[j] = 0.5 * (pcs[j] + apcs[j]); /* PCS averaged value */
+
+ for (f = 0; f < p->dout; f++)
+ dev[f] = 0.5 * (aout[f] + dev[f]); /* Average device */
+
+ /* Average Device to PCS */
+ p->clutipcsfunc(p->cbctx, dpcs, NULL, NULL, dev);
+
+ wpcsd = THRESH * absdiffn(3, pcs, apcs); /* Threshold value */
+ if (wpcsd < MINTHRESH) /* Set a minimum threshold */
+ wpcsd = MINTHRESH;
+
+ /* Compute error in PCS vs. Device interpolation */
+ ier = absdiffn(3, pcs, dpcs);
+
+#ifdef DO_STATS
+ aerr += ier;
+ ccount++;
+ if (ier > merr)
+ merr = ier;
+#endif /* STATS */
+ if (ier > wpcsd) { /* Over threshold */
+ markcell = 1;
+printf("~1 ier = %f, wpcsd = %f, Dev = %f %f %f %f\n", ier, wpcsd, aout[0], aout[1], aout[2], aout[3]);
+ }
+ }
+ }
+
+ if (markcell) {
+
+#ifndef WIDEFILTER
+ /* Mark the whole cube around this base point */
+ tcount++;
+ /* Grid points that make up cell */
+ for (m = 0; m < p->nhi; m++) {
+ float *fp = gp + p->fhi[m];
+ XLF_FLAGV(fp) |= XLF_TOFIX;
+ }
+ for (e = 0; e < p->din; e++) {
+ if (coa[e] < p->cmin[e])
+ p->cmin[e] = coa[e];
+ if ((coa[e]+2) > p->cmax[e])
+ p->cmax[e] = coa[e] + 2;
+ }
+#else
+ int fo[MAX_CHAN], fe; /* region counter */
+
+ /* Mark the whole cube around this base point */
+ tcount++;
+ /* Grid points one row beyond cell */
+ for (fe = 0; fe < p->din; fe++)
+ fo[fe] = -1; /* Init the neighborhood counter */
+ fe = 0;
+
+ /* For each corner of the filter region */
+ while (fe < p->din) {
+ float *fp = gp;
+
+ for (e = 0; e < p->din; e++) {
+ int oo = fo[e] + coa[e];
+ if (oo < 0 || oo >= p->res)
+ break;
+ if (oo < p->cmin[e])
+ p->cmin[e] = oo;
+ if ((oo+1) > p->cmax[e])
+ p->cmax[e] = oo + 1;
+ fp += fo[e] * p->fci[e];
+ }
+
+ if (e >= p->din) { /* Within the grid */
+ XLF_FLAGV(fp) |= XLF_TOFIX;
+ }
+
+ /* Increment the counter */
+ for (fe = 0; fe < p->din; fe++) {
+ if (++fo[fe] < 3)
+ break; /* No carry */
+ fo[fe] = -1;
+ }
+ }
+#endif /* WIDEFILTER */
+ }
+
+ /* - - - - - - - - - - - - - - */
+
+
+ /* Increment the main grid counter */
+ for (ce = 0; ce < p->din; ce++) {
+ if (++coa[ce] < (p->res-1))
+ break; /* No carry */
+ coa[ce] = 0;
+ }
+ }
+
+#ifdef DO_STATS
+ aerr /= ccount;
+
+ printf("~1Average interpolation error %f, maximum %f\n",aerr, merr);
+ printf("~1Number outside corner radius = %f%%\n",(double)tcount * 100.0/ccount);
+ printf("~1Bounding box is %d - %d, %d - %d, %d - %d\n",
+ p->cmin[0], p->cmax[0], p->cmin[1], p->cmax[1], p->cmin[2], p->cmax[2]);
+#endif /* STATS */
+
+ return tcount;
+}
+
+
+/* ----------------------------------------- */
+/* Do one filter pass of grid aux values that need fixing */
+/* If tharder is set, don't clamp new aux targets, but signal trading PCS for aux. */
+/* Return the number of grid points that have a new aux target */
+static int filter_grid(xifs *p, int tharder) {
+ int e, f;
+ int coa[MAX_CHAN], ce; /* grid counter */
+ int tcount = 0;
+
+ /* Init the grid counter */
+ for (ce = 0; ce < p->din; ce++)
+ coa[ce] = p->cmin[ce];
+ ce = 0;
+
+ /* Itterate throught the PCS clut grid cells, */
+ /* computing new auxiliary values */
+ while (ce < p->din) {
+ float *gp, *fp; /* Grid pointer */
+ int fo[MAX_CHAN], fe; /* filter counter */
+ double faux[MAX_CHAN]; /* Filtered auxiliary value */
+ double nfv; /* Number of values in filter value */
+
+ /* Compute base of cell pointer */
+ gp = p->g; /* Grid pointer */
+ for (e = 0; e < p->din; e++)
+ gp += coa[e] * p->fci[e];
+
+ if ((XLF_FLAGV(gp) & XLF_TOFIX) != 0) {
+
+ for (f = 0; f < p->daux; f++)
+ faux[f] = 0.0;
+ nfv = 0.0;
+
+ /* Init the neighborhood counter */
+ for (fe = 0; fe < p->din; fe++)
+ fo[fe] = -1;
+ fe = 0;
+
+ /* For each corner of the filter region, */
+ /* compute a filter kernel value */
+ while (fe < p->din) {
+
+ fp = gp + p->oauxv;
+ for (e = 0; e < p->din; e++) {
+ int oo = coa[e] + fo[e];
+ if (oo < 0 || oo >= p->res)
+ break;
+ fp += fo[e] * p->fci[e];
+ }
+
+ if (e >= p->din) { /* Add this neighborhood value */
+ for (f = 0; f < p->daux; f++)
+ faux[f] += fp[f];
+ nfv++;
+ }
+
+ /* Increment the counter */
+ for (fe = 0; fe < p->din; fe++) {
+ if (++fo[fe] < 2)
+ break; /* No carry */
+ fo[fe] = -1;
+ }
+ }
+
+ /* Compute average value, and save it */
+ fp = gp + p->oauxvv;
+ for (f = 0; f < p->daux; f++)
+ fp[f] = (float)(faux[f] / nfv);
+
+ }
+
+ /* Increment the counter */
+ for (ce = 0; ce < p->din; ce++) {
+ if (++coa[ce] < p->cmax[ce])
+ break; /* No carry */
+ coa[ce] = p->cmin[ce];
+ }
+ }
+
+ /* Clip the new values to the valid range, and put them into place */
+
+ /* Init the grid counter */
+ for (ce = 0; ce < p->din; ce++)
+ coa[ce] = p->cmin[ce];
+ ce = 0;
+
+ /* Itterate throught the PCS clut grid cells, */
+ /* computing new auxiliary values */
+ while (ce < p->din) {
+ float *gp, *dp, *sp, *rp; /* Grid pointer */
+
+ /* Compute base of cell pointer */
+ gp = p->g; /* Grid pointer */
+ for (e = 0; e < p->din; e++)
+ gp += coa[e] * p->fci[e];
+
+ if ((XLF_FLAGV(gp) & XLF_TOFIX) != 0) {
+ int ud = 0; /* Update point flag */
+ int th = 0; /* Try harder flag */
+ sp = gp + p->oauxvv; /* Source */
+ dp = gp + p->oauxv; /* Destination */
+ rp = gp + p->oauxr; /* Range */
+ for (f = 0; f < p->daux; f++) {
+ double v, ov;
+ v = sp[f];
+ if (v < rp[2 * f]) { /* Limit new aux to valid locus range */
+ if (tharder)
+ th = 1;
+ else
+ v = rp[2 * f];
+ }
+ if (v > rp[2 * f + 1]) {
+ if (tharder)
+ th = 1;
+ else
+ v = rp[2 * f + 1];
+ }
+ ov = dp[f]; /* Old aux value */
+ if (fabs(ov - v) > 0.001) {
+ dp[f] = (float)v;
+ ud = 1; /* Worth updating it */
+ }
+ }
+
+ if (ud != 0) {
+ XLF_FLAGV(gp) |= XLF_UPDATE;
+ if (th != 0)
+ XLF_FLAGV(gp) |= XLF_HARDER;
+ }
+ if (XLF_FLAGV(gp) & XLF_UPDATE)
+ tcount++;
+ }
+
+ /* Increment the counter */
+ for (ce = 0; ce < p->din; ce++) {
+ if (++coa[ce] < p->cmax[ce])
+ break; /* No carry */
+ coa[ce] = p->cmin[ce];
+ }
+ }
+#ifdef DO_STATS
+ printf("~1 totol no. cells that will change = %d\n",tcount);
+#endif
+
+ return tcount;
+}
+
+/* ----------------------------------------- */
+/* Update the grid values given the new auxiliary targets. */
+/* Reset the TOFIX flags. */
+static void fix_grid(
+xifs *p,
+double auxw /* Compromise PCS factor */
+) {
+ int e, f;
+ int coa[MAX_CHAN], ce; /* grid counter */
+
+ /* Init the grid counter */
+ for (ce = 0; ce < p->din; ce++)
+ coa[ce] = p->cmin[ce];
+ ce = 0;
+
+ /* Itterate throught the PCS clut grid cells, */
+ /* computing new auxiliary values */
+ while (ce < p->din) {
+ float *gp, *ep; /* Grid pointer */
+
+ /* Compute base of cell pointer */
+ gp = p->g; /* Grid pointer */
+ for (e = 0; e < p->din; e++)
+ gp += coa[e] * p->fci[e];
+
+ if ((XLF_FLAGV(gp) & XLF_TOFIX) != 0) {
+ if ((XLF_FLAGV(gp) & XLF_UPDATE) != 0) {
+ double out[MAX_CHAN], auxv[MAX_CHAN], pcs[MAX_CHAN];
+ double auxrv[MAX_CHAN];
+
+ ep = gp + p->opcs;
+ for (f = 0; f < 3; f++) /* Get PCS values */
+ pcs[f] = (double)ep[f];
+
+ ep = gp + p->oauxv;
+ for (f = 0; f < p->daux; f++) /* Get auxiliary values */
+ auxv[f] = (double)ep[f];
+
+ ep = gp + p->oout;
+
+ if ((XLF_FLAGV(gp) & XLF_HARDER) != 0) {
+ /* Use "try harder" PCS->devicve lookup */
+
+ /* Set starting value */
+ for (f = 0; f < p->dout; f++)
+ out[f] = (double)ep[f];
+
+ if (comp_pcs(p, auxw, auxrv, auxv, pcs, out) == 0) {
+ for (f = 0; f < p->dout; f++) /* Save the new output values */
+ ep[f] = (float)out[f];
+ }
+#ifndef NEVER
+ else {
+ printf("~9 comp_pcs failed!\n");
+ }
+#endif
+
+ /* Save actual auxiliary values */
+ ep = gp + p->oauxv;
+ for (f = 0; f < p->daux; f++)
+ ep[f] = (float)auxrv[f];
+
+ } else {
+
+ /* Lookup output value with different auxiliary target */
+ p->clutpcsfunc(p->cbctx, out, auxv, pcs);
+
+ for (f = 0; f < p->dout; f++) /* Save the new output values */
+ ep[f] = (float)out[f];
+
+ /* assume auxiliary target will have been met */
+ }
+ }
+
+ XLF_FLAGV(gp) &= ~(XLF_TOFIX | XLF_UPDATE | XLF_HARDER);
+ }
+
+ /* Increment the counter */
+ for (ce = 0; ce < p->din; ce++) {
+ if (++coa[ce] < p->cmax[ce])
+ break; /* No carry */
+ coa[ce] = p->cmin[ce];
+ }
+ }
+}
+
+/* ----------------------------------------- */
+
+/* minimizer callback function */
+static double minfunc( /* Return function value */
+void *fdata, /* Opaque data pointer */
+double *tp /* Device input value */
+) {
+ xifs *p = (xifs *)fdata;
+ double pcs[3];
+ double auxv[MAX_CHAN];
+ double olimit;
+ double fval;
+ double tval;
+ int e, f;
+
+#define GWHT 1000.0
+
+ /* Check if the device input values are outside (assumed) device range 0.0 - 1.0 */
+ for (tval = 0.0, f = 0; f < p->dout; f++) {
+ if (tp[f] < 0.0) {
+ if (tp[0] > tval)
+ tval = tp[0];
+ tp[f] = 0.0;
+ } else if (tp[f] > 1.0) {
+ if ((tp[0] - 1.0) > tval)
+ tval = (tp[0] - 1.0);
+ tp[f] = 1.0;
+ }
+ }
+
+ /* Figure PCS, auxiliary error, and amount over ink limit */
+ p->clutipcsfunc(p->cbctx, pcs, &olimit, auxv, tp);
+
+ if (olimit > tval)
+ tval = olimit;
+
+ fval = GWHT * tval; /* Largest value that exceeds device/ink range */
+
+ /* Figure auxiliary error */
+ for (tval = 0.0, e = 0; e < p->daux; e++) {
+ double tt;
+ tt = auxv[e] - p->m_auxv[e];
+ tval += tt * tt;
+ }
+
+ fval += p->m_auxw * sqrt(tval);
+
+ /* Figure PCS error */
+ for (tval = 0.0, e = 0; e < 3; e++) {
+ double tt;
+ tt = pcs[e] - p->m_pcs[e];
+ tval += tt * tt;
+ }
+
+ fval += sqrt(tval);
+
+//printf("~9 minfunc returning error %f on %f %f %f %f\n", fval, tp[0], tp[1], tp[2], tp[3]);
+ return fval;
+}
+
+/* Given a PCS target, and auxiliary target, and a current */
+/* device value, return a device value that is a better */
+/* tradeoff between the PCS target and the auxiliary target. */
+/* return non-zero on error */
+static int comp_pcs(
+xifs *p, /* Aux fix structure */
+double auxw, /* Auxiliary error weighting factor (ie. 5 - 100) */
+double *auxrv, /* If not NULL, return actual auxiliary acheived */
+double *auxv, /* Auxiliary target value */
+double *pcs, /* PCS target value */
+double *dev /* Device starting value, return value */
+) {
+ int i;
+ double rv;
+ double ss[MAX_CHAN];
+ double check[3]; /* Check PCS */
+#ifdef NEVER /* Diagnostic info */
+double start[3]; /* Starting PCS */
+double auxst[1]; /* Starting aux */
+double auxch[1]; /* Auxiliary check value */
+p->clutipcsfunc(p->cbctx, start, NULL, auxst, dev);
+#endif
+
+ p->m_auxw = auxw;
+
+ for (i = 0; i < p->daux; i++)
+ p->m_auxv[i] = auxv[i];
+
+ for (i = 0; i < 3; i++)
+ p->m_pcs[i] = pcs[i];
+
+ /* Set initial search size */
+ for (i = 0; i < p->dout; i++)
+ ss[i] = 0.3;
+
+ if (powell(&rv, p->dout, dev, ss, 0.001, 1000, minfunc, p, NULL, NULL) != 0) {
+ return 1;
+ }
+
+ /* Sanitise device values */
+ for (i = 0; i < p->dout; i++) {
+ double v = dev[i];
+ if (v < 0.0)
+ v = 0.0;
+ else if (v > 1.0)
+ v = 1.0;
+ dev[i] = v;
+ }
+
+ if (auxrv != NULL) { /* Return actual auxiliary */
+ p->clutipcsfunc(p->cbctx, check, NULL, auxrv, dev);
+ }
+
+#ifdef NEVER /* Diagnostic info */
+p->clutipcsfunc(p->cbctx, check, NULL, auxch, dev);
+printf("~9 comp_pcs target aux %f PCS %f %f %f\n", auxv[0], pcs[0], pcs[1], pcs[2]);
+printf("~9 returning error %f on %f %f %f %f\n", rv, dev[0], dev[1], dev[2], dev[3]);
+printf("~9 PCS start = %f %f %f (%f)\n",start[0], start[1], start[2],
+ absdiffn(3, start, pcs));
+printf("~9 PCS finish = %f %f %f (%f)\n",check[0], check[1], check[2],
+ absdiffn(3, check, pcs));
+printf("~9 PCS delta = %f, aux delta = %f\n", absdiffn(3, start, check),
+ fabs(auxst[0] - auxch[0]));
+#endif /* NEVER */
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xmatrix.c b/xicc/xmatrix.c
new file mode 100644
index 0000000..a194314
--- /dev/null
+++ b/xicc/xmatrix.c
@@ -0,0 +1,2022 @@
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 2/7/00
+ * Version: 1.00
+ *
+ * Copyright 2000, 2003 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.
+ *
+ * Based on the old iccXfm class.
+ */
+
+/*
+ * This module provides the expands icclib functionality
+ * for matrix profiles.
+ * This file is #included in xicc.c, to keep its functions private.
+ */
+
+/*
+ * TTBD:
+ *
+ * Some of the error handling is crude. Shouldn't use
+ * error(), should return status.
+ *
+ * Should allow for offset in curves - this will greatly improve
+ * profile quality on non-calibrated displays. See spectro/dispcal.c
+ * spectro/moncurve.c. Use conjgrad() instead of powell() to speed things up.
+ * Note that if curves have scale, the scale will have to be
+ * normalized back to zero by scaling the matrix before storing
+ * the result in the ICC profile.
+ *
+ */
+
+#define USE_CIE94_DE /* Use CIE94 delta E measure when creating fit */
+
+/* Weights in shaper parameters, to minimise unconstrained "wiggles" */
+#define MXNORDERS 30 /* Maximum shaper harmonic orders to use */
+#define XSHAPE_MAG 1.0 /* Overall shaper parameter magnitide */
+
+#define XSHAPE_OFFG 0.1 /* Input offset weights when ord 0 is gamma */
+#define XSHAPE_OFFS 1.0 /* Input offset weights when ord 0 is shaper */
+#define XSHAPE_HW01 0.002 /* 0 & 1 harmonic weights */
+#define XSHAPE_HBREAK 4 /* Harmonic that has HWBR */
+#define XSHAPE_HWBR 0.8 /* Base weight of harmonics HBREAK up */
+#define XSHAPE_HWINC 0.5 /* Increase in weight for each harmonic above HWBR */
+
+#define XSHAPE_GAMTHR 0.01 /* Input threshold for linear slope below gamma power */
+
+#undef DEBUG /* Extra printfs */
+#undef DEBUG_PLOT /* Plot curves */
+
+/* ========================================================= */
+/* Forward and Backward Matrix type conversion */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* Individual components of Fwd conversion: */
+static int
+icxLuMatrixFwd_curve (
+icxLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ return ((icmLuMatrix *)p->plu)->fwd_curve((icmLuMatrix *)p->plu, out, in);
+}
+
+static int
+icxLuMatrixFwd_matrix (
+icxLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ return ((icmLuMatrix *)p->plu)->fwd_matrix((icmLuMatrix *)p->plu, out, in);
+}
+
+static int
+icxLuMatrixFwd_abs (
+icxLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ rv |= ((icmLuMatrix *)p->plu)->fwd_abs((icmLuMatrix *)p->plu, out, in);
+
+ if (p->pcs == icxSigJabData) {
+ p->cam->XYZ_to_cam(p->cam, out, out);
+ }
+ return rv;
+}
+
+
+/* Overall Fwd conversion */
+static int
+icxLuMatrixFwd_lookup (
+icxLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icxLuMatrix *p = (icxLuMatrix *)pp;
+ rv |= icxLuMatrixFwd_curve(p, out, in);
+ rv |= icxLuMatrixFwd_matrix(p, out, out);
+ rv |= icxLuMatrixFwd_abs(p, out, out);
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given a relative XYZ or Lab PCS value, convert in the fwd direction into */
+/* the nominated output PCS (ie. Absolute, Jab etc.) */
+/* (This is used in generating gamut compression in B2A tables) */
+void icxLuMatrix_fwd_relpcs_outpcs(
+icxLuBase *pp,
+icColorSpaceSignature is, /* Input space, XYZ or Lab */
+double *out, double *in) {
+ icxLuMatrix *p = (icxLuMatrix *)pp;
+
+ if (is == icSigLabData && p->natpcs == icSigXYZData) {
+ icmLab2XYZ(&icmD50, out, in);
+ icxLuMatrixFwd_abs(p, out, out);
+ } else if (is == icSigXYZData && p->natpcs == icSigLabData) {
+ icmXYZ2Lab(&icmD50, out, in);
+ icxLuMatrixFwd_abs(p, out, out);
+ } else {
+ icxLuMatrixFwd_abs(p, out, in);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Individual components of Bwd conversion: */
+
+static int
+icxLuMatrixBwd_abs (
+icxLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+
+ if (p->pcs == icxSigJabData) {
+ p->cam->cam_to_XYZ(p->cam, out, in);
+ /* Hack to prevent CAM02 weirdness being amplified by */
+ /* any later per channel clipping. */
+ /* Limit -Y to non-stupid values by scaling */
+ if (out[1] < -0.1) {
+ out[0] *= -0.1/out[1];
+ out[2] *= -0.1/out[1];
+ out[1] = -0.1;
+ }
+ rv |= ((icmLuMatrix *)p->plu)->bwd_abs((icmLuMatrix *)p->plu, out, out);
+ } else {
+ rv |= ((icmLuMatrix *)p->plu)->bwd_abs((icmLuMatrix *)p->plu, out, in);
+ }
+ return rv;
+}
+
+static int
+icxLuMatrixBwd_matrix (
+icxLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ return ((icmLuMatrix *)p->plu)->bwd_matrix((icmLuMatrix *)p->plu, out, in);
+}
+
+static int
+icxLuMatrixBwd_curve (
+icxLuMatrix *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ return ((icmLuMatrix *)p->plu)->bwd_curve((icmLuMatrix *)p->plu, out, in);
+}
+
+/* Overall Bwd conversion */
+static int
+icxLuMatrixBwd_lookup (
+icxLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icxLuMatrix *p = (icxLuMatrix *)pp;
+ rv |= icxLuMatrixBwd_abs(p, out, in);
+ rv |= icxLuMatrixBwd_matrix(p, out, out);
+ rv |= icxLuMatrixBwd_curve(p, out, out);
+ return rv;
+}
+
+static void
+icxLuMatrix_free(
+icxLuBase *p
+) {
+ p->plu->del(p->plu);
+ if (p->cam != NULL)
+ p->cam->del(p->cam);
+ free(p);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given a nominated output PCS (ie. Absolute, Jab etc.), convert it in the bwd */
+/* direction into a relative XYZ or Lab PCS value */
+/* (This is used in generating gamut compression in B2A tables) */
+void icxLuMatrix_bwd_outpcs_relpcs(
+icxLuBase *pp,
+icColorSpaceSignature os, /* Output space, XYZ or Lab */
+double *out, double *in) {
+ icxLuMatrix *p = (icxLuMatrix *)pp;
+
+ icxLuMatrixFwd_abs(p, out, in);
+ if (os == icSigXYZData && p->natpcs == icSigLabData) {
+ icmLab2XYZ(&icmD50, out, out);
+ } else if (os == icSigXYZData && p->natpcs == icSigLabData) {
+ icmXYZ2Lab(&icmD50, out, out);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static gamut *icxLuMatrixGamut(icxLuBase *plu, double detail);
+
+/* Do the basic icxLuMatrix creation and initialisation */
+static icxLuMatrix *
+alloc_icxLuMatrix(
+ xicc *xicp,
+ icmLuBase *plu, /* Pointer to Lu we are expanding (ours) */
+ int dir, /* 0 = fwd, 1 = bwd */
+ int flags /* clip, merge flags */
+) {
+ icxLuMatrix *p;
+
+ if ((p = (icxLuMatrix *) calloc(1,sizeof(icxLuMatrix))) == NULL)
+ return NULL;
+
+ p->pp = xicp;
+ p->plu = plu;
+ p->del = icxLuMatrix_free;
+ p->lutspaces = icxLutSpaces;
+ p->spaces = icxLuSpaces;
+ p->get_native_ranges = icxLu_get_native_ranges;
+ p->get_ranges = icxLu_get_ranges;
+ p->efv_wh_bk_points = icxLuEfv_wh_bk_points;
+ p->get_gamut = icxLuMatrixGamut;
+ p->fwd_relpcs_outpcs = icxLuMatrix_fwd_relpcs_outpcs;
+ p->bwd_outpcs_relpcs = icxLuMatrix_bwd_outpcs_relpcs;
+
+ p->nearclip = 0; /* Set flag defaults */
+ p->mergeclut = 0;
+ p->noisluts = 0;
+ p->noipluts = 0;
+ p->nooluts = 0;
+
+ p->intsep = 0;
+
+ p->fwd_lookup = icxLuMatrixFwd_lookup;
+ p->fwd_curve = icxLuMatrixFwd_curve;
+ p->fwd_matrix = icxLuMatrixFwd_matrix;
+ p->fwd_abs = icxLuMatrixFwd_abs;
+ p->bwd_lookup = icxLuMatrixBwd_lookup;
+ p->bwd_abs = icxLuMatrixBwd_abs;
+ p->bwd_matrix = icxLuMatrixBwd_matrix;
+ p->bwd_curve = icxLuMatrixBwd_curve;
+
+ if (dir) { /* Bwd */
+ p->lookup = icxLuMatrixBwd_lookup;
+ p->inv_lookup = icxLuMatrixFwd_lookup;
+ } else {
+ p->lookup = icxLuMatrixFwd_lookup;
+ p->inv_lookup = icxLuMatrixBwd_lookup;
+ }
+
+ /* There are no matrix specific flags */
+ p->flags = flags;
+
+ /* Get details of internal, native color space */
+ p->plu->lutspaces(p->plu, &p->natis, NULL, &p->natos, NULL, &p->natpcs);
+
+ /* Get other details of conversion */
+ p->plu->spaces(p->plu, NULL, &p->inputChan, NULL, &p->outputChan, NULL, NULL, NULL, NULL, NULL);
+
+ return p;
+}
+
+/* We setup valid fwd and bwd component conversions, */
+/* but setup only the asked for overal conversion. */
+static icxLuBase *
+new_icxLuMatrix(
+xicc *xicp,
+int flags, /* clip, merge flags */
+icmLuBase *plu, /* Pointer to Lu we are expanding */
+icmLookupFunc func, /* Functionality requested */
+icRenderingIntent intent, /* Rendering intent */
+icColorSpaceSignature pcsor, /* PCS override (0 = def) */
+icxViewCond *vc, /* Viewing Condition (NULL if pcsor is not CIECAM) */
+int dir /* 0 = fwd, 1 = bwd */
+) {
+ icxLuMatrix *p;
+
+ /* Do basic creation and initialisation */
+ if ((p = alloc_icxLuMatrix(xicp, plu, dir, flags)) == NULL)
+ return NULL;
+
+ p->func = func;
+
+ /* Init the CAM model */
+ if (pcsor == icxSigJabData) {
+ if (vc != NULL) /* One has been provided */
+ p->vc = *vc; /* Copy the structure */
+ else
+ xicc_enum_viewcond(xicp, &p->vc, -1, NULL, 0, NULL); /* Use a default */
+ p->cam = new_icxcam(cam_default);
+ p->cam->set_view(p->cam, p->vc.Ev, p->vc.Wxyz, p->vc.La, p->vc.Yb, p->vc.Lv, p->vc.Yf,
+ p->vc.Fxyz, XICC_USE_HK);
+ } else {
+ p->cam = NULL;
+ }
+
+ /* Remember the effective intent */
+ p->intent = intent;
+
+ /* Get the effective spaces */
+ plu->spaces(plu, &p->ins, NULL, &p->outs, NULL, NULL, NULL, NULL, &p->pcs, NULL);
+
+ /* Override with pcsor */
+ if (pcsor == icxSigJabData) {
+ p->pcs = pcsor;
+ if (func == icmBwd || func == icmGamut || func == icmPreview)
+ p->ins = pcsor;
+ if (func == icmFwd || func == icmPreview)
+ p->outs = pcsor;
+ }
+
+ /* In general the native and effective ranges of the icx will be the same as the */
+ /* underlying icm lookup object. */
+ p->plu->get_lutranges(p->plu, p->ninmin, p->ninmax, p->noutmin, p->noutmax);
+ p->plu->get_ranges(p->plu, p->inmin, p->inmax, p->outmin, p->outmax);
+
+ /* If we have a Jab PCS override, reflect this in the effective icx range. */
+ /* Note that the ab ranges are nominal. They will exceed this range */
+ /* for colors representable in L*a*b* PCS */
+ if (p->ins == icxSigJabData) {
+ p->inmin[0] = 0.0; p->inmax[0] = 100.0;
+ p->inmin[1] = -128.0; p->inmax[1] = 128.0;
+ p->inmin[2] = -128.0; p->inmax[2] = 128.0;
+ } else if (p->outs == icxSigJabData) {
+ p->outmin[0] = 0.0; p->outmax[0] = 100.0;
+ p->outmin[1] = -128.0; p->outmax[1] = 128.0;
+ p->outmin[2] = -128.0; p->outmax[2] = 128.0;
+ }
+
+ return (icxLuBase *)p;
+}
+
+/* ========================================================== */
+/* xicc creation code */
+/* ========================================================== */
+
+/* Context for figuring input curves */
+typedef struct {
+ rspl *r; /* Device -> PCS rspl */
+ int linear; /* Flag */
+ double nmin, nmax; /* PCS End points to linearise */
+ double min, max; /* device End points to linearise */
+} mxinctx;
+
+#define NPARMS (9 + 6 + 3 * MXNORDERS)
+
+/* Context for optimising matrix */
+typedef struct {
+ int verb; /* Verbose */
+ int optdim; /* Optimisation dimensions */
+ int isLinear; /* NZ if no curves, fixed Gamma = 1.0 */
+ int isGamma; /* NZ if gamma + matrix, else shaper */
+ int isShTRC; /* NZ if shared TRC */
+ int shape0gam; /* NZ if zero'th order shaper should be gamma function */
+ int norders; /* Number of shaper orders */
+ int clipbw; /* Prevent white > 1 and -ve black */
+ int clipprims; /* Prevent primaries going -ve */
+ double smooth; /* Shaper smoothing factor (nominal = 1.0) */
+ double dscale; /* Scale device values */
+ double v[NPARMS]; /* Holder for parameters */
+ double sa[NPARMS]; /* Initial search area */
+ /* Rest are matrix : */
+ /* 0 1 2 R X */
+ /* 3 4 5 * G = Y */
+ /* 6 7 8 B Z */
+ /* For Gamma: */
+ /* 9, 10, 11 are gamma */
+ /* Else for shaper only: */
+ /* 9, 10, 11 are Input Offset */
+ /* 12, 13, 14 are Output Offset */
+ /* 15, 16, 17 are Gamma or 0th harmonics */
+ /* 18, 19, 20 are 1st harmonics */
+ /* 21, 22, 23 are 2nd harmonics */
+ /* 24, 25, 26 etc. */
+ /* For isShTRC there is only one set of offsets & harmonics */
+ icmXYZNumber wp; /* Assumed white point for Lab conversion */
+ cow *points; /* List of test points as dev->Lab */
+ int nodp; /* Number of data points */
+} mxopt;
+
+/* Per chanel function being optimised */
+static void mxmfunc1(mxopt *p, int j, double *v, double *out, double *in) {
+ double vv, g;
+ int ps = 3; /* Parameter spacing */
+
+ vv = *in * p->dscale;
+
+ if (p->isShTRC) {
+ j = 0;
+ ps = 1; /* Only one channel */
+ }
+
+ if (p->isLinear) { /* No per channel curve */
+ *out = vv;
+ return;
+ }
+
+ if (p->isGamma) { /* Pure Gamma */
+ /* Apply gamma */
+ g = v[9 + j];
+ if (g <= 0.0)
+ vv = 1.0;
+ else {
+ if (vv >= 0.0) {
+ vv = pow(vv, g);
+ } else {
+ vv = -pow(-vv, g);
+ }
+ }
+ } else { /* Add extra shaper parameters */
+ int ord;
+
+ if (p->shape0gam) {
+
+ /* Apply input offset */
+ g = v[9 + j]; /* Offset value */
+
+ if (g >= 1.0) {
+ vv = 1.0;
+ } else {
+ vv = g + ((1.0 - g) * vv);
+ }
+
+ /* Apply gamma as order 0 */
+ g = v[9 + 2 * ps + j];
+ if (g <= 0.0)
+ vv = 1.0;
+ else {
+ /* Power with straight line at small values */
+ if (vv >= XSHAPE_GAMTHR) {
+ vv = pow(vv, g);
+ } else {
+ double slope, oth;
+
+ oth = pow(XSHAPE_GAMTHR, g); /* Output at input threshold */
+ slope = g * pow(XSHAPE_GAMTHR, g - 1.0); /* Slope at input threshold */
+ vv = oth + (vv - XSHAPE_GAMTHR) * slope; /* Straight line */
+ }
+ }
+ }
+
+ /* Process all the shaper orders from high to low. */
+ /* [These shapers were inspired by a Graphics Gem idea */
+ /* (Gems IV, VI.3, "Fast Alternatives to Perlin's Bias and */
+ /* Gain Functions, pp 401). */
+ /* They have the nice properties that they are smooth, and */
+ /* can't be non-monotonic. The control parameter has been */
+ /* altered to have a range from -oo to +oo rather than 0.0 to 1.0 */
+ /* so that the search space is less non-linear. ] */
+ if (p->shape0gam)
+ ord = 1;
+ else
+ ord = 0;
+ for (; ord < p->norders; ord++)
+ {
+ int nsec; /* Number of sections */
+ double sec; /* Section */
+ g = v[9 + 2 * ps + ord * ps + j]; /* Parameter */
+
+ nsec = ord + 1; /* Increase sections for each order */
+
+ vv *= (double)nsec;
+
+ sec = floor(vv);
+ if (((int)sec) & 1)
+ g = -g; /* Alternate action in each section */
+ vv -= sec;
+ if (g >= 0.0) {
+ vv = vv/(g - g * vv + 1.0);
+ } else {
+ vv = (vv - g * vv)/(1.0 - g * vv);
+ }
+ vv += sec;
+ vv /= (double)nsec;
+ }
+
+ /* (For extrapolation it helps to pin 0 & 1) */
+ if (p->shape0gam) {
+ /* Apply output offset */
+ g = v[9 + 1 * ps + j]; /* Offset value */
+
+ if (g >= 1.0) {
+ vv = 1.0;
+ } else if (g > 0.0) {
+ vv = g + ((1.0 - g) * vv);
+ }
+ }
+ }
+
+ *out = vv;
+}
+
+/* Function being optimised */
+static void mxmfunc(mxopt *p, double *v, double *xyz, double *in) {
+ int j;
+ double rgb[3];
+
+ /* Apply per channel processing */
+ for (j = 0; j < 3; j++)
+ mxmfunc1(p, j, v, &rgb[j], &in[j]);
+
+ /* Apply matrix */
+ xyz[0] = v[0] * rgb[0] + v[1] * rgb[1] + v[2] * rgb[2];
+ xyz[1] = v[3] * rgb[0] + v[4] * rgb[1] + v[5] * rgb[2];
+ xyz[2] = v[6] * rgb[0] + v[7] * rgb[1] + v[8] * rgb[2];
+
+}
+
+/* return the sum of the squares of the current shaper parameters */
+static double xshapmag(
+mxopt *p, /* Base of optimisation structure */
+double *v /* Pointer to parameters */
+) {
+ double tt, w, tparam = 0.0;
+ int f, g;
+
+ if (p->isGamma) { /* Pure Gamma only */
+ return 0.0;
+ }
+
+ if (p->isShTRC) {
+ /* Input offset value */
+ if (p->shape0gam)
+ w = XSHAPE_OFFG;
+ else
+ w = XSHAPE_OFFS;
+
+ tt = v[9];
+ tt *= tt;
+ tparam += w * tt;
+
+ /* Output offset value */
+ tt = v[10];
+ tt *= tt;
+ tparam += w * tt;
+
+ /* Shaper values */
+ for (f = 0; f < p->norders; f++) {
+ tt = v[11 + f];
+ if (f == 0 && p->shape0gam)
+ tt -= 1.0; /* default is linear */
+ tt *= tt;
+ /* Weigh to suppress ripples */
+ if (f <= 1) { /* Use XSHAPE_HW01 */
+ w = XSHAPE_HW01;
+ } else if (f <= XSHAPE_HBREAK) { /* Blend from XSHAPE_HW01 to XSHAPE_HWBR * smooth */
+ double bl = (f - 1.0)/(XSHAPE_HBREAK - 1.0);
+ w = (1.0 - bl) * XSHAPE_HW01 + bl * XSHAPE_HWBR * p->smooth;
+ } else { /* Use XSHAPE_HWBR * smooth */
+ w = XSHAPE_HWBR + (f-XSHAPE_HBREAK) * XSHAPE_HWINC;
+ w *= p->smooth;
+ }
+ tparam += w * tt;
+ }
+ return XSHAPE_MAG * tparam;
+ }
+
+ /* Input ffset value */
+ if (p->shape0gam)
+ w = XSHAPE_OFFG;
+ else
+ w = XSHAPE_OFFS;
+
+ for (g = 0; g < 3; g++) {
+ tt = v[9 + g];
+ tt *= tt;
+ tparam += w * tt;
+ }
+ /* Output ffset value */
+ for (g = 0; g < 3; g++) {
+ tt = v[12 + g];
+ tt *= tt;
+ tparam += w * tt;
+ }
+ /* Shaper values */
+ for (f = 0; f < p->norders; f++) {
+ /* Weigh to suppress ripples */
+ if (f <= 1) {
+ w = XSHAPE_HW01;
+ } else if (f <= XSHAPE_HBREAK) {
+ double bl = (f - 1.0)/(XSHAPE_HBREAK - 1.0);
+ w = (1.0 - bl) * XSHAPE_HW01 + bl * XSHAPE_HWBR * p->smooth;
+ } else {
+ w = XSHAPE_HWBR + (f-XSHAPE_HBREAK) * XSHAPE_HWINC * p->smooth;
+ w *= p->smooth;
+ }
+ for (g = 0; g < 3; g++) {
+ tt = v[15 + 3 * f + g];
+ if (f == 0 && p->shape0gam)
+ tt -= 1.0; /* default is linear */
+ tt *= tt;
+ tparam += w * tt;
+ }
+ }
+ return XSHAPE_MAG * tparam/3.0;
+}
+
+/* Matrix optimisation function handed to powell() */
+static double mxoptfunc(void *edata, double *v) {
+ mxopt *p = (mxopt *)edata;
+ double err = 0.0, rv = 0.0, smv;
+ double xyz[3], lab[3];
+ int i;
+
+ for (i = 0; i < p->nodp; i++) {
+
+ /* Apply our function */
+//printf("%f %f %f -> %f %f %f\n", p->points[i].p[0], p->points[i].p[1], p->points[i].p[2], xyz[0], xyz[1], xyz[2]);
+ mxmfunc(p, v, xyz, p->points[i].p);
+
+ /* Convert to Lab */
+ icmXYZ2Lab(&p->wp, lab, xyz);
+//printf("%f %f %f -> %f %f %f, target %f %f %f\n", p->points[i].p[0], p->points[i].p[1], p->points[i].p[2], lab[0], lab[1], lab[2], p->points[i].v[0], p->points[i].v[1], p->points[i].v[2]);
+
+ /* Accumulate total delta E squared */
+#ifdef USE_CIE94_DE
+ rv += p->points[i].w * icmCIE94sq(lab, p->points[i].v);
+#else
+ rv += p->points[i].w * icmLabDEsq(lab, p->points[i].v);
+#endif
+ }
+
+ /* Normalise error to be an average delta E squared */
+ rv /= (double)p->nodp;
+
+ /* Sum with shaper parameters squared, to */
+ /* minimise unsconstrained "wiggles" */
+ smv = xshapmag(p, v);
+ rv += smv;
+
+ /* Penalize if we have white > 1 or -ve black */
+ if (p->clipbw) {
+ double tp[3];
+
+ tp[0] = tp[1] = tp[2] = 1.0;
+ mxmfunc(p, v, xyz, tp);
+ if ((xyz[1] - 1.0) > err)
+ err = xyz[1] - 1.0;
+
+ tp[0] = tp[1] = tp[2] = 0.0;
+ mxmfunc(p, v, xyz, tp);
+ for (i = 0; i < 3; i++) {
+ if (-xyz[i] > err)
+ err = -v[i];
+ }
+ }
+
+ /* Penalize if we have -ve primaries */
+ if (p->clipprims) {
+ for (i = 0; i < 9; i++) {
+ if (-v[i] > err)
+ err = -v[i];
+ }
+ }
+ rv += err * 1000.0;
+
+#ifdef DEBUG
+printf("~9(%f)mxoptfunc returning %f\n",smv,rv);
+#endif
+
+ return rv;
+}
+
+/* Matrix progress function handed to powell() */
+static void mxprogfunc(void *pdata, int perc) {
+ mxopt *p = (mxopt *)pdata;
+
+ if (p->verb) {
+ printf("%c% 3d%%",cr_char,perc);
+ if (perc == 100)
+ printf("\n");
+ fflush(stdout);
+ }
+}
+
+
+/* Given a correction matrix, transform the matrix values */
+static void mxtransform(mxopt *os, double mat[3][3]) {
+ double vec[3];
+
+ vec[0] = os->v[0]; vec[1] = os->v[3]; vec[2] = os->v[6];
+ icmMulBy3x3(vec, mat, vec);
+ os->v[0] = vec[0]; os->v[3] = vec[1]; os->v[6] = vec[2];
+
+ vec[0] = os->v[1]; vec[1] = os->v[4]; vec[2] = os->v[7];
+ icmMulBy3x3(vec, mat, vec);
+ os->v[1] = vec[0]; os->v[4] = vec[1]; os->v[7] = vec[2];
+
+ vec[0] = os->v[2]; vec[1] = os->v[5]; vec[2] = os->v[8];
+ icmMulBy3x3(vec, mat, vec);
+ os->v[2] = vec[0]; os->v[5] = vec[1]; os->v[8] = vec[2];
+}
+
+
+/* Setup and then return the optimized matrix fit in the mxopt structure. */
+/* Return 0 on sucess, error code on failure. */
+static int
+createMatrix(
+char *err, /* Return error message */
+mxopt *os, /* Optimisation information */
+int verb, /* NZ if verbose */
+int nodp, /* Number of points */
+cow *ipoints, /* Array of input points in XYZ space */
+int isLab, /* nz if data points are Lab */
+int quality, /* Quality metric, 0..3 (-1 == 2 orders only) */
+int isLinear, /* NZ if pure linear, gamma = 1.0 */
+int isGamma, /* NZ if gamma rather than shaper */
+int isShTRC, /* NZ if shared TRCs */
+int shape0gam, /* NZ if zero'th order shaper should be gamma function */
+int clipbw, /* Prevent white > 1 and -ve black */
+int clipprims, /* Prevent primaries going -ve */
+double smooth, /* Smoothing factor (nominal 1.0) */
+double scale /* Scale device values */
+) {
+ double nweight = 1.0; /* Amount to weight neutral patches (make a parameter ?) */
+ int inputChan = 3; /* Must be RGB like */
+ int outputChan = 3; /* Must be the PCS */
+ int rsplflags = 0; /* Flags for scattered data rspl */
+ int e, f, i, j;
+ int maxits = 200; /* Optimisation stop params */
+ double stopon = 0.01; /* Absolute delta E change to stop on */
+ cow *points; /* Lab copy of ipoints */
+ double rerr;
+
+#ifdef DEBUG_PLOT
+ #define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+#endif /* DEBUG_PLOT */
+
+ if (verb)
+ rsplflags |= RSPL_VERBOSE;
+
+ /* Allocate the array passed to fit_rspl() */
+ if ((points = (cow *)malloc(sizeof(cow) * nodp)) == NULL) {
+ if (err != NULL)
+ sprintf(err,"Allocation of scattered coordinate array failed");
+ return 2;
+ }
+
+ /* Setup for optimising run */
+ if (verb != 0)
+ os->verb = verb;
+ else
+ os->verb = 0;
+ os->points = points;
+ os->nodp = nodp;
+ os->isShTRC = 0;
+ os->shape0gam = shape0gam;
+ os->smooth = smooth;
+ os->clipbw = clipbw;
+ os->clipprims = clipprims;
+ os->dscale = scale;
+
+ /* Set quality/effort factors */
+ if (quality >= 3) { /* Ultra high */
+ os->norders = 20;
+ maxits = 10000;
+ stopon = 5e-7;
+ } else if (quality == 2) { /* High */
+ os->norders = 12;
+ maxits = 5000;
+ stopon = 5e-6;
+ } else if (quality == 1) { /* Medium */
+ os->norders = 8;
+ maxits = 2000;
+ stopon = 5e-5;
+ } else if (quality == 0) { /* Low */
+ os->norders = 4;
+ maxits = 1000;
+ stopon = 5e-4;
+ } else { /* Ultra Low */
+ os->norders = 2;
+ maxits = 1000;
+ stopon = 5e-4;
+ }
+ if (os->norders > MXNORDERS)
+ os->norders = MXNORDERS;
+
+ /* Setup points ready for optimisation and do an initial Lab conversion */
+ for (i = 0; i < nodp; i++) {
+ for (e = 0; e < inputChan; e++)
+ points[i].p[e] = ipoints[i].p[e];
+
+ for (f = 0; f < outputChan; f++)
+ points[i].v[f] = ipoints[i].v[f];
+
+ points[i].w = ipoints[i].w;
+ }
+
+ /* Pick a white point for the real Lab conversion */
+ {
+ double wp[3];
+ double wpy = -1e60;
+ int wix = -1;
+
+ /* We assume that the input target is well behaved, */
+ /* and that it includes a white point patch, */
+ /* and that it has an extreme L value */
+
+ for (i = 0; i < nodp; i++) {
+ double yv;
+
+ /* Tilt things towards D50 neutral white patches */
+ yv = points[i].v[0] - 0.3 * sqrt(points[i].v[1] * points[i].v[1]
+ + points[i].v[2] * points[i].v[2]);
+ if (yv > wpy) {
+ wpy = yv;
+ wix = i;
+ }
+ }
+//printf("~1 picked point %d as white\n",wix);
+ icmLab2XYZ(&icmD50, wp, points[wix].v);
+ wp[0] /= wp[1];
+ wp[2] /= wp[1];
+ wp[1] = 1.0;
+ icmAry2XYZ(os->wp, wp);
+
+ /* We'll use this wp for delta E calculation when creating the matrix */
+// if (os->verb) printf("Switching to L*a*b* white point %f %f %f\n",os->wp.X,os->wp.Y,os->wp.Z);
+ if (nweight < 1.0) /* Sanity */
+ nweight = 1.0;
+ for (i = 0; i < nodp; i++) {
+ double lch[3];
+ if (isLab)
+ icmLab2XYZ(&icmD50, points[i].v, points[i].v);
+ icmXYZ2Lab(&os->wp, points[i].v, points[i].v);
+ icmLab2LCh(lch, points[i].v);
+ /* Apply any neutral weighting */
+ if (lch[1] < 10.0) {
+ double w = nweight;
+ if (lch[1] > 5.0)
+ w = 1.0 + (nweight - 1.0) * (10.0 - lch[1])/(10.0 - 5.0);
+ points[i].w = w;
+ }
+//printf("~1 patch %d = Lab %f %f %f, C = %f w = %f\n",i,points[i].v[0], points[i].v[1], points[i].v[2], lch[1],points[i].w);
+ }
+ }
+
+ /* Set initial matrix optimisation values */
+ os->v[0] = 0.4; os->v[1] = 0.4; os->v[2] = 0.2; /* Matrix */
+ os->v[3] = 0.2; os->v[4] = 0.8; os->v[5] = 0.1;
+ os->v[6] = 0.02; os->v[7] = 0.15; os->v[8] = 1.3;
+
+ /* Do a first pass just setting the matrix values */
+ os->isLinear = 1;
+ os->isGamma = 1;
+ os->optdim = 9;
+ os->v[9] = os->v[10] = os->v[11] = 1.0; /* Linear */
+
+ /* Set search area to starting values */
+ for (j = 0; j < os->optdim; j++)
+ os->sa[j] = 0.2; /* Matrix, Gamma, Offsets, harmonics */
+
+ if (os->verb)
+ printf("Creating matrix...\n");
+
+ if (powell(&rerr, os->optdim, os->v, os->sa, stopon, maxits,
+ mxoptfunc, (void *)os, mxprogfunc, (void *)os) != 0)
+ warning("Powell failed to converge, residual error = %f",rerr);
+
+#ifndef NEVER
+ if (os->verb) {
+ printf("Matrix = %f %f %f\n",os->v[0], os->v[1], os->v[2]);
+ printf(" %f %f %f\n",os->v[3], os->v[4], os->v[5]);
+ printf(" %f %f %f\n",os->v[6], os->v[7], os->v[8]);
+ }
+#endif /* NEVER */
+
+ /* Now optimize again with shaper or gamma curves */
+ if (!isLinear || isGamma) {
+
+ /* Start from linear, which is what was assumed for the matrix fit, */
+ /* and fit first with a single shared curve. */
+ os->isShTRC = 1;
+ if (isGamma) { /* Just gamma curve */
+ os->isLinear = 0;
+ os->isGamma = 1;
+ os->optdim = 10;
+ os->v[9] = 1.0; /* Linear */
+ } else { /* Creating input curves */
+ os->isLinear = 0;
+ os->isGamma = 0;
+ os->optdim = 9 + 2 + os->norders; /* Matrix, offset + orders */
+ os->v[9] = 0.0; /* Input offset */
+ os->v[10] = 0.0; /* Output offset */
+ if (shape0gam)
+ os->v[11] = 1.0; /* Gamma */
+ else
+ os->v[11] = 0.0; /* 0th Harmonic */
+ for (i = 12; i < os->optdim; i++)
+ os->v[i] = 0.0; /* Higher orders */
+ }
+
+ /* Set search area to starting values */
+ for (j = 0; j < os->optdim; j++)
+ os->sa[j] = 0.2; /* Matrix, Gamma, Offsets, harmonics */
+
+ if (os->verb)
+ printf("Creating matrix and single curve...\n");
+
+ if (powell(&rerr, os->optdim, os->v, os->sa, stopon, maxits,
+ mxoptfunc, (void *)os, mxprogfunc, (void *)os) != 0)
+ warning("Powell failed to converge, residual error = %f",rerr);
+
+#ifndef NEVER
+ if (os->verb) {
+ printf("Matrix = %f %f %f\n",os->v[0], os->v[1], os->v[2]);
+ printf(" %f %f %f\n",os->v[3], os->v[4], os->v[5]);
+ printf(" %f %f %f\n",os->v[6], os->v[7], os->v[8]);
+ if (isGamma) { /* Creating input curves */
+ printf("Gamma = %f\n",os->v[9]);
+ } else { /* Creating input curves */
+ printf("Input offset = %f\n",os->v[9]);
+ printf("Output offset = %f\n",os->v[10]);
+ for (j = 0; j < os->norders; j++) {
+ if (shape0gam && j == 0)
+ printf("gamma = %f\n", os->v[11 + j]);
+ else
+ printf("%d harmonics = %f\n",j, os->v[11 + j]);
+ }
+ }
+ }
+#endif /* NEVER */
+
+ /* Now do the final optimisation with all curves */
+ if (!isShTRC) {
+ os->isShTRC = 0;
+ if (isGamma) { /* Just gamma curves */
+ os->isLinear = 0;
+ os->isGamma = 1;
+ os->optdim = 12;
+ os->v[9] = os->v[10] = os->v[11] = 1.0; /* Linear */
+ } else { /* Creating input curves */
+ os->isLinear = 0;
+ os->isGamma = 0;
+ os->optdim = 9 + 6 + 3 * os->norders; /* Matrix, offset + orders */
+ os->v[9] = os->v[10] = os->v[11] = 0.0; /* Input offset */
+ os->v[12] = os->v[13] = os->v[14] = 0.0; /* Output offset */
+ if (shape0gam)
+ os->v[15] = os->v[16] = os->v[17] = 1.0; /* Gamma */
+ else
+ os->v[15] = os->v[16] = os->v[17] = 0.0; /* 0th Harmonic */
+ for (i = 18; i < os->optdim; i++)
+ os->v[i] = 0.0; /* Higher orders */
+ }
+
+ /* Set search area to starting values */
+ for (j = 0; j < os->optdim; j++)
+ os->sa[j] = 0.2; /* Matrix, Gamma, Offsets, harmonics */
+
+ if (os->verb)
+ printf("Creating matrix and curves...\n");
+
+ if (powell(&rerr, os->optdim, os->v, os->sa, stopon, maxits,
+ mxoptfunc, (void *)os, mxprogfunc, (void *)os) != 0)
+ warning("Powell failed to converge, residual error = %f",rerr);
+ }
+ }
+ if (os->clipprims) { /* Clip -ve primaries */
+ for (i = 0; i < 9; i++) {
+ if (os->v[i] < 0.0)
+ os->v[i] = 0.0;
+ }
+ }
+
+#ifndef NEVER
+ if (os->verb) {
+ printf("Matrix = %f %f %f\n",os->v[0], os->v[1], os->v[2]);
+ printf(" %f %f %f\n",os->v[3], os->v[4], os->v[5]);
+ printf(" %f %f %f\n",os->v[6], os->v[7], os->v[8]);
+ if (!isLinear) { /* Creating input curves */
+ if (isGamma) { /* Creating input curves */
+ if (isShTRC)
+ printf("Gamma = %f\n",os->v[9]);
+ else
+ printf("Gamma = %f %f %f\n",os->v[9], os->v[10], os->v[11]);
+ } else { /* Creating input curves */
+ if (isShTRC) {
+ printf("Input offset = %f\n",os->v[9]);
+ printf("Output offset = %f\n",os->v[10]);
+ } else {
+ printf("Input offset = %f %f %f\n",os->v[9], os->v[10], os->v[11]);
+ printf("Output offset = %f %f %f\n",os->v[12], os->v[13], os->v[14]);
+ }
+ for (j = 0; j < os->norders; j++) {
+ if (isShTRC) {
+ if (shape0gam && j == 0)
+ printf("gamma = %f\n", os->v[11 + j]);
+ else
+ printf("%d harmonics = %f\n",j, os->v[11 + j]);
+ } else {
+ if (shape0gam && j == 0)
+ printf("%d gamma = %f %f %f\n",j, os->v[15 + j * 3],
+ os->v[16 + j * 3], os->v[17 + j * 3]);
+ else
+ printf("%d harmonics = %f %f %f\n",j, os->v[15 + j * 3],
+ os->v[16 + j * 3], os->v[17 + j * 3]);
+ }
+ }
+ }
+ }
+ }
+#endif /* NEVER */
+#ifdef NEVER /* Check DE of fit */
+ {
+ double xyz[3], txyz[3];
+
+ for (i = 0; i < nodp; i++) {
+
+ mxmfunc(os, os->v, xyz, ipoints[i].p);
+
+ if (isLab)
+ icmLab2XYZ(&icmD50, txyz, ipoints[i].v);
+ else
+ icmCpy3(txyz, ipoints[i].v);
+
+ printf("~1 point %d DE %f\n", i, icmXYZLabDE(&icmD50, txyz, xyz));
+ }
+ }
+#endif
+
+ /* Free the coordinate lists */
+ free(points);
+
+ return 0;
+}
+
+/* Apply a chromatic transform to the matrix to force the given */
+/* xyz value (typically white) to be exact */
+static void icxMM_force_exact(icxMatrixModel *p, double *targ, double *rgb) {
+ mxopt *os = (mxopt *)p->imp;
+ double txyz[3], axyz[3]; /* Target & actual xyz */
+ icmXYZNumber _tp, _ap;
+ double cmat[3][3]; /* Model transform matrix */
+
+ if (p->isLab)
+ icmLab2XYZ(&icmD50, txyz, targ);
+ else
+ icmCpy3(txyz, targ);
+
+ mxmfunc(os, os->v, axyz, rgb);
+
+ icmAry2XYZ(_ap, axyz);
+ icmAry2XYZ(_tp, txyz);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, _tp, _ap, cmat);
+
+ /* Apply correction to fine tune matrix. */
+ mxtransform(os, cmat);
+}
+
+static void icxMM_lookup(icxMatrixModel *p, double *out, double *in) {
+ mxopt *os = (mxopt *)p->imp;
+
+ mxmfunc(os, os->v, out, in);
+
+ if (p->isLab)
+ icmXYZ2Lab(&icmD50, out, out);
+}
+
+static void icxMM_del(icxMatrixModel *p) {
+ free(p->imp);
+ free(p);
+}
+
+/* Create a matrix model of a set of points, and return an object to lookup */
+/* points from the model. Return NULL on error. */
+icxMatrixModel *new_MatrixModel(
+int verb, /* NZ if verbose */
+int nodp, /* Number of points */
+cow *ipoints, /* Array of input points in XYZ space */
+int isLab, /* nz if data points are Lab */
+int quality, /* Quality metric, 0..3 (-1 == 2 orders only) */
+int isLinear, /* NZ if pure linear, gamma = 1.0 */
+int isGamma, /* NZ if gamma rather than shaper */
+int isShTRC, /* NZ if shared TRCs */
+int shape0gam, /* NZ if zero'th order shaper should be gamma function */
+int clipbw, /* Prevent white > 1 and -ve black */
+int clipprims, /* Prevent primaries going -ve */
+double smooth, /* Smoothing factor (nominal 1.0) */
+double scale /* Scale device values */
+) {
+ icxMatrixModel *p;
+
+ if ((p = (icxMatrixModel *) calloc(1,sizeof(icxMatrixModel))) == NULL)
+ return NULL;
+
+ p->force = icxMM_force_exact;
+ p->lookup = icxMM_lookup;
+ p->del = icxMM_del;
+
+ if ((p->imp = (void *) calloc(1,sizeof(mxopt))) == NULL) {
+ free(p);
+ return NULL;
+ }
+
+ if (createMatrix(NULL, (mxopt *)p->imp, verb, nodp, ipoints, isLab, quality,
+ isLinear, isGamma, isShTRC, shape0gam,
+ clipbw, clipprims, smooth, scale) != 0) {
+ free(p->imp);
+ free(p);
+ return NULL;
+ }
+
+ p->isLab = isLab;
+
+ return p;
+}
+
+/* Create icxLuMatrix and undelying tone reproduction curves and */
+/* colorant tags, initialised from the icc, and then overwritten */
+/* by a conversion created from the supplied scattered data points. */
+
+/* The scattered data is assumed to map Device -> native PCS (ie. dir = Fwd) */
+/* NOTE:- in theory once this icxLuMatrix is setup, it can be */
+/* called to translate color values. In practice I suspect */
+/* that the icxLuMatrix hasn't been setup completely enough to allows this. */
+/* Might be easier to close it and re-open it ? */
+static icxLuBase *
+set_icxLuMatrix(
+xicc *xicp,
+icmLuBase *plu, /* Pointer to Lu we are expanding (ours) */
+int flags, /* white/black point flags */
+int nodp, /* Number of points */
+int nodpbw, /* Number of points to look for white & black patches in */
+cow *ipoints, /* Array of input points in XYZ space */
+icxMatrixModel *skm, /* Optional skeleton model (not used here) */
+double dispLuminance, /* > 0.0 if display luminance value and is known */
+double wpscale, /* > 0.0 if input white point is to be scaled */
+int quality, /* Quality metric, 0..3 */
+double smooth /* Curve smoothing, nominally 1.0 */
+) {
+ icxLuMatrix *p; /* Object being created */
+ icc *icco = xicp->pp; /* Underlying icc object */
+ icmLuMatrix *pmlu = (icmLuMatrix *)plu; /* icc matrix lookup object */
+ int luflags = 0; /* icxLuMatrix alloc clip, merge flags */
+ int isLinear = 0; /* NZ if pure linear, gamma = 1.0 */
+ int isGamma = 0; /* NZ if gamma rather than shaper */
+ int isShTRC = 0; /* NZ if shared TRCs */
+ int inputChan = 3; /* Must be RGB like */
+ int outputChan = 3; /* Must be the PCS */
+ icmHeader *h = icco->header; /* Pointer to icc header */
+ int rsplflags = 0; /* Flags for scattered data rspl */
+ int e, f, i, j;
+ int maxits = 200; /* Optimisation stop params */
+ double stopon = 0.01; /* Absolute delta E change to stop on */
+ mxopt os; /* Optimisation information */
+ double rerr;
+ /* If ICX_SET_WHITE | ICX_SET_BLACK: */
+ double wp[3]; /* Absolute White point in XYZ */
+ double bp[3]; /* Absolute Black point in XYZ */
+ double dw[MXDI]; /* Device white value to adjust to be D50 */
+ double db[MXDI]; /* Device balck value */
+ double dgw[3]; /* Device space gamut boundary white for ICX_SET_WHITE_US */
+ double fromAbs[3][3]; /* From abs to relative */
+ double toAbs[3][3]; /* To abs from relative */
+ cow *rpoints = NULL; /* Aprox. relative in->output values */
+
+#ifdef DEBUG_PLOT
+ #define XRES 100
+ double xx[XRES];
+ double y1[XRES];
+#endif /* DEBUG_PLOT */
+
+ if (flags & ICX_VERBOSE)
+ rsplflags |= RSPL_VERBOSE;
+
+ luflags = flags; /* Transfer straight though ? */
+
+ /* Check out some things about the profile */
+ {
+ icmCurve *wor, *wog, *wob;
+ wor = pmlu->redCurve;
+ wog = pmlu->greenCurve;
+ wob = pmlu->blueCurve;
+
+ if (wor == wog) {
+ if (wog != wob) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_matrix: TRC sharing is inconsistent");
+ return NULL;
+ }
+ isShTRC = 1;
+ }
+ if (wor->flag != wog->flag || wog->flag != wob->flag) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_matrix: TRC type is inconsistent");
+ return NULL;
+ }
+ if (wor->flag == icmCurveGamma) {
+ isGamma = 1;
+ }
+
+ if (flags & ICX_NO_IN_SHP_LUTS) {
+ isLinear = 1;
+ }
+ }
+
+ /* Do basic icxLu creation and initialisation */
+ if ((p = alloc_icxLuMatrix(xicp, plu, 0, luflags)) == NULL) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_matrix: malloc failed");
+ return NULL;
+ }
+
+ p->func = icmFwd; /* Assumed by caller */
+
+ /* Get the effective spaces of underlying icm, and set icx the same */
+ plu->spaces(plu, &p->ins, NULL, &p->outs, NULL, NULL, &p->intent, NULL, &p->pcs, NULL);
+
+ /* For set_icx the effective pcs has to be the same as the native pcs */
+
+ /* Sanity check for matrix */
+ if (p->pcs != icSigXYZData) {
+ p->pp->errc = 1;
+ sprintf(p->pp->err,"Can't create matrix profile with PCS of Lab !");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ /* In general the native and effective ranges of the icx will be the same as the */
+ /* underlying icm lookup object. */
+ p->plu->get_lutranges(p->plu, p->ninmin, p->ninmax, p->noutmin, p->noutmax);
+ p->plu->get_ranges(p->plu, p->inmin, p->inmax, p->outmin, p->outmax);
+
+ /* If we have a Jab PCS override, reflect this in the effective icx range. */
+ /* Note that the ab ranges are nominal. They will exceed this range */
+ /* for colors representable in L*a*b* PCS */
+ if (p->ins == icxSigJabData) {
+ p->inmin[0] = 0.0; p->inmax[0] = 100.0;
+ p->inmin[1] = -128.0; p->inmax[1] = 128.0;
+ p->inmin[2] = -128.0; p->inmax[2] = 128.0;
+ } else if (p->outs == icxSigJabData) {
+ p->outmin[0] = 0.0; p->outmax[0] = 100.0;
+ p->outmin[1] = -128.0; p->outmax[1] = 128.0;
+ p->outmin[2] = -128.0; p->outmax[2] = 128.0;
+ }
+
+ /* ------------------------------- */
+
+ /* Choose a white and black point */
+ if (flags & (ICX_SET_WHITE | ICX_SET_BLACK)) {
+
+ if (flags & ICX_VERBOSE)
+ printf("Find white & black points\n");
+
+ /* Compute device white and black points as if */
+ /* we are doing an Output or Display device */
+ {
+ switch (h->colorSpace) {
+
+ case icSigCmyData:
+ for (e = 0; e < p->inputChan; e++) {
+ dw[e] = 0.0;
+ db[e] = 1.0;
+ }
+ break;
+ case icSigRgbData:
+ for (e = 0; e < p->inputChan; e++) {
+ dw[e] = 1.0;
+ db[e] = 0.0;
+ }
+ break;
+
+ default: {
+ xicp->errc = 1;
+ sprintf(xicp->err,"set_icxLuMatrix: can't handle color space %s",
+ icm2str(icmColorSpaceSignature, h->colorSpace));
+ p->del((icxLuBase *)p);
+ return NULL;
+ break;
+ }
+ }
+ }
+
+ /* dw is what we want for dgw[], used for XFIT_OUT_WP_REL_US */
+ for (e = 0; e < p->inputChan; e++)
+ dgw[e] = dw[e];
+
+ /* If this is actuall an input device, lookup wp & bp */
+ /* and override dwhite & dblack */
+ if (h->deviceClass == icSigInputClass) {
+ double wpy = -1e60, bpy = 1e60;
+ int wix = -1, bix = -1;
+
+ /* We assume that the input target is well behaved, */
+ /* and that it includes a white and black point patch, */
+ /* and that they have the extreme L/Y values */
+
+ /*
+ NOTE that this may not be the best approach !
+ It may be better to average the chromaticity
+ of all the neutral seeming patches, since
+ the whitest patch may have (for instance)
+ a blue tint.
+ */
+
+ /* Discover the white and black patches */
+ for (i = 0; i < nodpbw; i++) {
+ double labv[3], yv;
+
+ /* Create D50 Lab to allow some chromatic sensitivity */
+ /* in picking the white point */
+ icmXYZ2Lab(&icmD50, labv, ipoints[i].v);
+
+#ifdef NEVER
+ /* Choose Y */
+ if (ipoints[i].v[1] > wpy) {
+ wp[0] = ipoints[i].v[0];
+ wp[1] = ipoints[i].v[1];
+ wp[2] = ipoints[i].v[2];
+ for (e = 0; e < p->inputChan; e++)
+ dw[e] = ipoints[i].p[e];
+ wpy = ipoints[i].v[1];
+ wix = i;
+ }
+#else
+
+ /* Tilt things towards D50 neutral white patches */
+ yv = labv[0] - 0.3 * sqrt(labv[1] * labv[1] + labv[2] * labv[2]);
+ if (yv > wpy) {
+ wp[0] = ipoints[i].v[0];
+ wp[1] = ipoints[i].v[1];
+ wp[2] = ipoints[i].v[2];
+ for (e = 0; e < p->inputChan; e++)
+ dw[e] = ipoints[i].p[e];
+ wpy = yv;
+ wix = i;
+ }
+#endif
+ if (ipoints[i].v[1] < bpy) {
+ bp[0] = ipoints[i].v[0];
+ bp[1] = ipoints[i].v[1];
+ bp[2] = ipoints[i].v[2];
+ for (e = 0; e < p->inputChan; e++)
+ db[e] = ipoints[i].p[e];
+ bpy = ipoints[i].v[1];
+ bix = i;
+ }
+ }
+ if (flags & ICX_VERBOSE) {
+ printf("Picked white patch %d with dev = %s\n XYZ = %s, Lab = %s\n",
+ wix+1, icmPdv(p->inputChan, dw), icmPdv(3, wp), icmPLab(wp));
+ printf("Picked black patch %d with dev = %s\n XYZ = %s, Lab = %s\n",
+ bix+1, icmPdv(p->inputChan, db), icmPdv(3, bp), icmPLab(bp));
+ }
+
+ } else {
+ /* We assume that the display target is well behaved, */
+ /* and that it includes a white point patch. */
+ int nw = 0;
+
+ wp[0] = wp[1] = wp[2] = 0.0;
+
+ switch (h->colorSpace) {
+
+ case icSigCmyData:
+ for (i = 0; i < nodpbw; i++) {
+ if (ipoints[i].p[0] < 0.001
+ && ipoints[i].p[1] < 0.001
+ && ipoints[i].p[2] < 0.001) {
+ wp[0] += ipoints[i].v[0];
+ wp[1] += ipoints[i].v[1];
+ wp[2] += ipoints[i].v[2];
+ nw++;
+ }
+ }
+ break;
+ case icSigRgbData:
+ for (i = 0; i < nodpbw; i++) {
+ if (ipoints[i].p[0] > 0.999
+ && ipoints[i].p[1] > 0.999
+ && ipoints[i].p[2] > 0.999) {
+ wp[0] += ipoints[i].v[0];
+ wp[1] += ipoints[i].v[1];
+ wp[2] += ipoints[i].v[2];
+ nw++;
+ }
+ }
+ break;
+
+ default:
+ xicp->errc = 1;
+ sprintf(xicp->err,"set_icxLuMatrix: can't handle color space %s",
+ icm2str(icmColorSpaceSignature, h->colorSpace));
+ p->del((icxLuBase *)p);
+ return NULL;
+ break;
+ }
+
+ if (nw == 0) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"set_icxLuMatrix: can't handle test points without a white patch");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ wp[0] /= (double)nw;
+ wp[1] /= (double)nw;
+ wp[2] /= (double)nw;
+
+ if (flags & ICX_VERBOSE) {
+ printf("Initial white point = %f %f %f\n",wp[0],wp[1],wp[2]);
+ }
+
+ /* Need to lookup bp[] before we set the tag */
+ }
+
+ /* Create some abs<->rel chromatic conversions */
+ {
+ icmXYZNumber _wp;
+ icmAry2XYZ(_wp, wp);
+
+ /* Absolute->Aprox. Relative Adaptation matrix */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, fromAbs);
+
+ /* Aproximate relative to absolute conversion matrix */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, _wp, icmD50, toAbs);
+ }
+
+ } else {
+ icmSetUnity3x3(fromAbs);
+ icmSetUnity3x3(toAbs);
+ }
+
+ /* Create copy of input points with output converted to white relative */
+ if ((rpoints = (cow *)malloc(nodp * sizeof(cow))) == NULL) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"set_icxLuMatrix: malloc failed");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ for (i = 0; i < nodp; i++) {
+ rpoints[i].w = ipoints[i].w;
+ for (e = 0; e < inputChan; e++)
+ rpoints[i].p[e] = ipoints[i].p[e];
+ for (f = 0; f < outputChan; f++)
+ rpoints[i].v[f] = ipoints[i].v[f];
+
+ /* abs out -> aprox. rel out */
+ icmMulBy3x3(rpoints[i].v, fromAbs, rpoints[i].v);
+ }
+
+ /* ------------------------------- */
+
+ /* (Use a gamma curve as 0th order shape) */
+ if ((p->pp->errc = createMatrix(p->pp->err, &os, flags & ICX_VERBOSE ? 1 : 0,
+ nodp, rpoints, 0, quality,
+ isLinear, isGamma, isShTRC, 1,
+ flags & ICX_CLIP_WB ? 1 : 0,
+ flags & ICX_CLIP_PRIMS ? 1 : 0,
+ smooth, 1.0)) != 0) {
+ free(rpoints);
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ free(rpoints); rpoints = NULL;
+
+ /* The overall device to absolute conversion is now what we want */
+ /* (as dictated by the points, weighting and best fit), */
+ /* but we need to adjust the device to relative conversion */
+ /* to make device white map exactly to D50, without touching */
+ /* the overall absolute behaviour. */
+ if (p->flags & ICX_SET_WHITE) {
+ double aw[3]; /* aprox rel. white */
+ icmXYZNumber _wp; /* Uncorrected dw maps to _wp */
+ double cmat[3][3]; /* Model correction matrix */
+
+ if (flags & ICX_VERBOSE)
+ printf("Doing White point fine tune:\n");
+
+
+ /* See what the aprox. relative white point has turned out to be, */
+ /* by looking up the device white in the current conversion */
+ mxmfunc(&os, os.v, aw, dw);
+
+ if (flags & ICX_VERBOSE) {
+ printf("Before fine tune, rel WP = XYZ %s, Lab %s\n", icmPdv(3,aw), icmPLab(aw));
+ }
+
+ /* Matrix needed to correct aprox white to target D50 */
+ icmAry2XYZ(_wp, aw); /* Aprox relative target white point */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, cmat); /* Correction */
+
+ /* Compute the current absolute white point */
+ icmMulBy3x3(wp, toAbs, aw);
+
+ /* Apply correction to fine tune matrix. */
+ mxtransform(&os, cmat);
+
+ /* Fix relative conversions to leave absolute response unchanged. */
+ icmAry2XYZ(_wp, wp); /* Actual white point */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, fromAbs);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, _wp, icmD50, toAbs);
+
+ if (flags & ICX_VERBOSE) {
+ double tw[3];
+ mxmfunc(&os, os.v, tw, dw); /* Lookup white again */
+ printf("After fine tune, rel WP = XYZ %s, Lab %s\n", icmPdv(3, tw), icmPLab(tw));
+ printf(" abs WP = XYZ %s, Lab %s\n", icmPdv(3, wp), icmPLab(wp));
+ }
+ }
+
+ /* Create default wpscale */
+ if (wpscale < 0.0) {
+ wpscale = 1.0;
+ } else {
+ if (flags & ICX_VERBOSE) {
+ printf("White manual point scale %f\n", wpscale);
+ }
+ }
+
+ /* If we are going to auto scale the WP to avoid clipping */
+ /* values above the WP: (not important for matrix profiles ?) */
+ if ((p->flags & ICX_SET_WHITE_US) == ICX_SET_WHITE_US) {
+ double tw[3], bw[3];
+ icmXYZNumber _wp;
+ double uswpscale = 1.0;
+ double mxd, mxY;
+ double ndw[3];
+
+ /* See what device space gamut boundary white (ie. 1,1,1) maps to */
+ mxmfunc(&os, os.v, tw, dgw);
+ icmMulBy3x3(tw, toAbs, tw); /* Convert to absolute */
+
+ mxY = tw[1];
+ icmCpy3(bw, tw);
+//printf("~1 1,1,1 Y = %f\n",tw[1]);
+
+ /* See what the device white point value scaled to 1 produces */
+ mxd = -1.0;
+ for (e = 0; e < inputChan; e++) {
+ if (dw[e] > mxd)
+ mxd = dw[e];
+ }
+ for (e = 0; e < inputChan; e++)
+ ndw[e] = dw[e]/mxd;
+
+ mxmfunc(&os, os.v, tw, ndw);
+ icmMulBy3x3(tw, toAbs, tw); /* Convert to absolute */
+
+//printf("~1 ndw = %f %f %f Y = %f\n",ndw[0],ndw[1],ndw[2],tw[1]);
+ if (tw[1] > mxY) {
+ mxY = tw[1];
+ icmCpy3(bw, tw);
+ }
+
+ /* Compute WP scale factor needed to fit mxY */
+ if (mxY > wp[1]) {
+ uswpscale = mxY/wp[1];
+ wpscale *= uswpscale;
+ if (flags & ICX_VERBOSE) {
+ printf("Dev boundary white XYZ %s, scale WP by %f, total WP scale %f\n",
+ icmPdv(3, bw), uswpscale, wpscale);
+ }
+ }
+ }
+
+ /* If the scaled WP would have Y > 1.0, clip it to 1.0 */
+ if (p->flags & ICX_CLIP_WB) {
+
+ if ((wp[1] * wpscale) > 1.0) {
+ wpscale = 1.0/wp[1]; /* Make wp Y = 1.0 */
+ if (flags & ICX_VERBOSE) {
+ printf("WP Y would ve > 1.0. scale by %f to clip it\n",wpscale);
+ }
+ }
+ }
+
+ /* Apply our total wp scale factor */
+ if (wpscale != 1.0) {
+ icmXYZNumber _wp;
+ double cmat[3][3]; /* Model correction matrix */
+
+ /* Create inverse scaling matrix for relative rspl data */
+ icmSetUnity3x3(cmat);
+ icmScale3x3(cmat, cmat, 1.0/wpscale);
+
+ /* Inverse scale the matrix */
+ mxtransform(&os, cmat);
+
+ /* Scale the WP */
+ icmScale3(wp, wp, wpscale);
+
+ /* Fix absolute conversions to leave absolute response unchanged. */
+ icmAry2XYZ(_wp, wp); /* Actual white point */
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, icmD50, _wp, fromAbs);
+ icmChromAdaptMatrix(ICM_CAM_BRADFORD, _wp, icmD50, toAbs);
+ }
+
+ /* Look up the actual black point */
+ if (p->flags & ICX_SET_BLACK) {
+
+ /* Look black point up in dev->rel model */
+ mxmfunc(&os, os.v, bp, db);
+
+ /* Convert from relative to Absolute colorimetric */
+ icmMulBy3x3(bp, toAbs, bp);
+
+
+ /* Got XYZ black point in bp[] */
+ if (flags & ICX_VERBOSE) {
+ printf("Black point XYZ = %s, Lab = %s\n", icmPdv(3,bp),icmPLab(bp));
+ }
+
+ if (flags & ICX_CLIP_WB) {
+ if (bp[0] < 0.0 || bp[1] < 0.0 || bp[1] < 0.0) {
+ if (bp[0] < 0.0)
+ bp[0] = 0.0;
+ if (bp[1] < 0.0)
+ bp[1] = 0.0;
+ if (bp[2] < 0.0)
+ bp[2] = 0.0;
+ if (flags & ICX_VERBOSE)
+ printf("Black point clipped to XYZ = %s, Lab = %s\n",icmPdv(3,bp),icmPLab(bp));
+ }
+ }
+ }
+
+ if (flags & (ICX_SET_WHITE | ICX_SET_BLACK)) {
+
+ /* If this is a display, adjust the absolute white point to be */
+ /* exactly Y = 1.0, and compensate the matrix, dispLuminance */
+ /* and black point accordingly. */
+ if (h->deviceClass == icSigDisplayClass) {
+ double cmat[3][3]; /* Model correction matrix */
+ double scale = 1.0/wp[1];
+
+ if (flags & ICX_VERBOSE)
+ printf("Scaling White Point by %f to make Y = 1.0\n", scale);
+
+ /* Scale the WP & BP*/
+ icmScale3(wp, wp, scale);
+ icmScale3(bp, bp, scale);
+
+ /* Inverse scale the luminance */
+ dispLuminance /= scale;
+ }
+
+ /* Absolute luminance tag */
+ if (flags & ICX_WRITE_WBL
+ && h->deviceClass == icSigDisplayClass
+ && dispLuminance > 0.0) {
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)icco->read_tag(
+ icco, icSigLuminanceTag)) == NULL) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_luminance: couldn't find luminance tag");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ if (wo->ttype != icSigXYZArrayType) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"luminance: tag has wrong type");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = 0.0;
+ wo->data[0].Y = dispLuminance;
+ wo->data[0].Z = 0.0;
+
+ if (flags & ICX_VERBOSE)
+ printf("Display Luminance = %f\n", wo->data[0].Y);
+ }
+
+ /* Write white and black tags */
+ if ((flags & ICX_WRITE_WBL)
+ && (flags & ICX_SET_WHITE)) { /* White Point Tag: */
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)icco->read_tag(
+ icco, icSigMediaWhitePointTag)) == NULL) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_white_black: couldn't find white tag");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ if (wo->ttype != icSigXYZArrayType) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_white_black: white tag has wrong type");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = wp[0];
+ wo->data[0].Y = wp[1];
+ wo->data[0].Z = wp[2];
+
+ if (flags & ICX_VERBOSE)
+ printf("White point XYZ = %f %f %f\n",wp[0],wp[1],wp[2]);
+ }
+ if ((flags & ICX_WRITE_WBL)
+ && (flags & ICX_SET_BLACK)) { /* Black Point Tag: */
+ icmXYZArray *wo;
+ if ((wo = (icmXYZArray *)icco->read_tag(
+ icco, icSigMediaBlackPointTag)) == NULL) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_white_black: couldn't find black tag");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+ if (wo->ttype != icSigXYZArrayType) {
+ xicp->errc = 1;
+ sprintf(xicp->err,"icx_set_white_black: black tag has wrong type");
+ p->del((icxLuBase *)p);
+ return NULL;
+ }
+
+ wo->size = 1;
+ wo->allocate((icmBase *)wo); /* Allocate space */
+ wo->data[0].X = bp[0];
+ wo->data[0].Y = bp[1];
+ wo->data[0].Z = bp[2];
+
+ if (flags & ICX_VERBOSE)
+ printf("Black point XYZ = %f %f %f\n",bp[0],bp[1],bp[2]);
+ }
+
+ // ~~99
+ if (flags & ICX_CLIP_PRIMS) {
+ for (i = 0; i < 9; i++) {
+ if (os.v[i] < 0.0)
+ os.v[i] = 0.0;
+ }
+ }
+ }
+
+ if (flags & ICX_VERBOSE)
+ printf("Done gamma/shaper and matrix creation\n");
+
+ /* Write the gamma/shaper and matrix to the icc memory structures */
+ if (!isGamma) { /* Creating input curves */
+ unsigned int ui;
+ icmCurve *wor, *wog, *wob;
+ wor = pmlu->redCurve;
+ wog = pmlu->greenCurve;
+ wob = pmlu->blueCurve;
+
+ for (ui = 0; ui < wor->size; ui++) {
+ double in, rgb[3];
+
+ for (j = 0; j < 3; j++) {
+
+ in = (double)ui / (wor->size - 1.0);
+
+ mxmfunc1(&os, j, os.v, &rgb[j], &in);
+
+ if (rgb[j] < 0.0)
+ rgb[j] = 0.0;
+ else if (rgb[j] > 1.0)
+ rgb[j] = 1.0;
+ }
+ wor->data[ui] = rgb[0]; /* Curve values 0.0 - 1.0 */
+ if (!isShTRC) {
+ wog->data[ui] = rgb[1];
+ wob->data[ui] = rgb[2];
+ }
+ }
+#ifdef DEBUG_PLOT
+ /* Display the result fit */
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < XRES; i++) {
+ double x, y;
+ xx[i] = x = i/(double)(XRES-1);
+ mxmfunc1(&os, j, os.v, &y, &x);
+ if (y < 0.0)
+ y = 0.0;
+ else if (y > 1.0)
+ y = 1.0;
+ y1[i] = y;
+ }
+ do_plot(xx,y1,NULL,NULL,XRES);
+ }
+#endif /* DEBUG_PLOT */
+
+
+ } else { /* Gamma */
+ icmCurve *wor, *wog, *wob;
+ wor = pmlu->redCurve;
+ wog = pmlu->greenCurve;
+ wob = pmlu->blueCurve;
+ wor->data[0] = os.v[9]; /* Gamma values */
+ if (!isShTRC) {
+ wog->data[0] = os.v[10];
+ wob->data[0] = os.v[11];
+ }
+ }
+
+ /* Matrix values */
+ {
+ icmXYZArray *wor, *wog, *wob;
+ wor = pmlu->redColrnt;
+ wog = pmlu->greenColrnt;
+ wob = pmlu->blueColrnt;
+ wor->data[0].X = os.v[0]; wor->data[0].Y = os.v[3]; wor->data[0].Z = os.v[6];
+ wog->data[0].X = os.v[1]; wog->data[0].Y = os.v[4]; wog->data[0].Z = os.v[7];
+ wob->data[0].X = os.v[2]; wob->data[0].Y = os.v[5]; wob->data[0].Z = os.v[8];
+
+ /* Load into pmlu matrix and inverse ??? */
+ }
+
+ if (flags & ICX_VERBOSE)
+ printf("Profile done\n");
+
+ return (icxLuBase *)p;
+}
+
+/* ========================================================= */
+
+/* Given an xicc lookup object, returm a gamut object. */
+/* Note that the PCS must be Lab or Jab */
+/* Return NULL on error, check errc+err for reason */
+static gamut *icxLuMatrixGamut(
+icxLuBase *plu, /* this */
+double detail /* gamut detail level, 0.0 = def */
+) {
+ xicc *p = plu->pp; /* parent xicc */
+ icxLuMatrix *lumat = (icxLuMatrix *)plu; /* Lookup xMatrix type object */
+ icColorSpaceSignature pcs;
+ icmLookupFunc func;
+ double white[3], black[3], kblack[3];
+ gamut *gam;
+ int res; /* Sample point resolution */
+ int i, e;
+
+ if (detail == 0.0)
+ detail = 10.0;
+
+ /* get some details */
+ plu->spaces(plu, NULL, NULL, NULL, NULL, NULL, NULL, &func, &pcs);
+
+ if (func != icmFwd && func != icmBwd) {
+ p->errc = 1;
+ sprintf(p->err,"Creating Gamut surface for anything other than Device <-> PCS is not supported.");
+ return NULL;
+ }
+
+ if (pcs != icSigLabData && pcs != icxSigJabData) {
+ p->errc = 1;
+ sprintf(p->err,"Creating Gamut surface PCS of other than Lab or Jab is not supported.");
+ return NULL;
+ }
+
+ gam = new_gamut(detail, pcs == icxSigJabData, 0);
+
+ /* Explore the gamut by itterating through */
+ /* it with sample points in device space. */
+
+ res = (int)(600.0/detail); /* Establish an appropriate sampling density */
+
+ if (res < 40)
+ res = 40;
+
+ /* Since matrix profiles can't be non-monotonic, */
+ /* just itterate through the surface colors. */
+ for (i = 0; i < 3; i++) {
+ int co[3];
+ int ep[3];
+ int co_e = 0;
+
+ for (e = 0; e < 3; e++) {
+ co[e] = 0;
+ ep[e] = res;
+ }
+ ep[i] = 2;
+
+ while (co_e < 3) {
+ double in[3];
+ double out[3];
+
+ for (e = 0; e < 3; e++) /* Convert count to input value */
+ in[e] = co[e]/(ep[e]-1.0);
+
+ /* Always use the device->PCS conversion */
+ if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1)
+ error ("%d, %s",p->errc,p->err);
+
+ gam->expand(gam, out);
+
+ /* Increment the counter */
+ for (co_e = 0; co_e < 3; co_e++) {
+ co[co_e]++;
+ if (co[co_e] < ep[co_e])
+ break; /* No carry */
+ co[co_e] = 0;
+ }
+ }
+ }
+
+#ifdef NEVER
+ /* Try it twice */
+ for (i = 0; i < 3; i++) {
+ int co[3];
+ int ep[3];
+ int co_e = 0;
+
+ for (e = 0; e < 3; e++) {
+ co[e] = 0;
+ ep[e] = res;
+ }
+ ep[i] = 2;
+
+ while (co_e < 3) {
+ double in[3];
+ double out[3];
+
+ for (e = 0; e < 3; e++) /* Convert count to input value */
+ in[e] = co[e]/(ep[e]-1.0);
+
+ /* Always use the device->PCS conversion */
+ if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1)
+ error ("%d, %s",p->errc,p->err);
+
+ gam->expand(gam, out);
+
+ /* Increment the counter */
+ for (co_e = 0; co_e < 3; co_e++) {
+ co[co_e]++;
+ if (co[co_e] < ep[co_e])
+ break; /* No carry */
+ co[co_e] = 0;
+ }
+ }
+ }
+#endif
+
+#ifdef NEVER // (doesn't seem to make much difference)
+ /* run along the primary ridges in more detail too */
+ /* just itterate through the surface colors. */
+ for (i = 0; i < 3; i++) {
+ int j;
+ double in[3];
+ double out[3];
+
+ res *= 4;
+
+ for (j = 0; j < res; j++) {
+ double vv = i/(res-1.0);
+
+ in[0] = in[1] = in[2] = vv;
+ in[i] = 0.0;
+
+ if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1)
+ error ("%d, %s",p->errc,p->err);
+ gam->expand(gam, out);
+
+ in[0] = in[1] = in[2] = 0.0;
+ in[i] = vv;
+
+ if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1)
+ error ("%d, %s",p->errc,p->err);
+ gam->expand(gam, out);
+ }
+ }
+#endif
+
+ /* Put the white and black points in the gamut */
+ plu->efv_wh_bk_points(plu, white, black, kblack);
+ gam->setwb(gam, white, black, kblack);
+
+ /* set the cusp points by itterating through the 0 & 100% colorant combinations */
+ {
+ DCOUNT(co, 3, 3, 0, 0, 2);
+
+ gam->setcusps(gam, 0, NULL);
+ DC_INIT(co);
+ while(!DC_DONE(co)) {
+ int e;
+ double in[3];
+ double out[3];
+
+ if (!(co[0] == 0 && co[1] == 0 && co[2] == 0)
+ && !(co[0] == 1 && co[1] == 1 && co[2] == 1)) { /* Skip white and black */
+ for (e = 0; e < 3; e++)
+ in[e] = (double)co[e];
+
+ /* Always use the device->PCS conversion */
+ if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1)
+ error ("%d, %s",p->errc,p->err);
+ gam->setcusps(gam, 3, out);
+ }
+
+ DC_INC(co);
+ }
+ gam->setcusps(gam, 2, NULL);
+ }
+
+#ifdef NEVER /* Not sure if this is a good idea ?? */
+ gam->getwb(gam, NULL, NULL, white, black); /* Get the actual gamut white and black points */
+ gam->setwb(gam, white, black); /* Put it back as colorspace one */
+#endif
+
+ return gam;
+}
+
+#ifdef DEBUG
+#undef DEBUG
+#endif
diff --git a/xicc/xmono.c b/xicc/xmono.c
new file mode 100644
index 0000000..f0ee04f
--- /dev/null
+++ b/xicc/xmono.c
@@ -0,0 +1,324 @@
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 2/7/00
+ * Version: 1.00
+ *
+ * Copyright 2000 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.
+ *
+ * Based on the old iccXfm class.
+ */
+
+/*
+ * This module provides the expands icclib functionality
+ * for monochrome profiles.
+ * This file is #included in xicc.c, to keep its functions private.
+ */
+
+/*
+ * TTBD:
+ * Some of the error handling is crude. Shouldn't use
+ * error(), should return status.
+ *
+ */
+
+/* ============================================================= */
+/* Forward and Backward Monochrome type conversion */
+/* Return 0 on success, 1 if clipping occured, 2 on other error */
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Individual components of Fwd conversion: */
+static int
+icxLuMonoFwd_curve (
+icxLuMono *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ return ((icmLuMono *)p->plu)->fwd_curve((icmLuMono *)p->plu, out, in);
+}
+
+static int
+icxLuMonoFwd_map (
+icxLuMono *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ return ((icmLuMono *)p->plu)->fwd_map((icmLuMono *)p->plu, out, in);
+}
+
+static int
+icxLuMonoFwd_abs (
+icxLuMono *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ rv |= ((icmLuMono *)p->plu)->fwd_abs((icmLuMono *)p->plu, out, in);
+
+ if (p->pcs == icxSigJabData) {
+ p->cam->XYZ_to_cam(p->cam, out, out);
+ }
+ return rv;
+}
+
+
+/* Overall Fwd conversion routine */
+static int
+icxLuMonoFwd_lookup (
+icxLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+ icxLuMono *p = (icxLuMono *)pp;
+ rv |= icxLuMonoFwd_curve(p, out, in);
+ rv |= icxLuMonoFwd_map(p, out, out);
+ rv |= icxLuMonoFwd_abs(p, out, out);
+ return rv;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given a relative XYZ or Lab PCS value, convert in the fwd direction into */
+/* the nominated output PCS (ie. Absolute, Jab etc.) */
+/* (This is used in generating gamut compression in B2A tables) */
+void icxLuMono_fwd_relpcs_outpcs(
+icxLuBase *pp,
+icColorSpaceSignature is, /* Input space, XYZ or Lab */
+double *out, double *in) {
+ icxLuMono *p = (icxLuMono *)pp;
+
+ icmLab2XYZ(&icmD50, out, in);
+ if (is == icSigLabData && p->natpcs == icSigXYZData) {
+ icxLuMonoFwd_abs(p, out, out);
+ } else if (is == icSigXYZData && p->natpcs == icSigLabData) {
+ icxLuMonoFwd_abs(p, out, out);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - */
+/* Individual components of Bwd conversion: */
+
+static int
+icxLuMonoBwd_abs (
+icxLuMono *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ int rv = 0;
+
+ if (p->pcs == icxSigJabData) {
+ p->cam->cam_to_XYZ(p->cam, out, in);
+ rv |= ((icmLuMono *)p->plu)->bwd_abs((icmLuMono *)p->plu, out, out);
+ /* Hack to prevent CAM02 weirdness being amplified by */
+ /* any later per channel clipping. */
+ /* Limit -Y to non-stupid values by scaling */
+ if (out[1] < -0.1) {
+ out[0] *= -0.1/out[1];
+ out[2] *= -0.1/out[1];
+ out[1] = -0.1;
+ }
+ } else {
+ rv |= ((icmLuMono *)p->plu)->bwd_abs((icmLuMono *)p->plu, out, in);
+ }
+ return rv;
+}
+
+static int
+icxLuMonoBwd_map (
+icxLuMono *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ return ((icmLuMono *)p->plu)->bwd_map((icmLuMono *)p->plu, out, in);
+}
+
+static int
+icxLuMonoBwd_curve (
+icxLuMono *p, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ return ((icmLuMono *)p->plu)->bwd_curve((icmLuMono *)p->plu, out, in);
+}
+
+/* Overall Bwd conversion routine */
+static int
+icxLuMonoBwd_lookup (
+icxLuBase *pp, /* This */
+double *out, /* Vector of output values */
+double *in /* Vector of input values */
+) {
+ double temp[3];
+ int rv = 0;
+ icxLuMono *p = (icxLuMono *)pp;
+ rv |= icxLuMonoBwd_abs(p, temp, in);
+ rv |= icxLuMonoBwd_map(p, out, temp);
+ rv |= icxLuMonoBwd_curve(p, out, out);
+ return rv;
+}
+
+static void
+icxLuMono_free(
+icxLuBase *p
+) {
+ p->plu->del(p->plu);
+ if (p->cam != NULL)
+ p->cam->del(p->cam);
+ free(p);
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Given a nominated output PCS (ie. Absolute, Jab etc.), convert it in the bwd */
+/* direction into a relative XYZ or Lab PCS value */
+/* (This is used in generating gamut compression in B2A tables) */
+void icxLuMono_bwd_outpcs_relpcs(
+icxLuBase *pp,
+icColorSpaceSignature os, /* Output space, XYZ or Lab */
+double *out, double *in) {
+ icxLuMono *p = (icxLuMono *)pp;
+
+ if (os == icSigXYZData && p->natpcs == icSigLabData) {
+ icxLuMonoFwd_abs(p, out, in);
+ icmLab2XYZ(&icmD50, out, out);
+ } else if (os == icSigXYZData && p->natpcs == icSigLabData) {
+ icxLuMonoFwd_abs(p, out, in);
+ icmXYZ2Lab(&icmD50, out, out);
+ } else {
+ icxLuMonoFwd_abs(p, out, in);
+ }
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static gamut *icxLuMonoGamut(icxLuBase *plu, double detail);
+
+static icxLuBase *
+new_icxLuMono(
+xicc *xicp,
+int flags, /* clip, merge flags */
+icmLuBase *plu, /* Pointer to Lu we are expanding */
+icmLookupFunc func, /* Functionality requested */
+icRenderingIntent intent, /* Rendering intent */
+icColorSpaceSignature pcsor, /* PCS override (0 = def) */
+icxViewCond *vc, /* Viewing Condition (NULL if pcsor is not CIECAM) */
+int dir /* 0 = fwd, 1 = bwd */
+) {
+ icxLuMono *p;
+
+ /* Do the basic icxLuMono creation and initialisation */
+
+ if ((p = (icxLuMono *) calloc(1,sizeof(icxLuMono))) == NULL)
+ return NULL;
+
+ p->pp = xicp;
+ p->plu = plu;
+ p->del = icxLuMono_free;
+ p->lutspaces = icxLutSpaces;
+ p->spaces = icxLuSpaces;
+ p->get_native_ranges = icxLu_get_native_ranges;
+ p->get_ranges = icxLu_get_ranges;
+ p->efv_wh_bk_points = icxLuEfv_wh_bk_points;
+ p->get_gamut = icxLuMonoGamut;
+ p->fwd_relpcs_outpcs = icxLuMono_fwd_relpcs_outpcs;
+ p->bwd_outpcs_relpcs = icxLuMono_bwd_outpcs_relpcs;
+ p->nearclip = 0; /* Set flag defaults */
+ p->mergeclut = 0;
+ p->noisluts = 0;
+ p->noipluts = 0;
+ p->nooluts = 0;
+ p->intsep = 0;
+
+ p->fwd_lookup = icxLuMonoFwd_lookup;
+ p->fwd_curve = icxLuMonoFwd_curve;
+ p->fwd_map = icxLuMonoFwd_map;
+ p->fwd_abs = icxLuMonoFwd_abs;
+ p->bwd_lookup = icxLuMonoBwd_lookup;
+ p->bwd_abs = icxLuMonoFwd_abs;
+ p->bwd_map = icxLuMonoFwd_map;
+ p->bwd_curve = icxLuMonoFwd_curve;
+ if (dir) {
+ p->lookup = icxLuMonoBwd_lookup;
+ p->inv_lookup = icxLuMonoFwd_lookup;
+ } else {
+ p->lookup = icxLuMonoFwd_lookup;
+ p->inv_lookup = icxLuMonoBwd_lookup;
+ }
+
+ /* There are no mono specific flags */
+ p->flags = flags;
+ p->func = func;
+
+ /* Get details of internal, native color space */
+ plu->lutspaces(p->plu, &p->natis, NULL, &p->natos, NULL, &p->natpcs);
+
+ /* Get other details of conversion */
+ p->plu->spaces(p->plu, NULL, &p->inputChan, NULL, &p->outputChan, NULL, NULL, NULL, NULL, NULL);
+
+ /* Init the CAM model */
+ if (pcsor == icxSigJabData) {
+ p->vc = *vc; /* Copy the structure */
+ p->cam = new_icxcam(cam_default);
+ p->cam->set_view(p->cam, vc->Ev, vc->Wxyz, vc->La, vc->Yb, vc->Lv, vc->Yf, vc->Fxyz,
+ XICC_USE_HK);
+ } else
+ p->cam = NULL;
+
+ /* Remember the effective intent */
+ p->intent = intent;
+
+ /* Get the effective spaces */
+ plu->spaces(plu, &p->ins, NULL, &p->outs, NULL, NULL, NULL, NULL, &p->pcs, NULL);
+
+ /* Override with pcsor */
+ if (pcsor == icxSigJabData) {
+ p->pcs = pcsor;
+ if (func == icmBwd || func == icmGamut || func == icmPreview)
+ p->ins = pcsor;
+ if (func == icmFwd || func == icmPreview)
+ p->outs = pcsor;
+ }
+
+ /* In general the native and effective ranges of the icx will be the same as the */
+ /* underlying icm lookup object. */
+ p->plu->get_lutranges(p->plu, p->ninmin, p->ninmax, p->noutmin, p->noutmax);
+ p->plu->get_ranges(p->plu, p->inmin, p->inmax, p->outmin, p->outmax);
+
+ /* If we have a Jab PCS override, reflect this in the effective icx range. */
+ /* Note that the ab ranges are nominal. They will exceed this range */
+ /* for colors representable in L*a*b* PCS */
+ if (p->ins == icxSigJabData) {
+ p->inmin[0] = 0.0; p->inmax[0] = 100.0;
+ p->inmin[1] = -128.0; p->inmax[1] = 128.0;
+ p->inmin[2] = -128.0; p->inmax[2] = 128.0;
+ } else if (p->outs == icxSigJabData) {
+ p->outmin[0] = 0.0; p->outmax[0] = 100.0;
+ p->outmin[1] = -128.0; p->outmax[1] = 128.0;
+ p->outmin[2] = -128.0; p->outmax[2] = 128.0;
+ }
+
+ return (icxLuBase *)p;
+}
+
+/* ============================================================= */
+
+/* Given an xicc lookup object, returm a gamut object. */
+/* Note that the PCS must be Lab or Jab */
+/* Return NULL on error, check errc+err for reason */
+static gamut *icxLuMonoGamut(
+icxLuBase *plu, /* this */
+double detail /* gamut detail level, 0.0 = def */
+) {
+ gamut *xgam;
+ xicc *p = plu->pp; /* parent xicc */
+
+ p->errc = 1;
+ sprintf(p->err,"Creating Mono gamut surface not supported yet.");
+ plu->del(plu);
+ xgam = NULL;
+
+ return xgam;
+}
+
diff --git a/xicc/xspect.c b/xicc/xspect.c
new file mode 100644
index 0000000..a372d60
--- /dev/null
+++ b/xicc/xspect.c
@@ -0,0 +1,4714 @@
+
+/*
+ * International Color Consortium color transform expanded support
+ *
+ * Author: Graeme W. Gill
+ * Date: 21/6/01
+ * Version: 1.00
+ *
+ * Copyright 2000 - 2006 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ *
+ * Based on the old iccXfm class.
+ */
+
+/*
+ * This module supports converting spectral samples
+ * into CIE XYZ (1.0) or D50 Lab tristimulous values.
+ */
+
+/*
+ * TTBD:
+ *
+ * If needed by ISO 13655-1009:
+ * fwa_convert() function takes two illuminants:
+ * first one is the measurement illumination to correct to,
+ * the second is the assumed illumination spectrum for XYZ conversion.
+ * so we compute the spectral reflectance as if the instrument had
+ * one sort of practical illuminant (and taking into account FWA),
+ * and then convert to D50 equivalent.
+ * Need to bypass FWA if inst illum == simulated inst. illum.
+ * Need to modify tools to allow optional param to -f which is
+ * the simulated instrument illum, then make -i have -M0, -M1, -M2 options.
+ *
+ * [Does this make any sense though ? That is what's happening
+ * for a standard A illuminant instrument emitting D50 XYZ values,
+ * but doesn't represent actually viewing under a (say) M2 illuminant.
+ * But is M0 actual A illuminant, or notional D50 measured by an A illuminant ?]
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+#include <math.h>
+#ifndef SALONEINSTLIB
+# include "numlib.h"
+# include "cgats.h"
+# include "plot.h" /* For debugging */
+#else
+# include "numsup.h"
+#endif
+#include "xspect.h"
+
+#define CLAMP_XYZ /* [def] Clamp XYZ to be >= 0.0 */
+
+#ifndef SALONEINSTLIB
+
+#undef STOCKFWA /* [und] Use table shape else compute from flat line estimate*/
+
+#undef DEBUG /* [und] Extra printouts + debugging messages */
+#undef DOPLOT /* [und] Plot FWA setup */
+#undef DOPLOT_ALL_FWA /* [und] Plot all FWA corrected conversions */
+#undef WRITE_FWA1_STIM /* [und] Write file "fwa1_stip.sp" when FWA is setup */
+
+#endif /* !SALONEINSTLIB */
+
+#ifndef CLAMP_XYZ
+# pragma message("###### CLAMP_XYZ is not defined ######")
+#endif
+
+#if defined(DEBUG) || defined(DOPLOT) || defined(DOPLOT_ALL_FWA) || defined(WRITE_FWA1_STIM)
+# pragma message("###### xspect debugging is on ######")
+#endif
+
+#ifdef DEBUG
+# define DBG(xx) a1logd(g_log, 0, xx )
+# define DBGA g_log, 0 /* First argument to DBGF() */
+# define DBGF(xx) a1logd xx
+#else
+# define DBG(xx)
+# define DBGF(xx)
+#endif
+
+/* ======================================================== */
+#if defined(__APPLE__) && defined(__POWERPC__)
+
+/* Workaround for a PPC gcc 3.3 optimiser bug... */
+/* It seems to cause a segmentation fault instead of */
+/* converting an integer loop index into a float, */
+/* when there are sufficient variables in play. */
+static int gcc_bug_fix(int i) {
+ static int nn;
+ nn += i;
+ return nn;
+}
+#endif /* APPLE */
+
+/* ======================================================== */
+/* Define various standard spectra */
+
+/* ------------------ */
+/* Illuminant spectra */
+
+/* Dummy "no illuminant" illuminant spectra used to signal an emmission */
+/* or equal energy 'E' illuminant */
+static xspect il_none = {
+ 54, 300.0, 830.0, /* 54 bands from 300 to 830 in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
+ }
+};
+
+
+/* CIE 15.2-1986 Table 1.1 */
+/* Part 1: CIE Standard Illuminant A relative spectral power distribution */
+/* This is a 2848K tungsten filament lamp (Acording to the old temperature scale) */
+/* and 2856 according to the newer temerature scale. */
+static xspect il_A = {
+ 107, 300.0, 830.0, /* 107 bands from 300 to 830 nm in 5nm steps */
+ 100.0, /* Arbitrary scale factor */
+ {
+ 0.930483, 1.128210, 1.357690, 1.622190, 1.925080,
+ 2.269800, 2.659810, 3.098610, 3.589680, 4.136480,
+ 4.742380, 5.410700, 6.144620, 6.947200, 7.821350,
+ 8.769800, 9.795100, 10.899600, 12.085300, 13.354300,
+ 14.708000, 16.148000, 17.675300, 19.290700, 20.995000,
+ 22.788300, 24.670900, 26.642500, 28.702700, 30.850800,
+ 33.085900, 35.406800, 37.812100, 40.300200, 42.869300,
+ 45.517400, 48.242300, 51.041800, 53.913200, 56.853900,
+ 59.861100, 62.932000, 66.063500, 69.252500, 72.495900,
+ 75.790300, 79.132600, 82.519300, 85.947000, 89.412400,
+ 92.912000, 96.442300, 100.000000, 103.582000, 107.184000,
+ 110.803000, 114.436000, 118.080000, 121.731000, 125.386000,
+ 129.043000, 132.697000, 136.346000, 139.988000, 143.618000,
+ 147.235000, 150.836000, 154.418000, 157.979000, 161.516000,
+ 165.028000, 168.510000, 171.963000, 175.383000, 178.769000,
+ 182.118000, 185.429000, 188.701000, 191.931000, 195.118000,
+ 198.261000, 201.359000, 204.409000, 207.411000, 210.365000,
+ 213.268000, 216.120000, 218.920000, 221.667000, 224.361000,
+ 227.000000, 229.585000, 232.115000, 234.589000, 237.008000,
+ 239.370000, 241.675000, 243.924000, 246.116000, 248.251000,
+ 250.329000, 252.350000, 254.314000, 256.221000, 258.071000,
+ 259.865000, 261.602000
+ }
+};
+
+/* CIE 15.2-1986 Table 1.1 */
+/* Part 1: CIE Standard Illuminant C relative spectral power distribution */
+/* This is a CIE Illuminant A combined with a filter to simulate daylight. */
+static xspect il_C = {
+ 93, 320.0, 780.0, /* 107 bands from 300 to 830 nm in 5nm steps */
+ 100.0, /* Arbitrary factor */
+ {
+ 0.01, 0.20, 0.40, 1.55, 2.70, 4.85, 7.00, 9.95, 12.90, 17.20,
+ 21.40, 27.50, 33.00, 39.92, 47.40, 55.17, 63.30, 71.81, 80.60, 89.53,
+ 98.10, 105.80, 112.40, 117.75, 121.50, 123.45, 124.00, 123.60, 123.10, 123.30,
+ 123.80, 124.09, 123.90, 122.92, 120.70, 116.90, 112.10, 106.98, 102.30, 98.81,
+ 96.90, 96.78, 98.00, 99.94, 102.10, 103.95, 105.20, 105.67, 105.30, 104.11,
+ 102.30, 100.15, 97.80, 95.43, 93.20, 91.22, 89.70, 88.83, 88.40, 88.19,
+ 88.10, 88.06, 88.00, 87.86, 87.80, 87.99, 88.20, 88.20, 87.90, 87.22,
+ 86.30, 85.30, 84.00, 82.21, 80.20, 78.24, 76.30, 74.36, 72.40, 70.40,
+ 68.30, 66.30, 64.40, 62.80, 61.50, 60.20, 59.20, 58.50, 58.10, 58.00,
+ 58.20, 58.50, 59.10
+ }
+};
+
+/* D50 illuminant spectra */
+static xspect il_D50 = {
+ 107, 300.0, 830.0, /* 107 bands from 300 to 830 nm in 5nm steps */
+ 100.0, /* Arbitrary factor */
+ {
+ 0.02, 1.03, 2.05, 4.91, 7.78, 11.26, 14.75, 16.35, 17.95, 19.48,
+ 21.01, 22.48, 23.94, 25.45, 26.96, 25.72, 24.49, 27.18, 29.87, 39.59,
+ 49.31, 52.91, 56.51, 58.27, 60.03, 58.93, 57.82, 66.32, 74.82, 81.04,
+ 87.25, 88.93, 90.61, 90.99, 91.37, 93.24, 95.11, 93.54, 91.96, 93.84,
+ 95.72, 96.17, 96.61, 96.87, 97.13, 99.61, 102.10, 101.43, 100.75, 101.54,
+ 102.32, 101.16, 100.00, 98.87, 97.74, 98.33, 98.92, 96.21, 93.50, 95.59,
+ 97.69, 98.48, 99.27, 99.16, 99.04, 97.38, 95.72, 97.29, 98.86, 97.26,
+ 95.67, 96.93, 98.19, 100.60, 103.00, 101.07, 99.13, 93.26, 87.38, 89.49,
+ 91.60, 92.25, 92.89, 84.87, 76.85, 81.68, 86.51, 89.55, 92.58, 85.40,
+ 78.23, 67.96, 57.69, 70.31, 82.92, 80.60, 78.27, 78.91, 79.55, 76.48,
+ 73.40, 68.66, 63.92, 67.35, 70.78, 72.61, 74.44
+ }
+};
+
+/* D50M2 illuminant spectra, UV filtered */
+/* Computed from il_D50 */
+static xspect il_D50M2 = {
+ 0, 0.0, 0.0,
+ 0.0
+};
+
+
+/* CIE 15.2-1986 Table 1.1 */
+/* Part 2: CIE Standard Illuminant D65 relative spectral power distribution */
+static xspect il_D65 = {
+ 107, 300.0, 830.0, /* 107 bands from 300 to 830 nm in 5nm steps */
+ 100.0, /* Arbitrary factor */
+ {
+ 0.03410, 1.66430, 3.29450, 11.76520, 20.23600,
+ 28.64470, 37.05350, 38.50110, 39.94880, 42.43020,
+ 44.91170, 45.77500, 46.63830, 49.36370, 52.08910,
+ 51.03230, 49.97550, 52.31180, 54.64820, 68.70150,
+ 82.75490, 87.12040, 91.48600, 92.45890, 93.43180,
+ 90.05700, 86.68230, 95.77360, 104.86500, 110.93600,
+ 117.00800, 117.41000, 117.81200, 116.33600, 114.86100,
+ 115.39200, 115.92300, 112.36700, 108.81100, 109.08200,
+ 109.35400, 108.57800, 107.80200, 106.29600, 104.79000,
+ 106.23900, 107.68900, 106.04700, 104.40500, 104.22500,
+ 104.04600, 102.02300, 100.00000, 98.16710, 96.33420,
+ 96.06110, 95.78800, 92.23680, 88.68560, 89.34590,
+ 90.00620, 89.80260, 89.59910, 88.64890, 87.69870,
+ 85.49360, 83.28860, 83.49390, 83.69920, 81.86300,
+ 80.02680, 80.12070, 80.21460, 81.24620, 82.27780,
+ 80.28100, 78.28420, 74.00270, 69.72130, 70.66520,
+ 71.60910, 72.97900, 74.34900, 67.97650, 61.60400,
+ 65.74480, 69.88560, 72.48630, 75.08700, 69.33980,
+ 63.59270, 55.00540, 46.41820, 56.61180, 66.80540,
+ 65.09410, 63.38280, 63.84340, 64.30400, 61.87790,
+ 59.45190, 55.70540, 51.95900, 54.69980, 57.44060,
+ 58.87650, 60.31250
+ }
+};
+
+#ifndef SALONEINSTLIB
+/* General temperature Daylight spectra (Using CIE 1960 u,v CCT) */
+/* Fill in the given xspect with the specified daylight illuminant */
+/* Return nz if temperature is out of range */
+static int daylight_il(xspect *sp, double ct) {
+ static double s0[107] = {
+ 0.04, 3.02, 6.00, 17.80, 29.60, 42.45, 55.30, 56.30, 57.30, 59.55,
+ 61.80, 61.65, 61.50, 65.15, 68.80, 66.10, 63.40, 64.60, 65.80, 80.30,
+ 94.80, 99.80, 104.80, 105.35, 105.90, 101.35, 96.80, 105.35, 113.90, 119.75,
+ 125.60, 125.55, 125.50, 123.40, 121.30, 121.30, 121.30, 117.40, 113.50, 113.30,
+ 113.10, 111.95, 110.80, 108.65, 106.50, 107.65, 108.80, 107.05, 105.30, 104.85,
+ 104.40, 102.20, 100.00, 98.00, 96.00, 95.55, 95.10, 92.10, 89.10, 89.80,
+ 90.50, 90.40, 90.30, 89.35, 88.40, 86.20, 84.00, 84.55, 85.10, 83.50,
+ 81.90, 82.25, 82.60, 83.75, 84.90, 83.10, 81.30, 76.60, 71.90, 73.10,
+ 74.30, 75.35, 76.40, 69.85, 63.30, 67.50, 71.70, 74.35, 77.00, 71.10,
+ 65.20, 56.45, 47.70, 58.15, 68.60, 66.80, 65.00, 65.50, 66.00, 63.50,
+ 61.00, 57.15, 53.30, 56.10, 58.90, 60.40, 61.90
+ };
+ static double s1[107] = {
+ 0.02, 2.26, 4.50, 13.45, 22.40, 32.20, 42.00, 41.30, 40.60, 41.10,
+ 41.60, 39.80, 38.00, 40.20, 42.40, 40.45, 38.50, 36.75, 35.00, 39.20,
+ 43.40, 44.85, 46.30, 45.10, 43.90, 40.50, 37.10, 36.90, 36.70, 36.30,
+ 35.90, 34.25, 32.60, 30.25, 27.90, 26.10, 24.30, 22.20, 20.10, 18.15,
+ 16.20, 14.70, 13.20, 10.90, 8.60, 7.35, 6.10, 5.15, 4.20, 3.05,
+ 1.90, 0.95, 0.00, -0.80, -1.60, -2.55, -3.50, -3.50, -3.50, -4.65,
+ -5.80, -6.50, -7.20, -7.90, -8.60, -9.05, -9.50, -10.20, -10.90, -10.80,
+ -10.70, -11.35, -12.00, -13.00, -14.00, -13.80, -13.60, -12.80, -12.00, -12.65,
+ -13.30, -13.10, -12.90, -11.75, -10.60, -11.10, -11.60, -11.90, -12.20, -11.20,
+ -10.20, -9.00, -7.80, -9.50, -11.20, -10.80, -10.40, -10.50, -10.60, -10.15,
+ -9.70, -9.00, -8.30, -8.80, -9.30, -9.55, -9.80
+ };
+ static double s2[107] = {
+ 0.00, 1.00, 2.00, 3.00, 4.00, 6.25, 8.50, 8.15, 7.80, 7.25,
+ 6.70, 6.00, 5.30, 5.70, 6.10, 4.55, 3.00, 2.10, 1.20, 0.05,
+ -1.10, -0.80, -0.50, -0.60, -0.70, -0.95, -1.20, -1.90, -2.60, -2.75,
+ -2.90, -2.85, -2.80, -2.70, -2.60, -2.60, -2.60, -2.20, -1.80, -1.65,
+ -1.50, -1.40, -1.30, -1.25, -1.20, -1.10, -1.00, -0.75, -0.50, -0.40,
+ -0.30, -0.15, 0.00, 0.10, 0.20, 0.35, 0.50, 1.30, 2.10, 2.65,
+ 3.20, 3.65, 4.10, 4.40, 4.70, 4.90, 5.10, 5.90, 6.70, 7.00,
+ 7.30, 7.95, 8.60, 9.20, 9.80, 10.00, 10.20, 9.25, 8.30, 8.95,
+ 9.60, 9.05, 8.50, 7.75, 7.00, 7.30, 7.60, 7.80, 8.00, 7.35,
+ 6.70, 5.95, 5.20, 6.30, 7.40, 7.10, 6.80, 6.90, 7.00, 6.70,
+ 6.40, 5.95, 5.50, 5.80, 6.10, 6.30, 6.50
+ };
+ int i;
+ double xd, yd;
+ double m1, m2;
+
+ if (ct < 1000.0 || ct > 35000.0) /* Actually, accuracy is guaranteed from only 4000 - 25000 */
+ return 1;
+
+ /* Compute chromaticity coordinates */
+ if (ct < 7000.0) {
+ xd = -4.6070e9/(ct * ct * ct) + 2.9678e6/(ct * ct) + 0.09911e3/ct + 0.244063;
+ } else {
+ xd = -2.0064e9/(ct * ct * ct) + 1.9018e6/(ct * ct) + 0.24748e3/ct + 0.237040;
+ }
+ yd = -3.000 * xd * xd + 2.870 * xd - 0.275;
+
+ /* Compute m factors */
+ m1 = (-1.3515 - 1.7703 * xd + 5.9114 * yd)/(0.0241 + 0.2562 * xd - 0.7341 * yd);
+ m2 = (0.0300 - 31.4424 * xd + 30.0717 * yd)/(0.0241 + 0.2562 * xd - 0.7341 * yd);
+
+ /* Compute spectral values */
+ for (i = 0; i < 107; i++) {
+ sp->spec[i] = s0[i] + m1 * s1[i] + m2 * s2[i];
+ }
+ sp->spec_n = 107;
+ sp->spec_wl_short = 300.0;
+ sp->spec_wl_long = 830;
+ sp->norm = 100.0; /* Arbitrary */
+
+ return 0;
+}
+
+/* General temperature Planckian (black body) spectra */
+/* Fill in the given xspect with the specified Planckian illuminant */
+/* Return nz if temperature is out of range */
+static int planckian_il(xspect *sp, double ct) {
+ int i;
+ double wl, norm;
+
+ if (ct < 1.0 || ct > 1e6) /* set some arbitrary limits */
+ return 1;
+
+ /* Set out targets */
+// sp->spec_n = 107; /* 5nm */
+ sp->spec_n = 531; /* 1nm */
+ sp->spec_wl_short = 300.0;
+ sp->spec_wl_long = 830;
+
+ /* Compute spectral values using Plank's radiation law: */
+ /* Normalise numbers by energy at 560 nm */
+ wl = 1e-9 * 560;
+ norm = 0.01 * (3.74183e-16 * pow(wl, -5.0)) / (exp(1.4388e-2 / (wl * ct)) - 1.0);
+ for (i = 0; i < sp->spec_n; i++) {
+ wl = 1e-9 * XSPECT_XWL(sp, i); /* Wavelength in meters */
+ sp->spec[i] = (3.74183e-16 * pow(wl, -5.0)) / (exp(1.4388e-2 / (wl * ct)) - 1.0);
+ sp->spec[i] /= norm;
+
+ }
+ sp->norm = 100.0; /* Arbitrary */
+
+ return 0;
+}
+
+/* CIE F5 */
+/* Fluorescent, Standard, 6350K, CRI 72 */
+static xspect il_F5 = {
+ 107, 300.0, 830.0, /* 109 bands from 300 to 830 nm in 5nm steps */
+ 20.0, /* Arbitrary scale factor */
+ {
+/* 300 */ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+/* 340 */ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+/* 380 */ 1.87, 2.35, 2.92, 3.45, 5.10, 18.91, 6.00, 6.11, 6.85, 7.58,
+/* 430 */ 8.31, 40.76, 16.06, 10.32, 10.91, 11.40, 11.83, 12.17, 12.40, 12.54,
+/* 480 */ 12.58, 12.52, 12.47, 12.20, 11.89, 11.61, 11.33, 11.10, 10.96, 10.97,
+/* 530 */ 11.16, 11.54, 12.12, 27.78, 17.73, 14.47, 15.20, 15.77, 16.10, 18.54,
+/* 580 */ 19.50, 15.39, 14.64, 13.72, 12.69, 11.57, 10.45, 9.35, 8.29, 7.32,
+/* 630 */ 6.41, 5.63, 4.90, 4.26, 3.72, 3.25, 2.83, 2.49, 2.19, 1.93,
+/* 680 */ 1.71, 1.52, 1.48, 1.26, 1.13, 1.05, 0.96, 0.85, 0.78, 0.72,
+/* 730 */ 0.68, 0.67, 0.65, 0.61, 0.62, 0.59, 0.62, 0.64, 0.55, 0.47,
+/* 780 */ 0.40,
+/* 785 */ 0.0, 0.0, 0.0, 0.0, 0.0,
+/* 810 */ 0.0, 0.0, 0.0, 0.0, 0.0
+ }
+};
+
+
+/* CIE F8 */
+/* Fluorescent, Wide band 5000K, CRI 95 */
+static xspect il_F8 = {
+ 107, 300.0, 830.0, /* 109 bands from 300 to 830 nm in 5nm steps */
+ 20.0, /* Arbitrary scale factor */
+ {
+/* 300 */ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+/* 340 */ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+/* 380 */ 1.21, 1.5, 1.81, 2.13, 3.17, 13.08, 3.83, 3.45, 3.86, 4.42,
+/* 430 */ 5.09, 34.10, 12.42, 7.68, 8.6, 9.46, 10.24, 10.84, 11.33, 11.71,
+/* 480 */ 11.98, 12.17, 12.28, 12.32, 12.35, 12.44, 12.55, 12.68, 12.77, 12.72,
+/* 530 */ 12.60, 12.43, 12.22, 28.96, 16.51, 11.79, 11.76, 11.77, 11.84, 14.61,
+/* 580 */ 16.11, 12.34, 12.53, 12.72, 12.92, 13.12, 13.34, 13.61, 13.87, 14.07,
+/* 630 */ 14.20, 14.16, 14.13, 14.34, 14.50, 14.46, 14.00, 12.58, 10.99, 9.98,
+/* 680 */ 9.22, 8.62, 8.07, 7.39, 6.71, 6.16, 5.63, 5.03, 4.46, 4.02,
+/* 730 */ 3.66, 3.36, 3.09, 2.85, 2.65, 2.51, 2.37, 2.15, 1.89, 1.61,
+/* 780 */ 1.32,
+/* 785 */ 0.0, 0.0, 0.0, 0.0, 0.0,
+/* 810 */ 0.0, 0.0, 0.0, 0.0, 0.0
+ }
+};
+
+
+
+/* CIE F10 */
+/* Fluorescent, Narrow band 5000K, CRI 81 */
+static xspect il_F10 = {
+ 107, 300.0, 830.0, /* 109 bands from 300 to 830 nm in 5nm steps */
+ 20.0, /* Arbitrary scale factor */
+ {
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+ 1.11, 0.80, 0.62, 0.57, 1.48, 12.16, 2.12, 2.70, 3.74, 5.14,
+ 6.75, 34.39, 14.86, 10.40, 10.76, 10.67, 10.11, 9.27, 8.29, 7.29,
+ 7.91, 16.64, 16.73, 10.44, 5.94, 3.34, 2.35, 1.88, 1.59, 1.47,
+ 1.80, 5.71, 40.98, 73.69, 33.61, 8.24, 3.38, 2.47, 2.14, 4.86,
+ 11.45, 14.79, 12.16, 8.97, 6.53, 8.31, 44.12, 34.55, 12.09, 12.15,
+ 10.52, 4.43, 1.95, 2.19, 3.19, 2.77, 2.29, 2.00, 1.52, 1.35,
+ 1.47, 1.79, 1.74, 1.02, 1.14, 3.32, 4.49, 2.05, 0.49, 0.24,
+ 0.21, 0.21, 0.24, 0.24, 0.21, 0.17, 0.21, 0.22, 0.17, 0.12,
+ 0.09,
+ 0.0, 0.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0
+ }
+};
+
+/* Spectrocam Xenon Lamp */
+static xspect il_Spectrocam = {
+ 95, 325.0, 795.0, /* 95 bands from 325 to 795 nm in 5nm steps */
+ 1.0, /* Arbitrary scale factor */
+ {
+ 0.220794, 0.240550, 0.281212, 0.363042, 0.493282,
+ 0.582279, 0.657489, 0.715563, 0.797559, 0.916343,
+ 1.066625, 1.228461, 1.298467, 1.373143, 1.457366,
+ 1.496117, 1.509290, 1.573544, 1.596359, 1.495740,
+ 1.477898, 1.521371, 1.479780, 1.453196, 1.532119,
+ 1.548128, 1.503433, 1.428481, 1.357290, 1.354425,
+ 1.317263, 1.237048, 1.169737, 1.109248, 1.085784,
+ 1.080186, 1.104001, 1.131713, 1.161153, 1.158589,
+ 1.148998, 1.123934, 1.077395, 1.017907, 1.026532,
+ 1.045921, 1.083780, 1.081868, 1.048489, 1.021549,
+ 0.993572, 0.956559, 0.942657, 0.952544, 0.957087,
+ 0.958472, 0.945666, 0.923988, 0.890418, 0.852044,
+ 0.812935, 0.792055, 0.791141, 0.825459, 0.829230,
+ 0.818171, 0.851752, 0.913113, 1.038844, 1.116913,
+ 1.164211, 1.133376, 1.109062, 1.129427, 1.086885,
+ 0.991213, 0.924226, 0.875499, 0.894231, 0.922219,
+ 0.960372, 0.896142, 0.819477, 0.879305, 0.912777,
+ 0.908489, 0.775942, 0.598118, 0.532988, 0.484102,
+ 0.465986, 0.414848, 0.346473, 0.324622, 0.309978
+ }
+};
+
+#endif /* !SALONEINSTLIB */
+
+/* Apply ISO 13655:2009 UV filter to the given spectrum. */
+/* The filter is applied point by point. */
+static void uv_filter(xspect *dst, xspect *src) {
+ int i;
+
+ XSPECT_COPY_INFO(dst, src);
+ for (i = 0; i < src->spec_n; i++) {
+ double wl = XSPECT_XWL(src, i);
+ double ff = 1.0;
+
+ if (wl <= 395.0) {
+ ff = 0.0;
+ } else if (wl < 425.0) {
+ ff = (wl - 395.0)/(425.0 - 395.0);
+ ff = ff * ff * (3.0 - 2.0 * ff); /* Cubic spline */
+ }
+ dst->spec[i] = ff * src->spec[i];
+ }
+}
+
+/* Fill in an xpsect with a standard illuminant spectrum */
+/* return 0 on sucecss, nz if not matched */
+int standardIlluminant(
+xspect *sp, /* Xspect to fill in */
+icxIllumeType ilType, /* Type of illuminant */
+double temp /* Optional temperature in degrees kelvin, for Dtemp and Ptemp */
+) {
+ switch (ilType) {
+ case icxIT_none:
+ return 1;
+ case icxIT_custom:
+ return 1;
+ case icxIT_A:
+ *sp = il_A; /* Struct copy */
+ return 0;
+ case icxIT_C:
+ *sp = il_C; /* " */
+ return 0;
+ case icxIT_default:
+ case icxIT_D50:
+ *sp = il_D50; /* etc */
+ return 0;
+ case icxIT_D50M2:
+ if (il_D50M2.spec_n == 0)
+ uv_filter(&il_D50M2, &il_D50);
+ *sp = il_D50M2;
+ return 0;
+ case icxIT_D65:
+ *sp = il_D65;
+ return 0;
+ case icxIT_E:
+ *sp = il_none;
+ return 0;
+#ifndef SALONEINSTLIB
+ case icxIT_F5:
+ *sp = il_F5;
+ return 0;
+ case icxIT_F8:
+ *sp = il_F8;
+ return 0;
+ case icxIT_F10:
+ *sp = il_F10;
+ return 0;
+ case icxIT_Spectrocam:
+ *sp = il_Spectrocam;
+ return 0;
+ case icxIT_Dtemp:
+ return daylight_il(sp, temp);
+ case icxIT_Ptemp:
+ return planckian_il(sp, temp);
+#endif
+ }
+ return 1;
+}
+
+/* ------------- */
+
+/* Spectral locus poligon cache */
+typedef struct {
+ int n; /* Number of spectral vertexes, 0 if uninit */
+ double xmin, xmax, ymin, ymax; /* Boundint box */
+ double tx[3], ty[3]; /* Fast inner triangle test, RGB */
+ double be[3][3]; /* baricentric equations of triangle */
+// double eed[3]; /* Distance of triangle points to 0.3, 0.3 */
+ double x[XSPECT_MAX_BANDS]; /* x value of vertex */
+ double y[XSPECT_MAX_BANDS]; /* y value of vertex */
+} xslpoly;
+
+/* ------------- */
+/* Observer Data and locus poligon cache */
+
+/* Standard CIE 1931 2 degree */
+static xspect ob_CIE_1931_2[3] = {
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000129900000, 0.000145847000, 0.000163802100, 0.000184003700, 0.000206690200,
+ 0.000232100000, 0.000260728000, 0.000293075000, 0.000329388000, 0.000369914000,
+ 0.000414900000, 0.000464158700, 0.000518986000, 0.000581854000, 0.000655234700,
+ 0.000741600000, 0.000845029600, 0.000964526800, 0.001094949000, 0.001231154000,
+ 0.001368000000, 0.001502050000, 0.001642328000, 0.001802382000, 0.001995757000,
+ 0.002236000000, 0.002535385000, 0.002892603000, 0.003300829000, 0.003753236000,
+ 0.004243000000, 0.004762389000, 0.005330048000, 0.005978712000, 0.006741117000,
+ 0.007650000000, 0.008751373000, 0.010028880000, 0.011421700000, 0.012869010000,
+ 0.014310000000, 0.015704430000, 0.017147440000, 0.018781220000, 0.020748010000,
+ 0.023190000000, 0.026207360000, 0.029782480000, 0.033880920000, 0.038468240000,
+ 0.043510000000, 0.048995600000, 0.055022600000, 0.061718800000, 0.069212000000,
+ 0.077630000000, 0.086958110000, 0.097176720000, 0.108406300000, 0.120767200000,
+ 0.134380000000, 0.149358200000, 0.165395700000, 0.181983100000, 0.198611000000,
+ 0.214770000000, 0.230186800000, 0.244879700000, 0.258777300000, 0.271807900000,
+ 0.283900000000, 0.294943800000, 0.304896500000, 0.313787300000, 0.321645400000,
+ 0.328500000000, 0.334351300000, 0.339210100000, 0.343121300000, 0.346129600000,
+ 0.348280000000, 0.349599900000, 0.350147400000, 0.350013000000, 0.349287000000,
+ 0.348060000000, 0.346373300000, 0.344262400000, 0.341808800000, 0.339094100000,
+ 0.336200000000, 0.333197700000, 0.330041100000, 0.326635700000, 0.322886800000,
+ 0.318700000000, 0.314025100000, 0.308884000000, 0.303290400000, 0.297257900000,
+ 0.290800000000, 0.283970100000, 0.276721400000, 0.268917800000, 0.260422700000,
+ 0.251100000000, 0.240847500000, 0.229851200000, 0.218407200000, 0.206811500000,
+ 0.195360000000, 0.184213600000, 0.173327300000, 0.162688100000, 0.152283300000,
+ 0.142100000000, 0.132178600000, 0.122569600000, 0.113275200000, 0.104297900000,
+ 0.095640000000, 0.087299550000, 0.079308040000, 0.071717760000, 0.064580990000,
+ 0.057950010000, 0.051862110000, 0.046281520000, 0.041150880000, 0.036412830000,
+ 0.032010000000, 0.027917200000, 0.024144400000, 0.020687000000, 0.017540400000,
+ 0.014700000000, 0.012161790000, 0.009919960000, 0.007967240000, 0.006296346000,
+ 0.004900000000, 0.003777173000, 0.002945320000, 0.002424880000, 0.002236293000,
+ 0.002400000000, 0.002925520000, 0.003836560000, 0.005174840000, 0.006982080000,
+ 0.009300000000, 0.012149490000, 0.015535880000, 0.019477520000, 0.023992770000,
+ 0.029100000000, 0.034814850000, 0.041120160000, 0.047985040000, 0.055378610000,
+ 0.063270000000, 0.071635010000, 0.080462240000, 0.089739960000, 0.099456450000,
+ 0.109600000000, 0.120167400000, 0.131114500000, 0.142367900000, 0.153854200000,
+ 0.165500000000, 0.177257100000, 0.189140000000, 0.201169400000, 0.213365800000,
+ 0.225749900000, 0.238320900000, 0.251066800000, 0.263992200000, 0.277101700000,
+ 0.290400000000, 0.303891200000, 0.317572600000, 0.331438400000, 0.345482800000,
+ 0.359700000000, 0.374083900000, 0.388639600000, 0.403378400000, 0.418311500000,
+ 0.433449900000, 0.448795300000, 0.464336000000, 0.480064000000, 0.495971300000,
+ 0.512050100000, 0.528295900000, 0.544691600000, 0.561209400000, 0.577821500000,
+ 0.594500000000, 0.611220900000, 0.627975800000, 0.644760200000, 0.661569700000,
+ 0.678400000000, 0.695239200000, 0.712058600000, 0.728828400000, 0.745518800000,
+ 0.762100000000, 0.778543200000, 0.794825600000, 0.810926400000, 0.826824800000,
+ 0.842500000000, 0.857932500000, 0.873081600000, 0.887894400000, 0.902318100000,
+ 0.916300000000, 0.929799500000, 0.942798400000, 0.955277600000, 0.967217900000,
+ 0.978600000000, 0.989385600000, 0.999548800000, 1.009089200000, 1.018006400000,
+ 1.026300000000, 1.033982700000, 1.040986000000, 1.047188000000, 1.052466700000,
+ 1.056700000000, 1.059794400000, 1.061799200000, 1.062806800000, 1.062909600000,
+ 1.062200000000, 1.060735200000, 1.058443600000, 1.055224400000, 1.050976800000,
+ 1.045600000000, 1.039036900000, 1.031360800000, 1.022666200000, 1.013047700000,
+ 1.002600000000, 0.991367500000, 0.979331400000, 0.966491600000, 0.952847900000,
+ 0.938400000000, 0.923194000000, 0.907244000000, 0.890502000000, 0.872920000000,
+ 0.854449900000, 0.835084000000, 0.814946000000, 0.794186000000, 0.772954000000,
+ 0.751400000000, 0.729583600000, 0.707588800000, 0.685602200000, 0.663810400000,
+ 0.642400000000, 0.621514900000, 0.601113800000, 0.581105200000, 0.561397700000,
+ 0.541900000000, 0.522599500000, 0.503546400000, 0.484743600000, 0.466193900000,
+ 0.447900000000, 0.429861300000, 0.412098000000, 0.394644000000, 0.377533300000,
+ 0.360800000000, 0.344456300000, 0.328516800000, 0.313019200000, 0.298001100000,
+ 0.283500000000, 0.269544800000, 0.256118400000, 0.243189600000, 0.230727200000,
+ 0.218700000000, 0.207097100000, 0.195923200000, 0.185170800000, 0.174832300000,
+ 0.164900000000, 0.155366700000, 0.146230000000, 0.137490000000, 0.129146700000,
+ 0.121200000000, 0.113639700000, 0.106465000000, 0.099690440000, 0.093330610000,
+ 0.087400000000, 0.081900960000, 0.076804280000, 0.072077120000, 0.067686640000,
+ 0.063600000000, 0.059806850000, 0.056282160000, 0.052971040000, 0.049818610000,
+ 0.046770000000, 0.043784050000, 0.040875360000, 0.038072640000, 0.035404610000,
+ 0.032900000000, 0.030564190000, 0.028380560000, 0.026344840000, 0.024452750000,
+ 0.022700000000, 0.021084290000, 0.019599880000, 0.018237320000, 0.016987170000,
+ 0.015840000000, 0.014790640000, 0.013831320000, 0.012948680000, 0.012129200000,
+ 0.011359160000, 0.010629350000, 0.009938846000, 0.009288422000, 0.008678854000,
+ 0.008110916000, 0.007582388000, 0.007088746000, 0.006627313000, 0.006195408000,
+ 0.005790346000, 0.005409826000, 0.005052583000, 0.004717512000, 0.004403507000,
+ 0.004109457000, 0.003833913000, 0.003575748000, 0.003334342000, 0.003109075000,
+ 0.002899327000, 0.002704348000, 0.002523020000, 0.002354168000, 0.002196616000,
+ 0.002049190000, 0.001910960000, 0.001781438000, 0.001660110000, 0.001546459000,
+ 0.001439971000, 0.001340042000, 0.001246275000, 0.001158471000, 0.001076430000,
+ 0.000999949300, 0.000928735800, 0.000862433200, 0.000800750300, 0.000743396000,
+ 0.000690078600, 0.000640515600, 0.000594502100, 0.000551864600, 0.000512429000,
+ 0.000476021300, 0.000442453600, 0.000411511700, 0.000382981400, 0.000356649100,
+ 0.000332301100, 0.000309758600, 0.000288887100, 0.000269539400, 0.000251568200,
+ 0.000234826100, 0.000219171000, 0.000204525800, 0.000190840500, 0.000178065400,
+ 0.000166150500, 0.000155023600, 0.000144621900, 0.000134909800, 0.000125852000,
+ 0.000117413000, 0.000109551500, 0.000102224500, 0.000095394450, 0.000089023900,
+ 0.000083075270, 0.000077512690, 0.000072313040, 0.000067457780, 0.000062928440,
+ 0.000058706520, 0.000054770280, 0.000051099180, 0.000047676540, 0.000044485670,
+ 0.000041509940, 0.000038733240, 0.000036142030, 0.000033723520, 0.000031464870,
+ 0.000029353260, 0.000027375730, 0.000025524330, 0.000023793760, 0.000022178700,
+ 0.000020673830, 0.000019272260, 0.000017966400, 0.000016749910, 0.000015616480,
+ 0.000014559770, 0.000013573870, 0.000012654360, 0.000011797230, 0.000010998440,
+ 0.000010253980, 0.000009559646, 0.000008912044, 0.000008308358, 0.000007745769,
+ 0.000007221456, 0.000006732475, 0.000006276423, 0.000005851304, 0.000005455118,
+ 0.000005085868, 0.000004741466, 0.000004420236, 0.000004120783, 0.000003841716,
+ 0.000003581652, 0.000003339127, 0.000003112949, 0.000002902121, 0.000002705645,
+ 0.000002522525, 0.000002351726, 0.000002192415, 0.000002043902, 0.000001905497,
+ 0.000001776509, 0.000001656215, 0.000001544022, 0.000001439440, 0.000001341977,
+ 0.000001251141
+ }
+ },
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000003917000, 0.000004393581, 0.000004929604, 0.000005532136, 0.000006208245,
+ 0.000006965000, 0.000007813219, 0.000008767336, 0.000009839844, 0.000011043230,
+ 0.000012390000, 0.000013886410, 0.000015557280, 0.000017442960, 0.000019583750,
+ 0.000022020000, 0.000024839650, 0.000028041260, 0.000031531040, 0.000035215210,
+ 0.000039000000, 0.000042826400, 0.000046914600, 0.000051589600, 0.000057176400,
+ 0.000064000000, 0.000072344210, 0.000082212240, 0.000093508160, 0.000106136100,
+ 0.000120000000, 0.000134984000, 0.000151492000, 0.000170208000, 0.000191816000,
+ 0.000217000000, 0.000246906700, 0.000281240000, 0.000318520000, 0.000357266700,
+ 0.000396000000, 0.000433714700, 0.000473024000, 0.000517876000, 0.000572218700,
+ 0.000640000000, 0.000724560000, 0.000825500000, 0.000941160000, 0.001069880000,
+ 0.001210000000, 0.001362091000, 0.001530752000, 0.001720368000, 0.001935323000,
+ 0.002180000000, 0.002454800000, 0.002764000000, 0.003117800000, 0.003526400000,
+ 0.004000000000, 0.004546240000, 0.005159320000, 0.005829280000, 0.006546160000,
+ 0.007300000000, 0.008086507000, 0.008908720000, 0.009767680000, 0.010664430000,
+ 0.011600000000, 0.012573170000, 0.013582720000, 0.014629680000, 0.015715090000,
+ 0.016840000000, 0.018007360000, 0.019214480000, 0.020453920000, 0.021718240000,
+ 0.023000000000, 0.024294610000, 0.025610240000, 0.026958570000, 0.028351250000,
+ 0.029800000000, 0.031310830000, 0.032883680000, 0.034521120000, 0.036225710000,
+ 0.038000000000, 0.039846670000, 0.041768000000, 0.043766000000, 0.045842670000,
+ 0.048000000000, 0.050243680000, 0.052573040000, 0.054980560000, 0.057458720000,
+ 0.060000000000, 0.062601970000, 0.065277520000, 0.068042080000, 0.070911090000,
+ 0.073900000000, 0.077016000000, 0.080266400000, 0.083666800000, 0.087232800000,
+ 0.090980000000, 0.094917550000, 0.099045840000, 0.103367400000, 0.107884600000,
+ 0.112600000000, 0.117532000000, 0.122674400000, 0.127992800000, 0.133452800000,
+ 0.139020000000, 0.144676400000, 0.150469300000, 0.156461900000, 0.162717700000,
+ 0.169300000000, 0.176243100000, 0.183558100000, 0.191273500000, 0.199418000000,
+ 0.208020000000, 0.217119900000, 0.226734500000, 0.236857100000, 0.247481200000,
+ 0.258600000000, 0.270184900000, 0.282293900000, 0.295050500000, 0.308578000000,
+ 0.323000000000, 0.338402100000, 0.354685800000, 0.371698600000, 0.389287500000,
+ 0.407300000000, 0.425629900000, 0.444309600000, 0.463394400000, 0.482939500000,
+ 0.503000000000, 0.523569300000, 0.544512000000, 0.565690000000, 0.586965300000,
+ 0.608200000000, 0.629345600000, 0.650306800000, 0.670875200000, 0.690842400000,
+ 0.710000000000, 0.728185200000, 0.745463600000, 0.761969400000, 0.777836800000,
+ 0.793200000000, 0.808110400000, 0.822496200000, 0.836306800000, 0.849491600000,
+ 0.862000000000, 0.873810800000, 0.884962400000, 0.895493600000, 0.905443200000,
+ 0.914850100000, 0.923734800000, 0.932092400000, 0.939922600000, 0.947225200000,
+ 0.954000000000, 0.960256100000, 0.966007400000, 0.971260600000, 0.976022500000,
+ 0.980300000000, 0.984092400000, 0.987418200000, 0.990312800000, 0.992811600000,
+ 0.994950100000, 0.996710800000, 0.998098300000, 0.999112000000, 0.999748200000,
+ 1.000000000000, 0.999856700000, 0.999304600000, 0.998325500000, 0.996898700000,
+ 0.995000000000, 0.992600500000, 0.989742600000, 0.986444400000, 0.982724100000,
+ 0.978600000000, 0.974083700000, 0.969171200000, 0.963856800000, 0.958134900000,
+ 0.952000000000, 0.945450400000, 0.938499200000, 0.931162800000, 0.923457600000,
+ 0.915400000000, 0.907006400000, 0.898277200000, 0.889204800000, 0.879781600000,
+ 0.870000000000, 0.859861300000, 0.849392000000, 0.838622000000, 0.827581300000,
+ 0.816300000000, 0.804794700000, 0.793082000000, 0.781192000000, 0.769154700000,
+ 0.757000000000, 0.744754100000, 0.732422400000, 0.720003600000, 0.707496500000,
+ 0.694900000000, 0.682219200000, 0.669471600000, 0.656674400000, 0.643844800000,
+ 0.631000000000, 0.618155500000, 0.605314400000, 0.592475600000, 0.579637900000,
+ 0.566800000000, 0.553961100000, 0.541137200000, 0.528352800000, 0.515632300000,
+ 0.503000000000, 0.490468800000, 0.478030400000, 0.465677600000, 0.453403200000,
+ 0.441200000000, 0.429080000000, 0.417036000000, 0.405032000000, 0.393032000000,
+ 0.381000000000, 0.368918400000, 0.356827200000, 0.344776800000, 0.332817600000,
+ 0.321000000000, 0.309338100000, 0.297850400000, 0.286593600000, 0.275624500000,
+ 0.265000000000, 0.254763200000, 0.244889600000, 0.235334400000, 0.226052800000,
+ 0.217000000000, 0.208161600000, 0.199548800000, 0.191155200000, 0.182974400000,
+ 0.175000000000, 0.167223500000, 0.159646400000, 0.152277600000, 0.145125900000,
+ 0.138200000000, 0.131500300000, 0.125024800000, 0.118779200000, 0.112769100000,
+ 0.107000000000, 0.101476200000, 0.096188640000, 0.091122960000, 0.086264850000,
+ 0.081600000000, 0.077120640000, 0.072825520000, 0.068710080000, 0.064769760000,
+ 0.061000000000, 0.057396210000, 0.053955040000, 0.050673760000, 0.047549650000,
+ 0.044580000000, 0.041758720000, 0.039084960000, 0.036563840000, 0.034200480000,
+ 0.032000000000, 0.029962610000, 0.028076640000, 0.026329360000, 0.024708050000,
+ 0.023200000000, 0.021800770000, 0.020501120000, 0.019281080000, 0.018120690000,
+ 0.017000000000, 0.015903790000, 0.014837180000, 0.013810680000, 0.012834780000,
+ 0.011920000000, 0.011068310000, 0.010273390000, 0.009533311000, 0.008846157000,
+ 0.008210000000, 0.007623781000, 0.007085424000, 0.006591476000, 0.006138485000,
+ 0.005723000000, 0.005343059000, 0.004995796000, 0.004676404000, 0.004380075000,
+ 0.004102000000, 0.003838453000, 0.003589099000, 0.003354219000, 0.003134093000,
+ 0.002929000000, 0.002738139000, 0.002559876000, 0.002393244000, 0.002237275000,
+ 0.002091000000, 0.001953587000, 0.001824580000, 0.001703580000, 0.001590187000,
+ 0.001484000000, 0.001384496000, 0.001291268000, 0.001204092000, 0.001122744000,
+ 0.001047000000, 0.000976589600, 0.000911108800, 0.000850133200, 0.000793238400,
+ 0.000740000000, 0.000690082700, 0.000643310000, 0.000599496000, 0.000558454700,
+ 0.000520000000, 0.000483913600, 0.000450052800, 0.000418345200, 0.000388718400,
+ 0.000361100000, 0.000335383500, 0.000311440400, 0.000289165600, 0.000268453900,
+ 0.000249200000, 0.000231301900, 0.000214685600, 0.000199288400, 0.000185047500,
+ 0.000171900000, 0.000159778100, 0.000148604400, 0.000138301600, 0.000128792500,
+ 0.000120000000, 0.000111859500, 0.000104322400, 0.000097335600, 0.000090845870,
+ 0.000084800000, 0.000079146670, 0.000073858000, 0.000068916000, 0.000064302670,
+ 0.000060000000, 0.000055981870, 0.000052225600, 0.000048718400, 0.000045447470,
+ 0.000042400000, 0.000039561040, 0.000036915120, 0.000034448680, 0.000032148160,
+ 0.000030000000, 0.000027991250, 0.000026113560, 0.000024360240, 0.000022724610,
+ 0.000021200000, 0.000019778550, 0.000018452850, 0.000017216870, 0.000016064590,
+ 0.000014990000, 0.000013987280, 0.000013051550, 0.000012178180, 0.000011362540,
+ 0.000010600000, 0.000009885877, 0.000009217304, 0.000008592362, 0.000008009133,
+ 0.000007465700, 0.000006959567, 0.000006487995, 0.000006048699, 0.000005639396,
+ 0.000005257800, 0.000004901771, 0.000004569720, 0.000004260194, 0.000003971739,
+ 0.000003702900, 0.000003452163, 0.000003218302, 0.000003000300, 0.000002797139,
+ 0.000002607800, 0.000002431220, 0.000002266531, 0.000002113013, 0.000001969943,
+ 0.000001836600, 0.000001712230, 0.000001596228, 0.000001488090, 0.000001387314,
+ 0.000001293400, 0.000001205820, 0.000001124143, 0.000001048009, 0.000000977058,
+ 0.000000910930, 0.000000849251, 0.000000791721, 0.000000738090, 0.000000688110,
+ 0.000000641530, 0.000000598090, 0.000000557575, 0.000000519808, 0.000000484612,
+ 0.000000451810
+ }
+ },
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000606100000, 0.000680879200, 0.000765145600, 0.000860012400, 0.000966592800,
+ 0.001086000000, 0.001220586000, 0.001372729000, 0.001543579000, 0.001734286000,
+ 0.001946000000, 0.002177777000, 0.002435809000, 0.002731953000, 0.003078064000,
+ 0.003486000000, 0.003975227000, 0.004540880000, 0.005158320000, 0.005802907000,
+ 0.006450001000, 0.007083216000, 0.007745488000, 0.008501152000, 0.009414544000,
+ 0.010549990000, 0.011965800000, 0.013655870000, 0.015588050000, 0.017730150000,
+ 0.020050010000, 0.022511360000, 0.025202880000, 0.028279720000, 0.031897040000,
+ 0.036210000000, 0.041437710000, 0.047503720000, 0.054119880000, 0.060998030000,
+ 0.067850010000, 0.074486320000, 0.081361560000, 0.089153640000, 0.098540480000,
+ 0.110200000000, 0.124613300000, 0.141701700000, 0.161303500000, 0.183256800000,
+ 0.207400000000, 0.233692100000, 0.262611400000, 0.294774600000, 0.330798500000,
+ 0.371300000000, 0.416209100000, 0.465464200000, 0.519694800000, 0.579530300000,
+ 0.645600000000, 0.718483800000, 0.796713300000, 0.877845900000, 0.959439000000,
+ 1.039050100000, 1.115367300000, 1.188497100000, 1.258123300000, 1.323929600000,
+ 1.385600000000, 1.442635200000, 1.494803500000, 1.542190300000, 1.584880700000,
+ 1.622960000000, 1.656404800000, 1.685295900000, 1.709874500000, 1.730382100000,
+ 1.747060000000, 1.760044600000, 1.769623300000, 1.776263700000, 1.780433400000,
+ 1.782600000000, 1.782968200000, 1.781699800000, 1.779198200000, 1.775867100000,
+ 1.772110000000, 1.768258900000, 1.764039000000, 1.758943800000, 1.752466300000,
+ 1.744100000000, 1.733559500000, 1.720858100000, 1.705936900000, 1.688737200000,
+ 1.669200000000, 1.647528700000, 1.623412700000, 1.596022300000, 1.564528000000,
+ 1.528100000000, 1.486111400000, 1.439521500000, 1.389879900000, 1.338736200000,
+ 1.287640000000, 1.237422300000, 1.187824300000, 1.138761100000, 1.090148000000,
+ 1.041900000000, 0.994197600000, 0.947347300000, 0.901453100000, 0.856619300000,
+ 0.812950100000, 0.770517300000, 0.729444800000, 0.689913600000, 0.652104900000,
+ 0.616200000000, 0.582328600000, 0.550416200000, 0.520337600000, 0.491967300000,
+ 0.465180000000, 0.439924600000, 0.416183600000, 0.393882200000, 0.372945900000,
+ 0.353300000000, 0.334857800000, 0.317552100000, 0.301337500000, 0.286168600000,
+ 0.272000000000, 0.258817100000, 0.246483800000, 0.234771800000, 0.223453300000,
+ 0.212300000000, 0.201169200000, 0.190119600000, 0.179225400000, 0.168560800000,
+ 0.158200000000, 0.148138300000, 0.138375800000, 0.128994200000, 0.120075100000,
+ 0.111700000000, 0.103904800000, 0.096667480000, 0.089982720000, 0.083845310000,
+ 0.078249990000, 0.073208990000, 0.068678160000, 0.064567840000, 0.060788350000,
+ 0.057250010000, 0.053904350000, 0.050746640000, 0.047752760000, 0.044898590000,
+ 0.042160000000, 0.039507280000, 0.036935640000, 0.034458360000, 0.032088720000,
+ 0.029840000000, 0.027711810000, 0.025694440000, 0.023787160000, 0.021989250000,
+ 0.020300000000, 0.018718050000, 0.017240360000, 0.015863640000, 0.014584610000,
+ 0.013400000000, 0.012307230000, 0.011301880000, 0.010377920000, 0.009529306000,
+ 0.008749999000, 0.008035200000, 0.007381600000, 0.006785400000, 0.006242800000,
+ 0.005749999000, 0.005303600000, 0.004899800000, 0.004534200000, 0.004202400000,
+ 0.003900000000, 0.003623200000, 0.003370600000, 0.003141400000, 0.002934800000,
+ 0.002749999000, 0.002585200000, 0.002438600000, 0.002309400000, 0.002196800000,
+ 0.002100000000, 0.002017733000, 0.001948200000, 0.001889800000, 0.001840933000,
+ 0.001800000000, 0.001766267000, 0.001737800000, 0.001711200000, 0.001683067000,
+ 0.001650001000, 0.001610133000, 0.001564400000, 0.001513600000, 0.001458533000,
+ 0.001400000000, 0.001336667000, 0.001270000000, 0.001205000000, 0.001146667000,
+ 0.001100000000, 0.001068800000, 0.001049400000, 0.001035600000, 0.001021200000,
+ 0.001000000000, 0.000968640000, 0.000929920000, 0.000886880000, 0.000842560000,
+ 0.000800000000, 0.000760960000, 0.000723680000, 0.000685920000, 0.000645440000,
+ 0.000600000000, 0.000547866700, 0.000491600000, 0.000435400000, 0.000383466700,
+ 0.000340000000, 0.000307253300, 0.000283160000, 0.000265440000, 0.000251813300,
+ 0.000240000000, 0.000229546700, 0.000220640000, 0.000211960000, 0.000202186700,
+ 0.000190000000, 0.000174213300, 0.000155640000, 0.000135960000, 0.000116853300,
+ 0.000100000000, 0.000086133330, 0.000074600000, 0.000065000000, 0.000056933330,
+ 0.000049999990, 0.000044160000, 0.000039480000, 0.000035720000, 0.000032640000,
+ 0.000030000000, 0.000027653330, 0.000025560000, 0.000023640000, 0.000021813330,
+ 0.000020000000, 0.000018133330, 0.000016200000, 0.000014200000, 0.000012133330,
+ 0.000010000000, 0.000007733333, 0.000005400000, 0.000003200000, 0.000001333333,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000
+ }
+ }
+};
+
+static xslpoly poly_CIE_1931_2 = { 0 };
+
+/* Standard CIE 1964 10 degree */
+static xspect ob_CIE_1964_10[3] = {
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000000122200, 0.000000185138, 0.000000278830, 0.000000417470, 0.000000621330,
+ 0.000000919270, 0.000001351980, 0.000001976540, 0.000002872500, 0.000004149500,
+ 0.000005958600, 0.000008505600, 0.000012068600, 0.000017022600, 0.000023868000,
+ 0.000033266000, 0.000046087000, 0.000063472000, 0.000086892000, 0.000118246000,
+ 0.000159952000, 0.000215080000, 0.000287490000, 0.000381990000, 0.000504550000,
+ 0.000662440000, 0.000864500000, 0.001121500000, 0.001446160000, 0.001853590000,
+ 0.002361600000, 0.002990600000, 0.003764500000, 0.004710200000, 0.005858100000,
+ 0.007242300000, 0.008899600000, 0.010870900000, 0.013198900000, 0.015929200000,
+ 0.019109700000, 0.022788000000, 0.027011000000, 0.031829000000, 0.037278000000,
+ 0.043400000000, 0.050223000000, 0.057764000000, 0.066038000000, 0.075033000000,
+ 0.084736000000, 0.095041000000, 0.105836000000, 0.117066000000, 0.128682000000,
+ 0.140638000000, 0.152893000000, 0.165416000000, 0.178191000000, 0.191214000000,
+ 0.204492000000, 0.217650000000, 0.230267000000, 0.242311000000, 0.253793000000,
+ 0.264737000000, 0.275195000000, 0.285301000000, 0.295143000000, 0.304869000000,
+ 0.314679000000, 0.324355000000, 0.333570000000, 0.342243000000, 0.350312000000,
+ 0.357719000000, 0.364482000000, 0.370493000000, 0.375727000000, 0.380158000000,
+ 0.383734000000, 0.386327000000, 0.387858000000, 0.388396000000, 0.387978000000,
+ 0.386726000000, 0.384696000000, 0.382006000000, 0.378709000000, 0.374915000000,
+ 0.370702000000, 0.366089000000, 0.361045000000, 0.355518000000, 0.349486000000,
+ 0.342957000000, 0.335893000000, 0.328284000000, 0.320150000000, 0.311475000000,
+ 0.302273000000, 0.292858000000, 0.283502000000, 0.274044000000, 0.264263000000,
+ 0.254085000000, 0.243392000000, 0.232187000000, 0.220488000000, 0.208198000000,
+ 0.195618000000, 0.183034000000, 0.170222000000, 0.157348000000, 0.144650000000,
+ 0.132349000000, 0.120584000000, 0.109456000000, 0.099042000000, 0.089388000000,
+ 0.080507000000, 0.072034000000, 0.063710000000, 0.055694000000, 0.048117000000,
+ 0.041072000000, 0.034642000000, 0.028896000000, 0.023876000000, 0.019628000000,
+ 0.016172000000, 0.013300000000, 0.010759000000, 0.008542000000, 0.006661000000,
+ 0.005132000000, 0.003982000000, 0.003239000000, 0.002934000000, 0.003114000000,
+ 0.003816000000, 0.005095000000, 0.006936000000, 0.009299000000, 0.012147000000,
+ 0.015444000000, 0.019156000000, 0.023250000000, 0.027690000000, 0.032444000000,
+ 0.037465000000, 0.042956000000, 0.049114000000, 0.055920000000, 0.063349000000,
+ 0.071358000000, 0.079901000000, 0.088909000000, 0.098293000000, 0.107949000000,
+ 0.117749000000, 0.127839000000, 0.138450000000, 0.149516000000, 0.161041000000,
+ 0.172953000000, 0.185209000000, 0.197755000000, 0.210538000000, 0.223460000000,
+ 0.236491000000, 0.249633000000, 0.262972000000, 0.276515000000, 0.290269000000,
+ 0.304213000000, 0.318361000000, 0.332705000000, 0.347232000000, 0.361926000000,
+ 0.376772000000, 0.391683000000, 0.406594000000, 0.421539000000, 0.436517000000,
+ 0.451584000000, 0.466782000000, 0.482147000000, 0.497738000000, 0.513606000000,
+ 0.529826000000, 0.546440000000, 0.563426000000, 0.580726000000, 0.598290000000,
+ 0.616053000000, 0.633948000000, 0.651901000000, 0.669824000000, 0.687632000000,
+ 0.705224000000, 0.722773000000, 0.740483000000, 0.758273000000, 0.776083000000,
+ 0.793832000000, 0.811436000000, 0.828822000000, 0.845879000000, 0.862525000000,
+ 0.878655000000, 0.894208000000, 0.909206000000, 0.923672000000, 0.937638000000,
+ 0.951162000000, 0.964283000000, 0.977068000000, 0.989590000000, 1.001910000000,
+ 1.014160000000, 1.026500000000, 1.038800000000, 1.051000000000, 1.062900000000,
+ 1.074300000000, 1.085200000000, 1.095200000000, 1.104200000000, 1.112000000000,
+ 1.118520000000, 1.123800000000, 1.128000000000, 1.131100000000, 1.133200000000,
+ 1.134300000000, 1.134300000000, 1.133300000000, 1.131200000000, 1.128100000000,
+ 1.123990000000, 1.118900000000, 1.112900000000, 1.105900000000, 1.098000000000,
+ 1.089100000000, 1.079200000000, 1.068400000000, 1.056700000000, 1.044000000000,
+ 1.030480000000, 1.016000000000, 1.000800000000, 0.984790000000, 0.968080000000,
+ 0.950740000000, 0.932800000000, 0.914340000000, 0.895390000000, 0.876030000000,
+ 0.856297000000, 0.836350000000, 0.816290000000, 0.796050000000, 0.775610000000,
+ 0.754930000000, 0.733990000000, 0.712780000000, 0.691290000000, 0.669520000000,
+ 0.647467000000, 0.625110000000, 0.602520000000, 0.579890000000, 0.557370000000,
+ 0.535110000000, 0.513240000000, 0.491860000000, 0.471080000000, 0.450960000000,
+ 0.431567000000, 0.412870000000, 0.394750000000, 0.377210000000, 0.360190000000,
+ 0.343690000000, 0.327690000000, 0.312170000000, 0.297110000000, 0.282500000000,
+ 0.268329000000, 0.254590000000, 0.241300000000, 0.228480000000, 0.216140000000,
+ 0.204300000000, 0.192950000000, 0.182110000000, 0.171770000000, 0.161920000000,
+ 0.152568000000, 0.143670000000, 0.135200000000, 0.127130000000, 0.119480000000,
+ 0.112210000000, 0.105310000000, 0.098786000000, 0.092610000000, 0.086773000000,
+ 0.081260600000, 0.076048000000, 0.071114000000, 0.066454000000, 0.062062000000,
+ 0.057930000000, 0.054050000000, 0.050412000000, 0.047006000000, 0.043823000000,
+ 0.040850800000, 0.038072000000, 0.035468000000, 0.033031000000, 0.030753000000,
+ 0.028623000000, 0.026635000000, 0.024781000000, 0.023052000000, 0.021441000000,
+ 0.019941300000, 0.018544000000, 0.017241000000, 0.016027000000, 0.014896000000,
+ 0.013842000000, 0.012862000000, 0.011949000000, 0.011100000000, 0.010311000000,
+ 0.009576880000, 0.008894000000, 0.008258100000, 0.007666400000, 0.007116300000,
+ 0.006605200000, 0.006130600000, 0.005690300000, 0.005281900000, 0.004903300000,
+ 0.004552630000, 0.004227500000, 0.003925800000, 0.003645700000, 0.003385900000,
+ 0.003144700000, 0.002920800000, 0.002713000000, 0.002520200000, 0.002341100000,
+ 0.002174960000, 0.002020600000, 0.001877300000, 0.001744100000, 0.001620500000,
+ 0.001505700000, 0.001399200000, 0.001300400000, 0.001208700000, 0.001123600000,
+ 0.001044760000, 0.000971560000, 0.000903600000, 0.000840480000, 0.000781870000,
+ 0.000727450000, 0.000676900000, 0.000629960000, 0.000586370000, 0.000545870000,
+ 0.000508258000, 0.000473300000, 0.000440800000, 0.000410580000, 0.000382490000,
+ 0.000356380000, 0.000332110000, 0.000309550000, 0.000288580000, 0.000269090000,
+ 0.000250969000, 0.000234130000, 0.000218470000, 0.000203910000, 0.000190350000,
+ 0.000177730000, 0.000165970000, 0.000155020000, 0.000144800000, 0.000135280000,
+ 0.000126390000, 0.000118100000, 0.000110370000, 0.000103150000, 0.000096427000,
+ 0.000090151000, 0.000084294000, 0.000078830000, 0.000073729000, 0.000068969000,
+ 0.000064525800, 0.000060376000, 0.000056500000, 0.000052880000, 0.000049498000,
+ 0.000046339000, 0.000043389000, 0.000040634000, 0.000038060000, 0.000035657000,
+ 0.000033411700, 0.000031315000, 0.000029355000, 0.000027524000, 0.000025811000,
+ 0.000024209000, 0.000022711000, 0.000021308000, 0.000019994000, 0.000018764000,
+ 0.000017611500, 0.000016532000, 0.000015521000, 0.000014574000, 0.000013686000,
+ 0.000012855000, 0.000012075000, 0.000011345000, 0.000010659000, 0.000010017000,
+ 0.000009413630, 0.000008847900, 0.000008317100, 0.000007819000, 0.000007351600,
+ 0.000006913000, 0.000006501500, 0.000006115300, 0.000005752900, 0.000005412700,
+ 0.000005093470, 0.000004793800, 0.000004512500, 0.000004248300, 0.000004000200,
+ 0.000003767100, 0.000003548000, 0.000003342100, 0.000003148500, 0.000002966500,
+ 0.000002795310, 0.000002634500, 0.000002483400, 0.000002341400, 0.000002207800,
+ 0.000002082000, 0.000001963600, 0.000001851900, 0.000001746500, 0.000001647100,
+ 0.000001553140
+ }
+ },
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000000013398, 0.000000020294, 0.000000030560, 0.000000045740, 0.000000068050,
+ 0.000000100650, 0.000000147980, 0.000000216270, 0.000000314200, 0.000000453700,
+ 0.000000651100, 0.000000928800, 0.000001317500, 0.000001857200, 0.000002602000,
+ 0.000003625000, 0.000005019000, 0.000006907000, 0.000009449000, 0.000012848000,
+ 0.000017364000, 0.000023327000, 0.000031150000, 0.000041350000, 0.000054560000,
+ 0.000071560000, 0.000093300000, 0.000120870000, 0.000155640000, 0.000199200000,
+ 0.000253400000, 0.000320200000, 0.000402400000, 0.000502300000, 0.000623200000,
+ 0.000768500000, 0.000941700000, 0.001147800000, 0.001390300000, 0.001674000000,
+ 0.002004400000, 0.002386000000, 0.002822000000, 0.003319000000, 0.003880000000,
+ 0.004509000000, 0.005209000000, 0.005985000000, 0.006833000000, 0.007757000000,
+ 0.008756000000, 0.009816000000, 0.010918000000, 0.012058000000, 0.013237000000,
+ 0.014456000000, 0.015717000000, 0.017025000000, 0.018399000000, 0.019848000000,
+ 0.021391000000, 0.022992000000, 0.024598000000, 0.026213000000, 0.027841000000,
+ 0.029497000000, 0.031195000000, 0.032927000000, 0.034738000000, 0.036654000000,
+ 0.038676000000, 0.040792000000, 0.042946000000, 0.045114000000, 0.047333000000,
+ 0.049602000000, 0.051934000000, 0.054337000000, 0.056822000000, 0.059399000000,
+ 0.062077000000, 0.064737000000, 0.067285000000, 0.069764000000, 0.072218000000,
+ 0.074704000000, 0.077272000000, 0.079979000000, 0.082874000000, 0.086000000000,
+ 0.089456000000, 0.092947000000, 0.096275000000, 0.099535000000, 0.102829000000,
+ 0.106256000000, 0.109901000000, 0.113835000000, 0.118167000000, 0.122932000000,
+ 0.128201000000, 0.133457000000, 0.138323000000, 0.143042000000, 0.147787000000,
+ 0.152761000000, 0.158102000000, 0.163941000000, 0.170362000000, 0.177425000000,
+ 0.185190000000, 0.193025000000, 0.200313000000, 0.207156000000, 0.213644000000,
+ 0.219940000000, 0.226170000000, 0.232467000000, 0.239025000000, 0.245997000000,
+ 0.253589000000, 0.261876000000, 0.270643000000, 0.279645000000, 0.288694000000,
+ 0.297665000000, 0.306469000000, 0.315035000000, 0.323335000000, 0.331366000000,
+ 0.339133000000, 0.347860000000, 0.358326000000, 0.370001000000, 0.382464000000,
+ 0.395379000000, 0.408482000000, 0.421588000000, 0.434619000000, 0.447601000000,
+ 0.460777000000, 0.474340000000, 0.488200000000, 0.502340000000, 0.516740000000,
+ 0.531360000000, 0.546190000000, 0.561180000000, 0.576290000000, 0.591500000000,
+ 0.606741000000, 0.622150000000, 0.637830000000, 0.653710000000, 0.669680000000,
+ 0.685660000000, 0.701550000000, 0.717230000000, 0.732570000000, 0.747460000000,
+ 0.761757000000, 0.775340000000, 0.788220000000, 0.800460000000, 0.812140000000,
+ 0.823330000000, 0.834120000000, 0.844600000000, 0.854870000000, 0.865040000000,
+ 0.875211000000, 0.885370000000, 0.895370000000, 0.905150000000, 0.914650000000,
+ 0.923810000000, 0.932550000000, 0.940810000000, 0.948520000000, 0.955600000000,
+ 0.961988000000, 0.967540000000, 0.972230000000, 0.976170000000, 0.979460000000,
+ 0.982200000000, 0.984520000000, 0.986520000000, 0.988320000000, 0.990020000000,
+ 0.991761000000, 0.993530000000, 0.995230000000, 0.996770000000, 0.998090000000,
+ 0.999110000000, 0.999770000000, 1.000000000000, 0.999710000000, 0.998850000000,
+ 0.997340000000, 0.995260000000, 0.992740000000, 0.989750000000, 0.986300000000,
+ 0.982380000000, 0.977980000000, 0.973110000000, 0.967740000000, 0.961890000000,
+ 0.955552000000, 0.948601000000, 0.940981000000, 0.932798000000, 0.924158000000,
+ 0.915175000000, 0.905954000000, 0.896608000000, 0.887249000000, 0.877986000000,
+ 0.868934000000, 0.860164000000, 0.851519000000, 0.842963000000, 0.834393000000,
+ 0.825623000000, 0.816764000000, 0.807544000000, 0.797947000000, 0.787893000000,
+ 0.777405000000, 0.766490000000, 0.755309000000, 0.743845000000, 0.732190000000,
+ 0.720353000000, 0.708281000000, 0.696055000000, 0.683621000000, 0.671048000000,
+ 0.658341000000, 0.645545000000, 0.632718000000, 0.619815000000, 0.606887000000,
+ 0.593878000000, 0.580781000000, 0.567653000000, 0.554490000000, 0.541228000000,
+ 0.527963000000, 0.514634000000, 0.501363000000, 0.488124000000, 0.474935000000,
+ 0.461834000000, 0.448823000000, 0.435917000000, 0.423153000000, 0.410526000000,
+ 0.398057000000, 0.385835000000, 0.373951000000, 0.362311000000, 0.350863000000,
+ 0.339554000000, 0.328309000000, 0.317118000000, 0.305936000000, 0.294737000000,
+ 0.283493000000, 0.272222000000, 0.260990000000, 0.249877000000, 0.238946000000,
+ 0.228254000000, 0.217853000000, 0.207780000000, 0.198072000000, 0.188748000000,
+ 0.179828000000, 0.171285000000, 0.163059000000, 0.155151000000, 0.147535000000,
+ 0.140211000000, 0.133170000000, 0.126400000000, 0.119892000000, 0.113640000000,
+ 0.107633000000, 0.101870000000, 0.096347000000, 0.091063000000, 0.086010000000,
+ 0.081187000000, 0.076583000000, 0.072198000000, 0.068024000000, 0.064052000000,
+ 0.060281000000, 0.056697000000, 0.053292000000, 0.050059000000, 0.046998000000,
+ 0.044096000000, 0.041345000000, 0.038750700000, 0.036297800000, 0.033983200000,
+ 0.031800400000, 0.029739500000, 0.027791800000, 0.025955100000, 0.024226300000,
+ 0.022601700000, 0.021077900000, 0.019650500000, 0.018315300000, 0.017068600000,
+ 0.015905100000, 0.014818300000, 0.013800800000, 0.012849500000, 0.011960700000,
+ 0.011130300000, 0.010355500000, 0.009633200000, 0.008959900000, 0.008332400000,
+ 0.007748800000, 0.007204600000, 0.006697500000, 0.006225100000, 0.005785000000,
+ 0.005375100000, 0.004994100000, 0.004639200000, 0.004309300000, 0.004002800000,
+ 0.003717740000, 0.003452620000, 0.003205830000, 0.002976230000, 0.002762810000,
+ 0.002564560000, 0.002380480000, 0.002209710000, 0.002051320000, 0.001904490000,
+ 0.001768470000, 0.001642360000, 0.001525350000, 0.001416720000, 0.001315950000,
+ 0.001222390000, 0.001135550000, 0.001054940000, 0.000980140000, 0.000910660000,
+ 0.000846190000, 0.000786290000, 0.000730680000, 0.000678990000, 0.000631010000,
+ 0.000586440000, 0.000545110000, 0.000506720000, 0.000471110000, 0.000438050000,
+ 0.000407410000, 0.000378962000, 0.000352543000, 0.000328001000, 0.000305208000,
+ 0.000284041000, 0.000264375000, 0.000246109000, 0.000229143000, 0.000213376000,
+ 0.000198730000, 0.000185115000, 0.000172454000, 0.000160678000, 0.000149730000,
+ 0.000139550000, 0.000130086000, 0.000121290000, 0.000113106000, 0.000105501000,
+ 0.000098428000, 0.000091853000, 0.000085738000, 0.000080048000, 0.000074751000,
+ 0.000069819000, 0.000065222000, 0.000060939000, 0.000056942000, 0.000053217000,
+ 0.000049737000, 0.000046491000, 0.000043464000, 0.000040635000, 0.000038000000,
+ 0.000035540500, 0.000033244800, 0.000031100600, 0.000029099000, 0.000027230700,
+ 0.000025486000, 0.000023856100, 0.000022333200, 0.000020910400, 0.000019580800,
+ 0.000018338400, 0.000017177700, 0.000016093400, 0.000015080000, 0.000014133600,
+ 0.000013249000, 0.000012422600, 0.000011649900, 0.000010927700, 0.000010251900,
+ 0.000009619600, 0.000009028100, 0.000008474000, 0.000007954800, 0.000007468600,
+ 0.000007012800, 0.000006585800, 0.000006185700, 0.000005810700, 0.000005459000,
+ 0.000005129800, 0.000004820600, 0.000004531200, 0.000004259100, 0.000004004200,
+ 0.000003764730, 0.000003539950, 0.000003329140, 0.000003131150, 0.000002945290,
+ 0.000002770810, 0.000002607050, 0.000002453290, 0.000002308940, 0.000002173380,
+ 0.000002046130, 0.000001926620, 0.000001814400, 0.000001708950, 0.000001609880,
+ 0.000001516770, 0.000001429210, 0.000001346860, 0.000001269450, 0.000001196620,
+ 0.000001128090, 0.000001063680, 0.000001003130, 0.000000946220, 0.000000892630,
+ 0.000000842160, 0.000000794640, 0.000000749780, 0.000000707440, 0.000000667480,
+ 0.000000629700
+ }
+ },
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000000535027, 0.000000810720, 0.000001221200, 0.000001828700, 0.000002722200,
+ 0.000004028300, 0.000005925700, 0.000008665100, 0.000012596000, 0.000018201000,
+ 0.000026143700, 0.000037330000, 0.000052987000, 0.000074764000, 0.000104870000,
+ 0.000146220000, 0.000202660000, 0.000279230000, 0.000382450000, 0.000520720000,
+ 0.000704776000, 0.000948230000, 0.001268200000, 0.001686100000, 0.002228500000,
+ 0.002927800000, 0.003823700000, 0.004964200000, 0.006406700000, 0.008219300000,
+ 0.010482200000, 0.013289000000, 0.016747000000, 0.020980000000, 0.026127000000,
+ 0.032344000000, 0.039802000000, 0.048691000000, 0.059210000000, 0.071576000000,
+ 0.086010900000, 0.102740000000, 0.122000000000, 0.144020000000, 0.168990000000,
+ 0.197120000000, 0.228570000000, 0.263470000000, 0.301900000000, 0.343870000000,
+ 0.389366000000, 0.437970000000, 0.489220000000, 0.542900000000, 0.598810000000,
+ 0.656760000000, 0.716580000000, 0.778120000000, 0.841310000000, 0.906110000000,
+ 0.972542000000, 1.038900000000, 1.103100000000, 1.165100000000, 1.224900000000,
+ 1.282500000000, 1.338200000000, 1.392600000000, 1.446100000000, 1.499400000000,
+ 1.553480000000, 1.607200000000, 1.658900000000, 1.708200000000, 1.754800000000,
+ 1.798500000000, 1.839200000000, 1.876600000000, 1.910500000000, 1.940800000000,
+ 1.967280000000, 1.989100000000, 2.005700000000, 2.017400000000, 2.024400000000,
+ 2.027300000000, 2.026400000000, 2.022300000000, 2.015300000000, 2.006000000000,
+ 1.994800000000, 1.981400000000, 1.965300000000, 1.946400000000, 1.924800000000,
+ 1.900700000000, 1.874100000000, 1.845100000000, 1.813900000000, 1.780600000000,
+ 1.745370000000, 1.709100000000, 1.672300000000, 1.634700000000, 1.595600000000,
+ 1.554900000000, 1.512200000000, 1.467300000000, 1.419900000000, 1.370000000000,
+ 1.317560000000, 1.262400000000, 1.205000000000, 1.146600000000, 1.088000000000,
+ 1.030200000000, 0.973830000000, 0.919430000000, 0.867460000000, 0.818280000000,
+ 0.772125000000, 0.728290000000, 0.686040000000, 0.645530000000, 0.606850000000,
+ 0.570060000000, 0.535220000000, 0.502340000000, 0.471400000000, 0.442390000000,
+ 0.415254000000, 0.390024000000, 0.366399000000, 0.344015000000, 0.322689000000,
+ 0.302356000000, 0.283036000000, 0.264816000000, 0.247848000000, 0.232318000000,
+ 0.218502000000, 0.205851000000, 0.193596000000, 0.181736000000, 0.170281000000,
+ 0.159249000000, 0.148673000000, 0.138609000000, 0.129096000000, 0.120215000000,
+ 0.112044000000, 0.104710000000, 0.098196000000, 0.092361000000, 0.087088000000,
+ 0.082248000000, 0.077744000000, 0.073456000000, 0.069268000000, 0.065060000000,
+ 0.060709000000, 0.056457000000, 0.052609000000, 0.049122000000, 0.045954000000,
+ 0.043050000000, 0.040368000000, 0.037839000000, 0.035384000000, 0.032949000000,
+ 0.030451000000, 0.028029000000, 0.025862000000, 0.023920000000, 0.022174000000,
+ 0.020584000000, 0.019127000000, 0.017740000000, 0.016403000000, 0.015064000000,
+ 0.013676000000, 0.012308000000, 0.011056000000, 0.009915000000, 0.008872000000,
+ 0.007918000000, 0.007030000000, 0.006223000000, 0.005453000000, 0.004714000000,
+ 0.003988000000, 0.003289000000, 0.002646000000, 0.002063000000, 0.001533000000,
+ 0.001091000000, 0.000711000000, 0.000407000000, 0.000184000000, 0.000047000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000, 0.000000000000,
+ 0.000000000000
+ }
+ }
+};
+
+static xslpoly poly_CIE_1964_10 = { 0 };
+
+#ifndef SALONEINSTLIB
+/* Standard CIE 1964 10 degree observer, */
+/* adjusted for compatibility with 2 degree observer. */
+/* This has a problem in that it will return -ve XYZ values !! */
+static xspect ob_CIE_1964_10c[3] = {
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000001,
+ 0.000001, 0.000001, 0.000002, 0.000003, 0.000004,
+ 0.000006, 0.000008, 0.000012, 0.000016, 0.000023,
+ 0.000032, 0.000044, 0.000061, 0.000083, 0.000114,
+ 0.000154, 0.000207, 0.000276, 0.000367, 0.000485,
+ 0.000636, 0.000830, 0.001077, 0.001389, 0.001780,
+ 0.002268, 0.002872, 0.003616, 0.004524, 0.005626,
+ 0.006956, 0.008547, 0.010440, 0.012675, 0.015297,
+ 0.018351, 0.021882, 0.025937, 0.030562, 0.035793,
+ 0.041670, 0.048218, 0.055455, 0.063395, 0.072026,
+ 0.081334, 0.091218, 0.101571, 0.112339, 0.123475,
+ 0.134934, 0.146676, 0.158671, 0.170901, 0.183362,
+ 0.196059, 0.208632, 0.220678, 0.232166, 0.243106,
+ 0.253521, 0.263459, 0.273052, 0.282379, 0.291584,
+ 0.300858, 0.309993, 0.318677, 0.326834, 0.334402,
+ 0.341323, 0.347615, 0.353171, 0.357967, 0.361976,
+ 0.365148, 0.367370, 0.368575, 0.368826, 0.368155,
+ 0.366675, 0.364435, 0.361545, 0.358052, 0.354057,
+ 0.349627, 0.344810, 0.339593, 0.333917, 0.327752,
+ 0.321095, 0.313902, 0.306154, 0.297863, 0.289008,
+ 0.279595, 0.269978, 0.260456, 0.250851, 0.240930,
+ 0.230604, 0.219745, 0.208345, 0.196419, 0.183863,
+ 0.170973, 0.158090, 0.145040, 0.131973, 0.119113,
+ 0.106660, 0.094739, 0.083435, 0.072806, 0.062881,
+ 0.053655, 0.044761, 0.035965, 0.027445, 0.019347,
+ 0.011775, 0.004818, -0.001448, -0.006980, -0.011730,
+ -0.015680, -0.019142, -0.022434, -0.025515, -0.028335,
+ -0.030850, -0.033009, -0.034770, -0.036095, -0.036941,
+ -0.037294, -0.037113, -0.036399, -0.035191, -0.033525,
+ -0.031433, -0.028948, -0.026100, -0.022920, -0.019440,
+ -0.015700, -0.011512, -0.006687, -0.001238, 0.004822,
+ 0.011455, 0.018627, 0.026279, 0.034335, 0.042701,
+ 0.051262, 0.060174, 0.069663, 0.079658, 0.090158,
+ 0.101084, 0.112386, 0.124002, 0.135873, 0.147891,
+ 0.160018, 0.172256, 0.184702, 0.197370, 0.210271,
+ 0.223389, 0.236747, 0.250340, 0.264164, 0.278208,
+ 0.292463, 0.306856, 0.321322, 0.335886, 0.350539,
+ 0.365327, 0.380281, 0.395429, 0.410820, 0.426495,
+ 0.442517, 0.458930, 0.475719, 0.492834, 0.510231,
+ 0.527852, 0.545635, 0.563512, 0.581404, 0.599231,
+ 0.616897, 0.634569, 0.652440, 0.670431, 0.688482,
+ 0.706512, 0.724440, 0.742190, 0.759656, 0.776754,
+ 0.793379, 0.809482, 0.825090, 0.840216, 0.854883,
+ 0.869139, 0.883013, 0.896564, 0.909854, 0.922934,
+ 0.935926, 0.948983, 0.961990, 0.974889, 0.987491,
+ 0.999611, 1.011241, 1.022004, 1.031804, 1.040446,
+ 1.047851, 1.054056, 1.059207, 1.063287, 1.066386,
+ 1.068504, 1.069546, 1.069604, 1.068584, 1.066579,
+ 1.063578, 1.059609, 1.054735, 1.048871, 1.042112,
+ 1.034363, 1.025625, 1.015993, 1.005466, 0.993951,
+ 0.981619, 0.968336, 0.954330, 0.939514, 0.923995,
+ 0.907841, 0.891082, 0.873794, 0.856007, 0.837798,
+ 0.819205, 0.800376, 0.781406, 0.762235, 0.742849,
+ 0.723211, 0.703308, 0.683132, 0.662676, 0.641942,
+ 0.620930, 0.599617, 0.578068, 0.556470, 0.534965,
+ 0.513699, 0.492797, 0.472355, 0.452479, 0.433228,
+ 0.414667, 0.396767, 0.379415, 0.362613, 0.346305,
+ 0.330490, 0.315149, 0.300263, 0.285813, 0.271789,
+ 0.258182, 0.244984, 0.232213, 0.219890, 0.208026,
+ 0.196640, 0.185723, 0.175297, 0.165350, 0.155874,
+ 0.146878, 0.138317, 0.130168, 0.122403, 0.115042,
+ 0.108045, 0.101405, 0.095126, 0.089181, 0.083563,
+ 0.078256, 0.073238, 0.068488, 0.064001, 0.059773,
+ 0.055794, 0.052058, 0.048555, 0.045275, 0.042210,
+ 0.039347, 0.036671, 0.034163, 0.031816, 0.029622,
+ 0.027571, 0.025656, 0.023870, 0.022205, 0.020653,
+ 0.019209, 0.017863, 0.016608, 0.015438, 0.014349,
+ 0.013334, 0.012390, 0.011510, 0.010693, 0.009933,
+ 0.009225, 0.008568, 0.007955, 0.007385, 0.006855,
+ 0.006363, 0.005906, 0.005481, 0.005088, 0.004723,
+ 0.004385, 0.004072, 0.003782, 0.003512, 0.003261,
+ 0.003029, 0.002813, 0.002613, 0.002428, 0.002255,
+ 0.002095, 0.001946, 0.001808, 0.001680, 0.001561,
+ 0.001450, 0.001348, 0.001253, 0.001164, 0.001082,
+ 0.001006, 0.000936, 0.000870, 0.000809, 0.000753,
+ 0.000701, 0.000652, 0.000607, 0.000565, 0.000526,
+ 0.000489, 0.000456, 0.000425, 0.000395, 0.000368,
+ 0.000343, 0.000320, 0.000298, 0.000278, 0.000259,
+ 0.000242, 0.000225, 0.000210, 0.000196, 0.000183,
+ 0.000171, 0.000160, 0.000149, 0.000139, 0.000130,
+ 0.000122, 0.000114, 0.000106, 0.000099, 0.000093,
+ 0.000087, 0.000081, 0.000076, 0.000071, 0.000066,
+ 0.000062, 0.000058, 0.000054, 0.000051, 0.000048,
+ 0.000045, 0.000042, 0.000039, 0.000037, 0.000034,
+ 0.000032, 0.000030, 0.000028, 0.000026, 0.000025,
+ 0.000023, 0.000022, 0.000021, 0.000019, 0.000018,
+ 0.000017, 0.000016, 0.000015, 0.000014, 0.000013,
+ 0.000012, 0.000012, 0.000011, 0.000010, 0.000010,
+ 0.000009, 0.000009, 0.000008, 0.000008, 0.000007,
+ 0.000007, 0.000006, 0.000006, 0.000006, 0.000005,
+ 0.000005, 0.000005, 0.000004, 0.000004, 0.000004,
+ 0.000004, 0.000003, 0.000003, 0.000003, 0.000003,
+ 0.000003, 0.000003, 0.000002, 0.000002, 0.000002,
+ 0.000002, 0.000002, 0.000002, 0.000002, 0.000002,
+ 0.000001
+ }
+ },
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000001, -0.000001, -0.000001,
+ -0.000002, -0.000003, -0.000004, -0.000005, -0.000007,
+ -0.000009, -0.000012, -0.000017, -0.000022, -0.000029,
+ -0.000039, -0.000051, -0.000066, -0.000086, -0.000111,
+ -0.000142, -0.000181, -0.000229, -0.000289, -0.000362,
+ -0.000452, -0.000560, -0.000690, -0.000845, -0.001028,
+ -0.001243, -0.001494, -0.001786, -0.002121, -0.002505,
+ -0.002940, -0.003430, -0.003976, -0.004584, -0.005251,
+ -0.005978, -0.006763, -0.007608, -0.008509, -0.009457,
+ -0.010445, -0.011465, -0.012506, -0.013548, -0.014581,
+ -0.015588, -0.016540, -0.017410, -0.018194, -0.018887,
+ -0.019474, -0.019954, -0.020356, -0.020652, -0.020844,
+ -0.020966, -0.020987, -0.020899, -0.020710, -0.020374,
+ -0.019885, -0.019227, -0.018381, -0.017329, -0.016059,
+ -0.014554, -0.012894, -0.011147, -0.009284, -0.007270,
+ -0.005073, -0.002659, 0.000006, 0.002956, 0.006209,
+ 0.009845, 0.013596, 0.017297, 0.021039, 0.024915,
+ 0.029010, 0.033403, 0.038157, 0.043368, 0.049064,
+ 0.055306, 0.061573, 0.067495, 0.073309, 0.079203,
+ 0.085372, 0.091959, 0.099098, 0.106881, 0.115363,
+ 0.124611, 0.134041, 0.143043, 0.151664, 0.159962,
+ 0.168055, 0.176039, 0.184021, 0.192166, 0.200605,
+ 0.209524, 0.219014, 0.228895, 0.238933, 0.248950,
+ 0.258827, 0.268480, 0.277842, 0.286890, 0.295622,
+ 0.304046, 0.313314, 0.324171, 0.336130, 0.348800,
+ 0.361865, 0.375076, 0.388254, 0.401320, 0.414291,
+ 0.427388, 0.440818, 0.454528, 0.468501, 0.482717,
+ 0.497136, 0.511747, 0.526497, 0.541348, 0.556275,
+ 0.571209, 0.586279, 0.601590, 0.617079, 0.632648,
+ 0.648223, 0.663715, 0.679010, 0.693991, 0.708553,
+ 0.722563, 0.735901, 0.748570, 0.760630, 0.772158,
+ 0.783222, 0.793907, 0.804300, 0.814498, 0.824603,
+ 0.834716, 0.844817, 0.854762, 0.864494, 0.873959,
+ 0.883100, 0.891844, 0.900135, 0.907907, 0.915088,
+ 0.921619, 0.927360, 0.932278, 0.936482, 0.940066,
+ 0.943128, 0.945794, 0.948157, 0.950335, 0.952425,
+ 0.954563, 0.956738, 0.958855, 0.960827, 0.962596,
+ 0.964083, 0.965229, 0.965966, 0.966206, 0.965899,
+ 0.964967, 0.963491, 0.961602, 0.959270, 0.956503,
+ 0.953289, 0.949616, 0.945492, 0.940884, 0.935810,
+ 0.930259, 0.924111, 0.917313, 0.909967, 0.902174,
+ 0.894043, 0.885675, 0.877179, 0.868664, 0.860233,
+ 0.852001, 0.844039, 0.836194, 0.828430, 0.820645,
+ 0.812656, 0.804568, 0.796113, 0.787273, 0.777966,
+ 0.768211, 0.758017, 0.747540, 0.736765, 0.725779,
+ 0.714594, 0.703154, 0.691541, 0.679699, 0.667698,
+ 0.655540, 0.643271, 0.630947, 0.618523, 0.606050,
+ 0.593471, 0.580782, 0.568037, 0.555234, 0.542308,
+ 0.529357, 0.516318, 0.503314, 0.490317, 0.477348,
+ 0.464445, 0.451610, 0.438859, 0.426230, 0.413718,
+ 0.401346, 0.389202, 0.377375, 0.365775, 0.354350,
+ 0.343050, 0.331804, 0.320601, 0.309399, 0.298173,
+ 0.286897, 0.275586, 0.264305, 0.253136, 0.242143,
+ 0.231384, 0.220911, 0.210763, 0.200977, 0.191575,
+ 0.182575, 0.173953, 0.165647, 0.157658, 0.149962,
+ 0.142556, 0.135433, 0.128580, 0.121988, 0.115652,
+ 0.109560, 0.103711, 0.098103, 0.092734, 0.087598,
+ 0.082694, 0.078011, 0.073550, 0.069303, 0.065262,
+ 0.061425, 0.057778, 0.054312, 0.051021, 0.047905,
+ 0.044950, 0.042148, 0.039506, 0.037007, 0.034649,
+ 0.032426, 0.030326, 0.028341, 0.026469, 0.024707,
+ 0.023051, 0.021498, 0.020042, 0.018681, 0.017410,
+ 0.016224, 0.015115, 0.014078, 0.013108, 0.012201,
+ 0.011354, 0.010564, 0.009827, 0.009140, 0.008500,
+ 0.007905, 0.007350, 0.006833, 0.006351, 0.005902,
+ 0.005484, 0.005095, 0.004733, 0.004397, 0.004084,
+ 0.003793, 0.003523, 0.003271, 0.003036, 0.002819,
+ 0.002616, 0.002429, 0.002254, 0.002093, 0.001943,
+ 0.001804, 0.001676, 0.001556, 0.001445, 0.001342,
+ 0.001247, 0.001158, 0.001076, 0.001000, 0.000929,
+ 0.000863, 0.000802, 0.000745, 0.000693, 0.000644,
+ 0.000598, 0.000556, 0.000517, 0.000481, 0.000447,
+ 0.000416, 0.000387, 0.000360, 0.000335, 0.000311,
+ 0.000290, 0.000270, 0.000251, 0.000234, 0.000218,
+ 0.000203, 0.000189, 0.000176, 0.000164, 0.000153,
+ 0.000142, 0.000133, 0.000124, 0.000115, 0.000108,
+ 0.000100, 0.000094, 0.000087, 0.000082, 0.000076,
+ 0.000071, 0.000066, 0.000062, 0.000058, 0.000054,
+ 0.000051, 0.000047, 0.000044, 0.000041, 0.000039,
+ 0.000036, 0.000034, 0.000032, 0.000030, 0.000028,
+ 0.000026, 0.000024, 0.000023, 0.000021, 0.000020,
+ 0.000019, 0.000018, 0.000016, 0.000015, 0.000014,
+ 0.000013, 0.000013, 0.000012, 0.000011, 0.000010,
+ 0.000010, 0.000009, 0.000009, 0.000008, 0.000008,
+ 0.000007, 0.000007, 0.000006, 0.000006, 0.000006,
+ 0.000005, 0.000005, 0.000005, 0.000004, 0.000004,
+ 0.000004, 0.000004, 0.000003, 0.000003, 0.000003,
+ 0.000003, 0.000003, 0.000002, 0.000002, 0.000002,
+ 0.000002, 0.000002, 0.000002, 0.000002, 0.000002,
+ 0.000002, 0.000001, 0.000001, 0.000001, 0.000001,
+ 0.000001, 0.000001, 0.000001, 0.000001, 0.000001,
+ 0.000001, 0.000001, 0.000001, 0.000001, 0.000001,
+ 0.000001
+ }
+ },
+ {
+ 471, 360.0, 830.0, /* 471 bands from 360 to 830 nm in 1nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000000, 0.000001, 0.000001, 0.000002, 0.000002,
+ 0.000004, 0.000005, 0.000008, 0.000011, 0.000017,
+ 0.000024, 0.000034, 0.000048, 0.000068, 0.000095,
+ 0.000133, 0.000184, 0.000253, 0.000347, 0.000473,
+ 0.000640, 0.000861, 0.001151, 0.001530, 0.002023,
+ 0.002657, 0.003470, 0.004505, 0.005815, 0.007460,
+ 0.009514, 0.012061, 0.015200, 0.019042, 0.023714,
+ 0.029357, 0.036126, 0.044195, 0.053743, 0.064968,
+ 0.078071, 0.093257, 0.110741, 0.130730, 0.153398,
+ 0.178935, 0.207487, 0.239172, 0.274063, 0.312169,
+ 0.353478, 0.397611, 0.444150, 0.492897, 0.543671,
+ 0.596302, 0.650635, 0.706534, 0.763936, 0.822806,
+ 0.883165, 0.943463, 1.001808, 1.058162, 1.112525,
+ 1.164898, 1.215552, 1.265032, 1.313703, 1.362201,
+ 1.411414, 1.460308, 1.507373, 1.552264, 1.594709,
+ 1.634529, 1.671632, 1.705747, 1.736693, 1.764380,
+ 1.788610, 1.808612, 1.823873, 1.834684, 1.841230,
+ 1.844058, 1.843442, 1.839930, 1.833797, 1.825590,
+ 1.815677, 1.803767, 1.789396, 1.772476, 1.753107,
+ 1.731476, 1.707589, 1.681541, 1.653519, 1.623619,
+ 1.591997, 1.559431, 1.526359, 1.492551, 1.457384,
+ 1.420779, 1.382383, 1.342017, 1.299412, 1.254573,
+ 1.207456, 1.157853, 1.106181, 1.053574, 1.000759,
+ 0.948651, 0.897828, 0.848786, 0.801953, 0.757664,
+ 0.716144, 0.676765, 0.638856, 0.602538, 0.567881,
+ 0.534929, 0.503728, 0.474283, 0.446572, 0.420583,
+ 0.396265, 0.373716, 0.352709, 0.332886, 0.314056,
+ 0.296143, 0.279152, 0.263152, 0.248277, 0.234696,
+ 0.222673, 0.211713, 0.201107, 0.190856, 0.180969,
+ 0.171463, 0.162367, 0.153733, 0.145596, 0.138030,
+ 0.131104, 0.124934, 0.119502, 0.114675, 0.110342,
+ 0.106383, 0.102706, 0.099197, 0.095748, 0.092248,
+ 0.088582, 0.084959, 0.081651, 0.078623, 0.075842,
+ 0.073262, 0.070852, 0.068555, 0.066306, 0.064065,
+ 0.061762, 0.059523, 0.057502, 0.055668, 0.053992,
+ 0.052433, 0.050967, 0.049534, 0.048112, 0.046651,
+ 0.045104, 0.043532, 0.042023, 0.040577, 0.039188,
+ 0.037849, 0.036544, 0.035292, 0.034054, 0.032828,
+ 0.031603, 0.030388, 0.029205, 0.028058, 0.026937,
+ 0.025874, 0.024845, 0.023862, 0.022928, 0.022050,
+ 0.021230, 0.020427, 0.019595, 0.018738, 0.017856,
+ 0.016954, 0.016034, 0.015099, 0.014153, 0.013199,
+ 0.012241, 0.011277, 0.010301, 0.009319, 0.008334,
+ 0.007350, 0.006370, 0.005397, 0.004434, 0.003484,
+ 0.002547, 0.001621, 0.000702, -0.000208, -0.001107,
+ -0.001996, -0.002870, -0.003725, -0.004559, -0.005368,
+ -0.006147, -0.006898, -0.007619, -0.008311, -0.008971,
+ -0.009601, -0.010199, -0.010764, -0.011296, -0.011794,
+ -0.012259, -0.012690, -0.013085, -0.013445, -0.013769,
+ -0.014058, -0.014311, -0.014530, -0.014715, -0.014865,
+ -0.014982, -0.015064, -0.015114, -0.015131, -0.015117,
+ -0.015074, -0.015002, -0.014904, -0.014780, -0.014633,
+ -0.014462, -0.014272, -0.014059, -0.013828, -0.013579,
+ -0.013314, -0.013035, -0.012743, -0.012439, -0.012124,
+ -0.011801, -0.011467, -0.011122, -0.010769, -0.010411,
+ -0.010052, -0.009695, -0.009340, -0.008992, -0.008650,
+ -0.008318, -0.007995, -0.007679, -0.007371, -0.007069,
+ -0.006773, -0.006483, -0.006199, -0.005920, -0.005647,
+ -0.005378, -0.005116, -0.004859, -0.004609, -0.004366,
+ -0.004133, -0.003908, -0.003692, -0.003486, -0.003290,
+ -0.003104, -0.002926, -0.002757, -0.002595, -0.002441,
+ -0.002294, -0.002155, -0.002023, -0.001898, -0.001780,
+ -0.001668, -0.001562, -0.001462, -0.001367, -0.001277,
+ -0.001193, -0.001113, -0.001039, -0.000969, -0.000904,
+ -0.000843, -0.000786, -0.000732, -0.000682, -0.000635,
+ -0.000591, -0.000550, -0.000512, -0.000476, -0.000443,
+ -0.000412, -0.000383, -0.000356, -0.000331, -0.000308,
+ -0.000286, -0.000266, -0.000247, -0.000230, -0.000213,
+ -0.000198, -0.000184, -0.000171, -0.000159, -0.000147,
+ -0.000137, -0.000127, -0.000118, -0.000109, -0.000101,
+ -0.000094, -0.000087, -0.000081, -0.000075, -0.000070,
+ -0.000065, -0.000060, -0.000056, -0.000052, -0.000048,
+ -0.000045, -0.000042, -0.000039, -0.000036, -0.000033,
+ -0.000031, -0.000029, -0.000027, -0.000025, -0.000023,
+ -0.000022, -0.000020, -0.000019, -0.000017, -0.000016,
+ -0.000015, -0.000014, -0.000013, -0.000012, -0.000011,
+ -0.000010, -0.000010, -0.000009, -0.000008, -0.000008,
+ -0.000007, -0.000007, -0.000006, -0.000006, -0.000006,
+ -0.000005, -0.000005, -0.000004, -0.000004, -0.000004,
+ -0.000004, -0.000003, -0.000003, -0.000003, -0.000003,
+ -0.000003, -0.000002, -0.000002, -0.000002, -0.000002,
+ -0.000002, -0.000002, -0.000002, -0.000002, -0.000001,
+ -0.000001, -0.000001, -0.000001, -0.000001, -0.000001,
+ -0.000001, -0.000001, -0.000001, -0.000001, -0.000001,
+ -0.000001, -0.000001, -0.000001, -0.000001, -0.000001,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000, -0.000000, -0.000000, -0.000000, -0.000000,
+ -0.000000
+ }
+ }
+};
+
+static xslpoly poly_CIE_1964_10c = { 0 };
+
+/* Judd & Voss 1978 2 degree */
+static xspect ob_Judd_Voss_2[3] = {
+ {
+ 90, 380.0, 825.0, /* 90 bands from 380 to 825 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 2.689900e-003, 5.310500e-003, 1.078100e-002, 2.079200e-002, 3.798100e-002,
+ 6.315700e-002, 9.994100e-002, 1.582400e-001, 2.294800e-001, 2.810800e-001,
+ 3.109500e-001, 3.307200e-001, 3.333600e-001, 3.167200e-001, 2.888200e-001,
+ 2.596900e-001, 2.327600e-001, 2.099900e-001, 1.747600e-001, 1.328700e-001,
+ 9.194400e-002, 5.698500e-002, 3.173100e-002, 1.461300e-002, 4.849100e-003,
+ 2.321500e-003, 9.289900e-003, 2.927800e-002, 6.379100e-002, 1.108100e-001,
+ 1.669200e-001, 2.276800e-001, 2.926900e-001, 3.622500e-001, 4.363500e-001,
+ 5.151300e-001, 5.974800e-001, 6.812100e-001, 7.642500e-001, 8.439400e-001,
+ 9.163500e-001, 9.770300e-001, 1.023000e+000, 1.051300e+000, 1.055000e+000,
+ 1.036200e+000, 9.923900e-001, 9.286100e-001, 8.434600e-001, 7.398300e-001,
+ 6.328900e-001, 5.335100e-001, 4.406200e-001, 3.545300e-001, 2.786200e-001,
+ 2.148500e-001, 1.616100e-001, 1.182000e-001, 8.575300e-002, 6.307700e-002,
+ 4.583400e-002, 3.205700e-002, 2.218700e-002, 1.561200e-002, 1.109800e-002,
+ 7.923300e-003, 5.653100e-003, 4.003900e-003, 2.825300e-003, 1.994700e-003,
+ 1.399400e-003, 9.698000e-004, 6.684700e-004, 4.614100e-004, 3.207300e-004,
+ 2.257300e-004, 1.597300e-004, 1.127500e-004, 7.951300e-005, 5.608700e-005,
+ 3.954100e-005, 2.785200e-005, 1.959700e-005, 1.377000e-005, 9.670000e-006,
+ 6.791800e-006, 4.770600e-006, 3.355000e-006, 2.353400e-006, 1.637700e-006
+ }
+ },
+ {
+ 90, 380.0, 825.0, /* 90 bands from 380 to 825 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 2.000000e-004, 3.955600e-004, 8.000000e-004, 1.545700e-003, 2.800000e-003,
+ 4.656200e-003, 7.400000e-003, 1.177900e-002, 1.750000e-002, 2.267800e-002,
+ 2.730000e-002, 3.258400e-002, 3.790000e-002, 4.239100e-002, 4.680000e-002,
+ 5.212200e-002, 6.000000e-002, 7.294200e-002, 9.098000e-002, 1.128400e-001,
+ 1.390200e-001, 1.698700e-001, 2.080200e-001, 2.580800e-001, 3.230000e-001,
+ 4.054000e-001, 5.030000e-001, 6.081100e-001, 7.100000e-001, 7.951000e-001,
+ 8.620000e-001, 9.150500e-001, 9.540000e-001, 9.800400e-001, 9.949500e-001,
+ 1.000100e+000, 9.950000e-001, 9.787500e-001, 9.520000e-001, 9.155800e-001,
+ 8.700000e-001, 8.162300e-001, 7.570000e-001, 6.948300e-001, 6.310000e-001,
+ 5.665400e-001, 5.030000e-001, 4.417200e-001, 3.810000e-001, 3.205200e-001,
+ 2.650000e-001, 2.170200e-001, 1.750000e-001, 1.381200e-001, 1.070000e-001,
+ 8.165200e-002, 6.100000e-002, 4.432700e-002, 3.200000e-002, 2.345400e-002,
+ 1.700000e-002, 1.187200e-002, 8.210000e-003, 5.772300e-003, 4.102000e-003,
+ 2.929100e-003, 2.091000e-003, 1.482200e-003, 1.047000e-003, 7.401500e-004,
+ 5.200000e-004, 3.609300e-004, 2.492000e-004, 1.723100e-004, 1.200000e-004,
+ 8.462000e-005, 6.000000e-005, 4.244600e-005, 3.000000e-005, 2.121000e-005,
+ 1.498900e-005, 1.058400e-005, 7.465600e-006, 5.259200e-006, 3.702800e-006,
+ 2.607600e-006, 1.836500e-006, 1.295000e-006, 9.109200e-007, 6.356400e-007
+ }
+ },
+ {
+ 90, 380.0, 825.0, /* 90 bands from 380 to 825 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 1.226000e-002, 2.422200e-002, 4.925000e-002, 9.513500e-002, 1.740900e-001,
+ 2.901300e-001, 4.605300e-001, 7.316600e-001, 1.065800e+000, 1.314600e+000,
+ 1.467200e+000, 1.579600e+000, 1.616600e+000, 1.568200e+000, 1.471700e+000,
+ 1.374000e+000, 1.291700e+000, 1.235600e+000, 1.113800e+000, 9.422000e-001,
+ 7.559600e-001, 5.864000e-001, 4.466900e-001, 3.411600e-001, 2.643700e-001,
+ 2.059400e-001, 1.544500e-001, 1.091800e-001, 7.658500e-002, 5.622700e-002,
+ 4.136600e-002, 2.935300e-002, 2.004200e-002, 1.331200e-002, 8.782300e-003,
+ 5.857300e-003, 4.049300e-003, 2.921700e-003, 2.277100e-003, 1.970600e-003,
+ 1.806600e-003, 1.544900e-003, 1.234800e-003, 1.117700e-003, 9.056400e-004,
+ 6.946700e-004, 4.288500e-004, 3.181700e-004, 2.559800e-004, 1.567900e-004,
+ 9.769400e-005, 6.894400e-005, 5.116500e-005, 3.601600e-005, 2.423800e-005,
+ 1.691500e-005, 1.190600e-005, 8.148900e-006, 5.600600e-006, 3.954400e-006,
+ 2.791200e-006, 1.917600e-006, 1.313500e-006, 9.151900e-007, 6.476700e-007,
+ 4.635200e-007, 3.330400e-007, 2.382300e-007, 1.702600e-007, 1.220700e-007,
+ 8.710700e-008, 6.145500e-008, 4.316200e-008, 3.037900e-008, 2.155400e-008,
+ 1.549300e-008, 1.120400e-008, 8.087300e-009, 5.834000e-009, 4.211000e-009,
+ 3.038300e-009, 2.190700e-009, 1.577800e-009, 1.134800e-009, 8.156500e-010,
+ 5.862600e-010, 4.213800e-010, 3.031900e-010, 2.175300e-010, 1.547600e-010
+ }
+ }
+};
+
+static xslpoly poly_Judd_Voss_2 = { 0 };
+
+
+/* Stiles & Burch 1955 2 degree, */
+/* rotated to align with 1931 XYZ space, */
+/* using Mark Shaw's matrix. */
+static xspect ob_Stiles_Burch_2[3] = {
+ {
+ 69, 390.0, 730.0, /* 69 bands from 390 to 730 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.005035, 0.012873, 0.025933, 0.054264, 0.093147,
+ 0.144597, 0.207609, 0.266538, 0.303933, 0.336185,
+ 0.356549, 0.364180, 0.328209, 0.286053, 0.262928,
+ 0.210562, 0.182549, 0.131014, 0.081974, 0.045980,
+ 0.020673, 0.008302, 0.004814, 0.008248, 0.024412,
+ 0.050113, 0.084255, 0.131255, 0.186757, 0.243224,
+ 0.298768, 0.359848, 0.428510, 0.500880, 0.571271,
+ 0.650846, 0.742250, 0.829040, 0.905369, 0.971275,
+ 1.024797, 1.060952, 1.071632, 1.054762, 1.012750,
+ 0.947501, 0.861487, 0.761200, 0.654122, 0.548338,
+ 0.450269, 0.361237, 0.281687, 0.213565, 0.158588,
+ 0.115934, 0.083874, 0.060355, 0.043191, 0.030661,
+ 0.021532, 0.014822, 0.010047, 0.006832, 0.004755,
+ 0.003363, 0.002330, 0.001623, 0.001136
+ }
+ },
+ {
+ 69, 390.0, 730.0, /* 69 bands from 390 to 730 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.000021, 0.000137, 0.000267, 0.000499, 0.000959,
+ -0.000352, -0.000535, -0.002306, -0.001139, 0.001507,
+ 0.007142, 0.012389, 0.022879, 0.037200, 0.054616,
+ 0.080087, 0.108008, 0.140411, 0.170719, 0.199791,
+ 0.240641, 0.297681, 0.367645, 0.455184, 0.546333,
+ 0.641762, 0.736259, 0.813393, 0.873858, 0.911828,
+ 0.931983, 0.954960, 0.971754, 0.970171, 0.950790,
+ 0.937240, 0.932444, 0.903026, 0.857070, 0.815886,
+ 0.769666, 0.712437, 0.651257, 0.588631, 0.523557,
+ 0.457801, 0.393963, 0.332964, 0.275541, 0.223722,
+ 0.179091, 0.140943, 0.108310, 0.081218, 0.059780,
+ 0.043398, 0.031238, 0.022406, 0.016003, 0.011340,
+ 0.007953, 0.005473, 0.003713, 0.002527, 0.001759,
+ 0.001244, 0.000863, 0.000602, 0.000422
+ }
+ },
+ {
+ 69, 390.0, 730.0, /* 69 bands from 390 to 730 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.023163, 0.059308, 0.118897, 0.250907, 0.433765,
+ 0.684409, 0.999185, 1.308097, 1.518706, 1.707302,
+ 1.840521, 1.906560, 1.756384, 1.578949, 1.505983,
+ 1.283002, 1.178612, 0.947751, 0.709500, 0.529689,
+ 0.398963, 0.310980, 0.240664, 0.188969, 0.145151,
+ 0.110796, 0.087421, 0.069953, 0.059951, 0.051960,
+ 0.042905, 0.037710, 0.033821, 0.028764, 0.023371,
+ 0.018909, 0.015103, 0.009656, 0.003595, -0.001221,
+ -0.005978, -0.010905, -0.014270, -0.016302, -0.018412,
+ -0.019889, -0.019510, -0.017854, -0.015815, -0.013632,
+ -0.011388, -0.009171, -0.007076, -0.005238, -0.003775,
+ -0.002692, -0.001946, -0.001447, -0.001074, -0.000766,
+ -0.000527, -0.000357, -0.000242, -0.000164, -0.000113,
+ -0.000077, -0.000051, -0.000034, -0.000023
+ }
+ }
+};
+
+static xslpoly poly_Stiles_Burch_2 = { 0 };
+
+/* Shaw & Fairchild 1997 2 degree observer. */
+/* From Mark Shaw's Masters thesis: */
+/* "Evaluating the 1931 CIE Color Matching Functions" */
+static xspect ob_Shaw_Fairchild_2[3] = {
+ {
+ 61, 400.0, 700.0, /* 61 bands from 400 to 700 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.050035085, 0.10599540, 0.17570524, 0.26369069, 0.34385256,
+ 0.36314044, 0.35022338, 0.35921696, 0.37057582, 0.37027683,
+ 0.31092719, 0.24467905, 0.21495057, 0.16408854, 0.15609086,
+ 0.10496585, 0.053550350, 0.016029866, -0.010473666, -0.020635411,
+ -0.020599591, -0.010774255, 0.013507015, 0.045305699, 0.082609321,
+ 0.13244251, 0.18966495, 0.24710489, 0.30272442, 0.36362744,
+ 0.43329425, 0.50816654, 0.57883305, 0.66085495, 0.75701632,
+ 0.84336950, 0.91608703, 0.98348582, 1.0386456, 1.0699974,
+ 1.0751974, 1.0492333, 1.0010173, 0.92955516, 0.83907524,
+ 0.74332961, 0.64179542, 0.53031723, 0.42814376, 0.34048130,
+ 0.26368241, 0.19677558, 0.14402031, 0.10472063, 0.076398767,
+ 0.054311075, 0.037000030, 0.026240015, 0.018750015, 0.012892199,
+ 0.0081198003
+ }
+ },
+ {
+ 61, 400.0, 700.0, /* 61 bands from 400 to 700 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.00073439190, 0.0010295739, 0.0011050375, -0.00057123313, -0.0015421159,
+ -0.0050492258, -0.0060441241, -0.0050340813, -0.00046015829, 0.0043453053,
+ 0.014594307, 0.028653705, 0.047841334, 0.078039315, 0.11339641,
+ 0.15326829, 0.18931877, 0.22596008, 0.26950734, 0.32894461,
+ 0.39924943, 0.48161678, 0.56603317, 0.65284913, 0.73864212,
+ 0.80870955, 0.86388621, 0.90168525, 0.92331427, 0.94508269,
+ 0.96035974, 0.96084837, 0.94474215, 0.93248079, 0.92686312,
+ 0.89683591, 0.85193527, 0.81446493, 0.77206051, 0.71732417,
+ 0.65749412, 0.59544590, 0.53033945, 0.46382662, 0.39929743,
+ 0.33905951, 0.28179144, 0.22775797, 0.18104592, 0.14195030,
+ 0.10887196, 0.081491712, 0.059933233, 0.043516174, 0.031399280,
+ 0.022402933, 0.015787610, 0.011178068, 0.0078482427, 0.0054361119,
+ 0.0036285556
+ }
+ },
+ {
+ 61, 400.0, 700.0, /* 61 bands from 400 to 700 nm in 5nm steps */
+ 1.0, /* Scale factor */
+ {
+ 0.19346810, 0.37355444, 0.62641781, 0.98559734, 1.3578634,
+ 1.5413908, 1.6258281, 1.7422823, 1.8184109, 1.7982693,
+ 1.6624945, 1.4917210, 1.3537111, 1.2543216, 1.1444894,
+ 0.94078221, 0.73058355, 0.55774101, 0.42026628, 0.31970216,
+ 0.24388223, 0.18951860, 0.14567319, 0.11603887, 0.094972125,
+ 0.077803903, 0.065288720, 0.055235267, 0.046945157, 0.039405440,
+ 0.033042398, 0.026944585, 0.021626844, 0.016807242, 0.011642648,
+ 0.0061489002, 0.00061480026, -0.0044002687, -0.0090514735, -0.013048603,
+ -0.016063598, -0.018035874, -0.019053770, -0.019163305, -0.018371066,
+ -0.016810570, -0.014805852, -0.012650736, -0.010513405, -0.0085481723,
+ -0.0067628649, -0.0051813692, -0.0038792081, -0.0028536093, -0.0020731313,
+ -0.0014924891, -0.0010704383, -0.00075273042, -0.00052400943, -0.00036054897,
+ -0.00025295701
+ }
+ }
+};
+
+static xslpoly poly_Shaw_Fairchild_2 = { 0 };
+
+#endif /* !SALONEINSTLIB */
+
+/* Return pointers to three xpsects with a standard observer weighting curves */
+/* return 0 on sucecss, nz if not matched */
+int standardObserver(
+xspect *sp[3], /* Return 3 pointers */
+icxObserverType obType /* Type of observer */
+) {
+ switch (obType) {
+ case icxOT_custom:
+ return 1;
+ case icxOT_none:
+ return 1;
+ case icxOT_default:
+ case icxOT_CIE_1931_2:
+ sp[0] = &ob_CIE_1931_2[0];
+ sp[1] = &ob_CIE_1931_2[1];
+ sp[2] = &ob_CIE_1931_2[2];
+ return 0;
+ case icxOT_CIE_1964_10:
+ sp[0] = &ob_CIE_1964_10[0];
+ sp[1] = &ob_CIE_1964_10[1];
+ sp[2] = &ob_CIE_1964_10[2];
+ return 0;
+#ifndef SALONEINSTLIB
+ case icxOT_Stiles_Burch_2:
+ sp[0] = &ob_Stiles_Burch_2[0];
+ sp[1] = &ob_Stiles_Burch_2[1];
+ sp[2] = &ob_Stiles_Burch_2[2];
+ return 0;
+ case icxOT_Judd_Voss_2:
+ sp[0] = &ob_Judd_Voss_2[0];
+ sp[1] = &ob_Judd_Voss_2[1];
+ sp[2] = &ob_Judd_Voss_2[2];
+ return 0;
+ case icxOT_CIE_1964_10c:
+ sp[0] = &ob_CIE_1964_10c[0];
+ sp[1] = &ob_CIE_1964_10c[1];
+ sp[2] = &ob_CIE_1964_10c[2];
+ return 0;
+ case icxOT_Shaw_Fairchild_2:
+ sp[0] = &ob_Shaw_Fairchild_2[0];
+ sp[1] = &ob_Shaw_Fairchild_2[1];
+ sp[2] = &ob_Shaw_Fairchild_2[2];
+ return 0;
+#endif /* !SALONEINSTLIB */
+ default:
+ return 1;
+ }
+}
+
+/* Return a string describing the standard observer */
+char *standardObserverDescription(icxObserverType obType) {
+ switch (obType) {
+ case icxOT_custom:
+ return "Custom observer";
+ case icxOT_none:
+ return "No observer";
+ case icxOT_default:
+ case icxOT_CIE_1931_2:
+ return "CIE 1931 2 degree observer";
+ case icxOT_CIE_1964_10:
+ return "CIE 1964 10 degree observer";
+#ifndef SALONEINSTLIB
+ case icxOT_Stiles_Burch_2:
+ return "Stiles & Burch 1955 2 degree observer (aligned)";
+ case icxOT_Judd_Voss_2:
+ return "Judd & Voss 1978 2 degree observer";
+ case icxOT_CIE_1964_10c:
+ return "CIE 1964 10 degree observer (aligned)";
+ case icxOT_Shaw_Fairchild_2:
+ return "Shaw & Fairchild 1997 2 degree observer";
+#endif /* !SALONEINSTLIB */
+ }
+ return "Unknown observer";
+}
+
+/* Return a pointer to the spectral locus poligon */
+/* return NULL on failure. */
+static xslpoly *spectral_locus_poligon(
+icxObserverType obType /* Type of observer */
+) {
+ switch (obType) {
+ case icxOT_custom:
+ return NULL;
+ case icxOT_none:
+ return NULL;
+ case icxOT_default:
+ case icxOT_CIE_1931_2:
+ return &poly_CIE_1931_2;
+ case icxOT_CIE_1964_10:
+ return &poly_CIE_1964_10;
+#ifndef SALONEINSTLIB
+ case icxOT_Stiles_Burch_2:
+ return &poly_Stiles_Burch_2;
+ case icxOT_Judd_Voss_2:
+ return &poly_Judd_Voss_2;
+ case icxOT_CIE_1964_10c:
+ return &poly_CIE_1964_10c;
+ case icxOT_Shaw_Fairchild_2:
+ return &poly_Shaw_Fairchild_2;
+#endif /* !SALONEINSTLIB */
+ default:
+ return NULL;
+ }
+}
+
+
+#ifndef SALONEINSTLIB
+/* ----------------------------------- */
+/* Standard refelective sample spectra */
+
+/* Ra CRI Test Color Samples */
+static xspect CIE1995_TCS[] = {
+
+ /* TCS01 7.5 R 6/4 Light greyish red */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.12, 0.14, 0.16, 0.19, 0.22, 0.24, 0.25, 0.26, 0.26, 0.25,
+ 0.25, 0.25, 0.24, 0.24, 0.24, 0.23, 0.23, 0.23, 0.23, 0.22,
+ 0.22, 0.22, 0.22, 0.21, 0.21, 0.21, 0.22, 0.22, 0.22, 0.23,
+ 0.23, 0.23, 0.23, 0.23, 0.23, 0.23, 0.24, 0.25, 0.25, 0.26,
+ 0.27, 0.28, 0.3, 0.32, 0.34, 0.37, 0.39, 0.41, 0.42, 0.44,
+ 0.44, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45, 0.45,
+ 0.45, 0.45, 0.45, 0.45, 0.46, 0.46, 0.46, 0.46, 0.46, 0.46,
+ 0.46, 0.47, 0.47, 0.47, 0.47, 0.47, 0.47, 0.47, 0.47, 0.47,
+ 0.47, 0.47, 0.47, 0.47, 0.47, 0.47, 0.47, 0.47, 0.47, 0.47,
+ 0.47, 0.47, 0.47, 0.46, 0.46
+ }
+ },
+ /* TCS02 5 Y6/4 Dark greyish yellow */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.05, 0.06, 0.06, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12,
+ 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 0.13, 0.13,
+ 0.13, 0.13, 0.14, 0.14, 0.15, 0.16, 0.17, 0.19, 0.21, 0.23,
+ 0.24, 0.25, 0.26, 0.26, 0.27, 0.27, 0.27, 0.28, 0.28, 0.29,
+ 0.3, 0.31, 0.32, 0.33, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34,
+ 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34, 0.34,
+ 0.33, 0.33, 0.33, 0.33, 0.33, 0.33, 0.33, 0.33, 0.33, 0.33,
+ 0.33, 0.33, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32, 0.32,
+ 0.32, 0.32, 0.32, 0.31, 0.31, 0.31, 0.31, 0.31, 0.31, 0.31,
+ 0.31, 0.31, 0.31, 0.31, 0.31
+ }
+ },
+ /* TCS03 5 GY 6/8 Strong yellow green */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.06, 0.06, 0.06, 0.06, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07,
+ 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.08,
+ 0.08, 0.08, 0.09, 0.09, 0.11, 0.13, 0.15, 0.17, 0.2, 0.22,
+ 0.24, 0.26, 0.28, 0.3, 0.34, 0.37, 0.39, 0.4, 0.4, 0.39,
+ 0.38, 0.37, 0.35, 0.33, 0.32, 0.3, 0.29, 0.27, 0.26, 0.26,
+ 0.25, 0.25, 0.24, 0.24, 0.23, 0.22, 0.22, 0.22, 0.22, 0.22,
+ 0.22, 0.22, 0.23, 0.24, 0.25, 0.27, 0.29, 0.31, 0.34, 0.37,
+ 0.39, 0.41, 0.43, 0.45, 0.46, 0.47, 0.48, 0.49, 0.49, 0.5,
+ 0.5, 0.5, 0.51, 0.51, 0.52, 0.52, 0.52, 0.53, 0.53, 0.54,
+ 0.54, 0.54, 0.55, 0.55, 0.56
+ }
+ },
+ /* TCS04 2.5 G 6/6 Moderate yellowish green */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.06, 0.06, 0.06, 0.07, 0.07, 0.08, 0.09, 0.11, 0.12, 0.12,
+ 0.12, 0.13, 0.13, 0.13, 0.14, 0.14, 0.14, 0.15, 0.16, 0.17,
+ 0.19, 0.21, 0.23, 0.25, 0.28, 0.31, 0.33, 0.35, 0.37, 0.38,
+ 0.39, 0.39, 0.4, 0.39, 0.39, 0.38, 0.37, 0.35, 0.34, 0.33,
+ 0.31, 0.3, 0.28, 0.26, 0.25, 0.23, 0.21, 0.2, 0.19, 0.18,
+ 0.17, 0.16, 0.16, 0.16, 0.15, 0.15, 0.15, 0.15, 0.15, 0.15,
+ 0.15, 0.15, 0.15, 0.15, 0.16, 0.16, 0.17, 0.17, 0.17, 0.17,
+ 0.17, 0.17, 0.17, 0.16, 0.16, 0.17, 0.17, 0.17, 0.18, 0.18,
+ 0.19, 0.19, 0.19, 0.19, 0.2, 0.2, 0.2, 0.21, 0.22, 0.23,
+ 0.23, 0.24, 0.25, 0.26, 0.27
+ }
+ },
+ /* TCS05 10 BG 6/4 Light bluish green */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.14, 0.19, 0.23, 0.27, 0.3, 0.31, 0.31, 0.31, 0.31, 0.32,
+ 0.32, 0.32, 0.33, 0.33, 0.33, 0.34, 0.35, 0.35, 0.36, 0.37,
+ 0.38, 0.39, 0.4, 0.41, 0.42, 0.42, 0.42, 0.42, 0.41, 0.41,
+ 0.4, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.32,
+ 0.31, 0.3, 0.28, 0.27, 0.26, 0.25, 0.23, 0.22, 0.21, 0.2,
+ 0.19, 0.19, 0.19, 0.18, 0.18, 0.18, 0.18, 0.18, 0.18, 0.18,
+ 0.18, 0.18, 0.18, 0.18, 0.19, 0.19, 0.19, 0.2, 0.2, 0.2,
+ 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.21,
+ 0.21, 0.21, 0.22, 0.22, 0.22, 0.22, 0.23, 0.23, 0.24, 0.24,
+ 0.25, 0.26, 0.27, 0.27, 0.28
+ }
+ },
+ /* TCS06 5 PB 6/8 Light blue */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.08, 0.08, 0.09, 0.11, 0.15, 0.2, 0.27, 0.34, 0.41, 0.46,
+ 0.49, 0.51, 0.52, 0.52, 0.53, 0.54, 0.54, 0.55, 0.56, 0.56,
+ 0.55, 0.55, 0.54, 0.53, 0.52, 0.5, 0.49, 0.47, 0.45, 0.43,
+ 0.41, 0.4, 0.38, 0.36, 0.34, 0.33, 0.31, 0.29, 0.28, 0.27,
+ 0.25, 0.24, 0.23, 0.23, 0.23, 0.22, 0.22, 0.22, 0.22, 0.22,
+ 0.22, 0.22, 0.22, 0.23, 0.23, 0.24, 0.24, 0.25, 0.26, 0.26,
+ 0.27, 0.27, 0.28, 0.28, 0.28, 0.29, 0.29, 0.3, 0.3, 0.31,
+ 0.33, 0.34, 0.35, 0.36, 0.38, 0.39, 0.4, 0.41, 0.43, 0.44,
+ 0.45, 0.46, 0.47, 0.48, 0.49, 0.49, 0.5, 0.51, 0.51, 0.52,
+ 0.52, 0.53, 0.53, 0.53, 0.54
+ }
+ },
+ /* TCS07 2.5 P 6/8 Y6/4 Light violet */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.15, 0.18, 0.22, 0.29, 0.38, 0.46, 0.52, 0.55, 0.55, 0.56,
+ 0.56, 0.56, 0.56, 0.56, 0.56, 0.55, 0.54, 0.54, 0.52, 0.51,
+ 0.49, 0.47, 0.45, 0.43, 0.41, 0.39, 0.36, 0.34, 0.32, 0.31,
+ 0.3, 0.29, 0.28, 0.27, 0.27, 0.26, 0.26, 0.26, 0.26, 0.26,
+ 0.26, 0.26, 0.26, 0.25, 0.25, 0.26, 0.27, 0.28, 0.3, 0.32,
+ 0.34, 0.36, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45,
+ 0.45, 0.46, 0.46, 0.47, 0.47, 0.47, 0.47, 0.48, 0.48, 0.49,
+ 0.5, 0.5, 0.51, 0.52, 0.53, 0.53, 0.54, 0.55, 0.55, 0.56,
+ 0.57, 0.57, 0.58, 0.58, 0.58, 0.58, 0.59, 0.59, 0.59, 0.59,
+ 0.59, 0.59, 0.59, 0.59, 0.59
+ }
+ },
+ /* TCS08 10 P 6/8 Light reddish purple */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.08, 0.08, 0.08, 0.09, 0.1, 0.13, 0.17, 0.24, 0.32, 0.42,
+ 0.46, 0.48, 0.49, 0.49, 0.48, 0.47, 0.46, 0.45, 0.44, 0.43,
+ 0.41, 0.4, 0.38, 0.37, 0.35, 0.34, 0.33, 0.31, 0.3, 0.29,
+ 0.28, 0.28, 0.27, 0.26, 0.26, 0.25, 0.25, 0.25, 0.25, 0.26,
+ 0.26, 0.27, 0.27, 0.27, 0.28, 0.28, 0.3, 0.32, 0.35, 0.38,
+ 0.43, 0.48, 0.53, 0.57, 0.6, 0.63, 0.65, 0.66, 0.68, 0.69,
+ 0.69, 0.7, 0.71, 0.71, 0.71, 0.72, 0.72, 0.72, 0.72, 0.72,
+ 0.72, 0.72, 0.73, 0.73, 0.73, 0.73, 0.73, 0.73, 0.73, 0.73,
+ 0.73, 0.73, 0.73, 0.73, 0.73, 0.73, 0.73, 0.73, 0.73, 0.73,
+ 0.73, 0.73, 0.73, 0.73, 0.73
+ }
+ },
+ /* TCS09 4.5 R 4/13 Strong red */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.069, 0.072, 0.073, 0.070, 0.066, 0.062, 0.058, 0.055, 0.052, 0.052,
+ 0.051, 0.050, 0.050, 0.049, 0.048, 0.047, 0.046, 0.044, 0.042, 0.041,
+ 0.038, 0.035, 0.033, 0.031, 0.030, 0.029, 0.028, 0.028, 0.028, 0.029,
+ 0.030, 0.030, 0.031, 0.031, 0.032, 0.032, 0.033, 0.034, 0.035, 0.037,
+ 0.041, 0.044, 0.048, 0.052, 0.060, 0.076, 0.102, 0.136, 0.190, 0.256,
+ 0.336, 0.418, 0.505, 0.581, 0.641, 0.682, 0.717, 0.740, 0.758, 0.770,
+ 0.781, 0.790, 0.797, 0.803, 0.809, 0.814, 0.819, 0.824, 0.828, 0.830,
+ 0.831, 0.833, 0.835, 0.836, 0.836, 0.837, 0.838, 0.839, 0.839, 0.839,
+ 0.839, 0.839, 0.839, 0.839, 0.839, 0.839, 0.839, 0.839, 0.839, 0.839,
+ 0.838, 0.837, 0.837, 0.836, 0.836
+ }
+ },
+ /* TCS10 5 Y 8/10 Strong yellow */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.04, 0.04, 0.05, 0.05, 0.05, 0.05, 0.06, 0.06, 0.07, 0.07,
+ 0.07, 0.07, 0.07, 0.07, 0.07, 0.07, 0.08, 0.08, 0.08, 0.09,
+ 0.1, 0.1, 0.11, 0.13, 0.14, 0.16, 0.19, 0.22, 0.26, 0.31,
+ 0.37, 0.42, 0.47, 0.51, 0.55, 0.58, 0.61, 0.63, 0.65, 0.67,
+ 0.68, 0.69, 0.69, 0.7, 0.7, 0.7, 0.71, 0.71, 0.71, 0.71,
+ 0.71, 0.71, 0.71, 0.71, 0.71, 0.71, 0.71, 0.71, 0.72, 0.72,
+ 0.72, 0.72, 0.73, 0.73, 0.73, 0.74, 0.74, 0.74, 0.75, 0.75,
+ 0.75, 0.75, 0.75, 0.75, 0.76, 0.76, 0.76, 0.76, 0.76, 0.76,
+ 0.76, 0.76, 0.76, 0.76, 0.76, 0.76, 0.76, 0.76, 0.76, 0.76,
+ 0.76, 0.76, 0.76, 0.76, 0.76
+ }
+ },
+ /* TCS11 4.5 G 5/8 Strong green */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.13, 0.13, 0.12,
+ 0.12, 0.11, 0.11, 0.11, 0.1, 0.1, 0.11, 0.11, 0.11, 0.12,
+ 0.12, 0.13, 0.15, 0.17, 0.19, 0.22, 0.25, 0.29, 0.33, 0.35,
+ 0.36, 0.35, 0.35, 0.33, 0.31, 0.29, 0.27, 0.25, 0.23, 0.21,
+ 0.19, 0.17, 0.15, 0.14, 0.13, 0.11, 0.11, 0.1, 0.1, 0.09,
+ 0.09, 0.09, 0.09, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08,
+ 0.08, 0.08, 0.09, 0.09, 0.1, 0.11, 0.13, 0.14, 0.16, 0.18,
+ 0.2, 0.22, 0.24, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.31,
+ 0.32, 0.32, 0.33, 0.33, 0.34, 0.34, 0.35, 0.35, 0.36, 0.37,
+ 0.37, 0.38, 0.39, 0.4, 0.4
+ }
+ },
+ /* TCS12 3 PB 3/11 Strong blue */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.19, 0.18, 0.16, 0.14, 0.12, 0.1, 0.09, 0.08, 0.08, 0.07,
+ 0.06, 0.07, 0.08, 0.09, 0.12, 0.16, 0.21, 0.26, 0.3, 0.33,
+ 0.35, 0.35, 0.34, 0.33, 0.31, 0.28, 0.26, 0.23, 0.2, 0.18,
+ 0.15, 0.13, 0.11, 0.09, 0.08, 0.06, 0.05, 0.04, 0.04, 0.03,
+ 0.03, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02,
+ 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.02,
+ 0.02, 0.02, 0.03, 0.03, 0.04, 0.04, 0.06, 0.07, 0.1, 0.13,
+ 0.17, 0.21, 0.26, 0.31, 0.35, 0.4, 0.45, 0.49, 0.52, 0.55,
+ 0.58, 0.6, 0.62, 0.63, 0.65, 0.66, 0.67, 0.67, 0.68, 0.69,
+ 0.69, 0.69, 0.7, 0.7, 0.7
+ }
+ },
+ /* TCS13 5 YR 8/4 Light yellowish pink */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.07, 0.08, 0.08, 0.09, 0.1, 0.13, 0.16, 0.21, 0.26, 0.31,
+ 0.34, 0.35, 0.36, 0.36, 0.36, 0.37, 0.37, 0.37, 0.37, 0.37,
+ 0.38, 0.38, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45,
+ 0.46, 0.47, 0.47, 0.47, 0.47, 0.48, 0.48, 0.49, 0.51, 0.53,
+ 0.55, 0.58, 0.62, 0.65, 0.68, 0.7, 0.72, 0.73, 0.74, 0.74,
+ 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75,
+ 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75,
+ 0.75, 0.74, 0.74, 0.74, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75,
+ 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75, 0.75,
+ 0.75, 0.75, 0.75, 0.75, 0.75
+ }
+ },
+ /* TCS14 5 GY 4/4 Moderate olive green */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04,
+ 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.05, 0.05, 0.05,
+ 0.05, 0.05, 0.05, 0.05, 0.06, 0.06, 0.06, 0.07, 0.08, 0.08,
+ 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.15, 0.16, 0.15,
+ 0.15, 0.14, 0.13, 0.13, 0.12, 0.11, 0.11, 0.1, 0.1, 0.1,
+ 0.09, 0.09, 0.09, 0.09, 0.09, 0.09, 0.08, 0.08, 0.08, 0.08,
+ 0.09, 0.09, 0.09, 0.1, 0.1, 0.11, 0.12, 0.14, 0.15, 0.17,
+ 0.19, 0.21, 0.23, 0.24, 0.26, 0.28, 0.29, 0.31, 0.33, 0.34,
+ 0.35, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.42, 0.43, 0.43,
+ 0.44, 0.44, 0.45, 0.45, 0.45
+ }
+ },
+ /* TCS15 1 YR 6/4 Asian skin */
+ {
+ 95, 360.0, 830.0, /* 95 bands from 360 to 830 nm in 5nm steps */
+ 1.0, /* Scale factor */
+
+ {
+ 0, 0, 0, 0, 0.13, 0.14, 0.15, 0.15, 0.16, 0.16,
+ 0.16, 0.17, 0.17, 0.18, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23,
+ 0.24, 0.24, 0.25, 0.25, 0.26, 0.26, 0.27, 0.28, 0.28, 0.29,
+ 0.3, 0.3, 0.3, 0.29, 0.28, 0.28, 0.27, 0.28, 0.28, 0.29,
+ 0.29, 0.29, 0.29, 0.28, 0.29, 0.31, 0.35, 0.4, 0.44, 0.47,
+ 0.49, 0.51, 0.52, 0.54, 0.54, 0.55, 0.56, 0.57, 0.57, 0.58,
+ 0.58, 0.59, 0.59, 0.59, 0.6, 0.6, 0.61, 0.61, 0.61, 0.61,
+ 0.62, 0.62, 0.62, 0.62, 0.62, 0.61, 0.61, 0.61, 0.61, 0.61,
+ 0.61, 0.61, 0.61, 0.61, 0.61, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0
+ }
+ }
+};
+
+
+/* -------------------------------- */
+/* Fluorescent Whitening Agent Data */
+
+/* Generic stimulation/exitation spectrum, used in FWA. */
+/* This is also used to estimate the UV content of an illuminant, */
+/* by its FWA effect (illumread) */
+static xspect FWA1_stim = {
+ 14, 290.0, 420.0, /* 14 bands from 290 to 420 nm in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+/* 290 */ 0.000000,
+/* 300 */ 0.075000, 0.158000, 0.228000, 0.318638, 0.393663,
+/* 350 */ 0.460003, 0.524409, 0.550955, 0.540374, 0.497947,
+/* 400 */ 0.412503, 0.265935, 0.000000
+ }
+};
+
+/* !!! This is not normally used !!! */
+#ifdef STOCKFWA /* Use table shape as FWA basis, rather than estimating from spectrum. */
+
+/* Generic emmission spectrum */
+static xspect FWA1_emit = {
+ 17, 390.0, 550.0, /* 17 bands from 390 to 550 nm in 10nm steps */
+ 1.0, /* Scale factor */
+ {
+#ifdef NEVER
+/* 390 */ 0.00000,
+/* 400 */ 0.08989, 0.27831, 0.45278, 0.494, 0.496,
+/* 450 */ 0.36872, 0.30495, 0.226, 0.1676, 0.1216,
+/* 500 */ 0.08515, 0.06877, 0.04930, 0.0246, 0.0123,
+/* 550 */ 0.00000
+#else
+ /* Hacked */
+/* 390 */ 0.00000,
+/* 400 */ 0.01089, 0.15000, 0.20278, 0.374, 0.496,
+/* 450 */ 0.38000, 0.27495, 0.186, 0.1376, 0.1016,
+/* 500 */ 0.08515, 0.06877, 0.04930, 0.0246, 0.0123,
+/* 550 */ 0.00000
+#endif
+ }
+};
+
+#endif /* STOCKFWA */
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* save a set of spectrum to a CGATS file */
+/* type 0 = SPECT, 1 = CMF */
+/* Return NZ on error */
+int write_nxspect(char *fname, xspect *sp, int nspec, int type) {
+ char buf[100];
+ time_t clk = time(0);
+ struct tm *tsp = localtime(&clk);
+ char *atm = asctime(tsp); /* Ascii time */
+ cgats *ocg; /* output cgats structure */
+ cgats_set_elem *setel; /* Array of set value elements */
+ int i, j;
+
+ /* Setup output cgats file */
+ ocg = new_cgats(); /* Create a CGATS structure */
+ if (type != 0)
+ ocg->add_other(ocg, "CMF"); /* our special type is spectral color matching func */
+ else
+ ocg->add_other(ocg, "SPECT"); /* our special type is spectral power or reflectance */
+ ocg->add_table(ocg, tt_other, 0); /* Start the first table */
+
+ ocg->add_kword(ocg, 0, "DESCRIPTOR", "Argyll Spectral power/reflectance information",NULL);
+ ocg->add_kword(ocg, 0, "ORIGINATOR", "Argyll CMS", NULL);
+ atm[strlen(atm)-1] = '\000'; /* Remove \n from end */
+ ocg->add_kword(ocg, 0, "CREATED",atm, NULL);
+
+ sprintf(buf,"%d", sp->spec_n);
+ ocg->add_kword(ocg, 0, "SPECTRAL_BANDS",buf, NULL);
+ sprintf(buf,"%f", sp->spec_wl_short);
+ ocg->add_kword(ocg, 0, "SPECTRAL_START_NM",buf, NULL);
+ sprintf(buf,"%f", sp->spec_wl_long);
+ ocg->add_kword(ocg, 0, "SPECTRAL_END_NM",buf, NULL);
+ sprintf(buf,"%f", sp->norm);
+ ocg->add_kword(ocg, 0, "SPECTRAL_NORM",buf, NULL);
+
+ /* Generate fields for spectral values */
+ for (i = 0; i < sp->spec_n; i++) {
+ int nm;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(XSPECT_XWL(sp, i) + 0.5);
+ sprintf(buf,"SPEC_%03d",nm);
+ ocg->add_field(ocg, 0, buf, r_t);
+ }
+
+ if ((setel = (cgats_set_elem *)malloc(sizeof(cgats_set_elem) * sp->spec_n)) == NULL) {
+ ocg->del(ocg);
+ return 1;
+ }
+
+ for (j = 0; j < nspec; j++) {
+ for (i = 0; i < sp[j].spec_n; i++) {
+ setel[i].d = sp[j].spec[i];
+ }
+ ocg->add_setarr(ocg, 0, setel);
+ }
+
+ if (ocg->write_name(ocg, fname)) {
+ DBGF((DBGA,"CGATS file write error : %s\n",ocg->err));
+ return 1;
+ }
+
+ free(setel);
+ ocg->del(ocg); /* Clean up */
+
+ return 0;
+}
+
+/* restore a set of spectrum from a CGATS file. */
+/* Up to nspec will be restored starting at offset off.. */
+/* The number restored from the file will be written to *nret */
+/* type: 0 = any, mask: 1 = SPECT, 2 = CMF, 4 = ccss */
+/* Return NZ on error */
+/* (Would be nice to return an error message!) */
+int read_nxspect(xspect *sp, char *fname, int *nret, int off, int nspec, int type) {
+ cgats *icg; /* input cgats structure */
+ char buf[100];
+ int sflds[XSPECT_MAX_BANDS];
+ int i, j, ii;
+ xspect proto;
+
+ /* Open and look at the spectrum file */
+ if ((icg = new_cgats()) == NULL) { /* Create a CGATS structure */
+ DBG("new_cgats() failed");
+ icg->del(icg);
+ return 1;
+ }
+ if (type == 0) {
+ icg->add_other(icg, ""); /* Allow any signature file */
+ } else {
+ if (type & 1)
+ icg->add_other(icg, "SPECT"); /* Spectrum file */
+ if (type & 2)
+ icg->add_other(icg, "CMF"); /* Color Matching Functions */
+ if (type & 4)
+ icg->add_other(icg, "CCSS"); /* Color Correction Spectral Samples */
+ }
+
+ if (icg->read_name(icg, fname)) {
+ DBGF((DBGA,"CGATS file read error : %s\n",icg->err));
+ icg->del(icg);
+ return 1;
+ }
+
+ if (icg->ntables != 1) {
+ DBG("Input file doesn't contain exactly one table\n");
+ icg->del(icg);
+ return 1;
+ }
+
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_BANDS")) < 0) {
+ DBG ("Input file doesn't contain keyword SPECTRAL_BANDS\n");
+ icg->del(icg);
+ return 1;
+ }
+ proto.spec_n = atoi(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_START_NM")) < 0) {
+ DBG("Input file doesn't contain keyword SPECTRAL_START_NM\n");
+ icg->del(icg);
+ return 1;
+ }
+ proto.spec_wl_short = atof(icg->t[0].kdata[ii]);
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_END_NM")) < 0) {
+ DBG("Input file doesn't contain keyword SPECTRAL_END_NM\n");
+ icg->del(icg);
+ return 1;
+ }
+ proto.spec_wl_long = atof(icg->t[0].kdata[ii]);
+
+ if ((ii = icg->find_kword(icg, 0, "SPECTRAL_NORM")) < 0) {
+ DBG("Input file doesn't contain keyword SPECTRAL_NORM - assuming 1.0\n");
+ proto.norm = 1.0;
+ } else {
+ proto.norm = atof(icg->t[0].kdata[ii]);
+ }
+
+ /* Find the fields for spectral values */
+ for (i = 0; i < proto.spec_n; i++) {
+ int nm, fi;
+
+ /* Compute nearest integer wavelength */
+ nm = (int)(XSPECT_XWL(&proto, i) + 0.5);
+ sprintf(buf,"SPEC_%03d",nm);
+
+ if ((fi = icg->find_field(icg, 0, buf)) < 0) {
+ DBGF((DBGA,"Input file doesn't contain field %s\n",buf));
+ icg->del(icg);
+ return 1;
+ }
+
+ if (icg->t[0].ftype[fi] != r_t) {
+ DBGF((DBGA,"Field %s in specrum is wrong type - should be a float\n",buf));
+ icg->del(icg);
+ return 1;
+ }
+ sflds[i] = fi;
+ }
+
+ /* Read all the spectra */
+ for (j = off; j < nspec && j < icg->t[0].nsets; j++) {
+
+ XSPECT_COPY_INFO(&sp[j], &proto);
+
+ for (i = 0; i < proto.spec_n; i++) {
+ sp[j].spec[i] = *((double *)icg->t[0].fdata[j][sflds[i]]);
+ }
+ }
+ if (nret != NULL)
+ *nret = j - off;
+
+ icg->del(icg);
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* save a spectrum to a CGATS file */
+/* Return NZ on error */
+int write_xspect(char *fname, xspect *sp) {
+ return write_nxspect(fname, sp, 1, 0);
+}
+
+/* restore a spectrum from a CGATS file */
+/* Return NZ on error */
+/* (Would be nice to return an error message!) */
+int read_xspect(xspect *sp, char *fname) {
+ int rv, nret;
+
+ if ((rv = read_nxspect(sp, fname, &nret, 0, 1, 1)) != 0)
+ return rv;
+ if (nret != 1) {
+ DBG("Didn't read one spectra\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* save a set of 3 spectrum to a CGATS CMF file */
+/* Return NZ on error */
+int write_cmf(char *fname, xspect sp[3]) {
+ return write_nxspect(fname, sp, 3, 1);
+}
+
+/* restore a spectrum from a CGATS file */
+/* Return NZ on error */
+/* (Would be nice to return an error message!) */
+int read_cmf(xspect sp[3], char *fname) {
+ int rv, nret;
+
+ if ((rv = read_nxspect(sp, fname, &nret, 0, 3, 2)) != 0)
+ return rv;
+ if (nret != 3) {
+ DBG("Didn't read three spectra\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+/* ------------- */
+#endif /* !SALONEINSTLIB */
+
+
+/* Get a raw 3rd order polinomial interpolated spectrum value. */
+/* Return NZ if value is valid, Z and last valid value */
+/* if outside the range */
+/* NOTE: Returned value isn't normalised by sp->norm */
+static int getval_raw_xspec_poly3(xspect *sp, double *rv, double xw) {
+ int i, rc = 1;
+ double spcing, f;
+#ifdef NEVER
+ double w1, w2, w3; /* For Hermite curves */
+#endif
+ double y[4], yw;
+ double x[4];
+
+ if (xw < sp->spec_wl_short) {
+ xw = sp->spec_wl_short;
+ rc = 0;
+ }
+
+ if (xw > sp->spec_wl_long) {
+ xw = sp->spec_wl_long;
+ rc = 0;
+ }
+
+ /* Compute fraction 0.0 - 1.0 out of known spectrum */
+ spcing = (sp->spec_wl_long - sp->spec_wl_short)/(sp->spec_n-1.0);
+ f = (xw - sp->spec_wl_short) / (sp->spec_wl_long - sp->spec_wl_short);
+ f *= (sp->spec_n - 1.0);
+ i = (int)floor(f); /* Base grid coordinate */
+
+ if (i < 0) /* Limit to valid cube base index range */
+ i = 0;
+ else if (i > (sp->spec_n - 2))
+ i = (sp->spec_n - 2);
+
+ /* Setup the surrounding values */
+ x[0] = sp->spec_wl_short + (i-1) * spcing;
+ if (i == 0)
+ y[0] = sp->spec[i];
+ else
+ y[0] = sp->spec[i-1];
+ x[1] = sp->spec_wl_short + i * spcing;
+ y[1] = sp->spec[i];
+ x[2] = sp->spec_wl_short + (i+1) * spcing;
+ y[2] = sp->spec[i+1];
+ x[3] = sp->spec_wl_short + (i+2) * spcing;
+ if ((i+2) < sp->spec_n)
+ y[3] = sp->spec[i+2];
+ else
+ y[3] = sp->spec[i+1];
+
+#ifndef NEVER
+ /* Compute interpolated value using Lagrange: */
+ yw = y[0] * (xw-x[1]) * (xw-x[2]) * (xw-x[3])/((x[0]-x[1]) * (x[0]-x[2]) * (x[0]-x[3]))
+ + y[1] * (xw-x[0]) * (xw-x[2]) * (xw-x[3])/((x[1]-x[0]) * (x[1]-x[2]) * (x[1]-x[3]))
+ + y[2] * (xw-x[0]) * (xw-x[1]) * (xw-x[3])/((x[2]-x[0]) * (x[2]-x[1]) * (x[2]-x[3]))
+ + y[3] * (xw-x[0]) * (xw-x[1]) * (xw-x[2])/((x[3]-x[0]) * (x[3]-x[1]) * (x[3]-x[2]));
+#else
+ /* Use Hermite curves */
+ y[0] = 0.5 * (y[2] - y[0]); /* Convert to tangent */
+ y[3] = 0.5 * (y[3] - y[1]); /* Not sure about the best weighting here ... */
+
+ w1 = f - (double)i; /* Interpolation weighting factor, 0.0 - 1.0 */
+ w2 = w1 * w1;
+ w3 = w2 * w1;
+ yw = y[0] * (w3 - 2.0 * w2 + w1)
+ + y[1] * (2.0 * w3 - 3.0 * w2 + 1.0)
+ + y[2] * (-2.0 * w3 + 3.0 * w2)
+ + y[3] * (w3 - w2);
+#endif
+
+#ifdef NEVER // ~~99
+ /* Calibration issues or interpolation overshoot can give -ve values, */
+ /* so protect against this. */
+ /* On the other hand, not allowing -ve values wrecks black level */
+ /* by not averaging out the noise. */
+ if (yw < 0.0)
+ yw = 0.0;
+#endif /* NEVER */
+
+ *rv = yw;
+ return rc;
+}
+
+/* Get a raw linearly interpolated spectrum value. */
+/* Return NZ if value is valid, Z and last valid value */
+/* if outside the range */
+/* NOTE: Returned value isn't normalised by sp->norm */
+static int getval_raw_xspec_lin(xspect *sp, double *rv, double wl) {
+ int i, rc = 1;
+ double f, w;
+
+ if (wl < sp->spec_wl_short) {
+ wl = sp->spec_wl_short;
+ rc = 0;
+ }
+
+ if (wl > sp->spec_wl_long) {
+ wl = sp->spec_wl_long;
+ rc = 0;
+ }
+
+ /* Compute fraction 0.0 - 1.0 out of known spectrum */
+ f = (wl - sp->spec_wl_short) / (sp->spec_wl_long - sp->spec_wl_short);
+ f *= (sp->spec_n - 1.0);
+ i = (int)floor(f); /* Base grid coordinate */
+
+ if (i < 0) /* Limit to valid cube base index range */
+ i = 0;
+ else if (i > (sp->spec_n - 2))
+ i = (sp->spec_n - 2);
+
+ w = f - (double)i; /* Interpolation weighting factor */
+
+ /* Compute interpolated value */
+ *rv = (1.0 - w) * sp->spec[i] + w * sp->spec[i+1];
+
+#ifdef NEVER
+ /* Calibration issues or interpolation overshoot can give -ve values, */
+ /* so protect against this. */
+ /* On the other hand, not allowing -ve values wrecks black level */
+ /* by not averaging out the noise. */
+ if (*rv < 0.0)
+ *rv = 0.0;
+#endif /* NEVER */
+
+ return rc;
+}
+
+#ifdef NEVER /* Nearest neighbor resampler, for testing */
+/* Get a raw nearest-neighbor interpolated spectrum value. */
+/* Return NZ if value is valid, Z and last valid value */
+/* if outside the range */
+/* NOTE: Returned value isn't normalised by sp->norm */
+static int getval_raw_xspec_nn(xspect *sp, double *rv, double wl) {
+ int i, rc = 1;
+ double f;
+
+ if (wl < sp->spec_wl_short) {
+ wl = sp->spec_wl_short;
+ rc = 0;
+ }
+
+ if (wl > sp->spec_wl_long) {
+ wl = sp->spec_wl_long;
+ rc = 0;
+ }
+
+ /* Compute fraction 0.0 - 1.0 out of known spectrum */
+ f = (wl - sp->spec_wl_short) / (sp->spec_wl_long - sp->spec_wl_short);
+ f *= (sp->spec_n - 1.0);
+ i = (int)floor(f + 0.5); /* Base grid coordinate */
+
+ if (i < 0) /* Limit to valid cube base index range */
+ i = 0;
+ else if (i > (sp->spec_n - 1))
+ i = (sp->spec_n - 1);
+
+ /* Compute interpolated value */
+ *rv = sp->spec[i];
+
+#ifdef NEVER
+ /* Calibration issues or interpolation overshoot can give -ve values, */
+ /* so protect against this. */
+ /* On the other hand, not allowing -ve values wrecks black level */
+ /* by not averaging out the noise. */
+ if (*rv < 0.0)
+ *rv = 0.0;
+#endif /* NEVER */
+
+ return rc;
+}
+#endif /* NEVER */
+
+/* Call the appropriate interpolation routine */
+/* Return NZ if value is valid, Z and last valid value */
+/* if outside the range */
+/* NOTE: Returned value isn't normalised by sp->norm */
+static int getval_raw_xspec(xspect *sp, double *rv, double wl) {
+ double spcg = (sp->spec_wl_long - sp->spec_wl_short)/(sp->spec_n-1.0);
+
+ if (spcg < 5.01) {
+ return getval_raw_xspec_lin(sp, rv, wl);
+ } else {
+ return getval_raw_xspec_poly3(sp, rv, wl);
+ }
+}
+
+/* Get a (normalised) linearly or poly interpolated spectrum value. */
+/* Return NZ if value is valid, Z and last valid value */
+/* if outside the range */
+static int getval_xspec(xspect *sp, double *rv, double wl) {
+ int sv = getval_raw_xspec(sp, rv, wl);
+ *rv /= sp->norm;
+ return sv;
+}
+
+/* Public function to get a spectrum value. */
+/* Return a spectrum value at the given wavelenth. It */
+/* may have been interpolated or extrapolated. */
+/* Returned value isn't normalised by sp->norm */
+double value_xspect(xspect *sp, double wl) {
+ double rv;
+ getval_raw_xspec(sp, &rv, wl);
+ return rv;
+}
+
+/* Get a (normalised) linearly interpolated spectrum value. */
+/* Return NZ if value is valid, Z and last valid value */
+/* if outside the range */
+static int getval_lxspec(xspect *sp, double *rv, double wl) {
+ int sv = getval_raw_xspec_lin(sp, rv, wl);
+ *rv /= sp->norm;
+ return sv;
+}
+
+/* De-noramlize and set normalisation factor to 1.0 */
+void xspect_denorm(xspect *sp) {
+ int i;
+
+ for (i = 0; i < sp->spec_n; i++) {
+ sp->spec[i] /= sp->norm;
+ }
+ sp->norm = 1.0;
+}
+
+#ifndef SALONEINSTLIB
+/* Convert from one xspect type to another (targ type) */
+/* Linear or polinomial interpolation will be used as appropriate */
+/* (converted to targ norm too) */
+void xspect2xspect(xspect *dst, xspect *targ, xspect *src) {
+ xspect dd;
+ int i;
+
+ dd.spec_n = targ->spec_n;
+ dd.spec_wl_short = targ->spec_wl_short;
+ dd.spec_wl_long = targ->spec_wl_long;
+ dd.norm = targ->norm;
+
+ if (targ->spec_n != src->spec_n
+ || targ->spec_wl_short != src->spec_wl_short
+ || targ->spec_wl_long != src->spec_wl_long) {
+ for (i = 0; i < targ->spec_n; i++) {
+ double ww = XSPECT_XWL(targ, i);
+ getval_raw_xspec(src, &dd.spec[i], ww);
+ }
+ } else {
+ for (i = 0; i < targ->spec_n; i++)
+ dd.spec[i] = src->spec[i];
+ }
+ if (targ->norm != src->norm) {
+ for (i = 0; i < targ->spec_n; i++)
+ dd.spec[i] *= targ->norm/src->norm;
+ }
+ *dst = dd;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Given an emission spectrum, set the UV output to the given level. */
+/* The shape of the UV is taken from FWA1_stim, and the level is */
+/* with respect to the Y of the input spectrum. */
+void xsp_setUV(xspect *out, xspect *in, double uvlevel) {
+ int i, xs, xe;
+ double ww, avg;
+ xspect cin; /* Copy of in */
+
+ cin = *in;
+
+ /* Compute the average of the input spetrum */
+ for (avg = 0.0, i = 0; i < cin.spec_n; i++)
+ avg += cin.spec[i];
+ avg /= cin.spec_n;
+
+ if (avg < 1e-5) /* Make it do something with 0.0 */
+ avg = 1e-5;
+
+ /* Copy and Extend the range */
+ *out = cin;
+ i = (int)floor(XSPECT_XDIX(out, FWA1_stim.spec_wl_short));
+ ww = XSPECT_XWL(out, i);
+ if (i < 0)
+ out->spec_n -= i;
+ out->spec_wl_short = ww;
+
+ /* Copy from input and merge in the UV */
+ for (i = 0; i < out->spec_n; i++) {
+ double inv, uvv, bl, nbl, outv;
+
+ ww = XSPECT_XWL(out, i);
+ getval_raw_xspec_lin(&cin, &inv, ww);
+ getval_raw_xspec_lin(&FWA1_stim, &uvv, ww);
+
+ /* Taper measured illum out */
+ bl = (ww - FWA1_stim.spec_wl_short)/(FWA1_stim.spec_wl_long - FWA1_stim.spec_wl_short);
+ bl = bl < 0.0 ? 0.0 : (bl > 1.0 ? 1.0 : bl);
+ inv *= bl;
+
+ /* Add/subtract UV in */
+ outv = inv + uvv * uvlevel * avg;;
+
+ /* Protect against creating negative output */
+ if (outv >= out->spec[i])
+ out->spec[i] = outv;
+ }
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Set Media White. This enables extracting and applying the */
+/* colorant reflectance value from/to the meadia. */
+// ~~99 this is confused. ->media is set from ->imedia in fwa setup.
+// ~~99 what's going on here ? The API needs fixing.
+static int xsp2cie_set_mw(xsp2cie *p, /* this */
+xspect *media /* Spectrum of plain media measured under that instrument */
+) {
+ p->media = *media; /* Take copy of media white */
+ return 0;
+}
+
+/* Extract the colorant reflectance value from the media. Takes FWA */
+/* into account if set. Media white or FWA must be set. */
+static int xsp2cie_extract(xsp2cie *p, /* this */
+xspect *out, /* Extracted colorant refl. spectrum */
+xspect *in /* Spectrum to be converted, normalised by norm */
+) {
+ int j;
+
+ if (p->media.spec_n == 0)
+ return 1;
+
+ if (p->media.spec_n != in->spec_n
+ || p->media.spec_wl_short != in->spec_wl_short
+ || p->media.spec_wl_long != in->spec_wl_long)
+ return 1;
+
+ *out = *in;
+
+ /* Divide out the media */
+ for (j = 0; j < p->media.spec_n; j++) {
+ if (p->media.spec[j] < 0.01)
+ out->spec[j] = in->spec[j] / 0.01;
+ else
+ out->spec[j] = in->spec[j] / p->media.spec[j];
+ }
+
+ out->norm = in->norm / p->media.norm;
+ return 0;
+}
+
+
+/* Apply the colorant reflectance value from the media. Takes FWA */
+/* into account if set. Media white or FWA must be set. */
+static int xsp2cie_apply(xsp2cie *p, /* this */
+xspect *out, /* Applied refl. spectrum */
+xspect *in /* Colorant reflectance to be applied */
+) {
+ int j;
+
+ if (p->media.spec_n == 0)
+ return 1;
+
+ if (p->media.spec_n != in->spec_n
+ || p->media.spec_wl_short != in->spec_wl_short
+ || p->media.spec_wl_long != in->spec_wl_long)
+ return 1;
+
+ *out = *in;
+
+ /* Multiply in the media */
+ for (j = 0; j < p->media.spec_n; j++) {
+ if (p->media.spec[j] < 0.01)
+ out->spec[j] = in->spec[j] * 0.01;
+ else
+ out->spec[j] = in->spec[j] * p->media.spec[j];
+ }
+
+ out->norm = in->norm * p->media.norm;
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+static void xsp2cie_fwa_convert(xsp2cie *p, double *out, xspect *in);
+static void xsp2cie_fwa_sconvert(xsp2cie *p, xspect *sout, double *out, xspect *in);
+static int xsp2cie_fwa_extract(xsp2cie *p, xspect *out, xspect *in);
+static int xsp2cie_fwa_apply(xsp2cie *p, xspect *out, xspect *in);
+
+/* Set Fluorescent Whitening Agent compensation. */
+/* This attempts to compensate for the presense of */
+/* Fluorescent whitner in the media, under the possibly */
+/* different level of UV radiation of the illuminant being */
+/* simulated in the conversion from spectral absorbition */
+/* to CIE values, from the illuminant that the media was */
+/* measured under by the spectrometer. */
+/* Note that the media input spectrum normalisation value is used. */
+/* return nz if error */
+
+/*
+
+ Limitations of current FWA model:
+
+ Scattering: The inking model assumes that the inks are purely
+ absorbtive. If instead they have a significant scattering
+ component, then the FWA effect will be over estimated,
+ as it will be assumed that more UV is reaching the substrate
+ and not being filtered by the colorant.
+
+ Colorant UV transparency: The current model assumes that
+ the filtering behaviour of the ink can be extrapolated
+ from the blue reflectance. It could be that inks behave
+ quite differently, filtering more or less in UV than
+ they do in blue. Different inks might have different characteristics.
+
+ Solution: A solution would be to add a colorant correction model,
+ that takes as input the colorant levels. To create the model,
+ illumread would be augmented to read (say) 50% colorant swatches
+ as well as white, and use the discrepancy between the non-corrected
+ FWA spectrum and the actual spectrum under the illuminant to
+ create the correction model. This could be fine tuned by doing
+ similar measurements of neutral patches.
+ */
+
+/*
+ See page 248 of the Proceedings of the IS&T/SID
+ 11th Color Imaging Conference, November 2003:
+ "A Practical Approach to Measuring and Modelling Paper Fluorescense
+ for Improved Colorimetric Characterisation of Printing Processes"
+ ISBN: 0-89208-248-8
+ for more information about the fwa compensation approach.
+ */
+
+static int xsp2cie_set_fwa_imp(xsp2cie *p) {
+ double ww;
+ int i, j;
+ int flag;
+ double aw = 0.0, bw = 0.0; /* Points wavelength */
+ double ar, br; /* Points reflection */
+#ifdef STOCKFWA /* Use table shape */
+ double Em; /* Emmision multiplier */
+#endif
+#ifdef DOPLOT
+ double xx[XSPECT_MAX_BANDS];
+ double y1[XSPECT_MAX_BANDS];
+ double y2[XSPECT_MAX_BANDS];
+ double y3[XSPECT_MAX_BANDS];
+ double y4[XSPECT_MAX_BANDS];
+#endif /* DOPLOT */
+
+#ifdef WRITE_FWA1_STIM
+ write_xspect("fwa1_stip.sp", &FWA1_stim);
+#endif
+
+ DBG("set_fwa started\n");
+
+ p->bw = 1.0; /* Intergrate over 1nm bands */
+ p->oillum = p->illuminant; /* Take copy of observer illuminant */
+ xspect_denorm(&p->oillum);
+ if (p->tillum.spec_n == 0) { /* If not set by set_fwa(), use observer illuminant */
+ p->tillum = p->oillum; /* as target/simulated instrument illuminant. */
+ }
+
+ /* Compute Y = 1 normalised instrument illuminant spectrum */
+ {
+ double scale = 0.0;
+ double Iim; /* illuminant multiplier */
+
+ Iim = 0.0;
+ for (ww = p->observer[1].spec_wl_short; ww <= p->observer[1].spec_wl_long; ww += p->bw) {
+ double O, I;
+ getval_lxspec(&p->iillum, &I, ww);
+ getval_lxspec(&p->observer[1], &O, ww);
+ scale += O; /* Integrate Y observer values */
+ Iim += O * I;
+ }
+ Iim /= scale; /* Scale Y observer to unity */
+
+ Iim = 1.0/Iim; /* Scale factor to make illuminant integral 1.0 */
+
+ for (j = 0; j < p->iillum.spec_n; j++)
+ p->iillum.spec[j] *= Iim;
+ DBGF((DBGA,"Instrument Illum normal multiplier Iim = %f\n",Iim));
+ }
+
+ /* Compute Y = 1 normalised target illuminant spectrum */
+ {
+ double scale;
+ double Itm; /* illuminant multiplier */
+
+ scale = 0.0;
+ Itm = 0.0;
+ for (ww = p->observer[1].spec_wl_short; ww <= p->observer[1].spec_wl_long; ww += p->bw) {
+ double O, I;
+ getval_lxspec(&p->tillum, &I, ww);
+ getval_lxspec(&p->observer[1], &O, ww);
+ scale += O; /* Integrate Y observer values */
+ Itm += O * I;
+ }
+ Itm /= scale; /* Scale Y observer to unity */
+ Itm = 1.0/Itm; /* Scale factor to make illuminant integral 1.0 */
+
+ for (j = 0; j < p->tillum.spec_n; j++)
+ p->tillum.spec[j] *= Itm;
+ }
+
+ /* Check if the instrument and target/simulated illuminant are the same. */
+ /* If they are, FWA compensation can be bypassed. */
+ /* (We check for an almost exact matcg on the assumption that these will */
+ /* both be xspect presets) */
+#define DEQ(A, B) (fabs(A - B) < 1e-6)
+ p->insteqtarget = 0;
+ if (p->iillum.spec_n == p->tillum.spec_n
+ && DEQ(p->iillum.spec_wl_short, p->tillum.spec_wl_short)
+ && DEQ(p->iillum.spec_wl_long, p->tillum.spec_wl_long)) {
+ for (i = 0; i < p->iillum.spec_n; i++) {
+ if (!DEQ(p->tillum.spec[i], p->iillum.spec[i]))
+ break;
+ }
+ if (i >= p->iillum.spec_n) {
+ p->insteqtarget = 1;
+ DBGF((DBGA,"###### inst equals target illuminant #####\n"));
+ }
+ }
+#undef DEQ
+
+ /* Compute Y = 1 normalised observer illuminant spectrum */
+ {
+ double scale;
+ double Itm; /* Target illuminant multiplier */
+
+ scale = 0.0;
+ Itm = 0.0;
+ for (ww = p->observer[1].spec_wl_short; ww <= p->observer[1].spec_wl_long; ww += p->bw) {
+ double O, I;
+ getval_lxspec(&p->oillum, &I, ww);
+ getval_lxspec(&p->observer[1], &O, ww);
+ scale += O; /* Integrate Y observer values */
+ Itm += O * I;
+ }
+ Itm /= scale; /* Scale Y observer to unity */
+ Itm = 1.0/Itm; /* Scale factor to make illuminant integral 1.0 */
+
+ for (j = 0; j < p->oillum.spec_n; j++)
+ p->oillum.spec[j] *= Itm;
+ }
+
+ /* Estimate the amount of generic FWA in the media. */
+ /* and also compute an estimated media minus FWA spectrum */
+ /* by creating a target white line from the media spectrum */
+
+ /* This is quite good for "normal" media, which has a fairly */
+ /* flat underlying (non FWA) response, but doesn't work so */
+ /* well for meadia that rolls off at short wavelengths and uses */
+ /* FWA to compensate for this. */
+
+ /* Find darkest point between 450 and 510nm */
+ ar = 1e6;
+ for (ww = 450.0; ww <= 510.0; ww += p->bw) {
+ double rr;
+ getval_lxspec(&p->imedia, &rr, ww);
+ DBGF((DBGA,"media %f = %f\n",ww,rr));
+
+ if (rr < ar) {
+ aw = ww;
+ ar = rr;
+ }
+ }
+
+ /* Find lightest point between A point+70 and 650 */
+ br = -1.0;
+ for (ww = aw+70.0; ww <= 630.0; ww += p->bw) {
+ double rr;
+ getval_lxspec(&p->imedia, &rr, ww);
+ DBGF((DBGA,"media %f = %f\n",ww,rr));
+ if (rr > br) {
+ bw = ww;
+ br = rr;
+ }
+ }
+ if (br < ar)
+ br = ar; /* Make flat rather than slope to the right */
+
+ DBGF((DBGA,"Cuttoff line params: A = %f %f, B = %f %f\n", aw, ar, bw, br));
+
+#ifdef STOCKFWA /* Use table shape as FWA basis */
+
+ /* Compute an Em that explains the bump over the flat line */
+ Em = 0.0;
+ for (ww = FWA1_emit.spec_wl_short; ww <= (FWA1_emit.spec_wl_long - 100.0); ww += p->bw) {
+ double Rl, rr;
+
+ /* Compute value of line at this wavelength */
+ Rl = (ww - aw)/(bw - aw) * (br - ar) + ar;
+
+ getval_lxspec(&p->imedia, &rr, ww); /* Media at this point */
+
+ if (rr > Rl) { /* Media is over the line */
+ double Ii;
+ double Eu;
+ double mm;
+
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised illuminant at this wavelength */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+ getval_lxspec(&FWA1_emit, &Eu, ww); /* FWA emission at this wavelength */
+ mm = ((rr - Rl) * Ii)/Eu;
+ if (mm > Em) {
+ DBGF((DBGA,"Update Em to %f at %fnm for target %f\n",mm,ww,rr-Rl));
+ Em = mm; /* Greater multiplier to explain bump */
+ }
+ }
+ }
+ DBGF((DBGA,"Em = %f\n",Em));
+
+ /* Setup spectrum to hold result over exected range */
+ /* and base media reflectance */
+ p->media = p->imedia; /* Take copy of media white */
+ p->emits = p->imedia; /* Structure copy */
+ xspect_denorm(&p->media); /* Set norm to 1.0 */
+ xspect_denorm(&p->emits);
+
+ /* Copy emission spectra that explains bump over line */
+ /* plus estimated media without FWA spectrum. */
+ for (i = 0; i < p->media.spec_n; i++) {
+ double Eu, Ii;
+ double Rm, Rmb;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+
+ ww = (p->media.spec_wl_long - p->media.spec_wl_short)
+ * ((double)i/(p->media.spec_n-1.0)) + p->media.spec_wl_short;
+
+ getval_lxspec(&FWA1_emit, &Eu, ww); /* FWA emission at this wavelength */
+ Eu *= Em;
+ p->emits.spec[i] = p->emits.norm * Eu; /* Remember FWA spectrum */
+
+ Rm = p->media.spec[i]/p->media.norm; /* Media at this point */
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised illuminant at this wavelength */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+ Rm *= Ii; /* Light reflected from media */
+
+ Rmb = Rm - Eu; /* Convert media to base media */
+ if (Rmb < 0.01)
+ Rmb = 0.01; /* This would be silly */
+ p->media.spec[i] = p->media.norm * Rmb/Ii; /* Convert media to base media */
+ DBGF((DBGA,"ww %f, Eu %f, Rm %f, Rmb %f\n",ww, Eu, Rm, Rmb));
+
+ }
+ /* Prevent silliness */
+ p->emits.spec[0] = 0.0;
+ p->emits.spec[p->emits.spec_n-1] = 0.0;
+
+#else /* Not STOCK_FWA */
+ /* Setup spectrum to hold result over exected range */
+ /* and base media reflectance */
+ p->media = p->imedia; /* Take copy of media white */
+ p->emits = p->imedia; /* Structure copy */
+ xspect_denorm(&p->media); /* Set norm to 1.0 */
+ xspect_denorm(&p->emits);
+
+ /* Compute emission spectra that explains bump over line */
+ /* plus estimated media without FWA spectrum. */
+ /* Do this from long to short to allow for "filter off" trigger */
+ flag = 1; /* Filter is active */
+ for (i = (p->media.spec_n-1); i >= 0; i--) {
+ double Rl, Rm, Rmb;
+ double fwi = 25.0; /* Smoothing filter width +/- */
+ int fres = 5; /* Smoothing filter resolution */
+ double tweight;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ /* Wavelength we're generating */
+ ww = (p->media.spec_wl_long - p->media.spec_wl_short)
+ * ((double)i/(p->media.spec_n-1.0)) + p->media.spec_wl_short;
+
+ /* Compute the base media estimate at this point from */
+ /* the triangular smoothed filter of the smaller of the */
+ /* measured media and the line */
+ tweight = 0.0;
+ Rmb = 0.0;
+ for (j = -fres; j <= fres; j++) {
+ double fww, weight;
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(j);
+#endif
+ fww = ww + (double)j/(double)fres * fwi;
+ weight = 1.0 - fabs((double)j/(double)fres);
+
+ Rl = (fww - aw)/(bw - aw) * (br - ar) + ar; /* Line at this point */
+ getval_lxspec(&p->imedia, &Rm, fww); /* Media at this point */
+
+ if (Rm < Rl)
+ Rl = Rm;
+
+ Rmb += Rl * weight;
+ tweight += weight;
+ }
+ Rmb /= tweight; /* Base media estimate */
+
+ /* Compute value of line and media at this wavelength */
+ Rl = (ww - aw)/(bw - aw) * (br - ar) + ar; /* Line at this point */
+
+ getval_lxspec(&p->imedia, &Rm, ww); /* Media at this point */
+ DBGF((DBGA,"ww %f, Rl %f, Rm %f, Rmb %f\n",ww,Rl,Rm,Rmb));
+
+ /* Stop following the filter once the actual media has crossed over it */
+ if (ww < 450.0 && Rm < Rmb)
+ flag = 0;
+
+ /* Don't follow smoothed at long wl or if media has caught up to filtered */
+ if (flag == 0 || ww > 570.0)
+ Rmb = Rm;
+
+ if (Rm > Rmb && ww <= 570.0) { /* Media is over the line */
+ double Ii;
+
+ p->media.spec[i] = p->media.norm * Rmb; /* Convert media to base media */
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised illuminant at this wavelength */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+
+ p->emits.spec[i] = p->emits.norm * (Rm - Rmb) * Ii;
+ DBGF((DBGA,"ww %fnm, Rm %f, Rmb %f, Eu %f\n",ww, Rm, Rmb, p->emits.spec[i]/p->emits.norm));
+
+ } else {
+ p->emits.spec[i] = 0.0;
+ }
+#ifdef DOPLOT
+ xx[i] = ww;
+ y1[i] = Rl;
+ y2[i] = Rm;
+ y3[i] = Rmb;
+ y4[i] = p->emits.spec[i]/p->emits.norm;
+#endif
+ }
+#ifdef DOPLOT
+ printf("Estimated vs. real media spectrum calculation\n");
+ do_plot6(xx,y1,y2,y3,y4,NULL,NULL,p->media.spec_n);
+#endif
+ /* Prevent silliness */
+ p->emits.spec[0] = 0.0;
+ p->emits.spec[p->emits.spec_n-1] = 0.0;
+#endif /* !STOCKFWA */
+
+ /* Compute level of UV stimulating FWA */
+ p->Sm = 0.0;
+ for (ww = FWA1_stim.spec_wl_short; ww <= FWA1_stim.spec_wl_long; ww += p->bw) {
+ double Ii;
+ double Su;
+
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised illuminant at this wavelength */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+ getval_lxspec(&FWA1_stim, &Su, ww); /* FWA stimulation profile at this wavelength */
+ p->Sm += Su * Ii;
+ }
+ DBGF((DBGA,"Sm = %f\n",p->Sm));
+
+ /* Compute FWA content of this media, for information purposes */
+ p->FWAc = 0.0;
+ for (ww = p->emits.spec_wl_short; ww <= p->emits.spec_wl_long; ww += p->bw) {
+ double Eu;
+
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+ p->FWAc += Eu;
+ }
+ p->FWAc /= p->Sm; /* Divided by stimulation */
+ DBGF((DBGA,"FWA content = %f\n",p->FWAc));
+
+ /* Turn on FWA compensation */
+ p->convert = xsp2cie_fwa_convert;
+ p->sconvert = xsp2cie_fwa_sconvert;
+ p->extract = xsp2cie_fwa_extract;
+ p->apply = xsp2cie_fwa_apply;
+
+#if defined(DOPLOT) || defined(DEBUG)
+ /* Print the estimated vs. real media spectrum */
+ for (i = 0, ww = p->media.spec_wl_short; ww <= p->media.spec_wl_long; ww += 1.0, i++) {
+ double Rm; /* Real media reflectance */
+ double Rmb; /* Media reflectance without FWA */
+ double Rmd; /* Estimated media reflectance with FWA */
+ double Ii;
+ double Eu;
+
+ getval_lxspec(&p->imedia, &Rm, ww); /* Media at this point */
+ getval_lxspec(&p->media, &Rmb, ww); /* Base Media */
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised illuminant at this wavelength */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+
+ Rmd = ((Ii * Rmb) + Eu)/Ii; /* Base Media plus FWA */
+ DBGF((DBGA,"%fnm, is %f should be %f, Rmb %f, Eu %f\n",ww, Rm, Rmd, Rmb, Eu));
+
+#ifdef DOPLOT
+ xx[i] = ww;
+// y1[i] = Rm;
+ y1[i] = Rmb;
+ y2[i] = Eu;
+ y3[i] = Rmd;
+#endif
+ }
+#ifdef DOPLOT
+ printf("Estimated vs. real media spectrum\n");
+ do_plot(xx,y1,y2,y3,i);
+#endif
+#endif /* DEBUG */
+
+ DBGF((DBGA,"We're done\n"));
+ return 0;
+}
+
+/* Set FWA given instrument illuminant and white media measurement */
+static int xsp2cie_set_fwa(xsp2cie *p, /* this */
+xspect *iillum, /* Spectrum of instrument illuminent */
+xspect *tillum, /* Spectrum of target/simulated instrument illuminant */
+ /* NULL to use observer illuminant. */
+xspect *media /* Spectrum of plain media measured under that instrument */
+) {
+ p->iillum = *iillum; /* Take copy of instrument illuminant */
+ xspect_denorm(&p->iillum); /* Remove normalisation factor */
+ if (tillum != NULL) {
+ p->tillum = *tillum; /* Take copy of target/simulated instrument illuminant */
+ xspect_denorm(&p->tillum); /* Remove normalisation factor */
+ } else {
+ p->tillum.spec_n = 0;
+ }
+ p->imedia = *media; /* Take copy of measured media */
+
+ return xsp2cie_set_fwa_imp(p);
+}
+
+/* Set FWA given updated conversion illuminant. */
+/* We assume that xsp2cie_set_fwa has been called first. */
+static int xsp2cie_update_fwa_custillum(
+xsp2cie *p, /* this */
+xspect *tillum, /* Spectrum of target/simulated instrument illuminant, */
+ /* NULL to use previous set_fwa() value. */
+xspect *custIllum /* Spectrum of observer illuminant */
+) {
+ if (tillum != NULL) {
+ p->tillum = *tillum; /* Take copy of target/simulated instrument illuminant */
+ xspect_denorm(&p->tillum); /* Remove normalisation factor */
+ }
+ p->illuminant = *custIllum;
+
+ return xsp2cie_set_fwa_imp(p);
+}
+
+/* Get Fluorescent Whitening Agent compensation information */
+/* return NZ if error */
+static void xsp2cie_get_fwa_info(
+xsp2cie *p,
+double *FWAc) {
+
+ if (FWAc != NULL)
+ *FWAc = p->FWAc;
+}
+
+/* Do the FWA corrected spectral to CIE conversion. */
+/* If the instrument and target illuminant are the same, */
+/* then FWA correction is bypassed. */
+/* Note that the input spectrum normalisation value is used. */
+/* Emissive spectral values are assumed to be in mW/nm, and sampled */
+/* rather than integrated if they are not at 1nm spacing. */
+static void xsp2cie_fwa_sconvert(
+xsp2cie *p, /* this */
+xspect *sout, /* Return corrected input spectrum (may be NULL, or same as imput) */
+double *out, /* Return XYZ or D50 Lab value (may be NULL) */
+xspect *in /* Spectrum to be converted */
+) {
+ double ww;
+ int i, j, k;
+ double Emc, Smc; /* Emission and Stimulation multipiers for instrument meas. */
+ double Emct, Smct; /* Emission and Stimulation multipiers for target illum. */
+ double scale = 0.0;
+ xspect tsout; /* Temporary sout */
+ double wout[3]; /* Working CIE out */
+#ifdef DEBUG
+ double chout[3]; /* Out check values */
+ double oout[3];
+#endif /* DEBUG */
+#ifdef DOPLOT_ALL_FWA
+ double xx[XSPECT_MAX_BANDS];
+ double y1[XSPECT_MAX_BANDS];
+ double y2[XSPECT_MAX_BANDS];
+ double y3[XSPECT_MAX_BANDS];
+ int plix = 0;
+#endif /* DOPLOT_ALL_FWA */
+
+ tsout.spec_n = 0;
+ tsout.spec_wl_short = 0.0;
+ tsout.spec_wl_long = 0.0;
+ tsout.norm = 0.0;
+
+#define MIN_ILLUM 1e-8 /* Minimum assumed illumination level at wavelength */
+#define MIN_REFL 1e-6 /* Minimum assumed reflectance at wavelength */
+
+ /* With colorant, estimate stimulation level of FWA for instrument illuminant */
+ /* and for target illuminant. Because the colorant estimate depends on the FWA */
+ /* estimate, and the FWA emissions can contribute to FWA stimulation, */
+ /* we itterate a few times to allow this to converge. */
+ Emc = Emct = 0.0;
+ for (k = 0; k < 4; k++) {
+ Smct = Smc = 0.0;
+ for (ww = FWA1_stim.spec_wl_short; ww <= FWA1_stim.spec_wl_long; ww += p->bw) {
+ double Kc; /* FWA contribution for instrument illum */
+ double Kct; /* FWA contribution for target illum */
+ double Ii; /* Instrument illuminant level */
+ double It; /* Target illuminant level */
+ double Eu; /* FWA emmission profile */
+ double Rc; /* Measured reflectance under inst. illum. */
+ double Rmb; /* Media reflectance measured on instrument */
+ double Rcch; /* Half colorant reflectance value */
+ double Su; /* FWA sensitivity */
+
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+ Kc = Emc * Eu; /* FWA contribution under inst. illum. */
+ Kct = Emct * Eu; /* FWA contribution under target illum. */
+
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised instr. illuminant at wavelength */
+ if (Ii < MIN_ILLUM)
+ Ii = MIN_ILLUM;
+
+ getval_lxspec(&p->tillum, &It, ww);/* Normalised target. illuminant at wavelength */
+ if (It < MIN_ILLUM)
+ It = MIN_ILLUM;
+
+ getval_lxspec(&p->media, &Rmb, ww); /* Base media reflectance at this wavelength */
+ if (Rmb < MIN_REFL)
+ Rmb = MIN_REFL;
+
+ getval_lxspec(in, &Rc, ww) ; /* Media + colorant reflectance at wavelength */
+ if (Rc < 0.0)
+ Rc = 0.0;
+
+#ifdef NEVER
+ Rcch = sqrt(Rc/Rmb); /* Half reflectance estimate (valid if no FWA) */
+
+#else
+ /* Solve for underlying colorant half reflectance, discounting FWA */
+ if (Rmb <= MIN_REFL) /* Hmm. */
+ Rcch = sqrt(fabs(Rmb));
+ else
+ Rcch = (-Kc + sqrt(Kc * Kc + 4.0 * Ii * Ii * Rmb * Rc))/(2.0 * Ii * Rmb);
+#endif
+
+ getval_lxspec(&FWA1_stim, &Su, ww); /* FWA stimulation sensitivity this wavelength */
+
+
+ Smc += Su * (Ii * Rcch + Kc);
+ Smct += Su * (It * Rcch + Kct);
+ DBGF((DBGA,"at %.1fnm, Rmb %f, Rc %f, Rch %f, Rcch %f, Ii %f, It %f, Kct %f, Smc %f, Smct %f,\n",ww,Rmb,Rc,sqrt(Rc),Rcch,Ii,It,Kct,Su * (Ii * Rcch + Kc),Su * (It * Rcch + Kct)));
+ }
+ Emc = Smc/p->Sm; /* FWA Emmsion muliplier with colorant for instr. illum. */
+ Emct = Smct/p->Sm; /* FWA Emmsion muliplier with colorant for target illum. */
+
+ DBGF((DBGA,"Itteration %d, Smc %f, Smct %f, Emc %f, Emct %f\n\n",k, Smc,Smct,Emc,Emct));
+ }
+
+ for (j = 0; j < 3; j++) {
+ wout[j] = 0.0;
+#ifdef DEBUG
+ chout[j] = 0.0;
+#endif /* DEBUG */
+ }
+
+ /* Compute CIE output over observer range in 1nm increments */
+ scale = 0.0;
+ for (ww = p->observer[1].spec_wl_short; ww <= p->observer[1].spec_wl_long; ww += p->bw) {
+ double Kc; /* FWA contribution for instrument illum */
+ double Kct; /* FWA contribution for target illum */
+ double Ii; /* Instrument illuminant level */
+ double It; /* Target illuminant level */
+ double Io; /* Observer illuminant level */
+ double Rmb; /* Base media reflectance estimate */
+ double Eu; /* FWA emmission profile */
+ double Rc; /* Measured reflectance under inst. illum. */
+ /* Rch Measured half reflectance under inst. illum */
+ double Rcch; /* Corrected Rc colorant half reflectance */
+ double Rct; /* Corrected Rc for target illuminant */
+
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+ Kc = Emc * Eu; /* FWA contribution under inst. illum. */
+ Kct = Emct * Eu; /* FWA contribution under target illum. */
+
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised instr. illuminant at wavelength */
+ if (Ii < MIN_ILLUM)
+ Ii = MIN_ILLUM;
+
+ getval_lxspec(&p->tillum, &It, ww);/* Normalised target. illuminant at wavelength */
+ if (It < MIN_ILLUM)
+ It = MIN_ILLUM;
+
+ getval_lxspec(&p->media, &Rmb, ww); /* Base media reflectance at this wavelength */
+ if (Rmb < MIN_REFL)
+ Rmb = MIN_REFL;
+
+ getval_lxspec(in, &Rc, ww) ; /* Media + colorant reflectance at wavelength */
+ if (Rc < 0.0)
+ Rc = 0.0;
+
+ /* Solve for underlying colorant half transmittance, discounting FWA */
+ if (Rmb <= MIN_REFL) /* Hmm. */
+ Rcch = sqrt(fabs(Rmb));
+ else
+ Rcch = (-Kc + sqrt(Kc * Kc + 4.0 * Ii * Ii * Rmb * Rc))/(2.0 * Ii * Rmb);
+
+ /* Estimated corrected reflectance */
+ Rct = ((It * Rcch * Rmb + Kct) * Rcch)/It;
+
+ DBGF((DBGA,"at %.1fnm, Rmb %f, Rc %f, Rch %f, Rcch %f, Ii %f, It %f, Kct %f, Rct %f\n",ww,Rmb,Rc,sqrt(Rc),Rcch,Ii,It,Kct,Rct));
+
+ if (p->insteqtarget) /* Ignore FWA corrected value if same illuminant */
+ Rct = Rc;
+
+#ifdef DOPLOT_ALL_FWA
+ xx[plix] = ww;
+ y1[plix] = Rc; /* Uncorrected reflectance */
+// y2[plix] = Rct - Rc; /* Difference between corrected and uncorrected */
+// y2[plix] = Rcch * Rcch; /* Estimated underlying colorant reflectance without FWA */
+// y2[plix] = Rmb; /* Base media relectance estimate */
+ y2[plix] = Kct; /* FWA contribution under target illuminant */
+ y3[plix++] = Rct; /* Corrected reflectance */
+#endif /* DOPLOT_ALL_FWA */
+
+ /* Observer illuminant */
+ getval_lxspec(&p->oillum, &Io, ww); /* Normalised observer illuminant */
+
+ /* Compute CIE result */
+ for (j = 0; j < 3; j++) {
+ double O;
+ getval_lxspec(&p->observer[j], &O, ww);
+ if (j == 1)
+ scale += Io * O; /* Integrate Y illuminant/observer values */
+ wout[j] += Rct * Io * O; /* Corrected refl. * Observer illuminant */
+#ifdef DEBUG
+ chout[j] += Rc * It * O;
+#endif /* DEBUG */
+ }
+ }
+ if (p->isemis) {
+ scale = 0.683002; /* Convert from mW/m^2 to Lumens/m^2 */
+ /* (== 683 Luments/Watt/m^2) */
+ } else {
+ scale = 1.0/scale;
+ }
+ for (j = 0; j < 3; j++) { /* Scale for illuminant/observer normalisation of Y */
+ wout[j] *= scale;
+#ifdef CLAMP_XYZ
+ if (p->clamp && wout[j] < 0.0)
+ wout[j] = 0.0; /* Just to be sure we don't get silly values */
+#endif /* CLAMP_XYZ */
+ }
+
+#ifdef DEBUG
+ for (j = 0; j < 3; j++) { /* Scale for illuminant/observer normalisation of Y */
+ chout[j] *= scale;
+#ifdef CLAMP_XYZ
+ if (p->clamp && chout[j] < 0.0)
+ chout[j] = 0.0; /* Just to be sure we don't get silly values */
+#endif /* CLAMP_XYZ */
+ }
+ icmXYZ2Lab(&icmD50, oout, wout);
+ icmXYZ2Lab(&icmD50, chout, chout);
+ DBGF((DBGA,"Compensated %f %f %f, uncompensated %f %f %f\n",
+ oout[0], oout[1], oout[2], chout[0], chout[1], chout[2]));
+#endif /* DEBUG */
+
+#ifdef DOPLOT_ALL_FWA
+ printf("FWA compensated spectrum for sample\n");
+ do_plot(xx,y1,y2,y3,plix);
+#endif /* DOPLOT_ALL_FWA */
+
+ /* Do it again for output over optional returned spectrum range */
+ if (sout != NULL) {
+ tsout.spec_n = in->spec_n;
+ tsout.spec_wl_short = in->spec_wl_short;
+ tsout.spec_wl_long = in->spec_wl_long;
+ tsout.norm = in->norm;
+
+ for (i = 0; i < in->spec_n; i++) {
+ double Kc; /* FWA contribution for instrument illum */
+ double Kct; /* FWA contribution for target illum */
+ double Ii; /* Instrument illuminant level */
+ double It; /* Target/simulated instrument illuminant level */
+ double Rmb; /* Base media reflectance estimate */
+ double Eu; /* FWA emmission profile */
+ double Rc; /* Reflectance under inst. illum. */
+ double Rcch; /* Corrected Rc half reflectance */
+ double Rct; /* Corrected Rc for target illuminant */
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ ww = (in->spec_wl_long - in->spec_wl_short)
+ * ((double)i/(in->spec_n-1.0)) + in->spec_wl_short;
+
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+ Kc = Emc * Eu; /* FWA contribution under inst. illum. */
+ Kct = Emct * Eu; /* FWA contribution under target illum. */
+
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised instr. illuminant at wavelength */
+ if (Ii < MIN_ILLUM)
+ Ii = MIN_ILLUM;
+
+ getval_lxspec(&p->tillum, &It, ww);/* Normalised target. illuminant at wavelength */
+ if (It < MIN_ILLUM)
+ It = MIN_ILLUM;
+
+ getval_lxspec(&p->media, &Rmb, ww); /* Base media reflectance at this wavelength */
+ if (Rmb < MIN_REFL)
+ Rmb = MIN_REFL;
+
+ getval_lxspec(in, &Rc, ww) ; /* Media + colorant reflectance at wavelength */
+ if (Rc < 0.0)
+ Rc = 0.0;
+
+ if (Rmb < MIN_REFL) /* Hmm. */
+ Rcch = sqrt(fabs(Rmb));
+ else
+ Rcch = (-Kc + sqrt(Kc * Kc + 4.0 * Ii * Ii * Rmb * Rc))/(2.0 * Ii * Rmb);
+
+ Rct = ((It * Rcch * Rmb + Kct) * Rcch)/It;
+
+ if (p->insteqtarget) /* Ignore FWA corrected value if same illuminant */
+ Rct = Rc;
+
+ tsout.spec[i] = tsout.norm * Rct;
+ }
+ }
+
+ /* If Lab is target, convert to D50 Lab */
+ if (p->doLab) {
+ icmXYZ2Lab(&icmD50, wout, wout);
+ }
+
+ if (out != NULL) {
+ out[0] = wout[0];
+ out[1] = wout[1];
+ out[2] = wout[2];
+ }
+
+ if (sout != NULL) {
+ *sout = tsout; /* Structure copy */
+ }
+
+#undef MIN_ILLUM
+#undef MIN_REFL
+
+}
+
+/* Normal conversion without returning spectrum */
+static void xsp2cie_fwa_convert(xsp2cie *p, double *out, xspect *in) {
+ xsp2cie_fwa_sconvert(p, NULL, out, in);
+}
+
+/* Extract the colorant reflectance value from the media. Takes FWA */
+/* into account if set. FWA must be set. */
+static int xsp2cie_fwa_extract(xsp2cie *p, /* this */
+xspect *out, /* Extracted colorant refl. spectrum */
+xspect *in /* Spectrum to be converted, normalised by norm */
+) {
+ double ww;
+ int i, j, k;
+ double Emc, Smc; /* Emission and Stimulation multipiers for instrument meas. */
+
+#ifdef DOPLOT_ALL_FWA
+ double xx[XSPECT_MAX_BANDS];
+ double y1[XSPECT_MAX_BANDS];
+ double y2[XSPECT_MAX_BANDS];
+ double y3[XSPECT_MAX_BANDS];
+ int plix = 0;
+#endif /* DOPLOT_ALL_FWA */
+
+ /* With colorant, estimate stimulation level of FWA for instrument illuminant */
+ /* and for target illuminant. Because the colorant estimate depends on the FWA */
+ /* estimate, and the FWA emissions can contribute to FWA stimulation, */
+ /* we itterate a few times to allow this to converge. */
+ Emc = 0.0;
+ for (k = 0; k < 4; k++) {
+ Smc = 0.0;
+ for (ww = FWA1_stim.spec_wl_short; ww <= FWA1_stim.spec_wl_long; ww += p->bw) {
+ double Kc; /* FWA contribution for instrument illum */
+ double Ii; /* Instrument illuminant level */
+ double Su; /* FWA sensitivity */
+ double Rmb; /* Media reflectance measured on instrument */
+ double Eu; /* FWA emmission profile */
+ double Rc; /* Reflectance under inst. illum. */
+ double Rcch; /* Half colorant reflectance value */
+
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+ Kc = Emc * Eu; /* FWA contribution under inst. illum. */
+
+ getval_lxspec(&p->media, &Rmb, ww); /* Base Media */
+ getval_lxspec(in, &Rc, ww); /* Media + colorant reflectance at wavelength + FWA */
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised instrument illuminant */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+
+ if (Rmb < 1e-9) /* Hmm. */
+ Rcch = sqrt(fabs(Rmb));
+ else
+ Rcch = (-Kc + sqrt(Kc * Kc + 4.0 * Ii * Ii * Rmb * Rc))/(2.0 * Ii * Rmb);
+
+ getval_lxspec(&FWA1_stim, &Su, ww); /* FWA stimulation sensitivity this wavelength */
+ Smc += Su * (Ii * Rcch + Kc);
+
+//DBGF((DBGA,"ww = %f, Rmb %f, Rcch %f, Ii %f, Su %f, Smc %f\n", ww,Rmb,Rcch,Ii,Su,Smc));
+ }
+ Emc = Smc/p->Sm; /* FWA Emmsion muliplier with colorant for instr. illum. */
+ }
+
+ DBGF((DBGA,"extract:\n"));
+ DBGF((DBGA,"Smc = %f\n",Smc));
+ DBGF((DBGA,"Emc = %f\n",Emc));
+
+ out->spec_n = in->spec_n;
+ out->spec_wl_short = in->spec_wl_short;
+ out->spec_wl_long = in->spec_wl_long;
+ out->norm = in->norm;
+
+ for (i = 0; i < in->spec_n; i++) {
+ double Kc; /* FWA contribution for instrument illum */
+ double Ii; /* Instrument illuminant level */
+ double Rmb; /* Base media reflectance estimate */
+ double Eu; /* FWA emmission profile */
+ double Rc; /* Reflectance under inst. illum. */
+ double Rcch; /* Corrected Rc half reflectance */
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ ww = (in->spec_wl_long - in->spec_wl_short)
+ * ((double)i/(in->spec_n-1.0)) + in->spec_wl_short;
+
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+ Kc = Emc * Eu; /* FWA contribution under inst. illum. */
+
+ getval_lxspec(&p->media, &Rmb, ww); /* Base Media */
+ getval_lxspec(in, &Rc, ww); /* Media + colorant reflectance at wavelength + FWA */
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised instrument illuminant */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+
+ if (Rmb < 1e-9) /* Hmm. */
+ Rcch = sqrt(fabs(Rmb));
+ else
+ Rcch = (-Kc + sqrt(Kc * Kc + 4.0 * Ii * Ii * Rmb * Rc))/(2.0 * Ii * Rmb);
+
+ Rcch *= Rcch; /* Full reflectance value */
+
+ out->spec[i] = out->norm * Rcch;
+
+#ifdef DOPLOT_ALL_FWA
+ xx[plix] = ww;
+ y1[plix] = Rmb; /* Base media */
+ y2[plix] = Rc; /* Uncorrected reflectance */
+ y3[plix] = Rcch; /* Underlying colorant reflectance without FWA */
+ plix++;
+#endif /* DOPLOT_ALL_FWA */
+ }
+#ifdef DOPLOT_ALL_FWA
+ printf("FWA compensated extraction for sample\n");
+ do_plot(xx,y1,y2,y3,plix);
+#endif /* DOPLOT_ALL_FWA */
+ return 0;
+}
+
+
+/* Apply the colorant reflectance value from the media. Takes FWA */
+/* into account if set. DOESN'T convert to FWA target illumination! */
+/* FWA must be set. */
+static int xsp2cie_fwa_apply(xsp2cie *p, /* this */
+xspect *out, /* Applied refl. spectrum */
+xspect *in /* Colorant reflectance to be applied */
+) {
+ double ww;
+ int i, j, k;
+ double Emc, Smc; /* Emission and Stimulation multipiers for instrument meas. */
+
+#ifdef DOPLOT_ALL_FWA
+ double xx[XSPECT_MAX_BANDS];
+ double y1[XSPECT_MAX_BANDS];
+ double y2[XSPECT_MAX_BANDS];
+ double y3[XSPECT_MAX_BANDS];
+ int plix = 0;
+#endif /* DOPLOT_ALL_FWA */
+
+ /* With colorant, estimate stimulation level of FWA for instrument illuminant. */
+ /* We itterate a few times to allow for FWA self stimulation. */
+ Emc = 0.0;
+ for (k = 0; k < 4; k++) {
+ Smc = 0.0;
+ for (ww = FWA1_stim.spec_wl_short; ww <= FWA1_stim.spec_wl_long; ww += p->bw) {
+ double Kc; /* FWA contribution for instrument illum */
+ double Ii; /* Instrument illuminant level */
+ double Eu; /* FWA emmission profile */
+ double Su; /* FWA sensitivity */
+ double Rcch; /* Half colorant reflectance value */
+
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+ Kc = Emc * Eu; /* FWA contribution under inst. illum. */
+
+ getval_lxspec(in, &Rcch, ww); /* Colorant reflectance at wavelength */
+ Rcch = sqrt(Rcch); /* Half reflectance estimate (valid if no FWA) */
+
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised instr. illuminant at wavelength */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+
+ getval_lxspec(&FWA1_stim, &Su, ww); /* FWA stimulation sensitivity this wavelength */
+ Smc += Su * (Ii * Rcch + Kc);
+//DBGF((DBGA,"ww = %f, Rcch %f, Ii %f, Su %f, Smc %f\n", ww,Rcch,Ii,Su,Smc));
+ }
+ Emc = Smc/p->Sm; /* FWA Emmsion muliplier with colorant for instr. illum. */
+ }
+
+ DBGF((DBGA,"apply:\n"));
+ DBGF((DBGA,"Smc = %f\n",Smc));
+ DBGF((DBGA,"Emc = %f\n",Emc));
+
+ out->spec_n = in->spec_n;
+ out->spec_wl_short = in->spec_wl_short;
+ out->spec_wl_long = in->spec_wl_long;
+ out->norm = in->norm;
+
+ for (i = 0; i < in->spec_n; i++) {
+ double Kc; /* FWA contribution for instrument illum */
+ double Ii; /* Instrument illuminant level */
+ double Rmb; /* Base media reflectance estimate */
+ double Eu; /* FWA emmission profile */
+ double Rc; /* Reflectance under inst. illum. */
+ double Rcch; /* Rc half reflectance */
+ double RcI; /* Reconstituted Rc for inst. illuminant times illuminant */
+
+#if defined(__APPLE__) && defined(__POWERPC__)
+ gcc_bug_fix(i);
+#endif
+ ww = (in->spec_wl_long - in->spec_wl_short)
+ * ((double)i/(in->spec_n-1.0)) + in->spec_wl_short;
+
+ getval_lxspec(&p->emits, &Eu, ww); /* FWA emission at this wavelength */
+ Kc = Emc * Eu; /* FWA contribution under inst. illum. */
+
+ getval_lxspec(&p->media, &Rmb, ww); /* Base Media */
+ getval_lxspec(in, &Rcch, ww); /* Colorant reflectance at wavelength */
+ Rcch = sqrt(Rcch); /* Half reflectance at wavelength */
+ if (Rmb < 1e-9) /* Hmm. */
+ Rcch = sqrt(fabs(Rmb));
+
+ getval_lxspec(&p->iillum, &Ii, ww); /* Normalised instrument illuminant */
+ if (Ii < 1e-9)
+ Ii = 1e-9;
+
+ RcI = (Ii * Rcch * Rmb + Kc) * Rcch;
+
+ out->spec[i] = out->norm * RcI/Ii; /* Reconstituted reflectance */
+#ifdef DOPLOT_ALL_FWA
+ xx[plix] = ww;
+ y1[plix] = Rmb; /* Base media */
+ y2[plix] = Rcch; /* Underlying colorant reflectance without FWA */
+ y3[plix] = RcI/Ii; /* Reconstituted reflectance */
+ plix++;
+#endif /* DOPLOT_ALL_FWA */
+ }
+#ifdef DOPLOT_ALL_FWA
+ printf("FWA compensated application for sample\n");
+ do_plot(xx,y1,y2,y3,plix);
+#endif /* DOPLOT_ALL_FWA */
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+#endif /* !SALONEINSTLIB */
+
+/* Do the normal spectral to CIE conversion. */
+/* Note that the input spectrum normalisation value is used. */
+/* Emissive spectral values are assumed to be in mW/nm, and sampled */
+/* rather than integrated if they are not at 1nm spacing. */
+void xsp2cie_sconvert(
+xsp2cie *p, /* this */
+xspect *sout, /* Return input spectrum (may be NULL) */
+double *out, /* Return XYZ or D50 Lab value */
+xspect *in /* Spectrum to be converted */
+) {
+ int j;
+ double scale = 0.0;
+
+ /* Compute the XYZ values (normalised to 1.0) */
+ for (j = 0; j < 3; j++) {
+ double ww;
+
+ /* Integrate at 1nm intervals over the observer range (as */
+ /* per CIE recommendations). Lower resolution spectra are */
+ /* upsampled using linear/3rd order polinomial interpolated */
+ /* (also as per CIE recommendations), and consistent (?) with the */
+ /* assumption of a triangular spectral response made in the */
+ /* ANSI CGATS.5-1993 spec. If illumninant or material spectra */
+ /* values are truncated at the extremes, then the last valid values */
+ /* are used, also consistent with CIE and ANSI CGATS recommendations. */
+ out[j] = 0.0;
+ for (ww = p->observer[j].spec_wl_short; ww <= p->observer[j].spec_wl_long; ww += 1.0) {
+ double I, O, S;
+ getval_xspec(&p->illuminant, &I, ww);
+ getval_xspec(&p->observer[j], &O, ww);
+ getval_xspec(in, &S, ww);
+ if (j == 1)
+ scale += I * O; /* Integrate Y illuminant/observer values */
+ out[j] += I * O * S;
+ }
+ }
+ if (p->isemis) {
+ scale = 0.683002; /* Convert from mW/m^2 to Lumens/m^2 */
+ /* (== 683 Luments/Watt/m^2) */
+ } else {
+ scale = 1.0/scale;
+ }
+ for (j = 0; j < 3; j++) { /* Scale for illuminant/observer normalisation of Y */
+ out[j] *= scale;
+#ifdef CLAMP_XYZ
+ if (p->clamp && out[j] < 0.0)
+ out[j] = 0.0; /* Just to be sure we don't get silly values */
+#endif /* CLAMP_XYZ */
+ }
+
+#ifndef SALONEINSTLIB
+ /* If Lab is target, convert to D50 Lab */
+ if (p->doLab) {
+ icmXYZ2Lab(&icmD50, out, out);
+ }
+#endif /* !SALONEINSTLIB */
+
+ if (sout != NULL) {
+ *sout = *in; /* Structure copy */
+ }
+}
+
+/* Normal Tristumulus conversion */
+void xsp2cie_convert(xsp2cie *p, double *out, xspect *in) {
+ xsp2cie_sconvert(p, NULL, out, in);
+}
+
+void xsp2cie_del(
+xsp2cie *p
+) {
+ free(p);
+ return;
+}
+
+/* Create and return a new spectral conversion object */
+xsp2cie *new_xsp2cie(
+icxIllumeType ilType, /* Illuminant */
+xspect *custIllum, /* Optional custom illuminant */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+icColorSpaceSignature rcs, /* Return color space, icSigXYZData or icSigLabData */
+ /* ** Must be icSigXYZData if SALONEINSTLIB ** */
+icxClamping clamp /* NZ to clamp XYZ/Lab to be +ve */
+) {
+ xsp2cie *p;
+
+ if ((p = (xsp2cie *) calloc(1,sizeof(xsp2cie))) == NULL)
+ return NULL;
+
+ p->isemis = 0;
+ switch (ilType) {
+ case icxIT_none:
+ p->illuminant = il_none; /* Emissive */
+ p->isemis = 1;
+ break;
+ case icxIT_custom:
+ p->illuminant = *custIllum;
+ break;
+ case icxIT_A:
+ p->illuminant = il_A;
+ break;
+ case icxIT_C:
+ p->illuminant = il_C;
+ break;
+ case icxIT_default:
+ case icxIT_D50:
+ p->illuminant = il_D50;
+ break;
+ case icxIT_D50M2:
+ if (il_D50M2.spec_n == 0)
+ uv_filter(&il_D50M2, &il_D50);
+ p->illuminant = il_D50M2;
+ break;
+ case icxIT_D65:
+ p->illuminant = il_D65;
+ break;
+ case icxIT_E:
+ p->illuminant = il_none;
+ break;
+#ifndef SALONEINSTLIB
+ case icxIT_F5:
+ p->illuminant = il_F5;
+ break;
+ case icxIT_F8:
+ p->illuminant = il_F8;
+ break;
+ case icxIT_F10:
+ p->illuminant = il_F10;
+ break;
+ case icxIT_Spectrocam:
+ p->illuminant = il_Spectrocam;
+ break;
+#endif /* !SALONEINSTLIB */
+ default:
+ DBGF((DBGA,"new_xsp2cie() unrecognised illuminant 0x%x\n",ilType));
+ free(p);
+ return NULL;
+ }
+
+ /* Do 3 structure copies to record observer sensitivity curves */
+ switch (obType) {
+ case icxOT_custom:
+ p->observer[0] = custObserver[0];
+ p->observer[1] = custObserver[1];
+ p->observer[2] = custObserver[2];
+ break;
+ case icxOT_default:
+ case icxOT_CIE_1931_2:
+ p->observer[0] = ob_CIE_1931_2[0];
+ p->observer[1] = ob_CIE_1931_2[1];
+ p->observer[2] = ob_CIE_1931_2[2];
+ break;
+ case icxOT_CIE_1964_10:
+ p->observer[0] = ob_CIE_1964_10[0];
+ p->observer[1] = ob_CIE_1964_10[1];
+ p->observer[2] = ob_CIE_1964_10[2];
+ break;
+#ifndef SALONEINSTLIB
+ case icxOT_Stiles_Burch_2:
+ p->observer[0] = ob_Stiles_Burch_2[0];
+ p->observer[1] = ob_Stiles_Burch_2[1];
+ p->observer[2] = ob_Stiles_Burch_2[2];
+ break;
+ case icxOT_Judd_Voss_2:
+ p->observer[0] = ob_Judd_Voss_2[0];
+ p->observer[1] = ob_Judd_Voss_2[1];
+ p->observer[2] = ob_Judd_Voss_2[2];
+ break;
+ case icxOT_CIE_1964_10c:
+ p->observer[0] = ob_CIE_1964_10c[0];
+ p->observer[1] = ob_CIE_1964_10c[1];
+ p->observer[2] = ob_CIE_1964_10c[2];
+ break;
+ case icxOT_Shaw_Fairchild_2:
+ p->observer[0] = ob_Shaw_Fairchild_2[0];
+ p->observer[1] = ob_Shaw_Fairchild_2[1];
+ p->observer[2] = ob_Shaw_Fairchild_2[2];
+ break;
+#endif /* !SALONEINSTLIB */
+ default:
+ DBGF((DBGA,"new_xsp2cie() unrecognised observer type 0x%x\n",obType));
+ free(p);
+ return NULL;
+ }
+
+ if (rcs == icSigXYZData)
+ p->doLab = 0;
+#ifndef SALONEINSTLIB
+ else if (rcs == icSigLabData)
+ p->doLab = 1;
+#endif /* !SALONEINSTLIB */
+ else {
+ DBGF((DBGA,"new_xsp2cie() unrecognised CIE type 0x%x",rcs));
+ free(p);
+ return NULL;
+ }
+
+ p->clamp = clamp;
+
+ p->convert = xsp2cie_convert;
+ p->sconvert = xsp2cie_sconvert;
+#ifndef SALONEINSTLIB
+ p->set_mw = xsp2cie_set_mw; /* Default no media white */
+ p->set_fwa = xsp2cie_set_fwa; /* Default no FWA compensation */
+ p->update_fwa_custillum = xsp2cie_update_fwa_custillum;
+ p->get_fwa_info = xsp2cie_get_fwa_info;
+ p->extract = xsp2cie_extract;
+ p->apply = xsp2cie_apply;
+#endif /* !SALONEINSTLIB */
+ p->del = xsp2cie_del;
+
+ return p;
+}
+
+
+#ifndef SALONEINSTLIB
+/* -------------------------------------------------------- */
+
+/* Return the spectrum locus rangefor the given observer */
+/* return 0 on sucecss, nz if observer not known */
+int icx_spectrum_locus_range(double *min_wl, double *max_wl, icxObserverType obType) {
+ xspect *sp[3];
+ if (standardObserver(sp, obType))
+ return 1;
+ if (min_wl != NULL)
+ *min_wl = sp[0]->spec_wl_short;
+ if (max_wl != NULL)
+ *max_wl = sp[0]->spec_wl_long;
+
+ return 0;
+}
+
+/* Return an XYZ that is on the spectrum locus for the given observer. */
+/* wl is the input wavelength in the range icx_spectrum_locus_range(), */
+/* and return clipped result if outside this range. */
+/* Return nz if observer unknown. */
+int icx_spectrum_locus(double xyz[3], double wl, icxObserverType obType) {
+ xspect *sp[3];
+
+ DBGF((DBGA,"icx_spectrum_locus got obs %d wl %f\n",obType, wl));
+
+ if (standardObserver(sp, obType))
+ return 1;
+
+ if (wl < sp[0]->spec_wl_short)
+ wl = sp[0]->spec_wl_short;
+ if (wl > sp[0]->spec_wl_long)
+ wl = sp[0]->spec_wl_long;
+
+ xyz[0] = value_xspect(sp[0], wl);
+ xyz[1] = value_xspect(sp[1], wl);
+ xyz[2] = value_xspect(sp[2], wl);
+
+ DBGF((DBGA,"returning %f %f %f\n", xyz[0], xyz[1], xyz[2]));
+
+ return 0;
+}
+
+/* Init a xslpoly */
+/* Return nz on error */
+static int icx_init_locus_poly(icxObserverType obType) {
+ xslpoly *poly;
+
+ if ((poly = spectral_locus_poligon(obType)) == NULL)
+ return 1;
+
+ /* Initialise (should have a mutex!) */
+ if (poly->n == 0) {
+ int i, j, c;
+ double Yxy[3];
+ double xyz[3];
+ xspect *sp[3];
+double tt[3][3];
+
+ if (standardObserver(sp, obType))
+ return 3;
+
+ poly->n = sp[0]->spec_n;
+ poly->xmin = poly->ymin = 1e6;
+ poly->xmax = poly->ymax = -1e6;
+
+ for (i = 0; i < poly->n; i++) {
+ xyz[0] = sp[0]->spec[i];
+ xyz[1] = sp[1]->spec[i];
+ xyz[2] = sp[2]->spec[i];
+
+ icmXYZ2Yxy(Yxy, xyz);
+
+ poly->x[i] = Yxy[1];
+ poly->y[i] = Yxy[2];
+ if (poly->x[i] < poly->xmin)
+ poly->xmin = poly->x[i];
+ if (poly->x[i] > poly->xmax)
+ poly->xmax = poly->x[i];
+ if (poly->y[i] < poly->ymin)
+ poly->ymin = poly->y[i];
+ if (poly->y[i] > poly->ymax)
+ poly->ymax = poly->y[i];
+ }
+
+ /* Select 3 points for inner triangle in RGB order */
+ poly->tx[0] = poly->x[poly->n - 1];
+ poly->ty[0] = poly->y[poly->n - 1];
+
+ xyz[0] = value_xspect(sp[0], 517.0);
+ xyz[1] = value_xspect(sp[1], 517.0);
+ xyz[2] = value_xspect(sp[2], 517.0);
+ icmXYZ2Yxy(Yxy, xyz);
+ poly->tx[1] = Yxy[1];
+ poly->ty[1] = Yxy[2];
+
+ poly->tx[2] = poly->x[0];
+ poly->ty[2] = poly->y[0];
+
+ /* Compute distance from triangles to 0.3, 0.3 */
+// for (i = 0; i < 3; i++) {
+// poly->eed[i] = sqrt((poly->tx[i] - 0.3) * (poly->tx[i] - 0.3)
+// + (poly->ty[i] - 0.3) * (poly->ty[i] - 0.3));
+// }
+
+ /* Compute baricentric equations */
+ for (i = 0; i < 3; i++) {
+ tt[0][i] = poly->tx[i];
+ tt[1][i] = poly->ty[i];
+ tt[2][i] = 1.0;
+ }
+ if (icmInverse3x3(poly->be, tt))
+ error("icx_init_locus_poly: Matrix inversion failed");
+
+ /* Compute baricentric of 0.3 0.3 */
+ /* (Not currently used. How to move center to 0.3 0.3 ?? */
+// for (i = 0; i < 3; i++)
+// poly->eed[i] = poly->be[i][0] * 0.3 + poly->be[i][1] * 0.3 + poly->be[i][2];
+ }
+ return 0;
+}
+
+/* Determine whether the given XYZ is outside the spectrum locus */
+/* Return 0 if within locus */
+/* Return 1 if outside locus */
+/* Return 2 if unknown (bad observer) */
+int icx_outside_spec_locus(double xyz[3], icxObserverType obType) {
+ int i, j, c;
+ xslpoly *poly;
+ double Yxy[3];
+
+ if ((poly = spectral_locus_poligon(obType)) == NULL)
+ return 2;
+
+ /* Init poly if needed */
+ if (poly->n == 0 && icx_init_locus_poly(obType))
+ return 2;
+
+ icmXYZ2Yxy(Yxy, xyz);
+
+ /* Quick test - bounding box */
+ if (Yxy[1] < poly->xmin || Yxy[1] > poly->xmax
+ || Yxy[2] < poly->ymin || Yxy[2] > poly->ymax)
+ return 1;
+
+ /* Quick test - inner triangle */
+ for (c = 1, i = 0, j = 3-1; i < 3; j = i++) {
+ if ( ((poly->ty[i] > Yxy[2]) != (poly->ty[j] > Yxy[2]))
+ && (Yxy[1] < (poly->tx[j] - poly->tx[i]) * (Yxy[2] - poly->ty[i])
+ / (poly->ty[j] - poly->ty[i]) + poly->tx[i]) )
+ c = !c;
+ }
+ if (c == 0)
+ return 0;
+
+ /* Do point in poligon test */
+ /* (This could be speeded up in many ways) */
+ for (c = 1, i = 0, j = poly->n-1; i < poly->n; j = i++) {
+ if ( ((poly->y[i] > Yxy[2]) != (poly->y[j] > Yxy[2]))
+ && (Yxy[1] < (poly->x[j] - poly->x[i]) * (Yxy[2] - poly->y[i])
+ / (poly->y[j] - poly->y[i]) + poly->x[i]) )
+ c = !c;
+ }
+
+ return c;
+}
+
+/* Return an aproximate RGB value for coloring within the spectrum locus */
+void icx_spec_locus_color(double rgb[3], double xyz[3], icxObserverType obType) {
+ int i, j;
+ xslpoly *poly;
+ double Yxy[3];
+ double dtt[3]; /* Distances to triangle points */
+ double v[3];
+ double max;
+
+ if ((poly = spectral_locus_poligon(obType)) == NULL)
+ return;
+
+ /* Init poly if needed */
+ if (poly->n == 0 && icx_init_locus_poly(obType))
+ return;
+
+ icmXYZ2Yxy(Yxy, xyz);
+
+ /* Compute the baricentric coord for the input point, */
+ for (max = -1e6, i = 0; i < 3; i++) {
+ v[i] = poly->be[i][0] * Yxy[1] + poly->be[i][1] * Yxy[2] + poly->be[i][2];
+ if (v[i] < 0.0)
+ v[i] = 0.0;
+ else if (v[i] > 1.0)
+ v[i] = 1.0;
+
+ /* Normalise to put wp at 0.3 0.3 */
+ // ~~99
+
+ v[i] = pow(v[i], 1.0/2.2);
+
+ if (v[i] > max)
+ max = v[i];
+ }
+
+ for (i = 0; i < 3; i++) {
+ rgb[i] = v[i]/max;
+ }
+}
+
+/* -------------------------------------------------------- */
+
+/* Status T log10 weightings */
+/* CMYV */
+static xspect denT[4] = {
+ {
+ 44, 340.0, 770.0, /* 44 bands from 340 to 770 nm in 10nm steps */
+ 1.0, /* Log10 Scale factor */
+ {
+ 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.500, 1.778, 2.653, 4.477,
+ 5.000, 4.929, 4.740, 4.398, 4.000,
+ 3.699, 3.176, 2.699, 2.477, 2.176,
+ 1.699, 1.000, 0.500, 0.000, 0.000,
+ 0.000, 0.000, 0.000
+ }
+ },
+ {
+ 44, 340.0, 770.0, /* 44 bands from 340 to 770 nm in 10nm steps */
+ 1.0, /* Log10 Scale factor */
+ {
+ 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.500, 3.000, 3.699,
+ 4.447, 4.833, 4.964, 5.000, 4.944,
+ 4.820, 4.623, 4.342, 3.954, 3.398,
+ 2.845, 1.954, 1.000, 0.500, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000
+ }
+ },
+ {
+ 44, 340.0, 770.0, /* 44 bands from 340 to 770 nm in 10nm steps */
+ 1.0, /* Log10 Scale factor */
+ {
+ 0.500,
+ 1.000, 1.301, 2.000, 2.477, 3.176,
+ 3.778, 4.230, 4.602, 4.778, 4.914,
+ 4.973, 5.000, 4.987, 4.929, 4.813,
+ 4.602, 4.255, 3.699, 2.301, 1.602,
+ 0.500, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.000, 0.000, 0.000
+ }
+ },
+ {
+ 44, 340.0, 770.0, /* 44 bands from 340 to 770 nm in 10nm steps */
+ 1.0, /* Log10 Scale factor */
+ {
+ 0.000,
+ 0.000, 0.000, 0.000, 0.000, 0.000,
+ 0.500, 1.332, 1.914, 2.447, 2.881,
+ 3.090, 3.346, 3.582, 3.818, 4.041,
+ 4.276, 4.513, 4.702, 4.825, 4.905,
+ 4.957, 4.989, 5.000, 4.989, 4.956,
+ 4.902, 4.827, 4.731, 4.593, 4.433,
+ 4.238, 4.013, 3.749, 3.490, 3.188,
+ 2.901, 2.622, 2.334, 2.041, 1.732,
+ 1.431, 1.146, 0.500
+ }
+ }
+};
+
+/* Given a reflectance or transmition spectral product, (Relative */
+/* to the scale factor), return status T CMYV log10 density values */
+void xsp_Tdensity(
+double *out, /* Return CMYV density */
+xspect *in /* Spectral product to be converted */
+) {
+ int j;
+
+ /* Compute the CMYV values (normalised to 1.0) */
+ for (j = 0; j < 4; j++) {
+ double ww;
+ double sum;
+
+ /* Integrate at 1nm intervals */
+ sum = out[j] = 0.0;
+ for (ww = denT[j].spec_wl_short; ww <= denT[j].spec_wl_long; ww += 1.0) {
+ double W, S;
+
+ getval_xspec(&denT[j], &W, ww);
+ getval_xspec(in, &S, ww);
+ W = pow(10.0, W); /* Convert from log to linear weighting */
+ sum += W; /* Sum of weightings */
+ out[j] += S * W;
+ }
+ out[j] /= sum; /* Normalise */
+ if (out[j] < 0.00001)
+ out[j] = 0.00001; /* Just to be sure we don't get silly values */
+ else if (out[j] > 1.0)
+ out[j] = 1.0;
+
+ out[j] = -log10(out[j]); /* Convert to density */
+ }
+}
+
+/* XYZ to status T density aproximate conversion matrix */
+/* (Note we're multiplying by a 0.83 factor below to */
+/* avoid some limiting for some XYZ values) */
+static double xyz2tden[4][3] = {
+ { 1.750557, -0.361811, -0.265150 }, /* Red density */
+ { -0.919004, 1.861722, 0.105787 }, /* Green density */
+ { -0.047821, 0.093820, 1.163331 }, /* Blue density */
+ { 0.369966, 0.708047, -0.076312 } /* Visual density */
+};
+
+/* Given a reflectance or transmission XYZ value, */
+/* return approximate status T CMYV log10 density values */
+void icx_XYZ2Tdens(
+double *out, /* Return aproximate CMYV log10 density */
+double *in /* Input XYZ values */
+) {
+ int i, j;
+ double den[4];
+
+//DBGF((DBGA,"icx_XYZ2den got %f %f %f\n",in[0],in[1],in[2]));
+ for (i = 0; i < 4; i++) {
+
+ den[i] = 0.0;
+ for (j = 0; j < 3; j++)
+ den[i] += 0.83 * xyz2tden[i][j] * in[j];
+
+//DBGF((DBGA,"icx_XYZ2den raw den %d = %f\n",i,den[i]));
+ if (den[i] < 0.00001)
+ den[i] = 0.00001; /* Just to be sure we don't get silly values */
+ else if (den[i] > 1.0)
+ den[i] = 1.0;
+
+ out[i] = -log10(den[i]); /* Convert to density */
+ }
+//DBGF((DBGA,"icx_XYZ2den returning densities %f %f %f\n",out[0],out[1],out[2]));
+}
+
+/* Given a reflectance or transmission XYZ value, */
+/* return log10 XYZ density values */
+void icx_XYZ2dens(
+double *out, /* Return log10 XYZ density */
+double *in /* Input XYZ values */
+) {
+ int i;
+ double den[3];
+
+ for (i = 0; i < 3; i++) {
+
+ den[i] = in[i];
+
+ if (den[i] < 0.00001)
+ den[i] = 0.00001; /* Just to be sure we don't get silly values */
+ else if (den[i] > 1.0)
+ den[i] = 1.0;
+
+ out[i] = -log10(den[i]); /* Convert to density */
+ }
+}
+
+/* Given an XYZ value, */
+/* return approximate sRGB values */
+void icx_XYZ2sRGB(
+double *out, /* Return aproximate CMYV log10 density */
+double *wp, /* Input XYZ white point (may be NULL) */
+double *in /* Input XYZ values */
+) {
+ int i, j;
+ double XYZ[3];
+ double d65[3] = { 0.950543, 1.0, 1.089303 };
+ double mat[3][3] = {
+ { 3.2406, -1.5372, -0.4986 },
+ { -0.9689, 1.8758, 0.0415 },
+ { 0.0557, -0.2040, 1.0570 }
+ };
+
+ /* Do a simple Von Kries between input white point and D65 */
+ if (wp != NULL) {
+ for (j = 0; j < 3; j++)
+ XYZ[j] = d65[j] * in[j]/wp[j];
+ } else {
+ for (j = 0; j < 3; j++)
+ XYZ[j] = in[j];
+ }
+
+ /* Convert to sRGB cromaticities */
+ for (i = 0; i < 3; i++) {
+ out[i] = 0.0;
+ for (j = 0; j < 3; j++) {
+ out[i] += XYZ[j] * mat[i][j];
+ }
+ }
+
+ /* Apply gamma */
+ for (j = 0; j < 3; j++) {
+ if (out[j] <= (0.03928/12.92)) {
+ out[j] *= 12.92;
+ if (out[j] < 0.0)
+ out[j] = 0.0;
+ } else {
+ out[j] = pow(out[j], 1.0/2.4) * 1.055 - 0.055;
+ if (out[j] > 1.0)
+ out[j] = 1.0;
+ }
+ }
+}
+
+/* ------------------- */
+
+#ifdef NEVER /* Deprecated */
+
+/* Given a daylight color temperature in degrees K, */
+/* return the corresponding XYZ value (standard 2 degree observer) */
+void icx_DTEMP2XYZ(
+double *out, /* Return XYZ value with Y == 1 */
+double ct /* Input temperature in degrees K */
+) {
+ double Yxy[3];
+
+//DBGF((DBGA,"computing temperature %f\n",ct));
+ /* Compute chromaticity coordinates */
+ if (ct < 7000.0) {
+ Yxy[1] = -4.6070e9/(ct * ct * ct) + 2.9678e6/(ct * ct) + 0.09911e3/ct + 0.244063;
+ } else {
+ Yxy[1] = -2.0064e9/(ct * ct * ct) + 1.9018e6/(ct * ct) + 0.24748e3/ct + 0.237040;
+ }
+ Yxy[2] = -3.000 * Yxy[1] * Yxy[1] + 2.870 * Yxy[1] - 0.275;
+
+ Yxy[0] = 1.0;
+//DBGF((DBGA,"Yxy = %f %f %f\n",Yxy[0],Yxy[1],Yxy[2]));
+
+ /* Convert to XYZ */
+ icmYxy2XYZ(out, Yxy);
+
+//DBGF((DBGA,"XYZ = %f %f %f\n",out[0],out[1],out[2]));
+}
+
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Given an illuminant definition and an observer model, return */
+/* the normalised XYZ value for that spectrum. */
+/* Return 0 on sucess, 1 on error */
+int icx_ill_sp2XYZ(
+double xyz[3], /* Return XYZ value with Y == 1 */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+icxIllumeType ilType, /* Type of illuminant, icxIT_Dtemp or icxIT_Ptemp */
+double ct, /* Input temperature in degrees K */
+xspect *custIllum /* Optional custom illuminant */
+) {
+ xspect sp; /* Xspect to fill in */
+ xsp2cie *conv; /* Means of converting spectrum to XYZ */
+
+ if (ilType == icxIT_custom)
+ sp = *custIllum;
+ else if (standardIlluminant(&sp, ilType, ct) != 0)
+ return 1;
+
+ if ((conv = new_xsp2cie(icxIT_none, NULL, obType, custObserver, icSigXYZData, 1)) == NULL)
+ return 1;
+
+ conv->convert(conv, xyz, &sp);
+
+ conv->del(conv);
+
+ /* Normalise */
+ xyz[0] /= xyz[1];
+ xyz[2] /= xyz[1];
+ xyz[1] /= xyz[1];
+
+ return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/* Context for optimiser callback */
+typedef struct {
+ icxIllumeType ilType; /* Type of illuminant, icxIT_Dtemp or icxIT_Ptemp */
+ double xyz[3]; /* Target XYZ */
+ icmXYZNumber XYZ; /* Target as XYZ number */
+ xsp2cie *conv; /* Means of converting spectrum to XYZ */
+ int viscct; /* nz to use visual best match color temperature */
+} cctctx;
+
+static double cct_func(void *fdata, double tp[]) {
+ cctctx *x = (cctctx *)fdata;
+ double xyz[3]; /* Current value */
+ double lab1[3], lab2[3];
+ xspect sp;
+ double rv = 0.0;
+ icmXYZNumber *wp = &x->XYZ;
+
+ /* Compute the XYZ for the given temperature */
+ if (x->ilType == icxIT_Dtemp) {
+ if (daylight_il(&sp, tp[0]) != 0)
+ rv = 1e6;
+ } else {
+ if (planckian_il(&sp, tp[0]) != 0)
+ rv = 1e6;
+ }
+
+ if (rv == 0.0) {
+ x->conv->convert(x->conv, xyz, &sp);
+ xyz[0] /= xyz[1];
+ xyz[2] /= xyz[1];
+ xyz[1] /= xyz[1];
+ /* Compute the color difference to the target */
+ if (x->viscct) {
+ /* Use modern CIEDE2000 color difference - gives a better visual match */
+ icmXYZ2Lab(wp, lab1, x->xyz);
+ icmXYZ2Lab(wp, lab2, xyz);
+ rv = icmCIE2Ksq(lab1, lab2);
+ } else {
+ /* Use original CIE 1960 UCS space color difference */
+ icmXYZ21960UCS(lab1, x->xyz);
+ icmXYZ21960UCS(lab2, xyz);
+ rv = icmLabDEsq(lab1, lab2);
+ }
+ }
+
+//DBGF((DBGA,"returning %f for temp = %f\n",rv,tp[0]));
+ return rv;
+
+}
+
+/* Given a choice of temperature dependent illuminant (icxIT_Dtemp or icxIT_Ptemp), */
+/* return the closest correlated color temperature to the given spectrum or XYZ. */
+/* An observer type can be chosen for interpretting the spectrum of the input and */
+/* the illuminant. */
+/* Note we can use CIEDE2000, rather than the traditional L*u*v* 2/3 space for CCT */
+/* Return -1 on erorr */
+double icx_XYZ2ill_ct(
+double txyz[3], /* If not NULL, return the XYZ of the locus temperature */
+icxIllumeType ilType, /* Type of illuminant, icxIT_Dtemp or icxIT_Ptemp */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+double xyz[3], /* Input XYZ value, NULL if spectrum intead */
+xspect *insp, /* Input spectrum value, NULL if xyz[] instead */
+int viscct /* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
+) {
+ cctctx x; /* Context for callback */
+ double cp[1], s[1];
+ double rv;
+ int i;
+ double tc, ber, bct = 0.0;
+
+ x.viscct = viscct;
+
+ if (ilType != icxIT_Dtemp && ilType != icxIT_Ptemp)
+ return -1.0;
+ x.ilType = ilType;
+
+ if ((x.conv = new_xsp2cie(icxIT_none, NULL, obType, custObserver, icSigXYZData, 1)) == NULL)
+ return -1;
+
+ if (xyz == NULL) {
+ if (insp == NULL)
+ return -1.0;
+ x.conv->convert(x.conv, x.xyz, insp);
+ } else {
+ icmAry2Ary(x.xyz, xyz);
+ }
+
+ /* Normalise target */
+ x.xyz[0] /= x.xyz[1];
+ x.xyz[2] /= x.xyz[1];
+ x.xyz[1] /= x.xyz[1];
+ icmAry2XYZ(x.XYZ, x.xyz);
+
+ /* Do some start samples, to avoid getting trapped in local minima */
+ for (ber = 1e9, i = 0; i < 6; i++) {
+ double er;
+ tc = 1000.0 + i * 2000.0;
+ if ((er = cct_func((void *)&x, &tc)) < ber) {
+ ber = er;
+ bct = tc;
+ }
+//DBGF((DBGA,"tc = %f, er = %f\n",tc,er));
+ }
+ cp[0] = bct;
+ s[0] = 500.0;
+
+ /* Locate the CCT */
+ if (powell(&rv, 1, cp, s, 0.01, 1000, cct_func, (void *)&x, NULL, NULL) != 0) {
+ x.conv->del(x.conv);
+ return -1.0;
+ }
+
+ if (txyz != NULL) {
+ xspect sp;
+ if (x.ilType == icxIT_Dtemp) {
+ if (daylight_il(&sp, cp[0]) != 0) {
+ x.conv->del(x.conv);
+ txyz[0] = txyz[2] = txyz[1] = cp[0] = 0.0;
+ return cp[0];
+ }
+ } else {
+ if (planckian_il(&sp, cp[0]) != 0) {
+ x.conv->del(x.conv);
+ txyz[0] = txyz[2] = txyz[1] = cp[0] = 0.0;
+ return cp[0];
+ }
+ }
+ x.conv->convert(x.conv, txyz, &sp);
+ /* Make sure locus XYZ is Normalised */
+ txyz[0] /= txyz[1];
+ txyz[2] /= txyz[1];
+ txyz[1] /= txyz[1];
+ }
+ x.conv->del(x.conv);
+
+//DBGF((DBGA,"returning %f with error %f delta E94 %f\n",cp[0],sqrt(rv)));
+ return cp[0];
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+/* Convert UCS Yuv to chromatic adaptation Ycd */
+static void UCSYuv2Ycd(double *out, double *in) {
+ double u, v;
+ u = in[1];
+ v = in[2];
+
+ out[0] = in[0];
+ out[1] = (4.0 - u - 10.0 * v)/v;
+ out[2] = (1.708 * v - 1.481 * u + 0.404)/v;
+}
+
+
+
+/* Compute the CIE1995 CRI: Ra */
+/* Return < 0.0 on error */
+/* If invalid is not NULL, set it to nz if CRI */
+/* is invalid because the sample is not white enough. */
+double icx_CIE1995_CRI(
+int *invalid, /* if not NULL, set to nz if invalid */
+xspect *sample /* Illuminant sample to compute CRI of */
+) {
+ int i;
+ double cct;
+ xspect wts; /* Reference white spectrum */
+ xsp2cie *tocie;
+ double wt[3]; /* Reference white in CIE 1960 UCS */
+ icmXYZNumber wtn;
+ double wt_Ycd[3]; /* Ycd reference white */
+ double sa[3]; /* Sample white in CIE 1960 UCS */
+ double sa_Ycd[3]; /* Ycd sample white */
+ double dc; /* delta of sample to reference white in 1960 UCS */
+ double ref[8][3]; /* reference XYZ/1964 color space */
+ double sam[8][3]; /* sample XYZ/1964 color space */
+ double c_ad, d_ad; /* Chromatic adaptation scaling factors */
+ double cri = 0.0;
+
+//DBGF((DBGA,"icx_CIE1995_CRI called\n"));
+
+ /* First find the standard 2 degree observer plankian CCT */
+ if ((cct = icx_XYZ2ill_ct(NULL, icxIT_Ptemp, icxOT_CIE_1931_2, NULL, NULL, sample, 0)) < 0.0)
+ return -1.0;
+
+//DBGF((DBGA,"CCT = %f\n", cct));
+
+ /* Create a reference white spectrum with the same CCT */
+ if (cct < 5000.0) {
+ if (planckian_il(&wts, cct))
+ return -1.0;
+ } else {
+ if (daylight_il(&wts, cct))
+ return -1.0;
+ }
+
+ if ((tocie = new_xsp2cie(icxIT_none, NULL, icxOT_CIE_1931_2, NULL, icSigXYZData, 1)) == NULL)
+ return -1.0;
+
+ /* Compute the XYZ of the reference white and sample */
+ tocie->convert(tocie, wt, &wts);
+ tocie->convert(tocie, sa, sample);
+
+//DBGF((DBGA,"XYZ white = %f %f %f\n",wt[0],wt[1],wt[2]));
+//DBGF((DBGA,"XYZ sampl = %f %f %f\n",sa[0],sa[1],sa[2]));
+
+ /* Normalize the spectra so as to create a normalized white */
+ wts.norm *= wt[1];
+ sample->norm *= sa[1]; /* ~~~ shouldn't change sample!!!! ~~~~ */
+ tocie->convert(tocie, wt, &wts);
+ tocie->convert(tocie, sa, sample);
+ tocie->del(tocie);
+
+//DBGF((DBGA,"norm XYZ white = %f %f %f\n",wt[0],wt[1],wt[2]));
+//DBGF((DBGA,"norm XYZ sampl = %f %f %f\n",sa[0],sa[1],sa[2]));
+
+ /* Convert to perceptual CIE 1960 UCS */
+ icmAry2XYZ(wtn, wt); /* Use reference white as UCS white */
+ icmXYZ21960UCS(wt, wt); /* 1960 UCS Yuv reference white */
+ UCSYuv2Ycd(wt_Ycd, wt); /* Ycd version for chromatic adapation */
+ icmXYZ21960UCS(sa, sa); /* 1960 UCS Yuv sample white */
+ UCSYuv2Ycd(sa_Ycd, sa); /* Ycd version for chromatic adapation */
+
+ c_ad = wt_Ycd[1]/sa_Ycd[1]; /* Chromatic adaptation scaling factors */
+ d_ad = wt_Ycd[2]/sa_Ycd[2];
+
+//DBGF((DBGA,"UCS white = %f %f %f\n",wt[0],wt[1],wt[2]));
+//DBGF((DBGA,"UCS sampl = %f %f %f\n",sa[0],sa[1],sa[2]));
+
+ dc = sqrt((wt[1] - sa[1]) * (wt[1] - sa[1]) + (wt[2] - sa[2]) * (wt[2] - sa[2]));
+
+//DBGF((DBGA,"dc = %f\n",dc));
+//if (dc > 0.0054) DBGF((DBGA,"CRI is invalid\n"));
+
+ /* If dc > 0.0054 we should abort computing the CRI, */
+ /* but this means we fail on lots of real world lighting. */
+ if (invalid != NULL) {
+ if (dc > 0.0054)
+ *invalid = 1;
+ else
+ *invalid = 0;
+ }
+
+ /* Check out the delta E for each reflective sample */
+ if ((tocie = new_xsp2cie(icxIT_custom, &wts, icxOT_CIE_1931_2, NULL, icSigXYZData, 1)) == NULL)
+ return -1.0;
+ for (i = 0; i < 8; i++) {
+ tocie->convert(tocie, ref[i], &CIE1995_TCS[i]);
+ icmXYZ21964WUV(&wtn, ref[i], ref[i]);
+//DBGF((DBGA,"ref samp %d = WUV %f %f %f\n", i,ref[i][0],ref[i][1],ref[i][2]));
+ }
+ tocie->del(tocie);
+
+ if ((tocie = new_xsp2cie(icxIT_custom, sample, icxOT_CIE_1931_2, NULL, icSigXYZData, 1)) == NULL)
+ return -1.0;
+ for (i = 0; i < 8; i++) {
+ double c, d;
+ tocie->convert(tocie, sam[i], &CIE1995_TCS[i]);
+
+ icmXYZ21960UCS(sam[i], sam[i]);
+
+ /* Do chromatic adaptation */
+ UCSYuv2Ycd(sam[i], sam[i]);
+ c = sam[i][1];
+ d = sam[i][2];
+ sam[i][1] = (10.872 + 0.404 * c * c_ad - 4.0 * d * d_ad)/
+ (16.518 + 1.481 * c * c_ad - 1.0 * d * d_ad);
+
+ sam[i][2] = (5.520)/
+ (16.518 + 1.481 * c * c_ad - 1.0 * d * d_ad);
+
+ icm1960UCS21964WUV(&wtn, sam[i], sam[i]);
+
+//DBGF((DBGA,"sam samp %d = WUV %f %f %f\n", i,sam[i][0],sam[i][1],sam[i][2]));
+ }
+ tocie->del(tocie);
+
+ /* Compute the CRI */
+ for (i = 0; i < 8; i++) {
+ double de, tcri;
+
+ de = icmLabDE(ref[i], sam[i]);
+ tcri = 100.0 - 4.6 * de;
+//DBGF((DBGA,"sample %d: de = %f, CRI = %f\n",i,de,tcri));
+ cri += tcri;
+ }
+ cri /= 8.0;
+
+//DBGF((DBGA,"average CRI = %f\n",cri));
+ if (cri < 0.0)
+ cri = -1.0;
+
+//DBGF((DBGA,"returning CRI = %f\n",cri));
+ return cri;
+}
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+#endif /* !SALONEINSTLIB */
+
+
+
+
+
diff --git a/xicc/xspect.h b/xicc/xspect.h
new file mode 100644
index 0000000..caca8b2
--- /dev/null
+++ b/xicc/xspect.h
@@ -0,0 +1,430 @@
+
+#ifndef XSPECT_H
+#define XSPECT_H
+
+/*
+ * Author: Graeme W. Gill
+ * Date: 21/6/01
+ * Version: 1.00
+ *
+ * Copyright 2000 - 2010 Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+/*
+ * This class supports converting spectral samples
+ * into CIE XYZ or D50 Lab tristimulous values.
+ */
+
+/*
+ * TTBD:
+ *
+ */
+
+#ifndef SALONEINSTLIB
+#include "icc.h" /* icclib ICC definitions */
+#else /* SALONEINSTLIB */
+#include "conv.h" /* fake icclib ICC definitions */
+#endif /* SALONEINSTLIB */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/* ------------------------------------------------------------------------------ */
+
+/* Structure for conveying spectral information */
+
+/* NOTE :- should ditch norm, and replace it by */
+/* "units", ie. reflectance/transmittance 0..1, 0..100%, */
+/* W/nm/m^2 or mW/nm/m^2 */
+#define XSPECT_MAX_BANDS 601 /* Enought for 1nm from 300 to 900 */
+
+typedef struct {
+ int spec_n; /* Number of spectral bands, 0 if not valid */
+ double spec_wl_short; /* First reading wavelength in nm (shortest) */
+ double spec_wl_long; /* Last reading wavelength in nm (longest) */
+ double norm; /* Normalising scale value */
+ double spec[XSPECT_MAX_BANDS]; /* Spectral value, shortest to longest */
+} xspect;
+
+/* Some helpful macro's: */
+
+/* Copy everything except the spectral values */
+#define XSPECT_COPY_INFO(PDST, PSRC) \
+ (PDST)->spec_n = (PSRC)->spec_n, \
+ (PDST)->spec_wl_short = (PSRC)->spec_wl_short, \
+ (PDST)->spec_wl_long = (PSRC)->spec_wl_long, \
+ (PDST)->norm = (PSRC)->norm
+
+/* Given an index and the sampling ranges, compute the sample wavelength */
+#define XSPECT_WL(SHORT, LONG, N, IX) \
+((SHORT) + (double)(IX) * ((LONG) - (SHORT))/((N)-1.0))
+
+/* Given the address of an xspect and an index, compute the sample wavelegth */
+#define XSPECT_XWL(PXSP, IX) \
+(((PXSP)->spec_wl_short) + (double)(IX) * (((PXSP)->spec_wl_long) - ((PXSP)->spec_wl_short))/(((PXSP)->spec_n)-1.0))
+
+/* Given a wavelength and the sampling ranges, compute the double index */
+#define XSPECT_DIX(SHORT, LONG, N, WL) \
+(((N)-1.0) * ((WL) - (SHORT))/((LONG) - (SHORT)))
+
+/* Given the wavelength and address of an xspect, compute the double index */
+#define XSPECT_XDIX(PXSP, WL) \
+(((PXSP)->spec_n-1.0) * ((WL) - ((PXSP)->spec_wl_short))/(((PXSP)->spec_wl_long) - ((PXSP)->spec_wl_short)))
+
+/* Given a wavelength and the sampling ranges, compute the nearest index */
+#define XSPECT_IX(SHORT, LONG, N, WL) \
+((int)floor(XSPECT_DIX(SHORT, LONG, N, WL) + 0.5))
+
+/* Given a wavelength and address of an xspect, compute the nearest index */
+#define XSPECT_XIX(PXSP, WL) \
+((int)floor(XSPECT_DIX(PXSP, WL) + 0.5))
+
+#ifndef SALONEINSTLIB
+
+/* Single spectrum utility functions. Return NZ if error */
+int write_xspect(char *fname, xspect *s);
+int read_xspect(xspect *sp, char *fname);
+
+/* CMF utility functions. Return NZ if error */
+int write_cmf(char *fname, xspect cmf[3]);
+int read_cmf(xspect cmf[3], char *fname);
+
+/* Save a set of nspec spectrum to a CGATS file. Return NZ if error */
+/* type 0 = SPECT, 1 = CMF */
+int write_nxspect(char *fname, xspect *sp, int nspec, int type);
+
+/* Restore a set of up to nspec spectrum from a CGATS file. Return NZ if error */
+/* type = any, 1 = SPECT, 2 = CMF, 3 = both */
+int read_nxspect(xspect *sp, char *fname, int *nret, int off, int nspec, int type);
+
+#endif /* !SALONEINSTLIB*/
+
+/* Get interpolated value at wavelenth (not normalised) */
+double value_xspect(xspect *sp, double wl);
+
+/* De-normalize and set normalisation factor to 1.0 */
+void xspect_denorm(xspect *sp);
+
+#ifndef SALONEINSTLIB
+/* Convert from one xspect type to another */
+void xspect2xspect(xspect *dst, xspect *targ, xspect *src);
+#endif /* !SALONEINSTLIB*/
+
+/* ------------------------------------------------------------------------------ */
+/* Class for converting between spectral and CIE */
+
+/* We build in some useful spectra */
+
+/* Type of illumination */
+typedef enum {
+ icxIT_default = 0, /* Default illuminant (usually D50) */
+ icxIT_none = 1, /* No illuminant - self luminous spectrum */
+ icxIT_custom = 2, /* Custom illuminant spectrum */
+ icxIT_A = 3, /* Standard Illuminant A */
+ icxIT_C = 4, /* Standard Illuminant C */
+ icxIT_D50 = 5, /* Daylight 5000K */
+ icxIT_D50M2 = 6, /* Daylight 5000K, UV filtered (M2) */
+ icxIT_D65 = 7, /* Daylight 6500K */
+ icxIT_E = 8, /* Equal Energy */
+#ifndef SALONEINSTLIB
+ icxIT_F5 = 9, /* Fluorescent, Standard, 6350K, CRI 72 */
+ icxIT_F8 = 10, /* Fluorescent, Broad Band 5000K, CRI 95 */
+ icxIT_F10 = 11, /* Fluorescent Narrow Band 5000K, CRI 81 */
+ icxIT_Spectrocam = 12, /* Spectrocam Xenon Lamp */
+ icxIT_Dtemp = 13, /* Daylight at specified temperature */
+ icxIT_Ptemp = 14 /* Planckian at specified temperature */
+#endif /* !SALONEINSTLIB*/
+} icxIllumeType;
+
+/* Fill in an xpsect with a standard illuminant spectrum */
+/* return 0 on sucecss, nz if not matched */
+int standardIlluminant(
+xspect *sp, /* Xspect to fill in */
+icxIllumeType ilType, /* Type of illuminant */
+double temp); /* Optional temperature in degrees kelvin, for Dtemp and Ptemp */
+
+/* Given an emission spectrum, set the UV output to the given level. */
+/* The shape of the UV is taken from FWA1_stim, and the level is */
+/* with respect to the average of the input spectrum. */
+void xsp_setUV(xspect *out, xspect *in, double uvlevel);
+
+
+/* Type of observer */
+typedef enum {
+ icxOT_default = 0, /* Default observer (usually CIE_1931_2) */
+ icxOT_none = 1, /* No observer - (don't compute XYZ) */
+ icxOT_custom = 2, /* Custom observer type weighting */
+ icxOT_CIE_1931_2 = 3, /* Standard CIE 1931 2 degree */
+ icxOT_CIE_1964_10 = 4, /* Standard CIE 1964 10 degree */
+#ifndef SALONEINSTLIB
+ icxOT_Stiles_Burch_2 = 5, /* Stiles & Burch 1955 2 degree */
+ icxOT_Judd_Voss_2 = 6, /* Judd & Voss 1978 2 degree */
+ icxOT_CIE_1964_10c = 7, /* Standard CIE 1964 10 degree, 2 degree compatible */
+ icxOT_Shaw_Fairchild_2 = 8 /* Shaw & Fairchild 1997 2 degree */
+#endif /* !SALONEINSTLIB*/
+} icxObserverType;
+
+/* Return pointers to three xpsects with a standard observer weighting curves */
+/* return 0 on sucecss, nz if not matched */
+int standardObserver(xspect *sp[3], icxObserverType obType);
+
+/* Return a string describing the standard observer */
+char *standardObserverDescription(icxObserverType obType);
+
+/* Clamping state */
+typedef enum {
+ icxNoClamp = 0, /* Don't clamp XYZ/Lab to +ve */
+ icxClamp = 1, /* Clamp XYZ/Lab to +ve */
+} icxClamping;
+
+/* The conversion object */
+struct _xsp2cie {
+ /* Private: */
+ xspect illuminant; /* Lookup conversion/observer illuminant */
+ int isemis; /* nz if we are doing an emission conversion */
+ xspect observer[3];
+ int doLab; /* Return D50 Lab result */
+ icxClamping clamp; /* Clamp XYZ and Lab to be +ve */
+
+#ifndef SALONEINSTLIB
+ /* FWA compensation */
+ double bw; /* Integration bandwidth */
+ xspect iillum; /* Y = 1 Normalised instrument illuminant spectrum */
+ xspect imedia; /* Instrument measured media */
+ xspect emits; /* Estimated FWA emmission spectrum */
+ xspect media; /* Estimated base media (ie. minus FWA) */
+ xspect tillum; /* Y = 1 Normalised target/simulated instrument illuminant spectrum */
+ xspect oillum; /* Y = 1 Normalised observer illuminant spectrum */
+ double Sm; /* FWA Stimulation level for emits contribution */
+ double FWAc; /* FWA content (informational) */
+ int insteqtarget; /* iillum == tillum, bypass FWA */
+#endif /* !SALONEINSTLIB*/
+
+ /* Public: */
+ void (*del)(struct _xsp2cie *p);
+
+ /* Convert (and possibly fwa correct) reflectance spectrum */
+ /* Note that the input spectrum normalisation value is used. */
+ /* Note that the returned XYZ is 0..1 range for reflectanc. */
+ /* Emissive spectral values are assumed to be in mW/nm, and sampled */
+ /* rather than integrated if they are not at 1nm spacing. */
+ void (*convert) (struct _xsp2cie *p, /* this */
+ double *out, /* Return XYZ or D50 Lab value */
+ xspect *in /* Spectrum to be converted, normalised by norm */
+ );
+
+ /* Convert and also return (possibly corrected) reflectance spectrum */
+ /* Spectrum will be same wlength range and readings as input spectrum */
+ /* Note that the returned XYZ is 0..1 range for reflectanc. */
+ /* Emissive spectral values are assumed to be in mW/nm, and sampled */
+ /* rather than integrated if they are not at 1nm spacing. */
+ void (*sconvert) (struct _xsp2cie *p, /* this */
+ xspect *sout, /* Return corrected refl. spectrum (may be NULL) */
+ double *out, /* Return XYZ or D50 Lab value (may be NULL) */
+ xspect *in /* Spectrum to be converted, normalised by norm */
+ );
+
+#ifndef SALONEINSTLIB
+ /* Set Media White. This enables extracting and applying the */
+ /* colorant reflectance value from/to the meadia. */
+ /* return NZ if error */
+ int (*set_mw) (struct _xsp2cie *p, /* this */
+ xspect *white /* Spectrum of plain media */
+ );
+
+ /* Set Fluorescent Whitening Agent compensation */
+ /* return NZ if error */
+ int (*set_fwa) (struct _xsp2cie *p, /* this */
+ xspect *iillum, /* Spectrum of instrument illuminant */
+ xspect *tillum, /* Spectrum of target/simulated instrument illuminant, */
+ /* NULL to use observer illuminant. */
+ xspect *white /* Spectrum of plain media */
+ );
+
+ /* Set FWA given updated conversion illuminant. */
+ /* (We assume that xsp2cie_set_fwa has been called first) */
+ /* return NZ if error */
+ int (*update_fwa_custillum) (struct _xsp2cie *p,
+ xspect *tillum, /* Spectrum of target/simulated instrument illuminant, */
+ /* NULL to use set_fwa() value. */
+ xspect *custIllum /* Spectrum of observer illuminant */
+ );
+
+ /* Get Fluorescent Whitening Agent compensation information */
+ /* return NZ if error */
+ void (*get_fwa_info) (struct _xsp2cie *p, /* this */
+ double *FWAc /* FWA content as a ratio. */
+ );
+
+ /* Extract the colorant reflectance value from the media. Takes FWA */
+ /* into account if set. Media white or FWA must be set. */
+ /* return NZ if error */
+ int (*extract) (struct _xsp2cie *p, /* this */
+ xspect *out, /* Extracted colorant refl. spectrum */
+ xspect *in /* Spectrum to be converted, normalised by norm */
+ );
+
+
+ /* Apply the colorant reflectance value from the media. Takes FWA */
+ /* into account if set. DOESN'T convert to FWA target illumination! */
+ /* FWA must be set. */
+ int (*apply) (struct _xsp2cie *p, /* this */
+ xspect *out, /* Applied refl. spectrum */
+ xspect *in /* Colorant reflectance to be applied */
+ );
+#endif /* !SALONEINSTLIB*/
+
+}; typedef struct _xsp2cie xsp2cie;
+
+xsp2cie *new_xsp2cie(
+ icxIllumeType ilType, /* Observer Illuminant to use */
+ xspect *custIllum,
+
+ icxObserverType obType, /* Observer */
+ xspect custObserver[3],
+ icColorSpaceSignature rcs, /* Return color space, icSigXYZData or icSigLabData */
+ /* ** Must be icSigXYZData if SALONEINSTLIB ** */
+ icxClamping clamp /* NZ to clamp XYZ/Lab to be +ve */
+);
+
+#ifndef SALONEINSTLIB
+/* --------------------------- */
+/* Spectrum locus */
+
+/* Return the spectrum locus range for the given observer. */
+/* return 0 on sucecss, nz if observer not known */
+int icx_spectrum_locus_range(double *min_wl, double *max_wl, icxObserverType obType);
+
+/* Return an XYZ that is on the spectrum locus for the given observer. */
+/* wl is the input wavelength in the range icx_spectrum_locus_range(), */
+/* and return clipped result if outside this range. */
+/* Return nz if observer unknown. */
+int icx_spectrum_locus(double xyz[3], double in, icxObserverType obType);
+
+/* Determine whether the given XYZ is outside the spectrum locus */
+/* Return 0 if within locus */
+/* Return 1 if outside locus */
+/* Return 2 if unknown (bad observer) */
+int icx_outside_spec_locus(double xyz[3], icxObserverType obType);
+
+/* Return an aproximate RGB value for coloring within the spectrum locus */
+void icx_spec_locus_color(double rgb[3], double xyz[3], icxObserverType obType);
+
+/* --------------------------- */
+/* Density and other functions */
+
+/* Given a reflectance or transmition spectral product, */
+/* return status T CMY + V density values */
+void xsp_Tdensity(double *out, /* Return CMYV density */
+ xspect *in /* Spectral product to be converted */
+ );
+
+/* Given a reflectance or transmission XYZ value, */
+/* return approximate status T CMYV log10 density values */
+void icx_XYZ2Tdens(
+double *out, /* Return aproximate CMYV log10 density */
+double *in /* Input XYZ values */
+);
+
+/* Given a reflectance or transmission XYZ value, */
+/* return log10 XYZ density values */
+void icx_XYZ2dens(
+double *out, /* Return log10 XYZ density */
+double *in /* Input XYZ values */
+);
+
+/* Given an XYZ value, */
+/* return sRGB values */
+void icx_XYZ2sRGB(
+double *out, /* Return sRGB value */
+double *wp, /* Input XYZ white point (may be NULL) */
+double *in /* Input XYZ values */
+);
+
+
+
+/* Given an illuminant definition and an observer model, return */
+/* the normalised XYZ value for that spectrum. */
+/* Return 0 on sucess, 1 on error */
+int icx_ill_sp2XYZ(
+double xyz[3], /* Return XYZ value with Y == 1 */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+icxIllumeType ilType, /* Type of illuminant */
+double ct, /* Input temperature in degrees K */
+xspect *custIllum); /* Optional custom illuminant */
+
+
+/* Given a choice of temperature dependent illuminant (icxIT_Dtemp or icxIT_Ptemp), */
+/* return the closest correlated color temperature to the given spectrum or XYZ. */
+/* An observer type can be chosen for interpretting the spectrum of the input and */
+/* the illuminant. */
+/* Note we're using CICDE94, rather than the traditional L*u*v* 2/3 space for CCT */
+/* Return -1 on erorr */
+double icx_XYZ2ill_ct(
+double txyz[3], /* If not NULL, return the XYZ of the black body temperature */
+icxIllumeType ilType, /* Type of illuminant, icxIT_Dtemp or icxIT_Ptemp */
+icxObserverType obType, /* Observer */
+xspect custObserver[3], /* Optional custom observer */
+double xyz[3], /* Input XYZ value, NULL if spectrum intead */
+xspect *insp0, /* Input spectrum value, NULL if xyz[] instead */
+int viscct); /* nz to use visual CIEDE2000, 0 to use CCT CIE 1960 UCS. */
+
+/* Compute the CIE1995 CRI: Ra */
+/* Return < 0.0 on error */
+/* If invalid is not NULL, set it to nz if CRI */
+/* is invalid because the sample is not white enough. */
+double icx_CIE1995_CRI(
+int *invalid, /* if not NULL, set to nz if invalid */
+xspect *sample /* Illuminant sample to compute CRI of */
+);
+#endif /* !SALONEINSTLIB*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* XSPECTFM_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xutils.c b/xicc/xutils.c
new file mode 100644
index 0000000..019cee6
--- /dev/null
+++ b/xicc/xutils.c
@@ -0,0 +1,294 @@
+
+/*
+ * xicc standalone utilities
+ *
+ * Author: Graeme W. Gill
+ * Date: 2/7/00
+ * Version: 1.00
+ *
+ * Copyright 2000 - 2006 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.
+ *
+ */
+
+/*
+ * This module provides expanded capabilities,
+ * but is independent of other modules.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <ctype.h>
+#include <setjmp.h>
+#ifdef __sun
+#include <unistd.h>
+#endif
+#if defined(__IBMC__) && defined(_M_IX86)
+#include <float.h>
+#endif
+#include "copyright.h"
+#include "aconfig.h"
+#include "icc.h"
+#include "tiffio.h"
+#include "jpeglib.h"
+#include "iccjpeg.h"
+#include "xutils.h" /* definitions for this library */
+
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define errout stderr
+# define debug(xx) fprintf(errout, xx )
+# define debug2(xx) fprintf xx
+#else
+# define debug(xx)
+# define debug2(xx)
+#endif
+
+#if !defined(O_CREAT) && !defined(_O_CREAT)
+# error "Need to #include fcntl.h!"
+#endif
+
+/* ------------------------------------------------------ */
+/* Common clut table code */
+
+/* Default table of clut resolutions */
+/* See discussion in imdi/imdi_gen.c for ideal numbers */
+static int lut_resolutions[9][4] = {
+ /* low, med, high, vhigh */
+ { 0, 0, 0, 0 }, /* 0 */
+ { 256, 772, 4370, 4370 }, /* 1 */
+ { 86, 256, 256, 256 }, /* 2 */
+ { 9, 17, 33, 52 }, /* 3 */
+ { 6, 9, 18, 33 }, /* 4 */
+ { 6, 9, 16, 18 }, /* 5 */
+ { 6, 6, 9, 12 }, /* 6 */
+ { 6, 7, 7, 9 }, /* 7 */
+ { 3, 5, 5, 7 } /* 8 */
+};
+
+
+/* return a lut resolution given the input dimesion and quality */
+/* Input dimension [0-8], quality: low 0, medium 1, high 2, very high 3 . */
+/* A returned value of 0 indicates illegal. */
+int dim_to_clutres(int dim, int quality) {
+ if (dim < 0)
+ dim = 0;
+ else if (dim > 8)
+ dim = 8;
+ if (quality < 0)
+ quality = 0;
+ if (quality > 3)
+ quality = 3;
+ return lut_resolutions[dim][quality];
+}
+
+/* ------------------------------------------------------ */
+
+/* JPEG error information */
+typedef struct {
+ jmp_buf env; /* setjmp/longjmp environment */
+ char message[JMSG_LENGTH_MAX];
+} jpegerrorinfo;
+
+/* JPEG error handler */
+static void jpeg_error(j_common_ptr cinfo) {
+ jpegerrorinfo *p = (jpegerrorinfo *)cinfo->client_data;
+ (*cinfo->err->format_message) (cinfo, p->message);
+ longjmp(p->env, 1);
+}
+
+/* ------------------------------------------------------ */
+
+/* Open an ICC file or a TIFF or JPEG file with an embedded ICC profile for reading. */
+/* Return NULL on error */
+icc *read_embedded_icc(char *file_name) {
+ TIFF *rh = NULL;
+ int size;
+ void *tag, *buf;
+ icmAlloc *al;
+ icmFile *fp;
+ icc *icco;
+ TIFFErrorHandler olderrh, oldwarnh;
+ TIFFErrorHandlerExt olderrhx, oldwarnhx;
+ int rv;
+
+ /* First see if the file can be opened as an ICC profile */
+ if ((fp = new_icmFileStd_name(file_name,"r")) == NULL) {
+ debug2((errout,"Can't open file '%s'\n",file_name));
+ return NULL;
+ }
+
+ if ((icco = new_icc()) == NULL) {
+ debug("Creation of ICC object failed\n");
+ fp->del(fp);
+ return NULL;
+ }
+
+ if ((rv = icco->read_x(icco,fp,0,1)) == 0) {
+ debug2((errout,"Opened '%s' as an icc profile\n",file_name));
+ return icco;
+ }
+
+ debug2((errout,"icc read failed with %d, %s\n",rv,icco->err));
+ icco->del(icco); /* icc wil fp->del() */
+
+ /* Not an ICC profile, see if it's a TIFF file */
+ olderrh = TIFFSetErrorHandler(NULL);
+ oldwarnh = TIFFSetWarningHandler(NULL);
+ olderrhx = TIFFSetErrorHandlerExt(NULL);
+ oldwarnhx = TIFFSetWarningHandlerExt(NULL);
+
+ if ((rh = TIFFOpen(file_name, "r")) != NULL) {
+ TIFFSetErrorHandler(olderrh);
+ TIFFSetWarningHandler(oldwarnh);
+ TIFFSetErrorHandlerExt(olderrhx);
+ TIFFSetWarningHandlerExt(oldwarnhx);
+ debug("TIFFOpen suceeded\n");
+
+ if (TIFFGetField(rh, TIFFTAG_ICCPROFILE, &size, &tag) == 0 || size == 0) {
+ debug2((errout,"no ICC profile found in '%s'\n",file_name));
+ TIFFClose(rh);
+ return NULL;
+ }
+
+ /* Make a copy of the profile to a memory buffer */
+ if ((al = new_icmAllocStd()) == NULL) {
+ debug("new_icmAllocStd failed\n");
+ TIFFClose(rh);
+ return NULL;
+ }
+ if ((buf = al->malloc(al, size)) == NULL) {
+ debug("malloc of profile buffer failed\n");
+ al->del(al);
+ TIFFClose(rh);
+ return NULL;
+ }
+
+ memmove(buf, tag, size);
+ TIFFClose(rh);
+
+ } else {
+ jpegerrorinfo jpeg_rerr;
+ FILE *rf = NULL;
+ struct jpeg_decompress_struct rj;
+ struct jpeg_error_mgr jerr;
+ unsigned char *pdata;
+ unsigned int plen;
+
+ debug2((errout,"TIFFOpen failed for '%s'\n",file_name));
+ TIFFSetErrorHandler(olderrh);
+ TIFFSetWarningHandler(oldwarnh);
+ TIFFSetErrorHandlerExt(olderrhx);
+ TIFFSetWarningHandlerExt(oldwarnhx);
+
+ /* We cope with the horrible ijg jpeg library error handling */
+ /* by using a setjmp/longjmp. */
+ jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+ if (setjmp(jpeg_rerr.env)) {
+ debug2((errout,"jpeg_read_header failed for '%s'\n",file_name));
+ jpeg_destroy_decompress(&rj);
+ fclose(rf);
+ return NULL;
+ }
+
+ rj.err = &jerr;
+ rj.client_data = &jpeg_rerr;
+ jpeg_create_decompress(&rj);
+
+#if defined(O_BINARY) || defined(_O_BINARY)
+ if ((rf = fopen(file_name,"rb")) == NULL)
+#else
+ if ((rf = fopen(file_name,"r")) == NULL)
+#endif
+ {
+ debug2((errout,"fopen failed for '%s'\n",file_name));
+ jpeg_destroy_decompress(&rj);
+ return NULL;
+ }
+
+ jpeg_stdio_src(&rj, rf);
+ setup_read_icc_profile(&rj);
+
+ /* we'll longjmp on error */
+ jpeg_read_header(&rj, TRUE);
+
+ if (!read_icc_profile(&rj, &pdata, &plen)) {
+ debug2((errout,"no ICC profile found in '%s'\n",file_name));
+ jpeg_destroy_decompress(&rj);
+ fclose(rf);
+ return NULL;
+ }
+ jpeg_destroy_decompress(&rj);
+ fclose(rf);
+
+ /* Make a copy of the profile to a memory buffer */
+ /* (icmAllocStd may not be the same as malloc ?) */
+ if ((al = new_icmAllocStd()) == NULL) {
+ debug("new_icmAllocStd failed\n");
+ return NULL;
+ }
+ if ((buf = al->malloc(al, plen)) == NULL) {
+ debug("malloc of profile buffer failed\n");
+ al->del(al);
+ TIFFClose(rh);
+ return NULL;
+ }
+ memmove(buf, pdata, plen);
+ size = (int)plen;
+ free(pdata);
+ }
+
+ /* Memory File fp that will free the buffer when deleted: */
+ if ((fp = new_icmFileMem_ad(buf, size, al)) == NULL) {
+ debug("Creating memory file from CMProfileLocation failed");
+ al->free(al, buf);
+ al->del(al);
+ return NULL;
+ }
+
+ if ((icco = new_icc()) == NULL) {
+ debug("Creation of ICC object failed\n");
+ fp->del(fp); /* fp will delete al */
+ return NULL;
+ }
+
+ if ((rv = icco->read_x(icco,fp,0,1)) == 0) {
+ debug2((errout,"Opened '%s' embedded icc profile\n",file_name));
+ return icco;
+ }
+
+ debug2((errout,"Failed to read '%s' embedded icc profile\n",file_name));
+ icco->del(icco); /* icco will delete fp and al */
+ return NULL;
+}
+
+/* ------------------------------------------------------ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xicc/xutils.h b/xicc/xutils.h
new file mode 100644
index 0000000..27de570
--- /dev/null
+++ b/xicc/xutils.h
@@ -0,0 +1,69 @@
+#ifndef XUTILS_H
+#define XUTILS_H
+
+/*
+ * xicc standalone utilities.
+ *
+ * Author: Graeme W. Gill
+ * Date: 28/6/00
+ * Version: 1.00
+ *
+ * Copyright 2000 - 2006 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.
+ *
+ * Based on the old iccXfm class.
+ */
+
+/*
+ * These utilities, while living in xicc, are meant to
+ * not depend on other modules.
+ */
+
+/* Return a lut resolution given the input dimesion and quality */
+/* Input dimension [0-8], quality: low, medium, high, very high. */
+/* A returned value of 0 indicates illegal. */
+int dim_to_clutres(int dim, int quality);
+
+
+/* Open an ICC file or a TIFF or JPEG file with an embedded ICC profile for reading. */
+/* Return NULL on error */
+icc *read_embedded_icc(char *file_name);
+
+#endif /* XUTILS_H */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ziparch.sh b/ziparch.sh
new file mode 100644
index 0000000..d4496ca
--- /dev/null
+++ b/ziparch.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+
+# Make complete source distribution archive.
+
+echo "Making Complete Argyll source archive argyll.zip... "
+
+rm -f argyll.zip
+rm -rf _zipdir
+mkdir _zipdir
+NOTFOUND=
+
+for i in `cat adirs bdirs`
+do
+ echo
+ echo "#### Doing Directory $i ####"
+ if [ ! -e ${i}/afiles ] ; then
+ if [ ! -e ${i}/bfiles ] ; then
+ echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Can't find ${i}/afiles or ${i}/bfiles !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+ NOTFOUND="$NOTFOUND ${i}/afiles ${i}/bfiles"
+ fi
+ fi
+
+ if [ -e ${i}/afiles ] ; then
+ rm -f _ziplist
+
+ for j in `cat $i/afiles`
+ do
+ # Create any needed temporary directories
+ tt=${i}/${j}
+ path=${tt%/*} # extract path without filename
+
+ if ! expr _zipdir/${path} : '\b\.\b' > /dev/null ; then # if not "."
+ if [ ! -e _zipdir/${path} ] ; then # if not been created
+ mkdir -p _zipdir/${path}
+ fi
+ fi
+
+ if [ ! -e ${i}/${j} ] ; then
+ echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Can't find file ${i}/${j} !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+ NOTFOUND="$NOTFOUND ${i}/${j}"
+ else
+ dos2unix ${i}/${j}
+ cp ${i}/${j} _zipdir/${i}/${j}
+ echo ${i}/${j} >> _ziplist
+ fi
+ done
+
+ cd _zipdir
+ zip -9 -m ../argyll.zip `cat ../_ziplist`
+ cd ..
+ if ! expr ${i} : '\b\.\b' > /dev/null ; then
+ rm -r _zipdir/${i}
+ fi
+ fi
+
+ # same as above, but for "bfiles", if it exists
+ if [ -e ${i}/bfiles ] ; then
+ rm -f _ziplist
+
+ for j in `cat $i/bfiles`
+ do
+
+ # Create any needed temporary directories
+ tt=${i}/${j}
+ path=${tt%/*} # extract path without filename
+
+ if ! expr _zipdir/${path} : '\b\.\b' > /dev/null ; then # if not "."
+ if [ ! -e _zipdir/${path} ] ; then # if not been created
+ mkdir -p _zipdir/${path}
+ fi
+ fi
+
+ if [ ! -e ${i}/${j} ] ; then
+ echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Can't find file ${i}/${j} !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+ NOTFOUND="$NOTFOUND ${i}/${j}"
+ else
+ dos2unix ${i}/${j}
+ cp ${i}/${j} _zipdir/${i}/${j}
+ echo ${i}/${j} >> _ziplist
+ fi
+ done
+
+ cd _zipdir
+ zip -9 -m ../argyll.zip `cat ../_ziplist`
+ cd ..
+ if ! expr ${i} : '\b\.\b' > /dev/null ; then
+ rm -r _zipdir/${i}
+ fi
+ fi
+done
+rm -r _zipdir
+rm _ziplist
+if [ "X$NOTFOUND" != "X" ] ; then
+ echo "!!!!!! Didn't find $NOTFOUND !!!!!!"
+fi
+echo "Finished Complete Argyll source archive argyll.zip... "